]> gcc.gnu.org Git - gcc.git/blame - gcc/d/dmd/expression.d
d: Merge upstream dmd, druntime c8ae4adb2e, phobos 792c8b7c1.
[gcc.git] / gcc / d / dmd / expression.d
CommitLineData
5fee5ec3
IB
1/**
2 * Defines the bulk of the classes which represent the AST at the expression level.
3 *
4 * Specification: ($LINK2 https://dlang.org/spec/expression.html, Expressions)
5 *
c43b5909
IB
6 * Copyright: Copyright (C) 1999-2022 by The D Language Foundation, All Rights Reserved
7 * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
8 * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
5fee5ec3
IB
9 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/expression.d, _expression.d)
10 * Documentation: https://dlang.org/phobos/dmd_expression.html
11 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/expression.d
12 */
13
14module dmd.expression;
15
16import core.stdc.stdarg;
17import core.stdc.stdio;
18import core.stdc.string;
19
20import dmd.aggregate;
21import dmd.aliasthis;
22import dmd.apply;
23import dmd.arrayop;
24import dmd.arraytypes;
25import dmd.astenums;
26import dmd.ast_node;
27import dmd.gluelayer;
5fee5ec3
IB
28import dmd.constfold;
29import dmd.ctfeexpr;
30import dmd.ctorflow;
31import dmd.dcast;
32import dmd.dclass;
33import dmd.declaration;
34import dmd.delegatize;
35import dmd.dimport;
36import dmd.dinterpret;
37import dmd.dmodule;
38import dmd.dscope;
39import dmd.dstruct;
40import dmd.dsymbol;
41import dmd.dsymbolsem;
42import dmd.dtemplate;
43import dmd.errors;
44import dmd.escape;
45import dmd.expressionsem;
46import dmd.func;
47import dmd.globals;
48import dmd.hdrgen;
49import dmd.id;
50import dmd.identifier;
51import dmd.init;
52import dmd.inline;
53import dmd.mtype;
54import dmd.nspace;
55import dmd.objc;
56import dmd.opover;
57import dmd.optimize;
c43b5909 58import dmd.root.complex;
5fee5ec3
IB
59import dmd.root.ctfloat;
60import dmd.root.filename;
0fb57034 61import dmd.common.outbuffer;
9c7d5e88 62import dmd.root.optional;
5fee5ec3
IB
63import dmd.root.rmem;
64import dmd.root.rootobject;
65import dmd.root.string;
c43b5909 66import dmd.root.utf;
5fee5ec3
IB
67import dmd.safe;
68import dmd.sideeffect;
69import dmd.target;
70import dmd.tokens;
71import dmd.typesem;
5fee5ec3
IB
72import dmd.visitor;
73
74enum LOGSEMANTIC = false;
7e287503 75
5fee5ec3
IB
76void emplaceExp(T : Expression, Args...)(void* p, Args args)
77{
7e287503
IB
78 static if (__VERSION__ < 2099)
79 const init = typeid(T).initializer;
80 else
81 const init = __traits(initSymbol, T);
82 p[0 .. __traits(classInstanceSize, T)] = init[];
83 (cast(T)p).__ctor(args);
5fee5ec3
IB
84}
85
86void emplaceExp(T : UnionExp)(T* p, Expression e)
87{
88 memcpy(p, cast(void*)e, e.size);
89}
90
8977f4be 91/// Return value for `checkModifiable`
5fee5ec3
IB
92enum Modifiable
93{
94 /// Not modifiable
95 no,
96 /// Modifiable (the type is mutable)
97 yes,
98 /// Modifiable because it is initialization
99 initialization,
100}
101/**
102 * Specifies how the checkModify deals with certain situations
103 */
104enum ModifyFlags
105{
106 /// Issue error messages on invalid modifications of the variable
107 none,
108 /// No errors are emitted for invalid modifications
109 noError = 0x1,
110 /// The modification occurs for a subfield of the current variable
111 fieldAssign = 0x2,
112}
113
114/****************************************
115 * Find the first non-comma expression.
116 * Params:
117 * e = Expressions connected by commas
118 * Returns:
119 * left-most non-comma expression
120 */
121inout(Expression) firstComma(inout Expression e)
122{
123 Expression ex = cast()e;
9c7d5e88 124 while (ex.op == EXP.comma)
5fee5ec3
IB
125 ex = (cast(CommaExp)ex).e1;
126 return cast(inout)ex;
127
128}
129
130/****************************************
131 * Find the last non-comma expression.
132 * Params:
133 * e = Expressions connected by commas
134 * Returns:
135 * right-most non-comma expression
136 */
137
138inout(Expression) lastComma(inout Expression e)
139{
140 Expression ex = cast()e;
9c7d5e88 141 while (ex.op == EXP.comma)
5fee5ec3
IB
142 ex = (cast(CommaExp)ex).e2;
143 return cast(inout)ex;
144
145}
146
147/*****************************************
148 * Determine if `this` is available by walking up the enclosing
149 * scopes until a function is found.
150 *
151 * Params:
152 * sc = where to start looking for the enclosing function
153 * Returns:
154 * Found function if it satisfies `isThis()`, otherwise `null`
155 */
156FuncDeclaration hasThis(Scope* sc)
157{
158 //printf("hasThis()\n");
159 Dsymbol p = sc.parent;
160 while (p && p.isTemplateMixin())
161 p = p.parent;
162 FuncDeclaration fdthis = p ? p.isFuncDeclaration() : null;
163 //printf("fdthis = %p, '%s'\n", fdthis, fdthis ? fdthis.toChars() : "");
164
165 // Go upwards until we find the enclosing member function
166 FuncDeclaration fd = fdthis;
167 while (1)
168 {
169 if (!fd)
170 {
171 return null;
172 }
235d5a96 173 if (!fd.isNested() || fd.isThis() || (fd.hasDualContext() && fd.isMember2()))
5fee5ec3
IB
174 break;
175
176 Dsymbol parent = fd.parent;
177 while (1)
178 {
179 if (!parent)
180 return null;
181 TemplateInstance ti = parent.isTemplateInstance();
182 if (ti)
183 parent = ti.parent;
184 else
185 break;
186 }
187 fd = parent.isFuncDeclaration();
188 }
189
235d5a96 190 if (!fd.isThis() && !(fd.hasDualContext() && fd.isMember2()))
5fee5ec3
IB
191 {
192 return null;
193 }
194
195 assert(fd.vthis);
196 return fd;
197
198}
199
200/***********************************
201 * Determine if a `this` is needed to access `d`.
202 * Params:
203 * sc = context
204 * d = declaration to check
205 * Returns:
206 * true means a `this` is needed
207 */
208bool isNeedThisScope(Scope* sc, Declaration d)
209{
210 if (sc.intypeof == 1)
211 return false;
212
213 AggregateDeclaration ad = d.isThis();
214 if (!ad)
215 return false;
216 //printf("d = %s, ad = %s\n", d.toChars(), ad.toChars());
217
218 for (Dsymbol s = sc.parent; s; s = s.toParentLocal())
219 {
220 //printf("\ts = %s %s, toParent2() = %p\n", s.kind(), s.toChars(), s.toParent2());
221 if (AggregateDeclaration ad2 = s.isAggregateDeclaration())
222 {
223 if (ad2 == ad)
224 return false;
225 else if (ad2.isNested())
226 continue;
227 else
228 return true;
229 }
230 if (FuncDeclaration f = s.isFuncDeclaration())
231 {
232 if (f.isMemberLocal())
233 break;
234 }
235 }
236 return true;
237}
238
239/******************************
240 * check e is exp.opDispatch!(tiargs) or not
241 * It's used to switch to UFCS the semantic analysis path
242 */
243bool isDotOpDispatch(Expression e)
244{
245 if (auto dtie = e.isDotTemplateInstanceExp())
246 return dtie.ti.name == Id.opDispatch;
247 return false;
248}
249
250/****************************************
251 * Expand tuples.
252 * Input:
253 * exps aray of Expressions
254 * Output:
255 * exps rewritten in place
256 */
257extern (C++) void expandTuples(Expressions* exps)
258{
259 //printf("expandTuples()\n");
260 if (exps is null)
261 return;
262
6d799f0a 263 for (size_t i = 0; i < exps.length; i++)
5fee5ec3
IB
264 {
265 Expression arg = (*exps)[i];
266 if (!arg)
267 continue;
268
269 // Look for tuple with 0 members
270 if (auto e = arg.isTypeExp())
271 {
272 if (auto tt = e.type.toBasetype().isTypeTuple())
273 {
6d799f0a 274 if (!tt.arguments || tt.arguments.length == 0)
5fee5ec3
IB
275 {
276 exps.remove(i);
6d799f0a 277 if (i == exps.length)
5fee5ec3
IB
278 return;
279 }
280 else // Expand a TypeTuple
281 {
282 exps.remove(i);
283 auto texps = new Expressions(tt.arguments.length);
284 foreach (j, a; *tt.arguments)
285 (*texps)[j] = new TypeExp(e.loc, a.type);
286 exps.insert(i, texps);
287 }
288 i--;
289 continue;
290 }
291 }
292
293 // Inline expand all the tuples
9c7d5e88 294 while (arg.op == EXP.tuple)
5fee5ec3
IB
295 {
296 TupleExp te = cast(TupleExp)arg;
297 exps.remove(i); // remove arg
298 exps.insert(i, te.exps); // replace with tuple contents
6d799f0a 299 if (i == exps.length)
5fee5ec3
IB
300 return; // empty tuple, no more arguments
301 (*exps)[i] = Expression.combine(te.e0, (*exps)[i]);
302 arg = (*exps)[i];
303 }
304 }
305}
306
307/****************************************
308 * Expand alias this tuples.
309 */
310TupleDeclaration isAliasThisTuple(Expression e)
311{
312 if (!e.type)
313 return null;
314
315 Type t = e.type.toBasetype();
316 while (true)
317 {
318 if (Dsymbol s = t.toDsymbol(null))
319 {
320 if (auto ad = s.isAggregateDeclaration())
321 {
322 s = ad.aliasthis ? ad.aliasthis.sym : null;
323 if (s && s.isVarDeclaration())
324 {
325 TupleDeclaration td = s.isVarDeclaration().toAlias().isTupleDeclaration();
326 if (td && td.isexp)
327 return td;
328 }
329 if (Type att = t.aliasthisOf())
330 {
331 t = att;
332 continue;
333 }
334 }
335 }
336 return null;
337 }
338}
339
340int expandAliasThisTuples(Expressions* exps, size_t starti = 0)
341{
6d799f0a 342 if (!exps || exps.length == 0)
5fee5ec3
IB
343 return -1;
344
6d799f0a 345 for (size_t u = starti; u < exps.length; u++)
5fee5ec3
IB
346 {
347 Expression exp = (*exps)[u];
348 if (TupleDeclaration td = exp.isAliasThisTuple)
349 {
350 exps.remove(u);
d97f3bca
IB
351 size_t i;
352 td.foreachVar((s)
5fee5ec3 353 {
d97f3bca 354 auto d = s.isDeclaration();
5fee5ec3
IB
355 auto e = new DotVarExp(exp.loc, exp, d);
356 assert(d.type);
357 e.type = d.type;
358 exps.insert(u + i, e);
d97f3bca
IB
359 ++i;
360 });
5fee5ec3
IB
361 version (none)
362 {
363 printf("expansion ->\n");
364 foreach (e; exps)
365 {
9c7d5e88 366 printf("\texps[%d] e = %s %s\n", i, EXPtoString(e.op), e.toChars());
5fee5ec3
IB
367 }
368 }
369 return cast(int)u;
370 }
371 }
372 return -1;
373}
374
375/****************************************
376 * If `s` is a function template, i.e. the only member of a template
377 * and that member is a function, return that template.
378 * Params:
379 * s = symbol that might be a function template
380 * Returns:
381 * template for that function, otherwise null
382 */
383TemplateDeclaration getFuncTemplateDecl(Dsymbol s)
384{
385 FuncDeclaration f = s.isFuncDeclaration();
386 if (f && f.parent)
387 {
388 if (auto ti = f.parent.isTemplateInstance())
389 {
390 if (!ti.isTemplateMixin() && ti.tempdecl)
391 {
392 auto td = ti.tempdecl.isTemplateDeclaration();
393 if (td.onemember && td.ident == f.ident)
394 {
395 return td;
396 }
397 }
398 }
399 }
400 return null;
401}
402
403/************************************************
404 * If we want the value of this expression, but do not want to call
405 * the destructor on it.
406 */
407Expression valueNoDtor(Expression e)
408{
409 auto ex = lastComma(e);
410
411 if (auto ce = ex.isCallExp())
412 {
413 /* The struct value returned from the function is transferred
414 * so do not call the destructor on it.
415 * Recognize:
416 * ((S _ctmp = S.init), _ctmp).this(...)
417 * and make sure the destructor is not called on _ctmp
418 * BUG: if ex is a CommaExp, we should go down the right side.
419 */
420 if (auto dve = ce.e1.isDotVarExp())
421 {
422 if (dve.var.isCtorDeclaration())
423 {
424 // It's a constructor call
425 if (auto comma = dve.e1.isCommaExp())
426 {
427 if (auto ve = comma.e2.isVarExp())
428 {
429 VarDeclaration ctmp = ve.var.isVarDeclaration();
430 if (ctmp)
431 {
432 ctmp.storage_class |= STC.nodtor;
433 assert(!ce.isLvalue());
434 }
435 }
436 }
437 }
438 }
439 }
440 else if (auto ve = ex.isVarExp())
441 {
442 auto vtmp = ve.var.isVarDeclaration();
443 if (vtmp && (vtmp.storage_class & STC.rvalue))
444 {
445 vtmp.storage_class |= STC.nodtor;
446 }
447 }
448 return e;
449}
450
451/*********************************************
452 * If e is an instance of a struct, and that struct has a copy constructor,
453 * rewrite e as:
454 * (tmp = e),tmp
455 * Input:
456 * sc = just used to specify the scope of created temporary variable
457 * destinationType = the type of the object on which the copy constructor is called;
458 * may be null if the struct defines a postblit
459 */
460private Expression callCpCtor(Scope* sc, Expression e, Type destinationType)
461{
462 if (auto ts = e.type.baseElemOf().isTypeStruct())
463 {
464 StructDeclaration sd = ts.sym;
465 if (sd.postblit || sd.hasCopyCtor)
466 {
467 /* Create a variable tmp, and replace the argument e with:
468 * (tmp = e),tmp
469 * and let AssignExp() handle the construction.
470 * This is not the most efficient, ideally tmp would be constructed
471 * directly onto the stack.
472 */
473 auto tmp = copyToTemp(STC.rvalue, "__copytmp", e);
474 if (sd.hasCopyCtor && destinationType)
d7569187
IB
475 {
476 // https://issues.dlang.org/show_bug.cgi?id=22619
477 // If the destination type is inout we can preserve it
478 // only if inside an inout function; if we are not inside
479 // an inout function, then we will preserve the type of
480 // the source
481 if (destinationType.hasWild && !(sc.func.storage_class & STC.wild))
482 tmp.type = e.type;
483 else
484 tmp.type = destinationType;
485 }
5fee5ec3
IB
486 tmp.storage_class |= STC.nodtor;
487 tmp.dsymbolSemantic(sc);
488 Expression de = new DeclarationExp(e.loc, tmp);
489 Expression ve = new VarExp(e.loc, tmp);
490 de.type = Type.tvoid;
491 ve.type = e.type;
492 return Expression.combine(de, ve);
493 }
494 }
495 return e;
496}
497
498/************************************************
499 * Handle the postblit call on lvalue, or the move of rvalue.
500 *
501 * Params:
502 * sc = the scope where the expression is encountered
503 * e = the expression the needs to be moved or copied (source)
504 * t = if the struct defines a copy constructor, the type of the destination
505 *
506 * Returns:
507 * The expression that copy constructs or moves the value.
508 */
509extern (D) Expression doCopyOrMove(Scope *sc, Expression e, Type t = null)
510{
511 if (auto ce = e.isCondExp())
512 {
513 ce.e1 = doCopyOrMove(sc, ce.e1);
514 ce.e2 = doCopyOrMove(sc, ce.e2);
515 }
516 else
517 {
518 e = e.isLvalue() ? callCpCtor(sc, e, t) : valueNoDtor(e);
519 }
520 return e;
521}
522
523/****************************************************************/
524/* A type meant as a union of all the Expression types,
525 * to serve essentially as a Variant that will sit on the stack
526 * during CTFE to reduce memory consumption.
527 */
528extern (C++) struct UnionExp
529{
530 // yes, default constructor does nothing
531 extern (D) this(Expression e)
532 {
533 memcpy(&this, cast(void*)e, e.size);
534 }
535
536 /* Extract pointer to Expression
537 */
538 extern (C++) Expression exp() return
539 {
540 return cast(Expression)&u;
541 }
542
543 /* Convert to an allocated Expression
544 */
545 extern (C++) Expression copy()
546 {
547 Expression e = exp();
9c7d5e88 548 //if (e.size > sizeof(u)) printf("%s\n", EXPtoString(e.op).ptr);
5fee5ec3
IB
549 assert(e.size <= u.sizeof);
550 switch (e.op)
551 {
9c7d5e88
IB
552 case EXP.cantExpression: return CTFEExp.cantexp;
553 case EXP.voidExpression: return CTFEExp.voidexp;
554 case EXP.break_: return CTFEExp.breakexp;
555 case EXP.continue_: return CTFEExp.continueexp;
556 case EXP.goto_: return CTFEExp.gotoexp;
5fee5ec3
IB
557 default: return e.copy();
558 }
559 }
560
561private:
562 // Ensure that the union is suitably aligned.
563 align(8) union __AnonStruct__u
564 {
565 char[__traits(classInstanceSize, Expression)] exp;
566 char[__traits(classInstanceSize, IntegerExp)] integerexp;
567 char[__traits(classInstanceSize, ErrorExp)] errorexp;
568 char[__traits(classInstanceSize, RealExp)] realexp;
569 char[__traits(classInstanceSize, ComplexExp)] complexexp;
570 char[__traits(classInstanceSize, SymOffExp)] symoffexp;
571 char[__traits(classInstanceSize, StringExp)] stringexp;
572 char[__traits(classInstanceSize, ArrayLiteralExp)] arrayliteralexp;
573 char[__traits(classInstanceSize, AssocArrayLiteralExp)] assocarrayliteralexp;
574 char[__traits(classInstanceSize, StructLiteralExp)] structliteralexp;
575 char[__traits(classInstanceSize, CompoundLiteralExp)] compoundliteralexp;
576 char[__traits(classInstanceSize, NullExp)] nullexp;
577 char[__traits(classInstanceSize, DotVarExp)] dotvarexp;
578 char[__traits(classInstanceSize, AddrExp)] addrexp;
579 char[__traits(classInstanceSize, IndexExp)] indexexp;
580 char[__traits(classInstanceSize, SliceExp)] sliceexp;
581 char[__traits(classInstanceSize, VectorExp)] vectorexp;
582 }
583
584 __AnonStruct__u u;
585}
586
587/********************************
588 * Test to see if two reals are the same.
589 * Regard NaN's as equivalent.
590 * Regard +0 and -0 as different.
591 * Params:
592 * x1 = first operand
593 * x2 = second operand
594 * Returns:
595 * true if x1 is x2
596 * else false
597 */
598bool RealIdentical(real_t x1, real_t x2)
599{
600 return (CTFloat.isNaN(x1) && CTFloat.isNaN(x2)) || CTFloat.isIdentical(x1, x2);
601}
602
603/************************ TypeDotIdExp ************************************/
604/* Things like:
605 * int.size
606 * foo.size
607 * (foo).size
608 * cast(foo).size
609 */
610DotIdExp typeDotIdExp(const ref Loc loc, Type type, Identifier ident)
611{
612 return new DotIdExp(loc, new TypeExp(loc, type), ident);
613}
614
615/***************************************************
616 * Given an Expression, find the variable it really is.
617 *
618 * For example, `a[index]` is really `a`, and `s.f` is really `s`.
619 * Params:
620 * e = Expression to look at
621 * Returns:
622 * variable if there is one, null if not
623 */
624VarDeclaration expToVariable(Expression e)
625{
626 while (1)
627 {
628 switch (e.op)
629 {
9c7d5e88 630 case EXP.variable:
5fee5ec3
IB
631 return (cast(VarExp)e).var.isVarDeclaration();
632
9c7d5e88 633 case EXP.dotVariable:
5fee5ec3
IB
634 e = (cast(DotVarExp)e).e1;
635 continue;
636
9c7d5e88 637 case EXP.index:
5fee5ec3
IB
638 {
639 IndexExp ei = cast(IndexExp)e;
640 e = ei.e1;
641 Type ti = e.type.toBasetype();
642 if (ti.ty == Tsarray)
643 continue;
644 return null;
645 }
646
9c7d5e88 647 case EXP.slice:
5fee5ec3
IB
648 {
649 SliceExp ei = cast(SliceExp)e;
650 e = ei.e1;
651 Type ti = e.type.toBasetype();
652 if (ti.ty == Tsarray)
653 continue;
654 return null;
655 }
656
9c7d5e88
IB
657 case EXP.this_:
658 case EXP.super_:
5fee5ec3
IB
659 return (cast(ThisExp)e).var.isVarDeclaration();
660
661 default:
662 return null;
663 }
664 }
665}
666
667enum OwnedBy : ubyte
668{
669 code, // normal code expression in AST
670 ctfe, // value expression for CTFE
671 cache, // constant value cached for CTFE
672}
673
674enum WANTvalue = 0; // default
675enum WANTexpand = 1; // expand const/immutable variables if possible
676
677/***********************************************************
c43b5909 678 * https://dlang.org/spec/expression.html#expression
5fee5ec3
IB
679 */
680extern (C++) abstract class Expression : ASTNode
681{
9c7d5e88 682 const EXP op; // to minimize use of dynamic_cast
5fee5ec3
IB
683 ubyte size; // # of bytes in Expression so we can copy() it
684 ubyte parens; // if this is a parenthesized expression
685 Type type; // !=null means that semantic() has been run
686 Loc loc; // file location
687
9c7d5e88 688 extern (D) this(const ref Loc loc, EXP op, int size)
5fee5ec3
IB
689 {
690 //printf("Expression::Expression(op = %d) this = %p\n", op, this);
691 this.loc = loc;
692 this.op = op;
693 this.size = cast(ubyte)size;
694 }
695
696 static void _init()
697 {
9c7d5e88
IB
698 CTFEExp.cantexp = new CTFEExp(EXP.cantExpression);
699 CTFEExp.voidexp = new CTFEExp(EXP.voidExpression);
700 CTFEExp.breakexp = new CTFEExp(EXP.break_);
701 CTFEExp.continueexp = new CTFEExp(EXP.continue_);
702 CTFEExp.gotoexp = new CTFEExp(EXP.goto_);
703 CTFEExp.showcontext = new CTFEExp(EXP.showCtfeContext);
5fee5ec3
IB
704 }
705
706 /**
707 * Deinitializes the global state of the compiler.
708 *
709 * This can be used to restore the state set by `_init` to its original
710 * state.
711 */
712 static void deinitialize()
713 {
714 CTFEExp.cantexp = CTFEExp.cantexp.init;
715 CTFEExp.voidexp = CTFEExp.voidexp.init;
716 CTFEExp.breakexp = CTFEExp.breakexp.init;
717 CTFEExp.continueexp = CTFEExp.continueexp.init;
718 CTFEExp.gotoexp = CTFEExp.gotoexp.init;
719 CTFEExp.showcontext = CTFEExp.showcontext.init;
720 }
721
722 /*********************************
723 * Does *not* do a deep copy.
724 */
725 final Expression copy()
726 {
727 Expression e;
728 if (!size)
729 {
730 debug
731 {
732 fprintf(stderr, "No expression copy for: %s\n", toChars());
733 printf("op = %d\n", op);
734 }
735 assert(0);
736 }
737
738 // memory never freed, so can use the faster bump-pointer-allocation
739 e = cast(Expression)allocmemory(size);
740 //printf("Expression::copy(op = %d) e = %p\n", op, e);
741 return cast(Expression)memcpy(cast(void*)e, cast(void*)this, size);
742 }
743
744 Expression syntaxCopy()
745 {
746 //printf("Expression::syntaxCopy()\n");
747 //print();
748 return copy();
749 }
750
751 // kludge for template.isExpression()
752 override final DYNCAST dyncast() const
753 {
754 return DYNCAST.expression;
755 }
756
757 override const(char)* toChars() const
758 {
759 OutBuffer buf;
760 HdrGenState hgs;
761 toCBuffer(this, &buf, &hgs);
762 return buf.extractChars();
763 }
764
765 static if (__VERSION__ < 2092)
766 {
767 final void error(const(char)* format, ...) const
768 {
769 if (type != Type.terror)
770 {
771 va_list ap;
772 va_start(ap, format);
773 .verror(loc, format, ap);
774 va_end(ap);
775 }
776 }
777
778 final void errorSupplemental(const(char)* format, ...)
779 {
780 if (type == Type.terror)
781 return;
782
783 va_list ap;
784 va_start(ap, format);
785 .verrorSupplemental(loc, format, ap);
786 va_end(ap);
787 }
788
789 final void warning(const(char)* format, ...) const
790 {
791 if (type != Type.terror)
792 {
793 va_list ap;
794 va_start(ap, format);
795 .vwarning(loc, format, ap);
796 va_end(ap);
797 }
798 }
799
800 final void deprecation(const(char)* format, ...) const
801 {
802 if (type != Type.terror)
803 {
804 va_list ap;
805 va_start(ap, format);
806 .vdeprecation(loc, format, ap);
807 va_end(ap);
808 }
809 }
810 }
811 else
812 {
813 pragma(printf) final void error(const(char)* format, ...) const
814 {
815 if (type != Type.terror)
816 {
817 va_list ap;
818 va_start(ap, format);
819 .verror(loc, format, ap);
820 va_end(ap);
821 }
822 }
823
824 pragma(printf) final void errorSupplemental(const(char)* format, ...)
825 {
826 if (type == Type.terror)
827 return;
828
829 va_list ap;
830 va_start(ap, format);
831 .verrorSupplemental(loc, format, ap);
832 va_end(ap);
833 }
834
835 pragma(printf) final void warning(const(char)* format, ...) const
836 {
837 if (type != Type.terror)
838 {
839 va_list ap;
840 va_start(ap, format);
841 .vwarning(loc, format, ap);
842 va_end(ap);
843 }
844 }
845
846 pragma(printf) final void deprecation(const(char)* format, ...) const
847 {
848 if (type != Type.terror)
849 {
850 va_list ap;
851 va_start(ap, format);
852 .vdeprecation(loc, format, ap);
853 va_end(ap);
854 }
855 }
856 }
857
858 /**********************************
859 * Combine e1 and e2 by CommaExp if both are not NULL.
860 */
861 extern (D) static Expression combine(Expression e1, Expression e2)
862 {
863 if (e1)
864 {
865 if (e2)
866 {
867 e1 = new CommaExp(e1.loc, e1, e2);
868 e1.type = e2.type;
869 }
870 }
871 else
872 e1 = e2;
873 return e1;
874 }
875
876 extern (D) static Expression combine(Expression e1, Expression e2, Expression e3)
877 {
878 return combine(combine(e1, e2), e3);
879 }
880
881 extern (D) static Expression combine(Expression e1, Expression e2, Expression e3, Expression e4)
882 {
883 return combine(combine(e1, e2), combine(e3, e4));
884 }
885
886 /**********************************
887 * If 'e' is a tree of commas, returns the rightmost expression
888 * by stripping off it from the tree. The remained part of the tree
889 * is returned via e0.
890 * Otherwise 'e' is directly returned and e0 is set to NULL.
891 */
892 extern (D) static Expression extractLast(Expression e, out Expression e0)
893 {
9c7d5e88 894 if (e.op != EXP.comma)
5fee5ec3
IB
895 {
896 return e;
897 }
898
899 CommaExp ce = cast(CommaExp)e;
9c7d5e88 900 if (ce.e2.op != EXP.comma)
5fee5ec3
IB
901 {
902 e0 = ce.e1;
903 return ce.e2;
904 }
905 else
906 {
907 e0 = e;
908
909 Expression* pce = &ce.e2;
9c7d5e88 910 while ((cast(CommaExp)(*pce)).e2.op == EXP.comma)
5fee5ec3
IB
911 {
912 pce = &(cast(CommaExp)(*pce)).e2;
913 }
9c7d5e88 914 assert((*pce).op == EXP.comma);
5fee5ec3
IB
915 ce = cast(CommaExp)(*pce);
916 *pce = ce.e1;
917
918 return ce.e2;
919 }
920 }
921
922 extern (D) static Expressions* arraySyntaxCopy(Expressions* exps)
923 {
924 Expressions* a = null;
925 if (exps)
926 {
6d799f0a 927 a = new Expressions(exps.length);
5fee5ec3
IB
928 foreach (i, e; *exps)
929 {
930 (*a)[i] = e ? e.syntaxCopy() : null;
931 }
932 }
933 return a;
934 }
935
936 dinteger_t toInteger()
937 {
9c7d5e88 938 //printf("Expression %s\n", EXPtoString(op).ptr);
5fee5ec3
IB
939 error("integer constant expression expected instead of `%s`", toChars());
940 return 0;
941 }
942
943 uinteger_t toUInteger()
944 {
9c7d5e88 945 //printf("Expression %s\n", EXPtoString(op).ptr);
5fee5ec3
IB
946 return cast(uinteger_t)toInteger();
947 }
948
949 real_t toReal()
950 {
951 error("floating point constant expression expected instead of `%s`", toChars());
952 return CTFloat.zero;
953 }
954
955 real_t toImaginary()
956 {
957 error("floating point constant expression expected instead of `%s`", toChars());
958 return CTFloat.zero;
959 }
960
961 complex_t toComplex()
962 {
963 error("floating point constant expression expected instead of `%s`", toChars());
964 return complex_t(CTFloat.zero);
965 }
966
967 StringExp toStringExp()
968 {
969 return null;
970 }
971
5fee5ec3
IB
972 /***************************************
973 * Return !=0 if expression is an lvalue.
974 */
975 bool isLvalue()
976 {
977 return false;
978 }
979
980 /*******************************
981 * Give error if we're not an lvalue.
982 * If we can, convert expression to be an lvalue.
983 */
984 Expression toLvalue(Scope* sc, Expression e)
985 {
986 if (!e)
987 e = this;
988 else if (!loc.isValid())
989 loc = e.loc;
990
9c7d5e88 991 if (e.op == EXP.type)
5fee5ec3
IB
992 error("`%s` is a `%s` definition and cannot be modified", e.type.toChars(), e.type.kind());
993 else
994 error("`%s` is not an lvalue and cannot be modified", e.toChars());
995
996 return ErrorExp.get();
997 }
998
999 Expression modifiableLvalue(Scope* sc, Expression e)
1000 {
1001 //printf("Expression::modifiableLvalue() %s, type = %s\n", toChars(), type.toChars());
1002 // See if this expression is a modifiable lvalue (i.e. not const)
1003 if (checkModifiable(this, sc) == Modifiable.yes)
1004 {
1005 assert(type);
1006 if (!type.isMutable())
1007 {
1008 if (auto dve = this.isDotVarExp())
1009 {
1010 if (isNeedThisScope(sc, dve.var))
1011 for (Dsymbol s = sc.func; s; s = s.toParentLocal())
1012 {
1013 FuncDeclaration ff = s.isFuncDeclaration();
1014 if (!ff)
1015 break;
1016 if (!ff.type.isMutable)
1017 {
1018 error("cannot modify `%s` in `%s` function", toChars(), MODtoChars(type.mod));
1019 return ErrorExp.get();
1020 }
1021 }
1022 }
1023 error("cannot modify `%s` expression `%s`", MODtoChars(type.mod), toChars());
1024 return ErrorExp.get();
1025 }
1026 else if (!type.isAssignable())
1027 {
1028 error("cannot modify struct instance `%s` of type `%s` because it contains `const` or `immutable` members",
1029 toChars(), type.toChars());
1030 return ErrorExp.get();
1031 }
1032 }
1033 return toLvalue(sc, e);
1034 }
1035
1036 final Expression implicitCastTo(Scope* sc, Type t)
1037 {
1038 return .implicitCastTo(this, sc, t);
1039 }
1040
1041 final MATCH implicitConvTo(Type t)
1042 {
1043 return .implicitConvTo(this, t);
1044 }
1045
1046 final Expression castTo(Scope* sc, Type t)
1047 {
1048 return .castTo(this, sc, t);
1049 }
1050
1051 /****************************************
1052 * Resolve __FILE__, __LINE__, __MODULE__, __FUNCTION__, __PRETTY_FUNCTION__, __FILE_FULL_PATH__ to loc.
1053 */
1054 Expression resolveLoc(const ref Loc loc, Scope* sc)
1055 {
1056 this.loc = loc;
1057 return this;
1058 }
1059
1060 /****************************************
1061 * Check that the expression has a valid type.
1062 * If not, generates an error "... has no type".
1063 * Returns:
1064 * true if the expression is not valid.
1065 * Note:
1066 * When this function returns true, `checkValue()` should also return true.
1067 */
1068 bool checkType()
1069 {
1070 return false;
1071 }
1072
1073 /****************************************
1074 * Check that the expression has a valid value.
1075 * If not, generates an error "... has no value".
1076 * Returns:
1077 * true if the expression is not valid or has void type.
1078 */
1079 bool checkValue()
1080 {
1081 if (type && type.toBasetype().ty == Tvoid)
1082 {
1083 error("expression `%s` is `void` and has no value", toChars());
1084 //print(); assert(0);
1085 if (!global.gag)
1086 type = Type.terror;
1087 return true;
1088 }
1089 return false;
1090 }
1091
1092 extern (D) final bool checkScalar()
1093 {
9c7d5e88 1094 if (op == EXP.error)
5fee5ec3
IB
1095 return true;
1096 if (type.toBasetype().ty == Terror)
1097 return true;
1098 if (!type.isscalar())
1099 {
1100 error("`%s` is not a scalar, it is a `%s`", toChars(), type.toChars());
1101 return true;
1102 }
1103 return checkValue();
1104 }
1105
1106 extern (D) final bool checkNoBool()
1107 {
9c7d5e88 1108 if (op == EXP.error)
5fee5ec3
IB
1109 return true;
1110 if (type.toBasetype().ty == Terror)
1111 return true;
1112 if (type.toBasetype().ty == Tbool)
1113 {
1114 error("operation not allowed on `bool` `%s`", toChars());
1115 return true;
1116 }
1117 return false;
1118 }
1119
1120 extern (D) final bool checkIntegral()
1121 {
9c7d5e88 1122 if (op == EXP.error)
5fee5ec3
IB
1123 return true;
1124 if (type.toBasetype().ty == Terror)
1125 return true;
1126 if (!type.isintegral())
1127 {
1128 error("`%s` is not of integral type, it is a `%s`", toChars(), type.toChars());
1129 return true;
1130 }
1131 return checkValue();
1132 }
1133
1134 extern (D) final bool checkArithmetic()
1135 {
9c7d5e88 1136 if (op == EXP.error)
5fee5ec3
IB
1137 return true;
1138 if (type.toBasetype().ty == Terror)
1139 return true;
1140 if (!type.isintegral() && !type.isfloating())
1141 {
1142 error("`%s` is not of arithmetic type, it is a `%s`", toChars(), type.toChars());
1143 return true;
1144 }
1145 return checkValue();
1146 }
1147
1148 final bool checkDeprecated(Scope* sc, Dsymbol s)
1149 {
1150 return s.checkDeprecated(loc, sc);
1151 }
1152
1153 extern (D) final bool checkDisabled(Scope* sc, Dsymbol s)
1154 {
1155 if (auto d = s.isDeclaration())
1156 {
1157 return d.checkDisabled(loc, sc);
1158 }
1159
1160 return false;
1161 }
1162
1163 /*********************************************
1164 * Calling function f.
1165 * Check the purity, i.e. if we're in a pure function
1166 * we can only call other pure functions.
1167 * Returns true if error occurs.
1168 */
1169 extern (D) final bool checkPurity(Scope* sc, FuncDeclaration f)
1170 {
1171 if (!sc.func)
1172 return false;
1173 if (sc.func == f)
1174 return false;
1175 if (sc.intypeof == 1)
1176 return false;
1177 if (sc.flags & (SCOPE.ctfe | SCOPE.debug_))
1178 return false;
1179
1180 // If the call has a pure parent, then the called func must be pure.
1181 if (!f.isPure() && checkImpure(sc))
1182 {
1183 error("`pure` %s `%s` cannot call impure %s `%s`",
1184 sc.func.kind(), sc.func.toPrettyChars(), f.kind(),
1185 f.toPrettyChars());
1186
1187 checkOverridenDtor(sc, f, dd => dd.type.toTypeFunction().purity != PURE.impure, "impure");
1188 return true;
1189 }
1190 return false;
1191 }
1192
1193 /**
1194 * Checks whether `f` is a generated `DtorDeclaration` that hides a user-defined one
1195 * which passes `check` while `f` doesn't (e.g. when the user defined dtor is pure but
1196 * the generated dtor is not).
1197 * In that case the method will identify and print all members causing the attribute
1198 * missmatch.
1199 *
1200 * Params:
1201 * sc = scope
1202 * f = potential `DtorDeclaration`
1203 * check = current check (e.g. whether it's pure)
1204 * checkName = the kind of check (e.g. `"pure"`)
1205 */
1206 extern (D) final void checkOverridenDtor(Scope* sc, FuncDeclaration f,
1207 scope bool function(DtorDeclaration) check, const string checkName
1208 ) {
1209 auto dd = f.isDtorDeclaration();
235d5a96 1210 if (!dd || !dd.isGenerated())
5fee5ec3
IB
1211 return;
1212
1213 // DtorDeclaration without parents should fail at an earlier stage
1214 auto ad = cast(AggregateDeclaration) f.toParent2();
1215 assert(ad);
5fee5ec3 1216
6d799f0a 1217 if (ad.userDtors.length)
5fee5ec3 1218 {
0fb57034 1219 if (!check(ad.userDtors[0])) // doesn't match check (e.g. is impure as well)
5fee5ec3
IB
1220 return;
1221
1222 // Sanity check
0fb57034 1223 assert(!check(ad.fieldDtor));
5fee5ec3
IB
1224 }
1225
1226 dd.loc.errorSupplemental("%s`%s.~this` is %.*s because of the following field's destructors:",
235d5a96 1227 dd.isGenerated() ? "generated " : "".ptr,
5fee5ec3
IB
1228 ad.toChars,
1229 cast(int) checkName.length, checkName.ptr);
1230
1231 // Search for the offending fields
1232 foreach (field; ad.fields)
1233 {
1234 // Only structs may define automatically called destructors
1235 auto ts = field.type.isTypeStruct();
1236 if (!ts)
1237 {
1238 // But they might be part of a static array
1239 auto ta = field.type.isTypeSArray();
1240 if (!ta)
1241 continue;
1242
1243 ts = ta.baseElemOf().isTypeStruct();
1244 if (!ts)
1245 continue;
1246 }
1247
1248 auto fieldSym = ts.toDsymbol(sc);
1249 assert(fieldSym); // Resolving ts must succeed because missing defs. should error before
1250
1251 auto fieldSd = fieldSym.isStructDeclaration();
1252 assert(fieldSd); // ts is a TypeStruct, this would imply a malformed ASR
1253
1254 if (fieldSd.dtor && !check(fieldSd.dtor))
1255 {
1256 field.loc.errorSupplemental(" - %s %s", field.type.toChars(), field.toChars());
1257
235d5a96 1258 if (fieldSd.dtor.isGenerated())
5fee5ec3
IB
1259 checkOverridenDtor(sc, fieldSd.dtor, check, checkName);
1260 else
1261 fieldSd.dtor.loc.errorSupplemental(" %.*s `%s.~this` is declared here",
1262 cast(int) checkName.length, checkName.ptr, fieldSd.toChars());
1263 }
1264 }
1265 }
1266
1267 /*******************************************
1268 * Accessing variable v.
1269 * Check for purity and safety violations.
1270 * Returns true if error occurs.
1271 */
1272 extern (D) final bool checkPurity(Scope* sc, VarDeclaration v)
1273 {
1274 //printf("v = %s %s\n", v.type.toChars(), v.toChars());
1275 /* Look for purity and safety violations when accessing variable v
1276 * from current function.
1277 */
1278 if (!sc.func)
1279 return false;
1280 if (sc.intypeof == 1)
1281 return false; // allow violations inside typeof(expression)
1282 if (sc.flags & (SCOPE.ctfe | SCOPE.debug_))
1283 return false; // allow violations inside compile-time evaluated expressions and debug conditionals
1284 if (v.ident == Id.ctfe)
1285 return false; // magic variable never violates pure and safe
1286 if (v.isImmutable())
1287 return false; // always safe and pure to access immutables...
235d5a96 1288 if (v.isConst() && !v.isReference() && (v.isDataseg() || v.isParameter()) && v.type.implicitConvTo(v.type.immutableOf()))
5fee5ec3
IB
1289 return false; // or const global/parameter values which have no mutable indirections
1290 if (v.storage_class & STC.manifest)
1291 return false; // ...or manifest constants
1292
1293 // accessing empty structs is pure
1294 if (v.type.ty == Tstruct)
1295 {
1296 StructDeclaration sd = (cast(TypeStruct)v.type).sym;
1297 if (sd.members) // not opaque
1298 {
1299 sd.determineSize(v.loc);
1300 if (sd.hasNoFields)
1301 return false;
1302 }
1303 }
1304
1305 bool err = false;
1306 if (v.isDataseg())
1307 {
1308 // https://issues.dlang.org/show_bug.cgi?id=7533
1309 // Accessing implicit generated __gate is pure.
1310 if (v.ident == Id.gate)
1311 return false;
1312
1313 if (checkImpure(sc))
1314 {
1315 error("`pure` %s `%s` cannot access mutable static data `%s`",
1316 sc.func.kind(), sc.func.toPrettyChars(), v.toChars());
1317 err = true;
1318 }
1319 }
1320 else
1321 {
1322 /* Given:
1323 * void f() {
1324 * int fx;
1325 * pure void g() {
1326 * int gx;
1327 * /+pure+/ void h() {
1328 * int hx;
1329 * /+pure+/ void i() { }
1330 * }
1331 * }
1332 * }
1333 * i() can modify hx and gx but not fx
1334 */
1335
1336 Dsymbol vparent = v.toParent2();
1337 for (Dsymbol s = sc.func; !err && s; s = s.toParentP(vparent))
1338 {
1339 if (s == vparent)
1340 break;
1341
1342 if (AggregateDeclaration ad = s.isAggregateDeclaration())
1343 {
1344 if (ad.isNested())
1345 continue;
1346 break;
1347 }
1348 FuncDeclaration ff = s.isFuncDeclaration();
1349 if (!ff)
1350 break;
1351 if (ff.isNested() || ff.isThis())
1352 {
1353 if (ff.type.isImmutable() ||
1354 ff.type.isShared() && !MODimplicitConv(ff.type.mod, v.type.mod))
1355 {
1356 OutBuffer ffbuf;
1357 OutBuffer vbuf;
1358 MODMatchToBuffer(&ffbuf, ff.type.mod, v.type.mod);
1359 MODMatchToBuffer(&vbuf, v.type.mod, ff.type.mod);
1360 error("%s%s `%s` cannot access %sdata `%s`",
1361 ffbuf.peekChars(), ff.kind(), ff.toPrettyChars(), vbuf.peekChars(), v.toChars());
1362 err = true;
1363 break;
1364 }
1365 continue;
1366 }
1367 break;
1368 }
1369 }
1370
1371 /* Do not allow safe functions to access __gshared data
1372 */
1373 if (v.storage_class & STC.gshared)
1374 {
610d7898 1375 if (sc.setUnsafe(false, this.loc,
5eb9927a 1376 "`@safe` function `%s` cannot access `__gshared` data `%s`", sc.func, v))
5fee5ec3 1377 {
5fee5ec3
IB
1378 err = true;
1379 }
1380 }
1381
1382 return err;
1383 }
1384
1385 /*
1386 Check if sc.func is impure or can be made impure.
1387 Returns true on error, i.e. if sc.func is pure and cannot be made impure.
1388 */
1389 private static bool checkImpure(Scope* sc)
1390 {
1391 return sc.func && (sc.flags & SCOPE.compile
1392 ? sc.func.isPureBypassingInference() >= PURE.weak
1393 : sc.func.setImpure());
1394 }
1395
1396 /*********************************************
1397 * Calling function f.
1398 * Check the safety, i.e. if we're in a @safe function
1399 * we can only call @safe or @trusted functions.
1400 * Returns true if error occurs.
1401 */
1402 extern (D) final bool checkSafety(Scope* sc, FuncDeclaration f)
1403 {
5fee5ec3
IB
1404 if (sc.func == f)
1405 return false;
1406 if (sc.intypeof == 1)
1407 return false;
6d799f0a 1408 if (sc.flags & SCOPE.debug_)
5fee5ec3 1409 return false;
6d799f0a
IB
1410 if ((sc.flags & SCOPE.ctfe) && sc.func)
1411 return false;
1412
1413 if (!sc.func)
1414 {
1415 if (sc.varDecl && !f.safetyInprocess && !f.isSafe() && !f.isTrusted())
1416 {
1417 if (sc.varDecl.storage_class & STC.safe)
1418 {
1419 error("`@safe` variable `%s` cannot be initialized by calling `@system` function `%s`",
1420 sc.varDecl.toChars(), f.toChars());
1421 return true;
1422 }
1423 else
1424 {
1425 sc.varDecl.storage_class |= STC.system;
1426 }
1427 }
1428 return false;
1429 }
5fee5ec3
IB
1430
1431 if (!f.isSafe() && !f.isTrusted())
1432 {
5eb9927a 1433 if (sc.flags & SCOPE.compile ? sc.func.isSafeBypassingInference() : sc.func.setUnsafeCall(f))
5fee5ec3
IB
1434 {
1435 if (!loc.isValid()) // e.g. implicitly generated dtor
1436 loc = sc.func.loc;
1437
1438 const prettyChars = f.toPrettyChars();
1439 error("`@safe` %s `%s` cannot call `@system` %s `%s`",
1440 sc.func.kind(), sc.func.toPrettyChars(), f.kind(),
1441 prettyChars);
610d7898 1442 f.errorSupplementalInferredSafety(/*max depth*/ 10, /*deprecation*/ false);
5fee5ec3
IB
1443 .errorSupplemental(f.loc, "`%s` is declared here", prettyChars);
1444
1445 checkOverridenDtor(sc, f, dd => dd.type.toTypeFunction().trust > TRUST.system, "@system");
1446
1447 return true;
1448 }
1449 }
610d7898
IB
1450 else if (f.isSafe() && f.safetyViolation)
1451 {
1452 // for dip1000 by default transition, print deprecations for calling functions that will become `@system`
1453 if (sc.func.isSafeBypassingInference())
1454 {
1455 .deprecation(this.loc, "`@safe` function `%s` calling `%s`", sc.func.toChars(), f.toChars());
1456 errorSupplementalInferredSafety(f, 10, true);
1457 }
1458 else if (!sc.func.safetyViolation)
1459 {
1460 import dmd.func : AttributeViolation;
445d8def 1461 sc.func.safetyViolation = new AttributeViolation(this.loc, null, f, null, null);
610d7898
IB
1462 }
1463 }
5fee5ec3
IB
1464 return false;
1465 }
1466
1467 /*********************************************
1468 * Calling function f.
1469 * Check the @nogc-ness, i.e. if we're in a @nogc function
1470 * we can only call other @nogc functions.
1471 * Returns true if error occurs.
1472 */
1473 extern (D) final bool checkNogc(Scope* sc, FuncDeclaration f)
1474 {
1475 if (!sc.func)
1476 return false;
1477 if (sc.func == f)
1478 return false;
1479 if (sc.intypeof == 1)
1480 return false;
1481 if (sc.flags & (SCOPE.ctfe | SCOPE.debug_))
1482 return false;
1483
1484 if (!f.isNogc())
1485 {
1486 if (sc.flags & SCOPE.compile ? sc.func.isNogcBypassingInference() : sc.func.setGC())
1487 {
1488 if (loc.linnum == 0) // e.g. implicitly generated dtor
1489 loc = sc.func.loc;
1490
1491 // Lowered non-@nogc'd hooks will print their own error message inside of nogc.d (NOGCVisitor.visit(CallExp e)),
1492 // so don't print anything to avoid double error messages.
5eb9927a
IB
1493 if (!(f.ident == Id._d_HookTraceImpl || f.ident == Id._d_arraysetlengthT
1494 || f.ident == Id._d_arrayappendT || f.ident == Id._d_arrayappendcTX))
5fee5ec3
IB
1495 error("`@nogc` %s `%s` cannot call non-@nogc %s `%s`",
1496 sc.func.kind(), sc.func.toPrettyChars(), f.kind(), f.toPrettyChars());
1497
1498 checkOverridenDtor(sc, f, dd => dd.type.toTypeFunction().isnogc, "non-@nogc");
1499
1500 return true;
1501 }
1502 }
1503 return false;
1504 }
1505
1506 /********************************************
1507 * Check that the postblit is callable if t is an array of structs.
1508 * Returns true if error happens.
1509 */
1510 extern (D) final bool checkPostblit(Scope* sc, Type t)
1511 {
1512 if (auto ts = t.baseElemOf().isTypeStruct())
1513 {
1514 if (global.params.useTypeInfo && Type.dtypeinfo)
1515 {
1516 // https://issues.dlang.org/show_bug.cgi?id=11395
1517 // Require TypeInfo generation for array concatenation
1518 semanticTypeInfo(sc, t);
1519 }
1520
1521 StructDeclaration sd = ts.sym;
1522 if (sd.postblit)
1523 {
1524 if (sd.postblit.checkDisabled(loc, sc))
1525 return true;
1526
1527 //checkDeprecated(sc, sd.postblit); // necessary?
1528 checkPurity(sc, sd.postblit);
1529 checkSafety(sc, sd.postblit);
1530 checkNogc(sc, sd.postblit);
1531 //checkAccess(sd, loc, sc, sd.postblit); // necessary?
1532 return false;
1533 }
1534 }
1535 return false;
1536 }
1537
1538 extern (D) final bool checkRightThis(Scope* sc)
1539 {
9c7d5e88 1540 if (op == EXP.error)
5fee5ec3 1541 return true;
9c7d5e88 1542 if (op == EXP.variable && type.ty != Terror)
5fee5ec3
IB
1543 {
1544 VarExp ve = cast(VarExp)this;
1545 if (isNeedThisScope(sc, ve.var))
1546 {
1547 //printf("checkRightThis sc.intypeof = %d, ad = %p, func = %p, fdthis = %p\n",
1548 // sc.intypeof, sc.getStructClassScope(), func, fdthis);
1549 error("need `this` for `%s` of type `%s`", ve.var.toChars(), ve.var.type.toChars());
1550 return true;
1551 }
1552 }
1553 return false;
1554 }
1555
1556 /*******************************
1557 * Check whether the expression allows RMW operations, error with rmw operator diagnostic if not.
1558 * ex is the RHS expression, or NULL if ++/-- is used (for diagnostics)
1559 * Returns true if error occurs.
1560 */
9c7d5e88 1561 extern (D) final bool checkReadModifyWrite(EXP rmwOp, Expression ex = null)
5fee5ec3
IB
1562 {
1563 //printf("Expression::checkReadModifyWrite() %s %s", toChars(), ex ? ex.toChars() : "");
1564 if (!type || !type.isShared() || type.isTypeStruct() || type.isTypeClass())
1565 return false;
1566
1567 // atomicOp uses opAssign (+=/-=) rather than opOp (++/--) for the CT string literal.
1568 switch (rmwOp)
1569 {
9c7d5e88
IB
1570 case EXP.plusPlus:
1571 case EXP.prePlusPlus:
1572 rmwOp = EXP.addAssign;
5fee5ec3 1573 break;
9c7d5e88
IB
1574 case EXP.minusMinus:
1575 case EXP.preMinusMinus:
1576 rmwOp = EXP.minAssign;
5fee5ec3
IB
1577 break;
1578 default:
1579 break;
1580 }
1581
1582 error("read-modify-write operations are not allowed for `shared` variables");
1583 errorSupplemental("Use `core.atomic.atomicOp!\"%s\"(%s, %s)` instead",
9c7d5e88 1584 EXPtoString(rmwOp).ptr, toChars(), ex ? ex.toChars() : "1");
5fee5ec3
IB
1585 return true;
1586 }
1587
1588 /************************************************
1589 * Destructors are attached to VarDeclarations.
1590 * Hence, if expression returns a temp that needs a destructor,
1591 * make sure and create a VarDeclaration for that temp.
1592 */
1593 Expression addDtorHook(Scope* sc)
1594 {
1595 return this;
1596 }
1597
1598 /******************************
1599 * Take address of expression.
1600 */
1601 final Expression addressOf()
1602 {
1603 //printf("Expression::addressOf()\n");
1604 debug
1605 {
9c7d5e88 1606 assert(op == EXP.error || isLvalue());
5fee5ec3
IB
1607 }
1608 Expression e = new AddrExp(loc, this, type.pointerTo());
1609 return e;
1610 }
1611
1612 /******************************
1613 * If this is a reference, dereference it.
1614 */
1615 final Expression deref()
1616 {
1617 //printf("Expression::deref()\n");
1618 // type could be null if forward referencing an 'auto' variable
1619 if (type)
1620 if (auto tr = type.isTypeReference())
1621 {
1622 Expression e = new PtrExp(loc, this, tr.next);
1623 return e;
1624 }
1625 return this;
1626 }
1627
1628 final Expression optimize(int result, bool keepLvalue = false)
1629 {
1630 return Expression_optimize(this, result, keepLvalue);
1631 }
1632
1633 // Entry point for CTFE.
1634 // A compile-time result is required. Give an error if not possible
1635 final Expression ctfeInterpret()
1636 {
1637 return .ctfeInterpret(this);
1638 }
1639
1640 final int isConst()
1641 {
1642 return .isConst(this);
1643 }
1644
9c7d5e88
IB
1645 /// Statically evaluate this expression to a `bool` if possible
1646 /// Returns: an optional thath either contains the value or is empty
1647 Optional!bool toBool()
5fee5ec3 1648 {
9c7d5e88 1649 return typeof(return)();
5fee5ec3
IB
1650 }
1651
1652 bool hasCode()
1653 {
1654 return true;
1655 }
1656
1657 final pure inout nothrow @nogc @safe
1658 {
9c7d5e88
IB
1659 inout(IntegerExp) isIntegerExp() { return op == EXP.int64 ? cast(typeof(return))this : null; }
1660 inout(ErrorExp) isErrorExp() { return op == EXP.error ? cast(typeof(return))this : null; }
1661 inout(VoidInitExp) isVoidInitExp() { return op == EXP.void_ ? cast(typeof(return))this : null; }
1662 inout(RealExp) isRealExp() { return op == EXP.float64 ? cast(typeof(return))this : null; }
1663 inout(ComplexExp) isComplexExp() { return op == EXP.complex80 ? cast(typeof(return))this : null; }
1664 inout(IdentifierExp) isIdentifierExp() { return op == EXP.identifier ? cast(typeof(return))this : null; }
1665 inout(DollarExp) isDollarExp() { return op == EXP.dollar ? cast(typeof(return))this : null; }
1666 inout(DsymbolExp) isDsymbolExp() { return op == EXP.dSymbol ? cast(typeof(return))this : null; }
1667 inout(ThisExp) isThisExp() { return op == EXP.this_ ? cast(typeof(return))this : null; }
1668 inout(SuperExp) isSuperExp() { return op == EXP.super_ ? cast(typeof(return))this : null; }
1669 inout(NullExp) isNullExp() { return op == EXP.null_ ? cast(typeof(return))this : null; }
1670 inout(StringExp) isStringExp() { return op == EXP.string_ ? cast(typeof(return))this : null; }
1671 inout(TupleExp) isTupleExp() { return op == EXP.tuple ? cast(typeof(return))this : null; }
1672 inout(ArrayLiteralExp) isArrayLiteralExp() { return op == EXP.arrayLiteral ? cast(typeof(return))this : null; }
1673 inout(AssocArrayLiteralExp) isAssocArrayLiteralExp() { return op == EXP.assocArrayLiteral ? cast(typeof(return))this : null; }
1674 inout(StructLiteralExp) isStructLiteralExp() { return op == EXP.structLiteral ? cast(typeof(return))this : null; }
1675 inout(CompoundLiteralExp) isCompoundLiteralExp() { return op == EXP.compoundLiteral ? cast(typeof(return))this : null; }
1676 inout(TypeExp) isTypeExp() { return op == EXP.type ? cast(typeof(return))this : null; }
1677 inout(ScopeExp) isScopeExp() { return op == EXP.scope_ ? cast(typeof(return))this : null; }
1678 inout(TemplateExp) isTemplateExp() { return op == EXP.template_ ? cast(typeof(return))this : null; }
1679 inout(NewExp) isNewExp() { return op == EXP.new_ ? cast(typeof(return))this : null; }
1680 inout(NewAnonClassExp) isNewAnonClassExp() { return op == EXP.newAnonymousClass ? cast(typeof(return))this : null; }
1681 inout(SymOffExp) isSymOffExp() { return op == EXP.symbolOffset ? cast(typeof(return))this : null; }
1682 inout(VarExp) isVarExp() { return op == EXP.variable ? cast(typeof(return))this : null; }
1683 inout(OverExp) isOverExp() { return op == EXP.overloadSet ? cast(typeof(return))this : null; }
1684 inout(FuncExp) isFuncExp() { return op == EXP.function_ ? cast(typeof(return))this : null; }
1685 inout(DeclarationExp) isDeclarationExp() { return op == EXP.declaration ? cast(typeof(return))this : null; }
1686 inout(TypeidExp) isTypeidExp() { return op == EXP.typeid_ ? cast(typeof(return))this : null; }
1687 inout(TraitsExp) isTraitsExp() { return op == EXP.traits ? cast(typeof(return))this : null; }
1688 inout(HaltExp) isHaltExp() { return op == EXP.halt ? cast(typeof(return))this : null; }
1689 inout(IsExp) isExp() { return op == EXP.is_ ? cast(typeof(return))this : null; }
1690 inout(MixinExp) isMixinExp() { return op == EXP.mixin_ ? cast(typeof(return))this : null; }
1691 inout(ImportExp) isImportExp() { return op == EXP.import_ ? cast(typeof(return))this : null; }
1692 inout(AssertExp) isAssertExp() { return op == EXP.assert_ ? cast(typeof(return))this : null; }
31350635 1693 inout(ThrowExp) isThrowExp() { return op == EXP.throw_ ? cast(typeof(return))this : null; }
9c7d5e88
IB
1694 inout(DotIdExp) isDotIdExp() { return op == EXP.dotIdentifier ? cast(typeof(return))this : null; }
1695 inout(DotTemplateExp) isDotTemplateExp() { return op == EXP.dotTemplateDeclaration ? cast(typeof(return))this : null; }
1696 inout(DotVarExp) isDotVarExp() { return op == EXP.dotVariable ? cast(typeof(return))this : null; }
1697 inout(DotTemplateInstanceExp) isDotTemplateInstanceExp() { return op == EXP.dotTemplateInstance ? cast(typeof(return))this : null; }
1698 inout(DelegateExp) isDelegateExp() { return op == EXP.delegate_ ? cast(typeof(return))this : null; }
1699 inout(DotTypeExp) isDotTypeExp() { return op == EXP.dotType ? cast(typeof(return))this : null; }
1700 inout(CallExp) isCallExp() { return op == EXP.call ? cast(typeof(return))this : null; }
1701 inout(AddrExp) isAddrExp() { return op == EXP.address ? cast(typeof(return))this : null; }
1702 inout(PtrExp) isPtrExp() { return op == EXP.star ? cast(typeof(return))this : null; }
1703 inout(NegExp) isNegExp() { return op == EXP.negate ? cast(typeof(return))this : null; }
1704 inout(UAddExp) isUAddExp() { return op == EXP.uadd ? cast(typeof(return))this : null; }
1705 inout(ComExp) isComExp() { return op == EXP.tilde ? cast(typeof(return))this : null; }
1706 inout(NotExp) isNotExp() { return op == EXP.not ? cast(typeof(return))this : null; }
1707 inout(DeleteExp) isDeleteExp() { return op == EXP.delete_ ? cast(typeof(return))this : null; }
1708 inout(CastExp) isCastExp() { return op == EXP.cast_ ? cast(typeof(return))this : null; }
1709 inout(VectorExp) isVectorExp() { return op == EXP.vector ? cast(typeof(return))this : null; }
1710 inout(VectorArrayExp) isVectorArrayExp() { return op == EXP.vectorArray ? cast(typeof(return))this : null; }
1711 inout(SliceExp) isSliceExp() { return op == EXP.slice ? cast(typeof(return))this : null; }
1712 inout(ArrayLengthExp) isArrayLengthExp() { return op == EXP.arrayLength ? cast(typeof(return))this : null; }
1713 inout(ArrayExp) isArrayExp() { return op == EXP.array ? cast(typeof(return))this : null; }
1714 inout(DotExp) isDotExp() { return op == EXP.dot ? cast(typeof(return))this : null; }
1715 inout(CommaExp) isCommaExp() { return op == EXP.comma ? cast(typeof(return))this : null; }
1716 inout(IntervalExp) isIntervalExp() { return op == EXP.interval ? cast(typeof(return))this : null; }
1717 inout(DelegatePtrExp) isDelegatePtrExp() { return op == EXP.delegatePointer ? cast(typeof(return))this : null; }
1718 inout(DelegateFuncptrExp) isDelegateFuncptrExp() { return op == EXP.delegateFunctionPointer ? cast(typeof(return))this : null; }
1719 inout(IndexExp) isIndexExp() { return op == EXP.index ? cast(typeof(return))this : null; }
1720 inout(PostExp) isPostExp() { return (op == EXP.plusPlus || op == EXP.minusMinus) ? cast(typeof(return))this : null; }
1721 inout(PreExp) isPreExp() { return (op == EXP.prePlusPlus || op == EXP.preMinusMinus) ? cast(typeof(return))this : null; }
1722 inout(AssignExp) isAssignExp() { return op == EXP.assign ? cast(typeof(return))this : null; }
1723 inout(ConstructExp) isConstructExp() { return op == EXP.construct ? cast(typeof(return))this : null; }
1724 inout(BlitExp) isBlitExp() { return op == EXP.blit ? cast(typeof(return))this : null; }
1725 inout(AddAssignExp) isAddAssignExp() { return op == EXP.addAssign ? cast(typeof(return))this : null; }
1726 inout(MinAssignExp) isMinAssignExp() { return op == EXP.minAssign ? cast(typeof(return))this : null; }
1727 inout(MulAssignExp) isMulAssignExp() { return op == EXP.mulAssign ? cast(typeof(return))this : null; }
1728
1729 inout(DivAssignExp) isDivAssignExp() { return op == EXP.divAssign ? cast(typeof(return))this : null; }
1730 inout(ModAssignExp) isModAssignExp() { return op == EXP.modAssign ? cast(typeof(return))this : null; }
1731 inout(AndAssignExp) isAndAssignExp() { return op == EXP.andAssign ? cast(typeof(return))this : null; }
1732 inout(OrAssignExp) isOrAssignExp() { return op == EXP.orAssign ? cast(typeof(return))this : null; }
1733 inout(XorAssignExp) isXorAssignExp() { return op == EXP.xorAssign ? cast(typeof(return))this : null; }
1734 inout(PowAssignExp) isPowAssignExp() { return op == EXP.powAssign ? cast(typeof(return))this : null; }
1735
1736 inout(ShlAssignExp) isShlAssignExp() { return op == EXP.leftShiftAssign ? cast(typeof(return))this : null; }
1737 inout(ShrAssignExp) isShrAssignExp() { return op == EXP.rightShiftAssign ? cast(typeof(return))this : null; }
1738 inout(UshrAssignExp) isUshrAssignExp() { return op == EXP.unsignedRightShiftAssign ? cast(typeof(return))this : null; }
1739
1740 inout(CatAssignExp) isCatAssignExp() { return op == EXP.concatenateAssign
5fee5ec3
IB
1741 ? cast(typeof(return))this
1742 : null; }
1743
9c7d5e88 1744 inout(CatElemAssignExp) isCatElemAssignExp() { return op == EXP.concatenateElemAssign
5fee5ec3
IB
1745 ? cast(typeof(return))this
1746 : null; }
1747
9c7d5e88 1748 inout(CatDcharAssignExp) isCatDcharAssignExp() { return op == EXP.concatenateDcharAssign
5fee5ec3
IB
1749 ? cast(typeof(return))this
1750 : null; }
1751
9c7d5e88
IB
1752 inout(AddExp) isAddExp() { return op == EXP.add ? cast(typeof(return))this : null; }
1753 inout(MinExp) isMinExp() { return op == EXP.min ? cast(typeof(return))this : null; }
1754 inout(CatExp) isCatExp() { return op == EXP.concatenate ? cast(typeof(return))this : null; }
1755 inout(MulExp) isMulExp() { return op == EXP.mul ? cast(typeof(return))this : null; }
1756 inout(DivExp) isDivExp() { return op == EXP.div ? cast(typeof(return))this : null; }
1757 inout(ModExp) isModExp() { return op == EXP.mod ? cast(typeof(return))this : null; }
1758 inout(PowExp) isPowExp() { return op == EXP.pow ? cast(typeof(return))this : null; }
1759 inout(ShlExp) isShlExp() { return op == EXP.leftShift ? cast(typeof(return))this : null; }
1760 inout(ShrExp) isShrExp() { return op == EXP.rightShift ? cast(typeof(return))this : null; }
1761 inout(UshrExp) isUshrExp() { return op == EXP.unsignedRightShift ? cast(typeof(return))this : null; }
1762 inout(AndExp) isAndExp() { return op == EXP.and ? cast(typeof(return))this : null; }
1763 inout(OrExp) isOrExp() { return op == EXP.or ? cast(typeof(return))this : null; }
1764 inout(XorExp) isXorExp() { return op == EXP.xor ? cast(typeof(return))this : null; }
1765 inout(LogicalExp) isLogicalExp() { return (op == EXP.andAnd || op == EXP.orOr) ? cast(typeof(return))this : null; }
1766 //inout(CmpExp) isCmpExp() { return op == EXP. ? cast(typeof(return))this : null; }
1767 inout(InExp) isInExp() { return op == EXP.in_ ? cast(typeof(return))this : null; }
1768 inout(RemoveExp) isRemoveExp() { return op == EXP.remove ? cast(typeof(return))this : null; }
1769 inout(EqualExp) isEqualExp() { return (op == EXP.equal || op == EXP.notEqual) ? cast(typeof(return))this : null; }
1770 inout(IdentityExp) isIdentityExp() { return (op == EXP.identity || op == EXP.notIdentity) ? cast(typeof(return))this : null; }
1771 inout(CondExp) isCondExp() { return op == EXP.question ? cast(typeof(return))this : null; }
1772 inout(GenericExp) isGenericExp() { return op == EXP._Generic ? cast(typeof(return))this : null; }
5fee5ec3 1773 inout(DefaultInitExp) isDefaultInitExp() { return isDefaultInitOp(op) ? cast(typeof(return))this: null; }
9c7d5e88
IB
1774 inout(FileInitExp) isFileInitExp() { return (op == EXP.file || op == EXP.fileFullPath) ? cast(typeof(return))this : null; }
1775 inout(LineInitExp) isLineInitExp() { return op == EXP.line ? cast(typeof(return))this : null; }
1776 inout(ModuleInitExp) isModuleInitExp() { return op == EXP.moduleString ? cast(typeof(return))this : null; }
1777 inout(FuncInitExp) isFuncInitExp() { return op == EXP.functionString ? cast(typeof(return))this : null; }
1778 inout(PrettyFuncInitExp) isPrettyFuncInitExp() { return op == EXP.prettyFunction ? cast(typeof(return))this : null; }
ae56e2da 1779 inout(ObjcClassReferenceExp) isObjcClassReferenceExp() { return op == EXP.objcClassReference ? cast(typeof(return))this : null; }
9c7d5e88
IB
1780 inout(ClassReferenceExp) isClassReferenceExp() { return op == EXP.classReference ? cast(typeof(return))this : null; }
1781 inout(ThrownExceptionExp) isThrownExceptionExp() { return op == EXP.thrownException ? cast(typeof(return))this : null; }
5fee5ec3 1782
6384eff5
IB
1783 inout(UnaExp) isUnaExp() pure inout nothrow @nogc
1784 {
1785 return exptab[op] & EXPFLAGS.unary ? cast(typeof(return))this : null;
1786 }
1787
1788 inout(BinExp) isBinExp() pure inout nothrow @nogc
1789 {
1790 return exptab[op] & EXPFLAGS.binary ? cast(typeof(return))this : null;
1791 }
1792
1793 inout(BinAssignExp) isBinAssignExp() pure inout nothrow @nogc
1794 {
1795 return exptab[op] & EXPFLAGS.binaryAssign ? cast(typeof(return))this : null;
1796 }
5fee5ec3
IB
1797 }
1798
1799 override void accept(Visitor v)
1800 {
1801 v.visit(this);
1802 }
1803}
1804
1805/***********************************************************
8977f4be 1806 * A compile-time known integer value
5fee5ec3
IB
1807 */
1808extern (C++) final class IntegerExp : Expression
1809{
1810 private dinteger_t value;
1811
1812 extern (D) this(const ref Loc loc, dinteger_t value, Type type)
1813 {
9c7d5e88 1814 super(loc, EXP.int64, __traits(classInstanceSize, IntegerExp));
5fee5ec3
IB
1815 //printf("IntegerExp(value = %lld, type = '%s')\n", value, type ? type.toChars() : "");
1816 assert(type);
1817 if (!type.isscalar())
1818 {
1819 //printf("%s, loc = %d\n", toChars(), loc.linnum);
1820 if (type.ty != Terror)
1821 error("integral constant must be scalar type, not `%s`", type.toChars());
1822 type = Type.terror;
1823 }
1824 this.type = type;
1825 this.value = normalize(type.toBasetype().ty, value);
1826 }
1827
1828 extern (D) this(dinteger_t value)
1829 {
9c7d5e88 1830 super(Loc.initial, EXP.int64, __traits(classInstanceSize, IntegerExp));
5fee5ec3 1831 this.type = Type.tint32;
fbdaa581 1832 this.value = cast(int)value;
5fee5ec3
IB
1833 }
1834
0fb57034 1835 static IntegerExp create(const ref Loc loc, dinteger_t value, Type type)
5fee5ec3
IB
1836 {
1837 return new IntegerExp(loc, value, type);
1838 }
1839
1840 // Same as create, but doesn't allocate memory.
0fb57034 1841 static void emplace(UnionExp* pue, const ref Loc loc, dinteger_t value, Type type)
5fee5ec3
IB
1842 {
1843 emplaceExp!(IntegerExp)(pue, loc, value, type);
1844 }
1845
1846 override bool equals(const RootObject o) const
1847 {
1848 if (this == o)
1849 return true;
1850 if (auto ne = (cast(Expression)o).isIntegerExp())
1851 {
1852 if (type.toHeadMutable().equals(ne.type.toHeadMutable()) && value == ne.value)
1853 {
1854 return true;
1855 }
1856 }
1857 return false;
1858 }
1859
1860 override dinteger_t toInteger()
1861 {
1862 // normalize() is necessary until we fix all the paints of 'type'
1863 return value = normalize(type.toBasetype().ty, value);
1864 }
1865
1866 override real_t toReal()
1867 {
1868 // normalize() is necessary until we fix all the paints of 'type'
1869 const ty = type.toBasetype().ty;
1870 const val = normalize(ty, value);
1871 value = val;
1872 return (ty == Tuns64)
fbdaa581
IB
1873 ? real_t(cast(ulong)val)
1874 : real_t(cast(long)val);
5fee5ec3
IB
1875 }
1876
1877 override real_t toImaginary()
1878 {
1879 return CTFloat.zero;
1880 }
1881
1882 override complex_t toComplex()
1883 {
1884 return complex_t(toReal());
1885 }
1886
9c7d5e88 1887 override Optional!bool toBool()
5fee5ec3
IB
1888 {
1889 bool r = toInteger() != 0;
9c7d5e88 1890 return typeof(return)(r);
5fee5ec3
IB
1891 }
1892
1893 override Expression toLvalue(Scope* sc, Expression e)
1894 {
1895 if (!e)
1896 e = this;
1897 else if (!loc.isValid())
1898 loc = e.loc;
1899 e.error("cannot modify constant `%s`", e.toChars());
1900 return ErrorExp.get();
1901 }
1902
1903 override void accept(Visitor v)
1904 {
1905 v.visit(this);
1906 }
1907
1908 dinteger_t getInteger()
1909 {
1910 return value;
1911 }
1912
1913 void setInteger(dinteger_t value)
1914 {
1915 this.value = normalize(type.toBasetype().ty, value);
1916 }
1917
1918 extern (D) static dinteger_t normalize(TY ty, dinteger_t value)
1919 {
1920 /* 'Normalize' the value of the integer to be in range of the type
1921 */
1922 dinteger_t result;
1923 switch (ty)
1924 {
1925 case Tbool:
1926 result = (value != 0);
1927 break;
1928
1929 case Tint8:
fbdaa581 1930 result = cast(byte)value;
5fee5ec3
IB
1931 break;
1932
1933 case Tchar:
1934 case Tuns8:
fbdaa581 1935 result = cast(ubyte)value;
5fee5ec3
IB
1936 break;
1937
1938 case Tint16:
fbdaa581 1939 result = cast(short)value;
5fee5ec3
IB
1940 break;
1941
1942 case Twchar:
1943 case Tuns16:
fbdaa581 1944 result = cast(ushort)value;
5fee5ec3
IB
1945 break;
1946
1947 case Tint32:
fbdaa581 1948 result = cast(int)value;
5fee5ec3
IB
1949 break;
1950
1951 case Tdchar:
1952 case Tuns32:
fbdaa581 1953 result = cast(uint)value;
5fee5ec3
IB
1954 break;
1955
1956 case Tint64:
fbdaa581 1957 result = cast(long)value;
5fee5ec3
IB
1958 break;
1959
1960 case Tuns64:
fbdaa581 1961 result = cast(ulong)value;
5fee5ec3
IB
1962 break;
1963
1964 case Tpointer:
1965 if (target.ptrsize == 8)
1966 goto case Tuns64;
1967 if (target.ptrsize == 4)
1968 goto case Tuns32;
1969 if (target.ptrsize == 2)
1970 goto case Tuns16;
1971 assert(0);
1972
1973 default:
1974 break;
1975 }
1976 return result;
1977 }
1978
1979 override IntegerExp syntaxCopy()
1980 {
1981 return this;
1982 }
1983
1984 /**
1985 * Use this instead of creating new instances for commonly used literals
1986 * such as 0 or 1.
1987 *
1988 * Parameters:
1989 * v = The value of the expression
1990 * Returns:
1991 * A static instance of the expression, typed as `Tint32`.
1992 */
1993 static IntegerExp literal(int v)()
1994 {
1995 __gshared IntegerExp theConstant;
1996 if (!theConstant)
1997 theConstant = new IntegerExp(v);
1998 return theConstant;
1999 }
2000
2001 /**
2002 * Use this instead of creating new instances for commonly used bools.
2003 *
2004 * Parameters:
2005 * b = The value of the expression
2006 * Returns:
2007 * A static instance of the expression, typed as `Type.tbool`.
2008 */
2009 static IntegerExp createBool(bool b)
2010 {
2011 __gshared IntegerExp trueExp, falseExp;
2012 if (!trueExp)
2013 {
2014 trueExp = new IntegerExp(Loc.initial, 1, Type.tbool);
2015 falseExp = new IntegerExp(Loc.initial, 0, Type.tbool);
2016 }
2017 return b ? trueExp : falseExp;
2018 }
2019}
2020
2021/***********************************************************
2022 * Use this expression for error recovery.
8977f4be 2023 *
5fee5ec3
IB
2024 * It should behave as a 'sink' to prevent further cascaded error messages.
2025 */
2026extern (C++) final class ErrorExp : Expression
2027{
2028 private extern (D) this()
2029 {
9c7d5e88 2030 super(Loc.initial, EXP.error, __traits(classInstanceSize, ErrorExp));
5fee5ec3
IB
2031 type = Type.terror;
2032 }
2033
2034 static ErrorExp get ()
2035 {
2036 if (errorexp is null)
2037 errorexp = new ErrorExp();
2038
2039 if (global.errors == 0 && global.gaggedErrors == 0)
2040 {
2041 /* Unfortunately, errors can still leak out of gagged errors,
2042 * and we need to set the error count to prevent bogus code
2043 * generation. At least give a message.
2044 */
2045 .error(Loc.initial, "unknown, please file report on issues.dlang.org");
2046 }
2047
2048 return errorexp;
2049 }
2050
2051 override Expression toLvalue(Scope* sc, Expression e)
2052 {
2053 return this;
2054 }
2055
2056 override void accept(Visitor v)
2057 {
2058 v.visit(this);
2059 }
2060
2061 extern (C++) __gshared ErrorExp errorexp; // handy shared value
2062}
2063
2064
2065/***********************************************************
2066 * An uninitialized value,
2067 * generated from void initializers.
8977f4be
IB
2068 *
2069 * https://dlang.org/spec/declaration.html#void_init
5fee5ec3
IB
2070 */
2071extern (C++) final class VoidInitExp : Expression
2072{
2073 VarDeclaration var; /// the variable from where the void value came from, null if not known
2074 /// Useful for error messages
2075
2076 extern (D) this(VarDeclaration var)
2077 {
9c7d5e88 2078 super(var.loc, EXP.void_, __traits(classInstanceSize, VoidInitExp));
5fee5ec3
IB
2079 this.var = var;
2080 this.type = var.type;
2081 }
2082
2083 override const(char)* toChars() const
2084 {
2085 return "void";
2086 }
2087
2088 override void accept(Visitor v)
2089 {
2090 v.visit(this);
2091 }
2092}
2093
2094
2095/***********************************************************
8977f4be 2096 * A compile-time known floating point number
5fee5ec3
IB
2097 */
2098extern (C++) final class RealExp : Expression
2099{
2100 real_t value;
2101
2102 extern (D) this(const ref Loc loc, real_t value, Type type)
2103 {
9c7d5e88 2104 super(loc, EXP.float64, __traits(classInstanceSize, RealExp));
5fee5ec3
IB
2105 //printf("RealExp::RealExp(%Lg)\n", value);
2106 this.value = value;
2107 this.type = type;
2108 }
2109
0fb57034 2110 static RealExp create(const ref Loc loc, real_t value, Type type)
5fee5ec3
IB
2111 {
2112 return new RealExp(loc, value, type);
2113 }
2114
2115 // Same as create, but doesn't allocate memory.
0fb57034 2116 static void emplace(UnionExp* pue, const ref Loc loc, real_t value, Type type)
5fee5ec3
IB
2117 {
2118 emplaceExp!(RealExp)(pue, loc, value, type);
2119 }
2120
2121 override bool equals(const RootObject o) const
2122 {
2123 if (this == o)
2124 return true;
2125 if (auto ne = (cast(Expression)o).isRealExp())
2126 {
2127 if (type.toHeadMutable().equals(ne.type.toHeadMutable()) && RealIdentical(value, ne.value))
2128 {
2129 return true;
2130 }
2131 }
2132 return false;
2133 }
2134
2135 override dinteger_t toInteger()
2136 {
2137 return cast(sinteger_t)toReal();
2138 }
2139
2140 override uinteger_t toUInteger()
2141 {
2142 return cast(uinteger_t)toReal();
2143 }
2144
2145 override real_t toReal()
2146 {
2147 return type.isreal() ? value : CTFloat.zero;
2148 }
2149
2150 override real_t toImaginary()
2151 {
2152 return type.isreal() ? CTFloat.zero : value;
2153 }
2154
2155 override complex_t toComplex()
2156 {
2157 return complex_t(toReal(), toImaginary());
2158 }
2159
9c7d5e88 2160 override Optional!bool toBool()
5fee5ec3 2161 {
9c7d5e88 2162 return typeof(return)(!!value);
5fee5ec3
IB
2163 }
2164
2165 override void accept(Visitor v)
2166 {
2167 v.visit(this);
2168 }
2169}
2170
2171/***********************************************************
8977f4be 2172 * A compile-time complex number (deprecated)
5fee5ec3
IB
2173 */
2174extern (C++) final class ComplexExp : Expression
2175{
2176 complex_t value;
2177
2178 extern (D) this(const ref Loc loc, complex_t value, Type type)
2179 {
9c7d5e88 2180 super(loc, EXP.complex80, __traits(classInstanceSize, ComplexExp));
5fee5ec3
IB
2181 this.value = value;
2182 this.type = type;
2183 //printf("ComplexExp::ComplexExp(%s)\n", toChars());
2184 }
2185
0fb57034 2186 static ComplexExp create(const ref Loc loc, complex_t value, Type type)
5fee5ec3
IB
2187 {
2188 return new ComplexExp(loc, value, type);
2189 }
2190
2191 // Same as create, but doesn't allocate memory.
0fb57034 2192 static void emplace(UnionExp* pue, const ref Loc loc, complex_t value, Type type)
5fee5ec3
IB
2193 {
2194 emplaceExp!(ComplexExp)(pue, loc, value, type);
2195 }
2196
2197 override bool equals(const RootObject o) const
2198 {
2199 if (this == o)
2200 return true;
2201 if (auto ne = (cast(Expression)o).isComplexExp())
2202 {
2203 if (type.toHeadMutable().equals(ne.type.toHeadMutable()) && RealIdentical(creall(value), creall(ne.value)) && RealIdentical(cimagl(value), cimagl(ne.value)))
2204 {
2205 return true;
2206 }
2207 }
2208 return false;
2209 }
2210
2211 override dinteger_t toInteger()
2212 {
2213 return cast(sinteger_t)toReal();
2214 }
2215
2216 override uinteger_t toUInteger()
2217 {
2218 return cast(uinteger_t)toReal();
2219 }
2220
2221 override real_t toReal()
2222 {
2223 return creall(value);
2224 }
2225
2226 override real_t toImaginary()
2227 {
2228 return cimagl(value);
2229 }
2230
2231 override complex_t toComplex()
2232 {
2233 return value;
2234 }
2235
9c7d5e88 2236 override Optional!bool toBool()
5fee5ec3 2237 {
9c7d5e88 2238 return typeof(return)(!!value);
5fee5ec3
IB
2239 }
2240
2241 override void accept(Visitor v)
2242 {
2243 v.visit(this);
2244 }
2245}
2246
2247/***********************************************************
8977f4be
IB
2248 * An identifier in the context of an expression (as opposed to a declaration)
2249 *
2250 * ---
2251 * int x; // VarDeclaration with Identifier
2252 * x++; // PostExp with IdentifierExp
2253 * ---
5fee5ec3
IB
2254 */
2255extern (C++) class IdentifierExp : Expression
2256{
2257 Identifier ident;
2258
2259 extern (D) this(const ref Loc loc, Identifier ident)
2260 {
9c7d5e88 2261 super(loc, EXP.identifier, __traits(classInstanceSize, IdentifierExp));
5fee5ec3
IB
2262 this.ident = ident;
2263 }
2264
0fb57034 2265 static IdentifierExp create(const ref Loc loc, Identifier ident)
5fee5ec3
IB
2266 {
2267 return new IdentifierExp(loc, ident);
2268 }
2269
2270 override final bool isLvalue()
2271 {
2272 return true;
2273 }
2274
2275 override final Expression toLvalue(Scope* sc, Expression e)
2276 {
2277 return this;
2278 }
2279
2280 override void accept(Visitor v)
2281 {
2282 v.visit(this);
2283 }
2284}
2285
2286/***********************************************************
8977f4be
IB
2287 * The dollar operator used when indexing or slicing an array. E.g `a[$]`, `a[1 .. $]` etc.
2288 *
2289 * https://dlang.org/spec/arrays.html#array-length
5fee5ec3
IB
2290 */
2291extern (C++) final class DollarExp : IdentifierExp
2292{
2293 extern (D) this(const ref Loc loc)
2294 {
2295 super(loc, Id.dollar);
2296 }
2297
2298 override void accept(Visitor v)
2299 {
2300 v.visit(this);
2301 }
2302}
2303
2304/***********************************************************
2305 * Won't be generated by parser.
2306 */
2307extern (C++) final class DsymbolExp : Expression
2308{
2309 Dsymbol s;
2310 bool hasOverloads;
2311
2312 extern (D) this(const ref Loc loc, Dsymbol s, bool hasOverloads = true)
2313 {
9c7d5e88 2314 super(loc, EXP.dSymbol, __traits(classInstanceSize, DsymbolExp));
5fee5ec3
IB
2315 this.s = s;
2316 this.hasOverloads = hasOverloads;
2317 }
2318
2319 override bool isLvalue()
2320 {
2321 return true;
2322 }
2323
2324 override Expression toLvalue(Scope* sc, Expression e)
2325 {
2326 return this;
2327 }
2328
2329 override void accept(Visitor v)
2330 {
2331 v.visit(this);
2332 }
2333}
2334
2335/***********************************************************
c43b5909 2336 * https://dlang.org/spec/expression.html#this
5fee5ec3
IB
2337 */
2338extern (C++) class ThisExp : Expression
2339{
2340 VarDeclaration var;
2341
2342 extern (D) this(const ref Loc loc)
2343 {
9c7d5e88 2344 super(loc, EXP.this_, __traits(classInstanceSize, ThisExp));
5fee5ec3
IB
2345 //printf("ThisExp::ThisExp() loc = %d\n", loc.linnum);
2346 }
2347
9c7d5e88 2348 this(const ref Loc loc, const EXP tok)
5fee5ec3
IB
2349 {
2350 super(loc, tok, __traits(classInstanceSize, ThisExp));
2351 //printf("ThisExp::ThisExp() loc = %d\n", loc.linnum);
2352 }
2353
2354 override ThisExp syntaxCopy()
2355 {
2356 auto r = cast(ThisExp) super.syntaxCopy();
2357 // require new semantic (possibly new `var` etc.)
2358 r.type = null;
2359 r.var = null;
2360 return r;
2361 }
2362
9c7d5e88 2363 override Optional!bool toBool()
5fee5ec3 2364 {
9c7d5e88
IB
2365 // `this` is never null (what about structs?)
2366 return typeof(return)(true);
5fee5ec3
IB
2367 }
2368
2369 override final bool isLvalue()
2370 {
2371 // Class `this` should be an rvalue; struct `this` should be an lvalue.
2372 return type.toBasetype().ty != Tclass;
2373 }
2374
2375 override final Expression toLvalue(Scope* sc, Expression e)
2376 {
2377 if (type.toBasetype().ty == Tclass)
2378 {
2379 // Class `this` is an rvalue; struct `this` is an lvalue.
2380 return Expression.toLvalue(sc, e);
2381 }
2382 return this;
2383 }
2384
2385 override void accept(Visitor v)
2386 {
2387 v.visit(this);
2388 }
2389}
2390
2391/***********************************************************
c43b5909 2392 * https://dlang.org/spec/expression.html#super
5fee5ec3
IB
2393 */
2394extern (C++) final class SuperExp : ThisExp
2395{
2396 extern (D) this(const ref Loc loc)
2397 {
9c7d5e88 2398 super(loc, EXP.super_);
5fee5ec3
IB
2399 }
2400
2401 override void accept(Visitor v)
2402 {
2403 v.visit(this);
2404 }
2405}
2406
2407/***********************************************************
8977f4be
IB
2408 * A compile-time known `null` value
2409 *
c43b5909 2410 * https://dlang.org/spec/expression.html#null
5fee5ec3
IB
2411 */
2412extern (C++) final class NullExp : Expression
2413{
2414 extern (D) this(const ref Loc loc, Type type = null)
2415 {
9c7d5e88 2416 super(loc, EXP.null_, __traits(classInstanceSize, NullExp));
5fee5ec3
IB
2417 this.type = type;
2418 }
2419
2420 override bool equals(const RootObject o) const
2421 {
2422 if (auto e = o.isExpression())
2423 {
9c7d5e88 2424 if (e.op == EXP.null_ && type.equals(e.type))
5fee5ec3
IB
2425 {
2426 return true;
2427 }
2428 }
2429 return false;
2430 }
2431
9c7d5e88 2432 override Optional!bool toBool()
5fee5ec3 2433 {
9c7d5e88
IB
2434 // null in any type is false
2435 return typeof(return)(false);
5fee5ec3
IB
2436 }
2437
2438 override StringExp toStringExp()
2439 {
2440 if (implicitConvTo(Type.tstring))
2441 {
2442 auto se = new StringExp(loc, (cast(char*)mem.xcalloc(1, 1))[0 .. 0]);
2443 se.type = Type.tstring;
2444 return se;
2445 }
2446 return null;
2447 }
2448
2449 override void accept(Visitor v)
2450 {
2451 v.visit(this);
2452 }
2453}
2454
2455/***********************************************************
c43b5909 2456 * https://dlang.org/spec/expression.html#string_literals
5fee5ec3
IB
2457 */
2458extern (C++) final class StringExp : Expression
2459{
2460 private union
2461 {
2462 char* string; // if sz == 1
2463 wchar* wstring; // if sz == 2
2464 dchar* dstring; // if sz == 4
2465 } // (const if ownedByCtfe == OwnedBy.code)
2466 size_t len; // number of code units
2467 ubyte sz = 1; // 1: char, 2: wchar, 4: dchar
2468 ubyte committed; // !=0 if type is committed
2469 enum char NoPostfix = 0;
2470 char postfix = NoPostfix; // 'c', 'w', 'd'
2471 OwnedBy ownedByCtfe = OwnedBy.code;
2472
2473 extern (D) this(const ref Loc loc, const(void)[] string)
2474 {
9c7d5e88 2475 super(loc, EXP.string_, __traits(classInstanceSize, StringExp));
5fee5ec3
IB
2476 this.string = cast(char*)string.ptr; // note that this.string should be const
2477 this.len = string.length;
2478 this.sz = 1; // work around LDC bug #1286
2479 }
2480
2481 extern (D) this(const ref Loc loc, const(void)[] string, size_t len, ubyte sz, char postfix = NoPostfix)
2482 {
9c7d5e88 2483 super(loc, EXP.string_, __traits(classInstanceSize, StringExp));
5fee5ec3
IB
2484 this.string = cast(char*)string.ptr; // note that this.string should be const
2485 this.len = len;
2486 this.sz = sz;
2487 this.postfix = postfix;
2488 }
2489
0fb57034 2490 static StringExp create(const ref Loc loc, const(char)* s)
5fee5ec3
IB
2491 {
2492 return new StringExp(loc, s.toDString());
2493 }
2494
0fb57034 2495 static StringExp create(const ref Loc loc, const(void)* string, size_t len)
5fee5ec3
IB
2496 {
2497 return new StringExp(loc, string[0 .. len]);
2498 }
2499
2500 // Same as create, but doesn't allocate memory.
0fb57034 2501 static void emplace(UnionExp* pue, const ref Loc loc, const(char)* s)
5fee5ec3
IB
2502 {
2503 emplaceExp!(StringExp)(pue, loc, s.toDString());
2504 }
2505
0fb57034 2506 extern (D) static void emplace(UnionExp* pue, const ref Loc loc, const(void)[] string)
5fee5ec3
IB
2507 {
2508 emplaceExp!(StringExp)(pue, loc, string);
2509 }
2510
0fb57034 2511 extern (D) static void emplace(UnionExp* pue, const ref Loc loc, const(void)[] string, size_t len, ubyte sz, char postfix)
5fee5ec3
IB
2512 {
2513 emplaceExp!(StringExp)(pue, loc, string, len, sz, postfix);
2514 }
2515
2516 override bool equals(const RootObject o) const
2517 {
2518 //printf("StringExp::equals('%s') %s\n", o.toChars(), toChars());
2519 if (auto e = o.isExpression())
2520 {
2521 if (auto se = e.isStringExp())
2522 {
2523 return compare(se) == 0;
2524 }
2525 }
2526 return false;
2527 }
2528
2529 /**********************************
2530 * Return the number of code units the string would be if it were re-encoded
2531 * as tynto.
2532 * Params:
2533 * tynto = code unit type of the target encoding
2534 * Returns:
2535 * number of code units
2536 */
2537 size_t numberOfCodeUnits(int tynto = 0) const
2538 {
2539 int encSize;
2540 switch (tynto)
2541 {
2542 case 0: return len;
2543 case Tchar: encSize = 1; break;
2544 case Twchar: encSize = 2; break;
2545 case Tdchar: encSize = 4; break;
2546 default:
2547 assert(0);
2548 }
2549 if (sz == encSize)
2550 return len;
2551
2552 size_t result = 0;
2553 dchar c;
2554
2555 switch (sz)
2556 {
2557 case 1:
2558 for (size_t u = 0; u < len;)
2559 {
2560 if (const s = utf_decodeChar(string[0 .. len], u, c))
2561 {
2562 error("%.*s", cast(int)s.length, s.ptr);
2563 return 0;
2564 }
2565 result += utf_codeLength(encSize, c);
2566 }
2567 break;
2568
2569 case 2:
2570 for (size_t u = 0; u < len;)
2571 {
2572 if (const s = utf_decodeWchar(wstring[0 .. len], u, c))
2573 {
2574 error("%.*s", cast(int)s.length, s.ptr);
2575 return 0;
2576 }
2577 result += utf_codeLength(encSize, c);
2578 }
2579 break;
2580
2581 case 4:
2582 foreach (u; 0 .. len)
2583 {
2584 result += utf_codeLength(encSize, dstring[u]);
2585 }
2586 break;
2587
2588 default:
2589 assert(0);
2590 }
2591 return result;
2592 }
2593
2594 /**********************************************
2595 * Write the contents of the string to dest.
2596 * Use numberOfCodeUnits() to determine size of result.
2597 * Params:
2598 * dest = destination
2599 * tyto = encoding type of the result
2600 * zero = add terminating 0
2601 */
2602 void writeTo(void* dest, bool zero, int tyto = 0) const
2603 {
2604 int encSize;
2605 switch (tyto)
2606 {
2607 case 0: encSize = sz; break;
2608 case Tchar: encSize = 1; break;
2609 case Twchar: encSize = 2; break;
2610 case Tdchar: encSize = 4; break;
2611 default:
2612 assert(0);
2613 }
2614 if (sz == encSize)
2615 {
2616 memcpy(dest, string, len * sz);
2617 if (zero)
2618 memset(dest + len * sz, 0, sz);
2619 }
2620 else
2621 assert(0);
2622 }
2623
2624 /*********************************************
2625 * Get the code unit at index i
2626 * Params:
2627 * i = index
2628 * Returns:
2629 * code unit at index i
2630 */
2631 dchar getCodeUnit(size_t i) const pure
2632 {
2633 assert(i < len);
2634 final switch (sz)
2635 {
2636 case 1:
2637 return string[i];
2638 case 2:
2639 return wstring[i];
2640 case 4:
2641 return dstring[i];
2642 }
2643 }
2644
2645 /*********************************************
2646 * Set the code unit at index i to c
2647 * Params:
2648 * i = index
2649 * c = code unit to set it to
2650 */
2651 void setCodeUnit(size_t i, dchar c)
2652 {
2653 assert(i < len);
2654 final switch (sz)
2655 {
2656 case 1:
2657 string[i] = cast(char)c;
2658 break;
2659 case 2:
2660 wstring[i] = cast(wchar)c;
2661 break;
2662 case 4:
2663 dstring[i] = c;
2664 break;
2665 }
2666 }
2667
2668 override StringExp toStringExp()
2669 {
2670 return this;
2671 }
2672
2673 /****************************************
2674 * Convert string to char[].
2675 */
2676 StringExp toUTF8(Scope* sc)
2677 {
2678 if (sz != 1)
2679 {
2680 // Convert to UTF-8 string
2681 committed = 0;
2682 Expression e = castTo(sc, Type.tchar.arrayOf());
2683 e = e.optimize(WANTvalue);
2684 auto se = e.isStringExp();
2685 assert(se.sz == 1);
2686 return se;
2687 }
2688 return this;
2689 }
2690
2691 /**
2692 * Compare two `StringExp` by length, then value
2693 *
2694 * The comparison is not the usual C-style comparison as seen with
2695 * `strcmp` or `memcmp`, but instead first compare based on the length.
2696 * This allows both faster lookup and sorting when comparing sparse data.
2697 *
2698 * This ordering scheme is relied on by the string-switching feature.
2699 * Code in Druntime's `core.internal.switch_` relies on this ordering
2700 * when doing a binary search among case statements.
2701 *
2702 * Both `StringExp` should be of the same encoding.
2703 *
2704 * Params:
2705 * se2 = String expression to compare `this` to
2706 *
2707 * Returns:
2708 * `0` when `this` is equal to se2, a value greater than `0` if
2709 * `this` should be considered greater than `se2`,
2710 * and a value less than `0` if `this` is lesser than `se2`.
2711 */
2712 int compare(const StringExp se2) const nothrow pure @nogc
2713 {
2714 //printf("StringExp::compare()\n");
2715 const len1 = len;
2716 const len2 = se2.len;
2717
2718 assert(this.sz == se2.sz, "Comparing string expressions of different sizes");
31350635 2719 //printf("sz = %d, len1 = %d, len2 = %d\n", sz, cast(int)len1, cast(int)len2);
5fee5ec3
IB
2720 if (len1 == len2)
2721 {
2722 switch (sz)
2723 {
2724 case 1:
2725 return memcmp(string, se2.string, len1);
2726
2727 case 2:
2728 {
2729 wchar* s1 = cast(wchar*)string;
2730 wchar* s2 = cast(wchar*)se2.string;
2731 foreach (u; 0 .. len)
2732 {
2733 if (s1[u] != s2[u])
2734 return s1[u] - s2[u];
2735 }
2736 }
2737 break;
2738 case 4:
2739 {
2740 dchar* s1 = cast(dchar*)string;
2741 dchar* s2 = cast(dchar*)se2.string;
2742 foreach (u; 0 .. len)
2743 {
2744 if (s1[u] != s2[u])
2745 return s1[u] - s2[u];
2746 }
2747 }
2748 break;
2749 default:
2750 assert(0);
2751 }
2752 }
2753 return cast(int)(len1 - len2);
2754 }
2755
9c7d5e88 2756 override Optional!bool toBool()
5fee5ec3 2757 {
9c7d5e88
IB
2758 // Keep the old behaviour for this refactoring
2759 // Should probably match language spec instead and check for length
2760 return typeof(return)(true);
5fee5ec3
IB
2761 }
2762
2763 override bool isLvalue()
2764 {
2765 /* string literal is rvalue in default, but
2766 * conversion to reference of static array is only allowed.
2767 */
2768 return (type && type.toBasetype().ty == Tsarray);
2769 }
2770
2771 override Expression toLvalue(Scope* sc, Expression e)
2772 {
2773 //printf("StringExp::toLvalue(%s) type = %s\n", toChars(), type ? type.toChars() : NULL);
2774 return (type && type.toBasetype().ty == Tsarray) ? this : Expression.toLvalue(sc, e);
2775 }
2776
2777 override Expression modifiableLvalue(Scope* sc, Expression e)
2778 {
2779 error("cannot modify string literal `%s`", toChars());
2780 return ErrorExp.get();
2781 }
2782
5fee5ec3
IB
2783 /********************************
2784 * Convert string contents to a 0 terminated string,
2785 * allocated by mem.xmalloc().
2786 */
2787 extern (D) const(char)[] toStringz() const
2788 {
2789 auto nbytes = len * sz;
2790 char* s = cast(char*)mem.xmalloc(nbytes + sz);
2791 writeTo(s, true);
2792 return s[0 .. nbytes];
2793 }
2794
2795 extern (D) const(char)[] peekString() const
2796 {
2797 assert(sz == 1);
2798 return this.string[0 .. len];
2799 }
2800
2801 extern (D) const(wchar)[] peekWstring() const
2802 {
2803 assert(sz == 2);
2804 return this.wstring[0 .. len];
2805 }
2806
2807 extern (D) const(dchar)[] peekDstring() const
2808 {
2809 assert(sz == 4);
2810 return this.dstring[0 .. len];
2811 }
2812
2813 /*******************
2814 * Get a slice of the data.
2815 */
2816 extern (D) const(ubyte)[] peekData() const
2817 {
2818 return cast(const(ubyte)[])this.string[0 .. len * sz];
2819 }
2820
2821 /*******************
2822 * Borrow a slice of the data, so the caller can modify
2823 * it in-place (!)
2824 */
2825 extern (D) ubyte[] borrowData()
2826 {
2827 return cast(ubyte[])this.string[0 .. len * sz];
2828 }
2829
2830 /***********************
2831 * Set new string data.
2832 * `this` becomes the new owner of the data.
2833 */
2834 extern (D) void setData(void* s, size_t len, ubyte sz)
2835 {
2836 this.string = cast(char*)s;
2837 this.len = len;
2838 this.sz = sz;
2839 }
2840
2841 override void accept(Visitor v)
2842 {
2843 v.visit(this);
2844 }
2845}
2846
2847/***********************************************************
8977f4be
IB
2848 * A sequence of expressions
2849 *
2850 * ---
2851 * alias AliasSeq(T...) = T;
2852 * alias Tup = AliasSeq!(3, int, "abc");
2853 * ---
5fee5ec3
IB
2854 */
2855extern (C++) final class TupleExp : Expression
2856{
2857 /* Tuple-field access may need to take out its side effect part.
2858 * For example:
2859 * foo().tupleof
2860 * is rewritten as:
2861 * (ref __tup = foo(); tuple(__tup.field0, __tup.field1, ...))
2862 * The declaration of temporary variable __tup will be stored in TupleExp.e0.
2863 */
2864 Expression e0;
2865
2866 Expressions* exps;
2867
2868 extern (D) this(const ref Loc loc, Expression e0, Expressions* exps)
2869 {
9c7d5e88 2870 super(loc, EXP.tuple, __traits(classInstanceSize, TupleExp));
5fee5ec3
IB
2871 //printf("TupleExp(this = %p)\n", this);
2872 this.e0 = e0;
2873 this.exps = exps;
2874 }
2875
2876 extern (D) this(const ref Loc loc, Expressions* exps)
2877 {
9c7d5e88 2878 super(loc, EXP.tuple, __traits(classInstanceSize, TupleExp));
5fee5ec3
IB
2879 //printf("TupleExp(this = %p)\n", this);
2880 this.exps = exps;
2881 }
2882
2883 extern (D) this(const ref Loc loc, TupleDeclaration tup)
2884 {
9c7d5e88 2885 super(loc, EXP.tuple, __traits(classInstanceSize, TupleExp));
5fee5ec3
IB
2886 this.exps = new Expressions();
2887
6d799f0a 2888 this.exps.reserve(tup.objects.length);
5fee5ec3
IB
2889 foreach (o; *tup.objects)
2890 {
2891 if (Dsymbol s = getDsymbol(o))
2892 {
2893 /* If tuple element represents a symbol, translate to DsymbolExp
2894 * to supply implicit 'this' if needed later.
2895 */
2896 Expression e = new DsymbolExp(loc, s);
2897 this.exps.push(e);
2898 }
2899 else if (auto eo = o.isExpression())
2900 {
2901 auto e = eo.copy();
2902 e.loc = loc; // https://issues.dlang.org/show_bug.cgi?id=15669
2903 this.exps.push(e);
2904 }
2905 else if (auto t = o.isType())
2906 {
2907 Expression e = new TypeExp(loc, t);
2908 this.exps.push(e);
2909 }
2910 else
2911 {
2912 error("`%s` is not an expression", o.toChars());
2913 }
2914 }
2915 }
2916
0fb57034 2917 static TupleExp create(const ref Loc loc, Expressions* exps)
5fee5ec3
IB
2918 {
2919 return new TupleExp(loc, exps);
2920 }
2921
5fee5ec3
IB
2922 override TupleExp syntaxCopy()
2923 {
2924 return new TupleExp(loc, e0 ? e0.syntaxCopy() : null, arraySyntaxCopy(exps));
2925 }
2926
2927 override bool equals(const RootObject o) const
2928 {
2929 if (this == o)
2930 return true;
2931 if (auto e = o.isExpression())
2932 if (auto te = e.isTupleExp())
2933 {
6d799f0a 2934 if (exps.length != te.exps.length)
5fee5ec3
IB
2935 return false;
2936 if (e0 && !e0.equals(te.e0) || !e0 && te.e0)
2937 return false;
2938 foreach (i, e1; *exps)
2939 {
2940 auto e2 = (*te.exps)[i];
2941 if (!e1.equals(e2))
2942 return false;
2943 }
2944 return true;
2945 }
2946 return false;
2947 }
2948
2949 override void accept(Visitor v)
2950 {
2951 v.visit(this);
2952 }
2953}
2954
2955/***********************************************************
2956 * [ e1, e2, e3, ... ]
2957 *
c43b5909 2958 * https://dlang.org/spec/expression.html#array_literals
5fee5ec3
IB
2959 */
2960extern (C++) final class ArrayLiteralExp : Expression
2961{
2962 /** If !is null, elements[] can be sparse and basis is used for the
2963 * "default" element value. In other words, non-null elements[i] overrides
2964 * this 'basis' value.
2965 */
2966 Expression basis;
2967
2968 Expressions* elements;
2969 OwnedBy ownedByCtfe = OwnedBy.code;
7e7ebe3e 2970 bool onstack = false;
5fee5ec3
IB
2971
2972 extern (D) this(const ref Loc loc, Type type, Expressions* elements)
2973 {
9c7d5e88 2974 super(loc, EXP.arrayLiteral, __traits(classInstanceSize, ArrayLiteralExp));
5fee5ec3
IB
2975 this.type = type;
2976 this.elements = elements;
2977 }
2978
2979 extern (D) this(const ref Loc loc, Type type, Expression e)
2980 {
9c7d5e88 2981 super(loc, EXP.arrayLiteral, __traits(classInstanceSize, ArrayLiteralExp));
5fee5ec3
IB
2982 this.type = type;
2983 elements = new Expressions();
2984 elements.push(e);
2985 }
2986
2987 extern (D) this(const ref Loc loc, Type type, Expression basis, Expressions* elements)
2988 {
9c7d5e88 2989 super(loc, EXP.arrayLiteral, __traits(classInstanceSize, ArrayLiteralExp));
5fee5ec3
IB
2990 this.type = type;
2991 this.basis = basis;
2992 this.elements = elements;
2993 }
2994
0fb57034 2995 static ArrayLiteralExp create(const ref Loc loc, Expressions* elements)
5fee5ec3
IB
2996 {
2997 return new ArrayLiteralExp(loc, null, elements);
2998 }
2999
3000 // Same as create, but doesn't allocate memory.
0fb57034 3001 static void emplace(UnionExp* pue, const ref Loc loc, Expressions* elements)
5fee5ec3
IB
3002 {
3003 emplaceExp!(ArrayLiteralExp)(pue, loc, null, elements);
3004 }
3005
3006 override ArrayLiteralExp syntaxCopy()
3007 {
3008 return new ArrayLiteralExp(loc,
3009 null,
3010 basis ? basis.syntaxCopy() : null,
3011 arraySyntaxCopy(elements));
3012 }
3013
3014 override bool equals(const RootObject o) const
3015 {
3016 if (this == o)
3017 return true;
3018 auto e = o.isExpression();
3019 if (!e)
3020 return false;
3021 if (auto ae = e.isArrayLiteralExp())
3022 {
6d799f0a 3023 if (elements.length != ae.elements.length)
5fee5ec3 3024 return false;
6d799f0a 3025 if (elements.length == 0 && !type.equals(ae.type))
5fee5ec3
IB
3026 {
3027 return false;
3028 }
3029
3030 foreach (i, e1; *elements)
3031 {
3032 auto e2 = (*ae.elements)[i];
3033 auto e1x = e1 ? e1 : basis;
3034 auto e2x = e2 ? e2 : ae.basis;
3035
3036 if (e1x != e2x && (!e1x || !e2x || !e1x.equals(e2x)))
3037 return false;
3038 }
3039 return true;
3040 }
3041 return false;
3042 }
3043
3044 Expression getElement(size_t i)
3045 {
3046 return this[i];
3047 }
3048
3049 Expression opIndex(size_t i)
3050 {
3051 auto el = (*elements)[i];
3052 return el ? el : basis;
3053 }
3054
9c7d5e88 3055 override Optional!bool toBool()
5fee5ec3 3056 {
6d799f0a 3057 size_t dim = elements ? elements.length : 0;
9c7d5e88 3058 return typeof(return)(dim != 0);
5fee5ec3
IB
3059 }
3060
3061 override StringExp toStringExp()
3062 {
3063 TY telem = type.nextOf().toBasetype().ty;
6d799f0a 3064 if (telem.isSomeChar || (telem == Tvoid && (!elements || elements.length == 0)))
5fee5ec3
IB
3065 {
3066 ubyte sz = 1;
3067 if (telem == Twchar)
3068 sz = 2;
3069 else if (telem == Tdchar)
3070 sz = 4;
3071
3072 OutBuffer buf;
3073 if (elements)
3074 {
6d799f0a 3075 foreach (i; 0 .. elements.length)
5fee5ec3
IB
3076 {
3077 auto ch = this[i];
9c7d5e88 3078 if (ch.op != EXP.int64)
5fee5ec3
IB
3079 return null;
3080 if (sz == 1)
3081 buf.writeByte(cast(uint)ch.toInteger());
3082 else if (sz == 2)
3083 buf.writeword(cast(uint)ch.toInteger());
3084 else
3085 buf.write4(cast(uint)ch.toInteger());
3086 }
3087 }
3088 char prefix;
3089 if (sz == 1)
3090 {
3091 prefix = 'c';
3092 buf.writeByte(0);
3093 }
3094 else if (sz == 2)
3095 {
3096 prefix = 'w';
3097 buf.writeword(0);
3098 }
3099 else
3100 {
3101 prefix = 'd';
3102 buf.write4(0);
3103 }
3104
3105 const size_t len = buf.length / sz - 1;
3106 auto se = new StringExp(loc, buf.extractSlice()[0 .. len * sz], len, sz, prefix);
3107 se.sz = sz;
3108 se.type = type;
3109 return se;
3110 }
3111 return null;
3112 }
3113
3114 override void accept(Visitor v)
3115 {
3116 v.visit(this);
3117 }
3118}
3119
3120/***********************************************************
3121 * [ key0 : value0, key1 : value1, ... ]
3122 *
c43b5909 3123 * https://dlang.org/spec/expression.html#associative_array_literals
5fee5ec3
IB
3124 */
3125extern (C++) final class AssocArrayLiteralExp : Expression
3126{
3127 Expressions* keys;
3128 Expressions* values;
3129
3130 OwnedBy ownedByCtfe = OwnedBy.code;
3131
3132 extern (D) this(const ref Loc loc, Expressions* keys, Expressions* values)
3133 {
9c7d5e88 3134 super(loc, EXP.assocArrayLiteral, __traits(classInstanceSize, AssocArrayLiteralExp));
6d799f0a 3135 assert(keys.length == values.length);
5fee5ec3
IB
3136 this.keys = keys;
3137 this.values = values;
3138 }
3139
3140 override bool equals(const RootObject o) const
3141 {
3142 if (this == o)
3143 return true;
3144 auto e = o.isExpression();
3145 if (!e)
3146 return false;
3147 if (auto ae = e.isAssocArrayLiteralExp())
3148 {
6d799f0a 3149 if (keys.length != ae.keys.length)
5fee5ec3
IB
3150 return false;
3151 size_t count = 0;
3152 foreach (i, key; *keys)
3153 {
3154 foreach (j, akey; *ae.keys)
3155 {
3156 if (key.equals(akey))
3157 {
3158 if (!(*values)[i].equals((*ae.values)[j]))
3159 return false;
3160 ++count;
3161 }
3162 }
3163 }
6d799f0a 3164 return count == keys.length;
5fee5ec3
IB
3165 }
3166 return false;
3167 }
3168
3169 override AssocArrayLiteralExp syntaxCopy()
3170 {
3171 return new AssocArrayLiteralExp(loc, arraySyntaxCopy(keys), arraySyntaxCopy(values));
3172 }
3173
9c7d5e88 3174 override Optional!bool toBool()
5fee5ec3 3175 {
6d799f0a 3176 size_t dim = keys.length;
9c7d5e88 3177 return typeof(return)(dim != 0);
5fee5ec3
IB
3178 }
3179
3180 override void accept(Visitor v)
3181 {
3182 v.visit(this);
3183 }
3184}
3185
3186enum stageScrub = 0x1; /// scrubReturnValue is running
3187enum stageSearchPointers = 0x2; /// hasNonConstPointers is running
3188enum stageOptimize = 0x4; /// optimize is running
3189enum stageApply = 0x8; /// apply is running
3190enum stageInlineScan = 0x10; /// inlineScan is running
3191enum stageToCBuffer = 0x20; /// toCBuffer is running
3192
3193/***********************************************************
3194 * sd( e1, e2, e3, ... )
3195 */
3196extern (C++) final class StructLiteralExp : Expression
3197{
3198 StructDeclaration sd; /// which aggregate this is for
3199 Expressions* elements; /// parallels sd.fields[] with null entries for fields to skip
3200 Type stype; /// final type of result (can be different from sd's type)
3201
3202 Symbol* sym; /// back end symbol to initialize with literal
3203
3204 /** pointer to the origin instance of the expression.
3205 * once a new expression is created, origin is set to 'this'.
3206 * anytime when an expression copy is created, 'origin' pointer is set to
3207 * 'origin' pointer value of the original expression.
3208 */
3209 StructLiteralExp origin;
3210
3211 /// those fields need to prevent a infinite recursion when one field of struct initialized with 'this' pointer.
3212 StructLiteralExp inlinecopy;
3213
3214 /** anytime when recursive function is calling, 'stageflags' marks with bit flag of
3215 * current stage and unmarks before return from this function.
3216 * 'inlinecopy' uses similar 'stageflags' and from multiple evaluation 'doInline'
3217 * (with infinite recursion) of this expression.
3218 */
3219 int stageflags;
3220
3221 bool useStaticInit; /// if this is true, use the StructDeclaration's init symbol
3222 bool isOriginal = false; /// used when moving instances to indicate `this is this.origin`
3223 OwnedBy ownedByCtfe = OwnedBy.code;
3224
3225 extern (D) this(const ref Loc loc, StructDeclaration sd, Expressions* elements, Type stype = null)
3226 {
9c7d5e88 3227 super(loc, EXP.structLiteral, __traits(classInstanceSize, StructLiteralExp));
5fee5ec3
IB
3228 this.sd = sd;
3229 if (!elements)
3230 elements = new Expressions();
3231 this.elements = elements;
3232 this.stype = stype;
3233 this.origin = this;
3234 //printf("StructLiteralExp::StructLiteralExp(%s)\n", toChars());
3235 }
3236
0fb57034 3237 static StructLiteralExp create(const ref Loc loc, StructDeclaration sd, void* elements, Type stype = null)
5fee5ec3
IB
3238 {
3239 return new StructLiteralExp(loc, sd, cast(Expressions*)elements, stype);
3240 }
3241
3242 override bool equals(const RootObject o) const
3243 {
3244 if (this == o)
3245 return true;
3246 auto e = o.isExpression();
3247 if (!e)
3248 return false;
3249 if (auto se = e.isStructLiteralExp())
3250 {
3251 if (!type.equals(se.type))
3252 return false;
6d799f0a 3253 if (elements.length != se.elements.length)
5fee5ec3
IB
3254 return false;
3255 foreach (i, e1; *elements)
3256 {
3257 auto e2 = (*se.elements)[i];
3258 if (e1 != e2 && (!e1 || !e2 || !e1.equals(e2)))
3259 return false;
3260 }
3261 return true;
3262 }
3263 return false;
3264 }
3265
3266 override StructLiteralExp syntaxCopy()
3267 {
3268 auto exp = new StructLiteralExp(loc, sd, arraySyntaxCopy(elements), type ? type : stype);
3269 exp.origin = this;
3270 return exp;
3271 }
3272
3273 /**************************************
3274 * Gets expression at offset of type.
3275 * Returns NULL if not found.
3276 */
3277 Expression getField(Type type, uint offset)
3278 {
3279 //printf("StructLiteralExp::getField(this = %s, type = %s, offset = %u)\n",
3280 // /*toChars()*/"", type.toChars(), offset);
3281 Expression e = null;
3282 int i = getFieldIndex(type, offset);
3283
3284 if (i != -1)
3285 {
3286 //printf("\ti = %d\n", i);
3287 if (i >= sd.nonHiddenFields())
3288 return null;
3289
6d799f0a 3290 assert(i < elements.length);
5fee5ec3
IB
3291 e = (*elements)[i];
3292 if (e)
3293 {
3294 //printf("e = %s, e.type = %s\n", e.toChars(), e.type.toChars());
3295
3296 /* If type is a static array, and e is an initializer for that array,
3297 * then the field initializer should be an array literal of e.
3298 */
3299 auto tsa = type.isTypeSArray();
3300 if (tsa && e.type.castMod(0) != type.castMod(0))
3301 {
3302 const length = cast(size_t)tsa.dim.toInteger();
3303 auto z = new Expressions(length);
3304 foreach (ref q; *z)
3305 q = e.copy();
3306 e = new ArrayLiteralExp(loc, type, z);
3307 }
3308 else
3309 {
3310 e = e.copy();
3311 e.type = type;
3312 }
3313 if (useStaticInit && e.type.needsNested())
3314 if (auto se = e.isStructLiteralExp())
3315 {
3316 se.useStaticInit = true;
3317 }
3318 }
3319 }
3320 return e;
3321 }
3322
3323 /************************************
3324 * Get index of field.
3325 * Returns -1 if not found.
3326 */
3327 int getFieldIndex(Type type, uint offset)
3328 {
3329 /* Find which field offset is by looking at the field offsets
3330 */
6d799f0a 3331 if (elements.length)
5fee5ec3 3332 {
9c7d5e88
IB
3333 const sz = type.size();
3334 if (sz == SIZE_INVALID)
3335 return -1;
5fee5ec3
IB
3336 foreach (i, v; sd.fields)
3337 {
9c7d5e88 3338 if (offset == v.offset && sz == v.type.size())
5fee5ec3
IB
3339 {
3340 /* context fields might not be filled. */
3341 if (i >= sd.nonHiddenFields())
3342 return cast(int)i;
3343 if (auto e = (*elements)[i])
3344 {
3345 return cast(int)i;
3346 }
3347 break;
3348 }
3349 }
3350 }
3351 return -1;
3352 }
3353
3354 override Expression addDtorHook(Scope* sc)
3355 {
3356 /* If struct requires a destructor, rewrite as:
3357 * (S tmp = S()),tmp
3358 * so that the destructor can be hung on tmp.
3359 */
3360 if (sd.dtor && sc.func)
3361 {
3362 /* Make an identifier for the temporary of the form:
3363 * __sl%s%d, where %s is the struct name
3364 */
3365 char[10] buf = void;
3366 const prefix = "__sl";
3367 const ident = sd.ident.toString;
3368 const fullLen = prefix.length + ident.length;
3369 const len = fullLen < buf.length ? fullLen : buf.length;
3370 buf[0 .. prefix.length] = prefix;
3371 buf[prefix.length .. len] = ident[0 .. len - prefix.length];
3372
3373 auto tmp = copyToTemp(0, buf[0 .. len], this);
3374 Expression ae = new DeclarationExp(loc, tmp);
3375 Expression e = new CommaExp(loc, ae, new VarExp(loc, tmp));
3376 e = e.expressionSemantic(sc);
3377 return e;
3378 }
3379 return this;
3380 }
3381
3382 override Expression toLvalue(Scope* sc, Expression e)
3383 {
3384 if (sc.flags & SCOPE.Cfile)
3385 return this; // C struct literals are lvalues
3386 else
3387 return Expression.toLvalue(sc, e);
3388 }
3389
3390 override void accept(Visitor v)
3391 {
3392 v.visit(this);
3393 }
3394}
3395
3396/***********************************************************
3397 * C11 6.5.2.5
3398 * ( type-name ) { initializer-list }
3399 */
3400extern (C++) final class CompoundLiteralExp : Expression
3401{
3402 Initializer initializer; /// initializer-list
3403
3404 extern (D) this(const ref Loc loc, Type type_name, Initializer initializer)
3405 {
9c7d5e88 3406 super(loc, EXP.compoundLiteral, __traits(classInstanceSize, CompoundLiteralExp));
5fee5ec3
IB
3407 super.type = type_name;
3408 this.initializer = initializer;
3409 //printf("CompoundLiteralExp::CompoundLiteralExp(%s)\n", toChars());
3410 }
3411
3412 override void accept(Visitor v)
3413 {
3414 v.visit(this);
3415 }
3416}
3417
3418/***********************************************************
3419 * Mainly just a placeholder
3420 */
3421extern (C++) final class TypeExp : Expression
3422{
3423 extern (D) this(const ref Loc loc, Type type)
3424 {
9c7d5e88 3425 super(loc, EXP.type, __traits(classInstanceSize, TypeExp));
5fee5ec3
IB
3426 //printf("TypeExp::TypeExp(%s)\n", type.toChars());
3427 this.type = type;
3428 }
3429
3430 override TypeExp syntaxCopy()
3431 {
3432 return new TypeExp(loc, type.syntaxCopy());
3433 }
3434
3435 override bool checkType()
3436 {
3437 error("type `%s` is not an expression", toChars());
3438 return true;
3439 }
3440
3441 override bool checkValue()
3442 {
3443 error("type `%s` has no value", toChars());
3444 return true;
3445 }
3446
3447 override void accept(Visitor v)
3448 {
3449 v.visit(this);
3450 }
3451}
3452
3453/***********************************************************
3454 * Mainly just a placeholder of
3455 * Package, Module, Nspace, and TemplateInstance (including TemplateMixin)
3456 *
3457 * A template instance that requires IFTI:
3458 * foo!tiargs(fargs) // foo!tiargs
3459 * is left until CallExp::semantic() or resolveProperties()
3460 */
3461extern (C++) final class ScopeExp : Expression
3462{
3463 ScopeDsymbol sds;
3464
3465 extern (D) this(const ref Loc loc, ScopeDsymbol sds)
3466 {
9c7d5e88 3467 super(loc, EXP.scope_, __traits(classInstanceSize, ScopeExp));
5fee5ec3
IB
3468 //printf("ScopeExp::ScopeExp(sds = '%s')\n", sds.toChars());
3469 //static int count; if (++count == 38) *(char*)0=0;
3470 this.sds = sds;
3471 assert(!sds.isTemplateDeclaration()); // instead, you should use TemplateExp
3472 }
3473
3474 override ScopeExp syntaxCopy()
3475 {
3476 return new ScopeExp(loc, sds.syntaxCopy(null));
3477 }
3478
3479 override bool checkType()
3480 {
3481 if (sds.isPackage())
3482 {
3483 error("%s `%s` has no type", sds.kind(), sds.toChars());
3484 return true;
3485 }
3486 if (auto ti = sds.isTemplateInstance())
3487 {
3488 //assert(ti.needsTypeInference(sc));
3489 if (ti.tempdecl &&
3490 ti.semantictiargsdone &&
235d5a96 3491 ti.semanticRun == PASS.initial)
5fee5ec3
IB
3492 {
3493 error("partial %s `%s` has no type", sds.kind(), toChars());
3494 return true;
3495 }
3496 }
3497 return false;
3498 }
3499
3500 override bool checkValue()
3501 {
3502 error("%s `%s` has no value", sds.kind(), sds.toChars());
3503 return true;
3504 }
3505
3506 override void accept(Visitor v)
3507 {
3508 v.visit(this);
3509 }
3510}
3511
3512/***********************************************************
3513 * Mainly just a placeholder
3514 */
3515extern (C++) final class TemplateExp : Expression
3516{
3517 TemplateDeclaration td;
3518 FuncDeclaration fd;
3519
3520 extern (D) this(const ref Loc loc, TemplateDeclaration td, FuncDeclaration fd = null)
3521 {
9c7d5e88 3522 super(loc, EXP.template_, __traits(classInstanceSize, TemplateExp));
5fee5ec3
IB
3523 //printf("TemplateExp(): %s\n", td.toChars());
3524 this.td = td;
3525 this.fd = fd;
3526 }
3527
3528 override bool isLvalue()
3529 {
3530 return fd !is null;
3531 }
3532
3533 override Expression toLvalue(Scope* sc, Expression e)
3534 {
3535 if (!fd)
3536 return Expression.toLvalue(sc, e);
3537
3538 assert(sc);
3539 return symbolToExp(fd, loc, sc, true);
3540 }
3541
3542 override bool checkType()
3543 {
3544 error("%s `%s` has no type", td.kind(), toChars());
3545 return true;
3546 }
3547
3548 override bool checkValue()
3549 {
3550 error("%s `%s` has no value", td.kind(), toChars());
3551 return true;
3552 }
3553
3554 override void accept(Visitor v)
3555 {
3556 v.visit(this);
3557 }
3558}
3559
3560/***********************************************************
6384eff5 3561 * newtype(arguments)
5fee5ec3
IB
3562 */
3563extern (C++) final class NewExp : Expression
3564{
3565 Expression thisexp; // if !=null, 'this' for class being allocated
5fee5ec3
IB
3566 Type newtype;
3567 Expressions* arguments; // Array of Expression's
3568
3569 Expression argprefix; // expression to be evaluated just before arguments[]
3570 CtorDeclaration member; // constructor function
3571 bool onstack; // allocate on stack
3572 bool thrownew; // this NewExp is the expression of a ThrowStatement
3573
6384eff5 3574 extern (D) this(const ref Loc loc, Expression thisexp, Type newtype, Expressions* arguments)
5fee5ec3 3575 {
9c7d5e88 3576 super(loc, EXP.new_, __traits(classInstanceSize, NewExp));
5fee5ec3 3577 this.thisexp = thisexp;
5fee5ec3
IB
3578 this.newtype = newtype;
3579 this.arguments = arguments;
3580 }
3581
6384eff5 3582 static NewExp create(const ref Loc loc, Expression thisexp, Type newtype, Expressions* arguments)
5fee5ec3 3583 {
6384eff5 3584 return new NewExp(loc, thisexp, newtype, arguments);
5fee5ec3
IB
3585 }
3586
3587 override NewExp syntaxCopy()
3588 {
3589 return new NewExp(loc,
3590 thisexp ? thisexp.syntaxCopy() : null,
5fee5ec3
IB
3591 newtype.syntaxCopy(),
3592 arraySyntaxCopy(arguments));
3593 }
3594
3595 override void accept(Visitor v)
3596 {
3597 v.visit(this);
3598 }
3599}
3600
3601/***********************************************************
6384eff5 3602 * class baseclasses { } (arguments)
5fee5ec3
IB
3603 */
3604extern (C++) final class NewAnonClassExp : Expression
3605{
3606 Expression thisexp; // if !=null, 'this' for class being allocated
5fee5ec3
IB
3607 ClassDeclaration cd; // class being instantiated
3608 Expressions* arguments; // Array of Expression's to call class constructor
3609
6384eff5 3610 extern (D) this(const ref Loc loc, Expression thisexp, ClassDeclaration cd, Expressions* arguments)
5fee5ec3 3611 {
9c7d5e88 3612 super(loc, EXP.newAnonymousClass, __traits(classInstanceSize, NewAnonClassExp));
5fee5ec3 3613 this.thisexp = thisexp;
5fee5ec3
IB
3614 this.cd = cd;
3615 this.arguments = arguments;
3616 }
3617
3618 override NewAnonClassExp syntaxCopy()
3619 {
6384eff5 3620 return new NewAnonClassExp(loc, thisexp ? thisexp.syntaxCopy() : null, cd.syntaxCopy(null), arraySyntaxCopy(arguments));
5fee5ec3
IB
3621 }
3622
3623 override void accept(Visitor v)
3624 {
3625 v.visit(this);
3626 }
3627}
3628
3629/***********************************************************
3630 */
3631extern (C++) class SymbolExp : Expression
3632{
3633 Declaration var;
3634 Dsymbol originalScope; // original scope before inlining
3635 bool hasOverloads;
3636
9c7d5e88 3637 extern (D) this(const ref Loc loc, EXP op, int size, Declaration var, bool hasOverloads)
5fee5ec3
IB
3638 {
3639 super(loc, op, size);
3640 assert(var);
3641 this.var = var;
3642 this.hasOverloads = hasOverloads;
3643 }
3644
3645 override void accept(Visitor v)
3646 {
3647 v.visit(this);
3648 }
3649}
3650
3651/***********************************************************
3652 * Offset from symbol
3653 */
3654extern (C++) final class SymOffExp : SymbolExp
3655{
3656 dinteger_t offset;
3657
3658 extern (D) this(const ref Loc loc, Declaration var, dinteger_t offset, bool hasOverloads = true)
3659 {
3660 if (auto v = var.isVarDeclaration())
3661 {
3662 // FIXME: This error report will never be handled anyone.
3663 // It should be done before the SymOffExp construction.
3664 if (v.needThis())
3665 .error(loc, "need `this` for address of `%s`", v.toChars());
3666 hasOverloads = false;
3667 }
9c7d5e88 3668 super(loc, EXP.symbolOffset, __traits(classInstanceSize, SymOffExp), var, hasOverloads);
5fee5ec3
IB
3669 this.offset = offset;
3670 }
3671
9c7d5e88 3672 override Optional!bool toBool()
5fee5ec3 3673 {
9c7d5e88 3674 return typeof(return)(true);
5fee5ec3
IB
3675 }
3676
3677 override void accept(Visitor v)
3678 {
3679 v.visit(this);
3680 }
3681}
3682
3683/***********************************************************
3684 * Variable
3685 */
3686extern (C++) final class VarExp : SymbolExp
3687{
3688 bool delegateWasExtracted;
3689 extern (D) this(const ref Loc loc, Declaration var, bool hasOverloads = true)
3690 {
3691 if (var.isVarDeclaration())
3692 hasOverloads = false;
3693
9c7d5e88 3694 super(loc, EXP.variable, __traits(classInstanceSize, VarExp), var, hasOverloads);
5fee5ec3
IB
3695 //printf("VarExp(this = %p, '%s', loc = %s)\n", this, var.toChars(), loc.toChars());
3696 //if (strcmp(var.ident.toChars(), "func") == 0) assert(0);
3697 this.type = var.type;
3698 }
3699
0fb57034 3700 static VarExp create(const ref Loc loc, Declaration var, bool hasOverloads = true)
5fee5ec3
IB
3701 {
3702 return new VarExp(loc, var, hasOverloads);
3703 }
3704
3705 override bool equals(const RootObject o) const
3706 {
3707 if (this == o)
3708 return true;
3709 if (auto ne = o.isExpression().isVarExp())
3710 {
3711 if (type.toHeadMutable().equals(ne.type.toHeadMutable()) && var == ne.var)
3712 {
3713 return true;
3714 }
3715 }
3716 return false;
3717 }
3718
3719 override bool isLvalue()
3720 {
3721 if (var.storage_class & (STC.lazy_ | STC.rvalue | STC.manifest))
3722 return false;
3723 return true;
3724 }
3725
3726 override Expression toLvalue(Scope* sc, Expression e)
3727 {
3728 if (var.storage_class & STC.manifest)
3729 {
3730 error("manifest constant `%s` cannot be modified", var.toChars());
3731 return ErrorExp.get();
3732 }
3733 if (var.storage_class & STC.lazy_ && !delegateWasExtracted)
3734 {
3735 error("lazy variable `%s` cannot be modified", var.toChars());
3736 return ErrorExp.get();
3737 }
3738 if (var.ident == Id.ctfe)
3739 {
3740 error("cannot modify compiler-generated variable `__ctfe`");
3741 return ErrorExp.get();
3742 }
3743 if (var.ident == Id.dollar) // https://issues.dlang.org/show_bug.cgi?id=13574
3744 {
3745 error("cannot modify operator `$`");
3746 return ErrorExp.get();
3747 }
3748 return this;
3749 }
3750
3751 override Expression modifiableLvalue(Scope* sc, Expression e)
3752 {
3753 //printf("VarExp::modifiableLvalue('%s')\n", var.toChars());
3754 if (var.storage_class & STC.manifest)
3755 {
3756 error("cannot modify manifest constant `%s`", toChars());
3757 return ErrorExp.get();
3758 }
3759 // See if this expression is a modifiable lvalue (i.e. not const)
3760 return Expression.modifiableLvalue(sc, e);
3761 }
3762
3763 override void accept(Visitor v)
3764 {
3765 v.visit(this);
3766 }
3767}
3768
3769/***********************************************************
3770 * Overload Set
3771 */
3772extern (C++) final class OverExp : Expression
3773{
3774 OverloadSet vars;
3775
3776 extern (D) this(const ref Loc loc, OverloadSet s)
3777 {
9c7d5e88 3778 super(loc, EXP.overloadSet, __traits(classInstanceSize, OverExp));
5fee5ec3
IB
3779 //printf("OverExp(this = %p, '%s')\n", this, var.toChars());
3780 vars = s;
3781 type = Type.tvoid;
3782 }
3783
3784 override bool isLvalue()
3785 {
3786 return true;
3787 }
3788
3789 override Expression toLvalue(Scope* sc, Expression e)
3790 {
3791 return this;
3792 }
3793
3794 override void accept(Visitor v)
3795 {
3796 v.visit(this);
3797 }
3798}
3799
3800/***********************************************************
3801 * Function/Delegate literal
3802 */
3803
3804extern (C++) final class FuncExp : Expression
3805{
3806 FuncLiteralDeclaration fd;
3807 TemplateDeclaration td;
9c7d5e88 3808 TOK tok; // TOK.reserved, TOK.delegate_, TOK.function_
5fee5ec3
IB
3809
3810 extern (D) this(const ref Loc loc, Dsymbol s)
3811 {
9c7d5e88 3812 super(loc, EXP.function_, __traits(classInstanceSize, FuncExp));
5fee5ec3
IB
3813 this.td = s.isTemplateDeclaration();
3814 this.fd = s.isFuncLiteralDeclaration();
3815 if (td)
3816 {
3817 assert(td.literal);
6d799f0a 3818 assert(td.members && td.members.length == 1);
5fee5ec3
IB
3819 fd = (*td.members)[0].isFuncLiteralDeclaration();
3820 }
3821 tok = fd.tok; // save original kind of function/delegate/(infer)
3822 assert(fd.fbody);
3823 }
3824
3825 override bool equals(const RootObject o) const
3826 {
3827 if (this == o)
3828 return true;
3829 auto e = o.isExpression();
3830 if (!e)
3831 return false;
3832 if (auto fe = e.isFuncExp())
3833 {
3834 return fd == fe.fd;
3835 }
3836 return false;
3837 }
3838
3839 extern (D) void genIdent(Scope* sc)
3840 {
3841 if (fd.ident == Id.empty)
3842 {
3843 const(char)[] s;
3844 if (fd.fes)
3845 s = "__foreachbody";
3846 else if (fd.tok == TOK.reserved)
3847 s = "__lambda";
3848 else if (fd.tok == TOK.delegate_)
3849 s = "__dgliteral";
3850 else
3851 s = "__funcliteral";
3852
3853 DsymbolTable symtab;
3854 if (FuncDeclaration func = sc.parent.isFuncDeclaration())
3855 {
3856 if (func.localsymtab is null)
3857 {
3858 // Inside template constraint, symtab is not set yet.
3859 // Initialize it lazily.
3860 func.localsymtab = new DsymbolTable();
3861 }
3862 symtab = func.localsymtab;
3863 }
3864 else
3865 {
3866 ScopeDsymbol sds = sc.parent.isScopeDsymbol();
3867 if (!sds.symtab)
3868 {
3869 // Inside template constraint, symtab may not be set yet.
3870 // Initialize it lazily.
3871 assert(sds.isTemplateInstance());
3872 sds.symtab = new DsymbolTable();
3873 }
3874 symtab = sds.symtab;
3875 }
3876 assert(symtab);
3877 Identifier id = Identifier.generateId(s, symtab.length() + 1);
3878 fd.ident = id;
3879 if (td)
3880 td.ident = id;
3881 symtab.insert(td ? cast(Dsymbol)td : cast(Dsymbol)fd);
3882 }
3883 }
3884
3885 override FuncExp syntaxCopy()
3886 {
3887 if (td)
3888 return new FuncExp(loc, td.syntaxCopy(null));
235d5a96 3889 else if (fd.semanticRun == PASS.initial)
5fee5ec3
IB
3890 return new FuncExp(loc, fd.syntaxCopy(null));
3891 else // https://issues.dlang.org/show_bug.cgi?id=13481
3892 // Prevent multiple semantic analysis of lambda body.
3893 return new FuncExp(loc, fd);
3894 }
3895
3896 extern (D) MATCH matchType(Type to, Scope* sc, FuncExp* presult, int flag = 0)
3897 {
3898
3899 static MATCH cannotInfer(Expression e, Type to, int flag)
3900 {
3901 if (!flag)
3902 e.error("cannot infer parameter types from `%s`", to.toChars());
3903 return MATCH.nomatch;
3904 }
3905
3906 //printf("FuncExp::matchType('%s'), to=%s\n", type ? type.toChars() : "null", to.toChars());
3907 if (presult)
3908 *presult = null;
3909
3910 TypeFunction tof = null;
3911 if (to.ty == Tdelegate)
3912 {
3913 if (tok == TOK.function_)
3914 {
3915 if (!flag)
3916 error("cannot match function literal to delegate type `%s`", to.toChars());
3917 return MATCH.nomatch;
3918 }
3919 tof = cast(TypeFunction)to.nextOf();
3920 }
3921 else if (to.ty == Tpointer && (tof = to.nextOf().isTypeFunction()) !is null)
3922 {
3923 if (tok == TOK.delegate_)
3924 {
3925 if (!flag)
3926 error("cannot match delegate literal to function pointer type `%s`", to.toChars());
3927 return MATCH.nomatch;
3928 }
3929 }
3930
3931 if (td)
3932 {
3933 if (!tof)
3934 {
3935 return cannotInfer(this, to, flag);
3936 }
3937
3938 // Parameter types inference from 'tof'
3939 assert(td._scope);
3940 TypeFunction tf = fd.type.isTypeFunction();
3941 //printf("\ttof = %s\n", tof.toChars());
3942 //printf("\ttf = %s\n", tf.toChars());
3943 const dim = tf.parameterList.length;
3944
3945 if (tof.parameterList.length != dim || tof.parameterList.varargs != tf.parameterList.varargs)
3946 return cannotInfer(this, to, flag);
3947
3948 auto tiargs = new Objects();
6d799f0a 3949 tiargs.reserve(td.parameters.length);
5fee5ec3
IB
3950
3951 foreach (tp; *td.parameters)
3952 {
3953 size_t u = 0;
3954 foreach (i, p; tf.parameterList)
3955 {
3956 if (auto ti = p.type.isTypeIdentifier())
3957 if (ti && ti.ident == tp.ident)
3958 break;
3959
3960 ++u;
3961 }
3962 assert(u < dim);
3963 Parameter pto = tof.parameterList[u];
3964 Type t = pto.type;
3965 if (t.ty == Terror)
3966 return cannotInfer(this, to, flag);
3967 tiargs.push(t);
3968 }
3969
3970 // Set target of return type inference
3971 if (!tf.next && tof.next)
3972 fd.treq = to;
3973
3974 auto ti = new TemplateInstance(loc, td, tiargs);
3975 Expression ex = (new ScopeExp(loc, ti)).expressionSemantic(td._scope);
3976
3977 // Reset inference target for the later re-semantic
3978 fd.treq = null;
3979
9c7d5e88 3980 if (ex.op == EXP.error)
5fee5ec3
IB
3981 return MATCH.nomatch;
3982 if (auto ef = ex.isFuncExp())
3983 return ef.matchType(to, sc, presult, flag);
3984 else
3985 return cannotInfer(this, to, flag);
3986 }
3987
3988 if (!tof || !tof.next)
3989 return MATCH.nomatch;
3990
3991 assert(type && type != Type.tvoid);
3992 if (fd.type.ty == Terror)
3993 return MATCH.nomatch;
3994 auto tfx = fd.type.isTypeFunction();
3995 bool convertMatch = (type.ty != to.ty);
3996
3997 if (fd.inferRetType && tfx.next.implicitConvTo(tof.next) == MATCH.convert)
3998 {
3999 /* If return type is inferred and covariant return,
4000 * tweak return statements to required return type.
4001 *
4002 * interface I {}
4003 * class C : Object, I{}
4004 *
4005 * I delegate() dg = delegate() { return new class C(); }
4006 */
4007 convertMatch = true;
4008
4009 auto tfy = new TypeFunction(tfx.parameterList, tof.next,
4010 tfx.linkage, STC.undefined_);
4011 tfy.mod = tfx.mod;
0fb57034 4012 tfy.trust = tfx.trust;
5fee5ec3
IB
4013 tfy.isnothrow = tfx.isnothrow;
4014 tfy.isnogc = tfx.isnogc;
4015 tfy.purity = tfx.purity;
4016 tfy.isproperty = tfx.isproperty;
4017 tfy.isref = tfx.isref;
4018 tfy.isInOutParam = tfx.isInOutParam;
4019 tfy.isInOutQual = tfx.isInOutQual;
4020 tfy.deco = tfy.merge().deco;
4021
4022 tfx = tfy;
4023 }
4024 Type tx;
4025 if (tok == TOK.delegate_ ||
4026 tok == TOK.reserved && (type.ty == Tdelegate || type.ty == Tpointer && to.ty == Tdelegate))
4027 {
4028 // Allow conversion from implicit function pointer to delegate
4029 tx = new TypeDelegate(tfx);
4030 tx.deco = tx.merge().deco;
4031 }
4032 else
4033 {
fd43568c 4034 assert(tok == TOK.function_ || tok == TOK.reserved && type.ty == Tpointer || fd.errors);
5fee5ec3
IB
4035 tx = tfx.pointerTo();
4036 }
4037 //printf("\ttx = %s, to = %s\n", tx.toChars(), to.toChars());
4038
4039 MATCH m = tx.implicitConvTo(to);
4040 if (m > MATCH.nomatch)
4041 {
4042 // MATCH.exact: exact type match
4043 // MATCH.constant: covairiant type match (eg. attributes difference)
4044 // MATCH.convert: context conversion
4045 m = convertMatch ? MATCH.convert : tx.equals(to) ? MATCH.exact : MATCH.constant;
4046
4047 if (presult)
4048 {
4049 (*presult) = cast(FuncExp)copy();
4050 (*presult).type = to;
4051
4052 // https://issues.dlang.org/show_bug.cgi?id=12508
4053 // Tweak function body for covariant returns.
4054 (*presult).fd.modifyReturns(sc, tof.next);
4055 }
4056 }
4057 else if (!flag)
4058 {
4059 auto ts = toAutoQualChars(tx, to);
4060 error("cannot implicitly convert expression `%s` of type `%s` to `%s`",
4061 toChars(), ts[0], ts[1]);
4062 }
4063 return m;
4064 }
4065
4066 override const(char)* toChars() const
4067 {
4068 return fd.toChars();
4069 }
4070
4071 override bool checkType()
4072 {
4073 if (td)
4074 {
4075 error("template lambda has no type");
4076 return true;
4077 }
4078 return false;
4079 }
4080
4081 override bool checkValue()
4082 {
4083 if (td)
4084 {
4085 error("template lambda has no value");
4086 return true;
4087 }
4088 return false;
4089 }
4090
4091 override void accept(Visitor v)
4092 {
4093 v.visit(this);
4094 }
4095}
4096
4097/***********************************************************
4098 * Declaration of a symbol
4099 *
4100 * D grammar allows declarations only as statements. However in AST representation
4101 * it can be part of any expression. This is used, for example, during internal
4102 * syntax re-writes to inject hidden symbols.
4103 */
4104extern (C++) final class DeclarationExp : Expression
4105{
4106 Dsymbol declaration;
4107
4108 extern (D) this(const ref Loc loc, Dsymbol declaration)
4109 {
9c7d5e88 4110 super(loc, EXP.declaration, __traits(classInstanceSize, DeclarationExp));
5fee5ec3
IB
4111 this.declaration = declaration;
4112 }
4113
4114 override DeclarationExp syntaxCopy()
4115 {
4116 return new DeclarationExp(loc, declaration.syntaxCopy(null));
4117 }
4118
4119 override bool hasCode()
4120 {
4121 if (auto vd = declaration.isVarDeclaration())
4122 {
4123 return !(vd.storage_class & (STC.manifest | STC.static_));
4124 }
4125 return false;
4126 }
4127
4128 override void accept(Visitor v)
4129 {
4130 v.visit(this);
4131 }
4132}
4133
4134/***********************************************************
4135 * typeid(int)
4136 */
4137extern (C++) final class TypeidExp : Expression
4138{
4139 RootObject obj;
4140
4141 extern (D) this(const ref Loc loc, RootObject o)
4142 {
9c7d5e88 4143 super(loc, EXP.typeid_, __traits(classInstanceSize, TypeidExp));
5fee5ec3
IB
4144 this.obj = o;
4145 }
4146
4147 override TypeidExp syntaxCopy()
4148 {
4149 return new TypeidExp(loc, objectSyntaxCopy(obj));
4150 }
4151
4152 override void accept(Visitor v)
4153 {
4154 v.visit(this);
4155 }
4156}
4157
4158/***********************************************************
4159 * __traits(identifier, args...)
4160 */
4161extern (C++) final class TraitsExp : Expression
4162{
4163 Identifier ident;
4164 Objects* args;
4165
4166 extern (D) this(const ref Loc loc, Identifier ident, Objects* args)
4167 {
9c7d5e88 4168 super(loc, EXP.traits, __traits(classInstanceSize, TraitsExp));
5fee5ec3
IB
4169 this.ident = ident;
4170 this.args = args;
4171 }
4172
4173 override TraitsExp syntaxCopy()
4174 {
4175 return new TraitsExp(loc, ident, TemplateInstance.arraySyntaxCopy(args));
4176 }
4177
4178 override void accept(Visitor v)
4179 {
4180 v.visit(this);
4181 }
4182}
4183
4184/***********************************************************
8977f4be
IB
4185 * Generates a halt instruction
4186 *
4187 * `assert(0)` gets rewritten to this with `CHECKACTION.halt`
5fee5ec3
IB
4188 */
4189extern (C++) final class HaltExp : Expression
4190{
4191 extern (D) this(const ref Loc loc)
4192 {
9c7d5e88 4193 super(loc, EXP.halt, __traits(classInstanceSize, HaltExp));
5fee5ec3
IB
4194 }
4195
4196 override void accept(Visitor v)
4197 {
4198 v.visit(this);
4199 }
4200}
4201
4202/***********************************************************
4203 * is(targ id tok tspec)
4204 * is(targ id == tok2)
4205 */
4206extern (C++) final class IsExp : Expression
4207{
4208 Type targ;
4209 Identifier id; // can be null
4210 Type tspec; // can be null
4211 TemplateParameters* parameters;
4212 TOK tok; // ':' or '=='
4213 TOK tok2; // 'struct', 'union', etc.
4214
4215 extern (D) this(const ref Loc loc, Type targ, Identifier id, TOK tok, Type tspec, TOK tok2, TemplateParameters* parameters)
4216 {
9c7d5e88 4217 super(loc, EXP.is_, __traits(classInstanceSize, IsExp));
5fee5ec3
IB
4218 this.targ = targ;
4219 this.id = id;
4220 this.tok = tok;
4221 this.tspec = tspec;
4222 this.tok2 = tok2;
4223 this.parameters = parameters;
4224 }
4225
4226 override IsExp syntaxCopy()
4227 {
4228 // This section is identical to that in TemplateDeclaration::syntaxCopy()
4229 TemplateParameters* p = null;
4230 if (parameters)
4231 {
6d799f0a 4232 p = new TemplateParameters(parameters.length);
5fee5ec3
IB
4233 foreach (i, el; *parameters)
4234 (*p)[i] = el.syntaxCopy();
4235 }
4236 return new IsExp(loc, targ.syntaxCopy(), id, tok, tspec ? tspec.syntaxCopy() : null, tok2, p);
4237 }
4238
4239 override void accept(Visitor v)
4240 {
4241 v.visit(this);
4242 }
4243}
4244
4245/***********************************************************
8977f4be
IB
4246 * Base class for unary operators
4247 *
4248 * https://dlang.org/spec/expression.html#unary-expression
5fee5ec3
IB
4249 */
4250extern (C++) abstract class UnaExp : Expression
4251{
4252 Expression e1;
4253 Type att1; // Save alias this type to detect recursion
4254
9c7d5e88 4255 extern (D) this(const ref Loc loc, EXP op, int size, Expression e1)
5fee5ec3
IB
4256 {
4257 super(loc, op, size);
4258 this.e1 = e1;
4259 }
4260
4261 override UnaExp syntaxCopy()
4262 {
4263 UnaExp e = cast(UnaExp)copy();
4264 e.type = null;
4265 e.e1 = e.e1.syntaxCopy();
4266 return e;
4267 }
4268
4269 /********************************
4270 * The type for a unary expression is incompatible.
4271 * Print error message.
4272 * Returns:
4273 * ErrorExp
4274 */
4275 final Expression incompatibleTypes()
4276 {
4277 if (e1.type.toBasetype() == Type.terror)
4278 return e1;
4279
9c7d5e88 4280 if (e1.op == EXP.type)
5fee5ec3 4281 {
9c7d5e88 4282 error("incompatible type for `%s(%s)`: cannot use `%s` with types", EXPtoString(op).ptr, e1.toChars(), EXPtoString(op).ptr);
5fee5ec3
IB
4283 }
4284 else
4285 {
9c7d5e88 4286 error("incompatible type for `%s(%s)`: `%s`", EXPtoString(op).ptr, e1.toChars(), e1.type.toChars());
5fee5ec3
IB
4287 }
4288 return ErrorExp.get();
4289 }
4290
4291 /*********************
4292 * Mark the operand as will never be dereferenced,
4293 * which is useful info for @safe checks.
4294 * Do before semantic() on operands rewrites them.
4295 */
4296 final void setNoderefOperand()
4297 {
4298 if (auto edi = e1.isDotIdExp())
4299 edi.noderef = true;
4300
4301 }
4302
4303 override final Expression resolveLoc(const ref Loc loc, Scope* sc)
4304 {
4305 e1 = e1.resolveLoc(loc, sc);
4306 return this;
4307 }
4308
4309 override void accept(Visitor v)
4310 {
4311 v.visit(this);
4312 }
4313}
4314
4315alias fp_t = UnionExp function(const ref Loc loc, Type, Expression, Expression);
9c7d5e88 4316alias fp2_t = bool function(const ref Loc loc, EXP, Expression, Expression);
5fee5ec3
IB
4317
4318/***********************************************************
8977f4be 4319 * Base class for binary operators
5fee5ec3
IB
4320 */
4321extern (C++) abstract class BinExp : Expression
4322{
4323 Expression e1;
4324 Expression e2;
4325 Type att1; // Save alias this type to detect recursion
4326 Type att2; // Save alias this type to detect recursion
4327
9c7d5e88 4328 extern (D) this(const ref Loc loc, EXP op, int size, Expression e1, Expression e2)
5fee5ec3
IB
4329 {
4330 super(loc, op, size);
4331 this.e1 = e1;
4332 this.e2 = e2;
4333 }
4334
4335 override BinExp syntaxCopy()
4336 {
4337 BinExp e = cast(BinExp)copy();
4338 e.type = null;
4339 e.e1 = e.e1.syntaxCopy();
4340 e.e2 = e.e2.syntaxCopy();
4341 return e;
4342 }
4343
4344 /********************************
4345 * The types for a binary expression are incompatible.
4346 * Print error message.
4347 * Returns:
4348 * ErrorExp
4349 */
4350 final Expression incompatibleTypes()
4351 {
4352 if (e1.type.toBasetype() == Type.terror)
4353 return e1;
4354 if (e2.type.toBasetype() == Type.terror)
4355 return e2;
4356
4357 // CondExp uses 'a ? b : c' but we're comparing 'b : c'
9c7d5e88
IB
4358 const(char)* thisOp = (op == EXP.question) ? ":" : EXPtoString(op).ptr;
4359 if (e1.op == EXP.type || e2.op == EXP.type)
5fee5ec3
IB
4360 {
4361 error("incompatible types for `(%s) %s (%s)`: cannot use `%s` with types",
9c7d5e88 4362 e1.toChars(), thisOp, e2.toChars(), EXPtoString(op).ptr);
5fee5ec3
IB
4363 }
4364 else if (e1.type.equals(e2.type))
4365 {
4366 error("incompatible types for `(%s) %s (%s)`: both operands are of type `%s`",
9c7d5e88 4367 e1.toChars(), thisOp, e2.toChars(), e1.type.toChars());
5fee5ec3
IB
4368 }
4369 else
4370 {
4371 auto ts = toAutoQualChars(e1.type, e2.type);
4372 error("incompatible types for `(%s) %s (%s)`: `%s` and `%s`",
9c7d5e88 4373 e1.toChars(), thisOp, e2.toChars(), ts[0], ts[1]);
5fee5ec3
IB
4374 }
4375 return ErrorExp.get();
4376 }
4377
4378 extern (D) final Expression checkOpAssignTypes(Scope* sc)
4379 {
4380 // At that point t1 and t2 are the merged types. type is the original type of the lhs.
4381 Type t1 = e1.type;
4382 Type t2 = e2.type;
4383
4384 // T opAssign floating yields a floating. Prevent truncating conversions (float to int).
4385 // See issue 3841.
4386 // Should we also prevent double to float (type.isfloating() && type.size() < t2.size()) ?
9c7d5e88
IB
4387 if (op == EXP.addAssign || op == EXP.minAssign ||
4388 op == EXP.mulAssign || op == EXP.divAssign || op == EXP.modAssign ||
4389 op == EXP.powAssign)
5fee5ec3
IB
4390 {
4391 if ((type.isintegral() && t2.isfloating()))
4392 {
9c7d5e88 4393 warning("`%s %s %s` is performing truncating conversion", type.toChars(), EXPtoString(op).ptr, t2.toChars());
5fee5ec3
IB
4394 }
4395 }
4396
4397 // generate an error if this is a nonsensical *=,/=, or %=, eg real *= imaginary
9c7d5e88 4398 if (op == EXP.mulAssign || op == EXP.divAssign || op == EXP.modAssign)
5fee5ec3
IB
4399 {
4400 // Any multiplication by an imaginary or complex number yields a complex result.
4401 // r *= c, i*=c, r*=i, i*=i are all forbidden operations.
9c7d5e88 4402 const(char)* opstr = EXPtoString(op).ptr;
5fee5ec3
IB
4403 if (t1.isreal() && t2.iscomplex())
4404 {
4405 error("`%s %s %s` is undefined. Did you mean `%s %s %s.re`?", t1.toChars(), opstr, t2.toChars(), t1.toChars(), opstr, t2.toChars());
4406 return ErrorExp.get();
4407 }
4408 else if (t1.isimaginary() && t2.iscomplex())
4409 {
4410 error("`%s %s %s` is undefined. Did you mean `%s %s %s.im`?", t1.toChars(), opstr, t2.toChars(), t1.toChars(), opstr, t2.toChars());
4411 return ErrorExp.get();
4412 }
4413 else if ((t1.isreal() || t1.isimaginary()) && t2.isimaginary())
4414 {
4415 error("`%s %s %s` is an undefined operation", t1.toChars(), opstr, t2.toChars());
4416 return ErrorExp.get();
4417 }
4418 }
4419
4420 // generate an error if this is a nonsensical += or -=, eg real += imaginary
9c7d5e88 4421 if (op == EXP.addAssign || op == EXP.minAssign)
5fee5ec3
IB
4422 {
4423 // Addition or subtraction of a real and an imaginary is a complex result.
4424 // Thus, r+=i, r+=c, i+=r, i+=c are all forbidden operations.
4425 if ((t1.isreal() && (t2.isimaginary() || t2.iscomplex())) || (t1.isimaginary() && (t2.isreal() || t2.iscomplex())))
4426 {
9c7d5e88 4427 error("`%s %s %s` is undefined (result is complex)", t1.toChars(), EXPtoString(op).ptr, t2.toChars());
5fee5ec3
IB
4428 return ErrorExp.get();
4429 }
4430 if (type.isreal() || type.isimaginary())
4431 {
4432 assert(global.errors || t2.isfloating());
4433 e2 = e2.castTo(sc, t1);
4434 }
4435 }
9c7d5e88 4436 if (op == EXP.mulAssign)
5fee5ec3
IB
4437 {
4438 if (t2.isfloating())
4439 {
4440 if (t1.isreal())
4441 {
4442 if (t2.isimaginary() || t2.iscomplex())
4443 {
4444 e2 = e2.castTo(sc, t1);
4445 }
4446 }
4447 else if (t1.isimaginary())
4448 {
4449 if (t2.isimaginary() || t2.iscomplex())
4450 {
4451 switch (t1.ty)
4452 {
4453 case Timaginary32:
4454 t2 = Type.tfloat32;
4455 break;
4456
4457 case Timaginary64:
4458 t2 = Type.tfloat64;
4459 break;
4460
4461 case Timaginary80:
4462 t2 = Type.tfloat80;
4463 break;
4464
4465 default:
4466 assert(0);
4467 }
4468 e2 = e2.castTo(sc, t2);
4469 }
4470 }
4471 }
4472 }
9c7d5e88 4473 else if (op == EXP.divAssign)
5fee5ec3
IB
4474 {
4475 if (t2.isimaginary())
4476 {
4477 if (t1.isreal())
4478 {
4479 // x/iv = i(-x/v)
4480 // Therefore, the result is 0
4481 e2 = new CommaExp(loc, e2, new RealExp(loc, CTFloat.zero, t1));
4482 e2.type = t1;
4483 Expression e = new AssignExp(loc, e1, e2);
4484 e.type = t1;
4485 return e;
4486 }
4487 else if (t1.isimaginary())
4488 {
4489 Type t3;
4490 switch (t1.ty)
4491 {
4492 case Timaginary32:
4493 t3 = Type.tfloat32;
4494 break;
4495
4496 case Timaginary64:
4497 t3 = Type.tfloat64;
4498 break;
4499
4500 case Timaginary80:
4501 t3 = Type.tfloat80;
4502 break;
4503
4504 default:
4505 assert(0);
4506 }
4507 e2 = e2.castTo(sc, t3);
4508 Expression e = new AssignExp(loc, e1, e2);
4509 e.type = t1;
4510 return e;
4511 }
4512 }
4513 }
9c7d5e88 4514 else if (op == EXP.modAssign)
5fee5ec3
IB
4515 {
4516 if (t2.iscomplex())
4517 {
4518 error("cannot perform modulo complex arithmetic");
4519 return ErrorExp.get();
4520 }
4521 }
4522 return this;
4523 }
4524
4525 extern (D) final bool checkIntegralBin()
4526 {
4527 bool r1 = e1.checkIntegral();
4528 bool r2 = e2.checkIntegral();
4529 return (r1 || r2);
4530 }
4531
4532 extern (D) final bool checkArithmeticBin()
4533 {
4534 bool r1 = e1.checkArithmetic();
4535 bool r2 = e2.checkArithmetic();
4536 return (r1 || r2);
4537 }
4538
4539 extern (D) final bool checkSharedAccessBin(Scope* sc)
4540 {
4541 const r1 = e1.checkSharedAccess(sc);
4542 const r2 = e2.checkSharedAccess(sc);
4543 return (r1 || r2);
4544 }
4545
4546 /*********************
4547 * Mark the operands as will never be dereferenced,
4548 * which is useful info for @safe checks.
4549 * Do before semantic() on operands rewrites them.
4550 */
4551 final void setNoderefOperands()
4552 {
4553 if (auto edi = e1.isDotIdExp())
4554 edi.noderef = true;
4555 if (auto edi = e2.isDotIdExp())
4556 edi.noderef = true;
4557
4558 }
4559
4560 final Expression reorderSettingAAElem(Scope* sc)
4561 {
4562 BinExp be = this;
4563
4564 auto ie = be.e1.isIndexExp();
4565 if (!ie)
4566 return be;
4567 if (ie.e1.type.toBasetype().ty != Taarray)
4568 return be;
4569
4570 /* Fix evaluation order of setting AA element
4571 * https://issues.dlang.org/show_bug.cgi?id=3825
4572 * Rewrite:
4573 * aa[k1][k2][k3] op= val;
4574 * as:
4575 * auto ref __aatmp = aa;
4576 * auto ref __aakey3 = k1, __aakey2 = k2, __aakey1 = k3;
4577 * auto ref __aaval = val;
4578 * __aatmp[__aakey3][__aakey2][__aakey1] op= __aaval; // assignment
4579 */
4580
4581 Expression e0;
4582 while (1)
4583 {
4584 Expression de;
4585 ie.e2 = extractSideEffect(sc, "__aakey", de, ie.e2);
4586 e0 = Expression.combine(de, e0);
4587
4588 auto ie1 = ie.e1.isIndexExp();
4589 if (!ie1 ||
4590 ie1.e1.type.toBasetype().ty != Taarray)
4591 {
4592 break;
4593 }
4594 ie = ie1;
4595 }
4596 assert(ie.e1.type.toBasetype().ty == Taarray);
4597
4598 Expression de;
4599 ie.e1 = extractSideEffect(sc, "__aatmp", de, ie.e1);
4600 e0 = Expression.combine(de, e0);
4601
4602 be.e2 = extractSideEffect(sc, "__aaval", e0, be.e2, true);
4603
4604 //printf("-e0 = %s, be = %s\n", e0.toChars(), be.toChars());
4605 return Expression.combine(e0, be);
4606 }
4607
4608 override void accept(Visitor v)
4609 {
4610 v.visit(this);
4611 }
4612}
4613
4614/***********************************************************
8977f4be 4615 * Binary operator assignment, `+=` `-=` `*=` etc.
5fee5ec3
IB
4616 */
4617extern (C++) class BinAssignExp : BinExp
4618{
9c7d5e88 4619 extern (D) this(const ref Loc loc, EXP op, int size, Expression e1, Expression e2)
5fee5ec3
IB
4620 {
4621 super(loc, op, size, e1, e2);
4622 }
4623
4624 override final bool isLvalue()
4625 {
4626 return true;
4627 }
4628
4629 override final Expression toLvalue(Scope* sc, Expression ex)
4630 {
4631 // Lvalue-ness will be handled in glue layer.
4632 return this;
4633 }
4634
4635 override final Expression modifiableLvalue(Scope* sc, Expression e)
4636 {
4637 // should check e1.checkModifiable() ?
4638 return toLvalue(sc, this);
4639 }
4640
5fee5ec3
IB
4641 override void accept(Visitor v)
4642 {
4643 v.visit(this);
4644 }
4645}
4646
4647/***********************************************************
8977f4be
IB
4648 * A string mixin, `mixin("x")`
4649 *
5fee5ec3
IB
4650 * https://dlang.org/spec/expression.html#mixin_expressions
4651 */
4652extern (C++) final class MixinExp : Expression
4653{
4654 Expressions* exps;
4655
4656 extern (D) this(const ref Loc loc, Expressions* exps)
4657 {
9c7d5e88 4658 super(loc, EXP.mixin_, __traits(classInstanceSize, MixinExp));
5fee5ec3
IB
4659 this.exps = exps;
4660 }
4661
4662 override MixinExp syntaxCopy()
4663 {
4664 return new MixinExp(loc, arraySyntaxCopy(exps));
4665 }
4666
4667 override bool equals(const RootObject o) const
4668 {
4669 if (this == o)
4670 return true;
4671 auto e = o.isExpression();
4672 if (!e)
4673 return false;
4674 if (auto ce = e.isMixinExp())
4675 {
6d799f0a 4676 if (exps.length != ce.exps.length)
5fee5ec3
IB
4677 return false;
4678 foreach (i, e1; *exps)
4679 {
4680 auto e2 = (*ce.exps)[i];
4681 if (e1 != e2 && (!e1 || !e2 || !e1.equals(e2)))
4682 return false;
4683 }
4684 return true;
4685 }
4686 return false;
4687 }
4688
4689 override void accept(Visitor v)
4690 {
4691 v.visit(this);
4692 }
4693}
4694
4695/***********************************************************
8977f4be
IB
4696 * An import expression, `import("file.txt")`
4697 *
4698 * Not to be confused with module imports, `import std.stdio`, which is an `ImportStatement`
4699 *
4700 * https://dlang.org/spec/expression.html#import_expressions
5fee5ec3
IB
4701 */
4702extern (C++) final class ImportExp : UnaExp
4703{
4704 extern (D) this(const ref Loc loc, Expression e)
4705 {
9c7d5e88 4706 super(loc, EXP.import_, __traits(classInstanceSize, ImportExp), e);
5fee5ec3
IB
4707 }
4708
4709 override void accept(Visitor v)
4710 {
4711 v.visit(this);
4712 }
4713}
4714
4715/***********************************************************
8977f4be
IB
4716 * An assert expression, `assert(x == y)`
4717 *
5fee5ec3
IB
4718 * https://dlang.org/spec/expression.html#assert_expressions
4719 */
4720extern (C++) final class AssertExp : UnaExp
4721{
4722 Expression msg;
4723
4724 extern (D) this(const ref Loc loc, Expression e, Expression msg = null)
4725 {
9c7d5e88 4726 super(loc, EXP.assert_, __traits(classInstanceSize, AssertExp), e);
5fee5ec3
IB
4727 this.msg = msg;
4728 }
4729
4730 override AssertExp syntaxCopy()
4731 {
4732 return new AssertExp(loc, e1.syntaxCopy(), msg ? msg.syntaxCopy() : null);
4733 }
4734
4735 override void accept(Visitor v)
4736 {
4737 v.visit(this);
4738 }
4739}
4740
d7569187
IB
4741/***********************************************************
4742 * `throw <e1>` as proposed by DIP 1034.
4743 *
4744 * Replacement for the deprecated `ThrowStatement` that can be nested
4745 * in other expression.
4746 */
4747extern (C++) final class ThrowExp : UnaExp
4748{
4749 extern (D) this(const ref Loc loc, Expression e)
4750 {
4751 super(loc, EXP.throw_, __traits(classInstanceSize, ThrowExp), e);
4752 this.type = Type.tnoreturn;
4753 }
4754
4755 override ThrowExp syntaxCopy()
4756 {
4757 return new ThrowExp(loc, e1.syntaxCopy());
4758 }
4759
4760 override void accept(Visitor v)
4761 {
4762 v.visit(this);
4763 }
4764}
4765
5fee5ec3
IB
4766/***********************************************************
4767 */
4768extern (C++) final class DotIdExp : UnaExp
4769{
4770 Identifier ident;
4771 bool noderef; // true if the result of the expression will never be dereferenced
4772 bool wantsym; // do not replace Symbol with its initializer during semantic()
0fb57034 4773 bool arrow; // ImportC: if -> instead of .
5fee5ec3
IB
4774
4775 extern (D) this(const ref Loc loc, Expression e, Identifier ident)
4776 {
9c7d5e88 4777 super(loc, EXP.dotIdentifier, __traits(classInstanceSize, DotIdExp), e);
5fee5ec3
IB
4778 this.ident = ident;
4779 }
4780
0fb57034 4781 static DotIdExp create(const ref Loc loc, Expression e, Identifier ident)
5fee5ec3
IB
4782 {
4783 return new DotIdExp(loc, e, ident);
4784 }
4785
4786 override void accept(Visitor v)
4787 {
4788 v.visit(this);
4789 }
4790}
4791
4792/***********************************************************
4793 * Mainly just a placeholder
4794 */
4795extern (C++) final class DotTemplateExp : UnaExp
4796{
4797 TemplateDeclaration td;
4798
4799 extern (D) this(const ref Loc loc, Expression e, TemplateDeclaration td)
4800 {
9c7d5e88 4801 super(loc, EXP.dotTemplateDeclaration, __traits(classInstanceSize, DotTemplateExp), e);
5fee5ec3
IB
4802 this.td = td;
4803 }
4804
4805 override bool checkType()
4806 {
4807 error("%s `%s` has no type", td.kind(), toChars());
4808 return true;
4809 }
4810
4811 override bool checkValue()
4812 {
4813 error("%s `%s` has no value", td.kind(), toChars());
4814 return true;
4815 }
4816
4817 override void accept(Visitor v)
4818 {
4819 v.visit(this);
4820 }
4821}
4822
4823/***********************************************************
4824 */
4825extern (C++) final class DotVarExp : UnaExp
4826{
4827 Declaration var;
4828 bool hasOverloads;
4829
4830 extern (D) this(const ref Loc loc, Expression e, Declaration var, bool hasOverloads = true)
4831 {
4832 if (var.isVarDeclaration())
4833 hasOverloads = false;
4834
9c7d5e88 4835 super(loc, EXP.dotVariable, __traits(classInstanceSize, DotVarExp), e);
5fee5ec3
IB
4836 //printf("DotVarExp()\n");
4837 this.var = var;
4838 this.hasOverloads = hasOverloads;
4839 }
4840
4841 override bool isLvalue()
4842 {
9c7d5e88 4843 if (e1.op != EXP.structLiteral)
5fee5ec3
IB
4844 return true;
4845 auto vd = var.isVarDeclaration();
4846 return !(vd && vd.isField());
4847 }
4848
4849 override Expression toLvalue(Scope* sc, Expression e)
4850 {
4851 //printf("DotVarExp::toLvalue(%s)\n", toChars());
4852 if (sc && sc.flags & SCOPE.Cfile)
4853 {
4854 /* C11 6.5.2.3-3: A postfix expression followed by the '.' or '->' operator
4855 * is an lvalue if the first expression is an lvalue.
4856 */
4857 if (!e1.isLvalue())
4858 return Expression.toLvalue(sc, e);
4859 }
4860 if (!isLvalue())
4861 return Expression.toLvalue(sc, e);
9c7d5e88 4862 if (e1.op == EXP.this_ && sc.ctorflow.fieldinit.length && !(sc.ctorflow.callSuper & CSX.any_ctor))
5fee5ec3
IB
4863 {
4864 if (VarDeclaration vd = var.isVarDeclaration())
4865 {
4866 auto ad = vd.isMember2();
6d799f0a 4867 if (ad && ad.fields.length == sc.ctorflow.fieldinit.length)
5fee5ec3
IB
4868 {
4869 foreach (i, f; ad.fields)
4870 {
4871 if (f == vd)
4872 {
4873 if (!(sc.ctorflow.fieldinit[i].csx & CSX.this_ctor))
4874 {
4875 /* If the address of vd is taken, assume it is thereby initialized
4876 * https://issues.dlang.org/show_bug.cgi?id=15869
4877 */
4878 modifyFieldVar(loc, sc, vd, e1);
4879 }
4880 break;
4881 }
4882 }
4883 }
4884 }
4885 }
4886 return this;
4887 }
4888
4889 override Expression modifiableLvalue(Scope* sc, Expression e)
4890 {
4891 version (none)
4892 {
4893 printf("DotVarExp::modifiableLvalue(%s)\n", toChars());
4894 printf("e1.type = %s\n", e1.type.toChars());
4895 printf("var.type = %s\n", var.type.toChars());
4896 }
4897
4898 return Expression.modifiableLvalue(sc, e);
4899 }
4900
4901 override void accept(Visitor v)
4902 {
4903 v.visit(this);
4904 }
4905}
4906
4907/***********************************************************
4908 * foo.bar!(args)
4909 */
4910extern (C++) final class DotTemplateInstanceExp : UnaExp
4911{
4912 TemplateInstance ti;
4913
4914 extern (D) this(const ref Loc loc, Expression e, Identifier name, Objects* tiargs)
4915 {
9c7d5e88 4916 super(loc, EXP.dotTemplateInstance, __traits(classInstanceSize, DotTemplateInstanceExp), e);
5fee5ec3
IB
4917 //printf("DotTemplateInstanceExp()\n");
4918 this.ti = new TemplateInstance(loc, name, tiargs);
4919 }
4920
4921 extern (D) this(const ref Loc loc, Expression e, TemplateInstance ti)
4922 {
9c7d5e88 4923 super(loc, EXP.dotTemplateInstance, __traits(classInstanceSize, DotTemplateInstanceExp), e);
5fee5ec3
IB
4924 this.ti = ti;
4925 }
4926
4927 override DotTemplateInstanceExp syntaxCopy()
4928 {
4929 return new DotTemplateInstanceExp(loc, e1.syntaxCopy(), ti.name, TemplateInstance.arraySyntaxCopy(ti.tiargs));
4930 }
4931
4932 bool findTempDecl(Scope* sc)
4933 {
4934 static if (LOGSEMANTIC)
4935 {
4936 printf("DotTemplateInstanceExp::findTempDecl('%s')\n", toChars());
4937 }
4938 if (ti.tempdecl)
4939 return true;
4940
4941 Expression e = new DotIdExp(loc, e1, ti.name);
4942 e = e.expressionSemantic(sc);
9c7d5e88 4943 if (e.op == EXP.dot)
5fee5ec3
IB
4944 e = (cast(DotExp)e).e2;
4945
4946 Dsymbol s = null;
4947 switch (e.op)
4948 {
9c7d5e88 4949 case EXP.overloadSet:
5fee5ec3
IB
4950 s = (cast(OverExp)e).vars;
4951 break;
4952
9c7d5e88 4953 case EXP.dotTemplateDeclaration:
5fee5ec3
IB
4954 s = (cast(DotTemplateExp)e).td;
4955 break;
4956
9c7d5e88 4957 case EXP.scope_:
5fee5ec3
IB
4958 s = (cast(ScopeExp)e).sds;
4959 break;
4960
9c7d5e88 4961 case EXP.dotVariable:
5fee5ec3
IB
4962 s = (cast(DotVarExp)e).var;
4963 break;
4964
9c7d5e88 4965 case EXP.variable:
5fee5ec3
IB
4966 s = (cast(VarExp)e).var;
4967 break;
4968
4969 default:
4970 return false;
4971 }
4972 return ti.updateTempDecl(sc, s);
4973 }
4974
0fb57034
IB
4975 override bool checkType()
4976 {
4977 // Same logic as ScopeExp.checkType()
4978 if (ti.tempdecl &&
4979 ti.semantictiargsdone &&
235d5a96 4980 ti.semanticRun == PASS.initial)
0fb57034
IB
4981 {
4982 error("partial %s `%s` has no type", ti.kind(), toChars());
4983 return true;
4984 }
4985 return false;
4986 }
4987
4988 override bool checkValue()
4989 {
4990 if (ti.tempdecl &&
4991 ti.semantictiargsdone &&
235d5a96 4992 ti.semanticRun == PASS.initial)
0fb57034
IB
4993
4994 error("partial %s `%s` has no value", ti.kind(), toChars());
4995 else
4996 error("%s `%s` has no value", ti.kind(), ti.toChars());
4997 return true;
4998 }
4999
5fee5ec3
IB
5000 override void accept(Visitor v)
5001 {
5002 v.visit(this);
5003 }
5004}
5005
5006/***********************************************************
5007 */
5008extern (C++) final class DelegateExp : UnaExp
5009{
5010 FuncDeclaration func;
5011 bool hasOverloads;
5012 VarDeclaration vthis2; // container for multi-context
5013
5014 extern (D) this(const ref Loc loc, Expression e, FuncDeclaration f, bool hasOverloads = true, VarDeclaration vthis2 = null)
5015 {
9c7d5e88 5016 super(loc, EXP.delegate_, __traits(classInstanceSize, DelegateExp), e);
5fee5ec3
IB
5017 this.func = f;
5018 this.hasOverloads = hasOverloads;
5019 this.vthis2 = vthis2;
5020 }
5021
5022 override void accept(Visitor v)
5023 {
5024 v.visit(this);
5025 }
5026}
5027
5028/***********************************************************
5029 */
5030extern (C++) final class DotTypeExp : UnaExp
5031{
5032 Dsymbol sym; // symbol that represents a type
5033
5034 extern (D) this(const ref Loc loc, Expression e, Dsymbol s)
5035 {
9c7d5e88 5036 super(loc, EXP.dotType, __traits(classInstanceSize, DotTypeExp), e);
5fee5ec3
IB
5037 this.sym = s;
5038 }
5039
5040 override void accept(Visitor v)
5041 {
5042 v.visit(this);
5043 }
5044}
5045
5046/***********************************************************
5047 */
5048extern (C++) final class CallExp : UnaExp
5049{
5050 Expressions* arguments; // function arguments
5051 FuncDeclaration f; // symbol to call
5052 bool directcall; // true if a virtual call is devirtualized
5053 bool inDebugStatement; /// true if this was in a debug statement
5054 bool ignoreAttributes; /// don't enforce attributes (e.g. call @gc function in @nogc code)
5055 VarDeclaration vthis2; // container for multi-context
5056
5057 extern (D) this(const ref Loc loc, Expression e, Expressions* exps)
5058 {
9c7d5e88 5059 super(loc, EXP.call, __traits(classInstanceSize, CallExp), e);
5fee5ec3
IB
5060 this.arguments = exps;
5061 }
5062
5063 extern (D) this(const ref Loc loc, Expression e)
5064 {
9c7d5e88 5065 super(loc, EXP.call, __traits(classInstanceSize, CallExp), e);
5fee5ec3
IB
5066 }
5067
5068 extern (D) this(const ref Loc loc, Expression e, Expression earg1)
5069 {
9c7d5e88 5070 super(loc, EXP.call, __traits(classInstanceSize, CallExp), e);
5fee5ec3
IB
5071 this.arguments = new Expressions();
5072 if (earg1)
5073 this.arguments.push(earg1);
5074 }
5075
5076 extern (D) this(const ref Loc loc, Expression e, Expression earg1, Expression earg2)
5077 {
9c7d5e88 5078 super(loc, EXP.call, __traits(classInstanceSize, CallExp), e);
5fee5ec3
IB
5079 auto arguments = new Expressions(2);
5080 (*arguments)[0] = earg1;
5081 (*arguments)[1] = earg2;
5082 this.arguments = arguments;
5083 }
5084
5085 /***********************************************************
5086 * Instatiates a new function call expression
5087 * Params:
5088 * loc = location
5089 * fd = the declaration of the function to call
5090 * earg1 = the function argument
5091 */
5092 extern(D) this(const ref Loc loc, FuncDeclaration fd, Expression earg1)
5093 {
5094 this(loc, new VarExp(loc, fd, false), earg1);
5095 this.f = fd;
5096 }
5097
0fb57034 5098 static CallExp create(const ref Loc loc, Expression e, Expressions* exps)
5fee5ec3
IB
5099 {
5100 return new CallExp(loc, e, exps);
5101 }
5102
0fb57034 5103 static CallExp create(const ref Loc loc, Expression e)
5fee5ec3
IB
5104 {
5105 return new CallExp(loc, e);
5106 }
5107
0fb57034 5108 static CallExp create(const ref Loc loc, Expression e, Expression earg1)
5fee5ec3
IB
5109 {
5110 return new CallExp(loc, e, earg1);
5111 }
5112
5113 /***********************************************************
5114 * Creates a new function call expression
5115 * Params:
5116 * loc = location
5117 * fd = the declaration of the function to call
5118 * earg1 = the function argument
5119 */
0fb57034 5120 static CallExp create(const ref Loc loc, FuncDeclaration fd, Expression earg1)
5fee5ec3
IB
5121 {
5122 return new CallExp(loc, fd, earg1);
5123 }
5124
5125 override CallExp syntaxCopy()
5126 {
5127 return new CallExp(loc, e1.syntaxCopy(), arraySyntaxCopy(arguments));
5128 }
5129
5130 override bool isLvalue()
5131 {
5132 Type tb = e1.type.toBasetype();
5133 if (tb.ty == Tdelegate || tb.ty == Tpointer)
5134 tb = tb.nextOf();
5135 auto tf = tb.isTypeFunction();
5136 if (tf && tf.isref)
5137 {
5138 if (auto dve = e1.isDotVarExp())
5139 if (dve.var.isCtorDeclaration())
5140 return false;
5141 return true; // function returns a reference
5142 }
5143 return false;
5144 }
5145
5146 override Expression toLvalue(Scope* sc, Expression e)
5147 {
5148 if (isLvalue())
5149 return this;
5150 return Expression.toLvalue(sc, e);
5151 }
5152
5153 override Expression addDtorHook(Scope* sc)
5154 {
5155 /* Only need to add dtor hook if it's a type that needs destruction.
5156 * Use same logic as VarDeclaration::callScopeDtor()
5157 */
5158
5159 if (auto tf = e1.type.isTypeFunction())
5160 {
5161 if (tf.isref)
5162 return this;
5163 }
5164
5165 Type tv = type.baseElemOf();
5166 if (auto ts = tv.isTypeStruct())
5167 {
5168 StructDeclaration sd = ts.sym;
5169 if (sd.dtor)
5170 {
5171 /* Type needs destruction, so declare a tmp
5172 * which the back end will recognize and call dtor on
5173 */
b7a586be 5174 auto tmp = copyToTemp(0, Id.__tmpfordtor.toString(), this);
5fee5ec3
IB
5175 auto de = new DeclarationExp(loc, tmp);
5176 auto ve = new VarExp(loc, tmp);
5177 Expression e = new CommaExp(loc, de, ve);
5178 e = e.expressionSemantic(sc);
5179 return e;
5180 }
5181 }
5182 return this;
5183 }
5184
5185 override void accept(Visitor v)
5186 {
5187 v.visit(this);
5188 }
5189}
5190
5191FuncDeclaration isFuncAddress(Expression e, bool* hasOverloads = null)
5192{
5193 if (auto ae = e.isAddrExp())
5194 {
5195 auto ae1 = ae.e1;
5196 if (auto ve = ae1.isVarExp())
5197 {
5198 if (hasOverloads)
5199 *hasOverloads = ve.hasOverloads;
5200 return ve.var.isFuncDeclaration();
5201 }
5202 if (auto dve = ae1.isDotVarExp())
5203 {
5204 if (hasOverloads)
5205 *hasOverloads = dve.hasOverloads;
5206 return dve.var.isFuncDeclaration();
5207 }
5208 }
5209 else
5210 {
5211 if (auto soe = e.isSymOffExp())
5212 {
5213 if (hasOverloads)
5214 *hasOverloads = soe.hasOverloads;
5215 return soe.var.isFuncDeclaration();
5216 }
5217 if (auto dge = e.isDelegateExp())
5218 {
5219 if (hasOverloads)
5220 *hasOverloads = dge.hasOverloads;
5221 return dge.func.isFuncDeclaration();
5222 }
5223 }
5224 return null;
5225}
5226
5227/***********************************************************
8977f4be 5228 * The 'address of' operator, `&p`
5fee5ec3
IB
5229 */
5230extern (C++) final class AddrExp : UnaExp
5231{
5232 extern (D) this(const ref Loc loc, Expression e)
5233 {
9c7d5e88 5234 super(loc, EXP.address, __traits(classInstanceSize, AddrExp), e);
5fee5ec3
IB
5235 }
5236
5237 extern (D) this(const ref Loc loc, Expression e, Type t)
5238 {
5239 this(loc, e);
5240 type = t;
5241 }
5242
5243 override void accept(Visitor v)
5244 {
5245 v.visit(this);
5246 }
5247}
5248
5249/***********************************************************
8977f4be 5250 * The pointer dereference operator, `*p`
5fee5ec3
IB
5251 */
5252extern (C++) final class PtrExp : UnaExp
5253{
5254 extern (D) this(const ref Loc loc, Expression e)
5255 {
9c7d5e88 5256 super(loc, EXP.star, __traits(classInstanceSize, PtrExp), e);
5fee5ec3
IB
5257 //if (e.type)
5258 // type = ((TypePointer *)e.type).next;
5259 }
5260
5261 extern (D) this(const ref Loc loc, Expression e, Type t)
5262 {
9c7d5e88 5263 super(loc, EXP.star, __traits(classInstanceSize, PtrExp), e);
5fee5ec3
IB
5264 type = t;
5265 }
5266
5267 override bool isLvalue()
5268 {
5269 return true;
5270 }
5271
5272 override Expression toLvalue(Scope* sc, Expression e)
5273 {
5274 return this;
5275 }
5276
5277 override Expression modifiableLvalue(Scope* sc, Expression e)
5278 {
5279 //printf("PtrExp::modifiableLvalue() %s, type %s\n", toChars(), type.toChars());
0fb57034
IB
5280 Declaration var;
5281 if (auto se = e1.isSymOffExp())
5282 var = se.var;
5283 else if (auto ve = e1.isVarExp())
5284 var = ve.var;
5285 if (var && var.type.isFunction_Delegate_PtrToFunction())
5286 {
5287 if (var.type.isTypeFunction())
5288 error("function `%s` is not an lvalue and cannot be modified", var.toChars());
5289 else
5290 error("function pointed to by `%s` is not an lvalue and cannot be modified", var.toChars());
5291 return ErrorExp.get();
5292 }
5fee5ec3
IB
5293 return Expression.modifiableLvalue(sc, e);
5294 }
5295
5296 override void accept(Visitor v)
5297 {
5298 v.visit(this);
5299 }
5300}
5301
5302/***********************************************************
8977f4be 5303 * The negation operator, `-x`
5fee5ec3
IB
5304 */
5305extern (C++) final class NegExp : UnaExp
5306{
5307 extern (D) this(const ref Loc loc, Expression e)
5308 {
9c7d5e88 5309 super(loc, EXP.negate, __traits(classInstanceSize, NegExp), e);
5fee5ec3
IB
5310 }
5311
5312 override void accept(Visitor v)
5313 {
5314 v.visit(this);
5315 }
5316}
5317
5318/***********************************************************
8977f4be 5319 * The unary add operator, `+x`
5fee5ec3
IB
5320 */
5321extern (C++) final class UAddExp : UnaExp
5322{
5323 extern (D) this(const ref Loc loc, Expression e)
5324 {
9c7d5e88 5325 super(loc, EXP.uadd, __traits(classInstanceSize, UAddExp), e);
5fee5ec3
IB
5326 }
5327
5328 override void accept(Visitor v)
5329 {
5330 v.visit(this);
5331 }
5332}
5333
5334/***********************************************************
8977f4be 5335 * The bitwise complement operator, `~x`
5fee5ec3
IB
5336 */
5337extern (C++) final class ComExp : UnaExp
5338{
5339 extern (D) this(const ref Loc loc, Expression e)
5340 {
9c7d5e88 5341 super(loc, EXP.tilde, __traits(classInstanceSize, ComExp), e);
5fee5ec3
IB
5342 }
5343
5344 override void accept(Visitor v)
5345 {
5346 v.visit(this);
5347 }
5348}
5349
5350/***********************************************************
8977f4be 5351 * The logical not operator, `!x`
5fee5ec3
IB
5352 */
5353extern (C++) final class NotExp : UnaExp
5354{
5355 extern (D) this(const ref Loc loc, Expression e)
5356 {
9c7d5e88 5357 super(loc, EXP.not, __traits(classInstanceSize, NotExp), e);
5fee5ec3
IB
5358 }
5359
5360 override void accept(Visitor v)
5361 {
5362 v.visit(this);
5363 }
5364}
5365
5366/***********************************************************
8977f4be
IB
5367 * The delete operator, `delete x` (deprecated)
5368 *
5369 * https://dlang.org/spec/expression.html#delete_expressions
5fee5ec3
IB
5370 */
5371extern (C++) final class DeleteExp : UnaExp
5372{
5373 bool isRAII; // true if called automatically as a result of scoped destruction
5374
5375 extern (D) this(const ref Loc loc, Expression e, bool isRAII)
5376 {
9c7d5e88 5377 super(loc, EXP.delete_, __traits(classInstanceSize, DeleteExp), e);
5fee5ec3
IB
5378 this.isRAII = isRAII;
5379 }
5380
5381 override void accept(Visitor v)
5382 {
5383 v.visit(this);
5384 }
5385}
5386
5387/***********************************************************
8977f4be
IB
5388 * The type cast operator, `cast(T) x`
5389 *
5390 * It's possible to cast to one type while painting to another type
5391 *
5392 * https://dlang.org/spec/expression.html#cast_expressions
5fee5ec3
IB
5393 */
5394extern (C++) final class CastExp : UnaExp
5395{
5396 Type to; // type to cast to
5397 ubyte mod = cast(ubyte)~0; // MODxxxxx
5398
5399 extern (D) this(const ref Loc loc, Expression e, Type t)
5400 {
9c7d5e88 5401 super(loc, EXP.cast_, __traits(classInstanceSize, CastExp), e);
5fee5ec3
IB
5402 this.to = t;
5403 }
5404
5405 /* For cast(const) and cast(immutable)
5406 */
5407 extern (D) this(const ref Loc loc, Expression e, ubyte mod)
5408 {
9c7d5e88 5409 super(loc, EXP.cast_, __traits(classInstanceSize, CastExp), e);
5fee5ec3
IB
5410 this.mod = mod;
5411 }
5412
5413 override CastExp syntaxCopy()
5414 {
5415 return to ? new CastExp(loc, e1.syntaxCopy(), to.syntaxCopy()) : new CastExp(loc, e1.syntaxCopy(), mod);
5416 }
5417
5418 override bool isLvalue()
5419 {
5420 //printf("e1.type = %s, to.type = %s\n", e1.type.toChars(), to.toChars());
5421 if (!e1.isLvalue())
5422 return false;
5423 return (to.ty == Tsarray && (e1.type.ty == Tvector || e1.type.ty == Tsarray)) ||
5424 e1.type.mutableOf().unSharedOf().equals(to.mutableOf().unSharedOf());
5425 }
5426
5427 override Expression toLvalue(Scope* sc, Expression e)
5428 {
5429 if (sc && sc.flags & SCOPE.Cfile)
5430 {
5431 /* C11 6.5.4-5: A cast does not yield an lvalue.
5432 */
5433 return Expression.toLvalue(sc, e);
5434 }
5435 if (isLvalue())
5436 return this;
5437 return Expression.toLvalue(sc, e);
5438 }
5439
5440 override Expression addDtorHook(Scope* sc)
5441 {
5442 if (to.toBasetype().ty == Tvoid) // look past the cast(void)
5443 e1 = e1.addDtorHook(sc);
5444 return this;
5445 }
5446
5447 override void accept(Visitor v)
5448 {
5449 v.visit(this);
5450 }
5451}
5452
5453/***********************************************************
5454 */
5455extern (C++) final class VectorExp : UnaExp
5456{
5457 TypeVector to; // the target vector type before semantic()
5458 uint dim = ~0; // number of elements in the vector
5459 OwnedBy ownedByCtfe = OwnedBy.code;
5460
5461 extern (D) this(const ref Loc loc, Expression e, Type t)
5462 {
9c7d5e88 5463 super(loc, EXP.vector, __traits(classInstanceSize, VectorExp), e);
5fee5ec3
IB
5464 assert(t.ty == Tvector);
5465 to = cast(TypeVector)t;
5466 }
5467
0fb57034 5468 static VectorExp create(const ref Loc loc, Expression e, Type t)
5fee5ec3
IB
5469 {
5470 return new VectorExp(loc, e, t);
5471 }
5472
5473 // Same as create, but doesn't allocate memory.
0fb57034 5474 static void emplace(UnionExp* pue, const ref Loc loc, Expression e, Type type)
5fee5ec3
IB
5475 {
5476 emplaceExp!(VectorExp)(pue, loc, e, type);
5477 }
5478
5479 override VectorExp syntaxCopy()
5480 {
5481 return new VectorExp(loc, e1.syntaxCopy(), to.syntaxCopy());
5482 }
5483
5484 override void accept(Visitor v)
5485 {
5486 v.visit(this);
5487 }
5488}
5489
5490/***********************************************************
5491 * e1.array property for vectors.
5492 *
5493 * https://dlang.org/spec/simd.html#properties
5494 */
5495extern (C++) final class VectorArrayExp : UnaExp
5496{
5497 extern (D) this(const ref Loc loc, Expression e1)
5498 {
9c7d5e88 5499 super(loc, EXP.vectorArray, __traits(classInstanceSize, VectorArrayExp), e1);
5fee5ec3
IB
5500 }
5501
5502 override bool isLvalue()
5503 {
5504 return e1.isLvalue();
5505 }
5506
5507 override Expression toLvalue(Scope* sc, Expression e)
5508 {
5509 e1 = e1.toLvalue(sc, e);
5510 return this;
5511 }
5512
5513 override void accept(Visitor v)
5514 {
5515 v.visit(this);
5516 }
5517}
5518
5519/***********************************************************
5520 * e1 [lwr .. upr]
5521 *
c43b5909 5522 * https://dlang.org/spec/expression.html#slice_expressions
5fee5ec3
IB
5523 */
5524extern (C++) final class SliceExp : UnaExp
5525{
5526 Expression upr; // null if implicit 0
5527 Expression lwr; // null if implicit [length - 1]
5528
5529 VarDeclaration lengthVar;
5530 bool upperIsInBounds; // true if upr <= e1.length
5531 bool lowerIsLessThanUpper; // true if lwr <= upr
5532 bool arrayop; // an array operation, rather than a slice
5533
5534 /************************************************************/
5535 extern (D) this(const ref Loc loc, Expression e1, IntervalExp ie)
5536 {
9c7d5e88 5537 super(loc, EXP.slice, __traits(classInstanceSize, SliceExp), e1);
5fee5ec3
IB
5538 this.upr = ie ? ie.upr : null;
5539 this.lwr = ie ? ie.lwr : null;
5540 }
5541
5542 extern (D) this(const ref Loc loc, Expression e1, Expression lwr, Expression upr)
5543 {
9c7d5e88 5544 super(loc, EXP.slice, __traits(classInstanceSize, SliceExp), e1);
5fee5ec3
IB
5545 this.upr = upr;
5546 this.lwr = lwr;
5547 }
5548
5549 override SliceExp syntaxCopy()
5550 {
5551 auto se = new SliceExp(loc, e1.syntaxCopy(), lwr ? lwr.syntaxCopy() : null, upr ? upr.syntaxCopy() : null);
5552 se.lengthVar = this.lengthVar; // bug7871
5553 return se;
5554 }
5555
5556 override bool isLvalue()
5557 {
5558 /* slice expression is rvalue in default, but
5559 * conversion to reference of static array is only allowed.
5560 */
5561 return (type && type.toBasetype().ty == Tsarray);
5562 }
5563
5564 override Expression toLvalue(Scope* sc, Expression e)
5565 {
5566 //printf("SliceExp::toLvalue(%s) type = %s\n", toChars(), type ? type.toChars() : NULL);
5567 return (type && type.toBasetype().ty == Tsarray) ? this : Expression.toLvalue(sc, e);
5568 }
5569
5570 override Expression modifiableLvalue(Scope* sc, Expression e)
5571 {
5572 error("slice expression `%s` is not a modifiable lvalue", toChars());
5573 return this;
5574 }
5575
9c7d5e88 5576 override Optional!bool toBool()
5fee5ec3 5577 {
9c7d5e88 5578 return e1.toBool();
5fee5ec3
IB
5579 }
5580
5581 override void accept(Visitor v)
5582 {
5583 v.visit(this);
5584 }
5585}
5586
5587/***********************************************************
8977f4be 5588 * The `.length` property of an array
5fee5ec3
IB
5589 */
5590extern (C++) final class ArrayLengthExp : UnaExp
5591{
5592 extern (D) this(const ref Loc loc, Expression e1)
5593 {
9c7d5e88 5594 super(loc, EXP.arrayLength, __traits(classInstanceSize, ArrayLengthExp), e1);
5fee5ec3
IB
5595 }
5596
5597 override void accept(Visitor v)
5598 {
5599 v.visit(this);
5600 }
5601}
5602
5603/***********************************************************
5604 * e1 [ a0, a1, a2, a3 ,... ]
5605 *
c43b5909 5606 * https://dlang.org/spec/expression.html#index_expressions
5fee5ec3
IB
5607 */
5608extern (C++) final class ArrayExp : UnaExp
5609{
5610 Expressions* arguments; // Array of Expression's a0..an
5611
5612 size_t currentDimension; // for opDollar
5613 VarDeclaration lengthVar;
5614
5615 extern (D) this(const ref Loc loc, Expression e1, Expression index = null)
5616 {
9c7d5e88 5617 super(loc, EXP.array, __traits(classInstanceSize, ArrayExp), e1);
5fee5ec3
IB
5618 arguments = new Expressions();
5619 if (index)
5620 arguments.push(index);
5621 }
5622
5623 extern (D) this(const ref Loc loc, Expression e1, Expressions* args)
5624 {
9c7d5e88 5625 super(loc, EXP.array, __traits(classInstanceSize, ArrayExp), e1);
5fee5ec3
IB
5626 arguments = args;
5627 }
5628
5629 override ArrayExp syntaxCopy()
5630 {
5631 auto ae = new ArrayExp(loc, e1.syntaxCopy(), arraySyntaxCopy(arguments));
5632 ae.lengthVar = this.lengthVar; // bug7871
5633 return ae;
5634 }
5635
5636 override bool isLvalue()
5637 {
5638 if (type && type.toBasetype().ty == Tvoid)
5639 return false;
5640 return true;
5641 }
5642
5643 override Expression toLvalue(Scope* sc, Expression e)
5644 {
5645 if (type && type.toBasetype().ty == Tvoid)
5646 error("`void`s have no value");
5647 return this;
5648 }
5649
5650 override void accept(Visitor v)
5651 {
5652 v.visit(this);
5653 }
5654}
5655
5656/***********************************************************
5657 */
5658extern (C++) final class DotExp : BinExp
5659{
5660 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
5661 {
9c7d5e88 5662 super(loc, EXP.dot, __traits(classInstanceSize, DotExp), e1, e2);
5fee5ec3
IB
5663 }
5664
5665 override void accept(Visitor v)
5666 {
5667 v.visit(this);
5668 }
5669}
5670
5671/***********************************************************
5672 */
5673extern (C++) final class CommaExp : BinExp
5674{
5675 /// This is needed because AssignExp rewrites CommaExp, hence it needs
5676 /// to trigger the deprecation.
5677 const bool isGenerated;
5678
5679 /// Temporary variable to enable / disable deprecation of comma expression
5680 /// depending on the context.
5681 /// Since most constructor calls are rewritting, the only place where
5682 /// false will be passed will be from the parser.
5683 bool allowCommaExp;
5684
5685
5686 extern (D) this(const ref Loc loc, Expression e1, Expression e2, bool generated = true)
5687 {
9c7d5e88 5688 super(loc, EXP.comma, __traits(classInstanceSize, CommaExp), e1, e2);
5fee5ec3
IB
5689 allowCommaExp = isGenerated = generated;
5690 }
5691
5692 override bool isLvalue()
5693 {
5694 return e2.isLvalue();
5695 }
5696
5697 override Expression toLvalue(Scope* sc, Expression e)
5698 {
5699 e2 = e2.toLvalue(sc, null);
5700 return this;
5701 }
5702
5703 override Expression modifiableLvalue(Scope* sc, Expression e)
5704 {
5705 e2 = e2.modifiableLvalue(sc, e);
5706 return this;
5707 }
5708
9c7d5e88 5709 override Optional!bool toBool()
5fee5ec3 5710 {
9c7d5e88 5711 return e2.toBool();
5fee5ec3
IB
5712 }
5713
5714 override Expression addDtorHook(Scope* sc)
5715 {
5716 e2 = e2.addDtorHook(sc);
5717 return this;
5718 }
5719
5720 override void accept(Visitor v)
5721 {
5722 v.visit(this);
5723 }
5724
5725 /**
5726 * If the argument is a CommaExp, set a flag to prevent deprecation messages
5727 *
5728 * It's impossible to know from CommaExp.semantic if the result will
5729 * be used, hence when there is a result (type != void), a deprecation
5730 * message is always emitted.
5731 * However, some construct can produce a result but won't use it
5732 * (ExpStatement and for loop increment). Those should call this function
5733 * to prevent unwanted deprecations to be emitted.
5734 *
5735 * Params:
5736 * exp = An expression that discards its result.
5737 * If the argument is null or not a CommaExp, nothing happens.
5738 */
5739 static void allow(Expression exp)
5740 {
5741 if (exp)
5742 if (auto ce = exp.isCommaExp())
5743 ce.allowCommaExp = true;
5744 }
5745}
5746
5747/***********************************************************
5748 * Mainly just a placeholder
5749 */
5750extern (C++) final class IntervalExp : Expression
5751{
5752 Expression lwr;
5753 Expression upr;
5754
5755 extern (D) this(const ref Loc loc, Expression lwr, Expression upr)
5756 {
9c7d5e88 5757 super(loc, EXP.interval, __traits(classInstanceSize, IntervalExp));
5fee5ec3
IB
5758 this.lwr = lwr;
5759 this.upr = upr;
5760 }
5761
5762 override Expression syntaxCopy()
5763 {
5764 return new IntervalExp(loc, lwr.syntaxCopy(), upr.syntaxCopy());
5765 }
5766
5767 override void accept(Visitor v)
5768 {
5769 v.visit(this);
5770 }
5771}
5772
8977f4be
IB
5773/***********************************************************
5774 * The `dg.ptr` property, pointing to the delegate's 'context'
5775 *
5776 * c.f.`DelegateFuncptrExp` for the delegate's function pointer `dg.funcptr`
5777 */
5fee5ec3
IB
5778extern (C++) final class DelegatePtrExp : UnaExp
5779{
5780 extern (D) this(const ref Loc loc, Expression e1)
5781 {
9c7d5e88 5782 super(loc, EXP.delegatePointer, __traits(classInstanceSize, DelegatePtrExp), e1);
5fee5ec3
IB
5783 }
5784
5785 override bool isLvalue()
5786 {
5787 return e1.isLvalue();
5788 }
5789
5790 override Expression toLvalue(Scope* sc, Expression e)
5791 {
5792 e1 = e1.toLvalue(sc, e);
5793 return this;
5794 }
5795
5796 override Expression modifiableLvalue(Scope* sc, Expression e)
5797 {
610d7898 5798 if (sc.setUnsafe(false, this.loc, "cannot modify delegate pointer in `@safe` code `%s`", this))
5fee5ec3 5799 {
5fee5ec3
IB
5800 return ErrorExp.get();
5801 }
5802 return Expression.modifiableLvalue(sc, e);
5803 }
5804
5805 override void accept(Visitor v)
5806 {
5807 v.visit(this);
5808 }
5809}
5810
5811/***********************************************************
8977f4be
IB
5812 * The `dg.funcptr` property, pointing to the delegate's function
5813 *
5814 * c.f.`DelegatePtrExp` for the delegate's function pointer `dg.ptr`
5fee5ec3
IB
5815 */
5816extern (C++) final class DelegateFuncptrExp : UnaExp
5817{
5818 extern (D) this(const ref Loc loc, Expression e1)
5819 {
9c7d5e88 5820 super(loc, EXP.delegateFunctionPointer, __traits(classInstanceSize, DelegateFuncptrExp), e1);
5fee5ec3
IB
5821 }
5822
5823 override bool isLvalue()
5824 {
5825 return e1.isLvalue();
5826 }
5827
5828 override Expression toLvalue(Scope* sc, Expression e)
5829 {
5830 e1 = e1.toLvalue(sc, e);
5831 return this;
5832 }
5833
5834 override Expression modifiableLvalue(Scope* sc, Expression e)
5835 {
610d7898 5836 if (sc.setUnsafe(false, this.loc, "cannot modify delegate function pointer in `@safe` code `%s`", this))
5fee5ec3 5837 {
5fee5ec3
IB
5838 return ErrorExp.get();
5839 }
5840 return Expression.modifiableLvalue(sc, e);
5841 }
5842
5843 override void accept(Visitor v)
5844 {
5845 v.visit(this);
5846 }
5847}
5848
5849/***********************************************************
5850 * e1 [ e2 ]
5851 */
5852extern (C++) final class IndexExp : BinExp
5853{
5854 VarDeclaration lengthVar;
5855 bool modifiable = false; // assume it is an rvalue
5856 bool indexIsInBounds; // true if 0 <= e2 && e2 <= e1.length - 1
5857
5858 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
5859 {
9c7d5e88 5860 super(loc, EXP.index, __traits(classInstanceSize, IndexExp), e1, e2);
5fee5ec3
IB
5861 //printf("IndexExp::IndexExp('%s')\n", toChars());
5862 }
5863
7e287503
IB
5864 extern (D) this(const ref Loc loc, Expression e1, Expression e2, bool indexIsInBounds)
5865 {
5866 super(loc, EXP.index, __traits(classInstanceSize, IndexExp), e1, e2);
5867 this.indexIsInBounds = indexIsInBounds;
5868 //printf("IndexExp::IndexExp('%s')\n", toChars());
5869 }
5870
5fee5ec3
IB
5871 override IndexExp syntaxCopy()
5872 {
5873 auto ie = new IndexExp(loc, e1.syntaxCopy(), e2.syntaxCopy());
5874 ie.lengthVar = this.lengthVar; // bug7871
5875 return ie;
5876 }
5877
5878 override bool isLvalue()
5879 {
9c7d5e88 5880 if (e1.op == EXP.assocArrayLiteral)
5fee5ec3
IB
5881 return false;
5882 if (e1.type.ty == Tsarray ||
9c7d5e88 5883 (e1.op == EXP.index && e1.type.ty != Tarray))
5fee5ec3
IB
5884 {
5885 return e1.isLvalue();
5886 }
5887 return true;
5888 }
5889
5890 override Expression toLvalue(Scope* sc, Expression e)
5891 {
5892 if (isLvalue())
5893 return this;
5894 return Expression.toLvalue(sc, e);
5895 }
5896
5897 override Expression modifiableLvalue(Scope* sc, Expression e)
5898 {
5899 //printf("IndexExp::modifiableLvalue(%s)\n", toChars());
5900 Expression ex = markSettingAAElem();
9c7d5e88 5901 if (ex.op == EXP.error)
5fee5ec3
IB
5902 return ex;
5903
5904 return Expression.modifiableLvalue(sc, e);
5905 }
5906
5907 extern (D) Expression markSettingAAElem()
5908 {
5909 if (e1.type.toBasetype().ty == Taarray)
5910 {
5911 Type t2b = e2.type.toBasetype();
5912 if (t2b.ty == Tarray && t2b.nextOf().isMutable())
5913 {
5914 error("associative arrays can only be assigned values with immutable keys, not `%s`", e2.type.toChars());
5915 return ErrorExp.get();
5916 }
5917 modifiable = true;
5918
5919 if (auto ie = e1.isIndexExp())
5920 {
5921 Expression ex = ie.markSettingAAElem();
9c7d5e88 5922 if (ex.op == EXP.error)
5fee5ec3
IB
5923 return ex;
5924 assert(ex == e1);
5925 }
5926 }
5927 return this;
5928 }
5929
5930 override void accept(Visitor v)
5931 {
5932 v.visit(this);
5933 }
5934}
5935
5936/***********************************************************
8977f4be 5937 * The postfix increment/decrement operator, `i++` / `i--`
5fee5ec3
IB
5938 */
5939extern (C++) final class PostExp : BinExp
5940{
9c7d5e88 5941 extern (D) this(EXP op, const ref Loc loc, Expression e)
5fee5ec3
IB
5942 {
5943 super(loc, op, __traits(classInstanceSize, PostExp), e, IntegerExp.literal!1);
9c7d5e88 5944 assert(op == EXP.minusMinus || op == EXP.plusPlus);
5fee5ec3
IB
5945 }
5946
5947 override void accept(Visitor v)
5948 {
5949 v.visit(this);
5950 }
5951}
5952
5953/***********************************************************
8977f4be 5954 * The prefix increment/decrement operator, `++i` / `--i`
5fee5ec3
IB
5955 */
5956extern (C++) final class PreExp : UnaExp
5957{
9c7d5e88 5958 extern (D) this(EXP op, const ref Loc loc, Expression e)
5fee5ec3
IB
5959 {
5960 super(loc, op, __traits(classInstanceSize, PreExp), e);
9c7d5e88 5961 assert(op == EXP.preMinusMinus || op == EXP.prePlusPlus);
5fee5ec3
IB
5962 }
5963
5964 override void accept(Visitor v)
5965 {
5966 v.visit(this);
5967 }
5968}
5969
5970enum MemorySet
5971{
5972 none = 0, // simple assignment
5973 blockAssign = 1, // setting the contents of an array
5974 referenceInit = 2, // setting the reference of STC.ref_ variable
5975}
5976
5977/***********************************************************
8977f4be
IB
5978 * The assignment / initialization operator, `=`
5979 *
5980 * Note: operator assignment `op=` has a different base class, `BinAssignExp`
5fee5ec3
IB
5981 */
5982extern (C++) class AssignExp : BinExp
5983{
5984 MemorySet memset;
5985
5986 /************************************************************/
9c7d5e88 5987 /* op can be EXP.assign, EXP.construct, or EXP.blit */
5fee5ec3
IB
5988 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
5989 {
9c7d5e88 5990 super(loc, EXP.assign, __traits(classInstanceSize, AssignExp), e1, e2);
5fee5ec3
IB
5991 }
5992
9c7d5e88 5993 this(const ref Loc loc, EXP tok, Expression e1, Expression e2)
5fee5ec3
IB
5994 {
5995 super(loc, tok, __traits(classInstanceSize, AssignExp), e1, e2);
5996 }
5997
5998 override final bool isLvalue()
5999 {
6000 // Array-op 'x[] = y[]' should make an rvalue.
6001 // Setting array length 'x.length = v' should make an rvalue.
9c7d5e88 6002 if (e1.op == EXP.slice || e1.op == EXP.arrayLength)
5fee5ec3
IB
6003 {
6004 return false;
6005 }
6006 return true;
6007 }
6008
6009 override final Expression toLvalue(Scope* sc, Expression ex)
6010 {
9c7d5e88 6011 if (e1.op == EXP.slice || e1.op == EXP.arrayLength)
5fee5ec3
IB
6012 {
6013 return Expression.toLvalue(sc, ex);
6014 }
6015
6016 /* In front-end level, AssignExp should make an lvalue of e1.
6017 * Taking the address of e1 will be handled in low level layer,
6018 * so this function does nothing.
6019 */
6020 return this;
6021 }
6022
6023 override void accept(Visitor v)
6024 {
6025 v.visit(this);
6026 }
6027}
6028
6029/***********************************************************
6030 */
6031extern (C++) final class ConstructExp : AssignExp
6032{
6033 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6034 {
9c7d5e88 6035 super(loc, EXP.construct, e1, e2);
5fee5ec3
IB
6036 }
6037
6038 // Internal use only. If `v` is a reference variable, the assignment
6039 // will become a reference initialization automatically.
6040 extern (D) this(const ref Loc loc, VarDeclaration v, Expression e2)
6041 {
6042 auto ve = new VarExp(loc, v);
6043 assert(v.type && ve.type);
6044
9c7d5e88 6045 super(loc, EXP.construct, ve, e2);
5fee5ec3
IB
6046
6047 if (v.isReference())
6048 memset = MemorySet.referenceInit;
6049 }
6050
6051 override void accept(Visitor v)
6052 {
6053 v.visit(this);
6054 }
6055}
6056
6057/***********************************************************
8977f4be 6058 * A bit-for-bit copy from `e2` to `e1`
5fee5ec3
IB
6059 */
6060extern (C++) final class BlitExp : AssignExp
6061{
6062 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6063 {
9c7d5e88 6064 super(loc, EXP.blit, e1, e2);
5fee5ec3
IB
6065 }
6066
6067 // Internal use only. If `v` is a reference variable, the assinment
6068 // will become a reference rebinding automatically.
6069 extern (D) this(const ref Loc loc, VarDeclaration v, Expression e2)
6070 {
6071 auto ve = new VarExp(loc, v);
6072 assert(v.type && ve.type);
6073
9c7d5e88 6074 super(loc, EXP.blit, ve, e2);
5fee5ec3
IB
6075
6076 if (v.isReference())
6077 memset = MemorySet.referenceInit;
6078 }
6079
6080 override void accept(Visitor v)
6081 {
6082 v.visit(this);
6083 }
6084}
6085
6086/***********************************************************
8977f4be 6087 * `x += y`
5fee5ec3
IB
6088 */
6089extern (C++) final class AddAssignExp : BinAssignExp
6090{
6091 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6092 {
9c7d5e88 6093 super(loc, EXP.addAssign, __traits(classInstanceSize, AddAssignExp), e1, e2);
5fee5ec3
IB
6094 }
6095
6096 override void accept(Visitor v)
6097 {
6098 v.visit(this);
6099 }
6100}
6101
6102/***********************************************************
8977f4be 6103 * `x -= y`
5fee5ec3
IB
6104 */
6105extern (C++) final class MinAssignExp : BinAssignExp
6106{
6107 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6108 {
9c7d5e88 6109 super(loc, EXP.minAssign, __traits(classInstanceSize, MinAssignExp), e1, e2);
5fee5ec3
IB
6110 }
6111
6112 override void accept(Visitor v)
6113 {
6114 v.visit(this);
6115 }
6116}
6117
6118/***********************************************************
8977f4be 6119 * `x *= y`
5fee5ec3
IB
6120 */
6121extern (C++) final class MulAssignExp : BinAssignExp
6122{
6123 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6124 {
9c7d5e88 6125 super(loc, EXP.mulAssign, __traits(classInstanceSize, MulAssignExp), e1, e2);
5fee5ec3
IB
6126 }
6127
6128 override void accept(Visitor v)
6129 {
6130 v.visit(this);
6131 }
6132}
6133
6134/***********************************************************
8977f4be 6135 * `x /= y`
5fee5ec3
IB
6136 */
6137extern (C++) final class DivAssignExp : BinAssignExp
6138{
6139 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6140 {
9c7d5e88 6141 super(loc, EXP.divAssign, __traits(classInstanceSize, DivAssignExp), e1, e2);
5fee5ec3
IB
6142 }
6143
6144 override void accept(Visitor v)
6145 {
6146 v.visit(this);
6147 }
6148}
6149
6150/***********************************************************
8977f4be 6151 * `x %= y`
5fee5ec3
IB
6152 */
6153extern (C++) final class ModAssignExp : BinAssignExp
6154{
6155 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6156 {
9c7d5e88 6157 super(loc, EXP.modAssign, __traits(classInstanceSize, ModAssignExp), e1, e2);
5fee5ec3
IB
6158 }
6159
6160 override void accept(Visitor v)
6161 {
6162 v.visit(this);
6163 }
6164}
6165
6166/***********************************************************
8977f4be 6167 * `x &= y`
5fee5ec3
IB
6168 */
6169extern (C++) final class AndAssignExp : BinAssignExp
6170{
6171 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6172 {
9c7d5e88 6173 super(loc, EXP.andAssign, __traits(classInstanceSize, AndAssignExp), e1, e2);
5fee5ec3
IB
6174 }
6175
6176 override void accept(Visitor v)
6177 {
6178 v.visit(this);
6179 }
6180}
6181
6182/***********************************************************
8977f4be 6183 * `x |= y`
5fee5ec3
IB
6184 */
6185extern (C++) final class OrAssignExp : BinAssignExp
6186{
6187 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6188 {
9c7d5e88 6189 super(loc, EXP.orAssign, __traits(classInstanceSize, OrAssignExp), e1, e2);
5fee5ec3
IB
6190 }
6191
6192 override void accept(Visitor v)
6193 {
6194 v.visit(this);
6195 }
6196}
6197
6198/***********************************************************
8977f4be 6199 * `x ^= y`
5fee5ec3
IB
6200 */
6201extern (C++) final class XorAssignExp : BinAssignExp
6202{
6203 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6204 {
9c7d5e88 6205 super(loc, EXP.xorAssign, __traits(classInstanceSize, XorAssignExp), e1, e2);
5fee5ec3
IB
6206 }
6207
6208 override void accept(Visitor v)
6209 {
6210 v.visit(this);
6211 }
6212}
6213
6214/***********************************************************
8977f4be 6215 * `x ^^= y`
5fee5ec3
IB
6216 */
6217extern (C++) final class PowAssignExp : BinAssignExp
6218{
6219 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6220 {
9c7d5e88 6221 super(loc, EXP.powAssign, __traits(classInstanceSize, PowAssignExp), e1, e2);
5fee5ec3
IB
6222 }
6223
6224 override void accept(Visitor v)
6225 {
6226 v.visit(this);
6227 }
6228}
6229
6230/***********************************************************
8977f4be 6231 * `x <<= y`
5fee5ec3
IB
6232 */
6233extern (C++) final class ShlAssignExp : BinAssignExp
6234{
6235 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6236 {
9c7d5e88 6237 super(loc, EXP.leftShiftAssign, __traits(classInstanceSize, ShlAssignExp), e1, e2);
5fee5ec3
IB
6238 }
6239
6240 override void accept(Visitor v)
6241 {
6242 v.visit(this);
6243 }
6244}
6245
6246/***********************************************************
8977f4be 6247 * `x >>= y`
5fee5ec3
IB
6248 */
6249extern (C++) final class ShrAssignExp : BinAssignExp
6250{
6251 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6252 {
9c7d5e88 6253 super(loc, EXP.rightShiftAssign, __traits(classInstanceSize, ShrAssignExp), e1, e2);
5fee5ec3
IB
6254 }
6255
6256 override void accept(Visitor v)
6257 {
6258 v.visit(this);
6259 }
6260}
6261
6262/***********************************************************
8977f4be 6263 * `x >>>= y`
5fee5ec3
IB
6264 */
6265extern (C++) final class UshrAssignExp : BinAssignExp
6266{
6267 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6268 {
9c7d5e88 6269 super(loc, EXP.unsignedRightShiftAssign, __traits(classInstanceSize, UshrAssignExp), e1, e2);
5fee5ec3
IB
6270 }
6271
6272 override void accept(Visitor v)
6273 {
6274 v.visit(this);
6275 }
6276}
6277
6278/***********************************************************
8977f4be
IB
6279 * The `~=` operator.
6280 *
6281 * It can have one of the following operators:
5fee5ec3 6282 *
9c7d5e88
IB
6283 * EXP.concatenateAssign - appending T[] to T[]
6284 * EXP.concatenateElemAssign - appending T to T[]
6285 * EXP.concatenateDcharAssign - appending dchar to T[]
5fee5ec3 6286 *
9c7d5e88 6287 * The parser initially sets it to EXP.concatenateAssign, and semantic() later decides which
5fee5ec3
IB
6288 * of the three it will be set to.
6289 */
6290extern (C++) class CatAssignExp : BinAssignExp
6291{
6292 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6293 {
9c7d5e88 6294 super(loc, EXP.concatenateAssign, __traits(classInstanceSize, CatAssignExp), e1, e2);
5fee5ec3
IB
6295 }
6296
9c7d5e88 6297 extern (D) this(const ref Loc loc, EXP tok, Expression e1, Expression e2)
5fee5ec3
IB
6298 {
6299 super(loc, tok, __traits(classInstanceSize, CatAssignExp), e1, e2);
6300 }
6301
6302 override void accept(Visitor v)
6303 {
6304 v.visit(this);
6305 }
6306}
6307
8977f4be
IB
6308/***********************************************************
6309 * The `~=` operator when appending a single element
6310 */
5fee5ec3
IB
6311extern (C++) final class CatElemAssignExp : CatAssignExp
6312{
6313 extern (D) this(const ref Loc loc, Type type, Expression e1, Expression e2)
6314 {
9c7d5e88 6315 super(loc, EXP.concatenateElemAssign, e1, e2);
5fee5ec3
IB
6316 this.type = type;
6317 }
6318
6319 override void accept(Visitor v)
6320 {
6321 v.visit(this);
6322 }
6323}
6324
8977f4be
IB
6325/***********************************************************
6326 * The `~=` operator when appending a single `dchar`
6327 */
5fee5ec3
IB
6328extern (C++) final class CatDcharAssignExp : CatAssignExp
6329{
6330 extern (D) this(const ref Loc loc, Type type, Expression e1, Expression e2)
6331 {
9c7d5e88 6332 super(loc, EXP.concatenateDcharAssign, e1, e2);
5fee5ec3
IB
6333 this.type = type;
6334 }
6335
6336 override void accept(Visitor v)
6337 {
6338 v.visit(this);
6339 }
6340}
6341
6342/***********************************************************
8977f4be
IB
6343 * The addition operator, `x + y`
6344 *
c43b5909 6345 * https://dlang.org/spec/expression.html#add_expressions
5fee5ec3
IB
6346 */
6347extern (C++) final class AddExp : BinExp
6348{
6349 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6350 {
9c7d5e88 6351 super(loc, EXP.add, __traits(classInstanceSize, AddExp), e1, e2);
5fee5ec3
IB
6352 }
6353
6354 override void accept(Visitor v)
6355 {
6356 v.visit(this);
6357 }
6358}
6359
6360/***********************************************************
8977f4be
IB
6361 * The minus operator, `x - y`
6362 *
6363 * https://dlang.org/spec/expression.html#add_expressions
5fee5ec3
IB
6364 */
6365extern (C++) final class MinExp : BinExp
6366{
6367 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6368 {
9c7d5e88 6369 super(loc, EXP.min, __traits(classInstanceSize, MinExp), e1, e2);
5fee5ec3
IB
6370 }
6371
6372 override void accept(Visitor v)
6373 {
6374 v.visit(this);
6375 }
6376}
6377
6378/***********************************************************
8977f4be
IB
6379 * The concatenation operator, `x ~ y`
6380 *
c43b5909 6381 * https://dlang.org/spec/expression.html#cat_expressions
5fee5ec3
IB
6382 */
6383extern (C++) final class CatExp : BinExp
6384{
6385 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6386 {
9c7d5e88 6387 super(loc, EXP.concatenate, __traits(classInstanceSize, CatExp), e1, e2);
5fee5ec3
IB
6388 }
6389
6390 override Expression resolveLoc(const ref Loc loc, Scope* sc)
6391 {
6392 e1 = e1.resolveLoc(loc, sc);
6393 e2 = e2.resolveLoc(loc, sc);
6394 return this;
6395 }
6396
6397 override void accept(Visitor v)
6398 {
6399 v.visit(this);
6400 }
6401}
6402
6403/***********************************************************
8977f4be
IB
6404 * The multiplication operator, `x * y`
6405 *
c43b5909 6406 * https://dlang.org/spec/expression.html#mul_expressions
5fee5ec3
IB
6407 */
6408extern (C++) final class MulExp : BinExp
6409{
6410 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6411 {
9c7d5e88 6412 super(loc, EXP.mul, __traits(classInstanceSize, MulExp), e1, e2);
5fee5ec3
IB
6413 }
6414
6415 override void accept(Visitor v)
6416 {
6417 v.visit(this);
6418 }
6419}
6420
6421/***********************************************************
8977f4be
IB
6422 * The division operator, `x / y`
6423 *
c43b5909 6424 * https://dlang.org/spec/expression.html#mul_expressions
5fee5ec3
IB
6425 */
6426extern (C++) final class DivExp : BinExp
6427{
6428 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6429 {
9c7d5e88 6430 super(loc, EXP.div, __traits(classInstanceSize, DivExp), e1, e2);
5fee5ec3
IB
6431 }
6432
6433 override void accept(Visitor v)
6434 {
6435 v.visit(this);
6436 }
6437}
6438
6439/***********************************************************
8977f4be
IB
6440 * The modulo operator, `x % y`
6441 *
c43b5909 6442 * https://dlang.org/spec/expression.html#mul_expressions
5fee5ec3
IB
6443 */
6444extern (C++) final class ModExp : BinExp
6445{
6446 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6447 {
9c7d5e88 6448 super(loc, EXP.mod, __traits(classInstanceSize, ModExp), e1, e2);
5fee5ec3
IB
6449 }
6450
6451 override void accept(Visitor v)
6452 {
6453 v.visit(this);
6454 }
6455}
6456
6457/***********************************************************
8977f4be
IB
6458 * The 'power' operator, `x ^^ y`
6459 *
c43b5909 6460 * https://dlang.org/spec/expression.html#pow_expressions
5fee5ec3
IB
6461 */
6462extern (C++) final class PowExp : BinExp
6463{
6464 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6465 {
9c7d5e88 6466 super(loc, EXP.pow, __traits(classInstanceSize, PowExp), e1, e2);
5fee5ec3
IB
6467 }
6468
6469 override void accept(Visitor v)
6470 {
6471 v.visit(this);
6472 }
6473}
6474
6475/***********************************************************
8977f4be
IB
6476 * The 'shift left' operator, `x << y`
6477 *
6478 * https://dlang.org/spec/expression.html#shift_expressions
5fee5ec3
IB
6479 */
6480extern (C++) final class ShlExp : BinExp
6481{
6482 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6483 {
9c7d5e88 6484 super(loc, EXP.leftShift, __traits(classInstanceSize, ShlExp), e1, e2);
5fee5ec3
IB
6485 }
6486
6487 override void accept(Visitor v)
6488 {
6489 v.visit(this);
6490 }
6491}
6492
6493/***********************************************************
8977f4be
IB
6494 * The 'shift right' operator, `x >> y`
6495 *
6496 * https://dlang.org/spec/expression.html#shift_expressions
5fee5ec3
IB
6497 */
6498extern (C++) final class ShrExp : BinExp
6499{
6500 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6501 {
9c7d5e88 6502 super(loc, EXP.rightShift, __traits(classInstanceSize, ShrExp), e1, e2);
5fee5ec3
IB
6503 }
6504
6505 override void accept(Visitor v)
6506 {
6507 v.visit(this);
6508 }
6509}
6510
6511/***********************************************************
8977f4be
IB
6512 * The 'unsigned shift right' operator, `x >>> y`
6513 *
6514 * https://dlang.org/spec/expression.html#shift_expressions
5fee5ec3
IB
6515 */
6516extern (C++) final class UshrExp : BinExp
6517{
6518 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6519 {
9c7d5e88 6520 super(loc, EXP.unsignedRightShift, __traits(classInstanceSize, UshrExp), e1, e2);
5fee5ec3
IB
6521 }
6522
6523 override void accept(Visitor v)
6524 {
6525 v.visit(this);
6526 }
6527}
6528
6529/***********************************************************
8977f4be
IB
6530 * The bitwise 'and' operator, `x & y`
6531 *
6532 * https://dlang.org/spec/expression.html#and_expressions
5fee5ec3
IB
6533 */
6534extern (C++) final class AndExp : BinExp
6535{
6536 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6537 {
9c7d5e88 6538 super(loc, EXP.and, __traits(classInstanceSize, AndExp), e1, e2);
5fee5ec3
IB
6539 }
6540
6541 override void accept(Visitor v)
6542 {
6543 v.visit(this);
6544 }
6545}
6546
6547/***********************************************************
8977f4be
IB
6548 * The bitwise 'or' operator, `x | y`
6549 *
6550 * https://dlang.org/spec/expression.html#or_expressions
5fee5ec3
IB
6551 */
6552extern (C++) final class OrExp : BinExp
6553{
6554 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6555 {
9c7d5e88 6556 super(loc, EXP.or, __traits(classInstanceSize, OrExp), e1, e2);
5fee5ec3
IB
6557 }
6558
6559 override void accept(Visitor v)
6560 {
6561 v.visit(this);
6562 }
6563}
6564
6565/***********************************************************
8977f4be
IB
6566 * The bitwise 'xor' operator, `x ^ y`
6567 *
6568 * https://dlang.org/spec/expression.html#xor_expressions
5fee5ec3
IB
6569 */
6570extern (C++) final class XorExp : BinExp
6571{
6572 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6573 {
9c7d5e88 6574 super(loc, EXP.xor, __traits(classInstanceSize, XorExp), e1, e2);
5fee5ec3
IB
6575 }
6576
6577 override void accept(Visitor v)
6578 {
6579 v.visit(this);
6580 }
6581}
6582
6583/***********************************************************
8977f4be
IB
6584 * The logical 'and' / 'or' operator, `X && Y` / `X || Y`
6585 *
c43b5909
IB
6586 * https://dlang.org/spec/expression.html#andand_expressions
6587 * https://dlang.org/spec/expression.html#oror_expressions
5fee5ec3
IB
6588 */
6589extern (C++) final class LogicalExp : BinExp
6590{
9c7d5e88 6591 extern (D) this(const ref Loc loc, EXP op, Expression e1, Expression e2)
5fee5ec3
IB
6592 {
6593 super(loc, op, __traits(classInstanceSize, LogicalExp), e1, e2);
9c7d5e88 6594 assert(op == EXP.andAnd || op == EXP.orOr);
5fee5ec3
IB
6595 }
6596
6597 override void accept(Visitor v)
6598 {
6599 v.visit(this);
6600 }
6601}
6602
6603/***********************************************************
8977f4be
IB
6604 * A comparison operator, `<` `<=` `>` `>=`
6605 *
5fee5ec3 6606 * `op` is one of:
9c7d5e88 6607 * EXP.lessThan, EXP.lessOrEqual, EXP.greaterThan, EXP.greaterOrEqual
5fee5ec3 6608 *
c43b5909 6609 * https://dlang.org/spec/expression.html#relation_expressions
5fee5ec3
IB
6610 */
6611extern (C++) final class CmpExp : BinExp
6612{
9c7d5e88 6613 extern (D) this(EXP op, const ref Loc loc, Expression e1, Expression e2)
5fee5ec3
IB
6614 {
6615 super(loc, op, __traits(classInstanceSize, CmpExp), e1, e2);
9c7d5e88 6616 assert(op == EXP.lessThan || op == EXP.lessOrEqual || op == EXP.greaterThan || op == EXP.greaterOrEqual);
5fee5ec3
IB
6617 }
6618
6619 override void accept(Visitor v)
6620 {
6621 v.visit(this);
6622 }
6623}
6624
6625/***********************************************************
8977f4be
IB
6626 * The `in` operator, `"a" in ["a": 1]`
6627 *
6628 * Note: `x !in y` is rewritten to `!(x in y)` in the parser
6629 *
6630 * https://dlang.org/spec/expression.html#in_expressions
5fee5ec3
IB
6631 */
6632extern (C++) final class InExp : BinExp
6633{
6634 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6635 {
9c7d5e88 6636 super(loc, EXP.in_, __traits(classInstanceSize, InExp), e1, e2);
5fee5ec3
IB
6637 }
6638
6639 override void accept(Visitor v)
6640 {
6641 v.visit(this);
6642 }
6643}
6644
6645/***********************************************************
8977f4be
IB
6646 * Associative array removal, `aa.remove(arg)`
6647 *
5fee5ec3
IB
6648 * This deletes the key e1 from the associative array e2
6649 */
6650extern (C++) final class RemoveExp : BinExp
6651{
6652 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6653 {
9c7d5e88 6654 super(loc, EXP.remove, __traits(classInstanceSize, RemoveExp), e1, e2);
5fee5ec3
IB
6655 type = Type.tbool;
6656 }
6657
6658 override void accept(Visitor v)
6659 {
6660 v.visit(this);
6661 }
6662}
6663
6664/***********************************************************
6665 * `==` and `!=`
6666 *
9c7d5e88 6667 * EXP.equal and EXP.notEqual
5fee5ec3 6668 *
c43b5909 6669 * https://dlang.org/spec/expression.html#equality_expressions
5fee5ec3
IB
6670 */
6671extern (C++) final class EqualExp : BinExp
6672{
9c7d5e88 6673 extern (D) this(EXP op, const ref Loc loc, Expression e1, Expression e2)
5fee5ec3
IB
6674 {
6675 super(loc, op, __traits(classInstanceSize, EqualExp), e1, e2);
9c7d5e88 6676 assert(op == EXP.equal || op == EXP.notEqual);
5fee5ec3
IB
6677 }
6678
6679 override void accept(Visitor v)
6680 {
6681 v.visit(this);
6682 }
6683}
6684
6685/***********************************************************
6686 * `is` and `!is`
6687 *
9c7d5e88 6688 * EXP.identity and EXP.notIdentity
5fee5ec3 6689 *
c43b5909 6690 * https://dlang.org/spec/expression.html#identity_expressions
5fee5ec3
IB
6691 */
6692extern (C++) final class IdentityExp : BinExp
6693{
9c7d5e88 6694 extern (D) this(EXP op, const ref Loc loc, Expression e1, Expression e2)
5fee5ec3
IB
6695 {
6696 super(loc, op, __traits(classInstanceSize, IdentityExp), e1, e2);
9c7d5e88 6697 assert(op == EXP.identity || op == EXP.notIdentity);
5fee5ec3
IB
6698 }
6699
6700 override void accept(Visitor v)
6701 {
6702 v.visit(this);
6703 }
6704}
6705
6706/***********************************************************
8977f4be 6707 * The ternary operator, `econd ? e1 : e2`
5fee5ec3 6708 *
c43b5909 6709 * https://dlang.org/spec/expression.html#conditional_expressions
5fee5ec3
IB
6710 */
6711extern (C++) final class CondExp : BinExp
6712{
6713 Expression econd;
6714
6715 extern (D) this(const ref Loc loc, Expression econd, Expression e1, Expression e2)
6716 {
9c7d5e88 6717 super(loc, EXP.question, __traits(classInstanceSize, CondExp), e1, e2);
5fee5ec3
IB
6718 this.econd = econd;
6719 }
6720
6721 override CondExp syntaxCopy()
6722 {
6723 return new CondExp(loc, econd.syntaxCopy(), e1.syntaxCopy(), e2.syntaxCopy());
6724 }
6725
6726 override bool isLvalue()
6727 {
6728 return e1.isLvalue() && e2.isLvalue();
6729 }
6730
6731 override Expression toLvalue(Scope* sc, Expression ex)
6732 {
6733 // convert (econd ? e1 : e2) to *(econd ? &e1 : &e2)
6734 CondExp e = cast(CondExp)copy();
6735 e.e1 = e1.toLvalue(sc, null).addressOf();
6736 e.e2 = e2.toLvalue(sc, null).addressOf();
6737 e.type = type.pointerTo();
6738 return new PtrExp(loc, e, type);
6739 }
6740
6741 override Expression modifiableLvalue(Scope* sc, Expression e)
6742 {
6743 if (!e1.isLvalue() && !e2.isLvalue())
6744 {
6745 error("conditional expression `%s` is not a modifiable lvalue", toChars());
6746 return ErrorExp.get();
6747 }
6748 e1 = e1.modifiableLvalue(sc, e1);
6749 e2 = e2.modifiableLvalue(sc, e2);
6750 return toLvalue(sc, this);
6751 }
6752
6753 void hookDtors(Scope* sc)
6754 {
6755 extern (C++) final class DtorVisitor : StoppableVisitor
6756 {
6757 alias visit = typeof(super).visit;
6758 public:
6759 Scope* sc;
6760 CondExp ce;
6761 VarDeclaration vcond;
6762 bool isThen;
6763
6764 extern (D) this(Scope* sc, CondExp ce)
6765 {
6766 this.sc = sc;
6767 this.ce = ce;
6768 }
6769
6770 override void visit(Expression e)
6771 {
6772 //printf("(e = %s)\n", e.toChars());
6773 }
6774
6775 override void visit(DeclarationExp e)
6776 {
6777 auto v = e.declaration.isVarDeclaration();
6778 if (v && !v.isDataseg())
6779 {
6780 if (v._init)
6781 {
6782 if (auto ei = v._init.isExpInitializer())
6783 walkPostorder(ei.exp, this);
6784 }
6785
6786 if (v.edtor)
6787 walkPostorder(v.edtor, this);
6788
6789 if (v.needsScopeDtor())
6790 {
6791 if (!vcond)
6792 {
6793 vcond = copyToTemp(STC.volatile_ | STC.const_, "__cond", ce.econd);
6794 vcond.dsymbolSemantic(sc);
6795
6796 Expression de = new DeclarationExp(ce.econd.loc, vcond);
6797 de = de.expressionSemantic(sc);
6798
6799 Expression ve = new VarExp(ce.econd.loc, vcond);
6800 ce.econd = Expression.combine(de, ve);
6801 }
6802
6803 //printf("\t++v = %s, v.edtor = %s\n", v.toChars(), v.edtor.toChars());
6804 Expression ve = new VarExp(vcond.loc, vcond);
6805 if (isThen)
9c7d5e88 6806 v.edtor = new LogicalExp(v.edtor.loc, EXP.andAnd, ve, v.edtor);
5fee5ec3 6807 else
9c7d5e88 6808 v.edtor = new LogicalExp(v.edtor.loc, EXP.orOr, ve, v.edtor);
5fee5ec3
IB
6809 v.edtor = v.edtor.expressionSemantic(sc);
6810 //printf("\t--v = %s, v.edtor = %s\n", v.toChars(), v.edtor.toChars());
6811 }
6812 }
6813 }
6814 }
6815
6816 scope DtorVisitor v = new DtorVisitor(sc, this);
6817 //printf("+%s\n", toChars());
6818 v.isThen = true;
6819 walkPostorder(e1, v);
6820 v.isThen = false;
6821 walkPostorder(e2, v);
6822 //printf("-%s\n", toChars());
6823 }
6824
6825 override void accept(Visitor v)
6826 {
6827 v.visit(this);
6828 }
6829}
6830
6831/// Returns: if this token is the `op` for a derived `DefaultInitExp` class.
9c7d5e88 6832bool isDefaultInitOp(EXP op) pure nothrow @safe @nogc
5fee5ec3 6833{
9c7d5e88
IB
6834 return op == EXP.prettyFunction || op == EXP.functionString ||
6835 op == EXP.line || op == EXP.moduleString ||
6836 op == EXP.file || op == EXP.fileFullPath ;
5fee5ec3
IB
6837}
6838
6839/***********************************************************
8977f4be
IB
6840 * A special keyword when used as a function's default argument
6841 *
6842 * When possible, special keywords are resolved in the parser, but when
6843 * appearing as a default argument, they result in an expression deriving
6844 * from this base class that is resolved for each function call.
6845 *
6846 * ---
6847 * const x = __LINE__; // resolved in the parser
6848 * void foo(string file = __FILE__, int line = __LINE__); // DefaultInitExp
6849 * ---
6850 *
6851 * https://dlang.org/spec/expression.html#specialkeywords
5fee5ec3
IB
6852 */
6853extern (C++) class DefaultInitExp : Expression
6854{
9c7d5e88 6855 extern (D) this(const ref Loc loc, EXP op, int size)
5fee5ec3
IB
6856 {
6857 super(loc, op, size);
6858 }
6859
6860 override void accept(Visitor v)
6861 {
6862 v.visit(this);
6863 }
6864}
6865
6866/***********************************************************
8977f4be 6867 * The `__FILE__` token as a default argument
5fee5ec3
IB
6868 */
6869extern (C++) final class FileInitExp : DefaultInitExp
6870{
9c7d5e88 6871 extern (D) this(const ref Loc loc, EXP tok)
5fee5ec3
IB
6872 {
6873 super(loc, tok, __traits(classInstanceSize, FileInitExp));
6874 }
6875
6876 override Expression resolveLoc(const ref Loc loc, Scope* sc)
6877 {
6878 //printf("FileInitExp::resolve() %s\n", toChars());
6879 const(char)* s;
9c7d5e88 6880 if (op == EXP.fileFullPath)
5fee5ec3
IB
6881 s = FileName.toAbsolute(loc.isValid() ? loc.filename : sc._module.srcfile.toChars());
6882 else
6883 s = loc.isValid() ? loc.filename : sc._module.ident.toChars();
6884
6885 Expression e = new StringExp(loc, s.toDString());
6886 e = e.expressionSemantic(sc);
6887 e = e.castTo(sc, type);
6888 return e;
6889 }
6890
6891 override void accept(Visitor v)
6892 {
6893 v.visit(this);
6894 }
6895}
6896
6897/***********************************************************
8977f4be 6898 * The `__LINE__` token as a default argument
5fee5ec3
IB
6899 */
6900extern (C++) final class LineInitExp : DefaultInitExp
6901{
6902 extern (D) this(const ref Loc loc)
6903 {
9c7d5e88 6904 super(loc, EXP.line, __traits(classInstanceSize, LineInitExp));
5fee5ec3
IB
6905 }
6906
6907 override Expression resolveLoc(const ref Loc loc, Scope* sc)
6908 {
6909 Expression e = new IntegerExp(loc, loc.linnum, Type.tint32);
6910 e = e.castTo(sc, type);
6911 return e;
6912 }
6913
6914 override void accept(Visitor v)
6915 {
6916 v.visit(this);
6917 }
6918}
6919
6920/***********************************************************
8977f4be 6921 * The `__MODULE__` token as a default argument
5fee5ec3
IB
6922 */
6923extern (C++) final class ModuleInitExp : DefaultInitExp
6924{
6925 extern (D) this(const ref Loc loc)
6926 {
9c7d5e88 6927 super(loc, EXP.moduleString, __traits(classInstanceSize, ModuleInitExp));
5fee5ec3
IB
6928 }
6929
6930 override Expression resolveLoc(const ref Loc loc, Scope* sc)
6931 {
6932 const auto s = (sc.callsc ? sc.callsc : sc)._module.toPrettyChars().toDString();
6933 Expression e = new StringExp(loc, s);
6934 e = e.expressionSemantic(sc);
6935 e = e.castTo(sc, type);
6936 return e;
6937 }
6938
6939 override void accept(Visitor v)
6940 {
6941 v.visit(this);
6942 }
6943}
6944
6945/***********************************************************
8977f4be 6946 * The `__FUNCTION__` token as a default argument
5fee5ec3
IB
6947 */
6948extern (C++) final class FuncInitExp : DefaultInitExp
6949{
6950 extern (D) this(const ref Loc loc)
6951 {
9c7d5e88 6952 super(loc, EXP.functionString, __traits(classInstanceSize, FuncInitExp));
5fee5ec3
IB
6953 }
6954
6955 override Expression resolveLoc(const ref Loc loc, Scope* sc)
6956 {
6957 const(char)* s;
6958 if (sc.callsc && sc.callsc.func)
6959 s = sc.callsc.func.Dsymbol.toPrettyChars();
6960 else if (sc.func)
6961 s = sc.func.Dsymbol.toPrettyChars();
6962 else
6963 s = "";
6964 Expression e = new StringExp(loc, s.toDString());
6965 e = e.expressionSemantic(sc);
6966 e.type = Type.tstring;
6967 return e;
6968 }
6969
6970 override void accept(Visitor v)
6971 {
6972 v.visit(this);
6973 }
6974}
6975
6976/***********************************************************
8977f4be 6977 * The `__PRETTY_FUNCTION__` token as a default argument
5fee5ec3
IB
6978 */
6979extern (C++) final class PrettyFuncInitExp : DefaultInitExp
6980{
6981 extern (D) this(const ref Loc loc)
6982 {
9c7d5e88 6983 super(loc, EXP.prettyFunction, __traits(classInstanceSize, PrettyFuncInitExp));
5fee5ec3
IB
6984 }
6985
6986 override Expression resolveLoc(const ref Loc loc, Scope* sc)
6987 {
6988 FuncDeclaration fd = (sc.callsc && sc.callsc.func)
6989 ? sc.callsc.func
6990 : sc.func;
6991
6992 const(char)* s;
6993 if (fd)
6994 {
6995 const funcStr = fd.Dsymbol.toPrettyChars();
6996 OutBuffer buf;
6997 functionToBufferWithIdent(fd.type.isTypeFunction(), &buf, funcStr, fd.isStatic);
6998 s = buf.extractChars();
6999 }
7000 else
7001 {
7002 s = "";
7003 }
7004
7005 Expression e = new StringExp(loc, s.toDString());
7006 e = e.expressionSemantic(sc);
7007 e.type = Type.tstring;
7008 return e;
7009 }
7010
7011 override void accept(Visitor v)
7012 {
7013 v.visit(this);
7014 }
7015}
7016
7017/**
7018 * Objective-C class reference expression.
7019 *
7020 * Used to get the metaclass of an Objective-C class, `NSObject.Class`.
7021 */
7022extern (C++) final class ObjcClassReferenceExp : Expression
7023{
7024 ClassDeclaration classDeclaration;
7025
7026 extern (D) this(const ref Loc loc, ClassDeclaration classDeclaration)
7027 {
9c7d5e88 7028 super(loc, EXP.objcClassReference,
5fee5ec3
IB
7029 __traits(classInstanceSize, ObjcClassReferenceExp));
7030 this.classDeclaration = classDeclaration;
7031 type = objc.getRuntimeMetaclass(classDeclaration).getType();
7032 }
7033
7034 override void accept(Visitor v)
7035 {
7036 v.visit(this);
7037 }
7038}
7039
7040/*******************
7041 * C11 6.5.1.1 Generic Selection
7042 * For ImportC
7043 */
7044extern (C++) final class GenericExp : Expression
7045{
7046 Expression cntlExp; /// controlling expression of a generic selection (not evaluated)
7047 Types* types; /// type-names for generic associations (null entry for `default`)
7048 Expressions* exps; /// 1:1 mapping of typeNames to exps
7049
7050 extern (D) this(const ref Loc loc, Expression cntlExp, Types* types, Expressions* exps)
7051 {
9c7d5e88 7052 super(loc, EXP._Generic, __traits(classInstanceSize, GenericExp));
5fee5ec3
IB
7053 this.cntlExp = cntlExp;
7054 this.types = types;
7055 this.exps = exps;
7056 assert(types.length == exps.length); // must be the same and >=1
7057 }
7058
7059 override GenericExp syntaxCopy()
7060 {
7061 return new GenericExp(loc, cntlExp.syntaxCopy(), Type.arraySyntaxCopy(types), Expression.arraySyntaxCopy(exps));
7062 }
7063
7064 override void accept(Visitor v)
7065 {
7066 v.visit(this);
7067 }
7068}
7069
7070/***************************************
7071 * Parameters:
7072 * sc: scope
7073 * flag: 1: do not issue error message for invalid modification
7074 2: the exp is a DotVarExp and a subfield of the leftmost
7075 variable is modified
7076 * Returns:
7077 * Whether the type is modifiable
7078 */
7079extern(D) Modifiable checkModifiable(Expression exp, Scope* sc, ModifyFlags flag = ModifyFlags.none)
7080{
7081 switch(exp.op)
7082 {
9c7d5e88 7083 case EXP.variable:
5fee5ec3
IB
7084 auto varExp = cast(VarExp)exp;
7085
7086 //printf("VarExp::checkModifiable %s", varExp.toChars());
7087 assert(varExp.type);
7088 return varExp.var.checkModify(varExp.loc, sc, null, flag);
7089
9c7d5e88 7090 case EXP.dotVariable:
5fee5ec3
IB
7091 auto dotVarExp = cast(DotVarExp)exp;
7092
7093 //printf("DotVarExp::checkModifiable %s %s\n", dotVarExp.toChars(), dotVarExp.type.toChars());
9c7d5e88 7094 if (dotVarExp.e1.op == EXP.this_)
5fee5ec3
IB
7095 return dotVarExp.var.checkModify(dotVarExp.loc, sc, dotVarExp.e1, flag);
7096
7097 /* https://issues.dlang.org/show_bug.cgi?id=12764
7098 * If inside a constructor and an expression of type `this.field.var`
7099 * is encountered, where `field` is a struct declaration with
7100 * default construction disabled, we must make sure that
7101 * assigning to `var` does not imply that `field` was initialized
7102 */
7103 if (sc.func && sc.func.isCtorDeclaration())
7104 {
7105 // if inside a constructor scope and e1 of this DotVarExp
7106 // is another DotVarExp, then check if the leftmost expression is a `this` identifier
7107 if (auto dve = dotVarExp.e1.isDotVarExp())
7108 {
7109 // Iterate the chain of DotVarExp to find `this`
7110 // Keep track whether access to fields was limited to union members
7111 // s.t. one can initialize an entire struct inside nested unions
7112 // (but not its members)
7113 bool onlyUnion = true;
7114 while (true)
7115 {
7116 auto v = dve.var.isVarDeclaration();
7117 assert(v);
7118
7119 // Accessing union member?
7120 auto t = v.type.isTypeStruct();
7121 if (!t || !t.sym.isUnionDeclaration())
7122 onlyUnion = false;
7123
7124 // Another DotVarExp left?
9c7d5e88 7125 if (!dve.e1 || dve.e1.op != EXP.dotVariable)
5fee5ec3
IB
7126 break;
7127
7128 dve = cast(DotVarExp) dve.e1;
7129 }
7130
9c7d5e88 7131 if (dve.e1.op == EXP.this_)
5fee5ec3
IB
7132 {
7133 scope v = dve.var.isVarDeclaration();
7134 /* if v is a struct member field with no initializer, no default construction
7135 * and v wasn't intialized before
7136 */
7137 if (v && v.isField() && !v._init && !v.ctorinit)
7138 {
7139 if (auto ts = v.type.isTypeStruct())
7140 {
7141 if (ts.sym.noDefaultCtor)
7142 {
7143 /* checkModify will consider that this is an initialization
7144 * of v while it is actually an assignment of a field of v
7145 */
7146 scope modifyLevel = v.checkModify(dotVarExp.loc, sc, dve.e1, !onlyUnion ? (flag | ModifyFlags.fieldAssign) : flag);
7147 if (modifyLevel == Modifiable.initialization)
7148 {
7149 // https://issues.dlang.org/show_bug.cgi?id=22118
7150 // v is a union type field that was assigned
7151 // a variable, therefore it counts as initialization
7152 if (v.ctorinit)
7153 return Modifiable.initialization;
7154
7155 return Modifiable.yes;
7156 }
7157 return modifyLevel;
7158 }
7159 }
7160 }
7161 }
7162 }
7163 }
7164
7165 //printf("\te1 = %s\n", e1.toChars());
7166 return dotVarExp.e1.checkModifiable(sc, flag);
7167
9c7d5e88 7168 case EXP.star:
5fee5ec3
IB
7169 auto ptrExp = cast(PtrExp)exp;
7170 if (auto se = ptrExp.e1.isSymOffExp())
7171 {
7172 return se.var.checkModify(ptrExp.loc, sc, null, flag);
7173 }
7174 else if (auto ae = ptrExp.e1.isAddrExp())
7175 {
7176 return ae.e1.checkModifiable(sc, flag);
7177 }
7178 return Modifiable.yes;
7179
9c7d5e88 7180 case EXP.slice:
5fee5ec3
IB
7181 auto sliceExp = cast(SliceExp)exp;
7182
7183 //printf("SliceExp::checkModifiable %s\n", sliceExp.toChars());
7184 auto e1 = sliceExp.e1;
9c7d5e88 7185 if (e1.type.ty == Tsarray || (e1.op == EXP.index && e1.type.ty != Tarray) || e1.op == EXP.slice)
5fee5ec3
IB
7186 {
7187 return e1.checkModifiable(sc, flag);
7188 }
7189 return Modifiable.yes;
7190
9c7d5e88 7191 case EXP.comma:
5fee5ec3
IB
7192 return (cast(CommaExp)exp).e2.checkModifiable(sc, flag);
7193
9c7d5e88 7194 case EXP.index:
5fee5ec3
IB
7195 auto indexExp = cast(IndexExp)exp;
7196 auto e1 = indexExp.e1;
7197 if (e1.type.ty == Tsarray ||
7198 e1.type.ty == Taarray ||
9c7d5e88
IB
7199 (e1.op == EXP.index && e1.type.ty != Tarray) ||
7200 e1.op == EXP.slice)
5fee5ec3
IB
7201 {
7202 return e1.checkModifiable(sc, flag);
7203 }
7204 return Modifiable.yes;
7205
9c7d5e88 7206 case EXP.question:
5fee5ec3
IB
7207 auto condExp = cast(CondExp)exp;
7208 if (condExp.e1.checkModifiable(sc, flag) != Modifiable.no
7209 && condExp.e2.checkModifiable(sc, flag) != Modifiable.no)
7210 return Modifiable.yes;
7211 return Modifiable.no;
7212
7213 default:
7214 return exp.type ? Modifiable.yes : Modifiable.no; // default modifiable
7215 }
7216}
6384eff5 7217
c8dfa79c
IB
7218/**
7219 * Verify if the given identifier is any of
7220 * _d_array{ctor,setctor,setassign,assign_l, assign_r}.
7221 *
7222 * Params:
7223 * id = the identifier to verify
7224 *
7225 * Returns:
7226 * `true` if the identifier corresponds to a construction of assignement
7227 * runtime hook, `false` otherwise.
7228 */
7229bool isArrayConstructionOrAssign(const Identifier id)
7230{
7231 import dmd.id : Id;
7232
7233 return id == Id._d_arrayctor || id == Id._d_arraysetctor ||
7234 id == Id._d_arrayassign_l || id == Id._d_arrayassign_r ||
7235 id == Id._d_arraysetassign;
7236}
7237
6384eff5
IB
7238/******************************
7239 * Provide efficient way to implement isUnaExp(), isBinExp(), isBinAssignExp()
7240 */
7241private immutable ubyte[EXP.max + 1] exptab =
7242() {
7243 ubyte[EXP.max + 1] tab;
7244 with (EXPFLAGS)
7245 {
7246 foreach (i; Eunary) { tab[i] |= unary; }
7247 foreach (i; Ebinary) { tab[i] |= unary | binary; }
7248 foreach (i; EbinaryAssign) { tab[i] |= unary | binary | binaryAssign; }
7249 }
7250 return tab;
7251} ();
7252
7253private enum EXPFLAGS : ubyte
7254{
7255 unary = 1,
7256 binary = 2,
7257 binaryAssign = 4,
7258}
7259
7260private enum Eunary =
7261 [
7262 EXP.import_, EXP.assert_, EXP.throw_, EXP.dotIdentifier, EXP.dotTemplateDeclaration,
7263 EXP.dotVariable, EXP.dotTemplateInstance, EXP.delegate_, EXP.dotType, EXP.call,
7264 EXP.address, EXP.star, EXP.negate, EXP.uadd, EXP.tilde, EXP.not, EXP.delete_, EXP.cast_,
7265 EXP.vector, EXP.vectorArray, EXP.slice, EXP.arrayLength, EXP.array, EXP.delegatePointer,
7266 EXP.delegateFunctionPointer, EXP.preMinusMinus, EXP.prePlusPlus,
7267 ];
7268
7269private enum Ebinary =
7270 [
7271 EXP.dot, EXP.comma, EXP.index, EXP.minusMinus, EXP.plusPlus, EXP.assign,
7272 EXP.add, EXP.min, EXP.concatenate, EXP.mul, EXP.div, EXP.mod, EXP.pow, EXP.leftShift,
7273 EXP.rightShift, EXP.unsignedRightShift, EXP.and, EXP.or, EXP.xor, EXP.andAnd, EXP.orOr,
7274 EXP.lessThan, EXP.lessOrEqual, EXP.greaterThan, EXP.greaterOrEqual,
7275 EXP.in_, EXP.remove, EXP.equal, EXP.notEqual, EXP.identity, EXP.notIdentity,
7276 EXP.question,
7277 EXP.construct, EXP.blit,
7278 ];
7279
7280private enum EbinaryAssign =
7281 [
7282 EXP.addAssign, EXP.minAssign, EXP.mulAssign, EXP.divAssign, EXP.modAssign,
7283 EXP.andAssign, EXP.orAssign, EXP.xorAssign, EXP.powAssign,
7284 EXP.leftShiftAssign, EXP.rightShiftAssign, EXP.unsignedRightShiftAssign,
7285 EXP.concatenateAssign, EXP.concatenateElemAssign, EXP.concatenateDcharAssign,
7286 ];
This page took 1.153709 seconds and 5 git commands to generate.