d: Merge dmd, druntime d8e3976a58, phobos 7a6e95688
[official-gcc.git] / gcc / d / dmd / expression.d
blob41eeff923d8ee01e4dfada4c9b1e71fef34525dc
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-2024 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.arraytypes;
22 import dmd.astenums;
23 import dmd.ast_node;
24 import dmd.dclass;
25 import dmd.declaration;
26 import dmd.dimport;
27 import dmd.dmodule;
28 import dmd.dstruct;
29 import dmd.dsymbol;
30 import dmd.dtemplate;
31 import dmd.errors;
32 import dmd.errorsink;
33 import dmd.func;
34 import dmd.globals;
35 import dmd.hdrgen;
36 import dmd.id;
37 import dmd.identifier;
38 import dmd.init;
39 import dmd.location;
40 import dmd.mtype;
41 import dmd.root.complex;
42 import dmd.root.ctfloat;
43 import dmd.common.outbuffer;
44 import dmd.root.optional;
45 import dmd.root.rmem;
46 import dmd.rootobject;
47 import dmd.root.string;
48 import dmd.root.utf;
49 import dmd.target;
50 import dmd.tokens;
51 import dmd.visitor;
53 enum LOGSEMANTIC = false;
55 /// Return value for `checkModifiable`
56 enum Modifiable
58 /// Not modifiable
59 no,
60 /// Modifiable (the type is mutable)
61 yes,
62 /// Modifiable because it is initialization
63 initialization,
65 /**
66 * Specifies how the checkModify deals with certain situations
68 enum ModifyFlags
70 /// Issue error messages on invalid modifications of the variable
71 none,
72 /// No errors are emitted for invalid modifications
73 noError = 0x1,
74 /// The modification occurs for a subfield of the current variable
75 fieldAssign = 0x2,
78 /****************************************
79 * Find the last non-comma expression.
80 * Params:
81 * e = Expressions connected by commas
82 * Returns:
83 * right-most non-comma expression
86 inout(Expression) lastComma(inout Expression e)
88 Expression ex = cast()e;
89 while (ex.op == EXP.comma)
90 ex = (cast(CommaExp)ex).e2;
91 return cast(inout)ex;
95 /****************************************
96 * Expand tuples in-place.
98 * Example:
99 * When there's a call `f(10, pair: AliasSeq!(20, 30), single: 40)`, the input is:
100 * `exps = [10, (20, 30), 40]`
101 * `names = [null, "pair", "single"]`
102 * The arrays will be modified to:
103 * `exps = [10, 20, 30, 40]`
104 * `names = [null, "pair", null, "single"]`
106 * Params:
107 * exps = array of Expressions
108 * names = optional array of names corresponding to Expressions
110 extern (C++) void expandTuples(Expressions* exps, Identifiers* names = null)
112 //printf("expandTuples()\n");
113 if (exps is null)
114 return;
116 if (names)
118 if (exps.length != names.length)
120 printf("exps.length = %d, names.length = %d\n", cast(int) exps.length, cast(int) names.length);
121 printf("exps = %s, names = %s\n", exps.toChars(), names.toChars());
122 if (exps.length > 0)
123 printf("%s\n", (*exps)[0].loc.toChars());
124 assert(0);
128 // At `index`, a tuple of length `length` is expanded. Insert corresponding nulls in `names`.
129 void expandNames(size_t index, size_t length)
131 if (names)
133 if (length == 0)
135 names.remove(index);
136 return;
138 foreach (i; 1 .. length)
140 names.insert(index + i, cast(Identifier) null);
145 for (size_t i = 0; i < exps.length; i++)
147 Expression arg = (*exps)[i];
148 if (!arg)
149 continue;
151 // Look for tuple with 0 members
152 if (auto e = arg.isTypeExp())
154 if (auto tt = e.type.toBasetype().isTypeTuple())
156 if (!tt.arguments || tt.arguments.length == 0)
158 exps.remove(i);
159 expandNames(i, 0);
160 if (i == exps.length)
161 return;
163 else // Expand a TypeTuple
165 exps.remove(i);
166 auto texps = new Expressions(tt.arguments.length);
167 foreach (j, a; *tt.arguments)
168 (*texps)[j] = new TypeExp(e.loc, a.type);
169 exps.insert(i, texps);
170 expandNames(i, texps.length);
172 i--;
173 continue;
177 // Inline expand all the tuples
178 while (arg.op == EXP.tuple)
180 TupleExp te = cast(TupleExp)arg;
181 exps.remove(i); // remove arg
182 exps.insert(i, te.exps); // replace with tuple contents
183 expandNames(i, te.exps.length);
184 if (i == exps.length)
185 return; // empty tuple, no more arguments
186 (*exps)[i] = Expression.combine(te.e0, (*exps)[i]);
187 arg = (*exps)[i];
192 /****************************************
193 * Expand alias this tuples.
195 TupleDeclaration isAliasThisTuple(Expression e)
197 if (!e.type)
198 return null;
200 Type t = e.type.toBasetype();
201 while (true)
203 if (Dsymbol s = t.toDsymbol(null))
205 if (auto ad = s.isAggregateDeclaration())
207 s = ad.aliasthis ? ad.aliasthis.sym : null;
208 if (s && s.isVarDeclaration())
210 TupleDeclaration td = s.isVarDeclaration().toAlias().isTupleDeclaration();
211 if (td && td.isexp)
212 return td;
214 if (Type att = t.aliasthisOf())
216 t = att;
217 continue;
221 return null;
225 /****************************************
226 * If `s` is a function template, i.e. the only member of a template
227 * and that member is a function, return that template.
228 * Params:
229 * s = symbol that might be a function template
230 * Returns:
231 * template for that function, otherwise null
233 TemplateDeclaration getFuncTemplateDecl(Dsymbol s) @safe
235 FuncDeclaration f = s.isFuncDeclaration();
236 if (f && f.parent)
238 if (auto ti = f.parent.isTemplateInstance())
240 if (!ti.isTemplateMixin() && ti.tempdecl)
242 auto td = ti.tempdecl.isTemplateDeclaration();
243 if (td.onemember && td.ident == f.ident)
245 return td;
250 return null;
253 /************************ TypeDotIdExp ************************************/
254 /* Things like:
255 * int.size
256 * foo.size
257 * (foo).size
258 * cast(foo).size
260 DotIdExp typeDotIdExp(const ref Loc loc, Type type, Identifier ident) @safe
262 return new DotIdExp(loc, new TypeExp(loc, type), ident);
265 /***************************************************
266 * Given an Expression, find the variable it really is.
268 * For example, `a[index]` is really `a`, and `s.f` is really `s`.
269 * Params:
270 * e = Expression to look at
271 * Returns:
272 * variable if there is one, null if not
274 VarDeclaration expToVariable(Expression e)
276 while (1)
278 switch (e.op)
280 case EXP.variable:
281 return (cast(VarExp)e).var.isVarDeclaration();
283 case EXP.dotVariable:
284 e = (cast(DotVarExp)e).e1;
285 continue;
287 case EXP.index:
289 IndexExp ei = cast(IndexExp)e;
290 e = ei.e1;
291 Type ti = e.type.toBasetype();
292 if (ti.ty == Tsarray)
293 continue;
294 return null;
297 case EXP.slice:
299 SliceExp ei = cast(SliceExp)e;
300 e = ei.e1;
301 Type ti = e.type.toBasetype();
302 if (ti.ty == Tsarray)
303 continue;
304 return null;
307 case EXP.this_:
308 case EXP.super_:
309 return (cast(ThisExp)e).var.isVarDeclaration();
311 // Temporaries for rvalues that need destruction
312 // are of form: (T s = rvalue, s). For these cases
313 // we can just return var declaration of `s`. However,
314 // this is intentionally not calling `Expression.extractLast`
315 // because at this point we cannot infer the var declaration
316 // of more complex generated comma expressions such as the
317 // one for the array append hook.
318 case EXP.comma:
320 if (auto ve = e.isCommaExp().e2.isVarExp())
321 return ve.var.isVarDeclaration();
323 return null;
325 default:
326 return null;
331 enum OwnedBy : ubyte
333 code, // normal code expression in AST
334 ctfe, // value expression for CTFE
335 cache, // constant value cached for CTFE
338 enum WANTvalue = 0; // default
339 enum WANTexpand = 1; // expand const/immutable variables if possible
341 /***********************************************************
342 * https://dlang.org/spec/expression.html#expression
344 extern (C++) abstract class Expression : ASTNode
346 Type type; // !=null means that semantic() has been run
347 Loc loc; // file location
348 const EXP op; // to minimize use of dynamic_cast
350 extern (D) this(const ref Loc loc, EXP op) scope @safe
352 //printf("Expression::Expression(op = %d) this = %p\n", op, this);
353 this.loc = loc;
354 this.op = op;
357 /// Returns: class instance size of this expression (implemented manually because `extern(C++)`)
358 final size_t size() nothrow @nogc pure @safe const { return expSize[op]; }
360 static void _init()
362 CTFEExp.cantexp = new CTFEExp(EXP.cantExpression);
363 CTFEExp.voidexp = new CTFEExp(EXP.voidExpression);
364 CTFEExp.breakexp = new CTFEExp(EXP.break_);
365 CTFEExp.continueexp = new CTFEExp(EXP.continue_);
366 CTFEExp.gotoexp = new CTFEExp(EXP.goto_);
367 CTFEExp.showcontext = new CTFEExp(EXP.showCtfeContext);
371 * Deinitializes the global state of the compiler.
373 * This can be used to restore the state set by `_init` to its original
374 * state.
376 static void deinitialize()
378 CTFEExp.cantexp = CTFEExp.cantexp.init;
379 CTFEExp.voidexp = CTFEExp.voidexp.init;
380 CTFEExp.breakexp = CTFEExp.breakexp.init;
381 CTFEExp.continueexp = CTFEExp.continueexp.init;
382 CTFEExp.gotoexp = CTFEExp.gotoexp.init;
383 CTFEExp.showcontext = CTFEExp.showcontext.init;
386 /*********************************
387 * Does *not* do a deep copy.
389 extern (D) final Expression copy()
391 Expression e;
392 if (!size)
394 debug
396 fprintf(stderr, "No expression copy for: %s\n", toChars());
397 printf("op = %d\n", op);
399 assert(0);
402 // memory never freed, so can use the faster bump-pointer-allocation
403 e = cast(Expression)allocmemory(size);
404 //printf("Expression::copy(op = %d) e = %p\n", op, e);
405 return cast(Expression)memcpy(cast(void*)e, cast(void*)this, size);
408 Expression syntaxCopy()
410 //printf("Expression::syntaxCopy()\n");
411 //print();
412 return copy();
415 // kludge for template.isExpression()
416 override final DYNCAST dyncast() const
418 return DYNCAST.expression;
421 override const(char)* toChars() const
423 return .toChars(this);
426 /**********************************
427 * Combine e1 and e2 by CommaExp if both are not NULL.
429 extern (D) static Expression combine(Expression e1, Expression e2) @safe
431 if (e1)
433 if (e2)
435 e1 = new CommaExp(e1.loc, e1, e2);
436 e1.type = e2.type;
439 else
440 e1 = e2;
441 return e1;
444 extern (D) static Expression combine(Expression e1, Expression e2, Expression e3) @safe
446 return combine(combine(e1, e2), e3);
449 extern (D) static Expression combine(Expression e1, Expression e2, Expression e3, Expression e4) @safe
451 return combine(combine(e1, e2), combine(e3, e4));
454 /**********************************
455 * If 'e' is a tree of commas, returns the rightmost expression
456 * by stripping off it from the tree. The remained part of the tree
457 * is returned via e0.
458 * Otherwise 'e' is directly returned and e0 is set to NULL.
460 extern (D) static Expression extractLast(Expression e, out Expression e0) @safe
462 if (e.op != EXP.comma)
464 return e;
467 CommaExp ce = cast(CommaExp)e;
468 if (ce.e2.op != EXP.comma)
470 e0 = ce.e1;
471 return ce.e2;
473 else
475 e0 = e;
477 Expression* pce = &ce.e2;
478 while ((cast(CommaExp)(*pce)).e2.op == EXP.comma)
480 pce = &(cast(CommaExp)(*pce)).e2;
482 assert((*pce).op == EXP.comma);
483 ce = cast(CommaExp)(*pce);
484 *pce = ce.e1;
486 return ce.e2;
490 extern (D) static Expressions* arraySyntaxCopy(Expressions* exps)
492 Expressions* a = null;
493 if (exps)
495 a = new Expressions(exps.length);
496 foreach (i, e; *exps)
498 (*a)[i] = e ? e.syntaxCopy() : null;
501 return a;
504 dinteger_t toInteger()
506 //printf("Expression %s\n", EXPtoString(op).ptr);
507 if (!type.isTypeError())
508 error(loc, "integer constant expression expected instead of `%s`", toChars());
509 return 0;
512 uinteger_t toUInteger()
514 //printf("Expression %s\n", EXPtoString(op).ptr);
515 return cast(uinteger_t)toInteger();
518 real_t toReal()
520 error(loc, "floating point constant expression expected instead of `%s`", toChars());
521 return CTFloat.zero;
524 real_t toImaginary()
526 error(loc, "floating point constant expression expected instead of `%s`", toChars());
527 return CTFloat.zero;
530 complex_t toComplex()
532 error(loc, "floating point constant expression expected instead of `%s`", toChars());
533 return complex_t(CTFloat.zero);
536 StringExp toStringExp()
538 return null;
541 /***************************************
542 * Return !=0 if expression is an lvalue.
544 bool isLvalue()
546 return false;
549 /****************************************
550 * Check that the expression has a valid type.
551 * If not, generates an error "... has no type".
552 * Returns:
553 * true if the expression is not valid.
554 * Note:
555 * When this function returns true, `checkValue()` should also return true.
557 bool checkType()
559 return false;
562 /****************************************
563 * Check that the expression has a valid value.
564 * If not, generates an error "... has no value".
565 * Returns:
566 * true if the expression is not valid or has void type.
568 bool checkValue()
570 if (type && type.toBasetype().ty == Tvoid)
572 error(loc, "expression `%s` is `void` and has no value", toChars());
573 //print(); assert(0);
574 if (!global.gag)
575 type = Type.terror;
576 return true;
578 return false;
581 extern (D) final bool checkScalar()
583 if (op == EXP.error)
584 return true;
585 if (type.toBasetype().ty == Terror)
586 return true;
587 if (!type.isscalar())
589 error(loc, "`%s` is not a scalar, it is a `%s`", toChars(), type.toChars());
590 return true;
592 return checkValue();
595 extern (D) final bool checkNoBool()
597 if (op == EXP.error)
598 return true;
599 if (type.toBasetype().ty == Terror)
600 return true;
601 if (type.toBasetype().ty == Tbool)
603 error(loc, "operation not allowed on `bool` `%s`", toChars());
604 return true;
606 return false;
609 extern (D) final bool checkIntegral()
611 if (op == EXP.error)
612 return true;
613 if (type.toBasetype().ty == Terror)
614 return true;
615 if (!type.isintegral())
617 error(loc, "`%s` is not of integral type, it is a `%s`", toChars(), type.toChars());
618 return true;
620 return checkValue();
623 extern (D) final bool checkArithmetic(EXP op)
625 if (op == EXP.error)
626 return true;
627 if (type.toBasetype().ty == Terror)
628 return true;
629 if (!type.isintegral() && !type.isfloating())
631 // unary aggregate ops error here
632 const char* msg = type.isAggregate() ?
633 "operator `%s` is not defined for `%s` of type `%s`" :
634 "illegal operator `%s` for `%s` of type `%s`";
635 error(loc, msg, EXPtoString(op).ptr, toChars(), type.toChars());
636 return true;
638 return checkValue();
641 /*******************************
642 * Check whether the expression allows RMW operations, error with rmw operator diagnostic if not.
643 * ex is the RHS expression, or NULL if ++/-- is used (for diagnostics)
644 * Returns true if error occurs.
646 extern (D) final bool checkReadModifyWrite(EXP rmwOp, Expression ex = null)
648 //printf("Expression::checkReadModifyWrite() %s %s", toChars(), ex ? ex.toChars() : "");
649 if (!type || !type.isShared() || type.isTypeStruct() || type.isTypeClass())
650 return false;
652 // atomicOp uses opAssign (+=/-=) rather than opOp (++/--) for the CT string literal.
653 switch (rmwOp)
655 case EXP.plusPlus:
656 case EXP.prePlusPlus:
657 rmwOp = EXP.addAssign;
658 break;
659 case EXP.minusMinus:
660 case EXP.preMinusMinus:
661 rmwOp = EXP.minAssign;
662 break;
663 default:
664 break;
667 error(loc, "read-modify-write operations are not allowed for `shared` variables");
668 errorSupplemental(loc, "Use `core.atomic.atomicOp!\"%s\"(%s, %s)` instead",
669 EXPtoString(rmwOp).ptr, toChars(), ex ? ex.toChars() : "1");
670 return true;
673 /******************************
674 * Take address of expression.
676 final Expression addressOf()
678 //printf("Expression::addressOf()\n");
679 debug
681 assert(op == EXP.error || isLvalue());
683 Expression e = new AddrExp(loc, this, type.pointerTo());
684 return e;
687 /******************************
688 * If this is a reference, dereference it.
690 final Expression deref()
692 //printf("Expression::deref()\n");
693 // type could be null if forward referencing an 'auto' variable
694 if (type)
695 if (auto tr = type.isTypeReference())
697 Expression e = new PtrExp(loc, this, tr.next);
698 return e;
700 return this;
703 final int isConst()
705 //printf("Expression::isConst(): %s\n", e.toChars());
706 switch (op)
708 case EXP.int64:
709 case EXP.float64:
710 case EXP.complex80:
711 return 1;
712 case EXP.null_:
713 return 0;
714 case EXP.symbolOffset:
715 return 2;
716 default:
717 return 0;
719 assert(0);
722 /******
723 * Identical, not just equal. I.e. NaNs with different bit patterns are not identical
725 bool isIdentical(const Expression e) const
727 return equals(e);
731 /// Statically evaluate this expression to a `bool` if possible
732 /// Returns: an optional thath either contains the value or is empty
733 Optional!bool toBool()
735 return typeof(return)();
738 bool hasCode()
740 return true;
743 final pure inout nothrow @nogc @safe
745 inout(IntegerExp) isIntegerExp() { return op == EXP.int64 ? cast(typeof(return))this : null; }
746 inout(ErrorExp) isErrorExp() { return op == EXP.error ? cast(typeof(return))this : null; }
747 inout(VoidInitExp) isVoidInitExp() { return op == EXP.void_ ? cast(typeof(return))this : null; }
748 inout(RealExp) isRealExp() { return op == EXP.float64 ? cast(typeof(return))this : null; }
749 inout(ComplexExp) isComplexExp() { return op == EXP.complex80 ? cast(typeof(return))this : null; }
750 inout(IdentifierExp) isIdentifierExp() { return op == EXP.identifier ? cast(typeof(return))this : null; }
751 inout(DollarExp) isDollarExp() { return op == EXP.dollar ? cast(typeof(return))this : null; }
752 inout(DsymbolExp) isDsymbolExp() { return op == EXP.dSymbol ? cast(typeof(return))this : null; }
753 inout(ThisExp) isThisExp() { return op == EXP.this_ ? cast(typeof(return))this : null; }
754 inout(SuperExp) isSuperExp() { return op == EXP.super_ ? cast(typeof(return))this : null; }
755 inout(NullExp) isNullExp() { return op == EXP.null_ ? cast(typeof(return))this : null; }
756 inout(StringExp) isStringExp() { return op == EXP.string_ ? cast(typeof(return))this : null; }
757 inout(TupleExp) isTupleExp() { return op == EXP.tuple ? cast(typeof(return))this : null; }
758 inout(ArrayLiteralExp) isArrayLiteralExp() { return op == EXP.arrayLiteral ? cast(typeof(return))this : null; }
759 inout(AssocArrayLiteralExp) isAssocArrayLiteralExp() { return op == EXP.assocArrayLiteral ? cast(typeof(return))this : null; }
760 inout(StructLiteralExp) isStructLiteralExp() { return op == EXP.structLiteral ? cast(typeof(return))this : null; }
761 inout(CompoundLiteralExp) isCompoundLiteralExp() { return op == EXP.compoundLiteral ? cast(typeof(return))this : null; }
762 inout(TypeExp) isTypeExp() { return op == EXP.type ? cast(typeof(return))this : null; }
763 inout(ScopeExp) isScopeExp() { return op == EXP.scope_ ? cast(typeof(return))this : null; }
764 inout(TemplateExp) isTemplateExp() { return op == EXP.template_ ? cast(typeof(return))this : null; }
765 inout(NewExp) isNewExp() { return op == EXP.new_ ? cast(typeof(return))this : null; }
766 inout(NewAnonClassExp) isNewAnonClassExp() { return op == EXP.newAnonymousClass ? cast(typeof(return))this : null; }
767 inout(SymOffExp) isSymOffExp() { return op == EXP.symbolOffset ? cast(typeof(return))this : null; }
768 inout(VarExp) isVarExp() { return op == EXP.variable ? cast(typeof(return))this : null; }
769 inout(OverExp) isOverExp() { return op == EXP.overloadSet ? cast(typeof(return))this : null; }
770 inout(FuncExp) isFuncExp() { return op == EXP.function_ ? cast(typeof(return))this : null; }
771 inout(DeclarationExp) isDeclarationExp() { return op == EXP.declaration ? cast(typeof(return))this : null; }
772 inout(TypeidExp) isTypeidExp() { return op == EXP.typeid_ ? cast(typeof(return))this : null; }
773 inout(TraitsExp) isTraitsExp() { return op == EXP.traits ? cast(typeof(return))this : null; }
774 inout(HaltExp) isHaltExp() { return op == EXP.halt ? cast(typeof(return))this : null; }
775 inout(IsExp) isExp() { return op == EXP.is_ ? cast(typeof(return))this : null; }
776 inout(MixinExp) isMixinExp() { return op == EXP.mixin_ ? cast(typeof(return))this : null; }
777 inout(ImportExp) isImportExp() { return op == EXP.import_ ? cast(typeof(return))this : null; }
778 inout(AssertExp) isAssertExp() { return op == EXP.assert_ ? cast(typeof(return))this : null; }
779 inout(ThrowExp) isThrowExp() { return op == EXP.throw_ ? cast(typeof(return))this : null; }
780 inout(DotIdExp) isDotIdExp() { return op == EXP.dotIdentifier ? cast(typeof(return))this : null; }
781 inout(DotTemplateExp) isDotTemplateExp() { return op == EXP.dotTemplateDeclaration ? cast(typeof(return))this : null; }
782 inout(DotVarExp) isDotVarExp() { return op == EXP.dotVariable ? cast(typeof(return))this : null; }
783 inout(DotTemplateInstanceExp) isDotTemplateInstanceExp() { return op == EXP.dotTemplateInstance ? cast(typeof(return))this : null; }
784 inout(DelegateExp) isDelegateExp() { return op == EXP.delegate_ ? cast(typeof(return))this : null; }
785 inout(DotTypeExp) isDotTypeExp() { return op == EXP.dotType ? cast(typeof(return))this : null; }
786 inout(CallExp) isCallExp() { return op == EXP.call ? cast(typeof(return))this : null; }
787 inout(AddrExp) isAddrExp() { return op == EXP.address ? cast(typeof(return))this : null; }
788 inout(PtrExp) isPtrExp() { return op == EXP.star ? cast(typeof(return))this : null; }
789 inout(NegExp) isNegExp() { return op == EXP.negate ? cast(typeof(return))this : null; }
790 inout(UAddExp) isUAddExp() { return op == EXP.uadd ? cast(typeof(return))this : null; }
791 inout(ComExp) isComExp() { return op == EXP.tilde ? cast(typeof(return))this : null; }
792 inout(NotExp) isNotExp() { return op == EXP.not ? cast(typeof(return))this : null; }
793 inout(DeleteExp) isDeleteExp() { return op == EXP.delete_ ? cast(typeof(return))this : null; }
794 inout(CastExp) isCastExp() { return op == EXP.cast_ ? cast(typeof(return))this : null; }
795 inout(VectorExp) isVectorExp() { return op == EXP.vector ? cast(typeof(return))this : null; }
796 inout(VectorArrayExp) isVectorArrayExp() { return op == EXP.vectorArray ? cast(typeof(return))this : null; }
797 inout(SliceExp) isSliceExp() { return op == EXP.slice ? cast(typeof(return))this : null; }
798 inout(ArrayLengthExp) isArrayLengthExp() { return op == EXP.arrayLength ? cast(typeof(return))this : null; }
799 inout(ArrayExp) isArrayExp() { return op == EXP.array ? cast(typeof(return))this : null; }
800 inout(DotExp) isDotExp() { return op == EXP.dot ? cast(typeof(return))this : null; }
801 inout(CommaExp) isCommaExp() { return op == EXP.comma ? cast(typeof(return))this : null; }
802 inout(IntervalExp) isIntervalExp() { return op == EXP.interval ? cast(typeof(return))this : null; }
803 inout(DelegatePtrExp) isDelegatePtrExp() { return op == EXP.delegatePointer ? cast(typeof(return))this : null; }
804 inout(DelegateFuncptrExp) isDelegateFuncptrExp() { return op == EXP.delegateFunctionPointer ? cast(typeof(return))this : null; }
805 inout(IndexExp) isIndexExp() { return op == EXP.index ? cast(typeof(return))this : null; }
806 inout(PostExp) isPostExp() { return (op == EXP.plusPlus || op == EXP.minusMinus) ? cast(typeof(return))this : null; }
807 inout(PreExp) isPreExp() { return (op == EXP.prePlusPlus || op == EXP.preMinusMinus) ? cast(typeof(return))this : null; }
808 inout(AssignExp) isAssignExp() { return op == EXP.assign ? cast(typeof(return))this : null; }
809 inout(LoweredAssignExp) isLoweredAssignExp() { return op == EXP.loweredAssignExp ? cast(typeof(return))this : null; }
810 inout(ConstructExp) isConstructExp() { return op == EXP.construct ? cast(typeof(return))this : null; }
811 inout(BlitExp) isBlitExp() { return op == EXP.blit ? cast(typeof(return))this : null; }
812 inout(AddAssignExp) isAddAssignExp() { return op == EXP.addAssign ? cast(typeof(return))this : null; }
813 inout(MinAssignExp) isMinAssignExp() { return op == EXP.minAssign ? cast(typeof(return))this : null; }
814 inout(MulAssignExp) isMulAssignExp() { return op == EXP.mulAssign ? cast(typeof(return))this : null; }
816 inout(DivAssignExp) isDivAssignExp() { return op == EXP.divAssign ? cast(typeof(return))this : null; }
817 inout(ModAssignExp) isModAssignExp() { return op == EXP.modAssign ? cast(typeof(return))this : null; }
818 inout(AndAssignExp) isAndAssignExp() { return op == EXP.andAssign ? cast(typeof(return))this : null; }
819 inout(OrAssignExp) isOrAssignExp() { return op == EXP.orAssign ? cast(typeof(return))this : null; }
820 inout(XorAssignExp) isXorAssignExp() { return op == EXP.xorAssign ? cast(typeof(return))this : null; }
821 inout(PowAssignExp) isPowAssignExp() { return op == EXP.powAssign ? cast(typeof(return))this : null; }
823 inout(ShlAssignExp) isShlAssignExp() { return op == EXP.leftShiftAssign ? cast(typeof(return))this : null; }
824 inout(ShrAssignExp) isShrAssignExp() { return op == EXP.rightShiftAssign ? cast(typeof(return))this : null; }
825 inout(UshrAssignExp) isUshrAssignExp() { return op == EXP.unsignedRightShiftAssign ? cast(typeof(return))this : null; }
827 inout(CatAssignExp) isCatAssignExp() { return op == EXP.concatenateAssign
828 ? cast(typeof(return))this
829 : null; }
831 inout(CatElemAssignExp) isCatElemAssignExp() { return op == EXP.concatenateElemAssign
832 ? cast(typeof(return))this
833 : null; }
835 inout(CatDcharAssignExp) isCatDcharAssignExp() { return op == EXP.concatenateDcharAssign
836 ? cast(typeof(return))this
837 : null; }
839 inout(AddExp) isAddExp() { return op == EXP.add ? cast(typeof(return))this : null; }
840 inout(MinExp) isMinExp() { return op == EXP.min ? cast(typeof(return))this : null; }
841 inout(CatExp) isCatExp() { return op == EXP.concatenate ? cast(typeof(return))this : null; }
842 inout(MulExp) isMulExp() { return op == EXP.mul ? cast(typeof(return))this : null; }
843 inout(DivExp) isDivExp() { return op == EXP.div ? cast(typeof(return))this : null; }
844 inout(ModExp) isModExp() { return op == EXP.mod ? cast(typeof(return))this : null; }
845 inout(PowExp) isPowExp() { return op == EXP.pow ? cast(typeof(return))this : null; }
846 inout(ShlExp) isShlExp() { return op == EXP.leftShift ? cast(typeof(return))this : null; }
847 inout(ShrExp) isShrExp() { return op == EXP.rightShift ? cast(typeof(return))this : null; }
848 inout(UshrExp) isUshrExp() { return op == EXP.unsignedRightShift ? cast(typeof(return))this : null; }
849 inout(AndExp) isAndExp() { return op == EXP.and ? cast(typeof(return))this : null; }
850 inout(OrExp) isOrExp() { return op == EXP.or ? cast(typeof(return))this : null; }
851 inout(XorExp) isXorExp() { return op == EXP.xor ? cast(typeof(return))this : null; }
852 inout(LogicalExp) isLogicalExp() { return (op == EXP.andAnd || op == EXP.orOr) ? cast(typeof(return))this : null; }
853 //inout(CmpExp) isCmpExp() { return op == EXP. ? cast(typeof(return))this : null; }
854 inout(InExp) isInExp() { return op == EXP.in_ ? cast(typeof(return))this : null; }
855 inout(RemoveExp) isRemoveExp() { return op == EXP.remove ? cast(typeof(return))this : null; }
856 inout(EqualExp) isEqualExp() { return (op == EXP.equal || op == EXP.notEqual) ? cast(typeof(return))this : null; }
857 inout(IdentityExp) isIdentityExp() { return (op == EXP.identity || op == EXP.notIdentity) ? cast(typeof(return))this : null; }
858 inout(CondExp) isCondExp() { return op == EXP.question ? cast(typeof(return))this : null; }
859 inout(GenericExp) isGenericExp() { return op == EXP._Generic ? cast(typeof(return))this : null; }
860 inout(DefaultInitExp) isDefaultInitExp() { return
861 (op == EXP.prettyFunction || op == EXP.functionString ||
862 op == EXP.line || op == EXP.moduleString ||
863 op == EXP.file || op == EXP.fileFullPath ) ? cast(typeof(return))this : null; }
864 inout(FileInitExp) isFileInitExp() { return (op == EXP.file || op == EXP.fileFullPath) ? cast(typeof(return))this : null; }
865 inout(LineInitExp) isLineInitExp() { return op == EXP.line ? cast(typeof(return))this : null; }
866 inout(ModuleInitExp) isModuleInitExp() { return op == EXP.moduleString ? cast(typeof(return))this : null; }
867 inout(FuncInitExp) isFuncInitExp() { return op == EXP.functionString ? cast(typeof(return))this : null; }
868 inout(PrettyFuncInitExp) isPrettyFuncInitExp() { return op == EXP.prettyFunction ? cast(typeof(return))this : null; }
869 inout(ObjcClassReferenceExp) isObjcClassReferenceExp() { return op == EXP.objcClassReference ? cast(typeof(return))this : null; }
870 inout(ClassReferenceExp) isClassReferenceExp() { return op == EXP.classReference ? cast(typeof(return))this : null; }
871 inout(ThrownExceptionExp) isThrownExceptionExp() { return op == EXP.thrownException ? cast(typeof(return))this : null; }
873 inout(UnaExp) isUnaExp() pure inout nothrow @nogc
875 return exptab[op] & EXPFLAGS.unary ? cast(typeof(return))this : null;
878 inout(BinExp) isBinExp() pure inout nothrow @nogc
880 return exptab[op] & EXPFLAGS.binary ? cast(typeof(return))this : null;
883 inout(BinAssignExp) isBinAssignExp() pure inout nothrow @nogc
885 return exptab[op] & EXPFLAGS.binaryAssign ? cast(typeof(return))this : null;
889 override void accept(Visitor v)
891 v.visit(this);
895 /***********************************************************
896 * A compile-time known integer value
898 extern (C++) final class IntegerExp : Expression
900 private dinteger_t value;
902 extern (D) this(const ref Loc loc, dinteger_t value, Type type)
904 super(loc, EXP.int64);
905 //printf("IntegerExp(value = %lld, type = '%s')\n", value, type ? type.toChars() : "");
906 assert(type);
907 if (!type.isscalar())
909 //printf("%s, loc = %d\n", toChars(), loc.linnum);
910 if (type.ty != Terror)
911 error(loc, "integral constant must be scalar type, not `%s`", type.toChars());
912 type = Type.terror;
914 this.type = type;
915 this.value = normalize(type.toBasetype().ty, value);
918 extern (D) this(dinteger_t value)
920 super(Loc.initial, EXP.int64);
921 this.type = Type.tint32;
922 this.value = cast(int)value;
925 static IntegerExp create(const ref Loc loc, dinteger_t value, Type type)
927 return new IntegerExp(loc, value, type);
930 override bool equals(const RootObject o) const
932 if (this == o)
933 return true;
934 if (auto ne = (cast(Expression)o).isIntegerExp())
936 if (type.toHeadMutable().equals(ne.type.toHeadMutable()) && value == ne.value)
938 return true;
941 return false;
944 override dinteger_t toInteger()
946 // normalize() is necessary until we fix all the paints of 'type'
947 return value = normalize(type.toBasetype().ty, value);
950 override real_t toReal()
952 // normalize() is necessary until we fix all the paints of 'type'
953 const ty = type.toBasetype().ty;
954 const val = normalize(ty, value);
955 value = val;
956 return (ty == Tuns64)
957 ? real_t(cast(ulong)val)
958 : real_t(cast(long)val);
961 override real_t toImaginary()
963 return CTFloat.zero;
966 override complex_t toComplex()
968 return complex_t(toReal());
971 override Optional!bool toBool()
973 bool r = toInteger() != 0;
974 return typeof(return)(r);
977 override void accept(Visitor v)
979 v.visit(this);
982 dinteger_t getInteger()
984 return value;
987 extern (D) void setInteger(dinteger_t value)
989 this.value = normalize(type.toBasetype().ty, value);
992 extern (D) static dinteger_t normalize(TY ty, dinteger_t value)
994 /* 'Normalize' the value of the integer to be in range of the type
996 dinteger_t result;
997 switch (ty)
999 case Tbool:
1000 result = (value != 0);
1001 break;
1003 case Tint8:
1004 result = cast(byte)value;
1005 break;
1007 case Tchar:
1008 case Tuns8:
1009 result = cast(ubyte)value;
1010 break;
1012 case Tint16:
1013 result = cast(short)value;
1014 break;
1016 case Twchar:
1017 case Tuns16:
1018 result = cast(ushort)value;
1019 break;
1021 case Tint32:
1022 result = cast(int)value;
1023 break;
1025 case Tdchar:
1026 case Tuns32:
1027 result = cast(uint)value;
1028 break;
1030 case Tint64:
1031 result = cast(long)value;
1032 break;
1034 case Tuns64:
1035 result = cast(ulong)value;
1036 break;
1038 case Tpointer:
1039 if (target.ptrsize == 8)
1040 goto case Tuns64;
1041 if (target.ptrsize == 4)
1042 goto case Tuns32;
1043 if (target.ptrsize == 2)
1044 goto case Tuns16;
1045 assert(0);
1047 default:
1048 break;
1050 return result;
1053 override IntegerExp syntaxCopy()
1055 return this;
1059 * Use this instead of creating new instances for commonly used literals
1060 * such as 0 or 1.
1062 * Parameters:
1063 * v = The value of the expression
1064 * Returns:
1065 * A static instance of the expression, typed as `Tint32`.
1067 static IntegerExp literal(int v)()
1069 __gshared IntegerExp theConstant;
1070 if (!theConstant)
1071 theConstant = new IntegerExp(v);
1072 return theConstant;
1076 * Use this instead of creating new instances for commonly used bools.
1078 * Parameters:
1079 * b = The value of the expression
1080 * Returns:
1081 * A static instance of the expression, typed as `Type.tbool`.
1083 static IntegerExp createBool(bool b)
1085 __gshared IntegerExp trueExp, falseExp;
1086 if (!trueExp)
1088 trueExp = new IntegerExp(Loc.initial, 1, Type.tbool);
1089 falseExp = new IntegerExp(Loc.initial, 0, Type.tbool);
1091 return b ? trueExp : falseExp;
1095 /***********************************************************
1096 * Use this expression for error recovery.
1098 * It should behave as a 'sink' to prevent further cascaded error messages.
1100 extern (C++) final class ErrorExp : Expression
1102 extern (D) this()
1104 super(Loc.initial, EXP.error);
1105 type = Type.terror;
1108 static ErrorExp get ()
1110 if (errorexp is null)
1111 errorexp = new ErrorExp();
1113 if (global.errors == 0 && global.gaggedErrors == 0)
1115 /* Unfortunately, errors can still leak out of gagged errors,
1116 * and we need to set the error count to prevent bogus code
1117 * generation. At least give a message.
1119 .error(Loc.initial, "unknown, please file report on issues.dlang.org");
1122 return errorexp;
1125 override void accept(Visitor v)
1127 v.visit(this);
1130 extern (C++) __gshared ErrorExp errorexp; // handy shared value
1134 /***********************************************************
1135 * An uninitialized value,
1136 * generated from void initializers.
1138 * https://dlang.org/spec/declaration.html#void_init
1140 extern (C++) final class VoidInitExp : Expression
1142 VarDeclaration var; /// the variable from where the void value came from, null if not known
1143 /// Useful for error messages
1145 extern (D) this(VarDeclaration var) @safe
1147 super(var.loc, EXP.void_);
1148 this.var = var;
1149 this.type = var.type;
1152 override void accept(Visitor v)
1154 v.visit(this);
1159 /***********************************************************
1160 * A compile-time known floating point number
1162 extern (C++) final class RealExp : Expression
1164 real_t value;
1166 extern (D) this(const ref Loc loc, real_t value, Type type) @safe
1168 super(loc, EXP.float64);
1169 //printf("RealExp::RealExp(%Lg)\n", value);
1170 this.value = value;
1171 this.type = type;
1174 static RealExp create(const ref Loc loc, real_t value, Type type) @safe
1176 return new RealExp(loc, value, type);
1179 /********************************
1180 * Test to see if two reals are the same.
1181 * Regard NaN's as equivalent.
1182 * Regard +0 and -0 as different.
1183 * Params:
1184 * x1 = first operand
1185 * x2 = second operand
1186 * Returns:
1187 * true if x1 is x2
1188 * else false
1190 private static bool RealIdentical(real_t x1, real_t x2) @safe
1192 return (CTFloat.isNaN(x1) && CTFloat.isNaN(x2)) || CTFloat.isIdentical(x1, x2);
1194 override bool equals(const RootObject o) const
1196 if (this == o)
1197 return true;
1198 if (auto ne = (cast(Expression)o).isRealExp())
1200 if (type.toHeadMutable().equals(ne.type.toHeadMutable()) && RealIdentical(value, ne.value))
1202 return true;
1205 return false;
1208 override bool isIdentical(const Expression e) const
1210 if (!equals(e))
1211 return false;
1212 return CTFloat.isIdentical(value, e.isRealExp().value);
1215 override dinteger_t toInteger()
1217 return cast(sinteger_t)toReal();
1220 override uinteger_t toUInteger()
1222 return cast(uinteger_t)toReal();
1225 override real_t toReal()
1227 return type.isreal() ? value : CTFloat.zero;
1230 override real_t toImaginary()
1232 return type.isreal() ? CTFloat.zero : value;
1235 override complex_t toComplex()
1237 return complex_t(toReal(), toImaginary());
1240 override Optional!bool toBool()
1242 return typeof(return)(!!value);
1245 override void accept(Visitor v)
1247 v.visit(this);
1251 /***********************************************************
1252 * A compile-time complex number (deprecated)
1254 extern (C++) final class ComplexExp : Expression
1256 complex_t value;
1258 extern (D) this(const ref Loc loc, complex_t value, Type type) @safe
1260 super(loc, EXP.complex80);
1261 this.value = value;
1262 this.type = type;
1263 //printf("ComplexExp::ComplexExp(%s)\n", toChars());
1266 static ComplexExp create(const ref Loc loc, complex_t value, Type type) @safe
1268 return new ComplexExp(loc, value, type);
1271 override bool equals(const RootObject o) const
1273 if (this == o)
1274 return true;
1275 if (auto ne = (cast(Expression)o).isComplexExp())
1277 if (type.toHeadMutable().equals(ne.type.toHeadMutable()) &&
1278 RealExp.RealIdentical(creall(value), creall(ne.value)) &&
1279 RealExp.RealIdentical(cimagl(value), cimagl(ne.value)))
1281 return true;
1284 return false;
1287 override bool isIdentical(const Expression e) const
1289 if (!equals(e))
1290 return false;
1291 // equals() regards different NaN values as 'equals'
1292 auto c = e.isComplexExp();
1293 return CTFloat.isIdentical(creall(value), creall(c.value)) &&
1294 CTFloat.isIdentical(cimagl(value), cimagl(c.value));
1297 override dinteger_t toInteger()
1299 return cast(sinteger_t)toReal();
1302 override uinteger_t toUInteger()
1304 return cast(uinteger_t)toReal();
1307 override real_t toReal()
1309 return creall(value);
1312 override real_t toImaginary()
1314 return cimagl(value);
1317 override complex_t toComplex()
1319 return value;
1322 override Optional!bool toBool()
1324 return typeof(return)(!!value);
1327 override void accept(Visitor v)
1329 v.visit(this);
1333 /***********************************************************
1334 * An identifier in the context of an expression (as opposed to a declaration)
1336 * ---
1337 * int x; // VarDeclaration with Identifier
1338 * x++; // PostExp with IdentifierExp
1339 * ---
1341 extern (C++) class IdentifierExp : Expression
1343 Identifier ident;
1344 bool parens; // if it appears as (identifier)
1346 extern (D) this(const ref Loc loc, Identifier ident) scope @safe
1348 super(loc, EXP.identifier);
1349 this.ident = ident;
1352 static IdentifierExp create(const ref Loc loc, Identifier ident) @safe
1354 return new IdentifierExp(loc, ident);
1357 override final bool isLvalue()
1359 return true;
1362 override void accept(Visitor v)
1364 v.visit(this);
1368 /***********************************************************
1369 * The dollar operator used when indexing or slicing an array. E.g `a[$]`, `a[1 .. $]` etc.
1371 * https://dlang.org/spec/arrays.html#array-length
1373 extern (C++) final class DollarExp : IdentifierExp
1375 extern (D) this(const ref Loc loc)
1377 super(loc, Id.dollar);
1380 override void accept(Visitor v)
1382 v.visit(this);
1386 /***********************************************************
1387 * Won't be generated by parser.
1389 extern (C++) final class DsymbolExp : Expression
1391 Dsymbol s;
1392 bool hasOverloads;
1394 extern (D) this(const ref Loc loc, Dsymbol s, bool hasOverloads = true) @safe
1396 super(loc, EXP.dSymbol);
1397 this.s = s;
1398 this.hasOverloads = hasOverloads;
1401 override bool isLvalue()
1403 return true;
1406 override void accept(Visitor v)
1408 v.visit(this);
1412 /***********************************************************
1413 * https://dlang.org/spec/expression.html#this
1415 extern (C++) class ThisExp : Expression
1417 VarDeclaration var;
1419 extern (D) this(const ref Loc loc) @safe
1421 super(loc, EXP.this_);
1422 //printf("ThisExp::ThisExp() loc = %d\n", loc.linnum);
1425 this(const ref Loc loc, const EXP tok) @safe
1427 super(loc, tok);
1428 //printf("ThisExp::ThisExp() loc = %d\n", loc.linnum);
1431 override ThisExp syntaxCopy()
1433 auto r = cast(ThisExp) super.syntaxCopy();
1434 // require new semantic (possibly new `var` etc.)
1435 r.type = null;
1436 r.var = null;
1437 return r;
1440 override Optional!bool toBool()
1442 // `this` is never null (what about structs?)
1443 return typeof(return)(true);
1446 override final bool isLvalue()
1448 // Class `this` should be an rvalue; struct `this` should be an lvalue.
1449 return type.toBasetype().ty != Tclass;
1452 override void accept(Visitor v)
1454 v.visit(this);
1458 /***********************************************************
1459 * https://dlang.org/spec/expression.html#super
1461 extern (C++) final class SuperExp : ThisExp
1463 extern (D) this(const ref Loc loc) @safe
1465 super(loc, EXP.super_);
1468 override void accept(Visitor v)
1470 v.visit(this);
1474 /***********************************************************
1475 * A compile-time known `null` value
1477 * https://dlang.org/spec/expression.html#null
1479 extern (C++) final class NullExp : Expression
1481 extern (D) this(const ref Loc loc, Type type = null) scope @safe
1483 super(loc, EXP.null_);
1484 this.type = type;
1487 override bool equals(const RootObject o) const
1489 if (auto e = o.isExpression())
1491 if (e.op == EXP.null_ && type.equals(e.type))
1493 return true;
1496 return false;
1499 override Optional!bool toBool()
1501 // null in any type is false
1502 return typeof(return)(false);
1505 override StringExp toStringExp()
1507 if (this.type.implicitConvTo(Type.tstring))
1509 auto se = new StringExp(loc, (cast(char*)mem.xcalloc(1, 1))[0 .. 0]);
1510 se.type = Type.tstring;
1511 return se;
1514 return null;
1517 override void accept(Visitor v)
1519 v.visit(this);
1523 /***********************************************************
1524 * https://dlang.org/spec/expression.html#string_literals
1526 extern (C++) final class StringExp : Expression
1528 char postfix = NoPostfix; // 'c', 'w', 'd'
1529 OwnedBy ownedByCtfe = OwnedBy.code;
1530 private union
1532 char* string; // if sz == 1
1533 wchar* wstring; // if sz == 2
1534 dchar* dstring; // if sz == 4
1535 } // (const if ownedByCtfe == OwnedBy.code)
1536 size_t len; // number of code units
1537 ubyte sz = 1; // 1: char, 2: wchar, 4: dchar
1540 * Whether the string literal's type is fixed
1541 * Example:
1542 * ---
1543 * wstring x = "abc"; // OK, string literal is flexible
1544 * wstring y = cast(string) "abc"; // Error: type was committed after cast
1545 * ---
1547 bool committed;
1549 /// If the string is parsed from a hex string literal
1550 bool hexString = false;
1552 enum char NoPostfix = 0;
1554 extern (D) this(const ref Loc loc, const(void)[] string) scope
1556 super(loc, EXP.string_);
1557 this.string = cast(char*)string.ptr; // note that this.string should be const
1558 this.len = string.length;
1559 this.sz = 1; // work around LDC bug #1286
1562 extern (D) this(const ref Loc loc, const(void)[] string, size_t len, ubyte sz, char postfix = NoPostfix) scope
1564 super(loc, EXP.string_);
1565 this.string = cast(char*)string.ptr; // note that this.string should be const
1566 this.len = len;
1567 this.sz = sz;
1568 this.postfix = postfix;
1571 static StringExp create(const ref Loc loc, const(char)* s)
1573 return new StringExp(loc, s.toDString());
1576 static StringExp create(const ref Loc loc, const(void)* string, size_t len)
1578 return new StringExp(loc, string[0 .. len]);
1581 override bool equals(const RootObject o) const
1583 //printf("StringExp::equals('%s') %s\n", o.toChars(), toChars());
1584 if (auto e = o.isExpression())
1586 if (auto se = e.isStringExp())
1588 return compare(se) == 0;
1591 return false;
1594 /**********************************
1595 * Return the number of code units the string would be if it were re-encoded
1596 * as tynto.
1597 * Params:
1598 * tynto = code unit type of the target encoding
1599 * Returns:
1600 * number of code units
1602 size_t numberOfCodeUnits(int tynto = 0) const
1604 int encSize;
1605 switch (tynto)
1607 case 0: return len;
1608 case Tchar: encSize = 1; break;
1609 case Twchar: encSize = 2; break;
1610 case Tdchar: encSize = 4; break;
1611 default:
1612 assert(0);
1614 if (sz == encSize)
1615 return len;
1617 size_t result = 0;
1618 dchar c;
1620 switch (sz)
1622 case 1:
1623 for (size_t u = 0; u < len;)
1625 if (const s = utf_decodeChar(string[0 .. len], u, c))
1627 error(loc, "%.*s", cast(int)s.length, s.ptr);
1628 return 0;
1630 result += utf_codeLength(encSize, c);
1632 break;
1634 case 2:
1635 for (size_t u = 0; u < len;)
1637 if (const s = utf_decodeWchar(wstring[0 .. len], u, c))
1639 error(loc, "%.*s", cast(int)s.length, s.ptr);
1640 return 0;
1642 result += utf_codeLength(encSize, c);
1644 break;
1646 case 4:
1647 foreach (u; 0 .. len)
1649 result += utf_codeLength(encSize, dstring[u]);
1651 break;
1653 default:
1654 assert(0);
1656 return result;
1659 /**********************************************
1660 * Write the contents of the string to dest.
1661 * Use numberOfCodeUnits() to determine size of result.
1662 * Params:
1663 * dest = destination
1664 * tyto = encoding type of the result
1665 * zero = add terminating 0
1667 void writeTo(void* dest, bool zero, int tyto = 0) const
1669 int encSize;
1670 switch (tyto)
1672 case 0: encSize = sz; break;
1673 case Tchar: encSize = 1; break;
1674 case Twchar: encSize = 2; break;
1675 case Tdchar: encSize = 4; break;
1676 default:
1677 assert(0);
1679 if (sz == encSize)
1681 memcpy(dest, string, len * sz);
1682 if (zero)
1683 memset(dest + len * sz, 0, sz);
1685 else
1686 assert(0);
1689 /*********************************************
1690 * Get the code unit at index i
1691 * Params:
1692 * i = index
1693 * Returns:
1694 * code unit at index i
1696 dchar getCodeUnit(size_t i) const pure
1698 assert(i < len);
1699 final switch (sz)
1701 case 1:
1702 return string[i];
1703 case 2:
1704 return wstring[i];
1705 case 4:
1706 return dstring[i];
1710 /*********************************************
1711 * Set the code unit at index i to c
1712 * Params:
1713 * i = index
1714 * c = code unit to set it to
1716 extern (D) void setCodeUnit(size_t i, dchar c)
1718 assert(i < len);
1719 final switch (sz)
1721 case 1:
1722 string[i] = cast(char)c;
1723 break;
1724 case 2:
1725 wstring[i] = cast(wchar)c;
1726 break;
1727 case 4:
1728 dstring[i] = c;
1729 break;
1733 override StringExp toStringExp()
1735 return this;
1740 * Compare two `StringExp` by length, then value
1742 * The comparison is not the usual C-style comparison as seen with
1743 * `strcmp` or `memcmp`, but instead first compare based on the length.
1744 * This allows both faster lookup and sorting when comparing sparse data.
1746 * This ordering scheme is relied on by the string-switching feature.
1747 * Code in Druntime's `core.internal.switch_` relies on this ordering
1748 * when doing a binary search among case statements.
1750 * Both `StringExp` should be of the same encoding.
1752 * Params:
1753 * se2 = String expression to compare `this` to
1755 * Returns:
1756 * `0` when `this` is equal to se2, a value greater than `0` if
1757 * `this` should be considered greater than `se2`,
1758 * and a value less than `0` if `this` is lesser than `se2`.
1760 int compare(const StringExp se2) const nothrow pure @nogc
1762 //printf("StringExp::compare()\n");
1763 const len1 = len;
1764 const len2 = se2.len;
1766 assert(this.sz == se2.sz, "Comparing string expressions of different sizes");
1767 //printf("sz = %d, len1 = %d, len2 = %d\n", sz, cast(int)len1, cast(int)len2);
1768 if (len1 == len2)
1770 switch (sz)
1772 case 1:
1773 return memcmp(string, se2.string, len1);
1775 case 2:
1777 wchar* s1 = cast(wchar*)string;
1778 wchar* s2 = cast(wchar*)se2.string;
1779 foreach (u; 0 .. len)
1781 if (s1[u] != s2[u])
1782 return s1[u] - s2[u];
1785 break;
1786 case 4:
1788 dchar* s1 = cast(dchar*)string;
1789 dchar* s2 = cast(dchar*)se2.string;
1790 foreach (u; 0 .. len)
1792 if (s1[u] != s2[u])
1793 return s1[u] - s2[u];
1796 break;
1797 default:
1798 assert(0);
1801 return cast(int)(len1 - len2);
1804 override Optional!bool toBool()
1806 // Keep the old behaviour for this refactoring
1807 // Should probably match language spec instead and check for length
1808 return typeof(return)(true);
1811 override bool isLvalue()
1813 /* string literal is rvalue in default, but
1814 * conversion to reference of static array is only allowed.
1816 return (type && type.toBasetype().ty == Tsarray);
1819 /********************************
1820 * Convert string contents to a 0 terminated string,
1821 * allocated by mem.xmalloc().
1823 extern (D) const(char)[] toStringz() const
1825 auto nbytes = len * sz;
1826 char* s = cast(char*)mem.xmalloc(nbytes + sz);
1827 writeTo(s, true);
1828 return s[0 .. nbytes];
1831 extern (D) const(char)[] peekString() const
1833 assert(sz == 1);
1834 return this.string[0 .. len];
1837 extern (D) const(wchar)[] peekWstring() const
1839 assert(sz == 2);
1840 return this.wstring[0 .. len];
1843 extern (D) const(dchar)[] peekDstring() const
1845 assert(sz == 4);
1846 return this.dstring[0 .. len];
1849 /*******************
1850 * Get a slice of the data.
1852 extern (D) const(ubyte)[] peekData() const
1854 return cast(const(ubyte)[])this.string[0 .. len * sz];
1857 /*******************
1858 * Borrow a slice of the data, so the caller can modify
1859 * it in-place (!)
1861 extern (D) ubyte[] borrowData()
1863 return cast(ubyte[])this.string[0 .. len * sz];
1866 /***********************
1867 * Set new string data.
1868 * `this` becomes the new owner of the data.
1870 extern (D) void setData(void* s, size_t len, ubyte sz)
1872 this.string = cast(char*)s;
1873 this.len = len;
1874 this.sz = sz;
1877 override void accept(Visitor v)
1879 v.visit(this);
1883 /***********************************************************
1884 * A sequence of expressions
1886 * ---
1887 * alias AliasSeq(T...) = T;
1888 * alias Tup = AliasSeq!(3, int, "abc");
1889 * ---
1891 extern (C++) final class TupleExp : Expression
1893 /* Tuple-field access may need to take out its side effect part.
1894 * For example:
1895 * foo().tupleof
1896 * is rewritten as:
1897 * (ref __tup = foo(); tuple(__tup.field0, __tup.field1, ...))
1898 * The declaration of temporary variable __tup will be stored in TupleExp.e0.
1900 Expression e0;
1902 Expressions* exps;
1904 extern (D) this(const ref Loc loc, Expression e0, Expressions* exps) @safe
1906 super(loc, EXP.tuple);
1907 //printf("TupleExp(this = %p)\n", this);
1908 this.e0 = e0;
1909 this.exps = exps;
1912 extern (D) this(const ref Loc loc, Expressions* exps) @safe
1914 super(loc, EXP.tuple);
1915 //printf("TupleExp(this = %p)\n", this);
1916 this.exps = exps;
1919 extern (D) this(const ref Loc loc, TupleDeclaration tup)
1921 super(loc, EXP.tuple);
1922 this.exps = new Expressions();
1924 this.exps.reserve(tup.objects.length);
1925 foreach (o; *tup.objects)
1927 if (Dsymbol s = getDsymbol(o))
1929 /* If tuple element represents a symbol, translate to DsymbolExp
1930 * to supply implicit 'this' if needed later.
1932 Expression e = new DsymbolExp(loc, s);
1933 this.exps.push(e);
1935 else if (auto eo = o.isExpression())
1937 auto e = eo.copy();
1938 e.loc = loc; // https://issues.dlang.org/show_bug.cgi?id=15669
1939 this.exps.push(e);
1941 else if (auto t = o.isType())
1943 Expression e = new TypeExp(loc, t);
1944 this.exps.push(e);
1946 else
1948 error(loc, "`%s` is not an expression", o.toChars());
1953 static TupleExp create(const ref Loc loc, Expressions* exps) @safe
1955 return new TupleExp(loc, exps);
1958 override TupleExp syntaxCopy()
1960 return new TupleExp(loc, e0 ? e0.syntaxCopy() : null, arraySyntaxCopy(exps));
1963 override bool equals(const RootObject o) const
1965 if (this == o)
1966 return true;
1967 if (auto e = o.isExpression())
1968 if (auto te = e.isTupleExp())
1970 if (exps.length != te.exps.length)
1971 return false;
1972 if (e0 && !e0.equals(te.e0) || !e0 && te.e0)
1973 return false;
1974 foreach (i, e1; *exps)
1976 auto e2 = (*te.exps)[i];
1977 if (!e1.equals(e2))
1978 return false;
1980 return true;
1982 return false;
1985 override void accept(Visitor v)
1987 v.visit(this);
1991 /***********************************************************
1992 * [ e1, e2, e3, ... ]
1994 * https://dlang.org/spec/expression.html#array_literals
1996 extern (C++) final class ArrayLiteralExp : Expression
1998 OwnedBy ownedByCtfe = OwnedBy.code;
1999 bool onstack = false;
2001 /** If !is null, elements[] can be sparse and basis is used for the
2002 * "default" element value. In other words, non-null elements[i] overrides
2003 * this 'basis' value.
2005 Expression basis;
2007 Expressions* elements;
2009 extern (D) this(const ref Loc loc, Type type, Expressions* elements) @safe
2011 super(loc, EXP.arrayLiteral);
2012 this.type = type;
2013 this.elements = elements;
2016 extern (D) this(const ref Loc loc, Type type, Expression e)
2018 super(loc, EXP.arrayLiteral);
2019 this.type = type;
2020 elements = new Expressions();
2021 elements.push(e);
2024 extern (D) this(const ref Loc loc, Type type, Expression basis, Expressions* elements) @safe
2026 super(loc, EXP.arrayLiteral);
2027 this.type = type;
2028 this.basis = basis;
2029 this.elements = elements;
2032 static ArrayLiteralExp create(const ref Loc loc, Expressions* elements) @safe
2034 return new ArrayLiteralExp(loc, null, elements);
2037 override ArrayLiteralExp syntaxCopy()
2039 return new ArrayLiteralExp(loc,
2040 null,
2041 basis ? basis.syntaxCopy() : null,
2042 arraySyntaxCopy(elements));
2045 override bool equals(const RootObject o) const
2047 if (this == o)
2048 return true;
2049 auto e = o.isExpression();
2050 if (!e)
2051 return false;
2052 if (auto ae = e.isArrayLiteralExp())
2054 if (elements.length != ae.elements.length)
2055 return false;
2056 if (elements.length == 0 && !type.equals(ae.type))
2058 return false;
2061 foreach (i, e1; *elements)
2063 auto e2 = (*ae.elements)[i];
2064 auto e1x = e1 ? e1 : basis;
2065 auto e2x = e2 ? e2 : ae.basis;
2067 if (e1x != e2x && (!e1x || !e2x || !e1x.equals(e2x)))
2068 return false;
2070 return true;
2072 return false;
2075 Expression getElement(size_t i) // use opIndex instead
2077 return this[i];
2080 extern (D) Expression opIndex(size_t i)
2082 auto el = (*elements)[i];
2083 return el ? el : basis;
2086 override Optional!bool toBool()
2088 size_t dim = elements ? elements.length : 0;
2089 return typeof(return)(dim != 0);
2092 override StringExp toStringExp()
2094 TY telem = type.nextOf().toBasetype().ty;
2095 if (telem.isSomeChar || (telem == Tvoid && (!elements || elements.length == 0)))
2097 ubyte sz = 1;
2098 if (telem == Twchar)
2099 sz = 2;
2100 else if (telem == Tdchar)
2101 sz = 4;
2103 OutBuffer buf;
2104 if (elements)
2106 foreach (i; 0 .. elements.length)
2108 auto ch = this[i];
2109 if (ch.op != EXP.int64)
2110 return null;
2111 if (sz == 1)
2112 buf.writeByte(cast(uint)ch.toInteger());
2113 else if (sz == 2)
2114 buf.writeword(cast(uint)ch.toInteger());
2115 else
2116 buf.write4(cast(uint)ch.toInteger());
2119 char prefix;
2120 if (sz == 1)
2122 prefix = 'c';
2123 buf.writeByte(0);
2125 else if (sz == 2)
2127 prefix = 'w';
2128 buf.writeword(0);
2130 else
2132 prefix = 'd';
2133 buf.write4(0);
2136 const size_t len = buf.length / sz - 1;
2137 auto se = new StringExp(loc, buf.extractSlice()[0 .. len * sz], len, sz, prefix);
2138 se.sz = sz;
2139 se.type = type;
2140 return se;
2142 return null;
2145 override void accept(Visitor v)
2147 v.visit(this);
2151 /***********************************************************
2152 * [ key0 : value0, key1 : value1, ... ]
2154 * https://dlang.org/spec/expression.html#associative_array_literals
2156 extern (C++) final class AssocArrayLiteralExp : Expression
2158 OwnedBy ownedByCtfe = OwnedBy.code;
2160 Expressions* keys;
2161 Expressions* values;
2162 /// Lower to core.internal.newaa for static initializaton
2163 Expression lowering;
2165 extern (D) this(const ref Loc loc, Expressions* keys, Expressions* values) @safe
2167 super(loc, EXP.assocArrayLiteral);
2168 assert(keys.length == values.length);
2169 this.keys = keys;
2170 this.values = values;
2173 override bool equals(const RootObject o) const
2175 if (this == o)
2176 return true;
2177 auto e = o.isExpression();
2178 if (!e)
2179 return false;
2180 if (auto ae = e.isAssocArrayLiteralExp())
2182 if (keys.length != ae.keys.length)
2183 return false;
2184 size_t count = 0;
2185 foreach (i, key; *keys)
2187 foreach (j, akey; *ae.keys)
2189 if (key.equals(akey))
2191 if (!(*values)[i].equals((*ae.values)[j]))
2192 return false;
2193 ++count;
2197 return count == keys.length;
2199 return false;
2202 override AssocArrayLiteralExp syntaxCopy()
2204 return new AssocArrayLiteralExp(loc, arraySyntaxCopy(keys), arraySyntaxCopy(values));
2207 override Optional!bool toBool()
2209 size_t dim = keys.length;
2210 return typeof(return)(dim != 0);
2213 override void accept(Visitor v)
2215 v.visit(this);
2219 enum stageScrub = 0x1; /// scrubReturnValue is running
2220 enum stageSearchPointers = 0x2; /// hasNonConstPointers is running
2221 enum stageOptimize = 0x4; /// optimize is running
2222 enum stageApply = 0x8; /// apply is running
2223 enum stageInlineScan = 0x10; /// inlineScan is running
2224 enum stageToCBuffer = 0x20; /// toCBuffer is running
2226 /***********************************************************
2227 * sd( e1, e2, e3, ... )
2229 extern (C++) final class StructLiteralExp : Expression
2231 StructDeclaration sd; /// which aggregate this is for
2232 Expressions* elements; /// parallels sd.fields[] with null entries for fields to skip
2233 Type stype; /// final type of result (can be different from sd's type)
2235 // `inlineCopy` is only used temporarily in the `inline.d` pass,
2236 // while `sym` is only used in `e2ir/s2ir/tocsym` which comes after
2237 union
2239 void* sym; /// back end symbol to initialize with literal (used as a Symbol*)
2241 /// those fields need to prevent a infinite recursion when one field of struct initialized with 'this' pointer.
2242 StructLiteralExp inlinecopy;
2245 /** pointer to the origin instance of the expression.
2246 * once a new expression is created, origin is set to 'this'.
2247 * anytime when an expression copy is created, 'origin' pointer is set to
2248 * 'origin' pointer value of the original expression.
2250 StructLiteralExp origin;
2253 /** anytime when recursive function is calling, 'stageflags' marks with bit flag of
2254 * current stage and unmarks before return from this function.
2255 * 'inlinecopy' uses similar 'stageflags' and from multiple evaluation 'doInline'
2256 * (with infinite recursion) of this expression.
2258 ubyte stageflags;
2260 bool useStaticInit; /// if this is true, use the StructDeclaration's init symbol
2261 bool isOriginal = false; /// used when moving instances to indicate `this is this.origin`
2262 OwnedBy ownedByCtfe = OwnedBy.code;
2264 extern (D) this(const ref Loc loc, StructDeclaration sd, Expressions* elements, Type stype = null) @safe
2266 super(loc, EXP.structLiteral);
2267 this.sd = sd;
2268 if (!elements)
2269 elements = new Expressions();
2270 this.elements = elements;
2271 this.stype = stype;
2272 this.origin = this;
2273 //printf("StructLiteralExp::StructLiteralExp(%s)\n", toChars());
2276 static StructLiteralExp create(const ref Loc loc, StructDeclaration sd, void* elements, Type stype = null)
2278 return new StructLiteralExp(loc, sd, cast(Expressions*)elements, stype);
2281 override bool equals(const RootObject o) const
2283 if (this == o)
2284 return true;
2285 auto e = o.isExpression();
2286 if (!e)
2287 return false;
2288 if (auto se = e.isStructLiteralExp())
2290 if (!type.equals(se.type))
2291 return false;
2292 if (elements.length != se.elements.length)
2293 return false;
2294 foreach (i, e1; *elements)
2296 auto e2 = (*se.elements)[i];
2297 if (e1 != e2 && (!e1 || !e2 || !e1.equals(e2)))
2298 return false;
2300 return true;
2302 return false;
2305 override StructLiteralExp syntaxCopy()
2307 auto exp = new StructLiteralExp(loc, sd, arraySyntaxCopy(elements), type ? type : stype);
2308 exp.origin = this;
2309 return exp;
2312 /**************************************
2313 * Gets expression at offset of type.
2314 * Returns NULL if not found.
2316 extern (D) Expression getField(Type type, uint offset)
2318 //printf("StructLiteralExp::getField(this = %s, type = %s, offset = %u)\n",
2319 // /*toChars()*/"", type.toChars(), offset);
2320 Expression e = null;
2321 int i = getFieldIndex(type, offset);
2323 if (i != -1)
2325 //printf("\ti = %d\n", i);
2326 if (i >= sd.nonHiddenFields())
2327 return null;
2329 assert(i < elements.length);
2330 e = (*elements)[i];
2331 if (e)
2333 //printf("e = %s, e.type = %s\n", e.toChars(), e.type.toChars());
2335 /* If type is a static array, and e is an initializer for that array,
2336 * then the field initializer should be an array literal of e.
2338 auto tsa = type.isTypeSArray();
2339 if (tsa && e.type.castMod(0) != type.castMod(0))
2341 const length = cast(size_t)tsa.dim.toInteger();
2342 auto z = new Expressions(length);
2343 foreach (ref q; *z)
2344 q = e.copy();
2345 e = new ArrayLiteralExp(loc, type, z);
2347 else
2349 e = e.copy();
2350 e.type = type;
2352 if (useStaticInit && e.type.needsNested())
2353 if (auto se = e.isStructLiteralExp())
2355 se.useStaticInit = true;
2359 return e;
2362 /************************************
2363 * Get index of field.
2364 * Returns -1 if not found.
2366 extern (D) int getFieldIndex(Type type, uint offset)
2368 /* Find which field offset is by looking at the field offsets
2370 if (elements.length)
2372 const sz = type.size();
2373 if (sz == SIZE_INVALID)
2374 return -1;
2375 foreach (i, v; sd.fields)
2377 if (offset == v.offset && sz == v.type.size())
2379 /* context fields might not be filled. */
2380 if (i >= sd.nonHiddenFields())
2381 return cast(int)i;
2382 if (auto e = (*elements)[i])
2384 return cast(int)i;
2386 break;
2390 return -1;
2393 override void accept(Visitor v)
2395 v.visit(this);
2399 /***********************************************************
2400 * C11 6.5.2.5
2401 * ( type-name ) { initializer-list }
2403 extern (C++) final class CompoundLiteralExp : Expression
2405 Initializer initializer; /// initializer-list
2407 extern (D) this(const ref Loc loc, Type type_name, Initializer initializer) @safe
2409 super(loc, EXP.compoundLiteral);
2410 super.type = type_name;
2411 this.initializer = initializer;
2412 //printf("CompoundLiteralExp::CompoundLiteralExp(%s)\n", toChars());
2415 override void accept(Visitor v)
2417 v.visit(this);
2421 /***********************************************************
2422 * Mainly just a placeholder
2424 extern (C++) final class TypeExp : Expression
2426 bool parens; // if this is a parenthesized expression
2428 extern (D) this(const ref Loc loc, Type type) @safe
2430 super(loc, EXP.type);
2431 //printf("TypeExp::TypeExp(%s)\n", type.toChars());
2432 this.type = type;
2435 override TypeExp syntaxCopy()
2437 return new TypeExp(loc, type.syntaxCopy());
2440 override bool checkType()
2442 error(loc, "type `%s` is not an expression", toChars());
2443 return true;
2446 override bool checkValue()
2448 error(loc, "type `%s` has no value", toChars());
2449 return true;
2452 override void accept(Visitor v)
2454 v.visit(this);
2458 /***********************************************************
2459 * Mainly just a placeholder of
2460 * Package, Module, Nspace, and TemplateInstance (including TemplateMixin)
2462 * A template instance that requires IFTI:
2463 * foo!tiargs(fargs) // foo!tiargs
2464 * is left until CallExp::semantic() or resolveProperties()
2466 extern (C++) final class ScopeExp : Expression
2468 ScopeDsymbol sds;
2470 extern (D) this(const ref Loc loc, ScopeDsymbol sds) @safe
2472 super(loc, EXP.scope_);
2473 //printf("ScopeExp::ScopeExp(sds = '%s')\n", sds.toChars());
2474 //static int count; if (++count == 38) *(char*)0=0;
2475 this.sds = sds;
2476 assert(!sds.isTemplateDeclaration()); // instead, you should use TemplateExp
2479 override ScopeExp syntaxCopy()
2481 return new ScopeExp(loc, sds.syntaxCopy(null));
2484 override bool checkType()
2486 if (sds.isPackage())
2488 error(loc, "%s `%s` has no type", sds.kind(), sds.toChars());
2489 return true;
2491 if (auto ti = sds.isTemplateInstance())
2493 //assert(ti.needsTypeInference(sc));
2494 if (ti.tempdecl &&
2495 ti.semantictiargsdone &&
2496 ti.semanticRun == PASS.initial)
2498 error(loc, "partial %s `%s` has no type", sds.kind(), toChars());
2499 return true;
2502 return false;
2505 override bool checkValue()
2507 error(loc, "%s `%s` has no value", sds.kind(), sds.toChars());
2508 return true;
2511 override void accept(Visitor v)
2513 v.visit(this);
2517 /***********************************************************
2518 * Mainly just a placeholder
2520 extern (C++) final class TemplateExp : Expression
2522 TemplateDeclaration td;
2523 FuncDeclaration fd;
2525 extern (D) this(const ref Loc loc, TemplateDeclaration td, FuncDeclaration fd = null) @safe
2527 super(loc, EXP.template_);
2528 //printf("TemplateExp(): %s\n", td.toChars());
2529 this.td = td;
2530 this.fd = fd;
2533 override bool isLvalue()
2535 return fd !is null;
2538 override bool checkType()
2540 error(loc, "%s `%s` has no type", td.kind(), toChars());
2541 return true;
2544 override bool checkValue()
2546 error(loc, "%s `%s` has no value", td.kind(), toChars());
2547 return true;
2550 override void accept(Visitor v)
2552 v.visit(this);
2556 /***********************************************************
2557 * newtype(arguments)
2559 extern (C++) final class NewExp : Expression
2561 Expression thisexp; // if !=null, 'this' for class being allocated
2562 Type newtype;
2563 Expressions* arguments; // Array of Expression's
2564 Identifiers* names; // Array of names corresponding to expressions
2566 Expression argprefix; // expression to be evaluated just before arguments[]
2567 CtorDeclaration member; // constructor function
2568 bool onstack; // allocate on stack
2569 bool thrownew; // this NewExp is the expression of a ThrowStatement
2571 Expression lowering; // lowered druntime hook: `_d_new{class,itemT}`
2573 /// Puts the `arguments` and `names` into an `ArgumentList` for easily passing them around.
2574 /// The fields are still separate for backwards compatibility
2575 extern (D) ArgumentList argumentList() { return ArgumentList(arguments, names); }
2577 extern (D) this(const ref Loc loc, Expression thisexp, Type newtype, Expressions* arguments, Identifiers* names = null) @safe
2579 super(loc, EXP.new_);
2580 this.thisexp = thisexp;
2581 this.newtype = newtype;
2582 this.arguments = arguments;
2583 this.names = names;
2586 static NewExp create(const ref Loc loc, Expression thisexp, Type newtype, Expressions* arguments) @safe
2588 return new NewExp(loc, thisexp, newtype, arguments);
2591 override NewExp syntaxCopy()
2593 return new NewExp(loc,
2594 thisexp ? thisexp.syntaxCopy() : null,
2595 newtype.syntaxCopy(),
2596 arraySyntaxCopy(arguments),
2597 names ? names.copy() : null);
2600 override void accept(Visitor v)
2602 v.visit(this);
2606 /***********************************************************
2607 * class baseclasses { } (arguments)
2609 extern (C++) final class NewAnonClassExp : Expression
2611 Expression thisexp; // if !=null, 'this' for class being allocated
2612 ClassDeclaration cd; // class being instantiated
2613 Expressions* arguments; // Array of Expression's to call class constructor
2615 extern (D) this(const ref Loc loc, Expression thisexp, ClassDeclaration cd, Expressions* arguments) @safe
2617 super(loc, EXP.newAnonymousClass);
2618 this.thisexp = thisexp;
2619 this.cd = cd;
2620 this.arguments = arguments;
2623 override NewAnonClassExp syntaxCopy()
2625 return new NewAnonClassExp(loc, thisexp ? thisexp.syntaxCopy() : null, cd.syntaxCopy(null), arraySyntaxCopy(arguments));
2628 override void accept(Visitor v)
2630 v.visit(this);
2634 /***********************************************************
2636 extern (C++) class SymbolExp : Expression
2638 Declaration var;
2639 Dsymbol originalScope; // original scope before inlining
2640 bool hasOverloads;
2642 extern (D) this(const ref Loc loc, EXP op, Declaration var, bool hasOverloads) @safe
2644 super(loc, op);
2645 assert(var);
2646 this.var = var;
2647 this.hasOverloads = hasOverloads;
2650 override void accept(Visitor v)
2652 v.visit(this);
2656 /***********************************************************
2657 * Offset from symbol
2659 extern (C++) final class SymOffExp : SymbolExp
2661 dinteger_t offset;
2663 extern (D) this(const ref Loc loc, Declaration var, dinteger_t offset, bool hasOverloads = true)
2665 if (auto v = var.isVarDeclaration())
2667 // FIXME: This error report will never be handled anyone.
2668 // It should be done before the SymOffExp construction.
2669 if (v.needThis())
2671 auto t = v.isThis();
2672 assert(t);
2673 .error(loc, "taking the address of non-static variable `%s` requires an instance of `%s`", v.toChars(), t.toChars());
2675 hasOverloads = false;
2677 super(loc, EXP.symbolOffset, var, hasOverloads);
2678 this.offset = offset;
2681 override Optional!bool toBool()
2683 return typeof(return)(true);
2686 override void accept(Visitor v)
2688 v.visit(this);
2692 /***********************************************************
2693 * Variable
2695 extern (C++) final class VarExp : SymbolExp
2697 bool delegateWasExtracted;
2698 extern (D) this(const ref Loc loc, Declaration var, bool hasOverloads = true) @safe
2700 if (var.isVarDeclaration())
2701 hasOverloads = false;
2703 super(loc, EXP.variable, var, hasOverloads);
2704 //printf("VarExp(this = %p, '%s', loc = %s)\n", this, var.toChars(), loc.toChars());
2705 //if (strcmp(var.ident.toChars(), "func") == 0) assert(0);
2706 this.type = var.type;
2709 static VarExp create(const ref Loc loc, Declaration var, bool hasOverloads = true) @safe
2711 return new VarExp(loc, var, hasOverloads);
2714 override bool equals(const RootObject o) const
2716 if (this == o)
2717 return true;
2718 if (auto ne = o.isExpression().isVarExp())
2720 if (type.toHeadMutable().equals(ne.type.toHeadMutable()) && var == ne.var)
2722 return true;
2725 return false;
2728 override bool isLvalue()
2730 if (var.storage_class & (STC.lazy_ | STC.rvalue | STC.manifest))
2731 return false;
2732 return true;
2735 override void accept(Visitor v)
2737 v.visit(this);
2741 /***********************************************************
2742 * Overload Set
2744 extern (C++) final class OverExp : Expression
2746 OverloadSet vars;
2748 extern (D) this(const ref Loc loc, OverloadSet s)
2750 super(loc, EXP.overloadSet);
2751 //printf("OverExp(this = %p, '%s')\n", this, var.toChars());
2752 vars = s;
2753 type = Type.tvoid;
2756 override bool isLvalue()
2758 return true;
2761 override void accept(Visitor v)
2763 v.visit(this);
2767 /***********************************************************
2768 * Function/Delegate literal
2771 extern (C++) final class FuncExp : Expression
2773 FuncLiteralDeclaration fd;
2774 TemplateDeclaration td;
2775 TOK tok; // TOK.reserved, TOK.delegate_, TOK.function_
2777 extern (D) this(const ref Loc loc, Dsymbol s)
2779 super(loc, EXP.function_);
2780 this.td = s.isTemplateDeclaration();
2781 this.fd = s.isFuncLiteralDeclaration();
2782 if (td)
2784 assert(td.literal);
2785 assert(td.members && td.members.length == 1);
2786 fd = (*td.members)[0].isFuncLiteralDeclaration();
2788 tok = fd.tok; // save original kind of function/delegate/(infer)
2789 assert(fd.fbody);
2792 override bool equals(const RootObject o) const
2794 if (this == o)
2795 return true;
2796 auto e = o.isExpression();
2797 if (!e)
2798 return false;
2799 if (auto fe = e.isFuncExp())
2801 return fd == fe.fd;
2803 return false;
2806 override FuncExp syntaxCopy()
2808 if (td)
2809 return new FuncExp(loc, td.syntaxCopy(null));
2810 else if (fd.semanticRun == PASS.initial)
2811 return new FuncExp(loc, fd.syntaxCopy(null));
2812 else // https://issues.dlang.org/show_bug.cgi?id=13481
2813 // Prevent multiple semantic analysis of lambda body.
2814 return new FuncExp(loc, fd);
2817 override const(char)* toChars() const
2819 return fd.toChars();
2822 override bool checkType()
2824 if (td)
2826 error(loc, "template lambda has no type");
2827 return true;
2829 return false;
2832 override bool checkValue()
2834 if (td)
2836 error(loc, "template lambda has no value");
2837 return true;
2839 return false;
2842 override void accept(Visitor v)
2844 v.visit(this);
2848 /***********************************************************
2849 * Declaration of a symbol
2851 * D grammar allows declarations only as statements. However in AST representation
2852 * it can be part of any expression. This is used, for example, during internal
2853 * syntax re-writes to inject hidden symbols.
2855 extern (C++) final class DeclarationExp : Expression
2857 Dsymbol declaration;
2859 extern (D) this(const ref Loc loc, Dsymbol declaration) @safe
2861 super(loc, EXP.declaration);
2862 this.declaration = declaration;
2865 override DeclarationExp syntaxCopy()
2867 return new DeclarationExp(loc, declaration.syntaxCopy(null));
2870 override bool hasCode()
2872 if (auto vd = declaration.isVarDeclaration())
2874 return !(vd.storage_class & (STC.manifest | STC.static_));
2876 return false;
2879 override void accept(Visitor v)
2881 v.visit(this);
2885 /***********************************************************
2886 * typeid(int)
2888 extern (C++) final class TypeidExp : Expression
2890 RootObject obj;
2892 extern (D) this(const ref Loc loc, RootObject o) @safe
2894 super(loc, EXP.typeid_);
2895 this.obj = o;
2898 override TypeidExp syntaxCopy()
2900 return new TypeidExp(loc, objectSyntaxCopy(obj));
2903 override void accept(Visitor v)
2905 v.visit(this);
2909 /***********************************************************
2910 * __traits(identifier, args...)
2912 extern (C++) final class TraitsExp : Expression
2914 Identifier ident;
2915 Objects* args;
2917 extern (D) this(const ref Loc loc, Identifier ident, Objects* args) @safe
2919 super(loc, EXP.traits);
2920 this.ident = ident;
2921 this.args = args;
2924 override TraitsExp syntaxCopy()
2926 return new TraitsExp(loc, ident, TemplateInstance.arraySyntaxCopy(args));
2929 override void accept(Visitor v)
2931 v.visit(this);
2935 /***********************************************************
2936 * Generates a halt instruction
2938 * `assert(0)` gets rewritten to this with `CHECKACTION.halt`
2940 extern (C++) final class HaltExp : Expression
2942 extern (D) this(const ref Loc loc) @safe
2944 super(loc, EXP.halt);
2947 override void accept(Visitor v)
2949 v.visit(this);
2953 /***********************************************************
2954 * is(targ id tok tspec)
2955 * is(targ id == tok2)
2957 extern (C++) final class IsExp : Expression
2959 Type targ;
2960 Identifier id; // can be null
2961 Type tspec; // can be null
2962 TemplateParameters* parameters;
2963 TOK tok; // ':' or '=='
2964 TOK tok2; // 'struct', 'union', etc.
2966 extern (D) this(const ref Loc loc, Type targ, Identifier id, TOK tok, Type tspec, TOK tok2, TemplateParameters* parameters) scope @safe
2968 super(loc, EXP.is_);
2969 this.targ = targ;
2970 this.id = id;
2971 this.tok = tok;
2972 this.tspec = tspec;
2973 this.tok2 = tok2;
2974 this.parameters = parameters;
2977 override IsExp syntaxCopy()
2979 // This section is identical to that in TemplateDeclaration::syntaxCopy()
2980 TemplateParameters* p = null;
2981 if (parameters)
2983 p = new TemplateParameters(parameters.length);
2984 foreach (i, el; *parameters)
2985 (*p)[i] = el.syntaxCopy();
2987 return new IsExp(loc, targ.syntaxCopy(), id, tok, tspec ? tspec.syntaxCopy() : null, tok2, p);
2990 override void accept(Visitor v)
2992 v.visit(this);
2996 /***********************************************************
2997 * Base class for unary operators
2999 * https://dlang.org/spec/expression.html#unary-expression
3001 extern (C++) abstract class UnaExp : Expression
3003 Expression e1;
3005 extern (D) this(const ref Loc loc, EXP op, Expression e1) scope @safe
3007 super(loc, op);
3008 this.e1 = e1;
3011 override UnaExp syntaxCopy()
3013 UnaExp e = cast(UnaExp)copy();
3014 e.type = null;
3015 e.e1 = e.e1.syntaxCopy();
3016 return e;
3019 /********************************
3020 * The type for a unary expression is incompatible.
3021 * Print error message.
3022 * Returns:
3023 * ErrorExp
3025 extern (D) final Expression incompatibleTypes()
3027 if (e1.type.toBasetype() == Type.terror)
3028 return e1;
3030 if (e1.op == EXP.type)
3032 error(loc, "incompatible type for `%s(%s)`: cannot use `%s` with types", EXPtoString(op).ptr, e1.toChars(), EXPtoString(op).ptr);
3034 else
3036 error(loc, "incompatible type for `%s(%s)`: `%s`", EXPtoString(op).ptr, e1.toChars(), e1.type.toChars());
3038 return ErrorExp.get();
3041 /*********************
3042 * Mark the operand as will never be dereferenced,
3043 * which is useful info for @safe checks.
3044 * Do before semantic() on operands rewrites them.
3046 final void setNoderefOperand()
3048 if (auto edi = e1.isDotIdExp())
3049 edi.noderef = true;
3053 override void accept(Visitor v)
3055 v.visit(this);
3059 /***********************************************************
3060 * Base class for binary operators
3062 extern (C++) abstract class BinExp : Expression
3064 Expression e1;
3065 Expression e2;
3066 Type att1; // Save alias this type to detect recursion
3067 Type att2; // Save alias this type to detect recursion
3069 extern (D) this(const ref Loc loc, EXP op, Expression e1, Expression e2) scope @safe
3071 super(loc, op);
3072 this.e1 = e1;
3073 this.e2 = e2;
3076 override BinExp syntaxCopy()
3078 BinExp e = cast(BinExp)copy();
3079 e.type = null;
3080 e.e1 = e.e1.syntaxCopy();
3081 e.e2 = e.e2.syntaxCopy();
3082 return e;
3085 /********************************
3086 * The types for a binary expression are incompatible.
3087 * Print error message.
3088 * Returns:
3089 * ErrorExp
3091 extern (D) final Expression incompatibleTypes()
3093 if (e1.type.toBasetype() == Type.terror)
3094 return e1;
3095 if (e2.type.toBasetype() == Type.terror)
3096 return e2;
3098 // CondExp uses 'a ? b : c' but we're comparing 'b : c'
3099 const(char)* thisOp = (op == EXP.question) ? ":" : EXPtoString(op).ptr;
3100 if (e1.op == EXP.type || e2.op == EXP.type)
3102 error(loc, "incompatible types for `(%s) %s (%s)`: cannot use `%s` with types",
3103 e1.toChars(), thisOp, e2.toChars(), EXPtoString(op).ptr);
3105 else if (e1.type.equals(e2.type))
3107 error(loc, "incompatible types for `(%s) %s (%s)`: both operands are of type `%s`",
3108 e1.toChars(), thisOp, e2.toChars(), e1.type.toChars());
3110 else
3112 auto ts = toAutoQualChars(e1.type, e2.type);
3113 error(loc, "incompatible types for `(%s) %s (%s)`: `%s` and `%s`",
3114 e1.toChars(), thisOp, e2.toChars(), ts[0], ts[1]);
3116 return ErrorExp.get();
3119 extern (D) final bool checkIntegralBin()
3121 bool r1 = e1.checkIntegral();
3122 bool r2 = e2.checkIntegral();
3123 return (r1 || r2);
3126 extern (D) final bool checkArithmeticBin()
3128 bool r1 = e1.checkArithmetic(this.op);
3129 bool r2 = e2.checkArithmetic(this.op);
3130 return (r1 || r2);
3133 /*********************
3134 * Mark the operands as will never be dereferenced,
3135 * which is useful info for @safe checks.
3136 * Do before semantic() on operands rewrites them.
3138 final void setNoderefOperands()
3140 if (auto edi = e1.isDotIdExp())
3141 edi.noderef = true;
3142 if (auto edi = e2.isDotIdExp())
3143 edi.noderef = true;
3147 override void accept(Visitor v)
3149 v.visit(this);
3153 /***********************************************************
3154 * Binary operator assignment, `+=` `-=` `*=` etc.
3156 extern (C++) class BinAssignExp : BinExp
3158 extern (D) this(const ref Loc loc, EXP op, Expression e1, Expression e2) scope @safe
3160 super(loc, op, e1, e2);
3163 override final bool isLvalue()
3165 return true;
3168 override void accept(Visitor v)
3170 v.visit(this);
3174 /***********************************************************
3175 * A string mixin, `mixin("x")`
3177 * https://dlang.org/spec/expression.html#mixin_expressions
3179 extern (C++) final class MixinExp : Expression
3181 Expressions* exps;
3183 extern (D) this(const ref Loc loc, Expressions* exps) @safe
3185 super(loc, EXP.mixin_);
3186 this.exps = exps;
3189 override MixinExp syntaxCopy()
3191 return new MixinExp(loc, arraySyntaxCopy(exps));
3194 override bool equals(const RootObject o) const
3196 if (this == o)
3197 return true;
3198 auto e = o.isExpression();
3199 if (!e)
3200 return false;
3201 if (auto ce = e.isMixinExp())
3203 if (exps.length != ce.exps.length)
3204 return false;
3205 foreach (i, e1; *exps)
3207 auto e2 = (*ce.exps)[i];
3208 if (e1 != e2 && (!e1 || !e2 || !e1.equals(e2)))
3209 return false;
3211 return true;
3213 return false;
3216 override void accept(Visitor v)
3218 v.visit(this);
3222 /***********************************************************
3223 * An import expression, `import("file.txt")`
3225 * Not to be confused with module imports, `import std.stdio`, which is an `ImportStatement`
3227 * https://dlang.org/spec/expression.html#import_expressions
3229 extern (C++) final class ImportExp : UnaExp
3231 extern (D) this(const ref Loc loc, Expression e) @safe
3233 super(loc, EXP.import_, e);
3236 override void accept(Visitor v)
3238 v.visit(this);
3242 /***********************************************************
3243 * An assert expression, `assert(x == y)`
3245 * https://dlang.org/spec/expression.html#assert_expressions
3247 extern (C++) final class AssertExp : UnaExp
3249 Expression msg;
3251 extern (D) this(const ref Loc loc, Expression e, Expression msg = null) @safe
3253 super(loc, EXP.assert_, e);
3254 this.msg = msg;
3257 override AssertExp syntaxCopy()
3259 return new AssertExp(loc, e1.syntaxCopy(), msg ? msg.syntaxCopy() : null);
3262 override void accept(Visitor v)
3264 v.visit(this);
3268 /***********************************************************
3269 * `throw <e1>` as proposed by DIP 1034.
3271 * Replacement for the deprecated `ThrowStatement` that can be nested
3272 * in other expression.
3274 extern (C++) final class ThrowExp : UnaExp
3276 extern (D) this(const ref Loc loc, Expression e)
3278 super(loc, EXP.throw_, e);
3279 this.type = Type.tnoreturn;
3282 override ThrowExp syntaxCopy()
3284 return new ThrowExp(loc, e1.syntaxCopy());
3287 override void accept(Visitor v)
3289 v.visit(this);
3293 /***********************************************************
3295 extern (C++) final class DotIdExp : UnaExp
3297 Identifier ident;
3298 bool noderef; // true if the result of the expression will never be dereferenced
3299 bool wantsym; // do not replace Symbol with its initializer during semantic()
3300 bool arrow; // ImportC: if -> instead of .
3302 extern (D) this(const ref Loc loc, Expression e, Identifier ident) @safe
3304 super(loc, EXP.dotIdentifier, e);
3305 this.ident = ident;
3308 static DotIdExp create(const ref Loc loc, Expression e, Identifier ident) @safe
3310 return new DotIdExp(loc, e, ident);
3313 override void accept(Visitor v)
3315 v.visit(this);
3319 /***********************************************************
3320 * Mainly just a placeholder
3322 extern (C++) final class DotTemplateExp : UnaExp
3324 TemplateDeclaration td;
3326 extern (D) this(const ref Loc loc, Expression e, TemplateDeclaration td) @safe
3328 super(loc, EXP.dotTemplateDeclaration, e);
3329 this.td = td;
3332 override bool checkType()
3334 error(loc, "%s `%s` has no type", td.kind(), toChars());
3335 return true;
3338 override bool checkValue()
3340 error(loc, "%s `%s` has no value", td.kind(), toChars());
3341 return true;
3344 override void accept(Visitor v)
3346 v.visit(this);
3350 /***********************************************************
3352 extern (C++) final class DotVarExp : UnaExp
3354 Declaration var;
3355 bool hasOverloads;
3357 extern (D) this(const ref Loc loc, Expression e, Declaration var, bool hasOverloads = true) @safe
3359 if (var.isVarDeclaration())
3360 hasOverloads = false;
3362 super(loc, EXP.dotVariable, e);
3363 //printf("DotVarExp()\n");
3364 this.var = var;
3365 this.hasOverloads = hasOverloads;
3368 override bool isLvalue()
3370 if (e1.op != EXP.structLiteral)
3371 return true;
3372 auto vd = var.isVarDeclaration();
3373 return !(vd && vd.isField());
3376 override void accept(Visitor v)
3378 v.visit(this);
3382 /***********************************************************
3383 * foo.bar!(args)
3385 extern (C++) final class DotTemplateInstanceExp : UnaExp
3387 TemplateInstance ti;
3389 extern (D) this(const ref Loc loc, Expression e, Identifier name, Objects* tiargs)
3391 super(loc, EXP.dotTemplateInstance, e);
3392 //printf("DotTemplateInstanceExp()\n");
3393 this.ti = new TemplateInstance(loc, name, tiargs);
3396 extern (D) this(const ref Loc loc, Expression e, TemplateInstance ti) @safe
3398 super(loc, EXP.dotTemplateInstance, e);
3399 this.ti = ti;
3402 override DotTemplateInstanceExp syntaxCopy()
3404 return new DotTemplateInstanceExp(loc, e1.syntaxCopy(), ti.name, TemplateInstance.arraySyntaxCopy(ti.tiargs));
3407 override bool checkType()
3409 // Same logic as ScopeExp.checkType()
3410 if (ti.tempdecl &&
3411 ti.semantictiargsdone &&
3412 ti.semanticRun == PASS.initial)
3414 error(loc, "partial %s `%s` has no type", ti.kind(), toChars());
3415 return true;
3417 return false;
3420 override bool checkValue()
3422 if (ti.tempdecl &&
3423 ti.semantictiargsdone &&
3424 ti.semanticRun == PASS.initial)
3426 error(loc, "partial %s `%s` has no value", ti.kind(), toChars());
3427 else
3428 error(loc, "%s `%s` has no value", ti.kind(), ti.toChars());
3429 return true;
3432 override void accept(Visitor v)
3434 v.visit(this);
3438 /***********************************************************
3440 extern (C++) final class DelegateExp : UnaExp
3442 FuncDeclaration func;
3443 bool hasOverloads;
3444 VarDeclaration vthis2; // container for multi-context
3446 extern (D) this(const ref Loc loc, Expression e, FuncDeclaration f, bool hasOverloads = true, VarDeclaration vthis2 = null) @safe
3448 super(loc, EXP.delegate_, e);
3449 this.func = f;
3450 this.hasOverloads = hasOverloads;
3451 this.vthis2 = vthis2;
3454 override void accept(Visitor v)
3456 v.visit(this);
3460 /***********************************************************
3462 extern (C++) final class DotTypeExp : UnaExp
3464 Dsymbol sym; // symbol that represents a type
3466 extern (D) this(const ref Loc loc, Expression e, Dsymbol s) @safe
3468 super(loc, EXP.dotType, e);
3469 this.sym = s;
3472 override void accept(Visitor v)
3474 v.visit(this);
3479 * The arguments of a function call
3481 * Contains a list of expressions. If it is a named argument, the `names`
3482 * list has a non-null entry at the same index.
3484 struct ArgumentList
3486 Expressions* arguments; // function arguments
3487 Identifiers* names; // named argument identifiers
3489 size_t length() const @nogc nothrow pure @safe { return arguments ? arguments.length : 0; }
3491 /// Returns: whether this argument list contains any named arguments
3492 bool hasNames() const @nogc nothrow pure @safe
3494 if (names is null)
3495 return false;
3496 foreach (name; *names)
3497 if (name !is null)
3498 return true;
3500 return false;
3504 /***********************************************************
3506 extern (C++) final class CallExp : UnaExp
3508 Expressions* arguments; // function arguments
3509 Identifiers* names; // named argument identifiers
3510 FuncDeclaration f; // symbol to call
3511 bool directcall; // true if a virtual call is devirtualized
3512 bool inDebugStatement; /// true if this was in a debug statement
3513 bool ignoreAttributes; /// don't enforce attributes (e.g. call @gc function in @nogc code)
3514 bool isUfcsRewrite; /// the first argument was pushed in here by a UFCS rewrite
3515 VarDeclaration vthis2; // container for multi-context
3517 /// Puts the `arguments` and `names` into an `ArgumentList` for easily passing them around.
3518 /// The fields are still separate for backwards compatibility
3519 extern (D) ArgumentList argumentList() { return ArgumentList(arguments, names); }
3521 extern (D) this(const ref Loc loc, Expression e, Expressions* exps, Identifiers* names = null) @safe
3523 super(loc, EXP.call, e);
3524 this.arguments = exps;
3525 this.names = names;
3528 extern (D) this(const ref Loc loc, Expression e) @safe
3530 super(loc, EXP.call, e);
3533 extern (D) this(const ref Loc loc, Expression e, Expression earg1)
3535 super(loc, EXP.call, e);
3536 this.arguments = new Expressions();
3537 if (earg1)
3538 this.arguments.push(earg1);
3541 extern (D) this(const ref Loc loc, Expression e, Expression earg1, Expression earg2)
3543 super(loc, EXP.call, e);
3544 auto arguments = new Expressions(2);
3545 (*arguments)[0] = earg1;
3546 (*arguments)[1] = earg2;
3547 this.arguments = arguments;
3550 /***********************************************************
3551 * Instatiates a new function call expression
3552 * Params:
3553 * loc = location
3554 * fd = the declaration of the function to call
3555 * earg1 = the function argument
3557 extern(D) this(const ref Loc loc, FuncDeclaration fd, Expression earg1)
3559 this(loc, new VarExp(loc, fd, false), earg1);
3560 this.f = fd;
3563 static CallExp create(const ref Loc loc, Expression e, Expressions* exps) @safe
3565 return new CallExp(loc, e, exps);
3568 static CallExp create(const ref Loc loc, Expression e) @safe
3570 return new CallExp(loc, e);
3573 static CallExp create(const ref Loc loc, Expression e, Expression earg1)
3575 return new CallExp(loc, e, earg1);
3578 /***********************************************************
3579 * Creates a new function call expression
3580 * Params:
3581 * loc = location
3582 * fd = the declaration of the function to call
3583 * earg1 = the function argument
3585 static CallExp create(const ref Loc loc, FuncDeclaration fd, Expression earg1)
3587 return new CallExp(loc, fd, earg1);
3590 override CallExp syntaxCopy()
3592 return new CallExp(loc, e1.syntaxCopy(), arraySyntaxCopy(arguments), names ? names.copy() : null);
3595 override bool isLvalue()
3597 Type tb = e1.type.toBasetype();
3598 if (tb.ty == Tdelegate || tb.ty == Tpointer)
3599 tb = tb.nextOf();
3600 auto tf = tb.isTypeFunction();
3601 if (tf && tf.isref)
3603 if (auto dve = e1.isDotVarExp())
3604 if (dve.var.isCtorDeclaration())
3605 return false;
3606 return true; // function returns a reference
3608 return false;
3611 override void accept(Visitor v)
3613 v.visit(this);
3618 * Get the called function type from a call expression
3619 * Params:
3620 * ce = function call expression. Must have had semantic analysis done.
3621 * Returns: called function type, or `null` if error / no semantic analysis done
3623 TypeFunction calledFunctionType(CallExp ce)
3625 Type t = ce.e1.type;
3626 if (!t)
3627 return null;
3628 t = t.toBasetype();
3629 if (auto tf = t.isTypeFunction())
3630 return tf;
3631 else if (auto td = t.isTypeDelegate())
3632 return td.nextOf().isTypeFunction();
3633 else
3634 return null;
3637 FuncDeclaration isFuncAddress(Expression e, bool* hasOverloads = null) @safe
3639 if (auto ae = e.isAddrExp())
3641 auto ae1 = ae.e1;
3642 if (auto ve = ae1.isVarExp())
3644 if (hasOverloads)
3645 *hasOverloads = ve.hasOverloads;
3646 return ve.var.isFuncDeclaration();
3648 if (auto dve = ae1.isDotVarExp())
3650 if (hasOverloads)
3651 *hasOverloads = dve.hasOverloads;
3652 return dve.var.isFuncDeclaration();
3655 else
3657 if (auto soe = e.isSymOffExp())
3659 if (hasOverloads)
3660 *hasOverloads = soe.hasOverloads;
3661 return soe.var.isFuncDeclaration();
3663 if (auto dge = e.isDelegateExp())
3665 if (hasOverloads)
3666 *hasOverloads = dge.hasOverloads;
3667 return dge.func.isFuncDeclaration();
3670 return null;
3673 /***********************************************************
3674 * The 'address of' operator, `&p`
3676 extern (C++) final class AddrExp : UnaExp
3678 extern (D) this(const ref Loc loc, Expression e) @safe
3680 super(loc, EXP.address, e);
3683 extern (D) this(const ref Loc loc, Expression e, Type t) @safe
3685 this(loc, e);
3686 type = t;
3689 override void accept(Visitor v)
3691 v.visit(this);
3695 /***********************************************************
3696 * The pointer dereference operator, `*p`
3698 extern (C++) final class PtrExp : UnaExp
3700 extern (D) this(const ref Loc loc, Expression e) @safe
3702 super(loc, EXP.star, e);
3703 //if (e.type)
3704 // type = ((TypePointer *)e.type).next;
3707 extern (D) this(const ref Loc loc, Expression e, Type t) @safe
3709 super(loc, EXP.star, e);
3710 type = t;
3713 override bool isLvalue()
3715 return true;
3718 override void accept(Visitor v)
3720 v.visit(this);
3724 /***********************************************************
3725 * The negation operator, `-x`
3727 extern (C++) final class NegExp : UnaExp
3729 extern (D) this(const ref Loc loc, Expression e) @safe
3731 super(loc, EXP.negate, e);
3734 override void accept(Visitor v)
3736 v.visit(this);
3740 /***********************************************************
3741 * The unary add operator, `+x`
3743 extern (C++) final class UAddExp : UnaExp
3745 extern (D) this(const ref Loc loc, Expression e) scope @safe
3747 super(loc, EXP.uadd, e);
3750 override void accept(Visitor v)
3752 v.visit(this);
3756 /***********************************************************
3757 * The bitwise complement operator, `~x`
3759 extern (C++) final class ComExp : UnaExp
3761 extern (D) this(const ref Loc loc, Expression e) @safe
3763 super(loc, EXP.tilde, e);
3766 override void accept(Visitor v)
3768 v.visit(this);
3772 /***********************************************************
3773 * The logical not operator, `!x`
3775 extern (C++) final class NotExp : UnaExp
3777 extern (D) this(const ref Loc loc, Expression e) @safe
3779 super(loc, EXP.not, e);
3782 override void accept(Visitor v)
3784 v.visit(this);
3788 /***********************************************************
3789 * The delete operator, `delete x` (deprecated)
3791 * https://dlang.org/spec/expression.html#delete_expressions
3793 extern (C++) final class DeleteExp : UnaExp
3795 bool isRAII; // true if called automatically as a result of scoped destruction
3797 extern (D) this(const ref Loc loc, Expression e, bool isRAII) @safe
3799 super(loc, EXP.delete_, e);
3800 this.isRAII = isRAII;
3803 override void accept(Visitor v)
3805 v.visit(this);
3809 /***********************************************************
3810 * The type cast operator, `cast(T) x`
3812 * It's possible to cast to one type while painting to another type
3814 * https://dlang.org/spec/expression.html#cast_expressions
3816 extern (C++) final class CastExp : UnaExp
3818 Type to; // type to cast to
3819 ubyte mod = cast(ubyte)~0; // MODxxxxx
3821 extern (D) this(const ref Loc loc, Expression e, Type t) @safe
3823 super(loc, EXP.cast_, e);
3824 this.to = t;
3827 /* For cast(const) and cast(immutable)
3829 extern (D) this(const ref Loc loc, Expression e, ubyte mod) @safe
3831 super(loc, EXP.cast_, e);
3832 this.mod = mod;
3835 override CastExp syntaxCopy()
3837 return to ? new CastExp(loc, e1.syntaxCopy(), to.syntaxCopy()) : new CastExp(loc, e1.syntaxCopy(), mod);
3840 override bool isLvalue()
3842 //printf("e1.type = %s, to.type = %s\n", e1.type.toChars(), to.toChars());
3843 if (!e1.isLvalue())
3844 return false;
3845 return (to.ty == Tsarray && (e1.type.ty == Tvector || e1.type.ty == Tsarray)) ||
3846 e1.type.mutableOf().unSharedOf().equals(to.mutableOf().unSharedOf());
3849 override void accept(Visitor v)
3851 v.visit(this);
3855 /***********************************************************
3857 extern (C++) final class VectorExp : UnaExp
3859 TypeVector to; // the target vector type before semantic()
3860 uint dim = ~0; // number of elements in the vector
3861 OwnedBy ownedByCtfe = OwnedBy.code;
3863 extern (D) this(const ref Loc loc, Expression e, Type t) @safe
3865 super(loc, EXP.vector, e);
3866 assert(t.ty == Tvector);
3867 to = cast(TypeVector)t;
3870 static VectorExp create(const ref Loc loc, Expression e, Type t) @safe
3872 return new VectorExp(loc, e, t);
3875 override VectorExp syntaxCopy()
3877 return new VectorExp(loc, e1.syntaxCopy(), to.syntaxCopy());
3880 override void accept(Visitor v)
3882 v.visit(this);
3886 /***********************************************************
3887 * e1.array property for vectors.
3889 * https://dlang.org/spec/simd.html#properties
3891 extern (C++) final class VectorArrayExp : UnaExp
3893 extern (D) this(const ref Loc loc, Expression e1) @safe
3895 super(loc, EXP.vectorArray, e1);
3898 override bool isLvalue()
3900 return e1.isLvalue();
3903 override void accept(Visitor v)
3905 v.visit(this);
3909 /***********************************************************
3910 * e1 [lwr .. upr]
3912 * https://dlang.org/spec/expression.html#slice_expressions
3914 extern (C++) final class SliceExp : UnaExp
3916 Expression upr; // null if implicit 0
3917 Expression lwr; // null if implicit [length - 1]
3919 VarDeclaration lengthVar;
3921 private extern(D) static struct BitFields
3923 bool upperIsInBounds; // true if upr <= e1.length
3924 bool lowerIsLessThanUpper; // true if lwr <= upr
3925 bool arrayop; // an array operation, rather than a slice
3927 import dmd.common.bitfields : generateBitFields;
3928 mixin(generateBitFields!(BitFields, ubyte));
3930 /************************************************************/
3931 extern (D) this(const ref Loc loc, Expression e1, IntervalExp ie) @safe
3933 super(loc, EXP.slice, e1);
3934 this.upr = ie ? ie.upr : null;
3935 this.lwr = ie ? ie.lwr : null;
3938 extern (D) this(const ref Loc loc, Expression e1, Expression lwr, Expression upr) @safe
3940 super(loc, EXP.slice, e1);
3941 this.upr = upr;
3942 this.lwr = lwr;
3945 override SliceExp syntaxCopy()
3947 auto se = new SliceExp(loc, e1.syntaxCopy(), lwr ? lwr.syntaxCopy() : null, upr ? upr.syntaxCopy() : null);
3948 se.lengthVar = this.lengthVar; // bug7871
3949 return se;
3952 override bool isLvalue()
3954 /* slice expression is rvalue in default, but
3955 * conversion to reference of static array is only allowed.
3957 return (type && type.toBasetype().ty == Tsarray);
3960 override Optional!bool toBool()
3962 return e1.toBool();
3965 override void accept(Visitor v)
3967 v.visit(this);
3971 /***********************************************************
3972 * The `.length` property of an array
3974 extern (C++) final class ArrayLengthExp : UnaExp
3976 extern (D) this(const ref Loc loc, Expression e1) @safe
3978 super(loc, EXP.arrayLength, e1);
3981 override void accept(Visitor v)
3983 v.visit(this);
3987 /***********************************************************
3988 * e1 [ a0, a1, a2, a3 ,... ]
3990 * https://dlang.org/spec/expression.html#index_expressions
3992 extern (C++) final class ArrayExp : UnaExp
3994 Expressions* arguments; // Array of Expression's a0..an
3996 size_t currentDimension; // for opDollar
3997 VarDeclaration lengthVar;
3999 extern (D) this(const ref Loc loc, Expression e1, Expression index = null)
4001 super(loc, EXP.array, e1);
4002 arguments = new Expressions();
4003 if (index)
4004 arguments.push(index);
4007 extern (D) this(const ref Loc loc, Expression e1, Expressions* args) @safe
4009 super(loc, EXP.array, e1);
4010 arguments = args;
4013 override ArrayExp syntaxCopy()
4015 auto ae = new ArrayExp(loc, e1.syntaxCopy(), arraySyntaxCopy(arguments));
4016 ae.lengthVar = this.lengthVar; // bug7871
4017 return ae;
4020 override bool isLvalue()
4022 if (type && type.toBasetype().ty == Tvoid)
4023 return false;
4024 return true;
4027 override void accept(Visitor v)
4029 v.visit(this);
4033 /***********************************************************
4035 extern (C++) final class DotExp : BinExp
4037 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
4039 super(loc, EXP.dot, e1, e2);
4042 override void accept(Visitor v)
4044 v.visit(this);
4048 /***********************************************************
4050 extern (C++) final class CommaExp : BinExp
4052 /// This is needed because AssignExp rewrites CommaExp, hence it needs
4053 /// to trigger the deprecation.
4054 const bool isGenerated;
4056 /// Temporary variable to enable / disable deprecation of comma expression
4057 /// depending on the context.
4058 /// Since most constructor calls are rewritting, the only place where
4059 /// false will be passed will be from the parser.
4060 bool allowCommaExp;
4063 extern (D) this(const ref Loc loc, Expression e1, Expression e2, bool generated = true) @safe
4065 super(loc, EXP.comma, e1, e2);
4066 allowCommaExp = isGenerated = generated;
4069 override bool isLvalue()
4071 return e2.isLvalue();
4074 override Optional!bool toBool()
4076 return e2.toBool();
4079 override void accept(Visitor v)
4081 v.visit(this);
4085 * If the argument is a CommaExp, set a flag to prevent deprecation messages
4087 * It's impossible to know from CommaExp.semantic if the result will
4088 * be used, hence when there is a result (type != void), a deprecation
4089 * message is always emitted.
4090 * However, some construct can produce a result but won't use it
4091 * (ExpStatement and for loop increment). Those should call this function
4092 * to prevent unwanted deprecations to be emitted.
4094 * Params:
4095 * exp = An expression that discards its result.
4096 * If the argument is null or not a CommaExp, nothing happens.
4098 static void allow(Expression exp) @safe
4100 if (exp)
4101 if (auto ce = exp.isCommaExp())
4102 ce.allowCommaExp = true;
4106 /***********************************************************
4107 * Mainly just a placeholder
4109 extern (C++) final class IntervalExp : Expression
4111 Expression lwr;
4112 Expression upr;
4114 extern (D) this(const ref Loc loc, Expression lwr, Expression upr) @safe
4116 super(loc, EXP.interval);
4117 this.lwr = lwr;
4118 this.upr = upr;
4121 override Expression syntaxCopy()
4123 return new IntervalExp(loc, lwr.syntaxCopy(), upr.syntaxCopy());
4126 override void accept(Visitor v)
4128 v.visit(this);
4132 /***********************************************************
4133 * The `dg.ptr` property, pointing to the delegate's 'context'
4135 * c.f.`DelegateFuncptrExp` for the delegate's function pointer `dg.funcptr`
4137 extern (C++) final class DelegatePtrExp : UnaExp
4139 extern (D) this(const ref Loc loc, Expression e1) @safe
4141 super(loc, EXP.delegatePointer, e1);
4144 override bool isLvalue()
4146 return e1.isLvalue();
4149 override void accept(Visitor v)
4151 v.visit(this);
4155 /***********************************************************
4156 * The `dg.funcptr` property, pointing to the delegate's function
4158 * c.f.`DelegatePtrExp` for the delegate's function pointer `dg.ptr`
4160 extern (C++) final class DelegateFuncptrExp : UnaExp
4162 extern (D) this(const ref Loc loc, Expression e1) @safe
4164 super(loc, EXP.delegateFunctionPointer, e1);
4167 override bool isLvalue()
4169 return e1.isLvalue();
4172 override void accept(Visitor v)
4174 v.visit(this);
4178 /***********************************************************
4179 * e1 [ e2 ]
4181 extern (C++) final class IndexExp : BinExp
4183 VarDeclaration lengthVar;
4184 bool modifiable = false; // assume it is an rvalue
4185 bool indexIsInBounds; // true if 0 <= e2 && e2 <= e1.length - 1
4187 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
4189 super(loc, EXP.index, e1, e2);
4190 //printf("IndexExp::IndexExp('%s')\n", toChars());
4193 extern (D) this(const ref Loc loc, Expression e1, Expression e2, bool indexIsInBounds) @safe
4195 super(loc, EXP.index, e1, e2);
4196 this.indexIsInBounds = indexIsInBounds;
4197 //printf("IndexExp::IndexExp('%s')\n", toChars());
4200 override IndexExp syntaxCopy()
4202 auto ie = new IndexExp(loc, e1.syntaxCopy(), e2.syntaxCopy());
4203 ie.lengthVar = this.lengthVar; // bug7871
4204 return ie;
4207 override bool isLvalue()
4209 if (e1.op == EXP.assocArrayLiteral)
4210 return false;
4211 if (e1.type.ty == Tsarray ||
4212 (e1.op == EXP.index && e1.type.ty != Tarray))
4214 return e1.isLvalue();
4216 return true;
4219 extern (D) Expression markSettingAAElem()
4221 if (e1.type.toBasetype().ty == Taarray)
4223 Type t2b = e2.type.toBasetype();
4224 if (t2b.ty == Tarray && t2b.nextOf().isMutable())
4226 error(loc, "associative arrays can only be assigned values with immutable keys, not `%s`", e2.type.toChars());
4227 return ErrorExp.get();
4229 modifiable = true;
4231 if (auto ie = e1.isIndexExp())
4233 Expression ex = ie.markSettingAAElem();
4234 if (ex.op == EXP.error)
4235 return ex;
4236 assert(ex == e1);
4239 return this;
4242 override void accept(Visitor v)
4244 v.visit(this);
4248 /***********************************************************
4249 * The postfix increment/decrement operator, `i++` / `i--`
4251 extern (C++) final class PostExp : BinExp
4253 extern (D) this(EXP op, const ref Loc loc, Expression e)
4255 super(loc, op, e, IntegerExp.literal!1);
4256 assert(op == EXP.minusMinus || op == EXP.plusPlus);
4259 override void accept(Visitor v)
4261 v.visit(this);
4265 /***********************************************************
4266 * The prefix increment/decrement operator, `++i` / `--i`
4268 extern (C++) final class PreExp : UnaExp
4270 extern (D) this(EXP op, const ref Loc loc, Expression e) @safe
4272 super(loc, op, e);
4273 assert(op == EXP.preMinusMinus || op == EXP.prePlusPlus);
4276 override void accept(Visitor v)
4278 v.visit(this);
4282 enum MemorySet
4284 none = 0, // simple assignment
4285 blockAssign = 1, // setting the contents of an array
4286 referenceInit = 2, // setting the reference of STC.ref_ variable
4289 /***********************************************************
4290 * The assignment / initialization operator, `=`
4292 * Note: operator assignment `op=` has a different base class, `BinAssignExp`
4294 extern (C++) class AssignExp : BinExp
4296 MemorySet memset;
4298 /************************************************************/
4299 /* op can be EXP.assign, EXP.construct, or EXP.blit */
4300 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
4302 super(loc, EXP.assign, e1, e2);
4305 this(const ref Loc loc, EXP tok, Expression e1, Expression e2) @safe
4307 super(loc, tok, e1, e2);
4310 override final bool isLvalue()
4312 // Array-op 'x[] = y[]' should make an rvalue.
4313 // Setting array length 'x.length = v' should make an rvalue.
4314 if (e1.op == EXP.slice || e1.op == EXP.arrayLength)
4316 return false;
4318 return true;
4321 override void accept(Visitor v)
4323 v.visit(this);
4327 /***********************************************************
4328 * When an assignment expression is lowered to a druntime call
4329 * this class is used to store the lowering.
4330 * It essentially behaves the same as an AssignExp, but it is
4331 * used to not waste space for other AssignExp that are not
4332 * lowered to anything.
4334 extern (C++) final class LoweredAssignExp : AssignExp
4336 Expression lowering;
4337 extern (D) this(AssignExp exp, Expression lowering) @safe
4339 super(exp.loc, EXP.loweredAssignExp, exp.e1, exp.e2);
4340 this.lowering = lowering;
4343 override const(char)* toChars() const
4345 return lowering.toChars();
4347 override void accept(Visitor v)
4349 v.visit(this);
4353 /***********************************************************
4355 extern (C++) final class ConstructExp : AssignExp
4357 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
4359 super(loc, EXP.construct, e1, e2);
4362 // Internal use only. If `v` is a reference variable, the assignment
4363 // will become a reference initialization automatically.
4364 extern (D) this(const ref Loc loc, VarDeclaration v, Expression e2) @safe
4366 auto ve = new VarExp(loc, v);
4367 assert(v.type && ve.type);
4369 super(loc, EXP.construct, ve, e2);
4371 if (v.isReference())
4372 memset = MemorySet.referenceInit;
4375 override void accept(Visitor v)
4377 v.visit(this);
4381 /***********************************************************
4382 * A bit-for-bit copy from `e2` to `e1`
4384 extern (C++) final class BlitExp : AssignExp
4386 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
4388 super(loc, EXP.blit, e1, e2);
4391 // Internal use only. If `v` is a reference variable, the assinment
4392 // will become a reference rebinding automatically.
4393 extern (D) this(const ref Loc loc, VarDeclaration v, Expression e2) @safe
4395 auto ve = new VarExp(loc, v);
4396 assert(v.type && ve.type);
4398 super(loc, EXP.blit, ve, e2);
4400 if (v.isReference())
4401 memset = MemorySet.referenceInit;
4404 override void accept(Visitor v)
4406 v.visit(this);
4410 /***********************************************************
4411 * `x += y`
4413 extern (C++) final class AddAssignExp : BinAssignExp
4415 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
4417 super(loc, EXP.addAssign, e1, e2);
4420 override void accept(Visitor v)
4422 v.visit(this);
4426 /***********************************************************
4427 * `x -= y`
4429 extern (C++) final class MinAssignExp : BinAssignExp
4431 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
4433 super(loc, EXP.minAssign, e1, e2);
4436 override void accept(Visitor v)
4438 v.visit(this);
4442 /***********************************************************
4443 * `x *= y`
4445 extern (C++) final class MulAssignExp : BinAssignExp
4447 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
4449 super(loc, EXP.mulAssign, e1, e2);
4452 override void accept(Visitor v)
4454 v.visit(this);
4458 /***********************************************************
4459 * `x /= y`
4461 extern (C++) final class DivAssignExp : BinAssignExp
4463 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
4465 super(loc, EXP.divAssign, e1, e2);
4468 override void accept(Visitor v)
4470 v.visit(this);
4474 /***********************************************************
4475 * `x %= y`
4477 extern (C++) final class ModAssignExp : BinAssignExp
4479 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
4481 super(loc, EXP.modAssign, e1, e2);
4484 override void accept(Visitor v)
4486 v.visit(this);
4490 /***********************************************************
4491 * `x &= y`
4493 extern (C++) final class AndAssignExp : BinAssignExp
4495 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
4497 super(loc, EXP.andAssign, e1, e2);
4500 override void accept(Visitor v)
4502 v.visit(this);
4506 /***********************************************************
4507 * `x |= y`
4509 extern (C++) final class OrAssignExp : BinAssignExp
4511 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
4513 super(loc, EXP.orAssign, e1, e2);
4516 override void accept(Visitor v)
4518 v.visit(this);
4522 /***********************************************************
4523 * `x ^= y`
4525 extern (C++) final class XorAssignExp : BinAssignExp
4527 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
4529 super(loc, EXP.xorAssign, e1, e2);
4532 override void accept(Visitor v)
4534 v.visit(this);
4538 /***********************************************************
4539 * `x ^^= y`
4541 extern (C++) final class PowAssignExp : BinAssignExp
4543 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
4545 super(loc, EXP.powAssign, e1, e2);
4548 override void accept(Visitor v)
4550 v.visit(this);
4554 /***********************************************************
4555 * `x <<= y`
4557 extern (C++) final class ShlAssignExp : BinAssignExp
4559 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
4561 super(loc, EXP.leftShiftAssign, e1, e2);
4564 override void accept(Visitor v)
4566 v.visit(this);
4570 /***********************************************************
4571 * `x >>= y`
4573 extern (C++) final class ShrAssignExp : BinAssignExp
4575 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
4577 super(loc, EXP.rightShiftAssign, e1, e2);
4580 override void accept(Visitor v)
4582 v.visit(this);
4586 /***********************************************************
4587 * `x >>>= y`
4589 extern (C++) final class UshrAssignExp : BinAssignExp
4591 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
4593 super(loc, EXP.unsignedRightShiftAssign, e1, e2);
4596 override void accept(Visitor v)
4598 v.visit(this);
4602 /***********************************************************
4603 * The `~=` operator.
4605 * It can have one of the following operators:
4607 * EXP.concatenateAssign - appending T[] to T[]
4608 * EXP.concatenateElemAssign - appending T to T[]
4609 * EXP.concatenateDcharAssign - appending dchar to T[]
4611 * The parser initially sets it to EXP.concatenateAssign, and semantic() later decides which
4612 * of the three it will be set to.
4614 extern (C++) class CatAssignExp : BinAssignExp
4616 Expression lowering; // lowered druntime hook `_d_arrayappend{cTX,T}`
4618 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
4620 super(loc, EXP.concatenateAssign, e1, e2);
4623 extern (D) this(const ref Loc loc, EXP tok, Expression e1, Expression e2) @safe
4625 super(loc, tok, e1, e2);
4628 override void accept(Visitor v)
4630 v.visit(this);
4634 /***********************************************************
4635 * The `~=` operator when appending a single element
4637 extern (C++) final class CatElemAssignExp : CatAssignExp
4639 extern (D) this(const ref Loc loc, Type type, Expression e1, Expression e2) @safe
4641 super(loc, EXP.concatenateElemAssign, e1, e2);
4642 this.type = type;
4645 override void accept(Visitor v)
4647 v.visit(this);
4651 /***********************************************************
4652 * The `~=` operator when appending a single `dchar`
4654 extern (C++) final class CatDcharAssignExp : CatAssignExp
4656 extern (D) this(const ref Loc loc, Type type, Expression e1, Expression e2) @safe
4658 super(loc, EXP.concatenateDcharAssign, e1, e2);
4659 this.type = type;
4662 override void accept(Visitor v)
4664 v.visit(this);
4668 /***********************************************************
4669 * The addition operator, `x + y`
4671 * https://dlang.org/spec/expression.html#add_expressions
4673 extern (C++) final class AddExp : BinExp
4675 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
4677 super(loc, EXP.add, e1, e2);
4680 override void accept(Visitor v)
4682 v.visit(this);
4686 /***********************************************************
4687 * The minus operator, `x - y`
4689 * https://dlang.org/spec/expression.html#add_expressions
4691 extern (C++) final class MinExp : BinExp
4693 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
4695 super(loc, EXP.min, e1, e2);
4698 override void accept(Visitor v)
4700 v.visit(this);
4704 /***********************************************************
4705 * The concatenation operator, `x ~ y`
4707 * https://dlang.org/spec/expression.html#cat_expressions
4709 extern (C++) final class CatExp : BinExp
4711 Expression lowering; // call to druntime hook `_d_arraycatnTX`
4713 extern (D) this(const ref Loc loc, Expression e1, Expression e2) scope @safe
4715 super(loc, EXP.concatenate, e1, e2);
4718 override void accept(Visitor v)
4720 v.visit(this);
4724 /***********************************************************
4725 * The multiplication operator, `x * y`
4727 * https://dlang.org/spec/expression.html#mul_expressions
4729 extern (C++) final class MulExp : BinExp
4731 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
4733 super(loc, EXP.mul, e1, e2);
4736 override void accept(Visitor v)
4738 v.visit(this);
4742 /***********************************************************
4743 * The division operator, `x / y`
4745 * https://dlang.org/spec/expression.html#mul_expressions
4747 extern (C++) final class DivExp : BinExp
4749 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
4751 super(loc, EXP.div, e1, e2);
4754 override void accept(Visitor v)
4756 v.visit(this);
4760 /***********************************************************
4761 * The modulo operator, `x % y`
4763 * https://dlang.org/spec/expression.html#mul_expressions
4765 extern (C++) final class ModExp : BinExp
4767 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
4769 super(loc, EXP.mod, e1, e2);
4772 override void accept(Visitor v)
4774 v.visit(this);
4778 /***********************************************************
4779 * The 'power' operator, `x ^^ y`
4781 * https://dlang.org/spec/expression.html#pow_expressions
4783 extern (C++) final class PowExp : BinExp
4785 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
4787 super(loc, EXP.pow, e1, e2);
4790 override void accept(Visitor v)
4792 v.visit(this);
4796 /***********************************************************
4797 * The 'shift left' operator, `x << y`
4799 * https://dlang.org/spec/expression.html#shift_expressions
4801 extern (C++) final class ShlExp : BinExp
4803 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
4805 super(loc, EXP.leftShift, e1, e2);
4808 override void accept(Visitor v)
4810 v.visit(this);
4814 /***********************************************************
4815 * The 'shift right' operator, `x >> y`
4817 * https://dlang.org/spec/expression.html#shift_expressions
4819 extern (C++) final class ShrExp : BinExp
4821 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
4823 super(loc, EXP.rightShift, e1, e2);
4826 override void accept(Visitor v)
4828 v.visit(this);
4832 /***********************************************************
4833 * The 'unsigned shift right' operator, `x >>> y`
4835 * https://dlang.org/spec/expression.html#shift_expressions
4837 extern (C++) final class UshrExp : BinExp
4839 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
4841 super(loc, EXP.unsignedRightShift, e1, e2);
4844 override void accept(Visitor v)
4846 v.visit(this);
4850 /***********************************************************
4851 * The bitwise 'and' operator, `x & y`
4853 * https://dlang.org/spec/expression.html#and_expressions
4855 extern (C++) final class AndExp : BinExp
4857 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
4859 super(loc, EXP.and, e1, e2);
4862 override void accept(Visitor v)
4864 v.visit(this);
4868 /***********************************************************
4869 * The bitwise 'or' operator, `x | y`
4871 * https://dlang.org/spec/expression.html#or_expressions
4873 extern (C++) final class OrExp : BinExp
4875 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
4877 super(loc, EXP.or, e1, e2);
4880 override void accept(Visitor v)
4882 v.visit(this);
4886 /***********************************************************
4887 * The bitwise 'xor' operator, `x ^ y`
4889 * https://dlang.org/spec/expression.html#xor_expressions
4891 extern (C++) final class XorExp : BinExp
4893 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
4895 super(loc, EXP.xor, e1, e2);
4898 override void accept(Visitor v)
4900 v.visit(this);
4904 /***********************************************************
4905 * The logical 'and' / 'or' operator, `X && Y` / `X || Y`
4907 * https://dlang.org/spec/expression.html#andand_expressions
4908 * https://dlang.org/spec/expression.html#oror_expressions
4910 extern (C++) final class LogicalExp : BinExp
4912 extern (D) this(const ref Loc loc, EXP op, Expression e1, Expression e2) @safe
4914 super(loc, op, e1, e2);
4915 assert(op == EXP.andAnd || op == EXP.orOr);
4918 override void accept(Visitor v)
4920 v.visit(this);
4924 /***********************************************************
4925 * A comparison operator, `<` `<=` `>` `>=`
4927 * `op` is one of:
4928 * EXP.lessThan, EXP.lessOrEqual, EXP.greaterThan, EXP.greaterOrEqual
4930 * https://dlang.org/spec/expression.html#relation_expressions
4932 extern (C++) final class CmpExp : BinExp
4934 extern (D) this(EXP op, const ref Loc loc, Expression e1, Expression e2) @safe
4936 super(loc, op, e1, e2);
4937 assert(op == EXP.lessThan || op == EXP.lessOrEqual || op == EXP.greaterThan || op == EXP.greaterOrEqual);
4940 override void accept(Visitor v)
4942 v.visit(this);
4946 /***********************************************************
4947 * The `in` operator, `"a" in ["a": 1]`
4949 * Note: `x !in y` is rewritten to `!(x in y)` in the parser
4951 * https://dlang.org/spec/expression.html#in_expressions
4953 extern (C++) final class InExp : BinExp
4955 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
4957 super(loc, EXP.in_, e1, e2);
4960 override void accept(Visitor v)
4962 v.visit(this);
4966 /***********************************************************
4967 * Associative array removal, `aa.remove(arg)`
4969 * This deletes the key e1 from the associative array e2
4971 extern (C++) final class RemoveExp : BinExp
4973 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
4975 super(loc, EXP.remove, e1, e2);
4976 type = Type.tbool;
4979 override void accept(Visitor v)
4981 v.visit(this);
4985 /***********************************************************
4986 * `==` and `!=`
4988 * EXP.equal and EXP.notEqual
4990 * https://dlang.org/spec/expression.html#equality_expressions
4992 extern (C++) final class EqualExp : BinExp
4994 extern (D) this(EXP op, const ref Loc loc, Expression e1, Expression e2) @safe
4996 super(loc, op, e1, e2);
4997 assert(op == EXP.equal || op == EXP.notEqual);
5000 override void accept(Visitor v)
5002 v.visit(this);
5006 /***********************************************************
5007 * `is` and `!is`
5009 * EXP.identity and EXP.notIdentity
5011 * https://dlang.org/spec/expression.html#identity_expressions
5013 extern (C++) final class IdentityExp : BinExp
5015 extern (D) this(EXP op, const ref Loc loc, Expression e1, Expression e2) @safe
5017 super(loc, op, e1, e2);
5018 assert(op == EXP.identity || op == EXP.notIdentity);
5021 override void accept(Visitor v)
5023 v.visit(this);
5027 /***********************************************************
5028 * The ternary operator, `econd ? e1 : e2`
5030 * https://dlang.org/spec/expression.html#conditional_expressions
5032 extern (C++) final class CondExp : BinExp
5034 Expression econd;
5036 extern (D) this(const ref Loc loc, Expression econd, Expression e1, Expression e2) scope @safe
5038 super(loc, EXP.question, e1, e2);
5039 this.econd = econd;
5042 override CondExp syntaxCopy()
5044 return new CondExp(loc, econd.syntaxCopy(), e1.syntaxCopy(), e2.syntaxCopy());
5047 override bool isLvalue()
5049 return e1.isLvalue() && e2.isLvalue();
5052 override void accept(Visitor v)
5054 v.visit(this);
5058 /***********************************************************
5059 * A special keyword when used as a function's default argument
5061 * When possible, special keywords are resolved in the parser, but when
5062 * appearing as a default argument, they result in an expression deriving
5063 * from this base class that is resolved for each function call.
5065 * ---
5066 * const x = __LINE__; // resolved in the parser
5067 * void foo(string file = __FILE__, int line = __LINE__); // DefaultInitExp
5068 * ---
5070 * https://dlang.org/spec/expression.html#specialkeywords
5072 extern (C++) class DefaultInitExp : Expression
5074 /*************************
5075 * Params:
5076 * loc = location
5077 * op = EXP.prettyFunction, EXP.functionString, EXP.moduleString,
5078 * EXP.line, EXP.file, EXP.fileFullPath
5080 extern (D) this(const ref Loc loc, EXP op) @safe
5082 super(loc, op);
5085 override void accept(Visitor v)
5087 v.visit(this);
5091 /***********************************************************
5092 * The `__FILE__` token as a default argument
5094 extern (C++) final class FileInitExp : DefaultInitExp
5096 extern (D) this(const ref Loc loc, EXP tok) @safe
5098 super(loc, tok);
5101 override void accept(Visitor v)
5103 v.visit(this);
5107 /***********************************************************
5108 * The `__LINE__` token as a default argument
5110 extern (C++) final class LineInitExp : DefaultInitExp
5112 extern (D) this(const ref Loc loc) @safe
5114 super(loc, EXP.line);
5117 override void accept(Visitor v)
5119 v.visit(this);
5123 /***********************************************************
5124 * The `__MODULE__` token as a default argument
5126 extern (C++) final class ModuleInitExp : DefaultInitExp
5128 extern (D) this(const ref Loc loc) @safe
5130 super(loc, EXP.moduleString);
5133 override void accept(Visitor v)
5135 v.visit(this);
5139 /***********************************************************
5140 * The `__FUNCTION__` token as a default argument
5142 extern (C++) final class FuncInitExp : DefaultInitExp
5144 extern (D) this(const ref Loc loc) @safe
5146 super(loc, EXP.functionString);
5149 override void accept(Visitor v)
5151 v.visit(this);
5155 /***********************************************************
5156 * The `__PRETTY_FUNCTION__` token as a default argument
5158 extern (C++) final class PrettyFuncInitExp : DefaultInitExp
5160 extern (D) this(const ref Loc loc) @safe
5162 super(loc, EXP.prettyFunction);
5165 override void accept(Visitor v)
5167 v.visit(this);
5171 /***********************************************************
5172 * A reference to a class, or an interface. We need this when we
5173 * point to a base class (we must record what the type is).
5175 extern (C++) final class ClassReferenceExp : Expression
5177 StructLiteralExp value;
5179 extern (D) this(const ref Loc loc, StructLiteralExp lit, Type type) @safe
5181 super(loc, EXP.classReference);
5182 assert(lit && lit.sd && lit.sd.isClassDeclaration());
5183 this.value = lit;
5184 this.type = type;
5187 ClassDeclaration originalClass()
5189 return value.sd.isClassDeclaration();
5192 // Return index of the field, or -1 if not found
5193 int getFieldIndex(Type fieldtype, uint fieldoffset)
5195 ClassDeclaration cd = originalClass();
5196 uint fieldsSoFar = 0;
5197 for (size_t j = 0; j < value.elements.length; j++)
5199 while (j - fieldsSoFar >= cd.fields.length)
5201 fieldsSoFar += cd.fields.length;
5202 cd = cd.baseClass;
5204 VarDeclaration v2 = cd.fields[j - fieldsSoFar];
5205 if (fieldoffset == v2.offset && fieldtype.size() == v2.type.size())
5207 return cast(int)(value.elements.length - fieldsSoFar - cd.fields.length + (j - fieldsSoFar));
5210 return -1;
5213 // Return index of the field, or -1 if not found
5214 // Same as getFieldIndex, but checks for a direct match with the VarDeclaration
5215 int findFieldIndexByName(VarDeclaration v)
5217 ClassDeclaration cd = originalClass();
5218 size_t fieldsSoFar = 0;
5219 for (size_t j = 0; j < value.elements.length; j++)
5221 while (j - fieldsSoFar >= cd.fields.length)
5223 fieldsSoFar += cd.fields.length;
5224 cd = cd.baseClass;
5226 VarDeclaration v2 = cd.fields[j - fieldsSoFar];
5227 if (v == v2)
5229 return cast(int)(value.elements.length - fieldsSoFar - cd.fields.length + (j - fieldsSoFar));
5232 return -1;
5235 override void accept(Visitor v)
5237 v.visit(this);
5241 /***********************************************************
5242 * This type is only used by the interpreter.
5244 extern (C++) final class CTFEExp : Expression
5246 extern (D) this(EXP tok)
5248 super(Loc.initial, tok);
5249 type = Type.tvoid;
5252 override const(char)* toChars() const
5254 switch (op)
5256 case EXP.cantExpression:
5257 return "<cant>";
5258 case EXP.voidExpression:
5259 return "cast(void)0";
5260 case EXP.showCtfeContext:
5261 return "<error>";
5262 case EXP.break_:
5263 return "<break>";
5264 case EXP.continue_:
5265 return "<continue>";
5266 case EXP.goto_:
5267 return "<goto>";
5268 default:
5269 assert(0);
5273 extern (D) __gshared CTFEExp cantexp;
5274 extern (D) __gshared CTFEExp voidexp;
5275 extern (D) __gshared CTFEExp breakexp;
5276 extern (D) __gshared CTFEExp continueexp;
5277 extern (D) __gshared CTFEExp gotoexp;
5278 /* Used when additional information is needed regarding
5279 * a ctfe error.
5281 extern (D) __gshared CTFEExp showcontext;
5283 extern (D) static bool isCantExp(const Expression e) @safe
5285 return e && e.op == EXP.cantExpression;
5288 extern (D) static bool isGotoExp(const Expression e) @safe
5290 return e && e.op == EXP.goto_;
5294 /***********************************************************
5295 * Fake class which holds the thrown exception.
5296 * Used for implementing exception handling.
5298 extern (C++) final class ThrownExceptionExp : Expression
5300 ClassReferenceExp thrown; // the thing being tossed
5302 extern (D) this(const ref Loc loc, ClassReferenceExp victim) @safe
5304 super(loc, EXP.thrownException);
5305 this.thrown = victim;
5306 this.type = victim.type;
5309 override const(char)* toChars() const
5311 return "CTFE ThrownException";
5314 override void accept(Visitor v)
5316 v.visit(this);
5321 * Objective-C class reference expression.
5323 * Used to get the metaclass of an Objective-C class, `NSObject.Class`.
5325 extern (C++) final class ObjcClassReferenceExp : Expression
5327 ClassDeclaration classDeclaration;
5329 extern (D) this(const ref Loc loc, ClassDeclaration classDeclaration)
5331 super(loc, EXP.objcClassReference);
5332 this.classDeclaration = classDeclaration;
5335 override void accept(Visitor v)
5337 v.visit(this);
5341 /*******************
5342 * C11 6.5.1.1 Generic Selection
5343 * For ImportC
5345 extern (C++) final class GenericExp : Expression
5347 Expression cntlExp; /// controlling expression of a generic selection (not evaluated)
5348 Types* types; /// type-names for generic associations (null entry for `default`)
5349 Expressions* exps; /// 1:1 mapping of typeNames to exps
5351 extern (D) this(const ref Loc loc, Expression cntlExp, Types* types, Expressions* exps) @safe
5353 super(loc, EXP._Generic);
5354 this.cntlExp = cntlExp;
5355 this.types = types;
5356 this.exps = exps;
5357 assert(types.length == exps.length); // must be the same and >=1
5360 override GenericExp syntaxCopy()
5362 return new GenericExp(loc, cntlExp.syntaxCopy(), Type.arraySyntaxCopy(types), Expression.arraySyntaxCopy(exps));
5365 override void accept(Visitor v)
5367 v.visit(this);
5372 * Verify if the given identifier is _d_array{,set}ctor.
5374 * Params:
5375 * id = the identifier to verify
5377 * Returns:
5378 * `true` if the identifier corresponds to a construction runtime hook,
5379 * `false` otherwise.
5381 bool isArrayConstruction(const Identifier id)
5383 import dmd.id : Id;
5385 return id == Id._d_arrayctor || id == Id._d_arraysetctor;
5388 /******************************
5389 * Provide efficient way to implement isUnaExp(), isBinExp(), isBinAssignExp()
5391 private immutable ubyte[EXP.max + 1] exptab =
5392 () {
5393 ubyte[EXP.max + 1] tab;
5394 with (EXPFLAGS)
5396 foreach (i; Eunary) { tab[i] |= unary; }
5397 foreach (i; Ebinary) { tab[i] |= unary | binary; }
5398 foreach (i; EbinaryAssign) { tab[i] |= unary | binary | binaryAssign; }
5400 return tab;
5401 } ();
5403 private enum EXPFLAGS : ubyte
5405 unary = 1,
5406 binary = 2,
5407 binaryAssign = 4,
5410 private enum Eunary =
5412 EXP.import_, EXP.assert_, EXP.throw_, EXP.dotIdentifier, EXP.dotTemplateDeclaration,
5413 EXP.dotVariable, EXP.dotTemplateInstance, EXP.delegate_, EXP.dotType, EXP.call,
5414 EXP.address, EXP.star, EXP.negate, EXP.uadd, EXP.tilde, EXP.not, EXP.delete_, EXP.cast_,
5415 EXP.vector, EXP.vectorArray, EXP.slice, EXP.arrayLength, EXP.array, EXP.delegatePointer,
5416 EXP.delegateFunctionPointer, EXP.preMinusMinus, EXP.prePlusPlus,
5419 private enum Ebinary =
5421 EXP.dot, EXP.comma, EXP.index, EXP.minusMinus, EXP.plusPlus, EXP.assign,
5422 EXP.add, EXP.min, EXP.concatenate, EXP.mul, EXP.div, EXP.mod, EXP.pow, EXP.leftShift,
5423 EXP.rightShift, EXP.unsignedRightShift, EXP.and, EXP.or, EXP.xor, EXP.andAnd, EXP.orOr,
5424 EXP.lessThan, EXP.lessOrEqual, EXP.greaterThan, EXP.greaterOrEqual,
5425 EXP.in_, EXP.remove, EXP.equal, EXP.notEqual, EXP.identity, EXP.notIdentity,
5426 EXP.question,
5427 EXP.construct, EXP.blit,
5430 private enum EbinaryAssign =
5432 EXP.addAssign, EXP.minAssign, EXP.mulAssign, EXP.divAssign, EXP.modAssign,
5433 EXP.andAssign, EXP.orAssign, EXP.xorAssign, EXP.powAssign,
5434 EXP.leftShiftAssign, EXP.rightShiftAssign, EXP.unsignedRightShiftAssign,
5435 EXP.concatenateAssign, EXP.concatenateElemAssign, EXP.concatenateDcharAssign,
5438 /// Given a member of the EXP enum, get the class instance size of the corresponding Expression class.
5439 /// Needed because the classes are `extern(C++)`
5440 private immutable ubyte[EXP.max+1] expSize = [
5441 EXP.reserved: 0,
5442 EXP.negate: __traits(classInstanceSize, NegExp),
5443 EXP.cast_: __traits(classInstanceSize, CastExp),
5444 EXP.null_: __traits(classInstanceSize, NullExp),
5445 EXP.assert_: __traits(classInstanceSize, AssertExp),
5446 EXP.array: __traits(classInstanceSize, ArrayExp),
5447 EXP.call: __traits(classInstanceSize, CallExp),
5448 EXP.address: __traits(classInstanceSize, AddrExp),
5449 EXP.type: __traits(classInstanceSize, TypeExp),
5450 EXP.throw_: __traits(classInstanceSize, ThrowExp),
5451 EXP.new_: __traits(classInstanceSize, NewExp),
5452 EXP.delete_: __traits(classInstanceSize, DeleteExp),
5453 EXP.star: __traits(classInstanceSize, PtrExp),
5454 EXP.symbolOffset: __traits(classInstanceSize, SymOffExp),
5455 EXP.variable: __traits(classInstanceSize, VarExp),
5456 EXP.dotVariable: __traits(classInstanceSize, DotVarExp),
5457 EXP.dotIdentifier: __traits(classInstanceSize, DotIdExp),
5458 EXP.dotTemplateInstance: __traits(classInstanceSize, DotTemplateInstanceExp),
5459 EXP.dotType: __traits(classInstanceSize, DotTypeExp),
5460 EXP.slice: __traits(classInstanceSize, SliceExp),
5461 EXP.arrayLength: __traits(classInstanceSize, ArrayLengthExp),
5462 EXP.dollar: __traits(classInstanceSize, DollarExp),
5463 EXP.template_: __traits(classInstanceSize, TemplateExp),
5464 EXP.dotTemplateDeclaration: __traits(classInstanceSize, DotTemplateExp),
5465 EXP.declaration: __traits(classInstanceSize, DeclarationExp),
5466 EXP.dSymbol: __traits(classInstanceSize, DsymbolExp),
5467 EXP.typeid_: __traits(classInstanceSize, TypeidExp),
5468 EXP.uadd: __traits(classInstanceSize, UAddExp),
5469 EXP.remove: __traits(classInstanceSize, RemoveExp),
5470 EXP.newAnonymousClass: __traits(classInstanceSize, NewAnonClassExp),
5471 EXP.arrayLiteral: __traits(classInstanceSize, ArrayLiteralExp),
5472 EXP.assocArrayLiteral: __traits(classInstanceSize, AssocArrayLiteralExp),
5473 EXP.structLiteral: __traits(classInstanceSize, StructLiteralExp),
5474 EXP.classReference: __traits(classInstanceSize, ClassReferenceExp),
5475 EXP.thrownException: __traits(classInstanceSize, ThrownExceptionExp),
5476 EXP.delegatePointer: __traits(classInstanceSize, DelegatePtrExp),
5477 EXP.delegateFunctionPointer: __traits(classInstanceSize, DelegateFuncptrExp),
5478 EXP.lessThan: __traits(classInstanceSize, CmpExp),
5479 EXP.greaterThan: __traits(classInstanceSize, CmpExp),
5480 EXP.lessOrEqual: __traits(classInstanceSize, CmpExp),
5481 EXP.greaterOrEqual: __traits(classInstanceSize, CmpExp),
5482 EXP.equal: __traits(classInstanceSize, EqualExp),
5483 EXP.notEqual: __traits(classInstanceSize, EqualExp),
5484 EXP.identity: __traits(classInstanceSize, IdentityExp),
5485 EXP.notIdentity: __traits(classInstanceSize, IdentityExp),
5486 EXP.index: __traits(classInstanceSize, IndexExp),
5487 EXP.is_: __traits(classInstanceSize, IsExp),
5488 EXP.leftShift: __traits(classInstanceSize, ShlExp),
5489 EXP.rightShift: __traits(classInstanceSize, ShrExp),
5490 EXP.leftShiftAssign: __traits(classInstanceSize, ShlAssignExp),
5491 EXP.rightShiftAssign: __traits(classInstanceSize, ShrAssignExp),
5492 EXP.unsignedRightShift: __traits(classInstanceSize, UshrExp),
5493 EXP.unsignedRightShiftAssign: __traits(classInstanceSize, UshrAssignExp),
5494 EXP.concatenate: __traits(classInstanceSize, CatExp),
5495 EXP.concatenateAssign: __traits(classInstanceSize, CatAssignExp),
5496 EXP.concatenateElemAssign: __traits(classInstanceSize, CatElemAssignExp),
5497 EXP.concatenateDcharAssign: __traits(classInstanceSize, CatDcharAssignExp),
5498 EXP.add: __traits(classInstanceSize, AddExp),
5499 EXP.min: __traits(classInstanceSize, MinExp),
5500 EXP.addAssign: __traits(classInstanceSize, AddAssignExp),
5501 EXP.minAssign: __traits(classInstanceSize, MinAssignExp),
5502 EXP.mul: __traits(classInstanceSize, MulExp),
5503 EXP.div: __traits(classInstanceSize, DivExp),
5504 EXP.mod: __traits(classInstanceSize, ModExp),
5505 EXP.mulAssign: __traits(classInstanceSize, MulAssignExp),
5506 EXP.divAssign: __traits(classInstanceSize, DivAssignExp),
5507 EXP.modAssign: __traits(classInstanceSize, ModAssignExp),
5508 EXP.and: __traits(classInstanceSize, AndExp),
5509 EXP.or: __traits(classInstanceSize, OrExp),
5510 EXP.xor: __traits(classInstanceSize, XorExp),
5511 EXP.andAssign: __traits(classInstanceSize, AndAssignExp),
5512 EXP.orAssign: __traits(classInstanceSize, OrAssignExp),
5513 EXP.xorAssign: __traits(classInstanceSize, XorAssignExp),
5514 EXP.assign: __traits(classInstanceSize, AssignExp),
5515 EXP.not: __traits(classInstanceSize, NotExp),
5516 EXP.tilde: __traits(classInstanceSize, ComExp),
5517 EXP.plusPlus: __traits(classInstanceSize, PostExp),
5518 EXP.minusMinus: __traits(classInstanceSize, PostExp),
5519 EXP.construct: __traits(classInstanceSize, ConstructExp),
5520 EXP.blit: __traits(classInstanceSize, BlitExp),
5521 EXP.dot: __traits(classInstanceSize, DotExp),
5522 EXP.comma: __traits(classInstanceSize, CommaExp),
5523 EXP.question: __traits(classInstanceSize, CondExp),
5524 EXP.andAnd: __traits(classInstanceSize, LogicalExp),
5525 EXP.orOr: __traits(classInstanceSize, LogicalExp),
5526 EXP.prePlusPlus: __traits(classInstanceSize, PreExp),
5527 EXP.preMinusMinus: __traits(classInstanceSize, PreExp),
5528 EXP.identifier: __traits(classInstanceSize, IdentifierExp),
5529 EXP.string_: __traits(classInstanceSize, StringExp),
5530 EXP.this_: __traits(classInstanceSize, ThisExp),
5531 EXP.super_: __traits(classInstanceSize, SuperExp),
5532 EXP.halt: __traits(classInstanceSize, HaltExp),
5533 EXP.tuple: __traits(classInstanceSize, TupleExp),
5534 EXP.error: __traits(classInstanceSize, ErrorExp),
5535 EXP.void_: __traits(classInstanceSize, VoidInitExp),
5536 EXP.int64: __traits(classInstanceSize, IntegerExp),
5537 EXP.float64: __traits(classInstanceSize, RealExp),
5538 EXP.complex80: __traits(classInstanceSize, ComplexExp),
5539 EXP.import_: __traits(classInstanceSize, ImportExp),
5540 EXP.delegate_: __traits(classInstanceSize, DelegateExp),
5541 EXP.function_: __traits(classInstanceSize, FuncExp),
5542 EXP.mixin_: __traits(classInstanceSize, MixinExp),
5543 EXP.in_: __traits(classInstanceSize, InExp),
5544 EXP.break_: __traits(classInstanceSize, CTFEExp),
5545 EXP.continue_: __traits(classInstanceSize, CTFEExp),
5546 EXP.goto_: __traits(classInstanceSize, CTFEExp),
5547 EXP.scope_: __traits(classInstanceSize, ScopeExp),
5548 EXP.traits: __traits(classInstanceSize, TraitsExp),
5549 EXP.overloadSet: __traits(classInstanceSize, OverExp),
5550 EXP.line: __traits(classInstanceSize, LineInitExp),
5551 EXP.file: __traits(classInstanceSize, FileInitExp),
5552 EXP.fileFullPath: __traits(classInstanceSize, FileInitExp),
5553 EXP.moduleString: __traits(classInstanceSize, ModuleInitExp),
5554 EXP.functionString: __traits(classInstanceSize, FuncInitExp),
5555 EXP.prettyFunction: __traits(classInstanceSize, PrettyFuncInitExp),
5556 EXP.pow: __traits(classInstanceSize, PowExp),
5557 EXP.powAssign: __traits(classInstanceSize, PowAssignExp),
5558 EXP.vector: __traits(classInstanceSize, VectorExp),
5559 EXP.voidExpression: __traits(classInstanceSize, CTFEExp),
5560 EXP.cantExpression: __traits(classInstanceSize, CTFEExp),
5561 EXP.showCtfeContext: __traits(classInstanceSize, CTFEExp),
5562 EXP.objcClassReference: __traits(classInstanceSize, ObjcClassReferenceExp),
5563 EXP.vectorArray: __traits(classInstanceSize, VectorArrayExp),
5564 EXP.compoundLiteral: __traits(classInstanceSize, CompoundLiteralExp),
5565 EXP._Generic: __traits(classInstanceSize, GenericExp),
5566 EXP.interval: __traits(classInstanceSize, IntervalExp),
5567 EXP.loweredAssignExp : __traits(classInstanceSize, LoweredAssignExp),