d: Merge dmd. druntime e770945277, phobos 6d6e0b9b9
[official-gcc.git] / gcc / d / dmd / ctfeexpr.d
blobaf83aad554548fc2e5c848bed1779bd4596f7934
1 /**
2 * CTFE for expressions involving pointers, slices, array concatenation etc.
4 * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
5 * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
6 * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
7 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/ctfeexpr.d, _ctfeexpr.d)
8 * Documentation: https://dlang.org/phobos/dmd_ctfeexpr.html
9 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/ctfeexpr.d
12 module dmd.ctfeexpr;
14 import core.stdc.stdio;
15 import core.stdc.string;
16 import dmd.arraytypes;
17 import dmd.astenums;
18 import dmd.constfold;
19 import dmd.compiler;
20 import dmd.dclass;
21 import dmd.declaration;
22 import dmd.dinterpret;
23 import dmd.dstruct;
24 import dmd.dtemplate;
25 import dmd.errors;
26 import dmd.expression;
27 import dmd.func;
28 import dmd.globals;
29 import dmd.location;
30 import dmd.mtype;
31 import dmd.root.bitarray;
32 import dmd.root.complex;
33 import dmd.root.ctfloat;
34 import dmd.root.port;
35 import dmd.root.rmem;
36 import dmd.tokens;
37 import dmd.visitor;
39 /****************************************************************/
40 /* A type meant as a union of all the Expression types,
41 * to serve essentially as a Variant that will sit on the stack
42 * during CTFE to reduce memory consumption.
44 extern (D) struct UnionExp
46 // yes, default constructor does nothing
47 extern (D) this(Expression e) nothrow
49 memcpy(&this, cast(void*)e, e.size);
52 /* Extract pointer to Expression
54 extern (D) Expression exp() return nothrow
56 return cast(Expression)&u;
59 /* Convert to an allocated Expression
61 extern (D) Expression copy()
63 Expression e = exp();
64 //if (e.size > sizeof(u)) printf("%s\n", EXPtoString(e.op).ptr);
65 assert(e.size <= u.sizeof);
66 switch (e.op)
68 case EXP.cantExpression: return CTFEExp.cantexp;
69 case EXP.voidExpression: return CTFEExp.voidexp;
70 case EXP.break_: return CTFEExp.breakexp;
71 case EXP.continue_: return CTFEExp.continueexp;
72 case EXP.goto_: return CTFEExp.gotoexp;
73 default: return e.copy();
77 private:
78 // Ensure that the union is suitably aligned.
79 align(8) union _AnonStruct_u
81 char[__traits(classInstanceSize, Expression)] exp;
82 char[__traits(classInstanceSize, IntegerExp)] integerexp;
83 char[__traits(classInstanceSize, ErrorExp)] errorexp;
84 char[__traits(classInstanceSize, RealExp)] realexp;
85 char[__traits(classInstanceSize, ComplexExp)] complexexp;
86 char[__traits(classInstanceSize, SymOffExp)] symoffexp;
87 char[__traits(classInstanceSize, StringExp)] stringexp;
88 char[__traits(classInstanceSize, ArrayLiteralExp)] arrayliteralexp;
89 char[__traits(classInstanceSize, AssocArrayLiteralExp)] assocarrayliteralexp;
90 char[__traits(classInstanceSize, StructLiteralExp)] structliteralexp;
91 char[__traits(classInstanceSize, CompoundLiteralExp)] compoundliteralexp;
92 char[__traits(classInstanceSize, NullExp)] nullexp;
93 char[__traits(classInstanceSize, DotVarExp)] dotvarexp;
94 char[__traits(classInstanceSize, AddrExp)] addrexp;
95 char[__traits(classInstanceSize, IndexExp)] indexexp;
96 char[__traits(classInstanceSize, SliceExp)] sliceexp;
97 char[__traits(classInstanceSize, VectorExp)] vectorexp;
100 _AnonStruct_u u;
103 void emplaceExp(T : Expression, Args...)(void* p, Args args)
105 static if (__VERSION__ < 2099)
106 const init = typeid(T).initializer;
107 else
108 const init = __traits(initSymbol, T);
109 p[0 .. __traits(classInstanceSize, T)] = init[];
110 (cast(T)p).__ctor(args);
113 void emplaceExp(T : UnionExp)(T* p, Expression e) nothrow
115 memcpy(p, cast(void*)e, e.size);
118 // Generate an error message when this exception is not caught
119 void generateUncaughtError(ThrownExceptionExp tee)
121 UnionExp ue = void;
122 Expression e = resolveSlice((*tee.thrown.value.elements)[0], &ue);
123 StringExp se = e.toStringExp();
124 error(tee.thrown.loc, "uncaught CTFE exception `%s(%s)`", tee.thrown.type.toChars(), se ? se.toChars() : e.toChars());
125 /* Also give the line where the throw statement was. We won't have it
126 * in the case where the ThrowStatement is generated internally
127 * (eg, in ScopeStatement)
129 if (tee.loc.isValid() && !tee.loc.equals(tee.thrown.loc))
130 .errorSupplemental(tee.loc, "thrown from here");
133 /*************************
134 * Same as getFieldIndex, but checks for a direct match with the VarDeclaration
135 * Returns:
136 * index of the field, or -1 if not found
138 int findFieldIndexByName(const StructDeclaration sd, const VarDeclaration v) pure @safe nothrow
140 foreach (i, field; sd.fields)
142 if (field == v)
143 return cast(int)i;
145 return -1;
148 // True if 'e' is CTFEExp::cantexp, or an exception
149 bool exceptionOrCantInterpret(const Expression e) @safe nothrow
151 return e && (e.op == EXP.cantExpression || e.op == EXP.thrownException || e.op == EXP.showCtfeContext);
154 /************** Aggregate literals (AA/string/array/struct) ******************/
155 // Given expr, which evaluates to an array/AA/string literal,
156 // return true if it needs to be copied
157 bool needToCopyLiteral(const Expression expr) nothrow
159 Expression e = cast()expr;
160 for (;;)
162 switch (e.op)
164 case EXP.arrayLiteral:
165 return e.isArrayLiteralExp().ownedByCtfe == OwnedBy.code;
166 case EXP.assocArrayLiteral:
167 return e.isAssocArrayLiteralExp().ownedByCtfe == OwnedBy.code;
168 case EXP.structLiteral:
169 return e.isStructLiteralExp().ownedByCtfe == OwnedBy.code;
170 case EXP.string_:
171 case EXP.this_:
172 case EXP.variable:
173 return false;
174 case EXP.assign:
175 return false;
176 case EXP.index:
177 case EXP.dotVariable:
178 case EXP.slice:
179 case EXP.cast_:
180 e = e.isUnaExp().e1;
181 continue;
182 case EXP.concatenate:
183 return needToCopyLiteral(e.isBinExp().e1) || needToCopyLiteral(e.isBinExp().e2);
184 case EXP.concatenateAssign:
185 case EXP.concatenateElemAssign:
186 case EXP.concatenateDcharAssign:
187 e = e.isBinExp().e2;
188 continue;
189 default:
190 return false;
195 private Expressions* copyLiteralArray(Expressions* oldelems, Expression basis = null)
197 if (!oldelems)
198 return oldelems;
199 incArrayAllocs();
200 auto newelems = new Expressions(oldelems.length);
201 foreach (i, el; *oldelems)
203 (*newelems)[i] = copyLiteral(el ? el : basis).copy();
205 return newelems;
208 // Make a copy of the ArrayLiteral, AALiteral, String, or StructLiteral.
209 // This value will be used for in-place modification.
210 UnionExp copyLiteral(Expression e)
212 UnionExp ue = void;
213 if (auto se = e.isStringExp()) // syntaxCopy doesn't make a copy for StringExp!
215 char* s = cast(char*)mem.xcalloc(se.len + 1, se.sz);
216 const slice = se.peekData();
217 memcpy(s, slice.ptr, slice.length);
218 emplaceExp!(StringExp)(&ue, se.loc, s[0 .. se.len * se.sz], se.len, se.sz);
219 StringExp se2 = ue.exp().isStringExp();
220 se2.committed = se.committed;
221 se2.postfix = se.postfix;
222 se2.type = se.type;
223 se2.ownedByCtfe = OwnedBy.ctfe;
224 return ue;
226 if (auto ale = e.isArrayLiteralExp())
228 auto elements = copyLiteralArray(ale.elements, ale.basis);
230 emplaceExp!(ArrayLiteralExp)(&ue, e.loc, e.type, elements);
232 ArrayLiteralExp r = ue.exp().isArrayLiteralExp();
233 r.ownedByCtfe = OwnedBy.ctfe;
234 return ue;
236 if (auto aae = e.isAssocArrayLiteralExp())
238 emplaceExp!(AssocArrayLiteralExp)(&ue, aae.loc, copyLiteralArray(aae.keys), copyLiteralArray(aae.values));
239 AssocArrayLiteralExp r = ue.exp().isAssocArrayLiteralExp();
240 r.type = aae.type;
241 r.lowering = aae.lowering;
242 r.ownedByCtfe = OwnedBy.ctfe;
243 return ue;
245 if (auto sle = e.isStructLiteralExp())
247 /* syntaxCopy doesn't work for struct literals, because of a nasty special
248 * case: block assignment is permitted inside struct literals, eg,
249 * an int[4] array can be initialized with a single int.
251 auto oldelems = sle.elements;
252 auto newelems = new Expressions(oldelems.length);
253 foreach (i, ref el; *newelems)
255 // We need the struct definition to detect block assignment
256 auto v = sle.sd.fields[i];
257 auto m = (*oldelems)[i];
259 // If it is a void assignment, use the default initializer
260 if (!m)
261 m = voidInitLiteral(v.type, v).copy();
263 if (v.type.ty == Tarray || v.type.ty == Taarray)
265 // Don't have to copy array references
267 else
269 // Buzilla 15681: Copy the source element always.
270 m = copyLiteral(m).copy();
272 // Block assignment from inside struct literals
273 if (v.type.ty != m.type.ty && v.type.ty == Tsarray)
275 auto tsa = v.type.isTypeSArray();
276 auto len = cast(size_t)tsa.dim.toInteger();
277 m = createBlockDuplicatedArrayLiteral(&ue, e.loc, v.type, m, len);
278 if (m == ue.exp())
279 m = ue.copy();
282 el = m;
284 emplaceExp!(StructLiteralExp)(&ue, e.loc, sle.sd, newelems, sle.stype);
285 auto r = ue.exp().isStructLiteralExp();
286 r.type = e.type;
287 r.ownedByCtfe = OwnedBy.ctfe;
288 r.origin = sle.origin;
289 return ue;
292 switch(e.op)
294 case EXP.function_:
295 case EXP.delegate_:
296 case EXP.symbolOffset:
297 case EXP.null_:
298 case EXP.variable:
299 case EXP.dotVariable:
300 case EXP.int64:
301 case EXP.float64:
302 case EXP.complex80:
303 case EXP.void_:
304 case EXP.vector:
305 case EXP.typeid_:
306 // Simple value types
307 // Keep e1 for DelegateExp and DotVarExp
308 emplaceExp!(UnionExp)(&ue, e);
309 Expression r = ue.exp();
310 r.type = e.type;
311 return ue;
312 default: break;
315 if (auto se = e.isSliceExp())
317 if (se.type.toBasetype().ty == Tsarray)
319 // same with resolveSlice()
320 if (se.e1.op == EXP.null_)
322 emplaceExp!(NullExp)(&ue, se.loc, se.type);
323 return ue;
325 ue = Slice(se.type, se.e1, se.lwr, se.upr);
326 auto r = ue.exp().isArrayLiteralExp();
327 r.elements = copyLiteralArray(r.elements);
328 r.ownedByCtfe = OwnedBy.ctfe;
329 return ue;
331 else
333 // Array slices only do a shallow copy
334 emplaceExp!(SliceExp)(&ue, e.loc, se.e1, se.lwr, se.upr);
335 Expression r = ue.exp();
336 r.type = e.type;
337 return ue;
340 if (isPointer(e.type))
342 // For pointers, we only do a shallow copy.
343 if (auto ae = e.isAddrExp())
344 emplaceExp!(AddrExp)(&ue, e.loc, ae.e1);
345 else if (auto ie = e.isIndexExp())
346 emplaceExp!(IndexExp)(&ue, e.loc, ie.e1, ie.e2);
347 else if (auto dve = e.isDotVarExp())
349 emplaceExp!(DotVarExp)(&ue, e.loc, dve.e1, dve.var, dve.hasOverloads);
351 else
352 assert(0);
354 Expression r = ue.exp();
355 r.type = e.type;
356 return ue;
358 if (auto cre = e.isClassReferenceExp())
360 emplaceExp!(ClassReferenceExp)(&ue, e.loc, cre.value, e.type);
361 return ue;
363 if (e.op == EXP.error)
365 emplaceExp!(UnionExp)(&ue, e);
366 return ue;
368 error(e.loc, "CTFE internal error: literal `%s`", e.toChars());
369 assert(0);
372 /* Deal with type painting.
373 * Type painting is a major nuisance: we can't just set
374 * e.type = type, because that would change the original literal.
375 * But, we can't simply copy the literal either, because that would change
376 * the values of any pointers.
378 Expression paintTypeOntoLiteral(Type type, Expression lit)
380 if (lit.type.equals(type))
381 return lit;
382 return paintTypeOntoLiteralCopy(type, lit).copy();
385 Expression paintTypeOntoLiteral(UnionExp* pue, Type type, Expression lit)
387 if (lit.type.equals(type))
388 return lit;
389 *pue = paintTypeOntoLiteralCopy(type, lit);
390 return pue.exp();
393 private UnionExp paintTypeOntoLiteralCopy(Type type, Expression lit)
395 UnionExp ue;
396 if (lit.type.equals(type))
398 emplaceExp!(UnionExp)(&ue, lit);
399 return ue;
401 // If it is a cast to inout, retain the original type of the referenced part.
402 if (type.hasWild())
404 emplaceExp!(UnionExp)(&ue, lit);
405 ue.exp().type = type;
406 return ue;
408 if (auto se = lit.isSliceExp())
410 emplaceExp!(SliceExp)(&ue, lit.loc, se.e1, se.lwr, se.upr);
412 else if (auto ie = lit.isIndexExp())
414 emplaceExp!(IndexExp)(&ue, lit.loc, ie.e1, ie.e2);
416 else if (lit.op == EXP.arrayLiteral)
418 emplaceExp!(SliceExp)(&ue, lit.loc, lit, ctfeEmplaceExp!IntegerExp(Loc.initial, 0, Type.tsize_t), ArrayLength(Type.tsize_t, lit).copy());
420 else if (lit.op == EXP.string_)
422 // For strings, we need to introduce another level of indirection
423 emplaceExp!(SliceExp)(&ue, lit.loc, lit, ctfeEmplaceExp!IntegerExp(Loc.initial, 0, Type.tsize_t), ArrayLength(Type.tsize_t, lit).copy());
425 else if (auto aae = lit.isAssocArrayLiteralExp())
427 // TODO: we should be creating a reference to this AAExp, not
428 // just a ref to the keys and values.
429 OwnedBy wasOwned = aae.ownedByCtfe;
430 emplaceExp!(AssocArrayLiteralExp)(&ue, lit.loc, aae.keys, aae.values);
431 aae = ue.exp().isAssocArrayLiteralExp();
432 aae.ownedByCtfe = wasOwned;
434 else
436 // Can't type paint from struct to struct*; this needs another
437 // level of indirection
438 if (lit.op == EXP.structLiteral && isPointer(type))
439 error(lit.loc, "CTFE internal error: painting `%s`", type.toChars());
440 ue = copyLiteral(lit);
442 ue.exp().type = type;
443 return ue;
446 /*************************************
447 * If e is a SliceExp, constant fold it.
448 * Params:
449 * e = expression to resolve
450 * pue = if not null, store resulting expression here
451 * Returns:
452 * resulting expression
454 Expression resolveSlice(Expression e, UnionExp* pue = null)
456 SliceExp se = e.isSliceExp();
457 if (!se)
458 return e;
459 if (se.e1.op == EXP.null_)
460 return se.e1;
461 if (pue)
463 *pue = Slice(e.type, se.e1, se.lwr, se.upr);
464 return pue.exp();
466 else
467 return Slice(e.type, se.e1, se.lwr, se.upr).copy();
470 /* Determine the array length, without interpreting it.
471 * e must be an array literal, or a slice
472 * It's very wasteful to resolve the slice when we only
473 * need the length.
475 uinteger_t resolveArrayLength(Expression e)
477 switch (e.op)
479 case EXP.vector:
480 return e.isVectorExp().dim;
482 case EXP.null_:
483 return 0;
485 case EXP.slice:
487 auto se = e.isSliceExp();
488 const ilo = se.lwr.toInteger();
489 const iup = se.upr.toInteger();
490 return iup - ilo;
493 case EXP.string_:
494 return e.isStringExp().len;
496 case EXP.arrayLiteral:
498 const ale = e.isArrayLiteralExp();
499 return ale.elements ? ale.elements.length : 0;
502 case EXP.assocArrayLiteral:
504 return e.isAssocArrayLiteralExp().keys.length;
507 default:
508 assert(0);
512 /******************************
513 * Helper for NewExp
514 * Create an array literal consisting of 'elem' duplicated 'dim' times.
515 * Params:
516 * pue = where to store result
517 * loc = source location where the interpretation occurs
518 * type = target type of the result
519 * elem = the source of array element, it will be owned by the result
520 * dim = element number of the result
521 * Returns:
522 * Constructed ArrayLiteralExp
524 ArrayLiteralExp createBlockDuplicatedArrayLiteral(UnionExp* pue, const ref Loc loc, Type type, Expression elem, size_t dim)
526 if (type.ty == Tsarray && type.nextOf().ty == Tsarray && elem.type.ty != Tsarray)
528 // If it is a multidimensional array literal, do it recursively
529 auto tsa = type.nextOf().isTypeSArray();
530 const len = cast(size_t)tsa.dim.toInteger();
531 elem = createBlockDuplicatedArrayLiteral(pue, loc, type.nextOf(), elem, len);
532 if (elem == pue.exp())
533 elem = pue.copy();
536 // Buzilla 15681
537 const tb = elem.type.toBasetype();
538 const mustCopy = tb.ty == Tstruct || tb.ty == Tsarray;
540 auto elements = new Expressions(dim);
541 foreach (i, ref el; *elements)
543 el = mustCopy && i ? copyLiteral(elem).copy() : elem;
545 emplaceExp!(ArrayLiteralExp)(pue, loc, type, elements);
546 auto ale = pue.exp().isArrayLiteralExp();
547 ale.ownedByCtfe = OwnedBy.ctfe;
548 return ale;
551 /******************************
552 * Helper for NewExp
553 * Create a string literal consisting of 'value' duplicated 'dim' times.
555 StringExp createBlockDuplicatedStringLiteral(UnionExp* pue, const ref Loc loc, Type type, dchar value, size_t dim, ubyte sz)
557 auto s = cast(char*)mem.xcalloc(dim, sz);
558 foreach (elemi; 0 .. dim)
560 switch (sz)
562 case 1:
563 s[elemi] = cast(char)value;
564 break;
565 case 2:
566 (cast(wchar*)s)[elemi] = cast(wchar)value;
567 break;
568 case 4:
569 (cast(dchar*)s)[elemi] = value;
570 break;
571 case 8:
572 (cast(ulong*)s)[elemi] = value;
573 break;
574 default:
575 assert(0);
578 emplaceExp!(StringExp)(pue, loc, s[0 .. dim * sz], dim, sz);
579 auto se = pue.exp().isStringExp();
580 se.type = type;
581 se.committed = true;
582 se.ownedByCtfe = OwnedBy.ctfe;
583 return se;
586 // Return true if t is an AA
587 bool isAssocArray(Type t)
589 return t.toBasetype().isTypeAArray() !is null;
592 // Given a template AA type, extract the corresponding built-in AA type
593 TypeAArray toBuiltinAAType(Type t)
595 return t.toBasetype().isTypeAArray();
598 /************** TypeInfo operations ************************************/
599 // Return true if type is TypeInfo_Class
600 bool isTypeInfo_Class(const Type type) nothrow
602 auto tc = cast()type.isTypeClass();
603 return tc && (Type.dtypeinfo == tc.sym || Type.dtypeinfo.isBaseOf(tc.sym, null));
606 /************** Pointer operations ************************************/
607 // Return true if t is a pointer (not a function pointer)
608 bool isPointer(Type t)
610 Type tb = t.toBasetype();
611 return tb.ty == Tpointer && tb.nextOf().ty != Tfunction;
614 // For CTFE only. Returns true if 'e' is true or a non-null pointer.
615 bool isTrueBool(Expression e)
617 return e.toBool().hasValue(true) || ((e.type.ty == Tpointer || e.type.ty == Tclass) && e.op != EXP.null_);
620 /* Is it safe to convert from srcPointee* to destPointee* ?
621 * srcPointee is the genuine type (never void).
622 * destPointee may be void.
624 bool isSafePointerCast(Type srcPointee, Type destPointee)
626 // It's safe to cast S** to D** if it's OK to cast S* to D*
627 while (srcPointee.ty == Tpointer && destPointee.ty == Tpointer)
629 srcPointee = srcPointee.nextOf();
630 destPointee = destPointee.nextOf();
632 // It's OK if both are the same (modulo const)
633 if (srcPointee.constConv(destPointee))
634 return true;
636 // It's ok to cast from/to shared because CTFE is single threaded anyways
637 if (srcPointee.unSharedOf() == destPointee.unSharedOf())
638 return true;
640 // It's OK if function pointers differ only in safe/pure/nothrow
641 if (srcPointee.ty == Tfunction && destPointee.ty == Tfunction)
643 import dmd.typesem : covariant;
644 return srcPointee.covariant(destPointee) == Covariant.yes ||
645 destPointee.covariant(srcPointee) == Covariant.yes;
647 // it's OK to cast to void*
648 if (destPointee.ty == Tvoid)
649 return true;
650 // It's OK to cast from V[K] to void*
651 if (srcPointee.ty == Taarray && destPointee == Type.tvoidptr)
652 return true;
653 // It's OK if they are the same size (static array of) integers, eg:
654 // int* --> uint*
655 // int[5][] --> uint[5][]
656 if (srcPointee.ty == Tsarray && destPointee.ty == Tsarray)
658 if (srcPointee.size() != destPointee.size())
659 return false;
660 srcPointee = srcPointee.baseElemOf();
661 destPointee = destPointee.baseElemOf();
663 return srcPointee.isintegral() && destPointee.isintegral() && srcPointee.size() == destPointee.size();
666 Expression getAggregateFromPointer(Expression e, dinteger_t* ofs)
668 *ofs = 0;
669 if (auto ae = e.isAddrExp())
670 e = ae.e1;
671 if (auto soe = e.isSymOffExp())
672 *ofs = soe.offset;
673 if (auto dve = e.isDotVarExp())
675 auto ex = dve.e1;
676 const v = dve.var.isVarDeclaration();
677 assert(v);
678 StructLiteralExp se = (ex.op == EXP.classReference)
679 ? ex.isClassReferenceExp().value
680 : ex.isStructLiteralExp();
682 // We can't use getField, because it makes a copy
683 const i = (ex.op == EXP.classReference)
684 ? ex.isClassReferenceExp().getFieldIndex(e.type, v.offset)
685 : se.getFieldIndex(e.type, v.offset);
686 e = (*se.elements)[i];
688 if (auto ie = e.isIndexExp())
690 // Note that each AA element is part of its own memory block
691 if ((ie.e1.type.ty == Tarray || ie.e1.type.ty == Tsarray || ie.e1.op == EXP.string_ || ie.e1.op == EXP.arrayLiteral) && ie.e2.op == EXP.int64)
693 *ofs = ie.e2.toInteger();
694 return ie.e1;
697 if (auto se = e.isSliceExp())
699 if (se && e.type.toBasetype().ty == Tsarray &&
700 (se.e1.type.ty == Tarray || se.e1.type.ty == Tsarray || se.e1.op == EXP.string_ || se.e1.op == EXP.arrayLiteral) && se.lwr.op == EXP.int64)
702 *ofs = se.lwr.toInteger();
703 return se.e1;
707 // It can be a `null` disguised as a cast, e.g. `cast(void*)0`.
708 if (auto ie = e.isIntegerExp())
709 if (ie.type.ty == Tpointer && ie.getInteger() == 0)
710 return new NullExp(ie.loc, e.type.nextOf());
711 // Those casts are invalid, but let the rest of the code handle it,
712 // as it could be something like `x !is null`, which doesn't need
713 // to dereference the pointer, even if the pointer is `cast(void*)420`.
715 return e;
718 /** Return true if agg1 and agg2 are pointers to the same memory block
720 bool pointToSameMemoryBlock(Expression agg1, Expression agg2)
722 if (agg1 == agg2)
723 return true;
724 // For integers cast to pointers, we regard them as non-comparable
725 // unless they are identical. (This may be overly strict).
726 if (agg1.op == EXP.int64 && agg2.op == EXP.int64 && agg1.toInteger() == agg2.toInteger())
728 return true;
730 // Note that type painting can occur with VarExp, so we
731 // must compare the variables being pointed to.
732 if (agg1.op == EXP.variable && agg2.op == EXP.variable && agg1.isVarExp().var == agg2.isVarExp().var)
734 return true;
736 if (agg1.op == EXP.symbolOffset && agg2.op == EXP.symbolOffset && agg1.isSymOffExp().var == agg2.isSymOffExp().var)
738 return true;
740 return false;
743 // return e1 - e2 as an integer, or error if not possible
744 Expression pointerDifference(UnionExp* pue, const ref Loc loc, Type type, Expression e1, Expression e2)
746 dinteger_t ofs1, ofs2;
747 Expression agg1 = getAggregateFromPointer(e1, &ofs1);
748 Expression agg2 = getAggregateFromPointer(e2, &ofs2);
749 if (agg1 == agg2)
751 Type pointee = agg1.type.nextOf();
752 const sz = pointee.size();
753 emplaceExp!(IntegerExp)(pue, loc, (ofs1 - ofs2) * sz, type);
755 else if (agg1.op == EXP.string_ && agg2.op == EXP.string_ &&
756 agg1.isStringExp().peekString().ptr == agg2.isStringExp().peekString().ptr)
758 Type pointee = agg1.type.nextOf();
759 const sz = pointee.size();
760 emplaceExp!(IntegerExp)(pue, loc, (ofs1 - ofs2) * sz, type);
762 else if (agg1.op == EXP.symbolOffset && agg2.op == EXP.symbolOffset &&
763 agg1.isSymOffExp().var == agg2.isSymOffExp().var)
765 emplaceExp!(IntegerExp)(pue, loc, ofs1 - ofs2, type);
767 else
769 error(loc, "`%s - %s` cannot be interpreted at compile time: cannot subtract pointers to two different memory blocks", e1.toChars(), e2.toChars());
770 emplaceExp!(CTFEExp)(pue, EXP.cantExpression);
772 return pue.exp();
775 // Return eptr op e2, where eptr is a pointer, e2 is an integer,
776 // and op is EXP.add or EXP.min
777 Expression pointerArithmetic(UnionExp* pue, const ref Loc loc, EXP op, Type type, Expression eptr, Expression e2)
779 if (eptr.type.nextOf().ty == Tvoid)
781 error(loc, "cannot perform arithmetic on `void*` pointers at compile time");
782 Lcant:
783 emplaceExp!(CTFEExp)(pue, EXP.cantExpression);
784 return pue.exp();
786 if (eptr.op == EXP.address)
787 eptr = eptr.isAddrExp().e1;
788 dinteger_t ofs1;
789 Expression agg1 = getAggregateFromPointer(eptr, &ofs1);
790 if (agg1.op == EXP.symbolOffset)
792 if (agg1.isSymOffExp().var.type.ty != Tsarray)
794 error(loc, "cannot perform pointer arithmetic on arrays of unknown length at compile time");
795 goto Lcant;
798 else if (agg1.op != EXP.string_ && agg1.op != EXP.arrayLiteral)
800 error(loc, "cannot perform pointer arithmetic on non-arrays at compile time");
801 goto Lcant;
803 dinteger_t ofs2 = e2.toInteger();
804 Type pointee = agg1.type.toBasetype().nextOf();
805 dinteger_t sz = pointee.size();
806 sinteger_t indx;
807 dinteger_t len;
808 if (auto soe = agg1.isSymOffExp())
810 indx = ofs1 / sz;
811 len = soe.var.type.isTypeSArray().dim.toInteger();
813 else
815 Expression dollar = ArrayLength(Type.tsize_t, agg1).copy();
816 assert(!CTFEExp.isCantExp(dollar));
817 indx = ofs1;
818 len = dollar.toInteger();
820 if (op == EXP.add || op == EXP.addAssign || op == EXP.plusPlus)
821 indx += ofs2 / sz;
822 else if (op == EXP.min || op == EXP.minAssign || op == EXP.minusMinus)
823 indx -= ofs2 / sz;
824 else
826 error(loc, "CTFE internal error: bad pointer operation");
827 goto Lcant;
829 if (indx < 0 || len < indx)
831 error(loc, "cannot assign pointer to index %lld inside memory block `[0..%lld]`", indx, len);
832 goto Lcant;
834 if (agg1.op == EXP.symbolOffset)
836 emplaceExp!(SymOffExp)(pue, loc, agg1.isSymOffExp().var, indx * sz);
837 SymOffExp se = pue.exp().isSymOffExp();
838 se.type = type;
839 return pue.exp();
841 if (agg1.op != EXP.arrayLiteral && agg1.op != EXP.string_)
843 error(loc, "CTFE internal error: pointer arithmetic `%s`", agg1.toChars());
844 goto Lcant;
846 if (auto tsa = eptr.type.toBasetype().isTypeSArray())
848 dinteger_t dim = tsa.dim.toInteger();
849 // Create a CTFE pointer &agg1[indx .. indx+dim]
850 auto se = ctfeEmplaceExp!SliceExp(loc, agg1,
851 ctfeEmplaceExp!IntegerExp(loc, indx, Type.tsize_t),
852 ctfeEmplaceExp!IntegerExp(loc, indx + dim, Type.tsize_t));
853 se.type = type.toBasetype().nextOf();
854 emplaceExp!(AddrExp)(pue, loc, se);
855 pue.exp().type = type;
856 return pue.exp();
858 // Create a CTFE pointer &agg1[indx]
859 auto ofs = ctfeEmplaceExp!IntegerExp(loc, indx, Type.tsize_t);
860 Expression ie = ctfeEmplaceExp!IndexExp(loc, agg1, ofs);
861 ie.type = type.toBasetype().nextOf(); // https://issues.dlang.org/show_bug.cgi?id=13992
862 emplaceExp!(AddrExp)(pue, loc, ie);
863 pue.exp().type = type;
864 return pue.exp();
867 // Return 1 if true, 0 if false
868 // -1 if comparison is illegal because they point to non-comparable memory blocks
869 int comparePointers(EXP op, Expression agg1, dinteger_t ofs1, Expression agg2, dinteger_t ofs2)
871 if (pointToSameMemoryBlock(agg1, agg2))
873 int n;
874 switch (op)
876 case EXP.lessThan:
877 n = (ofs1 < ofs2);
878 break;
879 case EXP.lessOrEqual:
880 n = (ofs1 <= ofs2);
881 break;
882 case EXP.greaterThan:
883 n = (ofs1 > ofs2);
884 break;
885 case EXP.greaterOrEqual:
886 n = (ofs1 >= ofs2);
887 break;
888 case EXP.identity:
889 case EXP.equal:
890 n = (ofs1 == ofs2);
891 break;
892 case EXP.notIdentity:
893 case EXP.notEqual:
894 n = (ofs1 != ofs2);
895 break;
896 default:
897 assert(0);
899 return n;
901 const null1 = (agg1.op == EXP.null_);
902 const null2 = (agg2.op == EXP.null_);
903 int cmp;
904 if (null1 || null2)
906 switch (op)
908 case EXP.lessThan:
909 cmp = null1 && !null2;
910 break;
911 case EXP.greaterThan:
912 cmp = !null1 && null2;
913 break;
914 case EXP.lessOrEqual:
915 cmp = null1;
916 break;
917 case EXP.greaterOrEqual:
918 cmp = null2;
919 break;
920 case EXP.identity:
921 case EXP.equal:
922 case EXP.notIdentity: // 'cmp' gets inverted below
923 case EXP.notEqual:
924 cmp = (null1 == null2);
925 break;
926 default:
927 assert(0);
930 else
932 switch (op)
934 case EXP.identity:
935 case EXP.equal:
936 case EXP.notIdentity: // 'cmp' gets inverted below
937 case EXP.notEqual:
938 cmp = 0;
939 break;
940 default:
941 return -1; // memory blocks are different
944 if (op == EXP.notIdentity || op == EXP.notEqual)
945 cmp ^= 1;
946 return cmp;
949 // True if conversion from type 'from' to 'to' involves a reinterpret_cast
950 // floating point -> integer or integer -> floating point
951 bool isFloatIntPaint(Type to, Type from)
953 return from.size() == to.size() && (from.isintegral() && to.isfloating() || from.isfloating() && to.isintegral());
956 // Reinterpret float/int value 'fromVal' as a float/integer of type 'to'.
957 Expression paintFloatInt(UnionExp* pue, Expression fromVal, Type to)
959 if (exceptionOrCantInterpret(fromVal))
960 return fromVal;
961 assert(to.size() == 4 || to.size() == 8);
962 return Compiler.paintAsType(pue, fromVal, to);
965 /******** Constant folding, with support for CTFE ***************************/
966 /// Return true if non-pointer expression e can be compared
967 /// with >,is, ==, etc, using ctfeCmp, ctfeEqual, ctfeIdentity
968 bool isCtfeComparable(Expression e)
970 if (e.op == EXP.slice)
971 e = e.isSliceExp().e1;
972 if (e.isConst() != 1)
974 if (e.op == EXP.null_ || e.op == EXP.string_ || e.op == EXP.function_ || e.op == EXP.delegate_ || e.op == EXP.arrayLiteral || e.op == EXP.structLiteral || e.op == EXP.assocArrayLiteral || e.op == EXP.classReference)
976 return true;
978 // https://issues.dlang.org/show_bug.cgi?id=14123
979 // TypeInfo object is comparable in CTFE
980 if (e.op == EXP.typeid_)
981 return true;
982 return false;
984 return true;
987 /// Map EXP comparison ops
988 private bool numCmp(N)(EXP op, N n1, N n2) nothrow
990 switch (op)
992 case EXP.lessThan:
993 return n1 < n2;
994 case EXP.lessOrEqual:
995 return n1 <= n2;
996 case EXP.greaterThan:
997 return n1 > n2;
998 case EXP.greaterOrEqual:
999 return n1 >= n2;
1001 default:
1002 assert(0);
1006 /// Returns cmp OP 0; where OP is ==, !=, <, >=, etc. Result is 0 or 1
1007 bool specificCmp(EXP op, int rawCmp) @safe nothrow
1009 return numCmp!int(op, rawCmp, 0);
1012 /// Returns e1 OP e2; where OP is ==, !=, <, >=, etc. Result is 0 or 1
1013 bool intUnsignedCmp(EXP op, dinteger_t n1, dinteger_t n2) @safe nothrow
1015 return numCmp!dinteger_t(op, n1, n2);
1018 /// Returns e1 OP e2; where OP is ==, !=, <, >=, etc. Result is 0 or 1
1019 bool intSignedCmp(EXP op, sinteger_t n1, sinteger_t n2) @safe nothrow
1021 return numCmp!sinteger_t(op, n1, n2);
1024 /// Returns e1 OP e2; where OP is ==, !=, <, >=, etc. Result is 0 or 1
1025 bool realCmp(EXP op, real_t r1, real_t r2) @safe nothrow
1027 // Don't rely on compiler, handle NAN arguments separately
1028 if (CTFloat.isNaN(r1) || CTFloat.isNaN(r2)) // if unordered
1030 switch (op)
1032 case EXP.lessThan:
1033 case EXP.lessOrEqual:
1034 case EXP.greaterThan:
1035 case EXP.greaterOrEqual:
1036 return false;
1038 default:
1039 assert(0);
1042 else
1044 return numCmp!real_t(op, r1, r2);
1048 /* Conceptually the same as memcmp(e1, e2).
1049 * e1 and e2 may be strings, arrayliterals, or slices.
1050 * For string types, return <0 if e1 < e2, 0 if e1==e2, >0 if e1 > e2.
1051 * For all other types, return 0 if e1 == e2, !=0 if e1 != e2.
1052 * Returns:
1053 * -1,0,1
1055 private int ctfeCmpArrays(const ref Loc loc, Expression e1, Expression e2, uinteger_t len)
1057 // Resolve slices, if necessary
1058 uinteger_t lo1 = 0;
1059 uinteger_t lo2 = 0;
1061 Expression x1 = e1;
1062 if (auto sle1 = x1.isSliceExp())
1064 lo1 = sle1.lwr.toInteger();
1065 x1 = sle1.e1;
1067 auto se1 = x1.isStringExp();
1068 auto ae1 = x1.isArrayLiteralExp();
1070 Expression x2 = e2;
1071 if (auto sle2 = x2.isSliceExp())
1073 lo2 = sle2.lwr.toInteger();
1074 x2 = sle2.e1;
1076 auto se2 = x2.isStringExp();
1077 auto ae2 = x2.isArrayLiteralExp();
1079 // Now both must be either EXP.arrayLiteral or EXP.string_
1080 if (se1 && se2)
1081 return sliceCmpStringWithString(se1, se2, cast(size_t)lo1, cast(size_t)lo2, cast(size_t)len);
1082 if (se1 && ae2)
1083 return sliceCmpStringWithArray(se1, ae2, cast(size_t)lo1, cast(size_t)lo2, cast(size_t)len);
1084 if (se2 && ae1)
1085 return -sliceCmpStringWithArray(se2, ae1, cast(size_t)lo2, cast(size_t)lo1, cast(size_t)len);
1086 assert(ae1 && ae2);
1087 // Comparing two array literals. This case is potentially recursive.
1088 // If they aren't strings, we just need an equality check rather than
1089 // a full cmp.
1090 const bool needCmp = ae1.type.nextOf().isintegral();
1091 foreach (size_t i; 0 .. cast(size_t)len)
1093 Expression ee1 = (*ae1.elements)[cast(size_t)(lo1 + i)];
1094 Expression ee2 = (*ae2.elements)[cast(size_t)(lo2 + i)];
1095 if (needCmp)
1097 const sinteger_t c = ee1.toInteger() - ee2.toInteger();
1098 if (c > 0)
1099 return 1;
1100 if (c < 0)
1101 return -1;
1103 else
1105 if (ctfeRawCmp(loc, ee1, ee2))
1106 return 1;
1109 return 0;
1112 /* Given a delegate expression e, return .funcptr.
1113 * If e is NullExp, return NULL.
1115 private FuncDeclaration funcptrOf(Expression e) @safe nothrow
1117 assert(e.type.ty == Tdelegate);
1118 if (auto de = e.isDelegateExp())
1119 return de.func;
1120 if (auto fe = e.isFuncExp())
1121 return fe.fd;
1122 assert(e.op == EXP.null_);
1123 return null;
1126 private bool isArray(const Expression e) @safe nothrow
1128 return e.op == EXP.arrayLiteral || e.op == EXP.string_ || e.op == EXP.slice || e.op == EXP.null_;
1131 /*****
1132 * Params:
1133 * loc = source file location
1134 * e1 = left operand
1135 * e2 = right operand
1136 * identity = true for `is` identity comparisons
1137 * Returns:
1138 * For strings, return <0 if e1 < e2, 0 if e1==e2, >0 if e1 > e2.
1139 * For all other types, return 0 if e1 == e2, !=0 if e1 != e2.
1141 private int ctfeRawCmp(const ref Loc loc, Expression e1, Expression e2, bool identity = false)
1143 if (e1.op == EXP.classReference || e2.op == EXP.classReference)
1145 if (e1.op == EXP.classReference && e2.op == EXP.classReference &&
1146 e1.isClassReferenceExp().value == e2.isClassReferenceExp().value)
1147 return 0;
1148 return 1;
1150 if (e1.op == EXP.typeid_ && e2.op == EXP.typeid_)
1152 // printf("e1: %s\n", e1.toChars());
1153 // printf("e2: %s\n", e2.toChars());
1154 Type t1 = isType(e1.isTypeidExp().obj);
1155 Type t2 = isType(e2.isTypeidExp().obj);
1156 assert(t1);
1157 assert(t2);
1158 return t1 != t2;
1160 // null == null, regardless of type
1161 if (e1.op == EXP.null_ && e2.op == EXP.null_)
1162 return 0;
1163 if (e1.type.ty == Tpointer && e2.type.ty == Tpointer)
1165 // Can only be an equality test.
1166 dinteger_t ofs1, ofs2;
1167 Expression agg1 = getAggregateFromPointer(e1, &ofs1);
1168 Expression agg2 = getAggregateFromPointer(e2, &ofs2);
1169 if ((agg1 == agg2) || (agg1.op == EXP.variable && agg2.op == EXP.variable && agg1.isVarExp().var == agg2.isVarExp().var))
1171 if (ofs1 == ofs2)
1172 return 0;
1174 return 1;
1176 if (e1.type.ty == Tdelegate && e2.type.ty == Tdelegate)
1178 // If .funcptr isn't the same, they are not equal
1179 if (funcptrOf(e1) != funcptrOf(e2))
1180 return 1;
1181 // If both are delegate literals, assume they have the
1182 // same closure pointer. TODO: We don't support closures yet!
1183 if (e1.op == EXP.function_ && e2.op == EXP.function_)
1184 return 0;
1185 assert(e1.op == EXP.delegate_ && e2.op == EXP.delegate_);
1186 // Same .funcptr. Do they have the same .ptr?
1187 Expression ptr1 = e1.isDelegateExp().e1;
1188 Expression ptr2 = e2.isDelegateExp().e1;
1189 dinteger_t ofs1, ofs2;
1190 Expression agg1 = getAggregateFromPointer(ptr1, &ofs1);
1191 Expression agg2 = getAggregateFromPointer(ptr2, &ofs2);
1192 // If they are EXP.variable, it means they are FuncDeclarations
1193 if ((agg1 == agg2 && ofs1 == ofs2) || (agg1.op == EXP.variable && agg2.op == EXP.variable && agg1.isVarExp().var == agg2.isVarExp().var))
1195 return 0;
1197 return 1;
1199 if (isArray(e1) && isArray(e2))
1201 const uinteger_t len1 = resolveArrayLength(e1);
1202 const uinteger_t len2 = resolveArrayLength(e2);
1203 // workaround for dmc optimizer bug calculating wrong len for
1204 // uinteger_t len = (len1 < len2 ? len1 : len2);
1205 // if (len == 0) ...
1206 if (len1 > 0 && len2 > 0)
1208 const uinteger_t len = (len1 < len2 ? len1 : len2);
1209 const int res = ctfeCmpArrays(loc, e1, e2, len);
1210 if (res != 0)
1211 return res;
1213 return cast(int)(len1 - len2);
1215 if (e1.type.isintegral())
1217 return e1.toInteger() != e2.toInteger();
1219 if (identity && e1.type.isfloating())
1220 return !e1.isIdentical(e2);
1221 if (e1.type.isreal() || e1.type.isimaginary())
1223 real_t r1 = e1.type.isreal() ? e1.toReal() : e1.toImaginary();
1224 real_t r2 = e1.type.isreal() ? e2.toReal() : e2.toImaginary();
1225 if (CTFloat.isNaN(r1) || CTFloat.isNaN(r2)) // if unordered
1227 return 1; // they are not equal
1229 else
1231 return (r1 != r2);
1234 else if (e1.type.iscomplex())
1236 return e1.toComplex() != e2.toComplex();
1238 if (e1.op == EXP.structLiteral && e2.op == EXP.structLiteral)
1240 StructLiteralExp es1 = e1.isStructLiteralExp();
1241 StructLiteralExp es2 = e2.isStructLiteralExp();
1242 // For structs, we only need to return 0 or 1 (< and > aren't legal).
1243 if (es1.sd != es2.sd)
1244 return 1;
1245 else if ((!es1.elements || !es1.elements.length) && (!es2.elements || !es2.elements.length))
1246 return 0; // both arrays are empty
1247 else if (!es1.elements || !es2.elements)
1248 return 1;
1249 else if (es1.elements.length != es2.elements.length)
1250 return 1;
1251 else
1253 foreach (size_t i; 0 .. es1.elements.length)
1255 Expression ee1 = (*es1.elements)[i];
1256 Expression ee2 = (*es2.elements)[i];
1258 // https://issues.dlang.org/show_bug.cgi?id=16284
1259 if (ee1.op == EXP.void_ && ee2.op == EXP.void_) // if both are VoidInitExp
1260 continue;
1262 if (ee1 == ee2)
1263 continue;
1264 if (!ee1 || !ee2)
1265 return 1;
1266 const int cmp = ctfeRawCmp(loc, ee1, ee2, identity);
1267 if (cmp)
1268 return 1;
1270 return 0; // All elements are equal
1273 if (e1.op == EXP.assocArrayLiteral && e2.op == EXP.assocArrayLiteral)
1275 AssocArrayLiteralExp es1 = e1.isAssocArrayLiteralExp();
1276 AssocArrayLiteralExp es2 = e2.isAssocArrayLiteralExp();
1277 size_t dim = es1.keys.length;
1278 if (es2.keys.length != dim)
1279 return 1;
1280 BitArray used;
1281 used.length = dim;
1282 foreach (size_t i; 0 .. dim)
1284 Expression k1 = (*es1.keys)[i];
1285 Expression v1 = (*es1.values)[i];
1286 Expression v2 = null;
1287 foreach (size_t j; 0 .. dim)
1289 if (used[j])
1290 continue;
1291 Expression k2 = (*es2.keys)[j];
1292 if (ctfeRawCmp(loc, k1, k2, identity))
1293 continue;
1294 used[j] = true;
1295 v2 = (*es2.values)[j];
1296 break;
1298 if (!v2 || ctfeRawCmp(loc, v1, v2, identity))
1300 return 1;
1303 return 0;
1305 else if (e1.op == EXP.assocArrayLiteral && e2.op == EXP.null_)
1307 return e1.isAssocArrayLiteralExp.keys.length != 0;
1309 else if (e1.op == EXP.null_ && e2.op == EXP.assocArrayLiteral)
1311 return e2.isAssocArrayLiteralExp.keys.length != 0;
1314 error(loc, "CTFE internal error: bad compare of `%s` and `%s`", e1.toChars(), e2.toChars());
1315 assert(0);
1318 /// Evaluate ==, !=. Resolves slices before comparing. Returns 0 or 1
1319 bool ctfeEqual(const ref Loc loc, EXP op, Expression e1, Expression e2)
1321 return !ctfeRawCmp(loc, e1, e2) ^ (op == EXP.notEqual);
1324 /// Evaluate is, !is. Resolves slices before comparing. Returns 0 or 1
1325 bool ctfeIdentity(const ref Loc loc, EXP op, Expression e1, Expression e2)
1327 //printf("ctfeIdentity %s %s\n", e1.toChars(), e2.toChars());
1328 //printf("ctfeIdentity op = '%s', e1 = %s %s, e2 = %s %s\n", EXPtoString(op).ptr,
1329 // EXPtoString(e1.op).ptr, e1.toChars(), EXPtoString(e2.op).ptr, e1.toChars());
1330 bool cmp;
1331 if (e1.op == EXP.null_)
1333 cmp = (e2.op == EXP.null_);
1335 else if (e2.op == EXP.null_)
1337 cmp = false;
1339 else if (e1.op == EXP.symbolOffset && e2.op == EXP.symbolOffset)
1341 SymOffExp es1 = e1.isSymOffExp();
1342 SymOffExp es2 = e2.isSymOffExp();
1343 cmp = (es1.var == es2.var && es1.offset == es2.offset);
1345 else if (e1.type.isfloating())
1346 cmp = e1.isIdentical(e2);
1347 else
1349 cmp = !ctfeRawCmp(loc, e1, e2, true);
1351 if (op == EXP.notIdentity || op == EXP.notEqual)
1352 cmp ^= true;
1353 return cmp;
1356 /// Evaluate >,<=, etc. Resolves slices before comparing. Returns 0 or 1
1357 bool ctfeCmp(const ref Loc loc, EXP op, Expression e1, Expression e2)
1359 Type t1 = e1.type.toBasetype();
1360 Type t2 = e2.type.toBasetype();
1362 if (t1.isString() && t2.isString())
1363 return specificCmp(op, ctfeRawCmp(loc, e1, e2));
1364 else if (t1.isreal())
1365 return realCmp(op, e1.toReal(), e2.toReal());
1366 else if (t1.isimaginary())
1367 return realCmp(op, e1.toImaginary(), e2.toImaginary());
1368 else if (t1.isunsigned() || t2.isunsigned())
1369 return intUnsignedCmp(op, e1.toInteger(), e2.toInteger());
1370 else
1371 return intSignedCmp(op, e1.toInteger(), e2.toInteger());
1374 UnionExp ctfeCat(const ref Loc loc, Type type, Expression e1, Expression e2)
1376 Type t1 = e1.type.toBasetype();
1377 Type t2 = e2.type.toBasetype();
1378 UnionExp ue;
1379 if (e2.op == EXP.string_ && e1.op == EXP.arrayLiteral && t1.nextOf().isintegral())
1381 // [chars] ~ string => string (only valid for CTFE)
1382 StringExp es1 = e2.isStringExp();
1383 ArrayLiteralExp es2 = e1.isArrayLiteralExp();
1384 const len = es1.len + es2.elements.length;
1385 const sz = es1.sz;
1386 void* s = mem.xmalloc((len + 1) * sz);
1387 const data1 = es1.peekData();
1388 memcpy(cast(char*)s + sz * es2.elements.length, data1.ptr, data1.length);
1389 foreach (size_t i; 0 .. es2.elements.length)
1391 Expression es2e = (*es2.elements)[i];
1392 if (es2e.op != EXP.int64)
1394 emplaceExp!(CTFEExp)(&ue, EXP.cantExpression);
1395 return ue;
1397 dinteger_t v = es2e.toInteger();
1398 Port.valcpy(cast(char*)s + i * sz, v, sz);
1400 // Add terminating 0
1401 memset(cast(char*)s + len * sz, 0, sz);
1402 emplaceExp!(StringExp)(&ue, loc, s[0 .. len * sz], len, sz);
1403 StringExp es = ue.exp().isStringExp();
1404 es.committed = false;
1405 es.type = type;
1406 return ue;
1408 if (e1.op == EXP.string_ && e2.op == EXP.arrayLiteral && t2.nextOf().isintegral())
1410 // string ~ [chars] => string (only valid for CTFE)
1411 // Concatenate the strings
1412 StringExp es1 = e1.isStringExp();
1413 ArrayLiteralExp es2 = e2.isArrayLiteralExp();
1414 const len = es1.len + es2.elements.length;
1415 const sz = es1.sz;
1416 void* s = mem.xmalloc((len + 1) * sz);
1417 auto slice = es1.peekData();
1418 memcpy(s, slice.ptr, slice.length);
1419 foreach (size_t i; 0 .. es2.elements.length)
1421 Expression es2e = (*es2.elements)[i];
1422 if (es2e.op != EXP.int64)
1424 emplaceExp!(CTFEExp)(&ue, EXP.cantExpression);
1425 return ue;
1427 const v = es2e.toInteger();
1428 Port.valcpy(cast(char*)s + (es1.len + i) * sz, v, sz);
1430 // Add terminating 0
1431 memset(cast(char*)s + len * sz, 0, sz);
1432 emplaceExp!(StringExp)(&ue, loc, s[0 .. len * sz], len, sz);
1433 StringExp es = ue.exp().isStringExp();
1434 es.sz = sz;
1435 es.committed = false; //es1.committed;
1436 es.type = type;
1437 return ue;
1439 if (e1.op == EXP.arrayLiteral && e2.op == EXP.arrayLiteral && t1.nextOf().equals(t2.nextOf()))
1441 // [ e1 ] ~ [ e2 ] ---> [ e1, e2 ]
1442 ArrayLiteralExp es1 = e1.isArrayLiteralExp();
1443 ArrayLiteralExp es2 = e2.isArrayLiteralExp();
1444 emplaceExp!(ArrayLiteralExp)(&ue, es1.loc, type, copyLiteralArray(es1.elements));
1445 es1 = ue.exp().isArrayLiteralExp();
1446 es1.elements.insert(es1.elements.length, copyLiteralArray(es2.elements));
1447 return ue;
1449 if (e1.op == EXP.arrayLiteral && e2.op == EXP.null_ && t1.nextOf().equals(t2.nextOf()))
1451 // [ e1 ] ~ null ----> [ e1 ].dup
1452 ue = paintTypeOntoLiteralCopy(type, copyLiteral(e1).copy());
1453 return ue;
1455 if (e1.op == EXP.null_ && e2.op == EXP.arrayLiteral && t1.nextOf().equals(t2.nextOf()))
1457 // null ~ [ e2 ] ----> [ e2 ].dup
1458 ue = paintTypeOntoLiteralCopy(type, copyLiteral(e2).copy());
1459 return ue;
1461 ue = Cat(loc, type, e1, e2);
1462 return ue;
1465 /* Given an AA literal 'ae', and a key 'e2':
1466 * Return ae[e2] if present, or NULL if not found.
1468 Expression findKeyInAA(const ref Loc loc, AssocArrayLiteralExp ae, Expression e2)
1470 /* Search the keys backwards, in case there are duplicate keys
1472 for (size_t i = ae.keys.length; i;)
1474 --i;
1475 Expression ekey = (*ae.keys)[i];
1476 const int eq = ctfeEqual(loc, EXP.equal, ekey, e2);
1477 if (eq)
1479 return (*ae.values)[i];
1482 return null;
1485 /* Same as for constfold.Index, except that it only works for static arrays,
1486 * dynamic arrays, and strings. We know that e1 is an
1487 * interpreted CTFE expression, so it cannot have side-effects.
1489 Expression ctfeIndex(UnionExp* pue, const ref Loc loc, Type type, Expression e1, uinteger_t indx)
1491 //printf("ctfeIndex(e1 = %s)\n", e1.toChars());
1492 assert(e1.type);
1493 if (auto es1 = e1.isStringExp())
1495 if (indx >= es1.len)
1497 error(loc, "string index %llu is out of bounds `[0 .. %llu]`", indx, cast(ulong)es1.len);
1498 return CTFEExp.cantexp;
1500 emplaceExp!IntegerExp(pue, loc, es1.getIndex(cast(size_t) indx), type);
1501 return pue.exp();
1504 if (auto ale = e1.isArrayLiteralExp())
1506 if (indx >= ale.elements.length)
1508 error(loc, "array index %llu is out of bounds `%s[0 .. %llu]`", indx, e1.toChars(), cast(ulong)ale.elements.length);
1509 return CTFEExp.cantexp;
1511 Expression e = (*ale.elements)[cast(size_t)indx];
1512 return paintTypeOntoLiteral(pue, type, e);
1515 assert(0);
1518 Expression ctfeCast(UnionExp* pue, const ref Loc loc, Type type, Type to, Expression e, bool explicitCast = false)
1520 Expression paint()
1522 return paintTypeOntoLiteral(pue, to, e);
1525 if (e.op == EXP.null_)
1526 return paint();
1528 if (e.op == EXP.classReference)
1530 // Disallow reinterpreting class casts. Do this by ensuring that
1531 // the original class can implicitly convert to the target class.
1532 // Also do not check 'alias this' for explicit cast expressions.
1533 auto tclass = e.isClassReferenceExp().originalClass().type.isTypeClass();
1534 auto match = explicitCast ? tclass.implicitConvToWithoutAliasThis(to.mutableOf())
1535 : tclass.implicitConvTo(to.mutableOf());
1536 if (match)
1537 return paint();
1538 else
1540 emplaceExp!(NullExp)(pue, loc, to);
1541 return pue.exp();
1545 // Allow TypeInfo type painting
1546 if (isTypeInfo_Class(e.type) && e.type.implicitConvTo(to))
1547 return paint();
1549 // Allow casting away const for struct literals
1550 if (e.op == EXP.structLiteral && e.type.toBasetype().castMod(0) == to.toBasetype().castMod(0))
1551 return paint();
1553 Expression r;
1554 if (e.type.equals(type) && type.equals(to))
1556 // necessary not to change e's address for pointer comparisons
1557 r = e;
1559 else if (to.toBasetype().ty == Tarray &&
1560 type.toBasetype().ty == Tarray &&
1561 to.toBasetype().nextOf().size() == type.toBasetype().nextOf().size())
1563 // https://issues.dlang.org/show_bug.cgi?id=12495
1564 // Array reinterpret casts: eg. string to immutable(ubyte)[]
1565 return paint();
1567 else
1569 *pue = Cast(loc, type, to, e);
1570 r = pue.exp();
1573 if (CTFEExp.isCantExp(r))
1574 error(loc, "cannot cast `%s` to `%s` at compile time", e.toChars(), to.toChars());
1576 if (auto ae = e.isArrayLiteralExp())
1577 ae.ownedByCtfe = OwnedBy.ctfe;
1579 if (auto se = e.isStringExp())
1580 se.ownedByCtfe = OwnedBy.ctfe;
1582 return r;
1585 /******** Assignment helper functions ***************************/
1586 /* Set dest = src, where both dest and src are container value literals
1587 * (ie, struct literals, or static arrays (can be an array literal or a string))
1588 * Assignment is recursively in-place.
1589 * Purpose: any reference to a member of 'dest' will remain valid after the
1590 * assignment.
1592 void assignInPlace(Expression dest, Expression src)
1594 if (!(dest.op == EXP.structLiteral || dest.op == EXP.arrayLiteral || dest.op == EXP.string_))
1596 printf("invalid op %d %d\n", src.op, dest.op);
1597 assert(0);
1599 Expressions* oldelems;
1600 Expressions* newelems;
1601 if (dest.op == EXP.structLiteral)
1603 assert(dest.op == src.op);
1604 oldelems = dest.isStructLiteralExp().elements;
1605 newelems = src.isStructLiteralExp().elements;
1606 auto sd = dest.isStructLiteralExp().sd;
1607 const nfields = sd.nonHiddenFields();
1608 const nvthis = sd.fields.length - nfields;
1609 if (nvthis && oldelems.length >= nfields && oldelems.length < newelems.length)
1610 foreach (_; 0 .. newelems.length - oldelems.length)
1611 oldelems.push(null);
1613 else if (dest.op == EXP.arrayLiteral && src.op == EXP.arrayLiteral)
1615 oldelems = dest.isArrayLiteralExp().elements;
1616 newelems = src.isArrayLiteralExp().elements;
1618 else if (dest.op == EXP.string_ && src.op == EXP.string_)
1620 sliceAssignStringFromString(dest.isStringExp(), src.isStringExp(), 0);
1621 return;
1623 else if (dest.op == EXP.arrayLiteral && src.op == EXP.string_)
1625 sliceAssignArrayLiteralFromString(dest.isArrayLiteralExp(), src.isStringExp(), 0);
1626 return;
1628 else if (src.op == EXP.arrayLiteral && dest.op == EXP.string_)
1630 sliceAssignStringFromArrayLiteral(dest.isStringExp(), src.isArrayLiteralExp(), 0);
1631 return;
1633 else
1635 printf("invalid op %d %d\n", src.op, dest.op);
1636 assert(0);
1638 assert(oldelems.length == newelems.length);
1639 foreach (size_t i; 0 .. oldelems.length)
1641 Expression e = (*newelems)[i];
1642 Expression o = (*oldelems)[i];
1643 if (e.op == EXP.structLiteral)
1645 assert(o.op == e.op);
1646 assignInPlace(o, e);
1648 else if (e.type.ty == Tsarray && e.op != EXP.void_ && o.type.ty == Tsarray)
1650 assignInPlace(o, e);
1652 else
1654 (*oldelems)[i] = (*newelems)[i];
1659 // Given an AA literal aae, set aae[index] = newval and return newval.
1660 Expression assignAssocArrayElement(const ref Loc loc, AssocArrayLiteralExp aae, Expression index, Expression newval)
1662 /* Create new associative array literal reflecting updated key/value
1664 Expressions* keysx = aae.keys;
1665 Expressions* valuesx = aae.values;
1666 int updated = 0;
1667 for (size_t j = valuesx.length; j;)
1669 j--;
1670 Expression ekey = (*aae.keys)[j];
1671 int eq = ctfeEqual(loc, EXP.equal, ekey, index);
1672 if (eq)
1674 (*valuesx)[j] = newval;
1675 updated = 1;
1678 if (!updated)
1680 // Append index/newval to keysx[]/valuesx[]
1681 valuesx.push(newval);
1682 keysx.push(index);
1684 return newval;
1687 /// Given array literal oldval of type ArrayLiteralExp or StringExp, of length
1688 /// oldlen, change its length to newlen. If the newlen is longer than oldlen,
1689 /// all new elements will be set to the default initializer for the element type.
1690 Expression changeArrayLiteralLength(UnionExp* pue, const ref Loc loc, TypeArray arrayType, Expression oldval, size_t oldlen, size_t newlen)
1692 Type elemType = arrayType.next;
1693 assert(elemType);
1694 Expression defaultElem = elemType.defaultInitLiteral(loc);
1695 auto elements = new Expressions(newlen);
1696 // Resolve slices
1697 size_t indxlo = 0;
1698 if (oldval.op == EXP.slice)
1700 indxlo = cast(size_t)oldval.isSliceExp().lwr.toInteger();
1701 oldval = oldval.isSliceExp().e1;
1703 size_t copylen = oldlen < newlen ? oldlen : newlen;
1704 if (oldval.op == EXP.string_)
1706 StringExp oldse = oldval.isStringExp();
1707 void* s = mem.xcalloc(newlen + 1, oldse.sz);
1708 const data = oldse.peekData();
1709 memcpy(s, data.ptr, copylen * oldse.sz);
1710 const defaultValue = cast(ulong)defaultElem.toInteger();
1711 foreach (size_t elemi; copylen .. newlen)
1713 switch (oldse.sz)
1715 case 1:
1716 (cast(char*)s)[cast(size_t)(indxlo + elemi)] = cast(char)defaultValue;
1717 break;
1718 case 2:
1719 (cast(wchar*)s)[cast(size_t)(indxlo + elemi)] = cast(wchar)defaultValue;
1720 break;
1721 case 4:
1722 (cast(dchar*)s)[cast(size_t)(indxlo + elemi)] = cast(dchar)defaultValue;
1723 break;
1724 case 8:
1725 (cast(ulong*)s)[cast(size_t)(indxlo + elemi)] = cast(ulong)defaultValue;
1726 break;
1727 default:
1728 assert(0);
1731 emplaceExp!(StringExp)(pue, loc, s[0 .. newlen * oldse.sz], newlen, oldse.sz);
1732 StringExp se = pue.exp().isStringExp();
1733 se.type = arrayType;
1734 se.sz = oldse.sz;
1735 se.committed = oldse.committed;
1736 se.ownedByCtfe = OwnedBy.ctfe;
1738 else
1740 if (oldlen != 0)
1742 assert(oldval.op == EXP.arrayLiteral);
1743 ArrayLiteralExp ae = oldval.isArrayLiteralExp();
1744 foreach (size_t i; 0 .. copylen)
1745 (*elements)[i] = (*ae.elements)[indxlo + i];
1747 if (elemType.ty == Tstruct || elemType.ty == Tsarray)
1749 /* If it is an aggregate literal representing a value type,
1750 * we need to create a unique copy for each element
1752 foreach (size_t i; copylen .. newlen)
1753 (*elements)[i] = copyLiteral(defaultElem).copy();
1755 else
1757 foreach (size_t i; copylen .. newlen)
1758 (*elements)[i] = defaultElem;
1760 emplaceExp!(ArrayLiteralExp)(pue, loc, arrayType, elements);
1761 ArrayLiteralExp aae = pue.exp().isArrayLiteralExp();
1762 aae.ownedByCtfe = OwnedBy.ctfe;
1764 return pue.exp();
1767 /*************************** CTFE Sanity Checks ***************************/
1769 bool isCtfeValueValid(Expression newval)
1771 Type tb = newval.type.toBasetype();
1772 switch (newval.op)
1774 case EXP.int64:
1775 case EXP.float64:
1776 case EXP.complex80:
1777 return tb.isscalar();
1779 case EXP.null_:
1780 return tb.ty == Tnull ||
1781 tb.ty == Tpointer ||
1782 tb.ty == Tarray ||
1783 tb.ty == Taarray ||
1784 tb.ty == Tclass ||
1785 tb.ty == Tdelegate;
1787 case EXP.string_:
1788 return true; // CTFE would directly use the StringExp in AST.
1790 case EXP.arrayLiteral:
1791 return true; //((ArrayLiteralExp *)newval)->ownedByCtfe;
1793 case EXP.assocArrayLiteral:
1794 return true; //((AssocArrayLiteralExp *)newval)->ownedByCtfe;
1796 case EXP.structLiteral:
1797 return true; //((StructLiteralExp *)newval)->ownedByCtfe;
1799 case EXP.classReference:
1800 return true;
1802 case EXP.type:
1803 return true;
1805 case EXP.vector:
1806 return true; // vector literal
1808 case EXP.function_:
1809 return true; // function literal or delegate literal
1811 case EXP.delegate_:
1813 // &struct.func or &clasinst.func
1814 // &nestedfunc
1815 Expression ethis = newval.isDelegateExp().e1;
1816 return (ethis.op == EXP.structLiteral || ethis.op == EXP.classReference || ethis.op == EXP.variable && ethis.isVarExp().var == newval.isDelegateExp().func);
1819 case EXP.symbolOffset:
1821 // function pointer, or pointer to static variable
1822 Declaration d = newval.isSymOffExp().var;
1823 return d.isFuncDeclaration() || d.isDataseg();
1826 case EXP.typeid_:
1828 // always valid
1829 return true;
1832 case EXP.address:
1834 // e1 should be a CTFE reference
1835 Expression e1 = newval.isAddrExp().e1;
1836 return tb.ty == Tpointer &&
1838 (e1.op == EXP.structLiteral || e1.op == EXP.arrayLiteral) && isCtfeValueValid(e1) ||
1839 e1.op == EXP.variable ||
1840 e1.op == EXP.dotVariable && isCtfeReferenceValid(e1) ||
1841 e1.op == EXP.index && isCtfeReferenceValid(e1) ||
1842 e1.op == EXP.slice && e1.type.toBasetype().ty == Tsarray
1846 case EXP.slice:
1848 // e1 should be an array aggregate
1849 const SliceExp se = newval.isSliceExp();
1850 assert(se.lwr && se.lwr.op == EXP.int64);
1851 assert(se.upr && se.upr.op == EXP.int64);
1852 return (tb.ty == Tarray || tb.ty == Tsarray) && (se.e1.op == EXP.string_ || se.e1.op == EXP.arrayLiteral);
1855 case EXP.void_:
1856 return true; // uninitialized value
1858 default:
1859 error(newval.loc, "CTFE internal error: illegal CTFE value `%s`", newval.toChars());
1860 return false;
1864 bool isCtfeReferenceValid(Expression newval)
1866 switch (newval.op)
1868 case EXP.this_:
1869 return true;
1871 case EXP.variable:
1873 const VarDeclaration v = newval.isVarExp().var.isVarDeclaration();
1874 assert(v);
1875 // Must not be a reference to a reference
1876 return true;
1879 case EXP.index:
1881 const Expression eagg = newval.isIndexExp().e1;
1882 return eagg.op == EXP.string_ || eagg.op == EXP.arrayLiteral || eagg.op == EXP.assocArrayLiteral;
1885 case EXP.dotVariable:
1887 Expression eagg = newval.isDotVarExp().e1;
1888 return (eagg.op == EXP.structLiteral || eagg.op == EXP.classReference) && isCtfeValueValid(eagg);
1891 default:
1892 // Internally a ref variable may directly point a stack memory.
1893 // e.g. ref int v = 1;
1894 return isCtfeValueValid(newval);
1898 // Used for debugging only
1899 void showCtfeExpr(Expression e, int level = 0)
1901 for (int i = level; i > 0; --i)
1902 printf(" ");
1903 Expressions* elements = null;
1904 // We need the struct definition to detect block assignment
1905 StructDeclaration sd = null;
1906 ClassDeclaration cd = null;
1907 if (e.op == EXP.structLiteral)
1909 elements = e.isStructLiteralExp().elements;
1910 sd = e.isStructLiteralExp().sd;
1911 printf("STRUCT type = %s %p:\n", e.type.toChars(), e);
1913 else if (e.op == EXP.classReference)
1915 elements = e.isClassReferenceExp().value.elements;
1916 cd = e.isClassReferenceExp().originalClass();
1917 printf("CLASS type = %s %p:\n", e.type.toChars(), e.isClassReferenceExp().value);
1919 else if (e.op == EXP.arrayLiteral)
1921 elements = e.isArrayLiteralExp().elements;
1922 printf("ARRAY LITERAL type=%s %p:\n", e.type.toChars(), e);
1924 else if (e.op == EXP.assocArrayLiteral)
1926 printf("AA LITERAL type=%s %p:\n", e.type.toChars(), e);
1928 else if (e.op == EXP.string_)
1930 printf("STRING %s %p\n", e.toChars(), e.isStringExp.peekString.ptr);
1932 else if (e.op == EXP.slice)
1934 printf("SLICE %p: %s\n", e, e.toChars());
1935 showCtfeExpr(e.isSliceExp().e1, level + 1);
1937 else if (e.op == EXP.variable)
1939 printf("VAR %p %s\n", e, e.toChars());
1940 VarDeclaration v = e.isVarExp().var.isVarDeclaration();
1941 if (v && getValue(v))
1942 showCtfeExpr(getValue(v), level + 1);
1944 else if (e.op == EXP.address)
1946 // This is potentially recursive. We mustn't try to print the thing we're pointing to.
1947 printf("POINTER %p to %p: %s\n", e, e.isAddrExp().e1, e.toChars());
1949 else
1950 printf("VALUE %p: %s\n", e, e.toChars());
1951 if (elements)
1953 size_t fieldsSoFar = 0;
1954 for (size_t i = 0; i < elements.length; i++)
1956 Expression z = null;
1957 VarDeclaration v = null;
1958 if (i > 15)
1960 printf("...(total %d elements)\n", cast(int)elements.length);
1961 return;
1963 if (sd)
1965 v = sd.fields[i];
1966 z = (*elements)[i];
1968 else if (cd)
1970 while (i - fieldsSoFar >= cd.fields.length)
1972 fieldsSoFar += cd.fields.length;
1973 cd = cd.baseClass;
1974 for (int j = level; j > 0; --j)
1975 printf(" ");
1976 printf(" BASE CLASS: %s\n", cd.toChars());
1978 v = cd.fields[i - fieldsSoFar];
1979 assert((elements.length + i) >= (fieldsSoFar + cd.fields.length));
1980 size_t indx = (elements.length - fieldsSoFar) - cd.fields.length + i;
1981 assert(indx < elements.length);
1982 z = (*elements)[indx];
1984 if (!z)
1986 for (int j = level; j > 0; --j)
1987 printf(" ");
1988 printf(" void\n");
1989 continue;
1991 if (v)
1993 // If it is a void assignment, use the default initializer
1994 if ((v.type.ty != z.type.ty) && v.type.ty == Tsarray)
1996 for (int j = level; --j;)
1997 printf(" ");
1998 printf(" field: block initialized static array\n");
1999 continue;
2002 showCtfeExpr(z, level + 1);
2007 /*************************** Void initialization ***************************/
2008 UnionExp voidInitLiteral(Type t, VarDeclaration var)
2010 UnionExp ue;
2011 if (auto tsa = t.isTypeSArray())
2013 Expression elem = voidInitLiteral(tsa.next, var).copy();
2014 // For aggregate value types (structs, static arrays) we must
2015 // create an a separate copy for each element.
2016 const mustCopy = (elem.op == EXP.arrayLiteral || elem.op == EXP.structLiteral);
2017 const d = cast(size_t)tsa.dim.toInteger();
2018 auto elements = new Expressions(d);
2019 foreach (i; 0 .. d)
2021 if (mustCopy && i > 0)
2022 elem = copyLiteral(elem).copy();
2023 (*elements)[i] = elem;
2025 emplaceExp!(ArrayLiteralExp)(&ue, var.loc, tsa, elements);
2026 ArrayLiteralExp ae = ue.exp().isArrayLiteralExp();
2027 ae.ownedByCtfe = OwnedBy.ctfe;
2029 else if (auto ts = t.isTypeStruct())
2031 auto exps = new Expressions(ts.sym.fields.length);
2032 foreach (size_t i; 0 .. ts.sym.fields.length)
2034 (*exps)[i] = voidInitLiteral(ts.sym.fields[i].type, ts.sym.fields[i]).copy();
2036 emplaceExp!(StructLiteralExp)(&ue, var.loc, ts.sym, exps);
2037 StructLiteralExp se = ue.exp().isStructLiteralExp();
2038 se.type = ts;
2039 se.ownedByCtfe = OwnedBy.ctfe;
2041 else
2042 emplaceExp!(VoidInitExp)(&ue, var);
2043 return ue;