]> git.ipfire.org Git - people/ms/gcc.git/blame - gcc/d/dmd/expressionsem.d
d: Merge upstream dmd, druntime 4ca4140e58, phobos 454dff14d.
[people/ms/gcc.git] / gcc / d / dmd / expressionsem.d
CommitLineData
5fee5ec3
IB
1/**
2 * Semantic analysis of expressions.
3 *
4 * Specification: ($LINK2 https://dlang.org/spec/expression.html, Expressions)
5 *
f99303eb 6 * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved
c43b5909
IB
7 * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
8 * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
5fee5ec3
IB
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
14module dmd.expressionsem;
15
16import core.stdc.stdio;
17
18import dmd.access;
19import dmd.aggregate;
20import dmd.aliasthis;
21import dmd.arrayop;
22import dmd.arraytypes;
23import dmd.attrib;
24import dmd.astcodegen;
25import dmd.astenums;
26import dmd.canthrow;
27import dmd.chkformat;
28import dmd.ctorflow;
29import dmd.dscope;
30import dmd.dsymbol;
31import dmd.declaration;
32import dmd.dclass;
33import dmd.dcast;
34import dmd.delegatize;
35import dmd.denum;
36import dmd.dimport;
37import dmd.dinterpret;
38import dmd.dmangle;
39import dmd.dmodule;
40import dmd.dstruct;
41import dmd.dsymbolsem;
42import dmd.dtemplate;
43import dmd.errors;
44import dmd.escape;
45import dmd.expression;
0fb57034 46import dmd.file_manager;
5fee5ec3
IB
47import dmd.func;
48import dmd.globals;
49import dmd.hdrgen;
50import dmd.id;
51import dmd.identifier;
52import dmd.imphint;
0fb57034 53import dmd.importc;
5fee5ec3
IB
54import dmd.init;
55import dmd.initsem;
56import dmd.inline;
57import dmd.intrange;
f99303eb 58import dmd.location;
5fee5ec3 59import dmd.mtype;
31350635 60import dmd.mustuse;
5fee5ec3
IB
61import dmd.nspace;
62import dmd.opover;
63import dmd.optimize;
64import dmd.parse;
65import dmd.printast;
c8dfa79c 66import dmd.root.array;
5fee5ec3
IB
67import dmd.root.ctfloat;
68import dmd.root.file;
69import dmd.root.filename;
0fb57034 70import dmd.common.outbuffer;
5fee5ec3
IB
71import dmd.root.rootobject;
72import dmd.root.string;
c43b5909 73import dmd.root.utf;
5fee5ec3
IB
74import dmd.semantic2;
75import dmd.semantic3;
76import dmd.sideeffect;
77import dmd.safe;
78import dmd.target;
79import dmd.tokens;
80import dmd.traits;
81import dmd.typesem;
82import dmd.typinf;
5fee5ec3
IB
83import dmd.utils;
84import dmd.visitor;
85
86enum LOGSEMANTIC = false;
87
88/********************************************************
89 * Perform semantic analysis and CTFE on expressions to produce
90 * a string.
91 * Params:
92 * buf = append generated string to buffer
93 * sc = context
94 * exps = array of Expressions
95 * Returns:
96 * true on error
97 */
98bool expressionsToString(ref OutBuffer buf, Scope* sc, Expressions* exps)
99{
100 if (!exps)
101 return false;
102
103 foreach (ex; *exps)
104 {
105 if (!ex)
106 continue;
107 auto sc2 = sc.startCTFE();
8da8c7d3
IB
108 sc2.tinst = null;
109 sc2.minst = null; // prevents emission of any instantiated templates to object file
5fee5ec3
IB
110 auto e2 = ex.expressionSemantic(sc2);
111 auto e3 = resolveProperties(sc2, e2);
112 sc2.endCTFE();
113
114 // allowed to contain types as well as expressions
115 auto e4 = ctfeInterpretForPragmaMsg(e3);
9c7d5e88 116 if (!e4 || e4.op == EXP.error)
5fee5ec3
IB
117 return true;
118
119 // expand tuple
120 if (auto te = e4.isTupleExp())
121 {
122 if (expressionsToString(buf, sc, te.exps))
123 return true;
124 continue;
125 }
126 // char literals exp `.toStringExp` return `null` but we cant override it
127 // because in most contexts we don't want the conversion to succeed.
128 IntegerExp ie = e4.isIntegerExp();
129 const ty = (ie && ie.type) ? ie.type.ty : Terror;
130 if (ty.isSomeChar)
131 {
132 auto tsa = new TypeSArray(ie.type, IntegerExp.literal!1);
133 e4 = new ArrayLiteralExp(ex.loc, tsa, ie);
134 }
135
136 if (StringExp se = e4.toStringExp())
137 buf.writestring(se.toUTF8(sc).peekString());
138 else
139 buf.writestring(e4.toString());
140 }
141 return false;
142}
143
144
145/***********************************************************
146 * Resolve `exp` as a compile-time known string.
147 * Params:
148 * sc = scope
149 * exp = Expression which expected as a string
150 * s = What the string is expected for, will be used in error diagnostic.
151 * Returns:
152 * String literal, or `null` if error happens.
153 */
154StringExp semanticString(Scope *sc, Expression exp, const char* s)
155{
156 sc = sc.startCTFE();
157 exp = exp.expressionSemantic(sc);
158 exp = resolveProperties(sc, exp);
159 sc = sc.endCTFE();
160
9c7d5e88 161 if (exp.op == EXP.error)
5fee5ec3
IB
162 return null;
163
164 auto e = exp;
165 if (exp.type.isString())
166 {
167 e = e.ctfeInterpret();
9c7d5e88 168 if (e.op == EXP.error)
5fee5ec3
IB
169 return null;
170 }
171
172 auto se = e.toStringExp();
173 if (!se)
174 {
175 exp.error("`string` expected for %s, not `(%s)` of type `%s`",
176 s, exp.toChars(), exp.type.toChars());
177 return null;
178 }
179 return se;
180}
181
182private Expression extractOpDollarSideEffect(Scope* sc, UnaExp ue)
183{
184 Expression e0;
185 Expression e1 = Expression.extractLast(ue.e1, e0);
186 // https://issues.dlang.org/show_bug.cgi?id=12585
187 // Extract the side effect part if ue.e1 is comma.
188
189 if ((sc.flags & SCOPE.ctfe) ? hasSideEffect(e1) : !isTrivialExp(e1)) // match logic in extractSideEffect()
190 {
191 /* Even if opDollar is needed, 'e1' should be evaluate only once. So
192 * Rewrite:
193 * e1.opIndex( ... use of $ ... )
194 * e1.opSlice( ... use of $ ... )
195 * as:
196 * (ref __dop = e1, __dop).opIndex( ... __dop.opDollar ...)
197 * (ref __dop = e1, __dop).opSlice( ... __dop.opDollar ...)
198 */
199 e1 = extractSideEffect(sc, "__dop", e0, e1, false);
200 assert(e1.isVarExp());
201 e1.isVarExp().var.storage_class |= STC.exptemp; // lifetime limited to expression
202 }
203 ue.e1 = e1;
204 return e0;
205}
206
207/**************************************
208 * Runs semantic on ae.arguments. Declares temporary variables
209 * if '$' was used.
210 */
211Expression resolveOpDollar(Scope* sc, ArrayExp ae, Expression* pe0)
212{
213 assert(!ae.lengthVar);
214 *pe0 = null;
215 AggregateDeclaration ad = isAggregate(ae.e1.type);
216 Dsymbol slice = search_function(ad, Id.slice);
217 //printf("slice = %s %s\n", slice.kind(), slice.toChars());
218 foreach (i, e; *ae.arguments)
219 {
220 if (i == 0)
221 *pe0 = extractOpDollarSideEffect(sc, ae);
222
9c7d5e88 223 if (e.op == EXP.interval && !(slice && slice.isTemplateDeclaration()))
5fee5ec3
IB
224 {
225 Lfallback:
6d799f0a 226 if (ae.arguments.length == 1)
5fee5ec3
IB
227 return null;
228 ae.error("multi-dimensional slicing requires template `opSlice`");
229 return ErrorExp.get();
230 }
231 //printf("[%d] e = %s\n", i, e.toChars());
232
233 // Create scope for '$' variable for this dimension
234 auto sym = new ArrayScopeSymbol(sc, ae);
235 sym.parent = sc.scopesym;
236 sc = sc.push(sym);
237 ae.lengthVar = null; // Create it only if required
238 ae.currentDimension = i; // Dimension for $, if required
239
240 e = e.expressionSemantic(sc);
241 e = resolveProperties(sc, e);
242
243 if (ae.lengthVar && sc.func)
244 {
245 // If $ was used, declare it now
246 Expression de = new DeclarationExp(ae.loc, ae.lengthVar);
247 de = de.expressionSemantic(sc);
248 *pe0 = Expression.combine(*pe0, de);
249 }
250 sc = sc.pop();
251
252 if (auto ie = e.isIntervalExp())
253 {
254 auto tiargs = new Objects();
255 Expression edim = new IntegerExp(ae.loc, i, Type.tsize_t);
256 edim = edim.expressionSemantic(sc);
257 tiargs.push(edim);
258
259 auto fargs = new Expressions(2);
260 (*fargs)[0] = ie.lwr;
261 (*fargs)[1] = ie.upr;
262
263 uint xerrors = global.startGagging();
264 sc = sc.push();
8da8c7d3 265 FuncDeclaration fslice = resolveFuncCall(ae.loc, sc, slice, tiargs, ae.e1.type, ArgumentList(fargs), FuncResolveFlag.quiet);
5fee5ec3
IB
266 sc = sc.pop();
267 global.endGagging(xerrors);
268 if (!fslice)
269 goto Lfallback;
270
271 e = new DotTemplateInstanceExp(ae.loc, ae.e1, slice.ident, tiargs);
272 e = new CallExp(ae.loc, e, fargs);
273 e = e.expressionSemantic(sc);
274 }
275
276 if (!e.type)
277 {
278 ae.error("`%s` has no value", e.toChars());
279 e = ErrorExp.get();
280 }
9c7d5e88 281 if (e.op == EXP.error)
5fee5ec3
IB
282 return e;
283
284 (*ae.arguments)[i] = e;
285 }
286 return ae;
287}
288
289/**************************************
290 * Runs semantic on se.lwr and se.upr. Declares a temporary variable
291 * if '$' was used.
292 * Returns:
293 * ae, or ErrorExp if errors occurred
294 */
295Expression resolveOpDollar(Scope* sc, ArrayExp ae, IntervalExp ie, Expression* pe0)
296{
297 //assert(!ae.lengthVar);
298 if (!ie)
299 return ae;
300
301 VarDeclaration lengthVar = ae.lengthVar;
302 bool errors = false;
303
304 // create scope for '$'
305 auto sym = new ArrayScopeSymbol(sc, ae);
306 sym.parent = sc.scopesym;
307 sc = sc.push(sym);
308
309 Expression sem(Expression e)
310 {
311 e = e.expressionSemantic(sc);
312 e = resolveProperties(sc, e);
313 if (!e.type)
314 {
315 ae.error("`%s` has no value", e.toChars());
316 errors = true;
317 }
318 return e;
319 }
320
321 ie.lwr = sem(ie.lwr);
322 ie.upr = sem(ie.upr);
323
fd43568c
IB
324 if (ie.lwr.isErrorExp() || ie.upr.isErrorExp())
325 errors = true;
326
5fee5ec3
IB
327 if (lengthVar != ae.lengthVar && sc.func)
328 {
329 // If $ was used, declare it now
330 Expression de = new DeclarationExp(ae.loc, ae.lengthVar);
331 de = de.expressionSemantic(sc);
332 *pe0 = Expression.combine(*pe0, de);
333 }
334
335 sc = sc.pop();
336
337 return errors ? ErrorExp.get() : ae;
338}
339
340/******************************
341 * Perform semantic() on an array of Expressions.
342 */
c8dfa79c
IB
343extern(D) bool arrayExpressionSemantic(
344 Expression[] exps, Scope* sc, bool preserveErrors = false)
5fee5ec3
IB
345{
346 bool err = false;
c8dfa79c 347 foreach (ref e; exps)
5fee5ec3 348 {
c8dfa79c
IB
349 if (e is null) continue;
350 auto e2 = e.expressionSemantic(sc);
351 if (e2.op == EXP.error)
352 err = true;
353 if (preserveErrors || e2.op != EXP.error)
354 e = e2;
5fee5ec3
IB
355 }
356 return err;
357}
358
7e7ebe3e
IB
359/*
360Checks if `exp` contains a direct access to a `noreturn`
361variable. If that is the case, an `assert(0)` expression
362is generated and returned. This function should be called
363only after semantic analysis has been performed on `exp`.
364
365Params:
366 exp = expression that is checked
367
368Returns:
369 An `assert(0)` expression if `exp` contains a `noreturn`
370 variable access, `exp` otherwise.
371*/
372
373Expression checkNoreturnVarAccess(Expression exp)
374{
375 assert(exp.type);
376
377 Expression result = exp;
378 if (exp.type.isTypeNoreturn() && !exp.isAssertExp() &&
379 !exp.isThrowExp() && !exp.isCallExp())
380 {
381 auto msg = new StringExp(exp.loc, "Accessed expression of type `noreturn`");
382 msg.type = Type.tstring;
383 result = new AssertExp(exp.loc, IntegerExp.literal!0, msg);
384 result.type = exp.type;
385 }
386
387 return result;
388}
389
5fee5ec3
IB
390/******************************
391 * Check the tail CallExp is really property function call.
392 * Bugs:
393 * This doesn't appear to do anything.
394 */
395private bool checkPropertyCall(Expression e)
396{
397 e = lastComma(e);
398
399 if (auto ce = e.isCallExp())
400 {
401 if (ce.f)
402 {
403 auto tf = ce.f.type.isTypeFunction();
404 /* If a forward reference to ce.f, try to resolve it
405 */
406 if (!tf.deco && ce.f.semanticRun < PASS.semanticdone)
407 {
408 ce.f.dsymbolSemantic(null);
409 tf = ce.f.type.isTypeFunction();
410 }
411 }
412 else if (!ce.e1.type.isFunction_Delegate_PtrToFunction())
413 assert(0);
414 }
415 return false;
416}
417
418/******************************
419 * Find symbol in accordance with the UFCS name look up rule
420 */
421private Expression searchUFCS(Scope* sc, UnaExp ue, Identifier ident)
422{
423 //printf("searchUFCS(ident = %s)\n", ident.toChars());
424 Loc loc = ue.loc;
425
426 // TODO: merge with Scope.search.searchScopes()
427 Dsymbol searchScopes(int flags)
428 {
429 Dsymbol s = null;
430 for (Scope* scx = sc; scx; scx = scx.enclosing)
431 {
432 if (!scx.scopesym)
433 continue;
434 if (scx.scopesym.isModule())
435 flags |= SearchUnqualifiedModule; // tell Module.search() that SearchLocalsOnly is to be obeyed
436 s = scx.scopesym.search(loc, ident, flags);
437 if (s)
438 {
439 // overload set contains only module scope symbols.
440 if (s.isOverloadSet())
441 break;
442 // selective/renamed imports also be picked up
443 if (AliasDeclaration ad = s.isAliasDeclaration())
444 {
445 if (ad._import)
446 break;
447 }
448 // See only module scope symbols for UFCS target.
449 Dsymbol p = s.toParent2();
450 if (p && p.isModule())
451 break;
452 }
453 s = null;
454
455 // Stop when we hit a module, but keep going if that is not just under the global scope
456 if (scx.scopesym.isModule() && !(scx.enclosing && !scx.enclosing.enclosing))
457 break;
458 }
459 return s;
460 }
461
462 int flags = 0;
463 Dsymbol s;
464
465 if (sc.flags & SCOPE.ignoresymbolvisibility)
466 flags |= IgnoreSymbolVisibility;
467
468 // First look in local scopes
469 s = searchScopes(flags | SearchLocalsOnly);
470 if (!s)
471 {
472 // Second look in imported modules
473 s = searchScopes(flags | SearchImportsOnly);
474 }
475
476 if (!s)
c8dfa79c 477 return ue.e1.type.getProperty(sc, loc, ident, 0, ue.e1);
5fee5ec3
IB
478
479 FuncDeclaration f = s.isFuncDeclaration();
480 if (f)
481 {
482 TemplateDeclaration td = getFuncTemplateDecl(f);
483 if (td)
484 {
485 if (td.overroot)
486 td = td.overroot;
487 s = td;
488 }
489 }
490
491 if (auto dti = ue.isDotTemplateInstanceExp())
492 {
493 auto ti = new TemplateInstance(loc, s.ident, dti.ti.tiargs);
494 if (!ti.updateTempDecl(sc, s))
495 return ErrorExp.get();
496 return new ScopeExp(loc, ti);
497 }
498 else
499 {
500 //printf("-searchUFCS() %s\n", s.toChars());
501 return new DsymbolExp(loc, s);
502 }
503}
504
505/******************************
506 * Pull out callable entity with UFCS.
507 */
508private Expression resolveUFCS(Scope* sc, CallExp ce)
509{
510 Loc loc = ce.loc;
511 Expression eleft;
512 Expression e;
513
514 if (auto die = ce.e1.isDotIdExp())
515 {
516 Identifier ident = die.ident;
517
f99303eb 518 Expression ex = die.dotIdSemanticPropX(sc);
5fee5ec3
IB
519 if (ex != die)
520 {
521 ce.e1 = ex;
522 return null;
523 }
524 eleft = die.e1;
525
526 Type t = eleft.type.toBasetype();
527 if (t.ty == Tarray || t.ty == Tsarray || t.ty == Tnull || (t.isTypeBasic() && t.ty != Tvoid))
528 {
529 /* Built-in types and arrays have no callable properties, so do shortcut.
530 * It is necessary in: e.init()
531 */
532 }
533 else if (t.ty == Taarray)
534 {
535 if (ident == Id.remove)
536 {
537 /* Transform:
538 * aa.remove(arg) into delete aa[arg]
539 */
6d799f0a 540 if (!ce.arguments || ce.arguments.length != 1)
5fee5ec3
IB
541 {
542 ce.error("expected key as argument to `aa.remove()`");
543 return ErrorExp.get();
544 }
545 if (!eleft.type.isMutable())
546 {
547 ce.error("cannot remove key from `%s` associative array `%s`", MODtoChars(t.mod), eleft.toChars());
548 return ErrorExp.get();
549 }
550 Expression key = (*ce.arguments)[0];
551 key = key.expressionSemantic(sc);
552 key = resolveProperties(sc, key);
553
554 TypeAArray taa = t.isTypeAArray();
555 key = key.implicitCastTo(sc, taa.index);
556
557 if (key.checkValue() || key.checkSharedAccess(sc))
558 return ErrorExp.get();
559
560 semanticTypeInfo(sc, taa.index);
561
562 return new RemoveExp(loc, eleft, key);
563 }
564 }
565 else
566 {
f99303eb 567 if (Expression ey = die.dotIdSemanticProp(sc, 1))
5fee5ec3 568 {
9c7d5e88 569 if (ey.op == EXP.error)
5fee5ec3
IB
570 return ey;
571 ce.e1 = ey;
572 if (isDotOpDispatch(ey))
573 {
5fee5ec3
IB
574 // even opDispatch and UFCS must have valid arguments,
575 // so now that we've seen indication of a problem,
576 // check them for issues.
577 Expressions* originalArguments = Expression.arraySyntaxCopy(ce.arguments);
578
fd43568c
IB
579 uint errors = global.startGagging();
580 e = ce.expressionSemantic(sc);
581 if (!global.endGagging(errors))
582 return e;
583
c8dfa79c 584 if (arrayExpressionSemantic(originalArguments.peekSlice(), sc))
5fee5ec3
IB
585 return ErrorExp.get();
586
587 /* fall down to UFCS */
588 }
589 else
590 return null;
591 }
592 }
593
594 /* https://issues.dlang.org/show_bug.cgi?id=13953
595 *
596 * If a struct has an alias this to an associative array
597 * and remove is used on a struct instance, we have to
598 * check first if there is a remove function that can be called
599 * on the struct. If not we must check the alias this.
600 *
601 * struct A
602 * {
603 * string[string] a;
604 * alias a this;
605 * }
606 *
607 * void fun()
608 * {
609 * A s;
610 * s.remove("foo");
611 * }
612 */
613 const errors = global.startGagging();
614 e = searchUFCS(sc, die, ident);
615 // if there were any errors and the identifier was remove
616 if (global.endGagging(errors))
617 {
618 if (ident == Id.remove)
619 {
620 // check alias this
621 Expression alias_e = resolveAliasThis(sc, die.e1, 1);
622 if (alias_e && alias_e != die.e1)
623 {
624 die.e1 = alias_e;
625 CallExp ce2 = ce.syntaxCopy();
626 ce2.e1 = die;
627 e = ce2.isCallExp().trySemantic(sc);
628 if (e)
629 return e;
630 }
631 }
632 // if alias this did not work out, print the initial errors
633 searchUFCS(sc, die, ident);
634 }
635 }
636 else if (auto dti = ce.e1.isDotTemplateInstanceExp())
637 {
f99303eb 638 if (Expression ey = dti.dotTemplateSemanticProp(sc, 1))
5fee5ec3
IB
639 {
640 ce.e1 = ey;
641 return null;
642 }
643 eleft = dti.e1;
644 e = searchUFCS(sc, dti, dti.ti.name);
645 }
646 else
647 return null;
648
649 // Rewrite
650 ce.e1 = e;
651 if (!ce.arguments)
652 ce.arguments = new Expressions();
653 ce.arguments.shift(eleft);
8da8c7d3
IB
654 if (!ce.names)
655 ce.names = new Identifiers();
656 ce.names.shift(null);
5fee5ec3
IB
657
658 return null;
659}
660
661/******************************
662 * Pull out property with UFCS.
663 */
664private Expression resolveUFCSProperties(Scope* sc, Expression e1, Expression e2 = null)
665{
666 Loc loc = e1.loc;
667 Expression eleft;
668 Expression e;
669
670 if (auto die = e1.isDotIdExp())
671 {
672 eleft = die.e1;
673 e = searchUFCS(sc, die, die.ident);
674 }
675 else if (auto dti = e1.isDotTemplateInstanceExp())
676 {
677 eleft = dti.e1;
678 e = searchUFCS(sc, dti, dti.ti.name);
679 }
680 else
681 return null;
682
683 if (e is null)
684 return null;
685
686 // Rewrite
687 if (e2)
688 {
689 // run semantic without gagging
690 e2 = e2.expressionSemantic(sc);
691
692 /* f(e1) = e2
693 */
694 Expression ex = e.copy();
695 auto a1 = new Expressions(1);
696 (*a1)[0] = eleft;
697 ex = new CallExp(loc, ex, a1);
698 auto e1PassSemantic = ex.trySemantic(sc);
699
700 /* f(e1, e2)
701 */
702 auto a2 = new Expressions(2);
703 (*a2)[0] = eleft;
704 (*a2)[1] = e2;
705 e = new CallExp(loc, e, a2);
706 e = e.trySemantic(sc);
707 if (!e1PassSemantic && !e)
708 {
709 /* https://issues.dlang.org/show_bug.cgi?id=20448
710 *
711 * If both versions have failed to pass semantic,
712 * f(e1) = e2 gets priority in error printing
713 * because f might be a templated function that
714 * failed to instantiate and we have to print
715 * the instantiation errors.
716 */
717 return e1.expressionSemantic(sc);
718 }
719 else if (ex && !e)
720 {
721 checkPropertyCall(ex);
722 ex = new AssignExp(loc, ex, e2);
723 return ex.expressionSemantic(sc);
724 }
725 else
726 {
727 // strict setter prints errors if fails
728 e = e.expressionSemantic(sc);
729 }
730 checkPropertyCall(e);
731 return e;
732 }
733 else
734 {
735 /* f(e1)
736 */
737 auto arguments = new Expressions(1);
738 (*arguments)[0] = eleft;
739 e = new CallExp(loc, e, arguments);
740 e = e.expressionSemantic(sc);
741 checkPropertyCall(e);
742 return e.expressionSemantic(sc);
743 }
744}
745
746/******************************
747 * If e1 is a property function (template), resolve it.
748 */
749Expression resolvePropertiesOnly(Scope* sc, Expression e1)
750{
31350635 751 //printf("e1 = %s %s\n", Token.toChars(e1.op), e1.toChars());
5fee5ec3
IB
752
753 Expression handleOverloadSet(OverloadSet os)
754 {
755 assert(os);
756 foreach (s; os.a)
757 {
758 auto fd = s.isFuncDeclaration();
759 auto td = s.isTemplateDeclaration();
760 if (fd)
761 {
762 if (fd.type.isTypeFunction().isproperty)
763 return resolveProperties(sc, e1);
764 }
765 else if (td && td.onemember && (fd = td.onemember.isFuncDeclaration()) !is null)
766 {
767 if (fd.type.isTypeFunction().isproperty ||
768 (fd.storage_class2 & STC.property) ||
769 (td._scope.stc & STC.property))
770 return resolveProperties(sc, e1);
771 }
772 }
773 return e1;
774 }
775
776 Expression handleTemplateDecl(TemplateDeclaration td)
777 {
778 assert(td);
779 if (td.onemember)
780 {
781 if (auto fd = td.onemember.isFuncDeclaration())
782 {
783 if (fd.type.isTypeFunction().isproperty ||
784 (fd.storage_class2 & STC.property) ||
785 (td._scope.stc & STC.property))
786 return resolveProperties(sc, e1);
787 }
788 }
789 return e1;
790 }
791
792 Expression handleFuncDecl(FuncDeclaration fd)
793 {
794 assert(fd);
795 if (fd.type.isTypeFunction().isproperty)
796 return resolveProperties(sc, e1);
797 return e1;
798 }
799
800 if (auto de = e1.isDotExp())
801 {
802 if (auto os = de.e2.isOverExp())
803 return handleOverloadSet(os.vars);
804 }
805 else if (auto oe = e1.isOverExp())
806 return handleOverloadSet(oe.vars);
807 else if (auto dti = e1.isDotTemplateInstanceExp())
808 {
809 if (dti.ti.tempdecl)
810 if (auto td = dti.ti.tempdecl.isTemplateDeclaration())
811 return handleTemplateDecl(td);
812 }
813 else if (auto dte = e1.isDotTemplateExp())
814 return handleTemplateDecl(dte.td);
815 else if (auto se = e1.isScopeExp())
816 {
817 Dsymbol s = se.sds;
818 TemplateInstance ti = s.isTemplateInstance();
819 if (ti && !ti.semanticRun && ti.tempdecl)
820 if (auto td = ti.tempdecl.isTemplateDeclaration())
821 return handleTemplateDecl(td);
822 }
823 else if (auto et = e1.isTemplateExp())
824 return handleTemplateDecl(et.td);
825 else if (e1.isDotVarExp() && e1.type.isTypeFunction())
826 {
827 DotVarExp dve = e1.isDotVarExp();
828 return handleFuncDecl(dve.var.isFuncDeclaration());
829 }
830 else if (e1.isVarExp() && e1.type && e1.type.isTypeFunction() && (sc.intypeof || !e1.isVarExp().var.needThis()))
831 return handleFuncDecl(e1.isVarExp().var.isFuncDeclaration());
832 return e1;
833}
834
835/****************************************
836 * Turn symbol `s` into the expression it represents.
837 *
838 * Params:
839 * s = symbol to resolve
840 * loc = location of use of `s`
841 * sc = context
842 * hasOverloads = applies if `s` represents a function.
843 * true means it's overloaded and will be resolved later,
844 * false means it's the exact function symbol.
845 * Returns:
846 * `s` turned into an expression, `ErrorExp` if an error occurred
847 */
848Expression symbolToExp(Dsymbol s, const ref Loc loc, Scope *sc, bool hasOverloads)
849{
850 static if (LOGSEMANTIC)
851 {
852 printf("DsymbolExp::resolve(%s %s)\n", s.kind(), s.toChars());
853 }
854
855Lagain:
856 Expression e;
857
858 //printf("DsymbolExp:: %p '%s' is a symbol\n", this, toChars());
859 //printf("s = '%s', s.kind = '%s'\n", s.toChars(), s.kind());
860 Dsymbol olds = s;
861 Declaration d = s.isDeclaration();
862 if (d && (d.storage_class & STC.templateparameter))
863 {
864 s = s.toAlias();
865 }
866 else
867 {
868 // functions are checked after overloading
869 // templates are checked after matching constraints
870 if (!s.isFuncDeclaration() && !s.isTemplateDeclaration())
871 {
872 s.checkDeprecated(loc, sc);
873 if (d)
874 d.checkDisabled(loc, sc);
875 }
876
877 // https://issues.dlang.org/show_bug.cgi?id=12023
878 // if 's' is a tuple variable, the tuple is returned.
879 s = s.toAlias();
880
881 //printf("s = '%s', s.kind = '%s', s.needThis() = %p\n", s.toChars(), s.kind(), s.needThis());
882 if (s != olds && !s.isFuncDeclaration() && !s.isTemplateDeclaration())
883 {
884 s.checkDeprecated(loc, sc);
885 if (d)
886 d.checkDisabled(loc, sc);
887 }
7e7ebe3e
IB
888
889 if (auto sd = s.isDeclaration())
890 {
891 if (sd.isSystem())
892 {
893 if (sc.setUnsafePreview(global.params.systemVariables, false, loc,
894 "cannot access `@system` variable `%s` in @safe code", sd))
895 {
896 return ErrorExp.get();
897 }
898 }
899 }
5fee5ec3
IB
900 }
901
902 if (auto em = s.isEnumMember())
903 {
904 return em.getVarExp(loc, sc);
905 }
906 if (auto v = s.isVarDeclaration())
907 {
908 //printf("Identifier '%s' is a variable, type '%s'\n", s.toChars(), v.type.toChars());
909 if (sc.intypeof == 1 && !v.inuse)
910 v.dsymbolSemantic(sc);
911 if (!v.type || // during variable type inference
912 !v.type.deco && v.inuse) // during variable type semantic
913 {
914 if (v.inuse) // variable type depends on the variable itself
915 error(loc, "circular reference to %s `%s`", v.kind(), v.toPrettyChars());
916 else // variable type cannot be determined
917 error(loc, "forward reference to %s `%s`", v.kind(), v.toPrettyChars());
918 return ErrorExp.get();
919 }
920 if (v.type.ty == Terror)
921 return ErrorExp.get();
922
923 if ((v.storage_class & STC.manifest) && v._init)
924 {
925 if (v.inuse)
926 {
927 error(loc, "circular initialization of %s `%s`", v.kind(), v.toPrettyChars());
928 return ErrorExp.get();
929 }
930 e = v.expandInitializer(loc);
931 v.inuse++;
932 e = e.expressionSemantic(sc);
933 v.inuse--;
934 return e;
935 }
936
937 // We need to run semantics to correctly set 'STC.field' if it is a member variable
938 // that could be forward referenced. This is needed for 'v.needThis()' to work
939 if (v.isThis())
940 v.dsymbolSemantic(sc);
941
942 // Change the ancestor lambdas to delegate before hasThis(sc) call.
943 if (v.checkNestedReference(sc, loc))
944 return ErrorExp.get();
945
946 if (v.needThis() && hasThis(sc))
947 e = new DotVarExp(loc, new ThisExp(loc), v);
948 else
949 e = new VarExp(loc, v);
950 e = e.expressionSemantic(sc);
951 return e;
952 }
953 if (auto fld = s.isFuncLiteralDeclaration())
954 {
955 //printf("'%s' is a function literal\n", fld.toChars());
956 e = new FuncExp(loc, fld);
957 return e.expressionSemantic(sc);
958 }
959 if (auto f = s.isFuncDeclaration())
960 {
961 f = f.toAliasFunc();
962 if (!f.functionSemantic())
963 return ErrorExp.get();
964
965 if (!hasOverloads && f.checkForwardRef(loc))
966 return ErrorExp.get();
967
968 auto fd = s.isFuncDeclaration();
969 fd.type = f.type;
970 return new VarExp(loc, fd, hasOverloads);
971 }
972 if (OverDeclaration od = s.isOverDeclaration())
973 {
974 e = new VarExp(loc, od, true);
975 e.type = Type.tvoid;
976 return e;
977 }
978 if (OverloadSet o = s.isOverloadSet())
979 {
980 //printf("'%s' is an overload set\n", o.toChars());
981 return new OverExp(loc, o);
982 }
983
984 if (Import imp = s.isImport())
985 {
986 if (!imp.pkg)
987 {
988 .error(loc, "forward reference of import `%s`", imp.toChars());
989 return ErrorExp.get();
990 }
991 auto ie = new ScopeExp(loc, imp.pkg);
992 return ie.expressionSemantic(sc);
993 }
994 if (Package pkg = s.isPackage())
995 {
996 auto ie = new ScopeExp(loc, pkg);
997 return ie.expressionSemantic(sc);
998 }
999 if (Module mod = s.isModule())
1000 {
1001 auto ie = new ScopeExp(loc, mod);
1002 return ie.expressionSemantic(sc);
1003 }
1004 if (Nspace ns = s.isNspace())
1005 {
1006 auto ie = new ScopeExp(loc, ns);
1007 return ie.expressionSemantic(sc);
1008 }
1009
1010 if (Type t = s.getType())
1011 {
1012 return (new TypeExp(loc, t)).expressionSemantic(sc);
1013 }
1014
1015 if (TupleDeclaration tup = s.isTupleDeclaration())
1016 {
1017 if (tup.needThis() && hasThis(sc))
1018 e = new DotVarExp(loc, new ThisExp(loc), tup);
1019 else
1020 e = new TupleExp(loc, tup);
1021 e = e.expressionSemantic(sc);
1022 return e;
1023 }
1024
1025 if (TemplateInstance ti = s.isTemplateInstance())
1026 {
1027 ti.dsymbolSemantic(sc);
1028 if (!ti.inst || ti.errors)
1029 return ErrorExp.get();
1030 s = ti.toAlias();
1031 if (!s.isTemplateInstance())
1032 goto Lagain;
1033 e = new ScopeExp(loc, ti);
1034 e = e.expressionSemantic(sc);
1035 return e;
1036 }
1037 if (TemplateDeclaration td = s.isTemplateDeclaration())
1038 {
1039 Dsymbol p = td.toParentLocal();
1040 FuncDeclaration fdthis = hasThis(sc);
1041 AggregateDeclaration ad = p ? p.isAggregateDeclaration() : null;
1042 if (fdthis && ad && fdthis.isMemberLocal() == ad && (td._scope.stc & STC.static_) == 0)
1043 {
1044 e = new DotTemplateExp(loc, new ThisExp(loc), td);
1045 }
1046 else
1047 e = new TemplateExp(loc, td);
1048 e = e.expressionSemantic(sc);
1049 return e;
1050 }
1051
1052 .error(loc, "%s `%s` is not a variable", s.kind(), s.toChars());
1053 return ErrorExp.get();
1054}
1055
1056/*************************************************************
1057 * Given var, get the
1058 * right `this` pointer if var is in an outer class, but our
1059 * existing `this` pointer is in an inner class.
1060 * Params:
1061 * loc = location to use for error messages
1062 * sc = context
1063 * ad = struct or class we need the correct `this` for
1064 * e1 = existing `this`
1065 * var = the specific member of ad we're accessing
1066 * flag = if true, return `null` instead of throwing an error
1067 * Returns:
1068 * Expression representing the `this` for the var
1069 */
1070private Expression getRightThis(const ref Loc loc, Scope* sc, AggregateDeclaration ad, Expression e1, Dsymbol var, int flag = 0)
1071{
1072 //printf("\ngetRightThis(e1 = %s, ad = %s, var = %s)\n", e1.toChars(), ad.toChars(), var.toChars());
1073L1:
1074 Type t = e1.type.toBasetype();
1075 //printf("e1.type = %s, var.type = %s\n", e1.type.toChars(), var.type.toChars());
1076
9c7d5e88 1077 if (e1.op == EXP.objcClassReference)
5fee5ec3
IB
1078 {
1079 // We already have an Objective-C class reference, just use that as 'this'.
1080 return e1;
1081 }
1082 else if (ad && ad.isClassDeclaration && ad.isClassDeclaration.classKind == ClassKind.objc &&
1083 var.isFuncDeclaration && var.isFuncDeclaration.isStatic &&
1084 var.isFuncDeclaration.objc.selector)
1085 {
1086 return new ObjcClassReferenceExp(e1.loc, ad.isClassDeclaration());
1087 }
1088
1089 /* Access of a member which is a template parameter in dual-scope scenario
1090 * class A { inc(alias m)() { ++m; } } // `m` needs `this` of `B`
1091 * class B {int m; inc() { new A().inc!m(); } }
1092 */
9c7d5e88 1093 if (e1.op == EXP.this_)
5fee5ec3
IB
1094 {
1095 FuncDeclaration f = hasThis(sc);
235d5a96 1096 if (f && f.hasDualContext())
5fee5ec3
IB
1097 {
1098 if (f.followInstantiationContext(ad))
1099 {
1100 e1 = new VarExp(loc, f.vthis);
1101 e1 = new PtrExp(loc, e1);
1102 e1 = new IndexExp(loc, e1, IntegerExp.literal!1);
1103 e1 = getThisSkipNestedFuncs(loc, sc, f.toParent2(), ad, e1, t, var);
9c7d5e88 1104 if (e1.op == EXP.error)
5fee5ec3
IB
1105 return e1;
1106 goto L1;
1107 }
1108 }
1109 }
1110
1111 /* If e1 is not the 'this' pointer for ad
1112 */
1113 if (ad &&
1114 !(t.isTypePointer() && t.nextOf().isTypeStruct() && t.nextOf().isTypeStruct().sym == ad) &&
1115 !(t.isTypeStruct() && t.isTypeStruct().sym == ad))
1116 {
1117 ClassDeclaration cd = ad.isClassDeclaration();
1118 ClassDeclaration tcd = t.isClassHandle();
1119
1120 /* e1 is the right this if ad is a base class of e1
1121 */
1122 if (!cd || !tcd || !(tcd == cd || cd.isBaseOf(tcd, null)))
1123 {
1124 /* Only classes can be inner classes with an 'outer'
1125 * member pointing to the enclosing class instance
1126 */
1127 if (tcd && tcd.isNested())
1128 {
1129 /* e1 is the 'this' pointer for an inner class: tcd.
1130 * Rewrite it as the 'this' pointer for the outer class.
1131 */
1132 auto vthis = tcd.followInstantiationContext(ad) ? tcd.vthis2 : tcd.vthis;
1133 e1 = new DotVarExp(loc, e1, vthis);
1134 e1.type = vthis.type;
1135 e1.type = e1.type.addMod(t.mod);
1136 // Do not call ensureStaticLinkTo()
1137 //e1 = e1.semantic(sc);
1138
1139 // Skip up over nested functions, and get the enclosing
1140 // class type.
1141 e1 = getThisSkipNestedFuncs(loc, sc, tcd.toParentP(ad), ad, e1, t, var);
9c7d5e88 1142 if (e1.op == EXP.error)
5fee5ec3
IB
1143 return e1;
1144 goto L1;
1145 }
1146
1147 /* Can't find a path from e1 to ad
1148 */
1149 if (flag)
1150 return null;
1151 e1.error("`this` for `%s` needs to be type `%s` not type `%s`", var.toChars(), ad.toChars(), t.toChars());
1152 return ErrorExp.get();
1153 }
1154 }
1155 return e1;
1156}
1157
1158/***************************************
1159 * Pull out any properties.
1160 */
1161private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 = null)
1162{
9c7d5e88 1163 //printf("resolvePropertiesX, e1 = %s %s, e2 = %s\n", EXPtoString(e1.op).ptr, e1.toChars(), e2 ? e2.toChars() : null);
5fee5ec3
IB
1164 Loc loc = e1.loc;
1165
1166 OverloadSet os;
1167 Dsymbol s;
1168 Objects* tiargs;
1169 Type tthis;
1170 if (auto de = e1.isDotExp())
1171 {
1172 if (auto oe = de.e2.isOverExp())
1173 {
1174 tiargs = null;
1175 tthis = de.e1.type;
1176 os = oe.vars;
1177 goto Los;
1178 }
1179 }
1180 else if (e1.isOverExp())
1181 {
1182 tiargs = null;
1183 tthis = null;
1184 os = e1.isOverExp().vars;
1185 Los:
1186 assert(os);
1187 FuncDeclaration fd = null;
1188 if (e2)
1189 {
1190 e2 = e2.expressionSemantic(sc);
9c7d5e88 1191 if (e2.op == EXP.error)
5fee5ec3
IB
1192 return ErrorExp.get();
1193 e2 = resolveProperties(sc, e2);
1194
1195 Expressions a;
1196 a.push(e2);
1197
6d799f0a 1198 for (size_t i = 0; i < os.a.length; i++)
5fee5ec3 1199 {
8da8c7d3 1200 if (FuncDeclaration f = resolveFuncCall(loc, sc, os.a[i], tiargs, tthis, ArgumentList(&a), FuncResolveFlag.quiet))
5fee5ec3
IB
1201 {
1202 if (f.errors)
1203 return ErrorExp.get();
1204 fd = f;
1205 assert(fd.type.ty == Tfunction);
1206 }
1207 }
1208 if (fd)
1209 {
1210 Expression e = new CallExp(loc, e1, e2);
1211 return e.expressionSemantic(sc);
1212 }
1213 }
1214 {
6d799f0a 1215 for (size_t i = 0; i < os.a.length; i++)
5fee5ec3 1216 {
8da8c7d3 1217 if (FuncDeclaration f = resolveFuncCall(loc, sc, os.a[i], tiargs, tthis, ArgumentList(), FuncResolveFlag.quiet))
5fee5ec3
IB
1218 {
1219 if (f.errors)
1220 return ErrorExp.get();
1221 fd = f;
1222 assert(fd.type.ty == Tfunction);
1223 auto tf = fd.type.isTypeFunction();
1224 if (!tf.isref && e2)
1225 {
1226 error(loc, "%s is not an lvalue", e1.toChars());
1227 return ErrorExp.get();
1228 }
1229 }
1230 }
1231 if (fd)
1232 {
1233 Expression e = new CallExp(loc, e1);
1234 if (e2)
1235 e = new AssignExp(loc, e, e2);
1236 return e.expressionSemantic(sc);
1237 }
1238 }
1239 if (e2)
1240 goto Leprop;
1241 }
1242 else if (auto dti = e1.isDotTemplateInstanceExp())
1243 {
1244 if (!dti.findTempDecl(sc))
1245 goto Leprop;
1246 if (!dti.ti.semanticTiargs(sc))
1247 goto Leprop;
1248 tiargs = dti.ti.tiargs;
1249 tthis = dti.e1.type;
1250 if ((os = dti.ti.tempdecl.isOverloadSet()) !is null)
1251 goto Los;
1252 if ((s = dti.ti.tempdecl) !is null)
1253 goto Lfd;
1254 }
1255 else if (auto dte = e1.isDotTemplateExp())
1256 {
1257 s = dte.td;
1258 tiargs = null;
1259 tthis = dte.e1.type;
1260 goto Lfd;
1261 }
1262 else if (auto se = e1.isScopeExp())
1263 {
1264 s = se.sds;
1265 TemplateInstance ti = s.isTemplateInstance();
1266 if (ti && !ti.semanticRun && ti.tempdecl)
1267 {
1268 //assert(ti.needsTypeInference(sc));
1269 if (!ti.semanticTiargs(sc))
1270 goto Leprop;
1271 tiargs = ti.tiargs;
1272 tthis = null;
1273 if ((os = ti.tempdecl.isOverloadSet()) !is null)
1274 goto Los;
1275 if ((s = ti.tempdecl) !is null)
1276 goto Lfd;
1277 }
1278 }
1279 else if (auto te = e1.isTemplateExp())
1280 {
1281 s = te.td;
1282 tiargs = null;
1283 tthis = null;
1284 goto Lfd;
1285 }
6384eff5 1286 else if (e1.isDotVarExp() && e1.type && (e1.type.toBasetype().isTypeFunction() || e1.isDotVarExp().var.isOverDeclaration()))
5fee5ec3 1287 {
6384eff5 1288 DotVarExp dve = e1.isDotVarExp();
5fee5ec3
IB
1289 s = dve.var;
1290 tiargs = null;
1291 tthis = dve.e1.type;
1292 goto Lfd;
1293 }
6384eff5 1294 else if (sc && sc.flags & SCOPE.Cfile && e1.isVarExp() && !e2)
0fb57034
IB
1295 {
1296 // ImportC: do not implicitly call function if no ( ) are present
1297 }
6384eff5 1298 else if (e1.isVarExp() && e1.type && (e1.type.toBasetype().isTypeFunction() || e1.isVarExp().var.isOverDeclaration()))
5fee5ec3 1299 {
6384eff5 1300 s = e1.isVarExp().var;
5fee5ec3
IB
1301 tiargs = null;
1302 tthis = null;
1303 Lfd:
1304 assert(s);
1305 if (e2)
1306 {
1307 e2 = e2.expressionSemantic(sc);
9c7d5e88 1308 if (e2.op == EXP.error)
5fee5ec3
IB
1309 return ErrorExp.get();
1310 e2 = resolveProperties(sc, e2);
1311
1312 Expressions a;
1313 a.push(e2);
1314
8da8c7d3 1315 FuncDeclaration fd = resolveFuncCall(loc, sc, s, tiargs, tthis, ArgumentList(&a), FuncResolveFlag.quiet);
5fee5ec3
IB
1316 if (fd && fd.type)
1317 {
1318 if (fd.errors)
1319 return ErrorExp.get();
1320 if (!checkSymbolAccess(sc, fd))
1321 {
6384eff5 1322 // @@@DEPRECATED_2.105@@@
5fee5ec3 1323 // When turning into error, uncomment the return statement
6384eff5 1324 TypeFunction tf = fd.type.isTypeFunction();
5eb9927a 1325 deprecation(loc, "function `%s` of type `%s` is not accessible from module `%s`",
5fee5ec3
IB
1326 fd.toPrettyChars(), tf.toChars, sc._module.toChars);
1327 //return ErrorExp.get();
1328 }
1329 assert(fd.type.ty == Tfunction);
1330 Expression e = new CallExp(loc, e1, e2);
1331 return e.expressionSemantic(sc);
1332 }
1333 }
1334 {
8da8c7d3 1335 FuncDeclaration fd = resolveFuncCall(loc, sc, s, tiargs, tthis, ArgumentList(), FuncResolveFlag.quiet);
5fee5ec3
IB
1336 if (fd && fd.type)
1337 {
1338 if (fd.errors)
1339 return ErrorExp.get();
6384eff5 1340 TypeFunction tf = fd.type.isTypeFunction();
5fee5ec3
IB
1341 if (!e2 || tf.isref)
1342 {
1343 if (!checkSymbolAccess(sc, fd))
1344 {
6384eff5 1345 // @@@DEPRECATED_2.105@@@
5fee5ec3 1346 // When turning into error, uncomment the return statement
5eb9927a 1347 deprecation(loc, "function `%s` of type `%s` is not accessible from module `%s`",
5fee5ec3
IB
1348 fd.toPrettyChars(), tf.toChars, sc._module.toChars);
1349 //return ErrorExp.get();
1350 }
1351 Expression e = new CallExp(loc, e1);
1352 if (e2)
1353 e = new AssignExp(loc, e, e2);
1354 return e.expressionSemantic(sc);
1355 }
1356 }
1357 }
1358 if (FuncDeclaration fd = s.isFuncDeclaration())
1359 {
1360 // Keep better diagnostic message for invalid property usage of functions
1361 assert(fd.type.ty == Tfunction);
1362 Expression e = new CallExp(loc, e1, e2);
1363 return e.expressionSemantic(sc);
1364 }
1365 if (e2)
1366 goto Leprop;
1367 }
6384eff5 1368 if (auto ve = e1.isVarExp())
5fee5ec3 1369 {
6384eff5
IB
1370 if (auto v = ve.var.isVarDeclaration())
1371 {
1372 if (ve.checkPurity(sc, v))
1373 return ErrorExp.get();
1374 }
5fee5ec3
IB
1375 }
1376 if (e2)
1377 return null;
1378
6384eff5 1379 if (e1.type && !e1.isTypeExp()) // function type is not a property
5fee5ec3
IB
1380 {
1381 /* Look for e1 being a lazy parameter; rewrite as delegate call
1382 * only if the symbol wasn't already treated as a delegate
1383 */
1384 auto ve = e1.isVarExp();
1385 if (ve && ve.var.storage_class & STC.lazy_ && !ve.delegateWasExtracted)
1386 {
1387 Expression e = new CallExp(loc, e1);
1388 return e.expressionSemantic(sc);
1389 }
6384eff5 1390 else if (e1.isDotVarExp())
5fee5ec3
IB
1391 {
1392 // Check for reading overlapped pointer field in @safe code.
1393 if (checkUnsafeAccess(sc, e1, true, true))
1394 return ErrorExp.get();
1395 }
6384eff5 1396 else if (auto ce = e1.isCallExp())
5fee5ec3 1397 {
5fee5ec3
IB
1398 // Check for reading overlapped pointer field in @safe code.
1399 if (checkUnsafeAccess(sc, ce.e1, true, true))
1400 return ErrorExp.get();
1401 }
1402 }
1403
1404 if (!e1.type)
1405 {
1406 error(loc, "cannot resolve type for %s", e1.toChars());
1407 e1 = ErrorExp.get();
1408 }
1409 return e1;
1410
1411Leprop:
1412 error(loc, "not a property %s", e1.toChars());
1413 return ErrorExp.get();
1414}
1415
1416extern (C++) Expression resolveProperties(Scope* sc, Expression e)
1417{
1418 //printf("resolveProperties(%s)\n", e.toChars());
1419 e = resolvePropertiesX(sc, e);
1420 if (e.checkRightThis(sc))
1421 return ErrorExp.get();
1422 return e;
1423}
1424
1425/****************************************
1426 * The common type is determined by applying ?: to each pair.
1427 * Output:
1428 * exps[] properties resolved, implicitly cast to common type, rewritten in place
1429 * Returns:
1430 * The common type, or `null` if an error has occured
1431 */
1432private Type arrayExpressionToCommonType(Scope* sc, ref Expressions exps)
1433{
1434 /* Still have a problem with:
1435 * ubyte[][] = [ cast(ubyte[])"hello", [1]];
1436 * which works if the array literal is initialized top down with the ubyte[][]
1437 * type, but fails with this function doing bottom up typing.
1438 */
1439
1440 //printf("arrayExpressionToCommonType()\n");
1441 scope IntegerExp integerexp = IntegerExp.literal!0;
1442 scope CondExp condexp = new CondExp(Loc.initial, integerexp, null, null);
1443
1444 Type t0 = null;
1445 Expression e0 = null;
5fee5ec3
IB
1446 bool foundType;
1447
6d799f0a 1448 for (size_t i = 0; i < exps.length; i++)
5fee5ec3
IB
1449 {
1450 Expression e = exps[i];
1451 if (!e)
1452 continue;
1453
1454 e = resolveProperties(sc, e);
1455 if (!e.type)
1456 {
1457 e.error("`%s` has no value", e.toChars());
1458 t0 = Type.terror;
1459 continue;
1460 }
9c7d5e88 1461 if (e.op == EXP.type)
5fee5ec3
IB
1462 {
1463 foundType = true; // do not break immediately, there might be more errors
1464 e.checkValue(); // report an error "type T has no value"
1465 t0 = Type.terror;
1466 continue;
1467 }
1468 if (e.type.ty == Tvoid)
1469 {
1470 // void expressions do not concur to the determination of the common
1471 // type.
1472 continue;
1473 }
1474 if (checkNonAssignmentArrayOp(e))
1475 {
1476 t0 = Type.terror;
1477 continue;
1478 }
1479
1480 e = doCopyOrMove(sc, e);
1481
1482 if (!foundType && t0 && !t0.equals(e.type))
1483 {
1484 /* This applies ?: to merge the types. It's backwards;
1485 * ?: should call this function to merge types.
1486 */
1487 condexp.type = null;
1488 condexp.e1 = e0;
1489 condexp.e2 = e;
1490 condexp.loc = e.loc;
1491 Expression ex = condexp.expressionSemantic(sc);
9c7d5e88 1492 if (ex.op == EXP.error)
5fee5ec3 1493 e = ex;
5fee5ec3
IB
1494 else
1495 {
1496 // Convert to common type
0fb57034 1497 exps[i] = condexp.e1.castTo(sc, condexp.type);
5fee5ec3
IB
1498 e = condexp.e2.castTo(sc, condexp.type);
1499 }
1500 }
5fee5ec3
IB
1501 e0 = e;
1502 t0 = e.type;
9c7d5e88 1503 if (e.op != EXP.error)
5fee5ec3
IB
1504 exps[i] = e;
1505 }
1506
1507 // [] is typed as void[]
1508 if (!t0)
1509 return Type.tvoid;
1510
1511 // It's an error, don't do the cast
1512 if (t0.ty == Terror)
1513 return null;
1514
6d799f0a 1515 for (size_t i = 0; i < exps.length; i++)
5fee5ec3
IB
1516 {
1517 Expression e = exps[i];
1518 if (!e)
1519 continue;
1520
1521 e = e.implicitCastTo(sc, t0);
9c7d5e88 1522 if (e.op == EXP.error)
5fee5ec3
IB
1523 {
1524 /* https://issues.dlang.org/show_bug.cgi?id=13024
1525 * a workaround for the bug in typeMerge -
1526 * it should paint e1 and e2 by deduced common type,
1527 * but doesn't in this particular case.
1528 */
1529 return null;
1530 }
1531 exps[i] = e;
1532 }
1533 return t0;
1534}
1535
9c7d5e88 1536private Expression opAssignToOp(const ref Loc loc, EXP op, Expression e1, Expression e2)
5fee5ec3
IB
1537{
1538 Expression e;
1539 switch (op)
1540 {
9c7d5e88 1541 case EXP.addAssign:
5fee5ec3
IB
1542 e = new AddExp(loc, e1, e2);
1543 break;
1544
9c7d5e88 1545 case EXP.minAssign:
5fee5ec3
IB
1546 e = new MinExp(loc, e1, e2);
1547 break;
1548
9c7d5e88 1549 case EXP.mulAssign:
5fee5ec3
IB
1550 e = new MulExp(loc, e1, e2);
1551 break;
1552
9c7d5e88 1553 case EXP.divAssign:
5fee5ec3
IB
1554 e = new DivExp(loc, e1, e2);
1555 break;
1556
9c7d5e88 1557 case EXP.modAssign:
5fee5ec3
IB
1558 e = new ModExp(loc, e1, e2);
1559 break;
1560
9c7d5e88 1561 case EXP.andAssign:
5fee5ec3
IB
1562 e = new AndExp(loc, e1, e2);
1563 break;
1564
9c7d5e88 1565 case EXP.orAssign:
5fee5ec3
IB
1566 e = new OrExp(loc, e1, e2);
1567 break;
1568
9c7d5e88 1569 case EXP.xorAssign:
5fee5ec3
IB
1570 e = new XorExp(loc, e1, e2);
1571 break;
1572
9c7d5e88 1573 case EXP.leftShiftAssign:
5fee5ec3
IB
1574 e = new ShlExp(loc, e1, e2);
1575 break;
1576
9c7d5e88 1577 case EXP.rightShiftAssign:
5fee5ec3
IB
1578 e = new ShrExp(loc, e1, e2);
1579 break;
1580
9c7d5e88 1581 case EXP.unsignedRightShiftAssign:
5fee5ec3
IB
1582 e = new UshrExp(loc, e1, e2);
1583 break;
1584
1585 default:
1586 assert(0);
1587 }
1588 return e;
1589}
1590
1591/*********************
1592 * Rewrite:
1593 * array.length op= e2
5fee5ec3
IB
1594 */
1595private Expression rewriteOpAssign(BinExp exp)
1596{
6384eff5
IB
1597 ArrayLengthExp ale = exp.e1.isArrayLengthExp();
1598 if (ale.e1.isVarExp())
5fee5ec3 1599 {
8da8c7d3 1600 // array.length = array.length op e2
6384eff5 1601 Expression e = opAssignToOp(exp.loc, exp.op, ale, exp.e2);
5fee5ec3 1602 e = new AssignExp(exp.loc, ale.syntaxCopy(), e);
6384eff5 1603 return e;
5fee5ec3
IB
1604 }
1605 else
1606 {
8da8c7d3
IB
1607 // (ref tmp = array;), tmp.length = tmp.length op e2
1608 auto tmp = copyToTemp(STC.ref_, "__arraylength", ale.e1);
1609 Expression e1 = new ArrayLengthExp(ale.loc, new VarExp(ale.loc, tmp));
5fee5ec3 1610 Expression elvalue = e1.syntaxCopy();
6384eff5 1611 Expression e = opAssignToOp(exp.loc, exp.op, e1, exp.e2);
5fee5ec3
IB
1612 e = new AssignExp(exp.loc, elvalue, e);
1613 e = new CommaExp(exp.loc, new DeclarationExp(ale.loc, tmp), e);
6384eff5 1614 return e;
5fee5ec3 1615 }
5fee5ec3
IB
1616}
1617
1618/****************************************
1619 * Preprocess arguments to function.
8da8c7d3
IB
1620 *
1621 * Tuples in argumentList get expanded, properties resolved, rewritten in place
1622 *
1623 * Params:
1624 * sc = scope
1625 * argumentList = arguments to function
1626 * reportErrors = whether or not to report errors here. Some callers are not
5fee5ec3 1627 * checking actual function params, so they'll do their own error reporting
5fee5ec3 1628 * Returns:
8da8c7d3 1629 * `true` when a semantic error occurred
5fee5ec3 1630 */
8da8c7d3 1631private bool preFunctionParameters(Scope* sc, ArgumentList argumentList, const bool reportErrors = true)
5fee5ec3 1632{
8da8c7d3 1633 Expressions* exps = argumentList.arguments;
5fee5ec3
IB
1634 bool err = false;
1635 if (exps)
1636 {
8da8c7d3 1637 expandTuples(exps, argumentList.names);
5fee5ec3 1638
6d799f0a 1639 for (size_t i = 0; i < exps.length; i++)
5fee5ec3
IB
1640 {
1641 Expression arg = (*exps)[i];
1642 arg = resolveProperties(sc, arg);
0fb57034 1643 arg = arg.arrayFuncConv(sc);
9c7d5e88 1644 if (arg.op == EXP.type)
5fee5ec3
IB
1645 {
1646 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
1647 arg = resolveAliasThis(sc, arg);
1648
9c7d5e88 1649 if (arg.op == EXP.type)
5fee5ec3
IB
1650 {
1651 if (reportErrors)
1652 {
1653 arg.error("cannot pass type `%s` as a function argument", arg.toChars());
1654 arg = ErrorExp.get();
1655 }
1656 err = true;
1657 }
1658 }
1659 else if (arg.type.toBasetype().ty == Tfunction)
1660 {
1661 if (reportErrors)
1662 {
1663 arg.error("cannot pass function `%s` as a function argument", arg.toChars());
1664 arg = ErrorExp.get();
1665 }
1666 err = true;
1667 }
1668 else if (checkNonAssignmentArrayOp(arg))
1669 {
1670 arg = ErrorExp.get();
1671 err = true;
1672 }
1673 (*exps)[i] = arg;
1674 }
1675 }
1676 return err;
1677}
1678
1679/********************************************
1680 * Issue an error if default construction is disabled for type t.
1681 * Default construction is required for arrays and 'out' parameters.
1682 * Returns:
1683 * true an error was issued
1684 */
1685private bool checkDefCtor(Loc loc, Type t)
1686{
6384eff5 1687 if (auto ts = t.baseElemOf().isTypeStruct())
5fee5ec3 1688 {
6384eff5 1689 StructDeclaration sd = ts.sym;
5fee5ec3
IB
1690 if (sd.noDefaultCtor)
1691 {
1692 sd.error(loc, "default construction is disabled");
1693 return true;
1694 }
1695 }
1696 return false;
1697}
1698
1699/****************************************
1700 * Now that we know the exact type of the function we're calling,
1701 * the arguments[] need to be adjusted:
1702 * 1. implicitly convert argument to the corresponding parameter type
1703 * 2. add default arguments for any missing arguments
1704 * 3. do default promotions on arguments corresponding to ...
1705 * 4. add hidden _arguments[] argument
1706 * 5. call copy constructor for struct value arguments
1707 * Params:
1708 * loc = location of function call
1709 * sc = context
1710 * tf = type of the function
1711 * ethis = `this` argument, `null` if none or not known
1712 * tthis = type of `this` argument, `null` if no `this` argument
8da8c7d3 1713 * argumentsList = array of actual arguments to function call
5fee5ec3
IB
1714 * fd = the function being called, `null` if called indirectly
1715 * prettype = set to return type of function
1716 * peprefix = set to expression to execute before `arguments[]` are evaluated, `null` if none
1717 * Returns:
1718 * true errors happened
1719 */
1720private bool functionParameters(const ref Loc loc, Scope* sc,
8da8c7d3 1721 TypeFunction tf, Expression ethis, Type tthis, ArgumentList argumentList, FuncDeclaration fd,
5fee5ec3
IB
1722 Type* prettype, Expression* peprefix)
1723{
8da8c7d3 1724 Expressions* arguments = argumentList.arguments;
5fee5ec3
IB
1725 //printf("functionParameters() %s\n", fd ? fd.toChars() : "");
1726 assert(arguments);
1727 assert(fd || tf.next);
5fee5ec3
IB
1728 const size_t nparams = tf.parameterList.length;
1729 const olderrors = global.errors;
1730 bool err = false;
5fee5ec3
IB
1731 Expression eprefix = null;
1732 *peprefix = null;
1733
8da8c7d3
IB
1734 if (argumentList.names)
1735 {
1736 const(char)* msg = null;
1737 auto resolvedArgs = tf.resolveNamedArgs(argumentList, &msg);
1738 if (!resolvedArgs)
1739 {
1740 // while errors are usually already caught by `tf.callMatch`,
1741 // this can happen when calling `typeof(freefunc)`
1742 if (msg)
1743 error(loc, "%s", msg);
1744 return true;
1745 }
1746 // note: the argument list should be mutated with named arguments / default arguments,
1747 // so we can't simply change the pointer like `arguments = resolvedArgs;`
1748 arguments.setDim(0);
1749 arguments.pushSlice((*resolvedArgs)[]);
1750 }
1751 size_t nargs = arguments ? arguments.length : 0;
1752
5fee5ec3
IB
1753 if (nargs > nparams && tf.parameterList.varargs == VarArg.none)
1754 {
1755 error(loc, "expected %llu arguments, not %llu for non-variadic function type `%s`", cast(ulong)nparams, cast(ulong)nargs, tf.toChars());
1756 return true;
1757 }
1758
1759 // If inferring return type, and semantic3() needs to be run if not already run
1760 if (!tf.next && fd.inferRetType)
1761 {
1762 fd.functionSemantic();
1763 }
1764 else if (fd && fd.parent)
1765 {
1766 TemplateInstance ti = fd.parent.isTemplateInstance();
1767 if (ti && ti.tempdecl)
1768 {
1769 fd.functionSemantic3();
1770 }
1771 }
1772
1773 /* If calling a pragma(inline, true) function,
1774 * set flag to later scan for inlines.
1775 */
1776 if (fd && fd.inlining == PINLINE.always)
1777 {
1778 if (sc._module)
1779 sc._module.hasAlwaysInlines = true;
1780 if (sc.func)
7e7ebe3e 1781 sc.func.hasAlwaysInlines = true;
5fee5ec3
IB
1782 }
1783
1784 const isCtorCall = fd && fd.needThis() && fd.isCtorDeclaration();
1785
1786 const size_t n = (nargs > nparams) ? nargs : nparams; // n = max(nargs, nparams)
1787
1788 /* If the function return type has wildcards in it, we'll need to figure out the actual type
1789 * based on the actual argument types.
1790 * Start with the `this` argument, later on merge into wildmatch the mod bits of the rest
1791 * of the arguments.
1792 */
1793 MOD wildmatch = (tthis && !isCtorCall) ? tthis.Type.deduceWild(tf, false) : 0;
1794
1795 bool done = false;
1796 foreach (const i; 0 .. n)
1797 {
1798 Expression arg = (i < nargs) ? (*arguments)[i] : null;
1799
1800 if (i < nparams)
1801 {
1802 bool errorArgs()
1803 {
1804 error(loc, "expected %llu function arguments, not %llu", cast(ulong)nparams, cast(ulong)nargs);
1805 return true;
1806 }
1807
1808 Parameter p = tf.parameterList[i];
1809
1810 if (!arg)
1811 {
1812 if (!p.defaultArg)
1813 {
1814 if (tf.parameterList.varargs == VarArg.typesafe && i + 1 == nparams)
1815 goto L2;
1816 return errorArgs();
1817 }
1818 arg = p.defaultArg;
8da8c7d3
IB
1819 if (!arg.type)
1820 arg = arg.expressionSemantic(sc);
5fee5ec3
IB
1821 arg = inlineCopy(arg, sc);
1822 // __FILE__, __LINE__, __MODULE__, __FUNCTION__, and __PRETTY_FUNCTION__
1823 arg = arg.resolveLoc(loc, sc);
8da8c7d3
IB
1824 if (i >= nargs)
1825 {
1826 arguments.push(arg);
1827 nargs++;
1828 }
1829 else
1830 (*arguments)[i] = arg;
5fee5ec3
IB
1831 }
1832 else
1833 {
1834 if (isDefaultInitOp(arg.op))
1835 {
1836 arg = arg.resolveLoc(loc, sc);
1837 (*arguments)[i] = arg;
1838 }
1839 }
1840
1841
1842 if (tf.parameterList.varargs == VarArg.typesafe && i + 1 == nparams) // https://dlang.org/spec/function.html#variadic
1843 {
1844 //printf("\t\tvarargs == 2, p.type = '%s'\n", p.type.toChars());
1845 {
1846 MATCH m;
1847 if ((m = arg.implicitConvTo(p.type)) > MATCH.nomatch)
1848 {
1849 if (p.type.nextOf() && arg.implicitConvTo(p.type.nextOf()) >= m)
1850 goto L2;
1851 else if (nargs != nparams)
1852 return errorArgs();
1853 goto L1;
1854 }
1855 }
1856 L2:
1857 Type tb = p.type.toBasetype();
1858 switch (tb.ty)
1859 {
1860 case Tsarray:
1861 case Tarray:
1862 {
1863 /* Create a static array variable v of type arg.type:
1864 * T[dim] __arrayArg = [ arguments[i], ..., arguments[nargs-1] ];
1865 *
1866 * The array literal in the initializer of the hidden variable
1867 * is now optimized.
1868 * https://issues.dlang.org/show_bug.cgi?id=2356
1869 */
1870 Type tbn = (cast(TypeArray)tb).next; // array element type
1871 Type tret = p.isLazyArray();
1872
1873 auto elements = new Expressions(nargs - i);
6d799f0a 1874 foreach (u; 0 .. elements.length)
5fee5ec3
IB
1875 {
1876 Expression a = (*arguments)[i + u];
1877 if (tret && a.implicitConvTo(tret))
1878 {
1879 // p is a lazy array of delegates, tret is return type of the delegates
1880 a = a.implicitCastTo(sc, tret)
1881 .optimize(WANTvalue)
1882 .toDelegate(tret, sc);
1883 }
1884 else
1885 a = a.implicitCastTo(sc, tbn);
1886 a = a.addDtorHook(sc);
1887 (*elements)[u] = a;
1888 }
1889 // https://issues.dlang.org/show_bug.cgi?id=14395
1890 // Convert to a static array literal, or its slice.
1891 arg = new ArrayLiteralExp(loc, tbn.sarrayOf(nargs - i), elements);
1892 if (tb.ty == Tarray)
1893 {
1894 arg = new SliceExp(loc, arg, null, null);
1895 arg.type = p.type;
1896 }
1897 break;
1898 }
1899 case Tclass:
1900 {
1901 /* Set arg to be:
1902 * new Tclass(arg0, arg1, ..., argn)
1903 */
1904 auto args = new Expressions(nargs - i);
1905 foreach (u; i .. nargs)
1906 (*args)[u - i] = (*arguments)[u];
6384eff5 1907 arg = new NewExp(loc, null, p.type, args);
5fee5ec3
IB
1908 break;
1909 }
1910 default:
1911 if (!arg)
1912 {
1913 error(loc, "not enough arguments");
1914 return true;
1915 }
1916 break;
1917 }
1918 arg = arg.expressionSemantic(sc);
1919 //printf("\targ = '%s'\n", arg.toChars());
1920 arguments.setDim(i + 1);
1921 (*arguments)[i] = arg;
1922 nargs = i + 1;
1923 done = true;
1924 }
1925
1926 L1:
ec486b73 1927 if (!(p.isLazy() && p.type.ty == Tvoid))
5fee5ec3
IB
1928 {
1929 if (ubyte wm = arg.type.deduceWild(p.type, p.isReference()))
1930 {
1931 wildmatch = wildmatch ? MODmerge(wildmatch, wm) : wm;
1932 //printf("[%d] p = %s, a = %s, wm = %d, wildmatch = %d\n", i, p.type.toChars(), arg.type.toChars(), wm, wildmatch);
1933 }
1934 }
1935 }
1936 if (done)
1937 break;
1938 }
1939 if ((wildmatch == MODFlags.mutable || wildmatch == MODFlags.immutable_) &&
1940 tf.next && tf.next.hasWild() &&
1941 (tf.isref || !tf.next.implicitConvTo(tf.next.immutableOf())))
1942 {
1943 bool errorInout(MOD wildmatch)
1944 {
1945 const(char)* s = wildmatch == MODFlags.mutable ? "mutable" : MODtoChars(wildmatch);
1946 error(loc, "modify `inout` to `%s` is not allowed inside `inout` function", s);
1947 return true;
1948 }
1949
1950 if (fd)
1951 {
1952 /* If the called function may return the reference to
1953 * outer inout data, it should be rejected.
1954 *
1955 * void foo(ref inout(int) x) {
1956 * ref inout(int) bar(inout(int)) { return x; }
1957 * struct S {
1958 * ref inout(int) bar() inout { return x; }
1959 * ref inout(int) baz(alias a)() inout { return x; }
1960 * }
1961 * bar(int.init) = 1; // bad!
1962 * S().bar() = 1; // bad!
1963 * }
1964 * void test() {
1965 * int a;
1966 * auto s = foo(a);
1967 * s.baz!a() = 1; // bad!
1968 * }
1969 *
1970 */
1971 bool checkEnclosingWild(Dsymbol s)
1972 {
1973 bool checkWild(Dsymbol s)
1974 {
1975 if (!s)
1976 return false;
1977 if (auto ad = s.isAggregateDeclaration())
1978 {
1979 if (ad.isNested())
1980 return checkEnclosingWild(s);
1981 }
1982 else if (auto ff = s.isFuncDeclaration())
1983 {
6384eff5 1984 if (ff.type.isTypeFunction().iswild)
5fee5ec3
IB
1985 return errorInout(wildmatch);
1986
1987 if (ff.isNested() || ff.isThis())
1988 return checkEnclosingWild(s);
1989 }
1990 return false;
1991 }
1992
1993 Dsymbol ctx0 = s.toParent2();
1994 Dsymbol ctx1 = s.toParentLocal();
1995 if (checkWild(ctx0))
1996 return true;
1997 if (ctx0 != ctx1)
1998 return checkWild(ctx1);
1999 return false;
2000 }
2001 if ((fd.isThis() || fd.isNested()) && checkEnclosingWild(fd))
2002 return true;
2003 }
2004 else if (tf.isWild())
2005 return errorInout(wildmatch);
2006 }
2007
8da8c7d3
IB
2008 Expression firstArg = null;
2009 final switch (returnParamDest(tf, tthis))
2010 {
2011 case ReturnParamDest.returnVal:
2012 break;
2013 case ReturnParamDest.firstArg:
2014 firstArg = nargs > 0 ? (*arguments)[0] : null;
2015 break;
2016 case ReturnParamDest.this_:
2017 firstArg = ethis;
2018 break;
2019 }
5fee5ec3
IB
2020
2021 assert(nargs >= nparams);
2022 foreach (const i, arg; (*arguments)[0 .. nargs])
2023 {
2024 assert(arg);
2025 if (i < nparams)
2026 {
2027 Parameter p = tf.parameterList[i];
2028 Type targ = arg.type; // keep original type for isCopyable() because alias this
2029 // resolution may hide an uncopyable type
2030
ec486b73 2031 if (!(p.isLazy() && p.type.ty == Tvoid))
5fee5ec3
IB
2032 {
2033 Type tprm = p.type.hasWild()
2034 ? p.type.substWildTo(wildmatch)
2035 : p.type;
2036
6384eff5 2037 const hasCopyCtor = arg.type.isTypeStruct() && arg.type.isTypeStruct().sym.hasCopyCtor;
5fee5ec3
IB
2038 const typesMatch = arg.type.mutableOf().unSharedOf().equals(tprm.mutableOf().unSharedOf());
2039 if (!((hasCopyCtor && typesMatch) || tprm.equals(arg.type)))
2040 {
2041 //printf("arg.type = %s, p.type = %s\n", arg.type.toChars(), p.type.toChars());
2042 arg = arg.implicitCastTo(sc, tprm);
2043 arg = arg.optimize(WANTvalue, p.isReference());
2044 }
2045 }
2046
2047 // Support passing rvalue to `in` parameters
2048 if ((p.storageClass & (STC.in_ | STC.ref_)) == (STC.in_ | STC.ref_))
2049 {
2050 if (!arg.isLvalue())
2051 {
2052 auto v = copyToTemp(STC.exptemp, "__rvalue", arg);
2053 Expression ev = new DeclarationExp(arg.loc, v);
2054 ev = new CommaExp(arg.loc, ev, new VarExp(arg.loc, v));
2055 arg = ev.expressionSemantic(sc);
2056 }
2057 arg = arg.toLvalue(sc, arg);
2058
2059 // Look for mutable misaligned pointer, etc., in @safe mode
2060 err |= checkUnsafeAccess(sc, arg, false, true);
2061 }
2062 else if (p.storageClass & STC.ref_)
2063 {
fbdaa581 2064 if (global.params.rvalueRefParam == FeatureState.enabled &&
5fee5ec3
IB
2065 !arg.isLvalue() &&
2066 targ.isCopyable())
2067 { /* allow rvalues to be passed to ref parameters by copying
2068 * them to a temp, then pass the temp as the argument
2069 */
2070 auto v = copyToTemp(0, "__rvalue", arg);
2071 Expression ev = new DeclarationExp(arg.loc, v);
2072 ev = new CommaExp(arg.loc, ev, new VarExp(arg.loc, v));
2073 arg = ev.expressionSemantic(sc);
2074 }
2075 arg = arg.toLvalue(sc, arg);
2076
2077 // Look for mutable misaligned pointer, etc., in @safe mode
2078 err |= checkUnsafeAccess(sc, arg, false, true);
2079 }
2080 else if (p.storageClass & STC.out_)
2081 {
2082 Type t = arg.type;
2083 if (!t.isMutable() || !t.isAssignable()) // check blit assignable
2084 {
2085 arg.error("cannot modify struct `%s` with immutable members", arg.toChars());
2086 err = true;
2087 }
2088 else
2089 {
2090 // Look for misaligned pointer, etc., in @safe mode
2091 err |= checkUnsafeAccess(sc, arg, false, true);
2092 err |= checkDefCtor(arg.loc, t); // t must be default constructible
2093 }
2094 arg = arg.toLvalue(sc, arg);
2095 }
ec486b73 2096 else if (p.isLazy())
5fee5ec3
IB
2097 {
2098 // Convert lazy argument to a delegate
2099 auto t = (p.type.ty == Tvoid) ? p.type : arg.type;
2100 arg = toDelegate(arg, t, sc);
2101 }
2102 //printf("arg: %s\n", arg.toChars());
2103 //printf("type: %s\n", arg.type.toChars());
2104 //printf("param: %s\n", p.toChars());
2105
ae56e2da
IB
2106 const pStc = tf.parameterStorageClass(tthis, p);
2107
2108 if (firstArg && (pStc & STC.return_))
5fee5ec3
IB
2109 {
2110 /* Argument value can be assigned to firstArg.
2111 * Check arg to see if it matters.
2112 */
5eb9927a 2113 err |= checkParamArgumentReturn(sc, firstArg, arg, p, false);
5fee5ec3 2114 }
ae56e2da
IB
2115 // Allow 'lazy' to imply 'scope' - lazy parameters can be passed along
2116 // as lazy parameters to the next function, but that isn't escaping.
5eb9927a 2117 else if (!(pStc & STC.lazy_))
5fee5ec3
IB
2118 {
2119 /* Argument value can escape from the called function.
2120 * Check arg to see if it matters.
2121 */
b7a586be 2122 VarDeclaration vPar = fd ? (fd.parameters ? (*fd.parameters)[i] : null) : null;
6d799f0a 2123 err |= checkParamArgumentEscape(sc, fd, p.ident, vPar, cast(STC) pStc, arg, false, false);
5fee5ec3 2124 }
5eb9927a
IB
2125
2126 // Turning heap allocations into stack allocations is dangerous without dip1000, since `scope` inference
2127 // may be unreliable when scope violations only manifest as deprecation warnings.
2128 // However, existing `@nogc` code may rely on it, so still do it when the parameter is explicitly marked `scope`
ec486b73 2129 const explicitScope = p.isLazy() ||
5eb9927a
IB
2130 ((p.storageClass & STC.scope_) && !(p.storageClass & STC.scopeinferred));
2131 if ((pStc & (STC.scope_ | STC.lazy_)) &&
2132 ((global.params.useDIP1000 == FeatureState.enabled) || explicitScope) &&
2133 !(pStc & STC.return_))
5fee5ec3
IB
2134 {
2135 /* Argument value cannot escape from the called function.
2136 */
2137 Expression a = arg;
6384eff5
IB
2138 if (auto ce = a.isCastExp())
2139 a = ce.e1;
5fee5ec3
IB
2140
2141 ArrayLiteralExp ale;
2142 if (p.type.toBasetype().ty == Tarray &&
5eb9927a 2143 (ale = a.isArrayLiteralExp()) !is null && ale.elements && ale.elements.length > 0)
5fee5ec3
IB
2144 {
2145 // allocate the array literal as temporary static array on the stack
5eb9927a 2146 ale.type = ale.type.nextOf().sarrayOf(ale.elements.length);
5fee5ec3
IB
2147 auto tmp = copyToTemp(0, "__arrayliteral_on_stack", ale);
2148 auto declareTmp = new DeclarationExp(ale.loc, tmp);
5eb9927a
IB
2149 auto castToSlice = new CastExp(ale.loc, new VarExp(ale.loc, tmp),
2150 p.type.substWildTo(MODFlags.mutable));
5fee5ec3
IB
2151 arg = CommaExp.combine(declareTmp, castToSlice);
2152 arg = arg.expressionSemantic(sc);
2153 }
6384eff5 2154 else if (auto fe = a.isFuncExp())
5fee5ec3
IB
2155 {
2156 /* Function literals can only appear once, so if this
2157 * appearance was scoped, there cannot be any others.
2158 */
5fee5ec3
IB
2159 fe.fd.tookAddressOf = 0;
2160 }
6384eff5 2161 else if (auto de = a.isDelegateExp())
5fee5ec3
IB
2162 {
2163 /* For passing a delegate to a scoped parameter,
2164 * this doesn't count as taking the address of it.
2165 * We only worry about 'escaping' references to the function.
2166 */
6384eff5 2167 if (auto ve = de.e1.isVarExp())
5fee5ec3 2168 {
6384eff5 2169 if (auto f = ve.var.isFuncDeclaration())
5fee5ec3
IB
2170 {
2171 if (f.tookAddressOf)
2172 --f.tookAddressOf;
2173 //printf("--tookAddressOf = %d\n", f.tookAddressOf);
2174 }
2175 }
2176 }
2177 }
2178 if (!p.isReference())
2179 err |= arg.checkSharedAccess(sc);
2180
2181 arg = arg.optimize(WANTvalue, p.isReference());
5fee5ec3
IB
2182 }
2183 else
2184 {
2185 // These will be the trailing ... arguments
2186 // If not D linkage, do promotions
2187 if (tf.linkage != LINK.d)
2188 {
2189 // Promote bytes, words, etc., to ints
2190 arg = integralPromotions(arg, sc);
2191
2192 // Promote floats to doubles
2193 switch (arg.type.ty)
2194 {
2195 case Tfloat32:
2196 arg = arg.castTo(sc, Type.tfloat64);
2197 break;
2198
2199 case Timaginary32:
2200 arg = arg.castTo(sc, Type.timaginary64);
2201 break;
2202
2203 default:
2204 break;
2205 }
2206 if (tf.parameterList.varargs == VarArg.variadic)
2207 {
2208 const(char)* p = tf.linkage == LINK.c ? "extern(C)" : "extern(C++)";
2209 if (arg.type.ty == Tarray)
2210 {
2211 arg.error("cannot pass dynamic arrays to `%s` vararg functions", p);
2212 err = true;
2213 }
2214 if (arg.type.ty == Tsarray)
2215 {
2216 arg.error("cannot pass static arrays to `%s` vararg functions", p);
2217 err = true;
2218 }
2219 }
2220 }
2221
2222 // Do not allow types that need destructors or copy constructors.
2223 if (arg.type.needsDestruction())
2224 {
2225 arg.error("cannot pass types that need destruction as variadic arguments");
2226 err = true;
2227 }
2228 if (arg.type.needsCopyOrPostblit())
2229 {
2230 arg.error("cannot pass types with postblits or copy constructors as variadic arguments");
2231 err = true;
2232 }
2233
2234 // Convert static arrays to dynamic arrays
2235 // BUG: I don't think this is right for D2
2236 Type tb = arg.type.toBasetype();
6384eff5 2237 if (auto ts = tb.isTypeSArray())
5fee5ec3 2238 {
5fee5ec3
IB
2239 Type ta = ts.next.arrayOf();
2240 if (ts.size(arg.loc) == 0)
2241 arg = new NullExp(arg.loc, ta);
2242 else
2243 arg = arg.castTo(sc, ta);
2244 }
2245 if (tb.ty == Tstruct)
2246 {
2247 //arg = callCpCtor(sc, arg);
2248 }
2249 // Give error for overloaded function addresses
6384eff5 2250 if (auto se = arg.isSymOffExp())
5fee5ec3 2251 {
5fee5ec3
IB
2252 if (se.hasOverloads && !se.var.isFuncDeclaration().isUnique())
2253 {
2254 arg.error("function `%s` is overloaded", arg.toChars());
2255 err = true;
2256 }
2257 }
2258 err |= arg.checkValue();
2259 err |= arg.checkSharedAccess(sc);
2260 arg = arg.optimize(WANTvalue);
2261 }
2262 (*arguments)[i] = arg;
2263 }
2264
2265 /* If calling C scanf(), printf(), or any variants, check the format string against the arguments
2266 */
2267 const isVa_list = tf.parameterList.varargs == VarArg.none;
7e7ebe3e 2268 if (fd && fd.printf)
5fee5ec3
IB
2269 {
2270 if (auto se = (*arguments)[nparams - 1 - isVa_list].isStringExp())
2271 {
2272 checkPrintfFormat(se.loc, se.peekString(), (*arguments)[nparams .. nargs], isVa_list);
2273 }
2274 }
7e7ebe3e 2275 else if (fd && fd.scanf)
5fee5ec3
IB
2276 {
2277 if (auto se = (*arguments)[nparams - 1 - isVa_list].isStringExp())
2278 {
2279 checkScanfFormat(se.loc, se.peekString(), (*arguments)[nparams .. nargs], isVa_list);
2280 }
2281 }
2282 else
2283 {
2284 // TODO: not checking the "v" functions yet (for those, check format string only, not args)
2285 }
2286
2287 /* Remaining problems:
2288 * 1. order of evaluation - some function push L-to-R, others R-to-L. Until we resolve what array assignment does (which is
2289 * implemented by calling a function) we'll defer this for now.
2290 * 2. value structs (or static arrays of them) that need to be copy constructed
2291 * 3. value structs (or static arrays of them) that have destructors, and subsequent arguments that may throw before the
2292 * function gets called.
2293 * 4. value structs need to be destructed after the function call for platforms where the caller destroys the arguments.
2294 * 2, 3 and 4 are handled by doing the argument construction in 'eprefix' so that if a later argument throws, they are cleaned
2295 * up properly. Pushing arguments on the stack then cannot fail.
2296 */
2297 {
2298 /* TODO: tackle problem 1)
2299 */
2300 const bool leftToRight = true; // TODO: Any cases that need rightToLeft?
2301 if (!leftToRight)
2302 assert(nargs == nparams); // no variadics for RTL order, as they would probably be evaluated LTR and so add complexity
2303
2304 /* Does Problem (4) apply?
2305 */
2306 const bool callerDestroysArgs = !target.isCalleeDestroyingArgs(tf);
2307
2308 const ptrdiff_t start = (leftToRight ? 0 : cast(ptrdiff_t)nargs - 1);
2309 const ptrdiff_t end = (leftToRight ? cast(ptrdiff_t)nargs : -1);
2310 const ptrdiff_t step = (leftToRight ? 1 : -1);
2311
2312 /* Compute indices of last throwing argument and first arg needing destruction.
2313 * Used to not set up destructors unless an arg needs destruction on a throw
2314 * in a later argument.
2315 */
2316 ptrdiff_t lastthrow = -1; // last argument that may throw
2317 ptrdiff_t firstdtor = -1; // first argument that needs destruction
2318 ptrdiff_t lastdtor = -1; // last argument that needs destruction
2319 for (ptrdiff_t i = start; i != end; i += step)
2320 {
2321 Expression arg = (*arguments)[i];
2322 if (canThrow(arg, sc.func, false))
2323 lastthrow = i;
2324 if (arg.type.needsDestruction())
2325 {
2326 Parameter p = (i >= nparams ? null : tf.parameterList[i]);
ec486b73 2327 if (!(p && (p.isLazy() || p.isReference())))
5fee5ec3
IB
2328 {
2329 if (firstdtor == -1)
2330 firstdtor = i;
2331 lastdtor = i;
2332 }
2333 }
2334 }
2335
2336 /* Do we need 'eprefix' for problems 3 or 4?
2337 */
2338 const bool needsPrefix = callerDestroysArgs
2339 ? firstdtor >= 0 // true if any argument needs destruction
2340 : firstdtor >= 0 && lastthrow >= 0 &&
2341 (lastthrow - firstdtor) * step > 0; // last throw after first destruction
2342 const ptrdiff_t lastPrefix = callerDestroysArgs
2343 ? lastdtor // up to last argument requiring destruction
2344 : lastthrow; // up to last potentially throwing argument
2345
2346 /* Problem 3: initialize 'eprefix' by declaring the gate
2347 */
2348 VarDeclaration gate;
2349 if (needsPrefix && !callerDestroysArgs)
2350 {
2351 // eprefix => bool __gate [= false]
2352 Identifier idtmp = Identifier.generateId("__gate");
2353 gate = new VarDeclaration(loc, Type.tbool, idtmp, null);
2354 gate.storage_class |= STC.temp | STC.ctfe | STC.volatile_;
2355 gate.dsymbolSemantic(sc);
2356
2357 auto ae = new DeclarationExp(loc, gate);
2358 eprefix = ae.expressionSemantic(sc);
2359 }
2360
2361 for (ptrdiff_t i = start; i != end; i += step)
2362 {
2363 Expression arg = (*arguments)[i];
2364 //printf("arg[%d]: %s\n", cast(int)i, arg.toChars());
2365
2366 Parameter parameter = (i >= nparams ? null : tf.parameterList[i]);
2367 const bool isRef = parameter && parameter.isReference();
ec486b73 2368 const bool isLazy = parameter && parameter.isLazy();
5fee5ec3
IB
2369
2370 /* Skip lazy parameters
2371 */
2372 if (isLazy)
2373 continue;
2374
2375 /* Do we have 'eprefix' and aren't past 'lastPrefix' yet?
2376 * Then declare a temporary variable for this arg and append that declaration
2377 * to 'eprefix', which will implicitly take care of potential problem 2) for
2378 * this arg.
2379 * 'eprefix' will therefore finally contain all args up to and including 'lastPrefix',
2380 * excluding all lazy parameters.
2381 */
2382 if (needsPrefix && (lastPrefix - i) * step >= 0)
2383 {
2384 const bool needsDtor = !isRef && arg.type.needsDestruction() &&
2385 // Problem 3: last throwing arg doesn't require dtor patching
2386 (callerDestroysArgs || i != lastPrefix);
2387
2388 /* Declare temporary 'auto __pfx = arg' (needsDtor) or 'auto __pfy = arg' (!needsDtor)
2389 */
2390 auto tmp = copyToTemp(
2391 (parameter ? parameter.storageClass : tf.parameterList.stc) & (STC.scope_),
2392 needsDtor ? "__pfx" : "__pfy",
2393 !isRef ? arg : arg.addressOf());
2394 tmp.dsymbolSemantic(sc);
2395
2396 if (callerDestroysArgs)
2397 {
2398 /* Problem 4: Normal temporary, destructed after the call
2399 */
2400 if (needsDtor)
2401 tmp.isArgDtorVar = true; // mark it so that the backend passes it by ref to the function being called
2402 }
2403 else
2404 {
2405 /* Problem 3: Modify the destructor so it only runs if gate==false,
2406 * i.e., only if there was a throw while constructing the args
2407 */
2408 if (!needsDtor)
2409 {
2410 if (tmp.edtor)
2411 {
2412 assert(i == lastPrefix);
2413 tmp.edtor = null;
2414 }
2415 }
2416 else
2417 {
2418 // edtor => (__gate || edtor)
2419 assert(tmp.edtor);
2420 Expression e = tmp.edtor;
9c7d5e88 2421 e = new LogicalExp(e.loc, EXP.orOr, new VarExp(e.loc, gate), e);
5fee5ec3
IB
2422 tmp.edtor = e.expressionSemantic(sc);
2423 //printf("edtor: %s\n", tmp.edtor.toChars());
2424 }
2425 }
2426
2427 // eprefix => (eprefix, auto __pfx/y = arg)
2428 auto ae = new DeclarationExp(loc, tmp);
2429 eprefix = Expression.combine(eprefix, ae.expressionSemantic(sc));
2430
2431 // arg => __pfx/y
2432 arg = new VarExp(loc, tmp);
2433 arg = arg.expressionSemantic(sc);
2434 if (isRef)
2435 {
2436 arg = new PtrExp(loc, arg);
2437 arg = arg.expressionSemantic(sc);
2438 }
2439
2440 /* Problem 3: Last throwing arg?
2441 * Then finalize eprefix => (eprefix, gate = true), i.e., disable the
2442 * dtors right after constructing the last throwing arg.
2443 * From now on, the callee will take care of destructing the args because
2444 * the args are implicitly moved into function parameters.
2445 */
2446 if (!callerDestroysArgs && i == lastPrefix)
2447 {
2448 auto e = new AssignExp(gate.loc, new VarExp(gate.loc, gate), IntegerExp.createBool(true));
2449 eprefix = Expression.combine(eprefix, e.expressionSemantic(sc));
2450 }
2451 }
2452 else // not part of 'eprefix'
2453 {
2454 /* Handle problem 2) by calling the copy constructor for value structs
2455 * (or static arrays of them) if appropriate.
2456 */
2457 Type tv = arg.type.baseElemOf();
2458 if (!isRef && tv.ty == Tstruct)
2459 arg = doCopyOrMove(sc, arg, parameter ? parameter.type : null);
2460 }
2461
2462 (*arguments)[i] = arg;
2463 }
2464 }
2465 //if (eprefix) printf("eprefix: %s\n", eprefix.toChars());
2466
8da8c7d3 2467 /* Test compliance with DIP1021 Argument Ownership and Function Calls
5fee5ec3 2468 */
8da8c7d3
IB
2469 if (global.params.useDIP1021 && (tf.trust == TRUST.safe || tf.trust == TRUST.default_) ||
2470 tf.islive)
5fee5ec3
IB
2471 err |= checkMutableArguments(sc, fd, tf, ethis, arguments, false);
2472
2473 // If D linkage and variadic, add _arguments[] as first argument
2474 if (tf.isDstyleVariadic())
2475 {
6d799f0a 2476 assert(arguments.length >= nparams);
5fee5ec3 2477
6d799f0a
IB
2478 auto args = new Parameters(arguments.length - nparams);
2479 for (size_t i = 0; i < arguments.length - nparams; i++)
5fee5ec3
IB
2480 {
2481 auto arg = new Parameter(STC.in_, (*arguments)[nparams + i].type, null, null, null);
2482 (*args)[i] = arg;
2483 }
2484 auto tup = new TypeTuple(args);
2485 Expression e = (new TypeidExp(loc, tup)).expressionSemantic(sc);
2486 arguments.insert(0, e);
2487 }
2488
2489 /* Determine function return type: tret
2490 */
2491 Type tret = tf.next;
2492 if (isCtorCall)
2493 {
2494 //printf("[%s] fd = %s %s, %d %d %d\n", loc.toChars(), fd.toChars(), fd.type.toChars(),
2495 // wildmatch, tf.isWild(), fd.isReturnIsolated());
2496 if (!tthis)
2497 {
2498 assert(sc.intypeof || global.errors);
2499 tthis = fd.isThis().type.addMod(fd.type.mod);
2500 }
2501 if (tf.isWild() && !fd.isReturnIsolated())
2502 {
2503 if (wildmatch)
2504 tret = tret.substWildTo(wildmatch);
2505 int offset;
2506 if (!tret.implicitConvTo(tthis) && !(MODimplicitConv(tret.mod, tthis.mod) && tret.isBaseOf(tthis, &offset) && offset == 0))
2507 {
2508 const(char)* s1 = tret.isNaked() ? " mutable" : tret.modToChars();
2509 const(char)* s2 = tthis.isNaked() ? " mutable" : tthis.modToChars();
2510 .error(loc, "`inout` constructor `%s` creates%s object, not%s", fd.toPrettyChars(), s1, s2);
2511 err = true;
2512 }
2513 }
2514 tret = tthis;
2515 }
2516 else if (wildmatch && tret)
2517 {
2518 /* Adjust function return type based on wildmatch
2519 */
2520 //printf("wildmatch = x%x, tret = %s\n", wildmatch, tret.toChars());
2521 tret = tret.substWildTo(wildmatch);
2522 }
2523
2524 *prettype = tret;
2525 *peprefix = eprefix;
2526 return (err || olderrors != global.errors);
2527}
2528
2529/**
2530 * Determines whether a symbol represents a module or package
2531 * (Used as a helper for is(type == module) and is(type == package))
2532 *
2533 * Params:
2534 * sym = the symbol to be checked
2535 *
2536 * Returns:
2537 * the symbol which `sym` represents (or `null` if it doesn't represent a `Package`)
2538 */
2539Package resolveIsPackage(Dsymbol sym)
2540{
2541 Package pkg;
2542 if (Import imp = sym.isImport())
2543 {
2544 if (imp.pkg is null)
2545 {
5eb9927a 2546 .error(sym.loc, "internal compiler error: unable to process forward-referenced import `%s`",
5fee5ec3
IB
2547 imp.toChars());
2548 assert(0);
2549 }
2550 pkg = imp.pkg;
2551 }
2552 else if (auto mod = sym.isModule())
2553 pkg = mod.isPackageFile ? mod.pkg : sym.isPackage();
2554 else
2555 pkg = sym.isPackage();
2556 if (pkg)
2557 pkg.resolvePKGunknown();
2558 return pkg;
2559}
2560
5fee5ec3
IB
2561
2562private extern (C++) final class ExpressionSemanticVisitor : Visitor
2563{
2564 alias visit = Visitor.visit;
2565
2566 Scope* sc;
2567 Expression result;
2568
8da8c7d3 2569 this(Scope* sc) scope
5fee5ec3
IB
2570 {
2571 this.sc = sc;
2572 }
2573
2574 private void setError()
2575 {
2576 result = ErrorExp.get();
2577 }
2578
2579 /**************************
2580 * Semantically analyze Expression.
2581 * Determine types, fold constants, etc.
2582 */
2583 override void visit(Expression e)
2584 {
2585 static if (LOGSEMANTIC)
2586 {
2587 printf("Expression::semantic() %s\n", e.toChars());
2588 }
2589 if (e.type)
2590 e.type = e.type.typeSemantic(e.loc, sc);
2591 else
2592 e.type = Type.tvoid;
2593 result = e;
2594 }
2595
2596 override void visit(IntegerExp e)
2597 {
2598 assert(e.type);
2599 if (e.type.ty == Terror)
2600 return setError();
2601
2602 assert(e.type.deco);
2603 e.setInteger(e.getInteger());
2604 result = e;
2605 }
2606
2607 override void visit(RealExp e)
2608 {
2609 if (!e.type)
2610 e.type = Type.tfloat64;
2611 else
2612 e.type = e.type.typeSemantic(e.loc, sc);
2613 result = e;
2614 }
2615
2616 override void visit(ComplexExp e)
2617 {
2618 if (!e.type)
2619 e.type = Type.tcomplex80;
2620 else
2621 e.type = e.type.typeSemantic(e.loc, sc);
2622 result = e;
2623 }
2624
2625 override void visit(IdentifierExp exp)
2626 {
2627 static if (LOGSEMANTIC)
2628 {
2629 printf("IdentifierExp::semantic('%s')\n", exp.ident.toChars());
2630 }
2631 if (exp.type) // This is used as the dummy expression
2632 {
2633 result = exp;
2634 return;
2635 }
2636
2637 Dsymbol scopesym;
2638 Dsymbol s = sc.search(exp.loc, exp.ident, &scopesym);
2639 if (s)
2640 {
2641 if (s.errors)
2642 return setError();
2643
2644 Expression e;
2645
2646 /* See if the symbol was a member of an enclosing 'with'
2647 */
2648 WithScopeSymbol withsym = scopesym.isWithScopeSymbol();
2649 if (withsym && withsym.withstate.wthis && symbolIsVisible(sc, s))
2650 {
2651 /* Disallow shadowing
2652 */
2653 // First find the scope of the with
2654 Scope* scwith = sc;
2655 while (scwith.scopesym != scopesym)
2656 {
2657 scwith = scwith.enclosing;
2658 assert(scwith);
2659 }
2660 // Look at enclosing scopes for symbols with the same name,
2661 // in the same function
2662 for (Scope* scx = scwith; scx && scx.func == scwith.func; scx = scx.enclosing)
2663 {
2664 Dsymbol s2;
2665 if (scx.scopesym && scx.scopesym.symtab && (s2 = scx.scopesym.symtab.lookup(s.ident)) !is null && s != s2)
2666 {
2667 exp.error("with symbol `%s` is shadowing local symbol `%s`", s.toPrettyChars(), s2.toPrettyChars());
2668 return setError();
2669 }
2670 }
2671 s = s.toAlias();
2672
2673 // Same as wthis.ident
2674 // TODO: DotIdExp.semantic will find 'ident' from 'wthis' again.
2675 // The redudancy should be removed.
2676 e = new VarExp(exp.loc, withsym.withstate.wthis);
2677 e = new DotIdExp(exp.loc, e, exp.ident);
2678 e = e.expressionSemantic(sc);
2679 }
2680 else
2681 {
2682 if (withsym)
2683 {
2684 if (withsym.withstate.exp.type.ty != Tvoid)
2685 {
2686 // 'with (exp)' is a type expression
2687 // or 's' is not visible there (for error message)
2688 e = new TypeExp(exp.loc, withsym.withstate.exp.type);
2689 }
2690 else
2691 {
2692 // 'with (exp)' is a Package/Module
2693 e = withsym.withstate.exp;
2694 }
2695 e = new DotIdExp(exp.loc, e, exp.ident);
2696 result = e.expressionSemantic(sc);
2697 return;
2698 }
2699
2700 /* If f is really a function template,
2701 * then replace f with the function template declaration.
2702 */
2703 FuncDeclaration f = s.isFuncDeclaration();
2704 if (f)
2705 {
2706 TemplateDeclaration td = getFuncTemplateDecl(f);
2707 if (td)
2708 {
2709 if (td.overroot) // if not start of overloaded list of TemplateDeclaration's
2710 td = td.overroot; // then get the start
2711 e = new TemplateExp(exp.loc, td, f);
2712 e = e.expressionSemantic(sc);
2713 result = e;
2714 return;
2715 }
2716 }
2717
2718 if (global.params.fixAliasThis)
2719 {
2720 ExpressionDsymbol expDsym = scopesym.isExpressionDsymbol();
2721 if (expDsym)
2722 {
2723 //printf("expDsym = %s\n", expDsym.exp.toChars());
2724 result = expDsym.exp.expressionSemantic(sc);
2725 return;
2726 }
2727 }
2728 // Haven't done overload resolution yet, so pass 1
2729 e = symbolToExp(s, exp.loc, sc, true);
2730 }
2731 result = e;
2732 return;
2733 }
2734
2735 if (!global.params.fixAliasThis && hasThis(sc))
2736 {
2737 for (AggregateDeclaration ad = sc.getStructClassScope(); ad;)
2738 {
2739 if (ad.aliasthis)
2740 {
2741 Expression e;
2742 e = new ThisExp(exp.loc);
2743 e = new DotIdExp(exp.loc, e, ad.aliasthis.ident);
2744 e = new DotIdExp(exp.loc, e, exp.ident);
2745 e = e.trySemantic(sc);
2746 if (e)
2747 {
2748 result = e;
2749 return;
2750 }
2751 }
2752
2753 auto cd = ad.isClassDeclaration();
2754 if (cd && cd.baseClass && cd.baseClass != ClassDeclaration.object)
2755 {
2756 ad = cd.baseClass;
2757 continue;
2758 }
2759 break;
2760 }
2761 }
2762
2763 if (exp.ident == Id.ctfe)
2764 {
2765 if (sc.flags & SCOPE.ctfe)
2766 {
2767 exp.error("variable `__ctfe` cannot be read at compile time");
2768 return setError();
2769 }
2770
2771 // Create the magic __ctfe bool variable
2772 auto vd = new VarDeclaration(exp.loc, Type.tbool, Id.ctfe, null);
2773 vd.storage_class |= STC.temp;
2774 vd.semanticRun = PASS.semanticdone;
2775 Expression e = new VarExp(exp.loc, vd);
2776 e = e.expressionSemantic(sc);
2777 result = e;
2778 return;
2779 }
2780
2781 // If we've reached this point and are inside a with() scope then we may
2782 // try one last attempt by checking whether the 'wthis' object supports
2783 // dynamic dispatching via opDispatch.
2784 // This is done by rewriting this expression as wthis.ident.
2785 // The innermost with() scope of the hierarchy to satisfy the condition
2786 // above wins.
2787 // https://issues.dlang.org/show_bug.cgi?id=6400
2788 for (Scope* sc2 = sc; sc2; sc2 = sc2.enclosing)
2789 {
2790 if (!sc2.scopesym)
2791 continue;
2792
2793 if (auto ss = sc2.scopesym.isWithScopeSymbol())
2794 {
2795 if (ss.withstate.wthis)
2796 {
2797 Expression e;
2798 e = new VarExp(exp.loc, ss.withstate.wthis);
2799 e = new DotIdExp(exp.loc, e, exp.ident);
2800 e = e.trySemantic(sc);
2801 if (e)
2802 {
2803 result = e;
2804 return;
2805 }
2806 }
2807 // Try Type.opDispatch (so the static version)
9c7d5e88 2808 else if (ss.withstate.exp && ss.withstate.exp.op == EXP.type)
5fee5ec3
IB
2809 {
2810 if (Type t = ss.withstate.exp.isTypeExp().type)
2811 {
2812 Expression e;
2813 e = new TypeExp(exp.loc, t);
2814 e = new DotIdExp(exp.loc, e, exp.ident);
2815 e = e.trySemantic(sc);
2816 if (e)
2817 {
2818 result = e;
2819 return;
2820 }
2821 }
2822 }
2823 }
2824 }
2825
2826 /* Look for what user might have meant
2827 */
2828 if (const n = importHint(exp.ident.toString()))
2829 exp.error("`%s` is not defined, perhaps `import %.*s;` is needed?", exp.ident.toChars(), cast(int)n.length, n.ptr);
2830 else if (auto s2 = sc.search_correct(exp.ident))
2831 exp.error("undefined identifier `%s`, did you mean %s `%s`?", exp.ident.toChars(), s2.kind(), s2.toChars());
2832 else if (const p = Scope.search_correct_C(exp.ident))
2833 exp.error("undefined identifier `%s`, did you mean `%s`?", exp.ident.toChars(), p);
fd43568c
IB
2834 else if (exp.ident == Id.dollar)
2835 exp.error("undefined identifier `$`");
5fee5ec3
IB
2836 else
2837 exp.error("undefined identifier `%s`", exp.ident.toChars());
2838
2839 result = ErrorExp.get();
2840 }
2841
2842 override void visit(DsymbolExp e)
2843 {
2844 result = symbolToExp(e.s, e.loc, sc, e.hasOverloads);
2845 }
2846
2847 override void visit(ThisExp e)
2848 {
2849 static if (LOGSEMANTIC)
2850 {
2851 printf("ThisExp::semantic()\n");
2852 }
2853 if (e.type)
2854 {
2855 result = e;
2856 return;
2857 }
2858
2859 FuncDeclaration fd = hasThis(sc); // fd is the uplevel function with the 'this' variable
2860 AggregateDeclaration ad;
2861
2862 /* Special case for typeof(this) and typeof(super) since both
2863 * should work even if they are not inside a non-static member function
2864 */
2865 if (!fd && sc.intypeof == 1)
2866 {
2867 // Find enclosing struct or class
2868 for (Dsymbol s = sc.getStructClassScope(); 1; s = s.parent)
2869 {
2870 if (!s)
2871 {
2872 e.error("`%s` is not in a class or struct scope", e.toChars());
2873 goto Lerr;
2874 }
2875 ClassDeclaration cd = s.isClassDeclaration();
2876 if (cd)
2877 {
2878 e.type = cd.type;
2879 result = e;
2880 return;
2881 }
2882 StructDeclaration sd = s.isStructDeclaration();
2883 if (sd)
2884 {
2885 e.type = sd.type;
2886 result = e;
2887 return;
2888 }
2889 }
2890 }
2891 if (!fd)
2892 goto Lerr;
2893
2894 assert(fd.vthis);
2895 e.var = fd.vthis;
2896 assert(e.var.parent);
2897 ad = fd.isMemberLocal();
2898 if (!ad)
2899 ad = fd.isMember2();
2900 assert(ad);
2901 e.type = ad.type.addMod(e.var.type.mod);
2902
2903 if (e.var.checkNestedReference(sc, e.loc))
2904 return setError();
2905
2906 result = e;
2907 return;
2908
2909 Lerr:
2910 e.error("`this` is only defined in non-static member functions, not `%s`", sc.parent.toChars());
2911 result = ErrorExp.get();
2912 }
2913
2914 override void visit(SuperExp e)
2915 {
2916 static if (LOGSEMANTIC)
2917 {
2918 printf("SuperExp::semantic('%s')\n", e.toChars());
2919 }
2920 if (e.type)
2921 {
2922 result = e;
2923 return;
2924 }
2925
2926 FuncDeclaration fd = hasThis(sc);
2927 ClassDeclaration cd;
2928 Dsymbol s;
2929
2930 /* Special case for typeof(this) and typeof(super) since both
2931 * should work even if they are not inside a non-static member function
2932 */
2933 if (!fd && sc.intypeof == 1)
2934 {
2935 // Find enclosing class
2936 for (s = sc.getStructClassScope(); 1; s = s.parent)
2937 {
2938 if (!s)
2939 {
2940 e.error("`%s` is not in a class scope", e.toChars());
2941 goto Lerr;
2942 }
2943 cd = s.isClassDeclaration();
2944 if (cd)
2945 {
2946 cd = cd.baseClass;
2947 if (!cd)
2948 {
2949 e.error("class `%s` has no `super`", s.toChars());
2950 goto Lerr;
2951 }
2952 e.type = cd.type;
2953 result = e;
2954 return;
2955 }
2956 }
2957 }
2958 if (!fd)
2959 goto Lerr;
2960
2961 e.var = fd.vthis;
2962 assert(e.var && e.var.parent);
2963
2964 s = fd.toParentDecl();
2965 if (s.isTemplateDeclaration()) // allow inside template constraint
2966 s = s.toParent();
2967 assert(s);
2968 cd = s.isClassDeclaration();
2969 //printf("parent is %s %s\n", fd.toParent().kind(), fd.toParent().toChars());
2970 if (!cd)
2971 goto Lerr;
2972 if (!cd.baseClass)
2973 {
2974 e.error("no base class for `%s`", cd.toChars());
2975 e.type = cd.type.addMod(e.var.type.mod);
2976 }
2977 else
2978 {
2979 e.type = cd.baseClass.type;
2980 e.type = e.type.castMod(e.var.type.mod);
2981 }
2982
2983 if (e.var.checkNestedReference(sc, e.loc))
2984 return setError();
2985
2986 result = e;
2987 return;
2988
2989 Lerr:
2990 e.error("`super` is only allowed in non-static class member functions");
2991 result = ErrorExp.get();
2992 }
2993
2994 override void visit(NullExp e)
2995 {
2996 static if (LOGSEMANTIC)
2997 {
2998 printf("NullExp::semantic('%s')\n", e.toChars());
2999 }
3000 // NULL is the same as (void *)0
3001 if (e.type)
3002 {
3003 result = e;
3004 return;
3005 }
3006 e.type = Type.tnull;
3007 result = e;
3008 }
3009
3010 override void visit(StringExp e)
3011 {
3012 static if (LOGSEMANTIC)
3013 {
3014 printf("StringExp::semantic() %s\n", e.toChars());
3015 }
3016 if (e.type)
3017 {
3018 result = e;
3019 return;
3020 }
3021
3022 OutBuffer buffer;
3023 size_t newlen = 0;
3024 size_t u;
3025 dchar c;
3026
3027 switch (e.postfix)
3028 {
3029 case 'd':
3030 for (u = 0; u < e.len;)
3031 {
3032 if (const p = utf_decodeChar(e.peekString(), u, c))
3033 {
3034 e.error("%.*s", cast(int)p.length, p.ptr);
3035 return setError();
3036 }
3037 else
3038 {
3039 buffer.write4(c);
3040 newlen++;
3041 }
3042 }
3043 buffer.write4(0);
3044 e.setData(buffer.extractData(), newlen, 4);
3045 if (sc && sc.flags & SCOPE.Cfile)
5eb9927a 3046 e.type = Type.tuns32.sarrayOf(e.len + 1);
5fee5ec3
IB
3047 else
3048 e.type = Type.tdchar.immutableOf().arrayOf();
3049 e.committed = 1;
3050 break;
3051
3052 case 'w':
3053 for (u = 0; u < e.len;)
3054 {
3055 if (const p = utf_decodeChar(e.peekString(), u, c))
3056 {
3057 e.error("%.*s", cast(int)p.length, p.ptr);
3058 return setError();
3059 }
3060 else
3061 {
3062 buffer.writeUTF16(c);
3063 newlen++;
3064 if (c >= 0x10000)
3065 newlen++;
3066 }
3067 }
3068 buffer.writeUTF16(0);
3069 e.setData(buffer.extractData(), newlen, 2);
3070 if (sc && sc.flags & SCOPE.Cfile)
5eb9927a 3071 e.type = Type.tuns16.sarrayOf(e.len + 1);
5fee5ec3
IB
3072 else
3073 e.type = Type.twchar.immutableOf().arrayOf();
3074 e.committed = 1;
3075 break;
3076
3077 case 'c':
3078 e.committed = 1;
3079 goto default;
3080
3081 default:
3082 if (sc && sc.flags & SCOPE.Cfile)
5eb9927a 3083 e.type = Type.tchar.sarrayOf(e.len + 1);
5fee5ec3
IB
3084 else
3085 e.type = Type.tchar.immutableOf().arrayOf();
3086 break;
3087 }
3088 e.type = e.type.typeSemantic(e.loc, sc);
3089 //type = type.immutableOf();
3090 //printf("type = %s\n", type.toChars());
3091
3092 result = e;
3093 }
3094
3095 override void visit(TupleExp exp)
3096 {
3097 static if (LOGSEMANTIC)
3098 {
3099 printf("+TupleExp::semantic(%s)\n", exp.toChars());
3100 }
3101 if (exp.type)
3102 {
3103 result = exp;
3104 return;
3105 }
3106
3107 if (exp.e0)
3108 exp.e0 = exp.e0.expressionSemantic(sc);
3109
3110 // Run semantic() on each argument
3111 bool err = false;
6d799f0a 3112 for (size_t i = 0; i < exp.exps.length; i++)
5fee5ec3
IB
3113 {
3114 Expression e = (*exp.exps)[i];
3115 e = e.expressionSemantic(sc);
3116 if (!e.type)
3117 {
3118 exp.error("`%s` has no value", e.toChars());
3119 err = true;
3120 }
9c7d5e88 3121 else if (e.op == EXP.error)
5fee5ec3
IB
3122 err = true;
3123 else
3124 (*exp.exps)[i] = e;
3125 }
3126 if (err)
3127 return setError();
3128
3129 expandTuples(exp.exps);
3130
3131 exp.type = new TypeTuple(exp.exps);
3132 exp.type = exp.type.typeSemantic(exp.loc, sc);
3133 //printf("-TupleExp::semantic(%s)\n", toChars());
3134 result = exp;
3135 }
3136
3137 override void visit(ArrayLiteralExp e)
3138 {
3139 static if (LOGSEMANTIC)
3140 {
3141 printf("ArrayLiteralExp::semantic('%s')\n", e.toChars());
3142 }
3143 if (e.type)
3144 {
3145 result = e;
3146 return;
3147 }
3148
3149 /* Perhaps an empty array literal [ ] should be rewritten as null?
3150 */
3151
3152 if (e.basis)
3153 e.basis = e.basis.expressionSemantic(sc);
c8dfa79c 3154 if (arrayExpressionSemantic(e.elements.peekSlice(), sc) || (e.basis && e.basis.op == EXP.error))
5fee5ec3
IB
3155 return setError();
3156
3157 expandTuples(e.elements);
3158
3159 if (e.basis)
3160 e.elements.push(e.basis);
3161 Type t0 = arrayExpressionToCommonType(sc, *e.elements);
3162 if (e.basis)
3163 e.basis = e.elements.pop();
3164 if (t0 is null)
3165 return setError();
3166
3167 e.type = t0.arrayOf();
3168 e.type = e.type.typeSemantic(e.loc, sc);
3169
3170 /* Disallow array literals of type void being used.
3171 */
6d799f0a 3172 if (e.elements.length > 0 && t0.ty == Tvoid)
5fee5ec3
IB
3173 {
3174 e.error("`%s` of type `%s` has no value", e.toChars(), e.type.toChars());
3175 return setError();
3176 }
3177
3178 if (global.params.useTypeInfo && Type.dtypeinfo)
3179 semanticTypeInfo(sc, e.type);
3180
3181 result = e;
3182 }
3183
3184 override void visit(AssocArrayLiteralExp e)
3185 {
3186 static if (LOGSEMANTIC)
3187 {
3188 printf("AssocArrayLiteralExp::semantic('%s')\n", e.toChars());
3189 }
3190 if (e.type)
3191 {
3192 result = e;
3193 return;
3194 }
3195
3196 // Run semantic() on each element
c8dfa79c
IB
3197 bool err_keys = arrayExpressionSemantic(e.keys.peekSlice(), sc);
3198 bool err_vals = arrayExpressionSemantic(e.values.peekSlice(), sc);
5fee5ec3
IB
3199 if (err_keys || err_vals)
3200 return setError();
3201
3202 expandTuples(e.keys);
3203 expandTuples(e.values);
6d799f0a 3204 if (e.keys.length != e.values.length)
5fee5ec3
IB
3205 {
3206 e.error("number of keys is %llu, must match number of values %llu",
6d799f0a 3207 cast(ulong) e.keys.length, cast(ulong) e.values.length);
5fee5ec3
IB
3208 return setError();
3209 }
3210
3211 Type tkey = arrayExpressionToCommonType(sc, *e.keys);
3212 Type tvalue = arrayExpressionToCommonType(sc, *e.values);
3213 if (tkey is null || tvalue is null)
3214 return setError();
3215
3216 e.type = new TypeAArray(tvalue, tkey);
3217 e.type = e.type.typeSemantic(e.loc, sc);
3218
3219 semanticTypeInfo(sc, e.type);
3220
5eb9927a
IB
3221 if (checkAssocArrayLiteralEscape(sc, e, false))
3222 return setError();
5fee5ec3
IB
3223
3224 result = e;
3225 }
3226
3227 override void visit(StructLiteralExp e)
3228 {
3229 static if (LOGSEMANTIC)
3230 {
3231 printf("StructLiteralExp::semantic('%s')\n", e.toChars());
3232 }
3233 if (e.type)
3234 {
3235 result = e;
3236 return;
3237 }
3238
3239 e.sd.size(e.loc);
3240 if (e.sd.sizeok != Sizeok.done)
3241 return setError();
3242
3243 // run semantic() on each element
c8dfa79c 3244 if (arrayExpressionSemantic(e.elements.peekSlice(), sc))
5fee5ec3
IB
3245 return setError();
3246
3247 expandTuples(e.elements);
3248
3249 /* Fit elements[] to the corresponding type of field[].
3250 */
3251 if (!e.sd.fit(e.loc, sc, e.elements, e.stype))
3252 return setError();
3253
3254 /* Fill out remainder of elements[] with default initializers for fields[]
3255 */
c8dfa79c 3256 if (!e.sd.fill(e.loc, *e.elements, false))
5fee5ec3
IB
3257 {
3258 /* An error in the initializer needs to be recorded as an error
3259 * in the enclosing function or template, since the initializer
3260 * will be part of the stuct declaration.
3261 */
3262 global.increaseErrorCount();
3263 return setError();
3264 }
3265
6d799f0a 3266 if (checkFrameAccess(e.loc, sc, e.sd, e.elements.length))
5fee5ec3
IB
3267 return setError();
3268
3269 e.type = e.stype ? e.stype : e.sd.type;
3270 result = e;
3271 }
3272
3273 override void visit(CompoundLiteralExp cle)
3274 {
3275 static if (LOGSEMANTIC)
3276 {
3277 printf("CompoundLiteralExp::semantic('%s')\n", cle.toChars());
3278 }
3279 Type t = cle.type.typeSemantic(cle.loc, sc);
3280 auto init = initializerSemantic(cle.initializer, sc, t, INITnointerpret);
ae56e2da 3281 auto e = initializerToExpression(init, t, (sc.flags & SCOPE.Cfile) != 0);
5fee5ec3
IB
3282 if (!e)
3283 {
3284 error(cle.loc, "cannot convert initializer `%s` to expression", init.toChars());
3285 return setError();
3286 }
3287 result = e;
3288 return;
3289 }
3290
3291 override void visit(TypeExp exp)
3292 {
3293 if (exp.type.ty == Terror)
3294 return setError();
3295
3296 //printf("TypeExp::semantic(%s)\n", exp.type.toChars());
3297 Expression e;
3298 Type t;
3299 Dsymbol s;
3300
3301 dmd.typesem.resolve(exp.type, exp.loc, sc, e, t, s, true);
3302 if (e)
3303 {
3304 // `(Type)` is actually `(var)` so if `(var)` is a member requiring `this`
3305 // then rewrite as `(this.var)` in case it would be followed by a DotVar
3306 // to fix https://issues.dlang.org/show_bug.cgi?id=9490
3307 VarExp ve = e.isVarExp();
3308 if (ve && ve.var && exp.parens && !ve.var.isStatic() && !(sc.stc & STC.static_) &&
5eb9927a 3309 sc.func && sc.func.needThis && ve.var.isMember2())
5fee5ec3
IB
3310 {
3311 // printf("apply fix for issue 9490: add `this.` to `%s`...\n", e.toChars());
3312 e = new DotVarExp(exp.loc, new ThisExp(exp.loc), ve.var, false);
3313 }
31350635 3314 //printf("e = %s %s\n", Token.toChars(e.op), e.toChars());
5fee5ec3
IB
3315 e = e.expressionSemantic(sc);
3316 }
3317 else if (t)
3318 {
3319 //printf("t = %d %s\n", t.ty, t.toChars());
3320 exp.type = t.typeSemantic(exp.loc, sc);
3321 e = exp;
3322 }
3323 else if (s)
3324 {
3325 //printf("s = %s %s\n", s.kind(), s.toChars());
3326 e = symbolToExp(s, exp.loc, sc, true);
3327 }
3328 else
3329 assert(0);
3330
1027dc45 3331 exp.type.checkComplexTransition(exp.loc, sc);
5fee5ec3
IB
3332
3333 result = e;
3334 }
3335
3336 override void visit(ScopeExp exp)
3337 {
3338 static if (LOGSEMANTIC)
3339 {
3340 printf("+ScopeExp::semantic(%p '%s')\n", exp, exp.toChars());
3341 }
3342 if (exp.type)
3343 {
3344 result = exp;
3345 return;
3346 }
3347
3348 ScopeDsymbol sds2 = exp.sds;
3349 TemplateInstance ti = sds2.isTemplateInstance();
3350 while (ti)
3351 {
3352 WithScopeSymbol withsym;
3353 if (!ti.findTempDecl(sc, &withsym) || !ti.semanticTiargs(sc))
3354 return setError();
3355 if (withsym && withsym.withstate.wthis)
3356 {
3357 Expression e = new VarExp(exp.loc, withsym.withstate.wthis);
3358 e = new DotTemplateInstanceExp(exp.loc, e, ti);
3359 result = e.expressionSemantic(sc);
3360 return;
3361 }
3362 if (ti.needsTypeInference(sc))
3363 {
3364 if (TemplateDeclaration td = ti.tempdecl.isTemplateDeclaration())
3365 {
3366 Dsymbol p = td.toParentLocal();
3367 FuncDeclaration fdthis = hasThis(sc);
3368 AggregateDeclaration ad = p ? p.isAggregateDeclaration() : null;
3369 if (fdthis && ad && fdthis.isMemberLocal() == ad && (td._scope.stc & STC.static_) == 0)
3370 {
3371 Expression e = new DotTemplateInstanceExp(exp.loc, new ThisExp(exp.loc), ti);
3372 result = e.expressionSemantic(sc);
3373 return;
3374 }
3375 }
3376 else if (OverloadSet os = ti.tempdecl.isOverloadSet())
3377 {
3378 FuncDeclaration fdthis = hasThis(sc);
3379 AggregateDeclaration ad = os.parent.isAggregateDeclaration();
3380 if (fdthis && ad && fdthis.isMemberLocal() == ad)
3381 {
3382 Expression e = new DotTemplateInstanceExp(exp.loc, new ThisExp(exp.loc), ti);
3383 result = e.expressionSemantic(sc);
3384 return;
3385 }
3386 }
3387 // ti is an instance which requires IFTI.
3388 exp.sds = ti;
3389 exp.type = Type.tvoid;
3390 result = exp;
3391 return;
3392 }
3393 ti.dsymbolSemantic(sc);
3394 if (!ti.inst || ti.errors)
3395 return setError();
3396
3397 Dsymbol s = ti.toAlias();
3398 if (s == ti)
3399 {
3400 exp.sds = ti;
3401 exp.type = Type.tvoid;
3402 result = exp;
3403 return;
3404 }
3405 sds2 = s.isScopeDsymbol();
3406 if (sds2)
3407 {
3408 ti = sds2.isTemplateInstance();
3409 //printf("+ sds2 = %s, '%s'\n", sds2.kind(), sds2.toChars());
3410 continue;
3411 }
3412
3413 if (auto v = s.isVarDeclaration())
3414 {
3415 if (!v.type)
3416 {
3417 exp.error("forward reference of %s `%s`", v.kind(), v.toChars());
3418 return setError();
3419 }
3420 if ((v.storage_class & STC.manifest) && v._init)
3421 {
3422 /* When an instance that will be converted to a constant exists,
3423 * the instance representation "foo!tiargs" is treated like a
3424 * variable name, and its recursive appearance check (note that
3425 * it's equivalent with a recursive instantiation of foo) is done
3426 * separately from the circular initialization check for the
3427 * eponymous enum variable declaration.
3428 *
3429 * template foo(T) {
3430 * enum bool foo = foo; // recursive definition check (v.inuse)
3431 * }
3432 * template bar(T) {
3433 * enum bool bar = bar!T; // recursive instantiation check (ti.inuse)
3434 * }
3435 */
3436 if (ti.inuse)
3437 {
3438 exp.error("recursive expansion of %s `%s`", ti.kind(), ti.toPrettyChars());
3439 return setError();
3440 }
3441 v.checkDeprecated(exp.loc, sc);
3442 auto e = v.expandInitializer(exp.loc);
3443 ti.inuse++;
3444 e = e.expressionSemantic(sc);
3445 ti.inuse--;
3446 result = e;
3447 return;
3448 }
3449 }
3450
3451 //printf("s = %s, '%s'\n", s.kind(), s.toChars());
3452 auto e = symbolToExp(s, exp.loc, sc, true);
3453 //printf("-1ScopeExp::semantic()\n");
3454 result = e;
3455 return;
3456 }
3457
3458 //printf("sds2 = %s, '%s'\n", sds2.kind(), sds2.toChars());
3459 //printf("\tparent = '%s'\n", sds2.parent.toChars());
3460 sds2.dsymbolSemantic(sc);
3461
3462 // (Aggregate|Enum)Declaration
3463 if (auto t = sds2.getType())
3464 {
3465 result = (new TypeExp(exp.loc, t)).expressionSemantic(sc);
3466 return;
3467 }
3468
3469 if (auto td = sds2.isTemplateDeclaration())
3470 {
3471 result = (new TemplateExp(exp.loc, td)).expressionSemantic(sc);
3472 return;
3473 }
3474
3475 exp.sds = sds2;
3476 exp.type = Type.tvoid;
3477 //printf("-2ScopeExp::semantic() %s\n", toChars());
3478 result = exp;
3479 }
3480
3481 override void visit(NewExp exp)
3482 {
3483 static if (LOGSEMANTIC)
3484 {
3485 printf("NewExp::semantic() %s\n", exp.toChars());
3486 if (exp.thisexp)
3487 printf("\tthisexp = %s\n", exp.thisexp.toChars());
3488 printf("\tnewtype: %s\n", exp.newtype.toChars());
3489 }
3490 if (exp.type) // if semantic() already run
3491 {
3492 result = exp;
3493 return;
3494 }
3495
3496 //for error messages if the argument in [] is not convertible to size_t
3497 const originalNewtype = exp.newtype;
3498
3499 // https://issues.dlang.org/show_bug.cgi?id=11581
3500 // With the syntax `new T[edim]` or `thisexp.new T[edim]`,
3501 // T should be analyzed first and edim should go into arguments iff it's
3502 // not a tuple.
3503 Expression edim = null;
6384eff5 3504 if (!exp.arguments && exp.newtype.isTypeSArray())
5fee5ec3 3505 {
6384eff5 3506 auto ts = exp.newtype.isTypeSArray();
b6df1132
IB
3507 // check `new Value[Key]`
3508 ts.dim = ts.dim.expressionSemantic(sc);
3509 if (ts.dim.op == EXP.type)
3510 {
3511 exp.newtype = new TypeAArray(ts.next, ts.dim.isTypeExp().type);
3512 }
3513 else
3514 {
3515 edim = ts.dim;
3516 exp.newtype = ts.next;
3517 }
5fee5ec3
IB
3518 }
3519
3520 ClassDeclaration cdthis = null;
3521 if (exp.thisexp)
3522 {
3523 exp.thisexp = exp.thisexp.expressionSemantic(sc);
9c7d5e88 3524 if (exp.thisexp.op == EXP.error)
5fee5ec3
IB
3525 return setError();
3526
3527 cdthis = exp.thisexp.type.isClassHandle();
3528 if (!cdthis)
3529 {
3530 exp.error("`this` for nested class must be a class type, not `%s`", exp.thisexp.type.toChars());
3531 return setError();
3532 }
3533
3534 sc = sc.push(cdthis);
3535 exp.type = exp.newtype.typeSemantic(exp.loc, sc);
3536 sc = sc.pop();
3537 }
3538 else
3539 {
3540 exp.type = exp.newtype.typeSemantic(exp.loc, sc);
3541 }
3542 if (exp.type.ty == Terror)
3543 return setError();
3544
3545 if (edim)
3546 {
3547 if (exp.type.toBasetype().ty == Ttuple)
3548 {
3549 // --> new T[edim]
3550 exp.type = new TypeSArray(exp.type, edim);
3551 exp.type = exp.type.typeSemantic(exp.loc, sc);
3552 if (exp.type.ty == Terror)
3553 return setError();
3554 }
3555 else
3556 {
3557 // --> new T[](edim)
3558 exp.arguments = new Expressions();
3559 exp.arguments.push(edim);
3560 exp.type = exp.type.arrayOf();
3561 }
3562 }
3563
3564 exp.newtype = exp.type; // in case type gets cast to something else
3565 Type tb = exp.type.toBasetype();
3566 //printf("tb: %s, deco = %s\n", tb.toChars(), tb.deco);
c8dfa79c 3567 if (arrayExpressionSemantic(exp.arguments.peekSlice(), sc))
5fee5ec3
IB
3568 {
3569 return setError();
3570 }
8da8c7d3 3571 if (preFunctionParameters(sc, exp.argumentList))
5fee5ec3
IB
3572 {
3573 return setError();
3574 }
3575
3576 if (exp.thisexp && tb.ty != Tclass)
3577 {
3578 exp.error("`.new` is only for allocating nested classes, not `%s`", tb.toChars());
3579 return setError();
3580 }
3581
6d799f0a 3582 const size_t nargs = exp.arguments ? exp.arguments.length : 0;
5fee5ec3
IB
3583 Expression newprefix = null;
3584
6384eff5 3585 if (auto tc = tb.isTypeClass())
5fee5ec3 3586 {
6384eff5 3587 auto cd = tc.sym;
f99303eb
IB
3588 if (cd.errors)
3589 return setError();
5fee5ec3
IB
3590 cd.size(exp.loc);
3591 if (cd.sizeok != Sizeok.done)
3592 return setError();
3593 if (!cd.ctor)
3594 cd.ctor = cd.searchCtor();
3595 if (cd.noDefaultCtor && !nargs && !cd.defaultCtor)
3596 {
3597 exp.error("default construction is disabled for type `%s`", cd.type.toChars());
3598 return setError();
3599 }
3600
3601 if (cd.isInterfaceDeclaration())
3602 {
3603 exp.error("cannot create instance of interface `%s`", cd.toChars());
3604 return setError();
3605 }
3606
3607 if (cd.isAbstract())
3608 {
3609 exp.error("cannot create instance of abstract class `%s`", cd.toChars());
6d799f0a 3610 for (size_t i = 0; i < cd.vtbl.length; i++)
5fee5ec3
IB
3611 {
3612 FuncDeclaration fd = cd.vtbl[i].isFuncDeclaration();
3613 if (fd && fd.isAbstract())
3614 {
3615 errorSupplemental(exp.loc, "function `%s` is not implemented",
3616 fd.toFullSignature());
3617 }
3618 }
3619 return setError();
3620 }
3621 // checkDeprecated() is already done in newtype.typeSemantic().
3622
3623 if (cd.isNested())
3624 {
3625 /* We need a 'this' pointer for the nested class.
3626 * Ensure we have the right one.
3627 */
3628 Dsymbol s = cd.toParentLocal();
3629
3630 //printf("cd isNested, parent = %s '%s'\n", s.kind(), s.toPrettyChars());
3631 if (auto cdn = s.isClassDeclaration())
3632 {
3633 if (!cdthis)
3634 {
f99303eb 3635 void noReferenceToOuterClass()
d7569187 3636 {
f99303eb
IB
3637 if (cd.isAnonymous)
3638 exp.error("cannot construct anonymous nested class because no implicit `this` reference to outer class is available");
3639 else
3640 exp.error("cannot construct nested class `%s` because no implicit `this` reference to outer class `%s` is available",
3641 cd.toChars(), cdn.toChars());
d7569187
IB
3642 return setError();
3643 }
3644
f99303eb
IB
3645 if (!sc.hasThis)
3646 return noReferenceToOuterClass();
3647
5fee5ec3
IB
3648 // Supply an implicit 'this' and try again
3649 exp.thisexp = new ThisExp(exp.loc);
3650 for (Dsymbol sp = sc.parent; 1; sp = sp.toParentLocal())
3651 {
f99303eb
IB
3652 if (!sp)
3653 return noReferenceToOuterClass();
5fee5ec3
IB
3654 ClassDeclaration cdp = sp.isClassDeclaration();
3655 if (!cdp)
3656 continue;
3657 if (cdp == cdn || cdn.isBaseOf(cdp, null))
3658 break;
3659 // Add a '.outer' and try again
3660 exp.thisexp = new DotIdExp(exp.loc, exp.thisexp, Id.outer);
3661 }
3662
3663 exp.thisexp = exp.thisexp.expressionSemantic(sc);
9c7d5e88 3664 if (exp.thisexp.op == EXP.error)
5fee5ec3
IB
3665 return setError();
3666 cdthis = exp.thisexp.type.isClassHandle();
3667 }
3668 if (cdthis != cdn && !cdn.isBaseOf(cdthis, null))
3669 {
3670 //printf("cdthis = %s\n", cdthis.toChars());
3671 exp.error("`this` for nested class must be of type `%s`, not `%s`",
3672 cdn.toChars(), exp.thisexp.type.toChars());
3673 return setError();
3674 }
3675 if (!MODimplicitConv(exp.thisexp.type.mod, exp.newtype.mod))
3676 {
3677 exp.error("nested type `%s` should have the same or weaker constancy as enclosing type `%s`",
3678 exp.newtype.toChars(), exp.thisexp.type.toChars());
3679 return setError();
3680 }
3681 }
3682 else if (exp.thisexp)
3683 {
3684 exp.error("`.new` is only for allocating nested classes");
3685 return setError();
3686 }
3687 else if (auto fdn = s.isFuncDeclaration())
3688 {
3689 // make sure the parent context fdn of cd is reachable from sc
3690 if (!ensureStaticLinkTo(sc.parent, fdn))
3691 {
3692 exp.error("outer function context of `%s` is needed to `new` nested class `%s`",
3693 fdn.toPrettyChars(), cd.toPrettyChars());
3694 return setError();
3695 }
3696 }
3697 else
3698 assert(0);
3699 }
3700 else if (exp.thisexp)
3701 {
3702 exp.error("`.new` is only for allocating nested classes");
3703 return setError();
3704 }
3705
3706 if (cd.vthis2)
3707 {
3708 if (AggregateDeclaration ad2 = cd.isMember2())
3709 {
3710 Expression te = new ThisExp(exp.loc).expressionSemantic(sc);
9c7d5e88 3711 if (te.op != EXP.error)
5fee5ec3 3712 te = getRightThis(exp.loc, sc, ad2, te, cd);
9c7d5e88 3713 if (te.op == EXP.error)
5fee5ec3
IB
3714 {
3715 exp.error("need `this` of type `%s` needed to `new` nested class `%s`", ad2.toChars(), cd.toChars());
3716 return setError();
3717 }
3718 }
3719 }
3720
c8dfa79c 3721 if (cd.disableNew && !exp.onstack)
5fee5ec3
IB
3722 {
3723 exp.error("cannot allocate `class %s` with `new` because it is annotated with `@disable new()`",
3724 originalNewtype.toChars());
3725 return setError();
3726 }
5fee5ec3
IB
3727
3728 if (cd.ctor)
3729 {
8da8c7d3 3730 FuncDeclaration f = resolveFuncCall(exp.loc, sc, cd.ctor, null, tb, exp.argumentList, FuncResolveFlag.standard);
5fee5ec3
IB
3731 if (!f || f.errors)
3732 return setError();
3733
3734 checkFunctionAttributes(exp, sc, f);
3735 checkAccess(cd, exp.loc, sc, f);
3736
6384eff5 3737 TypeFunction tf = f.type.isTypeFunction();
5fee5ec3
IB
3738 if (!exp.arguments)
3739 exp.arguments = new Expressions();
8da8c7d3 3740 if (functionParameters(exp.loc, sc, tf, null, exp.type, exp.argumentList, f, &exp.type, &exp.argprefix))
5fee5ec3
IB
3741 return setError();
3742
3743 exp.member = f.isCtorDeclaration();
3744 assert(exp.member);
3745 }
3746 else
3747 {
3748 if (nargs)
3749 {
3750 exp.error("no constructor for `%s`", cd.toChars());
3751 return setError();
3752 }
3753
3754 // https://issues.dlang.org/show_bug.cgi?id=19941
3755 // Run semantic on all field initializers to resolve any forward
3756 // references. This is the same as done for structs in sd.fill().
3757 for (ClassDeclaration c = cd; c; c = c.baseClass)
3758 {
3759 foreach (v; c.fields)
3760 {
3761 if (v.inuse || v._scope is null || v._init is null ||
3762 v._init.isVoidInitializer())
3763 continue;
3764 v.inuse++;
3765 v._init = v._init.initializerSemantic(v._scope, v.type, INITinterpret);
3766 v.inuse--;
3767 }
3768 }
3769 }
ec486b73
IB
3770
3771 // When using `@nogc` exception handling, lower `throw new E(args)` to
3772 // `throw (__tmp = _d_newThrowable!E(), __tmp.__ctor(args), __tmp)`.
3773 if (global.params.ehnogc && exp.thrownew &&
3774 !cd.isCOMclass() && !cd.isCPPclass())
3775 {
3776 assert(cd.ctor);
3777
3778 Expression id = new IdentifierExp(exp.loc, Id.empty);
3779 id = new DotIdExp(exp.loc, id, Id.object);
3780
3781 auto tiargs = new Objects();
3782 tiargs.push(exp.newtype);
3783 id = new DotTemplateInstanceExp(exp.loc, id, Id._d_newThrowable, tiargs);
3784 id = new CallExp(exp.loc, id).expressionSemantic(sc);
3785
3786 Expression idVal;
3787 Expression tmp = extractSideEffect(sc, "__tmpThrowable", idVal, id, true);
3788 // auto castTmp = new CastExp(exp.loc, tmp, exp.type);
3789
3790 auto ctor = new DotIdExp(exp.loc, tmp, Id.ctor).expressionSemantic(sc);
3791 auto ctorCall = new CallExp(exp.loc, ctor, exp.arguments);
3792
3793 id = Expression.combine(idVal, exp.argprefix).expressionSemantic(sc);
3794 id = Expression.combine(id, ctorCall).expressionSemantic(sc);
3795 // id = Expression.combine(id, castTmp).expressionSemantic(sc);
3796
3797 result = id.expressionSemantic(sc);
3798 return;
3799 }
8da8c7d3
IB
3800 else if (!exp.onstack && !exp.type.isscope())
3801 {
3802 auto hook = global.params.tracegc ? Id._d_newclassTTrace : Id._d_newclassT;
3803 if (!verifyHookExist(exp.loc, *sc, hook, "new class"))
3804 return setError();
3805
3806 Expression id = new IdentifierExp(exp.loc, Id.empty);
3807 id = new DotIdExp(exp.loc, id, Id.object);
3808
3809 auto tiargs = new Objects();
3810 auto t = exp.newtype.unqualify(MODFlags.wild); // remove `inout`
3811 tiargs.push(t);
3812 id = new DotTemplateInstanceExp(exp.loc, id, hook, tiargs);
3813 auto arguments = new Expressions();
3814 if (global.params.tracegc)
3815 {
3816 auto funcname = (sc.callsc && sc.callsc.func) ?
3817 sc.callsc.func.toPrettyChars() : sc.func.toPrettyChars();
3818 arguments.push(new StringExp(exp.loc, exp.loc.filename.toDString()));
3819 arguments.push(new IntegerExp(exp.loc, exp.loc.linnum, Type.tint32));
3820 arguments.push(new StringExp(exp.loc, funcname.toDString()));
3821 }
3822 id = new CallExp(exp.loc, id, arguments);
3823
3824 exp.lowering = id.expressionSemantic(sc);
3825 }
5fee5ec3 3826 }
6384eff5 3827 else if (auto ts = tb.isTypeStruct())
5fee5ec3 3828 {
6384eff5 3829 auto sd = ts.sym;
5fee5ec3
IB
3830 sd.size(exp.loc);
3831 if (sd.sizeok != Sizeok.done)
3832 return setError();
3833 if (!sd.ctor)
3834 sd.ctor = sd.searchCtor();
3835 if (sd.noDefaultCtor && !nargs)
3836 {
3837 exp.error("default construction is disabled for type `%s`", sd.type.toChars());
3838 return setError();
3839 }
3840 // checkDeprecated() is already done in newtype.typeSemantic().
3841
3842 if (sd.disableNew)
3843 {
3844 exp.error("cannot allocate `struct %s` with `new` because it is annotated with `@disable new()`",
3845 originalNewtype.toChars());
3846 return setError();
3847 }
5fee5ec3 3848
235d5a96
IB
3849 // https://issues.dlang.org/show_bug.cgi?id=22639
3850 // If the new expression has arguments, we either should call a
3851 // regular constructor of a copy constructor if the first argument
3852 // is the same type as the struct
3853 if (nargs && (sd.hasRegularCtor() || (sd.ctor && (*exp.arguments)[0].type.mutableOf() == sd.type.mutableOf())))
5fee5ec3 3854 {
8da8c7d3 3855 FuncDeclaration f = resolveFuncCall(exp.loc, sc, sd.ctor, null, tb, exp.argumentList, FuncResolveFlag.standard);
5fee5ec3
IB
3856 if (!f || f.errors)
3857 return setError();
3858
3859 checkFunctionAttributes(exp, sc, f);
3860 checkAccess(sd, exp.loc, sc, f);
3861
6384eff5 3862 TypeFunction tf = f.type.isTypeFunction();
5fee5ec3
IB
3863 if (!exp.arguments)
3864 exp.arguments = new Expressions();
8da8c7d3 3865 if (functionParameters(exp.loc, sc, tf, null, exp.type, exp.argumentList, f, &exp.type, &exp.argprefix))
5fee5ec3
IB
3866 return setError();
3867
3868 exp.member = f.isCtorDeclaration();
3869 assert(exp.member);
3870
6d799f0a 3871 if (checkFrameAccess(exp.loc, sc, sd, sd.fields.length))
5fee5ec3
IB
3872 return setError();
3873 }
3874 else
3875 {
8da8c7d3
IB
3876 if (exp.names)
3877 {
3878 exp.arguments = resolveStructLiteralNamedArgs(sd, exp.type, sc, exp.loc,
3879 exp.names ? (*exp.names)[] : null,
3880 (size_t i, Type t) => (*exp.arguments)[i],
3881 i => (*exp.arguments)[i].loc
3882 );
3883 if (!exp.arguments)
3884 return setError();
3885 }
3886 else if (!exp.arguments)
3887 {
5fee5ec3 3888 exp.arguments = new Expressions();
8da8c7d3 3889 }
5fee5ec3
IB
3890
3891 if (!sd.fit(exp.loc, sc, exp.arguments, tb))
3892 return setError();
3893
c8dfa79c 3894 if (!sd.fill(exp.loc, *exp.arguments, false))
5fee5ec3
IB
3895 return setError();
3896
6d799f0a 3897 if (checkFrameAccess(exp.loc, sc, sd, exp.arguments ? exp.arguments.length : 0))
5fee5ec3
IB
3898 return setError();
3899
3900 /* Since a `new` allocation may escape, check each of the arguments for escaping
3901 */
5eb9927a 3902 foreach (arg; *exp.arguments)
5fee5ec3 3903 {
5eb9927a
IB
3904 if (arg && checkNewEscape(sc, arg, false))
3905 return setError();
5fee5ec3
IB
3906 }
3907 }
3908
3909 exp.type = exp.type.pointerTo();
3910 }
3911 else if (tb.ty == Tarray)
3912 {
3913 if (!nargs)
3914 {
3915 // https://issues.dlang.org/show_bug.cgi?id=20422
3916 // Without this check the compiler would give a misleading error
3917 exp.error("missing length argument for array");
3918 return setError();
3919 }
3920
3921 Type tn = tb.nextOf().baseElemOf();
3922 Dsymbol s = tn.toDsymbol(sc);
3923 AggregateDeclaration ad = s ? s.isAggregateDeclaration() : null;
3924 if (ad && ad.noDefaultCtor)
3925 {
3926 exp.error("default construction is disabled for type `%s`", tb.nextOf().toChars());
3927 return setError();
3928 }
3929 for (size_t i = 0; i < nargs; i++)
3930 {
3931 if (tb.ty != Tarray)
3932 {
3933 exp.error("too many arguments for array");
3934 return setError();
3935 }
3936
3937 Expression arg = (*exp.arguments)[i];
8da8c7d3
IB
3938 if (exp.names && (*exp.names)[i])
3939 {
3940 exp.error("no named argument `%s` allowed for array dimension", (*exp.names)[i].toChars());
3941 return setError();
3942 }
3943
5fee5ec3
IB
3944 arg = resolveProperties(sc, arg);
3945 arg = arg.implicitCastTo(sc, Type.tsize_t);
9c7d5e88 3946 if (arg.op == EXP.error)
5fee5ec3
IB
3947 return setError();
3948 arg = arg.optimize(WANTvalue);
9c7d5e88 3949 if (arg.op == EXP.int64 && cast(sinteger_t)arg.toInteger() < 0)
5fee5ec3
IB
3950 {
3951 exp.error("negative array index `%s`", arg.toChars());
3952 return setError();
3953 }
3954 (*exp.arguments)[i] = arg;
6384eff5 3955 tb = tb.isTypeDArray().next.toBasetype();
5fee5ec3
IB
3956 }
3957 }
3958 else if (tb.isscalar())
3959 {
3960 if (!nargs)
3961 {
3962 }
3963 else if (nargs == 1)
3964 {
8da8c7d3
IB
3965 if (exp.names && (*exp.names)[0])
3966 {
3967 exp.error("no named argument `%s` allowed for scalar", (*exp.names)[0].toChars());
3968 return setError();
3969 }
5fee5ec3
IB
3970 Expression e = (*exp.arguments)[0];
3971 e = e.implicitCastTo(sc, tb);
3972 (*exp.arguments)[0] = e;
3973 }
3974 else
3975 {
3976 exp.error("more than one argument for construction of `%s`", exp.type.toChars());
3977 return setError();
3978 }
3979
3980 exp.type = exp.type.pointerTo();
3981 }
b6df1132
IB
3982 else if (tb.ty == Taarray)
3983 {
3984 // e.g. `new Alias(args)`
3985 if (nargs)
3986 {
3987 exp.error("`new` cannot take arguments for an associative array");
3988 return setError();
3989 }
3990 }
5fee5ec3
IB
3991 else
3992 {
3993 exp.error("cannot create a `%s` with `new`", exp.type.toChars());
3994 return setError();
3995 }
3996
3997 //printf("NewExp: '%s'\n", toChars());
3998 //printf("NewExp:type '%s'\n", type.toChars());
3999 semanticTypeInfo(sc, exp.type);
4000
4001 if (newprefix)
4002 {
4003 result = Expression.combine(newprefix, exp);
4004 return;
4005 }
4006 result = exp;
4007 }
4008
4009 override void visit(NewAnonClassExp e)
4010 {
4011 static if (LOGSEMANTIC)
4012 {
4013 printf("NewAnonClassExp::semantic() %s\n", e.toChars());
4014 //printf("thisexp = %p\n", thisexp);
4015 //printf("type: %s\n", type.toChars());
4016 }
4017
4018 Expression d = new DeclarationExp(e.loc, e.cd);
4019 sc = sc.push(); // just create new scope
4020 sc.flags &= ~SCOPE.ctfe; // temporary stop CTFE
4021 d = d.expressionSemantic(sc);
4022 sc = sc.pop();
4023
4024 if (!e.cd.errors && sc.intypeof && !sc.parent.inNonRoot())
4025 {
4026 ScopeDsymbol sds = sc.tinst ? cast(ScopeDsymbol)sc.tinst : sc._module;
4027 if (!sds.members)
4028 sds.members = new Dsymbols();
4029 sds.members.push(e.cd);
4030 }
4031
6384eff5 4032 Expression n = new NewExp(e.loc, e.thisexp, e.cd.type, e.arguments);
5fee5ec3
IB
4033
4034 Expression c = new CommaExp(e.loc, d, n);
4035 result = c.expressionSemantic(sc);
4036 }
4037
4038 override void visit(SymOffExp e)
4039 {
4040 static if (LOGSEMANTIC)
4041 {
4042 printf("SymOffExp::semantic('%s')\n", e.toChars());
4043 }
4044 //var.dsymbolSemantic(sc);
4045 if (!e.type)
4046 e.type = e.var.type.pointerTo();
4047
4048 if (auto v = e.var.isVarDeclaration())
4049 {
4050 if (v.checkNestedReference(sc, e.loc))
4051 return setError();
4052 }
4053 else if (auto f = e.var.isFuncDeclaration())
4054 {
4055 if (f.checkNestedReference(sc, e.loc))
4056 return setError();
4057 }
4058
4059 result = e;
4060 }
4061
4062 override void visit(VarExp e)
4063 {
4064 static if (LOGSEMANTIC)
4065 {
4066 printf("VarExp::semantic(%s)\n", e.toChars());
4067 }
4068
4069 auto vd = e.var.isVarDeclaration();
4070 auto fd = e.var.isFuncDeclaration();
4071
4072 if (fd)
4073 {
4074 //printf("L%d fd = %s\n", __LINE__, f.toChars());
4075 if (!fd.functionSemantic())
4076 return setError();
4077 }
4078
4079 if (!e.type)
4080 e.type = e.var.type;
4081 if (e.type && !e.type.deco)
4082 {
4083 auto decl = e.var.isDeclaration();
4084 if (decl)
4085 decl.inuse++;
4086 e.type = e.type.typeSemantic(e.loc, sc);
4087 if (decl)
4088 decl.inuse--;
4089 }
4090
4091 /* Fix for 1161 doesn't work because it causes visibility
4092 * problems when instantiating imported templates passing private
4093 * variables as alias template parameters.
4094 */
4095 //checkAccess(loc, sc, NULL, var);
4096
4097 if (vd)
4098 {
4099 if (vd.checkNestedReference(sc, e.loc))
4100 return setError();
4101
4102 // https://issues.dlang.org/show_bug.cgi?id=12025
4103 // If the variable is not actually used in runtime code,
4104 // the purity violation error is redundant.
4105 //checkPurity(sc, vd);
4106 }
4107 else if (fd)
4108 {
4109 // TODO: If fd isn't yet resolved its overload, the checkNestedReference
4110 // call would cause incorrect validation.
4111 // Maybe here should be moved in CallExp, or AddrExp for functions.
4112 if (fd.checkNestedReference(sc, e.loc))
4113 return setError();
4114 }
4115 else if (auto od = e.var.isOverDeclaration())
4116 {
4117 e.type = Type.tvoid; // ambiguous type?
4118 }
4119
4120 result = e;
4121 }
4122
4123 override void visit(FuncExp exp)
4124 {
4125 static if (LOGSEMANTIC)
4126 {
4127 printf("FuncExp::semantic(%s)\n", exp.toChars());
4128 if (exp.fd.treq)
4129 printf(" treq = %s\n", exp.fd.treq.toChars());
4130 }
4131
4132 if (exp.type)
4133 {
4134 result = exp;
4135 return;
4136 }
4137
4138 Expression e = exp;
4139 uint olderrors;
4140
4141 sc = sc.push(); // just create new scope
4142 sc.flags &= ~SCOPE.ctfe; // temporary stop CTFE
4143 sc.visibility = Visibility(Visibility.Kind.public_); // https://issues.dlang.org/show_bug.cgi?id=12506
4144
4145 /* fd.treq might be incomplete type,
4146 * so should not semantic it.
4147 * void foo(T)(T delegate(int) dg){}
4148 * foo(a=>a); // in IFTI, treq == T delegate(int)
4149 */
4150 //if (fd.treq)
4151 // fd.treq = fd.treq.dsymbolSemantic(loc, sc);
4152
4153 exp.genIdent(sc);
4154
4155 // Set target of return type inference
4156 if (exp.fd.treq && !exp.fd.type.nextOf())
4157 {
4158 TypeFunction tfv = null;
4159 if (exp.fd.treq.ty == Tdelegate || exp.fd.treq.isPtrToFunction())
4160 tfv = cast(TypeFunction)exp.fd.treq.nextOf();
4161 if (tfv)
4162 {
4163 TypeFunction tfl = cast(TypeFunction)exp.fd.type;
4164 tfl.next = tfv.nextOf();
4165 }
4166 }
4167
4168 //printf("td = %p, treq = %p\n", td, fd.treq);
4169 if (exp.td)
4170 {
6d799f0a 4171 assert(exp.td.parameters && exp.td.parameters.length);
5fee5ec3
IB
4172 exp.td.dsymbolSemantic(sc);
4173 exp.type = Type.tvoid; // temporary type
4174
4175 if (exp.fd.treq) // defer type determination
4176 {
4177 FuncExp fe;
4178 if (exp.matchType(exp.fd.treq, sc, &fe) > MATCH.nomatch)
4179 e = fe;
4180 else
4181 e = ErrorExp.get();
4182 }
4183 goto Ldone;
4184 }
4185
4186 olderrors = global.errors;
4187 exp.fd.dsymbolSemantic(sc);
4188 if (olderrors == global.errors)
4189 {
4190 exp.fd.semantic2(sc);
4191 if (olderrors == global.errors)
4192 exp.fd.semantic3(sc);
4193 }
4194 if (olderrors != global.errors)
4195 {
4196 if (exp.fd.type && exp.fd.type.ty == Tfunction && !exp.fd.type.nextOf())
4197 (cast(TypeFunction)exp.fd.type).next = Type.terror;
4198 e = ErrorExp.get();
4199 goto Ldone;
4200 }
4201
4202 // Type is a "delegate to" or "pointer to" the function literal
4203 if ((exp.fd.isNested() && exp.fd.tok == TOK.delegate_) || (exp.tok == TOK.reserved && exp.fd.treq && exp.fd.treq.ty == Tdelegate))
4204 {
6384eff5
IB
4205 // https://issues.dlang.org/show_bug.cgi?id=22686
4206 // if the delegate return type is an error
4207 // abort semantic of the FuncExp and propagate
4208 // the error
4209 if (exp.fd.type.isTypeError())
4210 {
4211 e = ErrorExp.get();
4212 goto Ldone;
4213 }
5fee5ec3
IB
4214 exp.type = new TypeDelegate(exp.fd.type.isTypeFunction());
4215 exp.type = exp.type.typeSemantic(exp.loc, sc);
4216
4217 exp.fd.tok = TOK.delegate_;
4218 }
4219 else
4220 {
4221 exp.type = new TypePointer(exp.fd.type);
4222 exp.type = exp.type.typeSemantic(exp.loc, sc);
4223 //type = fd.type.pointerTo();
4224
4225 /* A lambda expression deduced to function pointer might become
4226 * to a delegate literal implicitly.
4227 *
4228 * auto foo(void function() fp) { return 1; }
4229 * assert(foo({}) == 1);
4230 *
9c7d5e88 4231 * So, should keep fd.tok == TOK.reserve if fd.treq == NULL.
5fee5ec3
IB
4232 */
4233 if (exp.fd.treq && exp.fd.treq.ty == Tpointer)
4234 {
4235 // change to non-nested
4236 exp.fd.tok = TOK.function_;
4237 exp.fd.vthis = null;
4238 }
4239 }
4240 exp.fd.tookAddressOf++;
4241
4242 Ldone:
4243 sc = sc.pop();
4244 result = e;
4245 }
4246
4247 /**
4248 * Perform semantic analysis on function literals
4249 *
4250 * Test the following construct:
4251 * ---
4252 * (x, y, z) { return x + y + z; }(42, 84, 1992);
4253 * ---
4254 */
4255 Expression callExpSemantic(FuncExp exp, Scope* sc, Expressions* arguments)
4256 {
6d799f0a 4257 if ((!exp.type || exp.type == Type.tvoid) && exp.td && arguments && arguments.length)
5fee5ec3 4258 {
6d799f0a 4259 for (size_t k = 0; k < arguments.length; k++)
5fee5ec3
IB
4260 {
4261 Expression checkarg = (*arguments)[k];
9c7d5e88 4262 if (checkarg.op == EXP.error)
5fee5ec3
IB
4263 return checkarg;
4264 }
4265
4266 exp.genIdent(sc);
4267
6d799f0a 4268 assert(exp.td.parameters && exp.td.parameters.length);
5fee5ec3
IB
4269 exp.td.dsymbolSemantic(sc);
4270
4271 TypeFunction tfl = cast(TypeFunction)exp.fd.type;
4272 size_t dim = tfl.parameterList.length;
6d799f0a 4273 if (arguments.length < dim)
5fee5ec3
IB
4274 {
4275 // Default arguments are always typed, so they don't need inference.
6d799f0a 4276 Parameter p = tfl.parameterList[arguments.length];
5fee5ec3 4277 if (p.defaultArg)
6d799f0a 4278 dim = arguments.length;
5fee5ec3
IB
4279 }
4280
6d799f0a
IB
4281 if ((tfl.parameterList.varargs == VarArg.none && arguments.length > dim) ||
4282 arguments.length < dim)
5fee5ec3
IB
4283 {
4284 OutBuffer buf;
4285 foreach (idx, ref arg; *arguments)
4286 buf.printf("%s%s", (idx ? ", ".ptr : "".ptr), arg.type.toChars());
4287 exp.error("function literal `%s%s` is not callable using argument types `(%s)`",
4288 exp.fd.toChars(), parametersTypeToChars(tfl.parameterList),
4289 buf.peekChars());
6d799f0a
IB
4290 exp.errorSupplemental("too %s arguments, expected %d, got %d",
4291 arguments.length < dim ? "few".ptr : "many".ptr,
4292 cast(int)dim, cast(int)arguments.length);
5fee5ec3
IB
4293 return ErrorExp.get();
4294 }
4295
4296 auto tiargs = new Objects();
6d799f0a 4297 tiargs.reserve(exp.td.parameters.length);
5fee5ec3 4298
6d799f0a 4299 for (size_t i = 0; i < exp.td.parameters.length; i++)
5fee5ec3
IB
4300 {
4301 TemplateParameter tp = (*exp.td.parameters)[i];
4302 assert(dim <= tfl.parameterList.length);
4303 foreach (u, p; tfl.parameterList)
4304 {
4305 if (u == dim)
4306 break;
4307
4308 if (p.type.ty == Tident && (cast(TypeIdentifier)p.type).ident == tp.ident)
4309 {
4310 Expression e = (*arguments)[u];
4311 tiargs.push(e.type);
4312 break;
4313 }
4314 }
4315 }
4316
4317 auto ti = new TemplateInstance(exp.loc, exp.td, tiargs);
4318 return (new ScopeExp(exp.loc, ti)).expressionSemantic(sc);
4319 }
4320 return exp.expressionSemantic(sc);
4321 }
4322
4323 override void visit(CallExp exp)
4324 {
4325 static if (LOGSEMANTIC)
4326 {
4327 printf("CallExp::semantic() %s\n", exp.toChars());
4328 }
4329 if (exp.type)
4330 {
4331 result = exp;
4332 return; // semantic() already run
4333 }
4334
4335 Objects* tiargs = null; // initial list of template arguments
4336 Expression ethis = null;
4337 Type tthis = null;
4338 Expression e1org = exp.e1;
4339
235d5a96 4340 if (auto ce = exp.e1.isCommaExp())
5fee5ec3
IB
4341 {
4342 /* Rewrite (a,b)(args) as (a,(b(args)))
4343 */
5fee5ec3
IB
4344 exp.e1 = ce.e2;
4345 ce.e2 = exp;
4346 result = ce.expressionSemantic(sc);
4347 return;
4348 }
235d5a96 4349 if (DelegateExp de = exp.e1.isDelegateExp())
5fee5ec3 4350 {
5fee5ec3
IB
4351 exp.e1 = new DotVarExp(de.loc, de.e1, de.func, de.hasOverloads);
4352 visit(exp);
4353 return;
4354 }
235d5a96 4355 if (FuncExp fe = exp.e1.isFuncExp())
5fee5ec3 4356 {
c8dfa79c 4357 if (arrayExpressionSemantic(exp.arguments.peekSlice(), sc) ||
8da8c7d3 4358 preFunctionParameters(sc, exp.argumentList))
5fee5ec3
IB
4359 return setError();
4360
4361 // Run e1 semantic even if arguments have any errors
5fee5ec3 4362 exp.e1 = callExpSemantic(fe, sc, exp.arguments);
9c7d5e88 4363 if (exp.e1.op == EXP.error)
5fee5ec3
IB
4364 {
4365 result = exp.e1;
4366 return;
4367 }
4368 }
fd43568c
IB
4369 if (sc.flags & SCOPE.Cfile)
4370 {
4371 /* See if need to rewrite the AST because of cast/call ambiguity
4372 */
4373 if (auto e = castCallAmbiguity(exp, sc))
4374 {
4375 result = expressionSemantic(e, sc);
4376 return;
4377 }
4378 }
5fee5ec3
IB
4379
4380 if (Expression ex = resolveUFCS(sc, exp))
4381 {
4382 result = ex;
4383 return;
4384 }
4385
4386 /* This recognizes:
4387 * foo!(tiargs)(funcargs)
4388 */
235d5a96 4389 if (ScopeExp se = exp.e1.isScopeExp())
5fee5ec3 4390 {
5fee5ec3
IB
4391 TemplateInstance ti = se.sds.isTemplateInstance();
4392 if (ti)
4393 {
4394 /* Attempt to instantiate ti. If that works, go with it.
4395 * If not, go with partial explicit specialization.
4396 */
4397 WithScopeSymbol withsym;
4398 if (!ti.findTempDecl(sc, &withsym) || !ti.semanticTiargs(sc))
4399 return setError();
4400 if (withsym && withsym.withstate.wthis)
4401 {
4402 exp.e1 = new VarExp(exp.e1.loc, withsym.withstate.wthis);
4403 exp.e1 = new DotTemplateInstanceExp(exp.e1.loc, exp.e1, ti);
4404 goto Ldotti;
4405 }
4406 if (ti.needsTypeInference(sc, 1))
4407 {
4408 /* Go with partial explicit specialization
4409 */
4410 tiargs = ti.tiargs;
4411 assert(ti.tempdecl);
4412 if (TemplateDeclaration td = ti.tempdecl.isTemplateDeclaration())
4413 exp.e1 = new TemplateExp(exp.loc, td);
4414 else if (OverDeclaration od = ti.tempdecl.isOverDeclaration())
4415 exp.e1 = new VarExp(exp.loc, od);
4416 else
4417 exp.e1 = new OverExp(exp.loc, ti.tempdecl.isOverloadSet());
4418 }
4419 else
4420 {
4421 Expression e1x = exp.e1.expressionSemantic(sc);
9c7d5e88 4422 if (e1x.op == EXP.error)
5fee5ec3
IB
4423 {
4424 result = e1x;
4425 return;
4426 }
4427 exp.e1 = e1x;
4428 }
4429 }
4430 }
4431
4432 /* This recognizes:
4433 * expr.foo!(tiargs)(funcargs)
4434 */
4435 Ldotti:
235d5a96 4436 if (DotTemplateInstanceExp se = exp.e1.isDotTemplateInstanceExp())
5fee5ec3 4437 {
5fee5ec3
IB
4438 TemplateInstance ti = se.ti;
4439 {
4440 /* Attempt to instantiate ti. If that works, go with it.
4441 * If not, go with partial explicit specialization.
4442 */
4443 if (!se.findTempDecl(sc) || !ti.semanticTiargs(sc))
4444 return setError();
4445 if (ti.needsTypeInference(sc, 1))
4446 {
4447 /* Go with partial explicit specialization
4448 */
4449 tiargs = ti.tiargs;
4450 assert(ti.tempdecl);
4451 if (TemplateDeclaration td = ti.tempdecl.isTemplateDeclaration())
4452 exp.e1 = new DotTemplateExp(exp.loc, se.e1, td);
4453 else if (OverDeclaration od = ti.tempdecl.isOverDeclaration())
4454 {
4455 exp.e1 = new DotVarExp(exp.loc, se.e1, od, true);
4456 }
4457 else
4458 exp.e1 = new DotExp(exp.loc, se.e1, new OverExp(exp.loc, ti.tempdecl.isOverloadSet()));
4459 }
4460 else
4461 {
4462 Expression e1x = exp.e1.expressionSemantic(sc);
9c7d5e88 4463 if (e1x.op == EXP.error)
5fee5ec3
IB
4464 {
4465 result = e1x;
4466 return;
4467 }
4468 exp.e1 = e1x;
4469 }
4470 }
4471 }
4472
4473 Lagain:
4474 //printf("Lagain: %s\n", toChars());
4475 exp.f = null;
9c7d5e88 4476 if (exp.e1.op == EXP.this_ || exp.e1.op == EXP.super_)
5fee5ec3
IB
4477 {
4478 // semantic() run later for these
4479 }
4480 else
4481 {
235d5a96 4482 if (DotIdExp die = exp.e1.isDotIdExp())
5fee5ec3 4483 {
5fee5ec3
IB
4484 exp.e1 = die.expressionSemantic(sc);
4485 /* Look for e1 having been rewritten to expr.opDispatch!(string)
4486 * We handle such earlier, so go back.
4487 * Note that in the rewrite, we carefully did not run semantic() on e1
4488 */
9c7d5e88 4489 if (exp.e1.op == EXP.dotTemplateInstance)
5fee5ec3
IB
4490 {
4491 goto Ldotti;
4492 }
4493 }
4494 else
4495 {
4496 __gshared int nest;
4497 if (++nest > global.recursionLimit)
4498 {
4499 exp.error("recursive evaluation of `%s`", exp.toChars());
4500 --nest;
4501 return setError();
4502 }
4503 Expression ex = unaSemantic(exp, sc);
4504 --nest;
4505 if (ex)
4506 {
4507 result = ex;
4508 return;
4509 }
4510 }
4511
4512 /* Look for e1 being a lazy parameter
4513 */
235d5a96 4514 if (VarExp ve = exp.e1.isVarExp())
5fee5ec3 4515 {
5fee5ec3
IB
4516 if (ve.var.storage_class & STC.lazy_)
4517 {
4518 // lazy parameters can be called without violating purity and safety
4519 Type tw = ve.var.type;
4520 Type tc = ve.var.type.substWildTo(MODFlags.const_);
4521 auto tf = new TypeFunction(ParameterList(), tc, LINK.d, STC.safe | STC.pure_);
4522 (tf = cast(TypeFunction)tf.typeSemantic(exp.loc, sc)).next = tw; // hack for bug7757
4523 auto t = new TypeDelegate(tf);
4524 ve.type = t.typeSemantic(exp.loc, sc);
4525 }
4526 VarDeclaration v = ve.var.isVarDeclaration();
4527 if (v && ve.checkPurity(sc, v))
4528 return setError();
4529 }
4530
9c7d5e88 4531 if (exp.e1.op == EXP.symbolOffset && (cast(SymOffExp)exp.e1).hasOverloads)
5fee5ec3
IB
4532 {
4533 SymOffExp se = cast(SymOffExp)exp.e1;
4534 exp.e1 = new VarExp(se.loc, se.var, true);
4535 exp.e1 = exp.e1.expressionSemantic(sc);
4536 }
235d5a96 4537 else if (DotExp de = exp.e1.isDotExp())
5fee5ec3 4538 {
9c7d5e88 4539 if (de.e2.op == EXP.overloadSet)
5fee5ec3
IB
4540 {
4541 ethis = de.e1;
4542 tthis = de.e1.type;
4543 exp.e1 = de.e2;
4544 }
4545 }
9c7d5e88 4546 else if (exp.e1.op == EXP.star && exp.e1.type.ty == Tfunction)
5fee5ec3
IB
4547 {
4548 // Rewrite (*fp)(arguments) to fp(arguments)
4549 exp.e1 = (cast(PtrExp)exp.e1).e1;
4550 }
9c7d5e88 4551 else if (exp.e1.op == EXP.type && (sc && sc.flags & SCOPE.Cfile))
5fee5ec3 4552 {
0fb57034 4553 const numArgs = exp.arguments ? exp.arguments.length : 0;
0fb57034 4554
5fee5ec3
IB
4555 /* Ambiguous cases arise from CParser where there is not enough
4556 * information to determine if we have a function call or declaration.
4557 * type-name ( identifier ) ;
4558 * identifier ( identifier ) ;
4559 * If exp.e1 is a type-name, then this is a declaration. C11 does not
4560 * have type construction syntax, so don't convert this to a cast().
4561 */
0fb57034 4562 if (numArgs == 1)
5fee5ec3
IB
4563 {
4564 Expression arg = (*exp.arguments)[0];
4565 if (auto ie = (*exp.arguments)[0].isIdentifierExp())
4566 {
4567 TypeExp te = cast(TypeExp)exp.e1;
4568 auto initializer = new VoidInitializer(ie.loc);
4569 Dsymbol s = new VarDeclaration(ie.loc, te.type, ie.ident, initializer);
4570 auto decls = new Dsymbols(1);
4571 (*decls)[0] = s;
4572 s = new LinkDeclaration(s.loc, LINK.c, decls);
4573 result = new DeclarationExp(exp.loc, s);
4574 result = result.expressionSemantic(sc);
4575 }
4576 else
4577 {
4578 arg.error("identifier or `(` expected");
4579 result = ErrorExp.get();
4580 }
4581 return;
4582 }
4583 exp.error("identifier or `(` expected before `)`");
4584 result = ErrorExp.get();
4585 return;
4586 }
4587 }
4588
4589 Type t1 = exp.e1.type ? exp.e1.type.toBasetype() : null;
4590
9c7d5e88 4591 if (exp.e1.op == EXP.error)
5fee5ec3
IB
4592 {
4593 result = exp.e1;
4594 return;
4595 }
c8dfa79c 4596 if (arrayExpressionSemantic(exp.arguments.peekSlice(), sc) ||
8da8c7d3 4597 preFunctionParameters(sc, exp.argumentList))
5fee5ec3
IB
4598 return setError();
4599
4600 // Check for call operator overload
4601 if (t1)
4602 {
4603 if (t1.ty == Tstruct)
4604 {
4605 auto sd = (cast(TypeStruct)t1).sym;
4606 sd.size(exp.loc); // Resolve forward references to construct object
4607 if (sd.sizeok != Sizeok.done)
4608 return setError();
4609 if (!sd.ctor)
4610 sd.ctor = sd.searchCtor();
4611 /* If `sd.ctor` is a generated copy constructor, this means that it
4612 is the single constructor that this struct has. In order to not
4613 disable default construction, the ctor is nullified. The side effect
4614 of this is that the generated copy constructor cannot be called
4615 explicitly, but that is ok, because when calling a constructor the
4616 default constructor should have priority over the generated copy
4617 constructor.
4618 */
4619 if (sd.ctor)
4620 {
4621 auto ctor = sd.ctor.isCtorDeclaration();
235d5a96 4622 if (ctor && ctor.isCpCtor && ctor.isGenerated())
5fee5ec3
IB
4623 sd.ctor = null;
4624 }
4625
4626 // First look for constructor
9c7d5e88 4627 if (exp.e1.op == EXP.type && sd.ctor)
5fee5ec3 4628 {
6d799f0a 4629 if (!sd.noDefaultCtor && !(exp.arguments && exp.arguments.length))
5fee5ec3
IB
4630 goto Lx;
4631
4632 /* https://issues.dlang.org/show_bug.cgi?id=20695
4633 If all constructors are copy constructors, then
4634 try default construction.
4635 */
235d5a96
IB
4636 if (!sd.hasRegularCtor &&
4637 // https://issues.dlang.org/show_bug.cgi?id=22639
4638 // we might still have a copy constructor that could be called
4639 (*exp.arguments)[0].type.mutableOf != sd.type.mutableOf())
5fee5ec3
IB
4640 goto Lx;
4641
4642 auto sle = new StructLiteralExp(exp.loc, sd, null, exp.e1.type);
c8dfa79c 4643 if (!sd.fill(exp.loc, *sle.elements, true))
5fee5ec3 4644 return setError();
6d799f0a 4645 if (checkFrameAccess(exp.loc, sc, sd, sle.elements.length))
5fee5ec3
IB
4646 return setError();
4647
4648 // https://issues.dlang.org/show_bug.cgi?id=14556
4649 // Set concrete type to avoid further redundant semantic().
4650 sle.type = exp.e1.type;
4651
4652 /* Constructor takes a mutable object, so don't use
4653 * the immutable initializer symbol.
4654 */
4655 sle.useStaticInit = false;
4656
4657 Expression e = sle;
4658 if (auto cf = sd.ctor.isCtorDeclaration())
4659 {
4660 e = new DotVarExp(exp.loc, e, cf, true);
4661 }
4662 else if (auto td = sd.ctor.isTemplateDeclaration())
4663 {
4664 e = new DotIdExp(exp.loc, e, td.ident);
4665 }
4666 else if (auto os = sd.ctor.isOverloadSet())
4667 {
4668 e = new DotExp(exp.loc, e, new OverExp(exp.loc, os));
4669 }
4670 else
4671 assert(0);
4672 e = new CallExp(exp.loc, e, exp.arguments);
4673 e = e.expressionSemantic(sc);
4674 result = e;
4675 return;
4676 }
4677 // No constructor, look for overload of opCall
4678 if (search_function(sd, Id.call))
4679 goto L1;
4680 // overload of opCall, therefore it's a call
9c7d5e88 4681 if (exp.e1.op != EXP.type)
5fee5ec3
IB
4682 {
4683 if (sd.aliasthis && !isRecursiveAliasThis(exp.att1, exp.e1.type))
4684 {
4685 exp.e1 = resolveAliasThis(sc, exp.e1);
4686 goto Lagain;
4687 }
4688 exp.error("%s `%s` does not overload ()", sd.kind(), sd.toChars());
4689 return setError();
4690 }
4691
4692 /* It's a struct literal
4693 */
4694 Lx:
8da8c7d3
IB
4695 Expressions* resolvedArgs = exp.arguments;
4696 if (exp.names)
4697 {
4698 resolvedArgs = resolveStructLiteralNamedArgs(sd, exp.e1.type, sc, exp.loc,
4699 (*exp.names)[],
4700 (size_t i, Type t) => (*exp.arguments)[i],
4701 i => (*exp.arguments)[i].loc
4702 );
4703 if (!resolvedArgs)
4704 {
4705 result = ErrorExp.get();
4706 return;
4707 }
4708 }
4709
4710 Expression e = new StructLiteralExp(exp.loc, sd, resolvedArgs, exp.e1.type);
5fee5ec3
IB
4711 e = e.expressionSemantic(sc);
4712 result = e;
4713 return;
4714 }
4715 else if (t1.ty == Tclass)
4716 {
4717 L1:
4718 // Rewrite as e1.call(arguments)
4719 Expression e = new DotIdExp(exp.loc, exp.e1, Id.call);
8da8c7d3 4720 e = new CallExp(exp.loc, e, exp.arguments, exp.names);
5fee5ec3
IB
4721 e = e.expressionSemantic(sc);
4722 result = e;
4723 return;
4724 }
9c7d5e88 4725 else if (exp.e1.op == EXP.type && t1.isscalar())
5fee5ec3
IB
4726 {
4727 Expression e;
4728
c8dfa79c 4729 // Make sure to use the enum type itself rather than its
5fee5ec3
IB
4730 // base type
4731 // https://issues.dlang.org/show_bug.cgi?id=16346
4732 if (exp.e1.type.ty == Tenum)
4733 {
4734 t1 = exp.e1.type;
4735 }
4736
6d799f0a 4737 if (!exp.arguments || exp.arguments.length == 0)
5fee5ec3
IB
4738 {
4739 e = t1.defaultInitLiteral(exp.loc);
4740 }
6d799f0a 4741 else if (exp.arguments.length == 1)
5fee5ec3
IB
4742 {
4743 e = (*exp.arguments)[0];
f99303eb
IB
4744 e = e.implicitCastTo(sc, t1);
4745 e = new CastExp(exp.loc, e, t1);
5fee5ec3
IB
4746 }
4747 else
4748 {
4749 exp.error("more than one argument for construction of `%s`", t1.toChars());
4750 return setError();
4751 }
4752 e = e.expressionSemantic(sc);
4753 result = e;
4754 return;
4755 }
4756 }
4757
6d799f0a 4758 FuncDeclaration resolveOverloadSet(Loc loc, Scope* sc,
8da8c7d3 4759 OverloadSet os, Objects* tiargs, Type tthis, ArgumentList argumentList)
5fee5ec3
IB
4760 {
4761 FuncDeclaration f = null;
4762 foreach (s; os.a)
4763 {
4764 if (tiargs && s.isFuncDeclaration())
4765 continue;
8da8c7d3 4766 if (auto f2 = resolveFuncCall(loc, sc, s, tiargs, tthis, argumentList, FuncResolveFlag.quiet))
5fee5ec3
IB
4767 {
4768 if (f2.errors)
4769 return null;
4770 if (f)
4771 {
4772 /* Error if match in more than one overload set,
4773 * even if one is a 'better' match than the other.
4774 */
4775 ScopeDsymbol.multiplyDefined(loc, f, f2);
4776 }
4777 else
4778 f = f2;
4779 }
4780 }
4781 if (!f)
6d799f0a
IB
4782 {
4783 .error(loc, "no overload matches for `%s`", exp.toChars());
4784 errorSupplemental(loc, "Candidates are:");
4785 foreach (s; os.a)
4786 {
4787 overloadApply(s, (ds){
4788 if (auto fd = ds.isFuncDeclaration())
4789 .errorSupplemental(ds.loc, "%s%s", fd.toChars(),
4790 fd.type.toTypeFunction().parameterList.parametersTypeToChars());
4791 else
4792 .errorSupplemental(ds.loc, "%s", ds.toChars());
4793 return 0;
4794 });
4795 }
4796 }
5fee5ec3
IB
4797 else if (f.errors)
4798 f = null;
4799 return f;
4800 }
4801
4802 bool isSuper = false;
9c7d5e88 4803 if (exp.e1.op == EXP.dotVariable && t1.ty == Tfunction || exp.e1.op == EXP.dotTemplateDeclaration)
5fee5ec3
IB
4804 {
4805 UnaExp ue = cast(UnaExp)exp.e1;
4806
0fb57034 4807 Expression ue1old = ue.e1; // need for 'right this' check
5fee5ec3
IB
4808 DotVarExp dve;
4809 DotTemplateExp dte;
4810 Dsymbol s;
9c7d5e88 4811 if (exp.e1.op == EXP.dotVariable)
5fee5ec3
IB
4812 {
4813 dve = cast(DotVarExp)exp.e1;
4814 dte = null;
4815 s = dve.var;
4816 tiargs = null;
4817 }
4818 else
4819 {
4820 dve = null;
4821 dte = cast(DotTemplateExp)exp.e1;
4822 s = dte.td;
4823 }
4824
4825 // Do overload resolution
8da8c7d3 4826 exp.f = resolveFuncCall(exp.loc, sc, s, tiargs, ue.e1.type, exp.argumentList, FuncResolveFlag.standard);
5fee5ec3
IB
4827 if (!exp.f || exp.f.errors || exp.f.type.ty == Terror)
4828 return setError();
4829
4830 if (exp.f.interfaceVirtual)
4831 {
4832 /* Cast 'this' to the type of the interface, and replace f with the interface's equivalent
4833 */
4834 auto b = exp.f.interfaceVirtual;
4835 auto ad2 = b.sym;
4836 ue.e1 = ue.e1.castTo(sc, ad2.type.addMod(ue.e1.type.mod));
4837 ue.e1 = ue.e1.expressionSemantic(sc);
6d799f0a 4838 auto vi = exp.f.findVtblIndex(&ad2.vtbl, cast(int)ad2.vtbl.length);
5fee5ec3
IB
4839 assert(vi >= 0);
4840 exp.f = ad2.vtbl[vi].isFuncDeclaration();
4841 assert(exp.f);
4842 }
4843 if (exp.f.needThis())
4844 {
5eb9927a 4845 AggregateDeclaration ad = exp.f.isMemberLocal();
5fee5ec3 4846 ue.e1 = getRightThis(exp.loc, sc, ad, ue.e1, exp.f);
9c7d5e88 4847 if (ue.e1.op == EXP.error)
5fee5ec3
IB
4848 {
4849 result = ue.e1;
4850 return;
4851 }
4852 ethis = ue.e1;
4853 tthis = ue.e1.type;
4854 if (!(exp.f.type.ty == Tfunction && (cast(TypeFunction)exp.f.type).isScopeQual))
4855 {
6d799f0a 4856 if (checkParamArgumentEscape(sc, exp.f, Id.This, exp.f.vthis, STC.undefined_, ethis, false, false))
5fee5ec3
IB
4857 return setError();
4858 }
4859 }
4860
4861 /* Cannot call public functions from inside invariant
4862 * (because then the invariant would have infinite recursion)
4863 */
9c7d5e88 4864 if (sc.func && sc.func.isInvariantDeclaration() && ue.e1.op == EXP.this_ && exp.f.addPostInvariant())
5fee5ec3
IB
4865 {
4866 exp.error("cannot call `public`/`export` function `%s` from invariant", exp.f.toChars());
4867 return setError();
4868 }
4869
4870 if (!exp.ignoreAttributes)
4871 checkFunctionAttributes(exp, sc, exp.f);
4872 checkAccess(exp.loc, sc, ue.e1, exp.f);
4873 if (!exp.f.needThis())
4874 {
4875 exp.e1 = Expression.combine(ue.e1, new VarExp(exp.loc, exp.f, false));
4876 }
4877 else
4878 {
4879 if (ue1old.checkRightThis(sc))
4880 return setError();
9c7d5e88 4881 if (exp.e1.op == EXP.dotVariable)
5fee5ec3
IB
4882 {
4883 dve.var = exp.f;
4884 exp.e1.type = exp.f.type;
4885 }
4886 else
4887 {
4888 exp.e1 = new DotVarExp(exp.loc, dte.e1, exp.f, false);
4889 exp.e1 = exp.e1.expressionSemantic(sc);
9c7d5e88 4890 if (exp.e1.op == EXP.error)
5fee5ec3
IB
4891 return setError();
4892 ue = cast(UnaExp)exp.e1;
4893 }
4894 version (none)
4895 {
4896 printf("ue.e1 = %s\n", ue.e1.toChars());
4897 printf("f = %s\n", exp.f.toChars());
4898 printf("t1 = %s\n", t1.toChars());
4899 printf("e1 = %s\n", exp.e1.toChars());
4900 printf("e1.type = %s\n", exp.e1.type.toChars());
4901 }
4902
4903 // See if we need to adjust the 'this' pointer
4904 AggregateDeclaration ad = exp.f.isThis();
4905 ClassDeclaration cd = ue.e1.type.isClassHandle();
4906 if (ad && cd && ad.isClassDeclaration())
4907 {
9c7d5e88 4908 if (ue.e1.op == EXP.dotType)
5fee5ec3
IB
4909 {
4910 ue.e1 = (cast(DotTypeExp)ue.e1).e1;
4911 exp.directcall = true;
4912 }
9c7d5e88 4913 else if (ue.e1.op == EXP.super_)
5fee5ec3
IB
4914 exp.directcall = true;
4915 else if ((cd.storage_class & STC.final_) != 0) // https://issues.dlang.org/show_bug.cgi?id=14211
4916 exp.directcall = true;
4917
4918 if (ad != cd)
4919 {
4920 ue.e1 = ue.e1.castTo(sc, ad.type.addMod(ue.e1.type.mod));
4921 ue.e1 = ue.e1.expressionSemantic(sc);
4922 }
4923 }
4924 }
4925 // If we've got a pointer to a function then deference it
4926 // https://issues.dlang.org/show_bug.cgi?id=16483
4927 if (exp.e1.type.isPtrToFunction())
4928 {
4929 Expression e = new PtrExp(exp.loc, exp.e1);
4930 e.type = exp.e1.type.nextOf();
4931 exp.e1 = e;
4932 }
4933 t1 = exp.e1.type;
4934 }
9c7d5e88 4935 else if (exp.e1.op == EXP.super_ || exp.e1.op == EXP.this_)
5fee5ec3
IB
4936 {
4937 auto ad = sc.func ? sc.func.isThis() : null;
4938 auto cd = ad ? ad.isClassDeclaration() : null;
4939
9c7d5e88 4940 isSuper = exp.e1.op == EXP.super_;
5fee5ec3
IB
4941 if (isSuper)
4942 {
4943 // Base class constructor call
4944 if (!cd || !cd.baseClass || !sc.func.isCtorDeclaration())
4945 {
4946 exp.error("super class constructor call must be in a constructor");
4947 return setError();
4948 }
4949 if (!cd.baseClass.ctor)
4950 {
4951 exp.error("no super class constructor for `%s`", cd.baseClass.toChars());
4952 return setError();
4953 }
4954 }
4955 else
4956 {
4957 // `this` call expression must be inside a
4958 // constructor
4959 if (!ad || !sc.func.isCtorDeclaration())
4960 {
4961 exp.error("constructor call must be in a constructor");
4962 return setError();
4963 }
4964
4965 // https://issues.dlang.org/show_bug.cgi?id=18719
4966 // If `exp` is a call expression to another constructor
4967 // then it means that all struct/class fields will be
4968 // initialized after this call.
4969 foreach (ref field; sc.ctorflow.fieldinit)
4970 {
4971 field.csx |= CSX.this_ctor;
4972 }
4973 }
4974
4975 if (!sc.intypeof && !(sc.ctorflow.callSuper & CSX.halt))
4976 {
4977 if (sc.inLoop || sc.ctorflow.callSuper & CSX.label)
4978 exp.error("constructor calls not allowed in loops or after labels");
4979 if (sc.ctorflow.callSuper & (CSX.super_ctor | CSX.this_ctor))
4980 exp.error("multiple constructor calls");
4981 if ((sc.ctorflow.callSuper & CSX.return_) && !(sc.ctorflow.callSuper & CSX.any_ctor))
4982 exp.error("an earlier `return` statement skips constructor");
4983 sc.ctorflow.callSuper |= CSX.any_ctor | (isSuper ? CSX.super_ctor : CSX.this_ctor);
4984 }
4985
4986 tthis = ad.type.addMod(sc.func.type.mod);
4987 auto ctor = isSuper ? cd.baseClass.ctor : ad.ctor;
4988 if (auto os = ctor.isOverloadSet())
8da8c7d3 4989 exp.f = resolveOverloadSet(exp.loc, sc, os, null, tthis, exp.argumentList);
5fee5ec3 4990 else
8da8c7d3 4991 exp.f = resolveFuncCall(exp.loc, sc, ctor, null, tthis, exp.argumentList, FuncResolveFlag.standard);
5fee5ec3
IB
4992
4993 if (!exp.f || exp.f.errors)
4994 return setError();
4995
4996 checkFunctionAttributes(exp, sc, exp.f);
4997 checkAccess(exp.loc, sc, null, exp.f);
4998
4999 exp.e1 = new DotVarExp(exp.e1.loc, exp.e1, exp.f, false);
5000 exp.e1 = exp.e1.expressionSemantic(sc);
5001 // https://issues.dlang.org/show_bug.cgi?id=21095
9c7d5e88 5002 if (exp.e1.op == EXP.error)
5fee5ec3
IB
5003 return setError();
5004 t1 = exp.e1.type;
5005
5006 // BUG: this should really be done by checking the static
5007 // call graph
5008 if (exp.f == sc.func)
5009 {
5010 exp.error("cyclic constructor call");
5011 return setError();
5012 }
5013 }
235d5a96 5014 else if (auto oe = exp.e1.isOverExp())
5fee5ec3 5015 {
8da8c7d3 5016 exp.f = resolveOverloadSet(exp.loc, sc, oe.vars, tiargs, tthis, exp.argumentList);
5fee5ec3
IB
5017 if (!exp.f)
5018 return setError();
5019 if (ethis)
5020 exp.e1 = new DotVarExp(exp.loc, ethis, exp.f, false);
5021 else
5022 exp.e1 = new VarExp(exp.loc, exp.f, false);
5023 goto Lagain;
5024 }
5025 else if (!t1)
5026 {
5027 exp.error("function expected before `()`, not `%s`", exp.e1.toChars());
5028 return setError();
5029 }
5030 else if (t1.ty == Terror)
5031 {
5032 return setError();
5033 }
5034 else if (t1.ty != Tfunction)
5035 {
5036 TypeFunction tf;
5037 const(char)* p;
5038 Dsymbol s;
5039 exp.f = null;
235d5a96 5040 if (auto fe = exp.e1.isFuncExp())
5fee5ec3
IB
5041 {
5042 // function literal that direct called is always inferred.
235d5a96
IB
5043 assert(fe.fd);
5044 exp.f = fe.fd;
5fee5ec3
IB
5045 tf = cast(TypeFunction)exp.f.type;
5046 p = "function literal";
5047 }
5048 else if (t1.ty == Tdelegate)
5049 {
5050 TypeDelegate td = cast(TypeDelegate)t1;
5051 assert(td.next.ty == Tfunction);
5052 tf = cast(TypeFunction)td.next;
5053 p = "delegate";
5054 }
5055 else if (auto tfx = t1.isPtrToFunction())
5056 {
5057 tf = tfx;
5058 p = "function pointer";
5059 }
9c7d5e88 5060 else if (exp.e1.op == EXP.dotVariable && (cast(DotVarExp)exp.e1).var.isOverDeclaration())
5fee5ec3
IB
5061 {
5062 DotVarExp dve = cast(DotVarExp)exp.e1;
8da8c7d3 5063 exp.f = resolveFuncCall(exp.loc, sc, dve.var, tiargs, dve.e1.type, exp.argumentList, FuncResolveFlag.overloadOnly);
5fee5ec3
IB
5064 if (!exp.f)
5065 return setError();
5066 if (exp.f.needThis())
5067 {
5068 dve.var = exp.f;
5069 dve.type = exp.f.type;
5070 dve.hasOverloads = false;
5071 goto Lagain;
5072 }
5073 exp.e1 = new VarExp(dve.loc, exp.f, false);
5074 Expression e = new CommaExp(exp.loc, dve.e1, exp);
5075 result = e.expressionSemantic(sc);
5076 return;
5077 }
9c7d5e88 5078 else if (exp.e1.op == EXP.variable && (cast(VarExp)exp.e1).var.isOverDeclaration())
5fee5ec3
IB
5079 {
5080 s = (cast(VarExp)exp.e1).var;
5081 goto L2;
5082 }
9c7d5e88 5083 else if (exp.e1.op == EXP.template_)
5fee5ec3
IB
5084 {
5085 s = (cast(TemplateExp)exp.e1).td;
5086 L2:
8da8c7d3 5087 exp.f = resolveFuncCall(exp.loc, sc, s, tiargs, null, exp.argumentList, FuncResolveFlag.standard);
5fee5ec3
IB
5088 if (!exp.f || exp.f.errors)
5089 return setError();
5090 if (exp.f.needThis())
5091 {
5092 if (hasThis(sc))
5093 {
5094 // Supply an implicit 'this', as in
5095 // this.ident
5096 exp.e1 = new DotVarExp(exp.loc, (new ThisExp(exp.loc)).expressionSemantic(sc), exp.f, false);
5097 goto Lagain;
5098 }
5099 else if (isNeedThisScope(sc, exp.f))
5100 {
5101 exp.error("need `this` for `%s` of type `%s`", exp.f.toChars(), exp.f.type.toChars());
5102 return setError();
5103 }
5104 }
5105 exp.e1 = new VarExp(exp.e1.loc, exp.f, false);
5106 goto Lagain;
5107 }
5108 else
5109 {
5110 exp.error("function expected before `()`, not `%s` of type `%s`", exp.e1.toChars(), exp.e1.type.toChars());
5111 return setError();
5112 }
5113
5114 const(char)* failMessage;
8da8c7d3 5115 if (!tf.callMatch(null, exp.argumentList, 0, &failMessage, sc))
5fee5ec3
IB
5116 {
5117 OutBuffer buf;
5118 buf.writeByte('(');
5119 argExpTypesToCBuffer(&buf, exp.arguments);
5120 buf.writeByte(')');
5121 if (tthis)
5122 tthis.modToBuffer(&buf);
5123
5124 //printf("tf = %s, args = %s\n", tf.deco, (*arguments)[0].type.deco);
5125 .error(exp.loc, "%s `%s%s` is not callable using argument types `%s`",
5126 p, exp.e1.toChars(), parametersTypeToChars(tf.parameterList), buf.peekChars());
5127 if (failMessage)
5128 errorSupplemental(exp.loc, "%s", failMessage);
5129 return setError();
5130 }
5131 // Purity and safety check should run after testing arguments matching
5132 if (exp.f)
5133 {
5134 exp.checkPurity(sc, exp.f);
5135 exp.checkSafety(sc, exp.f);
5136 exp.checkNogc(sc, exp.f);
5137 if (exp.f.checkNestedReference(sc, exp.loc))
5138 return setError();
5139 }
5140 else if (sc.func && sc.intypeof != 1 && !(sc.flags & (SCOPE.ctfe | SCOPE.debug_)))
5141 {
5142 bool err = false;
5143 if (!tf.purity && sc.func.setImpure())
5144 {
5145 exp.error("`pure` %s `%s` cannot call impure %s `%s`",
5146 sc.func.kind(), sc.func.toPrettyChars(), p, exp.e1.toChars());
5147 err = true;
5148 }
5149 if (!tf.isnogc && sc.func.setGC())
5150 {
5151 exp.error("`@nogc` %s `%s` cannot call non-@nogc %s `%s`",
5152 sc.func.kind(), sc.func.toPrettyChars(), p, exp.e1.toChars());
5153 err = true;
5154 }
b6df1132
IB
5155 if (tf.trust <= TRUST.system && sc.setUnsafe(true, exp.loc,
5156 "`@safe` function `%s` cannot call `@system` `%s`", sc.func, exp.e1))
5fee5ec3
IB
5157 {
5158 exp.error("`@safe` %s `%s` cannot call `@system` %s `%s`",
5159 sc.func.kind(), sc.func.toPrettyChars(), p, exp.e1.toChars());
5160 err = true;
5161 }
5162 if (err)
5163 return setError();
5164 }
5165
5166 if (t1.ty == Tpointer)
5167 {
5168 Expression e = new PtrExp(exp.loc, exp.e1);
5169 e.type = tf;
5170 exp.e1 = e;
5171 }
5172 t1 = tf;
5173 }
235d5a96 5174 else if (VarExp ve = exp.e1.isVarExp())
5fee5ec3
IB
5175 {
5176 // Do overload resolution
5fee5ec3
IB
5177 exp.f = ve.var.isFuncDeclaration();
5178 assert(exp.f);
5179 tiargs = null;
5180
5181 if (exp.f.overnext)
8da8c7d3 5182 exp.f = resolveFuncCall(exp.loc, sc, exp.f, tiargs, null, exp.argumentList, FuncResolveFlag.overloadOnly);
5fee5ec3
IB
5183 else
5184 {
5185 exp.f = exp.f.toAliasFunc();
5186 TypeFunction tf = cast(TypeFunction)exp.f.type;
5187 const(char)* failMessage;
8da8c7d3 5188 if (!tf.callMatch(null, exp.argumentList, 0, &failMessage, sc))
5fee5ec3
IB
5189 {
5190 OutBuffer buf;
5191 buf.writeByte('(');
5192 argExpTypesToCBuffer(&buf, exp.arguments);
5193 buf.writeByte(')');
5194
5195 //printf("tf = %s, args = %s\n", tf.deco, (*arguments)[0].type.deco);
5196 .error(exp.loc, "%s `%s%s` is not callable using argument types `%s`",
5197 exp.f.kind(), exp.f.toPrettyChars(), parametersTypeToChars(tf.parameterList), buf.peekChars());
5198 if (failMessage)
5199 errorSupplemental(exp.loc, "%s", failMessage);
5200 exp.f = null;
5201 }
5202 }
5203 if (!exp.f || exp.f.errors)
5204 return setError();
5205
5206 if (exp.f.needThis())
5207 {
5208 // Change the ancestor lambdas to delegate before hasThis(sc) call.
5209 if (exp.f.checkNestedReference(sc, exp.loc))
5210 return setError();
5211
5212 if (hasThis(sc))
5213 {
5214 // Supply an implicit 'this', as in
5215 // this.ident
5216 exp.e1 = new DotVarExp(exp.loc, (new ThisExp(exp.loc)).expressionSemantic(sc), ve.var);
5217 // Note: we cannot use f directly, because further overload resolution
5218 // through the supplied 'this' may cause different result.
5219 goto Lagain;
5220 }
5221 else if (isNeedThisScope(sc, exp.f))
5222 {
5223 // At this point it is possible that `exp.f` had an ambiguity error that was
5224 // silenced because the previous call to `resolveFuncCall` was done using
5225 // `FuncResolveFlag.overloadOnly`. To make sure that a proper error message
5226 // is printed, redo the call with `FuncResolveFlag.standard`.
5227 //
5228 // https://issues.dlang.org/show_bug.cgi?id=22157
5229 if (exp.f.overnext)
8da8c7d3 5230 exp.f = resolveFuncCall(exp.loc, sc, exp.f, tiargs, null, exp.argumentList, FuncResolveFlag.standard);
5fee5ec3
IB
5231
5232 if (!exp.f || exp.f.errors)
5233 return setError();
5234
5235 // If no error is printed, it means that `f` is the single matching overload
5236 // and it needs `this`.
5237 exp.error("need `this` for `%s` of type `%s`", exp.f.toChars(), exp.f.type.toChars());
5238 return setError();
5239 }
5240 }
5241
5242 checkFunctionAttributes(exp, sc, exp.f);
5243 checkAccess(exp.loc, sc, null, exp.f);
5244 if (exp.f.checkNestedReference(sc, exp.loc))
5245 return setError();
5246
5247 ethis = null;
5248 tthis = null;
5249
5250 if (ve.hasOverloads)
5251 {
5252 exp.e1 = new VarExp(ve.loc, exp.f, false);
5253 exp.e1.type = exp.f.type;
5254 }
5255 t1 = exp.f.type;
5256 }
5257 assert(t1.ty == Tfunction);
5258
5259 Expression argprefix;
5260 if (!exp.arguments)
5261 exp.arguments = new Expressions();
8da8c7d3 5262 if (functionParameters(exp.loc, sc, cast(TypeFunction)t1, ethis, tthis, exp.argumentList, exp.f, &exp.type, &argprefix))
5fee5ec3
IB
5263 return setError();
5264
5265 if (!exp.type)
5266 {
5267 exp.e1 = e1org; // https://issues.dlang.org/show_bug.cgi?id=10922
5268 // avoid recursive expression printing
5269 exp.error("forward reference to inferred return type of function call `%s`", exp.toChars());
5270 return setError();
5271 }
5272
5273 if (exp.f && exp.f.tintro)
5274 {
5275 Type t = exp.type;
5276 int offset = 0;
5277 TypeFunction tf = cast(TypeFunction)exp.f.tintro;
5278 if (tf.next.isBaseOf(t, &offset) && offset)
5279 {
5280 exp.type = tf.next;
5281 result = Expression.combine(argprefix, exp.castTo(sc, t));
5282 return;
5283 }
5284 }
5285
5286 // Handle the case of a direct lambda call
5287 if (exp.f && exp.f.isFuncLiteralDeclaration() && sc.func && !sc.intypeof)
5288 {
5289 exp.f.tookAddressOf = 0;
5290 }
5291
5292 result = Expression.combine(argprefix, exp);
5293
5294 if (isSuper)
5295 {
5296 auto ad = sc.func ? sc.func.isThis() : null;
5297 auto cd = ad ? ad.isClassDeclaration() : null;
5298 if (cd && cd.classKind == ClassKind.cpp && exp.f && !exp.f.fbody)
5299 {
5300 // if super is defined in C++, it sets the vtable pointer to the base class
5301 // so we have to restore it, but still return 'this' from super() call:
5302 // (auto __vptrTmp = this.__vptr, auto __superTmp = super()), (this.__vptr = __vptrTmp, __superTmp)
5303 Loc loc = exp.loc;
5304
5305 auto vptr = new DotIdExp(loc, new ThisExp(loc), Id.__vptr);
5306 auto vptrTmpDecl = copyToTemp(0, "__vptrTmp", vptr);
5307 auto declareVptrTmp = new DeclarationExp(loc, vptrTmpDecl);
5308
5309 auto superTmpDecl = copyToTemp(0, "__superTmp", result);
5310 auto declareSuperTmp = new DeclarationExp(loc, superTmpDecl);
5311
5312 auto declareTmps = new CommaExp(loc, declareVptrTmp, declareSuperTmp);
5313
5314 auto restoreVptr = new AssignExp(loc, vptr.syntaxCopy(), new VarExp(loc, vptrTmpDecl));
5315
5316 Expression e = new CommaExp(loc, declareTmps, new CommaExp(loc, restoreVptr, new VarExp(loc, superTmpDecl)));
5317 result = e.expressionSemantic(sc);
5318 }
5319 }
5320
5321 // declare dual-context container
235d5a96 5322 if (exp.f && exp.f.hasDualContext() && !sc.intypeof && sc.func)
5fee5ec3
IB
5323 {
5324 // check access to second `this`
5325 if (AggregateDeclaration ad2 = exp.f.isMember2())
5326 {
5327 Expression te = new ThisExp(exp.loc).expressionSemantic(sc);
9c7d5e88 5328 if (te.op != EXP.error)
5fee5ec3 5329 te = getRightThis(exp.loc, sc, ad2, te, exp.f);
9c7d5e88 5330 if (te.op == EXP.error)
5fee5ec3
IB
5331 {
5332 exp.error("need `this` of type `%s` to call function `%s`", ad2.toChars(), exp.f.toChars());
5333 return setError();
5334 }
5335 }
5336 exp.vthis2 = makeThis2Argument(exp.loc, sc, exp.f);
5337 Expression de = new DeclarationExp(exp.loc, exp.vthis2);
5338 result = Expression.combine(de, result);
5339 result = result.expressionSemantic(sc);
5340 }
5341 }
5342
5343 override void visit(DeclarationExp e)
5344 {
5345 if (e.type)
5346 {
5347 result = e;
5348 return;
5349 }
5350 static if (LOGSEMANTIC)
5351 {
5352 printf("DeclarationExp::semantic() %s\n", e.toChars());
5353 }
5354
5355 uint olderrors = global.errors;
5356
5357 /* This is here to support extern(linkage) declaration,
5358 * where the extern(linkage) winds up being an AttribDeclaration
5359 * wrapper.
5360 */
5361 Dsymbol s = e.declaration;
5362
5363 while (1)
5364 {
5365 AttribDeclaration ad = s.isAttribDeclaration();
5366 if (ad)
5367 {
6d799f0a 5368 if (ad.decl && ad.decl.length == 1)
5fee5ec3
IB
5369 {
5370 s = (*ad.decl)[0];
5371 continue;
5372 }
5373 }
5374 break;
5375 }
5376
5fee5ec3
IB
5377 //printf("inserting '%s' %p into sc = %p\n", s.toChars(), s, sc);
5378 // Insert into both local scope and function scope.
5379 // Must be unique in both.
5380 if (s.ident)
5381 {
6384eff5 5382 VarDeclaration v = s.isVarDeclaration();
d91cb205 5383 if (v)
6384eff5 5384 {
d91cb205
IB
5385 if (sc.flags & SCOPE.Cfile)
5386 {
5387 /* Do semantic() on the type before inserting v into the symbol table
5388 */
5389 if (!v.originalType)
5390 v.originalType = v.type.syntaxCopy();
5391 Scope* sc2 = sc.push();
5392 sc2.stc |= v.storage_class & STC.FUNCATTR;
5393 sc2.linkage = LINK.c; // account for the extern(C) in front of the declaration
5394 v.inuse++;
5395 v.type = v.type.typeSemantic(v.loc, sc2);
5396 v.inuse--;
5397 sc2.pop();
5398 }
5399 else
5400 {
5401 /* Do semantic() on initializer first so this will be illegal:
5402 * int a = a;
5403 */
5404 e.declaration.dsymbolSemantic(sc);
5405 s.parent = sc.parent;
5406 }
6384eff5
IB
5407 }
5408
5fee5ec3
IB
5409 if (!sc.insert(s))
5410 {
5411 auto conflict = sc.search(Loc.initial, s.ident, null);
5412 e.error("declaration `%s` is already defined", s.toPrettyChars());
5413 errorSupplemental(conflict.loc, "`%s` `%s` is defined here",
5414 conflict.kind(), conflict.toChars());
5415 return setError();
5416 }
6384eff5
IB
5417
5418 if (v && (sc.flags & SCOPE.Cfile))
5419 {
5420 /* Do semantic() on initializer last so this will be legal:
5421 * int a = a;
5422 */
5423 e.declaration.dsymbolSemantic(sc);
5424 s.parent = sc.parent;
5425 }
5426
5427 if (sc.func)
5fee5ec3
IB
5428 {
5429 // https://issues.dlang.org/show_bug.cgi?id=11720
5430 if ((s.isFuncDeclaration() ||
5431 s.isAggregateDeclaration() ||
5432 s.isEnumDeclaration() ||
5433 s.isTemplateDeclaration() ||
5434 v
5435 ) && !sc.func.localsymtab.insert(s))
5436 {
5437 // Get the previous symbol
5438 Dsymbol originalSymbol = sc.func.localsymtab.lookup(s.ident);
5439
5440 // Perturb the name mangling so that the symbols can co-exist
5441 // instead of colliding
5442 s.localNum = cast(ushort)(originalSymbol.localNum + 1);
6384eff5
IB
5443 // 65535 should be enough for anyone
5444 if (!s.localNum)
5445 {
5446 e.error("more than 65535 symbols with name `%s` generated", s.ident.toChars());
5447 return setError();
5448 }
5fee5ec3
IB
5449
5450 // Replace originalSymbol with s, which updates the localCount
5451 sc.func.localsymtab.update(s);
5452
5453 // The mangling change only works for D mangling
5454 }
6384eff5 5455
7e287503 5456 if (!(sc.flags & SCOPE.Cfile))
5fee5ec3
IB
5457 {
5458 /* https://issues.dlang.org/show_bug.cgi?id=21272
5459 * If we are in a foreach body we need to extract the
5460 * function containing the foreach
5461 */
5462 FuncDeclaration fes_enclosing_func;
5463 if (sc.func && sc.func.fes)
5464 fes_enclosing_func = sc.enclosing.enclosing.func;
5465
5466 // Disallow shadowing
5467 for (Scope* scx = sc.enclosing; scx && (scx.func == sc.func || (fes_enclosing_func && scx.func == fes_enclosing_func)); scx = scx.enclosing)
5468 {
5469 Dsymbol s2;
5470 if (scx.scopesym && scx.scopesym.symtab && (s2 = scx.scopesym.symtab.lookup(s.ident)) !is null && s != s2)
5471 {
5472 // allow STC.local symbols to be shadowed
5473 // TODO: not really an optimal design
5474 auto decl = s2.isDeclaration();
5475 if (!decl || !(decl.storage_class & STC.local))
5476 {
5477 if (sc.func.fes)
5478 {
5479 e.deprecation("%s `%s` is shadowing %s `%s`. Rename the `foreach` variable.", s.kind(), s.ident.toChars(), s2.kind(), s2.toPrettyChars());
5480 }
5481 else
5482 {
5483 e.error("%s `%s` is shadowing %s `%s`", s.kind(), s.ident.toChars(), s2.kind(), s2.toPrettyChars());
5484 return setError();
5485 }
5486 }
5487 }
5488 }
5489 }
5490 }
5491 }
5492 if (!s.isVarDeclaration())
5493 {
5494 Scope* sc2 = sc;
5495 if (sc2.stc & (STC.pure_ | STC.nothrow_ | STC.nogc))
5496 sc2 = sc.push();
5497 sc2.stc &= ~(STC.pure_ | STC.nothrow_ | STC.nogc);
5498 e.declaration.dsymbolSemantic(sc2);
5499 if (sc2 != sc)
5500 sc2.pop();
5501 s.parent = sc.parent;
5502 }
5503 if (global.errors == olderrors)
5504 {
5505 e.declaration.semantic2(sc);
5506 if (global.errors == olderrors)
5507 {
5508 e.declaration.semantic3(sc);
5509 }
5510 }
5511 // todo: error in declaration should be propagated.
5512
5513 e.type = Type.tvoid;
5514 result = e;
5515 }
5516
5517 override void visit(TypeidExp exp)
5518 {
5519 static if (LOGSEMANTIC)
5520 {
5521 printf("TypeidExp::semantic() %s\n", exp.toChars());
5522 }
5523 Type ta = isType(exp.obj);
5524 Expression ea = isExpression(exp.obj);
5525 Dsymbol sa = isDsymbol(exp.obj);
5526 //printf("ta %p ea %p sa %p\n", ta, ea, sa);
5527
5528 if (ta)
5529 {
5530 dmd.typesem.resolve(ta, exp.loc, sc, ea, ta, sa, true);
5531 }
5532
5533 if (ea)
5534 {
5535 if (auto sym = getDsymbol(ea))
5536 ea = symbolToExp(sym, exp.loc, sc, false);
5537 else
5538 ea = ea.expressionSemantic(sc);
5539 ea = resolveProperties(sc, ea);
5540 ta = ea.type;
9c7d5e88 5541 if (ea.op == EXP.type)
5fee5ec3
IB
5542 ea = null;
5543 }
5544
5545 if (!ta)
5546 {
5547 //printf("ta %p ea %p sa %p\n", ta, ea, sa);
5548 exp.error("no type for `typeid(%s)`", ea ? ea.toChars() : (sa ? sa.toChars() : ""));
5549 return setError();
5550 }
5551
1027dc45 5552 ta.checkComplexTransition(exp.loc, sc);
5fee5ec3
IB
5553
5554 Expression e;
5555 auto tb = ta.toBasetype();
5556 if (ea && tb.ty == Tclass)
5557 {
5558 if (tb.toDsymbol(sc).isClassDeclaration().classKind == ClassKind.cpp)
5559 {
5eb9927a 5560 error(exp.loc, "runtime type information is not supported for `extern(C++)` classes");
5fee5ec3
IB
5561 e = ErrorExp.get();
5562 }
5563 else if (!Type.typeinfoclass)
5564 {
5565 error(exp.loc, "`object.TypeInfo_Class` could not be found, but is implicitly used");
5566 e = ErrorExp.get();
5567 }
5568 else
5569 {
5570 /* Get the dynamic type, which is .classinfo
5571 */
5572 ea = ea.expressionSemantic(sc);
5573 e = new TypeidExp(ea.loc, ea);
5574 e.type = Type.typeinfoclass.type;
5575 }
5576 }
5577 else if (ta.ty == Terror)
5578 {
5579 e = ErrorExp.get();
5580 }
5581 else
5582 {
5583 // Handle this in the glue layer
5584 e = new TypeidExp(exp.loc, ta);
5fee5ec3 5585
8da8c7d3
IB
5586 bool genObjCode = true;
5587
5588 // https://issues.dlang.org/show_bug.cgi?id=23650
5589 // We generate object code for typeinfo, required
5590 // by typeid, only if in non-speculative context
5591 if (sc.flags & SCOPE.compile)
5592 {
5593 genObjCode = false;
5594 }
5595
5596 e.type = getTypeInfoType(exp.loc, ta, sc, genObjCode);
5fee5ec3
IB
5597 semanticTypeInfo(sc, ta);
5598
5599 if (ea)
5600 {
5601 e = new CommaExp(exp.loc, ea, e); // execute ea
5602 e = e.expressionSemantic(sc);
5603 }
5604 }
5605 result = e;
5606 }
5607
5608 override void visit(TraitsExp e)
5609 {
5610 result = semanticTraits(e, sc);
5611 }
5612
5613 override void visit(HaltExp e)
5614 {
5615 static if (LOGSEMANTIC)
5616 {
5617 printf("HaltExp::semantic()\n");
5618 }
5619 e.type = Type.tnoreturn;
5620 result = e;
5621 }
5622
5623 override void visit(IsExp e)
5624 {
5625 /* is(targ id tok tspec)
5626 * is(targ id : tok2)
5627 * is(targ id == tok2)
5628 */
5629 Type tded = null;
5630
5631 void yes()
5632 {
5633 //printf("yes\n");
5634 if (!e.id)
5635 {
5636 result = IntegerExp.createBool(true);
5637 return;
5638 }
5639
5640 Dsymbol s;
5641 Tuple tup = isTuple(tded);
5642 if (tup)
5643 s = new TupleDeclaration(e.loc, e.id, &tup.objects);
5644 else
5645 s = new AliasDeclaration(e.loc, e.id, tded);
5646 s.dsymbolSemantic(sc);
5647
5648 /* The reason for the !tup is unclear. It fails Phobos unittests if it is not there.
5649 * More investigation is needed.
5650 */
5651 if (!tup && !sc.insert(s))
5652 {
5653 auto conflict = sc.search(Loc.initial, s.ident, null);
5654 e.error("declaration `%s` is already defined", s.toPrettyChars());
5655 errorSupplemental(conflict.loc, "`%s` `%s` is defined here",
5656 conflict.kind(), conflict.toChars());
5657 }
5658
5659 unSpeculative(sc, s);
5660
5661 result = IntegerExp.createBool(true);
5662 }
5663 void no()
5664 {
5665 result = IntegerExp.createBool(false);
5666 //printf("no\n");
5667 }
5668
5669 static if (LOGSEMANTIC)
5670 {
5671 printf("IsExp::semantic(%s)\n", e.toChars());
5672 }
5673 if (e.id && !(sc.flags & SCOPE.condition))
5674 {
5675 e.error("can only declare type aliases within `static if` conditionals or `static assert`s");
5676 return setError();
5677 }
5678
5679 if (e.tok2 == TOK.package_ || e.tok2 == TOK.module_) // These is() expressions are special because they can work on modules, not just types.
5680 {
5681 const oldErrors = global.startGagging();
5682 Dsymbol sym = e.targ.toDsymbol(sc);
5683 global.endGagging(oldErrors);
5684
5685 if (sym is null)
5686 return no();
5687 Package p = resolveIsPackage(sym);
5688 if (p is null)
5689 return no();
5690 if (e.tok2 == TOK.package_ && p.isModule()) // Note that isModule() will return null for package modules because they're not actually instances of Module.
5691 return no();
5692 else if(e.tok2 == TOK.module_ && !(p.isModule() || p.isPackageMod()))
5693 return no();
5694 tded = e.targ;
5695 return yes();
5696 }
5697
5698 {
5699 Scope* sc2 = sc.copy(); // keep sc.flags
5700 sc2.tinst = null;
5701 sc2.minst = null;
5702 sc2.flags |= SCOPE.fullinst;
5703 Type t = e.targ.trySemantic(e.loc, sc2);
5704 sc2.pop();
5705 if (!t) // errors, so condition is false
5706 return no();
5707 e.targ = t;
5708 }
5709
5710 if (e.tok2 != TOK.reserved)
5711 {
5712 switch (e.tok2)
5713 {
5714 case TOK.struct_:
5715 if (e.targ.ty != Tstruct)
5716 return no();
5717 if ((cast(TypeStruct)e.targ).sym.isUnionDeclaration())
5718 return no();
5719 tded = e.targ;
5720 break;
5721
5722 case TOK.union_:
5723 if (e.targ.ty != Tstruct)
5724 return no();
5725 if (!(cast(TypeStruct)e.targ).sym.isUnionDeclaration())
5726 return no();
5727 tded = e.targ;
5728 break;
5729
5730 case TOK.class_:
5731 if (e.targ.ty != Tclass)
5732 return no();
5733 if ((cast(TypeClass)e.targ).sym.isInterfaceDeclaration())
5734 return no();
5735 tded = e.targ;
5736 break;
5737
5738 case TOK.interface_:
5739 if (e.targ.ty != Tclass)
5740 return no();
5741 if (!(cast(TypeClass)e.targ).sym.isInterfaceDeclaration())
5742 return no();
5743 tded = e.targ;
5744 break;
5745
5746 case TOK.const_:
5747 if (!e.targ.isConst())
5748 return no();
5749 tded = e.targ;
5750 break;
5751
5752 case TOK.immutable_:
5753 if (!e.targ.isImmutable())
5754 return no();
5755 tded = e.targ;
5756 break;
5757
5758 case TOK.shared_:
5759 if (!e.targ.isShared())
5760 return no();
5761 tded = e.targ;
5762 break;
5763
5764 case TOK.inout_:
5765 if (!e.targ.isWild())
5766 return no();
5767 tded = e.targ;
5768 break;
5769
5770 case TOK.super_:
5771 // If class or interface, get the base class and interfaces
5772 if (e.targ.ty != Tclass)
5773 return no();
5774 else
5775 {
5776 ClassDeclaration cd = (cast(TypeClass)e.targ).sym;
5777 auto args = new Parameters();
6d799f0a 5778 args.reserve(cd.baseclasses.length);
5fee5ec3
IB
5779 if (cd.semanticRun < PASS.semanticdone)
5780 cd.dsymbolSemantic(null);
6d799f0a 5781 for (size_t i = 0; i < cd.baseclasses.length; i++)
5fee5ec3
IB
5782 {
5783 BaseClass* b = (*cd.baseclasses)[i];
5784 args.push(new Parameter(STC.in_, b.type, null, null, null));
5785 }
5786 tded = new TypeTuple(args);
5787 }
5788 break;
5789
5790 case TOK.enum_:
5791 if (e.targ.ty != Tenum)
5792 return no();
5793 if (e.id)
5794 tded = (cast(TypeEnum)e.targ).sym.getMemtype(e.loc);
5795 else
5796 tded = e.targ;
5797
5798 if (tded.ty == Terror)
5799 return setError();
5800 break;
5801
5802 case TOK.delegate_:
5803 if (e.targ.ty != Tdelegate)
5804 return no();
5805 tded = (cast(TypeDelegate)e.targ).next; // the underlying function type
5806 break;
5807
5808 case TOK.function_:
5809 case TOK.parameters:
5810 {
5811 if (e.targ.ty != Tfunction)
5812 return no();
5813 tded = e.targ;
5814
5815 /* Generate tuple from function parameter types.
5816 */
5817 assert(tded.ty == Tfunction);
5818 auto tdedf = tded.isTypeFunction();
5819 auto args = new Parameters();
5820 foreach (i, arg; tdedf.parameterList)
5821 {
5822 assert(arg && arg.type);
5823 /* If one of the default arguments was an error,
5824 don't return an invalid tuple
5825 */
9c7d5e88 5826 if (e.tok2 == TOK.parameters && arg.defaultArg && arg.defaultArg.op == EXP.error)
5fee5ec3
IB
5827 return setError();
5828 args.push(new Parameter(arg.storageClass, arg.type, (e.tok2 == TOK.parameters) ? arg.ident : null, (e.tok2 == TOK.parameters) ? arg.defaultArg : null, arg.userAttribDecl));
5829 }
5830 tded = new TypeTuple(args);
5831 break;
5832 }
5833 case TOK.return_:
5834 /* Get the 'return type' for the function,
5835 * delegate, or pointer to function.
5836 */
5837 if (auto tf = e.targ.isFunction_Delegate_PtrToFunction())
5838 tded = tf.next;
5839 else
5840 return no();
5841 break;
5842
5843 case TOK.argumentTypes:
5844 /* Generate a type tuple of the equivalent types used to determine if a
5845 * function argument of this type can be passed in registers.
5846 * The results of this are highly platform dependent, and intended
5847 * primarly for use in implementing va_arg().
5848 */
5849 tded = target.toArgTypes(e.targ);
5850 if (!tded)
5851 return no();
5852 // not valid for a parameter
5853 break;
5854
5855 case TOK.vector:
5856 if (e.targ.ty != Tvector)
5857 return no();
5858 tded = (cast(TypeVector)e.targ).basetype;
5859 break;
5860
5861 default:
5862 assert(0);
5863 }
5864
5865 // https://issues.dlang.org/show_bug.cgi?id=18753
5866 if (tded)
5867 return yes();
5868 return no();
5869 }
6d799f0a 5870 else if (e.tspec && !e.id && !(e.parameters && e.parameters.length))
5fee5ec3
IB
5871 {
5872 /* Evaluate to true if targ matches tspec
5873 * is(targ == tspec)
5874 * is(targ : tspec)
5875 */
5876 e.tspec = e.tspec.typeSemantic(e.loc, sc);
5877 //printf("targ = %s, %s\n", e.targ.toChars(), e.targ.deco);
5878 //printf("tspec = %s, %s\n", e.tspec.toChars(), e.tspec.deco);
5879
5880 if (e.tok == TOK.colon)
5881 {
5882 // current scope is itself deprecated, or deprecations are not errors
5883 const bool deprecationAllowed = sc.isDeprecated
5884 || global.params.useDeprecated != DiagnosticReporting.error;
5885 const bool preventAliasThis = e.targ.hasDeprecatedAliasThis && !deprecationAllowed;
5886
5fee5ec3
IB
5887 if (preventAliasThis && e.targ.ty == Tstruct)
5888 {
5889 if ((cast(TypeStruct) e.targ).implicitConvToWithoutAliasThis(e.tspec))
5890 return yes();
5891 else
5892 return no();
5893 }
5894 else if (preventAliasThis && e.targ.ty == Tclass)
5895 {
5896 if ((cast(TypeClass) e.targ).implicitConvToWithoutAliasThis(e.tspec))
5897 return yes();
5898 else
5899 return no();
5900 }
5901 else if (e.targ.implicitConvTo(e.tspec))
5902 return yes();
5903 else
5904 return no();
5905 }
5906 else /* == */
5907 {
5908 if (e.targ.equals(e.tspec))
5909 return yes();
5910 else
5911 return no();
5912 }
5913 }
5914 else if (e.tspec)
5915 {
5916 /* Evaluate to true if targ matches tspec.
5917 * If true, declare id as an alias for the specialized type.
5918 * is(targ == tspec, tpl)
5919 * is(targ : tspec, tpl)
5920 * is(targ id == tspec)
5921 * is(targ id : tspec)
5922 * is(targ id == tspec, tpl)
5923 * is(targ id : tspec, tpl)
5924 */
5925 Identifier tid = e.id ? e.id : Identifier.generateId("__isexp_id");
5926 e.parameters.insert(0, new TemplateTypeParameter(e.loc, tid, null, null));
5927
6d799f0a 5928 Objects dedtypes = Objects(e.parameters.length);
5fee5ec3
IB
5929 dedtypes.zero();
5930
5931 MATCH m = deduceType(e.targ, sc, e.tspec, e.parameters, &dedtypes, null, 0, e.tok == TOK.equal);
f99303eb 5932
5fee5ec3
IB
5933 if (m == MATCH.nomatch || (m != MATCH.exact && e.tok == TOK.equal))
5934 {
5935 return no();
5936 }
5937 else
5938 {
5939 tded = cast(Type)dedtypes[0];
5940 if (!tded)
5941 tded = e.targ;
5942 Objects tiargs = Objects(1);
5943 tiargs[0] = e.targ;
5944
5945 /* Declare trailing parameters
5946 */
6d799f0a 5947 for (size_t i = 1; i < e.parameters.length; i++)
5fee5ec3
IB
5948 {
5949 TemplateParameter tp = (*e.parameters)[i];
5950 Declaration s = null;
5951
5952 m = tp.matchArg(e.loc, sc, &tiargs, i, e.parameters, &dedtypes, &s);
5953 if (m == MATCH.nomatch)
5954 return no();
5955 s.dsymbolSemantic(sc);
5956 if (!sc.insert(s))
5957 {
5958 auto conflict = sc.search(Loc.initial, s.ident, null);
5959 e.error("declaration `%s` is already defined", s.toPrettyChars());
5960 errorSupplemental(conflict.loc, "`%s` `%s` is defined here",
5961 conflict.kind(), conflict.toChars());
5962 }
5963
5964 unSpeculative(sc, s);
5965 }
5966 return yes();
5967 }
5968 }
5969 else if (e.id)
5970 {
5971 /* Declare id as an alias for type targ. Evaluate to true
5972 * is(targ id)
5973 */
5974 tded = e.targ;
5975 }
5976 return yes();
5977 }
5978
5979 override void visit(BinAssignExp exp)
5980 {
5981 if (exp.type)
5982 {
5983 result = exp;
5984 return;
5985 }
5986
5987 Expression e = exp.op_overload(sc);
5988 if (e)
5989 {
5990 result = e;
5991 return;
5992 }
5993
9c7d5e88 5994 if (exp.e1.op == EXP.arrayLength)
5fee5ec3
IB
5995 {
5996 // arr.length op= e2;
5997 e = rewriteOpAssign(exp);
5998 e = e.expressionSemantic(sc);
5999 result = e;
6000 return;
6001 }
9c7d5e88 6002 if (exp.e1.op == EXP.slice || exp.e1.type.ty == Tarray || exp.e1.type.ty == Tsarray)
5fee5ec3
IB
6003 {
6004 if (checkNonAssignmentArrayOp(exp.e1))
6005 return setError();
6006
9c7d5e88 6007 if (exp.e1.op == EXP.slice)
5fee5ec3
IB
6008 (cast(SliceExp)exp.e1).arrayop = true;
6009
6010 // T[] op= ...
6011 if (exp.e2.implicitConvTo(exp.e1.type.nextOf()))
6012 {
6013 // T[] op= T
6014 exp.e2 = exp.e2.castTo(sc, exp.e1.type.nextOf());
6015 }
6016 else if (Expression ex = typeCombine(exp, sc))
6017 {
6018 result = ex;
6019 return;
6020 }
6021 exp.type = exp.e1.type;
6022 result = arrayOp(exp, sc);
6023 return;
6024 }
6025
6026 exp.e1 = exp.e1.expressionSemantic(sc);
6027 exp.e1 = exp.e1.modifiableLvalue(sc, exp.e1);
6028 exp.e1 = exp.e1.optimize(WANTvalue, /*keepLvalue*/ true);
6029 exp.type = exp.e1.type;
6030
6031 if (auto ad = isAggregate(exp.e1.type))
6032 {
6033 if (const s = search_function(ad, Id.opOpAssign))
6034 {
6035 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());
6036 return setError();
6037 }
6038 }
6039 if (exp.e1.checkScalar() ||
6040 exp.e1.checkReadModifyWrite(exp.op, exp.e2) ||
6041 exp.e1.checkSharedAccess(sc))
6042 return setError();
6043
9c7d5e88
IB
6044 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);
6045 int bitwise = (exp.op == EXP.andAssign || exp.op == EXP.orAssign || exp.op == EXP.xorAssign);
6046 int shift = (exp.op == EXP.leftShiftAssign || exp.op == EXP.rightShiftAssign || exp.op == EXP.unsignedRightShiftAssign);
5fee5ec3
IB
6047
6048 if (bitwise && exp.type.toBasetype().ty == Tbool)
6049 exp.e2 = exp.e2.implicitCastTo(sc, exp.type);
6050 else if (exp.checkNoBool())
6051 return setError();
6052
9c7d5e88 6053 if ((exp.op == EXP.addAssign || exp.op == EXP.minAssign) && exp.e1.type.toBasetype().ty == Tpointer && exp.e2.type.toBasetype().isintegral())
5fee5ec3
IB
6054 {
6055 result = scaleFactor(exp, sc);
6056 return;
6057 }
6058
6059 if (Expression ex = typeCombine(exp, sc))
6060 {
6061 result = ex;
6062 return;
6063 }
6064
6065 if (arith && (exp.checkArithmeticBin() || exp.checkSharedAccessBin(sc)))
6066 return setError();
6067 if ((bitwise || shift) && (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc)))
6068 return setError();
6069
6070 if (shift)
6071 {
6072 if (exp.e2.type.toBasetype().ty != Tvector)
6073 exp.e2 = exp.e2.castTo(sc, Type.tshiftcnt);
6074 }
6075
6076 if (!target.isVectorOpSupported(exp.type.toBasetype(), exp.op, exp.e2.type.toBasetype()))
6077 {
6078 result = exp.incompatibleTypes();
6079 return;
6080 }
6081
9c7d5e88 6082 if (exp.e1.op == EXP.error || exp.e2.op == EXP.error)
5fee5ec3
IB
6083 return setError();
6084
6085 e = exp.checkOpAssignTypes(sc);
9c7d5e88 6086 if (e.op == EXP.error)
5fee5ec3
IB
6087 {
6088 result = e;
6089 return;
6090 }
6091
9c7d5e88 6092 assert(e.op == EXP.assign || e == exp);
5fee5ec3
IB
6093 result = (cast(BinExp)e).reorderSettingAAElem(sc);
6094 }
6095
6096 private Expression compileIt(MixinExp exp)
6097 {
6098 OutBuffer buf;
6099 if (expressionsToString(buf, sc, exp.exps))
6100 return null;
6101
6102 uint errors = global.errors;
6103 const len = buf.length;
6104 const str = buf.extractChars()[0 .. len];
8da8c7d3 6105 scope p = new Parser!ASTCodegen(exp.loc, sc._module, str, false, global.errorSink);
5fee5ec3
IB
6106 p.nextToken();
6107 //printf("p.loc.linnum = %d\n", p.loc.linnum);
6108
6109 Expression e = p.parseExpression();
6110 if (global.errors != errors)
6111 return null;
6112
6113 if (p.token.value != TOK.endOfFile)
6114 {
6115 exp.error("incomplete mixin expression `%s`", str.ptr);
6116 return null;
6117 }
6118 return e;
6119 }
6120
6121 override void visit(MixinExp exp)
6122 {
6123 /* https://dlang.org/spec/expression.html#mixin_expressions
6124 */
6125
6126 static if (LOGSEMANTIC)
6127 {
6128 printf("MixinExp::semantic('%s')\n", exp.toChars());
6129 }
6130
6131 auto e = compileIt(exp);
6132 if (!e)
6133 return setError();
6134 result = e.expressionSemantic(sc);
6135 }
6136
6137 override void visit(ImportExp e)
6138 {
6139 static if (LOGSEMANTIC)
6140 {
6141 printf("ImportExp::semantic('%s')\n", e.toChars());
6142 }
6143
6144 auto se = semanticString(sc, e.e1, "file name argument");
6145 if (!se)
6146 return setError();
6147 se = se.toUTF8(sc);
6148
d97f3bca 6149 auto namez = se.toStringz();
5fee5ec3
IB
6150 if (!global.filePath)
6151 {
d97f3bca 6152 e.error("need `-J` switch to import text file `%s`", namez.ptr);
5fee5ec3
IB
6153 return setError();
6154 }
6155
6156 /* Be wary of CWE-22: Improper Limitation of a Pathname to a Restricted Directory
6157 * ('Path Traversal') attacks.
c43b5909 6158 * https://cwe.mitre.org/data/definitions/22.html
5fee5ec3
IB
6159 */
6160
6161 if (FileName.absolute(namez))
6162 {
6163 e.error("absolute path is not allowed in import expression: `%s`", se.toChars());
6164 return setError();
6165 }
6166
6167 auto idxReserved = FileName.findReservedChar(namez);
6168 if (idxReserved != size_t.max)
6169 {
610d7898 6170 e.error("`%s` is not a valid filename on this platform", se.toChars());
5fee5ec3
IB
6171 e.errorSupplemental("Character `'%c'` is reserved and cannot be used", namez[idxReserved]);
6172 return setError();
6173 }
6174
6175 if (FileName.refersToParentDir(namez))
6176 {
6177 e.error("path refers to parent (`..`) directory: `%s`", se.toChars());
6178 return setError();
6179 }
6180
d97f3bca
IB
6181 auto resolvedNamez = FileName.searchPath(global.filePath, namez, false);
6182 if (!resolvedNamez)
5fee5ec3
IB
6183 {
6184 e.error("file `%s` cannot be found or not in a path specified with `-J`", se.toChars());
6185 e.errorSupplemental("Path(s) searched (as provided by `-J`):");
6186 foreach (idx, path; *global.filePath)
6187 {
6188 const attr = FileName.exists(path);
6189 const(char)* err = attr == 2 ? "" :
6190 (attr == 1 ? " (not a directory)" : " (path not found)");
c43b5909 6191 e.errorSupplemental("[%llu]: `%s`%s", cast(ulong)idx, path, err);
5fee5ec3
IB
6192 }
6193 return setError();
6194 }
6195
d97f3bca 6196 sc._module.contentImportedFiles.push(resolvedNamez.ptr);
5fee5ec3
IB
6197 if (global.params.verbose)
6198 {
6199 const slice = se.peekString();
d97f3bca 6200 message("file %.*s\t(%s)", cast(int)slice.length, slice.ptr, resolvedNamez.ptr);
5fee5ec3 6201 }
5eb9927a 6202 if (global.params.moduleDeps.buffer !is null)
5fee5ec3 6203 {
5eb9927a 6204 OutBuffer* ob = global.params.moduleDeps.buffer;
5fee5ec3
IB
6205 Module imod = sc._module;
6206
5eb9927a 6207 if (!global.params.moduleDeps.name)
5fee5ec3
IB
6208 ob.writestring("depsFile ");
6209 ob.writestring(imod.toPrettyChars());
6210 ob.writestring(" (");
6211 escapePath(ob, imod.srcfile.toChars());
6212 ob.writestring(") : ");
5eb9927a 6213 if (global.params.moduleDeps.name)
5fee5ec3
IB
6214 ob.writestring("string : ");
6215 ob.write(se.peekString());
6216 ob.writestring(" (");
d97f3bca 6217 escapePath(ob, resolvedNamez.ptr);
5fee5ec3
IB
6218 ob.writestring(")");
6219 ob.writenl();
6220 }
5eb9927a 6221 if (global.params.makeDeps.doOutput)
5fee5ec3 6222 {
d97f3bca 6223 global.params.makeDeps.files.push(resolvedNamez.ptr);
5fee5ec3
IB
6224 }
6225
6226 {
d97f3bca 6227 auto fileName = FileName(resolvedNamez);
235d5a96 6228 if (auto fmResult = global.fileManager.lookup(fileName))
5fee5ec3 6229 {
31350635 6230 se = new StringExp(e.loc, fmResult);
5fee5ec3
IB
6231 }
6232 else
6233 {
d97f3bca 6234 auto readResult = File.read(resolvedNamez);
0fb57034
IB
6235 if (!readResult.success)
6236 {
d97f3bca 6237 e.error("cannot read file `%s`", resolvedNamez.ptr);
0fb57034
IB
6238 return setError();
6239 }
6240 else
6241 {
6242 // take ownership of buffer (probably leaking)
6243 auto data = readResult.extractSlice();
6244 se = new StringExp(e.loc, data);
31350635 6245 global.fileManager.add(fileName, data);
0fb57034 6246 }
5fee5ec3
IB
6247 }
6248 }
6249 result = se.expressionSemantic(sc);
6250 }
6251
6252 override void visit(AssertExp exp)
6253 {
6254 // https://dlang.org/spec/expression.html#assert_expressions
6255 static if (LOGSEMANTIC)
6256 {
6257 printf("AssertExp::semantic('%s')\n", exp.toChars());
6258 }
6259
6260 const generateMsg = !exp.msg && global.params.checkAction == CHECKACTION.context && global.params.useAssert == CHECKENABLE.on;
6261 Expression temporariesPrefix;
6262
6263 if (generateMsg)
6264 // no message - use assert expression as msg
6265 {
6266 if (!verifyHookExist(exp.loc, *sc, Id._d_assert_fail, "generating assert messages"))
6267 return setError();
6268
6269 /*
6270 {
6271 auto a = e1, b = e2;
6272 assert(a == b, _d_assert_fail!"=="(a, b));
6273 }()
6274 */
6275
6276 /*
6277 Stores the result of an operand expression into a temporary
6278 if necessary, e.g. if it is an impure fuction call containing side
6279 effects as in https://issues.dlang.org/show_bug.cgi?id=20114
6280
6281 Params:
6282 op = an expression which may require a temporary (added to
6283 `temporariesPrefix`: `auto tmp = op`) and will be replaced
6284 by `tmp` if necessary
6285
6286 Returns: (possibly replaced) `op`
6287 */
6288 Expression maybePromoteToTmp(ref Expression op)
6289 {
6290 // https://issues.dlang.org/show_bug.cgi?id=20989
6291 // Flag that _d_assert_fail will never dereference `array.ptr` to avoid safety
6292 // errors for `assert(!array.ptr)` => `_d_assert_fail!"!"(array.ptr)`
6293 {
6294 auto die = op.isDotIdExp();
6295 if (die && die.ident == Id.ptr)
6296 die.noderef = true;
6297 }
6298
6299 op = op.expressionSemantic(sc);
6300 op = resolveProperties(sc, op);
6301
6302 // Detect assert's using static operator overloads (e.g. `"var" in environment`)
6303 if (auto te = op.isTypeExp())
6304 {
6305 // Replace the TypeExp with it's textual representation
6306 // Including "..." in the error message isn't quite right but
6307 // proper solutions require more drastic changes, e.g. directly
6308 // using miniFormat and combine instead of calling _d_assert_fail
6309 auto name = new StringExp(te.loc, te.toString());
6310 return name.expressionSemantic(sc);
6311 }
6312
6313 // Create a temporary for expressions with side effects
6314 // Defensively assume that function calls may have side effects even
6315 // though it's not detected by hasSideEffect (e.g. `debug puts("Hello")` )
6316 // Rewriting CallExp's also avoids some issues with the inliner/debug generation
6317 if (op.hasSideEffect(true))
6318 {
6319 // Don't create an invalid temporary for void-expressions
6320 // Further semantic will issue an appropriate error
6321 if (op.type.ty == Tvoid)
6322 return op;
6323
6324 // https://issues.dlang.org/show_bug.cgi?id=21590
6325 // Don't create unnecessary temporaries and detect `assert(a = b)`
6326 if (op.isAssignExp() || op.isBinAssignExp())
6327 {
6328 auto left = (cast(BinExp) op).e1;
6329
6330 // Find leftmost expression to handle other rewrites,
6331 // e.g. --(++a) => a += 1 -= 1
6332 while (left.isAssignExp() || left.isBinAssignExp())
6333 left = (cast(BinExp) left).e1;
6334
6335 // Only use the assignee if it's a variable and skip
6336 // other lvalues (e.g. ref's returned by functions)
6337 if (left.isVarExp())
6338 return left;
6339
6340 // Sanity check that `op` can be converted to boolean
6341 // But don't raise errors for assignments enclosed in another expression
6342 if (op is exp.e1)
6343 op.toBoolean(sc);
6344 }
6345
6346 // Tuples with side-effects already receive a temporary during semantic
6347 if (op.type.isTypeTuple())
6348 {
6349 auto te = op.isTupleExp();
6350 assert(te);
6351
6352 // Create a new tuple without the associated temporary
6353 auto res = new TupleExp(op.loc, te.exps);
6354 return res.expressionSemantic(sc);
6355 }
6356
6357 const stc = op.isLvalue() ? STC.ref_ : 0;
6358 auto tmp = copyToTemp(stc, "__assertOp", op);
6359 tmp.dsymbolSemantic(sc);
6360
6361 auto decl = new DeclarationExp(op.loc, tmp);
6362 temporariesPrefix = Expression.combine(temporariesPrefix, decl);
6363
6364 op = new VarExp(op.loc, tmp);
6365 op = op.expressionSemantic(sc);
6366 }
6367 return op;
6368 }
6369
6370 // if the assert condition is a mixin expression, try to compile it
6371 if (auto ce = exp.e1.isMixinExp())
6372 {
6373 if (auto e1 = compileIt(ce))
6374 exp.e1 = e1;
6375 }
6376
6377 Expressions* es;
6378 Objects* tiargs;
6379 Loc loc = exp.e1.loc;
6380
9c7d5e88 6381 const op = exp.e1.op;
5fee5ec3 6382 bool isEqualsCallExpression;
235d5a96 6383 if (const callExp = exp.e1.isCallExp())
5fee5ec3 6384 {
5fee5ec3
IB
6385 // https://issues.dlang.org/show_bug.cgi?id=20331
6386 // callExp.f may be null if the assert contains a call to
6387 // a function pointer or literal
6388 if (const callExpFunc = callExp.f)
6389 {
6390 const callExpIdent = callExpFunc.ident;
6391 isEqualsCallExpression = callExpIdent == Id.__equals ||
6392 callExpIdent == Id.eq;
6393 }
6394 }
9c7d5e88
IB
6395 if (op == EXP.equal || op == EXP.notEqual ||
6396 op == EXP.lessThan || op == EXP.greaterThan ||
6397 op == EXP.lessOrEqual || op == EXP.greaterOrEqual ||
6398 op == EXP.identity || op == EXP.notIdentity ||
6399 op == EXP.in_ ||
5fee5ec3
IB
6400 isEqualsCallExpression)
6401 {
6402 es = new Expressions(3);
6403 tiargs = new Objects(1);
6404
6405 if (isEqualsCallExpression)
6406 {
6407 auto callExp = cast(CallExp) exp.e1;
6408 auto args = callExp.arguments;
6409
6410 // structs with opEquals get rewritten to a DotVarExp:
6411 // a.opEquals(b)
6412 // https://issues.dlang.org/show_bug.cgi?id=20100
6413 if (args.length == 1)
6414 {
6415 auto dv = callExp.e1.isDotVarExp();
6416 assert(dv);
6417
6418 // runtime args
6419 (*es)[1] = maybePromoteToTmp(dv.e1);
6420 (*es)[2] = maybePromoteToTmp((*args)[0]);
6421 }
6422 else
6423 {
6424 // runtime args
6425 (*es)[1] = maybePromoteToTmp((*args)[0]);
6426 (*es)[2] = maybePromoteToTmp((*args)[1]);
6427 }
6428 }
6429 else
6430 {
6431 auto binExp = cast(EqualExp) exp.e1;
6432
6433 // runtime args
6434 (*es)[1] = maybePromoteToTmp(binExp.e1);
6435 (*es)[2] = maybePromoteToTmp(binExp.e2);
6436 }
6437
6438 // template args
9c7d5e88 6439 Expression comp = new StringExp(loc, isEqualsCallExpression ? "==" : EXPtoString(exp.e1.op));
5fee5ec3
IB
6440 comp = comp.expressionSemantic(sc);
6441 (*es)[0] = comp;
6442 (*tiargs)[0] = (*es)[1].type;
6443 }
6444
6445 // Format exp.e1 before any additional boolean conversion
6446 // Ignore &&/|| because "assert(...) failed" is more informative than "false != true"
9c7d5e88 6447 else if (op != EXP.andAnd && op != EXP.orOr)
5fee5ec3
IB
6448 {
6449 es = new Expressions(2);
6450 tiargs = new Objects(1);
6451
6452 if (auto ne = exp.e1.isNotExp())
6453 {
6454 // Fetch the (potential non-bool) expression and fold
6455 // (n) negations into (n % 2) negations, e.g. !!a => a
6456 for (bool neg = true; ; neg = !neg)
6457 {
6458 if (auto ne2 = ne.e1.isNotExp())
6459 ne = ne2;
6460 else
6461 {
6462 (*es)[0] = new StringExp(loc, neg ? "!" : "");
6463 (*es)[1] = maybePromoteToTmp(ne.e1);
6464 break;
6465 }
6466 }
6467 }
6468 else
6469 { // Simply format exp.e1
6470 (*es)[0] = new StringExp(loc, "");
6471 (*es)[1] = maybePromoteToTmp(exp.e1);
6472 }
6473
6474 (*tiargs)[0] = (*es)[1].type;
6475
6476 // Passing __ctfe to auto ref infers ref and aborts compilation:
6477 // "cannot modify compiler-generated variable __ctfe"
6478 auto ve = (*es)[1].isVarExp();
6479 if (ve && ve.var.ident == Id.ctfe)
6480 {
6481 exp.msg = new StringExp(loc, "assert(__ctfe) failed!");
6482 goto LSkip;
6483 }
6484 }
6485 else
6486 {
6487 OutBuffer buf;
6488 buf.printf("%s failed", exp.toChars());
6489 exp.msg = new StringExp(Loc.initial, buf.extractSlice());
6490 goto LSkip;
6491 }
6492
6493 Expression __assertFail = new IdentifierExp(exp.loc, Id.empty);
6494 auto assertFail = new DotIdExp(loc, __assertFail, Id.object);
6495
6496 auto dt = new DotTemplateInstanceExp(loc, assertFail, Id._d_assert_fail, tiargs);
6497 auto ec = CallExp.create(loc, dt, es);
6498 exp.msg = ec;
6499 }
6500
6501 LSkip:
6502 if (Expression ex = unaSemantic(exp, sc))
6503 {
6504 result = ex;
6505 return;
6506 }
6507
6508 exp.e1 = resolveProperties(sc, exp.e1);
6509 // BUG: see if we can do compile time elimination of the Assert
6510 exp.e1 = exp.e1.optimize(WANTvalue);
6511 exp.e1 = exp.e1.toBoolean(sc);
6512
9c7d5e88 6513 if (exp.e1.op == EXP.error)
5fee5ec3
IB
6514 {
6515 result = exp.e1;
6516 return;
6517 }
6518
6519 if (exp.msg)
6520 {
6521 exp.msg = expressionSemantic(exp.msg, sc);
6522 exp.msg = resolveProperties(sc, exp.msg);
6523 exp.msg = exp.msg.implicitCastTo(sc, Type.tchar.constOf().arrayOf());
6524 exp.msg = exp.msg.optimize(WANTvalue);
b7a586be 6525 checkParamArgumentEscape(sc, null, null, null, STC.undefined_, exp.msg, true, false);
5fee5ec3
IB
6526 }
6527
9c7d5e88 6528 if (exp.msg && exp.msg.op == EXP.error)
5fee5ec3
IB
6529 {
6530 result = exp.msg;
6531 return;
6532 }
6533
6534 auto f1 = checkNonAssignmentArrayOp(exp.e1);
6535 auto f2 = exp.msg && checkNonAssignmentArrayOp(exp.msg);
6536 if (f1 || f2)
6537 return setError();
6538
9c7d5e88 6539 if (exp.e1.toBool().hasValue(false))
5fee5ec3
IB
6540 {
6541 /* This is an `assert(0)` which means halt program execution
6542 */
6543 FuncDeclaration fd = sc.parent.isFuncDeclaration();
6544 if (fd)
6545 fd.hasReturnExp |= 4;
6546 sc.ctorflow.orCSX(CSX.halt);
6547
6548 if (global.params.useAssert == CHECKENABLE.off)
6549 {
6550 Expression e = new HaltExp(exp.loc);
6551 e = e.expressionSemantic(sc);
6552 result = e;
6553 return;
6554 }
0fb57034
IB
6555
6556 // Only override the type when it isn't already some flavour of noreturn,
6557 // e.g. when this assert was generated by defaultInitLiteral
6558 if (!exp.type || !exp.type.isTypeNoreturn())
6559 exp.type = Type.tnoreturn;
5fee5ec3
IB
6560 }
6561 else
6562 exp.type = Type.tvoid;
6563
6564 result = !temporariesPrefix
6565 ? exp
6566 : Expression.combine(temporariesPrefix, exp).expressionSemantic(sc);
6567 }
6568
d7569187
IB
6569 override void visit(ThrowExp te)
6570 {
6571 import dmd.statementsem;
6572
6573 if (StatementSemanticVisitor.throwSemantic(te.loc, te.e1, sc))
6574 result = te;
6575 else
6576 setError();
6577 }
6578
5fee5ec3
IB
6579 override void visit(DotIdExp exp)
6580 {
6581 static if (LOGSEMANTIC)
6582 {
6583 printf("DotIdExp::semantic(this = %p, '%s')\n", exp, exp.toChars());
31350635 6584 //printf("e1.op = %d, '%s'\n", e1.op, Token.toChars(e1.op));
5fee5ec3 6585 }
fd43568c
IB
6586
6587 if (sc.flags & SCOPE.Cfile)
6588 {
6589 /* See if need to rewrite the AST because of cast/call ambiguity
6590 */
6591 if (auto e = castCallAmbiguity(exp, sc))
6592 {
6593 result = expressionSemantic(e, sc);
6594 return;
6595 }
fd43568c 6596
6d799f0a
IB
6597 if (exp.arrow) // ImportC only
6598 exp.e1 = exp.e1.expressionSemantic(sc).arrayFuncConv(sc);
0fb57034 6599
0fb57034
IB
6600 if (exp.ident == Id.__xalignof && exp.e1.isTypeExp())
6601 {
6602 // C11 6.5.3 says _Alignof only applies to types
6603 Expression e;
6604 Type t;
6605 Dsymbol s;
6606 dmd.typesem.resolve(exp.e1.type, exp.e1.loc, sc, e, t, s, true);
6607 if (e)
6608 {
6609 exp.e1.error("argument to `_Alignof` must be a type");
6610 return setError();
6611 }
6612 else if (t)
6613 {
235d5a96
IB
6614 // Note similarity to getProperty() implementation of __xalignof
6615 const explicitAlignment = t.alignment();
6616 const naturalAlignment = t.alignsize();
6617 const actualAlignment = (explicitAlignment.isDefault() ? naturalAlignment : explicitAlignment.get());
6618 result = new IntegerExp(exp.loc, actualAlignment, Type.tsize_t);
0fb57034
IB
6619 }
6620 else if (s)
6621 {
6622 exp.e1.error("argument to `_Alignof` must be a type");
6623 return setError();
6624 }
6625 else
6626 assert(0);
6627 return;
6628 }
0fb57034 6629
6d799f0a
IB
6630 if (exp.ident != Id.__sizeof)
6631 {
6632 result = fieldLookup(exp.e1, sc, exp.ident);
6633 return;
6634 }
0fb57034
IB
6635 }
6636
f99303eb 6637 Expression e = exp.dotIdSemanticProp(sc, 1);
0fb57034 6638
5fee5ec3
IB
6639 if (e && isDotOpDispatch(e))
6640 {
0fb57034 6641 auto ode = e;
5fee5ec3
IB
6642 uint errors = global.startGagging();
6643 e = resolvePropertiesX(sc, e);
0fb57034
IB
6644 // Any error or if 'e' is not resolved, go to UFCS
6645 if (global.endGagging(errors) || e is ode)
5fee5ec3
IB
6646 e = null; /* fall down to UFCS */
6647 else
6648 {
6649 result = e;
6650 return;
6651 }
6652 }
6653 if (!e) // if failed to find the property
6654 {
6655 /* If ident is not a valid property, rewrite:
6656 * e1.ident
6657 * as:
6658 * .ident(e1)
6659 */
6660 e = resolveUFCSProperties(sc, exp);
6661 }
6662 result = e;
6663 }
6664
6665 override void visit(DotTemplateExp e)
6666 {
6667 if (e.type)
6668 {
6669 result = e;
6670 return;
6671 }
6672 if (Expression ex = unaSemantic(e, sc))
6673 {
6674 result = ex;
6675 return;
6676 }
6677 // 'void' like TemplateExp
6678 e.type = Type.tvoid;
6679 result = e;
6680 }
6681
6682 override void visit(DotVarExp exp)
6683 {
6684 static if (LOGSEMANTIC)
6685 {
6686 printf("DotVarExp::semantic('%s')\n", exp.toChars());
6687 }
6688 if (exp.type)
6689 {
6690 result = exp;
6691 return;
6692 }
6693
6694 exp.var = exp.var.toAlias().isDeclaration();
6695
6696 exp.e1 = exp.e1.expressionSemantic(sc);
6697
6698 if (auto tup = exp.var.isTupleDeclaration())
6699 {
6700 /* Replace:
6701 * e1.tuple(a, b, c)
6702 * with:
6703 * tuple(e1.a, e1.b, e1.c)
6704 */
6705 Expression e0;
6706 Expression ev = sc.func ? extractSideEffect(sc, "__tup", e0, exp.e1) : exp.e1;
6707
6708 auto exps = new Expressions();
6d799f0a
IB
6709 exps.reserve(tup.objects.length);
6710 for (size_t i = 0; i < tup.objects.length; i++)
5fee5ec3
IB
6711 {
6712 RootObject o = (*tup.objects)[i];
6713 Expression e;
6714 Declaration var;
610d7898 6715 switch (o.dyncast()) with (DYNCAST)
5fee5ec3 6716 {
610d7898 6717 case expression:
5fee5ec3
IB
6718 e = cast(Expression)o;
6719 if (auto se = e.isDsymbolExp())
6720 var = se.s.isDeclaration();
6721 else if (auto ve = e.isVarExp())
6722 if (!ve.var.isFuncDeclaration())
6723 // Exempt functions for backwards compatibility reasons.
6724 // See: https://issues.dlang.org/show_bug.cgi?id=20470#c1
6725 var = ve.var;
610d7898
IB
6726 break;
6727 case dsymbol:
5fee5ec3
IB
6728 Dsymbol s = cast(Dsymbol) o;
6729 Declaration d = s.isDeclaration();
6730 if (!d || d.isFuncDeclaration())
6731 // Exempt functions for backwards compatibility reasons.
6732 // See: https://issues.dlang.org/show_bug.cgi?id=20470#c1
6733 e = new DsymbolExp(exp.loc, s);
6734 else
6735 var = d;
610d7898
IB
6736 break;
6737 case type:
5fee5ec3 6738 e = new TypeExp(exp.loc, cast(Type)o);
610d7898
IB
6739 break;
6740 default:
5fee5ec3
IB
6741 exp.error("`%s` is not an expression", o.toChars());
6742 return setError();
6743 }
6744 if (var)
6745 e = new DotVarExp(exp.loc, ev, var);
6746 exps.push(e);
6747 }
6748
6749 Expression e = new TupleExp(exp.loc, e0, exps);
6750 e = e.expressionSemantic(sc);
6751 result = e;
6752 return;
6753 }
ec486b73
IB
6754 else if (auto ad = exp.var.isAliasDeclaration())
6755 {
6756 if (auto t = ad.getType())
6757 {
6758 result = new TypeExp(exp.loc, t).expressionSemantic(sc);
6759 return;
6760 }
6761 }
5fee5ec3
IB
6762
6763 exp.e1 = exp.e1.addDtorHook(sc);
6764
6765 Type t1 = exp.e1.type;
6766
6767 if (FuncDeclaration fd = exp.var.isFuncDeclaration())
6768 {
6769 // for functions, do checks after overload resolution
6770 if (!fd.functionSemantic())
6771 return setError();
6772
6773 /* https://issues.dlang.org/show_bug.cgi?id=13843
6774 * If fd obviously has no overloads, we should
6775 * normalize AST, and it will give a chance to wrap fd with FuncExp.
6776 */
6777 if ((fd.isNested() && !fd.isThis()) || fd.isFuncLiteralDeclaration())
6778 {
6779 // (e1, fd)
6780 auto e = symbolToExp(fd, exp.loc, sc, false);
6781 result = Expression.combine(exp.e1, e);
6782 return;
6783 }
6784
6785 exp.type = fd.type;
6786 assert(exp.type);
6787 }
6788 else if (OverDeclaration od = exp.var.isOverDeclaration())
6789 {
6790 exp.type = Type.tvoid; // ambiguous type?
6791 }
6792 else
6793 {
6794 exp.type = exp.var.type;
6795 if (!exp.type && global.errors) // var is goofed up, just return error.
6796 return setError();
6797 assert(exp.type);
6798
6799 if (t1.ty == Tpointer)
6800 t1 = t1.nextOf();
6801
6802 exp.type = exp.type.addMod(t1.mod);
6803
5eb9927a
IB
6804 // https://issues.dlang.org/show_bug.cgi?id=23109
6805 // Run semantic on the DotVarExp type
6806 if (auto handle = exp.type.isClassHandle())
6807 {
6808 if (handle.semanticRun < PASS.semanticdone && !handle.isBaseInfoComplete())
6809 handle.dsymbolSemantic(null);
6810 }
6811
5fee5ec3
IB
6812 Dsymbol vparent = exp.var.toParent();
6813 AggregateDeclaration ad = vparent ? vparent.isAggregateDeclaration() : null;
6814 if (Expression e1x = getRightThis(exp.loc, sc, ad, exp.e1, exp.var, 1))
6815 exp.e1 = e1x;
6816 else
6817 {
6818 /* Later checkRightThis will report correct error for invalid field variable access.
6819 */
6820 Expression e = new VarExp(exp.loc, exp.var);
6821 e = e.expressionSemantic(sc);
6822 result = e;
6823 return;
6824 }
6825 checkAccess(exp.loc, sc, exp.e1, exp.var);
6826
6827 VarDeclaration v = exp.var.isVarDeclaration();
6828 if (v && (v.isDataseg() || (v.storage_class & STC.manifest)))
6829 {
6830 Expression e = expandVar(WANTvalue, v);
6831 if (e)
6832 {
6833 result = e;
6834 return;
6835 }
6836 }
6837
6838 if (v && (v.isDataseg() || // fix https://issues.dlang.org/show_bug.cgi?id=8238
235d5a96 6839 (!v.needThis() && v.semanticRun > PASS.initial))) // fix https://issues.dlang.org/show_bug.cgi?id=17258
5fee5ec3
IB
6840 {
6841 // (e1, v)
6842 checkAccess(exp.loc, sc, exp.e1, v);
6843 Expression e = new VarExp(exp.loc, v);
6844 e = new CommaExp(exp.loc, exp.e1, e);
6845 e = e.expressionSemantic(sc);
6846 result = e;
6847 return;
6848 }
6849 }
6850 //printf("-DotVarExp::semantic('%s')\n", toChars());
6851 result = exp;
6852 }
6853
6854 override void visit(DotTemplateInstanceExp exp)
6855 {
6856 static if (LOGSEMANTIC)
6857 {
6858 printf("DotTemplateInstanceExp::semantic('%s')\n", exp.toChars());
6859 }
0fb57034
IB
6860 if (exp.type)
6861 {
6862 result = exp;
6863 return;
6864 }
5fee5ec3 6865 // Indicate we need to resolve by UFCS.
f99303eb 6866 Expression e = exp.dotTemplateSemanticProp(sc, 1);
5fee5ec3
IB
6867 if (!e)
6868 e = resolveUFCSProperties(sc, exp);
0fb57034
IB
6869 if (e is exp)
6870 e.type = Type.tvoid; // Unresolved type, because it needs inference
5fee5ec3
IB
6871 result = e;
6872 }
6873
6874 override void visit(DelegateExp e)
6875 {
6876 static if (LOGSEMANTIC)
6877 {
6878 printf("DelegateExp::semantic('%s')\n", e.toChars());
6879 }
6880 if (e.type)
6881 {
6882 result = e;
6883 return;
6884 }
6885
6886 e.e1 = e.e1.expressionSemantic(sc);
6887
6888 e.type = new TypeDelegate(e.func.type.isTypeFunction());
6889 e.type = e.type.typeSemantic(e.loc, sc);
6890
6891 FuncDeclaration f = e.func.toAliasFunc();
5eb9927a 6892 AggregateDeclaration ad = f.isMemberLocal();
5fee5ec3
IB
6893 if (f.needThis())
6894 e.e1 = getRightThis(e.loc, sc, ad, e.e1, f);
9c7d5e88 6895 if (e.e1.op == EXP.error)
5fee5ec3
IB
6896 return setError();
6897
5fee5ec3
IB
6898 if (f.type.ty == Tfunction)
6899 {
6900 TypeFunction tf = cast(TypeFunction)f.type;
6901 if (!MODmethodConv(e.e1.type.mod, f.type.mod))
6902 {
6903 OutBuffer thisBuf, funcBuf;
6904 MODMatchToBuffer(&thisBuf, e.e1.type.mod, tf.mod);
6905 MODMatchToBuffer(&funcBuf, tf.mod, e.e1.type.mod);
6906 e.error("%smethod `%s` is not callable using a %s`%s`",
6907 funcBuf.peekChars(), f.toPrettyChars(), thisBuf.peekChars(), e.e1.toChars());
6908 return setError();
6909 }
6910 }
6911 if (ad && ad.isClassDeclaration() && ad.type != e.e1.type)
6912 {
6913 // A downcast is required for interfaces
6914 // https://issues.dlang.org/show_bug.cgi?id=3706
6915 e.e1 = new CastExp(e.loc, e.e1, ad.type);
6916 e.e1 = e.e1.expressionSemantic(sc);
6917 }
6918 result = e;
6919 // declare dual-context container
235d5a96 6920 if (f.hasDualContext() && !sc.intypeof && sc.func)
5fee5ec3
IB
6921 {
6922 // check access to second `this`
6923 if (AggregateDeclaration ad2 = f.isMember2())
6924 {
6925 Expression te = new ThisExp(e.loc).expressionSemantic(sc);
9c7d5e88 6926 if (te.op != EXP.error)
5fee5ec3 6927 te = getRightThis(e.loc, sc, ad2, te, f);
9c7d5e88 6928 if (te.op == EXP.error)
5fee5ec3
IB
6929 {
6930 e.error("need `this` of type `%s` to make delegate from function `%s`", ad2.toChars(), f.toChars());
6931 return setError();
6932 }
6933 }
6934 VarDeclaration vthis2 = makeThis2Argument(e.loc, sc, f);
6935 e.vthis2 = vthis2;
6936 Expression de = new DeclarationExp(e.loc, vthis2);
6937 result = Expression.combine(de, result);
6938 result = result.expressionSemantic(sc);
6939 }
6940 }
6941
6942 override void visit(DotTypeExp exp)
6943 {
6944 static if (LOGSEMANTIC)
6945 {
6946 printf("DotTypeExp::semantic('%s')\n", exp.toChars());
6947 }
6948 if (exp.type)
6949 {
6950 result = exp;
6951 return;
6952 }
6953
6954 if (auto e = unaSemantic(exp, sc))
6955 {
6956 result = e;
6957 return;
6958 }
6959
6960 exp.type = exp.sym.getType().addMod(exp.e1.type.mod);
6961 result = exp;
6962 }
6963
6964 override void visit(AddrExp exp)
6965 {
6966 static if (LOGSEMANTIC)
6967 {
6968 printf("AddrExp::semantic('%s')\n", exp.toChars());
6969 }
6970 if (exp.type)
6971 {
6972 result = exp;
6973 return;
6974 }
6975
6976 if (Expression ex = unaSemantic(exp, sc))
6977 {
6978 result = ex;
6979 return;
6980 }
6981
6982 if (sc.flags & SCOPE.Cfile)
6983 {
5eb9927a
IB
6984 /* Special handling for &"string"/&(T[]){0, 1}
6985 * since C regards string/array literals as lvalues
5fee5ec3 6986 */
5eb9927a
IB
6987 auto e = exp.e1;
6988 if(e.isStringExp() || e.isArrayLiteralExp())
5fee5ec3 6989 {
5eb9927a
IB
6990 e.type = typeSemantic(e.type, Loc.initial, sc);
6991 // if type is already a pointer exp is an illegal expression of the form `&(&"")`
6992 if (!e.type.isTypePointer())
5fee5ec3 6993 {
5eb9927a
IB
6994 e.type = e.type.pointerTo();
6995 result = e;
5fee5ec3
IB
6996 return;
6997 }
5eb9927a
IB
6998 else
6999 {
7000 // `toLvalue` call further below is upon exp.e1, omitting & from the error message
7001 exp.toLvalue(sc, null);
7002 return setError();
7003 }
5fee5ec3
IB
7004 }
7005 }
7006
9c7d5e88 7007 int wasCond = exp.e1.op == EXP.question;
5fee5ec3 7008
9c7d5e88 7009 if (exp.e1.op == EXP.dotTemplateInstance)
5fee5ec3
IB
7010 {
7011 DotTemplateInstanceExp dti = cast(DotTemplateInstanceExp)exp.e1;
7012 TemplateInstance ti = dti.ti;
7013 {
7014 //assert(ti.needsTypeInference(sc));
7015 ti.dsymbolSemantic(sc);
7016 if (!ti.inst || ti.errors) // if template failed to expand
7017 return setError();
7018
7019 Dsymbol s = ti.toAlias();
7020 FuncDeclaration f = s.isFuncDeclaration();
7021 if (f)
7022 {
7023 exp.e1 = new DotVarExp(exp.e1.loc, dti.e1, f);
7024 exp.e1 = exp.e1.expressionSemantic(sc);
7025 }
7026 }
7027 }
9c7d5e88 7028 else if (exp.e1.op == EXP.scope_)
5fee5ec3
IB
7029 {
7030 TemplateInstance ti = (cast(ScopeExp)exp.e1).sds.isTemplateInstance();
7031 if (ti)
7032 {
7033 //assert(ti.needsTypeInference(sc));
7034 ti.dsymbolSemantic(sc);
7035 if (!ti.inst || ti.errors) // if template failed to expand
7036 return setError();
7037
7038 Dsymbol s = ti.toAlias();
7039 FuncDeclaration f = s.isFuncDeclaration();
7040 if (f)
7041 {
7042 exp.e1 = new VarExp(exp.e1.loc, f);
7043 exp.e1 = exp.e1.expressionSemantic(sc);
7044 }
7045 }
7046 }
7047 /* https://issues.dlang.org/show_bug.cgi?id=809
7048 *
7049 * If the address of a lazy variable is taken,
7050 * the expression is rewritten so that the type
7051 * of it is the delegate type. This means that
7052 * the symbol is not going to represent a call
7053 * to the delegate anymore, but rather, the
7054 * actual symbol.
7055 */
7056 if (auto ve = exp.e1.isVarExp())
7057 {
7058 if (ve.var.storage_class & STC.lazy_)
7059 {
7060 exp.e1 = exp.e1.expressionSemantic(sc);
7061 exp.e1 = resolveProperties(sc, exp.e1);
7062 if (auto callExp = exp.e1.isCallExp())
7063 {
7064 if (callExp.e1.type.toBasetype().ty == Tdelegate)
7065 {
7066 /* https://issues.dlang.org/show_bug.cgi?id=20551
7067 *
7068 * Cannot take address of lazy parameter in @safe code
7069 * because it might end up being a pointer to undefined
7070 * memory.
7071 */
610d7898 7072 if (1)
5fee5ec3 7073 {
610d7898 7074 if (sc.setUnsafe(false, exp.loc,
5eb9927a
IB
7075 "cannot take address of lazy parameter `%s` in `@safe` function `%s`", ve, sc.func))
7076 {
7077 setError();
7078 return;
7079 }
5fee5ec3 7080 }
5eb9927a
IB
7081 VarExp ve2 = callExp.e1.isVarExp();
7082 ve2.delegateWasExtracted = true;
7083 ve2.var.storage_class |= STC.scope_;
7084 result = ve2;
5fee5ec3
IB
7085 return;
7086 }
7087 }
7088 }
7089 }
7090
7091 exp.e1 = exp.e1.toLvalue(sc, null);
9c7d5e88 7092 if (exp.e1.op == EXP.error)
5fee5ec3
IB
7093 {
7094 result = exp.e1;
7095 return;
7096 }
7097 if (checkNonAssignmentArrayOp(exp.e1))
7098 return setError();
7099
7100 if (!exp.e1.type)
7101 {
7102 exp.error("cannot take address of `%s`", exp.e1.toChars());
7103 return setError();
7104 }
d97f3bca
IB
7105 if (!checkAddressable(exp, sc))
7106 return setError();
5fee5ec3
IB
7107
7108 bool hasOverloads;
7109 if (auto f = isFuncAddress(exp, &hasOverloads))
7110 {
7111 if (!hasOverloads && f.checkForwardRef(exp.loc))
7112 return setError();
7113 }
7114 else if (!exp.e1.type.deco)
7115 {
6384eff5
IB
7116 // try to resolve the type
7117 exp.e1.type = exp.e1.type.typeSemantic(exp.e1.loc, null);
7118 if (!exp.e1.type.deco) // still couldn't resolve it
5fee5ec3 7119 {
6384eff5
IB
7120 if (auto ve = exp.e1.isVarExp())
7121 {
7122 Declaration d = ve.var;
7123 exp.error("forward reference to %s `%s`", d.kind(), d.toChars());
7124 }
7125 else
7126 exp.error("forward reference to type `%s` of expression `%s`", exp.e1.type.toChars(), exp.e1.toChars());
7127 return setError();
5fee5ec3 7128 }
5fee5ec3
IB
7129 }
7130
7131 exp.type = exp.e1.type.pointerTo();
7132
7133 // See if this should really be a delegate
9c7d5e88 7134 if (exp.e1.op == EXP.dotVariable)
5fee5ec3
IB
7135 {
7136 DotVarExp dve = cast(DotVarExp)exp.e1;
7137 FuncDeclaration f = dve.var.isFuncDeclaration();
7138 if (f)
7139 {
7140 f = f.toAliasFunc(); // FIXME, should see overloads
7141 // https://issues.dlang.org/show_bug.cgi?id=1983
7142 if (!dve.hasOverloads)
7143 f.tookAddressOf++;
7144
7145 Expression e;
7146 if (f.needThis())
7147 e = new DelegateExp(exp.loc, dve.e1, f, dve.hasOverloads);
7148 else // It is a function pointer. Convert &v.f() --> (v, &V.f())
7149 e = new CommaExp(exp.loc, dve.e1, new AddrExp(exp.loc, new VarExp(exp.loc, f, dve.hasOverloads)));
7150 e = e.expressionSemantic(sc);
7151 result = e;
7152 return;
7153 }
7154
7155 // Look for misaligned pointer in @safe mode
7156 if (checkUnsafeAccess(sc, dve, !exp.type.isMutable(), true))
7157 return setError();
5fee5ec3 7158 }
9c7d5e88 7159 else if (exp.e1.op == EXP.variable)
5fee5ec3
IB
7160 {
7161 VarExp ve = cast(VarExp)exp.e1;
7162 VarDeclaration v = ve.var.isVarDeclaration();
7163 if (v)
7164 {
7165 if (!checkAddressVar(sc, exp.e1, v))
7166 return setError();
7167
7168 ve.checkPurity(sc, v);
7169 }
7170 FuncDeclaration f = ve.var.isFuncDeclaration();
7171 if (f)
7172 {
7173 /* Because nested functions cannot be overloaded,
7174 * mark here that we took its address because castTo()
7175 * may not be called with an exact match.
ec486b73
IB
7176 *
7177 * https://issues.dlang.org/show_bug.cgi?id=19285 :
7178 * We also need to make sure we aren't inside a typeof. Ideally the compiler
7179 * would do typeof(...) semantic analysis speculatively then collect information
7180 * about what it used rather than relying on what are effectively semantically-global
7181 * variables but it doesn't.
5fee5ec3 7182 */
ec486b73
IB
7183 if (!sc.isFromSpeculativeSemanticContext() && (!ve.hasOverloads || (f.isNested() && !f.needThis())))
7184 {
7185 // TODO: Refactor to use a proper interface that can keep track of causes.
5fee5ec3 7186 f.tookAddressOf++;
ec486b73
IB
7187 }
7188
5fee5ec3
IB
7189 if (f.isNested() && !f.needThis())
7190 {
7191 if (f.isFuncLiteralDeclaration())
7192 {
7193 if (!f.FuncDeclaration.isNested())
7194 {
7195 /* Supply a 'null' for a this pointer if no this is available
7196 */
7197 Expression e = new DelegateExp(exp.loc, new NullExp(exp.loc, Type.tnull), f, ve.hasOverloads);
7198 e = e.expressionSemantic(sc);
7199 result = e;
7200 return;
7201 }
7202 }
7203 Expression e = new DelegateExp(exp.loc, exp.e1, f, ve.hasOverloads);
7204 e = e.expressionSemantic(sc);
7205 result = e;
7206 return;
7207 }
7208 if (f.needThis())
7209 {
7210 if (hasThis(sc))
7211 {
7212 /* Should probably supply 'this' after overload resolution,
7213 * not before.
7214 */
7215 Expression ethis = new ThisExp(exp.loc);
7216 Expression e = new DelegateExp(exp.loc, ethis, f, ve.hasOverloads);
7217 e = e.expressionSemantic(sc);
7218 result = e;
7219 return;
7220 }
5eb9927a 7221 if (sc.func && !sc.intypeof && !(sc.flags & SCOPE.debug_))
5fee5ec3 7222 {
610d7898 7223 sc.setUnsafe(false, exp.loc,
5eb9927a
IB
7224 "`this` reference necessary to take address of member `%s` in `@safe` function `%s`",
7225 f, sc.func);
5fee5ec3
IB
7226 }
7227 }
7228 }
7229 }
9c7d5e88 7230 else if (exp.e1.op == EXP.index)
5fee5ec3
IB
7231 {
7232 /* For:
7233 * int[3] a;
7234 * &a[i]
7235 * check 'a' the same as for a regular variable
7236 */
7237 if (VarDeclaration v = expToVariable(exp.e1))
7238 {
5fee5ec3
IB
7239 exp.e1.checkPurity(sc, v);
7240 }
7241 }
7242 else if (wasCond)
7243 {
7244 /* a ? b : c was transformed to *(a ? &b : &c), but we still
7245 * need to do safety checks
7246 */
9c7d5e88 7247 assert(exp.e1.op == EXP.star);
5fee5ec3 7248 PtrExp pe = cast(PtrExp)exp.e1;
9c7d5e88 7249 assert(pe.e1.op == EXP.question);
5fee5ec3 7250 CondExp ce = cast(CondExp)pe.e1;
9c7d5e88
IB
7251 assert(ce.e1.op == EXP.address);
7252 assert(ce.e2.op == EXP.address);
5fee5ec3
IB
7253
7254 // Re-run semantic on the address expressions only
7255 ce.e1.type = null;
7256 ce.e1 = ce.e1.expressionSemantic(sc);
7257 ce.e2.type = null;
7258 ce.e2 = ce.e2.expressionSemantic(sc);
7259 }
7260 result = exp.optimize(WANTvalue);
7261 }
7262
7263 override void visit(PtrExp exp)
7264 {
7265 static if (LOGSEMANTIC)
7266 {
7267 printf("PtrExp::semantic('%s')\n", exp.toChars());
7268 }
7269 if (exp.type)
7270 {
7271 result = exp;
7272 return;
7273 }
7274
7275 Expression e = exp.op_overload(sc);
7276 if (e)
7277 {
7278 result = e;
7279 return;
7280 }
7281
fbdaa581
IB
7282 exp.e1 = exp.e1.arrayFuncConv(sc);
7283
5fee5ec3
IB
7284 Type tb = exp.e1.type.toBasetype();
7285 switch (tb.ty)
7286 {
7287 case Tpointer:
7288 exp.type = (cast(TypePointer)tb).next;
7289 break;
7290
7291 case Tsarray:
7292 case Tarray:
7293 if (isNonAssignmentArrayOp(exp.e1))
7294 goto default;
7295 exp.error("using `*` on an array is no longer supported; use `*(%s).ptr` instead", exp.e1.toChars());
7296 exp.type = (cast(TypeArray)tb).next;
7297 exp.e1 = exp.e1.castTo(sc, exp.type.pointerTo());
7298 break;
7299
7300 case Terror:
7301 return setError();
7302
7303 case Tnull:
7304 exp.type = Type.tnoreturn; // typeof(*null) is bottom type
7305 break;
7306
7307 default:
7308 exp.error("can only `*` a pointer, not a `%s`", exp.e1.type.toChars());
7309 goto case Terror;
7310 }
7311
7312 if (exp.checkValue())
7313 return setError();
7314
7315 result = exp;
7316 }
7317
7318 override void visit(NegExp exp)
7319 {
7320 static if (LOGSEMANTIC)
7321 {
7322 printf("NegExp::semantic('%s')\n", exp.toChars());
7323 }
7324 if (exp.type)
7325 {
7326 result = exp;
7327 return;
7328 }
7329
7330 Expression e = exp.op_overload(sc);
7331 if (e)
7332 {
7333 result = e;
7334 return;
7335 }
7336
7337 fix16997(sc, exp);
7338 exp.type = exp.e1.type;
7339 Type tb = exp.type.toBasetype();
7340 if (tb.ty == Tarray || tb.ty == Tsarray)
7341 {
7342 if (!isArrayOpValid(exp.e1))
7343 {
7344 result = arrayOpInvalidError(exp);
7345 return;
7346 }
7347 result = exp;
7348 return;
7349 }
7350 if (!target.isVectorOpSupported(tb, exp.op))
7351 {
7352 result = exp.incompatibleTypes();
7353 return;
7354 }
7355 if (exp.e1.checkNoBool())
7356 return setError();
7357 if (exp.e1.checkArithmetic() ||
7358 exp.e1.checkSharedAccess(sc))
7359 return setError();
7360
7361 result = exp;
7362 }
7363
7364 override void visit(UAddExp exp)
7365 {
7366 static if (LOGSEMANTIC)
7367 {
7368 printf("UAddExp::semantic('%s')\n", exp.toChars());
7369 }
7370 assert(!exp.type);
7371
7372 Expression e = exp.op_overload(sc);
7373 if (e)
7374 {
7375 result = e;
7376 return;
7377 }
7378
7379 fix16997(sc, exp);
7380 if (!target.isVectorOpSupported(exp.e1.type.toBasetype(), exp.op))
7381 {
7382 result = exp.incompatibleTypes();
7383 return;
7384 }
7385 if (exp.e1.checkNoBool())
7386 return setError();
7387 if (exp.e1.checkArithmetic())
7388 return setError();
7389 if (exp.e1.checkSharedAccess(sc))
7390 return setError();
7391
7392 result = exp.e1;
7393 }
7394
7395 override void visit(ComExp exp)
7396 {
7397 if (exp.type)
7398 {
7399 result = exp;
7400 return;
7401 }
7402
7403 Expression e = exp.op_overload(sc);
7404 if (e)
7405 {
7406 result = e;
7407 return;
7408 }
7409
7410 fix16997(sc, exp);
7411 exp.type = exp.e1.type;
7412 Type tb = exp.type.toBasetype();
7413 if (tb.ty == Tarray || tb.ty == Tsarray)
7414 {
7415 if (!isArrayOpValid(exp.e1))
7416 {
7417 result = arrayOpInvalidError(exp);
7418 return;
7419 }
7420 result = exp;
7421 return;
7422 }
7423 if (!target.isVectorOpSupported(tb, exp.op))
7424 {
7425 result = exp.incompatibleTypes();
7426 return;
7427 }
7428 if (exp.e1.checkNoBool())
7429 return setError();
7430 if (exp.e1.checkIntegral() ||
7431 exp.e1.checkSharedAccess(sc))
7432 return setError();
7433
7434 result = exp;
7435 }
7436
7437 override void visit(NotExp e)
7438 {
7439 if (e.type)
7440 {
7441 result = e;
7442 return;
7443 }
7444
7445 e.setNoderefOperand();
7446
7447 // Note there is no operator overload
7448 if (Expression ex = unaSemantic(e, sc))
7449 {
7450 result = ex;
7451 return;
7452 }
7453
7454 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
9c7d5e88 7455 if (e.e1.op == EXP.type)
5fee5ec3
IB
7456 e.e1 = resolveAliasThis(sc, e.e1);
7457
7458 e.e1 = resolveProperties(sc, e.e1);
7459 e.e1 = e.e1.toBoolean(sc);
7460 if (e.e1.type == Type.terror)
7461 {
7462 result = e.e1;
7463 return;
7464 }
7465
7466 if (!target.isVectorOpSupported(e.e1.type.toBasetype(), e.op))
7467 {
7468 result = e.incompatibleTypes();
7469 }
7470 // https://issues.dlang.org/show_bug.cgi?id=13910
7471 // Today NotExp can take an array as its operand.
7472 if (checkNonAssignmentArrayOp(e.e1))
7473 return setError();
7474
235d5a96 7475 e.type = (sc && sc.flags & SCOPE.Cfile) ? Type.tint32 : Type.tbool;
5fee5ec3
IB
7476 result = e;
7477 }
7478
7479 override void visit(DeleteExp exp)
7480 {
6384eff5
IB
7481 // @@@DEPRECATED_2.109@@@
7482 // 1. Deprecated since 2.079
7483 // 2. Error since 2.099
7484 // 3. Removal of keyword, "delete" can be used for other identities
7485 if (!exp.isRAII)
5fee5ec3 7486 {
235d5a96
IB
7487 error(exp.loc, "the `delete` keyword is obsolete");
7488 errorSupplemental(exp.loc, "use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead");
6384eff5 7489 return setError();
5fee5ec3
IB
7490 }
7491
b3f58f87
IB
7492 Expression e = exp;
7493
5fee5ec3
IB
7494 if (Expression ex = unaSemantic(exp, sc))
7495 {
7496 result = ex;
7497 return;
7498 }
7499 exp.e1 = resolveProperties(sc, exp.e1);
7500 exp.e1 = exp.e1.modifiableLvalue(sc, null);
9c7d5e88 7501 if (exp.e1.op == EXP.error)
5fee5ec3
IB
7502 {
7503 result = exp.e1;
7504 return;
7505 }
7506 exp.type = Type.tvoid;
7507
5fee5ec3 7508 Type tb = exp.e1.type.toBasetype();
b3f58f87 7509
6384eff5
IB
7510 /* Now that `delete` in user code is an error, we only get here when
7511 * `isRAII` has been set to true for the deletion of a `scope class`. */
7512 if (tb.ty != Tclass)
7513 {
5fee5ec3
IB
7514 exp.error("cannot delete type `%s`", exp.e1.type.toChars());
7515 return setError();
7516 }
7517
6384eff5
IB
7518 ClassDeclaration cd = (cast(TypeClass)tb).sym;
7519 if (cd.isCOMinterface())
5fee5ec3 7520 {
6384eff5
IB
7521 /* Because COM classes are deleted by IUnknown.Release()
7522 */
7523 exp.error("cannot `delete` instance of COM interface `%s`", cd.toChars());
7524 return setError();
5fee5ec3
IB
7525 }
7526
6384eff5
IB
7527 bool err = false;
7528 if (cd.dtor)
5fee5ec3 7529 {
6384eff5
IB
7530 err |= !cd.dtor.functionSemantic();
7531 err |= exp.checkPurity(sc, cd.dtor);
7532 err |= exp.checkSafety(sc, cd.dtor);
7533 err |= exp.checkNogc(sc, cd.dtor);
5fee5ec3
IB
7534 }
7535 if (err)
7536 return setError();
7537
b3f58f87 7538 result = e;
5fee5ec3
IB
7539 }
7540
7541 override void visit(CastExp exp)
7542 {
7543 static if (LOGSEMANTIC)
7544 {
7545 printf("CastExp::semantic('%s')\n", exp.toChars());
7546 }
7547 //static int x; assert(++x < 10);
7548 if (exp.type)
7549 {
7550 result = exp;
7551 return;
7552 }
7553
7554 if ((sc && sc.flags & SCOPE.Cfile) &&
6384eff5 7555 exp.to && (exp.to.ty == Tident || exp.to.ty == Tsarray) &&
9c7d5e88
IB
7556 (exp.e1.op == EXP.address || exp.e1.op == EXP.star ||
7557 exp.e1.op == EXP.uadd || exp.e1.op == EXP.negate))
5fee5ec3
IB
7558 {
7559 /* Ambiguous cases arise from CParser if type-name is just an identifier.
7560 * ( identifier ) cast-expression
6384eff5 7561 * ( identifier [expression]) cast-expression
5fee5ec3
IB
7562 * If we determine that `identifier` is a variable, and cast-expression
7563 * is one of the unary operators (& * + -), then rewrite this cast
7564 * as a binary expression.
7565 */
7566 Loc loc = exp.loc;
7567 Type t;
7568 Expression e;
7569 Dsymbol s;
7570 exp.to.resolve(loc, sc, e, t, s);
7571 if (e !is null)
7572 {
7573 if (auto ex = exp.e1.isAddrExp()) // (ident) &exp -> (ident & exp)
7574 result = new AndExp(loc, e, ex.e1);
7575 else if (auto ex = exp.e1.isPtrExp()) // (ident) *exp -> (ident * exp)
7576 result = new MulExp(loc, e, ex.e1);
7577 else if (auto ex = exp.e1.isUAddExp()) // (ident) +exp -> (ident + exp)
7578 result = new AddExp(loc, e, ex.e1);
7579 else if (auto ex = exp.e1.isNegExp()) // (ident) -exp -> (ident - exp)
7580 result = new MinExp(loc, e, ex.e1);
7581
7582 assert(result);
7583 result = result.expressionSemantic(sc);
7584 return;
7585 }
7586 }
7587
7588 if (exp.to)
7589 {
7590 exp.to = exp.to.typeSemantic(exp.loc, sc);
7591 if (exp.to == Type.terror)
7592 return setError();
7593
7594 if (!exp.to.hasPointers())
7595 exp.setNoderefOperand();
7596
7597 // When e1 is a template lambda, this cast may instantiate it with
7598 // the type 'to'.
7599 exp.e1 = inferType(exp.e1, exp.to);
7600 }
7601
7602 if (auto e = unaSemantic(exp, sc))
7603 {
7604 result = e;
7605 return;
7606 }
7607
fbdaa581
IB
7608 if (exp.to && !exp.to.isTypeSArray() && !exp.to.isTypeFunction())
7609 exp.e1 = exp.e1.arrayFuncConv(sc);
7610
5fee5ec3 7611 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
9c7d5e88 7612 if (exp.e1.op == EXP.type)
5fee5ec3
IB
7613 exp.e1 = resolveAliasThis(sc, exp.e1);
7614
7615 auto e1x = resolveProperties(sc, exp.e1);
9c7d5e88 7616 if (e1x.op == EXP.error)
5fee5ec3
IB
7617 {
7618 result = e1x;
7619 return;
7620 }
7621 if (e1x.checkType())
7622 return setError();
7623 exp.e1 = e1x;
7624
7625 if (!exp.e1.type)
7626 {
7627 exp.error("cannot cast `%s`", exp.e1.toChars());
7628 return setError();
7629 }
7630
7631 // https://issues.dlang.org/show_bug.cgi?id=19954
7632 if (exp.e1.type.ty == Ttuple)
7633 {
d7569187
IB
7634 if (exp.to)
7635 {
7636 if (TypeTuple tt = exp.to.isTypeTuple())
7637 {
7638 if (exp.e1.type.implicitConvTo(tt))
7639 {
7640 result = exp.e1.castTo(sc, tt);
7641 return;
7642 }
7643 }
7644 }
5fee5ec3 7645 TupleExp te = exp.e1.isTupleExp();
6d799f0a 7646 if (te.exps.length == 1)
5fee5ec3
IB
7647 exp.e1 = (*te.exps)[0];
7648 }
7649
7650 // only allow S(x) rewrite if cast specified S explicitly.
7651 // See https://issues.dlang.org/show_bug.cgi?id=18545
7652 const bool allowImplicitConstruction = exp.to !is null;
7653
7654 if (!exp.to) // Handle cast(const) and cast(immutable), etc.
7655 {
7656 exp.to = exp.e1.type.castMod(exp.mod);
7657 exp.to = exp.to.typeSemantic(exp.loc, sc);
7658
7659 if (exp.to == Type.terror)
7660 return setError();
7661 }
7662
7663 if (exp.to.ty == Ttuple)
7664 {
d7569187 7665 exp.error("cannot cast `%s` of type `%s` to tuple type `%s`", exp.e1.toChars(), exp.e1.type.toChars(), exp.to.toChars());
5fee5ec3
IB
7666 return setError();
7667 }
7668
7669 // cast(void) is used to mark e1 as unused, so it is safe
7670 if (exp.to.ty == Tvoid)
7671 {
7672 exp.type = exp.to;
7673 result = exp;
7674 return;
7675 }
7676
7677 if (!exp.to.equals(exp.e1.type) && exp.mod == cast(ubyte)~0)
7678 {
7679 if (Expression e = exp.op_overload(sc))
7680 {
7681 result = e.implicitCastTo(sc, exp.to);
7682 return;
7683 }
7684 }
7685
7686 Type t1b = exp.e1.type.toBasetype();
7687 Type tob = exp.to.toBasetype();
7688
7689 if (allowImplicitConstruction && tob.ty == Tstruct && !tob.equals(t1b))
7690 {
7691 /* Look to replace:
7692 * cast(S)t
7693 * with:
7694 * S(t)
7695 */
7696
7697 // Rewrite as to.call(e1)
7698 Expression e = new TypeExp(exp.loc, exp.to);
7699 e = new CallExp(exp.loc, e, exp.e1);
7700 e = e.trySemantic(sc);
7701 if (e)
7702 {
7703 result = e;
7704 return;
7705 }
7706 }
7707
7708 if (!t1b.equals(tob) && (t1b.ty == Tarray || t1b.ty == Tsarray))
7709 {
7710 if (checkNonAssignmentArrayOp(exp.e1))
7711 return setError();
7712 }
7713
7714 // Look for casting to a vector type
7715 if (tob.ty == Tvector && t1b.ty != Tvector)
7716 {
7717 result = new VectorExp(exp.loc, exp.e1, exp.to);
7718 result = result.expressionSemantic(sc);
7719 return;
7720 }
7721
7722 Expression ex = exp.e1.castTo(sc, exp.to);
9c7d5e88 7723 if (ex.op == EXP.error)
5fee5ec3
IB
7724 {
7725 result = ex;
7726 return;
7727 }
7728
7729 // Check for unsafe casts
b6df1132 7730 if (!isSafeCast(ex, t1b, tob))
5fee5ec3 7731 {
b6df1132
IB
7732 if (sc.setUnsafe(false, exp.loc, "cast from `%s` to `%s` not allowed in safe code", exp.e1.type, exp.to))
7733 {
7734 return setError();
7735 }
5fee5ec3
IB
7736 }
7737
7738 // `object.__ArrayCast` is a rewrite of an old runtime hook `_d_arraycast`. `_d_arraycast` was not built
7739 // to handle certain casts. Those casts which `object.__ArrayCast` does not support are filtered out.
7740 // See `e2ir.toElemCast` for other types of casts. If `object.__ArrayCast` is improved to support more
7741 // casts these conditions and potentially some logic in `e2ir.toElemCast` can be removed.
7742 if (tob.ty == Tarray)
7743 {
7744 // https://issues.dlang.org/show_bug.cgi?id=19840
7745 if (auto ad = isAggregate(t1b))
7746 {
7747 if (ad.aliasthis)
7748 {
7749 Expression e = resolveAliasThis(sc, exp.e1);
7750 e = new CastExp(exp.loc, e, exp.to);
7751 result = e.expressionSemantic(sc);
7752 return;
7753 }
7754 }
7755
9c7d5e88 7756 if(t1b.ty == Tarray && exp.e1.op != EXP.arrayLiteral && (sc.flags & SCOPE.ctfe) == 0)
5fee5ec3
IB
7757 {
7758 auto tFrom = t1b.nextOf();
7759 auto tTo = tob.nextOf();
7760
7761 // https://issues.dlang.org/show_bug.cgi?id=20130
9c7d5e88 7762 if (exp.e1.op != EXP.string_ || !ex.isStringExp)
5fee5ec3
IB
7763 {
7764 const uint fromSize = cast(uint)tFrom.size();
7765 const uint toSize = cast(uint)tTo.size();
9c7d5e88
IB
7766 if (fromSize == SIZE_INVALID || toSize == SIZE_INVALID)
7767 return setError();
5fee5ec3
IB
7768
7769 // If array element sizes do not match, we must adjust the dimensions
7770 if (fromSize != toSize)
7771 {
7772 if (!verifyHookExist(exp.loc, *sc, Id.__ArrayCast, "casting array of structs"))
7773 return setError();
7774
7775 // A runtime check is needed in case arrays don't line up. That check should
7776 // be done in the implementation of `object.__ArrayCast`
7777 if (toSize == 0 || (fromSize % toSize) != 0)
7778 {
7779 // lower to `object.__ArrayCast!(TFrom, TTo)(from)`
7780
7781 // fully qualify as `object.__ArrayCast`
7782 Expression id = new IdentifierExp(exp.loc, Id.empty);
7783 auto dotid = new DotIdExp(exp.loc, id, Id.object);
7784
7785 auto tiargs = new Objects();
7786 tiargs.push(tFrom);
7787 tiargs.push(tTo);
7788 auto dt = new DotTemplateInstanceExp(exp.loc, dotid, Id.__ArrayCast, tiargs);
7789
7790 auto arguments = new Expressions();
7791 arguments.push(exp.e1);
7792 Expression ce = new CallExp(exp.loc, dt, arguments);
7793
7794 result = expressionSemantic(ce, sc);
7795 return;
7796 }
7797 }
7798 }
7799 }
7800 }
7801
7802 if (sc && sc.flags & SCOPE.Cfile)
7803 {
7804 /* C11 6.5.4-5: A cast does not yield an lvalue.
7805 * So ensure that castTo does not strip away the cast so that this
7806 * can be enforced in other semantic visitor methods.
7807 */
7808 if (!ex.isCastExp())
7809 {
7810 ex = new CastExp(exp.loc, ex, exp.to);
7811 ex.type = exp.to;
7812 }
7813 }
7814 result = ex;
7815 }
7816
7817 override void visit(VectorExp exp)
7818 {
7819 static if (LOGSEMANTIC)
7820 {
7821 printf("VectorExp::semantic('%s')\n", exp.toChars());
7822 }
7823 if (exp.type)
7824 {
7825 result = exp;
7826 return;
7827 }
7828
7829 exp.e1 = exp.e1.expressionSemantic(sc);
7830 exp.type = exp.to.typeSemantic(exp.loc, sc);
9c7d5e88 7831 if (exp.e1.op == EXP.error || exp.type.ty == Terror)
5fee5ec3
IB
7832 {
7833 result = exp.e1;
7834 return;
7835 }
7836
7837 Type tb = exp.type.toBasetype();
7838 assert(tb.ty == Tvector);
7839 TypeVector tv = cast(TypeVector)tb;
7840 Type te = tv.elementType();
7841 exp.dim = cast(int)(tv.size(exp.loc) / te.size(exp.loc));
7842
7843 bool checkElem(Expression elem)
7844 {
7845 if (elem.isConst() == 1)
7846 return false;
7847
7848 exp.error("constant expression expected, not `%s`", elem.toChars());
7849 return true;
7850 }
7851
7852 exp.e1 = exp.e1.optimize(WANTvalue);
7853 bool res;
9c7d5e88 7854 if (exp.e1.op == EXP.arrayLiteral)
5fee5ec3
IB
7855 {
7856 foreach (i; 0 .. exp.dim)
7857 {
7858 // Do not stop on first error - check all AST nodes even if error found
7859 res |= checkElem(exp.e1.isArrayLiteralExp()[i]);
7860 }
7861 }
7862 else if (exp.e1.type.ty == Tvoid)
7863 checkElem(exp.e1);
7864
7865 result = res ? ErrorExp.get() : exp;
7866 }
7867
7868 override void visit(VectorArrayExp e)
7869 {
7870 static if (LOGSEMANTIC)
7871 {
7872 printf("VectorArrayExp::semantic('%s')\n", e.toChars());
7873 }
7874 if (!e.type)
7875 {
7876 unaSemantic(e, sc);
7877 e.e1 = resolveProperties(sc, e.e1);
7878
9c7d5e88 7879 if (e.e1.op == EXP.error)
5fee5ec3
IB
7880 {
7881 result = e.e1;
7882 return;
7883 }
7884 assert(e.e1.type.ty == Tvector);
7885 e.type = e.e1.type.isTypeVector().basetype;
7886 }
7887 result = e;
7888 }
7889
7890 override void visit(SliceExp exp)
7891 {
7892 static if (LOGSEMANTIC)
7893 {
7894 printf("SliceExp::semantic('%s')\n", exp.toChars());
7895 }
7896 if (exp.type)
7897 {
7898 result = exp;
7899 return;
7900 }
7901
7902 // operator overloading should be handled in ArrayExp already.
7903 if (Expression ex = unaSemantic(exp, sc))
7904 {
7905 result = ex;
7906 return;
7907 }
7908 exp.e1 = resolveProperties(sc, exp.e1);
9c7d5e88 7909 if (exp.e1.op == EXP.type && exp.e1.type.ty != Ttuple)
5fee5ec3
IB
7910 {
7911 if (exp.lwr || exp.upr)
7912 {
7913 exp.error("cannot slice type `%s`", exp.e1.toChars());
7914 return setError();
7915 }
7916 Expression e = new TypeExp(exp.loc, exp.e1.type.arrayOf());
7917 result = e.expressionSemantic(sc);
7918 return;
7919 }
7920 if (!exp.lwr && !exp.upr)
7921 {
9c7d5e88 7922 if (exp.e1.op == EXP.arrayLiteral)
5fee5ec3
IB
7923 {
7924 // Convert [a,b,c][] to [a,b,c]
7925 Type t1b = exp.e1.type.toBasetype();
7926 Expression e = exp.e1;
7927 if (t1b.ty == Tsarray)
7928 {
7929 e = e.copy();
7930 e.type = t1b.nextOf().arrayOf();
7931 }
7932 result = e;
7933 return;
7934 }
9c7d5e88 7935 if (exp.e1.op == EXP.slice)
5fee5ec3
IB
7936 {
7937 // Convert e[][] to e[]
7938 SliceExp se = cast(SliceExp)exp.e1;
7939 if (!se.lwr && !se.upr)
7940 {
7941 result = se;
7942 return;
7943 }
7944 }
7945 if (isArrayOpOperand(exp.e1))
7946 {
7947 // Convert (a[]+b[])[] to a[]+b[]
7948 result = exp.e1;
7949 return;
7950 }
7951 }
9c7d5e88 7952 if (exp.e1.op == EXP.error)
5fee5ec3
IB
7953 {
7954 result = exp.e1;
7955 return;
7956 }
7957 if (exp.e1.type.ty == Terror)
7958 return setError();
7959
7960 Type t1b = exp.e1.type.toBasetype();
7e287503 7961 if (auto tp = t1b.isTypePointer())
5fee5ec3
IB
7962 {
7963 if (t1b.isPtrToFunction())
7964 {
7965 exp.error("cannot slice function pointer `%s`", exp.e1.toChars());
7966 return setError();
7967 }
7968 if (!exp.lwr || !exp.upr)
7969 {
7e287503
IB
7970 exp.error("upper and lower bounds are needed to slice a pointer");
7971 if (auto ad = isAggregate(tp.next.toBasetype()))
7972 {
7973 auto s = search_function(ad, Id.index);
7974 if (!s) s = search_function(ad, Id.slice);
7975 if (s)
7976 {
7977 auto fd = s.isFuncDeclaration();
7978 if ((fd && !fd.getParameterList().length) || s.isTemplateDeclaration())
7979 {
7980 exp.errorSupplemental(
7981 "pointer `%s` points to an aggregate that defines an `%s`, perhaps you meant `(*%s)[]`",
7982 exp.e1.toChars(),
7983 s.ident.toChars(),
7984 exp.e1.toChars()
7985 );
7986 }
7987
7988 }
7989 }
7990
5fee5ec3
IB
7991 return setError();
7992 }
610d7898
IB
7993 if (sc.setUnsafe(false, exp.loc, "pointer slicing not allowed in safe functions"))
7994 return setError();
5fee5ec3
IB
7995 }
7996 else if (t1b.ty == Tarray)
7997 {
7998 }
7999 else if (t1b.ty == Tsarray)
8000 {
5fee5ec3
IB
8001 }
8002 else if (t1b.ty == Ttuple)
8003 {
8004 if (!exp.lwr && !exp.upr)
8005 {
8006 result = exp.e1;
8007 return;
8008 }
8009 if (!exp.lwr || !exp.upr)
8010 {
8011 exp.error("need upper and lower bound to slice tuple");
8012 return setError();
8013 }
8014 }
7e7ebe3e 8015 else if (t1b.ty == Tvector && exp.e1.isLvalue())
5fee5ec3
IB
8016 {
8017 // Convert e1 to corresponding static array
8018 TypeVector tv1 = cast(TypeVector)t1b;
8019 t1b = tv1.basetype;
8020 t1b = t1b.castMod(tv1.mod);
8021 exp.e1.type = t1b;
8022 }
8023 else
8024 {
8025 exp.error("`%s` cannot be sliced with `[]`", t1b.ty == Tvoid ? exp.e1.toChars() : t1b.toChars());
8026 return setError();
8027 }
8028
8029 /* Run semantic on lwr and upr.
8030 */
8031 Scope* scx = sc;
8032 if (t1b.ty == Tsarray || t1b.ty == Tarray || t1b.ty == Ttuple)
8033 {
8034 // Create scope for 'length' variable
8035 ScopeDsymbol sym = new ArrayScopeSymbol(sc, exp);
8036 sym.parent = sc.scopesym;
8037 sc = sc.push(sym);
8038 }
8039 if (exp.lwr)
8040 {
8041 if (t1b.ty == Ttuple)
8042 sc = sc.startCTFE();
8043 exp.lwr = exp.lwr.expressionSemantic(sc);
8044 exp.lwr = resolveProperties(sc, exp.lwr);
8045 if (t1b.ty == Ttuple)
8046 sc = sc.endCTFE();
8047 exp.lwr = exp.lwr.implicitCastTo(sc, Type.tsize_t);
8048 }
8049 if (exp.upr)
8050 {
8051 if (t1b.ty == Ttuple)
8052 sc = sc.startCTFE();
8053 exp.upr = exp.upr.expressionSemantic(sc);
8054 exp.upr = resolveProperties(sc, exp.upr);
8055 if (t1b.ty == Ttuple)
8056 sc = sc.endCTFE();
8057 exp.upr = exp.upr.implicitCastTo(sc, Type.tsize_t);
8058 }
8059 if (sc != scx)
8060 sc = sc.pop();
8061 if (exp.lwr && exp.lwr.type == Type.terror || exp.upr && exp.upr.type == Type.terror)
8062 return setError();
8063
8064 if (t1b.ty == Ttuple)
8065 {
8066 exp.lwr = exp.lwr.ctfeInterpret();
8067 exp.upr = exp.upr.ctfeInterpret();
8068 uinteger_t i1 = exp.lwr.toUInteger();
8069 uinteger_t i2 = exp.upr.toUInteger();
8070
8071 TupleExp te;
8072 TypeTuple tup;
8073 size_t length;
9c7d5e88 8074 if (exp.e1.op == EXP.tuple) // slicing an expression tuple
5fee5ec3
IB
8075 {
8076 te = cast(TupleExp)exp.e1;
8077 tup = null;
6d799f0a 8078 length = te.exps.length;
5fee5ec3 8079 }
9c7d5e88 8080 else if (exp.e1.op == EXP.type) // slicing a type tuple
5fee5ec3
IB
8081 {
8082 te = null;
8083 tup = cast(TypeTuple)t1b;
8084 length = Parameter.dim(tup.arguments);
8085 }
8086 else
8087 assert(0);
8088
8089 if (i2 < i1 || length < i2)
8090 {
8091 exp.error("string slice `[%llu .. %llu]` is out of bounds", i1, i2);
8092 return setError();
8093 }
8094
8095 size_t j1 = cast(size_t)i1;
8096 size_t j2 = cast(size_t)i2;
8097 Expression e;
9c7d5e88 8098 if (exp.e1.op == EXP.tuple)
5fee5ec3
IB
8099 {
8100 auto exps = new Expressions(j2 - j1);
8101 for (size_t i = 0; i < j2 - j1; i++)
8102 {
8103 (*exps)[i] = (*te.exps)[j1 + i];
8104 }
8105 e = new TupleExp(exp.loc, te.e0, exps);
8106 }
8107 else
8108 {
8109 auto args = new Parameters();
8110 args.reserve(j2 - j1);
8111 for (size_t i = j1; i < j2; i++)
8112 {
8113 Parameter arg = Parameter.getNth(tup.arguments, i);
8114 args.push(arg);
8115 }
8116 e = new TypeExp(exp.e1.loc, new TypeTuple(args));
8117 }
8118 e = e.expressionSemantic(sc);
8119 result = e;
8120 return;
8121 }
8122
8123 exp.type = t1b.nextOf().arrayOf();
8124 // Allow typedef[] -> typedef[]
8125 if (exp.type.equals(t1b))
8126 exp.type = exp.e1.type;
8127
8128 // We might know $ now
8129 setLengthVarIfKnown(exp.lengthVar, t1b);
8130
8131 if (exp.lwr && exp.upr)
8132 {
8133 exp.lwr = exp.lwr.optimize(WANTvalue);
8134 exp.upr = exp.upr.optimize(WANTvalue);
8135
8136 IntRange lwrRange = getIntRange(exp.lwr);
8137 IntRange uprRange = getIntRange(exp.upr);
8138
8139 if (t1b.ty == Tsarray || t1b.ty == Tarray)
8140 {
8141 Expression el = new ArrayLengthExp(exp.loc, exp.e1);
8142 el = el.expressionSemantic(sc);
8143 el = el.optimize(WANTvalue);
f99303eb 8144 if (el.op == EXP.int64)
5fee5ec3
IB
8145 {
8146 // Array length is known at compile-time. Upper is in bounds if it fits length.
8147 dinteger_t length = el.toInteger();
8148 auto bounds = IntRange(SignExtendedNumber(0), SignExtendedNumber(length));
8149 exp.upperIsInBounds = bounds.contains(uprRange);
8150 }
9c7d5e88 8151 else if (exp.upr.op == EXP.int64 && exp.upr.toInteger() == 0)
5fee5ec3
IB
8152 {
8153 // Upper slice expression is '0'. Value is always in bounds.
8154 exp.upperIsInBounds = true;
8155 }
9c7d5e88 8156 else if (exp.upr.op == EXP.variable && (cast(VarExp)exp.upr).var.ident == Id.dollar)
5fee5ec3
IB
8157 {
8158 // Upper slice expression is '$'. Value is always in bounds.
8159 exp.upperIsInBounds = true;
8160 }
8161 }
8162 else if (t1b.ty == Tpointer)
8163 {
8164 exp.upperIsInBounds = true;
8165 }
8166 else
8167 assert(0);
8168
8169 exp.lowerIsLessThanUpper = (lwrRange.imax <= uprRange.imin);
8170
8171 //printf("upperIsInBounds = %d lowerIsLessThanUpper = %d\n", exp.upperIsInBounds, exp.lowerIsLessThanUpper);
8172 }
8173
8174 result = exp;
8175 }
8176
8177 override void visit(ArrayLengthExp e)
8178 {
8179 static if (LOGSEMANTIC)
8180 {
8181 printf("ArrayLengthExp::semantic('%s')\n", e.toChars());
8182 }
8183 if (e.type)
8184 {
8185 result = e;
8186 return;
8187 }
8188
8189 if (Expression ex = unaSemantic(e, sc))
8190 {
8191 result = ex;
8192 return;
8193 }
8194 e.e1 = resolveProperties(sc, e.e1);
8195
8196 e.type = Type.tsize_t;
8197 result = e;
8198 }
8199
8200 override void visit(ArrayExp exp)
8201 {
8202 static if (LOGSEMANTIC)
8203 {
8204 printf("ArrayExp::semantic('%s')\n", exp.toChars());
8205 }
8206 assert(!exp.type);
0fb57034 8207
fd43568c
IB
8208 if (sc.flags & SCOPE.Cfile)
8209 {
8210 /* See if need to rewrite the AST because of cast/call ambiguity
8211 */
8212 if (auto e = castCallAmbiguity(exp, sc))
8213 {
8214 result = expressionSemantic(e, sc);
8215 return;
8216 }
8217 }
8218
0fb57034
IB
8219 result = exp.carraySemantic(sc); // C semantics
8220 if (result)
8221 return;
8222
5fee5ec3
IB
8223 Expression e = exp.op_overload(sc);
8224 if (e)
8225 {
8226 result = e;
8227 return;
8228 }
8229
8230 if (isAggregate(exp.e1.type))
8231 exp.error("no `[]` operator overload for type `%s`", exp.e1.type.toChars());
9c7d5e88 8232 else if (exp.e1.op == EXP.type && exp.e1.type.ty != Ttuple)
5fee5ec3
IB
8233 exp.error("static array of `%s` with multiple lengths not allowed", exp.e1.type.toChars());
8234 else if (isIndexableNonAggregate(exp.e1.type))
8235 exp.error("only one index allowed to index `%s`", exp.e1.type.toChars());
8236 else
8237 exp.error("cannot use `[]` operator on expression of type `%s`", exp.e1.type.toChars());
8238
8239 result = ErrorExp.get();
8240 }
8241
8242 override void visit(DotExp exp)
8243 {
8244 static if (LOGSEMANTIC)
8245 {
8246 printf("DotExp::semantic('%s')\n", exp.toChars());
8247 if (exp.type)
8248 printf("\ttype = %s\n", exp.type.toChars());
8249 }
8250 exp.e1 = exp.e1.expressionSemantic(sc);
8251 exp.e2 = exp.e2.expressionSemantic(sc);
8252
9c7d5e88 8253 if (exp.e1.op == EXP.type)
5fee5ec3
IB
8254 {
8255 result = exp.e2;
8256 return;
8257 }
9c7d5e88 8258 if (exp.e2.op == EXP.type)
5fee5ec3
IB
8259 {
8260 result = exp.e2;
8261 return;
8262 }
235d5a96 8263 if (auto te = exp.e2.isTemplateExp())
5fee5ec3 8264 {
235d5a96 8265 Expression e = new DotTemplateExp(exp.loc, exp.e1, te.td);
5fee5ec3
IB
8266 result = e.expressionSemantic(sc);
8267 return;
8268 }
8269 if (!exp.type)
8270 exp.type = exp.e2.type;
8271 result = exp;
8272 }
8273
8274 override void visit(CommaExp e)
8275 {
0fb57034 8276 //printf("Semantic.CommaExp() %s\n", e.toChars());
5fee5ec3
IB
8277 if (e.type)
8278 {
8279 result = e;
8280 return;
8281 }
8282
8283 // Allow `((a,b),(x,y))`
8284 if (e.allowCommaExp)
8285 {
8286 CommaExp.allow(e.e1);
8287 CommaExp.allow(e.e2);
8288 }
8289
8290 if (Expression ex = binSemanticProp(e, sc))
8291 {
8292 result = ex;
8293 return;
8294 }
8295 e.e1 = e.e1.addDtorHook(sc);
8296
8297 if (checkNonAssignmentArrayOp(e.e1))
8298 return setError();
8299
0fb57034
IB
8300 // Comma expressions trigger this conversion
8301 e.e2 = e.e2.arrayFuncConv(sc);
8302
5fee5ec3 8303 e.type = e.e2.type;
235d5a96
IB
8304 result = e;
8305
8306 if (sc.flags & SCOPE.Cfile)
8307 return;
8308
5fee5ec3 8309 if (e.type is Type.tvoid)
31350635
IB
8310 {
8311 checkMustUse(e.e1, sc);
5fee5ec3 8312 discardValue(e.e1);
31350635 8313 }
235d5a96 8314 else if (!e.allowCommaExp && !e.isGenerated)
5eb9927a 8315 e.error("using the result of a comma expression is not allowed");
5fee5ec3
IB
8316 }
8317
8318 override void visit(IntervalExp e)
8319 {
8320 static if (LOGSEMANTIC)
8321 {
8322 printf("IntervalExp::semantic('%s')\n", e.toChars());
8323 }
8324 if (e.type)
8325 {
8326 result = e;
8327 return;
8328 }
8329
8330 Expression le = e.lwr;
8331 le = le.expressionSemantic(sc);
8332 le = resolveProperties(sc, le);
8333
8334 Expression ue = e.upr;
8335 ue = ue.expressionSemantic(sc);
8336 ue = resolveProperties(sc, ue);
8337
9c7d5e88 8338 if (le.op == EXP.error)
5fee5ec3
IB
8339 {
8340 result = le;
8341 return;
8342 }
9c7d5e88 8343 if (ue.op == EXP.error)
5fee5ec3
IB
8344 {
8345 result = ue;
8346 return;
8347 }
8348
8349 e.lwr = le;
8350 e.upr = ue;
8351
8352 e.type = Type.tvoid;
8353 result = e;
8354 }
8355
8356 override void visit(DelegatePtrExp e)
8357 {
8358 static if (LOGSEMANTIC)
8359 {
8360 printf("DelegatePtrExp::semantic('%s')\n", e.toChars());
8361 }
8362 if (!e.type)
8363 {
8364 unaSemantic(e, sc);
8365 e.e1 = resolveProperties(sc, e.e1);
8366
9c7d5e88 8367 if (e.e1.op == EXP.error)
5fee5ec3
IB
8368 {
8369 result = e.e1;
8370 return;
8371 }
8372 e.type = Type.tvoidptr;
8373 }
8374 result = e;
8375 }
8376
8377 override void visit(DelegateFuncptrExp e)
8378 {
8379 static if (LOGSEMANTIC)
8380 {
8381 printf("DelegateFuncptrExp::semantic('%s')\n", e.toChars());
8382 }
8383 if (!e.type)
8384 {
8385 unaSemantic(e, sc);
8386 e.e1 = resolveProperties(sc, e.e1);
9c7d5e88 8387 if (e.e1.op == EXP.error)
5fee5ec3
IB
8388 {
8389 result = e.e1;
8390 return;
8391 }
8392 e.type = e.e1.type.nextOf().pointerTo();
8393 }
8394 result = e;
8395 }
8396
8397 override void visit(IndexExp exp)
8398 {
8399 static if (LOGSEMANTIC)
8400 {
8401 printf("IndexExp::semantic('%s')\n", exp.toChars());
8402 }
8403 if (exp.type)
8404 {
8405 result = exp;
8406 return;
8407 }
8408
8409 // operator overloading should be handled in ArrayExp already.
8410 if (!exp.e1.type)
0fb57034 8411 exp.e1 = exp.e1.expressionSemantic(sc).arrayFuncConv(sc);
5fee5ec3 8412 assert(exp.e1.type); // semantic() should already be run on it
9c7d5e88 8413 if (exp.e1.op == EXP.type && exp.e1.type.ty != Ttuple)
5fee5ec3
IB
8414 {
8415 exp.e2 = exp.e2.expressionSemantic(sc);
8416 exp.e2 = resolveProperties(sc, exp.e2);
8417 Type nt;
9c7d5e88 8418 if (exp.e2.op == EXP.type)
5fee5ec3
IB
8419 nt = new TypeAArray(exp.e1.type, exp.e2.type);
8420 else
8421 nt = new TypeSArray(exp.e1.type, exp.e2);
8422 Expression e = new TypeExp(exp.loc, nt);
8423 result = e.expressionSemantic(sc);
8424 return;
8425 }
9c7d5e88 8426 if (exp.e1.op == EXP.error)
5fee5ec3
IB
8427 {
8428 result = exp.e1;
8429 return;
8430 }
8431 if (exp.e1.type.ty == Terror)
8432 return setError();
8433
8434 // Note that unlike C we do not implement the int[ptr]
8435
8436 Type t1b = exp.e1.type.toBasetype();
8437
8da8c7d3 8438 if (TypeVector tv1 = t1b.isTypeVector())
5fee5ec3
IB
8439 {
8440 // Convert e1 to corresponding static array
5fee5ec3
IB
8441 t1b = tv1.basetype;
8442 t1b = t1b.castMod(tv1.mod);
8da8c7d3 8443 exp.e1 = exp.e1.castTo(sc, t1b);
5fee5ec3 8444 }
d97f3bca
IB
8445 if (t1b.ty == Tsarray || t1b.ty == Tarray)
8446 {
8447 if (!checkAddressable(exp, sc))
8448 return setError();
8449 }
5fee5ec3
IB
8450
8451 /* Run semantic on e2
8452 */
8453 Scope* scx = sc;
8454 if (t1b.ty == Tsarray || t1b.ty == Tarray || t1b.ty == Ttuple)
8455 {
8456 // Create scope for 'length' variable
8457 ScopeDsymbol sym = new ArrayScopeSymbol(sc, exp);
8458 sym.parent = sc.scopesym;
8459 sc = sc.push(sym);
8460 }
8461 if (t1b.ty == Ttuple)
8462 sc = sc.startCTFE();
0fb57034 8463 exp.e2 = exp.e2.expressionSemantic(sc).arrayFuncConv(sc);
5fee5ec3
IB
8464 exp.e2 = resolveProperties(sc, exp.e2);
8465 if (t1b.ty == Ttuple)
8466 sc = sc.endCTFE();
9c7d5e88 8467 if (exp.e2.op == EXP.tuple)
5fee5ec3
IB
8468 {
8469 TupleExp te = cast(TupleExp)exp.e2;
6d799f0a 8470 if (te.exps && te.exps.length == 1)
5fee5ec3
IB
8471 exp.e2 = Expression.combine(te.e0, (*te.exps)[0]); // bug 4444 fix
8472 }
8473 if (sc != scx)
8474 sc = sc.pop();
8475 if (exp.e2.type == Type.terror)
8476 return setError();
8477
8478 if (checkNonAssignmentArrayOp(exp.e1))
8479 return setError();
8480
8481 switch (t1b.ty)
8482 {
8483 case Tpointer:
8484 if (t1b.isPtrToFunction())
8485 {
8486 exp.error("cannot index function pointer `%s`", exp.e1.toChars());
8487 return setError();
8488 }
8489 exp.e2 = exp.e2.implicitCastTo(sc, Type.tsize_t);
8490 if (exp.e2.type == Type.terror)
8491 return setError();
8492 exp.e2 = exp.e2.optimize(WANTvalue);
9c7d5e88 8493 if (exp.e2.op == EXP.int64 && exp.e2.toInteger() == 0)
5fee5ec3
IB
8494 {
8495 }
610d7898 8496 else if (sc.setUnsafe(false, exp.loc, "`@safe` function `%s` cannot index pointer `%s`", sc.func, exp.e1))
5fee5ec3 8497 {
610d7898 8498 return setError();
5fee5ec3
IB
8499 }
8500 exp.type = (cast(TypeNext)t1b).next;
8501 break;
8502
8503 case Tarray:
8504 exp.e2 = exp.e2.implicitCastTo(sc, Type.tsize_t);
8505 if (exp.e2.type == Type.terror)
8506 return setError();
8507 exp.type = (cast(TypeNext)t1b).next;
8508 break;
8509
8510 case Tsarray:
8511 {
8512 exp.e2 = exp.e2.implicitCastTo(sc, Type.tsize_t);
8513 if (exp.e2.type == Type.terror)
8514 return setError();
8515 exp.type = t1b.nextOf();
8516 break;
8517 }
8518 case Taarray:
8519 {
8520 TypeAArray taa = cast(TypeAArray)t1b;
8521 /* We can skip the implicit conversion if they differ only by
8522 * constness
8523 * https://issues.dlang.org/show_bug.cgi?id=2684
8524 * see also bug https://issues.dlang.org/show_bug.cgi?id=2954 b
8525 */
8526 if (!arrayTypeCompatibleWithoutCasting(exp.e2.type, taa.index))
8527 {
8528 exp.e2 = exp.e2.implicitCastTo(sc, taa.index); // type checking
8529 if (exp.e2.type == Type.terror)
8530 return setError();
8531 }
8532
8533 semanticTypeInfo(sc, taa);
6d799f0a 8534 checkNewEscape(sc, exp.e2, false);
5fee5ec3
IB
8535
8536 exp.type = taa.next;
8537 break;
8538 }
8539 case Ttuple:
8540 {
8541 exp.e2 = exp.e2.implicitCastTo(sc, Type.tsize_t);
8542 if (exp.e2.type == Type.terror)
8543 return setError();
8544
8545 exp.e2 = exp.e2.ctfeInterpret();
8546 uinteger_t index = exp.e2.toUInteger();
8547
8548 TupleExp te;
8549 TypeTuple tup;
8550 size_t length;
9c7d5e88 8551 if (exp.e1.op == EXP.tuple)
5fee5ec3
IB
8552 {
8553 te = cast(TupleExp)exp.e1;
8554 tup = null;
6d799f0a 8555 length = te.exps.length;
5fee5ec3 8556 }
9c7d5e88 8557 else if (exp.e1.op == EXP.type)
5fee5ec3
IB
8558 {
8559 te = null;
8560 tup = cast(TypeTuple)t1b;
8561 length = Parameter.dim(tup.arguments);
8562 }
8563 else
8564 assert(0);
8565
8566 if (length <= index)
8567 {
8568 exp.error("array index `[%llu]` is outside array bounds `[0 .. %llu]`", index, cast(ulong)length);
8569 return setError();
8570 }
8571 Expression e;
9c7d5e88 8572 if (exp.e1.op == EXP.tuple)
5fee5ec3
IB
8573 {
8574 e = (*te.exps)[cast(size_t)index];
8575 e = Expression.combine(te.e0, e);
8576 }
8577 else
8578 e = new TypeExp(exp.e1.loc, Parameter.getNth(tup.arguments, cast(size_t)index).type);
8579 result = e;
8580 return;
8581 }
8582 default:
8583 exp.error("`%s` must be an array or pointer type, not `%s`", exp.e1.toChars(), exp.e1.type.toChars());
8584 return setError();
8585 }
8586
8587 // We might know $ now
8588 setLengthVarIfKnown(exp.lengthVar, t1b);
8589
8590 if (t1b.ty == Tsarray || t1b.ty == Tarray)
8591 {
8592 Expression el = new ArrayLengthExp(exp.loc, exp.e1);
8593 el = el.expressionSemantic(sc);
8594 el = el.optimize(WANTvalue);
9c7d5e88 8595 if (el.op == EXP.int64)
5fee5ec3
IB
8596 {
8597 exp.e2 = exp.e2.optimize(WANTvalue);
8598 dinteger_t length = el.toInteger();
8599 if (length)
8600 {
8601 auto bounds = IntRange(SignExtendedNumber(0), SignExtendedNumber(length - 1));
7e287503
IB
8602 // OR it in, because it might already be set for C array indexing
8603 exp.indexIsInBounds |= bounds.contains(getIntRange(exp.e2));
5fee5ec3 8604 }
235d5a96
IB
8605 else if (sc.flags & SCOPE.Cfile && t1b.ty == Tsarray)
8606 {
8607 if (auto ve = exp.e1.isVarExp())
8608 {
8609 /* Rewrite 0-length C array ve[exp.e2] as *(ve + exp.e2)
8610 */
8611 auto vp = ve.castTo(sc, t1b.isTypeSArray().next.pointerTo());
8612 auto e = new AddExp(exp.loc, vp, exp.e2);
8613 auto pe = new PtrExp(exp.loc, e);
8614 result = pe.expressionSemantic(sc).optimize(WANTvalue);
8615 return;
8616 }
8617 }
5fee5ec3
IB
8618 }
8619 }
8620
8621 result = exp;
8622 }
8623
8624 override void visit(PostExp exp)
8625 {
8626 static if (LOGSEMANTIC)
8627 {
8628 printf("PostExp::semantic('%s')\n", exp.toChars());
8629 }
8630 if (exp.type)
8631 {
8632 result = exp;
8633 return;
8634 }
8635
fd43568c
IB
8636 if (sc.flags & SCOPE.Cfile)
8637 {
8638 /* See if need to rewrite the AST because of cast/call ambiguity
8639 */
8640 if (auto e = castCallAmbiguity(exp, sc))
8641 {
8642 result = expressionSemantic(e, sc);
8643 return;
8644 }
8645 }
8646
5fee5ec3
IB
8647 if (Expression ex = binSemantic(exp, sc))
8648 {
8649 result = ex;
8650 return;
8651 }
8652 Expression e1x = resolveProperties(sc, exp.e1);
9c7d5e88 8653 if (e1x.op == EXP.error)
5fee5ec3
IB
8654 {
8655 result = e1x;
8656 return;
8657 }
8658 exp.e1 = e1x;
8659
8660 Expression e = exp.op_overload(sc);
8661 if (e)
8662 {
8663 result = e;
8664 return;
8665 }
8666
8667 if (exp.e1.checkReadModifyWrite(exp.op))
8668 return setError();
8669
9c7d5e88 8670 if (exp.e1.op == EXP.slice)
5fee5ec3 8671 {
9c7d5e88 8672 const(char)* s = exp.op == EXP.plusPlus ? "increment" : "decrement";
5fee5ec3
IB
8673 exp.error("cannot post-%s array slice `%s`, use pre-%s instead", s, exp.e1.toChars(), s);
8674 return setError();
8675 }
8676
8677 Type t1 = exp.e1.type.toBasetype();
9c7d5e88 8678 if (t1.ty == Tclass || t1.ty == Tstruct || exp.e1.op == EXP.arrayLength)
5fee5ec3
IB
8679 {
8680 /* Check for operator overloading,
8681 * but rewrite in terms of ++e instead of e++
8682 */
8683
8684 /* If e1 is not trivial, take a reference to it
8685 */
8686 Expression de = null;
9c7d5e88 8687 if (exp.e1.op != EXP.variable && exp.e1.op != EXP.arrayLength)
5fee5ec3
IB
8688 {
8689 // ref v = e1;
8690 auto v = copyToTemp(STC.ref_, "__postref", exp.e1);
8691 de = new DeclarationExp(exp.loc, v);
8692 exp.e1 = new VarExp(exp.e1.loc, v);
8693 }
8694
8695 /* Rewrite as:
8696 * auto tmp = e1; ++e1; tmp
8697 */
8698 auto tmp = copyToTemp(0, "__pitmp", exp.e1);
8699 Expression ea = new DeclarationExp(exp.loc, tmp);
8700
8701 Expression eb = exp.e1.syntaxCopy();
9c7d5e88 8702 eb = new PreExp(exp.op == EXP.plusPlus ? EXP.prePlusPlus : EXP.preMinusMinus, exp.loc, eb);
5fee5ec3
IB
8703
8704 Expression ec = new VarExp(exp.loc, tmp);
8705
8706 // Combine de,ea,eb,ec
8707 if (de)
8708 ea = new CommaExp(exp.loc, de, ea);
8709 e = new CommaExp(exp.loc, ea, eb);
8710 e = new CommaExp(exp.loc, e, ec);
8711 e = e.expressionSemantic(sc);
8712 result = e;
8713 return;
8714 }
8715
8716 exp.e1 = exp.e1.modifiableLvalue(sc, exp.e1);
8717 exp.e1 = exp.e1.optimize(WANTvalue, /*keepLvalue*/ true);
8718
8719 e = exp;
8720 if (exp.e1.checkScalar() ||
8721 exp.e1.checkSharedAccess(sc))
8722 return setError();
8723 if (exp.e1.checkNoBool())
8724 return setError();
8725
8726 if (exp.e1.type.ty == Tpointer)
8727 e = scaleFactor(exp, sc);
8728 else
8729 exp.e2 = exp.e2.castTo(sc, exp.e1.type);
8730 e.type = exp.e1.type;
8731 result = e;
8732 }
8733
8734 override void visit(PreExp exp)
8735 {
8736 Expression e = exp.op_overload(sc);
8737 // printf("PreExp::semantic('%s')\n", toChars());
8738 if (e)
8739 {
8740 result = e;
8741 return;
8742 }
8743
8744 // Rewrite as e1+=1 or e1-=1
9c7d5e88 8745 if (exp.op == EXP.prePlusPlus)
5fee5ec3
IB
8746 e = new AddAssignExp(exp.loc, exp.e1, IntegerExp.literal!1);
8747 else
8748 e = new MinAssignExp(exp.loc, exp.e1, IntegerExp.literal!1);
8749 result = e.expressionSemantic(sc);
8750 }
8751
8752 /*
8753 * Get the expression initializer for a specific struct
8754 *
8755 * Params:
8756 * sd = the struct for which the expression initializer is needed
8757 * loc = the location of the initializer
8758 * sc = the scope where the expression is located
8759 * t = the type of the expression
8760 *
8761 * Returns:
8762 * The expression initializer or error expression if any errors occured
8763 */
8764 private Expression getInitExp(StructDeclaration sd, Loc loc, Scope* sc, Type t)
8765 {
8766 if (sd.zeroInit && !sd.isNested())
8767 {
8768 // https://issues.dlang.org/show_bug.cgi?id=14606
8769 // Always use BlitExp for the special expression: (struct = 0)
8770 return IntegerExp.literal!0;
8771 }
8772
8773 if (sd.isNested())
8774 {
8775 auto sle = new StructLiteralExp(loc, sd, null, t);
c8dfa79c 8776 if (!sd.fill(loc, *sle.elements, true))
5fee5ec3 8777 return ErrorExp.get();
6d799f0a 8778 if (checkFrameAccess(loc, sc, sd, sle.elements.length))
5fee5ec3
IB
8779 return ErrorExp.get();
8780
8781 sle.type = t;
8782 return sle;
8783 }
8784
8785 return t.defaultInit(loc);
8786 }
8787
8788 override void visit(AssignExp exp)
8789 {
8790 static if (LOGSEMANTIC)
8791 {
5eb9927a
IB
8792 if (exp.op == EXP.blit) printf("BlitExp.toElem('%s')\n", exp.toChars());
8793 if (exp.op == EXP.assign) printf("AssignExp.toElem('%s')\n", exp.toChars());
8794 if (exp.op == EXP.construct) printf("ConstructExp.toElem('%s')\n", exp.toChars());
5fee5ec3 8795 }
5fee5ec3
IB
8796
8797 void setResult(Expression e, int line = __LINE__)
8798 {
8799 //printf("line %d\n", line);
8800 result = e;
8801 }
8802
8803 if (exp.type)
8804 {
8805 return setResult(exp);
8806 }
8807
8808 Expression e1old = exp.e1;
8809
8810 if (auto e2comma = exp.e2.isCommaExp())
8811 {
0fb57034 8812 if (!e2comma.isGenerated && !(sc.flags & SCOPE.Cfile))
5eb9927a 8813 exp.error("using the result of a comma expression is not allowed");
5fee5ec3
IB
8814
8815 /* Rewrite to get rid of the comma from rvalue
8816 * e1=(e0,e2) => e0,(e1=e2)
8817 */
8818 Expression e0;
8819 exp.e2 = Expression.extractLast(e2comma, e0);
8820 Expression e = Expression.combine(e0, exp);
8821 return setResult(e.expressionSemantic(sc));
8822 }
8823
8824 /* Look for operator overloading of a[arguments] = e2.
8825 * Do it before e1.expressionSemantic() otherwise the ArrayExp will have been
8826 * converted to unary operator overloading already.
8827 */
8828 if (auto ae = exp.e1.isArrayExp())
8829 {
8830 Expression res;
8831
8832 ae.e1 = ae.e1.expressionSemantic(sc);
8833 ae.e1 = resolveProperties(sc, ae.e1);
8834 Expression ae1old = ae.e1;
8835
8836 const(bool) maybeSlice =
6d799f0a
IB
8837 (ae.arguments.length == 0 ||
8838 ae.arguments.length == 1 && (*ae.arguments)[0].op == EXP.interval);
5fee5ec3
IB
8839
8840 IntervalExp ie = null;
6d799f0a 8841 if (maybeSlice && ae.arguments.length)
5fee5ec3 8842 {
9c7d5e88 8843 assert((*ae.arguments)[0].op == EXP.interval);
5fee5ec3
IB
8844 ie = cast(IntervalExp)(*ae.arguments)[0];
8845 }
8846 while (true)
8847 {
9c7d5e88 8848 if (ae.e1.op == EXP.error)
5fee5ec3
IB
8849 return setResult(ae.e1);
8850
8851 Expression e0 = null;
8852 Expression ae1save = ae.e1;
8853 ae.lengthVar = null;
8854
8855 Type t1b = ae.e1.type.toBasetype();
8856 AggregateDeclaration ad = isAggregate(t1b);
8857 if (!ad)
8858 break;
8859 if (search_function(ad, Id.indexass))
8860 {
8861 // Deal with $
8862 res = resolveOpDollar(sc, ae, &e0);
8863 if (!res) // a[i..j] = e2 might be: a.opSliceAssign(e2, i, j)
8864 goto Lfallback;
9c7d5e88 8865 if (res.op == EXP.error)
5fee5ec3
IB
8866 return setResult(res);
8867
8868 res = exp.e2.expressionSemantic(sc);
9c7d5e88 8869 if (res.op == EXP.error)
5fee5ec3
IB
8870 return setResult(res);
8871 exp.e2 = res;
8872
8873 /* Rewrite (a[arguments] = e2) as:
8874 * a.opIndexAssign(e2, arguments)
8875 */
8876 Expressions* a = ae.arguments.copy();
8877 a.insert(0, exp.e2);
8878 res = new DotIdExp(exp.loc, ae.e1, Id.indexass);
8879 res = new CallExp(exp.loc, res, a);
8880 if (maybeSlice) // a[] = e2 might be: a.opSliceAssign(e2)
8881 res = res.trySemantic(sc);
8882 else
8883 res = res.expressionSemantic(sc);
8884 if (res)
8885 return setResult(Expression.combine(e0, res));
8886 }
8887
8888 Lfallback:
8889 if (maybeSlice && search_function(ad, Id.sliceass))
8890 {
8891 // Deal with $
8892 res = resolveOpDollar(sc, ae, ie, &e0);
9c7d5e88 8893 if (res.op == EXP.error)
5fee5ec3
IB
8894 return setResult(res);
8895
8896 res = exp.e2.expressionSemantic(sc);
9c7d5e88 8897 if (res.op == EXP.error)
5fee5ec3
IB
8898 return setResult(res);
8899
8900 exp.e2 = res;
8901
8902 /* Rewrite (a[i..j] = e2) as:
8903 * a.opSliceAssign(e2, i, j)
8904 */
8905 auto a = new Expressions();
8906 a.push(exp.e2);
8907 if (ie)
8908 {
8909 a.push(ie.lwr);
8910 a.push(ie.upr);
8911 }
8912 res = new DotIdExp(exp.loc, ae.e1, Id.sliceass);
8913 res = new CallExp(exp.loc, res, a);
8914 res = res.expressionSemantic(sc);
8915 return setResult(Expression.combine(e0, res));
8916 }
8917
8918 // No operator overloading member function found yet, but
8919 // there might be an alias this to try.
8920 if (ad.aliasthis && !isRecursiveAliasThis(ae.att1, ae.e1.type))
8921 {
8922 /* Rewrite (a[arguments] op e2) as:
8923 * a.aliasthis[arguments] op e2
8924 */
8925 ae.e1 = resolveAliasThis(sc, ae1save, true);
8926 if (ae.e1)
8927 continue;
8928 }
8929 break;
8930 }
8931 ae.e1 = ae1old; // recovery
8932 ae.lengthVar = null;
8933 }
8934
8935 /* Run this.e1 semantic.
8936 */
8937 {
8938 Expression e1x = exp.e1;
8939
8940 /* With UFCS, e.f = value
8941 * Could mean:
8942 * .f(e, value)
8943 * or:
8944 * .f(e) = value
8945 */
8946 if (auto dti = e1x.isDotTemplateInstanceExp())
8947 {
f99303eb 8948 Expression e = dti.dotTemplateSemanticProp(sc, 1);
5fee5ec3
IB
8949 if (!e)
8950 {
8951 return setResult(resolveUFCSProperties(sc, e1x, exp.e2));
8952 }
8953
8954 e1x = e;
8955 }
0fb57034
IB
8956 else if (sc.flags & SCOPE.Cfile && e1x.isDotIdExp())
8957 {
8958 auto die = e1x.isDotIdExp();
8959 e1x = fieldLookup(die.e1, sc, die.ident);
8960 }
5fee5ec3
IB
8961 else if (auto die = e1x.isDotIdExp())
8962 {
f99303eb 8963 Expression e = die.dotIdSemanticProp(sc, 1);
5fee5ec3
IB
8964 if (e && isDotOpDispatch(e))
8965 {
8966 /* https://issues.dlang.org/show_bug.cgi?id=19687
8967 *
8968 * On this branch, e2 is semantically analyzed in resolvePropertiesX,
8969 * but that call is done with gagged errors. That is the only time when
8970 * semantic gets ran on e2, that is why the error never gets to be printed.
8971 * In order to make sure that UFCS is tried with correct parameters, e2
8972 * needs to have semantic ran on it.
8973 */
0fb57034 8974 auto ode = e;
5fee5ec3
IB
8975 exp.e2 = exp.e2.expressionSemantic(sc);
8976 uint errors = global.startGagging();
8977 e = resolvePropertiesX(sc, e, exp.e2);
0fb57034
IB
8978 // Any error or if 'e' is not resolved, go to UFCS
8979 if (global.endGagging(errors) || e is ode)
5fee5ec3
IB
8980 e = null; /* fall down to UFCS */
8981 else
8982 return setResult(e);
8983 }
8984 if (!e)
8985 return setResult(resolveUFCSProperties(sc, e1x, exp.e2));
8986 e1x = e;
8987 }
8988 else
8989 {
8990 if (auto se = e1x.isSliceExp())
8991 se.arrayop = true;
8992
8993 e1x = e1x.expressionSemantic(sc);
8994 }
8995
8996 /* We have f = value.
8997 * Could mean:
8998 * f(value)
8999 * or:
9000 * f() = value
9001 */
9002 if (Expression e = resolvePropertiesX(sc, e1x, exp.e2))
9003 return setResult(e);
9004
9005 if (e1x.checkRightThis(sc))
9006 {
9007 return setError();
9008 }
9009 exp.e1 = e1x;
9010 assert(exp.e1.type);
9011 }
7e7ebe3e 9012 Type t1 = exp.e1.type.isTypeEnum() ? exp.e1.type : exp.e1.type.toBasetype();
5fee5ec3
IB
9013
9014 /* Run this.e2 semantic.
9015 * Different from other binary expressions, the analysis of e2
9016 * depends on the result of e1 in assignments.
9017 */
9018 {
9019 Expression e2x = inferType(exp.e2, t1.baseElemOf());
9020 e2x = e2x.expressionSemantic(sc);
0fb57034
IB
9021 if (!t1.isTypeSArray())
9022 e2x = e2x.arrayFuncConv(sc);
5fee5ec3 9023 e2x = resolveProperties(sc, e2x);
9c7d5e88 9024 if (e2x.op == EXP.type)
5fee5ec3 9025 e2x = resolveAliasThis(sc, e2x); //https://issues.dlang.org/show_bug.cgi?id=17684
9c7d5e88 9026 if (e2x.op == EXP.error)
5fee5ec3 9027 return setResult(e2x);
0fb57034 9028 // We delay checking the value for structs/classes as these might have
5fee5ec3
IB
9029 // an opAssign defined.
9030 if ((t1.ty != Tstruct && t1.ty != Tclass && e2x.checkValue()) ||
9031 e2x.checkSharedAccess(sc))
9032 return setError();
b6df1132 9033
7e7ebe3e
IB
9034 auto etmp = checkNoreturnVarAccess(e2x);
9035 if (etmp != e2x)
9036 return setResult(etmp);
9037
5fee5ec3
IB
9038 exp.e2 = e2x;
9039 }
9040
9041 /* Rewrite tuple assignment as a tuple of assignments.
9042 */
9043 {
9044 Expression e2x = exp.e2;
9045
9046 Ltupleassign:
9c7d5e88 9047 if (exp.e1.op == EXP.tuple && e2x.op == EXP.tuple)
5fee5ec3
IB
9048 {
9049 TupleExp tup1 = cast(TupleExp)exp.e1;
9050 TupleExp tup2 = cast(TupleExp)e2x;
6d799f0a 9051 size_t dim = tup1.exps.length;
5fee5ec3 9052 Expression e = null;
6d799f0a 9053 if (dim != tup2.exps.length)
5fee5ec3 9054 {
6d799f0a 9055 exp.error("mismatched tuple lengths, %d and %d", cast(int)dim, cast(int)tup2.exps.length);
5fee5ec3
IB
9056 return setError();
9057 }
9058 if (dim == 0)
9059 {
9060 e = IntegerExp.literal!0;
9061 e = new CastExp(exp.loc, e, Type.tvoid); // avoid "has no effect" error
9062 e = Expression.combine(tup1.e0, tup2.e0, e);
9063 }
9064 else
9065 {
9066 auto exps = new Expressions(dim);
9067 for (size_t i = 0; i < dim; i++)
9068 {
9069 Expression ex1 = (*tup1.exps)[i];
9070 Expression ex2 = (*tup2.exps)[i];
9071 (*exps)[i] = new AssignExp(exp.loc, ex1, ex2);
9072 }
9073 e = new TupleExp(exp.loc, Expression.combine(tup1.e0, tup2.e0), exps);
9074 }
9075 return setResult(e.expressionSemantic(sc));
9076 }
9077
9078 /* Look for form: e1 = e2.aliasthis.
9079 */
9c7d5e88 9080 if (exp.e1.op == EXP.tuple)
5fee5ec3
IB
9081 {
9082 TupleDeclaration td = isAliasThisTuple(e2x);
9083 if (!td)
9084 goto Lnomatch;
9085
9086 assert(exp.e1.type.ty == Ttuple);
9087 TypeTuple tt = cast(TypeTuple)exp.e1.type;
9088
9089 Expression e0;
9090 Expression ev = extractSideEffect(sc, "__tup", e0, e2x);
9091
9092 auto iexps = new Expressions();
9093 iexps.push(ev);
6d799f0a 9094 for (size_t u = 0; u < iexps.length; u++)
5fee5ec3
IB
9095 {
9096 Lexpand:
9097 Expression e = (*iexps)[u];
9098
9099 Parameter arg = Parameter.getNth(tt.arguments, u);
6d799f0a 9100 //printf("[%d] iexps.length = %d, ", u, iexps.length);
31350635 9101 //printf("e = (%s %s, %s), ", Token.toChars[e.op], e.toChars(), e.type.toChars());
5fee5ec3
IB
9102 //printf("arg = (%s, %s)\n", arg.toChars(), arg.type.toChars());
9103
9104 if (!arg || !e.type.implicitConvTo(arg.type))
9105 {
9106 // expand initializer to tuple
9107 if (expandAliasThisTuples(iexps, u) != -1)
9108 {
6d799f0a 9109 if (iexps.length <= u)
5fee5ec3
IB
9110 break;
9111 goto Lexpand;
9112 }
9113 goto Lnomatch;
9114 }
9115 }
9116 e2x = new TupleExp(e2x.loc, e0, iexps);
9117 e2x = e2x.expressionSemantic(sc);
9c7d5e88 9118 if (e2x.op == EXP.error)
5fee5ec3
IB
9119 {
9120 result = e2x;
9121 return;
9122 }
9123 // Do not need to overwrite this.e2
9124 goto Ltupleassign;
9125 }
9126 Lnomatch:
9127 }
9128
9129 /* Inside constructor, if this is the first assignment of object field,
9130 * rewrite this to initializing the field.
9131 */
9c7d5e88 9132 if (exp.op == EXP.assign
5fee5ec3
IB
9133 && exp.e1.checkModifiable(sc) == Modifiable.initialization)
9134 {
9135 //printf("[%s] change to init - %s\n", exp.loc.toChars(), exp.toChars());
9136 auto t = exp.type;
9137 exp = new ConstructExp(exp.loc, exp.e1, exp.e2);
9138 exp.type = t;
9139
9140 // https://issues.dlang.org/show_bug.cgi?id=13515
9141 // set Index::modifiable flag for complex AA element initialization
9142 if (auto ie1 = exp.e1.isIndexExp())
9143 {
9144 Expression e1x = ie1.markSettingAAElem();
9c7d5e88 9145 if (e1x.op == EXP.error)
5fee5ec3
IB
9146 {
9147 result = e1x;
9148 return;
9149 }
9150 }
9151 }
9c7d5e88 9152 else if (exp.op == EXP.construct && exp.e1.op == EXP.variable &&
5fee5ec3
IB
9153 (cast(VarExp)exp.e1).var.storage_class & (STC.out_ | STC.ref_))
9154 {
9155 exp.memset = MemorySet.referenceInit;
9156 }
9157
9c7d5e88 9158 if (exp.op == EXP.assign) // skip EXP.blit and EXP.construct, which are initializations
5fee5ec3
IB
9159 {
9160 exp.e1.checkSharedAccess(sc);
9161 checkUnsafeAccess(sc, exp.e1, false, true);
9162 }
9163
9164 checkUnsafeAccess(sc, exp.e2, true, true); // Initializer must always be checked
9165
9166 /* If it is an assignment from a 'foreign' type,
9167 * check for operator overloading.
9168 */
9169 if (exp.memset == MemorySet.referenceInit)
9170 {
9171 // If this is an initialization of a reference,
9172 // do nothing
9173 }
9174 else if (t1.ty == Tstruct)
9175 {
9176 auto e1x = exp.e1;
9177 auto e2x = exp.e2;
9178 auto sd = (cast(TypeStruct)t1).sym;
9179
9c7d5e88 9180 if (exp.op == EXP.construct)
5fee5ec3
IB
9181 {
9182 Type t2 = e2x.type.toBasetype();
9183 if (t2.ty == Tstruct && sd == (cast(TypeStruct)t2).sym)
9184 {
9185 sd.size(exp.loc);
9186 if (sd.sizeok != Sizeok.done)
9187 return setError();
9188 if (!sd.ctor)
9189 sd.ctor = sd.searchCtor();
9190
9191 // https://issues.dlang.org/show_bug.cgi?id=15661
9192 // Look for the form from last of comma chain.
9193 auto e2y = lastComma(e2x);
9194
9c7d5e88
IB
9195 CallExp ce = (e2y.op == EXP.call) ? cast(CallExp)e2y : null;
9196 DotVarExp dve = (ce && ce.e1.op == EXP.dotVariable)
5fee5ec3
IB
9197 ? cast(DotVarExp)ce.e1 : null;
9198 if (sd.ctor && ce && dve && dve.var.isCtorDeclaration() &&
9199 // https://issues.dlang.org/show_bug.cgi?id=19389
9c7d5e88 9200 dve.e1.op != EXP.dotVariable &&
5fee5ec3
IB
9201 e2y.type.implicitConvTo(t1))
9202 {
9203 /* Look for form of constructor call which is:
9204 * __ctmp.ctor(arguments...)
9205 */
9206
9207 /* Before calling the constructor, initialize
9208 * variable with a bit copy of the default
9209 * initializer
9210 */
9211 Expression einit = getInitExp(sd, exp.loc, sc, t1);
9c7d5e88 9212 if (einit.op == EXP.error)
5fee5ec3
IB
9213 {
9214 result = einit;
9215 return;
9216 }
9217
9218 auto ae = new BlitExp(exp.loc, exp.e1, einit);
9219 ae.type = e1x.type;
9220
9221 /* Replace __ctmp being constructed with e1.
9222 * We need to copy constructor call expression,
9223 * because it may be used in other place.
9224 */
9225 auto dvx = cast(DotVarExp)dve.copy();
9226 dvx.e1 = e1x;
9227 auto cx = cast(CallExp)ce.copy();
9228 cx.e1 = dvx;
9229 if (checkConstructorEscape(sc, cx, false))
9230 return setError();
9231
9232 Expression e0;
9233 Expression.extractLast(e2x, e0);
9234
9235 auto e = Expression.combine(e0, ae, cx);
9236 e = e.expressionSemantic(sc);
9237 result = e;
9238 return;
9239 }
9240 // https://issues.dlang.org/show_bug.cgi?id=21586
9241 // Rewrite CondExp or e1 will miss direct construction, e.g.
9242 // e1 = a ? S(1) : ...; -> AST: e1 = a ? (S(0)).this(1) : ...;
9243 // a temporary created and an extra destructor call.
9244 // AST will be rewritten to:
9245 // a ? e1 = 0, e1.this(1) : ...; -> blitting plus construction
9c7d5e88 9246 if (e2x.op == EXP.question)
5fee5ec3
IB
9247 {
9248 /* Rewrite as:
9249 * a ? e1 = b : e1 = c;
9250 */
9251 CondExp econd = cast(CondExp)e2x;
9252 Expression ea1 = new ConstructExp(econd.e1.loc, e1x, econd.e1);
9253 Expression ea2 = new ConstructExp(econd.e2.loc, e1x, econd.e2);
9254 Expression e = new CondExp(exp.loc, econd.econd, ea1, ea2);
9255 result = e.expressionSemantic(sc);
9256 return;
9257 }
9258 if (sd.postblit || sd.hasCopyCtor)
9259 {
9260 /* We have a copy constructor for this
9261 */
9262
9263 if (e2x.isLvalue())
9264 {
9265 if (sd.hasCopyCtor)
9266 {
9267 /* Rewrite as:
9268 * e1 = init, e1.copyCtor(e2);
9269 */
9270 Expression einit = new BlitExp(exp.loc, exp.e1, getInitExp(sd, exp.loc, sc, t1));
9271 einit.type = e1x.type;
9272
9273 Expression e;
9274 e = new DotIdExp(exp.loc, e1x, Id.ctor);
9275 e = new CallExp(exp.loc, e, e2x);
9276 e = new CommaExp(exp.loc, einit, e);
9277
9278 //printf("e: %s\n", e.toChars());
9279
9280 result = e.expressionSemantic(sc);
9281 return;
9282 }
9283 else
9284 {
9285 if (!e2x.type.implicitConvTo(e1x.type))
9286 {
9287 exp.error("conversion error from `%s` to `%s`",
9288 e2x.type.toChars(), e1x.type.toChars());
9289 return setError();
9290 }
9291
9292 /* Rewrite as:
9293 * (e1 = e2).postblit();
9294 *
9295 * Blit assignment e1 = e2 returns a reference to the original e1,
9296 * then call the postblit on it.
9297 */
9298 Expression e = e1x.copy();
9299 e.type = e.type.mutableOf();
9300 if (e.type.isShared && !sd.type.isShared)
9301 e.type = e.type.unSharedOf();
9302 e = new BlitExp(exp.loc, e, e2x);
9303 e = new DotVarExp(exp.loc, e, sd.postblit, false);
9304 e = new CallExp(exp.loc, e);
9305 result = e.expressionSemantic(sc);
9306 return;
9307 }
9308 }
9309 else
9310 {
9311 /* The struct value returned from the function is transferred
9312 * so should not call the destructor on it.
9313 */
9314 e2x = valueNoDtor(e2x);
9315 }
9316 }
9317
9318 // https://issues.dlang.org/show_bug.cgi?id=19251
9319 // if e2 cannot be converted to e1.type, maybe there is an alias this
9320 if (!e2x.implicitConvTo(t1))
9321 {
9322 AggregateDeclaration ad2 = isAggregate(e2x.type);
9323 if (ad2 && ad2.aliasthis && !isRecursiveAliasThis(exp.att2, exp.e2.type))
9324 {
9325 /* Rewrite (e1 op e2) as:
9326 * (e1 op e2.aliasthis)
9327 */
9328 exp.e2 = new DotIdExp(exp.e2.loc, exp.e2, ad2.aliasthis.ident);
9329 result = exp.expressionSemantic(sc);
9330 return;
9331 }
9332 }
9333 }
9334 else if (!e2x.implicitConvTo(t1))
9335 {
9336 sd.size(exp.loc);
9337 if (sd.sizeok != Sizeok.done)
9338 return setError();
9339 if (!sd.ctor)
9340 sd.ctor = sd.searchCtor();
9341
9342 if (sd.ctor)
9343 {
9344 /* Look for implicit constructor call
9345 * Rewrite as:
9346 * e1 = init, e1.ctor(e2)
9347 */
9348
9349 /* Fix Issue 5153 : https://issues.dlang.org/show_bug.cgi?id=5153
9350 * Using `new` to initialize a struct object is a common mistake, but
9351 * the error message from the compiler is not very helpful in that
9352 * case. If exp.e2 is a NewExp and the type of new is the same as
9353 * the type as exp.e1 (struct in this case), then we know for sure
9354 * that the user wants to instantiate a struct. This is done to avoid
9355 * issuing an error when the user actually wants to call a constructor
9356 * which receives a class object.
9357 *
9358 * Foo f = new Foo2(0); is a valid expression if Foo has a constructor
9359 * which receives an instance of a Foo2 class
9360 */
9c7d5e88 9361 if (exp.e2.op == EXP.new_)
5fee5ec3
IB
9362 {
9363 auto newExp = cast(NewExp)(exp.e2);
9364 if (newExp.newtype && newExp.newtype == t1)
9365 {
9366 error(exp.loc, "cannot implicitly convert expression `%s` of type `%s` to `%s`",
9367 newExp.toChars(), newExp.type.toChars(), t1.toChars());
9368 errorSupplemental(exp.loc, "Perhaps remove the `new` keyword?");
9369 return setError();
9370 }
9371 }
9372
9373 Expression einit = new BlitExp(exp.loc, e1x, getInitExp(sd, exp.loc, sc, t1));
9374 einit.type = e1x.type;
9375
9376 Expression e;
9377 e = new DotIdExp(exp.loc, e1x, Id.ctor);
9378 e = new CallExp(exp.loc, e, e2x);
9379 e = new CommaExp(exp.loc, einit, e);
9380 e = e.expressionSemantic(sc);
9381 result = e;
9382 return;
9383 }
9384 if (search_function(sd, Id.call))
9385 {
9386 /* Look for static opCall
9387 * https://issues.dlang.org/show_bug.cgi?id=2702
9388 * Rewrite as:
9389 * e1 = typeof(e1).opCall(arguments)
9390 */
9391 e2x = typeDotIdExp(e2x.loc, e1x.type, Id.call);
9392 e2x = new CallExp(exp.loc, e2x, exp.e2);
9393
9394 e2x = e2x.expressionSemantic(sc);
9395 e2x = resolveProperties(sc, e2x);
9c7d5e88 9396 if (e2x.op == EXP.error)
5fee5ec3
IB
9397 {
9398 result = e2x;
9399 return;
9400 }
9401 if (e2x.checkValue() || e2x.checkSharedAccess(sc))
9402 return setError();
9403 }
9404 }
9405 else // https://issues.dlang.org/show_bug.cgi?id=11355
9406 {
9407 AggregateDeclaration ad2 = isAggregate(e2x.type);
9408 if (ad2 && ad2.aliasthis && !isRecursiveAliasThis(exp.att2, exp.e2.type))
9409 {
9410 /* Rewrite (e1 op e2) as:
9411 * (e1 op e2.aliasthis)
9412 */
9413 exp.e2 = new DotIdExp(exp.e2.loc, exp.e2, ad2.aliasthis.ident);
9414 result = exp.expressionSemantic(sc);
9415 return;
9416 }
9417 }
9418 }
9c7d5e88 9419 else if (exp.op == EXP.assign)
5fee5ec3 9420 {
9c7d5e88 9421 if (e1x.op == EXP.index && (cast(IndexExp)e1x).e1.type.toBasetype().ty == Taarray)
5fee5ec3
IB
9422 {
9423 /*
9424 * Rewrite:
9425 * aa[key] = e2;
9426 * as:
9427 * ref __aatmp = aa;
9428 * ref __aakey = key;
9429 * ref __aaval = e2;
9430 * (__aakey in __aatmp
9431 * ? __aatmp[__aakey].opAssign(__aaval)
9432 * : ConstructExp(__aatmp[__aakey], __aaval));
9433 */
9434 // ensure we keep the expr modifiable
9435 Expression esetting = (cast(IndexExp)e1x).markSettingAAElem();
9c7d5e88 9436 if (esetting.op == EXP.error)
5fee5ec3
IB
9437 {
9438 result = esetting;
9439 return;
9440 }
9c7d5e88 9441 assert(esetting.op == EXP.index);
5fee5ec3
IB
9442 IndexExp ie = cast(IndexExp) esetting;
9443 Type t2 = e2x.type.toBasetype();
9444
9445 Expression e0 = null;
9446 Expression ea = extractSideEffect(sc, "__aatmp", e0, ie.e1);
9447 Expression ek = extractSideEffect(sc, "__aakey", e0, ie.e2);
9448 Expression ev = extractSideEffect(sc, "__aaval", e0, e2x);
9449
9450 AssignExp ae = cast(AssignExp)exp.copy();
9451 ae.e1 = new IndexExp(exp.loc, ea, ek);
9452 ae.e1 = ae.e1.expressionSemantic(sc);
9453 ae.e1 = ae.e1.optimize(WANTvalue);
9454 ae.e2 = ev;
9455 Expression e = ae.op_overload(sc);
9456 if (e)
9457 {
9458 Expression ey = null;
9459 if (t2.ty == Tstruct && sd == t2.toDsymbol(sc))
9460 {
9461 ey = ev;
9462 }
9463 else if (!ev.implicitConvTo(ie.type) && sd.ctor)
9464 {
9465 // Look for implicit constructor call
9466 // Rewrite as S().ctor(e2)
9467 ey = new StructLiteralExp(exp.loc, sd, null);
9468 ey = new DotIdExp(exp.loc, ey, Id.ctor);
9469 ey = new CallExp(exp.loc, ey, ev);
9470 ey = ey.trySemantic(sc);
9471 }
9472 if (ey)
9473 {
9474 Expression ex;
9475 ex = new IndexExp(exp.loc, ea, ek);
9476 ex = ex.expressionSemantic(sc);
9477 ex = ex.modifiableLvalue(sc, ex); // allocate new slot
9478 ex = ex.optimize(WANTvalue);
9479
9480 ey = new ConstructExp(exp.loc, ex, ey);
9481 ey = ey.expressionSemantic(sc);
9c7d5e88 9482 if (ey.op == EXP.error)
5fee5ec3
IB
9483 {
9484 result = ey;
9485 return;
9486 }
9487 ex = e;
9488
9489 // https://issues.dlang.org/show_bug.cgi?id=14144
9490 // The whole expression should have the common type
9491 // of opAssign() return and assigned AA entry.
9492 // Even if there's no common type, expression should be typed as void.
9c7d5e88 9493 if (!typeMerge(sc, EXP.question, ex, ey))
5fee5ec3
IB
9494 {
9495 ex = new CastExp(ex.loc, ex, Type.tvoid);
9496 ey = new CastExp(ey.loc, ey, Type.tvoid);
9497 }
9498 e = new CondExp(exp.loc, new InExp(exp.loc, ek, ea), ex, ey);
9499 }
9500 e = Expression.combine(e0, e);
9501 e = e.expressionSemantic(sc);
9502 result = e;
9503 return;
9504 }
9505 }
9506 else
9507 {
9508 Expression e = exp.op_overload(sc);
9509 if (e)
9510 {
9511 result = e;
9512 return;
9513 }
9514 }
9515 }
9516 else
9c7d5e88 9517 assert(exp.op == EXP.blit);
5fee5ec3 9518
0fb57034
IB
9519 if (e2x.checkValue())
9520 return setError();
9521
5fee5ec3
IB
9522 exp.e1 = e1x;
9523 exp.e2 = e2x;
9524 }
9525 else if (t1.ty == Tclass)
9526 {
9527 // Disallow assignment operator overloads for same type
9c7d5e88 9528 if (exp.op == EXP.assign && !exp.e2.implicitConvTo(exp.e1.type))
5fee5ec3
IB
9529 {
9530 Expression e = exp.op_overload(sc);
9531 if (e)
9532 {
9533 result = e;
9534 return;
9535 }
9536 }
0fb57034
IB
9537 if (exp.e2.checkValue())
9538 return setError();
5fee5ec3
IB
9539 }
9540 else if (t1.ty == Tsarray)
9541 {
9542 // SliceExp cannot have static array type without context inference.
9c7d5e88 9543 assert(exp.e1.op != EXP.slice);
5fee5ec3
IB
9544 Expression e1x = exp.e1;
9545 Expression e2x = exp.e2;
9546
5eb9927a
IB
9547 /* C strings come through as static arrays. May need to adjust the size of the
9548 * string to match the size of e1.
9549 */
9550 Type t2 = e2x.type.toBasetype();
9551 if (sc.flags & SCOPE.Cfile && e2x.isStringExp() && t2.isTypeSArray())
9552 {
9553 uinteger_t dim1 = t1.isTypeSArray().dim.toInteger();
9554 uinteger_t dim2 = t2.isTypeSArray().dim.toInteger();
9555 if (dim1 + 1 == dim2 || dim2 < dim1)
9556 {
9557 auto tsa2 = t2.isTypeSArray();
9558 auto newt = tsa2.next.sarrayOf(dim1).immutableOf();
9559 e2x = castTo(e2x, sc, newt);
9560 exp.e2 = e2x;
9561 }
9562 }
9563
5fee5ec3
IB
9564 if (e2x.implicitConvTo(e1x.type))
9565 {
9c7d5e88 9566 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()))
5fee5ec3
IB
9567 {
9568 if (e1x.checkPostblit(sc, t1))
9569 return setError();
9570 }
9571
9572 // e2 matches to t1 because of the implicit length match, so
9573 if (isUnaArrayOp(e2x.op) || isBinArrayOp(e2x.op))
9574 {
9575 // convert e1 to e1[]
9576 // e.g. e1[] = a[] + b[];
9577 auto sle = new SliceExp(e1x.loc, e1x, null, null);
9578 sle.arrayop = true;
9579 e1x = sle.expressionSemantic(sc);
9580 }
9581 else
9582 {
9583 // convert e2 to t1 later
9584 // e.g. e1 = [1, 2, 3];
9585 }
9586 }
9587 else
9588 {
9589 if (e2x.implicitConvTo(t1.nextOf().arrayOf()) > MATCH.nomatch)
9590 {
9591 uinteger_t dim1 = (cast(TypeSArray)t1).dim.toInteger();
9592 uinteger_t dim2 = dim1;
9593 if (auto ale = e2x.isArrayLiteralExp())
9594 {
6d799f0a 9595 dim2 = ale.elements ? ale.elements.length : 0;
5fee5ec3
IB
9596 }
9597 else if (auto se = e2x.isSliceExp())
9598 {
9599 Type tx = toStaticArrayType(se);
9600 if (tx)
9601 dim2 = (cast(TypeSArray)tx).dim.toInteger();
9602 }
9603 if (dim1 != dim2)
9604 {
9605 exp.error("mismatched array lengths, %d and %d", cast(int)dim1, cast(int)dim2);
9606 return setError();
9607 }
9608 }
9609
9610 // May be block or element-wise assignment, so
9611 // convert e1 to e1[]
9c7d5e88 9612 if (exp.op != EXP.assign)
5fee5ec3
IB
9613 {
9614 // If multidimensional static array, treat as one large array
9615 //
9616 // Find the appropriate array type depending on the assignment, e.g.
9617 // int[3] = int => int[3]
9618 // int[3][2] = int => int[6]
9619 // int[3][2] = int[] => int[3][2]
9620 // int[3][2][4] + int => int[24]
9621 // int[3][2][4] + int[] => int[3][8]
9622 ulong dim = t1.isTypeSArray().dim.toUInteger();
9623 auto type = t1.nextOf();
9624
9625 for (TypeSArray tsa; (tsa = type.isTypeSArray()) !is null; )
9626 {
9627 import core.checkedint : mulu;
9628
9629 // Accumulate skipped dimensions
9630 bool overflow = false;
9631 dim = mulu(dim, tsa.dim.toUInteger(), overflow);
9632 if (overflow || dim >= uint.max)
9633 {
9634 // dym exceeds maximum array size
9635 exp.error("static array `%s` size overflowed to %llu",
9636 e1x.type.toChars(), cast(ulong) dim);
9637 return setError();
9638 }
9639
9640 // Move to the element type
9641 type = tsa.nextOf().toBasetype();
9642
9643 // Rewrite ex1 as a static array if a matching type was found
9644 if (e2x.implicitConvTo(type) > MATCH.nomatch)
9645 {
9646 e1x.type = type.sarrayOf(dim);
9647 break;
9648 }
9649 }
9650 }
9651 auto sle = new SliceExp(e1x.loc, e1x, null, null);
9652 sle.arrayop = true;
9653 e1x = sle.expressionSemantic(sc);
9654 }
9c7d5e88 9655 if (e1x.op == EXP.error)
5fee5ec3 9656 return setResult(e1x);
9c7d5e88 9657 if (e2x.op == EXP.error)
5fee5ec3
IB
9658 return setResult(e2x);
9659
9660 exp.e1 = e1x;
9661 exp.e2 = e2x;
9662 t1 = e1x.type.toBasetype();
9663 }
9664 /* Check the mutability of e1.
9665 */
9666 if (auto ale = exp.e1.isArrayLengthExp())
9667 {
9668 // e1 is not an lvalue, but we let code generator handle it
9669
9670 auto ale1x = ale.e1.modifiableLvalue(sc, exp.e1);
9c7d5e88 9671 if (ale1x.op == EXP.error)
5fee5ec3
IB
9672 return setResult(ale1x);
9673 ale.e1 = ale1x;
9674
9675 Type tn = ale.e1.type.toBasetype().nextOf();
9676 checkDefCtor(ale.loc, tn);
9677
9678 Identifier hook = global.params.tracegc ? Id._d_arraysetlengthTTrace : Id._d_arraysetlengthT;
9679 if (!verifyHookExist(exp.loc, *sc, Id._d_arraysetlengthTImpl, "resizing arrays"))
9680 return setError();
9681
9682 exp.e2 = exp.e2.expressionSemantic(sc);
9683 auto lc = lastComma(exp.e2);
9684 lc = lc.optimize(WANTvalue);
9685 // use slice expression when arr.length = 0 to avoid runtime call
9c7d5e88 9686 if(lc.op == EXP.int64 && lc.toInteger() == 0)
5fee5ec3
IB
9687 {
9688 Expression se = new SliceExp(ale.loc, ale.e1, lc, lc);
9689 Expression as = new AssignExp(ale.loc, ale.e1, se);
9690 as = as.expressionSemantic(sc);
9691 auto res = Expression.combine(as, exp.e2);
9692 res.type = ale.type;
9693 return setResult(res);
9694 }
9695
9696 // Lower to object._d_arraysetlengthTImpl!(typeof(e1))._d_arraysetlengthT{,Trace}(e1, e2)
9697 Expression id = new IdentifierExp(ale.loc, Id.empty);
9698 id = new DotIdExp(ale.loc, id, Id.object);
9699 auto tiargs = new Objects();
9700 tiargs.push(ale.e1.type);
9701 id = new DotTemplateInstanceExp(ale.loc, id, Id._d_arraysetlengthTImpl, tiargs);
9702 id = new DotIdExp(ale.loc, id, hook);
9703 id = id.expressionSemantic(sc);
9704
9705 auto arguments = new Expressions();
9706 arguments.reserve(5);
9707 if (global.params.tracegc)
9708 {
9709 auto funcname = (sc.callsc && sc.callsc.func) ? sc.callsc.func.toPrettyChars() : sc.func.toPrettyChars();
9710 arguments.push(new StringExp(exp.loc, exp.loc.filename.toDString()));
9711 arguments.push(new IntegerExp(exp.loc, exp.loc.linnum, Type.tint32));
9712 arguments.push(new StringExp(exp.loc, funcname.toDString()));
9713 }
9714 arguments.push(ale.e1);
9715 arguments.push(exp.e2);
9716
9717 Expression ce = new CallExp(ale.loc, id, arguments);
9718 auto res = ce.expressionSemantic(sc);
9719 // if (global.params.verbose)
9720 // message("lowered %s =>\n %s", exp.toChars(), res.toChars());
9721 return setResult(res);
9722 }
9723 else if (auto se = exp.e1.isSliceExp())
9724 {
9725 Type tn = se.type.nextOf();
9726 const fun = sc.func;
9c7d5e88 9727 if (exp.op == EXP.assign && !tn.isMutable() &&
5fee5ec3
IB
9728 // allow modifiation in module ctor, see
9729 // https://issues.dlang.org/show_bug.cgi?id=9884
9730 (!fun || (fun && !fun.isStaticCtorDeclaration())))
9731 {
9732 exp.error("slice `%s` is not mutable", se.toChars());
9733 return setError();
9734 }
9735
9c7d5e88 9736 if (exp.op == EXP.assign && !tn.baseElemOf().isAssignable())
5fee5ec3
IB
9737 {
9738 exp.error("slice `%s` is not mutable, struct `%s` has immutable members",
9739 exp.e1.toChars(), tn.baseElemOf().toChars());
9740 result = ErrorExp.get();
9741 return;
9742 }
9743
9744 // For conditional operator, both branches need conversion.
9c7d5e88 9745 while (se.e1.op == EXP.slice)
5fee5ec3 9746 se = cast(SliceExp)se.e1;
9c7d5e88 9747 if (se.e1.op == EXP.question && se.e1.type.toBasetype().ty == Tsarray)
5fee5ec3
IB
9748 {
9749 se.e1 = se.e1.modifiableLvalue(sc, exp.e1);
9c7d5e88 9750 if (se.e1.op == EXP.error)
5fee5ec3
IB
9751 return setResult(se.e1);
9752 }
9753 }
9754 else
9755 {
9c7d5e88 9756 if (t1.ty == Tsarray && exp.op == EXP.assign)
5fee5ec3
IB
9757 {
9758 Type tn = exp.e1.type.nextOf();
9759 if (tn && !tn.baseElemOf().isAssignable())
9760 {
9761 exp.error("array `%s` is not mutable, struct `%s` has immutable members",
9762 exp.e1.toChars(), tn.baseElemOf().toChars());
9763 result = ErrorExp.get();
9764 return;
9765 }
9766 }
9767
9768 Expression e1x = exp.e1;
9769
9770 // Try to do a decent error message with the expression
9771 // before it gets constant folded
9c7d5e88 9772 if (exp.op == EXP.assign)
5fee5ec3
IB
9773 e1x = e1x.modifiableLvalue(sc, e1old);
9774
9775 e1x = e1x.optimize(WANTvalue, /*keepLvalue*/ true);
9776
9c7d5e88 9777 if (e1x.op == EXP.error)
5fee5ec3
IB
9778 {
9779 result = e1x;
9780 return;
9781 }
9782 exp.e1 = e1x;
9783 }
9784
9785 /* Tweak e2 based on the type of e1.
9786 */
9787 Expression e2x = exp.e2;
9788 Type t2 = e2x.type.toBasetype();
9789
9790 // If it is a array, get the element type. Note that it may be
9791 // multi-dimensional.
9792 Type telem = t1;
9793 while (telem.ty == Tarray)
9794 telem = telem.nextOf();
9795
9c7d5e88
IB
9796 if (exp.e1.op == EXP.slice && t1.nextOf() &&
9797 (telem.ty != Tvoid || e2x.op == EXP.null_) &&
5fee5ec3
IB
9798 e2x.implicitConvTo(t1.nextOf()))
9799 {
9800 // Check for block assignment. If it is of type void[], void[][], etc,
9801 // '= null' is the only allowable block assignment (Bug 7493)
9802 exp.memset = MemorySet.blockAssign; // make it easy for back end to tell what this is
9803 e2x = e2x.implicitCastTo(sc, t1.nextOf());
9c7d5e88 9804 if (exp.op != EXP.blit && e2x.isLvalue() && exp.e1.checkPostblit(sc, t1.nextOf()))
5fee5ec3
IB
9805 return setError();
9806 }
9c7d5e88 9807 else if (exp.e1.op == EXP.slice &&
5fee5ec3
IB
9808 (t2.ty == Tarray || t2.ty == Tsarray) &&
9809 t2.nextOf().implicitConvTo(t1.nextOf()))
9810 {
9811 // Check element-wise assignment.
9812
9813 /* If assigned elements number is known at compile time,
9814 * check the mismatch.
9815 */
9816 SliceExp se1 = cast(SliceExp)exp.e1;
9817 TypeSArray tsa1 = cast(TypeSArray)toStaticArrayType(se1);
9818 TypeSArray tsa2 = null;
9819 if (auto ale = e2x.isArrayLiteralExp())
6d799f0a 9820 tsa2 = cast(TypeSArray)t2.nextOf().sarrayOf(ale.elements.length);
5fee5ec3
IB
9821 else if (auto se = e2x.isSliceExp())
9822 tsa2 = cast(TypeSArray)toStaticArrayType(se);
9823 else
9824 tsa2 = t2.isTypeSArray();
5eb9927a 9825
5fee5ec3
IB
9826 if (tsa1 && tsa2)
9827 {
9828 uinteger_t dim1 = tsa1.dim.toInteger();
9829 uinteger_t dim2 = tsa2.dim.toInteger();
9830 if (dim1 != dim2)
9831 {
5eb9927a 9832 exp.error("mismatched array lengths %d and %d for assignment `%s`", cast(int)dim1, cast(int)dim2, exp.toChars());
5fee5ec3
IB
9833 return setError();
9834 }
9835 }
9836
9c7d5e88
IB
9837 if (exp.op != EXP.blit &&
9838 (e2x.op == EXP.slice && (cast(UnaExp)e2x).e1.isLvalue() ||
9839 e2x.op == EXP.cast_ && (cast(UnaExp)e2x).e1.isLvalue() ||
9840 e2x.op != EXP.slice && e2x.isLvalue()))
5fee5ec3
IB
9841 {
9842 if (exp.e1.checkPostblit(sc, t1.nextOf()))
9843 return setError();
9844 }
9845
9c7d5e88
IB
9846 if (0 && global.params.warnings != DiagnosticReporting.off && !global.gag && exp.op == EXP.assign &&
9847 e2x.op != EXP.slice && e2x.op != EXP.assign &&
9848 e2x.op != EXP.arrayLiteral && e2x.op != EXP.string_ &&
9849 !(e2x.op == EXP.add || e2x.op == EXP.min ||
9850 e2x.op == EXP.mul || e2x.op == EXP.div ||
9851 e2x.op == EXP.mod || e2x.op == EXP.xor ||
9852 e2x.op == EXP.and || e2x.op == EXP.or ||
9853 e2x.op == EXP.pow ||
9854 e2x.op == EXP.tilde || e2x.op == EXP.negate))
5fee5ec3
IB
9855 {
9856 const(char)* e1str = exp.e1.toChars();
9857 const(char)* e2str = e2x.toChars();
9858 exp.warning("explicit element-wise assignment `%s = (%s)[]` is better than `%s = %s`", e1str, e2str, e1str, e2str);
9859 }
9860
9861 Type t2n = t2.nextOf();
9862 Type t1n = t1.nextOf();
9863 int offset;
9864 if (t2n.equivalent(t1n) ||
9865 t1n.isBaseOf(t2n, &offset) && offset == 0)
9866 {
9867 /* Allow copy of distinct qualifier elements.
9868 * eg.
9869 * char[] dst; const(char)[] src;
9870 * dst[] = src;
9871 *
9872 * class C {} class D : C {}
9873 * C[2] ca; D[] da;
9874 * ca[] = da;
9875 */
9876 if (isArrayOpValid(e2x))
9877 {
9878 // Don't add CastExp to keep AST for array operations
9879 e2x = e2x.copy();
9880 e2x.type = exp.e1.type.constOf();
9881 }
9882 else
9883 e2x = e2x.castTo(sc, exp.e1.type.constOf());
9884 }
9885 else
9886 {
9887 /* https://issues.dlang.org/show_bug.cgi?id=15778
9888 * A string literal has an array type of immutable
9889 * elements by default, and normally it cannot be convertible to
9890 * array type of mutable elements. But for element-wise assignment,
9891 * elements need to be const at best. So we should give a chance
9892 * to change code unit size for polysemous string literal.
9893 */
9c7d5e88 9894 if (e2x.op == EXP.string_)
5fee5ec3
IB
9895 e2x = e2x.implicitCastTo(sc, exp.e1.type.constOf());
9896 else
9897 e2x = e2x.implicitCastTo(sc, exp.e1.type);
9898 }
9899 if (t1n.toBasetype.ty == Tvoid && t2n.toBasetype.ty == Tvoid)
9900 {
610d7898
IB
9901 if (sc.setUnsafe(false, exp.loc, "cannot copy `void[]` to `void[]` in `@safe` code"))
9902 return setError();
5fee5ec3
IB
9903 }
9904 }
9905 else
9906 {
9c7d5e88 9907 if (0 && global.params.warnings != DiagnosticReporting.off && !global.gag && exp.op == EXP.assign &&
5fee5ec3 9908 t1.ty == Tarray && t2.ty == Tsarray &&
9c7d5e88 9909 e2x.op != EXP.slice &&
5fee5ec3
IB
9910 t2.implicitConvTo(t1))
9911 {
9912 // Disallow ar[] = sa (Converted to ar[] = sa[])
9913 // Disallow da = sa (Converted to da = sa[])
9914 const(char)* e1str = exp.e1.toChars();
9915 const(char)* e2str = e2x.toChars();
9c7d5e88 9916 const(char)* atypestr = exp.e1.op == EXP.slice ? "element-wise" : "slice";
5fee5ec3
IB
9917 exp.warning("explicit %s assignment `%s = (%s)[]` is better than `%s = %s`", atypestr, e1str, e2str, e1str, e2str);
9918 }
9c7d5e88 9919 if (exp.op == EXP.blit)
5fee5ec3
IB
9920 e2x = e2x.castTo(sc, exp.e1.type);
9921 else
9922 {
9923 e2x = e2x.implicitCastTo(sc, exp.e1.type);
9924
9925 // Fix Issue 13435: https://issues.dlang.org/show_bug.cgi?id=13435
9926
9927 // If the implicit cast has failed and the assign expression is
9928 // the initialization of a struct member field
9c7d5e88 9929 if (e2x.op == EXP.error && exp.op == EXP.construct && t1.ty == Tstruct)
5fee5ec3
IB
9930 {
9931 scope sd = (cast(TypeStruct)t1).sym;
9932 Dsymbol opAssign = search_function(sd, Id.assign);
9933
9934 // and the struct defines an opAssign
9935 if (opAssign)
9936 {
9937 // offer more information about the cause of the problem
9938 errorSupplemental(exp.loc,
9939 "`%s` is the first assignment of `%s` therefore it represents its initialization",
9940 exp.toChars(), exp.e1.toChars());
9941 errorSupplemental(exp.loc,
9942 "`opAssign` methods are not used for initialization, but for subsequent assignments");
9943 }
9944 }
9945 }
9946 }
9c7d5e88 9947 if (e2x.op == EXP.error)
5fee5ec3
IB
9948 {
9949 result = e2x;
9950 return;
9951 }
9952 exp.e2 = e2x;
9953 t2 = exp.e2.type.toBasetype();
9954
9955 /* Look for array operations
9956 */
9957 if ((t2.ty == Tarray || t2.ty == Tsarray) && isArrayOpValid(exp.e2))
9958 {
9959 // Look for valid array operations
9960 if (exp.memset != MemorySet.blockAssign &&
9c7d5e88 9961 exp.e1.op == EXP.slice &&
5fee5ec3
IB
9962 (isUnaArrayOp(exp.e2.op) || isBinArrayOp(exp.e2.op)))
9963 {
9964 exp.type = exp.e1.type;
9c7d5e88 9965 if (exp.op == EXP.construct) // https://issues.dlang.org/show_bug.cgi?id=10282
5fee5ec3
IB
9966 // tweak mutability of e1 element
9967 exp.e1.type = exp.e1.type.nextOf().mutableOf().arrayOf();
9968 result = arrayOp(exp, sc);
9969 return;
9970 }
9971
9972 // Drop invalid array operations in e2
9973 // d = a[] + b[], d = (a[] + b[])[0..2], etc
9c7d5e88 9974 if (checkNonAssignmentArrayOp(exp.e2, exp.memset != MemorySet.blockAssign && exp.op == EXP.assign))
5fee5ec3
IB
9975 return setError();
9976
9977 // Remains valid array assignments
9978 // d = d[], d = [1,2,3], etc
9979 }
9980
9981 /* Don't allow assignment to classes that were allocated on the stack with:
9982 * scope Class c = new Class();
9983 */
9c7d5e88 9984 if (exp.e1.op == EXP.variable && exp.op == EXP.assign)
5fee5ec3
IB
9985 {
9986 VarExp ve = cast(VarExp)exp.e1;
9987 VarDeclaration vd = ve.var.isVarDeclaration();
6384eff5 9988 if (vd && vd.onstack)
5fee5ec3
IB
9989 {
9990 assert(t1.ty == Tclass);
9991 exp.error("cannot rebind scope variables");
9992 }
9993 }
9994
9c7d5e88 9995 if (exp.e1.op == EXP.variable && (cast(VarExp)exp.e1).var.ident == Id.ctfe)
5fee5ec3
IB
9996 {
9997 exp.error("cannot modify compiler-generated variable `__ctfe`");
9998 }
9999
10000 exp.type = exp.e1.type;
10001 assert(exp.type);
7e7ebe3e 10002 auto assignElem = exp.e2;
9c7d5e88 10003 auto res = exp.op == EXP.assign ? exp.reorderSettingAAElem(sc) : exp;
0fb57034
IB
10004 /* https://issues.dlang.org/show_bug.cgi?id=22366
10005 *
10006 * `reorderSettingAAElem` creates a tree of comma expressions, however,
10007 * `checkAssignExp` expects only AssignExps.
10008 */
7e7ebe3e
IB
10009 if (res == exp) // no `AA[k] = v` rewrite was performed
10010 checkAssignEscape(sc, res, false, false);
10011 else
10012 checkNewEscape(sc, assignElem, false); // assigning to AA puts it on heap
9c7d5e88
IB
10013
10014 if (auto ae = res.isConstructExp())
10015 {
10016 Type t1b = ae.e1.type.toBasetype();
10017 if (t1b.ty != Tsarray && t1b.ty != Tarray)
10018 return setResult(res);
10019
7e7ebe3e
IB
10020 // only non-trivial array constructions may need to be lowered (non-POD elements basically)
10021 Type t1e = t1b.nextOf();
10022 TypeStruct ts = t1e.baseElemOf().isTypeStruct();
10023 if (!ts || (!ts.sym.postblit && !ts.sym.hasCopyCtor && !ts.sym.dtor))
10024 return setResult(res);
9c7d5e88 10025
7e7ebe3e
IB
10026 // don't lower ref-constructions etc.
10027 if (!(t1b.ty == Tsarray || ae.e1.isSliceExp) ||
10028 (ae.e1.isVarExp && ae.e1.isVarExp.var.isVarDeclaration.isReference))
10029 return setResult(res);
10030
10031 // Construction from an equivalent other array?
10032 // Only lower with lvalue RHS elements; let the glue layer move rvalue elements.
10033 Type t2b = ae.e2.type.toBasetype();
10034 // skip over a (possibly implicit) cast of a static array RHS to a slice
10035 Expression rhs = ae.e2;
10036 Type rhsType = t2b;
10037 if (t2b.ty == Tarray)
9c7d5e88 10038 {
7e7ebe3e
IB
10039 if (auto ce = rhs.isCastExp())
10040 {
10041 auto ct = ce.e1.type.toBasetype();
10042 if (ct.ty == Tsarray)
10043 {
10044 rhs = ce.e1;
10045 rhsType = ct;
10046 }
10047 }
10048 }
10049 const lowerToArrayCtor =
10050 ( (rhsType.ty == Tarray && !rhs.isArrayLiteralExp) ||
10051 (rhsType.ty == Tsarray && rhs.isLvalue) ) &&
10052 t1e.equivalent(t2b.nextOf);
10053
10054 // Construction from a single element?
10055 // If the RHS is an rvalue, then we'll need to make a temporary for it (copied multiple times).
10056 const lowerToArraySetCtor = !lowerToArrayCtor && t1e.equivalent(t2b);
9c7d5e88 10057
7e7ebe3e
IB
10058 if (lowerToArrayCtor || lowerToArraySetCtor)
10059 {
10060 auto func = lowerToArrayCtor ? Id._d_arrayctor : Id._d_arraysetctor;
10061 const other = lowerToArrayCtor ? "other array" : "value";
9c7d5e88
IB
10062 if (!verifyHookExist(exp.loc, *sc, func, "construct array with " ~ other, Id.object))
10063 return setError();
10064
10065 // Lower to object._d_array{,set}ctor(e1, e2)
10066 Expression id = new IdentifierExp(exp.loc, Id.empty);
10067 id = new DotIdExp(exp.loc, id, Id.object);
10068 id = new DotIdExp(exp.loc, id, func);
9c7d5e88
IB
10069
10070 auto arguments = new Expressions();
7e7ebe3e
IB
10071 arguments.push(new CastExp(ae.loc, ae.e1, t1e.arrayOf).expressionSemantic(sc));
10072 if (lowerToArrayCtor)
9c7d5e88 10073 {
7e7ebe3e 10074 arguments.push(new CastExp(ae.loc, rhs, t2b.nextOf.arrayOf).expressionSemantic(sc));
9c7d5e88
IB
10075 Expression ce = new CallExp(exp.loc, id, arguments);
10076 res = ce.expressionSemantic(sc);
10077 }
10078 else
10079 {
10080 Expression e0;
7e7ebe3e
IB
10081 // promote an rvalue RHS element to a temporary, it's passed by ref to _d_arraysetctor
10082 if (!ae.e2.isLvalue)
9c7d5e88
IB
10083 {
10084 auto vd = copyToTemp(STC.scope_, "__setctor", ae.e2);
10085 e0 = new DeclarationExp(vd.loc, vd).expressionSemantic(sc);
10086 arguments.push(new VarExp(vd.loc, vd).expressionSemantic(sc));
10087 }
10088 else
10089 arguments.push(ae.e2);
10090
10091 Expression ce = new CallExp(exp.loc, id, arguments);
10092 res = Expression.combine(e0, ce).expressionSemantic(sc);
10093 }
10094
10095 if (global.params.verbose)
10096 message("lowered %s =>\n %s", exp.toChars(), res.toChars());
10097 }
10098 }
b7a586be
IB
10099 else if (auto ae = res.isAssignExp())
10100 res = lowerArrayAssign(ae);
10101 else if (auto ce = res.isCommaExp())
10102 {
10103 if (auto ae1 = ce.e1.isAssignExp())
10104 ce.e1 = lowerArrayAssign(ae1, true);
10105 if (auto ae2 = ce.e2.isAssignExp())
10106 ce.e2 = lowerArrayAssign(ae2, true);
10107 }
9c7d5e88 10108
5fee5ec3
IB
10109 return setResult(res);
10110 }
10111
b7a586be 10112 /***************************************
c8dfa79c 10113 * Lower AssignExp to `_d_array{setassign,assign_l,assign_r}` if needed.
b7a586be
IB
10114 *
10115 * Params:
10116 * ae = the AssignExp to be lowered
10117 * fromCommaExp = indicates whether `ae` is part of a CommaExp or not,
10118 * so no unnecessary temporay variable is created.
10119 * Returns:
c8dfa79c
IB
10120 * a CommaExp contiaining call a to `_d_array{setassign,assign_l,assign_r}`
10121 * if needed or `ae` otherwise
b7a586be
IB
10122 */
10123 private Expression lowerArrayAssign(AssignExp ae, bool fromCommaExp = false)
10124 {
10125 Type t1b = ae.e1.type.toBasetype();
10126 if (t1b.ty != Tsarray && t1b.ty != Tarray)
10127 return ae;
10128
c8dfa79c 10129 const isArrayAssign = (ae.e1.isSliceExp() || ae.e1.type.ty == Tsarray) &&
b7a586be 10130 (ae.e2.type.ty == Tsarray || ae.e2.type.ty == Tarray) &&
c8dfa79c 10131 (ae.e1.type.nextOf() && ae.e2.type.nextOf() && ae.e1.type.nextOf.mutableOf.equals(ae.e2.type.nextOf.mutableOf()));
b7a586be 10132
c8dfa79c
IB
10133 const isArraySetAssign = (ae.e1.isSliceExp() || ae.e1.type.ty == Tsarray) &&
10134 (ae.e1.type.nextOf() && ae.e2.type.implicitConvTo(ae.e1.type.nextOf()));
10135
10136 if (!isArrayAssign && !isArraySetAssign)
b7a586be
IB
10137 return ae;
10138
10139 const ts = t1b.nextOf().baseElemOf().isTypeStruct();
10140 if (!ts || (!ts.sym.postblit && !ts.sym.dtor))
10141 return ae;
10142
10143 Expression res;
c8dfa79c
IB
10144 Identifier func = isArraySetAssign ? Id._d_arraysetassign :
10145 ae.e2.isLvalue() || ae.e2.isSliceExp() ? Id._d_arrayassign_l : Id._d_arrayassign_r;
b7a586be 10146
c8dfa79c 10147 // Lower to `.object._d_array{setassign,assign_l,assign_r}(e1, e2)``
b7a586be
IB
10148 Expression id = new IdentifierExp(ae.loc, Id.empty);
10149 id = new DotIdExp(ae.loc, id, Id.object);
10150 id = new DotIdExp(ae.loc, id, func);
10151
10152 auto arguments = new Expressions();
10153 arguments.push(new CastExp(ae.loc, ae.e1, ae.e1.type.nextOf.arrayOf)
10154 .expressionSemantic(sc));
10155
10156 Expression eValue2, value2 = ae.e2;
c8dfa79c
IB
10157 if (isArrayAssign && value2.isLvalue())
10158 value2 = new CastExp(ae.loc, ae.e2, ae.e2.type.nextOf.arrayOf())
b7a586be 10159 .expressionSemantic(sc);
c8dfa79c
IB
10160 else if (!fromCommaExp &&
10161 (isArrayAssign || (isArraySetAssign && !value2.isLvalue())))
b7a586be
IB
10162 {
10163 // Rvalues from CommaExps were introduced in `visit(AssignExp)`
10164 // and are temporary variables themselves. Rvalues from trivial
10165 // SliceExps are simply passed by reference without any copying.
10166
10167 // `__assigntmp` will be destroyed together with the array `ae.e1`.
10168 // When `ae.e2` is a variadic arg array, it is also `scope`, so
10169 // `__assigntmp` may also be scope.
c8dfa79c
IB
10170 StorageClass stc = STC.nodtor;
10171 if (isArrayAssign)
10172 stc |= STC.rvalue | STC.scope_;
10173
10174 auto vd = copyToTemp(stc, "__assigntmp", ae.e2);
b7a586be
IB
10175 eValue2 = new DeclarationExp(vd.loc, vd).expressionSemantic(sc);
10176 value2 = new VarExp(vd.loc, vd).expressionSemantic(sc);
10177 }
10178 arguments.push(value2);
10179
10180 Expression ce = new CallExp(ae.loc, id, arguments);
10181 res = Expression.combine(eValue2, ce).expressionSemantic(sc);
c8dfa79c
IB
10182 if (isArrayAssign)
10183 res = Expression.combine(res, ae.e1).expressionSemantic(sc);
b7a586be
IB
10184
10185 if (global.params.verbose)
10186 message("lowered %s =>\n %s", ae.toChars(), res.toChars());
10187
10188 return res;
10189 }
10190
5fee5ec3
IB
10191 override void visit(PowAssignExp exp)
10192 {
10193 if (exp.type)
10194 {
10195 result = exp;
10196 return;
10197 }
10198
10199 Expression e = exp.op_overload(sc);
10200 if (e)
10201 {
10202 result = e;
10203 return;
10204 }
10205
10206 if (exp.e1.checkReadModifyWrite(exp.op, exp.e2))
10207 return setError();
10208
10209 assert(exp.e1.type && exp.e2.type);
9c7d5e88 10210 if (exp.e1.op == EXP.slice || exp.e1.type.ty == Tarray || exp.e1.type.ty == Tsarray)
5fee5ec3
IB
10211 {
10212 if (checkNonAssignmentArrayOp(exp.e1))
10213 return setError();
10214
10215 // T[] ^^= ...
10216 if (exp.e2.implicitConvTo(exp.e1.type.nextOf()))
10217 {
10218 // T[] ^^= T
10219 exp.e2 = exp.e2.castTo(sc, exp.e1.type.nextOf());
10220 }
10221 else if (Expression ex = typeCombine(exp, sc))
10222 {
10223 result = ex;
10224 return;
10225 }
10226
10227 // Check element types are arithmetic
10228 Type tb1 = exp.e1.type.nextOf().toBasetype();
10229 Type tb2 = exp.e2.type.toBasetype();
10230 if (tb2.ty == Tarray || tb2.ty == Tsarray)
10231 tb2 = tb2.nextOf().toBasetype();
10232 if ((tb1.isintegral() || tb1.isfloating()) && (tb2.isintegral() || tb2.isfloating()))
10233 {
10234 exp.type = exp.e1.type;
10235 result = arrayOp(exp, sc);
10236 return;
10237 }
10238 }
10239 else
10240 {
10241 exp.e1 = exp.e1.modifiableLvalue(sc, exp.e1);
10242 }
10243
10244 if ((exp.e1.type.isintegral() || exp.e1.type.isfloating()) && (exp.e2.type.isintegral() || exp.e2.type.isfloating()))
10245 {
10246 Expression e0 = null;
10247 e = exp.reorderSettingAAElem(sc);
10248 e = Expression.extractLast(e, e0);
10249 assert(e == exp);
10250
9c7d5e88 10251 if (exp.e1.op == EXP.variable)
5fee5ec3
IB
10252 {
10253 // Rewrite: e1 = e1 ^^ e2
10254 e = new PowExp(exp.loc, exp.e1.syntaxCopy(), exp.e2);
10255 e = new AssignExp(exp.loc, exp.e1, e);
10256 }
10257 else
10258 {
10259 // Rewrite: ref tmp = e1; tmp = tmp ^^ e2
10260 auto v = copyToTemp(STC.ref_, "__powtmp", exp.e1);
10261 auto de = new DeclarationExp(exp.e1.loc, v);
10262 auto ve = new VarExp(exp.e1.loc, v);
10263 e = new PowExp(exp.loc, ve, exp.e2);
10264 e = new AssignExp(exp.loc, new VarExp(exp.e1.loc, v), e);
10265 e = new CommaExp(exp.loc, de, e);
10266 }
10267 e = Expression.combine(e0, e);
10268 e = e.expressionSemantic(sc);
10269 result = e;
10270 return;
10271 }
10272 result = exp.incompatibleTypes();
10273 }
10274
10275 override void visit(CatAssignExp exp)
10276 {
10277 if (exp.type)
10278 {
10279 result = exp;
10280 return;
10281 }
10282
10283 //printf("CatAssignExp::semantic() %s\n", exp.toChars());
10284 Expression e = exp.op_overload(sc);
10285 if (e)
10286 {
10287 result = e;
10288 return;
10289 }
10290
235d5a96 10291 if (SliceExp se = exp.e1.isSliceExp())
5fee5ec3 10292 {
5fee5ec3
IB
10293 if (se.e1.type.toBasetype().ty == Tsarray)
10294 {
10295 exp.error("cannot append to static array `%s`", se.e1.type.toChars());
10296 return setError();
10297 }
10298 }
10299
10300 exp.e1 = exp.e1.modifiableLvalue(sc, exp.e1);
9c7d5e88 10301 if (exp.e1.op == EXP.error)
5fee5ec3
IB
10302 {
10303 result = exp.e1;
10304 return;
10305 }
9c7d5e88 10306 if (exp.e2.op == EXP.error)
5fee5ec3
IB
10307 {
10308 result = exp.e2;
10309 return;
10310 }
10311
10312 if (checkNonAssignmentArrayOp(exp.e2))
10313 return setError();
10314
10315 Type tb1 = exp.e1.type.toBasetype();
10316 Type tb1next = tb1.nextOf();
10317 Type tb2 = exp.e2.type.toBasetype();
10318
10319 /* Possibilities:
9c7d5e88
IB
10320 * EXP.concatenateAssign: appending T[] to T[]
10321 * EXP.concatenateElemAssign: appending T to T[]
10322 * EXP.concatenateDcharAssign: appending dchar to T[]
5fee5ec3
IB
10323 */
10324 if ((tb1.ty == Tarray) &&
10325 (tb2.ty == Tarray || tb2.ty == Tsarray) &&
10326 (exp.e2.implicitConvTo(exp.e1.type) ||
10327 (tb2.nextOf().implicitConvTo(tb1next) &&
10328 (tb2.nextOf().size(Loc.initial) == tb1next.size(Loc.initial)))))
10329 {
9c7d5e88
IB
10330 // EXP.concatenateAssign
10331 assert(exp.op == EXP.concatenateAssign);
5fee5ec3
IB
10332 if (exp.e1.checkPostblit(sc, tb1next))
10333 return setError();
10334
10335 exp.e2 = exp.e2.castTo(sc, exp.e1.type);
10336 }
10337 else if ((tb1.ty == Tarray) && exp.e2.implicitConvTo(tb1next))
10338 {
10339 /* https://issues.dlang.org/show_bug.cgi?id=19782
10340 *
10341 * If e2 is implicitly convertible to tb1next, the conversion
10342 * might be done through alias this, in which case, e2 needs to
10343 * be modified accordingly (e2 => e2.aliasthis).
10344 */
10345 if (tb2.ty == Tstruct && (cast(TypeStruct)tb2).implicitConvToThroughAliasThis(tb1next))
10346 goto Laliasthis;
10347 if (tb2.ty == Tclass && (cast(TypeClass)tb2).implicitConvToThroughAliasThis(tb1next))
10348 goto Laliasthis;
10349 // Append element
10350 if (exp.e2.checkPostblit(sc, tb2))
10351 return setError();
10352
10353 if (checkNewEscape(sc, exp.e2, false))
10354 return setError();
10355
10356 exp = new CatElemAssignExp(exp.loc, exp.type, exp.e1, exp.e2.castTo(sc, tb1next));
10357 exp.e2 = doCopyOrMove(sc, exp.e2);
10358 }
10359 else if (tb1.ty == Tarray &&
10360 (tb1next.ty == Tchar || tb1next.ty == Twchar) &&
10361 exp.e2.type.ty != tb1next.ty &&
10362 exp.e2.implicitConvTo(Type.tdchar))
10363 {
10364 // Append dchar to char[] or wchar[]
10365 exp = new CatDcharAssignExp(exp.loc, exp.type, exp.e1, exp.e2.castTo(sc, Type.tdchar));
10366
10367 /* Do not allow appending wchar to char[] because if wchar happens
10368 * to be a surrogate pair, nothing good can result.
10369 */
10370 }
10371 else
10372 {
10373 // Try alias this on first operand
10374 static Expression tryAliasThisForLhs(BinAssignExp exp, Scope* sc)
10375 {
10376 AggregateDeclaration ad1 = isAggregate(exp.e1.type);
10377 if (!ad1 || !ad1.aliasthis)
10378 return null;
10379
10380 /* Rewrite (e1 op e2) as:
10381 * (e1.aliasthis op e2)
10382 */
10383 if (isRecursiveAliasThis(exp.att1, exp.e1.type))
10384 return null;
31350635 10385 //printf("att %s e1 = %s\n", Token.toChars(e.op), e.e1.type.toChars());
5fee5ec3
IB
10386 Expression e1 = new DotIdExp(exp.loc, exp.e1, ad1.aliasthis.ident);
10387 BinExp be = cast(BinExp)exp.copy();
10388 be.e1 = e1;
10389 return be.trySemantic(sc);
10390 }
10391
10392 // Try alias this on second operand
10393 static Expression tryAliasThisForRhs(BinAssignExp exp, Scope* sc)
10394 {
10395 AggregateDeclaration ad2 = isAggregate(exp.e2.type);
10396 if (!ad2 || !ad2.aliasthis)
10397 return null;
10398 /* Rewrite (e1 op e2) as:
10399 * (e1 op e2.aliasthis)
10400 */
10401 if (isRecursiveAliasThis(exp.att2, exp.e2.type))
10402 return null;
31350635 10403 //printf("att %s e2 = %s\n", Token.toChars(e.op), e.e2.type.toChars());
5fee5ec3
IB
10404 Expression e2 = new DotIdExp(exp.loc, exp.e2, ad2.aliasthis.ident);
10405 BinExp be = cast(BinExp)exp.copy();
10406 be.e2 = e2;
10407 return be.trySemantic(sc);
10408 }
10409
10410 Laliasthis:
10411 result = tryAliasThisForLhs(exp, sc);
10412 if (result)
10413 return;
10414
10415 result = tryAliasThisForRhs(exp, sc);
10416 if (result)
10417 return;
10418
10419 exp.error("cannot append type `%s` to type `%s`", tb2.toChars(), tb1.toChars());
10420 return setError();
10421 }
10422
10423 if (exp.e2.checkValue() || exp.e2.checkSharedAccess(sc))
10424 return setError();
10425
10426 exp.type = exp.e1.type;
6d799f0a 10427 auto assignElem = exp.e2;
5fee5ec3 10428 auto res = exp.reorderSettingAAElem(sc);
6d799f0a
IB
10429 if (res != exp) // `AA[k] = v` rewrite was performed
10430 checkNewEscape(sc, assignElem, false);
10431 else if (exp.op == EXP.concatenateElemAssign || exp.op == EXP.concatenateDcharAssign)
31350635 10432 checkAssignEscape(sc, res, false, false);
6d799f0a 10433
5fee5ec3 10434 result = res;
5eb9927a
IB
10435
10436 if ((exp.op == EXP.concatenateAssign || exp.op == EXP.concatenateElemAssign) &&
10437 !(sc.flags & (SCOPE.ctfe | SCOPE.compile)))
10438 {
10439 // if aa ordering is triggered, `res` will be a CommaExp
10440 // and `.e2` will be the rewritten original expression.
10441
10442 // `output` will point to the expression that the lowering will overwrite
10443 Expression* output;
10444 if (auto comma = res.isCommaExp())
10445 {
10446 output = &comma.e2;
10447 // manual cast because it could be either CatAssignExp or CatElemAssignExp
10448 exp = cast(CatAssignExp)comma.e2;
10449 }
10450 else
10451 {
10452 output = &result;
10453 exp = cast(CatAssignExp)result;
10454 }
10455
10456 if (exp.op == EXP.concatenateAssign)
10457 {
10458 Identifier hook = global.params.tracegc ? Id._d_arrayappendTTrace : Id._d_arrayappendT;
10459
10460 if (!verifyHookExist(exp.loc, *sc, hook, "appending array to arrays", Id.object))
10461 return setError();
10462
10463 // Lower to object._d_arrayappendT{,Trace}({file, line, funcname}, e1, e2)
10464 Expression id = new IdentifierExp(exp.loc, Id.empty);
10465 id = new DotIdExp(exp.loc, id, Id.object);
10466 id = new DotIdExp(exp.loc, id, hook);
10467
10468 auto arguments = new Expressions();
10469 arguments.reserve(5);
10470 if (global.params.tracegc)
10471 {
10472 auto funcname = (sc.callsc && sc.callsc.func) ? sc.callsc.func.toPrettyChars() : sc.func.toPrettyChars();
10473 arguments.push(new StringExp(exp.loc, exp.loc.filename.toDString()));
10474 arguments.push(new IntegerExp(exp.loc, exp.loc.linnum, Type.tint32));
10475 arguments.push(new StringExp(exp.loc, funcname.toDString()));
10476 }
10477
10478 arguments.push(exp.e1);
10479 arguments.push(exp.e2);
10480 Expression ce = new CallExp(exp.loc, id, arguments);
10481 *output = ce.expressionSemantic(sc);
10482 }
10483 else if (exp.op == EXP.concatenateElemAssign)
10484 {
10485 /* Do not lower concats to the indices array returned by
10486 *`static foreach`, as this array is only used at compile-time.
10487 */
10488 if (auto ve = exp.e1.isVarExp)
10489 {
10490 import core.stdc.ctype : isdigit;
10491 // The name of the indices array that static foreach loops uses.
10492 // See dmd.cond.lowerNonArrayAggregate
10493 enum varName = "__res";
10494 const(char)[] id = ve.var.ident.toString;
10495 if (ve.var.storage_class & STC.temp && id.length > varName.length &&
10496 id[0 .. varName.length] == varName && id[varName.length].isdigit)
10497 return;
10498 }
10499
10500 Identifier hook = global.params.tracegc ? Id._d_arrayappendcTXTrace : Id._d_arrayappendcTX;
10501 if (!verifyHookExist(exp.loc, *sc, Id._d_arrayappendcTXImpl, "appending element to arrays", Id.object))
10502 return setError();
10503
10504 // Lower to object._d_arrayappendcTXImpl!(typeof(e1))._d_arrayappendcTX{,Trace}(e1, 1), e1[$-1]=e2
10505 Expression id = new IdentifierExp(exp.loc, Id.empty);
10506 id = new DotIdExp(exp.loc, id, Id.object);
10507 auto tiargs = new Objects();
10508 tiargs.push(exp.e1.type);
10509 id = new DotTemplateInstanceExp(exp.loc, id, Id._d_arrayappendcTXImpl, tiargs);
10510 id = new DotIdExp(exp.loc, id, hook);
10511
10512 auto arguments = new Expressions();
10513 arguments.reserve(5);
10514 if (global.params.tracegc)
10515 {
10516 auto funcname = (sc.callsc && sc.callsc.func) ? sc.callsc.func.toPrettyChars() : sc.func.toPrettyChars();
10517 arguments.push(new StringExp(exp.loc, exp.loc.filename.toDString()));
10518 arguments.push(new IntegerExp(exp.loc, exp.loc.linnum, Type.tint32));
10519 arguments.push(new StringExp(exp.loc, funcname.toDString()));
10520 }
10521
10522 Expression eValue1;
10523 Expression value1 = extractSideEffect(sc, "__appendtmp", eValue1, exp.e1);
10524
10525 arguments.push(value1);
10526 arguments.push(new IntegerExp(exp.loc, 1, Type.tsize_t));
10527
10528 Expression ce = new CallExp(exp.loc, id, arguments);
10529
10530 Expression eValue2;
10531 Expression value2 = exp.e2;
10532 if (!value2.isVarExp() && !value2.isConst())
10533 {
10534 /* Before the template hook, this check was performed in e2ir.d
10535 * for expressions like `a ~= a[$-1]`. Here, $ will be modified
10536 * by calling `_d_arrayappendcT`, so we need to save `a[$-1]` in
10537 * a temporary variable.
10538 */
10539 value2 = extractSideEffect(sc, "__appendtmp", eValue2, value2, true);
10540 exp.e2 = value2;
10541
10542 // `__appendtmp*` will be destroyed together with the array `exp.e1`.
10543 auto vd = eValue2.isDeclarationExp().declaration.isVarDeclaration();
10544 vd.storage_class |= STC.nodtor;
b6df1132
IB
10545 // Be more explicit that this "declaration" is local to the expression
10546 vd.storage_class |= STC.exptemp;
5eb9927a
IB
10547 }
10548
10549 auto ale = new ArrayLengthExp(exp.loc, value1);
10550 auto elem = new IndexExp(exp.loc, value1, new MinExp(exp.loc, ale, IntegerExp.literal!1));
10551 auto ae = new ConstructExp(exp.loc, elem, value2);
10552
10553 auto e0 = Expression.combine(ce, ae).expressionSemantic(sc);
10554 e0 = Expression.combine(e0, value1);
10555 e0 = Expression.combine(eValue1, e0);
10556
10557 e0 = Expression.combine(eValue2, e0);
10558
10559 *output = e0.expressionSemantic(sc);
10560 }
10561 }
10562
5fee5ec3
IB
10563 }
10564
10565 override void visit(AddExp exp)
10566 {
10567 static if (LOGSEMANTIC)
10568 {
10569 printf("AddExp::semantic('%s')\n", exp.toChars());
10570 }
10571 if (exp.type)
10572 {
10573 result = exp;
10574 return;
10575 }
10576
10577 if (Expression ex = binSemanticProp(exp, sc))
10578 {
10579 result = ex;
10580 return;
10581 }
10582 Expression e = exp.op_overload(sc);
10583 if (e)
10584 {
10585 result = e;
10586 return;
10587 }
10588
0fb57034
IB
10589 /* ImportC: convert arrays to pointers, functions to pointers to functions
10590 */
10591 exp.e1 = exp.e1.arrayFuncConv(sc);
10592 exp.e2 = exp.e2.arrayFuncConv(sc);
10593
5fee5ec3
IB
10594 Type tb1 = exp.e1.type.toBasetype();
10595 Type tb2 = exp.e2.type.toBasetype();
10596
10597 bool err = false;
10598 if (tb1.ty == Tdelegate || tb1.isPtrToFunction())
10599 {
10600 err |= exp.e1.checkArithmetic() || exp.e1.checkSharedAccess(sc);
10601 }
10602 if (tb2.ty == Tdelegate || tb2.isPtrToFunction())
10603 {
10604 err |= exp.e2.checkArithmetic() || exp.e2.checkSharedAccess(sc);
10605 }
10606 if (err)
10607 return setError();
10608
10609 if (tb1.ty == Tpointer && exp.e2.type.isintegral() || tb2.ty == Tpointer && exp.e1.type.isintegral())
10610 {
10611 result = scaleFactor(exp, sc);
10612 return;
10613 }
10614
10615 if (tb1.ty == Tpointer && tb2.ty == Tpointer)
10616 {
10617 result = exp.incompatibleTypes();
10618 return;
10619 }
10620
10621 if (Expression ex = typeCombine(exp, sc))
10622 {
10623 result = ex;
10624 return;
10625 }
10626
10627 Type tb = exp.type.toBasetype();
10628 if (tb.ty == Tarray || tb.ty == Tsarray)
10629 {
10630 if (!isArrayOpValid(exp))
10631 {
10632 result = arrayOpInvalidError(exp);
10633 return;
10634 }
10635 result = exp;
10636 return;
10637 }
10638
10639 tb1 = exp.e1.type.toBasetype();
10640 if (!target.isVectorOpSupported(tb1, exp.op, tb2))
10641 {
10642 result = exp.incompatibleTypes();
10643 return;
10644 }
10645 if ((tb1.isreal() && exp.e2.type.isimaginary()) || (tb1.isimaginary() && exp.e2.type.isreal()))
10646 {
10647 switch (exp.type.toBasetype().ty)
10648 {
10649 case Tfloat32:
10650 case Timaginary32:
10651 exp.type = Type.tcomplex32;
10652 break;
10653
10654 case Tfloat64:
10655 case Timaginary64:
10656 exp.type = Type.tcomplex64;
10657 break;
10658
10659 case Tfloat80:
10660 case Timaginary80:
10661 exp.type = Type.tcomplex80;
10662 break;
10663
10664 default:
10665 assert(0);
10666 }
10667 }
10668 result = exp;
10669 }
10670
10671 override void visit(MinExp exp)
10672 {
10673 static if (LOGSEMANTIC)
10674 {
10675 printf("MinExp::semantic('%s')\n", exp.toChars());
10676 }
10677 if (exp.type)
10678 {
10679 result = exp;
10680 return;
10681 }
10682
10683 if (Expression ex = binSemanticProp(exp, sc))
10684 {
10685 result = ex;
10686 return;
10687 }
10688 Expression e = exp.op_overload(sc);
10689 if (e)
10690 {
10691 result = e;
10692 return;
10693 }
10694
0fb57034
IB
10695 /* ImportC: convert arrays to pointers, functions to pointers to functions
10696 */
10697 exp.e1 = exp.e1.arrayFuncConv(sc);
10698 exp.e2 = exp.e2.arrayFuncConv(sc);
10699
5fee5ec3
IB
10700 Type t1 = exp.e1.type.toBasetype();
10701 Type t2 = exp.e2.type.toBasetype();
10702
10703 bool err = false;
10704 if (t1.ty == Tdelegate || t1.isPtrToFunction())
10705 {
10706 err |= exp.e1.checkArithmetic() || exp.e1.checkSharedAccess(sc);
10707 }
10708 if (t2.ty == Tdelegate || t2.isPtrToFunction())
10709 {
10710 err |= exp.e2.checkArithmetic() || exp.e2.checkSharedAccess(sc);
10711 }
10712 if (err)
10713 return setError();
10714
10715 if (t1.ty == Tpointer)
10716 {
10717 if (t2.ty == Tpointer)
10718 {
10719 // https://dlang.org/spec/expression.html#add_expressions
10720 // "If both operands are pointers, and the operator is -, the pointers are
10721 // subtracted and the result is divided by the size of the type pointed to
10722 // by the operands. It is an error if the pointers point to different types."
10723 Type p1 = t1.nextOf();
10724 Type p2 = t2.nextOf();
10725
10726 if (!p1.equivalent(p2))
10727 {
10728 // Deprecation to remain for at least a year, after which this should be
10729 // changed to an error
10730 // See https://github.com/dlang/dmd/pull/7332
10731 deprecation(exp.loc,
10732 "cannot subtract pointers to different types: `%s` and `%s`.",
10733 t1.toChars(), t2.toChars());
10734 }
10735
10736 // Need to divide the result by the stride
10737 // Replace (ptr - ptr) with (ptr - ptr) / stride
fbdaa581 10738 long stride;
5fee5ec3
IB
10739
10740 // make sure pointer types are compatible
10741 if (Expression ex = typeCombine(exp, sc))
10742 {
10743 result = ex;
10744 return;
10745 }
10746
10747 exp.type = Type.tptrdiff_t;
10748 stride = t2.nextOf().size();
10749 if (stride == 0)
10750 {
10751 e = new IntegerExp(exp.loc, 0, Type.tptrdiff_t);
10752 }
fbdaa581 10753 else if (stride == cast(long)SIZE_INVALID)
9c7d5e88 10754 e = ErrorExp.get();
5fee5ec3
IB
10755 else
10756 {
10757 e = new DivExp(exp.loc, exp, new IntegerExp(Loc.initial, stride, Type.tptrdiff_t));
10758 e.type = Type.tptrdiff_t;
10759 }
10760 }
10761 else if (t2.isintegral())
10762 e = scaleFactor(exp, sc);
10763 else
10764 {
10765 exp.error("can't subtract `%s` from pointer", t2.toChars());
10766 e = ErrorExp.get();
10767 }
10768 result = e;
10769 return;
10770 }
10771 if (t2.ty == Tpointer)
10772 {
10773 exp.type = exp.e2.type;
10774 exp.error("can't subtract pointer from `%s`", exp.e1.type.toChars());
10775 return setError();
10776 }
10777
10778 if (Expression ex = typeCombine(exp, sc))
10779 {
10780 result = ex;
10781 return;
10782 }
10783
10784 Type tb = exp.type.toBasetype();
10785 if (tb.ty == Tarray || tb.ty == Tsarray)
10786 {
10787 if (!isArrayOpValid(exp))
10788 {
10789 result = arrayOpInvalidError(exp);
10790 return;
10791 }
10792 result = exp;
10793 return;
10794 }
10795
10796 t1 = exp.e1.type.toBasetype();
10797 t2 = exp.e2.type.toBasetype();
10798 if (!target.isVectorOpSupported(t1, exp.op, t2))
10799 {
10800 result = exp.incompatibleTypes();
10801 return;
10802 }
10803 if ((t1.isreal() && t2.isimaginary()) || (t1.isimaginary() && t2.isreal()))
10804 {
10805 switch (exp.type.ty)
10806 {
10807 case Tfloat32:
10808 case Timaginary32:
10809 exp.type = Type.tcomplex32;
10810 break;
10811
10812 case Tfloat64:
10813 case Timaginary64:
10814 exp.type = Type.tcomplex64;
10815 break;
10816
10817 case Tfloat80:
10818 case Timaginary80:
10819 exp.type = Type.tcomplex80;
10820 break;
10821
10822 default:
10823 assert(0);
10824 }
10825 }
10826 result = exp;
10827 return;
10828 }
10829
10830 override void visit(CatExp exp)
10831 {
10832 // https://dlang.org/spec/expression.html#cat_expressions
10833 //printf("CatExp.semantic() %s\n", toChars());
10834 if (exp.type)
10835 {
10836 result = exp;
10837 return;
10838 }
10839
10840 if (Expression ex = binSemanticProp(exp, sc))
10841 {
10842 result = ex;
10843 return;
10844 }
10845 Expression e = exp.op_overload(sc);
10846 if (e)
10847 {
10848 result = e;
10849 return;
10850 }
10851
10852 Type tb1 = exp.e1.type.toBasetype();
10853 Type tb2 = exp.e2.type.toBasetype();
10854
10855 auto f1 = checkNonAssignmentArrayOp(exp.e1);
10856 auto f2 = checkNonAssignmentArrayOp(exp.e2);
10857 if (f1 || f2)
10858 return setError();
10859
10860 Type tb1next = tb1.nextOf();
10861 Type tb2next = tb2.nextOf();
10862
10863 // Check for: array ~ array
9c7d5e88 10864 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)))
5fee5ec3
IB
10865 {
10866 /* https://issues.dlang.org/show_bug.cgi?id=9248
10867 * Here to avoid the case of:
10868 * void*[] a = [cast(void*)1];
10869 * void*[] b = [cast(void*)2];
10870 * a ~ b;
10871 * becoming:
10872 * a ~ [cast(void*)b];
10873 */
10874
10875 /* https://issues.dlang.org/show_bug.cgi?id=14682
10876 * Also to avoid the case of:
10877 * int[][] a;
10878 * a ~ [];
10879 * becoming:
10880 * a ~ cast(int[])[];
10881 */
10882 goto Lpeer;
10883 }
10884
10885 // Check for: array ~ element
10886 if ((tb1.ty == Tsarray || tb1.ty == Tarray) && tb2.ty != Tvoid)
10887 {
9c7d5e88 10888 if (exp.e1.op == EXP.arrayLiteral)
5fee5ec3
IB
10889 {
10890 exp.e2 = doCopyOrMove(sc, exp.e2);
10891 // https://issues.dlang.org/show_bug.cgi?id=14686
10892 // Postblit call appears in AST, and this is
10893 // finally translated to an ArrayLiteralExp in below optimize().
10894 }
9c7d5e88 10895 else if (exp.e1.op == EXP.string_)
5fee5ec3
IB
10896 {
10897 // No postblit call exists on character (integer) value.
10898 }
10899 else
10900 {
10901 if (exp.e2.checkPostblit(sc, tb2))
10902 return setError();
10903 // Postblit call will be done in runtime helper function
10904 }
10905
9c7d5e88 10906 if (exp.e1.op == EXP.arrayLiteral && exp.e1.implicitConvTo(tb2.arrayOf()))
5fee5ec3
IB
10907 {
10908 exp.e1 = exp.e1.implicitCastTo(sc, tb2.arrayOf());
10909 exp.type = tb2.arrayOf();
10910 goto L2elem;
10911 }
10912 if (exp.e2.implicitConvTo(tb1next) >= MATCH.convert)
10913 {
10914 exp.e2 = exp.e2.implicitCastTo(sc, tb1next);
10915 exp.type = tb1next.arrayOf();
10916 L2elem:
10917 if (tb2.ty == Tarray || tb2.ty == Tsarray)
10918 {
10919 // Make e2 into [e2]
10920 exp.e2 = new ArrayLiteralExp(exp.e2.loc, exp.type, exp.e2);
10921 }
10922 else if (checkNewEscape(sc, exp.e2, false))
10923 return setError();
10924 result = exp.optimize(WANTvalue);
10925 return;
10926 }
10927 }
10928 // Check for: element ~ array
10929 if ((tb2.ty == Tsarray || tb2.ty == Tarray) && tb1.ty != Tvoid)
10930 {
9c7d5e88 10931 if (exp.e2.op == EXP.arrayLiteral)
5fee5ec3
IB
10932 {
10933 exp.e1 = doCopyOrMove(sc, exp.e1);
10934 }
9c7d5e88 10935 else if (exp.e2.op == EXP.string_)
5fee5ec3
IB
10936 {
10937 }
10938 else
10939 {
10940 if (exp.e1.checkPostblit(sc, tb1))
10941 return setError();
10942 }
10943
9c7d5e88 10944 if (exp.e2.op == EXP.arrayLiteral && exp.e2.implicitConvTo(tb1.arrayOf()))
5fee5ec3
IB
10945 {
10946 exp.e2 = exp.e2.implicitCastTo(sc, tb1.arrayOf());
10947 exp.type = tb1.arrayOf();
10948 goto L1elem;
10949 }
10950 if (exp.e1.implicitConvTo(tb2next) >= MATCH.convert)
10951 {
10952 exp.e1 = exp.e1.implicitCastTo(sc, tb2next);
10953 exp.type = tb2next.arrayOf();
10954 L1elem:
10955 if (tb1.ty == Tarray || tb1.ty == Tsarray)
10956 {
10957 // Make e1 into [e1]
10958 exp.e1 = new ArrayLiteralExp(exp.e1.loc, exp.type, exp.e1);
10959 }
10960 else if (checkNewEscape(sc, exp.e1, false))
10961 return setError();
10962 result = exp.optimize(WANTvalue);
10963 return;
10964 }
10965 }
10966
10967 Lpeer:
10968 if ((tb1.ty == Tsarray || tb1.ty == Tarray) && (tb2.ty == Tsarray || tb2.ty == Tarray) && (tb1next.mod || tb2next.mod) && (tb1next.mod != tb2next.mod))
10969 {
10970 Type t1 = tb1next.mutableOf().constOf().arrayOf();
10971 Type t2 = tb2next.mutableOf().constOf().arrayOf();
9c7d5e88 10972 if (exp.e1.op == EXP.string_ && !(cast(StringExp)exp.e1).committed)
5fee5ec3
IB
10973 exp.e1.type = t1;
10974 else
10975 exp.e1 = exp.e1.castTo(sc, t1);
9c7d5e88 10976 if (exp.e2.op == EXP.string_ && !(cast(StringExp)exp.e2).committed)
5fee5ec3
IB
10977 exp.e2.type = t2;
10978 else
10979 exp.e2 = exp.e2.castTo(sc, t2);
10980 }
10981
10982 if (Expression ex = typeCombine(exp, sc))
10983 {
10984 result = ex;
10985 return;
10986 }
10987 exp.type = exp.type.toHeadMutable();
10988
10989 Type tb = exp.type.toBasetype();
10990 if (tb.ty == Tsarray)
10991 exp.type = tb.nextOf().arrayOf();
10992 if (exp.type.ty == Tarray && tb1next && tb2next && tb1next.mod != tb2next.mod)
10993 {
10994 exp.type = exp.type.nextOf().toHeadMutable().arrayOf();
10995 }
10996 if (Type tbn = tb.nextOf())
10997 {
10998 if (exp.checkPostblit(sc, tbn))
10999 return setError();
11000 }
11001 Type t1 = exp.e1.type.toBasetype();
11002 Type t2 = exp.e2.type.toBasetype();
11003 if ((t1.ty == Tarray || t1.ty == Tsarray) &&
11004 (t2.ty == Tarray || t2.ty == Tsarray))
11005 {
11006 // Normalize to ArrayLiteralExp or StringExp as far as possible
11007 e = exp.optimize(WANTvalue);
11008 }
11009 else
11010 {
11011 //printf("(%s) ~ (%s)\n", e1.toChars(), e2.toChars());
11012 result = exp.incompatibleTypes();
11013 return;
11014 }
11015
11016 result = e;
11017 }
11018
11019 override void visit(MulExp exp)
11020 {
11021 version (none)
11022 {
11023 printf("MulExp::semantic() %s\n", exp.toChars());
11024 }
11025 if (exp.type)
11026 {
11027 result = exp;
11028 return;
11029 }
11030
11031 if (Expression ex = binSemanticProp(exp, sc))
11032 {
11033 result = ex;
11034 return;
11035 }
11036 Expression e = exp.op_overload(sc);
11037 if (e)
11038 {
11039 result = e;
11040 return;
11041 }
11042
11043 if (Expression ex = typeCombine(exp, sc))
11044 {
11045 result = ex;
11046 return;
11047 }
11048
11049 Type tb = exp.type.toBasetype();
11050 if (tb.ty == Tarray || tb.ty == Tsarray)
11051 {
11052 if (!isArrayOpValid(exp))
11053 {
11054 result = arrayOpInvalidError(exp);
11055 return;
11056 }
11057 result = exp;
11058 return;
11059 }
11060
11061 if (exp.checkArithmeticBin() || exp.checkSharedAccessBin(sc))
11062 return setError();
11063
11064 if (exp.type.isfloating())
11065 {
11066 Type t1 = exp.e1.type;
11067 Type t2 = exp.e2.type;
11068
11069 if (t1.isreal())
11070 {
11071 exp.type = t2;
11072 }
11073 else if (t2.isreal())
11074 {
11075 exp.type = t1;
11076 }
11077 else if (t1.isimaginary())
11078 {
11079 if (t2.isimaginary())
11080 {
11081 switch (t1.toBasetype().ty)
11082 {
11083 case Timaginary32:
11084 exp.type = Type.tfloat32;
11085 break;
11086
11087 case Timaginary64:
11088 exp.type = Type.tfloat64;
11089 break;
11090
11091 case Timaginary80:
11092 exp.type = Type.tfloat80;
11093 break;
11094
11095 default:
11096 assert(0);
11097 }
11098
11099 // iy * iv = -yv
11100 exp.e1.type = exp.type;
11101 exp.e2.type = exp.type;
11102 e = new NegExp(exp.loc, exp);
11103 e = e.expressionSemantic(sc);
11104 result = e;
11105 return;
11106 }
11107 else
11108 exp.type = t2; // t2 is complex
11109 }
11110 else if (t2.isimaginary())
11111 {
11112 exp.type = t1; // t1 is complex
11113 }
11114 }
11115 else if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype()))
11116 {
11117 result = exp.incompatibleTypes();
11118 return;
11119 }
11120 result = exp;
11121 }
11122
11123 override void visit(DivExp exp)
11124 {
11125 if (exp.type)
11126 {
11127 result = exp;
11128 return;
11129 }
11130
11131 if (Expression ex = binSemanticProp(exp, sc))
11132 {
11133 result = ex;
11134 return;
11135 }
11136 Expression e = exp.op_overload(sc);
11137 if (e)
11138 {
11139 result = e;
11140 return;
11141 }
11142
11143 if (Expression ex = typeCombine(exp, sc))
11144 {
11145 result = ex;
11146 return;
11147 }
11148
11149 Type tb = exp.type.toBasetype();
11150 if (tb.ty == Tarray || tb.ty == Tsarray)
11151 {
11152 if (!isArrayOpValid(exp))
11153 {
11154 result = arrayOpInvalidError(exp);
11155 return;
11156 }
11157 result = exp;
11158 return;
11159 }
11160
11161 if (exp.checkArithmeticBin() || exp.checkSharedAccessBin(sc))
11162 return setError();
11163
11164 if (exp.type.isfloating())
11165 {
11166 Type t1 = exp.e1.type;
11167 Type t2 = exp.e2.type;
11168
11169 if (t1.isreal())
11170 {
11171 exp.type = t2;
11172 if (t2.isimaginary())
11173 {
11174 // x/iv = i(-x/v)
11175 exp.e2.type = t1;
11176 e = new NegExp(exp.loc, exp);
11177 e = e.expressionSemantic(sc);
11178 result = e;
11179 return;
11180 }
11181 }
11182 else if (t2.isreal())
11183 {
11184 exp.type = t1;
11185 }
11186 else if (t1.isimaginary())
11187 {
11188 if (t2.isimaginary())
11189 {
11190 switch (t1.toBasetype().ty)
11191 {
11192 case Timaginary32:
11193 exp.type = Type.tfloat32;
11194 break;
11195
11196 case Timaginary64:
11197 exp.type = Type.tfloat64;
11198 break;
11199
11200 case Timaginary80:
11201 exp.type = Type.tfloat80;
11202 break;
11203
11204 default:
11205 assert(0);
11206 }
11207 }
11208 else
11209 exp.type = t2; // t2 is complex
11210 }
11211 else if (t2.isimaginary())
11212 {
11213 exp.type = t1; // t1 is complex
11214 }
11215 }
11216 else if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype()))
11217 {
11218 result = exp.incompatibleTypes();
11219 return;
11220 }
11221 result = exp;
11222 }
11223
11224 override void visit(ModExp exp)
11225 {
11226 if (exp.type)
11227 {
11228 result = exp;
11229 return;
11230 }
11231
11232 if (Expression ex = binSemanticProp(exp, sc))
11233 {
11234 result = ex;
11235 return;
11236 }
11237 Expression e = exp.op_overload(sc);
11238 if (e)
11239 {
11240 result = e;
11241 return;
11242 }
11243
11244 if (Expression ex = typeCombine(exp, sc))
11245 {
11246 result = ex;
11247 return;
11248 }
11249
11250 Type tb = exp.type.toBasetype();
11251 if (tb.ty == Tarray || tb.ty == Tsarray)
11252 {
11253 if (!isArrayOpValid(exp))
11254 {
11255 result = arrayOpInvalidError(exp);
11256 return;
11257 }
11258 result = exp;
11259 return;
11260 }
11261 if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype()))
11262 {
11263 result = exp.incompatibleTypes();
11264 return;
11265 }
11266
11267 if (exp.checkArithmeticBin() || exp.checkSharedAccessBin(sc))
11268 return setError();
11269
11270 if (exp.type.isfloating())
11271 {
11272 exp.type = exp.e1.type;
11273 if (exp.e2.type.iscomplex())
11274 {
11275 exp.error("cannot perform modulo complex arithmetic");
11276 return setError();
11277 }
11278 }
11279 result = exp;
11280 }
11281
11282 override void visit(PowExp exp)
11283 {
11284 if (exp.type)
11285 {
11286 result = exp;
11287 return;
11288 }
11289
11290 //printf("PowExp::semantic() %s\n", toChars());
11291 if (Expression ex = binSemanticProp(exp, sc))
11292 {
11293 result = ex;
11294 return;
11295 }
11296 Expression e = exp.op_overload(sc);
11297 if (e)
11298 {
11299 result = e;
11300 return;
11301 }
11302
11303 if (Expression ex = typeCombine(exp, sc))
11304 {
11305 result = ex;
11306 return;
11307 }
11308
11309 Type tb = exp.type.toBasetype();
11310 if (tb.ty == Tarray || tb.ty == Tsarray)
11311 {
11312 if (!isArrayOpValid(exp))
11313 {
11314 result = arrayOpInvalidError(exp);
11315 return;
11316 }
11317 result = exp;
11318 return;
11319 }
11320
11321 if (exp.checkArithmeticBin() || exp.checkSharedAccessBin(sc))
11322 return setError();
11323
11324 if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype()))
11325 {
11326 result = exp.incompatibleTypes();
11327 return;
11328 }
11329
11330 // First, attempt to fold the expression.
11331 e = exp.optimize(WANTvalue);
9c7d5e88 11332 if (e.op != EXP.pow)
5fee5ec3
IB
11333 {
11334 e = e.expressionSemantic(sc);
11335 result = e;
11336 return;
11337 }
11338
f99303eb 11339 Module mmath = Module.loadStdMath();
5fee5ec3
IB
11340 if (!mmath)
11341 {
11342 e.error("`%s` requires `std.math` for `^^` operators", e.toChars());
11343 return setError();
11344 }
11345 e = new ScopeExp(exp.loc, mmath);
11346
9c7d5e88 11347 if (exp.e2.op == EXP.float64 && exp.e2.toReal() == CTFloat.half)
5fee5ec3
IB
11348 {
11349 // Replace e1 ^^ 0.5 with .std.math.sqrt(e1)
11350 e = new CallExp(exp.loc, new DotIdExp(exp.loc, e, Id._sqrt), exp.e1);
11351 }
11352 else
11353 {
11354 // Replace e1 ^^ e2 with .std.math.pow(e1, e2)
11355 e = new CallExp(exp.loc, new DotIdExp(exp.loc, e, Id._pow), exp.e1, exp.e2);
11356 }
11357 e = e.expressionSemantic(sc);
11358 result = e;
11359 return;
11360 }
11361
11362 override void visit(ShlExp exp)
11363 {
11364 //printf("ShlExp::semantic(), type = %p\n", type);
11365 if (exp.type)
11366 {
11367 result = exp;
11368 return;
11369 }
11370
11371 if (Expression ex = binSemanticProp(exp, sc))
11372 {
11373 result = ex;
11374 return;
11375 }
11376 Expression e = exp.op_overload(sc);
11377 if (e)
11378 {
11379 result = e;
11380 return;
11381 }
11382
11383 if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc))
11384 return setError();
11385
11386 if (!target.isVectorOpSupported(exp.e1.type.toBasetype(), exp.op, exp.e2.type.toBasetype()))
11387 {
11388 result = exp.incompatibleTypes();
11389 return;
11390 }
11391 exp.e1 = integralPromotions(exp.e1, sc);
11392 if (exp.e2.type.toBasetype().ty != Tvector)
11393 exp.e2 = exp.e2.castTo(sc, Type.tshiftcnt);
11394
11395 exp.type = exp.e1.type;
11396 result = exp;
11397 }
11398
11399 override void visit(ShrExp exp)
11400 {
11401 if (exp.type)
11402 {
11403 result = exp;
11404 return;
11405 }
11406
11407 if (Expression ex = binSemanticProp(exp, sc))
11408 {
11409 result = ex;
11410 return;
11411 }
11412 Expression e = exp.op_overload(sc);
11413 if (e)
11414 {
11415 result = e;
11416 return;
11417 }
11418
11419 if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc))
11420 return setError();
11421
11422 if (!target.isVectorOpSupported(exp.e1.type.toBasetype(), exp.op, exp.e2.type.toBasetype()))
11423 {
11424 result = exp.incompatibleTypes();
11425 return;
11426 }
11427 exp.e1 = integralPromotions(exp.e1, sc);
11428 if (exp.e2.type.toBasetype().ty != Tvector)
11429 exp.e2 = exp.e2.castTo(sc, Type.tshiftcnt);
11430
11431 exp.type = exp.e1.type;
11432 result = exp;
11433 }
11434
11435 override void visit(UshrExp exp)
11436 {
11437 if (exp.type)
11438 {
11439 result = exp;
11440 return;
11441 }
11442
11443 if (Expression ex = binSemanticProp(exp, sc))
11444 {
11445 result = ex;
11446 return;
11447 }
11448 Expression e = exp.op_overload(sc);
11449 if (e)
11450 {
11451 result = e;
11452 return;
11453 }
11454
11455 if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc))
11456 return setError();
11457
11458 if (!target.isVectorOpSupported(exp.e1.type.toBasetype(), exp.op, exp.e2.type.toBasetype()))
11459 {
11460 result = exp.incompatibleTypes();
11461 return;
11462 }
11463 exp.e1 = integralPromotions(exp.e1, sc);
11464 if (exp.e2.type.toBasetype().ty != Tvector)
11465 exp.e2 = exp.e2.castTo(sc, Type.tshiftcnt);
11466
11467 exp.type = exp.e1.type;
11468 result = exp;
11469 }
11470
11471 override void visit(AndExp exp)
11472 {
11473 if (exp.type)
11474 {
11475 result = exp;
11476 return;
11477 }
11478
11479 if (Expression ex = binSemanticProp(exp, sc))
11480 {
11481 result = ex;
11482 return;
11483 }
11484 Expression e = exp.op_overload(sc);
11485 if (e)
11486 {
11487 result = e;
11488 return;
11489 }
11490
11491 if (exp.e1.type.toBasetype().ty == Tbool && exp.e2.type.toBasetype().ty == Tbool)
11492 {
11493 exp.type = exp.e1.type;
11494 result = exp;
11495 return;
11496 }
11497
11498 if (Expression ex = typeCombine(exp, sc))
11499 {
11500 result = ex;
11501 return;
11502 }
11503
11504 Type tb = exp.type.toBasetype();
11505 if (tb.ty == Tarray || tb.ty == Tsarray)
11506 {
11507 if (!isArrayOpValid(exp))
11508 {
11509 result = arrayOpInvalidError(exp);
11510 return;
11511 }
11512 result = exp;
11513 return;
11514 }
11515 if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype()))
11516 {
11517 result = exp.incompatibleTypes();
11518 return;
11519 }
11520 if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc))
11521 return setError();
11522
11523 result = exp;
11524 }
11525
11526 override void visit(OrExp exp)
11527 {
11528 if (exp.type)
11529 {
11530 result = exp;
11531 return;
11532 }
11533
11534 if (Expression ex = binSemanticProp(exp, sc))
11535 {
11536 result = ex;
11537 return;
11538 }
11539 Expression e = exp.op_overload(sc);
11540 if (e)
11541 {
11542 result = e;
11543 return;
11544 }
11545
11546 if (exp.e1.type.toBasetype().ty == Tbool && exp.e2.type.toBasetype().ty == Tbool)
11547 {
11548 exp.type = exp.e1.type;
11549 result = exp;
11550 return;
11551 }
11552
11553 if (Expression ex = typeCombine(exp, sc))
11554 {
11555 result = ex;
11556 return;
11557 }
11558
11559 Type tb = exp.type.toBasetype();
11560 if (tb.ty == Tarray || tb.ty == Tsarray)
11561 {
11562 if (!isArrayOpValid(exp))
11563 {
11564 result = arrayOpInvalidError(exp);
11565 return;
11566 }
11567 result = exp;
11568 return;
11569 }
11570 if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype()))
11571 {
11572 result = exp.incompatibleTypes();
11573 return;
11574 }
11575 if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc))
11576 return setError();
11577
11578 result = exp;
11579 }
11580
11581 override void visit(XorExp exp)
11582 {
11583 if (exp.type)
11584 {
11585 result = exp;
11586 return;
11587 }
11588
11589 if (Expression ex = binSemanticProp(exp, sc))
11590 {
11591 result = ex;
11592 return;
11593 }
11594 Expression e = exp.op_overload(sc);
11595 if (e)
11596 {
11597 result = e;
11598 return;
11599 }
11600
11601 if (exp.e1.type.toBasetype().ty == Tbool && exp.e2.type.toBasetype().ty == Tbool)
11602 {
11603 exp.type = exp.e1.type;
11604 result = exp;
11605 return;
11606 }
11607
11608 if (Expression ex = typeCombine(exp, sc))
11609 {
11610 result = ex;
11611 return;
11612 }
11613
11614 Type tb = exp.type.toBasetype();
11615 if (tb.ty == Tarray || tb.ty == Tsarray)
11616 {
11617 if (!isArrayOpValid(exp))
11618 {
11619 result = arrayOpInvalidError(exp);
11620 return;
11621 }
11622 result = exp;
11623 return;
11624 }
11625 if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype()))
11626 {
11627 result = exp.incompatibleTypes();
11628 return;
11629 }
11630 if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc))
11631 return setError();
11632
11633 result = exp;
11634 }
11635
11636 override void visit(LogicalExp exp)
11637 {
11638 static if (LOGSEMANTIC)
11639 {
11640 printf("LogicalExp::semantic() %s\n", exp.toChars());
11641 }
11642
11643 if (exp.type)
11644 {
11645 result = exp;
11646 return;
11647 }
11648
11649 exp.setNoderefOperands();
11650
11651 Expression e1x = exp.e1.expressionSemantic(sc);
11652
11653 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
9c7d5e88 11654 if (e1x.op == EXP.type)
5fee5ec3
IB
11655 e1x = resolveAliasThis(sc, e1x);
11656
11657 e1x = resolveProperties(sc, e1x);
11658 e1x = e1x.toBoolean(sc);
11659
11660 if (sc.flags & SCOPE.condition)
11661 {
11662 /* If in static if, don't evaluate e2 if we don't have to.
11663 */
11664 e1x = e1x.optimize(WANTvalue);
9c7d5e88 11665 if (e1x.toBool().hasValue(exp.op == EXP.orOr))
5fee5ec3 11666 {
235d5a96
IB
11667 if (sc.flags & SCOPE.Cfile)
11668 result = new IntegerExp(exp.op == EXP.orOr);
11669 else
11670 result = IntegerExp.createBool(exp.op == EXP.orOr);
5fee5ec3
IB
11671 return;
11672 }
11673 }
11674
11675 CtorFlow ctorflow = sc.ctorflow.clone();
11676 Expression e2x = exp.e2.expressionSemantic(sc);
11677 sc.merge(exp.loc, ctorflow);
11678 ctorflow.freeFieldinit();
11679
11680 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
9c7d5e88 11681 if (e2x.op == EXP.type)
5fee5ec3
IB
11682 e2x = resolveAliasThis(sc, e2x);
11683
11684 e2x = resolveProperties(sc, e2x);
11685
11686 auto f1 = checkNonAssignmentArrayOp(e1x);
11687 auto f2 = checkNonAssignmentArrayOp(e2x);
11688 if (f1 || f2)
11689 return setError();
11690
11691 // Unless the right operand is 'void', the expression is converted to 'bool'.
11692 if (e2x.type.ty != Tvoid)
11693 e2x = e2x.toBoolean(sc);
11694
9c7d5e88 11695 if (e2x.op == EXP.type || e2x.op == EXP.scope_)
5fee5ec3
IB
11696 {
11697 exp.error("`%s` is not an expression", exp.e2.toChars());
11698 return setError();
11699 }
9c7d5e88 11700 if (e1x.op == EXP.error || e1x.type.ty == Tnoreturn)
5fee5ec3
IB
11701 {
11702 result = e1x;
11703 return;
11704 }
9c7d5e88 11705 if (e2x.op == EXP.error)
5fee5ec3
IB
11706 {
11707 result = e2x;
11708 return;
11709 }
11710
11711 // The result type is 'bool', unless the right operand has type 'void'.
11712 if (e2x.type.ty == Tvoid)
11713 exp.type = Type.tvoid;
11714 else
235d5a96 11715 exp.type = (sc && sc.flags & SCOPE.Cfile) ? Type.tint32 : Type.tbool;
5fee5ec3
IB
11716
11717 exp.e1 = e1x;
11718 exp.e2 = e2x;
11719 result = exp;
11720 }
11721
11722
11723 override void visit(CmpExp exp)
11724 {
11725 static if (LOGSEMANTIC)
11726 {
11727 printf("CmpExp::semantic('%s')\n", exp.toChars());
11728 }
11729 if (exp.type)
11730 {
11731 result = exp;
11732 return;
11733 }
11734
11735 exp.setNoderefOperands();
11736
11737 if (Expression ex = binSemanticProp(exp, sc))
11738 {
11739 result = ex;
11740 return;
11741 }
11742 Type t1 = exp.e1.type.toBasetype();
11743 Type t2 = exp.e2.type.toBasetype();
9c7d5e88 11744 if (t1.ty == Tclass && exp.e2.op == EXP.null_ || t2.ty == Tclass && exp.e1.op == EXP.null_)
5fee5ec3
IB
11745 {
11746 exp.error("do not use `null` when comparing class types");
11747 return setError();
11748 }
11749
d7569187
IB
11750
11751 EXP cmpop = exp.op;
5fee5ec3
IB
11752 if (auto e = exp.op_overload(sc, &cmpop))
11753 {
11754 if (!e.type.isscalar() && e.type.equals(exp.e1.type))
11755 {
11756 exp.error("recursive `opCmp` expansion");
11757 return setError();
11758 }
9c7d5e88 11759 if (e.op == EXP.call)
5fee5ec3 11760 {
d7569187
IB
11761
11762 if (t1.ty == Tclass && t2.ty == Tclass)
11763 {
11764 // Lower to object.__cmp(e1, e2)
11765 Expression cl = new IdentifierExp(exp.loc, Id.empty);
11766 cl = new DotIdExp(exp.loc, cl, Id.object);
11767 cl = new DotIdExp(exp.loc, cl, Id.__cmp);
11768 cl = cl.expressionSemantic(sc);
11769
11770 auto arguments = new Expressions();
11771 // Check if op_overload found a better match by calling e2.opCmp(e1)
11772 // If the operands were swapped, then the result must be reversed
11773 // e1.opCmp(e2) == -e2.opCmp(e1)
11774 // cmpop takes care of this
11775 if (exp.op == cmpop)
11776 {
11777 arguments.push(exp.e1);
11778 arguments.push(exp.e2);
11779 }
11780 else
11781 {
11782 // Use better match found by op_overload
11783 arguments.push(exp.e2);
11784 arguments.push(exp.e1);
11785 }
11786
11787 cl = new CallExp(exp.loc, cl, arguments);
11788 cl = new CmpExp(cmpop, exp.loc, cl, new IntegerExp(0));
11789 result = cl.expressionSemantic(sc);
11790 return;
11791 }
11792
5fee5ec3
IB
11793 e = new CmpExp(cmpop, exp.loc, e, IntegerExp.literal!0);
11794 e = e.expressionSemantic(sc);
11795 }
11796 result = e;
11797 return;
11798 }
11799
d7569187 11800
5fee5ec3
IB
11801 if (Expression ex = typeCombine(exp, sc))
11802 {
11803 result = ex;
11804 return;
11805 }
11806
11807 auto f1 = checkNonAssignmentArrayOp(exp.e1);
11808 auto f2 = checkNonAssignmentArrayOp(exp.e2);
11809 if (f1 || f2)
11810 return setError();
11811
235d5a96 11812 exp.type = (sc && sc.flags & SCOPE.Cfile) ? Type.tint32 : Type.tbool;
5fee5ec3
IB
11813
11814 // Special handling for array comparisons
11815 Expression arrayLowering = null;
11816 t1 = exp.e1.type.toBasetype();
11817 t2 = exp.e2.type.toBasetype();
11818 if ((t1.ty == Tarray || t1.ty == Tsarray || t1.ty == Tpointer) && (t2.ty == Tarray || t2.ty == Tsarray || t2.ty == Tpointer))
11819 {
11820 Type t1next = t1.nextOf();
11821 Type t2next = t2.nextOf();
11822 if (t1next.implicitConvTo(t2next) < MATCH.constant && t2next.implicitConvTo(t1next) < MATCH.constant && (t1next.ty != Tvoid && t2next.ty != Tvoid))
11823 {
11824 exp.error("array comparison type mismatch, `%s` vs `%s`", t1next.toChars(), t2next.toChars());
11825 return setError();
11826 }
11827 if ((t1.ty == Tarray || t1.ty == Tsarray) && (t2.ty == Tarray || t2.ty == Tsarray))
11828 {
11829 if (!verifyHookExist(exp.loc, *sc, Id.__cmp, "comparing arrays"))
11830 return setError();
11831
11832 // Lower to object.__cmp(e1, e2)
11833 Expression al = new IdentifierExp(exp.loc, Id.empty);
11834 al = new DotIdExp(exp.loc, al, Id.object);
11835 al = new DotIdExp(exp.loc, al, Id.__cmp);
11836 al = al.expressionSemantic(sc);
11837
11838 auto arguments = new Expressions(2);
11839 (*arguments)[0] = exp.e1;
11840 (*arguments)[1] = exp.e2;
11841
11842 al = new CallExp(exp.loc, al, arguments);
11843 al = new CmpExp(exp.op, exp.loc, al, IntegerExp.literal!0);
11844
11845 arrayLowering = al;
11846 }
11847 }
11848 else if (t1.ty == Tstruct || t2.ty == Tstruct || (t1.ty == Tclass && t2.ty == Tclass))
11849 {
11850 if (t2.ty == Tstruct)
11851 exp.error("need member function `opCmp()` for %s `%s` to compare", t2.toDsymbol(sc).kind(), t2.toChars());
11852 else
11853 exp.error("need member function `opCmp()` for %s `%s` to compare", t1.toDsymbol(sc).kind(), t1.toChars());
11854 return setError();
11855 }
11856 else if (t1.iscomplex() || t2.iscomplex())
11857 {
11858 exp.error("compare not defined for complex operands");
11859 return setError();
11860 }
11861 else if (t1.ty == Taarray || t2.ty == Taarray)
11862 {
9c7d5e88 11863 exp.error("`%s` is not defined for associative arrays", EXPtoString(exp.op).ptr);
5fee5ec3
IB
11864 return setError();
11865 }
11866 else if (!target.isVectorOpSupported(t1, exp.op, t2))
11867 {
11868 result = exp.incompatibleTypes();
11869 return;
11870 }
11871 else
11872 {
11873 bool r1 = exp.e1.checkValue() || exp.e1.checkSharedAccess(sc);
11874 bool r2 = exp.e2.checkValue() || exp.e2.checkSharedAccess(sc);
11875 if (r1 || r2)
11876 return setError();
11877 }
11878
11879 //printf("CmpExp: %s, type = %s\n", e.toChars(), e.type.toChars());
11880 if (arrayLowering)
11881 {
11882 arrayLowering = arrayLowering.expressionSemantic(sc);
11883 result = arrayLowering;
11884 return;
11885 }
7e7ebe3e 11886
f99303eb
IB
11887 if (auto tv = t1.isTypeVector())
11888 exp.type = tv.toBooleanVector();
7e7ebe3e 11889
5fee5ec3
IB
11890 result = exp;
11891 return;
11892 }
11893
11894 override void visit(InExp exp)
11895 {
11896 if (exp.type)
11897 {
11898 result = exp;
11899 return;
11900 }
11901
11902 if (Expression ex = binSemanticProp(exp, sc))
11903 {
11904 result = ex;
11905 return;
11906 }
11907 Expression e = exp.op_overload(sc);
11908 if (e)
11909 {
11910 result = e;
11911 return;
11912 }
11913
11914 Type t2b = exp.e2.type.toBasetype();
11915 switch (t2b.ty)
11916 {
11917 case Taarray:
11918 {
11919 TypeAArray ta = cast(TypeAArray)t2b;
11920
11921 // Special handling for array keys
11922 if (!arrayTypeCompatibleWithoutCasting(exp.e1.type, ta.index))
11923 {
11924 // Convert key to type of key
11925 exp.e1 = exp.e1.implicitCastTo(sc, ta.index);
11926 }
11927
11928 semanticTypeInfo(sc, ta.index);
11929
11930 // Return type is pointer to value
11931 exp.type = ta.nextOf().pointerTo();
11932 break;
11933 }
11934
11935 case Terror:
11936 return setError();
11937
208fbc77
IB
11938 case Tarray, Tsarray:
11939 result = exp.incompatibleTypes();
11940 exp.errorSupplemental("`in` is only allowed on associative arrays");
11941 const(char)* slice = (t2b.ty == Tsarray) ? "[]" : "";
11942 exp.errorSupplemental("perhaps use `std.algorithm.find(%s, %s%s)` instead",
11943 exp.e1.toChars(), exp.e2.toChars(), slice);
11944 return;
11945
5fee5ec3
IB
11946 default:
11947 result = exp.incompatibleTypes();
11948 return;
11949 }
11950 result = exp;
11951 }
11952
11953 override void visit(RemoveExp e)
11954 {
11955 if (Expression ex = binSemantic(e, sc))
11956 {
11957 result = ex;
11958 return;
11959 }
11960 result = e;
11961 }
11962
11963 override void visit(EqualExp exp)
11964 {
11965 //printf("EqualExp::semantic('%s')\n", exp.toChars());
11966 if (exp.type)
11967 {
11968 result = exp;
11969 return;
11970 }
11971
11972 exp.setNoderefOperands();
11973
11974 if (auto e = binSemanticProp(exp, sc))
11975 {
11976 result = e;
11977 return;
11978 }
9c7d5e88 11979 if (exp.e1.op == EXP.type || exp.e2.op == EXP.type)
5fee5ec3
IB
11980 {
11981 /* https://issues.dlang.org/show_bug.cgi?id=12520
11982 * empty tuples are represented as types so special cases are added
11983 * so that they can be compared for equality with tuples of values.
11984 */
11985 static auto extractTypeTupAndExpTup(Expression e)
11986 {
11987 static struct Result { bool ttEmpty; bool te; }
9c7d5e88 11988 auto tt = e.op == EXP.type ? e.isTypeExp().type.isTypeTuple() : null;
6d799f0a 11989 return Result(tt && (!tt.arguments || !tt.arguments.length), e.isTupleExp() !is null);
5fee5ec3
IB
11990 }
11991 auto tups1 = extractTypeTupAndExpTup(exp.e1);
11992 auto tups2 = extractTypeTupAndExpTup(exp.e2);
11993 // AliasSeq!() == AliasSeq!(<at least a value>)
11994 if (tups1.ttEmpty && tups2.te)
11995 {
9c7d5e88 11996 result = IntegerExp.createBool(exp.op != EXP.equal);
5fee5ec3
IB
11997 return;
11998 }
11999 // AliasSeq!(<at least a value>) == AliasSeq!()
12000 else if (tups1.te && tups2.ttEmpty)
12001 {
9c7d5e88 12002 result = IntegerExp.createBool(exp.op != EXP.equal);
5fee5ec3
IB
12003 return;
12004 }
12005 // AliasSeq!() == AliasSeq!()
12006 else if (tups1.ttEmpty && tups2.ttEmpty)
12007 {
9c7d5e88 12008 result = IntegerExp.createBool(exp.op == EXP.equal);
5fee5ec3
IB
12009 return;
12010 }
12011 // otherwise, two types are really not comparable
12012 result = exp.incompatibleTypes();
12013 return;
12014 }
12015
12016 {
12017 auto t1 = exp.e1.type;
12018 auto t2 = exp.e2.type;
12019 if (t1.ty == Tenum && t2.ty == Tenum && !t1.equivalent(t2))
5eb9927a 12020 exp.error("comparison between different enumeration types `%s` and `%s`; If this behavior is intended consider using `std.conv.asOriginalType`",
5fee5ec3
IB
12021 t1.toChars(), t2.toChars());
12022 }
12023
12024 /* Before checking for operator overloading, check to see if we're
12025 * comparing the addresses of two statics. If so, we can just see
12026 * if they are the same symbol.
12027 */
9c7d5e88 12028 if (exp.e1.op == EXP.address && exp.e2.op == EXP.address)
5fee5ec3
IB
12029 {
12030 AddrExp ae1 = cast(AddrExp)exp.e1;
12031 AddrExp ae2 = cast(AddrExp)exp.e2;
9c7d5e88 12032 if (ae1.e1.op == EXP.variable && ae2.e1.op == EXP.variable)
5fee5ec3
IB
12033 {
12034 VarExp ve1 = cast(VarExp)ae1.e1;
12035 VarExp ve2 = cast(VarExp)ae2.e1;
12036 if (ve1.var == ve2.var)
12037 {
12038 // They are the same, result is 'true' for ==, 'false' for !=
9c7d5e88 12039 result = IntegerExp.createBool(exp.op == EXP.equal);
5fee5ec3
IB
12040 return;
12041 }
12042 }
12043 }
12044
12045 Type t1 = exp.e1.type.toBasetype();
12046 Type t2 = exp.e2.type.toBasetype();
12047
12048 // Indicates whether the comparison of the 2 specified array types
12049 // requires an object.__equals() lowering.
12050 static bool needsDirectEq(Type t1, Type t2, Scope* sc)
12051 {
12052 Type t1n = t1.nextOf().toBasetype();
12053 Type t2n = t2.nextOf().toBasetype();
12054 if ((t1n.ty.isSomeChar && t2n.ty.isSomeChar) ||
12055 (t1n.ty == Tvoid || t2n.ty == Tvoid))
12056 {
12057 return false;
12058 }
12059 if (t1n.constOf() != t2n.constOf())
12060 return true;
12061
12062 Type t = t1n;
12063 while (t.toBasetype().nextOf())
12064 t = t.nextOf().toBasetype();
12065 if (auto ts = t.isTypeStruct())
12066 {
12067 // semanticTypeInfo() makes sure hasIdentityEquals has been computed
12068 if (global.params.useTypeInfo && Type.dtypeinfo)
12069 semanticTypeInfo(sc, ts);
12070
12071 return ts.sym.hasIdentityEquals; // has custom opEquals
12072 }
12073
12074 return false;
12075 }
12076
12077 if (auto e = exp.op_overload(sc))
12078 {
12079 result = e;
12080 return;
12081 }
12082
12083
12084 const isArrayComparison = (t1.ty == Tarray || t1.ty == Tsarray) &&
12085 (t2.ty == Tarray || t2.ty == Tsarray);
12086 const needsArrayLowering = isArrayComparison && needsDirectEq(t1, t2, sc);
12087
12088 if (!needsArrayLowering)
12089 {
12090 if (auto e = typeCombine(exp, sc))
12091 {
12092 result = e;
12093 return;
12094 }
12095 }
12096
12097 auto f1 = checkNonAssignmentArrayOp(exp.e1);
12098 auto f2 = checkNonAssignmentArrayOp(exp.e2);
12099 if (f1 || f2)
12100 return setError();
12101
235d5a96 12102 exp.type = (sc && sc.flags & SCOPE.Cfile) ? Type.tint32 : Type.tbool;
5fee5ec3
IB
12103
12104 if (!isArrayComparison)
12105 {
12106 if (exp.e1.type != exp.e2.type && exp.e1.type.isfloating() && exp.e2.type.isfloating())
12107 {
12108 // Cast both to complex
12109 exp.e1 = exp.e1.castTo(sc, Type.tcomplex80);
12110 exp.e2 = exp.e2.castTo(sc, Type.tcomplex80);
12111 }
12112 }
12113
12114 // lower some array comparisons to object.__equals(e1, e2)
12115 if (needsArrayLowering || (t1.ty == Tarray && t2.ty == Tarray))
12116 {
12117 //printf("Lowering to __equals %s %s\n", exp.e1.toChars(), exp.e2.toChars());
12118
b6df1132
IB
12119 // https://issues.dlang.org/show_bug.cgi?id=22390
12120 // Equality comparison between array of noreturns simply lowers to length equality comparison
12121 if (t1.nextOf.isTypeNoreturn() && t2.nextOf.isTypeNoreturn())
12122 {
12123 Expression exp_l1 = new DotIdExp(exp.e1.loc, exp.e1, Id.length);
12124 Expression exp_l2 = new DotIdExp(exp.e2.loc, exp.e2, Id.length);
12125 auto e = new EqualExp(EXP.equal, exp.loc, exp_l1, exp_l2);
12126 result = e.expressionSemantic(sc);
12127 return;
12128 }
12129
5fee5ec3
IB
12130 if (!verifyHookExist(exp.loc, *sc, Id.__equals, "equal checks on arrays"))
12131 return setError();
12132
12133 Expression __equals = new IdentifierExp(exp.loc, Id.empty);
12134 Identifier id = Identifier.idPool("__equals");
12135 __equals = new DotIdExp(exp.loc, __equals, Id.object);
12136 __equals = new DotIdExp(exp.loc, __equals, id);
12137
8da8c7d3
IB
12138 /* https://issues.dlang.org/show_bug.cgi?id=23674
12139 *
12140 * Optimize before creating the call expression to the
12141 * druntime hook as the optimizer may output errors
12142 * that will get swallowed otherwise.
12143 */
12144 exp.e1 = exp.e1.optimize(WANTvalue);
12145 exp.e2 = exp.e2.optimize(WANTvalue);
12146
5fee5ec3
IB
12147 auto arguments = new Expressions(2);
12148 (*arguments)[0] = exp.e1;
12149 (*arguments)[1] = exp.e2;
12150
12151 __equals = new CallExp(exp.loc, __equals, arguments);
9c7d5e88 12152 if (exp.op == EXP.notEqual)
5fee5ec3
IB
12153 {
12154 __equals = new NotExp(exp.loc, __equals);
12155 }
12156 __equals = __equals.trySemantic(sc); // for better error message
12157 if (!__equals)
12158 {
12159 exp.error("incompatible types for array comparison: `%s` and `%s`",
12160 exp.e1.type.toChars(), exp.e2.type.toChars());
12161 __equals = ErrorExp.get();
12162 }
12163
12164 result = __equals;
12165 return;
12166 }
12167
12168 if (exp.e1.type.toBasetype().ty == Taarray)
12169 semanticTypeInfo(sc, exp.e1.type.toBasetype());
12170
12171
12172 if (!target.isVectorOpSupported(t1, exp.op, t2))
12173 {
12174 result = exp.incompatibleTypes();
12175 return;
12176 }
12177
f99303eb
IB
12178 if (auto tv = t1.isTypeVector())
12179 exp.type = tv.toBooleanVector();
7e7ebe3e 12180
5fee5ec3
IB
12181 result = exp;
12182 }
12183
12184 override void visit(IdentityExp exp)
12185 {
12186 if (exp.type)
12187 {
12188 result = exp;
12189 return;
12190 }
12191
12192 exp.setNoderefOperands();
12193
12194 if (auto e = binSemanticProp(exp, sc))
12195 {
12196 result = e;
12197 return;
12198 }
12199
12200 if (auto e = typeCombine(exp, sc))
12201 {
12202 result = e;
12203 return;
12204 }
12205
12206 auto f1 = checkNonAssignmentArrayOp(exp.e1);
12207 auto f2 = checkNonAssignmentArrayOp(exp.e2);
12208 if (f1 || f2)
12209 return setError();
12210
9c7d5e88 12211 if (exp.e1.op == EXP.type || exp.e2.op == EXP.type)
5fee5ec3
IB
12212 {
12213 result = exp.incompatibleTypes();
12214 return;
12215 }
12216
12217 exp.type = Type.tbool;
12218
12219 if (exp.e1.type != exp.e2.type && exp.e1.type.isfloating() && exp.e2.type.isfloating())
12220 {
12221 // Cast both to complex
12222 exp.e1 = exp.e1.castTo(sc, Type.tcomplex80);
12223 exp.e2 = exp.e2.castTo(sc, Type.tcomplex80);
12224 }
12225
12226 auto tb1 = exp.e1.type.toBasetype();
12227 auto tb2 = exp.e2.type.toBasetype();
12228 if (!target.isVectorOpSupported(tb1, exp.op, tb2))
12229 {
12230 result = exp.incompatibleTypes();
12231 return;
12232 }
12233
9c7d5e88 12234 if (exp.e1.op == EXP.call)
5fee5ec3 12235 exp.e1 = (cast(CallExp)exp.e1).addDtorHook(sc);
9c7d5e88 12236 if (exp.e2.op == EXP.call)
5fee5ec3
IB
12237 exp.e2 = (cast(CallExp)exp.e2).addDtorHook(sc);
12238
12239 if (exp.e1.type.toBasetype().ty == Tsarray ||
12240 exp.e2.type.toBasetype().ty == Tsarray)
12241 exp.deprecation("identity comparison of static arrays "
12242 ~ "implicitly coerces them to slices, "
12243 ~ "which are compared by reference");
12244
12245 result = exp;
12246 }
12247
12248 override void visit(CondExp exp)
12249 {
12250 static if (LOGSEMANTIC)
12251 {
12252 printf("CondExp::semantic('%s')\n", exp.toChars());
12253 }
12254 if (exp.type)
12255 {
12256 result = exp;
12257 return;
12258 }
12259
235d5a96
IB
12260 if (auto die = exp.econd.isDotIdExp())
12261 die.noderef = true;
5fee5ec3
IB
12262
12263 Expression ec = exp.econd.expressionSemantic(sc);
12264 ec = resolveProperties(sc, ec);
12265 ec = ec.toBoolean(sc);
12266
12267 CtorFlow ctorflow_root = sc.ctorflow.clone();
0fb57034 12268 Expression e1x = exp.e1.expressionSemantic(sc).arrayFuncConv(sc);
5fee5ec3
IB
12269 e1x = resolveProperties(sc, e1x);
12270
12271 CtorFlow ctorflow1 = sc.ctorflow;
12272 sc.ctorflow = ctorflow_root;
0fb57034 12273 Expression e2x = exp.e2.expressionSemantic(sc).arrayFuncConv(sc);
5fee5ec3
IB
12274 e2x = resolveProperties(sc, e2x);
12275
12276 sc.merge(exp.loc, ctorflow1);
12277 ctorflow1.freeFieldinit();
12278
9c7d5e88 12279 if (ec.op == EXP.error)
5fee5ec3
IB
12280 {
12281 result = ec;
12282 return;
12283 }
12284 if (ec.type == Type.terror)
12285 return setError();
12286 exp.econd = ec;
12287
9c7d5e88 12288 if (e1x.op == EXP.error)
5fee5ec3
IB
12289 {
12290 result = e1x;
12291 return;
12292 }
12293 if (e1x.type == Type.terror)
12294 return setError();
12295 exp.e1 = e1x;
12296
9c7d5e88 12297 if (e2x.op == EXP.error)
5fee5ec3
IB
12298 {
12299 result = e2x;
12300 return;
12301 }
12302 if (e2x.type == Type.terror)
12303 return setError();
12304 exp.e2 = e2x;
12305
12306 auto f0 = checkNonAssignmentArrayOp(exp.econd);
12307 auto f1 = checkNonAssignmentArrayOp(exp.e1);
12308 auto f2 = checkNonAssignmentArrayOp(exp.e2);
12309 if (f0 || f1 || f2)
12310 return setError();
12311
12312 Type t1 = exp.e1.type;
12313 Type t2 = exp.e2.type;
12314 if (t1.ty == Tnoreturn)
12315 {
12316 exp.type = t2;
f99303eb 12317 exp.e1 = specialNoreturnCast(exp.e1, exp.type);
5fee5ec3
IB
12318 }
12319 else if (t2.ty == Tnoreturn)
12320 {
12321 exp.type = t1;
f99303eb 12322 exp.e2 = specialNoreturnCast(exp.e2, exp.type);
5fee5ec3
IB
12323 }
12324 // If either operand is void the result is void, we have to cast both
12325 // the expression to void so that we explicitly discard the expression
12326 // value if any
12327 // https://issues.dlang.org/show_bug.cgi?id=16598
12328 else if (t1.ty == Tvoid || t2.ty == Tvoid)
12329 {
12330 exp.type = Type.tvoid;
12331 exp.e1 = exp.e1.castTo(sc, exp.type);
12332 exp.e2 = exp.e2.castTo(sc, exp.type);
12333 }
12334 else if (t1 == t2)
12335 exp.type = t1;
12336 else
12337 {
12338 if (Expression ex = typeCombine(exp, sc))
12339 {
12340 result = ex;
12341 return;
12342 }
12343
12344 switch (exp.e1.type.toBasetype().ty)
12345 {
12346 case Tcomplex32:
12347 case Tcomplex64:
12348 case Tcomplex80:
12349 exp.e2 = exp.e2.castTo(sc, exp.e1.type);
12350 break;
12351 default:
12352 break;
12353 }
12354 switch (exp.e2.type.toBasetype().ty)
12355 {
12356 case Tcomplex32:
12357 case Tcomplex64:
12358 case Tcomplex80:
12359 exp.e1 = exp.e1.castTo(sc, exp.e2.type);
12360 break;
12361 default:
12362 break;
12363 }
12364 if (exp.type.toBasetype().ty == Tarray)
12365 {
12366 exp.e1 = exp.e1.castTo(sc, exp.type);
12367 exp.e2 = exp.e2.castTo(sc, exp.type);
12368 }
12369 }
12370 exp.type = exp.type.merge2();
12371 version (none)
12372 {
12373 printf("res: %s\n", exp.type.toChars());
12374 printf("e1 : %s\n", exp.e1.type.toChars());
12375 printf("e2 : %s\n", exp.e2.type.toChars());
12376 }
12377
12378 /* https://issues.dlang.org/show_bug.cgi?id=14696
12379 * If either e1 or e2 contain temporaries which need dtor,
12380 * make them conditional.
12381 * Rewrite:
12382 * cond ? (__tmp1 = ..., __tmp1) : (__tmp2 = ..., __tmp2)
12383 * to:
12384 * (auto __cond = cond) ? (... __tmp1) : (... __tmp2)
12385 * and replace edtors of __tmp1 and __tmp2 with:
12386 * __tmp1.edtor --> __cond && __tmp1.dtor()
12387 * __tmp2.edtor --> __cond || __tmp2.dtor()
12388 */
12389 exp.hookDtors(sc);
12390
12391 result = exp;
12392 }
12393
12394 override void visit(GenericExp exp)
12395 {
12396 static if (LOGSEMANTIC)
12397 {
12398 printf("GenericExp::semantic('%s')\n", exp.toChars());
12399 }
12400 // C11 6.5.1.1 Generic Selection
12401
5eb9927a 12402 auto ec = exp.cntlExp.expressionSemantic(sc).arrayFuncConv(sc);
5fee5ec3
IB
12403 bool errors = ec.isErrorExp() !is null;
12404 auto tc = ec.type;
12405
12406 auto types = (*exp.types)[];
12407 foreach (i, ref t; types)
12408 {
12409 if (!t)
12410 continue; // `default:` case
12411 t = t.typeSemantic(ec.loc, sc);
12412 if (t.isTypeError())
12413 {
12414 errors = true;
12415 continue;
12416 }
12417
12418 /* C11 6.5.1-2 duplicate check
12419 */
12420 /* C11 distinguishes int, long, and long long. But D doesn't, so depending on the
12421 * C target, a long may have the same type as `int` in the D type system.
12422 * So, skip checks when this may be the case. Later pick the first match
12423 */
12424 if (
12425 (t.ty == Tint32 || t.ty == Tuns32) && target.c.longsize == 4 ||
12426 (t.ty == Tint64 || t.ty == Tuns64) && target.c.longsize == 8 ||
12427 (t.ty == Tfloat64 || t.ty == Timaginary64 || t.ty == Tcomplex64) && target.c.long_doublesize == 8
12428 )
12429 continue;
12430
12431 foreach (t2; types[0 .. i])
12432 {
12433 if (t2 && t2.equals(t))
12434 {
12435 error(ec.loc, "generic association type `%s` can only appear once", t.toChars());
12436 errors = true;
12437 break;
12438 }
12439 }
12440 }
12441
12442 auto exps = (*exp.exps)[];
12443 foreach (ref e; exps)
12444 {
12445 e = e.expressionSemantic(sc);
12446 if (e.isErrorExp())
12447 errors = true;
12448 }
12449
12450 if (errors)
12451 return setError();
12452
12453 enum size_t None = ~0;
12454 size_t imatch = None;
12455 size_t idefault = None;
12456 foreach (const i, t; types)
12457 {
12458 if (t)
12459 {
12460 /* if tc is compatible with t, it's a match
12461 * C11 6.2.7 defines a compatible type as being the same type, including qualifiers
12462 */
12463 if (tc.equals(t))
12464 {
12465 assert(imatch == None);
12466 imatch = i;
12467 break; // pick first match
12468 }
12469 }
12470 else
12471 idefault = i; // multiple defaults are not allowed, and are caught by cparse
12472 }
12473
12474 if (imatch == None)
12475 imatch = idefault;
12476 if (imatch == None)
12477 {
12478 error(exp.loc, "no compatible generic association type for controlling expression type `%s`", tc.toChars());
12479 return setError();
12480 }
12481
12482 result = exps[imatch];
12483 }
12484
12485 override void visit(FileInitExp e)
12486 {
12487 //printf("FileInitExp::semantic()\n");
12488 e.type = Type.tstring;
12489 result = e;
12490 }
12491
12492 override void visit(LineInitExp e)
12493 {
12494 e.type = Type.tint32;
12495 result = e;
12496 }
12497
12498 override void visit(ModuleInitExp e)
12499 {
12500 //printf("ModuleInitExp::semantic()\n");
12501 e.type = Type.tstring;
12502 result = e;
12503 }
12504
12505 override void visit(FuncInitExp e)
12506 {
12507 //printf("FuncInitExp::semantic()\n");
12508 e.type = Type.tstring;
12509 if (sc.func)
12510 {
12511 result = e.resolveLoc(Loc.initial, sc);
12512 return;
12513 }
12514 result = e;
12515 }
12516
12517 override void visit(PrettyFuncInitExp e)
12518 {
12519 //printf("PrettyFuncInitExp::semantic()\n");
12520 e.type = Type.tstring;
12521 if (sc.func)
12522 {
12523 result = e.resolveLoc(Loc.initial, sc);
12524 return;
12525 }
12526
12527 result = e;
12528 }
12529}
12530
12531/**********************************
12532 * Try to run semantic routines.
12533 * If they fail, return NULL.
12534 */
12535Expression trySemantic(Expression exp, Scope* sc)
12536{
12537 //printf("+trySemantic(%s)\n", exp.toChars());
12538 uint errors = global.startGagging();
12539 Expression e = expressionSemantic(exp, sc);
12540 if (global.endGagging(errors))
12541 {
12542 e = null;
12543 }
12544 //printf("-trySemantic(%s)\n", exp.toChars());
12545 return e;
12546}
12547
12548/**************************
12549 * Helper function for easy error propagation.
12550 * If error occurs, returns ErrorExp. Otherwise returns NULL.
12551 */
12552Expression unaSemantic(UnaExp e, Scope* sc)
12553{
12554 static if (LOGSEMANTIC)
12555 {
12556 printf("UnaExp::semantic('%s')\n", e.toChars());
12557 }
12558 Expression e1x = e.e1.expressionSemantic(sc);
9c7d5e88 12559 if (e1x.op == EXP.error)
5fee5ec3
IB
12560 return e1x;
12561 e.e1 = e1x;
12562 return null;
12563}
12564
12565/**************************
12566 * Helper function for easy error propagation.
12567 * If error occurs, returns ErrorExp. Otherwise returns NULL.
12568 */
12569Expression binSemantic(BinExp e, Scope* sc)
12570{
12571 static if (LOGSEMANTIC)
12572 {
12573 printf("BinExp::semantic('%s')\n", e.toChars());
12574 }
12575 Expression e1x = e.e1.expressionSemantic(sc);
12576 Expression e2x = e.e2.expressionSemantic(sc);
12577
12578 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
9c7d5e88 12579 if (e1x.op == EXP.type)
5fee5ec3 12580 e1x = resolveAliasThis(sc, e1x);
9c7d5e88 12581 if (e2x.op == EXP.type)
5fee5ec3
IB
12582 e2x = resolveAliasThis(sc, e2x);
12583
9c7d5e88 12584 if (e1x.op == EXP.error)
5fee5ec3 12585 return e1x;
9c7d5e88 12586 if (e2x.op == EXP.error)
5fee5ec3
IB
12587 return e2x;
12588 e.e1 = e1x;
12589 e.e2 = e2x;
12590 return null;
12591}
12592
12593Expression binSemanticProp(BinExp e, Scope* sc)
12594{
12595 if (Expression ex = binSemantic(e, sc))
12596 return ex;
12597 Expression e1x = resolveProperties(sc, e.e1);
12598 Expression e2x = resolveProperties(sc, e.e2);
9c7d5e88 12599 if (e1x.op == EXP.error)
5fee5ec3 12600 return e1x;
9c7d5e88 12601 if (e2x.op == EXP.error)
5fee5ec3
IB
12602 return e2x;
12603 e.e1 = e1x;
12604 e.e2 = e2x;
12605 return null;
12606}
12607
12608// entrypoint for semantic ExpressionSemanticVisitor
12609extern (C++) Expression expressionSemantic(Expression e, Scope* sc)
12610{
12611 scope v = new ExpressionSemanticVisitor(sc);
12612 e.accept(v);
12613 return v.result;
12614}
12615
f99303eb 12616private Expression dotIdSemanticPropX(DotIdExp exp, Scope* sc)
5fee5ec3
IB
12617{
12618 //printf("DotIdExp::semanticX(this = %p, '%s')\n", this, toChars());
12619 if (Expression ex = unaSemantic(exp, sc))
12620 return ex;
12621
ae56e2da 12622 if (!(sc.flags & SCOPE.Cfile) && exp.ident == Id._mangleof)
5fee5ec3
IB
12623 {
12624 // symbol.mangleof
0fb57034
IB
12625
12626 // return mangleof as an Expression
12627 static Expression dotMangleof(const ref Loc loc, Scope* sc, Dsymbol ds)
5fee5ec3 12628 {
0fb57034
IB
12629 assert(ds);
12630 if (auto f = ds.isFuncDeclaration())
5fee5ec3 12631 {
0fb57034
IB
12632 if (f.checkForwardRef(loc))
12633 return ErrorExp.get();
12634
7e7ebe3e 12635 if (f.purityInprocess || f.safetyInprocess || f.nothrowInprocess || f.nogcInprocess)
5fee5ec3 12636 {
0fb57034
IB
12637 f.error(loc, "cannot retrieve its `.mangleof` while inferring attributes");
12638 return ErrorExp.get();
5fee5ec3 12639 }
5fee5ec3 12640 }
0fb57034
IB
12641 OutBuffer buf;
12642 mangleToBuffer(ds, &buf);
12643 Expression e = new StringExp(loc, buf.extractSlice());
12644 return e.expressionSemantic(sc);
12645 }
12646
12647 Dsymbol ds;
12648 switch (exp.e1.op)
12649 {
9c7d5e88
IB
12650 case EXP.scope_: return dotMangleof(exp.loc, sc, exp.e1.isScopeExp().sds);
12651 case EXP.variable: return dotMangleof(exp.loc, sc, exp.e1.isVarExp().var);
12652 case EXP.dotVariable: return dotMangleof(exp.loc, sc, exp.e1.isDotVarExp().var);
12653 case EXP.overloadSet: return dotMangleof(exp.loc, sc, exp.e1.isOverExp().vars);
12654 case EXP.template_:
0fb57034
IB
12655 {
12656 TemplateExp te = exp.e1.isTemplateExp();
12657 return dotMangleof(exp.loc, sc, ds = te.fd ? te.fd.isDsymbol() : te.td);
12658 }
12659
12660 default:
12661 break;
5fee5ec3
IB
12662 }
12663 }
12664
0fb57034 12665 if (exp.e1.isVarExp() && exp.e1.type.toBasetype().isTypeSArray() && exp.ident == Id.length)
5fee5ec3
IB
12666 {
12667 // bypass checkPurity
12668 return exp.e1.type.dotExp(sc, exp.e1, exp.ident, exp.noderef ? DotExpFlag.noDeref : 0);
12669 }
12670
0fb57034 12671 if (!exp.e1.isDotExp())
5fee5ec3
IB
12672 {
12673 exp.e1 = resolvePropertiesX(sc, exp.e1);
12674 }
0fb57034
IB
12675
12676 if (auto te = exp.e1.isTupleExp())
5fee5ec3 12677 {
0fb57034 12678 if (exp.ident == Id.offsetof)
5fee5ec3 12679 {
0fb57034
IB
12680 /* 'distribute' the .offsetof to each of the tuple elements.
12681 */
6d799f0a 12682 auto exps = new Expressions(te.exps.length);
0fb57034
IB
12683 foreach (i, e; (*te.exps)[])
12684 {
12685 (*exps)[i] = new DotIdExp(e.loc, e, Id.offsetof);
12686 }
12687 // Don't evaluate te.e0 in runtime
12688 Expression e = new TupleExp(exp.loc, null, exps);
5fee5ec3 12689 e = e.expressionSemantic(sc);
0fb57034
IB
12690 return e;
12691 }
12692 if (exp.ident == Id.length)
12693 {
12694 // Don't evaluate te.e0 in runtime
6d799f0a 12695 return new IntegerExp(exp.loc, te.exps.length, Type.tsize_t);
5fee5ec3 12696 }
5fee5ec3
IB
12697 }
12698
12699 // https://issues.dlang.org/show_bug.cgi?id=14416
12700 // Template has no built-in properties except for 'stringof'.
0fb57034 12701 if ((exp.e1.isDotTemplateExp() || exp.e1.isTemplateExp()) && exp.ident != Id.stringof)
5fee5ec3
IB
12702 {
12703 exp.error("template `%s` does not have property `%s`", exp.e1.toChars(), exp.ident.toChars());
12704 return ErrorExp.get();
12705 }
12706 if (!exp.e1.type)
12707 {
12708 exp.error("expression `%s` does not have property `%s`", exp.e1.toChars(), exp.ident.toChars());
12709 return ErrorExp.get();
12710 }
12711
12712 return exp;
12713}
12714
0fb57034
IB
12715/******************************
12716 * Resolve properties, i.e. `e1.ident`, without seeing UFCS.
12717 * Params:
12718 * exp = expression to resolve
12719 * sc = context
12720 * flag = if 1 then do not emit error messages, just return null
12721 * Returns:
12722 * resolved expression, null if error
12723 */
f99303eb 12724Expression dotIdSemanticProp(DotIdExp exp, Scope* sc, int flag)
5fee5ec3
IB
12725{
12726 //printf("DotIdExp::semanticY(this = %p, '%s')\n", exp, exp.toChars());
12727
12728 //{ static int z; fflush(stdout); if (++z == 10) *(char*)0=0; }
12729
ae56e2da
IB
12730 const cfile = (sc.flags & SCOPE.Cfile) != 0;
12731
5fee5ec3
IB
12732 /* Special case: rewrite this.id and super.id
12733 * to be classtype.id and baseclasstype.id
12734 * if we have no this pointer.
12735 */
0fb57034 12736 if ((exp.e1.isThisExp() || exp.e1.isSuperExp()) && !hasThis(sc))
5fee5ec3
IB
12737 {
12738 if (AggregateDeclaration ad = sc.getStructClassScope())
12739 {
0fb57034 12740 if (exp.e1.isThisExp())
5fee5ec3
IB
12741 {
12742 exp.e1 = new TypeExp(exp.e1.loc, ad.type);
12743 }
12744 else
12745 {
0fb57034
IB
12746 if (auto cd = ad.isClassDeclaration())
12747 {
12748 if (cd.baseClass)
12749 exp.e1 = new TypeExp(exp.e1.loc, cd.baseClass.type);
12750 }
5fee5ec3
IB
12751 }
12752 }
12753 }
12754
0fb57034 12755 {
f99303eb 12756 Expression e = dotIdSemanticPropX(exp, sc);
0fb57034
IB
12757 if (e != exp)
12758 return e;
12759 }
5fee5ec3
IB
12760
12761 Expression eleft;
12762 Expression eright;
0fb57034 12763 if (auto de = exp.e1.isDotExp())
5fee5ec3 12764 {
5fee5ec3
IB
12765 eleft = de.e1;
12766 eright = de.e2;
12767 }
12768 else
12769 {
12770 eleft = null;
12771 eright = exp.e1;
12772 }
12773
12774 Type t1b = exp.e1.type.toBasetype();
12775
0fb57034 12776 if (auto ie = eright.isScopeExp()) // also used for template alias's
5fee5ec3 12777 {
0fb57034 12778 auto flags = SearchLocalsOnly;
5fee5ec3
IB
12779 /* Disable access to another module's private imports.
12780 * The check for 'is sds our current module' is because
12781 * the current module should have access to its own imports.
12782 */
12783 if (ie.sds.isModule() && ie.sds != sc._module)
12784 flags |= IgnorePrivateImports;
12785 if (sc.flags & SCOPE.ignoresymbolvisibility)
12786 flags |= IgnoreSymbolVisibility;
12787 Dsymbol s = ie.sds.search(exp.loc, exp.ident, flags);
12788 /* Check for visibility before resolving aliases because public
12789 * aliases to private symbols are public.
12790 */
12791 if (s && !(sc.flags & SCOPE.ignoresymbolvisibility) && !symbolIsVisible(sc._module, s))
12792 {
12793 s = null;
12794 }
12795 if (s)
12796 {
12797 auto p = s.isPackage();
12798 if (p && checkAccess(sc, p))
12799 {
12800 s = null;
12801 }
12802 }
12803 if (s)
12804 {
12805 // if 's' is a tuple variable, the tuple is returned.
12806 s = s.toAlias();
12807
12808 exp.checkDeprecated(sc, s);
12809 exp.checkDisabled(sc, s);
12810
0fb57034 12811 if (auto em = s.isEnumMember())
5fee5ec3
IB
12812 {
12813 return em.getVarExp(exp.loc, sc);
12814 }
0fb57034 12815 if (auto v = s.isVarDeclaration())
5fee5ec3
IB
12816 {
12817 //printf("DotIdExp:: Identifier '%s' is a variable, type '%s'\n", toChars(), v.type.toChars());
12818 if (!v.type ||
12819 !v.type.deco && v.inuse)
12820 {
12821 if (v.inuse)
12822 exp.error("circular reference to %s `%s`", v.kind(), v.toPrettyChars());
12823 else
12824 exp.error("forward reference to %s `%s`", v.kind(), v.toPrettyChars());
12825 return ErrorExp.get();
12826 }
0fb57034 12827 if (v.type.isTypeError())
5fee5ec3
IB
12828 return ErrorExp.get();
12829
12830 if ((v.storage_class & STC.manifest) && v._init && !exp.wantsym)
12831 {
12832 /* Normally, the replacement of a symbol with its initializer is supposed to be in semantic2().
12833 * Introduced by https://github.com/dlang/dmd/pull/5588 which should probably
12834 * be reverted. `wantsym` is the hack to work around the problem.
12835 */
12836 if (v.inuse)
12837 {
12838 error(exp.loc, "circular initialization of %s `%s`", v.kind(), v.toPrettyChars());
12839 return ErrorExp.get();
12840 }
0fb57034 12841 auto e = v.expandInitializer(exp.loc);
5fee5ec3
IB
12842 v.inuse++;
12843 e = e.expressionSemantic(sc);
12844 v.inuse--;
12845 return e;
12846 }
12847
0fb57034 12848 Expression e;
5fee5ec3
IB
12849 if (v.needThis())
12850 {
12851 if (!eleft)
12852 eleft = new ThisExp(exp.loc);
12853 e = new DotVarExp(exp.loc, eleft, v);
12854 e = e.expressionSemantic(sc);
12855 }
12856 else
12857 {
12858 e = new VarExp(exp.loc, v);
12859 if (eleft)
12860 {
12861 e = new CommaExp(exp.loc, eleft, e);
12862 e.type = v.type;
12863 }
12864 }
12865 e = e.deref();
12866 return e.expressionSemantic(sc);
12867 }
12868
0fb57034 12869 if (auto f = s.isFuncDeclaration())
5fee5ec3
IB
12870 {
12871 //printf("it's a function\n");
12872 if (!f.functionSemantic())
12873 return ErrorExp.get();
0fb57034 12874 Expression e;
5fee5ec3
IB
12875 if (f.needThis())
12876 {
12877 if (!eleft)
12878 eleft = new ThisExp(exp.loc);
12879 e = new DotVarExp(exp.loc, eleft, f, true);
12880 e = e.expressionSemantic(sc);
12881 }
12882 else
12883 {
12884 e = new VarExp(exp.loc, f, true);
12885 if (eleft)
12886 {
12887 e = new CommaExp(exp.loc, eleft, e);
12888 e.type = f.type;
12889 }
12890 }
12891 return e;
12892 }
12893 if (auto td = s.isTemplateDeclaration())
12894 {
0fb57034 12895 Expression e;
5fee5ec3
IB
12896 if (eleft)
12897 e = new DotTemplateExp(exp.loc, eleft, td);
12898 else
12899 e = new TemplateExp(exp.loc, td);
12900 e = e.expressionSemantic(sc);
12901 return e;
12902 }
12903 if (OverDeclaration od = s.isOverDeclaration())
12904 {
0fb57034 12905 Expression e = new VarExp(exp.loc, od, true);
5fee5ec3
IB
12906 if (eleft)
12907 {
12908 e = new CommaExp(exp.loc, eleft, e);
12909 e.type = Type.tvoid; // ambiguous type?
12910 }
b6df1132 12911 return e.expressionSemantic(sc);
5fee5ec3 12912 }
0fb57034 12913 if (auto o = s.isOverloadSet())
5fee5ec3
IB
12914 {
12915 //printf("'%s' is an overload set\n", o.toChars());
12916 return new OverExp(exp.loc, o);
12917 }
12918
12919 if (auto t = s.getType())
12920 {
12921 return (new TypeExp(exp.loc, t)).expressionSemantic(sc);
12922 }
12923
0fb57034 12924 if (auto tup = s.isTupleDeclaration())
5fee5ec3
IB
12925 {
12926 if (eleft)
12927 {
0fb57034 12928 Expression e = new DotVarExp(exp.loc, eleft, tup);
5fee5ec3
IB
12929 e = e.expressionSemantic(sc);
12930 return e;
12931 }
0fb57034 12932 Expression e = new TupleExp(exp.loc, tup);
5fee5ec3
IB
12933 e = e.expressionSemantic(sc);
12934 return e;
12935 }
12936
0fb57034 12937 if (auto sds = s.isScopeDsymbol())
5fee5ec3
IB
12938 {
12939 //printf("it's a ScopeDsymbol %s\n", ident.toChars());
0fb57034 12940 Expression e = new ScopeExp(exp.loc, sds);
5fee5ec3
IB
12941 e = e.expressionSemantic(sc);
12942 if (eleft)
12943 e = new DotExp(exp.loc, eleft, e);
12944 return e;
12945 }
12946
0fb57034 12947 if (auto imp = s.isImport())
5fee5ec3 12948 {
0fb57034
IB
12949 Expression se = new ScopeExp(exp.loc, imp.pkg);
12950 return se.expressionSemantic(sc);
5fee5ec3
IB
12951 }
12952 // BUG: handle other cases like in IdentifierExp::semantic()
12953 debug
12954 {
12955 printf("s = '%s', kind = '%s'\n", s.toChars(), s.kind());
12956 }
12957 assert(0);
12958 }
12959 else if (exp.ident == Id.stringof)
12960 {
0fb57034 12961 Expression e = new StringExp(exp.loc, ie.toString());
5fee5ec3
IB
12962 e = e.expressionSemantic(sc);
12963 return e;
12964 }
12965 if (ie.sds.isPackage() || ie.sds.isImport() || ie.sds.isModule())
12966 {
12967 flag = 0;
12968 }
12969 if (flag)
12970 return null;
12971 s = ie.sds.search_correct(exp.ident);
12972 if (s && symbolIsVisible(sc, s))
12973 {
12974 if (s.isPackage())
12975 exp.error("undefined identifier `%s` in %s `%s`, perhaps add `static import %s;`", exp.ident.toChars(), ie.sds.kind(), ie.sds.toPrettyChars(), s.toPrettyChars());
12976 else
12977 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());
12978 }
12979 else
12980 exp.error("undefined identifier `%s` in %s `%s`", exp.ident.toChars(), ie.sds.kind(), ie.sds.toPrettyChars());
12981 return ErrorExp.get();
12982 }
ae56e2da
IB
12983 else if (t1b.ty == Tpointer && exp.e1.type.ty != Tenum &&
12984 !(
12985 exp.ident == Id.__sizeof ||
12986 exp.ident == Id.__xalignof ||
12987 !cfile &&
12988 (exp.ident == Id._mangleof ||
12989 exp.ident == Id.offsetof ||
12990 exp.ident == Id._init ||
12991 exp.ident == Id.stringof)
12992 ))
5fee5ec3
IB
12993 {
12994 Type t1bn = t1b.nextOf();
12995 if (flag)
12996 {
0fb57034
IB
12997 if (AggregateDeclaration ad = isAggregate(t1bn))
12998 {
12999 if (!ad.members) // https://issues.dlang.org/show_bug.cgi?id=11312
13000 return null;
13001 }
5fee5ec3
IB
13002 }
13003
13004 /* Rewrite:
13005 * p.ident
13006 * as:
13007 * (*p).ident
13008 */
13009 if (flag && t1bn.ty == Tvoid)
13010 return null;
0fb57034 13011 Expression e = new PtrExp(exp.loc, exp.e1);
5fee5ec3
IB
13012 e = e.expressionSemantic(sc);
13013 return e.type.dotExp(sc, e, exp.ident, flag | (exp.noderef ? DotExpFlag.noDeref : 0));
13014 }
13015 else if (exp.ident == Id.__xalignof &&
13016 exp.e1.isVarExp() &&
13017 exp.e1.isVarExp().var.isVarDeclaration() &&
0fb57034 13018 !exp.e1.isVarExp().var.isVarDeclaration().alignment.isUnknown())
5fee5ec3
IB
13019 {
13020 // For `x.alignof` get the alignment of the variable, not the alignment of its type
13021 const explicitAlignment = exp.e1.isVarExp().var.isVarDeclaration().alignment;
13022 const naturalAlignment = exp.e1.type.alignsize();
0fb57034
IB
13023 const actualAlignment = explicitAlignment.isDefault() ? naturalAlignment : explicitAlignment.get();
13024 Expression e = new IntegerExp(exp.loc, actualAlignment, Type.tsize_t);
5fee5ec3
IB
13025 return e;
13026 }
5eb9927a
IB
13027 else if ((exp.ident == Id.max || exp.ident == Id.min) &&
13028 exp.e1.isVarExp() &&
13029 exp.e1.isVarExp().var.isBitFieldDeclaration())
fbdaa581 13030 {
5eb9927a
IB
13031 // For `x.max` and `x.min` get the max/min of the bitfield, not the max/min of its type
13032 auto bf = exp.e1.isVarExp().var.isBitFieldDeclaration();
13033 return new IntegerExp(exp.loc, bf.getMinMax(exp.ident), bf.type);
13034 }
13035 else if ((exp.ident == Id.max || exp.ident == Id.min) &&
13036 exp.e1.isDotVarExp() &&
13037 exp.e1.isDotVarExp().var.isBitFieldDeclaration())
13038 {
13039 // For `x.max` and `x.min` get the max/min of the bitfield, not the max/min of its type
13040 auto bf = exp.e1.isDotVarExp().var.isBitFieldDeclaration();
13041 return new IntegerExp(exp.loc, bf.getMinMax(exp.ident), bf.type);
fbdaa581 13042 }
5fee5ec3
IB
13043 else
13044 {
0fb57034 13045 if (exp.e1.isTypeExp() || exp.e1.isTemplateExp())
5fee5ec3 13046 flag = 0;
0fb57034 13047 Expression e = exp.e1.type.dotExp(sc, exp.e1, exp.ident, flag | (exp.noderef ? DotExpFlag.noDeref : 0));
5fee5ec3 13048 if (e)
5eb9927a 13049 {
5fee5ec3 13050 e = e.expressionSemantic(sc);
5eb9927a 13051 }
5fee5ec3
IB
13052 return e;
13053 }
13054}
13055
13056// Resolve e1.ident!tiargs without seeing UFCS.
13057// If flag == 1, stop "not a property" error and return NULL.
f99303eb 13058Expression dotTemplateSemanticProp(DotTemplateInstanceExp exp, Scope* sc, int flag)
5fee5ec3
IB
13059{
13060 static if (LOGSEMANTIC)
13061 {
13062 printf("DotTemplateInstanceExpY::semantic('%s')\n", exp.toChars());
13063 }
13064
13065 static Expression errorExp()
13066 {
13067 return ErrorExp.get();
13068 }
13069
13070 Expression e1 = exp.e1;
13071
13072 if (exp.ti.tempdecl && exp.ti.tempdecl.parent && exp.ti.tempdecl.parent.isTemplateMixin())
13073 {
13074 // if 'ti.tempdecl' happens to be found in a mixin template don't lose that info
13075 // and do the symbol search in that context (Issue: 19476)
13076 auto tm = cast(TemplateMixin)exp.ti.tempdecl.parent;
13077 e1 = new DotExp(exp.e1.loc, exp.e1, new ScopeExp(tm.loc, tm));
13078 }
13079
13080 auto die = new DotIdExp(exp.loc, e1, exp.ti.name);
13081
f99303eb 13082 Expression e = die.dotIdSemanticPropX(sc);
5fee5ec3
IB
13083 if (e == die)
13084 {
13085 exp.e1 = die.e1; // take back
13086 Type t1b = exp.e1.type.toBasetype();
13087 if (t1b.ty == Tarray || t1b.ty == Tsarray || t1b.ty == Taarray || t1b.ty == Tnull || (t1b.isTypeBasic() && t1b.ty != Tvoid))
13088 {
13089 /* No built-in type has templatized properties, so do shortcut.
13090 * It is necessary in: 1024.max!"a < b"
13091 */
13092 if (flag)
13093 return null;
13094 }
f99303eb 13095 e = die.dotIdSemanticProp(sc, flag);
5fee5ec3
IB
13096 if (flag)
13097 {
13098 if (!e ||
13099 isDotOpDispatch(e))
13100 {
13101 /* opDispatch!tiargs would be a function template that needs IFTI,
13102 * so it's not a template
13103 */
13104 return null;
13105 }
13106 }
13107 }
13108 assert(e);
13109
9c7d5e88 13110 if (e.op == EXP.error)
5fee5ec3 13111 return e;
235d5a96 13112 if (DotVarExp dve = e.isDotVarExp())
5fee5ec3 13113 {
5fee5ec3
IB
13114 if (FuncDeclaration fd = dve.var.isFuncDeclaration())
13115 {
13116 if (TemplateDeclaration td = fd.findTemplateDeclRoot())
13117 {
13118 e = new DotTemplateExp(dve.loc, dve.e1, td);
13119 e = e.expressionSemantic(sc);
13120 }
13121 }
13122 else if (OverDeclaration od = dve.var.isOverDeclaration())
13123 {
13124 exp.e1 = dve.e1; // pull semantic() result
13125
13126 if (!exp.findTempDecl(sc))
13127 goto Lerr;
13128 if (exp.ti.needsTypeInference(sc))
13129 return exp;
13130 exp.ti.dsymbolSemantic(sc);
13131 if (!exp.ti.inst || exp.ti.errors) // if template failed to expand
13132 return errorExp();
13133
13134 if (Declaration v = exp.ti.toAlias().isDeclaration())
13135 {
13136 if (v.type && !v.type.deco)
13137 v.type = v.type.typeSemantic(v.loc, sc);
13138 return new DotVarExp(exp.loc, exp.e1, v)
13139 .expressionSemantic(sc);
13140 }
13141 return new DotExp(exp.loc, exp.e1, new ScopeExp(exp.loc, exp.ti))
13142 .expressionSemantic(sc);
13143 }
13144 }
9c7d5e88 13145 else if (e.op == EXP.variable)
5fee5ec3
IB
13146 {
13147 VarExp ve = cast(VarExp)e;
13148 if (FuncDeclaration fd = ve.var.isFuncDeclaration())
13149 {
13150 if (TemplateDeclaration td = fd.findTemplateDeclRoot())
13151 {
13152 e = new TemplateExp(ve.loc, td)
13153 .expressionSemantic(sc);
13154 }
13155 }
13156 else if (OverDeclaration od = ve.var.isOverDeclaration())
13157 {
13158 exp.ti.tempdecl = od;
13159 return new ScopeExp(exp.loc, exp.ti)
13160 .expressionSemantic(sc);
13161 }
13162 }
13163
235d5a96 13164 if (DotTemplateExp dte = e.isDotTemplateExp())
5fee5ec3 13165 {
5fee5ec3
IB
13166 exp.e1 = dte.e1; // pull semantic() result
13167
13168 exp.ti.tempdecl = dte.td;
13169 if (!exp.ti.semanticTiargs(sc))
13170 return errorExp();
13171 if (exp.ti.needsTypeInference(sc))
13172 return exp;
13173 exp.ti.dsymbolSemantic(sc);
13174 if (!exp.ti.inst || exp.ti.errors) // if template failed to expand
13175 return errorExp();
13176
13177 if (Declaration v = exp.ti.toAlias().isDeclaration())
13178 {
ec486b73
IB
13179 return new DotVarExp(exp.loc, exp.e1, v)
13180 .expressionSemantic(sc);
5fee5ec3
IB
13181 }
13182 return new DotExp(exp.loc, exp.e1, new ScopeExp(exp.loc, exp.ti))
13183 .expressionSemantic(sc);
13184 }
9c7d5e88 13185 else if (e.op == EXP.template_)
5fee5ec3
IB
13186 {
13187 exp.ti.tempdecl = (cast(TemplateExp)e).td;
13188 return new ScopeExp(exp.loc, exp.ti)
13189 .expressionSemantic(sc);
13190 }
235d5a96 13191 else if (DotExp de = e.isDotExp())
5fee5ec3 13192 {
9c7d5e88 13193 if (de.e2.op == EXP.overloadSet)
5fee5ec3
IB
13194 {
13195 if (!exp.findTempDecl(sc) || !exp.ti.semanticTiargs(sc))
13196 {
13197 return errorExp();
13198 }
13199 if (exp.ti.needsTypeInference(sc))
13200 return exp;
13201 exp.ti.dsymbolSemantic(sc);
13202 if (!exp.ti.inst || exp.ti.errors) // if template failed to expand
13203 return errorExp();
13204
13205 if (Declaration v = exp.ti.toAlias().isDeclaration())
13206 {
13207 if (v.type && !v.type.deco)
13208 v.type = v.type.typeSemantic(v.loc, sc);
13209 return new DotVarExp(exp.loc, exp.e1, v)
13210 .expressionSemantic(sc);
13211 }
13212 return new DotExp(exp.loc, exp.e1, new ScopeExp(exp.loc, exp.ti))
13213 .expressionSemantic(sc);
13214 }
13215 }
235d5a96 13216 else if (OverExp oe = e.isOverExp())
5fee5ec3 13217 {
5fee5ec3
IB
13218 exp.ti.tempdecl = oe.vars;
13219 return new ScopeExp(exp.loc, exp.ti)
13220 .expressionSemantic(sc);
13221 }
13222
13223Lerr:
13224 exp.error("`%s` isn't a template", e.toChars());
13225 return errorExp();
13226}
13227
13228/***************************************
13229 * If expression is shared, check that we can access it.
13230 * Give error message if not.
13231 *
13232 * Params:
13233 * e = expression to check
13234 * sc = context
13235 * returnRef = Whether this expression is for a `return` statement
13236 * off a `ref` function, in which case a single level
13237 * of dereference is allowed (e.g. `shared(int)*`).
13238 * Returns:
13239 * true on error
13240 */
13241bool checkSharedAccess(Expression e, Scope* sc, bool returnRef = false)
13242{
7e7ebe3e 13243 if (global.params.noSharedAccess != FeatureState.enabled ||
f99303eb 13244 !sc ||
5fee5ec3
IB
13245 sc.intypeof ||
13246 sc.flags & SCOPE.ctfe)
13247 {
13248 return false;
13249 }
13250
31350635 13251 //printf("checkSharedAccess() `%s` returnRef: %d\n", e.toChars(), returnRef);
5fee5ec3 13252
31350635
IB
13253 bool check(Expression e, bool allowRef)
13254 {
13255 bool sharedError(Expression e)
5fee5ec3
IB
13256 {
13257 // https://dlang.org/phobos/core_atomic.html
13258 e.error("direct access to shared `%s` is not allowed, see `core.atomic`", e.toChars());
31350635 13259 return true;
5fee5ec3
IB
13260 }
13261
5fee5ec3 13262 // Error by default
31350635 13263 bool visit(Expression e)
5fee5ec3 13264 {
8da8c7d3
IB
13265 // https://issues.dlang.org/show_bug.cgi?id=23639
13266 // Should be able to cast(shared)
13267 if (!e.isCastExp() && e.type.isShared())
31350635
IB
13268 return sharedError(e);
13269 return false;
5fee5ec3
IB
13270 }
13271
31350635 13272 bool visitNew(NewExp e)
5fee5ec3 13273 {
31350635
IB
13274 if (e.thisexp)
13275 check(e.thisexp, false);
31350635 13276 return false;
5fee5ec3
IB
13277 }
13278
31350635 13279 bool visitVar(VarExp e)
5fee5ec3 13280 {
ec486b73
IB
13281 // https://issues.dlang.org/show_bug.cgi?id=22626
13282 // Synchronized functions don't need to use core.atomic
13283 // when accessing `this`.
13284 if (sc.func && sc.func.isSynchronized())
13285 {
13286 if (e.var.isThisDeclaration())
13287 return false;
13288 else
13289 return sharedError(e);
13290 }
13291 else if (!allowRef && e.var.type.isShared())
31350635 13292 return sharedError(e);
ec486b73 13293
31350635 13294 return false;
5fee5ec3
IB
13295 }
13296
31350635 13297 bool visitAddr(AddrExp e)
5fee5ec3 13298 {
31350635 13299 return check(e.e1, true);
5fee5ec3
IB
13300 }
13301
31350635 13302 bool visitPtr(PtrExp e)
5fee5ec3 13303 {
31350635
IB
13304 if (!allowRef && e.type.isShared())
13305 return sharedError(e);
5fee5ec3
IB
13306
13307 if (e.e1.type.isShared())
31350635 13308 return sharedError(e);
5fee5ec3 13309
31350635 13310 return check(e.e1, false);
5fee5ec3
IB
13311 }
13312
8da8c7d3 13313 bool visitDotVar(DotVarExp e)
ec486b73 13314 {
8da8c7d3
IB
13315 //printf("dotvarexp = %s\n", e.toChars());
13316 if (e.type.isShared())
13317 {
13318 // / https://issues.dlang.org/show_bug.cgi?id=22626
13319 if (e.e1.isThisExp() && sc.func && sc.func.isSynchronized())
13320 return false;
ec486b73 13321
8da8c7d3
IB
13322 auto fd = e.var.isFuncDeclaration();
13323 const sharedFunc = fd && fd.type.isShared;
13324 if (!allowRef && !sharedFunc)
13325 return sharedError(e);
b7a586be 13326
8da8c7d3
IB
13327 // Allow using `DotVarExp` within value types
13328 if (e.e1.type.isTypeSArray() || e.e1.type.isTypeStruct())
13329 return check(e.e1, allowRef);
ec486b73 13330
8da8c7d3
IB
13331 // If we end up with a single `VarExp`, it might be a `ref` param
13332 // `shared ref T` param == `shared(T)*`.
13333 if (auto ve = e.e1.isVarExp())
13334 {
13335 return check(e.e1, allowRef && (ve.var.storage_class & STC.ref_));
13336 }
5fee5ec3 13337
8da8c7d3 13338 return sharedError(e);
5fee5ec3
IB
13339 }
13340
31350635 13341 return check(e.e1, false);
5fee5ec3
IB
13342 }
13343
31350635 13344 bool visitIndex(IndexExp e)
5fee5ec3 13345 {
31350635
IB
13346 if (!allowRef && e.type.isShared())
13347 return sharedError(e);
5fee5ec3
IB
13348
13349 if (e.e1.type.isShared())
31350635 13350 return sharedError(e);
5fee5ec3 13351
31350635 13352 return check(e.e1, false);
5fee5ec3
IB
13353 }
13354
31350635 13355 bool visitComma(CommaExp e)
5fee5ec3
IB
13356 {
13357 // Cannot be `return ref` since we can't use the return,
13358 // but it's better to show that error than an unrelated `shared` one
31350635
IB
13359 return check(e.e2, true);
13360 }
13361
13362 switch (e.op)
13363 {
13364 default: return visit(e);
13365
13366 // Those have no indirections / can be ignored
13367 case EXP.call:
13368 case EXP.error:
13369 case EXP.complex80:
13370 case EXP.int64:
13371 case EXP.null_: return false;
13372
13373 case EXP.variable: return visitVar(e.isVarExp());
13374 case EXP.new_: return visitNew(e.isNewExp());
13375 case EXP.address: return visitAddr(e.isAddrExp());
13376 case EXP.star: return visitPtr(e.isPtrExp());
13377 case EXP.dotVariable: return visitDotVar(e.isDotVarExp());
13378 case EXP.index: return visitIndex(e.isIndexExp());
5fee5ec3
IB
13379 }
13380 }
13381
31350635 13382 return check(e, returnRef);
5fee5ec3
IB
13383}
13384
13385
13386
13387/****************************************************
13388 * Determine if `exp`, which gets its address taken, can do so safely.
13389 * Params:
13390 * sc = context
13391 * exp = expression having its address taken
13392 * v = the variable getting its address taken
13393 * Returns:
13394 * `true` if ok, `false` for error
13395 */
13396bool checkAddressVar(Scope* sc, Expression exp, VarDeclaration v)
13397{
13398 //printf("checkAddressVar(exp: %s, v: %s)\n", exp.toChars(), v.toChars());
b6df1132
IB
13399 if (v is null)
13400 return true;
13401
13402 if (!v.canTakeAddressOf())
13403 {
13404 exp.error("cannot take address of `%s`", exp.toChars());
13405 return false;
13406 }
13407 if (sc.func && !sc.intypeof && !v.isDataseg())
5fee5ec3 13408 {
b6df1132
IB
13409 if (global.params.useDIP1000 != FeatureState.enabled &&
13410 !(v.storage_class & STC.temp) &&
13411 sc.setUnsafe(false, exp.loc, "cannot take address of local `%s` in `@safe` function `%s`", v, sc.func))
5fee5ec3 13412 {
5fee5ec3
IB
13413 return false;
13414 }
5fee5ec3
IB
13415 }
13416 return true;
13417}
13418
d97f3bca
IB
13419/**************************************
13420 * This check ensures that the object in `exp` can have its address taken, or
13421 * issue a diagnostic error.
13422 * Params:
13423 * e = expression to check
13424 * sc = context
13425 * Returns:
13426 * true if the expression is addressable
13427 */
13428bool checkAddressable(Expression e, Scope* sc)
13429{
13430 Expression ex = e;
13431 while (true)
13432 {
13433 switch (ex.op)
13434 {
13435 case EXP.dotVariable:
13436 // https://issues.dlang.org/show_bug.cgi?id=22749
13437 // Error about taking address of any bit-field, regardless of
13438 // whether SCOPE.Cfile is set.
13439 if (auto bf = ex.isDotVarExp().var.isBitFieldDeclaration())
13440 {
13441 e.error("cannot take address of bit-field `%s`", bf.toChars());
13442 return false;
13443 }
13444 goto case EXP.cast_;
13445
13446 case EXP.index:
13447 ex = ex.isBinExp().e1;
13448 continue;
13449
13450 case EXP.address:
13451 case EXP.array:
13452 case EXP.cast_:
13453 ex = ex.isUnaExp().e1;
13454 continue;
13455
13456 case EXP.variable:
13457 if (sc.flags & SCOPE.Cfile)
13458 {
13459 // C11 6.5.3.2: A variable that has its address taken cannot be
13460 // stored in a register.
13461 // C11 6.3.2.1: An array that has its address computed with `[]`
13462 // or cast to an lvalue pointer cannot be stored in a register.
13463 if (ex.isVarExp().var.storage_class & STC.register)
13464 {
13465 if (e.isIndexExp())
13466 e.error("cannot index through register variable `%s`", ex.toChars());
13467 else
13468 e.error("cannot take address of register variable `%s`", ex.toChars());
13469 return false;
13470 }
13471 }
13472 break;
13473
13474 default:
13475 break;
13476 }
13477 break;
13478 }
13479 return true;
13480}
13481
7e287503 13482
5fee5ec3
IB
13483/*******************************
13484 * Checks the attributes of a function.
13485 * Purity (`pure`), safety (`@safe`), no GC allocations(`@nogc`)
13486 * and usage of `deprecated` and `@disabled`-ed symbols are checked.
13487 *
13488 * Params:
13489 * exp = expression to check attributes for
13490 * sc = scope of the function
13491 * f = function to be checked
13492 * Returns: `true` if error occur.
13493 */
13494private bool checkFunctionAttributes(Expression exp, Scope* sc, FuncDeclaration f)
13495{
13496 with(exp)
13497 {
13498 bool error = checkDisabled(sc, f);
13499 error |= checkDeprecated(sc, f);
13500 error |= checkPurity(sc, f);
13501 error |= checkSafety(sc, f);
13502 error |= checkNogc(sc, f);
13503 return error;
13504 }
13505}
13506
13507/*******************************
13508 * Helper function for `getRightThis()`.
13509 * Gets `this` of the next outer aggregate.
13510 * Params:
13511 * loc = location to use for error messages
13512 * sc = context
13513 * s = the parent symbol of the existing `this`
13514 * ad = struct or class we need the correct `this` for
13515 * e1 = existing `this`
13516 * t = type of the existing `this`
13517 * var = the specific member of ad we're accessing
13518 * flag = if true, return `null` instead of throwing an error
13519 * Returns:
13520 * Expression representing the `this` for the var
13521 */
13522Expression getThisSkipNestedFuncs(const ref Loc loc, Scope* sc, Dsymbol s, AggregateDeclaration ad, Expression e1, Type t, Dsymbol var, bool flag = false)
13523{
13524 int n = 0;
13525 while (s && s.isFuncDeclaration())
13526 {
13527 FuncDeclaration f = s.isFuncDeclaration();
13528 if (f.vthis)
13529 {
13530 n++;
13531 e1 = new VarExp(loc, f.vthis);
235d5a96 13532 if (f.hasDualContext())
5fee5ec3
IB
13533 {
13534 // (*__this)[i]
13535 if (n > 1)
13536 e1 = e1.expressionSemantic(sc);
13537 e1 = new PtrExp(loc, e1);
13538 uint i = f.followInstantiationContext(ad);
13539 e1 = new IndexExp(loc, e1, new IntegerExp(i));
13540 s = f.toParentP(ad);
13541 continue;
13542 }
13543 }
13544 else
13545 {
13546 if (flag)
13547 return null;
13548 e1.error("need `this` of type `%s` to access member `%s` from static function `%s`", ad.toChars(), var.toChars(), f.toChars());
13549 e1 = ErrorExp.get();
13550 return e1;
13551 }
13552 s = s.toParent2();
13553 }
9c7d5e88 13554 if (n > 1 || e1.op == EXP.index)
5fee5ec3
IB
13555 e1 = e1.expressionSemantic(sc);
13556 if (s && e1.type.equivalent(Type.tvoidptr))
13557 {
13558 if (auto sad = s.isAggregateDeclaration())
13559 {
13560 Type ta = sad.handleType();
13561 if (ta.ty == Tstruct)
13562 ta = ta.pointerTo();
13563 e1.type = ta;
13564 }
13565 }
13566 e1.type = e1.type.addMod(t.mod);
13567 return e1;
13568}
13569
13570/*******************************
13571 * Make a dual-context container for use as a `this` argument.
13572 * Params:
13573 * loc = location to use for error messages
13574 * sc = current scope
13575 * fd = target function that will take the `this` argument
13576 * Returns:
13577 * Temporary closure variable.
13578 * Note:
13579 * The function `fd` is added to the nested references of the
13580 * newly created variable such that a closure is made for the variable when
13581 * the address of `fd` is taken.
13582 */
13583VarDeclaration makeThis2Argument(const ref Loc loc, Scope* sc, FuncDeclaration fd)
13584{
13585 Type tthis2 = Type.tvoidptr.sarrayOf(2);
13586 VarDeclaration vthis2 = new VarDeclaration(loc, tthis2, Identifier.generateId("__this"), null);
13587 vthis2.storage_class |= STC.temp;
13588 vthis2.dsymbolSemantic(sc);
13589 vthis2.parent = sc.parent;
13590 // make it a closure var
13591 assert(sc.func);
13592 sc.func.closureVars.push(vthis2);
13593 // add `fd` to the nested refs
13594 vthis2.nestedrefs.push(fd);
13595 return vthis2;
13596}
13597
13598/*******************************
13599 * Make sure that the runtime hook `id` exists.
13600 * Params:
13601 * loc = location to use for error messages
13602 * sc = current scope
13603 * id = the hook identifier
13604 * description = what the hook does
13605 * module_ = what module the hook is located in
13606 * Returns:
13607 * a `bool` indicating if the hook is present.
13608 */
13609bool verifyHookExist(const ref Loc loc, ref Scope sc, Identifier id, string description, Identifier module_ = Id.object)
13610{
13611 auto rootSymbol = sc.search(loc, Id.empty, null);
13612 if (auto moduleSymbol = rootSymbol.search(loc, module_))
13613 if (moduleSymbol.search(loc, id))
13614 return true;
13615 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);
13616 return false;
13617}
13618
13619/***************************************
13620 * Fit elements[] to the corresponding types of the `sd`'s fields.
13621 *
13622 * Params:
13623 * sd = the struct declaration
13624 * loc = location to use for error messages
13625 * sc = context
13626 * elements = explicit arguments used to construct object
13627 * stype = the constructed object type.
13628 * Returns:
13629 * false if any errors occur,
13630 * otherwise true and elements[] are rewritten for the output.
13631 */
13632private bool fit(StructDeclaration sd, const ref Loc loc, Scope* sc, Expressions* elements, Type stype)
13633{
13634 if (!elements)
13635 return true;
13636
13637 const nfields = sd.nonHiddenFields();
13638 size_t offset = 0;
6d799f0a 13639 for (size_t i = 0; i < elements.length; i++)
5fee5ec3
IB
13640 {
13641 Expression e = (*elements)[i];
13642 if (!e)
13643 continue;
13644
13645 e = resolveProperties(sc, e);
13646 if (i >= nfields)
13647 {
6d799f0a 13648 if (i < sd.fields.length && e.op == EXP.null_)
5fee5ec3
IB
13649 {
13650 // CTFE sometimes creates null as hidden pointer; we'll allow this.
13651 continue;
13652 }
c43b5909 13653 .error(loc, "more initializers than fields (%llu) of `%s`", cast(ulong)nfields, sd.toChars());
5fee5ec3
IB
13654 return false;
13655 }
13656 VarDeclaration v = sd.fields[i];
13657 if (v.offset < offset)
13658 {
13659 .error(loc, "overlapping initialization for `%s`", v.toChars());
13660 if (!sd.isUnionDeclaration())
13661 {
13662 enum errorMsg = "`struct` initializers that contain anonymous unions" ~
13663 " must initialize only the first member of a `union`. All subsequent" ~
13664 " non-overlapping fields are default initialized";
13665 .errorSupplemental(loc, errorMsg);
13666 }
13667 return false;
13668 }
9c7d5e88
IB
13669 const vsize = v.type.size();
13670 if (vsize == SIZE_INVALID)
13671 return false;
13672 offset = cast(uint)(v.offset + vsize);
5fee5ec3
IB
13673
13674 Type t = v.type;
13675 if (stype)
13676 t = t.addMod(stype.mod);
13677 Type origType = t;
13678 Type tb = t.toBasetype();
13679
13680 const hasPointers = tb.hasPointers();
13681 if (hasPointers)
13682 {
0fb57034 13683 if ((!stype.alignment.isDefault() && stype.alignment.get() < target.ptrsize ||
5fee5ec3 13684 (v.offset & (target.ptrsize - 1))) &&
610d7898 13685 (sc.setUnsafe(false, loc,
5eb9927a 13686 "field `%s.%s` cannot assign to misaligned pointers in `@safe` code", sd, v)))
5fee5ec3 13687 {
5fee5ec3
IB
13688 return false;
13689 }
13690 }
13691
13692 /* Look for case of initializing a static array with a too-short
13693 * string literal, such as:
13694 * char[5] foo = "abc";
13695 * Allow this by doing an explicit cast, which will lengthen the string
13696 * literal.
13697 */
9c7d5e88 13698 if (e.op == EXP.string_ && tb.ty == Tsarray)
5fee5ec3
IB
13699 {
13700 StringExp se = cast(StringExp)e;
13701 Type typeb = se.type.toBasetype();
13702 TY tynto = tb.nextOf().ty;
13703 if (!se.committed &&
13704 (typeb.ty == Tarray || typeb.ty == Tsarray) && tynto.isSomeChar &&
13705 se.numberOfCodeUnits(tynto) < (cast(TypeSArray)tb).dim.toInteger())
13706 {
13707 e = se.castTo(sc, t);
13708 goto L1;
13709 }
13710 }
13711
13712 while (!e.implicitConvTo(t) && tb.ty == Tsarray)
13713 {
13714 /* Static array initialization, as in:
13715 * T[3][5] = e;
13716 */
13717 t = tb.nextOf();
13718 tb = t.toBasetype();
13719 }
13720 if (!e.implicitConvTo(t))
13721 t = origType; // restore type for better diagnostic
13722
13723 e = e.implicitCastTo(sc, t);
13724 L1:
9c7d5e88 13725 if (e.op == EXP.error)
5fee5ec3
IB
13726 return false;
13727
13728 (*elements)[i] = doCopyOrMove(sc, e);
13729 }
13730 return true;
13731}
13732
13733
13734/**
13735 * Returns `em` as a VariableExp
13736 * Params:
13737 * em = the EnumMember to wrap
13738 * loc = location of use of em
13739 * sc = scope of use of em
13740 * Returns:
13741 * VarExp referenceing `em` or ErrorExp if `em` if disabled/deprecated
13742 */
13743Expression getVarExp(EnumMember em, const ref Loc loc, Scope* sc)
13744{
13745 dsymbolSemantic(em, sc);
13746 if (em.errors)
13747 return ErrorExp.get();
13748 em.checkDisabled(loc, sc);
13749
13750 if (em.depdecl && !em.depdecl._scope)
13751 em.depdecl._scope = sc;
13752 em.checkDeprecated(loc, sc);
13753
13754 if (em.errors)
13755 return ErrorExp.get();
13756 Expression e = new VarExp(loc, em);
d7569187
IB
13757 e = e.expressionSemantic(sc);
13758 if (!(sc.flags & SCOPE.Cfile) && em.isCsymbol())
13759 {
13760 /* C11 types them as int. But if in D file,
13761 * type qualified names as the enum
13762 */
13763 e.type = em.parent.isEnumDeclaration().type;
13764 assert(e.type);
13765 }
13766 return e;
5fee5ec3
IB
13767}
13768
13769
13770/*****************************
13771 * Try to treat `exp` as a boolean,
13772 * Params:
13773 * exp = the expression
13774 * sc = scope to evalute `exp` in
13775 * Returns:
13776 * Modified expression on success, ErrorExp on error
13777 */
13778Expression toBoolean(Expression exp, Scope* sc)
13779{
13780 switch(exp.op)
13781 {
9c7d5e88 13782 case EXP.delete_:
5fee5ec3
IB
13783 exp.error("`delete` does not give a boolean result");
13784 return ErrorExp.get();
13785
9c7d5e88 13786 case EXP.comma:
5fee5ec3
IB
13787 auto ce = exp.isCommaExp();
13788 auto ex2 = ce.e2.toBoolean(sc);
9c7d5e88 13789 if (ex2.op == EXP.error)
5fee5ec3
IB
13790 return ex2;
13791 ce.e2 = ex2;
13792 ce.type = ce.e2.type;
13793 return ce;
13794
9c7d5e88
IB
13795 case EXP.assign:
13796 case EXP.construct:
13797 case EXP.blit:
d7569187
IB
13798 if (sc.flags & SCOPE.Cfile)
13799 return exp;
5fee5ec3
IB
13800 // Things like:
13801 // if (a = b) ...
13802 // are usually mistakes.
13803 exp.error("assignment cannot be used as a condition, perhaps `==` was meant?");
13804 return ErrorExp.get();
13805
13806 //LogicalExp
9c7d5e88
IB
13807 case EXP.andAnd:
13808 case EXP.orOr:
5fee5ec3
IB
13809 auto le = exp.isLogicalExp();
13810 auto ex2 = le.e2.toBoolean(sc);
9c7d5e88 13811 if (ex2.op == EXP.error)
5fee5ec3
IB
13812 return ex2;
13813 le.e2 = ex2;
13814 return le;
13815
9c7d5e88 13816 case EXP.question:
5fee5ec3
IB
13817 auto ce = exp.isCondExp();
13818 auto ex1 = ce.e1.toBoolean(sc);
13819 auto ex2 = ce.e2.toBoolean(sc);
9c7d5e88 13820 if (ex1.op == EXP.error)
5fee5ec3 13821 return ex1;
9c7d5e88 13822 if (ex2.op == EXP.error)
5fee5ec3
IB
13823 return ex2;
13824 ce.e1 = ex1;
13825 ce.e2 = ex2;
13826 return ce;
13827
13828
13829 default:
13830 // Default is 'yes' - do nothing
235d5a96
IB
13831 Expression e = arrayFuncConv(exp, sc);
13832 Type t = e.type;
5fee5ec3
IB
13833 Type tb = t.toBasetype();
13834 Type att = null;
13835
13836 while (1)
13837 {
13838 // Structs can be converted to bool using opCast(bool)()
13839 if (auto ts = tb.isTypeStruct())
13840 {
13841 AggregateDeclaration ad = ts.sym;
13842 /* Don't really need to check for opCast first, but by doing so we
13843 * get better error messages if it isn't there.
13844 */
13845 if (Dsymbol fd = search_function(ad, Id._cast))
13846 {
13847 e = new CastExp(exp.loc, e, Type.tbool);
13848 e = e.expressionSemantic(sc);
13849 return e;
13850 }
13851
13852 // Forward to aliasthis.
13853 if (ad.aliasthis && !isRecursiveAliasThis(att, tb))
13854 {
13855 e = resolveAliasThis(sc, e);
13856 t = e.type;
13857 tb = e.type.toBasetype();
13858 continue;
13859 }
13860 }
13861 break;
13862 }
13863
13864 if (!t.isBoolean())
13865 {
13866 if (tb != Type.terror)
13867 exp.error("expression `%s` of type `%s` does not have a boolean value",
13868 exp.toChars(), t.toChars());
13869 return ErrorExp.get();
13870 }
13871 return e;
13872 }
13873}