d: Merge dmd. druntime e770945277, phobos 6d6e0b9b9
[official-gcc.git] / gcc / d / dmd / expression.d
blob1603f2bbb5350421a8777abe6c39b12c46069373
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 * If `s` is a function template, i.e. the only member of a template
194 * and that member is a function, return that template.
195 * Params:
196 * s = symbol that might be a function template
197 * Returns:
198 * template for that function, otherwise null
200 TemplateDeclaration getFuncTemplateDecl(Dsymbol s) @safe
202 FuncDeclaration f = s.isFuncDeclaration();
203 if (f && f.parent)
205 if (auto ti = f.parent.isTemplateInstance())
207 if (!ti.isTemplateMixin() && ti.tempdecl)
209 auto td = ti.tempdecl.isTemplateDeclaration();
210 if (td.onemember && td.ident == f.ident)
212 return td;
217 return null;
220 /************************ TypeDotIdExp ************************************/
221 /* Things like:
222 * int.size
223 * foo.size
224 * (foo).size
225 * cast(foo).size
227 DotIdExp typeDotIdExp(const ref Loc loc, Type type, Identifier ident) @safe
229 return new DotIdExp(loc, new TypeExp(loc, type), ident);
232 /***************************************************
233 * Given an Expression, find the variable it really is.
235 * For example, `a[index]` is really `a`, and `s.f` is really `s`.
236 * Params:
237 * e = Expression to look at
238 * Returns:
239 * variable if there is one, null if not
241 VarDeclaration expToVariable(Expression e)
243 while (1)
245 switch (e.op)
247 case EXP.variable:
248 return (cast(VarExp)e).var.isVarDeclaration();
250 case EXP.dotVariable:
251 e = (cast(DotVarExp)e).e1;
252 continue;
254 case EXP.index:
256 IndexExp ei = cast(IndexExp)e;
257 e = ei.e1;
258 Type ti = e.type.toBasetype();
259 if (ti.ty == Tsarray)
260 continue;
261 return null;
264 case EXP.slice:
266 SliceExp ei = cast(SliceExp)e;
267 e = ei.e1;
268 Type ti = e.type.toBasetype();
269 if (ti.ty == Tsarray)
270 continue;
271 return null;
274 case EXP.this_:
275 case EXP.super_:
276 return (cast(ThisExp)e).var.isVarDeclaration();
278 // Temporaries for rvalues that need destruction
279 // are of form: (T s = rvalue, s). For these cases
280 // we can just return var declaration of `s`. However,
281 // this is intentionally not calling `Expression.extractLast`
282 // because at this point we cannot infer the var declaration
283 // of more complex generated comma expressions such as the
284 // one for the array append hook.
285 case EXP.comma:
287 if (auto ve = e.isCommaExp().e2.isVarExp())
288 return ve.var.isVarDeclaration();
290 return null;
292 default:
293 return null;
298 enum OwnedBy : ubyte
300 code, // normal code expression in AST
301 ctfe, // value expression for CTFE
302 cache, // constant value cached for CTFE
305 enum WANTvalue = 0; // default
306 enum WANTexpand = 1; // expand const/immutable variables if possible
308 /***********************************************************
309 * https://dlang.org/spec/expression.html#expression
311 extern (C++) abstract class Expression : ASTNode
313 Type type; // !=null means that semantic() has been run
314 Loc loc; // file location
315 const EXP op; // to minimize use of dynamic_cast
317 extern (D) this(const ref Loc loc, EXP op) scope @safe
319 //printf("Expression::Expression(op = %d) this = %p\n", op, this);
320 this.loc = loc;
321 this.op = op;
324 /// Returns: class instance size of this expression (implemented manually because `extern(C++)`)
325 final size_t size() nothrow @nogc pure @safe const { return expSize[op]; }
327 static void _init()
329 CTFEExp.cantexp = new CTFEExp(EXP.cantExpression);
330 CTFEExp.voidexp = new CTFEExp(EXP.voidExpression);
331 CTFEExp.breakexp = new CTFEExp(EXP.break_);
332 CTFEExp.continueexp = new CTFEExp(EXP.continue_);
333 CTFEExp.gotoexp = new CTFEExp(EXP.goto_);
334 CTFEExp.showcontext = new CTFEExp(EXP.showCtfeContext);
338 * Deinitializes the global state of the compiler.
340 * This can be used to restore the state set by `_init` to its original
341 * state.
343 static void deinitialize()
345 CTFEExp.cantexp = CTFEExp.cantexp.init;
346 CTFEExp.voidexp = CTFEExp.voidexp.init;
347 CTFEExp.breakexp = CTFEExp.breakexp.init;
348 CTFEExp.continueexp = CTFEExp.continueexp.init;
349 CTFEExp.gotoexp = CTFEExp.gotoexp.init;
350 CTFEExp.showcontext = CTFEExp.showcontext.init;
353 /*********************************
354 * Does *not* do a deep copy.
356 extern (D) final Expression copy()
358 Expression e;
359 if (!size)
361 debug
363 fprintf(stderr, "No expression copy for: %s\n", toChars());
364 printf("op = %d\n", op);
366 assert(0);
369 // memory never freed, so can use the faster bump-pointer-allocation
370 e = cast(Expression)allocmemory(size);
371 //printf("Expression::copy(op = %d) e = %p\n", op, e);
372 return cast(Expression)memcpy(cast(void*)e, cast(void*)this, size);
375 Expression syntaxCopy()
377 //printf("Expression::syntaxCopy()\n");
378 //print();
379 return copy();
382 // kludge for template.isExpression()
383 override final DYNCAST dyncast() const
385 return DYNCAST.expression;
388 override const(char)* toChars() const
390 return .toChars(this);
393 /**********************************
394 * Combine e1 and e2 by CommaExp if both are not NULL.
396 extern (D) static Expression combine(Expression e1, Expression e2) @safe
398 if (e1)
400 if (e2)
402 e1 = new CommaExp(e1.loc, e1, e2);
403 e1.type = e2.type;
406 else
407 e1 = e2;
408 return e1;
411 extern (D) static Expression combine(Expression e1, Expression e2, Expression e3) @safe
413 return combine(combine(e1, e2), e3);
416 extern (D) static Expression combine(Expression e1, Expression e2, Expression e3, Expression e4) @safe
418 return combine(combine(e1, e2), combine(e3, e4));
421 /**********************************
422 * If 'e' is a tree of commas, returns the rightmost expression
423 * by stripping off it from the tree. The remained part of the tree
424 * is returned via e0.
425 * Otherwise 'e' is directly returned and e0 is set to NULL.
427 extern (D) static Expression extractLast(Expression e, out Expression e0) @safe
429 if (e.op != EXP.comma)
431 return e;
434 CommaExp ce = cast(CommaExp)e;
435 if (ce.e2.op != EXP.comma)
437 e0 = ce.e1;
438 return ce.e2;
440 else
442 e0 = e;
444 Expression* pce = &ce.e2;
445 while ((cast(CommaExp)(*pce)).e2.op == EXP.comma)
447 pce = &(cast(CommaExp)(*pce)).e2;
449 assert((*pce).op == EXP.comma);
450 ce = cast(CommaExp)(*pce);
451 *pce = ce.e1;
453 return ce.e2;
457 extern (D) static Expressions* arraySyntaxCopy(Expressions* exps)
459 Expressions* a = null;
460 if (exps)
462 a = new Expressions(exps.length);
463 foreach (i, e; *exps)
465 (*a)[i] = e ? e.syntaxCopy() : null;
468 return a;
471 dinteger_t toInteger()
473 //printf("Expression %s\n", EXPtoString(op).ptr);
474 if (!type.isTypeError())
475 error(loc, "integer constant expression expected instead of `%s`", toChars());
476 return 0;
479 uinteger_t toUInteger()
481 //printf("Expression %s\n", EXPtoString(op).ptr);
482 return cast(uinteger_t)toInteger();
485 real_t toReal()
487 error(loc, "floating point constant expression expected instead of `%s`", toChars());
488 return CTFloat.zero;
491 real_t toImaginary()
493 error(loc, "floating point constant expression expected instead of `%s`", toChars());
494 return CTFloat.zero;
497 complex_t toComplex()
499 error(loc, "floating point constant expression expected instead of `%s`", toChars());
500 return complex_t(CTFloat.zero);
503 StringExp toStringExp()
505 return null;
508 /***************************************
509 * Return !=0 if expression is an lvalue.
511 bool isLvalue()
513 return false;
516 /****************************************
517 * Check that the expression has a valid type.
518 * If not, generates an error "... has no type".
519 * Returns:
520 * true if the expression is not valid.
521 * Note:
522 * When this function returns true, `checkValue()` should also return true.
524 bool checkType()
526 return false;
529 /****************************************
530 * Check that the expression has a valid value.
531 * If not, generates an error "... has no value".
532 * Returns:
533 * true if the expression is not valid or has void type.
535 bool checkValue()
537 if (type && type.toBasetype().ty == Tvoid)
539 error(loc, "expression `%s` is `void` and has no value", toChars());
540 //print(); assert(0);
541 if (!global.gag)
542 type = Type.terror;
543 return true;
545 return false;
548 extern (D) final bool checkScalar()
550 if (op == EXP.error)
551 return true;
552 if (type.toBasetype().ty == Terror)
553 return true;
554 if (!type.isscalar())
556 error(loc, "`%s` is not a scalar, it is a `%s`", toChars(), type.toChars());
557 return true;
559 return checkValue();
562 extern (D) final bool checkNoBool()
564 if (op == EXP.error)
565 return true;
566 if (type.toBasetype().ty == Terror)
567 return true;
568 if (type.toBasetype().ty == Tbool)
570 error(loc, "operation not allowed on `bool` `%s`", toChars());
571 return true;
573 return false;
576 extern (D) final bool checkIntegral()
578 if (op == EXP.error)
579 return true;
580 if (type.toBasetype().ty == Terror)
581 return true;
582 if (!type.isintegral())
584 error(loc, "`%s` is not of integral type, it is a `%s`", toChars(), type.toChars());
585 return true;
587 return checkValue();
590 extern (D) final bool checkArithmetic(EXP op)
592 if (op == EXP.error)
593 return true;
594 if (type.toBasetype().ty == Terror)
595 return true;
596 if (!type.isintegral() && !type.isfloating())
598 // unary aggregate ops error here
599 const char* msg = type.isAggregate() ?
600 "operator `%s` is not defined for `%s` of type `%s`" :
601 "illegal operator `%s` for `%s` of type `%s`";
602 error(loc, msg, EXPtoString(op).ptr, toChars(), type.toChars());
603 return true;
605 return checkValue();
608 /*******************************
609 * Check whether the expression allows RMW operations, error with rmw operator diagnostic if not.
610 * ex is the RHS expression, or NULL if ++/-- is used (for diagnostics)
611 * Returns true if error occurs.
613 extern (D) final bool checkReadModifyWrite(EXP rmwOp, Expression ex = null)
615 //printf("Expression::checkReadModifyWrite() %s %s", toChars(), ex ? ex.toChars() : "");
616 if (!type || !type.isShared() || type.isTypeStruct() || type.isTypeClass())
617 return false;
619 // atomicOp uses opAssign (+=/-=) rather than opOp (++/--) for the CT string literal.
620 switch (rmwOp)
622 case EXP.plusPlus:
623 case EXP.prePlusPlus:
624 rmwOp = EXP.addAssign;
625 break;
626 case EXP.minusMinus:
627 case EXP.preMinusMinus:
628 rmwOp = EXP.minAssign;
629 break;
630 default:
631 break;
634 error(loc, "read-modify-write operations are not allowed for `shared` variables");
635 errorSupplemental(loc, "Use `core.atomic.atomicOp!\"%s\"(%s, %s)` instead",
636 EXPtoString(rmwOp).ptr, toChars(), ex ? ex.toChars() : "1");
637 return true;
640 /******************************
641 * Take address of expression.
643 final Expression addressOf()
645 //printf("Expression::addressOf()\n");
646 debug
648 assert(op == EXP.error || isLvalue());
650 Expression e = new AddrExp(loc, this, type.pointerTo());
651 return e;
654 /******************************
655 * If this is a reference, dereference it.
657 final Expression deref()
659 //printf("Expression::deref()\n");
660 // type could be null if forward referencing an 'auto' variable
661 if (type)
662 if (auto tr = type.isTypeReference())
664 Expression e = new PtrExp(loc, this, tr.next);
665 return e;
667 return this;
670 final int isConst()
672 //printf("Expression::isConst(): %s\n", e.toChars());
673 switch (op)
675 case EXP.int64:
676 case EXP.float64:
677 case EXP.complex80:
678 return 1;
679 case EXP.null_:
680 return 0;
681 case EXP.symbolOffset:
682 return 2;
683 default:
684 return 0;
686 assert(0);
689 /******
690 * Identical, not just equal. I.e. NaNs with different bit patterns are not identical
692 bool isIdentical(const Expression e) const
694 return equals(e);
698 /// Statically evaluate this expression to a `bool` if possible
699 /// Returns: an optional thath either contains the value or is empty
700 Optional!bool toBool()
702 return typeof(return)();
705 bool hasCode()
707 return true;
710 final pure inout nothrow @nogc @safe
712 inout(IntegerExp) isIntegerExp() { return op == EXP.int64 ? cast(typeof(return))this : null; }
713 inout(ErrorExp) isErrorExp() { return op == EXP.error ? cast(typeof(return))this : null; }
714 inout(VoidInitExp) isVoidInitExp() { return op == EXP.void_ ? cast(typeof(return))this : null; }
715 inout(RealExp) isRealExp() { return op == EXP.float64 ? cast(typeof(return))this : null; }
716 inout(ComplexExp) isComplexExp() { return op == EXP.complex80 ? cast(typeof(return))this : null; }
717 inout(IdentifierExp) isIdentifierExp() { return op == EXP.identifier ? cast(typeof(return))this : null; }
718 inout(DollarExp) isDollarExp() { return op == EXP.dollar ? cast(typeof(return))this : null; }
719 inout(DsymbolExp) isDsymbolExp() { return op == EXP.dSymbol ? cast(typeof(return))this : null; }
720 inout(ThisExp) isThisExp() { return op == EXP.this_ ? cast(typeof(return))this : null; }
721 inout(SuperExp) isSuperExp() { return op == EXP.super_ ? cast(typeof(return))this : null; }
722 inout(NullExp) isNullExp() { return op == EXP.null_ ? cast(typeof(return))this : null; }
723 inout(StringExp) isStringExp() { return op == EXP.string_ ? cast(typeof(return))this : null; }
724 inout(InterpExp) isInterpExp() { return op == EXP.interpolated ? cast(typeof(return))this : null; }
725 inout(TupleExp) isTupleExp() { return op == EXP.tuple ? cast(typeof(return))this : null; }
726 inout(ArrayLiteralExp) isArrayLiteralExp() { return op == EXP.arrayLiteral ? cast(typeof(return))this : null; }
727 inout(AssocArrayLiteralExp) isAssocArrayLiteralExp() { return op == EXP.assocArrayLiteral ? cast(typeof(return))this : null; }
728 inout(StructLiteralExp) isStructLiteralExp() { return op == EXP.structLiteral ? cast(typeof(return))this : null; }
729 inout(CompoundLiteralExp) isCompoundLiteralExp() { return op == EXP.compoundLiteral ? cast(typeof(return))this : null; }
730 inout(TypeExp) isTypeExp() { return op == EXP.type ? cast(typeof(return))this : null; }
731 inout(ScopeExp) isScopeExp() { return op == EXP.scope_ ? cast(typeof(return))this : null; }
732 inout(TemplateExp) isTemplateExp() { return op == EXP.template_ ? cast(typeof(return))this : null; }
733 inout(NewExp) isNewExp() { return op == EXP.new_ ? cast(typeof(return))this : null; }
734 inout(NewAnonClassExp) isNewAnonClassExp() { return op == EXP.newAnonymousClass ? cast(typeof(return))this : null; }
735 inout(SymOffExp) isSymOffExp() { return op == EXP.symbolOffset ? cast(typeof(return))this : null; }
736 inout(VarExp) isVarExp() { return op == EXP.variable ? cast(typeof(return))this : null; }
737 inout(OverExp) isOverExp() { return op == EXP.overloadSet ? cast(typeof(return))this : null; }
738 inout(FuncExp) isFuncExp() { return op == EXP.function_ ? cast(typeof(return))this : null; }
739 inout(DeclarationExp) isDeclarationExp() { return op == EXP.declaration ? cast(typeof(return))this : null; }
740 inout(TypeidExp) isTypeidExp() { return op == EXP.typeid_ ? cast(typeof(return))this : null; }
741 inout(TraitsExp) isTraitsExp() { return op == EXP.traits ? cast(typeof(return))this : null; }
742 inout(HaltExp) isHaltExp() { return op == EXP.halt ? cast(typeof(return))this : null; }
743 inout(IsExp) isExp() { return op == EXP.is_ ? cast(typeof(return))this : null; }
744 inout(MixinExp) isMixinExp() { return op == EXP.mixin_ ? cast(typeof(return))this : null; }
745 inout(ImportExp) isImportExp() { return op == EXP.import_ ? cast(typeof(return))this : null; }
746 inout(AssertExp) isAssertExp() { return op == EXP.assert_ ? cast(typeof(return))this : null; }
747 inout(ThrowExp) isThrowExp() { return op == EXP.throw_ ? cast(typeof(return))this : null; }
748 inout(DotIdExp) isDotIdExp() { return op == EXP.dotIdentifier ? cast(typeof(return))this : null; }
749 inout(DotTemplateExp) isDotTemplateExp() { return op == EXP.dotTemplateDeclaration ? cast(typeof(return))this : null; }
750 inout(DotVarExp) isDotVarExp() { return op == EXP.dotVariable ? cast(typeof(return))this : null; }
751 inout(DotTemplateInstanceExp) isDotTemplateInstanceExp() { return op == EXP.dotTemplateInstance ? cast(typeof(return))this : null; }
752 inout(DelegateExp) isDelegateExp() { return op == EXP.delegate_ ? cast(typeof(return))this : null; }
753 inout(DotTypeExp) isDotTypeExp() { return op == EXP.dotType ? cast(typeof(return))this : null; }
754 inout(CallExp) isCallExp() { return op == EXP.call ? cast(typeof(return))this : null; }
755 inout(AddrExp) isAddrExp() { return op == EXP.address ? cast(typeof(return))this : null; }
756 inout(PtrExp) isPtrExp() { return op == EXP.star ? cast(typeof(return))this : null; }
757 inout(NegExp) isNegExp() { return op == EXP.negate ? cast(typeof(return))this : null; }
758 inout(UAddExp) isUAddExp() { return op == EXP.uadd ? cast(typeof(return))this : null; }
759 inout(ComExp) isComExp() { return op == EXP.tilde ? cast(typeof(return))this : null; }
760 inout(NotExp) isNotExp() { return op == EXP.not ? cast(typeof(return))this : null; }
761 inout(DeleteExp) isDeleteExp() { return op == EXP.delete_ ? cast(typeof(return))this : null; }
762 inout(CastExp) isCastExp() { return op == EXP.cast_ ? cast(typeof(return))this : null; }
763 inout(VectorExp) isVectorExp() { return op == EXP.vector ? cast(typeof(return))this : null; }
764 inout(VectorArrayExp) isVectorArrayExp() { return op == EXP.vectorArray ? cast(typeof(return))this : null; }
765 inout(SliceExp) isSliceExp() { return op == EXP.slice ? cast(typeof(return))this : null; }
766 inout(ArrayLengthExp) isArrayLengthExp() { return op == EXP.arrayLength ? cast(typeof(return))this : null; }
767 inout(ArrayExp) isArrayExp() { return op == EXP.array ? cast(typeof(return))this : null; }
768 inout(DotExp) isDotExp() { return op == EXP.dot ? cast(typeof(return))this : null; }
769 inout(CommaExp) isCommaExp() { return op == EXP.comma ? cast(typeof(return))this : null; }
770 inout(IntervalExp) isIntervalExp() { return op == EXP.interval ? cast(typeof(return))this : null; }
771 inout(DelegatePtrExp) isDelegatePtrExp() { return op == EXP.delegatePointer ? cast(typeof(return))this : null; }
772 inout(DelegateFuncptrExp) isDelegateFuncptrExp() { return op == EXP.delegateFunctionPointer ? cast(typeof(return))this : null; }
773 inout(IndexExp) isIndexExp() { return op == EXP.index ? cast(typeof(return))this : null; }
774 inout(PostExp) isPostExp() { return (op == EXP.plusPlus || op == EXP.minusMinus) ? cast(typeof(return))this : null; }
775 inout(PreExp) isPreExp() { return (op == EXP.prePlusPlus || op == EXP.preMinusMinus) ? cast(typeof(return))this : null; }
776 inout(AssignExp) isAssignExp() { return op == EXP.assign ? cast(typeof(return))this : null; }
777 inout(LoweredAssignExp) isLoweredAssignExp() { return op == EXP.loweredAssignExp ? cast(typeof(return))this : null; }
778 inout(ConstructExp) isConstructExp() { return op == EXP.construct ? cast(typeof(return))this : null; }
779 inout(BlitExp) isBlitExp() { return op == EXP.blit ? cast(typeof(return))this : null; }
780 inout(AddAssignExp) isAddAssignExp() { return op == EXP.addAssign ? cast(typeof(return))this : null; }
781 inout(MinAssignExp) isMinAssignExp() { return op == EXP.minAssign ? cast(typeof(return))this : null; }
782 inout(MulAssignExp) isMulAssignExp() { return op == EXP.mulAssign ? cast(typeof(return))this : null; }
784 inout(DivAssignExp) isDivAssignExp() { return op == EXP.divAssign ? cast(typeof(return))this : null; }
785 inout(ModAssignExp) isModAssignExp() { return op == EXP.modAssign ? cast(typeof(return))this : null; }
786 inout(AndAssignExp) isAndAssignExp() { return op == EXP.andAssign ? cast(typeof(return))this : null; }
787 inout(OrAssignExp) isOrAssignExp() { return op == EXP.orAssign ? cast(typeof(return))this : null; }
788 inout(XorAssignExp) isXorAssignExp() { return op == EXP.xorAssign ? cast(typeof(return))this : null; }
789 inout(PowAssignExp) isPowAssignExp() { return op == EXP.powAssign ? cast(typeof(return))this : null; }
791 inout(ShlAssignExp) isShlAssignExp() { return op == EXP.leftShiftAssign ? cast(typeof(return))this : null; }
792 inout(ShrAssignExp) isShrAssignExp() { return op == EXP.rightShiftAssign ? cast(typeof(return))this : null; }
793 inout(UshrAssignExp) isUshrAssignExp() { return op == EXP.unsignedRightShiftAssign ? cast(typeof(return))this : null; }
795 inout(CatAssignExp) isCatAssignExp() { return op == EXP.concatenateAssign
796 ? cast(typeof(return))this
797 : null; }
799 inout(CatElemAssignExp) isCatElemAssignExp() { return op == EXP.concatenateElemAssign
800 ? cast(typeof(return))this
801 : null; }
803 inout(CatDcharAssignExp) isCatDcharAssignExp() { return op == EXP.concatenateDcharAssign
804 ? cast(typeof(return))this
805 : null; }
807 inout(AddExp) isAddExp() { return op == EXP.add ? cast(typeof(return))this : null; }
808 inout(MinExp) isMinExp() { return op == EXP.min ? cast(typeof(return))this : null; }
809 inout(CatExp) isCatExp() { return op == EXP.concatenate ? cast(typeof(return))this : null; }
810 inout(MulExp) isMulExp() { return op == EXP.mul ? cast(typeof(return))this : null; }
811 inout(DivExp) isDivExp() { return op == EXP.div ? cast(typeof(return))this : null; }
812 inout(ModExp) isModExp() { return op == EXP.mod ? cast(typeof(return))this : null; }
813 inout(PowExp) isPowExp() { return op == EXP.pow ? cast(typeof(return))this : null; }
814 inout(ShlExp) isShlExp() { return op == EXP.leftShift ? cast(typeof(return))this : null; }
815 inout(ShrExp) isShrExp() { return op == EXP.rightShift ? cast(typeof(return))this : null; }
816 inout(UshrExp) isUshrExp() { return op == EXP.unsignedRightShift ? cast(typeof(return))this : null; }
817 inout(AndExp) isAndExp() { return op == EXP.and ? cast(typeof(return))this : null; }
818 inout(OrExp) isOrExp() { return op == EXP.or ? cast(typeof(return))this : null; }
819 inout(XorExp) isXorExp() { return op == EXP.xor ? cast(typeof(return))this : null; }
820 inout(LogicalExp) isLogicalExp() { return (op == EXP.andAnd || op == EXP.orOr) ? cast(typeof(return))this : null; }
821 //inout(CmpExp) isCmpExp() { return op == EXP. ? cast(typeof(return))this : null; }
822 inout(InExp) isInExp() { return op == EXP.in_ ? cast(typeof(return))this : null; }
823 inout(RemoveExp) isRemoveExp() { return op == EXP.remove ? cast(typeof(return))this : null; }
824 inout(EqualExp) isEqualExp() { return (op == EXP.equal || op == EXP.notEqual) ? cast(typeof(return))this : null; }
825 inout(IdentityExp) isIdentityExp() { return (op == EXP.identity || op == EXP.notIdentity) ? cast(typeof(return))this : null; }
826 inout(CondExp) isCondExp() { return op == EXP.question ? cast(typeof(return))this : null; }
827 inout(GenericExp) isGenericExp() { return op == EXP._Generic ? cast(typeof(return))this : null; }
828 inout(DefaultInitExp) isDefaultInitExp() { return
829 (op == EXP.prettyFunction || op == EXP.functionString ||
830 op == EXP.line || op == EXP.moduleString ||
831 op == EXP.file || op == EXP.fileFullPath ) ? cast(typeof(return))this : null; }
832 inout(FileInitExp) isFileInitExp() { return (op == EXP.file || op == EXP.fileFullPath) ? cast(typeof(return))this : null; }
833 inout(LineInitExp) isLineInitExp() { return op == EXP.line ? cast(typeof(return))this : null; }
834 inout(ModuleInitExp) isModuleInitExp() { return op == EXP.moduleString ? cast(typeof(return))this : null; }
835 inout(FuncInitExp) isFuncInitExp() { return op == EXP.functionString ? cast(typeof(return))this : null; }
836 inout(PrettyFuncInitExp) isPrettyFuncInitExp() { return op == EXP.prettyFunction ? cast(typeof(return))this : null; }
837 inout(ObjcClassReferenceExp) isObjcClassReferenceExp() { return op == EXP.objcClassReference ? cast(typeof(return))this : null; }
838 inout(ClassReferenceExp) isClassReferenceExp() { return op == EXP.classReference ? cast(typeof(return))this : null; }
839 inout(ThrownExceptionExp) isThrownExceptionExp() { return op == EXP.thrownException ? cast(typeof(return))this : null; }
841 inout(UnaExp) isUnaExp() pure inout nothrow @nogc
843 return exptab[op] & EXPFLAGS.unary ? cast(typeof(return))this : null;
846 inout(BinExp) isBinExp() pure inout nothrow @nogc
848 return exptab[op] & EXPFLAGS.binary ? cast(typeof(return))this : null;
851 inout(BinAssignExp) isBinAssignExp() pure inout nothrow @nogc
853 return exptab[op] & EXPFLAGS.binaryAssign ? cast(typeof(return))this : null;
857 override void accept(Visitor v)
859 v.visit(this);
863 /***********************************************************
864 * A compile-time known integer value
866 extern (C++) final class IntegerExp : Expression
868 private dinteger_t value;
870 extern (D) this(const ref Loc loc, dinteger_t value, Type type)
872 super(loc, EXP.int64);
873 //printf("IntegerExp(value = %lld, type = '%s')\n", value, type ? type.toChars() : "");
874 assert(type);
875 if (!type.isscalar())
877 //printf("%s, loc = %d\n", toChars(), loc.linnum);
878 if (type.ty != Terror)
879 error(loc, "integral constant must be scalar type, not `%s`", type.toChars());
880 type = Type.terror;
882 this.type = type;
883 this.value = normalize(type.toBasetype().ty, value);
886 extern (D) this(dinteger_t value)
888 super(Loc.initial, EXP.int64);
889 this.type = Type.tint32;
890 this.value = cast(int)value;
893 static IntegerExp create(const ref Loc loc, dinteger_t value, Type type)
895 return new IntegerExp(loc, value, type);
898 override bool equals(const RootObject o) const
900 if (this == o)
901 return true;
902 if (auto ne = (cast(Expression)o).isIntegerExp())
904 if (type.toHeadMutable().equals(ne.type.toHeadMutable()) && value == ne.value)
906 return true;
909 return false;
912 override dinteger_t toInteger()
914 // normalize() is necessary until we fix all the paints of 'type'
915 return value = normalize(type.toBasetype().ty, value);
918 override real_t toReal()
920 // normalize() is necessary until we fix all the paints of 'type'
921 const ty = type.toBasetype().ty;
922 const val = normalize(ty, value);
923 value = val;
924 return (ty == Tuns64)
925 ? real_t(cast(ulong)val)
926 : real_t(cast(long)val);
929 override real_t toImaginary()
931 return CTFloat.zero;
934 override complex_t toComplex()
936 return complex_t(toReal());
939 override Optional!bool toBool()
941 bool r = toInteger() != 0;
942 return typeof(return)(r);
945 override void accept(Visitor v)
947 v.visit(this);
950 dinteger_t getInteger()
952 return value;
955 extern (D) void setInteger(dinteger_t value)
957 this.value = normalize(type.toBasetype().ty, value);
960 extern (D) static dinteger_t normalize(TY ty, dinteger_t value)
962 /* 'Normalize' the value of the integer to be in range of the type
964 dinteger_t result;
965 switch (ty)
967 case Tbool:
968 result = (value != 0);
969 break;
971 case Tint8:
972 result = cast(byte)value;
973 break;
975 case Tchar:
976 case Tuns8:
977 result = cast(ubyte)value;
978 break;
980 case Tint16:
981 result = cast(short)value;
982 break;
984 case Twchar:
985 case Tuns16:
986 result = cast(ushort)value;
987 break;
989 case Tint32:
990 result = cast(int)value;
991 break;
993 case Tdchar:
994 case Tuns32:
995 result = cast(uint)value;
996 break;
998 case Tint64:
999 result = cast(long)value;
1000 break;
1002 case Tuns64:
1003 result = cast(ulong)value;
1004 break;
1006 case Tpointer:
1007 if (target.ptrsize == 8)
1008 goto case Tuns64;
1009 if (target.ptrsize == 4)
1010 goto case Tuns32;
1011 if (target.ptrsize == 2)
1012 goto case Tuns16;
1013 assert(0);
1015 default:
1016 break;
1018 return result;
1021 override IntegerExp syntaxCopy()
1023 return this;
1027 * Use this instead of creating new instances for commonly used literals
1028 * such as 0 or 1.
1030 * Parameters:
1031 * v = The value of the expression
1032 * Returns:
1033 * A static instance of the expression, typed as `Tint32`.
1035 static IntegerExp literal(int v)()
1037 __gshared IntegerExp theConstant;
1038 if (!theConstant)
1039 theConstant = new IntegerExp(v);
1040 return theConstant;
1044 * Use this instead of creating new instances for commonly used bools.
1046 * Parameters:
1047 * b = The value of the expression
1048 * Returns:
1049 * A static instance of the expression, typed as `Type.tbool`.
1051 static IntegerExp createBool(bool b)
1053 __gshared IntegerExp trueExp, falseExp;
1054 if (!trueExp)
1056 trueExp = new IntegerExp(Loc.initial, 1, Type.tbool);
1057 falseExp = new IntegerExp(Loc.initial, 0, Type.tbool);
1059 return b ? trueExp : falseExp;
1063 /***********************************************************
1064 * Use this expression for error recovery.
1066 * It should behave as a 'sink' to prevent further cascaded error messages.
1068 extern (C++) final class ErrorExp : Expression
1070 extern (D) this()
1072 super(Loc.initial, EXP.error);
1073 type = Type.terror;
1076 static ErrorExp get ()
1078 if (errorexp is null)
1079 errorexp = new ErrorExp();
1081 if (global.errors == 0 && global.gaggedErrors == 0)
1083 /* Unfortunately, errors can still leak out of gagged errors,
1084 * and we need to set the error count to prevent bogus code
1085 * generation. At least give a message.
1087 .error(Loc.initial, "unknown, please file report on issues.dlang.org");
1090 return errorexp;
1093 override void accept(Visitor v)
1095 v.visit(this);
1098 extern (C++) __gshared ErrorExp errorexp; // handy shared value
1102 /***********************************************************
1103 * An uninitialized value,
1104 * generated from void initializers.
1106 * https://dlang.org/spec/declaration.html#void_init
1108 extern (C++) final class VoidInitExp : Expression
1110 VarDeclaration var; /// the variable from where the void value came from, null if not known
1111 /// Useful for error messages
1113 extern (D) this(VarDeclaration var) @safe
1115 super(var.loc, EXP.void_);
1116 this.var = var;
1117 this.type = var.type;
1120 override void accept(Visitor v)
1122 v.visit(this);
1127 /***********************************************************
1128 * A compile-time known floating point number
1130 extern (C++) final class RealExp : Expression
1132 real_t value;
1134 extern (D) this(const ref Loc loc, real_t value, Type type) @safe
1136 super(loc, EXP.float64);
1137 //printf("RealExp::RealExp(%Lg)\n", value);
1138 this.value = value;
1139 this.type = type;
1142 static RealExp create(const ref Loc loc, real_t value, Type type) @safe
1144 return new RealExp(loc, value, type);
1147 /********************************
1148 * Test to see if two reals are the same.
1149 * Regard NaN's as equivalent.
1150 * Regard +0 and -0 as different.
1151 * Params:
1152 * x1 = first operand
1153 * x2 = second operand
1154 * Returns:
1155 * true if x1 is x2
1156 * else false
1158 private static bool RealIdentical(real_t x1, real_t x2) @safe
1160 return (CTFloat.isNaN(x1) && CTFloat.isNaN(x2)) || CTFloat.isIdentical(x1, x2);
1162 override bool equals(const RootObject o) const
1164 if (this == o)
1165 return true;
1166 if (auto ne = (cast(Expression)o).isRealExp())
1168 if (type.toHeadMutable().equals(ne.type.toHeadMutable()) && RealIdentical(value, ne.value))
1170 return true;
1173 return false;
1176 override bool isIdentical(const Expression e) const
1178 if (!equals(e))
1179 return false;
1180 return CTFloat.isIdentical(value, e.isRealExp().value);
1183 override dinteger_t toInteger()
1185 return cast(sinteger_t)toReal();
1188 override uinteger_t toUInteger()
1190 return cast(uinteger_t)toReal();
1193 override real_t toReal()
1195 return type.isreal() ? value : CTFloat.zero;
1198 override real_t toImaginary()
1200 return type.isreal() ? CTFloat.zero : value;
1203 override complex_t toComplex()
1205 return complex_t(toReal(), toImaginary());
1208 override Optional!bool toBool()
1210 return typeof(return)(!!value);
1213 override void accept(Visitor v)
1215 v.visit(this);
1219 /***********************************************************
1220 * A compile-time complex number (deprecated)
1222 extern (C++) final class ComplexExp : Expression
1224 complex_t value;
1226 extern (D) this(const ref Loc loc, complex_t value, Type type) @safe
1228 super(loc, EXP.complex80);
1229 this.value = value;
1230 this.type = type;
1231 //printf("ComplexExp::ComplexExp(%s)\n", toChars());
1234 static ComplexExp create(const ref Loc loc, complex_t value, Type type) @safe
1236 return new ComplexExp(loc, value, type);
1239 override bool equals(const RootObject o) const
1241 if (this == o)
1242 return true;
1243 if (auto ne = (cast(Expression)o).isComplexExp())
1245 if (type.toHeadMutable().equals(ne.type.toHeadMutable()) &&
1246 RealExp.RealIdentical(creall(value), creall(ne.value)) &&
1247 RealExp.RealIdentical(cimagl(value), cimagl(ne.value)))
1249 return true;
1252 return false;
1255 override bool isIdentical(const Expression e) const
1257 if (!equals(e))
1258 return false;
1259 // equals() regards different NaN values as 'equals'
1260 auto c = e.isComplexExp();
1261 return CTFloat.isIdentical(creall(value), creall(c.value)) &&
1262 CTFloat.isIdentical(cimagl(value), cimagl(c.value));
1265 override dinteger_t toInteger()
1267 return cast(sinteger_t)toReal();
1270 override uinteger_t toUInteger()
1272 return cast(uinteger_t)toReal();
1275 override real_t toReal()
1277 return creall(value);
1280 override real_t toImaginary()
1282 return cimagl(value);
1285 override complex_t toComplex()
1287 return value;
1290 override Optional!bool toBool()
1292 return typeof(return)(!!value);
1295 override void accept(Visitor v)
1297 v.visit(this);
1301 /***********************************************************
1302 * An identifier in the context of an expression (as opposed to a declaration)
1304 * ---
1305 * int x; // VarDeclaration with Identifier
1306 * x++; // PostExp with IdentifierExp
1307 * ---
1309 extern (C++) class IdentifierExp : Expression
1311 Identifier ident;
1312 bool parens; // if it appears as (identifier)
1314 extern (D) this(const ref Loc loc, Identifier ident) scope @safe
1316 super(loc, EXP.identifier);
1317 this.ident = ident;
1320 static IdentifierExp create(const ref Loc loc, Identifier ident) @safe
1322 return new IdentifierExp(loc, ident);
1325 override final bool isLvalue()
1327 return true;
1330 override void accept(Visitor v)
1332 v.visit(this);
1336 /***********************************************************
1337 * The dollar operator used when indexing or slicing an array. E.g `a[$]`, `a[1 .. $]` etc.
1339 * https://dlang.org/spec/arrays.html#array-length
1341 extern (C++) final class DollarExp : IdentifierExp
1343 extern (D) this(const ref Loc loc)
1345 super(loc, Id.dollar);
1348 override void accept(Visitor v)
1350 v.visit(this);
1354 /***********************************************************
1355 * Won't be generated by parser.
1357 extern (C++) final class DsymbolExp : Expression
1359 Dsymbol s;
1360 bool hasOverloads;
1362 extern (D) this(const ref Loc loc, Dsymbol s, bool hasOverloads = true) @safe
1364 super(loc, EXP.dSymbol);
1365 this.s = s;
1366 this.hasOverloads = hasOverloads;
1369 override bool isLvalue()
1371 return true;
1374 override void accept(Visitor v)
1376 v.visit(this);
1380 /***********************************************************
1381 * https://dlang.org/spec/expression.html#this
1383 extern (C++) class ThisExp : Expression
1385 VarDeclaration var;
1387 extern (D) this(const ref Loc loc) @safe
1389 super(loc, EXP.this_);
1390 //printf("ThisExp::ThisExp() loc = %d\n", loc.linnum);
1393 this(const ref Loc loc, const EXP tok) @safe
1395 super(loc, tok);
1396 //printf("ThisExp::ThisExp() loc = %d\n", loc.linnum);
1399 override ThisExp syntaxCopy()
1401 auto r = cast(ThisExp) super.syntaxCopy();
1402 // require new semantic (possibly new `var` etc.)
1403 r.type = null;
1404 r.var = null;
1405 return r;
1408 override Optional!bool toBool()
1410 // `this` is never null (what about structs?)
1411 return typeof(return)(true);
1414 override final bool isLvalue()
1416 // Class `this` should be an rvalue; struct `this` should be an lvalue.
1417 return type.toBasetype().ty != Tclass;
1420 override void accept(Visitor v)
1422 v.visit(this);
1426 /***********************************************************
1427 * https://dlang.org/spec/expression.html#super
1429 extern (C++) final class SuperExp : ThisExp
1431 extern (D) this(const ref Loc loc) @safe
1433 super(loc, EXP.super_);
1436 override void accept(Visitor v)
1438 v.visit(this);
1442 /***********************************************************
1443 * A compile-time known `null` value
1445 * https://dlang.org/spec/expression.html#null
1447 extern (C++) final class NullExp : Expression
1449 extern (D) this(const ref Loc loc, Type type = null) scope @safe
1451 super(loc, EXP.null_);
1452 this.type = type;
1455 override bool equals(const RootObject o) const
1457 if (auto e = o.isExpression())
1459 if (e.op == EXP.null_ && type.equals(e.type))
1461 return true;
1464 return false;
1467 override Optional!bool toBool()
1469 // null in any type is false
1470 return typeof(return)(false);
1473 override StringExp toStringExp()
1475 if (this.type.implicitConvTo(Type.tstring))
1477 auto se = new StringExp(loc, (cast(char*)mem.xcalloc(1, 1))[0 .. 0]);
1478 se.type = Type.tstring;
1479 return se;
1482 return null;
1485 override void accept(Visitor v)
1487 v.visit(this);
1491 /***********************************************************
1492 * https://dlang.org/spec/expression.html#string_literals
1494 extern (C++) final class StringExp : Expression
1496 char postfix = NoPostfix; // 'c', 'w', 'd'
1497 OwnedBy ownedByCtfe = OwnedBy.code;
1498 private union
1500 char* string; // if sz == 1
1501 wchar* wstring; // if sz == 2
1502 dchar* dstring; // if sz == 4
1503 ulong* lstring; // if sz == 8
1504 } // (const if ownedByCtfe == OwnedBy.code)
1505 size_t len; // number of code units
1506 ubyte sz = 1; // 1: char, 2: wchar, 4: dchar
1509 * Whether the string literal's type is fixed
1510 * Example:
1511 * ---
1512 * wstring x = "abc"; // OK, string literal is flexible
1513 * wstring y = cast(string) "abc"; // Error: type was committed after cast
1514 * ---
1516 bool committed;
1518 /// If the string is parsed from a hex string literal
1519 bool hexString = false;
1521 enum char NoPostfix = 0;
1523 extern (D) this(const ref Loc loc, const(void)[] string) scope
1525 super(loc, EXP.string_);
1526 this.string = cast(char*)string.ptr; // note that this.string should be const
1527 this.len = string.length;
1528 this.sz = 1; // work around LDC bug #1286
1531 extern (D) this(const ref Loc loc, const(void)[] string, size_t len, ubyte sz, char postfix = NoPostfix) scope
1533 super(loc, EXP.string_);
1534 this.string = cast(char*)string.ptr; // note that this.string should be const
1535 this.len = len;
1536 this.sz = sz;
1537 this.postfix = postfix;
1540 static StringExp create(const ref Loc loc, const(char)* s)
1542 return new StringExp(loc, s.toDString());
1545 static StringExp create(const ref Loc loc, const(void)* string, size_t len)
1547 return new StringExp(loc, string[0 .. len]);
1550 override bool equals(const RootObject o) const
1552 //printf("StringExp::equals('%s') %s\n", o.toChars(), toChars());
1553 if (auto e = o.isExpression())
1555 if (auto se = e.isStringExp())
1557 return compare(se) == 0;
1560 return false;
1563 /**********************************
1564 * Return the number of code units the string would be if it were re-encoded
1565 * as tynto.
1566 * Params:
1567 * tynto = code unit type of the target encoding
1568 * Returns:
1569 * number of code units
1571 size_t numberOfCodeUnits(int tynto = 0) const
1573 int encSize;
1574 switch (tynto)
1576 case 0: return len;
1577 case Tchar: encSize = 1; break;
1578 case Twchar: encSize = 2; break;
1579 case Tdchar: encSize = 4; break;
1580 default:
1581 assert(0);
1583 if (sz == encSize)
1584 return len;
1586 size_t result = 0;
1587 dchar c;
1589 switch (sz)
1591 case 1:
1592 for (size_t u = 0; u < len;)
1594 if (const s = utf_decodeChar(string[0 .. len], u, c))
1596 error(loc, "%.*s", cast(int)s.length, s.ptr);
1597 return 0;
1599 result += utf_codeLength(encSize, c);
1601 break;
1603 case 2:
1604 for (size_t u = 0; u < len;)
1606 if (const s = utf_decodeWchar(wstring[0 .. len], u, c))
1608 error(loc, "%.*s", cast(int)s.length, s.ptr);
1609 return 0;
1611 result += utf_codeLength(encSize, c);
1613 break;
1615 case 4:
1616 foreach (u; 0 .. len)
1618 result += utf_codeLength(encSize, dstring[u]);
1620 break;
1622 default:
1623 assert(0);
1625 return result;
1628 /**********************************************
1629 * Write the contents of the string to dest.
1630 * Use numberOfCodeUnits() to determine size of result.
1631 * Params:
1632 * dest = destination
1633 * tyto = encoding type of the result
1634 * zero = add terminating 0
1636 void writeTo(void* dest, bool zero, int tyto = 0) const
1638 int encSize;
1639 switch (tyto)
1641 case 0: encSize = sz; break;
1642 case Tchar: encSize = 1; break;
1643 case Twchar: encSize = 2; break;
1644 case Tdchar: encSize = 4; break;
1645 default:
1646 assert(0);
1648 if (sz == encSize)
1650 memcpy(dest, string, len * sz);
1651 if (zero)
1652 memset(dest + len * sz, 0, sz);
1654 else
1655 assert(0);
1658 /*********************************************
1659 * Get the code unit at index i
1660 * Params:
1661 * i = index
1662 * Returns:
1663 * code unit at index i
1665 dchar getCodeUnit(size_t i) const pure
1667 assert(this.sz <= dchar.sizeof);
1668 return cast(dchar) getIndex(i);
1671 /// Returns: integer at index `i`
1672 dinteger_t getIndex(size_t i) const pure
1674 assert(i < len);
1675 final switch (sz)
1677 case 1:
1678 return string[i];
1679 case 2:
1680 return wstring[i];
1681 case 4:
1682 return dstring[i];
1683 case 8:
1684 return lstring[i];
1688 /*********************************************
1689 * Set the code unit at index i to c
1690 * Params:
1691 * i = index
1692 * c = code unit to set it to
1694 extern (D) void setCodeUnit(size_t i, dchar c)
1696 return setIndex(i, c);
1699 extern (D) void setIndex(size_t i, long c)
1701 assert(i < len);
1702 final switch (sz)
1704 case 1:
1705 string[i] = cast(char)c;
1706 break;
1707 case 2:
1708 wstring[i] = cast(wchar)c;
1709 break;
1710 case 4:
1711 dstring[i] = cast(dchar) c;
1712 break;
1713 case 8:
1714 lstring[i] = c;
1715 break;
1719 override StringExp toStringExp()
1721 return this;
1726 * Compare two `StringExp` by length, then value
1728 * The comparison is not the usual C-style comparison as seen with
1729 * `strcmp` or `memcmp`, but instead first compare based on the length.
1730 * This allows both faster lookup and sorting when comparing sparse data.
1732 * This ordering scheme is relied on by the string-switching feature.
1733 * Code in Druntime's `core.internal.switch_` relies on this ordering
1734 * when doing a binary search among case statements.
1736 * Both `StringExp` should be of the same encoding.
1738 * Params:
1739 * se2 = String expression to compare `this` to
1741 * Returns:
1742 * `0` when `this` is equal to se2, a value greater than `0` if
1743 * `this` should be considered greater than `se2`,
1744 * and a value less than `0` if `this` is lesser than `se2`.
1746 int compare(const StringExp se2) const nothrow pure @nogc
1748 //printf("StringExp::compare()\n");
1749 const len1 = len;
1750 const len2 = se2.len;
1752 assert(this.sz == se2.sz, "Comparing string expressions of different sizes");
1753 //printf("sz = %d, len1 = %d, len2 = %d\n", sz, cast(int)len1, cast(int)len2);
1754 if (len1 == len2)
1756 switch (sz)
1758 case 1:
1759 return memcmp(string, se2.string, len1);
1761 case 2:
1763 wchar* s1 = cast(wchar*)string;
1764 wchar* s2 = cast(wchar*)se2.string;
1765 foreach (u; 0 .. len)
1767 if (s1[u] != s2[u])
1768 return s1[u] - s2[u];
1771 break;
1772 case 4:
1774 dchar* s1 = cast(dchar*)string;
1775 dchar* s2 = cast(dchar*)se2.string;
1776 foreach (u; 0 .. len)
1778 if (s1[u] != s2[u])
1779 return s1[u] - s2[u];
1782 break;
1783 default:
1784 assert(0);
1787 return cast(int)(len1 - len2);
1790 override Optional!bool toBool()
1792 // Keep the old behaviour for this refactoring
1793 // Should probably match language spec instead and check for length
1794 return typeof(return)(true);
1797 override bool isLvalue()
1799 /* string literal is rvalue in default, but
1800 * conversion to reference of static array is only allowed.
1802 return (type && type.toBasetype().ty == Tsarray);
1805 /********************************
1806 * Convert string contents to a 0 terminated string,
1807 * allocated by mem.xmalloc().
1809 extern (D) const(char)[] toStringz() const
1811 auto nbytes = len * sz;
1812 char* s = cast(char*)mem.xmalloc(nbytes + sz);
1813 writeTo(s, true);
1814 return s[0 .. nbytes];
1817 extern (D) const(char)[] peekString() const
1819 assert(sz == 1);
1820 return this.string[0 .. len];
1823 extern (D) const(wchar)[] peekWstring() const
1825 assert(sz == 2);
1826 return this.wstring[0 .. len];
1829 extern (D) const(dchar)[] peekDstring() const
1831 assert(sz == 4);
1832 return this.dstring[0 .. len];
1835 /*******************
1836 * Get a slice of the data.
1838 extern (D) const(ubyte)[] peekData() const
1840 return cast(const(ubyte)[])this.string[0 .. len * sz];
1843 /*******************
1844 * Borrow a slice of the data, so the caller can modify
1845 * it in-place (!)
1847 extern (D) ubyte[] borrowData()
1849 return cast(ubyte[])this.string[0 .. len * sz];
1852 /***********************
1853 * Set new string data.
1854 * `this` becomes the new owner of the data.
1856 extern (D) void setData(void* s, size_t len, ubyte sz)
1858 this.string = cast(char*)s;
1859 this.len = len;
1860 this.sz = sz;
1863 override void accept(Visitor v)
1865 v.visit(this);
1869 extern (C++) final class InterpExp : Expression
1871 char postfix = NoPostfix; // 'c', 'w', 'd'
1872 OwnedBy ownedByCtfe = OwnedBy.code;
1873 InterpolatedSet* interpolatedSet;
1875 enum char NoPostfix = 0;
1877 extern (D) this(const ref Loc loc, InterpolatedSet* set, char postfix = NoPostfix) scope
1879 super(loc, EXP.interpolated);
1880 this.interpolatedSet = set;
1881 this.postfix = postfix;
1884 override void accept(Visitor v)
1886 v.visit(this);
1891 /***********************************************************
1892 * A sequence of expressions
1894 * ---
1895 * alias AliasSeq(T...) = T;
1896 * alias Tup = AliasSeq!(3, int, "abc");
1897 * ---
1899 extern (C++) final class TupleExp : Expression
1901 /* Tuple-field access may need to take out its side effect part.
1902 * For example:
1903 * foo().tupleof
1904 * is rewritten as:
1905 * (ref __tup = foo(); tuple(__tup.field0, __tup.field1, ...))
1906 * The declaration of temporary variable __tup will be stored in TupleExp.e0.
1908 Expression e0;
1910 Expressions* exps;
1912 extern (D) this(const ref Loc loc, Expression e0, Expressions* exps) @safe
1914 super(loc, EXP.tuple);
1915 //printf("TupleExp(this = %p)\n", this);
1916 this.e0 = e0;
1917 this.exps = exps;
1920 extern (D) this(const ref Loc loc, Expressions* exps) @safe
1922 super(loc, EXP.tuple);
1923 //printf("TupleExp(this = %p)\n", this);
1924 this.exps = exps;
1927 extern (D) this(const ref Loc loc, TupleDeclaration tup)
1929 super(loc, EXP.tuple);
1930 this.exps = new Expressions();
1932 this.exps.reserve(tup.objects.length);
1933 foreach (o; *tup.objects)
1935 if (Dsymbol s = getDsymbol(o))
1937 /* If tuple element represents a symbol, translate to DsymbolExp
1938 * to supply implicit 'this' if needed later.
1940 Expression e = new DsymbolExp(loc, s);
1941 this.exps.push(e);
1943 else if (auto eo = o.isExpression())
1945 auto e = eo.copy();
1946 e.loc = loc; // https://issues.dlang.org/show_bug.cgi?id=15669
1947 this.exps.push(e);
1949 else if (auto t = o.isType())
1951 Expression e = new TypeExp(loc, t);
1952 this.exps.push(e);
1954 else
1956 error(loc, "`%s` is not an expression", o.toChars());
1961 static TupleExp create(const ref Loc loc, Expressions* exps) @safe
1963 return new TupleExp(loc, exps);
1966 override TupleExp syntaxCopy()
1968 return new TupleExp(loc, e0 ? e0.syntaxCopy() : null, arraySyntaxCopy(exps));
1971 override bool equals(const RootObject o) const
1973 if (this == o)
1974 return true;
1975 if (auto e = o.isExpression())
1976 if (auto te = e.isTupleExp())
1978 if (exps.length != te.exps.length)
1979 return false;
1980 if (e0 && !e0.equals(te.e0) || !e0 && te.e0)
1981 return false;
1982 foreach (i, e1; *exps)
1984 auto e2 = (*te.exps)[i];
1985 if (!e1.equals(e2))
1986 return false;
1988 return true;
1990 return false;
1993 override void accept(Visitor v)
1995 v.visit(this);
1999 /***********************************************************
2000 * [ e1, e2, e3, ... ]
2002 * https://dlang.org/spec/expression.html#array_literals
2004 extern (C++) final class ArrayLiteralExp : Expression
2006 OwnedBy ownedByCtfe = OwnedBy.code;
2007 bool onstack = false;
2009 /** If !is null, elements[] can be sparse and basis is used for the
2010 * "default" element value. In other words, non-null elements[i] overrides
2011 * this 'basis' value.
2013 Expression basis;
2015 Expressions* elements;
2017 extern (D) this(const ref Loc loc, Type type, Expressions* elements) @safe
2019 super(loc, EXP.arrayLiteral);
2020 this.type = type;
2021 this.elements = elements;
2024 extern (D) this(const ref Loc loc, Type type, Expression e)
2026 super(loc, EXP.arrayLiteral);
2027 this.type = type;
2028 elements = new Expressions();
2029 elements.push(e);
2032 extern (D) this(const ref Loc loc, Type type, Expression basis, Expressions* elements) @safe
2034 super(loc, EXP.arrayLiteral);
2035 this.type = type;
2036 this.basis = basis;
2037 this.elements = elements;
2040 static ArrayLiteralExp create(const ref Loc loc, Expressions* elements) @safe
2042 return new ArrayLiteralExp(loc, null, elements);
2045 override ArrayLiteralExp syntaxCopy()
2047 return new ArrayLiteralExp(loc,
2048 null,
2049 basis ? basis.syntaxCopy() : null,
2050 arraySyntaxCopy(elements));
2053 override bool equals(const RootObject o) const
2055 if (this == o)
2056 return true;
2057 auto e = o.isExpression();
2058 if (!e)
2059 return false;
2060 if (auto ae = e.isArrayLiteralExp())
2062 if (elements.length != ae.elements.length)
2063 return false;
2064 if (elements.length == 0 && !type.equals(ae.type))
2066 return false;
2069 foreach (i, e1; *elements)
2071 auto e2 = (*ae.elements)[i];
2072 auto e1x = e1 ? e1 : basis;
2073 auto e2x = e2 ? e2 : ae.basis;
2075 if (e1x != e2x && (!e1x || !e2x || !e1x.equals(e2x)))
2076 return false;
2078 return true;
2080 return false;
2083 Expression getElement(size_t i) // use opIndex instead
2085 return this[i];
2088 extern (D) Expression opIndex(size_t i)
2090 auto el = (*elements)[i];
2091 return el ? el : basis;
2094 override Optional!bool toBool()
2096 size_t dim = elements ? elements.length : 0;
2097 return typeof(return)(dim != 0);
2100 override StringExp toStringExp()
2102 TY telem = type.nextOf().toBasetype().ty;
2103 if (telem.isSomeChar || (telem == Tvoid && (!elements || elements.length == 0)))
2105 ubyte sz = 1;
2106 if (telem == Twchar)
2107 sz = 2;
2108 else if (telem == Tdchar)
2109 sz = 4;
2111 OutBuffer buf;
2112 if (elements)
2114 foreach (i; 0 .. elements.length)
2116 auto ch = this[i];
2117 if (ch.op != EXP.int64)
2118 return null;
2119 if (sz == 1)
2120 buf.writeByte(cast(uint)ch.toInteger());
2121 else if (sz == 2)
2122 buf.writeword(cast(uint)ch.toInteger());
2123 else
2124 buf.write4(cast(uint)ch.toInteger());
2127 char prefix;
2128 if (sz == 1)
2130 prefix = 'c';
2131 buf.writeByte(0);
2133 else if (sz == 2)
2135 prefix = 'w';
2136 buf.writeword(0);
2138 else
2140 prefix = 'd';
2141 buf.write4(0);
2144 const size_t len = buf.length / sz - 1;
2145 auto se = new StringExp(loc, buf.extractSlice()[0 .. len * sz], len, sz, prefix);
2146 se.sz = sz;
2147 se.type = type;
2148 return se;
2150 return null;
2153 override void accept(Visitor v)
2155 v.visit(this);
2159 /***********************************************************
2160 * [ key0 : value0, key1 : value1, ... ]
2162 * https://dlang.org/spec/expression.html#associative_array_literals
2164 extern (C++) final class AssocArrayLiteralExp : Expression
2166 OwnedBy ownedByCtfe = OwnedBy.code;
2168 Expressions* keys;
2169 Expressions* values;
2170 /// Lower to core.internal.newaa for static initializaton
2171 Expression lowering;
2173 extern (D) this(const ref Loc loc, Expressions* keys, Expressions* values) @safe
2175 super(loc, EXP.assocArrayLiteral);
2176 assert(keys.length == values.length);
2177 this.keys = keys;
2178 this.values = values;
2181 override bool equals(const RootObject o) const
2183 if (this == o)
2184 return true;
2185 auto e = o.isExpression();
2186 if (!e)
2187 return false;
2188 if (auto ae = e.isAssocArrayLiteralExp())
2190 if (keys.length != ae.keys.length)
2191 return false;
2192 size_t count = 0;
2193 foreach (i, key; *keys)
2195 foreach (j, akey; *ae.keys)
2197 if (key.equals(akey))
2199 if (!(*values)[i].equals((*ae.values)[j]))
2200 return false;
2201 ++count;
2205 return count == keys.length;
2207 return false;
2210 override AssocArrayLiteralExp syntaxCopy()
2212 return new AssocArrayLiteralExp(loc, arraySyntaxCopy(keys), arraySyntaxCopy(values));
2215 override Optional!bool toBool()
2217 size_t dim = keys.length;
2218 return typeof(return)(dim != 0);
2221 override void accept(Visitor v)
2223 v.visit(this);
2227 enum stageScrub = 0x1; /// scrubReturnValue is running
2228 enum stageSearchPointers = 0x2; /// hasNonConstPointers is running
2229 enum stageOptimize = 0x4; /// optimize is running
2230 enum stageApply = 0x8; /// apply is running
2231 enum stageInlineScan = 0x10; /// inlineScan is running
2232 enum stageToCBuffer = 0x20; /// toCBuffer is running
2234 /***********************************************************
2235 * sd( e1, e2, e3, ... )
2237 extern (C++) final class StructLiteralExp : Expression
2239 StructDeclaration sd; /// which aggregate this is for
2240 Expressions* elements; /// parallels sd.fields[] with null entries for fields to skip
2241 Type stype; /// final type of result (can be different from sd's type)
2243 // `inlineCopy` is only used temporarily in the `inline.d` pass,
2244 // while `sym` is only used in `e2ir/s2ir/tocsym` which comes after
2245 union
2247 void* sym; /// back end symbol to initialize with literal (used as a Symbol*)
2249 /// those fields need to prevent a infinite recursion when one field of struct initialized with 'this' pointer.
2250 StructLiteralExp inlinecopy;
2253 /** pointer to the origin instance of the expression.
2254 * once a new expression is created, origin is set to 'this'.
2255 * anytime when an expression copy is created, 'origin' pointer is set to
2256 * 'origin' pointer value of the original expression.
2258 StructLiteralExp origin;
2261 /** anytime when recursive function is calling, 'stageflags' marks with bit flag of
2262 * current stage and unmarks before return from this function.
2263 * 'inlinecopy' uses similar 'stageflags' and from multiple evaluation 'doInline'
2264 * (with infinite recursion) of this expression.
2266 ubyte stageflags;
2268 bool useStaticInit; /// if this is true, use the StructDeclaration's init symbol
2269 bool isOriginal = false; /// used when moving instances to indicate `this is this.origin`
2270 OwnedBy ownedByCtfe = OwnedBy.code;
2272 extern (D) this(const ref Loc loc, StructDeclaration sd, Expressions* elements, Type stype = null) @safe
2274 super(loc, EXP.structLiteral);
2275 this.sd = sd;
2276 if (!elements)
2277 elements = new Expressions();
2278 this.elements = elements;
2279 this.stype = stype;
2280 this.origin = this;
2281 //printf("StructLiteralExp::StructLiteralExp(%s)\n", toChars());
2284 static StructLiteralExp create(const ref Loc loc, StructDeclaration sd, void* elements, Type stype = null)
2286 return new StructLiteralExp(loc, sd, cast(Expressions*)elements, stype);
2289 override bool equals(const RootObject o) const
2291 if (this == o)
2292 return true;
2293 auto e = o.isExpression();
2294 if (!e)
2295 return false;
2296 if (auto se = e.isStructLiteralExp())
2298 if (!type.equals(se.type))
2299 return false;
2300 if (elements.length != se.elements.length)
2301 return false;
2302 foreach (i, e1; *elements)
2304 auto e2 = (*se.elements)[i];
2305 if (e1 != e2 && (!e1 || !e2 || !e1.equals(e2)))
2306 return false;
2308 return true;
2310 return false;
2313 override StructLiteralExp syntaxCopy()
2315 auto exp = new StructLiteralExp(loc, sd, arraySyntaxCopy(elements), type ? type : stype);
2316 exp.origin = this;
2317 return exp;
2320 /**************************************
2321 * Gets expression at offset of type.
2322 * Returns NULL if not found.
2324 extern (D) Expression getField(Type type, uint offset)
2326 //printf("StructLiteralExp::getField(this = %s, type = %s, offset = %u)\n",
2327 // /*toChars()*/"", type.toChars(), offset);
2328 Expression e = null;
2329 int i = getFieldIndex(type, offset);
2331 if (i != -1)
2333 //printf("\ti = %d\n", i);
2334 if (i >= sd.nonHiddenFields())
2335 return null;
2337 assert(i < elements.length);
2338 e = (*elements)[i];
2339 if (e)
2341 //printf("e = %s, e.type = %s\n", e.toChars(), e.type.toChars());
2343 /* If type is a static array, and e is an initializer for that array,
2344 * then the field initializer should be an array literal of e.
2346 auto tsa = type.isTypeSArray();
2347 if (tsa && e.type.castMod(0) != type.castMod(0))
2349 const length = cast(size_t)tsa.dim.toInteger();
2350 auto z = new Expressions(length);
2351 foreach (ref q; *z)
2352 q = e.copy();
2353 e = new ArrayLiteralExp(loc, type, z);
2355 else
2357 e = e.copy();
2358 e.type = type;
2360 if (useStaticInit && e.type.needsNested())
2361 if (auto se = e.isStructLiteralExp())
2363 se.useStaticInit = true;
2367 return e;
2370 /************************************
2371 * Get index of field.
2372 * Returns -1 if not found.
2374 extern (D) int getFieldIndex(Type type, uint offset)
2376 /* Find which field offset is by looking at the field offsets
2378 if (elements.length)
2380 const sz = type.size();
2381 if (sz == SIZE_INVALID)
2382 return -1;
2383 foreach (i, v; sd.fields)
2385 if (offset == v.offset && sz == v.type.size())
2387 /* context fields might not be filled. */
2388 if (i >= sd.nonHiddenFields())
2389 return cast(int)i;
2390 if (auto e = (*elements)[i])
2392 return cast(int)i;
2394 break;
2398 return -1;
2401 override void accept(Visitor v)
2403 v.visit(this);
2407 /***********************************************************
2408 * C11 6.5.2.5
2409 * ( type-name ) { initializer-list }
2411 extern (C++) final class CompoundLiteralExp : Expression
2413 Initializer initializer; /// initializer-list
2415 extern (D) this(const ref Loc loc, Type type_name, Initializer initializer) @safe
2417 super(loc, EXP.compoundLiteral);
2418 super.type = type_name;
2419 this.initializer = initializer;
2420 //printf("CompoundLiteralExp::CompoundLiteralExp(%s)\n", toChars());
2423 override void accept(Visitor v)
2425 v.visit(this);
2429 /***********************************************************
2430 * Mainly just a placeholder
2432 extern (C++) final class TypeExp : Expression
2434 bool parens; // if this is a parenthesized expression
2436 extern (D) this(const ref Loc loc, Type type) @safe
2438 super(loc, EXP.type);
2439 //printf("TypeExp::TypeExp(%s)\n", type.toChars());
2440 this.type = type;
2443 override TypeExp syntaxCopy()
2445 return new TypeExp(loc, type.syntaxCopy());
2448 override bool checkType()
2450 error(loc, "type `%s` is not an expression", toChars());
2451 return true;
2454 override bool checkValue()
2456 error(loc, "type `%s` has no value", toChars());
2457 return true;
2460 override void accept(Visitor v)
2462 v.visit(this);
2466 /***********************************************************
2467 * Mainly just a placeholder of
2468 * Package, Module, Nspace, and TemplateInstance (including TemplateMixin)
2470 * A template instance that requires IFTI:
2471 * foo!tiargs(fargs) // foo!tiargs
2472 * is left until CallExp::semantic() or resolveProperties()
2474 extern (C++) final class ScopeExp : Expression
2476 ScopeDsymbol sds;
2478 extern (D) this(const ref Loc loc, ScopeDsymbol sds) @safe
2480 super(loc, EXP.scope_);
2481 //printf("ScopeExp::ScopeExp(sds = '%s')\n", sds.toChars());
2482 //static int count; if (++count == 38) *(char*)0=0;
2483 this.sds = sds;
2484 assert(!sds.isTemplateDeclaration()); // instead, you should use TemplateExp
2487 override ScopeExp syntaxCopy()
2489 return new ScopeExp(loc, sds.syntaxCopy(null));
2492 override bool checkType()
2494 if (sds.isPackage())
2496 error(loc, "%s `%s` has no type", sds.kind(), sds.toChars());
2497 return true;
2499 if (auto ti = sds.isTemplateInstance())
2501 //assert(ti.needsTypeInference(sc));
2502 if (ti.tempdecl &&
2503 ti.semantictiargsdone &&
2504 ti.semanticRun == PASS.initial)
2506 error(loc, "partial %s `%s` has no type", sds.kind(), toChars());
2507 return true;
2510 return false;
2513 override bool checkValue()
2515 error(loc, "%s `%s` has no value", sds.kind(), sds.toChars());
2516 return true;
2519 override void accept(Visitor v)
2521 v.visit(this);
2525 /***********************************************************
2526 * Mainly just a placeholder
2528 extern (C++) final class TemplateExp : Expression
2530 TemplateDeclaration td;
2531 FuncDeclaration fd;
2533 extern (D) this(const ref Loc loc, TemplateDeclaration td, FuncDeclaration fd = null) @safe
2535 super(loc, EXP.template_);
2536 //printf("TemplateExp(): %s\n", td.toChars());
2537 this.td = td;
2538 this.fd = fd;
2541 override bool isLvalue()
2543 return fd !is null;
2546 override bool checkType()
2548 error(loc, "%s `%s` has no type", td.kind(), toChars());
2549 return true;
2552 override bool checkValue()
2554 error(loc, "%s `%s` has no value", td.kind(), toChars());
2555 return true;
2558 override void accept(Visitor v)
2560 v.visit(this);
2564 /***********************************************************
2565 * newtype(arguments)
2567 extern (C++) final class NewExp : Expression
2569 Expression thisexp; // if !=null, 'this' for class being allocated
2570 Type newtype;
2571 Expressions* arguments; // Array of Expression's
2572 Identifiers* names; // Array of names corresponding to expressions
2574 Expression argprefix; // expression to be evaluated just before arguments[]
2575 CtorDeclaration member; // constructor function
2576 bool onstack; // allocate on stack
2577 bool thrownew; // this NewExp is the expression of a ThrowStatement
2579 Expression lowering; // lowered druntime hook: `_d_new{class,itemT}`
2581 /// Puts the `arguments` and `names` into an `ArgumentList` for easily passing them around.
2582 /// The fields are still separate for backwards compatibility
2583 extern (D) ArgumentList argumentList() { return ArgumentList(arguments, names); }
2585 extern (D) this(const ref Loc loc, Expression thisexp, Type newtype, Expressions* arguments, Identifiers* names = null) @safe
2587 super(loc, EXP.new_);
2588 this.thisexp = thisexp;
2589 this.newtype = newtype;
2590 this.arguments = arguments;
2591 this.names = names;
2594 static NewExp create(const ref Loc loc, Expression thisexp, Type newtype, Expressions* arguments) @safe
2596 return new NewExp(loc, thisexp, newtype, arguments);
2599 override NewExp syntaxCopy()
2601 return new NewExp(loc,
2602 thisexp ? thisexp.syntaxCopy() : null,
2603 newtype.syntaxCopy(),
2604 arraySyntaxCopy(arguments),
2605 names ? names.copy() : null);
2608 override void accept(Visitor v)
2610 v.visit(this);
2614 /***********************************************************
2615 * class baseclasses { } (arguments)
2617 extern (C++) final class NewAnonClassExp : Expression
2619 Expression thisexp; // if !=null, 'this' for class being allocated
2620 ClassDeclaration cd; // class being instantiated
2621 Expressions* arguments; // Array of Expression's to call class constructor
2623 extern (D) this(const ref Loc loc, Expression thisexp, ClassDeclaration cd, Expressions* arguments) @safe
2625 super(loc, EXP.newAnonymousClass);
2626 this.thisexp = thisexp;
2627 this.cd = cd;
2628 this.arguments = arguments;
2631 override NewAnonClassExp syntaxCopy()
2633 return new NewAnonClassExp(loc, thisexp ? thisexp.syntaxCopy() : null, cd.syntaxCopy(null), arraySyntaxCopy(arguments));
2636 override void accept(Visitor v)
2638 v.visit(this);
2642 /***********************************************************
2644 extern (C++) class SymbolExp : Expression
2646 Declaration var;
2647 Dsymbol originalScope; // original scope before inlining
2648 bool hasOverloads;
2650 extern (D) this(const ref Loc loc, EXP op, Declaration var, bool hasOverloads) @safe
2652 super(loc, op);
2653 assert(var);
2654 this.var = var;
2655 this.hasOverloads = hasOverloads;
2658 override void accept(Visitor v)
2660 v.visit(this);
2664 /***********************************************************
2665 * Offset from symbol
2667 extern (C++) final class SymOffExp : SymbolExp
2669 dinteger_t offset;
2671 extern (D) this(const ref Loc loc, Declaration var, dinteger_t offset, bool hasOverloads = true)
2673 if (auto v = var.isVarDeclaration())
2675 // FIXME: This error report will never be handled anyone.
2676 // It should be done before the SymOffExp construction.
2677 if (v.needThis())
2679 auto t = v.isThis();
2680 assert(t);
2681 .error(loc, "taking the address of non-static variable `%s` requires an instance of `%s`", v.toChars(), t.toChars());
2683 hasOverloads = false;
2685 super(loc, EXP.symbolOffset, var, hasOverloads);
2686 this.offset = offset;
2689 override Optional!bool toBool()
2691 return typeof(return)(true);
2694 override void accept(Visitor v)
2696 v.visit(this);
2700 /***********************************************************
2701 * Variable
2703 extern (C++) final class VarExp : SymbolExp
2705 bool delegateWasExtracted;
2706 extern (D) this(const ref Loc loc, Declaration var, bool hasOverloads = true) @safe
2708 if (var.isVarDeclaration())
2709 hasOverloads = false;
2711 super(loc, EXP.variable, var, hasOverloads);
2712 //printf("VarExp(this = %p, '%s', loc = %s)\n", this, var.toChars(), loc.toChars());
2713 //if (strcmp(var.ident.toChars(), "func") == 0) assert(0);
2714 this.type = var.type;
2717 static VarExp create(const ref Loc loc, Declaration var, bool hasOverloads = true) @safe
2719 return new VarExp(loc, var, hasOverloads);
2722 override bool equals(const RootObject o) const
2724 if (this == o)
2725 return true;
2726 if (auto ne = o.isExpression().isVarExp())
2728 if (type.toHeadMutable().equals(ne.type.toHeadMutable()) && var == ne.var)
2730 return true;
2733 return false;
2736 override bool isLvalue()
2738 if (var.storage_class & (STC.lazy_ | STC.rvalue | STC.manifest))
2739 return false;
2740 return true;
2743 override void accept(Visitor v)
2745 v.visit(this);
2749 /***********************************************************
2750 * Overload Set
2752 extern (C++) final class OverExp : Expression
2754 OverloadSet vars;
2756 extern (D) this(const ref Loc loc, OverloadSet s)
2758 super(loc, EXP.overloadSet);
2759 //printf("OverExp(this = %p, '%s')\n", this, var.toChars());
2760 vars = s;
2761 type = Type.tvoid;
2764 override bool isLvalue()
2766 return true;
2769 override void accept(Visitor v)
2771 v.visit(this);
2775 /***********************************************************
2776 * Function/Delegate literal
2779 extern (C++) final class FuncExp : Expression
2781 FuncLiteralDeclaration fd;
2782 TemplateDeclaration td;
2783 TOK tok; // TOK.reserved, TOK.delegate_, TOK.function_
2785 extern (D) this(const ref Loc loc, Dsymbol s)
2787 super(loc, EXP.function_);
2788 this.td = s.isTemplateDeclaration();
2789 this.fd = s.isFuncLiteralDeclaration();
2790 if (td)
2792 assert(td.literal);
2793 assert(td.members && td.members.length == 1);
2794 fd = (*td.members)[0].isFuncLiteralDeclaration();
2796 tok = fd.tok; // save original kind of function/delegate/(infer)
2797 assert(fd.fbody);
2800 override bool equals(const RootObject o) const
2802 if (this == o)
2803 return true;
2804 auto e = o.isExpression();
2805 if (!e)
2806 return false;
2807 if (auto fe = e.isFuncExp())
2809 return fd == fe.fd;
2811 return false;
2814 override FuncExp syntaxCopy()
2816 if (td)
2817 return new FuncExp(loc, td.syntaxCopy(null));
2818 else if (fd.semanticRun == PASS.initial)
2819 return new FuncExp(loc, fd.syntaxCopy(null));
2820 else // https://issues.dlang.org/show_bug.cgi?id=13481
2821 // Prevent multiple semantic analysis of lambda body.
2822 return new FuncExp(loc, fd);
2825 override const(char)* toChars() const
2827 return fd.toChars();
2830 override bool checkType()
2832 if (td)
2834 error(loc, "template lambda has no type");
2835 return true;
2837 return false;
2840 override bool checkValue()
2842 if (td)
2844 error(loc, "template lambda has no value");
2845 return true;
2847 return false;
2850 override void accept(Visitor v)
2852 v.visit(this);
2856 /***********************************************************
2857 * Declaration of a symbol
2859 * D grammar allows declarations only as statements. However in AST representation
2860 * it can be part of any expression. This is used, for example, during internal
2861 * syntax re-writes to inject hidden symbols.
2863 extern (C++) final class DeclarationExp : Expression
2865 Dsymbol declaration;
2867 extern (D) this(const ref Loc loc, Dsymbol declaration) @safe
2869 super(loc, EXP.declaration);
2870 this.declaration = declaration;
2873 override DeclarationExp syntaxCopy()
2875 return new DeclarationExp(loc, declaration.syntaxCopy(null));
2878 override bool hasCode()
2880 if (auto vd = declaration.isVarDeclaration())
2882 return !(vd.storage_class & (STC.manifest | STC.static_));
2884 return false;
2887 override void accept(Visitor v)
2889 v.visit(this);
2893 /***********************************************************
2894 * typeid(int)
2896 extern (C++) final class TypeidExp : Expression
2898 RootObject obj;
2900 extern (D) this(const ref Loc loc, RootObject o) @safe
2902 super(loc, EXP.typeid_);
2903 this.obj = o;
2906 override TypeidExp syntaxCopy()
2908 return new TypeidExp(loc, objectSyntaxCopy(obj));
2911 override void accept(Visitor v)
2913 v.visit(this);
2917 /***********************************************************
2918 * __traits(identifier, args...)
2920 extern (C++) final class TraitsExp : Expression
2922 Identifier ident;
2923 Objects* args;
2925 extern (D) this(const ref Loc loc, Identifier ident, Objects* args) @safe
2927 super(loc, EXP.traits);
2928 this.ident = ident;
2929 this.args = args;
2932 override TraitsExp syntaxCopy()
2934 return new TraitsExp(loc, ident, TemplateInstance.arraySyntaxCopy(args));
2937 override void accept(Visitor v)
2939 v.visit(this);
2943 /***********************************************************
2944 * Generates a halt instruction
2946 * `assert(0)` gets rewritten to this with `CHECKACTION.halt`
2948 extern (C++) final class HaltExp : Expression
2950 extern (D) this(const ref Loc loc) @safe
2952 super(loc, EXP.halt);
2955 override void accept(Visitor v)
2957 v.visit(this);
2961 /***********************************************************
2962 * is(targ id tok tspec)
2963 * is(targ id == tok2)
2965 extern (C++) final class IsExp : Expression
2967 Type targ;
2968 Identifier id; // can be null
2969 Type tspec; // can be null
2970 TemplateParameters* parameters;
2971 TOK tok; // ':' or '=='
2972 TOK tok2; // 'struct', 'union', etc.
2974 extern (D) this(const ref Loc loc, Type targ, Identifier id, TOK tok, Type tspec, TOK tok2, TemplateParameters* parameters) scope @safe
2976 super(loc, EXP.is_);
2977 this.targ = targ;
2978 this.id = id;
2979 this.tok = tok;
2980 this.tspec = tspec;
2981 this.tok2 = tok2;
2982 this.parameters = parameters;
2985 override IsExp syntaxCopy()
2987 // This section is identical to that in TemplateDeclaration::syntaxCopy()
2988 TemplateParameters* p = null;
2989 if (parameters)
2991 p = new TemplateParameters(parameters.length);
2992 foreach (i, el; *parameters)
2993 (*p)[i] = el.syntaxCopy();
2995 return new IsExp(loc, targ.syntaxCopy(), id, tok, tspec ? tspec.syntaxCopy() : null, tok2, p);
2998 override void accept(Visitor v)
3000 v.visit(this);
3004 /***********************************************************
3005 * Base class for unary operators
3007 * https://dlang.org/spec/expression.html#unary-expression
3009 extern (C++) abstract class UnaExp : Expression
3011 Expression e1;
3013 extern (D) this(const ref Loc loc, EXP op, Expression e1) scope @safe
3015 super(loc, op);
3016 this.e1 = e1;
3019 override UnaExp syntaxCopy()
3021 UnaExp e = cast(UnaExp)copy();
3022 e.type = null;
3023 e.e1 = e.e1.syntaxCopy();
3024 return e;
3027 /********************************
3028 * The type for a unary expression is incompatible.
3029 * Print error message.
3030 * Returns:
3031 * ErrorExp
3033 extern (D) final Expression incompatibleTypes()
3035 if (e1.type.toBasetype() == Type.terror)
3036 return e1;
3038 if (e1.op == EXP.type)
3040 error(loc, "incompatible type for `%s(%s)`: cannot use `%s` with types", EXPtoString(op).ptr, e1.toChars(), EXPtoString(op).ptr);
3042 else
3044 error(loc, "incompatible type for `%s(%s)`: `%s`", EXPtoString(op).ptr, e1.toChars(), e1.type.toChars());
3046 return ErrorExp.get();
3049 /*********************
3050 * Mark the operand as will never be dereferenced,
3051 * which is useful info for @safe checks.
3052 * Do before semantic() on operands rewrites them.
3054 final void setNoderefOperand()
3056 if (auto edi = e1.isDotIdExp())
3057 edi.noderef = true;
3061 override void accept(Visitor v)
3063 v.visit(this);
3067 /***********************************************************
3068 * Base class for binary operators
3070 extern (C++) abstract class BinExp : Expression
3072 Expression e1;
3073 Expression e2;
3074 Type att1; // Save alias this type to detect recursion
3075 Type att2; // Save alias this type to detect recursion
3077 extern (D) this(const ref Loc loc, EXP op, Expression e1, Expression e2) scope @safe
3079 super(loc, op);
3080 this.e1 = e1;
3081 this.e2 = e2;
3084 override BinExp syntaxCopy()
3086 BinExp e = cast(BinExp)copy();
3087 e.type = null;
3088 e.e1 = e.e1.syntaxCopy();
3089 e.e2 = e.e2.syntaxCopy();
3090 return e;
3093 /********************************
3094 * The types for a binary expression are incompatible.
3095 * Print error message.
3096 * Returns:
3097 * ErrorExp
3099 extern (D) final Expression incompatibleTypes()
3101 if (e1.type.toBasetype() == Type.terror)
3102 return e1;
3103 if (e2.type.toBasetype() == Type.terror)
3104 return e2;
3106 // CondExp uses 'a ? b : c' but we're comparing 'b : c'
3107 const(char)* thisOp = (op == EXP.question) ? ":" : EXPtoString(op).ptr;
3108 if (e1.op == EXP.type || e2.op == EXP.type)
3110 error(loc, "incompatible types for `(%s) %s (%s)`: cannot use `%s` with types",
3111 e1.toChars(), thisOp, e2.toChars(), EXPtoString(op).ptr);
3113 else if (e1.type.equals(e2.type))
3115 error(loc, "incompatible types for `(%s) %s (%s)`: both operands are of type `%s`",
3116 e1.toChars(), thisOp, e2.toChars(), e1.type.toChars());
3118 else
3120 auto ts = toAutoQualChars(e1.type, e2.type);
3121 error(loc, "incompatible types for `(%s) %s (%s)`: `%s` and `%s`",
3122 e1.toChars(), thisOp, e2.toChars(), ts[0], ts[1]);
3124 return ErrorExp.get();
3127 extern (D) final bool checkIntegralBin()
3129 bool r1 = e1.checkIntegral();
3130 bool r2 = e2.checkIntegral();
3131 return (r1 || r2);
3134 extern (D) final bool checkArithmeticBin()
3136 bool r1 = e1.checkArithmetic(this.op);
3137 bool r2 = e2.checkArithmetic(this.op);
3138 return (r1 || r2);
3141 /*********************
3142 * Mark the operands as will never be dereferenced,
3143 * which is useful info for @safe checks.
3144 * Do before semantic() on operands rewrites them.
3146 final void setNoderefOperands()
3148 if (auto edi = e1.isDotIdExp())
3149 edi.noderef = true;
3150 if (auto edi = e2.isDotIdExp())
3151 edi.noderef = true;
3155 override void accept(Visitor v)
3157 v.visit(this);
3161 /***********************************************************
3162 * Binary operator assignment, `+=` `-=` `*=` etc.
3164 extern (C++) class BinAssignExp : BinExp
3166 extern (D) this(const ref Loc loc, EXP op, Expression e1, Expression e2) scope @safe
3168 super(loc, op, e1, e2);
3171 override final bool isLvalue()
3173 return true;
3176 override void accept(Visitor v)
3178 v.visit(this);
3182 /***********************************************************
3183 * A string mixin, `mixin("x")`
3185 * https://dlang.org/spec/expression.html#mixin_expressions
3187 extern (C++) final class MixinExp : Expression
3189 Expressions* exps;
3191 extern (D) this(const ref Loc loc, Expressions* exps) @safe
3193 super(loc, EXP.mixin_);
3194 this.exps = exps;
3197 override MixinExp syntaxCopy()
3199 return new MixinExp(loc, arraySyntaxCopy(exps));
3202 override bool equals(const RootObject o) const
3204 if (this == o)
3205 return true;
3206 auto e = o.isExpression();
3207 if (!e)
3208 return false;
3209 if (auto ce = e.isMixinExp())
3211 if (exps.length != ce.exps.length)
3212 return false;
3213 foreach (i, e1; *exps)
3215 auto e2 = (*ce.exps)[i];
3216 if (e1 != e2 && (!e1 || !e2 || !e1.equals(e2)))
3217 return false;
3219 return true;
3221 return false;
3224 override void accept(Visitor v)
3226 v.visit(this);
3230 /***********************************************************
3231 * An import expression, `import("file.txt")`
3233 * Not to be confused with module imports, `import std.stdio`, which is an `ImportStatement`
3235 * https://dlang.org/spec/expression.html#import_expressions
3237 extern (C++) final class ImportExp : UnaExp
3239 extern (D) this(const ref Loc loc, Expression e) @safe
3241 super(loc, EXP.import_, e);
3244 override void accept(Visitor v)
3246 v.visit(this);
3250 /***********************************************************
3251 * An assert expression, `assert(x == y)`
3253 * https://dlang.org/spec/expression.html#assert_expressions
3255 extern (C++) final class AssertExp : UnaExp
3257 Expression msg;
3259 extern (D) this(const ref Loc loc, Expression e, Expression msg = null) @safe
3261 super(loc, EXP.assert_, e);
3262 this.msg = msg;
3265 override AssertExp syntaxCopy()
3267 return new AssertExp(loc, e1.syntaxCopy(), msg ? msg.syntaxCopy() : null);
3270 override void accept(Visitor v)
3272 v.visit(this);
3276 /***********************************************************
3277 * `throw <e1>` as proposed by DIP 1034.
3279 * Replacement for the deprecated `ThrowStatement` that can be nested
3280 * in other expression.
3282 extern (C++) final class ThrowExp : UnaExp
3284 extern (D) this(const ref Loc loc, Expression e)
3286 super(loc, EXP.throw_, e);
3287 this.type = Type.tnoreturn;
3290 override ThrowExp syntaxCopy()
3292 return new ThrowExp(loc, e1.syntaxCopy());
3295 override void accept(Visitor v)
3297 v.visit(this);
3301 /***********************************************************
3303 extern (C++) final class DotIdExp : UnaExp
3305 Identifier ident;
3306 bool noderef; // true if the result of the expression will never be dereferenced
3307 bool wantsym; // do not replace Symbol with its initializer during semantic()
3308 bool arrow; // ImportC: if -> instead of .
3310 extern (D) this(const ref Loc loc, Expression e, Identifier ident) @safe
3312 super(loc, EXP.dotIdentifier, e);
3313 this.ident = ident;
3316 static DotIdExp create(const ref Loc loc, Expression e, Identifier ident) @safe
3318 return new DotIdExp(loc, e, ident);
3321 override void accept(Visitor v)
3323 v.visit(this);
3327 /***********************************************************
3328 * Mainly just a placeholder
3330 extern (C++) final class DotTemplateExp : UnaExp
3332 TemplateDeclaration td;
3334 extern (D) this(const ref Loc loc, Expression e, TemplateDeclaration td) @safe
3336 super(loc, EXP.dotTemplateDeclaration, e);
3337 this.td = td;
3340 override bool checkType()
3342 error(loc, "%s `%s` has no type", td.kind(), toChars());
3343 return true;
3346 override bool checkValue()
3348 error(loc, "%s `%s` has no value", td.kind(), toChars());
3349 return true;
3352 override void accept(Visitor v)
3354 v.visit(this);
3358 /***********************************************************
3360 extern (C++) final class DotVarExp : UnaExp
3362 Declaration var;
3363 bool hasOverloads;
3365 extern (D) this(const ref Loc loc, Expression e, Declaration var, bool hasOverloads = true) @safe
3367 if (var.isVarDeclaration())
3368 hasOverloads = false;
3370 super(loc, EXP.dotVariable, e);
3371 //printf("DotVarExp()\n");
3372 this.var = var;
3373 this.hasOverloads = hasOverloads;
3376 override bool isLvalue()
3378 if (e1.op != EXP.structLiteral)
3379 return true;
3380 auto vd = var.isVarDeclaration();
3381 return !(vd && vd.isField());
3384 override void accept(Visitor v)
3386 v.visit(this);
3390 /***********************************************************
3391 * foo.bar!(args)
3393 extern (C++) final class DotTemplateInstanceExp : UnaExp
3395 TemplateInstance ti;
3397 extern (D) this(const ref Loc loc, Expression e, Identifier name, Objects* tiargs)
3399 super(loc, EXP.dotTemplateInstance, e);
3400 //printf("DotTemplateInstanceExp()\n");
3401 this.ti = new TemplateInstance(loc, name, tiargs);
3404 extern (D) this(const ref Loc loc, Expression e, TemplateInstance ti) @safe
3406 super(loc, EXP.dotTemplateInstance, e);
3407 this.ti = ti;
3410 override DotTemplateInstanceExp syntaxCopy()
3412 return new DotTemplateInstanceExp(loc, e1.syntaxCopy(), ti.name, TemplateInstance.arraySyntaxCopy(ti.tiargs));
3415 override bool checkType()
3417 // Same logic as ScopeExp.checkType()
3418 if (ti.tempdecl &&
3419 ti.semantictiargsdone &&
3420 ti.semanticRun == PASS.initial)
3422 error(loc, "partial %s `%s` has no type", ti.kind(), toChars());
3423 return true;
3425 return false;
3428 override bool checkValue()
3430 if (ti.tempdecl &&
3431 ti.semantictiargsdone &&
3432 ti.semanticRun == PASS.initial)
3434 error(loc, "partial %s `%s` has no value", ti.kind(), toChars());
3435 else
3436 error(loc, "%s `%s` has no value", ti.kind(), ti.toChars());
3437 return true;
3440 override void accept(Visitor v)
3442 v.visit(this);
3446 /***********************************************************
3448 extern (C++) final class DelegateExp : UnaExp
3450 FuncDeclaration func;
3451 bool hasOverloads;
3452 VarDeclaration vthis2; // container for multi-context
3454 extern (D) this(const ref Loc loc, Expression e, FuncDeclaration f, bool hasOverloads = true, VarDeclaration vthis2 = null) @safe
3456 super(loc, EXP.delegate_, e);
3457 this.func = f;
3458 this.hasOverloads = hasOverloads;
3459 this.vthis2 = vthis2;
3462 override void accept(Visitor v)
3464 v.visit(this);
3468 /***********************************************************
3470 extern (C++) final class DotTypeExp : UnaExp
3472 Dsymbol sym; // symbol that represents a type
3474 extern (D) this(const ref Loc loc, Expression e, Dsymbol s) @safe
3476 super(loc, EXP.dotType, e);
3477 this.sym = s;
3480 override void accept(Visitor v)
3482 v.visit(this);
3487 * The arguments of a function call
3489 * Contains a list of expressions. If it is a named argument, the `names`
3490 * list has a non-null entry at the same index.
3492 struct ArgumentList
3494 Expressions* arguments; // function arguments
3495 Identifiers* names; // named argument identifiers
3497 size_t length() const @nogc nothrow pure @safe { return arguments ? arguments.length : 0; }
3499 /// Returns: whether this argument list contains any named arguments
3500 bool hasNames() const @nogc nothrow pure @safe
3502 if (names is null)
3503 return false;
3504 foreach (name; *names)
3505 if (name !is null)
3506 return true;
3508 return false;
3512 /***********************************************************
3514 extern (C++) final class CallExp : UnaExp
3516 Expressions* arguments; // function arguments
3517 Identifiers* names; // named argument identifiers
3518 FuncDeclaration f; // symbol to call
3519 bool directcall; // true if a virtual call is devirtualized
3520 bool inDebugStatement; /// true if this was in a debug statement
3521 bool ignoreAttributes; /// don't enforce attributes (e.g. call @gc function in @nogc code)
3522 bool isUfcsRewrite; /// the first argument was pushed in here by a UFCS rewrite
3523 VarDeclaration vthis2; // container for multi-context
3525 /// Puts the `arguments` and `names` into an `ArgumentList` for easily passing them around.
3526 /// The fields are still separate for backwards compatibility
3527 extern (D) ArgumentList argumentList() { return ArgumentList(arguments, names); }
3529 extern (D) this(const ref Loc loc, Expression e, Expressions* exps, Identifiers* names = null) @safe
3531 super(loc, EXP.call, e);
3532 this.arguments = exps;
3533 this.names = names;
3536 extern (D) this(const ref Loc loc, Expression e) @safe
3538 super(loc, EXP.call, e);
3541 extern (D) this(const ref Loc loc, Expression e, Expression earg1)
3543 super(loc, EXP.call, e);
3544 this.arguments = new Expressions();
3545 if (earg1)
3546 this.arguments.push(earg1);
3549 extern (D) this(const ref Loc loc, Expression e, Expression earg1, Expression earg2)
3551 super(loc, EXP.call, e);
3552 auto arguments = new Expressions(2);
3553 (*arguments)[0] = earg1;
3554 (*arguments)[1] = earg2;
3555 this.arguments = arguments;
3558 /***********************************************************
3559 * Instatiates a new function call expression
3560 * Params:
3561 * loc = location
3562 * fd = the declaration of the function to call
3563 * earg1 = the function argument
3565 extern(D) this(const ref Loc loc, FuncDeclaration fd, Expression earg1)
3567 this(loc, new VarExp(loc, fd, false), earg1);
3568 this.f = fd;
3571 static CallExp create(const ref Loc loc, Expression e, Expressions* exps) @safe
3573 return new CallExp(loc, e, exps);
3576 static CallExp create(const ref Loc loc, Expression e) @safe
3578 return new CallExp(loc, e);
3581 static CallExp create(const ref Loc loc, Expression e, Expression earg1)
3583 return new CallExp(loc, e, earg1);
3586 /***********************************************************
3587 * Creates a new function call expression
3588 * Params:
3589 * loc = location
3590 * fd = the declaration of the function to call
3591 * earg1 = the function argument
3593 static CallExp create(const ref Loc loc, FuncDeclaration fd, Expression earg1)
3595 return new CallExp(loc, fd, earg1);
3598 override CallExp syntaxCopy()
3600 return new CallExp(loc, e1.syntaxCopy(), arraySyntaxCopy(arguments), names ? names.copy() : null);
3603 override bool isLvalue()
3605 Type tb = e1.type.toBasetype();
3606 if (tb.ty == Tdelegate || tb.ty == Tpointer)
3607 tb = tb.nextOf();
3608 auto tf = tb.isTypeFunction();
3609 if (tf && tf.isref)
3611 if (auto dve = e1.isDotVarExp())
3612 if (dve.var.isCtorDeclaration())
3613 return false;
3614 return true; // function returns a reference
3616 return false;
3619 override void accept(Visitor v)
3621 v.visit(this);
3626 * Get the called function type from a call expression
3627 * Params:
3628 * ce = function call expression. Must have had semantic analysis done.
3629 * Returns: called function type, or `null` if error / no semantic analysis done
3631 TypeFunction calledFunctionType(CallExp ce)
3633 Type t = ce.e1.type;
3634 if (!t)
3635 return null;
3636 t = t.toBasetype();
3637 if (auto tf = t.isTypeFunction())
3638 return tf;
3639 else if (auto td = t.isTypeDelegate())
3640 return td.nextOf().isTypeFunction();
3641 else
3642 return null;
3645 FuncDeclaration isFuncAddress(Expression e, bool* hasOverloads = null) @safe
3647 if (auto ae = e.isAddrExp())
3649 auto ae1 = ae.e1;
3650 if (auto ve = ae1.isVarExp())
3652 if (hasOverloads)
3653 *hasOverloads = ve.hasOverloads;
3654 return ve.var.isFuncDeclaration();
3656 if (auto dve = ae1.isDotVarExp())
3658 if (hasOverloads)
3659 *hasOverloads = dve.hasOverloads;
3660 return dve.var.isFuncDeclaration();
3663 else
3665 if (auto soe = e.isSymOffExp())
3667 if (hasOverloads)
3668 *hasOverloads = soe.hasOverloads;
3669 return soe.var.isFuncDeclaration();
3671 if (auto dge = e.isDelegateExp())
3673 if (hasOverloads)
3674 *hasOverloads = dge.hasOverloads;
3675 return dge.func.isFuncDeclaration();
3678 return null;
3681 /***********************************************************
3682 * The 'address of' operator, `&p`
3684 extern (C++) final class AddrExp : UnaExp
3686 extern (D) this(const ref Loc loc, Expression e) @safe
3688 super(loc, EXP.address, e);
3691 extern (D) this(const ref Loc loc, Expression e, Type t) @safe
3693 this(loc, e);
3694 type = t;
3697 override void accept(Visitor v)
3699 v.visit(this);
3703 /***********************************************************
3704 * The pointer dereference operator, `*p`
3706 extern (C++) final class PtrExp : UnaExp
3708 extern (D) this(const ref Loc loc, Expression e) @safe
3710 super(loc, EXP.star, e);
3711 //if (e.type)
3712 // type = ((TypePointer *)e.type).next;
3715 extern (D) this(const ref Loc loc, Expression e, Type t) @safe
3717 super(loc, EXP.star, e);
3718 type = t;
3721 override bool isLvalue()
3723 return true;
3726 override void accept(Visitor v)
3728 v.visit(this);
3732 /***********************************************************
3733 * The negation operator, `-x`
3735 extern (C++) final class NegExp : UnaExp
3737 extern (D) this(const ref Loc loc, Expression e) @safe
3739 super(loc, EXP.negate, e);
3742 override void accept(Visitor v)
3744 v.visit(this);
3748 /***********************************************************
3749 * The unary add operator, `+x`
3751 extern (C++) final class UAddExp : UnaExp
3753 extern (D) this(const ref Loc loc, Expression e) scope @safe
3755 super(loc, EXP.uadd, e);
3758 override void accept(Visitor v)
3760 v.visit(this);
3764 /***********************************************************
3765 * The bitwise complement operator, `~x`
3767 extern (C++) final class ComExp : UnaExp
3769 extern (D) this(const ref Loc loc, Expression e) @safe
3771 super(loc, EXP.tilde, e);
3774 override void accept(Visitor v)
3776 v.visit(this);
3780 /***********************************************************
3781 * The logical not operator, `!x`
3783 extern (C++) final class NotExp : UnaExp
3785 extern (D) this(const ref Loc loc, Expression e) @safe
3787 super(loc, EXP.not, e);
3790 override void accept(Visitor v)
3792 v.visit(this);
3796 /***********************************************************
3797 * The delete operator, `delete x` (deprecated)
3799 * https://dlang.org/spec/expression.html#delete_expressions
3801 extern (C++) final class DeleteExp : UnaExp
3803 bool isRAII; // true if called automatically as a result of scoped destruction
3805 extern (D) this(const ref Loc loc, Expression e, bool isRAII) @safe
3807 super(loc, EXP.delete_, e);
3808 this.isRAII = isRAII;
3811 override void accept(Visitor v)
3813 v.visit(this);
3817 /***********************************************************
3818 * The type cast operator, `cast(T) x`
3820 * It's possible to cast to one type while painting to another type
3822 * https://dlang.org/spec/expression.html#cast_expressions
3824 extern (C++) final class CastExp : UnaExp
3826 Type to; // type to cast to
3827 ubyte mod = cast(ubyte)~0; // MODxxxxx
3829 extern (D) this(const ref Loc loc, Expression e, Type t) @safe
3831 super(loc, EXP.cast_, e);
3832 this.to = t;
3835 /* For cast(const) and cast(immutable)
3837 extern (D) this(const ref Loc loc, Expression e, ubyte mod) @safe
3839 super(loc, EXP.cast_, e);
3840 this.mod = mod;
3843 override CastExp syntaxCopy()
3845 return to ? new CastExp(loc, e1.syntaxCopy(), to.syntaxCopy()) : new CastExp(loc, e1.syntaxCopy(), mod);
3848 override bool isLvalue()
3850 //printf("e1.type = %s, to.type = %s\n", e1.type.toChars(), to.toChars());
3851 if (!e1.isLvalue())
3852 return false;
3853 return (to.ty == Tsarray && (e1.type.ty == Tvector || e1.type.ty == Tsarray)) ||
3854 e1.type.mutableOf().unSharedOf().equals(to.mutableOf().unSharedOf());
3857 override void accept(Visitor v)
3859 v.visit(this);
3863 /***********************************************************
3865 extern (C++) final class VectorExp : UnaExp
3867 TypeVector to; // the target vector type before semantic()
3868 uint dim = ~0; // number of elements in the vector
3869 OwnedBy ownedByCtfe = OwnedBy.code;
3871 extern (D) this(const ref Loc loc, Expression e, Type t) @safe
3873 super(loc, EXP.vector, e);
3874 assert(t.ty == Tvector);
3875 to = cast(TypeVector)t;
3878 static VectorExp create(const ref Loc loc, Expression e, Type t) @safe
3880 return new VectorExp(loc, e, t);
3883 override VectorExp syntaxCopy()
3885 return new VectorExp(loc, e1.syntaxCopy(), to.syntaxCopy());
3888 override void accept(Visitor v)
3890 v.visit(this);
3894 /***********************************************************
3895 * e1.array property for vectors.
3897 * https://dlang.org/spec/simd.html#properties
3899 extern (C++) final class VectorArrayExp : UnaExp
3901 extern (D) this(const ref Loc loc, Expression e1) @safe
3903 super(loc, EXP.vectorArray, e1);
3906 override bool isLvalue()
3908 return e1.isLvalue();
3911 override void accept(Visitor v)
3913 v.visit(this);
3917 /***********************************************************
3918 * e1 [lwr .. upr]
3920 * https://dlang.org/spec/expression.html#slice_expressions
3922 extern (C++) final class SliceExp : UnaExp
3924 Expression upr; // null if implicit 0
3925 Expression lwr; // null if implicit [length - 1]
3927 VarDeclaration lengthVar;
3929 private extern(D) static struct BitFields
3931 bool upperIsInBounds; // true if upr <= e1.length
3932 bool lowerIsLessThanUpper; // true if lwr <= upr
3933 bool arrayop; // an array operation, rather than a slice
3935 import dmd.common.bitfields : generateBitFields;
3936 mixin(generateBitFields!(BitFields, ubyte));
3938 /************************************************************/
3939 extern (D) this(const ref Loc loc, Expression e1, IntervalExp ie) @safe
3941 super(loc, EXP.slice, e1);
3942 this.upr = ie ? ie.upr : null;
3943 this.lwr = ie ? ie.lwr : null;
3946 extern (D) this(const ref Loc loc, Expression e1, Expression lwr, Expression upr) @safe
3948 super(loc, EXP.slice, e1);
3949 this.upr = upr;
3950 this.lwr = lwr;
3953 override SliceExp syntaxCopy()
3955 auto se = new SliceExp(loc, e1.syntaxCopy(), lwr ? lwr.syntaxCopy() : null, upr ? upr.syntaxCopy() : null);
3956 se.lengthVar = this.lengthVar; // bug7871
3957 return se;
3960 override bool isLvalue()
3962 /* slice expression is rvalue in default, but
3963 * conversion to reference of static array is only allowed.
3965 return (type && type.toBasetype().ty == Tsarray);
3968 override Optional!bool toBool()
3970 return e1.toBool();
3973 override void accept(Visitor v)
3975 v.visit(this);
3979 /***********************************************************
3980 * The `.length` property of an array
3982 extern (C++) final class ArrayLengthExp : UnaExp
3984 extern (D) this(const ref Loc loc, Expression e1) @safe
3986 super(loc, EXP.arrayLength, e1);
3989 override void accept(Visitor v)
3991 v.visit(this);
3995 /***********************************************************
3996 * e1 [ a0, a1, a2, a3 ,... ]
3998 * https://dlang.org/spec/expression.html#index_expressions
4000 extern (C++) final class ArrayExp : UnaExp
4002 Expressions* arguments; // Array of Expression's a0..an
4004 size_t currentDimension; // for opDollar
4005 VarDeclaration lengthVar;
4007 extern (D) this(const ref Loc loc, Expression e1, Expression index = null)
4009 super(loc, EXP.array, e1);
4010 arguments = new Expressions();
4011 if (index)
4012 arguments.push(index);
4015 extern (D) this(const ref Loc loc, Expression e1, Expressions* args) @safe
4017 super(loc, EXP.array, e1);
4018 arguments = args;
4021 override ArrayExp syntaxCopy()
4023 auto ae = new ArrayExp(loc, e1.syntaxCopy(), arraySyntaxCopy(arguments));
4024 ae.lengthVar = this.lengthVar; // bug7871
4025 return ae;
4028 override bool isLvalue()
4030 if (type && type.toBasetype().ty == Tvoid)
4031 return false;
4032 return true;
4035 override void accept(Visitor v)
4037 v.visit(this);
4041 /***********************************************************
4043 extern (C++) final class DotExp : BinExp
4045 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
4047 super(loc, EXP.dot, e1, e2);
4050 override void accept(Visitor v)
4052 v.visit(this);
4056 /***********************************************************
4058 extern (C++) final class CommaExp : BinExp
4060 /// This is needed because AssignExp rewrites CommaExp, hence it needs
4061 /// to trigger the deprecation.
4062 const bool isGenerated;
4064 /// Temporary variable to enable / disable deprecation of comma expression
4065 /// depending on the context.
4066 /// Since most constructor calls are rewritting, the only place where
4067 /// false will be passed will be from the parser.
4068 bool allowCommaExp;
4071 extern (D) this(const ref Loc loc, Expression e1, Expression e2, bool generated = true) @safe
4073 super(loc, EXP.comma, e1, e2);
4074 allowCommaExp = isGenerated = generated;
4077 override bool isLvalue()
4079 return e2.isLvalue();
4082 override Optional!bool toBool()
4084 return e2.toBool();
4087 override void accept(Visitor v)
4089 v.visit(this);
4093 * If the argument is a CommaExp, set a flag to prevent deprecation messages
4095 * It's impossible to know from CommaExp.semantic if the result will
4096 * be used, hence when there is a result (type != void), a deprecation
4097 * message is always emitted.
4098 * However, some construct can produce a result but won't use it
4099 * (ExpStatement and for loop increment). Those should call this function
4100 * to prevent unwanted deprecations to be emitted.
4102 * Params:
4103 * exp = An expression that discards its result.
4104 * If the argument is null or not a CommaExp, nothing happens.
4106 static void allow(Expression exp) @safe
4108 if (exp)
4109 if (auto ce = exp.isCommaExp())
4110 ce.allowCommaExp = true;
4114 /***********************************************************
4115 * Mainly just a placeholder
4117 extern (C++) final class IntervalExp : Expression
4119 Expression lwr;
4120 Expression upr;
4122 extern (D) this(const ref Loc loc, Expression lwr, Expression upr) @safe
4124 super(loc, EXP.interval);
4125 this.lwr = lwr;
4126 this.upr = upr;
4129 override Expression syntaxCopy()
4131 return new IntervalExp(loc, lwr.syntaxCopy(), upr.syntaxCopy());
4134 override void accept(Visitor v)
4136 v.visit(this);
4140 /***********************************************************
4141 * The `dg.ptr` property, pointing to the delegate's 'context'
4143 * c.f.`DelegateFuncptrExp` for the delegate's function pointer `dg.funcptr`
4145 extern (C++) final class DelegatePtrExp : UnaExp
4147 extern (D) this(const ref Loc loc, Expression e1) @safe
4149 super(loc, EXP.delegatePointer, e1);
4152 override bool isLvalue()
4154 return e1.isLvalue();
4157 override void accept(Visitor v)
4159 v.visit(this);
4163 /***********************************************************
4164 * The `dg.funcptr` property, pointing to the delegate's function
4166 * c.f.`DelegatePtrExp` for the delegate's function pointer `dg.ptr`
4168 extern (C++) final class DelegateFuncptrExp : UnaExp
4170 extern (D) this(const ref Loc loc, Expression e1) @safe
4172 super(loc, EXP.delegateFunctionPointer, e1);
4175 override bool isLvalue()
4177 return e1.isLvalue();
4180 override void accept(Visitor v)
4182 v.visit(this);
4186 /***********************************************************
4187 * e1 [ e2 ]
4189 extern (C++) final class IndexExp : BinExp
4191 VarDeclaration lengthVar;
4192 bool modifiable = false; // assume it is an rvalue
4193 bool indexIsInBounds; // true if 0 <= e2 && e2 <= e1.length - 1
4195 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
4197 super(loc, EXP.index, e1, e2);
4198 //printf("IndexExp::IndexExp('%s')\n", toChars());
4201 extern (D) this(const ref Loc loc, Expression e1, Expression e2, bool indexIsInBounds) @safe
4203 super(loc, EXP.index, e1, e2);
4204 this.indexIsInBounds = indexIsInBounds;
4205 //printf("IndexExp::IndexExp('%s')\n", toChars());
4208 override IndexExp syntaxCopy()
4210 auto ie = new IndexExp(loc, e1.syntaxCopy(), e2.syntaxCopy());
4211 ie.lengthVar = this.lengthVar; // bug7871
4212 return ie;
4215 override bool isLvalue()
4217 if (e1.op == EXP.assocArrayLiteral)
4218 return false;
4219 if (e1.type.ty == Tsarray ||
4220 (e1.op == EXP.index && e1.type.ty != Tarray))
4222 return e1.isLvalue();
4224 return true;
4227 extern (D) Expression markSettingAAElem()
4229 if (e1.type.toBasetype().ty == Taarray)
4231 Type t2b = e2.type.toBasetype();
4232 if (t2b.ty == Tarray && t2b.nextOf().isMutable())
4234 error(loc, "associative arrays can only be assigned values with immutable keys, not `%s`", e2.type.toChars());
4235 return ErrorExp.get();
4237 modifiable = true;
4239 if (auto ie = e1.isIndexExp())
4241 Expression ex = ie.markSettingAAElem();
4242 if (ex.op == EXP.error)
4243 return ex;
4244 assert(ex == e1);
4247 return this;
4250 override void accept(Visitor v)
4252 v.visit(this);
4256 /***********************************************************
4257 * The postfix increment/decrement operator, `i++` / `i--`
4259 extern (C++) final class PostExp : BinExp
4261 extern (D) this(EXP op, const ref Loc loc, Expression e)
4263 super(loc, op, e, IntegerExp.literal!1);
4264 assert(op == EXP.minusMinus || op == EXP.plusPlus);
4267 override void accept(Visitor v)
4269 v.visit(this);
4273 /***********************************************************
4274 * The prefix increment/decrement operator, `++i` / `--i`
4276 extern (C++) final class PreExp : UnaExp
4278 extern (D) this(EXP op, const ref Loc loc, Expression e) @safe
4280 super(loc, op, e);
4281 assert(op == EXP.preMinusMinus || op == EXP.prePlusPlus);
4284 override void accept(Visitor v)
4286 v.visit(this);
4290 enum MemorySet
4292 none = 0, // simple assignment
4293 blockAssign = 1, // setting the contents of an array
4294 referenceInit = 2, // setting the reference of STC.ref_ variable
4297 /***********************************************************
4298 * The assignment / initialization operator, `=`
4300 * Note: operator assignment `op=` has a different base class, `BinAssignExp`
4302 extern (C++) class AssignExp : BinExp
4304 MemorySet memset;
4306 /************************************************************/
4307 /* op can be EXP.assign, EXP.construct, or EXP.blit */
4308 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
4310 super(loc, EXP.assign, e1, e2);
4313 this(const ref Loc loc, EXP tok, Expression e1, Expression e2) @safe
4315 super(loc, tok, e1, e2);
4318 override final bool isLvalue()
4320 // Array-op 'x[] = y[]' should make an rvalue.
4321 // Setting array length 'x.length = v' should make an rvalue.
4322 if (e1.op == EXP.slice || e1.op == EXP.arrayLength)
4324 return false;
4326 return true;
4329 override void accept(Visitor v)
4331 v.visit(this);
4335 /***********************************************************
4336 * When an assignment expression is lowered to a druntime call
4337 * this class is used to store the lowering.
4338 * It essentially behaves the same as an AssignExp, but it is
4339 * used to not waste space for other AssignExp that are not
4340 * lowered to anything.
4342 extern (C++) final class LoweredAssignExp : AssignExp
4344 Expression lowering;
4345 extern (D) this(AssignExp exp, Expression lowering) @safe
4347 super(exp.loc, EXP.loweredAssignExp, exp.e1, exp.e2);
4348 this.lowering = lowering;
4351 override const(char)* toChars() const
4353 return lowering.toChars();
4355 override void accept(Visitor v)
4357 v.visit(this);
4361 /***********************************************************
4363 extern (C++) final class ConstructExp : AssignExp
4365 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
4367 super(loc, EXP.construct, e1, e2);
4370 // Internal use only. If `v` is a reference variable, the assignment
4371 // will become a reference initialization automatically.
4372 extern (D) this(const ref Loc loc, VarDeclaration v, Expression e2) @safe
4374 auto ve = new VarExp(loc, v);
4375 assert(v.type && ve.type);
4377 super(loc, EXP.construct, ve, e2);
4379 if (v.isReference())
4380 memset = MemorySet.referenceInit;
4383 override void accept(Visitor v)
4385 v.visit(this);
4389 /***********************************************************
4390 * A bit-for-bit copy from `e2` to `e1`
4392 extern (C++) final class BlitExp : AssignExp
4394 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
4396 super(loc, EXP.blit, e1, e2);
4399 // Internal use only. If `v` is a reference variable, the assinment
4400 // will become a reference rebinding automatically.
4401 extern (D) this(const ref Loc loc, VarDeclaration v, Expression e2) @safe
4403 auto ve = new VarExp(loc, v);
4404 assert(v.type && ve.type);
4406 super(loc, EXP.blit, ve, e2);
4408 if (v.isReference())
4409 memset = MemorySet.referenceInit;
4412 override void accept(Visitor v)
4414 v.visit(this);
4418 /***********************************************************
4419 * `x += y`
4421 extern (C++) final class AddAssignExp : BinAssignExp
4423 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
4425 super(loc, EXP.addAssign, e1, e2);
4428 override void accept(Visitor v)
4430 v.visit(this);
4434 /***********************************************************
4435 * `x -= y`
4437 extern (C++) final class MinAssignExp : BinAssignExp
4439 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
4441 super(loc, EXP.minAssign, e1, e2);
4444 override void accept(Visitor v)
4446 v.visit(this);
4450 /***********************************************************
4451 * `x *= y`
4453 extern (C++) final class MulAssignExp : BinAssignExp
4455 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
4457 super(loc, EXP.mulAssign, e1, e2);
4460 override void accept(Visitor v)
4462 v.visit(this);
4466 /***********************************************************
4467 * `x /= y`
4469 extern (C++) final class DivAssignExp : BinAssignExp
4471 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
4473 super(loc, EXP.divAssign, e1, e2);
4476 override void accept(Visitor v)
4478 v.visit(this);
4482 /***********************************************************
4483 * `x %= y`
4485 extern (C++) final class ModAssignExp : BinAssignExp
4487 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
4489 super(loc, EXP.modAssign, e1, e2);
4492 override void accept(Visitor v)
4494 v.visit(this);
4498 /***********************************************************
4499 * `x &= y`
4501 extern (C++) final class AndAssignExp : BinAssignExp
4503 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
4505 super(loc, EXP.andAssign, e1, e2);
4508 override void accept(Visitor v)
4510 v.visit(this);
4514 /***********************************************************
4515 * `x |= y`
4517 extern (C++) final class OrAssignExp : BinAssignExp
4519 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
4521 super(loc, EXP.orAssign, e1, e2);
4524 override void accept(Visitor v)
4526 v.visit(this);
4530 /***********************************************************
4531 * `x ^= y`
4533 extern (C++) final class XorAssignExp : BinAssignExp
4535 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
4537 super(loc, EXP.xorAssign, e1, e2);
4540 override void accept(Visitor v)
4542 v.visit(this);
4546 /***********************************************************
4547 * `x ^^= y`
4549 extern (C++) final class PowAssignExp : BinAssignExp
4551 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
4553 super(loc, EXP.powAssign, e1, e2);
4556 override void accept(Visitor v)
4558 v.visit(this);
4562 /***********************************************************
4563 * `x <<= y`
4565 extern (C++) final class ShlAssignExp : BinAssignExp
4567 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
4569 super(loc, EXP.leftShiftAssign, e1, e2);
4572 override void accept(Visitor v)
4574 v.visit(this);
4578 /***********************************************************
4579 * `x >>= y`
4581 extern (C++) final class ShrAssignExp : BinAssignExp
4583 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
4585 super(loc, EXP.rightShiftAssign, e1, e2);
4588 override void accept(Visitor v)
4590 v.visit(this);
4594 /***********************************************************
4595 * `x >>>= y`
4597 extern (C++) final class UshrAssignExp : BinAssignExp
4599 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
4601 super(loc, EXP.unsignedRightShiftAssign, e1, e2);
4604 override void accept(Visitor v)
4606 v.visit(this);
4610 /***********************************************************
4611 * The `~=` operator.
4613 * It can have one of the following operators:
4615 * EXP.concatenateAssign - appending T[] to T[]
4616 * EXP.concatenateElemAssign - appending T to T[]
4617 * EXP.concatenateDcharAssign - appending dchar to T[]
4619 * The parser initially sets it to EXP.concatenateAssign, and semantic() later decides which
4620 * of the three it will be set to.
4622 extern (C++) class CatAssignExp : BinAssignExp
4624 Expression lowering; // lowered druntime hook `_d_arrayappend{cTX,T}`
4626 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
4628 super(loc, EXP.concatenateAssign, e1, e2);
4631 extern (D) this(const ref Loc loc, EXP tok, Expression e1, Expression e2) @safe
4633 super(loc, tok, e1, e2);
4636 override void accept(Visitor v)
4638 v.visit(this);
4642 /***********************************************************
4643 * The `~=` operator when appending a single element
4645 extern (C++) final class CatElemAssignExp : CatAssignExp
4647 extern (D) this(const ref Loc loc, Type type, Expression e1, Expression e2) @safe
4649 super(loc, EXP.concatenateElemAssign, e1, e2);
4650 this.type = type;
4653 override void accept(Visitor v)
4655 v.visit(this);
4659 /***********************************************************
4660 * The `~=` operator when appending a single `dchar`
4662 extern (C++) final class CatDcharAssignExp : CatAssignExp
4664 extern (D) this(const ref Loc loc, Type type, Expression e1, Expression e2) @safe
4666 super(loc, EXP.concatenateDcharAssign, e1, e2);
4667 this.type = type;
4670 override void accept(Visitor v)
4672 v.visit(this);
4676 /***********************************************************
4677 * The addition operator, `x + y`
4679 * https://dlang.org/spec/expression.html#add_expressions
4681 extern (C++) final class AddExp : BinExp
4683 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
4685 super(loc, EXP.add, e1, e2);
4688 override void accept(Visitor v)
4690 v.visit(this);
4694 /***********************************************************
4695 * The minus operator, `x - y`
4697 * https://dlang.org/spec/expression.html#add_expressions
4699 extern (C++) final class MinExp : BinExp
4701 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
4703 super(loc, EXP.min, e1, e2);
4706 override void accept(Visitor v)
4708 v.visit(this);
4712 /***********************************************************
4713 * The concatenation operator, `x ~ y`
4715 * https://dlang.org/spec/expression.html#cat_expressions
4717 extern (C++) final class CatExp : BinExp
4719 Expression lowering; // call to druntime hook `_d_arraycatnTX`
4721 extern (D) this(const ref Loc loc, Expression e1, Expression e2) scope @safe
4723 super(loc, EXP.concatenate, e1, e2);
4726 override void accept(Visitor v)
4728 v.visit(this);
4732 /***********************************************************
4733 * The multiplication operator, `x * y`
4735 * https://dlang.org/spec/expression.html#mul_expressions
4737 extern (C++) final class MulExp : BinExp
4739 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
4741 super(loc, EXP.mul, e1, e2);
4744 override void accept(Visitor v)
4746 v.visit(this);
4750 /***********************************************************
4751 * The division operator, `x / y`
4753 * https://dlang.org/spec/expression.html#mul_expressions
4755 extern (C++) final class DivExp : BinExp
4757 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
4759 super(loc, EXP.div, e1, e2);
4762 override void accept(Visitor v)
4764 v.visit(this);
4768 /***********************************************************
4769 * The modulo operator, `x % y`
4771 * https://dlang.org/spec/expression.html#mul_expressions
4773 extern (C++) final class ModExp : BinExp
4775 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
4777 super(loc, EXP.mod, e1, e2);
4780 override void accept(Visitor v)
4782 v.visit(this);
4786 /***********************************************************
4787 * The 'power' operator, `x ^^ y`
4789 * https://dlang.org/spec/expression.html#pow_expressions
4791 extern (C++) final class PowExp : BinExp
4793 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
4795 super(loc, EXP.pow, e1, e2);
4798 override void accept(Visitor v)
4800 v.visit(this);
4804 /***********************************************************
4805 * The 'shift left' operator, `x << y`
4807 * https://dlang.org/spec/expression.html#shift_expressions
4809 extern (C++) final class ShlExp : BinExp
4811 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
4813 super(loc, EXP.leftShift, e1, e2);
4816 override void accept(Visitor v)
4818 v.visit(this);
4822 /***********************************************************
4823 * The 'shift right' operator, `x >> y`
4825 * https://dlang.org/spec/expression.html#shift_expressions
4827 extern (C++) final class ShrExp : BinExp
4829 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
4831 super(loc, EXP.rightShift, e1, e2);
4834 override void accept(Visitor v)
4836 v.visit(this);
4840 /***********************************************************
4841 * The 'unsigned shift right' operator, `x >>> y`
4843 * https://dlang.org/spec/expression.html#shift_expressions
4845 extern (C++) final class UshrExp : BinExp
4847 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
4849 super(loc, EXP.unsignedRightShift, e1, e2);
4852 override void accept(Visitor v)
4854 v.visit(this);
4858 /***********************************************************
4859 * The bitwise 'and' operator, `x & y`
4861 * https://dlang.org/spec/expression.html#and_expressions
4863 extern (C++) final class AndExp : BinExp
4865 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
4867 super(loc, EXP.and, e1, e2);
4870 override void accept(Visitor v)
4872 v.visit(this);
4876 /***********************************************************
4877 * The bitwise 'or' operator, `x | y`
4879 * https://dlang.org/spec/expression.html#or_expressions
4881 extern (C++) final class OrExp : BinExp
4883 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
4885 super(loc, EXP.or, e1, e2);
4888 override void accept(Visitor v)
4890 v.visit(this);
4894 /***********************************************************
4895 * The bitwise 'xor' operator, `x ^ y`
4897 * https://dlang.org/spec/expression.html#xor_expressions
4899 extern (C++) final class XorExp : BinExp
4901 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
4903 super(loc, EXP.xor, e1, e2);
4906 override void accept(Visitor v)
4908 v.visit(this);
4912 /***********************************************************
4913 * The logical 'and' / 'or' operator, `X && Y` / `X || Y`
4915 * https://dlang.org/spec/expression.html#andand_expressions
4916 * https://dlang.org/spec/expression.html#oror_expressions
4918 extern (C++) final class LogicalExp : BinExp
4920 extern (D) this(const ref Loc loc, EXP op, Expression e1, Expression e2) @safe
4922 super(loc, op, e1, e2);
4923 assert(op == EXP.andAnd || op == EXP.orOr);
4926 override void accept(Visitor v)
4928 v.visit(this);
4932 /***********************************************************
4933 * A comparison operator, `<` `<=` `>` `>=`
4935 * `op` is one of:
4936 * EXP.lessThan, EXP.lessOrEqual, EXP.greaterThan, EXP.greaterOrEqual
4938 * https://dlang.org/spec/expression.html#relation_expressions
4940 extern (C++) final class CmpExp : BinExp
4942 extern (D) this(EXP op, const ref Loc loc, Expression e1, Expression e2) @safe
4944 super(loc, op, e1, e2);
4945 assert(op == EXP.lessThan || op == EXP.lessOrEqual || op == EXP.greaterThan || op == EXP.greaterOrEqual);
4948 override void accept(Visitor v)
4950 v.visit(this);
4954 /***********************************************************
4955 * The `in` operator, `"a" in ["a": 1]`
4957 * Note: `x !in y` is rewritten to `!(x in y)` in the parser
4959 * https://dlang.org/spec/expression.html#in_expressions
4961 extern (C++) final class InExp : BinExp
4963 extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
4965 super(loc, EXP.in_, e1, e2);
4968 override void accept(Visitor v)
4970 v.visit(this);
4974 /***********************************************************
4975 * Associative array removal, `aa.remove(arg)`
4977 * This deletes the key e1 from the associative array e2
4979 extern (C++) final class RemoveExp : BinExp
4981 extern (D) this(const ref Loc loc, Expression e1, Expression e2)
4983 super(loc, EXP.remove, e1, e2);
4984 type = Type.tbool;
4987 override void accept(Visitor v)
4989 v.visit(this);
4993 /***********************************************************
4994 * `==` and `!=`
4996 * EXP.equal and EXP.notEqual
4998 * https://dlang.org/spec/expression.html#equality_expressions
5000 extern (C++) final class EqualExp : BinExp
5002 extern (D) this(EXP op, const ref Loc loc, Expression e1, Expression e2) @safe
5004 super(loc, op, e1, e2);
5005 assert(op == EXP.equal || op == EXP.notEqual);
5008 override void accept(Visitor v)
5010 v.visit(this);
5014 /***********************************************************
5015 * `is` and `!is`
5017 * EXP.identity and EXP.notIdentity
5019 * https://dlang.org/spec/expression.html#identity_expressions
5021 extern (C++) final class IdentityExp : BinExp
5023 extern (D) this(EXP op, const ref Loc loc, Expression e1, Expression e2) @safe
5025 super(loc, op, e1, e2);
5026 assert(op == EXP.identity || op == EXP.notIdentity);
5029 override void accept(Visitor v)
5031 v.visit(this);
5035 /***********************************************************
5036 * The ternary operator, `econd ? e1 : e2`
5038 * https://dlang.org/spec/expression.html#conditional_expressions
5040 extern (C++) final class CondExp : BinExp
5042 Expression econd;
5044 extern (D) this(const ref Loc loc, Expression econd, Expression e1, Expression e2) scope @safe
5046 super(loc, EXP.question, e1, e2);
5047 this.econd = econd;
5050 override CondExp syntaxCopy()
5052 return new CondExp(loc, econd.syntaxCopy(), e1.syntaxCopy(), e2.syntaxCopy());
5055 override bool isLvalue()
5057 return e1.isLvalue() && e2.isLvalue();
5060 override void accept(Visitor v)
5062 v.visit(this);
5066 /***********************************************************
5067 * A special keyword when used as a function's default argument
5069 * When possible, special keywords are resolved in the parser, but when
5070 * appearing as a default argument, they result in an expression deriving
5071 * from this base class that is resolved for each function call.
5073 * ---
5074 * const x = __LINE__; // resolved in the parser
5075 * void foo(string file = __FILE__, int line = __LINE__); // DefaultInitExp
5076 * ---
5078 * https://dlang.org/spec/expression.html#specialkeywords
5080 extern (C++) class DefaultInitExp : Expression
5082 /*************************
5083 * Params:
5084 * loc = location
5085 * op = EXP.prettyFunction, EXP.functionString, EXP.moduleString,
5086 * EXP.line, EXP.file, EXP.fileFullPath
5088 extern (D) this(const ref Loc loc, EXP op) @safe
5090 super(loc, op);
5093 override void accept(Visitor v)
5095 v.visit(this);
5099 /***********************************************************
5100 * The `__FILE__` token as a default argument
5102 extern (C++) final class FileInitExp : DefaultInitExp
5104 extern (D) this(const ref Loc loc, EXP tok) @safe
5106 super(loc, tok);
5109 override void accept(Visitor v)
5111 v.visit(this);
5115 /***********************************************************
5116 * The `__LINE__` token as a default argument
5118 extern (C++) final class LineInitExp : DefaultInitExp
5120 extern (D) this(const ref Loc loc) @safe
5122 super(loc, EXP.line);
5125 override void accept(Visitor v)
5127 v.visit(this);
5131 /***********************************************************
5132 * The `__MODULE__` token as a default argument
5134 extern (C++) final class ModuleInitExp : DefaultInitExp
5136 extern (D) this(const ref Loc loc) @safe
5138 super(loc, EXP.moduleString);
5141 override void accept(Visitor v)
5143 v.visit(this);
5147 /***********************************************************
5148 * The `__FUNCTION__` token as a default argument
5150 extern (C++) final class FuncInitExp : DefaultInitExp
5152 extern (D) this(const ref Loc loc) @safe
5154 super(loc, EXP.functionString);
5157 override void accept(Visitor v)
5159 v.visit(this);
5163 /***********************************************************
5164 * The `__PRETTY_FUNCTION__` token as a default argument
5166 extern (C++) final class PrettyFuncInitExp : DefaultInitExp
5168 extern (D) this(const ref Loc loc) @safe
5170 super(loc, EXP.prettyFunction);
5173 override void accept(Visitor v)
5175 v.visit(this);
5179 /***********************************************************
5180 * A reference to a class, or an interface. We need this when we
5181 * point to a base class (we must record what the type is).
5183 extern (C++) final class ClassReferenceExp : Expression
5185 StructLiteralExp value;
5187 extern (D) this(const ref Loc loc, StructLiteralExp lit, Type type) @safe
5189 super(loc, EXP.classReference);
5190 assert(lit && lit.sd && lit.sd.isClassDeclaration());
5191 this.value = lit;
5192 this.type = type;
5195 ClassDeclaration originalClass()
5197 return value.sd.isClassDeclaration();
5200 // Return index of the field, or -1 if not found
5201 int getFieldIndex(Type fieldtype, uint fieldoffset)
5203 ClassDeclaration cd = originalClass();
5204 uint fieldsSoFar = 0;
5205 for (size_t j = 0; j < value.elements.length; j++)
5207 while (j - fieldsSoFar >= cd.fields.length)
5209 fieldsSoFar += cd.fields.length;
5210 cd = cd.baseClass;
5212 VarDeclaration v2 = cd.fields[j - fieldsSoFar];
5213 if (fieldoffset == v2.offset && fieldtype.size() == v2.type.size())
5215 return cast(int)(value.elements.length - fieldsSoFar - cd.fields.length + (j - fieldsSoFar));
5218 return -1;
5221 // Return index of the field, or -1 if not found
5222 // Same as getFieldIndex, but checks for a direct match with the VarDeclaration
5223 int findFieldIndexByName(VarDeclaration v)
5225 ClassDeclaration cd = originalClass();
5226 size_t fieldsSoFar = 0;
5227 for (size_t j = 0; j < value.elements.length; j++)
5229 while (j - fieldsSoFar >= cd.fields.length)
5231 fieldsSoFar += cd.fields.length;
5232 cd = cd.baseClass;
5234 VarDeclaration v2 = cd.fields[j - fieldsSoFar];
5235 if (v == v2)
5237 return cast(int)(value.elements.length - fieldsSoFar - cd.fields.length + (j - fieldsSoFar));
5240 return -1;
5243 override void accept(Visitor v)
5245 v.visit(this);
5249 /***********************************************************
5250 * This type is only used by the interpreter.
5252 extern (C++) final class CTFEExp : Expression
5254 extern (D) this(EXP tok)
5256 super(Loc.initial, tok);
5257 type = Type.tvoid;
5260 override const(char)* toChars() const
5262 switch (op)
5264 case EXP.cantExpression:
5265 return "<cant>";
5266 case EXP.voidExpression:
5267 return "cast(void)0";
5268 case EXP.showCtfeContext:
5269 return "<error>";
5270 case EXP.break_:
5271 return "<break>";
5272 case EXP.continue_:
5273 return "<continue>";
5274 case EXP.goto_:
5275 return "<goto>";
5276 default:
5277 assert(0);
5281 extern (D) __gshared CTFEExp cantexp;
5282 extern (D) __gshared CTFEExp voidexp;
5283 extern (D) __gshared CTFEExp breakexp;
5284 extern (D) __gshared CTFEExp continueexp;
5285 extern (D) __gshared CTFEExp gotoexp;
5286 /* Used when additional information is needed regarding
5287 * a ctfe error.
5289 extern (D) __gshared CTFEExp showcontext;
5291 extern (D) static bool isCantExp(const Expression e) @safe
5293 return e && e.op == EXP.cantExpression;
5296 extern (D) static bool isGotoExp(const Expression e) @safe
5298 return e && e.op == EXP.goto_;
5302 /***********************************************************
5303 * Fake class which holds the thrown exception.
5304 * Used for implementing exception handling.
5306 extern (C++) final class ThrownExceptionExp : Expression
5308 ClassReferenceExp thrown; // the thing being tossed
5310 extern (D) this(const ref Loc loc, ClassReferenceExp victim) @safe
5312 super(loc, EXP.thrownException);
5313 this.thrown = victim;
5314 this.type = victim.type;
5317 override const(char)* toChars() const
5319 return "CTFE ThrownException";
5322 override void accept(Visitor v)
5324 v.visit(this);
5329 * Objective-C class reference expression.
5331 * Used to get the metaclass of an Objective-C class, `NSObject.Class`.
5333 extern (C++) final class ObjcClassReferenceExp : Expression
5335 ClassDeclaration classDeclaration;
5337 extern (D) this(const ref Loc loc, ClassDeclaration classDeclaration)
5339 super(loc, EXP.objcClassReference);
5340 this.classDeclaration = classDeclaration;
5343 override void accept(Visitor v)
5345 v.visit(this);
5349 /*******************
5350 * C11 6.5.1.1 Generic Selection
5351 * For ImportC
5353 extern (C++) final class GenericExp : Expression
5355 Expression cntlExp; /// controlling expression of a generic selection (not evaluated)
5356 Types* types; /// type-names for generic associations (null entry for `default`)
5357 Expressions* exps; /// 1:1 mapping of typeNames to exps
5359 extern (D) this(const ref Loc loc, Expression cntlExp, Types* types, Expressions* exps) @safe
5361 super(loc, EXP._Generic);
5362 this.cntlExp = cntlExp;
5363 this.types = types;
5364 this.exps = exps;
5365 assert(types.length == exps.length); // must be the same and >=1
5368 override GenericExp syntaxCopy()
5370 return new GenericExp(loc, cntlExp.syntaxCopy(), Type.arraySyntaxCopy(types), Expression.arraySyntaxCopy(exps));
5373 override void accept(Visitor v)
5375 v.visit(this);
5380 * Verify if the given identifier is _d_array{,set}ctor.
5382 * Params:
5383 * id = the identifier to verify
5385 * Returns:
5386 * `true` if the identifier corresponds to a construction runtime hook,
5387 * `false` otherwise.
5389 bool isArrayConstruction(const Identifier id)
5391 import dmd.id : Id;
5393 return id == Id._d_arrayctor || id == Id._d_arraysetctor;
5396 /******************************
5397 * Provide efficient way to implement isUnaExp(), isBinExp(), isBinAssignExp()
5399 private immutable ubyte[EXP.max + 1] exptab =
5400 () {
5401 ubyte[EXP.max + 1] tab;
5402 with (EXPFLAGS)
5404 foreach (i; Eunary) { tab[i] |= unary; }
5405 foreach (i; Ebinary) { tab[i] |= unary | binary; }
5406 foreach (i; EbinaryAssign) { tab[i] |= unary | binary | binaryAssign; }
5408 return tab;
5409 } ();
5411 private enum EXPFLAGS : ubyte
5413 unary = 1,
5414 binary = 2,
5415 binaryAssign = 4,
5418 private enum Eunary =
5420 EXP.import_, EXP.assert_, EXP.throw_, EXP.dotIdentifier, EXP.dotTemplateDeclaration,
5421 EXP.dotVariable, EXP.dotTemplateInstance, EXP.delegate_, EXP.dotType, EXP.call,
5422 EXP.address, EXP.star, EXP.negate, EXP.uadd, EXP.tilde, EXP.not, EXP.delete_, EXP.cast_,
5423 EXP.vector, EXP.vectorArray, EXP.slice, EXP.arrayLength, EXP.array, EXP.delegatePointer,
5424 EXP.delegateFunctionPointer, EXP.preMinusMinus, EXP.prePlusPlus,
5427 private enum Ebinary =
5429 EXP.dot, EXP.comma, EXP.index, EXP.minusMinus, EXP.plusPlus, EXP.assign,
5430 EXP.add, EXP.min, EXP.concatenate, EXP.mul, EXP.div, EXP.mod, EXP.pow, EXP.leftShift,
5431 EXP.rightShift, EXP.unsignedRightShift, EXP.and, EXP.or, EXP.xor, EXP.andAnd, EXP.orOr,
5432 EXP.lessThan, EXP.lessOrEqual, EXP.greaterThan, EXP.greaterOrEqual,
5433 EXP.in_, EXP.remove, EXP.equal, EXP.notEqual, EXP.identity, EXP.notIdentity,
5434 EXP.question,
5435 EXP.construct, EXP.blit,
5438 private enum EbinaryAssign =
5440 EXP.addAssign, EXP.minAssign, EXP.mulAssign, EXP.divAssign, EXP.modAssign,
5441 EXP.andAssign, EXP.orAssign, EXP.xorAssign, EXP.powAssign,
5442 EXP.leftShiftAssign, EXP.rightShiftAssign, EXP.unsignedRightShiftAssign,
5443 EXP.concatenateAssign, EXP.concatenateElemAssign, EXP.concatenateDcharAssign,
5446 /// Given a member of the EXP enum, get the class instance size of the corresponding Expression class.
5447 /// Needed because the classes are `extern(C++)`
5448 private immutable ubyte[EXP.max+1] expSize = [
5449 EXP.reserved: 0,
5450 EXP.negate: __traits(classInstanceSize, NegExp),
5451 EXP.cast_: __traits(classInstanceSize, CastExp),
5452 EXP.null_: __traits(classInstanceSize, NullExp),
5453 EXP.assert_: __traits(classInstanceSize, AssertExp),
5454 EXP.array: __traits(classInstanceSize, ArrayExp),
5455 EXP.call: __traits(classInstanceSize, CallExp),
5456 EXP.address: __traits(classInstanceSize, AddrExp),
5457 EXP.type: __traits(classInstanceSize, TypeExp),
5458 EXP.throw_: __traits(classInstanceSize, ThrowExp),
5459 EXP.new_: __traits(classInstanceSize, NewExp),
5460 EXP.delete_: __traits(classInstanceSize, DeleteExp),
5461 EXP.star: __traits(classInstanceSize, PtrExp),
5462 EXP.symbolOffset: __traits(classInstanceSize, SymOffExp),
5463 EXP.variable: __traits(classInstanceSize, VarExp),
5464 EXP.dotVariable: __traits(classInstanceSize, DotVarExp),
5465 EXP.dotIdentifier: __traits(classInstanceSize, DotIdExp),
5466 EXP.dotTemplateInstance: __traits(classInstanceSize, DotTemplateInstanceExp),
5467 EXP.dotType: __traits(classInstanceSize, DotTypeExp),
5468 EXP.slice: __traits(classInstanceSize, SliceExp),
5469 EXP.arrayLength: __traits(classInstanceSize, ArrayLengthExp),
5470 EXP.dollar: __traits(classInstanceSize, DollarExp),
5471 EXP.template_: __traits(classInstanceSize, TemplateExp),
5472 EXP.dotTemplateDeclaration: __traits(classInstanceSize, DotTemplateExp),
5473 EXP.declaration: __traits(classInstanceSize, DeclarationExp),
5474 EXP.dSymbol: __traits(classInstanceSize, DsymbolExp),
5475 EXP.typeid_: __traits(classInstanceSize, TypeidExp),
5476 EXP.uadd: __traits(classInstanceSize, UAddExp),
5477 EXP.remove: __traits(classInstanceSize, RemoveExp),
5478 EXP.newAnonymousClass: __traits(classInstanceSize, NewAnonClassExp),
5479 EXP.arrayLiteral: __traits(classInstanceSize, ArrayLiteralExp),
5480 EXP.assocArrayLiteral: __traits(classInstanceSize, AssocArrayLiteralExp),
5481 EXP.structLiteral: __traits(classInstanceSize, StructLiteralExp),
5482 EXP.classReference: __traits(classInstanceSize, ClassReferenceExp),
5483 EXP.thrownException: __traits(classInstanceSize, ThrownExceptionExp),
5484 EXP.delegatePointer: __traits(classInstanceSize, DelegatePtrExp),
5485 EXP.delegateFunctionPointer: __traits(classInstanceSize, DelegateFuncptrExp),
5486 EXP.lessThan: __traits(classInstanceSize, CmpExp),
5487 EXP.greaterThan: __traits(classInstanceSize, CmpExp),
5488 EXP.lessOrEqual: __traits(classInstanceSize, CmpExp),
5489 EXP.greaterOrEqual: __traits(classInstanceSize, CmpExp),
5490 EXP.equal: __traits(classInstanceSize, EqualExp),
5491 EXP.notEqual: __traits(classInstanceSize, EqualExp),
5492 EXP.identity: __traits(classInstanceSize, IdentityExp),
5493 EXP.notIdentity: __traits(classInstanceSize, IdentityExp),
5494 EXP.index: __traits(classInstanceSize, IndexExp),
5495 EXP.is_: __traits(classInstanceSize, IsExp),
5496 EXP.leftShift: __traits(classInstanceSize, ShlExp),
5497 EXP.rightShift: __traits(classInstanceSize, ShrExp),
5498 EXP.leftShiftAssign: __traits(classInstanceSize, ShlAssignExp),
5499 EXP.rightShiftAssign: __traits(classInstanceSize, ShrAssignExp),
5500 EXP.unsignedRightShift: __traits(classInstanceSize, UshrExp),
5501 EXP.unsignedRightShiftAssign: __traits(classInstanceSize, UshrAssignExp),
5502 EXP.concatenate: __traits(classInstanceSize, CatExp),
5503 EXP.concatenateAssign: __traits(classInstanceSize, CatAssignExp),
5504 EXP.concatenateElemAssign: __traits(classInstanceSize, CatElemAssignExp),
5505 EXP.concatenateDcharAssign: __traits(classInstanceSize, CatDcharAssignExp),
5506 EXP.add: __traits(classInstanceSize, AddExp),
5507 EXP.min: __traits(classInstanceSize, MinExp),
5508 EXP.addAssign: __traits(classInstanceSize, AddAssignExp),
5509 EXP.minAssign: __traits(classInstanceSize, MinAssignExp),
5510 EXP.mul: __traits(classInstanceSize, MulExp),
5511 EXP.div: __traits(classInstanceSize, DivExp),
5512 EXP.mod: __traits(classInstanceSize, ModExp),
5513 EXP.mulAssign: __traits(classInstanceSize, MulAssignExp),
5514 EXP.divAssign: __traits(classInstanceSize, DivAssignExp),
5515 EXP.modAssign: __traits(classInstanceSize, ModAssignExp),
5516 EXP.and: __traits(classInstanceSize, AndExp),
5517 EXP.or: __traits(classInstanceSize, OrExp),
5518 EXP.xor: __traits(classInstanceSize, XorExp),
5519 EXP.andAssign: __traits(classInstanceSize, AndAssignExp),
5520 EXP.orAssign: __traits(classInstanceSize, OrAssignExp),
5521 EXP.xorAssign: __traits(classInstanceSize, XorAssignExp),
5522 EXP.assign: __traits(classInstanceSize, AssignExp),
5523 EXP.not: __traits(classInstanceSize, NotExp),
5524 EXP.tilde: __traits(classInstanceSize, ComExp),
5525 EXP.plusPlus: __traits(classInstanceSize, PostExp),
5526 EXP.minusMinus: __traits(classInstanceSize, PostExp),
5527 EXP.construct: __traits(classInstanceSize, ConstructExp),
5528 EXP.blit: __traits(classInstanceSize, BlitExp),
5529 EXP.dot: __traits(classInstanceSize, DotExp),
5530 EXP.comma: __traits(classInstanceSize, CommaExp),
5531 EXP.question: __traits(classInstanceSize, CondExp),
5532 EXP.andAnd: __traits(classInstanceSize, LogicalExp),
5533 EXP.orOr: __traits(classInstanceSize, LogicalExp),
5534 EXP.prePlusPlus: __traits(classInstanceSize, PreExp),
5535 EXP.preMinusMinus: __traits(classInstanceSize, PreExp),
5536 EXP.identifier: __traits(classInstanceSize, IdentifierExp),
5537 EXP.string_: __traits(classInstanceSize, StringExp),
5538 EXP.interpolated: __traits(classInstanceSize, InterpExp),
5539 EXP.this_: __traits(classInstanceSize, ThisExp),
5540 EXP.super_: __traits(classInstanceSize, SuperExp),
5541 EXP.halt: __traits(classInstanceSize, HaltExp),
5542 EXP.tuple: __traits(classInstanceSize, TupleExp),
5543 EXP.error: __traits(classInstanceSize, ErrorExp),
5544 EXP.void_: __traits(classInstanceSize, VoidInitExp),
5545 EXP.int64: __traits(classInstanceSize, IntegerExp),
5546 EXP.float64: __traits(classInstanceSize, RealExp),
5547 EXP.complex80: __traits(classInstanceSize, ComplexExp),
5548 EXP.import_: __traits(classInstanceSize, ImportExp),
5549 EXP.delegate_: __traits(classInstanceSize, DelegateExp),
5550 EXP.function_: __traits(classInstanceSize, FuncExp),
5551 EXP.mixin_: __traits(classInstanceSize, MixinExp),
5552 EXP.in_: __traits(classInstanceSize, InExp),
5553 EXP.break_: __traits(classInstanceSize, CTFEExp),
5554 EXP.continue_: __traits(classInstanceSize, CTFEExp),
5555 EXP.goto_: __traits(classInstanceSize, CTFEExp),
5556 EXP.scope_: __traits(classInstanceSize, ScopeExp),
5557 EXP.traits: __traits(classInstanceSize, TraitsExp),
5558 EXP.overloadSet: __traits(classInstanceSize, OverExp),
5559 EXP.line: __traits(classInstanceSize, LineInitExp),
5560 EXP.file: __traits(classInstanceSize, FileInitExp),
5561 EXP.fileFullPath: __traits(classInstanceSize, FileInitExp),
5562 EXP.moduleString: __traits(classInstanceSize, ModuleInitExp),
5563 EXP.functionString: __traits(classInstanceSize, FuncInitExp),
5564 EXP.prettyFunction: __traits(classInstanceSize, PrettyFuncInitExp),
5565 EXP.pow: __traits(classInstanceSize, PowExp),
5566 EXP.powAssign: __traits(classInstanceSize, PowAssignExp),
5567 EXP.vector: __traits(classInstanceSize, VectorExp),
5568 EXP.voidExpression: __traits(classInstanceSize, CTFEExp),
5569 EXP.cantExpression: __traits(classInstanceSize, CTFEExp),
5570 EXP.showCtfeContext: __traits(classInstanceSize, CTFEExp),
5571 EXP.objcClassReference: __traits(classInstanceSize, ObjcClassReferenceExp),
5572 EXP.vectorArray: __traits(classInstanceSize, VectorArrayExp),
5573 EXP.compoundLiteral: __traits(classInstanceSize, CompoundLiteralExp),
5574 EXP._Generic: __traits(classInstanceSize, GenericExp),
5575 EXP.interval: __traits(classInstanceSize, IntervalExp),
5576 EXP.loweredAssignExp : __traits(classInstanceSize, LoweredAssignExp),