72
|
1 module dmd.VarExp;
|
|
2
|
|
3 import dmd.Expression;
|
|
4 import dmd.Declaration;
|
|
5 import dmd.InterState;
|
|
6 import dmd.OutBuffer;
|
|
7 import dmd.Loc;
|
|
8 import dmd.Scope;
|
|
9 import dmd.InlineCostState;
|
|
10 import dmd.FuncLiteralDeclaration;
|
|
11 import dmd.VarDeclaration;
|
|
12 import dmd.Dsymbol;
|
|
13 import dmd.FuncDeclaration;
|
|
14 import dmd.InlineDoState;
|
|
15 import dmd.HdrGenState;
|
|
16 import dmd.TOK;
|
|
17 import dmd.TY;
|
|
18 import dmd.STC;
|
|
19 import dmd.SymbolExp;
|
|
20 import dmd.Type;
|
|
21 import dmd.interpret.Util;
|
|
22 import dmd.backend.dt_t;
|
|
23 import dmd.expression.Util;
|
|
24
|
|
25 // Variable
|
|
26
|
0
|
27 class VarExp : SymbolExp
|
|
28 {
|
73
|
29 this(Loc loc, Declaration var, bool hasOverloads = false)
|
0
|
30 {
|
72
|
31 super(loc, TOK.TOKvar, VarExp.sizeof, var, hasOverloads);
|
|
32
|
|
33 //printf("VarExp(this = %p, '%s', loc = %s)\n", this, var.toChars(), loc.toChars());
|
|
34 //if (strcmp(var.ident.toChars(), "func") == 0) halt();
|
0
|
35 this.type = var.type;
|
|
36 }
|
|
37
|
72
|
38 override bool equals(Object o)
|
0
|
39 {
|
|
40 assert(false);
|
|
41 }
|
|
42
|
72
|
43 override Expression semantic(Scope sc)
|
0
|
44 {
|
72
|
45 FuncLiteralDeclaration fd;
|
|
46
|
|
47 version (LOGSEMANTIC) {
|
|
48 printf("VarExp.semantic(%s)\n", toChars());
|
|
49 }
|
|
50 if (!type)
|
|
51 {
|
|
52 type = var.type;
|
|
53 static if (false) {
|
|
54 if (var.storage_class & STC.STClazy)
|
|
55 {
|
|
56 TypeFunction tf = new TypeFunction(null, type, 0, LINK.LINKd);
|
|
57 type = new TypeDelegate(tf);
|
|
58 type = type.semantic(loc, sc);
|
|
59 }
|
|
60 }
|
|
61 }
|
|
62
|
|
63 /* Fix for 1161 doesn't work because it causes protection
|
|
64 * problems when instantiating imported templates passing private
|
|
65 * variables as alias template parameters.
|
|
66 */
|
|
67 //accessCheck(loc, sc, null, var);
|
|
68
|
|
69 VarDeclaration v = var.isVarDeclaration();
|
|
70 if (v)
|
|
71 {
|
|
72 static if (false) {
|
|
73 if ((v.isConst() || v.isInvariant()) && type.toBasetype().ty != TY.Tsarray && v.init)
|
|
74 {
|
|
75 ExpInitializer ei = v.init.isExpInitializer();
|
|
76 if (ei)
|
|
77 {
|
|
78 //ei.exp.implicitCastTo(sc, type).print();
|
|
79 return ei.exp.implicitCastTo(sc, type);
|
|
80 }
|
|
81 }
|
|
82 }
|
|
83 v.checkNestedReference(sc, loc);
|
|
84 version (DMDV2) {
|
|
85 static if (true) {
|
|
86 if (sc.func)
|
|
87 {
|
|
88 /* Determine if sc.func is pure or if any function that
|
|
89 * encloses it is also pure.
|
|
90 */
|
|
91 bool hasPureParent = false;
|
|
92 for (FuncDeclaration outerfunc = sc.func; outerfunc;)
|
|
93 {
|
|
94 if (outerfunc.isPure())
|
|
95 {
|
|
96 hasPureParent = true;
|
|
97 break;
|
|
98 }
|
|
99 Dsymbol parent = outerfunc.toParent2();
|
|
100 if (!parent)
|
|
101 break;
|
|
102 outerfunc = parent.isFuncDeclaration();
|
|
103 }
|
|
104
|
|
105 /* If ANY of its enclosing functions are pure,
|
|
106 * it cannot do anything impure.
|
|
107 * If it is pure, it cannot access any mutable variables other
|
|
108 * than those inside itself
|
|
109 */
|
|
110 if (hasPureParent && !sc.intypeof && v.isDataseg() && !v.isInvariant())
|
|
111 {
|
|
112 error("pure function '%s' cannot access mutable static data '%s'",
|
|
113 sc.func.toChars(), v.toChars());
|
|
114 }
|
|
115 else if (sc.func.isPure() && sc.parent != v.parent && !sc.intypeof && !v.isInvariant() && !(v.storage_class & STC.STCmanifest))
|
|
116 {
|
|
117 error("pure nested function '%s' cannot access mutable data '%s'", sc.func.toChars(), v.toChars());
|
|
118 if (v.isEnumDeclaration())
|
|
119 error("enum");
|
|
120 }
|
|
121 }
|
|
122 } else {
|
|
123 if (sc.func && sc.func.isPure() && !sc.intypeof)
|
|
124 {
|
|
125 if (v.isDataseg() && !v.isInvariant())
|
|
126 error("pure function '%s' cannot access mutable static data '%s'", sc.func.toChars(), v.toChars());
|
|
127 }
|
|
128 }
|
|
129 }
|
|
130 }
|
|
131 else
|
|
132 {
|
|
133 static if (false) {
|
|
134 if ((fd = var.isFuncLiteralDeclaration()) !is null)
|
|
135 {
|
|
136 Expression e = new FuncExp(loc, fd);
|
|
137 e.type = type;
|
|
138 return e;
|
|
139 }
|
|
140 }
|
|
141 }
|
|
142
|
0
|
143 return this;
|
|
144 }
|
|
145
|
72
|
146 override Expression optimize(int result)
|
0
|
147 {
|
|
148 return fromConstInitializer(result, this);
|
|
149 }
|
|
150
|
72
|
151 override Expression interpret(InterState istate)
|
0
|
152 {
|
72
|
153 version (LOG) {
|
|
154 printf("VarExp.interpret() %.*s\n", toChars());
|
|
155 }
|
63
|
156 return getVarExp(loc, istate, var);
|
0
|
157 }
|
|
158
|
72
|
159 override void dump(int indent)
|
0
|
160 {
|
|
161 assert(false);
|
|
162 }
|
|
163
|
72
|
164 override string toChars()
|
0
|
165 {
|
|
166 return var.toChars();
|
|
167 }
|
|
168
|
72
|
169 override void toCBuffer(OutBuffer buf, HdrGenState* hgs)
|
0
|
170 {
|
|
171 buf.writestring(var.toChars());
|
|
172 }
|
|
173
|
72
|
174 override void checkEscape()
|
0
|
175 {
|
72
|
176 VarDeclaration v = var.isVarDeclaration();
|
|
177 if (v)
|
|
178 {
|
|
179 Type tb = v.type.toBasetype();
|
|
180 // if reference type
|
|
181 if (tb.ty == TY.Tarray || tb.ty == TY.Tsarray || tb.ty == TY.Tclass)
|
|
182 {
|
|
183 if ((v.isAuto() || v.isScope()) && !v.noauto)
|
|
184 error("escaping reference to scope local %s", v.toChars());
|
|
185 else if (v.storage_class & STC.STCvariadic)
|
|
186 error("escaping reference to variadic parameter %s", v.toChars());
|
|
187 }
|
0
|
188 }
|
|
189 }
|
72
|
190
|
0
|
191 version (DMDV2) {
|
72
|
192 override int isLvalue()
|
0
|
193 {
|
72
|
194 if (var.storage_class & STClazy)
|
|
195 return 0;
|
0
|
196 return 1;
|
|
197 }
|
|
198 }
|
72
|
199 override Expression toLvalue(Scope sc, Expression e)
|
0
|
200 {
|
72
|
201 static if (false) {
|
|
202 tym = tybasic(e1.ET.Tty);
|
|
203 if (!(tyscalar(tym) ||
|
|
204 tym == TYM.TYstruct ||
|
|
205 tym == TYM.TYarray && e.Eoper == TOK.TOKaddr))
|
|
206 {
|
|
207 synerr(EM_lvalue); // lvalue expected
|
|
208 }
|
|
209 }
|
|
210 if (var.storage_class & STC.STClazy)
|
|
211 error("lazy variables cannot be lvalues");
|
|
212
|
0
|
213 return this;
|
|
214 }
|
|
215
|
72
|
216 override Expression modifiableLvalue(Scope sc, Expression e)
|
0
|
217 {
|
72
|
218 //printf("VarExp::modifiableLvalue('%s')\n", var.toChars());
|
|
219 if (type && type.toBasetype().ty == TY.Tsarray)
|
|
220 error("cannot change reference to static array '%s'", var.toChars());
|
|
221
|
|
222 var.checkModify(loc, sc, type);
|
|
223
|
|
224 // See if this expression is a modifiable lvalue (i.e. not const)
|
0
|
225 return toLvalue(sc, e);
|
|
226 }
|
|
227
|
72
|
228 override dt_t** toDt(dt_t** pdt)
|
0
|
229 {
|
|
230 assert(false);
|
|
231 }
|
|
232
|
72
|
233 override void scanForNestedRef(Scope sc)
|
0
|
234 {
|
72
|
235 //printf("VarExp.scanForNestedRef(%s)\n", toChars());
|
|
236 VarDeclaration v = var.isVarDeclaration();
|
|
237 if (v)
|
64
|
238 v.checkNestedReference(sc, Loc(0));
|
0
|
239 }
|
|
240
|
72
|
241 override int inlineCost(InlineCostState* ics)
|
0
|
242 {
|
72
|
243 //printf("VarExp.inlineCost() %s\n", toChars());
|
0
|
244 return 1;
|
|
245 }
|
|
246
|
72
|
247 override Expression doInline(InlineDoState ids)
|
0
|
248 {
|
72
|
249 int i;
|
|
250
|
|
251 //printf("VarExp.doInline(%s)\n", toChars());
|
|
252 for (i = 0; i < ids.from.dim; i++)
|
|
253 {
|
|
254 if (var == cast(Declaration)ids.from.data[i])
|
|
255 {
|
|
256 VarExp ve = cast(VarExp)copy();
|
|
257
|
|
258 ve.var = cast(Declaration)ids.to.data[i];
|
|
259 return ve;
|
|
260 }
|
|
261 }
|
0
|
262 return this;
|
|
263 }
|
|
264 }
|
|
265
|