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