d: Merge upstream dmd, druntime 26f049fb26, phobos 330d6a4fd.
[official-gcc.git] / gcc / d / dmd / expression.d
blob9477867e929472140453b6fde73983261d88cc57
1 /**
2 * Defines the bulk of the classes which represent the AST at the expression level.
4 * Specification: ($LINK2 https://dlang.org/spec/expression.html, Expressions)
6 * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved
7 * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
8 * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
9 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/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
14 module dmd.expression;
16 import core.stdc.stdarg;
17 import core.stdc.stdio;
18 import core.stdc.string;
20 import dmd.aggregate;
21 import dmd.aliasthis;
22 import dmd.arrayop;
23 import dmd.arraytypes;
24 import dmd.astenums;
25 import dmd.ast_node;
26 import dmd.gluelayer;
27 import dmd.constfold;
28 import dmd.ctfeexpr;
29 import dmd.ctorflow;
30 import dmd.dcast;
31 import dmd.dclass;
32 import dmd.declaration;
33 import dmd.delegatize;
34 import dmd.dimport;
35 import dmd.dinterpret;
36 import dmd.dmodule;
37 import dmd.dscope;
38 import dmd.dstruct;
39 import dmd.dsymbol;
40 import dmd.dsymbolsem;
41 import dmd.dtemplate;
42 import dmd.errors;
43 import dmd.escape;
44 import dmd.expressionsem;
45 import dmd.func;
46 import dmd.globals;
47 import dmd.hdrgen;
48 import dmd.id;
49 import dmd.identifier;
50 import dmd.init;
51 import dmd.inline;
52 import dmd.location;
53 import dmd.mtype;
54 import dmd.nspace;
55 import dmd.objc;
56 import dmd.opover;
57 import dmd.optimize;
58 import dmd.postordervisitor;
59 import dmd.root.complex;
60 import dmd.root.ctfloat;
61 import dmd.root.filename;
62 import dmd.common.outbuffer;
63 import dmd.root.optional;
64 import dmd.root.rmem;
65 import dmd.root.rootobject;
66 import dmd.root.string;
67 import dmd.root.utf;
68 import dmd.safe;
69 import dmd.sideeffect;
70 import dmd.target;
71 import dmd.tokens;
72 import dmd.typesem;
73 import dmd.visitor;
75 enum LOGSEMANTIC = false;
77 void emplaceExp(T : Expression, Args...)(void* p, Args args)
79 static if (__VERSION__ < 2099)
80 const init = typeid(T).initializer;
81 else
82 const init = __traits(initSymbol, T);
83 p[0 .. __traits(classInstanceSize, T)] = init[];
84 (cast(T)p).__ctor(args);
87 void emplaceExp(T : UnionExp)(T* p, Expression e)
89 memcpy(p, cast(void*)e, e.size);
92 /// Return value for `checkModifiable`
93 enum Modifiable
95 /// Not modifiable
96 no,
97 /// Modifiable (the type is mutable)
98 yes,
99 /// Modifiable because it is initialization
100 initialization,
103 * Specifies how the checkModify deals with certain situations
105 enum ModifyFlags
107 /// Issue error messages on invalid modifications of the variable
108 none,
109 /// No errors are emitted for invalid modifications
110 noError = 0x1,
111 /// The modification occurs for a subfield of the current variable
112 fieldAssign = 0x2,
115 /****************************************
116 * Find the first non-comma expression.
117 * Params:
118 * e = Expressions connected by commas
119 * Returns:
120 * left-most non-comma expression
122 inout(Expression) firstComma(inout Expression e)
124 Expression ex = cast()e;
125 while (ex.op == EXP.comma)
126 ex = (cast(CommaExp)ex).e1;
127 return cast(inout)ex;
131 /****************************************
132 * Find the last non-comma expression.
133 * Params:
134 * e = Expressions connected by commas
135 * Returns:
136 * right-most non-comma expression
139 inout(Expression) lastComma(inout Expression e)
141 Expression ex = cast()e;
142 while (ex.op == EXP.comma)
143 ex = (cast(CommaExp)ex).e2;
144 return cast(inout)ex;
148 /*****************************************
149 * Determine if `this` is available by walking up the enclosing
150 * scopes until a function is found.
152 * Params:
153 * sc = where to start looking for the enclosing function
154 * Returns:
155 * Found function if it satisfies `isThis()`, otherwise `null`
157 FuncDeclaration hasThis(Scope* sc)
159 //printf("hasThis()\n");
160 Dsymbol p = sc.parent;
161 while (p && p.isTemplateMixin())
162 p = p.parent;
163 FuncDeclaration fdthis = p ? p.isFuncDeclaration() : null;
164 //printf("fdthis = %p, '%s'\n", fdthis, fdthis ? fdthis.toChars() : "");
166 // Go upwards until we find the enclosing member function
167 FuncDeclaration fd = fdthis;
168 while (1)
170 if (!fd)
172 return null;
174 if (!fd.isNested() || fd.isThis() || (fd.hasDualContext() && fd.isMember2()))
175 break;
177 Dsymbol parent = fd.parent;
178 while (1)
180 if (!parent)
181 return null;
182 TemplateInstance ti = parent.isTemplateInstance();
183 if (ti)
184 parent = ti.parent;
185 else
186 break;
188 fd = parent.isFuncDeclaration();
191 if (!fd.isThis() && !(fd.hasDualContext() && fd.isMember2()))
193 return null;
196 assert(fd.vthis);
197 return fd;
201 /***********************************
202 * Determine if a `this` is needed to access `d`.
203 * Params:
204 * sc = context
205 * d = declaration to check
206 * Returns:
207 * true means a `this` is needed
209 bool isNeedThisScope(Scope* sc, Declaration d)
211 if (sc.intypeof == 1)
212 return false;
214 AggregateDeclaration ad = d.isThis();
215 if (!ad)
216 return false;
217 //printf("d = %s, ad = %s\n", d.toChars(), ad.toChars());
219 for (Dsymbol s = sc.parent; s; s = s.toParentLocal())
221 //printf("\ts = %s %s, toParent2() = %p\n", s.kind(), s.toChars(), s.toParent2());
222 if (AggregateDeclaration ad2 = s.isAggregateDeclaration())
224 if (ad2 == ad)
225 return false;
226 else if (ad2.isNested())
227 continue;
228 else
229 return true;
231 if (FuncDeclaration f = s.isFuncDeclaration())
233 if (f.isMemberLocal())
234 break;
237 return true;
240 /******************************
241 * check e is exp.opDispatch!(tiargs) or not
242 * It's used to switch to UFCS the semantic analysis path
244 bool isDotOpDispatch(Expression e)
246 if (auto dtie = e.isDotTemplateInstanceExp())
247 return dtie.ti.name == Id.opDispatch;
248 return false;
251 /****************************************
252 * Expand tuples in-place.
254 * Example:
255 * When there's a call `f(10, pair: AliasSeq!(20, 30), single: 40)`, the input is:
256 * `exps = [10, (20, 30), 40]`
257 * `names = [null, "pair", "single"]`
258 * The arrays will be modified to:
259 * `exps = [10, 20, 30, 40]`
260 * `names = [null, "pair", null, "single"]`
262 * Params:
263 * exps = array of Expressions
264 * names = optional array of names corresponding to Expressions
266 extern (C++) void expandTuples(Expressions* exps, Identifiers* names = null)
268 //printf("expandTuples()\n");
269 if (exps is null)
270 return;
272 if (names)
274 if (exps.length != names.length)
276 printf("exps.length = %d, names.length = %d\n", cast(int) exps.length, cast(int) names.length);
277 printf("exps = %s, names = %s\n", exps.toChars(), names.toChars());
278 if (exps.length > 0)
279 printf("%s\n", (*exps)[0].loc.toChars());
280 assert(0);
284 // At `index`, a tuple of length `length` is expanded. Insert corresponding nulls in `names`.
285 void expandNames(size_t index, size_t length)
287 if (names)
289 if (length == 0)
291 names.remove(index);
292 return;
294 foreach (i; 1 .. length)
296 names.insert(index + i, cast(Identifier) null);
301 for (size_t i = 0; i < exps.length; i++)
303 Expression arg = (*exps)[i];
304 if (!arg)
305 continue;
307 // Look for tuple with 0 members
308 if (auto e = arg.isTypeExp())
310 if (auto tt = e.type.toBasetype().isTypeTuple())
312 if (!tt.arguments || tt.arguments.length == 0)
314 exps.remove(i);
315 expandNames(i, 0);
316 if (i == exps.length)
317 return;
319 else // Expand a TypeTuple
321 exps.remove(i);
322 auto texps = new Expressions(tt.arguments.length);
323 foreach (j, a; *tt.arguments)
324 (*texps)[j] = new TypeExp(e.loc, a.type);
325 exps.insert(i, texps);
326 expandNames(i, texps.length);
328 i--;
329 continue;
333 // Inline expand all the tuples
334 while (arg.op == EXP.tuple)
336 TupleExp te = cast(TupleExp)arg;
337 exps.remove(i); // remove arg
338 exps.insert(i, te.exps); // replace with tuple contents
339 expandNames(i, te.exps.length);
340 if (i == exps.length)
341 return; // empty tuple, no more arguments
342 (*exps)[i] = Expression.combine(te.e0, (*exps)[i]);
343 arg = (*exps)[i];
348 /****************************************
349 * Expand alias this tuples.
351 TupleDeclaration isAliasThisTuple(Expression e)
353 if (!e.type)
354 return null;
356 Type t = e.type.toBasetype();
357 while (true)
359 if (Dsymbol s = t.toDsymbol(null))
361 if (auto ad = s.isAggregateDeclaration())
363 s = ad.aliasthis ? ad.aliasthis.sym : null;
364 if (s && s.isVarDeclaration())
366 TupleDeclaration td = s.isVarDeclaration().toAlias().isTupleDeclaration();
367 if (td && td.isexp)
368 return td;
370 if (Type att = t.aliasthisOf())
372 t = att;
373 continue;
377 return null;
381 int expandAliasThisTuples(Expressions* exps, size_t starti = 0)
383 if (!exps || exps.length == 0)
384 return -1;
386 for (size_t u = starti; u < exps.length; u++)
388 Expression exp = (*exps)[u];
389 if (TupleDeclaration td = exp.isAliasThisTuple)
391 exps.remove(u);
392 size_t i;
393 td.foreachVar((s)
395 auto d = s.isDeclaration();
396 auto e = new DotVarExp(exp.loc, exp, d);
397 assert(d.type);
398 e.type = d.type;
399 exps.insert(u + i, e);
400 ++i;
402 version (none)
404 printf("expansion ->\n");
405 foreach (e; exps)
407 printf("\texps[%d] e = %s %s\n", i, EXPtoString(e.op), e.toChars());
410 return cast(int)u;
413 return -1;
416 /****************************************
417 * If `s` is a function template, i.e. the only member of a template
418 * and that member is a function, return that template.
419 * Params:
420 * s = symbol that might be a function template
421 * Returns:
422 * template for that function, otherwise null
424 TemplateDeclaration getFuncTemplateDecl(Dsymbol s)
426 FuncDeclaration f = s.isFuncDeclaration();
427 if (f && f.parent)
429 if (auto ti = f.parent.isTemplateInstance())
431 if (!ti.isTemplateMixin() && ti.tempdecl)
433 auto td = ti.tempdecl.isTemplateDeclaration();
434 if (td.onemember && td.ident == f.ident)
436 return td;
441 return null;
444 /************************************************
445 * If we want the value of this expression, but do not want to call
446 * the destructor on it.
448 Expression valueNoDtor(Expression e)
450 auto ex = lastComma(e);
452 if (auto ce = ex.isCallExp())
454 /* The struct value returned from the function is transferred
455 * so do not call the destructor on it.
456 * Recognize:
457 * ((S _ctmp = S.init), _ctmp).this(...)
458 * and make sure the destructor is not called on _ctmp
459 * BUG: if ex is a CommaExp, we should go down the right side.
461 if (auto dve = ce.e1.isDotVarExp())
463 if (dve.var.isCtorDeclaration())
465 // It's a constructor call
466 if (auto comma = dve.e1.isCommaExp())
468 if (auto ve = comma.e2.isVarExp())
470 VarDeclaration ctmp = ve.var.isVarDeclaration();
471 if (ctmp)
473 ctmp.storage_class |= STC.nodtor;
474 assert(!ce.isLvalue());
481 else if (auto ve = ex.isVarExp())
483 auto vtmp = ve.var.isVarDeclaration();
484 if (vtmp && (vtmp.storage_class & STC.rvalue))
486 vtmp.storage_class |= STC.nodtor;
489 return e;
492 /*********************************************
493 * If e is an instance of a struct, and that struct has a copy constructor,
494 * rewrite e as:
495 * (tmp = e),tmp
496 * Input:
497 * sc = just used to specify the scope of created temporary variable
498 * destinationType = the type of the object on which the copy constructor is called;
499 * may be null if the struct defines a postblit
501 private Expression callCpCtor(Scope* sc, Expression e, Type destinationType)
503 if (auto ts = e.type.baseElemOf().isTypeStruct())
505 StructDeclaration sd = ts.sym;
506 if (sd.postblit || sd.hasCopyCtor)
508 /* Create a variable tmp, and replace the argument e with:
509 * (tmp = e),tmp
510 * and let AssignExp() handle the construction.
511 * This is not the most efficient, ideally tmp would be constructed
512 * directly onto the stack.
514 auto tmp = copyToTemp(STC.rvalue, "__copytmp", e);
515 if (sd.hasCopyCtor && destinationType)
517 // https://issues.dlang.org/show_bug.cgi?id=22619
518 // If the destination type is inout we can preserve it
519 // only if inside an inout function; if we are not inside
520 // an inout function, then we will preserve the type of
521 // the source
522 if (destinationType.hasWild && !(sc.func.storage_class & STC.wild))
523 tmp.type = e.type;
524 else
525 tmp.type = destinationType;
527 tmp.storage_class |= STC.nodtor;
528 tmp.dsymbolSemantic(sc);
529 Expression de = new DeclarationExp(e.loc, tmp);
530 Expression ve = new VarExp(e.loc, tmp);
531 de.type = Type.tvoid;
532 ve.type = e.type;
533 return Expression.combine(de, ve);
536 return e;
539 /************************************************
540 * Handle the postblit call on lvalue, or the move of rvalue.
542 * Params:
543 * sc = the scope where the expression is encountered
544 * e = the expression the needs to be moved or copied (source)
545 * t = if the struct defines a copy constructor, the type of the destination
547 * Returns:
548 * The expression that copy constructs or moves the value.
550 extern (D) Expression doCopyOrMove(Scope *sc, Expression e, Type t = null)
552 if (auto ce = e.isCondExp())
554 ce.e1 = doCopyOrMove(sc, ce.e1);
555 ce.e2 = doCopyOrMove(sc, ce.e2);
557 else
559 e = e.isLvalue() ? callCpCtor(sc, e, t) : valueNoDtor(e);
561 return e;
564 /****************************************************************/
565 /* A type meant as a union of all the Expression types,
566 * to serve essentially as a Variant that will sit on the stack
567 * during CTFE to reduce memory consumption.
569 extern (C++) struct UnionExp
571 // yes, default constructor does nothing
572 extern (D) this(Expression e)
574 memcpy(&this, cast(void*)e, e.size);
577 /* Extract pointer to Expression
579 extern (C++) Expression exp() return
581 return cast(Expression)&u;
584 /* Convert to an allocated Expression
586 extern (C++) Expression copy()
588 Expression e = exp();
589 //if (e.size > sizeof(u)) printf("%s\n", EXPtoString(e.op).ptr);
590 assert(e.size <= u.sizeof);
591 switch (e.op)
593 case EXP.cantExpression: return CTFEExp.cantexp;
594 case EXP.voidExpression: return CTFEExp.voidexp;
595 case EXP.break_: return CTFEExp.breakexp;
596 case EXP.continue_: return CTFEExp.continueexp;
597 case EXP.goto_: return CTFEExp.gotoexp;
598 default: return e.copy();
602 private:
603 // Ensure that the union is suitably aligned.
604 align(8) union __AnonStruct__u
606 char[__traits(classInstanceSize, Expression)] exp;
607 char[__traits(classInstanceSize, IntegerExp)] integerexp;
608 char[__traits(classInstanceSize, ErrorExp)] errorexp;
609 char[__traits(classInstanceSize, RealExp)] realexp;
610 char[__traits(classInstanceSize, ComplexExp)] complexexp;
611 char[__traits(classInstanceSize, SymOffExp)] symoffexp;
612 char[__traits(classInstanceSize, StringExp)] stringexp;
613 char[__traits(classInstanceSize, ArrayLiteralExp)] arrayliteralexp;
614 char[__traits(classInstanceSize, AssocArrayLiteralExp)] assocarrayliteralexp;
615 char[__traits(classInstanceSize, StructLiteralExp)] structliteralexp;
616 char[__traits(classInstanceSize, CompoundLiteralExp)] compoundliteralexp;
617 char[__traits(classInstanceSize, NullExp)] nullexp;
618 char[__traits(classInstanceSize, DotVarExp)] dotvarexp;
619 char[__traits(classInstanceSize, AddrExp)] addrexp;
620 char[__traits(classInstanceSize, IndexExp)] indexexp;
621 char[__traits(classInstanceSize, SliceExp)] sliceexp;
622 char[__traits(classInstanceSize, VectorExp)] vectorexp;
625 __AnonStruct__u u;
628 /********************************
629 * Test to see if two reals are the same.
630 * Regard NaN's as equivalent.
631 * Regard +0 and -0 as different.
632 * Params:
633 * x1 = first operand
634 * x2 = second operand
635 * Returns:
636 * true if x1 is x2
637 * else false
639 bool RealIdentical(real_t x1, real_t x2)
641 return (CTFloat.isNaN(x1) && CTFloat.isNaN(x2)) || CTFloat.isIdentical(x1, x2);
644 /************************ TypeDotIdExp ************************************/
645 /* Things like:
646 * int.size
647 * foo.size
648 * (foo).size
649 * cast(foo).size
651 DotIdExp typeDotIdExp(const ref Loc loc, Type type, Identifier ident)
653 return new DotIdExp(loc, new TypeExp(loc, type), ident);
656 /***************************************************
657 * Given an Expression, find the variable it really is.
659 * For example, `a[index]` is really `a`, and `s.f` is really `s`.
660 * Params:
661 * e = Expression to look at
662 * Returns:
663 * variable if there is one, null if not
665 VarDeclaration expToVariable(Expression e)
667 while (1)
669 switch (e.op)
671 case EXP.variable:
672 return (cast(VarExp)e).var.isVarDeclaration();
674 case EXP.dotVariable:
675 e = (cast(DotVarExp)e).e1;
676 continue;
678 case EXP.index:
680 IndexExp ei = cast(IndexExp)e;
681 e = ei.e1;
682 Type ti = e.type.toBasetype();
683 if (ti.ty == Tsarray)
684 continue;
685 return null;
688 case EXP.slice:
690 SliceExp ei = cast(SliceExp)e;
691 e = ei.e1;
692 Type ti = e.type.toBasetype();
693 if (ti.ty == Tsarray)
694 continue;
695 return null;
698 case EXP.this_:
699 case EXP.super_:
700 return (cast(ThisExp)e).var.isVarDeclaration();
702 // Temporaries for rvalues that need destruction
703 // are of form: (T s = rvalue, s). For these cases
704 // we can just return var declaration of `s`. However,
705 // this is intentionally not calling `Expression.extractLast`
706 // because at this point we cannot infer the var declaration
707 // of more complex generated comma expressions such as the
708 // one for the array append hook.
709 case EXP.comma:
711 if (auto ve = e.isCommaExp().e2.isVarExp())
712 return ve.var.isVarDeclaration();
714 return null;
716 default:
717 return null;
722 enum OwnedBy : ubyte
724 code, // normal code expression in AST
725 ctfe, // value expression for CTFE
726 cache, // constant value cached for CTFE
729 enum WANTvalue = 0; // default
730 enum WANTexpand = 1; // expand const/immutable variables if possible
732 /***********************************************************
733 * https://dlang.org/spec/expression.html#expression
735 extern (C++) abstract class Expression : ASTNode
737 Type type; // !=null means that semantic() has been run
738 Loc loc; // file location
739 const EXP op; // to minimize use of dynamic_cast
741 extern (D) this(const ref Loc loc, EXP op) scope
743 //printf("Expression::Expression(op = %d) this = %p\n", op, this);
744 this.loc = loc;
745 this.op = op;
748 /// Returns: class instance size of this expression (implemented manually because `extern(C++)`)
749 final size_t size() nothrow @nogc pure @safe const { return expSize[op]; }
751 static void _init()
753 CTFEExp.cantexp = new CTFEExp(EXP.cantExpression);
754 CTFEExp.voidexp = new CTFEExp(EXP.voidExpression);
755 CTFEExp.breakexp = new CTFEExp(EXP.break_);
756 CTFEExp.continueexp = new CTFEExp(EXP.continue_);
757 CTFEExp.gotoexp = new CTFEExp(EXP.goto_);
758 CTFEExp.showcontext = new CTFEExp(EXP.showCtfeContext);
762 * Deinitializes the global state of the compiler.
764 * This can be used to restore the state set by `_init` to its original
765 * state.
767 static void deinitialize()
769 CTFEExp.cantexp = CTFEExp.cantexp.init;
770 CTFEExp.voidexp = CTFEExp.voidexp.init;
771 CTFEExp.breakexp = CTFEExp.breakexp.init;
772 CTFEExp.continueexp = CTFEExp.continueexp.init;
773 CTFEExp.gotoexp = CTFEExp.gotoexp.init;
774 CTFEExp.showcontext = CTFEExp.showcontext.init;
777 /*********************************
778 * Does *not* do a deep copy.
780 final Expression copy()
782 Expression e;
783 if (!size)
785 debug
787 fprintf(stderr, "No expression copy for: %s\n", toChars());
788 printf("op = %d\n", op);
790 assert(0);
793 // memory never freed, so can use the faster bump-pointer-allocation
794 e = cast(Expression)allocmemory(size);
795 //printf("Expression::copy(op = %d) e = %p\n", op, e);
796 return cast(Expression)memcpy(cast(void*)e, cast(void*)this, size);
799 Expression syntaxCopy()
801 //printf("Expression::syntaxCopy()\n");
802 //print();
803 return copy();
806 // kludge for template.isExpression()
807 override final DYNCAST dyncast() const
809 return DYNCAST.expression;
812 override const(char)* toChars() const
814 OutBuffer buf;
815 HdrGenState hgs;
816 toCBuffer(this, &buf, &hgs);
817 return buf.extractChars();
820 static if (__VERSION__ < 2092)
822 final void error(const(char)* format, ...) const
824 if (type != Type.terror)
826 va_list ap;
827 va_start(ap, format);
828 .verror(loc, format, ap);
829 va_end(ap);
833 final void errorSupplemental(const(char)* format, ...)
835 if (type == Type.terror)
836 return;
838 va_list ap;
839 va_start(ap, format);
840 .verrorSupplemental(loc, format, ap);
841 va_end(ap);
844 final void warning(const(char)* format, ...) const
846 if (type != Type.terror)
848 va_list ap;
849 va_start(ap, format);
850 .vwarning(loc, format, ap);
851 va_end(ap);
855 final void deprecation(const(char)* format, ...) const
857 if (type != Type.terror)
859 va_list ap;
860 va_start(ap, format);
861 .vdeprecation(loc, format, ap);
862 va_end(ap);
866 else
868 pragma(printf) final void error(const(char)* format, ...) const
870 if (type != Type.terror)
872 va_list ap;
873 va_start(ap, format);
874 .verror(loc, format, ap);
875 va_end(ap);
879 pragma(printf) final void errorSupplemental(const(char)* format, ...)
881 if (type == Type.terror)
882 return;
884 va_list ap;
885 va_start(ap, format);
886 .verrorSupplemental(loc, format, ap);
887 va_end(ap);
890 pragma(printf) final void warning(const(char)* format, ...) const
892 if (type != Type.terror)
894 va_list ap;
895 va_start(ap, format);
896 .vwarning(loc, format, ap);
897 va_end(ap);
901 pragma(printf) final void deprecation(const(char)* format, ...) const
903 if (type != Type.terror)
905 va_list ap;
906 va_start(ap, format);
907 .vdeprecation(loc, format, ap);
908 va_end(ap);
913 /**********************************
914 * Combine e1 and e2 by CommaExp if both are not NULL.
916 extern (D) static Expression combine(Expression e1, Expression e2)
918 if (e1)
920 if (e2)
922 e1 = new CommaExp(e1.loc, e1, e2);
923 e1.type = e2.type;
926 else
927 e1 = e2;
928 return e1;
931 extern (D) static Expression combine(Expression e1, Expression e2, Expression e3)
933 return combine(combine(e1, e2), e3);
936 extern (D) static Expression combine(Expression e1, Expression e2, Expression e3, Expression e4)
938 return combine(combine(e1, e2), combine(e3, e4));
941 /**********************************
942 * If 'e' is a tree of commas, returns the rightmost expression
943 * by stripping off it from the tree. The remained part of the tree
944 * is returned via e0.
945 * Otherwise 'e' is directly returned and e0 is set to NULL.
947 extern (D) static Expression extractLast(Expression e, out Expression e0)
949 if (e.op != EXP.comma)
951 return e;
954 CommaExp ce = cast(CommaExp)e;
955 if (ce.e2.op != EXP.comma)
957 e0 = ce.e1;
958 return ce.e2;
960 else
962 e0 = e;
964 Expression* pce = &ce.e2;
965 while ((cast(CommaExp)(*pce)).e2.op == EXP.comma)
967 pce = &(cast(CommaExp)(*pce)).e2;
969 assert((*pce).op == EXP.comma);
970 ce = cast(CommaExp)(*pce);
971 *pce = ce.e1;
973 return ce.e2;
977 extern (D) static Expressions* arraySyntaxCopy(Expressions* exps)
979 Expressions* a = null;
980 if (exps)
982 a = new Expressions(exps.length);
983 foreach (i, e; *exps)
985 (*a)[i] = e ? e.syntaxCopy() : null;
988 return a;
991 dinteger_t toInteger()
993 //printf("Expression %s\n", EXPtoString(op).ptr);
994 error("integer constant expression expected instead of `%s`", toChars());
995 return 0;
998 uinteger_t toUInteger()
1000 //printf("Expression %s\n", EXPtoString(op).ptr);
1001 return cast(uinteger_t)toInteger();
1004 real_t toReal()
1006 error("floating point constant expression expected instead of `%s`", toChars());
1007 return CTFloat.zero;
1010 real_t toImaginary()
1012 error("floating point constant expression expected instead of `%s`", toChars());
1013 return CTFloat.zero;
1016 complex_t toComplex()
1018 error("floating point constant expression expected instead of `%s`", toChars());
1019 return complex_t(CTFloat.zero);
1022 StringExp toStringExp()
1024 return null;
1027 /***************************************
1028 * Return !=0 if expression is an lvalue.
1030 bool isLvalue()
1032 return false;
1035 /*******************************
1036 * Give error if we're not an lvalue.
1037 * If we can, convert expression to be an lvalue.
1039 Expression toLvalue(Scope* sc, Expression e)
1041 if (!e)
1042 e = this;
1043 else if (!loc.isValid())
1044 loc = e.loc;
1046 if (e.op == EXP.type)
1047 error("`%s` is a `%s` definition and cannot be modified", e.type.toChars(), e.type.kind());
1048 else
1049 error("`%s` is not an lvalue and cannot be modified", e.toChars());
1051 return ErrorExp.get();
1054 Expression modifiableLvalue(Scope* sc, Expression e)
1056 //printf("Expression::modifiableLvalue() %s, type = %s\n", toChars(), type.toChars());
1057 // See if this expression is a modifiable lvalue (i.e. not const)
1058 if (checkModifiable(this, sc) == Modifiable.yes)
1060 assert(type);
1061 if (!type.isMutable())
1063 if (auto dve = this.isDotVarExp())
1065 if (isNeedThisScope(sc, dve.var))
1066 for (Dsymbol s = sc.func; s; s = s.toParentLocal())
1068 FuncDeclaration ff = s.isFuncDeclaration();
1069 if (!ff)
1070 break;
1071 if (!ff.type.isMutable)
1073 error("cannot modify `%s` in `%s` function", toChars(), MODtoChars(type.mod));
1074 return ErrorExp.get();
1078 error("cannot modify `%s` expression `%s`", MODtoChars(type.mod), toChars());
1079 return ErrorExp.get();
1081 else if (!type.isAssignable())
1083 error("cannot modify struct instance `%s` of type `%s` because it contains `const` or `immutable` members",
1084 toChars(), type.toChars());
1085 return ErrorExp.get();
1088 return toLvalue(sc, e);
1091 final Expression implicitCastTo(Scope* sc, Type t)
1093 return .implicitCastTo(this, sc, t);
1096 final MATCH implicitConvTo(Type t)
1098 return .implicitConvTo(this, t);
1101 final Expression castTo(Scope* sc, Type t)
1103 return .castTo(this, sc, t);
1106 /****************************************
1107 * Resolve __FILE__, __LINE__, __MODULE__, __FUNCTION__, __PRETTY_FUNCTION__, __FILE_FULL_PATH__ to loc.
1109 Expression resolveLoc(const ref Loc loc, Scope* sc)
1111 this.loc = loc;
1112 return this;
1115 /****************************************
1116 * Check that the expression has a valid type.
1117 * If not, generates an error "... has no type".
1118 * Returns:
1119 * true if the expression is not valid.
1120 * Note:
1121 * When this function returns true, `checkValue()` should also return true.
1123 bool checkType()
1125 return false;
1128 /****************************************
1129 * Check that the expression has a valid value.
1130 * If not, generates an error "... has no value".
1131 * Returns:
1132 * true if the expression is not valid or has void type.
1134 bool checkValue()
1136 if (type && type.toBasetype().ty == Tvoid)
1138 error("expression `%s` is `void` and has no value", toChars());
1139 //print(); assert(0);
1140 if (!global.gag)
1141 type = Type.terror;
1142 return true;
1144 return false;
1147 extern (D) final bool checkScalar()
1149 if (op == EXP.error)
1150 return true;
1151 if (type.toBasetype().ty == Terror)
1152 return true;
1153 if (!type.isscalar())
1155 error("`%s` is not a scalar, it is a `%s`", toChars(), type.toChars());
1156 return true;
1158 return checkValue();
1161 extern (D) final bool checkNoBool()
1163 if (op == EXP.error)
1164 return true;
1165 if (type.toBasetype().ty == Terror)
1166 return true;
1167 if (type.toBasetype().ty == Tbool)
1169 error("operation not allowed on `bool` `%s`", toChars());
1170 return true;
1172 return false;
1175 extern (D) final bool checkIntegral()
1177 if (op == EXP.error)
1178 return true;
1179 if (type.toBasetype().ty == Terror)
1180 return true;
1181 if (!type.isintegral())
1183 error("`%s` is not of integral type, it is a `%s`", toChars(), type.toChars());
1184 return true;
1186 return checkValue();
1189 extern (D) final bool checkArithmetic()
1191 if (op == EXP.error)
1192 return true;
1193 if (type.toBasetype().ty == Terror)
1194 return true;
1195 if (!type.isintegral() && !type.isfloating())
1197 error("`%s` is not of arithmetic type, it is a `%s`", toChars(), type.toChars());
1198 return true;
1200 return checkValue();
1203 final bool checkDeprecated(Scope* sc, Dsymbol s)
1205 return s.checkDeprecated(loc, sc);
1208 extern (D) final bool checkDisabled(Scope* sc, Dsymbol s)
1210 if (auto d = s.isDeclaration())
1212 return d.checkDisabled(loc, sc);
1215 return false;
1218 /*********************************************
1219 * Calling function f.
1220 * Check the purity, i.e. if we're in a pure function
1221 * we can only call other pure functions.
1222 * Returns true if error occurs.
1224 extern (D) final bool checkPurity(Scope* sc, FuncDeclaration f)
1226 if (!sc.func)
1227 return false;
1228 if (sc.func == f)
1229 return false;
1230 if (sc.intypeof == 1)
1231 return false;
1232 if (sc.flags & (SCOPE.ctfe | SCOPE.debug_))
1233 return false;
1235 // If the call has a pure parent, then the called func must be pure.
1236 if (!f.isPure() && checkImpure(sc, loc, null, f))
1238 error("`pure` %s `%s` cannot call impure %s `%s`",
1239 sc.func.kind(), sc.func.toPrettyChars(), f.kind(),
1240 f.toPrettyChars());
1242 if (!f.isDtorDeclaration())
1243 errorSupplementalInferredAttr(f, /*max depth*/ 10, /*deprecation*/ false, STC.pure_);
1245 checkOverriddenDtor(sc, f, dd => dd.type.toTypeFunction().purity != PURE.impure, "impure");
1246 return true;
1248 return false;
1252 * Checks whether `f` is a generated `DtorDeclaration` that hides a user-defined one
1253 * which passes `check` while `f` doesn't (e.g. when the user defined dtor is pure but
1254 * the generated dtor is not).
1255 * In that case the method will identify and print all members causing the attribute
1256 * missmatch.
1258 * Params:
1259 * sc = scope
1260 * f = potential `DtorDeclaration`
1261 * check = current check (e.g. whether it's pure)
1262 * checkName = the kind of check (e.g. `"pure"`)
1264 extern (D) final void checkOverriddenDtor(Scope* sc, FuncDeclaration f,
1265 scope bool function(DtorDeclaration) check, const string checkName
1267 auto dd = f.isDtorDeclaration();
1268 if (!dd || !dd.isGenerated())
1269 return;
1271 // DtorDeclaration without parents should fail at an earlier stage
1272 auto ad = cast(AggregateDeclaration) f.toParent2();
1273 assert(ad);
1275 if (ad.userDtors.length)
1277 if (!check(ad.userDtors[0])) // doesn't match check (e.g. is impure as well)
1278 return;
1280 // Sanity check
1281 assert(!check(ad.fieldDtor));
1284 dd.loc.errorSupplemental("%s`%s.~this` is %.*s because of the following field's destructors:",
1285 dd.isGenerated() ? "generated " : "".ptr,
1286 ad.toChars,
1287 cast(int) checkName.length, checkName.ptr);
1289 // Search for the offending fields
1290 foreach (field; ad.fields)
1292 // Only structs may define automatically called destructors
1293 auto ts = field.type.isTypeStruct();
1294 if (!ts)
1296 // But they might be part of a static array
1297 auto ta = field.type.isTypeSArray();
1298 if (!ta)
1299 continue;
1301 ts = ta.baseElemOf().isTypeStruct();
1302 if (!ts)
1303 continue;
1306 auto fieldSym = ts.toDsymbol(sc);
1307 assert(fieldSym); // Resolving ts must succeed because missing defs. should error before
1309 auto fieldSd = fieldSym.isStructDeclaration();
1310 assert(fieldSd); // ts is a TypeStruct, this would imply a malformed ASR
1312 if (fieldSd.dtor && !check(fieldSd.dtor))
1314 field.loc.errorSupplemental(" - %s %s", field.type.toChars(), field.toChars());
1316 if (fieldSd.dtor.isGenerated())
1317 checkOverriddenDtor(sc, fieldSd.dtor, check, checkName);
1318 else
1319 fieldSd.dtor.loc.errorSupplemental(" %.*s `%s.~this` is declared here",
1320 cast(int) checkName.length, checkName.ptr, fieldSd.toChars());
1325 /*******************************************
1326 * Accessing variable v.
1327 * Check for purity and safety violations.
1328 * Returns true if error occurs.
1330 extern (D) final bool checkPurity(Scope* sc, VarDeclaration v)
1332 //printf("v = %s %s\n", v.type.toChars(), v.toChars());
1333 /* Look for purity and safety violations when accessing variable v
1334 * from current function.
1336 if (!sc.func)
1337 return false;
1338 if (sc.intypeof == 1)
1339 return false; // allow violations inside typeof(expression)
1340 if (sc.flags & (SCOPE.ctfe | SCOPE.debug_))
1341 return false; // allow violations inside compile-time evaluated expressions and debug conditionals
1342 if (v.ident == Id.ctfe)
1343 return false; // magic variable never violates pure and safe
1344 if (v.isImmutable())
1345 return false; // always safe and pure to access immutables...
1346 if (v.isConst() && !v.isReference() && (v.isDataseg() || v.isParameter()) && v.type.implicitConvTo(v.type.immutableOf()))
1347 return false; // or const global/parameter values which have no mutable indirections
1348 if (v.storage_class & STC.manifest)
1349 return false; // ...or manifest constants
1351 // accessing empty structs is pure
1352 // https://issues.dlang.org/show_bug.cgi?id=18694
1353 // https://issues.dlang.org/show_bug.cgi?id=21464
1354 // https://issues.dlang.org/show_bug.cgi?id=23589
1355 if (v.type.ty == Tstruct)
1357 StructDeclaration sd = (cast(TypeStruct)v.type).sym;
1358 if (sd.members) // not opaque
1360 if (sd.semanticRun >= PASS.semanticdone)
1361 sd.determineSize(v.loc);
1362 if (sd.hasNoFields)
1363 return false;
1367 bool err = false;
1368 if (v.isDataseg())
1370 // https://issues.dlang.org/show_bug.cgi?id=7533
1371 // Accessing implicit generated __gate is pure.
1372 if (v.ident == Id.gate)
1373 return false;
1375 if (checkImpure(sc, loc, "`pure` %s `%s` cannot access mutable static data `%s`", v))
1377 error("`pure` %s `%s` cannot access mutable static data `%s`",
1378 sc.func.kind(), sc.func.toPrettyChars(), v.toChars());
1379 err = true;
1382 else
1384 /* Given:
1385 * void f() {
1386 * int fx;
1387 * pure void g() {
1388 * int gx;
1389 * /+pure+/ void h() {
1390 * int hx;
1391 * /+pure+/ void i() { }
1395 * i() can modify hx and gx but not fx
1398 Dsymbol vparent = v.toParent2();
1399 for (Dsymbol s = sc.func; !err && s; s = s.toParentP(vparent))
1401 if (s == vparent)
1402 break;
1404 if (AggregateDeclaration ad = s.isAggregateDeclaration())
1406 if (ad.isNested())
1407 continue;
1408 break;
1410 FuncDeclaration ff = s.isFuncDeclaration();
1411 if (!ff)
1412 break;
1413 if (ff.isNested() || ff.isThis())
1415 if (ff.type.isImmutable() ||
1416 ff.type.isShared() && !MODimplicitConv(ff.type.mod, v.type.mod))
1418 OutBuffer ffbuf;
1419 OutBuffer vbuf;
1420 MODMatchToBuffer(&ffbuf, ff.type.mod, v.type.mod);
1421 MODMatchToBuffer(&vbuf, v.type.mod, ff.type.mod);
1422 error("%s%s `%s` cannot access %sdata `%s`",
1423 ffbuf.peekChars(), ff.kind(), ff.toPrettyChars(), vbuf.peekChars(), v.toChars());
1424 err = true;
1425 break;
1427 continue;
1429 break;
1433 /* Do not allow safe functions to access __gshared data
1435 if (v.storage_class & STC.gshared)
1437 if (sc.setUnsafe(false, this.loc,
1438 "`@safe` function `%s` cannot access `__gshared` data `%s`", sc.func, v))
1440 err = true;
1444 return err;
1448 Check if sc.func is impure or can be made impure.
1449 Returns true on error, i.e. if sc.func is pure and cannot be made impure.
1451 private static bool checkImpure(Scope* sc, Loc loc, const(char)* fmt, RootObject arg0)
1453 return sc.func && (isRootTraitsCompilesScope(sc)
1454 ? sc.func.isPureBypassingInference() >= PURE.weak
1455 : sc.func.setImpure(loc, fmt, arg0));
1458 /*********************************************
1459 * Calling function f.
1460 * Check the safety, i.e. if we're in a @safe function
1461 * we can only call @safe or @trusted functions.
1462 * Returns true if error occurs.
1464 extern (D) final bool checkSafety(Scope* sc, FuncDeclaration f)
1466 if (sc.func == f)
1467 return false;
1468 if (sc.intypeof == 1)
1469 return false;
1470 if (sc.flags & SCOPE.debug_)
1471 return false;
1472 if ((sc.flags & SCOPE.ctfe) && sc.func)
1473 return false;
1475 if (!sc.func)
1477 if (sc.varDecl && !f.safetyInprocess && !f.isSafe() && !f.isTrusted())
1479 if (sc.varDecl.storage_class & STC.safe)
1481 error("`@safe` variable `%s` cannot be initialized by calling `@system` function `%s`",
1482 sc.varDecl.toChars(), f.toChars());
1483 return true;
1485 else
1487 sc.varDecl.storage_class |= STC.system;
1490 return false;
1493 if (!f.isSafe() && !f.isTrusted())
1495 if (isRootTraitsCompilesScope(sc) ? sc.func.isSafeBypassingInference() : sc.func.setUnsafeCall(f))
1497 if (!loc.isValid()) // e.g. implicitly generated dtor
1498 loc = sc.func.loc;
1500 const prettyChars = f.toPrettyChars();
1501 error("`@safe` %s `%s` cannot call `@system` %s `%s`",
1502 sc.func.kind(), sc.func.toPrettyChars(), f.kind(),
1503 prettyChars);
1504 if (!f.isDtorDeclaration)
1505 errorSupplementalInferredAttr(f, /*max depth*/ 10, /*deprecation*/ false, STC.safe);
1506 .errorSupplemental(f.loc, "`%s` is declared here", prettyChars);
1508 checkOverriddenDtor(sc, f, dd => dd.type.toTypeFunction().trust > TRUST.system, "@system");
1510 return true;
1513 else if (f.isSafe() && f.safetyViolation)
1515 // for dip1000 by default transition, print deprecations for calling functions that will become `@system`
1516 if (sc.func.isSafeBypassingInference())
1518 .deprecation(this.loc, "`@safe` function `%s` calling `%s`", sc.func.toChars(), f.toChars());
1519 errorSupplementalInferredAttr(f, 10, true, STC.safe);
1521 else if (!sc.func.safetyViolation)
1523 import dmd.func : AttributeViolation;
1524 sc.func.safetyViolation = new AttributeViolation(this.loc, null, f, null, null);
1527 return false;
1530 /*********************************************
1531 * Calling function f.
1532 * Check the @nogc-ness, i.e. if we're in a @nogc function
1533 * we can only call other @nogc functions.
1534 * Returns true if error occurs.
1536 extern (D) final bool checkNogc(Scope* sc, FuncDeclaration f)
1538 if (!sc.func)
1539 return false;
1540 if (sc.func == f)
1541 return false;
1542 if (sc.intypeof == 1)
1543 return false;
1544 if (sc.flags & (SCOPE.ctfe | SCOPE.debug_))
1545 return false;
1546 /* The original expression (`new S(...)`) will be verified instead. This
1547 * is to keep errors related to the original code and not the lowering.
1549 if (f.ident == Id._d_newitemT)
1550 return false;
1552 if (!f.isNogc())
1554 if (isRootTraitsCompilesScope(sc) ? sc.func.isNogcBypassingInference() : sc.func.setGCCall(f))
1556 if (loc.linnum == 0) // e.g. implicitly generated dtor
1557 loc = sc.func.loc;
1559 // Lowered non-@nogc'd hooks will print their own error message inside of nogc.d (NOGCVisitor.visit(CallExp e)),
1560 // so don't print anything to avoid double error messages.
1561 if (!(f.ident == Id._d_HookTraceImpl || f.ident == Id._d_arraysetlengthT
1562 || f.ident == Id._d_arrayappendT || f.ident == Id._d_arrayappendcTX
1563 || f.ident == Id._d_arraycatnTX || f.ident == Id._d_newclassT))
1565 error("`@nogc` %s `%s` cannot call non-@nogc %s `%s`",
1566 sc.func.kind(), sc.func.toPrettyChars(), f.kind(), f.toPrettyChars());
1568 if (!f.isDtorDeclaration)
1569 f.errorSupplementalInferredAttr(/*max depth*/ 10, /*deprecation*/ false, STC.nogc);
1572 checkOverriddenDtor(sc, f, dd => dd.type.toTypeFunction().isnogc, "non-@nogc");
1574 return true;
1577 return false;
1580 /********************************************
1581 * Check that the postblit is callable if t is an array of structs.
1582 * Returns true if error happens.
1584 extern (D) final bool checkPostblit(Scope* sc, Type t)
1586 if (auto ts = t.baseElemOf().isTypeStruct())
1588 if (global.params.useTypeInfo && Type.dtypeinfo)
1590 // https://issues.dlang.org/show_bug.cgi?id=11395
1591 // Require TypeInfo generation for array concatenation
1592 semanticTypeInfo(sc, t);
1595 StructDeclaration sd = ts.sym;
1596 if (sd.postblit)
1598 if (sd.postblit.checkDisabled(loc, sc))
1599 return true;
1601 //checkDeprecated(sc, sd.postblit); // necessary?
1602 checkPurity(sc, sd.postblit);
1603 checkSafety(sc, sd.postblit);
1604 checkNogc(sc, sd.postblit);
1605 //checkAccess(sd, loc, sc, sd.postblit); // necessary?
1606 return false;
1609 return false;
1612 extern (D) final bool checkRightThis(Scope* sc)
1614 if (op == EXP.error)
1615 return true;
1616 if (op == EXP.variable && type.ty != Terror)
1618 VarExp ve = cast(VarExp)this;
1619 if (isNeedThisScope(sc, ve.var))
1621 //printf("checkRightThis sc.intypeof = %d, ad = %p, func = %p, fdthis = %p\n",
1622 // sc.intypeof, sc.getStructClassScope(), func, fdthis);
1623 error("need `this` for `%s` of type `%s`", ve.var.toChars(), ve.var.type.toChars());
1624 return true;
1627 return false;
1630 /*******************************
1631 * Check whether the expression allows RMW operations, error with rmw operator diagnostic if not.
1632 * ex is the RHS expression, or NULL if ++/-- is used (for diagnostics)
1633 * Returns true if error occurs.
1635 extern (D) final bool checkReadModifyWrite(EXP rmwOp, Expression ex = null)
1637 //printf("Expression::checkReadModifyWrite() %s %s", toChars(), ex ? ex.toChars() : "");
1638 if (!type || !type.isShared() || type.isTypeStruct() || type.isTypeClass())
1639 return false;
1641 // atomicOp uses opAssign (+=/-=) rather than opOp (++/--) for the CT string literal.
1642 switch (rmwOp)
1644 case EXP.plusPlus:
1645 case EXP.prePlusPlus:
1646 rmwOp = EXP.addAssign;
1647 break;
1648 case EXP.minusMinus:
1649 case EXP.preMinusMinus:
1650 rmwOp = EXP.minAssign;
1651 break;
1652 default:
1653 break;
1656 error("read-modify-write operations are not allowed for `shared` variables");
1657 errorSupplemental("Use `core.atomic.atomicOp!\"%s\"(%s, %s)` instead",
1658 EXPtoString(rmwOp).ptr, toChars(), ex ? ex.toChars() : "1");
1659 return true;
1662 /************************************************
1663 * Destructors are attached to VarDeclarations.
1664 * Hence, if expression returns a temp that needs a destructor,
1665 * make sure and create a VarDeclaration for that temp.
1667 Expression addDtorHook(Scope* sc)
1669 return this;
1672 /******************************
1673 * Take address of expression.
1675 final Expression addressOf()
1677 //printf("Expression::addressOf()\n");
1678 debug
1680 assert(op == EXP.error || isLvalue());
1682 Expression e = new AddrExp(loc, this, type.pointerTo());
1683 return e;
1686 /******************************
1687 * If this is a reference, dereference it.
1689 final Expression deref()
1691 //printf("Expression::deref()\n");
1692 // type could be null if forward referencing an 'auto' variable
1693 if (type)
1694 if (auto tr = type.isTypeReference())
1696 Expression e = new PtrExp(loc, this, tr.next);
1697 return e;
1699 return this;
1702 final Expression optimize(int result, bool keepLvalue = false)
1704 return Expression_optimize(this, result, keepLvalue);
1707 // Entry point for CTFE.
1708 // A compile-time result is required. Give an error if not possible
1709 final Expression ctfeInterpret()
1711 return .ctfeInterpret(this);
1714 final int isConst()
1716 return .isConst(this);
1719 /******
1720 * Identical, not just equal. I.e. NaNs with different bit patterns are not identical
1722 bool isIdentical(const Expression e) const
1724 return equals(e);
1728 /// Statically evaluate this expression to a `bool` if possible
1729 /// Returns: an optional thath either contains the value or is empty
1730 Optional!bool toBool()
1732 return typeof(return)();
1735 bool hasCode()
1737 return true;
1740 final pure inout nothrow @nogc @safe
1742 inout(IntegerExp) isIntegerExp() { return op == EXP.int64 ? cast(typeof(return))this : null; }
1743 inout(ErrorExp) isErrorExp() { return op == EXP.error ? cast(typeof(return))this : null; }
1744 inout(VoidInitExp) isVoidInitExp() { return op == EXP.void_ ? cast(typeof(return))this : null; }
1745 inout(RealExp) isRealExp() { return op == EXP.float64 ? cast(typeof(return))this : null; }
1746 inout(ComplexExp) isComplexExp() { return op == EXP.complex80 ? cast(typeof(return))this : null; }
1747 inout(IdentifierExp) isIdentifierExp() { return op == EXP.identifier ? cast(typeof(return))this : null; }
1748 inout(DollarExp) isDollarExp() { return op == EXP.dollar ? cast(typeof(return))this : null; }
1749 inout(DsymbolExp) isDsymbolExp() { return op == EXP.dSymbol ? cast(typeof(return))this : null; }
1750 inout(ThisExp) isThisExp() { return op == EXP.this_ ? cast(typeof(return))this : null; }
1751 inout(SuperExp) isSuperExp() { return op == EXP.super_ ? cast(typeof(return))this : null; }
1752 inout(NullExp) isNullExp() { return op == EXP.null_ ? cast(typeof(return))this : null; }
1753 inout(StringExp) isStringExp() { return op == EXP.string_ ? cast(typeof(return))this : null; }
1754 inout(TupleExp) isTupleExp() { return op == EXP.tuple ? cast(typeof(return))this : null; }
1755 inout(ArrayLiteralExp) isArrayLiteralExp() { return op == EXP.arrayLiteral ? cast(typeof(return))this : null; }
1756 inout(AssocArrayLiteralExp) isAssocArrayLiteralExp() { return op == EXP.assocArrayLiteral ? cast(typeof(return))this : null; }
1757 inout(StructLiteralExp) isStructLiteralExp() { return op == EXP.structLiteral ? cast(typeof(return))this : null; }
1758 inout(CompoundLiteralExp) isCompoundLiteralExp() { return op == EXP.compoundLiteral ? cast(typeof(return))this : null; }
1759 inout(TypeExp) isTypeExp() { return op == EXP.type ? cast(typeof(return))this : null; }
1760 inout(ScopeExp) isScopeExp() { return op == EXP.scope_ ? cast(typeof(return))this : null; }
1761 inout(TemplateExp) isTemplateExp() { return op == EXP.template_ ? cast(typeof(return))this : null; }
1762 inout(NewExp) isNewExp() { return op == EXP.new_ ? cast(typeof(return))this : null; }
1763 inout(NewAnonClassExp) isNewAnonClassExp() { return op == EXP.newAnonymousClass ? cast(typeof(return))this : null; }
1764 inout(SymOffExp) isSymOffExp() { return op == EXP.symbolOffset ? cast(typeof(return))this : null; }
1765 inout(VarExp) isVarExp() { return op == EXP.variable ? cast(typeof(return))this : null; }
1766 inout(OverExp) isOverExp() { return op == EXP.overloadSet ? cast(typeof(return))this : null; }
1767 inout(FuncExp) isFuncExp() { return op == EXP.function_ ? cast(typeof(return))this : null; }
1768 inout(DeclarationExp) isDeclarationExp() { return op == EXP.declaration ? cast(typeof(return))this : null; }
1769 inout(TypeidExp) isTypeidExp() { return op == EXP.typeid_ ? cast(typeof(return))this : null; }
1770 inout(TraitsExp) isTraitsExp() { return op == EXP.traits ? cast(typeof(return))this : null; }
1771 inout(HaltExp) isHaltExp() { return op == EXP.halt ? cast(typeof(return))this : null; }
1772 inout(IsExp) isExp() { return op == EXP.is_ ? cast(typeof(return))this : null; }
1773 inout(MixinExp) isMixinExp() { return op == EXP.mixin_ ? cast(typeof(return))this : null; }
1774 inout(ImportExp) isImportExp() { return op == EXP.import_ ? cast(typeof(return))this : null; }
1775 inout(AssertExp) isAssertExp() { return op == EXP.assert_ ? cast(typeof(return))this : null; }
1776 inout(ThrowExp) isThrowExp() { return op == EXP.throw_ ? cast(typeof(return))this : null; }
1777 inout(DotIdExp) isDotIdExp() { return op == EXP.dotIdentifier ? cast(typeof(return))this : null; }
1778 inout(DotTemplateExp) isDotTemplateExp() { return op == EXP.dotTemplateDeclaration ? cast(typeof(return))this : null; }
1779 inout(DotVarExp) isDotVarExp() { return op == EXP.dotVariable ? cast(typeof(return))this : null; }
1780 inout(DotTemplateInstanceExp) isDotTemplateInstanceExp() { return op == EXP.dotTemplateInstance ? cast(typeof(return))this : null; }
1781 inout(DelegateExp) isDelegateExp() { return op == EXP.delegate_ ? cast(typeof(return))this : null; }
1782 inout(DotTypeExp) isDotTypeExp() { return op == EXP.dotType ? cast(typeof(return))this : null; }
1783 inout(CallExp) isCallExp() { return op == EXP.call ? cast(typeof(return))this : null; }
1784 inout(AddrExp) isAddrExp() { return op == EXP.address ? cast(typeof(return))this : null; }
1785 inout(PtrExp) isPtrExp() { return op == EXP.star ? cast(typeof(return))this : null; }
1786 inout(NegExp) isNegExp() { return op == EXP.negate ? cast(typeof(return))this : null; }
1787 inout(UAddExp) isUAddExp() { return op == EXP.uadd ? cast(typeof(return))this : null; }
1788 inout(ComExp) isComExp() { return op == EXP.tilde ? cast(typeof(return))this : null; }
1789 inout(NotExp) isNotExp() { return op == EXP.not ? cast(typeof(return))this : null; }
1790 inout(DeleteExp) isDeleteExp() { return op == EXP.delete_ ? cast(typeof(return))this : null; }
1791 inout(CastExp) isCastExp() { return op == EXP.cast_ ? cast(typeof(return))this : null; }
1792 inout(VectorExp) isVectorExp() { return op == EXP.vector ? cast(typeof(return))this : null; }
1793 inout(VectorArrayExp) isVectorArrayExp() { return op == EXP.vectorArray ? cast(typeof(return))this : null; }
1794 inout(SliceExp) isSliceExp() { return op == EXP.slice ? cast(typeof(return))this : null; }
1795 inout(ArrayLengthExp) isArrayLengthExp() { return op == EXP.arrayLength ? cast(typeof(return))this : null; }
1796 inout(ArrayExp) isArrayExp() { return op == EXP.array ? cast(typeof(return))this : null; }
1797 inout(DotExp) isDotExp() { return op == EXP.dot ? cast(typeof(return))this : null; }
1798 inout(CommaExp) isCommaExp() { return op == EXP.comma ? cast(typeof(return))this : null; }
1799 inout(IntervalExp) isIntervalExp() { return op == EXP.interval ? cast(typeof(return))this : null; }
1800 inout(DelegatePtrExp) isDelegatePtrExp() { return op == EXP.delegatePointer ? cast(typeof(return))this : null; }
1801 inout(DelegateFuncptrExp) isDelegateFuncptrExp() { return op == EXP.delegateFunctionPointer ? cast(typeof(return))this : null; }
1802 inout(IndexExp) isIndexExp() { return op == EXP.index ? cast(typeof(return))this : null; }
1803 inout(PostExp) isPostExp() { return (op == EXP.plusPlus || op == EXP.minusMinus) ? cast(typeof(return))this : null; }
1804 inout(PreExp) isPreExp() { return (op == EXP.prePlusPlus || op == EXP.preMinusMinus) ? cast(typeof(return))this : null; }
1805 inout(AssignExp) isAssignExp() { return op == EXP.assign ? cast(typeof(return))this : null; }
1806 inout(LoweredAssignExp) isLoweredAssignExp() { return op == EXP.loweredAssignExp ? cast(typeof(return))this : null; }
1807 inout(ConstructExp) isConstructExp() { return op == EXP.construct ? cast(typeof(return))this : null; }
1808 inout(BlitExp) isBlitExp() { return op == EXP.blit ? cast(typeof(return))this : null; }
1809 inout(AddAssignExp) isAddAssignExp() { return op == EXP.addAssign ? cast(typeof(return))this : null; }
1810 inout(MinAssignExp) isMinAssignExp() { return op == EXP.minAssign ? cast(typeof(return))this : null; }
1811 inout(MulAssignExp) isMulAssignExp() { return op == EXP.mulAssign ? cast(typeof(return))this : null; }
1813 inout(DivAssignExp) isDivAssignExp() { return op == EXP.divAssign ? cast(typeof(return))this : null; }
1814 inout(ModAssignExp) isModAssignExp() { return op == EXP.modAssign ? cast(typeof(return))this : null; }
1815 inout(AndAssignExp) isAndAssignExp() { return op == EXP.andAssign ? cast(typeof(return))this : null; }
1816 inout(OrAssignExp) isOrAssignExp() { return op == EXP.orAssign ? cast(typeof(return))this : null; }
1817 inout(XorAssignExp) isXorAssignExp() { return op == EXP.xorAssign ? cast(typeof(return))this : null; }
1818 inout(PowAssignExp) isPowAssignExp() { return op == EXP.powAssign ? cast(typeof(return))this : null; }
1820 inout(ShlAssignExp) isShlAssignExp() { return op == EXP.leftShiftAssign ? cast(typeof(return))this : null; }
1821 inout(ShrAssignExp) isShrAssignExp() { return op == EXP.rightShiftAssign ? cast(typeof(return))this : null; }
1822 inout(UshrAssignExp) isUshrAssignExp() { return op == EXP.unsignedRightShiftAssign ? cast(typeof(return))this : null; }
1824 inout(CatAssignExp) isCatAssignExp() { return op == EXP.concatenateAssign
1825 ? cast(typeof(return))this
1826 : null; }
1828 inout(CatElemAssignExp) isCatElemAssignExp() { return op == EXP.concatenateElemAssign
1829 ? cast(typeof(return))this
1830 : null; }
1832 inout(CatDcharAssignExp) isCatDcharAssignExp() { return op == EXP.concatenateDcharAssign
1833 ? cast(typeof(return))this
1834 : null; }
1836 inout(AddExp) isAddExp() { return op == EXP.add ? cast(typeof(return))this : null; }
1837 inout(MinExp) isMinExp() { return op == EXP.min ? cast(typeof(return))this : null; }
1838 inout(CatExp) isCatExp() { return op == EXP.concatenate ? cast(typeof(return))this : null; }
1839 inout(MulExp) isMulExp() { return op == EXP.mul ? cast(typeof(return))this : null; }
1840 inout(DivExp) isDivExp() { return op == EXP.div ? cast(typeof(return))this : null; }
1841 inout(ModExp) isModExp() { return op == EXP.mod ? cast(typeof(return))this : null; }
1842 inout(PowExp) isPowExp() { return op == EXP.pow ? cast(typeof(return))this : null; }
1843 inout(ShlExp) isShlExp() { return op == EXP.leftShift ? cast(typeof(return))this : null; }
1844 inout(ShrExp) isShrExp() { return op == EXP.rightShift ? cast(typeof(return))this : null; }
1845 inout(UshrExp) isUshrExp() { return op == EXP.unsignedRightShift ? cast(typeof(return))this : null; }
1846 inout(AndExp) isAndExp() { return op == EXP.and ? cast(typeof(return))this : null; }
1847 inout(OrExp) isOrExp() { return op == EXP.or ? cast(typeof(return))this : null; }
1848 inout(XorExp) isXorExp() { return op == EXP.xor ? cast(typeof(return))this : null; }
1849 inout(LogicalExp) isLogicalExp() { return (op == EXP.andAnd || op == EXP.orOr) ? cast(typeof(return))this : null; }
1850 //inout(CmpExp) isCmpExp() { return op == EXP. ? cast(typeof(return))this : null; }
1851 inout(InExp) isInExp() { return op == EXP.in_ ? cast(typeof(return))this : null; }
1852 inout(RemoveExp) isRemoveExp() { return op == EXP.remove ? cast(typeof(return))this : null; }
1853 inout(EqualExp) isEqualExp() { return (op == EXP.equal || op == EXP.notEqual) ? cast(typeof(return))this : null; }
1854 inout(IdentityExp) isIdentityExp() { return (op == EXP.identity || op == EXP.notIdentity) ? cast(typeof(return))this : null; }
1855 inout(CondExp) isCondExp() { return op == EXP.question ? cast(typeof(return))this : null; }
1856 inout(GenericExp) isGenericExp() { return op == EXP._Generic ? cast(typeof(return))this : null; }
1857 inout(DefaultInitExp) isDefaultInitExp() { return isDefaultInitOp(op) ? cast(typeof(return))this: null; }
1858 inout(FileInitExp) isFileInitExp() { return (op == EXP.file || op == EXP.fileFullPath) ? cast(typeof(return))this : null; }
1859 inout(LineInitExp) isLineInitExp() { return op == EXP.line ? cast(typeof(return))this : null; }
1860 inout(ModuleInitExp) isModuleInitExp() { return op == EXP.moduleString ? cast(typeof(return))this : null; }
1861 inout(FuncInitExp) isFuncInitExp() { return op == EXP.functionString ? cast(typeof(return))this : null; }
1862 inout(PrettyFuncInitExp) isPrettyFuncInitExp() { return op == EXP.prettyFunction ? cast(typeof(return))this : null; }
1863 inout(ObjcClassReferenceExp) isObjcClassReferenceExp() { return op == EXP.objcClassReference ? cast(typeof(return))this : null; }
1864 inout(ClassReferenceExp) isClassReferenceExp() { return op == EXP.classReference ? cast(typeof(return))this : null; }
1865 inout(ThrownExceptionExp) isThrownExceptionExp() { return op == EXP.thrownException ? cast(typeof(return))this : null; }
1867 inout(UnaExp) isUnaExp() pure inout nothrow @nogc
1869 return exptab[op] & EXPFLAGS.unary ? cast(typeof(return))this : null;
1872 inout(BinExp) isBinExp() pure inout nothrow @nogc
1874 return exptab[op] & EXPFLAGS.binary ? cast(typeof(return))this : null;
1877 inout(BinAssignExp) isBinAssignExp() pure inout nothrow @nogc
1879 return exptab[op] & EXPFLAGS.binaryAssign ? cast(typeof(return))this : null;
1883 override void accept(Visitor v)
1885 v.visit(this);
1889 /***********************************************************
1890 * A compile-time known integer value
1892 extern (C++) final class IntegerExp : Expression
1894 private dinteger_t value;
1896 extern (D) this(const ref Loc loc, dinteger_t value, Type type)
1898 super(loc, EXP.int64);
1899 //printf("IntegerExp(value = %lld, type = '%s')\n", value, type ? type.toChars() : "");
1900 assert(type);
1901 if (!type.isscalar())
1903 //printf("%s, loc = %d\n", toChars(), loc.linnum);
1904 if (type.ty != Terror)
1905 error("integral constant must be scalar type, not `%s`", type.toChars());
1906 type = Type.terror;
1908 this.type = type;
1909 this.value = normalize(type.toBasetype().ty, value);
1912 extern (D) this(dinteger_t value)
1914 super(Loc.initial, EXP.int64);
1915 this.type = Type.tint32;
1916 this.value = cast(int)value;
1919 static IntegerExp create(const ref Loc loc, dinteger_t value, Type type)
1921 return new IntegerExp(loc, value, type);
1924 // Same as create, but doesn't allocate memory.
1925 static void emplace(UnionExp* pue, const ref Loc loc, dinteger_t value, Type type)
1927 emplaceExp!(IntegerExp)(pue, loc, value, type);
1930 override bool equals(const RootObject o) const
1932 if (this == o)
1933 return true;
1934 if (auto ne = (cast(Expression)o).isIntegerExp())
1936 if (type.toHeadMutable().equals(ne.type.toHeadMutable()) && value == ne.value)
1938 return true;
1941 return false;
1944 override dinteger_t toInteger()
1946 // normalize() is necessary until we fix all the paints of 'type'
1947 return value = normalize(type.toBasetype().ty, value);
1950 override real_t toReal()
1952 // normalize() is necessary until we fix all the paints of 'type'
1953 const ty = type.toBasetype().ty;
1954 const val = normalize(ty, value);
1955 value = val;
1956 return (ty == Tuns64)
1957 ? real_t(cast(ulong)val)
1958 : real_t(cast(long)val);
1961 override real_t toImaginary()
1963 return CTFloat.zero;
1966 override complex_t toComplex()
1968 return complex_t(toReal());
1971 override Optional!bool toBool()
1973 bool r = toInteger() != 0;
1974 return typeof(return)(r);
1977 override Expression toLvalue(Scope* sc, Expression e)
1979 if (!e)
1980 e = this;
1981 else if (!loc.isValid())
1982 loc = e.loc;
1983 e.error("cannot modify constant `%s`", e.toChars());
1984 return ErrorExp.get();
1987 override void accept(Visitor v)
1989 v.visit(this);
1992 dinteger_t getInteger()
1994 return value;
1997 void setInteger(dinteger_t value)
1999 this.value = normalize(type.toBasetype().ty, value);
2002 extern (D) static dinteger_t normalize(TY ty, dinteger_t value)
2004 /* 'Normalize' the value of the integer to be in range of the type
2006 dinteger_t result;
2007 switch (ty)
2009 case Tbool:
2010 result = (value != 0);
2011 break;
2013 case Tint8:
2014 result = cast(byte)value;
2015 break;
2017 case Tchar:
2018 case Tuns8:
2019 result = cast(ubyte)value;
2020 break;
2022 case Tint16:
2023 result = cast(short)value;
2024 break;
2026 case Twchar:
2027 case Tuns16:
2028 result = cast(ushort)value;
2029 break;
2031 case Tint32:
2032 result = cast(int)value;
2033 break;
2035 case Tdchar:
2036 case Tuns32:
2037 result = cast(uint)value;
2038 break;
2040 case Tint64:
2041 result = cast(long)value;
2042 break;
2044 case Tuns64:
2045 result = cast(ulong)value;
2046 break;
2048 case Tpointer:
2049 if (target.ptrsize == 8)
2050 goto case Tuns64;
2051 if (target.ptrsize == 4)
2052 goto case Tuns32;
2053 if (target.ptrsize == 2)
2054 goto case Tuns16;
2055 assert(0);
2057 default:
2058 break;
2060 return result;
2063 override IntegerExp syntaxCopy()
2065 return this;
2069 * Use this instead of creating new instances for commonly used literals
2070 * such as 0 or 1.
2072 * Parameters:
2073 * v = The value of the expression
2074 * Returns:
2075 * A static instance of the expression, typed as `Tint32`.
2077 static IntegerExp literal(int v)()
2079 __gshared IntegerExp theConstant;
2080 if (!theConstant)
2081 theConstant = new IntegerExp(v);
2082 return theConstant;
2086 * Use this instead of creating new instances for commonly used bools.
2088 * Parameters:
2089 * b = The value of the expression
2090 * Returns:
2091 * A static instance of the expression, typed as `Type.tbool`.
2093 static IntegerExp createBool(bool b)
2095 __gshared IntegerExp trueExp, falseExp;
2096 if (!trueExp)
2098 trueExp = new IntegerExp(Loc.initial, 1, Type.tbool);
2099 falseExp = new IntegerExp(Loc.initial, 0, Type.tbool);
2101 return b ? trueExp : falseExp;
2105 /***********************************************************
2106 * Use this expression for error recovery.
2108 * It should behave as a 'sink' to prevent further cascaded error messages.
2110 extern (C++) final class ErrorExp : Expression
2112 private extern (D) this()
2114 super(Loc.initial, EXP.error);
2115 type = Type.terror;
2118 static ErrorExp get ()
2120 if (errorexp is null)
2121 errorexp = new ErrorExp();
2123 if (global.errors == 0 && global.gaggedErrors == 0)
2125 /* Unfortunately, errors can still leak out of gagged errors,
2126 * and we need to set the error count to prevent bogus code
2127 * generation. At least give a message.
2129 .error(Loc.initial, "unknown, please file report on issues.dlang.org");
2132 return errorexp;
2135 override Expression toLvalue(Scope* sc, Expression e)
2137 return this;
2140 override void accept(Visitor v)
2142 v.visit(this);
2145 extern (C++) __gshared ErrorExp errorexp; // handy shared value
2149 /***********************************************************
2150 * An uninitialized value,
2151 * generated from void initializers.
2153 * https://dlang.org/spec/declaration.html#void_init
2155 extern (C++) final class VoidInitExp : Expression
2157 VarDeclaration var; /// the variable from where the void value came from, null if not known
2158 /// Useful for error messages
2160 extern (D) this(VarDeclaration var)
2162 super(var.loc, EXP.void_);
2163 this.var = var;
2164 this.type = var.type;
2167 override const(char)* toChars() const
2169 return "void";
2172 override void accept(Visitor v)
2174 v.visit(this);
2179 /***********************************************************
2180 * A compile-time known floating point number
2182 extern (C++) final class RealExp : Expression
2184 real_t value;
2186 extern (D) this(const ref Loc loc, real_t value, Type type)
2188 super(loc, EXP.float64);
2189 //printf("RealExp::RealExp(%Lg)\n", value);
2190 this.value = value;
2191 this.type = type;
2194 static RealExp create(const ref Loc loc, real_t value, Type type)
2196 return new RealExp(loc, value, type);
2199 // Same as create, but doesn't allocate memory.
2200 static void emplace(UnionExp* pue, const ref Loc loc, real_t value, Type type)
2202 emplaceExp!(RealExp)(pue, loc, value, type);
2205 override bool equals(const RootObject o) const
2207 if (this == o)
2208 return true;
2209 if (auto ne = (cast(Expression)o).isRealExp())
2211 if (type.toHeadMutable().equals(ne.type.toHeadMutable()) && RealIdentical(value, ne.value))
2213 return true;
2216 return false;
2219 override bool isIdentical(const Expression e) const
2221 if (!equals(e))
2222 return false;
2223 return CTFloat.isIdentical(value, e.isRealExp().value);
2226 override dinteger_t toInteger()
2228 return cast(sinteger_t)toReal();
2231 override uinteger_t toUInteger()
2233 return cast(uinteger_t)toReal();
2236 override real_t toReal()
2238 return type.isreal() ? value : CTFloat.zero;
2241 override real_t toImaginary()
2243 return type.isreal() ? CTFloat.zero : value;
2246 override complex_t toComplex()
2248 return complex_t(toReal(), toImaginary());
2251 override Optional!bool toBool()
2253 return typeof(return)(!!value);
2256 override void accept(Visitor v)
2258 v.visit(this);
2262 /***********************************************************
2263 * A compile-time complex number (deprecated)
2265 extern (C++) final class ComplexExp : Expression
2267 complex_t value;
2269 extern (D) this(const ref Loc loc, complex_t value, Type type)
2271 super(loc, EXP.complex80);
2272 this.value = value;
2273 this.type = type;
2274 //printf("ComplexExp::ComplexExp(%s)\n", toChars());
2277 static ComplexExp create(const ref Loc loc, complex_t value, Type type)
2279 return new ComplexExp(loc, value, type);
2282 // Same as create, but doesn't allocate memory.
2283 static void emplace(UnionExp* pue, const ref Loc loc, complex_t value, Type type)
2285 emplaceExp!(ComplexExp)(pue, loc, value, type);
2288 override bool equals(const RootObject o) const
2290 if (this == o)
2291 return true;
2292 if (auto ne = (cast(Expression)o).isComplexExp())
2294 if (type.toHeadMutable().equals(ne.type.toHeadMutable()) && RealIdentical(creall(value), creall(ne.value)) && RealIdentical(cimagl(value), cimagl(ne.value)))
2296 return true;
2299 return false;
2302 override bool isIdentical(const Expression e) const
2304 if (!equals(e))
2305 return false;
2306 // equals() regards different NaN values as 'equals'
2307 auto c = e.isComplexExp();
2308 return CTFloat.isIdentical(creall(value), creall(c.value)) &&
2309 CTFloat.isIdentical(cimagl(value), cimagl(c.value));
2312 override dinteger_t toInteger()
2314 return cast(sinteger_t)toReal();
2317 override uinteger_t toUInteger()
2319 return cast(uinteger_t)toReal();
2322 override real_t toReal()
2324 return creall(value);
2327 override real_t toImaginary()
2329 return cimagl(value);
2332 override complex_t toComplex()
2334 return value;
2337 override Optional!bool toBool()
2339 return typeof(return)(!!value);
2342 override void accept(Visitor v)
2344 v.visit(this);
2348 /***********************************************************
2349 * An identifier in the context of an expression (as opposed to a declaration)
2351 * ---
2352 * int x; // VarDeclaration with Identifier
2353 * x++; // PostExp with IdentifierExp
2354 * ---
2356 extern (C++) class IdentifierExp : Expression
2358 Identifier ident;
2359 bool parens; // if it appears as (identifier)
2361 extern (D) this(const ref Loc loc, Identifier ident) scope
2363 super(loc, EXP.identifier);
2364 this.ident = ident;
2367 static IdentifierExp create(const ref Loc loc, Identifier ident)
2369 return new IdentifierExp(loc, ident);
2372 override final bool isLvalue()
2374 return true;
2377 override final Expression toLvalue(Scope* sc, Expression e)
2379 return this;
2382 override void accept(Visitor v)
2384 v.visit(this);
2388 /***********************************************************
2389 * The dollar operator used when indexing or slicing an array. E.g `a[$]`, `a[1 .. $]` etc.
2391 * https://dlang.org/spec/arrays.html#array-length
2393 extern (C++) final class DollarExp : IdentifierExp
2395 extern (D) this(const ref Loc loc)
2397 super(loc, Id.dollar);
2400 override void accept(Visitor v)
2402 v.visit(this);
2406 /***********************************************************
2407 * Won't be generated by parser.
2409 extern (C++) final class DsymbolExp : Expression
2411 Dsymbol s;
2412 bool hasOverloads;
2414 extern (D) this(const ref Loc loc, Dsymbol s, bool hasOverloads = true)
2416 super(loc, EXP.dSymbol);
2417 this.s = s;
2418 this.hasOverloads = hasOverloads;
2421 override bool isLvalue()
2423 return true;
2426 override Expression toLvalue(Scope* sc, Expression e)
2428 return this;
2431 override void accept(Visitor v)
2433 v.visit(this);
2437 /***********************************************************
2438 * https://dlang.org/spec/expression.html#this
2440 extern (C++) class ThisExp : Expression
2442 VarDeclaration var;
2444 extern (D) this(const ref Loc loc)
2446 super(loc, EXP.this_);
2447 //printf("ThisExp::ThisExp() loc = %d\n", loc.linnum);
2450 this(const ref Loc loc, const EXP tok)
2452 super(loc, tok);
2453 //printf("ThisExp::ThisExp() loc = %d\n", loc.linnum);
2456 override ThisExp syntaxCopy()
2458 auto r = cast(ThisExp) super.syntaxCopy();
2459 // require new semantic (possibly new `var` etc.)
2460 r.type = null;
2461 r.var = null;
2462 return r;
2465 override Optional!bool toBool()
2467 // `this` is never null (what about structs?)
2468 return typeof(return)(true);
2471 override bool isLvalue()
2473 return true;
2476 override Expression toLvalue(Scope* sc, Expression e)
2478 return this;
2481 override void accept(Visitor v)
2483 v.visit(this);
2487 /***********************************************************
2488 * https://dlang.org/spec/expression.html#super
2490 extern (C++) final class SuperExp : ThisExp
2492 extern (D) this(const ref Loc loc)
2494 super(loc, EXP.super_);
2497 override bool isLvalue()
2499 // Class `super` should be an rvalue
2500 return false;
2503 override Expression toLvalue(Scope* sc, Expression e)
2505 // Class `super` is an rvalue
2506 return Expression.toLvalue(sc, e);
2509 override void accept(Visitor v)
2511 v.visit(this);
2515 /***********************************************************
2516 * A compile-time known `null` value
2518 * https://dlang.org/spec/expression.html#null
2520 extern (C++) final class NullExp : Expression
2522 extern (D) this(const ref Loc loc, Type type = null) scope
2524 super(loc, EXP.null_);
2525 this.type = type;
2528 override bool equals(const RootObject o) const
2530 if (auto e = o.isExpression())
2532 if (e.op == EXP.null_ && type.equals(e.type))
2534 return true;
2537 return false;
2540 override Optional!bool toBool()
2542 // null in any type is false
2543 return typeof(return)(false);
2546 override StringExp toStringExp()
2548 if (implicitConvTo(Type.tstring))
2550 auto se = new StringExp(loc, (cast(char*)mem.xcalloc(1, 1))[0 .. 0]);
2551 se.type = Type.tstring;
2552 return se;
2554 return null;
2557 override void accept(Visitor v)
2559 v.visit(this);
2563 /***********************************************************
2564 * https://dlang.org/spec/expression.html#string_literals
2566 extern (C++) final class StringExp : Expression
2568 char postfix = NoPostfix; // 'c', 'w', 'd'
2569 OwnedBy ownedByCtfe = OwnedBy.code;
2570 private union
2572 char* string; // if sz == 1
2573 wchar* wstring; // if sz == 2
2574 dchar* dstring; // if sz == 4
2575 } // (const if ownedByCtfe == OwnedBy.code)
2576 size_t len; // number of code units
2577 ubyte sz = 1; // 1: char, 2: wchar, 4: dchar
2580 * Whether the string literal's type is fixed
2581 * Example:
2582 * ---
2583 * wstring x = "abc"; // OK, string literal is flexible
2584 * wstring y = cast(string) "abc"; // Error: type was committed after cast
2585 * ---
2587 bool committed;
2589 enum char NoPostfix = 0;
2591 extern (D) this(const ref Loc loc, const(void)[] string) scope
2593 super(loc, EXP.string_);
2594 this.string = cast(char*)string.ptr; // note that this.string should be const
2595 this.len = string.length;
2596 this.sz = 1; // work around LDC bug #1286
2599 extern (D) this(const ref Loc loc, const(void)[] string, size_t len, ubyte sz, char postfix = NoPostfix) scope
2601 super(loc, EXP.string_);
2602 this.string = cast(char*)string.ptr; // note that this.string should be const
2603 this.len = len;
2604 this.sz = sz;
2605 this.postfix = postfix;
2608 static StringExp create(const ref Loc loc, const(char)* s)
2610 return new StringExp(loc, s.toDString());
2613 static StringExp create(const ref Loc loc, const(void)* string, size_t len)
2615 return new StringExp(loc, string[0 .. len]);
2618 // Same as create, but doesn't allocate memory.
2619 static void emplace(UnionExp* pue, const ref Loc loc, const(char)* s)
2621 emplaceExp!(StringExp)(pue, loc, s.toDString());
2624 extern (D) static void emplace(UnionExp* pue, const ref Loc loc, const(void)[] string)
2626 emplaceExp!(StringExp)(pue, loc, string);
2629 extern (D) static void emplace(UnionExp* pue, const ref Loc loc, const(void)[] string, size_t len, ubyte sz, char postfix)
2631 emplaceExp!(StringExp)(pue, loc, string, len, sz, postfix);
2634 override bool equals(const RootObject o) const
2636 //printf("StringExp::equals('%s') %s\n", o.toChars(), toChars());
2637 if (auto e = o.isExpression())
2639 if (auto se = e.isStringExp())
2641 return compare(se) == 0;
2644 return false;
2647 /**********************************
2648 * Return the number of code units the string would be if it were re-encoded
2649 * as tynto.
2650 * Params:
2651 * tynto = code unit type of the target encoding
2652 * Returns:
2653 * number of code units
2655 size_t numberOfCodeUnits(int tynto = 0) const
2657 int encSize;
2658 switch (tynto)
2660 case 0: return len;
2661 case Tchar: encSize = 1; break;
2662 case Twchar: encSize = 2; break;
2663 case Tdchar: encSize = 4; break;
2664 default:
2665 assert(0);
2667 if (sz == encSize)
2668 return len;
2670 size_t result = 0;
2671 dchar c;
2673 switch (sz)
2675 case 1:
2676 for (size_t u = 0; u < len;)
2678 if (const s = utf_decodeChar(string[0 .. len], u, c))
2680 error("%.*s", cast(int)s.length, s.ptr);
2681 return 0;
2683 result += utf_codeLength(encSize, c);
2685 break;
2687 case 2:
2688 for (size_t u = 0; u < len;)
2690 if (const s = utf_decodeWchar(wstring[0 .. len], u, c))
2692 error("%.*s", cast(int)s.length, s.ptr);
2693 return 0;
2695 result += utf_codeLength(encSize, c);
2697 break;
2699 case 4:
2700 foreach (u; 0 .. len)
2702 result += utf_codeLength(encSize, dstring[u]);
2704 break;
2706 default:
2707 assert(0);
2709 return result;
2712 /**********************************************
2713 * Write the contents of the string to dest.
2714 * Use numberOfCodeUnits() to determine size of result.
2715 * Params:
2716 * dest = destination
2717 * tyto = encoding type of the result
2718 * zero = add terminating 0
2720 void writeTo(void* dest, bool zero, int tyto = 0) const
2722 int encSize;
2723 switch (tyto)
2725 case 0: encSize = sz; break;
2726 case Tchar: encSize = 1; break;
2727 case Twchar: encSize = 2; break;
2728 case Tdchar: encSize = 4; break;
2729 default:
2730 assert(0);
2732 if (sz == encSize)
2734 memcpy(dest, string, len * sz);
2735 if (zero)
2736 memset(dest + len * sz, 0, sz);
2738 else
2739 assert(0);
2742 /*********************************************
2743 * Get the code unit at index i
2744 * Params:
2745 * i = index
2746 * Returns:
2747 * code unit at index i
2749 dchar getCodeUnit(size_t i) const pure
2751 assert(i < len);
2752 final switch (sz)
2754 case 1:
2755 return string[i];
2756 case 2:
2757 return wstring[i];
2758 case 4:
2759 return dstring[i];
2763 /*********************************************
2764 * Set the code unit at index i to c
2765 * Params:
2766 * i = index
2767 * c = code unit to set it to
2769 void setCodeUnit(size_t i, dchar c)
2771 assert(i < len);
2772 final switch (sz)
2774 case 1:
2775 string[i] = cast(char)c;
2776 break;
2777 case 2:
2778 wstring[i] = cast(wchar)c;
2779 break;
2780 case 4:
2781 dstring[i] = c;
2782 break;
2786 override StringExp toStringExp()
2788 return this;
2791 /****************************************
2792 * Convert string to char[].
2794 StringExp toUTF8(Scope* sc)
2796 if (sz != 1)
2798 // Convert to UTF-8 string
2799 committed = false;
2800 Expression e = castTo(sc, Type.tchar.arrayOf());
2801 e = e.optimize(WANTvalue);
2802 auto se = e.isStringExp();
2803 assert(se.sz == 1);
2804 return se;
2806 return this;
2810 * Compare two `StringExp` by length, then value
2812 * The comparison is not the usual C-style comparison as seen with
2813 * `strcmp` or `memcmp`, but instead first compare based on the length.
2814 * This allows both faster lookup and sorting when comparing sparse data.
2816 * This ordering scheme is relied on by the string-switching feature.
2817 * Code in Druntime's `core.internal.switch_` relies on this ordering
2818 * when doing a binary search among case statements.
2820 * Both `StringExp` should be of the same encoding.
2822 * Params:
2823 * se2 = String expression to compare `this` to
2825 * Returns:
2826 * `0` when `this` is equal to se2, a value greater than `0` if
2827 * `this` should be considered greater than `se2`,
2828 * and a value less than `0` if `this` is lesser than `se2`.
2830 int compare(const StringExp se2) const nothrow pure @nogc
2832 //printf("StringExp::compare()\n");
2833 const len1 = len;
2834 const len2 = se2.len;
2836 assert(this.sz == se2.sz, "Comparing string expressions of different sizes");
2837 //printf("sz = %d, len1 = %d, len2 = %d\n", sz, cast(int)len1, cast(int)len2);
2838 if (len1 == len2)
2840 switch (sz)
2842 case 1:
2843 return memcmp(string, se2.string, len1);
2845 case 2:
2847 wchar* s1 = cast(wchar*)string;
2848 wchar* s2 = cast(wchar*)se2.string;
2849 foreach (u; 0 .. len)
2851 if (s1[u] != s2[u])
2852 return s1[u] - s2[u];
2855 break;
2856 case 4:
2858 dchar* s1 = cast(dchar*)string;
2859 dchar* s2 = cast(dchar*)se2.string;
2860 foreach (u; 0 .. len)
2862 if (s1[u] != s2[u])
2863 return s1[u] - s2[u];
2866 break;
2867 default:
2868 assert(0);
2871 return cast(int)(len1 - len2);
2874 override Optional!bool toBool()
2876 // Keep the old behaviour for this refactoring
2877 // Should probably match language spec instead and check for length
2878 return typeof(return)(true);
2881 override bool isLvalue()
2883 /* string literal is rvalue in default, but
2884 * conversion to reference of static array is only allowed.
2886 return (type && type.toBasetype().ty == Tsarray);
2889 override Expression toLvalue(Scope* sc, Expression e)
2891 //printf("StringExp::toLvalue(%s) type = %s\n", toChars(), type ? type.toChars() : NULL);
2892 return (type && type.toBasetype().ty == Tsarray) ? this : Expression.toLvalue(sc, e);
2895 override Expression modifiableLvalue(Scope* sc, Expression e)
2897 error("cannot modify string literal `%s`", toChars());
2898 return ErrorExp.get();
2901 /********************************
2902 * Convert string contents to a 0 terminated string,
2903 * allocated by mem.xmalloc().
2905 extern (D) const(char)[] toStringz() const
2907 auto nbytes = len * sz;
2908 char* s = cast(char*)mem.xmalloc(nbytes + sz);
2909 writeTo(s, true);
2910 return s[0 .. nbytes];
2913 extern (D) const(char)[] peekString() const
2915 assert(sz == 1);
2916 return this.string[0 .. len];
2919 extern (D) const(wchar)[] peekWstring() const
2921 assert(sz == 2);
2922 return this.wstring[0 .. len];
2925 extern (D) const(dchar)[] peekDstring() const
2927 assert(sz == 4);
2928 return this.dstring[0 .. len];
2931 /*******************
2932 * Get a slice of the data.
2934 extern (D) const(ubyte)[] peekData() const
2936 return cast(const(ubyte)[])this.string[0 .. len * sz];
2939 /*******************
2940 * Borrow a slice of the data, so the caller can modify
2941 * it in-place (!)
2943 extern (D) ubyte[] borrowData()
2945 return cast(ubyte[])this.string[0 .. len * sz];
2948 /***********************
2949 * Set new string data.
2950 * `this` becomes the new owner of the data.
2952 extern (D) void setData(void* s, size_t len, ubyte sz)
2954 this.string = cast(char*)s;
2955 this.len = len;
2956 this.sz = sz;
2959 override void accept(Visitor v)
2961 v.visit(this);
2965 /***********************************************************
2966 * A sequence of expressions
2968 * ---
2969 * alias AliasSeq(T...) = T;
2970 * alias Tup = AliasSeq!(3, int, "abc");
2971 * ---
2973 extern (C++) final class TupleExp : Expression
2975 /* Tuple-field access may need to take out its side effect part.
2976 * For example:
2977 * foo().tupleof
2978 * is rewritten as:
2979 * (ref __tup = foo(); tuple(__tup.field0, __tup.field1, ...))
2980 * The declaration of temporary variable __tup will be stored in TupleExp.e0.
2982 Expression e0;
2984 Expressions* exps;
2986 extern (D) this(const ref Loc loc, Expression e0, Expressions* exps)
2988 super(loc, EXP.tuple);
2989 //printf("TupleExp(this = %p)\n", this);
2990 this.e0 = e0;
2991 this.exps = exps;
2994 extern (D) this(const ref Loc loc, Expressions* exps)
2996 super(loc, EXP.tuple);
2997 //printf("TupleExp(this = %p)\n", this);
2998 this.exps = exps;
3001 extern (D) this(const ref Loc loc, TupleDeclaration tup)
3003 super(loc, EXP.tuple);
3004 this.exps = new Expressions();
3006 this.exps.reserve(tup.objects.length);
3007 foreach (o; *tup.objects)
3009 if (Dsymbol s = getDsymbol(o))
3011 /* If tuple element represents a symbol, translate to DsymbolExp
3012 * to supply implicit 'this' if needed later.
3014 Expression e = new DsymbolExp(loc, s);
3015 this.exps.push(e);
3017 else if (auto eo = o.isExpression())
3019 auto e = eo.copy();
3020 e.loc = loc; // https://issues.dlang.org/show_bug.cgi?id=15669
3021 this.exps.push(e);
3023 else if (auto t = o.isType())
3025 Expression e = new TypeExp(loc, t);
3026 this.exps.push(e);
3028 else
3030 error("`%s` is not an expression", o.toChars());
3035 static TupleExp create(const ref Loc loc, Expressions* exps)
3037 return new TupleExp(loc, exps);
3040 override TupleExp syntaxCopy()
3042 return new TupleExp(loc, e0 ? e0.syntaxCopy() : null, arraySyntaxCopy(exps));
3045 override bool equals(const RootObject o) const
3047 if (this == o)
3048 return true;
3049 if (auto e = o.isExpression())
3050 if (auto te = e.isTupleExp())
3052 if (exps.length != te.exps.length)
3053 return false;
3054 if (e0 && !e0.equals(te.e0) || !e0 && te.e0)
3055 return false;
3056 foreach (i, e1; *exps)
3058 auto e2 = (*te.exps)[i];
3059 if (!e1.equals(e2))
3060 return false;
3062 return true;
3064 return false;
3067 override void accept(Visitor v)
3069 v.visit(this);
3073 /***********************************************************
3074 * [ e1, e2, e3, ... ]
3076 * https://dlang.org/spec/expression.html#array_literals
3078 extern (C++) final class ArrayLiteralExp : Expression
3080 OwnedBy ownedByCtfe = OwnedBy.code;
3081 bool onstack = false;
3083 /** If !is null, elements[] can be sparse and basis is used for the
3084 * "default" element value. In other words, non-null elements[i] overrides
3085 * this 'basis' value.
3087 Expression basis;
3089 Expressions* elements;
3091 extern (D) this(const ref Loc loc, Type type, Expressions* elements)
3093 super(loc, EXP.arrayLiteral);
3094 this.type = type;
3095 this.elements = elements;
3098 extern (D) this(const ref Loc loc, Type type, Expression e)
3100 super(loc, EXP.arrayLiteral);
3101 this.type = type;
3102 elements = new Expressions();
3103 elements.push(e);
3106 extern (D) this(const ref Loc loc, Type type, Expression basis, Expressions* elements)
3108 super(loc, EXP.arrayLiteral);
3109 this.type = type;
3110 this.basis = basis;
3111 this.elements = elements;
3114 static ArrayLiteralExp create(const ref Loc loc, Expressions* elements)
3116 return new ArrayLiteralExp(loc, null, elements);
3119 // Same as create, but doesn't allocate memory.
3120 static void emplace(UnionExp* pue, const ref Loc loc, Expressions* elements)
3122 emplaceExp!(ArrayLiteralExp)(pue, loc, null, elements);
3125 override ArrayLiteralExp syntaxCopy()
3127 return new ArrayLiteralExp(loc,
3128 null,
3129 basis ? basis.syntaxCopy() : null,
3130 arraySyntaxCopy(elements));
3133 override bool equals(const RootObject o) const
3135 if (this == o)
3136 return true;
3137 auto e = o.isExpression();
3138 if (!e)
3139 return false;
3140 if (auto ae = e.isArrayLiteralExp())
3142 if (elements.length != ae.elements.length)
3143 return false;
3144 if (elements.length == 0 && !type.equals(ae.type))
3146 return false;
3149 foreach (i, e1; *elements)
3151 auto e2 = (*ae.elements)[i];
3152 auto e1x = e1 ? e1 : basis;
3153 auto e2x = e2 ? e2 : ae.basis;
3155 if (e1x != e2x && (!e1x || !e2x || !e1x.equals(e2x)))
3156 return false;
3158 return true;
3160 return false;
3163 Expression getElement(size_t i)
3165 return this[i];
3168 Expression opIndex(size_t i)
3170 auto el = (*elements)[i];
3171 return el ? el : basis;
3174 override Optional!bool toBool()
3176 size_t dim = elements ? elements.length : 0;
3177 return typeof(return)(dim != 0);
3180 override StringExp toStringExp()
3182 TY telem = type.nextOf().toBasetype().ty;
3183 if (telem.isSomeChar || (telem == Tvoid && (!elements || elements.length == 0)))
3185 ubyte sz = 1;
3186 if (telem == Twchar)
3187 sz = 2;
3188 else if (telem == Tdchar)
3189 sz = 4;
3191 OutBuffer buf;
3192 if (elements)
3194 foreach (i; 0 .. elements.length)
3196 auto ch = this[i];
3197 if (ch.op != EXP.int64)
3198 return null;
3199 if (sz == 1)
3200 buf.writeByte(cast(uint)ch.toInteger());
3201 else if (sz == 2)
3202 buf.writeword(cast(uint)ch.toInteger());
3203 else
3204 buf.write4(cast(uint)ch.toInteger());
3207 char prefix;
3208 if (sz == 1)
3210 prefix = 'c';
3211 buf.writeByte(0);
3213 else if (sz == 2)
3215 prefix = 'w';
3216 buf.writeword(0);
3218 else
3220 prefix = 'd';
3221 buf.write4(0);
3224 const size_t len = buf.length / sz - 1;
3225 auto se = new StringExp(loc, buf.extractSlice()[0 .. len * sz], len, sz, prefix);
3226 se.sz = sz;
3227 se.type = type;
3228 return se;
3230 return null;
3233 override void accept(Visitor v)
3235 v.visit(this);
3239 /***********************************************************
3240 * [ key0 : value0, key1 : value1, ... ]
3242 * https://dlang.org/spec/expression.html#associative_array_literals
3244 extern (C++) final class AssocArrayLiteralExp : Expression
3246 OwnedBy ownedByCtfe = OwnedBy.code;
3248 Expressions* keys;
3249 Expressions* values;
3251 extern (D) this(const ref Loc loc, Expressions* keys, Expressions* values)
3253 super(loc, EXP.assocArrayLiteral);
3254 assert(keys.length == values.length);
3255 this.keys = keys;
3256 this.values = values;
3259 override bool equals(const RootObject o) const
3261 if (this == o)
3262 return true;
3263 auto e = o.isExpression();
3264 if (!e)
3265 return false;
3266 if (auto ae = e.isAssocArrayLiteralExp())
3268 if (keys.length != ae.keys.length)
3269 return false;
3270 size_t count = 0;
3271 foreach (i, key; *keys)
3273 foreach (j, akey; *ae.keys)
3275 if (key.equals(akey))
3277 if (!(*values)[i].equals((*ae.values)[j]))
3278 return false;
3279 ++count;
3283 return count == keys.length;
3285 return false;
3288 override AssocArrayLiteralExp syntaxCopy()
3290 return new AssocArrayLiteralExp(loc, arraySyntaxCopy(keys), arraySyntaxCopy(values));
3293 override Optional!bool toBool()
3295 size_t dim = keys.length;
3296 return typeof(return)(dim != 0);
3299 override void accept(Visitor v)
3301 v.visit(this);
3305 enum stageScrub = 0x1; /// scrubReturnValue is running
3306 enum stageSearchPointers = 0x2; /// hasNonConstPointers is running
3307 enum stageOptimize = 0x4; /// optimize is running
3308 enum stageApply = 0x8; /// apply is running
3309 enum stageInlineScan = 0x10; /// inlineScan is running
3310 enum stageToCBuffer = 0x20; /// toCBuffer is running
3312 /***********************************************************
3313 * sd( e1, e2, e3, ... )
3315 extern (C++) final class StructLiteralExp : Expression
3317 StructDeclaration sd; /// which aggregate this is for
3318 Expressions* elements; /// parallels sd.fields[] with null entries for fields to skip
3319 Type stype; /// final type of result (can be different from sd's type)
3321 // `inlineCopy` is only used temporarily in the `inline.d` pass,
3322 // while `sym` is only used in `e2ir/s2ir/tocsym` which comes after
3323 union
3325 Symbol* sym; /// back end symbol to initialize with literal
3327 /// those fields need to prevent a infinite recursion when one field of struct initialized with 'this' pointer.
3328 StructLiteralExp inlinecopy;
3331 /** pointer to the origin instance of the expression.
3332 * once a new expression is created, origin is set to 'this'.
3333 * anytime when an expression copy is created, 'origin' pointer is set to
3334 * 'origin' pointer value of the original expression.
3336 StructLiteralExp origin;
3339 /** anytime when recursive function is calling, 'stageflags' marks with bit flag of
3340 * current stage and unmarks before return from this function.
3341 * 'inlinecopy' uses similar 'stageflags' and from multiple evaluation 'doInline'
3342 * (with infinite recursion) of this expression.
3344 ubyte stageflags;
3346 bool useStaticInit; /// if this is true, use the StructDeclaration's init symbol
3347 bool isOriginal = false; /// used when moving instances to indicate `this is this.origin`
3348 OwnedBy ownedByCtfe = OwnedBy.code;
3350 extern (D) this(const ref Loc loc, StructDeclaration sd, Expressions* elements, Type stype = null)
3352 super(loc, EXP.structLiteral);
3353 this.sd = sd;
3354 if (!elements)
3355 elements = new Expressions();
3356 this.elements = elements;
3357 this.stype = stype;
3358 this.origin = this;
3359 //printf("StructLiteralExp::StructLiteralExp(%s)\n", toChars());
3362 static StructLiteralExp create(const ref Loc loc, StructDeclaration sd, void* elements, Type stype = null)
3364 return new StructLiteralExp(loc, sd, cast(Expressions*)elements, stype);
3367 override bool equals(const RootObject o) const
3369 if (this == o)
3370 return true;
3371 auto e = o.isExpression();
3372 if (!e)
3373 return false;
3374 if (auto se = e.isStructLiteralExp())
3376 if (!type.equals(se.type))
3377 return false;
3378 if (elements.length != se.elements.length)
3379 return false;
3380 foreach (i, e1; *elements)
3382 auto e2 = (*se.elements)[i];
3383 if (e1 != e2 && (!e1 || !e2 || !e1.equals(e2)))
3384 return false;
3386 return true;
3388 return false;
3391 override StructLiteralExp syntaxCopy()
3393 auto exp = new StructLiteralExp(loc, sd, arraySyntaxCopy(elements), type ? type : stype);
3394 exp.origin = this;
3395 return exp;
3398 /**************************************
3399 * Gets expression at offset of type.
3400 * Returns NULL if not found.
3402 Expression getField(Type type, uint offset)
3404 //printf("StructLiteralExp::getField(this = %s, type = %s, offset = %u)\n",
3405 // /*toChars()*/"", type.toChars(), offset);
3406 Expression e = null;
3407 int i = getFieldIndex(type, offset);
3409 if (i != -1)
3411 //printf("\ti = %d\n", i);
3412 if (i >= sd.nonHiddenFields())
3413 return null;
3415 assert(i < elements.length);
3416 e = (*elements)[i];
3417 if (e)
3419 //printf("e = %s, e.type = %s\n", e.toChars(), e.type.toChars());
3421 /* If type is a static array, and e is an initializer for that array,
3422 * then the field initializer should be an array literal of e.
3424 auto tsa = type.isTypeSArray();
3425 if (tsa && e.type.castMod(0) != type.castMod(0))
3427 const length = cast(size_t)tsa.dim.toInteger();
3428 auto z = new Expressions(length);
3429 foreach (ref q; *z)
3430 q = e.copy();
3431 e = new ArrayLiteralExp(loc, type, z);
3433 else
3435 e = e.copy();
3436 e.type = type;
3438 if (useStaticInit && e.type.needsNested())
3439 if (auto se = e.isStructLiteralExp())
3441 se.useStaticInit = true;
3445 return e;
3448 /************************************
3449 * Get index of field.
3450 * Returns -1 if not found.
3452 int getFieldIndex(Type type, uint offset)
3454 /* Find which field offset is by looking at the field offsets
3456 if (elements.length)
3458 const sz = type.size();
3459 if (sz == SIZE_INVALID)
3460 return -1;
3461 foreach (i, v; sd.fields)
3463 if (offset == v.offset && sz == v.type.size())
3465 /* context fields might not be filled. */
3466 if (i >= sd.nonHiddenFields())
3467 return cast(int)i;
3468 if (auto e = (*elements)[i])
3470 return cast(int)i;
3472 break;
3476 return -1;
3479 override Expression addDtorHook(Scope* sc)
3481 /* If struct requires a destructor, rewrite as:
3482 * (S tmp = S()),tmp
3483 * so that the destructor can be hung on tmp.
3485 if (sd.dtor && sc.func)
3487 /* Make an identifier for the temporary of the form:
3488 * __sl%s%d, where %s is the struct name
3490 char[10] buf = void;
3491 const prefix = "__sl";
3492 const ident = sd.ident.toString;
3493 const fullLen = prefix.length + ident.length;
3494 const len = fullLen < buf.length ? fullLen : buf.length;
3495 buf[0 .. prefix.length] = prefix;
3496 buf[prefix.length .. len] = ident[0 .. len - prefix.length];
3498 auto tmp = copyToTemp(0, buf[0 .. len], this);
3499 Expression ae = new DeclarationExp(loc, tmp);
3500 Expression e = new CommaExp(loc, ae, new VarExp(loc, tmp));
3501 e = e.expressionSemantic(sc);
3502 return e;
3504 return this;
3507 override Expression toLvalue(Scope* sc, Expression e)
3509 if (sc.flags & SCOPE.Cfile)
3510 return this; // C struct literals are lvalues
3511 else
3512 return Expression.toLvalue(sc, e);
3515 override void accept(Visitor v)
3517 v.visit(this);
3521 /***********************************************************
3522 * C11 6.5.2.5
3523 * ( type-name ) { initializer-list }
3525 extern (C++) final class CompoundLiteralExp : Expression
3527 Initializer initializer; /// initializer-list
3529 extern (D) this(const ref Loc loc, Type type_name, Initializer initializer)
3531 super(loc, EXP.compoundLiteral);
3532 super.type = type_name;
3533 this.initializer = initializer;
3534 //printf("CompoundLiteralExp::CompoundLiteralExp(%s)\n", toChars());
3537 override void accept(Visitor v)
3539 v.visit(this);
3543 /***********************************************************
3544 * Mainly just a placeholder
3546 extern (C++) final class TypeExp : Expression
3548 bool parens; // if this is a parenthesized expression
3550 extern (D) this(const ref Loc loc, Type type)
3552 super(loc, EXP.type);
3553 //printf("TypeExp::TypeExp(%s)\n", type.toChars());
3554 this.type = type;
3557 override TypeExp syntaxCopy()
3559 return new TypeExp(loc, type.syntaxCopy());
3562 override bool checkType()
3564 error("type `%s` is not an expression", toChars());
3565 return true;
3568 override bool checkValue()
3570 error("type `%s` has no value", toChars());
3571 return true;
3574 override void accept(Visitor v)
3576 v.visit(this);
3580 /***********************************************************
3581 * Mainly just a placeholder of
3582 * Package, Module, Nspace, and TemplateInstance (including TemplateMixin)
3584 * A template instance that requires IFTI:
3585 * foo!tiargs(fargs) // foo!tiargs
3586 * is left until CallExp::semantic() or resolveProperties()
3588 extern (C++) final class ScopeExp : Expression
3590 ScopeDsymbol sds;
3592 extern (D) this(const ref Loc loc, ScopeDsymbol sds)
3594 super(loc, EXP.scope_);
3595 //printf("ScopeExp::ScopeExp(sds = '%s')\n", sds.toChars());
3596 //static int count; if (++count == 38) *(char*)0=0;
3597 this.sds = sds;
3598 assert(!sds.isTemplateDeclaration()); // instead, you should use TemplateExp
3601 override ScopeExp syntaxCopy()
3603 return new ScopeExp(loc, sds.syntaxCopy(null));
3606 override bool checkType()
3608 if (sds.isPackage())
3610 error("%s `%s` has no type", sds.kind(), sds.toChars());
3611 return true;
3613 if (auto ti = sds.isTemplateInstance())
3615 //assert(ti.needsTypeInference(sc));
3616 if (ti.tempdecl &&
3617 ti.semantictiargsdone &&
3618 ti.semanticRun == PASS.initial)
3620 error("partial %s `%s` has no type", sds.kind(), toChars());
3621 return true;
3624 return false;
3627 override bool checkValue()
3629 error("%s `%s` has no value", sds.kind(), sds.toChars());
3630 return true;
3633 override void accept(Visitor v)
3635 v.visit(this);
3639 /***********************************************************
3640 * Mainly just a placeholder
3642 extern (C++) final class TemplateExp : Expression
3644 TemplateDeclaration td;
3645 FuncDeclaration fd;
3647 extern (D) this(const ref Loc loc, TemplateDeclaration td, FuncDeclaration fd = null)
3649 super(loc, EXP.template_);
3650 //printf("TemplateExp(): %s\n", td.toChars());
3651 this.td = td;
3652 this.fd = fd;
3655 override bool isLvalue()
3657 return fd !is null;
3660 override Expression toLvalue(Scope* sc, Expression e)
3662 if (!fd)
3663 return Expression.toLvalue(sc, e);
3665 assert(sc);
3666 return symbolToExp(fd, loc, sc, true);
3669 override bool checkType()
3671 error("%s `%s` has no type", td.kind(), toChars());
3672 return true;
3675 override bool checkValue()
3677 error("%s `%s` has no value", td.kind(), toChars());
3678 return true;
3681 override void accept(Visitor v)
3683 v.visit(this);
3687 /***********************************************************
3688 * newtype(arguments)
3690 extern (C++) final class NewExp : Expression
3692 Expression thisexp; // if !=null, 'this' for class being allocated
3693 Type newtype;
3694 Expressions* arguments; // Array of Expression's
3695 Identifiers* names; // Array of names corresponding to expressions
3697 Expression argprefix; // expression to be evaluated just before arguments[]
3698 CtorDeclaration member; // constructor function
3699 bool onstack; // allocate on stack
3700 bool thrownew; // this NewExp is the expression of a ThrowStatement
3702 Expression lowering; // lowered druntime hook: `_d_new{class,itemT}`
3704 /// Puts the `arguments` and `names` into an `ArgumentList` for easily passing them around.
3705 /// The fields are still separate for backwards compatibility
3706 extern (D) ArgumentList argumentList() { return ArgumentList(arguments, names); }
3708 extern (D) this(const ref Loc loc, Expression thisexp, Type newtype, Expressions* arguments, Identifiers* names = null)
3710 super(loc, EXP.new_);
3711 this.thisexp = thisexp;
3712 this.newtype = newtype;
3713 this.arguments = arguments;
3714 this.names = names;
3717 static NewExp create(const ref Loc loc, Expression thisexp, Type newtype, Expressions* arguments)
3719 return new NewExp(loc, thisexp, newtype, arguments);
3722 override NewExp syntaxCopy()
3724 return new NewExp(loc,
3725 thisexp ? thisexp.syntaxCopy() : null,
3726 newtype.syntaxCopy(),
3727 arraySyntaxCopy(arguments),
3728 names ? names.copy() : null);
3731 override void accept(Visitor v)
3733 v.visit(this);
3737 /***********************************************************
3738 * class baseclasses { } (arguments)
3740 extern (C++) final class NewAnonClassExp : Expression
3742 Expression thisexp; // if !=null, 'this' for class being allocated
3743 ClassDeclaration cd; // class being instantiated
3744 Expressions* arguments; // Array of Expression's to call class constructor
3746 extern (D) this(const ref Loc loc, Expression thisexp, ClassDeclaration cd, Expressions* arguments)
3748 super(loc, EXP.newAnonymousClass);
3749 this.thisexp = thisexp;
3750 this.cd = cd;
3751 this.arguments = arguments;
3754 override NewAnonClassExp syntaxCopy()
3756 return new NewAnonClassExp(loc, thisexp ? thisexp.syntaxCopy() : null, cd.syntaxCopy(null), arraySyntaxCopy(arguments));
3759 override void accept(Visitor v)
3761 v.visit(this);
3765 /***********************************************************
3767 extern (C++) class SymbolExp : Expression
3769 Declaration var;
3770 Dsymbol originalScope; // original scope before inlining
3771 bool hasOverloads;
3773 extern (D) this(const ref Loc loc, EXP op, Declaration var, bool hasOverloads)
3775 super(loc, op);
3776 assert(var);
3777 this.var = var;
3778 this.hasOverloads = hasOverloads;
3781 override void accept(Visitor v)
3783 v.visit(this);
3787 /***********************************************************
3788 * Offset from symbol
3790 extern (C++) final class SymOffExp : SymbolExp
3792 dinteger_t offset;
3794 extern (D) this(const ref Loc loc, Declaration var, dinteger_t offset, bool hasOverloads = true)
3796 if (auto v = var.isVarDeclaration())
3798 // FIXME: This error report will never be handled anyone.
3799 // It should be done before the SymOffExp construction.
3800 if (v.needThis())
3801 .error(loc, "need `this` for address of `%s`", v.toChars());
3802 hasOverloads = false;
3804 super(loc, EXP.symbolOffset, var, hasOverloads);
3805 this.offset = offset;
3808 override Optional!bool toBool()
3810 return typeof(return)(true);
3813 override void accept(Visitor v)
3815 v.visit(this);
3819 /***********************************************************
3820 * Variable
3822 extern (C++) final class VarExp : SymbolExp
3824 bool delegateWasExtracted;
3825 extern (D) this(const ref Loc loc, Declaration var, bool hasOverloads = true)
3827 if (var.isVarDeclaration())
3828 hasOverloads = false;
3830 super(loc, EXP.variable, var, hasOverloads);
3831 //printf("VarExp(this = %p, '%s', loc = %s)\n", this, var.toChars(), loc.toChars());
3832 //if (strcmp(var.ident.toChars(), "func") == 0) assert(0);
3833 this.type = var.type;
3836 static VarExp create(const ref Loc loc, Declaration var, bool hasOverloads = true)
3838 return new VarExp(loc, var, hasOverloads);
3841 override bool equals(const RootObject o) const
3843 if (this == o)
3844 return true;
3845 if (auto ne = o.isExpression().isVarExp())
3847 if (type.toHeadMutable().equals(ne.type.toHeadMutable()) && var == ne.var)
3849 return true;
3852 return false;
3855 override bool isLvalue()
3857 if (var.storage_class & (STC.lazy_ | STC.rvalue | STC.manifest))
3858 return false;
3859 return true;
3862 override Expression toLvalue(Scope* sc, Expression e)
3864 if (var.storage_class & STC.manifest)
3866 error("manifest constant `%s` cannot be modified", var.toChars());
3867 return ErrorExp.get();
3869 if (var.storage_class & STC.lazy_ && !delegateWasExtracted)
3871 error("lazy variable `%s` cannot be modified", var.toChars());
3872 return ErrorExp.get();
3874 if (var.ident == Id.ctfe)
3876 error("cannot modify compiler-generated variable `__ctfe`");
3877 return ErrorExp.get();
3879 if (var.ident == Id.dollar) // https://issues.dlang.org/show_bug.cgi?id=13574
3881 error("cannot modify operator `$`");
3882 return ErrorExp.get();
3884 return this;
3887 override Expression modifiableLvalue(Scope* sc, Expression e)
3889 //printf("VarExp::modifiableLvalue('%s')\n", var.toChars());
3890 if (var.storage_class & STC.manifest)
3892 error("cannot modify manifest constant `%s`", toChars());
3893 return ErrorExp.get();
3895 // See if this expression is a modifiable lvalue (i.e. not const)
3896 return Expression.modifiableLvalue(sc, e);
3899 override void accept(Visitor v)
3901 v.visit(this);
3905 /***********************************************************
3906 * Overload Set
3908 extern (C++) final class OverExp : Expression
3910 OverloadSet vars;
3912 extern (D) this(const ref Loc loc, OverloadSet s)
3914 super(loc, EXP.overloadSet);
3915 //printf("OverExp(this = %p, '%s')\n", this, var.toChars());
3916 vars = s;
3917 type = Type.tvoid;
3920 override bool isLvalue()
3922 return true;
3925 override Expression toLvalue(Scope* sc, Expression e)
3927 return this;
3930 override void accept(Visitor v)
3932 v.visit(this);
3936 /***********************************************************
3937 * Function/Delegate literal
3940 extern (C++) final class FuncExp : Expression
3942 FuncLiteralDeclaration fd;
3943 TemplateDeclaration td;
3944 TOK tok; // TOK.reserved, TOK.delegate_, TOK.function_
3946 extern (D) this(const ref Loc loc, Dsymbol s)
3948 super(loc, EXP.function_);
3949 this.td = s.isTemplateDeclaration();
3950 this.fd = s.isFuncLiteralDeclaration();
3951 if (td)
3953 assert(td.literal);
3954 assert(td.members && td.members.length == 1);
3955 fd = (*td.members)[0].isFuncLiteralDeclaration();
3957 tok = fd.tok; // save original kind of function/delegate/(infer)
3958 assert(fd.fbody);
3961 override bool equals(const RootObject o) const
3963 if (this == o)
3964 return true;
3965 auto e = o.isExpression();
3966 if (!e)
3967 return false;
3968 if (auto fe = e.isFuncExp())
3970 return fd == fe.fd;
3972 return false;
3975 extern (D) void genIdent(Scope* sc)
3977 if (fd.ident == Id.empty)
3979 const(char)[] s;
3980 if (fd.fes)
3981 s = "__foreachbody";
3982 else if (fd.tok == TOK.reserved)
3983 s = "__lambda";
3984 else if (fd.tok == TOK.delegate_)
3985 s = "__dgliteral";
3986 else
3987 s = "__funcliteral";
3989 DsymbolTable symtab;
3990 if (FuncDeclaration func = sc.parent.isFuncDeclaration())
3992 if (func.localsymtab is null)
3994 // Inside template constraint, symtab is not set yet.
3995 // Initialize it lazily.
3996 func.localsymtab = new DsymbolTable();
3998 symtab = func.localsymtab;
4000 else
4002 ScopeDsymbol sds = sc.parent.isScopeDsymbol();
4003 if (!sds.symtab)
4005 // Inside template constraint, symtab may not be set yet.
4006 // Initialize it lazily.
4007 assert(sds.isTemplateInstance());
4008 sds.symtab = new DsymbolTable();
4010 symtab = sds.symtab;
4012 assert(symtab);
4013 Identifier id = Identifier.generateId(s, symtab.length() + 1);
4014 fd.ident = id;
4015 if (td)
4016 td.ident = id;
4017 symtab.insert(td ? cast(Dsymbol)td : cast(Dsymbol)fd);
4021 override FuncExp syntaxCopy()
4023 if (td)
4024 return new FuncExp(loc, td.syntaxCopy(null));
4025 else if (fd.semanticRun == PASS.initial)
4026 return new FuncExp(loc, fd.syntaxCopy(null));
4027 else // https://issues.dlang.org/show_bug.cgi?id=13481
4028 // Prevent multiple semantic analysis of lambda body.
4029 return new FuncExp(loc, fd);
4032 extern (D) MATCH matchType(Type to, Scope* sc, FuncExp* presult, int flag = 0)
4035 static MATCH cannotInfer(Expression e, Type to, int flag)
4037 if (!flag)
4038 e.error("cannot infer parameter types from `%s`", to.toChars());
4039 return MATCH.nomatch;
4042 //printf("FuncExp::matchType('%s'), to=%s\n", type ? type.toChars() : "null", to.toChars());
4043 if (presult)
4044 *presult = null;
4046 TypeFunction tof = null;
4047 if (to.ty == Tdelegate)
4049 if (tok == TOK.function_)
4051 if (!flag)
4052 error("cannot match function literal to delegate type `%s`", to.toChars());
4053 return MATCH.nomatch;
4055 tof = cast(TypeFunction)to.nextOf();
4057 else if (to.ty == Tpointer && (tof = to.nextOf().isTypeFunction()) !is null)
4059 if (tok == TOK.delegate_)
4061 if (!flag)
4062 error("cannot match delegate literal to function pointer type `%s`", to.toChars());
4063 return MATCH.nomatch;
4067 if (td)
4069 if (!tof)
4071 return cannotInfer(this, to, flag);
4074 // Parameter types inference from 'tof'
4075 assert(td._scope);
4076 TypeFunction tf = fd.type.isTypeFunction();
4077 //printf("\ttof = %s\n", tof.toChars());
4078 //printf("\ttf = %s\n", tf.toChars());
4079 const dim = tf.parameterList.length;
4081 if (tof.parameterList.length != dim || tof.parameterList.varargs != tf.parameterList.varargs)
4082 return cannotInfer(this, to, flag);
4084 auto tiargs = new Objects();
4085 tiargs.reserve(td.parameters.length);
4087 foreach (tp; *td.parameters)
4089 size_t u = 0;
4090 foreach (i, p; tf.parameterList)
4092 if (auto ti = p.type.isTypeIdentifier())
4093 if (ti && ti.ident == tp.ident)
4094 break;
4096 ++u;
4098 assert(u < dim);
4099 Parameter pto = tof.parameterList[u];
4100 Type t = pto.type;
4101 if (t.ty == Terror)
4102 return cannotInfer(this, to, flag);
4103 tf.parameterList[u].storageClass = tof.parameterList[u].storageClass;
4104 tiargs.push(t);
4107 // Set target of return type inference
4108 if (!tf.next && tof.next)
4109 fd.treq = to;
4111 auto ti = new TemplateInstance(loc, td, tiargs);
4112 Expression ex = (new ScopeExp(loc, ti)).expressionSemantic(td._scope);
4114 // Reset inference target for the later re-semantic
4115 fd.treq = null;
4117 if (ex.op == EXP.error)
4118 return MATCH.nomatch;
4119 if (auto ef = ex.isFuncExp())
4120 return ef.matchType(to, sc, presult, flag);
4121 else
4122 return cannotInfer(this, to, flag);
4125 if (!tof || !tof.next)
4126 return MATCH.nomatch;
4128 assert(type && type != Type.tvoid);
4129 if (fd.type.ty == Terror)
4130 return MATCH.nomatch;
4131 auto tfx = fd.type.isTypeFunction();
4132 bool convertMatch = (type.ty != to.ty);
4134 if (fd.inferRetType && tfx.next.implicitConvTo(tof.next) == MATCH.convert)
4136 /* If return type is inferred and covariant return,
4137 * tweak return statements to required return type.
4139 * interface I {}
4140 * class C : Object, I{}
4142 * I delegate() dg = delegate() { return new class C(); }
4144 convertMatch = true;
4146 auto tfy = new TypeFunction(tfx.parameterList, tof.next,
4147 tfx.linkage, STC.undefined_);
4148 tfy.mod = tfx.mod;
4149 tfy.trust = tfx.trust;
4150 tfy.isnothrow = tfx.isnothrow;
4151 tfy.isnogc = tfx.isnogc;
4152 tfy.purity = tfx.purity;
4153 tfy.isproperty = tfx.isproperty;
4154 tfy.isref = tfx.isref;
4155 tfy.isInOutParam = tfx.isInOutParam;
4156 tfy.isInOutQual = tfx.isInOutQual;
4157 tfy.deco = tfy.merge().deco;
4159 tfx = tfy;
4161 Type tx;
4162 if (tok == TOK.delegate_ ||
4163 tok == TOK.reserved && (type.ty == Tdelegate || type.ty == Tpointer && to.ty == Tdelegate))
4165 // Allow conversion from implicit function pointer to delegate
4166 tx = new TypeDelegate(tfx);
4167 tx.deco = tx.merge().deco;
4169 else
4171 assert(tok == TOK.function_ || tok == TOK.reserved && type.ty == Tpointer || fd.errors);
4172 tx = tfx.pointerTo();
4174 //printf("\ttx = %s, to = %s\n", tx.toChars(), to.toChars());
4176 MATCH m = tx.implicitConvTo(to);
4177 if (m > MATCH.nomatch)
4179 // MATCH.exact: exact type match
4180 // MATCH.constant: covairiant type match (eg. attributes difference)
4181 // MATCH.convert: context conversion
4182 m = convertMatch ? MATCH.convert : tx.equals(to) ? MATCH.exact : MATCH.constant;
4184 if (presult)
4186 (*presult) = cast(FuncExp)copy();
4187 (*presult).type = to;
4189 // https://issues.dlang.org/show_bug.cgi?id=12508
4190 // Tweak function body for covariant returns.
4191 (*presult).fd.modifyReturns(sc, tof.next);
4194 else if (!flag)
4196 auto ts = toAutoQualChars(tx, to);
4197 error("cannot implicitly convert expression `%s` of type `%s` to `%s`",
4198 toChars(), ts[0], ts[1]);
4200 return m;
4203 override const(char)* toChars() const
4205 return fd.toChars();
4208 override bool checkType()
4210 if (td)
4212 error("template lambda has no type");
4213 return true;
4215 return false;
4218 override bool checkValue()
4220 if (td)
4222 error("template lambda has no value");
4223 return true;
4225 return false;
4228 override void accept(Visitor v)
4230 v.visit(this);
4234 /***********************************************************
4235 * Declaration of a symbol
4237 * D grammar allows declarations only as statements. However in AST representation
4238 * it can be part of any expression. This is used, for example, during internal
4239 * syntax re-writes to inject hidden symbols.
4241 extern (C++) final class DeclarationExp : Expression
4243 Dsymbol declaration;
4245 extern (D) this(const ref Loc loc, Dsymbol declaration)
4247 super(loc, EXP.declaration);
4248 this.declaration = declaration;
4251 override DeclarationExp syntaxCopy()
4253 return new DeclarationExp(loc, declaration.syntaxCopy(null));
4256 override bool hasCode()
4258 if (auto vd = declaration.isVarDeclaration())
4260 return !(vd.storage_class & (STC.manifest | STC.static_));
4262 return false;
4265 override void accept(Visitor v)
4267 v.visit(this);
4271 /***********************************************************
4272 * typeid(int)
4274 extern (C++) final class TypeidExp : Expression
4276 RootObject obj;
4278 extern (D) this(const ref Loc loc, RootObject o)
4280 super(loc, EXP.typeid_);
4281 this.obj = o;
4284 override TypeidExp syntaxCopy()
4286 return new TypeidExp(loc, objectSyntaxCopy(obj));
4289 override void accept(Visitor v)
4291 v.visit(this);
4295 /***********************************************************
4296 * __traits(identifier, args...)
4298 extern (C++) final class TraitsExp : Expression
4300 Identifier ident;
4301 Objects* args;
4303 extern (D) this(const ref Loc loc, Identifier ident, Objects* args)
4305 super(loc, EXP.traits);
4306 this.ident = ident;
4307 this.args = args;
4310 override TraitsExp syntaxCopy()
4312 return new TraitsExp(loc, ident, TemplateInstance.arraySyntaxCopy(args));
4315 override void accept(Visitor v)
4317 v.visit(this);
4321 /***********************************************************
4322 * Generates a halt instruction
4324 * `assert(0)` gets rewritten to this with `CHECKACTION.halt`
4326 extern (C++) final class HaltExp : Expression
4328 extern (D) this(const ref Loc loc)
4330 super(loc, EXP.halt);
4333 override void accept(Visitor v)
4335 v.visit(this);
4339 /***********************************************************
4340 * is(targ id tok tspec)
4341 * is(targ id == tok2)
4343 extern (C++) final class IsExp : Expression
4345 Type targ;
4346 Identifier id; // can be null
4347 Type tspec; // can be null
4348 TemplateParameters* parameters;
4349 TOK tok; // ':' or '=='
4350 TOK tok2; // 'struct', 'union', etc.
4352 extern (D) this(const ref Loc loc, Type targ, Identifier id, TOK tok, Type tspec, TOK tok2, TemplateParameters* parameters) scope
4354 super(loc, EXP.is_);
4355 this.targ = targ;
4356 this.id = id;
4357 this.tok = tok;
4358 this.tspec = tspec;
4359 this.tok2 = tok2;
4360 this.parameters = parameters;
4363 override IsExp syntaxCopy()
4365 // This section is identical to that in TemplateDeclaration::syntaxCopy()
4366 TemplateParameters* p = null;
4367 if (parameters)
4369 p = new TemplateParameters(parameters.length);
4370 foreach (i, el; *parameters)
4371 (*p)[i] = el.syntaxCopy();
4373 return new IsExp(loc, targ.syntaxCopy(), id, tok, tspec ? tspec.syntaxCopy() : null, tok2, p);
4376 override void accept(Visitor v)
4378 v.visit(this);
4382 /***********************************************************
4383 * Base class for unary operators
4385 * https://dlang.org/spec/expression.html#unary-expression
4387 extern (C++) abstract class UnaExp : Expression
4389 Expression e1;
4391 extern (D) this(const ref Loc loc, EXP op, Expression e1) scope
4393 super(loc, op);
4394 this.e1 = e1;
4397 override UnaExp syntaxCopy()
4399 UnaExp e = cast(UnaExp)copy();
4400 e.type = null;
4401 e.e1 = e.e1.syntaxCopy();
4402 return e;
4405 /********************************
4406 * The type for a unary expression is incompatible.
4407 * Print error message.
4408 * Returns:
4409 * ErrorExp
4411 final Expression incompatibleTypes()
4413 if (e1.type.toBasetype() == Type.terror)
4414 return e1;
4416 if (e1.op == EXP.type)
4418 error("incompatible type for `%s(%s)`: cannot use `%s` with types", EXPtoString(op).ptr, e1.toChars(), EXPtoString(op).ptr);
4420 else
4422 error("incompatible type for `%s(%s)`: `%s`", EXPtoString(op).ptr, e1.toChars(), e1.type.toChars());
4424 return ErrorExp.get();
4427 /*********************
4428 * Mark the operand as will never be dereferenced,
4429 * which is useful info for @safe checks.
4430 * Do before semantic() on operands rewrites them.
4432 final void setNoderefOperand()
4434 if (auto edi = e1.isDotIdExp())
4435 edi.noderef = true;
4439 override final Expression resolveLoc(const ref Loc loc, Scope* sc)
4441 e1 = e1.resolveLoc(loc, sc);
4442 return this;
4445 override void accept(Visitor v)
4447 v.visit(this);
4451 alias fp_t = UnionExp function(const ref Loc loc, Type, Expression, Expression);
4452 alias fp2_t = bool function(const ref Loc loc, EXP, Expression, Expression);
4454 /***********************************************************
4455 * Base class for binary operators
4457 extern (C++) abstract class BinExp : Expression
4459 Expression e1;
4460 Expression e2;
4461 Type att1; // Save alias this type to detect recursion
4462 Type att2; // Save alias this type to detect recursion
4464 extern (D) this(const ref Loc loc, EXP op, Expression e1, Expression e2) scope
4466 super(loc, op);
4467 this.e1 = e1;
4468 this.e2 = e2;
4471 override BinExp syntaxCopy()
4473 BinExp e = cast(BinExp)copy();
4474 e.type = null;
4475 e.e1 = e.e1.syntaxCopy();
4476 e.e2 = e.e2.syntaxCopy();
4477 return e;
4480 /********************************
4481 * The types for a binary expression are incompatible.
4482 * Print error message.
4483 * Returns:
4484 * ErrorExp
4486 final Expression incompatibleTypes()
4488 if (e1.type.toBasetype() == Type.terror)
4489 return e1;
4490 if (e2.type.toBasetype() == Type.terror)
4491 return e2;
4493 // CondExp uses 'a ? b : c' but we're comparing 'b : c'
4494 const(char)* thisOp = (op == EXP.question) ? ":" : EXPtoString(op).ptr;
4495 if (e1.op == EXP.type || e2.op == EXP.type)
4497 error("incompatible types for `(%s) %s (%s)`: cannot use `%s` with types",
4498 e1.toChars(), thisOp, e2.toChars(), EXPtoString(op).ptr);
4500 else if (e1.type.equals(e2.type))
4502 error("incompatible types for `(%s) %s (%s)`: both operands are of type `%s`",
4503 e1.toChars(), thisOp, e2.toChars(), e1.type.toChars());
4505 else
4507 auto ts = toAutoQualChars(e1.type, e2.type);
4508 error("incompatible types for `(%s) %s (%s)`: `%s` and `%s`",
4509 e1.toChars(), thisOp, e2.toChars(), ts[0], ts[1]);
4511 return ErrorExp.get();
4514 extern (D) final Expression checkOpAssignTypes(Scope* sc)
4516 // At that point t1 and t2 are the merged types. type is the original type of the lhs.
4517 Type t1 = e1.type;
4518 Type t2 = e2.type;
4520 // T opAssign floating yields a floating. Prevent truncating conversions (float to int).
4521 // See https://issues.dlang.org/show_bug.cgi?id=3841.
4522 // Should we also prevent double to float (type.isfloating() && type.size() < t2.size()) ?
4523 if (op == EXP.addAssign || op == EXP.minAssign ||
4524 op == EXP.mulAssign || op == EXP.divAssign || op == EXP.modAssign ||
4525 op == EXP.powAssign)
4527 if ((type.isintegral() && t2.isfloating()))
4529 warning("`%s %s %s` is performing truncating conversion", type.toChars(), EXPtoString(op).ptr, t2.toChars());
4533 // generate an error if this is a nonsensical *=,/=, or %=, eg real *= imaginary
4534 if (op == EXP.mulAssign || op == EXP.divAssign || op == EXP.modAssign)
4536 // Any multiplication by an imaginary or complex number yields a complex result.
4537 // r *= c, i*=c, r*=i, i*=i are all forbidden operations.
4538 const(char)* opstr = EXPtoString(op).ptr;
4539 if (t1.isreal() && t2.iscomplex())
4541 error("`%s %s %s` is undefined. Did you mean `%s %s %s.re`?", t1.toChars(), opstr, t2.toChars(), t1.toChars(), opstr, t2.toChars());
4542 return ErrorExp.get();
4544 else if (t1.isimaginary() && t2.iscomplex())
4546 error("`%s %s %s` is undefined. Did you mean `%s %s %s.im`?", t1.toChars(), opstr, t2.toChars(), t1.toChars(), opstr, t2.toChars());
4547 return ErrorExp.get();
4549 else if ((t1.isreal() || t1.isimaginary()) && t2.isimaginary())
4551 error("`%s %s %s` is an undefined operation", t1.toChars(), opstr, t2.toChars());
4552 return ErrorExp.get();
4556 // generate an error if this is a nonsensical += or -=, eg real += imaginary
4557 if (op == EXP.addAssign || op == EXP.minAssign)
4559 // Addition or subtraction of a real and an imaginary is a complex result.
4560 // Thus, r+=i, r+=c, i+=r, i+=c are all forbidden operations.
4561 if ((t1.isreal() && (t2.isimaginary() || t2.iscomplex())) || (t1.isimaginary() && (t2.isreal() || t2.iscomplex())))
4563 error("`%s %s %s` is undefined (result is complex)", t1.toChars(), EXPtoString(op).ptr, t2.toChars());
4564 return ErrorExp.get();
4566 if (type.isreal() || type.isimaginary())
4568 assert(global.errors || t2.isfloating());
4569 e2 = e2.castTo(sc, t1);
4572 if (op == EXP.mulAssign)
4574 if (t2.isfloating())
4576 if (t1.isreal())
4578 if (t2.isimaginary() || t2.iscomplex())
4580 e2 = e2.castTo(sc, t1);
4583 else if (t1.isimaginary())
4585 if (t2.isimaginary() || t2.iscomplex())
4587 switch (t1.ty)
4589 case Timaginary32:
4590 t2 = Type.tfloat32;
4591 break;
4593 case Timaginary64:
4594 t2 = Type.tfloat64;
4595 break;
4597 case Timaginary80:
4598 t2 = Type.tfloat80;
4599 break;
4601 default:
4602 assert(0);
4604 e2 = e2.castTo(sc, t2);
4609 else if (op == EXP.divAssign)
4611 if (t2.isimaginary())
4613 if (t1.isreal())
4615 // x/iv = i(-x/v)
4616 // Therefore, the result is 0
4617 e2 = new CommaExp(loc, e2, new RealExp(loc, CTFloat.zero, t1));
4618 e2.type = t1;
4619 Expression e = new AssignExp(loc, e1, e2);
4620 e.type = t1;
4621 return e;
4623 else if (t1.isimaginary())
4625 Type t3;
4626 switch (t1.ty)
4628 case Timaginary32:
4629 t3 = Type.tfloat32;
4630 break;
4632 case Timaginary64:
4633 t3 = Type.tfloat64;
4634 break;
4636 case Timaginary80:
4637 t3 = Type.tfloat80;
4638 break;
4640 default:
4641 assert(0);
4643 e2 = e2.castTo(sc, t3);
4644 Expression e = new AssignExp(loc, e1, e2);
4645 e.type = t1;
4646 return e;
4650 else if (op == EXP.modAssign)
4652 if (t2.iscomplex())
4654 error("cannot perform modulo complex arithmetic");
4655 return ErrorExp.get();
4658 return this;
4661 extern (D) final bool checkIntegralBin()
4663 bool r1 = e1.checkIntegral();
4664 bool r2 = e2.checkIntegral();
4665 return (r1 || r2);
4668 extern (D) final bool checkArithmeticBin()
4670 bool r1 = e1.checkArithmetic();
4671 bool r2 = e2.checkArithmetic();
4672 return (r1 || r2);
4675 extern (D) final bool checkSharedAccessBin(Scope* sc)
4677 const r1 = e1.checkSharedAccess(sc);
4678 const r2 = e2.checkSharedAccess(sc);
4679 return (r1 || r2);
4682 /*********************
4683 * Mark the operands as will never be dereferenced,
4684 * which is useful info for @safe checks.
4685 * Do before semantic() on operands rewrites them.
4687 final void setNoderefOperands()
4689 if (auto edi = e1.isDotIdExp())
4690 edi.noderef = true;
4691 if (auto edi = e2.isDotIdExp())
4692 edi.noderef = true;
4696 final Expression reorderSettingAAElem(Scope* sc)
4698 BinExp be = this;
4700 auto ie = be.e1.isIndexExp();
4701 if (!ie)
4702 return be;
4703 if (ie.e1.type.toBasetype().ty != Taarray)
4704 return be;
4706 /* Fix evaluation order of setting AA element
4707 * https://issues.dlang.org/show_bug.cgi?id=3825
4708 * Rewrite:
4709 * aa[k1][k2][k3] op= val;
4710 * as:
4711 * auto ref __aatmp = aa;
4712 * auto ref __aakey3 = k1, __aakey2 = k2, __aakey1 = k3;
4713 * auto ref __aaval = val;
4714 * __aatmp[__aakey3][__aakey2][__aakey1] op= __aaval; // assignment
4717 Expression e0;
4718 while (1)
4720 Expression de;
4721 ie.e2 = extractSideEffect(sc, "__aakey", de, ie.e2);
4722 e0 = Expression.combine(de, e0);
4724 auto ie1 = ie.e1.isIndexExp();
4725 if (!ie1 ||
4726 ie1.e1.type.toBasetype().ty != Taarray)
4728 break;
4730 ie = ie1;
4732 assert(ie.e1.type.toBasetype().ty == Taarray);
4734 Expression de;
4735 ie.e1 = extractSideEffect(sc, "__aatmp", de, ie.e1);
4736 e0 = Expression.combine(de, e0);
4738 be.e2 = extractSideEffect(sc, "__aaval", e0, be.e2, true);
4740 //printf("-e0 = %s, be = %s\n", e0.toChars(), be.toChars());
4741 return Expression.combine(e0, be);
4744 override void accept(Visitor v)
4746 v.visit(this);
4750 /***********************************************************
4751 * Binary operator assignment, `+=` `-=` `*=` etc.
4753 extern (C++) class BinAssignExp : BinExp
4755 extern (D) this(const ref Loc loc, EXP op, Expression e1, Expression e2) scope
4757 super(loc, op, e1, e2);
4760 override final bool isLvalue()
4762 return true;
4765 override final Expression toLvalue(Scope* sc, Expression ex)
4767 // Lvalue-ness will be handled in glue layer.
4768 return this;
4771 override final Expression modifiableLvalue(Scope* sc, Expression e)
4773 // should check e1.checkModifiable() ?
4774 return toLvalue(sc, this);
4777 override void accept(Visitor v)
4779 v.visit(this);
4783 /***********************************************************
4784 * A string mixin, `mixin("x")`
4786 * https://dlang.org/spec/expression.html#mixin_expressions
4788 extern (C++) final class MixinExp : Expression
4790 Expressions* exps;
4792 extern (D) this(const ref Loc loc, Expressions* exps)
4794 super(loc, EXP.mixin_);
4795 this.exps = exps;
4798 override MixinExp syntaxCopy()
4800 return new MixinExp(loc, arraySyntaxCopy(exps));
4803 override bool equals(const RootObject o) const
4805 if (this == o)
4806 return true;
4807 auto e = o.isExpression();
4808 if (!e)
4809 return false;
4810 if (auto ce = e.isMixinExp())
4812 if (exps.length != ce.exps.length)
4813 return false;
4814 foreach (i, e1; *exps)
4816 auto e2 = (*ce.exps)[i];
4817 if (e1 != e2 && (!e1 || !e2 || !e1.equals(e2)))
4818 return false;
4820 return true;
4822 return false;
4825 override void accept(Visitor v)
4827 v.visit(this);
4831 /***********************************************************
4832 * An import expression, `import("file.txt")`
4834 * Not to be confused with module imports, `import std.stdio`, which is an `ImportStatement`
4836 * https://dlang.org/spec/expression.html#import_expressions
4838 extern (C++) final class ImportExp : UnaExp
4840 extern (D) this(const ref Loc loc, Expression e)
4842 super(loc, EXP.import_, e);
4845 override void accept(Visitor v)
4847 v.visit(this);
4851 /***********************************************************
4852 * An assert expression, `assert(x == y)`
4854 * https://dlang.org/spec/expression.html#assert_expressions
4856 extern (C++) final class AssertExp : UnaExp
4858 Expression msg;
4860 extern (D) this(const ref Loc loc, Expression e, Expression msg = null)
4862 super(loc, EXP.assert_, e);
4863 this.msg = msg;
4866 override AssertExp syntaxCopy()
4868 return new AssertExp(loc, e1.syntaxCopy(), msg ? msg.syntaxCopy() : null);
4871 override void accept(Visitor v)
4873 v.visit(this);
4877 /***********************************************************
4878 * `throw <e1>` as proposed by DIP 1034.
4880 * Replacement for the deprecated `ThrowStatement` that can be nested
4881 * in other expression.
4883 extern (C++) final class ThrowExp : UnaExp
4885 extern (D) this(const ref Loc loc, Expression e)
4887 super(loc, EXP.throw_, e);
4888 this.type = Type.tnoreturn;
4891 override ThrowExp syntaxCopy()
4893 return new ThrowExp(loc, e1.syntaxCopy());
4896 override void accept(Visitor v)
4898 v.visit(this);
4902 /***********************************************************
4904 extern (C++) final class DotIdExp : UnaExp
4906 Identifier ident;
4907 bool noderef; // true if the result of the expression will never be dereferenced
4908 bool wantsym; // do not replace Symbol with its initializer during semantic()
4909 bool arrow; // ImportC: if -> instead of .
4911 extern (D) this(const ref Loc loc, Expression e, Identifier ident)
4913 super(loc, EXP.dotIdentifier, e);
4914 this.ident = ident;
4917 static DotIdExp create(const ref Loc loc, Expression e, Identifier ident)
4919 return new DotIdExp(loc, e, ident);
4922 override void accept(Visitor v)
4924 v.visit(this);
4928 /***********************************************************
4929 * Mainly just a placeholder
4931 extern (C++) final class DotTemplateExp : UnaExp
4933 TemplateDeclaration td;
4935 extern (D) this(const ref Loc loc, Expression e, TemplateDeclaration td)
4937 super(loc, EXP.dotTemplateDeclaration, e);
4938 this.td = td;
4941 override bool checkType()
4943 error("%s `%s` has no type", td.kind(), toChars());
4944 return true;
4947 override bool checkValue()
4949 error("%s `%s` has no value", td.kind(), toChars());
4950 return true;
4953 override void accept(Visitor v)
4955 v.visit(this);
4959 /***********************************************************
4961 extern (C++) final class DotVarExp : UnaExp
4963 Declaration var;
4964 bool hasOverloads;
4966 extern (D) this(const ref Loc loc, Expression e, Declaration var, bool hasOverloads = true)
4968 if (var.isVarDeclaration())
4969 hasOverloads = false;
4971 super(loc, EXP.dotVariable, e);
4972 //printf("DotVarExp()\n");
4973 this.var = var;
4974 this.hasOverloads = hasOverloads;
4977 override bool isLvalue()
4979 if (e1.op != EXP.structLiteral)
4980 return true;
4981 auto vd = var.isVarDeclaration();
4982 return !(vd && vd.isField());
4985 override Expression toLvalue(Scope* sc, Expression e)
4987 //printf("DotVarExp::toLvalue(%s)\n", toChars());
4988 if (sc && sc.flags & SCOPE.Cfile)
4990 /* C11 6.5.2.3-3: A postfix expression followed by the '.' or '->' operator
4991 * is an lvalue if the first expression is an lvalue.
4993 if (!e1.isLvalue())
4994 return Expression.toLvalue(sc, e);
4996 if (!isLvalue())
4997 return Expression.toLvalue(sc, e);
4998 if (e1.op == EXP.this_ && sc.ctorflow.fieldinit.length && !(sc.ctorflow.callSuper & CSX.any_ctor))
5000 if (VarDeclaration vd = var.isVarDeclaration())
5002 auto ad = vd.isMember2();
5003 if (ad && ad.fields.length == sc.ctorflow.fieldinit.length)
5005 foreach (i, f; ad.fields)
5007 if (f == vd)
5009 if (!(sc.ctorflow.fieldinit[i].csx & CSX.this_ctor))
5011 /* If the address of vd is taken, assume it is thereby initialized
5012 * https://issues.dlang.org/show_bug.cgi?id=15869
5014 modifyFieldVar(loc, sc, vd, e1);
5016 break;
5022 return this;
5025 override Expression modifiableLvalue(Scope* sc, Expression e)
5027 version (none)
5029 printf("DotVarExp::modifiableLvalue(%s)\n", toChars());
5030 printf("e1.type = %s\n", e1.type.toChars());
5031 printf("var.type = %s\n", var.type.toChars());
5034 return Expression.modifiableLvalue(sc, e);
5037 override void accept(Visitor v)
5039 v.visit(this);
5043 /***********************************************************
5044 * foo.bar!(args)
5046 extern (C++) final class DotTemplateInstanceExp : UnaExp
5048 TemplateInstance ti;
5050 extern (D) this(const ref Loc loc, Expression e, Identifier name, Objects* tiargs)
5052 super(loc, EXP.dotTemplateInstance, e);
5053 //printf("DotTemplateInstanceExp()\n");
5054 this.ti = new TemplateInstance(loc, name, tiargs);
5057 extern (D) this(const ref Loc loc, Expression e, TemplateInstance ti)
5059 super(loc, EXP.dotTemplateInstance, e);
5060 this.ti = ti;
5063 override DotTemplateInstanceExp syntaxCopy()
5065 return new DotTemplateInstanceExp(loc, e1.syntaxCopy(), ti.name, TemplateInstance.arraySyntaxCopy(ti.tiargs));
5068 bool findTempDecl(Scope* sc)
5070 static if (LOGSEMANTIC)
5072 printf("DotTemplateInstanceExp::findTempDecl('%s')\n", toChars());
5074 if (ti.tempdecl)
5075 return true;
5077 Expression e = new DotIdExp(loc, e1, ti.name);
5078 e = e.expressionSemantic(sc);
5079 if (e.op == EXP.dot)
5080 e = (cast(DotExp)e).e2;
5082 Dsymbol s = null;
5083 switch (e.op)
5085 case EXP.overloadSet:
5086 s = (cast(OverExp)e).vars;
5087 break;
5089 case EXP.dotTemplateDeclaration:
5090 s = (cast(DotTemplateExp)e).td;
5091 break;
5093 case EXP.scope_:
5094 s = (cast(ScopeExp)e).sds;
5095 break;
5097 case EXP.dotVariable:
5098 s = (cast(DotVarExp)e).var;
5099 break;
5101 case EXP.variable:
5102 s = (cast(VarExp)e).var;
5103 break;
5105 default:
5106 return false;
5108 return ti.updateTempDecl(sc, s);
5111 override bool checkType()
5113 // Same logic as ScopeExp.checkType()
5114 if (ti.tempdecl &&
5115 ti.semantictiargsdone &&
5116 ti.semanticRun == PASS.initial)
5118 error("partial %s `%s` has no type", ti.kind(), toChars());
5119 return true;
5121 return false;
5124 override bool checkValue()
5126 if (ti.tempdecl &&
5127 ti.semantictiargsdone &&
5128 ti.semanticRun == PASS.initial)
5130 error("partial %s `%s` has no value", ti.kind(), toChars());
5131 else
5132 error("%s `%s` has no value", ti.kind(), ti.toChars());
5133 return true;
5136 override void accept(Visitor v)
5138 v.visit(this);
5142 /***********************************************************
5144 extern (C++) final class DelegateExp : UnaExp
5146 FuncDeclaration func;
5147 bool hasOverloads;
5148 VarDeclaration vthis2; // container for multi-context
5150 extern (D) this(const ref Loc loc, Expression e, FuncDeclaration f, bool hasOverloads = true, VarDeclaration vthis2 = null)
5152 super(loc, EXP.delegate_, e);
5153 this.func = f;
5154 this.hasOverloads = hasOverloads;
5155 this.vthis2 = vthis2;
5158 override void accept(Visitor v)
5160 v.visit(this);
5164 /***********************************************************
5166 extern (C++) final class DotTypeExp : UnaExp
5168 Dsymbol sym; // symbol that represents a type
5170 extern (D) this(const ref Loc loc, Expression e, Dsymbol s)
5172 super(loc, EXP.dotType, e);
5173 this.sym = s;
5176 override void accept(Visitor v)
5178 v.visit(this);
5183 * The arguments of a function call
5185 * Contains a list of expressions. If it is a named argument, the `names`
5186 * list has a non-null entry at the same index.
5188 struct ArgumentList
5190 Expressions* arguments; // function arguments
5191 Identifiers* names; // named argument identifiers
5193 size_t length() const @nogc nothrow pure @safe { return arguments ? arguments.length : 0; }
5195 /// Returns: whether this argument list contains any named arguments
5196 bool hasNames() const @nogc nothrow pure @safe
5198 if (names is null)
5199 return false;
5200 foreach (name; *names)
5201 if (name !is null)
5202 return true;
5204 return false;
5208 /***********************************************************
5210 extern (C++) final class CallExp : UnaExp
5212 Expressions* arguments; // function arguments
5213 Identifiers* names; // named argument identifiers
5214 FuncDeclaration f; // symbol to call
5215 bool directcall; // true if a virtual call is devirtualized
5216 bool inDebugStatement; /// true if this was in a debug statement
5217 bool ignoreAttributes; /// don't enforce attributes (e.g. call @gc function in @nogc code)
5218 bool isUfcsRewrite; /// the first argument was pushed in here by a UFCS rewrite
5219 VarDeclaration vthis2; // container for multi-context
5221 /// Puts the `arguments` and `names` into an `ArgumentList` for easily passing them around.
5222 /// The fields are still separate for backwards compatibility
5223 extern (D) ArgumentList argumentList() { return ArgumentList(arguments, names); }
5225 extern (D) this(const ref Loc loc, Expression e, Expressions* exps, Identifiers* names = null)
5227 super(loc, EXP.call, e);
5228 this.arguments = exps;
5229 this.names = names;
5232 extern (D) this(const ref Loc loc, Expression e)
5234 super(loc, EXP.call, e);
5237 extern (D) this(const ref Loc loc, Expression e, Expression earg1)
5239 super(loc, EXP.call, e);
5240 this.arguments = new Expressions();
5241 if (earg1)
5242 this.arguments.push(earg1);
5245 extern (D) this(const ref Loc loc, Expression e, Expression earg1, Expression earg2)
5247 super(loc, EXP.call, e);
5248 auto arguments = new Expressions(2);
5249 (*arguments)[0] = earg1;
5250 (*arguments)[1] = earg2;
5251 this.arguments = arguments;
5254 /***********************************************************
5255 * Instatiates a new function call expression
5256 * Params:
5257 * loc = location
5258 * fd = the declaration of the function to call
5259 * earg1 = the function argument
5261 extern(D) this(const ref Loc loc, FuncDeclaration fd, Expression earg1)
5263 this(loc, new VarExp(loc, fd, false), earg1);
5264 this.f = fd;
5267 static CallExp create(const ref Loc loc, Expression e, Expressions* exps)
5269 return new CallExp(loc, e, exps);
5272 static CallExp create(const ref Loc loc, Expression e)
5274 return new CallExp(loc, e);
5277 static CallExp create(const ref Loc loc, Expression e, Expression earg1)
5279 return new CallExp(loc, e, earg1);
5282 /***********************************************************
5283 * Creates a new function call expression
5284 * Params:
5285 * loc = location
5286 * fd = the declaration of the function to call
5287 * earg1 = the function argument
5289 static CallExp create(const ref Loc loc, FuncDeclaration fd, Expression earg1)
5291 return new CallExp(loc, fd, earg1);
5294 override CallExp syntaxCopy()
5296 return new CallExp(loc, e1.syntaxCopy(), arraySyntaxCopy(arguments), names ? names.copy() : null);
5299 override bool isLvalue()
5301 Type tb = e1.type.toBasetype();
5302 if (tb.ty == Tdelegate || tb.ty == Tpointer)
5303 tb = tb.nextOf();
5304 auto tf = tb.isTypeFunction();
5305 if (tf && tf.isref)
5307 if (auto dve = e1.isDotVarExp())
5308 if (dve.var.isCtorDeclaration())
5309 return false;
5310 return true; // function returns a reference
5312 return false;
5315 override Expression toLvalue(Scope* sc, Expression e)
5317 if (isLvalue())
5318 return this;
5319 return Expression.toLvalue(sc, e);
5322 override Expression addDtorHook(Scope* sc)
5324 /* Only need to add dtor hook if it's a type that needs destruction.
5325 * Use same logic as VarDeclaration::callScopeDtor()
5328 if (auto tf = e1.type.isTypeFunction())
5330 if (tf.isref)
5331 return this;
5334 Type tv = type.baseElemOf();
5335 if (auto ts = tv.isTypeStruct())
5337 StructDeclaration sd = ts.sym;
5338 if (sd.dtor)
5340 /* Type needs destruction, so declare a tmp
5341 * which the back end will recognize and call dtor on
5343 auto tmp = copyToTemp(0, Id.__tmpfordtor.toString(), this);
5344 auto de = new DeclarationExp(loc, tmp);
5345 auto ve = new VarExp(loc, tmp);
5346 Expression e = new CommaExp(loc, de, ve);
5347 e = e.expressionSemantic(sc);
5348 return e;
5351 return this;
5354 override void accept(Visitor v)
5356 v.visit(this);
5361 * Get the called function type from a call expression
5362 * Params:
5363 * ce = function call expression. Must have had semantic analysis done.
5364 * Returns: called function type, or `null` if error / no semantic analysis done
5366 TypeFunction calledFunctionType(CallExp ce)
5368 Type t = ce.e1.type;
5369 if (!t)
5370 return null;
5371 t = t.toBasetype();
5372 if (auto tf = t.isTypeFunction())
5373 return tf;
5374 else if (auto td = t.isTypeDelegate())
5375 return td.nextOf().isTypeFunction();
5376 else
5377 return null;
5380 FuncDeclaration isFuncAddress(Expression e, bool* hasOverloads = null)
5382 if (auto ae = e.isAddrExp())
5384 auto ae1 = ae.e1;
5385 if (auto ve = ae1.isVarExp())
5387 if (hasOverloads)
5388 *hasOverloads = ve.hasOverloads;
5389 return ve.var.isFuncDeclaration();
5391 if (auto dve = ae1.isDotVarExp())
5393 if (hasOverloads)
5394 *hasOverloads = dve.hasOverloads;
5395 return dve.var.isFuncDeclaration();
5398 else
5400 if (auto soe = e.isSymOffExp())
5402 if (hasOverloads)
5403 *hasOverloads = soe.hasOverloads;
5404 return soe.var.isFuncDeclaration();
5406 if (auto dge = e.isDelegateExp())
5408 if (hasOverloads)
5409 *hasOverloads = dge.hasOverloads;
5410 return dge.func.isFuncDeclaration();
5413 return null;
5416 /***********************************************************
5417 * The 'address of' operator, `&p`
5419 extern (C++) final class AddrExp : UnaExp
5421 extern (D) this(const ref Loc loc, Expression e)
5423 super(loc, EXP.address, e);
5426 extern (D) this(const ref Loc loc, Expression e, Type t)
5428 this(loc, e);
5429 type = t;
5432 override void accept(Visitor v)
5434 v.visit(this);
5438 /***********************************************************
5439 * The pointer dereference operator, `*p`
5441 extern (C++) final class PtrExp : UnaExp
5443 extern (D) this(const ref Loc loc, Expression e)
5445 super(loc, EXP.star, e);
5446 //if (e.type)
5447 // type = ((TypePointer *)e.type).next;
5450 extern (D) this(const ref Loc loc, Expression e, Type t)
5452 super(loc, EXP.star, e);
5453 type = t;
5456 override bool isLvalue()
5458 return true;
5461 override Expression toLvalue(Scope* sc, Expression e)
5463 return this;
5466 override Expression modifiableLvalue(Scope* sc, Expression e)
5468 //printf("PtrExp::modifiableLvalue() %s, type %s\n", toChars(), type.toChars());
5469 Declaration var;
5470 if (auto se = e1.isSymOffExp())
5471 var = se.var;
5472 else if (auto ve = e1.isVarExp())
5473 var = ve.var;
5474 if (var && var.type.isFunction_Delegate_PtrToFunction())
5476 if (var.type.isTypeFunction())
5477 error("function `%s` is not an lvalue and cannot be modified", var.toChars());
5478 else
5479 error("function pointed to by `%s` is not an lvalue and cannot be modified", var.toChars());
5480 return ErrorExp.get();
5482 return Expression.modifiableLvalue(sc, e);
5485 override void accept(Visitor v)
5487 v.visit(this);
5491 /***********************************************************
5492 * The negation operator, `-x`
5494 extern (C++) final class NegExp : UnaExp
5496 extern (D) this(const ref Loc loc, Expression e)
5498 super(loc, EXP.negate, e);
5501 override void accept(Visitor v)
5503 v.visit(this);
5507 /***********************************************************
5508 * The unary add operator, `+x`
5510 extern (C++) final class UAddExp : UnaExp
5512 extern (D) this(const ref Loc loc, Expression e) scope
5514 super(loc, EXP.uadd, e);
5517 override void accept(Visitor v)
5519 v.visit(this);
5523 /***********************************************************
5524 * The bitwise complement operator, `~x`
5526 extern (C++) final class ComExp : UnaExp
5528 extern (D) this(const ref Loc loc, Expression e)
5530 super(loc, EXP.tilde, e);
5533 override void accept(Visitor v)
5535 v.visit(this);
5539 /***********************************************************
5540 * The logical not operator, `!x`
5542 extern (C++) final class NotExp : UnaExp
5544 extern (D) this(const ref Loc loc, Expression e)
5546 super(loc, EXP.not, e);
5549 override void accept(Visitor v)
5551 v.visit(this);
5555 /***********************************************************
5556 * The delete operator, `delete x` (deprecated)
5558 * https://dlang.org/spec/expression.html#delete_expressions
5560 extern (C++) final class DeleteExp : UnaExp
5562 bool isRAII; // true if called automatically as a result of scoped destruction
5564 extern (D) this(const ref Loc loc, Expression e, bool isRAII)
5566 super(loc, EXP.delete_, e);
5567 this.isRAII = isRAII;
5570 override void accept(Visitor v)
5572 v.visit(this);
5576 /***********************************************************
5577 * The type cast operator, `cast(T) x`
5579 * It's possible to cast to one type while painting to another type
5581 * https://dlang.org/spec/expression.html#cast_expressions
5583 extern (C++) final class CastExp : UnaExp
5585 Type to; // type to cast to
5586 ubyte mod = cast(ubyte)~0; // MODxxxxx
5588 extern (D) this(const ref Loc loc, Expression e, Type t)
5590 super(loc, EXP.cast_, e);
5591 this.to = t;
5594 /* For cast(const) and cast(immutable)
5596 extern (D) this(const ref Loc loc, Expression e, ubyte mod)
5598 super(loc, EXP.cast_, e);
5599 this.mod = mod;
5602 override CastExp syntaxCopy()
5604 return to ? new CastExp(loc, e1.syntaxCopy(), to.syntaxCopy()) : new CastExp(loc, e1.syntaxCopy(), mod);
5607 override bool isLvalue()
5609 //printf("e1.type = %s, to.type = %s\n", e1.type.toChars(), to.toChars());
5610 if (!e1.isLvalue())
5611 return false;
5612 return (to.ty == Tsarray && (e1.type.ty == Tvector || e1.type.ty == Tsarray)) ||
5613 e1.type.mutableOf().unSharedOf().equals(to.mutableOf().unSharedOf());
5616 override Expression toLvalue(Scope* sc, Expression e)
5618 if (sc && sc.flags & SCOPE.Cfile)
5620 /* C11 6.5.4-5: A cast does not yield an lvalue.
5622 return Expression.toLvalue(sc, e);
5624 if (isLvalue())
5625 return this;
5626 return Expression.toLvalue(sc, e);
5629 override Expression addDtorHook(Scope* sc)
5631 if (to.toBasetype().ty == Tvoid) // look past the cast(void)
5632 e1 = e1.addDtorHook(sc);
5633 return this;
5636 override void accept(Visitor v)
5638 v.visit(this);
5642 /***********************************************************
5644 extern (C++) final class VectorExp : UnaExp
5646 TypeVector to; // the target vector type before semantic()
5647 uint dim = ~0; // number of elements in the vector
5648 OwnedBy ownedByCtfe = OwnedBy.code;
5650 extern (D) this(const ref Loc loc, Expression e, Type t)
5652 super(loc, EXP.vector, e);
5653 assert(t.ty == Tvector);
5654 to = cast(TypeVector)t;
5657 static VectorExp create(const ref Loc loc, Expression e, Type t)
5659 return new VectorExp(loc, e, t);
5662 // Same as create, but doesn't allocate memory.
5663 static void emplace(UnionExp* pue, const ref Loc loc, Expression e, Type type)
5665 emplaceExp!(VectorExp)(pue, loc, e, type);
5668 override VectorExp syntaxCopy()
5670 return new VectorExp(loc, e1.syntaxCopy(), to.syntaxCopy());
5673 override void accept(Visitor v)
5675 v.visit(this);
5679 /***********************************************************
5680 * e1.array property for vectors.
5682 * https://dlang.org/spec/simd.html#properties
5684 extern (C++) final class VectorArrayExp : UnaExp
5686 extern (D) this(const ref Loc loc, Expression e1)
5688 super(loc, EXP.vectorArray, e1);
5691 override bool isLvalue()
5693 return e1.isLvalue();
5696 override Expression toLvalue(Scope* sc, Expression e)
5698 e1 = e1.toLvalue(sc, e);
5699 return this;
5702 override void accept(Visitor v)
5704 v.visit(this);
5708 /***********************************************************
5709 * e1 [lwr .. upr]
5711 * https://dlang.org/spec/expression.html#slice_expressions
5713 extern (C++) final class SliceExp : UnaExp
5715 Expression upr; // null if implicit 0
5716 Expression lwr; // null if implicit [length - 1]
5718 VarDeclaration lengthVar;
5720 private extern(D) static struct BitFields
5722 bool upperIsInBounds; // true if upr <= e1.length
5723 bool lowerIsLessThanUpper; // true if lwr <= upr
5724 bool arrayop; // an array operation, rather than a slice
5726 import dmd.common.bitfields : generateBitFields;
5727 mixin(generateBitFields!(BitFields, ubyte));
5729 /************************************************************/
5730 extern (D) this(const ref Loc loc, Expression e1, IntervalExp ie)
5732 super(loc, EXP.slice, e1);
5733 this.upr = ie ? ie.upr : null;
5734 this.lwr = ie ? ie.lwr : null;
5737 extern (D) this(const ref Loc loc, Expression e1, Expression lwr, Expression upr)
5739 super(loc, EXP.slice, e1);
5740 this.upr = upr;
5741 this.lwr = lwr;
5744 override SliceExp syntaxCopy()
5746 auto se = new SliceExp(loc, e1.syntaxCopy(), lwr ? lwr.syntaxCopy() : null, upr ? upr.syntaxCopy() : null);
5747 se.lengthVar = this.lengthVar; // bug7871
5748 return se;
5751 override bool isLvalue()
5753 /* slice expression is rvalue in default, but
5754 * conversion to reference of static array is only allowed.
5756 return (type && type.toBasetype().ty == Tsarray);
5759 override Expression toLvalue(Scope* sc, Expression e)
5761 //printf("SliceExp::toLvalue(%s) type = %s\n", toChars(), type ? type.toChars() : NULL);
5762 return (type && type.toBasetype().ty == Tsarray) ? this : Expression.toLvalue(sc, e);
5765 override Expression modifiableLvalue(Scope* sc, Expression e)
5767 error("slice expression `%s` is not a modifiable lvalue", toChars());
5768 return this;
5771 override Optional!bool toBool()
5773 return e1.toBool();
5776 override void accept(Visitor v)
5778 v.visit(this);
5782 /***********************************************************
5783 * The `.length` property of an array
5785 extern (C++) final class ArrayLengthExp : UnaExp
5787 extern (D) this(const ref Loc loc, Expression e1)
5789 super(loc, EXP.arrayLength, e1);
5792 override void accept(Visitor v)
5794 v.visit(this);
5798 /***********************************************************
5799 * e1 [ a0, a1, a2, a3 ,... ]
5801 * https://dlang.org/spec/expression.html#index_expressions
5803 extern (C++) final class ArrayExp : UnaExp
5805 Expressions* arguments; // Array of Expression's a0..an
5807 size_t currentDimension; // for opDollar
5808 VarDeclaration lengthVar;
5810 extern (D) this(const ref Loc loc, Expression e1, Expression index = null)
5812 super(loc, EXP.array, e1);
5813 arguments = new Expressions();
5814 if (index)
5815 arguments.push(index);
5818 extern (D) this(const ref Loc loc, Expression e1, Expressions* args)
5820 super(loc, EXP.array, e1);
5821 arguments = args;
5824 override ArrayExp syntaxCopy()
5826 auto ae = new ArrayExp(loc, e1.syntaxCopy(), arraySyntaxCopy(arguments));
5827 ae.lengthVar = this.lengthVar; // bug7871
5828 return ae;
5831 override bool isLvalue()
5833 if (type && type.toBasetype().ty == Tvoid)
5834 return false;
5835 return true;
5838 override Expression toLvalue(Scope* sc, Expression e)
5840 if (type && type.toBasetype().ty == Tvoid)
5841 error("`void`s have no value");
5842 return this;
5845 override void accept(Visitor v)
5847 v.visit(this);
5851 /***********************************************************
5853 extern (C++) final class DotExp : BinExp
5855 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
5857 super(loc, EXP.dot, e1, e2);
5860 override void accept(Visitor v)
5862 v.visit(this);
5866 /***********************************************************
5868 extern (C++) final class CommaExp : BinExp
5870 /// This is needed because AssignExp rewrites CommaExp, hence it needs
5871 /// to trigger the deprecation.
5872 const bool isGenerated;
5874 /// Temporary variable to enable / disable deprecation of comma expression
5875 /// depending on the context.
5876 /// Since most constructor calls are rewritting, the only place where
5877 /// false will be passed will be from the parser.
5878 bool allowCommaExp;
5881 extern (D) this(const ref Loc loc, Expression e1, Expression e2, bool generated = true)
5883 super(loc, EXP.comma, e1, e2);
5884 allowCommaExp = isGenerated = generated;
5887 override bool isLvalue()
5889 return e2.isLvalue();
5892 override Expression toLvalue(Scope* sc, Expression e)
5894 e2 = e2.toLvalue(sc, null);
5895 return this;
5898 override Expression modifiableLvalue(Scope* sc, Expression e)
5900 e2 = e2.modifiableLvalue(sc, e);
5901 return this;
5904 override Optional!bool toBool()
5906 return e2.toBool();
5909 override Expression addDtorHook(Scope* sc)
5911 e2 = e2.addDtorHook(sc);
5912 return this;
5915 override void accept(Visitor v)
5917 v.visit(this);
5921 * If the argument is a CommaExp, set a flag to prevent deprecation messages
5923 * It's impossible to know from CommaExp.semantic if the result will
5924 * be used, hence when there is a result (type != void), a deprecation
5925 * message is always emitted.
5926 * However, some construct can produce a result but won't use it
5927 * (ExpStatement and for loop increment). Those should call this function
5928 * to prevent unwanted deprecations to be emitted.
5930 * Params:
5931 * exp = An expression that discards its result.
5932 * If the argument is null or not a CommaExp, nothing happens.
5934 static void allow(Expression exp)
5936 if (exp)
5937 if (auto ce = exp.isCommaExp())
5938 ce.allowCommaExp = true;
5942 /***********************************************************
5943 * Mainly just a placeholder
5945 extern (C++) final class IntervalExp : Expression
5947 Expression lwr;
5948 Expression upr;
5950 extern (D) this(const ref Loc loc, Expression lwr, Expression upr)
5952 super(loc, EXP.interval);
5953 this.lwr = lwr;
5954 this.upr = upr;
5957 override Expression syntaxCopy()
5959 return new IntervalExp(loc, lwr.syntaxCopy(), upr.syntaxCopy());
5962 override void accept(Visitor v)
5964 v.visit(this);
5968 /***********************************************************
5969 * The `dg.ptr` property, pointing to the delegate's 'context'
5971 * c.f.`DelegateFuncptrExp` for the delegate's function pointer `dg.funcptr`
5973 extern (C++) final class DelegatePtrExp : UnaExp
5975 extern (D) this(const ref Loc loc, Expression e1)
5977 super(loc, EXP.delegatePointer, e1);
5980 override bool isLvalue()
5982 return e1.isLvalue();
5985 override Expression toLvalue(Scope* sc, Expression e)
5987 e1 = e1.toLvalue(sc, e);
5988 return this;
5991 override Expression modifiableLvalue(Scope* sc, Expression e)
5993 if (sc.setUnsafe(false, this.loc, "cannot modify delegate pointer in `@safe` code `%s`", this))
5995 return ErrorExp.get();
5997 return Expression.modifiableLvalue(sc, e);
6000 override void accept(Visitor v)
6002 v.visit(this);
6006 /***********************************************************
6007 * The `dg.funcptr` property, pointing to the delegate's function
6009 * c.f.`DelegatePtrExp` for the delegate's function pointer `dg.ptr`
6011 extern (C++) final class DelegateFuncptrExp : UnaExp
6013 extern (D) this(const ref Loc loc, Expression e1)
6015 super(loc, EXP.delegateFunctionPointer, e1);
6018 override bool isLvalue()
6020 return e1.isLvalue();
6023 override Expression toLvalue(Scope* sc, Expression e)
6025 e1 = e1.toLvalue(sc, e);
6026 return this;
6029 override Expression modifiableLvalue(Scope* sc, Expression e)
6031 if (sc.setUnsafe(false, this.loc, "cannot modify delegate function pointer in `@safe` code `%s`", this))
6033 return ErrorExp.get();
6035 return Expression.modifiableLvalue(sc, e);
6038 override void accept(Visitor v)
6040 v.visit(this);
6044 /***********************************************************
6045 * e1 [ e2 ]
6047 extern (C++) final class IndexExp : BinExp
6049 VarDeclaration lengthVar;
6050 bool modifiable = false; // assume it is an rvalue
6051 bool indexIsInBounds; // true if 0 <= e2 && e2 <= e1.length - 1
6053 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6055 super(loc, EXP.index, e1, e2);
6056 //printf("IndexExp::IndexExp('%s')\n", toChars());
6059 extern (D) this(const ref Loc loc, Expression e1, Expression e2, bool indexIsInBounds)
6061 super(loc, EXP.index, e1, e2);
6062 this.indexIsInBounds = indexIsInBounds;
6063 //printf("IndexExp::IndexExp('%s')\n", toChars());
6066 override IndexExp syntaxCopy()
6068 auto ie = new IndexExp(loc, e1.syntaxCopy(), e2.syntaxCopy());
6069 ie.lengthVar = this.lengthVar; // bug7871
6070 return ie;
6073 override bool isLvalue()
6075 if (e1.op == EXP.assocArrayLiteral)
6076 return false;
6077 if (e1.type.ty == Tsarray ||
6078 (e1.op == EXP.index && e1.type.ty != Tarray))
6080 return e1.isLvalue();
6082 return true;
6085 override Expression toLvalue(Scope* sc, Expression e)
6087 if (isLvalue())
6088 return this;
6089 return Expression.toLvalue(sc, e);
6092 override Expression modifiableLvalue(Scope* sc, Expression e)
6094 //printf("IndexExp::modifiableLvalue(%s)\n", toChars());
6095 Expression ex = markSettingAAElem();
6096 if (ex.op == EXP.error)
6097 return ex;
6099 return Expression.modifiableLvalue(sc, e);
6102 extern (D) Expression markSettingAAElem()
6104 if (e1.type.toBasetype().ty == Taarray)
6106 Type t2b = e2.type.toBasetype();
6107 if (t2b.ty == Tarray && t2b.nextOf().isMutable())
6109 error("associative arrays can only be assigned values with immutable keys, not `%s`", e2.type.toChars());
6110 return ErrorExp.get();
6112 modifiable = true;
6114 if (auto ie = e1.isIndexExp())
6116 Expression ex = ie.markSettingAAElem();
6117 if (ex.op == EXP.error)
6118 return ex;
6119 assert(ex == e1);
6122 return this;
6125 override void accept(Visitor v)
6127 v.visit(this);
6131 /***********************************************************
6132 * The postfix increment/decrement operator, `i++` / `i--`
6134 extern (C++) final class PostExp : BinExp
6136 extern (D) this(EXP op, const ref Loc loc, Expression e)
6138 super(loc, op, e, IntegerExp.literal!1);
6139 assert(op == EXP.minusMinus || op == EXP.plusPlus);
6142 override void accept(Visitor v)
6144 v.visit(this);
6148 /***********************************************************
6149 * The prefix increment/decrement operator, `++i` / `--i`
6151 extern (C++) final class PreExp : UnaExp
6153 extern (D) this(EXP op, const ref Loc loc, Expression e)
6155 super(loc, op, e);
6156 assert(op == EXP.preMinusMinus || op == EXP.prePlusPlus);
6159 override void accept(Visitor v)
6161 v.visit(this);
6165 enum MemorySet
6167 none = 0, // simple assignment
6168 blockAssign = 1, // setting the contents of an array
6169 referenceInit = 2, // setting the reference of STC.ref_ variable
6172 /***********************************************************
6173 * The assignment / initialization operator, `=`
6175 * Note: operator assignment `op=` has a different base class, `BinAssignExp`
6177 extern (C++) class AssignExp : BinExp
6179 MemorySet memset;
6181 /************************************************************/
6182 /* op can be EXP.assign, EXP.construct, or EXP.blit */
6183 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6185 super(loc, EXP.assign, e1, e2);
6188 this(const ref Loc loc, EXP tok, Expression e1, Expression e2)
6190 super(loc, tok, e1, e2);
6193 override final bool isLvalue()
6195 // Array-op 'x[] = y[]' should make an rvalue.
6196 // Setting array length 'x.length = v' should make an rvalue.
6197 if (e1.op == EXP.slice || e1.op == EXP.arrayLength)
6199 return false;
6201 return true;
6204 override final Expression toLvalue(Scope* sc, Expression ex)
6206 if (e1.op == EXP.slice || e1.op == EXP.arrayLength)
6208 return Expression.toLvalue(sc, ex);
6211 /* In front-end level, AssignExp should make an lvalue of e1.
6212 * Taking the address of e1 will be handled in low level layer,
6213 * so this function does nothing.
6215 return this;
6218 override void accept(Visitor v)
6220 v.visit(this);
6224 /***********************************************************
6225 * When an assignment expression is lowered to a druntime call
6226 * this class is used to store the lowering.
6227 * It essentially behaves the same as an AssignExp, but it is
6228 * used to not waste space for other AssignExp that are not
6229 * lowered to anything.
6231 extern (C++) final class LoweredAssignExp : AssignExp
6233 Expression lowering;
6234 extern (D) this(AssignExp exp, Expression lowering)
6236 super(exp.loc, EXP.loweredAssignExp, exp.e1, exp.e2);
6237 this.lowering = lowering;
6240 override const(char)* toChars() const
6242 return lowering.toChars();
6244 override void accept(Visitor v)
6246 v.visit(this);
6250 /***********************************************************
6252 extern (C++) final class ConstructExp : AssignExp
6254 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6256 super(loc, EXP.construct, e1, e2);
6259 // Internal use only. If `v` is a reference variable, the assignment
6260 // will become a reference initialization automatically.
6261 extern (D) this(const ref Loc loc, VarDeclaration v, Expression e2)
6263 auto ve = new VarExp(loc, v);
6264 assert(v.type && ve.type);
6266 super(loc, EXP.construct, ve, e2);
6268 if (v.isReference())
6269 memset = MemorySet.referenceInit;
6272 override void accept(Visitor v)
6274 v.visit(this);
6278 /***********************************************************
6279 * A bit-for-bit copy from `e2` to `e1`
6281 extern (C++) final class BlitExp : AssignExp
6283 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6285 super(loc, EXP.blit, e1, e2);
6288 // Internal use only. If `v` is a reference variable, the assinment
6289 // will become a reference rebinding automatically.
6290 extern (D) this(const ref Loc loc, VarDeclaration v, Expression e2)
6292 auto ve = new VarExp(loc, v);
6293 assert(v.type && ve.type);
6295 super(loc, EXP.blit, ve, e2);
6297 if (v.isReference())
6298 memset = MemorySet.referenceInit;
6301 override void accept(Visitor v)
6303 v.visit(this);
6307 /***********************************************************
6308 * `x += y`
6310 extern (C++) final class AddAssignExp : BinAssignExp
6312 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6314 super(loc, EXP.addAssign, e1, e2);
6317 override void accept(Visitor v)
6319 v.visit(this);
6323 /***********************************************************
6324 * `x -= y`
6326 extern (C++) final class MinAssignExp : BinAssignExp
6328 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6330 super(loc, EXP.minAssign, e1, e2);
6333 override void accept(Visitor v)
6335 v.visit(this);
6339 /***********************************************************
6340 * `x *= y`
6342 extern (C++) final class MulAssignExp : BinAssignExp
6344 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6346 super(loc, EXP.mulAssign, e1, e2);
6349 override void accept(Visitor v)
6351 v.visit(this);
6355 /***********************************************************
6356 * `x /= y`
6358 extern (C++) final class DivAssignExp : BinAssignExp
6360 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6362 super(loc, EXP.divAssign, e1, e2);
6365 override void accept(Visitor v)
6367 v.visit(this);
6371 /***********************************************************
6372 * `x %= y`
6374 extern (C++) final class ModAssignExp : BinAssignExp
6376 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6378 super(loc, EXP.modAssign, e1, e2);
6381 override void accept(Visitor v)
6383 v.visit(this);
6387 /***********************************************************
6388 * `x &= y`
6390 extern (C++) final class AndAssignExp : BinAssignExp
6392 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6394 super(loc, EXP.andAssign, e1, e2);
6397 override void accept(Visitor v)
6399 v.visit(this);
6403 /***********************************************************
6404 * `x |= y`
6406 extern (C++) final class OrAssignExp : BinAssignExp
6408 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6410 super(loc, EXP.orAssign, e1, e2);
6413 override void accept(Visitor v)
6415 v.visit(this);
6419 /***********************************************************
6420 * `x ^= y`
6422 extern (C++) final class XorAssignExp : BinAssignExp
6424 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6426 super(loc, EXP.xorAssign, e1, e2);
6429 override void accept(Visitor v)
6431 v.visit(this);
6435 /***********************************************************
6436 * `x ^^= y`
6438 extern (C++) final class PowAssignExp : BinAssignExp
6440 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6442 super(loc, EXP.powAssign, e1, e2);
6445 override void accept(Visitor v)
6447 v.visit(this);
6451 /***********************************************************
6452 * `x <<= y`
6454 extern (C++) final class ShlAssignExp : BinAssignExp
6456 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6458 super(loc, EXP.leftShiftAssign, e1, e2);
6461 override void accept(Visitor v)
6463 v.visit(this);
6467 /***********************************************************
6468 * `x >>= y`
6470 extern (C++) final class ShrAssignExp : BinAssignExp
6472 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6474 super(loc, EXP.rightShiftAssign, e1, e2);
6477 override void accept(Visitor v)
6479 v.visit(this);
6483 /***********************************************************
6484 * `x >>>= y`
6486 extern (C++) final class UshrAssignExp : BinAssignExp
6488 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6490 super(loc, EXP.unsignedRightShiftAssign, e1, e2);
6493 override void accept(Visitor v)
6495 v.visit(this);
6499 /***********************************************************
6500 * The `~=` operator.
6502 * It can have one of the following operators:
6504 * EXP.concatenateAssign - appending T[] to T[]
6505 * EXP.concatenateElemAssign - appending T to T[]
6506 * EXP.concatenateDcharAssign - appending dchar to T[]
6508 * The parser initially sets it to EXP.concatenateAssign, and semantic() later decides which
6509 * of the three it will be set to.
6511 extern (C++) class CatAssignExp : BinAssignExp
6513 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6515 super(loc, EXP.concatenateAssign, e1, e2);
6518 extern (D) this(const ref Loc loc, EXP tok, Expression e1, Expression e2)
6520 super(loc, tok, e1, e2);
6523 override void accept(Visitor v)
6525 v.visit(this);
6529 /***********************************************************
6530 * The `~=` operator when appending a single element
6532 extern (C++) final class CatElemAssignExp : CatAssignExp
6534 extern (D) this(const ref Loc loc, Type type, Expression e1, Expression e2)
6536 super(loc, EXP.concatenateElemAssign, e1, e2);
6537 this.type = type;
6540 override void accept(Visitor v)
6542 v.visit(this);
6546 /***********************************************************
6547 * The `~=` operator when appending a single `dchar`
6549 extern (C++) final class CatDcharAssignExp : CatAssignExp
6551 extern (D) this(const ref Loc loc, Type type, Expression e1, Expression e2)
6553 super(loc, EXP.concatenateDcharAssign, e1, e2);
6554 this.type = type;
6557 override void accept(Visitor v)
6559 v.visit(this);
6563 /***********************************************************
6564 * The addition operator, `x + y`
6566 * https://dlang.org/spec/expression.html#add_expressions
6568 extern (C++) final class AddExp : BinExp
6570 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6572 super(loc, EXP.add, e1, e2);
6575 override void accept(Visitor v)
6577 v.visit(this);
6581 /***********************************************************
6582 * The minus operator, `x - y`
6584 * https://dlang.org/spec/expression.html#add_expressions
6586 extern (C++) final class MinExp : BinExp
6588 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6590 super(loc, EXP.min, e1, e2);
6593 override void accept(Visitor v)
6595 v.visit(this);
6599 /***********************************************************
6600 * The concatenation operator, `x ~ y`
6602 * https://dlang.org/spec/expression.html#cat_expressions
6604 extern (C++) final class CatExp : BinExp
6606 Expression lowering; // call to druntime hook `_d_arraycatnTX`
6608 extern (D) this(const ref Loc loc, Expression e1, Expression e2) scope
6610 super(loc, EXP.concatenate, e1, e2);
6613 override Expression resolveLoc(const ref Loc loc, Scope* sc)
6615 e1 = e1.resolveLoc(loc, sc);
6616 e2 = e2.resolveLoc(loc, sc);
6617 return this;
6620 override void accept(Visitor v)
6622 v.visit(this);
6626 /***********************************************************
6627 * The multiplication operator, `x * y`
6629 * https://dlang.org/spec/expression.html#mul_expressions
6631 extern (C++) final class MulExp : BinExp
6633 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6635 super(loc, EXP.mul, e1, e2);
6638 override void accept(Visitor v)
6640 v.visit(this);
6644 /***********************************************************
6645 * The division operator, `x / y`
6647 * https://dlang.org/spec/expression.html#mul_expressions
6649 extern (C++) final class DivExp : BinExp
6651 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6653 super(loc, EXP.div, e1, e2);
6656 override void accept(Visitor v)
6658 v.visit(this);
6662 /***********************************************************
6663 * The modulo operator, `x % y`
6665 * https://dlang.org/spec/expression.html#mul_expressions
6667 extern (C++) final class ModExp : BinExp
6669 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6671 super(loc, EXP.mod, e1, e2);
6674 override void accept(Visitor v)
6676 v.visit(this);
6680 /***********************************************************
6681 * The 'power' operator, `x ^^ y`
6683 * https://dlang.org/spec/expression.html#pow_expressions
6685 extern (C++) final class PowExp : BinExp
6687 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6689 super(loc, EXP.pow, e1, e2);
6692 override void accept(Visitor v)
6694 v.visit(this);
6698 /***********************************************************
6699 * The 'shift left' operator, `x << y`
6701 * https://dlang.org/spec/expression.html#shift_expressions
6703 extern (C++) final class ShlExp : BinExp
6705 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6707 super(loc, EXP.leftShift, e1, e2);
6710 override void accept(Visitor v)
6712 v.visit(this);
6716 /***********************************************************
6717 * The 'shift right' operator, `x >> y`
6719 * https://dlang.org/spec/expression.html#shift_expressions
6721 extern (C++) final class ShrExp : BinExp
6723 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6725 super(loc, EXP.rightShift, e1, e2);
6728 override void accept(Visitor v)
6730 v.visit(this);
6734 /***********************************************************
6735 * The 'unsigned shift right' operator, `x >>> y`
6737 * https://dlang.org/spec/expression.html#shift_expressions
6739 extern (C++) final class UshrExp : BinExp
6741 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6743 super(loc, EXP.unsignedRightShift, e1, e2);
6746 override void accept(Visitor v)
6748 v.visit(this);
6752 /***********************************************************
6753 * The bitwise 'and' operator, `x & y`
6755 * https://dlang.org/spec/expression.html#and_expressions
6757 extern (C++) final class AndExp : BinExp
6759 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6761 super(loc, EXP.and, e1, e2);
6764 override void accept(Visitor v)
6766 v.visit(this);
6770 /***********************************************************
6771 * The bitwise 'or' operator, `x | y`
6773 * https://dlang.org/spec/expression.html#or_expressions
6775 extern (C++) final class OrExp : BinExp
6777 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6779 super(loc, EXP.or, e1, e2);
6782 override void accept(Visitor v)
6784 v.visit(this);
6788 /***********************************************************
6789 * The bitwise 'xor' operator, `x ^ y`
6791 * https://dlang.org/spec/expression.html#xor_expressions
6793 extern (C++) final class XorExp : BinExp
6795 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6797 super(loc, EXP.xor, e1, e2);
6800 override void accept(Visitor v)
6802 v.visit(this);
6806 /***********************************************************
6807 * The logical 'and' / 'or' operator, `X && Y` / `X || Y`
6809 * https://dlang.org/spec/expression.html#andand_expressions
6810 * https://dlang.org/spec/expression.html#oror_expressions
6812 extern (C++) final class LogicalExp : BinExp
6814 extern (D) this(const ref Loc loc, EXP op, Expression e1, Expression e2)
6816 super(loc, op, e1, e2);
6817 assert(op == EXP.andAnd || op == EXP.orOr);
6820 override void accept(Visitor v)
6822 v.visit(this);
6826 /***********************************************************
6827 * A comparison operator, `<` `<=` `>` `>=`
6829 * `op` is one of:
6830 * EXP.lessThan, EXP.lessOrEqual, EXP.greaterThan, EXP.greaterOrEqual
6832 * https://dlang.org/spec/expression.html#relation_expressions
6834 extern (C++) final class CmpExp : BinExp
6836 extern (D) this(EXP op, const ref Loc loc, Expression e1, Expression e2)
6838 super(loc, op, e1, e2);
6839 assert(op == EXP.lessThan || op == EXP.lessOrEqual || op == EXP.greaterThan || op == EXP.greaterOrEqual);
6842 override void accept(Visitor v)
6844 v.visit(this);
6848 /***********************************************************
6849 * The `in` operator, `"a" in ["a": 1]`
6851 * Note: `x !in y` is rewritten to `!(x in y)` in the parser
6853 * https://dlang.org/spec/expression.html#in_expressions
6855 extern (C++) final class InExp : BinExp
6857 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6859 super(loc, EXP.in_, e1, e2);
6862 override void accept(Visitor v)
6864 v.visit(this);
6868 /***********************************************************
6869 * Associative array removal, `aa.remove(arg)`
6871 * This deletes the key e1 from the associative array e2
6873 extern (C++) final class RemoveExp : BinExp
6875 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6877 super(loc, EXP.remove, e1, e2);
6878 type = Type.tbool;
6881 override void accept(Visitor v)
6883 v.visit(this);
6887 /***********************************************************
6888 * `==` and `!=`
6890 * EXP.equal and EXP.notEqual
6892 * https://dlang.org/spec/expression.html#equality_expressions
6894 extern (C++) final class EqualExp : BinExp
6896 extern (D) this(EXP op, const ref Loc loc, Expression e1, Expression e2)
6898 super(loc, op, e1, e2);
6899 assert(op == EXP.equal || op == EXP.notEqual);
6902 override void accept(Visitor v)
6904 v.visit(this);
6908 /***********************************************************
6909 * `is` and `!is`
6911 * EXP.identity and EXP.notIdentity
6913 * https://dlang.org/spec/expression.html#identity_expressions
6915 extern (C++) final class IdentityExp : BinExp
6917 extern (D) this(EXP op, const ref Loc loc, Expression e1, Expression e2)
6919 super(loc, op, e1, e2);
6920 assert(op == EXP.identity || op == EXP.notIdentity);
6923 override void accept(Visitor v)
6925 v.visit(this);
6929 /***********************************************************
6930 * The ternary operator, `econd ? e1 : e2`
6932 * https://dlang.org/spec/expression.html#conditional_expressions
6934 extern (C++) final class CondExp : BinExp
6936 Expression econd;
6938 extern (D) this(const ref Loc loc, Expression econd, Expression e1, Expression e2) scope
6940 super(loc, EXP.question, e1, e2);
6941 this.econd = econd;
6944 override CondExp syntaxCopy()
6946 return new CondExp(loc, econd.syntaxCopy(), e1.syntaxCopy(), e2.syntaxCopy());
6949 override bool isLvalue()
6951 return e1.isLvalue() && e2.isLvalue();
6954 override Expression toLvalue(Scope* sc, Expression ex)
6956 // convert (econd ? e1 : e2) to *(econd ? &e1 : &e2)
6957 CondExp e = cast(CondExp)copy();
6958 e.e1 = e1.toLvalue(sc, null).addressOf();
6959 e.e2 = e2.toLvalue(sc, null).addressOf();
6960 e.type = type.pointerTo();
6961 return new PtrExp(loc, e, type);
6964 override Expression modifiableLvalue(Scope* sc, Expression e)
6966 if (!e1.isLvalue() && !e2.isLvalue())
6968 error("conditional expression `%s` is not a modifiable lvalue", toChars());
6969 return ErrorExp.get();
6971 e1 = e1.modifiableLvalue(sc, e1);
6972 e2 = e2.modifiableLvalue(sc, e2);
6973 return toLvalue(sc, this);
6976 void hookDtors(Scope* sc)
6978 extern (C++) final class DtorVisitor : StoppableVisitor
6980 alias visit = typeof(super).visit;
6981 public:
6982 Scope* sc;
6983 CondExp ce;
6984 VarDeclaration vcond;
6985 bool isThen;
6987 extern (D) this(Scope* sc, CondExp ce)
6989 this.sc = sc;
6990 this.ce = ce;
6993 override void visit(Expression e)
6995 //printf("(e = %s)\n", e.toChars());
6998 override void visit(DeclarationExp e)
7000 auto v = e.declaration.isVarDeclaration();
7001 if (v && !v.isDataseg())
7003 if (v._init)
7005 if (auto ei = v._init.isExpInitializer())
7006 walkPostorder(ei.exp, this);
7009 if (v.edtor)
7010 walkPostorder(v.edtor, this);
7012 if (v.needsScopeDtor())
7014 if (!vcond)
7016 vcond = copyToTemp(STC.volatile_ | STC.const_, "__cond", ce.econd);
7017 vcond.dsymbolSemantic(sc);
7019 Expression de = new DeclarationExp(ce.econd.loc, vcond);
7020 de = de.expressionSemantic(sc);
7022 Expression ve = new VarExp(ce.econd.loc, vcond);
7023 ce.econd = Expression.combine(de, ve);
7026 //printf("\t++v = %s, v.edtor = %s\n", v.toChars(), v.edtor.toChars());
7027 Expression ve = new VarExp(vcond.loc, vcond);
7028 if (isThen)
7029 v.edtor = new LogicalExp(v.edtor.loc, EXP.andAnd, ve, v.edtor);
7030 else
7031 v.edtor = new LogicalExp(v.edtor.loc, EXP.orOr, ve, v.edtor);
7032 v.edtor = v.edtor.expressionSemantic(sc);
7033 //printf("\t--v = %s, v.edtor = %s\n", v.toChars(), v.edtor.toChars());
7039 scope DtorVisitor v = new DtorVisitor(sc, this);
7040 //printf("+%s\n", toChars());
7041 v.isThen = true;
7042 walkPostorder(e1, v);
7043 v.isThen = false;
7044 walkPostorder(e2, v);
7045 //printf("-%s\n", toChars());
7048 override void accept(Visitor v)
7050 v.visit(this);
7054 /// Returns: if this token is the `op` for a derived `DefaultInitExp` class.
7055 bool isDefaultInitOp(EXP op) pure nothrow @safe @nogc
7057 return op == EXP.prettyFunction || op == EXP.functionString ||
7058 op == EXP.line || op == EXP.moduleString ||
7059 op == EXP.file || op == EXP.fileFullPath ;
7062 /***********************************************************
7063 * A special keyword when used as a function's default argument
7065 * When possible, special keywords are resolved in the parser, but when
7066 * appearing as a default argument, they result in an expression deriving
7067 * from this base class that is resolved for each function call.
7069 * ---
7070 * const x = __LINE__; // resolved in the parser
7071 * void foo(string file = __FILE__, int line = __LINE__); // DefaultInitExp
7072 * ---
7074 * https://dlang.org/spec/expression.html#specialkeywords
7076 extern (C++) class DefaultInitExp : Expression
7078 extern (D) this(const ref Loc loc, EXP op)
7080 super(loc, op);
7083 override void accept(Visitor v)
7085 v.visit(this);
7089 /***********************************************************
7090 * The `__FILE__` token as a default argument
7092 extern (C++) final class FileInitExp : DefaultInitExp
7094 extern (D) this(const ref Loc loc, EXP tok)
7096 super(loc, tok);
7099 override Expression resolveLoc(const ref Loc loc, Scope* sc)
7101 //printf("FileInitExp::resolve() %s\n", toChars());
7102 const(char)* s;
7103 if (op == EXP.fileFullPath)
7104 s = FileName.toAbsolute(loc.isValid() ? loc.filename : sc._module.srcfile.toChars());
7105 else
7106 s = loc.isValid() ? loc.filename : sc._module.ident.toChars();
7108 Expression e = new StringExp(loc, s.toDString());
7109 return e.expressionSemantic(sc);
7112 override void accept(Visitor v)
7114 v.visit(this);
7118 /***********************************************************
7119 * The `__LINE__` token as a default argument
7121 extern (C++) final class LineInitExp : DefaultInitExp
7123 extern (D) this(const ref Loc loc)
7125 super(loc, EXP.line);
7128 override Expression resolveLoc(const ref Loc loc, Scope* sc)
7130 Expression e = new IntegerExp(loc, loc.linnum, Type.tint32);
7131 return e.expressionSemantic(sc);
7134 override void accept(Visitor v)
7136 v.visit(this);
7140 /***********************************************************
7141 * The `__MODULE__` token as a default argument
7143 extern (C++) final class ModuleInitExp : DefaultInitExp
7145 extern (D) this(const ref Loc loc)
7147 super(loc, EXP.moduleString);
7150 override Expression resolveLoc(const ref Loc loc, Scope* sc)
7152 const auto s = (sc.callsc ? sc.callsc : sc)._module.toPrettyChars().toDString();
7153 Expression e = new StringExp(loc, s);
7154 return e.expressionSemantic(sc);
7157 override void accept(Visitor v)
7159 v.visit(this);
7163 /***********************************************************
7164 * The `__FUNCTION__` token as a default argument
7166 extern (C++) final class FuncInitExp : DefaultInitExp
7168 extern (D) this(const ref Loc loc)
7170 super(loc, EXP.functionString);
7173 override Expression resolveLoc(const ref Loc loc, Scope* sc)
7175 const(char)* s;
7176 if (sc.callsc && sc.callsc.func)
7177 s = sc.callsc.func.Dsymbol.toPrettyChars();
7178 else if (sc.func)
7179 s = sc.func.Dsymbol.toPrettyChars();
7180 else
7181 s = "";
7182 Expression e = new StringExp(loc, s.toDString());
7183 return e.expressionSemantic(sc);
7186 override void accept(Visitor v)
7188 v.visit(this);
7192 /***********************************************************
7193 * The `__PRETTY_FUNCTION__` token as a default argument
7195 extern (C++) final class PrettyFuncInitExp : DefaultInitExp
7197 extern (D) this(const ref Loc loc)
7199 super(loc, EXP.prettyFunction);
7202 override Expression resolveLoc(const ref Loc loc, Scope* sc)
7204 FuncDeclaration fd = (sc.callsc && sc.callsc.func)
7205 ? sc.callsc.func
7206 : sc.func;
7208 const(char)* s;
7209 if (fd)
7211 const funcStr = fd.Dsymbol.toPrettyChars();
7212 OutBuffer buf;
7213 functionToBufferWithIdent(fd.type.isTypeFunction(), &buf, funcStr, fd.isStatic);
7214 s = buf.extractChars();
7216 else
7218 s = "";
7221 Expression e = new StringExp(loc, s.toDString());
7222 e = e.expressionSemantic(sc);
7223 e.type = Type.tstring;
7224 return e;
7227 override void accept(Visitor v)
7229 v.visit(this);
7234 * Objective-C class reference expression.
7236 * Used to get the metaclass of an Objective-C class, `NSObject.Class`.
7238 extern (C++) final class ObjcClassReferenceExp : Expression
7240 ClassDeclaration classDeclaration;
7242 extern (D) this(const ref Loc loc, ClassDeclaration classDeclaration)
7244 super(loc, EXP.objcClassReference);
7245 this.classDeclaration = classDeclaration;
7246 type = objc.getRuntimeMetaclass(classDeclaration).getType();
7249 override void accept(Visitor v)
7251 v.visit(this);
7255 /*******************
7256 * C11 6.5.1.1 Generic Selection
7257 * For ImportC
7259 extern (C++) final class GenericExp : Expression
7261 Expression cntlExp; /// controlling expression of a generic selection (not evaluated)
7262 Types* types; /// type-names for generic associations (null entry for `default`)
7263 Expressions* exps; /// 1:1 mapping of typeNames to exps
7265 extern (D) this(const ref Loc loc, Expression cntlExp, Types* types, Expressions* exps)
7267 super(loc, EXP._Generic);
7268 this.cntlExp = cntlExp;
7269 this.types = types;
7270 this.exps = exps;
7271 assert(types.length == exps.length); // must be the same and >=1
7274 override GenericExp syntaxCopy()
7276 return new GenericExp(loc, cntlExp.syntaxCopy(), Type.arraySyntaxCopy(types), Expression.arraySyntaxCopy(exps));
7279 override void accept(Visitor v)
7281 v.visit(this);
7285 /***************************************
7286 * Parameters:
7287 * sc: scope
7288 * flag: 1: do not issue error message for invalid modification
7289 2: the exp is a DotVarExp and a subfield of the leftmost
7290 variable is modified
7291 * Returns:
7292 * Whether the type is modifiable
7294 extern(D) Modifiable checkModifiable(Expression exp, Scope* sc, ModifyFlags flag = ModifyFlags.none)
7296 switch(exp.op)
7298 case EXP.variable:
7299 auto varExp = cast(VarExp)exp;
7301 //printf("VarExp::checkModifiable %s", varExp.toChars());
7302 assert(varExp.type);
7303 return varExp.var.checkModify(varExp.loc, sc, null, flag);
7305 case EXP.dotVariable:
7306 auto dotVarExp = cast(DotVarExp)exp;
7308 //printf("DotVarExp::checkModifiable %s %s\n", dotVarExp.toChars(), dotVarExp.type.toChars());
7309 if (dotVarExp.e1.op == EXP.this_)
7310 return dotVarExp.var.checkModify(dotVarExp.loc, sc, dotVarExp.e1, flag);
7312 /* https://issues.dlang.org/show_bug.cgi?id=12764
7313 * If inside a constructor and an expression of type `this.field.var`
7314 * is encountered, where `field` is a struct declaration with
7315 * default construction disabled, we must make sure that
7316 * assigning to `var` does not imply that `field` was initialized
7318 if (sc.func && sc.func.isCtorDeclaration())
7320 // if inside a constructor scope and e1 of this DotVarExp
7321 // is another DotVarExp, then check if the leftmost expression is a `this` identifier
7322 if (auto dve = dotVarExp.e1.isDotVarExp())
7324 // Iterate the chain of DotVarExp to find `this`
7325 // Keep track whether access to fields was limited to union members
7326 // s.t. one can initialize an entire struct inside nested unions
7327 // (but not its members)
7328 bool onlyUnion = true;
7329 while (true)
7331 auto v = dve.var.isVarDeclaration();
7332 assert(v);
7334 // Accessing union member?
7335 auto t = v.type.isTypeStruct();
7336 if (!t || !t.sym.isUnionDeclaration())
7337 onlyUnion = false;
7339 // Another DotVarExp left?
7340 if (!dve.e1 || dve.e1.op != EXP.dotVariable)
7341 break;
7343 dve = cast(DotVarExp) dve.e1;
7346 if (dve.e1.op == EXP.this_)
7348 scope v = dve.var.isVarDeclaration();
7349 /* if v is a struct member field with no initializer, no default construction
7350 * and v wasn't intialized before
7352 if (v && v.isField() && !v._init && !v.ctorinit)
7354 if (auto ts = v.type.isTypeStruct())
7356 if (ts.sym.noDefaultCtor)
7358 /* checkModify will consider that this is an initialization
7359 * of v while it is actually an assignment of a field of v
7361 scope modifyLevel = v.checkModify(dotVarExp.loc, sc, dve.e1, !onlyUnion ? (flag | ModifyFlags.fieldAssign) : flag);
7362 if (modifyLevel == Modifiable.initialization)
7364 // https://issues.dlang.org/show_bug.cgi?id=22118
7365 // v is a union type field that was assigned
7366 // a variable, therefore it counts as initialization
7367 if (v.ctorinit)
7368 return Modifiable.initialization;
7370 return Modifiable.yes;
7372 return modifyLevel;
7380 //printf("\te1 = %s\n", e1.toChars());
7381 return dotVarExp.e1.checkModifiable(sc, flag);
7383 case EXP.star:
7384 auto ptrExp = cast(PtrExp)exp;
7385 if (auto se = ptrExp.e1.isSymOffExp())
7387 return se.var.checkModify(ptrExp.loc, sc, null, flag);
7389 else if (auto ae = ptrExp.e1.isAddrExp())
7391 return ae.e1.checkModifiable(sc, flag);
7393 return Modifiable.yes;
7395 case EXP.slice:
7396 auto sliceExp = cast(SliceExp)exp;
7398 //printf("SliceExp::checkModifiable %s\n", sliceExp.toChars());
7399 auto e1 = sliceExp.e1;
7400 if (e1.type.ty == Tsarray || (e1.op == EXP.index && e1.type.ty != Tarray) || e1.op == EXP.slice)
7402 return e1.checkModifiable(sc, flag);
7404 return Modifiable.yes;
7406 case EXP.comma:
7407 return (cast(CommaExp)exp).e2.checkModifiable(sc, flag);
7409 case EXP.index:
7410 auto indexExp = cast(IndexExp)exp;
7411 auto e1 = indexExp.e1;
7412 if (e1.type.ty == Tsarray ||
7413 e1.type.ty == Taarray ||
7414 (e1.op == EXP.index && e1.type.ty != Tarray) ||
7415 e1.op == EXP.slice)
7417 return e1.checkModifiable(sc, flag);
7419 return Modifiable.yes;
7421 case EXP.question:
7422 auto condExp = cast(CondExp)exp;
7423 if (condExp.e1.checkModifiable(sc, flag) != Modifiable.no
7424 && condExp.e2.checkModifiable(sc, flag) != Modifiable.no)
7425 return Modifiable.yes;
7426 return Modifiable.no;
7428 default:
7429 return exp.type ? Modifiable.yes : Modifiable.no; // default modifiable
7434 * Verify if the given identifier is _d_array{,set}ctor.
7436 * Params:
7437 * id = the identifier to verify
7439 * Returns:
7440 * `true` if the identifier corresponds to a construction runtime hook,
7441 * `false` otherwise.
7443 bool isArrayConstruction(const Identifier id)
7445 import dmd.id : Id;
7447 return id == Id._d_arrayctor || id == Id._d_arraysetctor;
7450 /******************************
7451 * Provide efficient way to implement isUnaExp(), isBinExp(), isBinAssignExp()
7453 private immutable ubyte[EXP.max + 1] exptab =
7454 () {
7455 ubyte[EXP.max + 1] tab;
7456 with (EXPFLAGS)
7458 foreach (i; Eunary) { tab[i] |= unary; }
7459 foreach (i; Ebinary) { tab[i] |= unary | binary; }
7460 foreach (i; EbinaryAssign) { tab[i] |= unary | binary | binaryAssign; }
7462 return tab;
7463 } ();
7465 private enum EXPFLAGS : ubyte
7467 unary = 1,
7468 binary = 2,
7469 binaryAssign = 4,
7472 private enum Eunary =
7474 EXP.import_, EXP.assert_, EXP.throw_, EXP.dotIdentifier, EXP.dotTemplateDeclaration,
7475 EXP.dotVariable, EXP.dotTemplateInstance, EXP.delegate_, EXP.dotType, EXP.call,
7476 EXP.address, EXP.star, EXP.negate, EXP.uadd, EXP.tilde, EXP.not, EXP.delete_, EXP.cast_,
7477 EXP.vector, EXP.vectorArray, EXP.slice, EXP.arrayLength, EXP.array, EXP.delegatePointer,
7478 EXP.delegateFunctionPointer, EXP.preMinusMinus, EXP.prePlusPlus,
7481 private enum Ebinary =
7483 EXP.dot, EXP.comma, EXP.index, EXP.minusMinus, EXP.plusPlus, EXP.assign,
7484 EXP.add, EXP.min, EXP.concatenate, EXP.mul, EXP.div, EXP.mod, EXP.pow, EXP.leftShift,
7485 EXP.rightShift, EXP.unsignedRightShift, EXP.and, EXP.or, EXP.xor, EXP.andAnd, EXP.orOr,
7486 EXP.lessThan, EXP.lessOrEqual, EXP.greaterThan, EXP.greaterOrEqual,
7487 EXP.in_, EXP.remove, EXP.equal, EXP.notEqual, EXP.identity, EXP.notIdentity,
7488 EXP.question,
7489 EXP.construct, EXP.blit,
7492 private enum EbinaryAssign =
7494 EXP.addAssign, EXP.minAssign, EXP.mulAssign, EXP.divAssign, EXP.modAssign,
7495 EXP.andAssign, EXP.orAssign, EXP.xorAssign, EXP.powAssign,
7496 EXP.leftShiftAssign, EXP.rightShiftAssign, EXP.unsignedRightShiftAssign,
7497 EXP.concatenateAssign, EXP.concatenateElemAssign, EXP.concatenateDcharAssign,
7500 /// Given a member of the EXP enum, get the class instance size of the corresponding Expression class.
7501 /// Needed because the classes are `extern(C++)`
7502 private immutable ubyte[EXP.max+1] expSize = [
7503 EXP.reserved: 0,
7504 EXP.negate: __traits(classInstanceSize, NegExp),
7505 EXP.cast_: __traits(classInstanceSize, CastExp),
7506 EXP.null_: __traits(classInstanceSize, NullExp),
7507 EXP.assert_: __traits(classInstanceSize, AssertExp),
7508 EXP.array: __traits(classInstanceSize, ArrayExp),
7509 EXP.call: __traits(classInstanceSize, CallExp),
7510 EXP.address: __traits(classInstanceSize, AddrExp),
7511 EXP.type: __traits(classInstanceSize, TypeExp),
7512 EXP.throw_: __traits(classInstanceSize, ThrowExp),
7513 EXP.new_: __traits(classInstanceSize, NewExp),
7514 EXP.delete_: __traits(classInstanceSize, DeleteExp),
7515 EXP.star: __traits(classInstanceSize, PtrExp),
7516 EXP.symbolOffset: __traits(classInstanceSize, SymOffExp),
7517 EXP.variable: __traits(classInstanceSize, VarExp),
7518 EXP.dotVariable: __traits(classInstanceSize, DotVarExp),
7519 EXP.dotIdentifier: __traits(classInstanceSize, DotIdExp),
7520 EXP.dotTemplateInstance: __traits(classInstanceSize, DotTemplateInstanceExp),
7521 EXP.dotType: __traits(classInstanceSize, DotTypeExp),
7522 EXP.slice: __traits(classInstanceSize, SliceExp),
7523 EXP.arrayLength: __traits(classInstanceSize, ArrayLengthExp),
7524 EXP.dollar: __traits(classInstanceSize, DollarExp),
7525 EXP.template_: __traits(classInstanceSize, TemplateExp),
7526 EXP.dotTemplateDeclaration: __traits(classInstanceSize, DotTemplateExp),
7527 EXP.declaration: __traits(classInstanceSize, DeclarationExp),
7528 EXP.dSymbol: __traits(classInstanceSize, DsymbolExp),
7529 EXP.typeid_: __traits(classInstanceSize, TypeidExp),
7530 EXP.uadd: __traits(classInstanceSize, UAddExp),
7531 EXP.remove: __traits(classInstanceSize, RemoveExp),
7532 EXP.newAnonymousClass: __traits(classInstanceSize, NewAnonClassExp),
7533 EXP.arrayLiteral: __traits(classInstanceSize, ArrayLiteralExp),
7534 EXP.assocArrayLiteral: __traits(classInstanceSize, AssocArrayLiteralExp),
7535 EXP.structLiteral: __traits(classInstanceSize, StructLiteralExp),
7536 EXP.classReference: __traits(classInstanceSize, ClassReferenceExp),
7537 EXP.thrownException: __traits(classInstanceSize, ThrownExceptionExp),
7538 EXP.delegatePointer: __traits(classInstanceSize, DelegatePtrExp),
7539 EXP.delegateFunctionPointer: __traits(classInstanceSize, DelegateFuncptrExp),
7540 EXP.lessThan: __traits(classInstanceSize, CmpExp),
7541 EXP.greaterThan: __traits(classInstanceSize, CmpExp),
7542 EXP.lessOrEqual: __traits(classInstanceSize, CmpExp),
7543 EXP.greaterOrEqual: __traits(classInstanceSize, CmpExp),
7544 EXP.equal: __traits(classInstanceSize, EqualExp),
7545 EXP.notEqual: __traits(classInstanceSize, EqualExp),
7546 EXP.identity: __traits(classInstanceSize, IdentityExp),
7547 EXP.notIdentity: __traits(classInstanceSize, IdentityExp),
7548 EXP.index: __traits(classInstanceSize, IndexExp),
7549 EXP.is_: __traits(classInstanceSize, IsExp),
7550 EXP.leftShift: __traits(classInstanceSize, ShlExp),
7551 EXP.rightShift: __traits(classInstanceSize, ShrExp),
7552 EXP.leftShiftAssign: __traits(classInstanceSize, ShlAssignExp),
7553 EXP.rightShiftAssign: __traits(classInstanceSize, ShrAssignExp),
7554 EXP.unsignedRightShift: __traits(classInstanceSize, UshrExp),
7555 EXP.unsignedRightShiftAssign: __traits(classInstanceSize, UshrAssignExp),
7556 EXP.concatenate: __traits(classInstanceSize, CatExp),
7557 EXP.concatenateAssign: __traits(classInstanceSize, CatAssignExp),
7558 EXP.concatenateElemAssign: __traits(classInstanceSize, CatElemAssignExp),
7559 EXP.concatenateDcharAssign: __traits(classInstanceSize, CatDcharAssignExp),
7560 EXP.add: __traits(classInstanceSize, AddExp),
7561 EXP.min: __traits(classInstanceSize, MinExp),
7562 EXP.addAssign: __traits(classInstanceSize, AddAssignExp),
7563 EXP.minAssign: __traits(classInstanceSize, MinAssignExp),
7564 EXP.mul: __traits(classInstanceSize, MulExp),
7565 EXP.div: __traits(classInstanceSize, DivExp),
7566 EXP.mod: __traits(classInstanceSize, ModExp),
7567 EXP.mulAssign: __traits(classInstanceSize, MulAssignExp),
7568 EXP.divAssign: __traits(classInstanceSize, DivAssignExp),
7569 EXP.modAssign: __traits(classInstanceSize, ModAssignExp),
7570 EXP.and: __traits(classInstanceSize, AndExp),
7571 EXP.or: __traits(classInstanceSize, OrExp),
7572 EXP.xor: __traits(classInstanceSize, XorExp),
7573 EXP.andAssign: __traits(classInstanceSize, AndAssignExp),
7574 EXP.orAssign: __traits(classInstanceSize, OrAssignExp),
7575 EXP.xorAssign: __traits(classInstanceSize, XorAssignExp),
7576 EXP.assign: __traits(classInstanceSize, AssignExp),
7577 EXP.not: __traits(classInstanceSize, NotExp),
7578 EXP.tilde: __traits(classInstanceSize, ComExp),
7579 EXP.plusPlus: __traits(classInstanceSize, PostExp),
7580 EXP.minusMinus: __traits(classInstanceSize, PostExp),
7581 EXP.construct: __traits(classInstanceSize, ConstructExp),
7582 EXP.blit: __traits(classInstanceSize, BlitExp),
7583 EXP.dot: __traits(classInstanceSize, DotExp),
7584 EXP.comma: __traits(classInstanceSize, CommaExp),
7585 EXP.question: __traits(classInstanceSize, CondExp),
7586 EXP.andAnd: __traits(classInstanceSize, LogicalExp),
7587 EXP.orOr: __traits(classInstanceSize, LogicalExp),
7588 EXP.prePlusPlus: __traits(classInstanceSize, PreExp),
7589 EXP.preMinusMinus: __traits(classInstanceSize, PreExp),
7590 EXP.identifier: __traits(classInstanceSize, IdentifierExp),
7591 EXP.string_: __traits(classInstanceSize, StringExp),
7592 EXP.this_: __traits(classInstanceSize, ThisExp),
7593 EXP.super_: __traits(classInstanceSize, SuperExp),
7594 EXP.halt: __traits(classInstanceSize, HaltExp),
7595 EXP.tuple: __traits(classInstanceSize, TupleExp),
7596 EXP.error: __traits(classInstanceSize, ErrorExp),
7597 EXP.void_: __traits(classInstanceSize, VoidInitExp),
7598 EXP.int64: __traits(classInstanceSize, IntegerExp),
7599 EXP.float64: __traits(classInstanceSize, RealExp),
7600 EXP.complex80: __traits(classInstanceSize, ComplexExp),
7601 EXP.import_: __traits(classInstanceSize, ImportExp),
7602 EXP.delegate_: __traits(classInstanceSize, DelegateExp),
7603 EXP.function_: __traits(classInstanceSize, FuncExp),
7604 EXP.mixin_: __traits(classInstanceSize, MixinExp),
7605 EXP.in_: __traits(classInstanceSize, InExp),
7606 EXP.break_: __traits(classInstanceSize, CTFEExp),
7607 EXP.continue_: __traits(classInstanceSize, CTFEExp),
7608 EXP.goto_: __traits(classInstanceSize, CTFEExp),
7609 EXP.scope_: __traits(classInstanceSize, ScopeExp),
7610 EXP.traits: __traits(classInstanceSize, TraitsExp),
7611 EXP.overloadSet: __traits(classInstanceSize, OverExp),
7612 EXP.line: __traits(classInstanceSize, LineInitExp),
7613 EXP.file: __traits(classInstanceSize, FileInitExp),
7614 EXP.fileFullPath: __traits(classInstanceSize, FileInitExp),
7615 EXP.moduleString: __traits(classInstanceSize, ModuleInitExp),
7616 EXP.functionString: __traits(classInstanceSize, FuncInitExp),
7617 EXP.prettyFunction: __traits(classInstanceSize, PrettyFuncInitExp),
7618 EXP.pow: __traits(classInstanceSize, PowExp),
7619 EXP.powAssign: __traits(classInstanceSize, PowAssignExp),
7620 EXP.vector: __traits(classInstanceSize, VectorExp),
7621 EXP.voidExpression: __traits(classInstanceSize, CTFEExp),
7622 EXP.cantExpression: __traits(classInstanceSize, CTFEExp),
7623 EXP.showCtfeContext: __traits(classInstanceSize, CTFEExp),
7624 EXP.objcClassReference: __traits(classInstanceSize, ObjcClassReferenceExp),
7625 EXP.vectorArray: __traits(classInstanceSize, VectorArrayExp),
7626 EXP.compoundLiteral: __traits(classInstanceSize, CompoundLiteralExp),
7627 EXP._Generic: __traits(classInstanceSize, GenericExp),
7628 EXP.interval: __traits(classInstanceSize, IntervalExp),
7629 EXP.loweredAssignExp : __traits(classInstanceSize, LoweredAssignExp),