1 /** 2 * Compiler implementation of the 3 * $(LINK2 http://www.dlang.org, D programming language). 4 * 5 * Copyright: Copyright (c) 1999-2016 by Digital Mars, All Rights Reserved 6 * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) 7 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 8 * Source: $(DMDSRC _delegatize.d) 9 */ 10 11 module ddmd.delegatize; 12 13 import core.stdc.stdio; 14 import ddmd.apply; 15 import ddmd.declaration; 16 import ddmd.dscope; 17 import ddmd.dsymbol; 18 import ddmd.expression; 19 import ddmd.func; 20 import ddmd.globals; 21 import ddmd.mtype; 22 import ddmd.statement; 23 import ddmd.tokens; 24 import ddmd.visitor; 25 26 extern (C++) Expression toDelegate(Expression e, Type t, Scope* sc) 27 { 28 //printf("Expression::toDelegate(t = %s) %s\n", t->toChars(), e->toChars()); 29 Loc loc = e.loc; 30 auto tf = new TypeFunction(null, t, 0, LINKd); 31 if (t.hasWild()) 32 tf.mod = MODwild; 33 auto fld = new FuncLiteralDeclaration(loc, loc, tf, TOKdelegate, null); 34 sc = sc.push(); 35 sc.parent = fld; // set current function to be the delegate 36 lambdaSetParent(e, sc); 37 bool r = lambdaCheckForNestedRef(e, sc); 38 sc = sc.pop(); 39 if (r) 40 return new ErrorExp(); 41 Statement s; 42 if (t.ty == Tvoid) 43 s = new ExpStatement(loc, e); 44 else 45 s = new ReturnStatement(loc, e); 46 fld.fbody = s; 47 e = new FuncExp(loc, fld); 48 e = e.semantic(sc); 49 return e; 50 } 51 52 /****************************************** 53 * Patch the parent of declarations to be the new function literal. 54 */ 55 extern (C++) void lambdaSetParent(Expression e, Scope* sc) 56 { 57 extern (C++) final class LambdaSetParent : StoppableVisitor 58 { 59 alias visit = super.visit; 60 Scope* sc; 61 62 public: 63 extern (D) this(Scope* sc) 64 { 65 this.sc = sc; 66 } 67 68 override void visit(Expression) 69 { 70 } 71 72 override void visit(DeclarationExp e) 73 { 74 e.declaration.parent = sc.parent; 75 } 76 77 override void visit(IndexExp e) 78 { 79 if (e.lengthVar) 80 { 81 //printf("lengthVar\n"); 82 e.lengthVar.parent = sc.parent; 83 } 84 } 85 86 override void visit(SliceExp e) 87 { 88 if (e.lengthVar) 89 { 90 //printf("lengthVar\n"); 91 e.lengthVar.parent = sc.parent; 92 } 93 } 94 } 95 96 scope LambdaSetParent lsp = new LambdaSetParent(sc); 97 walkPostorder(e, lsp); 98 } 99 100 /******************************************* 101 * Look for references to variables in a scope enclosing the new function literal. 102 * Returns true if error occurs. 103 */ 104 extern (C++) bool lambdaCheckForNestedRef(Expression e, Scope* sc) 105 { 106 extern (C++) final class LambdaCheckForNestedRef : StoppableVisitor 107 { 108 alias visit = super.visit; 109 public: 110 Scope* sc; 111 bool result; 112 113 extern (D) this(Scope* sc) 114 { 115 this.sc = sc; 116 } 117 118 override void visit(Expression) 119 { 120 } 121 122 override void visit(SymOffExp e) 123 { 124 VarDeclaration v = e.var.isVarDeclaration(); 125 if (v) 126 result = v.checkNestedReference(sc, Loc()); 127 } 128 129 override void visit(VarExp e) 130 { 131 VarDeclaration v = e.var.isVarDeclaration(); 132 if (v) 133 result = v.checkNestedReference(sc, Loc()); 134 } 135 136 override void visit(ThisExp e) 137 { 138 if (e.var) 139 result = e.var.checkNestedReference(sc, Loc()); 140 } 141 142 override void visit(DeclarationExp e) 143 { 144 VarDeclaration v = e.declaration.isVarDeclaration(); 145 if (v) 146 { 147 result = v.checkNestedReference(sc, Loc()); 148 if (result) 149 return; 150 /* Some expressions cause the frontend to create a temporary. 151 * For example, structs with cpctors replace the original 152 * expression e with: 153 * __cpcttmp = __cpcttmp.cpctor(e); 154 * 155 * In this instance, we need to ensure that the original 156 * expression e does not have any nested references by 157 * checking the declaration initializer too. 158 */ 159 if (v._init && v._init.isExpInitializer()) 160 { 161 Expression ie = v._init.toExpression(); 162 result = lambdaCheckForNestedRef(ie, sc); 163 } 164 } 165 } 166 } 167 168 scope LambdaCheckForNestedRef v = new LambdaCheckForNestedRef(sc); 169 walkPostorder(e, v); 170 return v.result; 171 } 172 173 bool checkNestedRef(Dsymbol s, Dsymbol p) 174 { 175 while (s) 176 { 177 if (s == p) // hit! 178 return false; 179 180 if (auto fd = s.isFuncDeclaration()) 181 { 182 if (!fd.isThis() && !fd.isNested()) 183 break; 184 185 // Bugzilla 15332: change to delegate if fd is actually nested. 186 if (auto fld = fd.isFuncLiteralDeclaration()) 187 fld.tok = TOKdelegate; 188 } 189 if (auto ad = s.isAggregateDeclaration()) 190 { 191 if (ad.storage_class & STCstatic) 192 break; 193 } 194 s = s.toParent2(); 195 } 196 return true; 197 }