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