1 /**
2 * Semantic analysis of expressions.
3 *
4 * Specification: ($LINK2 https://dlang.org/spec/expression.html, Expressions)
5 *
6 * Copyright: Copyright (C) 1999-2022 by The D Language Foundation, All Rights Reserved
7 * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
8 * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
9 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/expressionsem.d, _expressionsem.d)
10 * Documentation: https://dlang.org/phobos/dmd_expressionsem.html
11 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/expressionsem.d
12 */
13
14 module dmd.expressionsem;
15
16 import core.stdc.stdio;
17
18 import dmd.access;
19 import dmd.aggregate;
20 import dmd.aliasthis;
21 import dmd.arrayop;
22 import dmd.arraytypes;
23 import dmd.attrib;
24 import dmd.astcodegen;
25 import dmd.astenums;
26 import dmd.canthrow;
27 import dmd.chkformat;
28 import dmd.ctorflow;
29 import dmd.dscope;
30 import dmd.dsymbol;
31 import dmd.declaration;
32 import dmd.dclass;
33 import dmd.dcast;
34 import dmd.delegatize;
35 import dmd.denum;
36 import dmd.dimport;
37 import dmd.dinterpret;
38 import dmd.dmangle;
39 import dmd.dmodule;
40 import dmd.dstruct;
41 import dmd.dsymbolsem;
42 import dmd.dtemplate;
43 import dmd.errors;
44 import dmd.escape;
45 import dmd.expression;
46 import dmd.file_manager;
47 import dmd.func;
48 import dmd.globals;
49 import dmd.hdrgen;
50 import dmd.id;
51 import dmd.identifier;
52 import dmd.imphint;
53 import dmd.importc;
54 import dmd.init;
55 import dmd.initsem;
56 import dmd.inline;
57 import dmd.intrange;
58 import dmd.mtype;
59 import dmd.mustuse;
60 import dmd.nspace;
61 import dmd.opover;
62 import dmd.optimize;
63 import dmd.parse;
64 import dmd.printast;
65 import dmd.root.ctfloat;
66 import dmd.root.file;
67 import dmd.root.filename;
68 import dmd.common.outbuffer;
69 import dmd.root.rootobject;
70 import dmd.root.string;
71 import dmd.root.utf;
72 import dmd.semantic2;
73 import dmd.semantic3;
74 import dmd.sideeffect;
75 import dmd.safe;
76 import dmd.target;
77 import dmd.tokens;
78 import dmd.traits;
79 import dmd.typesem;
80 import dmd.typinf;
81 import dmd.utils;
82 import dmd.visitor;
83
84 enum LOGSEMANTIC = false;
85
86 /********************************************************
87 * Perform semantic analysis and CTFE on expressions to produce
88 * a string.
89 * Params:
90 * buf = append generated string to buffer
91 * sc = context
92 * exps = array of Expressions
93 * Returns:
94 * true on error
95 */
expressionsToString(ref OutBuffer buf,Scope * sc,Expressions * exps)96 bool expressionsToString(ref OutBuffer buf, Scope* sc, Expressions* exps)
97 {
98 if (!exps)
99 return false;
100
101 foreach (ex; *exps)
102 {
103 if (!ex)
104 continue;
105 auto sc2 = sc.startCTFE();
106 auto e2 = ex.expressionSemantic(sc2);
107 auto e3 = resolveProperties(sc2, e2);
108 sc2.endCTFE();
109
110 // allowed to contain types as well as expressions
111 auto e4 = ctfeInterpretForPragmaMsg(e3);
112 if (!e4 || e4.op == EXP.error)
113 return true;
114
115 // expand tuple
116 if (auto te = e4.isTupleExp())
117 {
118 if (expressionsToString(buf, sc, te.exps))
119 return true;
120 continue;
121 }
122 // char literals exp `.toStringExp` return `null` but we cant override it
123 // because in most contexts we don't want the conversion to succeed.
124 IntegerExp ie = e4.isIntegerExp();
125 const ty = (ie && ie.type) ? ie.type.ty : Terror;
126 if (ty.isSomeChar)
127 {
128 auto tsa = new TypeSArray(ie.type, IntegerExp.literal!1);
129 e4 = new ArrayLiteralExp(ex.loc, tsa, ie);
130 }
131
132 if (StringExp se = e4.toStringExp())
133 buf.writestring(se.toUTF8(sc).peekString());
134 else
135 buf.writestring(e4.toString());
136 }
137 return false;
138 }
139
140
141 /***********************************************************
142 * Resolve `exp` as a compile-time known string.
143 * Params:
144 * sc = scope
145 * exp = Expression which expected as a string
146 * s = What the string is expected for, will be used in error diagnostic.
147 * Returns:
148 * String literal, or `null` if error happens.
149 */
semanticString(Scope * sc,Expression exp,const char * s)150 StringExp semanticString(Scope *sc, Expression exp, const char* s)
151 {
152 sc = sc.startCTFE();
153 exp = exp.expressionSemantic(sc);
154 exp = resolveProperties(sc, exp);
155 sc = sc.endCTFE();
156
157 if (exp.op == EXP.error)
158 return null;
159
160 auto e = exp;
161 if (exp.type.isString())
162 {
163 e = e.ctfeInterpret();
164 if (e.op == EXP.error)
165 return null;
166 }
167
168 auto se = e.toStringExp();
169 if (!se)
170 {
171 exp.error("`string` expected for %s, not `(%s)` of type `%s`",
172 s, exp.toChars(), exp.type.toChars());
173 return null;
174 }
175 return se;
176 }
177
extractOpDollarSideEffect(Scope * sc,UnaExp ue)178 private Expression extractOpDollarSideEffect(Scope* sc, UnaExp ue)
179 {
180 Expression e0;
181 Expression e1 = Expression.extractLast(ue.e1, e0);
182 // https://issues.dlang.org/show_bug.cgi?id=12585
183 // Extract the side effect part if ue.e1 is comma.
184
185 if ((sc.flags & SCOPE.ctfe) ? hasSideEffect(e1) : !isTrivialExp(e1)) // match logic in extractSideEffect()
186 {
187 /* Even if opDollar is needed, 'e1' should be evaluate only once. So
188 * Rewrite:
189 * e1.opIndex( ... use of $ ... )
190 * e1.opSlice( ... use of $ ... )
191 * as:
192 * (ref __dop = e1, __dop).opIndex( ... __dop.opDollar ...)
193 * (ref __dop = e1, __dop).opSlice( ... __dop.opDollar ...)
194 */
195 e1 = extractSideEffect(sc, "__dop", e0, e1, false);
196 assert(e1.isVarExp());
197 e1.isVarExp().var.storage_class |= STC.exptemp; // lifetime limited to expression
198 }
199 ue.e1 = e1;
200 return e0;
201 }
202
203 /**************************************
204 * Runs semantic on ae.arguments. Declares temporary variables
205 * if '$' was used.
206 */
resolveOpDollar(Scope * sc,ArrayExp ae,Expression * pe0)207 Expression resolveOpDollar(Scope* sc, ArrayExp ae, Expression* pe0)
208 {
209 assert(!ae.lengthVar);
210 *pe0 = null;
211 AggregateDeclaration ad = isAggregate(ae.e1.type);
212 Dsymbol slice = search_function(ad, Id.slice);
213 //printf("slice = %s %s\n", slice.kind(), slice.toChars());
214 foreach (i, e; *ae.arguments)
215 {
216 if (i == 0)
217 *pe0 = extractOpDollarSideEffect(sc, ae);
218
219 if (e.op == EXP.interval && !(slice && slice.isTemplateDeclaration()))
220 {
221 Lfallback:
222 if (ae.arguments.dim == 1)
223 return null;
224 ae.error("multi-dimensional slicing requires template `opSlice`");
225 return ErrorExp.get();
226 }
227 //printf("[%d] e = %s\n", i, e.toChars());
228
229 // Create scope for '$' variable for this dimension
230 auto sym = new ArrayScopeSymbol(sc, ae);
231 sym.parent = sc.scopesym;
232 sc = sc.push(sym);
233 ae.lengthVar = null; // Create it only if required
234 ae.currentDimension = i; // Dimension for $, if required
235
236 e = e.expressionSemantic(sc);
237 e = resolveProperties(sc, e);
238
239 if (ae.lengthVar && sc.func)
240 {
241 // If $ was used, declare it now
242 Expression de = new DeclarationExp(ae.loc, ae.lengthVar);
243 de = de.expressionSemantic(sc);
244 *pe0 = Expression.combine(*pe0, de);
245 }
246 sc = sc.pop();
247
248 if (auto ie = e.isIntervalExp())
249 {
250 auto tiargs = new Objects();
251 Expression edim = new IntegerExp(ae.loc, i, Type.tsize_t);
252 edim = edim.expressionSemantic(sc);
253 tiargs.push(edim);
254
255 auto fargs = new Expressions(2);
256 (*fargs)[0] = ie.lwr;
257 (*fargs)[1] = ie.upr;
258
259 uint xerrors = global.startGagging();
260 sc = sc.push();
261 FuncDeclaration fslice = resolveFuncCall(ae.loc, sc, slice, tiargs, ae.e1.type, fargs, FuncResolveFlag.quiet);
262 sc = sc.pop();
263 global.endGagging(xerrors);
264 if (!fslice)
265 goto Lfallback;
266
267 e = new DotTemplateInstanceExp(ae.loc, ae.e1, slice.ident, tiargs);
268 e = new CallExp(ae.loc, e, fargs);
269 e = e.expressionSemantic(sc);
270 }
271
272 if (!e.type)
273 {
274 ae.error("`%s` has no value", e.toChars());
275 e = ErrorExp.get();
276 }
277 if (e.op == EXP.error)
278 return e;
279
280 (*ae.arguments)[i] = e;
281 }
282 return ae;
283 }
284
285 /**************************************
286 * Runs semantic on se.lwr and se.upr. Declares a temporary variable
287 * if '$' was used.
288 * Returns:
289 * ae, or ErrorExp if errors occurred
290 */
resolveOpDollar(Scope * sc,ArrayExp ae,IntervalExp ie,Expression * pe0)291 Expression resolveOpDollar(Scope* sc, ArrayExp ae, IntervalExp ie, Expression* pe0)
292 {
293 //assert(!ae.lengthVar);
294 if (!ie)
295 return ae;
296
297 VarDeclaration lengthVar = ae.lengthVar;
298 bool errors = false;
299
300 // create scope for '$'
301 auto sym = new ArrayScopeSymbol(sc, ae);
302 sym.parent = sc.scopesym;
303 sc = sc.push(sym);
304
305 Expression sem(Expression e)
306 {
307 e = e.expressionSemantic(sc);
308 e = resolveProperties(sc, e);
309 if (!e.type)
310 {
311 ae.error("`%s` has no value", e.toChars());
312 errors = true;
313 }
314 return e;
315 }
316
317 ie.lwr = sem(ie.lwr);
318 ie.upr = sem(ie.upr);
319
320 if (ie.lwr.isErrorExp() || ie.upr.isErrorExp())
321 errors = true;
322
323 if (lengthVar != ae.lengthVar && sc.func)
324 {
325 // If $ was used, declare it now
326 Expression de = new DeclarationExp(ae.loc, ae.lengthVar);
327 de = de.expressionSemantic(sc);
328 *pe0 = Expression.combine(*pe0, de);
329 }
330
331 sc = sc.pop();
332
333 return errors ? ErrorExp.get() : ae;
334 }
335
336 /******************************
337 * Perform semantic() on an array of Expressions.
338 */
339 bool arrayExpressionSemantic(Expressions* exps, Scope* sc, bool preserveErrors = false)
340 {
341 bool err = false;
342 if (exps)
343 {
foreach(ref e;* exps)344 foreach (ref e; *exps)
345 {
346 if (e)
347 {
348 auto e2 = e.expressionSemantic(sc);
349 if (e2.op == EXP.error)
350 err = true;
351 if (preserveErrors || e2.op != EXP.error)
352 e = e2;
353 }
354 }
355 }
356 return err;
357 }
358
359 /******************************
360 * Check the tail CallExp is really property function call.
361 * Bugs:
362 * This doesn't appear to do anything.
363 */
checkPropertyCall(Expression e)364 private bool checkPropertyCall(Expression e)
365 {
366 e = lastComma(e);
367
368 if (auto ce = e.isCallExp())
369 {
370 if (ce.f)
371 {
372 auto tf = ce.f.type.isTypeFunction();
373 /* If a forward reference to ce.f, try to resolve it
374 */
375 if (!tf.deco && ce.f.semanticRun < PASS.semanticdone)
376 {
377 ce.f.dsymbolSemantic(null);
378 tf = ce.f.type.isTypeFunction();
379 }
380 }
381 else if (!ce.e1.type.isFunction_Delegate_PtrToFunction())
382 assert(0);
383 }
384 return false;
385 }
386
387 /******************************
388 * Find symbol in accordance with the UFCS name look up rule
389 */
searchUFCS(Scope * sc,UnaExp ue,Identifier ident)390 private Expression searchUFCS(Scope* sc, UnaExp ue, Identifier ident)
391 {
392 //printf("searchUFCS(ident = %s)\n", ident.toChars());
393 Loc loc = ue.loc;
394
395 // TODO: merge with Scope.search.searchScopes()
396 Dsymbol searchScopes(int flags)
397 {
398 Dsymbol s = null;
399 for (Scope* scx = sc; scx; scx = scx.enclosing)
400 {
401 if (!scx.scopesym)
402 continue;
403 if (scx.scopesym.isModule())
404 flags |= SearchUnqualifiedModule; // tell Module.search() that SearchLocalsOnly is to be obeyed
405 s = scx.scopesym.search(loc, ident, flags);
406 if (s)
407 {
408 // overload set contains only module scope symbols.
409 if (s.isOverloadSet())
410 break;
411 // selective/renamed imports also be picked up
412 if (AliasDeclaration ad = s.isAliasDeclaration())
413 {
414 if (ad._import)
415 break;
416 }
417 // See only module scope symbols for UFCS target.
418 Dsymbol p = s.toParent2();
419 if (p && p.isModule())
420 break;
421 }
422 s = null;
423
424 // Stop when we hit a module, but keep going if that is not just under the global scope
425 if (scx.scopesym.isModule() && !(scx.enclosing && !scx.enclosing.enclosing))
426 break;
427 }
428 return s;
429 }
430
431 int flags = 0;
432 Dsymbol s;
433
434 if (sc.flags & SCOPE.ignoresymbolvisibility)
435 flags |= IgnoreSymbolVisibility;
436
437 // First look in local scopes
438 s = searchScopes(flags | SearchLocalsOnly);
439 if (!s)
440 {
441 // Second look in imported modules
442 s = searchScopes(flags | SearchImportsOnly);
443 }
444
445 if (!s)
446 return ue.e1.type.Type.getProperty(sc, loc, ident, 0);
447
448 FuncDeclaration f = s.isFuncDeclaration();
449 if (f)
450 {
451 TemplateDeclaration td = getFuncTemplateDecl(f);
452 if (td)
453 {
454 if (td.overroot)
455 td = td.overroot;
456 s = td;
457 }
458 }
459
460 if (auto dti = ue.isDotTemplateInstanceExp())
461 {
462 auto ti = new TemplateInstance(loc, s.ident, dti.ti.tiargs);
463 if (!ti.updateTempDecl(sc, s))
464 return ErrorExp.get();
465 return new ScopeExp(loc, ti);
466 }
467 else
468 {
469 //printf("-searchUFCS() %s\n", s.toChars());
470 return new DsymbolExp(loc, s);
471 }
472 }
473
474 /******************************
475 * Pull out callable entity with UFCS.
476 */
resolveUFCS(Scope * sc,CallExp ce)477 private Expression resolveUFCS(Scope* sc, CallExp ce)
478 {
479 Loc loc = ce.loc;
480 Expression eleft;
481 Expression e;
482
483 if (auto die = ce.e1.isDotIdExp())
484 {
485 Identifier ident = die.ident;
486
487 Expression ex = die.semanticX(sc);
488 if (ex != die)
489 {
490 ce.e1 = ex;
491 return null;
492 }
493 eleft = die.e1;
494
495 Type t = eleft.type.toBasetype();
496 if (t.ty == Tarray || t.ty == Tsarray || t.ty == Tnull || (t.isTypeBasic() && t.ty != Tvoid))
497 {
498 /* Built-in types and arrays have no callable properties, so do shortcut.
499 * It is necessary in: e.init()
500 */
501 }
502 else if (t.ty == Taarray)
503 {
504 if (ident == Id.remove)
505 {
506 /* Transform:
507 * aa.remove(arg) into delete aa[arg]
508 */
509 if (!ce.arguments || ce.arguments.dim != 1)
510 {
511 ce.error("expected key as argument to `aa.remove()`");
512 return ErrorExp.get();
513 }
514 if (!eleft.type.isMutable())
515 {
516 ce.error("cannot remove key from `%s` associative array `%s`", MODtoChars(t.mod), eleft.toChars());
517 return ErrorExp.get();
518 }
519 Expression key = (*ce.arguments)[0];
520 key = key.expressionSemantic(sc);
521 key = resolveProperties(sc, key);
522
523 TypeAArray taa = t.isTypeAArray();
524 key = key.implicitCastTo(sc, taa.index);
525
526 if (key.checkValue() || key.checkSharedAccess(sc))
527 return ErrorExp.get();
528
529 semanticTypeInfo(sc, taa.index);
530
531 return new RemoveExp(loc, eleft, key);
532 }
533 }
534 else
535 {
536 if (Expression ey = die.semanticY(sc, 1))
537 {
538 if (ey.op == EXP.error)
539 return ey;
540 ce.e1 = ey;
541 if (isDotOpDispatch(ey))
542 {
543 // even opDispatch and UFCS must have valid arguments,
544 // so now that we've seen indication of a problem,
545 // check them for issues.
546 Expressions* originalArguments = Expression.arraySyntaxCopy(ce.arguments);
547
548 uint errors = global.startGagging();
549 e = ce.expressionSemantic(sc);
550 if (!global.endGagging(errors))
551 return e;
552
553 if (arrayExpressionSemantic(originalArguments, sc))
554 return ErrorExp.get();
555
556 /* fall down to UFCS */
557 }
558 else
559 return null;
560 }
561 }
562
563 /* https://issues.dlang.org/show_bug.cgi?id=13953
564 *
565 * If a struct has an alias this to an associative array
566 * and remove is used on a struct instance, we have to
567 * check first if there is a remove function that can be called
568 * on the struct. If not we must check the alias this.
569 *
570 * struct A
571 * {
572 * string[string] a;
573 * alias a this;
574 * }
575 *
576 * void fun()
577 * {
578 * A s;
579 * s.remove("foo");
580 * }
581 */
582 const errors = global.startGagging();
583 e = searchUFCS(sc, die, ident);
584 // if there were any errors and the identifier was remove
585 if (global.endGagging(errors))
586 {
587 if (ident == Id.remove)
588 {
589 // check alias this
590 Expression alias_e = resolveAliasThis(sc, die.e1, 1);
591 if (alias_e && alias_e != die.e1)
592 {
593 die.e1 = alias_e;
594 CallExp ce2 = ce.syntaxCopy();
595 ce2.e1 = die;
596 e = ce2.isCallExp().trySemantic(sc);
597 if (e)
598 return e;
599 }
600 }
601 // if alias this did not work out, print the initial errors
602 searchUFCS(sc, die, ident);
603 }
604 }
605 else if (auto dti = ce.e1.isDotTemplateInstanceExp())
606 {
607 if (Expression ey = dti.semanticY(sc, 1))
608 {
609 ce.e1 = ey;
610 return null;
611 }
612 eleft = dti.e1;
613 e = searchUFCS(sc, dti, dti.ti.name);
614 }
615 else
616 return null;
617
618 // Rewrite
619 ce.e1 = e;
620 if (!ce.arguments)
621 ce.arguments = new Expressions();
622 ce.arguments.shift(eleft);
623
624 return null;
625 }
626
627 /******************************
628 * Pull out property with UFCS.
629 */
630 private Expression resolveUFCSProperties(Scope* sc, Expression e1, Expression e2 = null)
631 {
632 Loc loc = e1.loc;
633 Expression eleft;
634 Expression e;
635
636 if (auto die = e1.isDotIdExp())
637 {
638 eleft = die.e1;
639 e = searchUFCS(sc, die, die.ident);
640 }
641 else if (auto dti = e1.isDotTemplateInstanceExp())
642 {
643 eleft = dti.e1;
644 e = searchUFCS(sc, dti, dti.ti.name);
645 }
646 else
647 return null;
648
649 if (e is null)
650 return null;
651
652 // Rewrite
653 if (e2)
654 {
655 // run semantic without gagging
656 e2 = e2.expressionSemantic(sc);
657
658 /* f(e1) = e2
659 */
660 Expression ex = e.copy();
661 auto a1 = new Expressions(1);
662 (*a1)[0] = eleft;
663 ex = new CallExp(loc, ex, a1);
664 auto e1PassSemantic = ex.trySemantic(sc);
665
666 /* f(e1, e2)
667 */
668 auto a2 = new Expressions(2);
669 (*a2)[0] = eleft;
670 (*a2)[1] = e2;
671 e = new CallExp(loc, e, a2);
672 e = e.trySemantic(sc);
673 if (!e1PassSemantic && !e)
674 {
675 /* https://issues.dlang.org/show_bug.cgi?id=20448
676 *
677 * If both versions have failed to pass semantic,
678 * f(e1) = e2 gets priority in error printing
679 * because f might be a templated function that
680 * failed to instantiate and we have to print
681 * the instantiation errors.
682 */
683 return e1.expressionSemantic(sc);
684 }
685 else if (ex && !e)
686 {
687 checkPropertyCall(ex);
688 ex = new AssignExp(loc, ex, e2);
689 return ex.expressionSemantic(sc);
690 }
691 else
692 {
693 // strict setter prints errors if fails
694 e = e.expressionSemantic(sc);
695 }
696 checkPropertyCall(e);
697 return e;
698 }
699 else
700 {
701 /* f(e1)
702 */
703 auto arguments = new Expressions(1);
704 (*arguments)[0] = eleft;
705 e = new CallExp(loc, e, arguments);
706 e = e.expressionSemantic(sc);
707 checkPropertyCall(e);
708 return e.expressionSemantic(sc);
709 }
710 }
711
712 /******************************
713 * If e1 is a property function (template), resolve it.
714 */
resolvePropertiesOnly(Scope * sc,Expression e1)715 Expression resolvePropertiesOnly(Scope* sc, Expression e1)
716 {
717 //printf("e1 = %s %s\n", Token.toChars(e1.op), e1.toChars());
718
719 Expression handleOverloadSet(OverloadSet os)
720 {
721 assert(os);
722 foreach (s; os.a)
723 {
724 auto fd = s.isFuncDeclaration();
725 auto td = s.isTemplateDeclaration();
726 if (fd)
727 {
728 if (fd.type.isTypeFunction().isproperty)
729 return resolveProperties(sc, e1);
730 }
731 else if (td && td.onemember && (fd = td.onemember.isFuncDeclaration()) !is null)
732 {
733 if (fd.type.isTypeFunction().isproperty ||
734 (fd.storage_class2 & STC.property) ||
735 (td._scope.stc & STC.property))
736 return resolveProperties(sc, e1);
737 }
738 }
739 return e1;
740 }
741
742 Expression handleTemplateDecl(TemplateDeclaration td)
743 {
744 assert(td);
745 if (td.onemember)
746 {
747 if (auto fd = td.onemember.isFuncDeclaration())
748 {
749 if (fd.type.isTypeFunction().isproperty ||
750 (fd.storage_class2 & STC.property) ||
751 (td._scope.stc & STC.property))
752 return resolveProperties(sc, e1);
753 }
754 }
755 return e1;
756 }
757
758 Expression handleFuncDecl(FuncDeclaration fd)
759 {
760 assert(fd);
761 if (fd.type.isTypeFunction().isproperty)
762 return resolveProperties(sc, e1);
763 return e1;
764 }
765
766 if (auto de = e1.isDotExp())
767 {
768 if (auto os = de.e2.isOverExp())
769 return handleOverloadSet(os.vars);
770 }
771 else if (auto oe = e1.isOverExp())
772 return handleOverloadSet(oe.vars);
773 else if (auto dti = e1.isDotTemplateInstanceExp())
774 {
775 if (dti.ti.tempdecl)
776 if (auto td = dti.ti.tempdecl.isTemplateDeclaration())
777 return handleTemplateDecl(td);
778 }
779 else if (auto dte = e1.isDotTemplateExp())
780 return handleTemplateDecl(dte.td);
781 else if (auto se = e1.isScopeExp())
782 {
783 Dsymbol s = se.sds;
784 TemplateInstance ti = s.isTemplateInstance();
785 if (ti && !ti.semanticRun && ti.tempdecl)
786 if (auto td = ti.tempdecl.isTemplateDeclaration())
787 return handleTemplateDecl(td);
788 }
789 else if (auto et = e1.isTemplateExp())
790 return handleTemplateDecl(et.td);
791 else if (e1.isDotVarExp() && e1.type.isTypeFunction())
792 {
793 DotVarExp dve = e1.isDotVarExp();
794 return handleFuncDecl(dve.var.isFuncDeclaration());
795 }
796 else if (e1.isVarExp() && e1.type && e1.type.isTypeFunction() && (sc.intypeof || !e1.isVarExp().var.needThis()))
797 return handleFuncDecl(e1.isVarExp().var.isFuncDeclaration());
798 return e1;
799 }
800
801 /****************************************
802 * Turn symbol `s` into the expression it represents.
803 *
804 * Params:
805 * s = symbol to resolve
806 * loc = location of use of `s`
807 * sc = context
808 * hasOverloads = applies if `s` represents a function.
809 * true means it's overloaded and will be resolved later,
810 * false means it's the exact function symbol.
811 * Returns:
812 * `s` turned into an expression, `ErrorExp` if an error occurred
813 */
symbolToExp(Dsymbol s,const ref Loc loc,Scope * sc,bool hasOverloads)814 Expression symbolToExp(Dsymbol s, const ref Loc loc, Scope *sc, bool hasOverloads)
815 {
816 static if (LOGSEMANTIC)
817 {
818 printf("DsymbolExp::resolve(%s %s)\n", s.kind(), s.toChars());
819 }
820
821 Lagain:
822 Expression e;
823
824 //printf("DsymbolExp:: %p '%s' is a symbol\n", this, toChars());
825 //printf("s = '%s', s.kind = '%s'\n", s.toChars(), s.kind());
826 Dsymbol olds = s;
827 Declaration d = s.isDeclaration();
828 if (d && (d.storage_class & STC.templateparameter))
829 {
830 s = s.toAlias();
831 }
832 else
833 {
834 // functions are checked after overloading
835 // templates are checked after matching constraints
836 if (!s.isFuncDeclaration() && !s.isTemplateDeclaration())
837 {
838 s.checkDeprecated(loc, sc);
839 if (d)
840 d.checkDisabled(loc, sc);
841 }
842
843 // https://issues.dlang.org/show_bug.cgi?id=12023
844 // if 's' is a tuple variable, the tuple is returned.
845 s = s.toAlias();
846
847 //printf("s = '%s', s.kind = '%s', s.needThis() = %p\n", s.toChars(), s.kind(), s.needThis());
848 if (s != olds && !s.isFuncDeclaration() && !s.isTemplateDeclaration())
849 {
850 s.checkDeprecated(loc, sc);
851 if (d)
852 d.checkDisabled(loc, sc);
853 }
854 }
855
856 if (auto em = s.isEnumMember())
857 {
858 return em.getVarExp(loc, sc);
859 }
860 if (auto v = s.isVarDeclaration())
861 {
862 //printf("Identifier '%s' is a variable, type '%s'\n", s.toChars(), v.type.toChars());
863 if (sc.intypeof == 1 && !v.inuse)
864 v.dsymbolSemantic(sc);
865 if (!v.type || // during variable type inference
866 !v.type.deco && v.inuse) // during variable type semantic
867 {
868 if (v.inuse) // variable type depends on the variable itself
869 error(loc, "circular reference to %s `%s`", v.kind(), v.toPrettyChars());
870 else // variable type cannot be determined
871 error(loc, "forward reference to %s `%s`", v.kind(), v.toPrettyChars());
872 return ErrorExp.get();
873 }
874 if (v.type.ty == Terror)
875 return ErrorExp.get();
876
877 if ((v.storage_class & STC.manifest) && v._init)
878 {
879 if (v.inuse)
880 {
881 error(loc, "circular initialization of %s `%s`", v.kind(), v.toPrettyChars());
882 return ErrorExp.get();
883 }
884 e = v.expandInitializer(loc);
885 v.inuse++;
886 e = e.expressionSemantic(sc);
887 v.inuse--;
888 return e;
889 }
890
891 // We need to run semantics to correctly set 'STC.field' if it is a member variable
892 // that could be forward referenced. This is needed for 'v.needThis()' to work
893 if (v.isThis())
894 v.dsymbolSemantic(sc);
895
896 // Change the ancestor lambdas to delegate before hasThis(sc) call.
897 if (v.checkNestedReference(sc, loc))
898 return ErrorExp.get();
899
900 if (v.needThis() && hasThis(sc))
901 e = new DotVarExp(loc, new ThisExp(loc), v);
902 else
903 e = new VarExp(loc, v);
904 e = e.expressionSemantic(sc);
905 return e;
906 }
907 if (auto fld = s.isFuncLiteralDeclaration())
908 {
909 //printf("'%s' is a function literal\n", fld.toChars());
910 e = new FuncExp(loc, fld);
911 return e.expressionSemantic(sc);
912 }
913 if (auto f = s.isFuncDeclaration())
914 {
915 f = f.toAliasFunc();
916 if (!f.functionSemantic())
917 return ErrorExp.get();
918
919 if (!hasOverloads && f.checkForwardRef(loc))
920 return ErrorExp.get();
921
922 auto fd = s.isFuncDeclaration();
923 fd.type = f.type;
924 return new VarExp(loc, fd, hasOverloads);
925 }
926 if (OverDeclaration od = s.isOverDeclaration())
927 {
928 e = new VarExp(loc, od, true);
929 e.type = Type.tvoid;
930 return e;
931 }
932 if (OverloadSet o = s.isOverloadSet())
933 {
934 //printf("'%s' is an overload set\n", o.toChars());
935 return new OverExp(loc, o);
936 }
937
938 if (Import imp = s.isImport())
939 {
940 if (!imp.pkg)
941 {
942 .error(loc, "forward reference of import `%s`", imp.toChars());
943 return ErrorExp.get();
944 }
945 auto ie = new ScopeExp(loc, imp.pkg);
946 return ie.expressionSemantic(sc);
947 }
948 if (Package pkg = s.isPackage())
949 {
950 auto ie = new ScopeExp(loc, pkg);
951 return ie.expressionSemantic(sc);
952 }
953 if (Module mod = s.isModule())
954 {
955 auto ie = new ScopeExp(loc, mod);
956 return ie.expressionSemantic(sc);
957 }
958 if (Nspace ns = s.isNspace())
959 {
960 auto ie = new ScopeExp(loc, ns);
961 return ie.expressionSemantic(sc);
962 }
963
964 if (Type t = s.getType())
965 {
966 return (new TypeExp(loc, t)).expressionSemantic(sc);
967 }
968
969 if (TupleDeclaration tup = s.isTupleDeclaration())
970 {
971 if (tup.needThis() && hasThis(sc))
972 e = new DotVarExp(loc, new ThisExp(loc), tup);
973 else
974 e = new TupleExp(loc, tup);
975 e = e.expressionSemantic(sc);
976 return e;
977 }
978
979 if (TemplateInstance ti = s.isTemplateInstance())
980 {
981 ti.dsymbolSemantic(sc);
982 if (!ti.inst || ti.errors)
983 return ErrorExp.get();
984 s = ti.toAlias();
985 if (!s.isTemplateInstance())
986 goto Lagain;
987 e = new ScopeExp(loc, ti);
988 e = e.expressionSemantic(sc);
989 return e;
990 }
991 if (TemplateDeclaration td = s.isTemplateDeclaration())
992 {
993 Dsymbol p = td.toParentLocal();
994 FuncDeclaration fdthis = hasThis(sc);
995 AggregateDeclaration ad = p ? p.isAggregateDeclaration() : null;
996 if (fdthis && ad && fdthis.isMemberLocal() == ad && (td._scope.stc & STC.static_) == 0)
997 {
998 e = new DotTemplateExp(loc, new ThisExp(loc), td);
999 }
1000 else
1001 e = new TemplateExp(loc, td);
1002 e = e.expressionSemantic(sc);
1003 return e;
1004 }
1005
1006 .error(loc, "%s `%s` is not a variable", s.kind(), s.toChars());
1007 return ErrorExp.get();
1008 }
1009
1010 /*************************************************************
1011 * Given var, get the
1012 * right `this` pointer if var is in an outer class, but our
1013 * existing `this` pointer is in an inner class.
1014 * Params:
1015 * loc = location to use for error messages
1016 * sc = context
1017 * ad = struct or class we need the correct `this` for
1018 * e1 = existing `this`
1019 * var = the specific member of ad we're accessing
1020 * flag = if true, return `null` instead of throwing an error
1021 * Returns:
1022 * Expression representing the `this` for the var
1023 */
1024 private Expression getRightThis(const ref Loc loc, Scope* sc, AggregateDeclaration ad, Expression e1, Dsymbol var, int flag = 0)
1025 {
1026 //printf("\ngetRightThis(e1 = %s, ad = %s, var = %s)\n", e1.toChars(), ad.toChars(), var.toChars());
1027 L1:
1028 Type t = e1.type.toBasetype();
1029 //printf("e1.type = %s, var.type = %s\n", e1.type.toChars(), var.type.toChars());
1030
1031 if (e1.op == EXP.objcClassReference)
1032 {
1033 // We already have an Objective-C class reference, just use that as 'this'.
1034 return e1;
1035 }
1036 else if (ad && ad.isClassDeclaration && ad.isClassDeclaration.classKind == ClassKind.objc &&
1037 var.isFuncDeclaration && var.isFuncDeclaration.isStatic &&
1038 var.isFuncDeclaration.objc.selector)
1039 {
1040 return new ObjcClassReferenceExp(e1.loc, ad.isClassDeclaration());
1041 }
1042
1043 /* Access of a member which is a template parameter in dual-scope scenario
1044 * class A { inc(alias m)() { ++m; } } // `m` needs `this` of `B`
1045 * class B {int m; inc() { new A().inc!m(); } }
1046 */
1047 if (e1.op == EXP.this_)
1048 {
1049 FuncDeclaration f = hasThis(sc);
1050 if (f && f.hasDualContext())
1051 {
1052 if (f.followInstantiationContext(ad))
1053 {
1054 e1 = new VarExp(loc, f.vthis);
1055 e1 = new PtrExp(loc, e1);
1056 e1 = new IndexExp(loc, e1, IntegerExp.literal!1);
1057 e1 = getThisSkipNestedFuncs(loc, sc, f.toParent2(), ad, e1, t, var);
1058 if (e1.op == EXP.error)
1059 return e1;
1060 goto L1;
1061 }
1062 }
1063 }
1064
1065 /* If e1 is not the 'this' pointer for ad
1066 */
1067 if (ad &&
1068 !(t.isTypePointer() && t.nextOf().isTypeStruct() && t.nextOf().isTypeStruct().sym == ad) &&
1069 !(t.isTypeStruct() && t.isTypeStruct().sym == ad))
1070 {
1071 ClassDeclaration cd = ad.isClassDeclaration();
1072 ClassDeclaration tcd = t.isClassHandle();
1073
1074 /* e1 is the right this if ad is a base class of e1
1075 */
1076 if (!cd || !tcd || !(tcd == cd || cd.isBaseOf(tcd, null)))
1077 {
1078 /* Only classes can be inner classes with an 'outer'
1079 * member pointing to the enclosing class instance
1080 */
1081 if (tcd && tcd.isNested())
1082 {
1083 /* e1 is the 'this' pointer for an inner class: tcd.
1084 * Rewrite it as the 'this' pointer for the outer class.
1085 */
1086 auto vthis = tcd.followInstantiationContext(ad) ? tcd.vthis2 : tcd.vthis;
1087 e1 = new DotVarExp(loc, e1, vthis);
1088 e1.type = vthis.type;
1089 e1.type = e1.type.addMod(t.mod);
1090 // Do not call ensureStaticLinkTo()
1091 //e1 = e1.semantic(sc);
1092
1093 // Skip up over nested functions, and get the enclosing
1094 // class type.
1095 e1 = getThisSkipNestedFuncs(loc, sc, tcd.toParentP(ad), ad, e1, t, var);
1096 if (e1.op == EXP.error)
1097 return e1;
1098 goto L1;
1099 }
1100
1101 /* Can't find a path from e1 to ad
1102 */
1103 if (flag)
1104 return null;
1105 e1.error("`this` for `%s` needs to be type `%s` not type `%s`", var.toChars(), ad.toChars(), t.toChars());
1106 return ErrorExp.get();
1107 }
1108 }
1109 return e1;
1110 }
1111
1112 /***************************************
1113 * Pull out any properties.
1114 */
1115 private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 = null)
1116 {
1117 //printf("resolvePropertiesX, e1 = %s %s, e2 = %s\n", EXPtoString(e1.op).ptr, e1.toChars(), e2 ? e2.toChars() : null);
1118 Loc loc = e1.loc;
1119
1120 OverloadSet os;
1121 Dsymbol s;
1122 Objects* tiargs;
1123 Type tthis;
1124 if (auto de = e1.isDotExp())
1125 {
1126 if (auto oe = de.e2.isOverExp())
1127 {
1128 tiargs = null;
1129 tthis = de.e1.type;
1130 os = oe.vars;
1131 goto Los;
1132 }
1133 }
1134 else if (e1.isOverExp())
1135 {
1136 tiargs = null;
1137 tthis = null;
1138 os = e1.isOverExp().vars;
1139 Los:
1140 assert(os);
1141 FuncDeclaration fd = null;
1142 if (e2)
1143 {
1144 e2 = e2.expressionSemantic(sc);
1145 if (e2.op == EXP.error)
1146 return ErrorExp.get();
1147 e2 = resolveProperties(sc, e2);
1148
1149 Expressions a;
1150 a.push(e2);
1151
1152 for (size_t i = 0; i < os.a.dim; i++)
1153 {
1154 if (FuncDeclaration f = resolveFuncCall(loc, sc, os.a[i], tiargs, tthis, &a, FuncResolveFlag.quiet))
1155 {
1156 if (f.errors)
1157 return ErrorExp.get();
1158 fd = f;
1159 assert(fd.type.ty == Tfunction);
1160 }
1161 }
1162 if (fd)
1163 {
1164 Expression e = new CallExp(loc, e1, e2);
1165 return e.expressionSemantic(sc);
1166 }
1167 }
1168 {
1169 for (size_t i = 0; i < os.a.dim; i++)
1170 {
1171 if (FuncDeclaration f = resolveFuncCall(loc, sc, os.a[i], tiargs, tthis, null, FuncResolveFlag.quiet))
1172 {
1173 if (f.errors)
1174 return ErrorExp.get();
1175 fd = f;
1176 assert(fd.type.ty == Tfunction);
1177 auto tf = fd.type.isTypeFunction();
1178 if (!tf.isref && e2)
1179 {
1180 error(loc, "%s is not an lvalue", e1.toChars());
1181 return ErrorExp.get();
1182 }
1183 }
1184 }
1185 if (fd)
1186 {
1187 Expression e = new CallExp(loc, e1);
1188 if (e2)
1189 e = new AssignExp(loc, e, e2);
1190 return e.expressionSemantic(sc);
1191 }
1192 }
1193 if (e2)
1194 goto Leprop;
1195 }
1196 else if (auto dti = e1.isDotTemplateInstanceExp())
1197 {
1198 if (!dti.findTempDecl(sc))
1199 goto Leprop;
1200 if (!dti.ti.semanticTiargs(sc))
1201 goto Leprop;
1202 tiargs = dti.ti.tiargs;
1203 tthis = dti.e1.type;
1204 if ((os = dti.ti.tempdecl.isOverloadSet()) !is null)
1205 goto Los;
1206 if ((s = dti.ti.tempdecl) !is null)
1207 goto Lfd;
1208 }
1209 else if (auto dte = e1.isDotTemplateExp())
1210 {
1211 s = dte.td;
1212 tiargs = null;
1213 tthis = dte.e1.type;
1214 goto Lfd;
1215 }
1216 else if (auto se = e1.isScopeExp())
1217 {
1218 s = se.sds;
1219 TemplateInstance ti = s.isTemplateInstance();
1220 if (ti && !ti.semanticRun && ti.tempdecl)
1221 {
1222 //assert(ti.needsTypeInference(sc));
1223 if (!ti.semanticTiargs(sc))
1224 goto Leprop;
1225 tiargs = ti.tiargs;
1226 tthis = null;
1227 if ((os = ti.tempdecl.isOverloadSet()) !is null)
1228 goto Los;
1229 if ((s = ti.tempdecl) !is null)
1230 goto Lfd;
1231 }
1232 }
1233 else if (auto te = e1.isTemplateExp())
1234 {
1235 s = te.td;
1236 tiargs = null;
1237 tthis = null;
1238 goto Lfd;
1239 }
1240 else if (e1.isDotVarExp() && e1.type && (e1.type.toBasetype().isTypeFunction() || e1.isDotVarExp().var.isOverDeclaration()))
1241 {
1242 DotVarExp dve = e1.isDotVarExp();
1243 s = dve.var;
1244 tiargs = null;
1245 tthis = dve.e1.type;
1246 goto Lfd;
1247 }
1248 else if (sc && sc.flags & SCOPE.Cfile && e1.isVarExp() && !e2)
1249 {
1250 // ImportC: do not implicitly call function if no ( ) are present
1251 }
1252 else if (e1.isVarExp() && e1.type && (e1.type.toBasetype().isTypeFunction() || e1.isVarExp().var.isOverDeclaration()))
1253 {
1254 s = e1.isVarExp().var;
1255 tiargs = null;
1256 tthis = null;
1257 Lfd:
1258 assert(s);
1259 if (e2)
1260 {
1261 e2 = e2.expressionSemantic(sc);
1262 if (e2.op == EXP.error)
1263 return ErrorExp.get();
1264 e2 = resolveProperties(sc, e2);
1265
1266 Expressions a;
1267 a.push(e2);
1268
1269 FuncDeclaration fd = resolveFuncCall(loc, sc, s, tiargs, tthis, &a, FuncResolveFlag.quiet);
1270 if (fd && fd.type)
1271 {
1272 if (fd.errors)
1273 return ErrorExp.get();
1274 if (!checkSymbolAccess(sc, fd))
1275 {
1276 // @@@DEPRECATED_2.105@@@
1277 // When turning into error, uncomment the return statement
1278 TypeFunction tf = fd.type.isTypeFunction();
1279 deprecation(loc, "Function `%s` of type `%s` is not accessible from module `%s`",
1280 fd.toPrettyChars(), tf.toChars, sc._module.toChars);
1281 //return ErrorExp.get();
1282 }
1283 assert(fd.type.ty == Tfunction);
1284 Expression e = new CallExp(loc, e1, e2);
1285 return e.expressionSemantic(sc);
1286 }
1287 }
1288 {
1289 FuncDeclaration fd = resolveFuncCall(loc, sc, s, tiargs, tthis, null, FuncResolveFlag.quiet);
1290 if (fd && fd.type)
1291 {
1292 if (fd.errors)
1293 return ErrorExp.get();
1294 TypeFunction tf = fd.type.isTypeFunction();
1295 if (!e2 || tf.isref)
1296 {
1297 if (!checkSymbolAccess(sc, fd))
1298 {
1299 // @@@DEPRECATED_2.105@@@
1300 // When turning into error, uncomment the return statement
1301 deprecation(loc, "Function `%s` of type `%s` is not accessible from module `%s`",
1302 fd.toPrettyChars(), tf.toChars, sc._module.toChars);
1303 //return ErrorExp.get();
1304 }
1305 Expression e = new CallExp(loc, e1);
1306 if (e2)
1307 e = new AssignExp(loc, e, e2);
1308 return e.expressionSemantic(sc);
1309 }
1310 }
1311 }
1312 if (FuncDeclaration fd = s.isFuncDeclaration())
1313 {
1314 // Keep better diagnostic message for invalid property usage of functions
1315 assert(fd.type.ty == Tfunction);
1316 Expression e = new CallExp(loc, e1, e2);
1317 return e.expressionSemantic(sc);
1318 }
1319 if (e2)
1320 goto Leprop;
1321 }
1322 if (auto ve = e1.isVarExp())
1323 {
1324 if (auto v = ve.var.isVarDeclaration())
1325 {
1326 if (ve.checkPurity(sc, v))
1327 return ErrorExp.get();
1328 }
1329 }
1330 if (e2)
1331 return null;
1332
1333 if (e1.type && !e1.isTypeExp()) // function type is not a property
1334 {
1335 /* Look for e1 being a lazy parameter; rewrite as delegate call
1336 * only if the symbol wasn't already treated as a delegate
1337 */
1338 auto ve = e1.isVarExp();
1339 if (ve && ve.var.storage_class & STC.lazy_ && !ve.delegateWasExtracted)
1340 {
1341 Expression e = new CallExp(loc, e1);
1342 return e.expressionSemantic(sc);
1343 }
1344 else if (e1.isDotVarExp())
1345 {
1346 // Check for reading overlapped pointer field in @safe code.
1347 if (checkUnsafeAccess(sc, e1, true, true))
1348 return ErrorExp.get();
1349 }
1350 else if (auto ce = e1.isCallExp())
1351 {
1352 // Check for reading overlapped pointer field in @safe code.
1353 if (checkUnsafeAccess(sc, ce.e1, true, true))
1354 return ErrorExp.get();
1355 }
1356 }
1357
1358 if (!e1.type)
1359 {
1360 error(loc, "cannot resolve type for %s", e1.toChars());
1361 e1 = ErrorExp.get();
1362 }
1363 return e1;
1364
1365 Leprop:
1366 error(loc, "not a property %s", e1.toChars());
1367 return ErrorExp.get();
1368 }
1369
resolveProperties(Scope * sc,Expression e)1370 extern (C++) Expression resolveProperties(Scope* sc, Expression e)
1371 {
1372 //printf("resolveProperties(%s)\n", e.toChars());
1373 e = resolvePropertiesX(sc, e);
1374 if (e.checkRightThis(sc))
1375 return ErrorExp.get();
1376 return e;
1377 }
1378
1379 /****************************************
1380 * The common type is determined by applying ?: to each pair.
1381 * Output:
1382 * exps[] properties resolved, implicitly cast to common type, rewritten in place
1383 * Returns:
1384 * The common type, or `null` if an error has occured
1385 */
arrayExpressionToCommonType(Scope * sc,ref Expressions exps)1386 private Type arrayExpressionToCommonType(Scope* sc, ref Expressions exps)
1387 {
1388 /* Still have a problem with:
1389 * ubyte[][] = [ cast(ubyte[])"hello", [1]];
1390 * which works if the array literal is initialized top down with the ubyte[][]
1391 * type, but fails with this function doing bottom up typing.
1392 */
1393
1394 //printf("arrayExpressionToCommonType()\n");
1395 scope IntegerExp integerexp = IntegerExp.literal!0;
1396 scope CondExp condexp = new CondExp(Loc.initial, integerexp, null, null);
1397
1398 Type t0 = null;
1399 Expression e0 = null;
1400 bool foundType;
1401
1402 for (size_t i = 0; i < exps.dim; i++)
1403 {
1404 Expression e = exps[i];
1405 if (!e)
1406 continue;
1407
1408 e = resolveProperties(sc, e);
1409 if (!e.type)
1410 {
1411 e.error("`%s` has no value", e.toChars());
1412 t0 = Type.terror;
1413 continue;
1414 }
1415 if (e.op == EXP.type)
1416 {
1417 foundType = true; // do not break immediately, there might be more errors
1418 e.checkValue(); // report an error "type T has no value"
1419 t0 = Type.terror;
1420 continue;
1421 }
1422 if (e.type.ty == Tvoid)
1423 {
1424 // void expressions do not concur to the determination of the common
1425 // type.
1426 continue;
1427 }
1428 if (checkNonAssignmentArrayOp(e))
1429 {
1430 t0 = Type.terror;
1431 continue;
1432 }
1433
1434 e = doCopyOrMove(sc, e);
1435
1436 if (!foundType && t0 && !t0.equals(e.type))
1437 {
1438 /* This applies ?: to merge the types. It's backwards;
1439 * ?: should call this function to merge types.
1440 */
1441 condexp.type = null;
1442 condexp.e1 = e0;
1443 condexp.e2 = e;
1444 condexp.loc = e.loc;
1445 Expression ex = condexp.expressionSemantic(sc);
1446 if (ex.op == EXP.error)
1447 e = ex;
1448 else
1449 {
1450 // Convert to common type
1451 exps[i] = condexp.e1.castTo(sc, condexp.type);
1452 e = condexp.e2.castTo(sc, condexp.type);
1453 }
1454 }
1455 e0 = e;
1456 t0 = e.type;
1457 if (e.op != EXP.error)
1458 exps[i] = e;
1459 }
1460
1461 // [] is typed as void[]
1462 if (!t0)
1463 return Type.tvoid;
1464
1465 // It's an error, don't do the cast
1466 if (t0.ty == Terror)
1467 return null;
1468
1469 for (size_t i = 0; i < exps.dim; i++)
1470 {
1471 Expression e = exps[i];
1472 if (!e)
1473 continue;
1474
1475 e = e.implicitCastTo(sc, t0);
1476 if (e.op == EXP.error)
1477 {
1478 /* https://issues.dlang.org/show_bug.cgi?id=13024
1479 * a workaround for the bug in typeMerge -
1480 * it should paint e1 and e2 by deduced common type,
1481 * but doesn't in this particular case.
1482 */
1483 return null;
1484 }
1485 exps[i] = e;
1486 }
1487 return t0;
1488 }
1489
opAssignToOp(const ref Loc loc,EXP op,Expression e1,Expression e2)1490 private Expression opAssignToOp(const ref Loc loc, EXP op, Expression e1, Expression e2)
1491 {
1492 Expression e;
1493 switch (op)
1494 {
1495 case EXP.addAssign:
1496 e = new AddExp(loc, e1, e2);
1497 break;
1498
1499 case EXP.minAssign:
1500 e = new MinExp(loc, e1, e2);
1501 break;
1502
1503 case EXP.mulAssign:
1504 e = new MulExp(loc, e1, e2);
1505 break;
1506
1507 case EXP.divAssign:
1508 e = new DivExp(loc, e1, e2);
1509 break;
1510
1511 case EXP.modAssign:
1512 e = new ModExp(loc, e1, e2);
1513 break;
1514
1515 case EXP.andAssign:
1516 e = new AndExp(loc, e1, e2);
1517 break;
1518
1519 case EXP.orAssign:
1520 e = new OrExp(loc, e1, e2);
1521 break;
1522
1523 case EXP.xorAssign:
1524 e = new XorExp(loc, e1, e2);
1525 break;
1526
1527 case EXP.leftShiftAssign:
1528 e = new ShlExp(loc, e1, e2);
1529 break;
1530
1531 case EXP.rightShiftAssign:
1532 e = new ShrExp(loc, e1, e2);
1533 break;
1534
1535 case EXP.unsignedRightShiftAssign:
1536 e = new UshrExp(loc, e1, e2);
1537 break;
1538
1539 default:
1540 assert(0);
1541 }
1542 return e;
1543 }
1544
1545 /*********************
1546 * Rewrite:
1547 * array.length op= e2
1548 * as:
1549 * array.length = array.length op e2
1550 * or:
1551 * auto tmp = &array;
1552 * (*tmp).length = (*tmp).length op e2
1553 */
rewriteOpAssign(BinExp exp)1554 private Expression rewriteOpAssign(BinExp exp)
1555 {
1556 ArrayLengthExp ale = exp.e1.isArrayLengthExp();
1557 if (ale.e1.isVarExp())
1558 {
1559 Expression e = opAssignToOp(exp.loc, exp.op, ale, exp.e2);
1560 e = new AssignExp(exp.loc, ale.syntaxCopy(), e);
1561 return e;
1562 }
1563 else
1564 {
1565 /* auto tmp = &array;
1566 * (*tmp).length = (*tmp).length op e2
1567 */
1568 auto tmp = copyToTemp(0, "__arraylength", new AddrExp(ale.loc, ale.e1));
1569
1570 Expression e1 = new ArrayLengthExp(ale.loc, new PtrExp(ale.loc, new VarExp(ale.loc, tmp)));
1571 Expression elvalue = e1.syntaxCopy();
1572 Expression e = opAssignToOp(exp.loc, exp.op, e1, exp.e2);
1573 e = new AssignExp(exp.loc, elvalue, e);
1574 e = new CommaExp(exp.loc, new DeclarationExp(ale.loc, tmp), e);
1575 return e;
1576 }
1577 }
1578
1579 /****************************************
1580 * Preprocess arguments to function.
1581 * Input:
1582 * reportErrors whether or not to report errors here. Some callers are not
1583 * checking actual function params, so they'll do their own error reporting
1584 * Output:
1585 * exps[] tuples expanded, properties resolved, rewritten in place
1586 * Returns:
1587 * true a semantic error occurred
1588 */
1589 private bool preFunctionParameters(Scope* sc, Expressions* exps, const bool reportErrors = true)
1590 {
1591 bool err = false;
1592 if (exps)
1593 {
1594 expandTuples(exps);
1595
1596 for (size_t i = 0; i < exps.dim; i++)
1597 {
1598 Expression arg = (*exps)[i];
1599 arg = resolveProperties(sc, arg);
1600 arg = arg.arrayFuncConv(sc);
1601 if (arg.op == EXP.type)
1602 {
1603 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
1604 arg = resolveAliasThis(sc, arg);
1605
1606 if (arg.op == EXP.type)
1607 {
1608 if (reportErrors)
1609 {
1610 arg.error("cannot pass type `%s` as a function argument", arg.toChars());
1611 arg = ErrorExp.get();
1612 }
1613 err = true;
1614 }
1615 }
1616 else if (arg.type.toBasetype().ty == Tfunction)
1617 {
1618 if (reportErrors)
1619 {
1620 arg.error("cannot pass function `%s` as a function argument", arg.toChars());
1621 arg = ErrorExp.get();
1622 }
1623 err = true;
1624 }
1625 else if (checkNonAssignmentArrayOp(arg))
1626 {
1627 arg = ErrorExp.get();
1628 err = true;
1629 }
1630 (*exps)[i] = arg;
1631 }
1632 }
1633 return err;
1634 }
1635
1636 /********************************************
1637 * Issue an error if default construction is disabled for type t.
1638 * Default construction is required for arrays and 'out' parameters.
1639 * Returns:
1640 * true an error was issued
1641 */
checkDefCtor(Loc loc,Type t)1642 private bool checkDefCtor(Loc loc, Type t)
1643 {
1644 if (auto ts = t.baseElemOf().isTypeStruct())
1645 {
1646 StructDeclaration sd = ts.sym;
1647 if (sd.noDefaultCtor)
1648 {
1649 sd.error(loc, "default construction is disabled");
1650 return true;
1651 }
1652 }
1653 return false;
1654 }
1655
1656 /****************************************
1657 * Now that we know the exact type of the function we're calling,
1658 * the arguments[] need to be adjusted:
1659 * 1. implicitly convert argument to the corresponding parameter type
1660 * 2. add default arguments for any missing arguments
1661 * 3. do default promotions on arguments corresponding to ...
1662 * 4. add hidden _arguments[] argument
1663 * 5. call copy constructor for struct value arguments
1664 * Params:
1665 * loc = location of function call
1666 * sc = context
1667 * tf = type of the function
1668 * ethis = `this` argument, `null` if none or not known
1669 * tthis = type of `this` argument, `null` if no `this` argument
1670 * arguments = array of actual arguments to function call
1671 * fd = the function being called, `null` if called indirectly
1672 * prettype = set to return type of function
1673 * peprefix = set to expression to execute before `arguments[]` are evaluated, `null` if none
1674 * Returns:
1675 * true errors happened
1676 */
functionParameters(const ref Loc loc,Scope * sc,TypeFunction tf,Expression ethis,Type tthis,Expressions * arguments,FuncDeclaration fd,Type * prettype,Expression * peprefix)1677 private bool functionParameters(const ref Loc loc, Scope* sc,
1678 TypeFunction tf, Expression ethis, Type tthis, Expressions* arguments, FuncDeclaration fd,
1679 Type* prettype, Expression* peprefix)
1680 {
1681 //printf("functionParameters() %s\n", fd ? fd.toChars() : "");
1682 assert(arguments);
1683 assert(fd || tf.next);
1684 size_t nargs = arguments ? arguments.dim : 0;
1685 const size_t nparams = tf.parameterList.length;
1686 const olderrors = global.errors;
1687 bool err = false;
1688 *prettype = Type.terror;
1689 Expression eprefix = null;
1690 *peprefix = null;
1691
1692 if (nargs > nparams && tf.parameterList.varargs == VarArg.none)
1693 {
1694 error(loc, "expected %llu arguments, not %llu for non-variadic function type `%s`", cast(ulong)nparams, cast(ulong)nargs, tf.toChars());
1695 return true;
1696 }
1697
1698 // If inferring return type, and semantic3() needs to be run if not already run
1699 if (!tf.next && fd.inferRetType)
1700 {
1701 fd.functionSemantic();
1702 }
1703 else if (fd && fd.parent)
1704 {
1705 TemplateInstance ti = fd.parent.isTemplateInstance();
1706 if (ti && ti.tempdecl)
1707 {
1708 fd.functionSemantic3();
1709 }
1710 }
1711
1712 /* If calling a pragma(inline, true) function,
1713 * set flag to later scan for inlines.
1714 */
1715 if (fd && fd.inlining == PINLINE.always)
1716 {
1717 if (sc._module)
1718 sc._module.hasAlwaysInlines = true;
1719 if (sc.func)
1720 sc.func.flags |= FUNCFLAG.hasAlwaysInline;
1721 }
1722
1723 const isCtorCall = fd && fd.needThis() && fd.isCtorDeclaration();
1724
1725 const size_t n = (nargs > nparams) ? nargs : nparams; // n = max(nargs, nparams)
1726
1727 /* If the function return type has wildcards in it, we'll need to figure out the actual type
1728 * based on the actual argument types.
1729 * Start with the `this` argument, later on merge into wildmatch the mod bits of the rest
1730 * of the arguments.
1731 */
1732 MOD wildmatch = (tthis && !isCtorCall) ? tthis.Type.deduceWild(tf, false) : 0;
1733
1734 bool done = false;
1735 foreach (const i; 0 .. n)
1736 {
1737 Expression arg = (i < nargs) ? (*arguments)[i] : null;
1738
1739 if (i < nparams)
1740 {
1741 bool errorArgs()
1742 {
1743 error(loc, "expected %llu function arguments, not %llu", cast(ulong)nparams, cast(ulong)nargs);
1744 return true;
1745 }
1746
1747 Parameter p = tf.parameterList[i];
1748
1749 if (!arg)
1750 {
1751 if (!p.defaultArg)
1752 {
1753 if (tf.parameterList.varargs == VarArg.typesafe && i + 1 == nparams)
1754 goto L2;
1755 return errorArgs();
1756 }
1757 arg = p.defaultArg;
1758 arg = inlineCopy(arg, sc);
1759 // __FILE__, __LINE__, __MODULE__, __FUNCTION__, and __PRETTY_FUNCTION__
1760 arg = arg.resolveLoc(loc, sc);
1761 arguments.push(arg);
1762 nargs++;
1763 }
1764 else
1765 {
1766 if (isDefaultInitOp(arg.op))
1767 {
1768 arg = arg.resolveLoc(loc, sc);
1769 (*arguments)[i] = arg;
1770 }
1771 }
1772
1773
1774 if (tf.parameterList.varargs == VarArg.typesafe && i + 1 == nparams) // https://dlang.org/spec/function.html#variadic
1775 {
1776 //printf("\t\tvarargs == 2, p.type = '%s'\n", p.type.toChars());
1777 {
1778 MATCH m;
1779 if ((m = arg.implicitConvTo(p.type)) > MATCH.nomatch)
1780 {
1781 if (p.type.nextOf() && arg.implicitConvTo(p.type.nextOf()) >= m)
1782 goto L2;
1783 else if (nargs != nparams)
1784 return errorArgs();
1785 goto L1;
1786 }
1787 }
1788 L2:
1789 Type tb = p.type.toBasetype();
1790 switch (tb.ty)
1791 {
1792 case Tsarray:
1793 case Tarray:
1794 {
1795 /* Create a static array variable v of type arg.type:
1796 * T[dim] __arrayArg = [ arguments[i], ..., arguments[nargs-1] ];
1797 *
1798 * The array literal in the initializer of the hidden variable
1799 * is now optimized.
1800 * https://issues.dlang.org/show_bug.cgi?id=2356
1801 */
1802 Type tbn = (cast(TypeArray)tb).next; // array element type
1803 Type tret = p.isLazyArray();
1804
1805 auto elements = new Expressions(nargs - i);
1806 foreach (u; 0 .. elements.dim)
1807 {
1808 Expression a = (*arguments)[i + u];
1809 if (tret && a.implicitConvTo(tret))
1810 {
1811 // p is a lazy array of delegates, tret is return type of the delegates
1812 a = a.implicitCastTo(sc, tret)
1813 .optimize(WANTvalue)
1814 .toDelegate(tret, sc);
1815 }
1816 else
1817 a = a.implicitCastTo(sc, tbn);
1818 a = a.addDtorHook(sc);
1819 (*elements)[u] = a;
1820 }
1821 // https://issues.dlang.org/show_bug.cgi?id=14395
1822 // Convert to a static array literal, or its slice.
1823 arg = new ArrayLiteralExp(loc, tbn.sarrayOf(nargs - i), elements);
1824 if (tb.ty == Tarray)
1825 {
1826 arg = new SliceExp(loc, arg, null, null);
1827 arg.type = p.type;
1828 }
1829 break;
1830 }
1831 case Tclass:
1832 {
1833 /* Set arg to be:
1834 * new Tclass(arg0, arg1, ..., argn)
1835 */
1836 auto args = new Expressions(nargs - i);
1837 foreach (u; i .. nargs)
1838 (*args)[u - i] = (*arguments)[u];
1839 arg = new NewExp(loc, null, p.type, args);
1840 break;
1841 }
1842 default:
1843 if (!arg)
1844 {
1845 error(loc, "not enough arguments");
1846 return true;
1847 }
1848 break;
1849 }
1850 arg = arg.expressionSemantic(sc);
1851 //printf("\targ = '%s'\n", arg.toChars());
1852 arguments.setDim(i + 1);
1853 (*arguments)[i] = arg;
1854 nargs = i + 1;
1855 done = true;
1856 }
1857
1858 L1:
1859 if (!(p.storageClass & STC.lazy_ && p.type.ty == Tvoid))
1860 {
1861 if (ubyte wm = arg.type.deduceWild(p.type, p.isReference()))
1862 {
1863 wildmatch = wildmatch ? MODmerge(wildmatch, wm) : wm;
1864 //printf("[%d] p = %s, a = %s, wm = %d, wildmatch = %d\n", i, p.type.toChars(), arg.type.toChars(), wm, wildmatch);
1865 }
1866 }
1867 }
1868 if (done)
1869 break;
1870 }
1871 if ((wildmatch == MODFlags.mutable || wildmatch == MODFlags.immutable_) &&
1872 tf.next && tf.next.hasWild() &&
1873 (tf.isref || !tf.next.implicitConvTo(tf.next.immutableOf())))
1874 {
1875 bool errorInout(MOD wildmatch)
1876 {
1877 const(char)* s = wildmatch == MODFlags.mutable ? "mutable" : MODtoChars(wildmatch);
1878 error(loc, "modify `inout` to `%s` is not allowed inside `inout` function", s);
1879 return true;
1880 }
1881
1882 if (fd)
1883 {
1884 /* If the called function may return the reference to
1885 * outer inout data, it should be rejected.
1886 *
1887 * void foo(ref inout(int) x) {
1888 * ref inout(int) bar(inout(int)) { return x; }
1889 * struct S {
1890 * ref inout(int) bar() inout { return x; }
1891 * ref inout(int) baz(alias a)() inout { return x; }
1892 * }
1893 * bar(int.init) = 1; // bad!
1894 * S().bar() = 1; // bad!
1895 * }
1896 * void test() {
1897 * int a;
1898 * auto s = foo(a);
1899 * s.baz!a() = 1; // bad!
1900 * }
1901 *
1902 */
1903 bool checkEnclosingWild(Dsymbol s)
1904 {
1905 bool checkWild(Dsymbol s)
1906 {
1907 if (!s)
1908 return false;
1909 if (auto ad = s.isAggregateDeclaration())
1910 {
1911 if (ad.isNested())
1912 return checkEnclosingWild(s);
1913 }
1914 else if (auto ff = s.isFuncDeclaration())
1915 {
1916 if (ff.type.isTypeFunction().iswild)
1917 return errorInout(wildmatch);
1918
1919 if (ff.isNested() || ff.isThis())
1920 return checkEnclosingWild(s);
1921 }
1922 return false;
1923 }
1924
1925 Dsymbol ctx0 = s.toParent2();
1926 Dsymbol ctx1 = s.toParentLocal();
1927 if (checkWild(ctx0))
1928 return true;
1929 if (ctx0 != ctx1)
1930 return checkWild(ctx1);
1931 return false;
1932 }
1933 if ((fd.isThis() || fd.isNested()) && checkEnclosingWild(fd))
1934 return true;
1935 }
1936 else if (tf.isWild())
1937 return errorInout(wildmatch);
1938 }
1939
1940 Expression firstArg = ((tf.next && tf.next.ty == Tvoid || isCtorCall) &&
1941 tthis &&
1942 tthis.isMutable() && tthis.toBasetype().ty == Tstruct &&
1943 tthis.hasPointers())
1944 ? ethis : null;
1945
1946 assert(nargs >= nparams);
1947 foreach (const i, arg; (*arguments)[0 .. nargs])
1948 {
1949 assert(arg);
1950 if (i < nparams)
1951 {
1952 Parameter p = tf.parameterList[i];
1953 Type targ = arg.type; // keep original type for isCopyable() because alias this
1954 // resolution may hide an uncopyable type
1955
1956 if (!(p.storageClass & STC.lazy_ && p.type.ty == Tvoid))
1957 {
1958 Type tprm = p.type.hasWild()
1959 ? p.type.substWildTo(wildmatch)
1960 : p.type;
1961
1962 const hasCopyCtor = arg.type.isTypeStruct() && arg.type.isTypeStruct().sym.hasCopyCtor;
1963 const typesMatch = arg.type.mutableOf().unSharedOf().equals(tprm.mutableOf().unSharedOf());
1964 if (!((hasCopyCtor && typesMatch) || tprm.equals(arg.type)))
1965 {
1966 //printf("arg.type = %s, p.type = %s\n", arg.type.toChars(), p.type.toChars());
1967 arg = arg.implicitCastTo(sc, tprm);
1968 arg = arg.optimize(WANTvalue, p.isReference());
1969 }
1970 }
1971
1972 // Support passing rvalue to `in` parameters
1973 if ((p.storageClass & (STC.in_ | STC.ref_)) == (STC.in_ | STC.ref_))
1974 {
1975 if (!arg.isLvalue())
1976 {
1977 auto v = copyToTemp(STC.exptemp, "__rvalue", arg);
1978 Expression ev = new DeclarationExp(arg.loc, v);
1979 ev = new CommaExp(arg.loc, ev, new VarExp(arg.loc, v));
1980 arg = ev.expressionSemantic(sc);
1981 }
1982 arg = arg.toLvalue(sc, arg);
1983
1984 // Look for mutable misaligned pointer, etc., in @safe mode
1985 err |= checkUnsafeAccess(sc, arg, false, true);
1986 }
1987 else if (p.storageClass & STC.ref_)
1988 {
1989 if (global.params.rvalueRefParam == FeatureState.enabled &&
1990 !arg.isLvalue() &&
1991 targ.isCopyable())
1992 { /* allow rvalues to be passed to ref parameters by copying
1993 * them to a temp, then pass the temp as the argument
1994 */
1995 auto v = copyToTemp(0, "__rvalue", arg);
1996 Expression ev = new DeclarationExp(arg.loc, v);
1997 ev = new CommaExp(arg.loc, ev, new VarExp(arg.loc, v));
1998 arg = ev.expressionSemantic(sc);
1999 }
2000 arg = arg.toLvalue(sc, arg);
2001
2002 // Look for mutable misaligned pointer, etc., in @safe mode
2003 err |= checkUnsafeAccess(sc, arg, false, true);
2004 }
2005 else if (p.storageClass & STC.out_)
2006 {
2007 Type t = arg.type;
2008 if (!t.isMutable() || !t.isAssignable()) // check blit assignable
2009 {
2010 arg.error("cannot modify struct `%s` with immutable members", arg.toChars());
2011 err = true;
2012 }
2013 else
2014 {
2015 // Look for misaligned pointer, etc., in @safe mode
2016 err |= checkUnsafeAccess(sc, arg, false, true);
2017 err |= checkDefCtor(arg.loc, t); // t must be default constructible
2018 }
2019 arg = arg.toLvalue(sc, arg);
2020 }
2021 else if (p.storageClass & STC.lazy_)
2022 {
2023 // Convert lazy argument to a delegate
2024 auto t = (p.type.ty == Tvoid) ? p.type : arg.type;
2025 arg = toDelegate(arg, t, sc);
2026 }
2027 //printf("arg: %s\n", arg.toChars());
2028 //printf("type: %s\n", arg.type.toChars());
2029 //printf("param: %s\n", p.toChars());
2030
2031 const pStc = tf.parameterStorageClass(tthis, p);
2032
2033 if (firstArg && (pStc & STC.return_))
2034 {
2035 /* Argument value can be assigned to firstArg.
2036 * Check arg to see if it matters.
2037 */
2038 if (global.params.useDIP1000 == FeatureState.enabled)
2039 err |= checkParamArgumentReturn(sc, firstArg, arg, p, false);
2040 }
2041 // Allow 'lazy' to imply 'scope' - lazy parameters can be passed along
2042 // as lazy parameters to the next function, but that isn't escaping.
2043 else if (!(pStc & (STC.scope_ | STC.lazy_)))
2044 {
2045 /* Argument value can escape from the called function.
2046 * Check arg to see if it matters.
2047 */
2048 if (global.params.useDIP1000 == FeatureState.enabled)
2049 err |= checkParamArgumentEscape(sc, fd, p, arg, false, false);
2050 }
2051 else if (!(pStc & STC.return_) &&
2052 ((global.params.useDIP1000 == FeatureState.enabled) || !(p.storageClass & STC.scopeinferred)))
2053 {
2054 /* Argument value cannot escape from the called function.
2055 */
2056 Expression a = arg;
2057 if (auto ce = a.isCastExp())
2058 a = ce.e1;
2059
2060 ArrayLiteralExp ale;
2061 if (p.type.toBasetype().ty == Tarray &&
2062 (ale = a.isArrayLiteralExp()) !is null && ale.elements && ale.elements.length > 0)
2063 {
2064 // allocate the array literal as temporary static array on the stack
2065 ale.type = ale.type.nextOf().sarrayOf(ale.elements.length);
2066 auto tmp = copyToTemp(0, "__arrayliteral_on_stack", ale);
2067 auto declareTmp = new DeclarationExp(ale.loc, tmp);
2068 auto castToSlice = new CastExp(ale.loc, new VarExp(ale.loc, tmp),
2069 p.type.substWildTo(MODFlags.mutable));
2070 arg = CommaExp.combine(declareTmp, castToSlice);
2071 arg = arg.expressionSemantic(sc);
2072 }
2073 else if (auto fe = a.isFuncExp())
2074 {
2075 /* Function literals can only appear once, so if this
2076 * appearance was scoped, there cannot be any others.
2077 */
2078 fe.fd.tookAddressOf = 0;
2079 }
2080 else if (auto de = a.isDelegateExp())
2081 {
2082 /* For passing a delegate to a scoped parameter,
2083 * this doesn't count as taking the address of it.
2084 * We only worry about 'escaping' references to the function.
2085 */
2086 if (auto ve = de.e1.isVarExp())
2087 {
2088 if (auto f = ve.var.isFuncDeclaration())
2089 {
2090 if (f.tookAddressOf)
2091 --f.tookAddressOf;
2092 //printf("--tookAddressOf = %d\n", f.tookAddressOf);
2093 }
2094 }
2095 }
2096 }
2097 if (!p.isReference())
2098 err |= arg.checkSharedAccess(sc);
2099
2100 arg = arg.optimize(WANTvalue, p.isReference());
2101
2102 /* Determine if this parameter is the "first reference" parameter through which
2103 * later "return" arguments can be stored.
2104 */
2105 if (i == 0 && !tthis && p.isReference() && p.type &&
2106 (tf.next && tf.next.ty == Tvoid || isCtorCall))
2107 {
2108 Type tb = p.type.baseElemOf();
2109 if (tb.isMutable() && tb.hasPointers())
2110 {
2111 firstArg = arg;
2112 }
2113 }
2114 }
2115 else
2116 {
2117 // These will be the trailing ... arguments
2118 // If not D linkage, do promotions
2119 if (tf.linkage != LINK.d)
2120 {
2121 // Promote bytes, words, etc., to ints
2122 arg = integralPromotions(arg, sc);
2123
2124 // Promote floats to doubles
2125 switch (arg.type.ty)
2126 {
2127 case Tfloat32:
2128 arg = arg.castTo(sc, Type.tfloat64);
2129 break;
2130
2131 case Timaginary32:
2132 arg = arg.castTo(sc, Type.timaginary64);
2133 break;
2134
2135 default:
2136 break;
2137 }
2138 if (tf.parameterList.varargs == VarArg.variadic)
2139 {
2140 const(char)* p = tf.linkage == LINK.c ? "extern(C)" : "extern(C++)";
2141 if (arg.type.ty == Tarray)
2142 {
2143 arg.error("cannot pass dynamic arrays to `%s` vararg functions", p);
2144 err = true;
2145 }
2146 if (arg.type.ty == Tsarray)
2147 {
2148 arg.error("cannot pass static arrays to `%s` vararg functions", p);
2149 err = true;
2150 }
2151 }
2152 }
2153
2154 // Do not allow types that need destructors or copy constructors.
2155 if (arg.type.needsDestruction())
2156 {
2157 arg.error("cannot pass types that need destruction as variadic arguments");
2158 err = true;
2159 }
2160 if (arg.type.needsCopyOrPostblit())
2161 {
2162 arg.error("cannot pass types with postblits or copy constructors as variadic arguments");
2163 err = true;
2164 }
2165
2166 // Convert static arrays to dynamic arrays
2167 // BUG: I don't think this is right for D2
2168 Type tb = arg.type.toBasetype();
2169 if (auto ts = tb.isTypeSArray())
2170 {
2171 Type ta = ts.next.arrayOf();
2172 if (ts.size(arg.loc) == 0)
2173 arg = new NullExp(arg.loc, ta);
2174 else
2175 arg = arg.castTo(sc, ta);
2176 }
2177 if (tb.ty == Tstruct)
2178 {
2179 //arg = callCpCtor(sc, arg);
2180 }
2181 // Give error for overloaded function addresses
2182 if (auto se = arg.isSymOffExp())
2183 {
2184 if (se.hasOverloads && !se.var.isFuncDeclaration().isUnique())
2185 {
2186 arg.error("function `%s` is overloaded", arg.toChars());
2187 err = true;
2188 }
2189 }
2190 err |= arg.checkValue();
2191 err |= arg.checkSharedAccess(sc);
2192 arg = arg.optimize(WANTvalue);
2193 }
2194 (*arguments)[i] = arg;
2195 }
2196
2197 /* If calling C scanf(), printf(), or any variants, check the format string against the arguments
2198 */
2199 const isVa_list = tf.parameterList.varargs == VarArg.none;
2200 if (fd && fd.flags & FUNCFLAG.printf)
2201 {
2202 if (auto se = (*arguments)[nparams - 1 - isVa_list].isStringExp())
2203 {
2204 checkPrintfFormat(se.loc, se.peekString(), (*arguments)[nparams .. nargs], isVa_list);
2205 }
2206 }
2207 else if (fd && fd.flags & FUNCFLAG.scanf)
2208 {
2209 if (auto se = (*arguments)[nparams - 1 - isVa_list].isStringExp())
2210 {
2211 checkScanfFormat(se.loc, se.peekString(), (*arguments)[nparams .. nargs], isVa_list);
2212 }
2213 }
2214 else
2215 {
2216 // TODO: not checking the "v" functions yet (for those, check format string only, not args)
2217 }
2218
2219 /* Remaining problems:
2220 * 1. order of evaluation - some function push L-to-R, others R-to-L. Until we resolve what array assignment does (which is
2221 * implemented by calling a function) we'll defer this for now.
2222 * 2. value structs (or static arrays of them) that need to be copy constructed
2223 * 3. value structs (or static arrays of them) that have destructors, and subsequent arguments that may throw before the
2224 * function gets called.
2225 * 4. value structs need to be destructed after the function call for platforms where the caller destroys the arguments.
2226 * 2, 3 and 4 are handled by doing the argument construction in 'eprefix' so that if a later argument throws, they are cleaned
2227 * up properly. Pushing arguments on the stack then cannot fail.
2228 */
2229 {
2230 /* TODO: tackle problem 1)
2231 */
2232 const bool leftToRight = true; // TODO: Any cases that need rightToLeft?
2233 if (!leftToRight)
2234 assert(nargs == nparams); // no variadics for RTL order, as they would probably be evaluated LTR and so add complexity
2235
2236 /* Does Problem (4) apply?
2237 */
2238 const bool callerDestroysArgs = !target.isCalleeDestroyingArgs(tf);
2239
2240 const ptrdiff_t start = (leftToRight ? 0 : cast(ptrdiff_t)nargs - 1);
2241 const ptrdiff_t end = (leftToRight ? cast(ptrdiff_t)nargs : -1);
2242 const ptrdiff_t step = (leftToRight ? 1 : -1);
2243
2244 /* Compute indices of last throwing argument and first arg needing destruction.
2245 * Used to not set up destructors unless an arg needs destruction on a throw
2246 * in a later argument.
2247 */
2248 ptrdiff_t lastthrow = -1; // last argument that may throw
2249 ptrdiff_t firstdtor = -1; // first argument that needs destruction
2250 ptrdiff_t lastdtor = -1; // last argument that needs destruction
2251 for (ptrdiff_t i = start; i != end; i += step)
2252 {
2253 Expression arg = (*arguments)[i];
2254 if (canThrow(arg, sc.func, false))
2255 lastthrow = i;
2256 if (arg.type.needsDestruction())
2257 {
2258 Parameter p = (i >= nparams ? null : tf.parameterList[i]);
2259 if (!(p && (p.storageClass & (STC.lazy_ | STC.ref_ | STC.out_))))
2260 {
2261 if (firstdtor == -1)
2262 firstdtor = i;
2263 lastdtor = i;
2264 }
2265 }
2266 }
2267
2268 /* Do we need 'eprefix' for problems 3 or 4?
2269 */
2270 const bool needsPrefix = callerDestroysArgs
2271 ? firstdtor >= 0 // true if any argument needs destruction
2272 : firstdtor >= 0 && lastthrow >= 0 &&
2273 (lastthrow - firstdtor) * step > 0; // last throw after first destruction
2274 const ptrdiff_t lastPrefix = callerDestroysArgs
2275 ? lastdtor // up to last argument requiring destruction
2276 : lastthrow; // up to last potentially throwing argument
2277
2278 /* Problem 3: initialize 'eprefix' by declaring the gate
2279 */
2280 VarDeclaration gate;
2281 if (needsPrefix && !callerDestroysArgs)
2282 {
2283 // eprefix => bool __gate [= false]
2284 Identifier idtmp = Identifier.generateId("__gate");
2285 gate = new VarDeclaration(loc, Type.tbool, idtmp, null);
2286 gate.storage_class |= STC.temp | STC.ctfe | STC.volatile_;
2287 gate.dsymbolSemantic(sc);
2288
2289 auto ae = new DeclarationExp(loc, gate);
2290 eprefix = ae.expressionSemantic(sc);
2291 }
2292
2293 for (ptrdiff_t i = start; i != end; i += step)
2294 {
2295 Expression arg = (*arguments)[i];
2296 //printf("arg[%d]: %s\n", cast(int)i, arg.toChars());
2297
2298 Parameter parameter = (i >= nparams ? null : tf.parameterList[i]);
2299 const bool isRef = parameter && parameter.isReference();
2300 const bool isLazy = (parameter && (parameter.storageClass & STC.lazy_));
2301
2302 /* Skip lazy parameters
2303 */
2304 if (isLazy)
2305 continue;
2306
2307 /* Do we have 'eprefix' and aren't past 'lastPrefix' yet?
2308 * Then declare a temporary variable for this arg and append that declaration
2309 * to 'eprefix', which will implicitly take care of potential problem 2) for
2310 * this arg.
2311 * 'eprefix' will therefore finally contain all args up to and including 'lastPrefix',
2312 * excluding all lazy parameters.
2313 */
2314 if (needsPrefix && (lastPrefix - i) * step >= 0)
2315 {
2316 const bool needsDtor = !isRef && arg.type.needsDestruction() &&
2317 // Problem 3: last throwing arg doesn't require dtor patching
2318 (callerDestroysArgs || i != lastPrefix);
2319
2320 /* Declare temporary 'auto __pfx = arg' (needsDtor) or 'auto __pfy = arg' (!needsDtor)
2321 */
2322 auto tmp = copyToTemp(
2323 (parameter ? parameter.storageClass : tf.parameterList.stc) & (STC.scope_),
2324 needsDtor ? "__pfx" : "__pfy",
2325 !isRef ? arg : arg.addressOf());
2326 tmp.dsymbolSemantic(sc);
2327
2328 if (callerDestroysArgs)
2329 {
2330 /* Problem 4: Normal temporary, destructed after the call
2331 */
2332 if (needsDtor)
2333 tmp.isArgDtorVar = true; // mark it so that the backend passes it by ref to the function being called
2334 }
2335 else
2336 {
2337 /* Problem 3: Modify the destructor so it only runs if gate==false,
2338 * i.e., only if there was a throw while constructing the args
2339 */
2340 if (!needsDtor)
2341 {
2342 if (tmp.edtor)
2343 {
2344 assert(i == lastPrefix);
2345 tmp.edtor = null;
2346 }
2347 }
2348 else
2349 {
2350 // edtor => (__gate || edtor)
2351 assert(tmp.edtor);
2352 Expression e = tmp.edtor;
2353 e = new LogicalExp(e.loc, EXP.orOr, new VarExp(e.loc, gate), e);
2354 tmp.edtor = e.expressionSemantic(sc);
2355 //printf("edtor: %s\n", tmp.edtor.toChars());
2356 }
2357 }
2358
2359 // eprefix => (eprefix, auto __pfx/y = arg)
2360 auto ae = new DeclarationExp(loc, tmp);
2361 eprefix = Expression.combine(eprefix, ae.expressionSemantic(sc));
2362
2363 // arg => __pfx/y
2364 arg = new VarExp(loc, tmp);
2365 arg = arg.expressionSemantic(sc);
2366 if (isRef)
2367 {
2368 arg = new PtrExp(loc, arg);
2369 arg = arg.expressionSemantic(sc);
2370 }
2371
2372 /* Problem 3: Last throwing arg?
2373 * Then finalize eprefix => (eprefix, gate = true), i.e., disable the
2374 * dtors right after constructing the last throwing arg.
2375 * From now on, the callee will take care of destructing the args because
2376 * the args are implicitly moved into function parameters.
2377 */
2378 if (!callerDestroysArgs && i == lastPrefix)
2379 {
2380 auto e = new AssignExp(gate.loc, new VarExp(gate.loc, gate), IntegerExp.createBool(true));
2381 eprefix = Expression.combine(eprefix, e.expressionSemantic(sc));
2382 }
2383 }
2384 else // not part of 'eprefix'
2385 {
2386 /* Handle problem 2) by calling the copy constructor for value structs
2387 * (or static arrays of them) if appropriate.
2388 */
2389 Type tv = arg.type.baseElemOf();
2390 if (!isRef && tv.ty == Tstruct)
2391 arg = doCopyOrMove(sc, arg, parameter ? parameter.type : null);
2392 }
2393
2394 (*arguments)[i] = arg;
2395 }
2396 }
2397 //if (eprefix) printf("eprefix: %s\n", eprefix.toChars());
2398
2399 /* Test compliance with DIP1021
2400 */
2401 if (global.params.useDIP1021 &&
2402 tf.trust != TRUST.system && tf.trust != TRUST.trusted)
2403 err |= checkMutableArguments(sc, fd, tf, ethis, arguments, false);
2404
2405 // If D linkage and variadic, add _arguments[] as first argument
2406 if (tf.isDstyleVariadic())
2407 {
2408 assert(arguments.dim >= nparams);
2409
2410 auto args = new Parameters(arguments.dim - nparams);
2411 for (size_t i = 0; i < arguments.dim - nparams; i++)
2412 {
2413 auto arg = new Parameter(STC.in_, (*arguments)[nparams + i].type, null, null, null);
2414 (*args)[i] = arg;
2415 }
2416 auto tup = new TypeTuple(args);
2417 Expression e = (new TypeidExp(loc, tup)).expressionSemantic(sc);
2418 arguments.insert(0, e);
2419 }
2420
2421 /* Determine function return type: tret
2422 */
2423 Type tret = tf.next;
2424 if (isCtorCall)
2425 {
2426 //printf("[%s] fd = %s %s, %d %d %d\n", loc.toChars(), fd.toChars(), fd.type.toChars(),
2427 // wildmatch, tf.isWild(), fd.isReturnIsolated());
2428 if (!tthis)
2429 {
2430 assert(sc.intypeof || global.errors);
2431 tthis = fd.isThis().type.addMod(fd.type.mod);
2432 }
2433 if (tf.isWild() && !fd.isReturnIsolated())
2434 {
2435 if (wildmatch)
2436 tret = tret.substWildTo(wildmatch);
2437 int offset;
2438 if (!tret.implicitConvTo(tthis) && !(MODimplicitConv(tret.mod, tthis.mod) && tret.isBaseOf(tthis, &offset) && offset == 0))
2439 {
2440 const(char)* s1 = tret.isNaked() ? " mutable" : tret.modToChars();
2441 const(char)* s2 = tthis.isNaked() ? " mutable" : tthis.modToChars();
2442 .error(loc, "`inout` constructor `%s` creates%s object, not%s", fd.toPrettyChars(), s1, s2);
2443 err = true;
2444 }
2445 }
2446 tret = tthis;
2447 }
2448 else if (wildmatch && tret)
2449 {
2450 /* Adjust function return type based on wildmatch
2451 */
2452 //printf("wildmatch = x%x, tret = %s\n", wildmatch, tret.toChars());
2453 tret = tret.substWildTo(wildmatch);
2454 }
2455
2456 *prettype = tret;
2457 *peprefix = eprefix;
2458 return (err || olderrors != global.errors);
2459 }
2460
2461 /**
2462 * Determines whether a symbol represents a module or package
2463 * (Used as a helper for is(type == module) and is(type == package))
2464 *
2465 * Params:
2466 * sym = the symbol to be checked
2467 *
2468 * Returns:
2469 * the symbol which `sym` represents (or `null` if it doesn't represent a `Package`)
2470 */
resolveIsPackage(Dsymbol sym)2471 Package resolveIsPackage(Dsymbol sym)
2472 {
2473 Package pkg;
2474 if (Import imp = sym.isImport())
2475 {
2476 if (imp.pkg is null)
2477 {
2478 .error(sym.loc, "Internal Compiler Error: unable to process forward-referenced import `%s`",
2479 imp.toChars());
2480 assert(0);
2481 }
2482 pkg = imp.pkg;
2483 }
2484 else if (auto mod = sym.isModule())
2485 pkg = mod.isPackageFile ? mod.pkg : sym.isPackage();
2486 else
2487 pkg = sym.isPackage();
2488 if (pkg)
2489 pkg.resolvePKGunknown();
2490 return pkg;
2491 }
2492
loadStdMath()2493 private Module loadStdMath()
2494 {
2495 __gshared Import impStdMath = null;
2496 __gshared Identifier[1] stdID;
2497 if (!impStdMath)
2498 {
2499 stdID[0] = Id.std;
2500 auto s = new Import(Loc.initial, stdID[], Id.math, null, false);
2501 // Module.load will call fatal() if there's no std.math available.
2502 // Gag the error here, pushing the error handling to the caller.
2503 uint errors = global.startGagging();
2504 s.load(null);
2505 if (s.mod)
2506 {
2507 s.mod.importAll(null);
2508 s.mod.dsymbolSemantic(null);
2509 }
2510 global.endGagging(errors);
2511 impStdMath = s;
2512 }
2513 return impStdMath.mod;
2514 }
2515
2516 private extern (C++) final class ExpressionSemanticVisitor : Visitor
2517 {
2518 alias visit = Visitor.visit;
2519
2520 Scope* sc;
2521 Expression result;
2522
this(Scope * sc)2523 this(Scope* sc)
2524 {
2525 this.sc = sc;
2526 }
2527
setError()2528 private void setError()
2529 {
2530 result = ErrorExp.get();
2531 }
2532
2533 /**************************
2534 * Semantically analyze Expression.
2535 * Determine types, fold constants, etc.
2536 */
visit(Expression e)2537 override void visit(Expression e)
2538 {
2539 static if (LOGSEMANTIC)
2540 {
2541 printf("Expression::semantic() %s\n", e.toChars());
2542 }
2543 if (e.type)
2544 e.type = e.type.typeSemantic(e.loc, sc);
2545 else
2546 e.type = Type.tvoid;
2547 result = e;
2548 }
2549
visit(IntegerExp e)2550 override void visit(IntegerExp e)
2551 {
2552 assert(e.type);
2553 if (e.type.ty == Terror)
2554 return setError();
2555
2556 assert(e.type.deco);
2557 e.setInteger(e.getInteger());
2558 result = e;
2559 }
2560
visit(RealExp e)2561 override void visit(RealExp e)
2562 {
2563 if (!e.type)
2564 e.type = Type.tfloat64;
2565 else
2566 e.type = e.type.typeSemantic(e.loc, sc);
2567 result = e;
2568 }
2569
visit(ComplexExp e)2570 override void visit(ComplexExp e)
2571 {
2572 if (!e.type)
2573 e.type = Type.tcomplex80;
2574 else
2575 e.type = e.type.typeSemantic(e.loc, sc);
2576 result = e;
2577 }
2578
visit(IdentifierExp exp)2579 override void visit(IdentifierExp exp)
2580 {
2581 static if (LOGSEMANTIC)
2582 {
2583 printf("IdentifierExp::semantic('%s')\n", exp.ident.toChars());
2584 }
2585 if (exp.type) // This is used as the dummy expression
2586 {
2587 result = exp;
2588 return;
2589 }
2590
2591 Dsymbol scopesym;
2592 Dsymbol s = sc.search(exp.loc, exp.ident, &scopesym);
2593 if (s)
2594 {
2595 if (s.errors)
2596 return setError();
2597
2598 Expression e;
2599
2600 /* See if the symbol was a member of an enclosing 'with'
2601 */
2602 WithScopeSymbol withsym = scopesym.isWithScopeSymbol();
2603 if (withsym && withsym.withstate.wthis && symbolIsVisible(sc, s))
2604 {
2605 /* Disallow shadowing
2606 */
2607 // First find the scope of the with
2608 Scope* scwith = sc;
2609 while (scwith.scopesym != scopesym)
2610 {
2611 scwith = scwith.enclosing;
2612 assert(scwith);
2613 }
2614 // Look at enclosing scopes for symbols with the same name,
2615 // in the same function
2616 for (Scope* scx = scwith; scx && scx.func == scwith.func; scx = scx.enclosing)
2617 {
2618 Dsymbol s2;
2619 if (scx.scopesym && scx.scopesym.symtab && (s2 = scx.scopesym.symtab.lookup(s.ident)) !is null && s != s2)
2620 {
2621 exp.error("with symbol `%s` is shadowing local symbol `%s`", s.toPrettyChars(), s2.toPrettyChars());
2622 return setError();
2623 }
2624 }
2625 s = s.toAlias();
2626
2627 // Same as wthis.ident
2628 // TODO: DotIdExp.semantic will find 'ident' from 'wthis' again.
2629 // The redudancy should be removed.
2630 e = new VarExp(exp.loc, withsym.withstate.wthis);
2631 e = new DotIdExp(exp.loc, e, exp.ident);
2632 e = e.expressionSemantic(sc);
2633 }
2634 else
2635 {
2636 if (withsym)
2637 {
2638 if (withsym.withstate.exp.type.ty != Tvoid)
2639 {
2640 // 'with (exp)' is a type expression
2641 // or 's' is not visible there (for error message)
2642 e = new TypeExp(exp.loc, withsym.withstate.exp.type);
2643 }
2644 else
2645 {
2646 // 'with (exp)' is a Package/Module
2647 e = withsym.withstate.exp;
2648 }
2649 e = new DotIdExp(exp.loc, e, exp.ident);
2650 result = e.expressionSemantic(sc);
2651 return;
2652 }
2653
2654 /* If f is really a function template,
2655 * then replace f with the function template declaration.
2656 */
2657 FuncDeclaration f = s.isFuncDeclaration();
2658 if (f)
2659 {
2660 TemplateDeclaration td = getFuncTemplateDecl(f);
2661 if (td)
2662 {
2663 if (td.overroot) // if not start of overloaded list of TemplateDeclaration's
2664 td = td.overroot; // then get the start
2665 e = new TemplateExp(exp.loc, td, f);
2666 e = e.expressionSemantic(sc);
2667 result = e;
2668 return;
2669 }
2670 }
2671
2672 if (global.params.fixAliasThis)
2673 {
2674 ExpressionDsymbol expDsym = scopesym.isExpressionDsymbol();
2675 if (expDsym)
2676 {
2677 //printf("expDsym = %s\n", expDsym.exp.toChars());
2678 result = expDsym.exp.expressionSemantic(sc);
2679 return;
2680 }
2681 }
2682 // Haven't done overload resolution yet, so pass 1
2683 e = symbolToExp(s, exp.loc, sc, true);
2684 }
2685 result = e;
2686 return;
2687 }
2688
2689 if (!global.params.fixAliasThis && hasThis(sc))
2690 {
2691 for (AggregateDeclaration ad = sc.getStructClassScope(); ad;)
2692 {
2693 if (ad.aliasthis)
2694 {
2695 Expression e;
2696 e = new ThisExp(exp.loc);
2697 e = new DotIdExp(exp.loc, e, ad.aliasthis.ident);
2698 e = new DotIdExp(exp.loc, e, exp.ident);
2699 e = e.trySemantic(sc);
2700 if (e)
2701 {
2702 result = e;
2703 return;
2704 }
2705 }
2706
2707 auto cd = ad.isClassDeclaration();
2708 if (cd && cd.baseClass && cd.baseClass != ClassDeclaration.object)
2709 {
2710 ad = cd.baseClass;
2711 continue;
2712 }
2713 break;
2714 }
2715 }
2716
2717 if (exp.ident == Id.ctfe)
2718 {
2719 if (sc.flags & SCOPE.ctfe)
2720 {
2721 exp.error("variable `__ctfe` cannot be read at compile time");
2722 return setError();
2723 }
2724
2725 // Create the magic __ctfe bool variable
2726 auto vd = new VarDeclaration(exp.loc, Type.tbool, Id.ctfe, null);
2727 vd.storage_class |= STC.temp;
2728 vd.semanticRun = PASS.semanticdone;
2729 Expression e = new VarExp(exp.loc, vd);
2730 e = e.expressionSemantic(sc);
2731 result = e;
2732 return;
2733 }
2734
2735 // If we've reached this point and are inside a with() scope then we may
2736 // try one last attempt by checking whether the 'wthis' object supports
2737 // dynamic dispatching via opDispatch.
2738 // This is done by rewriting this expression as wthis.ident.
2739 // The innermost with() scope of the hierarchy to satisfy the condition
2740 // above wins.
2741 // https://issues.dlang.org/show_bug.cgi?id=6400
2742 for (Scope* sc2 = sc; sc2; sc2 = sc2.enclosing)
2743 {
2744 if (!sc2.scopesym)
2745 continue;
2746
2747 if (auto ss = sc2.scopesym.isWithScopeSymbol())
2748 {
2749 if (ss.withstate.wthis)
2750 {
2751 Expression e;
2752 e = new VarExp(exp.loc, ss.withstate.wthis);
2753 e = new DotIdExp(exp.loc, e, exp.ident);
2754 e = e.trySemantic(sc);
2755 if (e)
2756 {
2757 result = e;
2758 return;
2759 }
2760 }
2761 // Try Type.opDispatch (so the static version)
2762 else if (ss.withstate.exp && ss.withstate.exp.op == EXP.type)
2763 {
2764 if (Type t = ss.withstate.exp.isTypeExp().type)
2765 {
2766 Expression e;
2767 e = new TypeExp(exp.loc, t);
2768 e = new DotIdExp(exp.loc, e, exp.ident);
2769 e = e.trySemantic(sc);
2770 if (e)
2771 {
2772 result = e;
2773 return;
2774 }
2775 }
2776 }
2777 }
2778 }
2779
2780 /* Look for what user might have meant
2781 */
2782 if (const n = importHint(exp.ident.toString()))
2783 exp.error("`%s` is not defined, perhaps `import %.*s;` is needed?", exp.ident.toChars(), cast(int)n.length, n.ptr);
2784 else if (auto s2 = sc.search_correct(exp.ident))
2785 exp.error("undefined identifier `%s`, did you mean %s `%s`?", exp.ident.toChars(), s2.kind(), s2.toChars());
2786 else if (const p = Scope.search_correct_C(exp.ident))
2787 exp.error("undefined identifier `%s`, did you mean `%s`?", exp.ident.toChars(), p);
2788 else if (exp.ident == Id.dollar)
2789 exp.error("undefined identifier `$`");
2790 else
2791 exp.error("undefined identifier `%s`", exp.ident.toChars());
2792
2793 result = ErrorExp.get();
2794 }
2795
visit(DsymbolExp e)2796 override void visit(DsymbolExp e)
2797 {
2798 result = symbolToExp(e.s, e.loc, sc, e.hasOverloads);
2799 }
2800
visit(ThisExp e)2801 override void visit(ThisExp e)
2802 {
2803 static if (LOGSEMANTIC)
2804 {
2805 printf("ThisExp::semantic()\n");
2806 }
2807 if (e.type)
2808 {
2809 result = e;
2810 return;
2811 }
2812
2813 FuncDeclaration fd = hasThis(sc); // fd is the uplevel function with the 'this' variable
2814 AggregateDeclaration ad;
2815
2816 /* Special case for typeof(this) and typeof(super) since both
2817 * should work even if they are not inside a non-static member function
2818 */
2819 if (!fd && sc.intypeof == 1)
2820 {
2821 // Find enclosing struct or class
2822 for (Dsymbol s = sc.getStructClassScope(); 1; s = s.parent)
2823 {
2824 if (!s)
2825 {
2826 e.error("`%s` is not in a class or struct scope", e.toChars());
2827 goto Lerr;
2828 }
2829 ClassDeclaration cd = s.isClassDeclaration();
2830 if (cd)
2831 {
2832 e.type = cd.type;
2833 result = e;
2834 return;
2835 }
2836 StructDeclaration sd = s.isStructDeclaration();
2837 if (sd)
2838 {
2839 e.type = sd.type;
2840 result = e;
2841 return;
2842 }
2843 }
2844 }
2845 if (!fd)
2846 goto Lerr;
2847
2848 assert(fd.vthis);
2849 e.var = fd.vthis;
2850 assert(e.var.parent);
2851 ad = fd.isMemberLocal();
2852 if (!ad)
2853 ad = fd.isMember2();
2854 assert(ad);
2855 e.type = ad.type.addMod(e.var.type.mod);
2856
2857 if (e.var.checkNestedReference(sc, e.loc))
2858 return setError();
2859
2860 result = e;
2861 return;
2862
2863 Lerr:
2864 e.error("`this` is only defined in non-static member functions, not `%s`", sc.parent.toChars());
2865 result = ErrorExp.get();
2866 }
2867
visit(SuperExp e)2868 override void visit(SuperExp e)
2869 {
2870 static if (LOGSEMANTIC)
2871 {
2872 printf("SuperExp::semantic('%s')\n", e.toChars());
2873 }
2874 if (e.type)
2875 {
2876 result = e;
2877 return;
2878 }
2879
2880 FuncDeclaration fd = hasThis(sc);
2881 ClassDeclaration cd;
2882 Dsymbol s;
2883
2884 /* Special case for typeof(this) and typeof(super) since both
2885 * should work even if they are not inside a non-static member function
2886 */
2887 if (!fd && sc.intypeof == 1)
2888 {
2889 // Find enclosing class
2890 for (s = sc.getStructClassScope(); 1; s = s.parent)
2891 {
2892 if (!s)
2893 {
2894 e.error("`%s` is not in a class scope", e.toChars());
2895 goto Lerr;
2896 }
2897 cd = s.isClassDeclaration();
2898 if (cd)
2899 {
2900 cd = cd.baseClass;
2901 if (!cd)
2902 {
2903 e.error("class `%s` has no `super`", s.toChars());
2904 goto Lerr;
2905 }
2906 e.type = cd.type;
2907 result = e;
2908 return;
2909 }
2910 }
2911 }
2912 if (!fd)
2913 goto Lerr;
2914
2915 e.var = fd.vthis;
2916 assert(e.var && e.var.parent);
2917
2918 s = fd.toParentDecl();
2919 if (s.isTemplateDeclaration()) // allow inside template constraint
2920 s = s.toParent();
2921 assert(s);
2922 cd = s.isClassDeclaration();
2923 //printf("parent is %s %s\n", fd.toParent().kind(), fd.toParent().toChars());
2924 if (!cd)
2925 goto Lerr;
2926 if (!cd.baseClass)
2927 {
2928 e.error("no base class for `%s`", cd.toChars());
2929 e.type = cd.type.addMod(e.var.type.mod);
2930 }
2931 else
2932 {
2933 e.type = cd.baseClass.type;
2934 e.type = e.type.castMod(e.var.type.mod);
2935 }
2936
2937 if (e.var.checkNestedReference(sc, e.loc))
2938 return setError();
2939
2940 result = e;
2941 return;
2942
2943 Lerr:
2944 e.error("`super` is only allowed in non-static class member functions");
2945 result = ErrorExp.get();
2946 }
2947
visit(NullExp e)2948 override void visit(NullExp e)
2949 {
2950 static if (LOGSEMANTIC)
2951 {
2952 printf("NullExp::semantic('%s')\n", e.toChars());
2953 }
2954 // NULL is the same as (void *)0
2955 if (e.type)
2956 {
2957 result = e;
2958 return;
2959 }
2960 e.type = Type.tnull;
2961 result = e;
2962 }
2963
visit(StringExp e)2964 override void visit(StringExp e)
2965 {
2966 static if (LOGSEMANTIC)
2967 {
2968 printf("StringExp::semantic() %s\n", e.toChars());
2969 }
2970 if (e.type)
2971 {
2972 result = e;
2973 return;
2974 }
2975
2976 OutBuffer buffer;
2977 size_t newlen = 0;
2978 size_t u;
2979 dchar c;
2980
2981 switch (e.postfix)
2982 {
2983 case 'd':
2984 for (u = 0; u < e.len;)
2985 {
2986 if (const p = utf_decodeChar(e.peekString(), u, c))
2987 {
2988 e.error("%.*s", cast(int)p.length, p.ptr);
2989 return setError();
2990 }
2991 else
2992 {
2993 buffer.write4(c);
2994 newlen++;
2995 }
2996 }
2997 buffer.write4(0);
2998 e.setData(buffer.extractData(), newlen, 4);
2999 if (sc && sc.flags & SCOPE.Cfile)
3000 e.type = Type.tuns32.pointerTo();
3001 else
3002 e.type = Type.tdchar.immutableOf().arrayOf();
3003 e.committed = 1;
3004 break;
3005
3006 case 'w':
3007 for (u = 0; u < e.len;)
3008 {
3009 if (const p = utf_decodeChar(e.peekString(), u, c))
3010 {
3011 e.error("%.*s", cast(int)p.length, p.ptr);
3012 return setError();
3013 }
3014 else
3015 {
3016 buffer.writeUTF16(c);
3017 newlen++;
3018 if (c >= 0x10000)
3019 newlen++;
3020 }
3021 }
3022 buffer.writeUTF16(0);
3023 e.setData(buffer.extractData(), newlen, 2);
3024 if (sc && sc.flags & SCOPE.Cfile)
3025 e.type = Type.tuns16.pointerTo();
3026 else
3027 e.type = Type.twchar.immutableOf().arrayOf();
3028 e.committed = 1;
3029 break;
3030
3031 case 'c':
3032 e.committed = 1;
3033 goto default;
3034
3035 default:
3036 if (sc && sc.flags & SCOPE.Cfile)
3037 e.type = Type.tchar.pointerTo();
3038 else
3039 e.type = Type.tchar.immutableOf().arrayOf();
3040 break;
3041 }
3042 e.type = e.type.typeSemantic(e.loc, sc);
3043 //type = type.immutableOf();
3044 //printf("type = %s\n", type.toChars());
3045
3046 result = e;
3047 }
3048
visit(TupleExp exp)3049 override void visit(TupleExp exp)
3050 {
3051 static if (LOGSEMANTIC)
3052 {
3053 printf("+TupleExp::semantic(%s)\n", exp.toChars());
3054 }
3055 if (exp.type)
3056 {
3057 result = exp;
3058 return;
3059 }
3060
3061 if (exp.e0)
3062 exp.e0 = exp.e0.expressionSemantic(sc);
3063
3064 // Run semantic() on each argument
3065 bool err = false;
3066 for (size_t i = 0; i < exp.exps.dim; i++)
3067 {
3068 Expression e = (*exp.exps)[i];
3069 e = e.expressionSemantic(sc);
3070 if (!e.type)
3071 {
3072 exp.error("`%s` has no value", e.toChars());
3073 err = true;
3074 }
3075 else if (e.op == EXP.error)
3076 err = true;
3077 else
3078 (*exp.exps)[i] = e;
3079 }
3080 if (err)
3081 return setError();
3082
3083 expandTuples(exp.exps);
3084
3085 exp.type = new TypeTuple(exp.exps);
3086 exp.type = exp.type.typeSemantic(exp.loc, sc);
3087 //printf("-TupleExp::semantic(%s)\n", toChars());
3088 result = exp;
3089 }
3090
visit(ArrayLiteralExp e)3091 override void visit(ArrayLiteralExp e)
3092 {
3093 static if (LOGSEMANTIC)
3094 {
3095 printf("ArrayLiteralExp::semantic('%s')\n", e.toChars());
3096 }
3097 if (e.type)
3098 {
3099 result = e;
3100 return;
3101 }
3102
3103 /* Perhaps an empty array literal [ ] should be rewritten as null?
3104 */
3105
3106 if (e.basis)
3107 e.basis = e.basis.expressionSemantic(sc);
3108 if (arrayExpressionSemantic(e.elements, sc) || (e.basis && e.basis.op == EXP.error))
3109 return setError();
3110
3111 expandTuples(e.elements);
3112
3113 if (e.basis)
3114 e.elements.push(e.basis);
3115 Type t0 = arrayExpressionToCommonType(sc, *e.elements);
3116 if (e.basis)
3117 e.basis = e.elements.pop();
3118 if (t0 is null)
3119 return setError();
3120
3121 e.type = t0.arrayOf();
3122 e.type = e.type.typeSemantic(e.loc, sc);
3123
3124 /* Disallow array literals of type void being used.
3125 */
3126 if (e.elements.dim > 0 && t0.ty == Tvoid)
3127 {
3128 e.error("`%s` of type `%s` has no value", e.toChars(), e.type.toChars());
3129 return setError();
3130 }
3131
3132 if (global.params.useTypeInfo && Type.dtypeinfo)
3133 semanticTypeInfo(sc, e.type);
3134
3135 result = e;
3136 }
3137
visit(AssocArrayLiteralExp e)3138 override void visit(AssocArrayLiteralExp e)
3139 {
3140 static if (LOGSEMANTIC)
3141 {
3142 printf("AssocArrayLiteralExp::semantic('%s')\n", e.toChars());
3143 }
3144 if (e.type)
3145 {
3146 result = e;
3147 return;
3148 }
3149
3150 // Run semantic() on each element
3151 bool err_keys = arrayExpressionSemantic(e.keys, sc);
3152 bool err_vals = arrayExpressionSemantic(e.values, sc);
3153 if (err_keys || err_vals)
3154 return setError();
3155
3156 expandTuples(e.keys);
3157 expandTuples(e.values);
3158 if (e.keys.dim != e.values.dim)
3159 {
3160 e.error("number of keys is %llu, must match number of values %llu",
3161 cast(ulong) e.keys.dim, cast(ulong) e.values.dim);
3162 return setError();
3163 }
3164
3165 Type tkey = arrayExpressionToCommonType(sc, *e.keys);
3166 Type tvalue = arrayExpressionToCommonType(sc, *e.values);
3167 if (tkey is null || tvalue is null)
3168 return setError();
3169
3170 e.type = new TypeAArray(tvalue, tkey);
3171 e.type = e.type.typeSemantic(e.loc, sc);
3172
3173 semanticTypeInfo(sc, e.type);
3174
3175 if (global.params.useDIP1000 == FeatureState.enabled)
3176 {
3177 if (checkAssocArrayLiteralEscape(sc, e, false))
3178 return setError();
3179 }
3180
3181 result = e;
3182 }
3183
visit(StructLiteralExp e)3184 override void visit(StructLiteralExp e)
3185 {
3186 static if (LOGSEMANTIC)
3187 {
3188 printf("StructLiteralExp::semantic('%s')\n", e.toChars());
3189 }
3190 if (e.type)
3191 {
3192 result = e;
3193 return;
3194 }
3195
3196 e.sd.size(e.loc);
3197 if (e.sd.sizeok != Sizeok.done)
3198 return setError();
3199
3200 // run semantic() on each element
3201 if (arrayExpressionSemantic(e.elements, sc))
3202 return setError();
3203
3204 expandTuples(e.elements);
3205
3206 /* Fit elements[] to the corresponding type of field[].
3207 */
3208 if (!e.sd.fit(e.loc, sc, e.elements, e.stype))
3209 return setError();
3210
3211 /* Fill out remainder of elements[] with default initializers for fields[]
3212 */
3213 if (!e.sd.fill(e.loc, e.elements, false))
3214 {
3215 /* An error in the initializer needs to be recorded as an error
3216 * in the enclosing function or template, since the initializer
3217 * will be part of the stuct declaration.
3218 */
3219 global.increaseErrorCount();
3220 return setError();
3221 }
3222
3223 if (checkFrameAccess(e.loc, sc, e.sd, e.elements.dim))
3224 return setError();
3225
3226 e.type = e.stype ? e.stype : e.sd.type;
3227 result = e;
3228 }
3229
visit(CompoundLiteralExp cle)3230 override void visit(CompoundLiteralExp cle)
3231 {
3232 static if (LOGSEMANTIC)
3233 {
3234 printf("CompoundLiteralExp::semantic('%s')\n", cle.toChars());
3235 }
3236 Type t = cle.type.typeSemantic(cle.loc, sc);
3237 auto init = initializerSemantic(cle.initializer, sc, t, INITnointerpret);
3238 auto e = initializerToExpression(init, t, (sc.flags & SCOPE.Cfile) != 0);
3239 if (!e)
3240 {
3241 error(cle.loc, "cannot convert initializer `%s` to expression", init.toChars());
3242 return setError();
3243 }
3244 result = e;
3245 return;
3246 }
3247
visit(TypeExp exp)3248 override void visit(TypeExp exp)
3249 {
3250 if (exp.type.ty == Terror)
3251 return setError();
3252
3253 //printf("TypeExp::semantic(%s)\n", exp.type.toChars());
3254 Expression e;
3255 Type t;
3256 Dsymbol s;
3257
3258 dmd.typesem.resolve(exp.type, exp.loc, sc, e, t, s, true);
3259 if (e)
3260 {
3261 // `(Type)` is actually `(var)` so if `(var)` is a member requiring `this`
3262 // then rewrite as `(this.var)` in case it would be followed by a DotVar
3263 // to fix https://issues.dlang.org/show_bug.cgi?id=9490
3264 VarExp ve = e.isVarExp();
3265 if (ve && ve.var && exp.parens && !ve.var.isStatic() && !(sc.stc & STC.static_) &&
3266 sc.func && sc.func.needThis && ve.var.toParent2().isAggregateDeclaration())
3267 {
3268 // printf("apply fix for issue 9490: add `this.` to `%s`...\n", e.toChars());
3269 e = new DotVarExp(exp.loc, new ThisExp(exp.loc), ve.var, false);
3270 }
3271 //printf("e = %s %s\n", Token.toChars(e.op), e.toChars());
3272 e = e.expressionSemantic(sc);
3273 }
3274 else if (t)
3275 {
3276 //printf("t = %d %s\n", t.ty, t.toChars());
3277 exp.type = t.typeSemantic(exp.loc, sc);
3278 e = exp;
3279 }
3280 else if (s)
3281 {
3282 //printf("s = %s %s\n", s.kind(), s.toChars());
3283 e = symbolToExp(s, exp.loc, sc, true);
3284 }
3285 else
3286 assert(0);
3287
3288 exp.type.checkComplexTransition(exp.loc, sc);
3289
3290 result = e;
3291 }
3292
visit(ScopeExp exp)3293 override void visit(ScopeExp exp)
3294 {
3295 static if (LOGSEMANTIC)
3296 {
3297 printf("+ScopeExp::semantic(%p '%s')\n", exp, exp.toChars());
3298 }
3299 if (exp.type)
3300 {
3301 result = exp;
3302 return;
3303 }
3304
3305 ScopeDsymbol sds2 = exp.sds;
3306 TemplateInstance ti = sds2.isTemplateInstance();
3307 while (ti)
3308 {
3309 WithScopeSymbol withsym;
3310 if (!ti.findTempDecl(sc, &withsym) || !ti.semanticTiargs(sc))
3311 return setError();
3312 if (withsym && withsym.withstate.wthis)
3313 {
3314 Expression e = new VarExp(exp.loc, withsym.withstate.wthis);
3315 e = new DotTemplateInstanceExp(exp.loc, e, ti);
3316 result = e.expressionSemantic(sc);
3317 return;
3318 }
3319 if (ti.needsTypeInference(sc))
3320 {
3321 if (TemplateDeclaration td = ti.tempdecl.isTemplateDeclaration())
3322 {
3323 Dsymbol p = td.toParentLocal();
3324 FuncDeclaration fdthis = hasThis(sc);
3325 AggregateDeclaration ad = p ? p.isAggregateDeclaration() : null;
3326 if (fdthis && ad && fdthis.isMemberLocal() == ad && (td._scope.stc & STC.static_) == 0)
3327 {
3328 Expression e = new DotTemplateInstanceExp(exp.loc, new ThisExp(exp.loc), ti);
3329 result = e.expressionSemantic(sc);
3330 return;
3331 }
3332 }
3333 else if (OverloadSet os = ti.tempdecl.isOverloadSet())
3334 {
3335 FuncDeclaration fdthis = hasThis(sc);
3336 AggregateDeclaration ad = os.parent.isAggregateDeclaration();
3337 if (fdthis && ad && fdthis.isMemberLocal() == ad)
3338 {
3339 Expression e = new DotTemplateInstanceExp(exp.loc, new ThisExp(exp.loc), ti);
3340 result = e.expressionSemantic(sc);
3341 return;
3342 }
3343 }
3344 // ti is an instance which requires IFTI.
3345 exp.sds = ti;
3346 exp.type = Type.tvoid;
3347 result = exp;
3348 return;
3349 }
3350 ti.dsymbolSemantic(sc);
3351 if (!ti.inst || ti.errors)
3352 return setError();
3353
3354 Dsymbol s = ti.toAlias();
3355 if (s == ti)
3356 {
3357 exp.sds = ti;
3358 exp.type = Type.tvoid;
3359 result = exp;
3360 return;
3361 }
3362 sds2 = s.isScopeDsymbol();
3363 if (sds2)
3364 {
3365 ti = sds2.isTemplateInstance();
3366 //printf("+ sds2 = %s, '%s'\n", sds2.kind(), sds2.toChars());
3367 continue;
3368 }
3369
3370 if (auto v = s.isVarDeclaration())
3371 {
3372 if (!v.type)
3373 {
3374 exp.error("forward reference of %s `%s`", v.kind(), v.toChars());
3375 return setError();
3376 }
3377 if ((v.storage_class & STC.manifest) && v._init)
3378 {
3379 /* When an instance that will be converted to a constant exists,
3380 * the instance representation "foo!tiargs" is treated like a
3381 * variable name, and its recursive appearance check (note that
3382 * it's equivalent with a recursive instantiation of foo) is done
3383 * separately from the circular initialization check for the
3384 * eponymous enum variable declaration.
3385 *
3386 * template foo(T) {
3387 * enum bool foo = foo; // recursive definition check (v.inuse)
3388 * }
3389 * template bar(T) {
3390 * enum bool bar = bar!T; // recursive instantiation check (ti.inuse)
3391 * }
3392 */
3393 if (ti.inuse)
3394 {
3395 exp.error("recursive expansion of %s `%s`", ti.kind(), ti.toPrettyChars());
3396 return setError();
3397 }
3398 v.checkDeprecated(exp.loc, sc);
3399 auto e = v.expandInitializer(exp.loc);
3400 ti.inuse++;
3401 e = e.expressionSemantic(sc);
3402 ti.inuse--;
3403 result = e;
3404 return;
3405 }
3406 }
3407
3408 //printf("s = %s, '%s'\n", s.kind(), s.toChars());
3409 auto e = symbolToExp(s, exp.loc, sc, true);
3410 //printf("-1ScopeExp::semantic()\n");
3411 result = e;
3412 return;
3413 }
3414
3415 //printf("sds2 = %s, '%s'\n", sds2.kind(), sds2.toChars());
3416 //printf("\tparent = '%s'\n", sds2.parent.toChars());
3417 sds2.dsymbolSemantic(sc);
3418
3419 // (Aggregate|Enum)Declaration
3420 if (auto t = sds2.getType())
3421 {
3422 result = (new TypeExp(exp.loc, t)).expressionSemantic(sc);
3423 return;
3424 }
3425
3426 if (auto td = sds2.isTemplateDeclaration())
3427 {
3428 result = (new TemplateExp(exp.loc, td)).expressionSemantic(sc);
3429 return;
3430 }
3431
3432 exp.sds = sds2;
3433 exp.type = Type.tvoid;
3434 //printf("-2ScopeExp::semantic() %s\n", toChars());
3435 result = exp;
3436 }
3437
visit(NewExp exp)3438 override void visit(NewExp exp)
3439 {
3440 static if (LOGSEMANTIC)
3441 {
3442 printf("NewExp::semantic() %s\n", exp.toChars());
3443 if (exp.thisexp)
3444 printf("\tthisexp = %s\n", exp.thisexp.toChars());
3445 printf("\tnewtype: %s\n", exp.newtype.toChars());
3446 }
3447 if (exp.type) // if semantic() already run
3448 {
3449 result = exp;
3450 return;
3451 }
3452
3453 //for error messages if the argument in [] is not convertible to size_t
3454 const originalNewtype = exp.newtype;
3455
3456 // https://issues.dlang.org/show_bug.cgi?id=11581
3457 // With the syntax `new T[edim]` or `thisexp.new T[edim]`,
3458 // T should be analyzed first and edim should go into arguments iff it's
3459 // not a tuple.
3460 Expression edim = null;
3461 if (!exp.arguments && exp.newtype.isTypeSArray())
3462 {
3463 auto ts = exp.newtype.isTypeSArray();
3464 edim = ts.dim;
3465 exp.newtype = ts.next;
3466 }
3467
3468 ClassDeclaration cdthis = null;
3469 if (exp.thisexp)
3470 {
3471 exp.thisexp = exp.thisexp.expressionSemantic(sc);
3472 if (exp.thisexp.op == EXP.error)
3473 return setError();
3474
3475 cdthis = exp.thisexp.type.isClassHandle();
3476 if (!cdthis)
3477 {
3478 exp.error("`this` for nested class must be a class type, not `%s`", exp.thisexp.type.toChars());
3479 return setError();
3480 }
3481
3482 sc = sc.push(cdthis);
3483 exp.type = exp.newtype.typeSemantic(exp.loc, sc);
3484 sc = sc.pop();
3485 }
3486 else
3487 {
3488 exp.type = exp.newtype.typeSemantic(exp.loc, sc);
3489 }
3490 if (exp.type.ty == Terror)
3491 return setError();
3492
3493 if (edim)
3494 {
3495 if (exp.type.toBasetype().ty == Ttuple)
3496 {
3497 // --> new T[edim]
3498 exp.type = new TypeSArray(exp.type, edim);
3499 exp.type = exp.type.typeSemantic(exp.loc, sc);
3500 if (exp.type.ty == Terror)
3501 return setError();
3502 }
3503 else
3504 {
3505 // --> new T[](edim)
3506 exp.arguments = new Expressions();
3507 exp.arguments.push(edim);
3508 exp.type = exp.type.arrayOf();
3509 }
3510 }
3511
3512 exp.newtype = exp.type; // in case type gets cast to something else
3513 Type tb = exp.type.toBasetype();
3514 //printf("tb: %s, deco = %s\n", tb.toChars(), tb.deco);
3515 if (arrayExpressionSemantic(exp.arguments, sc))
3516 {
3517 return setError();
3518 }
3519 //https://issues.dlang.org/show_bug.cgi?id=20547
3520 //exp.arguments are the "parameters" to [], not to a real function
3521 //so the errors that come from preFunctionParameters are misleading
3522 if (originalNewtype.ty == Tsarray)
3523 {
3524 if (preFunctionParameters(sc, exp.arguments, false))
3525 {
3526 exp.error("cannot create a `%s` with `new`", originalNewtype.toChars());
3527 return setError();
3528 }
3529 }
3530 else if (preFunctionParameters(sc, exp.arguments))
3531 {
3532 return setError();
3533 }
3534
3535 if (exp.thisexp && tb.ty != Tclass)
3536 {
3537 exp.error("`.new` is only for allocating nested classes, not `%s`", tb.toChars());
3538 return setError();
3539 }
3540
3541 const size_t nargs = exp.arguments ? exp.arguments.dim : 0;
3542 Expression newprefix = null;
3543
3544 if (auto tc = tb.isTypeClass())
3545 {
3546 auto cd = tc.sym;
3547 cd.size(exp.loc);
3548 if (cd.sizeok != Sizeok.done)
3549 return setError();
3550 if (!cd.ctor)
3551 cd.ctor = cd.searchCtor();
3552 if (cd.noDefaultCtor && !nargs && !cd.defaultCtor)
3553 {
3554 exp.error("default construction is disabled for type `%s`", cd.type.toChars());
3555 return setError();
3556 }
3557
3558 if (cd.isInterfaceDeclaration())
3559 {
3560 exp.error("cannot create instance of interface `%s`", cd.toChars());
3561 return setError();
3562 }
3563
3564 if (cd.isAbstract())
3565 {
3566 exp.error("cannot create instance of abstract class `%s`", cd.toChars());
3567 for (size_t i = 0; i < cd.vtbl.dim; i++)
3568 {
3569 FuncDeclaration fd = cd.vtbl[i].isFuncDeclaration();
3570 if (fd && fd.isAbstract())
3571 {
3572 errorSupplemental(exp.loc, "function `%s` is not implemented",
3573 fd.toFullSignature());
3574 }
3575 }
3576 return setError();
3577 }
3578 // checkDeprecated() is already done in newtype.typeSemantic().
3579
3580 if (cd.isNested())
3581 {
3582 /* We need a 'this' pointer for the nested class.
3583 * Ensure we have the right one.
3584 */
3585 Dsymbol s = cd.toParentLocal();
3586
3587 //printf("cd isNested, parent = %s '%s'\n", s.kind(), s.toPrettyChars());
3588 if (auto cdn = s.isClassDeclaration())
3589 {
3590 if (!cdthis)
3591 {
3592 if (!sc.hasThis)
3593 {
3594 string msg = "cannot construct " ~
3595 (cd.isAnonymous ? "anonymous nested class" : "nested class `%s`") ~
3596 " because no implicit `this` reference to outer class" ~
3597 (cdn.isAnonymous ? "" : " `%s`") ~ " is available\0";
3598
3599 exp.error(msg.ptr, cd.toChars, cdn.toChars);
3600 return setError();
3601 }
3602
3603 // Supply an implicit 'this' and try again
3604 exp.thisexp = new ThisExp(exp.loc);
3605 for (Dsymbol sp = sc.parent; 1; sp = sp.toParentLocal())
3606 {
3607 ClassDeclaration cdp = sp.isClassDeclaration();
3608 if (!cdp)
3609 continue;
3610 if (cdp == cdn || cdn.isBaseOf(cdp, null))
3611 break;
3612 // Add a '.outer' and try again
3613 exp.thisexp = new DotIdExp(exp.loc, exp.thisexp, Id.outer);
3614 }
3615
3616 exp.thisexp = exp.thisexp.expressionSemantic(sc);
3617 if (exp.thisexp.op == EXP.error)
3618 return setError();
3619 cdthis = exp.thisexp.type.isClassHandle();
3620 }
3621 if (cdthis != cdn && !cdn.isBaseOf(cdthis, null))
3622 {
3623 //printf("cdthis = %s\n", cdthis.toChars());
3624 exp.error("`this` for nested class must be of type `%s`, not `%s`",
3625 cdn.toChars(), exp.thisexp.type.toChars());
3626 return setError();
3627 }
3628 if (!MODimplicitConv(exp.thisexp.type.mod, exp.newtype.mod))
3629 {
3630 exp.error("nested type `%s` should have the same or weaker constancy as enclosing type `%s`",
3631 exp.newtype.toChars(), exp.thisexp.type.toChars());
3632 return setError();
3633 }
3634 }
3635 else if (exp.thisexp)
3636 {
3637 exp.error("`.new` is only for allocating nested classes");
3638 return setError();
3639 }
3640 else if (auto fdn = s.isFuncDeclaration())
3641 {
3642 // make sure the parent context fdn of cd is reachable from sc
3643 if (!ensureStaticLinkTo(sc.parent, fdn))
3644 {
3645 exp.error("outer function context of `%s` is needed to `new` nested class `%s`",
3646 fdn.toPrettyChars(), cd.toPrettyChars());
3647 return setError();
3648 }
3649 }
3650 else
3651 assert(0);
3652 }
3653 else if (exp.thisexp)
3654 {
3655 exp.error("`.new` is only for allocating nested classes");
3656 return setError();
3657 }
3658
3659 if (cd.vthis2)
3660 {
3661 if (AggregateDeclaration ad2 = cd.isMember2())
3662 {
3663 Expression te = new ThisExp(exp.loc).expressionSemantic(sc);
3664 if (te.op != EXP.error)
3665 te = getRightThis(exp.loc, sc, ad2, te, cd);
3666 if (te.op == EXP.error)
3667 {
3668 exp.error("need `this` of type `%s` needed to `new` nested class `%s`", ad2.toChars(), cd.toChars());
3669 return setError();
3670 }
3671 }
3672 }
3673
3674 if (cd.disableNew)
3675 {
3676 exp.error("cannot allocate `class %s` with `new` because it is annotated with `@disable new()`",
3677 originalNewtype.toChars());
3678 return setError();
3679 }
3680
3681 if (cd.ctor)
3682 {
3683 FuncDeclaration f = resolveFuncCall(exp.loc, sc, cd.ctor, null, tb, exp.arguments, FuncResolveFlag.standard);
3684 if (!f || f.errors)
3685 return setError();
3686
3687 checkFunctionAttributes(exp, sc, f);
3688 checkAccess(cd, exp.loc, sc, f);
3689
3690 TypeFunction tf = f.type.isTypeFunction();
3691 if (!exp.arguments)
3692 exp.arguments = new Expressions();
3693 if (functionParameters(exp.loc, sc, tf, null, exp.type, exp.arguments, f, &exp.type, &exp.argprefix))
3694 return setError();
3695
3696 exp.member = f.isCtorDeclaration();
3697 assert(exp.member);
3698 }
3699 else
3700 {
3701 if (nargs)
3702 {
3703 exp.error("no constructor for `%s`", cd.toChars());
3704 return setError();
3705 }
3706
3707 // https://issues.dlang.org/show_bug.cgi?id=19941
3708 // Run semantic on all field initializers to resolve any forward
3709 // references. This is the same as done for structs in sd.fill().
3710 for (ClassDeclaration c = cd; c; c = c.baseClass)
3711 {
3712 foreach (v; c.fields)
3713 {
3714 if (v.inuse || v._scope is null || v._init is null ||
3715 v._init.isVoidInitializer())
3716 continue;
3717 v.inuse++;
3718 v._init = v._init.initializerSemantic(v._scope, v.type, INITinterpret);
3719 v.inuse--;
3720 }
3721 }
3722 }
3723 }
3724 else if (auto ts = tb.isTypeStruct())
3725 {
3726 auto sd = ts.sym;
3727 sd.size(exp.loc);
3728 if (sd.sizeok != Sizeok.done)
3729 return setError();
3730 if (!sd.ctor)
3731 sd.ctor = sd.searchCtor();
3732 if (sd.noDefaultCtor && !nargs)
3733 {
3734 exp.error("default construction is disabled for type `%s`", sd.type.toChars());
3735 return setError();
3736 }
3737 // checkDeprecated() is already done in newtype.typeSemantic().
3738
3739 if (sd.disableNew)
3740 {
3741 exp.error("cannot allocate `struct %s` with `new` because it is annotated with `@disable new()`",
3742 originalNewtype.toChars());
3743 return setError();
3744 }
3745
3746 // https://issues.dlang.org/show_bug.cgi?id=22639
3747 // If the new expression has arguments, we either should call a
3748 // regular constructor of a copy constructor if the first argument
3749 // is the same type as the struct
3750 if (nargs && (sd.hasRegularCtor() || (sd.ctor && (*exp.arguments)[0].type.mutableOf() == sd.type.mutableOf())))
3751 {
3752 FuncDeclaration f = resolveFuncCall(exp.loc, sc, sd.ctor, null, tb, exp.arguments, FuncResolveFlag.standard);
3753 if (!f || f.errors)
3754 return setError();
3755
3756 checkFunctionAttributes(exp, sc, f);
3757 checkAccess(sd, exp.loc, sc, f);
3758
3759 TypeFunction tf = f.type.isTypeFunction();
3760 if (!exp.arguments)
3761 exp.arguments = new Expressions();
3762 if (functionParameters(exp.loc, sc, tf, null, exp.type, exp.arguments, f, &exp.type, &exp.argprefix))
3763 return setError();
3764
3765 exp.member = f.isCtorDeclaration();
3766 assert(exp.member);
3767
3768 if (checkFrameAccess(exp.loc, sc, sd, sd.fields.dim))
3769 return setError();
3770 }
3771 else
3772 {
3773 if (!exp.arguments)
3774 exp.arguments = new Expressions();
3775
3776 if (!sd.fit(exp.loc, sc, exp.arguments, tb))
3777 return setError();
3778
3779 if (!sd.fill(exp.loc, exp.arguments, false))
3780 return setError();
3781
3782 if (checkFrameAccess(exp.loc, sc, sd, exp.arguments ? exp.arguments.dim : 0))
3783 return setError();
3784
3785 /* Since a `new` allocation may escape, check each of the arguments for escaping
3786 */
3787 if (global.params.useDIP1000 == FeatureState.enabled)
3788 {
3789 foreach (arg; *exp.arguments)
3790 {
3791 if (arg && checkNewEscape(sc, arg, false))
3792 return setError();
3793 }
3794 }
3795 }
3796
3797 exp.type = exp.type.pointerTo();
3798 }
3799 else if (tb.ty == Tarray)
3800 {
3801 if (!nargs)
3802 {
3803 // https://issues.dlang.org/show_bug.cgi?id=20422
3804 // Without this check the compiler would give a misleading error
3805 exp.error("missing length argument for array");
3806 return setError();
3807 }
3808
3809 Type tn = tb.nextOf().baseElemOf();
3810 Dsymbol s = tn.toDsymbol(sc);
3811 AggregateDeclaration ad = s ? s.isAggregateDeclaration() : null;
3812 if (ad && ad.noDefaultCtor)
3813 {
3814 exp.error("default construction is disabled for type `%s`", tb.nextOf().toChars());
3815 return setError();
3816 }
3817 for (size_t i = 0; i < nargs; i++)
3818 {
3819 if (tb.ty != Tarray)
3820 {
3821 exp.error("too many arguments for array");
3822 return setError();
3823 }
3824
3825 Expression arg = (*exp.arguments)[i];
3826 arg = resolveProperties(sc, arg);
3827 arg = arg.implicitCastTo(sc, Type.tsize_t);
3828 if (arg.op == EXP.error)
3829 return setError();
3830 arg = arg.optimize(WANTvalue);
3831 if (arg.op == EXP.int64 && cast(sinteger_t)arg.toInteger() < 0)
3832 {
3833 exp.error("negative array index `%s`", arg.toChars());
3834 return setError();
3835 }
3836 (*exp.arguments)[i] = arg;
3837 tb = tb.isTypeDArray().next.toBasetype();
3838 }
3839 }
3840 else if (tb.isscalar())
3841 {
3842 if (!nargs)
3843 {
3844 }
3845 else if (nargs == 1)
3846 {
3847 Expression e = (*exp.arguments)[0];
3848 e = e.implicitCastTo(sc, tb);
3849 (*exp.arguments)[0] = e;
3850 }
3851 else
3852 {
3853 exp.error("more than one argument for construction of `%s`", exp.type.toChars());
3854 return setError();
3855 }
3856
3857 exp.type = exp.type.pointerTo();
3858 }
3859 else
3860 {
3861 exp.error("cannot create a `%s` with `new`", exp.type.toChars());
3862 return setError();
3863 }
3864
3865 //printf("NewExp: '%s'\n", toChars());
3866 //printf("NewExp:type '%s'\n", type.toChars());
3867 semanticTypeInfo(sc, exp.type);
3868
3869 if (newprefix)
3870 {
3871 result = Expression.combine(newprefix, exp);
3872 return;
3873 }
3874 result = exp;
3875 }
3876
visit(NewAnonClassExp e)3877 override void visit(NewAnonClassExp e)
3878 {
3879 static if (LOGSEMANTIC)
3880 {
3881 printf("NewAnonClassExp::semantic() %s\n", e.toChars());
3882 //printf("thisexp = %p\n", thisexp);
3883 //printf("type: %s\n", type.toChars());
3884 }
3885
3886 Expression d = new DeclarationExp(e.loc, e.cd);
3887 sc = sc.push(); // just create new scope
3888 sc.flags &= ~SCOPE.ctfe; // temporary stop CTFE
3889 d = d.expressionSemantic(sc);
3890 sc = sc.pop();
3891
3892 if (!e.cd.errors && sc.intypeof && !sc.parent.inNonRoot())
3893 {
3894 ScopeDsymbol sds = sc.tinst ? cast(ScopeDsymbol)sc.tinst : sc._module;
3895 if (!sds.members)
3896 sds.members = new Dsymbols();
3897 sds.members.push(e.cd);
3898 }
3899
3900 Expression n = new NewExp(e.loc, e.thisexp, e.cd.type, e.arguments);
3901
3902 Expression c = new CommaExp(e.loc, d, n);
3903 result = c.expressionSemantic(sc);
3904 }
3905
visit(SymOffExp e)3906 override void visit(SymOffExp e)
3907 {
3908 static if (LOGSEMANTIC)
3909 {
3910 printf("SymOffExp::semantic('%s')\n", e.toChars());
3911 }
3912 //var.dsymbolSemantic(sc);
3913 if (!e.type)
3914 e.type = e.var.type.pointerTo();
3915
3916 if (auto v = e.var.isVarDeclaration())
3917 {
3918 if (v.checkNestedReference(sc, e.loc))
3919 return setError();
3920 }
3921 else if (auto f = e.var.isFuncDeclaration())
3922 {
3923 if (f.checkNestedReference(sc, e.loc))
3924 return setError();
3925 }
3926
3927 result = e;
3928 }
3929
visit(VarExp e)3930 override void visit(VarExp e)
3931 {
3932 static if (LOGSEMANTIC)
3933 {
3934 printf("VarExp::semantic(%s)\n", e.toChars());
3935 }
3936
3937 auto vd = e.var.isVarDeclaration();
3938 auto fd = e.var.isFuncDeclaration();
3939
3940 if (fd)
3941 {
3942 //printf("L%d fd = %s\n", __LINE__, f.toChars());
3943 if (!fd.functionSemantic())
3944 return setError();
3945 }
3946
3947 if (!e.type)
3948 e.type = e.var.type;
3949 if (e.type && !e.type.deco)
3950 {
3951 auto decl = e.var.isDeclaration();
3952 if (decl)
3953 decl.inuse++;
3954 e.type = e.type.typeSemantic(e.loc, sc);
3955 if (decl)
3956 decl.inuse--;
3957 }
3958
3959 /* Fix for 1161 doesn't work because it causes visibility
3960 * problems when instantiating imported templates passing private
3961 * variables as alias template parameters.
3962 */
3963 //checkAccess(loc, sc, NULL, var);
3964
3965 if (vd)
3966 {
3967 if (vd.checkNestedReference(sc, e.loc))
3968 return setError();
3969
3970 // https://issues.dlang.org/show_bug.cgi?id=12025
3971 // If the variable is not actually used in runtime code,
3972 // the purity violation error is redundant.
3973 //checkPurity(sc, vd);
3974 }
3975 else if (fd)
3976 {
3977 // TODO: If fd isn't yet resolved its overload, the checkNestedReference
3978 // call would cause incorrect validation.
3979 // Maybe here should be moved in CallExp, or AddrExp for functions.
3980 if (fd.checkNestedReference(sc, e.loc))
3981 return setError();
3982 }
3983 else if (auto od = e.var.isOverDeclaration())
3984 {
3985 e.type = Type.tvoid; // ambiguous type?
3986 }
3987
3988 result = e;
3989 }
3990
visit(FuncExp exp)3991 override void visit(FuncExp exp)
3992 {
3993 static if (LOGSEMANTIC)
3994 {
3995 printf("FuncExp::semantic(%s)\n", exp.toChars());
3996 if (exp.fd.treq)
3997 printf(" treq = %s\n", exp.fd.treq.toChars());
3998 }
3999
4000 if (exp.type)
4001 {
4002 result = exp;
4003 return;
4004 }
4005
4006 Expression e = exp;
4007 uint olderrors;
4008
4009 sc = sc.push(); // just create new scope
4010 sc.flags &= ~SCOPE.ctfe; // temporary stop CTFE
4011 sc.visibility = Visibility(Visibility.Kind.public_); // https://issues.dlang.org/show_bug.cgi?id=12506
4012
4013 /* fd.treq might be incomplete type,
4014 * so should not semantic it.
4015 * void foo(T)(T delegate(int) dg){}
4016 * foo(a=>a); // in IFTI, treq == T delegate(int)
4017 */
4018 //if (fd.treq)
4019 // fd.treq = fd.treq.dsymbolSemantic(loc, sc);
4020
4021 exp.genIdent(sc);
4022
4023 // Set target of return type inference
4024 if (exp.fd.treq && !exp.fd.type.nextOf())
4025 {
4026 TypeFunction tfv = null;
4027 if (exp.fd.treq.ty == Tdelegate || exp.fd.treq.isPtrToFunction())
4028 tfv = cast(TypeFunction)exp.fd.treq.nextOf();
4029 if (tfv)
4030 {
4031 TypeFunction tfl = cast(TypeFunction)exp.fd.type;
4032 tfl.next = tfv.nextOf();
4033 }
4034 }
4035
4036 //printf("td = %p, treq = %p\n", td, fd.treq);
4037 if (exp.td)
4038 {
4039 assert(exp.td.parameters && exp.td.parameters.dim);
4040 exp.td.dsymbolSemantic(sc);
4041 exp.type = Type.tvoid; // temporary type
4042
4043 if (exp.fd.treq) // defer type determination
4044 {
4045 FuncExp fe;
4046 if (exp.matchType(exp.fd.treq, sc, &fe) > MATCH.nomatch)
4047 e = fe;
4048 else
4049 e = ErrorExp.get();
4050 }
4051 goto Ldone;
4052 }
4053
4054 olderrors = global.errors;
4055 exp.fd.dsymbolSemantic(sc);
4056 if (olderrors == global.errors)
4057 {
4058 exp.fd.semantic2(sc);
4059 if (olderrors == global.errors)
4060 exp.fd.semantic3(sc);
4061 }
4062 if (olderrors != global.errors)
4063 {
4064 if (exp.fd.type && exp.fd.type.ty == Tfunction && !exp.fd.type.nextOf())
4065 (cast(TypeFunction)exp.fd.type).next = Type.terror;
4066 e = ErrorExp.get();
4067 goto Ldone;
4068 }
4069
4070 // Type is a "delegate to" or "pointer to" the function literal
4071 if ((exp.fd.isNested() && exp.fd.tok == TOK.delegate_) || (exp.tok == TOK.reserved && exp.fd.treq && exp.fd.treq.ty == Tdelegate))
4072 {
4073 // https://issues.dlang.org/show_bug.cgi?id=22686
4074 // if the delegate return type is an error
4075 // abort semantic of the FuncExp and propagate
4076 // the error
4077 if (exp.fd.type.isTypeError())
4078 {
4079 e = ErrorExp.get();
4080 goto Ldone;
4081 }
4082 exp.type = new TypeDelegate(exp.fd.type.isTypeFunction());
4083 exp.type = exp.type.typeSemantic(exp.loc, sc);
4084
4085 exp.fd.tok = TOK.delegate_;
4086 }
4087 else
4088 {
4089 exp.type = new TypePointer(exp.fd.type);
4090 exp.type = exp.type.typeSemantic(exp.loc, sc);
4091 //type = fd.type.pointerTo();
4092
4093 /* A lambda expression deduced to function pointer might become
4094 * to a delegate literal implicitly.
4095 *
4096 * auto foo(void function() fp) { return 1; }
4097 * assert(foo({}) == 1);
4098 *
4099 * So, should keep fd.tok == TOK.reserve if fd.treq == NULL.
4100 */
4101 if (exp.fd.treq && exp.fd.treq.ty == Tpointer)
4102 {
4103 // change to non-nested
4104 exp.fd.tok = TOK.function_;
4105 exp.fd.vthis = null;
4106 }
4107 }
4108 exp.fd.tookAddressOf++;
4109
4110 Ldone:
4111 sc = sc.pop();
4112 result = e;
4113 }
4114
4115 /**
4116 * Perform semantic analysis on function literals
4117 *
4118 * Test the following construct:
4119 * ---
4120 * (x, y, z) { return x + y + z; }(42, 84, 1992);
4121 * ---
4122 */
callExpSemantic(FuncExp exp,Scope * sc,Expressions * arguments)4123 Expression callExpSemantic(FuncExp exp, Scope* sc, Expressions* arguments)
4124 {
4125 if ((!exp.type || exp.type == Type.tvoid) && exp.td && arguments && arguments.dim)
4126 {
4127 for (size_t k = 0; k < arguments.dim; k++)
4128 {
4129 Expression checkarg = (*arguments)[k];
4130 if (checkarg.op == EXP.error)
4131 return checkarg;
4132 }
4133
4134 exp.genIdent(sc);
4135
4136 assert(exp.td.parameters && exp.td.parameters.dim);
4137 exp.td.dsymbolSemantic(sc);
4138
4139 TypeFunction tfl = cast(TypeFunction)exp.fd.type;
4140 size_t dim = tfl.parameterList.length;
4141 if (arguments.dim < dim)
4142 {
4143 // Default arguments are always typed, so they don't need inference.
4144 Parameter p = tfl.parameterList[arguments.dim];
4145 if (p.defaultArg)
4146 dim = arguments.dim;
4147 }
4148
4149 if ((tfl.parameterList.varargs == VarArg.none && arguments.dim > dim) ||
4150 arguments.dim < dim)
4151 {
4152 OutBuffer buf;
4153 foreach (idx, ref arg; *arguments)
4154 buf.printf("%s%s", (idx ? ", ".ptr : "".ptr), arg.type.toChars());
4155 exp.error("function literal `%s%s` is not callable using argument types `(%s)`",
4156 exp.fd.toChars(), parametersTypeToChars(tfl.parameterList),
4157 buf.peekChars());
4158 exp.errorSupplemental("too %s arguments, expected `%d`, got `%d`",
4159 arguments.dim < dim ? "few".ptr : "many".ptr,
4160 cast(int)dim, cast(int)arguments.dim);
4161 return ErrorExp.get();
4162 }
4163
4164 auto tiargs = new Objects();
4165 tiargs.reserve(exp.td.parameters.dim);
4166
4167 for (size_t i = 0; i < exp.td.parameters.dim; i++)
4168 {
4169 TemplateParameter tp = (*exp.td.parameters)[i];
4170 assert(dim <= tfl.parameterList.length);
4171 foreach (u, p; tfl.parameterList)
4172 {
4173 if (u == dim)
4174 break;
4175
4176 if (p.type.ty == Tident && (cast(TypeIdentifier)p.type).ident == tp.ident)
4177 {
4178 Expression e = (*arguments)[u];
4179 tiargs.push(e.type);
4180 break;
4181 }
4182 }
4183 }
4184
4185 auto ti = new TemplateInstance(exp.loc, exp.td, tiargs);
4186 return (new ScopeExp(exp.loc, ti)).expressionSemantic(sc);
4187 }
4188 return exp.expressionSemantic(sc);
4189 }
4190
visit(CallExp exp)4191 override void visit(CallExp exp)
4192 {
4193 static if (LOGSEMANTIC)
4194 {
4195 printf("CallExp::semantic() %s\n", exp.toChars());
4196 }
4197 if (exp.type)
4198 {
4199 result = exp;
4200 return; // semantic() already run
4201 }
4202
4203 Objects* tiargs = null; // initial list of template arguments
4204 Expression ethis = null;
4205 Type tthis = null;
4206 Expression e1org = exp.e1;
4207
4208 if (auto ce = exp.e1.isCommaExp())
4209 {
4210 /* Rewrite (a,b)(args) as (a,(b(args)))
4211 */
4212 exp.e1 = ce.e2;
4213 ce.e2 = exp;
4214 result = ce.expressionSemantic(sc);
4215 return;
4216 }
4217 if (DelegateExp de = exp.e1.isDelegateExp())
4218 {
4219 exp.e1 = new DotVarExp(de.loc, de.e1, de.func, de.hasOverloads);
4220 visit(exp);
4221 return;
4222 }
4223 if (FuncExp fe = exp.e1.isFuncExp())
4224 {
4225 if (arrayExpressionSemantic(exp.arguments, sc) || preFunctionParameters(sc, exp.arguments))
4226 return setError();
4227
4228 // Run e1 semantic even if arguments have any errors
4229 exp.e1 = callExpSemantic(fe, sc, exp.arguments);
4230 if (exp.e1.op == EXP.error)
4231 {
4232 result = exp.e1;
4233 return;
4234 }
4235 }
4236 if (sc.flags & SCOPE.Cfile)
4237 {
4238 /* See if need to rewrite the AST because of cast/call ambiguity
4239 */
4240 if (auto e = castCallAmbiguity(exp, sc))
4241 {
4242 result = expressionSemantic(e, sc);
4243 return;
4244 }
4245 }
4246
4247 if (Expression ex = resolveUFCS(sc, exp))
4248 {
4249 result = ex;
4250 return;
4251 }
4252
4253 /* This recognizes:
4254 * foo!(tiargs)(funcargs)
4255 */
4256 if (ScopeExp se = exp.e1.isScopeExp())
4257 {
4258 TemplateInstance ti = se.sds.isTemplateInstance();
4259 if (ti)
4260 {
4261 /* Attempt to instantiate ti. If that works, go with it.
4262 * If not, go with partial explicit specialization.
4263 */
4264 WithScopeSymbol withsym;
4265 if (!ti.findTempDecl(sc, &withsym) || !ti.semanticTiargs(sc))
4266 return setError();
4267 if (withsym && withsym.withstate.wthis)
4268 {
4269 exp.e1 = new VarExp(exp.e1.loc, withsym.withstate.wthis);
4270 exp.e1 = new DotTemplateInstanceExp(exp.e1.loc, exp.e1, ti);
4271 goto Ldotti;
4272 }
4273 if (ti.needsTypeInference(sc, 1))
4274 {
4275 /* Go with partial explicit specialization
4276 */
4277 tiargs = ti.tiargs;
4278 assert(ti.tempdecl);
4279 if (TemplateDeclaration td = ti.tempdecl.isTemplateDeclaration())
4280 exp.e1 = new TemplateExp(exp.loc, td);
4281 else if (OverDeclaration od = ti.tempdecl.isOverDeclaration())
4282 exp.e1 = new VarExp(exp.loc, od);
4283 else
4284 exp.e1 = new OverExp(exp.loc, ti.tempdecl.isOverloadSet());
4285 }
4286 else
4287 {
4288 Expression e1x = exp.e1.expressionSemantic(sc);
4289 if (e1x.op == EXP.error)
4290 {
4291 result = e1x;
4292 return;
4293 }
4294 exp.e1 = e1x;
4295 }
4296 }
4297 }
4298
4299 /* This recognizes:
4300 * expr.foo!(tiargs)(funcargs)
4301 */
4302 Ldotti:
4303 if (DotTemplateInstanceExp se = exp.e1.isDotTemplateInstanceExp())
4304 {
4305 TemplateInstance ti = se.ti;
4306 {
4307 /* Attempt to instantiate ti. If that works, go with it.
4308 * If not, go with partial explicit specialization.
4309 */
4310 if (!se.findTempDecl(sc) || !ti.semanticTiargs(sc))
4311 return setError();
4312 if (ti.needsTypeInference(sc, 1))
4313 {
4314 /* Go with partial explicit specialization
4315 */
4316 tiargs = ti.tiargs;
4317 assert(ti.tempdecl);
4318 if (TemplateDeclaration td = ti.tempdecl.isTemplateDeclaration())
4319 exp.e1 = new DotTemplateExp(exp.loc, se.e1, td);
4320 else if (OverDeclaration od = ti.tempdecl.isOverDeclaration())
4321 {
4322 exp.e1 = new DotVarExp(exp.loc, se.e1, od, true);
4323 }
4324 else
4325 exp.e1 = new DotExp(exp.loc, se.e1, new OverExp(exp.loc, ti.tempdecl.isOverloadSet()));
4326 }
4327 else
4328 {
4329 Expression e1x = exp.e1.expressionSemantic(sc);
4330 if (e1x.op == EXP.error)
4331 {
4332 result = e1x;
4333 return;
4334 }
4335 exp.e1 = e1x;
4336 }
4337 }
4338 }
4339
4340 Lagain:
4341 //printf("Lagain: %s\n", toChars());
4342 exp.f = null;
4343 if (exp.e1.op == EXP.this_ || exp.e1.op == EXP.super_)
4344 {
4345 // semantic() run later for these
4346 }
4347 else
4348 {
4349 if (DotIdExp die = exp.e1.isDotIdExp())
4350 {
4351 exp.e1 = die.expressionSemantic(sc);
4352 /* Look for e1 having been rewritten to expr.opDispatch!(string)
4353 * We handle such earlier, so go back.
4354 * Note that in the rewrite, we carefully did not run semantic() on e1
4355 */
4356 if (exp.e1.op == EXP.dotTemplateInstance)
4357 {
4358 goto Ldotti;
4359 }
4360 }
4361 else
4362 {
4363 __gshared int nest;
4364 if (++nest > global.recursionLimit)
4365 {
4366 exp.error("recursive evaluation of `%s`", exp.toChars());
4367 --nest;
4368 return setError();
4369 }
4370 Expression ex = unaSemantic(exp, sc);
4371 --nest;
4372 if (ex)
4373 {
4374 result = ex;
4375 return;
4376 }
4377 }
4378
4379 /* Look for e1 being a lazy parameter
4380 */
4381 if (VarExp ve = exp.e1.isVarExp())
4382 {
4383 if (ve.var.storage_class & STC.lazy_)
4384 {
4385 // lazy parameters can be called without violating purity and safety
4386 Type tw = ve.var.type;
4387 Type tc = ve.var.type.substWildTo(MODFlags.const_);
4388 auto tf = new TypeFunction(ParameterList(), tc, LINK.d, STC.safe | STC.pure_);
4389 (tf = cast(TypeFunction)tf.typeSemantic(exp.loc, sc)).next = tw; // hack for bug7757
4390 auto t = new TypeDelegate(tf);
4391 ve.type = t.typeSemantic(exp.loc, sc);
4392 }
4393 VarDeclaration v = ve.var.isVarDeclaration();
4394 if (v && ve.checkPurity(sc, v))
4395 return setError();
4396 }
4397
4398 if (exp.e1.op == EXP.symbolOffset && (cast(SymOffExp)exp.e1).hasOverloads)
4399 {
4400 SymOffExp se = cast(SymOffExp)exp.e1;
4401 exp.e1 = new VarExp(se.loc, se.var, true);
4402 exp.e1 = exp.e1.expressionSemantic(sc);
4403 }
4404 else if (DotExp de = exp.e1.isDotExp())
4405 {
4406 if (de.e2.op == EXP.overloadSet)
4407 {
4408 ethis = de.e1;
4409 tthis = de.e1.type;
4410 exp.e1 = de.e2;
4411 }
4412 }
4413 else if (exp.e1.op == EXP.star && exp.e1.type.ty == Tfunction)
4414 {
4415 // Rewrite (*fp)(arguments) to fp(arguments)
4416 exp.e1 = (cast(PtrExp)exp.e1).e1;
4417 }
4418 else if (exp.e1.op == EXP.type && (sc && sc.flags & SCOPE.Cfile))
4419 {
4420 const numArgs = exp.arguments ? exp.arguments.length : 0;
4421
4422 /* Ambiguous cases arise from CParser where there is not enough
4423 * information to determine if we have a function call or declaration.
4424 * type-name ( identifier ) ;
4425 * identifier ( identifier ) ;
4426 * If exp.e1 is a type-name, then this is a declaration. C11 does not
4427 * have type construction syntax, so don't convert this to a cast().
4428 */
4429 if (numArgs == 1)
4430 {
4431 Expression arg = (*exp.arguments)[0];
4432 if (auto ie = (*exp.arguments)[0].isIdentifierExp())
4433 {
4434 TypeExp te = cast(TypeExp)exp.e1;
4435 auto initializer = new VoidInitializer(ie.loc);
4436 Dsymbol s = new VarDeclaration(ie.loc, te.type, ie.ident, initializer);
4437 auto decls = new Dsymbols(1);
4438 (*decls)[0] = s;
4439 s = new LinkDeclaration(s.loc, LINK.c, decls);
4440 result = new DeclarationExp(exp.loc, s);
4441 result = result.expressionSemantic(sc);
4442 }
4443 else
4444 {
4445 arg.error("identifier or `(` expected");
4446 result = ErrorExp.get();
4447 }
4448 return;
4449 }
4450 exp.error("identifier or `(` expected before `)`");
4451 result = ErrorExp.get();
4452 return;
4453 }
4454 }
4455
4456 Type t1 = exp.e1.type ? exp.e1.type.toBasetype() : null;
4457
4458 if (exp.e1.op == EXP.error)
4459 {
4460 result = exp.e1;
4461 return;
4462 }
4463 if (arrayExpressionSemantic(exp.arguments, sc) || preFunctionParameters(sc, exp.arguments))
4464 return setError();
4465
4466 // Check for call operator overload
4467 if (t1)
4468 {
4469 if (t1.ty == Tstruct)
4470 {
4471 auto sd = (cast(TypeStruct)t1).sym;
4472 sd.size(exp.loc); // Resolve forward references to construct object
4473 if (sd.sizeok != Sizeok.done)
4474 return setError();
4475 if (!sd.ctor)
4476 sd.ctor = sd.searchCtor();
4477 /* If `sd.ctor` is a generated copy constructor, this means that it
4478 is the single constructor that this struct has. In order to not
4479 disable default construction, the ctor is nullified. The side effect
4480 of this is that the generated copy constructor cannot be called
4481 explicitly, but that is ok, because when calling a constructor the
4482 default constructor should have priority over the generated copy
4483 constructor.
4484 */
4485 if (sd.ctor)
4486 {
4487 auto ctor = sd.ctor.isCtorDeclaration();
4488 if (ctor && ctor.isCpCtor && ctor.isGenerated())
4489 sd.ctor = null;
4490 }
4491
4492 // First look for constructor
4493 if (exp.e1.op == EXP.type && sd.ctor)
4494 {
4495 if (!sd.noDefaultCtor && !(exp.arguments && exp.arguments.dim))
4496 goto Lx;
4497
4498 /* https://issues.dlang.org/show_bug.cgi?id=20695
4499 If all constructors are copy constructors, then
4500 try default construction.
4501 */
4502 if (!sd.hasRegularCtor &&
4503 // https://issues.dlang.org/show_bug.cgi?id=22639
4504 // we might still have a copy constructor that could be called
4505 (*exp.arguments)[0].type.mutableOf != sd.type.mutableOf())
4506 goto Lx;
4507
4508 auto sle = new StructLiteralExp(exp.loc, sd, null, exp.e1.type);
4509 if (!sd.fill(exp.loc, sle.elements, true))
4510 return setError();
4511 if (checkFrameAccess(exp.loc, sc, sd, sle.elements.dim))
4512 return setError();
4513
4514 // https://issues.dlang.org/show_bug.cgi?id=14556
4515 // Set concrete type to avoid further redundant semantic().
4516 sle.type = exp.e1.type;
4517
4518 /* Constructor takes a mutable object, so don't use
4519 * the immutable initializer symbol.
4520 */
4521 sle.useStaticInit = false;
4522
4523 Expression e = sle;
4524 if (auto cf = sd.ctor.isCtorDeclaration())
4525 {
4526 e = new DotVarExp(exp.loc, e, cf, true);
4527 }
4528 else if (auto td = sd.ctor.isTemplateDeclaration())
4529 {
4530 e = new DotIdExp(exp.loc, e, td.ident);
4531 }
4532 else if (auto os = sd.ctor.isOverloadSet())
4533 {
4534 e = new DotExp(exp.loc, e, new OverExp(exp.loc, os));
4535 }
4536 else
4537 assert(0);
4538 e = new CallExp(exp.loc, e, exp.arguments);
4539 e = e.expressionSemantic(sc);
4540 result = e;
4541 return;
4542 }
4543 // No constructor, look for overload of opCall
4544 if (search_function(sd, Id.call))
4545 goto L1;
4546 // overload of opCall, therefore it's a call
4547 if (exp.e1.op != EXP.type)
4548 {
4549 if (sd.aliasthis && !isRecursiveAliasThis(exp.att1, exp.e1.type))
4550 {
4551 exp.e1 = resolveAliasThis(sc, exp.e1);
4552 goto Lagain;
4553 }
4554 exp.error("%s `%s` does not overload ()", sd.kind(), sd.toChars());
4555 return setError();
4556 }
4557
4558 /* It's a struct literal
4559 */
4560 Lx:
4561 Expression e = new StructLiteralExp(exp.loc, sd, exp.arguments, exp.e1.type);
4562 e = e.expressionSemantic(sc);
4563 result = e;
4564 return;
4565 }
4566 else if (t1.ty == Tclass)
4567 {
4568 L1:
4569 // Rewrite as e1.call(arguments)
4570 Expression e = new DotIdExp(exp.loc, exp.e1, Id.call);
4571 e = new CallExp(exp.loc, e, exp.arguments);
4572 e = e.expressionSemantic(sc);
4573 result = e;
4574 return;
4575 }
4576 else if (exp.e1.op == EXP.type && t1.isscalar())
4577 {
4578 Expression e;
4579
4580 // Make sure to use the the enum type itself rather than its
4581 // base type
4582 // https://issues.dlang.org/show_bug.cgi?id=16346
4583 if (exp.e1.type.ty == Tenum)
4584 {
4585 t1 = exp.e1.type;
4586 }
4587
4588 if (!exp.arguments || exp.arguments.dim == 0)
4589 {
4590 e = t1.defaultInitLiteral(exp.loc);
4591 }
4592 else if (exp.arguments.dim == 1)
4593 {
4594 e = (*exp.arguments)[0];
4595 e = e.implicitCastTo(sc, t1);
4596 e = new CastExp(exp.loc, e, t1);
4597 }
4598 else
4599 {
4600 exp.error("more than one argument for construction of `%s`", t1.toChars());
4601 return setError();
4602 }
4603 e = e.expressionSemantic(sc);
4604 result = e;
4605 return;
4606 }
4607 }
4608
4609 static FuncDeclaration resolveOverloadSet(Loc loc, Scope* sc,
4610 OverloadSet os, Objects* tiargs, Type tthis, Expressions* arguments)
4611 {
4612 FuncDeclaration f = null;
4613 foreach (s; os.a)
4614 {
4615 if (tiargs && s.isFuncDeclaration())
4616 continue;
4617 if (auto f2 = resolveFuncCall(loc, sc, s, tiargs, tthis, arguments, FuncResolveFlag.quiet))
4618 {
4619 if (f2.errors)
4620 return null;
4621 if (f)
4622 {
4623 /* Error if match in more than one overload set,
4624 * even if one is a 'better' match than the other.
4625 */
4626 ScopeDsymbol.multiplyDefined(loc, f, f2);
4627 }
4628 else
4629 f = f2;
4630 }
4631 }
4632 if (!f)
4633 .error(loc, "no overload matches for `%s`", os.toChars());
4634 else if (f.errors)
4635 f = null;
4636 return f;
4637 }
4638
4639 bool isSuper = false;
4640 if (exp.e1.op == EXP.dotVariable && t1.ty == Tfunction || exp.e1.op == EXP.dotTemplateDeclaration)
4641 {
4642 UnaExp ue = cast(UnaExp)exp.e1;
4643
4644 Expression ue1old = ue.e1; // need for 'right this' check
4645 DotVarExp dve;
4646 DotTemplateExp dte;
4647 Dsymbol s;
4648 if (exp.e1.op == EXP.dotVariable)
4649 {
4650 dve = cast(DotVarExp)exp.e1;
4651 dte = null;
4652 s = dve.var;
4653 tiargs = null;
4654 }
4655 else
4656 {
4657 dve = null;
4658 dte = cast(DotTemplateExp)exp.e1;
4659 s = dte.td;
4660 }
4661
4662 // Do overload resolution
4663 exp.f = resolveFuncCall(exp.loc, sc, s, tiargs, ue.e1.type, exp.arguments, FuncResolveFlag.standard);
4664 if (!exp.f || exp.f.errors || exp.f.type.ty == Terror)
4665 return setError();
4666
4667 if (exp.f.interfaceVirtual)
4668 {
4669 /* Cast 'this' to the type of the interface, and replace f with the interface's equivalent
4670 */
4671 auto b = exp.f.interfaceVirtual;
4672 auto ad2 = b.sym;
4673 ue.e1 = ue.e1.castTo(sc, ad2.type.addMod(ue.e1.type.mod));
4674 ue.e1 = ue.e1.expressionSemantic(sc);
4675 auto vi = exp.f.findVtblIndex(&ad2.vtbl, cast(int)ad2.vtbl.dim);
4676 assert(vi >= 0);
4677 exp.f = ad2.vtbl[vi].isFuncDeclaration();
4678 assert(exp.f);
4679 }
4680 if (exp.f.needThis())
4681 {
4682 AggregateDeclaration ad = exp.f.toParentLocal().isAggregateDeclaration();
4683 ue.e1 = getRightThis(exp.loc, sc, ad, ue.e1, exp.f);
4684 if (ue.e1.op == EXP.error)
4685 {
4686 result = ue.e1;
4687 return;
4688 }
4689 ethis = ue.e1;
4690 tthis = ue.e1.type;
4691 if (!(exp.f.type.ty == Tfunction && (cast(TypeFunction)exp.f.type).isScopeQual))
4692 {
4693 if (global.params.useDIP1000 == FeatureState.enabled && checkParamArgumentEscape(sc, exp.f, null, ethis, false, false))
4694 return setError();
4695 }
4696 }
4697
4698 /* Cannot call public functions from inside invariant
4699 * (because then the invariant would have infinite recursion)
4700 */
4701 if (sc.func && sc.func.isInvariantDeclaration() && ue.e1.op == EXP.this_ && exp.f.addPostInvariant())
4702 {
4703 exp.error("cannot call `public`/`export` function `%s` from invariant", exp.f.toChars());
4704 return setError();
4705 }
4706
4707 if (!exp.ignoreAttributes)
4708 checkFunctionAttributes(exp, sc, exp.f);
4709 checkAccess(exp.loc, sc, ue.e1, exp.f);
4710 if (!exp.f.needThis())
4711 {
4712 exp.e1 = Expression.combine(ue.e1, new VarExp(exp.loc, exp.f, false));
4713 }
4714 else
4715 {
4716 if (ue1old.checkRightThis(sc))
4717 return setError();
4718 if (exp.e1.op == EXP.dotVariable)
4719 {
4720 dve.var = exp.f;
4721 exp.e1.type = exp.f.type;
4722 }
4723 else
4724 {
4725 exp.e1 = new DotVarExp(exp.loc, dte.e1, exp.f, false);
4726 exp.e1 = exp.e1.expressionSemantic(sc);
4727 if (exp.e1.op == EXP.error)
4728 return setError();
4729 ue = cast(UnaExp)exp.e1;
4730 }
4731 version (none)
4732 {
4733 printf("ue.e1 = %s\n", ue.e1.toChars());
4734 printf("f = %s\n", exp.f.toChars());
4735 printf("t1 = %s\n", t1.toChars());
4736 printf("e1 = %s\n", exp.e1.toChars());
4737 printf("e1.type = %s\n", exp.e1.type.toChars());
4738 }
4739
4740 // See if we need to adjust the 'this' pointer
4741 AggregateDeclaration ad = exp.f.isThis();
4742 ClassDeclaration cd = ue.e1.type.isClassHandle();
4743 if (ad && cd && ad.isClassDeclaration())
4744 {
4745 if (ue.e1.op == EXP.dotType)
4746 {
4747 ue.e1 = (cast(DotTypeExp)ue.e1).e1;
4748 exp.directcall = true;
4749 }
4750 else if (ue.e1.op == EXP.super_)
4751 exp.directcall = true;
4752 else if ((cd.storage_class & STC.final_) != 0) // https://issues.dlang.org/show_bug.cgi?id=14211
4753 exp.directcall = true;
4754
4755 if (ad != cd)
4756 {
4757 ue.e1 = ue.e1.castTo(sc, ad.type.addMod(ue.e1.type.mod));
4758 ue.e1 = ue.e1.expressionSemantic(sc);
4759 }
4760 }
4761 }
4762 // If we've got a pointer to a function then deference it
4763 // https://issues.dlang.org/show_bug.cgi?id=16483
4764 if (exp.e1.type.isPtrToFunction())
4765 {
4766 Expression e = new PtrExp(exp.loc, exp.e1);
4767 e.type = exp.e1.type.nextOf();
4768 exp.e1 = e;
4769 }
4770 t1 = exp.e1.type;
4771 }
4772 else if (exp.e1.op == EXP.super_ || exp.e1.op == EXP.this_)
4773 {
4774 auto ad = sc.func ? sc.func.isThis() : null;
4775 auto cd = ad ? ad.isClassDeclaration() : null;
4776
4777 isSuper = exp.e1.op == EXP.super_;
4778 if (isSuper)
4779 {
4780 // Base class constructor call
4781 if (!cd || !cd.baseClass || !sc.func.isCtorDeclaration())
4782 {
4783 exp.error("super class constructor call must be in a constructor");
4784 return setError();
4785 }
4786 if (!cd.baseClass.ctor)
4787 {
4788 exp.error("no super class constructor for `%s`", cd.baseClass.toChars());
4789 return setError();
4790 }
4791 }
4792 else
4793 {
4794 // `this` call expression must be inside a
4795 // constructor
4796 if (!ad || !sc.func.isCtorDeclaration())
4797 {
4798 exp.error("constructor call must be in a constructor");
4799 return setError();
4800 }
4801
4802 // https://issues.dlang.org/show_bug.cgi?id=18719
4803 // If `exp` is a call expression to another constructor
4804 // then it means that all struct/class fields will be
4805 // initialized after this call.
4806 foreach (ref field; sc.ctorflow.fieldinit)
4807 {
4808 field.csx |= CSX.this_ctor;
4809 }
4810 }
4811
4812 if (!sc.intypeof && !(sc.ctorflow.callSuper & CSX.halt))
4813 {
4814 if (sc.inLoop || sc.ctorflow.callSuper & CSX.label)
4815 exp.error("constructor calls not allowed in loops or after labels");
4816 if (sc.ctorflow.callSuper & (CSX.super_ctor | CSX.this_ctor))
4817 exp.error("multiple constructor calls");
4818 if ((sc.ctorflow.callSuper & CSX.return_) && !(sc.ctorflow.callSuper & CSX.any_ctor))
4819 exp.error("an earlier `return` statement skips constructor");
4820 sc.ctorflow.callSuper |= CSX.any_ctor | (isSuper ? CSX.super_ctor : CSX.this_ctor);
4821 }
4822
4823 tthis = ad.type.addMod(sc.func.type.mod);
4824 auto ctor = isSuper ? cd.baseClass.ctor : ad.ctor;
4825 if (auto os = ctor.isOverloadSet())
4826 exp.f = resolveOverloadSet(exp.loc, sc, os, null, tthis, exp.arguments);
4827 else
4828 exp.f = resolveFuncCall(exp.loc, sc, ctor, null, tthis, exp.arguments, FuncResolveFlag.standard);
4829
4830 if (!exp.f || exp.f.errors)
4831 return setError();
4832
4833 checkFunctionAttributes(exp, sc, exp.f);
4834 checkAccess(exp.loc, sc, null, exp.f);
4835
4836 exp.e1 = new DotVarExp(exp.e1.loc, exp.e1, exp.f, false);
4837 exp.e1 = exp.e1.expressionSemantic(sc);
4838 // https://issues.dlang.org/show_bug.cgi?id=21095
4839 if (exp.e1.op == EXP.error)
4840 return setError();
4841 t1 = exp.e1.type;
4842
4843 // BUG: this should really be done by checking the static
4844 // call graph
4845 if (exp.f == sc.func)
4846 {
4847 exp.error("cyclic constructor call");
4848 return setError();
4849 }
4850 }
4851 else if (auto oe = exp.e1.isOverExp())
4852 {
4853 exp.f = resolveOverloadSet(exp.loc, sc, oe.vars, tiargs, tthis, exp.arguments);
4854 if (!exp.f)
4855 return setError();
4856 if (ethis)
4857 exp.e1 = new DotVarExp(exp.loc, ethis, exp.f, false);
4858 else
4859 exp.e1 = new VarExp(exp.loc, exp.f, false);
4860 goto Lagain;
4861 }
4862 else if (!t1)
4863 {
4864 exp.error("function expected before `()`, not `%s`", exp.e1.toChars());
4865 return setError();
4866 }
4867 else if (t1.ty == Terror)
4868 {
4869 return setError();
4870 }
4871 else if (t1.ty != Tfunction)
4872 {
4873 TypeFunction tf;
4874 const(char)* p;
4875 Dsymbol s;
4876 exp.f = null;
4877 if (auto fe = exp.e1.isFuncExp())
4878 {
4879 // function literal that direct called is always inferred.
4880 assert(fe.fd);
4881 exp.f = fe.fd;
4882 tf = cast(TypeFunction)exp.f.type;
4883 p = "function literal";
4884 }
4885 else if (t1.ty == Tdelegate)
4886 {
4887 TypeDelegate td = cast(TypeDelegate)t1;
4888 assert(td.next.ty == Tfunction);
4889 tf = cast(TypeFunction)td.next;
4890 p = "delegate";
4891 }
4892 else if (auto tfx = t1.isPtrToFunction())
4893 {
4894 tf = tfx;
4895 p = "function pointer";
4896 }
4897 else if (exp.e1.op == EXP.dotVariable && (cast(DotVarExp)exp.e1).var.isOverDeclaration())
4898 {
4899 DotVarExp dve = cast(DotVarExp)exp.e1;
4900 exp.f = resolveFuncCall(exp.loc, sc, dve.var, tiargs, dve.e1.type, exp.arguments, FuncResolveFlag.overloadOnly);
4901 if (!exp.f)
4902 return setError();
4903 if (exp.f.needThis())
4904 {
4905 dve.var = exp.f;
4906 dve.type = exp.f.type;
4907 dve.hasOverloads = false;
4908 goto Lagain;
4909 }
4910 exp.e1 = new VarExp(dve.loc, exp.f, false);
4911 Expression e = new CommaExp(exp.loc, dve.e1, exp);
4912 result = e.expressionSemantic(sc);
4913 return;
4914 }
4915 else if (exp.e1.op == EXP.variable && (cast(VarExp)exp.e1).var.isOverDeclaration())
4916 {
4917 s = (cast(VarExp)exp.e1).var;
4918 goto L2;
4919 }
4920 else if (exp.e1.op == EXP.template_)
4921 {
4922 s = (cast(TemplateExp)exp.e1).td;
4923 L2:
4924 exp.f = resolveFuncCall(exp.loc, sc, s, tiargs, null, exp.arguments, FuncResolveFlag.standard);
4925 if (!exp.f || exp.f.errors)
4926 return setError();
4927 if (exp.f.needThis())
4928 {
4929 if (hasThis(sc))
4930 {
4931 // Supply an implicit 'this', as in
4932 // this.ident
4933 exp.e1 = new DotVarExp(exp.loc, (new ThisExp(exp.loc)).expressionSemantic(sc), exp.f, false);
4934 goto Lagain;
4935 }
4936 else if (isNeedThisScope(sc, exp.f))
4937 {
4938 exp.error("need `this` for `%s` of type `%s`", exp.f.toChars(), exp.f.type.toChars());
4939 return setError();
4940 }
4941 }
4942 exp.e1 = new VarExp(exp.e1.loc, exp.f, false);
4943 goto Lagain;
4944 }
4945 else
4946 {
4947 exp.error("function expected before `()`, not `%s` of type `%s`", exp.e1.toChars(), exp.e1.type.toChars());
4948 return setError();
4949 }
4950
4951 const(char)* failMessage;
4952 Expression[] fargs = exp.arguments ? (*exp.arguments)[] : null;
4953 if (!tf.callMatch(null, fargs, 0, &failMessage, sc))
4954 {
4955 OutBuffer buf;
4956 buf.writeByte('(');
4957 argExpTypesToCBuffer(&buf, exp.arguments);
4958 buf.writeByte(')');
4959 if (tthis)
4960 tthis.modToBuffer(&buf);
4961
4962 //printf("tf = %s, args = %s\n", tf.deco, (*arguments)[0].type.deco);
4963 .error(exp.loc, "%s `%s%s` is not callable using argument types `%s`",
4964 p, exp.e1.toChars(), parametersTypeToChars(tf.parameterList), buf.peekChars());
4965 if (failMessage)
4966 errorSupplemental(exp.loc, "%s", failMessage);
4967 return setError();
4968 }
4969 // Purity and safety check should run after testing arguments matching
4970 if (exp.f)
4971 {
4972 exp.checkPurity(sc, exp.f);
4973 exp.checkSafety(sc, exp.f);
4974 exp.checkNogc(sc, exp.f);
4975 if (exp.f.checkNestedReference(sc, exp.loc))
4976 return setError();
4977 }
4978 else if (sc.func && sc.intypeof != 1 && !(sc.flags & (SCOPE.ctfe | SCOPE.debug_)))
4979 {
4980 bool err = false;
4981 if (!tf.purity && sc.func.setImpure())
4982 {
4983 exp.error("`pure` %s `%s` cannot call impure %s `%s`",
4984 sc.func.kind(), sc.func.toPrettyChars(), p, exp.e1.toChars());
4985 err = true;
4986 }
4987 if (!tf.isnogc && sc.func.setGC())
4988 {
4989 exp.error("`@nogc` %s `%s` cannot call non-@nogc %s `%s`",
4990 sc.func.kind(), sc.func.toPrettyChars(), p, exp.e1.toChars());
4991 err = true;
4992 }
4993 if (tf.trust <= TRUST.system && sc.func.setUnsafe())
4994 {
4995 exp.error("`@safe` %s `%s` cannot call `@system` %s `%s`",
4996 sc.func.kind(), sc.func.toPrettyChars(), p, exp.e1.toChars());
4997 err = true;
4998 }
4999 if (err)
5000 return setError();
5001 }
5002
5003 if (t1.ty == Tpointer)
5004 {
5005 Expression e = new PtrExp(exp.loc, exp.e1);
5006 e.type = tf;
5007 exp.e1 = e;
5008 }
5009 t1 = tf;
5010 }
5011 else if (VarExp ve = exp.e1.isVarExp())
5012 {
5013 // Do overload resolution
5014 exp.f = ve.var.isFuncDeclaration();
5015 assert(exp.f);
5016 tiargs = null;
5017
5018 if (exp.f.overnext)
5019 exp.f = resolveFuncCall(exp.loc, sc, exp.f, tiargs, null, exp.arguments, FuncResolveFlag.overloadOnly);
5020 else
5021 {
5022 exp.f = exp.f.toAliasFunc();
5023 TypeFunction tf = cast(TypeFunction)exp.f.type;
5024 const(char)* failMessage;
5025 Expression[] fargs = exp.arguments ? (*exp.arguments)[] : null;
5026 if (!tf.callMatch(null, fargs, 0, &failMessage, sc))
5027 {
5028 OutBuffer buf;
5029 buf.writeByte('(');
5030 argExpTypesToCBuffer(&buf, exp.arguments);
5031 buf.writeByte(')');
5032
5033 //printf("tf = %s, args = %s\n", tf.deco, (*arguments)[0].type.deco);
5034 .error(exp.loc, "%s `%s%s` is not callable using argument types `%s`",
5035 exp.f.kind(), exp.f.toPrettyChars(), parametersTypeToChars(tf.parameterList), buf.peekChars());
5036 if (failMessage)
5037 errorSupplemental(exp.loc, "%s", failMessage);
5038 exp.f = null;
5039 }
5040 }
5041 if (!exp.f || exp.f.errors)
5042 return setError();
5043
5044 if (exp.f.needThis())
5045 {
5046 // Change the ancestor lambdas to delegate before hasThis(sc) call.
5047 if (exp.f.checkNestedReference(sc, exp.loc))
5048 return setError();
5049
5050 if (hasThis(sc))
5051 {
5052 // Supply an implicit 'this', as in
5053 // this.ident
5054 exp.e1 = new DotVarExp(exp.loc, (new ThisExp(exp.loc)).expressionSemantic(sc), ve.var);
5055 // Note: we cannot use f directly, because further overload resolution
5056 // through the supplied 'this' may cause different result.
5057 goto Lagain;
5058 }
5059 else if (isNeedThisScope(sc, exp.f))
5060 {
5061 // At this point it is possible that `exp.f` had an ambiguity error that was
5062 // silenced because the previous call to `resolveFuncCall` was done using
5063 // `FuncResolveFlag.overloadOnly`. To make sure that a proper error message
5064 // is printed, redo the call with `FuncResolveFlag.standard`.
5065 //
5066 // https://issues.dlang.org/show_bug.cgi?id=22157
5067 if (exp.f.overnext)
5068 exp.f = resolveFuncCall(exp.loc, sc, exp.f, tiargs, null, exp.arguments, FuncResolveFlag.standard);
5069
5070 if (!exp.f || exp.f.errors)
5071 return setError();
5072
5073 // If no error is printed, it means that `f` is the single matching overload
5074 // and it needs `this`.
5075 exp.error("need `this` for `%s` of type `%s`", exp.f.toChars(), exp.f.type.toChars());
5076 return setError();
5077 }
5078 }
5079
5080 checkFunctionAttributes(exp, sc, exp.f);
5081 checkAccess(exp.loc, sc, null, exp.f);
5082 if (exp.f.checkNestedReference(sc, exp.loc))
5083 return setError();
5084
5085 ethis = null;
5086 tthis = null;
5087
5088 if (ve.hasOverloads)
5089 {
5090 exp.e1 = new VarExp(ve.loc, exp.f, false);
5091 exp.e1.type = exp.f.type;
5092 }
5093 t1 = exp.f.type;
5094 }
5095 assert(t1.ty == Tfunction);
5096
5097 Expression argprefix;
5098 if (!exp.arguments)
5099 exp.arguments = new Expressions();
5100 if (functionParameters(exp.loc, sc, cast(TypeFunction)t1, ethis, tthis, exp.arguments, exp.f, &exp.type, &argprefix))
5101 return setError();
5102
5103 if (!exp.type)
5104 {
5105 exp.e1 = e1org; // https://issues.dlang.org/show_bug.cgi?id=10922
5106 // avoid recursive expression printing
5107 exp.error("forward reference to inferred return type of function call `%s`", exp.toChars());
5108 return setError();
5109 }
5110
5111 if (exp.f && exp.f.tintro)
5112 {
5113 Type t = exp.type;
5114 int offset = 0;
5115 TypeFunction tf = cast(TypeFunction)exp.f.tintro;
5116 if (tf.next.isBaseOf(t, &offset) && offset)
5117 {
5118 exp.type = tf.next;
5119 result = Expression.combine(argprefix, exp.castTo(sc, t));
5120 return;
5121 }
5122 }
5123
5124 // Handle the case of a direct lambda call
5125 if (exp.f && exp.f.isFuncLiteralDeclaration() && sc.func && !sc.intypeof)
5126 {
5127 exp.f.tookAddressOf = 0;
5128 }
5129
5130 result = Expression.combine(argprefix, exp);
5131
5132 if (isSuper)
5133 {
5134 auto ad = sc.func ? sc.func.isThis() : null;
5135 auto cd = ad ? ad.isClassDeclaration() : null;
5136 if (cd && cd.classKind == ClassKind.cpp && exp.f && !exp.f.fbody)
5137 {
5138 // if super is defined in C++, it sets the vtable pointer to the base class
5139 // so we have to restore it, but still return 'this' from super() call:
5140 // (auto __vptrTmp = this.__vptr, auto __superTmp = super()), (this.__vptr = __vptrTmp, __superTmp)
5141 Loc loc = exp.loc;
5142
5143 auto vptr = new DotIdExp(loc, new ThisExp(loc), Id.__vptr);
5144 auto vptrTmpDecl = copyToTemp(0, "__vptrTmp", vptr);
5145 auto declareVptrTmp = new DeclarationExp(loc, vptrTmpDecl);
5146
5147 auto superTmpDecl = copyToTemp(0, "__superTmp", result);
5148 auto declareSuperTmp = new DeclarationExp(loc, superTmpDecl);
5149
5150 auto declareTmps = new CommaExp(loc, declareVptrTmp, declareSuperTmp);
5151
5152 auto restoreVptr = new AssignExp(loc, vptr.syntaxCopy(), new VarExp(loc, vptrTmpDecl));
5153
5154 Expression e = new CommaExp(loc, declareTmps, new CommaExp(loc, restoreVptr, new VarExp(loc, superTmpDecl)));
5155 result = e.expressionSemantic(sc);
5156 }
5157 }
5158
5159 // declare dual-context container
5160 if (exp.f && exp.f.hasDualContext() && !sc.intypeof && sc.func)
5161 {
5162 // check access to second `this`
5163 if (AggregateDeclaration ad2 = exp.f.isMember2())
5164 {
5165 Expression te = new ThisExp(exp.loc).expressionSemantic(sc);
5166 if (te.op != EXP.error)
5167 te = getRightThis(exp.loc, sc, ad2, te, exp.f);
5168 if (te.op == EXP.error)
5169 {
5170 exp.error("need `this` of type `%s` to call function `%s`", ad2.toChars(), exp.f.toChars());
5171 return setError();
5172 }
5173 }
5174 exp.vthis2 = makeThis2Argument(exp.loc, sc, exp.f);
5175 Expression de = new DeclarationExp(exp.loc, exp.vthis2);
5176 result = Expression.combine(de, result);
5177 result = result.expressionSemantic(sc);
5178 }
5179 }
5180
visit(DeclarationExp e)5181 override void visit(DeclarationExp e)
5182 {
5183 if (e.type)
5184 {
5185 result = e;
5186 return;
5187 }
5188 static if (LOGSEMANTIC)
5189 {
5190 printf("DeclarationExp::semantic() %s\n", e.toChars());
5191 }
5192
5193 uint olderrors = global.errors;
5194
5195 /* This is here to support extern(linkage) declaration,
5196 * where the extern(linkage) winds up being an AttribDeclaration
5197 * wrapper.
5198 */
5199 Dsymbol s = e.declaration;
5200
5201 while (1)
5202 {
5203 AttribDeclaration ad = s.isAttribDeclaration();
5204 if (ad)
5205 {
5206 if (ad.decl && ad.decl.dim == 1)
5207 {
5208 s = (*ad.decl)[0];
5209 continue;
5210 }
5211 }
5212 break;
5213 }
5214
5215 //printf("inserting '%s' %p into sc = %p\n", s.toChars(), s, sc);
5216 // Insert into both local scope and function scope.
5217 // Must be unique in both.
5218 if (s.ident)
5219 {
5220 VarDeclaration v = s.isVarDeclaration();
5221 if (v)
5222 {
5223 if (sc.flags & SCOPE.Cfile)
5224 {
5225 /* Do semantic() on the type before inserting v into the symbol table
5226 */
5227 if (!v.originalType)
5228 v.originalType = v.type.syntaxCopy();
5229 Scope* sc2 = sc.push();
5230 sc2.stc |= v.storage_class & STC.FUNCATTR;
5231 sc2.linkage = LINK.c; // account for the extern(C) in front of the declaration
5232 v.inuse++;
5233 v.type = v.type.typeSemantic(v.loc, sc2);
5234 v.inuse--;
5235 sc2.pop();
5236 }
5237 else
5238 {
5239 /* Do semantic() on initializer first so this will be illegal:
5240 * int a = a;
5241 */
5242 e.declaration.dsymbolSemantic(sc);
5243 s.parent = sc.parent;
5244 }
5245 }
5246
5247 if (!sc.insert(s))
5248 {
5249 auto conflict = sc.search(Loc.initial, s.ident, null);
5250 e.error("declaration `%s` is already defined", s.toPrettyChars());
5251 errorSupplemental(conflict.loc, "`%s` `%s` is defined here",
5252 conflict.kind(), conflict.toChars());
5253 return setError();
5254 }
5255
5256 if (v && (sc.flags & SCOPE.Cfile))
5257 {
5258 /* Do semantic() on initializer last so this will be legal:
5259 * int a = a;
5260 */
5261 e.declaration.dsymbolSemantic(sc);
5262 s.parent = sc.parent;
5263 }
5264
5265 if (sc.func)
5266 {
5267 // https://issues.dlang.org/show_bug.cgi?id=11720
5268 if ((s.isFuncDeclaration() ||
5269 s.isAggregateDeclaration() ||
5270 s.isEnumDeclaration() ||
5271 s.isTemplateDeclaration() ||
5272 v
5273 ) && !sc.func.localsymtab.insert(s))
5274 {
5275 // Get the previous symbol
5276 Dsymbol originalSymbol = sc.func.localsymtab.lookup(s.ident);
5277
5278 // Perturb the name mangling so that the symbols can co-exist
5279 // instead of colliding
5280 s.localNum = cast(ushort)(originalSymbol.localNum + 1);
5281 // 65535 should be enough for anyone
5282 if (!s.localNum)
5283 {
5284 e.error("more than 65535 symbols with name `%s` generated", s.ident.toChars());
5285 return setError();
5286 }
5287
5288 // Replace originalSymbol with s, which updates the localCount
5289 sc.func.localsymtab.update(s);
5290
5291 // The mangling change only works for D mangling
5292 }
5293
5294 if (!(sc.flags & SCOPE.Cfile))
5295 {
5296 /* https://issues.dlang.org/show_bug.cgi?id=21272
5297 * If we are in a foreach body we need to extract the
5298 * function containing the foreach
5299 */
5300 FuncDeclaration fes_enclosing_func;
5301 if (sc.func && sc.func.fes)
5302 fes_enclosing_func = sc.enclosing.enclosing.func;
5303
5304 // Disallow shadowing
5305 for (Scope* scx = sc.enclosing; scx && (scx.func == sc.func || (fes_enclosing_func && scx.func == fes_enclosing_func)); scx = scx.enclosing)
5306 {
5307 Dsymbol s2;
5308 if (scx.scopesym && scx.scopesym.symtab && (s2 = scx.scopesym.symtab.lookup(s.ident)) !is null && s != s2)
5309 {
5310 // allow STC.local symbols to be shadowed
5311 // TODO: not really an optimal design
5312 auto decl = s2.isDeclaration();
5313 if (!decl || !(decl.storage_class & STC.local))
5314 {
5315 if (sc.func.fes)
5316 {
5317 e.deprecation("%s `%s` is shadowing %s `%s`. Rename the `foreach` variable.", s.kind(), s.ident.toChars(), s2.kind(), s2.toPrettyChars());
5318 }
5319 else
5320 {
5321 e.error("%s `%s` is shadowing %s `%s`", s.kind(), s.ident.toChars(), s2.kind(), s2.toPrettyChars());
5322 return setError();
5323 }
5324 }
5325 }
5326 }
5327 }
5328 }
5329 }
5330 if (!s.isVarDeclaration())
5331 {
5332 Scope* sc2 = sc;
5333 if (sc2.stc & (STC.pure_ | STC.nothrow_ | STC.nogc))
5334 sc2 = sc.push();
5335 sc2.stc &= ~(STC.pure_ | STC.nothrow_ | STC.nogc);
5336 e.declaration.dsymbolSemantic(sc2);
5337 if (sc2 != sc)
5338 sc2.pop();
5339 s.parent = sc.parent;
5340 }
5341 if (global.errors == olderrors)
5342 {
5343 e.declaration.semantic2(sc);
5344 if (global.errors == olderrors)
5345 {
5346 e.declaration.semantic3(sc);
5347 }
5348 }
5349 // todo: error in declaration should be propagated.
5350
5351 e.type = Type.tvoid;
5352 result = e;
5353 }
5354
visit(TypeidExp exp)5355 override void visit(TypeidExp exp)
5356 {
5357 static if (LOGSEMANTIC)
5358 {
5359 printf("TypeidExp::semantic() %s\n", exp.toChars());
5360 }
5361 Type ta = isType(exp.obj);
5362 Expression ea = isExpression(exp.obj);
5363 Dsymbol sa = isDsymbol(exp.obj);
5364 //printf("ta %p ea %p sa %p\n", ta, ea, sa);
5365
5366 if (ta)
5367 {
5368 dmd.typesem.resolve(ta, exp.loc, sc, ea, ta, sa, true);
5369 }
5370
5371 if (ea)
5372 {
5373 if (auto sym = getDsymbol(ea))
5374 ea = symbolToExp(sym, exp.loc, sc, false);
5375 else
5376 ea = ea.expressionSemantic(sc);
5377 ea = resolveProperties(sc, ea);
5378 ta = ea.type;
5379 if (ea.op == EXP.type)
5380 ea = null;
5381 }
5382
5383 if (!ta)
5384 {
5385 //printf("ta %p ea %p sa %p\n", ta, ea, sa);
5386 exp.error("no type for `typeid(%s)`", ea ? ea.toChars() : (sa ? sa.toChars() : ""));
5387 return setError();
5388 }
5389
5390 ta.checkComplexTransition(exp.loc, sc);
5391
5392 Expression e;
5393 auto tb = ta.toBasetype();
5394 if (ea && tb.ty == Tclass)
5395 {
5396 if (tb.toDsymbol(sc).isClassDeclaration().classKind == ClassKind.cpp)
5397 {
5398 error(exp.loc, "Runtime type information is not supported for `extern(C++)` classes");
5399 e = ErrorExp.get();
5400 }
5401 else if (!Type.typeinfoclass)
5402 {
5403 error(exp.loc, "`object.TypeInfo_Class` could not be found, but is implicitly used");
5404 e = ErrorExp.get();
5405 }
5406 else
5407 {
5408 /* Get the dynamic type, which is .classinfo
5409 */
5410 ea = ea.expressionSemantic(sc);
5411 e = new TypeidExp(ea.loc, ea);
5412 e.type = Type.typeinfoclass.type;
5413 }
5414 }
5415 else if (ta.ty == Terror)
5416 {
5417 e = ErrorExp.get();
5418 }
5419 else
5420 {
5421 // Handle this in the glue layer
5422 e = new TypeidExp(exp.loc, ta);
5423 e.type = getTypeInfoType(exp.loc, ta, sc);
5424
5425 semanticTypeInfo(sc, ta);
5426
5427 if (ea)
5428 {
5429 e = new CommaExp(exp.loc, ea, e); // execute ea
5430 e = e.expressionSemantic(sc);
5431 }
5432 }
5433 result = e;
5434 }
5435
visit(TraitsExp e)5436 override void visit(TraitsExp e)
5437 {
5438 result = semanticTraits(e, sc);
5439 }
5440
visit(HaltExp e)5441 override void visit(HaltExp e)
5442 {
5443 static if (LOGSEMANTIC)
5444 {
5445 printf("HaltExp::semantic()\n");
5446 }
5447 e.type = Type.tnoreturn;
5448 result = e;
5449 }
5450
visit(IsExp e)5451 override void visit(IsExp e)
5452 {
5453 /* is(targ id tok tspec)
5454 * is(targ id : tok2)
5455 * is(targ id == tok2)
5456 */
5457 Type tded = null;
5458
5459 void yes()
5460 {
5461 //printf("yes\n");
5462 if (!e.id)
5463 {
5464 result = IntegerExp.createBool(true);
5465 return;
5466 }
5467
5468 Dsymbol s;
5469 Tuple tup = isTuple(tded);
5470 if (tup)
5471 s = new TupleDeclaration(e.loc, e.id, &tup.objects);
5472 else
5473 s = new AliasDeclaration(e.loc, e.id, tded);
5474 s.dsymbolSemantic(sc);
5475
5476 /* The reason for the !tup is unclear. It fails Phobos unittests if it is not there.
5477 * More investigation is needed.
5478 */
5479 if (!tup && !sc.insert(s))
5480 {
5481 auto conflict = sc.search(Loc.initial, s.ident, null);
5482 e.error("declaration `%s` is already defined", s.toPrettyChars());
5483 errorSupplemental(conflict.loc, "`%s` `%s` is defined here",
5484 conflict.kind(), conflict.toChars());
5485 }
5486
5487 unSpeculative(sc, s);
5488
5489 result = IntegerExp.createBool(true);
5490 }
5491 void no()
5492 {
5493 result = IntegerExp.createBool(false);
5494 //printf("no\n");
5495 }
5496
5497 static if (LOGSEMANTIC)
5498 {
5499 printf("IsExp::semantic(%s)\n", e.toChars());
5500 }
5501 if (e.id && !(sc.flags & SCOPE.condition))
5502 {
5503 e.error("can only declare type aliases within `static if` conditionals or `static assert`s");
5504 return setError();
5505 }
5506
5507 if (e.tok2 == TOK.package_ || e.tok2 == TOK.module_) // These is() expressions are special because they can work on modules, not just types.
5508 {
5509 const oldErrors = global.startGagging();
5510 Dsymbol sym = e.targ.toDsymbol(sc);
5511 global.endGagging(oldErrors);
5512
5513 if (sym is null)
5514 return no();
5515 Package p = resolveIsPackage(sym);
5516 if (p is null)
5517 return no();
5518 if (e.tok2 == TOK.package_ && p.isModule()) // Note that isModule() will return null for package modules because they're not actually instances of Module.
5519 return no();
5520 else if(e.tok2 == TOK.module_ && !(p.isModule() || p.isPackageMod()))
5521 return no();
5522 tded = e.targ;
5523 return yes();
5524 }
5525
5526 {
5527 Scope* sc2 = sc.copy(); // keep sc.flags
5528 sc2.tinst = null;
5529 sc2.minst = null;
5530 sc2.flags |= SCOPE.fullinst;
5531 Type t = e.targ.trySemantic(e.loc, sc2);
5532 sc2.pop();
5533 if (!t) // errors, so condition is false
5534 return no();
5535 e.targ = t;
5536 }
5537
5538 if (e.tok2 != TOK.reserved)
5539 {
5540 switch (e.tok2)
5541 {
5542 case TOK.struct_:
5543 if (e.targ.ty != Tstruct)
5544 return no();
5545 if ((cast(TypeStruct)e.targ).sym.isUnionDeclaration())
5546 return no();
5547 tded = e.targ;
5548 break;
5549
5550 case TOK.union_:
5551 if (e.targ.ty != Tstruct)
5552 return no();
5553 if (!(cast(TypeStruct)e.targ).sym.isUnionDeclaration())
5554 return no();
5555 tded = e.targ;
5556 break;
5557
5558 case TOK.class_:
5559 if (e.targ.ty != Tclass)
5560 return no();
5561 if ((cast(TypeClass)e.targ).sym.isInterfaceDeclaration())
5562 return no();
5563 tded = e.targ;
5564 break;
5565
5566 case TOK.interface_:
5567 if (e.targ.ty != Tclass)
5568 return no();
5569 if (!(cast(TypeClass)e.targ).sym.isInterfaceDeclaration())
5570 return no();
5571 tded = e.targ;
5572 break;
5573
5574 case TOK.const_:
5575 if (!e.targ.isConst())
5576 return no();
5577 tded = e.targ;
5578 break;
5579
5580 case TOK.immutable_:
5581 if (!e.targ.isImmutable())
5582 return no();
5583 tded = e.targ;
5584 break;
5585
5586 case TOK.shared_:
5587 if (!e.targ.isShared())
5588 return no();
5589 tded = e.targ;
5590 break;
5591
5592 case TOK.inout_:
5593 if (!e.targ.isWild())
5594 return no();
5595 tded = e.targ;
5596 break;
5597
5598 case TOK.super_:
5599 // If class or interface, get the base class and interfaces
5600 if (e.targ.ty != Tclass)
5601 return no();
5602 else
5603 {
5604 ClassDeclaration cd = (cast(TypeClass)e.targ).sym;
5605 auto args = new Parameters();
5606 args.reserve(cd.baseclasses.dim);
5607 if (cd.semanticRun < PASS.semanticdone)
5608 cd.dsymbolSemantic(null);
5609 for (size_t i = 0; i < cd.baseclasses.dim; i++)
5610 {
5611 BaseClass* b = (*cd.baseclasses)[i];
5612 args.push(new Parameter(STC.in_, b.type, null, null, null));
5613 }
5614 tded = new TypeTuple(args);
5615 }
5616 break;
5617
5618 case TOK.enum_:
5619 if (e.targ.ty != Tenum)
5620 return no();
5621 if (e.id)
5622 tded = (cast(TypeEnum)e.targ).sym.getMemtype(e.loc);
5623 else
5624 tded = e.targ;
5625
5626 if (tded.ty == Terror)
5627 return setError();
5628 break;
5629
5630 case TOK.delegate_:
5631 if (e.targ.ty != Tdelegate)
5632 return no();
5633 tded = (cast(TypeDelegate)e.targ).next; // the underlying function type
5634 break;
5635
5636 case TOK.function_:
5637 case TOK.parameters:
5638 {
5639 if (e.targ.ty != Tfunction)
5640 return no();
5641 tded = e.targ;
5642
5643 /* Generate tuple from function parameter types.
5644 */
5645 assert(tded.ty == Tfunction);
5646 auto tdedf = tded.isTypeFunction();
5647 auto args = new Parameters();
5648 foreach (i, arg; tdedf.parameterList)
5649 {
5650 assert(arg && arg.type);
5651 /* If one of the default arguments was an error,
5652 don't return an invalid tuple
5653 */
5654 if (e.tok2 == TOK.parameters && arg.defaultArg && arg.defaultArg.op == EXP.error)
5655 return setError();
5656 args.push(new Parameter(arg.storageClass, arg.type, (e.tok2 == TOK.parameters) ? arg.ident : null, (e.tok2 == TOK.parameters) ? arg.defaultArg : null, arg.userAttribDecl));
5657 }
5658 tded = new TypeTuple(args);
5659 break;
5660 }
5661 case TOK.return_:
5662 /* Get the 'return type' for the function,
5663 * delegate, or pointer to function.
5664 */
5665 if (auto tf = e.targ.isFunction_Delegate_PtrToFunction())
5666 tded = tf.next;
5667 else
5668 return no();
5669 break;
5670
5671 case TOK.argumentTypes:
5672 /* Generate a type tuple of the equivalent types used to determine if a
5673 * function argument of this type can be passed in registers.
5674 * The results of this are highly platform dependent, and intended
5675 * primarly for use in implementing va_arg().
5676 */
5677 tded = target.toArgTypes(e.targ);
5678 if (!tded)
5679 return no();
5680 // not valid for a parameter
5681 break;
5682
5683 case TOK.vector:
5684 if (e.targ.ty != Tvector)
5685 return no();
5686 tded = (cast(TypeVector)e.targ).basetype;
5687 break;
5688
5689 default:
5690 assert(0);
5691 }
5692
5693 // https://issues.dlang.org/show_bug.cgi?id=18753
5694 if (tded)
5695 return yes();
5696 return no();
5697 }
5698 else if (e.tspec && !e.id && !(e.parameters && e.parameters.dim))
5699 {
5700 /* Evaluate to true if targ matches tspec
5701 * is(targ == tspec)
5702 * is(targ : tspec)
5703 */
5704 e.tspec = e.tspec.typeSemantic(e.loc, sc);
5705 //printf("targ = %s, %s\n", e.targ.toChars(), e.targ.deco);
5706 //printf("tspec = %s, %s\n", e.tspec.toChars(), e.tspec.deco);
5707
5708 if (e.tok == TOK.colon)
5709 {
5710 // current scope is itself deprecated, or deprecations are not errors
5711 const bool deprecationAllowed = sc.isDeprecated
5712 || global.params.useDeprecated != DiagnosticReporting.error;
5713 const bool preventAliasThis = e.targ.hasDeprecatedAliasThis && !deprecationAllowed;
5714
5715 if (preventAliasThis && e.targ.ty == Tstruct)
5716 {
5717 if ((cast(TypeStruct) e.targ).implicitConvToWithoutAliasThis(e.tspec))
5718 return yes();
5719 else
5720 return no();
5721 }
5722 else if (preventAliasThis && e.targ.ty == Tclass)
5723 {
5724 if ((cast(TypeClass) e.targ).implicitConvToWithoutAliasThis(e.tspec))
5725 return yes();
5726 else
5727 return no();
5728 }
5729 else if (e.targ.implicitConvTo(e.tspec))
5730 return yes();
5731 else
5732 return no();
5733 }
5734 else /* == */
5735 {
5736 if (e.targ.equals(e.tspec))
5737 return yes();
5738 else
5739 return no();
5740 }
5741 }
5742 else if (e.tspec)
5743 {
5744 /* Evaluate to true if targ matches tspec.
5745 * If true, declare id as an alias for the specialized type.
5746 * is(targ == tspec, tpl)
5747 * is(targ : tspec, tpl)
5748 * is(targ id == tspec)
5749 * is(targ id : tspec)
5750 * is(targ id == tspec, tpl)
5751 * is(targ id : tspec, tpl)
5752 */
5753 Identifier tid = e.id ? e.id : Identifier.generateId("__isexp_id");
5754 e.parameters.insert(0, new TemplateTypeParameter(e.loc, tid, null, null));
5755
5756 Objects dedtypes = Objects(e.parameters.dim);
5757 dedtypes.zero();
5758
5759 MATCH m = deduceType(e.targ, sc, e.tspec, e.parameters, &dedtypes, null, 0, e.tok == TOK.equal);
5760 //printf("targ: %s\n", targ.toChars());
5761 //printf("tspec: %s\n", tspec.toChars());
5762 if (m == MATCH.nomatch || (m != MATCH.exact && e.tok == TOK.equal))
5763 {
5764 return no();
5765 }
5766 else
5767 {
5768 tded = cast(Type)dedtypes[0];
5769 if (!tded)
5770 tded = e.targ;
5771 Objects tiargs = Objects(1);
5772 tiargs[0] = e.targ;
5773
5774 /* Declare trailing parameters
5775 */
5776 for (size_t i = 1; i < e.parameters.dim; i++)
5777 {
5778 TemplateParameter tp = (*e.parameters)[i];
5779 Declaration s = null;
5780
5781 m = tp.matchArg(e.loc, sc, &tiargs, i, e.parameters, &dedtypes, &s);
5782 if (m == MATCH.nomatch)
5783 return no();
5784 s.dsymbolSemantic(sc);
5785 if (!sc.insert(s))
5786 {
5787 auto conflict = sc.search(Loc.initial, s.ident, null);
5788 e.error("declaration `%s` is already defined", s.toPrettyChars());
5789 errorSupplemental(conflict.loc, "`%s` `%s` is defined here",
5790 conflict.kind(), conflict.toChars());
5791 }
5792
5793 unSpeculative(sc, s);
5794 }
5795 return yes();
5796 }
5797 }
5798 else if (e.id)
5799 {
5800 /* Declare id as an alias for type targ. Evaluate to true
5801 * is(targ id)
5802 */
5803 tded = e.targ;
5804 }
5805 return yes();
5806 }
5807
visit(BinAssignExp exp)5808 override void visit(BinAssignExp exp)
5809 {
5810 if (exp.type)
5811 {
5812 result = exp;
5813 return;
5814 }
5815
5816 Expression e = exp.op_overload(sc);
5817 if (e)
5818 {
5819 result = e;
5820 return;
5821 }
5822
5823 if (exp.e1.op == EXP.arrayLength)
5824 {
5825 // arr.length op= e2;
5826 e = rewriteOpAssign(exp);
5827 e = e.expressionSemantic(sc);
5828 result = e;
5829 return;
5830 }
5831 if (exp.e1.op == EXP.slice || exp.e1.type.ty == Tarray || exp.e1.type.ty == Tsarray)
5832 {
5833 if (checkNonAssignmentArrayOp(exp.e1))
5834 return setError();
5835
5836 if (exp.e1.op == EXP.slice)
5837 (cast(SliceExp)exp.e1).arrayop = true;
5838
5839 // T[] op= ...
5840 if (exp.e2.implicitConvTo(exp.e1.type.nextOf()))
5841 {
5842 // T[] op= T
5843 exp.e2 = exp.e2.castTo(sc, exp.e1.type.nextOf());
5844 }
5845 else if (Expression ex = typeCombine(exp, sc))
5846 {
5847 result = ex;
5848 return;
5849 }
5850 exp.type = exp.e1.type;
5851 result = arrayOp(exp, sc);
5852 return;
5853 }
5854
5855 exp.e1 = exp.e1.expressionSemantic(sc);
5856 exp.e1 = exp.e1.modifiableLvalue(sc, exp.e1);
5857 exp.e1 = exp.e1.optimize(WANTvalue, /*keepLvalue*/ true);
5858 exp.type = exp.e1.type;
5859
5860 if (auto ad = isAggregate(exp.e1.type))
5861 {
5862 if (const s = search_function(ad, Id.opOpAssign))
5863 {
5864 error(exp.loc, "none of the `opOpAssign` overloads of `%s` are callable for `%s` of type `%s`", ad.toChars(), exp.e1.toChars(), exp.e1.type.toChars());
5865 return setError();
5866 }
5867 }
5868 if (exp.e1.checkScalar() ||
5869 exp.e1.checkReadModifyWrite(exp.op, exp.e2) ||
5870 exp.e1.checkSharedAccess(sc))
5871 return setError();
5872
5873 int arith = (exp.op == EXP.addAssign || exp.op == EXP.minAssign || exp.op == EXP.mulAssign || exp.op == EXP.divAssign || exp.op == EXP.modAssign || exp.op == EXP.powAssign);
5874 int bitwise = (exp.op == EXP.andAssign || exp.op == EXP.orAssign || exp.op == EXP.xorAssign);
5875 int shift = (exp.op == EXP.leftShiftAssign || exp.op == EXP.rightShiftAssign || exp.op == EXP.unsignedRightShiftAssign);
5876
5877 if (bitwise && exp.type.toBasetype().ty == Tbool)
5878 exp.e2 = exp.e2.implicitCastTo(sc, exp.type);
5879 else if (exp.checkNoBool())
5880 return setError();
5881
5882 if ((exp.op == EXP.addAssign || exp.op == EXP.minAssign) && exp.e1.type.toBasetype().ty == Tpointer && exp.e2.type.toBasetype().isintegral())
5883 {
5884 result = scaleFactor(exp, sc);
5885 return;
5886 }
5887
5888 if (Expression ex = typeCombine(exp, sc))
5889 {
5890 result = ex;
5891 return;
5892 }
5893
5894 if (arith && (exp.checkArithmeticBin() || exp.checkSharedAccessBin(sc)))
5895 return setError();
5896 if ((bitwise || shift) && (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc)))
5897 return setError();
5898
5899 if (shift)
5900 {
5901 if (exp.e2.type.toBasetype().ty != Tvector)
5902 exp.e2 = exp.e2.castTo(sc, Type.tshiftcnt);
5903 }
5904
5905 if (!target.isVectorOpSupported(exp.type.toBasetype(), exp.op, exp.e2.type.toBasetype()))
5906 {
5907 result = exp.incompatibleTypes();
5908 return;
5909 }
5910
5911 if (exp.e1.op == EXP.error || exp.e2.op == EXP.error)
5912 return setError();
5913
5914 e = exp.checkOpAssignTypes(sc);
5915 if (e.op == EXP.error)
5916 {
5917 result = e;
5918 return;
5919 }
5920
5921 assert(e.op == EXP.assign || e == exp);
5922 result = (cast(BinExp)e).reorderSettingAAElem(sc);
5923 }
5924
compileIt(MixinExp exp)5925 private Expression compileIt(MixinExp exp)
5926 {
5927 OutBuffer buf;
5928 if (expressionsToString(buf, sc, exp.exps))
5929 return null;
5930
5931 uint errors = global.errors;
5932 const len = buf.length;
5933 const str = buf.extractChars()[0 .. len];
5934 scope p = new Parser!ASTCodegen(exp.loc, sc._module, str, false);
5935 p.nextToken();
5936 //printf("p.loc.linnum = %d\n", p.loc.linnum);
5937
5938 Expression e = p.parseExpression();
5939 if (global.errors != errors)
5940 return null;
5941
5942 if (p.token.value != TOK.endOfFile)
5943 {
5944 exp.error("incomplete mixin expression `%s`", str.ptr);
5945 return null;
5946 }
5947 return e;
5948 }
5949
visit(MixinExp exp)5950 override void visit(MixinExp exp)
5951 {
5952 /* https://dlang.org/spec/expression.html#mixin_expressions
5953 */
5954
5955 static if (LOGSEMANTIC)
5956 {
5957 printf("MixinExp::semantic('%s')\n", exp.toChars());
5958 }
5959
5960 auto e = compileIt(exp);
5961 if (!e)
5962 return setError();
5963 result = e.expressionSemantic(sc);
5964 }
5965
visit(ImportExp e)5966 override void visit(ImportExp e)
5967 {
5968 static if (LOGSEMANTIC)
5969 {
5970 printf("ImportExp::semantic('%s')\n", e.toChars());
5971 }
5972
5973 auto se = semanticString(sc, e.e1, "file name argument");
5974 if (!se)
5975 return setError();
5976 se = se.toUTF8(sc);
5977
5978 auto namez = se.toStringz().ptr;
5979 if (!global.filePath)
5980 {
5981 e.error("need `-J` switch to import text file `%s`", namez);
5982 return setError();
5983 }
5984
5985 /* Be wary of CWE-22: Improper Limitation of a Pathname to a Restricted Directory
5986 * ('Path Traversal') attacks.
5987 * https://cwe.mitre.org/data/definitions/22.html
5988 */
5989
5990 if (FileName.absolute(namez))
5991 {
5992 e.error("absolute path is not allowed in import expression: `%s`", se.toChars());
5993 return setError();
5994 }
5995
5996 auto idxReserved = FileName.findReservedChar(namez);
5997 if (idxReserved != size_t.max)
5998 {
5999 e.error("`%s` is not a valid filename on this platform", se.toChars());
6000 e.errorSupplemental("Character `'%c'` is reserved and cannot be used", namez[idxReserved]);
6001 return setError();
6002 }
6003
6004 if (FileName.refersToParentDir(namez))
6005 {
6006 e.error("path refers to parent (`..`) directory: `%s`", se.toChars());
6007 return setError();
6008 }
6009
6010 auto name = FileName.searchPath(global.filePath, namez, false);
6011 if (!name)
6012 {
6013 e.error("file `%s` cannot be found or not in a path specified with `-J`", se.toChars());
6014 e.errorSupplemental("Path(s) searched (as provided by `-J`):");
6015 foreach (idx, path; *global.filePath)
6016 {
6017 const attr = FileName.exists(path);
6018 const(char)* err = attr == 2 ? "" :
6019 (attr == 1 ? " (not a directory)" : " (path not found)");
6020 e.errorSupplemental("[%llu]: `%s`%s", cast(ulong)idx, path, err);
6021 }
6022 return setError();
6023 }
6024
6025 sc._module.contentImportedFiles.push(name);
6026 if (global.params.verbose)
6027 {
6028 const slice = se.peekString();
6029 message("file %.*s\t(%s)", cast(int)slice.length, slice.ptr, name);
6030 }
6031 if (global.params.moduleDeps !is null)
6032 {
6033 OutBuffer* ob = global.params.moduleDeps;
6034 Module imod = sc._module;
6035
6036 if (!global.params.moduleDepsFile)
6037 ob.writestring("depsFile ");
6038 ob.writestring(imod.toPrettyChars());
6039 ob.writestring(" (");
6040 escapePath(ob, imod.srcfile.toChars());
6041 ob.writestring(") : ");
6042 if (global.params.moduleDepsFile)
6043 ob.writestring("string : ");
6044 ob.write(se.peekString());
6045 ob.writestring(" (");
6046 escapePath(ob, name);
6047 ob.writestring(")");
6048 ob.writenl();
6049 }
6050 if (global.params.emitMakeDeps)
6051 {
6052 global.params.makeDeps.push(name);
6053 }
6054
6055 {
6056 auto fileName = FileName(name.toDString);
6057 if (auto fmResult = global.fileManager.lookup(fileName))
6058 {
6059 se = new StringExp(e.loc, fmResult);
6060 }
6061 else
6062 {
6063 auto readResult = File.read(name.toDString);
6064 if (!readResult.success)
6065 {
6066 e.error("cannot read file `%s`", name);
6067 return setError();
6068 }
6069 else
6070 {
6071 // take ownership of buffer (probably leaking)
6072 auto data = readResult.extractSlice();
6073 se = new StringExp(e.loc, data);
6074 global.fileManager.add(fileName, data);
6075 }
6076 }
6077 }
6078 result = se.expressionSemantic(sc);
6079 }
6080
visit(AssertExp exp)6081 override void visit(AssertExp exp)
6082 {
6083 // https://dlang.org/spec/expression.html#assert_expressions
6084 static if (LOGSEMANTIC)
6085 {
6086 printf("AssertExp::semantic('%s')\n", exp.toChars());
6087 }
6088
6089 const generateMsg = !exp.msg && global.params.checkAction == CHECKACTION.context && global.params.useAssert == CHECKENABLE.on;
6090 Expression temporariesPrefix;
6091
6092 if (generateMsg)
6093 // no message - use assert expression as msg
6094 {
6095 if (!verifyHookExist(exp.loc, *sc, Id._d_assert_fail, "generating assert messages"))
6096 return setError();
6097
6098 /*
6099 {
6100 auto a = e1, b = e2;
6101 assert(a == b, _d_assert_fail!"=="(a, b));
6102 }()
6103 */
6104
6105 /*
6106 Stores the result of an operand expression into a temporary
6107 if necessary, e.g. if it is an impure fuction call containing side
6108 effects as in https://issues.dlang.org/show_bug.cgi?id=20114
6109
6110 Params:
6111 op = an expression which may require a temporary (added to
6112 `temporariesPrefix`: `auto tmp = op`) and will be replaced
6113 by `tmp` if necessary
6114
6115 Returns: (possibly replaced) `op`
6116 */
6117 Expression maybePromoteToTmp(ref Expression op)
6118 {
6119 // https://issues.dlang.org/show_bug.cgi?id=20989
6120 // Flag that _d_assert_fail will never dereference `array.ptr` to avoid safety
6121 // errors for `assert(!array.ptr)` => `_d_assert_fail!"!"(array.ptr)`
6122 {
6123 auto die = op.isDotIdExp();
6124 if (die && die.ident == Id.ptr)
6125 die.noderef = true;
6126 }
6127
6128 op = op.expressionSemantic(sc);
6129 op = resolveProperties(sc, op);
6130
6131 // Detect assert's using static operator overloads (e.g. `"var" in environment`)
6132 if (auto te = op.isTypeExp())
6133 {
6134 // Replace the TypeExp with it's textual representation
6135 // Including "..." in the error message isn't quite right but
6136 // proper solutions require more drastic changes, e.g. directly
6137 // using miniFormat and combine instead of calling _d_assert_fail
6138 auto name = new StringExp(te.loc, te.toString());
6139 return name.expressionSemantic(sc);
6140 }
6141
6142 // Create a temporary for expressions with side effects
6143 // Defensively assume that function calls may have side effects even
6144 // though it's not detected by hasSideEffect (e.g. `debug puts("Hello")` )
6145 // Rewriting CallExp's also avoids some issues with the inliner/debug generation
6146 if (op.hasSideEffect(true))
6147 {
6148 // Don't create an invalid temporary for void-expressions
6149 // Further semantic will issue an appropriate error
6150 if (op.type.ty == Tvoid)
6151 return op;
6152
6153 // https://issues.dlang.org/show_bug.cgi?id=21590
6154 // Don't create unnecessary temporaries and detect `assert(a = b)`
6155 if (op.isAssignExp() || op.isBinAssignExp())
6156 {
6157 auto left = (cast(BinExp) op).e1;
6158
6159 // Find leftmost expression to handle other rewrites,
6160 // e.g. --(++a) => a += 1 -= 1
6161 while (left.isAssignExp() || left.isBinAssignExp())
6162 left = (cast(BinExp) left).e1;
6163
6164 // Only use the assignee if it's a variable and skip
6165 // other lvalues (e.g. ref's returned by functions)
6166 if (left.isVarExp())
6167 return left;
6168
6169 // Sanity check that `op` can be converted to boolean
6170 // But don't raise errors for assignments enclosed in another expression
6171 if (op is exp.e1)
6172 op.toBoolean(sc);
6173 }
6174
6175 // Tuples with side-effects already receive a temporary during semantic
6176 if (op.type.isTypeTuple())
6177 {
6178 auto te = op.isTupleExp();
6179 assert(te);
6180
6181 // Create a new tuple without the associated temporary
6182 auto res = new TupleExp(op.loc, te.exps);
6183 return res.expressionSemantic(sc);
6184 }
6185
6186 const stc = op.isLvalue() ? STC.ref_ : 0;
6187 auto tmp = copyToTemp(stc, "__assertOp", op);
6188 tmp.dsymbolSemantic(sc);
6189
6190 auto decl = new DeclarationExp(op.loc, tmp);
6191 temporariesPrefix = Expression.combine(temporariesPrefix, decl);
6192
6193 op = new VarExp(op.loc, tmp);
6194 op = op.expressionSemantic(sc);
6195 }
6196 return op;
6197 }
6198
6199 // if the assert condition is a mixin expression, try to compile it
6200 if (auto ce = exp.e1.isMixinExp())
6201 {
6202 if (auto e1 = compileIt(ce))
6203 exp.e1 = e1;
6204 }
6205
6206 Expressions* es;
6207 Objects* tiargs;
6208 Loc loc = exp.e1.loc;
6209
6210 const op = exp.e1.op;
6211 bool isEqualsCallExpression;
6212 if (const callExp = exp.e1.isCallExp())
6213 {
6214 // https://issues.dlang.org/show_bug.cgi?id=20331
6215 // callExp.f may be null if the assert contains a call to
6216 // a function pointer or literal
6217 if (const callExpFunc = callExp.f)
6218 {
6219 const callExpIdent = callExpFunc.ident;
6220 isEqualsCallExpression = callExpIdent == Id.__equals ||
6221 callExpIdent == Id.eq;
6222 }
6223 }
6224 if (op == EXP.equal || op == EXP.notEqual ||
6225 op == EXP.lessThan || op == EXP.greaterThan ||
6226 op == EXP.lessOrEqual || op == EXP.greaterOrEqual ||
6227 op == EXP.identity || op == EXP.notIdentity ||
6228 op == EXP.in_ ||
6229 isEqualsCallExpression)
6230 {
6231 es = new Expressions(3);
6232 tiargs = new Objects(1);
6233
6234 if (isEqualsCallExpression)
6235 {
6236 auto callExp = cast(CallExp) exp.e1;
6237 auto args = callExp.arguments;
6238
6239 // structs with opEquals get rewritten to a DotVarExp:
6240 // a.opEquals(b)
6241 // https://issues.dlang.org/show_bug.cgi?id=20100
6242 if (args.length == 1)
6243 {
6244 auto dv = callExp.e1.isDotVarExp();
6245 assert(dv);
6246
6247 // runtime args
6248 (*es)[1] = maybePromoteToTmp(dv.e1);
6249 (*es)[2] = maybePromoteToTmp((*args)[0]);
6250 }
6251 else
6252 {
6253 // runtime args
6254 (*es)[1] = maybePromoteToTmp((*args)[0]);
6255 (*es)[2] = maybePromoteToTmp((*args)[1]);
6256 }
6257 }
6258 else
6259 {
6260 auto binExp = cast(EqualExp) exp.e1;
6261
6262 // runtime args
6263 (*es)[1] = maybePromoteToTmp(binExp.e1);
6264 (*es)[2] = maybePromoteToTmp(binExp.e2);
6265 }
6266
6267 // template args
6268 Expression comp = new StringExp(loc, isEqualsCallExpression ? "==" : EXPtoString(exp.e1.op));
6269 comp = comp.expressionSemantic(sc);
6270 (*es)[0] = comp;
6271 (*tiargs)[0] = (*es)[1].type;
6272 }
6273
6274 // Format exp.e1 before any additional boolean conversion
6275 // Ignore &&/|| because "assert(...) failed" is more informative than "false != true"
6276 else if (op != EXP.andAnd && op != EXP.orOr)
6277 {
6278 es = new Expressions(2);
6279 tiargs = new Objects(1);
6280
6281 if (auto ne = exp.e1.isNotExp())
6282 {
6283 // Fetch the (potential non-bool) expression and fold
6284 // (n) negations into (n % 2) negations, e.g. !!a => a
6285 for (bool neg = true; ; neg = !neg)
6286 {
6287 if (auto ne2 = ne.e1.isNotExp())
6288 ne = ne2;
6289 else
6290 {
6291 (*es)[0] = new StringExp(loc, neg ? "!" : "");
6292 (*es)[1] = maybePromoteToTmp(ne.e1);
6293 break;
6294 }
6295 }
6296 }
6297 else
6298 { // Simply format exp.e1
6299 (*es)[0] = new StringExp(loc, "");
6300 (*es)[1] = maybePromoteToTmp(exp.e1);
6301 }
6302
6303 (*tiargs)[0] = (*es)[1].type;
6304
6305 // Passing __ctfe to auto ref infers ref and aborts compilation:
6306 // "cannot modify compiler-generated variable __ctfe"
6307 auto ve = (*es)[1].isVarExp();
6308 if (ve && ve.var.ident == Id.ctfe)
6309 {
6310 exp.msg = new StringExp(loc, "assert(__ctfe) failed!");
6311 goto LSkip;
6312 }
6313 }
6314 else
6315 {
6316 OutBuffer buf;
6317 buf.printf("%s failed", exp.toChars());
6318 exp.msg = new StringExp(Loc.initial, buf.extractSlice());
6319 goto LSkip;
6320 }
6321
6322 Expression __assertFail = new IdentifierExp(exp.loc, Id.empty);
6323 auto assertFail = new DotIdExp(loc, __assertFail, Id.object);
6324
6325 auto dt = new DotTemplateInstanceExp(loc, assertFail, Id._d_assert_fail, tiargs);
6326 auto ec = CallExp.create(loc, dt, es);
6327 exp.msg = ec;
6328 }
6329
6330 LSkip:
6331 if (Expression ex = unaSemantic(exp, sc))
6332 {
6333 result = ex;
6334 return;
6335 }
6336
6337 exp.e1 = resolveProperties(sc, exp.e1);
6338 // BUG: see if we can do compile time elimination of the Assert
6339 exp.e1 = exp.e1.optimize(WANTvalue);
6340 exp.e1 = exp.e1.toBoolean(sc);
6341
6342 if (exp.e1.op == EXP.error)
6343 {
6344 result = exp.e1;
6345 return;
6346 }
6347
6348 if (exp.msg)
6349 {
6350 exp.msg = expressionSemantic(exp.msg, sc);
6351 exp.msg = resolveProperties(sc, exp.msg);
6352 exp.msg = exp.msg.implicitCastTo(sc, Type.tchar.constOf().arrayOf());
6353 exp.msg = exp.msg.optimize(WANTvalue);
6354 checkParamArgumentEscape(sc, null, null, exp.msg, true, false);
6355 }
6356
6357 if (exp.msg && exp.msg.op == EXP.error)
6358 {
6359 result = exp.msg;
6360 return;
6361 }
6362
6363 auto f1 = checkNonAssignmentArrayOp(exp.e1);
6364 auto f2 = exp.msg && checkNonAssignmentArrayOp(exp.msg);
6365 if (f1 || f2)
6366 return setError();
6367
6368 if (exp.e1.toBool().hasValue(false))
6369 {
6370 /* This is an `assert(0)` which means halt program execution
6371 */
6372 FuncDeclaration fd = sc.parent.isFuncDeclaration();
6373 if (fd)
6374 fd.hasReturnExp |= 4;
6375 sc.ctorflow.orCSX(CSX.halt);
6376
6377 if (global.params.useAssert == CHECKENABLE.off)
6378 {
6379 Expression e = new HaltExp(exp.loc);
6380 e = e.expressionSemantic(sc);
6381 result = e;
6382 return;
6383 }
6384
6385 // Only override the type when it isn't already some flavour of noreturn,
6386 // e.g. when this assert was generated by defaultInitLiteral
6387 if (!exp.type || !exp.type.isTypeNoreturn())
6388 exp.type = Type.tnoreturn;
6389 }
6390 else
6391 exp.type = Type.tvoid;
6392
6393 result = !temporariesPrefix
6394 ? exp
6395 : Expression.combine(temporariesPrefix, exp).expressionSemantic(sc);
6396 }
6397
visit(ThrowExp te)6398 override void visit(ThrowExp te)
6399 {
6400 import dmd.statementsem;
6401
6402 if (StatementSemanticVisitor.throwSemantic(te.loc, te.e1, sc))
6403 result = te;
6404 else
6405 setError();
6406 }
6407
visit(DotIdExp exp)6408 override void visit(DotIdExp exp)
6409 {
6410 static if (LOGSEMANTIC)
6411 {
6412 printf("DotIdExp::semantic(this = %p, '%s')\n", exp, exp.toChars());
6413 //printf("e1.op = %d, '%s'\n", e1.op, Token.toChars(e1.op));
6414 }
6415
6416 if (sc.flags & SCOPE.Cfile)
6417 {
6418 /* See if need to rewrite the AST because of cast/call ambiguity
6419 */
6420 if (auto e = castCallAmbiguity(exp, sc))
6421 {
6422 result = expressionSemantic(e, sc);
6423 return;
6424 }
6425 }
6426
6427 if (exp.arrow) // ImportC only
6428 exp.e1 = exp.e1.expressionSemantic(sc).arrayFuncConv(sc);
6429
6430 if (sc.flags & SCOPE.Cfile)
6431 {
6432 if (exp.ident == Id.__xalignof && exp.e1.isTypeExp())
6433 {
6434 // C11 6.5.3 says _Alignof only applies to types
6435 Expression e;
6436 Type t;
6437 Dsymbol s;
6438 dmd.typesem.resolve(exp.e1.type, exp.e1.loc, sc, e, t, s, true);
6439 if (e)
6440 {
6441 exp.e1.error("argument to `_Alignof` must be a type");
6442 return setError();
6443 }
6444 else if (t)
6445 {
6446 // Note similarity to getProperty() implementation of __xalignof
6447 const explicitAlignment = t.alignment();
6448 const naturalAlignment = t.alignsize();
6449 const actualAlignment = (explicitAlignment.isDefault() ? naturalAlignment : explicitAlignment.get());
6450 result = new IntegerExp(exp.loc, actualAlignment, Type.tsize_t);
6451 }
6452 else if (s)
6453 {
6454 exp.e1.error("argument to `_Alignof` must be a type");
6455 return setError();
6456 }
6457 else
6458 assert(0);
6459 return;
6460 }
6461 }
6462
6463 if (sc.flags & SCOPE.Cfile && exp.ident != Id.__sizeof)
6464 {
6465 result = fieldLookup(exp.e1, sc, exp.ident);
6466 return;
6467 }
6468
6469 Expression e = exp.semanticY(sc, 1);
6470
6471 if (e && isDotOpDispatch(e))
6472 {
6473 auto ode = e;
6474 uint errors = global.startGagging();
6475 e = resolvePropertiesX(sc, e);
6476 // Any error or if 'e' is not resolved, go to UFCS
6477 if (global.endGagging(errors) || e is ode)
6478 e = null; /* fall down to UFCS */
6479 else
6480 {
6481 result = e;
6482 return;
6483 }
6484 }
6485 if (!e) // if failed to find the property
6486 {
6487 /* If ident is not a valid property, rewrite:
6488 * e1.ident
6489 * as:
6490 * .ident(e1)
6491 */
6492 e = resolveUFCSProperties(sc, exp);
6493 }
6494 result = e;
6495 }
6496
visit(DotTemplateExp e)6497 override void visit(DotTemplateExp e)
6498 {
6499 if (e.type)
6500 {
6501 result = e;
6502 return;
6503 }
6504 if (Expression ex = unaSemantic(e, sc))
6505 {
6506 result = ex;
6507 return;
6508 }
6509 // 'void' like TemplateExp
6510 e.type = Type.tvoid;
6511 result = e;
6512 }
6513
visit(DotVarExp exp)6514 override void visit(DotVarExp exp)
6515 {
6516 static if (LOGSEMANTIC)
6517 {
6518 printf("DotVarExp::semantic('%s')\n", exp.toChars());
6519 }
6520 if (exp.type)
6521 {
6522 result = exp;
6523 return;
6524 }
6525
6526 exp.var = exp.var.toAlias().isDeclaration();
6527
6528 exp.e1 = exp.e1.expressionSemantic(sc);
6529
6530 if (auto tup = exp.var.isTupleDeclaration())
6531 {
6532 /* Replace:
6533 * e1.tuple(a, b, c)
6534 * with:
6535 * tuple(e1.a, e1.b, e1.c)
6536 */
6537 Expression e0;
6538 Expression ev = sc.func ? extractSideEffect(sc, "__tup", e0, exp.e1) : exp.e1;
6539
6540 auto exps = new Expressions();
6541 exps.reserve(tup.objects.dim);
6542 for (size_t i = 0; i < tup.objects.dim; i++)
6543 {
6544 RootObject o = (*tup.objects)[i];
6545 Expression e;
6546 Declaration var;
6547 if (o.dyncast() == DYNCAST.expression)
6548 {
6549 e = cast(Expression)o;
6550 if (auto se = e.isDsymbolExp())
6551 var = se.s.isDeclaration();
6552 else if (auto ve = e.isVarExp())
6553 if (!ve.var.isFuncDeclaration())
6554 // Exempt functions for backwards compatibility reasons.
6555 // See: https://issues.dlang.org/show_bug.cgi?id=20470#c1
6556 var = ve.var;
6557 }
6558 else if (o.dyncast() == DYNCAST.dsymbol)
6559 {
6560 Dsymbol s = cast(Dsymbol) o;
6561 Declaration d = s.isDeclaration();
6562 if (!d || d.isFuncDeclaration())
6563 // Exempt functions for backwards compatibility reasons.
6564 // See: https://issues.dlang.org/show_bug.cgi?id=20470#c1
6565 e = new DsymbolExp(exp.loc, s);
6566 else
6567 var = d;
6568 }
6569 else if (o.dyncast() == DYNCAST.type)
6570 {
6571 e = new TypeExp(exp.loc, cast(Type)o);
6572 }
6573 else
6574 {
6575 exp.error("`%s` is not an expression", o.toChars());
6576 return setError();
6577 }
6578 if (var)
6579 e = new DotVarExp(exp.loc, ev, var);
6580 exps.push(e);
6581 }
6582
6583 Expression e = new TupleExp(exp.loc, e0, exps);
6584 e = e.expressionSemantic(sc);
6585 result = e;
6586 return;
6587 }
6588
6589 exp.e1 = exp.e1.addDtorHook(sc);
6590
6591 Type t1 = exp.e1.type;
6592
6593 if (FuncDeclaration fd = exp.var.isFuncDeclaration())
6594 {
6595 // for functions, do checks after overload resolution
6596 if (!fd.functionSemantic())
6597 return setError();
6598
6599 /* https://issues.dlang.org/show_bug.cgi?id=13843
6600 * If fd obviously has no overloads, we should
6601 * normalize AST, and it will give a chance to wrap fd with FuncExp.
6602 */
6603 if ((fd.isNested() && !fd.isThis()) || fd.isFuncLiteralDeclaration())
6604 {
6605 // (e1, fd)
6606 auto e = symbolToExp(fd, exp.loc, sc, false);
6607 result = Expression.combine(exp.e1, e);
6608 return;
6609 }
6610
6611 exp.type = fd.type;
6612 assert(exp.type);
6613 }
6614 else if (OverDeclaration od = exp.var.isOverDeclaration())
6615 {
6616 exp.type = Type.tvoid; // ambiguous type?
6617 }
6618 else
6619 {
6620 exp.type = exp.var.type;
6621 if (!exp.type && global.errors) // var is goofed up, just return error.
6622 return setError();
6623 assert(exp.type);
6624
6625 if (t1.ty == Tpointer)
6626 t1 = t1.nextOf();
6627
6628 exp.type = exp.type.addMod(t1.mod);
6629
6630 // https://issues.dlang.org/show_bug.cgi?id=23109
6631 // Run semantic on the DotVarExp type
6632 if (auto handle = exp.type.isClassHandle())
6633 {
6634 if (handle.semanticRun < PASS.semanticdone && !handle.isBaseInfoComplete())
6635 handle.dsymbolSemantic(null);
6636 }
6637
6638 Dsymbol vparent = exp.var.toParent();
6639 AggregateDeclaration ad = vparent ? vparent.isAggregateDeclaration() : null;
6640 if (Expression e1x = getRightThis(exp.loc, sc, ad, exp.e1, exp.var, 1))
6641 exp.e1 = e1x;
6642 else
6643 {
6644 /* Later checkRightThis will report correct error for invalid field variable access.
6645 */
6646 Expression e = new VarExp(exp.loc, exp.var);
6647 e = e.expressionSemantic(sc);
6648 result = e;
6649 return;
6650 }
6651 checkAccess(exp.loc, sc, exp.e1, exp.var);
6652
6653 VarDeclaration v = exp.var.isVarDeclaration();
6654 if (v && (v.isDataseg() || (v.storage_class & STC.manifest)))
6655 {
6656 Expression e = expandVar(WANTvalue, v);
6657 if (e)
6658 {
6659 result = e;
6660 return;
6661 }
6662 }
6663
6664 if (v && (v.isDataseg() || // fix https://issues.dlang.org/show_bug.cgi?id=8238
6665 (!v.needThis() && v.semanticRun > PASS.initial))) // fix https://issues.dlang.org/show_bug.cgi?id=17258
6666 {
6667 // (e1, v)
6668 checkAccess(exp.loc, sc, exp.e1, v);
6669 Expression e = new VarExp(exp.loc, v);
6670 e = new CommaExp(exp.loc, exp.e1, e);
6671 e = e.expressionSemantic(sc);
6672 result = e;
6673 return;
6674 }
6675 }
6676 //printf("-DotVarExp::semantic('%s')\n", toChars());
6677 result = exp;
6678 }
6679
visit(DotTemplateInstanceExp exp)6680 override void visit(DotTemplateInstanceExp exp)
6681 {
6682 static if (LOGSEMANTIC)
6683 {
6684 printf("DotTemplateInstanceExp::semantic('%s')\n", exp.toChars());
6685 }
6686 if (exp.type)
6687 {
6688 result = exp;
6689 return;
6690 }
6691 // Indicate we need to resolve by UFCS.
6692 Expression e = exp.semanticY(sc, 1);
6693 if (!e)
6694 e = resolveUFCSProperties(sc, exp);
6695 if (e is exp)
6696 e.type = Type.tvoid; // Unresolved type, because it needs inference
6697 result = e;
6698 }
6699
visit(DelegateExp e)6700 override void visit(DelegateExp e)
6701 {
6702 static if (LOGSEMANTIC)
6703 {
6704 printf("DelegateExp::semantic('%s')\n", e.toChars());
6705 }
6706 if (e.type)
6707 {
6708 result = e;
6709 return;
6710 }
6711
6712 e.e1 = e.e1.expressionSemantic(sc);
6713
6714 e.type = new TypeDelegate(e.func.type.isTypeFunction());
6715 e.type = e.type.typeSemantic(e.loc, sc);
6716
6717 FuncDeclaration f = e.func.toAliasFunc();
6718 AggregateDeclaration ad = f.toParentLocal().isAggregateDeclaration();
6719 if (f.needThis())
6720 e.e1 = getRightThis(e.loc, sc, ad, e.e1, f);
6721 if (e.e1.op == EXP.error)
6722 return setError();
6723
6724 /* A delegate takes the address of e.e1 in order to set the .ptr field
6725 * https://issues.dlang.org/show_bug.cgi?id=18575
6726 */
6727 if (global.params.useDIP1000 == FeatureState.enabled && e.e1.type.toBasetype().ty == Tstruct)
6728 {
6729 if (auto v = expToVariable(e.e1))
6730 {
6731 if (!checkAddressVar(sc, e.e1, v))
6732 return setError();
6733 }
6734 }
6735
6736 if (f.type.ty == Tfunction)
6737 {
6738 TypeFunction tf = cast(TypeFunction)f.type;
6739 if (!MODmethodConv(e.e1.type.mod, f.type.mod))
6740 {
6741 OutBuffer thisBuf, funcBuf;
6742 MODMatchToBuffer(&thisBuf, e.e1.type.mod, tf.mod);
6743 MODMatchToBuffer(&funcBuf, tf.mod, e.e1.type.mod);
6744 e.error("%smethod `%s` is not callable using a %s`%s`",
6745 funcBuf.peekChars(), f.toPrettyChars(), thisBuf.peekChars(), e.e1.toChars());
6746 return setError();
6747 }
6748 }
6749 if (ad && ad.isClassDeclaration() && ad.type != e.e1.type)
6750 {
6751 // A downcast is required for interfaces
6752 // https://issues.dlang.org/show_bug.cgi?id=3706
6753 e.e1 = new CastExp(e.loc, e.e1, ad.type);
6754 e.e1 = e.e1.expressionSemantic(sc);
6755 }
6756 result = e;
6757 // declare dual-context container
6758 if (f.hasDualContext() && !sc.intypeof && sc.func)
6759 {
6760 // check access to second `this`
6761 if (AggregateDeclaration ad2 = f.isMember2())
6762 {
6763 Expression te = new ThisExp(e.loc).expressionSemantic(sc);
6764 if (te.op != EXP.error)
6765 te = getRightThis(e.loc, sc, ad2, te, f);
6766 if (te.op == EXP.error)
6767 {
6768 e.error("need `this` of type `%s` to make delegate from function `%s`", ad2.toChars(), f.toChars());
6769 return setError();
6770 }
6771 }
6772 VarDeclaration vthis2 = makeThis2Argument(e.loc, sc, f);
6773 e.vthis2 = vthis2;
6774 Expression de = new DeclarationExp(e.loc, vthis2);
6775 result = Expression.combine(de, result);
6776 result = result.expressionSemantic(sc);
6777 }
6778 }
6779
visit(DotTypeExp exp)6780 override void visit(DotTypeExp exp)
6781 {
6782 static if (LOGSEMANTIC)
6783 {
6784 printf("DotTypeExp::semantic('%s')\n", exp.toChars());
6785 }
6786 if (exp.type)
6787 {
6788 result = exp;
6789 return;
6790 }
6791
6792 if (auto e = unaSemantic(exp, sc))
6793 {
6794 result = e;
6795 return;
6796 }
6797
6798 exp.type = exp.sym.getType().addMod(exp.e1.type.mod);
6799 result = exp;
6800 }
6801
visit(AddrExp exp)6802 override void visit(AddrExp exp)
6803 {
6804 static if (LOGSEMANTIC)
6805 {
6806 printf("AddrExp::semantic('%s')\n", exp.toChars());
6807 }
6808 if (exp.type)
6809 {
6810 result = exp;
6811 return;
6812 }
6813
6814 if (Expression ex = unaSemantic(exp, sc))
6815 {
6816 result = ex;
6817 return;
6818 }
6819
6820 if (sc.flags & SCOPE.Cfile)
6821 {
6822 /* Special handling for &"string"
6823 * since C regards a string literal as an lvalue
6824 */
6825 if (auto se = exp.e1.isStringExp())
6826 {
6827 if (auto tp = se.type.toBasetype().isTypePointer())
6828 {
6829 /* Switch from pointer-to-char to pointer-to-static-array-of-char
6830 */
6831 auto ts = new TypeSArray(tp.nextOf(), new IntegerExp(Loc.initial, se.len + 1, Type.tsize_t));
6832 se.type = typeSemantic(ts, Loc.initial, sc).pointerTo();
6833 result = se;
6834 return;
6835 }
6836 }
6837 }
6838
6839 int wasCond = exp.e1.op == EXP.question;
6840
6841 if (exp.e1.op == EXP.dotTemplateInstance)
6842 {
6843 DotTemplateInstanceExp dti = cast(DotTemplateInstanceExp)exp.e1;
6844 TemplateInstance ti = dti.ti;
6845 {
6846 //assert(ti.needsTypeInference(sc));
6847 ti.dsymbolSemantic(sc);
6848 if (!ti.inst || ti.errors) // if template failed to expand
6849 return setError();
6850
6851 Dsymbol s = ti.toAlias();
6852 FuncDeclaration f = s.isFuncDeclaration();
6853 if (f)
6854 {
6855 exp.e1 = new DotVarExp(exp.e1.loc, dti.e1, f);
6856 exp.e1 = exp.e1.expressionSemantic(sc);
6857 }
6858 }
6859 }
6860 else if (exp.e1.op == EXP.scope_)
6861 {
6862 TemplateInstance ti = (cast(ScopeExp)exp.e1).sds.isTemplateInstance();
6863 if (ti)
6864 {
6865 //assert(ti.needsTypeInference(sc));
6866 ti.dsymbolSemantic(sc);
6867 if (!ti.inst || ti.errors) // if template failed to expand
6868 return setError();
6869
6870 Dsymbol s = ti.toAlias();
6871 FuncDeclaration f = s.isFuncDeclaration();
6872 if (f)
6873 {
6874 exp.e1 = new VarExp(exp.e1.loc, f);
6875 exp.e1 = exp.e1.expressionSemantic(sc);
6876 }
6877 }
6878 }
6879 /* https://issues.dlang.org/show_bug.cgi?id=809
6880 *
6881 * If the address of a lazy variable is taken,
6882 * the expression is rewritten so that the type
6883 * of it is the delegate type. This means that
6884 * the symbol is not going to represent a call
6885 * to the delegate anymore, but rather, the
6886 * actual symbol.
6887 */
6888 if (auto ve = exp.e1.isVarExp())
6889 {
6890 if (ve.var.storage_class & STC.lazy_)
6891 {
6892 exp.e1 = exp.e1.expressionSemantic(sc);
6893 exp.e1 = resolveProperties(sc, exp.e1);
6894 if (auto callExp = exp.e1.isCallExp())
6895 {
6896 if (callExp.e1.type.toBasetype().ty == Tdelegate)
6897 {
6898 /* https://issues.dlang.org/show_bug.cgi?id=20551
6899 *
6900 * Cannot take address of lazy parameter in @safe code
6901 * because it might end up being a pointer to undefined
6902 * memory.
6903 */
6904 if (sc.func && !sc.intypeof && !(sc.flags & SCOPE.debug_) && sc.func.setUnsafe())
6905 {
6906 exp.error("cannot take address of lazy parameter `%s` in `@safe` function `%s`",
6907 ve.toChars(), sc.func.toChars());
6908 setError();
6909 }
6910 else
6911 {
6912 VarExp ve2 = callExp.e1.isVarExp();
6913 ve2.delegateWasExtracted = true;
6914 ve2.var.storage_class |= STC.scope_;
6915 result = ve2;
6916 }
6917 return;
6918 }
6919 }
6920 }
6921 }
6922
6923 exp.e1 = exp.e1.toLvalue(sc, null);
6924 if (exp.e1.op == EXP.error)
6925 {
6926 result = exp.e1;
6927 return;
6928 }
6929 if (checkNonAssignmentArrayOp(exp.e1))
6930 return setError();
6931
6932 if (!exp.e1.type)
6933 {
6934 exp.error("cannot take address of `%s`", exp.e1.toChars());
6935 return setError();
6936 }
6937 if (auto dve = exp.e1.isDotVarExp())
6938 {
6939 /* https://issues.dlang.org/show_bug.cgi?id=22749
6940 * Error about taking address of any bit-field, regardless of
6941 * whether SCOPE.Cfile is set.
6942 */
6943 if (auto bf = dve.var.isBitFieldDeclaration())
6944 {
6945 exp.error("cannot take address of bit-field `%s`", bf.toChars());
6946 return setError();
6947 }
6948 }
6949
6950 bool hasOverloads;
6951 if (auto f = isFuncAddress(exp, &hasOverloads))
6952 {
6953 if (!hasOverloads && f.checkForwardRef(exp.loc))
6954 return setError();
6955 }
6956 else if (!exp.e1.type.deco)
6957 {
6958 // try to resolve the type
6959 exp.e1.type = exp.e1.type.typeSemantic(exp.e1.loc, null);
6960 if (!exp.e1.type.deco) // still couldn't resolve it
6961 {
6962 if (auto ve = exp.e1.isVarExp())
6963 {
6964 Declaration d = ve.var;
6965 exp.error("forward reference to %s `%s`", d.kind(), d.toChars());
6966 }
6967 else
6968 exp.error("forward reference to type `%s` of expression `%s`", exp.e1.type.toChars(), exp.e1.toChars());
6969 return setError();
6970 }
6971 }
6972
6973 exp.type = exp.e1.type.pointerTo();
6974
6975 // See if this should really be a delegate
6976 if (exp.e1.op == EXP.dotVariable)
6977 {
6978 DotVarExp dve = cast(DotVarExp)exp.e1;
6979 FuncDeclaration f = dve.var.isFuncDeclaration();
6980 if (f)
6981 {
6982 f = f.toAliasFunc(); // FIXME, should see overloads
6983 // https://issues.dlang.org/show_bug.cgi?id=1983
6984 if (!dve.hasOverloads)
6985 f.tookAddressOf++;
6986
6987 Expression e;
6988 if (f.needThis())
6989 e = new DelegateExp(exp.loc, dve.e1, f, dve.hasOverloads);
6990 else // It is a function pointer. Convert &v.f() --> (v, &V.f())
6991 e = new CommaExp(exp.loc, dve.e1, new AddrExp(exp.loc, new VarExp(exp.loc, f, dve.hasOverloads)));
6992 e = e.expressionSemantic(sc);
6993 result = e;
6994 return;
6995 }
6996
6997 // Look for misaligned pointer in @safe mode
6998 if (checkUnsafeAccess(sc, dve, !exp.type.isMutable(), true))
6999 return setError();
7000
7001 if (global.params.useDIP1000 == FeatureState.enabled)
7002 {
7003 if (VarDeclaration v = expToVariable(dve.e1))
7004 {
7005 if (!checkAddressVar(sc, exp.e1, v))
7006 return setError();
7007 }
7008 }
7009 }
7010 else if (exp.e1.op == EXP.variable)
7011 {
7012 VarExp ve = cast(VarExp)exp.e1;
7013 VarDeclaration v = ve.var.isVarDeclaration();
7014 if (v)
7015 {
7016 if (!checkAddressVar(sc, exp.e1, v))
7017 return setError();
7018
7019 ve.checkPurity(sc, v);
7020 }
7021 FuncDeclaration f = ve.var.isFuncDeclaration();
7022 if (f)
7023 {
7024 /* Because nested functions cannot be overloaded,
7025 * mark here that we took its address because castTo()
7026 * may not be called with an exact match.
7027 */
7028 if (!ve.hasOverloads || (f.isNested() && !f.needThis()))
7029 f.tookAddressOf++;
7030 if (f.isNested() && !f.needThis())
7031 {
7032 if (f.isFuncLiteralDeclaration())
7033 {
7034 if (!f.FuncDeclaration.isNested())
7035 {
7036 /* Supply a 'null' for a this pointer if no this is available
7037 */
7038 Expression e = new DelegateExp(exp.loc, new NullExp(exp.loc, Type.tnull), f, ve.hasOverloads);
7039 e = e.expressionSemantic(sc);
7040 result = e;
7041 return;
7042 }
7043 }
7044 Expression e = new DelegateExp(exp.loc, exp.e1, f, ve.hasOverloads);
7045 e = e.expressionSemantic(sc);
7046 result = e;
7047 return;
7048 }
7049 if (f.needThis())
7050 {
7051 if (hasThis(sc))
7052 {
7053 /* Should probably supply 'this' after overload resolution,
7054 * not before.
7055 */
7056 Expression ethis = new ThisExp(exp.loc);
7057 Expression e = new DelegateExp(exp.loc, ethis, f, ve.hasOverloads);
7058 e = e.expressionSemantic(sc);
7059 result = e;
7060 return;
7061 }
7062 if (sc.func && !sc.intypeof)
7063 {
7064 if (!(sc.flags & SCOPE.debug_) && sc.func.setUnsafe())
7065 {
7066 exp.error("`this` reference necessary to take address of member `%s` in `@safe` function `%s`", f.toChars(), sc.func.toChars());
7067 }
7068 }
7069 }
7070 }
7071 }
7072 else if ((exp.e1.op == EXP.this_ || exp.e1.op == EXP.super_) && global.params.useDIP1000 == FeatureState.enabled)
7073 {
7074 if (VarDeclaration v = expToVariable(exp.e1))
7075 {
7076 if (!checkAddressVar(sc, exp.e1, v))
7077 return setError();
7078 }
7079 }
7080 else if (auto ce = exp.e1.isCallExp())
7081 {
7082 if (!checkAddressCall(sc, ce, "take address of"))
7083 return setError();
7084 }
7085 else if (exp.e1.op == EXP.index)
7086 {
7087 /* For:
7088 * int[3] a;
7089 * &a[i]
7090 * check 'a' the same as for a regular variable
7091 */
7092 if (VarDeclaration v = expToVariable(exp.e1))
7093 {
7094 if (global.params.useDIP1000 == FeatureState.enabled && !checkAddressVar(sc, exp.e1, v))
7095 return setError();
7096
7097 exp.e1.checkPurity(sc, v);
7098 }
7099 }
7100 else if (wasCond)
7101 {
7102 /* a ? b : c was transformed to *(a ? &b : &c), but we still
7103 * need to do safety checks
7104 */
7105 assert(exp.e1.op == EXP.star);
7106 PtrExp pe = cast(PtrExp)exp.e1;
7107 assert(pe.e1.op == EXP.question);
7108 CondExp ce = cast(CondExp)pe.e1;
7109 assert(ce.e1.op == EXP.address);
7110 assert(ce.e2.op == EXP.address);
7111
7112 // Re-run semantic on the address expressions only
7113 ce.e1.type = null;
7114 ce.e1 = ce.e1.expressionSemantic(sc);
7115 ce.e2.type = null;
7116 ce.e2 = ce.e2.expressionSemantic(sc);
7117 }
7118 result = exp.optimize(WANTvalue);
7119 }
7120
visit(PtrExp exp)7121 override void visit(PtrExp exp)
7122 {
7123 static if (LOGSEMANTIC)
7124 {
7125 printf("PtrExp::semantic('%s')\n", exp.toChars());
7126 }
7127 if (exp.type)
7128 {
7129 result = exp;
7130 return;
7131 }
7132
7133 Expression e = exp.op_overload(sc);
7134 if (e)
7135 {
7136 result = e;
7137 return;
7138 }
7139
7140 exp.e1 = exp.e1.arrayFuncConv(sc);
7141
7142 Type tb = exp.e1.type.toBasetype();
7143 switch (tb.ty)
7144 {
7145 case Tpointer:
7146 exp.type = (cast(TypePointer)tb).next;
7147 break;
7148
7149 case Tsarray:
7150 case Tarray:
7151 if (isNonAssignmentArrayOp(exp.e1))
7152 goto default;
7153 exp.error("using `*` on an array is no longer supported; use `*(%s).ptr` instead", exp.e1.toChars());
7154 exp.type = (cast(TypeArray)tb).next;
7155 exp.e1 = exp.e1.castTo(sc, exp.type.pointerTo());
7156 break;
7157
7158 case Terror:
7159 return setError();
7160
7161 case Tnull:
7162 exp.type = Type.tnoreturn; // typeof(*null) is bottom type
7163 break;
7164
7165 default:
7166 exp.error("can only `*` a pointer, not a `%s`", exp.e1.type.toChars());
7167 goto case Terror;
7168 }
7169
7170 if (exp.checkValue())
7171 return setError();
7172
7173 result = exp;
7174 }
7175
visit(NegExp exp)7176 override void visit(NegExp exp)
7177 {
7178 static if (LOGSEMANTIC)
7179 {
7180 printf("NegExp::semantic('%s')\n", exp.toChars());
7181 }
7182 if (exp.type)
7183 {
7184 result = exp;
7185 return;
7186 }
7187
7188 Expression e = exp.op_overload(sc);
7189 if (e)
7190 {
7191 result = e;
7192 return;
7193 }
7194
7195 fix16997(sc, exp);
7196 exp.type = exp.e1.type;
7197 Type tb = exp.type.toBasetype();
7198 if (tb.ty == Tarray || tb.ty == Tsarray)
7199 {
7200 if (!isArrayOpValid(exp.e1))
7201 {
7202 result = arrayOpInvalidError(exp);
7203 return;
7204 }
7205 result = exp;
7206 return;
7207 }
7208 if (!target.isVectorOpSupported(tb, exp.op))
7209 {
7210 result = exp.incompatibleTypes();
7211 return;
7212 }
7213 if (exp.e1.checkNoBool())
7214 return setError();
7215 if (exp.e1.checkArithmetic() ||
7216 exp.e1.checkSharedAccess(sc))
7217 return setError();
7218
7219 result = exp;
7220 }
7221
visit(UAddExp exp)7222 override void visit(UAddExp exp)
7223 {
7224 static if (LOGSEMANTIC)
7225 {
7226 printf("UAddExp::semantic('%s')\n", exp.toChars());
7227 }
7228 assert(!exp.type);
7229
7230 Expression e = exp.op_overload(sc);
7231 if (e)
7232 {
7233 result = e;
7234 return;
7235 }
7236
7237 fix16997(sc, exp);
7238 if (!target.isVectorOpSupported(exp.e1.type.toBasetype(), exp.op))
7239 {
7240 result = exp.incompatibleTypes();
7241 return;
7242 }
7243 if (exp.e1.checkNoBool())
7244 return setError();
7245 if (exp.e1.checkArithmetic())
7246 return setError();
7247 if (exp.e1.checkSharedAccess(sc))
7248 return setError();
7249
7250 result = exp.e1;
7251 }
7252
visit(ComExp exp)7253 override void visit(ComExp exp)
7254 {
7255 if (exp.type)
7256 {
7257 result = exp;
7258 return;
7259 }
7260
7261 Expression e = exp.op_overload(sc);
7262 if (e)
7263 {
7264 result = e;
7265 return;
7266 }
7267
7268 fix16997(sc, exp);
7269 exp.type = exp.e1.type;
7270 Type tb = exp.type.toBasetype();
7271 if (tb.ty == Tarray || tb.ty == Tsarray)
7272 {
7273 if (!isArrayOpValid(exp.e1))
7274 {
7275 result = arrayOpInvalidError(exp);
7276 return;
7277 }
7278 result = exp;
7279 return;
7280 }
7281 if (!target.isVectorOpSupported(tb, exp.op))
7282 {
7283 result = exp.incompatibleTypes();
7284 return;
7285 }
7286 if (exp.e1.checkNoBool())
7287 return setError();
7288 if (exp.e1.checkIntegral() ||
7289 exp.e1.checkSharedAccess(sc))
7290 return setError();
7291
7292 result = exp;
7293 }
7294
visit(NotExp e)7295 override void visit(NotExp e)
7296 {
7297 if (e.type)
7298 {
7299 result = e;
7300 return;
7301 }
7302
7303 e.setNoderefOperand();
7304
7305 // Note there is no operator overload
7306 if (Expression ex = unaSemantic(e, sc))
7307 {
7308 result = ex;
7309 return;
7310 }
7311
7312 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
7313 if (e.e1.op == EXP.type)
7314 e.e1 = resolveAliasThis(sc, e.e1);
7315
7316 e.e1 = resolveProperties(sc, e.e1);
7317 e.e1 = e.e1.toBoolean(sc);
7318 if (e.e1.type == Type.terror)
7319 {
7320 result = e.e1;
7321 return;
7322 }
7323
7324 if (!target.isVectorOpSupported(e.e1.type.toBasetype(), e.op))
7325 {
7326 result = e.incompatibleTypes();
7327 }
7328 // https://issues.dlang.org/show_bug.cgi?id=13910
7329 // Today NotExp can take an array as its operand.
7330 if (checkNonAssignmentArrayOp(e.e1))
7331 return setError();
7332
7333 e.type = (sc && sc.flags & SCOPE.Cfile) ? Type.tint32 : Type.tbool;
7334 result = e;
7335 }
7336
visit(DeleteExp exp)7337 override void visit(DeleteExp exp)
7338 {
7339 // @@@DEPRECATED_2.109@@@
7340 // 1. Deprecated since 2.079
7341 // 2. Error since 2.099
7342 // 3. Removal of keyword, "delete" can be used for other identities
7343 if (!exp.isRAII)
7344 {
7345 error(exp.loc, "the `delete` keyword is obsolete");
7346 errorSupplemental(exp.loc, "use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead");
7347 return setError();
7348 }
7349
7350 Expression e = exp;
7351
7352 if (Expression ex = unaSemantic(exp, sc))
7353 {
7354 result = ex;
7355 return;
7356 }
7357 exp.e1 = resolveProperties(sc, exp.e1);
7358 exp.e1 = exp.e1.modifiableLvalue(sc, null);
7359 if (exp.e1.op == EXP.error)
7360 {
7361 result = exp.e1;
7362 return;
7363 }
7364 exp.type = Type.tvoid;
7365
7366 Type tb = exp.e1.type.toBasetype();
7367
7368 /* Now that `delete` in user code is an error, we only get here when
7369 * `isRAII` has been set to true for the deletion of a `scope class`. */
7370 if (tb.ty != Tclass)
7371 {
7372 exp.error("cannot delete type `%s`", exp.e1.type.toChars());
7373 return setError();
7374 }
7375
7376 ClassDeclaration cd = (cast(TypeClass)tb).sym;
7377 if (cd.isCOMinterface())
7378 {
7379 /* Because COM classes are deleted by IUnknown.Release()
7380 */
7381 exp.error("cannot `delete` instance of COM interface `%s`", cd.toChars());
7382 return setError();
7383 }
7384
7385 bool err = false;
7386 if (cd.dtor)
7387 {
7388 err |= !cd.dtor.functionSemantic();
7389 err |= exp.checkPurity(sc, cd.dtor);
7390 err |= exp.checkSafety(sc, cd.dtor);
7391 err |= exp.checkNogc(sc, cd.dtor);
7392 }
7393 if (err)
7394 return setError();
7395
7396 result = e;
7397 }
7398
visit(CastExp exp)7399 override void visit(CastExp exp)
7400 {
7401 static if (LOGSEMANTIC)
7402 {
7403 printf("CastExp::semantic('%s')\n", exp.toChars());
7404 }
7405 //static int x; assert(++x < 10);
7406 if (exp.type)
7407 {
7408 result = exp;
7409 return;
7410 }
7411
7412 if ((sc && sc.flags & SCOPE.Cfile) &&
7413 exp.to && (exp.to.ty == Tident || exp.to.ty == Tsarray) &&
7414 (exp.e1.op == EXP.address || exp.e1.op == EXP.star ||
7415 exp.e1.op == EXP.uadd || exp.e1.op == EXP.negate))
7416 {
7417 /* Ambiguous cases arise from CParser if type-name is just an identifier.
7418 * ( identifier ) cast-expression
7419 * ( identifier [expression]) cast-expression
7420 * If we determine that `identifier` is a variable, and cast-expression
7421 * is one of the unary operators (& * + -), then rewrite this cast
7422 * as a binary expression.
7423 */
7424 Loc loc = exp.loc;
7425 Type t;
7426 Expression e;
7427 Dsymbol s;
7428 exp.to.resolve(loc, sc, e, t, s);
7429 if (e !is null)
7430 {
7431 if (auto ex = exp.e1.isAddrExp()) // (ident) &exp -> (ident & exp)
7432 result = new AndExp(loc, e, ex.e1);
7433 else if (auto ex = exp.e1.isPtrExp()) // (ident) *exp -> (ident * exp)
7434 result = new MulExp(loc, e, ex.e1);
7435 else if (auto ex = exp.e1.isUAddExp()) // (ident) +exp -> (ident + exp)
7436 result = new AddExp(loc, e, ex.e1);
7437 else if (auto ex = exp.e1.isNegExp()) // (ident) -exp -> (ident - exp)
7438 result = new MinExp(loc, e, ex.e1);
7439
7440 assert(result);
7441 result = result.expressionSemantic(sc);
7442 return;
7443 }
7444 }
7445
7446 if (exp.to)
7447 {
7448 exp.to = exp.to.typeSemantic(exp.loc, sc);
7449 if (exp.to == Type.terror)
7450 return setError();
7451
7452 if (!exp.to.hasPointers())
7453 exp.setNoderefOperand();
7454
7455 // When e1 is a template lambda, this cast may instantiate it with
7456 // the type 'to'.
7457 exp.e1 = inferType(exp.e1, exp.to);
7458 }
7459
7460 if (auto e = unaSemantic(exp, sc))
7461 {
7462 result = e;
7463 return;
7464 }
7465
7466 if (exp.to && !exp.to.isTypeSArray() && !exp.to.isTypeFunction())
7467 exp.e1 = exp.e1.arrayFuncConv(sc);
7468
7469 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
7470 if (exp.e1.op == EXP.type)
7471 exp.e1 = resolveAliasThis(sc, exp.e1);
7472
7473 auto e1x = resolveProperties(sc, exp.e1);
7474 if (e1x.op == EXP.error)
7475 {
7476 result = e1x;
7477 return;
7478 }
7479 if (e1x.checkType())
7480 return setError();
7481 exp.e1 = e1x;
7482
7483 if (!exp.e1.type)
7484 {
7485 exp.error("cannot cast `%s`", exp.e1.toChars());
7486 return setError();
7487 }
7488
7489 // https://issues.dlang.org/show_bug.cgi?id=19954
7490 if (exp.e1.type.ty == Ttuple)
7491 {
7492 if (exp.to)
7493 {
7494 if (TypeTuple tt = exp.to.isTypeTuple())
7495 {
7496 if (exp.e1.type.implicitConvTo(tt))
7497 {
7498 result = exp.e1.castTo(sc, tt);
7499 return;
7500 }
7501 }
7502 }
7503 TupleExp te = exp.e1.isTupleExp();
7504 if (te.exps.dim == 1)
7505 exp.e1 = (*te.exps)[0];
7506 }
7507
7508 // only allow S(x) rewrite if cast specified S explicitly.
7509 // See https://issues.dlang.org/show_bug.cgi?id=18545
7510 const bool allowImplicitConstruction = exp.to !is null;
7511
7512 if (!exp.to) // Handle cast(const) and cast(immutable), etc.
7513 {
7514 exp.to = exp.e1.type.castMod(exp.mod);
7515 exp.to = exp.to.typeSemantic(exp.loc, sc);
7516
7517 if (exp.to == Type.terror)
7518 return setError();
7519 }
7520
7521 if (exp.to.ty == Ttuple)
7522 {
7523 exp.error("cannot cast `%s` of type `%s` to tuple type `%s`", exp.e1.toChars(), exp.e1.type.toChars(), exp.to.toChars());
7524 return setError();
7525 }
7526
7527 // cast(void) is used to mark e1 as unused, so it is safe
7528 if (exp.to.ty == Tvoid)
7529 {
7530 exp.type = exp.to;
7531 result = exp;
7532 return;
7533 }
7534
7535 if (!exp.to.equals(exp.e1.type) && exp.mod == cast(ubyte)~0)
7536 {
7537 if (Expression e = exp.op_overload(sc))
7538 {
7539 result = e.implicitCastTo(sc, exp.to);
7540 return;
7541 }
7542 }
7543
7544 Type t1b = exp.e1.type.toBasetype();
7545 Type tob = exp.to.toBasetype();
7546
7547 if (allowImplicitConstruction && tob.ty == Tstruct && !tob.equals(t1b))
7548 {
7549 /* Look to replace:
7550 * cast(S)t
7551 * with:
7552 * S(t)
7553 */
7554
7555 // Rewrite as to.call(e1)
7556 Expression e = new TypeExp(exp.loc, exp.to);
7557 e = new CallExp(exp.loc, e, exp.e1);
7558 e = e.trySemantic(sc);
7559 if (e)
7560 {
7561 result = e;
7562 return;
7563 }
7564 }
7565
7566 if (!t1b.equals(tob) && (t1b.ty == Tarray || t1b.ty == Tsarray))
7567 {
7568 if (checkNonAssignmentArrayOp(exp.e1))
7569 return setError();
7570 }
7571
7572 // Look for casting to a vector type
7573 if (tob.ty == Tvector && t1b.ty != Tvector)
7574 {
7575 result = new VectorExp(exp.loc, exp.e1, exp.to);
7576 result = result.expressionSemantic(sc);
7577 return;
7578 }
7579
7580 Expression ex = exp.e1.castTo(sc, exp.to);
7581 if (ex.op == EXP.error)
7582 {
7583 result = ex;
7584 return;
7585 }
7586
7587 // Check for unsafe casts
7588 if (!sc.intypeof &&
7589 !(sc.flags & SCOPE.debug_) &&
7590 !isSafeCast(ex, t1b, tob) &&
7591 (!sc.func && sc.stc & STC.safe || sc.func && sc.func.setUnsafe()))
7592 {
7593 exp.error("cast from `%s` to `%s` not allowed in safe code", exp.e1.type.toChars(), exp.to.toChars());
7594 return setError();
7595 }
7596
7597 // `object.__ArrayCast` is a rewrite of an old runtime hook `_d_arraycast`. `_d_arraycast` was not built
7598 // to handle certain casts. Those casts which `object.__ArrayCast` does not support are filtered out.
7599 // See `e2ir.toElemCast` for other types of casts. If `object.__ArrayCast` is improved to support more
7600 // casts these conditions and potentially some logic in `e2ir.toElemCast` can be removed.
7601 if (tob.ty == Tarray)
7602 {
7603 // https://issues.dlang.org/show_bug.cgi?id=19840
7604 if (auto ad = isAggregate(t1b))
7605 {
7606 if (ad.aliasthis)
7607 {
7608 Expression e = resolveAliasThis(sc, exp.e1);
7609 e = new CastExp(exp.loc, e, exp.to);
7610 result = e.expressionSemantic(sc);
7611 return;
7612 }
7613 }
7614
7615 if(t1b.ty == Tarray && exp.e1.op != EXP.arrayLiteral && (sc.flags & SCOPE.ctfe) == 0)
7616 {
7617 auto tFrom = t1b.nextOf();
7618 auto tTo = tob.nextOf();
7619
7620 // https://issues.dlang.org/show_bug.cgi?id=20130
7621 if (exp.e1.op != EXP.string_ || !ex.isStringExp)
7622 {
7623 const uint fromSize = cast(uint)tFrom.size();
7624 const uint toSize = cast(uint)tTo.size();
7625 if (fromSize == SIZE_INVALID || toSize == SIZE_INVALID)
7626 return setError();
7627
7628 // If array element sizes do not match, we must adjust the dimensions
7629 if (fromSize != toSize)
7630 {
7631 if (!verifyHookExist(exp.loc, *sc, Id.__ArrayCast, "casting array of structs"))
7632 return setError();
7633
7634 // A runtime check is needed in case arrays don't line up. That check should
7635 // be done in the implementation of `object.__ArrayCast`
7636 if (toSize == 0 || (fromSize % toSize) != 0)
7637 {
7638 // lower to `object.__ArrayCast!(TFrom, TTo)(from)`
7639
7640 // fully qualify as `object.__ArrayCast`
7641 Expression id = new IdentifierExp(exp.loc, Id.empty);
7642 auto dotid = new DotIdExp(exp.loc, id, Id.object);
7643
7644 auto tiargs = new Objects();
7645 tiargs.push(tFrom);
7646 tiargs.push(tTo);
7647 auto dt = new DotTemplateInstanceExp(exp.loc, dotid, Id.__ArrayCast, tiargs);
7648
7649 auto arguments = new Expressions();
7650 arguments.push(exp.e1);
7651 Expression ce = new CallExp(exp.loc, dt, arguments);
7652
7653 result = expressionSemantic(ce, sc);
7654 return;
7655 }
7656 }
7657 }
7658 }
7659 }
7660
7661 if (sc && sc.flags & SCOPE.Cfile)
7662 {
7663 /* C11 6.5.4-5: A cast does not yield an lvalue.
7664 * So ensure that castTo does not strip away the cast so that this
7665 * can be enforced in other semantic visitor methods.
7666 */
7667 if (!ex.isCastExp())
7668 {
7669 ex = new CastExp(exp.loc, ex, exp.to);
7670 ex.type = exp.to;
7671 }
7672 }
7673 result = ex;
7674 }
7675
visit(VectorExp exp)7676 override void visit(VectorExp exp)
7677 {
7678 static if (LOGSEMANTIC)
7679 {
7680 printf("VectorExp::semantic('%s')\n", exp.toChars());
7681 }
7682 if (exp.type)
7683 {
7684 result = exp;
7685 return;
7686 }
7687
7688 exp.e1 = exp.e1.expressionSemantic(sc);
7689 exp.type = exp.to.typeSemantic(exp.loc, sc);
7690 if (exp.e1.op == EXP.error || exp.type.ty == Terror)
7691 {
7692 result = exp.e1;
7693 return;
7694 }
7695
7696 Type tb = exp.type.toBasetype();
7697 assert(tb.ty == Tvector);
7698 TypeVector tv = cast(TypeVector)tb;
7699 Type te = tv.elementType();
7700 exp.dim = cast(int)(tv.size(exp.loc) / te.size(exp.loc));
7701
7702 bool checkElem(Expression elem)
7703 {
7704 if (elem.isConst() == 1)
7705 return false;
7706
7707 exp.error("constant expression expected, not `%s`", elem.toChars());
7708 return true;
7709 }
7710
7711 exp.e1 = exp.e1.optimize(WANTvalue);
7712 bool res;
7713 if (exp.e1.op == EXP.arrayLiteral)
7714 {
7715 foreach (i; 0 .. exp.dim)
7716 {
7717 // Do not stop on first error - check all AST nodes even if error found
7718 res |= checkElem(exp.e1.isArrayLiteralExp()[i]);
7719 }
7720 }
7721 else if (exp.e1.type.ty == Tvoid)
7722 checkElem(exp.e1);
7723
7724 result = res ? ErrorExp.get() : exp;
7725 }
7726
visit(VectorArrayExp e)7727 override void visit(VectorArrayExp e)
7728 {
7729 static if (LOGSEMANTIC)
7730 {
7731 printf("VectorArrayExp::semantic('%s')\n", e.toChars());
7732 }
7733 if (!e.type)
7734 {
7735 unaSemantic(e, sc);
7736 e.e1 = resolveProperties(sc, e.e1);
7737
7738 if (e.e1.op == EXP.error)
7739 {
7740 result = e.e1;
7741 return;
7742 }
7743 assert(e.e1.type.ty == Tvector);
7744 e.type = e.e1.type.isTypeVector().basetype;
7745 }
7746 result = e;
7747 }
7748
visit(SliceExp exp)7749 override void visit(SliceExp exp)
7750 {
7751 static if (LOGSEMANTIC)
7752 {
7753 printf("SliceExp::semantic('%s')\n", exp.toChars());
7754 }
7755 if (exp.type)
7756 {
7757 result = exp;
7758 return;
7759 }
7760
7761 // operator overloading should be handled in ArrayExp already.
7762 if (Expression ex = unaSemantic(exp, sc))
7763 {
7764 result = ex;
7765 return;
7766 }
7767 exp.e1 = resolveProperties(sc, exp.e1);
7768 if (exp.e1.op == EXP.type && exp.e1.type.ty != Ttuple)
7769 {
7770 if (exp.lwr || exp.upr)
7771 {
7772 exp.error("cannot slice type `%s`", exp.e1.toChars());
7773 return setError();
7774 }
7775 Expression e = new TypeExp(exp.loc, exp.e1.type.arrayOf());
7776 result = e.expressionSemantic(sc);
7777 return;
7778 }
7779 if (!exp.lwr && !exp.upr)
7780 {
7781 if (exp.e1.op == EXP.arrayLiteral)
7782 {
7783 // Convert [a,b,c][] to [a,b,c]
7784 Type t1b = exp.e1.type.toBasetype();
7785 Expression e = exp.e1;
7786 if (t1b.ty == Tsarray)
7787 {
7788 e = e.copy();
7789 e.type = t1b.nextOf().arrayOf();
7790 }
7791 result = e;
7792 return;
7793 }
7794 if (exp.e1.op == EXP.slice)
7795 {
7796 // Convert e[][] to e[]
7797 SliceExp se = cast(SliceExp)exp.e1;
7798 if (!se.lwr && !se.upr)
7799 {
7800 result = se;
7801 return;
7802 }
7803 }
7804 if (isArrayOpOperand(exp.e1))
7805 {
7806 // Convert (a[]+b[])[] to a[]+b[]
7807 result = exp.e1;
7808 return;
7809 }
7810 }
7811 if (exp.e1.op == EXP.error)
7812 {
7813 result = exp.e1;
7814 return;
7815 }
7816 if (exp.e1.type.ty == Terror)
7817 return setError();
7818
7819 Type t1b = exp.e1.type.toBasetype();
7820 if (auto tp = t1b.isTypePointer())
7821 {
7822 if (t1b.isPtrToFunction())
7823 {
7824 exp.error("cannot slice function pointer `%s`", exp.e1.toChars());
7825 return setError();
7826 }
7827 if (!exp.lwr || !exp.upr)
7828 {
7829 exp.error("upper and lower bounds are needed to slice a pointer");
7830 if (auto ad = isAggregate(tp.next.toBasetype()))
7831 {
7832 auto s = search_function(ad, Id.index);
7833 if (!s) s = search_function(ad, Id.slice);
7834 if (s)
7835 {
7836 auto fd = s.isFuncDeclaration();
7837 if ((fd && !fd.getParameterList().length) || s.isTemplateDeclaration())
7838 {
7839 exp.errorSupplemental(
7840 "pointer `%s` points to an aggregate that defines an `%s`, perhaps you meant `(*%s)[]`",
7841 exp.e1.toChars(),
7842 s.ident.toChars(),
7843 exp.e1.toChars()
7844 );
7845 }
7846
7847 }
7848 }
7849
7850 return setError();
7851 }
7852 if (sc.func && !sc.intypeof && !(sc.flags & SCOPE.debug_) && sc.func.setUnsafe())
7853 {
7854 exp.error("pointer slicing not allowed in safe functions");
7855 return setError();
7856 }
7857 }
7858 else if (t1b.ty == Tarray)
7859 {
7860 }
7861 else if (t1b.ty == Tsarray)
7862 {
7863 if (!exp.arrayop && global.params.useDIP1000 == FeatureState.enabled)
7864 {
7865 /* Slicing a static array is like taking the address of it.
7866 * Perform checks as if e[] was &e
7867 */
7868 if (VarDeclaration v = expToVariable(exp.e1))
7869 {
7870 if (DotVarExp dve = exp.e1.isDotVarExp())
7871 {
7872
7873 if ((dve.e1.op == EXP.this_ || dve.e1.op == EXP.super_) &&
7874 !(v.storage_class & STC.ref_))
7875 {
7876 // because it's a class
7877 v = null;
7878 }
7879 }
7880
7881 if (v && !checkAddressVar(sc, exp.e1, v))
7882 return setError();
7883 }
7884 // https://issues.dlang.org/show_bug.cgi?id=22539
7885 if (auto ce = exp.e1.isCallExp())
7886 {
7887 if (!checkAddressCall(sc, ce, "slice static array of"))
7888 return setError();
7889 }
7890 }
7891 }
7892 else if (t1b.ty == Ttuple)
7893 {
7894 if (!exp.lwr && !exp.upr)
7895 {
7896 result = exp.e1;
7897 return;
7898 }
7899 if (!exp.lwr || !exp.upr)
7900 {
7901 exp.error("need upper and lower bound to slice tuple");
7902 return setError();
7903 }
7904 }
7905 else if (t1b.ty == Tvector)
7906 {
7907 // Convert e1 to corresponding static array
7908 TypeVector tv1 = cast(TypeVector)t1b;
7909 t1b = tv1.basetype;
7910 t1b = t1b.castMod(tv1.mod);
7911 exp.e1.type = t1b;
7912 }
7913 else
7914 {
7915 exp.error("`%s` cannot be sliced with `[]`", t1b.ty == Tvoid ? exp.e1.toChars() : t1b.toChars());
7916 return setError();
7917 }
7918
7919 /* Run semantic on lwr and upr.
7920 */
7921 Scope* scx = sc;
7922 if (t1b.ty == Tsarray || t1b.ty == Tarray || t1b.ty == Ttuple)
7923 {
7924 // Create scope for 'length' variable
7925 ScopeDsymbol sym = new ArrayScopeSymbol(sc, exp);
7926 sym.parent = sc.scopesym;
7927 sc = sc.push(sym);
7928 }
7929 if (exp.lwr)
7930 {
7931 if (t1b.ty == Ttuple)
7932 sc = sc.startCTFE();
7933 exp.lwr = exp.lwr.expressionSemantic(sc);
7934 exp.lwr = resolveProperties(sc, exp.lwr);
7935 if (t1b.ty == Ttuple)
7936 sc = sc.endCTFE();
7937 exp.lwr = exp.lwr.implicitCastTo(sc, Type.tsize_t);
7938 }
7939 if (exp.upr)
7940 {
7941 if (t1b.ty == Ttuple)
7942 sc = sc.startCTFE();
7943 exp.upr = exp.upr.expressionSemantic(sc);
7944 exp.upr = resolveProperties(sc, exp.upr);
7945 if (t1b.ty == Ttuple)
7946 sc = sc.endCTFE();
7947 exp.upr = exp.upr.implicitCastTo(sc, Type.tsize_t);
7948 }
7949 if (sc != scx)
7950 sc = sc.pop();
7951 if (exp.lwr && exp.lwr.type == Type.terror || exp.upr && exp.upr.type == Type.terror)
7952 return setError();
7953
7954 if (t1b.ty == Ttuple)
7955 {
7956 exp.lwr = exp.lwr.ctfeInterpret();
7957 exp.upr = exp.upr.ctfeInterpret();
7958 uinteger_t i1 = exp.lwr.toUInteger();
7959 uinteger_t i2 = exp.upr.toUInteger();
7960
7961 TupleExp te;
7962 TypeTuple tup;
7963 size_t length;
7964 if (exp.e1.op == EXP.tuple) // slicing an expression tuple
7965 {
7966 te = cast(TupleExp)exp.e1;
7967 tup = null;
7968 length = te.exps.dim;
7969 }
7970 else if (exp.e1.op == EXP.type) // slicing a type tuple
7971 {
7972 te = null;
7973 tup = cast(TypeTuple)t1b;
7974 length = Parameter.dim(tup.arguments);
7975 }
7976 else
7977 assert(0);
7978
7979 if (i2 < i1 || length < i2)
7980 {
7981 exp.error("string slice `[%llu .. %llu]` is out of bounds", i1, i2);
7982 return setError();
7983 }
7984
7985 size_t j1 = cast(size_t)i1;
7986 size_t j2 = cast(size_t)i2;
7987 Expression e;
7988 if (exp.e1.op == EXP.tuple)
7989 {
7990 auto exps = new Expressions(j2 - j1);
7991 for (size_t i = 0; i < j2 - j1; i++)
7992 {
7993 (*exps)[i] = (*te.exps)[j1 + i];
7994 }
7995 e = new TupleExp(exp.loc, te.e0, exps);
7996 }
7997 else
7998 {
7999 auto args = new Parameters();
8000 args.reserve(j2 - j1);
8001 for (size_t i = j1; i < j2; i++)
8002 {
8003 Parameter arg = Parameter.getNth(tup.arguments, i);
8004 args.push(arg);
8005 }
8006 e = new TypeExp(exp.e1.loc, new TypeTuple(args));
8007 }
8008 e = e.expressionSemantic(sc);
8009 result = e;
8010 return;
8011 }
8012
8013 exp.type = t1b.nextOf().arrayOf();
8014 // Allow typedef[] -> typedef[]
8015 if (exp.type.equals(t1b))
8016 exp.type = exp.e1.type;
8017
8018 // We might know $ now
8019 setLengthVarIfKnown(exp.lengthVar, t1b);
8020
8021 if (exp.lwr && exp.upr)
8022 {
8023 exp.lwr = exp.lwr.optimize(WANTvalue);
8024 exp.upr = exp.upr.optimize(WANTvalue);
8025
8026 IntRange lwrRange = getIntRange(exp.lwr);
8027 IntRange uprRange = getIntRange(exp.upr);
8028
8029 if (t1b.ty == Tsarray || t1b.ty == Tarray)
8030 {
8031 Expression el = new ArrayLengthExp(exp.loc, exp.e1);
8032 el = el.expressionSemantic(sc);
8033 el = el.optimize(WANTvalue);
8034 if (el.op == EXP.int64 && t1b.ty == Tsarray)
8035 {
8036 // Array length is known at compile-time. Upper is in bounds if it fits length.
8037 dinteger_t length = el.toInteger();
8038 auto bounds = IntRange(SignExtendedNumber(0), SignExtendedNumber(length));
8039 exp.upperIsInBounds = bounds.contains(uprRange);
8040 if (exp.lwr.op == EXP.int64 && exp.upr.op == EXP.int64 && exp.lwr.toInteger() > exp.upr.toInteger())
8041 {
8042 exp.error("in slice `%s[%llu .. %llu]`, lower bound is greater than upper bound", exp.e1.toChars, exp.lwr.toInteger(), exp.upr.toInteger());
8043 return setError();
8044 }
8045 if (exp.upr.op == EXP.int64 && exp.upr.toInteger() > length)
8046 {
8047 exp.error("in slice `%s[%llu .. %llu]`, upper bound is greater than array length `%llu`", exp.e1.toChars, exp.lwr.toInteger(), exp.upr.toInteger(), length);
8048 return setError();
8049 }
8050 }
8051 else if (exp.upr.op == EXP.int64 && exp.upr.toInteger() == 0)
8052 {
8053 // Upper slice expression is '0'. Value is always in bounds.
8054 exp.upperIsInBounds = true;
8055 }
8056 else if (exp.upr.op == EXP.variable && (cast(VarExp)exp.upr).var.ident == Id.dollar)
8057 {
8058 // Upper slice expression is '$'. Value is always in bounds.
8059 exp.upperIsInBounds = true;
8060 }
8061 }
8062 else if (t1b.ty == Tpointer)
8063 {
8064 exp.upperIsInBounds = true;
8065 }
8066 else
8067 assert(0);
8068
8069 exp.lowerIsLessThanUpper = (lwrRange.imax <= uprRange.imin);
8070
8071 //printf("upperIsInBounds = %d lowerIsLessThanUpper = %d\n", exp.upperIsInBounds, exp.lowerIsLessThanUpper);
8072 }
8073
8074 result = exp;
8075 }
8076
visit(ArrayLengthExp e)8077 override void visit(ArrayLengthExp e)
8078 {
8079 static if (LOGSEMANTIC)
8080 {
8081 printf("ArrayLengthExp::semantic('%s')\n", e.toChars());
8082 }
8083 if (e.type)
8084 {
8085 result = e;
8086 return;
8087 }
8088
8089 if (Expression ex = unaSemantic(e, sc))
8090 {
8091 result = ex;
8092 return;
8093 }
8094 e.e1 = resolveProperties(sc, e.e1);
8095
8096 e.type = Type.tsize_t;
8097 result = e;
8098 }
8099
visit(ArrayExp exp)8100 override void visit(ArrayExp exp)
8101 {
8102 static if (LOGSEMANTIC)
8103 {
8104 printf("ArrayExp::semantic('%s')\n", exp.toChars());
8105 }
8106 assert(!exp.type);
8107
8108 if (sc.flags & SCOPE.Cfile)
8109 {
8110 /* See if need to rewrite the AST because of cast/call ambiguity
8111 */
8112 if (auto e = castCallAmbiguity(exp, sc))
8113 {
8114 result = expressionSemantic(e, sc);
8115 return;
8116 }
8117 }
8118
8119 result = exp.carraySemantic(sc); // C semantics
8120 if (result)
8121 return;
8122
8123 Expression e = exp.op_overload(sc);
8124 if (e)
8125 {
8126 result = e;
8127 return;
8128 }
8129
8130 if (isAggregate(exp.e1.type))
8131 exp.error("no `[]` operator overload for type `%s`", exp.e1.type.toChars());
8132 else if (exp.e1.op == EXP.type && exp.e1.type.ty != Ttuple)
8133 exp.error("static array of `%s` with multiple lengths not allowed", exp.e1.type.toChars());
8134 else if (isIndexableNonAggregate(exp.e1.type))
8135 exp.error("only one index allowed to index `%s`", exp.e1.type.toChars());
8136 else
8137 exp.error("cannot use `[]` operator on expression of type `%s`", exp.e1.type.toChars());
8138
8139 result = ErrorExp.get();
8140 }
8141
visit(DotExp exp)8142 override void visit(DotExp exp)
8143 {
8144 static if (LOGSEMANTIC)
8145 {
8146 printf("DotExp::semantic('%s')\n", exp.toChars());
8147 if (exp.type)
8148 printf("\ttype = %s\n", exp.type.toChars());
8149 }
8150 exp.e1 = exp.e1.expressionSemantic(sc);
8151 exp.e2 = exp.e2.expressionSemantic(sc);
8152
8153 if (exp.e1.op == EXP.type)
8154 {
8155 result = exp.e2;
8156 return;
8157 }
8158 if (exp.e2.op == EXP.type)
8159 {
8160 result = exp.e2;
8161 return;
8162 }
8163 if (auto te = exp.e2.isTemplateExp())
8164 {
8165 Expression e = new DotTemplateExp(exp.loc, exp.e1, te.td);
8166 result = e.expressionSemantic(sc);
8167 return;
8168 }
8169 if (!exp.type)
8170 exp.type = exp.e2.type;
8171 result = exp;
8172 }
8173
visit(CommaExp e)8174 override void visit(CommaExp e)
8175 {
8176 //printf("Semantic.CommaExp() %s\n", e.toChars());
8177 if (e.type)
8178 {
8179 result = e;
8180 return;
8181 }
8182
8183 // Allow `((a,b),(x,y))`
8184 if (e.allowCommaExp)
8185 {
8186 CommaExp.allow(e.e1);
8187 CommaExp.allow(e.e2);
8188 }
8189
8190 if (Expression ex = binSemanticProp(e, sc))
8191 {
8192 result = ex;
8193 return;
8194 }
8195 e.e1 = e.e1.addDtorHook(sc);
8196
8197 if (checkNonAssignmentArrayOp(e.e1))
8198 return setError();
8199
8200 // Comma expressions trigger this conversion
8201 e.e2 = e.e2.arrayFuncConv(sc);
8202
8203 e.type = e.e2.type;
8204 result = e;
8205
8206 if (sc.flags & SCOPE.Cfile)
8207 return;
8208
8209 if (e.type is Type.tvoid)
8210 {
8211 checkMustUse(e.e1, sc);
8212 discardValue(e.e1);
8213 }
8214 else if (!e.allowCommaExp && !e.isGenerated)
8215 e.error("Using the result of a comma expression is not allowed");
8216 }
8217
visit(IntervalExp e)8218 override void visit(IntervalExp e)
8219 {
8220 static if (LOGSEMANTIC)
8221 {
8222 printf("IntervalExp::semantic('%s')\n", e.toChars());
8223 }
8224 if (e.type)
8225 {
8226 result = e;
8227 return;
8228 }
8229
8230 Expression le = e.lwr;
8231 le = le.expressionSemantic(sc);
8232 le = resolveProperties(sc, le);
8233
8234 Expression ue = e.upr;
8235 ue = ue.expressionSemantic(sc);
8236 ue = resolveProperties(sc, ue);
8237
8238 if (le.op == EXP.error)
8239 {
8240 result = le;
8241 return;
8242 }
8243 if (ue.op == EXP.error)
8244 {
8245 result = ue;
8246 return;
8247 }
8248
8249 e.lwr = le;
8250 e.upr = ue;
8251
8252 e.type = Type.tvoid;
8253 result = e;
8254 }
8255
visit(DelegatePtrExp e)8256 override void visit(DelegatePtrExp e)
8257 {
8258 static if (LOGSEMANTIC)
8259 {
8260 printf("DelegatePtrExp::semantic('%s')\n", e.toChars());
8261 }
8262 if (!e.type)
8263 {
8264 unaSemantic(e, sc);
8265 e.e1 = resolveProperties(sc, e.e1);
8266
8267 if (e.e1.op == EXP.error)
8268 {
8269 result = e.e1;
8270 return;
8271 }
8272 e.type = Type.tvoidptr;
8273 }
8274 result = e;
8275 }
8276
visit(DelegateFuncptrExp e)8277 override void visit(DelegateFuncptrExp e)
8278 {
8279 static if (LOGSEMANTIC)
8280 {
8281 printf("DelegateFuncptrExp::semantic('%s')\n", e.toChars());
8282 }
8283 if (!e.type)
8284 {
8285 unaSemantic(e, sc);
8286 e.e1 = resolveProperties(sc, e.e1);
8287 if (e.e1.op == EXP.error)
8288 {
8289 result = e.e1;
8290 return;
8291 }
8292 e.type = e.e1.type.nextOf().pointerTo();
8293 }
8294 result = e;
8295 }
8296
visit(IndexExp exp)8297 override void visit(IndexExp exp)
8298 {
8299 static if (LOGSEMANTIC)
8300 {
8301 printf("IndexExp::semantic('%s')\n", exp.toChars());
8302 }
8303 if (exp.type)
8304 {
8305 result = exp;
8306 return;
8307 }
8308
8309 // operator overloading should be handled in ArrayExp already.
8310 if (!exp.e1.type)
8311 exp.e1 = exp.e1.expressionSemantic(sc).arrayFuncConv(sc);
8312 assert(exp.e1.type); // semantic() should already be run on it
8313 if (exp.e1.op == EXP.type && exp.e1.type.ty != Ttuple)
8314 {
8315 exp.e2 = exp.e2.expressionSemantic(sc);
8316 exp.e2 = resolveProperties(sc, exp.e2);
8317 Type nt;
8318 if (exp.e2.op == EXP.type)
8319 nt = new TypeAArray(exp.e1.type, exp.e2.type);
8320 else
8321 nt = new TypeSArray(exp.e1.type, exp.e2);
8322 Expression e = new TypeExp(exp.loc, nt);
8323 result = e.expressionSemantic(sc);
8324 return;
8325 }
8326 if (exp.e1.op == EXP.error)
8327 {
8328 result = exp.e1;
8329 return;
8330 }
8331 if (exp.e1.type.ty == Terror)
8332 return setError();
8333
8334 // Note that unlike C we do not implement the int[ptr]
8335
8336 Type t1b = exp.e1.type.toBasetype();
8337
8338 if (t1b.ty == Tvector)
8339 {
8340 // Convert e1 to corresponding static array
8341 TypeVector tv1 = cast(TypeVector)t1b;
8342 t1b = tv1.basetype;
8343 t1b = t1b.castMod(tv1.mod);
8344 exp.e1.type = t1b;
8345 }
8346
8347 /* Run semantic on e2
8348 */
8349 Scope* scx = sc;
8350 if (t1b.ty == Tsarray || t1b.ty == Tarray || t1b.ty == Ttuple)
8351 {
8352 // Create scope for 'length' variable
8353 ScopeDsymbol sym = new ArrayScopeSymbol(sc, exp);
8354 sym.parent = sc.scopesym;
8355 sc = sc.push(sym);
8356 }
8357 if (t1b.ty == Ttuple)
8358 sc = sc.startCTFE();
8359 exp.e2 = exp.e2.expressionSemantic(sc).arrayFuncConv(sc);
8360 exp.e2 = resolveProperties(sc, exp.e2);
8361 if (t1b.ty == Ttuple)
8362 sc = sc.endCTFE();
8363 if (exp.e2.op == EXP.tuple)
8364 {
8365 TupleExp te = cast(TupleExp)exp.e2;
8366 if (te.exps && te.exps.dim == 1)
8367 exp.e2 = Expression.combine(te.e0, (*te.exps)[0]); // bug 4444 fix
8368 }
8369 if (sc != scx)
8370 sc = sc.pop();
8371 if (exp.e2.type == Type.terror)
8372 return setError();
8373
8374 if (checkNonAssignmentArrayOp(exp.e1))
8375 return setError();
8376
8377 switch (t1b.ty)
8378 {
8379 case Tpointer:
8380 if (t1b.isPtrToFunction())
8381 {
8382 exp.error("cannot index function pointer `%s`", exp.e1.toChars());
8383 return setError();
8384 }
8385 exp.e2 = exp.e2.implicitCastTo(sc, Type.tsize_t);
8386 if (exp.e2.type == Type.terror)
8387 return setError();
8388 exp.e2 = exp.e2.optimize(WANTvalue);
8389 if (exp.e2.op == EXP.int64 && exp.e2.toInteger() == 0)
8390 {
8391 }
8392 else if (sc.func && !(sc.flags & SCOPE.debug_) && sc.func.setUnsafe())
8393 {
8394 exp.error("safe function `%s` cannot index pointer `%s`", sc.func.toPrettyChars(), exp.e1.toChars());
8395 return setError();
8396 }
8397 exp.type = (cast(TypeNext)t1b).next;
8398 break;
8399
8400 case Tarray:
8401 exp.e2 = exp.e2.implicitCastTo(sc, Type.tsize_t);
8402 if (exp.e2.type == Type.terror)
8403 return setError();
8404 exp.type = (cast(TypeNext)t1b).next;
8405 break;
8406
8407 case Tsarray:
8408 {
8409 exp.e2 = exp.e2.implicitCastTo(sc, Type.tsize_t);
8410 if (exp.e2.type == Type.terror)
8411 return setError();
8412 exp.type = t1b.nextOf();
8413 break;
8414 }
8415 case Taarray:
8416 {
8417 TypeAArray taa = cast(TypeAArray)t1b;
8418 /* We can skip the implicit conversion if they differ only by
8419 * constness
8420 * https://issues.dlang.org/show_bug.cgi?id=2684
8421 * see also bug https://issues.dlang.org/show_bug.cgi?id=2954 b
8422 */
8423 if (!arrayTypeCompatibleWithoutCasting(exp.e2.type, taa.index))
8424 {
8425 exp.e2 = exp.e2.implicitCastTo(sc, taa.index); // type checking
8426 if (exp.e2.type == Type.terror)
8427 return setError();
8428 }
8429
8430 semanticTypeInfo(sc, taa);
8431
8432 exp.type = taa.next;
8433 break;
8434 }
8435 case Ttuple:
8436 {
8437 exp.e2 = exp.e2.implicitCastTo(sc, Type.tsize_t);
8438 if (exp.e2.type == Type.terror)
8439 return setError();
8440
8441 exp.e2 = exp.e2.ctfeInterpret();
8442 uinteger_t index = exp.e2.toUInteger();
8443
8444 TupleExp te;
8445 TypeTuple tup;
8446 size_t length;
8447 if (exp.e1.op == EXP.tuple)
8448 {
8449 te = cast(TupleExp)exp.e1;
8450 tup = null;
8451 length = te.exps.dim;
8452 }
8453 else if (exp.e1.op == EXP.type)
8454 {
8455 te = null;
8456 tup = cast(TypeTuple)t1b;
8457 length = Parameter.dim(tup.arguments);
8458 }
8459 else
8460 assert(0);
8461
8462 if (length <= index)
8463 {
8464 exp.error("array index `[%llu]` is outside array bounds `[0 .. %llu]`", index, cast(ulong)length);
8465 return setError();
8466 }
8467 Expression e;
8468 if (exp.e1.op == EXP.tuple)
8469 {
8470 e = (*te.exps)[cast(size_t)index];
8471 e = Expression.combine(te.e0, e);
8472 }
8473 else
8474 e = new TypeExp(exp.e1.loc, Parameter.getNth(tup.arguments, cast(size_t)index).type);
8475 result = e;
8476 return;
8477 }
8478 default:
8479 exp.error("`%s` must be an array or pointer type, not `%s`", exp.e1.toChars(), exp.e1.type.toChars());
8480 return setError();
8481 }
8482
8483 // We might know $ now
8484 setLengthVarIfKnown(exp.lengthVar, t1b);
8485
8486 if (t1b.ty == Tsarray || t1b.ty == Tarray)
8487 {
8488 Expression el = new ArrayLengthExp(exp.loc, exp.e1);
8489 el = el.expressionSemantic(sc);
8490 el = el.optimize(WANTvalue);
8491 if (el.op == EXP.int64)
8492 {
8493 exp.e2 = exp.e2.optimize(WANTvalue);
8494 dinteger_t length = el.toInteger();
8495 if (length)
8496 {
8497 auto bounds = IntRange(SignExtendedNumber(0), SignExtendedNumber(length - 1));
8498 // OR it in, because it might already be set for C array indexing
8499 exp.indexIsInBounds |= bounds.contains(getIntRange(exp.e2));
8500 }
8501 else if (sc.flags & SCOPE.Cfile && t1b.ty == Tsarray)
8502 {
8503 if (auto ve = exp.e1.isVarExp())
8504 {
8505 /* Rewrite 0-length C array ve[exp.e2] as *(ve + exp.e2)
8506 */
8507 auto vp = ve.castTo(sc, t1b.isTypeSArray().next.pointerTo());
8508 auto e = new AddExp(exp.loc, vp, exp.e2);
8509 auto pe = new PtrExp(exp.loc, e);
8510 result = pe.expressionSemantic(sc).optimize(WANTvalue);
8511 return;
8512 }
8513 }
8514 }
8515 }
8516
8517 result = exp;
8518 }
8519
visit(PostExp exp)8520 override void visit(PostExp exp)
8521 {
8522 static if (LOGSEMANTIC)
8523 {
8524 printf("PostExp::semantic('%s')\n", exp.toChars());
8525 }
8526 if (exp.type)
8527 {
8528 result = exp;
8529 return;
8530 }
8531
8532 if (sc.flags & SCOPE.Cfile)
8533 {
8534 /* See if need to rewrite the AST because of cast/call ambiguity
8535 */
8536 if (auto e = castCallAmbiguity(exp, sc))
8537 {
8538 result = expressionSemantic(e, sc);
8539 return;
8540 }
8541 }
8542
8543 if (Expression ex = binSemantic(exp, sc))
8544 {
8545 result = ex;
8546 return;
8547 }
8548 Expression e1x = resolveProperties(sc, exp.e1);
8549 if (e1x.op == EXP.error)
8550 {
8551 result = e1x;
8552 return;
8553 }
8554 exp.e1 = e1x;
8555
8556 Expression e = exp.op_overload(sc);
8557 if (e)
8558 {
8559 result = e;
8560 return;
8561 }
8562
8563 if (exp.e1.checkReadModifyWrite(exp.op))
8564 return setError();
8565
8566 if (exp.e1.op == EXP.slice)
8567 {
8568 const(char)* s = exp.op == EXP.plusPlus ? "increment" : "decrement";
8569 exp.error("cannot post-%s array slice `%s`, use pre-%s instead", s, exp.e1.toChars(), s);
8570 return setError();
8571 }
8572
8573 Type t1 = exp.e1.type.toBasetype();
8574 if (t1.ty == Tclass || t1.ty == Tstruct || exp.e1.op == EXP.arrayLength)
8575 {
8576 /* Check for operator overloading,
8577 * but rewrite in terms of ++e instead of e++
8578 */
8579
8580 /* If e1 is not trivial, take a reference to it
8581 */
8582 Expression de = null;
8583 if (exp.e1.op != EXP.variable && exp.e1.op != EXP.arrayLength)
8584 {
8585 // ref v = e1;
8586 auto v = copyToTemp(STC.ref_, "__postref", exp.e1);
8587 de = new DeclarationExp(exp.loc, v);
8588 exp.e1 = new VarExp(exp.e1.loc, v);
8589 }
8590
8591 /* Rewrite as:
8592 * auto tmp = e1; ++e1; tmp
8593 */
8594 auto tmp = copyToTemp(0, "__pitmp", exp.e1);
8595 Expression ea = new DeclarationExp(exp.loc, tmp);
8596
8597 Expression eb = exp.e1.syntaxCopy();
8598 eb = new PreExp(exp.op == EXP.plusPlus ? EXP.prePlusPlus : EXP.preMinusMinus, exp.loc, eb);
8599
8600 Expression ec = new VarExp(exp.loc, tmp);
8601
8602 // Combine de,ea,eb,ec
8603 if (de)
8604 ea = new CommaExp(exp.loc, de, ea);
8605 e = new CommaExp(exp.loc, ea, eb);
8606 e = new CommaExp(exp.loc, e, ec);
8607 e = e.expressionSemantic(sc);
8608 result = e;
8609 return;
8610 }
8611
8612 exp.e1 = exp.e1.modifiableLvalue(sc, exp.e1);
8613 exp.e1 = exp.e1.optimize(WANTvalue, /*keepLvalue*/ true);
8614
8615 e = exp;
8616 if (exp.e1.checkScalar() ||
8617 exp.e1.checkSharedAccess(sc))
8618 return setError();
8619 if (exp.e1.checkNoBool())
8620 return setError();
8621
8622 if (exp.e1.type.ty == Tpointer)
8623 e = scaleFactor(exp, sc);
8624 else
8625 exp.e2 = exp.e2.castTo(sc, exp.e1.type);
8626 e.type = exp.e1.type;
8627 result = e;
8628 }
8629
visit(PreExp exp)8630 override void visit(PreExp exp)
8631 {
8632 Expression e = exp.op_overload(sc);
8633 // printf("PreExp::semantic('%s')\n", toChars());
8634 if (e)
8635 {
8636 result = e;
8637 return;
8638 }
8639
8640 // Rewrite as e1+=1 or e1-=1
8641 if (exp.op == EXP.prePlusPlus)
8642 e = new AddAssignExp(exp.loc, exp.e1, IntegerExp.literal!1);
8643 else
8644 e = new MinAssignExp(exp.loc, exp.e1, IntegerExp.literal!1);
8645 result = e.expressionSemantic(sc);
8646 }
8647
8648 /*
8649 * Get the expression initializer for a specific struct
8650 *
8651 * Params:
8652 * sd = the struct for which the expression initializer is needed
8653 * loc = the location of the initializer
8654 * sc = the scope where the expression is located
8655 * t = the type of the expression
8656 *
8657 * Returns:
8658 * The expression initializer or error expression if any errors occured
8659 */
getInitExp(StructDeclaration sd,Loc loc,Scope * sc,Type t)8660 private Expression getInitExp(StructDeclaration sd, Loc loc, Scope* sc, Type t)
8661 {
8662 if (sd.zeroInit && !sd.isNested())
8663 {
8664 // https://issues.dlang.org/show_bug.cgi?id=14606
8665 // Always use BlitExp for the special expression: (struct = 0)
8666 return IntegerExp.literal!0;
8667 }
8668
8669 if (sd.isNested())
8670 {
8671 auto sle = new StructLiteralExp(loc, sd, null, t);
8672 if (!sd.fill(loc, sle.elements, true))
8673 return ErrorExp.get();
8674 if (checkFrameAccess(loc, sc, sd, sle.elements.dim))
8675 return ErrorExp.get();
8676
8677 sle.type = t;
8678 return sle;
8679 }
8680
8681 return t.defaultInit(loc);
8682 }
8683
visit(AssignExp exp)8684 override void visit(AssignExp exp)
8685 {
8686 static if (LOGSEMANTIC)
8687 {
8688 if (exp.op == EXP.blit) printf("BlitExp.toElem('%s')\n", exp.toChars());
8689 if (exp.op == EXP.assign) printf("AssignExp.toElem('%s')\n", exp.toChars());
8690 if (exp.op == EXP.construct) printf("ConstructExp.toElem('%s')\n", exp.toChars());
8691 }
8692 //printf("exp.e1.op = %d, '%s'\n", exp.e1.op, EXPtoString(exp.e1.op).ptr);
8693 //printf("exp.e2.op = %d, '%s'\n", exp.e2.op, EXPtoString(exp.e2.op).ptr);
8694
8695 void setResult(Expression e, int line = __LINE__)
8696 {
8697 //printf("line %d\n", line);
8698 result = e;
8699 }
8700
8701 if (exp.type)
8702 {
8703 return setResult(exp);
8704 }
8705
8706 Expression e1old = exp.e1;
8707
8708 if (auto e2comma = exp.e2.isCommaExp())
8709 {
8710 if (!e2comma.isGenerated && !(sc.flags & SCOPE.Cfile))
8711 exp.error("Using the result of a comma expression is not allowed");
8712
8713 /* Rewrite to get rid of the comma from rvalue
8714 * e1=(e0,e2) => e0,(e1=e2)
8715 */
8716 Expression e0;
8717 exp.e2 = Expression.extractLast(e2comma, e0);
8718 Expression e = Expression.combine(e0, exp);
8719 return setResult(e.expressionSemantic(sc));
8720 }
8721
8722 /* Look for operator overloading of a[arguments] = e2.
8723 * Do it before e1.expressionSemantic() otherwise the ArrayExp will have been
8724 * converted to unary operator overloading already.
8725 */
8726 if (auto ae = exp.e1.isArrayExp())
8727 {
8728 Expression res;
8729
8730 ae.e1 = ae.e1.expressionSemantic(sc);
8731 ae.e1 = resolveProperties(sc, ae.e1);
8732 Expression ae1old = ae.e1;
8733
8734 const(bool) maybeSlice =
8735 (ae.arguments.dim == 0 ||
8736 ae.arguments.dim == 1 && (*ae.arguments)[0].op == EXP.interval);
8737
8738 IntervalExp ie = null;
8739 if (maybeSlice && ae.arguments.dim)
8740 {
8741 assert((*ae.arguments)[0].op == EXP.interval);
8742 ie = cast(IntervalExp)(*ae.arguments)[0];
8743 }
8744 while (true)
8745 {
8746 if (ae.e1.op == EXP.error)
8747 return setResult(ae.e1);
8748
8749 Expression e0 = null;
8750 Expression ae1save = ae.e1;
8751 ae.lengthVar = null;
8752
8753 Type t1b = ae.e1.type.toBasetype();
8754 AggregateDeclaration ad = isAggregate(t1b);
8755 if (!ad)
8756 break;
8757 if (search_function(ad, Id.indexass))
8758 {
8759 // Deal with $
8760 res = resolveOpDollar(sc, ae, &e0);
8761 if (!res) // a[i..j] = e2 might be: a.opSliceAssign(e2, i, j)
8762 goto Lfallback;
8763 if (res.op == EXP.error)
8764 return setResult(res);
8765
8766 res = exp.e2.expressionSemantic(sc);
8767 if (res.op == EXP.error)
8768 return setResult(res);
8769 exp.e2 = res;
8770
8771 /* Rewrite (a[arguments] = e2) as:
8772 * a.opIndexAssign(e2, arguments)
8773 */
8774 Expressions* a = ae.arguments.copy();
8775 a.insert(0, exp.e2);
8776 res = new DotIdExp(exp.loc, ae.e1, Id.indexass);
8777 res = new CallExp(exp.loc, res, a);
8778 if (maybeSlice) // a[] = e2 might be: a.opSliceAssign(e2)
8779 res = res.trySemantic(sc);
8780 else
8781 res = res.expressionSemantic(sc);
8782 if (res)
8783 return setResult(Expression.combine(e0, res));
8784 }
8785
8786 Lfallback:
8787 if (maybeSlice && search_function(ad, Id.sliceass))
8788 {
8789 // Deal with $
8790 res = resolveOpDollar(sc, ae, ie, &e0);
8791 if (res.op == EXP.error)
8792 return setResult(res);
8793
8794 res = exp.e2.expressionSemantic(sc);
8795 if (res.op == EXP.error)
8796 return setResult(res);
8797
8798 exp.e2 = res;
8799
8800 /* Rewrite (a[i..j] = e2) as:
8801 * a.opSliceAssign(e2, i, j)
8802 */
8803 auto a = new Expressions();
8804 a.push(exp.e2);
8805 if (ie)
8806 {
8807 a.push(ie.lwr);
8808 a.push(ie.upr);
8809 }
8810 res = new DotIdExp(exp.loc, ae.e1, Id.sliceass);
8811 res = new CallExp(exp.loc, res, a);
8812 res = res.expressionSemantic(sc);
8813 return setResult(Expression.combine(e0, res));
8814 }
8815
8816 // No operator overloading member function found yet, but
8817 // there might be an alias this to try.
8818 if (ad.aliasthis && !isRecursiveAliasThis(ae.att1, ae.e1.type))
8819 {
8820 /* Rewrite (a[arguments] op e2) as:
8821 * a.aliasthis[arguments] op e2
8822 */
8823 ae.e1 = resolveAliasThis(sc, ae1save, true);
8824 if (ae.e1)
8825 continue;
8826 }
8827 break;
8828 }
8829 ae.e1 = ae1old; // recovery
8830 ae.lengthVar = null;
8831 }
8832
8833 /* Run this.e1 semantic.
8834 */
8835 {
8836 Expression e1x = exp.e1;
8837
8838 /* With UFCS, e.f = value
8839 * Could mean:
8840 * .f(e, value)
8841 * or:
8842 * .f(e) = value
8843 */
8844 if (auto dti = e1x.isDotTemplateInstanceExp())
8845 {
8846 Expression e = dti.semanticY(sc, 1);
8847 if (!e)
8848 {
8849 return setResult(resolveUFCSProperties(sc, e1x, exp.e2));
8850 }
8851
8852 e1x = e;
8853 }
8854 else if (sc.flags & SCOPE.Cfile && e1x.isDotIdExp())
8855 {
8856 auto die = e1x.isDotIdExp();
8857 e1x = fieldLookup(die.e1, sc, die.ident);
8858 }
8859 else if (auto die = e1x.isDotIdExp())
8860 {
8861 Expression e = die.semanticY(sc, 1);
8862 if (e && isDotOpDispatch(e))
8863 {
8864 /* https://issues.dlang.org/show_bug.cgi?id=19687
8865 *
8866 * On this branch, e2 is semantically analyzed in resolvePropertiesX,
8867 * but that call is done with gagged errors. That is the only time when
8868 * semantic gets ran on e2, that is why the error never gets to be printed.
8869 * In order to make sure that UFCS is tried with correct parameters, e2
8870 * needs to have semantic ran on it.
8871 */
8872 auto ode = e;
8873 exp.e2 = exp.e2.expressionSemantic(sc);
8874 uint errors = global.startGagging();
8875 e = resolvePropertiesX(sc, e, exp.e2);
8876 // Any error or if 'e' is not resolved, go to UFCS
8877 if (global.endGagging(errors) || e is ode)
8878 e = null; /* fall down to UFCS */
8879 else
8880 return setResult(e);
8881 }
8882 if (!e)
8883 return setResult(resolveUFCSProperties(sc, e1x, exp.e2));
8884 e1x = e;
8885 }
8886 else
8887 {
8888 if (auto se = e1x.isSliceExp())
8889 se.arrayop = true;
8890
8891 e1x = e1x.expressionSemantic(sc);
8892 }
8893
8894 /* We have f = value.
8895 * Could mean:
8896 * f(value)
8897 * or:
8898 * f() = value
8899 */
8900 if (Expression e = resolvePropertiesX(sc, e1x, exp.e2))
8901 return setResult(e);
8902
8903 if (e1x.checkRightThis(sc))
8904 {
8905 return setError();
8906 }
8907 exp.e1 = e1x;
8908 assert(exp.e1.type);
8909 }
8910 Type t1 = exp.e1.type.toBasetype();
8911
8912 /* Run this.e2 semantic.
8913 * Different from other binary expressions, the analysis of e2
8914 * depends on the result of e1 in assignments.
8915 */
8916 {
8917 Expression e2x = inferType(exp.e2, t1.baseElemOf());
8918 e2x = e2x.expressionSemantic(sc);
8919 if (!t1.isTypeSArray())
8920 e2x = e2x.arrayFuncConv(sc);
8921 e2x = resolveProperties(sc, e2x);
8922 if (e2x.op == EXP.type)
8923 e2x = resolveAliasThis(sc, e2x); //https://issues.dlang.org/show_bug.cgi?id=17684
8924 if (e2x.op == EXP.error)
8925 return setResult(e2x);
8926 // We delay checking the value for structs/classes as these might have
8927 // an opAssign defined.
8928 if ((t1.ty != Tstruct && t1.ty != Tclass && e2x.checkValue()) ||
8929 e2x.checkSharedAccess(sc))
8930 return setError();
8931 exp.e2 = e2x;
8932 }
8933
8934 /* Rewrite tuple assignment as a tuple of assignments.
8935 */
8936 {
8937 Expression e2x = exp.e2;
8938
8939 Ltupleassign:
8940 if (exp.e1.op == EXP.tuple && e2x.op == EXP.tuple)
8941 {
8942 TupleExp tup1 = cast(TupleExp)exp.e1;
8943 TupleExp tup2 = cast(TupleExp)e2x;
8944 size_t dim = tup1.exps.dim;
8945 Expression e = null;
8946 if (dim != tup2.exps.dim)
8947 {
8948 exp.error("mismatched tuple lengths, %d and %d", cast(int)dim, cast(int)tup2.exps.dim);
8949 return setError();
8950 }
8951 if (dim == 0)
8952 {
8953 e = IntegerExp.literal!0;
8954 e = new CastExp(exp.loc, e, Type.tvoid); // avoid "has no effect" error
8955 e = Expression.combine(tup1.e0, tup2.e0, e);
8956 }
8957 else
8958 {
8959 auto exps = new Expressions(dim);
8960 for (size_t i = 0; i < dim; i++)
8961 {
8962 Expression ex1 = (*tup1.exps)[i];
8963 Expression ex2 = (*tup2.exps)[i];
8964 (*exps)[i] = new AssignExp(exp.loc, ex1, ex2);
8965 }
8966 e = new TupleExp(exp.loc, Expression.combine(tup1.e0, tup2.e0), exps);
8967 }
8968 return setResult(e.expressionSemantic(sc));
8969 }
8970
8971 /* Look for form: e1 = e2.aliasthis.
8972 */
8973 if (exp.e1.op == EXP.tuple)
8974 {
8975 TupleDeclaration td = isAliasThisTuple(e2x);
8976 if (!td)
8977 goto Lnomatch;
8978
8979 assert(exp.e1.type.ty == Ttuple);
8980 TypeTuple tt = cast(TypeTuple)exp.e1.type;
8981
8982 Expression e0;
8983 Expression ev = extractSideEffect(sc, "__tup", e0, e2x);
8984
8985 auto iexps = new Expressions();
8986 iexps.push(ev);
8987 for (size_t u = 0; u < iexps.dim; u++)
8988 {
8989 Lexpand:
8990 Expression e = (*iexps)[u];
8991
8992 Parameter arg = Parameter.getNth(tt.arguments, u);
8993 //printf("[%d] iexps.dim = %d, ", u, iexps.dim);
8994 //printf("e = (%s %s, %s), ", Token.toChars[e.op], e.toChars(), e.type.toChars());
8995 //printf("arg = (%s, %s)\n", arg.toChars(), arg.type.toChars());
8996
8997 if (!arg || !e.type.implicitConvTo(arg.type))
8998 {
8999 // expand initializer to tuple
9000 if (expandAliasThisTuples(iexps, u) != -1)
9001 {
9002 if (iexps.dim <= u)
9003 break;
9004 goto Lexpand;
9005 }
9006 goto Lnomatch;
9007 }
9008 }
9009 e2x = new TupleExp(e2x.loc, e0, iexps);
9010 e2x = e2x.expressionSemantic(sc);
9011 if (e2x.op == EXP.error)
9012 {
9013 result = e2x;
9014 return;
9015 }
9016 // Do not need to overwrite this.e2
9017 goto Ltupleassign;
9018 }
9019 Lnomatch:
9020 }
9021
9022 /* Inside constructor, if this is the first assignment of object field,
9023 * rewrite this to initializing the field.
9024 */
9025 if (exp.op == EXP.assign
9026 && exp.e1.checkModifiable(sc) == Modifiable.initialization)
9027 {
9028 //printf("[%s] change to init - %s\n", exp.loc.toChars(), exp.toChars());
9029 auto t = exp.type;
9030 exp = new ConstructExp(exp.loc, exp.e1, exp.e2);
9031 exp.type = t;
9032
9033 // https://issues.dlang.org/show_bug.cgi?id=13515
9034 // set Index::modifiable flag for complex AA element initialization
9035 if (auto ie1 = exp.e1.isIndexExp())
9036 {
9037 Expression e1x = ie1.markSettingAAElem();
9038 if (e1x.op == EXP.error)
9039 {
9040 result = e1x;
9041 return;
9042 }
9043 }
9044 }
9045 else if (exp.op == EXP.construct && exp.e1.op == EXP.variable &&
9046 (cast(VarExp)exp.e1).var.storage_class & (STC.out_ | STC.ref_))
9047 {
9048 exp.memset = MemorySet.referenceInit;
9049 }
9050
9051 if (exp.op == EXP.assign) // skip EXP.blit and EXP.construct, which are initializations
9052 {
9053 exp.e1.checkSharedAccess(sc);
9054 checkUnsafeAccess(sc, exp.e1, false, true);
9055 }
9056
9057 checkUnsafeAccess(sc, exp.e2, true, true); // Initializer must always be checked
9058
9059 /* If it is an assignment from a 'foreign' type,
9060 * check for operator overloading.
9061 */
9062 if (exp.memset == MemorySet.referenceInit)
9063 {
9064 // If this is an initialization of a reference,
9065 // do nothing
9066 }
9067 else if (t1.ty == Tstruct)
9068 {
9069 auto e1x = exp.e1;
9070 auto e2x = exp.e2;
9071 auto sd = (cast(TypeStruct)t1).sym;
9072
9073 if (exp.op == EXP.construct)
9074 {
9075 Type t2 = e2x.type.toBasetype();
9076 if (t2.ty == Tstruct && sd == (cast(TypeStruct)t2).sym)
9077 {
9078 sd.size(exp.loc);
9079 if (sd.sizeok != Sizeok.done)
9080 return setError();
9081 if (!sd.ctor)
9082 sd.ctor = sd.searchCtor();
9083
9084 // https://issues.dlang.org/show_bug.cgi?id=15661
9085 // Look for the form from last of comma chain.
9086 auto e2y = lastComma(e2x);
9087
9088 CallExp ce = (e2y.op == EXP.call) ? cast(CallExp)e2y : null;
9089 DotVarExp dve = (ce && ce.e1.op == EXP.dotVariable)
9090 ? cast(DotVarExp)ce.e1 : null;
9091 if (sd.ctor && ce && dve && dve.var.isCtorDeclaration() &&
9092 // https://issues.dlang.org/show_bug.cgi?id=19389
9093 dve.e1.op != EXP.dotVariable &&
9094 e2y.type.implicitConvTo(t1))
9095 {
9096 /* Look for form of constructor call which is:
9097 * __ctmp.ctor(arguments...)
9098 */
9099
9100 /* Before calling the constructor, initialize
9101 * variable with a bit copy of the default
9102 * initializer
9103 */
9104 Expression einit = getInitExp(sd, exp.loc, sc, t1);
9105 if (einit.op == EXP.error)
9106 {
9107 result = einit;
9108 return;
9109 }
9110
9111 auto ae = new BlitExp(exp.loc, exp.e1, einit);
9112 ae.type = e1x.type;
9113
9114 /* Replace __ctmp being constructed with e1.
9115 * We need to copy constructor call expression,
9116 * because it may be used in other place.
9117 */
9118 auto dvx = cast(DotVarExp)dve.copy();
9119 dvx.e1 = e1x;
9120 auto cx = cast(CallExp)ce.copy();
9121 cx.e1 = dvx;
9122 if (checkConstructorEscape(sc, cx, false))
9123 return setError();
9124
9125 Expression e0;
9126 Expression.extractLast(e2x, e0);
9127
9128 auto e = Expression.combine(e0, ae, cx);
9129 e = e.expressionSemantic(sc);
9130 result = e;
9131 return;
9132 }
9133 // https://issues.dlang.org/show_bug.cgi?id=21586
9134 // Rewrite CondExp or e1 will miss direct construction, e.g.
9135 // e1 = a ? S(1) : ...; -> AST: e1 = a ? (S(0)).this(1) : ...;
9136 // a temporary created and an extra destructor call.
9137 // AST will be rewritten to:
9138 // a ? e1 = 0, e1.this(1) : ...; -> blitting plus construction
9139 if (e2x.op == EXP.question)
9140 {
9141 /* Rewrite as:
9142 * a ? e1 = b : e1 = c;
9143 */
9144 CondExp econd = cast(CondExp)e2x;
9145 Expression ea1 = new ConstructExp(econd.e1.loc, e1x, econd.e1);
9146 Expression ea2 = new ConstructExp(econd.e2.loc, e1x, econd.e2);
9147 Expression e = new CondExp(exp.loc, econd.econd, ea1, ea2);
9148 result = e.expressionSemantic(sc);
9149 return;
9150 }
9151 if (sd.postblit || sd.hasCopyCtor)
9152 {
9153 /* We have a copy constructor for this
9154 */
9155
9156 if (e2x.isLvalue())
9157 {
9158 if (sd.hasCopyCtor)
9159 {
9160 /* Rewrite as:
9161 * e1 = init, e1.copyCtor(e2);
9162 */
9163 Expression einit = new BlitExp(exp.loc, exp.e1, getInitExp(sd, exp.loc, sc, t1));
9164 einit.type = e1x.type;
9165
9166 Expression e;
9167 e = new DotIdExp(exp.loc, e1x, Id.ctor);
9168 e = new CallExp(exp.loc, e, e2x);
9169 e = new CommaExp(exp.loc, einit, e);
9170
9171 //printf("e: %s\n", e.toChars());
9172
9173 result = e.expressionSemantic(sc);
9174 return;
9175 }
9176 else
9177 {
9178 if (!e2x.type.implicitConvTo(e1x.type))
9179 {
9180 exp.error("conversion error from `%s` to `%s`",
9181 e2x.type.toChars(), e1x.type.toChars());
9182 return setError();
9183 }
9184
9185 /* Rewrite as:
9186 * (e1 = e2).postblit();
9187 *
9188 * Blit assignment e1 = e2 returns a reference to the original e1,
9189 * then call the postblit on it.
9190 */
9191 Expression e = e1x.copy();
9192 e.type = e.type.mutableOf();
9193 if (e.type.isShared && !sd.type.isShared)
9194 e.type = e.type.unSharedOf();
9195 e = new BlitExp(exp.loc, e, e2x);
9196 e = new DotVarExp(exp.loc, e, sd.postblit, false);
9197 e = new CallExp(exp.loc, e);
9198 result = e.expressionSemantic(sc);
9199 return;
9200 }
9201 }
9202 else
9203 {
9204 /* The struct value returned from the function is transferred
9205 * so should not call the destructor on it.
9206 */
9207 e2x = valueNoDtor(e2x);
9208 }
9209 }
9210
9211 // https://issues.dlang.org/show_bug.cgi?id=19251
9212 // if e2 cannot be converted to e1.type, maybe there is an alias this
9213 if (!e2x.implicitConvTo(t1))
9214 {
9215 AggregateDeclaration ad2 = isAggregate(e2x.type);
9216 if (ad2 && ad2.aliasthis && !isRecursiveAliasThis(exp.att2, exp.e2.type))
9217 {
9218 /* Rewrite (e1 op e2) as:
9219 * (e1 op e2.aliasthis)
9220 */
9221 exp.e2 = new DotIdExp(exp.e2.loc, exp.e2, ad2.aliasthis.ident);
9222 result = exp.expressionSemantic(sc);
9223 return;
9224 }
9225 }
9226 }
9227 else if (!e2x.implicitConvTo(t1))
9228 {
9229 sd.size(exp.loc);
9230 if (sd.sizeok != Sizeok.done)
9231 return setError();
9232 if (!sd.ctor)
9233 sd.ctor = sd.searchCtor();
9234
9235 if (sd.ctor)
9236 {
9237 /* Look for implicit constructor call
9238 * Rewrite as:
9239 * e1 = init, e1.ctor(e2)
9240 */
9241
9242 /* Fix Issue 5153 : https://issues.dlang.org/show_bug.cgi?id=5153
9243 * Using `new` to initialize a struct object is a common mistake, but
9244 * the error message from the compiler is not very helpful in that
9245 * case. If exp.e2 is a NewExp and the type of new is the same as
9246 * the type as exp.e1 (struct in this case), then we know for sure
9247 * that the user wants to instantiate a struct. This is done to avoid
9248 * issuing an error when the user actually wants to call a constructor
9249 * which receives a class object.
9250 *
9251 * Foo f = new Foo2(0); is a valid expression if Foo has a constructor
9252 * which receives an instance of a Foo2 class
9253 */
9254 if (exp.e2.op == EXP.new_)
9255 {
9256 auto newExp = cast(NewExp)(exp.e2);
9257 if (newExp.newtype && newExp.newtype == t1)
9258 {
9259 error(exp.loc, "cannot implicitly convert expression `%s` of type `%s` to `%s`",
9260 newExp.toChars(), newExp.type.toChars(), t1.toChars());
9261 errorSupplemental(exp.loc, "Perhaps remove the `new` keyword?");
9262 return setError();
9263 }
9264 }
9265
9266 Expression einit = new BlitExp(exp.loc, e1x, getInitExp(sd, exp.loc, sc, t1));
9267 einit.type = e1x.type;
9268
9269 Expression e;
9270 e = new DotIdExp(exp.loc, e1x, Id.ctor);
9271 e = new CallExp(exp.loc, e, e2x);
9272 e = new CommaExp(exp.loc, einit, e);
9273 e = e.expressionSemantic(sc);
9274 result = e;
9275 return;
9276 }
9277 if (search_function(sd, Id.call))
9278 {
9279 /* Look for static opCall
9280 * https://issues.dlang.org/show_bug.cgi?id=2702
9281 * Rewrite as:
9282 * e1 = typeof(e1).opCall(arguments)
9283 */
9284 e2x = typeDotIdExp(e2x.loc, e1x.type, Id.call);
9285 e2x = new CallExp(exp.loc, e2x, exp.e2);
9286
9287 e2x = e2x.expressionSemantic(sc);
9288 e2x = resolveProperties(sc, e2x);
9289 if (e2x.op == EXP.error)
9290 {
9291 result = e2x;
9292 return;
9293 }
9294 if (e2x.checkValue() || e2x.checkSharedAccess(sc))
9295 return setError();
9296 }
9297 }
9298 else // https://issues.dlang.org/show_bug.cgi?id=11355
9299 {
9300 AggregateDeclaration ad2 = isAggregate(e2x.type);
9301 if (ad2 && ad2.aliasthis && !isRecursiveAliasThis(exp.att2, exp.e2.type))
9302 {
9303 /* Rewrite (e1 op e2) as:
9304 * (e1 op e2.aliasthis)
9305 */
9306 exp.e2 = new DotIdExp(exp.e2.loc, exp.e2, ad2.aliasthis.ident);
9307 result = exp.expressionSemantic(sc);
9308 return;
9309 }
9310 }
9311 }
9312 else if (exp.op == EXP.assign)
9313 {
9314 if (e1x.op == EXP.index && (cast(IndexExp)e1x).e1.type.toBasetype().ty == Taarray)
9315 {
9316 /*
9317 * Rewrite:
9318 * aa[key] = e2;
9319 * as:
9320 * ref __aatmp = aa;
9321 * ref __aakey = key;
9322 * ref __aaval = e2;
9323 * (__aakey in __aatmp
9324 * ? __aatmp[__aakey].opAssign(__aaval)
9325 * : ConstructExp(__aatmp[__aakey], __aaval));
9326 */
9327 // ensure we keep the expr modifiable
9328 Expression esetting = (cast(IndexExp)e1x).markSettingAAElem();
9329 if (esetting.op == EXP.error)
9330 {
9331 result = esetting;
9332 return;
9333 }
9334 assert(esetting.op == EXP.index);
9335 IndexExp ie = cast(IndexExp) esetting;
9336 Type t2 = e2x.type.toBasetype();
9337
9338 Expression e0 = null;
9339 Expression ea = extractSideEffect(sc, "__aatmp", e0, ie.e1);
9340 Expression ek = extractSideEffect(sc, "__aakey", e0, ie.e2);
9341 Expression ev = extractSideEffect(sc, "__aaval", e0, e2x);
9342
9343 AssignExp ae = cast(AssignExp)exp.copy();
9344 ae.e1 = new IndexExp(exp.loc, ea, ek);
9345 ae.e1 = ae.e1.expressionSemantic(sc);
9346 ae.e1 = ae.e1.optimize(WANTvalue);
9347 ae.e2 = ev;
9348 Expression e = ae.op_overload(sc);
9349 if (e)
9350 {
9351 Expression ey = null;
9352 if (t2.ty == Tstruct && sd == t2.toDsymbol(sc))
9353 {
9354 ey = ev;
9355 }
9356 else if (!ev.implicitConvTo(ie.type) && sd.ctor)
9357 {
9358 // Look for implicit constructor call
9359 // Rewrite as S().ctor(e2)
9360 ey = new StructLiteralExp(exp.loc, sd, null);
9361 ey = new DotIdExp(exp.loc, ey, Id.ctor);
9362 ey = new CallExp(exp.loc, ey, ev);
9363 ey = ey.trySemantic(sc);
9364 }
9365 if (ey)
9366 {
9367 Expression ex;
9368 ex = new IndexExp(exp.loc, ea, ek);
9369 ex = ex.expressionSemantic(sc);
9370 ex = ex.modifiableLvalue(sc, ex); // allocate new slot
9371 ex = ex.optimize(WANTvalue);
9372
9373 ey = new ConstructExp(exp.loc, ex, ey);
9374 ey = ey.expressionSemantic(sc);
9375 if (ey.op == EXP.error)
9376 {
9377 result = ey;
9378 return;
9379 }
9380 ex = e;
9381
9382 // https://issues.dlang.org/show_bug.cgi?id=14144
9383 // The whole expression should have the common type
9384 // of opAssign() return and assigned AA entry.
9385 // Even if there's no common type, expression should be typed as void.
9386 if (!typeMerge(sc, EXP.question, ex, ey))
9387 {
9388 ex = new CastExp(ex.loc, ex, Type.tvoid);
9389 ey = new CastExp(ey.loc, ey, Type.tvoid);
9390 }
9391 e = new CondExp(exp.loc, new InExp(exp.loc, ek, ea), ex, ey);
9392 }
9393 e = Expression.combine(e0, e);
9394 e = e.expressionSemantic(sc);
9395 result = e;
9396 return;
9397 }
9398 }
9399 else
9400 {
9401 Expression e = exp.op_overload(sc);
9402 if (e)
9403 {
9404 result = e;
9405 return;
9406 }
9407 }
9408 }
9409 else
9410 assert(exp.op == EXP.blit);
9411
9412 if (e2x.checkValue())
9413 return setError();
9414
9415 exp.e1 = e1x;
9416 exp.e2 = e2x;
9417 }
9418 else if (t1.ty == Tclass)
9419 {
9420 // Disallow assignment operator overloads for same type
9421 if (exp.op == EXP.assign && !exp.e2.implicitConvTo(exp.e1.type))
9422 {
9423 Expression e = exp.op_overload(sc);
9424 if (e)
9425 {
9426 result = e;
9427 return;
9428 }
9429 }
9430 if (exp.e2.checkValue())
9431 return setError();
9432 }
9433 else if (t1.ty == Tsarray)
9434 {
9435 // SliceExp cannot have static array type without context inference.
9436 assert(exp.e1.op != EXP.slice);
9437 Expression e1x = exp.e1;
9438 Expression e2x = exp.e2;
9439
9440 /* C strings come through as static arrays. May need to adjust the size of the
9441 * string to match the size of e1.
9442 */
9443 Type t2 = e2x.type.toBasetype();
9444 if (sc.flags & SCOPE.Cfile && e2x.isStringExp() && t2.isTypeSArray())
9445 {
9446 uinteger_t dim1 = t1.isTypeSArray().dim.toInteger();
9447 uinteger_t dim2 = t2.isTypeSArray().dim.toInteger();
9448 if (dim1 + 1 == dim2 || dim2 < dim1)
9449 {
9450 auto tsa2 = t2.isTypeSArray();
9451 auto newt = tsa2.next.sarrayOf(dim1).immutableOf();
9452 e2x = castTo(e2x, sc, newt);
9453 exp.e2 = e2x;
9454 }
9455 }
9456
9457 if (e2x.implicitConvTo(e1x.type))
9458 {
9459 if (exp.op != EXP.blit && (e2x.op == EXP.slice && (cast(UnaExp)e2x).e1.isLvalue() || e2x.op == EXP.cast_ && (cast(UnaExp)e2x).e1.isLvalue() || e2x.op != EXP.slice && e2x.isLvalue()))
9460 {
9461 if (e1x.checkPostblit(sc, t1))
9462 return setError();
9463 }
9464
9465 // e2 matches to t1 because of the implicit length match, so
9466 if (isUnaArrayOp(e2x.op) || isBinArrayOp(e2x.op))
9467 {
9468 // convert e1 to e1[]
9469 // e.g. e1[] = a[] + b[];
9470 auto sle = new SliceExp(e1x.loc, e1x, null, null);
9471 sle.arrayop = true;
9472 e1x = sle.expressionSemantic(sc);
9473 }
9474 else
9475 {
9476 // convert e2 to t1 later
9477 // e.g. e1 = [1, 2, 3];
9478 }
9479 }
9480 else
9481 {
9482 if (e2x.implicitConvTo(t1.nextOf().arrayOf()) > MATCH.nomatch)
9483 {
9484 uinteger_t dim1 = (cast(TypeSArray)t1).dim.toInteger();
9485 uinteger_t dim2 = dim1;
9486 if (auto ale = e2x.isArrayLiteralExp())
9487 {
9488 dim2 = ale.elements ? ale.elements.dim : 0;
9489 }
9490 else if (auto se = e2x.isSliceExp())
9491 {
9492 Type tx = toStaticArrayType(se);
9493 if (tx)
9494 dim2 = (cast(TypeSArray)tx).dim.toInteger();
9495 }
9496 if (dim1 != dim2)
9497 {
9498 exp.error("mismatched array lengths, %d and %d", cast(int)dim1, cast(int)dim2);
9499 return setError();
9500 }
9501 }
9502
9503 // May be block or element-wise assignment, so
9504 // convert e1 to e1[]
9505 if (exp.op != EXP.assign)
9506 {
9507 // If multidimensional static array, treat as one large array
9508 //
9509 // Find the appropriate array type depending on the assignment, e.g.
9510 // int[3] = int => int[3]
9511 // int[3][2] = int => int[6]
9512 // int[3][2] = int[] => int[3][2]
9513 // int[3][2][4] + int => int[24]
9514 // int[3][2][4] + int[] => int[3][8]
9515 ulong dim = t1.isTypeSArray().dim.toUInteger();
9516 auto type = t1.nextOf();
9517
9518 for (TypeSArray tsa; (tsa = type.isTypeSArray()) !is null; )
9519 {
9520 import core.checkedint : mulu;
9521
9522 // Accumulate skipped dimensions
9523 bool overflow = false;
9524 dim = mulu(dim, tsa.dim.toUInteger(), overflow);
9525 if (overflow || dim >= uint.max)
9526 {
9527 // dym exceeds maximum array size
9528 exp.error("static array `%s` size overflowed to %llu",
9529 e1x.type.toChars(), cast(ulong) dim);
9530 return setError();
9531 }
9532
9533 // Move to the element type
9534 type = tsa.nextOf().toBasetype();
9535
9536 // Rewrite ex1 as a static array if a matching type was found
9537 if (e2x.implicitConvTo(type) > MATCH.nomatch)
9538 {
9539 e1x.type = type.sarrayOf(dim);
9540 break;
9541 }
9542 }
9543 }
9544 auto sle = new SliceExp(e1x.loc, e1x, null, null);
9545 sle.arrayop = true;
9546 e1x = sle.expressionSemantic(sc);
9547 }
9548 if (e1x.op == EXP.error)
9549 return setResult(e1x);
9550 if (e2x.op == EXP.error)
9551 return setResult(e2x);
9552
9553 exp.e1 = e1x;
9554 exp.e2 = e2x;
9555 t1 = e1x.type.toBasetype();
9556 }
9557 /* Check the mutability of e1.
9558 */
9559 if (auto ale = exp.e1.isArrayLengthExp())
9560 {
9561 // e1 is not an lvalue, but we let code generator handle it
9562
9563 auto ale1x = ale.e1.modifiableLvalue(sc, exp.e1);
9564 if (ale1x.op == EXP.error)
9565 return setResult(ale1x);
9566 ale.e1 = ale1x;
9567
9568 Type tn = ale.e1.type.toBasetype().nextOf();
9569 checkDefCtor(ale.loc, tn);
9570
9571 Identifier hook = global.params.tracegc ? Id._d_arraysetlengthTTrace : Id._d_arraysetlengthT;
9572 if (!verifyHookExist(exp.loc, *sc, Id._d_arraysetlengthTImpl, "resizing arrays"))
9573 return setError();
9574
9575 exp.e2 = exp.e2.expressionSemantic(sc);
9576 auto lc = lastComma(exp.e2);
9577 lc = lc.optimize(WANTvalue);
9578 // use slice expression when arr.length = 0 to avoid runtime call
9579 if(lc.op == EXP.int64 && lc.toInteger() == 0)
9580 {
9581 Expression se = new SliceExp(ale.loc, ale.e1, lc, lc);
9582 Expression as = new AssignExp(ale.loc, ale.e1, se);
9583 as = as.expressionSemantic(sc);
9584 auto res = Expression.combine(as, exp.e2);
9585 res.type = ale.type;
9586 return setResult(res);
9587 }
9588
9589 // Lower to object._d_arraysetlengthTImpl!(typeof(e1))._d_arraysetlengthT{,Trace}(e1, e2)
9590 Expression id = new IdentifierExp(ale.loc, Id.empty);
9591 id = new DotIdExp(ale.loc, id, Id.object);
9592 auto tiargs = new Objects();
9593 tiargs.push(ale.e1.type);
9594 id = new DotTemplateInstanceExp(ale.loc, id, Id._d_arraysetlengthTImpl, tiargs);
9595 id = new DotIdExp(ale.loc, id, hook);
9596 id = id.expressionSemantic(sc);
9597
9598 auto arguments = new Expressions();
9599 arguments.reserve(5);
9600 if (global.params.tracegc)
9601 {
9602 auto funcname = (sc.callsc && sc.callsc.func) ? sc.callsc.func.toPrettyChars() : sc.func.toPrettyChars();
9603 arguments.push(new StringExp(exp.loc, exp.loc.filename.toDString()));
9604 arguments.push(new IntegerExp(exp.loc, exp.loc.linnum, Type.tint32));
9605 arguments.push(new StringExp(exp.loc, funcname.toDString()));
9606 }
9607 arguments.push(ale.e1);
9608 arguments.push(exp.e2);
9609
9610 Expression ce = new CallExp(ale.loc, id, arguments);
9611 auto res = ce.expressionSemantic(sc);
9612 // if (global.params.verbose)
9613 // message("lowered %s =>\n %s", exp.toChars(), res.toChars());
9614 return setResult(res);
9615 }
9616 else if (auto se = exp.e1.isSliceExp())
9617 {
9618 Type tn = se.type.nextOf();
9619 const fun = sc.func;
9620 if (exp.op == EXP.assign && !tn.isMutable() &&
9621 // allow modifiation in module ctor, see
9622 // https://issues.dlang.org/show_bug.cgi?id=9884
9623 (!fun || (fun && !fun.isStaticCtorDeclaration())))
9624 {
9625 exp.error("slice `%s` is not mutable", se.toChars());
9626 return setError();
9627 }
9628
9629 if (exp.op == EXP.assign && !tn.baseElemOf().isAssignable())
9630 {
9631 exp.error("slice `%s` is not mutable, struct `%s` has immutable members",
9632 exp.e1.toChars(), tn.baseElemOf().toChars());
9633 result = ErrorExp.get();
9634 return;
9635 }
9636
9637 // For conditional operator, both branches need conversion.
9638 while (se.e1.op == EXP.slice)
9639 se = cast(SliceExp)se.e1;
9640 if (se.e1.op == EXP.question && se.e1.type.toBasetype().ty == Tsarray)
9641 {
9642 se.e1 = se.e1.modifiableLvalue(sc, exp.e1);
9643 if (se.e1.op == EXP.error)
9644 return setResult(se.e1);
9645 }
9646 }
9647 else
9648 {
9649 if (t1.ty == Tsarray && exp.op == EXP.assign)
9650 {
9651 Type tn = exp.e1.type.nextOf();
9652 if (tn && !tn.baseElemOf().isAssignable())
9653 {
9654 exp.error("array `%s` is not mutable, struct `%s` has immutable members",
9655 exp.e1.toChars(), tn.baseElemOf().toChars());
9656 result = ErrorExp.get();
9657 return;
9658 }
9659 }
9660
9661 Expression e1x = exp.e1;
9662
9663 // Try to do a decent error message with the expression
9664 // before it gets constant folded
9665 if (exp.op == EXP.assign)
9666 e1x = e1x.modifiableLvalue(sc, e1old);
9667
9668 e1x = e1x.optimize(WANTvalue, /*keepLvalue*/ true);
9669
9670 if (e1x.op == EXP.error)
9671 {
9672 result = e1x;
9673 return;
9674 }
9675 exp.e1 = e1x;
9676 }
9677
9678 /* Tweak e2 based on the type of e1.
9679 */
9680 Expression e2x = exp.e2;
9681 Type t2 = e2x.type.toBasetype();
9682
9683 // If it is a array, get the element type. Note that it may be
9684 // multi-dimensional.
9685 Type telem = t1;
9686 while (telem.ty == Tarray)
9687 telem = telem.nextOf();
9688
9689 if (exp.e1.op == EXP.slice && t1.nextOf() &&
9690 (telem.ty != Tvoid || e2x.op == EXP.null_) &&
9691 e2x.implicitConvTo(t1.nextOf()))
9692 {
9693 // Check for block assignment. If it is of type void[], void[][], etc,
9694 // '= null' is the only allowable block assignment (Bug 7493)
9695 exp.memset = MemorySet.blockAssign; // make it easy for back end to tell what this is
9696 e2x = e2x.implicitCastTo(sc, t1.nextOf());
9697 if (exp.op != EXP.blit && e2x.isLvalue() && exp.e1.checkPostblit(sc, t1.nextOf()))
9698 return setError();
9699 }
9700 else if (exp.e1.op == EXP.slice &&
9701 (t2.ty == Tarray || t2.ty == Tsarray) &&
9702 t2.nextOf().implicitConvTo(t1.nextOf()))
9703 {
9704 // Check element-wise assignment.
9705
9706 /* If assigned elements number is known at compile time,
9707 * check the mismatch.
9708 */
9709 SliceExp se1 = cast(SliceExp)exp.e1;
9710 TypeSArray tsa1 = cast(TypeSArray)toStaticArrayType(se1);
9711 TypeSArray tsa2 = null;
9712 if (auto ale = e2x.isArrayLiteralExp())
9713 tsa2 = cast(TypeSArray)t2.nextOf().sarrayOf(ale.elements.dim);
9714 else if (auto se = e2x.isSliceExp())
9715 tsa2 = cast(TypeSArray)toStaticArrayType(se);
9716 else
9717 tsa2 = t2.isTypeSArray();
9718
9719 if (tsa1 && tsa2)
9720 {
9721 uinteger_t dim1 = tsa1.dim.toInteger();
9722 uinteger_t dim2 = tsa2.dim.toInteger();
9723 if (dim1 != dim2)
9724 {
9725 exp.error("mismatched array lengths %d and %d for assignment `%s`", cast(int)dim1, cast(int)dim2, exp.toChars());
9726 return setError();
9727 }
9728 }
9729
9730 if (exp.op != EXP.blit &&
9731 (e2x.op == EXP.slice && (cast(UnaExp)e2x).e1.isLvalue() ||
9732 e2x.op == EXP.cast_ && (cast(UnaExp)e2x).e1.isLvalue() ||
9733 e2x.op != EXP.slice && e2x.isLvalue()))
9734 {
9735 if (exp.e1.checkPostblit(sc, t1.nextOf()))
9736 return setError();
9737 }
9738
9739 if (0 && global.params.warnings != DiagnosticReporting.off && !global.gag && exp.op == EXP.assign &&
9740 e2x.op != EXP.slice && e2x.op != EXP.assign &&
9741 e2x.op != EXP.arrayLiteral && e2x.op != EXP.string_ &&
9742 !(e2x.op == EXP.add || e2x.op == EXP.min ||
9743 e2x.op == EXP.mul || e2x.op == EXP.div ||
9744 e2x.op == EXP.mod || e2x.op == EXP.xor ||
9745 e2x.op == EXP.and || e2x.op == EXP.or ||
9746 e2x.op == EXP.pow ||
9747 e2x.op == EXP.tilde || e2x.op == EXP.negate))
9748 {
9749 const(char)* e1str = exp.e1.toChars();
9750 const(char)* e2str = e2x.toChars();
9751 exp.warning("explicit element-wise assignment `%s = (%s)[]` is better than `%s = %s`", e1str, e2str, e1str, e2str);
9752 }
9753
9754 Type t2n = t2.nextOf();
9755 Type t1n = t1.nextOf();
9756 int offset;
9757 if (t2n.equivalent(t1n) ||
9758 t1n.isBaseOf(t2n, &offset) && offset == 0)
9759 {
9760 /* Allow copy of distinct qualifier elements.
9761 * eg.
9762 * char[] dst; const(char)[] src;
9763 * dst[] = src;
9764 *
9765 * class C {} class D : C {}
9766 * C[2] ca; D[] da;
9767 * ca[] = da;
9768 */
9769 if (isArrayOpValid(e2x))
9770 {
9771 // Don't add CastExp to keep AST for array operations
9772 e2x = e2x.copy();
9773 e2x.type = exp.e1.type.constOf();
9774 }
9775 else
9776 e2x = e2x.castTo(sc, exp.e1.type.constOf());
9777 }
9778 else
9779 {
9780 /* https://issues.dlang.org/show_bug.cgi?id=15778
9781 * A string literal has an array type of immutable
9782 * elements by default, and normally it cannot be convertible to
9783 * array type of mutable elements. But for element-wise assignment,
9784 * elements need to be const at best. So we should give a chance
9785 * to change code unit size for polysemous string literal.
9786 */
9787 if (e2x.op == EXP.string_)
9788 e2x = e2x.implicitCastTo(sc, exp.e1.type.constOf());
9789 else
9790 e2x = e2x.implicitCastTo(sc, exp.e1.type);
9791 }
9792 if (t1n.toBasetype.ty == Tvoid && t2n.toBasetype.ty == Tvoid)
9793 {
9794 if (!sc.intypeof && sc.func && !(sc.flags & SCOPE.debug_) && sc.func.setUnsafe())
9795 {
9796 exp.error("cannot copy `void[]` to `void[]` in `@safe` code");
9797 return setError();
9798 }
9799 }
9800 }
9801 else
9802 {
9803 if (0 && global.params.warnings != DiagnosticReporting.off && !global.gag && exp.op == EXP.assign &&
9804 t1.ty == Tarray && t2.ty == Tsarray &&
9805 e2x.op != EXP.slice &&
9806 t2.implicitConvTo(t1))
9807 {
9808 // Disallow ar[] = sa (Converted to ar[] = sa[])
9809 // Disallow da = sa (Converted to da = sa[])
9810 const(char)* e1str = exp.e1.toChars();
9811 const(char)* e2str = e2x.toChars();
9812 const(char)* atypestr = exp.e1.op == EXP.slice ? "element-wise" : "slice";
9813 exp.warning("explicit %s assignment `%s = (%s)[]` is better than `%s = %s`", atypestr, e1str, e2str, e1str, e2str);
9814 }
9815 if (exp.op == EXP.blit)
9816 e2x = e2x.castTo(sc, exp.e1.type);
9817 else
9818 {
9819 e2x = e2x.implicitCastTo(sc, exp.e1.type);
9820
9821 // Fix Issue 13435: https://issues.dlang.org/show_bug.cgi?id=13435
9822
9823 // If the implicit cast has failed and the assign expression is
9824 // the initialization of a struct member field
9825 if (e2x.op == EXP.error && exp.op == EXP.construct && t1.ty == Tstruct)
9826 {
9827 scope sd = (cast(TypeStruct)t1).sym;
9828 Dsymbol opAssign = search_function(sd, Id.assign);
9829
9830 // and the struct defines an opAssign
9831 if (opAssign)
9832 {
9833 // offer more information about the cause of the problem
9834 errorSupplemental(exp.loc,
9835 "`%s` is the first assignment of `%s` therefore it represents its initialization",
9836 exp.toChars(), exp.e1.toChars());
9837 errorSupplemental(exp.loc,
9838 "`opAssign` methods are not used for initialization, but for subsequent assignments");
9839 }
9840 }
9841 }
9842 }
9843 if (e2x.op == EXP.error)
9844 {
9845 result = e2x;
9846 return;
9847 }
9848 exp.e2 = e2x;
9849 t2 = exp.e2.type.toBasetype();
9850
9851 /* Look for array operations
9852 */
9853 if ((t2.ty == Tarray || t2.ty == Tsarray) && isArrayOpValid(exp.e2))
9854 {
9855 // Look for valid array operations
9856 if (exp.memset != MemorySet.blockAssign &&
9857 exp.e1.op == EXP.slice &&
9858 (isUnaArrayOp(exp.e2.op) || isBinArrayOp(exp.e2.op)))
9859 {
9860 exp.type = exp.e1.type;
9861 if (exp.op == EXP.construct) // https://issues.dlang.org/show_bug.cgi?id=10282
9862 // tweak mutability of e1 element
9863 exp.e1.type = exp.e1.type.nextOf().mutableOf().arrayOf();
9864 result = arrayOp(exp, sc);
9865 return;
9866 }
9867
9868 // Drop invalid array operations in e2
9869 // d = a[] + b[], d = (a[] + b[])[0..2], etc
9870 if (checkNonAssignmentArrayOp(exp.e2, exp.memset != MemorySet.blockAssign && exp.op == EXP.assign))
9871 return setError();
9872
9873 // Remains valid array assignments
9874 // d = d[], d = [1,2,3], etc
9875 }
9876
9877 /* Don't allow assignment to classes that were allocated on the stack with:
9878 * scope Class c = new Class();
9879 */
9880 if (exp.e1.op == EXP.variable && exp.op == EXP.assign)
9881 {
9882 VarExp ve = cast(VarExp)exp.e1;
9883 VarDeclaration vd = ve.var.isVarDeclaration();
9884 if (vd && vd.onstack)
9885 {
9886 assert(t1.ty == Tclass);
9887 exp.error("cannot rebind scope variables");
9888 }
9889 }
9890
9891 if (exp.e1.op == EXP.variable && (cast(VarExp)exp.e1).var.ident == Id.ctfe)
9892 {
9893 exp.error("cannot modify compiler-generated variable `__ctfe`");
9894 }
9895
9896 exp.type = exp.e1.type;
9897 assert(exp.type);
9898 auto res = exp.op == EXP.assign ? exp.reorderSettingAAElem(sc) : exp;
9899 Expression tmp;
9900 /* https://issues.dlang.org/show_bug.cgi?id=22366
9901 *
9902 * `reorderSettingAAElem` creates a tree of comma expressions, however,
9903 * `checkAssignExp` expects only AssignExps.
9904 */
9905 checkAssignEscape(sc, Expression.extractLast(res, tmp), false, false);
9906
9907 if (auto ae = res.isConstructExp())
9908 {
9909 Type t1b = ae.e1.type.toBasetype();
9910 if (t1b.ty != Tsarray && t1b.ty != Tarray)
9911 return setResult(res);
9912
9913 /* Do not lower Rvalues and references, as they need to be moved,
9914 * not copied.
9915 * Skip the lowering when the RHS is an array literal, as e2ir
9916 * already handles such cases more elegantly.
9917 */
9918 const isArrayCtor =
9919 (ae.e1.isSliceExp || ae.e1.type.ty == Tsarray) &&
9920 ae.e2.isLvalue &&
9921 !(ae.e1.isVarExp &&
9922 ae.e1.isVarExp.var.isVarDeclaration.isReference) &&
9923 (ae.e2.isVarExp ||
9924 ae.e2.isSliceExp ||
9925 (ae.e2.type.ty == Tsarray && !ae.e2.isArrayLiteralExp)) &&
9926 ae.e1.type.nextOf &&
9927 ae.e2.type.nextOf &&
9928 ae.e1.type.nextOf.mutableOf.equals(ae.e2.type.nextOf.mutableOf);
9929
9930 /* Unlike isArrayCtor above, lower all Rvalues. If the RHS is a literal,
9931 * then we do want to make a temporary for it and call its destructor.
9932 */
9933 const isArraySetCtor =
9934 (ae.e1.isSliceExp || ae.e1.type.ty == Tsarray) &&
9935 (ae.e2.type.ty == Tstruct || ae.e2.type.ty == Tsarray) &&
9936 ae.e1.type.nextOf &&
9937 ae.e1.type.nextOf.equivalent(ae.e2.type);
9938
9939 if (isArrayCtor || isArraySetCtor)
9940 {
9941 const ts = t1b.nextOf().baseElemOf().isTypeStruct();
9942 if (!ts || (!ts.sym.postblit && !ts.sym.dtor))
9943 return setResult(res);
9944
9945 auto func = isArrayCtor ? Id._d_arrayctor : Id._d_arraysetctor;
9946 const other = isArrayCtor ? "other array" : "value";
9947 if (!verifyHookExist(exp.loc, *sc, func, "construct array with " ~ other, Id.object))
9948 return setError();
9949
9950 // Lower to object._d_array{,set}ctor(e1, e2)
9951 Expression id = new IdentifierExp(exp.loc, Id.empty);
9952 id = new DotIdExp(exp.loc, id, Id.object);
9953 id = new DotIdExp(exp.loc, id, func);
9954
9955 auto arguments = new Expressions();
9956 arguments.push(new CastExp(ae.loc, ae.e1, ae.e1.type.nextOf.arrayOf).expressionSemantic(sc));
9957 if (isArrayCtor)
9958 {
9959 arguments.push(new CastExp(ae.loc, ae.e2, ae.e2.type.nextOf.arrayOf).expressionSemantic(sc));
9960 Expression ce = new CallExp(exp.loc, id, arguments);
9961 res = ce.expressionSemantic(sc);
9962 }
9963 else
9964 {
9965 Expression e0;
9966 // If ae.e2 is not a variable, construct a temp variable, as _d_arraysetctor requires `ref` access
9967 if (!ae.e2.isVarExp)
9968 {
9969 auto vd = copyToTemp(STC.scope_, "__setctor", ae.e2);
9970 e0 = new DeclarationExp(vd.loc, vd).expressionSemantic(sc);
9971 arguments.push(new VarExp(vd.loc, vd).expressionSemantic(sc));
9972 }
9973 else
9974 arguments.push(ae.e2);
9975
9976 Expression ce = new CallExp(exp.loc, id, arguments);
9977 res = Expression.combine(e0, ce).expressionSemantic(sc);
9978 }
9979
9980 if (global.params.verbose)
9981 message("lowered %s =>\n %s", exp.toChars(), res.toChars());
9982 }
9983 }
9984
9985 return setResult(res);
9986 }
9987
visit(PowAssignExp exp)9988 override void visit(PowAssignExp exp)
9989 {
9990 if (exp.type)
9991 {
9992 result = exp;
9993 return;
9994 }
9995
9996 Expression e = exp.op_overload(sc);
9997 if (e)
9998 {
9999 result = e;
10000 return;
10001 }
10002
10003 if (exp.e1.checkReadModifyWrite(exp.op, exp.e2))
10004 return setError();
10005
10006 assert(exp.e1.type && exp.e2.type);
10007 if (exp.e1.op == EXP.slice || exp.e1.type.ty == Tarray || exp.e1.type.ty == Tsarray)
10008 {
10009 if (checkNonAssignmentArrayOp(exp.e1))
10010 return setError();
10011
10012 // T[] ^^= ...
10013 if (exp.e2.implicitConvTo(exp.e1.type.nextOf()))
10014 {
10015 // T[] ^^= T
10016 exp.e2 = exp.e2.castTo(sc, exp.e1.type.nextOf());
10017 }
10018 else if (Expression ex = typeCombine(exp, sc))
10019 {
10020 result = ex;
10021 return;
10022 }
10023
10024 // Check element types are arithmetic
10025 Type tb1 = exp.e1.type.nextOf().toBasetype();
10026 Type tb2 = exp.e2.type.toBasetype();
10027 if (tb2.ty == Tarray || tb2.ty == Tsarray)
10028 tb2 = tb2.nextOf().toBasetype();
10029 if ((tb1.isintegral() || tb1.isfloating()) && (tb2.isintegral() || tb2.isfloating()))
10030 {
10031 exp.type = exp.e1.type;
10032 result = arrayOp(exp, sc);
10033 return;
10034 }
10035 }
10036 else
10037 {
10038 exp.e1 = exp.e1.modifiableLvalue(sc, exp.e1);
10039 }
10040
10041 if ((exp.e1.type.isintegral() || exp.e1.type.isfloating()) && (exp.e2.type.isintegral() || exp.e2.type.isfloating()))
10042 {
10043 Expression e0 = null;
10044 e = exp.reorderSettingAAElem(sc);
10045 e = Expression.extractLast(e, e0);
10046 assert(e == exp);
10047
10048 if (exp.e1.op == EXP.variable)
10049 {
10050 // Rewrite: e1 = e1 ^^ e2
10051 e = new PowExp(exp.loc, exp.e1.syntaxCopy(), exp.e2);
10052 e = new AssignExp(exp.loc, exp.e1, e);
10053 }
10054 else
10055 {
10056 // Rewrite: ref tmp = e1; tmp = tmp ^^ e2
10057 auto v = copyToTemp(STC.ref_, "__powtmp", exp.e1);
10058 auto de = new DeclarationExp(exp.e1.loc, v);
10059 auto ve = new VarExp(exp.e1.loc, v);
10060 e = new PowExp(exp.loc, ve, exp.e2);
10061 e = new AssignExp(exp.loc, new VarExp(exp.e1.loc, v), e);
10062 e = new CommaExp(exp.loc, de, e);
10063 }
10064 e = Expression.combine(e0, e);
10065 e = e.expressionSemantic(sc);
10066 result = e;
10067 return;
10068 }
10069 result = exp.incompatibleTypes();
10070 }
10071
visit(CatAssignExp exp)10072 override void visit(CatAssignExp exp)
10073 {
10074 if (exp.type)
10075 {
10076 result = exp;
10077 return;
10078 }
10079
10080 //printf("CatAssignExp::semantic() %s\n", exp.toChars());
10081 Expression e = exp.op_overload(sc);
10082 if (e)
10083 {
10084 result = e;
10085 return;
10086 }
10087
10088 if (SliceExp se = exp.e1.isSliceExp())
10089 {
10090 if (se.e1.type.toBasetype().ty == Tsarray)
10091 {
10092 exp.error("cannot append to static array `%s`", se.e1.type.toChars());
10093 return setError();
10094 }
10095 }
10096
10097 exp.e1 = exp.e1.modifiableLvalue(sc, exp.e1);
10098 if (exp.e1.op == EXP.error)
10099 {
10100 result = exp.e1;
10101 return;
10102 }
10103 if (exp.e2.op == EXP.error)
10104 {
10105 result = exp.e2;
10106 return;
10107 }
10108
10109 if (checkNonAssignmentArrayOp(exp.e2))
10110 return setError();
10111
10112 Type tb1 = exp.e1.type.toBasetype();
10113 Type tb1next = tb1.nextOf();
10114 Type tb2 = exp.e2.type.toBasetype();
10115
10116 /* Possibilities:
10117 * EXP.concatenateAssign: appending T[] to T[]
10118 * EXP.concatenateElemAssign: appending T to T[]
10119 * EXP.concatenateDcharAssign: appending dchar to T[]
10120 */
10121 if ((tb1.ty == Tarray) &&
10122 (tb2.ty == Tarray || tb2.ty == Tsarray) &&
10123 (exp.e2.implicitConvTo(exp.e1.type) ||
10124 (tb2.nextOf().implicitConvTo(tb1next) &&
10125 (tb2.nextOf().size(Loc.initial) == tb1next.size(Loc.initial)))))
10126 {
10127 // EXP.concatenateAssign
10128 assert(exp.op == EXP.concatenateAssign);
10129 if (exp.e1.checkPostblit(sc, tb1next))
10130 return setError();
10131
10132 exp.e2 = exp.e2.castTo(sc, exp.e1.type);
10133 }
10134 else if ((tb1.ty == Tarray) && exp.e2.implicitConvTo(tb1next))
10135 {
10136 /* https://issues.dlang.org/show_bug.cgi?id=19782
10137 *
10138 * If e2 is implicitly convertible to tb1next, the conversion
10139 * might be done through alias this, in which case, e2 needs to
10140 * be modified accordingly (e2 => e2.aliasthis).
10141 */
10142 if (tb2.ty == Tstruct && (cast(TypeStruct)tb2).implicitConvToThroughAliasThis(tb1next))
10143 goto Laliasthis;
10144 if (tb2.ty == Tclass && (cast(TypeClass)tb2).implicitConvToThroughAliasThis(tb1next))
10145 goto Laliasthis;
10146 // Append element
10147 if (exp.e2.checkPostblit(sc, tb2))
10148 return setError();
10149
10150 if (checkNewEscape(sc, exp.e2, false))
10151 return setError();
10152
10153 exp = new CatElemAssignExp(exp.loc, exp.type, exp.e1, exp.e2.castTo(sc, tb1next));
10154 exp.e2 = doCopyOrMove(sc, exp.e2);
10155 }
10156 else if (tb1.ty == Tarray &&
10157 (tb1next.ty == Tchar || tb1next.ty == Twchar) &&
10158 exp.e2.type.ty != tb1next.ty &&
10159 exp.e2.implicitConvTo(Type.tdchar))
10160 {
10161 // Append dchar to char[] or wchar[]
10162 exp = new CatDcharAssignExp(exp.loc, exp.type, exp.e1, exp.e2.castTo(sc, Type.tdchar));
10163
10164 /* Do not allow appending wchar to char[] because if wchar happens
10165 * to be a surrogate pair, nothing good can result.
10166 */
10167 }
10168 else
10169 {
10170 // Try alias this on first operand
10171 static Expression tryAliasThisForLhs(BinAssignExp exp, Scope* sc)
10172 {
10173 AggregateDeclaration ad1 = isAggregate(exp.e1.type);
10174 if (!ad1 || !ad1.aliasthis)
10175 return null;
10176
10177 /* Rewrite (e1 op e2) as:
10178 * (e1.aliasthis op e2)
10179 */
10180 if (isRecursiveAliasThis(exp.att1, exp.e1.type))
10181 return null;
10182 //printf("att %s e1 = %s\n", Token.toChars(e.op), e.e1.type.toChars());
10183 Expression e1 = new DotIdExp(exp.loc, exp.e1, ad1.aliasthis.ident);
10184 BinExp be = cast(BinExp)exp.copy();
10185 be.e1 = e1;
10186 return be.trySemantic(sc);
10187 }
10188
10189 // Try alias this on second operand
10190 static Expression tryAliasThisForRhs(BinAssignExp exp, Scope* sc)
10191 {
10192 AggregateDeclaration ad2 = isAggregate(exp.e2.type);
10193 if (!ad2 || !ad2.aliasthis)
10194 return null;
10195 /* Rewrite (e1 op e2) as:
10196 * (e1 op e2.aliasthis)
10197 */
10198 if (isRecursiveAliasThis(exp.att2, exp.e2.type))
10199 return null;
10200 //printf("att %s e2 = %s\n", Token.toChars(e.op), e.e2.type.toChars());
10201 Expression e2 = new DotIdExp(exp.loc, exp.e2, ad2.aliasthis.ident);
10202 BinExp be = cast(BinExp)exp.copy();
10203 be.e2 = e2;
10204 return be.trySemantic(sc);
10205 }
10206
10207 Laliasthis:
10208 result = tryAliasThisForLhs(exp, sc);
10209 if (result)
10210 return;
10211
10212 result = tryAliasThisForRhs(exp, sc);
10213 if (result)
10214 return;
10215
10216 exp.error("cannot append type `%s` to type `%s`", tb2.toChars(), tb1.toChars());
10217 return setError();
10218 }
10219
10220 if (exp.e2.checkValue() || exp.e2.checkSharedAccess(sc))
10221 return setError();
10222
10223 exp.type = exp.e1.type;
10224 auto res = exp.reorderSettingAAElem(sc);
10225 if ((exp.op == EXP.concatenateElemAssign || exp.op == EXP.concatenateDcharAssign) &&
10226 global.params.useDIP1000 == FeatureState.enabled)
10227 checkAssignEscape(sc, res, false, false);
10228 result = res;
10229 }
10230
visit(AddExp exp)10231 override void visit(AddExp exp)
10232 {
10233 static if (LOGSEMANTIC)
10234 {
10235 printf("AddExp::semantic('%s')\n", exp.toChars());
10236 }
10237 if (exp.type)
10238 {
10239 result = exp;
10240 return;
10241 }
10242
10243 if (Expression ex = binSemanticProp(exp, sc))
10244 {
10245 result = ex;
10246 return;
10247 }
10248 Expression e = exp.op_overload(sc);
10249 if (e)
10250 {
10251 result = e;
10252 return;
10253 }
10254
10255 /* ImportC: convert arrays to pointers, functions to pointers to functions
10256 */
10257 exp.e1 = exp.e1.arrayFuncConv(sc);
10258 exp.e2 = exp.e2.arrayFuncConv(sc);
10259
10260 Type tb1 = exp.e1.type.toBasetype();
10261 Type tb2 = exp.e2.type.toBasetype();
10262
10263 bool err = false;
10264 if (tb1.ty == Tdelegate || tb1.isPtrToFunction())
10265 {
10266 err |= exp.e1.checkArithmetic() || exp.e1.checkSharedAccess(sc);
10267 }
10268 if (tb2.ty == Tdelegate || tb2.isPtrToFunction())
10269 {
10270 err |= exp.e2.checkArithmetic() || exp.e2.checkSharedAccess(sc);
10271 }
10272 if (err)
10273 return setError();
10274
10275 if (tb1.ty == Tpointer && exp.e2.type.isintegral() || tb2.ty == Tpointer && exp.e1.type.isintegral())
10276 {
10277 result = scaleFactor(exp, sc);
10278 return;
10279 }
10280
10281 if (tb1.ty == Tpointer && tb2.ty == Tpointer)
10282 {
10283 result = exp.incompatibleTypes();
10284 return;
10285 }
10286
10287 if (Expression ex = typeCombine(exp, sc))
10288 {
10289 result = ex;
10290 return;
10291 }
10292
10293 Type tb = exp.type.toBasetype();
10294 if (tb.ty == Tarray || tb.ty == Tsarray)
10295 {
10296 if (!isArrayOpValid(exp))
10297 {
10298 result = arrayOpInvalidError(exp);
10299 return;
10300 }
10301 result = exp;
10302 return;
10303 }
10304
10305 tb1 = exp.e1.type.toBasetype();
10306 if (!target.isVectorOpSupported(tb1, exp.op, tb2))
10307 {
10308 result = exp.incompatibleTypes();
10309 return;
10310 }
10311 if ((tb1.isreal() && exp.e2.type.isimaginary()) || (tb1.isimaginary() && exp.e2.type.isreal()))
10312 {
10313 switch (exp.type.toBasetype().ty)
10314 {
10315 case Tfloat32:
10316 case Timaginary32:
10317 exp.type = Type.tcomplex32;
10318 break;
10319
10320 case Tfloat64:
10321 case Timaginary64:
10322 exp.type = Type.tcomplex64;
10323 break;
10324
10325 case Tfloat80:
10326 case Timaginary80:
10327 exp.type = Type.tcomplex80;
10328 break;
10329
10330 default:
10331 assert(0);
10332 }
10333 }
10334 result = exp;
10335 }
10336
visit(MinExp exp)10337 override void visit(MinExp exp)
10338 {
10339 static if (LOGSEMANTIC)
10340 {
10341 printf("MinExp::semantic('%s')\n", exp.toChars());
10342 }
10343 if (exp.type)
10344 {
10345 result = exp;
10346 return;
10347 }
10348
10349 if (Expression ex = binSemanticProp(exp, sc))
10350 {
10351 result = ex;
10352 return;
10353 }
10354 Expression e = exp.op_overload(sc);
10355 if (e)
10356 {
10357 result = e;
10358 return;
10359 }
10360
10361 /* ImportC: convert arrays to pointers, functions to pointers to functions
10362 */
10363 exp.e1 = exp.e1.arrayFuncConv(sc);
10364 exp.e2 = exp.e2.arrayFuncConv(sc);
10365
10366 Type t1 = exp.e1.type.toBasetype();
10367 Type t2 = exp.e2.type.toBasetype();
10368
10369 bool err = false;
10370 if (t1.ty == Tdelegate || t1.isPtrToFunction())
10371 {
10372 err |= exp.e1.checkArithmetic() || exp.e1.checkSharedAccess(sc);
10373 }
10374 if (t2.ty == Tdelegate || t2.isPtrToFunction())
10375 {
10376 err |= exp.e2.checkArithmetic() || exp.e2.checkSharedAccess(sc);
10377 }
10378 if (err)
10379 return setError();
10380
10381 if (t1.ty == Tpointer)
10382 {
10383 if (t2.ty == Tpointer)
10384 {
10385 // https://dlang.org/spec/expression.html#add_expressions
10386 // "If both operands are pointers, and the operator is -, the pointers are
10387 // subtracted and the result is divided by the size of the type pointed to
10388 // by the operands. It is an error if the pointers point to different types."
10389 Type p1 = t1.nextOf();
10390 Type p2 = t2.nextOf();
10391
10392 if (!p1.equivalent(p2))
10393 {
10394 // Deprecation to remain for at least a year, after which this should be
10395 // changed to an error
10396 // See https://github.com/dlang/dmd/pull/7332
10397 deprecation(exp.loc,
10398 "cannot subtract pointers to different types: `%s` and `%s`.",
10399 t1.toChars(), t2.toChars());
10400 }
10401
10402 // Need to divide the result by the stride
10403 // Replace (ptr - ptr) with (ptr - ptr) / stride
10404 long stride;
10405
10406 // make sure pointer types are compatible
10407 if (Expression ex = typeCombine(exp, sc))
10408 {
10409 result = ex;
10410 return;
10411 }
10412
10413 exp.type = Type.tptrdiff_t;
10414 stride = t2.nextOf().size();
10415 if (stride == 0)
10416 {
10417 e = new IntegerExp(exp.loc, 0, Type.tptrdiff_t);
10418 }
10419 else if (stride == cast(long)SIZE_INVALID)
10420 e = ErrorExp.get();
10421 else
10422 {
10423 e = new DivExp(exp.loc, exp, new IntegerExp(Loc.initial, stride, Type.tptrdiff_t));
10424 e.type = Type.tptrdiff_t;
10425 }
10426 }
10427 else if (t2.isintegral())
10428 e = scaleFactor(exp, sc);
10429 else
10430 {
10431 exp.error("can't subtract `%s` from pointer", t2.toChars());
10432 e = ErrorExp.get();
10433 }
10434 result = e;
10435 return;
10436 }
10437 if (t2.ty == Tpointer)
10438 {
10439 exp.type = exp.e2.type;
10440 exp.error("can't subtract pointer from `%s`", exp.e1.type.toChars());
10441 return setError();
10442 }
10443
10444 if (Expression ex = typeCombine(exp, sc))
10445 {
10446 result = ex;
10447 return;
10448 }
10449
10450 Type tb = exp.type.toBasetype();
10451 if (tb.ty == Tarray || tb.ty == Tsarray)
10452 {
10453 if (!isArrayOpValid(exp))
10454 {
10455 result = arrayOpInvalidError(exp);
10456 return;
10457 }
10458 result = exp;
10459 return;
10460 }
10461
10462 t1 = exp.e1.type.toBasetype();
10463 t2 = exp.e2.type.toBasetype();
10464 if (!target.isVectorOpSupported(t1, exp.op, t2))
10465 {
10466 result = exp.incompatibleTypes();
10467 return;
10468 }
10469 if ((t1.isreal() && t2.isimaginary()) || (t1.isimaginary() && t2.isreal()))
10470 {
10471 switch (exp.type.ty)
10472 {
10473 case Tfloat32:
10474 case Timaginary32:
10475 exp.type = Type.tcomplex32;
10476 break;
10477
10478 case Tfloat64:
10479 case Timaginary64:
10480 exp.type = Type.tcomplex64;
10481 break;
10482
10483 case Tfloat80:
10484 case Timaginary80:
10485 exp.type = Type.tcomplex80;
10486 break;
10487
10488 default:
10489 assert(0);
10490 }
10491 }
10492 result = exp;
10493 return;
10494 }
10495
visit(CatExp exp)10496 override void visit(CatExp exp)
10497 {
10498 // https://dlang.org/spec/expression.html#cat_expressions
10499 //printf("CatExp.semantic() %s\n", toChars());
10500 if (exp.type)
10501 {
10502 result = exp;
10503 return;
10504 }
10505
10506 if (Expression ex = binSemanticProp(exp, sc))
10507 {
10508 result = ex;
10509 return;
10510 }
10511 Expression e = exp.op_overload(sc);
10512 if (e)
10513 {
10514 result = e;
10515 return;
10516 }
10517
10518 Type tb1 = exp.e1.type.toBasetype();
10519 Type tb2 = exp.e2.type.toBasetype();
10520
10521 auto f1 = checkNonAssignmentArrayOp(exp.e1);
10522 auto f2 = checkNonAssignmentArrayOp(exp.e2);
10523 if (f1 || f2)
10524 return setError();
10525
10526 Type tb1next = tb1.nextOf();
10527 Type tb2next = tb2.nextOf();
10528
10529 // Check for: array ~ array
10530 if (tb1next && tb2next && (tb1next.implicitConvTo(tb2next) >= MATCH.constant || tb2next.implicitConvTo(tb1next) >= MATCH.constant || exp.e1.op == EXP.arrayLiteral && exp.e1.implicitConvTo(tb2) || exp.e2.op == EXP.arrayLiteral && exp.e2.implicitConvTo(tb1)))
10531 {
10532 /* https://issues.dlang.org/show_bug.cgi?id=9248
10533 * Here to avoid the case of:
10534 * void*[] a = [cast(void*)1];
10535 * void*[] b = [cast(void*)2];
10536 * a ~ b;
10537 * becoming:
10538 * a ~ [cast(void*)b];
10539 */
10540
10541 /* https://issues.dlang.org/show_bug.cgi?id=14682
10542 * Also to avoid the case of:
10543 * int[][] a;
10544 * a ~ [];
10545 * becoming:
10546 * a ~ cast(int[])[];
10547 */
10548 goto Lpeer;
10549 }
10550
10551 // Check for: array ~ element
10552 if ((tb1.ty == Tsarray || tb1.ty == Tarray) && tb2.ty != Tvoid)
10553 {
10554 if (exp.e1.op == EXP.arrayLiteral)
10555 {
10556 exp.e2 = doCopyOrMove(sc, exp.e2);
10557 // https://issues.dlang.org/show_bug.cgi?id=14686
10558 // Postblit call appears in AST, and this is
10559 // finally translated to an ArrayLiteralExp in below optimize().
10560 }
10561 else if (exp.e1.op == EXP.string_)
10562 {
10563 // No postblit call exists on character (integer) value.
10564 }
10565 else
10566 {
10567 if (exp.e2.checkPostblit(sc, tb2))
10568 return setError();
10569 // Postblit call will be done in runtime helper function
10570 }
10571
10572 if (exp.e1.op == EXP.arrayLiteral && exp.e1.implicitConvTo(tb2.arrayOf()))
10573 {
10574 exp.e1 = exp.e1.implicitCastTo(sc, tb2.arrayOf());
10575 exp.type = tb2.arrayOf();
10576 goto L2elem;
10577 }
10578 if (exp.e2.implicitConvTo(tb1next) >= MATCH.convert)
10579 {
10580 exp.e2 = exp.e2.implicitCastTo(sc, tb1next);
10581 exp.type = tb1next.arrayOf();
10582 L2elem:
10583 if (tb2.ty == Tarray || tb2.ty == Tsarray)
10584 {
10585 // Make e2 into [e2]
10586 exp.e2 = new ArrayLiteralExp(exp.e2.loc, exp.type, exp.e2);
10587 }
10588 else if (checkNewEscape(sc, exp.e2, false))
10589 return setError();
10590 result = exp.optimize(WANTvalue);
10591 return;
10592 }
10593 }
10594 // Check for: element ~ array
10595 if ((tb2.ty == Tsarray || tb2.ty == Tarray) && tb1.ty != Tvoid)
10596 {
10597 if (exp.e2.op == EXP.arrayLiteral)
10598 {
10599 exp.e1 = doCopyOrMove(sc, exp.e1);
10600 }
10601 else if (exp.e2.op == EXP.string_)
10602 {
10603 }
10604 else
10605 {
10606 if (exp.e1.checkPostblit(sc, tb1))
10607 return setError();
10608 }
10609
10610 if (exp.e2.op == EXP.arrayLiteral && exp.e2.implicitConvTo(tb1.arrayOf()))
10611 {
10612 exp.e2 = exp.e2.implicitCastTo(sc, tb1.arrayOf());
10613 exp.type = tb1.arrayOf();
10614 goto L1elem;
10615 }
10616 if (exp.e1.implicitConvTo(tb2next) >= MATCH.convert)
10617 {
10618 exp.e1 = exp.e1.implicitCastTo(sc, tb2next);
10619 exp.type = tb2next.arrayOf();
10620 L1elem:
10621 if (tb1.ty == Tarray || tb1.ty == Tsarray)
10622 {
10623 // Make e1 into [e1]
10624 exp.e1 = new ArrayLiteralExp(exp.e1.loc, exp.type, exp.e1);
10625 }
10626 else if (checkNewEscape(sc, exp.e1, false))
10627 return setError();
10628 result = exp.optimize(WANTvalue);
10629 return;
10630 }
10631 }
10632
10633 Lpeer:
10634 if ((tb1.ty == Tsarray || tb1.ty == Tarray) && (tb2.ty == Tsarray || tb2.ty == Tarray) && (tb1next.mod || tb2next.mod) && (tb1next.mod != tb2next.mod))
10635 {
10636 Type t1 = tb1next.mutableOf().constOf().arrayOf();
10637 Type t2 = tb2next.mutableOf().constOf().arrayOf();
10638 if (exp.e1.op == EXP.string_ && !(cast(StringExp)exp.e1).committed)
10639 exp.e1.type = t1;
10640 else
10641 exp.e1 = exp.e1.castTo(sc, t1);
10642 if (exp.e2.op == EXP.string_ && !(cast(StringExp)exp.e2).committed)
10643 exp.e2.type = t2;
10644 else
10645 exp.e2 = exp.e2.castTo(sc, t2);
10646 }
10647
10648 if (Expression ex = typeCombine(exp, sc))
10649 {
10650 result = ex;
10651 return;
10652 }
10653 exp.type = exp.type.toHeadMutable();
10654
10655 Type tb = exp.type.toBasetype();
10656 if (tb.ty == Tsarray)
10657 exp.type = tb.nextOf().arrayOf();
10658 if (exp.type.ty == Tarray && tb1next && tb2next && tb1next.mod != tb2next.mod)
10659 {
10660 exp.type = exp.type.nextOf().toHeadMutable().arrayOf();
10661 }
10662 if (Type tbn = tb.nextOf())
10663 {
10664 if (exp.checkPostblit(sc, tbn))
10665 return setError();
10666 }
10667 Type t1 = exp.e1.type.toBasetype();
10668 Type t2 = exp.e2.type.toBasetype();
10669 if ((t1.ty == Tarray || t1.ty == Tsarray) &&
10670 (t2.ty == Tarray || t2.ty == Tsarray))
10671 {
10672 // Normalize to ArrayLiteralExp or StringExp as far as possible
10673 e = exp.optimize(WANTvalue);
10674 }
10675 else
10676 {
10677 //printf("(%s) ~ (%s)\n", e1.toChars(), e2.toChars());
10678 result = exp.incompatibleTypes();
10679 return;
10680 }
10681
10682 result = e;
10683 }
10684
visit(MulExp exp)10685 override void visit(MulExp exp)
10686 {
10687 version (none)
10688 {
10689 printf("MulExp::semantic() %s\n", exp.toChars());
10690 }
10691 if (exp.type)
10692 {
10693 result = exp;
10694 return;
10695 }
10696
10697 if (Expression ex = binSemanticProp(exp, sc))
10698 {
10699 result = ex;
10700 return;
10701 }
10702 Expression e = exp.op_overload(sc);
10703 if (e)
10704 {
10705 result = e;
10706 return;
10707 }
10708
10709 if (Expression ex = typeCombine(exp, sc))
10710 {
10711 result = ex;
10712 return;
10713 }
10714
10715 Type tb = exp.type.toBasetype();
10716 if (tb.ty == Tarray || tb.ty == Tsarray)
10717 {
10718 if (!isArrayOpValid(exp))
10719 {
10720 result = arrayOpInvalidError(exp);
10721 return;
10722 }
10723 result = exp;
10724 return;
10725 }
10726
10727 if (exp.checkArithmeticBin() || exp.checkSharedAccessBin(sc))
10728 return setError();
10729
10730 if (exp.type.isfloating())
10731 {
10732 Type t1 = exp.e1.type;
10733 Type t2 = exp.e2.type;
10734
10735 if (t1.isreal())
10736 {
10737 exp.type = t2;
10738 }
10739 else if (t2.isreal())
10740 {
10741 exp.type = t1;
10742 }
10743 else if (t1.isimaginary())
10744 {
10745 if (t2.isimaginary())
10746 {
10747 switch (t1.toBasetype().ty)
10748 {
10749 case Timaginary32:
10750 exp.type = Type.tfloat32;
10751 break;
10752
10753 case Timaginary64:
10754 exp.type = Type.tfloat64;
10755 break;
10756
10757 case Timaginary80:
10758 exp.type = Type.tfloat80;
10759 break;
10760
10761 default:
10762 assert(0);
10763 }
10764
10765 // iy * iv = -yv
10766 exp.e1.type = exp.type;
10767 exp.e2.type = exp.type;
10768 e = new NegExp(exp.loc, exp);
10769 e = e.expressionSemantic(sc);
10770 result = e;
10771 return;
10772 }
10773 else
10774 exp.type = t2; // t2 is complex
10775 }
10776 else if (t2.isimaginary())
10777 {
10778 exp.type = t1; // t1 is complex
10779 }
10780 }
10781 else if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype()))
10782 {
10783 result = exp.incompatibleTypes();
10784 return;
10785 }
10786 result = exp;
10787 }
10788
visit(DivExp exp)10789 override void visit(DivExp exp)
10790 {
10791 if (exp.type)
10792 {
10793 result = exp;
10794 return;
10795 }
10796
10797 if (Expression ex = binSemanticProp(exp, sc))
10798 {
10799 result = ex;
10800 return;
10801 }
10802 Expression e = exp.op_overload(sc);
10803 if (e)
10804 {
10805 result = e;
10806 return;
10807 }
10808
10809 if (Expression ex = typeCombine(exp, sc))
10810 {
10811 result = ex;
10812 return;
10813 }
10814
10815 Type tb = exp.type.toBasetype();
10816 if (tb.ty == Tarray || tb.ty == Tsarray)
10817 {
10818 if (!isArrayOpValid(exp))
10819 {
10820 result = arrayOpInvalidError(exp);
10821 return;
10822 }
10823 result = exp;
10824 return;
10825 }
10826
10827 if (exp.checkArithmeticBin() || exp.checkSharedAccessBin(sc))
10828 return setError();
10829
10830 if (exp.type.isfloating())
10831 {
10832 Type t1 = exp.e1.type;
10833 Type t2 = exp.e2.type;
10834
10835 if (t1.isreal())
10836 {
10837 exp.type = t2;
10838 if (t2.isimaginary())
10839 {
10840 // x/iv = i(-x/v)
10841 exp.e2.type = t1;
10842 e = new NegExp(exp.loc, exp);
10843 e = e.expressionSemantic(sc);
10844 result = e;
10845 return;
10846 }
10847 }
10848 else if (t2.isreal())
10849 {
10850 exp.type = t1;
10851 }
10852 else if (t1.isimaginary())
10853 {
10854 if (t2.isimaginary())
10855 {
10856 switch (t1.toBasetype().ty)
10857 {
10858 case Timaginary32:
10859 exp.type = Type.tfloat32;
10860 break;
10861
10862 case Timaginary64:
10863 exp.type = Type.tfloat64;
10864 break;
10865
10866 case Timaginary80:
10867 exp.type = Type.tfloat80;
10868 break;
10869
10870 default:
10871 assert(0);
10872 }
10873 }
10874 else
10875 exp.type = t2; // t2 is complex
10876 }
10877 else if (t2.isimaginary())
10878 {
10879 exp.type = t1; // t1 is complex
10880 }
10881 }
10882 else if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype()))
10883 {
10884 result = exp.incompatibleTypes();
10885 return;
10886 }
10887 result = exp;
10888 }
10889
visit(ModExp exp)10890 override void visit(ModExp exp)
10891 {
10892 if (exp.type)
10893 {
10894 result = exp;
10895 return;
10896 }
10897
10898 if (Expression ex = binSemanticProp(exp, sc))
10899 {
10900 result = ex;
10901 return;
10902 }
10903 Expression e = exp.op_overload(sc);
10904 if (e)
10905 {
10906 result = e;
10907 return;
10908 }
10909
10910 if (Expression ex = typeCombine(exp, sc))
10911 {
10912 result = ex;
10913 return;
10914 }
10915
10916 Type tb = exp.type.toBasetype();
10917 if (tb.ty == Tarray || tb.ty == Tsarray)
10918 {
10919 if (!isArrayOpValid(exp))
10920 {
10921 result = arrayOpInvalidError(exp);
10922 return;
10923 }
10924 result = exp;
10925 return;
10926 }
10927 if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype()))
10928 {
10929 result = exp.incompatibleTypes();
10930 return;
10931 }
10932
10933 if (exp.checkArithmeticBin() || exp.checkSharedAccessBin(sc))
10934 return setError();
10935
10936 if (exp.type.isfloating())
10937 {
10938 exp.type = exp.e1.type;
10939 if (exp.e2.type.iscomplex())
10940 {
10941 exp.error("cannot perform modulo complex arithmetic");
10942 return setError();
10943 }
10944 }
10945 result = exp;
10946 }
10947
visit(PowExp exp)10948 override void visit(PowExp exp)
10949 {
10950 if (exp.type)
10951 {
10952 result = exp;
10953 return;
10954 }
10955
10956 //printf("PowExp::semantic() %s\n", toChars());
10957 if (Expression ex = binSemanticProp(exp, sc))
10958 {
10959 result = ex;
10960 return;
10961 }
10962 Expression e = exp.op_overload(sc);
10963 if (e)
10964 {
10965 result = e;
10966 return;
10967 }
10968
10969 if (Expression ex = typeCombine(exp, sc))
10970 {
10971 result = ex;
10972 return;
10973 }
10974
10975 Type tb = exp.type.toBasetype();
10976 if (tb.ty == Tarray || tb.ty == Tsarray)
10977 {
10978 if (!isArrayOpValid(exp))
10979 {
10980 result = arrayOpInvalidError(exp);
10981 return;
10982 }
10983 result = exp;
10984 return;
10985 }
10986
10987 if (exp.checkArithmeticBin() || exp.checkSharedAccessBin(sc))
10988 return setError();
10989
10990 if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype()))
10991 {
10992 result = exp.incompatibleTypes();
10993 return;
10994 }
10995
10996 // First, attempt to fold the expression.
10997 e = exp.optimize(WANTvalue);
10998 if (e.op != EXP.pow)
10999 {
11000 e = e.expressionSemantic(sc);
11001 result = e;
11002 return;
11003 }
11004
11005 Module mmath = loadStdMath();
11006 if (!mmath)
11007 {
11008 e.error("`%s` requires `std.math` for `^^` operators", e.toChars());
11009 return setError();
11010 }
11011 e = new ScopeExp(exp.loc, mmath);
11012
11013 if (exp.e2.op == EXP.float64 && exp.e2.toReal() == CTFloat.half)
11014 {
11015 // Replace e1 ^^ 0.5 with .std.math.sqrt(e1)
11016 e = new CallExp(exp.loc, new DotIdExp(exp.loc, e, Id._sqrt), exp.e1);
11017 }
11018 else
11019 {
11020 // Replace e1 ^^ e2 with .std.math.pow(e1, e2)
11021 e = new CallExp(exp.loc, new DotIdExp(exp.loc, e, Id._pow), exp.e1, exp.e2);
11022 }
11023 e = e.expressionSemantic(sc);
11024 result = e;
11025 return;
11026 }
11027
visit(ShlExp exp)11028 override void visit(ShlExp exp)
11029 {
11030 //printf("ShlExp::semantic(), type = %p\n", type);
11031 if (exp.type)
11032 {
11033 result = exp;
11034 return;
11035 }
11036
11037 if (Expression ex = binSemanticProp(exp, sc))
11038 {
11039 result = ex;
11040 return;
11041 }
11042 Expression e = exp.op_overload(sc);
11043 if (e)
11044 {
11045 result = e;
11046 return;
11047 }
11048
11049 if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc))
11050 return setError();
11051
11052 if (!target.isVectorOpSupported(exp.e1.type.toBasetype(), exp.op, exp.e2.type.toBasetype()))
11053 {
11054 result = exp.incompatibleTypes();
11055 return;
11056 }
11057 exp.e1 = integralPromotions(exp.e1, sc);
11058 if (exp.e2.type.toBasetype().ty != Tvector)
11059 exp.e2 = exp.e2.castTo(sc, Type.tshiftcnt);
11060
11061 exp.type = exp.e1.type;
11062 result = exp;
11063 }
11064
visit(ShrExp exp)11065 override void visit(ShrExp exp)
11066 {
11067 if (exp.type)
11068 {
11069 result = exp;
11070 return;
11071 }
11072
11073 if (Expression ex = binSemanticProp(exp, sc))
11074 {
11075 result = ex;
11076 return;
11077 }
11078 Expression e = exp.op_overload(sc);
11079 if (e)
11080 {
11081 result = e;
11082 return;
11083 }
11084
11085 if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc))
11086 return setError();
11087
11088 if (!target.isVectorOpSupported(exp.e1.type.toBasetype(), exp.op, exp.e2.type.toBasetype()))
11089 {
11090 result = exp.incompatibleTypes();
11091 return;
11092 }
11093 exp.e1 = integralPromotions(exp.e1, sc);
11094 if (exp.e2.type.toBasetype().ty != Tvector)
11095 exp.e2 = exp.e2.castTo(sc, Type.tshiftcnt);
11096
11097 exp.type = exp.e1.type;
11098 result = exp;
11099 }
11100
visit(UshrExp exp)11101 override void visit(UshrExp exp)
11102 {
11103 if (exp.type)
11104 {
11105 result = exp;
11106 return;
11107 }
11108
11109 if (Expression ex = binSemanticProp(exp, sc))
11110 {
11111 result = ex;
11112 return;
11113 }
11114 Expression e = exp.op_overload(sc);
11115 if (e)
11116 {
11117 result = e;
11118 return;
11119 }
11120
11121 if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc))
11122 return setError();
11123
11124 if (!target.isVectorOpSupported(exp.e1.type.toBasetype(), exp.op, exp.e2.type.toBasetype()))
11125 {
11126 result = exp.incompatibleTypes();
11127 return;
11128 }
11129 exp.e1 = integralPromotions(exp.e1, sc);
11130 if (exp.e2.type.toBasetype().ty != Tvector)
11131 exp.e2 = exp.e2.castTo(sc, Type.tshiftcnt);
11132
11133 exp.type = exp.e1.type;
11134 result = exp;
11135 }
11136
visit(AndExp exp)11137 override void visit(AndExp exp)
11138 {
11139 if (exp.type)
11140 {
11141 result = exp;
11142 return;
11143 }
11144
11145 if (Expression ex = binSemanticProp(exp, sc))
11146 {
11147 result = ex;
11148 return;
11149 }
11150 Expression e = exp.op_overload(sc);
11151 if (e)
11152 {
11153 result = e;
11154 return;
11155 }
11156
11157 if (exp.e1.type.toBasetype().ty == Tbool && exp.e2.type.toBasetype().ty == Tbool)
11158 {
11159 exp.type = exp.e1.type;
11160 result = exp;
11161 return;
11162 }
11163
11164 if (Expression ex = typeCombine(exp, sc))
11165 {
11166 result = ex;
11167 return;
11168 }
11169
11170 Type tb = exp.type.toBasetype();
11171 if (tb.ty == Tarray || tb.ty == Tsarray)
11172 {
11173 if (!isArrayOpValid(exp))
11174 {
11175 result = arrayOpInvalidError(exp);
11176 return;
11177 }
11178 result = exp;
11179 return;
11180 }
11181 if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype()))
11182 {
11183 result = exp.incompatibleTypes();
11184 return;
11185 }
11186 if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc))
11187 return setError();
11188
11189 result = exp;
11190 }
11191
visit(OrExp exp)11192 override void visit(OrExp exp)
11193 {
11194 if (exp.type)
11195 {
11196 result = exp;
11197 return;
11198 }
11199
11200 if (Expression ex = binSemanticProp(exp, sc))
11201 {
11202 result = ex;
11203 return;
11204 }
11205 Expression e = exp.op_overload(sc);
11206 if (e)
11207 {
11208 result = e;
11209 return;
11210 }
11211
11212 if (exp.e1.type.toBasetype().ty == Tbool && exp.e2.type.toBasetype().ty == Tbool)
11213 {
11214 exp.type = exp.e1.type;
11215 result = exp;
11216 return;
11217 }
11218
11219 if (Expression ex = typeCombine(exp, sc))
11220 {
11221 result = ex;
11222 return;
11223 }
11224
11225 Type tb = exp.type.toBasetype();
11226 if (tb.ty == Tarray || tb.ty == Tsarray)
11227 {
11228 if (!isArrayOpValid(exp))
11229 {
11230 result = arrayOpInvalidError(exp);
11231 return;
11232 }
11233 result = exp;
11234 return;
11235 }
11236 if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype()))
11237 {
11238 result = exp.incompatibleTypes();
11239 return;
11240 }
11241 if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc))
11242 return setError();
11243
11244 result = exp;
11245 }
11246
visit(XorExp exp)11247 override void visit(XorExp exp)
11248 {
11249 if (exp.type)
11250 {
11251 result = exp;
11252 return;
11253 }
11254
11255 if (Expression ex = binSemanticProp(exp, sc))
11256 {
11257 result = ex;
11258 return;
11259 }
11260 Expression e = exp.op_overload(sc);
11261 if (e)
11262 {
11263 result = e;
11264 return;
11265 }
11266
11267 if (exp.e1.type.toBasetype().ty == Tbool && exp.e2.type.toBasetype().ty == Tbool)
11268 {
11269 exp.type = exp.e1.type;
11270 result = exp;
11271 return;
11272 }
11273
11274 if (Expression ex = typeCombine(exp, sc))
11275 {
11276 result = ex;
11277 return;
11278 }
11279
11280 Type tb = exp.type.toBasetype();
11281 if (tb.ty == Tarray || tb.ty == Tsarray)
11282 {
11283 if (!isArrayOpValid(exp))
11284 {
11285 result = arrayOpInvalidError(exp);
11286 return;
11287 }
11288 result = exp;
11289 return;
11290 }
11291 if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype()))
11292 {
11293 result = exp.incompatibleTypes();
11294 return;
11295 }
11296 if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc))
11297 return setError();
11298
11299 result = exp;
11300 }
11301
visit(LogicalExp exp)11302 override void visit(LogicalExp exp)
11303 {
11304 static if (LOGSEMANTIC)
11305 {
11306 printf("LogicalExp::semantic() %s\n", exp.toChars());
11307 }
11308
11309 if (exp.type)
11310 {
11311 result = exp;
11312 return;
11313 }
11314
11315 exp.setNoderefOperands();
11316
11317 Expression e1x = exp.e1.expressionSemantic(sc);
11318
11319 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
11320 if (e1x.op == EXP.type)
11321 e1x = resolveAliasThis(sc, e1x);
11322
11323 e1x = resolveProperties(sc, e1x);
11324 e1x = e1x.toBoolean(sc);
11325
11326 if (sc.flags & SCOPE.condition)
11327 {
11328 /* If in static if, don't evaluate e2 if we don't have to.
11329 */
11330 e1x = e1x.optimize(WANTvalue);
11331 if (e1x.toBool().hasValue(exp.op == EXP.orOr))
11332 {
11333 if (sc.flags & SCOPE.Cfile)
11334 result = new IntegerExp(exp.op == EXP.orOr);
11335 else
11336 result = IntegerExp.createBool(exp.op == EXP.orOr);
11337 return;
11338 }
11339 }
11340
11341 CtorFlow ctorflow = sc.ctorflow.clone();
11342 Expression e2x = exp.e2.expressionSemantic(sc);
11343 sc.merge(exp.loc, ctorflow);
11344 ctorflow.freeFieldinit();
11345
11346 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
11347 if (e2x.op == EXP.type)
11348 e2x = resolveAliasThis(sc, e2x);
11349
11350 e2x = resolveProperties(sc, e2x);
11351
11352 auto f1 = checkNonAssignmentArrayOp(e1x);
11353 auto f2 = checkNonAssignmentArrayOp(e2x);
11354 if (f1 || f2)
11355 return setError();
11356
11357 // Unless the right operand is 'void', the expression is converted to 'bool'.
11358 if (e2x.type.ty != Tvoid)
11359 e2x = e2x.toBoolean(sc);
11360
11361 if (e2x.op == EXP.type || e2x.op == EXP.scope_)
11362 {
11363 exp.error("`%s` is not an expression", exp.e2.toChars());
11364 return setError();
11365 }
11366 if (e1x.op == EXP.error || e1x.type.ty == Tnoreturn)
11367 {
11368 result = e1x;
11369 return;
11370 }
11371 if (e2x.op == EXP.error)
11372 {
11373 result = e2x;
11374 return;
11375 }
11376
11377 // The result type is 'bool', unless the right operand has type 'void'.
11378 if (e2x.type.ty == Tvoid)
11379 exp.type = Type.tvoid;
11380 else
11381 exp.type = (sc && sc.flags & SCOPE.Cfile) ? Type.tint32 : Type.tbool;
11382
11383 exp.e1 = e1x;
11384 exp.e2 = e2x;
11385 result = exp;
11386 }
11387
11388
visit(CmpExp exp)11389 override void visit(CmpExp exp)
11390 {
11391 static if (LOGSEMANTIC)
11392 {
11393 printf("CmpExp::semantic('%s')\n", exp.toChars());
11394 }
11395 if (exp.type)
11396 {
11397 result = exp;
11398 return;
11399 }
11400
11401 exp.setNoderefOperands();
11402
11403 if (Expression ex = binSemanticProp(exp, sc))
11404 {
11405 result = ex;
11406 return;
11407 }
11408 Type t1 = exp.e1.type.toBasetype();
11409 Type t2 = exp.e2.type.toBasetype();
11410 if (t1.ty == Tclass && exp.e2.op == EXP.null_ || t2.ty == Tclass && exp.e1.op == EXP.null_)
11411 {
11412 exp.error("do not use `null` when comparing class types");
11413 return setError();
11414 }
11415
11416
11417 EXP cmpop = exp.op;
11418 if (auto e = exp.op_overload(sc, &cmpop))
11419 {
11420 if (!e.type.isscalar() && e.type.equals(exp.e1.type))
11421 {
11422 exp.error("recursive `opCmp` expansion");
11423 return setError();
11424 }
11425 if (e.op == EXP.call)
11426 {
11427
11428 if (t1.ty == Tclass && t2.ty == Tclass)
11429 {
11430 // Lower to object.__cmp(e1, e2)
11431 Expression cl = new IdentifierExp(exp.loc, Id.empty);
11432 cl = new DotIdExp(exp.loc, cl, Id.object);
11433 cl = new DotIdExp(exp.loc, cl, Id.__cmp);
11434 cl = cl.expressionSemantic(sc);
11435
11436 auto arguments = new Expressions();
11437 // Check if op_overload found a better match by calling e2.opCmp(e1)
11438 // If the operands were swapped, then the result must be reversed
11439 // e1.opCmp(e2) == -e2.opCmp(e1)
11440 // cmpop takes care of this
11441 if (exp.op == cmpop)
11442 {
11443 arguments.push(exp.e1);
11444 arguments.push(exp.e2);
11445 }
11446 else
11447 {
11448 // Use better match found by op_overload
11449 arguments.push(exp.e2);
11450 arguments.push(exp.e1);
11451 }
11452
11453 cl = new CallExp(exp.loc, cl, arguments);
11454 cl = new CmpExp(cmpop, exp.loc, cl, new IntegerExp(0));
11455 result = cl.expressionSemantic(sc);
11456 return;
11457 }
11458
11459 e = new CmpExp(cmpop, exp.loc, e, IntegerExp.literal!0);
11460 e = e.expressionSemantic(sc);
11461 }
11462 result = e;
11463 return;
11464 }
11465
11466
11467 if (Expression ex = typeCombine(exp, sc))
11468 {
11469 result = ex;
11470 return;
11471 }
11472
11473 auto f1 = checkNonAssignmentArrayOp(exp.e1);
11474 auto f2 = checkNonAssignmentArrayOp(exp.e2);
11475 if (f1 || f2)
11476 return setError();
11477
11478 exp.type = (sc && sc.flags & SCOPE.Cfile) ? Type.tint32 : Type.tbool;
11479
11480 // Special handling for array comparisons
11481 Expression arrayLowering = null;
11482 t1 = exp.e1.type.toBasetype();
11483 t2 = exp.e2.type.toBasetype();
11484 if ((t1.ty == Tarray || t1.ty == Tsarray || t1.ty == Tpointer) && (t2.ty == Tarray || t2.ty == Tsarray || t2.ty == Tpointer))
11485 {
11486 Type t1next = t1.nextOf();
11487 Type t2next = t2.nextOf();
11488 if (t1next.implicitConvTo(t2next) < MATCH.constant && t2next.implicitConvTo(t1next) < MATCH.constant && (t1next.ty != Tvoid && t2next.ty != Tvoid))
11489 {
11490 exp.error("array comparison type mismatch, `%s` vs `%s`", t1next.toChars(), t2next.toChars());
11491 return setError();
11492 }
11493 if ((t1.ty == Tarray || t1.ty == Tsarray) && (t2.ty == Tarray || t2.ty == Tsarray))
11494 {
11495 if (!verifyHookExist(exp.loc, *sc, Id.__cmp, "comparing arrays"))
11496 return setError();
11497
11498 // Lower to object.__cmp(e1, e2)
11499 Expression al = new IdentifierExp(exp.loc, Id.empty);
11500 al = new DotIdExp(exp.loc, al, Id.object);
11501 al = new DotIdExp(exp.loc, al, Id.__cmp);
11502 al = al.expressionSemantic(sc);
11503
11504 auto arguments = new Expressions(2);
11505 (*arguments)[0] = exp.e1;
11506 (*arguments)[1] = exp.e2;
11507
11508 al = new CallExp(exp.loc, al, arguments);
11509 al = new CmpExp(exp.op, exp.loc, al, IntegerExp.literal!0);
11510
11511 arrayLowering = al;
11512 }
11513 }
11514 else if (t1.ty == Tstruct || t2.ty == Tstruct || (t1.ty == Tclass && t2.ty == Tclass))
11515 {
11516 if (t2.ty == Tstruct)
11517 exp.error("need member function `opCmp()` for %s `%s` to compare", t2.toDsymbol(sc).kind(), t2.toChars());
11518 else
11519 exp.error("need member function `opCmp()` for %s `%s` to compare", t1.toDsymbol(sc).kind(), t1.toChars());
11520 return setError();
11521 }
11522 else if (t1.iscomplex() || t2.iscomplex())
11523 {
11524 exp.error("compare not defined for complex operands");
11525 return setError();
11526 }
11527 else if (t1.ty == Taarray || t2.ty == Taarray)
11528 {
11529 exp.error("`%s` is not defined for associative arrays", EXPtoString(exp.op).ptr);
11530 return setError();
11531 }
11532 else if (!target.isVectorOpSupported(t1, exp.op, t2))
11533 {
11534 result = exp.incompatibleTypes();
11535 return;
11536 }
11537 else
11538 {
11539 bool r1 = exp.e1.checkValue() || exp.e1.checkSharedAccess(sc);
11540 bool r2 = exp.e2.checkValue() || exp.e2.checkSharedAccess(sc);
11541 if (r1 || r2)
11542 return setError();
11543 }
11544
11545 //printf("CmpExp: %s, type = %s\n", e.toChars(), e.type.toChars());
11546 if (arrayLowering)
11547 {
11548 arrayLowering = arrayLowering.expressionSemantic(sc);
11549 result = arrayLowering;
11550 return;
11551 }
11552 result = exp;
11553 return;
11554 }
11555
visit(InExp exp)11556 override void visit(InExp exp)
11557 {
11558 if (exp.type)
11559 {
11560 result = exp;
11561 return;
11562 }
11563
11564 if (Expression ex = binSemanticProp(exp, sc))
11565 {
11566 result = ex;
11567 return;
11568 }
11569 Expression e = exp.op_overload(sc);
11570 if (e)
11571 {
11572 result = e;
11573 return;
11574 }
11575
11576 Type t2b = exp.e2.type.toBasetype();
11577 switch (t2b.ty)
11578 {
11579 case Taarray:
11580 {
11581 TypeAArray ta = cast(TypeAArray)t2b;
11582
11583 // Special handling for array keys
11584 if (!arrayTypeCompatibleWithoutCasting(exp.e1.type, ta.index))
11585 {
11586 // Convert key to type of key
11587 exp.e1 = exp.e1.implicitCastTo(sc, ta.index);
11588 }
11589
11590 semanticTypeInfo(sc, ta.index);
11591
11592 // Return type is pointer to value
11593 exp.type = ta.nextOf().pointerTo();
11594 break;
11595 }
11596
11597 case Terror:
11598 return setError();
11599
11600 default:
11601 result = exp.incompatibleTypes();
11602 return;
11603 }
11604 result = exp;
11605 }
11606
visit(RemoveExp e)11607 override void visit(RemoveExp e)
11608 {
11609 if (Expression ex = binSemantic(e, sc))
11610 {
11611 result = ex;
11612 return;
11613 }
11614 result = e;
11615 }
11616
visit(EqualExp exp)11617 override void visit(EqualExp exp)
11618 {
11619 //printf("EqualExp::semantic('%s')\n", exp.toChars());
11620 if (exp.type)
11621 {
11622 result = exp;
11623 return;
11624 }
11625
11626 exp.setNoderefOperands();
11627
11628 if (auto e = binSemanticProp(exp, sc))
11629 {
11630 result = e;
11631 return;
11632 }
11633 if (exp.e1.op == EXP.type || exp.e2.op == EXP.type)
11634 {
11635 /* https://issues.dlang.org/show_bug.cgi?id=12520
11636 * empty tuples are represented as types so special cases are added
11637 * so that they can be compared for equality with tuples of values.
11638 */
11639 static auto extractTypeTupAndExpTup(Expression e)
11640 {
11641 static struct Result { bool ttEmpty; bool te; }
11642 auto tt = e.op == EXP.type ? e.isTypeExp().type.isTypeTuple() : null;
11643 return Result(tt && (!tt.arguments || !tt.arguments.dim), e.isTupleExp() !is null);
11644 }
11645 auto tups1 = extractTypeTupAndExpTup(exp.e1);
11646 auto tups2 = extractTypeTupAndExpTup(exp.e2);
11647 // AliasSeq!() == AliasSeq!(<at least a value>)
11648 if (tups1.ttEmpty && tups2.te)
11649 {
11650 result = IntegerExp.createBool(exp.op != EXP.equal);
11651 return;
11652 }
11653 // AliasSeq!(<at least a value>) == AliasSeq!()
11654 else if (tups1.te && tups2.ttEmpty)
11655 {
11656 result = IntegerExp.createBool(exp.op != EXP.equal);
11657 return;
11658 }
11659 // AliasSeq!() == AliasSeq!()
11660 else if (tups1.ttEmpty && tups2.ttEmpty)
11661 {
11662 result = IntegerExp.createBool(exp.op == EXP.equal);
11663 return;
11664 }
11665 // otherwise, two types are really not comparable
11666 result = exp.incompatibleTypes();
11667 return;
11668 }
11669
11670 {
11671 auto t1 = exp.e1.type;
11672 auto t2 = exp.e2.type;
11673 if (t1.ty == Tenum && t2.ty == Tenum && !t1.equivalent(t2))
11674 exp.error("Comparison between different enumeration types `%s` and `%s`; If this behavior is intended consider using `std.conv.asOriginalType`",
11675 t1.toChars(), t2.toChars());
11676 }
11677
11678 /* Before checking for operator overloading, check to see if we're
11679 * comparing the addresses of two statics. If so, we can just see
11680 * if they are the same symbol.
11681 */
11682 if (exp.e1.op == EXP.address && exp.e2.op == EXP.address)
11683 {
11684 AddrExp ae1 = cast(AddrExp)exp.e1;
11685 AddrExp ae2 = cast(AddrExp)exp.e2;
11686 if (ae1.e1.op == EXP.variable && ae2.e1.op == EXP.variable)
11687 {
11688 VarExp ve1 = cast(VarExp)ae1.e1;
11689 VarExp ve2 = cast(VarExp)ae2.e1;
11690 if (ve1.var == ve2.var)
11691 {
11692 // They are the same, result is 'true' for ==, 'false' for !=
11693 result = IntegerExp.createBool(exp.op == EXP.equal);
11694 return;
11695 }
11696 }
11697 }
11698
11699 Type t1 = exp.e1.type.toBasetype();
11700 Type t2 = exp.e2.type.toBasetype();
11701
11702 // Indicates whether the comparison of the 2 specified array types
11703 // requires an object.__equals() lowering.
11704 static bool needsDirectEq(Type t1, Type t2, Scope* sc)
11705 {
11706 Type t1n = t1.nextOf().toBasetype();
11707 Type t2n = t2.nextOf().toBasetype();
11708 if ((t1n.ty.isSomeChar && t2n.ty.isSomeChar) ||
11709 (t1n.ty == Tvoid || t2n.ty == Tvoid))
11710 {
11711 return false;
11712 }
11713 if (t1n.constOf() != t2n.constOf())
11714 return true;
11715
11716 Type t = t1n;
11717 while (t.toBasetype().nextOf())
11718 t = t.nextOf().toBasetype();
11719 if (auto ts = t.isTypeStruct())
11720 {
11721 // semanticTypeInfo() makes sure hasIdentityEquals has been computed
11722 if (global.params.useTypeInfo && Type.dtypeinfo)
11723 semanticTypeInfo(sc, ts);
11724
11725 return ts.sym.hasIdentityEquals; // has custom opEquals
11726 }
11727
11728 return false;
11729 }
11730
11731 if (auto e = exp.op_overload(sc))
11732 {
11733 result = e;
11734 return;
11735 }
11736
11737
11738 const isArrayComparison = (t1.ty == Tarray || t1.ty == Tsarray) &&
11739 (t2.ty == Tarray || t2.ty == Tsarray);
11740 const needsArrayLowering = isArrayComparison && needsDirectEq(t1, t2, sc);
11741
11742 if (!needsArrayLowering)
11743 {
11744 if (auto e = typeCombine(exp, sc))
11745 {
11746 result = e;
11747 return;
11748 }
11749 }
11750
11751 auto f1 = checkNonAssignmentArrayOp(exp.e1);
11752 auto f2 = checkNonAssignmentArrayOp(exp.e2);
11753 if (f1 || f2)
11754 return setError();
11755
11756 exp.type = (sc && sc.flags & SCOPE.Cfile) ? Type.tint32 : Type.tbool;
11757
11758 if (!isArrayComparison)
11759 {
11760 if (exp.e1.type != exp.e2.type && exp.e1.type.isfloating() && exp.e2.type.isfloating())
11761 {
11762 // Cast both to complex
11763 exp.e1 = exp.e1.castTo(sc, Type.tcomplex80);
11764 exp.e2 = exp.e2.castTo(sc, Type.tcomplex80);
11765 }
11766 }
11767
11768 // lower some array comparisons to object.__equals(e1, e2)
11769 if (needsArrayLowering || (t1.ty == Tarray && t2.ty == Tarray))
11770 {
11771 //printf("Lowering to __equals %s %s\n", exp.e1.toChars(), exp.e2.toChars());
11772
11773 if (!verifyHookExist(exp.loc, *sc, Id.__equals, "equal checks on arrays"))
11774 return setError();
11775
11776 Expression __equals = new IdentifierExp(exp.loc, Id.empty);
11777 Identifier id = Identifier.idPool("__equals");
11778 __equals = new DotIdExp(exp.loc, __equals, Id.object);
11779 __equals = new DotIdExp(exp.loc, __equals, id);
11780
11781 auto arguments = new Expressions(2);
11782 (*arguments)[0] = exp.e1;
11783 (*arguments)[1] = exp.e2;
11784
11785 __equals = new CallExp(exp.loc, __equals, arguments);
11786 if (exp.op == EXP.notEqual)
11787 {
11788 __equals = new NotExp(exp.loc, __equals);
11789 }
11790 __equals = __equals.trySemantic(sc); // for better error message
11791 if (!__equals)
11792 {
11793 exp.error("incompatible types for array comparison: `%s` and `%s`",
11794 exp.e1.type.toChars(), exp.e2.type.toChars());
11795 __equals = ErrorExp.get();
11796 }
11797
11798 result = __equals;
11799 return;
11800 }
11801
11802 if (exp.e1.type.toBasetype().ty == Taarray)
11803 semanticTypeInfo(sc, exp.e1.type.toBasetype());
11804
11805
11806 if (!target.isVectorOpSupported(t1, exp.op, t2))
11807 {
11808 result = exp.incompatibleTypes();
11809 return;
11810 }
11811
11812 result = exp;
11813 }
11814
visit(IdentityExp exp)11815 override void visit(IdentityExp exp)
11816 {
11817 if (exp.type)
11818 {
11819 result = exp;
11820 return;
11821 }
11822
11823 exp.setNoderefOperands();
11824
11825 if (auto e = binSemanticProp(exp, sc))
11826 {
11827 result = e;
11828 return;
11829 }
11830
11831 if (auto e = typeCombine(exp, sc))
11832 {
11833 result = e;
11834 return;
11835 }
11836
11837 auto f1 = checkNonAssignmentArrayOp(exp.e1);
11838 auto f2 = checkNonAssignmentArrayOp(exp.e2);
11839 if (f1 || f2)
11840 return setError();
11841
11842 if (exp.e1.op == EXP.type || exp.e2.op == EXP.type)
11843 {
11844 result = exp.incompatibleTypes();
11845 return;
11846 }
11847
11848 exp.type = Type.tbool;
11849
11850 if (exp.e1.type != exp.e2.type && exp.e1.type.isfloating() && exp.e2.type.isfloating())
11851 {
11852 // Cast both to complex
11853 exp.e1 = exp.e1.castTo(sc, Type.tcomplex80);
11854 exp.e2 = exp.e2.castTo(sc, Type.tcomplex80);
11855 }
11856
11857 auto tb1 = exp.e1.type.toBasetype();
11858 auto tb2 = exp.e2.type.toBasetype();
11859 if (!target.isVectorOpSupported(tb1, exp.op, tb2))
11860 {
11861 result = exp.incompatibleTypes();
11862 return;
11863 }
11864
11865 if (exp.e1.op == EXP.call)
11866 exp.e1 = (cast(CallExp)exp.e1).addDtorHook(sc);
11867 if (exp.e2.op == EXP.call)
11868 exp.e2 = (cast(CallExp)exp.e2).addDtorHook(sc);
11869
11870 if (exp.e1.type.toBasetype().ty == Tsarray ||
11871 exp.e2.type.toBasetype().ty == Tsarray)
11872 exp.deprecation("identity comparison of static arrays "
11873 ~ "implicitly coerces them to slices, "
11874 ~ "which are compared by reference");
11875
11876 result = exp;
11877 }
11878
visit(CondExp exp)11879 override void visit(CondExp exp)
11880 {
11881 static if (LOGSEMANTIC)
11882 {
11883 printf("CondExp::semantic('%s')\n", exp.toChars());
11884 }
11885 if (exp.type)
11886 {
11887 result = exp;
11888 return;
11889 }
11890
11891 if (auto die = exp.econd.isDotIdExp())
11892 die.noderef = true;
11893
11894 Expression ec = exp.econd.expressionSemantic(sc);
11895 ec = resolveProperties(sc, ec);
11896 ec = ec.toBoolean(sc);
11897
11898 CtorFlow ctorflow_root = sc.ctorflow.clone();
11899 Expression e1x = exp.e1.expressionSemantic(sc).arrayFuncConv(sc);
11900 e1x = resolveProperties(sc, e1x);
11901
11902 CtorFlow ctorflow1 = sc.ctorflow;
11903 sc.ctorflow = ctorflow_root;
11904 Expression e2x = exp.e2.expressionSemantic(sc).arrayFuncConv(sc);
11905 e2x = resolveProperties(sc, e2x);
11906
11907 sc.merge(exp.loc, ctorflow1);
11908 ctorflow1.freeFieldinit();
11909
11910 if (ec.op == EXP.error)
11911 {
11912 result = ec;
11913 return;
11914 }
11915 if (ec.type == Type.terror)
11916 return setError();
11917 exp.econd = ec;
11918
11919 if (e1x.op == EXP.error)
11920 {
11921 result = e1x;
11922 return;
11923 }
11924 if (e1x.type == Type.terror)
11925 return setError();
11926 exp.e1 = e1x;
11927
11928 if (e2x.op == EXP.error)
11929 {
11930 result = e2x;
11931 return;
11932 }
11933 if (e2x.type == Type.terror)
11934 return setError();
11935 exp.e2 = e2x;
11936
11937 auto f0 = checkNonAssignmentArrayOp(exp.econd);
11938 auto f1 = checkNonAssignmentArrayOp(exp.e1);
11939 auto f2 = checkNonAssignmentArrayOp(exp.e2);
11940 if (f0 || f1 || f2)
11941 return setError();
11942
11943 Type t1 = exp.e1.type;
11944 Type t2 = exp.e2.type;
11945 if (t1.ty == Tnoreturn)
11946 {
11947 exp.type = t2;
11948 }
11949 else if (t2.ty == Tnoreturn)
11950 {
11951 exp.type = t1;
11952 }
11953 // If either operand is void the result is void, we have to cast both
11954 // the expression to void so that we explicitly discard the expression
11955 // value if any
11956 // https://issues.dlang.org/show_bug.cgi?id=16598
11957 else if (t1.ty == Tvoid || t2.ty == Tvoid)
11958 {
11959 exp.type = Type.tvoid;
11960 exp.e1 = exp.e1.castTo(sc, exp.type);
11961 exp.e2 = exp.e2.castTo(sc, exp.type);
11962 }
11963 else if (t1 == t2)
11964 exp.type = t1;
11965 else
11966 {
11967 if (Expression ex = typeCombine(exp, sc))
11968 {
11969 result = ex;
11970 return;
11971 }
11972
11973 switch (exp.e1.type.toBasetype().ty)
11974 {
11975 case Tcomplex32:
11976 case Tcomplex64:
11977 case Tcomplex80:
11978 exp.e2 = exp.e2.castTo(sc, exp.e1.type);
11979 break;
11980 default:
11981 break;
11982 }
11983 switch (exp.e2.type.toBasetype().ty)
11984 {
11985 case Tcomplex32:
11986 case Tcomplex64:
11987 case Tcomplex80:
11988 exp.e1 = exp.e1.castTo(sc, exp.e2.type);
11989 break;
11990 default:
11991 break;
11992 }
11993 if (exp.type.toBasetype().ty == Tarray)
11994 {
11995 exp.e1 = exp.e1.castTo(sc, exp.type);
11996 exp.e2 = exp.e2.castTo(sc, exp.type);
11997 }
11998 }
11999 exp.type = exp.type.merge2();
12000 version (none)
12001 {
12002 printf("res: %s\n", exp.type.toChars());
12003 printf("e1 : %s\n", exp.e1.type.toChars());
12004 printf("e2 : %s\n", exp.e2.type.toChars());
12005 }
12006
12007 /* https://issues.dlang.org/show_bug.cgi?id=14696
12008 * If either e1 or e2 contain temporaries which need dtor,
12009 * make them conditional.
12010 * Rewrite:
12011 * cond ? (__tmp1 = ..., __tmp1) : (__tmp2 = ..., __tmp2)
12012 * to:
12013 * (auto __cond = cond) ? (... __tmp1) : (... __tmp2)
12014 * and replace edtors of __tmp1 and __tmp2 with:
12015 * __tmp1.edtor --> __cond && __tmp1.dtor()
12016 * __tmp2.edtor --> __cond || __tmp2.dtor()
12017 */
12018 exp.hookDtors(sc);
12019
12020 result = exp;
12021 }
12022
visit(GenericExp exp)12023 override void visit(GenericExp exp)
12024 {
12025 static if (LOGSEMANTIC)
12026 {
12027 printf("GenericExp::semantic('%s')\n", exp.toChars());
12028 }
12029 // C11 6.5.1.1 Generic Selection
12030
12031 auto ec = exp.cntlExp.expressionSemantic(sc);
12032 bool errors = ec.isErrorExp() !is null;
12033 auto tc = ec.type;
12034
12035 auto types = (*exp.types)[];
12036 foreach (i, ref t; types)
12037 {
12038 if (!t)
12039 continue; // `default:` case
12040 t = t.typeSemantic(ec.loc, sc);
12041 if (t.isTypeError())
12042 {
12043 errors = true;
12044 continue;
12045 }
12046
12047 /* C11 6.5.1-2 duplicate check
12048 */
12049 /* C11 distinguishes int, long, and long long. But D doesn't, so depending on the
12050 * C target, a long may have the same type as `int` in the D type system.
12051 * So, skip checks when this may be the case. Later pick the first match
12052 */
12053 if (
12054 (t.ty == Tint32 || t.ty == Tuns32) && target.c.longsize == 4 ||
12055 (t.ty == Tint64 || t.ty == Tuns64) && target.c.longsize == 8 ||
12056 (t.ty == Tfloat64 || t.ty == Timaginary64 || t.ty == Tcomplex64) && target.c.long_doublesize == 8
12057 )
12058 continue;
12059
12060 foreach (t2; types[0 .. i])
12061 {
12062 if (t2 && t2.equals(t))
12063 {
12064 error(ec.loc, "generic association type `%s` can only appear once", t.toChars());
12065 errors = true;
12066 break;
12067 }
12068 }
12069 }
12070
12071 auto exps = (*exp.exps)[];
12072 foreach (ref e; exps)
12073 {
12074 e = e.expressionSemantic(sc);
12075 if (e.isErrorExp())
12076 errors = true;
12077 }
12078
12079 if (errors)
12080 return setError();
12081
12082 enum size_t None = ~0;
12083 size_t imatch = None;
12084 size_t idefault = None;
12085 foreach (const i, t; types)
12086 {
12087 if (t)
12088 {
12089 /* if tc is compatible with t, it's a match
12090 * C11 6.2.7 defines a compatible type as being the same type, including qualifiers
12091 */
12092 if (tc.equals(t))
12093 {
12094 assert(imatch == None);
12095 imatch = i;
12096 break; // pick first match
12097 }
12098 }
12099 else
12100 idefault = i; // multiple defaults are not allowed, and are caught by cparse
12101 }
12102
12103 if (imatch == None)
12104 imatch = idefault;
12105 if (imatch == None)
12106 {
12107 error(exp.loc, "no compatible generic association type for controlling expression type `%s`", tc.toChars());
12108 return setError();
12109 }
12110
12111 result = exps[imatch];
12112 }
12113
visit(FileInitExp e)12114 override void visit(FileInitExp e)
12115 {
12116 //printf("FileInitExp::semantic()\n");
12117 e.type = Type.tstring;
12118 result = e;
12119 }
12120
visit(LineInitExp e)12121 override void visit(LineInitExp e)
12122 {
12123 e.type = Type.tint32;
12124 result = e;
12125 }
12126
visit(ModuleInitExp e)12127 override void visit(ModuleInitExp e)
12128 {
12129 //printf("ModuleInitExp::semantic()\n");
12130 e.type = Type.tstring;
12131 result = e;
12132 }
12133
visit(FuncInitExp e)12134 override void visit(FuncInitExp e)
12135 {
12136 //printf("FuncInitExp::semantic()\n");
12137 e.type = Type.tstring;
12138 if (sc.func)
12139 {
12140 result = e.resolveLoc(Loc.initial, sc);
12141 return;
12142 }
12143 result = e;
12144 }
12145
visit(PrettyFuncInitExp e)12146 override void visit(PrettyFuncInitExp e)
12147 {
12148 //printf("PrettyFuncInitExp::semantic()\n");
12149 e.type = Type.tstring;
12150 if (sc.func)
12151 {
12152 result = e.resolveLoc(Loc.initial, sc);
12153 return;
12154 }
12155
12156 result = e;
12157 }
12158 }
12159
12160 /**********************************
12161 * Try to run semantic routines.
12162 * If they fail, return NULL.
12163 */
trySemantic(Expression exp,Scope * sc)12164 Expression trySemantic(Expression exp, Scope* sc)
12165 {
12166 //printf("+trySemantic(%s)\n", exp.toChars());
12167 uint errors = global.startGagging();
12168 Expression e = expressionSemantic(exp, sc);
12169 if (global.endGagging(errors))
12170 {
12171 e = null;
12172 }
12173 //printf("-trySemantic(%s)\n", exp.toChars());
12174 return e;
12175 }
12176
12177 /**************************
12178 * Helper function for easy error propagation.
12179 * If error occurs, returns ErrorExp. Otherwise returns NULL.
12180 */
unaSemantic(UnaExp e,Scope * sc)12181 Expression unaSemantic(UnaExp e, Scope* sc)
12182 {
12183 static if (LOGSEMANTIC)
12184 {
12185 printf("UnaExp::semantic('%s')\n", e.toChars());
12186 }
12187 Expression e1x = e.e1.expressionSemantic(sc);
12188 if (e1x.op == EXP.error)
12189 return e1x;
12190 e.e1 = e1x;
12191 return null;
12192 }
12193
12194 /**************************
12195 * Helper function for easy error propagation.
12196 * If error occurs, returns ErrorExp. Otherwise returns NULL.
12197 */
binSemantic(BinExp e,Scope * sc)12198 Expression binSemantic(BinExp e, Scope* sc)
12199 {
12200 static if (LOGSEMANTIC)
12201 {
12202 printf("BinExp::semantic('%s')\n", e.toChars());
12203 }
12204 Expression e1x = e.e1.expressionSemantic(sc);
12205 Expression e2x = e.e2.expressionSemantic(sc);
12206
12207 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
12208 if (e1x.op == EXP.type)
12209 e1x = resolveAliasThis(sc, e1x);
12210 if (e2x.op == EXP.type)
12211 e2x = resolveAliasThis(sc, e2x);
12212
12213 if (e1x.op == EXP.error)
12214 return e1x;
12215 if (e2x.op == EXP.error)
12216 return e2x;
12217 e.e1 = e1x;
12218 e.e2 = e2x;
12219 return null;
12220 }
12221
binSemanticProp(BinExp e,Scope * sc)12222 Expression binSemanticProp(BinExp e, Scope* sc)
12223 {
12224 if (Expression ex = binSemantic(e, sc))
12225 return ex;
12226 Expression e1x = resolveProperties(sc, e.e1);
12227 Expression e2x = resolveProperties(sc, e.e2);
12228 if (e1x.op == EXP.error)
12229 return e1x;
12230 if (e2x.op == EXP.error)
12231 return e2x;
12232 e.e1 = e1x;
12233 e.e2 = e2x;
12234 return null;
12235 }
12236
12237 // entrypoint for semantic ExpressionSemanticVisitor
expressionSemantic(Expression e,Scope * sc)12238 extern (C++) Expression expressionSemantic(Expression e, Scope* sc)
12239 {
12240 scope v = new ExpressionSemanticVisitor(sc);
12241 e.accept(v);
12242 return v.result;
12243 }
12244
semanticX(DotIdExp exp,Scope * sc)12245 Expression semanticX(DotIdExp exp, Scope* sc)
12246 {
12247 //printf("DotIdExp::semanticX(this = %p, '%s')\n", this, toChars());
12248 if (Expression ex = unaSemantic(exp, sc))
12249 return ex;
12250
12251 if (!(sc.flags & SCOPE.Cfile) && exp.ident == Id._mangleof)
12252 {
12253 // symbol.mangleof
12254
12255 // return mangleof as an Expression
12256 static Expression dotMangleof(const ref Loc loc, Scope* sc, Dsymbol ds)
12257 {
12258 assert(ds);
12259 if (auto f = ds.isFuncDeclaration())
12260 {
12261 if (f.checkForwardRef(loc))
12262 return ErrorExp.get();
12263
12264 if (f.flags & (FUNCFLAG.purityInprocess | FUNCFLAG.safetyInprocess |
12265 FUNCFLAG.nothrowInprocess | FUNCFLAG.nogcInprocess))
12266 {
12267 f.error(loc, "cannot retrieve its `.mangleof` while inferring attributes");
12268 return ErrorExp.get();
12269 }
12270 }
12271 OutBuffer buf;
12272 mangleToBuffer(ds, &buf);
12273 Expression e = new StringExp(loc, buf.extractSlice());
12274 return e.expressionSemantic(sc);
12275 }
12276
12277 Dsymbol ds;
12278 switch (exp.e1.op)
12279 {
12280 case EXP.scope_: return dotMangleof(exp.loc, sc, exp.e1.isScopeExp().sds);
12281 case EXP.variable: return dotMangleof(exp.loc, sc, exp.e1.isVarExp().var);
12282 case EXP.dotVariable: return dotMangleof(exp.loc, sc, exp.e1.isDotVarExp().var);
12283 case EXP.overloadSet: return dotMangleof(exp.loc, sc, exp.e1.isOverExp().vars);
12284 case EXP.template_:
12285 {
12286 TemplateExp te = exp.e1.isTemplateExp();
12287 return dotMangleof(exp.loc, sc, ds = te.fd ? te.fd.isDsymbol() : te.td);
12288 }
12289
12290 default:
12291 break;
12292 }
12293 }
12294
12295 if (exp.e1.isVarExp() && exp.e1.type.toBasetype().isTypeSArray() && exp.ident == Id.length)
12296 {
12297 // bypass checkPurity
12298 return exp.e1.type.dotExp(sc, exp.e1, exp.ident, exp.noderef ? DotExpFlag.noDeref : 0);
12299 }
12300
12301 if (!exp.e1.isDotExp())
12302 {
12303 exp.e1 = resolvePropertiesX(sc, exp.e1);
12304 }
12305
12306 if (auto te = exp.e1.isTupleExp())
12307 {
12308 if (exp.ident == Id.offsetof)
12309 {
12310 /* 'distribute' the .offsetof to each of the tuple elements.
12311 */
12312 auto exps = new Expressions(te.exps.dim);
12313 foreach (i, e; (*te.exps)[])
12314 {
12315 (*exps)[i] = new DotIdExp(e.loc, e, Id.offsetof);
12316 }
12317 // Don't evaluate te.e0 in runtime
12318 Expression e = new TupleExp(exp.loc, null, exps);
12319 e = e.expressionSemantic(sc);
12320 return e;
12321 }
12322 if (exp.ident == Id.length)
12323 {
12324 // Don't evaluate te.e0 in runtime
12325 return new IntegerExp(exp.loc, te.exps.dim, Type.tsize_t);
12326 }
12327 }
12328
12329 // https://issues.dlang.org/show_bug.cgi?id=14416
12330 // Template has no built-in properties except for 'stringof'.
12331 if ((exp.e1.isDotTemplateExp() || exp.e1.isTemplateExp()) && exp.ident != Id.stringof)
12332 {
12333 exp.error("template `%s` does not have property `%s`", exp.e1.toChars(), exp.ident.toChars());
12334 return ErrorExp.get();
12335 }
12336 if (!exp.e1.type)
12337 {
12338 exp.error("expression `%s` does not have property `%s`", exp.e1.toChars(), exp.ident.toChars());
12339 return ErrorExp.get();
12340 }
12341
12342 return exp;
12343 }
12344
12345 /******************************
12346 * Resolve properties, i.e. `e1.ident`, without seeing UFCS.
12347 * Params:
12348 * exp = expression to resolve
12349 * sc = context
12350 * flag = if 1 then do not emit error messages, just return null
12351 * Returns:
12352 * resolved expression, null if error
12353 */
semanticY(DotIdExp exp,Scope * sc,int flag)12354 Expression semanticY(DotIdExp exp, Scope* sc, int flag)
12355 {
12356 //printf("DotIdExp::semanticY(this = %p, '%s')\n", exp, exp.toChars());
12357
12358 //{ static int z; fflush(stdout); if (++z == 10) *(char*)0=0; }
12359
12360 const cfile = (sc.flags & SCOPE.Cfile) != 0;
12361
12362 /* Special case: rewrite this.id and super.id
12363 * to be classtype.id and baseclasstype.id
12364 * if we have no this pointer.
12365 */
12366 if ((exp.e1.isThisExp() || exp.e1.isSuperExp()) && !hasThis(sc))
12367 {
12368 if (AggregateDeclaration ad = sc.getStructClassScope())
12369 {
12370 if (exp.e1.isThisExp())
12371 {
12372 exp.e1 = new TypeExp(exp.e1.loc, ad.type);
12373 }
12374 else
12375 {
12376 if (auto cd = ad.isClassDeclaration())
12377 {
12378 if (cd.baseClass)
12379 exp.e1 = new TypeExp(exp.e1.loc, cd.baseClass.type);
12380 }
12381 }
12382 }
12383 }
12384
12385 {
12386 Expression e = semanticX(exp, sc);
12387 if (e != exp)
12388 return e;
12389 }
12390
12391 Expression eleft;
12392 Expression eright;
12393 if (auto de = exp.e1.isDotExp())
12394 {
12395 eleft = de.e1;
12396 eright = de.e2;
12397 }
12398 else
12399 {
12400 eleft = null;
12401 eright = exp.e1;
12402 }
12403
12404 Type t1b = exp.e1.type.toBasetype();
12405
12406 if (auto ie = eright.isScopeExp()) // also used for template alias's
12407 {
12408 auto flags = SearchLocalsOnly;
12409 /* Disable access to another module's private imports.
12410 * The check for 'is sds our current module' is because
12411 * the current module should have access to its own imports.
12412 */
12413 if (ie.sds.isModule() && ie.sds != sc._module)
12414 flags |= IgnorePrivateImports;
12415 if (sc.flags & SCOPE.ignoresymbolvisibility)
12416 flags |= IgnoreSymbolVisibility;
12417 Dsymbol s = ie.sds.search(exp.loc, exp.ident, flags);
12418 /* Check for visibility before resolving aliases because public
12419 * aliases to private symbols are public.
12420 */
12421 if (s && !(sc.flags & SCOPE.ignoresymbolvisibility) && !symbolIsVisible(sc._module, s))
12422 {
12423 s = null;
12424 }
12425 if (s)
12426 {
12427 auto p = s.isPackage();
12428 if (p && checkAccess(sc, p))
12429 {
12430 s = null;
12431 }
12432 }
12433 if (s)
12434 {
12435 // if 's' is a tuple variable, the tuple is returned.
12436 s = s.toAlias();
12437
12438 exp.checkDeprecated(sc, s);
12439 exp.checkDisabled(sc, s);
12440
12441 if (auto em = s.isEnumMember())
12442 {
12443 return em.getVarExp(exp.loc, sc);
12444 }
12445 if (auto v = s.isVarDeclaration())
12446 {
12447 //printf("DotIdExp:: Identifier '%s' is a variable, type '%s'\n", toChars(), v.type.toChars());
12448 if (!v.type ||
12449 !v.type.deco && v.inuse)
12450 {
12451 if (v.inuse)
12452 exp.error("circular reference to %s `%s`", v.kind(), v.toPrettyChars());
12453 else
12454 exp.error("forward reference to %s `%s`", v.kind(), v.toPrettyChars());
12455 return ErrorExp.get();
12456 }
12457 if (v.type.isTypeError())
12458 return ErrorExp.get();
12459
12460 if ((v.storage_class & STC.manifest) && v._init && !exp.wantsym)
12461 {
12462 /* Normally, the replacement of a symbol with its initializer is supposed to be in semantic2().
12463 * Introduced by https://github.com/dlang/dmd/pull/5588 which should probably
12464 * be reverted. `wantsym` is the hack to work around the problem.
12465 */
12466 if (v.inuse)
12467 {
12468 error(exp.loc, "circular initialization of %s `%s`", v.kind(), v.toPrettyChars());
12469 return ErrorExp.get();
12470 }
12471 auto e = v.expandInitializer(exp.loc);
12472 v.inuse++;
12473 e = e.expressionSemantic(sc);
12474 v.inuse--;
12475 return e;
12476 }
12477
12478 Expression e;
12479 if (v.needThis())
12480 {
12481 if (!eleft)
12482 eleft = new ThisExp(exp.loc);
12483 e = new DotVarExp(exp.loc, eleft, v);
12484 e = e.expressionSemantic(sc);
12485 }
12486 else
12487 {
12488 e = new VarExp(exp.loc, v);
12489 if (eleft)
12490 {
12491 e = new CommaExp(exp.loc, eleft, e);
12492 e.type = v.type;
12493 }
12494 }
12495 e = e.deref();
12496 return e.expressionSemantic(sc);
12497 }
12498
12499 if (auto f = s.isFuncDeclaration())
12500 {
12501 //printf("it's a function\n");
12502 if (!f.functionSemantic())
12503 return ErrorExp.get();
12504 Expression e;
12505 if (f.needThis())
12506 {
12507 if (!eleft)
12508 eleft = new ThisExp(exp.loc);
12509 e = new DotVarExp(exp.loc, eleft, f, true);
12510 e = e.expressionSemantic(sc);
12511 }
12512 else
12513 {
12514 e = new VarExp(exp.loc, f, true);
12515 if (eleft)
12516 {
12517 e = new CommaExp(exp.loc, eleft, e);
12518 e.type = f.type;
12519 }
12520 }
12521 return e;
12522 }
12523 if (auto td = s.isTemplateDeclaration())
12524 {
12525 Expression e;
12526 if (eleft)
12527 e = new DotTemplateExp(exp.loc, eleft, td);
12528 else
12529 e = new TemplateExp(exp.loc, td);
12530 e = e.expressionSemantic(sc);
12531 return e;
12532 }
12533 if (OverDeclaration od = s.isOverDeclaration())
12534 {
12535 Expression e = new VarExp(exp.loc, od, true);
12536 if (eleft)
12537 {
12538 e = new CommaExp(exp.loc, eleft, e);
12539 e.type = Type.tvoid; // ambiguous type?
12540 }
12541 return e.expressionSemantic(sc);
12542 }
12543 if (auto o = s.isOverloadSet())
12544 {
12545 //printf("'%s' is an overload set\n", o.toChars());
12546 return new OverExp(exp.loc, o);
12547 }
12548
12549 if (auto t = s.getType())
12550 {
12551 return (new TypeExp(exp.loc, t)).expressionSemantic(sc);
12552 }
12553
12554 if (auto tup = s.isTupleDeclaration())
12555 {
12556 if (eleft)
12557 {
12558 Expression e = new DotVarExp(exp.loc, eleft, tup);
12559 e = e.expressionSemantic(sc);
12560 return e;
12561 }
12562 Expression e = new TupleExp(exp.loc, tup);
12563 e = e.expressionSemantic(sc);
12564 return e;
12565 }
12566
12567 if (auto sds = s.isScopeDsymbol())
12568 {
12569 //printf("it's a ScopeDsymbol %s\n", ident.toChars());
12570 Expression e = new ScopeExp(exp.loc, sds);
12571 e = e.expressionSemantic(sc);
12572 if (eleft)
12573 e = new DotExp(exp.loc, eleft, e);
12574 return e;
12575 }
12576
12577 if (auto imp = s.isImport())
12578 {
12579 Expression se = new ScopeExp(exp.loc, imp.pkg);
12580 return se.expressionSemantic(sc);
12581 }
12582 // BUG: handle other cases like in IdentifierExp::semantic()
12583 debug
12584 {
12585 printf("s = '%s', kind = '%s'\n", s.toChars(), s.kind());
12586 }
12587 assert(0);
12588 }
12589 else if (exp.ident == Id.stringof)
12590 {
12591 Expression e = new StringExp(exp.loc, ie.toString());
12592 e = e.expressionSemantic(sc);
12593 return e;
12594 }
12595 if (ie.sds.isPackage() || ie.sds.isImport() || ie.sds.isModule())
12596 {
12597 flag = 0;
12598 }
12599 if (flag)
12600 return null;
12601 s = ie.sds.search_correct(exp.ident);
12602 if (s && symbolIsVisible(sc, s))
12603 {
12604 if (s.isPackage())
12605 exp.error("undefined identifier `%s` in %s `%s`, perhaps add `static import %s;`", exp.ident.toChars(), ie.sds.kind(), ie.sds.toPrettyChars(), s.toPrettyChars());
12606 else
12607 exp.error("undefined identifier `%s` in %s `%s`, did you mean %s `%s`?", exp.ident.toChars(), ie.sds.kind(), ie.sds.toPrettyChars(), s.kind(), s.toChars());
12608 }
12609 else
12610 exp.error("undefined identifier `%s` in %s `%s`", exp.ident.toChars(), ie.sds.kind(), ie.sds.toPrettyChars());
12611 return ErrorExp.get();
12612 }
12613 else if (t1b.ty == Tpointer && exp.e1.type.ty != Tenum &&
12614 !(
12615 exp.ident == Id.__sizeof ||
12616 exp.ident == Id.__xalignof ||
12617 !cfile &&
12618 (exp.ident == Id._mangleof ||
12619 exp.ident == Id.offsetof ||
12620 exp.ident == Id._init ||
12621 exp.ident == Id.stringof)
12622 ))
12623 {
12624 Type t1bn = t1b.nextOf();
12625 if (flag)
12626 {
12627 if (AggregateDeclaration ad = isAggregate(t1bn))
12628 {
12629 if (!ad.members) // https://issues.dlang.org/show_bug.cgi?id=11312
12630 return null;
12631 }
12632 }
12633
12634 /* Rewrite:
12635 * p.ident
12636 * as:
12637 * (*p).ident
12638 */
12639 if (flag && t1bn.ty == Tvoid)
12640 return null;
12641 Expression e = new PtrExp(exp.loc, exp.e1);
12642 e = e.expressionSemantic(sc);
12643 return e.type.dotExp(sc, e, exp.ident, flag | (exp.noderef ? DotExpFlag.noDeref : 0));
12644 }
12645 else if (exp.ident == Id.__xalignof &&
12646 exp.e1.isVarExp() &&
12647 exp.e1.isVarExp().var.isVarDeclaration() &&
12648 !exp.e1.isVarExp().var.isVarDeclaration().alignment.isUnknown())
12649 {
12650 // For `x.alignof` get the alignment of the variable, not the alignment of its type
12651 const explicitAlignment = exp.e1.isVarExp().var.isVarDeclaration().alignment;
12652 const naturalAlignment = exp.e1.type.alignsize();
12653 const actualAlignment = explicitAlignment.isDefault() ? naturalAlignment : explicitAlignment.get();
12654 Expression e = new IntegerExp(exp.loc, actualAlignment, Type.tsize_t);
12655 return e;
12656 }
12657 else if (cfile && exp.ident == Id.__sizeof && exp.e1.isStringExp())
12658 {
12659 // Sizeof string literal includes the terminating 0
12660 auto se = exp.e1.isStringExp();
12661 Expression e = new IntegerExp(exp.loc, (se.len + 1) * se.sz, Type.tsize_t);
12662 return e;
12663 }
12664 else
12665 {
12666 if (exp.e1.isTypeExp() || exp.e1.isTemplateExp())
12667 flag = 0;
12668 Expression e = exp.e1.type.dotExp(sc, exp.e1, exp.ident, flag | (exp.noderef ? DotExpFlag.noDeref : 0));
12669 if (e)
12670 e = e.expressionSemantic(sc);
12671 return e;
12672 }
12673 }
12674
12675 // Resolve e1.ident!tiargs without seeing UFCS.
12676 // If flag == 1, stop "not a property" error and return NULL.
semanticY(DotTemplateInstanceExp exp,Scope * sc,int flag)12677 Expression semanticY(DotTemplateInstanceExp exp, Scope* sc, int flag)
12678 {
12679 static if (LOGSEMANTIC)
12680 {
12681 printf("DotTemplateInstanceExpY::semantic('%s')\n", exp.toChars());
12682 }
12683
12684 static Expression errorExp()
12685 {
12686 return ErrorExp.get();
12687 }
12688
12689 Expression e1 = exp.e1;
12690
12691 if (exp.ti.tempdecl && exp.ti.tempdecl.parent && exp.ti.tempdecl.parent.isTemplateMixin())
12692 {
12693 // if 'ti.tempdecl' happens to be found in a mixin template don't lose that info
12694 // and do the symbol search in that context (Issue: 19476)
12695 auto tm = cast(TemplateMixin)exp.ti.tempdecl.parent;
12696 e1 = new DotExp(exp.e1.loc, exp.e1, new ScopeExp(tm.loc, tm));
12697 }
12698
12699 auto die = new DotIdExp(exp.loc, e1, exp.ti.name);
12700
12701 Expression e = die.semanticX(sc);
12702 if (e == die)
12703 {
12704 exp.e1 = die.e1; // take back
12705 Type t1b = exp.e1.type.toBasetype();
12706 if (t1b.ty == Tarray || t1b.ty == Tsarray || t1b.ty == Taarray || t1b.ty == Tnull || (t1b.isTypeBasic() && t1b.ty != Tvoid))
12707 {
12708 /* No built-in type has templatized properties, so do shortcut.
12709 * It is necessary in: 1024.max!"a < b"
12710 */
12711 if (flag)
12712 return null;
12713 }
12714 e = die.semanticY(sc, flag);
12715 if (flag)
12716 {
12717 if (!e ||
12718 isDotOpDispatch(e))
12719 {
12720 /* opDispatch!tiargs would be a function template that needs IFTI,
12721 * so it's not a template
12722 */
12723 return null;
12724 }
12725 }
12726 }
12727 assert(e);
12728
12729 if (e.op == EXP.error)
12730 return e;
12731 if (DotVarExp dve = e.isDotVarExp())
12732 {
12733 if (FuncDeclaration fd = dve.var.isFuncDeclaration())
12734 {
12735 if (TemplateDeclaration td = fd.findTemplateDeclRoot())
12736 {
12737 e = new DotTemplateExp(dve.loc, dve.e1, td);
12738 e = e.expressionSemantic(sc);
12739 }
12740 }
12741 else if (OverDeclaration od = dve.var.isOverDeclaration())
12742 {
12743 exp.e1 = dve.e1; // pull semantic() result
12744
12745 if (!exp.findTempDecl(sc))
12746 goto Lerr;
12747 if (exp.ti.needsTypeInference(sc))
12748 return exp;
12749 exp.ti.dsymbolSemantic(sc);
12750 if (!exp.ti.inst || exp.ti.errors) // if template failed to expand
12751 return errorExp();
12752
12753 if (Declaration v = exp.ti.toAlias().isDeclaration())
12754 {
12755 if (v.type && !v.type.deco)
12756 v.type = v.type.typeSemantic(v.loc, sc);
12757 return new DotVarExp(exp.loc, exp.e1, v)
12758 .expressionSemantic(sc);
12759 }
12760 return new DotExp(exp.loc, exp.e1, new ScopeExp(exp.loc, exp.ti))
12761 .expressionSemantic(sc);
12762 }
12763 }
12764 else if (e.op == EXP.variable)
12765 {
12766 VarExp ve = cast(VarExp)e;
12767 if (FuncDeclaration fd = ve.var.isFuncDeclaration())
12768 {
12769 if (TemplateDeclaration td = fd.findTemplateDeclRoot())
12770 {
12771 e = new TemplateExp(ve.loc, td)
12772 .expressionSemantic(sc);
12773 }
12774 }
12775 else if (OverDeclaration od = ve.var.isOverDeclaration())
12776 {
12777 exp.ti.tempdecl = od;
12778 return new ScopeExp(exp.loc, exp.ti)
12779 .expressionSemantic(sc);
12780 }
12781 }
12782
12783 if (DotTemplateExp dte = e.isDotTemplateExp())
12784 {
12785 exp.e1 = dte.e1; // pull semantic() result
12786
12787 exp.ti.tempdecl = dte.td;
12788 if (!exp.ti.semanticTiargs(sc))
12789 return errorExp();
12790 if (exp.ti.needsTypeInference(sc))
12791 return exp;
12792 exp.ti.dsymbolSemantic(sc);
12793 if (!exp.ti.inst || exp.ti.errors) // if template failed to expand
12794 return errorExp();
12795
12796 if (Declaration v = exp.ti.toAlias().isDeclaration())
12797 {
12798 if (v.isFuncDeclaration() || v.isVarDeclaration())
12799 {
12800 return new DotVarExp(exp.loc, exp.e1, v)
12801 .expressionSemantic(sc);
12802 }
12803 }
12804 return new DotExp(exp.loc, exp.e1, new ScopeExp(exp.loc, exp.ti))
12805 .expressionSemantic(sc);
12806 }
12807 else if (e.op == EXP.template_)
12808 {
12809 exp.ti.tempdecl = (cast(TemplateExp)e).td;
12810 return new ScopeExp(exp.loc, exp.ti)
12811 .expressionSemantic(sc);
12812 }
12813 else if (DotExp de = e.isDotExp())
12814 {
12815 if (de.e2.op == EXP.overloadSet)
12816 {
12817 if (!exp.findTempDecl(sc) || !exp.ti.semanticTiargs(sc))
12818 {
12819 return errorExp();
12820 }
12821 if (exp.ti.needsTypeInference(sc))
12822 return exp;
12823 exp.ti.dsymbolSemantic(sc);
12824 if (!exp.ti.inst || exp.ti.errors) // if template failed to expand
12825 return errorExp();
12826
12827 if (Declaration v = exp.ti.toAlias().isDeclaration())
12828 {
12829 if (v.type && !v.type.deco)
12830 v.type = v.type.typeSemantic(v.loc, sc);
12831 return new DotVarExp(exp.loc, exp.e1, v)
12832 .expressionSemantic(sc);
12833 }
12834 return new DotExp(exp.loc, exp.e1, new ScopeExp(exp.loc, exp.ti))
12835 .expressionSemantic(sc);
12836 }
12837 }
12838 else if (OverExp oe = e.isOverExp())
12839 {
12840 exp.ti.tempdecl = oe.vars;
12841 return new ScopeExp(exp.loc, exp.ti)
12842 .expressionSemantic(sc);
12843 }
12844
12845 Lerr:
12846 exp.error("`%s` isn't a template", e.toChars());
12847 return errorExp();
12848 }
12849
12850 /***************************************
12851 * If expression is shared, check that we can access it.
12852 * Give error message if not.
12853 *
12854 * Params:
12855 * e = expression to check
12856 * sc = context
12857 * returnRef = Whether this expression is for a `return` statement
12858 * off a `ref` function, in which case a single level
12859 * of dereference is allowed (e.g. `shared(int)*`).
12860 * Returns:
12861 * true on error
12862 */
12863 bool checkSharedAccess(Expression e, Scope* sc, bool returnRef = false)
12864 {
12865 if (!global.params.noSharedAccess ||
12866 sc.intypeof ||
12867 sc.flags & SCOPE.ctfe)
12868 {
12869 return false;
12870 }
12871
12872 //printf("checkSharedAccess() `%s` returnRef: %d\n", e.toChars(), returnRef);
12873
12874 /* In case we don't know which expression triggered it,
12875 * e.g. for `visit(Type)` overload
12876 */
12877 Expression original = e;
12878
check(Expression e,bool allowRef)12879 bool check(Expression e, bool allowRef)
12880 {
12881 bool sharedError(Expression e)
12882 {
12883 // https://dlang.org/phobos/core_atomic.html
12884 e.error("direct access to shared `%s` is not allowed, see `core.atomic`", e.toChars());
12885 return true;
12886 }
12887
12888 // Error by default
12889 bool visit(Expression e)
12890 {
12891 if (e.type.isShared())
12892 return sharedError(e);
12893 return false;
12894 }
12895
12896 bool visitNew(NewExp e)
12897 {
12898 if (e.thisexp)
12899 check(e.thisexp, false);
12900 // Note: This handles things like `new shared(Throwable).msg`,
12901 // where accessing `msg` would violate `shared`.
12902 if (e.newtype.isShared())
12903 return sharedError(original);
12904 return false;
12905 }
12906
12907 bool visitVar(VarExp e)
12908 {
12909 if (!allowRef && e.var.type.isShared())
12910 return sharedError(e);
12911 return false;
12912 }
12913
12914 bool visitAddr(AddrExp e)
12915 {
12916 return check(e.e1, true);
12917 }
12918
12919 bool visitPtr(PtrExp e)
12920 {
12921 if (!allowRef && e.type.isShared())
12922 return sharedError(e);
12923
12924 if (e.e1.type.isShared())
12925 return sharedError(e);
12926
12927 return check(e.e1, false);
12928 }
12929
12930 bool visitDotVar(DotVarExp e)
12931 {
12932 auto fd = e.var.isFuncDeclaration();
12933 const sharedFunc = fd && fd.type.isShared;
12934
12935 if (!allowRef && e.type.isShared() && !sharedFunc)
12936 return sharedError(e);
12937
12938 // Allow using `DotVarExp` within value types
12939 if (e.e1.type.isTypeSArray() || e.e1.type.isTypeStruct())
12940 return check(e.e1, allowRef);
12941
12942 // If we end up with a single `VarExp`, it might be a `ref` param
12943 // `shared ref T` param == `shared(T)*`.
12944 if (auto ve = e.e1.isVarExp())
12945 {
12946 return check(e.e1, allowRef && (ve.var.storage_class & STC.ref_));
12947 }
12948
12949 return check(e.e1, false);
12950 }
12951
12952 bool visitIndex(IndexExp e)
12953 {
12954 if (!allowRef && e.type.isShared())
12955 return sharedError(e);
12956
12957 if (e.e1.type.isShared())
12958 return sharedError(e);
12959
12960 return check(e.e1, false);
12961 }
12962
12963 bool visitComma(CommaExp e)
12964 {
12965 // Cannot be `return ref` since we can't use the return,
12966 // but it's better to show that error than an unrelated `shared` one
12967 return check(e.e2, true);
12968 }
12969
12970 switch (e.op)
12971 {
12972 default: return visit(e);
12973
12974 // Those have no indirections / can be ignored
12975 case EXP.call:
12976 case EXP.error:
12977 case EXP.complex80:
12978 case EXP.int64:
12979 case EXP.null_: return false;
12980
12981 case EXP.variable: return visitVar(e.isVarExp());
12982 case EXP.new_: return visitNew(e.isNewExp());
12983 case EXP.address: return visitAddr(e.isAddrExp());
12984 case EXP.star: return visitPtr(e.isPtrExp());
12985 case EXP.dotVariable: return visitDotVar(e.isDotVarExp());
12986 case EXP.index: return visitIndex(e.isIndexExp());
12987 }
12988 }
12989
12990 return check(e, returnRef);
12991 }
12992
12993
12994
12995 /****************************************************
12996 * Determine if `exp`, which gets its address taken, can do so safely.
12997 * Params:
12998 * sc = context
12999 * exp = expression having its address taken
13000 * v = the variable getting its address taken
13001 * Returns:
13002 * `true` if ok, `false` for error
13003 */
checkAddressVar(Scope * sc,Expression exp,VarDeclaration v)13004 bool checkAddressVar(Scope* sc, Expression exp, VarDeclaration v)
13005 {
13006 //printf("checkAddressVar(exp: %s, v: %s)\n", exp.toChars(), v.toChars());
13007 if (v)
13008 {
13009 if (!v.canTakeAddressOf())
13010 {
13011 exp.error("cannot take address of `%s`", exp.toChars());
13012 return false;
13013 }
13014 if (sc.func && !sc.intypeof && !v.isDataseg())
13015 {
13016 const(char)* p = v.isParameter() ? "parameter" : "local";
13017 if (global.params.useDIP1000 == FeatureState.enabled)
13018 {
13019 // Taking the address of v means it cannot be set to 'scope' later
13020 v.storage_class &= ~STC.maybescope;
13021 v.doNotInferScope = true;
13022 if (exp.type.hasPointers() && v.storage_class & STC.scope_ &&
13023 !(v.storage_class & STC.temp) &&
13024 !(sc.flags & SCOPE.debug_) && sc.func.setUnsafe())
13025 {
13026 exp.error("cannot take address of `scope` %s `%s` in `@safe` function `%s`", p, v.toChars(), sc.func.toChars());
13027 return false;
13028 }
13029 }
13030 else if (!(sc.flags & SCOPE.debug_) &&
13031 !(v.storage_class & STC.temp) &&
13032 sc.func.setUnsafe())
13033 {
13034 exp.error("cannot take address of %s `%s` in `@safe` function `%s`", p, v.toChars(), sc.func.toChars());
13035 return false;
13036 }
13037 }
13038 }
13039 return true;
13040 }
13041
13042 /****************************************************
13043 * Determine if the address of a `ref return` value of
13044 * a function call with type `tf` can be taken safely.
13045 *
13046 * This is currently stricter than necessary: it can be safe to take the
13047 * address of a `ref` with pointer type when the pointer isn't `scope`, but
13048 * that involves inspecting the function arguments and parameter types, which
13049 * is left as a future enhancement.
13050 *
13051 * Params:
13052 * sc = context
13053 * ce = function call in question
13054 * action = for the error message, how the pointer is taken, e.g. "slice static array of"
13055 * Returns:
13056 * `true` if ok, `false` for error
13057 */
checkAddressCall(Scope * sc,CallExp ce,const (char)* action)13058 private bool checkAddressCall(Scope* sc, CallExp ce, const(char)* action)
13059 {
13060 if (auto tf = ce.e1.type.isTypeFunction())
13061 {
13062 if (tf.isref && sc.func && !sc.intypeof && !(sc.flags & SCOPE.debug_)
13063 && tf.next.hasPointers() && sc.func.setUnsafe())
13064 {
13065 ce.error("cannot %s `ref return` of `%s()` in `@safe` function `%s`",
13066 action, ce.e1.toChars(), sc.func.toChars());
13067 ce.errorSupplemental("return type `%s` has pointers that may be `scope`", tf.next.toChars());
13068 return false;
13069 }
13070 }
13071 return true;
13072 }
13073
13074 /*******************************
13075 * Checks the attributes of a function.
13076 * Purity (`pure`), safety (`@safe`), no GC allocations(`@nogc`)
13077 * and usage of `deprecated` and `@disabled`-ed symbols are checked.
13078 *
13079 * Params:
13080 * exp = expression to check attributes for
13081 * sc = scope of the function
13082 * f = function to be checked
13083 * Returns: `true` if error occur.
13084 */
checkFunctionAttributes(Expression exp,Scope * sc,FuncDeclaration f)13085 private bool checkFunctionAttributes(Expression exp, Scope* sc, FuncDeclaration f)
13086 {
13087 with(exp)
13088 {
13089 bool error = checkDisabled(sc, f);
13090 error |= checkDeprecated(sc, f);
13091 error |= checkPurity(sc, f);
13092 error |= checkSafety(sc, f);
13093 error |= checkNogc(sc, f);
13094 return error;
13095 }
13096 }
13097
13098 /*******************************
13099 * Helper function for `getRightThis()`.
13100 * Gets `this` of the next outer aggregate.
13101 * Params:
13102 * loc = location to use for error messages
13103 * sc = context
13104 * s = the parent symbol of the existing `this`
13105 * ad = struct or class we need the correct `this` for
13106 * e1 = existing `this`
13107 * t = type of the existing `this`
13108 * var = the specific member of ad we're accessing
13109 * flag = if true, return `null` instead of throwing an error
13110 * Returns:
13111 * Expression representing the `this` for the var
13112 */
13113 Expression getThisSkipNestedFuncs(const ref Loc loc, Scope* sc, Dsymbol s, AggregateDeclaration ad, Expression e1, Type t, Dsymbol var, bool flag = false)
13114 {
13115 int n = 0;
13116 while (s && s.isFuncDeclaration())
13117 {
13118 FuncDeclaration f = s.isFuncDeclaration();
13119 if (f.vthis)
13120 {
13121 n++;
13122 e1 = new VarExp(loc, f.vthis);
13123 if (f.hasDualContext())
13124 {
13125 // (*__this)[i]
13126 if (n > 1)
13127 e1 = e1.expressionSemantic(sc);
13128 e1 = new PtrExp(loc, e1);
13129 uint i = f.followInstantiationContext(ad);
13130 e1 = new IndexExp(loc, e1, new IntegerExp(i));
13131 s = f.toParentP(ad);
13132 continue;
13133 }
13134 }
13135 else
13136 {
13137 if (flag)
13138 return null;
13139 e1.error("need `this` of type `%s` to access member `%s` from static function `%s`", ad.toChars(), var.toChars(), f.toChars());
13140 e1 = ErrorExp.get();
13141 return e1;
13142 }
13143 s = s.toParent2();
13144 }
13145 if (n > 1 || e1.op == EXP.index)
13146 e1 = e1.expressionSemantic(sc);
13147 if (s && e1.type.equivalent(Type.tvoidptr))
13148 {
13149 if (auto sad = s.isAggregateDeclaration())
13150 {
13151 Type ta = sad.handleType();
13152 if (ta.ty == Tstruct)
13153 ta = ta.pointerTo();
13154 e1.type = ta;
13155 }
13156 }
13157 e1.type = e1.type.addMod(t.mod);
13158 return e1;
13159 }
13160
13161 /*******************************
13162 * Make a dual-context container for use as a `this` argument.
13163 * Params:
13164 * loc = location to use for error messages
13165 * sc = current scope
13166 * fd = target function that will take the `this` argument
13167 * Returns:
13168 * Temporary closure variable.
13169 * Note:
13170 * The function `fd` is added to the nested references of the
13171 * newly created variable such that a closure is made for the variable when
13172 * the address of `fd` is taken.
13173 */
makeThis2Argument(const ref Loc loc,Scope * sc,FuncDeclaration fd)13174 VarDeclaration makeThis2Argument(const ref Loc loc, Scope* sc, FuncDeclaration fd)
13175 {
13176 Type tthis2 = Type.tvoidptr.sarrayOf(2);
13177 VarDeclaration vthis2 = new VarDeclaration(loc, tthis2, Identifier.generateId("__this"), null);
13178 vthis2.storage_class |= STC.temp;
13179 vthis2.dsymbolSemantic(sc);
13180 vthis2.parent = sc.parent;
13181 // make it a closure var
13182 assert(sc.func);
13183 sc.func.closureVars.push(vthis2);
13184 // add `fd` to the nested refs
13185 vthis2.nestedrefs.push(fd);
13186 return vthis2;
13187 }
13188
13189 /*******************************
13190 * Make sure that the runtime hook `id` exists.
13191 * Params:
13192 * loc = location to use for error messages
13193 * sc = current scope
13194 * id = the hook identifier
13195 * description = what the hook does
13196 * module_ = what module the hook is located in
13197 * Returns:
13198 * a `bool` indicating if the hook is present.
13199 */
13200 bool verifyHookExist(const ref Loc loc, ref Scope sc, Identifier id, string description, Identifier module_ = Id.object)
13201 {
13202 auto rootSymbol = sc.search(loc, Id.empty, null);
13203 if (auto moduleSymbol = rootSymbol.search(loc, module_))
13204 if (moduleSymbol.search(loc, id))
13205 return true;
13206 error(loc, "`%s.%s` not found. The current runtime does not support %.*s, or the runtime is corrupt.", module_.toChars(), id.toChars(), cast(int)description.length, description.ptr);
13207 return false;
13208 }
13209
13210 /***************************************
13211 * Fit elements[] to the corresponding types of the `sd`'s fields.
13212 *
13213 * Params:
13214 * sd = the struct declaration
13215 * loc = location to use for error messages
13216 * sc = context
13217 * elements = explicit arguments used to construct object
13218 * stype = the constructed object type.
13219 * Returns:
13220 * false if any errors occur,
13221 * otherwise true and elements[] are rewritten for the output.
13222 */
fit(StructDeclaration sd,const ref Loc loc,Scope * sc,Expressions * elements,Type stype)13223 private bool fit(StructDeclaration sd, const ref Loc loc, Scope* sc, Expressions* elements, Type stype)
13224 {
13225 if (!elements)
13226 return true;
13227
13228 const nfields = sd.nonHiddenFields();
13229 size_t offset = 0;
13230 for (size_t i = 0; i < elements.dim; i++)
13231 {
13232 Expression e = (*elements)[i];
13233 if (!e)
13234 continue;
13235
13236 e = resolveProperties(sc, e);
13237 if (i >= nfields)
13238 {
13239 if (i < sd.fields.dim && e.op == EXP.null_)
13240 {
13241 // CTFE sometimes creates null as hidden pointer; we'll allow this.
13242 continue;
13243 }
13244 .error(loc, "more initializers than fields (%llu) of `%s`", cast(ulong)nfields, sd.toChars());
13245 return false;
13246 }
13247 VarDeclaration v = sd.fields[i];
13248 if (v.offset < offset)
13249 {
13250 .error(loc, "overlapping initialization for `%s`", v.toChars());
13251 if (!sd.isUnionDeclaration())
13252 {
13253 enum errorMsg = "`struct` initializers that contain anonymous unions" ~
13254 " must initialize only the first member of a `union`. All subsequent" ~
13255 " non-overlapping fields are default initialized";
13256 .errorSupplemental(loc, errorMsg);
13257 }
13258 return false;
13259 }
13260 const vsize = v.type.size();
13261 if (vsize == SIZE_INVALID)
13262 return false;
13263 offset = cast(uint)(v.offset + vsize);
13264
13265 Type t = v.type;
13266 if (stype)
13267 t = t.addMod(stype.mod);
13268 Type origType = t;
13269 Type tb = t.toBasetype();
13270
13271 const hasPointers = tb.hasPointers();
13272 if (hasPointers)
13273 {
13274 if ((!stype.alignment.isDefault() && stype.alignment.get() < target.ptrsize ||
13275 (v.offset & (target.ptrsize - 1))) &&
13276 (sc.func && sc.func.setUnsafe()))
13277 {
13278 .error(loc, "field `%s.%s` cannot assign to misaligned pointers in `@safe` code",
13279 sd.toChars(), v.toChars());
13280 return false;
13281 }
13282 }
13283
13284 /* Look for case of initializing a static array with a too-short
13285 * string literal, such as:
13286 * char[5] foo = "abc";
13287 * Allow this by doing an explicit cast, which will lengthen the string
13288 * literal.
13289 */
13290 if (e.op == EXP.string_ && tb.ty == Tsarray)
13291 {
13292 StringExp se = cast(StringExp)e;
13293 Type typeb = se.type.toBasetype();
13294 TY tynto = tb.nextOf().ty;
13295 if (!se.committed &&
13296 (typeb.ty == Tarray || typeb.ty == Tsarray) && tynto.isSomeChar &&
13297 se.numberOfCodeUnits(tynto) < (cast(TypeSArray)tb).dim.toInteger())
13298 {
13299 e = se.castTo(sc, t);
13300 goto L1;
13301 }
13302 }
13303
13304 while (!e.implicitConvTo(t) && tb.ty == Tsarray)
13305 {
13306 /* Static array initialization, as in:
13307 * T[3][5] = e;
13308 */
13309 t = tb.nextOf();
13310 tb = t.toBasetype();
13311 }
13312 if (!e.implicitConvTo(t))
13313 t = origType; // restore type for better diagnostic
13314
13315 e = e.implicitCastTo(sc, t);
13316 L1:
13317 if (e.op == EXP.error)
13318 return false;
13319
13320 (*elements)[i] = doCopyOrMove(sc, e);
13321 }
13322 return true;
13323 }
13324
13325
13326 /**
13327 * Returns `em` as a VariableExp
13328 * Params:
13329 * em = the EnumMember to wrap
13330 * loc = location of use of em
13331 * sc = scope of use of em
13332 * Returns:
13333 * VarExp referenceing `em` or ErrorExp if `em` if disabled/deprecated
13334 */
getVarExp(EnumMember em,const ref Loc loc,Scope * sc)13335 Expression getVarExp(EnumMember em, const ref Loc loc, Scope* sc)
13336 {
13337 dsymbolSemantic(em, sc);
13338 if (em.errors)
13339 return ErrorExp.get();
13340 em.checkDisabled(loc, sc);
13341
13342 if (em.depdecl && !em.depdecl._scope)
13343 em.depdecl._scope = sc;
13344 em.checkDeprecated(loc, sc);
13345
13346 if (em.errors)
13347 return ErrorExp.get();
13348 Expression e = new VarExp(loc, em);
13349 e = e.expressionSemantic(sc);
13350 if (!(sc.flags & SCOPE.Cfile) && em.isCsymbol())
13351 {
13352 /* C11 types them as int. But if in D file,
13353 * type qualified names as the enum
13354 */
13355 e.type = em.parent.isEnumDeclaration().type;
13356 assert(e.type);
13357 }
13358 return e;
13359 }
13360
13361
13362 /*****************************
13363 * Try to treat `exp` as a boolean,
13364 * Params:
13365 * exp = the expression
13366 * sc = scope to evalute `exp` in
13367 * Returns:
13368 * Modified expression on success, ErrorExp on error
13369 */
toBoolean(Expression exp,Scope * sc)13370 Expression toBoolean(Expression exp, Scope* sc)
13371 {
13372 switch(exp.op)
13373 {
13374 case EXP.delete_:
13375 exp.error("`delete` does not give a boolean result");
13376 return ErrorExp.get();
13377
13378 case EXP.comma:
13379 auto ce = exp.isCommaExp();
13380 auto ex2 = ce.e2.toBoolean(sc);
13381 if (ex2.op == EXP.error)
13382 return ex2;
13383 ce.e2 = ex2;
13384 ce.type = ce.e2.type;
13385 return ce;
13386
13387 case EXP.assign:
13388 case EXP.construct:
13389 case EXP.blit:
13390 if (sc.flags & SCOPE.Cfile)
13391 return exp;
13392 // Things like:
13393 // if (a = b) ...
13394 // are usually mistakes.
13395 exp.error("assignment cannot be used as a condition, perhaps `==` was meant?");
13396 return ErrorExp.get();
13397
13398 //LogicalExp
13399 case EXP.andAnd:
13400 case EXP.orOr:
13401 auto le = exp.isLogicalExp();
13402 auto ex2 = le.e2.toBoolean(sc);
13403 if (ex2.op == EXP.error)
13404 return ex2;
13405 le.e2 = ex2;
13406 return le;
13407
13408 case EXP.question:
13409 auto ce = exp.isCondExp();
13410 auto ex1 = ce.e1.toBoolean(sc);
13411 auto ex2 = ce.e2.toBoolean(sc);
13412 if (ex1.op == EXP.error)
13413 return ex1;
13414 if (ex2.op == EXP.error)
13415 return ex2;
13416 ce.e1 = ex1;
13417 ce.e2 = ex2;
13418 return ce;
13419
13420
13421 default:
13422 // Default is 'yes' - do nothing
13423 Expression e = arrayFuncConv(exp, sc);
13424 Type t = e.type;
13425 Type tb = t.toBasetype();
13426 Type att = null;
13427
13428 while (1)
13429 {
13430 // Structs can be converted to bool using opCast(bool)()
13431 if (auto ts = tb.isTypeStruct())
13432 {
13433 AggregateDeclaration ad = ts.sym;
13434 /* Don't really need to check for opCast first, but by doing so we
13435 * get better error messages if it isn't there.
13436 */
13437 if (Dsymbol fd = search_function(ad, Id._cast))
13438 {
13439 e = new CastExp(exp.loc, e, Type.tbool);
13440 e = e.expressionSemantic(sc);
13441 return e;
13442 }
13443
13444 // Forward to aliasthis.
13445 if (ad.aliasthis && !isRecursiveAliasThis(att, tb))
13446 {
13447 e = resolveAliasThis(sc, e);
13448 t = e.type;
13449 tb = e.type.toBasetype();
13450 continue;
13451 }
13452 }
13453 break;
13454 }
13455
13456 if (!t.isBoolean())
13457 {
13458 if (tb != Type.terror)
13459 exp.error("expression `%s` of type `%s` does not have a boolean value",
13460 exp.toChars(), t.toChars());
13461 return ErrorExp.get();
13462 }
13463 return e;
13464 }
13465 }
13466