D issues are now tracked on GitHub. This Bugzilla instance remains as a read-only archive.
Issue 3316 - Functions nested in a pure templated function cannot reference its local variables
Summary: Functions nested in a pure templated function cannot reference its local vari...
Status: RESOLVED FIXED
Alias: None
Product: D
Classification: Unclassified
Component: dmd (show other issues)
Version: D2
Hardware: Other All
: P2 normal
Assignee: No Owner
URL:
Keywords: patch, rejects-valid
Depends on:
Blocks:
 
Reported: 2009-09-13 16:17 UTC by pc
Modified: 2015-06-09 01:26 UTC (History)
1 user (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this issue.
Description pc 2009-09-13 16:17:31 UTC
import std.stdio;

/*
  ATTEMPT TO USE NESTED "PURE" FUNCTIONS IN A TEMPLATE.

  All works fine unless you uncomment the third line in main. If you
  do, dmd 2.032 yeilds:

  pure.d(35): Error: pure nested function 'bar' cannot access mutable
  data 'fooState'

  pure.d(36): Error: pure nested function 'bar' cannot access mutable
  data 'y'

  pure.d(47): Error: template instance pure.fooPT!(char) error
  instantiating
*/


//"pure" inner function, with concrete types - ok
pure string foo(string x, string y){
  
  string fooState;

  string bar(string x){
    fooState = "hello ";
    return x ~ y;
  }

  return fooState ~ bar(x);
}

//potentially pure (?) templated version not labled as pure - ok
immutable(T)[] fooT(T)(immutable(T)[] x, immutable(T)[] y){

  immutable(T)[] fooState;

  immutable(T)[] bar(immutable(T)[] x){
    fooState = "hello ";
    return x ~ y;
  }

  return fooState ~ bar(x);

}

//attempt to make templated version pure - no dice
pure immutable(T)[] fooPT(T)(immutable(T)[] x, immutable(T)[] y){

  immutable(T)[] fooState;

  immutable(T)[] bar(immutable(T)[] x){
    fooState = "hello ";
    return x ~ y;
  }

  return fooState ~ bar(x);

}


void main(){
  writeln(foo("p", "c"));
  writeln(fooT("p", "c"));
  //writeln(fooPT("p", "c"));
Comment 1 Don 2009-09-29 23:56:55 UTC
This is happening because the nested template is being marked as pure. This 
happens in mtype.c, in TypeFunction::semantic, line 4038:
 the template function gets marked as pure/nothrow because it's taken from the 
parent scope. This is wrong, because pure/nothrow shouldn't be inherited by 
members.

PATCH: In DeclarationExp::semantic(Scope *sc), pure (and nothrow) should not be 
passed on to members. Turn it off while running semantic on those functions.

Index: expression.c
===================================================================
--- expression.c	(revision 196)
+++ expression.c	(working copy)
\@@ -4505,8 +4505,12 @@
     }
     if (!s->isVarDeclaration())
     {
+	// 'pure nothrow' is not inherited by member declarations
+        int scopePureNothrow = sc->stc & (STCpure | STCnothrow);
+	sc->stc ^= scopePureNothrow;
 	declaration->semantic(sc);
 	s->parent = sc->parent;
+	sc->stc ^= scopePureNothrow;
     }
     if (!global.errors)
     {
Comment 2 Don 2009-10-21 06:41:44 UTC
Fixed DMD2.035.