Mercurial > projects > ddmd
annotate dmd/CallExp.d @ 191:52188e7e3fb5
Fixed deprecated features, now compiles with DMD2.058
Also changed Array allocation policy:
Now doesn't reallocate but malloc's, followed by a memcpy (no free).
(this fixes a crash while compiling druntime. Same bug in dmd)
author | korDen@korDen-pc |
---|---|
date | Sun, 25 Mar 2012 03:11:12 +0400 |
parents | b0d41ff5e0df |
children |
rev | line source |
---|---|
72 | 1 module dmd.CallExp; |
2 | |
114 | 3 import dmd.common; |
79 | 4 import dmd.ErrorExp; |
72 | 5 import dmd.Expression; |
6 import dmd.Cast; | |
7 import dmd.WANT; | |
8 import dmd.BUILTIN; | |
9 import dmd.TypeFunction; | |
10 import dmd.ScopeDsymbol; | |
11 import dmd.CastExp; | |
179 | 12 import dmd.FuncExp; |
13 import dmd.SymOffExp; | |
72 | 14 import dmd.GlobalExpressions; |
15 import dmd.TypePointer; | |
16 import dmd.ThisExp; | |
17 import dmd.OverExp; | |
18 import dmd.Dsymbol; | |
19 import dmd.CSX; | |
20 import dmd.AggregateDeclaration; | |
21 import dmd.TypeDelegate; | |
22 import dmd.ClassDeclaration; | |
23 import dmd.DsymbolExp; | |
24 import dmd.DotExp; | |
25 import dmd.TemplateExp; | |
26 import dmd.TypeStruct; | |
27 import dmd.TypeClass; | |
28 import dmd.Identifier; | |
29 import dmd.Lexer; | |
30 import dmd.VarDeclaration; | |
31 import dmd.DeclarationExp; | |
32 import dmd.CtorDeclaration; | |
33 import dmd.PtrExp; | |
34 import dmd.TemplateDeclaration; | |
35 import dmd.StructLiteralExp; | |
36 import dmd.StructDeclaration; | |
37 import dmd.DotTemplateExp; | |
38 import dmd.CommaExp; | |
39 import dmd.AggregateDeclaration; | |
40 import dmd.FuncDeclaration; | |
41 import dmd.Type; | |
42 import dmd.ScopeExp; | |
43 import dmd.VarExp; | |
44 import dmd.STC; | |
45 import dmd.LINK; | |
46 import dmd.Global; | |
47 import dmd.DotTemplateInstanceExp; | |
48 import dmd.TemplateInstance; | |
49 import dmd.DelegateExp; | |
50 import dmd.IdentifierExp; | |
51 import dmd.DotVarExp; | |
52 import dmd.DotIdExp; | |
53 import dmd.TY; | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
54 import dmd.TRUST; |
72 | 55 import dmd.Id; |
56 import dmd.TypeAArray; | |
57 import dmd.RemoveExp; | |
58 import dmd.backend.elem; | |
59 import dmd.UnaExp; | |
60 import dmd.InterState; | |
61 import dmd.OutBuffer; | |
62 import dmd.Loc; | |
63 import dmd.Scope; | |
64 import dmd.InlineCostState; | |
65 import dmd.IRState; | |
66 import dmd.InlineDoState; | |
67 import dmd.HdrGenState; | |
68 import dmd.InlineScanState; | |
69 import dmd.ArrayTypes; | |
70 import dmd.TOK; | |
71 import dmd.PREC; | |
72 import dmd.expression.Util; | |
73 import dmd.backend.Symbol; | |
74 import dmd.backend.TYPE; | |
75 import dmd.backend.Util; | |
76 import dmd.backend.TYM; | |
77 import dmd.codegen.Util; | |
78 | |
79 import std.stdio; | |
80 | |
187
b0d41ff5e0df
Added expandability scheme outlined in http://www.dsource.org/forums/viewtopic.php?t=5659&sid=6f2150ff5b0bffcd47512a6a7608d218
Abscissa
parents:
179
diff
changeset
|
81 import dmd.DDMDExtensions; |
b0d41ff5e0df
Added expandability scheme outlined in http://www.dsource.org/forums/viewtopic.php?t=5659&sid=6f2150ff5b0bffcd47512a6a7608d218
Abscissa
parents:
179
diff
changeset
|
82 |
0 | 83 class CallExp : UnaExp |
84 { | |
187
b0d41ff5e0df
Added expandability scheme outlined in http://www.dsource.org/forums/viewtopic.php?t=5659&sid=6f2150ff5b0bffcd47512a6a7608d218
Abscissa
parents:
179
diff
changeset
|
85 mixin insertMemberExtension!(typeof(this)); |
b0d41ff5e0df
Added expandability scheme outlined in http://www.dsource.org/forums/viewtopic.php?t=5659&sid=6f2150ff5b0bffcd47512a6a7608d218
Abscissa
parents:
179
diff
changeset
|
86 |
0 | 87 Expressions arguments; |
88 | |
89 this(Loc loc, Expression e, Expressions exps) | |
90 { | |
178 | 91 register(); |
92 | |
72 | 93 super(loc, TOK.TOKcall, CallExp.sizeof, e); |
0 | 94 this.arguments = exps; |
95 } | |
96 | |
97 this(Loc loc, Expression e) | |
98 { | |
178 | 99 register(); |
100 | |
0 | 101 super(loc, TOK.TOKcall, CallExp.sizeof, e); |
102 } | |
103 | |
104 this(Loc loc, Expression e, Expression earg1) | |
105 { | |
178 | 106 register(); |
107 | |
72 | 108 super(loc, TOK.TOKcall, CallExp.sizeof, e); |
109 | |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
79
diff
changeset
|
110 auto arguments = new Expressions(); |
96 | 111 if (earg1) |
73 | 112 { |
113 arguments.setDim(1); | |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
79
diff
changeset
|
114 arguments[0] = earg1; |
73 | 115 } |
0 | 116 this.arguments = arguments; |
117 } | |
118 | |
119 this(Loc loc, Expression e, Expression earg1, Expression earg2) | |
72 | 120 { |
178 | 121 register(); |
122 | |
72 | 123 super(loc, TOK.TOKcall, CallExp.sizeof, e); |
66 | 124 |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
79
diff
changeset
|
125 auto arguments = new Expressions(); |
72 | 126 arguments.setDim(2); |
90
39648eb578f6
more Expressions work
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
84
diff
changeset
|
127 arguments[0] = earg1; |
39648eb578f6
more Expressions work
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
84
diff
changeset
|
128 arguments[1] = earg2; |
72 | 129 |
66 | 130 this.arguments = arguments; |
0 | 131 } |
132 | |
72 | 133 override Expression syntaxCopy() |
0 | 134 { |
135 return new CallExp(loc, e1.syntaxCopy(), arraySyntaxCopy(arguments)); | |
136 } | |
137 | |
72 | 138 override Expression semantic(Scope sc) |
139 { | |
140 TypeFunction tf; | |
141 FuncDeclaration f; | |
142 Type t1; | |
143 int istemp; | |
144 Objects targsi; // initial list of template arguments | |
145 TemplateInstance tierror; | |
146 | |
79 | 147 version (LOGSEMANTIC) |
148 { | |
72 | 149 printf("CallExp.semantic() %s\n", toChars()); |
150 } | |
151 if (type) | |
152 return this; // semantic() already run | |
153 | |
79 | 154 static if (false) |
155 { | |
72 | 156 if (arguments && arguments.dim) |
157 { | |
158 Expression earg = cast(Expression)arguments.data[0]; | |
159 earg.print(); | |
160 if (earg.type) earg.type.print(); | |
161 } | |
162 } | |
163 | |
164 if (e1.op == TOK.TOKdelegate) | |
165 { | |
166 DelegateExp de = cast(DelegateExp)e1; | |
167 | |
168 e1 = new DotVarExp(de.loc, de.e1, de.func); | |
169 return semantic(sc); | |
170 } | |
171 | |
172 /* Transform: | |
173 * array.id(args) into .id(array,args) | |
174 * aa.remove(arg) into delete aa[arg] | |
175 */ | |
176 if (e1.op == TOK.TOKdot) | |
177 { | |
178 // BUG: we should handle array.a.b.c.e(args) too | |
179 | |
180 DotIdExp dotid = cast(DotIdExp)(e1); | |
181 dotid.e1 = dotid.e1.semantic(sc); | |
182 assert(dotid.e1); | |
183 if (dotid.e1.type) | |
184 { | |
185 TY e1ty = dotid.e1.type.toBasetype().ty; | |
186 if (e1ty == TY.Taarray && dotid.ident == Id.remove) | |
187 { | |
188 if (!arguments || arguments.dim != 1) | |
189 { | |
190 error("expected key as argument to aa.remove()"); | |
191 goto Lagain; | |
192 } | |
90
39648eb578f6
more Expressions work
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
84
diff
changeset
|
193 auto key = arguments[0]; |
72 | 194 key = key.semantic(sc); |
195 key = resolveProperties(sc, key); | |
196 key.rvalue(); | |
197 | |
90
39648eb578f6
more Expressions work
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
84
diff
changeset
|
198 auto taa = cast(TypeAArray)dotid.e1.type.toBasetype(); |
72 | 199 key = key.implicitCastTo(sc, taa.index); |
200 | |
201 return new RemoveExp(loc, dotid.e1, key); | |
202 } | |
109 | 203 else if (e1ty == TY.Tarray || e1ty == TY.Tsarray || |
204 (e1ty == Taarray && dotid.ident != Id.apply && dotid.ident != Id.applyReverse)) | |
72 | 205 { |
206 if (!arguments) | |
207 arguments = new Expressions(); | |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
79
diff
changeset
|
208 arguments.shift(dotid.e1); |
72 | 209 version (DMDV2) { |
210 e1 = new DotIdExp(dotid.loc, new IdentifierExp(dotid.loc, Id.empty), dotid.ident); | |
211 } else { | |
212 e1 = new IdentifierExp(dotid.loc, dotid.ident); | |
213 } | |
214 } | |
215 } | |
216 } | |
217 | |
218 static if (true) { | |
219 /* This recognizes: | |
220 * foo!(tiargs)(funcargs) | |
221 */ | |
222 if (e1.op == TOK.TOKimport && !e1.type) | |
223 { | |
224 ScopeExp se = cast(ScopeExp)e1; | |
225 TemplateInstance ti = se.sds.isTemplateInstance(); | |
226 if (ti && !ti.semanticRun) | |
227 { | |
228 /* Attempt to instantiate ti. If that works, go with it. | |
229 * If not, go with partial explicit specialization. | |
230 */ | |
231 ti.semanticTiargs(sc); | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
232 if (ti.needsTypeInference(sc)) |
72 | 233 { |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
234 /* Go with partial explicit specialization |
72 | 235 */ |
236 targsi = ti.tiargs; | |
237 tierror = ti; // for error reporting | |
238 e1 = new IdentifierExp(loc, ti.name); | |
239 } | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
240 else |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
241 { |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
242 ti.semantic(sc); |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
243 } |
72 | 244 } |
245 } | |
246 | |
247 /* This recognizes: | |
248 * expr.foo!(tiargs)(funcargs) | |
249 */ | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
250 Ldotti: |
72 | 251 if (e1.op == TOK.TOKdotti && !e1.type) |
252 { | |
253 DotTemplateInstanceExp se = cast(DotTemplateInstanceExp)e1; | |
254 TemplateInstance ti = se.ti; | |
255 if (!ti.semanticRun) | |
256 { | |
257 /* Attempt to instantiate ti. If that works, go with it. | |
258 * If not, go with partial explicit specialization. | |
259 */ | |
260 ti.semanticTiargs(sc); | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
261 static if (false) { |
72 | 262 Expression etmp = e1.trySemantic(sc); |
263 if (etmp) | |
264 e1 = etmp; // it worked | |
265 else // didn't work | |
266 { | |
267 targsi = ti.tiargs; | |
268 tierror = ti; // for error reporting | |
269 e1 = new DotIdExp(loc, se.e1, ti.name); | |
270 } | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
271 } else { |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
272 if (!ti.tempdecl) |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
273 { |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
274 se.getTempdecl(sc); |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
275 } |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
276 if (ti.tempdecl && ti.needsTypeInference(sc)) |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
277 { |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
278 /* Go with partial explicit specialization |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
279 */ |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
280 targsi = ti.tiargs; |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
281 tierror = ti; // for error reporting |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
282 e1 = new DotIdExp(loc, se.e1, ti.name); |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
283 } |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
284 else |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
285 { |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
286 e1 = e1.semantic(sc); |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
287 } |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
288 } |
72 | 289 } |
290 } | |
291 } | |
292 | |
293 istemp = 0; | |
294 Lagain: | |
295 //printf("Lagain: %s\n", toChars()); | |
296 f = null; | |
297 if (e1.op == TOK.TOKthis || e1.op == TOK.TOKsuper) | |
298 { | |
299 // semantic() run later for these | |
300 } | |
301 else | |
302 { | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
303 if (e1.op == TOK.TOKdot) |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
304 { |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
305 auto die = cast(DotIdExp)e1; |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
306 e1 = die.semantic(sc, 1); |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
307 /* Look for e1 having been rewritten to expr.opDispatch!(string) |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
308 * We handle such earlier, so go back. |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
309 * Note that in the rewrite, we carefully did not run semantic() on e1 |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
310 */ |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
311 if (e1.op == TOK.TOKdotti && !e1.type) |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
312 { |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
313 goto Ldotti; |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
314 } |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
315 } |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
316 else |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
317 UnaExp.semantic(sc); |
72 | 318 |
319 /* Look for e1 being a lazy parameter | |
320 */ | |
321 if (e1.op == TOK.TOKvar) | |
322 { | |
323 VarExp ve = cast(VarExp)e1; | |
324 | |
325 if (ve.var.storage_class & STC.STClazy) | |
326 { | |
327 TypeFunction tff = new TypeFunction(null, ve.var.type, 0, LINK.LINKd); | |
328 TypeDelegate t = new TypeDelegate(tff); | |
329 ve.type = t.semantic(loc, sc); | |
330 } | |
331 } | |
332 | |
333 if (e1.op == TOK.TOKimport) | |
334 { | |
335 // Perhaps this should be moved to ScopeExp.semantic() | |
336 ScopeExp se = cast(ScopeExp)e1; | |
337 e1 = new DsymbolExp(loc, se.sds); | |
338 e1 = e1.semantic(sc); | |
339 } | |
340 ///static if (true) { // patch for #540 by Oskar Linde | |
341 else if (e1.op == TOK.TOKdotexp) | |
342 { | |
343 DotExp de = cast(DotExp)e1; | |
344 | |
345 if (de.e2.op == TOK.TOKimport) | |
346 { | |
347 // This should *really* be moved to ScopeExp.semantic() | |
348 ScopeExp se = cast(ScopeExp)de.e2; | |
349 de.e2 = new DsymbolExp(loc, se.sds); | |
350 de.e2 = de.e2.semantic(sc); | |
351 } | |
352 | |
353 if (de.e2.op == TOK.TOKtemplate) | |
354 { | |
355 TemplateExp te = cast(TemplateExp)de.e2; | |
356 e1 = new DotTemplateExp(loc,de.e1,te.td); | |
357 } | |
358 } | |
359 ///} | |
360 } | |
361 | |
362 if (e1.op == TOK.TOKcomma) | |
363 { | |
364 CommaExp ce = cast(CommaExp)e1; | |
365 | |
366 e1 = ce.e2; | |
367 e1.type = ce.type; | |
368 ce.e2 = this; | |
369 ce.type = null; | |
370 return ce.semantic(sc); | |
371 } | |
372 | |
373 t1 = null; | |
374 if (e1.type) | |
375 t1 = e1.type.toBasetype(); | |
376 | |
377 // Check for call operator overload | |
378 if (t1) | |
379 { | |
380 AggregateDeclaration ad; | |
381 | |
382 if (t1.ty == TY.Tstruct) | |
383 { | |
384 ad = (cast(TypeStruct)t1).sym; | |
385 version (DMDV2) { | |
386 // First look for constructor | |
387 if (ad.ctor && arguments && arguments.dim) | |
388 { | |
389 // Create variable that will get constructed | |
390 Identifier idtmp = Lexer.uniqueId("__ctmp"); | |
391 VarDeclaration tmp = new VarDeclaration(loc, t1, idtmp, null); | |
179 | 392 tmp.storage_class |= STCctfe; |
72 | 393 Expression av = new DeclarationExp(loc, tmp); |
394 av = new CommaExp(loc, av, new VarExp(loc, tmp)); | |
395 | |
396 Expression e; | |
397 CtorDeclaration cf = ad.ctor.isCtorDeclaration(); | |
398 if (cf) | |
399 e = new DotVarExp(loc, av, cf, 1); | |
400 else | |
401 { | |
402 TemplateDeclaration td = ad.ctor.isTemplateDeclaration(); | |
403 assert(td); | |
404 e = new DotTemplateExp(loc, av, td); | |
405 } | |
406 e = new CallExp(loc, e, arguments); | |
407 version (STRUCTTHISREF) { | |
408 } else { | |
409 /* Constructors return a pointer to the instance | |
410 */ | |
411 e = new PtrExp(loc, e); | |
412 } | |
413 e = e.semantic(sc); | |
414 return e; | |
415 } | |
416 } | |
417 // No constructor, look for overload of opCall | |
418 if (search_function(ad, Id.call)) | |
419 goto L1; // overload of opCall, therefore it's a call | |
420 | |
421 if (e1.op != TOK.TOKtype) | |
422 error("%s %s does not overload ()", ad.kind(), ad.toChars()); | |
423 | |
424 /* It's a struct literal | |
425 */ | |
426 Expression e = new StructLiteralExp(loc, cast(StructDeclaration)ad, arguments); | |
427 e = e.semantic(sc); | |
428 e.type = e1.type; // in case e1.type was a typedef | |
429 return e; | |
430 } | |
431 else if (t1.ty == TY.Tclass) | |
432 { | |
433 ad = (cast(TypeClass)t1).sym; | |
434 goto L1; | |
435 L1: | |
436 // Rewrite as e1.call(arguments) | |
437 Expression e = new DotIdExp(loc, e1, Id.call); | |
438 e = new CallExp(loc, e, arguments); | |
439 e = e.semantic(sc); | |
440 return e; | |
441 } | |
442 } | |
443 | |
444 arrayExpressionSemantic(arguments, sc); | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
445 preFunctionParameters(loc, sc, arguments); |
72 | 446 |
447 if (e1.op == TOK.TOKdotvar && t1.ty == TY.Tfunction || | |
448 e1.op == TOK.TOKdottd) | |
449 { | |
450 DotVarExp dve; | |
451 DotTemplateExp dte; | |
452 AggregateDeclaration ad; | |
453 UnaExp ue = cast(UnaExp)e1; | |
454 | |
455 if (e1.op == TOK.TOKdotvar) | |
456 { | |
457 // Do overload resolution | |
458 dve = cast(DotVarExp)e1; | |
459 | |
460 f = dve.var.isFuncDeclaration(); | |
461 assert(f); | |
462 f = f.overloadResolve(loc, ue.e1, arguments); | |
463 | |
464 ad = f.toParent().isAggregateDeclaration(); | |
465 } | |
466 else | |
467 { | |
468 dte = cast(DotTemplateExp)e1; | |
469 TemplateDeclaration td = dte.td; | |
470 assert(td); | |
471 | |
472 if (!arguments) | |
473 // Should fix deduceFunctionTemplate() so it works on null argument | |
474 arguments = new Expressions(); | |
475 | |
476 f = td.deduceFunctionTemplate(sc, loc, targsi, ue.e1, arguments); | |
477 if (!f) | |
478 { | |
479 type = Type.terror; | |
480 return this; | |
481 } | |
482 ad = td.toParent().isAggregateDeclaration(); | |
483 } | |
484 | |
485 if (f.needThis()) | |
486 { | |
487 ue.e1 = getRightThis(loc, sc, ad, ue.e1, f); | |
488 } | |
489 | |
490 /* Cannot call public functions from inside invariant | |
491 * (because then the invariant would have infinite recursion) | |
492 */ | |
493 if (sc.func && sc.func.isInvariantDeclaration() && | |
494 ue.e1.op == TOK.TOKthis && f.addPostInvariant()) | |
495 { | |
496 error("cannot call public/export function %s from invariant", f.toChars()); | |
497 } | |
498 | |
499 checkDeprecated(sc, f); | |
500 version (DMDV2) { | |
501 checkPurity(sc, f); | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
502 checkSafety(sc, f); |
72 | 503 } |
504 accessCheck(loc, sc, ue.e1, f); | |
505 if (!f.needThis()) | |
506 { | |
507 VarExp ve = new VarExp(loc, f); | |
508 e1 = new CommaExp(loc, ue.e1, ve); | |
509 e1.type = f.type; | |
510 } | |
511 else | |
512 { | |
513 if (e1.op == TOK.TOKdotvar) | |
514 dve.var = f; | |
515 else | |
516 e1 = new DotVarExp(loc, dte.e1, f); | |
517 | |
518 e1.type = f.type; | |
519 static if (false) { | |
520 printf("ue.e1 = %s\n", ue.e1.toChars()); | |
521 printf("f = %s\n", f.toChars()); | |
522 printf("t = %s\n", t.toChars()); | |
523 printf("e1 = %s\n", e1.toChars()); | |
524 printf("e1.type = %s\n", e1.type.toChars()); | |
525 } | |
135 | 526 // Const member function can take const/immutable/mutable/inout this |
72 | 527 if (!(f.type.isConst())) |
528 { | |
529 // Check for const/immutable compatibility | |
530 Type tthis = ue.e1.type.toBasetype(); | |
531 if (tthis.ty == TY.Tpointer) | |
532 tthis = tthis.nextOf().toBasetype(); | |
533 | |
534 static if (false) { // this checking should have been already done | |
135 | 535 if (f.type.isImmutable()) |
72 | 536 { |
135 | 537 if (tthis.mod != MOD.MODimmutable) |
72 | 538 error("%s can only be called with an immutable object", e1.toChars()); |
539 } | |
540 else if (f.type.isShared()) | |
541 { | |
135 | 542 if (tthis.mod != MOD.MODimmutable && tthis.mod != MOD.MODshared && tthis.mod != (MOD.MODshared | MOD.MODconst)) |
72 | 543 error("shared %s can only be called with a shared or immutable object", e1.toChars()); |
544 } | |
545 else | |
546 { | |
547 if (tthis.mod != MOD.MODundefined) | |
548 { | |
549 //printf("mod = %x\n", tthis.mod); | |
550 error("%s can only be called with a mutable object, not %s", e1.toChars(), tthis.toChars()); | |
551 } | |
552 } | |
553 } | |
554 /* Cannot call mutable method on a final struct | |
555 */ | |
556 if (tthis.ty == TY.Tstruct && | |
557 ue.e1.op == TOK.TOKvar) | |
558 { | |
559 VarExp v = cast(VarExp)ue.e1; | |
560 if (v.var.storage_class & STC.STCfinal) | |
561 error("cannot call mutable method on final struct"); | |
562 } | |
563 } | |
564 | |
565 // See if we need to adjust the 'this' pointer | |
566 AggregateDeclaration add = f.isThis(); | |
567 ClassDeclaration cd = ue.e1.type.isClassHandle(); | |
568 if (add && cd && add.isClassDeclaration() && add != cd && ue.e1.op != TOK.TOKsuper) | |
569 { | |
570 ue.e1 = ue.e1.castTo(sc, add.type); //new CastExp(loc, ue.e1, add.type); | |
571 ue.e1 = ue.e1.semantic(sc); | |
572 } | |
573 } | |
574 t1 = e1.type; | |
575 } | |
576 else if (e1.op == TOK.TOKsuper) | |
577 { | |
578 // Base class constructor call | |
579 ClassDeclaration cd = null; | |
580 | |
581 if (sc.func) | |
582 cd = sc.func.toParent().isClassDeclaration(); | |
583 if (!cd || !cd.baseClass || !sc.func.isCtorDeclaration()) | |
584 { | |
585 error("super class constructor call must be in a constructor"); | |
586 type = Type.terror; | |
587 return this; | |
588 } | |
589 else | |
590 { | |
591 if (!cd.baseClass.ctor) | |
592 { | |
593 error("no super class constructor for %s", cd.baseClass.toChars()); | |
594 type = Type.terror; | |
595 return this; | |
596 } | |
597 else | |
598 { | |
599 if (!sc.intypeof) | |
600 { | |
601 static if (false) { | |
602 if (sc.callSuper & (CSX.CSXthis | CSX.CSXsuper)) | |
603 error("reference to this before super()"); | |
604 } | |
605 if (sc.noctor || sc.callSuper & CSX.CSXlabel) | |
606 error("constructor calls not allowed in loops or after labels"); | |
607 if (sc.callSuper & (CSX.CSXsuper_ctor | CSX.CSXthis_ctor)) | |
608 error("multiple constructor calls"); | |
609 sc.callSuper |= CSX.CSXany_ctor | CSX.CSXsuper_ctor; | |
610 } | |
611 | |
612 f = resolveFuncCall(sc, loc, cd.baseClass.ctor, null, null, arguments, 0); | |
613 checkDeprecated(sc, f); | |
614 version (DMDV2) { | |
615 checkPurity(sc, f); | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
616 checkSafety(sc, f); |
72 | 617 } |
618 e1 = new DotVarExp(e1.loc, e1, f); | |
619 e1 = e1.semantic(sc); | |
620 t1 = e1.type; | |
621 } | |
622 } | |
623 } | |
624 else if (e1.op == TOK.TOKthis) | |
625 { | |
626 // same class constructor call | |
627 AggregateDeclaration cd = null; | |
628 | |
629 if (sc.func) | |
630 cd = sc.func.toParent().isAggregateDeclaration(); | |
631 if (!cd || !sc.func.isCtorDeclaration()) | |
632 { | |
633 error("constructor call must be in a constructor"); | |
634 type = Type.terror; | |
635 return this; | |
636 } | |
637 else | |
638 { | |
639 if (!sc.intypeof) | |
640 { | |
641 static if (false) { | |
642 if (sc.callSuper & (CSXthis | CSXsuper)) | |
643 error("reference to this before super()"); | |
644 } | |
645 if (sc.noctor || sc.callSuper & CSX.CSXlabel) | |
646 error("constructor calls not allowed in loops or after labels"); | |
647 if (sc.callSuper & (CSX.CSXsuper_ctor | CSX.CSXthis_ctor)) | |
648 error("multiple constructor calls"); | |
649 sc.callSuper |= CSX.CSXany_ctor | CSX.CSXthis_ctor; | |
650 } | |
651 | |
652 f = resolveFuncCall(sc, loc, cd.ctor, null, null, arguments, 0); | |
653 checkDeprecated(sc, f); | |
654 version (DMDV2) { | |
655 checkPurity(sc, f); | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
656 checkSafety(sc, f); |
72 | 657 } |
658 e1 = new DotVarExp(e1.loc, e1, f); | |
659 e1 = e1.semantic(sc); | |
660 t1 = e1.type; | |
661 | |
662 // BUG: this should really be done by checking the static | |
663 // call graph | |
664 if (f == sc.func) | |
665 error("cyclic constructor call"); | |
666 } | |
667 } | |
668 else if (e1.op == TOK.TOKoverloadset) | |
669 { | |
670 OverExp eo = cast(OverExp)e1; | |
671 FuncDeclaration ff = null; | |
79 | 672 Dsymbol s = null; |
673 for(size_t i = 0; i<eo.vars.a.dim; i++) | |
674 { | |
675 s = eo.vars.a[i]; | |
72 | 676 FuncDeclaration f2 = s.isFuncDeclaration(); |
677 if (f2) | |
678 { | |
679 f2 = f2.overloadResolve(loc, null, arguments, 1); | |
680 } | |
681 else | |
682 { | |
683 TemplateDeclaration td = s.isTemplateDeclaration(); | |
684 assert(td); | |
685 f2 = td.deduceFunctionTemplate(sc, loc, targsi, null, arguments, 1); | |
686 } | |
687 if (f2) | |
688 { | |
689 if (ff) | |
690 /* Error if match in more than one overload set, | |
691 * even if one is a 'better' match than the other. | |
692 */ | |
693 ScopeDsymbol.multiplyDefined(loc, ff, f2); | |
694 else | |
695 ff = f2; | |
696 } | |
697 } | |
698 if (!ff) | |
79 | 699 { |
700 // No overload matches | |
701 error("no overload matches for %s", s.toChars()); | |
702 return new ErrorExp(); | |
72 | 703 } |
704 e1 = new VarExp(loc, ff); | |
705 goto Lagain; | |
706 } | |
707 else if (!t1) | |
708 { | |
709 error("function expected before (), not '%s'", e1.toChars()); | |
710 type = Type.terror; | |
711 return this; | |
712 } | |
713 else if (t1.ty != TY.Tfunction) | |
714 { | |
715 if (t1.ty == TY.Tdelegate) | |
716 { | |
717 TypeDelegate td = cast(TypeDelegate)t1; | |
718 assert(td.next.ty == TY.Tfunction); | |
719 tf = cast(TypeFunction)(td.next); | |
720 if (sc.func && sc.func.isPure() && !tf.ispure) | |
721 { | |
722 error("pure function '%s' cannot call impure delegate '%s'", sc.func.toChars(), e1.toChars()); | |
723 } | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
724 if (sc.func && sc.func.isSafe() && tf.trust <= TRUST.TRUSTsystem) |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
725 { |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
726 error("safe function '%s' cannot call system delegate '%s'", sc.func.toChars(), e1.toChars()); |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
727 } |
72 | 728 goto Lcheckargs; |
729 } | |
730 else if (t1.ty == TY.Tpointer && (cast(TypePointer)t1).next.ty == TY.Tfunction) | |
731 { | |
732 Expression e = new PtrExp(loc, e1); | |
733 t1 = (cast(TypePointer)t1).next; | |
734 if (sc.func && sc.func.isPure() && !(cast(TypeFunction)t1).ispure) | |
735 { | |
736 error("pure function '%s' cannot call impure function pointer '%s'", sc.func.toChars(), e1.toChars()); | |
737 } | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
738 if (sc.func && sc.func.isSafe() && !(cast(TypeFunction)t1).trust <= TRUST.TRUSTsystem) |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
739 { |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
740 error("safe function '%s' cannot call system function pointer '%s'", sc.func.toChars(), e1.toChars()); |
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
741 } |
72 | 742 e.type = t1; |
743 e1 = e; | |
744 } | |
745 else if (e1.op == TOK.TOKtemplate) | |
746 { | |
747 TemplateExp te = cast(TemplateExp)e1; | |
748 f = te.td.deduceFunctionTemplate(sc, loc, targsi, null, arguments); | |
749 if (!f) | |
750 { | |
751 if (tierror) | |
752 tierror.error("errors instantiating template"); // give better error message | |
753 type = Type.terror; | |
754 return this; | |
755 } | |
756 if (f.needThis() && hasThis(sc)) | |
757 { | |
758 // Supply an implicit 'this', as in | |
759 // this.ident | |
760 | |
761 e1 = new DotTemplateExp(loc, (new ThisExp(loc)).semantic(sc), te.td); | |
762 goto Lagain; | |
763 } | |
764 | |
765 e1 = new VarExp(loc, f); | |
766 goto Lagain; | |
767 } | |
768 else | |
769 { | |
770 error("function expected before (), not %s of type %s", e1.toChars(), e1.type.toChars()); | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
771 return new ErrorExp(); |
72 | 772 } |
773 } | |
774 else if (e1.op == TOK.TOKvar) | |
775 { | |
776 // Do overload resolution | |
777 VarExp ve = cast(VarExp)e1; | |
778 | |
779 f = ve.var.isFuncDeclaration(); | |
780 assert(f); | |
781 | |
782 if (ve.hasOverloads) | |
783 f = f.overloadResolve(loc, null, arguments); | |
784 | |
785 checkDeprecated(sc, f); | |
786 version (DMDV2) { | |
787 checkPurity(sc, f); | |
130
60bb0fe4563e
dmdfe 2.037 first main iteration
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
114
diff
changeset
|
788 checkSafety(sc, f); |
72 | 789 } |
790 | |
791 if (f.needThis() && hasThis(sc)) | |
792 { | |
793 // Supply an implicit 'this', as in | |
794 // this.ident | |
795 | |
796 e1 = new DotVarExp(loc, new ThisExp(loc), f); | |
797 goto Lagain; | |
798 } | |
799 | |
800 accessCheck(loc, sc, null, f); | |
801 | |
802 ve.var = f; | |
73 | 803 // ve.hasOverloads = false; |
72 | 804 ve.type = f.type; |
805 t1 = f.type; | |
806 } | |
807 assert(t1.ty == TY.Tfunction); | |
808 tf = cast(TypeFunction)t1; | |
809 | |
810 Lcheckargs: | |
811 assert(tf.ty == TY.Tfunction); | |
812 | |
813 if (!arguments) | |
814 arguments = new Expressions(); | |
815 | |
135 | 816 type = functionParameters(loc, sc, tf, arguments); |
72 | 817 |
818 if (!type) | |
819 { | |
820 error("forward reference to inferred return type of function call %s", toChars()); | |
821 type = Type.terror; | |
822 } | |
823 | |
824 if (f && f.tintro) | |
825 { | |
826 Type t = type; | |
827 int offset = 0; | |
828 TypeFunction tff = cast(TypeFunction)f.tintro; | |
829 | |
830 if (tff.next.isBaseOf(t, &offset) && offset) | |
831 { | |
832 type = tff.next; | |
833 return castTo(sc, t); | |
834 } | |
835 } | |
836 | |
837 return this; | |
0 | 838 } |
839 | |
72 | 840 override Expression optimize(int result) |
0 | 841 { |
96 | 842 // writef("CallExp::optimize(result = %d) %s\n", result, toChars()); |
72 | 843 Expression e = this; |
844 | |
845 // Optimize parameters | |
846 if (arguments) | |
847 { | |
84
be2ab491772e
Expressions -> Vector!Expression
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
79
diff
changeset
|
848 foreach (ref Expression ee; arguments) |
72 | 849 { |
850 ee = ee.optimize(WANT.WANTvalue); | |
851 } | |
852 } | |
853 | |
854 e1 = e1.optimize(result); | |
179 | 855 static if (true) { |
856 if (result & WANTinterpret) | |
857 { | |
858 Expression eresult = interpret(null); | |
859 if (eresult is EXP_CANT_INTERPRET) | |
860 return e; | |
861 if (eresult && eresult !is EXP_VOID_INTERPRET) | |
862 e = eresult; | |
863 else | |
864 error("cannot evaluate %s at compile time", toChars()); | |
865 } | |
866 } else { | |
72 | 867 if (e1.op == TOK.TOKvar) |
868 { | |
869 FuncDeclaration fd = (cast(VarExp)e1).var.isFuncDeclaration(); | |
870 if (fd) | |
871 { | |
872 BUILTIN b = fd.isBuiltin(); | |
873 if (b) | |
874 { | |
875 e = eval_builtin(b, arguments); | |
876 if (!e) // failed | |
877 e = this; // evaluate at runtime | |
878 } | |
879 else if (result & WANT.WANTinterpret) | |
880 { | |
881 Expression eresult = fd.interpret(null, arguments); | |
882 if (eresult && eresult !is EXP_VOID_INTERPRET) | |
883 e = eresult; | |
884 else | |
885 error("cannot evaluate %s at compile time", toChars()); | |
886 } | |
887 } | |
888 } | |
96 | 889 else if (e1.op == TOKdotvar && result & WANTinterpret) |
890 { | |
891 DotVarExp dve = cast(DotVarExp) e1; | |
892 FuncDeclaration fd = dve.var.isFuncDeclaration(); | |
893 if (fd) | |
894 { | |
895 Expression eresult = fd.interpret(null, arguments, dve.e1); | |
896 if (eresult && eresult != EXP_VOID_INTERPRET) | |
897 e = eresult; | |
898 else | |
899 error("cannot evaluate %s at compile time", toChars()); | |
900 } | |
901 } | |
179 | 902 } |
0 | 903 return e; |
904 } | |
905 | |
72 | 906 override Expression interpret(InterState istate) |
0 | 907 { |
72 | 908 Expression e = EXP_CANT_INTERPRET; |
909 | |
910 version (LOG) { | |
911 printf("CallExp.interpret() %.*s\n", toChars()); | |
912 } | |
179 | 913 Expression pthis = null; |
914 FuncDeclaration fd = null; | |
915 Expression ecall = e1; | |
916 if (ecall.op == TOKindex) | |
917 ecall = e1.interpret(istate); | |
918 if (ecall.op == TOKdotvar && !(cast(DotVarExp)ecall).var.isFuncDeclaration()) | |
919 ecall = e1.interpret(istate); | |
920 | |
921 if (ecall.op == TOKdotvar) | |
922 { // Calling a member function | |
923 pthis = (cast(DotVarExp)e1).e1; | |
924 fd = (cast(DotVarExp)e1).var.isFuncDeclaration(); | |
925 } | |
926 else if (ecall.op == TOKvar) | |
72 | 927 { |
179 | 928 VarDeclaration vd = (cast(VarExp)ecall).var.isVarDeclaration(); |
929 if (vd && vd.value) | |
930 ecall = vd.value; | |
931 else // Calling a function | |
932 fd = (cast(VarExp)e1).var.isFuncDeclaration(); | |
933 } | |
934 if (ecall.op == TOKdelegate) | |
935 { | |
936 // Calling a delegate | |
937 fd = (cast(DelegateExp)ecall).func; | |
938 pthis = (cast(DelegateExp)ecall).e1; | |
939 } | |
940 else if (ecall.op == TOKfunction) | |
941 { // Calling a delegate literal | |
942 fd = (cast(FuncExp)ecall).fd; | |
943 } | |
944 else if (ecall.op == TOKstar && (cast(PtrExp)ecall).e1.op == TOKfunction) | |
945 { // Calling a function literal | |
946 fd = (cast(FuncExp)(cast(PtrExp)ecall).e1).fd; | |
947 } | |
948 else if (ecall.op == TOKstar && (cast(PtrExp*)ecall).e1.op==TOKvar) | |
949 { // Calling a function pointer | |
950 VarDeclaration vd = (cast(VarExp)(cast(PtrExp*)ecall).e1).var.isVarDeclaration(); | |
951 if (vd && vd.value && vd.value.op == TOKsymoff) | |
952 fd = (cast(SymOffExp)vd.value).var.isFuncDeclaration(); | |
953 } | |
954 | |
955 TypeFunction tf = fd ? cast(TypeFunction)(fd.type) : null; | |
956 if (!tf) | |
957 { | |
958 // DAC: I'm not sure if this ever happens | |
959 //printf("ecall=%s %d %d\n", ecall->toChars(), ecall->op, TOKcall); | |
960 error("cannot evaluate %s at compile time", toChars()); | |
961 return EXP_CANT_INTERPRET; | |
962 } | |
963 if (pthis && fd) | |
964 { | |
965 // Member function call | |
966 if (pthis.op == TOKthis) | |
967 pthis = istate.localThis; | |
968 else if (pthis.op == TOKcomma) | |
969 pthis = pthis.interpret(istate); | |
970 Expression eresult = fd.interpret(istate, arguments, pthis); | |
971 if (eresult) | |
972 e = eresult; | |
973 else if (fd.type.toBasetype().nextOf().ty == Tvoid && !global.errors) | |
974 e = EXP_VOID_INTERPRET; | |
975 else | |
976 error("cannot evaluate %s at compile time", toChars()); | |
977 return e; | |
978 } | |
979 else if (fd) | |
980 { // function call | |
981 | |
982 ///version (DMDV2) { | |
983 BUILTIN b = fd.isBuiltin(); | |
984 if (b) | |
985 { | |
986 scope Expressions args = new Expressions(); | |
987 args.setDim(arguments.dim); | |
988 for (size_t i = 0; i < args.dim; i++) | |
989 { | |
990 auto earg = arguments[i]; | |
991 earg = earg.interpret(istate); | |
992 if (earg == EXP_CANT_INTERPRET) | |
993 return earg; | |
994 args[i] = earg; | |
995 } | |
996 e = eval_builtin(b, args); | |
997 if (!e) | |
998 e = EXP_CANT_INTERPRET; | |
999 } | |
1000 else | |
1001 ///} | |
1002 // Inline .dup | |
1003 if (fd.ident == Id.adDup && arguments && arguments.dim == 2) | |
1004 { | |
1005 e = arguments[1]; | |
1006 e = e.interpret(istate); | |
1007 if (e !is EXP_CANT_INTERPRET) | |
1008 { | |
1009 e = expType(type, e); | |
1010 } | |
1011 } | |
1012 else | |
1013 { | |
1014 Expression eresult = fd.interpret(istate, arguments); | |
72 | 1015 if (eresult) |
1016 e = eresult; | |
1017 else if (fd.type.toBasetype().nextOf().ty == Tvoid && !global.errors) | |
1018 e = EXP_VOID_INTERPRET; | |
1019 else | |
1020 error("cannot evaluate %s at compile time", toChars()); | |
1021 } | |
1022 } | |
179 | 1023 else |
1024 { | |
1025 error("cannot evaluate %s at compile time", toChars()); | |
1026 return EXP_CANT_INTERPRET; | |
1027 } | |
1028 | |
63 | 1029 return e; |
0 | 1030 } |
1031 | |
72 | 1032 override bool checkSideEffect(int flag) |
0 | 1033 { |
72 | 1034 version (DMDV2) { |
1035 if (flag != 2) | |
1036 return true; | |
1037 | |
1038 if (e1.checkSideEffect(2)) | |
1039 return true; | |
1040 | |
1041 /* If any of the arguments have side effects, this expression does | |
1042 */ | |
90
39648eb578f6
more Expressions work
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
84
diff
changeset
|
1043 foreach (e; arguments) |
72 | 1044 { |
1045 if (e.checkSideEffect(2)) | |
1046 return true; | |
1047 } | |
1048 | |
1049 /* If calling a function or delegate that is typed as pure, | |
1050 * then this expression has no side effects. | |
1051 */ | |
1052 Type t = e1.type.toBasetype(); | |
1053 if (t.ty == TY.Tfunction && (cast(TypeFunction)t).ispure) | |
1054 return false; | |
1055 if (t.ty == TY.Tdelegate && (cast(TypeFunction)(cast(TypeDelegate)t).next).ispure) | |
1056 return false; | |
1057 } | |
0 | 1058 return true; |
1059 } | |
1060 | |
72 | 1061 override void toCBuffer(OutBuffer buf, HdrGenState* hgs) |
0 | 1062 { |
72 | 1063 int i; |
1064 expToCBuffer(buf, hgs, e1, precedence[op]); | |
1065 buf.writeByte('('); | |
1066 argsToCBuffer(buf, arguments, hgs); | |
0 | 1067 buf.writeByte(')'); |
1068 } | |
1069 | |
72 | 1070 override void dump(int indent) |
0 | 1071 { |
1072 assert(false); | |
1073 } | |
1074 | |
72 | 1075 override elem* toElem(IRState* irs) |
0 | 1076 { |
72 | 1077 //printf("CallExp::toElem('%s')\n", toChars()); |
1078 assert(e1.type); | |
1079 elem* ec; | |
1080 int directcall; | |
1081 FuncDeclaration fd; | |
1082 Type t1 = e1.type.toBasetype(); | |
1083 Type ectype = t1; | |
1084 | |
1085 elem* ehidden = irs.ehidden; | |
1086 irs.ehidden = null; | |
1087 | |
1088 directcall = 0; | |
1089 fd = null; | |
1090 if (e1.op == TOK.TOKdotvar && t1.ty != TY.Tdelegate) | |
1091 { | |
1092 DotVarExp dve = cast(DotVarExp)e1; | |
1093 | |
1094 fd = dve.var.isFuncDeclaration(); | |
1095 Expression ex = dve.e1; | |
1096 while (1) | |
1097 { | |
1098 switch (ex.op) | |
1099 { | |
1100 case TOK.TOKsuper: // super.member() calls directly | |
1101 case TOK.TOKdottype: // type.member() calls directly | |
1102 directcall = 1; | |
1103 break; | |
1104 | |
1105 case TOK.TOKcast: | |
1106 ex = (cast(CastExp)ex).e1; | |
1107 continue; | |
1108 | |
1109 default: | |
1110 //ex.dump(0); | |
1111 break; | |
1112 } | |
1113 break; | |
1114 } | |
1115 ec = dve.e1.toElem(irs); | |
1116 ectype = dve.e1.type.toBasetype(); | |
1117 } | |
1118 else if (e1.op == TOK.TOKvar) | |
1119 { | |
1120 fd = (cast(VarExp)e1).var.isFuncDeclaration(); | |
1121 | |
1122 if (fd && fd.ident == Id.alloca && !fd.fbody && fd.linkage == LINK.LINKc && arguments && arguments.dim == 1) | |
1123 { | |
90
39648eb578f6
more Expressions work
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
84
diff
changeset
|
1124 auto arg = arguments[0]; |
72 | 1125 arg = arg.optimize(WANT.WANTvalue); |
1126 if (arg.isConst() && arg.type.isintegral()) | |
1127 { | |
1128 long sz = arg.toInteger(); | |
1129 if (sz > 0 && sz < 0x40000) | |
1130 { | |
1131 // It's an alloca(sz) of a fixed amount. | |
1132 // Replace with an array allocated on the stack | |
1133 // of the same size: char[sz] tmp; | |
1134 | |
1135 Symbol* stmp; | |
1136 .type* t; | |
1137 | |
1138 assert(!ehidden); | |
1139 t = type_allocn(TYM.TYarray, tschar); | |
1140 t.Tdim = cast(uint)sz; | |
1141 stmp = symbol_genauto(t); | |
1142 ec = el_ptr(stmp); | |
1143 el_setLoc(ec,loc); | |
1144 return ec; | |
1145 } | |
1146 } | |
1147 } | |
1148 | |
1149 ec = e1.toElem(irs); | |
1150 } | |
1151 else | |
1152 { | |
1153 ec = e1.toElem(irs); | |
1154 } | |
1155 ec = callfunc(loc, irs, directcall, type, ec, ectype, fd, t1, ehidden, arguments); | |
1156 el_setLoc(ec,loc); | |
0 | 1157 return ec; |
1158 } | |
1159 | |
72 | 1160 override void scanForNestedRef(Scope sc) |
0 | 1161 { |
72 | 1162 //printf("CallExp.scanForNestedRef(Scope *sc): %s\n", toChars()); |
1163 e1.scanForNestedRef(sc); | |
64 | 1164 arrayExpressionScanForNestedRef(sc, arguments); |
72 | 1165 } |
0 | 1166 |
1167 version (DMDV2) { | |
191
52188e7e3fb5
Fixed deprecated features, now compiles with DMD2.058
korDen@korDen-pc
parents:
187
diff
changeset
|
1168 override bool isLvalue() |
0 | 1169 { |
96 | 1170 // if (type.toBasetype().ty == Tstruct) |
72 | 1171 // return 1; |
1172 Type tb = e1.type.toBasetype(); | |
1173 if (tb.ty == Tfunction && (cast(TypeFunction)tb).isref) | |
191
52188e7e3fb5
Fixed deprecated features, now compiles with DMD2.058
korDen@korDen-pc
parents:
187
diff
changeset
|
1174 return true; // function returns a reference |
52188e7e3fb5
Fixed deprecated features, now compiles with DMD2.058
korDen@korDen-pc
parents:
187
diff
changeset
|
1175 return false; |
0 | 1176 } |
1177 } | |
72 | 1178 override Expression toLvalue(Scope sc, Expression e) |
0 | 1179 { |
72 | 1180 if (isLvalue()) |
1181 return this; | |
0 | 1182 return Expression.toLvalue(sc, e); |
72 | 1183 } |
0 | 1184 |
1185 version (DMDV2) { | |
72 | 1186 override bool canThrow() |
0 | 1187 { |
72 | 1188 //printf("CallExp::canThrow() %s\n", toChars()); |
1189 if (e1.canThrow()) | |
1190 return true; | |
1191 | |
1192 /* If any of the arguments can throw, then this expression can throw | |
1193 */ | |
90
39648eb578f6
more Expressions work
Eldar Insafutdinov <e.insafutdinov@gmail.com>
parents:
84
diff
changeset
|
1194 foreach (e; arguments) |
72 | 1195 { |
1196 if (e && e.canThrow()) | |
1197 return true; | |
1198 } | |
1199 | |
1200 if (global.errors && !e1.type) | |
1201 return false; // error recovery | |
1202 | |
1203 /* If calling a function or delegate that is typed as nothrow, | |
1204 * then this expression cannot throw. | |
1205 * Note that pure functions can throw. | |
1206 */ | |
1207 Type t = e1.type.toBasetype(); | |
1208 if (t.ty == TY.Tfunction && (cast(TypeFunction)t).isnothrow) | |
1209 return false; | |
1210 if (t.ty == TY.Tdelegate && (cast(TypeFunction)(cast(TypeDelegate)t).next).isnothrow) | |
1211 return false; | |
1212 | |
0 | 1213 return true; |
1214 } | |
1215 } | |
72 | 1216 override int inlineCost(InlineCostState* ics) |
0 | 1217 { |
1218 return 1 + e1.inlineCost(ics) + arrayInlineCost(ics, arguments); | |
1219 } | |
1220 | |
72 | 1221 override Expression doInline(InlineDoState ids) |
0 | 1222 { |
72 | 1223 CallExp ce = cast(CallExp)copy(); |
1224 ce.e1 = e1.doInline(ids); | |
1225 ce.arguments = arrayExpressiondoInline(arguments, ids); | |
0 | 1226 return ce; |
1227 } | |
1228 | |
72 | 1229 override Expression inlineScan(InlineScanState* iss) |
0 | 1230 { |
72 | 1231 Expression e = this; |
1232 | |
1233 //printf("CallExp.inlineScan()\n"); | |
1234 e1 = e1.inlineScan(iss); | |
1235 arrayInlineScan(iss, arguments); | |
1236 | |
1237 if (e1.op == TOKvar) | |
1238 { | |
1239 VarExp ve = cast(VarExp)e1; | |
1240 FuncDeclaration fd = ve.var.isFuncDeclaration(); | |
1241 | |
1242 if (fd && fd != iss.fd && fd.canInline(0)) | |
1243 { | |
1244 e = fd.doInline(iss, null, arguments); | |
1245 } | |
1246 } | |
1247 else if (e1.op == TOKdotvar) | |
1248 { | |
1249 DotVarExp dve = cast(DotVarExp)e1; | |
1250 FuncDeclaration fd = dve.var.isFuncDeclaration(); | |
1251 | |
1252 if (fd && fd != iss.fd && fd.canInline(1)) | |
1253 { | |
1254 if (dve.e1.op == TOKcall && | |
1255 dve.e1.type.toBasetype().ty == Tstruct) | |
1256 { | |
1257 /* To create ethis, we'll need to take the address | |
1258 * of dve.e1, but this won't work if dve.e1 is | |
1259 * a function call. | |
1260 */ | |
1261 ; | |
1262 } | |
1263 else | |
1264 e = fd.doInline(iss, dve.e1, arguments); | |
1265 } | |
1266 } | |
1267 | |
0 | 1268 return e; |
1269 } | |
1270 } | |
1271 |