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