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