blob: f899bd79d20b177ea8121ed292b4551adb0fd41a [file] [log] [blame]
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02001/**
2 * Semantic analysis of expressions.
3 *
4 * Specification: ($LINK2 https://dlang.org/spec/expression.html, Expressions)
5 *
Iain Buclawc43b5902022-01-02 13:36:51 +01006 * Copyright: Copyright (C) 1999-2022 by The D Language Foundation, All Rights Reserved
7 * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
8 * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02009 * 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;
Iain Buclaw0fb57032021-12-05 17:11:12 +010046import dmd.file_manager;
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020047import dmd.func;
48import dmd.globals;
49import dmd.hdrgen;
50import dmd.id;
51import dmd.identifier;
52import dmd.imphint;
Iain Buclaw0fb57032021-12-05 17:11:12 +010053import dmd.importc;
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020054import dmd.init;
55import dmd.initsem;
56import dmd.inline;
57import dmd.intrange;
58import dmd.mtype;
Iain Buclaw31350632022-04-13 13:34:49 +010059import dmd.mustuse;
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020060import dmd.nspace;
61import dmd.opover;
62import dmd.optimize;
63import dmd.parse;
64import dmd.printast;
Iain Buclawc8dfa792022-09-27 10:43:32 +020065import dmd.root.array;
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020066import dmd.root.ctfloat;
67import dmd.root.file;
68import dmd.root.filename;
Iain Buclaw0fb57032021-12-05 17:11:12 +010069import dmd.common.outbuffer;
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020070import dmd.root.rootobject;
71import dmd.root.string;
Iain Buclawc43b5902022-01-02 13:36:51 +010072import dmd.root.utf;
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020073import dmd.semantic2;
74import dmd.semantic3;
75import dmd.sideeffect;
76import dmd.safe;
77import dmd.target;
78import dmd.tokens;
79import dmd.traits;
80import dmd.typesem;
81import dmd.typinf;
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020082import dmd.utils;
83import dmd.visitor;
84
85enum LOGSEMANTIC = false;
86
87/********************************************************
88 * Perform semantic analysis and CTFE on expressions to produce
89 * a string.
90 * Params:
91 * buf = append generated string to buffer
92 * sc = context
93 * exps = array of Expressions
94 * Returns:
95 * true on error
96 */
97bool expressionsToString(ref OutBuffer buf, Scope* sc, Expressions* exps)
98{
99 if (!exps)
100 return false;
101
102 foreach (ex; *exps)
103 {
104 if (!ex)
105 continue;
106 auto sc2 = sc.startCTFE();
107 auto e2 = ex.expressionSemantic(sc2);
108 auto e3 = resolveProperties(sc2, e2);
109 sc2.endCTFE();
110
111 // allowed to contain types as well as expressions
112 auto e4 = ctfeInterpretForPragmaMsg(e3);
Iain Buclaw9c7d5e882021-12-10 03:14:20 +0100113 if (!e4 || e4.op == EXP.error)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +0200114 return true;
115
116 // expand tuple
117 if (auto te = e4.isTupleExp())
118 {
119 if (expressionsToString(buf, sc, te.exps))
120 return true;
121 continue;
122 }
123 // char literals exp `.toStringExp` return `null` but we cant override it
124 // because in most contexts we don't want the conversion to succeed.
125 IntegerExp ie = e4.isIntegerExp();
126 const ty = (ie && ie.type) ? ie.type.ty : Terror;
127 if (ty.isSomeChar)
128 {
129 auto tsa = new TypeSArray(ie.type, IntegerExp.literal!1);
130 e4 = new ArrayLiteralExp(ex.loc, tsa, ie);
131 }
132
133 if (StringExp se = e4.toStringExp())
134 buf.writestring(se.toUTF8(sc).peekString());
135 else
136 buf.writestring(e4.toString());
137 }
138 return false;
139}
140
141
142/***********************************************************
143 * Resolve `exp` as a compile-time known string.
144 * Params:
145 * sc = scope
146 * exp = Expression which expected as a string
147 * s = What the string is expected for, will be used in error diagnostic.
148 * Returns:
149 * String literal, or `null` if error happens.
150 */
151StringExp semanticString(Scope *sc, Expression exp, const char* s)
152{
153 sc = sc.startCTFE();
154 exp = exp.expressionSemantic(sc);
155 exp = resolveProperties(sc, exp);
156 sc = sc.endCTFE();
157
Iain Buclaw9c7d5e882021-12-10 03:14:20 +0100158 if (exp.op == EXP.error)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +0200159 return null;
160
161 auto e = exp;
162 if (exp.type.isString())
163 {
164 e = e.ctfeInterpret();
Iain Buclaw9c7d5e882021-12-10 03:14:20 +0100165 if (e.op == EXP.error)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +0200166 return null;
167 }
168
169 auto se = e.toStringExp();
170 if (!se)
171 {
172 exp.error("`string` expected for %s, not `(%s)` of type `%s`",
173 s, exp.toChars(), exp.type.toChars());
174 return null;
175 }
176 return se;
177}
178
179private Expression extractOpDollarSideEffect(Scope* sc, UnaExp ue)
180{
181 Expression e0;
182 Expression e1 = Expression.extractLast(ue.e1, e0);
183 // https://issues.dlang.org/show_bug.cgi?id=12585
184 // Extract the side effect part if ue.e1 is comma.
185
186 if ((sc.flags & SCOPE.ctfe) ? hasSideEffect(e1) : !isTrivialExp(e1)) // match logic in extractSideEffect()
187 {
188 /* Even if opDollar is needed, 'e1' should be evaluate only once. So
189 * Rewrite:
190 * e1.opIndex( ... use of $ ... )
191 * e1.opSlice( ... use of $ ... )
192 * as:
193 * (ref __dop = e1, __dop).opIndex( ... __dop.opDollar ...)
194 * (ref __dop = e1, __dop).opSlice( ... __dop.opDollar ...)
195 */
196 e1 = extractSideEffect(sc, "__dop", e0, e1, false);
197 assert(e1.isVarExp());
198 e1.isVarExp().var.storage_class |= STC.exptemp; // lifetime limited to expression
199 }
200 ue.e1 = e1;
201 return e0;
202}
203
204/**************************************
205 * Runs semantic on ae.arguments. Declares temporary variables
206 * if '$' was used.
207 */
208Expression resolveOpDollar(Scope* sc, ArrayExp ae, Expression* pe0)
209{
210 assert(!ae.lengthVar);
211 *pe0 = null;
212 AggregateDeclaration ad = isAggregate(ae.e1.type);
213 Dsymbol slice = search_function(ad, Id.slice);
214 //printf("slice = %s %s\n", slice.kind(), slice.toChars());
215 foreach (i, e; *ae.arguments)
216 {
217 if (i == 0)
218 *pe0 = extractOpDollarSideEffect(sc, ae);
219
Iain Buclaw9c7d5e882021-12-10 03:14:20 +0100220 if (e.op == EXP.interval && !(slice && slice.isTemplateDeclaration()))
Iain Buclaw5fee5ec32019-06-18 20:42:10 +0200221 {
222 Lfallback:
223 if (ae.arguments.dim == 1)
224 return null;
225 ae.error("multi-dimensional slicing requires template `opSlice`");
226 return ErrorExp.get();
227 }
228 //printf("[%d] e = %s\n", i, e.toChars());
229
230 // Create scope for '$' variable for this dimension
231 auto sym = new ArrayScopeSymbol(sc, ae);
232 sym.parent = sc.scopesym;
233 sc = sc.push(sym);
234 ae.lengthVar = null; // Create it only if required
235 ae.currentDimension = i; // Dimension for $, if required
236
237 e = e.expressionSemantic(sc);
238 e = resolveProperties(sc, e);
239
240 if (ae.lengthVar && sc.func)
241 {
242 // If $ was used, declare it now
243 Expression de = new DeclarationExp(ae.loc, ae.lengthVar);
244 de = de.expressionSemantic(sc);
245 *pe0 = Expression.combine(*pe0, de);
246 }
247 sc = sc.pop();
248
249 if (auto ie = e.isIntervalExp())
250 {
251 auto tiargs = new Objects();
252 Expression edim = new IntegerExp(ae.loc, i, Type.tsize_t);
253 edim = edim.expressionSemantic(sc);
254 tiargs.push(edim);
255
256 auto fargs = new Expressions(2);
257 (*fargs)[0] = ie.lwr;
258 (*fargs)[1] = ie.upr;
259
260 uint xerrors = global.startGagging();
261 sc = sc.push();
262 FuncDeclaration fslice = resolveFuncCall(ae.loc, sc, slice, tiargs, ae.e1.type, fargs, FuncResolveFlag.quiet);
263 sc = sc.pop();
264 global.endGagging(xerrors);
265 if (!fslice)
266 goto Lfallback;
267
268 e = new DotTemplateInstanceExp(ae.loc, ae.e1, slice.ident, tiargs);
269 e = new CallExp(ae.loc, e, fargs);
270 e = e.expressionSemantic(sc);
271 }
272
273 if (!e.type)
274 {
275 ae.error("`%s` has no value", e.toChars());
276 e = ErrorExp.get();
277 }
Iain Buclaw9c7d5e882021-12-10 03:14:20 +0100278 if (e.op == EXP.error)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +0200279 return e;
280
281 (*ae.arguments)[i] = e;
282 }
283 return ae;
284}
285
286/**************************************
287 * Runs semantic on se.lwr and se.upr. Declares a temporary variable
288 * if '$' was used.
289 * Returns:
290 * ae, or ErrorExp if errors occurred
291 */
292Expression resolveOpDollar(Scope* sc, ArrayExp ae, IntervalExp ie, Expression* pe0)
293{
294 //assert(!ae.lengthVar);
295 if (!ie)
296 return ae;
297
298 VarDeclaration lengthVar = ae.lengthVar;
299 bool errors = false;
300
301 // create scope for '$'
302 auto sym = new ArrayScopeSymbol(sc, ae);
303 sym.parent = sc.scopesym;
304 sc = sc.push(sym);
305
306 Expression sem(Expression e)
307 {
308 e = e.expressionSemantic(sc);
309 e = resolveProperties(sc, e);
310 if (!e.type)
311 {
312 ae.error("`%s` has no value", e.toChars());
313 errors = true;
314 }
315 return e;
316 }
317
318 ie.lwr = sem(ie.lwr);
319 ie.upr = sem(ie.upr);
320
Iain Buclawfd435682021-12-15 19:47:02 +0100321 if (ie.lwr.isErrorExp() || ie.upr.isErrorExp())
322 errors = true;
323
Iain Buclaw5fee5ec32019-06-18 20:42:10 +0200324 if (lengthVar != ae.lengthVar && sc.func)
325 {
326 // If $ was used, declare it now
327 Expression de = new DeclarationExp(ae.loc, ae.lengthVar);
328 de = de.expressionSemantic(sc);
329 *pe0 = Expression.combine(*pe0, de);
330 }
331
332 sc = sc.pop();
333
334 return errors ? ErrorExp.get() : ae;
335}
336
337/******************************
338 * Perform semantic() on an array of Expressions.
339 */
Iain Buclawc8dfa792022-09-27 10:43:32 +0200340extern(D) bool arrayExpressionSemantic(
341 Expression[] exps, Scope* sc, bool preserveErrors = false)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +0200342{
343 bool err = false;
Iain Buclawc8dfa792022-09-27 10:43:32 +0200344 foreach (ref e; exps)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +0200345 {
Iain Buclawc8dfa792022-09-27 10:43:32 +0200346 if (e is null) continue;
347 auto e2 = e.expressionSemantic(sc);
348 if (e2.op == EXP.error)
349 err = true;
350 if (preserveErrors || e2.op != EXP.error)
351 e = e2;
Iain Buclaw5fee5ec32019-06-18 20:42:10 +0200352 }
353 return err;
354}
355
Iain Buclaw7e7ebe32022-10-29 09:05:54 +0200356/*
357Checks if `exp` contains a direct access to a `noreturn`
358variable. If that is the case, an `assert(0)` expression
359is generated and returned. This function should be called
360only after semantic analysis has been performed on `exp`.
361
362Params:
363 exp = expression that is checked
364
365Returns:
366 An `assert(0)` expression if `exp` contains a `noreturn`
367 variable access, `exp` otherwise.
368*/
369
370Expression checkNoreturnVarAccess(Expression exp)
371{
372 assert(exp.type);
373
374 Expression result = exp;
375 if (exp.type.isTypeNoreturn() && !exp.isAssertExp() &&
376 !exp.isThrowExp() && !exp.isCallExp())
377 {
378 auto msg = new StringExp(exp.loc, "Accessed expression of type `noreturn`");
379 msg.type = Type.tstring;
380 result = new AssertExp(exp.loc, IntegerExp.literal!0, msg);
381 result.type = exp.type;
382 }
383
384 return result;
385}
386
Iain Buclaw5fee5ec32019-06-18 20:42:10 +0200387/******************************
388 * Check the tail CallExp is really property function call.
389 * Bugs:
390 * This doesn't appear to do anything.
391 */
392private bool checkPropertyCall(Expression e)
393{
394 e = lastComma(e);
395
396 if (auto ce = e.isCallExp())
397 {
398 if (ce.f)
399 {
400 auto tf = ce.f.type.isTypeFunction();
401 /* If a forward reference to ce.f, try to resolve it
402 */
403 if (!tf.deco && ce.f.semanticRun < PASS.semanticdone)
404 {
405 ce.f.dsymbolSemantic(null);
406 tf = ce.f.type.isTypeFunction();
407 }
408 }
409 else if (!ce.e1.type.isFunction_Delegate_PtrToFunction())
410 assert(0);
411 }
412 return false;
413}
414
415/******************************
416 * Find symbol in accordance with the UFCS name look up rule
417 */
418private Expression searchUFCS(Scope* sc, UnaExp ue, Identifier ident)
419{
420 //printf("searchUFCS(ident = %s)\n", ident.toChars());
421 Loc loc = ue.loc;
422
423 // TODO: merge with Scope.search.searchScopes()
424 Dsymbol searchScopes(int flags)
425 {
426 Dsymbol s = null;
427 for (Scope* scx = sc; scx; scx = scx.enclosing)
428 {
429 if (!scx.scopesym)
430 continue;
431 if (scx.scopesym.isModule())
432 flags |= SearchUnqualifiedModule; // tell Module.search() that SearchLocalsOnly is to be obeyed
433 s = scx.scopesym.search(loc, ident, flags);
434 if (s)
435 {
436 // overload set contains only module scope symbols.
437 if (s.isOverloadSet())
438 break;
439 // selective/renamed imports also be picked up
440 if (AliasDeclaration ad = s.isAliasDeclaration())
441 {
442 if (ad._import)
443 break;
444 }
445 // See only module scope symbols for UFCS target.
446 Dsymbol p = s.toParent2();
447 if (p && p.isModule())
448 break;
449 }
450 s = null;
451
452 // Stop when we hit a module, but keep going if that is not just under the global scope
453 if (scx.scopesym.isModule() && !(scx.enclosing && !scx.enclosing.enclosing))
454 break;
455 }
456 return s;
457 }
458
459 int flags = 0;
460 Dsymbol s;
461
462 if (sc.flags & SCOPE.ignoresymbolvisibility)
463 flags |= IgnoreSymbolVisibility;
464
465 // First look in local scopes
466 s = searchScopes(flags | SearchLocalsOnly);
467 if (!s)
468 {
469 // Second look in imported modules
470 s = searchScopes(flags | SearchImportsOnly);
471 }
472
473 if (!s)
Iain Buclawc8dfa792022-09-27 10:43:32 +0200474 return ue.e1.type.getProperty(sc, loc, ident, 0, ue.e1);
Iain Buclaw5fee5ec32019-06-18 20:42:10 +0200475
476 FuncDeclaration f = s.isFuncDeclaration();
477 if (f)
478 {
479 TemplateDeclaration td = getFuncTemplateDecl(f);
480 if (td)
481 {
482 if (td.overroot)
483 td = td.overroot;
484 s = td;
485 }
486 }
487
488 if (auto dti = ue.isDotTemplateInstanceExp())
489 {
490 auto ti = new TemplateInstance(loc, s.ident, dti.ti.tiargs);
491 if (!ti.updateTempDecl(sc, s))
492 return ErrorExp.get();
493 return new ScopeExp(loc, ti);
494 }
495 else
496 {
497 //printf("-searchUFCS() %s\n", s.toChars());
498 return new DsymbolExp(loc, s);
499 }
500}
501
502/******************************
503 * Pull out callable entity with UFCS.
504 */
505private Expression resolveUFCS(Scope* sc, CallExp ce)
506{
507 Loc loc = ce.loc;
508 Expression eleft;
509 Expression e;
510
511 if (auto die = ce.e1.isDotIdExp())
512 {
513 Identifier ident = die.ident;
514
515 Expression ex = die.semanticX(sc);
516 if (ex != die)
517 {
518 ce.e1 = ex;
519 return null;
520 }
521 eleft = die.e1;
522
523 Type t = eleft.type.toBasetype();
524 if (t.ty == Tarray || t.ty == Tsarray || t.ty == Tnull || (t.isTypeBasic() && t.ty != Tvoid))
525 {
526 /* Built-in types and arrays have no callable properties, so do shortcut.
527 * It is necessary in: e.init()
528 */
529 }
530 else if (t.ty == Taarray)
531 {
532 if (ident == Id.remove)
533 {
534 /* Transform:
535 * aa.remove(arg) into delete aa[arg]
536 */
537 if (!ce.arguments || ce.arguments.dim != 1)
538 {
539 ce.error("expected key as argument to `aa.remove()`");
540 return ErrorExp.get();
541 }
542 if (!eleft.type.isMutable())
543 {
544 ce.error("cannot remove key from `%s` associative array `%s`", MODtoChars(t.mod), eleft.toChars());
545 return ErrorExp.get();
546 }
547 Expression key = (*ce.arguments)[0];
548 key = key.expressionSemantic(sc);
549 key = resolveProperties(sc, key);
550
551 TypeAArray taa = t.isTypeAArray();
552 key = key.implicitCastTo(sc, taa.index);
553
554 if (key.checkValue() || key.checkSharedAccess(sc))
555 return ErrorExp.get();
556
557 semanticTypeInfo(sc, taa.index);
558
559 return new RemoveExp(loc, eleft, key);
560 }
561 }
562 else
563 {
564 if (Expression ey = die.semanticY(sc, 1))
565 {
Iain Buclaw9c7d5e882021-12-10 03:14:20 +0100566 if (ey.op == EXP.error)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +0200567 return ey;
568 ce.e1 = ey;
569 if (isDotOpDispatch(ey))
570 {
Iain Buclaw5fee5ec32019-06-18 20:42:10 +0200571 // even opDispatch and UFCS must have valid arguments,
572 // so now that we've seen indication of a problem,
573 // check them for issues.
574 Expressions* originalArguments = Expression.arraySyntaxCopy(ce.arguments);
575
Iain Buclawfd435682021-12-15 19:47:02 +0100576 uint errors = global.startGagging();
577 e = ce.expressionSemantic(sc);
578 if (!global.endGagging(errors))
579 return e;
580
Iain Buclawc8dfa792022-09-27 10:43:32 +0200581 if (arrayExpressionSemantic(originalArguments.peekSlice(), sc))
Iain Buclaw5fee5ec32019-06-18 20:42:10 +0200582 return ErrorExp.get();
583
584 /* fall down to UFCS */
585 }
586 else
587 return null;
588 }
589 }
590
591 /* https://issues.dlang.org/show_bug.cgi?id=13953
592 *
593 * If a struct has an alias this to an associative array
594 * and remove is used on a struct instance, we have to
595 * check first if there is a remove function that can be called
596 * on the struct. If not we must check the alias this.
597 *
598 * struct A
599 * {
600 * string[string] a;
601 * alias a this;
602 * }
603 *
604 * void fun()
605 * {
606 * A s;
607 * s.remove("foo");
608 * }
609 */
610 const errors = global.startGagging();
611 e = searchUFCS(sc, die, ident);
612 // if there were any errors and the identifier was remove
613 if (global.endGagging(errors))
614 {
615 if (ident == Id.remove)
616 {
617 // check alias this
618 Expression alias_e = resolveAliasThis(sc, die.e1, 1);
619 if (alias_e && alias_e != die.e1)
620 {
621 die.e1 = alias_e;
622 CallExp ce2 = ce.syntaxCopy();
623 ce2.e1 = die;
624 e = ce2.isCallExp().trySemantic(sc);
625 if (e)
626 return e;
627 }
628 }
629 // if alias this did not work out, print the initial errors
630 searchUFCS(sc, die, ident);
631 }
632 }
633 else if (auto dti = ce.e1.isDotTemplateInstanceExp())
634 {
635 if (Expression ey = dti.semanticY(sc, 1))
636 {
637 ce.e1 = ey;
638 return null;
639 }
640 eleft = dti.e1;
641 e = searchUFCS(sc, dti, dti.ti.name);
642 }
643 else
644 return null;
645
646 // Rewrite
647 ce.e1 = e;
648 if (!ce.arguments)
649 ce.arguments = new Expressions();
650 ce.arguments.shift(eleft);
651
652 return null;
653}
654
655/******************************
656 * Pull out property with UFCS.
657 */
658private Expression resolveUFCSProperties(Scope* sc, Expression e1, Expression e2 = null)
659{
660 Loc loc = e1.loc;
661 Expression eleft;
662 Expression e;
663
664 if (auto die = e1.isDotIdExp())
665 {
666 eleft = die.e1;
667 e = searchUFCS(sc, die, die.ident);
668 }
669 else if (auto dti = e1.isDotTemplateInstanceExp())
670 {
671 eleft = dti.e1;
672 e = searchUFCS(sc, dti, dti.ti.name);
673 }
674 else
675 return null;
676
677 if (e is null)
678 return null;
679
680 // Rewrite
681 if (e2)
682 {
683 // run semantic without gagging
684 e2 = e2.expressionSemantic(sc);
685
686 /* f(e1) = e2
687 */
688 Expression ex = e.copy();
689 auto a1 = new Expressions(1);
690 (*a1)[0] = eleft;
691 ex = new CallExp(loc, ex, a1);
692 auto e1PassSemantic = ex.trySemantic(sc);
693
694 /* f(e1, e2)
695 */
696 auto a2 = new Expressions(2);
697 (*a2)[0] = eleft;
698 (*a2)[1] = e2;
699 e = new CallExp(loc, e, a2);
700 e = e.trySemantic(sc);
701 if (!e1PassSemantic && !e)
702 {
703 /* https://issues.dlang.org/show_bug.cgi?id=20448
704 *
705 * If both versions have failed to pass semantic,
706 * f(e1) = e2 gets priority in error printing
707 * because f might be a templated function that
708 * failed to instantiate and we have to print
709 * the instantiation errors.
710 */
711 return e1.expressionSemantic(sc);
712 }
713 else if (ex && !e)
714 {
715 checkPropertyCall(ex);
716 ex = new AssignExp(loc, ex, e2);
717 return ex.expressionSemantic(sc);
718 }
719 else
720 {
721 // strict setter prints errors if fails
722 e = e.expressionSemantic(sc);
723 }
724 checkPropertyCall(e);
725 return e;
726 }
727 else
728 {
729 /* f(e1)
730 */
731 auto arguments = new Expressions(1);
732 (*arguments)[0] = eleft;
733 e = new CallExp(loc, e, arguments);
734 e = e.expressionSemantic(sc);
735 checkPropertyCall(e);
736 return e.expressionSemantic(sc);
737 }
738}
739
740/******************************
741 * If e1 is a property function (template), resolve it.
742 */
743Expression resolvePropertiesOnly(Scope* sc, Expression e1)
744{
Iain Buclaw31350632022-04-13 13:34:49 +0100745 //printf("e1 = %s %s\n", Token.toChars(e1.op), e1.toChars());
Iain Buclaw5fee5ec32019-06-18 20:42:10 +0200746
747 Expression handleOverloadSet(OverloadSet os)
748 {
749 assert(os);
750 foreach (s; os.a)
751 {
752 auto fd = s.isFuncDeclaration();
753 auto td = s.isTemplateDeclaration();
754 if (fd)
755 {
756 if (fd.type.isTypeFunction().isproperty)
757 return resolveProperties(sc, e1);
758 }
759 else if (td && td.onemember && (fd = td.onemember.isFuncDeclaration()) !is null)
760 {
761 if (fd.type.isTypeFunction().isproperty ||
762 (fd.storage_class2 & STC.property) ||
763 (td._scope.stc & STC.property))
764 return resolveProperties(sc, e1);
765 }
766 }
767 return e1;
768 }
769
770 Expression handleTemplateDecl(TemplateDeclaration td)
771 {
772 assert(td);
773 if (td.onemember)
774 {
775 if (auto fd = td.onemember.isFuncDeclaration())
776 {
777 if (fd.type.isTypeFunction().isproperty ||
778 (fd.storage_class2 & STC.property) ||
779 (td._scope.stc & STC.property))
780 return resolveProperties(sc, e1);
781 }
782 }
783 return e1;
784 }
785
786 Expression handleFuncDecl(FuncDeclaration fd)
787 {
788 assert(fd);
789 if (fd.type.isTypeFunction().isproperty)
790 return resolveProperties(sc, e1);
791 return e1;
792 }
793
794 if (auto de = e1.isDotExp())
795 {
796 if (auto os = de.e2.isOverExp())
797 return handleOverloadSet(os.vars);
798 }
799 else if (auto oe = e1.isOverExp())
800 return handleOverloadSet(oe.vars);
801 else if (auto dti = e1.isDotTemplateInstanceExp())
802 {
803 if (dti.ti.tempdecl)
804 if (auto td = dti.ti.tempdecl.isTemplateDeclaration())
805 return handleTemplateDecl(td);
806 }
807 else if (auto dte = e1.isDotTemplateExp())
808 return handleTemplateDecl(dte.td);
809 else if (auto se = e1.isScopeExp())
810 {
811 Dsymbol s = se.sds;
812 TemplateInstance ti = s.isTemplateInstance();
813 if (ti && !ti.semanticRun && ti.tempdecl)
814 if (auto td = ti.tempdecl.isTemplateDeclaration())
815 return handleTemplateDecl(td);
816 }
817 else if (auto et = e1.isTemplateExp())
818 return handleTemplateDecl(et.td);
819 else if (e1.isDotVarExp() && e1.type.isTypeFunction())
820 {
821 DotVarExp dve = e1.isDotVarExp();
822 return handleFuncDecl(dve.var.isFuncDeclaration());
823 }
824 else if (e1.isVarExp() && e1.type && e1.type.isTypeFunction() && (sc.intypeof || !e1.isVarExp().var.needThis()))
825 return handleFuncDecl(e1.isVarExp().var.isFuncDeclaration());
826 return e1;
827}
828
829/****************************************
830 * Turn symbol `s` into the expression it represents.
831 *
832 * Params:
833 * s = symbol to resolve
834 * loc = location of use of `s`
835 * sc = context
836 * hasOverloads = applies if `s` represents a function.
837 * true means it's overloaded and will be resolved later,
838 * false means it's the exact function symbol.
839 * Returns:
840 * `s` turned into an expression, `ErrorExp` if an error occurred
841 */
842Expression symbolToExp(Dsymbol s, const ref Loc loc, Scope *sc, bool hasOverloads)
843{
844 static if (LOGSEMANTIC)
845 {
846 printf("DsymbolExp::resolve(%s %s)\n", s.kind(), s.toChars());
847 }
848
849Lagain:
850 Expression e;
851
852 //printf("DsymbolExp:: %p '%s' is a symbol\n", this, toChars());
853 //printf("s = '%s', s.kind = '%s'\n", s.toChars(), s.kind());
854 Dsymbol olds = s;
855 Declaration d = s.isDeclaration();
856 if (d && (d.storage_class & STC.templateparameter))
857 {
858 s = s.toAlias();
859 }
860 else
861 {
862 // functions are checked after overloading
863 // templates are checked after matching constraints
864 if (!s.isFuncDeclaration() && !s.isTemplateDeclaration())
865 {
866 s.checkDeprecated(loc, sc);
867 if (d)
868 d.checkDisabled(loc, sc);
869 }
870
871 // https://issues.dlang.org/show_bug.cgi?id=12023
872 // if 's' is a tuple variable, the tuple is returned.
873 s = s.toAlias();
874
875 //printf("s = '%s', s.kind = '%s', s.needThis() = %p\n", s.toChars(), s.kind(), s.needThis());
876 if (s != olds && !s.isFuncDeclaration() && !s.isTemplateDeclaration())
877 {
878 s.checkDeprecated(loc, sc);
879 if (d)
880 d.checkDisabled(loc, sc);
881 }
Iain Buclaw7e7ebe32022-10-29 09:05:54 +0200882
883 if (auto sd = s.isDeclaration())
884 {
885 if (sd.isSystem())
886 {
887 if (sc.setUnsafePreview(global.params.systemVariables, false, loc,
888 "cannot access `@system` variable `%s` in @safe code", sd))
889 {
890 return ErrorExp.get();
891 }
892 }
893 }
Iain Buclaw5fee5ec32019-06-18 20:42:10 +0200894 }
895
896 if (auto em = s.isEnumMember())
897 {
898 return em.getVarExp(loc, sc);
899 }
900 if (auto v = s.isVarDeclaration())
901 {
902 //printf("Identifier '%s' is a variable, type '%s'\n", s.toChars(), v.type.toChars());
903 if (sc.intypeof == 1 && !v.inuse)
904 v.dsymbolSemantic(sc);
905 if (!v.type || // during variable type inference
906 !v.type.deco && v.inuse) // during variable type semantic
907 {
908 if (v.inuse) // variable type depends on the variable itself
909 error(loc, "circular reference to %s `%s`", v.kind(), v.toPrettyChars());
910 else // variable type cannot be determined
911 error(loc, "forward reference to %s `%s`", v.kind(), v.toPrettyChars());
912 return ErrorExp.get();
913 }
914 if (v.type.ty == Terror)
915 return ErrorExp.get();
916
917 if ((v.storage_class & STC.manifest) && v._init)
918 {
919 if (v.inuse)
920 {
921 error(loc, "circular initialization of %s `%s`", v.kind(), v.toPrettyChars());
922 return ErrorExp.get();
923 }
924 e = v.expandInitializer(loc);
925 v.inuse++;
926 e = e.expressionSemantic(sc);
927 v.inuse--;
928 return e;
929 }
930
931 // We need to run semantics to correctly set 'STC.field' if it is a member variable
932 // that could be forward referenced. This is needed for 'v.needThis()' to work
933 if (v.isThis())
934 v.dsymbolSemantic(sc);
935
936 // Change the ancestor lambdas to delegate before hasThis(sc) call.
937 if (v.checkNestedReference(sc, loc))
938 return ErrorExp.get();
939
940 if (v.needThis() && hasThis(sc))
941 e = new DotVarExp(loc, new ThisExp(loc), v);
942 else
943 e = new VarExp(loc, v);
944 e = e.expressionSemantic(sc);
945 return e;
946 }
947 if (auto fld = s.isFuncLiteralDeclaration())
948 {
949 //printf("'%s' is a function literal\n", fld.toChars());
950 e = new FuncExp(loc, fld);
951 return e.expressionSemantic(sc);
952 }
953 if (auto f = s.isFuncDeclaration())
954 {
955 f = f.toAliasFunc();
956 if (!f.functionSemantic())
957 return ErrorExp.get();
958
959 if (!hasOverloads && f.checkForwardRef(loc))
960 return ErrorExp.get();
961
962 auto fd = s.isFuncDeclaration();
963 fd.type = f.type;
964 return new VarExp(loc, fd, hasOverloads);
965 }
966 if (OverDeclaration od = s.isOverDeclaration())
967 {
968 e = new VarExp(loc, od, true);
969 e.type = Type.tvoid;
970 return e;
971 }
972 if (OverloadSet o = s.isOverloadSet())
973 {
974 //printf("'%s' is an overload set\n", o.toChars());
975 return new OverExp(loc, o);
976 }
977
978 if (Import imp = s.isImport())
979 {
980 if (!imp.pkg)
981 {
982 .error(loc, "forward reference of import `%s`", imp.toChars());
983 return ErrorExp.get();
984 }
985 auto ie = new ScopeExp(loc, imp.pkg);
986 return ie.expressionSemantic(sc);
987 }
988 if (Package pkg = s.isPackage())
989 {
990 auto ie = new ScopeExp(loc, pkg);
991 return ie.expressionSemantic(sc);
992 }
993 if (Module mod = s.isModule())
994 {
995 auto ie = new ScopeExp(loc, mod);
996 return ie.expressionSemantic(sc);
997 }
998 if (Nspace ns = s.isNspace())
999 {
1000 auto ie = new ScopeExp(loc, ns);
1001 return ie.expressionSemantic(sc);
1002 }
1003
1004 if (Type t = s.getType())
1005 {
1006 return (new TypeExp(loc, t)).expressionSemantic(sc);
1007 }
1008
1009 if (TupleDeclaration tup = s.isTupleDeclaration())
1010 {
1011 if (tup.needThis() && hasThis(sc))
1012 e = new DotVarExp(loc, new ThisExp(loc), tup);
1013 else
1014 e = new TupleExp(loc, tup);
1015 e = e.expressionSemantic(sc);
1016 return e;
1017 }
1018
1019 if (TemplateInstance ti = s.isTemplateInstance())
1020 {
1021 ti.dsymbolSemantic(sc);
1022 if (!ti.inst || ti.errors)
1023 return ErrorExp.get();
1024 s = ti.toAlias();
1025 if (!s.isTemplateInstance())
1026 goto Lagain;
1027 e = new ScopeExp(loc, ti);
1028 e = e.expressionSemantic(sc);
1029 return e;
1030 }
1031 if (TemplateDeclaration td = s.isTemplateDeclaration())
1032 {
1033 Dsymbol p = td.toParentLocal();
1034 FuncDeclaration fdthis = hasThis(sc);
1035 AggregateDeclaration ad = p ? p.isAggregateDeclaration() : null;
1036 if (fdthis && ad && fdthis.isMemberLocal() == ad && (td._scope.stc & STC.static_) == 0)
1037 {
1038 e = new DotTemplateExp(loc, new ThisExp(loc), td);
1039 }
1040 else
1041 e = new TemplateExp(loc, td);
1042 e = e.expressionSemantic(sc);
1043 return e;
1044 }
1045
1046 .error(loc, "%s `%s` is not a variable", s.kind(), s.toChars());
1047 return ErrorExp.get();
1048}
1049
1050/*************************************************************
1051 * Given var, get the
1052 * right `this` pointer if var is in an outer class, but our
1053 * existing `this` pointer is in an inner class.
1054 * Params:
1055 * loc = location to use for error messages
1056 * sc = context
1057 * ad = struct or class we need the correct `this` for
1058 * e1 = existing `this`
1059 * var = the specific member of ad we're accessing
1060 * flag = if true, return `null` instead of throwing an error
1061 * Returns:
1062 * Expression representing the `this` for the var
1063 */
1064private Expression getRightThis(const ref Loc loc, Scope* sc, AggregateDeclaration ad, Expression e1, Dsymbol var, int flag = 0)
1065{
1066 //printf("\ngetRightThis(e1 = %s, ad = %s, var = %s)\n", e1.toChars(), ad.toChars(), var.toChars());
1067L1:
1068 Type t = e1.type.toBasetype();
1069 //printf("e1.type = %s, var.type = %s\n", e1.type.toChars(), var.type.toChars());
1070
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01001071 if (e1.op == EXP.objcClassReference)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02001072 {
1073 // We already have an Objective-C class reference, just use that as 'this'.
1074 return e1;
1075 }
1076 else if (ad && ad.isClassDeclaration && ad.isClassDeclaration.classKind == ClassKind.objc &&
1077 var.isFuncDeclaration && var.isFuncDeclaration.isStatic &&
1078 var.isFuncDeclaration.objc.selector)
1079 {
1080 return new ObjcClassReferenceExp(e1.loc, ad.isClassDeclaration());
1081 }
1082
1083 /* Access of a member which is a template parameter in dual-scope scenario
1084 * class A { inc(alias m)() { ++m; } } // `m` needs `this` of `B`
1085 * class B {int m; inc() { new A().inc!m(); } }
1086 */
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01001087 if (e1.op == EXP.this_)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02001088 {
1089 FuncDeclaration f = hasThis(sc);
Iain Buclaw235d5a92022-03-29 16:57:10 +02001090 if (f && f.hasDualContext())
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02001091 {
1092 if (f.followInstantiationContext(ad))
1093 {
1094 e1 = new VarExp(loc, f.vthis);
1095 e1 = new PtrExp(loc, e1);
1096 e1 = new IndexExp(loc, e1, IntegerExp.literal!1);
1097 e1 = getThisSkipNestedFuncs(loc, sc, f.toParent2(), ad, e1, t, var);
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01001098 if (e1.op == EXP.error)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02001099 return e1;
1100 goto L1;
1101 }
1102 }
1103 }
1104
1105 /* If e1 is not the 'this' pointer for ad
1106 */
1107 if (ad &&
1108 !(t.isTypePointer() && t.nextOf().isTypeStruct() && t.nextOf().isTypeStruct().sym == ad) &&
1109 !(t.isTypeStruct() && t.isTypeStruct().sym == ad))
1110 {
1111 ClassDeclaration cd = ad.isClassDeclaration();
1112 ClassDeclaration tcd = t.isClassHandle();
1113
1114 /* e1 is the right this if ad is a base class of e1
1115 */
1116 if (!cd || !tcd || !(tcd == cd || cd.isBaseOf(tcd, null)))
1117 {
1118 /* Only classes can be inner classes with an 'outer'
1119 * member pointing to the enclosing class instance
1120 */
1121 if (tcd && tcd.isNested())
1122 {
1123 /* e1 is the 'this' pointer for an inner class: tcd.
1124 * Rewrite it as the 'this' pointer for the outer class.
1125 */
1126 auto vthis = tcd.followInstantiationContext(ad) ? tcd.vthis2 : tcd.vthis;
1127 e1 = new DotVarExp(loc, e1, vthis);
1128 e1.type = vthis.type;
1129 e1.type = e1.type.addMod(t.mod);
1130 // Do not call ensureStaticLinkTo()
1131 //e1 = e1.semantic(sc);
1132
1133 // Skip up over nested functions, and get the enclosing
1134 // class type.
1135 e1 = getThisSkipNestedFuncs(loc, sc, tcd.toParentP(ad), ad, e1, t, var);
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01001136 if (e1.op == EXP.error)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02001137 return e1;
1138 goto L1;
1139 }
1140
1141 /* Can't find a path from e1 to ad
1142 */
1143 if (flag)
1144 return null;
1145 e1.error("`this` for `%s` needs to be type `%s` not type `%s`", var.toChars(), ad.toChars(), t.toChars());
1146 return ErrorExp.get();
1147 }
1148 }
1149 return e1;
1150}
1151
1152/***************************************
1153 * Pull out any properties.
1154 */
1155private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 = null)
1156{
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01001157 //printf("resolvePropertiesX, e1 = %s %s, e2 = %s\n", EXPtoString(e1.op).ptr, e1.toChars(), e2 ? e2.toChars() : null);
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02001158 Loc loc = e1.loc;
1159
1160 OverloadSet os;
1161 Dsymbol s;
1162 Objects* tiargs;
1163 Type tthis;
1164 if (auto de = e1.isDotExp())
1165 {
1166 if (auto oe = de.e2.isOverExp())
1167 {
1168 tiargs = null;
1169 tthis = de.e1.type;
1170 os = oe.vars;
1171 goto Los;
1172 }
1173 }
1174 else if (e1.isOverExp())
1175 {
1176 tiargs = null;
1177 tthis = null;
1178 os = e1.isOverExp().vars;
1179 Los:
1180 assert(os);
1181 FuncDeclaration fd = null;
1182 if (e2)
1183 {
1184 e2 = e2.expressionSemantic(sc);
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01001185 if (e2.op == EXP.error)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02001186 return ErrorExp.get();
1187 e2 = resolveProperties(sc, e2);
1188
1189 Expressions a;
1190 a.push(e2);
1191
1192 for (size_t i = 0; i < os.a.dim; i++)
1193 {
1194 if (FuncDeclaration f = resolveFuncCall(loc, sc, os.a[i], tiargs, tthis, &a, FuncResolveFlag.quiet))
1195 {
1196 if (f.errors)
1197 return ErrorExp.get();
1198 fd = f;
1199 assert(fd.type.ty == Tfunction);
1200 }
1201 }
1202 if (fd)
1203 {
1204 Expression e = new CallExp(loc, e1, e2);
1205 return e.expressionSemantic(sc);
1206 }
1207 }
1208 {
1209 for (size_t i = 0; i < os.a.dim; i++)
1210 {
1211 if (FuncDeclaration f = resolveFuncCall(loc, sc, os.a[i], tiargs, tthis, null, FuncResolveFlag.quiet))
1212 {
1213 if (f.errors)
1214 return ErrorExp.get();
1215 fd = f;
1216 assert(fd.type.ty == Tfunction);
1217 auto tf = fd.type.isTypeFunction();
1218 if (!tf.isref && e2)
1219 {
1220 error(loc, "%s is not an lvalue", e1.toChars());
1221 return ErrorExp.get();
1222 }
1223 }
1224 }
1225 if (fd)
1226 {
1227 Expression e = new CallExp(loc, e1);
1228 if (e2)
1229 e = new AssignExp(loc, e, e2);
1230 return e.expressionSemantic(sc);
1231 }
1232 }
1233 if (e2)
1234 goto Leprop;
1235 }
1236 else if (auto dti = e1.isDotTemplateInstanceExp())
1237 {
1238 if (!dti.findTempDecl(sc))
1239 goto Leprop;
1240 if (!dti.ti.semanticTiargs(sc))
1241 goto Leprop;
1242 tiargs = dti.ti.tiargs;
1243 tthis = dti.e1.type;
1244 if ((os = dti.ti.tempdecl.isOverloadSet()) !is null)
1245 goto Los;
1246 if ((s = dti.ti.tempdecl) !is null)
1247 goto Lfd;
1248 }
1249 else if (auto dte = e1.isDotTemplateExp())
1250 {
1251 s = dte.td;
1252 tiargs = null;
1253 tthis = dte.e1.type;
1254 goto Lfd;
1255 }
1256 else if (auto se = e1.isScopeExp())
1257 {
1258 s = se.sds;
1259 TemplateInstance ti = s.isTemplateInstance();
1260 if (ti && !ti.semanticRun && ti.tempdecl)
1261 {
1262 //assert(ti.needsTypeInference(sc));
1263 if (!ti.semanticTiargs(sc))
1264 goto Leprop;
1265 tiargs = ti.tiargs;
1266 tthis = null;
1267 if ((os = ti.tempdecl.isOverloadSet()) !is null)
1268 goto Los;
1269 if ((s = ti.tempdecl) !is null)
1270 goto Lfd;
1271 }
1272 }
1273 else if (auto te = e1.isTemplateExp())
1274 {
1275 s = te.td;
1276 tiargs = null;
1277 tthis = null;
1278 goto Lfd;
1279 }
Iain Buclaw6384eff2022-02-20 20:02:23 +01001280 else if (e1.isDotVarExp() && e1.type && (e1.type.toBasetype().isTypeFunction() || e1.isDotVarExp().var.isOverDeclaration()))
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02001281 {
Iain Buclaw6384eff2022-02-20 20:02:23 +01001282 DotVarExp dve = e1.isDotVarExp();
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02001283 s = dve.var;
1284 tiargs = null;
1285 tthis = dve.e1.type;
1286 goto Lfd;
1287 }
Iain Buclaw6384eff2022-02-20 20:02:23 +01001288 else if (sc && sc.flags & SCOPE.Cfile && e1.isVarExp() && !e2)
Iain Buclaw0fb57032021-12-05 17:11:12 +01001289 {
1290 // ImportC: do not implicitly call function if no ( ) are present
1291 }
Iain Buclaw6384eff2022-02-20 20:02:23 +01001292 else if (e1.isVarExp() && e1.type && (e1.type.toBasetype().isTypeFunction() || e1.isVarExp().var.isOverDeclaration()))
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02001293 {
Iain Buclaw6384eff2022-02-20 20:02:23 +01001294 s = e1.isVarExp().var;
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02001295 tiargs = null;
1296 tthis = null;
1297 Lfd:
1298 assert(s);
1299 if (e2)
1300 {
1301 e2 = e2.expressionSemantic(sc);
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01001302 if (e2.op == EXP.error)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02001303 return ErrorExp.get();
1304 e2 = resolveProperties(sc, e2);
1305
1306 Expressions a;
1307 a.push(e2);
1308
1309 FuncDeclaration fd = resolveFuncCall(loc, sc, s, tiargs, tthis, &a, FuncResolveFlag.quiet);
1310 if (fd && fd.type)
1311 {
1312 if (fd.errors)
1313 return ErrorExp.get();
1314 if (!checkSymbolAccess(sc, fd))
1315 {
Iain Buclaw6384eff2022-02-20 20:02:23 +01001316 // @@@DEPRECATED_2.105@@@
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02001317 // When turning into error, uncomment the return statement
Iain Buclaw6384eff2022-02-20 20:02:23 +01001318 TypeFunction tf = fd.type.isTypeFunction();
Iain Buclaw5eb99272022-05-16 18:30:46 +02001319 deprecation(loc, "function `%s` of type `%s` is not accessible from module `%s`",
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02001320 fd.toPrettyChars(), tf.toChars, sc._module.toChars);
1321 //return ErrorExp.get();
1322 }
1323 assert(fd.type.ty == Tfunction);
1324 Expression e = new CallExp(loc, e1, e2);
1325 return e.expressionSemantic(sc);
1326 }
1327 }
1328 {
1329 FuncDeclaration fd = resolveFuncCall(loc, sc, s, tiargs, tthis, null, FuncResolveFlag.quiet);
1330 if (fd && fd.type)
1331 {
1332 if (fd.errors)
1333 return ErrorExp.get();
Iain Buclaw6384eff2022-02-20 20:02:23 +01001334 TypeFunction tf = fd.type.isTypeFunction();
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02001335 if (!e2 || tf.isref)
1336 {
1337 if (!checkSymbolAccess(sc, fd))
1338 {
Iain Buclaw6384eff2022-02-20 20:02:23 +01001339 // @@@DEPRECATED_2.105@@@
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02001340 // When turning into error, uncomment the return statement
Iain Buclaw5eb99272022-05-16 18:30:46 +02001341 deprecation(loc, "function `%s` of type `%s` is not accessible from module `%s`",
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02001342 fd.toPrettyChars(), tf.toChars, sc._module.toChars);
1343 //return ErrorExp.get();
1344 }
1345 Expression e = new CallExp(loc, e1);
1346 if (e2)
1347 e = new AssignExp(loc, e, e2);
1348 return e.expressionSemantic(sc);
1349 }
1350 }
1351 }
1352 if (FuncDeclaration fd = s.isFuncDeclaration())
1353 {
1354 // Keep better diagnostic message for invalid property usage of functions
1355 assert(fd.type.ty == Tfunction);
1356 Expression e = new CallExp(loc, e1, e2);
1357 return e.expressionSemantic(sc);
1358 }
1359 if (e2)
1360 goto Leprop;
1361 }
Iain Buclaw6384eff2022-02-20 20:02:23 +01001362 if (auto ve = e1.isVarExp())
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02001363 {
Iain Buclaw6384eff2022-02-20 20:02:23 +01001364 if (auto v = ve.var.isVarDeclaration())
1365 {
1366 if (ve.checkPurity(sc, v))
1367 return ErrorExp.get();
1368 }
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02001369 }
1370 if (e2)
1371 return null;
1372
Iain Buclaw6384eff2022-02-20 20:02:23 +01001373 if (e1.type && !e1.isTypeExp()) // function type is not a property
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02001374 {
1375 /* Look for e1 being a lazy parameter; rewrite as delegate call
1376 * only if the symbol wasn't already treated as a delegate
1377 */
1378 auto ve = e1.isVarExp();
1379 if (ve && ve.var.storage_class & STC.lazy_ && !ve.delegateWasExtracted)
1380 {
1381 Expression e = new CallExp(loc, e1);
1382 return e.expressionSemantic(sc);
1383 }
Iain Buclaw6384eff2022-02-20 20:02:23 +01001384 else if (e1.isDotVarExp())
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02001385 {
1386 // Check for reading overlapped pointer field in @safe code.
1387 if (checkUnsafeAccess(sc, e1, true, true))
1388 return ErrorExp.get();
1389 }
Iain Buclaw6384eff2022-02-20 20:02:23 +01001390 else if (auto ce = e1.isCallExp())
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02001391 {
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02001392 // Check for reading overlapped pointer field in @safe code.
1393 if (checkUnsafeAccess(sc, ce.e1, true, true))
1394 return ErrorExp.get();
1395 }
1396 }
1397
1398 if (!e1.type)
1399 {
1400 error(loc, "cannot resolve type for %s", e1.toChars());
1401 e1 = ErrorExp.get();
1402 }
1403 return e1;
1404
1405Leprop:
1406 error(loc, "not a property %s", e1.toChars());
1407 return ErrorExp.get();
1408}
1409
1410extern (C++) Expression resolveProperties(Scope* sc, Expression e)
1411{
1412 //printf("resolveProperties(%s)\n", e.toChars());
1413 e = resolvePropertiesX(sc, e);
1414 if (e.checkRightThis(sc))
1415 return ErrorExp.get();
1416 return e;
1417}
1418
1419/****************************************
1420 * The common type is determined by applying ?: to each pair.
1421 * Output:
1422 * exps[] properties resolved, implicitly cast to common type, rewritten in place
1423 * Returns:
1424 * The common type, or `null` if an error has occured
1425 */
1426private Type arrayExpressionToCommonType(Scope* sc, ref Expressions exps)
1427{
1428 /* Still have a problem with:
1429 * ubyte[][] = [ cast(ubyte[])"hello", [1]];
1430 * which works if the array literal is initialized top down with the ubyte[][]
1431 * type, but fails with this function doing bottom up typing.
1432 */
1433
1434 //printf("arrayExpressionToCommonType()\n");
1435 scope IntegerExp integerexp = IntegerExp.literal!0;
1436 scope CondExp condexp = new CondExp(Loc.initial, integerexp, null, null);
1437
1438 Type t0 = null;
1439 Expression e0 = null;
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02001440 bool foundType;
1441
1442 for (size_t i = 0; i < exps.dim; i++)
1443 {
1444 Expression e = exps[i];
1445 if (!e)
1446 continue;
1447
1448 e = resolveProperties(sc, e);
1449 if (!e.type)
1450 {
1451 e.error("`%s` has no value", e.toChars());
1452 t0 = Type.terror;
1453 continue;
1454 }
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01001455 if (e.op == EXP.type)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02001456 {
1457 foundType = true; // do not break immediately, there might be more errors
1458 e.checkValue(); // report an error "type T has no value"
1459 t0 = Type.terror;
1460 continue;
1461 }
1462 if (e.type.ty == Tvoid)
1463 {
1464 // void expressions do not concur to the determination of the common
1465 // type.
1466 continue;
1467 }
1468 if (checkNonAssignmentArrayOp(e))
1469 {
1470 t0 = Type.terror;
1471 continue;
1472 }
1473
1474 e = doCopyOrMove(sc, e);
1475
1476 if (!foundType && t0 && !t0.equals(e.type))
1477 {
1478 /* This applies ?: to merge the types. It's backwards;
1479 * ?: should call this function to merge types.
1480 */
1481 condexp.type = null;
1482 condexp.e1 = e0;
1483 condexp.e2 = e;
1484 condexp.loc = e.loc;
1485 Expression ex = condexp.expressionSemantic(sc);
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01001486 if (ex.op == EXP.error)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02001487 e = ex;
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02001488 else
1489 {
1490 // Convert to common type
Iain Buclaw0fb57032021-12-05 17:11:12 +01001491 exps[i] = condexp.e1.castTo(sc, condexp.type);
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02001492 e = condexp.e2.castTo(sc, condexp.type);
1493 }
1494 }
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02001495 e0 = e;
1496 t0 = e.type;
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01001497 if (e.op != EXP.error)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02001498 exps[i] = e;
1499 }
1500
1501 // [] is typed as void[]
1502 if (!t0)
1503 return Type.tvoid;
1504
1505 // It's an error, don't do the cast
1506 if (t0.ty == Terror)
1507 return null;
1508
1509 for (size_t i = 0; i < exps.dim; i++)
1510 {
1511 Expression e = exps[i];
1512 if (!e)
1513 continue;
1514
1515 e = e.implicitCastTo(sc, t0);
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01001516 if (e.op == EXP.error)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02001517 {
1518 /* https://issues.dlang.org/show_bug.cgi?id=13024
1519 * a workaround for the bug in typeMerge -
1520 * it should paint e1 and e2 by deduced common type,
1521 * but doesn't in this particular case.
1522 */
1523 return null;
1524 }
1525 exps[i] = e;
1526 }
1527 return t0;
1528}
1529
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01001530private Expression opAssignToOp(const ref Loc loc, EXP op, Expression e1, Expression e2)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02001531{
1532 Expression e;
1533 switch (op)
1534 {
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01001535 case EXP.addAssign:
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02001536 e = new AddExp(loc, e1, e2);
1537 break;
1538
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01001539 case EXP.minAssign:
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02001540 e = new MinExp(loc, e1, e2);
1541 break;
1542
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01001543 case EXP.mulAssign:
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02001544 e = new MulExp(loc, e1, e2);
1545 break;
1546
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01001547 case EXP.divAssign:
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02001548 e = new DivExp(loc, e1, e2);
1549 break;
1550
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01001551 case EXP.modAssign:
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02001552 e = new ModExp(loc, e1, e2);
1553 break;
1554
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01001555 case EXP.andAssign:
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02001556 e = new AndExp(loc, e1, e2);
1557 break;
1558
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01001559 case EXP.orAssign:
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02001560 e = new OrExp(loc, e1, e2);
1561 break;
1562
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01001563 case EXP.xorAssign:
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02001564 e = new XorExp(loc, e1, e2);
1565 break;
1566
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01001567 case EXP.leftShiftAssign:
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02001568 e = new ShlExp(loc, e1, e2);
1569 break;
1570
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01001571 case EXP.rightShiftAssign:
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02001572 e = new ShrExp(loc, e1, e2);
1573 break;
1574
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01001575 case EXP.unsignedRightShiftAssign:
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02001576 e = new UshrExp(loc, e1, e2);
1577 break;
1578
1579 default:
1580 assert(0);
1581 }
1582 return e;
1583}
1584
1585/*********************
1586 * Rewrite:
1587 * array.length op= e2
1588 * as:
1589 * array.length = array.length op e2
1590 * or:
1591 * auto tmp = &array;
1592 * (*tmp).length = (*tmp).length op e2
1593 */
1594private Expression rewriteOpAssign(BinExp exp)
1595{
Iain Buclaw6384eff2022-02-20 20:02:23 +01001596 ArrayLengthExp ale = exp.e1.isArrayLengthExp();
1597 if (ale.e1.isVarExp())
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02001598 {
Iain Buclaw6384eff2022-02-20 20:02:23 +01001599 Expression e = opAssignToOp(exp.loc, exp.op, ale, exp.e2);
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02001600 e = new AssignExp(exp.loc, ale.syntaxCopy(), e);
Iain Buclaw6384eff2022-02-20 20:02:23 +01001601 return e;
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02001602 }
1603 else
1604 {
1605 /* auto tmp = &array;
1606 * (*tmp).length = (*tmp).length op e2
1607 */
1608 auto tmp = copyToTemp(0, "__arraylength", new AddrExp(ale.loc, ale.e1));
1609
1610 Expression e1 = new ArrayLengthExp(ale.loc, new PtrExp(ale.loc, new VarExp(ale.loc, tmp)));
1611 Expression elvalue = e1.syntaxCopy();
Iain Buclaw6384eff2022-02-20 20:02:23 +01001612 Expression e = opAssignToOp(exp.loc, exp.op, e1, exp.e2);
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02001613 e = new AssignExp(exp.loc, elvalue, e);
1614 e = new CommaExp(exp.loc, new DeclarationExp(ale.loc, tmp), e);
Iain Buclaw6384eff2022-02-20 20:02:23 +01001615 return e;
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02001616 }
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02001617}
1618
1619/****************************************
1620 * Preprocess arguments to function.
1621 * Input:
1622 * reportErrors whether or not to report errors here. Some callers are not
1623 * checking actual function params, so they'll do their own error reporting
1624 * Output:
1625 * exps[] tuples expanded, properties resolved, rewritten in place
1626 * Returns:
1627 * true a semantic error occurred
1628 */
1629private bool preFunctionParameters(Scope* sc, Expressions* exps, const bool reportErrors = true)
1630{
1631 bool err = false;
1632 if (exps)
1633 {
1634 expandTuples(exps);
1635
1636 for (size_t i = 0; i < exps.dim; i++)
1637 {
1638 Expression arg = (*exps)[i];
1639 arg = resolveProperties(sc, arg);
Iain Buclaw0fb57032021-12-05 17:11:12 +01001640 arg = arg.arrayFuncConv(sc);
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01001641 if (arg.op == EXP.type)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02001642 {
1643 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
1644 arg = resolveAliasThis(sc, arg);
1645
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01001646 if (arg.op == EXP.type)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02001647 {
1648 if (reportErrors)
1649 {
1650 arg.error("cannot pass type `%s` as a function argument", arg.toChars());
1651 arg = ErrorExp.get();
1652 }
1653 err = true;
1654 }
1655 }
1656 else if (arg.type.toBasetype().ty == Tfunction)
1657 {
1658 if (reportErrors)
1659 {
1660 arg.error("cannot pass function `%s` as a function argument", arg.toChars());
1661 arg = ErrorExp.get();
1662 }
1663 err = true;
1664 }
1665 else if (checkNonAssignmentArrayOp(arg))
1666 {
1667 arg = ErrorExp.get();
1668 err = true;
1669 }
1670 (*exps)[i] = arg;
1671 }
1672 }
1673 return err;
1674}
1675
1676/********************************************
1677 * Issue an error if default construction is disabled for type t.
1678 * Default construction is required for arrays and 'out' parameters.
1679 * Returns:
1680 * true an error was issued
1681 */
1682private bool checkDefCtor(Loc loc, Type t)
1683{
Iain Buclaw6384eff2022-02-20 20:02:23 +01001684 if (auto ts = t.baseElemOf().isTypeStruct())
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02001685 {
Iain Buclaw6384eff2022-02-20 20:02:23 +01001686 StructDeclaration sd = ts.sym;
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02001687 if (sd.noDefaultCtor)
1688 {
1689 sd.error(loc, "default construction is disabled");
1690 return true;
1691 }
1692 }
1693 return false;
1694}
1695
1696/****************************************
1697 * Now that we know the exact type of the function we're calling,
1698 * the arguments[] need to be adjusted:
1699 * 1. implicitly convert argument to the corresponding parameter type
1700 * 2. add default arguments for any missing arguments
1701 * 3. do default promotions on arguments corresponding to ...
1702 * 4. add hidden _arguments[] argument
1703 * 5. call copy constructor for struct value arguments
1704 * Params:
1705 * loc = location of function call
1706 * sc = context
1707 * tf = type of the function
1708 * ethis = `this` argument, `null` if none or not known
1709 * tthis = type of `this` argument, `null` if no `this` argument
1710 * arguments = array of actual arguments to function call
1711 * fd = the function being called, `null` if called indirectly
1712 * prettype = set to return type of function
1713 * peprefix = set to expression to execute before `arguments[]` are evaluated, `null` if none
1714 * Returns:
1715 * true errors happened
1716 */
1717private bool functionParameters(const ref Loc loc, Scope* sc,
1718 TypeFunction tf, Expression ethis, Type tthis, Expressions* arguments, FuncDeclaration fd,
1719 Type* prettype, Expression* peprefix)
1720{
1721 //printf("functionParameters() %s\n", fd ? fd.toChars() : "");
1722 assert(arguments);
1723 assert(fd || tf.next);
1724 size_t nargs = arguments ? arguments.dim : 0;
1725 const size_t nparams = tf.parameterList.length;
1726 const olderrors = global.errors;
1727 bool err = false;
1728 *prettype = Type.terror;
1729 Expression eprefix = null;
1730 *peprefix = null;
1731
1732 if (nargs > nparams && tf.parameterList.varargs == VarArg.none)
1733 {
1734 error(loc, "expected %llu arguments, not %llu for non-variadic function type `%s`", cast(ulong)nparams, cast(ulong)nargs, tf.toChars());
1735 return true;
1736 }
1737
1738 // If inferring return type, and semantic3() needs to be run if not already run
1739 if (!tf.next && fd.inferRetType)
1740 {
1741 fd.functionSemantic();
1742 }
1743 else if (fd && fd.parent)
1744 {
1745 TemplateInstance ti = fd.parent.isTemplateInstance();
1746 if (ti && ti.tempdecl)
1747 {
1748 fd.functionSemantic3();
1749 }
1750 }
1751
1752 /* If calling a pragma(inline, true) function,
1753 * set flag to later scan for inlines.
1754 */
1755 if (fd && fd.inlining == PINLINE.always)
1756 {
1757 if (sc._module)
1758 sc._module.hasAlwaysInlines = true;
1759 if (sc.func)
Iain Buclaw7e7ebe32022-10-29 09:05:54 +02001760 sc.func.hasAlwaysInlines = true;
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02001761 }
1762
1763 const isCtorCall = fd && fd.needThis() && fd.isCtorDeclaration();
1764
1765 const size_t n = (nargs > nparams) ? nargs : nparams; // n = max(nargs, nparams)
1766
1767 /* If the function return type has wildcards in it, we'll need to figure out the actual type
1768 * based on the actual argument types.
1769 * Start with the `this` argument, later on merge into wildmatch the mod bits of the rest
1770 * of the arguments.
1771 */
1772 MOD wildmatch = (tthis && !isCtorCall) ? tthis.Type.deduceWild(tf, false) : 0;
1773
1774 bool done = false;
1775 foreach (const i; 0 .. n)
1776 {
1777 Expression arg = (i < nargs) ? (*arguments)[i] : null;
1778
1779 if (i < nparams)
1780 {
1781 bool errorArgs()
1782 {
1783 error(loc, "expected %llu function arguments, not %llu", cast(ulong)nparams, cast(ulong)nargs);
1784 return true;
1785 }
1786
1787 Parameter p = tf.parameterList[i];
1788
1789 if (!arg)
1790 {
1791 if (!p.defaultArg)
1792 {
1793 if (tf.parameterList.varargs == VarArg.typesafe && i + 1 == nparams)
1794 goto L2;
1795 return errorArgs();
1796 }
1797 arg = p.defaultArg;
1798 arg = inlineCopy(arg, sc);
1799 // __FILE__, __LINE__, __MODULE__, __FUNCTION__, and __PRETTY_FUNCTION__
1800 arg = arg.resolveLoc(loc, sc);
1801 arguments.push(arg);
1802 nargs++;
1803 }
1804 else
1805 {
1806 if (isDefaultInitOp(arg.op))
1807 {
1808 arg = arg.resolveLoc(loc, sc);
1809 (*arguments)[i] = arg;
1810 }
1811 }
1812
1813
1814 if (tf.parameterList.varargs == VarArg.typesafe && i + 1 == nparams) // https://dlang.org/spec/function.html#variadic
1815 {
1816 //printf("\t\tvarargs == 2, p.type = '%s'\n", p.type.toChars());
1817 {
1818 MATCH m;
1819 if ((m = arg.implicitConvTo(p.type)) > MATCH.nomatch)
1820 {
1821 if (p.type.nextOf() && arg.implicitConvTo(p.type.nextOf()) >= m)
1822 goto L2;
1823 else if (nargs != nparams)
1824 return errorArgs();
1825 goto L1;
1826 }
1827 }
1828 L2:
1829 Type tb = p.type.toBasetype();
1830 switch (tb.ty)
1831 {
1832 case Tsarray:
1833 case Tarray:
1834 {
1835 /* Create a static array variable v of type arg.type:
1836 * T[dim] __arrayArg = [ arguments[i], ..., arguments[nargs-1] ];
1837 *
1838 * The array literal in the initializer of the hidden variable
1839 * is now optimized.
1840 * https://issues.dlang.org/show_bug.cgi?id=2356
1841 */
1842 Type tbn = (cast(TypeArray)tb).next; // array element type
1843 Type tret = p.isLazyArray();
1844
1845 auto elements = new Expressions(nargs - i);
1846 foreach (u; 0 .. elements.dim)
1847 {
1848 Expression a = (*arguments)[i + u];
1849 if (tret && a.implicitConvTo(tret))
1850 {
1851 // p is a lazy array of delegates, tret is return type of the delegates
1852 a = a.implicitCastTo(sc, tret)
1853 .optimize(WANTvalue)
1854 .toDelegate(tret, sc);
1855 }
1856 else
1857 a = a.implicitCastTo(sc, tbn);
1858 a = a.addDtorHook(sc);
1859 (*elements)[u] = a;
1860 }
1861 // https://issues.dlang.org/show_bug.cgi?id=14395
1862 // Convert to a static array literal, or its slice.
1863 arg = new ArrayLiteralExp(loc, tbn.sarrayOf(nargs - i), elements);
1864 if (tb.ty == Tarray)
1865 {
1866 arg = new SliceExp(loc, arg, null, null);
1867 arg.type = p.type;
1868 }
1869 break;
1870 }
1871 case Tclass:
1872 {
1873 /* Set arg to be:
1874 * new Tclass(arg0, arg1, ..., argn)
1875 */
1876 auto args = new Expressions(nargs - i);
1877 foreach (u; i .. nargs)
1878 (*args)[u - i] = (*arguments)[u];
Iain Buclaw6384eff2022-02-20 20:02:23 +01001879 arg = new NewExp(loc, null, p.type, args);
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02001880 break;
1881 }
1882 default:
1883 if (!arg)
1884 {
1885 error(loc, "not enough arguments");
1886 return true;
1887 }
1888 break;
1889 }
1890 arg = arg.expressionSemantic(sc);
1891 //printf("\targ = '%s'\n", arg.toChars());
1892 arguments.setDim(i + 1);
1893 (*arguments)[i] = arg;
1894 nargs = i + 1;
1895 done = true;
1896 }
1897
1898 L1:
Iain Buclawec486b72022-06-13 10:41:57 +02001899 if (!(p.isLazy() && p.type.ty == Tvoid))
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02001900 {
1901 if (ubyte wm = arg.type.deduceWild(p.type, p.isReference()))
1902 {
1903 wildmatch = wildmatch ? MODmerge(wildmatch, wm) : wm;
1904 //printf("[%d] p = %s, a = %s, wm = %d, wildmatch = %d\n", i, p.type.toChars(), arg.type.toChars(), wm, wildmatch);
1905 }
1906 }
1907 }
1908 if (done)
1909 break;
1910 }
1911 if ((wildmatch == MODFlags.mutable || wildmatch == MODFlags.immutable_) &&
1912 tf.next && tf.next.hasWild() &&
1913 (tf.isref || !tf.next.implicitConvTo(tf.next.immutableOf())))
1914 {
1915 bool errorInout(MOD wildmatch)
1916 {
1917 const(char)* s = wildmatch == MODFlags.mutable ? "mutable" : MODtoChars(wildmatch);
1918 error(loc, "modify `inout` to `%s` is not allowed inside `inout` function", s);
1919 return true;
1920 }
1921
1922 if (fd)
1923 {
1924 /* If the called function may return the reference to
1925 * outer inout data, it should be rejected.
1926 *
1927 * void foo(ref inout(int) x) {
1928 * ref inout(int) bar(inout(int)) { return x; }
1929 * struct S {
1930 * ref inout(int) bar() inout { return x; }
1931 * ref inout(int) baz(alias a)() inout { return x; }
1932 * }
1933 * bar(int.init) = 1; // bad!
1934 * S().bar() = 1; // bad!
1935 * }
1936 * void test() {
1937 * int a;
1938 * auto s = foo(a);
1939 * s.baz!a() = 1; // bad!
1940 * }
1941 *
1942 */
1943 bool checkEnclosingWild(Dsymbol s)
1944 {
1945 bool checkWild(Dsymbol s)
1946 {
1947 if (!s)
1948 return false;
1949 if (auto ad = s.isAggregateDeclaration())
1950 {
1951 if (ad.isNested())
1952 return checkEnclosingWild(s);
1953 }
1954 else if (auto ff = s.isFuncDeclaration())
1955 {
Iain Buclaw6384eff2022-02-20 20:02:23 +01001956 if (ff.type.isTypeFunction().iswild)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02001957 return errorInout(wildmatch);
1958
1959 if (ff.isNested() || ff.isThis())
1960 return checkEnclosingWild(s);
1961 }
1962 return false;
1963 }
1964
1965 Dsymbol ctx0 = s.toParent2();
1966 Dsymbol ctx1 = s.toParentLocal();
1967 if (checkWild(ctx0))
1968 return true;
1969 if (ctx0 != ctx1)
1970 return checkWild(ctx1);
1971 return false;
1972 }
1973 if ((fd.isThis() || fd.isNested()) && checkEnclosingWild(fd))
1974 return true;
1975 }
1976 else if (tf.isWild())
1977 return errorInout(wildmatch);
1978 }
1979
1980 Expression firstArg = ((tf.next && tf.next.ty == Tvoid || isCtorCall) &&
1981 tthis &&
1982 tthis.isMutable() && tthis.toBasetype().ty == Tstruct &&
1983 tthis.hasPointers())
1984 ? ethis : null;
1985
1986 assert(nargs >= nparams);
1987 foreach (const i, arg; (*arguments)[0 .. nargs])
1988 {
1989 assert(arg);
1990 if (i < nparams)
1991 {
1992 Parameter p = tf.parameterList[i];
1993 Type targ = arg.type; // keep original type for isCopyable() because alias this
1994 // resolution may hide an uncopyable type
1995
Iain Buclawec486b72022-06-13 10:41:57 +02001996 if (!(p.isLazy() && p.type.ty == Tvoid))
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02001997 {
1998 Type tprm = p.type.hasWild()
1999 ? p.type.substWildTo(wildmatch)
2000 : p.type;
2001
Iain Buclaw6384eff2022-02-20 20:02:23 +01002002 const hasCopyCtor = arg.type.isTypeStruct() && arg.type.isTypeStruct().sym.hasCopyCtor;
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02002003 const typesMatch = arg.type.mutableOf().unSharedOf().equals(tprm.mutableOf().unSharedOf());
2004 if (!((hasCopyCtor && typesMatch) || tprm.equals(arg.type)))
2005 {
2006 //printf("arg.type = %s, p.type = %s\n", arg.type.toChars(), p.type.toChars());
2007 arg = arg.implicitCastTo(sc, tprm);
2008 arg = arg.optimize(WANTvalue, p.isReference());
2009 }
2010 }
2011
2012 // Support passing rvalue to `in` parameters
2013 if ((p.storageClass & (STC.in_ | STC.ref_)) == (STC.in_ | STC.ref_))
2014 {
2015 if (!arg.isLvalue())
2016 {
2017 auto v = copyToTemp(STC.exptemp, "__rvalue", arg);
2018 Expression ev = new DeclarationExp(arg.loc, v);
2019 ev = new CommaExp(arg.loc, ev, new VarExp(arg.loc, v));
2020 arg = ev.expressionSemantic(sc);
2021 }
2022 arg = arg.toLvalue(sc, arg);
2023
2024 // Look for mutable misaligned pointer, etc., in @safe mode
2025 err |= checkUnsafeAccess(sc, arg, false, true);
2026 }
2027 else if (p.storageClass & STC.ref_)
2028 {
Iain Buclawfbdaa582022-03-21 16:52:40 +01002029 if (global.params.rvalueRefParam == FeatureState.enabled &&
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02002030 !arg.isLvalue() &&
2031 targ.isCopyable())
2032 { /* allow rvalues to be passed to ref parameters by copying
2033 * them to a temp, then pass the temp as the argument
2034 */
2035 auto v = copyToTemp(0, "__rvalue", arg);
2036 Expression ev = new DeclarationExp(arg.loc, v);
2037 ev = new CommaExp(arg.loc, ev, new VarExp(arg.loc, v));
2038 arg = ev.expressionSemantic(sc);
2039 }
2040 arg = arg.toLvalue(sc, arg);
2041
2042 // Look for mutable misaligned pointer, etc., in @safe mode
2043 err |= checkUnsafeAccess(sc, arg, false, true);
2044 }
2045 else if (p.storageClass & STC.out_)
2046 {
2047 Type t = arg.type;
2048 if (!t.isMutable() || !t.isAssignable()) // check blit assignable
2049 {
2050 arg.error("cannot modify struct `%s` with immutable members", arg.toChars());
2051 err = true;
2052 }
2053 else
2054 {
2055 // Look for misaligned pointer, etc., in @safe mode
2056 err |= checkUnsafeAccess(sc, arg, false, true);
2057 err |= checkDefCtor(arg.loc, t); // t must be default constructible
2058 }
2059 arg = arg.toLvalue(sc, arg);
2060 }
Iain Buclawec486b72022-06-13 10:41:57 +02002061 else if (p.isLazy())
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02002062 {
2063 // Convert lazy argument to a delegate
2064 auto t = (p.type.ty == Tvoid) ? p.type : arg.type;
2065 arg = toDelegate(arg, t, sc);
2066 }
2067 //printf("arg: %s\n", arg.toChars());
2068 //printf("type: %s\n", arg.type.toChars());
2069 //printf("param: %s\n", p.toChars());
2070
Iain Buclawae56e2d2022-04-21 14:25:26 +01002071 const pStc = tf.parameterStorageClass(tthis, p);
2072
2073 if (firstArg && (pStc & STC.return_))
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02002074 {
2075 /* Argument value can be assigned to firstArg.
2076 * Check arg to see if it matters.
2077 */
Iain Buclaw5eb99272022-05-16 18:30:46 +02002078 err |= checkParamArgumentReturn(sc, firstArg, arg, p, false);
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02002079 }
Iain Buclawae56e2d2022-04-21 14:25:26 +01002080 // Allow 'lazy' to imply 'scope' - lazy parameters can be passed along
2081 // as lazy parameters to the next function, but that isn't escaping.
Iain Buclaw5eb99272022-05-16 18:30:46 +02002082 else if (!(pStc & STC.lazy_))
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02002083 {
2084 /* Argument value can escape from the called function.
2085 * Check arg to see if it matters.
2086 */
Iain Buclawb7a586b2022-08-25 19:04:50 +02002087 VarDeclaration vPar = fd ? (fd.parameters ? (*fd.parameters)[i] : null) : null;
2088 err |= checkParamArgumentEscape(sc, fd, p, vPar, cast(STC) pStc, arg, false, false);
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02002089 }
Iain Buclaw5eb99272022-05-16 18:30:46 +02002090
2091 // Turning heap allocations into stack allocations is dangerous without dip1000, since `scope` inference
2092 // may be unreliable when scope violations only manifest as deprecation warnings.
2093 // However, existing `@nogc` code may rely on it, so still do it when the parameter is explicitly marked `scope`
Iain Buclawec486b72022-06-13 10:41:57 +02002094 const explicitScope = p.isLazy() ||
Iain Buclaw5eb99272022-05-16 18:30:46 +02002095 ((p.storageClass & STC.scope_) && !(p.storageClass & STC.scopeinferred));
2096 if ((pStc & (STC.scope_ | STC.lazy_)) &&
2097 ((global.params.useDIP1000 == FeatureState.enabled) || explicitScope) &&
2098 !(pStc & STC.return_))
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02002099 {
2100 /* Argument value cannot escape from the called function.
2101 */
2102 Expression a = arg;
Iain Buclaw6384eff2022-02-20 20:02:23 +01002103 if (auto ce = a.isCastExp())
2104 a = ce.e1;
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02002105
2106 ArrayLiteralExp ale;
2107 if (p.type.toBasetype().ty == Tarray &&
Iain Buclaw5eb99272022-05-16 18:30:46 +02002108 (ale = a.isArrayLiteralExp()) !is null && ale.elements && ale.elements.length > 0)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02002109 {
2110 // allocate the array literal as temporary static array on the stack
Iain Buclaw5eb99272022-05-16 18:30:46 +02002111 ale.type = ale.type.nextOf().sarrayOf(ale.elements.length);
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02002112 auto tmp = copyToTemp(0, "__arrayliteral_on_stack", ale);
2113 auto declareTmp = new DeclarationExp(ale.loc, tmp);
Iain Buclaw5eb99272022-05-16 18:30:46 +02002114 auto castToSlice = new CastExp(ale.loc, new VarExp(ale.loc, tmp),
2115 p.type.substWildTo(MODFlags.mutable));
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02002116 arg = CommaExp.combine(declareTmp, castToSlice);
2117 arg = arg.expressionSemantic(sc);
2118 }
Iain Buclaw6384eff2022-02-20 20:02:23 +01002119 else if (auto fe = a.isFuncExp())
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02002120 {
2121 /* Function literals can only appear once, so if this
2122 * appearance was scoped, there cannot be any others.
2123 */
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02002124 fe.fd.tookAddressOf = 0;
2125 }
Iain Buclaw6384eff2022-02-20 20:02:23 +01002126 else if (auto de = a.isDelegateExp())
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02002127 {
2128 /* For passing a delegate to a scoped parameter,
2129 * this doesn't count as taking the address of it.
2130 * We only worry about 'escaping' references to the function.
2131 */
Iain Buclaw6384eff2022-02-20 20:02:23 +01002132 if (auto ve = de.e1.isVarExp())
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02002133 {
Iain Buclaw6384eff2022-02-20 20:02:23 +01002134 if (auto f = ve.var.isFuncDeclaration())
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02002135 {
2136 if (f.tookAddressOf)
2137 --f.tookAddressOf;
2138 //printf("--tookAddressOf = %d\n", f.tookAddressOf);
2139 }
2140 }
2141 }
2142 }
2143 if (!p.isReference())
2144 err |= arg.checkSharedAccess(sc);
2145
2146 arg = arg.optimize(WANTvalue, p.isReference());
2147
2148 /* Determine if this parameter is the "first reference" parameter through which
2149 * later "return" arguments can be stored.
2150 */
2151 if (i == 0 && !tthis && p.isReference() && p.type &&
2152 (tf.next && tf.next.ty == Tvoid || isCtorCall))
2153 {
2154 Type tb = p.type.baseElemOf();
2155 if (tb.isMutable() && tb.hasPointers())
2156 {
2157 firstArg = arg;
2158 }
2159 }
2160 }
2161 else
2162 {
2163 // These will be the trailing ... arguments
2164 // If not D linkage, do promotions
2165 if (tf.linkage != LINK.d)
2166 {
2167 // Promote bytes, words, etc., to ints
2168 arg = integralPromotions(arg, sc);
2169
2170 // Promote floats to doubles
2171 switch (arg.type.ty)
2172 {
2173 case Tfloat32:
2174 arg = arg.castTo(sc, Type.tfloat64);
2175 break;
2176
2177 case Timaginary32:
2178 arg = arg.castTo(sc, Type.timaginary64);
2179 break;
2180
2181 default:
2182 break;
2183 }
2184 if (tf.parameterList.varargs == VarArg.variadic)
2185 {
2186 const(char)* p = tf.linkage == LINK.c ? "extern(C)" : "extern(C++)";
2187 if (arg.type.ty == Tarray)
2188 {
2189 arg.error("cannot pass dynamic arrays to `%s` vararg functions", p);
2190 err = true;
2191 }
2192 if (arg.type.ty == Tsarray)
2193 {
2194 arg.error("cannot pass static arrays to `%s` vararg functions", p);
2195 err = true;
2196 }
2197 }
2198 }
2199
2200 // Do not allow types that need destructors or copy constructors.
2201 if (arg.type.needsDestruction())
2202 {
2203 arg.error("cannot pass types that need destruction as variadic arguments");
2204 err = true;
2205 }
2206 if (arg.type.needsCopyOrPostblit())
2207 {
2208 arg.error("cannot pass types with postblits or copy constructors as variadic arguments");
2209 err = true;
2210 }
2211
2212 // Convert static arrays to dynamic arrays
2213 // BUG: I don't think this is right for D2
2214 Type tb = arg.type.toBasetype();
Iain Buclaw6384eff2022-02-20 20:02:23 +01002215 if (auto ts = tb.isTypeSArray())
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02002216 {
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02002217 Type ta = ts.next.arrayOf();
2218 if (ts.size(arg.loc) == 0)
2219 arg = new NullExp(arg.loc, ta);
2220 else
2221 arg = arg.castTo(sc, ta);
2222 }
2223 if (tb.ty == Tstruct)
2224 {
2225 //arg = callCpCtor(sc, arg);
2226 }
2227 // Give error for overloaded function addresses
Iain Buclaw6384eff2022-02-20 20:02:23 +01002228 if (auto se = arg.isSymOffExp())
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02002229 {
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02002230 if (se.hasOverloads && !se.var.isFuncDeclaration().isUnique())
2231 {
2232 arg.error("function `%s` is overloaded", arg.toChars());
2233 err = true;
2234 }
2235 }
2236 err |= arg.checkValue();
2237 err |= arg.checkSharedAccess(sc);
2238 arg = arg.optimize(WANTvalue);
2239 }
2240 (*arguments)[i] = arg;
2241 }
2242
2243 /* If calling C scanf(), printf(), or any variants, check the format string against the arguments
2244 */
2245 const isVa_list = tf.parameterList.varargs == VarArg.none;
Iain Buclaw7e7ebe32022-10-29 09:05:54 +02002246 if (fd && fd.printf)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02002247 {
2248 if (auto se = (*arguments)[nparams - 1 - isVa_list].isStringExp())
2249 {
2250 checkPrintfFormat(se.loc, se.peekString(), (*arguments)[nparams .. nargs], isVa_list);
2251 }
2252 }
Iain Buclaw7e7ebe32022-10-29 09:05:54 +02002253 else if (fd && fd.scanf)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02002254 {
2255 if (auto se = (*arguments)[nparams - 1 - isVa_list].isStringExp())
2256 {
2257 checkScanfFormat(se.loc, se.peekString(), (*arguments)[nparams .. nargs], isVa_list);
2258 }
2259 }
2260 else
2261 {
2262 // TODO: not checking the "v" functions yet (for those, check format string only, not args)
2263 }
2264
2265 /* Remaining problems:
2266 * 1. order of evaluation - some function push L-to-R, others R-to-L. Until we resolve what array assignment does (which is
2267 * implemented by calling a function) we'll defer this for now.
2268 * 2. value structs (or static arrays of them) that need to be copy constructed
2269 * 3. value structs (or static arrays of them) that have destructors, and subsequent arguments that may throw before the
2270 * function gets called.
2271 * 4. value structs need to be destructed after the function call for platforms where the caller destroys the arguments.
2272 * 2, 3 and 4 are handled by doing the argument construction in 'eprefix' so that if a later argument throws, they are cleaned
2273 * up properly. Pushing arguments on the stack then cannot fail.
2274 */
2275 {
2276 /* TODO: tackle problem 1)
2277 */
2278 const bool leftToRight = true; // TODO: Any cases that need rightToLeft?
2279 if (!leftToRight)
2280 assert(nargs == nparams); // no variadics for RTL order, as they would probably be evaluated LTR and so add complexity
2281
2282 /* Does Problem (4) apply?
2283 */
2284 const bool callerDestroysArgs = !target.isCalleeDestroyingArgs(tf);
2285
2286 const ptrdiff_t start = (leftToRight ? 0 : cast(ptrdiff_t)nargs - 1);
2287 const ptrdiff_t end = (leftToRight ? cast(ptrdiff_t)nargs : -1);
2288 const ptrdiff_t step = (leftToRight ? 1 : -1);
2289
2290 /* Compute indices of last throwing argument and first arg needing destruction.
2291 * Used to not set up destructors unless an arg needs destruction on a throw
2292 * in a later argument.
2293 */
2294 ptrdiff_t lastthrow = -1; // last argument that may throw
2295 ptrdiff_t firstdtor = -1; // first argument that needs destruction
2296 ptrdiff_t lastdtor = -1; // last argument that needs destruction
2297 for (ptrdiff_t i = start; i != end; i += step)
2298 {
2299 Expression arg = (*arguments)[i];
2300 if (canThrow(arg, sc.func, false))
2301 lastthrow = i;
2302 if (arg.type.needsDestruction())
2303 {
2304 Parameter p = (i >= nparams ? null : tf.parameterList[i]);
Iain Buclawec486b72022-06-13 10:41:57 +02002305 if (!(p && (p.isLazy() || p.isReference())))
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02002306 {
2307 if (firstdtor == -1)
2308 firstdtor = i;
2309 lastdtor = i;
2310 }
2311 }
2312 }
2313
2314 /* Do we need 'eprefix' for problems 3 or 4?
2315 */
2316 const bool needsPrefix = callerDestroysArgs
2317 ? firstdtor >= 0 // true if any argument needs destruction
2318 : firstdtor >= 0 && lastthrow >= 0 &&
2319 (lastthrow - firstdtor) * step > 0; // last throw after first destruction
2320 const ptrdiff_t lastPrefix = callerDestroysArgs
2321 ? lastdtor // up to last argument requiring destruction
2322 : lastthrow; // up to last potentially throwing argument
2323
2324 /* Problem 3: initialize 'eprefix' by declaring the gate
2325 */
2326 VarDeclaration gate;
2327 if (needsPrefix && !callerDestroysArgs)
2328 {
2329 // eprefix => bool __gate [= false]
2330 Identifier idtmp = Identifier.generateId("__gate");
2331 gate = new VarDeclaration(loc, Type.tbool, idtmp, null);
2332 gate.storage_class |= STC.temp | STC.ctfe | STC.volatile_;
2333 gate.dsymbolSemantic(sc);
2334
2335 auto ae = new DeclarationExp(loc, gate);
2336 eprefix = ae.expressionSemantic(sc);
2337 }
2338
2339 for (ptrdiff_t i = start; i != end; i += step)
2340 {
2341 Expression arg = (*arguments)[i];
2342 //printf("arg[%d]: %s\n", cast(int)i, arg.toChars());
2343
2344 Parameter parameter = (i >= nparams ? null : tf.parameterList[i]);
2345 const bool isRef = parameter && parameter.isReference();
Iain Buclawec486b72022-06-13 10:41:57 +02002346 const bool isLazy = parameter && parameter.isLazy();
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02002347
2348 /* Skip lazy parameters
2349 */
2350 if (isLazy)
2351 continue;
2352
2353 /* Do we have 'eprefix' and aren't past 'lastPrefix' yet?
2354 * Then declare a temporary variable for this arg and append that declaration
2355 * to 'eprefix', which will implicitly take care of potential problem 2) for
2356 * this arg.
2357 * 'eprefix' will therefore finally contain all args up to and including 'lastPrefix',
2358 * excluding all lazy parameters.
2359 */
2360 if (needsPrefix && (lastPrefix - i) * step >= 0)
2361 {
2362 const bool needsDtor = !isRef && arg.type.needsDestruction() &&
2363 // Problem 3: last throwing arg doesn't require dtor patching
2364 (callerDestroysArgs || i != lastPrefix);
2365
2366 /* Declare temporary 'auto __pfx = arg' (needsDtor) or 'auto __pfy = arg' (!needsDtor)
2367 */
2368 auto tmp = copyToTemp(
2369 (parameter ? parameter.storageClass : tf.parameterList.stc) & (STC.scope_),
2370 needsDtor ? "__pfx" : "__pfy",
2371 !isRef ? arg : arg.addressOf());
2372 tmp.dsymbolSemantic(sc);
2373
2374 if (callerDestroysArgs)
2375 {
2376 /* Problem 4: Normal temporary, destructed after the call
2377 */
2378 if (needsDtor)
2379 tmp.isArgDtorVar = true; // mark it so that the backend passes it by ref to the function being called
2380 }
2381 else
2382 {
2383 /* Problem 3: Modify the destructor so it only runs if gate==false,
2384 * i.e., only if there was a throw while constructing the args
2385 */
2386 if (!needsDtor)
2387 {
2388 if (tmp.edtor)
2389 {
2390 assert(i == lastPrefix);
2391 tmp.edtor = null;
2392 }
2393 }
2394 else
2395 {
2396 // edtor => (__gate || edtor)
2397 assert(tmp.edtor);
2398 Expression e = tmp.edtor;
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01002399 e = new LogicalExp(e.loc, EXP.orOr, new VarExp(e.loc, gate), e);
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02002400 tmp.edtor = e.expressionSemantic(sc);
2401 //printf("edtor: %s\n", tmp.edtor.toChars());
2402 }
2403 }
2404
2405 // eprefix => (eprefix, auto __pfx/y = arg)
2406 auto ae = new DeclarationExp(loc, tmp);
2407 eprefix = Expression.combine(eprefix, ae.expressionSemantic(sc));
2408
2409 // arg => __pfx/y
2410 arg = new VarExp(loc, tmp);
2411 arg = arg.expressionSemantic(sc);
2412 if (isRef)
2413 {
2414 arg = new PtrExp(loc, arg);
2415 arg = arg.expressionSemantic(sc);
2416 }
2417
2418 /* Problem 3: Last throwing arg?
2419 * Then finalize eprefix => (eprefix, gate = true), i.e., disable the
2420 * dtors right after constructing the last throwing arg.
2421 * From now on, the callee will take care of destructing the args because
2422 * the args are implicitly moved into function parameters.
2423 */
2424 if (!callerDestroysArgs && i == lastPrefix)
2425 {
2426 auto e = new AssignExp(gate.loc, new VarExp(gate.loc, gate), IntegerExp.createBool(true));
2427 eprefix = Expression.combine(eprefix, e.expressionSemantic(sc));
2428 }
2429 }
2430 else // not part of 'eprefix'
2431 {
2432 /* Handle problem 2) by calling the copy constructor for value structs
2433 * (or static arrays of them) if appropriate.
2434 */
2435 Type tv = arg.type.baseElemOf();
2436 if (!isRef && tv.ty == Tstruct)
2437 arg = doCopyOrMove(sc, arg, parameter ? parameter.type : null);
2438 }
2439
2440 (*arguments)[i] = arg;
2441 }
2442 }
2443 //if (eprefix) printf("eprefix: %s\n", eprefix.toChars());
2444
2445 /* Test compliance with DIP1021
2446 */
2447 if (global.params.useDIP1021 &&
2448 tf.trust != TRUST.system && tf.trust != TRUST.trusted)
2449 err |= checkMutableArguments(sc, fd, tf, ethis, arguments, false);
2450
2451 // If D linkage and variadic, add _arguments[] as first argument
2452 if (tf.isDstyleVariadic())
2453 {
2454 assert(arguments.dim >= nparams);
2455
2456 auto args = new Parameters(arguments.dim - nparams);
2457 for (size_t i = 0; i < arguments.dim - nparams; i++)
2458 {
2459 auto arg = new Parameter(STC.in_, (*arguments)[nparams + i].type, null, null, null);
2460 (*args)[i] = arg;
2461 }
2462 auto tup = new TypeTuple(args);
2463 Expression e = (new TypeidExp(loc, tup)).expressionSemantic(sc);
2464 arguments.insert(0, e);
2465 }
2466
2467 /* Determine function return type: tret
2468 */
2469 Type tret = tf.next;
2470 if (isCtorCall)
2471 {
2472 //printf("[%s] fd = %s %s, %d %d %d\n", loc.toChars(), fd.toChars(), fd.type.toChars(),
2473 // wildmatch, tf.isWild(), fd.isReturnIsolated());
2474 if (!tthis)
2475 {
2476 assert(sc.intypeof || global.errors);
2477 tthis = fd.isThis().type.addMod(fd.type.mod);
2478 }
2479 if (tf.isWild() && !fd.isReturnIsolated())
2480 {
2481 if (wildmatch)
2482 tret = tret.substWildTo(wildmatch);
2483 int offset;
2484 if (!tret.implicitConvTo(tthis) && !(MODimplicitConv(tret.mod, tthis.mod) && tret.isBaseOf(tthis, &offset) && offset == 0))
2485 {
2486 const(char)* s1 = tret.isNaked() ? " mutable" : tret.modToChars();
2487 const(char)* s2 = tthis.isNaked() ? " mutable" : tthis.modToChars();
2488 .error(loc, "`inout` constructor `%s` creates%s object, not%s", fd.toPrettyChars(), s1, s2);
2489 err = true;
2490 }
2491 }
2492 tret = tthis;
2493 }
2494 else if (wildmatch && tret)
2495 {
2496 /* Adjust function return type based on wildmatch
2497 */
2498 //printf("wildmatch = x%x, tret = %s\n", wildmatch, tret.toChars());
2499 tret = tret.substWildTo(wildmatch);
2500 }
2501
2502 *prettype = tret;
2503 *peprefix = eprefix;
2504 return (err || olderrors != global.errors);
2505}
2506
2507/**
2508 * Determines whether a symbol represents a module or package
2509 * (Used as a helper for is(type == module) and is(type == package))
2510 *
2511 * Params:
2512 * sym = the symbol to be checked
2513 *
2514 * Returns:
2515 * the symbol which `sym` represents (or `null` if it doesn't represent a `Package`)
2516 */
2517Package resolveIsPackage(Dsymbol sym)
2518{
2519 Package pkg;
2520 if (Import imp = sym.isImport())
2521 {
2522 if (imp.pkg is null)
2523 {
Iain Buclaw5eb99272022-05-16 18:30:46 +02002524 .error(sym.loc, "internal compiler error: unable to process forward-referenced import `%s`",
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02002525 imp.toChars());
2526 assert(0);
2527 }
2528 pkg = imp.pkg;
2529 }
2530 else if (auto mod = sym.isModule())
2531 pkg = mod.isPackageFile ? mod.pkg : sym.isPackage();
2532 else
2533 pkg = sym.isPackage();
2534 if (pkg)
2535 pkg.resolvePKGunknown();
2536 return pkg;
2537}
2538
2539private Module loadStdMath()
2540{
2541 __gshared Import impStdMath = null;
2542 __gshared Identifier[1] stdID;
2543 if (!impStdMath)
2544 {
2545 stdID[0] = Id.std;
2546 auto s = new Import(Loc.initial, stdID[], Id.math, null, false);
2547 // Module.load will call fatal() if there's no std.math available.
2548 // Gag the error here, pushing the error handling to the caller.
2549 uint errors = global.startGagging();
2550 s.load(null);
2551 if (s.mod)
2552 {
2553 s.mod.importAll(null);
2554 s.mod.dsymbolSemantic(null);
2555 }
2556 global.endGagging(errors);
2557 impStdMath = s;
2558 }
2559 return impStdMath.mod;
2560}
2561
2562private extern (C++) final class ExpressionSemanticVisitor : Visitor
2563{
2564 alias visit = Visitor.visit;
2565
2566 Scope* sc;
2567 Expression result;
2568
2569 this(Scope* sc)
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)
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01002808 else if (ss.withstate.exp && ss.withstate.exp.op == EXP.type)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02002809 {
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);
Iain Buclawfd435682021-12-15 19:47:02 +01002834 else if (exp.ident == Id.dollar)
2835 exp.error("undefined identifier `$`");
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02002836 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)
Iain Buclaw5eb99272022-05-16 18:30:46 +02003046 e.type = Type.tuns32.sarrayOf(e.len + 1);
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02003047 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)
Iain Buclaw5eb99272022-05-16 18:30:46 +02003071 e.type = Type.tuns16.sarrayOf(e.len + 1);
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02003072 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)
Iain Buclaw5eb99272022-05-16 18:30:46 +02003083 e.type = Type.tchar.sarrayOf(e.len + 1);
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02003084 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;
3112 for (size_t i = 0; i < exp.exps.dim; i++)
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 }
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01003121 else if (e.op == EXP.error)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02003122 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);
Iain Buclawc8dfa792022-09-27 10:43:32 +02003154 if (arrayExpressionSemantic(e.elements.peekSlice(), sc) || (e.basis && e.basis.op == EXP.error))
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02003155 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 */
3172 if (e.elements.dim > 0 && t0.ty == Tvoid)
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
Iain Buclawc8dfa792022-09-27 10:43:32 +02003197 bool err_keys = arrayExpressionSemantic(e.keys.peekSlice(), sc);
3198 bool err_vals = arrayExpressionSemantic(e.values.peekSlice(), sc);
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02003199 if (err_keys || err_vals)
3200 return setError();
3201
3202 expandTuples(e.keys);
3203 expandTuples(e.values);
3204 if (e.keys.dim != e.values.dim)
3205 {
3206 e.error("number of keys is %llu, must match number of values %llu",
3207 cast(ulong) e.keys.dim, cast(ulong) e.values.dim);
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
Iain Buclaw5eb99272022-05-16 18:30:46 +02003221 if (checkAssocArrayLiteralEscape(sc, e, false))
3222 return setError();
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02003223
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
Iain Buclawc8dfa792022-09-27 10:43:32 +02003244 if (arrayExpressionSemantic(e.elements.peekSlice(), sc))
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02003245 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 */
Iain Buclawc8dfa792022-09-27 10:43:32 +02003256 if (!e.sd.fill(e.loc, *e.elements, false))
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02003257 {
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
3266 if (checkFrameAccess(e.loc, sc, e.sd, e.elements.dim))
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);
Iain Buclawae56e2d2022-04-21 14:25:26 +01003281 auto e = initializerToExpression(init, t, (sc.flags & SCOPE.Cfile) != 0);
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02003282 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_) &&
Iain Buclaw5eb99272022-05-16 18:30:46 +02003309 sc.func && sc.func.needThis && ve.var.isMember2())
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02003310 {
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 }
Iain Buclaw31350632022-04-13 13:34:49 +01003314 //printf("e = %s %s\n", Token.toChars(e.op), e.toChars());
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02003315 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
Iain Buclaw1027dc42022-02-28 15:47:52 +01003331 exp.type.checkComplexTransition(exp.loc, sc);
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02003332
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;
Iain Buclaw6384eff2022-02-20 20:02:23 +01003504 if (!exp.arguments && exp.newtype.isTypeSArray())
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02003505 {
Iain Buclaw6384eff2022-02-20 20:02:23 +01003506 auto ts = exp.newtype.isTypeSArray();
Iain Buclawb6df1132022-07-26 17:42:23 +02003507 // 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 }
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02003518 }
3519
3520 ClassDeclaration cdthis = null;
3521 if (exp.thisexp)
3522 {
3523 exp.thisexp = exp.thisexp.expressionSemantic(sc);
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01003524 if (exp.thisexp.op == EXP.error)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02003525 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);
Iain Buclawc8dfa792022-09-27 10:43:32 +02003567 if (arrayExpressionSemantic(exp.arguments.peekSlice(), sc))
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02003568 {
3569 return setError();
3570 }
Iain Buclawb6df1132022-07-26 17:42:23 +02003571 if (preFunctionParameters(sc, exp.arguments))
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02003572 {
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
3582 const size_t nargs = exp.arguments ? exp.arguments.dim : 0;
3583 Expression newprefix = null;
3584
Iain Buclaw6384eff2022-02-20 20:02:23 +01003585 if (auto tc = tb.isTypeClass())
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02003586 {
Iain Buclaw6384eff2022-02-20 20:02:23 +01003587 auto cd = tc.sym;
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02003588 cd.size(exp.loc);
3589 if (cd.sizeok != Sizeok.done)
3590 return setError();
3591 if (!cd.ctor)
3592 cd.ctor = cd.searchCtor();
3593 if (cd.noDefaultCtor && !nargs && !cd.defaultCtor)
3594 {
3595 exp.error("default construction is disabled for type `%s`", cd.type.toChars());
3596 return setError();
3597 }
3598
3599 if (cd.isInterfaceDeclaration())
3600 {
3601 exp.error("cannot create instance of interface `%s`", cd.toChars());
3602 return setError();
3603 }
3604
3605 if (cd.isAbstract())
3606 {
3607 exp.error("cannot create instance of abstract class `%s`", cd.toChars());
3608 for (size_t i = 0; i < cd.vtbl.dim; i++)
3609 {
3610 FuncDeclaration fd = cd.vtbl[i].isFuncDeclaration();
3611 if (fd && fd.isAbstract())
3612 {
3613 errorSupplemental(exp.loc, "function `%s` is not implemented",
3614 fd.toFullSignature());
3615 }
3616 }
3617 return setError();
3618 }
3619 // checkDeprecated() is already done in newtype.typeSemantic().
3620
3621 if (cd.isNested())
3622 {
3623 /* We need a 'this' pointer for the nested class.
3624 * Ensure we have the right one.
3625 */
3626 Dsymbol s = cd.toParentLocal();
3627
3628 //printf("cd isNested, parent = %s '%s'\n", s.kind(), s.toPrettyChars());
3629 if (auto cdn = s.isClassDeclaration())
3630 {
3631 if (!cdthis)
3632 {
Iain Buclawd7569182022-02-13 20:17:53 +01003633 if (!sc.hasThis)
3634 {
3635 string msg = "cannot construct " ~
3636 (cd.isAnonymous ? "anonymous nested class" : "nested class `%s`") ~
3637 " because no implicit `this` reference to outer class" ~
3638 (cdn.isAnonymous ? "" : " `%s`") ~ " is available\0";
3639
3640 exp.error(msg.ptr, cd.toChars, cdn.toChars);
3641 return setError();
3642 }
3643
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02003644 // Supply an implicit 'this' and try again
3645 exp.thisexp = new ThisExp(exp.loc);
3646 for (Dsymbol sp = sc.parent; 1; sp = sp.toParentLocal())
3647 {
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02003648 ClassDeclaration cdp = sp.isClassDeclaration();
3649 if (!cdp)
3650 continue;
3651 if (cdp == cdn || cdn.isBaseOf(cdp, null))
3652 break;
3653 // Add a '.outer' and try again
3654 exp.thisexp = new DotIdExp(exp.loc, exp.thisexp, Id.outer);
3655 }
3656
3657 exp.thisexp = exp.thisexp.expressionSemantic(sc);
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01003658 if (exp.thisexp.op == EXP.error)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02003659 return setError();
3660 cdthis = exp.thisexp.type.isClassHandle();
3661 }
3662 if (cdthis != cdn && !cdn.isBaseOf(cdthis, null))
3663 {
3664 //printf("cdthis = %s\n", cdthis.toChars());
3665 exp.error("`this` for nested class must be of type `%s`, not `%s`",
3666 cdn.toChars(), exp.thisexp.type.toChars());
3667 return setError();
3668 }
3669 if (!MODimplicitConv(exp.thisexp.type.mod, exp.newtype.mod))
3670 {
3671 exp.error("nested type `%s` should have the same or weaker constancy as enclosing type `%s`",
3672 exp.newtype.toChars(), exp.thisexp.type.toChars());
3673 return setError();
3674 }
3675 }
3676 else if (exp.thisexp)
3677 {
3678 exp.error("`.new` is only for allocating nested classes");
3679 return setError();
3680 }
3681 else if (auto fdn = s.isFuncDeclaration())
3682 {
3683 // make sure the parent context fdn of cd is reachable from sc
3684 if (!ensureStaticLinkTo(sc.parent, fdn))
3685 {
3686 exp.error("outer function context of `%s` is needed to `new` nested class `%s`",
3687 fdn.toPrettyChars(), cd.toPrettyChars());
3688 return setError();
3689 }
3690 }
3691 else
3692 assert(0);
3693 }
3694 else if (exp.thisexp)
3695 {
3696 exp.error("`.new` is only for allocating nested classes");
3697 return setError();
3698 }
3699
3700 if (cd.vthis2)
3701 {
3702 if (AggregateDeclaration ad2 = cd.isMember2())
3703 {
3704 Expression te = new ThisExp(exp.loc).expressionSemantic(sc);
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01003705 if (te.op != EXP.error)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02003706 te = getRightThis(exp.loc, sc, ad2, te, cd);
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01003707 if (te.op == EXP.error)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02003708 {
3709 exp.error("need `this` of type `%s` needed to `new` nested class `%s`", ad2.toChars(), cd.toChars());
3710 return setError();
3711 }
3712 }
3713 }
3714
Iain Buclawc8dfa792022-09-27 10:43:32 +02003715 if (cd.disableNew && !exp.onstack)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02003716 {
3717 exp.error("cannot allocate `class %s` with `new` because it is annotated with `@disable new()`",
3718 originalNewtype.toChars());
3719 return setError();
3720 }
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02003721
3722 if (cd.ctor)
3723 {
3724 FuncDeclaration f = resolveFuncCall(exp.loc, sc, cd.ctor, null, tb, exp.arguments, FuncResolveFlag.standard);
3725 if (!f || f.errors)
3726 return setError();
3727
3728 checkFunctionAttributes(exp, sc, f);
3729 checkAccess(cd, exp.loc, sc, f);
3730
Iain Buclaw6384eff2022-02-20 20:02:23 +01003731 TypeFunction tf = f.type.isTypeFunction();
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02003732 if (!exp.arguments)
3733 exp.arguments = new Expressions();
3734 if (functionParameters(exp.loc, sc, tf, null, exp.type, exp.arguments, f, &exp.type, &exp.argprefix))
3735 return setError();
3736
3737 exp.member = f.isCtorDeclaration();
3738 assert(exp.member);
3739 }
3740 else
3741 {
3742 if (nargs)
3743 {
3744 exp.error("no constructor for `%s`", cd.toChars());
3745 return setError();
3746 }
3747
3748 // https://issues.dlang.org/show_bug.cgi?id=19941
3749 // Run semantic on all field initializers to resolve any forward
3750 // references. This is the same as done for structs in sd.fill().
3751 for (ClassDeclaration c = cd; c; c = c.baseClass)
3752 {
3753 foreach (v; c.fields)
3754 {
3755 if (v.inuse || v._scope is null || v._init is null ||
3756 v._init.isVoidInitializer())
3757 continue;
3758 v.inuse++;
3759 v._init = v._init.initializerSemantic(v._scope, v.type, INITinterpret);
3760 v.inuse--;
3761 }
3762 }
3763 }
Iain Buclawec486b72022-06-13 10:41:57 +02003764
3765 // When using `@nogc` exception handling, lower `throw new E(args)` to
3766 // `throw (__tmp = _d_newThrowable!E(), __tmp.__ctor(args), __tmp)`.
3767 if (global.params.ehnogc && exp.thrownew &&
3768 !cd.isCOMclass() && !cd.isCPPclass())
3769 {
3770 assert(cd.ctor);
3771
3772 Expression id = new IdentifierExp(exp.loc, Id.empty);
3773 id = new DotIdExp(exp.loc, id, Id.object);
3774
3775 auto tiargs = new Objects();
3776 tiargs.push(exp.newtype);
3777 id = new DotTemplateInstanceExp(exp.loc, id, Id._d_newThrowable, tiargs);
3778 id = new CallExp(exp.loc, id).expressionSemantic(sc);
3779
3780 Expression idVal;
3781 Expression tmp = extractSideEffect(sc, "__tmpThrowable", idVal, id, true);
3782 // auto castTmp = new CastExp(exp.loc, tmp, exp.type);
3783
3784 auto ctor = new DotIdExp(exp.loc, tmp, Id.ctor).expressionSemantic(sc);
3785 auto ctorCall = new CallExp(exp.loc, ctor, exp.arguments);
3786
3787 id = Expression.combine(idVal, exp.argprefix).expressionSemantic(sc);
3788 id = Expression.combine(id, ctorCall).expressionSemantic(sc);
3789 // id = Expression.combine(id, castTmp).expressionSemantic(sc);
3790
3791 result = id.expressionSemantic(sc);
3792 return;
3793 }
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02003794 }
Iain Buclaw6384eff2022-02-20 20:02:23 +01003795 else if (auto ts = tb.isTypeStruct())
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02003796 {
Iain Buclaw6384eff2022-02-20 20:02:23 +01003797 auto sd = ts.sym;
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02003798 sd.size(exp.loc);
3799 if (sd.sizeok != Sizeok.done)
3800 return setError();
3801 if (!sd.ctor)
3802 sd.ctor = sd.searchCtor();
3803 if (sd.noDefaultCtor && !nargs)
3804 {
3805 exp.error("default construction is disabled for type `%s`", sd.type.toChars());
3806 return setError();
3807 }
3808 // checkDeprecated() is already done in newtype.typeSemantic().
3809
3810 if (sd.disableNew)
3811 {
3812 exp.error("cannot allocate `struct %s` with `new` because it is annotated with `@disable new()`",
3813 originalNewtype.toChars());
3814 return setError();
3815 }
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02003816
Iain Buclaw235d5a92022-03-29 16:57:10 +02003817 // https://issues.dlang.org/show_bug.cgi?id=22639
3818 // If the new expression has arguments, we either should call a
3819 // regular constructor of a copy constructor if the first argument
3820 // is the same type as the struct
3821 if (nargs && (sd.hasRegularCtor() || (sd.ctor && (*exp.arguments)[0].type.mutableOf() == sd.type.mutableOf())))
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02003822 {
3823 FuncDeclaration f = resolveFuncCall(exp.loc, sc, sd.ctor, null, tb, exp.arguments, FuncResolveFlag.standard);
3824 if (!f || f.errors)
3825 return setError();
3826
3827 checkFunctionAttributes(exp, sc, f);
3828 checkAccess(sd, exp.loc, sc, f);
3829
Iain Buclaw6384eff2022-02-20 20:02:23 +01003830 TypeFunction tf = f.type.isTypeFunction();
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02003831 if (!exp.arguments)
3832 exp.arguments = new Expressions();
3833 if (functionParameters(exp.loc, sc, tf, null, exp.type, exp.arguments, f, &exp.type, &exp.argprefix))
3834 return setError();
3835
3836 exp.member = f.isCtorDeclaration();
3837 assert(exp.member);
3838
3839 if (checkFrameAccess(exp.loc, sc, sd, sd.fields.dim))
3840 return setError();
3841 }
3842 else
3843 {
3844 if (!exp.arguments)
3845 exp.arguments = new Expressions();
3846
3847 if (!sd.fit(exp.loc, sc, exp.arguments, tb))
3848 return setError();
3849
Iain Buclawc8dfa792022-09-27 10:43:32 +02003850 if (!sd.fill(exp.loc, *exp.arguments, false))
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02003851 return setError();
3852
3853 if (checkFrameAccess(exp.loc, sc, sd, exp.arguments ? exp.arguments.dim : 0))
3854 return setError();
3855
3856 /* Since a `new` allocation may escape, check each of the arguments for escaping
3857 */
Iain Buclaw5eb99272022-05-16 18:30:46 +02003858 foreach (arg; *exp.arguments)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02003859 {
Iain Buclaw5eb99272022-05-16 18:30:46 +02003860 if (arg && checkNewEscape(sc, arg, false))
3861 return setError();
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02003862 }
3863 }
3864
3865 exp.type = exp.type.pointerTo();
3866 }
3867 else if (tb.ty == Tarray)
3868 {
3869 if (!nargs)
3870 {
3871 // https://issues.dlang.org/show_bug.cgi?id=20422
3872 // Without this check the compiler would give a misleading error
3873 exp.error("missing length argument for array");
3874 return setError();
3875 }
3876
3877 Type tn = tb.nextOf().baseElemOf();
3878 Dsymbol s = tn.toDsymbol(sc);
3879 AggregateDeclaration ad = s ? s.isAggregateDeclaration() : null;
3880 if (ad && ad.noDefaultCtor)
3881 {
3882 exp.error("default construction is disabled for type `%s`", tb.nextOf().toChars());
3883 return setError();
3884 }
3885 for (size_t i = 0; i < nargs; i++)
3886 {
3887 if (tb.ty != Tarray)
3888 {
3889 exp.error("too many arguments for array");
3890 return setError();
3891 }
3892
3893 Expression arg = (*exp.arguments)[i];
3894 arg = resolveProperties(sc, arg);
3895 arg = arg.implicitCastTo(sc, Type.tsize_t);
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01003896 if (arg.op == EXP.error)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02003897 return setError();
3898 arg = arg.optimize(WANTvalue);
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01003899 if (arg.op == EXP.int64 && cast(sinteger_t)arg.toInteger() < 0)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02003900 {
3901 exp.error("negative array index `%s`", arg.toChars());
3902 return setError();
3903 }
3904 (*exp.arguments)[i] = arg;
Iain Buclaw6384eff2022-02-20 20:02:23 +01003905 tb = tb.isTypeDArray().next.toBasetype();
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02003906 }
3907 }
3908 else if (tb.isscalar())
3909 {
3910 if (!nargs)
3911 {
3912 }
3913 else if (nargs == 1)
3914 {
3915 Expression e = (*exp.arguments)[0];
3916 e = e.implicitCastTo(sc, tb);
3917 (*exp.arguments)[0] = e;
3918 }
3919 else
3920 {
3921 exp.error("more than one argument for construction of `%s`", exp.type.toChars());
3922 return setError();
3923 }
3924
3925 exp.type = exp.type.pointerTo();
3926 }
Iain Buclawb6df1132022-07-26 17:42:23 +02003927 else if (tb.ty == Taarray)
3928 {
3929 // e.g. `new Alias(args)`
3930 if (nargs)
3931 {
3932 exp.error("`new` cannot take arguments for an associative array");
3933 return setError();
3934 }
3935 }
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02003936 else
3937 {
3938 exp.error("cannot create a `%s` with `new`", exp.type.toChars());
3939 return setError();
3940 }
3941
3942 //printf("NewExp: '%s'\n", toChars());
3943 //printf("NewExp:type '%s'\n", type.toChars());
3944 semanticTypeInfo(sc, exp.type);
3945
3946 if (newprefix)
3947 {
3948 result = Expression.combine(newprefix, exp);
3949 return;
3950 }
3951 result = exp;
3952 }
3953
3954 override void visit(NewAnonClassExp e)
3955 {
3956 static if (LOGSEMANTIC)
3957 {
3958 printf("NewAnonClassExp::semantic() %s\n", e.toChars());
3959 //printf("thisexp = %p\n", thisexp);
3960 //printf("type: %s\n", type.toChars());
3961 }
3962
3963 Expression d = new DeclarationExp(e.loc, e.cd);
3964 sc = sc.push(); // just create new scope
3965 sc.flags &= ~SCOPE.ctfe; // temporary stop CTFE
3966 d = d.expressionSemantic(sc);
3967 sc = sc.pop();
3968
3969 if (!e.cd.errors && sc.intypeof && !sc.parent.inNonRoot())
3970 {
3971 ScopeDsymbol sds = sc.tinst ? cast(ScopeDsymbol)sc.tinst : sc._module;
3972 if (!sds.members)
3973 sds.members = new Dsymbols();
3974 sds.members.push(e.cd);
3975 }
3976
Iain Buclaw6384eff2022-02-20 20:02:23 +01003977 Expression n = new NewExp(e.loc, e.thisexp, e.cd.type, e.arguments);
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02003978
3979 Expression c = new CommaExp(e.loc, d, n);
3980 result = c.expressionSemantic(sc);
3981 }
3982
3983 override void visit(SymOffExp e)
3984 {
3985 static if (LOGSEMANTIC)
3986 {
3987 printf("SymOffExp::semantic('%s')\n", e.toChars());
3988 }
3989 //var.dsymbolSemantic(sc);
3990 if (!e.type)
3991 e.type = e.var.type.pointerTo();
3992
3993 if (auto v = e.var.isVarDeclaration())
3994 {
3995 if (v.checkNestedReference(sc, e.loc))
3996 return setError();
3997 }
3998 else if (auto f = e.var.isFuncDeclaration())
3999 {
4000 if (f.checkNestedReference(sc, e.loc))
4001 return setError();
4002 }
4003
4004 result = e;
4005 }
4006
4007 override void visit(VarExp e)
4008 {
4009 static if (LOGSEMANTIC)
4010 {
4011 printf("VarExp::semantic(%s)\n", e.toChars());
4012 }
4013
4014 auto vd = e.var.isVarDeclaration();
4015 auto fd = e.var.isFuncDeclaration();
4016
4017 if (fd)
4018 {
4019 //printf("L%d fd = %s\n", __LINE__, f.toChars());
4020 if (!fd.functionSemantic())
4021 return setError();
4022 }
4023
4024 if (!e.type)
4025 e.type = e.var.type;
4026 if (e.type && !e.type.deco)
4027 {
4028 auto decl = e.var.isDeclaration();
4029 if (decl)
4030 decl.inuse++;
4031 e.type = e.type.typeSemantic(e.loc, sc);
4032 if (decl)
4033 decl.inuse--;
4034 }
4035
4036 /* Fix for 1161 doesn't work because it causes visibility
4037 * problems when instantiating imported templates passing private
4038 * variables as alias template parameters.
4039 */
4040 //checkAccess(loc, sc, NULL, var);
4041
4042 if (vd)
4043 {
4044 if (vd.checkNestedReference(sc, e.loc))
4045 return setError();
4046
4047 // https://issues.dlang.org/show_bug.cgi?id=12025
4048 // If the variable is not actually used in runtime code,
4049 // the purity violation error is redundant.
4050 //checkPurity(sc, vd);
4051 }
4052 else if (fd)
4053 {
4054 // TODO: If fd isn't yet resolved its overload, the checkNestedReference
4055 // call would cause incorrect validation.
4056 // Maybe here should be moved in CallExp, or AddrExp for functions.
4057 if (fd.checkNestedReference(sc, e.loc))
4058 return setError();
4059 }
4060 else if (auto od = e.var.isOverDeclaration())
4061 {
4062 e.type = Type.tvoid; // ambiguous type?
4063 }
4064
4065 result = e;
4066 }
4067
4068 override void visit(FuncExp exp)
4069 {
4070 static if (LOGSEMANTIC)
4071 {
4072 printf("FuncExp::semantic(%s)\n", exp.toChars());
4073 if (exp.fd.treq)
4074 printf(" treq = %s\n", exp.fd.treq.toChars());
4075 }
4076
4077 if (exp.type)
4078 {
4079 result = exp;
4080 return;
4081 }
4082
4083 Expression e = exp;
4084 uint olderrors;
4085
4086 sc = sc.push(); // just create new scope
4087 sc.flags &= ~SCOPE.ctfe; // temporary stop CTFE
4088 sc.visibility = Visibility(Visibility.Kind.public_); // https://issues.dlang.org/show_bug.cgi?id=12506
4089
4090 /* fd.treq might be incomplete type,
4091 * so should not semantic it.
4092 * void foo(T)(T delegate(int) dg){}
4093 * foo(a=>a); // in IFTI, treq == T delegate(int)
4094 */
4095 //if (fd.treq)
4096 // fd.treq = fd.treq.dsymbolSemantic(loc, sc);
4097
4098 exp.genIdent(sc);
4099
4100 // Set target of return type inference
4101 if (exp.fd.treq && !exp.fd.type.nextOf())
4102 {
4103 TypeFunction tfv = null;
4104 if (exp.fd.treq.ty == Tdelegate || exp.fd.treq.isPtrToFunction())
4105 tfv = cast(TypeFunction)exp.fd.treq.nextOf();
4106 if (tfv)
4107 {
4108 TypeFunction tfl = cast(TypeFunction)exp.fd.type;
4109 tfl.next = tfv.nextOf();
4110 }
4111 }
4112
4113 //printf("td = %p, treq = %p\n", td, fd.treq);
4114 if (exp.td)
4115 {
4116 assert(exp.td.parameters && exp.td.parameters.dim);
4117 exp.td.dsymbolSemantic(sc);
4118 exp.type = Type.tvoid; // temporary type
4119
4120 if (exp.fd.treq) // defer type determination
4121 {
4122 FuncExp fe;
4123 if (exp.matchType(exp.fd.treq, sc, &fe) > MATCH.nomatch)
4124 e = fe;
4125 else
4126 e = ErrorExp.get();
4127 }
4128 goto Ldone;
4129 }
4130
4131 olderrors = global.errors;
4132 exp.fd.dsymbolSemantic(sc);
4133 if (olderrors == global.errors)
4134 {
4135 exp.fd.semantic2(sc);
4136 if (olderrors == global.errors)
4137 exp.fd.semantic3(sc);
4138 }
4139 if (olderrors != global.errors)
4140 {
4141 if (exp.fd.type && exp.fd.type.ty == Tfunction && !exp.fd.type.nextOf())
4142 (cast(TypeFunction)exp.fd.type).next = Type.terror;
4143 e = ErrorExp.get();
4144 goto Ldone;
4145 }
4146
4147 // Type is a "delegate to" or "pointer to" the function literal
4148 if ((exp.fd.isNested() && exp.fd.tok == TOK.delegate_) || (exp.tok == TOK.reserved && exp.fd.treq && exp.fd.treq.ty == Tdelegate))
4149 {
Iain Buclaw6384eff2022-02-20 20:02:23 +01004150 // https://issues.dlang.org/show_bug.cgi?id=22686
4151 // if the delegate return type is an error
4152 // abort semantic of the FuncExp and propagate
4153 // the error
4154 if (exp.fd.type.isTypeError())
4155 {
4156 e = ErrorExp.get();
4157 goto Ldone;
4158 }
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02004159 exp.type = new TypeDelegate(exp.fd.type.isTypeFunction());
4160 exp.type = exp.type.typeSemantic(exp.loc, sc);
4161
4162 exp.fd.tok = TOK.delegate_;
4163 }
4164 else
4165 {
4166 exp.type = new TypePointer(exp.fd.type);
4167 exp.type = exp.type.typeSemantic(exp.loc, sc);
4168 //type = fd.type.pointerTo();
4169
4170 /* A lambda expression deduced to function pointer might become
4171 * to a delegate literal implicitly.
4172 *
4173 * auto foo(void function() fp) { return 1; }
4174 * assert(foo({}) == 1);
4175 *
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01004176 * So, should keep fd.tok == TOK.reserve if fd.treq == NULL.
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02004177 */
4178 if (exp.fd.treq && exp.fd.treq.ty == Tpointer)
4179 {
4180 // change to non-nested
4181 exp.fd.tok = TOK.function_;
4182 exp.fd.vthis = null;
4183 }
4184 }
4185 exp.fd.tookAddressOf++;
4186
4187 Ldone:
4188 sc = sc.pop();
4189 result = e;
4190 }
4191
4192 /**
4193 * Perform semantic analysis on function literals
4194 *
4195 * Test the following construct:
4196 * ---
4197 * (x, y, z) { return x + y + z; }(42, 84, 1992);
4198 * ---
4199 */
4200 Expression callExpSemantic(FuncExp exp, Scope* sc, Expressions* arguments)
4201 {
4202 if ((!exp.type || exp.type == Type.tvoid) && exp.td && arguments && arguments.dim)
4203 {
4204 for (size_t k = 0; k < arguments.dim; k++)
4205 {
4206 Expression checkarg = (*arguments)[k];
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01004207 if (checkarg.op == EXP.error)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02004208 return checkarg;
4209 }
4210
4211 exp.genIdent(sc);
4212
4213 assert(exp.td.parameters && exp.td.parameters.dim);
4214 exp.td.dsymbolSemantic(sc);
4215
4216 TypeFunction tfl = cast(TypeFunction)exp.fd.type;
4217 size_t dim = tfl.parameterList.length;
4218 if (arguments.dim < dim)
4219 {
4220 // Default arguments are always typed, so they don't need inference.
4221 Parameter p = tfl.parameterList[arguments.dim];
4222 if (p.defaultArg)
4223 dim = arguments.dim;
4224 }
4225
4226 if ((tfl.parameterList.varargs == VarArg.none && arguments.dim > dim) ||
4227 arguments.dim < dim)
4228 {
4229 OutBuffer buf;
4230 foreach (idx, ref arg; *arguments)
4231 buf.printf("%s%s", (idx ? ", ".ptr : "".ptr), arg.type.toChars());
4232 exp.error("function literal `%s%s` is not callable using argument types `(%s)`",
4233 exp.fd.toChars(), parametersTypeToChars(tfl.parameterList),
4234 buf.peekChars());
4235 exp.errorSupplemental("too %s arguments, expected `%d`, got `%d`",
4236 arguments.dim < dim ? "few".ptr : "many".ptr,
4237 cast(int)dim, cast(int)arguments.dim);
4238 return ErrorExp.get();
4239 }
4240
4241 auto tiargs = new Objects();
4242 tiargs.reserve(exp.td.parameters.dim);
4243
4244 for (size_t i = 0; i < exp.td.parameters.dim; i++)
4245 {
4246 TemplateParameter tp = (*exp.td.parameters)[i];
4247 assert(dim <= tfl.parameterList.length);
4248 foreach (u, p; tfl.parameterList)
4249 {
4250 if (u == dim)
4251 break;
4252
4253 if (p.type.ty == Tident && (cast(TypeIdentifier)p.type).ident == tp.ident)
4254 {
4255 Expression e = (*arguments)[u];
4256 tiargs.push(e.type);
4257 break;
4258 }
4259 }
4260 }
4261
4262 auto ti = new TemplateInstance(exp.loc, exp.td, tiargs);
4263 return (new ScopeExp(exp.loc, ti)).expressionSemantic(sc);
4264 }
4265 return exp.expressionSemantic(sc);
4266 }
4267
4268 override void visit(CallExp exp)
4269 {
4270 static if (LOGSEMANTIC)
4271 {
4272 printf("CallExp::semantic() %s\n", exp.toChars());
4273 }
4274 if (exp.type)
4275 {
4276 result = exp;
4277 return; // semantic() already run
4278 }
4279
4280 Objects* tiargs = null; // initial list of template arguments
4281 Expression ethis = null;
4282 Type tthis = null;
4283 Expression e1org = exp.e1;
4284
Iain Buclaw235d5a92022-03-29 16:57:10 +02004285 if (auto ce = exp.e1.isCommaExp())
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02004286 {
4287 /* Rewrite (a,b)(args) as (a,(b(args)))
4288 */
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02004289 exp.e1 = ce.e2;
4290 ce.e2 = exp;
4291 result = ce.expressionSemantic(sc);
4292 return;
4293 }
Iain Buclaw235d5a92022-03-29 16:57:10 +02004294 if (DelegateExp de = exp.e1.isDelegateExp())
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02004295 {
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02004296 exp.e1 = new DotVarExp(de.loc, de.e1, de.func, de.hasOverloads);
4297 visit(exp);
4298 return;
4299 }
Iain Buclaw235d5a92022-03-29 16:57:10 +02004300 if (FuncExp fe = exp.e1.isFuncExp())
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02004301 {
Iain Buclawc8dfa792022-09-27 10:43:32 +02004302 if (arrayExpressionSemantic(exp.arguments.peekSlice(), sc) ||
4303 preFunctionParameters(sc, exp.arguments))
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02004304 return setError();
4305
4306 // Run e1 semantic even if arguments have any errors
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02004307 exp.e1 = callExpSemantic(fe, sc, exp.arguments);
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01004308 if (exp.e1.op == EXP.error)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02004309 {
4310 result = exp.e1;
4311 return;
4312 }
4313 }
Iain Buclawfd435682021-12-15 19:47:02 +01004314 if (sc.flags & SCOPE.Cfile)
4315 {
4316 /* See if need to rewrite the AST because of cast/call ambiguity
4317 */
4318 if (auto e = castCallAmbiguity(exp, sc))
4319 {
4320 result = expressionSemantic(e, sc);
4321 return;
4322 }
4323 }
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02004324
4325 if (Expression ex = resolveUFCS(sc, exp))
4326 {
4327 result = ex;
4328 return;
4329 }
4330
4331 /* This recognizes:
4332 * foo!(tiargs)(funcargs)
4333 */
Iain Buclaw235d5a92022-03-29 16:57:10 +02004334 if (ScopeExp se = exp.e1.isScopeExp())
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02004335 {
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02004336 TemplateInstance ti = se.sds.isTemplateInstance();
4337 if (ti)
4338 {
4339 /* Attempt to instantiate ti. If that works, go with it.
4340 * If not, go with partial explicit specialization.
4341 */
4342 WithScopeSymbol withsym;
4343 if (!ti.findTempDecl(sc, &withsym) || !ti.semanticTiargs(sc))
4344 return setError();
4345 if (withsym && withsym.withstate.wthis)
4346 {
4347 exp.e1 = new VarExp(exp.e1.loc, withsym.withstate.wthis);
4348 exp.e1 = new DotTemplateInstanceExp(exp.e1.loc, exp.e1, ti);
4349 goto Ldotti;
4350 }
4351 if (ti.needsTypeInference(sc, 1))
4352 {
4353 /* Go with partial explicit specialization
4354 */
4355 tiargs = ti.tiargs;
4356 assert(ti.tempdecl);
4357 if (TemplateDeclaration td = ti.tempdecl.isTemplateDeclaration())
4358 exp.e1 = new TemplateExp(exp.loc, td);
4359 else if (OverDeclaration od = ti.tempdecl.isOverDeclaration())
4360 exp.e1 = new VarExp(exp.loc, od);
4361 else
4362 exp.e1 = new OverExp(exp.loc, ti.tempdecl.isOverloadSet());
4363 }
4364 else
4365 {
4366 Expression e1x = exp.e1.expressionSemantic(sc);
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01004367 if (e1x.op == EXP.error)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02004368 {
4369 result = e1x;
4370 return;
4371 }
4372 exp.e1 = e1x;
4373 }
4374 }
4375 }
4376
4377 /* This recognizes:
4378 * expr.foo!(tiargs)(funcargs)
4379 */
4380 Ldotti:
Iain Buclaw235d5a92022-03-29 16:57:10 +02004381 if (DotTemplateInstanceExp se = exp.e1.isDotTemplateInstanceExp())
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02004382 {
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02004383 TemplateInstance ti = se.ti;
4384 {
4385 /* Attempt to instantiate ti. If that works, go with it.
4386 * If not, go with partial explicit specialization.
4387 */
4388 if (!se.findTempDecl(sc) || !ti.semanticTiargs(sc))
4389 return setError();
4390 if (ti.needsTypeInference(sc, 1))
4391 {
4392 /* Go with partial explicit specialization
4393 */
4394 tiargs = ti.tiargs;
4395 assert(ti.tempdecl);
4396 if (TemplateDeclaration td = ti.tempdecl.isTemplateDeclaration())
4397 exp.e1 = new DotTemplateExp(exp.loc, se.e1, td);
4398 else if (OverDeclaration od = ti.tempdecl.isOverDeclaration())
4399 {
4400 exp.e1 = new DotVarExp(exp.loc, se.e1, od, true);
4401 }
4402 else
4403 exp.e1 = new DotExp(exp.loc, se.e1, new OverExp(exp.loc, ti.tempdecl.isOverloadSet()));
4404 }
4405 else
4406 {
4407 Expression e1x = exp.e1.expressionSemantic(sc);
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01004408 if (e1x.op == EXP.error)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02004409 {
4410 result = e1x;
4411 return;
4412 }
4413 exp.e1 = e1x;
4414 }
4415 }
4416 }
4417
4418 Lagain:
4419 //printf("Lagain: %s\n", toChars());
4420 exp.f = null;
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01004421 if (exp.e1.op == EXP.this_ || exp.e1.op == EXP.super_)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02004422 {
4423 // semantic() run later for these
4424 }
4425 else
4426 {
Iain Buclaw235d5a92022-03-29 16:57:10 +02004427 if (DotIdExp die = exp.e1.isDotIdExp())
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02004428 {
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02004429 exp.e1 = die.expressionSemantic(sc);
4430 /* Look for e1 having been rewritten to expr.opDispatch!(string)
4431 * We handle such earlier, so go back.
4432 * Note that in the rewrite, we carefully did not run semantic() on e1
4433 */
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01004434 if (exp.e1.op == EXP.dotTemplateInstance)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02004435 {
4436 goto Ldotti;
4437 }
4438 }
4439 else
4440 {
4441 __gshared int nest;
4442 if (++nest > global.recursionLimit)
4443 {
4444 exp.error("recursive evaluation of `%s`", exp.toChars());
4445 --nest;
4446 return setError();
4447 }
4448 Expression ex = unaSemantic(exp, sc);
4449 --nest;
4450 if (ex)
4451 {
4452 result = ex;
4453 return;
4454 }
4455 }
4456
4457 /* Look for e1 being a lazy parameter
4458 */
Iain Buclaw235d5a92022-03-29 16:57:10 +02004459 if (VarExp ve = exp.e1.isVarExp())
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02004460 {
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02004461 if (ve.var.storage_class & STC.lazy_)
4462 {
4463 // lazy parameters can be called without violating purity and safety
4464 Type tw = ve.var.type;
4465 Type tc = ve.var.type.substWildTo(MODFlags.const_);
4466 auto tf = new TypeFunction(ParameterList(), tc, LINK.d, STC.safe | STC.pure_);
4467 (tf = cast(TypeFunction)tf.typeSemantic(exp.loc, sc)).next = tw; // hack for bug7757
4468 auto t = new TypeDelegate(tf);
4469 ve.type = t.typeSemantic(exp.loc, sc);
4470 }
4471 VarDeclaration v = ve.var.isVarDeclaration();
4472 if (v && ve.checkPurity(sc, v))
4473 return setError();
4474 }
4475
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01004476 if (exp.e1.op == EXP.symbolOffset && (cast(SymOffExp)exp.e1).hasOverloads)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02004477 {
4478 SymOffExp se = cast(SymOffExp)exp.e1;
4479 exp.e1 = new VarExp(se.loc, se.var, true);
4480 exp.e1 = exp.e1.expressionSemantic(sc);
4481 }
Iain Buclaw235d5a92022-03-29 16:57:10 +02004482 else if (DotExp de = exp.e1.isDotExp())
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02004483 {
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01004484 if (de.e2.op == EXP.overloadSet)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02004485 {
4486 ethis = de.e1;
4487 tthis = de.e1.type;
4488 exp.e1 = de.e2;
4489 }
4490 }
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01004491 else if (exp.e1.op == EXP.star && exp.e1.type.ty == Tfunction)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02004492 {
4493 // Rewrite (*fp)(arguments) to fp(arguments)
4494 exp.e1 = (cast(PtrExp)exp.e1).e1;
4495 }
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01004496 else if (exp.e1.op == EXP.type && (sc && sc.flags & SCOPE.Cfile))
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02004497 {
Iain Buclaw0fb57032021-12-05 17:11:12 +01004498 const numArgs = exp.arguments ? exp.arguments.length : 0;
Iain Buclaw0fb57032021-12-05 17:11:12 +01004499
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02004500 /* Ambiguous cases arise from CParser where there is not enough
4501 * information to determine if we have a function call or declaration.
4502 * type-name ( identifier ) ;
4503 * identifier ( identifier ) ;
4504 * If exp.e1 is a type-name, then this is a declaration. C11 does not
4505 * have type construction syntax, so don't convert this to a cast().
4506 */
Iain Buclaw0fb57032021-12-05 17:11:12 +01004507 if (numArgs == 1)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02004508 {
4509 Expression arg = (*exp.arguments)[0];
4510 if (auto ie = (*exp.arguments)[0].isIdentifierExp())
4511 {
4512 TypeExp te = cast(TypeExp)exp.e1;
4513 auto initializer = new VoidInitializer(ie.loc);
4514 Dsymbol s = new VarDeclaration(ie.loc, te.type, ie.ident, initializer);
4515 auto decls = new Dsymbols(1);
4516 (*decls)[0] = s;
4517 s = new LinkDeclaration(s.loc, LINK.c, decls);
4518 result = new DeclarationExp(exp.loc, s);
4519 result = result.expressionSemantic(sc);
4520 }
4521 else
4522 {
4523 arg.error("identifier or `(` expected");
4524 result = ErrorExp.get();
4525 }
4526 return;
4527 }
4528 exp.error("identifier or `(` expected before `)`");
4529 result = ErrorExp.get();
4530 return;
4531 }
4532 }
4533
4534 Type t1 = exp.e1.type ? exp.e1.type.toBasetype() : null;
4535
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01004536 if (exp.e1.op == EXP.error)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02004537 {
4538 result = exp.e1;
4539 return;
4540 }
Iain Buclawc8dfa792022-09-27 10:43:32 +02004541 if (arrayExpressionSemantic(exp.arguments.peekSlice(), sc) ||
4542 preFunctionParameters(sc, exp.arguments))
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02004543 return setError();
4544
4545 // Check for call operator overload
4546 if (t1)
4547 {
4548 if (t1.ty == Tstruct)
4549 {
4550 auto sd = (cast(TypeStruct)t1).sym;
4551 sd.size(exp.loc); // Resolve forward references to construct object
4552 if (sd.sizeok != Sizeok.done)
4553 return setError();
4554 if (!sd.ctor)
4555 sd.ctor = sd.searchCtor();
4556 /* If `sd.ctor` is a generated copy constructor, this means that it
4557 is the single constructor that this struct has. In order to not
4558 disable default construction, the ctor is nullified. The side effect
4559 of this is that the generated copy constructor cannot be called
4560 explicitly, but that is ok, because when calling a constructor the
4561 default constructor should have priority over the generated copy
4562 constructor.
4563 */
4564 if (sd.ctor)
4565 {
4566 auto ctor = sd.ctor.isCtorDeclaration();
Iain Buclaw235d5a92022-03-29 16:57:10 +02004567 if (ctor && ctor.isCpCtor && ctor.isGenerated())
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02004568 sd.ctor = null;
4569 }
4570
4571 // First look for constructor
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01004572 if (exp.e1.op == EXP.type && sd.ctor)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02004573 {
4574 if (!sd.noDefaultCtor && !(exp.arguments && exp.arguments.dim))
4575 goto Lx;
4576
4577 /* https://issues.dlang.org/show_bug.cgi?id=20695
4578 If all constructors are copy constructors, then
4579 try default construction.
4580 */
Iain Buclaw235d5a92022-03-29 16:57:10 +02004581 if (!sd.hasRegularCtor &&
4582 // https://issues.dlang.org/show_bug.cgi?id=22639
4583 // we might still have a copy constructor that could be called
4584 (*exp.arguments)[0].type.mutableOf != sd.type.mutableOf())
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02004585 goto Lx;
4586
4587 auto sle = new StructLiteralExp(exp.loc, sd, null, exp.e1.type);
Iain Buclawc8dfa792022-09-27 10:43:32 +02004588 if (!sd.fill(exp.loc, *sle.elements, true))
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02004589 return setError();
4590 if (checkFrameAccess(exp.loc, sc, sd, sle.elements.dim))
4591 return setError();
4592
4593 // https://issues.dlang.org/show_bug.cgi?id=14556
4594 // Set concrete type to avoid further redundant semantic().
4595 sle.type = exp.e1.type;
4596
4597 /* Constructor takes a mutable object, so don't use
4598 * the immutable initializer symbol.
4599 */
4600 sle.useStaticInit = false;
4601
4602 Expression e = sle;
4603 if (auto cf = sd.ctor.isCtorDeclaration())
4604 {
4605 e = new DotVarExp(exp.loc, e, cf, true);
4606 }
4607 else if (auto td = sd.ctor.isTemplateDeclaration())
4608 {
4609 e = new DotIdExp(exp.loc, e, td.ident);
4610 }
4611 else if (auto os = sd.ctor.isOverloadSet())
4612 {
4613 e = new DotExp(exp.loc, e, new OverExp(exp.loc, os));
4614 }
4615 else
4616 assert(0);
4617 e = new CallExp(exp.loc, e, exp.arguments);
4618 e = e.expressionSemantic(sc);
4619 result = e;
4620 return;
4621 }
4622 // No constructor, look for overload of opCall
4623 if (search_function(sd, Id.call))
4624 goto L1;
4625 // overload of opCall, therefore it's a call
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01004626 if (exp.e1.op != EXP.type)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02004627 {
4628 if (sd.aliasthis && !isRecursiveAliasThis(exp.att1, exp.e1.type))
4629 {
4630 exp.e1 = resolveAliasThis(sc, exp.e1);
4631 goto Lagain;
4632 }
4633 exp.error("%s `%s` does not overload ()", sd.kind(), sd.toChars());
4634 return setError();
4635 }
4636
4637 /* It's a struct literal
4638 */
4639 Lx:
4640 Expression e = new StructLiteralExp(exp.loc, sd, exp.arguments, exp.e1.type);
4641 e = e.expressionSemantic(sc);
4642 result = e;
4643 return;
4644 }
4645 else if (t1.ty == Tclass)
4646 {
4647 L1:
4648 // Rewrite as e1.call(arguments)
4649 Expression e = new DotIdExp(exp.loc, exp.e1, Id.call);
4650 e = new CallExp(exp.loc, e, exp.arguments);
4651 e = e.expressionSemantic(sc);
4652 result = e;
4653 return;
4654 }
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01004655 else if (exp.e1.op == EXP.type && t1.isscalar())
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02004656 {
4657 Expression e;
4658
Iain Buclawc8dfa792022-09-27 10:43:32 +02004659 // Make sure to use the enum type itself rather than its
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02004660 // base type
4661 // https://issues.dlang.org/show_bug.cgi?id=16346
4662 if (exp.e1.type.ty == Tenum)
4663 {
4664 t1 = exp.e1.type;
4665 }
4666
4667 if (!exp.arguments || exp.arguments.dim == 0)
4668 {
4669 e = t1.defaultInitLiteral(exp.loc);
4670 }
4671 else if (exp.arguments.dim == 1)
4672 {
4673 e = (*exp.arguments)[0];
Iain Buclaw7e7ebe32022-10-29 09:05:54 +02004674 if (!e.type.isTypeNoreturn())
4675 e = e.implicitCastTo(sc, t1);
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02004676 }
4677 else
4678 {
4679 exp.error("more than one argument for construction of `%s`", t1.toChars());
4680 return setError();
4681 }
4682 e = e.expressionSemantic(sc);
4683 result = e;
4684 return;
4685 }
4686 }
4687
4688 static FuncDeclaration resolveOverloadSet(Loc loc, Scope* sc,
4689 OverloadSet os, Objects* tiargs, Type tthis, Expressions* arguments)
4690 {
4691 FuncDeclaration f = null;
4692 foreach (s; os.a)
4693 {
4694 if (tiargs && s.isFuncDeclaration())
4695 continue;
4696 if (auto f2 = resolveFuncCall(loc, sc, s, tiargs, tthis, arguments, FuncResolveFlag.quiet))
4697 {
4698 if (f2.errors)
4699 return null;
4700 if (f)
4701 {
4702 /* Error if match in more than one overload set,
4703 * even if one is a 'better' match than the other.
4704 */
4705 ScopeDsymbol.multiplyDefined(loc, f, f2);
4706 }
4707 else
4708 f = f2;
4709 }
4710 }
4711 if (!f)
4712 .error(loc, "no overload matches for `%s`", os.toChars());
4713 else if (f.errors)
4714 f = null;
4715 return f;
4716 }
4717
4718 bool isSuper = false;
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01004719 if (exp.e1.op == EXP.dotVariable && t1.ty == Tfunction || exp.e1.op == EXP.dotTemplateDeclaration)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02004720 {
4721 UnaExp ue = cast(UnaExp)exp.e1;
4722
Iain Buclaw0fb57032021-12-05 17:11:12 +01004723 Expression ue1old = ue.e1; // need for 'right this' check
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02004724 DotVarExp dve;
4725 DotTemplateExp dte;
4726 Dsymbol s;
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01004727 if (exp.e1.op == EXP.dotVariable)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02004728 {
4729 dve = cast(DotVarExp)exp.e1;
4730 dte = null;
4731 s = dve.var;
4732 tiargs = null;
4733 }
4734 else
4735 {
4736 dve = null;
4737 dte = cast(DotTemplateExp)exp.e1;
4738 s = dte.td;
4739 }
4740
4741 // Do overload resolution
Iain Buclaw0fb57032021-12-05 17:11:12 +01004742 exp.f = resolveFuncCall(exp.loc, sc, s, tiargs, ue.e1.type, exp.arguments, FuncResolveFlag.standard);
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02004743 if (!exp.f || exp.f.errors || exp.f.type.ty == Terror)
4744 return setError();
4745
4746 if (exp.f.interfaceVirtual)
4747 {
4748 /* Cast 'this' to the type of the interface, and replace f with the interface's equivalent
4749 */
4750 auto b = exp.f.interfaceVirtual;
4751 auto ad2 = b.sym;
4752 ue.e1 = ue.e1.castTo(sc, ad2.type.addMod(ue.e1.type.mod));
4753 ue.e1 = ue.e1.expressionSemantic(sc);
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02004754 auto vi = exp.f.findVtblIndex(&ad2.vtbl, cast(int)ad2.vtbl.dim);
4755 assert(vi >= 0);
4756 exp.f = ad2.vtbl[vi].isFuncDeclaration();
4757 assert(exp.f);
4758 }
4759 if (exp.f.needThis())
4760 {
Iain Buclaw5eb99272022-05-16 18:30:46 +02004761 AggregateDeclaration ad = exp.f.isMemberLocal();
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02004762 ue.e1 = getRightThis(exp.loc, sc, ad, ue.e1, exp.f);
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01004763 if (ue.e1.op == EXP.error)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02004764 {
4765 result = ue.e1;
4766 return;
4767 }
4768 ethis = ue.e1;
4769 tthis = ue.e1.type;
4770 if (!(exp.f.type.ty == Tfunction && (cast(TypeFunction)exp.f.type).isScopeQual))
4771 {
Iain Buclawb7a586b2022-08-25 19:04:50 +02004772 if (checkParamArgumentEscape(sc, exp.f, null, null, STC.undefined_, ethis, false, false))
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02004773 return setError();
4774 }
4775 }
4776
4777 /* Cannot call public functions from inside invariant
4778 * (because then the invariant would have infinite recursion)
4779 */
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01004780 if (sc.func && sc.func.isInvariantDeclaration() && ue.e1.op == EXP.this_ && exp.f.addPostInvariant())
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02004781 {
4782 exp.error("cannot call `public`/`export` function `%s` from invariant", exp.f.toChars());
4783 return setError();
4784 }
4785
4786 if (!exp.ignoreAttributes)
4787 checkFunctionAttributes(exp, sc, exp.f);
4788 checkAccess(exp.loc, sc, ue.e1, exp.f);
4789 if (!exp.f.needThis())
4790 {
4791 exp.e1 = Expression.combine(ue.e1, new VarExp(exp.loc, exp.f, false));
4792 }
4793 else
4794 {
4795 if (ue1old.checkRightThis(sc))
4796 return setError();
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01004797 if (exp.e1.op == EXP.dotVariable)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02004798 {
4799 dve.var = exp.f;
4800 exp.e1.type = exp.f.type;
4801 }
4802 else
4803 {
4804 exp.e1 = new DotVarExp(exp.loc, dte.e1, exp.f, false);
4805 exp.e1 = exp.e1.expressionSemantic(sc);
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01004806 if (exp.e1.op == EXP.error)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02004807 return setError();
4808 ue = cast(UnaExp)exp.e1;
4809 }
4810 version (none)
4811 {
4812 printf("ue.e1 = %s\n", ue.e1.toChars());
4813 printf("f = %s\n", exp.f.toChars());
4814 printf("t1 = %s\n", t1.toChars());
4815 printf("e1 = %s\n", exp.e1.toChars());
4816 printf("e1.type = %s\n", exp.e1.type.toChars());
4817 }
4818
4819 // See if we need to adjust the 'this' pointer
4820 AggregateDeclaration ad = exp.f.isThis();
4821 ClassDeclaration cd = ue.e1.type.isClassHandle();
4822 if (ad && cd && ad.isClassDeclaration())
4823 {
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01004824 if (ue.e1.op == EXP.dotType)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02004825 {
4826 ue.e1 = (cast(DotTypeExp)ue.e1).e1;
4827 exp.directcall = true;
4828 }
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01004829 else if (ue.e1.op == EXP.super_)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02004830 exp.directcall = true;
4831 else if ((cd.storage_class & STC.final_) != 0) // https://issues.dlang.org/show_bug.cgi?id=14211
4832 exp.directcall = true;
4833
4834 if (ad != cd)
4835 {
4836 ue.e1 = ue.e1.castTo(sc, ad.type.addMod(ue.e1.type.mod));
4837 ue.e1 = ue.e1.expressionSemantic(sc);
4838 }
4839 }
4840 }
4841 // If we've got a pointer to a function then deference it
4842 // https://issues.dlang.org/show_bug.cgi?id=16483
4843 if (exp.e1.type.isPtrToFunction())
4844 {
4845 Expression e = new PtrExp(exp.loc, exp.e1);
4846 e.type = exp.e1.type.nextOf();
4847 exp.e1 = e;
4848 }
4849 t1 = exp.e1.type;
4850 }
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01004851 else if (exp.e1.op == EXP.super_ || exp.e1.op == EXP.this_)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02004852 {
4853 auto ad = sc.func ? sc.func.isThis() : null;
4854 auto cd = ad ? ad.isClassDeclaration() : null;
4855
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01004856 isSuper = exp.e1.op == EXP.super_;
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02004857 if (isSuper)
4858 {
4859 // Base class constructor call
4860 if (!cd || !cd.baseClass || !sc.func.isCtorDeclaration())
4861 {
4862 exp.error("super class constructor call must be in a constructor");
4863 return setError();
4864 }
4865 if (!cd.baseClass.ctor)
4866 {
4867 exp.error("no super class constructor for `%s`", cd.baseClass.toChars());
4868 return setError();
4869 }
4870 }
4871 else
4872 {
4873 // `this` call expression must be inside a
4874 // constructor
4875 if (!ad || !sc.func.isCtorDeclaration())
4876 {
4877 exp.error("constructor call must be in a constructor");
4878 return setError();
4879 }
4880
4881 // https://issues.dlang.org/show_bug.cgi?id=18719
4882 // If `exp` is a call expression to another constructor
4883 // then it means that all struct/class fields will be
4884 // initialized after this call.
4885 foreach (ref field; sc.ctorflow.fieldinit)
4886 {
4887 field.csx |= CSX.this_ctor;
4888 }
4889 }
4890
4891 if (!sc.intypeof && !(sc.ctorflow.callSuper & CSX.halt))
4892 {
4893 if (sc.inLoop || sc.ctorflow.callSuper & CSX.label)
4894 exp.error("constructor calls not allowed in loops or after labels");
4895 if (sc.ctorflow.callSuper & (CSX.super_ctor | CSX.this_ctor))
4896 exp.error("multiple constructor calls");
4897 if ((sc.ctorflow.callSuper & CSX.return_) && !(sc.ctorflow.callSuper & CSX.any_ctor))
4898 exp.error("an earlier `return` statement skips constructor");
4899 sc.ctorflow.callSuper |= CSX.any_ctor | (isSuper ? CSX.super_ctor : CSX.this_ctor);
4900 }
4901
4902 tthis = ad.type.addMod(sc.func.type.mod);
4903 auto ctor = isSuper ? cd.baseClass.ctor : ad.ctor;
4904 if (auto os = ctor.isOverloadSet())
4905 exp.f = resolveOverloadSet(exp.loc, sc, os, null, tthis, exp.arguments);
4906 else
4907 exp.f = resolveFuncCall(exp.loc, sc, ctor, null, tthis, exp.arguments, FuncResolveFlag.standard);
4908
4909 if (!exp.f || exp.f.errors)
4910 return setError();
4911
4912 checkFunctionAttributes(exp, sc, exp.f);
4913 checkAccess(exp.loc, sc, null, exp.f);
4914
4915 exp.e1 = new DotVarExp(exp.e1.loc, exp.e1, exp.f, false);
4916 exp.e1 = exp.e1.expressionSemantic(sc);
4917 // https://issues.dlang.org/show_bug.cgi?id=21095
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01004918 if (exp.e1.op == EXP.error)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02004919 return setError();
4920 t1 = exp.e1.type;
4921
4922 // BUG: this should really be done by checking the static
4923 // call graph
4924 if (exp.f == sc.func)
4925 {
4926 exp.error("cyclic constructor call");
4927 return setError();
4928 }
4929 }
Iain Buclaw235d5a92022-03-29 16:57:10 +02004930 else if (auto oe = exp.e1.isOverExp())
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02004931 {
Iain Buclaw235d5a92022-03-29 16:57:10 +02004932 exp.f = resolveOverloadSet(exp.loc, sc, oe.vars, tiargs, tthis, exp.arguments);
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02004933 if (!exp.f)
4934 return setError();
4935 if (ethis)
4936 exp.e1 = new DotVarExp(exp.loc, ethis, exp.f, false);
4937 else
4938 exp.e1 = new VarExp(exp.loc, exp.f, false);
4939 goto Lagain;
4940 }
4941 else if (!t1)
4942 {
4943 exp.error("function expected before `()`, not `%s`", exp.e1.toChars());
4944 return setError();
4945 }
4946 else if (t1.ty == Terror)
4947 {
4948 return setError();
4949 }
4950 else if (t1.ty != Tfunction)
4951 {
4952 TypeFunction tf;
4953 const(char)* p;
4954 Dsymbol s;
4955 exp.f = null;
Iain Buclaw235d5a92022-03-29 16:57:10 +02004956 if (auto fe = exp.e1.isFuncExp())
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02004957 {
4958 // function literal that direct called is always inferred.
Iain Buclaw235d5a92022-03-29 16:57:10 +02004959 assert(fe.fd);
4960 exp.f = fe.fd;
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02004961 tf = cast(TypeFunction)exp.f.type;
4962 p = "function literal";
4963 }
4964 else if (t1.ty == Tdelegate)
4965 {
4966 TypeDelegate td = cast(TypeDelegate)t1;
4967 assert(td.next.ty == Tfunction);
4968 tf = cast(TypeFunction)td.next;
4969 p = "delegate";
4970 }
4971 else if (auto tfx = t1.isPtrToFunction())
4972 {
4973 tf = tfx;
4974 p = "function pointer";
4975 }
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01004976 else if (exp.e1.op == EXP.dotVariable && (cast(DotVarExp)exp.e1).var.isOverDeclaration())
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02004977 {
4978 DotVarExp dve = cast(DotVarExp)exp.e1;
4979 exp.f = resolveFuncCall(exp.loc, sc, dve.var, tiargs, dve.e1.type, exp.arguments, FuncResolveFlag.overloadOnly);
4980 if (!exp.f)
4981 return setError();
4982 if (exp.f.needThis())
4983 {
4984 dve.var = exp.f;
4985 dve.type = exp.f.type;
4986 dve.hasOverloads = false;
4987 goto Lagain;
4988 }
4989 exp.e1 = new VarExp(dve.loc, exp.f, false);
4990 Expression e = new CommaExp(exp.loc, dve.e1, exp);
4991 result = e.expressionSemantic(sc);
4992 return;
4993 }
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01004994 else if (exp.e1.op == EXP.variable && (cast(VarExp)exp.e1).var.isOverDeclaration())
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02004995 {
4996 s = (cast(VarExp)exp.e1).var;
4997 goto L2;
4998 }
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01004999 else if (exp.e1.op == EXP.template_)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02005000 {
5001 s = (cast(TemplateExp)exp.e1).td;
5002 L2:
5003 exp.f = resolveFuncCall(exp.loc, sc, s, tiargs, null, exp.arguments, FuncResolveFlag.standard);
5004 if (!exp.f || exp.f.errors)
5005 return setError();
5006 if (exp.f.needThis())
5007 {
5008 if (hasThis(sc))
5009 {
5010 // Supply an implicit 'this', as in
5011 // this.ident
5012 exp.e1 = new DotVarExp(exp.loc, (new ThisExp(exp.loc)).expressionSemantic(sc), exp.f, false);
5013 goto Lagain;
5014 }
5015 else if (isNeedThisScope(sc, exp.f))
5016 {
5017 exp.error("need `this` for `%s` of type `%s`", exp.f.toChars(), exp.f.type.toChars());
5018 return setError();
5019 }
5020 }
5021 exp.e1 = new VarExp(exp.e1.loc, exp.f, false);
5022 goto Lagain;
5023 }
5024 else
5025 {
5026 exp.error("function expected before `()`, not `%s` of type `%s`", exp.e1.toChars(), exp.e1.type.toChars());
5027 return setError();
5028 }
5029
5030 const(char)* failMessage;
5031 Expression[] fargs = exp.arguments ? (*exp.arguments)[] : null;
5032 if (!tf.callMatch(null, fargs, 0, &failMessage, sc))
5033 {
5034 OutBuffer buf;
5035 buf.writeByte('(');
5036 argExpTypesToCBuffer(&buf, exp.arguments);
5037 buf.writeByte(')');
5038 if (tthis)
5039 tthis.modToBuffer(&buf);
5040
5041 //printf("tf = %s, args = %s\n", tf.deco, (*arguments)[0].type.deco);
5042 .error(exp.loc, "%s `%s%s` is not callable using argument types `%s`",
5043 p, exp.e1.toChars(), parametersTypeToChars(tf.parameterList), buf.peekChars());
5044 if (failMessage)
5045 errorSupplemental(exp.loc, "%s", failMessage);
5046 return setError();
5047 }
5048 // Purity and safety check should run after testing arguments matching
5049 if (exp.f)
5050 {
5051 exp.checkPurity(sc, exp.f);
5052 exp.checkSafety(sc, exp.f);
5053 exp.checkNogc(sc, exp.f);
5054 if (exp.f.checkNestedReference(sc, exp.loc))
5055 return setError();
5056 }
5057 else if (sc.func && sc.intypeof != 1 && !(sc.flags & (SCOPE.ctfe | SCOPE.debug_)))
5058 {
5059 bool err = false;
5060 if (!tf.purity && sc.func.setImpure())
5061 {
5062 exp.error("`pure` %s `%s` cannot call impure %s `%s`",
5063 sc.func.kind(), sc.func.toPrettyChars(), p, exp.e1.toChars());
5064 err = true;
5065 }
5066 if (!tf.isnogc && sc.func.setGC())
5067 {
5068 exp.error("`@nogc` %s `%s` cannot call non-@nogc %s `%s`",
5069 sc.func.kind(), sc.func.toPrettyChars(), p, exp.e1.toChars());
5070 err = true;
5071 }
Iain Buclawb6df1132022-07-26 17:42:23 +02005072 if (tf.trust <= TRUST.system && sc.setUnsafe(true, exp.loc,
5073 "`@safe` function `%s` cannot call `@system` `%s`", sc.func, exp.e1))
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02005074 {
5075 exp.error("`@safe` %s `%s` cannot call `@system` %s `%s`",
5076 sc.func.kind(), sc.func.toPrettyChars(), p, exp.e1.toChars());
5077 err = true;
5078 }
5079 if (err)
5080 return setError();
5081 }
5082
5083 if (t1.ty == Tpointer)
5084 {
5085 Expression e = new PtrExp(exp.loc, exp.e1);
5086 e.type = tf;
5087 exp.e1 = e;
5088 }
5089 t1 = tf;
5090 }
Iain Buclaw235d5a92022-03-29 16:57:10 +02005091 else if (VarExp ve = exp.e1.isVarExp())
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02005092 {
5093 // Do overload resolution
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02005094 exp.f = ve.var.isFuncDeclaration();
5095 assert(exp.f);
5096 tiargs = null;
5097
5098 if (exp.f.overnext)
5099 exp.f = resolveFuncCall(exp.loc, sc, exp.f, tiargs, null, exp.arguments, FuncResolveFlag.overloadOnly);
5100 else
5101 {
5102 exp.f = exp.f.toAliasFunc();
5103 TypeFunction tf = cast(TypeFunction)exp.f.type;
5104 const(char)* failMessage;
5105 Expression[] fargs = exp.arguments ? (*exp.arguments)[] : null;
5106 if (!tf.callMatch(null, fargs, 0, &failMessage, sc))
5107 {
5108 OutBuffer buf;
5109 buf.writeByte('(');
5110 argExpTypesToCBuffer(&buf, exp.arguments);
5111 buf.writeByte(')');
5112
5113 //printf("tf = %s, args = %s\n", tf.deco, (*arguments)[0].type.deco);
5114 .error(exp.loc, "%s `%s%s` is not callable using argument types `%s`",
5115 exp.f.kind(), exp.f.toPrettyChars(), parametersTypeToChars(tf.parameterList), buf.peekChars());
5116 if (failMessage)
5117 errorSupplemental(exp.loc, "%s", failMessage);
5118 exp.f = null;
5119 }
5120 }
5121 if (!exp.f || exp.f.errors)
5122 return setError();
5123
5124 if (exp.f.needThis())
5125 {
5126 // Change the ancestor lambdas to delegate before hasThis(sc) call.
5127 if (exp.f.checkNestedReference(sc, exp.loc))
5128 return setError();
5129
5130 if (hasThis(sc))
5131 {
5132 // Supply an implicit 'this', as in
5133 // this.ident
5134 exp.e1 = new DotVarExp(exp.loc, (new ThisExp(exp.loc)).expressionSemantic(sc), ve.var);
5135 // Note: we cannot use f directly, because further overload resolution
5136 // through the supplied 'this' may cause different result.
5137 goto Lagain;
5138 }
5139 else if (isNeedThisScope(sc, exp.f))
5140 {
5141 // At this point it is possible that `exp.f` had an ambiguity error that was
5142 // silenced because the previous call to `resolveFuncCall` was done using
5143 // `FuncResolveFlag.overloadOnly`. To make sure that a proper error message
5144 // is printed, redo the call with `FuncResolveFlag.standard`.
5145 //
5146 // https://issues.dlang.org/show_bug.cgi?id=22157
5147 if (exp.f.overnext)
5148 exp.f = resolveFuncCall(exp.loc, sc, exp.f, tiargs, null, exp.arguments, FuncResolveFlag.standard);
5149
5150 if (!exp.f || exp.f.errors)
5151 return setError();
5152
5153 // If no error is printed, it means that `f` is the single matching overload
5154 // and it needs `this`.
5155 exp.error("need `this` for `%s` of type `%s`", exp.f.toChars(), exp.f.type.toChars());
5156 return setError();
5157 }
5158 }
5159
5160 checkFunctionAttributes(exp, sc, exp.f);
5161 checkAccess(exp.loc, sc, null, exp.f);
5162 if (exp.f.checkNestedReference(sc, exp.loc))
5163 return setError();
5164
5165 ethis = null;
5166 tthis = null;
5167
5168 if (ve.hasOverloads)
5169 {
5170 exp.e1 = new VarExp(ve.loc, exp.f, false);
5171 exp.e1.type = exp.f.type;
5172 }
5173 t1 = exp.f.type;
5174 }
5175 assert(t1.ty == Tfunction);
5176
5177 Expression argprefix;
5178 if (!exp.arguments)
5179 exp.arguments = new Expressions();
5180 if (functionParameters(exp.loc, sc, cast(TypeFunction)t1, ethis, tthis, exp.arguments, exp.f, &exp.type, &argprefix))
5181 return setError();
5182
5183 if (!exp.type)
5184 {
5185 exp.e1 = e1org; // https://issues.dlang.org/show_bug.cgi?id=10922
5186 // avoid recursive expression printing
5187 exp.error("forward reference to inferred return type of function call `%s`", exp.toChars());
5188 return setError();
5189 }
5190
5191 if (exp.f && exp.f.tintro)
5192 {
5193 Type t = exp.type;
5194 int offset = 0;
5195 TypeFunction tf = cast(TypeFunction)exp.f.tintro;
5196 if (tf.next.isBaseOf(t, &offset) && offset)
5197 {
5198 exp.type = tf.next;
5199 result = Expression.combine(argprefix, exp.castTo(sc, t));
5200 return;
5201 }
5202 }
5203
5204 // Handle the case of a direct lambda call
5205 if (exp.f && exp.f.isFuncLiteralDeclaration() && sc.func && !sc.intypeof)
5206 {
5207 exp.f.tookAddressOf = 0;
5208 }
5209
5210 result = Expression.combine(argprefix, exp);
5211
5212 if (isSuper)
5213 {
5214 auto ad = sc.func ? sc.func.isThis() : null;
5215 auto cd = ad ? ad.isClassDeclaration() : null;
5216 if (cd && cd.classKind == ClassKind.cpp && exp.f && !exp.f.fbody)
5217 {
5218 // if super is defined in C++, it sets the vtable pointer to the base class
5219 // so we have to restore it, but still return 'this' from super() call:
5220 // (auto __vptrTmp = this.__vptr, auto __superTmp = super()), (this.__vptr = __vptrTmp, __superTmp)
5221 Loc loc = exp.loc;
5222
5223 auto vptr = new DotIdExp(loc, new ThisExp(loc), Id.__vptr);
5224 auto vptrTmpDecl = copyToTemp(0, "__vptrTmp", vptr);
5225 auto declareVptrTmp = new DeclarationExp(loc, vptrTmpDecl);
5226
5227 auto superTmpDecl = copyToTemp(0, "__superTmp", result);
5228 auto declareSuperTmp = new DeclarationExp(loc, superTmpDecl);
5229
5230 auto declareTmps = new CommaExp(loc, declareVptrTmp, declareSuperTmp);
5231
5232 auto restoreVptr = new AssignExp(loc, vptr.syntaxCopy(), new VarExp(loc, vptrTmpDecl));
5233
5234 Expression e = new CommaExp(loc, declareTmps, new CommaExp(loc, restoreVptr, new VarExp(loc, superTmpDecl)));
5235 result = e.expressionSemantic(sc);
5236 }
5237 }
5238
5239 // declare dual-context container
Iain Buclaw235d5a92022-03-29 16:57:10 +02005240 if (exp.f && exp.f.hasDualContext() && !sc.intypeof && sc.func)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02005241 {
5242 // check access to second `this`
5243 if (AggregateDeclaration ad2 = exp.f.isMember2())
5244 {
5245 Expression te = new ThisExp(exp.loc).expressionSemantic(sc);
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01005246 if (te.op != EXP.error)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02005247 te = getRightThis(exp.loc, sc, ad2, te, exp.f);
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01005248 if (te.op == EXP.error)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02005249 {
5250 exp.error("need `this` of type `%s` to call function `%s`", ad2.toChars(), exp.f.toChars());
5251 return setError();
5252 }
5253 }
5254 exp.vthis2 = makeThis2Argument(exp.loc, sc, exp.f);
5255 Expression de = new DeclarationExp(exp.loc, exp.vthis2);
5256 result = Expression.combine(de, result);
5257 result = result.expressionSemantic(sc);
5258 }
5259 }
5260
5261 override void visit(DeclarationExp e)
5262 {
5263 if (e.type)
5264 {
5265 result = e;
5266 return;
5267 }
5268 static if (LOGSEMANTIC)
5269 {
5270 printf("DeclarationExp::semantic() %s\n", e.toChars());
5271 }
5272
5273 uint olderrors = global.errors;
5274
5275 /* This is here to support extern(linkage) declaration,
5276 * where the extern(linkage) winds up being an AttribDeclaration
5277 * wrapper.
5278 */
5279 Dsymbol s = e.declaration;
5280
5281 while (1)
5282 {
5283 AttribDeclaration ad = s.isAttribDeclaration();
5284 if (ad)
5285 {
5286 if (ad.decl && ad.decl.dim == 1)
5287 {
5288 s = (*ad.decl)[0];
5289 continue;
5290 }
5291 }
5292 break;
5293 }
5294
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02005295 //printf("inserting '%s' %p into sc = %p\n", s.toChars(), s, sc);
5296 // Insert into both local scope and function scope.
5297 // Must be unique in both.
5298 if (s.ident)
5299 {
Iain Buclaw6384eff2022-02-20 20:02:23 +01005300 VarDeclaration v = s.isVarDeclaration();
Iain Buclawd91cb202022-04-28 12:40:59 +02005301 if (v)
Iain Buclaw6384eff2022-02-20 20:02:23 +01005302 {
Iain Buclawd91cb202022-04-28 12:40:59 +02005303 if (sc.flags & SCOPE.Cfile)
5304 {
5305 /* Do semantic() on the type before inserting v into the symbol table
5306 */
5307 if (!v.originalType)
5308 v.originalType = v.type.syntaxCopy();
5309 Scope* sc2 = sc.push();
5310 sc2.stc |= v.storage_class & STC.FUNCATTR;
5311 sc2.linkage = LINK.c; // account for the extern(C) in front of the declaration
5312 v.inuse++;
5313 v.type = v.type.typeSemantic(v.loc, sc2);
5314 v.inuse--;
5315 sc2.pop();
5316 }
5317 else
5318 {
5319 /* Do semantic() on initializer first so this will be illegal:
5320 * int a = a;
5321 */
5322 e.declaration.dsymbolSemantic(sc);
5323 s.parent = sc.parent;
5324 }
Iain Buclaw6384eff2022-02-20 20:02:23 +01005325 }
5326
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02005327 if (!sc.insert(s))
5328 {
5329 auto conflict = sc.search(Loc.initial, s.ident, null);
5330 e.error("declaration `%s` is already defined", s.toPrettyChars());
5331 errorSupplemental(conflict.loc, "`%s` `%s` is defined here",
5332 conflict.kind(), conflict.toChars());
5333 return setError();
5334 }
Iain Buclaw6384eff2022-02-20 20:02:23 +01005335
5336 if (v && (sc.flags & SCOPE.Cfile))
5337 {
5338 /* Do semantic() on initializer last so this will be legal:
5339 * int a = a;
5340 */
5341 e.declaration.dsymbolSemantic(sc);
5342 s.parent = sc.parent;
5343 }
5344
5345 if (sc.func)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02005346 {
5347 // https://issues.dlang.org/show_bug.cgi?id=11720
5348 if ((s.isFuncDeclaration() ||
5349 s.isAggregateDeclaration() ||
5350 s.isEnumDeclaration() ||
5351 s.isTemplateDeclaration() ||
5352 v
5353 ) && !sc.func.localsymtab.insert(s))
5354 {
5355 // Get the previous symbol
5356 Dsymbol originalSymbol = sc.func.localsymtab.lookup(s.ident);
5357
5358 // Perturb the name mangling so that the symbols can co-exist
5359 // instead of colliding
5360 s.localNum = cast(ushort)(originalSymbol.localNum + 1);
Iain Buclaw6384eff2022-02-20 20:02:23 +01005361 // 65535 should be enough for anyone
5362 if (!s.localNum)
5363 {
5364 e.error("more than 65535 symbols with name `%s` generated", s.ident.toChars());
5365 return setError();
5366 }
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02005367
5368 // Replace originalSymbol with s, which updates the localCount
5369 sc.func.localsymtab.update(s);
5370
5371 // The mangling change only works for D mangling
5372 }
Iain Buclaw6384eff2022-02-20 20:02:23 +01005373
Iain Buclaw7e287502022-03-13 12:28:05 +01005374 if (!(sc.flags & SCOPE.Cfile))
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02005375 {
5376 /* https://issues.dlang.org/show_bug.cgi?id=21272
5377 * If we are in a foreach body we need to extract the
5378 * function containing the foreach
5379 */
5380 FuncDeclaration fes_enclosing_func;
5381 if (sc.func && sc.func.fes)
5382 fes_enclosing_func = sc.enclosing.enclosing.func;
5383
5384 // Disallow shadowing
5385 for (Scope* scx = sc.enclosing; scx && (scx.func == sc.func || (fes_enclosing_func && scx.func == fes_enclosing_func)); scx = scx.enclosing)
5386 {
5387 Dsymbol s2;
5388 if (scx.scopesym && scx.scopesym.symtab && (s2 = scx.scopesym.symtab.lookup(s.ident)) !is null && s != s2)
5389 {
5390 // allow STC.local symbols to be shadowed
5391 // TODO: not really an optimal design
5392 auto decl = s2.isDeclaration();
5393 if (!decl || !(decl.storage_class & STC.local))
5394 {
5395 if (sc.func.fes)
5396 {
5397 e.deprecation("%s `%s` is shadowing %s `%s`. Rename the `foreach` variable.", s.kind(), s.ident.toChars(), s2.kind(), s2.toPrettyChars());
5398 }
5399 else
5400 {
5401 e.error("%s `%s` is shadowing %s `%s`", s.kind(), s.ident.toChars(), s2.kind(), s2.toPrettyChars());
5402 return setError();
5403 }
5404 }
5405 }
5406 }
5407 }
5408 }
5409 }
5410 if (!s.isVarDeclaration())
5411 {
5412 Scope* sc2 = sc;
5413 if (sc2.stc & (STC.pure_ | STC.nothrow_ | STC.nogc))
5414 sc2 = sc.push();
5415 sc2.stc &= ~(STC.pure_ | STC.nothrow_ | STC.nogc);
5416 e.declaration.dsymbolSemantic(sc2);
5417 if (sc2 != sc)
5418 sc2.pop();
5419 s.parent = sc.parent;
5420 }
5421 if (global.errors == olderrors)
5422 {
5423 e.declaration.semantic2(sc);
5424 if (global.errors == olderrors)
5425 {
5426 e.declaration.semantic3(sc);
5427 }
5428 }
5429 // todo: error in declaration should be propagated.
5430
5431 e.type = Type.tvoid;
5432 result = e;
5433 }
5434
5435 override void visit(TypeidExp exp)
5436 {
5437 static if (LOGSEMANTIC)
5438 {
5439 printf("TypeidExp::semantic() %s\n", exp.toChars());
5440 }
5441 Type ta = isType(exp.obj);
5442 Expression ea = isExpression(exp.obj);
5443 Dsymbol sa = isDsymbol(exp.obj);
5444 //printf("ta %p ea %p sa %p\n", ta, ea, sa);
5445
5446 if (ta)
5447 {
5448 dmd.typesem.resolve(ta, exp.loc, sc, ea, ta, sa, true);
5449 }
5450
5451 if (ea)
5452 {
5453 if (auto sym = getDsymbol(ea))
5454 ea = symbolToExp(sym, exp.loc, sc, false);
5455 else
5456 ea = ea.expressionSemantic(sc);
5457 ea = resolveProperties(sc, ea);
5458 ta = ea.type;
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01005459 if (ea.op == EXP.type)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02005460 ea = null;
5461 }
5462
5463 if (!ta)
5464 {
5465 //printf("ta %p ea %p sa %p\n", ta, ea, sa);
5466 exp.error("no type for `typeid(%s)`", ea ? ea.toChars() : (sa ? sa.toChars() : ""));
5467 return setError();
5468 }
5469
Iain Buclaw1027dc42022-02-28 15:47:52 +01005470 ta.checkComplexTransition(exp.loc, sc);
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02005471
5472 Expression e;
5473 auto tb = ta.toBasetype();
5474 if (ea && tb.ty == Tclass)
5475 {
5476 if (tb.toDsymbol(sc).isClassDeclaration().classKind == ClassKind.cpp)
5477 {
Iain Buclaw5eb99272022-05-16 18:30:46 +02005478 error(exp.loc, "runtime type information is not supported for `extern(C++)` classes");
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02005479 e = ErrorExp.get();
5480 }
5481 else if (!Type.typeinfoclass)
5482 {
5483 error(exp.loc, "`object.TypeInfo_Class` could not be found, but is implicitly used");
5484 e = ErrorExp.get();
5485 }
5486 else
5487 {
5488 /* Get the dynamic type, which is .classinfo
5489 */
5490 ea = ea.expressionSemantic(sc);
5491 e = new TypeidExp(ea.loc, ea);
5492 e.type = Type.typeinfoclass.type;
5493 }
5494 }
5495 else if (ta.ty == Terror)
5496 {
5497 e = ErrorExp.get();
5498 }
5499 else
5500 {
5501 // Handle this in the glue layer
5502 e = new TypeidExp(exp.loc, ta);
5503 e.type = getTypeInfoType(exp.loc, ta, sc);
5504
5505 semanticTypeInfo(sc, ta);
5506
5507 if (ea)
5508 {
5509 e = new CommaExp(exp.loc, ea, e); // execute ea
5510 e = e.expressionSemantic(sc);
5511 }
5512 }
5513 result = e;
5514 }
5515
5516 override void visit(TraitsExp e)
5517 {
5518 result = semanticTraits(e, sc);
5519 }
5520
5521 override void visit(HaltExp e)
5522 {
5523 static if (LOGSEMANTIC)
5524 {
5525 printf("HaltExp::semantic()\n");
5526 }
5527 e.type = Type.tnoreturn;
5528 result = e;
5529 }
5530
5531 override void visit(IsExp e)
5532 {
5533 /* is(targ id tok tspec)
5534 * is(targ id : tok2)
5535 * is(targ id == tok2)
5536 */
5537 Type tded = null;
5538
5539 void yes()
5540 {
5541 //printf("yes\n");
5542 if (!e.id)
5543 {
5544 result = IntegerExp.createBool(true);
5545 return;
5546 }
5547
5548 Dsymbol s;
5549 Tuple tup = isTuple(tded);
5550 if (tup)
5551 s = new TupleDeclaration(e.loc, e.id, &tup.objects);
5552 else
5553 s = new AliasDeclaration(e.loc, e.id, tded);
5554 s.dsymbolSemantic(sc);
5555
5556 /* The reason for the !tup is unclear. It fails Phobos unittests if it is not there.
5557 * More investigation is needed.
5558 */
5559 if (!tup && !sc.insert(s))
5560 {
5561 auto conflict = sc.search(Loc.initial, s.ident, null);
5562 e.error("declaration `%s` is already defined", s.toPrettyChars());
5563 errorSupplemental(conflict.loc, "`%s` `%s` is defined here",
5564 conflict.kind(), conflict.toChars());
5565 }
5566
5567 unSpeculative(sc, s);
5568
5569 result = IntegerExp.createBool(true);
5570 }
5571 void no()
5572 {
5573 result = IntegerExp.createBool(false);
5574 //printf("no\n");
5575 }
5576
5577 static if (LOGSEMANTIC)
5578 {
5579 printf("IsExp::semantic(%s)\n", e.toChars());
5580 }
5581 if (e.id && !(sc.flags & SCOPE.condition))
5582 {
5583 e.error("can only declare type aliases within `static if` conditionals or `static assert`s");
5584 return setError();
5585 }
5586
5587 if (e.tok2 == TOK.package_ || e.tok2 == TOK.module_) // These is() expressions are special because they can work on modules, not just types.
5588 {
5589 const oldErrors = global.startGagging();
5590 Dsymbol sym = e.targ.toDsymbol(sc);
5591 global.endGagging(oldErrors);
5592
5593 if (sym is null)
5594 return no();
5595 Package p = resolveIsPackage(sym);
5596 if (p is null)
5597 return no();
5598 if (e.tok2 == TOK.package_ && p.isModule()) // Note that isModule() will return null for package modules because they're not actually instances of Module.
5599 return no();
5600 else if(e.tok2 == TOK.module_ && !(p.isModule() || p.isPackageMod()))
5601 return no();
5602 tded = e.targ;
5603 return yes();
5604 }
5605
5606 {
5607 Scope* sc2 = sc.copy(); // keep sc.flags
5608 sc2.tinst = null;
5609 sc2.minst = null;
5610 sc2.flags |= SCOPE.fullinst;
5611 Type t = e.targ.trySemantic(e.loc, sc2);
5612 sc2.pop();
5613 if (!t) // errors, so condition is false
5614 return no();
5615 e.targ = t;
5616 }
5617
5618 if (e.tok2 != TOK.reserved)
5619 {
5620 switch (e.tok2)
5621 {
5622 case TOK.struct_:
5623 if (e.targ.ty != Tstruct)
5624 return no();
5625 if ((cast(TypeStruct)e.targ).sym.isUnionDeclaration())
5626 return no();
5627 tded = e.targ;
5628 break;
5629
5630 case TOK.union_:
5631 if (e.targ.ty != Tstruct)
5632 return no();
5633 if (!(cast(TypeStruct)e.targ).sym.isUnionDeclaration())
5634 return no();
5635 tded = e.targ;
5636 break;
5637
5638 case TOK.class_:
5639 if (e.targ.ty != Tclass)
5640 return no();
5641 if ((cast(TypeClass)e.targ).sym.isInterfaceDeclaration())
5642 return no();
5643 tded = e.targ;
5644 break;
5645
5646 case TOK.interface_:
5647 if (e.targ.ty != Tclass)
5648 return no();
5649 if (!(cast(TypeClass)e.targ).sym.isInterfaceDeclaration())
5650 return no();
5651 tded = e.targ;
5652 break;
5653
5654 case TOK.const_:
5655 if (!e.targ.isConst())
5656 return no();
5657 tded = e.targ;
5658 break;
5659
5660 case TOK.immutable_:
5661 if (!e.targ.isImmutable())
5662 return no();
5663 tded = e.targ;
5664 break;
5665
5666 case TOK.shared_:
5667 if (!e.targ.isShared())
5668 return no();
5669 tded = e.targ;
5670 break;
5671
5672 case TOK.inout_:
5673 if (!e.targ.isWild())
5674 return no();
5675 tded = e.targ;
5676 break;
5677
5678 case TOK.super_:
5679 // If class or interface, get the base class and interfaces
5680 if (e.targ.ty != Tclass)
5681 return no();
5682 else
5683 {
5684 ClassDeclaration cd = (cast(TypeClass)e.targ).sym;
5685 auto args = new Parameters();
5686 args.reserve(cd.baseclasses.dim);
5687 if (cd.semanticRun < PASS.semanticdone)
5688 cd.dsymbolSemantic(null);
5689 for (size_t i = 0; i < cd.baseclasses.dim; i++)
5690 {
5691 BaseClass* b = (*cd.baseclasses)[i];
5692 args.push(new Parameter(STC.in_, b.type, null, null, null));
5693 }
5694 tded = new TypeTuple(args);
5695 }
5696 break;
5697
5698 case TOK.enum_:
5699 if (e.targ.ty != Tenum)
5700 return no();
5701 if (e.id)
5702 tded = (cast(TypeEnum)e.targ).sym.getMemtype(e.loc);
5703 else
5704 tded = e.targ;
5705
5706 if (tded.ty == Terror)
5707 return setError();
5708 break;
5709
5710 case TOK.delegate_:
5711 if (e.targ.ty != Tdelegate)
5712 return no();
5713 tded = (cast(TypeDelegate)e.targ).next; // the underlying function type
5714 break;
5715
5716 case TOK.function_:
5717 case TOK.parameters:
5718 {
5719 if (e.targ.ty != Tfunction)
5720 return no();
5721 tded = e.targ;
5722
5723 /* Generate tuple from function parameter types.
5724 */
5725 assert(tded.ty == Tfunction);
5726 auto tdedf = tded.isTypeFunction();
5727 auto args = new Parameters();
5728 foreach (i, arg; tdedf.parameterList)
5729 {
5730 assert(arg && arg.type);
5731 /* If one of the default arguments was an error,
5732 don't return an invalid tuple
5733 */
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01005734 if (e.tok2 == TOK.parameters && arg.defaultArg && arg.defaultArg.op == EXP.error)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02005735 return setError();
5736 args.push(new Parameter(arg.storageClass, arg.type, (e.tok2 == TOK.parameters) ? arg.ident : null, (e.tok2 == TOK.parameters) ? arg.defaultArg : null, arg.userAttribDecl));
5737 }
5738 tded = new TypeTuple(args);
5739 break;
5740 }
5741 case TOK.return_:
5742 /* Get the 'return type' for the function,
5743 * delegate, or pointer to function.
5744 */
5745 if (auto tf = e.targ.isFunction_Delegate_PtrToFunction())
5746 tded = tf.next;
5747 else
5748 return no();
5749 break;
5750
5751 case TOK.argumentTypes:
5752 /* Generate a type tuple of the equivalent types used to determine if a
5753 * function argument of this type can be passed in registers.
5754 * The results of this are highly platform dependent, and intended
5755 * primarly for use in implementing va_arg().
5756 */
5757 tded = target.toArgTypes(e.targ);
5758 if (!tded)
5759 return no();
5760 // not valid for a parameter
5761 break;
5762
5763 case TOK.vector:
5764 if (e.targ.ty != Tvector)
5765 return no();
5766 tded = (cast(TypeVector)e.targ).basetype;
5767 break;
5768
5769 default:
5770 assert(0);
5771 }
5772
5773 // https://issues.dlang.org/show_bug.cgi?id=18753
5774 if (tded)
5775 return yes();
5776 return no();
5777 }
5778 else if (e.tspec && !e.id && !(e.parameters && e.parameters.dim))
5779 {
5780 /* Evaluate to true if targ matches tspec
5781 * is(targ == tspec)
5782 * is(targ : tspec)
5783 */
5784 e.tspec = e.tspec.typeSemantic(e.loc, sc);
5785 //printf("targ = %s, %s\n", e.targ.toChars(), e.targ.deco);
5786 //printf("tspec = %s, %s\n", e.tspec.toChars(), e.tspec.deco);
5787
5788 if (e.tok == TOK.colon)
5789 {
5790 // current scope is itself deprecated, or deprecations are not errors
5791 const bool deprecationAllowed = sc.isDeprecated
5792 || global.params.useDeprecated != DiagnosticReporting.error;
5793 const bool preventAliasThis = e.targ.hasDeprecatedAliasThis && !deprecationAllowed;
5794
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02005795 if (preventAliasThis && e.targ.ty == Tstruct)
5796 {
5797 if ((cast(TypeStruct) e.targ).implicitConvToWithoutAliasThis(e.tspec))
5798 return yes();
5799 else
5800 return no();
5801 }
5802 else if (preventAliasThis && e.targ.ty == Tclass)
5803 {
5804 if ((cast(TypeClass) e.targ).implicitConvToWithoutAliasThis(e.tspec))
5805 return yes();
5806 else
5807 return no();
5808 }
5809 else if (e.targ.implicitConvTo(e.tspec))
5810 return yes();
5811 else
5812 return no();
5813 }
5814 else /* == */
5815 {
5816 if (e.targ.equals(e.tspec))
5817 return yes();
5818 else
5819 return no();
5820 }
5821 }
5822 else if (e.tspec)
5823 {
5824 /* Evaluate to true if targ matches tspec.
5825 * If true, declare id as an alias for the specialized type.
5826 * is(targ == tspec, tpl)
5827 * is(targ : tspec, tpl)
5828 * is(targ id == tspec)
5829 * is(targ id : tspec)
5830 * is(targ id == tspec, tpl)
5831 * is(targ id : tspec, tpl)
5832 */
5833 Identifier tid = e.id ? e.id : Identifier.generateId("__isexp_id");
5834 e.parameters.insert(0, new TemplateTypeParameter(e.loc, tid, null, null));
5835
5836 Objects dedtypes = Objects(e.parameters.dim);
5837 dedtypes.zero();
5838
5839 MATCH m = deduceType(e.targ, sc, e.tspec, e.parameters, &dedtypes, null, 0, e.tok == TOK.equal);
5840 //printf("targ: %s\n", targ.toChars());
5841 //printf("tspec: %s\n", tspec.toChars());
5842 if (m == MATCH.nomatch || (m != MATCH.exact && e.tok == TOK.equal))
5843 {
5844 return no();
5845 }
5846 else
5847 {
5848 tded = cast(Type)dedtypes[0];
5849 if (!tded)
5850 tded = e.targ;
5851 Objects tiargs = Objects(1);
5852 tiargs[0] = e.targ;
5853
5854 /* Declare trailing parameters
5855 */
5856 for (size_t i = 1; i < e.parameters.dim; i++)
5857 {
5858 TemplateParameter tp = (*e.parameters)[i];
5859 Declaration s = null;
5860
5861 m = tp.matchArg(e.loc, sc, &tiargs, i, e.parameters, &dedtypes, &s);
5862 if (m == MATCH.nomatch)
5863 return no();
5864 s.dsymbolSemantic(sc);
5865 if (!sc.insert(s))
5866 {
5867 auto conflict = sc.search(Loc.initial, s.ident, null);
5868 e.error("declaration `%s` is already defined", s.toPrettyChars());
5869 errorSupplemental(conflict.loc, "`%s` `%s` is defined here",
5870 conflict.kind(), conflict.toChars());
5871 }
5872
5873 unSpeculative(sc, s);
5874 }
5875 return yes();
5876 }
5877 }
5878 else if (e.id)
5879 {
5880 /* Declare id as an alias for type targ. Evaluate to true
5881 * is(targ id)
5882 */
5883 tded = e.targ;
5884 }
5885 return yes();
5886 }
5887
5888 override void visit(BinAssignExp exp)
5889 {
5890 if (exp.type)
5891 {
5892 result = exp;
5893 return;
5894 }
5895
5896 Expression e = exp.op_overload(sc);
5897 if (e)
5898 {
5899 result = e;
5900 return;
5901 }
5902
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01005903 if (exp.e1.op == EXP.arrayLength)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02005904 {
5905 // arr.length op= e2;
5906 e = rewriteOpAssign(exp);
5907 e = e.expressionSemantic(sc);
5908 result = e;
5909 return;
5910 }
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01005911 if (exp.e1.op == EXP.slice || exp.e1.type.ty == Tarray || exp.e1.type.ty == Tsarray)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02005912 {
5913 if (checkNonAssignmentArrayOp(exp.e1))
5914 return setError();
5915
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01005916 if (exp.e1.op == EXP.slice)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02005917 (cast(SliceExp)exp.e1).arrayop = true;
5918
5919 // T[] op= ...
5920 if (exp.e2.implicitConvTo(exp.e1.type.nextOf()))
5921 {
5922 // T[] op= T
5923 exp.e2 = exp.e2.castTo(sc, exp.e1.type.nextOf());
5924 }
5925 else if (Expression ex = typeCombine(exp, sc))
5926 {
5927 result = ex;
5928 return;
5929 }
5930 exp.type = exp.e1.type;
5931 result = arrayOp(exp, sc);
5932 return;
5933 }
5934
5935 exp.e1 = exp.e1.expressionSemantic(sc);
5936 exp.e1 = exp.e1.modifiableLvalue(sc, exp.e1);
5937 exp.e1 = exp.e1.optimize(WANTvalue, /*keepLvalue*/ true);
5938 exp.type = exp.e1.type;
5939
5940 if (auto ad = isAggregate(exp.e1.type))
5941 {
5942 if (const s = search_function(ad, Id.opOpAssign))
5943 {
5944 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());
5945 return setError();
5946 }
5947 }
5948 if (exp.e1.checkScalar() ||
5949 exp.e1.checkReadModifyWrite(exp.op, exp.e2) ||
5950 exp.e1.checkSharedAccess(sc))
5951 return setError();
5952
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01005953 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);
5954 int bitwise = (exp.op == EXP.andAssign || exp.op == EXP.orAssign || exp.op == EXP.xorAssign);
5955 int shift = (exp.op == EXP.leftShiftAssign || exp.op == EXP.rightShiftAssign || exp.op == EXP.unsignedRightShiftAssign);
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02005956
5957 if (bitwise && exp.type.toBasetype().ty == Tbool)
5958 exp.e2 = exp.e2.implicitCastTo(sc, exp.type);
5959 else if (exp.checkNoBool())
5960 return setError();
5961
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01005962 if ((exp.op == EXP.addAssign || exp.op == EXP.minAssign) && exp.e1.type.toBasetype().ty == Tpointer && exp.e2.type.toBasetype().isintegral())
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02005963 {
5964 result = scaleFactor(exp, sc);
5965 return;
5966 }
5967
5968 if (Expression ex = typeCombine(exp, sc))
5969 {
5970 result = ex;
5971 return;
5972 }
5973
5974 if (arith && (exp.checkArithmeticBin() || exp.checkSharedAccessBin(sc)))
5975 return setError();
5976 if ((bitwise || shift) && (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc)))
5977 return setError();
5978
5979 if (shift)
5980 {
5981 if (exp.e2.type.toBasetype().ty != Tvector)
5982 exp.e2 = exp.e2.castTo(sc, Type.tshiftcnt);
5983 }
5984
5985 if (!target.isVectorOpSupported(exp.type.toBasetype(), exp.op, exp.e2.type.toBasetype()))
5986 {
5987 result = exp.incompatibleTypes();
5988 return;
5989 }
5990
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01005991 if (exp.e1.op == EXP.error || exp.e2.op == EXP.error)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02005992 return setError();
5993
5994 e = exp.checkOpAssignTypes(sc);
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01005995 if (e.op == EXP.error)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02005996 {
5997 result = e;
5998 return;
5999 }
6000
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01006001 assert(e.op == EXP.assign || e == exp);
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02006002 result = (cast(BinExp)e).reorderSettingAAElem(sc);
6003 }
6004
6005 private Expression compileIt(MixinExp exp)
6006 {
6007 OutBuffer buf;
6008 if (expressionsToString(buf, sc, exp.exps))
6009 return null;
6010
6011 uint errors = global.errors;
6012 const len = buf.length;
6013 const str = buf.extractChars()[0 .. len];
6014 scope p = new Parser!ASTCodegen(exp.loc, sc._module, str, false);
6015 p.nextToken();
6016 //printf("p.loc.linnum = %d\n", p.loc.linnum);
6017
6018 Expression e = p.parseExpression();
6019 if (global.errors != errors)
6020 return null;
6021
6022 if (p.token.value != TOK.endOfFile)
6023 {
6024 exp.error("incomplete mixin expression `%s`", str.ptr);
6025 return null;
6026 }
6027 return e;
6028 }
6029
6030 override void visit(MixinExp exp)
6031 {
6032 /* https://dlang.org/spec/expression.html#mixin_expressions
6033 */
6034
6035 static if (LOGSEMANTIC)
6036 {
6037 printf("MixinExp::semantic('%s')\n", exp.toChars());
6038 }
6039
6040 auto e = compileIt(exp);
6041 if (!e)
6042 return setError();
6043 result = e.expressionSemantic(sc);
6044 }
6045
6046 override void visit(ImportExp e)
6047 {
6048 static if (LOGSEMANTIC)
6049 {
6050 printf("ImportExp::semantic('%s')\n", e.toChars());
6051 }
6052
6053 auto se = semanticString(sc, e.e1, "file name argument");
6054 if (!se)
6055 return setError();
6056 se = se.toUTF8(sc);
6057
Iain Buclawd97f3bc2022-06-24 19:41:41 +02006058 auto namez = se.toStringz();
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02006059 if (!global.filePath)
6060 {
Iain Buclawd97f3bc2022-06-24 19:41:41 +02006061 e.error("need `-J` switch to import text file `%s`", namez.ptr);
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02006062 return setError();
6063 }
6064
6065 /* Be wary of CWE-22: Improper Limitation of a Pathname to a Restricted Directory
6066 * ('Path Traversal') attacks.
Iain Buclawc43b5902022-01-02 13:36:51 +01006067 * https://cwe.mitre.org/data/definitions/22.html
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02006068 */
6069
6070 if (FileName.absolute(namez))
6071 {
6072 e.error("absolute path is not allowed in import expression: `%s`", se.toChars());
6073 return setError();
6074 }
6075
6076 auto idxReserved = FileName.findReservedChar(namez);
6077 if (idxReserved != size_t.max)
6078 {
Iain Buclaw610d7892022-05-27 19:36:06 +02006079 e.error("`%s` is not a valid filename on this platform", se.toChars());
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02006080 e.errorSupplemental("Character `'%c'` is reserved and cannot be used", namez[idxReserved]);
6081 return setError();
6082 }
6083
6084 if (FileName.refersToParentDir(namez))
6085 {
6086 e.error("path refers to parent (`..`) directory: `%s`", se.toChars());
6087 return setError();
6088 }
6089
Iain Buclawd97f3bc2022-06-24 19:41:41 +02006090 auto resolvedNamez = FileName.searchPath(global.filePath, namez, false);
6091 if (!resolvedNamez)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02006092 {
6093 e.error("file `%s` cannot be found or not in a path specified with `-J`", se.toChars());
6094 e.errorSupplemental("Path(s) searched (as provided by `-J`):");
6095 foreach (idx, path; *global.filePath)
6096 {
6097 const attr = FileName.exists(path);
6098 const(char)* err = attr == 2 ? "" :
6099 (attr == 1 ? " (not a directory)" : " (path not found)");
Iain Buclawc43b5902022-01-02 13:36:51 +01006100 e.errorSupplemental("[%llu]: `%s`%s", cast(ulong)idx, path, err);
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02006101 }
6102 return setError();
6103 }
6104
Iain Buclawd97f3bc2022-06-24 19:41:41 +02006105 sc._module.contentImportedFiles.push(resolvedNamez.ptr);
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02006106 if (global.params.verbose)
6107 {
6108 const slice = se.peekString();
Iain Buclawd97f3bc2022-06-24 19:41:41 +02006109 message("file %.*s\t(%s)", cast(int)slice.length, slice.ptr, resolvedNamez.ptr);
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02006110 }
Iain Buclaw5eb99272022-05-16 18:30:46 +02006111 if (global.params.moduleDeps.buffer !is null)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02006112 {
Iain Buclaw5eb99272022-05-16 18:30:46 +02006113 OutBuffer* ob = global.params.moduleDeps.buffer;
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02006114 Module imod = sc._module;
6115
Iain Buclaw5eb99272022-05-16 18:30:46 +02006116 if (!global.params.moduleDeps.name)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02006117 ob.writestring("depsFile ");
6118 ob.writestring(imod.toPrettyChars());
6119 ob.writestring(" (");
6120 escapePath(ob, imod.srcfile.toChars());
6121 ob.writestring(") : ");
Iain Buclaw5eb99272022-05-16 18:30:46 +02006122 if (global.params.moduleDeps.name)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02006123 ob.writestring("string : ");
6124 ob.write(se.peekString());
6125 ob.writestring(" (");
Iain Buclawd97f3bc2022-06-24 19:41:41 +02006126 escapePath(ob, resolvedNamez.ptr);
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02006127 ob.writestring(")");
6128 ob.writenl();
6129 }
Iain Buclaw5eb99272022-05-16 18:30:46 +02006130 if (global.params.makeDeps.doOutput)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02006131 {
Iain Buclawd97f3bc2022-06-24 19:41:41 +02006132 global.params.makeDeps.files.push(resolvedNamez.ptr);
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02006133 }
6134
6135 {
Iain Buclawd97f3bc2022-06-24 19:41:41 +02006136 auto fileName = FileName(resolvedNamez);
Iain Buclaw235d5a92022-03-29 16:57:10 +02006137 if (auto fmResult = global.fileManager.lookup(fileName))
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02006138 {
Iain Buclaw31350632022-04-13 13:34:49 +01006139 se = new StringExp(e.loc, fmResult);
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02006140 }
6141 else
6142 {
Iain Buclawd97f3bc2022-06-24 19:41:41 +02006143 auto readResult = File.read(resolvedNamez);
Iain Buclaw0fb57032021-12-05 17:11:12 +01006144 if (!readResult.success)
6145 {
Iain Buclawd97f3bc2022-06-24 19:41:41 +02006146 e.error("cannot read file `%s`", resolvedNamez.ptr);
Iain Buclaw0fb57032021-12-05 17:11:12 +01006147 return setError();
6148 }
6149 else
6150 {
6151 // take ownership of buffer (probably leaking)
6152 auto data = readResult.extractSlice();
6153 se = new StringExp(e.loc, data);
Iain Buclaw31350632022-04-13 13:34:49 +01006154 global.fileManager.add(fileName, data);
Iain Buclaw0fb57032021-12-05 17:11:12 +01006155 }
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02006156 }
6157 }
6158 result = se.expressionSemantic(sc);
6159 }
6160
6161 override void visit(AssertExp exp)
6162 {
6163 // https://dlang.org/spec/expression.html#assert_expressions
6164 static if (LOGSEMANTIC)
6165 {
6166 printf("AssertExp::semantic('%s')\n", exp.toChars());
6167 }
6168
6169 const generateMsg = !exp.msg && global.params.checkAction == CHECKACTION.context && global.params.useAssert == CHECKENABLE.on;
6170 Expression temporariesPrefix;
6171
6172 if (generateMsg)
6173 // no message - use assert expression as msg
6174 {
6175 if (!verifyHookExist(exp.loc, *sc, Id._d_assert_fail, "generating assert messages"))
6176 return setError();
6177
6178 /*
6179 {
6180 auto a = e1, b = e2;
6181 assert(a == b, _d_assert_fail!"=="(a, b));
6182 }()
6183 */
6184
6185 /*
6186 Stores the result of an operand expression into a temporary
6187 if necessary, e.g. if it is an impure fuction call containing side
6188 effects as in https://issues.dlang.org/show_bug.cgi?id=20114
6189
6190 Params:
6191 op = an expression which may require a temporary (added to
6192 `temporariesPrefix`: `auto tmp = op`) and will be replaced
6193 by `tmp` if necessary
6194
6195 Returns: (possibly replaced) `op`
6196 */
6197 Expression maybePromoteToTmp(ref Expression op)
6198 {
6199 // https://issues.dlang.org/show_bug.cgi?id=20989
6200 // Flag that _d_assert_fail will never dereference `array.ptr` to avoid safety
6201 // errors for `assert(!array.ptr)` => `_d_assert_fail!"!"(array.ptr)`
6202 {
6203 auto die = op.isDotIdExp();
6204 if (die && die.ident == Id.ptr)
6205 die.noderef = true;
6206 }
6207
6208 op = op.expressionSemantic(sc);
6209 op = resolveProperties(sc, op);
6210
6211 // Detect assert's using static operator overloads (e.g. `"var" in environment`)
6212 if (auto te = op.isTypeExp())
6213 {
6214 // Replace the TypeExp with it's textual representation
6215 // Including "..." in the error message isn't quite right but
6216 // proper solutions require more drastic changes, e.g. directly
6217 // using miniFormat and combine instead of calling _d_assert_fail
6218 auto name = new StringExp(te.loc, te.toString());
6219 return name.expressionSemantic(sc);
6220 }
6221
6222 // Create a temporary for expressions with side effects
6223 // Defensively assume that function calls may have side effects even
6224 // though it's not detected by hasSideEffect (e.g. `debug puts("Hello")` )
6225 // Rewriting CallExp's also avoids some issues with the inliner/debug generation
6226 if (op.hasSideEffect(true))
6227 {
6228 // Don't create an invalid temporary for void-expressions
6229 // Further semantic will issue an appropriate error
6230 if (op.type.ty == Tvoid)
6231 return op;
6232
6233 // https://issues.dlang.org/show_bug.cgi?id=21590
6234 // Don't create unnecessary temporaries and detect `assert(a = b)`
6235 if (op.isAssignExp() || op.isBinAssignExp())
6236 {
6237 auto left = (cast(BinExp) op).e1;
6238
6239 // Find leftmost expression to handle other rewrites,
6240 // e.g. --(++a) => a += 1 -= 1
6241 while (left.isAssignExp() || left.isBinAssignExp())
6242 left = (cast(BinExp) left).e1;
6243
6244 // Only use the assignee if it's a variable and skip
6245 // other lvalues (e.g. ref's returned by functions)
6246 if (left.isVarExp())
6247 return left;
6248
6249 // Sanity check that `op` can be converted to boolean
6250 // But don't raise errors for assignments enclosed in another expression
6251 if (op is exp.e1)
6252 op.toBoolean(sc);
6253 }
6254
6255 // Tuples with side-effects already receive a temporary during semantic
6256 if (op.type.isTypeTuple())
6257 {
6258 auto te = op.isTupleExp();
6259 assert(te);
6260
6261 // Create a new tuple without the associated temporary
6262 auto res = new TupleExp(op.loc, te.exps);
6263 return res.expressionSemantic(sc);
6264 }
6265
6266 const stc = op.isLvalue() ? STC.ref_ : 0;
6267 auto tmp = copyToTemp(stc, "__assertOp", op);
6268 tmp.dsymbolSemantic(sc);
6269
6270 auto decl = new DeclarationExp(op.loc, tmp);
6271 temporariesPrefix = Expression.combine(temporariesPrefix, decl);
6272
6273 op = new VarExp(op.loc, tmp);
6274 op = op.expressionSemantic(sc);
6275 }
6276 return op;
6277 }
6278
6279 // if the assert condition is a mixin expression, try to compile it
6280 if (auto ce = exp.e1.isMixinExp())
6281 {
6282 if (auto e1 = compileIt(ce))
6283 exp.e1 = e1;
6284 }
6285
6286 Expressions* es;
6287 Objects* tiargs;
6288 Loc loc = exp.e1.loc;
6289
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01006290 const op = exp.e1.op;
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02006291 bool isEqualsCallExpression;
Iain Buclaw235d5a92022-03-29 16:57:10 +02006292 if (const callExp = exp.e1.isCallExp())
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02006293 {
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02006294 // https://issues.dlang.org/show_bug.cgi?id=20331
6295 // callExp.f may be null if the assert contains a call to
6296 // a function pointer or literal
6297 if (const callExpFunc = callExp.f)
6298 {
6299 const callExpIdent = callExpFunc.ident;
6300 isEqualsCallExpression = callExpIdent == Id.__equals ||
6301 callExpIdent == Id.eq;
6302 }
6303 }
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01006304 if (op == EXP.equal || op == EXP.notEqual ||
6305 op == EXP.lessThan || op == EXP.greaterThan ||
6306 op == EXP.lessOrEqual || op == EXP.greaterOrEqual ||
6307 op == EXP.identity || op == EXP.notIdentity ||
6308 op == EXP.in_ ||
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02006309 isEqualsCallExpression)
6310 {
6311 es = new Expressions(3);
6312 tiargs = new Objects(1);
6313
6314 if (isEqualsCallExpression)
6315 {
6316 auto callExp = cast(CallExp) exp.e1;
6317 auto args = callExp.arguments;
6318
6319 // structs with opEquals get rewritten to a DotVarExp:
6320 // a.opEquals(b)
6321 // https://issues.dlang.org/show_bug.cgi?id=20100
6322 if (args.length == 1)
6323 {
6324 auto dv = callExp.e1.isDotVarExp();
6325 assert(dv);
6326
6327 // runtime args
6328 (*es)[1] = maybePromoteToTmp(dv.e1);
6329 (*es)[2] = maybePromoteToTmp((*args)[0]);
6330 }
6331 else
6332 {
6333 // runtime args
6334 (*es)[1] = maybePromoteToTmp((*args)[0]);
6335 (*es)[2] = maybePromoteToTmp((*args)[1]);
6336 }
6337 }
6338 else
6339 {
6340 auto binExp = cast(EqualExp) exp.e1;
6341
6342 // runtime args
6343 (*es)[1] = maybePromoteToTmp(binExp.e1);
6344 (*es)[2] = maybePromoteToTmp(binExp.e2);
6345 }
6346
6347 // template args
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01006348 Expression comp = new StringExp(loc, isEqualsCallExpression ? "==" : EXPtoString(exp.e1.op));
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02006349 comp = comp.expressionSemantic(sc);
6350 (*es)[0] = comp;
6351 (*tiargs)[0] = (*es)[1].type;
6352 }
6353
6354 // Format exp.e1 before any additional boolean conversion
6355 // Ignore &&/|| because "assert(...) failed" is more informative than "false != true"
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01006356 else if (op != EXP.andAnd && op != EXP.orOr)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02006357 {
6358 es = new Expressions(2);
6359 tiargs = new Objects(1);
6360
6361 if (auto ne = exp.e1.isNotExp())
6362 {
6363 // Fetch the (potential non-bool) expression and fold
6364 // (n) negations into (n % 2) negations, e.g. !!a => a
6365 for (bool neg = true; ; neg = !neg)
6366 {
6367 if (auto ne2 = ne.e1.isNotExp())
6368 ne = ne2;
6369 else
6370 {
6371 (*es)[0] = new StringExp(loc, neg ? "!" : "");
6372 (*es)[1] = maybePromoteToTmp(ne.e1);
6373 break;
6374 }
6375 }
6376 }
6377 else
6378 { // Simply format exp.e1
6379 (*es)[0] = new StringExp(loc, "");
6380 (*es)[1] = maybePromoteToTmp(exp.e1);
6381 }
6382
6383 (*tiargs)[0] = (*es)[1].type;
6384
6385 // Passing __ctfe to auto ref infers ref and aborts compilation:
6386 // "cannot modify compiler-generated variable __ctfe"
6387 auto ve = (*es)[1].isVarExp();
6388 if (ve && ve.var.ident == Id.ctfe)
6389 {
6390 exp.msg = new StringExp(loc, "assert(__ctfe) failed!");
6391 goto LSkip;
6392 }
6393 }
6394 else
6395 {
6396 OutBuffer buf;
6397 buf.printf("%s failed", exp.toChars());
6398 exp.msg = new StringExp(Loc.initial, buf.extractSlice());
6399 goto LSkip;
6400 }
6401
6402 Expression __assertFail = new IdentifierExp(exp.loc, Id.empty);
6403 auto assertFail = new DotIdExp(loc, __assertFail, Id.object);
6404
6405 auto dt = new DotTemplateInstanceExp(loc, assertFail, Id._d_assert_fail, tiargs);
6406 auto ec = CallExp.create(loc, dt, es);
6407 exp.msg = ec;
6408 }
6409
6410 LSkip:
6411 if (Expression ex = unaSemantic(exp, sc))
6412 {
6413 result = ex;
6414 return;
6415 }
6416
6417 exp.e1 = resolveProperties(sc, exp.e1);
6418 // BUG: see if we can do compile time elimination of the Assert
6419 exp.e1 = exp.e1.optimize(WANTvalue);
6420 exp.e1 = exp.e1.toBoolean(sc);
6421
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01006422 if (exp.e1.op == EXP.error)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02006423 {
6424 result = exp.e1;
6425 return;
6426 }
6427
6428 if (exp.msg)
6429 {
6430 exp.msg = expressionSemantic(exp.msg, sc);
6431 exp.msg = resolveProperties(sc, exp.msg);
6432 exp.msg = exp.msg.implicitCastTo(sc, Type.tchar.constOf().arrayOf());
6433 exp.msg = exp.msg.optimize(WANTvalue);
Iain Buclawb7a586b2022-08-25 19:04:50 +02006434 checkParamArgumentEscape(sc, null, null, null, STC.undefined_, exp.msg, true, false);
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02006435 }
6436
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01006437 if (exp.msg && exp.msg.op == EXP.error)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02006438 {
6439 result = exp.msg;
6440 return;
6441 }
6442
6443 auto f1 = checkNonAssignmentArrayOp(exp.e1);
6444 auto f2 = exp.msg && checkNonAssignmentArrayOp(exp.msg);
6445 if (f1 || f2)
6446 return setError();
6447
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01006448 if (exp.e1.toBool().hasValue(false))
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02006449 {
6450 /* This is an `assert(0)` which means halt program execution
6451 */
6452 FuncDeclaration fd = sc.parent.isFuncDeclaration();
6453 if (fd)
6454 fd.hasReturnExp |= 4;
6455 sc.ctorflow.orCSX(CSX.halt);
6456
6457 if (global.params.useAssert == CHECKENABLE.off)
6458 {
6459 Expression e = new HaltExp(exp.loc);
6460 e = e.expressionSemantic(sc);
6461 result = e;
6462 return;
6463 }
Iain Buclaw0fb57032021-12-05 17:11:12 +01006464
6465 // Only override the type when it isn't already some flavour of noreturn,
6466 // e.g. when this assert was generated by defaultInitLiteral
6467 if (!exp.type || !exp.type.isTypeNoreturn())
6468 exp.type = Type.tnoreturn;
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02006469 }
6470 else
6471 exp.type = Type.tvoid;
6472
6473 result = !temporariesPrefix
6474 ? exp
6475 : Expression.combine(temporariesPrefix, exp).expressionSemantic(sc);
6476 }
6477
Iain Buclawd7569182022-02-13 20:17:53 +01006478 override void visit(ThrowExp te)
6479 {
6480 import dmd.statementsem;
6481
6482 if (StatementSemanticVisitor.throwSemantic(te.loc, te.e1, sc))
6483 result = te;
6484 else
6485 setError();
6486 }
6487
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02006488 override void visit(DotIdExp exp)
6489 {
6490 static if (LOGSEMANTIC)
6491 {
6492 printf("DotIdExp::semantic(this = %p, '%s')\n", exp, exp.toChars());
Iain Buclaw31350632022-04-13 13:34:49 +01006493 //printf("e1.op = %d, '%s'\n", e1.op, Token.toChars(e1.op));
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02006494 }
Iain Buclawfd435682021-12-15 19:47:02 +01006495
6496 if (sc.flags & SCOPE.Cfile)
6497 {
6498 /* See if need to rewrite the AST because of cast/call ambiguity
6499 */
6500 if (auto e = castCallAmbiguity(exp, sc))
6501 {
6502 result = expressionSemantic(e, sc);
6503 return;
6504 }
6505 }
6506
Iain Buclaw0fb57032021-12-05 17:11:12 +01006507 if (exp.arrow) // ImportC only
6508 exp.e1 = exp.e1.expressionSemantic(sc).arrayFuncConv(sc);
6509
6510 if (sc.flags & SCOPE.Cfile)
6511 {
6512 if (exp.ident == Id.__xalignof && exp.e1.isTypeExp())
6513 {
6514 // C11 6.5.3 says _Alignof only applies to types
6515 Expression e;
6516 Type t;
6517 Dsymbol s;
6518 dmd.typesem.resolve(exp.e1.type, exp.e1.loc, sc, e, t, s, true);
6519 if (e)
6520 {
6521 exp.e1.error("argument to `_Alignof` must be a type");
6522 return setError();
6523 }
6524 else if (t)
6525 {
Iain Buclaw235d5a92022-03-29 16:57:10 +02006526 // Note similarity to getProperty() implementation of __xalignof
6527 const explicitAlignment = t.alignment();
6528 const naturalAlignment = t.alignsize();
6529 const actualAlignment = (explicitAlignment.isDefault() ? naturalAlignment : explicitAlignment.get());
6530 result = new IntegerExp(exp.loc, actualAlignment, Type.tsize_t);
Iain Buclaw0fb57032021-12-05 17:11:12 +01006531 }
6532 else if (s)
6533 {
6534 exp.e1.error("argument to `_Alignof` must be a type");
6535 return setError();
6536 }
6537 else
6538 assert(0);
6539 return;
6540 }
6541 }
6542
6543 if (sc.flags & SCOPE.Cfile && exp.ident != Id.__sizeof)
6544 {
6545 result = fieldLookup(exp.e1, sc, exp.ident);
6546 return;
6547 }
6548
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02006549 Expression e = exp.semanticY(sc, 1);
Iain Buclaw0fb57032021-12-05 17:11:12 +01006550
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02006551 if (e && isDotOpDispatch(e))
6552 {
Iain Buclaw0fb57032021-12-05 17:11:12 +01006553 auto ode = e;
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02006554 uint errors = global.startGagging();
6555 e = resolvePropertiesX(sc, e);
Iain Buclaw0fb57032021-12-05 17:11:12 +01006556 // Any error or if 'e' is not resolved, go to UFCS
6557 if (global.endGagging(errors) || e is ode)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02006558 e = null; /* fall down to UFCS */
6559 else
6560 {
6561 result = e;
6562 return;
6563 }
6564 }
6565 if (!e) // if failed to find the property
6566 {
6567 /* If ident is not a valid property, rewrite:
6568 * e1.ident
6569 * as:
6570 * .ident(e1)
6571 */
6572 e = resolveUFCSProperties(sc, exp);
6573 }
6574 result = e;
6575 }
6576
6577 override void visit(DotTemplateExp e)
6578 {
6579 if (e.type)
6580 {
6581 result = e;
6582 return;
6583 }
6584 if (Expression ex = unaSemantic(e, sc))
6585 {
6586 result = ex;
6587 return;
6588 }
6589 // 'void' like TemplateExp
6590 e.type = Type.tvoid;
6591 result = e;
6592 }
6593
6594 override void visit(DotVarExp exp)
6595 {
6596 static if (LOGSEMANTIC)
6597 {
6598 printf("DotVarExp::semantic('%s')\n", exp.toChars());
6599 }
6600 if (exp.type)
6601 {
6602 result = exp;
6603 return;
6604 }
6605
6606 exp.var = exp.var.toAlias().isDeclaration();
6607
6608 exp.e1 = exp.e1.expressionSemantic(sc);
6609
6610 if (auto tup = exp.var.isTupleDeclaration())
6611 {
6612 /* Replace:
6613 * e1.tuple(a, b, c)
6614 * with:
6615 * tuple(e1.a, e1.b, e1.c)
6616 */
6617 Expression e0;
6618 Expression ev = sc.func ? extractSideEffect(sc, "__tup", e0, exp.e1) : exp.e1;
6619
6620 auto exps = new Expressions();
6621 exps.reserve(tup.objects.dim);
6622 for (size_t i = 0; i < tup.objects.dim; i++)
6623 {
6624 RootObject o = (*tup.objects)[i];
6625 Expression e;
6626 Declaration var;
Iain Buclaw610d7892022-05-27 19:36:06 +02006627 switch (o.dyncast()) with (DYNCAST)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02006628 {
Iain Buclaw610d7892022-05-27 19:36:06 +02006629 case expression:
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02006630 e = cast(Expression)o;
6631 if (auto se = e.isDsymbolExp())
6632 var = se.s.isDeclaration();
6633 else if (auto ve = e.isVarExp())
6634 if (!ve.var.isFuncDeclaration())
6635 // Exempt functions for backwards compatibility reasons.
6636 // See: https://issues.dlang.org/show_bug.cgi?id=20470#c1
6637 var = ve.var;
Iain Buclaw610d7892022-05-27 19:36:06 +02006638 break;
6639 case dsymbol:
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02006640 Dsymbol s = cast(Dsymbol) o;
6641 Declaration d = s.isDeclaration();
6642 if (!d || d.isFuncDeclaration())
6643 // Exempt functions for backwards compatibility reasons.
6644 // See: https://issues.dlang.org/show_bug.cgi?id=20470#c1
6645 e = new DsymbolExp(exp.loc, s);
6646 else
6647 var = d;
Iain Buclaw610d7892022-05-27 19:36:06 +02006648 break;
6649 case type:
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02006650 e = new TypeExp(exp.loc, cast(Type)o);
Iain Buclaw610d7892022-05-27 19:36:06 +02006651 break;
6652 default:
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02006653 exp.error("`%s` is not an expression", o.toChars());
6654 return setError();
6655 }
6656 if (var)
6657 e = new DotVarExp(exp.loc, ev, var);
6658 exps.push(e);
6659 }
6660
6661 Expression e = new TupleExp(exp.loc, e0, exps);
6662 e = e.expressionSemantic(sc);
6663 result = e;
6664 return;
6665 }
Iain Buclawec486b72022-06-13 10:41:57 +02006666 else if (auto ad = exp.var.isAliasDeclaration())
6667 {
6668 if (auto t = ad.getType())
6669 {
6670 result = new TypeExp(exp.loc, t).expressionSemantic(sc);
6671 return;
6672 }
6673 }
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02006674
6675 exp.e1 = exp.e1.addDtorHook(sc);
6676
6677 Type t1 = exp.e1.type;
6678
6679 if (FuncDeclaration fd = exp.var.isFuncDeclaration())
6680 {
6681 // for functions, do checks after overload resolution
6682 if (!fd.functionSemantic())
6683 return setError();
6684
6685 /* https://issues.dlang.org/show_bug.cgi?id=13843
6686 * If fd obviously has no overloads, we should
6687 * normalize AST, and it will give a chance to wrap fd with FuncExp.
6688 */
6689 if ((fd.isNested() && !fd.isThis()) || fd.isFuncLiteralDeclaration())
6690 {
6691 // (e1, fd)
6692 auto e = symbolToExp(fd, exp.loc, sc, false);
6693 result = Expression.combine(exp.e1, e);
6694 return;
6695 }
6696
6697 exp.type = fd.type;
6698 assert(exp.type);
6699 }
6700 else if (OverDeclaration od = exp.var.isOverDeclaration())
6701 {
6702 exp.type = Type.tvoid; // ambiguous type?
6703 }
6704 else
6705 {
6706 exp.type = exp.var.type;
6707 if (!exp.type && global.errors) // var is goofed up, just return error.
6708 return setError();
6709 assert(exp.type);
6710
6711 if (t1.ty == Tpointer)
6712 t1 = t1.nextOf();
6713
6714 exp.type = exp.type.addMod(t1.mod);
6715
Iain Buclaw5eb99272022-05-16 18:30:46 +02006716 // https://issues.dlang.org/show_bug.cgi?id=23109
6717 // Run semantic on the DotVarExp type
6718 if (auto handle = exp.type.isClassHandle())
6719 {
6720 if (handle.semanticRun < PASS.semanticdone && !handle.isBaseInfoComplete())
6721 handle.dsymbolSemantic(null);
6722 }
6723
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02006724 Dsymbol vparent = exp.var.toParent();
6725 AggregateDeclaration ad = vparent ? vparent.isAggregateDeclaration() : null;
6726 if (Expression e1x = getRightThis(exp.loc, sc, ad, exp.e1, exp.var, 1))
6727 exp.e1 = e1x;
6728 else
6729 {
6730 /* Later checkRightThis will report correct error for invalid field variable access.
6731 */
6732 Expression e = new VarExp(exp.loc, exp.var);
6733 e = e.expressionSemantic(sc);
6734 result = e;
6735 return;
6736 }
6737 checkAccess(exp.loc, sc, exp.e1, exp.var);
6738
6739 VarDeclaration v = exp.var.isVarDeclaration();
6740 if (v && (v.isDataseg() || (v.storage_class & STC.manifest)))
6741 {
6742 Expression e = expandVar(WANTvalue, v);
6743 if (e)
6744 {
6745 result = e;
6746 return;
6747 }
6748 }
6749
6750 if (v && (v.isDataseg() || // fix https://issues.dlang.org/show_bug.cgi?id=8238
Iain Buclaw235d5a92022-03-29 16:57:10 +02006751 (!v.needThis() && v.semanticRun > PASS.initial))) // fix https://issues.dlang.org/show_bug.cgi?id=17258
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02006752 {
6753 // (e1, v)
6754 checkAccess(exp.loc, sc, exp.e1, v);
6755 Expression e = new VarExp(exp.loc, v);
6756 e = new CommaExp(exp.loc, exp.e1, e);
6757 e = e.expressionSemantic(sc);
6758 result = e;
6759 return;
6760 }
6761 }
6762 //printf("-DotVarExp::semantic('%s')\n", toChars());
6763 result = exp;
6764 }
6765
6766 override void visit(DotTemplateInstanceExp exp)
6767 {
6768 static if (LOGSEMANTIC)
6769 {
6770 printf("DotTemplateInstanceExp::semantic('%s')\n", exp.toChars());
6771 }
Iain Buclaw0fb57032021-12-05 17:11:12 +01006772 if (exp.type)
6773 {
6774 result = exp;
6775 return;
6776 }
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02006777 // Indicate we need to resolve by UFCS.
6778 Expression e = exp.semanticY(sc, 1);
6779 if (!e)
6780 e = resolveUFCSProperties(sc, exp);
Iain Buclaw0fb57032021-12-05 17:11:12 +01006781 if (e is exp)
6782 e.type = Type.tvoid; // Unresolved type, because it needs inference
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02006783 result = e;
6784 }
6785
6786 override void visit(DelegateExp e)
6787 {
6788 static if (LOGSEMANTIC)
6789 {
6790 printf("DelegateExp::semantic('%s')\n", e.toChars());
6791 }
6792 if (e.type)
6793 {
6794 result = e;
6795 return;
6796 }
6797
6798 e.e1 = e.e1.expressionSemantic(sc);
6799
6800 e.type = new TypeDelegate(e.func.type.isTypeFunction());
6801 e.type = e.type.typeSemantic(e.loc, sc);
6802
6803 FuncDeclaration f = e.func.toAliasFunc();
Iain Buclaw5eb99272022-05-16 18:30:46 +02006804 AggregateDeclaration ad = f.isMemberLocal();
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02006805 if (f.needThis())
6806 e.e1 = getRightThis(e.loc, sc, ad, e.e1, f);
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01006807 if (e.e1.op == EXP.error)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02006808 return setError();
6809
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02006810 if (f.type.ty == Tfunction)
6811 {
6812 TypeFunction tf = cast(TypeFunction)f.type;
6813 if (!MODmethodConv(e.e1.type.mod, f.type.mod))
6814 {
6815 OutBuffer thisBuf, funcBuf;
6816 MODMatchToBuffer(&thisBuf, e.e1.type.mod, tf.mod);
6817 MODMatchToBuffer(&funcBuf, tf.mod, e.e1.type.mod);
6818 e.error("%smethod `%s` is not callable using a %s`%s`",
6819 funcBuf.peekChars(), f.toPrettyChars(), thisBuf.peekChars(), e.e1.toChars());
6820 return setError();
6821 }
6822 }
6823 if (ad && ad.isClassDeclaration() && ad.type != e.e1.type)
6824 {
6825 // A downcast is required for interfaces
6826 // https://issues.dlang.org/show_bug.cgi?id=3706
6827 e.e1 = new CastExp(e.loc, e.e1, ad.type);
6828 e.e1 = e.e1.expressionSemantic(sc);
6829 }
6830 result = e;
6831 // declare dual-context container
Iain Buclaw235d5a92022-03-29 16:57:10 +02006832 if (f.hasDualContext() && !sc.intypeof && sc.func)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02006833 {
6834 // check access to second `this`
6835 if (AggregateDeclaration ad2 = f.isMember2())
6836 {
6837 Expression te = new ThisExp(e.loc).expressionSemantic(sc);
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01006838 if (te.op != EXP.error)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02006839 te = getRightThis(e.loc, sc, ad2, te, f);
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01006840 if (te.op == EXP.error)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02006841 {
6842 e.error("need `this` of type `%s` to make delegate from function `%s`", ad2.toChars(), f.toChars());
6843 return setError();
6844 }
6845 }
6846 VarDeclaration vthis2 = makeThis2Argument(e.loc, sc, f);
6847 e.vthis2 = vthis2;
6848 Expression de = new DeclarationExp(e.loc, vthis2);
6849 result = Expression.combine(de, result);
6850 result = result.expressionSemantic(sc);
6851 }
6852 }
6853
6854 override void visit(DotTypeExp exp)
6855 {
6856 static if (LOGSEMANTIC)
6857 {
6858 printf("DotTypeExp::semantic('%s')\n", exp.toChars());
6859 }
6860 if (exp.type)
6861 {
6862 result = exp;
6863 return;
6864 }
6865
6866 if (auto e = unaSemantic(exp, sc))
6867 {
6868 result = e;
6869 return;
6870 }
6871
6872 exp.type = exp.sym.getType().addMod(exp.e1.type.mod);
6873 result = exp;
6874 }
6875
6876 override void visit(AddrExp exp)
6877 {
6878 static if (LOGSEMANTIC)
6879 {
6880 printf("AddrExp::semantic('%s')\n", exp.toChars());
6881 }
6882 if (exp.type)
6883 {
6884 result = exp;
6885 return;
6886 }
6887
6888 if (Expression ex = unaSemantic(exp, sc))
6889 {
6890 result = ex;
6891 return;
6892 }
6893
6894 if (sc.flags & SCOPE.Cfile)
6895 {
Iain Buclaw5eb99272022-05-16 18:30:46 +02006896 /* Special handling for &"string"/&(T[]){0, 1}
6897 * since C regards string/array literals as lvalues
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02006898 */
Iain Buclaw5eb99272022-05-16 18:30:46 +02006899 auto e = exp.e1;
6900 if(e.isStringExp() || e.isArrayLiteralExp())
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02006901 {
Iain Buclaw5eb99272022-05-16 18:30:46 +02006902 e.type = typeSemantic(e.type, Loc.initial, sc);
6903 // if type is already a pointer exp is an illegal expression of the form `&(&"")`
6904 if (!e.type.isTypePointer())
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02006905 {
Iain Buclaw5eb99272022-05-16 18:30:46 +02006906 e.type = e.type.pointerTo();
6907 result = e;
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02006908 return;
6909 }
Iain Buclaw5eb99272022-05-16 18:30:46 +02006910 else
6911 {
6912 // `toLvalue` call further below is upon exp.e1, omitting & from the error message
6913 exp.toLvalue(sc, null);
6914 return setError();
6915 }
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02006916 }
6917 }
6918
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01006919 int wasCond = exp.e1.op == EXP.question;
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02006920
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01006921 if (exp.e1.op == EXP.dotTemplateInstance)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02006922 {
6923 DotTemplateInstanceExp dti = cast(DotTemplateInstanceExp)exp.e1;
6924 TemplateInstance ti = dti.ti;
6925 {
6926 //assert(ti.needsTypeInference(sc));
6927 ti.dsymbolSemantic(sc);
6928 if (!ti.inst || ti.errors) // if template failed to expand
6929 return setError();
6930
6931 Dsymbol s = ti.toAlias();
6932 FuncDeclaration f = s.isFuncDeclaration();
6933 if (f)
6934 {
6935 exp.e1 = new DotVarExp(exp.e1.loc, dti.e1, f);
6936 exp.e1 = exp.e1.expressionSemantic(sc);
6937 }
6938 }
6939 }
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01006940 else if (exp.e1.op == EXP.scope_)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02006941 {
6942 TemplateInstance ti = (cast(ScopeExp)exp.e1).sds.isTemplateInstance();
6943 if (ti)
6944 {
6945 //assert(ti.needsTypeInference(sc));
6946 ti.dsymbolSemantic(sc);
6947 if (!ti.inst || ti.errors) // if template failed to expand
6948 return setError();
6949
6950 Dsymbol s = ti.toAlias();
6951 FuncDeclaration f = s.isFuncDeclaration();
6952 if (f)
6953 {
6954 exp.e1 = new VarExp(exp.e1.loc, f);
6955 exp.e1 = exp.e1.expressionSemantic(sc);
6956 }
6957 }
6958 }
6959 /* https://issues.dlang.org/show_bug.cgi?id=809
6960 *
6961 * If the address of a lazy variable is taken,
6962 * the expression is rewritten so that the type
6963 * of it is the delegate type. This means that
6964 * the symbol is not going to represent a call
6965 * to the delegate anymore, but rather, the
6966 * actual symbol.
6967 */
6968 if (auto ve = exp.e1.isVarExp())
6969 {
6970 if (ve.var.storage_class & STC.lazy_)
6971 {
6972 exp.e1 = exp.e1.expressionSemantic(sc);
6973 exp.e1 = resolveProperties(sc, exp.e1);
6974 if (auto callExp = exp.e1.isCallExp())
6975 {
6976 if (callExp.e1.type.toBasetype().ty == Tdelegate)
6977 {
6978 /* https://issues.dlang.org/show_bug.cgi?id=20551
6979 *
6980 * Cannot take address of lazy parameter in @safe code
6981 * because it might end up being a pointer to undefined
6982 * memory.
6983 */
Iain Buclaw610d7892022-05-27 19:36:06 +02006984 if (1)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02006985 {
Iain Buclaw610d7892022-05-27 19:36:06 +02006986 if (sc.setUnsafe(false, exp.loc,
Iain Buclaw5eb99272022-05-16 18:30:46 +02006987 "cannot take address of lazy parameter `%s` in `@safe` function `%s`", ve, sc.func))
6988 {
6989 setError();
6990 return;
6991 }
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02006992 }
Iain Buclaw5eb99272022-05-16 18:30:46 +02006993 VarExp ve2 = callExp.e1.isVarExp();
6994 ve2.delegateWasExtracted = true;
6995 ve2.var.storage_class |= STC.scope_;
6996 result = ve2;
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02006997 return;
6998 }
6999 }
7000 }
7001 }
7002
7003 exp.e1 = exp.e1.toLvalue(sc, null);
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01007004 if (exp.e1.op == EXP.error)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02007005 {
7006 result = exp.e1;
7007 return;
7008 }
7009 if (checkNonAssignmentArrayOp(exp.e1))
7010 return setError();
7011
7012 if (!exp.e1.type)
7013 {
7014 exp.error("cannot take address of `%s`", exp.e1.toChars());
7015 return setError();
7016 }
Iain Buclawd97f3bc2022-06-24 19:41:41 +02007017 if (!checkAddressable(exp, sc))
7018 return setError();
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02007019
7020 bool hasOverloads;
7021 if (auto f = isFuncAddress(exp, &hasOverloads))
7022 {
7023 if (!hasOverloads && f.checkForwardRef(exp.loc))
7024 return setError();
7025 }
7026 else if (!exp.e1.type.deco)
7027 {
Iain Buclaw6384eff2022-02-20 20:02:23 +01007028 // try to resolve the type
7029 exp.e1.type = exp.e1.type.typeSemantic(exp.e1.loc, null);
7030 if (!exp.e1.type.deco) // still couldn't resolve it
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02007031 {
Iain Buclaw6384eff2022-02-20 20:02:23 +01007032 if (auto ve = exp.e1.isVarExp())
7033 {
7034 Declaration d = ve.var;
7035 exp.error("forward reference to %s `%s`", d.kind(), d.toChars());
7036 }
7037 else
7038 exp.error("forward reference to type `%s` of expression `%s`", exp.e1.type.toChars(), exp.e1.toChars());
7039 return setError();
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02007040 }
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02007041 }
7042
7043 exp.type = exp.e1.type.pointerTo();
7044
7045 // See if this should really be a delegate
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01007046 if (exp.e1.op == EXP.dotVariable)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02007047 {
7048 DotVarExp dve = cast(DotVarExp)exp.e1;
7049 FuncDeclaration f = dve.var.isFuncDeclaration();
7050 if (f)
7051 {
7052 f = f.toAliasFunc(); // FIXME, should see overloads
7053 // https://issues.dlang.org/show_bug.cgi?id=1983
7054 if (!dve.hasOverloads)
7055 f.tookAddressOf++;
7056
7057 Expression e;
7058 if (f.needThis())
7059 e = new DelegateExp(exp.loc, dve.e1, f, dve.hasOverloads);
7060 else // It is a function pointer. Convert &v.f() --> (v, &V.f())
7061 e = new CommaExp(exp.loc, dve.e1, new AddrExp(exp.loc, new VarExp(exp.loc, f, dve.hasOverloads)));
7062 e = e.expressionSemantic(sc);
7063 result = e;
7064 return;
7065 }
7066
7067 // Look for misaligned pointer in @safe mode
7068 if (checkUnsafeAccess(sc, dve, !exp.type.isMutable(), true))
7069 return setError();
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02007070 }
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01007071 else if (exp.e1.op == EXP.variable)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02007072 {
7073 VarExp ve = cast(VarExp)exp.e1;
7074 VarDeclaration v = ve.var.isVarDeclaration();
7075 if (v)
7076 {
7077 if (!checkAddressVar(sc, exp.e1, v))
7078 return setError();
7079
7080 ve.checkPurity(sc, v);
7081 }
7082 FuncDeclaration f = ve.var.isFuncDeclaration();
7083 if (f)
7084 {
7085 /* Because nested functions cannot be overloaded,
7086 * mark here that we took its address because castTo()
7087 * may not be called with an exact match.
Iain Buclawec486b72022-06-13 10:41:57 +02007088 *
7089 * https://issues.dlang.org/show_bug.cgi?id=19285 :
7090 * We also need to make sure we aren't inside a typeof. Ideally the compiler
7091 * would do typeof(...) semantic analysis speculatively then collect information
7092 * about what it used rather than relying on what are effectively semantically-global
7093 * variables but it doesn't.
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02007094 */
Iain Buclawec486b72022-06-13 10:41:57 +02007095 if (!sc.isFromSpeculativeSemanticContext() && (!ve.hasOverloads || (f.isNested() && !f.needThis())))
7096 {
7097 // TODO: Refactor to use a proper interface that can keep track of causes.
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02007098 f.tookAddressOf++;
Iain Buclawec486b72022-06-13 10:41:57 +02007099 }
7100
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02007101 if (f.isNested() && !f.needThis())
7102 {
7103 if (f.isFuncLiteralDeclaration())
7104 {
7105 if (!f.FuncDeclaration.isNested())
7106 {
7107 /* Supply a 'null' for a this pointer if no this is available
7108 */
7109 Expression e = new DelegateExp(exp.loc, new NullExp(exp.loc, Type.tnull), f, ve.hasOverloads);
7110 e = e.expressionSemantic(sc);
7111 result = e;
7112 return;
7113 }
7114 }
7115 Expression e = new DelegateExp(exp.loc, exp.e1, f, ve.hasOverloads);
7116 e = e.expressionSemantic(sc);
7117 result = e;
7118 return;
7119 }
7120 if (f.needThis())
7121 {
7122 if (hasThis(sc))
7123 {
7124 /* Should probably supply 'this' after overload resolution,
7125 * not before.
7126 */
7127 Expression ethis = new ThisExp(exp.loc);
7128 Expression e = new DelegateExp(exp.loc, ethis, f, ve.hasOverloads);
7129 e = e.expressionSemantic(sc);
7130 result = e;
7131 return;
7132 }
Iain Buclaw5eb99272022-05-16 18:30:46 +02007133 if (sc.func && !sc.intypeof && !(sc.flags & SCOPE.debug_))
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02007134 {
Iain Buclaw610d7892022-05-27 19:36:06 +02007135 sc.setUnsafe(false, exp.loc,
Iain Buclaw5eb99272022-05-16 18:30:46 +02007136 "`this` reference necessary to take address of member `%s` in `@safe` function `%s`",
7137 f, sc.func);
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02007138 }
7139 }
7140 }
7141 }
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01007142 else if (exp.e1.op == EXP.index)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02007143 {
7144 /* For:
7145 * int[3] a;
7146 * &a[i]
7147 * check 'a' the same as for a regular variable
7148 */
7149 if (VarDeclaration v = expToVariable(exp.e1))
7150 {
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02007151 exp.e1.checkPurity(sc, v);
7152 }
7153 }
7154 else if (wasCond)
7155 {
7156 /* a ? b : c was transformed to *(a ? &b : &c), but we still
7157 * need to do safety checks
7158 */
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01007159 assert(exp.e1.op == EXP.star);
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02007160 PtrExp pe = cast(PtrExp)exp.e1;
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01007161 assert(pe.e1.op == EXP.question);
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02007162 CondExp ce = cast(CondExp)pe.e1;
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01007163 assert(ce.e1.op == EXP.address);
7164 assert(ce.e2.op == EXP.address);
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02007165
7166 // Re-run semantic on the address expressions only
7167 ce.e1.type = null;
7168 ce.e1 = ce.e1.expressionSemantic(sc);
7169 ce.e2.type = null;
7170 ce.e2 = ce.e2.expressionSemantic(sc);
7171 }
7172 result = exp.optimize(WANTvalue);
7173 }
7174
7175 override void visit(PtrExp exp)
7176 {
7177 static if (LOGSEMANTIC)
7178 {
7179 printf("PtrExp::semantic('%s')\n", exp.toChars());
7180 }
7181 if (exp.type)
7182 {
7183 result = exp;
7184 return;
7185 }
7186
7187 Expression e = exp.op_overload(sc);
7188 if (e)
7189 {
7190 result = e;
7191 return;
7192 }
7193
Iain Buclawfbdaa582022-03-21 16:52:40 +01007194 exp.e1 = exp.e1.arrayFuncConv(sc);
7195
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02007196 Type tb = exp.e1.type.toBasetype();
7197 switch (tb.ty)
7198 {
7199 case Tpointer:
7200 exp.type = (cast(TypePointer)tb).next;
7201 break;
7202
7203 case Tsarray:
7204 case Tarray:
7205 if (isNonAssignmentArrayOp(exp.e1))
7206 goto default;
7207 exp.error("using `*` on an array is no longer supported; use `*(%s).ptr` instead", exp.e1.toChars());
7208 exp.type = (cast(TypeArray)tb).next;
7209 exp.e1 = exp.e1.castTo(sc, exp.type.pointerTo());
7210 break;
7211
7212 case Terror:
7213 return setError();
7214
7215 case Tnull:
7216 exp.type = Type.tnoreturn; // typeof(*null) is bottom type
7217 break;
7218
7219 default:
7220 exp.error("can only `*` a pointer, not a `%s`", exp.e1.type.toChars());
7221 goto case Terror;
7222 }
7223
7224 if (exp.checkValue())
7225 return setError();
7226
7227 result = exp;
7228 }
7229
7230 override void visit(NegExp exp)
7231 {
7232 static if (LOGSEMANTIC)
7233 {
7234 printf("NegExp::semantic('%s')\n", exp.toChars());
7235 }
7236 if (exp.type)
7237 {
7238 result = exp;
7239 return;
7240 }
7241
7242 Expression e = exp.op_overload(sc);
7243 if (e)
7244 {
7245 result = e;
7246 return;
7247 }
7248
7249 fix16997(sc, exp);
7250 exp.type = exp.e1.type;
7251 Type tb = exp.type.toBasetype();
7252 if (tb.ty == Tarray || tb.ty == Tsarray)
7253 {
7254 if (!isArrayOpValid(exp.e1))
7255 {
7256 result = arrayOpInvalidError(exp);
7257 return;
7258 }
7259 result = exp;
7260 return;
7261 }
7262 if (!target.isVectorOpSupported(tb, exp.op))
7263 {
7264 result = exp.incompatibleTypes();
7265 return;
7266 }
7267 if (exp.e1.checkNoBool())
7268 return setError();
7269 if (exp.e1.checkArithmetic() ||
7270 exp.e1.checkSharedAccess(sc))
7271 return setError();
7272
7273 result = exp;
7274 }
7275
7276 override void visit(UAddExp exp)
7277 {
7278 static if (LOGSEMANTIC)
7279 {
7280 printf("UAddExp::semantic('%s')\n", exp.toChars());
7281 }
7282 assert(!exp.type);
7283
7284 Expression e = exp.op_overload(sc);
7285 if (e)
7286 {
7287 result = e;
7288 return;
7289 }
7290
7291 fix16997(sc, exp);
7292 if (!target.isVectorOpSupported(exp.e1.type.toBasetype(), exp.op))
7293 {
7294 result = exp.incompatibleTypes();
7295 return;
7296 }
7297 if (exp.e1.checkNoBool())
7298 return setError();
7299 if (exp.e1.checkArithmetic())
7300 return setError();
7301 if (exp.e1.checkSharedAccess(sc))
7302 return setError();
7303
7304 result = exp.e1;
7305 }
7306
7307 override void visit(ComExp exp)
7308 {
7309 if (exp.type)
7310 {
7311 result = exp;
7312 return;
7313 }
7314
7315 Expression e = exp.op_overload(sc);
7316 if (e)
7317 {
7318 result = e;
7319 return;
7320 }
7321
7322 fix16997(sc, exp);
7323 exp.type = exp.e1.type;
7324 Type tb = exp.type.toBasetype();
7325 if (tb.ty == Tarray || tb.ty == Tsarray)
7326 {
7327 if (!isArrayOpValid(exp.e1))
7328 {
7329 result = arrayOpInvalidError(exp);
7330 return;
7331 }
7332 result = exp;
7333 return;
7334 }
7335 if (!target.isVectorOpSupported(tb, exp.op))
7336 {
7337 result = exp.incompatibleTypes();
7338 return;
7339 }
7340 if (exp.e1.checkNoBool())
7341 return setError();
7342 if (exp.e1.checkIntegral() ||
7343 exp.e1.checkSharedAccess(sc))
7344 return setError();
7345
7346 result = exp;
7347 }
7348
7349 override void visit(NotExp e)
7350 {
7351 if (e.type)
7352 {
7353 result = e;
7354 return;
7355 }
7356
7357 e.setNoderefOperand();
7358
7359 // Note there is no operator overload
7360 if (Expression ex = unaSemantic(e, sc))
7361 {
7362 result = ex;
7363 return;
7364 }
7365
7366 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01007367 if (e.e1.op == EXP.type)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02007368 e.e1 = resolveAliasThis(sc, e.e1);
7369
7370 e.e1 = resolveProperties(sc, e.e1);
7371 e.e1 = e.e1.toBoolean(sc);
7372 if (e.e1.type == Type.terror)
7373 {
7374 result = e.e1;
7375 return;
7376 }
7377
7378 if (!target.isVectorOpSupported(e.e1.type.toBasetype(), e.op))
7379 {
7380 result = e.incompatibleTypes();
7381 }
7382 // https://issues.dlang.org/show_bug.cgi?id=13910
7383 // Today NotExp can take an array as its operand.
7384 if (checkNonAssignmentArrayOp(e.e1))
7385 return setError();
7386
Iain Buclaw235d5a92022-03-29 16:57:10 +02007387 e.type = (sc && sc.flags & SCOPE.Cfile) ? Type.tint32 : Type.tbool;
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02007388 result = e;
7389 }
7390
7391 override void visit(DeleteExp exp)
7392 {
Iain Buclaw6384eff2022-02-20 20:02:23 +01007393 // @@@DEPRECATED_2.109@@@
7394 // 1. Deprecated since 2.079
7395 // 2. Error since 2.099
7396 // 3. Removal of keyword, "delete" can be used for other identities
7397 if (!exp.isRAII)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02007398 {
Iain Buclaw235d5a92022-03-29 16:57:10 +02007399 error(exp.loc, "the `delete` keyword is obsolete");
7400 errorSupplemental(exp.loc, "use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead");
Iain Buclaw6384eff2022-02-20 20:02:23 +01007401 return setError();
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02007402 }
7403
Iain Buclawb3f58f82021-12-20 19:25:32 +01007404 Expression e = exp;
7405
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02007406 if (Expression ex = unaSemantic(exp, sc))
7407 {
7408 result = ex;
7409 return;
7410 }
7411 exp.e1 = resolveProperties(sc, exp.e1);
7412 exp.e1 = exp.e1.modifiableLvalue(sc, null);
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01007413 if (exp.e1.op == EXP.error)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02007414 {
7415 result = exp.e1;
7416 return;
7417 }
7418 exp.type = Type.tvoid;
7419
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02007420 Type tb = exp.e1.type.toBasetype();
Iain Buclaw6384eff2022-02-20 20:02:23 +01007421
7422 /* Now that `delete` in user code is an error, we only get here when
7423 * `isRAII` has been set to true for the deletion of a `scope class`. */
7424 if (tb.ty != Tclass)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02007425 {
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02007426 exp.error("cannot delete type `%s`", exp.e1.type.toChars());
7427 return setError();
7428 }
7429
Iain Buclaw6384eff2022-02-20 20:02:23 +01007430 ClassDeclaration cd = (cast(TypeClass)tb).sym;
7431 if (cd.isCOMinterface())
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02007432 {
Iain Buclaw6384eff2022-02-20 20:02:23 +01007433 /* Because COM classes are deleted by IUnknown.Release()
7434 */
7435 exp.error("cannot `delete` instance of COM interface `%s`", cd.toChars());
7436 return setError();
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02007437 }
7438
Iain Buclaw6384eff2022-02-20 20:02:23 +01007439 bool err = false;
7440 if (cd.dtor)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02007441 {
Iain Buclaw6384eff2022-02-20 20:02:23 +01007442 err |= !cd.dtor.functionSemantic();
7443 err |= exp.checkPurity(sc, cd.dtor);
7444 err |= exp.checkSafety(sc, cd.dtor);
7445 err |= exp.checkNogc(sc, cd.dtor);
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02007446 }
7447 if (err)
7448 return setError();
7449
Iain Buclawb3f58f82021-12-20 19:25:32 +01007450 result = e;
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02007451 }
7452
7453 override void visit(CastExp exp)
7454 {
7455 static if (LOGSEMANTIC)
7456 {
7457 printf("CastExp::semantic('%s')\n", exp.toChars());
7458 }
7459 //static int x; assert(++x < 10);
7460 if (exp.type)
7461 {
7462 result = exp;
7463 return;
7464 }
7465
7466 if ((sc && sc.flags & SCOPE.Cfile) &&
Iain Buclaw6384eff2022-02-20 20:02:23 +01007467 exp.to && (exp.to.ty == Tident || exp.to.ty == Tsarray) &&
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01007468 (exp.e1.op == EXP.address || exp.e1.op == EXP.star ||
7469 exp.e1.op == EXP.uadd || exp.e1.op == EXP.negate))
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02007470 {
7471 /* Ambiguous cases arise from CParser if type-name is just an identifier.
7472 * ( identifier ) cast-expression
Iain Buclaw6384eff2022-02-20 20:02:23 +01007473 * ( identifier [expression]) cast-expression
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02007474 * If we determine that `identifier` is a variable, and cast-expression
7475 * is one of the unary operators (& * + -), then rewrite this cast
7476 * as a binary expression.
7477 */
7478 Loc loc = exp.loc;
7479 Type t;
7480 Expression e;
7481 Dsymbol s;
7482 exp.to.resolve(loc, sc, e, t, s);
7483 if (e !is null)
7484 {
7485 if (auto ex = exp.e1.isAddrExp()) // (ident) &exp -> (ident & exp)
7486 result = new AndExp(loc, e, ex.e1);
7487 else if (auto ex = exp.e1.isPtrExp()) // (ident) *exp -> (ident * exp)
7488 result = new MulExp(loc, e, ex.e1);
7489 else if (auto ex = exp.e1.isUAddExp()) // (ident) +exp -> (ident + exp)
7490 result = new AddExp(loc, e, ex.e1);
7491 else if (auto ex = exp.e1.isNegExp()) // (ident) -exp -> (ident - exp)
7492 result = new MinExp(loc, e, ex.e1);
7493
7494 assert(result);
7495 result = result.expressionSemantic(sc);
7496 return;
7497 }
7498 }
7499
7500 if (exp.to)
7501 {
7502 exp.to = exp.to.typeSemantic(exp.loc, sc);
7503 if (exp.to == Type.terror)
7504 return setError();
7505
7506 if (!exp.to.hasPointers())
7507 exp.setNoderefOperand();
7508
7509 // When e1 is a template lambda, this cast may instantiate it with
7510 // the type 'to'.
7511 exp.e1 = inferType(exp.e1, exp.to);
7512 }
7513
7514 if (auto e = unaSemantic(exp, sc))
7515 {
7516 result = e;
7517 return;
7518 }
7519
Iain Buclaw7e7ebe32022-10-29 09:05:54 +02007520 if (exp.e1.type.isTypeNoreturn() && (!exp.to || !exp.to.isTypeNoreturn()))
7521 {
7522 result = exp.e1;
7523 return;
7524 }
Iain Buclawfbdaa582022-03-21 16:52:40 +01007525 if (exp.to && !exp.to.isTypeSArray() && !exp.to.isTypeFunction())
7526 exp.e1 = exp.e1.arrayFuncConv(sc);
7527
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02007528 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01007529 if (exp.e1.op == EXP.type)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02007530 exp.e1 = resolveAliasThis(sc, exp.e1);
7531
7532 auto e1x = resolveProperties(sc, exp.e1);
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01007533 if (e1x.op == EXP.error)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02007534 {
7535 result = e1x;
7536 return;
7537 }
7538 if (e1x.checkType())
7539 return setError();
7540 exp.e1 = e1x;
7541
7542 if (!exp.e1.type)
7543 {
7544 exp.error("cannot cast `%s`", exp.e1.toChars());
7545 return setError();
7546 }
7547
7548 // https://issues.dlang.org/show_bug.cgi?id=19954
7549 if (exp.e1.type.ty == Ttuple)
7550 {
Iain Buclawd7569182022-02-13 20:17:53 +01007551 if (exp.to)
7552 {
7553 if (TypeTuple tt = exp.to.isTypeTuple())
7554 {
7555 if (exp.e1.type.implicitConvTo(tt))
7556 {
7557 result = exp.e1.castTo(sc, tt);
7558 return;
7559 }
7560 }
7561 }
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02007562 TupleExp te = exp.e1.isTupleExp();
7563 if (te.exps.dim == 1)
7564 exp.e1 = (*te.exps)[0];
7565 }
7566
7567 // only allow S(x) rewrite if cast specified S explicitly.
7568 // See https://issues.dlang.org/show_bug.cgi?id=18545
7569 const bool allowImplicitConstruction = exp.to !is null;
7570
7571 if (!exp.to) // Handle cast(const) and cast(immutable), etc.
7572 {
7573 exp.to = exp.e1.type.castMod(exp.mod);
7574 exp.to = exp.to.typeSemantic(exp.loc, sc);
7575
7576 if (exp.to == Type.terror)
7577 return setError();
7578 }
7579
7580 if (exp.to.ty == Ttuple)
7581 {
Iain Buclawd7569182022-02-13 20:17:53 +01007582 exp.error("cannot cast `%s` of type `%s` to tuple type `%s`", exp.e1.toChars(), exp.e1.type.toChars(), exp.to.toChars());
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02007583 return setError();
7584 }
7585
7586 // cast(void) is used to mark e1 as unused, so it is safe
7587 if (exp.to.ty == Tvoid)
7588 {
7589 exp.type = exp.to;
7590 result = exp;
7591 return;
7592 }
7593
7594 if (!exp.to.equals(exp.e1.type) && exp.mod == cast(ubyte)~0)
7595 {
7596 if (Expression e = exp.op_overload(sc))
7597 {
7598 result = e.implicitCastTo(sc, exp.to);
7599 return;
7600 }
7601 }
7602
7603 Type t1b = exp.e1.type.toBasetype();
7604 Type tob = exp.to.toBasetype();
7605
7606 if (allowImplicitConstruction && tob.ty == Tstruct && !tob.equals(t1b))
7607 {
7608 /* Look to replace:
7609 * cast(S)t
7610 * with:
7611 * S(t)
7612 */
7613
7614 // Rewrite as to.call(e1)
7615 Expression e = new TypeExp(exp.loc, exp.to);
7616 e = new CallExp(exp.loc, e, exp.e1);
7617 e = e.trySemantic(sc);
7618 if (e)
7619 {
7620 result = e;
7621 return;
7622 }
7623 }
7624
7625 if (!t1b.equals(tob) && (t1b.ty == Tarray || t1b.ty == Tsarray))
7626 {
7627 if (checkNonAssignmentArrayOp(exp.e1))
7628 return setError();
7629 }
7630
7631 // Look for casting to a vector type
7632 if (tob.ty == Tvector && t1b.ty != Tvector)
7633 {
7634 result = new VectorExp(exp.loc, exp.e1, exp.to);
7635 result = result.expressionSemantic(sc);
7636 return;
7637 }
7638
7639 Expression ex = exp.e1.castTo(sc, exp.to);
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01007640 if (ex.op == EXP.error)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02007641 {
7642 result = ex;
7643 return;
7644 }
7645
7646 // Check for unsafe casts
Iain Buclawb6df1132022-07-26 17:42:23 +02007647 if (!isSafeCast(ex, t1b, tob))
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02007648 {
Iain Buclawb6df1132022-07-26 17:42:23 +02007649 // This is an ad-hoc fix for https://issues.dlang.org/show_bug.cgi?id=19646
7650 // Should be replaced by a more general @system variables implementation
7651 if (!sc.func && sc.stc & STC.safe)
7652 {
7653 exp.error("cast from `%s` to `%s` not allowed in safe code", exp.e1.type.toChars(), exp.to.toChars());
7654 return setError();
7655 }
7656
7657 if (sc.setUnsafe(false, exp.loc, "cast from `%s` to `%s` not allowed in safe code", exp.e1.type, exp.to))
7658 {
7659 return setError();
7660 }
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02007661 }
7662
7663 // `object.__ArrayCast` is a rewrite of an old runtime hook `_d_arraycast`. `_d_arraycast` was not built
7664 // to handle certain casts. Those casts which `object.__ArrayCast` does not support are filtered out.
7665 // See `e2ir.toElemCast` for other types of casts. If `object.__ArrayCast` is improved to support more
7666 // casts these conditions and potentially some logic in `e2ir.toElemCast` can be removed.
7667 if (tob.ty == Tarray)
7668 {
7669 // https://issues.dlang.org/show_bug.cgi?id=19840
7670 if (auto ad = isAggregate(t1b))
7671 {
7672 if (ad.aliasthis)
7673 {
7674 Expression e = resolveAliasThis(sc, exp.e1);
7675 e = new CastExp(exp.loc, e, exp.to);
7676 result = e.expressionSemantic(sc);
7677 return;
7678 }
7679 }
7680
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01007681 if(t1b.ty == Tarray && exp.e1.op != EXP.arrayLiteral && (sc.flags & SCOPE.ctfe) == 0)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02007682 {
7683 auto tFrom = t1b.nextOf();
7684 auto tTo = tob.nextOf();
7685
7686 // https://issues.dlang.org/show_bug.cgi?id=20130
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01007687 if (exp.e1.op != EXP.string_ || !ex.isStringExp)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02007688 {
7689 const uint fromSize = cast(uint)tFrom.size();
7690 const uint toSize = cast(uint)tTo.size();
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01007691 if (fromSize == SIZE_INVALID || toSize == SIZE_INVALID)
7692 return setError();
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02007693
7694 // If array element sizes do not match, we must adjust the dimensions
7695 if (fromSize != toSize)
7696 {
7697 if (!verifyHookExist(exp.loc, *sc, Id.__ArrayCast, "casting array of structs"))
7698 return setError();
7699
7700 // A runtime check is needed in case arrays don't line up. That check should
7701 // be done in the implementation of `object.__ArrayCast`
7702 if (toSize == 0 || (fromSize % toSize) != 0)
7703 {
7704 // lower to `object.__ArrayCast!(TFrom, TTo)(from)`
7705
7706 // fully qualify as `object.__ArrayCast`
7707 Expression id = new IdentifierExp(exp.loc, Id.empty);
7708 auto dotid = new DotIdExp(exp.loc, id, Id.object);
7709
7710 auto tiargs = new Objects();
7711 tiargs.push(tFrom);
7712 tiargs.push(tTo);
7713 auto dt = new DotTemplateInstanceExp(exp.loc, dotid, Id.__ArrayCast, tiargs);
7714
7715 auto arguments = new Expressions();
7716 arguments.push(exp.e1);
7717 Expression ce = new CallExp(exp.loc, dt, arguments);
7718
7719 result = expressionSemantic(ce, sc);
7720 return;
7721 }
7722 }
7723 }
7724 }
7725 }
7726
7727 if (sc && sc.flags & SCOPE.Cfile)
7728 {
7729 /* C11 6.5.4-5: A cast does not yield an lvalue.
7730 * So ensure that castTo does not strip away the cast so that this
7731 * can be enforced in other semantic visitor methods.
7732 */
7733 if (!ex.isCastExp())
7734 {
7735 ex = new CastExp(exp.loc, ex, exp.to);
7736 ex.type = exp.to;
7737 }
7738 }
7739 result = ex;
7740 }
7741
7742 override void visit(VectorExp exp)
7743 {
7744 static if (LOGSEMANTIC)
7745 {
7746 printf("VectorExp::semantic('%s')\n", exp.toChars());
7747 }
7748 if (exp.type)
7749 {
7750 result = exp;
7751 return;
7752 }
7753
7754 exp.e1 = exp.e1.expressionSemantic(sc);
7755 exp.type = exp.to.typeSemantic(exp.loc, sc);
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01007756 if (exp.e1.op == EXP.error || exp.type.ty == Terror)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02007757 {
7758 result = exp.e1;
7759 return;
7760 }
7761
7762 Type tb = exp.type.toBasetype();
7763 assert(tb.ty == Tvector);
7764 TypeVector tv = cast(TypeVector)tb;
7765 Type te = tv.elementType();
7766 exp.dim = cast(int)(tv.size(exp.loc) / te.size(exp.loc));
7767
7768 bool checkElem(Expression elem)
7769 {
7770 if (elem.isConst() == 1)
7771 return false;
7772
7773 exp.error("constant expression expected, not `%s`", elem.toChars());
7774 return true;
7775 }
7776
7777 exp.e1 = exp.e1.optimize(WANTvalue);
7778 bool res;
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01007779 if (exp.e1.op == EXP.arrayLiteral)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02007780 {
7781 foreach (i; 0 .. exp.dim)
7782 {
7783 // Do not stop on first error - check all AST nodes even if error found
7784 res |= checkElem(exp.e1.isArrayLiteralExp()[i]);
7785 }
7786 }
7787 else if (exp.e1.type.ty == Tvoid)
7788 checkElem(exp.e1);
7789
7790 result = res ? ErrorExp.get() : exp;
7791 }
7792
7793 override void visit(VectorArrayExp e)
7794 {
7795 static if (LOGSEMANTIC)
7796 {
7797 printf("VectorArrayExp::semantic('%s')\n", e.toChars());
7798 }
7799 if (!e.type)
7800 {
7801 unaSemantic(e, sc);
7802 e.e1 = resolveProperties(sc, e.e1);
7803
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01007804 if (e.e1.op == EXP.error)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02007805 {
7806 result = e.e1;
7807 return;
7808 }
7809 assert(e.e1.type.ty == Tvector);
7810 e.type = e.e1.type.isTypeVector().basetype;
7811 }
7812 result = e;
7813 }
7814
7815 override void visit(SliceExp exp)
7816 {
7817 static if (LOGSEMANTIC)
7818 {
7819 printf("SliceExp::semantic('%s')\n", exp.toChars());
7820 }
7821 if (exp.type)
7822 {
7823 result = exp;
7824 return;
7825 }
7826
7827 // operator overloading should be handled in ArrayExp already.
7828 if (Expression ex = unaSemantic(exp, sc))
7829 {
7830 result = ex;
7831 return;
7832 }
7833 exp.e1 = resolveProperties(sc, exp.e1);
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01007834 if (exp.e1.op == EXP.type && exp.e1.type.ty != Ttuple)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02007835 {
7836 if (exp.lwr || exp.upr)
7837 {
7838 exp.error("cannot slice type `%s`", exp.e1.toChars());
7839 return setError();
7840 }
7841 Expression e = new TypeExp(exp.loc, exp.e1.type.arrayOf());
7842 result = e.expressionSemantic(sc);
7843 return;
7844 }
7845 if (!exp.lwr && !exp.upr)
7846 {
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01007847 if (exp.e1.op == EXP.arrayLiteral)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02007848 {
7849 // Convert [a,b,c][] to [a,b,c]
7850 Type t1b = exp.e1.type.toBasetype();
7851 Expression e = exp.e1;
7852 if (t1b.ty == Tsarray)
7853 {
7854 e = e.copy();
7855 e.type = t1b.nextOf().arrayOf();
7856 }
7857 result = e;
7858 return;
7859 }
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01007860 if (exp.e1.op == EXP.slice)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02007861 {
7862 // Convert e[][] to e[]
7863 SliceExp se = cast(SliceExp)exp.e1;
7864 if (!se.lwr && !se.upr)
7865 {
7866 result = se;
7867 return;
7868 }
7869 }
7870 if (isArrayOpOperand(exp.e1))
7871 {
7872 // Convert (a[]+b[])[] to a[]+b[]
7873 result = exp.e1;
7874 return;
7875 }
7876 }
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01007877 if (exp.e1.op == EXP.error)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02007878 {
7879 result = exp.e1;
7880 return;
7881 }
7882 if (exp.e1.type.ty == Terror)
7883 return setError();
7884
7885 Type t1b = exp.e1.type.toBasetype();
Iain Buclaw7e287502022-03-13 12:28:05 +01007886 if (auto tp = t1b.isTypePointer())
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02007887 {
7888 if (t1b.isPtrToFunction())
7889 {
7890 exp.error("cannot slice function pointer `%s`", exp.e1.toChars());
7891 return setError();
7892 }
7893 if (!exp.lwr || !exp.upr)
7894 {
Iain Buclaw7e287502022-03-13 12:28:05 +01007895 exp.error("upper and lower bounds are needed to slice a pointer");
7896 if (auto ad = isAggregate(tp.next.toBasetype()))
7897 {
7898 auto s = search_function(ad, Id.index);
7899 if (!s) s = search_function(ad, Id.slice);
7900 if (s)
7901 {
7902 auto fd = s.isFuncDeclaration();
7903 if ((fd && !fd.getParameterList().length) || s.isTemplateDeclaration())
7904 {
7905 exp.errorSupplemental(
7906 "pointer `%s` points to an aggregate that defines an `%s`, perhaps you meant `(*%s)[]`",
7907 exp.e1.toChars(),
7908 s.ident.toChars(),
7909 exp.e1.toChars()
7910 );
7911 }
7912
7913 }
7914 }
7915
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02007916 return setError();
7917 }
Iain Buclaw610d7892022-05-27 19:36:06 +02007918 if (sc.setUnsafe(false, exp.loc, "pointer slicing not allowed in safe functions"))
7919 return setError();
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02007920 }
7921 else if (t1b.ty == Tarray)
7922 {
7923 }
7924 else if (t1b.ty == Tsarray)
7925 {
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02007926 }
7927 else if (t1b.ty == Ttuple)
7928 {
7929 if (!exp.lwr && !exp.upr)
7930 {
7931 result = exp.e1;
7932 return;
7933 }
7934 if (!exp.lwr || !exp.upr)
7935 {
7936 exp.error("need upper and lower bound to slice tuple");
7937 return setError();
7938 }
7939 }
Iain Buclaw7e7ebe32022-10-29 09:05:54 +02007940 else if (t1b.ty == Tvector && exp.e1.isLvalue())
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02007941 {
7942 // Convert e1 to corresponding static array
7943 TypeVector tv1 = cast(TypeVector)t1b;
7944 t1b = tv1.basetype;
7945 t1b = t1b.castMod(tv1.mod);
7946 exp.e1.type = t1b;
7947 }
7948 else
7949 {
7950 exp.error("`%s` cannot be sliced with `[]`", t1b.ty == Tvoid ? exp.e1.toChars() : t1b.toChars());
7951 return setError();
7952 }
7953
7954 /* Run semantic on lwr and upr.
7955 */
7956 Scope* scx = sc;
7957 if (t1b.ty == Tsarray || t1b.ty == Tarray || t1b.ty == Ttuple)
7958 {
7959 // Create scope for 'length' variable
7960 ScopeDsymbol sym = new ArrayScopeSymbol(sc, exp);
7961 sym.parent = sc.scopesym;
7962 sc = sc.push(sym);
7963 }
7964 if (exp.lwr)
7965 {
7966 if (t1b.ty == Ttuple)
7967 sc = sc.startCTFE();
7968 exp.lwr = exp.lwr.expressionSemantic(sc);
7969 exp.lwr = resolveProperties(sc, exp.lwr);
7970 if (t1b.ty == Ttuple)
7971 sc = sc.endCTFE();
7972 exp.lwr = exp.lwr.implicitCastTo(sc, Type.tsize_t);
7973 }
7974 if (exp.upr)
7975 {
7976 if (t1b.ty == Ttuple)
7977 sc = sc.startCTFE();
7978 exp.upr = exp.upr.expressionSemantic(sc);
7979 exp.upr = resolveProperties(sc, exp.upr);
7980 if (t1b.ty == Ttuple)
7981 sc = sc.endCTFE();
7982 exp.upr = exp.upr.implicitCastTo(sc, Type.tsize_t);
7983 }
7984 if (sc != scx)
7985 sc = sc.pop();
7986 if (exp.lwr && exp.lwr.type == Type.terror || exp.upr && exp.upr.type == Type.terror)
7987 return setError();
7988
7989 if (t1b.ty == Ttuple)
7990 {
7991 exp.lwr = exp.lwr.ctfeInterpret();
7992 exp.upr = exp.upr.ctfeInterpret();
7993 uinteger_t i1 = exp.lwr.toUInteger();
7994 uinteger_t i2 = exp.upr.toUInteger();
7995
7996 TupleExp te;
7997 TypeTuple tup;
7998 size_t length;
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01007999 if (exp.e1.op == EXP.tuple) // slicing an expression tuple
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02008000 {
8001 te = cast(TupleExp)exp.e1;
8002 tup = null;
8003 length = te.exps.dim;
8004 }
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01008005 else if (exp.e1.op == EXP.type) // slicing a type tuple
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02008006 {
8007 te = null;
8008 tup = cast(TypeTuple)t1b;
8009 length = Parameter.dim(tup.arguments);
8010 }
8011 else
8012 assert(0);
8013
8014 if (i2 < i1 || length < i2)
8015 {
8016 exp.error("string slice `[%llu .. %llu]` is out of bounds", i1, i2);
8017 return setError();
8018 }
8019
8020 size_t j1 = cast(size_t)i1;
8021 size_t j2 = cast(size_t)i2;
8022 Expression e;
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01008023 if (exp.e1.op == EXP.tuple)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02008024 {
8025 auto exps = new Expressions(j2 - j1);
8026 for (size_t i = 0; i < j2 - j1; i++)
8027 {
8028 (*exps)[i] = (*te.exps)[j1 + i];
8029 }
8030 e = new TupleExp(exp.loc, te.e0, exps);
8031 }
8032 else
8033 {
8034 auto args = new Parameters();
8035 args.reserve(j2 - j1);
8036 for (size_t i = j1; i < j2; i++)
8037 {
8038 Parameter arg = Parameter.getNth(tup.arguments, i);
8039 args.push(arg);
8040 }
8041 e = new TypeExp(exp.e1.loc, new TypeTuple(args));
8042 }
8043 e = e.expressionSemantic(sc);
8044 result = e;
8045 return;
8046 }
8047
8048 exp.type = t1b.nextOf().arrayOf();
8049 // Allow typedef[] -> typedef[]
8050 if (exp.type.equals(t1b))
8051 exp.type = exp.e1.type;
8052
8053 // We might know $ now
8054 setLengthVarIfKnown(exp.lengthVar, t1b);
8055
8056 if (exp.lwr && exp.upr)
8057 {
8058 exp.lwr = exp.lwr.optimize(WANTvalue);
8059 exp.upr = exp.upr.optimize(WANTvalue);
8060
8061 IntRange lwrRange = getIntRange(exp.lwr);
8062 IntRange uprRange = getIntRange(exp.upr);
8063
8064 if (t1b.ty == Tsarray || t1b.ty == Tarray)
8065 {
8066 Expression el = new ArrayLengthExp(exp.loc, exp.e1);
8067 el = el.expressionSemantic(sc);
8068 el = el.optimize(WANTvalue);
Iain Buclawd7569182022-02-13 20:17:53 +01008069 if (el.op == EXP.int64 && t1b.ty == Tsarray)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02008070 {
8071 // Array length is known at compile-time. Upper is in bounds if it fits length.
8072 dinteger_t length = el.toInteger();
8073 auto bounds = IntRange(SignExtendedNumber(0), SignExtendedNumber(length));
8074 exp.upperIsInBounds = bounds.contains(uprRange);
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01008075 if (exp.lwr.op == EXP.int64 && exp.upr.op == EXP.int64 && exp.lwr.toInteger() > exp.upr.toInteger())
Iain Buclaw0fb57032021-12-05 17:11:12 +01008076 {
8077 exp.error("in slice `%s[%llu .. %llu]`, lower bound is greater than upper bound", exp.e1.toChars, exp.lwr.toInteger(), exp.upr.toInteger());
8078 return setError();
8079 }
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01008080 if (exp.upr.op == EXP.int64 && exp.upr.toInteger() > length)
Iain Buclaw0fb57032021-12-05 17:11:12 +01008081 {
8082 exp.error("in slice `%s[%llu .. %llu]`, upper bound is greater than array length `%llu`", exp.e1.toChars, exp.lwr.toInteger(), exp.upr.toInteger(), length);
8083 return setError();
8084 }
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02008085 }
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01008086 else if (exp.upr.op == EXP.int64 && exp.upr.toInteger() == 0)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02008087 {
8088 // Upper slice expression is '0'. Value is always in bounds.
8089 exp.upperIsInBounds = true;
8090 }
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01008091 else if (exp.upr.op == EXP.variable && (cast(VarExp)exp.upr).var.ident == Id.dollar)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02008092 {
8093 // Upper slice expression is '$'. Value is always in bounds.
8094 exp.upperIsInBounds = true;
8095 }
8096 }
8097 else if (t1b.ty == Tpointer)
8098 {
8099 exp.upperIsInBounds = true;
8100 }
8101 else
8102 assert(0);
8103
8104 exp.lowerIsLessThanUpper = (lwrRange.imax <= uprRange.imin);
8105
8106 //printf("upperIsInBounds = %d lowerIsLessThanUpper = %d\n", exp.upperIsInBounds, exp.lowerIsLessThanUpper);
8107 }
8108
8109 result = exp;
8110 }
8111
8112 override void visit(ArrayLengthExp e)
8113 {
8114 static if (LOGSEMANTIC)
8115 {
8116 printf("ArrayLengthExp::semantic('%s')\n", e.toChars());
8117 }
8118 if (e.type)
8119 {
8120 result = e;
8121 return;
8122 }
8123
8124 if (Expression ex = unaSemantic(e, sc))
8125 {
8126 result = ex;
8127 return;
8128 }
8129 e.e1 = resolveProperties(sc, e.e1);
8130
8131 e.type = Type.tsize_t;
8132 result = e;
8133 }
8134
8135 override void visit(ArrayExp exp)
8136 {
8137 static if (LOGSEMANTIC)
8138 {
8139 printf("ArrayExp::semantic('%s')\n", exp.toChars());
8140 }
8141 assert(!exp.type);
Iain Buclaw0fb57032021-12-05 17:11:12 +01008142
Iain Buclawfd435682021-12-15 19:47:02 +01008143 if (sc.flags & SCOPE.Cfile)
8144 {
8145 /* See if need to rewrite the AST because of cast/call ambiguity
8146 */
8147 if (auto e = castCallAmbiguity(exp, sc))
8148 {
8149 result = expressionSemantic(e, sc);
8150 return;
8151 }
8152 }
8153
Iain Buclaw0fb57032021-12-05 17:11:12 +01008154 result = exp.carraySemantic(sc); // C semantics
8155 if (result)
8156 return;
8157
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02008158 Expression e = exp.op_overload(sc);
8159 if (e)
8160 {
8161 result = e;
8162 return;
8163 }
8164
8165 if (isAggregate(exp.e1.type))
8166 exp.error("no `[]` operator overload for type `%s`", exp.e1.type.toChars());
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01008167 else if (exp.e1.op == EXP.type && exp.e1.type.ty != Ttuple)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02008168 exp.error("static array of `%s` with multiple lengths not allowed", exp.e1.type.toChars());
8169 else if (isIndexableNonAggregate(exp.e1.type))
8170 exp.error("only one index allowed to index `%s`", exp.e1.type.toChars());
8171 else
8172 exp.error("cannot use `[]` operator on expression of type `%s`", exp.e1.type.toChars());
8173
8174 result = ErrorExp.get();
8175 }
8176
8177 override void visit(DotExp exp)
8178 {
8179 static if (LOGSEMANTIC)
8180 {
8181 printf("DotExp::semantic('%s')\n", exp.toChars());
8182 if (exp.type)
8183 printf("\ttype = %s\n", exp.type.toChars());
8184 }
8185 exp.e1 = exp.e1.expressionSemantic(sc);
8186 exp.e2 = exp.e2.expressionSemantic(sc);
8187
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01008188 if (exp.e1.op == EXP.type)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02008189 {
8190 result = exp.e2;
8191 return;
8192 }
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01008193 if (exp.e2.op == EXP.type)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02008194 {
8195 result = exp.e2;
8196 return;
8197 }
Iain Buclaw235d5a92022-03-29 16:57:10 +02008198 if (auto te = exp.e2.isTemplateExp())
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02008199 {
Iain Buclaw235d5a92022-03-29 16:57:10 +02008200 Expression e = new DotTemplateExp(exp.loc, exp.e1, te.td);
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02008201 result = e.expressionSemantic(sc);
8202 return;
8203 }
8204 if (!exp.type)
8205 exp.type = exp.e2.type;
8206 result = exp;
8207 }
8208
8209 override void visit(CommaExp e)
8210 {
Iain Buclaw0fb57032021-12-05 17:11:12 +01008211 //printf("Semantic.CommaExp() %s\n", e.toChars());
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02008212 if (e.type)
8213 {
8214 result = e;
8215 return;
8216 }
8217
8218 // Allow `((a,b),(x,y))`
8219 if (e.allowCommaExp)
8220 {
8221 CommaExp.allow(e.e1);
8222 CommaExp.allow(e.e2);
8223 }
8224
8225 if (Expression ex = binSemanticProp(e, sc))
8226 {
8227 result = ex;
8228 return;
8229 }
8230 e.e1 = e.e1.addDtorHook(sc);
8231
8232 if (checkNonAssignmentArrayOp(e.e1))
8233 return setError();
8234
Iain Buclaw0fb57032021-12-05 17:11:12 +01008235 // Comma expressions trigger this conversion
8236 e.e2 = e.e2.arrayFuncConv(sc);
8237
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02008238 e.type = e.e2.type;
Iain Buclaw235d5a92022-03-29 16:57:10 +02008239 result = e;
8240
8241 if (sc.flags & SCOPE.Cfile)
8242 return;
8243
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02008244 if (e.type is Type.tvoid)
Iain Buclaw31350632022-04-13 13:34:49 +01008245 {
8246 checkMustUse(e.e1, sc);
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02008247 discardValue(e.e1);
Iain Buclaw31350632022-04-13 13:34:49 +01008248 }
Iain Buclaw235d5a92022-03-29 16:57:10 +02008249 else if (!e.allowCommaExp && !e.isGenerated)
Iain Buclaw5eb99272022-05-16 18:30:46 +02008250 e.error("using the result of a comma expression is not allowed");
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02008251 }
8252
8253 override void visit(IntervalExp e)
8254 {
8255 static if (LOGSEMANTIC)
8256 {
8257 printf("IntervalExp::semantic('%s')\n", e.toChars());
8258 }
8259 if (e.type)
8260 {
8261 result = e;
8262 return;
8263 }
8264
8265 Expression le = e.lwr;
8266 le = le.expressionSemantic(sc);
8267 le = resolveProperties(sc, le);
8268
8269 Expression ue = e.upr;
8270 ue = ue.expressionSemantic(sc);
8271 ue = resolveProperties(sc, ue);
8272
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01008273 if (le.op == EXP.error)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02008274 {
8275 result = le;
8276 return;
8277 }
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01008278 if (ue.op == EXP.error)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02008279 {
8280 result = ue;
8281 return;
8282 }
8283
8284 e.lwr = le;
8285 e.upr = ue;
8286
8287 e.type = Type.tvoid;
8288 result = e;
8289 }
8290
8291 override void visit(DelegatePtrExp e)
8292 {
8293 static if (LOGSEMANTIC)
8294 {
8295 printf("DelegatePtrExp::semantic('%s')\n", e.toChars());
8296 }
8297 if (!e.type)
8298 {
8299 unaSemantic(e, sc);
8300 e.e1 = resolveProperties(sc, e.e1);
8301
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01008302 if (e.e1.op == EXP.error)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02008303 {
8304 result = e.e1;
8305 return;
8306 }
8307 e.type = Type.tvoidptr;
8308 }
8309 result = e;
8310 }
8311
8312 override void visit(DelegateFuncptrExp e)
8313 {
8314 static if (LOGSEMANTIC)
8315 {
8316 printf("DelegateFuncptrExp::semantic('%s')\n", e.toChars());
8317 }
8318 if (!e.type)
8319 {
8320 unaSemantic(e, sc);
8321 e.e1 = resolveProperties(sc, e.e1);
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01008322 if (e.e1.op == EXP.error)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02008323 {
8324 result = e.e1;
8325 return;
8326 }
8327 e.type = e.e1.type.nextOf().pointerTo();
8328 }
8329 result = e;
8330 }
8331
8332 override void visit(IndexExp exp)
8333 {
8334 static if (LOGSEMANTIC)
8335 {
8336 printf("IndexExp::semantic('%s')\n", exp.toChars());
8337 }
8338 if (exp.type)
8339 {
8340 result = exp;
8341 return;
8342 }
8343
8344 // operator overloading should be handled in ArrayExp already.
8345 if (!exp.e1.type)
Iain Buclaw0fb57032021-12-05 17:11:12 +01008346 exp.e1 = exp.e1.expressionSemantic(sc).arrayFuncConv(sc);
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02008347 assert(exp.e1.type); // semantic() should already be run on it
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01008348 if (exp.e1.op == EXP.type && exp.e1.type.ty != Ttuple)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02008349 {
8350 exp.e2 = exp.e2.expressionSemantic(sc);
8351 exp.e2 = resolveProperties(sc, exp.e2);
8352 Type nt;
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01008353 if (exp.e2.op == EXP.type)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02008354 nt = new TypeAArray(exp.e1.type, exp.e2.type);
8355 else
8356 nt = new TypeSArray(exp.e1.type, exp.e2);
8357 Expression e = new TypeExp(exp.loc, nt);
8358 result = e.expressionSemantic(sc);
8359 return;
8360 }
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01008361 if (exp.e1.op == EXP.error)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02008362 {
8363 result = exp.e1;
8364 return;
8365 }
8366 if (exp.e1.type.ty == Terror)
8367 return setError();
8368
8369 // Note that unlike C we do not implement the int[ptr]
8370
8371 Type t1b = exp.e1.type.toBasetype();
8372
8373 if (t1b.ty == Tvector)
8374 {
8375 // Convert e1 to corresponding static array
8376 TypeVector tv1 = cast(TypeVector)t1b;
8377 t1b = tv1.basetype;
8378 t1b = t1b.castMod(tv1.mod);
8379 exp.e1.type = t1b;
8380 }
Iain Buclawd97f3bc2022-06-24 19:41:41 +02008381 if (t1b.ty == Tsarray || t1b.ty == Tarray)
8382 {
8383 if (!checkAddressable(exp, sc))
8384 return setError();
8385 }
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02008386
8387 /* Run semantic on e2
8388 */
8389 Scope* scx = sc;
8390 if (t1b.ty == Tsarray || t1b.ty == Tarray || t1b.ty == Ttuple)
8391 {
8392 // Create scope for 'length' variable
8393 ScopeDsymbol sym = new ArrayScopeSymbol(sc, exp);
8394 sym.parent = sc.scopesym;
8395 sc = sc.push(sym);
8396 }
8397 if (t1b.ty == Ttuple)
8398 sc = sc.startCTFE();
Iain Buclaw0fb57032021-12-05 17:11:12 +01008399 exp.e2 = exp.e2.expressionSemantic(sc).arrayFuncConv(sc);
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02008400 exp.e2 = resolveProperties(sc, exp.e2);
8401 if (t1b.ty == Ttuple)
8402 sc = sc.endCTFE();
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01008403 if (exp.e2.op == EXP.tuple)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02008404 {
8405 TupleExp te = cast(TupleExp)exp.e2;
8406 if (te.exps && te.exps.dim == 1)
8407 exp.e2 = Expression.combine(te.e0, (*te.exps)[0]); // bug 4444 fix
8408 }
8409 if (sc != scx)
8410 sc = sc.pop();
8411 if (exp.e2.type == Type.terror)
8412 return setError();
8413
8414 if (checkNonAssignmentArrayOp(exp.e1))
8415 return setError();
8416
8417 switch (t1b.ty)
8418 {
8419 case Tpointer:
8420 if (t1b.isPtrToFunction())
8421 {
8422 exp.error("cannot index function pointer `%s`", exp.e1.toChars());
8423 return setError();
8424 }
8425 exp.e2 = exp.e2.implicitCastTo(sc, Type.tsize_t);
8426 if (exp.e2.type == Type.terror)
8427 return setError();
8428 exp.e2 = exp.e2.optimize(WANTvalue);
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01008429 if (exp.e2.op == EXP.int64 && exp.e2.toInteger() == 0)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02008430 {
8431 }
Iain Buclaw610d7892022-05-27 19:36:06 +02008432 else if (sc.setUnsafe(false, exp.loc, "`@safe` function `%s` cannot index pointer `%s`", sc.func, exp.e1))
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02008433 {
Iain Buclaw610d7892022-05-27 19:36:06 +02008434 return setError();
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02008435 }
8436 exp.type = (cast(TypeNext)t1b).next;
8437 break;
8438
8439 case Tarray:
8440 exp.e2 = exp.e2.implicitCastTo(sc, Type.tsize_t);
8441 if (exp.e2.type == Type.terror)
8442 return setError();
8443 exp.type = (cast(TypeNext)t1b).next;
8444 break;
8445
8446 case Tsarray:
8447 {
8448 exp.e2 = exp.e2.implicitCastTo(sc, Type.tsize_t);
8449 if (exp.e2.type == Type.terror)
8450 return setError();
8451 exp.type = t1b.nextOf();
8452 break;
8453 }
8454 case Taarray:
8455 {
8456 TypeAArray taa = cast(TypeAArray)t1b;
8457 /* We can skip the implicit conversion if they differ only by
8458 * constness
8459 * https://issues.dlang.org/show_bug.cgi?id=2684
8460 * see also bug https://issues.dlang.org/show_bug.cgi?id=2954 b
8461 */
8462 if (!arrayTypeCompatibleWithoutCasting(exp.e2.type, taa.index))
8463 {
8464 exp.e2 = exp.e2.implicitCastTo(sc, taa.index); // type checking
8465 if (exp.e2.type == Type.terror)
8466 return setError();
8467 }
8468
8469 semanticTypeInfo(sc, taa);
8470
8471 exp.type = taa.next;
8472 break;
8473 }
8474 case Ttuple:
8475 {
8476 exp.e2 = exp.e2.implicitCastTo(sc, Type.tsize_t);
8477 if (exp.e2.type == Type.terror)
8478 return setError();
8479
8480 exp.e2 = exp.e2.ctfeInterpret();
8481 uinteger_t index = exp.e2.toUInteger();
8482
8483 TupleExp te;
8484 TypeTuple tup;
8485 size_t length;
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01008486 if (exp.e1.op == EXP.tuple)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02008487 {
8488 te = cast(TupleExp)exp.e1;
8489 tup = null;
8490 length = te.exps.dim;
8491 }
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01008492 else if (exp.e1.op == EXP.type)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02008493 {
8494 te = null;
8495 tup = cast(TypeTuple)t1b;
8496 length = Parameter.dim(tup.arguments);
8497 }
8498 else
8499 assert(0);
8500
8501 if (length <= index)
8502 {
8503 exp.error("array index `[%llu]` is outside array bounds `[0 .. %llu]`", index, cast(ulong)length);
8504 return setError();
8505 }
8506 Expression e;
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01008507 if (exp.e1.op == EXP.tuple)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02008508 {
8509 e = (*te.exps)[cast(size_t)index];
8510 e = Expression.combine(te.e0, e);
8511 }
8512 else
8513 e = new TypeExp(exp.e1.loc, Parameter.getNth(tup.arguments, cast(size_t)index).type);
8514 result = e;
8515 return;
8516 }
8517 default:
8518 exp.error("`%s` must be an array or pointer type, not `%s`", exp.e1.toChars(), exp.e1.type.toChars());
8519 return setError();
8520 }
8521
8522 // We might know $ now
8523 setLengthVarIfKnown(exp.lengthVar, t1b);
8524
8525 if (t1b.ty == Tsarray || t1b.ty == Tarray)
8526 {
8527 Expression el = new ArrayLengthExp(exp.loc, exp.e1);
8528 el = el.expressionSemantic(sc);
8529 el = el.optimize(WANTvalue);
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01008530 if (el.op == EXP.int64)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02008531 {
8532 exp.e2 = exp.e2.optimize(WANTvalue);
8533 dinteger_t length = el.toInteger();
8534 if (length)
8535 {
8536 auto bounds = IntRange(SignExtendedNumber(0), SignExtendedNumber(length - 1));
Iain Buclaw7e287502022-03-13 12:28:05 +01008537 // OR it in, because it might already be set for C array indexing
8538 exp.indexIsInBounds |= bounds.contains(getIntRange(exp.e2));
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02008539 }
Iain Buclaw235d5a92022-03-29 16:57:10 +02008540 else if (sc.flags & SCOPE.Cfile && t1b.ty == Tsarray)
8541 {
8542 if (auto ve = exp.e1.isVarExp())
8543 {
8544 /* Rewrite 0-length C array ve[exp.e2] as *(ve + exp.e2)
8545 */
8546 auto vp = ve.castTo(sc, t1b.isTypeSArray().next.pointerTo());
8547 auto e = new AddExp(exp.loc, vp, exp.e2);
8548 auto pe = new PtrExp(exp.loc, e);
8549 result = pe.expressionSemantic(sc).optimize(WANTvalue);
8550 return;
8551 }
8552 }
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02008553 }
8554 }
8555
8556 result = exp;
8557 }
8558
8559 override void visit(PostExp exp)
8560 {
8561 static if (LOGSEMANTIC)
8562 {
8563 printf("PostExp::semantic('%s')\n", exp.toChars());
8564 }
8565 if (exp.type)
8566 {
8567 result = exp;
8568 return;
8569 }
8570
Iain Buclawfd435682021-12-15 19:47:02 +01008571 if (sc.flags & SCOPE.Cfile)
8572 {
8573 /* See if need to rewrite the AST because of cast/call ambiguity
8574 */
8575 if (auto e = castCallAmbiguity(exp, sc))
8576 {
8577 result = expressionSemantic(e, sc);
8578 return;
8579 }
8580 }
8581
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02008582 if (Expression ex = binSemantic(exp, sc))
8583 {
8584 result = ex;
8585 return;
8586 }
8587 Expression e1x = resolveProperties(sc, exp.e1);
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01008588 if (e1x.op == EXP.error)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02008589 {
8590 result = e1x;
8591 return;
8592 }
8593 exp.e1 = e1x;
8594
8595 Expression e = exp.op_overload(sc);
8596 if (e)
8597 {
8598 result = e;
8599 return;
8600 }
8601
8602 if (exp.e1.checkReadModifyWrite(exp.op))
8603 return setError();
8604
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01008605 if (exp.e1.op == EXP.slice)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02008606 {
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01008607 const(char)* s = exp.op == EXP.plusPlus ? "increment" : "decrement";
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02008608 exp.error("cannot post-%s array slice `%s`, use pre-%s instead", s, exp.e1.toChars(), s);
8609 return setError();
8610 }
8611
8612 Type t1 = exp.e1.type.toBasetype();
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01008613 if (t1.ty == Tclass || t1.ty == Tstruct || exp.e1.op == EXP.arrayLength)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02008614 {
8615 /* Check for operator overloading,
8616 * but rewrite in terms of ++e instead of e++
8617 */
8618
8619 /* If e1 is not trivial, take a reference to it
8620 */
8621 Expression de = null;
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01008622 if (exp.e1.op != EXP.variable && exp.e1.op != EXP.arrayLength)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02008623 {
8624 // ref v = e1;
8625 auto v = copyToTemp(STC.ref_, "__postref", exp.e1);
8626 de = new DeclarationExp(exp.loc, v);
8627 exp.e1 = new VarExp(exp.e1.loc, v);
8628 }
8629
8630 /* Rewrite as:
8631 * auto tmp = e1; ++e1; tmp
8632 */
8633 auto tmp = copyToTemp(0, "__pitmp", exp.e1);
8634 Expression ea = new DeclarationExp(exp.loc, tmp);
8635
8636 Expression eb = exp.e1.syntaxCopy();
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01008637 eb = new PreExp(exp.op == EXP.plusPlus ? EXP.prePlusPlus : EXP.preMinusMinus, exp.loc, eb);
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02008638
8639 Expression ec = new VarExp(exp.loc, tmp);
8640
8641 // Combine de,ea,eb,ec
8642 if (de)
8643 ea = new CommaExp(exp.loc, de, ea);
8644 e = new CommaExp(exp.loc, ea, eb);
8645 e = new CommaExp(exp.loc, e, ec);
8646 e = e.expressionSemantic(sc);
8647 result = e;
8648 return;
8649 }
8650
8651 exp.e1 = exp.e1.modifiableLvalue(sc, exp.e1);
8652 exp.e1 = exp.e1.optimize(WANTvalue, /*keepLvalue*/ true);
8653
8654 e = exp;
8655 if (exp.e1.checkScalar() ||
8656 exp.e1.checkSharedAccess(sc))
8657 return setError();
8658 if (exp.e1.checkNoBool())
8659 return setError();
8660
8661 if (exp.e1.type.ty == Tpointer)
8662 e = scaleFactor(exp, sc);
8663 else
8664 exp.e2 = exp.e2.castTo(sc, exp.e1.type);
8665 e.type = exp.e1.type;
8666 result = e;
8667 }
8668
8669 override void visit(PreExp exp)
8670 {
8671 Expression e = exp.op_overload(sc);
8672 // printf("PreExp::semantic('%s')\n", toChars());
8673 if (e)
8674 {
8675 result = e;
8676 return;
8677 }
8678
8679 // Rewrite as e1+=1 or e1-=1
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01008680 if (exp.op == EXP.prePlusPlus)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02008681 e = new AddAssignExp(exp.loc, exp.e1, IntegerExp.literal!1);
8682 else
8683 e = new MinAssignExp(exp.loc, exp.e1, IntegerExp.literal!1);
8684 result = e.expressionSemantic(sc);
8685 }
8686
8687 /*
8688 * Get the expression initializer for a specific struct
8689 *
8690 * Params:
8691 * sd = the struct for which the expression initializer is needed
8692 * loc = the location of the initializer
8693 * sc = the scope where the expression is located
8694 * t = the type of the expression
8695 *
8696 * Returns:
8697 * The expression initializer or error expression if any errors occured
8698 */
8699 private Expression getInitExp(StructDeclaration sd, Loc loc, Scope* sc, Type t)
8700 {
8701 if (sd.zeroInit && !sd.isNested())
8702 {
8703 // https://issues.dlang.org/show_bug.cgi?id=14606
8704 // Always use BlitExp for the special expression: (struct = 0)
8705 return IntegerExp.literal!0;
8706 }
8707
8708 if (sd.isNested())
8709 {
8710 auto sle = new StructLiteralExp(loc, sd, null, t);
Iain Buclawc8dfa792022-09-27 10:43:32 +02008711 if (!sd.fill(loc, *sle.elements, true))
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02008712 return ErrorExp.get();
8713 if (checkFrameAccess(loc, sc, sd, sle.elements.dim))
8714 return ErrorExp.get();
8715
8716 sle.type = t;
8717 return sle;
8718 }
8719
8720 return t.defaultInit(loc);
8721 }
8722
8723 override void visit(AssignExp exp)
8724 {
8725 static if (LOGSEMANTIC)
8726 {
Iain Buclaw5eb99272022-05-16 18:30:46 +02008727 if (exp.op == EXP.blit) printf("BlitExp.toElem('%s')\n", exp.toChars());
8728 if (exp.op == EXP.assign) printf("AssignExp.toElem('%s')\n", exp.toChars());
8729 if (exp.op == EXP.construct) printf("ConstructExp.toElem('%s')\n", exp.toChars());
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02008730 }
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02008731
8732 void setResult(Expression e, int line = __LINE__)
8733 {
8734 //printf("line %d\n", line);
8735 result = e;
8736 }
8737
8738 if (exp.type)
8739 {
8740 return setResult(exp);
8741 }
8742
8743 Expression e1old = exp.e1;
8744
8745 if (auto e2comma = exp.e2.isCommaExp())
8746 {
Iain Buclaw0fb57032021-12-05 17:11:12 +01008747 if (!e2comma.isGenerated && !(sc.flags & SCOPE.Cfile))
Iain Buclaw5eb99272022-05-16 18:30:46 +02008748 exp.error("using the result of a comma expression is not allowed");
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02008749
8750 /* Rewrite to get rid of the comma from rvalue
8751 * e1=(e0,e2) => e0,(e1=e2)
8752 */
8753 Expression e0;
8754 exp.e2 = Expression.extractLast(e2comma, e0);
8755 Expression e = Expression.combine(e0, exp);
8756 return setResult(e.expressionSemantic(sc));
8757 }
8758
8759 /* Look for operator overloading of a[arguments] = e2.
8760 * Do it before e1.expressionSemantic() otherwise the ArrayExp will have been
8761 * converted to unary operator overloading already.
8762 */
8763 if (auto ae = exp.e1.isArrayExp())
8764 {
8765 Expression res;
8766
8767 ae.e1 = ae.e1.expressionSemantic(sc);
8768 ae.e1 = resolveProperties(sc, ae.e1);
8769 Expression ae1old = ae.e1;
8770
8771 const(bool) maybeSlice =
8772 (ae.arguments.dim == 0 ||
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01008773 ae.arguments.dim == 1 && (*ae.arguments)[0].op == EXP.interval);
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02008774
8775 IntervalExp ie = null;
8776 if (maybeSlice && ae.arguments.dim)
8777 {
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01008778 assert((*ae.arguments)[0].op == EXP.interval);
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02008779 ie = cast(IntervalExp)(*ae.arguments)[0];
8780 }
8781 while (true)
8782 {
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01008783 if (ae.e1.op == EXP.error)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02008784 return setResult(ae.e1);
8785
8786 Expression e0 = null;
8787 Expression ae1save = ae.e1;
8788 ae.lengthVar = null;
8789
8790 Type t1b = ae.e1.type.toBasetype();
8791 AggregateDeclaration ad = isAggregate(t1b);
8792 if (!ad)
8793 break;
8794 if (search_function(ad, Id.indexass))
8795 {
8796 // Deal with $
8797 res = resolveOpDollar(sc, ae, &e0);
8798 if (!res) // a[i..j] = e2 might be: a.opSliceAssign(e2, i, j)
8799 goto Lfallback;
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01008800 if (res.op == EXP.error)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02008801 return setResult(res);
8802
8803 res = exp.e2.expressionSemantic(sc);
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01008804 if (res.op == EXP.error)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02008805 return setResult(res);
8806 exp.e2 = res;
8807
8808 /* Rewrite (a[arguments] = e2) as:
8809 * a.opIndexAssign(e2, arguments)
8810 */
8811 Expressions* a = ae.arguments.copy();
8812 a.insert(0, exp.e2);
8813 res = new DotIdExp(exp.loc, ae.e1, Id.indexass);
8814 res = new CallExp(exp.loc, res, a);
8815 if (maybeSlice) // a[] = e2 might be: a.opSliceAssign(e2)
8816 res = res.trySemantic(sc);
8817 else
8818 res = res.expressionSemantic(sc);
8819 if (res)
8820 return setResult(Expression.combine(e0, res));
8821 }
8822
8823 Lfallback:
8824 if (maybeSlice && search_function(ad, Id.sliceass))
8825 {
8826 // Deal with $
8827 res = resolveOpDollar(sc, ae, ie, &e0);
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01008828 if (res.op == EXP.error)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02008829 return setResult(res);
8830
8831 res = exp.e2.expressionSemantic(sc);
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01008832 if (res.op == EXP.error)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02008833 return setResult(res);
8834
8835 exp.e2 = res;
8836
8837 /* Rewrite (a[i..j] = e2) as:
8838 * a.opSliceAssign(e2, i, j)
8839 */
8840 auto a = new Expressions();
8841 a.push(exp.e2);
8842 if (ie)
8843 {
8844 a.push(ie.lwr);
8845 a.push(ie.upr);
8846 }
8847 res = new DotIdExp(exp.loc, ae.e1, Id.sliceass);
8848 res = new CallExp(exp.loc, res, a);
8849 res = res.expressionSemantic(sc);
8850 return setResult(Expression.combine(e0, res));
8851 }
8852
8853 // No operator overloading member function found yet, but
8854 // there might be an alias this to try.
8855 if (ad.aliasthis && !isRecursiveAliasThis(ae.att1, ae.e1.type))
8856 {
8857 /* Rewrite (a[arguments] op e2) as:
8858 * a.aliasthis[arguments] op e2
8859 */
8860 ae.e1 = resolveAliasThis(sc, ae1save, true);
8861 if (ae.e1)
8862 continue;
8863 }
8864 break;
8865 }
8866 ae.e1 = ae1old; // recovery
8867 ae.lengthVar = null;
8868 }
8869
8870 /* Run this.e1 semantic.
8871 */
8872 {
8873 Expression e1x = exp.e1;
8874
8875 /* With UFCS, e.f = value
8876 * Could mean:
8877 * .f(e, value)
8878 * or:
8879 * .f(e) = value
8880 */
8881 if (auto dti = e1x.isDotTemplateInstanceExp())
8882 {
8883 Expression e = dti.semanticY(sc, 1);
8884 if (!e)
8885 {
8886 return setResult(resolveUFCSProperties(sc, e1x, exp.e2));
8887 }
8888
8889 e1x = e;
8890 }
Iain Buclaw0fb57032021-12-05 17:11:12 +01008891 else if (sc.flags & SCOPE.Cfile && e1x.isDotIdExp())
8892 {
8893 auto die = e1x.isDotIdExp();
8894 e1x = fieldLookup(die.e1, sc, die.ident);
8895 }
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02008896 else if (auto die = e1x.isDotIdExp())
8897 {
8898 Expression e = die.semanticY(sc, 1);
8899 if (e && isDotOpDispatch(e))
8900 {
8901 /* https://issues.dlang.org/show_bug.cgi?id=19687
8902 *
8903 * On this branch, e2 is semantically analyzed in resolvePropertiesX,
8904 * but that call is done with gagged errors. That is the only time when
8905 * semantic gets ran on e2, that is why the error never gets to be printed.
8906 * In order to make sure that UFCS is tried with correct parameters, e2
8907 * needs to have semantic ran on it.
8908 */
Iain Buclaw0fb57032021-12-05 17:11:12 +01008909 auto ode = e;
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02008910 exp.e2 = exp.e2.expressionSemantic(sc);
8911 uint errors = global.startGagging();
8912 e = resolvePropertiesX(sc, e, exp.e2);
Iain Buclaw0fb57032021-12-05 17:11:12 +01008913 // Any error or if 'e' is not resolved, go to UFCS
8914 if (global.endGagging(errors) || e is ode)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02008915 e = null; /* fall down to UFCS */
8916 else
8917 return setResult(e);
8918 }
8919 if (!e)
8920 return setResult(resolveUFCSProperties(sc, e1x, exp.e2));
8921 e1x = e;
8922 }
8923 else
8924 {
8925 if (auto se = e1x.isSliceExp())
8926 se.arrayop = true;
8927
8928 e1x = e1x.expressionSemantic(sc);
8929 }
8930
8931 /* We have f = value.
8932 * Could mean:
8933 * f(value)
8934 * or:
8935 * f() = value
8936 */
8937 if (Expression e = resolvePropertiesX(sc, e1x, exp.e2))
8938 return setResult(e);
8939
8940 if (e1x.checkRightThis(sc))
8941 {
8942 return setError();
8943 }
8944 exp.e1 = e1x;
8945 assert(exp.e1.type);
8946 }
Iain Buclaw7e7ebe32022-10-29 09:05:54 +02008947 Type t1 = exp.e1.type.isTypeEnum() ? exp.e1.type : exp.e1.type.toBasetype();
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02008948
8949 /* Run this.e2 semantic.
8950 * Different from other binary expressions, the analysis of e2
8951 * depends on the result of e1 in assignments.
8952 */
8953 {
8954 Expression e2x = inferType(exp.e2, t1.baseElemOf());
8955 e2x = e2x.expressionSemantic(sc);
Iain Buclaw0fb57032021-12-05 17:11:12 +01008956 if (!t1.isTypeSArray())
8957 e2x = e2x.arrayFuncConv(sc);
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02008958 e2x = resolveProperties(sc, e2x);
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01008959 if (e2x.op == EXP.type)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02008960 e2x = resolveAliasThis(sc, e2x); //https://issues.dlang.org/show_bug.cgi?id=17684
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01008961 if (e2x.op == EXP.error)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02008962 return setResult(e2x);
Iain Buclaw0fb57032021-12-05 17:11:12 +01008963 // We delay checking the value for structs/classes as these might have
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02008964 // an opAssign defined.
8965 if ((t1.ty != Tstruct && t1.ty != Tclass && e2x.checkValue()) ||
8966 e2x.checkSharedAccess(sc))
8967 return setError();
Iain Buclawb6df1132022-07-26 17:42:23 +02008968
Iain Buclaw7e7ebe32022-10-29 09:05:54 +02008969 auto etmp = checkNoreturnVarAccess(e2x);
8970 if (etmp != e2x)
8971 return setResult(etmp);
8972
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02008973 exp.e2 = e2x;
8974 }
8975
8976 /* Rewrite tuple assignment as a tuple of assignments.
8977 */
8978 {
8979 Expression e2x = exp.e2;
8980
8981 Ltupleassign:
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01008982 if (exp.e1.op == EXP.tuple && e2x.op == EXP.tuple)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02008983 {
8984 TupleExp tup1 = cast(TupleExp)exp.e1;
8985 TupleExp tup2 = cast(TupleExp)e2x;
8986 size_t dim = tup1.exps.dim;
8987 Expression e = null;
8988 if (dim != tup2.exps.dim)
8989 {
8990 exp.error("mismatched tuple lengths, %d and %d", cast(int)dim, cast(int)tup2.exps.dim);
8991 return setError();
8992 }
8993 if (dim == 0)
8994 {
8995 e = IntegerExp.literal!0;
8996 e = new CastExp(exp.loc, e, Type.tvoid); // avoid "has no effect" error
8997 e = Expression.combine(tup1.e0, tup2.e0, e);
8998 }
8999 else
9000 {
9001 auto exps = new Expressions(dim);
9002 for (size_t i = 0; i < dim; i++)
9003 {
9004 Expression ex1 = (*tup1.exps)[i];
9005 Expression ex2 = (*tup2.exps)[i];
9006 (*exps)[i] = new AssignExp(exp.loc, ex1, ex2);
9007 }
9008 e = new TupleExp(exp.loc, Expression.combine(tup1.e0, tup2.e0), exps);
9009 }
9010 return setResult(e.expressionSemantic(sc));
9011 }
9012
9013 /* Look for form: e1 = e2.aliasthis.
9014 */
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01009015 if (exp.e1.op == EXP.tuple)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02009016 {
9017 TupleDeclaration td = isAliasThisTuple(e2x);
9018 if (!td)
9019 goto Lnomatch;
9020
9021 assert(exp.e1.type.ty == Ttuple);
9022 TypeTuple tt = cast(TypeTuple)exp.e1.type;
9023
9024 Expression e0;
9025 Expression ev = extractSideEffect(sc, "__tup", e0, e2x);
9026
9027 auto iexps = new Expressions();
9028 iexps.push(ev);
9029 for (size_t u = 0; u < iexps.dim; u++)
9030 {
9031 Lexpand:
9032 Expression e = (*iexps)[u];
9033
9034 Parameter arg = Parameter.getNth(tt.arguments, u);
9035 //printf("[%d] iexps.dim = %d, ", u, iexps.dim);
Iain Buclaw31350632022-04-13 13:34:49 +01009036 //printf("e = (%s %s, %s), ", Token.toChars[e.op], e.toChars(), e.type.toChars());
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02009037 //printf("arg = (%s, %s)\n", arg.toChars(), arg.type.toChars());
9038
9039 if (!arg || !e.type.implicitConvTo(arg.type))
9040 {
9041 // expand initializer to tuple
9042 if (expandAliasThisTuples(iexps, u) != -1)
9043 {
9044 if (iexps.dim <= u)
9045 break;
9046 goto Lexpand;
9047 }
9048 goto Lnomatch;
9049 }
9050 }
9051 e2x = new TupleExp(e2x.loc, e0, iexps);
9052 e2x = e2x.expressionSemantic(sc);
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01009053 if (e2x.op == EXP.error)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02009054 {
9055 result = e2x;
9056 return;
9057 }
9058 // Do not need to overwrite this.e2
9059 goto Ltupleassign;
9060 }
9061 Lnomatch:
9062 }
9063
9064 /* Inside constructor, if this is the first assignment of object field,
9065 * rewrite this to initializing the field.
9066 */
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01009067 if (exp.op == EXP.assign
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02009068 && exp.e1.checkModifiable(sc) == Modifiable.initialization)
9069 {
9070 //printf("[%s] change to init - %s\n", exp.loc.toChars(), exp.toChars());
9071 auto t = exp.type;
9072 exp = new ConstructExp(exp.loc, exp.e1, exp.e2);
9073 exp.type = t;
9074
9075 // https://issues.dlang.org/show_bug.cgi?id=13515
9076 // set Index::modifiable flag for complex AA element initialization
9077 if (auto ie1 = exp.e1.isIndexExp())
9078 {
9079 Expression e1x = ie1.markSettingAAElem();
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01009080 if (e1x.op == EXP.error)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02009081 {
9082 result = e1x;
9083 return;
9084 }
9085 }
9086 }
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01009087 else if (exp.op == EXP.construct && exp.e1.op == EXP.variable &&
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02009088 (cast(VarExp)exp.e1).var.storage_class & (STC.out_ | STC.ref_))
9089 {
9090 exp.memset = MemorySet.referenceInit;
9091 }
9092
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01009093 if (exp.op == EXP.assign) // skip EXP.blit and EXP.construct, which are initializations
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02009094 {
9095 exp.e1.checkSharedAccess(sc);
9096 checkUnsafeAccess(sc, exp.e1, false, true);
9097 }
9098
9099 checkUnsafeAccess(sc, exp.e2, true, true); // Initializer must always be checked
9100
9101 /* If it is an assignment from a 'foreign' type,
9102 * check for operator overloading.
9103 */
9104 if (exp.memset == MemorySet.referenceInit)
9105 {
9106 // If this is an initialization of a reference,
9107 // do nothing
9108 }
9109 else if (t1.ty == Tstruct)
9110 {
9111 auto e1x = exp.e1;
9112 auto e2x = exp.e2;
9113 auto sd = (cast(TypeStruct)t1).sym;
9114
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01009115 if (exp.op == EXP.construct)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02009116 {
9117 Type t2 = e2x.type.toBasetype();
9118 if (t2.ty == Tstruct && sd == (cast(TypeStruct)t2).sym)
9119 {
9120 sd.size(exp.loc);
9121 if (sd.sizeok != Sizeok.done)
9122 return setError();
9123 if (!sd.ctor)
9124 sd.ctor = sd.searchCtor();
9125
9126 // https://issues.dlang.org/show_bug.cgi?id=15661
9127 // Look for the form from last of comma chain.
9128 auto e2y = lastComma(e2x);
9129
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01009130 CallExp ce = (e2y.op == EXP.call) ? cast(CallExp)e2y : null;
9131 DotVarExp dve = (ce && ce.e1.op == EXP.dotVariable)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02009132 ? cast(DotVarExp)ce.e1 : null;
9133 if (sd.ctor && ce && dve && dve.var.isCtorDeclaration() &&
9134 // https://issues.dlang.org/show_bug.cgi?id=19389
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01009135 dve.e1.op != EXP.dotVariable &&
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02009136 e2y.type.implicitConvTo(t1))
9137 {
9138 /* Look for form of constructor call which is:
9139 * __ctmp.ctor(arguments...)
9140 */
9141
9142 /* Before calling the constructor, initialize
9143 * variable with a bit copy of the default
9144 * initializer
9145 */
9146 Expression einit = getInitExp(sd, exp.loc, sc, t1);
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01009147 if (einit.op == EXP.error)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02009148 {
9149 result = einit;
9150 return;
9151 }
9152
9153 auto ae = new BlitExp(exp.loc, exp.e1, einit);
9154 ae.type = e1x.type;
9155
9156 /* Replace __ctmp being constructed with e1.
9157 * We need to copy constructor call expression,
9158 * because it may be used in other place.
9159 */
9160 auto dvx = cast(DotVarExp)dve.copy();
9161 dvx.e1 = e1x;
9162 auto cx = cast(CallExp)ce.copy();
9163 cx.e1 = dvx;
9164 if (checkConstructorEscape(sc, cx, false))
9165 return setError();
9166
9167 Expression e0;
9168 Expression.extractLast(e2x, e0);
9169
9170 auto e = Expression.combine(e0, ae, cx);
9171 e = e.expressionSemantic(sc);
9172 result = e;
9173 return;
9174 }
9175 // https://issues.dlang.org/show_bug.cgi?id=21586
9176 // Rewrite CondExp or e1 will miss direct construction, e.g.
9177 // e1 = a ? S(1) : ...; -> AST: e1 = a ? (S(0)).this(1) : ...;
9178 // a temporary created and an extra destructor call.
9179 // AST will be rewritten to:
9180 // a ? e1 = 0, e1.this(1) : ...; -> blitting plus construction
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01009181 if (e2x.op == EXP.question)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02009182 {
9183 /* Rewrite as:
9184 * a ? e1 = b : e1 = c;
9185 */
9186 CondExp econd = cast(CondExp)e2x;
9187 Expression ea1 = new ConstructExp(econd.e1.loc, e1x, econd.e1);
9188 Expression ea2 = new ConstructExp(econd.e2.loc, e1x, econd.e2);
9189 Expression e = new CondExp(exp.loc, econd.econd, ea1, ea2);
9190 result = e.expressionSemantic(sc);
9191 return;
9192 }
9193 if (sd.postblit || sd.hasCopyCtor)
9194 {
9195 /* We have a copy constructor for this
9196 */
9197
9198 if (e2x.isLvalue())
9199 {
9200 if (sd.hasCopyCtor)
9201 {
9202 /* Rewrite as:
9203 * e1 = init, e1.copyCtor(e2);
9204 */
9205 Expression einit = new BlitExp(exp.loc, exp.e1, getInitExp(sd, exp.loc, sc, t1));
9206 einit.type = e1x.type;
9207
9208 Expression e;
9209 e = new DotIdExp(exp.loc, e1x, Id.ctor);
9210 e = new CallExp(exp.loc, e, e2x);
9211 e = new CommaExp(exp.loc, einit, e);
9212
9213 //printf("e: %s\n", e.toChars());
9214
9215 result = e.expressionSemantic(sc);
9216 return;
9217 }
9218 else
9219 {
9220 if (!e2x.type.implicitConvTo(e1x.type))
9221 {
9222 exp.error("conversion error from `%s` to `%s`",
9223 e2x.type.toChars(), e1x.type.toChars());
9224 return setError();
9225 }
9226
9227 /* Rewrite as:
9228 * (e1 = e2).postblit();
9229 *
9230 * Blit assignment e1 = e2 returns a reference to the original e1,
9231 * then call the postblit on it.
9232 */
9233 Expression e = e1x.copy();
9234 e.type = e.type.mutableOf();
9235 if (e.type.isShared && !sd.type.isShared)
9236 e.type = e.type.unSharedOf();
9237 e = new BlitExp(exp.loc, e, e2x);
9238 e = new DotVarExp(exp.loc, e, sd.postblit, false);
9239 e = new CallExp(exp.loc, e);
9240 result = e.expressionSemantic(sc);
9241 return;
9242 }
9243 }
9244 else
9245 {
9246 /* The struct value returned from the function is transferred
9247 * so should not call the destructor on it.
9248 */
9249 e2x = valueNoDtor(e2x);
9250 }
9251 }
9252
9253 // https://issues.dlang.org/show_bug.cgi?id=19251
9254 // if e2 cannot be converted to e1.type, maybe there is an alias this
9255 if (!e2x.implicitConvTo(t1))
9256 {
9257 AggregateDeclaration ad2 = isAggregate(e2x.type);
9258 if (ad2 && ad2.aliasthis && !isRecursiveAliasThis(exp.att2, exp.e2.type))
9259 {
9260 /* Rewrite (e1 op e2) as:
9261 * (e1 op e2.aliasthis)
9262 */
9263 exp.e2 = new DotIdExp(exp.e2.loc, exp.e2, ad2.aliasthis.ident);
9264 result = exp.expressionSemantic(sc);
9265 return;
9266 }
9267 }
9268 }
9269 else if (!e2x.implicitConvTo(t1))
9270 {
9271 sd.size(exp.loc);
9272 if (sd.sizeok != Sizeok.done)
9273 return setError();
9274 if (!sd.ctor)
9275 sd.ctor = sd.searchCtor();
9276
9277 if (sd.ctor)
9278 {
9279 /* Look for implicit constructor call
9280 * Rewrite as:
9281 * e1 = init, e1.ctor(e2)
9282 */
9283
9284 /* Fix Issue 5153 : https://issues.dlang.org/show_bug.cgi?id=5153
9285 * Using `new` to initialize a struct object is a common mistake, but
9286 * the error message from the compiler is not very helpful in that
9287 * case. If exp.e2 is a NewExp and the type of new is the same as
9288 * the type as exp.e1 (struct in this case), then we know for sure
9289 * that the user wants to instantiate a struct. This is done to avoid
9290 * issuing an error when the user actually wants to call a constructor
9291 * which receives a class object.
9292 *
9293 * Foo f = new Foo2(0); is a valid expression if Foo has a constructor
9294 * which receives an instance of a Foo2 class
9295 */
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01009296 if (exp.e2.op == EXP.new_)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02009297 {
9298 auto newExp = cast(NewExp)(exp.e2);
9299 if (newExp.newtype && newExp.newtype == t1)
9300 {
9301 error(exp.loc, "cannot implicitly convert expression `%s` of type `%s` to `%s`",
9302 newExp.toChars(), newExp.type.toChars(), t1.toChars());
9303 errorSupplemental(exp.loc, "Perhaps remove the `new` keyword?");
9304 return setError();
9305 }
9306 }
9307
9308 Expression einit = new BlitExp(exp.loc, e1x, getInitExp(sd, exp.loc, sc, t1));
9309 einit.type = e1x.type;
9310
9311 Expression e;
9312 e = new DotIdExp(exp.loc, e1x, Id.ctor);
9313 e = new CallExp(exp.loc, e, e2x);
9314 e = new CommaExp(exp.loc, einit, e);
9315 e = e.expressionSemantic(sc);
9316 result = e;
9317 return;
9318 }
9319 if (search_function(sd, Id.call))
9320 {
9321 /* Look for static opCall
9322 * https://issues.dlang.org/show_bug.cgi?id=2702
9323 * Rewrite as:
9324 * e1 = typeof(e1).opCall(arguments)
9325 */
9326 e2x = typeDotIdExp(e2x.loc, e1x.type, Id.call);
9327 e2x = new CallExp(exp.loc, e2x, exp.e2);
9328
9329 e2x = e2x.expressionSemantic(sc);
9330 e2x = resolveProperties(sc, e2x);
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01009331 if (e2x.op == EXP.error)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02009332 {
9333 result = e2x;
9334 return;
9335 }
9336 if (e2x.checkValue() || e2x.checkSharedAccess(sc))
9337 return setError();
9338 }
9339 }
9340 else // https://issues.dlang.org/show_bug.cgi?id=11355
9341 {
9342 AggregateDeclaration ad2 = isAggregate(e2x.type);
9343 if (ad2 && ad2.aliasthis && !isRecursiveAliasThis(exp.att2, exp.e2.type))
9344 {
9345 /* Rewrite (e1 op e2) as:
9346 * (e1 op e2.aliasthis)
9347 */
9348 exp.e2 = new DotIdExp(exp.e2.loc, exp.e2, ad2.aliasthis.ident);
9349 result = exp.expressionSemantic(sc);
9350 return;
9351 }
9352 }
9353 }
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01009354 else if (exp.op == EXP.assign)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02009355 {
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01009356 if (e1x.op == EXP.index && (cast(IndexExp)e1x).e1.type.toBasetype().ty == Taarray)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02009357 {
9358 /*
9359 * Rewrite:
9360 * aa[key] = e2;
9361 * as:
9362 * ref __aatmp = aa;
9363 * ref __aakey = key;
9364 * ref __aaval = e2;
9365 * (__aakey in __aatmp
9366 * ? __aatmp[__aakey].opAssign(__aaval)
9367 * : ConstructExp(__aatmp[__aakey], __aaval));
9368 */
9369 // ensure we keep the expr modifiable
9370 Expression esetting = (cast(IndexExp)e1x).markSettingAAElem();
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01009371 if (esetting.op == EXP.error)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02009372 {
9373 result = esetting;
9374 return;
9375 }
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01009376 assert(esetting.op == EXP.index);
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02009377 IndexExp ie = cast(IndexExp) esetting;
9378 Type t2 = e2x.type.toBasetype();
9379
9380 Expression e0 = null;
9381 Expression ea = extractSideEffect(sc, "__aatmp", e0, ie.e1);
9382 Expression ek = extractSideEffect(sc, "__aakey", e0, ie.e2);
9383 Expression ev = extractSideEffect(sc, "__aaval", e0, e2x);
9384
9385 AssignExp ae = cast(AssignExp)exp.copy();
9386 ae.e1 = new IndexExp(exp.loc, ea, ek);
9387 ae.e1 = ae.e1.expressionSemantic(sc);
9388 ae.e1 = ae.e1.optimize(WANTvalue);
9389 ae.e2 = ev;
9390 Expression e = ae.op_overload(sc);
9391 if (e)
9392 {
9393 Expression ey = null;
9394 if (t2.ty == Tstruct && sd == t2.toDsymbol(sc))
9395 {
9396 ey = ev;
9397 }
9398 else if (!ev.implicitConvTo(ie.type) && sd.ctor)
9399 {
9400 // Look for implicit constructor call
9401 // Rewrite as S().ctor(e2)
9402 ey = new StructLiteralExp(exp.loc, sd, null);
9403 ey = new DotIdExp(exp.loc, ey, Id.ctor);
9404 ey = new CallExp(exp.loc, ey, ev);
9405 ey = ey.trySemantic(sc);
9406 }
9407 if (ey)
9408 {
9409 Expression ex;
9410 ex = new IndexExp(exp.loc, ea, ek);
9411 ex = ex.expressionSemantic(sc);
9412 ex = ex.modifiableLvalue(sc, ex); // allocate new slot
9413 ex = ex.optimize(WANTvalue);
9414
9415 ey = new ConstructExp(exp.loc, ex, ey);
9416 ey = ey.expressionSemantic(sc);
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01009417 if (ey.op == EXP.error)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02009418 {
9419 result = ey;
9420 return;
9421 }
9422 ex = e;
9423
9424 // https://issues.dlang.org/show_bug.cgi?id=14144
9425 // The whole expression should have the common type
9426 // of opAssign() return and assigned AA entry.
9427 // Even if there's no common type, expression should be typed as void.
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01009428 if (!typeMerge(sc, EXP.question, ex, ey))
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02009429 {
9430 ex = new CastExp(ex.loc, ex, Type.tvoid);
9431 ey = new CastExp(ey.loc, ey, Type.tvoid);
9432 }
9433 e = new CondExp(exp.loc, new InExp(exp.loc, ek, ea), ex, ey);
9434 }
9435 e = Expression.combine(e0, e);
9436 e = e.expressionSemantic(sc);
9437 result = e;
9438 return;
9439 }
9440 }
9441 else
9442 {
9443 Expression e = exp.op_overload(sc);
9444 if (e)
9445 {
9446 result = e;
9447 return;
9448 }
9449 }
9450 }
9451 else
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01009452 assert(exp.op == EXP.blit);
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02009453
Iain Buclaw0fb57032021-12-05 17:11:12 +01009454 if (e2x.checkValue())
9455 return setError();
9456
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02009457 exp.e1 = e1x;
9458 exp.e2 = e2x;
9459 }
9460 else if (t1.ty == Tclass)
9461 {
9462 // Disallow assignment operator overloads for same type
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01009463 if (exp.op == EXP.assign && !exp.e2.implicitConvTo(exp.e1.type))
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02009464 {
9465 Expression e = exp.op_overload(sc);
9466 if (e)
9467 {
9468 result = e;
9469 return;
9470 }
9471 }
Iain Buclaw0fb57032021-12-05 17:11:12 +01009472 if (exp.e2.checkValue())
9473 return setError();
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02009474 }
9475 else if (t1.ty == Tsarray)
9476 {
9477 // SliceExp cannot have static array type without context inference.
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01009478 assert(exp.e1.op != EXP.slice);
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02009479 Expression e1x = exp.e1;
9480 Expression e2x = exp.e2;
9481
Iain Buclaw5eb99272022-05-16 18:30:46 +02009482 /* C strings come through as static arrays. May need to adjust the size of the
9483 * string to match the size of e1.
9484 */
9485 Type t2 = e2x.type.toBasetype();
9486 if (sc.flags & SCOPE.Cfile && e2x.isStringExp() && t2.isTypeSArray())
9487 {
9488 uinteger_t dim1 = t1.isTypeSArray().dim.toInteger();
9489 uinteger_t dim2 = t2.isTypeSArray().dim.toInteger();
9490 if (dim1 + 1 == dim2 || dim2 < dim1)
9491 {
9492 auto tsa2 = t2.isTypeSArray();
9493 auto newt = tsa2.next.sarrayOf(dim1).immutableOf();
9494 e2x = castTo(e2x, sc, newt);
9495 exp.e2 = e2x;
9496 }
9497 }
9498
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02009499 if (e2x.implicitConvTo(e1x.type))
9500 {
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01009501 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()))
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02009502 {
9503 if (e1x.checkPostblit(sc, t1))
9504 return setError();
9505 }
9506
9507 // e2 matches to t1 because of the implicit length match, so
9508 if (isUnaArrayOp(e2x.op) || isBinArrayOp(e2x.op))
9509 {
9510 // convert e1 to e1[]
9511 // e.g. e1[] = a[] + b[];
9512 auto sle = new SliceExp(e1x.loc, e1x, null, null);
9513 sle.arrayop = true;
9514 e1x = sle.expressionSemantic(sc);
9515 }
9516 else
9517 {
9518 // convert e2 to t1 later
9519 // e.g. e1 = [1, 2, 3];
9520 }
9521 }
9522 else
9523 {
9524 if (e2x.implicitConvTo(t1.nextOf().arrayOf()) > MATCH.nomatch)
9525 {
9526 uinteger_t dim1 = (cast(TypeSArray)t1).dim.toInteger();
9527 uinteger_t dim2 = dim1;
9528 if (auto ale = e2x.isArrayLiteralExp())
9529 {
9530 dim2 = ale.elements ? ale.elements.dim : 0;
9531 }
9532 else if (auto se = e2x.isSliceExp())
9533 {
9534 Type tx = toStaticArrayType(se);
9535 if (tx)
9536 dim2 = (cast(TypeSArray)tx).dim.toInteger();
9537 }
9538 if (dim1 != dim2)
9539 {
9540 exp.error("mismatched array lengths, %d and %d", cast(int)dim1, cast(int)dim2);
9541 return setError();
9542 }
9543 }
9544
9545 // May be block or element-wise assignment, so
9546 // convert e1 to e1[]
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01009547 if (exp.op != EXP.assign)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02009548 {
9549 // If multidimensional static array, treat as one large array
9550 //
9551 // Find the appropriate array type depending on the assignment, e.g.
9552 // int[3] = int => int[3]
9553 // int[3][2] = int => int[6]
9554 // int[3][2] = int[] => int[3][2]
9555 // int[3][2][4] + int => int[24]
9556 // int[3][2][4] + int[] => int[3][8]
9557 ulong dim = t1.isTypeSArray().dim.toUInteger();
9558 auto type = t1.nextOf();
9559
9560 for (TypeSArray tsa; (tsa = type.isTypeSArray()) !is null; )
9561 {
9562 import core.checkedint : mulu;
9563
9564 // Accumulate skipped dimensions
9565 bool overflow = false;
9566 dim = mulu(dim, tsa.dim.toUInteger(), overflow);
9567 if (overflow || dim >= uint.max)
9568 {
9569 // dym exceeds maximum array size
9570 exp.error("static array `%s` size overflowed to %llu",
9571 e1x.type.toChars(), cast(ulong) dim);
9572 return setError();
9573 }
9574
9575 // Move to the element type
9576 type = tsa.nextOf().toBasetype();
9577
9578 // Rewrite ex1 as a static array if a matching type was found
9579 if (e2x.implicitConvTo(type) > MATCH.nomatch)
9580 {
9581 e1x.type = type.sarrayOf(dim);
9582 break;
9583 }
9584 }
9585 }
9586 auto sle = new SliceExp(e1x.loc, e1x, null, null);
9587 sle.arrayop = true;
9588 e1x = sle.expressionSemantic(sc);
9589 }
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01009590 if (e1x.op == EXP.error)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02009591 return setResult(e1x);
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01009592 if (e2x.op == EXP.error)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02009593 return setResult(e2x);
9594
9595 exp.e1 = e1x;
9596 exp.e2 = e2x;
9597 t1 = e1x.type.toBasetype();
9598 }
9599 /* Check the mutability of e1.
9600 */
9601 if (auto ale = exp.e1.isArrayLengthExp())
9602 {
9603 // e1 is not an lvalue, but we let code generator handle it
9604
9605 auto ale1x = ale.e1.modifiableLvalue(sc, exp.e1);
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01009606 if (ale1x.op == EXP.error)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02009607 return setResult(ale1x);
9608 ale.e1 = ale1x;
9609
9610 Type tn = ale.e1.type.toBasetype().nextOf();
9611 checkDefCtor(ale.loc, tn);
9612
9613 Identifier hook = global.params.tracegc ? Id._d_arraysetlengthTTrace : Id._d_arraysetlengthT;
9614 if (!verifyHookExist(exp.loc, *sc, Id._d_arraysetlengthTImpl, "resizing arrays"))
9615 return setError();
9616
9617 exp.e2 = exp.e2.expressionSemantic(sc);
9618 auto lc = lastComma(exp.e2);
9619 lc = lc.optimize(WANTvalue);
9620 // use slice expression when arr.length = 0 to avoid runtime call
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01009621 if(lc.op == EXP.int64 && lc.toInteger() == 0)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02009622 {
9623 Expression se = new SliceExp(ale.loc, ale.e1, lc, lc);
9624 Expression as = new AssignExp(ale.loc, ale.e1, se);
9625 as = as.expressionSemantic(sc);
9626 auto res = Expression.combine(as, exp.e2);
9627 res.type = ale.type;
9628 return setResult(res);
9629 }
9630
9631 // Lower to object._d_arraysetlengthTImpl!(typeof(e1))._d_arraysetlengthT{,Trace}(e1, e2)
9632 Expression id = new IdentifierExp(ale.loc, Id.empty);
9633 id = new DotIdExp(ale.loc, id, Id.object);
9634 auto tiargs = new Objects();
9635 tiargs.push(ale.e1.type);
9636 id = new DotTemplateInstanceExp(ale.loc, id, Id._d_arraysetlengthTImpl, tiargs);
9637 id = new DotIdExp(ale.loc, id, hook);
9638 id = id.expressionSemantic(sc);
9639
9640 auto arguments = new Expressions();
9641 arguments.reserve(5);
9642 if (global.params.tracegc)
9643 {
9644 auto funcname = (sc.callsc && sc.callsc.func) ? sc.callsc.func.toPrettyChars() : sc.func.toPrettyChars();
9645 arguments.push(new StringExp(exp.loc, exp.loc.filename.toDString()));
9646 arguments.push(new IntegerExp(exp.loc, exp.loc.linnum, Type.tint32));
9647 arguments.push(new StringExp(exp.loc, funcname.toDString()));
9648 }
9649 arguments.push(ale.e1);
9650 arguments.push(exp.e2);
9651
9652 Expression ce = new CallExp(ale.loc, id, arguments);
9653 auto res = ce.expressionSemantic(sc);
9654 // if (global.params.verbose)
9655 // message("lowered %s =>\n %s", exp.toChars(), res.toChars());
9656 return setResult(res);
9657 }
9658 else if (auto se = exp.e1.isSliceExp())
9659 {
9660 Type tn = se.type.nextOf();
9661 const fun = sc.func;
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01009662 if (exp.op == EXP.assign && !tn.isMutable() &&
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02009663 // allow modifiation in module ctor, see
9664 // https://issues.dlang.org/show_bug.cgi?id=9884
9665 (!fun || (fun && !fun.isStaticCtorDeclaration())))
9666 {
9667 exp.error("slice `%s` is not mutable", se.toChars());
9668 return setError();
9669 }
9670
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01009671 if (exp.op == EXP.assign && !tn.baseElemOf().isAssignable())
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02009672 {
9673 exp.error("slice `%s` is not mutable, struct `%s` has immutable members",
9674 exp.e1.toChars(), tn.baseElemOf().toChars());
9675 result = ErrorExp.get();
9676 return;
9677 }
9678
9679 // For conditional operator, both branches need conversion.
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01009680 while (se.e1.op == EXP.slice)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02009681 se = cast(SliceExp)se.e1;
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01009682 if (se.e1.op == EXP.question && se.e1.type.toBasetype().ty == Tsarray)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02009683 {
9684 se.e1 = se.e1.modifiableLvalue(sc, exp.e1);
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01009685 if (se.e1.op == EXP.error)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02009686 return setResult(se.e1);
9687 }
9688 }
9689 else
9690 {
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01009691 if (t1.ty == Tsarray && exp.op == EXP.assign)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02009692 {
9693 Type tn = exp.e1.type.nextOf();
9694 if (tn && !tn.baseElemOf().isAssignable())
9695 {
9696 exp.error("array `%s` is not mutable, struct `%s` has immutable members",
9697 exp.e1.toChars(), tn.baseElemOf().toChars());
9698 result = ErrorExp.get();
9699 return;
9700 }
9701 }
9702
9703 Expression e1x = exp.e1;
9704
9705 // Try to do a decent error message with the expression
9706 // before it gets constant folded
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01009707 if (exp.op == EXP.assign)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02009708 e1x = e1x.modifiableLvalue(sc, e1old);
9709
9710 e1x = e1x.optimize(WANTvalue, /*keepLvalue*/ true);
9711
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01009712 if (e1x.op == EXP.error)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02009713 {
9714 result = e1x;
9715 return;
9716 }
9717 exp.e1 = e1x;
9718 }
9719
9720 /* Tweak e2 based on the type of e1.
9721 */
9722 Expression e2x = exp.e2;
9723 Type t2 = e2x.type.toBasetype();
9724
9725 // If it is a array, get the element type. Note that it may be
9726 // multi-dimensional.
9727 Type telem = t1;
9728 while (telem.ty == Tarray)
9729 telem = telem.nextOf();
9730
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01009731 if (exp.e1.op == EXP.slice && t1.nextOf() &&
9732 (telem.ty != Tvoid || e2x.op == EXP.null_) &&
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02009733 e2x.implicitConvTo(t1.nextOf()))
9734 {
9735 // Check for block assignment. If it is of type void[], void[][], etc,
9736 // '= null' is the only allowable block assignment (Bug 7493)
9737 exp.memset = MemorySet.blockAssign; // make it easy for back end to tell what this is
9738 e2x = e2x.implicitCastTo(sc, t1.nextOf());
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01009739 if (exp.op != EXP.blit && e2x.isLvalue() && exp.e1.checkPostblit(sc, t1.nextOf()))
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02009740 return setError();
9741 }
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01009742 else if (exp.e1.op == EXP.slice &&
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02009743 (t2.ty == Tarray || t2.ty == Tsarray) &&
9744 t2.nextOf().implicitConvTo(t1.nextOf()))
9745 {
9746 // Check element-wise assignment.
9747
9748 /* If assigned elements number is known at compile time,
9749 * check the mismatch.
9750 */
9751 SliceExp se1 = cast(SliceExp)exp.e1;
9752 TypeSArray tsa1 = cast(TypeSArray)toStaticArrayType(se1);
9753 TypeSArray tsa2 = null;
9754 if (auto ale = e2x.isArrayLiteralExp())
9755 tsa2 = cast(TypeSArray)t2.nextOf().sarrayOf(ale.elements.dim);
9756 else if (auto se = e2x.isSliceExp())
9757 tsa2 = cast(TypeSArray)toStaticArrayType(se);
9758 else
9759 tsa2 = t2.isTypeSArray();
Iain Buclaw5eb99272022-05-16 18:30:46 +02009760
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02009761 if (tsa1 && tsa2)
9762 {
9763 uinteger_t dim1 = tsa1.dim.toInteger();
9764 uinteger_t dim2 = tsa2.dim.toInteger();
9765 if (dim1 != dim2)
9766 {
Iain Buclaw5eb99272022-05-16 18:30:46 +02009767 exp.error("mismatched array lengths %d and %d for assignment `%s`", cast(int)dim1, cast(int)dim2, exp.toChars());
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02009768 return setError();
9769 }
9770 }
9771
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01009772 if (exp.op != EXP.blit &&
9773 (e2x.op == EXP.slice && (cast(UnaExp)e2x).e1.isLvalue() ||
9774 e2x.op == EXP.cast_ && (cast(UnaExp)e2x).e1.isLvalue() ||
9775 e2x.op != EXP.slice && e2x.isLvalue()))
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02009776 {
9777 if (exp.e1.checkPostblit(sc, t1.nextOf()))
9778 return setError();
9779 }
9780
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01009781 if (0 && global.params.warnings != DiagnosticReporting.off && !global.gag && exp.op == EXP.assign &&
9782 e2x.op != EXP.slice && e2x.op != EXP.assign &&
9783 e2x.op != EXP.arrayLiteral && e2x.op != EXP.string_ &&
9784 !(e2x.op == EXP.add || e2x.op == EXP.min ||
9785 e2x.op == EXP.mul || e2x.op == EXP.div ||
9786 e2x.op == EXP.mod || e2x.op == EXP.xor ||
9787 e2x.op == EXP.and || e2x.op == EXP.or ||
9788 e2x.op == EXP.pow ||
9789 e2x.op == EXP.tilde || e2x.op == EXP.negate))
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02009790 {
9791 const(char)* e1str = exp.e1.toChars();
9792 const(char)* e2str = e2x.toChars();
9793 exp.warning("explicit element-wise assignment `%s = (%s)[]` is better than `%s = %s`", e1str, e2str, e1str, e2str);
9794 }
9795
9796 Type t2n = t2.nextOf();
9797 Type t1n = t1.nextOf();
9798 int offset;
9799 if (t2n.equivalent(t1n) ||
9800 t1n.isBaseOf(t2n, &offset) && offset == 0)
9801 {
9802 /* Allow copy of distinct qualifier elements.
9803 * eg.
9804 * char[] dst; const(char)[] src;
9805 * dst[] = src;
9806 *
9807 * class C {} class D : C {}
9808 * C[2] ca; D[] da;
9809 * ca[] = da;
9810 */
9811 if (isArrayOpValid(e2x))
9812 {
9813 // Don't add CastExp to keep AST for array operations
9814 e2x = e2x.copy();
9815 e2x.type = exp.e1.type.constOf();
9816 }
9817 else
9818 e2x = e2x.castTo(sc, exp.e1.type.constOf());
9819 }
9820 else
9821 {
9822 /* https://issues.dlang.org/show_bug.cgi?id=15778
9823 * A string literal has an array type of immutable
9824 * elements by default, and normally it cannot be convertible to
9825 * array type of mutable elements. But for element-wise assignment,
9826 * elements need to be const at best. So we should give a chance
9827 * to change code unit size for polysemous string literal.
9828 */
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01009829 if (e2x.op == EXP.string_)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02009830 e2x = e2x.implicitCastTo(sc, exp.e1.type.constOf());
9831 else
9832 e2x = e2x.implicitCastTo(sc, exp.e1.type);
9833 }
9834 if (t1n.toBasetype.ty == Tvoid && t2n.toBasetype.ty == Tvoid)
9835 {
Iain Buclaw610d7892022-05-27 19:36:06 +02009836 if (sc.setUnsafe(false, exp.loc, "cannot copy `void[]` to `void[]` in `@safe` code"))
9837 return setError();
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02009838 }
9839 }
9840 else
9841 {
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01009842 if (0 && global.params.warnings != DiagnosticReporting.off && !global.gag && exp.op == EXP.assign &&
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02009843 t1.ty == Tarray && t2.ty == Tsarray &&
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01009844 e2x.op != EXP.slice &&
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02009845 t2.implicitConvTo(t1))
9846 {
9847 // Disallow ar[] = sa (Converted to ar[] = sa[])
9848 // Disallow da = sa (Converted to da = sa[])
9849 const(char)* e1str = exp.e1.toChars();
9850 const(char)* e2str = e2x.toChars();
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01009851 const(char)* atypestr = exp.e1.op == EXP.slice ? "element-wise" : "slice";
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02009852 exp.warning("explicit %s assignment `%s = (%s)[]` is better than `%s = %s`", atypestr, e1str, e2str, e1str, e2str);
9853 }
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01009854 if (exp.op == EXP.blit)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02009855 e2x = e2x.castTo(sc, exp.e1.type);
9856 else
9857 {
9858 e2x = e2x.implicitCastTo(sc, exp.e1.type);
9859
9860 // Fix Issue 13435: https://issues.dlang.org/show_bug.cgi?id=13435
9861
9862 // If the implicit cast has failed and the assign expression is
9863 // the initialization of a struct member field
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01009864 if (e2x.op == EXP.error && exp.op == EXP.construct && t1.ty == Tstruct)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02009865 {
9866 scope sd = (cast(TypeStruct)t1).sym;
9867 Dsymbol opAssign = search_function(sd, Id.assign);
9868
9869 // and the struct defines an opAssign
9870 if (opAssign)
9871 {
9872 // offer more information about the cause of the problem
9873 errorSupplemental(exp.loc,
9874 "`%s` is the first assignment of `%s` therefore it represents its initialization",
9875 exp.toChars(), exp.e1.toChars());
9876 errorSupplemental(exp.loc,
9877 "`opAssign` methods are not used for initialization, but for subsequent assignments");
9878 }
9879 }
9880 }
9881 }
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01009882 if (e2x.op == EXP.error)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02009883 {
9884 result = e2x;
9885 return;
9886 }
9887 exp.e2 = e2x;
9888 t2 = exp.e2.type.toBasetype();
9889
9890 /* Look for array operations
9891 */
9892 if ((t2.ty == Tarray || t2.ty == Tsarray) && isArrayOpValid(exp.e2))
9893 {
9894 // Look for valid array operations
9895 if (exp.memset != MemorySet.blockAssign &&
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01009896 exp.e1.op == EXP.slice &&
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02009897 (isUnaArrayOp(exp.e2.op) || isBinArrayOp(exp.e2.op)))
9898 {
9899 exp.type = exp.e1.type;
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01009900 if (exp.op == EXP.construct) // https://issues.dlang.org/show_bug.cgi?id=10282
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02009901 // tweak mutability of e1 element
9902 exp.e1.type = exp.e1.type.nextOf().mutableOf().arrayOf();
9903 result = arrayOp(exp, sc);
9904 return;
9905 }
9906
9907 // Drop invalid array operations in e2
9908 // d = a[] + b[], d = (a[] + b[])[0..2], etc
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01009909 if (checkNonAssignmentArrayOp(exp.e2, exp.memset != MemorySet.blockAssign && exp.op == EXP.assign))
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02009910 return setError();
9911
9912 // Remains valid array assignments
9913 // d = d[], d = [1,2,3], etc
9914 }
9915
9916 /* Don't allow assignment to classes that were allocated on the stack with:
9917 * scope Class c = new Class();
9918 */
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01009919 if (exp.e1.op == EXP.variable && exp.op == EXP.assign)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02009920 {
9921 VarExp ve = cast(VarExp)exp.e1;
9922 VarDeclaration vd = ve.var.isVarDeclaration();
Iain Buclaw6384eff2022-02-20 20:02:23 +01009923 if (vd && vd.onstack)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02009924 {
9925 assert(t1.ty == Tclass);
9926 exp.error("cannot rebind scope variables");
9927 }
9928 }
9929
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01009930 if (exp.e1.op == EXP.variable && (cast(VarExp)exp.e1).var.ident == Id.ctfe)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +02009931 {
9932 exp.error("cannot modify compiler-generated variable `__ctfe`");
9933 }
9934
9935 exp.type = exp.e1.type;
9936 assert(exp.type);
Iain Buclaw7e7ebe32022-10-29 09:05:54 +02009937 auto assignElem = exp.e2;
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01009938 auto res = exp.op == EXP.assign ? exp.reorderSettingAAElem(sc) : exp;
Iain Buclaw0fb57032021-12-05 17:11:12 +01009939 /* https://issues.dlang.org/show_bug.cgi?id=22366
9940 *
9941 * `reorderSettingAAElem` creates a tree of comma expressions, however,
9942 * `checkAssignExp` expects only AssignExps.
9943 */
Iain Buclaw7e7ebe32022-10-29 09:05:54 +02009944 if (res == exp) // no `AA[k] = v` rewrite was performed
9945 checkAssignEscape(sc, res, false, false);
9946 else
9947 checkNewEscape(sc, assignElem, false); // assigning to AA puts it on heap
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01009948
9949 if (auto ae = res.isConstructExp())
9950 {
9951 Type t1b = ae.e1.type.toBasetype();
9952 if (t1b.ty != Tsarray && t1b.ty != Tarray)
9953 return setResult(res);
9954
Iain Buclaw7e7ebe32022-10-29 09:05:54 +02009955 // only non-trivial array constructions may need to be lowered (non-POD elements basically)
9956 Type t1e = t1b.nextOf();
9957 TypeStruct ts = t1e.baseElemOf().isTypeStruct();
9958 if (!ts || (!ts.sym.postblit && !ts.sym.hasCopyCtor && !ts.sym.dtor))
9959 return setResult(res);
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01009960
Iain Buclaw7e7ebe32022-10-29 09:05:54 +02009961 // don't lower ref-constructions etc.
9962 if (!(t1b.ty == Tsarray || ae.e1.isSliceExp) ||
9963 (ae.e1.isVarExp && ae.e1.isVarExp.var.isVarDeclaration.isReference))
9964 return setResult(res);
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01009965
Iain Buclaw7e7ebe32022-10-29 09:05:54 +02009966 // Construction from an equivalent other array?
9967 // Only lower with lvalue RHS elements; let the glue layer move rvalue elements.
9968 Type t2b = ae.e2.type.toBasetype();
9969 // skip over a (possibly implicit) cast of a static array RHS to a slice
9970 Expression rhs = ae.e2;
9971 Type rhsType = t2b;
9972 if (t2b.ty == Tarray)
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01009973 {
Iain Buclaw7e7ebe32022-10-29 09:05:54 +02009974 if (auto ce = rhs.isCastExp())
9975 {
9976 auto ct = ce.e1.type.toBasetype();
9977 if (ct.ty == Tsarray)
9978 {
9979 rhs = ce.e1;
9980 rhsType = ct;
9981 }
9982 }
9983 }
9984 const lowerToArrayCtor =
9985 ( (rhsType.ty == Tarray && !rhs.isArrayLiteralExp) ||
9986 (rhsType.ty == Tsarray && rhs.isLvalue) ) &&
9987 t1e.equivalent(t2b.nextOf);
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01009988
Iain Buclaw7e7ebe32022-10-29 09:05:54 +02009989 // Construction from a single element?
9990 // If the RHS is an rvalue, then we'll need to make a temporary for it (copied multiple times).
9991 const lowerToArraySetCtor = !lowerToArrayCtor && t1e.equivalent(t2b);
9992
9993 if (lowerToArrayCtor || lowerToArraySetCtor)
9994 {
9995 auto func = lowerToArrayCtor ? Id._d_arrayctor : Id._d_arraysetctor;
9996 const other = lowerToArrayCtor ? "other array" : "value";
Iain Buclaw9c7d5e882021-12-10 03:14:20 +01009997 if (!verifyHookExist(exp.loc, *sc, func, "construct array with " ~ other, Id.object))
9998 return setError();
9999
10000 // Lower to object._d_array{,set}ctor(e1, e2)
10001 Expression id = new IdentifierExp(exp.loc, Id.empty);
10002 id = new DotIdExp(exp.loc, id, Id.object);
10003 id = new DotIdExp(exp.loc, id, func);
Iain Buclaw9c7d5e882021-12-10 03:14:20 +010010004
10005 auto arguments = new Expressions();
Iain Buclaw7e7ebe32022-10-29 09:05:54 +020010006 arguments.push(new CastExp(ae.loc, ae.e1, t1e.arrayOf).expressionSemantic(sc));
10007 if (lowerToArrayCtor)
Iain Buclaw9c7d5e882021-12-10 03:14:20 +010010008 {
Iain Buclaw7e7ebe32022-10-29 09:05:54 +020010009 arguments.push(new CastExp(ae.loc, rhs, t2b.nextOf.arrayOf).expressionSemantic(sc));
Iain Buclaw9c7d5e882021-12-10 03:14:20 +010010010 Expression ce = new CallExp(exp.loc, id, arguments);
10011 res = ce.expressionSemantic(sc);
10012 }
10013 else
10014 {
10015 Expression e0;
Iain Buclaw7e7ebe32022-10-29 09:05:54 +020010016 // promote an rvalue RHS element to a temporary, it's passed by ref to _d_arraysetctor
10017 if (!ae.e2.isLvalue)
Iain Buclaw9c7d5e882021-12-10 03:14:20 +010010018 {
10019 auto vd = copyToTemp(STC.scope_, "__setctor", ae.e2);
10020 e0 = new DeclarationExp(vd.loc, vd).expressionSemantic(sc);
10021 arguments.push(new VarExp(vd.loc, vd).expressionSemantic(sc));
10022 }
10023 else
10024 arguments.push(ae.e2);
10025
10026 Expression ce = new CallExp(exp.loc, id, arguments);
10027 res = Expression.combine(e0, ce).expressionSemantic(sc);
10028 }
10029
10030 if (global.params.verbose)
10031 message("lowered %s =>\n %s", exp.toChars(), res.toChars());
10032 }
10033 }
Iain Buclawb7a586b2022-08-25 19:04:50 +020010034 else if (auto ae = res.isAssignExp())
10035 res = lowerArrayAssign(ae);
10036 else if (auto ce = res.isCommaExp())
10037 {
10038 if (auto ae1 = ce.e1.isAssignExp())
10039 ce.e1 = lowerArrayAssign(ae1, true);
10040 if (auto ae2 = ce.e2.isAssignExp())
10041 ce.e2 = lowerArrayAssign(ae2, true);
10042 }
Iain Buclaw9c7d5e882021-12-10 03:14:20 +010010043
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020010044 return setResult(res);
10045 }
10046
Iain Buclawb7a586b2022-08-25 19:04:50 +020010047 /***************************************
Iain Buclawc8dfa792022-09-27 10:43:32 +020010048 * Lower AssignExp to `_d_array{setassign,assign_l,assign_r}` if needed.
Iain Buclawb7a586b2022-08-25 19:04:50 +020010049 *
10050 * Params:
10051 * ae = the AssignExp to be lowered
10052 * fromCommaExp = indicates whether `ae` is part of a CommaExp or not,
10053 * so no unnecessary temporay variable is created.
10054 * Returns:
Iain Buclawc8dfa792022-09-27 10:43:32 +020010055 * a CommaExp contiaining call a to `_d_array{setassign,assign_l,assign_r}`
10056 * if needed or `ae` otherwise
Iain Buclawb7a586b2022-08-25 19:04:50 +020010057 */
10058 private Expression lowerArrayAssign(AssignExp ae, bool fromCommaExp = false)
10059 {
10060 Type t1b = ae.e1.type.toBasetype();
10061 if (t1b.ty != Tsarray && t1b.ty != Tarray)
10062 return ae;
10063
Iain Buclawc8dfa792022-09-27 10:43:32 +020010064 const isArrayAssign = (ae.e1.isSliceExp() || ae.e1.type.ty == Tsarray) &&
Iain Buclawb7a586b2022-08-25 19:04:50 +020010065 (ae.e2.type.ty == Tsarray || ae.e2.type.ty == Tarray) &&
Iain Buclawc8dfa792022-09-27 10:43:32 +020010066 (ae.e1.type.nextOf() && ae.e2.type.nextOf() && ae.e1.type.nextOf.mutableOf.equals(ae.e2.type.nextOf.mutableOf()));
Iain Buclawb7a586b2022-08-25 19:04:50 +020010067
Iain Buclawc8dfa792022-09-27 10:43:32 +020010068 const isArraySetAssign = (ae.e1.isSliceExp() || ae.e1.type.ty == Tsarray) &&
10069 (ae.e1.type.nextOf() && ae.e2.type.implicitConvTo(ae.e1.type.nextOf()));
10070
10071 if (!isArrayAssign && !isArraySetAssign)
Iain Buclawb7a586b2022-08-25 19:04:50 +020010072 return ae;
10073
10074 const ts = t1b.nextOf().baseElemOf().isTypeStruct();
10075 if (!ts || (!ts.sym.postblit && !ts.sym.dtor))
10076 return ae;
10077
10078 Expression res;
Iain Buclawc8dfa792022-09-27 10:43:32 +020010079 Identifier func = isArraySetAssign ? Id._d_arraysetassign :
10080 ae.e2.isLvalue() || ae.e2.isSliceExp() ? Id._d_arrayassign_l : Id._d_arrayassign_r;
Iain Buclawb7a586b2022-08-25 19:04:50 +020010081
Iain Buclawc8dfa792022-09-27 10:43:32 +020010082 // Lower to `.object._d_array{setassign,assign_l,assign_r}(e1, e2)``
Iain Buclawb7a586b2022-08-25 19:04:50 +020010083 Expression id = new IdentifierExp(ae.loc, Id.empty);
10084 id = new DotIdExp(ae.loc, id, Id.object);
10085 id = new DotIdExp(ae.loc, id, func);
10086
10087 auto arguments = new Expressions();
10088 arguments.push(new CastExp(ae.loc, ae.e1, ae.e1.type.nextOf.arrayOf)
10089 .expressionSemantic(sc));
10090
10091 Expression eValue2, value2 = ae.e2;
Iain Buclawc8dfa792022-09-27 10:43:32 +020010092 if (isArrayAssign && value2.isLvalue())
10093 value2 = new CastExp(ae.loc, ae.e2, ae.e2.type.nextOf.arrayOf())
Iain Buclawb7a586b2022-08-25 19:04:50 +020010094 .expressionSemantic(sc);
Iain Buclawc8dfa792022-09-27 10:43:32 +020010095 else if (!fromCommaExp &&
10096 (isArrayAssign || (isArraySetAssign && !value2.isLvalue())))
Iain Buclawb7a586b2022-08-25 19:04:50 +020010097 {
10098 // Rvalues from CommaExps were introduced in `visit(AssignExp)`
10099 // and are temporary variables themselves. Rvalues from trivial
10100 // SliceExps are simply passed by reference without any copying.
10101
10102 // `__assigntmp` will be destroyed together with the array `ae.e1`.
10103 // When `ae.e2` is a variadic arg array, it is also `scope`, so
10104 // `__assigntmp` may also be scope.
Iain Buclawc8dfa792022-09-27 10:43:32 +020010105 StorageClass stc = STC.nodtor;
10106 if (isArrayAssign)
10107 stc |= STC.rvalue | STC.scope_;
10108
10109 auto vd = copyToTemp(stc, "__assigntmp", ae.e2);
Iain Buclawb7a586b2022-08-25 19:04:50 +020010110 eValue2 = new DeclarationExp(vd.loc, vd).expressionSemantic(sc);
10111 value2 = new VarExp(vd.loc, vd).expressionSemantic(sc);
10112 }
10113 arguments.push(value2);
10114
10115 Expression ce = new CallExp(ae.loc, id, arguments);
10116 res = Expression.combine(eValue2, ce).expressionSemantic(sc);
Iain Buclawc8dfa792022-09-27 10:43:32 +020010117 if (isArrayAssign)
10118 res = Expression.combine(res, ae.e1).expressionSemantic(sc);
Iain Buclawb7a586b2022-08-25 19:04:50 +020010119
10120 if (global.params.verbose)
10121 message("lowered %s =>\n %s", ae.toChars(), res.toChars());
10122
10123 return res;
10124 }
10125
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020010126 override void visit(PowAssignExp exp)
10127 {
10128 if (exp.type)
10129 {
10130 result = exp;
10131 return;
10132 }
10133
10134 Expression e = exp.op_overload(sc);
10135 if (e)
10136 {
10137 result = e;
10138 return;
10139 }
10140
10141 if (exp.e1.checkReadModifyWrite(exp.op, exp.e2))
10142 return setError();
10143
10144 assert(exp.e1.type && exp.e2.type);
Iain Buclaw9c7d5e882021-12-10 03:14:20 +010010145 if (exp.e1.op == EXP.slice || exp.e1.type.ty == Tarray || exp.e1.type.ty == Tsarray)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020010146 {
10147 if (checkNonAssignmentArrayOp(exp.e1))
10148 return setError();
10149
10150 // T[] ^^= ...
10151 if (exp.e2.implicitConvTo(exp.e1.type.nextOf()))
10152 {
10153 // T[] ^^= T
10154 exp.e2 = exp.e2.castTo(sc, exp.e1.type.nextOf());
10155 }
10156 else if (Expression ex = typeCombine(exp, sc))
10157 {
10158 result = ex;
10159 return;
10160 }
10161
10162 // Check element types are arithmetic
10163 Type tb1 = exp.e1.type.nextOf().toBasetype();
10164 Type tb2 = exp.e2.type.toBasetype();
10165 if (tb2.ty == Tarray || tb2.ty == Tsarray)
10166 tb2 = tb2.nextOf().toBasetype();
10167 if ((tb1.isintegral() || tb1.isfloating()) && (tb2.isintegral() || tb2.isfloating()))
10168 {
10169 exp.type = exp.e1.type;
10170 result = arrayOp(exp, sc);
10171 return;
10172 }
10173 }
10174 else
10175 {
10176 exp.e1 = exp.e1.modifiableLvalue(sc, exp.e1);
10177 }
10178
10179 if ((exp.e1.type.isintegral() || exp.e1.type.isfloating()) && (exp.e2.type.isintegral() || exp.e2.type.isfloating()))
10180 {
10181 Expression e0 = null;
10182 e = exp.reorderSettingAAElem(sc);
10183 e = Expression.extractLast(e, e0);
10184 assert(e == exp);
10185
Iain Buclaw9c7d5e882021-12-10 03:14:20 +010010186 if (exp.e1.op == EXP.variable)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020010187 {
10188 // Rewrite: e1 = e1 ^^ e2
10189 e = new PowExp(exp.loc, exp.e1.syntaxCopy(), exp.e2);
10190 e = new AssignExp(exp.loc, exp.e1, e);
10191 }
10192 else
10193 {
10194 // Rewrite: ref tmp = e1; tmp = tmp ^^ e2
10195 auto v = copyToTemp(STC.ref_, "__powtmp", exp.e1);
10196 auto de = new DeclarationExp(exp.e1.loc, v);
10197 auto ve = new VarExp(exp.e1.loc, v);
10198 e = new PowExp(exp.loc, ve, exp.e2);
10199 e = new AssignExp(exp.loc, new VarExp(exp.e1.loc, v), e);
10200 e = new CommaExp(exp.loc, de, e);
10201 }
10202 e = Expression.combine(e0, e);
10203 e = e.expressionSemantic(sc);
10204 result = e;
10205 return;
10206 }
10207 result = exp.incompatibleTypes();
10208 }
10209
10210 override void visit(CatAssignExp exp)
10211 {
10212 if (exp.type)
10213 {
10214 result = exp;
10215 return;
10216 }
10217
10218 //printf("CatAssignExp::semantic() %s\n", exp.toChars());
10219 Expression e = exp.op_overload(sc);
10220 if (e)
10221 {
10222 result = e;
10223 return;
10224 }
10225
Iain Buclaw235d5a92022-03-29 16:57:10 +020010226 if (SliceExp se = exp.e1.isSliceExp())
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020010227 {
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020010228 if (se.e1.type.toBasetype().ty == Tsarray)
10229 {
10230 exp.error("cannot append to static array `%s`", se.e1.type.toChars());
10231 return setError();
10232 }
10233 }
10234
10235 exp.e1 = exp.e1.modifiableLvalue(sc, exp.e1);
Iain Buclaw9c7d5e882021-12-10 03:14:20 +010010236 if (exp.e1.op == EXP.error)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020010237 {
10238 result = exp.e1;
10239 return;
10240 }
Iain Buclaw9c7d5e882021-12-10 03:14:20 +010010241 if (exp.e2.op == EXP.error)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020010242 {
10243 result = exp.e2;
10244 return;
10245 }
10246
10247 if (checkNonAssignmentArrayOp(exp.e2))
10248 return setError();
10249
10250 Type tb1 = exp.e1.type.toBasetype();
10251 Type tb1next = tb1.nextOf();
10252 Type tb2 = exp.e2.type.toBasetype();
10253
10254 /* Possibilities:
Iain Buclaw9c7d5e882021-12-10 03:14:20 +010010255 * EXP.concatenateAssign: appending T[] to T[]
10256 * EXP.concatenateElemAssign: appending T to T[]
10257 * EXP.concatenateDcharAssign: appending dchar to T[]
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020010258 */
10259 if ((tb1.ty == Tarray) &&
10260 (tb2.ty == Tarray || tb2.ty == Tsarray) &&
10261 (exp.e2.implicitConvTo(exp.e1.type) ||
10262 (tb2.nextOf().implicitConvTo(tb1next) &&
10263 (tb2.nextOf().size(Loc.initial) == tb1next.size(Loc.initial)))))
10264 {
Iain Buclaw9c7d5e882021-12-10 03:14:20 +010010265 // EXP.concatenateAssign
10266 assert(exp.op == EXP.concatenateAssign);
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020010267 if (exp.e1.checkPostblit(sc, tb1next))
10268 return setError();
10269
10270 exp.e2 = exp.e2.castTo(sc, exp.e1.type);
10271 }
10272 else if ((tb1.ty == Tarray) && exp.e2.implicitConvTo(tb1next))
10273 {
10274 /* https://issues.dlang.org/show_bug.cgi?id=19782
10275 *
10276 * If e2 is implicitly convertible to tb1next, the conversion
10277 * might be done through alias this, in which case, e2 needs to
10278 * be modified accordingly (e2 => e2.aliasthis).
10279 */
10280 if (tb2.ty == Tstruct && (cast(TypeStruct)tb2).implicitConvToThroughAliasThis(tb1next))
10281 goto Laliasthis;
10282 if (tb2.ty == Tclass && (cast(TypeClass)tb2).implicitConvToThroughAliasThis(tb1next))
10283 goto Laliasthis;
10284 // Append element
10285 if (exp.e2.checkPostblit(sc, tb2))
10286 return setError();
10287
10288 if (checkNewEscape(sc, exp.e2, false))
10289 return setError();
10290
10291 exp = new CatElemAssignExp(exp.loc, exp.type, exp.e1, exp.e2.castTo(sc, tb1next));
10292 exp.e2 = doCopyOrMove(sc, exp.e2);
10293 }
10294 else if (tb1.ty == Tarray &&
10295 (tb1next.ty == Tchar || tb1next.ty == Twchar) &&
10296 exp.e2.type.ty != tb1next.ty &&
10297 exp.e2.implicitConvTo(Type.tdchar))
10298 {
10299 // Append dchar to char[] or wchar[]
10300 exp = new CatDcharAssignExp(exp.loc, exp.type, exp.e1, exp.e2.castTo(sc, Type.tdchar));
10301
10302 /* Do not allow appending wchar to char[] because if wchar happens
10303 * to be a surrogate pair, nothing good can result.
10304 */
10305 }
10306 else
10307 {
10308 // Try alias this on first operand
10309 static Expression tryAliasThisForLhs(BinAssignExp exp, Scope* sc)
10310 {
10311 AggregateDeclaration ad1 = isAggregate(exp.e1.type);
10312 if (!ad1 || !ad1.aliasthis)
10313 return null;
10314
10315 /* Rewrite (e1 op e2) as:
10316 * (e1.aliasthis op e2)
10317 */
10318 if (isRecursiveAliasThis(exp.att1, exp.e1.type))
10319 return null;
Iain Buclaw31350632022-04-13 13:34:49 +010010320 //printf("att %s e1 = %s\n", Token.toChars(e.op), e.e1.type.toChars());
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020010321 Expression e1 = new DotIdExp(exp.loc, exp.e1, ad1.aliasthis.ident);
10322 BinExp be = cast(BinExp)exp.copy();
10323 be.e1 = e1;
10324 return be.trySemantic(sc);
10325 }
10326
10327 // Try alias this on second operand
10328 static Expression tryAliasThisForRhs(BinAssignExp exp, Scope* sc)
10329 {
10330 AggregateDeclaration ad2 = isAggregate(exp.e2.type);
10331 if (!ad2 || !ad2.aliasthis)
10332 return null;
10333 /* Rewrite (e1 op e2) as:
10334 * (e1 op e2.aliasthis)
10335 */
10336 if (isRecursiveAliasThis(exp.att2, exp.e2.type))
10337 return null;
Iain Buclaw31350632022-04-13 13:34:49 +010010338 //printf("att %s e2 = %s\n", Token.toChars(e.op), e.e2.type.toChars());
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020010339 Expression e2 = new DotIdExp(exp.loc, exp.e2, ad2.aliasthis.ident);
10340 BinExp be = cast(BinExp)exp.copy();
10341 be.e2 = e2;
10342 return be.trySemantic(sc);
10343 }
10344
10345 Laliasthis:
10346 result = tryAliasThisForLhs(exp, sc);
10347 if (result)
10348 return;
10349
10350 result = tryAliasThisForRhs(exp, sc);
10351 if (result)
10352 return;
10353
10354 exp.error("cannot append type `%s` to type `%s`", tb2.toChars(), tb1.toChars());
10355 return setError();
10356 }
10357
10358 if (exp.e2.checkValue() || exp.e2.checkSharedAccess(sc))
10359 return setError();
10360
10361 exp.type = exp.e1.type;
10362 auto res = exp.reorderSettingAAElem(sc);
Iain Buclaw5eb99272022-05-16 18:30:46 +020010363 if (exp.op == EXP.concatenateElemAssign || exp.op == EXP.concatenateDcharAssign)
Iain Buclaw31350632022-04-13 13:34:49 +010010364 checkAssignEscape(sc, res, false, false);
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020010365 result = res;
Iain Buclaw5eb99272022-05-16 18:30:46 +020010366
10367 if ((exp.op == EXP.concatenateAssign || exp.op == EXP.concatenateElemAssign) &&
10368 !(sc.flags & (SCOPE.ctfe | SCOPE.compile)))
10369 {
10370 // if aa ordering is triggered, `res` will be a CommaExp
10371 // and `.e2` will be the rewritten original expression.
10372
10373 // `output` will point to the expression that the lowering will overwrite
10374 Expression* output;
10375 if (auto comma = res.isCommaExp())
10376 {
10377 output = &comma.e2;
10378 // manual cast because it could be either CatAssignExp or CatElemAssignExp
10379 exp = cast(CatAssignExp)comma.e2;
10380 }
10381 else
10382 {
10383 output = &result;
10384 exp = cast(CatAssignExp)result;
10385 }
10386
10387 if (exp.op == EXP.concatenateAssign)
10388 {
10389 Identifier hook = global.params.tracegc ? Id._d_arrayappendTTrace : Id._d_arrayappendT;
10390
10391 if (!verifyHookExist(exp.loc, *sc, hook, "appending array to arrays", Id.object))
10392 return setError();
10393
10394 // Lower to object._d_arrayappendT{,Trace}({file, line, funcname}, e1, e2)
10395 Expression id = new IdentifierExp(exp.loc, Id.empty);
10396 id = new DotIdExp(exp.loc, id, Id.object);
10397 id = new DotIdExp(exp.loc, id, hook);
10398
10399 auto arguments = new Expressions();
10400 arguments.reserve(5);
10401 if (global.params.tracegc)
10402 {
10403 auto funcname = (sc.callsc && sc.callsc.func) ? sc.callsc.func.toPrettyChars() : sc.func.toPrettyChars();
10404 arguments.push(new StringExp(exp.loc, exp.loc.filename.toDString()));
10405 arguments.push(new IntegerExp(exp.loc, exp.loc.linnum, Type.tint32));
10406 arguments.push(new StringExp(exp.loc, funcname.toDString()));
10407 }
10408
10409 arguments.push(exp.e1);
10410 arguments.push(exp.e2);
10411 Expression ce = new CallExp(exp.loc, id, arguments);
10412 *output = ce.expressionSemantic(sc);
10413 }
10414 else if (exp.op == EXP.concatenateElemAssign)
10415 {
10416 /* Do not lower concats to the indices array returned by
10417 *`static foreach`, as this array is only used at compile-time.
10418 */
10419 if (auto ve = exp.e1.isVarExp)
10420 {
10421 import core.stdc.ctype : isdigit;
10422 // The name of the indices array that static foreach loops uses.
10423 // See dmd.cond.lowerNonArrayAggregate
10424 enum varName = "__res";
10425 const(char)[] id = ve.var.ident.toString;
10426 if (ve.var.storage_class & STC.temp && id.length > varName.length &&
10427 id[0 .. varName.length] == varName && id[varName.length].isdigit)
10428 return;
10429 }
10430
10431 Identifier hook = global.params.tracegc ? Id._d_arrayappendcTXTrace : Id._d_arrayappendcTX;
10432 if (!verifyHookExist(exp.loc, *sc, Id._d_arrayappendcTXImpl, "appending element to arrays", Id.object))
10433 return setError();
10434
10435 // Lower to object._d_arrayappendcTXImpl!(typeof(e1))._d_arrayappendcTX{,Trace}(e1, 1), e1[$-1]=e2
10436 Expression id = new IdentifierExp(exp.loc, Id.empty);
10437 id = new DotIdExp(exp.loc, id, Id.object);
10438 auto tiargs = new Objects();
10439 tiargs.push(exp.e1.type);
10440 id = new DotTemplateInstanceExp(exp.loc, id, Id._d_arrayappendcTXImpl, tiargs);
10441 id = new DotIdExp(exp.loc, id, hook);
10442
10443 auto arguments = new Expressions();
10444 arguments.reserve(5);
10445 if (global.params.tracegc)
10446 {
10447 auto funcname = (sc.callsc && sc.callsc.func) ? sc.callsc.func.toPrettyChars() : sc.func.toPrettyChars();
10448 arguments.push(new StringExp(exp.loc, exp.loc.filename.toDString()));
10449 arguments.push(new IntegerExp(exp.loc, exp.loc.linnum, Type.tint32));
10450 arguments.push(new StringExp(exp.loc, funcname.toDString()));
10451 }
10452
10453 Expression eValue1;
10454 Expression value1 = extractSideEffect(sc, "__appendtmp", eValue1, exp.e1);
10455
10456 arguments.push(value1);
10457 arguments.push(new IntegerExp(exp.loc, 1, Type.tsize_t));
10458
10459 Expression ce = new CallExp(exp.loc, id, arguments);
10460
10461 Expression eValue2;
10462 Expression value2 = exp.e2;
10463 if (!value2.isVarExp() && !value2.isConst())
10464 {
10465 /* Before the template hook, this check was performed in e2ir.d
10466 * for expressions like `a ~= a[$-1]`. Here, $ will be modified
10467 * by calling `_d_arrayappendcT`, so we need to save `a[$-1]` in
10468 * a temporary variable.
10469 */
10470 value2 = extractSideEffect(sc, "__appendtmp", eValue2, value2, true);
10471 exp.e2 = value2;
10472
10473 // `__appendtmp*` will be destroyed together with the array `exp.e1`.
10474 auto vd = eValue2.isDeclarationExp().declaration.isVarDeclaration();
10475 vd.storage_class |= STC.nodtor;
Iain Buclawb6df1132022-07-26 17:42:23 +020010476 // Be more explicit that this "declaration" is local to the expression
10477 vd.storage_class |= STC.exptemp;
Iain Buclaw5eb99272022-05-16 18:30:46 +020010478 }
10479
10480 auto ale = new ArrayLengthExp(exp.loc, value1);
10481 auto elem = new IndexExp(exp.loc, value1, new MinExp(exp.loc, ale, IntegerExp.literal!1));
10482 auto ae = new ConstructExp(exp.loc, elem, value2);
10483
10484 auto e0 = Expression.combine(ce, ae).expressionSemantic(sc);
10485 e0 = Expression.combine(e0, value1);
10486 e0 = Expression.combine(eValue1, e0);
10487
10488 e0 = Expression.combine(eValue2, e0);
10489
10490 *output = e0.expressionSemantic(sc);
10491 }
10492 }
10493
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020010494 }
10495
10496 override void visit(AddExp exp)
10497 {
10498 static if (LOGSEMANTIC)
10499 {
10500 printf("AddExp::semantic('%s')\n", exp.toChars());
10501 }
10502 if (exp.type)
10503 {
10504 result = exp;
10505 return;
10506 }
10507
10508 if (Expression ex = binSemanticProp(exp, sc))
10509 {
10510 result = ex;
10511 return;
10512 }
10513 Expression e = exp.op_overload(sc);
10514 if (e)
10515 {
10516 result = e;
10517 return;
10518 }
10519
Iain Buclaw0fb57032021-12-05 17:11:12 +010010520 /* ImportC: convert arrays to pointers, functions to pointers to functions
10521 */
10522 exp.e1 = exp.e1.arrayFuncConv(sc);
10523 exp.e2 = exp.e2.arrayFuncConv(sc);
10524
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020010525 Type tb1 = exp.e1.type.toBasetype();
10526 Type tb2 = exp.e2.type.toBasetype();
10527
10528 bool err = false;
10529 if (tb1.ty == Tdelegate || tb1.isPtrToFunction())
10530 {
10531 err |= exp.e1.checkArithmetic() || exp.e1.checkSharedAccess(sc);
10532 }
10533 if (tb2.ty == Tdelegate || tb2.isPtrToFunction())
10534 {
10535 err |= exp.e2.checkArithmetic() || exp.e2.checkSharedAccess(sc);
10536 }
10537 if (err)
10538 return setError();
10539
10540 if (tb1.ty == Tpointer && exp.e2.type.isintegral() || tb2.ty == Tpointer && exp.e1.type.isintegral())
10541 {
10542 result = scaleFactor(exp, sc);
10543 return;
10544 }
10545
10546 if (tb1.ty == Tpointer && tb2.ty == Tpointer)
10547 {
10548 result = exp.incompatibleTypes();
10549 return;
10550 }
10551
10552 if (Expression ex = typeCombine(exp, sc))
10553 {
10554 result = ex;
10555 return;
10556 }
10557
10558 Type tb = exp.type.toBasetype();
10559 if (tb.ty == Tarray || tb.ty == Tsarray)
10560 {
10561 if (!isArrayOpValid(exp))
10562 {
10563 result = arrayOpInvalidError(exp);
10564 return;
10565 }
10566 result = exp;
10567 return;
10568 }
10569
10570 tb1 = exp.e1.type.toBasetype();
10571 if (!target.isVectorOpSupported(tb1, exp.op, tb2))
10572 {
10573 result = exp.incompatibleTypes();
10574 return;
10575 }
10576 if ((tb1.isreal() && exp.e2.type.isimaginary()) || (tb1.isimaginary() && exp.e2.type.isreal()))
10577 {
10578 switch (exp.type.toBasetype().ty)
10579 {
10580 case Tfloat32:
10581 case Timaginary32:
10582 exp.type = Type.tcomplex32;
10583 break;
10584
10585 case Tfloat64:
10586 case Timaginary64:
10587 exp.type = Type.tcomplex64;
10588 break;
10589
10590 case Tfloat80:
10591 case Timaginary80:
10592 exp.type = Type.tcomplex80;
10593 break;
10594
10595 default:
10596 assert(0);
10597 }
10598 }
10599 result = exp;
10600 }
10601
10602 override void visit(MinExp exp)
10603 {
10604 static if (LOGSEMANTIC)
10605 {
10606 printf("MinExp::semantic('%s')\n", exp.toChars());
10607 }
10608 if (exp.type)
10609 {
10610 result = exp;
10611 return;
10612 }
10613
10614 if (Expression ex = binSemanticProp(exp, sc))
10615 {
10616 result = ex;
10617 return;
10618 }
10619 Expression e = exp.op_overload(sc);
10620 if (e)
10621 {
10622 result = e;
10623 return;
10624 }
10625
Iain Buclaw0fb57032021-12-05 17:11:12 +010010626 /* ImportC: convert arrays to pointers, functions to pointers to functions
10627 */
10628 exp.e1 = exp.e1.arrayFuncConv(sc);
10629 exp.e2 = exp.e2.arrayFuncConv(sc);
10630
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020010631 Type t1 = exp.e1.type.toBasetype();
10632 Type t2 = exp.e2.type.toBasetype();
10633
10634 bool err = false;
10635 if (t1.ty == Tdelegate || t1.isPtrToFunction())
10636 {
10637 err |= exp.e1.checkArithmetic() || exp.e1.checkSharedAccess(sc);
10638 }
10639 if (t2.ty == Tdelegate || t2.isPtrToFunction())
10640 {
10641 err |= exp.e2.checkArithmetic() || exp.e2.checkSharedAccess(sc);
10642 }
10643 if (err)
10644 return setError();
10645
10646 if (t1.ty == Tpointer)
10647 {
10648 if (t2.ty == Tpointer)
10649 {
10650 // https://dlang.org/spec/expression.html#add_expressions
10651 // "If both operands are pointers, and the operator is -, the pointers are
10652 // subtracted and the result is divided by the size of the type pointed to
10653 // by the operands. It is an error if the pointers point to different types."
10654 Type p1 = t1.nextOf();
10655 Type p2 = t2.nextOf();
10656
10657 if (!p1.equivalent(p2))
10658 {
10659 // Deprecation to remain for at least a year, after which this should be
10660 // changed to an error
10661 // See https://github.com/dlang/dmd/pull/7332
10662 deprecation(exp.loc,
10663 "cannot subtract pointers to different types: `%s` and `%s`.",
10664 t1.toChars(), t2.toChars());
10665 }
10666
10667 // Need to divide the result by the stride
10668 // Replace (ptr - ptr) with (ptr - ptr) / stride
Iain Buclawfbdaa582022-03-21 16:52:40 +010010669 long stride;
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020010670
10671 // make sure pointer types are compatible
10672 if (Expression ex = typeCombine(exp, sc))
10673 {
10674 result = ex;
10675 return;
10676 }
10677
10678 exp.type = Type.tptrdiff_t;
10679 stride = t2.nextOf().size();
10680 if (stride == 0)
10681 {
10682 e = new IntegerExp(exp.loc, 0, Type.tptrdiff_t);
10683 }
Iain Buclawfbdaa582022-03-21 16:52:40 +010010684 else if (stride == cast(long)SIZE_INVALID)
Iain Buclaw9c7d5e882021-12-10 03:14:20 +010010685 e = ErrorExp.get();
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020010686 else
10687 {
10688 e = new DivExp(exp.loc, exp, new IntegerExp(Loc.initial, stride, Type.tptrdiff_t));
10689 e.type = Type.tptrdiff_t;
10690 }
10691 }
10692 else if (t2.isintegral())
10693 e = scaleFactor(exp, sc);
10694 else
10695 {
10696 exp.error("can't subtract `%s` from pointer", t2.toChars());
10697 e = ErrorExp.get();
10698 }
10699 result = e;
10700 return;
10701 }
10702 if (t2.ty == Tpointer)
10703 {
10704 exp.type = exp.e2.type;
10705 exp.error("can't subtract pointer from `%s`", exp.e1.type.toChars());
10706 return setError();
10707 }
10708
10709 if (Expression ex = typeCombine(exp, sc))
10710 {
10711 result = ex;
10712 return;
10713 }
10714
10715 Type tb = exp.type.toBasetype();
10716 if (tb.ty == Tarray || tb.ty == Tsarray)
10717 {
10718 if (!isArrayOpValid(exp))
10719 {
10720 result = arrayOpInvalidError(exp);
10721 return;
10722 }
10723 result = exp;
10724 return;
10725 }
10726
10727 t1 = exp.e1.type.toBasetype();
10728 t2 = exp.e2.type.toBasetype();
10729 if (!target.isVectorOpSupported(t1, exp.op, t2))
10730 {
10731 result = exp.incompatibleTypes();
10732 return;
10733 }
10734 if ((t1.isreal() && t2.isimaginary()) || (t1.isimaginary() && t2.isreal()))
10735 {
10736 switch (exp.type.ty)
10737 {
10738 case Tfloat32:
10739 case Timaginary32:
10740 exp.type = Type.tcomplex32;
10741 break;
10742
10743 case Tfloat64:
10744 case Timaginary64:
10745 exp.type = Type.tcomplex64;
10746 break;
10747
10748 case Tfloat80:
10749 case Timaginary80:
10750 exp.type = Type.tcomplex80;
10751 break;
10752
10753 default:
10754 assert(0);
10755 }
10756 }
10757 result = exp;
10758 return;
10759 }
10760
10761 override void visit(CatExp exp)
10762 {
10763 // https://dlang.org/spec/expression.html#cat_expressions
10764 //printf("CatExp.semantic() %s\n", toChars());
10765 if (exp.type)
10766 {
10767 result = exp;
10768 return;
10769 }
10770
10771 if (Expression ex = binSemanticProp(exp, sc))
10772 {
10773 result = ex;
10774 return;
10775 }
10776 Expression e = exp.op_overload(sc);
10777 if (e)
10778 {
10779 result = e;
10780 return;
10781 }
10782
10783 Type tb1 = exp.e1.type.toBasetype();
10784 Type tb2 = exp.e2.type.toBasetype();
10785
10786 auto f1 = checkNonAssignmentArrayOp(exp.e1);
10787 auto f2 = checkNonAssignmentArrayOp(exp.e2);
10788 if (f1 || f2)
10789 return setError();
10790
10791 Type tb1next = tb1.nextOf();
10792 Type tb2next = tb2.nextOf();
10793
10794 // Check for: array ~ array
Iain Buclaw9c7d5e882021-12-10 03:14:20 +010010795 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)))
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020010796 {
10797 /* https://issues.dlang.org/show_bug.cgi?id=9248
10798 * Here to avoid the case of:
10799 * void*[] a = [cast(void*)1];
10800 * void*[] b = [cast(void*)2];
10801 * a ~ b;
10802 * becoming:
10803 * a ~ [cast(void*)b];
10804 */
10805
10806 /* https://issues.dlang.org/show_bug.cgi?id=14682
10807 * Also to avoid the case of:
10808 * int[][] a;
10809 * a ~ [];
10810 * becoming:
10811 * a ~ cast(int[])[];
10812 */
10813 goto Lpeer;
10814 }
10815
10816 // Check for: array ~ element
10817 if ((tb1.ty == Tsarray || tb1.ty == Tarray) && tb2.ty != Tvoid)
10818 {
Iain Buclaw9c7d5e882021-12-10 03:14:20 +010010819 if (exp.e1.op == EXP.arrayLiteral)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020010820 {
10821 exp.e2 = doCopyOrMove(sc, exp.e2);
10822 // https://issues.dlang.org/show_bug.cgi?id=14686
10823 // Postblit call appears in AST, and this is
10824 // finally translated to an ArrayLiteralExp in below optimize().
10825 }
Iain Buclaw9c7d5e882021-12-10 03:14:20 +010010826 else if (exp.e1.op == EXP.string_)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020010827 {
10828 // No postblit call exists on character (integer) value.
10829 }
10830 else
10831 {
10832 if (exp.e2.checkPostblit(sc, tb2))
10833 return setError();
10834 // Postblit call will be done in runtime helper function
10835 }
10836
Iain Buclaw9c7d5e882021-12-10 03:14:20 +010010837 if (exp.e1.op == EXP.arrayLiteral && exp.e1.implicitConvTo(tb2.arrayOf()))
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020010838 {
10839 exp.e1 = exp.e1.implicitCastTo(sc, tb2.arrayOf());
10840 exp.type = tb2.arrayOf();
10841 goto L2elem;
10842 }
10843 if (exp.e2.implicitConvTo(tb1next) >= MATCH.convert)
10844 {
10845 exp.e2 = exp.e2.implicitCastTo(sc, tb1next);
10846 exp.type = tb1next.arrayOf();
10847 L2elem:
10848 if (tb2.ty == Tarray || tb2.ty == Tsarray)
10849 {
10850 // Make e2 into [e2]
10851 exp.e2 = new ArrayLiteralExp(exp.e2.loc, exp.type, exp.e2);
10852 }
10853 else if (checkNewEscape(sc, exp.e2, false))
10854 return setError();
10855 result = exp.optimize(WANTvalue);
10856 return;
10857 }
10858 }
10859 // Check for: element ~ array
10860 if ((tb2.ty == Tsarray || tb2.ty == Tarray) && tb1.ty != Tvoid)
10861 {
Iain Buclaw9c7d5e882021-12-10 03:14:20 +010010862 if (exp.e2.op == EXP.arrayLiteral)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020010863 {
10864 exp.e1 = doCopyOrMove(sc, exp.e1);
10865 }
Iain Buclaw9c7d5e882021-12-10 03:14:20 +010010866 else if (exp.e2.op == EXP.string_)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020010867 {
10868 }
10869 else
10870 {
10871 if (exp.e1.checkPostblit(sc, tb1))
10872 return setError();
10873 }
10874
Iain Buclaw9c7d5e882021-12-10 03:14:20 +010010875 if (exp.e2.op == EXP.arrayLiteral && exp.e2.implicitConvTo(tb1.arrayOf()))
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020010876 {
10877 exp.e2 = exp.e2.implicitCastTo(sc, tb1.arrayOf());
10878 exp.type = tb1.arrayOf();
10879 goto L1elem;
10880 }
10881 if (exp.e1.implicitConvTo(tb2next) >= MATCH.convert)
10882 {
10883 exp.e1 = exp.e1.implicitCastTo(sc, tb2next);
10884 exp.type = tb2next.arrayOf();
10885 L1elem:
10886 if (tb1.ty == Tarray || tb1.ty == Tsarray)
10887 {
10888 // Make e1 into [e1]
10889 exp.e1 = new ArrayLiteralExp(exp.e1.loc, exp.type, exp.e1);
10890 }
10891 else if (checkNewEscape(sc, exp.e1, false))
10892 return setError();
10893 result = exp.optimize(WANTvalue);
10894 return;
10895 }
10896 }
10897
10898 Lpeer:
10899 if ((tb1.ty == Tsarray || tb1.ty == Tarray) && (tb2.ty == Tsarray || tb2.ty == Tarray) && (tb1next.mod || tb2next.mod) && (tb1next.mod != tb2next.mod))
10900 {
10901 Type t1 = tb1next.mutableOf().constOf().arrayOf();
10902 Type t2 = tb2next.mutableOf().constOf().arrayOf();
Iain Buclaw9c7d5e882021-12-10 03:14:20 +010010903 if (exp.e1.op == EXP.string_ && !(cast(StringExp)exp.e1).committed)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020010904 exp.e1.type = t1;
10905 else
10906 exp.e1 = exp.e1.castTo(sc, t1);
Iain Buclaw9c7d5e882021-12-10 03:14:20 +010010907 if (exp.e2.op == EXP.string_ && !(cast(StringExp)exp.e2).committed)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020010908 exp.e2.type = t2;
10909 else
10910 exp.e2 = exp.e2.castTo(sc, t2);
10911 }
10912
10913 if (Expression ex = typeCombine(exp, sc))
10914 {
10915 result = ex;
10916 return;
10917 }
10918 exp.type = exp.type.toHeadMutable();
10919
10920 Type tb = exp.type.toBasetype();
10921 if (tb.ty == Tsarray)
10922 exp.type = tb.nextOf().arrayOf();
10923 if (exp.type.ty == Tarray && tb1next && tb2next && tb1next.mod != tb2next.mod)
10924 {
10925 exp.type = exp.type.nextOf().toHeadMutable().arrayOf();
10926 }
10927 if (Type tbn = tb.nextOf())
10928 {
10929 if (exp.checkPostblit(sc, tbn))
10930 return setError();
10931 }
10932 Type t1 = exp.e1.type.toBasetype();
10933 Type t2 = exp.e2.type.toBasetype();
10934 if ((t1.ty == Tarray || t1.ty == Tsarray) &&
10935 (t2.ty == Tarray || t2.ty == Tsarray))
10936 {
10937 // Normalize to ArrayLiteralExp or StringExp as far as possible
10938 e = exp.optimize(WANTvalue);
10939 }
10940 else
10941 {
10942 //printf("(%s) ~ (%s)\n", e1.toChars(), e2.toChars());
10943 result = exp.incompatibleTypes();
10944 return;
10945 }
10946
10947 result = e;
10948 }
10949
10950 override void visit(MulExp exp)
10951 {
10952 version (none)
10953 {
10954 printf("MulExp::semantic() %s\n", exp.toChars());
10955 }
10956 if (exp.type)
10957 {
10958 result = exp;
10959 return;
10960 }
10961
10962 if (Expression ex = binSemanticProp(exp, sc))
10963 {
10964 result = ex;
10965 return;
10966 }
10967 Expression e = exp.op_overload(sc);
10968 if (e)
10969 {
10970 result = e;
10971 return;
10972 }
10973
10974 if (Expression ex = typeCombine(exp, sc))
10975 {
10976 result = ex;
10977 return;
10978 }
10979
10980 Type tb = exp.type.toBasetype();
10981 if (tb.ty == Tarray || tb.ty == Tsarray)
10982 {
10983 if (!isArrayOpValid(exp))
10984 {
10985 result = arrayOpInvalidError(exp);
10986 return;
10987 }
10988 result = exp;
10989 return;
10990 }
10991
10992 if (exp.checkArithmeticBin() || exp.checkSharedAccessBin(sc))
10993 return setError();
10994
10995 if (exp.type.isfloating())
10996 {
10997 Type t1 = exp.e1.type;
10998 Type t2 = exp.e2.type;
10999
11000 if (t1.isreal())
11001 {
11002 exp.type = t2;
11003 }
11004 else if (t2.isreal())
11005 {
11006 exp.type = t1;
11007 }
11008 else if (t1.isimaginary())
11009 {
11010 if (t2.isimaginary())
11011 {
11012 switch (t1.toBasetype().ty)
11013 {
11014 case Timaginary32:
11015 exp.type = Type.tfloat32;
11016 break;
11017
11018 case Timaginary64:
11019 exp.type = Type.tfloat64;
11020 break;
11021
11022 case Timaginary80:
11023 exp.type = Type.tfloat80;
11024 break;
11025
11026 default:
11027 assert(0);
11028 }
11029
11030 // iy * iv = -yv
11031 exp.e1.type = exp.type;
11032 exp.e2.type = exp.type;
11033 e = new NegExp(exp.loc, exp);
11034 e = e.expressionSemantic(sc);
11035 result = e;
11036 return;
11037 }
11038 else
11039 exp.type = t2; // t2 is complex
11040 }
11041 else if (t2.isimaginary())
11042 {
11043 exp.type = t1; // t1 is complex
11044 }
11045 }
11046 else if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype()))
11047 {
11048 result = exp.incompatibleTypes();
11049 return;
11050 }
11051 result = exp;
11052 }
11053
11054 override void visit(DivExp exp)
11055 {
11056 if (exp.type)
11057 {
11058 result = exp;
11059 return;
11060 }
11061
11062 if (Expression ex = binSemanticProp(exp, sc))
11063 {
11064 result = ex;
11065 return;
11066 }
11067 Expression e = exp.op_overload(sc);
11068 if (e)
11069 {
11070 result = e;
11071 return;
11072 }
11073
11074 if (Expression ex = typeCombine(exp, sc))
11075 {
11076 result = ex;
11077 return;
11078 }
11079
11080 Type tb = exp.type.toBasetype();
11081 if (tb.ty == Tarray || tb.ty == Tsarray)
11082 {
11083 if (!isArrayOpValid(exp))
11084 {
11085 result = arrayOpInvalidError(exp);
11086 return;
11087 }
11088 result = exp;
11089 return;
11090 }
11091
11092 if (exp.checkArithmeticBin() || exp.checkSharedAccessBin(sc))
11093 return setError();
11094
11095 if (exp.type.isfloating())
11096 {
11097 Type t1 = exp.e1.type;
11098 Type t2 = exp.e2.type;
11099
11100 if (t1.isreal())
11101 {
11102 exp.type = t2;
11103 if (t2.isimaginary())
11104 {
11105 // x/iv = i(-x/v)
11106 exp.e2.type = t1;
11107 e = new NegExp(exp.loc, exp);
11108 e = e.expressionSemantic(sc);
11109 result = e;
11110 return;
11111 }
11112 }
11113 else if (t2.isreal())
11114 {
11115 exp.type = t1;
11116 }
11117 else if (t1.isimaginary())
11118 {
11119 if (t2.isimaginary())
11120 {
11121 switch (t1.toBasetype().ty)
11122 {
11123 case Timaginary32:
11124 exp.type = Type.tfloat32;
11125 break;
11126
11127 case Timaginary64:
11128 exp.type = Type.tfloat64;
11129 break;
11130
11131 case Timaginary80:
11132 exp.type = Type.tfloat80;
11133 break;
11134
11135 default:
11136 assert(0);
11137 }
11138 }
11139 else
11140 exp.type = t2; // t2 is complex
11141 }
11142 else if (t2.isimaginary())
11143 {
11144 exp.type = t1; // t1 is complex
11145 }
11146 }
11147 else if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype()))
11148 {
11149 result = exp.incompatibleTypes();
11150 return;
11151 }
11152 result = exp;
11153 }
11154
11155 override void visit(ModExp exp)
11156 {
11157 if (exp.type)
11158 {
11159 result = exp;
11160 return;
11161 }
11162
11163 if (Expression ex = binSemanticProp(exp, sc))
11164 {
11165 result = ex;
11166 return;
11167 }
11168 Expression e = exp.op_overload(sc);
11169 if (e)
11170 {
11171 result = e;
11172 return;
11173 }
11174
11175 if (Expression ex = typeCombine(exp, sc))
11176 {
11177 result = ex;
11178 return;
11179 }
11180
11181 Type tb = exp.type.toBasetype();
11182 if (tb.ty == Tarray || tb.ty == Tsarray)
11183 {
11184 if (!isArrayOpValid(exp))
11185 {
11186 result = arrayOpInvalidError(exp);
11187 return;
11188 }
11189 result = exp;
11190 return;
11191 }
11192 if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype()))
11193 {
11194 result = exp.incompatibleTypes();
11195 return;
11196 }
11197
11198 if (exp.checkArithmeticBin() || exp.checkSharedAccessBin(sc))
11199 return setError();
11200
11201 if (exp.type.isfloating())
11202 {
11203 exp.type = exp.e1.type;
11204 if (exp.e2.type.iscomplex())
11205 {
11206 exp.error("cannot perform modulo complex arithmetic");
11207 return setError();
11208 }
11209 }
11210 result = exp;
11211 }
11212
11213 override void visit(PowExp exp)
11214 {
11215 if (exp.type)
11216 {
11217 result = exp;
11218 return;
11219 }
11220
11221 //printf("PowExp::semantic() %s\n", toChars());
11222 if (Expression ex = binSemanticProp(exp, sc))
11223 {
11224 result = ex;
11225 return;
11226 }
11227 Expression e = exp.op_overload(sc);
11228 if (e)
11229 {
11230 result = e;
11231 return;
11232 }
11233
11234 if (Expression ex = typeCombine(exp, sc))
11235 {
11236 result = ex;
11237 return;
11238 }
11239
11240 Type tb = exp.type.toBasetype();
11241 if (tb.ty == Tarray || tb.ty == Tsarray)
11242 {
11243 if (!isArrayOpValid(exp))
11244 {
11245 result = arrayOpInvalidError(exp);
11246 return;
11247 }
11248 result = exp;
11249 return;
11250 }
11251
11252 if (exp.checkArithmeticBin() || exp.checkSharedAccessBin(sc))
11253 return setError();
11254
11255 if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype()))
11256 {
11257 result = exp.incompatibleTypes();
11258 return;
11259 }
11260
11261 // First, attempt to fold the expression.
11262 e = exp.optimize(WANTvalue);
Iain Buclaw9c7d5e882021-12-10 03:14:20 +010011263 if (e.op != EXP.pow)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020011264 {
11265 e = e.expressionSemantic(sc);
11266 result = e;
11267 return;
11268 }
11269
11270 Module mmath = loadStdMath();
11271 if (!mmath)
11272 {
11273 e.error("`%s` requires `std.math` for `^^` operators", e.toChars());
11274 return setError();
11275 }
11276 e = new ScopeExp(exp.loc, mmath);
11277
Iain Buclaw9c7d5e882021-12-10 03:14:20 +010011278 if (exp.e2.op == EXP.float64 && exp.e2.toReal() == CTFloat.half)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020011279 {
11280 // Replace e1 ^^ 0.5 with .std.math.sqrt(e1)
11281 e = new CallExp(exp.loc, new DotIdExp(exp.loc, e, Id._sqrt), exp.e1);
11282 }
11283 else
11284 {
11285 // Replace e1 ^^ e2 with .std.math.pow(e1, e2)
11286 e = new CallExp(exp.loc, new DotIdExp(exp.loc, e, Id._pow), exp.e1, exp.e2);
11287 }
11288 e = e.expressionSemantic(sc);
11289 result = e;
11290 return;
11291 }
11292
11293 override void visit(ShlExp exp)
11294 {
11295 //printf("ShlExp::semantic(), type = %p\n", type);
11296 if (exp.type)
11297 {
11298 result = exp;
11299 return;
11300 }
11301
11302 if (Expression ex = binSemanticProp(exp, sc))
11303 {
11304 result = ex;
11305 return;
11306 }
11307 Expression e = exp.op_overload(sc);
11308 if (e)
11309 {
11310 result = e;
11311 return;
11312 }
11313
11314 if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc))
11315 return setError();
11316
11317 if (!target.isVectorOpSupported(exp.e1.type.toBasetype(), exp.op, exp.e2.type.toBasetype()))
11318 {
11319 result = exp.incompatibleTypes();
11320 return;
11321 }
11322 exp.e1 = integralPromotions(exp.e1, sc);
11323 if (exp.e2.type.toBasetype().ty != Tvector)
11324 exp.e2 = exp.e2.castTo(sc, Type.tshiftcnt);
11325
11326 exp.type = exp.e1.type;
11327 result = exp;
11328 }
11329
11330 override void visit(ShrExp exp)
11331 {
11332 if (exp.type)
11333 {
11334 result = exp;
11335 return;
11336 }
11337
11338 if (Expression ex = binSemanticProp(exp, sc))
11339 {
11340 result = ex;
11341 return;
11342 }
11343 Expression e = exp.op_overload(sc);
11344 if (e)
11345 {
11346 result = e;
11347 return;
11348 }
11349
11350 if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc))
11351 return setError();
11352
11353 if (!target.isVectorOpSupported(exp.e1.type.toBasetype(), exp.op, exp.e2.type.toBasetype()))
11354 {
11355 result = exp.incompatibleTypes();
11356 return;
11357 }
11358 exp.e1 = integralPromotions(exp.e1, sc);
11359 if (exp.e2.type.toBasetype().ty != Tvector)
11360 exp.e2 = exp.e2.castTo(sc, Type.tshiftcnt);
11361
11362 exp.type = exp.e1.type;
11363 result = exp;
11364 }
11365
11366 override void visit(UshrExp exp)
11367 {
11368 if (exp.type)
11369 {
11370 result = exp;
11371 return;
11372 }
11373
11374 if (Expression ex = binSemanticProp(exp, sc))
11375 {
11376 result = ex;
11377 return;
11378 }
11379 Expression e = exp.op_overload(sc);
11380 if (e)
11381 {
11382 result = e;
11383 return;
11384 }
11385
11386 if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc))
11387 return setError();
11388
11389 if (!target.isVectorOpSupported(exp.e1.type.toBasetype(), exp.op, exp.e2.type.toBasetype()))
11390 {
11391 result = exp.incompatibleTypes();
11392 return;
11393 }
11394 exp.e1 = integralPromotions(exp.e1, sc);
11395 if (exp.e2.type.toBasetype().ty != Tvector)
11396 exp.e2 = exp.e2.castTo(sc, Type.tshiftcnt);
11397
11398 exp.type = exp.e1.type;
11399 result = exp;
11400 }
11401
11402 override void visit(AndExp exp)
11403 {
11404 if (exp.type)
11405 {
11406 result = exp;
11407 return;
11408 }
11409
11410 if (Expression ex = binSemanticProp(exp, sc))
11411 {
11412 result = ex;
11413 return;
11414 }
11415 Expression e = exp.op_overload(sc);
11416 if (e)
11417 {
11418 result = e;
11419 return;
11420 }
11421
11422 if (exp.e1.type.toBasetype().ty == Tbool && exp.e2.type.toBasetype().ty == Tbool)
11423 {
11424 exp.type = exp.e1.type;
11425 result = exp;
11426 return;
11427 }
11428
11429 if (Expression ex = typeCombine(exp, sc))
11430 {
11431 result = ex;
11432 return;
11433 }
11434
11435 Type tb = exp.type.toBasetype();
11436 if (tb.ty == Tarray || tb.ty == Tsarray)
11437 {
11438 if (!isArrayOpValid(exp))
11439 {
11440 result = arrayOpInvalidError(exp);
11441 return;
11442 }
11443 result = exp;
11444 return;
11445 }
11446 if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype()))
11447 {
11448 result = exp.incompatibleTypes();
11449 return;
11450 }
11451 if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc))
11452 return setError();
11453
11454 result = exp;
11455 }
11456
11457 override void visit(OrExp exp)
11458 {
11459 if (exp.type)
11460 {
11461 result = exp;
11462 return;
11463 }
11464
11465 if (Expression ex = binSemanticProp(exp, sc))
11466 {
11467 result = ex;
11468 return;
11469 }
11470 Expression e = exp.op_overload(sc);
11471 if (e)
11472 {
11473 result = e;
11474 return;
11475 }
11476
11477 if (exp.e1.type.toBasetype().ty == Tbool && exp.e2.type.toBasetype().ty == Tbool)
11478 {
11479 exp.type = exp.e1.type;
11480 result = exp;
11481 return;
11482 }
11483
11484 if (Expression ex = typeCombine(exp, sc))
11485 {
11486 result = ex;
11487 return;
11488 }
11489
11490 Type tb = exp.type.toBasetype();
11491 if (tb.ty == Tarray || tb.ty == Tsarray)
11492 {
11493 if (!isArrayOpValid(exp))
11494 {
11495 result = arrayOpInvalidError(exp);
11496 return;
11497 }
11498 result = exp;
11499 return;
11500 }
11501 if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype()))
11502 {
11503 result = exp.incompatibleTypes();
11504 return;
11505 }
11506 if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc))
11507 return setError();
11508
11509 result = exp;
11510 }
11511
11512 override void visit(XorExp exp)
11513 {
11514 if (exp.type)
11515 {
11516 result = exp;
11517 return;
11518 }
11519
11520 if (Expression ex = binSemanticProp(exp, sc))
11521 {
11522 result = ex;
11523 return;
11524 }
11525 Expression e = exp.op_overload(sc);
11526 if (e)
11527 {
11528 result = e;
11529 return;
11530 }
11531
11532 if (exp.e1.type.toBasetype().ty == Tbool && exp.e2.type.toBasetype().ty == Tbool)
11533 {
11534 exp.type = exp.e1.type;
11535 result = exp;
11536 return;
11537 }
11538
11539 if (Expression ex = typeCombine(exp, sc))
11540 {
11541 result = ex;
11542 return;
11543 }
11544
11545 Type tb = exp.type.toBasetype();
11546 if (tb.ty == Tarray || tb.ty == Tsarray)
11547 {
11548 if (!isArrayOpValid(exp))
11549 {
11550 result = arrayOpInvalidError(exp);
11551 return;
11552 }
11553 result = exp;
11554 return;
11555 }
11556 if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype()))
11557 {
11558 result = exp.incompatibleTypes();
11559 return;
11560 }
11561 if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc))
11562 return setError();
11563
11564 result = exp;
11565 }
11566
11567 override void visit(LogicalExp exp)
11568 {
11569 static if (LOGSEMANTIC)
11570 {
11571 printf("LogicalExp::semantic() %s\n", exp.toChars());
11572 }
11573
11574 if (exp.type)
11575 {
11576 result = exp;
11577 return;
11578 }
11579
11580 exp.setNoderefOperands();
11581
11582 Expression e1x = exp.e1.expressionSemantic(sc);
11583
11584 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
Iain Buclaw9c7d5e882021-12-10 03:14:20 +010011585 if (e1x.op == EXP.type)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020011586 e1x = resolveAliasThis(sc, e1x);
11587
11588 e1x = resolveProperties(sc, e1x);
11589 e1x = e1x.toBoolean(sc);
11590
11591 if (sc.flags & SCOPE.condition)
11592 {
11593 /* If in static if, don't evaluate e2 if we don't have to.
11594 */
11595 e1x = e1x.optimize(WANTvalue);
Iain Buclaw9c7d5e882021-12-10 03:14:20 +010011596 if (e1x.toBool().hasValue(exp.op == EXP.orOr))
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020011597 {
Iain Buclaw235d5a92022-03-29 16:57:10 +020011598 if (sc.flags & SCOPE.Cfile)
11599 result = new IntegerExp(exp.op == EXP.orOr);
11600 else
11601 result = IntegerExp.createBool(exp.op == EXP.orOr);
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020011602 return;
11603 }
11604 }
11605
11606 CtorFlow ctorflow = sc.ctorflow.clone();
11607 Expression e2x = exp.e2.expressionSemantic(sc);
11608 sc.merge(exp.loc, ctorflow);
11609 ctorflow.freeFieldinit();
11610
11611 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
Iain Buclaw9c7d5e882021-12-10 03:14:20 +010011612 if (e2x.op == EXP.type)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020011613 e2x = resolveAliasThis(sc, e2x);
11614
11615 e2x = resolveProperties(sc, e2x);
11616
11617 auto f1 = checkNonAssignmentArrayOp(e1x);
11618 auto f2 = checkNonAssignmentArrayOp(e2x);
11619 if (f1 || f2)
11620 return setError();
11621
11622 // Unless the right operand is 'void', the expression is converted to 'bool'.
11623 if (e2x.type.ty != Tvoid)
11624 e2x = e2x.toBoolean(sc);
11625
Iain Buclaw9c7d5e882021-12-10 03:14:20 +010011626 if (e2x.op == EXP.type || e2x.op == EXP.scope_)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020011627 {
11628 exp.error("`%s` is not an expression", exp.e2.toChars());
11629 return setError();
11630 }
Iain Buclaw9c7d5e882021-12-10 03:14:20 +010011631 if (e1x.op == EXP.error || e1x.type.ty == Tnoreturn)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020011632 {
11633 result = e1x;
11634 return;
11635 }
Iain Buclaw9c7d5e882021-12-10 03:14:20 +010011636 if (e2x.op == EXP.error)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020011637 {
11638 result = e2x;
11639 return;
11640 }
11641
11642 // The result type is 'bool', unless the right operand has type 'void'.
11643 if (e2x.type.ty == Tvoid)
11644 exp.type = Type.tvoid;
11645 else
Iain Buclaw235d5a92022-03-29 16:57:10 +020011646 exp.type = (sc && sc.flags & SCOPE.Cfile) ? Type.tint32 : Type.tbool;
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020011647
11648 exp.e1 = e1x;
11649 exp.e2 = e2x;
11650 result = exp;
11651 }
11652
11653
11654 override void visit(CmpExp exp)
11655 {
11656 static if (LOGSEMANTIC)
11657 {
11658 printf("CmpExp::semantic('%s')\n", exp.toChars());
11659 }
11660 if (exp.type)
11661 {
11662 result = exp;
11663 return;
11664 }
11665
11666 exp.setNoderefOperands();
11667
11668 if (Expression ex = binSemanticProp(exp, sc))
11669 {
11670 result = ex;
11671 return;
11672 }
11673 Type t1 = exp.e1.type.toBasetype();
11674 Type t2 = exp.e2.type.toBasetype();
Iain Buclaw9c7d5e882021-12-10 03:14:20 +010011675 if (t1.ty == Tclass && exp.e2.op == EXP.null_ || t2.ty == Tclass && exp.e1.op == EXP.null_)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020011676 {
11677 exp.error("do not use `null` when comparing class types");
11678 return setError();
11679 }
11680
Iain Buclawd7569182022-02-13 20:17:53 +010011681
11682 EXP cmpop = exp.op;
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020011683 if (auto e = exp.op_overload(sc, &cmpop))
11684 {
11685 if (!e.type.isscalar() && e.type.equals(exp.e1.type))
11686 {
11687 exp.error("recursive `opCmp` expansion");
11688 return setError();
11689 }
Iain Buclaw9c7d5e882021-12-10 03:14:20 +010011690 if (e.op == EXP.call)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020011691 {
Iain Buclawd7569182022-02-13 20:17:53 +010011692
11693 if (t1.ty == Tclass && t2.ty == Tclass)
11694 {
11695 // Lower to object.__cmp(e1, e2)
11696 Expression cl = new IdentifierExp(exp.loc, Id.empty);
11697 cl = new DotIdExp(exp.loc, cl, Id.object);
11698 cl = new DotIdExp(exp.loc, cl, Id.__cmp);
11699 cl = cl.expressionSemantic(sc);
11700
11701 auto arguments = new Expressions();
11702 // Check if op_overload found a better match by calling e2.opCmp(e1)
11703 // If the operands were swapped, then the result must be reversed
11704 // e1.opCmp(e2) == -e2.opCmp(e1)
11705 // cmpop takes care of this
11706 if (exp.op == cmpop)
11707 {
11708 arguments.push(exp.e1);
11709 arguments.push(exp.e2);
11710 }
11711 else
11712 {
11713 // Use better match found by op_overload
11714 arguments.push(exp.e2);
11715 arguments.push(exp.e1);
11716 }
11717
11718 cl = new CallExp(exp.loc, cl, arguments);
11719 cl = new CmpExp(cmpop, exp.loc, cl, new IntegerExp(0));
11720 result = cl.expressionSemantic(sc);
11721 return;
11722 }
11723
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020011724 e = new CmpExp(cmpop, exp.loc, e, IntegerExp.literal!0);
11725 e = e.expressionSemantic(sc);
11726 }
11727 result = e;
11728 return;
11729 }
11730
Iain Buclawd7569182022-02-13 20:17:53 +010011731
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020011732 if (Expression ex = typeCombine(exp, sc))
11733 {
11734 result = ex;
11735 return;
11736 }
11737
11738 auto f1 = checkNonAssignmentArrayOp(exp.e1);
11739 auto f2 = checkNonAssignmentArrayOp(exp.e2);
11740 if (f1 || f2)
11741 return setError();
11742
Iain Buclaw235d5a92022-03-29 16:57:10 +020011743 exp.type = (sc && sc.flags & SCOPE.Cfile) ? Type.tint32 : Type.tbool;
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020011744
11745 // Special handling for array comparisons
11746 Expression arrayLowering = null;
11747 t1 = exp.e1.type.toBasetype();
11748 t2 = exp.e2.type.toBasetype();
11749 if ((t1.ty == Tarray || t1.ty == Tsarray || t1.ty == Tpointer) && (t2.ty == Tarray || t2.ty == Tsarray || t2.ty == Tpointer))
11750 {
11751 Type t1next = t1.nextOf();
11752 Type t2next = t2.nextOf();
11753 if (t1next.implicitConvTo(t2next) < MATCH.constant && t2next.implicitConvTo(t1next) < MATCH.constant && (t1next.ty != Tvoid && t2next.ty != Tvoid))
11754 {
11755 exp.error("array comparison type mismatch, `%s` vs `%s`", t1next.toChars(), t2next.toChars());
11756 return setError();
11757 }
11758 if ((t1.ty == Tarray || t1.ty == Tsarray) && (t2.ty == Tarray || t2.ty == Tsarray))
11759 {
11760 if (!verifyHookExist(exp.loc, *sc, Id.__cmp, "comparing arrays"))
11761 return setError();
11762
11763 // Lower to object.__cmp(e1, e2)
11764 Expression al = new IdentifierExp(exp.loc, Id.empty);
11765 al = new DotIdExp(exp.loc, al, Id.object);
11766 al = new DotIdExp(exp.loc, al, Id.__cmp);
11767 al = al.expressionSemantic(sc);
11768
11769 auto arguments = new Expressions(2);
11770 (*arguments)[0] = exp.e1;
11771 (*arguments)[1] = exp.e2;
11772
11773 al = new CallExp(exp.loc, al, arguments);
11774 al = new CmpExp(exp.op, exp.loc, al, IntegerExp.literal!0);
11775
11776 arrayLowering = al;
11777 }
11778 }
11779 else if (t1.ty == Tstruct || t2.ty == Tstruct || (t1.ty == Tclass && t2.ty == Tclass))
11780 {
11781 if (t2.ty == Tstruct)
11782 exp.error("need member function `opCmp()` for %s `%s` to compare", t2.toDsymbol(sc).kind(), t2.toChars());
11783 else
11784 exp.error("need member function `opCmp()` for %s `%s` to compare", t1.toDsymbol(sc).kind(), t1.toChars());
11785 return setError();
11786 }
11787 else if (t1.iscomplex() || t2.iscomplex())
11788 {
11789 exp.error("compare not defined for complex operands");
11790 return setError();
11791 }
11792 else if (t1.ty == Taarray || t2.ty == Taarray)
11793 {
Iain Buclaw9c7d5e882021-12-10 03:14:20 +010011794 exp.error("`%s` is not defined for associative arrays", EXPtoString(exp.op).ptr);
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020011795 return setError();
11796 }
11797 else if (!target.isVectorOpSupported(t1, exp.op, t2))
11798 {
11799 result = exp.incompatibleTypes();
11800 return;
11801 }
11802 else
11803 {
11804 bool r1 = exp.e1.checkValue() || exp.e1.checkSharedAccess(sc);
11805 bool r2 = exp.e2.checkValue() || exp.e2.checkSharedAccess(sc);
11806 if (r1 || r2)
11807 return setError();
11808 }
11809
11810 //printf("CmpExp: %s, type = %s\n", e.toChars(), e.type.toChars());
11811 if (arrayLowering)
11812 {
11813 arrayLowering = arrayLowering.expressionSemantic(sc);
11814 result = arrayLowering;
11815 return;
11816 }
Iain Buclaw7e7ebe32022-10-29 09:05:54 +020011817
11818 if (t1.isTypeVector())
11819 exp.type = t1;
11820
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020011821 result = exp;
11822 return;
11823 }
11824
11825 override void visit(InExp exp)
11826 {
11827 if (exp.type)
11828 {
11829 result = exp;
11830 return;
11831 }
11832
11833 if (Expression ex = binSemanticProp(exp, sc))
11834 {
11835 result = ex;
11836 return;
11837 }
11838 Expression e = exp.op_overload(sc);
11839 if (e)
11840 {
11841 result = e;
11842 return;
11843 }
11844
11845 Type t2b = exp.e2.type.toBasetype();
11846 switch (t2b.ty)
11847 {
11848 case Taarray:
11849 {
11850 TypeAArray ta = cast(TypeAArray)t2b;
11851
11852 // Special handling for array keys
11853 if (!arrayTypeCompatibleWithoutCasting(exp.e1.type, ta.index))
11854 {
11855 // Convert key to type of key
11856 exp.e1 = exp.e1.implicitCastTo(sc, ta.index);
11857 }
11858
11859 semanticTypeInfo(sc, ta.index);
11860
11861 // Return type is pointer to value
11862 exp.type = ta.nextOf().pointerTo();
11863 break;
11864 }
11865
11866 case Terror:
11867 return setError();
11868
Iain Buclaw208fbc72022-07-06 19:45:28 +020011869 case Tarray, Tsarray:
11870 result = exp.incompatibleTypes();
11871 exp.errorSupplemental("`in` is only allowed on associative arrays");
11872 const(char)* slice = (t2b.ty == Tsarray) ? "[]" : "";
11873 exp.errorSupplemental("perhaps use `std.algorithm.find(%s, %s%s)` instead",
11874 exp.e1.toChars(), exp.e2.toChars(), slice);
11875 return;
11876
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020011877 default:
11878 result = exp.incompatibleTypes();
11879 return;
11880 }
11881 result = exp;
11882 }
11883
11884 override void visit(RemoveExp e)
11885 {
11886 if (Expression ex = binSemantic(e, sc))
11887 {
11888 result = ex;
11889 return;
11890 }
11891 result = e;
11892 }
11893
11894 override void visit(EqualExp exp)
11895 {
11896 //printf("EqualExp::semantic('%s')\n", exp.toChars());
11897 if (exp.type)
11898 {
11899 result = exp;
11900 return;
11901 }
11902
11903 exp.setNoderefOperands();
11904
11905 if (auto e = binSemanticProp(exp, sc))
11906 {
11907 result = e;
11908 return;
11909 }
Iain Buclaw9c7d5e882021-12-10 03:14:20 +010011910 if (exp.e1.op == EXP.type || exp.e2.op == EXP.type)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020011911 {
11912 /* https://issues.dlang.org/show_bug.cgi?id=12520
11913 * empty tuples are represented as types so special cases are added
11914 * so that they can be compared for equality with tuples of values.
11915 */
11916 static auto extractTypeTupAndExpTup(Expression e)
11917 {
11918 static struct Result { bool ttEmpty; bool te; }
Iain Buclaw9c7d5e882021-12-10 03:14:20 +010011919 auto tt = e.op == EXP.type ? e.isTypeExp().type.isTypeTuple() : null;
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020011920 return Result(tt && (!tt.arguments || !tt.arguments.dim), e.isTupleExp() !is null);
11921 }
11922 auto tups1 = extractTypeTupAndExpTup(exp.e1);
11923 auto tups2 = extractTypeTupAndExpTup(exp.e2);
11924 // AliasSeq!() == AliasSeq!(<at least a value>)
11925 if (tups1.ttEmpty && tups2.te)
11926 {
Iain Buclaw9c7d5e882021-12-10 03:14:20 +010011927 result = IntegerExp.createBool(exp.op != EXP.equal);
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020011928 return;
11929 }
11930 // AliasSeq!(<at least a value>) == AliasSeq!()
11931 else if (tups1.te && tups2.ttEmpty)
11932 {
Iain Buclaw9c7d5e882021-12-10 03:14:20 +010011933 result = IntegerExp.createBool(exp.op != EXP.equal);
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020011934 return;
11935 }
11936 // AliasSeq!() == AliasSeq!()
11937 else if (tups1.ttEmpty && tups2.ttEmpty)
11938 {
Iain Buclaw9c7d5e882021-12-10 03:14:20 +010011939 result = IntegerExp.createBool(exp.op == EXP.equal);
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020011940 return;
11941 }
11942 // otherwise, two types are really not comparable
11943 result = exp.incompatibleTypes();
11944 return;
11945 }
11946
11947 {
11948 auto t1 = exp.e1.type;
11949 auto t2 = exp.e2.type;
11950 if (t1.ty == Tenum && t2.ty == Tenum && !t1.equivalent(t2))
Iain Buclaw5eb99272022-05-16 18:30:46 +020011951 exp.error("comparison between different enumeration types `%s` and `%s`; If this behavior is intended consider using `std.conv.asOriginalType`",
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020011952 t1.toChars(), t2.toChars());
11953 }
11954
11955 /* Before checking for operator overloading, check to see if we're
11956 * comparing the addresses of two statics. If so, we can just see
11957 * if they are the same symbol.
11958 */
Iain Buclaw9c7d5e882021-12-10 03:14:20 +010011959 if (exp.e1.op == EXP.address && exp.e2.op == EXP.address)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020011960 {
11961 AddrExp ae1 = cast(AddrExp)exp.e1;
11962 AddrExp ae2 = cast(AddrExp)exp.e2;
Iain Buclaw9c7d5e882021-12-10 03:14:20 +010011963 if (ae1.e1.op == EXP.variable && ae2.e1.op == EXP.variable)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020011964 {
11965 VarExp ve1 = cast(VarExp)ae1.e1;
11966 VarExp ve2 = cast(VarExp)ae2.e1;
11967 if (ve1.var == ve2.var)
11968 {
11969 // They are the same, result is 'true' for ==, 'false' for !=
Iain Buclaw9c7d5e882021-12-10 03:14:20 +010011970 result = IntegerExp.createBool(exp.op == EXP.equal);
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020011971 return;
11972 }
11973 }
11974 }
11975
11976 Type t1 = exp.e1.type.toBasetype();
11977 Type t2 = exp.e2.type.toBasetype();
11978
11979 // Indicates whether the comparison of the 2 specified array types
11980 // requires an object.__equals() lowering.
11981 static bool needsDirectEq(Type t1, Type t2, Scope* sc)
11982 {
11983 Type t1n = t1.nextOf().toBasetype();
11984 Type t2n = t2.nextOf().toBasetype();
11985 if ((t1n.ty.isSomeChar && t2n.ty.isSomeChar) ||
11986 (t1n.ty == Tvoid || t2n.ty == Tvoid))
11987 {
11988 return false;
11989 }
11990 if (t1n.constOf() != t2n.constOf())
11991 return true;
11992
11993 Type t = t1n;
11994 while (t.toBasetype().nextOf())
11995 t = t.nextOf().toBasetype();
11996 if (auto ts = t.isTypeStruct())
11997 {
11998 // semanticTypeInfo() makes sure hasIdentityEquals has been computed
11999 if (global.params.useTypeInfo && Type.dtypeinfo)
12000 semanticTypeInfo(sc, ts);
12001
12002 return ts.sym.hasIdentityEquals; // has custom opEquals
12003 }
12004
12005 return false;
12006 }
12007
12008 if (auto e = exp.op_overload(sc))
12009 {
12010 result = e;
12011 return;
12012 }
12013
12014
12015 const isArrayComparison = (t1.ty == Tarray || t1.ty == Tsarray) &&
12016 (t2.ty == Tarray || t2.ty == Tsarray);
12017 const needsArrayLowering = isArrayComparison && needsDirectEq(t1, t2, sc);
12018
12019 if (!needsArrayLowering)
12020 {
12021 if (auto e = typeCombine(exp, sc))
12022 {
12023 result = e;
12024 return;
12025 }
12026 }
12027
12028 auto f1 = checkNonAssignmentArrayOp(exp.e1);
12029 auto f2 = checkNonAssignmentArrayOp(exp.e2);
12030 if (f1 || f2)
12031 return setError();
12032
Iain Buclaw235d5a92022-03-29 16:57:10 +020012033 exp.type = (sc && sc.flags & SCOPE.Cfile) ? Type.tint32 : Type.tbool;
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020012034
12035 if (!isArrayComparison)
12036 {
12037 if (exp.e1.type != exp.e2.type && exp.e1.type.isfloating() && exp.e2.type.isfloating())
12038 {
12039 // Cast both to complex
12040 exp.e1 = exp.e1.castTo(sc, Type.tcomplex80);
12041 exp.e2 = exp.e2.castTo(sc, Type.tcomplex80);
12042 }
12043 }
12044
12045 // lower some array comparisons to object.__equals(e1, e2)
12046 if (needsArrayLowering || (t1.ty == Tarray && t2.ty == Tarray))
12047 {
12048 //printf("Lowering to __equals %s %s\n", exp.e1.toChars(), exp.e2.toChars());
12049
Iain Buclawb6df1132022-07-26 17:42:23 +020012050 // https://issues.dlang.org/show_bug.cgi?id=22390
12051 // Equality comparison between array of noreturns simply lowers to length equality comparison
12052 if (t1.nextOf.isTypeNoreturn() && t2.nextOf.isTypeNoreturn())
12053 {
12054 Expression exp_l1 = new DotIdExp(exp.e1.loc, exp.e1, Id.length);
12055 Expression exp_l2 = new DotIdExp(exp.e2.loc, exp.e2, Id.length);
12056 auto e = new EqualExp(EXP.equal, exp.loc, exp_l1, exp_l2);
12057 result = e.expressionSemantic(sc);
12058 return;
12059 }
12060
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020012061 if (!verifyHookExist(exp.loc, *sc, Id.__equals, "equal checks on arrays"))
12062 return setError();
12063
12064 Expression __equals = new IdentifierExp(exp.loc, Id.empty);
12065 Identifier id = Identifier.idPool("__equals");
12066 __equals = new DotIdExp(exp.loc, __equals, Id.object);
12067 __equals = new DotIdExp(exp.loc, __equals, id);
12068
12069 auto arguments = new Expressions(2);
12070 (*arguments)[0] = exp.e1;
12071 (*arguments)[1] = exp.e2;
12072
12073 __equals = new CallExp(exp.loc, __equals, arguments);
Iain Buclaw9c7d5e882021-12-10 03:14:20 +010012074 if (exp.op == EXP.notEqual)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020012075 {
12076 __equals = new NotExp(exp.loc, __equals);
12077 }
12078 __equals = __equals.trySemantic(sc); // for better error message
12079 if (!__equals)
12080 {
12081 exp.error("incompatible types for array comparison: `%s` and `%s`",
12082 exp.e1.type.toChars(), exp.e2.type.toChars());
12083 __equals = ErrorExp.get();
12084 }
12085
12086 result = __equals;
12087 return;
12088 }
12089
12090 if (exp.e1.type.toBasetype().ty == Taarray)
12091 semanticTypeInfo(sc, exp.e1.type.toBasetype());
12092
12093
12094 if (!target.isVectorOpSupported(t1, exp.op, t2))
12095 {
12096 result = exp.incompatibleTypes();
12097 return;
12098 }
12099
Iain Buclaw7e7ebe32022-10-29 09:05:54 +020012100 if (t1.isTypeVector())
12101 exp.type = t1;
12102
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020012103 result = exp;
12104 }
12105
12106 override void visit(IdentityExp exp)
12107 {
12108 if (exp.type)
12109 {
12110 result = exp;
12111 return;
12112 }
12113
12114 exp.setNoderefOperands();
12115
12116 if (auto e = binSemanticProp(exp, sc))
12117 {
12118 result = e;
12119 return;
12120 }
12121
12122 if (auto e = typeCombine(exp, sc))
12123 {
12124 result = e;
12125 return;
12126 }
12127
12128 auto f1 = checkNonAssignmentArrayOp(exp.e1);
12129 auto f2 = checkNonAssignmentArrayOp(exp.e2);
12130 if (f1 || f2)
12131 return setError();
12132
Iain Buclaw9c7d5e882021-12-10 03:14:20 +010012133 if (exp.e1.op == EXP.type || exp.e2.op == EXP.type)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020012134 {
12135 result = exp.incompatibleTypes();
12136 return;
12137 }
12138
12139 exp.type = Type.tbool;
12140
12141 if (exp.e1.type != exp.e2.type && exp.e1.type.isfloating() && exp.e2.type.isfloating())
12142 {
12143 // Cast both to complex
12144 exp.e1 = exp.e1.castTo(sc, Type.tcomplex80);
12145 exp.e2 = exp.e2.castTo(sc, Type.tcomplex80);
12146 }
12147
12148 auto tb1 = exp.e1.type.toBasetype();
12149 auto tb2 = exp.e2.type.toBasetype();
12150 if (!target.isVectorOpSupported(tb1, exp.op, tb2))
12151 {
12152 result = exp.incompatibleTypes();
12153 return;
12154 }
12155
Iain Buclaw9c7d5e882021-12-10 03:14:20 +010012156 if (exp.e1.op == EXP.call)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020012157 exp.e1 = (cast(CallExp)exp.e1).addDtorHook(sc);
Iain Buclaw9c7d5e882021-12-10 03:14:20 +010012158 if (exp.e2.op == EXP.call)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020012159 exp.e2 = (cast(CallExp)exp.e2).addDtorHook(sc);
12160
12161 if (exp.e1.type.toBasetype().ty == Tsarray ||
12162 exp.e2.type.toBasetype().ty == Tsarray)
12163 exp.deprecation("identity comparison of static arrays "
12164 ~ "implicitly coerces them to slices, "
12165 ~ "which are compared by reference");
12166
12167 result = exp;
12168 }
12169
12170 override void visit(CondExp exp)
12171 {
12172 static if (LOGSEMANTIC)
12173 {
12174 printf("CondExp::semantic('%s')\n", exp.toChars());
12175 }
12176 if (exp.type)
12177 {
12178 result = exp;
12179 return;
12180 }
12181
Iain Buclaw235d5a92022-03-29 16:57:10 +020012182 if (auto die = exp.econd.isDotIdExp())
12183 die.noderef = true;
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020012184
12185 Expression ec = exp.econd.expressionSemantic(sc);
12186 ec = resolveProperties(sc, ec);
12187 ec = ec.toBoolean(sc);
12188
12189 CtorFlow ctorflow_root = sc.ctorflow.clone();
Iain Buclaw0fb57032021-12-05 17:11:12 +010012190 Expression e1x = exp.e1.expressionSemantic(sc).arrayFuncConv(sc);
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020012191 e1x = resolveProperties(sc, e1x);
12192
12193 CtorFlow ctorflow1 = sc.ctorflow;
12194 sc.ctorflow = ctorflow_root;
Iain Buclaw0fb57032021-12-05 17:11:12 +010012195 Expression e2x = exp.e2.expressionSemantic(sc).arrayFuncConv(sc);
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020012196 e2x = resolveProperties(sc, e2x);
12197
12198 sc.merge(exp.loc, ctorflow1);
12199 ctorflow1.freeFieldinit();
12200
Iain Buclaw9c7d5e882021-12-10 03:14:20 +010012201 if (ec.op == EXP.error)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020012202 {
12203 result = ec;
12204 return;
12205 }
12206 if (ec.type == Type.terror)
12207 return setError();
12208 exp.econd = ec;
12209
Iain Buclaw9c7d5e882021-12-10 03:14:20 +010012210 if (e1x.op == EXP.error)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020012211 {
12212 result = e1x;
12213 return;
12214 }
12215 if (e1x.type == Type.terror)
12216 return setError();
12217 exp.e1 = e1x;
12218
Iain Buclaw9c7d5e882021-12-10 03:14:20 +010012219 if (e2x.op == EXP.error)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020012220 {
12221 result = e2x;
12222 return;
12223 }
12224 if (e2x.type == Type.terror)
12225 return setError();
12226 exp.e2 = e2x;
12227
12228 auto f0 = checkNonAssignmentArrayOp(exp.econd);
12229 auto f1 = checkNonAssignmentArrayOp(exp.e1);
12230 auto f2 = checkNonAssignmentArrayOp(exp.e2);
12231 if (f0 || f1 || f2)
12232 return setError();
12233
12234 Type t1 = exp.e1.type;
12235 Type t2 = exp.e2.type;
12236 if (t1.ty == Tnoreturn)
12237 {
12238 exp.type = t2;
12239 }
12240 else if (t2.ty == Tnoreturn)
12241 {
12242 exp.type = t1;
12243 }
12244 // If either operand is void the result is void, we have to cast both
12245 // the expression to void so that we explicitly discard the expression
12246 // value if any
12247 // https://issues.dlang.org/show_bug.cgi?id=16598
12248 else if (t1.ty == Tvoid || t2.ty == Tvoid)
12249 {
12250 exp.type = Type.tvoid;
12251 exp.e1 = exp.e1.castTo(sc, exp.type);
12252 exp.e2 = exp.e2.castTo(sc, exp.type);
12253 }
12254 else if (t1 == t2)
12255 exp.type = t1;
12256 else
12257 {
12258 if (Expression ex = typeCombine(exp, sc))
12259 {
12260 result = ex;
12261 return;
12262 }
12263
12264 switch (exp.e1.type.toBasetype().ty)
12265 {
12266 case Tcomplex32:
12267 case Tcomplex64:
12268 case Tcomplex80:
12269 exp.e2 = exp.e2.castTo(sc, exp.e1.type);
12270 break;
12271 default:
12272 break;
12273 }
12274 switch (exp.e2.type.toBasetype().ty)
12275 {
12276 case Tcomplex32:
12277 case Tcomplex64:
12278 case Tcomplex80:
12279 exp.e1 = exp.e1.castTo(sc, exp.e2.type);
12280 break;
12281 default:
12282 break;
12283 }
12284 if (exp.type.toBasetype().ty == Tarray)
12285 {
12286 exp.e1 = exp.e1.castTo(sc, exp.type);
12287 exp.e2 = exp.e2.castTo(sc, exp.type);
12288 }
12289 }
12290 exp.type = exp.type.merge2();
12291 version (none)
12292 {
12293 printf("res: %s\n", exp.type.toChars());
12294 printf("e1 : %s\n", exp.e1.type.toChars());
12295 printf("e2 : %s\n", exp.e2.type.toChars());
12296 }
12297
12298 /* https://issues.dlang.org/show_bug.cgi?id=14696
12299 * If either e1 or e2 contain temporaries which need dtor,
12300 * make them conditional.
12301 * Rewrite:
12302 * cond ? (__tmp1 = ..., __tmp1) : (__tmp2 = ..., __tmp2)
12303 * to:
12304 * (auto __cond = cond) ? (... __tmp1) : (... __tmp2)
12305 * and replace edtors of __tmp1 and __tmp2 with:
12306 * __tmp1.edtor --> __cond && __tmp1.dtor()
12307 * __tmp2.edtor --> __cond || __tmp2.dtor()
12308 */
12309 exp.hookDtors(sc);
12310
12311 result = exp;
12312 }
12313
12314 override void visit(GenericExp exp)
12315 {
12316 static if (LOGSEMANTIC)
12317 {
12318 printf("GenericExp::semantic('%s')\n", exp.toChars());
12319 }
12320 // C11 6.5.1.1 Generic Selection
12321
Iain Buclaw5eb99272022-05-16 18:30:46 +020012322 auto ec = exp.cntlExp.expressionSemantic(sc).arrayFuncConv(sc);
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020012323 bool errors = ec.isErrorExp() !is null;
12324 auto tc = ec.type;
12325
12326 auto types = (*exp.types)[];
12327 foreach (i, ref t; types)
12328 {
12329 if (!t)
12330 continue; // `default:` case
12331 t = t.typeSemantic(ec.loc, sc);
12332 if (t.isTypeError())
12333 {
12334 errors = true;
12335 continue;
12336 }
12337
12338 /* C11 6.5.1-2 duplicate check
12339 */
12340 /* C11 distinguishes int, long, and long long. But D doesn't, so depending on the
12341 * C target, a long may have the same type as `int` in the D type system.
12342 * So, skip checks when this may be the case. Later pick the first match
12343 */
12344 if (
12345 (t.ty == Tint32 || t.ty == Tuns32) && target.c.longsize == 4 ||
12346 (t.ty == Tint64 || t.ty == Tuns64) && target.c.longsize == 8 ||
12347 (t.ty == Tfloat64 || t.ty == Timaginary64 || t.ty == Tcomplex64) && target.c.long_doublesize == 8
12348 )
12349 continue;
12350
12351 foreach (t2; types[0 .. i])
12352 {
12353 if (t2 && t2.equals(t))
12354 {
12355 error(ec.loc, "generic association type `%s` can only appear once", t.toChars());
12356 errors = true;
12357 break;
12358 }
12359 }
12360 }
12361
12362 auto exps = (*exp.exps)[];
12363 foreach (ref e; exps)
12364 {
12365 e = e.expressionSemantic(sc);
12366 if (e.isErrorExp())
12367 errors = true;
12368 }
12369
12370 if (errors)
12371 return setError();
12372
12373 enum size_t None = ~0;
12374 size_t imatch = None;
12375 size_t idefault = None;
12376 foreach (const i, t; types)
12377 {
12378 if (t)
12379 {
12380 /* if tc is compatible with t, it's a match
12381 * C11 6.2.7 defines a compatible type as being the same type, including qualifiers
12382 */
12383 if (tc.equals(t))
12384 {
12385 assert(imatch == None);
12386 imatch = i;
12387 break; // pick first match
12388 }
12389 }
12390 else
12391 idefault = i; // multiple defaults are not allowed, and are caught by cparse
12392 }
12393
12394 if (imatch == None)
12395 imatch = idefault;
12396 if (imatch == None)
12397 {
12398 error(exp.loc, "no compatible generic association type for controlling expression type `%s`", tc.toChars());
12399 return setError();
12400 }
12401
12402 result = exps[imatch];
12403 }
12404
12405 override void visit(FileInitExp e)
12406 {
12407 //printf("FileInitExp::semantic()\n");
12408 e.type = Type.tstring;
12409 result = e;
12410 }
12411
12412 override void visit(LineInitExp e)
12413 {
12414 e.type = Type.tint32;
12415 result = e;
12416 }
12417
12418 override void visit(ModuleInitExp e)
12419 {
12420 //printf("ModuleInitExp::semantic()\n");
12421 e.type = Type.tstring;
12422 result = e;
12423 }
12424
12425 override void visit(FuncInitExp e)
12426 {
12427 //printf("FuncInitExp::semantic()\n");
12428 e.type = Type.tstring;
12429 if (sc.func)
12430 {
12431 result = e.resolveLoc(Loc.initial, sc);
12432 return;
12433 }
12434 result = e;
12435 }
12436
12437 override void visit(PrettyFuncInitExp e)
12438 {
12439 //printf("PrettyFuncInitExp::semantic()\n");
12440 e.type = Type.tstring;
12441 if (sc.func)
12442 {
12443 result = e.resolveLoc(Loc.initial, sc);
12444 return;
12445 }
12446
12447 result = e;
12448 }
12449}
12450
12451/**********************************
12452 * Try to run semantic routines.
12453 * If they fail, return NULL.
12454 */
12455Expression trySemantic(Expression exp, Scope* sc)
12456{
12457 //printf("+trySemantic(%s)\n", exp.toChars());
12458 uint errors = global.startGagging();
12459 Expression e = expressionSemantic(exp, sc);
12460 if (global.endGagging(errors))
12461 {
12462 e = null;
12463 }
12464 //printf("-trySemantic(%s)\n", exp.toChars());
12465 return e;
12466}
12467
12468/**************************
12469 * Helper function for easy error propagation.
12470 * If error occurs, returns ErrorExp. Otherwise returns NULL.
12471 */
12472Expression unaSemantic(UnaExp e, Scope* sc)
12473{
12474 static if (LOGSEMANTIC)
12475 {
12476 printf("UnaExp::semantic('%s')\n", e.toChars());
12477 }
12478 Expression e1x = e.e1.expressionSemantic(sc);
Iain Buclaw9c7d5e882021-12-10 03:14:20 +010012479 if (e1x.op == EXP.error)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020012480 return e1x;
12481 e.e1 = e1x;
12482 return null;
12483}
12484
12485/**************************
12486 * Helper function for easy error propagation.
12487 * If error occurs, returns ErrorExp. Otherwise returns NULL.
12488 */
12489Expression binSemantic(BinExp e, Scope* sc)
12490{
12491 static if (LOGSEMANTIC)
12492 {
12493 printf("BinExp::semantic('%s')\n", e.toChars());
12494 }
12495 Expression e1x = e.e1.expressionSemantic(sc);
12496 Expression e2x = e.e2.expressionSemantic(sc);
12497
12498 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
Iain Buclaw9c7d5e882021-12-10 03:14:20 +010012499 if (e1x.op == EXP.type)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020012500 e1x = resolveAliasThis(sc, e1x);
Iain Buclaw9c7d5e882021-12-10 03:14:20 +010012501 if (e2x.op == EXP.type)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020012502 e2x = resolveAliasThis(sc, e2x);
12503
Iain Buclaw9c7d5e882021-12-10 03:14:20 +010012504 if (e1x.op == EXP.error)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020012505 return e1x;
Iain Buclaw9c7d5e882021-12-10 03:14:20 +010012506 if (e2x.op == EXP.error)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020012507 return e2x;
12508 e.e1 = e1x;
12509 e.e2 = e2x;
12510 return null;
12511}
12512
12513Expression binSemanticProp(BinExp e, Scope* sc)
12514{
12515 if (Expression ex = binSemantic(e, sc))
12516 return ex;
12517 Expression e1x = resolveProperties(sc, e.e1);
12518 Expression e2x = resolveProperties(sc, e.e2);
Iain Buclaw9c7d5e882021-12-10 03:14:20 +010012519 if (e1x.op == EXP.error)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020012520 return e1x;
Iain Buclaw9c7d5e882021-12-10 03:14:20 +010012521 if (e2x.op == EXP.error)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020012522 return e2x;
12523 e.e1 = e1x;
12524 e.e2 = e2x;
12525 return null;
12526}
12527
12528// entrypoint for semantic ExpressionSemanticVisitor
12529extern (C++) Expression expressionSemantic(Expression e, Scope* sc)
12530{
12531 scope v = new ExpressionSemanticVisitor(sc);
12532 e.accept(v);
12533 return v.result;
12534}
12535
12536Expression semanticX(DotIdExp exp, Scope* sc)
12537{
12538 //printf("DotIdExp::semanticX(this = %p, '%s')\n", this, toChars());
12539 if (Expression ex = unaSemantic(exp, sc))
12540 return ex;
12541
Iain Buclawae56e2d2022-04-21 14:25:26 +010012542 if (!(sc.flags & SCOPE.Cfile) && exp.ident == Id._mangleof)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020012543 {
12544 // symbol.mangleof
Iain Buclaw0fb57032021-12-05 17:11:12 +010012545
12546 // return mangleof as an Expression
12547 static Expression dotMangleof(const ref Loc loc, Scope* sc, Dsymbol ds)
12548 {
12549 assert(ds);
12550 if (auto f = ds.isFuncDeclaration())
12551 {
12552 if (f.checkForwardRef(loc))
12553 return ErrorExp.get();
12554
Iain Buclaw7e7ebe32022-10-29 09:05:54 +020012555 if (f.purityInprocess || f.safetyInprocess || f.nothrowInprocess || f.nogcInprocess)
Iain Buclaw0fb57032021-12-05 17:11:12 +010012556 {
12557 f.error(loc, "cannot retrieve its `.mangleof` while inferring attributes");
12558 return ErrorExp.get();
12559 }
12560 }
12561 OutBuffer buf;
12562 mangleToBuffer(ds, &buf);
12563 Expression e = new StringExp(loc, buf.extractSlice());
12564 return e.expressionSemantic(sc);
12565 }
12566
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020012567 Dsymbol ds;
12568 switch (exp.e1.op)
12569 {
Iain Buclaw9c7d5e882021-12-10 03:14:20 +010012570 case EXP.scope_: return dotMangleof(exp.loc, sc, exp.e1.isScopeExp().sds);
12571 case EXP.variable: return dotMangleof(exp.loc, sc, exp.e1.isVarExp().var);
12572 case EXP.dotVariable: return dotMangleof(exp.loc, sc, exp.e1.isDotVarExp().var);
12573 case EXP.overloadSet: return dotMangleof(exp.loc, sc, exp.e1.isOverExp().vars);
12574 case EXP.template_:
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020012575 {
Iain Buclaw0fb57032021-12-05 17:11:12 +010012576 TemplateExp te = exp.e1.isTemplateExp();
12577 return dotMangleof(exp.loc, sc, ds = te.fd ? te.fd.isDsymbol() : te.td);
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020012578 }
Iain Buclaw0fb57032021-12-05 17:11:12 +010012579
12580 default:
12581 break;
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020012582 }
12583 }
12584
Iain Buclaw0fb57032021-12-05 17:11:12 +010012585 if (exp.e1.isVarExp() && exp.e1.type.toBasetype().isTypeSArray() && exp.ident == Id.length)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020012586 {
12587 // bypass checkPurity
12588 return exp.e1.type.dotExp(sc, exp.e1, exp.ident, exp.noderef ? DotExpFlag.noDeref : 0);
12589 }
12590
Iain Buclaw0fb57032021-12-05 17:11:12 +010012591 if (!exp.e1.isDotExp())
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020012592 {
12593 exp.e1 = resolvePropertiesX(sc, exp.e1);
12594 }
Iain Buclaw0fb57032021-12-05 17:11:12 +010012595
12596 if (auto te = exp.e1.isTupleExp())
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020012597 {
Iain Buclaw0fb57032021-12-05 17:11:12 +010012598 if (exp.ident == Id.offsetof)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020012599 {
Iain Buclaw0fb57032021-12-05 17:11:12 +010012600 /* 'distribute' the .offsetof to each of the tuple elements.
12601 */
12602 auto exps = new Expressions(te.exps.dim);
12603 foreach (i, e; (*te.exps)[])
12604 {
12605 (*exps)[i] = new DotIdExp(e.loc, e, Id.offsetof);
12606 }
12607 // Don't evaluate te.e0 in runtime
12608 Expression e = new TupleExp(exp.loc, null, exps);
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020012609 e = e.expressionSemantic(sc);
Iain Buclaw0fb57032021-12-05 17:11:12 +010012610 return e;
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020012611 }
Iain Buclaw0fb57032021-12-05 17:11:12 +010012612 if (exp.ident == Id.length)
12613 {
12614 // Don't evaluate te.e0 in runtime
12615 return new IntegerExp(exp.loc, te.exps.dim, Type.tsize_t);
12616 }
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020012617 }
12618
12619 // https://issues.dlang.org/show_bug.cgi?id=14416
12620 // Template has no built-in properties except for 'stringof'.
Iain Buclaw0fb57032021-12-05 17:11:12 +010012621 if ((exp.e1.isDotTemplateExp() || exp.e1.isTemplateExp()) && exp.ident != Id.stringof)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020012622 {
12623 exp.error("template `%s` does not have property `%s`", exp.e1.toChars(), exp.ident.toChars());
12624 return ErrorExp.get();
12625 }
12626 if (!exp.e1.type)
12627 {
12628 exp.error("expression `%s` does not have property `%s`", exp.e1.toChars(), exp.ident.toChars());
12629 return ErrorExp.get();
12630 }
12631
12632 return exp;
12633}
12634
Iain Buclaw0fb57032021-12-05 17:11:12 +010012635/******************************
12636 * Resolve properties, i.e. `e1.ident`, without seeing UFCS.
12637 * Params:
12638 * exp = expression to resolve
12639 * sc = context
12640 * flag = if 1 then do not emit error messages, just return null
12641 * Returns:
12642 * resolved expression, null if error
12643 */
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020012644Expression semanticY(DotIdExp exp, Scope* sc, int flag)
12645{
12646 //printf("DotIdExp::semanticY(this = %p, '%s')\n", exp, exp.toChars());
12647
12648 //{ static int z; fflush(stdout); if (++z == 10) *(char*)0=0; }
12649
Iain Buclawae56e2d2022-04-21 14:25:26 +010012650 const cfile = (sc.flags & SCOPE.Cfile) != 0;
12651
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020012652 /* Special case: rewrite this.id and super.id
12653 * to be classtype.id and baseclasstype.id
12654 * if we have no this pointer.
12655 */
Iain Buclaw0fb57032021-12-05 17:11:12 +010012656 if ((exp.e1.isThisExp() || exp.e1.isSuperExp()) && !hasThis(sc))
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020012657 {
12658 if (AggregateDeclaration ad = sc.getStructClassScope())
12659 {
Iain Buclaw0fb57032021-12-05 17:11:12 +010012660 if (exp.e1.isThisExp())
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020012661 {
12662 exp.e1 = new TypeExp(exp.e1.loc, ad.type);
12663 }
12664 else
12665 {
Iain Buclaw0fb57032021-12-05 17:11:12 +010012666 if (auto cd = ad.isClassDeclaration())
12667 {
12668 if (cd.baseClass)
12669 exp.e1 = new TypeExp(exp.e1.loc, cd.baseClass.type);
12670 }
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020012671 }
12672 }
12673 }
12674
Iain Buclaw0fb57032021-12-05 17:11:12 +010012675 {
12676 Expression e = semanticX(exp, sc);
12677 if (e != exp)
12678 return e;
12679 }
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020012680
12681 Expression eleft;
12682 Expression eright;
Iain Buclaw0fb57032021-12-05 17:11:12 +010012683 if (auto de = exp.e1.isDotExp())
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020012684 {
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020012685 eleft = de.e1;
12686 eright = de.e2;
12687 }
12688 else
12689 {
12690 eleft = null;
12691 eright = exp.e1;
12692 }
12693
12694 Type t1b = exp.e1.type.toBasetype();
12695
Iain Buclaw0fb57032021-12-05 17:11:12 +010012696 if (auto ie = eright.isScopeExp()) // also used for template alias's
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020012697 {
Iain Buclaw0fb57032021-12-05 17:11:12 +010012698 auto flags = SearchLocalsOnly;
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020012699 /* Disable access to another module's private imports.
12700 * The check for 'is sds our current module' is because
12701 * the current module should have access to its own imports.
12702 */
12703 if (ie.sds.isModule() && ie.sds != sc._module)
12704 flags |= IgnorePrivateImports;
12705 if (sc.flags & SCOPE.ignoresymbolvisibility)
12706 flags |= IgnoreSymbolVisibility;
12707 Dsymbol s = ie.sds.search(exp.loc, exp.ident, flags);
12708 /* Check for visibility before resolving aliases because public
12709 * aliases to private symbols are public.
12710 */
12711 if (s && !(sc.flags & SCOPE.ignoresymbolvisibility) && !symbolIsVisible(sc._module, s))
12712 {
12713 s = null;
12714 }
12715 if (s)
12716 {
12717 auto p = s.isPackage();
12718 if (p && checkAccess(sc, p))
12719 {
12720 s = null;
12721 }
12722 }
12723 if (s)
12724 {
12725 // if 's' is a tuple variable, the tuple is returned.
12726 s = s.toAlias();
12727
12728 exp.checkDeprecated(sc, s);
12729 exp.checkDisabled(sc, s);
12730
Iain Buclaw0fb57032021-12-05 17:11:12 +010012731 if (auto em = s.isEnumMember())
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020012732 {
12733 return em.getVarExp(exp.loc, sc);
12734 }
Iain Buclaw0fb57032021-12-05 17:11:12 +010012735 if (auto v = s.isVarDeclaration())
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020012736 {
12737 //printf("DotIdExp:: Identifier '%s' is a variable, type '%s'\n", toChars(), v.type.toChars());
12738 if (!v.type ||
12739 !v.type.deco && v.inuse)
12740 {
12741 if (v.inuse)
12742 exp.error("circular reference to %s `%s`", v.kind(), v.toPrettyChars());
12743 else
12744 exp.error("forward reference to %s `%s`", v.kind(), v.toPrettyChars());
12745 return ErrorExp.get();
12746 }
Iain Buclaw0fb57032021-12-05 17:11:12 +010012747 if (v.type.isTypeError())
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020012748 return ErrorExp.get();
12749
12750 if ((v.storage_class & STC.manifest) && v._init && !exp.wantsym)
12751 {
12752 /* Normally, the replacement of a symbol with its initializer is supposed to be in semantic2().
12753 * Introduced by https://github.com/dlang/dmd/pull/5588 which should probably
12754 * be reverted. `wantsym` is the hack to work around the problem.
12755 */
12756 if (v.inuse)
12757 {
12758 error(exp.loc, "circular initialization of %s `%s`", v.kind(), v.toPrettyChars());
12759 return ErrorExp.get();
12760 }
Iain Buclaw0fb57032021-12-05 17:11:12 +010012761 auto e = v.expandInitializer(exp.loc);
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020012762 v.inuse++;
12763 e = e.expressionSemantic(sc);
12764 v.inuse--;
12765 return e;
12766 }
12767
Iain Buclaw0fb57032021-12-05 17:11:12 +010012768 Expression e;
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020012769 if (v.needThis())
12770 {
12771 if (!eleft)
12772 eleft = new ThisExp(exp.loc);
12773 e = new DotVarExp(exp.loc, eleft, v);
12774 e = e.expressionSemantic(sc);
12775 }
12776 else
12777 {
12778 e = new VarExp(exp.loc, v);
12779 if (eleft)
12780 {
12781 e = new CommaExp(exp.loc, eleft, e);
12782 e.type = v.type;
12783 }
12784 }
12785 e = e.deref();
12786 return e.expressionSemantic(sc);
12787 }
12788
Iain Buclaw0fb57032021-12-05 17:11:12 +010012789 if (auto f = s.isFuncDeclaration())
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020012790 {
12791 //printf("it's a function\n");
12792 if (!f.functionSemantic())
12793 return ErrorExp.get();
Iain Buclaw0fb57032021-12-05 17:11:12 +010012794 Expression e;
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020012795 if (f.needThis())
12796 {
12797 if (!eleft)
12798 eleft = new ThisExp(exp.loc);
12799 e = new DotVarExp(exp.loc, eleft, f, true);
12800 e = e.expressionSemantic(sc);
12801 }
12802 else
12803 {
12804 e = new VarExp(exp.loc, f, true);
12805 if (eleft)
12806 {
12807 e = new CommaExp(exp.loc, eleft, e);
12808 e.type = f.type;
12809 }
12810 }
12811 return e;
12812 }
12813 if (auto td = s.isTemplateDeclaration())
12814 {
Iain Buclaw0fb57032021-12-05 17:11:12 +010012815 Expression e;
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020012816 if (eleft)
12817 e = new DotTemplateExp(exp.loc, eleft, td);
12818 else
12819 e = new TemplateExp(exp.loc, td);
12820 e = e.expressionSemantic(sc);
12821 return e;
12822 }
12823 if (OverDeclaration od = s.isOverDeclaration())
12824 {
Iain Buclaw0fb57032021-12-05 17:11:12 +010012825 Expression e = new VarExp(exp.loc, od, true);
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020012826 if (eleft)
12827 {
12828 e = new CommaExp(exp.loc, eleft, e);
12829 e.type = Type.tvoid; // ambiguous type?
12830 }
Iain Buclawb6df1132022-07-26 17:42:23 +020012831 return e.expressionSemantic(sc);
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020012832 }
Iain Buclaw0fb57032021-12-05 17:11:12 +010012833 if (auto o = s.isOverloadSet())
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020012834 {
12835 //printf("'%s' is an overload set\n", o.toChars());
12836 return new OverExp(exp.loc, o);
12837 }
12838
12839 if (auto t = s.getType())
12840 {
12841 return (new TypeExp(exp.loc, t)).expressionSemantic(sc);
12842 }
12843
Iain Buclaw0fb57032021-12-05 17:11:12 +010012844 if (auto tup = s.isTupleDeclaration())
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020012845 {
12846 if (eleft)
12847 {
Iain Buclaw0fb57032021-12-05 17:11:12 +010012848 Expression e = new DotVarExp(exp.loc, eleft, tup);
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020012849 e = e.expressionSemantic(sc);
12850 return e;
12851 }
Iain Buclaw0fb57032021-12-05 17:11:12 +010012852 Expression e = new TupleExp(exp.loc, tup);
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020012853 e = e.expressionSemantic(sc);
12854 return e;
12855 }
12856
Iain Buclaw0fb57032021-12-05 17:11:12 +010012857 if (auto sds = s.isScopeDsymbol())
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020012858 {
12859 //printf("it's a ScopeDsymbol %s\n", ident.toChars());
Iain Buclaw0fb57032021-12-05 17:11:12 +010012860 Expression e = new ScopeExp(exp.loc, sds);
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020012861 e = e.expressionSemantic(sc);
12862 if (eleft)
12863 e = new DotExp(exp.loc, eleft, e);
12864 return e;
12865 }
12866
Iain Buclaw0fb57032021-12-05 17:11:12 +010012867 if (auto imp = s.isImport())
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020012868 {
Iain Buclaw0fb57032021-12-05 17:11:12 +010012869 Expression se = new ScopeExp(exp.loc, imp.pkg);
12870 return se.expressionSemantic(sc);
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020012871 }
12872 // BUG: handle other cases like in IdentifierExp::semantic()
12873 debug
12874 {
12875 printf("s = '%s', kind = '%s'\n", s.toChars(), s.kind());
12876 }
12877 assert(0);
12878 }
12879 else if (exp.ident == Id.stringof)
12880 {
Iain Buclaw0fb57032021-12-05 17:11:12 +010012881 Expression e = new StringExp(exp.loc, ie.toString());
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020012882 e = e.expressionSemantic(sc);
12883 return e;
12884 }
12885 if (ie.sds.isPackage() || ie.sds.isImport() || ie.sds.isModule())
12886 {
12887 flag = 0;
12888 }
12889 if (flag)
12890 return null;
12891 s = ie.sds.search_correct(exp.ident);
12892 if (s && symbolIsVisible(sc, s))
12893 {
12894 if (s.isPackage())
12895 exp.error("undefined identifier `%s` in %s `%s`, perhaps add `static import %s;`", exp.ident.toChars(), ie.sds.kind(), ie.sds.toPrettyChars(), s.toPrettyChars());
12896 else
12897 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());
12898 }
12899 else
12900 exp.error("undefined identifier `%s` in %s `%s`", exp.ident.toChars(), ie.sds.kind(), ie.sds.toPrettyChars());
12901 return ErrorExp.get();
12902 }
Iain Buclawae56e2d2022-04-21 14:25:26 +010012903 else if (t1b.ty == Tpointer && exp.e1.type.ty != Tenum &&
12904 !(
12905 exp.ident == Id.__sizeof ||
12906 exp.ident == Id.__xalignof ||
12907 !cfile &&
12908 (exp.ident == Id._mangleof ||
12909 exp.ident == Id.offsetof ||
12910 exp.ident == Id._init ||
12911 exp.ident == Id.stringof)
12912 ))
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020012913 {
12914 Type t1bn = t1b.nextOf();
12915 if (flag)
12916 {
Iain Buclaw0fb57032021-12-05 17:11:12 +010012917 if (AggregateDeclaration ad = isAggregate(t1bn))
12918 {
12919 if (!ad.members) // https://issues.dlang.org/show_bug.cgi?id=11312
12920 return null;
12921 }
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020012922 }
12923
12924 /* Rewrite:
12925 * p.ident
12926 * as:
12927 * (*p).ident
12928 */
12929 if (flag && t1bn.ty == Tvoid)
12930 return null;
Iain Buclaw0fb57032021-12-05 17:11:12 +010012931 Expression e = new PtrExp(exp.loc, exp.e1);
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020012932 e = e.expressionSemantic(sc);
12933 return e.type.dotExp(sc, e, exp.ident, flag | (exp.noderef ? DotExpFlag.noDeref : 0));
12934 }
12935 else if (exp.ident == Id.__xalignof &&
12936 exp.e1.isVarExp() &&
12937 exp.e1.isVarExp().var.isVarDeclaration() &&
Iain Buclaw0fb57032021-12-05 17:11:12 +010012938 !exp.e1.isVarExp().var.isVarDeclaration().alignment.isUnknown())
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020012939 {
12940 // For `x.alignof` get the alignment of the variable, not the alignment of its type
12941 const explicitAlignment = exp.e1.isVarExp().var.isVarDeclaration().alignment;
12942 const naturalAlignment = exp.e1.type.alignsize();
Iain Buclaw0fb57032021-12-05 17:11:12 +010012943 const actualAlignment = explicitAlignment.isDefault() ? naturalAlignment : explicitAlignment.get();
12944 Expression e = new IntegerExp(exp.loc, actualAlignment, Type.tsize_t);
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020012945 return e;
12946 }
Iain Buclaw5eb99272022-05-16 18:30:46 +020012947 else if ((exp.ident == Id.max || exp.ident == Id.min) &&
12948 exp.e1.isVarExp() &&
12949 exp.e1.isVarExp().var.isBitFieldDeclaration())
Iain Buclawfbdaa582022-03-21 16:52:40 +010012950 {
Iain Buclaw5eb99272022-05-16 18:30:46 +020012951 // For `x.max` and `x.min` get the max/min of the bitfield, not the max/min of its type
12952 auto bf = exp.e1.isVarExp().var.isBitFieldDeclaration();
12953 return new IntegerExp(exp.loc, bf.getMinMax(exp.ident), bf.type);
12954 }
12955 else if ((exp.ident == Id.max || exp.ident == Id.min) &&
12956 exp.e1.isDotVarExp() &&
12957 exp.e1.isDotVarExp().var.isBitFieldDeclaration())
12958 {
12959 // For `x.max` and `x.min` get the max/min of the bitfield, not the max/min of its type
12960 auto bf = exp.e1.isDotVarExp().var.isBitFieldDeclaration();
12961 return new IntegerExp(exp.loc, bf.getMinMax(exp.ident), bf.type);
Iain Buclawfbdaa582022-03-21 16:52:40 +010012962 }
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020012963 else
12964 {
Iain Buclaw0fb57032021-12-05 17:11:12 +010012965 if (exp.e1.isTypeExp() || exp.e1.isTemplateExp())
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020012966 flag = 0;
Iain Buclaw0fb57032021-12-05 17:11:12 +010012967 Expression e = exp.e1.type.dotExp(sc, exp.e1, exp.ident, flag | (exp.noderef ? DotExpFlag.noDeref : 0));
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020012968 if (e)
Iain Buclaw5eb99272022-05-16 18:30:46 +020012969 {
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020012970 e = e.expressionSemantic(sc);
Iain Buclaw5eb99272022-05-16 18:30:46 +020012971 }
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020012972 return e;
12973 }
12974}
12975
12976// Resolve e1.ident!tiargs without seeing UFCS.
12977// If flag == 1, stop "not a property" error and return NULL.
12978Expression semanticY(DotTemplateInstanceExp exp, Scope* sc, int flag)
12979{
12980 static if (LOGSEMANTIC)
12981 {
12982 printf("DotTemplateInstanceExpY::semantic('%s')\n", exp.toChars());
12983 }
12984
12985 static Expression errorExp()
12986 {
12987 return ErrorExp.get();
12988 }
12989
12990 Expression e1 = exp.e1;
12991
12992 if (exp.ti.tempdecl && exp.ti.tempdecl.parent && exp.ti.tempdecl.parent.isTemplateMixin())
12993 {
12994 // if 'ti.tempdecl' happens to be found in a mixin template don't lose that info
12995 // and do the symbol search in that context (Issue: 19476)
12996 auto tm = cast(TemplateMixin)exp.ti.tempdecl.parent;
12997 e1 = new DotExp(exp.e1.loc, exp.e1, new ScopeExp(tm.loc, tm));
12998 }
12999
13000 auto die = new DotIdExp(exp.loc, e1, exp.ti.name);
13001
13002 Expression e = die.semanticX(sc);
13003 if (e == die)
13004 {
13005 exp.e1 = die.e1; // take back
13006 Type t1b = exp.e1.type.toBasetype();
13007 if (t1b.ty == Tarray || t1b.ty == Tsarray || t1b.ty == Taarray || t1b.ty == Tnull || (t1b.isTypeBasic() && t1b.ty != Tvoid))
13008 {
13009 /* No built-in type has templatized properties, so do shortcut.
13010 * It is necessary in: 1024.max!"a < b"
13011 */
13012 if (flag)
13013 return null;
13014 }
13015 e = die.semanticY(sc, flag);
13016 if (flag)
13017 {
13018 if (!e ||
13019 isDotOpDispatch(e))
13020 {
13021 /* opDispatch!tiargs would be a function template that needs IFTI,
13022 * so it's not a template
13023 */
13024 return null;
13025 }
13026 }
13027 }
13028 assert(e);
13029
Iain Buclaw9c7d5e882021-12-10 03:14:20 +010013030 if (e.op == EXP.error)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020013031 return e;
Iain Buclaw235d5a92022-03-29 16:57:10 +020013032 if (DotVarExp dve = e.isDotVarExp())
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020013033 {
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020013034 if (FuncDeclaration fd = dve.var.isFuncDeclaration())
13035 {
13036 if (TemplateDeclaration td = fd.findTemplateDeclRoot())
13037 {
13038 e = new DotTemplateExp(dve.loc, dve.e1, td);
13039 e = e.expressionSemantic(sc);
13040 }
13041 }
13042 else if (OverDeclaration od = dve.var.isOverDeclaration())
13043 {
13044 exp.e1 = dve.e1; // pull semantic() result
13045
13046 if (!exp.findTempDecl(sc))
13047 goto Lerr;
13048 if (exp.ti.needsTypeInference(sc))
13049 return exp;
13050 exp.ti.dsymbolSemantic(sc);
13051 if (!exp.ti.inst || exp.ti.errors) // if template failed to expand
13052 return errorExp();
13053
13054 if (Declaration v = exp.ti.toAlias().isDeclaration())
13055 {
13056 if (v.type && !v.type.deco)
13057 v.type = v.type.typeSemantic(v.loc, sc);
13058 return new DotVarExp(exp.loc, exp.e1, v)
13059 .expressionSemantic(sc);
13060 }
13061 return new DotExp(exp.loc, exp.e1, new ScopeExp(exp.loc, exp.ti))
13062 .expressionSemantic(sc);
13063 }
13064 }
Iain Buclaw9c7d5e882021-12-10 03:14:20 +010013065 else if (e.op == EXP.variable)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020013066 {
13067 VarExp ve = cast(VarExp)e;
13068 if (FuncDeclaration fd = ve.var.isFuncDeclaration())
13069 {
13070 if (TemplateDeclaration td = fd.findTemplateDeclRoot())
13071 {
13072 e = new TemplateExp(ve.loc, td)
13073 .expressionSemantic(sc);
13074 }
13075 }
13076 else if (OverDeclaration od = ve.var.isOverDeclaration())
13077 {
13078 exp.ti.tempdecl = od;
13079 return new ScopeExp(exp.loc, exp.ti)
13080 .expressionSemantic(sc);
13081 }
13082 }
13083
Iain Buclaw235d5a92022-03-29 16:57:10 +020013084 if (DotTemplateExp dte = e.isDotTemplateExp())
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020013085 {
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020013086 exp.e1 = dte.e1; // pull semantic() result
13087
13088 exp.ti.tempdecl = dte.td;
13089 if (!exp.ti.semanticTiargs(sc))
13090 return errorExp();
13091 if (exp.ti.needsTypeInference(sc))
13092 return exp;
13093 exp.ti.dsymbolSemantic(sc);
13094 if (!exp.ti.inst || exp.ti.errors) // if template failed to expand
13095 return errorExp();
13096
13097 if (Declaration v = exp.ti.toAlias().isDeclaration())
13098 {
Iain Buclawec486b72022-06-13 10:41:57 +020013099 return new DotVarExp(exp.loc, exp.e1, v)
13100 .expressionSemantic(sc);
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020013101 }
13102 return new DotExp(exp.loc, exp.e1, new ScopeExp(exp.loc, exp.ti))
13103 .expressionSemantic(sc);
13104 }
Iain Buclaw9c7d5e882021-12-10 03:14:20 +010013105 else if (e.op == EXP.template_)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020013106 {
13107 exp.ti.tempdecl = (cast(TemplateExp)e).td;
13108 return new ScopeExp(exp.loc, exp.ti)
13109 .expressionSemantic(sc);
13110 }
Iain Buclaw235d5a92022-03-29 16:57:10 +020013111 else if (DotExp de = e.isDotExp())
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020013112 {
Iain Buclaw9c7d5e882021-12-10 03:14:20 +010013113 if (de.e2.op == EXP.overloadSet)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020013114 {
13115 if (!exp.findTempDecl(sc) || !exp.ti.semanticTiargs(sc))
13116 {
13117 return errorExp();
13118 }
13119 if (exp.ti.needsTypeInference(sc))
13120 return exp;
13121 exp.ti.dsymbolSemantic(sc);
13122 if (!exp.ti.inst || exp.ti.errors) // if template failed to expand
13123 return errorExp();
13124
13125 if (Declaration v = exp.ti.toAlias().isDeclaration())
13126 {
13127 if (v.type && !v.type.deco)
13128 v.type = v.type.typeSemantic(v.loc, sc);
13129 return new DotVarExp(exp.loc, exp.e1, v)
13130 .expressionSemantic(sc);
13131 }
13132 return new DotExp(exp.loc, exp.e1, new ScopeExp(exp.loc, exp.ti))
13133 .expressionSemantic(sc);
13134 }
13135 }
Iain Buclaw235d5a92022-03-29 16:57:10 +020013136 else if (OverExp oe = e.isOverExp())
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020013137 {
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020013138 exp.ti.tempdecl = oe.vars;
13139 return new ScopeExp(exp.loc, exp.ti)
13140 .expressionSemantic(sc);
13141 }
13142
13143Lerr:
13144 exp.error("`%s` isn't a template", e.toChars());
13145 return errorExp();
13146}
13147
13148/***************************************
13149 * If expression is shared, check that we can access it.
13150 * Give error message if not.
13151 *
13152 * Params:
13153 * e = expression to check
13154 * sc = context
13155 * returnRef = Whether this expression is for a `return` statement
13156 * off a `ref` function, in which case a single level
13157 * of dereference is allowed (e.g. `shared(int)*`).
13158 * Returns:
13159 * true on error
13160 */
13161bool checkSharedAccess(Expression e, Scope* sc, bool returnRef = false)
13162{
Iain Buclaw7e7ebe32022-10-29 09:05:54 +020013163 if (global.params.noSharedAccess != FeatureState.enabled ||
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020013164 sc.intypeof ||
13165 sc.flags & SCOPE.ctfe)
13166 {
13167 return false;
13168 }
13169
Iain Buclaw31350632022-04-13 13:34:49 +010013170 //printf("checkSharedAccess() `%s` returnRef: %d\n", e.toChars(), returnRef);
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020013171
Iain Buclaw31350632022-04-13 13:34:49 +010013172 /* In case we don't know which expression triggered it,
13173 * e.g. for `visit(Type)` overload
13174 */
13175 Expression original = e;
13176
13177 bool check(Expression e, bool allowRef)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020013178 {
Iain Buclaw31350632022-04-13 13:34:49 +010013179 bool sharedError(Expression e)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020013180 {
13181 // https://dlang.org/phobos/core_atomic.html
13182 e.error("direct access to shared `%s` is not allowed, see `core.atomic`", e.toChars());
Iain Buclaw31350632022-04-13 13:34:49 +010013183 return true;
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020013184 }
13185
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020013186 // Error by default
Iain Buclaw31350632022-04-13 13:34:49 +010013187 bool visit(Expression e)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020013188 {
13189 if (e.type.isShared())
Iain Buclaw31350632022-04-13 13:34:49 +010013190 return sharedError(e);
13191 return false;
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020013192 }
13193
Iain Buclaw31350632022-04-13 13:34:49 +010013194 bool visitNew(NewExp e)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020013195 {
Iain Buclaw31350632022-04-13 13:34:49 +010013196 if (e.thisexp)
13197 check(e.thisexp, false);
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020013198 // Note: This handles things like `new shared(Throwable).msg`,
13199 // where accessing `msg` would violate `shared`.
Iain Buclaw31350632022-04-13 13:34:49 +010013200 if (e.newtype.isShared())
13201 return sharedError(original);
13202 return false;
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020013203 }
13204
Iain Buclaw31350632022-04-13 13:34:49 +010013205 bool visitVar(VarExp e)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020013206 {
Iain Buclawec486b72022-06-13 10:41:57 +020013207 // https://issues.dlang.org/show_bug.cgi?id=22626
13208 // Synchronized functions don't need to use core.atomic
13209 // when accessing `this`.
13210 if (sc.func && sc.func.isSynchronized())
13211 {
13212 if (e.var.isThisDeclaration())
13213 return false;
13214 else
13215 return sharedError(e);
13216 }
13217 else if (!allowRef && e.var.type.isShared())
Iain Buclaw31350632022-04-13 13:34:49 +010013218 return sharedError(e);
Iain Buclawec486b72022-06-13 10:41:57 +020013219
Iain Buclaw31350632022-04-13 13:34:49 +010013220 return false;
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020013221 }
13222
Iain Buclaw31350632022-04-13 13:34:49 +010013223 bool visitAddr(AddrExp e)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020013224 {
Iain Buclaw31350632022-04-13 13:34:49 +010013225 return check(e.e1, true);
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020013226 }
13227
Iain Buclaw31350632022-04-13 13:34:49 +010013228 bool visitPtr(PtrExp e)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020013229 {
Iain Buclaw31350632022-04-13 13:34:49 +010013230 if (!allowRef && e.type.isShared())
13231 return sharedError(e);
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020013232
13233 if (e.e1.type.isShared())
Iain Buclaw31350632022-04-13 13:34:49 +010013234 return sharedError(e);
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020013235
Iain Buclaw31350632022-04-13 13:34:49 +010013236 return check(e.e1, false);
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020013237 }
13238
Iain Buclawec486b72022-06-13 10:41:57 +020013239 bool visitThis(ThisExp e)
13240 {
13241 if (sc.func && sc.func.isSynchronized())
13242 return false;
13243
Iain Buclawb7a586b2022-08-25 19:04:50 +020013244 if (!allowRef && e.type.isShared())
13245 return sharedError(e);
13246
13247 return false;
Iain Buclawec486b72022-06-13 10:41:57 +020013248 }
13249
Iain Buclaw31350632022-04-13 13:34:49 +010013250 bool visitDotVar(DotVarExp e)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020013251 {
Iain Buclawec486b72022-06-13 10:41:57 +020013252 //printf("dotvarexp = %s\n", e.toChars());
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020013253 auto fd = e.var.isFuncDeclaration();
13254 const sharedFunc = fd && fd.type.isShared;
Iain Buclaw31350632022-04-13 13:34:49 +010013255 // Allow using `DotVarExp` within value types
Iain Buclawec486b72022-06-13 10:41:57 +020013256 if (!allowRef && e.type.isShared() && !sharedFunc && !(sc.func && sc.func.isSynchronized()))
13257 return sharedError(e);
Iain Buclaw31350632022-04-13 13:34:49 +010013258 if (e.e1.type.isTypeSArray() || e.e1.type.isTypeStruct())
13259 return check(e.e1, allowRef);
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020013260
13261 // If we end up with a single `VarExp`, it might be a `ref` param
13262 // `shared ref T` param == `shared(T)*`.
13263 if (auto ve = e.e1.isVarExp())
13264 {
Iain Buclaw31350632022-04-13 13:34:49 +010013265 return check(e.e1, allowRef && (ve.var.storage_class & STC.ref_));
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020013266 }
13267
Iain Buclaw31350632022-04-13 13:34:49 +010013268 return check(e.e1, false);
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020013269 }
13270
Iain Buclaw31350632022-04-13 13:34:49 +010013271 bool visitIndex(IndexExp e)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020013272 {
Iain Buclaw31350632022-04-13 13:34:49 +010013273 if (!allowRef && e.type.isShared())
13274 return sharedError(e);
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020013275
13276 if (e.e1.type.isShared())
Iain Buclaw31350632022-04-13 13:34:49 +010013277 return sharedError(e);
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020013278
Iain Buclaw31350632022-04-13 13:34:49 +010013279 return check(e.e1, false);
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020013280 }
13281
Iain Buclaw31350632022-04-13 13:34:49 +010013282 bool visitComma(CommaExp e)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020013283 {
13284 // Cannot be `return ref` since we can't use the return,
13285 // but it's better to show that error than an unrelated `shared` one
Iain Buclaw31350632022-04-13 13:34:49 +010013286 return check(e.e2, true);
13287 }
13288
13289 switch (e.op)
13290 {
13291 default: return visit(e);
13292
13293 // Those have no indirections / can be ignored
13294 case EXP.call:
13295 case EXP.error:
13296 case EXP.complex80:
13297 case EXP.int64:
13298 case EXP.null_: return false;
13299
13300 case EXP.variable: return visitVar(e.isVarExp());
13301 case EXP.new_: return visitNew(e.isNewExp());
13302 case EXP.address: return visitAddr(e.isAddrExp());
13303 case EXP.star: return visitPtr(e.isPtrExp());
13304 case EXP.dotVariable: return visitDotVar(e.isDotVarExp());
13305 case EXP.index: return visitIndex(e.isIndexExp());
Iain Buclawec486b72022-06-13 10:41:57 +020013306 case EXP.this_: return visitThis(e.isThisExp());
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020013307 }
13308 }
13309
Iain Buclaw31350632022-04-13 13:34:49 +010013310 return check(e, returnRef);
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020013311}
13312
13313
13314
13315/****************************************************
13316 * Determine if `exp`, which gets its address taken, can do so safely.
13317 * Params:
13318 * sc = context
13319 * exp = expression having its address taken
13320 * v = the variable getting its address taken
13321 * Returns:
13322 * `true` if ok, `false` for error
13323 */
13324bool checkAddressVar(Scope* sc, Expression exp, VarDeclaration v)
13325{
13326 //printf("checkAddressVar(exp: %s, v: %s)\n", exp.toChars(), v.toChars());
Iain Buclawb6df1132022-07-26 17:42:23 +020013327 if (v is null)
13328 return true;
13329
13330 if (!v.canTakeAddressOf())
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020013331 {
Iain Buclawb6df1132022-07-26 17:42:23 +020013332 exp.error("cannot take address of `%s`", exp.toChars());
13333 return false;
13334 }
13335 if (sc.func && !sc.intypeof && !v.isDataseg())
13336 {
Iain Buclawb6df1132022-07-26 17:42:23 +020013337 if (global.params.useDIP1000 != FeatureState.enabled &&
13338 !(v.storage_class & STC.temp) &&
13339 sc.setUnsafe(false, exp.loc, "cannot take address of local `%s` in `@safe` function `%s`", v, sc.func))
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020013340 {
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020013341 return false;
13342 }
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020013343 }
13344 return true;
13345}
13346
Iain Buclawd97f3bc2022-06-24 19:41:41 +020013347/**************************************
13348 * This check ensures that the object in `exp` can have its address taken, or
13349 * issue a diagnostic error.
13350 * Params:
13351 * e = expression to check
13352 * sc = context
13353 * Returns:
13354 * true if the expression is addressable
13355 */
13356bool checkAddressable(Expression e, Scope* sc)
13357{
13358 Expression ex = e;
13359 while (true)
13360 {
13361 switch (ex.op)
13362 {
13363 case EXP.dotVariable:
13364 // https://issues.dlang.org/show_bug.cgi?id=22749
13365 // Error about taking address of any bit-field, regardless of
13366 // whether SCOPE.Cfile is set.
13367 if (auto bf = ex.isDotVarExp().var.isBitFieldDeclaration())
13368 {
13369 e.error("cannot take address of bit-field `%s`", bf.toChars());
13370 return false;
13371 }
13372 goto case EXP.cast_;
13373
13374 case EXP.index:
13375 ex = ex.isBinExp().e1;
13376 continue;
13377
13378 case EXP.address:
13379 case EXP.array:
13380 case EXP.cast_:
13381 ex = ex.isUnaExp().e1;
13382 continue;
13383
13384 case EXP.variable:
13385 if (sc.flags & SCOPE.Cfile)
13386 {
13387 // C11 6.5.3.2: A variable that has its address taken cannot be
13388 // stored in a register.
13389 // C11 6.3.2.1: An array that has its address computed with `[]`
13390 // or cast to an lvalue pointer cannot be stored in a register.
13391 if (ex.isVarExp().var.storage_class & STC.register)
13392 {
13393 if (e.isIndexExp())
13394 e.error("cannot index through register variable `%s`", ex.toChars());
13395 else
13396 e.error("cannot take address of register variable `%s`", ex.toChars());
13397 return false;
13398 }
13399 }
13400 break;
13401
13402 default:
13403 break;
13404 }
13405 break;
13406 }
13407 return true;
13408}
13409
Iain Buclaw7e287502022-03-13 12:28:05 +010013410
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020013411/*******************************
13412 * Checks the attributes of a function.
13413 * Purity (`pure`), safety (`@safe`), no GC allocations(`@nogc`)
13414 * and usage of `deprecated` and `@disabled`-ed symbols are checked.
13415 *
13416 * Params:
13417 * exp = expression to check attributes for
13418 * sc = scope of the function
13419 * f = function to be checked
13420 * Returns: `true` if error occur.
13421 */
13422private bool checkFunctionAttributes(Expression exp, Scope* sc, FuncDeclaration f)
13423{
13424 with(exp)
13425 {
13426 bool error = checkDisabled(sc, f);
13427 error |= checkDeprecated(sc, f);
13428 error |= checkPurity(sc, f);
13429 error |= checkSafety(sc, f);
13430 error |= checkNogc(sc, f);
13431 return error;
13432 }
13433}
13434
13435/*******************************
13436 * Helper function for `getRightThis()`.
13437 * Gets `this` of the next outer aggregate.
13438 * Params:
13439 * loc = location to use for error messages
13440 * sc = context
13441 * s = the parent symbol of the existing `this`
13442 * ad = struct or class we need the correct `this` for
13443 * e1 = existing `this`
13444 * t = type of the existing `this`
13445 * var = the specific member of ad we're accessing
13446 * flag = if true, return `null` instead of throwing an error
13447 * Returns:
13448 * Expression representing the `this` for the var
13449 */
13450Expression getThisSkipNestedFuncs(const ref Loc loc, Scope* sc, Dsymbol s, AggregateDeclaration ad, Expression e1, Type t, Dsymbol var, bool flag = false)
13451{
13452 int n = 0;
13453 while (s && s.isFuncDeclaration())
13454 {
13455 FuncDeclaration f = s.isFuncDeclaration();
13456 if (f.vthis)
13457 {
13458 n++;
13459 e1 = new VarExp(loc, f.vthis);
Iain Buclaw235d5a92022-03-29 16:57:10 +020013460 if (f.hasDualContext())
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020013461 {
13462 // (*__this)[i]
13463 if (n > 1)
13464 e1 = e1.expressionSemantic(sc);
13465 e1 = new PtrExp(loc, e1);
13466 uint i = f.followInstantiationContext(ad);
13467 e1 = new IndexExp(loc, e1, new IntegerExp(i));
13468 s = f.toParentP(ad);
13469 continue;
13470 }
13471 }
13472 else
13473 {
13474 if (flag)
13475 return null;
13476 e1.error("need `this` of type `%s` to access member `%s` from static function `%s`", ad.toChars(), var.toChars(), f.toChars());
13477 e1 = ErrorExp.get();
13478 return e1;
13479 }
13480 s = s.toParent2();
13481 }
Iain Buclaw9c7d5e882021-12-10 03:14:20 +010013482 if (n > 1 || e1.op == EXP.index)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020013483 e1 = e1.expressionSemantic(sc);
13484 if (s && e1.type.equivalent(Type.tvoidptr))
13485 {
13486 if (auto sad = s.isAggregateDeclaration())
13487 {
13488 Type ta = sad.handleType();
13489 if (ta.ty == Tstruct)
13490 ta = ta.pointerTo();
13491 e1.type = ta;
13492 }
13493 }
13494 e1.type = e1.type.addMod(t.mod);
13495 return e1;
13496}
13497
13498/*******************************
13499 * Make a dual-context container for use as a `this` argument.
13500 * Params:
13501 * loc = location to use for error messages
13502 * sc = current scope
13503 * fd = target function that will take the `this` argument
13504 * Returns:
13505 * Temporary closure variable.
13506 * Note:
13507 * The function `fd` is added to the nested references of the
13508 * newly created variable such that a closure is made for the variable when
13509 * the address of `fd` is taken.
13510 */
13511VarDeclaration makeThis2Argument(const ref Loc loc, Scope* sc, FuncDeclaration fd)
13512{
13513 Type tthis2 = Type.tvoidptr.sarrayOf(2);
13514 VarDeclaration vthis2 = new VarDeclaration(loc, tthis2, Identifier.generateId("__this"), null);
13515 vthis2.storage_class |= STC.temp;
13516 vthis2.dsymbolSemantic(sc);
13517 vthis2.parent = sc.parent;
13518 // make it a closure var
13519 assert(sc.func);
13520 sc.func.closureVars.push(vthis2);
13521 // add `fd` to the nested refs
13522 vthis2.nestedrefs.push(fd);
13523 return vthis2;
13524}
13525
13526/*******************************
13527 * Make sure that the runtime hook `id` exists.
13528 * Params:
13529 * loc = location to use for error messages
13530 * sc = current scope
13531 * id = the hook identifier
13532 * description = what the hook does
13533 * module_ = what module the hook is located in
13534 * Returns:
13535 * a `bool` indicating if the hook is present.
13536 */
13537bool verifyHookExist(const ref Loc loc, ref Scope sc, Identifier id, string description, Identifier module_ = Id.object)
13538{
13539 auto rootSymbol = sc.search(loc, Id.empty, null);
13540 if (auto moduleSymbol = rootSymbol.search(loc, module_))
13541 if (moduleSymbol.search(loc, id))
13542 return true;
13543 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);
13544 return false;
13545}
13546
13547/***************************************
13548 * Fit elements[] to the corresponding types of the `sd`'s fields.
13549 *
13550 * Params:
13551 * sd = the struct declaration
13552 * loc = location to use for error messages
13553 * sc = context
13554 * elements = explicit arguments used to construct object
13555 * stype = the constructed object type.
13556 * Returns:
13557 * false if any errors occur,
13558 * otherwise true and elements[] are rewritten for the output.
13559 */
13560private bool fit(StructDeclaration sd, const ref Loc loc, Scope* sc, Expressions* elements, Type stype)
13561{
13562 if (!elements)
13563 return true;
13564
13565 const nfields = sd.nonHiddenFields();
13566 size_t offset = 0;
13567 for (size_t i = 0; i < elements.dim; i++)
13568 {
13569 Expression e = (*elements)[i];
13570 if (!e)
13571 continue;
13572
13573 e = resolveProperties(sc, e);
13574 if (i >= nfields)
13575 {
Iain Buclawfd435682021-12-15 19:47:02 +010013576 if (i < sd.fields.dim && e.op == EXP.null_)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020013577 {
13578 // CTFE sometimes creates null as hidden pointer; we'll allow this.
13579 continue;
13580 }
Iain Buclawc43b5902022-01-02 13:36:51 +010013581 .error(loc, "more initializers than fields (%llu) of `%s`", cast(ulong)nfields, sd.toChars());
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020013582 return false;
13583 }
13584 VarDeclaration v = sd.fields[i];
13585 if (v.offset < offset)
13586 {
13587 .error(loc, "overlapping initialization for `%s`", v.toChars());
13588 if (!sd.isUnionDeclaration())
13589 {
13590 enum errorMsg = "`struct` initializers that contain anonymous unions" ~
13591 " must initialize only the first member of a `union`. All subsequent" ~
13592 " non-overlapping fields are default initialized";
13593 .errorSupplemental(loc, errorMsg);
13594 }
13595 return false;
13596 }
Iain Buclaw9c7d5e882021-12-10 03:14:20 +010013597 const vsize = v.type.size();
13598 if (vsize == SIZE_INVALID)
13599 return false;
13600 offset = cast(uint)(v.offset + vsize);
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020013601
13602 Type t = v.type;
13603 if (stype)
13604 t = t.addMod(stype.mod);
13605 Type origType = t;
13606 Type tb = t.toBasetype();
13607
13608 const hasPointers = tb.hasPointers();
13609 if (hasPointers)
13610 {
Iain Buclaw0fb57032021-12-05 17:11:12 +010013611 if ((!stype.alignment.isDefault() && stype.alignment.get() < target.ptrsize ||
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020013612 (v.offset & (target.ptrsize - 1))) &&
Iain Buclaw610d7892022-05-27 19:36:06 +020013613 (sc.setUnsafe(false, loc,
Iain Buclaw5eb99272022-05-16 18:30:46 +020013614 "field `%s.%s` cannot assign to misaligned pointers in `@safe` code", sd, v)))
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020013615 {
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020013616 return false;
13617 }
13618 }
13619
13620 /* Look for case of initializing a static array with a too-short
13621 * string literal, such as:
13622 * char[5] foo = "abc";
13623 * Allow this by doing an explicit cast, which will lengthen the string
13624 * literal.
13625 */
Iain Buclaw9c7d5e882021-12-10 03:14:20 +010013626 if (e.op == EXP.string_ && tb.ty == Tsarray)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020013627 {
13628 StringExp se = cast(StringExp)e;
13629 Type typeb = se.type.toBasetype();
13630 TY tynto = tb.nextOf().ty;
13631 if (!se.committed &&
13632 (typeb.ty == Tarray || typeb.ty == Tsarray) && tynto.isSomeChar &&
13633 se.numberOfCodeUnits(tynto) < (cast(TypeSArray)tb).dim.toInteger())
13634 {
13635 e = se.castTo(sc, t);
13636 goto L1;
13637 }
13638 }
13639
13640 while (!e.implicitConvTo(t) && tb.ty == Tsarray)
13641 {
13642 /* Static array initialization, as in:
13643 * T[3][5] = e;
13644 */
13645 t = tb.nextOf();
13646 tb = t.toBasetype();
13647 }
13648 if (!e.implicitConvTo(t))
13649 t = origType; // restore type for better diagnostic
13650
13651 e = e.implicitCastTo(sc, t);
13652 L1:
Iain Buclaw9c7d5e882021-12-10 03:14:20 +010013653 if (e.op == EXP.error)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020013654 return false;
13655
13656 (*elements)[i] = doCopyOrMove(sc, e);
13657 }
13658 return true;
13659}
13660
13661
13662/**
13663 * Returns `em` as a VariableExp
13664 * Params:
13665 * em = the EnumMember to wrap
13666 * loc = location of use of em
13667 * sc = scope of use of em
13668 * Returns:
13669 * VarExp referenceing `em` or ErrorExp if `em` if disabled/deprecated
13670 */
13671Expression getVarExp(EnumMember em, const ref Loc loc, Scope* sc)
13672{
13673 dsymbolSemantic(em, sc);
13674 if (em.errors)
13675 return ErrorExp.get();
13676 em.checkDisabled(loc, sc);
13677
13678 if (em.depdecl && !em.depdecl._scope)
13679 em.depdecl._scope = sc;
13680 em.checkDeprecated(loc, sc);
13681
13682 if (em.errors)
13683 return ErrorExp.get();
13684 Expression e = new VarExp(loc, em);
Iain Buclawd7569182022-02-13 20:17:53 +010013685 e = e.expressionSemantic(sc);
13686 if (!(sc.flags & SCOPE.Cfile) && em.isCsymbol())
13687 {
13688 /* C11 types them as int. But if in D file,
13689 * type qualified names as the enum
13690 */
13691 e.type = em.parent.isEnumDeclaration().type;
13692 assert(e.type);
13693 }
13694 return e;
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020013695}
13696
13697
13698/*****************************
13699 * Try to treat `exp` as a boolean,
13700 * Params:
13701 * exp = the expression
13702 * sc = scope to evalute `exp` in
13703 * Returns:
13704 * Modified expression on success, ErrorExp on error
13705 */
13706Expression toBoolean(Expression exp, Scope* sc)
13707{
13708 switch(exp.op)
13709 {
Iain Buclaw9c7d5e882021-12-10 03:14:20 +010013710 case EXP.delete_:
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020013711 exp.error("`delete` does not give a boolean result");
13712 return ErrorExp.get();
13713
Iain Buclaw9c7d5e882021-12-10 03:14:20 +010013714 case EXP.comma:
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020013715 auto ce = exp.isCommaExp();
13716 auto ex2 = ce.e2.toBoolean(sc);
Iain Buclaw9c7d5e882021-12-10 03:14:20 +010013717 if (ex2.op == EXP.error)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020013718 return ex2;
13719 ce.e2 = ex2;
13720 ce.type = ce.e2.type;
13721 return ce;
13722
Iain Buclaw9c7d5e882021-12-10 03:14:20 +010013723 case EXP.assign:
13724 case EXP.construct:
13725 case EXP.blit:
Iain Buclawd7569182022-02-13 20:17:53 +010013726 if (sc.flags & SCOPE.Cfile)
13727 return exp;
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020013728 // Things like:
13729 // if (a = b) ...
13730 // are usually mistakes.
13731 exp.error("assignment cannot be used as a condition, perhaps `==` was meant?");
13732 return ErrorExp.get();
13733
13734 //LogicalExp
Iain Buclaw9c7d5e882021-12-10 03:14:20 +010013735 case EXP.andAnd:
13736 case EXP.orOr:
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020013737 auto le = exp.isLogicalExp();
13738 auto ex2 = le.e2.toBoolean(sc);
Iain Buclaw9c7d5e882021-12-10 03:14:20 +010013739 if (ex2.op == EXP.error)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020013740 return ex2;
13741 le.e2 = ex2;
13742 return le;
13743
Iain Buclaw9c7d5e882021-12-10 03:14:20 +010013744 case EXP.question:
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020013745 auto ce = exp.isCondExp();
13746 auto ex1 = ce.e1.toBoolean(sc);
13747 auto ex2 = ce.e2.toBoolean(sc);
Iain Buclaw9c7d5e882021-12-10 03:14:20 +010013748 if (ex1.op == EXP.error)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020013749 return ex1;
Iain Buclaw9c7d5e882021-12-10 03:14:20 +010013750 if (ex2.op == EXP.error)
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020013751 return ex2;
13752 ce.e1 = ex1;
13753 ce.e2 = ex2;
13754 return ce;
13755
13756
13757 default:
13758 // Default is 'yes' - do nothing
Iain Buclaw235d5a92022-03-29 16:57:10 +020013759 Expression e = arrayFuncConv(exp, sc);
13760 Type t = e.type;
Iain Buclaw5fee5ec32019-06-18 20:42:10 +020013761 Type tb = t.toBasetype();
13762 Type att = null;
13763
13764 while (1)
13765 {
13766 // Structs can be converted to bool using opCast(bool)()
13767 if (auto ts = tb.isTypeStruct())
13768 {
13769 AggregateDeclaration ad = ts.sym;
13770 /* Don't really need to check for opCast first, but by doing so we
13771 * get better error messages if it isn't there.
13772 */
13773 if (Dsymbol fd = search_function(ad, Id._cast))
13774 {
13775 e = new CastExp(exp.loc, e, Type.tbool);
13776 e = e.expressionSemantic(sc);
13777 return e;
13778 }
13779
13780 // Forward to aliasthis.
13781 if (ad.aliasthis && !isRecursiveAliasThis(att, tb))
13782 {
13783 e = resolveAliasThis(sc, e);
13784 t = e.type;
13785 tb = e.type.toBasetype();
13786 continue;
13787 }
13788 }
13789 break;
13790 }
13791
13792 if (!t.isBoolean())
13793 {
13794 if (tb != Type.terror)
13795 exp.error("expression `%s` of type `%s` does not have a boolean value",
13796 exp.toChars(), t.toChars());
13797 return ErrorExp.get();
13798 }
13799 return e;
13800 }
13801}