d: Merge upstream dmd, druntime 4c18eed967, phobos d945686a4.
[official-gcc.git] / gcc / d / dmd / expression.d
blob720523174b77f947cf5508c731306d845984b781
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.errorsink;
44 import dmd.escape;
45 import dmd.expressionsem;
46 import dmd.func;
47 import dmd.globals;
48 import dmd.hdrgen;
49 import dmd.id;
50 import dmd.identifier;
51 import dmd.init;
52 import dmd.inline;
53 import dmd.location;
54 import dmd.mtype;
55 import dmd.nspace;
56 import dmd.objc;
57 import dmd.opover;
58 import dmd.optimize;
59 import dmd.postordervisitor;
60 import dmd.root.complex;
61 import dmd.root.ctfloat;
62 import dmd.root.filename;
63 import dmd.common.outbuffer;
64 import dmd.root.optional;
65 import dmd.root.rmem;
66 import dmd.root.rootobject;
67 import dmd.root.string;
68 import dmd.root.utf;
69 import dmd.safe;
70 import dmd.sideeffect;
71 import dmd.target;
72 import dmd.tokens;
73 import dmd.typesem;
74 import dmd.visitor;
76 enum LOGSEMANTIC = false;
78 void emplaceExp(T : Expression, Args...)(void* p, Args args)
80 static if (__VERSION__ < 2099)
81 const init = typeid(T).initializer;
82 else
83 const init = __traits(initSymbol, T);
84 p[0 .. __traits(classInstanceSize, T)] = init[];
85 (cast(T)p).__ctor(args);
88 void emplaceExp(T : UnionExp)(T* p, Expression e)
90 memcpy(p, cast(void*)e, e.size);
93 /// Return value for `checkModifiable`
94 enum Modifiable
96 /// Not modifiable
97 no,
98 /// Modifiable (the type is mutable)
99 yes,
100 /// Modifiable because it is initialization
101 initialization,
104 * Specifies how the checkModify deals with certain situations
106 enum ModifyFlags
108 /// Issue error messages on invalid modifications of the variable
109 none,
110 /// No errors are emitted for invalid modifications
111 noError = 0x1,
112 /// The modification occurs for a subfield of the current variable
113 fieldAssign = 0x2,
116 /****************************************
117 * Find the first non-comma expression.
118 * Params:
119 * e = Expressions connected by commas
120 * Returns:
121 * left-most non-comma expression
123 inout(Expression) firstComma(inout Expression e)
125 Expression ex = cast()e;
126 while (ex.op == EXP.comma)
127 ex = (cast(CommaExp)ex).e1;
128 return cast(inout)ex;
132 /****************************************
133 * Find the last non-comma expression.
134 * Params:
135 * e = Expressions connected by commas
136 * Returns:
137 * right-most non-comma expression
140 inout(Expression) lastComma(inout Expression e)
142 Expression ex = cast()e;
143 while (ex.op == EXP.comma)
144 ex = (cast(CommaExp)ex).e2;
145 return cast(inout)ex;
149 /*****************************************
150 * Determine if `this` is available by walking up the enclosing
151 * scopes until a function is found.
153 * Params:
154 * sc = where to start looking for the enclosing function
155 * Returns:
156 * Found function if it satisfies `isThis()`, otherwise `null`
158 FuncDeclaration hasThis(Scope* sc)
160 //printf("hasThis()\n");
161 Dsymbol p = sc.parent;
162 while (p && p.isTemplateMixin())
163 p = p.parent;
164 FuncDeclaration fdthis = p ? p.isFuncDeclaration() : null;
165 //printf("fdthis = %p, '%s'\n", fdthis, fdthis ? fdthis.toChars() : "");
167 // Go upwards until we find the enclosing member function
168 FuncDeclaration fd = fdthis;
169 while (1)
171 if (!fd)
173 return null;
175 if (!fd.isNested() || fd.isThis() || (fd.hasDualContext() && fd.isMember2()))
176 break;
178 Dsymbol parent = fd.parent;
179 while (1)
181 if (!parent)
182 return null;
183 TemplateInstance ti = parent.isTemplateInstance();
184 if (ti)
185 parent = ti.parent;
186 else
187 break;
189 fd = parent.isFuncDeclaration();
192 if (!fd.isThis() && !(fd.hasDualContext() && fd.isMember2()))
194 return null;
197 assert(fd.vthis);
198 return fd;
202 /***********************************
203 * Determine if a `this` is needed to access `d`.
204 * Params:
205 * sc = context
206 * d = declaration to check
207 * Returns:
208 * true means a `this` is needed
210 bool isNeedThisScope(Scope* sc, Declaration d)
212 if (sc.intypeof == 1)
213 return false;
215 AggregateDeclaration ad = d.isThis();
216 if (!ad)
217 return false;
218 //printf("d = %s, ad = %s\n", d.toChars(), ad.toChars());
220 for (Dsymbol s = sc.parent; s; s = s.toParentLocal())
222 //printf("\ts = %s %s, toParent2() = %p\n", s.kind(), s.toChars(), s.toParent2());
223 if (AggregateDeclaration ad2 = s.isAggregateDeclaration())
225 if (ad2 == ad)
226 return false;
227 else if (ad2.isNested())
228 continue;
229 else
230 return true;
232 if (FuncDeclaration f = s.isFuncDeclaration())
234 if (f.isMemberLocal())
235 break;
238 return true;
241 /****************************************
242 * Expand tuples in-place.
244 * Example:
245 * When there's a call `f(10, pair: AliasSeq!(20, 30), single: 40)`, the input is:
246 * `exps = [10, (20, 30), 40]`
247 * `names = [null, "pair", "single"]`
248 * The arrays will be modified to:
249 * `exps = [10, 20, 30, 40]`
250 * `names = [null, "pair", null, "single"]`
252 * Params:
253 * exps = array of Expressions
254 * names = optional array of names corresponding to Expressions
256 extern (C++) void expandTuples(Expressions* exps, Identifiers* names = null)
258 //printf("expandTuples()\n");
259 if (exps is null)
260 return;
262 if (names)
264 if (exps.length != names.length)
266 printf("exps.length = %d, names.length = %d\n", cast(int) exps.length, cast(int) names.length);
267 printf("exps = %s, names = %s\n", exps.toChars(), names.toChars());
268 if (exps.length > 0)
269 printf("%s\n", (*exps)[0].loc.toChars());
270 assert(0);
274 // At `index`, a tuple of length `length` is expanded. Insert corresponding nulls in `names`.
275 void expandNames(size_t index, size_t length)
277 if (names)
279 if (length == 0)
281 names.remove(index);
282 return;
284 foreach (i; 1 .. length)
286 names.insert(index + i, cast(Identifier) null);
291 for (size_t i = 0; i < exps.length; i++)
293 Expression arg = (*exps)[i];
294 if (!arg)
295 continue;
297 // Look for tuple with 0 members
298 if (auto e = arg.isTypeExp())
300 if (auto tt = e.type.toBasetype().isTypeTuple())
302 if (!tt.arguments || tt.arguments.length == 0)
304 exps.remove(i);
305 expandNames(i, 0);
306 if (i == exps.length)
307 return;
309 else // Expand a TypeTuple
311 exps.remove(i);
312 auto texps = new Expressions(tt.arguments.length);
313 foreach (j, a; *tt.arguments)
314 (*texps)[j] = new TypeExp(e.loc, a.type);
315 exps.insert(i, texps);
316 expandNames(i, texps.length);
318 i--;
319 continue;
323 // Inline expand all the tuples
324 while (arg.op == EXP.tuple)
326 TupleExp te = cast(TupleExp)arg;
327 exps.remove(i); // remove arg
328 exps.insert(i, te.exps); // replace with tuple contents
329 expandNames(i, te.exps.length);
330 if (i == exps.length)
331 return; // empty tuple, no more arguments
332 (*exps)[i] = Expression.combine(te.e0, (*exps)[i]);
333 arg = (*exps)[i];
338 /****************************************
339 * Expand alias this tuples.
341 TupleDeclaration isAliasThisTuple(Expression e)
343 if (!e.type)
344 return null;
346 Type t = e.type.toBasetype();
347 while (true)
349 if (Dsymbol s = t.toDsymbol(null))
351 if (auto ad = s.isAggregateDeclaration())
353 s = ad.aliasthis ? ad.aliasthis.sym : null;
354 if (s && s.isVarDeclaration())
356 TupleDeclaration td = s.isVarDeclaration().toAlias().isTupleDeclaration();
357 if (td && td.isexp)
358 return td;
360 if (Type att = t.aliasthisOf())
362 t = att;
363 continue;
367 return null;
371 /****************************************
372 * If `s` is a function template, i.e. the only member of a template
373 * and that member is a function, return that template.
374 * Params:
375 * s = symbol that might be a function template
376 * Returns:
377 * template for that function, otherwise null
379 TemplateDeclaration getFuncTemplateDecl(Dsymbol s) @safe
381 FuncDeclaration f = s.isFuncDeclaration();
382 if (f && f.parent)
384 if (auto ti = f.parent.isTemplateInstance())
386 if (!ti.isTemplateMixin() && ti.tempdecl)
388 auto td = ti.tempdecl.isTemplateDeclaration();
389 if (td.onemember && td.ident == f.ident)
391 return td;
396 return null;
399 /************************************************
400 * If we want the value of this expression, but do not want to call
401 * the destructor on it.
403 Expression valueNoDtor(Expression e)
405 auto ex = lastComma(e);
407 if (auto ce = ex.isCallExp())
409 /* The struct value returned from the function is transferred
410 * so do not call the destructor on it.
411 * Recognize:
412 * ((S _ctmp = S.init), _ctmp).this(...)
413 * and make sure the destructor is not called on _ctmp
414 * BUG: if ex is a CommaExp, we should go down the right side.
416 if (auto dve = ce.e1.isDotVarExp())
418 if (dve.var.isCtorDeclaration())
420 // It's a constructor call
421 if (auto comma = dve.e1.isCommaExp())
423 if (auto ve = comma.e2.isVarExp())
425 VarDeclaration ctmp = ve.var.isVarDeclaration();
426 if (ctmp)
428 ctmp.storage_class |= STC.nodtor;
429 assert(!ce.isLvalue());
436 else if (auto ve = ex.isVarExp())
438 auto vtmp = ve.var.isVarDeclaration();
439 if (vtmp && (vtmp.storage_class & STC.rvalue))
441 vtmp.storage_class |= STC.nodtor;
444 return e;
447 /*********************************************
448 * If e is an instance of a struct, and that struct has a copy constructor,
449 * rewrite e as:
450 * (tmp = e),tmp
451 * Input:
452 * sc = just used to specify the scope of created temporary variable
453 * destinationType = the type of the object on which the copy constructor is called;
454 * may be null if the struct defines a postblit
456 private Expression callCpCtor(Scope* sc, Expression e, Type destinationType)
458 if (auto ts = e.type.baseElemOf().isTypeStruct())
460 StructDeclaration sd = ts.sym;
461 if (sd.postblit || sd.hasCopyCtor)
463 /* Create a variable tmp, and replace the argument e with:
464 * (tmp = e),tmp
465 * and let AssignExp() handle the construction.
466 * This is not the most efficient, ideally tmp would be constructed
467 * directly onto the stack.
469 auto tmp = copyToTemp(STC.rvalue, "__copytmp", e);
470 if (sd.hasCopyCtor && destinationType)
472 // https://issues.dlang.org/show_bug.cgi?id=22619
473 // If the destination type is inout we can preserve it
474 // only if inside an inout function; if we are not inside
475 // an inout function, then we will preserve the type of
476 // the source
477 if (destinationType.hasWild && !(sc.func.storage_class & STC.wild))
478 tmp.type = e.type;
479 else
480 tmp.type = destinationType;
482 tmp.storage_class |= STC.nodtor;
483 tmp.dsymbolSemantic(sc);
484 Expression de = new DeclarationExp(e.loc, tmp);
485 Expression ve = new VarExp(e.loc, tmp);
486 de.type = Type.tvoid;
487 ve.type = e.type;
488 return Expression.combine(de, ve);
491 return e;
494 /************************************************
495 * Handle the postblit call on lvalue, or the move of rvalue.
497 * Params:
498 * sc = the scope where the expression is encountered
499 * e = the expression the needs to be moved or copied (source)
500 * t = if the struct defines a copy constructor, the type of the destination
502 * Returns:
503 * The expression that copy constructs or moves the value.
505 extern (D) Expression doCopyOrMove(Scope *sc, Expression e, Type t = null)
507 if (auto ce = e.isCondExp())
509 ce.e1 = doCopyOrMove(sc, ce.e1);
510 ce.e2 = doCopyOrMove(sc, ce.e2);
512 else
514 e = e.isLvalue() ? callCpCtor(sc, e, t) : valueNoDtor(e);
516 return e;
519 /****************************************************************/
520 /* A type meant as a union of all the Expression types,
521 * to serve essentially as a Variant that will sit on the stack
522 * during CTFE to reduce memory consumption.
524 extern (C++) struct UnionExp
526 // yes, default constructor does nothing
527 extern (D) this(Expression e)
529 memcpy(&this, cast(void*)e, e.size);
532 /* Extract pointer to Expression
534 extern (C++) Expression exp() return
536 return cast(Expression)&u;
539 /* Convert to an allocated Expression
541 extern (C++) Expression copy()
543 Expression e = exp();
544 //if (e.size > sizeof(u)) printf("%s\n", EXPtoString(e.op).ptr);
545 assert(e.size <= u.sizeof);
546 switch (e.op)
548 case EXP.cantExpression: return CTFEExp.cantexp;
549 case EXP.voidExpression: return CTFEExp.voidexp;
550 case EXP.break_: return CTFEExp.breakexp;
551 case EXP.continue_: return CTFEExp.continueexp;
552 case EXP.goto_: return CTFEExp.gotoexp;
553 default: return e.copy();
557 private:
558 // Ensure that the union is suitably aligned.
559 align(8) union _AnonStruct_u
561 char[__traits(classInstanceSize, Expression)] exp;
562 char[__traits(classInstanceSize, IntegerExp)] integerexp;
563 char[__traits(classInstanceSize, ErrorExp)] errorexp;
564 char[__traits(classInstanceSize, RealExp)] realexp;
565 char[__traits(classInstanceSize, ComplexExp)] complexexp;
566 char[__traits(classInstanceSize, SymOffExp)] symoffexp;
567 char[__traits(classInstanceSize, StringExp)] stringexp;
568 char[__traits(classInstanceSize, ArrayLiteralExp)] arrayliteralexp;
569 char[__traits(classInstanceSize, AssocArrayLiteralExp)] assocarrayliteralexp;
570 char[__traits(classInstanceSize, StructLiteralExp)] structliteralexp;
571 char[__traits(classInstanceSize, CompoundLiteralExp)] compoundliteralexp;
572 char[__traits(classInstanceSize, NullExp)] nullexp;
573 char[__traits(classInstanceSize, DotVarExp)] dotvarexp;
574 char[__traits(classInstanceSize, AddrExp)] addrexp;
575 char[__traits(classInstanceSize, IndexExp)] indexexp;
576 char[__traits(classInstanceSize, SliceExp)] sliceexp;
577 char[__traits(classInstanceSize, VectorExp)] vectorexp;
580 _AnonStruct_u u;
583 /************************ TypeDotIdExp ************************************/
584 /* Things like:
585 * int.size
586 * foo.size
587 * (foo).size
588 * cast(foo).size
590 DotIdExp typeDotIdExp(const ref Loc loc, Type type, Identifier ident) @safe
592 return new DotIdExp(loc, new TypeExp(loc, type), ident);
595 /***************************************************
596 * Given an Expression, find the variable it really is.
598 * For example, `a[index]` is really `a`, and `s.f` is really `s`.
599 * Params:
600 * e = Expression to look at
601 * Returns:
602 * variable if there is one, null if not
604 VarDeclaration expToVariable(Expression e)
606 while (1)
608 switch (e.op)
610 case EXP.variable:
611 return (cast(VarExp)e).var.isVarDeclaration();
613 case EXP.dotVariable:
614 e = (cast(DotVarExp)e).e1;
615 continue;
617 case EXP.index:
619 IndexExp ei = cast(IndexExp)e;
620 e = ei.e1;
621 Type ti = e.type.toBasetype();
622 if (ti.ty == Tsarray)
623 continue;
624 return null;
627 case EXP.slice:
629 SliceExp ei = cast(SliceExp)e;
630 e = ei.e1;
631 Type ti = e.type.toBasetype();
632 if (ti.ty == Tsarray)
633 continue;
634 return null;
637 case EXP.this_:
638 case EXP.super_:
639 return (cast(ThisExp)e).var.isVarDeclaration();
641 // Temporaries for rvalues that need destruction
642 // are of form: (T s = rvalue, s). For these cases
643 // we can just return var declaration of `s`. However,
644 // this is intentionally not calling `Expression.extractLast`
645 // because at this point we cannot infer the var declaration
646 // of more complex generated comma expressions such as the
647 // one for the array append hook.
648 case EXP.comma:
650 if (auto ve = e.isCommaExp().e2.isVarExp())
651 return ve.var.isVarDeclaration();
653 return null;
655 default:
656 return null;
661 enum OwnedBy : ubyte
663 code, // normal code expression in AST
664 ctfe, // value expression for CTFE
665 cache, // constant value cached for CTFE
668 enum WANTvalue = 0; // default
669 enum WANTexpand = 1; // expand const/immutable variables if possible
671 /***********************************************************
672 * https://dlang.org/spec/expression.html#expression
674 extern (C++) abstract class Expression : ASTNode
676 Type type; // !=null means that semantic() has been run
677 Loc loc; // file location
678 const EXP op; // to minimize use of dynamic_cast
680 extern (D) this(const ref Loc loc, EXP op) scope @safe
682 //printf("Expression::Expression(op = %d) this = %p\n", op, this);
683 this.loc = loc;
684 this.op = op;
687 /// Returns: class instance size of this expression (implemented manually because `extern(C++)`)
688 final size_t size() nothrow @nogc pure @safe const { return expSize[op]; }
690 static void _init()
692 CTFEExp.cantexp = new CTFEExp(EXP.cantExpression);
693 CTFEExp.voidexp = new CTFEExp(EXP.voidExpression);
694 CTFEExp.breakexp = new CTFEExp(EXP.break_);
695 CTFEExp.continueexp = new CTFEExp(EXP.continue_);
696 CTFEExp.gotoexp = new CTFEExp(EXP.goto_);
697 CTFEExp.showcontext = new CTFEExp(EXP.showCtfeContext);
701 * Deinitializes the global state of the compiler.
703 * This can be used to restore the state set by `_init` to its original
704 * state.
706 static void deinitialize()
708 CTFEExp.cantexp = CTFEExp.cantexp.init;
709 CTFEExp.voidexp = CTFEExp.voidexp.init;
710 CTFEExp.breakexp = CTFEExp.breakexp.init;
711 CTFEExp.continueexp = CTFEExp.continueexp.init;
712 CTFEExp.gotoexp = CTFEExp.gotoexp.init;
713 CTFEExp.showcontext = CTFEExp.showcontext.init;
716 /*********************************
717 * Does *not* do a deep copy.
719 final Expression copy()
721 Expression e;
722 if (!size)
724 debug
726 fprintf(stderr, "No expression copy for: %s\n", toChars());
727 printf("op = %d\n", op);
729 assert(0);
732 // memory never freed, so can use the faster bump-pointer-allocation
733 e = cast(Expression)allocmemory(size);
734 //printf("Expression::copy(op = %d) e = %p\n", op, e);
735 return cast(Expression)memcpy(cast(void*)e, cast(void*)this, size);
738 Expression syntaxCopy()
740 //printf("Expression::syntaxCopy()\n");
741 //print();
742 return copy();
745 // kludge for template.isExpression()
746 override final DYNCAST dyncast() const
748 return DYNCAST.expression;
751 override const(char)* toChars() const
753 OutBuffer buf;
754 HdrGenState hgs;
755 toCBuffer(this, buf, hgs);
756 return buf.extractChars();
759 /**********************************
760 * Combine e1 and e2 by CommaExp if both are not NULL.
762 extern (D) static Expression combine(Expression e1, Expression e2) @safe
764 if (e1)
766 if (e2)
768 e1 = new CommaExp(e1.loc, e1, e2);
769 e1.type = e2.type;
772 else
773 e1 = e2;
774 return e1;
777 extern (D) static Expression combine(Expression e1, Expression e2, Expression e3) @safe
779 return combine(combine(e1, e2), e3);
782 extern (D) static Expression combine(Expression e1, Expression e2, Expression e3, Expression e4) @safe
784 return combine(combine(e1, e2), combine(e3, e4));
787 /**********************************
788 * If 'e' is a tree of commas, returns the rightmost expression
789 * by stripping off it from the tree. The remained part of the tree
790 * is returned via e0.
791 * Otherwise 'e' is directly returned and e0 is set to NULL.
793 extern (D) static Expression extractLast(Expression e, out Expression e0) @safe
795 if (e.op != EXP.comma)
797 return e;
800 CommaExp ce = cast(CommaExp)e;
801 if (ce.e2.op != EXP.comma)
803 e0 = ce.e1;
804 return ce.e2;
806 else
808 e0 = e;
810 Expression* pce = &ce.e2;
811 while ((cast(CommaExp)(*pce)).e2.op == EXP.comma)
813 pce = &(cast(CommaExp)(*pce)).e2;
815 assert((*pce).op == EXP.comma);
816 ce = cast(CommaExp)(*pce);
817 *pce = ce.e1;
819 return ce.e2;
823 extern (D) static Expressions* arraySyntaxCopy(Expressions* exps)
825 Expressions* a = null;
826 if (exps)
828 a = new Expressions(exps.length);
829 foreach (i, e; *exps)
831 (*a)[i] = e ? e.syntaxCopy() : null;
834 return a;
837 dinteger_t toInteger()
839 //printf("Expression %s\n", EXPtoString(op).ptr);
840 if (!type.isTypeError())
841 error(loc, "integer constant expression expected instead of `%s`", toChars());
842 return 0;
845 uinteger_t toUInteger()
847 //printf("Expression %s\n", EXPtoString(op).ptr);
848 return cast(uinteger_t)toInteger();
851 real_t toReal()
853 error(loc, "floating point constant expression expected instead of `%s`", toChars());
854 return CTFloat.zero;
857 real_t toImaginary()
859 error(loc, "floating point constant expression expected instead of `%s`", toChars());
860 return CTFloat.zero;
863 complex_t toComplex()
865 error(loc, "floating point constant expression expected instead of `%s`", toChars());
866 return complex_t(CTFloat.zero);
869 StringExp toStringExp()
871 return null;
874 /***************************************
875 * Return !=0 if expression is an lvalue.
877 bool isLvalue()
879 return false;
882 /*******************************
883 * Give error if we're not an lvalue.
884 * If we can, convert expression to be an lvalue.
886 Expression toLvalue(Scope* sc, Expression e)
888 if (!e)
889 e = this;
890 else if (!loc.isValid())
891 loc = e.loc;
893 if (e.op == EXP.type)
894 error(loc, "`%s` is a `%s` definition and cannot be modified", e.type.toChars(), e.type.kind());
895 else
896 error(loc, "`%s` is not an lvalue and cannot be modified", e.toChars());
898 return ErrorExp.get();
901 Expression modifiableLvalue(Scope* sc, Expression e)
903 //printf("Expression::modifiableLvalue() %s, type = %s\n", toChars(), type.toChars());
904 // See if this expression is a modifiable lvalue (i.e. not const)
905 if (checkModifiable(this, sc) == Modifiable.yes)
907 assert(type);
908 if (!type.isMutable())
910 if (auto dve = this.isDotVarExp())
912 if (isNeedThisScope(sc, dve.var))
913 for (Dsymbol s = sc.func; s; s = s.toParentLocal())
915 FuncDeclaration ff = s.isFuncDeclaration();
916 if (!ff)
917 break;
918 if (!ff.type.isMutable)
920 error(loc, "cannot modify `%s` in `%s` function", toChars(), MODtoChars(type.mod));
921 return ErrorExp.get();
925 error(loc, "cannot modify `%s` expression `%s`", MODtoChars(type.mod), toChars());
926 return ErrorExp.get();
928 else if (!type.isAssignable())
930 error(loc, "cannot modify struct instance `%s` of type `%s` because it contains `const` or `immutable` members",
931 toChars(), type.toChars());
932 return ErrorExp.get();
935 return toLvalue(sc, e);
938 final Expression implicitCastTo(Scope* sc, Type t)
940 return .implicitCastTo(this, sc, t);
943 final MATCH implicitConvTo(Type t)
945 return .implicitConvTo(this, t);
948 final Expression castTo(Scope* sc, Type t)
950 return .castTo(this, sc, t);
953 /****************************************
954 * Resolve __FILE__, __LINE__, __MODULE__, __FUNCTION__, __PRETTY_FUNCTION__, __FILE_FULL_PATH__ to loc.
956 Expression resolveLoc(const ref Loc loc, Scope* sc)
958 this.loc = loc;
959 return this;
962 /****************************************
963 * Check that the expression has a valid type.
964 * If not, generates an error "... has no type".
965 * Returns:
966 * true if the expression is not valid.
967 * Note:
968 * When this function returns true, `checkValue()` should also return true.
970 bool checkType()
972 return false;
975 /****************************************
976 * Check that the expression has a valid value.
977 * If not, generates an error "... has no value".
978 * Returns:
979 * true if the expression is not valid or has void type.
981 bool checkValue()
983 if (type && type.toBasetype().ty == Tvoid)
985 error(loc, "expression `%s` is `void` and has no value", toChars());
986 //print(); assert(0);
987 if (!global.gag)
988 type = Type.terror;
989 return true;
991 return false;
994 extern (D) final bool checkScalar()
996 if (op == EXP.error)
997 return true;
998 if (type.toBasetype().ty == Terror)
999 return true;
1000 if (!type.isscalar())
1002 error(loc, "`%s` is not a scalar, it is a `%s`", toChars(), type.toChars());
1003 return true;
1005 return checkValue();
1008 extern (D) final bool checkNoBool()
1010 if (op == EXP.error)
1011 return true;
1012 if (type.toBasetype().ty == Terror)
1013 return true;
1014 if (type.toBasetype().ty == Tbool)
1016 error(loc, "operation not allowed on `bool` `%s`", toChars());
1017 return true;
1019 return false;
1022 extern (D) final bool checkIntegral()
1024 if (op == EXP.error)
1025 return true;
1026 if (type.toBasetype().ty == Terror)
1027 return true;
1028 if (!type.isintegral())
1030 error(loc, "`%s` is not of integral type, it is a `%s`", toChars(), type.toChars());
1031 return true;
1033 return checkValue();
1036 extern (D) final bool checkArithmetic(EXP op)
1038 if (op == EXP.error)
1039 return true;
1040 if (type.toBasetype().ty == Terror)
1041 return true;
1042 if (!type.isintegral() && !type.isfloating())
1044 // unary aggregate ops error here
1045 const char* msg = type.isAggregate() ?
1046 "operator `%s` is not defined for `%s` of type `%s`" :
1047 "illegal operator `%s` for `%s` of type `%s`";
1048 error(loc, msg, EXPtoString(op).ptr, toChars(), type.toChars());
1049 return true;
1051 return checkValue();
1054 final bool checkDeprecated(Scope* sc, Dsymbol s)
1056 return s.checkDeprecated(loc, sc);
1059 extern (D) final bool checkDisabled(Scope* sc, Dsymbol s)
1061 if (auto d = s.isDeclaration())
1063 return d.checkDisabled(loc, sc);
1066 return false;
1069 /*********************************************
1070 * Calling function f.
1071 * Check the purity, i.e. if we're in a pure function
1072 * we can only call other pure functions.
1073 * Returns true if error occurs.
1075 extern (D) final bool checkPurity(Scope* sc, FuncDeclaration f)
1077 if (!sc.func)
1078 return false;
1079 if (sc.func == f)
1080 return false;
1081 if (sc.intypeof == 1)
1082 return false;
1083 if (sc.flags & (SCOPE.ctfe | SCOPE.debug_))
1084 return false;
1086 // If the call has a pure parent, then the called func must be pure.
1087 if (!f.isPure() && checkImpure(sc, loc, null, f))
1089 error(loc, "`pure` %s `%s` cannot call impure %s `%s`",
1090 sc.func.kind(), sc.func.toPrettyChars(), f.kind(),
1091 f.toPrettyChars());
1093 if (!f.isDtorDeclaration())
1094 errorSupplementalInferredAttr(f, /*max depth*/ 10, /*deprecation*/ false, STC.pure_);
1096 checkOverriddenDtor(sc, f, dd => dd.type.toTypeFunction().purity != PURE.impure, "impure");
1097 return true;
1099 return false;
1103 * Checks whether `f` is a generated `DtorDeclaration` that hides a user-defined one
1104 * which passes `check` while `f` doesn't (e.g. when the user defined dtor is pure but
1105 * the generated dtor is not).
1106 * In that case the method will identify and print all members causing the attribute
1107 * missmatch.
1109 * Params:
1110 * sc = scope
1111 * f = potential `DtorDeclaration`
1112 * check = current check (e.g. whether it's pure)
1113 * checkName = the kind of check (e.g. `"pure"`)
1115 extern (D) final void checkOverriddenDtor(Scope* sc, FuncDeclaration f,
1116 scope bool function(DtorDeclaration) check, const string checkName
1118 auto dd = f.isDtorDeclaration();
1119 if (!dd || !dd.isGenerated())
1120 return;
1122 // DtorDeclaration without parents should fail at an earlier stage
1123 auto ad = cast(AggregateDeclaration) f.toParent2();
1124 assert(ad);
1126 if (ad.userDtors.length)
1128 if (!check(ad.userDtors[0])) // doesn't match check (e.g. is impure as well)
1129 return;
1131 // Sanity check
1132 assert(!check(ad.fieldDtor));
1135 dd.loc.errorSupplemental("%s`%s.~this` is %.*s because of the following field's destructors:",
1136 dd.isGenerated() ? "generated " : "".ptr,
1137 ad.toChars,
1138 cast(int) checkName.length, checkName.ptr);
1140 // Search for the offending fields
1141 foreach (field; ad.fields)
1143 // Only structs may define automatically called destructors
1144 auto ts = field.type.isTypeStruct();
1145 if (!ts)
1147 // But they might be part of a static array
1148 auto ta = field.type.isTypeSArray();
1149 if (!ta)
1150 continue;
1152 ts = ta.baseElemOf().isTypeStruct();
1153 if (!ts)
1154 continue;
1157 auto fieldSym = ts.toDsymbol(sc);
1158 assert(fieldSym); // Resolving ts must succeed because missing defs. should error before
1160 auto fieldSd = fieldSym.isStructDeclaration();
1161 assert(fieldSd); // ts is a TypeStruct, this would imply a malformed ASR
1163 if (fieldSd.dtor && !check(fieldSd.dtor))
1165 field.loc.errorSupplemental(" - %s %s", field.type.toChars(), field.toChars());
1167 if (fieldSd.dtor.isGenerated())
1168 checkOverriddenDtor(sc, fieldSd.dtor, check, checkName);
1169 else
1170 fieldSd.dtor.loc.errorSupplemental(" %.*s `%s.~this` is declared here",
1171 cast(int) checkName.length, checkName.ptr, fieldSd.toChars());
1176 /*******************************************
1177 * Accessing variable v.
1178 * Check for purity and safety violations.
1179 * Returns true if error occurs.
1181 extern (D) final bool checkPurity(Scope* sc, VarDeclaration v)
1183 //printf("v = %s %s\n", v.type.toChars(), v.toChars());
1184 /* Look for purity and safety violations when accessing variable v
1185 * from current function.
1187 if (!sc.func)
1188 return false;
1189 if (sc.intypeof == 1)
1190 return false; // allow violations inside typeof(expression)
1191 if (sc.flags & (SCOPE.ctfe | SCOPE.debug_))
1192 return false; // allow violations inside compile-time evaluated expressions and debug conditionals
1193 if (v.ident == Id.ctfe)
1194 return false; // magic variable never violates pure and safe
1195 if (v.isImmutable())
1196 return false; // always safe and pure to access immutables...
1197 if (v.isConst() && !v.isReference() && (v.isDataseg() || v.isParameter()) && v.type.implicitConvTo(v.type.immutableOf()))
1198 return false; // or const global/parameter values which have no mutable indirections
1199 if (v.storage_class & STC.manifest)
1200 return false; // ...or manifest constants
1202 // accessing empty structs is pure
1203 // https://issues.dlang.org/show_bug.cgi?id=18694
1204 // https://issues.dlang.org/show_bug.cgi?id=21464
1205 // https://issues.dlang.org/show_bug.cgi?id=23589
1206 if (v.type.ty == Tstruct)
1208 StructDeclaration sd = (cast(TypeStruct)v.type).sym;
1209 if (sd.members) // not opaque
1211 if (sd.semanticRun >= PASS.semanticdone)
1212 sd.determineSize(v.loc);
1213 if (sd.hasNoFields)
1214 return false;
1218 bool err = false;
1219 if (v.isDataseg())
1221 // https://issues.dlang.org/show_bug.cgi?id=7533
1222 // Accessing implicit generated __gate is pure.
1223 if (v.ident == Id.gate)
1224 return false;
1226 if (checkImpure(sc, loc, "`pure` %s `%s` cannot access mutable static data `%s`", v))
1228 error(loc, "`pure` %s `%s` cannot access mutable static data `%s`",
1229 sc.func.kind(), sc.func.toPrettyChars(), v.toChars());
1230 err = true;
1233 else
1235 /* Given:
1236 * void f() {
1237 * int fx;
1238 * pure void g() {
1239 * int gx;
1240 * /+pure+/ void h() {
1241 * int hx;
1242 * /+pure+/ void i() { }
1246 * i() can modify hx and gx but not fx
1249 Dsymbol vparent = v.toParent2();
1250 for (Dsymbol s = sc.func; !err && s; s = s.toParentP(vparent))
1252 if (s == vparent)
1253 break;
1255 if (AggregateDeclaration ad = s.isAggregateDeclaration())
1257 if (ad.isNested())
1258 continue;
1259 break;
1261 FuncDeclaration ff = s.isFuncDeclaration();
1262 if (!ff)
1263 break;
1264 if (ff.isNested() || ff.isThis())
1266 if (ff.type.isImmutable() ||
1267 ff.type.isShared() && !MODimplicitConv(ff.type.mod, v.type.mod))
1269 OutBuffer ffbuf;
1270 OutBuffer vbuf;
1271 MODMatchToBuffer(&ffbuf, ff.type.mod, v.type.mod);
1272 MODMatchToBuffer(&vbuf, v.type.mod, ff.type.mod);
1273 error(loc, "%s%s `%s` cannot access %sdata `%s`",
1274 ffbuf.peekChars(), ff.kind(), ff.toPrettyChars(), vbuf.peekChars(), v.toChars());
1275 err = true;
1276 break;
1278 continue;
1280 break;
1284 /* Do not allow safe functions to access __gshared data
1286 if (v.storage_class & STC.gshared)
1288 if (sc.setUnsafe(false, this.loc,
1289 "`@safe` function `%s` cannot access `__gshared` data `%s`", sc.func, v))
1291 err = true;
1295 return err;
1299 Check if sc.func is impure or can be made impure.
1300 Returns true on error, i.e. if sc.func is pure and cannot be made impure.
1302 private static bool checkImpure(Scope* sc, Loc loc, const(char)* fmt, RootObject arg0)
1304 return sc.func && (isRootTraitsCompilesScope(sc)
1305 ? sc.func.isPureBypassingInference() >= PURE.weak
1306 : sc.func.setImpure(loc, fmt, arg0));
1309 /*********************************************
1310 * Calling function f.
1311 * Check the safety, i.e. if we're in a @safe function
1312 * we can only call @safe or @trusted functions.
1313 * Returns true if error occurs.
1315 extern (D) final bool checkSafety(Scope* sc, FuncDeclaration f)
1317 if (sc.func == f)
1318 return false;
1319 if (sc.intypeof == 1)
1320 return false;
1321 if (sc.flags & SCOPE.debug_)
1322 return false;
1323 if ((sc.flags & SCOPE.ctfe) && sc.func)
1324 return false;
1326 if (!sc.func)
1328 if (sc.varDecl && !f.safetyInprocess && !f.isSafe() && !f.isTrusted())
1330 if (sc.varDecl.storage_class & STC.safe)
1332 error(loc, "`@safe` variable `%s` cannot be initialized by calling `@system` function `%s`",
1333 sc.varDecl.toChars(), f.toChars());
1334 return true;
1336 else
1338 sc.varDecl.storage_class |= STC.system;
1339 sc.varDecl.systemInferred = true;
1342 return false;
1345 if (!f.isSafe() && !f.isTrusted())
1347 if (isRootTraitsCompilesScope(sc) ? sc.func.isSafeBypassingInference() : sc.func.setUnsafeCall(f))
1349 if (!loc.isValid()) // e.g. implicitly generated dtor
1350 loc = sc.func.loc;
1352 const prettyChars = f.toPrettyChars();
1353 error(loc, "`@safe` %s `%s` cannot call `@system` %s `%s`",
1354 sc.func.kind(), sc.func.toPrettyChars(), f.kind(),
1355 prettyChars);
1356 if (!f.isDtorDeclaration)
1357 errorSupplementalInferredAttr(f, /*max depth*/ 10, /*deprecation*/ false, STC.safe);
1358 .errorSupplemental(f.loc, "`%s` is declared here", prettyChars);
1360 checkOverriddenDtor(sc, f, dd => dd.type.toTypeFunction().trust > TRUST.system, "@system");
1362 return true;
1365 else if (f.isSafe() && f.safetyViolation)
1367 // for dip1000 by default transition, print deprecations for calling functions that will become `@system`
1368 if (sc.func.isSafeBypassingInference())
1370 .deprecation(this.loc, "`@safe` function `%s` calling `%s`", sc.func.toChars(), f.toChars());
1371 errorSupplementalInferredAttr(f, 10, true, STC.safe);
1373 else if (!sc.func.safetyViolation)
1375 import dmd.func : AttributeViolation;
1376 sc.func.safetyViolation = new AttributeViolation(this.loc, null, f, null, null);
1379 return false;
1382 /*********************************************
1383 * Calling function f.
1384 * Check the @nogc-ness, i.e. if we're in a @nogc function
1385 * we can only call other @nogc functions.
1386 * Returns true if error occurs.
1388 extern (D) final bool checkNogc(Scope* sc, FuncDeclaration f)
1390 if (!sc.func)
1391 return false;
1392 if (sc.func == f)
1393 return false;
1394 if (sc.intypeof == 1)
1395 return false;
1396 if (sc.flags & (SCOPE.ctfe | SCOPE.debug_))
1397 return false;
1398 /* The original expression (`new S(...)`) will be verified instead. This
1399 * is to keep errors related to the original code and not the lowering.
1401 if (f.ident == Id._d_newitemT)
1402 return false;
1404 if (!f.isNogc())
1406 if (isRootTraitsCompilesScope(sc) ? sc.func.isNogcBypassingInference() : sc.func.setGCCall(f))
1408 if (loc.linnum == 0) // e.g. implicitly generated dtor
1409 loc = sc.func.loc;
1411 // Lowered non-@nogc'd hooks will print their own error message inside of nogc.d (NOGCVisitor.visit(CallExp e)),
1412 // so don't print anything to avoid double error messages.
1413 if (!(f.ident == Id._d_HookTraceImpl || f.ident == Id._d_arraysetlengthT
1414 || f.ident == Id._d_arrayappendT || f.ident == Id._d_arrayappendcTX
1415 || f.ident == Id._d_arraycatnTX || f.ident == Id._d_newclassT))
1417 error(loc, "`@nogc` %s `%s` cannot call non-@nogc %s `%s`",
1418 sc.func.kind(), sc.func.toPrettyChars(), f.kind(), f.toPrettyChars());
1420 if (!f.isDtorDeclaration)
1421 f.errorSupplementalInferredAttr(/*max depth*/ 10, /*deprecation*/ false, STC.nogc);
1424 checkOverriddenDtor(sc, f, dd => dd.type.toTypeFunction().isnogc, "non-@nogc");
1426 return true;
1429 return false;
1432 /********************************************
1433 * Check that the postblit is callable if t is an array of structs.
1434 * Returns true if error happens.
1436 extern (D) final bool checkPostblit(Scope* sc, Type t)
1438 if (auto ts = t.baseElemOf().isTypeStruct())
1440 if (global.params.useTypeInfo && Type.dtypeinfo)
1442 // https://issues.dlang.org/show_bug.cgi?id=11395
1443 // Require TypeInfo generation for array concatenation
1444 semanticTypeInfo(sc, t);
1447 StructDeclaration sd = ts.sym;
1448 if (sd.postblit)
1450 if (sd.postblit.checkDisabled(loc, sc))
1451 return true;
1453 //checkDeprecated(sc, sd.postblit); // necessary?
1454 checkPurity(sc, sd.postblit);
1455 checkSafety(sc, sd.postblit);
1456 checkNogc(sc, sd.postblit);
1457 //checkAccess(sd, loc, sc, sd.postblit); // necessary?
1458 return false;
1461 return false;
1464 extern (D) final bool checkRightThis(Scope* sc)
1466 if (op == EXP.error)
1467 return true;
1468 if (op == EXP.variable && type.ty != Terror)
1470 VarExp ve = cast(VarExp)this;
1471 if (isNeedThisScope(sc, ve.var))
1473 //printf("checkRightThis sc.intypeof = %d, ad = %p, func = %p, fdthis = %p\n",
1474 // sc.intypeof, sc.getStructClassScope(), func, fdthis);
1475 auto t = ve.var.isThis();
1476 assert(t);
1477 error(loc, "accessing non-static variable `%s` requires an instance of `%s`", ve.var.toChars(), t.toChars());
1478 return true;
1481 return false;
1484 /*******************************
1485 * Check whether the expression allows RMW operations, error with rmw operator diagnostic if not.
1486 * ex is the RHS expression, or NULL if ++/-- is used (for diagnostics)
1487 * Returns true if error occurs.
1489 extern (D) final bool checkReadModifyWrite(EXP rmwOp, Expression ex = null)
1491 //printf("Expression::checkReadModifyWrite() %s %s", toChars(), ex ? ex.toChars() : "");
1492 if (!type || !type.isShared() || type.isTypeStruct() || type.isTypeClass())
1493 return false;
1495 // atomicOp uses opAssign (+=/-=) rather than opOp (++/--) for the CT string literal.
1496 switch (rmwOp)
1498 case EXP.plusPlus:
1499 case EXP.prePlusPlus:
1500 rmwOp = EXP.addAssign;
1501 break;
1502 case EXP.minusMinus:
1503 case EXP.preMinusMinus:
1504 rmwOp = EXP.minAssign;
1505 break;
1506 default:
1507 break;
1510 error(loc, "read-modify-write operations are not allowed for `shared` variables");
1511 errorSupplemental(loc, "Use `core.atomic.atomicOp!\"%s\"(%s, %s)` instead",
1512 EXPtoString(rmwOp).ptr, toChars(), ex ? ex.toChars() : "1");
1513 return true;
1516 /************************************************
1517 * Destructors are attached to VarDeclarations.
1518 * Hence, if expression returns a temp that needs a destructor,
1519 * make sure and create a VarDeclaration for that temp.
1521 Expression addDtorHook(Scope* sc)
1523 return this;
1526 /******************************
1527 * Take address of expression.
1529 final Expression addressOf()
1531 //printf("Expression::addressOf()\n");
1532 debug
1534 assert(op == EXP.error || isLvalue());
1536 Expression e = new AddrExp(loc, this, type.pointerTo());
1537 return e;
1540 /******************************
1541 * If this is a reference, dereference it.
1543 final Expression deref()
1545 //printf("Expression::deref()\n");
1546 // type could be null if forward referencing an 'auto' variable
1547 if (type)
1548 if (auto tr = type.isTypeReference())
1550 Expression e = new PtrExp(loc, this, tr.next);
1551 return e;
1553 return this;
1556 final Expression optimize(int result, bool keepLvalue = false)
1558 return Expression_optimize(this, result, keepLvalue);
1561 // Entry point for CTFE.
1562 // A compile-time result is required. Give an error if not possible
1563 final Expression ctfeInterpret()
1565 return .ctfeInterpret(this);
1568 final int isConst()
1570 return .isConst(this);
1573 /******
1574 * Identical, not just equal. I.e. NaNs with different bit patterns are not identical
1576 bool isIdentical(const Expression e) const
1578 return equals(e);
1582 /// Statically evaluate this expression to a `bool` if possible
1583 /// Returns: an optional thath either contains the value or is empty
1584 Optional!bool toBool()
1586 return typeof(return)();
1589 bool hasCode()
1591 return true;
1594 final pure inout nothrow @nogc @safe
1596 inout(IntegerExp) isIntegerExp() { return op == EXP.int64 ? cast(typeof(return))this : null; }
1597 inout(ErrorExp) isErrorExp() { return op == EXP.error ? cast(typeof(return))this : null; }
1598 inout(VoidInitExp) isVoidInitExp() { return op == EXP.void_ ? cast(typeof(return))this : null; }
1599 inout(RealExp) isRealExp() { return op == EXP.float64 ? cast(typeof(return))this : null; }
1600 inout(ComplexExp) isComplexExp() { return op == EXP.complex80 ? cast(typeof(return))this : null; }
1601 inout(IdentifierExp) isIdentifierExp() { return op == EXP.identifier ? cast(typeof(return))this : null; }
1602 inout(DollarExp) isDollarExp() { return op == EXP.dollar ? cast(typeof(return))this : null; }
1603 inout(DsymbolExp) isDsymbolExp() { return op == EXP.dSymbol ? cast(typeof(return))this : null; }
1604 inout(ThisExp) isThisExp() { return op == EXP.this_ ? cast(typeof(return))this : null; }
1605 inout(SuperExp) isSuperExp() { return op == EXP.super_ ? cast(typeof(return))this : null; }
1606 inout(NullExp) isNullExp() { return op == EXP.null_ ? cast(typeof(return))this : null; }
1607 inout(StringExp) isStringExp() { return op == EXP.string_ ? cast(typeof(return))this : null; }
1608 inout(TupleExp) isTupleExp() { return op == EXP.tuple ? cast(typeof(return))this : null; }
1609 inout(ArrayLiteralExp) isArrayLiteralExp() { return op == EXP.arrayLiteral ? cast(typeof(return))this : null; }
1610 inout(AssocArrayLiteralExp) isAssocArrayLiteralExp() { return op == EXP.assocArrayLiteral ? cast(typeof(return))this : null; }
1611 inout(StructLiteralExp) isStructLiteralExp() { return op == EXP.structLiteral ? cast(typeof(return))this : null; }
1612 inout(CompoundLiteralExp) isCompoundLiteralExp() { return op == EXP.compoundLiteral ? cast(typeof(return))this : null; }
1613 inout(TypeExp) isTypeExp() { return op == EXP.type ? cast(typeof(return))this : null; }
1614 inout(ScopeExp) isScopeExp() { return op == EXP.scope_ ? cast(typeof(return))this : null; }
1615 inout(TemplateExp) isTemplateExp() { return op == EXP.template_ ? cast(typeof(return))this : null; }
1616 inout(NewExp) isNewExp() { return op == EXP.new_ ? cast(typeof(return))this : null; }
1617 inout(NewAnonClassExp) isNewAnonClassExp() { return op == EXP.newAnonymousClass ? cast(typeof(return))this : null; }
1618 inout(SymOffExp) isSymOffExp() { return op == EXP.symbolOffset ? cast(typeof(return))this : null; }
1619 inout(VarExp) isVarExp() { return op == EXP.variable ? cast(typeof(return))this : null; }
1620 inout(OverExp) isOverExp() { return op == EXP.overloadSet ? cast(typeof(return))this : null; }
1621 inout(FuncExp) isFuncExp() { return op == EXP.function_ ? cast(typeof(return))this : null; }
1622 inout(DeclarationExp) isDeclarationExp() { return op == EXP.declaration ? cast(typeof(return))this : null; }
1623 inout(TypeidExp) isTypeidExp() { return op == EXP.typeid_ ? cast(typeof(return))this : null; }
1624 inout(TraitsExp) isTraitsExp() { return op == EXP.traits ? cast(typeof(return))this : null; }
1625 inout(HaltExp) isHaltExp() { return op == EXP.halt ? cast(typeof(return))this : null; }
1626 inout(IsExp) isExp() { return op == EXP.is_ ? cast(typeof(return))this : null; }
1627 inout(MixinExp) isMixinExp() { return op == EXP.mixin_ ? cast(typeof(return))this : null; }
1628 inout(ImportExp) isImportExp() { return op == EXP.import_ ? cast(typeof(return))this : null; }
1629 inout(AssertExp) isAssertExp() { return op == EXP.assert_ ? cast(typeof(return))this : null; }
1630 inout(ThrowExp) isThrowExp() { return op == EXP.throw_ ? cast(typeof(return))this : null; }
1631 inout(DotIdExp) isDotIdExp() { return op == EXP.dotIdentifier ? cast(typeof(return))this : null; }
1632 inout(DotTemplateExp) isDotTemplateExp() { return op == EXP.dotTemplateDeclaration ? cast(typeof(return))this : null; }
1633 inout(DotVarExp) isDotVarExp() { return op == EXP.dotVariable ? cast(typeof(return))this : null; }
1634 inout(DotTemplateInstanceExp) isDotTemplateInstanceExp() { return op == EXP.dotTemplateInstance ? cast(typeof(return))this : null; }
1635 inout(DelegateExp) isDelegateExp() { return op == EXP.delegate_ ? cast(typeof(return))this : null; }
1636 inout(DotTypeExp) isDotTypeExp() { return op == EXP.dotType ? cast(typeof(return))this : null; }
1637 inout(CallExp) isCallExp() { return op == EXP.call ? cast(typeof(return))this : null; }
1638 inout(AddrExp) isAddrExp() { return op == EXP.address ? cast(typeof(return))this : null; }
1639 inout(PtrExp) isPtrExp() { return op == EXP.star ? cast(typeof(return))this : null; }
1640 inout(NegExp) isNegExp() { return op == EXP.negate ? cast(typeof(return))this : null; }
1641 inout(UAddExp) isUAddExp() { return op == EXP.uadd ? cast(typeof(return))this : null; }
1642 inout(ComExp) isComExp() { return op == EXP.tilde ? cast(typeof(return))this : null; }
1643 inout(NotExp) isNotExp() { return op == EXP.not ? cast(typeof(return))this : null; }
1644 inout(DeleteExp) isDeleteExp() { return op == EXP.delete_ ? cast(typeof(return))this : null; }
1645 inout(CastExp) isCastExp() { return op == EXP.cast_ ? cast(typeof(return))this : null; }
1646 inout(VectorExp) isVectorExp() { return op == EXP.vector ? cast(typeof(return))this : null; }
1647 inout(VectorArrayExp) isVectorArrayExp() { return op == EXP.vectorArray ? cast(typeof(return))this : null; }
1648 inout(SliceExp) isSliceExp() { return op == EXP.slice ? cast(typeof(return))this : null; }
1649 inout(ArrayLengthExp) isArrayLengthExp() { return op == EXP.arrayLength ? cast(typeof(return))this : null; }
1650 inout(ArrayExp) isArrayExp() { return op == EXP.array ? cast(typeof(return))this : null; }
1651 inout(DotExp) isDotExp() { return op == EXP.dot ? cast(typeof(return))this : null; }
1652 inout(CommaExp) isCommaExp() { return op == EXP.comma ? cast(typeof(return))this : null; }
1653 inout(IntervalExp) isIntervalExp() { return op == EXP.interval ? cast(typeof(return))this : null; }
1654 inout(DelegatePtrExp) isDelegatePtrExp() { return op == EXP.delegatePointer ? cast(typeof(return))this : null; }
1655 inout(DelegateFuncptrExp) isDelegateFuncptrExp() { return op == EXP.delegateFunctionPointer ? cast(typeof(return))this : null; }
1656 inout(IndexExp) isIndexExp() { return op == EXP.index ? cast(typeof(return))this : null; }
1657 inout(PostExp) isPostExp() { return (op == EXP.plusPlus || op == EXP.minusMinus) ? cast(typeof(return))this : null; }
1658 inout(PreExp) isPreExp() { return (op == EXP.prePlusPlus || op == EXP.preMinusMinus) ? cast(typeof(return))this : null; }
1659 inout(AssignExp) isAssignExp() { return op == EXP.assign ? cast(typeof(return))this : null; }
1660 inout(LoweredAssignExp) isLoweredAssignExp() { return op == EXP.loweredAssignExp ? cast(typeof(return))this : null; }
1661 inout(ConstructExp) isConstructExp() { return op == EXP.construct ? cast(typeof(return))this : null; }
1662 inout(BlitExp) isBlitExp() { return op == EXP.blit ? cast(typeof(return))this : null; }
1663 inout(AddAssignExp) isAddAssignExp() { return op == EXP.addAssign ? cast(typeof(return))this : null; }
1664 inout(MinAssignExp) isMinAssignExp() { return op == EXP.minAssign ? cast(typeof(return))this : null; }
1665 inout(MulAssignExp) isMulAssignExp() { return op == EXP.mulAssign ? cast(typeof(return))this : null; }
1667 inout(DivAssignExp) isDivAssignExp() { return op == EXP.divAssign ? cast(typeof(return))this : null; }
1668 inout(ModAssignExp) isModAssignExp() { return op == EXP.modAssign ? cast(typeof(return))this : null; }
1669 inout(AndAssignExp) isAndAssignExp() { return op == EXP.andAssign ? cast(typeof(return))this : null; }
1670 inout(OrAssignExp) isOrAssignExp() { return op == EXP.orAssign ? cast(typeof(return))this : null; }
1671 inout(XorAssignExp) isXorAssignExp() { return op == EXP.xorAssign ? cast(typeof(return))this : null; }
1672 inout(PowAssignExp) isPowAssignExp() { return op == EXP.powAssign ? cast(typeof(return))this : null; }
1674 inout(ShlAssignExp) isShlAssignExp() { return op == EXP.leftShiftAssign ? cast(typeof(return))this : null; }
1675 inout(ShrAssignExp) isShrAssignExp() { return op == EXP.rightShiftAssign ? cast(typeof(return))this : null; }
1676 inout(UshrAssignExp) isUshrAssignExp() { return op == EXP.unsignedRightShiftAssign ? cast(typeof(return))this : null; }
1678 inout(CatAssignExp) isCatAssignExp() { return op == EXP.concatenateAssign
1679 ? cast(typeof(return))this
1680 : null; }
1682 inout(CatElemAssignExp) isCatElemAssignExp() { return op == EXP.concatenateElemAssign
1683 ? cast(typeof(return))this
1684 : null; }
1686 inout(CatDcharAssignExp) isCatDcharAssignExp() { return op == EXP.concatenateDcharAssign
1687 ? cast(typeof(return))this
1688 : null; }
1690 inout(AddExp) isAddExp() { return op == EXP.add ? cast(typeof(return))this : null; }
1691 inout(MinExp) isMinExp() { return op == EXP.min ? cast(typeof(return))this : null; }
1692 inout(CatExp) isCatExp() { return op == EXP.concatenate ? cast(typeof(return))this : null; }
1693 inout(MulExp) isMulExp() { return op == EXP.mul ? cast(typeof(return))this : null; }
1694 inout(DivExp) isDivExp() { return op == EXP.div ? cast(typeof(return))this : null; }
1695 inout(ModExp) isModExp() { return op == EXP.mod ? cast(typeof(return))this : null; }
1696 inout(PowExp) isPowExp() { return op == EXP.pow ? cast(typeof(return))this : null; }
1697 inout(ShlExp) isShlExp() { return op == EXP.leftShift ? cast(typeof(return))this : null; }
1698 inout(ShrExp) isShrExp() { return op == EXP.rightShift ? cast(typeof(return))this : null; }
1699 inout(UshrExp) isUshrExp() { return op == EXP.unsignedRightShift ? cast(typeof(return))this : null; }
1700 inout(AndExp) isAndExp() { return op == EXP.and ? cast(typeof(return))this : null; }
1701 inout(OrExp) isOrExp() { return op == EXP.or ? cast(typeof(return))this : null; }
1702 inout(XorExp) isXorExp() { return op == EXP.xor ? cast(typeof(return))this : null; }
1703 inout(LogicalExp) isLogicalExp() { return (op == EXP.andAnd || op == EXP.orOr) ? cast(typeof(return))this : null; }
1704 //inout(CmpExp) isCmpExp() { return op == EXP. ? cast(typeof(return))this : null; }
1705 inout(InExp) isInExp() { return op == EXP.in_ ? cast(typeof(return))this : null; }
1706 inout(RemoveExp) isRemoveExp() { return op == EXP.remove ? cast(typeof(return))this : null; }
1707 inout(EqualExp) isEqualExp() { return (op == EXP.equal || op == EXP.notEqual) ? cast(typeof(return))this : null; }
1708 inout(IdentityExp) isIdentityExp() { return (op == EXP.identity || op == EXP.notIdentity) ? cast(typeof(return))this : null; }
1709 inout(CondExp) isCondExp() { return op == EXP.question ? cast(typeof(return))this : null; }
1710 inout(GenericExp) isGenericExp() { return op == EXP._Generic ? cast(typeof(return))this : null; }
1711 inout(DefaultInitExp) isDefaultInitExp() { return
1712 (op == EXP.prettyFunction || op == EXP.functionString ||
1713 op == EXP.line || op == EXP.moduleString ||
1714 op == EXP.file || op == EXP.fileFullPath ) ? cast(typeof(return))this : null; }
1715 inout(FileInitExp) isFileInitExp() { return (op == EXP.file || op == EXP.fileFullPath) ? cast(typeof(return))this : null; }
1716 inout(LineInitExp) isLineInitExp() { return op == EXP.line ? cast(typeof(return))this : null; }
1717 inout(ModuleInitExp) isModuleInitExp() { return op == EXP.moduleString ? cast(typeof(return))this : null; }
1718 inout(FuncInitExp) isFuncInitExp() { return op == EXP.functionString ? cast(typeof(return))this : null; }
1719 inout(PrettyFuncInitExp) isPrettyFuncInitExp() { return op == EXP.prettyFunction ? cast(typeof(return))this : null; }
1720 inout(ObjcClassReferenceExp) isObjcClassReferenceExp() { return op == EXP.objcClassReference ? cast(typeof(return))this : null; }
1721 inout(ClassReferenceExp) isClassReferenceExp() { return op == EXP.classReference ? cast(typeof(return))this : null; }
1722 inout(ThrownExceptionExp) isThrownExceptionExp() { return op == EXP.thrownException ? cast(typeof(return))this : null; }
1724 inout(UnaExp) isUnaExp() pure inout nothrow @nogc
1726 return exptab[op] & EXPFLAGS.unary ? cast(typeof(return))this : null;
1729 inout(BinExp) isBinExp() pure inout nothrow @nogc
1731 return exptab[op] & EXPFLAGS.binary ? cast(typeof(return))this : null;
1734 inout(BinAssignExp) isBinAssignExp() pure inout nothrow @nogc
1736 return exptab[op] & EXPFLAGS.binaryAssign ? cast(typeof(return))this : null;
1740 override void accept(Visitor v)
1742 v.visit(this);
1746 /***********************************************************
1747 * A compile-time known integer value
1749 extern (C++) final class IntegerExp : Expression
1751 private dinteger_t value;
1753 extern (D) this(const ref Loc loc, dinteger_t value, Type type)
1755 super(loc, EXP.int64);
1756 //printf("IntegerExp(value = %lld, type = '%s')\n", value, type ? type.toChars() : "");
1757 assert(type);
1758 if (!type.isscalar())
1760 //printf("%s, loc = %d\n", toChars(), loc.linnum);
1761 if (type.ty != Terror)
1762 error(loc, "integral constant must be scalar type, not `%s`", type.toChars());
1763 type = Type.terror;
1765 this.type = type;
1766 this.value = normalize(type.toBasetype().ty, value);
1769 extern (D) this(dinteger_t value)
1771 super(Loc.initial, EXP.int64);
1772 this.type = Type.tint32;
1773 this.value = cast(int)value;
1776 static IntegerExp create(const ref Loc loc, dinteger_t value, Type type)
1778 return new IntegerExp(loc, value, type);
1781 // Same as create, but doesn't allocate memory.
1782 static void emplace(UnionExp* pue, const ref Loc loc, dinteger_t value, Type type)
1784 emplaceExp!(IntegerExp)(pue, loc, value, type);
1787 override bool equals(const RootObject o) const
1789 if (this == o)
1790 return true;
1791 if (auto ne = (cast(Expression)o).isIntegerExp())
1793 if (type.toHeadMutable().equals(ne.type.toHeadMutable()) && value == ne.value)
1795 return true;
1798 return false;
1801 override dinteger_t toInteger()
1803 // normalize() is necessary until we fix all the paints of 'type'
1804 return value = normalize(type.toBasetype().ty, value);
1807 override real_t toReal()
1809 // normalize() is necessary until we fix all the paints of 'type'
1810 const ty = type.toBasetype().ty;
1811 const val = normalize(ty, value);
1812 value = val;
1813 return (ty == Tuns64)
1814 ? real_t(cast(ulong)val)
1815 : real_t(cast(long)val);
1818 override real_t toImaginary()
1820 return CTFloat.zero;
1823 override complex_t toComplex()
1825 return complex_t(toReal());
1828 override Optional!bool toBool()
1830 bool r = toInteger() != 0;
1831 return typeof(return)(r);
1834 override Expression toLvalue(Scope* sc, Expression e)
1836 if (!e)
1837 e = this;
1838 else if (!loc.isValid())
1839 loc = e.loc;
1840 error(e.loc, "cannot modify constant `%s`", e.toChars());
1841 return ErrorExp.get();
1844 override void accept(Visitor v)
1846 v.visit(this);
1849 dinteger_t getInteger()
1851 return value;
1854 void setInteger(dinteger_t value)
1856 this.value = normalize(type.toBasetype().ty, value);
1859 extern (D) static dinteger_t normalize(TY ty, dinteger_t value)
1861 /* 'Normalize' the value of the integer to be in range of the type
1863 dinteger_t result;
1864 switch (ty)
1866 case Tbool:
1867 result = (value != 0);
1868 break;
1870 case Tint8:
1871 result = cast(byte)value;
1872 break;
1874 case Tchar:
1875 case Tuns8:
1876 result = cast(ubyte)value;
1877 break;
1879 case Tint16:
1880 result = cast(short)value;
1881 break;
1883 case Twchar:
1884 case Tuns16:
1885 result = cast(ushort)value;
1886 break;
1888 case Tint32:
1889 result = cast(int)value;
1890 break;
1892 case Tdchar:
1893 case Tuns32:
1894 result = cast(uint)value;
1895 break;
1897 case Tint64:
1898 result = cast(long)value;
1899 break;
1901 case Tuns64:
1902 result = cast(ulong)value;
1903 break;
1905 case Tpointer:
1906 if (target.ptrsize == 8)
1907 goto case Tuns64;
1908 if (target.ptrsize == 4)
1909 goto case Tuns32;
1910 if (target.ptrsize == 2)
1911 goto case Tuns16;
1912 assert(0);
1914 default:
1915 break;
1917 return result;
1920 override IntegerExp syntaxCopy()
1922 return this;
1926 * Use this instead of creating new instances for commonly used literals
1927 * such as 0 or 1.
1929 * Parameters:
1930 * v = The value of the expression
1931 * Returns:
1932 * A static instance of the expression, typed as `Tint32`.
1934 static IntegerExp literal(int v)()
1936 __gshared IntegerExp theConstant;
1937 if (!theConstant)
1938 theConstant = new IntegerExp(v);
1939 return theConstant;
1943 * Use this instead of creating new instances for commonly used bools.
1945 * Parameters:
1946 * b = The value of the expression
1947 * Returns:
1948 * A static instance of the expression, typed as `Type.tbool`.
1950 static IntegerExp createBool(bool b)
1952 __gshared IntegerExp trueExp, falseExp;
1953 if (!trueExp)
1955 trueExp = new IntegerExp(Loc.initial, 1, Type.tbool);
1956 falseExp = new IntegerExp(Loc.initial, 0, Type.tbool);
1958 return b ? trueExp : falseExp;
1962 /***********************************************************
1963 * Use this expression for error recovery.
1965 * It should behave as a 'sink' to prevent further cascaded error messages.
1967 extern (C++) final class ErrorExp : Expression
1969 private extern (D) this()
1971 super(Loc.initial, EXP.error);
1972 type = Type.terror;
1975 static ErrorExp get ()
1977 if (errorexp is null)
1978 errorexp = new ErrorExp();
1980 if (global.errors == 0 && global.gaggedErrors == 0)
1982 /* Unfortunately, errors can still leak out of gagged errors,
1983 * and we need to set the error count to prevent bogus code
1984 * generation. At least give a message.
1986 .error(Loc.initial, "unknown, please file report on issues.dlang.org");
1989 return errorexp;
1992 override Expression toLvalue(Scope* sc, Expression e)
1994 return this;
1997 override void accept(Visitor v)
1999 v.visit(this);
2002 extern (C++) __gshared ErrorExp errorexp; // handy shared value
2006 /***********************************************************
2007 * An uninitialized value,
2008 * generated from void initializers.
2010 * https://dlang.org/spec/declaration.html#void_init
2012 extern (C++) final class VoidInitExp : Expression
2014 VarDeclaration var; /// the variable from where the void value came from, null if not known
2015 /// Useful for error messages
2017 extern (D) this(VarDeclaration var) @safe
2019 super(var.loc, EXP.void_);
2020 this.var = var;
2021 this.type = var.type;
2024 override void accept(Visitor v)
2026 v.visit(this);
2031 /***********************************************************
2032 * A compile-time known floating point number
2034 extern (C++) final class RealExp : Expression
2036 real_t value;
2038 extern (D) this(const ref Loc loc, real_t value, Type type) @safe
2040 super(loc, EXP.float64);
2041 //printf("RealExp::RealExp(%Lg)\n", value);
2042 this.value = value;
2043 this.type = type;
2046 static RealExp create(const ref Loc loc, real_t value, Type type) @safe
2048 return new RealExp(loc, value, type);
2051 // Same as create, but doesn't allocate memory.
2052 static void emplace(UnionExp* pue, const ref Loc loc, real_t value, Type type)
2054 emplaceExp!(RealExp)(pue, loc, value, type);
2057 /********************************
2058 * Test to see if two reals are the same.
2059 * Regard NaN's as equivalent.
2060 * Regard +0 and -0 as different.
2061 * Params:
2062 * x1 = first operand
2063 * x2 = second operand
2064 * Returns:
2065 * true if x1 is x2
2066 * else false
2068 private static bool RealIdentical(real_t x1, real_t x2) @safe
2070 return (CTFloat.isNaN(x1) && CTFloat.isNaN(x2)) || CTFloat.isIdentical(x1, x2);
2072 override bool equals(const RootObject o) const
2074 if (this == o)
2075 return true;
2076 if (auto ne = (cast(Expression)o).isRealExp())
2078 if (type.toHeadMutable().equals(ne.type.toHeadMutable()) && RealIdentical(value, ne.value))
2080 return true;
2083 return false;
2086 override bool isIdentical(const Expression e) const
2088 if (!equals(e))
2089 return false;
2090 return CTFloat.isIdentical(value, e.isRealExp().value);
2093 override dinteger_t toInteger()
2095 return cast(sinteger_t)toReal();
2098 override uinteger_t toUInteger()
2100 return cast(uinteger_t)toReal();
2103 override real_t toReal()
2105 return type.isreal() ? value : CTFloat.zero;
2108 override real_t toImaginary()
2110 return type.isreal() ? CTFloat.zero : value;
2113 override complex_t toComplex()
2115 return complex_t(toReal(), toImaginary());
2118 override Optional!bool toBool()
2120 return typeof(return)(!!value);
2123 override void accept(Visitor v)
2125 v.visit(this);
2129 /***********************************************************
2130 * A compile-time complex number (deprecated)
2132 extern (C++) final class ComplexExp : Expression
2134 complex_t value;
2136 extern (D) this(const ref Loc loc, complex_t value, Type type) @safe
2138 super(loc, EXP.complex80);
2139 this.value = value;
2140 this.type = type;
2141 //printf("ComplexExp::ComplexExp(%s)\n", toChars());
2144 static ComplexExp create(const ref Loc loc, complex_t value, Type type) @safe
2146 return new ComplexExp(loc, value, type);
2149 // Same as create, but doesn't allocate memory.
2150 static void emplace(UnionExp* pue, const ref Loc loc, complex_t value, Type type)
2152 emplaceExp!(ComplexExp)(pue, loc, value, type);
2155 override bool equals(const RootObject o) const
2157 if (this == o)
2158 return true;
2159 if (auto ne = (cast(Expression)o).isComplexExp())
2161 if (type.toHeadMutable().equals(ne.type.toHeadMutable()) &&
2162 RealExp.RealIdentical(creall(value), creall(ne.value)) &&
2163 RealExp.RealIdentical(cimagl(value), cimagl(ne.value)))
2165 return true;
2168 return false;
2171 override bool isIdentical(const Expression e) const
2173 if (!equals(e))
2174 return false;
2175 // equals() regards different NaN values as 'equals'
2176 auto c = e.isComplexExp();
2177 return CTFloat.isIdentical(creall(value), creall(c.value)) &&
2178 CTFloat.isIdentical(cimagl(value), cimagl(c.value));
2181 override dinteger_t toInteger()
2183 return cast(sinteger_t)toReal();
2186 override uinteger_t toUInteger()
2188 return cast(uinteger_t)toReal();
2191 override real_t toReal()
2193 return creall(value);
2196 override real_t toImaginary()
2198 return cimagl(value);
2201 override complex_t toComplex()
2203 return value;
2206 override Optional!bool toBool()
2208 return typeof(return)(!!value);
2211 override void accept(Visitor v)
2213 v.visit(this);
2217 /***********************************************************
2218 * An identifier in the context of an expression (as opposed to a declaration)
2220 * ---
2221 * int x; // VarDeclaration with Identifier
2222 * x++; // PostExp with IdentifierExp
2223 * ---
2225 extern (C++) class IdentifierExp : Expression
2227 Identifier ident;
2228 bool parens; // if it appears as (identifier)
2230 extern (D) this(const ref Loc loc, Identifier ident) scope @safe
2232 super(loc, EXP.identifier);
2233 this.ident = ident;
2236 static IdentifierExp create(const ref Loc loc, Identifier ident) @safe
2238 return new IdentifierExp(loc, ident);
2241 override final bool isLvalue()
2243 return true;
2246 override final Expression toLvalue(Scope* sc, Expression e)
2248 return this;
2251 override void accept(Visitor v)
2253 v.visit(this);
2257 /***********************************************************
2258 * The dollar operator used when indexing or slicing an array. E.g `a[$]`, `a[1 .. $]` etc.
2260 * https://dlang.org/spec/arrays.html#array-length
2262 extern (C++) final class DollarExp : IdentifierExp
2264 extern (D) this(const ref Loc loc)
2266 super(loc, Id.dollar);
2269 override void accept(Visitor v)
2271 v.visit(this);
2275 /***********************************************************
2276 * Won't be generated by parser.
2278 extern (C++) final class DsymbolExp : Expression
2280 Dsymbol s;
2281 bool hasOverloads;
2283 extern (D) this(const ref Loc loc, Dsymbol s, bool hasOverloads = true) @safe
2285 super(loc, EXP.dSymbol);
2286 this.s = s;
2287 this.hasOverloads = hasOverloads;
2290 override bool isLvalue()
2292 return true;
2295 override Expression toLvalue(Scope* sc, Expression e)
2297 return this;
2300 override void accept(Visitor v)
2302 v.visit(this);
2306 /***********************************************************
2307 * https://dlang.org/spec/expression.html#this
2309 extern (C++) class ThisExp : Expression
2311 VarDeclaration var;
2313 extern (D) this(const ref Loc loc) @safe
2315 super(loc, EXP.this_);
2316 //printf("ThisExp::ThisExp() loc = %d\n", loc.linnum);
2319 this(const ref Loc loc, const EXP tok) @safe
2321 super(loc, tok);
2322 //printf("ThisExp::ThisExp() loc = %d\n", loc.linnum);
2325 override ThisExp syntaxCopy()
2327 auto r = cast(ThisExp) super.syntaxCopy();
2328 // require new semantic (possibly new `var` etc.)
2329 r.type = null;
2330 r.var = null;
2331 return r;
2334 override Optional!bool toBool()
2336 // `this` is never null (what about structs?)
2337 return typeof(return)(true);
2340 override bool isLvalue()
2342 return true;
2345 override Expression toLvalue(Scope* sc, Expression e)
2347 return this;
2350 override void accept(Visitor v)
2352 v.visit(this);
2356 /***********************************************************
2357 * https://dlang.org/spec/expression.html#super
2359 extern (C++) final class SuperExp : ThisExp
2361 extern (D) this(const ref Loc loc) @safe
2363 super(loc, EXP.super_);
2366 override bool isLvalue()
2368 // Class `super` should be an rvalue
2369 return false;
2372 override Expression toLvalue(Scope* sc, Expression e)
2374 // Class `super` is an rvalue
2375 return Expression.toLvalue(sc, e);
2378 override void accept(Visitor v)
2380 v.visit(this);
2384 /***********************************************************
2385 * A compile-time known `null` value
2387 * https://dlang.org/spec/expression.html#null
2389 extern (C++) final class NullExp : Expression
2391 extern (D) this(const ref Loc loc, Type type = null) scope @safe
2393 super(loc, EXP.null_);
2394 this.type = type;
2397 override bool equals(const RootObject o) const
2399 if (auto e = o.isExpression())
2401 if (e.op == EXP.null_ && type.equals(e.type))
2403 return true;
2406 return false;
2409 override Optional!bool toBool()
2411 // null in any type is false
2412 return typeof(return)(false);
2415 override StringExp toStringExp()
2417 if (implicitConvTo(Type.tstring))
2419 auto se = new StringExp(loc, (cast(char*)mem.xcalloc(1, 1))[0 .. 0]);
2420 se.type = Type.tstring;
2421 return se;
2423 return null;
2426 override void accept(Visitor v)
2428 v.visit(this);
2432 /***********************************************************
2433 * https://dlang.org/spec/expression.html#string_literals
2435 extern (C++) final class StringExp : Expression
2437 char postfix = NoPostfix; // 'c', 'w', 'd'
2438 OwnedBy ownedByCtfe = OwnedBy.code;
2439 private union
2441 char* string; // if sz == 1
2442 wchar* wstring; // if sz == 2
2443 dchar* dstring; // if sz == 4
2444 } // (const if ownedByCtfe == OwnedBy.code)
2445 size_t len; // number of code units
2446 ubyte sz = 1; // 1: char, 2: wchar, 4: dchar
2449 * Whether the string literal's type is fixed
2450 * Example:
2451 * ---
2452 * wstring x = "abc"; // OK, string literal is flexible
2453 * wstring y = cast(string) "abc"; // Error: type was committed after cast
2454 * ---
2456 bool committed;
2458 /// If the string is parsed from a hex string literal
2459 bool hexString = false;
2461 enum char NoPostfix = 0;
2463 extern (D) this(const ref Loc loc, const(void)[] string) scope
2465 super(loc, EXP.string_);
2466 this.string = cast(char*)string.ptr; // note that this.string should be const
2467 this.len = string.length;
2468 this.sz = 1; // work around LDC bug #1286
2471 extern (D) this(const ref Loc loc, const(void)[] string, size_t len, ubyte sz, char postfix = NoPostfix) scope
2473 super(loc, EXP.string_);
2474 this.string = cast(char*)string.ptr; // note that this.string should be const
2475 this.len = len;
2476 this.sz = sz;
2477 this.postfix = postfix;
2480 static StringExp create(const ref Loc loc, const(char)* s)
2482 return new StringExp(loc, s.toDString());
2485 static StringExp create(const ref Loc loc, const(void)* string, size_t len)
2487 return new StringExp(loc, string[0 .. len]);
2490 // Same as create, but doesn't allocate memory.
2491 static void emplace(UnionExp* pue, const ref Loc loc, const(char)* s)
2493 emplaceExp!(StringExp)(pue, loc, s.toDString());
2496 extern (D) static void emplace(UnionExp* pue, const ref Loc loc, const(void)[] string)
2498 emplaceExp!(StringExp)(pue, loc, string);
2501 extern (D) static void emplace(UnionExp* pue, const ref Loc loc, const(void)[] string, size_t len, ubyte sz, char postfix)
2503 emplaceExp!(StringExp)(pue, loc, string, len, sz, postfix);
2506 override bool equals(const RootObject o) const
2508 //printf("StringExp::equals('%s') %s\n", o.toChars(), toChars());
2509 if (auto e = o.isExpression())
2511 if (auto se = e.isStringExp())
2513 return compare(se) == 0;
2516 return false;
2519 /**********************************
2520 * Return the number of code units the string would be if it were re-encoded
2521 * as tynto.
2522 * Params:
2523 * tynto = code unit type of the target encoding
2524 * Returns:
2525 * number of code units
2527 size_t numberOfCodeUnits(int tynto = 0) const
2529 int encSize;
2530 switch (tynto)
2532 case 0: return len;
2533 case Tchar: encSize = 1; break;
2534 case Twchar: encSize = 2; break;
2535 case Tdchar: encSize = 4; break;
2536 default:
2537 assert(0);
2539 if (sz == encSize)
2540 return len;
2542 size_t result = 0;
2543 dchar c;
2545 switch (sz)
2547 case 1:
2548 for (size_t u = 0; u < len;)
2550 if (const s = utf_decodeChar(string[0 .. len], u, c))
2552 error(loc, "%.*s", cast(int)s.length, s.ptr);
2553 return 0;
2555 result += utf_codeLength(encSize, c);
2557 break;
2559 case 2:
2560 for (size_t u = 0; u < len;)
2562 if (const s = utf_decodeWchar(wstring[0 .. len], u, c))
2564 error(loc, "%.*s", cast(int)s.length, s.ptr);
2565 return 0;
2567 result += utf_codeLength(encSize, c);
2569 break;
2571 case 4:
2572 foreach (u; 0 .. len)
2574 result += utf_codeLength(encSize, dstring[u]);
2576 break;
2578 default:
2579 assert(0);
2581 return result;
2584 /**********************************************
2585 * Write the contents of the string to dest.
2586 * Use numberOfCodeUnits() to determine size of result.
2587 * Params:
2588 * dest = destination
2589 * tyto = encoding type of the result
2590 * zero = add terminating 0
2592 void writeTo(void* dest, bool zero, int tyto = 0) const
2594 int encSize;
2595 switch (tyto)
2597 case 0: encSize = sz; break;
2598 case Tchar: encSize = 1; break;
2599 case Twchar: encSize = 2; break;
2600 case Tdchar: encSize = 4; break;
2601 default:
2602 assert(0);
2604 if (sz == encSize)
2606 memcpy(dest, string, len * sz);
2607 if (zero)
2608 memset(dest + len * sz, 0, sz);
2610 else
2611 assert(0);
2614 /*********************************************
2615 * Get the code unit at index i
2616 * Params:
2617 * i = index
2618 * Returns:
2619 * code unit at index i
2621 dchar getCodeUnit(size_t i) const pure
2623 assert(i < len);
2624 final switch (sz)
2626 case 1:
2627 return string[i];
2628 case 2:
2629 return wstring[i];
2630 case 4:
2631 return dstring[i];
2635 /*********************************************
2636 * Set the code unit at index i to c
2637 * Params:
2638 * i = index
2639 * c = code unit to set it to
2641 void setCodeUnit(size_t i, dchar c)
2643 assert(i < len);
2644 final switch (sz)
2646 case 1:
2647 string[i] = cast(char)c;
2648 break;
2649 case 2:
2650 wstring[i] = cast(wchar)c;
2651 break;
2652 case 4:
2653 dstring[i] = c;
2654 break;
2658 override StringExp toStringExp()
2660 return this;
2663 /****************************************
2664 * Convert string to char[].
2666 StringExp toUTF8(Scope* sc)
2668 if (sz != 1)
2670 // Convert to UTF-8 string
2671 committed = false;
2672 Expression e = castTo(sc, Type.tchar.arrayOf());
2673 e = e.optimize(WANTvalue);
2674 auto se = e.isStringExp();
2675 assert(se.sz == 1);
2676 return se;
2678 return this;
2682 * Compare two `StringExp` by length, then value
2684 * The comparison is not the usual C-style comparison as seen with
2685 * `strcmp` or `memcmp`, but instead first compare based on the length.
2686 * This allows both faster lookup and sorting when comparing sparse data.
2688 * This ordering scheme is relied on by the string-switching feature.
2689 * Code in Druntime's `core.internal.switch_` relies on this ordering
2690 * when doing a binary search among case statements.
2692 * Both `StringExp` should be of the same encoding.
2694 * Params:
2695 * se2 = String expression to compare `this` to
2697 * Returns:
2698 * `0` when `this` is equal to se2, a value greater than `0` if
2699 * `this` should be considered greater than `se2`,
2700 * and a value less than `0` if `this` is lesser than `se2`.
2702 int compare(const StringExp se2) const nothrow pure @nogc
2704 //printf("StringExp::compare()\n");
2705 const len1 = len;
2706 const len2 = se2.len;
2708 assert(this.sz == se2.sz, "Comparing string expressions of different sizes");
2709 //printf("sz = %d, len1 = %d, len2 = %d\n", sz, cast(int)len1, cast(int)len2);
2710 if (len1 == len2)
2712 switch (sz)
2714 case 1:
2715 return memcmp(string, se2.string, len1);
2717 case 2:
2719 wchar* s1 = cast(wchar*)string;
2720 wchar* s2 = cast(wchar*)se2.string;
2721 foreach (u; 0 .. len)
2723 if (s1[u] != s2[u])
2724 return s1[u] - s2[u];
2727 break;
2728 case 4:
2730 dchar* s1 = cast(dchar*)string;
2731 dchar* s2 = cast(dchar*)se2.string;
2732 foreach (u; 0 .. len)
2734 if (s1[u] != s2[u])
2735 return s1[u] - s2[u];
2738 break;
2739 default:
2740 assert(0);
2743 return cast(int)(len1 - len2);
2746 override Optional!bool toBool()
2748 // Keep the old behaviour for this refactoring
2749 // Should probably match language spec instead and check for length
2750 return typeof(return)(true);
2753 override bool isLvalue()
2755 /* string literal is rvalue in default, but
2756 * conversion to reference of static array is only allowed.
2758 return (type && type.toBasetype().ty == Tsarray);
2761 override Expression toLvalue(Scope* sc, Expression e)
2763 //printf("StringExp::toLvalue(%s) type = %s\n", toChars(), type ? type.toChars() : NULL);
2764 return (type && type.toBasetype().ty == Tsarray) ? this : Expression.toLvalue(sc, e);
2767 override Expression modifiableLvalue(Scope* sc, Expression e)
2769 error(loc, "cannot modify string literal `%s`", toChars());
2770 return ErrorExp.get();
2773 /********************************
2774 * Convert string contents to a 0 terminated string,
2775 * allocated by mem.xmalloc().
2777 extern (D) const(char)[] toStringz() const
2779 auto nbytes = len * sz;
2780 char* s = cast(char*)mem.xmalloc(nbytes + sz);
2781 writeTo(s, true);
2782 return s[0 .. nbytes];
2785 extern (D) const(char)[] peekString() const
2787 assert(sz == 1);
2788 return this.string[0 .. len];
2791 extern (D) const(wchar)[] peekWstring() const
2793 assert(sz == 2);
2794 return this.wstring[0 .. len];
2797 extern (D) const(dchar)[] peekDstring() const
2799 assert(sz == 4);
2800 return this.dstring[0 .. len];
2803 /*******************
2804 * Get a slice of the data.
2806 extern (D) const(ubyte)[] peekData() const
2808 return cast(const(ubyte)[])this.string[0 .. len * sz];
2811 /*******************
2812 * Borrow a slice of the data, so the caller can modify
2813 * it in-place (!)
2815 extern (D) ubyte[] borrowData()
2817 return cast(ubyte[])this.string[0 .. len * sz];
2820 /***********************
2821 * Set new string data.
2822 * `this` becomes the new owner of the data.
2824 extern (D) void setData(void* s, size_t len, ubyte sz)
2826 this.string = cast(char*)s;
2827 this.len = len;
2828 this.sz = sz;
2831 override void accept(Visitor v)
2833 v.visit(this);
2837 /***********************************************************
2838 * A sequence of expressions
2840 * ---
2841 * alias AliasSeq(T...) = T;
2842 * alias Tup = AliasSeq!(3, int, "abc");
2843 * ---
2845 extern (C++) final class TupleExp : Expression
2847 /* Tuple-field access may need to take out its side effect part.
2848 * For example:
2849 * foo().tupleof
2850 * is rewritten as:
2851 * (ref __tup = foo(); tuple(__tup.field0, __tup.field1, ...))
2852 * The declaration of temporary variable __tup will be stored in TupleExp.e0.
2854 Expression e0;
2856 Expressions* exps;
2858 extern (D) this(const ref Loc loc, Expression e0, Expressions* exps) @safe
2860 super(loc, EXP.tuple);
2861 //printf("TupleExp(this = %p)\n", this);
2862 this.e0 = e0;
2863 this.exps = exps;
2866 extern (D) this(const ref Loc loc, Expressions* exps) @safe
2868 super(loc, EXP.tuple);
2869 //printf("TupleExp(this = %p)\n", this);
2870 this.exps = exps;
2873 extern (D) this(const ref Loc loc, TupleDeclaration tup)
2875 super(loc, EXP.tuple);
2876 this.exps = new Expressions();
2878 this.exps.reserve(tup.objects.length);
2879 foreach (o; *tup.objects)
2881 if (Dsymbol s = getDsymbol(o))
2883 /* If tuple element represents a symbol, translate to DsymbolExp
2884 * to supply implicit 'this' if needed later.
2886 Expression e = new DsymbolExp(loc, s);
2887 this.exps.push(e);
2889 else if (auto eo = o.isExpression())
2891 auto e = eo.copy();
2892 e.loc = loc; // https://issues.dlang.org/show_bug.cgi?id=15669
2893 this.exps.push(e);
2895 else if (auto t = o.isType())
2897 Expression e = new TypeExp(loc, t);
2898 this.exps.push(e);
2900 else
2902 error(loc, "`%s` is not an expression", o.toChars());
2907 static TupleExp create(const ref Loc loc, Expressions* exps) @safe
2909 return new TupleExp(loc, exps);
2912 override TupleExp syntaxCopy()
2914 return new TupleExp(loc, e0 ? e0.syntaxCopy() : null, arraySyntaxCopy(exps));
2917 override bool equals(const RootObject o) const
2919 if (this == o)
2920 return true;
2921 if (auto e = o.isExpression())
2922 if (auto te = e.isTupleExp())
2924 if (exps.length != te.exps.length)
2925 return false;
2926 if (e0 && !e0.equals(te.e0) || !e0 && te.e0)
2927 return false;
2928 foreach (i, e1; *exps)
2930 auto e2 = (*te.exps)[i];
2931 if (!e1.equals(e2))
2932 return false;
2934 return true;
2936 return false;
2939 override void accept(Visitor v)
2941 v.visit(this);
2945 /***********************************************************
2946 * [ e1, e2, e3, ... ]
2948 * https://dlang.org/spec/expression.html#array_literals
2950 extern (C++) final class ArrayLiteralExp : Expression
2952 OwnedBy ownedByCtfe = OwnedBy.code;
2953 bool onstack = false;
2955 /** If !is null, elements[] can be sparse and basis is used for the
2956 * "default" element value. In other words, non-null elements[i] overrides
2957 * this 'basis' value.
2959 Expression basis;
2961 Expressions* elements;
2963 extern (D) this(const ref Loc loc, Type type, Expressions* elements) @safe
2965 super(loc, EXP.arrayLiteral);
2966 this.type = type;
2967 this.elements = elements;
2970 extern (D) this(const ref Loc loc, Type type, Expression e)
2972 super(loc, EXP.arrayLiteral);
2973 this.type = type;
2974 elements = new Expressions();
2975 elements.push(e);
2978 extern (D) this(const ref Loc loc, Type type, Expression basis, Expressions* elements) @safe
2980 super(loc, EXP.arrayLiteral);
2981 this.type = type;
2982 this.basis = basis;
2983 this.elements = elements;
2986 static ArrayLiteralExp create(const ref Loc loc, Expressions* elements) @safe
2988 return new ArrayLiteralExp(loc, null, elements);
2991 // Same as create, but doesn't allocate memory.
2992 static void emplace(UnionExp* pue, const ref Loc loc, Expressions* elements)
2994 emplaceExp!(ArrayLiteralExp)(pue, loc, null, elements);
2997 override ArrayLiteralExp syntaxCopy()
2999 return new ArrayLiteralExp(loc,
3000 null,
3001 basis ? basis.syntaxCopy() : null,
3002 arraySyntaxCopy(elements));
3005 override bool equals(const RootObject o) const
3007 if (this == o)
3008 return true;
3009 auto e = o.isExpression();
3010 if (!e)
3011 return false;
3012 if (auto ae = e.isArrayLiteralExp())
3014 if (elements.length != ae.elements.length)
3015 return false;
3016 if (elements.length == 0 && !type.equals(ae.type))
3018 return false;
3021 foreach (i, e1; *elements)
3023 auto e2 = (*ae.elements)[i];
3024 auto e1x = e1 ? e1 : basis;
3025 auto e2x = e2 ? e2 : ae.basis;
3027 if (e1x != e2x && (!e1x || !e2x || !e1x.equals(e2x)))
3028 return false;
3030 return true;
3032 return false;
3035 Expression getElement(size_t i)
3037 return this[i];
3040 Expression opIndex(size_t i)
3042 auto el = (*elements)[i];
3043 return el ? el : basis;
3046 override Optional!bool toBool()
3048 size_t dim = elements ? elements.length : 0;
3049 return typeof(return)(dim != 0);
3052 override StringExp toStringExp()
3054 TY telem = type.nextOf().toBasetype().ty;
3055 if (telem.isSomeChar || (telem == Tvoid && (!elements || elements.length == 0)))
3057 ubyte sz = 1;
3058 if (telem == Twchar)
3059 sz = 2;
3060 else if (telem == Tdchar)
3061 sz = 4;
3063 OutBuffer buf;
3064 if (elements)
3066 foreach (i; 0 .. elements.length)
3068 auto ch = this[i];
3069 if (ch.op != EXP.int64)
3070 return null;
3071 if (sz == 1)
3072 buf.writeByte(cast(uint)ch.toInteger());
3073 else if (sz == 2)
3074 buf.writeword(cast(uint)ch.toInteger());
3075 else
3076 buf.write4(cast(uint)ch.toInteger());
3079 char prefix;
3080 if (sz == 1)
3082 prefix = 'c';
3083 buf.writeByte(0);
3085 else if (sz == 2)
3087 prefix = 'w';
3088 buf.writeword(0);
3090 else
3092 prefix = 'd';
3093 buf.write4(0);
3096 const size_t len = buf.length / sz - 1;
3097 auto se = new StringExp(loc, buf.extractSlice()[0 .. len * sz], len, sz, prefix);
3098 se.sz = sz;
3099 se.type = type;
3100 return se;
3102 return null;
3105 override void accept(Visitor v)
3107 v.visit(this);
3111 /***********************************************************
3112 * [ key0 : value0, key1 : value1, ... ]
3114 * https://dlang.org/spec/expression.html#associative_array_literals
3116 extern (C++) final class AssocArrayLiteralExp : Expression
3118 OwnedBy ownedByCtfe = OwnedBy.code;
3120 Expressions* keys;
3121 Expressions* values;
3122 /// Lower to core.internal.newaa for static initializaton
3123 Expression lowering;
3125 extern (D) this(const ref Loc loc, Expressions* keys, Expressions* values) @safe
3127 super(loc, EXP.assocArrayLiteral);
3128 assert(keys.length == values.length);
3129 this.keys = keys;
3130 this.values = values;
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.isAssocArrayLiteralExp())
3142 if (keys.length != ae.keys.length)
3143 return false;
3144 size_t count = 0;
3145 foreach (i, key; *keys)
3147 foreach (j, akey; *ae.keys)
3149 if (key.equals(akey))
3151 if (!(*values)[i].equals((*ae.values)[j]))
3152 return false;
3153 ++count;
3157 return count == keys.length;
3159 return false;
3162 override AssocArrayLiteralExp syntaxCopy()
3164 return new AssocArrayLiteralExp(loc, arraySyntaxCopy(keys), arraySyntaxCopy(values));
3167 override Optional!bool toBool()
3169 size_t dim = keys.length;
3170 return typeof(return)(dim != 0);
3173 override void accept(Visitor v)
3175 v.visit(this);
3179 enum stageScrub = 0x1; /// scrubReturnValue is running
3180 enum stageSearchPointers = 0x2; /// hasNonConstPointers is running
3181 enum stageOptimize = 0x4; /// optimize is running
3182 enum stageApply = 0x8; /// apply is running
3183 enum stageInlineScan = 0x10; /// inlineScan is running
3184 enum stageToCBuffer = 0x20; /// toCBuffer is running
3186 /***********************************************************
3187 * sd( e1, e2, e3, ... )
3189 extern (C++) final class StructLiteralExp : Expression
3191 StructDeclaration sd; /// which aggregate this is for
3192 Expressions* elements; /// parallels sd.fields[] with null entries for fields to skip
3193 Type stype; /// final type of result (can be different from sd's type)
3195 // `inlineCopy` is only used temporarily in the `inline.d` pass,
3196 // while `sym` is only used in `e2ir/s2ir/tocsym` which comes after
3197 union
3199 Symbol* sym; /// back end symbol to initialize with literal
3201 /// those fields need to prevent a infinite recursion when one field of struct initialized with 'this' pointer.
3202 StructLiteralExp inlinecopy;
3205 /** pointer to the origin instance of the expression.
3206 * once a new expression is created, origin is set to 'this'.
3207 * anytime when an expression copy is created, 'origin' pointer is set to
3208 * 'origin' pointer value of the original expression.
3210 StructLiteralExp origin;
3213 /** anytime when recursive function is calling, 'stageflags' marks with bit flag of
3214 * current stage and unmarks before return from this function.
3215 * 'inlinecopy' uses similar 'stageflags' and from multiple evaluation 'doInline'
3216 * (with infinite recursion) of this expression.
3218 ubyte stageflags;
3220 bool useStaticInit; /// if this is true, use the StructDeclaration's init symbol
3221 bool isOriginal = false; /// used when moving instances to indicate `this is this.origin`
3222 OwnedBy ownedByCtfe = OwnedBy.code;
3224 extern (D) this(const ref Loc loc, StructDeclaration sd, Expressions* elements, Type stype = null) @safe
3226 super(loc, EXP.structLiteral);
3227 this.sd = sd;
3228 if (!elements)
3229 elements = new Expressions();
3230 this.elements = elements;
3231 this.stype = stype;
3232 this.origin = this;
3233 //printf("StructLiteralExp::StructLiteralExp(%s)\n", toChars());
3236 static StructLiteralExp create(const ref Loc loc, StructDeclaration sd, void* elements, Type stype = null)
3238 return new StructLiteralExp(loc, sd, cast(Expressions*)elements, stype);
3241 override bool equals(const RootObject o) const
3243 if (this == o)
3244 return true;
3245 auto e = o.isExpression();
3246 if (!e)
3247 return false;
3248 if (auto se = e.isStructLiteralExp())
3250 if (!type.equals(se.type))
3251 return false;
3252 if (elements.length != se.elements.length)
3253 return false;
3254 foreach (i, e1; *elements)
3256 auto e2 = (*se.elements)[i];
3257 if (e1 != e2 && (!e1 || !e2 || !e1.equals(e2)))
3258 return false;
3260 return true;
3262 return false;
3265 override StructLiteralExp syntaxCopy()
3267 auto exp = new StructLiteralExp(loc, sd, arraySyntaxCopy(elements), type ? type : stype);
3268 exp.origin = this;
3269 return exp;
3272 /**************************************
3273 * Gets expression at offset of type.
3274 * Returns NULL if not found.
3276 Expression getField(Type type, uint offset)
3278 //printf("StructLiteralExp::getField(this = %s, type = %s, offset = %u)\n",
3279 // /*toChars()*/"", type.toChars(), offset);
3280 Expression e = null;
3281 int i = getFieldIndex(type, offset);
3283 if (i != -1)
3285 //printf("\ti = %d\n", i);
3286 if (i >= sd.nonHiddenFields())
3287 return null;
3289 assert(i < elements.length);
3290 e = (*elements)[i];
3291 if (e)
3293 //printf("e = %s, e.type = %s\n", e.toChars(), e.type.toChars());
3295 /* If type is a static array, and e is an initializer for that array,
3296 * then the field initializer should be an array literal of e.
3298 auto tsa = type.isTypeSArray();
3299 if (tsa && e.type.castMod(0) != type.castMod(0))
3301 const length = cast(size_t)tsa.dim.toInteger();
3302 auto z = new Expressions(length);
3303 foreach (ref q; *z)
3304 q = e.copy();
3305 e = new ArrayLiteralExp(loc, type, z);
3307 else
3309 e = e.copy();
3310 e.type = type;
3312 if (useStaticInit && e.type.needsNested())
3313 if (auto se = e.isStructLiteralExp())
3315 se.useStaticInit = true;
3319 return e;
3322 /************************************
3323 * Get index of field.
3324 * Returns -1 if not found.
3326 int getFieldIndex(Type type, uint offset)
3328 /* Find which field offset is by looking at the field offsets
3330 if (elements.length)
3332 const sz = type.size();
3333 if (sz == SIZE_INVALID)
3334 return -1;
3335 foreach (i, v; sd.fields)
3337 if (offset == v.offset && sz == v.type.size())
3339 /* context fields might not be filled. */
3340 if (i >= sd.nonHiddenFields())
3341 return cast(int)i;
3342 if (auto e = (*elements)[i])
3344 return cast(int)i;
3346 break;
3350 return -1;
3353 override Expression addDtorHook(Scope* sc)
3355 /* If struct requires a destructor, rewrite as:
3356 * (S tmp = S()),tmp
3357 * so that the destructor can be hung on tmp.
3359 if (sd.dtor && sc.func)
3361 /* Make an identifier for the temporary of the form:
3362 * __sl%s%d, where %s is the struct name
3364 char[10] buf = void;
3365 const prefix = "__sl";
3366 const ident = sd.ident.toString;
3367 const fullLen = prefix.length + ident.length;
3368 const len = fullLen < buf.length ? fullLen : buf.length;
3369 buf[0 .. prefix.length] = prefix;
3370 buf[prefix.length .. len] = ident[0 .. len - prefix.length];
3372 auto tmp = copyToTemp(0, buf[0 .. len], this);
3373 Expression ae = new DeclarationExp(loc, tmp);
3374 Expression e = new CommaExp(loc, ae, new VarExp(loc, tmp));
3375 e = e.expressionSemantic(sc);
3376 return e;
3378 return this;
3381 override Expression toLvalue(Scope* sc, Expression e)
3383 if (sc.flags & SCOPE.Cfile)
3384 return this; // C struct literals are lvalues
3385 else
3386 return Expression.toLvalue(sc, e);
3389 override void accept(Visitor v)
3391 v.visit(this);
3395 /***********************************************************
3396 * C11 6.5.2.5
3397 * ( type-name ) { initializer-list }
3399 extern (C++) final class CompoundLiteralExp : Expression
3401 Initializer initializer; /// initializer-list
3403 extern (D) this(const ref Loc loc, Type type_name, Initializer initializer) @safe
3405 super(loc, EXP.compoundLiteral);
3406 super.type = type_name;
3407 this.initializer = initializer;
3408 //printf("CompoundLiteralExp::CompoundLiteralExp(%s)\n", toChars());
3411 override void accept(Visitor v)
3413 v.visit(this);
3417 /***********************************************************
3418 * Mainly just a placeholder
3420 extern (C++) final class TypeExp : Expression
3422 bool parens; // if this is a parenthesized expression
3424 extern (D) this(const ref Loc loc, Type type) @safe
3426 super(loc, EXP.type);
3427 //printf("TypeExp::TypeExp(%s)\n", type.toChars());
3428 this.type = type;
3431 override TypeExp syntaxCopy()
3433 return new TypeExp(loc, type.syntaxCopy());
3436 override bool checkType()
3438 error(loc, "type `%s` is not an expression", toChars());
3439 return true;
3442 override bool checkValue()
3444 error(loc, "type `%s` has no value", toChars());
3445 return true;
3448 override void accept(Visitor v)
3450 v.visit(this);
3454 /***********************************************************
3455 * Mainly just a placeholder of
3456 * Package, Module, Nspace, and TemplateInstance (including TemplateMixin)
3458 * A template instance that requires IFTI:
3459 * foo!tiargs(fargs) // foo!tiargs
3460 * is left until CallExp::semantic() or resolveProperties()
3462 extern (C++) final class ScopeExp : Expression
3464 ScopeDsymbol sds;
3466 extern (D) this(const ref Loc loc, ScopeDsymbol sds) @safe
3468 super(loc, EXP.scope_);
3469 //printf("ScopeExp::ScopeExp(sds = '%s')\n", sds.toChars());
3470 //static int count; if (++count == 38) *(char*)0=0;
3471 this.sds = sds;
3472 assert(!sds.isTemplateDeclaration()); // instead, you should use TemplateExp
3475 override ScopeExp syntaxCopy()
3477 return new ScopeExp(loc, sds.syntaxCopy(null));
3480 override bool checkType()
3482 if (sds.isPackage())
3484 error(loc, "%s `%s` has no type", sds.kind(), sds.toChars());
3485 return true;
3487 if (auto ti = sds.isTemplateInstance())
3489 //assert(ti.needsTypeInference(sc));
3490 if (ti.tempdecl &&
3491 ti.semantictiargsdone &&
3492 ti.semanticRun == PASS.initial)
3494 error(loc, "partial %s `%s` has no type", sds.kind(), toChars());
3495 return true;
3498 return false;
3501 override bool checkValue()
3503 error(loc, "%s `%s` has no value", sds.kind(), sds.toChars());
3504 return true;
3507 override void accept(Visitor v)
3509 v.visit(this);
3513 /***********************************************************
3514 * Mainly just a placeholder
3516 extern (C++) final class TemplateExp : Expression
3518 TemplateDeclaration td;
3519 FuncDeclaration fd;
3521 extern (D) this(const ref Loc loc, TemplateDeclaration td, FuncDeclaration fd = null) @safe
3523 super(loc, EXP.template_);
3524 //printf("TemplateExp(): %s\n", td.toChars());
3525 this.td = td;
3526 this.fd = fd;
3529 override bool isLvalue()
3531 return fd !is null;
3534 override Expression toLvalue(Scope* sc, Expression e)
3536 if (!fd)
3537 return Expression.toLvalue(sc, e);
3539 assert(sc);
3540 return symbolToExp(fd, loc, sc, true);
3543 override bool checkType()
3545 error(loc, "%s `%s` has no type", td.kind(), toChars());
3546 return true;
3549 override bool checkValue()
3551 error(loc, "%s `%s` has no value", td.kind(), toChars());
3552 return true;
3555 override void accept(Visitor v)
3557 v.visit(this);
3561 /***********************************************************
3562 * newtype(arguments)
3564 extern (C++) final class NewExp : Expression
3566 Expression thisexp; // if !=null, 'this' for class being allocated
3567 Type newtype;
3568 Expressions* arguments; // Array of Expression's
3569 Identifiers* names; // Array of names corresponding to expressions
3571 Expression argprefix; // expression to be evaluated just before arguments[]
3572 CtorDeclaration member; // constructor function
3573 bool onstack; // allocate on stack
3574 bool thrownew; // this NewExp is the expression of a ThrowStatement
3576 Expression lowering; // lowered druntime hook: `_d_new{class,itemT}`
3578 /// Puts the `arguments` and `names` into an `ArgumentList` for easily passing them around.
3579 /// The fields are still separate for backwards compatibility
3580 extern (D) ArgumentList argumentList() { return ArgumentList(arguments, names); }
3582 extern (D) this(const ref Loc loc, Expression thisexp, Type newtype, Expressions* arguments, Identifiers* names = null) @safe
3584 super(loc, EXP.new_);
3585 this.thisexp = thisexp;
3586 this.newtype = newtype;
3587 this.arguments = arguments;
3588 this.names = names;
3591 static NewExp create(const ref Loc loc, Expression thisexp, Type newtype, Expressions* arguments) @safe
3593 return new NewExp(loc, thisexp, newtype, arguments);
3596 override NewExp syntaxCopy()
3598 return new NewExp(loc,
3599 thisexp ? thisexp.syntaxCopy() : null,
3600 newtype.syntaxCopy(),
3601 arraySyntaxCopy(arguments),
3602 names ? names.copy() : null);
3605 override void accept(Visitor v)
3607 v.visit(this);
3611 /***********************************************************
3612 * class baseclasses { } (arguments)
3614 extern (C++) final class NewAnonClassExp : Expression
3616 Expression thisexp; // if !=null, 'this' for class being allocated
3617 ClassDeclaration cd; // class being instantiated
3618 Expressions* arguments; // Array of Expression's to call class constructor
3620 extern (D) this(const ref Loc loc, Expression thisexp, ClassDeclaration cd, Expressions* arguments) @safe
3622 super(loc, EXP.newAnonymousClass);
3623 this.thisexp = thisexp;
3624 this.cd = cd;
3625 this.arguments = arguments;
3628 override NewAnonClassExp syntaxCopy()
3630 return new NewAnonClassExp(loc, thisexp ? thisexp.syntaxCopy() : null, cd.syntaxCopy(null), arraySyntaxCopy(arguments));
3633 override void accept(Visitor v)
3635 v.visit(this);
3639 /***********************************************************
3641 extern (C++) class SymbolExp : Expression
3643 Declaration var;
3644 Dsymbol originalScope; // original scope before inlining
3645 bool hasOverloads;
3647 extern (D) this(const ref Loc loc, EXP op, Declaration var, bool hasOverloads) @safe
3649 super(loc, op);
3650 assert(var);
3651 this.var = var;
3652 this.hasOverloads = hasOverloads;
3655 override void accept(Visitor v)
3657 v.visit(this);
3661 /***********************************************************
3662 * Offset from symbol
3664 extern (C++) final class SymOffExp : SymbolExp
3666 dinteger_t offset;
3668 extern (D) this(const ref Loc loc, Declaration var, dinteger_t offset, bool hasOverloads = true)
3670 if (auto v = var.isVarDeclaration())
3672 // FIXME: This error report will never be handled anyone.
3673 // It should be done before the SymOffExp construction.
3674 if (v.needThis())
3676 auto t = v.isThis();
3677 assert(t);
3678 .error(loc, "taking the address of non-static variable `%s` requires an instance of `%s`", v.toChars(), t.toChars());
3680 hasOverloads = false;
3682 super(loc, EXP.symbolOffset, var, hasOverloads);
3683 this.offset = offset;
3686 override Optional!bool toBool()
3688 return typeof(return)(true);
3691 override void accept(Visitor v)
3693 v.visit(this);
3697 /***********************************************************
3698 * Variable
3700 extern (C++) final class VarExp : SymbolExp
3702 bool delegateWasExtracted;
3703 extern (D) this(const ref Loc loc, Declaration var, bool hasOverloads = true) @safe
3705 if (var.isVarDeclaration())
3706 hasOverloads = false;
3708 super(loc, EXP.variable, var, hasOverloads);
3709 //printf("VarExp(this = %p, '%s', loc = %s)\n", this, var.toChars(), loc.toChars());
3710 //if (strcmp(var.ident.toChars(), "func") == 0) assert(0);
3711 this.type = var.type;
3714 static VarExp create(const ref Loc loc, Declaration var, bool hasOverloads = true) @safe
3716 return new VarExp(loc, var, hasOverloads);
3719 override bool equals(const RootObject o) const
3721 if (this == o)
3722 return true;
3723 if (auto ne = o.isExpression().isVarExp())
3725 if (type.toHeadMutable().equals(ne.type.toHeadMutable()) && var == ne.var)
3727 return true;
3730 return false;
3733 override bool isLvalue()
3735 if (var.storage_class & (STC.lazy_ | STC.rvalue | STC.manifest))
3736 return false;
3737 return true;
3740 override Expression toLvalue(Scope* sc, Expression e)
3742 if (var.storage_class & STC.manifest)
3744 error(loc, "manifest constant `%s` cannot be modified", var.toChars());
3745 return ErrorExp.get();
3747 if (var.storage_class & STC.lazy_ && !delegateWasExtracted)
3749 error(loc, "lazy variable `%s` cannot be modified", var.toChars());
3750 return ErrorExp.get();
3752 if (var.ident == Id.ctfe)
3754 error(loc, "cannot modify compiler-generated variable `__ctfe`");
3755 return ErrorExp.get();
3757 if (var.ident == Id.dollar) // https://issues.dlang.org/show_bug.cgi?id=13574
3759 error(loc, "cannot modify operator `$`");
3760 return ErrorExp.get();
3762 return this;
3765 override Expression modifiableLvalue(Scope* sc, Expression e)
3767 //printf("VarExp::modifiableLvalue('%s')\n", var.toChars());
3768 if (var.storage_class & STC.manifest)
3770 error(loc, "cannot modify manifest constant `%s`", toChars());
3771 return ErrorExp.get();
3773 // See if this expression is a modifiable lvalue (i.e. not const)
3774 return Expression.modifiableLvalue(sc, e);
3777 override void accept(Visitor v)
3779 v.visit(this);
3783 /***********************************************************
3784 * Overload Set
3786 extern (C++) final class OverExp : Expression
3788 OverloadSet vars;
3790 extern (D) this(const ref Loc loc, OverloadSet s)
3792 super(loc, EXP.overloadSet);
3793 //printf("OverExp(this = %p, '%s')\n", this, var.toChars());
3794 vars = s;
3795 type = Type.tvoid;
3798 override bool isLvalue()
3800 return true;
3803 override Expression toLvalue(Scope* sc, Expression e)
3805 return this;
3808 override void accept(Visitor v)
3810 v.visit(this);
3814 /***********************************************************
3815 * Function/Delegate literal
3818 extern (C++) final class FuncExp : Expression
3820 FuncLiteralDeclaration fd;
3821 TemplateDeclaration td;
3822 TOK tok; // TOK.reserved, TOK.delegate_, TOK.function_
3824 extern (D) this(const ref Loc loc, Dsymbol s)
3826 super(loc, EXP.function_);
3827 this.td = s.isTemplateDeclaration();
3828 this.fd = s.isFuncLiteralDeclaration();
3829 if (td)
3831 assert(td.literal);
3832 assert(td.members && td.members.length == 1);
3833 fd = (*td.members)[0].isFuncLiteralDeclaration();
3835 tok = fd.tok; // save original kind of function/delegate/(infer)
3836 assert(fd.fbody);
3839 override bool equals(const RootObject o) const
3841 if (this == o)
3842 return true;
3843 auto e = o.isExpression();
3844 if (!e)
3845 return false;
3846 if (auto fe = e.isFuncExp())
3848 return fd == fe.fd;
3850 return false;
3853 extern (D) void genIdent(Scope* sc)
3855 if (fd.ident == Id.empty)
3857 const(char)[] s;
3858 if (fd.fes)
3859 s = "__foreachbody";
3860 else if (fd.tok == TOK.reserved)
3861 s = "__lambda";
3862 else if (fd.tok == TOK.delegate_)
3863 s = "__dgliteral";
3864 else
3865 s = "__funcliteral";
3867 DsymbolTable symtab;
3868 if (FuncDeclaration func = sc.parent.isFuncDeclaration())
3870 if (func.localsymtab is null)
3872 // Inside template constraint, symtab is not set yet.
3873 // Initialize it lazily.
3874 func.localsymtab = new DsymbolTable();
3876 symtab = func.localsymtab;
3878 else
3880 ScopeDsymbol sds = sc.parent.isScopeDsymbol();
3881 if (!sds.symtab)
3883 // Inside template constraint, symtab may not be set yet.
3884 // Initialize it lazily.
3885 assert(sds.isTemplateInstance());
3886 sds.symtab = new DsymbolTable();
3888 symtab = sds.symtab;
3890 assert(symtab);
3891 Identifier id = Identifier.generateId(s, symtab.length() + 1);
3892 fd.ident = id;
3893 if (td)
3894 td.ident = id;
3895 symtab.insert(td ? cast(Dsymbol)td : cast(Dsymbol)fd);
3899 override FuncExp syntaxCopy()
3901 if (td)
3902 return new FuncExp(loc, td.syntaxCopy(null));
3903 else if (fd.semanticRun == PASS.initial)
3904 return new FuncExp(loc, fd.syntaxCopy(null));
3905 else // https://issues.dlang.org/show_bug.cgi?id=13481
3906 // Prevent multiple semantic analysis of lambda body.
3907 return new FuncExp(loc, fd);
3910 extern (D) MATCH matchType(Type to, Scope* sc, FuncExp* presult, ErrorSink eSink)
3912 MATCH cannotInfer()
3914 eSink.error(loc, "cannot infer parameter types from `%s`", to.toChars());
3915 return MATCH.nomatch;
3918 //printf("FuncExp::matchType('%s'), to=%s\n", type ? type.toChars() : "null", to.toChars());
3919 if (presult)
3920 *presult = null;
3922 TypeFunction tof = null;
3923 if (to.ty == Tdelegate)
3925 if (tok == TOK.function_)
3927 eSink.error(loc, "cannot match function literal to delegate type `%s`", to.toChars());
3928 return MATCH.nomatch;
3930 tof = cast(TypeFunction)to.nextOf();
3932 else if (to.ty == Tpointer && (tof = to.nextOf().isTypeFunction()) !is null)
3934 if (tok == TOK.delegate_)
3936 eSink.error(loc, "cannot match delegate literal to function pointer type `%s`", to.toChars());
3937 return MATCH.nomatch;
3941 if (td)
3943 if (!tof)
3945 return cannotInfer();
3948 // Parameter types inference from 'tof'
3949 assert(td._scope);
3950 TypeFunction tf = fd.type.isTypeFunction();
3951 //printf("\ttof = %s\n", tof.toChars());
3952 //printf("\ttf = %s\n", tf.toChars());
3953 const dim = tf.parameterList.length;
3955 if (tof.parameterList.length != dim || tof.parameterList.varargs != tf.parameterList.varargs)
3956 return cannotInfer();
3958 auto tiargs = new Objects();
3959 tiargs.reserve(td.parameters.length);
3961 foreach (tp; *td.parameters)
3963 size_t u = 0;
3964 foreach (i, p; tf.parameterList)
3966 if (auto ti = p.type.isTypeIdentifier())
3967 if (ti && ti.ident == tp.ident)
3968 break;
3970 ++u;
3972 assert(u < dim);
3973 Parameter pto = tof.parameterList[u];
3974 Type t = pto.type;
3975 if (t.ty == Terror)
3976 return cannotInfer();
3977 tf.parameterList[u].storageClass = tof.parameterList[u].storageClass;
3978 tiargs.push(t);
3981 // Set target of return type inference
3982 if (!tf.next && tof.next)
3983 fd.treq = to;
3985 auto ti = new TemplateInstance(loc, td, tiargs);
3986 Expression ex = (new ScopeExp(loc, ti)).expressionSemantic(td._scope);
3988 // Reset inference target for the later re-semantic
3989 fd.treq = null;
3991 if (ex.op == EXP.error)
3992 return MATCH.nomatch;
3993 if (auto ef = ex.isFuncExp())
3994 return ef.matchType(to, sc, presult, eSink);
3995 else
3996 return cannotInfer();
3999 if (!tof || !tof.next)
4000 return MATCH.nomatch;
4002 assert(type && type != Type.tvoid);
4003 if (fd.type.ty == Terror)
4004 return MATCH.nomatch;
4005 auto tfx = fd.type.isTypeFunction();
4006 bool convertMatch = (type.ty != to.ty);
4008 if (fd.inferRetType && tfx.next.implicitConvTo(tof.next) == MATCH.convert)
4010 /* If return type is inferred and covariant return,
4011 * tweak return statements to required return type.
4013 * interface I {}
4014 * class C : Object, I{}
4016 * I delegate() dg = delegate() { return new class C(); }
4018 convertMatch = true;
4020 auto tfy = new TypeFunction(tfx.parameterList, tof.next,
4021 tfx.linkage, STC.undefined_);
4022 tfy.mod = tfx.mod;
4023 tfy.trust = tfx.trust;
4024 tfy.isnothrow = tfx.isnothrow;
4025 tfy.isnogc = tfx.isnogc;
4026 tfy.purity = tfx.purity;
4027 tfy.isproperty = tfx.isproperty;
4028 tfy.isref = tfx.isref;
4029 tfy.isInOutParam = tfx.isInOutParam;
4030 tfy.isInOutQual = tfx.isInOutQual;
4031 tfy.deco = tfy.merge().deco;
4033 tfx = tfy;
4035 Type tx;
4036 if (tok == TOK.delegate_ ||
4037 tok == TOK.reserved && (type.ty == Tdelegate || type.ty == Tpointer && to.ty == Tdelegate))
4039 // Allow conversion from implicit function pointer to delegate
4040 tx = new TypeDelegate(tfx);
4041 tx.deco = tx.merge().deco;
4043 else
4045 assert(tok == TOK.function_ || tok == TOK.reserved && type.ty == Tpointer || fd.errors);
4046 tx = tfx.pointerTo();
4048 //printf("\ttx = %s, to = %s\n", tx.toChars(), to.toChars());
4050 MATCH m = tx.implicitConvTo(to);
4051 if (m > MATCH.nomatch)
4053 // MATCH.exact: exact type match
4054 // MATCH.constant: covairiant type match (eg. attributes difference)
4055 // MATCH.convert: context conversion
4056 m = convertMatch ? MATCH.convert : tx.equals(to) ? MATCH.exact : MATCH.constant;
4058 if (presult)
4060 (*presult) = cast(FuncExp)copy();
4061 (*presult).type = to;
4063 // https://issues.dlang.org/show_bug.cgi?id=12508
4064 // Tweak function body for covariant returns.
4065 (*presult).fd.modifyReturns(sc, tof.next);
4068 else if (!cast(ErrorSinkNull)eSink)
4070 auto ts = toAutoQualChars(tx, to);
4071 eSink.error(loc, "cannot implicitly convert expression `%s` of type `%s` to `%s`",
4072 toChars(), ts[0], ts[1]);
4074 return m;
4077 override const(char)* toChars() const
4079 return fd.toChars();
4082 override bool checkType()
4084 if (td)
4086 error(loc, "template lambda has no type");
4087 return true;
4089 return false;
4092 override bool checkValue()
4094 if (td)
4096 error(loc, "template lambda has no value");
4097 return true;
4099 return false;
4102 override void accept(Visitor v)
4104 v.visit(this);
4108 /***********************************************************
4109 * Declaration of a symbol
4111 * D grammar allows declarations only as statements. However in AST representation
4112 * it can be part of any expression. This is used, for example, during internal
4113 * syntax re-writes to inject hidden symbols.
4115 extern (C++) final class DeclarationExp : Expression
4117 Dsymbol declaration;
4119 extern (D) this(const ref Loc loc, Dsymbol declaration) @safe
4121 super(loc, EXP.declaration);
4122 this.declaration = declaration;
4125 override DeclarationExp syntaxCopy()
4127 return new DeclarationExp(loc, declaration.syntaxCopy(null));
4130 override bool hasCode()
4132 if (auto vd = declaration.isVarDeclaration())
4134 return !(vd.storage_class & (STC.manifest | STC.static_));
4136 return false;
4139 override void accept(Visitor v)
4141 v.visit(this);
4145 /***********************************************************
4146 * typeid(int)
4148 extern (C++) final class TypeidExp : Expression
4150 RootObject obj;
4152 extern (D) this(const ref Loc loc, RootObject o) @safe
4154 super(loc, EXP.typeid_);
4155 this.obj = o;
4158 override TypeidExp syntaxCopy()
4160 return new TypeidExp(loc, objectSyntaxCopy(obj));
4163 override void accept(Visitor v)
4165 v.visit(this);
4169 /***********************************************************
4170 * __traits(identifier, args...)
4172 extern (C++) final class TraitsExp : Expression
4174 Identifier ident;
4175 Objects* args;
4177 extern (D) this(const ref Loc loc, Identifier ident, Objects* args) @safe
4179 super(loc, EXP.traits);
4180 this.ident = ident;
4181 this.args = args;
4184 override TraitsExp syntaxCopy()
4186 return new TraitsExp(loc, ident, TemplateInstance.arraySyntaxCopy(args));
4189 override void accept(Visitor v)
4191 v.visit(this);
4195 /***********************************************************
4196 * Generates a halt instruction
4198 * `assert(0)` gets rewritten to this with `CHECKACTION.halt`
4200 extern (C++) final class HaltExp : Expression
4202 extern (D) this(const ref Loc loc) @safe
4204 super(loc, EXP.halt);
4207 override void accept(Visitor v)
4209 v.visit(this);
4213 /***********************************************************
4214 * is(targ id tok tspec)
4215 * is(targ id == tok2)
4217 extern (C++) final class IsExp : Expression
4219 Type targ;
4220 Identifier id; // can be null
4221 Type tspec; // can be null
4222 TemplateParameters* parameters;
4223 TOK tok; // ':' or '=='
4224 TOK tok2; // 'struct', 'union', etc.
4226 extern (D) this(const ref Loc loc, Type targ, Identifier id, TOK tok, Type tspec, TOK tok2, TemplateParameters* parameters) scope @safe
4228 super(loc, EXP.is_);
4229 this.targ = targ;
4230 this.id = id;
4231 this.tok = tok;
4232 this.tspec = tspec;
4233 this.tok2 = tok2;
4234 this.parameters = parameters;
4237 override IsExp syntaxCopy()
4239 // This section is identical to that in TemplateDeclaration::syntaxCopy()
4240 TemplateParameters* p = null;
4241 if (parameters)
4243 p = new TemplateParameters(parameters.length);
4244 foreach (i, el; *parameters)
4245 (*p)[i] = el.syntaxCopy();
4247 return new IsExp(loc, targ.syntaxCopy(), id, tok, tspec ? tspec.syntaxCopy() : null, tok2, p);
4250 override void accept(Visitor v)
4252 v.visit(this);
4256 /***********************************************************
4257 * Base class for unary operators
4259 * https://dlang.org/spec/expression.html#unary-expression
4261 extern (C++) abstract class UnaExp : Expression
4263 Expression e1;
4265 extern (D) this(const ref Loc loc, EXP op, Expression e1) scope @safe
4267 super(loc, op);
4268 this.e1 = e1;
4271 override UnaExp syntaxCopy()
4273 UnaExp e = cast(UnaExp)copy();
4274 e.type = null;
4275 e.e1 = e.e1.syntaxCopy();
4276 return e;
4279 /********************************
4280 * The type for a unary expression is incompatible.
4281 * Print error message.
4282 * Returns:
4283 * ErrorExp
4285 final Expression incompatibleTypes()
4287 if (e1.type.toBasetype() == Type.terror)
4288 return e1;
4290 if (e1.op == EXP.type)
4292 error(loc, "incompatible type for `%s(%s)`: cannot use `%s` with types", EXPtoString(op).ptr, e1.toChars(), EXPtoString(op).ptr);
4294 else
4296 error(loc, "incompatible type for `%s(%s)`: `%s`", EXPtoString(op).ptr, e1.toChars(), e1.type.toChars());
4298 return ErrorExp.get();
4301 /*********************
4302 * Mark the operand as will never be dereferenced,
4303 * which is useful info for @safe checks.
4304 * Do before semantic() on operands rewrites them.
4306 final void setNoderefOperand()
4308 if (auto edi = e1.isDotIdExp())
4309 edi.noderef = true;
4313 override final Expression resolveLoc(const ref Loc loc, Scope* sc)
4315 e1 = e1.resolveLoc(loc, sc);
4316 return this;
4319 override void accept(Visitor v)
4321 v.visit(this);
4325 alias fp_t = UnionExp function(const ref Loc loc, Type, Expression, Expression);
4326 alias fp2_t = bool function(const ref Loc loc, EXP, Expression, Expression);
4328 /***********************************************************
4329 * Base class for binary operators
4331 extern (C++) abstract class BinExp : Expression
4333 Expression e1;
4334 Expression e2;
4335 Type att1; // Save alias this type to detect recursion
4336 Type att2; // Save alias this type to detect recursion
4338 extern (D) this(const ref Loc loc, EXP op, Expression e1, Expression e2) scope @safe
4340 super(loc, op);
4341 this.e1 = e1;
4342 this.e2 = e2;
4345 override BinExp syntaxCopy()
4347 BinExp e = cast(BinExp)copy();
4348 e.type = null;
4349 e.e1 = e.e1.syntaxCopy();
4350 e.e2 = e.e2.syntaxCopy();
4351 return e;
4354 /********************************
4355 * The types for a binary expression are incompatible.
4356 * Print error message.
4357 * Returns:
4358 * ErrorExp
4360 final Expression incompatibleTypes()
4362 if (e1.type.toBasetype() == Type.terror)
4363 return e1;
4364 if (e2.type.toBasetype() == Type.terror)
4365 return e2;
4367 // CondExp uses 'a ? b : c' but we're comparing 'b : c'
4368 const(char)* thisOp = (op == EXP.question) ? ":" : EXPtoString(op).ptr;
4369 if (e1.op == EXP.type || e2.op == EXP.type)
4371 error(loc, "incompatible types for `(%s) %s (%s)`: cannot use `%s` with types",
4372 e1.toChars(), thisOp, e2.toChars(), EXPtoString(op).ptr);
4374 else if (e1.type.equals(e2.type))
4376 error(loc, "incompatible types for `(%s) %s (%s)`: both operands are of type `%s`",
4377 e1.toChars(), thisOp, e2.toChars(), e1.type.toChars());
4379 else
4381 auto ts = toAutoQualChars(e1.type, e2.type);
4382 error(loc, "incompatible types for `(%s) %s (%s)`: `%s` and `%s`",
4383 e1.toChars(), thisOp, e2.toChars(), ts[0], ts[1]);
4385 return ErrorExp.get();
4388 extern (D) final Expression checkOpAssignTypes(Scope* sc)
4390 // At that point t1 and t2 are the merged types. type is the original type of the lhs.
4391 Type t1 = e1.type;
4392 Type t2 = e2.type;
4394 // T opAssign floating yields a floating. Prevent truncating conversions (float to int).
4395 // See https://issues.dlang.org/show_bug.cgi?id=3841.
4396 // Should we also prevent double to float (type.isfloating() && type.size() < t2.size()) ?
4397 if (op == EXP.addAssign || op == EXP.minAssign ||
4398 op == EXP.mulAssign || op == EXP.divAssign || op == EXP.modAssign ||
4399 op == EXP.powAssign)
4401 if ((type.isintegral() && t2.isfloating()))
4403 warning(loc, "`%s %s %s` is performing truncating conversion", type.toChars(), EXPtoString(op).ptr, t2.toChars());
4407 // generate an error if this is a nonsensical *=,/=, or %=, eg real *= imaginary
4408 if (op == EXP.mulAssign || op == EXP.divAssign || op == EXP.modAssign)
4410 // Any multiplication by an imaginary or complex number yields a complex result.
4411 // r *= c, i*=c, r*=i, i*=i are all forbidden operations.
4412 const(char)* opstr = EXPtoString(op).ptr;
4413 if (t1.isreal() && t2.iscomplex())
4415 error(loc, "`%s %s %s` is undefined. Did you mean `%s %s %s.re`?", t1.toChars(), opstr, t2.toChars(), t1.toChars(), opstr, t2.toChars());
4416 return ErrorExp.get();
4418 else if (t1.isimaginary() && t2.iscomplex())
4420 error(loc, "`%s %s %s` is undefined. Did you mean `%s %s %s.im`?", t1.toChars(), opstr, t2.toChars(), t1.toChars(), opstr, t2.toChars());
4421 return ErrorExp.get();
4423 else if ((t1.isreal() || t1.isimaginary()) && t2.isimaginary())
4425 error(loc, "`%s %s %s` is an undefined operation", t1.toChars(), opstr, t2.toChars());
4426 return ErrorExp.get();
4430 // generate an error if this is a nonsensical += or -=, eg real += imaginary
4431 if (op == EXP.addAssign || op == EXP.minAssign)
4433 // Addition or subtraction of a real and an imaginary is a complex result.
4434 // Thus, r+=i, r+=c, i+=r, i+=c are all forbidden operations.
4435 if ((t1.isreal() && (t2.isimaginary() || t2.iscomplex())) || (t1.isimaginary() && (t2.isreal() || t2.iscomplex())))
4437 error(loc, "`%s %s %s` is undefined (result is complex)", t1.toChars(), EXPtoString(op).ptr, t2.toChars());
4438 return ErrorExp.get();
4440 if (type.isreal() || type.isimaginary())
4442 assert(global.errors || t2.isfloating());
4443 e2 = e2.castTo(sc, t1);
4446 if (op == EXP.mulAssign)
4448 if (t2.isfloating())
4450 if (t1.isreal())
4452 if (t2.isimaginary() || t2.iscomplex())
4454 e2 = e2.castTo(sc, t1);
4457 else if (t1.isimaginary())
4459 if (t2.isimaginary() || t2.iscomplex())
4461 switch (t1.ty)
4463 case Timaginary32:
4464 t2 = Type.tfloat32;
4465 break;
4467 case Timaginary64:
4468 t2 = Type.tfloat64;
4469 break;
4471 case Timaginary80:
4472 t2 = Type.tfloat80;
4473 break;
4475 default:
4476 assert(0);
4478 e2 = e2.castTo(sc, t2);
4483 else if (op == EXP.divAssign)
4485 if (t2.isimaginary())
4487 if (t1.isreal())
4489 // x/iv = i(-x/v)
4490 // Therefore, the result is 0
4491 e2 = new CommaExp(loc, e2, new RealExp(loc, CTFloat.zero, t1));
4492 e2.type = t1;
4493 Expression e = new AssignExp(loc, e1, e2);
4494 e.type = t1;
4495 return e;
4497 else if (t1.isimaginary())
4499 Type t3;
4500 switch (t1.ty)
4502 case Timaginary32:
4503 t3 = Type.tfloat32;
4504 break;
4506 case Timaginary64:
4507 t3 = Type.tfloat64;
4508 break;
4510 case Timaginary80:
4511 t3 = Type.tfloat80;
4512 break;
4514 default:
4515 assert(0);
4517 e2 = e2.castTo(sc, t3);
4518 Expression e = new AssignExp(loc, e1, e2);
4519 e.type = t1;
4520 return e;
4524 else if (op == EXP.modAssign)
4526 if (t2.iscomplex())
4528 error(loc, "cannot perform modulo complex arithmetic");
4529 return ErrorExp.get();
4532 return this;
4535 extern (D) final bool checkIntegralBin()
4537 bool r1 = e1.checkIntegral();
4538 bool r2 = e2.checkIntegral();
4539 return (r1 || r2);
4542 extern (D) final bool checkArithmeticBin()
4544 bool r1 = e1.checkArithmetic(this.op);
4545 bool r2 = e2.checkArithmetic(this.op);
4546 return (r1 || r2);
4549 extern (D) final bool checkSharedAccessBin(Scope* sc)
4551 const r1 = e1.checkSharedAccess(sc);
4552 const r2 = e2.checkSharedAccess(sc);
4553 return (r1 || r2);
4556 /*********************
4557 * Mark the operands as will never be dereferenced,
4558 * which is useful info for @safe checks.
4559 * Do before semantic() on operands rewrites them.
4561 final void setNoderefOperands()
4563 if (auto edi = e1.isDotIdExp())
4564 edi.noderef = true;
4565 if (auto edi = e2.isDotIdExp())
4566 edi.noderef = true;
4570 final Expression reorderSettingAAElem(Scope* sc)
4572 BinExp be = this;
4574 auto ie = be.e1.isIndexExp();
4575 if (!ie)
4576 return be;
4577 if (ie.e1.type.toBasetype().ty != Taarray)
4578 return be;
4580 /* Fix evaluation order of setting AA element
4581 * https://issues.dlang.org/show_bug.cgi?id=3825
4582 * Rewrite:
4583 * aa[k1][k2][k3] op= val;
4584 * as:
4585 * auto ref __aatmp = aa;
4586 * auto ref __aakey3 = k1, __aakey2 = k2, __aakey1 = k3;
4587 * auto ref __aaval = val;
4588 * __aatmp[__aakey3][__aakey2][__aakey1] op= __aaval; // assignment
4591 Expression e0;
4592 while (1)
4594 Expression de;
4595 ie.e2 = extractSideEffect(sc, "__aakey", de, ie.e2);
4596 e0 = Expression.combine(de, e0);
4598 auto ie1 = ie.e1.isIndexExp();
4599 if (!ie1 ||
4600 ie1.e1.type.toBasetype().ty != Taarray)
4602 break;
4604 ie = ie1;
4606 assert(ie.e1.type.toBasetype().ty == Taarray);
4608 Expression de;
4609 ie.e1 = extractSideEffect(sc, "__aatmp", de, ie.e1);
4610 e0 = Expression.combine(de, e0);
4612 be.e2 = extractSideEffect(sc, "__aaval", e0, be.e2, true);
4614 //printf("-e0 = %s, be = %s\n", e0.toChars(), be.toChars());
4615 return Expression.combine(e0, be);
4618 override void accept(Visitor v)
4620 v.visit(this);
4624 /***********************************************************
4625 * Binary operator assignment, `+=` `-=` `*=` etc.
4627 extern (C++) class BinAssignExp : BinExp
4629 extern (D) this(const ref Loc loc, EXP op, Expression e1, Expression e2) scope @safe
4631 super(loc, op, e1, e2);
4634 override final bool isLvalue()
4636 return true;
4639 override final Expression toLvalue(Scope* sc, Expression ex)
4641 // Lvalue-ness will be handled in glue layer.
4642 return this;
4645 override final Expression modifiableLvalue(Scope* sc, Expression e)
4647 // should check e1.checkModifiable() ?
4648 return toLvalue(sc, this);
4651 override void accept(Visitor v)
4653 v.visit(this);
4657 /***********************************************************
4658 * A string mixin, `mixin("x")`
4660 * https://dlang.org/spec/expression.html#mixin_expressions
4662 extern (C++) final class MixinExp : Expression
4664 Expressions* exps;
4666 extern (D) this(const ref Loc loc, Expressions* exps) @safe
4668 super(loc, EXP.mixin_);
4669 this.exps = exps;
4672 override MixinExp syntaxCopy()
4674 return new MixinExp(loc, arraySyntaxCopy(exps));
4677 override bool equals(const RootObject o) const
4679 if (this == o)
4680 return true;
4681 auto e = o.isExpression();
4682 if (!e)
4683 return false;
4684 if (auto ce = e.isMixinExp())
4686 if (exps.length != ce.exps.length)
4687 return false;
4688 foreach (i, e1; *exps)
4690 auto e2 = (*ce.exps)[i];
4691 if (e1 != e2 && (!e1 || !e2 || !e1.equals(e2)))
4692 return false;
4694 return true;
4696 return false;
4699 override void accept(Visitor v)
4701 v.visit(this);
4705 /***********************************************************
4706 * An import expression, `import("file.txt")`
4708 * Not to be confused with module imports, `import std.stdio`, which is an `ImportStatement`
4710 * https://dlang.org/spec/expression.html#import_expressions
4712 extern (C++) final class ImportExp : UnaExp
4714 extern (D) this(const ref Loc loc, Expression e) @safe
4716 super(loc, EXP.import_, e);
4719 override void accept(Visitor v)
4721 v.visit(this);
4725 /***********************************************************
4726 * An assert expression, `assert(x == y)`
4728 * https://dlang.org/spec/expression.html#assert_expressions
4730 extern (C++) final class AssertExp : UnaExp
4732 Expression msg;
4734 extern (D) this(const ref Loc loc, Expression e, Expression msg = null) @safe
4736 super(loc, EXP.assert_, e);
4737 this.msg = msg;
4740 override AssertExp syntaxCopy()
4742 return new AssertExp(loc, e1.syntaxCopy(), msg ? msg.syntaxCopy() : null);
4745 override void accept(Visitor v)
4747 v.visit(this);
4751 /***********************************************************
4752 * `throw <e1>` as proposed by DIP 1034.
4754 * Replacement for the deprecated `ThrowStatement` that can be nested
4755 * in other expression.
4757 extern (C++) final class ThrowExp : UnaExp
4759 extern (D) this(const ref Loc loc, Expression e)
4761 super(loc, EXP.throw_, e);
4762 this.type = Type.tnoreturn;
4765 override ThrowExp syntaxCopy()
4767 return new ThrowExp(loc, e1.syntaxCopy());
4770 override void accept(Visitor v)
4772 v.visit(this);
4776 /***********************************************************
4778 extern (C++) final class DotIdExp : UnaExp
4780 Identifier ident;
4781 bool noderef; // true if the result of the expression will never be dereferenced
4782 bool wantsym; // do not replace Symbol with its initializer during semantic()
4783 bool arrow; // ImportC: if -> instead of .
4785 extern (D) this(const ref Loc loc, Expression e, Identifier ident) @safe
4787 super(loc, EXP.dotIdentifier, e);
4788 this.ident = ident;
4791 static DotIdExp create(const ref Loc loc, Expression e, Identifier ident) @safe
4793 return new DotIdExp(loc, e, ident);
4796 override void accept(Visitor v)
4798 v.visit(this);
4802 /***********************************************************
4803 * Mainly just a placeholder
4805 extern (C++) final class DotTemplateExp : UnaExp
4807 TemplateDeclaration td;
4809 extern (D) this(const ref Loc loc, Expression e, TemplateDeclaration td) @safe
4811 super(loc, EXP.dotTemplateDeclaration, e);
4812 this.td = td;
4815 override bool checkType()
4817 error(loc, "%s `%s` has no type", td.kind(), toChars());
4818 return true;
4821 override bool checkValue()
4823 error(loc, "%s `%s` has no value", td.kind(), toChars());
4824 return true;
4827 override void accept(Visitor v)
4829 v.visit(this);
4833 /***********************************************************
4835 extern (C++) final class DotVarExp : UnaExp
4837 Declaration var;
4838 bool hasOverloads;
4840 extern (D) this(const ref Loc loc, Expression e, Declaration var, bool hasOverloads = true) @safe
4842 if (var.isVarDeclaration())
4843 hasOverloads = false;
4845 super(loc, EXP.dotVariable, e);
4846 //printf("DotVarExp()\n");
4847 this.var = var;
4848 this.hasOverloads = hasOverloads;
4851 override bool isLvalue()
4853 if (e1.op != EXP.structLiteral)
4854 return true;
4855 auto vd = var.isVarDeclaration();
4856 return !(vd && vd.isField());
4859 override Expression toLvalue(Scope* sc, Expression e)
4861 //printf("DotVarExp::toLvalue(%s)\n", toChars());
4862 if (sc && sc.flags & SCOPE.Cfile)
4864 /* C11 6.5.2.3-3: A postfix expression followed by the '.' or '->' operator
4865 * is an lvalue if the first expression is an lvalue.
4867 if (!e1.isLvalue())
4868 return Expression.toLvalue(sc, e);
4870 if (!isLvalue())
4871 return Expression.toLvalue(sc, e);
4872 if (e1.op == EXP.this_ && sc.ctorflow.fieldinit.length && !(sc.ctorflow.callSuper & CSX.any_ctor))
4874 if (VarDeclaration vd = var.isVarDeclaration())
4876 auto ad = vd.isMember2();
4877 if (ad && ad.fields.length == sc.ctorflow.fieldinit.length)
4879 foreach (i, f; ad.fields)
4881 if (f == vd)
4883 if (!(sc.ctorflow.fieldinit[i].csx & CSX.this_ctor))
4885 /* If the address of vd is taken, assume it is thereby initialized
4886 * https://issues.dlang.org/show_bug.cgi?id=15869
4888 modifyFieldVar(loc, sc, vd, e1);
4890 break;
4896 return this;
4899 override Expression modifiableLvalue(Scope* sc, Expression e)
4901 version (none)
4903 printf("DotVarExp::modifiableLvalue(%s)\n", toChars());
4904 printf("e1.type = %s\n", e1.type.toChars());
4905 printf("var.type = %s\n", var.type.toChars());
4908 return Expression.modifiableLvalue(sc, e);
4911 override void accept(Visitor v)
4913 v.visit(this);
4917 /***********************************************************
4918 * foo.bar!(args)
4920 extern (C++) final class DotTemplateInstanceExp : UnaExp
4922 TemplateInstance ti;
4924 extern (D) this(const ref Loc loc, Expression e, Identifier name, Objects* tiargs)
4926 super(loc, EXP.dotTemplateInstance, e);
4927 //printf("DotTemplateInstanceExp()\n");
4928 this.ti = new TemplateInstance(loc, name, tiargs);
4931 extern (D) this(const ref Loc loc, Expression e, TemplateInstance ti) @safe
4933 super(loc, EXP.dotTemplateInstance, e);
4934 this.ti = ti;
4937 override DotTemplateInstanceExp syntaxCopy()
4939 return new DotTemplateInstanceExp(loc, e1.syntaxCopy(), ti.name, TemplateInstance.arraySyntaxCopy(ti.tiargs));
4942 bool findTempDecl(Scope* sc)
4944 static if (LOGSEMANTIC)
4946 printf("DotTemplateInstanceExp::findTempDecl('%s')\n", toChars());
4948 if (ti.tempdecl)
4949 return true;
4951 Expression e = new DotIdExp(loc, e1, ti.name);
4952 e = e.expressionSemantic(sc);
4953 if (e.op == EXP.dot)
4954 e = (cast(DotExp)e).e2;
4956 Dsymbol s = null;
4957 switch (e.op)
4959 case EXP.overloadSet:
4960 s = (cast(OverExp)e).vars;
4961 break;
4963 case EXP.dotTemplateDeclaration:
4964 s = (cast(DotTemplateExp)e).td;
4965 break;
4967 case EXP.scope_:
4968 s = (cast(ScopeExp)e).sds;
4969 break;
4971 case EXP.dotVariable:
4972 s = (cast(DotVarExp)e).var;
4973 break;
4975 case EXP.variable:
4976 s = (cast(VarExp)e).var;
4977 break;
4979 default:
4980 return false;
4982 return ti.updateTempDecl(sc, s);
4985 override bool checkType()
4987 // Same logic as ScopeExp.checkType()
4988 if (ti.tempdecl &&
4989 ti.semantictiargsdone &&
4990 ti.semanticRun == PASS.initial)
4992 error(loc, "partial %s `%s` has no type", ti.kind(), toChars());
4993 return true;
4995 return false;
4998 override bool checkValue()
5000 if (ti.tempdecl &&
5001 ti.semantictiargsdone &&
5002 ti.semanticRun == PASS.initial)
5004 error(loc, "partial %s `%s` has no value", ti.kind(), toChars());
5005 else
5006 error(loc, "%s `%s` has no value", ti.kind(), ti.toChars());
5007 return true;
5010 override void accept(Visitor v)
5012 v.visit(this);
5016 /***********************************************************
5018 extern (C++) final class DelegateExp : UnaExp
5020 FuncDeclaration func;
5021 bool hasOverloads;
5022 VarDeclaration vthis2; // container for multi-context
5024 extern (D) this(const ref Loc loc, Expression e, FuncDeclaration f, bool hasOverloads = true, VarDeclaration vthis2 = null) @safe
5026 super(loc, EXP.delegate_, e);
5027 this.func = f;
5028 this.hasOverloads = hasOverloads;
5029 this.vthis2 = vthis2;
5032 override void accept(Visitor v)
5034 v.visit(this);
5038 /***********************************************************
5040 extern (C++) final class DotTypeExp : UnaExp
5042 Dsymbol sym; // symbol that represents a type
5044 extern (D) this(const ref Loc loc, Expression e, Dsymbol s) @safe
5046 super(loc, EXP.dotType, e);
5047 this.sym = s;
5050 override void accept(Visitor v)
5052 v.visit(this);
5057 * The arguments of a function call
5059 * Contains a list of expressions. If it is a named argument, the `names`
5060 * list has a non-null entry at the same index.
5062 struct ArgumentList
5064 Expressions* arguments; // function arguments
5065 Identifiers* names; // named argument identifiers
5067 size_t length() const @nogc nothrow pure @safe { return arguments ? arguments.length : 0; }
5069 /// Returns: whether this argument list contains any named arguments
5070 bool hasNames() const @nogc nothrow pure @safe
5072 if (names is null)
5073 return false;
5074 foreach (name; *names)
5075 if (name !is null)
5076 return true;
5078 return false;
5082 /***********************************************************
5084 extern (C++) final class CallExp : UnaExp
5086 Expressions* arguments; // function arguments
5087 Identifiers* names; // named argument identifiers
5088 FuncDeclaration f; // symbol to call
5089 bool directcall; // true if a virtual call is devirtualized
5090 bool inDebugStatement; /// true if this was in a debug statement
5091 bool ignoreAttributes; /// don't enforce attributes (e.g. call @gc function in @nogc code)
5092 bool isUfcsRewrite; /// the first argument was pushed in here by a UFCS rewrite
5093 VarDeclaration vthis2; // container for multi-context
5095 /// Puts the `arguments` and `names` into an `ArgumentList` for easily passing them around.
5096 /// The fields are still separate for backwards compatibility
5097 extern (D) ArgumentList argumentList() { return ArgumentList(arguments, names); }
5099 extern (D) this(const ref Loc loc, Expression e, Expressions* exps, Identifiers* names = null) @safe
5101 super(loc, EXP.call, e);
5102 this.arguments = exps;
5103 this.names = names;
5106 extern (D) this(const ref Loc loc, Expression e) @safe
5108 super(loc, EXP.call, e);
5111 extern (D) this(const ref Loc loc, Expression e, Expression earg1)
5113 super(loc, EXP.call, e);
5114 this.arguments = new Expressions();
5115 if (earg1)
5116 this.arguments.push(earg1);
5119 extern (D) this(const ref Loc loc, Expression e, Expression earg1, Expression earg2)
5121 super(loc, EXP.call, e);
5122 auto arguments = new Expressions(2);
5123 (*arguments)[0] = earg1;
5124 (*arguments)[1] = earg2;
5125 this.arguments = arguments;
5128 /***********************************************************
5129 * Instatiates a new function call expression
5130 * Params:
5131 * loc = location
5132 * fd = the declaration of the function to call
5133 * earg1 = the function argument
5135 extern(D) this(const ref Loc loc, FuncDeclaration fd, Expression earg1)
5137 this(loc, new VarExp(loc, fd, false), earg1);
5138 this.f = fd;
5141 static CallExp create(const ref Loc loc, Expression e, Expressions* exps) @safe
5143 return new CallExp(loc, e, exps);
5146 static CallExp create(const ref Loc loc, Expression e) @safe
5148 return new CallExp(loc, e);
5151 static CallExp create(const ref Loc loc, Expression e, Expression earg1)
5153 return new CallExp(loc, e, earg1);
5156 /***********************************************************
5157 * Creates a new function call expression
5158 * Params:
5159 * loc = location
5160 * fd = the declaration of the function to call
5161 * earg1 = the function argument
5163 static CallExp create(const ref Loc loc, FuncDeclaration fd, Expression earg1)
5165 return new CallExp(loc, fd, earg1);
5168 override CallExp syntaxCopy()
5170 return new CallExp(loc, e1.syntaxCopy(), arraySyntaxCopy(arguments), names ? names.copy() : null);
5173 override bool isLvalue()
5175 Type tb = e1.type.toBasetype();
5176 if (tb.ty == Tdelegate || tb.ty == Tpointer)
5177 tb = tb.nextOf();
5178 auto tf = tb.isTypeFunction();
5179 if (tf && tf.isref)
5181 if (auto dve = e1.isDotVarExp())
5182 if (dve.var.isCtorDeclaration())
5183 return false;
5184 return true; // function returns a reference
5186 return false;
5189 override Expression toLvalue(Scope* sc, Expression e)
5191 if (isLvalue())
5192 return this;
5193 return Expression.toLvalue(sc, e);
5196 override Expression addDtorHook(Scope* sc)
5198 /* Only need to add dtor hook if it's a type that needs destruction.
5199 * Use same logic as VarDeclaration::callScopeDtor()
5202 if (auto tf = e1.type.isTypeFunction())
5204 if (tf.isref)
5205 return this;
5208 Type tv = type.baseElemOf();
5209 if (auto ts = tv.isTypeStruct())
5211 StructDeclaration sd = ts.sym;
5212 if (sd.dtor)
5214 /* Type needs destruction, so declare a tmp
5215 * which the back end will recognize and call dtor on
5217 auto tmp = copyToTemp(0, Id.__tmpfordtor.toString(), this);
5218 auto de = new DeclarationExp(loc, tmp);
5219 auto ve = new VarExp(loc, tmp);
5220 Expression e = new CommaExp(loc, de, ve);
5221 e = e.expressionSemantic(sc);
5222 return e;
5225 return this;
5228 override void accept(Visitor v)
5230 v.visit(this);
5235 * Get the called function type from a call expression
5236 * Params:
5237 * ce = function call expression. Must have had semantic analysis done.
5238 * Returns: called function type, or `null` if error / no semantic analysis done
5240 TypeFunction calledFunctionType(CallExp ce)
5242 Type t = ce.e1.type;
5243 if (!t)
5244 return null;
5245 t = t.toBasetype();
5246 if (auto tf = t.isTypeFunction())
5247 return tf;
5248 else if (auto td = t.isTypeDelegate())
5249 return td.nextOf().isTypeFunction();
5250 else
5251 return null;
5254 FuncDeclaration isFuncAddress(Expression e, bool* hasOverloads = null) @safe
5256 if (auto ae = e.isAddrExp())
5258 auto ae1 = ae.e1;
5259 if (auto ve = ae1.isVarExp())
5261 if (hasOverloads)
5262 *hasOverloads = ve.hasOverloads;
5263 return ve.var.isFuncDeclaration();
5265 if (auto dve = ae1.isDotVarExp())
5267 if (hasOverloads)
5268 *hasOverloads = dve.hasOverloads;
5269 return dve.var.isFuncDeclaration();
5272 else
5274 if (auto soe = e.isSymOffExp())
5276 if (hasOverloads)
5277 *hasOverloads = soe.hasOverloads;
5278 return soe.var.isFuncDeclaration();
5280 if (auto dge = e.isDelegateExp())
5282 if (hasOverloads)
5283 *hasOverloads = dge.hasOverloads;
5284 return dge.func.isFuncDeclaration();
5287 return null;
5290 /***********************************************************
5291 * The 'address of' operator, `&p`
5293 extern (C++) final class AddrExp : UnaExp
5295 extern (D) this(const ref Loc loc, Expression e) @safe
5297 super(loc, EXP.address, e);
5300 extern (D) this(const ref Loc loc, Expression e, Type t) @safe
5302 this(loc, e);
5303 type = t;
5306 override void accept(Visitor v)
5308 v.visit(this);
5312 /***********************************************************
5313 * The pointer dereference operator, `*p`
5315 extern (C++) final class PtrExp : UnaExp
5317 extern (D) this(const ref Loc loc, Expression e) @safe
5319 super(loc, EXP.star, e);
5320 //if (e.type)
5321 // type = ((TypePointer *)e.type).next;
5324 extern (D) this(const ref Loc loc, Expression e, Type t) @safe
5326 super(loc, EXP.star, e);
5327 type = t;
5330 override bool isLvalue()
5332 return true;
5335 override Expression toLvalue(Scope* sc, Expression e)
5337 return this;
5340 override Expression modifiableLvalue(Scope* sc, Expression e)
5342 //printf("PtrExp::modifiableLvalue() %s, type %s\n", toChars(), type.toChars());
5343 Declaration var;
5344 if (auto se = e1.isSymOffExp())
5345 var = se.var;
5346 else if (auto ve = e1.isVarExp())
5347 var = ve.var;
5348 if (var && var.type.isFunction_Delegate_PtrToFunction())
5350 if (var.type.isTypeFunction())
5351 error(loc, "function `%s` is not an lvalue and cannot be modified", var.toChars());
5352 else
5353 error(loc, "function pointed to by `%s` is not an lvalue and cannot be modified", var.toChars());
5354 return ErrorExp.get();
5356 return Expression.modifiableLvalue(sc, e);
5359 override void accept(Visitor v)
5361 v.visit(this);
5365 /***********************************************************
5366 * The negation operator, `-x`
5368 extern (C++) final class NegExp : UnaExp
5370 extern (D) this(const ref Loc loc, Expression e) @safe
5372 super(loc, EXP.negate, e);
5375 override void accept(Visitor v)
5377 v.visit(this);
5381 /***********************************************************
5382 * The unary add operator, `+x`
5384 extern (C++) final class UAddExp : UnaExp
5386 extern (D) this(const ref Loc loc, Expression e) scope @safe
5388 super(loc, EXP.uadd, e);
5391 override void accept(Visitor v)
5393 v.visit(this);
5397 /***********************************************************
5398 * The bitwise complement operator, `~x`
5400 extern (C++) final class ComExp : UnaExp
5402 extern (D) this(const ref Loc loc, Expression e) @safe
5404 super(loc, EXP.tilde, e);
5407 override void accept(Visitor v)
5409 v.visit(this);
5413 /***********************************************************
5414 * The logical not operator, `!x`
5416 extern (C++) final class NotExp : UnaExp
5418 extern (D) this(const ref Loc loc, Expression e) @safe
5420 super(loc, EXP.not, e);
5423 override void accept(Visitor v)
5425 v.visit(this);
5429 /***********************************************************
5430 * The delete operator, `delete x` (deprecated)
5432 * https://dlang.org/spec/expression.html#delete_expressions
5434 extern (C++) final class DeleteExp : UnaExp
5436 bool isRAII; // true if called automatically as a result of scoped destruction
5438 extern (D) this(const ref Loc loc, Expression e, bool isRAII) @safe
5440 super(loc, EXP.delete_, e);
5441 this.isRAII = isRAII;
5444 override void accept(Visitor v)
5446 v.visit(this);
5450 /***********************************************************
5451 * The type cast operator, `cast(T) x`
5453 * It's possible to cast to one type while painting to another type
5455 * https://dlang.org/spec/expression.html#cast_expressions
5457 extern (C++) final class CastExp : UnaExp
5459 Type to; // type to cast to
5460 ubyte mod = cast(ubyte)~0; // MODxxxxx
5462 extern (D) this(const ref Loc loc, Expression e, Type t) @safe
5464 super(loc, EXP.cast_, e);
5465 this.to = t;
5468 /* For cast(const) and cast(immutable)
5470 extern (D) this(const ref Loc loc, Expression e, ubyte mod) @safe
5472 super(loc, EXP.cast_, e);
5473 this.mod = mod;
5476 override CastExp syntaxCopy()
5478 return to ? new CastExp(loc, e1.syntaxCopy(), to.syntaxCopy()) : new CastExp(loc, e1.syntaxCopy(), mod);
5481 override bool isLvalue()
5483 //printf("e1.type = %s, to.type = %s\n", e1.type.toChars(), to.toChars());
5484 if (!e1.isLvalue())
5485 return false;
5486 return (to.ty == Tsarray && (e1.type.ty == Tvector || e1.type.ty == Tsarray)) ||
5487 e1.type.mutableOf().unSharedOf().equals(to.mutableOf().unSharedOf());
5490 override Expression toLvalue(Scope* sc, Expression e)
5492 if (sc && sc.flags & SCOPE.Cfile)
5494 /* C11 6.5.4-5: A cast does not yield an lvalue.
5496 return Expression.toLvalue(sc, e);
5498 if (isLvalue())
5499 return this;
5500 return Expression.toLvalue(sc, e);
5503 override Expression addDtorHook(Scope* sc)
5505 if (to.toBasetype().ty == Tvoid) // look past the cast(void)
5506 e1 = e1.addDtorHook(sc);
5507 return this;
5510 override void accept(Visitor v)
5512 v.visit(this);
5516 /***********************************************************
5518 extern (C++) final class VectorExp : UnaExp
5520 TypeVector to; // the target vector type before semantic()
5521 uint dim = ~0; // number of elements in the vector
5522 OwnedBy ownedByCtfe = OwnedBy.code;
5524 extern (D) this(const ref Loc loc, Expression e, Type t) @safe
5526 super(loc, EXP.vector, e);
5527 assert(t.ty == Tvector);
5528 to = cast(TypeVector)t;
5531 static VectorExp create(const ref Loc loc, Expression e, Type t) @safe
5533 return new VectorExp(loc, e, t);
5536 // Same as create, but doesn't allocate memory.
5537 static void emplace(UnionExp* pue, const ref Loc loc, Expression e, Type type)
5539 emplaceExp!(VectorExp)(pue, loc, e, type);
5542 override VectorExp syntaxCopy()
5544 return new VectorExp(loc, e1.syntaxCopy(), to.syntaxCopy());
5547 override void accept(Visitor v)
5549 v.visit(this);
5553 /***********************************************************
5554 * e1.array property for vectors.
5556 * https://dlang.org/spec/simd.html#properties
5558 extern (C++) final class VectorArrayExp : UnaExp
5560 extern (D) this(const ref Loc loc, Expression e1) @safe
5562 super(loc, EXP.vectorArray, e1);
5565 override bool isLvalue()
5567 return e1.isLvalue();
5570 override Expression toLvalue(Scope* sc, Expression e)
5572 e1 = e1.toLvalue(sc, e);
5573 return this;
5576 override void accept(Visitor v)
5578 v.visit(this);
5582 /***********************************************************
5583 * e1 [lwr .. upr]
5585 * https://dlang.org/spec/expression.html#slice_expressions
5587 extern (C++) final class SliceExp : UnaExp
5589 Expression upr; // null if implicit 0
5590 Expression lwr; // null if implicit [length - 1]
5592 VarDeclaration lengthVar;
5594 private extern(D) static struct BitFields
5596 bool upperIsInBounds; // true if upr <= e1.length
5597 bool lowerIsLessThanUpper; // true if lwr <= upr
5598 bool arrayop; // an array operation, rather than a slice
5600 import dmd.common.bitfields : generateBitFields;
5601 mixin(generateBitFields!(BitFields, ubyte));
5603 /************************************************************/
5604 extern (D) this(const ref Loc loc, Expression e1, IntervalExp ie) @safe
5606 super(loc, EXP.slice, e1);
5607 this.upr = ie ? ie.upr : null;
5608 this.lwr = ie ? ie.lwr : null;
5611 extern (D) this(const ref Loc loc, Expression e1, Expression lwr, Expression upr) @safe
5613 super(loc, EXP.slice, e1);
5614 this.upr = upr;
5615 this.lwr = lwr;
5618 override SliceExp syntaxCopy()
5620 auto se = new SliceExp(loc, e1.syntaxCopy(), lwr ? lwr.syntaxCopy() : null, upr ? upr.syntaxCopy() : null);
5621 se.lengthVar = this.lengthVar; // bug7871
5622 return se;
5625 override bool isLvalue()
5627 /* slice expression is rvalue in default, but
5628 * conversion to reference of static array is only allowed.
5630 return (type && type.toBasetype().ty == Tsarray);
5633 override Expression toLvalue(Scope* sc, Expression e)
5635 //printf("SliceExp::toLvalue(%s) type = %s\n", toChars(), type ? type.toChars() : NULL);
5636 return (type && type.toBasetype().ty == Tsarray) ? this : Expression.toLvalue(sc, e);
5639 override Expression modifiableLvalue(Scope* sc, Expression e)
5641 error(loc, "slice expression `%s` is not a modifiable lvalue", toChars());
5642 return this;
5645 override Optional!bool toBool()
5647 return e1.toBool();
5650 override void accept(Visitor v)
5652 v.visit(this);
5656 /***********************************************************
5657 * The `.length` property of an array
5659 extern (C++) final class ArrayLengthExp : UnaExp
5661 extern (D) this(const ref Loc loc, Expression e1) @safe
5663 super(loc, EXP.arrayLength, e1);
5666 override void accept(Visitor v)
5668 v.visit(this);
5672 /***********************************************************
5673 * e1 [ a0, a1, a2, a3 ,... ]
5675 * https://dlang.org/spec/expression.html#index_expressions
5677 extern (C++) final class ArrayExp : UnaExp
5679 Expressions* arguments; // Array of Expression's a0..an
5681 size_t currentDimension; // for opDollar
5682 VarDeclaration lengthVar;
5684 extern (D) this(const ref Loc loc, Expression e1, Expression index = null)
5686 super(loc, EXP.array, e1);
5687 arguments = new Expressions();
5688 if (index)
5689 arguments.push(index);
5692 extern (D) this(const ref Loc loc, Expression e1, Expressions* args) @safe
5694 super(loc, EXP.array, e1);
5695 arguments = args;
5698 override ArrayExp syntaxCopy()
5700 auto ae = new ArrayExp(loc, e1.syntaxCopy(), arraySyntaxCopy(arguments));
5701 ae.lengthVar = this.lengthVar; // bug7871
5702 return ae;
5705 override bool isLvalue()
5707 if (type && type.toBasetype().ty == Tvoid)
5708 return false;
5709 return true;
5712 override Expression toLvalue(Scope* sc, Expression e)
5714 if (type && type.toBasetype().ty == Tvoid)
5715 error(loc, "`void`s have no value");
5716 return this;
5719 override void accept(Visitor v)
5721 v.visit(this);
5725 /***********************************************************
5727 extern (C++) final class DotExp : BinExp
5729 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
5731 super(loc, EXP.dot, e1, e2);
5734 override void accept(Visitor v)
5736 v.visit(this);
5740 /***********************************************************
5742 extern (C++) final class CommaExp : BinExp
5744 /// This is needed because AssignExp rewrites CommaExp, hence it needs
5745 /// to trigger the deprecation.
5746 const bool isGenerated;
5748 /// Temporary variable to enable / disable deprecation of comma expression
5749 /// depending on the context.
5750 /// Since most constructor calls are rewritting, the only place where
5751 /// false will be passed will be from the parser.
5752 bool allowCommaExp;
5755 extern (D) this(const ref Loc loc, Expression e1, Expression e2, bool generated = true) @safe
5757 super(loc, EXP.comma, e1, e2);
5758 allowCommaExp = isGenerated = generated;
5761 override bool isLvalue()
5763 return e2.isLvalue();
5766 override Expression toLvalue(Scope* sc, Expression e)
5768 e2 = e2.toLvalue(sc, null);
5769 return this;
5772 override Expression modifiableLvalue(Scope* sc, Expression e)
5774 e2 = e2.modifiableLvalue(sc, e);
5775 return this;
5778 override Optional!bool toBool()
5780 return e2.toBool();
5783 override Expression addDtorHook(Scope* sc)
5785 e2 = e2.addDtorHook(sc);
5786 return this;
5789 override void accept(Visitor v)
5791 v.visit(this);
5795 * If the argument is a CommaExp, set a flag to prevent deprecation messages
5797 * It's impossible to know from CommaExp.semantic if the result will
5798 * be used, hence when there is a result (type != void), a deprecation
5799 * message is always emitted.
5800 * However, some construct can produce a result but won't use it
5801 * (ExpStatement and for loop increment). Those should call this function
5802 * to prevent unwanted deprecations to be emitted.
5804 * Params:
5805 * exp = An expression that discards its result.
5806 * If the argument is null or not a CommaExp, nothing happens.
5808 static void allow(Expression exp) @safe
5810 if (exp)
5811 if (auto ce = exp.isCommaExp())
5812 ce.allowCommaExp = true;
5816 /***********************************************************
5817 * Mainly just a placeholder
5819 extern (C++) final class IntervalExp : Expression
5821 Expression lwr;
5822 Expression upr;
5824 extern (D) this(const ref Loc loc, Expression lwr, Expression upr) @safe
5826 super(loc, EXP.interval);
5827 this.lwr = lwr;
5828 this.upr = upr;
5831 override Expression syntaxCopy()
5833 return new IntervalExp(loc, lwr.syntaxCopy(), upr.syntaxCopy());
5836 override void accept(Visitor v)
5838 v.visit(this);
5842 /***********************************************************
5843 * The `dg.ptr` property, pointing to the delegate's 'context'
5845 * c.f.`DelegateFuncptrExp` for the delegate's function pointer `dg.funcptr`
5847 extern (C++) final class DelegatePtrExp : UnaExp
5849 extern (D) this(const ref Loc loc, Expression e1) @safe
5851 super(loc, EXP.delegatePointer, e1);
5854 override bool isLvalue()
5856 return e1.isLvalue();
5859 override Expression toLvalue(Scope* sc, Expression e)
5861 e1 = e1.toLvalue(sc, e);
5862 return this;
5865 override Expression modifiableLvalue(Scope* sc, Expression e)
5867 if (sc.setUnsafe(false, this.loc, "cannot modify delegate pointer in `@safe` code `%s`", this))
5869 return ErrorExp.get();
5871 return Expression.modifiableLvalue(sc, e);
5874 override void accept(Visitor v)
5876 v.visit(this);
5880 /***********************************************************
5881 * The `dg.funcptr` property, pointing to the delegate's function
5883 * c.f.`DelegatePtrExp` for the delegate's function pointer `dg.ptr`
5885 extern (C++) final class DelegateFuncptrExp : UnaExp
5887 extern (D) this(const ref Loc loc, Expression e1) @safe
5889 super(loc, EXP.delegateFunctionPointer, e1);
5892 override bool isLvalue()
5894 return e1.isLvalue();
5897 override Expression toLvalue(Scope* sc, Expression e)
5899 e1 = e1.toLvalue(sc, e);
5900 return this;
5903 override Expression modifiableLvalue(Scope* sc, Expression e)
5905 if (sc.setUnsafe(false, this.loc, "cannot modify delegate function pointer in `@safe` code `%s`", this))
5907 return ErrorExp.get();
5909 return Expression.modifiableLvalue(sc, e);
5912 override void accept(Visitor v)
5914 v.visit(this);
5918 /***********************************************************
5919 * e1 [ e2 ]
5921 extern (C++) final class IndexExp : BinExp
5923 VarDeclaration lengthVar;
5924 bool modifiable = false; // assume it is an rvalue
5925 bool indexIsInBounds; // true if 0 <= e2 && e2 <= e1.length - 1
5927 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
5929 super(loc, EXP.index, e1, e2);
5930 //printf("IndexExp::IndexExp('%s')\n", toChars());
5933 extern (D) this(const ref Loc loc, Expression e1, Expression e2, bool indexIsInBounds) @safe
5935 super(loc, EXP.index, e1, e2);
5936 this.indexIsInBounds = indexIsInBounds;
5937 //printf("IndexExp::IndexExp('%s')\n", toChars());
5940 override IndexExp syntaxCopy()
5942 auto ie = new IndexExp(loc, e1.syntaxCopy(), e2.syntaxCopy());
5943 ie.lengthVar = this.lengthVar; // bug7871
5944 return ie;
5947 override bool isLvalue()
5949 if (e1.op == EXP.assocArrayLiteral)
5950 return false;
5951 if (e1.type.ty == Tsarray ||
5952 (e1.op == EXP.index && e1.type.ty != Tarray))
5954 return e1.isLvalue();
5956 return true;
5959 override Expression toLvalue(Scope* sc, Expression e)
5961 if (isLvalue())
5962 return this;
5963 return Expression.toLvalue(sc, e);
5966 override Expression modifiableLvalue(Scope* sc, Expression e)
5968 //printf("IndexExp::modifiableLvalue(%s)\n", toChars());
5969 Expression ex = markSettingAAElem();
5970 if (ex.op == EXP.error)
5971 return ex;
5973 return Expression.modifiableLvalue(sc, e);
5976 extern (D) Expression markSettingAAElem()
5978 if (e1.type.toBasetype().ty == Taarray)
5980 Type t2b = e2.type.toBasetype();
5981 if (t2b.ty == Tarray && t2b.nextOf().isMutable())
5983 error(loc, "associative arrays can only be assigned values with immutable keys, not `%s`", e2.type.toChars());
5984 return ErrorExp.get();
5986 modifiable = true;
5988 if (auto ie = e1.isIndexExp())
5990 Expression ex = ie.markSettingAAElem();
5991 if (ex.op == EXP.error)
5992 return ex;
5993 assert(ex == e1);
5996 return this;
5999 override void accept(Visitor v)
6001 v.visit(this);
6005 /***********************************************************
6006 * The postfix increment/decrement operator, `i++` / `i--`
6008 extern (C++) final class PostExp : BinExp
6010 extern (D) this(EXP op, const ref Loc loc, Expression e)
6012 super(loc, op, e, IntegerExp.literal!1);
6013 assert(op == EXP.minusMinus || op == EXP.plusPlus);
6016 override void accept(Visitor v)
6018 v.visit(this);
6022 /***********************************************************
6023 * The prefix increment/decrement operator, `++i` / `--i`
6025 extern (C++) final class PreExp : UnaExp
6027 extern (D) this(EXP op, const ref Loc loc, Expression e) @safe
6029 super(loc, op, e);
6030 assert(op == EXP.preMinusMinus || op == EXP.prePlusPlus);
6033 override void accept(Visitor v)
6035 v.visit(this);
6039 enum MemorySet
6041 none = 0, // simple assignment
6042 blockAssign = 1, // setting the contents of an array
6043 referenceInit = 2, // setting the reference of STC.ref_ variable
6046 /***********************************************************
6047 * The assignment / initialization operator, `=`
6049 * Note: operator assignment `op=` has a different base class, `BinAssignExp`
6051 extern (C++) class AssignExp : BinExp
6053 MemorySet memset;
6055 /************************************************************/
6056 /* op can be EXP.assign, EXP.construct, or EXP.blit */
6057 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
6059 super(loc, EXP.assign, e1, e2);
6062 this(const ref Loc loc, EXP tok, Expression e1, Expression e2) @safe
6064 super(loc, tok, e1, e2);
6067 override final bool isLvalue()
6069 // Array-op 'x[] = y[]' should make an rvalue.
6070 // Setting array length 'x.length = v' should make an rvalue.
6071 if (e1.op == EXP.slice || e1.op == EXP.arrayLength)
6073 return false;
6075 return true;
6078 override final Expression toLvalue(Scope* sc, Expression ex)
6080 if (e1.op == EXP.slice || e1.op == EXP.arrayLength)
6082 return Expression.toLvalue(sc, ex);
6085 /* In front-end level, AssignExp should make an lvalue of e1.
6086 * Taking the address of e1 will be handled in low level layer,
6087 * so this function does nothing.
6089 return this;
6092 override void accept(Visitor v)
6094 v.visit(this);
6098 /***********************************************************
6099 * When an assignment expression is lowered to a druntime call
6100 * this class is used to store the lowering.
6101 * It essentially behaves the same as an AssignExp, but it is
6102 * used to not waste space for other AssignExp that are not
6103 * lowered to anything.
6105 extern (C++) final class LoweredAssignExp : AssignExp
6107 Expression lowering;
6108 extern (D) this(AssignExp exp, Expression lowering) @safe
6110 super(exp.loc, EXP.loweredAssignExp, exp.e1, exp.e2);
6111 this.lowering = lowering;
6114 override const(char)* toChars() const
6116 return lowering.toChars();
6118 override void accept(Visitor v)
6120 v.visit(this);
6124 /***********************************************************
6126 extern (C++) final class ConstructExp : AssignExp
6128 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
6130 super(loc, EXP.construct, e1, e2);
6133 // Internal use only. If `v` is a reference variable, the assignment
6134 // will become a reference initialization automatically.
6135 extern (D) this(const ref Loc loc, VarDeclaration v, Expression e2) @safe
6137 auto ve = new VarExp(loc, v);
6138 assert(v.type && ve.type);
6140 super(loc, EXP.construct, ve, e2);
6142 if (v.isReference())
6143 memset = MemorySet.referenceInit;
6146 override void accept(Visitor v)
6148 v.visit(this);
6152 /***********************************************************
6153 * A bit-for-bit copy from `e2` to `e1`
6155 extern (C++) final class BlitExp : AssignExp
6157 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
6159 super(loc, EXP.blit, e1, e2);
6162 // Internal use only. If `v` is a reference variable, the assinment
6163 // will become a reference rebinding automatically.
6164 extern (D) this(const ref Loc loc, VarDeclaration v, Expression e2) @safe
6166 auto ve = new VarExp(loc, v);
6167 assert(v.type && ve.type);
6169 super(loc, EXP.blit, ve, e2);
6171 if (v.isReference())
6172 memset = MemorySet.referenceInit;
6175 override void accept(Visitor v)
6177 v.visit(this);
6181 /***********************************************************
6182 * `x += y`
6184 extern (C++) final class AddAssignExp : BinAssignExp
6186 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
6188 super(loc, EXP.addAssign, e1, e2);
6191 override void accept(Visitor v)
6193 v.visit(this);
6197 /***********************************************************
6198 * `x -= y`
6200 extern (C++) final class MinAssignExp : BinAssignExp
6202 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
6204 super(loc, EXP.minAssign, e1, e2);
6207 override void accept(Visitor v)
6209 v.visit(this);
6213 /***********************************************************
6214 * `x *= y`
6216 extern (C++) final class MulAssignExp : BinAssignExp
6218 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
6220 super(loc, EXP.mulAssign, e1, e2);
6223 override void accept(Visitor v)
6225 v.visit(this);
6229 /***********************************************************
6230 * `x /= y`
6232 extern (C++) final class DivAssignExp : BinAssignExp
6234 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
6236 super(loc, EXP.divAssign, e1, e2);
6239 override void accept(Visitor v)
6241 v.visit(this);
6245 /***********************************************************
6246 * `x %= y`
6248 extern (C++) final class ModAssignExp : BinAssignExp
6250 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
6252 super(loc, EXP.modAssign, e1, e2);
6255 override void accept(Visitor v)
6257 v.visit(this);
6261 /***********************************************************
6262 * `x &= y`
6264 extern (C++) final class AndAssignExp : BinAssignExp
6266 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
6268 super(loc, EXP.andAssign, e1, e2);
6271 override void accept(Visitor v)
6273 v.visit(this);
6277 /***********************************************************
6278 * `x |= y`
6280 extern (C++) final class OrAssignExp : BinAssignExp
6282 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
6284 super(loc, EXP.orAssign, e1, e2);
6287 override void accept(Visitor v)
6289 v.visit(this);
6293 /***********************************************************
6294 * `x ^= y`
6296 extern (C++) final class XorAssignExp : BinAssignExp
6298 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
6300 super(loc, EXP.xorAssign, e1, e2);
6303 override void accept(Visitor v)
6305 v.visit(this);
6309 /***********************************************************
6310 * `x ^^= y`
6312 extern (C++) final class PowAssignExp : BinAssignExp
6314 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
6316 super(loc, EXP.powAssign, e1, e2);
6319 override void accept(Visitor v)
6321 v.visit(this);
6325 /***********************************************************
6326 * `x <<= y`
6328 extern (C++) final class ShlAssignExp : BinAssignExp
6330 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
6332 super(loc, EXP.leftShiftAssign, e1, e2);
6335 override void accept(Visitor v)
6337 v.visit(this);
6341 /***********************************************************
6342 * `x >>= y`
6344 extern (C++) final class ShrAssignExp : BinAssignExp
6346 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
6348 super(loc, EXP.rightShiftAssign, e1, e2);
6351 override void accept(Visitor v)
6353 v.visit(this);
6357 /***********************************************************
6358 * `x >>>= y`
6360 extern (C++) final class UshrAssignExp : BinAssignExp
6362 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
6364 super(loc, EXP.unsignedRightShiftAssign, e1, e2);
6367 override void accept(Visitor v)
6369 v.visit(this);
6373 /***********************************************************
6374 * The `~=` operator.
6376 * It can have one of the following operators:
6378 * EXP.concatenateAssign - appending T[] to T[]
6379 * EXP.concatenateElemAssign - appending T to T[]
6380 * EXP.concatenateDcharAssign - appending dchar to T[]
6382 * The parser initially sets it to EXP.concatenateAssign, and semantic() later decides which
6383 * of the three it will be set to.
6385 extern (C++) class CatAssignExp : BinAssignExp
6387 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
6389 super(loc, EXP.concatenateAssign, e1, e2);
6392 extern (D) this(const ref Loc loc, EXP tok, Expression e1, Expression e2) @safe
6394 super(loc, tok, e1, e2);
6397 override void accept(Visitor v)
6399 v.visit(this);
6403 /***********************************************************
6404 * The `~=` operator when appending a single element
6406 extern (C++) final class CatElemAssignExp : CatAssignExp
6408 extern (D) this(const ref Loc loc, Type type, Expression e1, Expression e2) @safe
6410 super(loc, EXP.concatenateElemAssign, e1, e2);
6411 this.type = type;
6414 override void accept(Visitor v)
6416 v.visit(this);
6420 /***********************************************************
6421 * The `~=` operator when appending a single `dchar`
6423 extern (C++) final class CatDcharAssignExp : CatAssignExp
6425 extern (D) this(const ref Loc loc, Type type, Expression e1, Expression e2) @safe
6427 super(loc, EXP.concatenateDcharAssign, e1, e2);
6428 this.type = type;
6431 override void accept(Visitor v)
6433 v.visit(this);
6437 /***********************************************************
6438 * The addition operator, `x + y`
6440 * https://dlang.org/spec/expression.html#add_expressions
6442 extern (C++) final class AddExp : BinExp
6444 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
6446 super(loc, EXP.add, e1, e2);
6449 override void accept(Visitor v)
6451 v.visit(this);
6455 /***********************************************************
6456 * The minus operator, `x - y`
6458 * https://dlang.org/spec/expression.html#add_expressions
6460 extern (C++) final class MinExp : BinExp
6462 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
6464 super(loc, EXP.min, e1, e2);
6467 override void accept(Visitor v)
6469 v.visit(this);
6473 /***********************************************************
6474 * The concatenation operator, `x ~ y`
6476 * https://dlang.org/spec/expression.html#cat_expressions
6478 extern (C++) final class CatExp : BinExp
6480 Expression lowering; // call to druntime hook `_d_arraycatnTX`
6482 extern (D) this(const ref Loc loc, Expression e1, Expression e2) scope @safe
6484 super(loc, EXP.concatenate, e1, e2);
6487 override Expression resolveLoc(const ref Loc loc, Scope* sc)
6489 e1 = e1.resolveLoc(loc, sc);
6490 e2 = e2.resolveLoc(loc, sc);
6491 return this;
6494 override void accept(Visitor v)
6496 v.visit(this);
6500 /***********************************************************
6501 * The multiplication operator, `x * y`
6503 * https://dlang.org/spec/expression.html#mul_expressions
6505 extern (C++) final class MulExp : BinExp
6507 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
6509 super(loc, EXP.mul, e1, e2);
6512 override void accept(Visitor v)
6514 v.visit(this);
6518 /***********************************************************
6519 * The division operator, `x / y`
6521 * https://dlang.org/spec/expression.html#mul_expressions
6523 extern (C++) final class DivExp : BinExp
6525 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
6527 super(loc, EXP.div, e1, e2);
6530 override void accept(Visitor v)
6532 v.visit(this);
6536 /***********************************************************
6537 * The modulo operator, `x % y`
6539 * https://dlang.org/spec/expression.html#mul_expressions
6541 extern (C++) final class ModExp : BinExp
6543 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
6545 super(loc, EXP.mod, e1, e2);
6548 override void accept(Visitor v)
6550 v.visit(this);
6554 /***********************************************************
6555 * The 'power' operator, `x ^^ y`
6557 * https://dlang.org/spec/expression.html#pow_expressions
6559 extern (C++) final class PowExp : BinExp
6561 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
6563 super(loc, EXP.pow, e1, e2);
6566 override void accept(Visitor v)
6568 v.visit(this);
6572 /***********************************************************
6573 * The 'shift left' operator, `x << y`
6575 * https://dlang.org/spec/expression.html#shift_expressions
6577 extern (C++) final class ShlExp : BinExp
6579 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
6581 super(loc, EXP.leftShift, e1, e2);
6584 override void accept(Visitor v)
6586 v.visit(this);
6590 /***********************************************************
6591 * The 'shift right' operator, `x >> y`
6593 * https://dlang.org/spec/expression.html#shift_expressions
6595 extern (C++) final class ShrExp : BinExp
6597 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
6599 super(loc, EXP.rightShift, e1, e2);
6602 override void accept(Visitor v)
6604 v.visit(this);
6608 /***********************************************************
6609 * The 'unsigned shift right' operator, `x >>> y`
6611 * https://dlang.org/spec/expression.html#shift_expressions
6613 extern (C++) final class UshrExp : BinExp
6615 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
6617 super(loc, EXP.unsignedRightShift, e1, e2);
6620 override void accept(Visitor v)
6622 v.visit(this);
6626 /***********************************************************
6627 * The bitwise 'and' operator, `x & y`
6629 * https://dlang.org/spec/expression.html#and_expressions
6631 extern (C++) final class AndExp : BinExp
6633 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
6635 super(loc, EXP.and, e1, e2);
6638 override void accept(Visitor v)
6640 v.visit(this);
6644 /***********************************************************
6645 * The bitwise 'or' operator, `x | y`
6647 * https://dlang.org/spec/expression.html#or_expressions
6649 extern (C++) final class OrExp : BinExp
6651 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
6653 super(loc, EXP.or, e1, e2);
6656 override void accept(Visitor v)
6658 v.visit(this);
6662 /***********************************************************
6663 * The bitwise 'xor' operator, `x ^ y`
6665 * https://dlang.org/spec/expression.html#xor_expressions
6667 extern (C++) final class XorExp : BinExp
6669 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
6671 super(loc, EXP.xor, e1, e2);
6674 override void accept(Visitor v)
6676 v.visit(this);
6680 /***********************************************************
6681 * The logical 'and' / 'or' operator, `X && Y` / `X || Y`
6683 * https://dlang.org/spec/expression.html#andand_expressions
6684 * https://dlang.org/spec/expression.html#oror_expressions
6686 extern (C++) final class LogicalExp : BinExp
6688 extern (D) this(const ref Loc loc, EXP op, Expression e1, Expression e2) @safe
6690 super(loc, op, e1, e2);
6691 assert(op == EXP.andAnd || op == EXP.orOr);
6694 override void accept(Visitor v)
6696 v.visit(this);
6700 /***********************************************************
6701 * A comparison operator, `<` `<=` `>` `>=`
6703 * `op` is one of:
6704 * EXP.lessThan, EXP.lessOrEqual, EXP.greaterThan, EXP.greaterOrEqual
6706 * https://dlang.org/spec/expression.html#relation_expressions
6708 extern (C++) final class CmpExp : BinExp
6710 extern (D) this(EXP op, const ref Loc loc, Expression e1, Expression e2) @safe
6712 super(loc, op, e1, e2);
6713 assert(op == EXP.lessThan || op == EXP.lessOrEqual || op == EXP.greaterThan || op == EXP.greaterOrEqual);
6716 override void accept(Visitor v)
6718 v.visit(this);
6722 /***********************************************************
6723 * The `in` operator, `"a" in ["a": 1]`
6725 * Note: `x !in y` is rewritten to `!(x in y)` in the parser
6727 * https://dlang.org/spec/expression.html#in_expressions
6729 extern (C++) final class InExp : BinExp
6731 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
6733 super(loc, EXP.in_, e1, e2);
6736 override void accept(Visitor v)
6738 v.visit(this);
6742 /***********************************************************
6743 * Associative array removal, `aa.remove(arg)`
6745 * This deletes the key e1 from the associative array e2
6747 extern (C++) final class RemoveExp : BinExp
6749 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6751 super(loc, EXP.remove, e1, e2);
6752 type = Type.tbool;
6755 override void accept(Visitor v)
6757 v.visit(this);
6761 /***********************************************************
6762 * `==` and `!=`
6764 * EXP.equal and EXP.notEqual
6766 * https://dlang.org/spec/expression.html#equality_expressions
6768 extern (C++) final class EqualExp : BinExp
6770 extern (D) this(EXP op, const ref Loc loc, Expression e1, Expression e2) @safe
6772 super(loc, op, e1, e2);
6773 assert(op == EXP.equal || op == EXP.notEqual);
6776 override void accept(Visitor v)
6778 v.visit(this);
6782 /***********************************************************
6783 * `is` and `!is`
6785 * EXP.identity and EXP.notIdentity
6787 * https://dlang.org/spec/expression.html#identity_expressions
6789 extern (C++) final class IdentityExp : BinExp
6791 extern (D) this(EXP op, const ref Loc loc, Expression e1, Expression e2) @safe
6793 super(loc, op, e1, e2);
6794 assert(op == EXP.identity || op == EXP.notIdentity);
6797 override void accept(Visitor v)
6799 v.visit(this);
6803 /***********************************************************
6804 * The ternary operator, `econd ? e1 : e2`
6806 * https://dlang.org/spec/expression.html#conditional_expressions
6808 extern (C++) final class CondExp : BinExp
6810 Expression econd;
6812 extern (D) this(const ref Loc loc, Expression econd, Expression e1, Expression e2) scope @safe
6814 super(loc, EXP.question, e1, e2);
6815 this.econd = econd;
6818 override CondExp syntaxCopy()
6820 return new CondExp(loc, econd.syntaxCopy(), e1.syntaxCopy(), e2.syntaxCopy());
6823 override bool isLvalue()
6825 return e1.isLvalue() && e2.isLvalue();
6828 override Expression toLvalue(Scope* sc, Expression ex)
6830 // convert (econd ? e1 : e2) to *(econd ? &e1 : &e2)
6831 CondExp e = cast(CondExp)copy();
6832 e.e1 = e1.toLvalue(sc, null).addressOf();
6833 e.e2 = e2.toLvalue(sc, null).addressOf();
6834 e.type = type.pointerTo();
6835 return new PtrExp(loc, e, type);
6838 override Expression modifiableLvalue(Scope* sc, Expression e)
6840 if (!e1.isLvalue() && !e2.isLvalue())
6842 error(loc, "conditional expression `%s` is not a modifiable lvalue", toChars());
6843 return ErrorExp.get();
6845 e1 = e1.modifiableLvalue(sc, e1);
6846 e2 = e2.modifiableLvalue(sc, e2);
6847 return toLvalue(sc, this);
6850 void hookDtors(Scope* sc)
6852 extern (C++) final class DtorVisitor : StoppableVisitor
6854 alias visit = typeof(super).visit;
6855 public:
6856 Scope* sc;
6857 CondExp ce;
6858 VarDeclaration vcond;
6859 bool isThen;
6861 extern (D) this(Scope* sc, CondExp ce) @safe
6863 this.sc = sc;
6864 this.ce = ce;
6867 override void visit(Expression e)
6869 //printf("(e = %s)\n", e.toChars());
6872 override void visit(DeclarationExp e)
6874 auto v = e.declaration.isVarDeclaration();
6875 if (v && !v.isDataseg())
6877 if (v._init)
6879 if (auto ei = v._init.isExpInitializer())
6880 walkPostorder(ei.exp, this);
6883 if (v.edtor)
6884 walkPostorder(v.edtor, this);
6886 if (v.needsScopeDtor())
6888 if (!vcond)
6890 vcond = copyToTemp(STC.volatile_ | STC.const_, "__cond", ce.econd);
6891 vcond.dsymbolSemantic(sc);
6893 Expression de = new DeclarationExp(ce.econd.loc, vcond);
6894 de = de.expressionSemantic(sc);
6896 Expression ve = new VarExp(ce.econd.loc, vcond);
6897 ce.econd = Expression.combine(de, ve);
6900 //printf("\t++v = %s, v.edtor = %s\n", v.toChars(), v.edtor.toChars());
6901 Expression ve = new VarExp(vcond.loc, vcond);
6902 if (isThen)
6903 v.edtor = new LogicalExp(v.edtor.loc, EXP.andAnd, ve, v.edtor);
6904 else
6905 v.edtor = new LogicalExp(v.edtor.loc, EXP.orOr, ve, v.edtor);
6906 v.edtor = v.edtor.expressionSemantic(sc);
6907 //printf("\t--v = %s, v.edtor = %s\n", v.toChars(), v.edtor.toChars());
6913 scope DtorVisitor v = new DtorVisitor(sc, this);
6914 //printf("+%s\n", toChars());
6915 v.isThen = true;
6916 walkPostorder(e1, v);
6917 v.isThen = false;
6918 walkPostorder(e2, v);
6919 //printf("-%s\n", toChars());
6922 override void accept(Visitor v)
6924 v.visit(this);
6928 /***********************************************************
6929 * A special keyword when used as a function's default argument
6931 * When possible, special keywords are resolved in the parser, but when
6932 * appearing as a default argument, they result in an expression deriving
6933 * from this base class that is resolved for each function call.
6935 * ---
6936 * const x = __LINE__; // resolved in the parser
6937 * void foo(string file = __FILE__, int line = __LINE__); // DefaultInitExp
6938 * ---
6940 * https://dlang.org/spec/expression.html#specialkeywords
6942 extern (C++) class DefaultInitExp : Expression
6944 /*************************
6945 * Params:
6946 * loc = location
6947 * op = EXP.prettyFunction, EXP.functionString, EXP.moduleString,
6948 * EXP.line, EXP.file, EXP.fileFullPath
6950 extern (D) this(const ref Loc loc, EXP op) @safe
6952 super(loc, op);
6955 override void accept(Visitor v)
6957 v.visit(this);
6961 /***********************************************************
6962 * The `__FILE__` token as a default argument
6964 extern (C++) final class FileInitExp : DefaultInitExp
6966 extern (D) this(const ref Loc loc, EXP tok) @safe
6968 super(loc, tok);
6971 override Expression resolveLoc(const ref Loc loc, Scope* sc)
6973 //printf("FileInitExp::resolve() %s\n", toChars());
6974 const(char)* s;
6975 if (op == EXP.fileFullPath)
6976 s = FileName.toAbsolute(loc.isValid() ? loc.filename : sc._module.srcfile.toChars());
6977 else
6978 s = loc.isValid() ? loc.filename : sc._module.ident.toChars();
6980 Expression e = new StringExp(loc, s.toDString());
6981 return e.expressionSemantic(sc);
6984 override void accept(Visitor v)
6986 v.visit(this);
6990 /***********************************************************
6991 * The `__LINE__` token as a default argument
6993 extern (C++) final class LineInitExp : DefaultInitExp
6995 extern (D) this(const ref Loc loc) @safe
6997 super(loc, EXP.line);
7000 override Expression resolveLoc(const ref Loc loc, Scope* sc)
7002 Expression e = new IntegerExp(loc, loc.linnum, Type.tint32);
7003 return e.expressionSemantic(sc);
7006 override void accept(Visitor v)
7008 v.visit(this);
7012 /***********************************************************
7013 * The `__MODULE__` token as a default argument
7015 extern (C++) final class ModuleInitExp : DefaultInitExp
7017 extern (D) this(const ref Loc loc) @safe
7019 super(loc, EXP.moduleString);
7022 override Expression resolveLoc(const ref Loc loc, Scope* sc)
7024 const auto s = (sc.callsc ? sc.callsc : sc)._module.toPrettyChars().toDString();
7025 Expression e = new StringExp(loc, s);
7026 return e.expressionSemantic(sc);
7029 override void accept(Visitor v)
7031 v.visit(this);
7035 /***********************************************************
7036 * The `__FUNCTION__` token as a default argument
7038 extern (C++) final class FuncInitExp : DefaultInitExp
7040 extern (D) this(const ref Loc loc) @safe
7042 super(loc, EXP.functionString);
7045 override Expression resolveLoc(const ref Loc loc, Scope* sc)
7047 const(char)* s;
7048 if (sc.callsc && sc.callsc.func)
7049 s = sc.callsc.func.Dsymbol.toPrettyChars();
7050 else if (sc.func)
7051 s = sc.func.Dsymbol.toPrettyChars();
7052 else
7053 s = "";
7054 Expression e = new StringExp(loc, s.toDString());
7055 return e.expressionSemantic(sc);
7058 override void accept(Visitor v)
7060 v.visit(this);
7064 /***********************************************************
7065 * The `__PRETTY_FUNCTION__` token as a default argument
7067 extern (C++) final class PrettyFuncInitExp : DefaultInitExp
7069 extern (D) this(const ref Loc loc) @safe
7071 super(loc, EXP.prettyFunction);
7074 override Expression resolveLoc(const ref Loc loc, Scope* sc)
7076 FuncDeclaration fd = (sc.callsc && sc.callsc.func)
7077 ? sc.callsc.func
7078 : sc.func;
7080 const(char)* s;
7081 if (fd)
7083 const funcStr = fd.Dsymbol.toPrettyChars();
7084 OutBuffer buf;
7085 functionToBufferWithIdent(fd.type.isTypeFunction(), buf, funcStr, fd.isStatic);
7086 s = buf.extractChars();
7088 else
7090 s = "";
7093 Expression e = new StringExp(loc, s.toDString());
7094 e = e.expressionSemantic(sc);
7095 e.type = Type.tstring;
7096 return e;
7099 override void accept(Visitor v)
7101 v.visit(this);
7106 * Objective-C class reference expression.
7108 * Used to get the metaclass of an Objective-C class, `NSObject.Class`.
7110 extern (C++) final class ObjcClassReferenceExp : Expression
7112 ClassDeclaration classDeclaration;
7114 extern (D) this(const ref Loc loc, ClassDeclaration classDeclaration)
7116 super(loc, EXP.objcClassReference);
7117 this.classDeclaration = classDeclaration;
7118 type = objc.getRuntimeMetaclass(classDeclaration).getType();
7121 override void accept(Visitor v)
7123 v.visit(this);
7127 /*******************
7128 * C11 6.5.1.1 Generic Selection
7129 * For ImportC
7131 extern (C++) final class GenericExp : Expression
7133 Expression cntlExp; /// controlling expression of a generic selection (not evaluated)
7134 Types* types; /// type-names for generic associations (null entry for `default`)
7135 Expressions* exps; /// 1:1 mapping of typeNames to exps
7137 extern (D) this(const ref Loc loc, Expression cntlExp, Types* types, Expressions* exps) @safe
7139 super(loc, EXP._Generic);
7140 this.cntlExp = cntlExp;
7141 this.types = types;
7142 this.exps = exps;
7143 assert(types.length == exps.length); // must be the same and >=1
7146 override GenericExp syntaxCopy()
7148 return new GenericExp(loc, cntlExp.syntaxCopy(), Type.arraySyntaxCopy(types), Expression.arraySyntaxCopy(exps));
7151 override void accept(Visitor v)
7153 v.visit(this);
7157 /***************************************
7158 * Parameters:
7159 * sc: scope
7160 * flag: 1: do not issue error message for invalid modification
7161 2: the exp is a DotVarExp and a subfield of the leftmost
7162 variable is modified
7163 * Returns:
7164 * Whether the type is modifiable
7166 extern(D) Modifiable checkModifiable(Expression exp, Scope* sc, ModifyFlags flag = ModifyFlags.none)
7168 switch(exp.op)
7170 case EXP.variable:
7171 auto varExp = cast(VarExp)exp;
7173 //printf("VarExp::checkModifiable %s", varExp.toChars());
7174 assert(varExp.type);
7175 return varExp.var.checkModify(varExp.loc, sc, null, flag);
7177 case EXP.dotVariable:
7178 auto dotVarExp = cast(DotVarExp)exp;
7180 //printf("DotVarExp::checkModifiable %s %s\n", dotVarExp.toChars(), dotVarExp.type.toChars());
7181 if (dotVarExp.e1.op == EXP.this_)
7182 return dotVarExp.var.checkModify(dotVarExp.loc, sc, dotVarExp.e1, flag);
7184 /* https://issues.dlang.org/show_bug.cgi?id=12764
7185 * If inside a constructor and an expression of type `this.field.var`
7186 * is encountered, where `field` is a struct declaration with
7187 * default construction disabled, we must make sure that
7188 * assigning to `var` does not imply that `field` was initialized
7190 if (sc.func && sc.func.isCtorDeclaration())
7192 // if inside a constructor scope and e1 of this DotVarExp
7193 // is another DotVarExp, then check if the leftmost expression is a `this` identifier
7194 if (auto dve = dotVarExp.e1.isDotVarExp())
7196 // Iterate the chain of DotVarExp to find `this`
7197 // Keep track whether access to fields was limited to union members
7198 // s.t. one can initialize an entire struct inside nested unions
7199 // (but not its members)
7200 bool onlyUnion = true;
7201 while (true)
7203 auto v = dve.var.isVarDeclaration();
7204 assert(v);
7206 // Accessing union member?
7207 auto t = v.type.isTypeStruct();
7208 if (!t || !t.sym.isUnionDeclaration())
7209 onlyUnion = false;
7211 // Another DotVarExp left?
7212 if (!dve.e1 || dve.e1.op != EXP.dotVariable)
7213 break;
7215 dve = cast(DotVarExp) dve.e1;
7218 if (dve.e1.op == EXP.this_)
7220 scope v = dve.var.isVarDeclaration();
7221 /* if v is a struct member field with no initializer, no default construction
7222 * and v wasn't intialized before
7224 if (v && v.isField() && !v._init && !v.ctorinit)
7226 if (auto ts = v.type.isTypeStruct())
7228 if (ts.sym.noDefaultCtor)
7230 /* checkModify will consider that this is an initialization
7231 * of v while it is actually an assignment of a field of v
7233 scope modifyLevel = v.checkModify(dotVarExp.loc, sc, dve.e1, !onlyUnion ? (flag | ModifyFlags.fieldAssign) : flag);
7234 if (modifyLevel == Modifiable.initialization)
7236 // https://issues.dlang.org/show_bug.cgi?id=22118
7237 // v is a union type field that was assigned
7238 // a variable, therefore it counts as initialization
7239 if (v.ctorinit)
7240 return Modifiable.initialization;
7242 return Modifiable.yes;
7244 return modifyLevel;
7252 //printf("\te1 = %s\n", e1.toChars());
7253 return dotVarExp.e1.checkModifiable(sc, flag);
7255 case EXP.star:
7256 auto ptrExp = cast(PtrExp)exp;
7257 if (auto se = ptrExp.e1.isSymOffExp())
7259 return se.var.checkModify(ptrExp.loc, sc, null, flag);
7261 else if (auto ae = ptrExp.e1.isAddrExp())
7263 return ae.e1.checkModifiable(sc, flag);
7265 return Modifiable.yes;
7267 case EXP.slice:
7268 auto sliceExp = cast(SliceExp)exp;
7270 //printf("SliceExp::checkModifiable %s\n", sliceExp.toChars());
7271 auto e1 = sliceExp.e1;
7272 if (e1.type.ty == Tsarray || (e1.op == EXP.index && e1.type.ty != Tarray) || e1.op == EXP.slice)
7274 return e1.checkModifiable(sc, flag);
7276 return Modifiable.yes;
7278 case EXP.comma:
7279 return (cast(CommaExp)exp).e2.checkModifiable(sc, flag);
7281 case EXP.index:
7282 auto indexExp = cast(IndexExp)exp;
7283 auto e1 = indexExp.e1;
7284 if (e1.type.ty == Tsarray ||
7285 e1.type.ty == Taarray ||
7286 (e1.op == EXP.index && e1.type.ty != Tarray) ||
7287 e1.op == EXP.slice)
7289 return e1.checkModifiable(sc, flag);
7291 return Modifiable.yes;
7293 case EXP.question:
7294 auto condExp = cast(CondExp)exp;
7295 if (condExp.e1.checkModifiable(sc, flag) != Modifiable.no
7296 && condExp.e2.checkModifiable(sc, flag) != Modifiable.no)
7297 return Modifiable.yes;
7298 return Modifiable.no;
7300 default:
7301 return exp.type ? Modifiable.yes : Modifiable.no; // default modifiable
7306 * Verify if the given identifier is _d_array{,set}ctor.
7308 * Params:
7309 * id = the identifier to verify
7311 * Returns:
7312 * `true` if the identifier corresponds to a construction runtime hook,
7313 * `false` otherwise.
7315 bool isArrayConstruction(const Identifier id)
7317 import dmd.id : Id;
7319 return id == Id._d_arrayctor || id == Id._d_arraysetctor;
7322 /******************************
7323 * Provide efficient way to implement isUnaExp(), isBinExp(), isBinAssignExp()
7325 private immutable ubyte[EXP.max + 1] exptab =
7326 () {
7327 ubyte[EXP.max + 1] tab;
7328 with (EXPFLAGS)
7330 foreach (i; Eunary) { tab[i] |= unary; }
7331 foreach (i; Ebinary) { tab[i] |= unary | binary; }
7332 foreach (i; EbinaryAssign) { tab[i] |= unary | binary | binaryAssign; }
7334 return tab;
7335 } ();
7337 private enum EXPFLAGS : ubyte
7339 unary = 1,
7340 binary = 2,
7341 binaryAssign = 4,
7344 private enum Eunary =
7346 EXP.import_, EXP.assert_, EXP.throw_, EXP.dotIdentifier, EXP.dotTemplateDeclaration,
7347 EXP.dotVariable, EXP.dotTemplateInstance, EXP.delegate_, EXP.dotType, EXP.call,
7348 EXP.address, EXP.star, EXP.negate, EXP.uadd, EXP.tilde, EXP.not, EXP.delete_, EXP.cast_,
7349 EXP.vector, EXP.vectorArray, EXP.slice, EXP.arrayLength, EXP.array, EXP.delegatePointer,
7350 EXP.delegateFunctionPointer, EXP.preMinusMinus, EXP.prePlusPlus,
7353 private enum Ebinary =
7355 EXP.dot, EXP.comma, EXP.index, EXP.minusMinus, EXP.plusPlus, EXP.assign,
7356 EXP.add, EXP.min, EXP.concatenate, EXP.mul, EXP.div, EXP.mod, EXP.pow, EXP.leftShift,
7357 EXP.rightShift, EXP.unsignedRightShift, EXP.and, EXP.or, EXP.xor, EXP.andAnd, EXP.orOr,
7358 EXP.lessThan, EXP.lessOrEqual, EXP.greaterThan, EXP.greaterOrEqual,
7359 EXP.in_, EXP.remove, EXP.equal, EXP.notEqual, EXP.identity, EXP.notIdentity,
7360 EXP.question,
7361 EXP.construct, EXP.blit,
7364 private enum EbinaryAssign =
7366 EXP.addAssign, EXP.minAssign, EXP.mulAssign, EXP.divAssign, EXP.modAssign,
7367 EXP.andAssign, EXP.orAssign, EXP.xorAssign, EXP.powAssign,
7368 EXP.leftShiftAssign, EXP.rightShiftAssign, EXP.unsignedRightShiftAssign,
7369 EXP.concatenateAssign, EXP.concatenateElemAssign, EXP.concatenateDcharAssign,
7372 /// Given a member of the EXP enum, get the class instance size of the corresponding Expression class.
7373 /// Needed because the classes are `extern(C++)`
7374 private immutable ubyte[EXP.max+1] expSize = [
7375 EXP.reserved: 0,
7376 EXP.negate: __traits(classInstanceSize, NegExp),
7377 EXP.cast_: __traits(classInstanceSize, CastExp),
7378 EXP.null_: __traits(classInstanceSize, NullExp),
7379 EXP.assert_: __traits(classInstanceSize, AssertExp),
7380 EXP.array: __traits(classInstanceSize, ArrayExp),
7381 EXP.call: __traits(classInstanceSize, CallExp),
7382 EXP.address: __traits(classInstanceSize, AddrExp),
7383 EXP.type: __traits(classInstanceSize, TypeExp),
7384 EXP.throw_: __traits(classInstanceSize, ThrowExp),
7385 EXP.new_: __traits(classInstanceSize, NewExp),
7386 EXP.delete_: __traits(classInstanceSize, DeleteExp),
7387 EXP.star: __traits(classInstanceSize, PtrExp),
7388 EXP.symbolOffset: __traits(classInstanceSize, SymOffExp),
7389 EXP.variable: __traits(classInstanceSize, VarExp),
7390 EXP.dotVariable: __traits(classInstanceSize, DotVarExp),
7391 EXP.dotIdentifier: __traits(classInstanceSize, DotIdExp),
7392 EXP.dotTemplateInstance: __traits(classInstanceSize, DotTemplateInstanceExp),
7393 EXP.dotType: __traits(classInstanceSize, DotTypeExp),
7394 EXP.slice: __traits(classInstanceSize, SliceExp),
7395 EXP.arrayLength: __traits(classInstanceSize, ArrayLengthExp),
7396 EXP.dollar: __traits(classInstanceSize, DollarExp),
7397 EXP.template_: __traits(classInstanceSize, TemplateExp),
7398 EXP.dotTemplateDeclaration: __traits(classInstanceSize, DotTemplateExp),
7399 EXP.declaration: __traits(classInstanceSize, DeclarationExp),
7400 EXP.dSymbol: __traits(classInstanceSize, DsymbolExp),
7401 EXP.typeid_: __traits(classInstanceSize, TypeidExp),
7402 EXP.uadd: __traits(classInstanceSize, UAddExp),
7403 EXP.remove: __traits(classInstanceSize, RemoveExp),
7404 EXP.newAnonymousClass: __traits(classInstanceSize, NewAnonClassExp),
7405 EXP.arrayLiteral: __traits(classInstanceSize, ArrayLiteralExp),
7406 EXP.assocArrayLiteral: __traits(classInstanceSize, AssocArrayLiteralExp),
7407 EXP.structLiteral: __traits(classInstanceSize, StructLiteralExp),
7408 EXP.classReference: __traits(classInstanceSize, ClassReferenceExp),
7409 EXP.thrownException: __traits(classInstanceSize, ThrownExceptionExp),
7410 EXP.delegatePointer: __traits(classInstanceSize, DelegatePtrExp),
7411 EXP.delegateFunctionPointer: __traits(classInstanceSize, DelegateFuncptrExp),
7412 EXP.lessThan: __traits(classInstanceSize, CmpExp),
7413 EXP.greaterThan: __traits(classInstanceSize, CmpExp),
7414 EXP.lessOrEqual: __traits(classInstanceSize, CmpExp),
7415 EXP.greaterOrEqual: __traits(classInstanceSize, CmpExp),
7416 EXP.equal: __traits(classInstanceSize, EqualExp),
7417 EXP.notEqual: __traits(classInstanceSize, EqualExp),
7418 EXP.identity: __traits(classInstanceSize, IdentityExp),
7419 EXP.notIdentity: __traits(classInstanceSize, IdentityExp),
7420 EXP.index: __traits(classInstanceSize, IndexExp),
7421 EXP.is_: __traits(classInstanceSize, IsExp),
7422 EXP.leftShift: __traits(classInstanceSize, ShlExp),
7423 EXP.rightShift: __traits(classInstanceSize, ShrExp),
7424 EXP.leftShiftAssign: __traits(classInstanceSize, ShlAssignExp),
7425 EXP.rightShiftAssign: __traits(classInstanceSize, ShrAssignExp),
7426 EXP.unsignedRightShift: __traits(classInstanceSize, UshrExp),
7427 EXP.unsignedRightShiftAssign: __traits(classInstanceSize, UshrAssignExp),
7428 EXP.concatenate: __traits(classInstanceSize, CatExp),
7429 EXP.concatenateAssign: __traits(classInstanceSize, CatAssignExp),
7430 EXP.concatenateElemAssign: __traits(classInstanceSize, CatElemAssignExp),
7431 EXP.concatenateDcharAssign: __traits(classInstanceSize, CatDcharAssignExp),
7432 EXP.add: __traits(classInstanceSize, AddExp),
7433 EXP.min: __traits(classInstanceSize, MinExp),
7434 EXP.addAssign: __traits(classInstanceSize, AddAssignExp),
7435 EXP.minAssign: __traits(classInstanceSize, MinAssignExp),
7436 EXP.mul: __traits(classInstanceSize, MulExp),
7437 EXP.div: __traits(classInstanceSize, DivExp),
7438 EXP.mod: __traits(classInstanceSize, ModExp),
7439 EXP.mulAssign: __traits(classInstanceSize, MulAssignExp),
7440 EXP.divAssign: __traits(classInstanceSize, DivAssignExp),
7441 EXP.modAssign: __traits(classInstanceSize, ModAssignExp),
7442 EXP.and: __traits(classInstanceSize, AndExp),
7443 EXP.or: __traits(classInstanceSize, OrExp),
7444 EXP.xor: __traits(classInstanceSize, XorExp),
7445 EXP.andAssign: __traits(classInstanceSize, AndAssignExp),
7446 EXP.orAssign: __traits(classInstanceSize, OrAssignExp),
7447 EXP.xorAssign: __traits(classInstanceSize, XorAssignExp),
7448 EXP.assign: __traits(classInstanceSize, AssignExp),
7449 EXP.not: __traits(classInstanceSize, NotExp),
7450 EXP.tilde: __traits(classInstanceSize, ComExp),
7451 EXP.plusPlus: __traits(classInstanceSize, PostExp),
7452 EXP.minusMinus: __traits(classInstanceSize, PostExp),
7453 EXP.construct: __traits(classInstanceSize, ConstructExp),
7454 EXP.blit: __traits(classInstanceSize, BlitExp),
7455 EXP.dot: __traits(classInstanceSize, DotExp),
7456 EXP.comma: __traits(classInstanceSize, CommaExp),
7457 EXP.question: __traits(classInstanceSize, CondExp),
7458 EXP.andAnd: __traits(classInstanceSize, LogicalExp),
7459 EXP.orOr: __traits(classInstanceSize, LogicalExp),
7460 EXP.prePlusPlus: __traits(classInstanceSize, PreExp),
7461 EXP.preMinusMinus: __traits(classInstanceSize, PreExp),
7462 EXP.identifier: __traits(classInstanceSize, IdentifierExp),
7463 EXP.string_: __traits(classInstanceSize, StringExp),
7464 EXP.this_: __traits(classInstanceSize, ThisExp),
7465 EXP.super_: __traits(classInstanceSize, SuperExp),
7466 EXP.halt: __traits(classInstanceSize, HaltExp),
7467 EXP.tuple: __traits(classInstanceSize, TupleExp),
7468 EXP.error: __traits(classInstanceSize, ErrorExp),
7469 EXP.void_: __traits(classInstanceSize, VoidInitExp),
7470 EXP.int64: __traits(classInstanceSize, IntegerExp),
7471 EXP.float64: __traits(classInstanceSize, RealExp),
7472 EXP.complex80: __traits(classInstanceSize, ComplexExp),
7473 EXP.import_: __traits(classInstanceSize, ImportExp),
7474 EXP.delegate_: __traits(classInstanceSize, DelegateExp),
7475 EXP.function_: __traits(classInstanceSize, FuncExp),
7476 EXP.mixin_: __traits(classInstanceSize, MixinExp),
7477 EXP.in_: __traits(classInstanceSize, InExp),
7478 EXP.break_: __traits(classInstanceSize, CTFEExp),
7479 EXP.continue_: __traits(classInstanceSize, CTFEExp),
7480 EXP.goto_: __traits(classInstanceSize, CTFEExp),
7481 EXP.scope_: __traits(classInstanceSize, ScopeExp),
7482 EXP.traits: __traits(classInstanceSize, TraitsExp),
7483 EXP.overloadSet: __traits(classInstanceSize, OverExp),
7484 EXP.line: __traits(classInstanceSize, LineInitExp),
7485 EXP.file: __traits(classInstanceSize, FileInitExp),
7486 EXP.fileFullPath: __traits(classInstanceSize, FileInitExp),
7487 EXP.moduleString: __traits(classInstanceSize, ModuleInitExp),
7488 EXP.functionString: __traits(classInstanceSize, FuncInitExp),
7489 EXP.prettyFunction: __traits(classInstanceSize, PrettyFuncInitExp),
7490 EXP.pow: __traits(classInstanceSize, PowExp),
7491 EXP.powAssign: __traits(classInstanceSize, PowAssignExp),
7492 EXP.vector: __traits(classInstanceSize, VectorExp),
7493 EXP.voidExpression: __traits(classInstanceSize, CTFEExp),
7494 EXP.cantExpression: __traits(classInstanceSize, CTFEExp),
7495 EXP.showCtfeContext: __traits(classInstanceSize, CTFEExp),
7496 EXP.objcClassReference: __traits(classInstanceSize, ObjcClassReferenceExp),
7497 EXP.vectorArray: __traits(classInstanceSize, VectorArrayExp),
7498 EXP.compoundLiteral: __traits(classInstanceSize, CompoundLiteralExp),
7499 EXP._Generic: __traits(classInstanceSize, GenericExp),
7500 EXP.interval: __traits(classInstanceSize, IntervalExp),
7501 EXP.loweredAssignExp : __traits(classInstanceSize, LoweredAssignExp),