2 * The entry point for CTFE.
4 * Specification: ($LINK2 https://dlang.org/spec/function.html#interpretation, Compile Time Function Execution (CTFE))
6 * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
7 * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
8 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
9 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dinterpret.d, _dinterpret.d)
10 * Documentation: https://dlang.org/phobos/dmd_dinterpret.html
11 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/dinterpret.d
14 module dmd.dinterpret;
16 import core.stdc.stdio;
17 import core.stdc.stdlib;
18 import core.stdc.string;
20 import dmd.arraytypes;
27 import dmd.declaration;
30 import dmd.dsymbolsem;
33 import dmd.expression;
34 import dmd.expressionsem;
39 import dmd.identifier;
45 import dmd.root.array;
46 import dmd.root.ctfloat;
47 import dmd.root.region;
48 import dmd.root.rootobject;
54 /*************************************
55 * Entry point for CTFE.
56 * A compile-time result is required. Give an error if not possible.
58 * `e` must be semantically valid expression. In other words, it should not
59 * contain any `ErrorExp`s in it. But, CTFE interpretation will cross over
60 * functions and may invoke a function that contains `ErrorStatement` in its body.
61 * If that, the "CTFE failed because of previous errors" error is raised.
63 public Expression ctfeInterpret(Expression e)
77 case EXP.template_: // non-eponymous template/instance
78 case EXP.scope_: // ditto
79 case EXP.dotTemplateDeclaration: // ditto, e.e1 doesn't matter here
80 case EXP.dotTemplateInstance: // ditto
81 case EXP.dot: // ditto
82 if (e.type.ty == Terror)
83 return ErrorExp.get();
93 assert(e.type); // https://issues.dlang.org/show_bug.cgi?id=14642
94 //assert(e.type.ty != Terror); // FIXME
95 if (e.type.ty == Terror)
96 return ErrorExp.get();
98 auto rgnpos = ctfeGlobals.region.savePos();
100 Expression result = interpret(e, null);
102 result = copyRegionExp(result);
104 if (!CTFEExp.isCantExp(result))
105 result = scrubReturnValue(e.loc, result);
106 if (CTFEExp.isCantExp(result))
107 result = ErrorExp.get();
109 ctfeGlobals.region.release(rgnpos);
114 /* Run CTFE on the expression, but allow the expression to be a TypeExp
115 * or a tuple containing a TypeExp. (This is required by pragma(msg)).
117 public Expression ctfeInterpretForPragmaMsg(Expression e)
119 if (e.op == EXP.error || e.op == EXP.type)
122 // It's also OK for it to be a function declaration (happens only with
123 // __traits(getOverloads))
124 if (auto ve = e.isVarExp())
125 if (ve.var.isFuncDeclaration())
130 auto tup = e.isTupleExp();
132 return e.ctfeInterpret();
134 // Tuples need to be treated separately, since they are
135 // allowed to contain a TypeExp in this case.
137 Expressions* expsx = null;
138 foreach (i, g; *tup.exps)
140 auto h = ctfeInterpretForPragmaMsg(g);
145 expsx = tup.exps.copy();
152 auto te = new TupleExp(e.loc, expsx);
153 expandTuples(te.exps);
154 te.type = new TypeTuple(te.exps);
160 public extern (C++) Expression getValue(VarDeclaration vd)
162 return ctfeGlobals.stack.getValue(vd);
165 /*************************************************
166 * Allocate an Expression in the ctfe region.
168 * T = type of Expression to allocate
169 * args = arguments to Expression's constructor
171 * allocated Expression
173 T ctfeEmplaceExp(T : Expression, Args...)(Args args)
177 auto p = ctfeGlobals.region.malloc(__traits(classInstanceSize, T));
178 emplaceExp!T(p, args);
182 // CTFE diagnostic information
183 public extern (C++) void printCtfePerformanceStats()
185 debug (SHOWPERFORMANCE)
187 printf(" ---- CTFE Performance ----\n");
188 printf("max call depth = %d\tmax stack = %d\n", ctfeGlobals.maxCallDepth, ctfeGlobals.stack.maxStackUsage());
189 printf("array allocs = %d\tassignments = %d\n\n", ctfeGlobals.numArrayAllocs, ctfeGlobals.numAssignments);
193 /**************************
196 void incArrayAllocs()
198 ++ctfeGlobals.numArrayAllocs;
201 /* ================================================ Implementation ======================================= */
206 * Collect together globals used by CTFE
214 int callDepth = 0; // current number of recursive calls
216 // When printing a stack trace, suppress this number of calls
217 int stackTraceCallsToSuppress = 0;
219 int maxCallDepth = 0; // highest number of recursive calls
220 int numArrayAllocs = 0; // Number of allocated arrays
221 int numAssignments = 0; // total number of assignments executed
224 __gshared CtfeGlobals ctfeGlobals;
228 RValue, /// Must return an Rvalue (== CTFE value)
229 LValue, /// Must return an Lvalue (== CTFE reference)
230 Nothing, /// The return value is not required
235 //debug = LOGCOMPILE;
236 //debug = SHOWPERFORMANCE;
238 // Maximum allowable recursive function calls in CTFE
239 enum CTFE_RECURSION_LIMIT = 1000;
242 The values of all CTFE variables
247 /* The stack. Every declaration we encounter is pushed here,
248 * together with the VarDeclaration, and the previous
249 * stack address of that variable, so that we can restore it
250 * when we leave the stack frame.
251 * Note that when a function is forward referenced, the interpreter must
252 * run semantic3, and that may start CTFE again with a NULL istate. Thus
253 * the stack might not be empty when CTFE begins.
255 * Ctfe Stack addresses are just 0-based integers, but we save
256 * them as 'void *' because Array can only do pointers.
258 Expressions values; // values on the stack
259 VarDeclarations vars; // corresponding variables
260 Array!(void*) savedId; // id of the previous state of that var
262 Array!(void*) frames; // all previous frame pointers
263 Expressions savedThis; // all previous values of localThis
265 /* Global constants get saved here after evaluation, so we never
266 * have to redo them. This saves a lot of time and memory.
268 Expressions globalValues; // values of global constants
270 size_t framepointer; // current frame pointer
271 size_t maxStackPointer; // most stack we've ever used
272 Expression localThis; // value of 'this', or NULL if none
275 extern (C++) size_t stackPointer()
280 // The current value of 'this', or NULL if none
281 extern (C++) Expression getThis()
286 // Largest number of stack positions we've used
287 extern (C++) size_t maxStackUsage()
289 return maxStackPointer;
292 // Start a new stack frame, using the provided 'this'.
293 extern (C++) void startFrame(Expression thisexp)
295 frames.push(cast(void*)cast(size_t)framepointer);
296 savedThis.push(localThis);
297 framepointer = stackPointer();
301 extern (C++) void endFrame()
303 size_t oldframe = cast(size_t)frames[frames.dim - 1];
304 localThis = savedThis[savedThis.dim - 1];
305 popAll(framepointer);
306 framepointer = oldframe;
307 frames.setDim(frames.dim - 1);
308 savedThis.setDim(savedThis.dim - 1);
311 extern (C++) bool isInCurrentFrame(VarDeclaration v)
313 if (v.isDataseg() && !v.isCTFE())
314 return false; // It's a global
315 return v.ctfeAdrOnStack >= framepointer;
318 extern (C++) Expression getValue(VarDeclaration v)
320 //printf("getValue() %s\n", v.toChars());
321 if ((v.isDataseg() || v.storage_class & STC.manifest) && !v.isCTFE())
323 assert(v.ctfeAdrOnStack < globalValues.dim);
324 return globalValues[v.ctfeAdrOnStack];
326 assert(v.ctfeAdrOnStack < stackPointer());
327 return values[v.ctfeAdrOnStack];
330 extern (C++) void setValue(VarDeclaration v, Expression e)
332 //printf("setValue() %s : %s\n", v.toChars(), e.toChars());
333 assert(!v.isDataseg() || v.isCTFE());
334 assert(v.ctfeAdrOnStack < stackPointer());
335 values[v.ctfeAdrOnStack] = e;
338 extern (C++) void push(VarDeclaration v)
340 //printf("push() %s\n", v.toChars());
341 assert(!v.isDataseg() || v.isCTFE());
342 if (v.ctfeAdrOnStack != VarDeclaration.AdrOnStackNone && v.ctfeAdrOnStack >= framepointer)
344 // Already exists in this frame, reuse it.
345 values[v.ctfeAdrOnStack] = null;
348 savedId.push(cast(void*)cast(size_t)v.ctfeAdrOnStack);
349 v.ctfeAdrOnStack = cast(uint)values.dim;
354 extern (C++) void pop(VarDeclaration v)
356 assert(!v.isDataseg() || v.isCTFE());
357 assert(!v.isReference());
358 const oldid = v.ctfeAdrOnStack;
359 v.ctfeAdrOnStack = cast(uint)cast(size_t)savedId[oldid];
360 if (v.ctfeAdrOnStack == values.dim - 1)
368 extern (C++) void popAll(size_t stackpointer)
370 if (stackPointer() > maxStackPointer)
371 maxStackPointer = stackPointer();
372 assert(values.dim >= stackpointer);
373 for (size_t i = stackpointer; i < values.dim; ++i)
375 VarDeclaration v = vars[i];
376 v.ctfeAdrOnStack = cast(uint)cast(size_t)savedId[i];
378 values.setDim(stackpointer);
379 vars.setDim(stackpointer);
380 savedId.setDim(stackpointer);
383 extern (C++) void saveGlobalConstant(VarDeclaration v, Expression e)
385 assert(v._init && (v.isConst() || v.isImmutable() || v.storage_class & STC.manifest) && !v.isCTFE());
386 v.ctfeAdrOnStack = cast(uint)globalValues.dim;
387 globalValues.push(copyRegionExp(e));
391 private struct InterState
393 InterState* caller; // calling function's InterState
394 FuncDeclaration fd; // function being interpreted
395 Statement start; // if !=NULL, start execution at this statement
397 /* target of CTFEExp result; also
398 * target of labelled CTFEExp or
399 * CTFEExp. (null if no label).
401 Statement gotoTarget;
404 /*************************************
405 * Attempt to interpret a function given the arguments.
407 * pue = storage for result
408 * fd = function being called
409 * istate = state for calling function (NULL if none)
410 * arguments = function arguments
411 * thisarg = 'this', if a needThis() function, NULL if not.
414 * result expression if successful, EXP.cantExpression if not,
415 * or CTFEExp if function returned void.
417 private Expression interpretFunction(UnionExp* pue, FuncDeclaration fd, InterState* istate, Expressions* arguments, Expression thisarg)
421 printf("\n********\n%s FuncDeclaration::interpret(istate = %p) %s\n", fd.loc.toChars(), istate, fd.toChars());
424 if (fd.semanticRun == PASS.semantic3)
426 fd.error("circular dependency. Functions cannot be interpreted while being compiled");
427 return CTFEExp.cantexp;
429 if (!fd.functionSemantic3())
430 return CTFEExp.cantexp;
431 if (fd.semanticRun < PASS.semantic3done)
433 fd.error("circular dependency. Functions cannot be interpreted while being compiled");
434 return CTFEExp.cantexp;
437 auto tf = fd.type.toBasetype().isTypeFunction();
438 if (tf.parameterList.varargs != VarArg.none && arguments &&
439 ((fd.parameters && arguments.dim != fd.parameters.dim) || (!fd.parameters && arguments.dim)))
441 fd.error("C-style variadic functions are not yet implemented in CTFE");
442 return CTFEExp.cantexp;
445 // Nested functions always inherit the 'this' pointer from the parent,
446 // except for delegates. (Note that the 'this' pointer may be null).
447 // Func literals report isNested() even if they are in global scope,
448 // so we need to check that the parent is a function.
449 if (fd.isNested() && fd.toParentLocal().isFuncDeclaration() && !thisarg && istate)
450 thisarg = ctfeGlobals.stack.getThis();
452 if (fd.needThis() && !thisarg)
454 // error, no this. Prevent segfault.
455 // Here should be unreachable by the strict 'this' check in front-end.
456 fd.error("need `this` to access member `%s`", fd.toChars());
457 return CTFEExp.cantexp;
460 // Place to hold all the arguments to the function while
461 // we are evaluating them.
462 size_t dim = arguments ? arguments.dim : 0;
463 assert((fd.parameters ? fd.parameters.dim : 0) == dim);
465 /* Evaluate all the arguments to the function,
466 * store the results in eargs[]
468 Expressions eargs = Expressions(dim);
469 for (size_t i = 0; i < dim; i++)
471 Expression earg = (*arguments)[i];
472 Parameter fparam = tf.parameterList[i];
474 if (fparam.isReference())
476 if (!istate && (fparam.storageClass & STC.out_))
478 // initializing an out parameter involves writing to it.
479 earg.error("global `%s` cannot be passed as an `out` parameter at compile time", earg.toChars());
480 return CTFEExp.cantexp;
482 // Convert all reference arguments into lvalue references
483 earg = interpretRegion(earg, istate, CTFEGoal.LValue);
484 if (CTFEExp.isCantExp(earg))
487 else if (fparam.storageClass & STC.lazy_)
494 Type ta = fparam.type.toBasetype();
495 if (ta.ty == Tsarray)
496 if (auto eaddr = earg.isAddrExp())
498 /* Static arrays are passed by a simple pointer.
499 * Skip past this to get at the actual arg.
504 earg = interpretRegion(earg, istate);
505 if (CTFEExp.isCantExp(earg))
508 /* Struct literals are passed by value, but we don't need to
509 * copy them if they are passed as const
511 if (earg.op == EXP.structLiteral && !(fparam.storageClass & (STC.const_ | STC.immutable_)))
512 earg = copyLiteral(earg).copy();
514 if (auto tee = earg.isThrownExceptionExp())
518 tee.generateUncaughtError();
519 return CTFEExp.cantexp;
524 // Now that we've evaluated all the arguments, we can start the frame
525 // (this is the moment when the 'call' actually takes place).
527 istatex.caller = istate;
532 Expression arg0 = thisarg;
533 if (arg0 && arg0.type.ty == Tstruct)
535 Type t = arg0.type.pointerTo();
536 arg0 = ctfeEmplaceExp!AddrExp(arg0.loc, arg0);
539 auto elements = new Expressions(2);
540 (*elements)[0] = arg0;
541 (*elements)[1] = ctfeGlobals.stack.getThis();
542 Type t2 = Type.tvoidptr.sarrayOf(2);
543 const loc = thisarg ? thisarg.loc : fd.loc;
544 thisarg = ctfeEmplaceExp!ArrayLiteralExp(loc, t2, elements);
545 thisarg = ctfeEmplaceExp!AddrExp(loc, thisarg);
546 thisarg.type = t2.pointerTo();
549 ctfeGlobals.stack.startFrame(thisarg);
550 if (fd.vthis && thisarg)
552 ctfeGlobals.stack.push(fd.vthis);
553 setValue(fd.vthis, thisarg);
556 for (size_t i = 0; i < dim; i++)
558 Expression earg = eargs[i];
559 Parameter fparam = tf.parameterList[i];
560 VarDeclaration v = (*fd.parameters)[i];
563 printf("arg[%zu] = %s\n", i, earg.toChars());
565 ctfeGlobals.stack.push(v);
567 if (fparam.isReference() && earg.op == EXP.variable &&
568 earg.isVarExp().var.toParent2() == fd)
570 VarDeclaration vx = earg.isVarExp().var.isVarDeclaration();
573 fd.error("cannot interpret `%s` as a `ref` parameter", earg.toChars());
574 return CTFEExp.cantexp;
577 /* vx is a variable that is declared in fd.
578 * It means that fd is recursively called. e.g.
580 * void fd(int n, ref int v = dummy) {
582 * if (n == 1) fd(2, vx);
586 * The old value of vx on the stack in fd(1)
587 * should be saved at the start of fd(2, vx) call.
589 const oldadr = vx.ctfeAdrOnStack;
591 ctfeGlobals.stack.push(vx);
592 assert(!hasValue(vx)); // vx is made uninitialized
594 // https://issues.dlang.org/show_bug.cgi?id=14299
595 // v.ctfeAdrOnStack should be saved already
596 // in the stack before the overwrite.
597 v.ctfeAdrOnStack = oldadr;
598 assert(hasValue(v)); // ref parameter v should refer existing value.
602 // Value parameters and non-trivial references
603 setValueWithoutChecking(v, earg);
607 printf("interpreted arg[%zu] = %s\n", i, earg.toChars());
612 printf("interpreted arg[%zu] = %s\n", i, earg.toChars());
618 ctfeGlobals.stack.push(fd.vresult);
620 // Enter the function
621 ++ctfeGlobals.callDepth;
622 if (ctfeGlobals.callDepth > ctfeGlobals.maxCallDepth)
623 ctfeGlobals.maxCallDepth = ctfeGlobals.callDepth;
628 if (ctfeGlobals.callDepth > CTFE_RECURSION_LIMIT)
630 // This is a compiler error. It must not be suppressed.
632 fd.error("CTFE recursion limit exceeded");
636 e = interpret(pue, fd.fbody, &istatex);
637 if (CTFEExp.isCantExp(e))
641 printf("function body failed to interpret\n");
647 fd.error("CTFE internal error: failed to resume at statement `%s`", istatex.start.toChars());
648 return CTFEExp.cantexp;
651 /* This is how we deal with a recursive statement AST
652 * that has arbitrary goto statements in it.
653 * Bubble up a 'result' which is the target of the goto
654 * statement, then go recursively down the AST looking
655 * for that statement, then execute starting there.
657 if (CTFEExp.isGotoExp(e))
659 istatex.start = istatex.gotoTarget; // set starting statement
660 istatex.gotoTarget = null;
664 assert(!e || (e.op != EXP.continue_ && e.op != EXP.break_));
668 // If fell off the end of a void function, return void
669 if (!e && tf.next.ty == Tvoid)
671 if (tf.isref && e.op == EXP.variable && e.isVarExp().var == fd.vthis)
673 if (tf.isref && fd.isThis2 && e.op == EXP.index)
675 auto ie = e.isIndexExp();
676 auto pe = ie.e1.isPtrExp();
677 auto ve = !pe ? null : pe.e1.isVarExp();
678 if (ve && ve.var == fd.vthis)
680 auto ne = ie.e2.isIntegerExp();
682 auto ale = thisarg.isAddrExp().e1.isArrayLiteralExp();
683 e = (*ale.elements)[cast(size_t)ne.getInteger()];
684 if (auto ae = e.isAddrExp())
692 // Leave the function
693 --ctfeGlobals.callDepth;
695 ctfeGlobals.stack.endFrame();
697 // If it generated an uncaught exception, report error.
698 if (!istate && e.isThrownExceptionExp())
702 e.isThrownExceptionExp().generateUncaughtError();
709 /// used to collect coverage information in ctfe
710 void incUsageCtfe(InterState* istate, const ref Loc loc)
712 if (global.params.ctfe_cov && istate)
714 auto line = loc.linnum;
715 auto mod = istate.fd.getModule();
717 ++mod.ctfe_cov[line];
721 private extern (C++) final class Interpreter : Visitor
723 alias visit = Visitor.visit;
728 UnionExp* pue; // storage for `result`
730 extern (D) this(UnionExp* pue, InterState* istate, CTFEGoal goal)
733 this.istate = istate;
737 // If e is EXP.throw_exception or EXP.cantExpression,
738 // set it to 'result' and returns true.
739 bool exceptionOrCant(Expression e)
741 if (exceptionOrCantInterpret(e))
743 // Make sure e is not pointing to a stack temporary
744 result = (e.op == EXP.cantExpression) ? CTFEExp.cantexp : e;
750 static Expressions* copyArrayOnWrite(Expressions* exps, Expressions* original)
752 if (exps is original)
755 exps = new Expressions();
757 exps = original.copy();
758 ++ctfeGlobals.numArrayAllocs;
763 /******************************** Statement ***************************/
765 override void visit(Statement s)
769 printf("%s Statement::interpret()\n", s.loc.toChars());
773 if (istate.start != s)
778 s.error("statement `%s` cannot be interpreted at compile time", s.toChars());
779 result = CTFEExp.cantexp;
782 override void visit(ExpStatement s)
786 printf("%s ExpStatement::interpret(%s)\n", s.loc.toChars(), s.exp ? s.exp.toChars() : "");
790 if (istate.start != s)
794 if (s.exp && s.exp.hasCode)
795 incUsageCtfe(istate, s.loc);
797 Expression e = interpret(pue, s.exp, istate, CTFEGoal.Nothing);
798 if (exceptionOrCant(e))
802 override void visit(CompoundStatement s)
806 printf("%s CompoundStatement::interpret()\n", s.loc.toChars());
808 if (istate.start == s)
811 const dim = s.statements ? s.statements.dim : 0;
812 foreach (i; 0 .. dim)
814 Statement sx = (*s.statements)[i];
815 result = interpret(pue, sx, istate);
821 printf("%s -CompoundStatement::interpret() %p\n", s.loc.toChars(), result);
825 override void visit(UnrolledLoopStatement s)
829 printf("%s UnrolledLoopStatement::interpret()\n", s.loc.toChars());
831 if (istate.start == s)
834 const dim = s.statements ? s.statements.dim : 0;
835 foreach (i; 0 .. dim)
837 Statement sx = (*s.statements)[i];
838 Expression e = interpret(pue, sx, istate);
839 if (!e) // succeeds to interpret, or goto target was not found
841 if (exceptionOrCant(e))
843 if (e.op == EXP.break_)
845 if (istate.gotoTarget && istate.gotoTarget != s)
847 result = e; // break at a higher level
850 istate.gotoTarget = null;
854 if (e.op == EXP.continue_)
856 if (istate.gotoTarget && istate.gotoTarget != s)
858 result = e; // continue at a higher level
861 istate.gotoTarget = null;
865 // expression from return statement, or thrown exception
871 override void visit(IfStatement s)
875 printf("%s IfStatement::interpret(%s)\n", s.loc.toChars(), s.condition.toChars());
877 incUsageCtfe(istate, s.loc);
878 if (istate.start == s)
883 e = interpret(s.ifbody, istate);
884 if (!e && istate.start)
885 e = interpret(s.elsebody, istate);
891 Expression e = interpret(&ue, s.condition, istate);
893 if (exceptionOrCant(e))
897 result = interpret(pue, s.ifbody, istate);
898 else if (e.toBool().hasValue(false))
899 result = interpret(pue, s.elsebody, istate);
902 // no error, or assert(0)?
903 result = CTFEExp.cantexp;
907 override void visit(ScopeStatement s)
911 printf("%s ScopeStatement::interpret()\n", s.loc.toChars());
913 if (istate.start == s)
916 result = interpret(pue, s.statement, istate);
920 Given an expression e which is about to be returned from the current
921 function, generate an error if it contains pointers to local variables.
923 Only checks expressions passed by value (pointers to local variables
924 may already be stored in members of classes, arrays, or AAs which
925 were passed as mutable function parameters).
927 true if it is safe to return, false if an error was generated.
929 static bool stopPointersEscaping(const ref Loc loc, Expression e)
931 if (!e.type.hasPointers())
933 if (isPointer(e.type))
936 if (auto eaddr = e.isAddrExp())
939 while (x.op == EXP.variable && (v = (cast(VarExp)x).var.isVarDeclaration()) !is null)
941 if (v.storage_class & STC.ref_)
944 if (auto eaddr = e.isAddrExp())
948 if (ctfeGlobals.stack.isInCurrentFrame(v))
950 error(loc, "returning a pointer to a local stack variable");
956 // TODO: If it is a EXP.dotVariable or EXP.index, we should check that it is not
957 // pointing to a local struct or static array.
959 if (auto se = e.isStructLiteralExp())
961 return stopPointersEscapingFromArray(loc, se.elements);
963 if (auto ale = e.isArrayLiteralExp())
965 return stopPointersEscapingFromArray(loc, ale.elements);
967 if (auto aae = e.isAssocArrayLiteralExp())
969 if (!stopPointersEscapingFromArray(loc, aae.keys))
971 return stopPointersEscapingFromArray(loc, aae.values);
976 // Check all elements of an array for escaping local variables. Return false if error
977 static bool stopPointersEscapingFromArray(const ref Loc loc, Expressions* elems)
981 if (e && !stopPointersEscaping(loc, e))
987 override void visit(ReturnStatement s)
991 printf("%s ReturnStatement::interpret(%s)\n", s.loc.toChars(), s.exp ? s.exp.toChars() : "");
995 if (istate.start != s)
1002 result = CTFEExp.voidexp;
1006 incUsageCtfe(istate, s.loc);
1007 assert(istate && istate.fd && istate.fd.type && istate.fd.type.ty == Tfunction);
1008 TypeFunction tf = cast(TypeFunction)istate.fd.type;
1010 /* If the function returns a ref AND it's been called from an assignment,
1011 * we need to return an lvalue. Otherwise, just do an (rvalue) interpret.
1015 result = interpret(pue, s.exp, istate, CTFEGoal.LValue);
1018 if (tf.next && tf.next.ty == Tdelegate && istate.fd.closureVars.dim > 0)
1020 // To support this, we need to copy all the closure vars
1021 // into the delegate literal.
1022 s.error("closures are not yet supported in CTFE");
1023 result = CTFEExp.cantexp;
1027 // We need to treat pointers specially, because EXP.symbolOffset can be used to
1028 // return a value OR a pointer
1029 Expression e = interpret(pue, s.exp, istate);
1030 if (exceptionOrCant(e))
1033 // Disallow returning pointers to stack-allocated variables (bug 7876)
1034 if (!stopPointersEscaping(s.loc, e))
1036 result = CTFEExp.cantexp;
1040 if (needToCopyLiteral(e))
1041 e = copyLiteral(e).copy();
1044 printf("RETURN %s\n", s.loc.toChars());
1050 static Statement findGotoTarget(InterState* istate, Identifier ident)
1052 Statement target = null;
1055 LabelDsymbol label = istate.fd.searchLabel(ident);
1056 assert(label && label.statement);
1057 LabelStatement ls = label.statement;
1058 target = ls.gotoTarget ? ls.gotoTarget : ls.statement;
1063 override void visit(BreakStatement s)
1067 printf("%s BreakStatement::interpret()\n", s.loc.toChars());
1069 incUsageCtfe(istate, s.loc);
1072 if (istate.start != s)
1074 istate.start = null;
1077 istate.gotoTarget = findGotoTarget(istate, s.ident);
1078 result = CTFEExp.breakexp;
1081 override void visit(ContinueStatement s)
1085 printf("%s ContinueStatement::interpret()\n", s.loc.toChars());
1087 incUsageCtfe(istate, s.loc);
1090 if (istate.start != s)
1092 istate.start = null;
1095 istate.gotoTarget = findGotoTarget(istate, s.ident);
1096 result = CTFEExp.continueexp;
1099 override void visit(WhileStatement s)
1103 printf("WhileStatement::interpret()\n");
1105 assert(0); // rewritten to ForStatement
1108 override void visit(DoStatement s)
1112 printf("%s DoStatement::interpret()\n", s.loc.toChars());
1114 if (istate.start == s)
1115 istate.start = null;
1119 Expression e = interpret(s._body, istate);
1120 if (!e && istate.start) // goto target was not found
1122 assert(!istate.start);
1124 if (exceptionOrCant(e))
1126 if (e && e.op == EXP.break_)
1128 if (istate.gotoTarget && istate.gotoTarget != s)
1130 result = e; // break at a higher level
1133 istate.gotoTarget = null;
1136 if (e && e.op == EXP.continue_)
1138 if (istate.gotoTarget && istate.gotoTarget != s)
1140 result = e; // continue at a higher level
1143 istate.gotoTarget = null;
1148 result = e; // bubbled up from ReturnStatement
1153 incUsageCtfe(istate, s.condition.loc);
1154 e = interpret(&ue, s.condition, istate);
1155 if (exceptionOrCant(e))
1159 result = CTFEExp.cantexp;
1162 if (e.toBool().hasValue(false))
1164 assert(isTrueBool(e));
1166 assert(result is null);
1169 override void visit(ForStatement s)
1173 printf("%s ForStatement::interpret()\n", s.loc.toChars());
1175 if (istate.start == s)
1176 istate.start = null;
1178 UnionExp ueinit = void;
1179 Expression ei = interpret(&ueinit, s._init, istate);
1180 if (exceptionOrCant(ei))
1182 assert(!ei); // s.init never returns from function, or jumps out from it
1186 if (s.condition && !istate.start)
1189 incUsageCtfe(istate, s.condition.loc);
1190 Expression e = interpret(&ue, s.condition, istate);
1191 if (exceptionOrCant(e))
1193 if (e.toBool().hasValue(false))
1195 assert(isTrueBool(e));
1198 Expression e = interpret(pue, s._body, istate);
1199 if (!e && istate.start) // goto target was not found
1201 assert(!istate.start);
1203 if (exceptionOrCant(e))
1205 if (e && e.op == EXP.break_)
1207 if (istate.gotoTarget && istate.gotoTarget != s)
1209 result = e; // break at a higher level
1212 istate.gotoTarget = null;
1215 if (e && e.op == EXP.continue_)
1217 if (istate.gotoTarget && istate.gotoTarget != s)
1219 result = e; // continue at a higher level
1222 istate.gotoTarget = null;
1227 result = e; // bubbled up from ReturnStatement
1231 UnionExp uei = void;
1233 incUsageCtfe(istate, s.increment.loc);
1234 e = interpret(&uei, s.increment, istate, CTFEGoal.Nothing);
1235 if (exceptionOrCant(e))
1238 assert(result is null);
1241 override void visit(ForeachStatement s)
1243 assert(0); // rewritten to ForStatement
1246 override void visit(ForeachRangeStatement s)
1248 assert(0); // rewritten to ForStatement
1251 override void visit(SwitchStatement s)
1255 printf("%s SwitchStatement::interpret()\n", s.loc.toChars());
1257 incUsageCtfe(istate, s.loc);
1258 if (istate.start == s)
1259 istate.start = null;
1262 Expression e = interpret(s._body, istate);
1263 if (istate.start) // goto target was not found
1265 if (exceptionOrCant(e))
1267 if (e && e.op == EXP.break_)
1269 if (istate.gotoTarget && istate.gotoTarget != s)
1271 result = e; // break at a higher level
1274 istate.gotoTarget = null;
1281 UnionExp uecond = void;
1282 Expression econdition = interpret(&uecond, s.condition, istate);
1283 if (exceptionOrCant(econdition))
1286 Statement scase = null;
1288 foreach (cs; *s.cases)
1290 UnionExp uecase = void;
1291 Expression ecase = interpret(&uecase, cs.exp, istate);
1292 if (exceptionOrCant(ecase))
1294 if (ctfeEqual(cs.exp.loc, EXP.equal, econdition, ecase))
1303 s.error("no `default` or `case` for `%s` in `switch` statement", econdition.toChars());
1311 istate.start = scase;
1312 Expression e = interpret(pue, s._body, istate);
1313 assert(!istate.start); // jump must not fail
1314 if (e && e.op == EXP.break_)
1316 if (istate.gotoTarget && istate.gotoTarget != s)
1318 result = e; // break at a higher level
1321 istate.gotoTarget = null;
1327 override void visit(CaseStatement s)
1331 printf("%s CaseStatement::interpret(%s) this = %p\n", s.loc.toChars(), s.exp.toChars(), s);
1333 incUsageCtfe(istate, s.loc);
1334 if (istate.start == s)
1335 istate.start = null;
1337 result = interpret(pue, s.statement, istate);
1340 override void visit(DefaultStatement s)
1344 printf("%s DefaultStatement::interpret()\n", s.loc.toChars());
1346 incUsageCtfe(istate, s.loc);
1347 if (istate.start == s)
1348 istate.start = null;
1350 result = interpret(pue, s.statement, istate);
1353 override void visit(GotoStatement s)
1357 printf("%s GotoStatement::interpret()\n", s.loc.toChars());
1361 if (istate.start != s)
1363 istate.start = null;
1365 incUsageCtfe(istate, s.loc);
1367 assert(s.label && s.label.statement);
1368 istate.gotoTarget = s.label.statement;
1369 result = CTFEExp.gotoexp;
1372 override void visit(GotoCaseStatement s)
1376 printf("%s GotoCaseStatement::interpret()\n", s.loc.toChars());
1380 if (istate.start != s)
1382 istate.start = null;
1384 incUsageCtfe(istate, s.loc);
1387 istate.gotoTarget = s.cs;
1388 result = CTFEExp.gotoexp;
1391 override void visit(GotoDefaultStatement s)
1395 printf("%s GotoDefaultStatement::interpret()\n", s.loc.toChars());
1399 if (istate.start != s)
1401 istate.start = null;
1403 incUsageCtfe(istate, s.loc);
1405 assert(s.sw && s.sw.sdefault);
1406 istate.gotoTarget = s.sw.sdefault;
1407 result = CTFEExp.gotoexp;
1410 override void visit(LabelStatement s)
1414 printf("%s LabelStatement::interpret()\n", s.loc.toChars());
1416 if (istate.start == s)
1417 istate.start = null;
1419 result = interpret(pue, s.statement, istate);
1422 override void visit(TryCatchStatement s)
1426 printf("%s TryCatchStatement::interpret()\n", s.loc.toChars());
1428 if (istate.start == s)
1429 istate.start = null;
1432 Expression e = null;
1433 e = interpret(pue, s._body, istate);
1434 foreach (ca; *s.catches)
1436 if (e || !istate.start) // goto target was found
1438 e = interpret(pue, ca.handler, istate);
1444 Expression e = interpret(s._body, istate);
1446 // An exception was thrown
1447 if (e && e.isThrownExceptionExp())
1449 ThrownExceptionExp ex = e.isThrownExceptionExp();
1450 Type extype = ex.thrown.originalClass().type;
1452 // Search for an appropriate catch clause.
1453 foreach (ca; *s.catches)
1455 Type catype = ca.type;
1456 if (!catype.equals(extype) && !catype.isBaseOf(extype, null))
1459 // Execute the handler
1462 ctfeGlobals.stack.push(ca.var);
1463 setValue(ca.var, ex.thrown);
1465 e = interpret(ca.handler, istate);
1466 if (CTFEExp.isGotoExp(e))
1468 /* This is an optimization that relies on the locality of the jump target.
1469 * If the label is in the same catch handler, the following scan
1470 * would find it quickly and can reduce jump cost.
1471 * Otherwise, the catch block may be unnnecessary scanned again
1472 * so it would make CTFE speed slower.
1474 InterState istatex = *istate;
1475 istatex.start = istate.gotoTarget; // set starting statement
1476 istatex.gotoTarget = null;
1477 Expression eh = interpret(ca.handler, &istatex);
1480 istate.gotoTarget = null;
1490 static bool isAnErrorException(ClassDeclaration cd)
1492 return cd == ClassDeclaration.errorException || ClassDeclaration.errorException.isBaseOf(cd, null);
1495 static ThrownExceptionExp chainExceptions(ThrownExceptionExp oldest, ThrownExceptionExp newest)
1499 printf("Collided exceptions %s %s\n", oldest.thrown.toChars(), newest.thrown.toChars());
1501 // Little sanity check to make sure it's really a Throwable
1502 ClassReferenceExp boss = oldest.thrown;
1503 const next = 4; // index of Throwable.next
1504 assert((*boss.value.elements)[next].type.ty == Tclass); // Throwable.next
1505 ClassReferenceExp collateral = newest.thrown;
1506 if (isAnErrorException(collateral.originalClass()) && !isAnErrorException(boss.originalClass()))
1508 /* Find the index of the Error.bypassException field
1510 auto bypass = next + 1;
1511 if ((*collateral.value.elements)[bypass].type.ty == Tuns32)
1512 bypass += 1; // skip over _refcount field
1513 assert((*collateral.value.elements)[bypass].type.ty == Tclass);
1515 // The new exception bypass the existing chain
1516 (*collateral.value.elements)[bypass] = boss;
1519 while ((*boss.value.elements)[next].op == EXP.classReference)
1521 boss = cast(ClassReferenceExp)(*boss.value.elements)[next];
1523 (*boss.value.elements)[next] = collateral;
1527 override void visit(TryFinallyStatement s)
1531 printf("%s TryFinallyStatement::interpret()\n", s.loc.toChars());
1533 if (istate.start == s)
1534 istate.start = null;
1537 Expression e = null;
1538 e = interpret(pue, s._body, istate);
1539 // Jump into/out from finalbody is disabled in semantic analysis.
1540 // and jump inside will be handled by the ScopeStatement == finalbody.
1545 Expression ex = interpret(s._body, istate);
1546 if (CTFEExp.isCantExp(ex))
1551 while (CTFEExp.isGotoExp(ex))
1553 // If the goto target is within the body, we must not interpret the finally statement,
1554 // because that will call destructors for objects within the scope, which we should not do.
1555 InterState istatex = *istate;
1556 istatex.start = istate.gotoTarget; // set starting statement
1557 istatex.gotoTarget = null;
1558 Expression bex = interpret(s._body, &istatex);
1561 // The goto target is outside the current scope.
1564 // The goto target was within the body.
1565 if (CTFEExp.isCantExp(bex))
1574 Expression ey = interpret(s.finalbody, istate);
1575 if (CTFEExp.isCantExp(ey))
1580 if (ey && ey.isThrownExceptionExp())
1582 // Check for collided exceptions
1583 if (ex && ex.isThrownExceptionExp())
1584 ex = chainExceptions(ex.isThrownExceptionExp(), ey.isThrownExceptionExp());
1591 override void visit(ThrowStatement s)
1595 printf("%s ThrowStatement::interpret()\n", s.loc.toChars());
1599 if (istate.start != s)
1601 istate.start = null;
1604 incUsageCtfe(istate, s.loc);
1606 Expression e = interpretRegion(s.exp, istate);
1607 if (exceptionOrCant(e))
1610 assert(e.op == EXP.classReference);
1611 result = ctfeEmplaceExp!ThrownExceptionExp(s.loc, e.isClassReferenceExp());
1614 override void visit(ScopeGuardStatement s)
1619 override void visit(WithStatement s)
1623 printf("%s WithStatement::interpret()\n", s.loc.toChars());
1625 if (istate.start == s)
1626 istate.start = null;
1629 result = s._body ? interpret(s._body, istate) : null;
1633 // If it is with(Enum) {...}, just execute the body.
1634 if (s.exp.op == EXP.scope_ || s.exp.op == EXP.type)
1636 result = interpret(pue, s._body, istate);
1640 incUsageCtfe(istate, s.loc);
1642 Expression e = interpret(s.exp, istate);
1643 if (exceptionOrCant(e))
1646 if (s.wthis.type.ty == Tpointer && s.exp.type.ty != Tpointer)
1648 e = ctfeEmplaceExp!AddrExp(s.loc, e, s.wthis.type);
1650 ctfeGlobals.stack.push(s.wthis);
1651 setValue(s.wthis, e);
1652 e = interpret(s._body, istate);
1653 if (CTFEExp.isGotoExp(e))
1655 /* This is an optimization that relies on the locality of the jump target.
1656 * If the label is in the same WithStatement, the following scan
1657 * would find it quickly and can reduce jump cost.
1658 * Otherwise, the statement body may be unnnecessary scanned again
1659 * so it would make CTFE speed slower.
1661 InterState istatex = *istate;
1662 istatex.start = istate.gotoTarget; // set starting statement
1663 istatex.gotoTarget = null;
1664 Expression ex = interpret(s._body, &istatex);
1667 istate.gotoTarget = null;
1671 ctfeGlobals.stack.pop(s.wthis);
1675 override void visit(AsmStatement s)
1679 printf("%s AsmStatement::interpret()\n", s.loc.toChars());
1683 if (istate.start != s)
1685 istate.start = null;
1687 s.error("`asm` statements cannot be interpreted at compile time");
1688 result = CTFEExp.cantexp;
1691 override void visit(ImportStatement s)
1695 printf("ImportStatement::interpret()\n");
1699 if (istate.start != s)
1701 istate.start = null;
1705 /******************************** Expression ***************************/
1707 override void visit(Expression e)
1711 printf("%s Expression::interpret() '%s' %s\n", e.loc.toChars(), EXPtoString(e.op).ptr, e.toChars());
1712 printf("type = %s\n", e.type.toChars());
1715 e.error("cannot interpret `%s` at compile time", e.toChars());
1716 result = CTFEExp.cantexp;
1719 override void visit(TypeExp e)
1723 printf("%s TypeExp.interpret() %s\n", e.loc.toChars(), e.toChars());
1728 override void visit(ThisExp e)
1732 printf("%s ThisExp::interpret() %s\n", e.loc.toChars(), e.toChars());
1734 if (goal == CTFEGoal.LValue)
1736 // We might end up here with istate being zero
1737 // https://issues.dlang.org/show_bug.cgi?id=16382
1738 if (istate && istate.fd.vthis)
1740 result = ctfeEmplaceExp!VarExp(e.loc, istate.fd.vthis);
1741 if (istate.fd.isThis2)
1743 result = ctfeEmplaceExp!PtrExp(e.loc, result);
1744 result.type = Type.tvoidptr.sarrayOf(2);
1745 result = ctfeEmplaceExp!IndexExp(e.loc, result, IntegerExp.literal!0);
1747 result.type = e.type;
1754 result = ctfeGlobals.stack.getThis();
1757 if (istate && istate.fd.isThis2)
1759 assert(result.op == EXP.address);
1760 result = (cast(AddrExp)result).e1;
1761 assert(result.op == EXP.arrayLiteral);
1762 result = (*(cast(ArrayLiteralExp)result).elements)[0];
1763 if (e.type.ty == Tstruct)
1765 result = (cast(AddrExp)result).e1;
1769 assert(result.op == EXP.structLiteral || result.op == EXP.classReference || result.op == EXP.type);
1772 e.error("value of `this` is not known at compile time");
1773 result = CTFEExp.cantexp;
1776 override void visit(NullExp e)
1781 override void visit(IntegerExp e)
1785 printf("%s IntegerExp::interpret() %s\n", e.loc.toChars(), e.toChars());
1790 override void visit(RealExp e)
1794 printf("%s RealExp::interpret() %s\n", e.loc.toChars(), e.toChars());
1799 override void visit(ComplexExp e)
1804 override void visit(StringExp e)
1808 printf("%s StringExp::interpret() %s\n", e.loc.toChars(), e.toChars());
1810 /* Attempts to modify string literals are prevented
1811 * in BinExp::interpretAssignCommon.
1816 override void visit(FuncExp e)
1820 printf("%s FuncExp::interpret() %s\n", e.loc.toChars(), e.toChars());
1825 override void visit(SymOffExp e)
1829 printf("%s SymOffExp::interpret() %s\n", e.loc.toChars(), e.toChars());
1831 if (e.var.isFuncDeclaration() && e.offset == 0)
1836 if (isTypeInfo_Class(e.type) && e.offset == 0)
1841 if (e.type.ty != Tpointer)
1843 // Probably impossible
1844 e.error("cannot interpret `%s` at compile time", e.toChars());
1845 result = CTFEExp.cantexp;
1848 Type pointee = (cast(TypePointer)e.type).next;
1849 if (e.var.isThreadlocal())
1851 e.error("cannot take address of thread-local variable %s at compile time", e.var.toChars());
1852 result = CTFEExp.cantexp;
1855 // Check for taking an address of a shared variable.
1856 // If the shared variable is an array, the offset might not be zero.
1857 Type fromType = null;
1858 if (e.var.type.ty == Tarray || e.var.type.ty == Tsarray)
1860 fromType = (cast(TypeArray)e.var.type).next;
1862 if (e.var.isDataseg() && ((e.offset == 0 && isSafePointerCast(e.var.type, pointee)) || (fromType && isSafePointerCast(fromType, pointee))))
1868 Expression val = getVarExp(e.loc, istate, e.var, goal);
1869 if (exceptionOrCant(val))
1871 if (val.type.ty == Tarray || val.type.ty == Tsarray)
1873 // Check for unsupported type painting operations
1874 Type elemtype = (cast(TypeArray)val.type).next;
1875 d_uns64 elemsize = elemtype.size();
1877 // It's OK to cast from fixed length to fixed length array, eg &int[n] to int[d]*.
1878 if (val.type.ty == Tsarray && pointee.ty == Tsarray && elemsize == pointee.nextOf().size())
1880 size_t d = cast(size_t)(cast(TypeSArray)pointee).dim.toInteger();
1881 Expression elwr = ctfeEmplaceExp!IntegerExp(e.loc, e.offset / elemsize, Type.tsize_t);
1882 Expression eupr = ctfeEmplaceExp!IntegerExp(e.loc, e.offset / elemsize + d, Type.tsize_t);
1884 // Create a CTFE pointer &val[ofs..ofs+d]
1885 auto se = ctfeEmplaceExp!SliceExp(e.loc, val, elwr, eupr);
1887 emplaceExp!(AddrExp)(pue, e.loc, se, e.type);
1892 if (!isSafePointerCast(elemtype, pointee))
1894 // It's also OK to cast from &string to string*.
1895 if (e.offset == 0 && isSafePointerCast(e.var.type, pointee))
1897 // Create a CTFE pointer &var
1898 auto ve = ctfeEmplaceExp!VarExp(e.loc, e.var);
1900 emplaceExp!(AddrExp)(pue, e.loc, ve, e.type);
1904 e.error("reinterpreting cast from `%s` to `%s` is not supported in CTFE", val.type.toChars(), e.type.toChars());
1905 result = CTFEExp.cantexp;
1909 const dinteger_t sz = pointee.size();
1910 dinteger_t indx = e.offset / sz;
1911 assert(sz * indx == e.offset);
1912 Expression aggregate = null;
1913 if (val.op == EXP.arrayLiteral || val.op == EXP.string_)
1917 else if (auto se = val.isSliceExp())
1920 UnionExp uelwr = void;
1921 Expression lwr = interpret(&uelwr, se.lwr, istate);
1922 indx += lwr.toInteger();
1926 // Create a CTFE pointer &aggregate[ofs]
1927 auto ofs = ctfeEmplaceExp!IntegerExp(e.loc, indx, Type.tsize_t);
1928 auto ei = ctfeEmplaceExp!IndexExp(e.loc, aggregate, ofs);
1930 emplaceExp!(AddrExp)(pue, e.loc, ei, e.type);
1935 else if (e.offset == 0 && isSafePointerCast(e.var.type, pointee))
1937 // Create a CTFE pointer &var
1938 auto ve = ctfeEmplaceExp!VarExp(e.loc, e.var);
1939 ve.type = e.var.type;
1940 emplaceExp!(AddrExp)(pue, e.loc, ve, e.type);
1945 e.error("cannot convert `&%s` to `%s` at compile time", e.var.type.toChars(), e.type.toChars());
1946 result = CTFEExp.cantexp;
1949 override void visit(AddrExp e)
1953 printf("%s AddrExp::interpret() %s\n", e.loc.toChars(), e.toChars());
1955 if (auto ve = e.e1.isVarExp())
1957 Declaration decl = ve.var;
1959 // We cannot take the address of an imported symbol at compile time
1960 if (decl.isImportedSymbol()) {
1961 e.error("cannot take address of imported symbol `%s` at compile time", decl.toChars());
1962 result = CTFEExp.cantexp;
1966 if (decl.isDataseg()) {
1967 // Normally this is already done by optimize()
1968 // Do it here in case optimize(WANTvalue) wasn't run before CTFE
1969 emplaceExp!(SymOffExp)(pue, e.loc, (cast(VarExp)e.e1).var, 0);
1971 result.type = e.type;
1975 auto er = interpret(e.e1, istate, CTFEGoal.LValue);
1976 if (auto ve = er.isVarExp())
1977 if (ve.var == istate.fd.vthis)
1978 er = interpret(er, istate);
1980 if (exceptionOrCant(er))
1983 // Return a simplified address expression
1984 emplaceExp!(AddrExp)(pue, e.loc, er, e.type);
1988 override void visit(DelegateExp e)
1992 printf("%s DelegateExp::interpret() %s\n", e.loc.toChars(), e.toChars());
1994 // TODO: Really we should create a CTFE-only delegate expression
1995 // of a pointer and a funcptr.
1997 // If it is &nestedfunc, just return it
1998 // TODO: We should save the context pointer
1999 if (auto ve1 = e.e1.isVarExp())
2000 if (ve1.var == e.func)
2006 auto er = interpret(pue, e.e1, istate);
2007 if (exceptionOrCant(er))
2011 // If it has already been CTFE'd, just return it
2016 er = (er == pue.exp()) ? pue.copy() : er;
2017 emplaceExp!(DelegateExp)(pue, e.loc, er, e.func, false);
2019 result.type = e.type;
2023 static Expression getVarExp(const ref Loc loc, InterState* istate, Declaration d, CTFEGoal goal)
2025 Expression e = CTFEExp.cantexp;
2026 if (VarDeclaration v = d.isVarDeclaration())
2028 /* Magic variable __ctfe always returns true when interpreting
2030 if (v.ident == Id.ctfe)
2031 return IntegerExp.createBool(true);
2033 if (!v.originalType && v.semanticRun < PASS.semanticdone) // semantic() not yet run
2035 v.dsymbolSemantic(null);
2036 if (v.type.ty == Terror)
2037 return CTFEExp.cantexp;
2040 if ((v.isConst() || v.isImmutable() || v.storage_class & STC.manifest) && !hasValue(v) && v._init && !v.isCTFE())
2044 error(loc, "circular initialization of %s `%s`", v.kind(), v.toPrettyChars());
2045 return CTFEExp.cantexp;
2050 v._init = v._init.initializerSemantic(v._scope, v.type, INITinterpret); // might not be run on aggregate members
2053 e = v._init.initializerToExpression(v.type);
2055 return CTFEExp.cantexp;
2058 if (e.op == EXP.construct || e.op == EXP.blit)
2060 AssignExp ae = cast(AssignExp)e;
2064 if (e.op == EXP.error)
2066 // FIXME: Ultimately all errors should be detected in prior semantic analysis stage.
2068 else if (v.isDataseg() || (v.storage_class & STC.manifest))
2070 /* https://issues.dlang.org/show_bug.cgi?id=14304
2071 * e is a value that is not yet owned by CTFE.
2072 * Mark as "cached", and use it directly during interpretation.
2074 e = scrubCacheValue(e);
2075 ctfeGlobals.stack.saveGlobalConstant(v, e);
2080 e = interpret(e, istate);
2082 if (CTFEExp.isCantExp(e) && !global.gag && !ctfeGlobals.stackTraceCallsToSuppress)
2083 errorSupplemental(loc, "while evaluating %s.init", v.toChars());
2084 if (exceptionOrCantInterpret(e))
2088 else if (v.isCTFE() && !hasValue(v))
2090 if (v._init && v.type.size() != 0)
2092 if (v._init.isVoidInitializer())
2094 // var should have been initialized when it was created
2095 error(loc, "CTFE internal error: trying to access uninitialized var");
2098 e = v._init.initializerToExpression();
2101 // Zero-length arrays don't have an initializer
2102 e = v.type.defaultInitLiteral(e.loc);
2104 e = interpret(e, istate);
2106 else if (!(v.isDataseg() || v.storage_class & STC.manifest) && !v.isCTFE() && !istate)
2108 error(loc, "variable `%s` cannot be read at compile time", v.toChars());
2109 return CTFEExp.cantexp;
2113 e = hasValue(v) ? getValue(v) : null;
2116 // Zero-length arrays don't have an initializer
2117 if (v.type.size() == 0)
2118 e = v.type.defaultInitLiteral(loc);
2119 else if (!v.isCTFE() && v.isDataseg())
2121 error(loc, "static variable `%s` cannot be read at compile time", v.toChars());
2122 return CTFEExp.cantexp;
2126 assert(!(v._init && v._init.isVoidInitializer()));
2127 // CTFE initiated from inside a function
2128 error(loc, "variable `%s` cannot be read at compile time", v.toChars());
2129 return CTFEExp.cantexp;
2132 if (auto vie = e.isVoidInitExp())
2134 error(loc, "cannot read uninitialized variable `%s` in ctfe", v.toPrettyChars());
2135 errorSupplemental(vie.var.loc, "`%s` was uninitialized and used before set", vie.var.toChars());
2136 return CTFEExp.cantexp;
2138 if (goal != CTFEGoal.LValue && v.isReference())
2139 e = interpret(e, istate, goal);
2142 e = CTFEExp.cantexp;
2144 else if (SymbolDeclaration s = d.isSymbolDeclaration())
2146 // exclude void[]-typed `__traits(initSymbol)`
2147 if (auto ta = s.type.toBasetype().isTypeDArray())
2149 assert(ta.next.ty == Tvoid);
2150 error(loc, "cannot determine the address of the initializer symbol during CTFE");
2151 return CTFEExp.cantexp;
2154 // Struct static initializers, for example
2155 e = s.dsym.type.defaultInitLiteral(loc);
2156 if (e.op == EXP.error)
2157 error(loc, "CTFE failed because of previous errors in `%s.init`", s.toChars());
2158 e = e.expressionSemantic(null);
2159 if (e.op == EXP.error)
2160 e = CTFEExp.cantexp;
2161 else // Convert NULL to CTFEExp
2162 e = interpret(e, istate, goal);
2165 error(loc, "cannot interpret declaration `%s` at compile time", d.toChars());
2169 override void visit(VarExp e)
2173 printf("%s VarExp::interpret() `%s`, goal = %d\n", e.loc.toChars(), e.toChars(), goal);
2175 if (e.var.isFuncDeclaration())
2181 if (goal == CTFEGoal.LValue)
2183 if (auto v = e.var.isVarDeclaration())
2187 // Compile-time known non-CTFE variable from an outer context
2188 // e.g. global or from a ref argument
2189 if (v.isConst() || v.isImmutable())
2191 result = getVarExp(e.loc, istate, v, goal);
2195 if (!v.isCTFE() && v.isDataseg())
2196 e.error("static variable `%s` cannot be read at compile time", v.toChars());
2197 else // CTFE initiated from inside a function
2198 e.error("variable `%s` cannot be read at compile time", v.toChars());
2199 result = CTFEExp.cantexp;
2203 if (v.storage_class & (STC.out_ | STC.ref_))
2205 // Strip off the nest of ref variables
2206 Expression ev = getValue(v);
2207 if (ev.op == EXP.variable ||
2208 ev.op == EXP.index ||
2209 (ev.op == EXP.slice && ev.type.toBasetype().ty == Tsarray) ||
2210 ev.op == EXP.dotVariable)
2212 result = interpret(pue, ev, istate, goal);
2220 result = getVarExp(e.loc, istate, e.var, goal);
2221 if (exceptionOrCant(result))
2224 // Visit the default initializer for noreturn variables
2225 // (Custom initializers would abort the current function call and exit above)
2226 if (result.type.ty == Tnoreturn)
2228 result.accept(this);
2232 if ((e.var.storage_class & (STC.ref_ | STC.out_)) == 0 && e.type.baseElemOf().ty != Tstruct)
2234 /* Ultimately, STC.ref_|STC.out_ check should be enough to see the
2235 * necessity of type repainting. But currently front-end paints
2236 * non-ref struct variables by the const type.
2238 * auto foo(ref const S cs);
2240 * foo(s); // VarExp('s') will have const(S)
2242 // A VarExp may include an implicit cast. It must be done explicitly.
2243 result = paintTypeOntoLiteral(pue, e.type, result);
2247 override void visit(DeclarationExp e)
2251 printf("%s DeclarationExp::interpret() %s\n", e.loc.toChars(), e.toChars());
2253 Dsymbol s = e.declaration;
2254 while (s.isAttribDeclaration())
2256 auto ad = cast(AttribDeclaration)s;
2257 assert(ad.decl && ad.decl.dim == 1); // Currently, only one allowed when parsing
2260 if (VarDeclaration v = s.isVarDeclaration())
2262 if (TupleDeclaration td = v.toAlias().isTupleDeclaration())
2266 // Reserve stack space for all tuple members
2269 foreach (o; *td.objects)
2271 Expression ex = isExpression(o);
2272 DsymbolExp ds = ex ? ex.isDsymbolExp() : null;
2273 VarDeclaration v2 = ds ? ds.s.isVarDeclaration() : null;
2275 if (v2.isDataseg() && !v2.isCTFE())
2278 ctfeGlobals.stack.push(v2);
2282 if (ExpInitializer ie = v2._init.isExpInitializer())
2284 einit = interpretRegion(ie.exp, istate, goal);
2285 if (exceptionOrCant(einit))
2288 else if (v2._init.isVoidInitializer())
2290 einit = voidInitLiteral(v2.type, v2).copy();
2294 e.error("declaration `%s` is not yet implemented in CTFE", e.toChars());
2295 result = CTFEExp.cantexp;
2298 setValue(v2, einit);
2305 // Just ignore static variables which aren't read or written yet
2309 if (!(v.isDataseg() || v.storage_class & STC.manifest) || v.isCTFE())
2310 ctfeGlobals.stack.push(v);
2313 if (ExpInitializer ie = v._init.isExpInitializer())
2315 result = interpretRegion(ie.exp, istate, goal);
2317 else if (v._init.isVoidInitializer())
2319 result = voidInitLiteral(v.type, v).copy();
2320 // There is no AssignExp for void initializers,
2322 setValue(v, result);
2326 e.error("declaration `%s` is not yet implemented in CTFE", e.toChars());
2327 result = CTFEExp.cantexp;
2330 else if (v.type.size() == 0)
2332 // Zero-length arrays don't need an initializer
2333 result = v.type.defaultInitLiteral(e.loc);
2337 e.error("variable `%s` cannot be modified at compile time", v.toChars());
2338 result = CTFEExp.cantexp;
2342 if (s.isTemplateMixin() || s.isTupleDeclaration())
2344 // These can be made to work, too lazy now
2345 e.error("declaration `%s` is not yet implemented in CTFE", e.toChars());
2346 result = CTFEExp.cantexp;
2350 // Others should not contain executable code, so are trivial to evaluate
2354 printf("-DeclarationExp::interpret(%s): %p\n", e.toChars(), result);
2358 override void visit(TypeidExp e)
2362 printf("%s TypeidExp::interpret() %s\n", e.loc.toChars(), e.toChars());
2364 if (Type t = isType(e.obj))
2369 if (Expression ex = isExpression(e.obj))
2371 result = interpret(pue, ex, istate);
2372 if (exceptionOrCant(ex))
2375 if (result.op == EXP.null_)
2377 e.error("null pointer dereference evaluating typeid. `%s` is `null`", ex.toChars());
2378 result = CTFEExp.cantexp;
2381 if (result.op != EXP.classReference)
2383 e.error("CTFE internal error: determining classinfo");
2384 result = CTFEExp.cantexp;
2388 ClassDeclaration cd = (cast(ClassReferenceExp)result).originalClass();
2391 emplaceExp!(TypeidExp)(pue, e.loc, cd.type);
2393 result.type = e.type;
2396 visit(cast(Expression)e);
2399 override void visit(TupleExp e)
2403 printf("%s TupleExp::interpret() %s\n", e.loc.toChars(), e.toChars());
2405 if (exceptionOrCant(interpretRegion(e.e0, istate, CTFEGoal.Nothing)))
2408 auto expsx = e.exps;
2409 foreach (i, exp; *expsx)
2411 Expression ex = interpretRegion(exp, istate);
2412 if (exceptionOrCant(ex))
2415 // A tuple of assignments can contain void (Bug 5676).
2416 if (goal == CTFEGoal.Nothing)
2418 if (ex.op == EXP.voidExpression)
2420 e.error("CTFE internal error: void element `%s` in tuple", exp.toChars());
2424 /* If any changes, do Copy On Write
2428 expsx = copyArrayOnWrite(expsx, e.exps);
2429 (*expsx)[i] = copyRegionExp(ex);
2433 if (expsx !is e.exps)
2435 expandTuples(expsx);
2436 emplaceExp!(TupleExp)(pue, e.loc, expsx);
2438 result.type = new TypeTuple(expsx);
2444 override void visit(ArrayLiteralExp e)
2448 printf("%s ArrayLiteralExp::interpret() %s\n", e.loc.toChars(), e.toChars());
2450 if (e.ownedByCtfe >= OwnedBy.ctfe) // We've already interpreted all the elements
2456 Type tn = e.type.toBasetype().nextOf().toBasetype();
2457 bool wantCopy = (tn.ty == Tsarray || tn.ty == Tstruct);
2459 auto basis = interpretRegion(e.basis, istate);
2460 if (exceptionOrCant(basis))
2463 auto expsx = e.elements;
2464 size_t dim = expsx ? expsx.dim : 0;
2465 for (size_t i = 0; i < dim; i++)
2467 Expression exp = (*expsx)[i];
2471 ex = copyLiteral(basis).copy();
2475 // segfault bug 6250
2476 assert(exp.op != EXP.index || (cast(IndexExp)exp).e1 != e);
2478 ex = interpretRegion(exp, istate);
2479 if (exceptionOrCant(ex))
2482 /* Each elements should have distinct CTFE memory.
2484 * int[1][] pieces = [z,z]; // here
2487 ex = copyLiteral(ex).copy();
2490 /* If any changes, do Copy On Write
2494 expsx = copyArrayOnWrite(expsx, e.elements);
2499 if (expsx !is e.elements)
2501 // todo: all tuple expansions should go in semantic phase.
2502 expandTuples(expsx);
2503 if (expsx.dim != dim)
2505 e.error("CTFE internal error: invalid array literal");
2506 result = CTFEExp.cantexp;
2509 emplaceExp!(ArrayLiteralExp)(pue, e.loc, e.type, basis, expsx);
2510 auto ale = cast(ArrayLiteralExp)pue.exp();
2511 ale.ownedByCtfe = OwnedBy.ctfe;
2514 else if ((cast(TypeNext)e.type).next.mod & (MODFlags.const_ | MODFlags.immutable_))
2516 // If it's immutable, we don't need to dup it
2521 *pue = copyLiteral(e);
2526 override void visit(AssocArrayLiteralExp e)
2530 printf("%s AssocArrayLiteralExp::interpret() %s\n", e.loc.toChars(), e.toChars());
2532 if (e.ownedByCtfe >= OwnedBy.ctfe) // We've already interpreted all the elements
2538 auto keysx = e.keys;
2539 auto valuesx = e.values;
2540 foreach (i, ekey; *keysx)
2542 auto evalue = (*valuesx)[i];
2544 auto ek = interpretRegion(ekey, istate);
2545 if (exceptionOrCant(ek))
2547 auto ev = interpretRegion(evalue, istate);
2548 if (exceptionOrCant(ev))
2551 /* If any changes, do Copy On Write
2556 keysx = copyArrayOnWrite(keysx, e.keys);
2557 valuesx = copyArrayOnWrite(valuesx, e.values);
2562 if (keysx !is e.keys)
2563 expandTuples(keysx);
2564 if (valuesx !is e.values)
2565 expandTuples(valuesx);
2566 if (keysx.dim != valuesx.dim)
2568 e.error("CTFE internal error: invalid AA");
2569 result = CTFEExp.cantexp;
2573 /* Remove duplicate keys
2575 for (size_t i = 1; i < keysx.dim; i++)
2577 auto ekey = (*keysx)[i - 1];
2578 for (size_t j = i; j < keysx.dim; j++)
2580 auto ekey2 = (*keysx)[j];
2581 if (!ctfeEqual(e.loc, EXP.equal, ekey, ekey2))
2585 keysx = copyArrayOnWrite(keysx, e.keys);
2586 valuesx = copyArrayOnWrite(valuesx, e.values);
2587 keysx.remove(i - 1);
2588 valuesx.remove(i - 1);
2590 i -= 1; // redo the i'th iteration
2595 if (keysx !is e.keys ||
2596 valuesx !is e.values)
2598 assert(keysx !is e.keys &&
2599 valuesx !is e.values);
2600 auto aae = ctfeEmplaceExp!AssocArrayLiteralExp(e.loc, keysx, valuesx);
2602 aae.ownedByCtfe = OwnedBy.ctfe;
2607 *pue = copyLiteral(e);
2612 override void visit(StructLiteralExp e)
2616 printf("%s StructLiteralExp::interpret() %s ownedByCtfe = %d\n", e.loc.toChars(), e.toChars(), e.ownedByCtfe);
2618 if (e.ownedByCtfe >= OwnedBy.ctfe)
2624 size_t dim = e.elements ? e.elements.dim : 0;
2625 auto expsx = e.elements;
2627 if (dim != e.sd.fields.dim)
2629 // guaranteed by AggregateDeclaration.fill and TypeStruct.defaultInitLiteral
2630 const nvthis = e.sd.fields.dim - e.sd.nonHiddenFields();
2631 assert(e.sd.fields.dim - dim == nvthis);
2633 /* If a nested struct has no initialized hidden pointer,
2634 * set it to null to match the runtime behaviour.
2636 foreach (const i; 0 .. nvthis)
2638 auto ne = ctfeEmplaceExp!NullExp(e.loc);
2639 auto vthis = i == 0 ? e.sd.vthis : e.sd.vthis2;
2640 ne.type = vthis.type;
2642 expsx = copyArrayOnWrite(expsx, e.elements);
2647 assert(dim == e.sd.fields.dim);
2649 foreach (i; 0 .. dim)
2651 auto v = e.sd.fields[i];
2652 Expression exp = (*expsx)[i];
2656 ex = voidInitLiteral(v.type, v).copy();
2660 ex = interpretRegion(exp, istate);
2661 if (exceptionOrCant(ex))
2663 if ((v.type.ty != ex.type.ty) && v.type.ty == Tsarray)
2665 // Block assignment from inside struct literals
2666 auto tsa = cast(TypeSArray)v.type;
2667 auto len = cast(size_t)tsa.dim.toInteger();
2669 ex = createBlockDuplicatedArrayLiteral(&ue, ex.loc, v.type, ex, len);
2675 /* If any changes, do Copy On Write
2679 expsx = copyArrayOnWrite(expsx, e.elements);
2684 if (expsx !is e.elements)
2686 expandTuples(expsx);
2687 if (expsx.dim != e.sd.fields.dim)
2689 e.error("CTFE internal error: invalid struct literal");
2690 result = CTFEExp.cantexp;
2693 emplaceExp!(StructLiteralExp)(pue, e.loc, e.sd, expsx);
2694 auto sle = cast(StructLiteralExp)pue.exp();
2696 sle.ownedByCtfe = OwnedBy.ctfe;
2697 sle.origin = e.origin;
2702 *pue = copyLiteral(e);
2707 // Create an array literal of type 'newtype' with dimensions given by
2708 // 'arguments'[argnum..$]
2709 static Expression recursivelyCreateArrayLiteral(UnionExp* pue, const ref Loc loc, Type newtype, InterState* istate, Expressions* arguments, int argnum)
2711 Expression lenExpr = interpret(pue, (*arguments)[argnum], istate);
2712 if (exceptionOrCantInterpret(lenExpr))
2714 size_t len = cast(size_t)lenExpr.toInteger();
2715 Type elemType = (cast(TypeArray)newtype).next;
2716 if (elemType.ty == Tarray && argnum < arguments.dim - 1)
2718 Expression elem = recursivelyCreateArrayLiteral(pue, loc, elemType, istate, arguments, argnum + 1);
2719 if (exceptionOrCantInterpret(elem))
2722 auto elements = new Expressions(len);
2723 foreach (ref element; *elements)
2724 element = copyLiteral(elem).copy();
2725 emplaceExp!(ArrayLiteralExp)(pue, loc, newtype, elements);
2726 auto ae = cast(ArrayLiteralExp)pue.exp();
2727 ae.ownedByCtfe = OwnedBy.ctfe;
2730 assert(argnum == arguments.dim - 1);
2731 if (elemType.ty.isSomeChar)
2733 const ch = cast(dchar)elemType.defaultInitLiteral(loc).toInteger();
2734 const sz = cast(ubyte)elemType.size();
2735 return createBlockDuplicatedStringLiteral(pue, loc, newtype, ch, len, sz);
2739 auto el = interpret(elemType.defaultInitLiteral(loc), istate);
2740 return createBlockDuplicatedArrayLiteral(pue, loc, newtype, el, len);
2744 override void visit(NewExp e)
2748 printf("%s NewExp::interpret() %s\n", e.loc.toChars(), e.toChars());
2751 Expression epre = interpret(pue, e.argprefix, istate, CTFEGoal.Nothing);
2752 if (exceptionOrCant(epre))
2755 if (e.newtype.ty == Tarray && e.arguments)
2757 result = recursivelyCreateArrayLiteral(pue, e.loc, e.newtype, istate, e.arguments, 0);
2760 if (auto ts = e.newtype.toBasetype().isTypeStruct())
2764 Expression se = e.newtype.defaultInitLiteral(e.loc);
2765 se = interpret(se, istate);
2766 if (exceptionOrCant(se))
2768 result = interpretFunction(pue, e.member, istate, e.arguments, se);
2770 // Repaint as same as CallExp::interpret() does.
2775 StructDeclaration sd = ts.sym;
2776 auto exps = new Expressions();
2777 exps.reserve(sd.fields.dim);
2780 exps.setDim(e.arguments.dim);
2781 foreach (i, ex; *e.arguments)
2783 ex = interpretRegion(ex, istate);
2784 if (exceptionOrCant(ex))
2789 sd.fill(e.loc, exps, false);
2791 auto se = ctfeEmplaceExp!StructLiteralExp(e.loc, sd, exps, e.newtype);
2793 se.type = e.newtype;
2794 se.ownedByCtfe = OwnedBy.ctfe;
2795 result = interpret(pue, se, istate);
2797 if (exceptionOrCant(result))
2799 Expression ev = (result == pue.exp()) ? pue.copy() : result;
2800 emplaceExp!(AddrExp)(pue, e.loc, ev, e.type);
2804 if (auto tc = e.newtype.toBasetype().isTypeClass())
2806 ClassDeclaration cd = tc.sym;
2807 size_t totalFieldCount = 0;
2808 for (ClassDeclaration c = cd; c; c = c.baseClass)
2809 totalFieldCount += c.fields.dim;
2810 auto elems = new Expressions(totalFieldCount);
2811 size_t fieldsSoFar = totalFieldCount;
2812 for (ClassDeclaration c = cd; c; c = c.baseClass)
2814 fieldsSoFar -= c.fields.dim;
2815 foreach (i, v; c.fields)
2819 e.error("circular reference to `%s`", v.toPrettyChars());
2820 result = CTFEExp.cantexp;
2826 if (v._init.isVoidInitializer())
2827 m = voidInitLiteral(v.type, v).copy();
2829 m = v.getConstInitializer(true);
2832 m = v.type.defaultInitLiteral(e.loc);
2833 if (exceptionOrCant(m))
2835 (*elems)[fieldsSoFar + i] = copyLiteral(m).copy();
2838 // Hack: we store a ClassDeclaration instead of a StructDeclaration.
2839 // We probably won't get away with this.
2840 // auto se = new StructLiteralExp(e.loc, cast(StructDeclaration)cd, elems, e.newtype);
2841 auto se = ctfeEmplaceExp!StructLiteralExp(e.loc, cast(StructDeclaration)cd, elems, e.newtype);
2843 se.ownedByCtfe = OwnedBy.ctfe;
2844 Expression eref = ctfeEmplaceExp!ClassReferenceExp(e.loc, se, e.type);
2848 if (!e.member.fbody)
2850 Expression ctorfail = evaluateIfBuiltin(pue, istate, e.loc, e.member, e.arguments, eref);
2853 if (exceptionOrCant(ctorfail))
2858 e.member.error("`%s` cannot be constructed at compile time, because the constructor has no available source code", e.newtype.toChars());
2859 result = CTFEExp.cantexp;
2863 Expression ctorfail = interpretFunction(&ue, e.member, istate, e.arguments, eref);
2864 if (exceptionOrCant(ctorfail))
2867 /* https://issues.dlang.org/show_bug.cgi?id=14465
2868 * Repaint the loc, because a super() call
2869 * in the constructor modifies the loc of ClassReferenceExp
2870 * in CallExp::interpret().
2877 if (e.newtype.toBasetype().isscalar())
2880 if (e.arguments && e.arguments.dim)
2881 newval = (*e.arguments)[0];
2883 newval = e.newtype.defaultInitLiteral(e.loc);
2884 newval = interpretRegion(newval, istate);
2885 if (exceptionOrCant(newval))
2888 // Create a CTFE pointer &[newval][0]
2889 auto elements = new Expressions(1);
2890 (*elements)[0] = newval;
2891 auto ae = ctfeEmplaceExp!ArrayLiteralExp(e.loc, e.newtype.arrayOf(), elements);
2892 ae.ownedByCtfe = OwnedBy.ctfe;
2894 auto ei = ctfeEmplaceExp!IndexExp(e.loc, ae, ctfeEmplaceExp!IntegerExp(Loc.initial, 0, Type.tsize_t));
2895 ei.type = e.newtype;
2896 emplaceExp!(AddrExp)(pue, e.loc, ei, e.type);
2900 e.error("cannot interpret `%s` at compile time", e.toChars());
2901 result = CTFEExp.cantexp;
2904 override void visit(UnaExp e)
2908 printf("%s UnaExp::interpret() %s\n", e.loc.toChars(), e.toChars());
2911 Expression e1 = interpret(&ue, e.e1, istate);
2912 if (exceptionOrCant(e1))
2917 *pue = Neg(e.type, e1);
2921 *pue = Com(e.type, e1);
2925 *pue = Not(e.type, e1);
2931 result = (*pue).exp();
2934 override void visit(DotTypeExp e)
2938 printf("%s DotTypeExp::interpret() %s\n", e.loc.toChars(), e.toChars());
2941 Expression e1 = interpret(&ue, e.e1, istate);
2942 if (exceptionOrCant(e1))
2945 result = e; // optimize: reuse this CTFE reference
2948 auto edt = cast(DotTypeExp)e.copy();
2949 edt.e1 = (e1 == ue.exp()) ? e1.copy() : e1; // don't return pointer to ue
2954 extern (D) private void interpretCommon(BinExp e, fp_t fp)
2958 printf("%s BinExp::interpretCommon() %s\n", e.loc.toChars(), e.toChars());
2960 if (e.e1.type.ty == Tpointer && e.e2.type.ty == Tpointer && e.op == EXP.min)
2962 UnionExp ue1 = void;
2963 Expression e1 = interpret(&ue1, e.e1, istate);
2964 if (exceptionOrCant(e1))
2966 UnionExp ue2 = void;
2967 Expression e2 = interpret(&ue2, e.e2, istate);
2968 if (exceptionOrCant(e2))
2970 *pue = pointerDifference(e.loc, e.type, e1, e2);
2971 result = (*pue).exp();
2974 if (e.e1.type.ty == Tpointer && e.e2.type.isintegral())
2976 UnionExp ue1 = void;
2977 Expression e1 = interpret(&ue1, e.e1, istate);
2978 if (exceptionOrCant(e1))
2980 UnionExp ue2 = void;
2981 Expression e2 = interpret(&ue2, e.e2, istate);
2982 if (exceptionOrCant(e2))
2984 *pue = pointerArithmetic(e.loc, e.op, e.type, e1, e2);
2985 result = (*pue).exp();
2988 if (e.e2.type.ty == Tpointer && e.e1.type.isintegral() && e.op == EXP.add)
2990 UnionExp ue1 = void;
2991 Expression e1 = interpret(&ue1, e.e1, istate);
2992 if (exceptionOrCant(e1))
2994 UnionExp ue2 = void;
2995 Expression e2 = interpret(&ue2, e.e2, istate);
2996 if (exceptionOrCant(e2))
2998 *pue = pointerArithmetic(e.loc, e.op, e.type, e2, e1);
2999 result = (*pue).exp();
3002 if (e.e1.type.ty == Tpointer || e.e2.type.ty == Tpointer)
3004 e.error("pointer expression `%s` cannot be interpreted at compile time", e.toChars());
3005 result = CTFEExp.cantexp;
3009 bool evalOperand(UnionExp* pue, Expression ex, out Expression er)
3011 er = interpret(pue, ex, istate);
3012 if (exceptionOrCant(er))
3017 UnionExp ue1 = void;
3019 if (!evalOperand(&ue1, e.e1, e1))
3022 UnionExp ue2 = void;
3024 if (!evalOperand(&ue2, e.e2, e2))
3027 if (e.op == EXP.rightShift || e.op == EXP.leftShift || e.op == EXP.unsignedRightShift)
3029 const sinteger_t i2 = e2.toInteger();
3030 const d_uns64 sz = e1.type.size() * 8;
3031 if (i2 < 0 || i2 >= sz)
3033 e.error("shift by %lld is outside the range 0..%llu", i2, cast(ulong)sz - 1);
3034 result = CTFEExp.cantexp;
3039 /******************************************
3040 * Perform the operation fp on operands e1 and e2.
3042 UnionExp evaluate(Loc loc, Type type, Expression e1, Expression e2)
3045 auto ae1 = e1.isArrayLiteralExp();
3046 auto ae2 = e2.isArrayLiteralExp();
3054 if (ae1 && e2.implicitConvTo(e1.type.toBasetype().nextOf())) // case 3
3056 else if (ae2 && e1.implicitConvTo(e2.type.toBasetype().nextOf())) // case 2
3060 auto aex = ae1 ? ae1 : ae2;
3063 emplaceExp!ArrayLiteralExp(&ue, loc, type, cast(Expressions*) null);
3066 const length = aex.elements.length;
3067 Expressions* elements = new Expressions(length);
3069 emplaceExp!ArrayLiteralExp(&ue, loc, type, elements);
3070 foreach (i; 0 .. length)
3072 Expression e1x = ae1 ? ae1[i] : e1;
3073 Expression e2x = ae2 ? ae2[i] : e2;
3074 UnionExp uex = evaluate(loc, e1x.type, e1x, e2x);
3075 // This can be made more efficient by making use of ue.basis
3076 (*elements)[i] = uex.copy();
3081 if (e1.isConst() != 1)
3083 // The following should really be an assert()
3084 e1.error("CTFE internal error: non-constant value `%s`", e1.toChars());
3085 emplaceExp!CTFEExp(&ue, EXP.cantExpression);
3088 if (e2.isConst() != 1)
3090 e2.error("CTFE internal error: non-constant value `%s`", e2.toChars());
3091 emplaceExp!CTFEExp(&ue, EXP.cantExpression);
3095 return (*fp)(loc, type, e1, e2);
3098 *pue = evaluate(e.loc, e.type, e1, e2);
3099 result = (*pue).exp();
3100 if (CTFEExp.isCantExp(result))
3101 e.error("`%s` cannot be interpreted at compile time", e.toChars());
3104 extern (D) private void interpretCompareCommon(BinExp e, fp2_t fp)
3108 printf("%s BinExp::interpretCompareCommon() %s\n", e.loc.toChars(), e.toChars());
3110 UnionExp ue1 = void;
3111 UnionExp ue2 = void;
3112 if (e.e1.type.ty == Tpointer && e.e2.type.ty == Tpointer)
3114 Expression e1 = interpret(&ue1, e.e1, istate);
3115 if (exceptionOrCant(e1))
3117 Expression e2 = interpret(&ue2, e.e2, istate);
3118 if (exceptionOrCant(e2))
3120 //printf("e1 = %s %s, e2 = %s %s\n", e1.type.toChars(), e1.toChars(), e2.type.toChars(), e2.toChars());
3121 dinteger_t ofs1, ofs2;
3122 Expression agg1 = getAggregateFromPointer(e1, &ofs1);
3123 Expression agg2 = getAggregateFromPointer(e2, &ofs2);
3124 //printf("agg1 = %p %s, agg2 = %p %s\n", agg1, agg1.toChars(), agg2, agg2.toChars());
3125 const cmp = comparePointers(e.op, agg1, ofs1, agg2, ofs2);
3128 char dir = (e.op == EXP.greaterThan || e.op == EXP.greaterOrEqual) ? '<' : '>';
3129 e.error("the ordering of pointers to unrelated memory blocks is indeterminate in CTFE. To check if they point to the same memory block, use both `>` and `<` inside `&&` or `||`, eg `%s && %s %c= %s + 1`", e.toChars(), e.e1.toChars(), dir, e.e2.toChars());
3130 result = CTFEExp.cantexp;
3133 if (e.type.equals(Type.tbool))
3134 result = IntegerExp.createBool(cmp != 0);
3137 emplaceExp!(IntegerExp)(pue, e.loc, cmp, e.type);
3138 result = (*pue).exp();
3142 Expression e1 = interpret(&ue1, e.e1, istate);
3143 if (exceptionOrCant(e1))
3145 if (!isCtfeComparable(e1))
3147 e.error("cannot compare `%s` at compile time", e1.toChars());
3148 result = CTFEExp.cantexp;
3151 Expression e2 = interpret(&ue2, e.e2, istate);
3152 if (exceptionOrCant(e2))
3154 if (!isCtfeComparable(e2))
3156 e.error("cannot compare `%s` at compile time", e2.toChars());
3157 result = CTFEExp.cantexp;
3160 const cmp = (*fp)(e.loc, e.op, e1, e2);
3161 if (e.type.equals(Type.tbool))
3162 result = IntegerExp.createBool(cmp);
3165 emplaceExp!(IntegerExp)(pue, e.loc, cmp, e.type);
3166 result = (*pue).exp();
3170 override void visit(BinExp e)
3175 interpretCommon(e, &Add);
3179 interpretCommon(e, &Min);
3183 interpretCommon(e, &Mul);
3187 interpretCommon(e, &Div);
3191 interpretCommon(e, &Mod);
3195 interpretCommon(e, &Shl);
3198 case EXP.rightShift:
3199 interpretCommon(e, &Shr);
3202 case EXP.unsignedRightShift:
3203 interpretCommon(e, &Ushr);
3207 interpretCommon(e, &And);
3211 interpretCommon(e, &Or);
3215 interpretCommon(e, &Xor);
3219 interpretCommon(e, &Pow);
3224 interpretCompareCommon(e, &ctfeEqual);
3228 case EXP.notIdentity:
3229 interpretCompareCommon(e, &ctfeIdentity);
3233 case EXP.lessOrEqual:
3234 case EXP.greaterThan:
3235 case EXP.greaterOrEqual:
3236 interpretCompareCommon(e, &ctfeCmp);
3240 printf("be = '%s' %s at [%s]\n", EXPtoString(e.op).ptr, e.toChars(), e.loc.toChars());
3245 /* Helper functions for BinExp::interpretAssignCommon
3247 // Returns the variable which is eventually modified, or NULL if an rvalue.
3248 // thisval is the current value of 'this'.
3249 static VarDeclaration findParentVar(Expression e)
3253 if (auto ve = e.isVarExp())
3255 VarDeclaration v = ve.var.isVarDeclaration();
3259 if (auto ie = e.isIndexExp())
3261 else if (auto dve = e.isDotVarExp())
3263 else if (auto dtie = e.isDotTemplateInstanceExp())
3265 else if (auto se = e.isSliceExp())
3272 extern (D) private void interpretAssignCommon(BinExp e, fp_t fp, int post = 0)
3276 printf("%s BinExp::interpretAssignCommon() %s\n", e.loc.toChars(), e.toChars());
3278 result = CTFEExp.cantexp;
3280 Expression e1 = e.e1;
3283 e.error("value of `%s` is not known at compile time", e1.toChars());
3287 ++ctfeGlobals.numAssignments;
3289 /* Before we begin, we need to know if this is a reference assignment
3290 * (dynamic array, AA, or class) or a value assignment.
3291 * Determining this for slice assignments are tricky: we need to know
3292 * if it is a block assignment (a[] = e) rather than a direct slice
3293 * assignment (a[] = b[]). Note that initializers of multi-dimensional
3294 * static arrays can have 2D block assignments (eg, int[7][7] x = 6;).
3295 * So we need to recurse to determine if it is a block assignment.
3297 bool isBlockAssignment = false;
3298 if (e1.op == EXP.slice)
3300 // a[] = e can have const e. So we compare the naked types.
3301 Type tdst = e1.type.toBasetype();
3302 Type tsrc = e.e2.type.toBasetype();
3303 while (tdst.ty == Tsarray || tdst.ty == Tarray)
3305 tdst = (cast(TypeArray)tdst).next.toBasetype();
3306 if (tsrc.equivalent(tdst))
3308 isBlockAssignment = true;
3314 // ---------------------------------------
3315 // Deal with reference assignment
3316 // ---------------------------------------
3317 // If it is a construction of a ref variable, it is a ref assignment
3318 if ((e.op == EXP.construct || e.op == EXP.blit) &&
3319 ((cast(AssignExp)e).memset == MemorySet.referenceInit))
3323 Expression newval = interpretRegion(e.e2, istate, CTFEGoal.LValue);
3324 if (exceptionOrCant(newval))
3327 VarDeclaration v = (cast(VarExp)e1).var.isVarDeclaration();
3328 setValue(v, newval);
3330 // Get the value to return. Note that 'newval' is an Lvalue,
3331 // so if we need an Rvalue, we have to interpret again.
3332 if (goal == CTFEGoal.RValue)
3333 result = interpretRegion(newval, istate);
3335 result = e1; // VarExp is a CTFE reference
3341 while (e1.op == EXP.cast_)
3343 CastExp ce = cast(CastExp)e1;
3348 // ---------------------------------------
3349 // Interpret left hand side
3350 // ---------------------------------------
3351 AssocArrayLiteralExp existingAA = null;
3352 Expression lastIndex = null;
3353 Expression oldval = null;
3354 if (e1.op == EXP.index && (cast(IndexExp)e1).e1.type.toBasetype().ty == Taarray)
3356 // ---------------------------------------
3357 // Deal with AA index assignment
3358 // ---------------------------------------
3359 /* This needs special treatment if the AA doesn't exist yet.
3360 * There are two special cases:
3361 * (1) If the AA is itself an index of another AA, we may need to create
3362 * multiple nested AA literals before we can insert the new value.
3363 * (2) If the ultimate AA is null, no insertion happens at all. Instead,
3364 * we create nested AA literals, and change it into a assignment.
3366 IndexExp ie = cast(IndexExp)e1;
3367 int depth = 0; // how many nested AA indices are there?
3368 while (ie.e1.op == EXP.index && (cast(IndexExp)ie.e1).e1.type.toBasetype().ty == Taarray)
3370 assert(ie.modifiable);
3371 ie = cast(IndexExp)ie.e1;
3375 // Get the AA value to be modified.
3376 Expression aggregate = interpretRegion(ie.e1, istate);
3377 if (exceptionOrCant(aggregate))
3379 if ((existingAA = aggregate.isAssocArrayLiteralExp()) !is null)
3381 // Normal case, ultimate parent AA already exists
3382 // We need to walk from the deepest index up, checking that an AA literal
3383 // already exists on each level.
3384 lastIndex = interpretRegion((cast(IndexExp)e1).e2, istate);
3385 lastIndex = resolveSlice(lastIndex); // only happens with AA assignment
3386 if (exceptionOrCant(lastIndex))
3391 // Walk the syntax tree to find the indexExp at this depth
3392 IndexExp xe = cast(IndexExp)e1;
3393 foreach (d; 0 .. depth)
3394 xe = cast(IndexExp)xe.e1;
3396 Expression ekey = interpretRegion(xe.e2, istate);
3397 if (exceptionOrCant(ekey))
3399 UnionExp ekeyTmp = void;
3400 ekey = resolveSlice(ekey, &ekeyTmp); // only happens with AA assignment
3402 // Look up this index in it up in the existing AA, to get the next level of AA.
3403 AssocArrayLiteralExp newAA = cast(AssocArrayLiteralExp)findKeyInAA(e.loc, existingAA, ekey);
3404 if (exceptionOrCant(newAA))
3408 // Doesn't exist yet, create an empty AA...
3409 auto keysx = new Expressions();
3410 auto valuesx = new Expressions();
3411 newAA = ctfeEmplaceExp!AssocArrayLiteralExp(e.loc, keysx, valuesx);
3412 newAA.type = xe.type;
3413 newAA.ownedByCtfe = OwnedBy.ctfe;
3414 //... and insert it into the existing AA.
3415 existingAA.keys.push(ekey);
3416 existingAA.values.push(newAA);
3424 oldval = findKeyInAA(e.loc, existingAA, lastIndex);
3426 oldval = copyLiteral(e.e1.type.defaultInitLiteral(e.loc)).copy();
3431 /* The AA is currently null. 'aggregate' is actually a reference to
3432 * whatever contains it. It could be anything: var, dotvarexp, ...
3433 * We rewrite the assignment from:
3434 * aa[i][j] op= newval;
3436 * aa = [i:[j:T.init]];
3439 oldval = copyLiteral(e.e1.type.defaultInitLiteral(e.loc)).copy();
3441 Expression newaae = oldval;
3442 while (e1.op == EXP.index && (cast(IndexExp)e1).e1.type.toBasetype().ty == Taarray)
3444 Expression ekey = interpretRegion((cast(IndexExp)e1).e2, istate);
3445 if (exceptionOrCant(ekey))
3447 ekey = resolveSlice(ekey); // only happens with AA assignment
3449 auto keysx = new Expressions();
3450 auto valuesx = new Expressions();
3452 valuesx.push(newaae);
3454 auto aae = ctfeEmplaceExp!AssocArrayLiteralExp(e.loc, keysx, valuesx);
3455 aae.type = (cast(IndexExp)e1).e1.type;
3456 aae.ownedByCtfe = OwnedBy.ctfe;
3463 e1 = (cast(IndexExp)e1).e1;
3466 // We must set to aggregate with newaae
3467 e1 = interpretRegion(e1, istate, CTFEGoal.LValue);
3468 if (exceptionOrCant(e1))
3470 e1 = assignToLvalue(e, e1, newaae);
3471 if (exceptionOrCant(e1))
3474 assert(existingAA && lastIndex);
3477 else if (e1.op == EXP.arrayLength)
3479 oldval = interpretRegion(e1, istate);
3480 if (exceptionOrCant(oldval))
3483 else if (e.op == EXP.construct || e.op == EXP.blit)
3485 // Unless we have a simple var assignment, we're
3486 // only modifying part of the variable. So we need to make sure
3487 // that the parent variable exists.
3488 VarDeclaration ultimateVar = findParentVar(e1);
3489 if (auto ve = e1.isVarExp())
3491 VarDeclaration v = ve.var.isVarDeclaration();
3493 if (v.storage_class & STC.out_)
3496 else if (ultimateVar && !getValue(ultimateVar))
3498 Expression ex = interpretRegion(ultimateVar.type.defaultInitLiteral(e.loc), istate);
3499 if (exceptionOrCant(ex))
3501 setValue(ultimateVar, ex);
3509 e1 = interpretRegion(e1, istate, CTFEGoal.LValue);
3510 if (exceptionOrCant(e1))
3513 if (e1.op == EXP.index && (cast(IndexExp)e1).e1.type.toBasetype().ty == Taarray)
3515 IndexExp ie = cast(IndexExp)e1;
3516 assert(ie.e1.op == EXP.assocArrayLiteral);
3517 existingAA = cast(AssocArrayLiteralExp)ie.e1;
3522 // ---------------------------------------
3523 // Interpret right hand side
3524 // ---------------------------------------
3525 Expression newval = interpretRegion(e.e2, istate);
3526 if (exceptionOrCant(newval))
3528 if (e.op == EXP.blit && newval.op == EXP.int64)
3530 Type tbn = e.type.baseElemOf();
3531 if (tbn.ty == Tstruct)
3533 /* Look for special case of struct being initialized with 0.
3535 newval = e.type.defaultInitLiteral(e.loc);
3536 if (newval.op == EXP.error)
3538 result = CTFEExp.cantexp;
3541 newval = interpretRegion(newval, istate); // copy and set ownedByCtfe flag
3542 if (exceptionOrCant(newval))
3547 // ----------------------------------------------------
3548 // Deal with read-modify-write assignments.
3549 // Set 'newval' to the final assignment value
3550 // Also determine the return value (except for slice
3551 // assignments, which are more complicated)
3552 // ----------------------------------------------------
3557 // Load the left hand side after interpreting the right hand side.
3558 oldval = interpretRegion(e1, istate);
3559 if (exceptionOrCant(oldval))
3563 if (e.e1.type.ty != Tpointer)
3565 // ~= can create new values (see bug 6052)
3566 if (e.op == EXP.concatenateAssign || e.op == EXP.concatenateElemAssign || e.op == EXP.concatenateDcharAssign)
3568 // We need to dup it and repaint the type. For a dynamic array
3569 // we can skip duplication, because it gets copied later anyway.
3570 if (newval.type.ty != Tarray)
3572 newval = copyLiteral(newval).copy();
3573 newval.type = e.e2.type; // repaint type
3577 newval = paintTypeOntoLiteral(e.e2.type, newval);
3578 newval = resolveSlice(newval);
3581 oldval = resolveSlice(oldval);
3583 newval = (*fp)(e.loc, e.type, oldval, newval).copy();
3585 else if (e.e2.type.isintegral() &&
3586 (e.op == EXP.addAssign ||
3587 e.op == EXP.minAssign ||
3588 e.op == EXP.plusPlus ||
3589 e.op == EXP.minusMinus))
3591 newval = pointerArithmetic(e.loc, e.op, e.type, oldval, newval).copy();
3595 e.error("pointer expression `%s` cannot be interpreted at compile time", e.toChars());
3596 result = CTFEExp.cantexp;
3599 if (exceptionOrCant(newval))
3601 if (CTFEExp.isCantExp(newval))
3602 e.error("cannot interpret `%s` at compile time", e.toChars());
3609 if (existingAA.ownedByCtfe != OwnedBy.ctfe)
3611 e.error("cannot modify read-only constant `%s`", existingAA.toChars());
3612 result = CTFEExp.cantexp;
3616 //printf("\t+L%d existingAA = %s, lastIndex = %s, oldval = %s, newval = %s\n",
3617 // __LINE__, existingAA.toChars(), lastIndex.toChars(), oldval ? oldval.toChars() : NULL, newval.toChars());
3618 assignAssocArrayElement(e.loc, existingAA, lastIndex, newval);
3620 // Determine the return value
3621 result = ctfeCast(pue, e.loc, e.type, e.type, fp && post ? oldval : newval);
3624 if (e1.op == EXP.arrayLength)
3626 /* Change the assignment from:
3629 * arr = new_length_array; (result is n)
3632 // Determine the return value
3633 result = ctfeCast(pue, e.loc, e.type, e.type, fp && post ? oldval : newval);
3634 if (exceptionOrCant(result))
3637 if (result == pue.exp())
3638 result = pue.copy();
3640 size_t oldlen = cast(size_t)oldval.toInteger();
3641 size_t newlen = cast(size_t)newval.toInteger();
3642 if (oldlen == newlen) // no change required -- we're done!
3645 // We have changed it into a reference assignment
3646 // Note that returnValue is still the new length.
3647 e1 = (cast(ArrayLengthExp)e1).e1;
3648 Type t = e1.type.toBasetype();
3651 e.error("`%s` is not yet supported at compile time", e.toChars());
3652 result = CTFEExp.cantexp;
3655 e1 = interpretRegion(e1, istate, CTFEGoal.LValue);
3656 if (exceptionOrCant(e1))
3659 if (oldlen != 0) // Get the old array literal.
3660 oldval = interpretRegion(e1, istate);
3661 UnionExp utmp = void;
3662 oldval = resolveSlice(oldval, &utmp);
3664 newval = changeArrayLiteralLength(e.loc, cast(TypeArray)t, oldval, oldlen, newlen).copy();
3666 e1 = assignToLvalue(e, e1, newval);
3667 if (exceptionOrCant(e1))
3673 if (!isBlockAssignment)
3675 newval = ctfeCast(pue, e.loc, e.type, e.type, newval);
3676 if (exceptionOrCant(newval))
3678 if (newval == pue.exp())
3679 newval = pue.copy();
3681 // Determine the return value
3682 if (goal == CTFEGoal.LValue) // https://issues.dlang.org/show_bug.cgi?id=14371
3686 result = ctfeCast(pue, e.loc, e.type, e.type, fp && post ? oldval : newval);
3687 if (result == pue.exp())
3688 result = pue.copy();
3690 if (exceptionOrCant(result))
3693 if (exceptionOrCant(newval))
3698 printf("ASSIGN: %s=%s\n", e1.toChars(), newval.toChars());
3699 showCtfeExpr(newval);
3702 /* Block assignment or element-wise assignment.
3704 if (e1.op == EXP.slice ||
3705 e1.op == EXP.vector ||
3706 e1.op == EXP.arrayLiteral ||
3707 e1.op == EXP.string_ ||
3708 e1.op == EXP.null_ && e1.type.toBasetype().ty == Tarray)
3710 // Note that slice assignments don't support things like ++, so
3711 // we don't need to remember 'returnValue'.
3712 result = interpretAssignToSlice(pue, e, e1, newval, isBlockAssignment);
3713 if (exceptionOrCant(result))
3715 if (auto se = e.e1.isSliceExp())
3717 Expression e1x = interpretRegion(se.e1, istate, CTFEGoal.LValue);
3718 if (auto dve = e1x.isDotVarExp())
3721 auto sle = ex.op == EXP.structLiteral ? (cast(StructLiteralExp)ex)
3722 : ex.op == EXP.classReference ? (cast(ClassReferenceExp)ex).value
3724 auto v = dve.var.isVarDeclaration();
3727 e.error("CTFE internal error: dotvar slice assignment");
3728 result = CTFEExp.cantexp;
3731 stompOverlappedFields(sle, v);
3738 /* Assignment to a CTFE reference.
3740 if (Expression ex = assignToLvalue(e, e1, newval))
3746 /* Set all sibling fields which overlap with v to VoidExp.
3748 private void stompOverlappedFields(StructLiteralExp sle, VarDeclaration v)
3752 foreach (size_t i, v2; sle.sd.fields)
3754 if (v is v2 || !v.isOverlappedWith(v2))
3756 auto e = (*sle.elements)[i];
3757 if (e.op != EXP.void_)
3758 (*sle.elements)[i] = voidInitLiteral(e.type, v).copy();
3762 private Expression assignToLvalue(BinExp e, Expression e1, Expression newval)
3764 //printf("assignToLvalue() e: %s e1: %s newval: %s\n", e.toChars(), e1.toChars(), newval.toChars());
3765 VarDeclaration vd = null;
3766 Expression* payload = null; // dead-store to prevent spurious warning
3769 if (auto ve = e1.isVarExp())
3771 vd = ve.var.isVarDeclaration();
3772 oldval = getValue(vd);
3774 else if (auto dve = e1.isDotVarExp())
3776 /* Assignment to member variable of the form:
3780 auto sle = ex.op == EXP.structLiteral ? (cast(StructLiteralExp)ex)
3781 : ex.op == EXP.classReference ? (cast(ClassReferenceExp)ex).value
3783 auto v = (cast(DotVarExp)e1).var.isVarDeclaration();
3786 e.error("CTFE internal error: dotvar assignment");
3787 return CTFEExp.cantexp;
3789 if (sle.ownedByCtfe != OwnedBy.ctfe)
3791 e.error("cannot modify read-only constant `%s`", sle.toChars());
3792 return CTFEExp.cantexp;
3795 int fieldi = ex.op == EXP.structLiteral ? findFieldIndexByName(sle.sd, v)
3796 : (cast(ClassReferenceExp)ex).findFieldIndexByName(v);
3799 e.error("CTFE internal error: cannot find field `%s` in `%s`", v.toChars(), ex.toChars());
3800 return CTFEExp.cantexp;
3802 assert(0 <= fieldi && fieldi < sle.elements.dim);
3804 // If it's a union, set all other members of this union to void
3805 stompOverlappedFields(sle, v);
3807 payload = &(*sle.elements)[fieldi];
3810 else if (auto ie = e1.isIndexExp())
3812 assert(ie.e1.type.toBasetype().ty != Taarray);
3814 Expression aggregate;
3815 uinteger_t indexToModify;
3816 if (!resolveIndexing(ie, istate, &aggregate, &indexToModify, true))
3818 return CTFEExp.cantexp;
3820 size_t index = cast(size_t)indexToModify;
3822 if (auto existingSE = aggregate.isStringExp())
3824 if (existingSE.ownedByCtfe != OwnedBy.ctfe)
3826 e.error("cannot modify read-only string literal `%s`", ie.e1.toChars());
3827 return CTFEExp.cantexp;
3829 existingSE.setCodeUnit(index, cast(dchar)newval.toInteger());
3832 if (aggregate.op != EXP.arrayLiteral)
3834 e.error("index assignment `%s` is not yet supported in CTFE ", e.toChars());
3835 return CTFEExp.cantexp;
3838 ArrayLiteralExp existingAE = cast(ArrayLiteralExp)aggregate;
3839 if (existingAE.ownedByCtfe != OwnedBy.ctfe)
3841 e.error("cannot modify read-only constant `%s`", existingAE.toChars());
3842 return CTFEExp.cantexp;
3845 payload = &(*existingAE.elements)[index];
3850 e.error("`%s` cannot be evaluated at compile time", e.toChars());
3851 return CTFEExp.cantexp;
3854 Type t1b = e1.type.toBasetype();
3855 bool wantCopy = t1b.baseElemOf().ty == Tstruct;
3857 if (auto ve = newval.isVectorExp())
3859 // Ensure ve is an array literal, and not a broadcast
3860 if (ve.e1.op == EXP.int64 || ve.e1.op == EXP.float64) // if broadcast
3863 Expression ex = interpretVectorToArray(&ue, ve);
3864 ve.e1 = (ex == ue.exp()) ? ue.copy() : ex;
3868 if (newval.op == EXP.structLiteral && oldval)
3870 assert(oldval.op == EXP.structLiteral || oldval.op == EXP.arrayLiteral || oldval.op == EXP.string_);
3871 newval = copyLiteral(newval).copy();
3872 assignInPlace(oldval, newval);
3874 else if (wantCopy && e.op == EXP.assign)
3876 // Currently postblit/destructor calls on static array are done
3877 // in the druntime internal functions so they don't appear in AST.
3878 // Therefore interpreter should handle them specially.
3881 version (all) // todo: instead we can directly access to each elements of the slice
3883 newval = resolveSlice(newval);
3884 if (CTFEExp.isCantExp(newval))
3886 e.error("CTFE internal error: assignment `%s`", e.toChars());
3887 return CTFEExp.cantexp;
3890 assert(oldval.op == EXP.arrayLiteral);
3891 assert(newval.op == EXP.arrayLiteral);
3893 Expressions* oldelems = (cast(ArrayLiteralExp)oldval).elements;
3894 Expressions* newelems = (cast(ArrayLiteralExp)newval).elements;
3895 assert(oldelems.dim == newelems.dim);
3897 Type elemtype = oldval.type.nextOf();
3898 foreach (i, ref oldelem; *oldelems)
3900 Expression newelem = paintTypeOntoLiteral(elemtype, (*newelems)[i]);
3901 // https://issues.dlang.org/show_bug.cgi?id=9245
3902 if (e.e2.isLvalue())
3904 if (Expression ex = evaluatePostblit(istate, newelem))
3907 // https://issues.dlang.org/show_bug.cgi?id=13661
3908 if (Expression ex = evaluateDtor(istate, oldelem))
3915 // e1 has its own payload, so we have to create a new literal.
3917 newval = copyLiteral(newval).copy();
3919 if (t1b.ty == Tsarray && e.op == EXP.construct && e.e2.isLvalue())
3921 // https://issues.dlang.org/show_bug.cgi?id=9245
3922 if (Expression ex = evaluatePostblit(istate, newval))
3930 setValue(vd, oldval);
3934 // Blit assignment should return the newly created value.
3935 if (e.op == EXP.blit)
3942 * Deal with assignments of the form:
3944 * dest[low..upp] = newval
3945 * where newval has already been interpreted
3947 * This could be a slice assignment or a block assignment, and
3948 * dest could be either an array literal, or a string.
3950 * Returns EXP.cantExpression on failure. If there are no errors,
3951 * it returns aggregate[low..upp], except that as an optimisation,
3952 * if goal == CTFEGoal.Nothing, it will return NULL
3954 private Expression interpretAssignToSlice(UnionExp* pue, BinExp e, Expression e1, Expression newval, bool isBlockAssignment)
3956 dinteger_t lowerbound;
3957 dinteger_t upperbound;
3958 dinteger_t firstIndex;
3960 Expression aggregate;
3962 if (auto se = e1.isSliceExp())
3964 // ------------------------------
3965 // aggregate[] = newval
3966 // aggregate[low..upp] = newval
3967 // ------------------------------
3968 version (all) // should be move in interpretAssignCommon as the evaluation of e1
3970 Expression oldval = interpretRegion(se.e1, istate);
3972 // Set the $ variable
3973 uinteger_t dollar = resolveArrayLength(oldval);
3976 Expression dollarExp = ctfeEmplaceExp!IntegerExp(e1.loc, dollar, Type.tsize_t);
3977 ctfeGlobals.stack.push(se.lengthVar);
3978 setValue(se.lengthVar, dollarExp);
3980 Expression lwr = interpretRegion(se.lwr, istate);
3981 if (exceptionOrCantInterpret(lwr))
3984 ctfeGlobals.stack.pop(se.lengthVar);
3987 Expression upr = interpretRegion(se.upr, istate);
3988 if (exceptionOrCantInterpret(upr))
3991 ctfeGlobals.stack.pop(se.lengthVar);
3995 ctfeGlobals.stack.pop(se.lengthVar); // $ is defined only in [L..U]
3998 lowerbound = lwr ? lwr.toInteger() : 0;
3999 upperbound = upr ? upr.toInteger() : dim;
4001 if (lowerbound < 0 || dim < upperbound)
4003 e.error("array bounds `[0..%llu]` exceeded in slice `[%llu..%llu]`",
4004 ulong(dim), ulong(lowerbound), ulong(upperbound));
4005 return CTFEExp.cantexp;
4009 firstIndex = lowerbound;
4011 if (auto oldse = aggregate.isSliceExp())
4013 // Slice of a slice --> change the bounds
4014 if (oldse.upr.toInteger() < upperbound + oldse.lwr.toInteger())
4016 e.error("slice `[%llu..%llu]` exceeds array bounds `[0..%llu]`",
4017 ulong(lowerbound), ulong(upperbound), oldse.upr.toInteger() - oldse.lwr.toInteger());
4018 return CTFEExp.cantexp;
4020 aggregate = oldse.e1;
4021 firstIndex = lowerbound + oldse.lwr.toInteger();
4026 if (auto ale = e1.isArrayLiteralExp())
4029 upperbound = ale.elements.dim;
4031 else if (auto se = e1.isStringExp())
4034 upperbound = se.len;
4036 else if (e1.op == EXP.null_)
4041 else if (VectorExp ve = e1.isVectorExp())
4043 // ve is not handled but a proper error message is returned
4044 // this is to prevent https://issues.dlang.org/show_bug.cgi?id=20042
4046 upperbound = ve.dim;
4052 firstIndex = lowerbound;
4054 if (upperbound == lowerbound)
4057 // For slice assignment, we check that the lengths match.
4058 if (!isBlockAssignment)
4060 const srclen = resolveArrayLength(newval);
4061 if (srclen != (upperbound - lowerbound))
4063 e.error("array length mismatch assigning `[0..%llu]` to `[%llu..%llu]`",
4064 ulong(srclen), ulong(lowerbound), ulong(upperbound));
4065 return CTFEExp.cantexp;
4069 if (auto existingSE = aggregate.isStringExp())
4071 if (existingSE.ownedByCtfe != OwnedBy.ctfe)
4073 e.error("cannot modify read-only string literal `%s`", existingSE.toChars());
4074 return CTFEExp.cantexp;
4077 if (auto se = newval.isSliceExp())
4080 const srclower = se.lwr.toInteger();
4081 const srcupper = se.upr.toInteger();
4083 if (aggregate == aggr2 &&
4084 lowerbound < srcupper && srclower < upperbound)
4086 e.error("overlapping slice assignment `[%llu..%llu] = [%llu..%llu]`",
4087 ulong(lowerbound), ulong(upperbound), ulong(srclower), ulong(srcupper));
4088 return CTFEExp.cantexp;
4090 version (all) // todo: instead we can directly access to each elements of the slice
4092 Expression orignewval = newval;
4093 newval = resolveSlice(newval);
4094 if (CTFEExp.isCantExp(newval))
4096 e.error("CTFE internal error: slice `%s`", orignewval.toChars());
4097 return CTFEExp.cantexp;
4100 assert(newval.op != EXP.slice);
4102 if (auto se = newval.isStringExp())
4104 sliceAssignStringFromString(existingSE, se, cast(size_t)firstIndex);
4107 if (auto ale = newval.isArrayLiteralExp())
4109 /* Mixed slice: it was initialized as a string literal.
4110 * Now a slice of it is being set with an array literal.
4112 sliceAssignStringFromArrayLiteral(existingSE, ale, cast(size_t)firstIndex);
4116 // String literal block slice assign
4117 const value = cast(dchar)newval.toInteger();
4118 foreach (i; 0 .. upperbound - lowerbound)
4120 existingSE.setCodeUnit(cast(size_t)(i + firstIndex), value);
4122 if (goal == CTFEGoal.Nothing)
4123 return null; // avoid creating an unused literal
4124 auto retslice = ctfeEmplaceExp!SliceExp(e.loc, existingSE,
4125 ctfeEmplaceExp!IntegerExp(e.loc, firstIndex, Type.tsize_t),
4126 ctfeEmplaceExp!IntegerExp(e.loc, firstIndex + upperbound - lowerbound, Type.tsize_t));
4127 retslice.type = e.type;
4128 return interpret(pue, retslice, istate);
4130 if (auto existingAE = aggregate.isArrayLiteralExp())
4132 if (existingAE.ownedByCtfe != OwnedBy.ctfe)
4134 e.error("cannot modify read-only constant `%s`", existingAE.toChars());
4135 return CTFEExp.cantexp;
4138 if (newval.op == EXP.slice && !isBlockAssignment)
4140 auto se = cast(SliceExp)newval;
4142 const srclower = se.lwr.toInteger();
4143 const srcupper = se.upr.toInteger();
4144 const wantCopy = (newval.type.toBasetype().nextOf().baseElemOf().ty == Tstruct);
4146 //printf("oldval = %p %s[%d..%u]\nnewval = %p %s[%llu..%llu] wantCopy = %d\n",
4147 // aggregate, aggregate.toChars(), lowerbound, upperbound,
4148 // aggr2, aggr2.toChars(), srclower, srcupper, wantCopy);
4151 // Currently overlapping for struct array is allowed.
4152 // The order of elements processing depends on the overlapping.
4153 // https://issues.dlang.org/show_bug.cgi?id=14024
4154 assert(aggr2.op == EXP.arrayLiteral);
4155 Expressions* oldelems = existingAE.elements;
4156 Expressions* newelems = (cast(ArrayLiteralExp)aggr2).elements;
4158 Type elemtype = aggregate.type.nextOf();
4159 bool needsPostblit = e.e2.isLvalue();
4161 if (aggregate == aggr2 && srclower < lowerbound && lowerbound < srcupper)
4164 for (auto i = upperbound - lowerbound; 0 < i--;)
4166 Expression oldelem = (*oldelems)[cast(size_t)(i + firstIndex)];
4167 Expression newelem = (*newelems)[cast(size_t)(i + srclower)];
4168 newelem = copyLiteral(newelem).copy();
4169 newelem.type = elemtype;
4172 if (Expression x = evaluatePostblit(istate, newelem))
4175 if (Expression x = evaluateDtor(istate, oldelem))
4177 (*oldelems)[cast(size_t)(lowerbound + i)] = newelem;
4183 for (auto i = 0; i < upperbound - lowerbound; i++)
4185 Expression oldelem = (*oldelems)[cast(size_t)(i + firstIndex)];
4186 Expression newelem = (*newelems)[cast(size_t)(i + srclower)];
4187 newelem = copyLiteral(newelem).copy();
4188 newelem.type = elemtype;
4191 if (Expression x = evaluatePostblit(istate, newelem))
4194 if (Expression x = evaluateDtor(istate, oldelem))
4196 (*oldelems)[cast(size_t)(lowerbound + i)] = newelem;
4201 return newval; // oldval?
4203 if (aggregate == aggr2 &&
4204 lowerbound < srcupper && srclower < upperbound)
4206 e.error("overlapping slice assignment `[%llu..%llu] = [%llu..%llu]`",
4207 ulong(lowerbound), ulong(upperbound), ulong(srclower), ulong(srcupper));
4208 return CTFEExp.cantexp;
4210 version (all) // todo: instead we can directly access to each elements of the slice
4212 Expression orignewval = newval;
4213 newval = resolveSlice(newval);
4214 if (CTFEExp.isCantExp(newval))
4216 e.error("CTFE internal error: slice `%s`", orignewval.toChars());
4217 return CTFEExp.cantexp;
4222 assert(newval.op != EXP.slice);
4224 if (newval.op == EXP.string_ && !isBlockAssignment)
4226 /* Mixed slice: it was initialized as an array literal of chars/integers.
4227 * Now a slice of it is being set with a string.
4229 sliceAssignArrayLiteralFromString(existingAE, cast(StringExp)newval, cast(size_t)firstIndex);
4232 if (newval.op == EXP.arrayLiteral && !isBlockAssignment)
4234 Expressions* oldelems = existingAE.elements;
4235 Expressions* newelems = (cast(ArrayLiteralExp)newval).elements;
4236 Type elemtype = existingAE.type.nextOf();
4237 bool needsPostblit = e.op != EXP.blit && e.e2.isLvalue();
4238 foreach (j, newelem; *newelems)
4240 newelem = paintTypeOntoLiteral(elemtype, newelem);
4243 Expression x = evaluatePostblit(istate, newelem);
4244 if (exceptionOrCantInterpret(x))
4247 (*oldelems)[cast(size_t)(j + firstIndex)] = newelem;
4252 /* Block assignment, initialization of static arrays
4254 * x may be a multidimensional static array. (Note that this
4255 * only happens with array literals, never with strings).
4257 struct RecursiveBlock
4265 extern (C++) Expression assignTo(ArrayLiteralExp ae)
4267 return assignTo(ae, 0, ae.elements.dim);
4270 extern (C++) Expression assignTo(ArrayLiteralExp ae, size_t lwr, size_t upr)
4272 Expressions* w = ae.elements;
4273 assert(ae.type.ty == Tsarray || ae.type.ty == Tarray);
4274 bool directblk = (cast(TypeArray)ae.type).next.equivalent(newval.type);
4275 for (size_t k = lwr; k < upr; k++)
4277 if (!directblk && (*w)[k].op == EXP.arrayLiteral)
4279 // Multidimensional array block assign
4280 if (Expression ex = assignTo(cast(ArrayLiteralExp)(*w)[k]))
4287 else if (!needsPostblit && !needsDtor)
4289 assignInPlace((*w)[k], newval);
4293 Expression oldelem = (*w)[k];
4294 Expression tmpelem = needsDtor ? copyLiteral(oldelem).copy() : null;
4295 assignInPlace(oldelem, newval);
4298 if (Expression ex = evaluatePostblit(istate, oldelem))
4303 // https://issues.dlang.org/show_bug.cgi?id=14860
4304 if (Expression ex = evaluateDtor(istate, tmpelem))
4313 Type tn = newval.type.toBasetype();
4314 bool wantRef = (tn.ty == Tarray || isAssocArray(tn) || tn.ty == Tclass);
4315 bool cow = newval.op != EXP.structLiteral && newval.op != EXP.arrayLiteral && newval.op != EXP.string_;
4316 Type tb = tn.baseElemOf();
4317 StructDeclaration sd = (tb.ty == Tstruct ? (cast(TypeStruct)tb).sym : null);
4322 rb.refCopy = wantRef || cow;
4323 rb.needsPostblit = sd && sd.postblit && e.op != EXP.blit && e.e2.isLvalue();
4324 rb.needsDtor = sd && sd.dtor && e.op == EXP.assign;
4325 if (Expression ex = rb.assignTo(existingAE, cast(size_t)lowerbound, cast(size_t)upperbound))
4328 if (goal == CTFEGoal.Nothing)
4329 return null; // avoid creating an unused literal
4330 auto retslice = ctfeEmplaceExp!SliceExp(e.loc, existingAE,
4331 ctfeEmplaceExp!IntegerExp(e.loc, firstIndex, Type.tsize_t),
4332 ctfeEmplaceExp!IntegerExp(e.loc, firstIndex + upperbound - lowerbound, Type.tsize_t));
4333 retslice.type = e.type;
4334 return interpret(pue, retslice, istate);
4337 e.error("slice operation `%s = %s` cannot be evaluated at compile time", e1.toChars(), newval.toChars());
4338 return CTFEExp.cantexp;
4341 override void visit(AssignExp e)
4343 interpretAssignCommon(e, null);
4346 override void visit(BinAssignExp e)
4351 interpretAssignCommon(e, &Add);
4355 interpretAssignCommon(e, &Min);
4358 case EXP.concatenateAssign:
4359 case EXP.concatenateElemAssign:
4360 case EXP.concatenateDcharAssign:
4361 interpretAssignCommon(e, &ctfeCat);
4365 interpretAssignCommon(e, &Mul);
4369 interpretAssignCommon(e, &Div);
4373 interpretAssignCommon(e, &Mod);
4376 case EXP.leftShiftAssign:
4377 interpretAssignCommon(e, &Shl);
4380 case EXP.rightShiftAssign:
4381 interpretAssignCommon(e, &Shr);
4384 case EXP.unsignedRightShiftAssign:
4385 interpretAssignCommon(e, &Ushr);
4389 interpretAssignCommon(e, &And);
4393 interpretAssignCommon(e, &Or);
4397 interpretAssignCommon(e, &Xor);
4401 interpretAssignCommon(e, &Pow);
4409 override void visit(PostExp e)
4413 printf("%s PostExp::interpret() %s\n", e.loc.toChars(), e.toChars());
4415 if (e.op == EXP.plusPlus)
4416 interpretAssignCommon(e, &Add, 1);
4418 interpretAssignCommon(e, &Min, 1);
4421 if (CTFEExp.isCantExp(result))
4422 printf("PostExp::interpret() CANT\n");
4426 /* Return 1 if e is a p1 > p2 or p1 >= p2 pointer comparison;
4427 * -1 if e is a p1 < p2 or p1 <= p2 pointer comparison;
4430 static int isPointerCmpExp(Expression e, Expression* p1, Expression* p2)
4433 while (e.op == EXP.not)
4436 e = (cast(NotExp)e).e1;
4441 case EXP.lessOrEqual:
4443 goto case; /+ fall through +/
4444 case EXP.greaterThan:
4445 case EXP.greaterOrEqual:
4446 *p1 = (cast(BinExp)e).e1;
4447 *p2 = (cast(BinExp)e).e2;
4448 if (!(isPointer((*p1).type) && isPointer((*p2).type)))
4459 /** If this is a four pointer relation, evaluate it, else return NULL.
4461 * This is an expression of the form (p1 > q1 && p2 < q2) or (p1 < q1 || p2 > q2)
4462 * where p1, p2 are expressions yielding pointers to memory block p,
4463 * and q1, q2 are expressions yielding pointers to memory block q.
4464 * This expression is valid even if p and q are independent memory
4465 * blocks and are therefore not normally comparable; the && form returns true
4466 * if [p1..p2] lies inside [q1..q2], and false otherwise; the || form returns
4467 * true if [p1..p2] lies outside [q1..q2], and false otherwise.
4469 * Within the expression, any ordering of p1, p2, q1, q2 is permissible;
4470 * the comparison operators can be any of >, <, <=, >=, provided that
4471 * both directions (p > q and p < q) are checked. Additionally the
4472 * relational sub-expressions can be negated, eg
4473 * (!(q1 < p1) && p2 <= q2) is valid.
4475 private void interpretFourPointerRelation(UnionExp* pue, BinExp e)
4477 assert(e.op == EXP.andAnd || e.op == EXP.orOr);
4479 /* It can only be an isInside expression, if both e1 and e2 are
4480 * directional pointer comparisons.
4481 * Note that this check can be made statically; it does not depends on
4482 * any runtime values. This allows a JIT implementation to compile a
4483 * special AndAndPossiblyInside, keeping the normal AndAnd case efficient.
4486 // Save the pointer expressions and the comparison directions,
4487 // so we can use them later.
4488 Expression p1 = null;
4489 Expression p2 = null;
4490 Expression p3 = null;
4491 Expression p4 = null;
4492 int dir1 = isPointerCmpExp(e.e1, &p1, &p2);
4493 int dir2 = isPointerCmpExp(e.e2, &p3, &p4);
4494 if (dir1 == 0 || dir2 == 0)
4500 //printf("FourPointerRelation %s\n", toChars());
4502 UnionExp ue1 = void;
4503 UnionExp ue2 = void;
4504 UnionExp ue3 = void;
4505 UnionExp ue4 = void;
4507 // Evaluate the first two pointers
4508 p1 = interpret(&ue1, p1, istate);
4509 if (exceptionOrCant(p1))
4511 p2 = interpret(&ue2, p2, istate);
4512 if (exceptionOrCant(p2))
4514 dinteger_t ofs1, ofs2;
4515 Expression agg1 = getAggregateFromPointer(p1, &ofs1);
4516 Expression agg2 = getAggregateFromPointer(p2, &ofs2);
4518 if (!pointToSameMemoryBlock(agg1, agg2) && agg1.op != EXP.null_ && agg2.op != EXP.null_)
4520 // Here it is either CANT_INTERPRET,
4521 // or an IsInside comparison returning false.
4522 p3 = interpret(&ue3, p3, istate);
4523 if (CTFEExp.isCantExp(p3))
4525 // Note that it is NOT legal for it to throw an exception!
4526 Expression except = null;
4527 if (exceptionOrCantInterpret(p3))
4531 p4 = interpret(&ue4, p4, istate);
4532 if (CTFEExp.isCantExp(p4))
4537 if (exceptionOrCantInterpret(p4))
4542 e.error("comparison `%s` of pointers to unrelated memory blocks remains indeterminate at compile time because exception `%s` was thrown while evaluating `%s`", e.e1.toChars(), except.toChars(), e.e2.toChars());
4543 result = CTFEExp.cantexp;
4546 dinteger_t ofs3, ofs4;
4547 Expression agg3 = getAggregateFromPointer(p3, &ofs3);
4548 Expression agg4 = getAggregateFromPointer(p4, &ofs4);
4549 // The valid cases are:
4550 // p1 > p2 && p3 > p4 (same direction, also for < && <)
4551 // p1 > p2 && p3 < p4 (different direction, also < && >)
4552 // Changing any > into >= doesn't affect the result
4553 if ((dir1 == dir2 && pointToSameMemoryBlock(agg1, agg4) && pointToSameMemoryBlock(agg2, agg3)) ||
4554 (dir1 != dir2 && pointToSameMemoryBlock(agg1, agg3) && pointToSameMemoryBlock(agg2, agg4)))
4556 // it's a legal two-sided comparison
4557 emplaceExp!(IntegerExp)(pue, e.loc, (e.op == EXP.andAnd) ? 0 : 1, e.type);
4561 // It's an invalid four-pointer comparison. Either the second
4562 // comparison is in the same direction as the first, or else
4563 // more than two memory blocks are involved (either two independent
4564 // invalid comparisons are present, or else agg3 == agg4).
4565 e.error("comparison `%s` of pointers to unrelated memory blocks is indeterminate at compile time, even when combined with `%s`.", e.e1.toChars(), e.e2.toChars());
4566 result = CTFEExp.cantexp;
4569 // The first pointer expression didn't need special treatment, so we
4570 // we need to interpret the entire expression exactly as a normal && or ||.
4571 // This is easy because we haven't evaluated e2 at all yet, and we already
4572 // know it will return a bool.
4573 // But we mustn't evaluate the pointer expressions in e1 again, in case
4574 // they have side-effects.
4576 Expression ex = e.e1;
4579 if (auto ne = ex.isNotExp())
4588 /** Negate relational operator, eg >= becomes <
4590 * op = comparison operator to negate
4594 static EXP negateRelation(EXP op) pure
4598 case EXP.greaterOrEqual: op = EXP.lessThan; break;
4599 case EXP.greaterThan: op = EXP.lessOrEqual; break;
4600 case EXP.lessOrEqual: op = EXP.greaterThan; break;
4601 case EXP.lessThan: op = EXP.greaterOrEqual; break;
4607 const EXP cmpop = nott ? negateRelation(ex.op) : ex.op;
4608 const cmp = comparePointers(cmpop, agg1, ofs1, agg2, ofs2);
4609 // We already know this is a valid comparison.
4611 if (e.op == EXP.andAnd && cmp == 1 || e.op == EXP.orOr && cmp == 0)
4613 result = interpret(pue, e.e2, istate);
4616 emplaceExp!(IntegerExp)(pue, e.loc, (e.op == EXP.andAnd) ? 0 : 1, e.type);
4620 override void visit(LogicalExp e)
4624 printf("%s LogicalExp::interpret() %s\n", e.loc.toChars(), e.toChars());
4626 // Check for an insidePointer expression, evaluate it if so
4627 interpretFourPointerRelation(pue, e);
4631 UnionExp ue1 = void;
4632 result = interpret(&ue1, e.e1, istate);
4633 if (exceptionOrCant(result))
4637 const andand = e.op == EXP.andAnd;
4638 if (andand ? result.toBool().hasValue(false) : isTrueBool(result))
4640 else if (andand ? isTrueBool(result) : result.toBool().hasValue(false))
4642 UnionExp ue2 = void;
4643 result = interpret(&ue2, e.e2, istate);
4644 if (exceptionOrCant(result))
4646 if (result.op == EXP.voidExpression)
4648 assert(e.type.ty == Tvoid);
4652 if (result.toBool().hasValue(false))
4654 else if (isTrueBool(result))
4658 e.error("`%s` does not evaluate to a `bool`", result.toChars());
4659 result = CTFEExp.cantexp;
4665 e.error("`%s` cannot be interpreted as a `bool`", result.toChars());
4666 result = CTFEExp.cantexp;
4669 incUsageCtfe(istate, e.e2.loc);
4671 if (goal != CTFEGoal.Nothing)
4673 if (e.type.equals(Type.tbool))
4674 result = IntegerExp.createBool(res);
4677 emplaceExp!(IntegerExp)(pue, e.loc, res, e.type);
4684 // Print a stack trace, starting from callingExp which called fd.
4685 // To shorten the stack trace, try to detect recursion.
4686 private void showCtfeBackTrace(CallExp callingExp, FuncDeclaration fd)
4688 if (ctfeGlobals.stackTraceCallsToSuppress > 0)
4690 --ctfeGlobals.stackTraceCallsToSuppress;
4693 errorSupplemental(callingExp.loc, "called from here: `%s`", callingExp.toChars());
4694 // Quit if it's not worth trying to compress the stack trace
4695 if (ctfeGlobals.callDepth < 6 || global.params.verbose)
4697 // Recursion happens if the current function already exists in the call stack.
4698 int numToSuppress = 0;
4699 int recurseCount = 0;
4701 InterState* lastRecurse = istate;
4702 for (InterState* cur = istate; cur; cur = cur.caller)
4707 numToSuppress = depthSoFar;
4712 // We need at least three calls to the same function, to make compression worthwhile
4713 if (recurseCount < 2)
4715 // We found a useful recursion. Print all the calls involved in the recursion
4716 errorSupplemental(fd.loc, "%d recursive calls to function `%s`", recurseCount, fd.toChars());
4717 for (InterState* cur = istate; cur.fd != fd; cur = cur.caller)
4719 errorSupplemental(cur.fd.loc, "recursively called from function `%s`", cur.fd.toChars());
4721 // We probably didn't enter the recursion in this function.
4722 // Go deeper to find the real beginning.
4723 InterState* cur = istate;
4724 while (lastRecurse.caller && cur.fd == lastRecurse.caller.fd)
4727 lastRecurse = lastRecurse.caller;
4730 ctfeGlobals.stackTraceCallsToSuppress = numToSuppress;
4733 override void visit(CallExp e)
4737 printf("%s CallExp::interpret() %s\n", e.loc.toChars(), e.toChars());
4739 Expression pthis = null;
4740 FuncDeclaration fd = null;
4742 Expression ecall = interpretRegion(e.e1, istate);
4743 if (exceptionOrCant(ecall))
4746 if (auto dve = ecall.isDotVarExp())
4748 // Calling a member function
4750 fd = dve.var.isFuncDeclaration();
4753 if (auto dte = pthis.isDotTypeExp())
4756 else if (auto ve = ecall.isVarExp())
4758 fd = ve.var.isFuncDeclaration();
4761 // If `_d_HookTraceImpl` is found, resolve the underlying hook and replace `e` and `fd` with it.
4762 removeHookTraceImpl(e, fd);
4764 if (fd.ident == Id.__ArrayPostblit || fd.ident == Id.__ArrayDtor)
4766 assert(e.arguments.dim == 1);
4767 Expression ea = (*e.arguments)[0];
4768 // printf("1 ea = %s %s\n", ea.type.toChars(), ea.toChars());
4769 if (auto se = ea.isSliceExp())
4771 if (auto ce = ea.isCastExp())
4774 // printf("2 ea = %s, %s %s\n", ea.type.toChars(), EXPtoString(ea.op).ptr, ea.toChars());
4775 if (ea.op == EXP.variable || ea.op == EXP.symbolOffset)
4776 result = getVarExp(e.loc, istate, (cast(SymbolExp)ea).var, CTFEGoal.RValue);
4777 else if (auto ae = ea.isAddrExp())
4778 result = interpretRegion(ae.e1, istate);
4780 // https://issues.dlang.org/show_bug.cgi?id=18871
4781 // https://issues.dlang.org/show_bug.cgi?id=18819
4782 else if (auto ale = ea.isArrayLiteralExp())
4783 result = interpretRegion(ale, istate);
4787 if (CTFEExp.isCantExp(result))
4790 if (fd.ident == Id.__ArrayPostblit)
4791 result = evaluatePostblit(istate, result);
4793 result = evaluateDtor(istate, result);
4795 result = CTFEExp.voidexp;
4798 else if (fd.ident == Id._d_arraysetlengthT)
4800 // In expressionsem.d `ea.length = eb;` got lowered to `_d_arraysetlengthT(ea, eb);`.
4801 // The following code will rewrite it back to `ea.length = eb` and then interpret that expression.
4802 assert(e.arguments.dim == 2);
4804 Expression ea = (*e.arguments)[0];
4805 Expression eb = (*e.arguments)[1];
4807 auto ale = ctfeEmplaceExp!ArrayLengthExp(e.loc, ea);
4808 ale.type = Type.tsize_t;
4809 AssignExp ae = ctfeEmplaceExp!AssignExp(e.loc, ale, eb);
4812 // if (global.params.verbose)
4813 // message("interpret %s =>\n %s", e.toChars(), ae.toChars());
4814 result = interpretRegion(ae, istate);
4817 else if (fd.ident == Id._d_arrayctor || fd.ident == Id._d_arraysetctor)
4819 // In expressionsem.d `T[x] ea = eb;` was lowered to `_d_array{,set}ctor(ea[], eb[]);`.
4820 // The following code will rewrite it back to `ea = eb` and then interpret that expression.
4821 if (fd.ident == Id._d_arraysetctor)
4822 assert(e.arguments.dim == 2);
4824 assert(e.arguments.dim == 3);
4826 Expression ea = (*e.arguments)[0];
4828 ea = ea.isCastExp.e1;
4830 Expression eb = (*e.arguments)[1];
4831 if (eb.isCastExp && fd.ident == Id._d_arrayctor)
4832 eb = eb.isCastExp.e1;
4834 ConstructExp ce = new ConstructExp(e.loc, ea, eb);
4837 result = interpret(ce, istate);
4841 else if (auto soe = ecall.isSymOffExp())
4843 fd = soe.var.isFuncDeclaration();
4844 assert(fd && soe.offset == 0);
4846 else if (auto de = ecall.isDelegateExp())
4848 // Calling a delegate
4852 // Special handling for: &nestedfunc --> DelegateExp(VarExp(nestedfunc), nestedfunc)
4853 if (auto ve = pthis.isVarExp())
4855 pthis = null; // context is not necessary for CTFE
4857 else if (auto fe = ecall.isFuncExp())
4859 // Calling a delegate literal
4864 // delegate.funcptr()
4866 e.error("cannot call `%s` at compile time", e.toChars());
4867 result = CTFEExp.cantexp;
4872 e.error("CTFE internal error: cannot evaluate `%s` at compile time", e.toChars());
4873 result = CTFEExp.cantexp;
4878 // Member function call
4880 // Currently this is satisfied because closure is not yet supported.
4881 assert(!fd.isNested() || fd.needThis());
4883 if (pthis.op == EXP.typeid_)
4885 pthis.error("static variable `%s` cannot be read at compile time", pthis.toChars());
4886 result = CTFEExp.cantexp;
4891 if (pthis.op == EXP.null_)
4893 assert(pthis.type.toBasetype().ty == Tclass);
4894 e.error("function call through null class reference `%s`", pthis.toChars());
4895 result = CTFEExp.cantexp;
4899 assert(pthis.op == EXP.structLiteral || pthis.op == EXP.classReference || pthis.op == EXP.type);
4901 if (fd.isVirtual() && !e.directcall)
4903 // Make a virtual function call.
4904 // Get the function from the vtable of the original class
4905 ClassDeclaration cd = pthis.isClassReferenceExp().originalClass();
4907 // We can't just use the vtable index to look it up, because
4908 // vtables for interfaces don't get populated until the glue layer.
4909 fd = cd.findFunc(fd.ident, fd.type.isTypeFunction());
4914 if (fd && fd.semanticRun >= PASS.semantic3done && fd.semantic3Errors)
4916 e.error("CTFE failed because of previous errors in `%s`", fd.toChars());
4917 result = CTFEExp.cantexp;
4921 // Check for built-in functions
4922 result = evaluateIfBuiltin(pue, istate, e.loc, fd, e.arguments, pthis);
4928 e.error("`%s` cannot be interpreted at compile time, because it has no available source code", fd.toChars());
4929 result = CTFEExp.showcontext;
4933 result = interpretFunction(pue, fd, istate, e.arguments, pthis);
4934 if (result.op == EXP.voidExpression)
4936 if (!exceptionOrCantInterpret(result))
4938 if (goal != CTFEGoal.LValue) // Peel off CTFE reference if it's unnecessary
4940 if (result == pue.exp())
4941 result = pue.copy();
4942 result = interpret(pue, result, istate);
4945 if (!exceptionOrCantInterpret(result))
4947 result = paintTypeOntoLiteral(pue, e.type, result);
4950 else if (CTFEExp.isCantExp(result) && !global.gag)
4951 showCtfeBackTrace(e, fd); // Print a stack trace.
4954 override void visit(CommaExp e)
4958 printf("%s CommaExp::interpret() %s\n", e.loc.toChars(), e.toChars());
4961 // If it creates a variable, and there's no context for
4962 // the variable to be created in, we need to create one now.
4963 InterState istateComma;
4964 if (!istate && firstComma(e.e1).op == EXP.declaration)
4966 ctfeGlobals.stack.startFrame(null);
4967 istate = &istateComma;
4970 void endTempStackFrame()
4972 // If we created a temporary stack frame, end it now.
4973 if (istate == &istateComma)
4974 ctfeGlobals.stack.endFrame();
4977 result = CTFEExp.cantexp;
4979 // If the comma returns a temporary variable, it needs to be an lvalue
4980 // (this is particularly important for struct constructors)
4981 if (e.e1.op == EXP.declaration &&
4982 e.e2.op == EXP.variable &&
4983 e.e1.isDeclarationExp().declaration == e.e2.isVarExp().var &&
4984 e.e2.isVarExp().var.storage_class & STC.ctfe)
4986 VarExp ve = e.e2.isVarExp();
4987 VarDeclaration v = ve.var.isVarDeclaration();
4988 ctfeGlobals.stack.push(v);
4989 if (!v._init && !getValue(v))
4991 setValue(v, copyLiteral(v.type.defaultInitLiteral(e.loc)).copy());
4995 Expression newval = v._init.initializerToExpression();
4996 // Bug 4027. Copy constructors are a weird case where the
4997 // initializer is a void function (the variable is modified
4998 // through a reference parameter instead).
4999 newval = interpretRegion(newval, istate);
5000 if (exceptionOrCant(newval))
5001 return endTempStackFrame();
5002 if (newval.op != EXP.voidExpression)
5004 // v isn't necessarily null.
5005 setValueWithoutChecking(v, copyLiteral(newval).copy());
5012 auto e1 = interpret(&ue, e.e1, istate, CTFEGoal.Nothing);
5013 if (exceptionOrCant(e1))
5014 return endTempStackFrame();
5016 result = interpret(pue, e.e2, istate, goal);
5017 return endTempStackFrame();
5020 override void visit(CondExp e)
5024 printf("%s CondExp::interpret() %s\n", e.loc.toChars(), e.toChars());
5026 UnionExp uecond = void;
5028 econd = interpret(&uecond, e.econd, istate);
5029 if (exceptionOrCant(econd))
5032 if (isPointer(e.econd.type))
5034 if (econd.op != EXP.null_)
5036 econd = IntegerExp.createBool(true);
5040 if (isTrueBool(econd))
5042 result = interpret(pue, e.e1, istate, goal);
5043 incUsageCtfe(istate, e.e1.loc);
5045 else if (econd.toBool().hasValue(false))
5047 result = interpret(pue, e.e2, istate, goal);
5048 incUsageCtfe(istate, e.e2.loc);
5052 e.error("`%s` does not evaluate to boolean result at compile time", e.econd.toChars());
5053 result = CTFEExp.cantexp;
5057 override void visit(ArrayLengthExp e)
5061 printf("%s ArrayLengthExp::interpret() %s\n", e.loc.toChars(), e.toChars());
5064 Expression e1 = interpret(&ue1, e.e1, istate);
5066 if (exceptionOrCant(e1))
5068 if (e1.op != EXP.string_ && e1.op != EXP.arrayLiteral && e1.op != EXP.slice && e1.op != EXP.null_)
5070 e.error("`%s` cannot be evaluated at compile time", e.toChars());
5071 result = CTFEExp.cantexp;
5074 emplaceExp!(IntegerExp)(pue, e.loc, resolveArrayLength(e1), e.type);
5079 * Interpret the vector expression as an array literal.
5081 * pue = non-null pointer to temporary storage that can be used to store the return value
5082 * e = Expression to interpret
5084 * resulting array literal or 'e' if unable to interpret
5086 static Expression interpretVectorToArray(UnionExp* pue, VectorExp e)
5088 if (auto ale = e.e1.isArrayLiteralExp())
5089 return ale; // it's already an array literal
5090 if (e.e1.op == EXP.int64 || e.e1.op == EXP.float64)
5092 // Convert literal __vector(int) -> __vector([array])
5093 auto elements = new Expressions(e.dim);
5094 foreach (ref element; *elements)
5095 element = copyLiteral(e.e1).copy();
5096 auto type = (e.type.ty == Tvector) ? e.type.isTypeVector().basetype : e.type.isTypeSArray();
5098 emplaceExp!(ArrayLiteralExp)(pue, e.loc, type, elements);
5099 auto ale = pue.exp().isArrayLiteralExp();
5100 ale.ownedByCtfe = OwnedBy.ctfe;
5106 override void visit(VectorExp e)
5110 printf("%s VectorExp::interpret() %s\n", e.loc.toChars(), e.toChars());
5112 if (e.ownedByCtfe >= OwnedBy.ctfe) // We've already interpreted all the elements
5117 Expression e1 = interpret(pue, e.e1, istate);
5119 if (exceptionOrCant(e1))
5121 if (e1.op != EXP.arrayLiteral && e1.op != EXP.int64 && e1.op != EXP.float64)
5123 e.error("`%s` cannot be evaluated at compile time", e.toChars());
5124 result = CTFEExp.cantexp;
5127 if (e1 == pue.exp())
5129 emplaceExp!(VectorExp)(pue, e.loc, e1, e.to);
5130 auto ve = pue.exp().isVectorExp();
5133 ve.ownedByCtfe = OwnedBy.ctfe;
5137 override void visit(VectorArrayExp e)
5141 printf("%s VectorArrayExp::interpret() %s\n", e.loc.toChars(), e.toChars());
5143 Expression e1 = interpret(pue, e.e1, istate);
5145 if (exceptionOrCant(e1))
5147 if (auto ve = e1.isVectorExp())
5149 result = interpretVectorToArray(pue, ve);
5150 if (result.op != EXP.vector)
5153 e.error("`%s` cannot be evaluated at compile time", e.toChars());
5154 result = CTFEExp.cantexp;
5157 override void visit(DelegatePtrExp e)
5161 printf("%s DelegatePtrExp::interpret() %s\n", e.loc.toChars(), e.toChars());
5163 Expression e1 = interpret(pue, e.e1, istate);
5165 if (exceptionOrCant(e1))
5167 e.error("`%s` cannot be evaluated at compile time", e.toChars());
5168 result = CTFEExp.cantexp;
5171 override void visit(DelegateFuncptrExp e)
5175 printf("%s DelegateFuncptrExp::interpret() %s\n", e.loc.toChars(), e.toChars());
5177 Expression e1 = interpret(pue, e.e1, istate);
5179 if (exceptionOrCant(e1))
5181 e.error("`%s` cannot be evaluated at compile time", e.toChars());
5182 result = CTFEExp.cantexp;
5185 static bool resolveIndexing(IndexExp e, InterState* istate, Expression* pagg, uinteger_t* pidx, bool modify)
5187 assert(e.e1.type.toBasetype().ty != Taarray);
5189 if (e.e1.type.toBasetype().ty == Tpointer)
5191 // Indexing a pointer. Note that there is no $ in this case.
5192 Expression e1 = interpretRegion(e.e1, istate);
5193 if (exceptionOrCantInterpret(e1))
5196 Expression e2 = interpretRegion(e.e2, istate);
5197 if (exceptionOrCantInterpret(e2))
5199 sinteger_t indx = e2.toInteger();
5202 Expression agg = getAggregateFromPointer(e1, &ofs);
5204 if (agg.op == EXP.null_)
5206 e.error("cannot index through null pointer `%s`", e.e1.toChars());
5209 if (agg.op == EXP.int64)
5211 e.error("cannot index through invalid pointer `%s` of value `%s`", e.e1.toChars(), e1.toChars());
5214 // Pointer to a non-array variable
5215 if (agg.op == EXP.symbolOffset)
5217 e.error("mutable variable `%s` cannot be %s at compile time, even through a pointer", cast(char*)(modify ? "modified" : "read"), (cast(SymOffExp)agg).var.toChars());
5221 if (agg.op == EXP.arrayLiteral || agg.op == EXP.string_)
5223 dinteger_t len = resolveArrayLength(agg);
5224 if (ofs + indx >= len)
5226 e.error("pointer index `[%lld]` exceeds allocated memory block `[0..%lld]`", ofs + indx, len);
5232 if (ofs + indx != 0)
5234 e.error("pointer index `[%lld]` lies outside memory block `[0..1]`", ofs + indx);
5243 Expression e1 = interpretRegion(e.e1, istate);
5244 if (exceptionOrCantInterpret(e1))
5246 if (e1.op == EXP.null_)
5248 e.error("cannot index null array `%s`", e.e1.toChars());
5251 if (auto ve = e1.isVectorExp())
5254 e1 = interpretVectorToArray(&ue, ve);
5255 e1 = (e1 == ue.exp()) ? ue.copy() : e1;
5258 // Set the $ variable, and find the array literal to modify
5260 if (e1.op == EXP.variable && e1.type.toBasetype().ty == Tsarray)
5261 len = e1.type.toBasetype().isTypeSArray().dim.toInteger();
5264 if (e1.op != EXP.arrayLiteral && e1.op != EXP.string_ && e1.op != EXP.slice && e1.op != EXP.vector)
5266 e.error("cannot determine length of `%s` at compile time", e.e1.toChars());
5269 len = resolveArrayLength(e1);
5274 Expression dollarExp = ctfeEmplaceExp!IntegerExp(e.loc, len, Type.tsize_t);
5275 ctfeGlobals.stack.push(e.lengthVar);
5276 setValue(e.lengthVar, dollarExp);
5278 Expression e2 = interpretRegion(e.e2, istate);
5280 ctfeGlobals.stack.pop(e.lengthVar); // $ is defined only inside []
5281 if (exceptionOrCantInterpret(e2))
5283 if (e2.op != EXP.int64)
5285 e.error("CTFE internal error: non-integral index `[%s]`", e.e2.toChars());
5289 if (auto se = e1.isSliceExp())
5291 // Simplify index of slice: agg[lwr..upr][indx] --> agg[indx']
5292 uinteger_t index = e2.toInteger();
5293 uinteger_t ilwr = se.lwr.toInteger();
5294 uinteger_t iupr = se.upr.toInteger();
5296 if (index > iupr - ilwr)
5298 e.error("index %llu exceeds array length %llu", index, iupr - ilwr);
5301 *pagg = (cast(SliceExp)e1).e1;
5302 *pidx = index + ilwr;
5307 *pidx = e2.toInteger();
5310 e.error("array index %lld is out of bounds `[0..%lld]`", *pidx, len);
5317 override void visit(IndexExp e)
5321 printf("%s IndexExp::interpret() %s, goal = %d\n", e.loc.toChars(), e.toChars(), goal);
5323 if (e.e1.type.toBasetype().ty == Tpointer)
5326 uinteger_t indexToAccess;
5327 if (!resolveIndexing(e, istate, &agg, &indexToAccess, false))
5329 result = CTFEExp.cantexp;
5332 if (agg.op == EXP.arrayLiteral || agg.op == EXP.string_)
5334 if (goal == CTFEGoal.LValue)
5336 // if we need a reference, IndexExp shouldn't be interpreting
5337 // the expression to a value, it should stay as a reference
5338 emplaceExp!(IndexExp)(pue, e.loc, agg, ctfeEmplaceExp!IntegerExp(e.e2.loc, indexToAccess, e.e2.type));
5340 result.type = e.type;
5343 result = ctfeIndex(pue, e.loc, e.type, agg, indexToAccess);
5348 assert(indexToAccess == 0);
5349 result = interpretRegion(agg, istate, goal);
5350 if (exceptionOrCant(result))
5352 result = paintTypeOntoLiteral(pue, e.type, result);
5357 if (e.e1.type.toBasetype().ty == Taarray)
5359 Expression e1 = interpretRegion(e.e1, istate);
5360 if (exceptionOrCant(e1))
5362 if (e1.op == EXP.null_)
5364 if (goal == CTFEGoal.LValue && e1.type.ty == Taarray && e.modifiable)
5366 assert(0); // does not reach here?
5368 e.error("cannot index null array `%s`", e.e1.toChars());
5369 result = CTFEExp.cantexp;
5372 Expression e2 = interpretRegion(e.e2, istate);
5373 if (exceptionOrCant(e2))
5376 if (goal == CTFEGoal.LValue)
5378 // Pointer or reference of a scalar type
5379 if (e1 == e.e1 && e2 == e.e2)
5383 emplaceExp!(IndexExp)(pue, e.loc, e1, e2);
5385 result.type = e.type;
5390 assert(e1.op == EXP.assocArrayLiteral);
5391 UnionExp e2tmp = void;
5392 e2 = resolveSlice(e2, &e2tmp);
5393 result = findKeyInAA(e.loc, cast(AssocArrayLiteralExp)e1, e2);
5396 e.error("key `%s` not found in associative array `%s`", e2.toChars(), e.e1.toChars());
5397 result = CTFEExp.cantexp;
5403 uinteger_t indexToAccess;
5404 if (!resolveIndexing(e, istate, &agg, &indexToAccess, false))
5406 result = CTFEExp.cantexp;
5410 if (goal == CTFEGoal.LValue)
5412 Expression e2 = ctfeEmplaceExp!IntegerExp(e.e2.loc, indexToAccess, Type.tsize_t);
5413 emplaceExp!(IndexExp)(pue, e.loc, agg, e2);
5415 result.type = e.type;
5419 result = ctfeIndex(pue, e.loc, e.type, agg, indexToAccess);
5420 if (exceptionOrCant(result))
5422 if (result.op == EXP.void_)
5424 e.error("`%s` is used before initialized", e.toChars());
5425 errorSupplemental(result.loc, "originally uninitialized here");
5426 result = CTFEExp.cantexp;
5429 if (result == pue.exp())
5430 result = result.copy();
5433 override void visit(SliceExp e)
5437 printf("%s SliceExp::interpret() %s\n", e.loc.toChars(), e.toChars());
5439 if (e.e1.type.toBasetype().ty == Tpointer)
5441 // Slicing a pointer. Note that there is no $ in this case.
5442 Expression e1 = interpretRegion(e.e1, istate);
5443 if (exceptionOrCant(e1))
5445 if (e1.op == EXP.int64)
5447 e.error("cannot slice invalid pointer `%s` of value `%s`", e.e1.toChars(), e1.toChars());
5448 result = CTFEExp.cantexp;
5452 /* Evaluate lower and upper bounds of slice
5454 Expression lwr = interpretRegion(e.lwr, istate);
5455 if (exceptionOrCant(lwr))
5457 Expression upr = interpretRegion(e.upr, istate);
5458 if (exceptionOrCant(upr))
5460 uinteger_t ilwr = lwr.toInteger();
5461 uinteger_t iupr = upr.toInteger();
5464 Expression agg = getAggregateFromPointer(e1, &ofs);
5467 if (agg.op == EXP.null_)
5471 result = ctfeEmplaceExp!NullExp(e.loc);
5472 result.type = e.type;
5475 e.error("cannot slice null pointer `%s`", e.e1.toChars());
5476 result = CTFEExp.cantexp;
5479 if (agg.op == EXP.symbolOffset)
5481 e.error("slicing pointers to static variables is not supported in CTFE");
5482 result = CTFEExp.cantexp;
5485 if (agg.op != EXP.arrayLiteral && agg.op != EXP.string_)
5487 e.error("pointer `%s` cannot be sliced at compile time (it does not point to an array)", e.e1.toChars());
5488 result = CTFEExp.cantexp;
5491 assert(agg.op == EXP.arrayLiteral || agg.op == EXP.string_);
5492 dinteger_t len = ArrayLength(Type.tsize_t, agg).exp().toInteger();
5493 //Type *pointee = ((TypePointer *)agg.type)->next;
5494 if (iupr > (len + 1) || iupr < ilwr)
5496 e.error("pointer slice `[%lld..%lld]` exceeds allocated memory block `[0..%lld]`", ilwr, iupr, len);
5497 result = CTFEExp.cantexp;
5502 lwr = ctfeEmplaceExp!IntegerExp(e.loc, ilwr, lwr.type);
5503 upr = ctfeEmplaceExp!IntegerExp(e.loc, iupr, upr.type);
5505 emplaceExp!(SliceExp)(pue, e.loc, agg, lwr, upr);
5507 result.type = e.type;
5511 CTFEGoal goal1 = CTFEGoal.RValue;
5512 if (goal == CTFEGoal.LValue)
5514 if (e.e1.type.toBasetype().ty == Tsarray)
5515 if (auto ve = e.e1.isVarExp())
5516 if (auto vd = ve.var.isVarDeclaration())
5517 if (vd.storage_class & STC.ref_)
5518 goal1 = CTFEGoal.LValue;
5520 Expression e1 = interpret(e.e1, istate, goal1);
5521 if (exceptionOrCant(e1))
5526 result = paintTypeOntoLiteral(pue, e.type, e1);
5529 if (auto ve = e1.isVectorExp())
5531 e1 = interpretVectorToArray(pue, ve);
5532 e1 = (e1 == pue.exp()) ? pue.copy() : e1;
5535 /* Set dollar to the length of the array
5538 if ((e1.op == EXP.variable || e1.op == EXP.dotVariable) && e1.type.toBasetype().ty == Tsarray)
5539 dollar = e1.type.toBasetype().isTypeSArray().dim.toInteger();
5542 if (e1.op != EXP.arrayLiteral && e1.op != EXP.string_ && e1.op != EXP.null_ && e1.op != EXP.slice && e1.op != EXP.vector)
5544 e.error("cannot determine length of `%s` at compile time", e1.toChars());
5545 result = CTFEExp.cantexp;
5548 dollar = resolveArrayLength(e1);
5551 /* Set the $ variable
5555 auto dollarExp = ctfeEmplaceExp!IntegerExp(e.loc, dollar, Type.tsize_t);
5556 ctfeGlobals.stack.push(e.lengthVar);
5557 setValue(e.lengthVar, dollarExp);
5560 /* Evaluate lower and upper bounds of slice
5562 Expression lwr = interpretRegion(e.lwr, istate);
5563 if (exceptionOrCant(lwr))
5566 ctfeGlobals.stack.pop(e.lengthVar);
5569 Expression upr = interpretRegion(e.upr, istate);
5570 if (exceptionOrCant(upr))
5573 ctfeGlobals.stack.pop(e.lengthVar);
5577 ctfeGlobals.stack.pop(e.lengthVar); // $ is defined only inside [L..U]
5579 uinteger_t ilwr = lwr.toInteger();
5580 uinteger_t iupr = upr.toInteger();
5581 if (e1.op == EXP.null_)
5583 if (ilwr == 0 && iupr == 0)
5588 e1.error("slice `[%llu..%llu]` is out of bounds", ilwr, iupr);
5589 result = CTFEExp.cantexp;
5592 if (auto se = e1.isSliceExp())
5594 // Simplify slice of slice:
5595 // aggregate[lo1..up1][lwr..upr] ---> aggregate[lwr'..upr']
5596 uinteger_t lo1 = se.lwr.toInteger();
5597 uinteger_t up1 = se.upr.toInteger();
5598 if (ilwr > iupr || iupr > up1 - lo1)
5600 e.error("slice `[%llu..%llu]` exceeds array bounds `[%llu..%llu]`", ilwr, iupr, lo1, up1);
5601 result = CTFEExp.cantexp;
5606 emplaceExp!(SliceExp)(pue, e.loc, se.e1,
5607 ctfeEmplaceExp!IntegerExp(e.loc, ilwr, lwr.type),
5608 ctfeEmplaceExp!IntegerExp(e.loc, iupr, upr.type));
5610 result.type = e.type;
5613 if (e1.op == EXP.arrayLiteral || e1.op == EXP.string_)
5615 if (iupr < ilwr || dollar < iupr)
5617 e.error("slice `[%lld..%lld]` exceeds array bounds `[0..%lld]`", ilwr, iupr, dollar);
5618 result = CTFEExp.cantexp;
5622 emplaceExp!(SliceExp)(pue, e.loc, e1, lwr, upr);
5624 result.type = e.type;
5627 override void visit(InExp e)
5631 printf("%s InExp::interpret() %s\n", e.loc.toChars(), e.toChars());
5633 Expression e1 = interpretRegion(e.e1, istate);
5634 if (exceptionOrCant(e1))
5636 Expression e2 = interpretRegion(e.e2, istate);
5637 if (exceptionOrCant(e2))
5639 if (e2.op == EXP.null_)
5641 emplaceExp!(NullExp)(pue, e.loc, e.type);
5645 if (e2.op != EXP.assocArrayLiteral)
5647 e.error("`%s` cannot be interpreted at compile time", e.toChars());
5648 result = CTFEExp.cantexp;
5652 e1 = resolveSlice(e1);
5653 result = findKeyInAA(e.loc, cast(AssocArrayLiteralExp)e2, e1);
5654 if (exceptionOrCant(result))
5658 emplaceExp!(NullExp)(pue, e.loc, e.type);
5663 // Create a CTFE pointer &aa[index]
5664 result = ctfeEmplaceExp!IndexExp(e.loc, e2, e1);
5665 result.type = e.type.nextOf();
5666 emplaceExp!(AddrExp)(pue, e.loc, result, e.type);
5671 override void visit(CatExp e)
5675 printf("%s CatExp::interpret() %s\n", e.loc.toChars(), e.toChars());
5678 UnionExp ue1 = void;
5679 Expression e1 = interpret(&ue1, e.e1, istate);
5680 if (exceptionOrCant(e1))
5683 UnionExp ue2 = void;
5684 Expression e2 = interpret(&ue2, e.e2, istate);
5685 if (exceptionOrCant(e2))
5688 UnionExp e1tmp = void;
5689 e1 = resolveSlice(e1, &e1tmp);
5691 UnionExp e2tmp = void;
5692 e2 = resolveSlice(e2, &e2tmp);
5694 /* e1 and e2 can't go on the stack because of x~[y] and [x]~y will
5695 * result in [x,y] and then x or y is on the stack.
5696 * But if they are both strings, we can, because it isn't the x~[y] case.
5698 if (!(e1.op == EXP.string_ && e2.op == EXP.string_))
5700 if (e1 == ue1.exp())
5702 if (e2 == ue2.exp())
5706 *pue = ctfeCat(e.loc, e.type, e1, e2);
5709 if (CTFEExp.isCantExp(result))
5711 e.error("`%s` cannot be interpreted at compile time", e.toChars());
5714 // We know we still own it, because we interpreted both e1 and e2
5715 if (auto ale = result.isArrayLiteralExp())
5717 ale.ownedByCtfe = OwnedBy.ctfe;
5719 // https://issues.dlang.org/show_bug.cgi?id=14686
5720 foreach (elem; *ale.elements)
5722 Expression ex = evaluatePostblit(istate, elem);
5723 if (exceptionOrCant(ex))
5727 else if (auto se = result.isStringExp())
5728 se.ownedByCtfe = OwnedBy.ctfe;
5731 override void visit(DeleteExp e)
5735 printf("%s DeleteExp::interpret() %s\n", e.loc.toChars(), e.toChars());
5737 result = interpretRegion(e.e1, istate);
5738 if (exceptionOrCant(result))
5741 if (result.op == EXP.null_)
5743 result = CTFEExp.voidexp;
5747 auto tb = e.e1.type.toBasetype();
5751 if (result.op != EXP.classReference)
5753 e.error("`delete` on invalid class reference `%s`", result.toChars());
5754 result = CTFEExp.cantexp;
5758 auto cre = cast(ClassReferenceExp)result;
5759 auto cd = cre.originalClass();
5761 // Find dtor(s) in inheritance chain
5766 result = interpretFunction(pue, cd.dtor, istate, null, cre);
5767 if (exceptionOrCant(result))
5770 // Dtors of Non-extern(D) classes use implicit chaining (like structs)
5771 import dmd.aggregate : ClassKind;
5772 if (cd.classKind != ClassKind.d)
5776 // Emulate manual chaining as done in rt_finalize2
5779 } while (cd); // Stop after Object
5784 tb = (cast(TypePointer)tb).next.toBasetype();
5785 if (tb.ty == Tstruct)
5787 if (result.op != EXP.address ||
5788 (cast(AddrExp)result).e1.op != EXP.structLiteral)
5790 e.error("`delete` on invalid struct pointer `%s`", result.toChars());
5791 result = CTFEExp.cantexp;
5795 auto sd = (cast(TypeStruct)tb).sym;
5796 auto sle = cast(StructLiteralExp)(cast(AddrExp)result).e1;
5800 result = interpretFunction(pue, sd.dtor, istate, null, sle);
5801 if (exceptionOrCant(result))
5808 auto tv = tb.nextOf().baseElemOf();
5809 if (tv.ty == Tstruct)
5811 if (result.op != EXP.arrayLiteral)
5813 e.error("`delete` on invalid struct array `%s`", result.toChars());
5814 result = CTFEExp.cantexp;
5818 auto sd = (cast(TypeStruct)tv).sym;
5822 auto ale = cast(ArrayLiteralExp)result;
5823 foreach (el; *ale.elements)
5825 result = interpretFunction(pue, sd.dtor, istate, null, el);
5826 if (exceptionOrCant(result))
5836 result = CTFEExp.voidexp;
5839 override void visit(CastExp e)
5843 printf("%s CastExp::interpret() %s\n", e.loc.toChars(), e.toChars());
5845 Expression e1 = interpretRegion(e.e1, istate, goal);
5846 if (exceptionOrCant(e1))
5848 // If the expression has been cast to void, do nothing.
5849 if (e.to.ty == Tvoid)
5851 result = CTFEExp.voidexp;
5854 if (e.to.ty == Tpointer && e1.op != EXP.null_)
5856 Type pointee = (cast(TypePointer)e.type).next;
5857 // Implement special cases of normally-unsafe casts
5858 if (e1.op == EXP.int64)
5860 // Happens with Windows HANDLEs, for example.
5861 result = paintTypeOntoLiteral(pue, e.to, e1);
5865 bool castToSarrayPointer = false;
5866 bool castBackFromVoid = false;
5867 if (e1.type.ty == Tarray || e1.type.ty == Tsarray || e1.type.ty == Tpointer)
5869 // Check for unsupported type painting operations
5870 // For slices, we need the type being sliced,
5871 // since it may have already been type painted
5872 Type elemtype = e1.type.nextOf();
5873 if (auto se = e1.isSliceExp())
5874 elemtype = se.e1.type.nextOf();
5876 // Allow casts from X* to void *, and X** to void** for any X.
5877 // But don't allow cast from X* to void**.
5878 // So, we strip all matching * from source and target to find X.
5879 // Allow casts to X* from void* only if the 'void' was originally an X;
5880 // we check this later on.
5881 Type ultimatePointee = pointee;
5882 Type ultimateSrc = elemtype;
5883 while (ultimatePointee.ty == Tpointer && ultimateSrc.ty == Tpointer)
5885 ultimatePointee = ultimatePointee.nextOf();
5886 ultimateSrc = ultimateSrc.nextOf();
5888 if (ultimatePointee.ty == Tsarray && ultimatePointee.nextOf().equivalent(ultimateSrc))
5890 castToSarrayPointer = true;
5892 else if (ultimatePointee.ty != Tvoid && ultimateSrc.ty != Tvoid && !isSafePointerCast(elemtype, pointee))
5894 e.error("reinterpreting cast from `%s*` to `%s*` is not supported in CTFE", elemtype.toChars(), pointee.toChars());
5895 result = CTFEExp.cantexp;
5898 if (ultimateSrc.ty == Tvoid)
5899 castBackFromVoid = true;
5902 if (auto se = e1.isSliceExp())
5904 if (se.e1.op == EXP.null_)
5906 result = paintTypeOntoLiteral(pue, e.type, se.e1);
5909 // Create a CTFE pointer &aggregate[1..2]
5910 auto ei = ctfeEmplaceExp!IndexExp(e.loc, se.e1, se.lwr);
5911 ei.type = e.type.nextOf();
5912 emplaceExp!(AddrExp)(pue, e.loc, ei, e.type);
5916 if (e1.op == EXP.arrayLiteral || e1.op == EXP.string_)
5918 // Create a CTFE pointer &[1,2,3][0] or &"abc"[0]
5919 auto ei = ctfeEmplaceExp!IndexExp(e.loc, e1, ctfeEmplaceExp!IntegerExp(e.loc, 0, Type.tsize_t));
5920 ei.type = e.type.nextOf();
5921 emplaceExp!(AddrExp)(pue, e.loc, ei, e.type);
5925 if (e1.op == EXP.index && !(cast(IndexExp)e1).e1.type.equals(e1.type))
5927 // type painting operation
5928 IndexExp ie = cast(IndexExp)e1;
5929 if (castBackFromVoid)
5931 // get the original type. For strings, it's just the type...
5932 Type origType = ie.e1.type.nextOf();
5933 // ..but for arrays of type void*, it's the type of the element
5934 if (ie.e1.op == EXP.arrayLiteral && ie.e2.op == EXP.int64)
5936 ArrayLiteralExp ale = cast(ArrayLiteralExp)ie.e1;
5937 const indx = cast(size_t)ie.e2.toInteger();
5938 if (indx < ale.elements.dim)
5940 if (Expression xx = (*ale.elements)[indx])
5942 if (auto iex = xx.isIndexExp())
5943 origType = iex.e1.type.nextOf();
5944 else if (auto ae = xx.isAddrExp())
5945 origType = ae.e1.type;
5946 else if (auto ve = xx.isVarExp())
5947 origType = ve.var.type;
5951 if (!isSafePointerCast(origType, pointee))
5953 e.error("using `void*` to reinterpret cast from `%s*` to `%s*` is not supported in CTFE", origType.toChars(), pointee.toChars());
5954 result = CTFEExp.cantexp;
5958 emplaceExp!(IndexExp)(pue, e1.loc, ie.e1, ie.e2);
5960 result.type = e.type;
5964 if (auto ae = e1.isAddrExp())
5966 Type origType = ae.e1.type;
5967 if (isSafePointerCast(origType, pointee))
5969 emplaceExp!(AddrExp)(pue, e.loc, ae.e1, e.type);
5974 if (castToSarrayPointer && pointee.toBasetype().ty == Tsarray && ae.e1.op == EXP.index)
5977 dinteger_t dim = (cast(TypeSArray)pointee.toBasetype()).dim.toInteger();
5978 IndexExp ie = cast(IndexExp)ae.e1;
5979 Expression lwr = ie.e2;
5980 Expression upr = ctfeEmplaceExp!IntegerExp(ie.e2.loc, ie.e2.toInteger() + dim, Type.tsize_t);
5982 // Create a CTFE pointer &val[idx..idx+dim]
5983 auto er = ctfeEmplaceExp!SliceExp(e.loc, ie.e1, lwr, upr);
5985 emplaceExp!(AddrExp)(pue, e.loc, er, e.type);
5991 if (e1.op == EXP.variable || e1.op == EXP.symbolOffset)
5993 // type painting operation
5994 Type origType = (cast(SymbolExp)e1).var.type;
5995 if (castBackFromVoid && !isSafePointerCast(origType, pointee))
5997 e.error("using `void*` to reinterpret cast from `%s*` to `%s*` is not supported in CTFE", origType.toChars(), pointee.toChars());
5998 result = CTFEExp.cantexp;
6001 if (auto ve = e1.isVarExp())
6002 emplaceExp!(VarExp)(pue, e.loc, ve.var);
6004 emplaceExp!(SymOffExp)(pue, e.loc, (cast(SymOffExp)e1).var, (cast(SymOffExp)e1).offset);
6010 // Check if we have a null pointer (eg, inside a struct)
6011 e1 = interpretRegion(e1, istate);
6012 if (e1.op != EXP.null_)
6014 e.error("pointer cast from `%s` to `%s` is not supported at compile time", e1.type.toChars(), e.to.toChars());
6015 result = CTFEExp.cantexp;
6019 if (e.to.ty == Tsarray && e.e1.type.ty == Tvector)
6021 // Special handling for: cast(float[4])__vector([w, x, y, z])
6022 e1 = interpretRegion(e.e1, istate);
6023 if (exceptionOrCant(e1))
6025 assert(e1.op == EXP.vector);
6026 e1 = interpretVectorToArray(pue, e1.isVectorExp());
6028 if (e.to.ty == Tarray && e1.op == EXP.slice)
6030 // Note that the slice may be void[], so when checking for dangerous
6031 // casts, we need to use the original type, which is se.e1.
6032 SliceExp se = cast(SliceExp)e1;
6033 if (!isSafePointerCast(se.e1.type.nextOf(), e.to.nextOf()))
6035 e.error("array cast from `%s` to `%s` is not supported at compile time", se.e1.type.toChars(), e.to.toChars());
6036 result = CTFEExp.cantexp;
6039 emplaceExp!(SliceExp)(pue, e1.loc, se.e1, se.lwr, se.upr);
6044 // Disallow array type painting, except for conversions between built-in
6045 // types of identical size.
6046 if ((e.to.ty == Tsarray || e.to.ty == Tarray) && (e1.type.ty == Tsarray || e1.type.ty == Tarray) && !isSafePointerCast(e1.type.nextOf(), e.to.nextOf()))
6048 e.error("array cast from `%s` to `%s` is not supported at compile time", e1.type.toChars(), e.to.toChars());
6049 result = CTFEExp.cantexp;
6052 if (e.to.ty == Tsarray)
6053 e1 = resolveSlice(e1);
6055 auto tobt = e.to.toBasetype();
6056 if (tobt.ty == Tbool && e1.type.ty == Tpointer)
6058 emplaceExp!(IntegerExp)(pue, e.loc, e1.op != EXP.null_, e.to);
6062 else if (tobt.isTypeBasic() && e1.op == EXP.null_)
6064 if (tobt.isintegral())
6065 emplaceExp!(IntegerExp)(pue, e.loc, 0, e.to);
6066 else if (tobt.isreal())
6067 emplaceExp!(RealExp)(pue, e.loc, CTFloat.zero, e.to);
6071 result = ctfeCast(pue, e.loc, e.type, e.to, e1);
6074 override void visit(AssertExp e)
6078 printf("%s AssertExp::interpret() %s\n", e.loc.toChars(), e.toChars());
6080 Expression e1 = interpret(pue, e.e1, istate);
6081 if (exceptionOrCant(e1))
6086 else if (e1.toBool().hasValue(false))
6091 result = interpret(&ue, e.msg, istate);
6092 if (exceptionOrCant(result))
6094 e.error("`%s`", result.toChars());
6097 e.error("`%s` failed", e.toChars());
6098 result = CTFEExp.cantexp;
6103 e.error("`%s` is not a compile time boolean expression", e1.toChars());
6104 result = CTFEExp.cantexp;
6111 override void visit(PtrExp e)
6115 printf("%s PtrExp::interpret() %s\n", e.loc.toChars(), e.toChars());
6117 // Check for int<->float and long<->double casts.
6118 if (auto soe1 = e.e1.isSymOffExp())
6119 if (soe1.offset == 0 && soe1.var.isVarDeclaration() && isFloatIntPaint(e.type, soe1.var.type))
6121 // *(cast(int*)&v), where v is a float variable
6122 result = paintFloatInt(pue, getVarExp(e.loc, istate, soe1.var, CTFEGoal.RValue), e.type);
6126 if (auto ce1 = e.e1.isCastExp())
6127 if (auto ae11 = ce1.e1.isAddrExp())
6129 // *(cast(int*)&x), where x is a float expression
6130 Expression x = ae11.e1;
6131 if (isFloatIntPaint(e.type, x.type))
6133 result = paintFloatInt(pue, interpretRegion(x, istate), e.type);
6138 // Constant fold *(&structliteral + offset)
6139 if (auto ae = e.e1.isAddExp())
6141 if (ae.e1.op == EXP.address && ae.e2.op == EXP.int64)
6143 AddrExp ade = cast(AddrExp)ae.e1;
6144 Expression ex = interpretRegion(ade.e1, istate);
6145 if (exceptionOrCant(ex))
6147 if (auto se = ex.isStructLiteralExp())
6149 dinteger_t offset = ae.e2.toInteger();
6150 result = se.getField(e.type, cast(uint)offset);
6157 // It's possible we have an array bounds error. We need to make sure it
6158 // errors with this line number, not the one where the pointer was set.
6159 result = interpretRegion(e.e1, istate);
6160 if (exceptionOrCant(result))
6163 if (result.op == EXP.function_)
6165 if (auto soe = result.isSymOffExp())
6167 if (soe.offset == 0 && soe.var.isFuncDeclaration())
6169 e.error("cannot dereference pointer to static variable `%s` at compile time", soe.var.toChars());
6170 result = CTFEExp.cantexp;
6174 if (result.isStringExp())
6177 if (result.op != EXP.address)
6179 if (result.op == EXP.null_)
6180 e.error("dereference of null pointer `%s`", e.e1.toChars());
6182 e.error("dereference of invalid pointer `%s`", result.toChars());
6183 result = CTFEExp.cantexp;
6188 result = (cast(AddrExp)result).e1;
6190 if (result.op == EXP.slice && e.type.toBasetype().ty == Tsarray)
6193 * upr may exceed the upper boundary of aggr, but the check is deferred
6194 * until those out-of-bounds elements will be touched.
6198 result = interpret(pue, result, istate, goal);
6199 if (exceptionOrCant(result))
6204 if (CTFEExp.isCantExp(result))
6205 printf("PtrExp::interpret() %s = CTFEExp::cantexp\n", e.toChars());
6209 override void visit(DotVarExp e)
6211 void notImplementedYet()
6213 e.error("`%s.%s` is not yet implemented at compile time", e.e1.toChars(), e.var.toChars());
6214 result = CTFEExp.cantexp;
6220 printf("%s DotVarExp::interpret() %s, goal = %d\n", e.loc.toChars(), e.toChars(), goal);
6222 Expression ex = interpretRegion(e.e1, istate);
6223 if (exceptionOrCant(ex))
6226 if (FuncDeclaration f = e.var.isFuncDeclaration())
6229 result = e; // optimize: reuse this CTFE reference
6232 emplaceExp!(DotVarExp)(pue, e.loc, ex, f, false);
6234 result.type = e.type;
6239 VarDeclaration v = e.var.isVarDeclaration();
6242 e.error("CTFE internal error: `%s`", e.toChars());
6243 result = CTFEExp.cantexp;
6247 if (ex.op == EXP.null_)
6249 if (ex.type.toBasetype().ty == Tclass)
6250 e.error("class `%s` is `null` and cannot be dereferenced", e.e1.toChars());
6252 e.error("CTFE internal error: null this `%s`", e.e1.toChars());
6253 result = CTFEExp.cantexp;
6257 StructLiteralExp se;
6260 if (ex.op != EXP.structLiteral && ex.op != EXP.classReference && ex.op != EXP.typeid_)
6262 return notImplementedYet();
6265 // We can't use getField, because it makes a copy
6266 if (ex.op == EXP.classReference)
6268 se = (cast(ClassReferenceExp)ex).value;
6269 i = (cast(ClassReferenceExp)ex).findFieldIndexByName(v);
6271 else if (ex.op == EXP.typeid_)
6273 if (v.ident == Identifier.idPool("name"))
6275 if (auto t = isType(ex.isTypeidExp().obj))
6277 auto sym = t.toDsymbol(null);
6278 if (auto ident = (sym ? sym.ident : null))
6280 result = new StringExp(e.loc, ident.toString());
6281 result.expressionSemantic(null);
6286 return notImplementedYet();
6290 se = cast(StructLiteralExp)ex;
6291 i = findFieldIndexByName(se.sd, v);
6295 e.error("couldn't find field `%s` of type `%s` in `%s`", v.toChars(), e.type.toChars(), se.toChars());
6296 result = CTFEExp.cantexp;
6300 // https://issues.dlang.org/show_bug.cgi?id=19897
6301 // https://issues.dlang.org/show_bug.cgi?id=20710
6302 // Zero-elements fields don't have an initializer. See: scrubArray function
6303 if ((*se.elements)[i] is null)
6304 (*se.elements)[i] = voidInitLiteral(e.type, v).copy();
6306 if (goal == CTFEGoal.LValue)
6308 // just return the (simplified) dotvar expression as a CTFE reference
6313 emplaceExp!(DotVarExp)(pue, e.loc, ex, v);
6315 result.type = e.type;
6320 result = (*se.elements)[i];
6323 e.error("Internal Compiler Error: null field `%s`", v.toChars());
6324 result = CTFEExp.cantexp;
6327 if (auto vie = result.isVoidInitExp())
6329 const s = vie.var.toChars();
6332 e.error("reinterpretation through overlapped field `%s` is not allowed in CTFE", s);
6333 result = CTFEExp.cantexp;
6336 e.error("cannot read uninitialized variable `%s` in CTFE", s);
6337 result = CTFEExp.cantexp;
6341 if (v.type.ty != result.type.ty && v.type.ty == Tsarray)
6343 // Block assignment from inside struct literals
6344 auto tsa = cast(TypeSArray)v.type;
6345 auto len = cast(size_t)tsa.dim.toInteger();
6347 result = createBlockDuplicatedArrayLiteral(&ue, e.loc, v.type, result, len);
6348 if (result == ue.exp())
6350 (*se.elements)[i] = result;
6354 if (CTFEExp.isCantExp(result))
6355 printf("DotVarExp::interpret() %s = CTFEExp::cantexp\n", e.toChars());
6359 override void visit(RemoveExp e)
6363 printf("%s RemoveExp::interpret() %s\n", e.loc.toChars(), e.toChars());
6365 Expression agg = interpret(e.e1, istate);
6366 if (exceptionOrCant(agg))
6368 Expression index = interpret(e.e2, istate);
6369 if (exceptionOrCant(index))
6371 if (agg.op == EXP.null_)
6373 result = CTFEExp.voidexp;
6377 AssocArrayLiteralExp aae = agg.isAssocArrayLiteralExp();
6378 Expressions* keysx = aae.keys;
6379 Expressions* valuesx = aae.values;
6381 foreach (j, evalue; *valuesx)
6383 Expression ekey = (*keysx)[j];
6384 int eq = ctfeEqual(e.loc, EXP.equal, ekey, index);
6387 else if (removed != 0)
6389 (*keysx)[j - removed] = ekey;
6390 (*valuesx)[j - removed] = evalue;
6393 valuesx.dim = valuesx.dim - removed;
6394 keysx.dim = keysx.dim - removed;
6395 result = IntegerExp.createBool(removed != 0);
6398 override void visit(ClassReferenceExp e)
6400 //printf("ClassReferenceExp::interpret() %s\n", e.value.toChars());
6404 override void visit(VoidInitExp e)
6406 e.error("CTFE internal error: trying to read uninitialized variable");
6410 override void visit(ThrownExceptionExp e)
6412 assert(0); // This should never be interpreted
6416 /********************************************
6417 * Interpret the expression.
6419 * pue = non-null pointer to temporary storage that can be used to store the return value
6420 * e = Expression to interpret
6422 * goal = what the result will be used for
6424 * resulting expression
6427 Expression interpret(UnionExp* pue, Expression e, InterState* istate, CTFEGoal goal = CTFEGoal.RValue)
6431 scope Interpreter v = new Interpreter(pue, istate, goal);
6433 Expression ex = v.result;
6434 assert(goal == CTFEGoal.Nothing || ex !is null);
6439 Expression interpret(Expression e, InterState* istate, CTFEGoal goal = CTFEGoal.RValue)
6442 auto result = interpret(&ue, e, istate, goal);
6443 if (result == ue.exp())
6448 /*****************************
6449 * Same as interpret(), but return result allocated in Region.
6451 * e = Expression to interpret
6453 * goal = what the result will be used for
6455 * resulting expression
6457 Expression interpretRegion(Expression e, InterState* istate, CTFEGoal goal = CTFEGoal.RValue)
6460 auto result = interpret(&ue, e, istate, goal);
6461 auto uexp = ue.exp();
6464 if (mem.isGCEnabled)
6467 // mimicking UnionExp.copy, but with region allocation
6470 case EXP.cantExpression: return CTFEExp.cantexp;
6471 case EXP.voidExpression: return CTFEExp.voidexp;
6472 case EXP.break_: return CTFEExp.breakexp;
6473 case EXP.continue_: return CTFEExp.continueexp;
6474 case EXP.goto_: return CTFEExp.gotoexp;
6477 auto p = ctfeGlobals.region.malloc(uexp.size);
6478 return cast(Expression)memcpy(p, cast(void*)uexp, uexp.size);
6481 /***********************************
6482 * Interpret the statement.
6484 * pue = non-null pointer to temporary storage that can be used to store the return value
6485 * s = Statement to interpret
6488 * NULL continue to next statement
6489 * EXP.cantExpression cannot interpret statement at compile time
6490 * !NULL expression from return statement, or thrown exception
6492 Expression interpret(UnionExp* pue, Statement s, InterState* istate)
6496 scope Interpreter v = new Interpreter(pue, istate, CTFEGoal.Nothing);
6502 Expression interpret(Statement s, InterState* istate)
6505 auto result = interpret(&ue, s, istate);
6506 if (result == ue.exp())
6512 * All results destined for use outside of CTFE need to have their CTFE-specific
6515 * 1. all slices must be resolved.
6516 * 2. all .ownedByCtfe set to OwnedBy.code
6518 private Expression scrubReturnValue(const ref Loc loc, Expression e)
6520 /* Returns: true if e is void,
6521 * or is an array literal or struct literal of void elements.
6523 static bool isVoid(const Expression e, bool checkArrayType = false) pure
6525 if (e.op == EXP.void_)
6528 static bool isEntirelyVoid(const Expressions* elems)
6532 // It can be NULL for performance reasons,
6533 // see StructLiteralExp::interpret().
6534 if (e && !isVoid(e))
6540 if (auto sle = e.isStructLiteralExp())
6541 return isEntirelyVoid(sle.elements);
6543 if (checkArrayType && e.type.ty != Tsarray)
6546 if (auto ale = e.isArrayLiteralExp())
6547 return isEntirelyVoid(ale.elements);
6553 /* Scrub all elements of elems[].
6554 * Returns: null for success, error Expression for failure
6556 Expression scrubArray(Expressions* elems, bool structlit = false)
6558 foreach (ref e; *elems)
6560 // It can be NULL for performance reasons,
6561 // see StructLiteralExp::interpret().
6565 // A struct .init may contain void members.
6566 // Static array members are a weird special case https://issues.dlang.org/show_bug.cgi?id=10994
6567 if (structlit && isVoid(e, true))
6573 e = scrubReturnValue(loc, e);
6574 if (CTFEExp.isCantExp(e) || e.op == EXP.error)
6581 Expression scrubSE(StructLiteralExp sle)
6583 sle.ownedByCtfe = OwnedBy.code;
6584 if (!(sle.stageflags & stageScrub))
6586 const old = sle.stageflags;
6587 sle.stageflags |= stageScrub; // prevent infinite recursion
6588 if (auto ex = scrubArray(sle.elements, true))
6590 sle.stageflags = old;
6595 if (e.op == EXP.classReference)
6597 StructLiteralExp sle = (cast(ClassReferenceExp)e).value;
6598 if (auto ex = scrubSE(sle))
6601 else if (auto vie = e.isVoidInitExp())
6603 error(loc, "uninitialized variable `%s` cannot be returned from CTFE", vie.var.toChars());
6604 return ErrorExp.get();
6607 e = resolveSlice(e);
6609 if (auto sle = e.isStructLiteralExp())
6611 if (auto ex = scrubSE(sle))
6614 else if (auto se = e.isStringExp())
6616 se.ownedByCtfe = OwnedBy.code;
6618 else if (auto ale = e.isArrayLiteralExp())
6620 ale.ownedByCtfe = OwnedBy.code;
6621 if (auto ex = scrubArray(ale.elements))
6624 else if (auto aae = e.isAssocArrayLiteralExp())
6626 aae.ownedByCtfe = OwnedBy.code;
6627 if (auto ex = scrubArray(aae.keys))
6629 if (auto ex = scrubArray(aae.values))
6631 aae.type = toBuiltinAAType(aae.type);
6633 else if (auto ve = e.isVectorExp())
6635 ve.ownedByCtfe = OwnedBy.code;
6636 if (auto ale = ve.e1.isArrayLiteralExp())
6638 ale.ownedByCtfe = OwnedBy.code;
6639 if (auto ex = scrubArray(ale.elements))
6646 /**************************************
6647 * Transitively set all .ownedByCtfe to OwnedBy.cache
6649 private Expression scrubCacheValue(Expression e)
6654 Expression scrubArrayCache(Expressions* elems)
6656 foreach (ref e; *elems)
6657 e = scrubCacheValue(e);
6661 Expression scrubSE(StructLiteralExp sle)
6663 sle.ownedByCtfe = OwnedBy.cache;
6664 if (!(sle.stageflags & stageScrub))
6666 const old = sle.stageflags;
6667 sle.stageflags |= stageScrub; // prevent infinite recursion
6668 if (auto ex = scrubArrayCache(sle.elements))
6670 sle.stageflags = old;
6675 if (e.op == EXP.classReference)
6677 if (auto ex = scrubSE((cast(ClassReferenceExp)e).value))
6680 else if (auto sle = e.isStructLiteralExp())
6682 if (auto ex = scrubSE(sle))
6685 else if (auto se = e.isStringExp())
6687 se.ownedByCtfe = OwnedBy.cache;
6689 else if (auto ale = e.isArrayLiteralExp())
6691 ale.ownedByCtfe = OwnedBy.cache;
6692 if (Expression ex = scrubArrayCache(ale.elements))
6695 else if (auto aae = e.isAssocArrayLiteralExp())
6697 aae.ownedByCtfe = OwnedBy.cache;
6698 if (auto ex = scrubArrayCache(aae.keys))
6700 if (auto ex = scrubArrayCache(aae.values))
6703 else if (auto ve = e.isVectorExp())
6705 ve.ownedByCtfe = OwnedBy.cache;
6706 if (auto ale = ve.e1.isArrayLiteralExp())
6708 ale.ownedByCtfe = OwnedBy.cache;
6709 if (auto ex = scrubArrayCache(ale.elements))
6716 /********************************************
6717 * Transitively replace all Expressions allocated in ctfeGlobals.region
6718 * with Mem owned copies.
6720 * e = possible ctfeGlobals.region owned expression
6722 * Mem owned expression
6724 private Expression copyRegionExp(Expression e)
6729 static void copyArray(Expressions* elems)
6731 foreach (ref e; *elems)
6735 e = copyRegionExp(ex);
6739 static void copySE(StructLiteralExp sle)
6741 if (1 || !(sle.stageflags & stageScrub))
6743 const old = sle.stageflags;
6744 sle.stageflags |= stageScrub; // prevent infinite recursion
6745 copyArray(sle.elements);
6746 sle.stageflags = old;
6752 case EXP.classReference:
6754 auto cre = e.isClassReferenceExp();
6755 cre.value = copyRegionExp(cre.value).isStructLiteralExp();
6759 case EXP.structLiteral:
6761 auto sle = e.isStructLiteralExp();
6763 /* The following is to take care of updating sle.origin correctly,
6764 * which may have multiple objects pointing to it.
6766 if (sle.isOriginal && !ctfeGlobals.region.contains(cast(void*)sle.origin))
6768 /* This means sle has already been moved out of the region,
6769 * and sle.origin is the new location.
6774 sle.isOriginal = sle is sle.origin;
6776 auto slec = ctfeGlobals.region.contains(cast(void*)e)
6777 ? e.copy().isStructLiteralExp() // move sle out of region to slec
6780 if (ctfeGlobals.region.contains(cast(void*)sle.origin))
6782 auto sleo = sle.origin == sle ? slec : sle.origin.copy().isStructLiteralExp();
6789 case EXP.arrayLiteral:
6791 auto ale = e.isArrayLiteralExp();
6792 ale.basis = copyRegionExp(ale.basis);
6793 copyArray(ale.elements);
6797 case EXP.assocArrayLiteral:
6798 copyArray(e.isAssocArrayLiteralExp().keys);
6799 copyArray(e.isAssocArrayLiteralExp().values);
6804 auto se = e.isSliceExp();
6805 se.e1 = copyRegionExp(se.e1);
6806 se.upr = copyRegionExp(se.upr);
6807 se.lwr = copyRegionExp(se.lwr);
6813 auto te = e.isTupleExp();
6814 te.e0 = copyRegionExp(te.e0);
6822 case EXP.dotVariable:
6824 UnaExp ue = cast(UnaExp)e;
6825 ue.e1 = copyRegionExp(ue.e1);
6831 BinExp be = cast(BinExp)e;
6832 be.e1 = copyRegionExp(be.e1);
6833 be.e2 = copyRegionExp(be.e2);
6850 case EXP.symbolOffset:
6854 case EXP.cantExpression:
6855 case EXP.voidExpression:
6856 case EXP.showCtfeContext:
6860 printf("e: %s, %s\n", EXPtoString(e.op).ptr, e.toChars());
6864 if (ctfeGlobals.region.contains(cast(void*)e))
6871 /******************************* Special Functions ***************************/
6873 private Expression interpret_length(UnionExp* pue, InterState* istate, Expression earg)
6875 //printf("interpret_length()\n");
6876 earg = interpret(pue, earg, istate);
6877 if (exceptionOrCantInterpret(earg))
6880 if (auto aae = earg.isAssocArrayLiteralExp())
6883 assert(earg.op == EXP.null_);
6884 emplaceExp!(IntegerExp)(pue, earg.loc, len, Type.tsize_t);
6888 private Expression interpret_keys(UnionExp* pue, InterState* istate, Expression earg, Type returnType)
6892 printf("interpret_keys()\n");
6894 earg = interpret(pue, earg, istate);
6895 if (exceptionOrCantInterpret(earg))
6897 if (earg.op == EXP.null_)
6899 emplaceExp!(NullExp)(pue, earg.loc, earg.type);
6902 if (earg.op != EXP.assocArrayLiteral && earg.type.toBasetype().ty != Taarray)
6904 AssocArrayLiteralExp aae = earg.isAssocArrayLiteralExp();
6905 auto ae = ctfeEmplaceExp!ArrayLiteralExp(aae.loc, returnType, aae.keys);
6906 ae.ownedByCtfe = aae.ownedByCtfe;
6907 *pue = copyLiteral(ae);
6911 private Expression interpret_values(UnionExp* pue, InterState* istate, Expression earg, Type returnType)
6915 printf("interpret_values()\n");
6917 earg = interpret(pue, earg, istate);
6918 if (exceptionOrCantInterpret(earg))
6920 if (earg.op == EXP.null_)
6922 emplaceExp!(NullExp)(pue, earg.loc, earg.type);
6925 if (earg.op != EXP.assocArrayLiteral && earg.type.toBasetype().ty != Taarray)
6927 auto aae = earg.isAssocArrayLiteralExp();
6928 auto ae = ctfeEmplaceExp!ArrayLiteralExp(aae.loc, returnType, aae.values);
6929 ae.ownedByCtfe = aae.ownedByCtfe;
6930 //printf("result is %s\n", e.toChars());
6931 *pue = copyLiteral(ae);
6935 private Expression interpret_dup(UnionExp* pue, InterState* istate, Expression earg)
6939 printf("interpret_dup()\n");
6941 earg = interpret(pue, earg, istate);
6942 if (exceptionOrCantInterpret(earg))
6944 if (earg.op == EXP.null_)
6946 emplaceExp!(NullExp)(pue, earg.loc, earg.type);
6949 if (earg.op != EXP.assocArrayLiteral && earg.type.toBasetype().ty != Taarray)
6951 auto aae = copyLiteral(earg).copy().isAssocArrayLiteralExp();
6952 for (size_t i = 0; i < aae.keys.dim; i++)
6954 if (Expression e = evaluatePostblit(istate, (*aae.keys)[i]))
6956 if (Expression e = evaluatePostblit(istate, (*aae.values)[i]))
6959 aae.type = earg.type.mutableOf(); // repaint type from const(int[int]) to const(int)[int]
6960 //printf("result is %s\n", aae.toChars());
6964 // signature is int delegate(ref Value) OR int delegate(ref Key, ref Value)
6965 private Expression interpret_aaApply(UnionExp* pue, InterState* istate, Expression aa, Expression deleg)
6967 aa = interpret(aa, istate);
6968 if (exceptionOrCantInterpret(aa))
6970 if (aa.op != EXP.assocArrayLiteral)
6972 emplaceExp!(IntegerExp)(pue, deleg.loc, 0, Type.tsize_t);
6976 FuncDeclaration fd = null;
6977 Expression pthis = null;
6978 if (auto de = deleg.isDelegateExp())
6983 else if (auto fe = deleg.isFuncExp())
6986 assert(fd && fd.fbody);
6987 assert(fd.parameters);
6988 size_t numParams = fd.parameters.dim;
6989 assert(numParams == 1 || numParams == 2);
6991 Parameter fparam = fd.type.isTypeFunction().parameterList[numParams - 1];
6992 const wantRefValue = fparam.isReference();
6994 Expressions args = Expressions(numParams);
6996 AssocArrayLiteralExp ae = cast(AssocArrayLiteralExp)aa;
6997 if (!ae.keys || ae.keys.dim == 0)
6998 return ctfeEmplaceExp!IntegerExp(deleg.loc, 0, Type.tsize_t);
7001 for (size_t i = 0; i < ae.keys.dim; ++i)
7003 Expression ekey = (*ae.keys)[i];
7004 Expression evalue = (*ae.values)[i];
7007 Type t = evalue.type;
7008 evalue = ctfeEmplaceExp!IndexExp(deleg.loc, ae, ekey);
7011 args[numParams - 1] = evalue;
7016 eresult = interpretFunction(&ue, fd, istate, &args, pthis);
7017 if (eresult == ue.exp())
7018 eresult = ue.copy();
7019 if (exceptionOrCantInterpret(eresult))
7022 if (eresult.isIntegerExp().getInteger() != 0)
7028 /* Decoding UTF strings for foreach loops. Duplicates the functionality of
7029 * the twelve _aApplyXXn functions in aApply.d in the runtime.
7031 private Expression foreachApplyUtf(UnionExp* pue, InterState* istate, Expression str, Expression deleg, bool rvs)
7035 printf("foreachApplyUtf(%s, %s)\n", str.toChars(), deleg.toChars());
7037 FuncDeclaration fd = null;
7038 Expression pthis = null;
7039 if (auto de = deleg.isDelegateExp())
7044 else if (auto fe = deleg.isFuncExp())
7047 assert(fd && fd.fbody);
7048 assert(fd.parameters);
7049 size_t numParams = fd.parameters.dim;
7050 assert(numParams == 1 || numParams == 2);
7051 Type charType = (*fd.parameters)[numParams - 1].type;
7052 Type indexType = numParams == 2 ? (*fd.parameters)[0].type : Type.tsize_t;
7053 size_t len = cast(size_t)resolveArrayLength(str);
7056 emplaceExp!(IntegerExp)(pue, deleg.loc, 0, indexType);
7060 UnionExp strTmp = void;
7061 str = resolveSlice(str, &strTmp);
7063 auto se = str.isStringExp();
7064 auto ale = str.isArrayLiteralExp();
7067 str.error("CTFE internal error: cannot foreach `%s`", str.toChars());
7068 return CTFEExp.cantexp;
7070 Expressions args = Expressions(numParams);
7072 Expression eresult = null; // ded-store to prevent spurious warning
7074 // Buffers for encoding; also used for decoding array literals
7075 char[4] utf8buf = void;
7076 wchar[2] utf16buf = void;
7078 size_t start = rvs ? len : 0;
7079 size_t end = rvs ? 0 : len;
7080 for (size_t indx = start; indx != end;)
7082 // Step 1: Decode the next dchar from the string.
7084 string errmsg = null; // Used for reporting decoding errors
7085 dchar rawvalue; // Holds the decoded dchar
7086 size_t currentIndex = indx; // The index of the decoded character
7090 // If it is an array literal, copy the code points into the buffer
7091 size_t buflen = 1; // #code points in the buffer
7092 size_t n = 1; // #code points in this char
7093 size_t sz = cast(size_t)ale.type.nextOf().size();
7100 // find the start of the string
7103 while (indx > 0 && buflen < 4)
7105 Expression r = (*ale.elements)[indx];
7106 char x = cast(char)r.isIntegerExp().getInteger();
7107 if ((x & 0xC0) != 0x80)
7114 buflen = (indx + 4 > len) ? len - indx : 4;
7115 for (size_t i = 0; i < buflen; ++i)
7117 Expression r = (*ale.elements)[indx + i];
7118 utf8buf[i] = cast(char)r.isIntegerExp().getInteger();
7121 errmsg = utf_decodeChar(utf8buf[0 .. buflen], n, rawvalue);
7127 // find the start of the string
7130 Expression r = (*ale.elements)[indx];
7131 ushort x = cast(ushort)r.isIntegerExp().getInteger();
7132 if (indx > 0 && x >= 0xDC00 && x <= 0xDFFF)
7139 buflen = (indx + 2 > len) ? len - indx : 2;
7140 for (size_t i = 0; i < buflen; ++i)
7142 Expression r = (*ale.elements)[indx + i];
7143 utf16buf[i] = cast(ushort)r.isIntegerExp().getInteger();
7146 errmsg = utf_decodeWchar(utf16buf[0 .. buflen], n, rawvalue);
7153 Expression r = (*ale.elements)[indx];
7154 rawvalue = cast(dchar)r.isIntegerExp().getInteger();
7168 size_t saveindx; // used for reverse iteration
7176 // find the start of the string
7178 while (indx > 0 && ((se.getCodeUnit(indx) & 0xC0) == 0x80))
7182 auto slice = se.peekString();
7183 errmsg = utf_decodeChar(slice, indx, rawvalue);
7194 auto wc = se.getCodeUnit(indx);
7195 if (wc >= 0xDC00 && wc <= 0xDFFF)
7199 const slice = se.peekWstring();
7200 errmsg = utf_decodeWchar(slice, indx, rawvalue);
7208 rawvalue = se.getCodeUnit(indx);
7219 deleg.error("`%.*s`", cast(int)errmsg.length, errmsg.ptr);
7220 return CTFEExp.cantexp;
7223 // Step 2: encode the dchar in the target encoding
7225 int charlen = 1; // How many codepoints are involved?
7226 switch (charType.size())
7229 charlen = utf_codeLengthChar(rawvalue);
7230 utf_encodeChar(&utf8buf[0], rawvalue);
7233 charlen = utf_codeLengthWchar(rawvalue);
7234 utf_encodeWchar(&utf16buf[0], rawvalue);
7242 currentIndex = indx;
7244 // Step 3: call the delegate once for each code point
7246 // The index only needs to be set once
7248 args[0] = ctfeEmplaceExp!IntegerExp(deleg.loc, currentIndex, indexType);
7250 Expression val = null;
7252 foreach (k; 0 .. charlen)
7255 switch (charType.size())
7258 codepoint = utf8buf[k];
7261 codepoint = utf16buf[k];
7264 codepoint = rawvalue;
7269 val = ctfeEmplaceExp!IntegerExp(str.loc, codepoint, charType);
7271 args[numParams - 1] = val;
7274 eresult = interpretFunction(&ue, fd, istate, &args, pthis);
7275 if (eresult == ue.exp())
7276 eresult = ue.copy();
7277 if (exceptionOrCantInterpret(eresult))
7279 if (eresult.isIntegerExp().getInteger() != 0)
7286 /* If this is a built-in function, return the interpreted result,
7287 * Otherwise, return NULL.
7289 private Expression evaluateIfBuiltin(UnionExp* pue, InterState* istate, const ref Loc loc, FuncDeclaration fd, Expressions* arguments, Expression pthis)
7291 Expression e = null;
7292 size_t nargs = arguments ? arguments.dim : 0;
7295 if (isBuiltin(fd) != BUILTIN.unimp)
7297 Expressions args = Expressions(nargs);
7298 foreach (i, ref arg; args)
7300 Expression earg = (*arguments)[i];
7301 earg = interpret(earg, istate);
7302 if (exceptionOrCantInterpret(earg))
7306 e = eval_builtin(loc, fd, &args);
7309 error(loc, "cannot evaluate unimplemented builtin `%s` at compile time", fd.toChars());
7310 e = CTFEExp.cantexp;
7316 if (nargs == 1 || nargs == 3)
7318 Expression firstarg = (*arguments)[0];
7319 if (auto firstAAtype = firstarg.type.toBasetype().isTypeAArray())
7321 const id = fd.ident;
7325 return interpret_length(pue, istate, firstarg);
7327 if (fd.toParent2().ident == Id.object)
7330 return interpret_keys(pue, istate, firstarg, firstAAtype.index.arrayOf());
7331 if (id == Id.values)
7332 return interpret_values(pue, istate, firstarg, firstAAtype.nextOf().arrayOf());
7333 if (id == Id.rehash)
7334 return interpret(pue, firstarg, istate);
7336 return interpret_dup(pue, istate, firstarg);
7339 else // (nargs == 3)
7341 if (id == Id._aaApply)
7342 return interpret_aaApply(pue, istate, firstarg, (*arguments)[2]);
7343 if (id == Id._aaApply2)
7344 return interpret_aaApply(pue, istate, firstarg, (*arguments)[2]);
7349 if (pthis && !fd.fbody && fd.isCtorDeclaration() && fd.parent && fd.parent.parent && fd.parent.parent.ident == Id.object)
7351 if (pthis.op == EXP.classReference && fd.parent.ident == Id.Throwable)
7353 // At present, the constructors just copy their arguments into the struct.
7354 // But we might need some magic if stack tracing gets added to druntime.
7355 StructLiteralExp se = (cast(ClassReferenceExp)pthis).value;
7356 assert(arguments.dim <= se.elements.dim);
7357 foreach (i, arg; *arguments)
7359 auto elem = interpret(arg, istate);
7360 if (exceptionOrCantInterpret(elem))
7362 (*se.elements)[i] = elem;
7364 return CTFEExp.voidexp;
7367 if (nargs == 1 && !pthis && (fd.ident == Id.criticalenter || fd.ident == Id.criticalexit))
7369 // Support synchronized{} as a no-op
7370 return CTFEExp.voidexp;
7374 const idlen = fd.ident.toString().length;
7375 const id = fd.ident.toChars();
7376 if (nargs == 2 && (idlen == 10 || idlen == 11) && !strncmp(id, "_aApply", 7))
7378 // Functions from aApply.d and aApplyR.d in the runtime
7379 bool rvs = (idlen == 11); // true if foreach_reverse
7380 char c = id[idlen - 3]; // char width: 'c', 'w', or 'd'
7381 char s = id[idlen - 2]; // string width: 'c', 'w', or 'd'
7382 char n = id[idlen - 1]; // numParams: 1 or 2.
7383 // There are 12 combinations
7384 if ((n == '1' || n == '2') &&
7385 (c == 'c' || c == 'w' || c == 'd') &&
7386 (s == 'c' || s == 'w' || s == 'd') &&
7389 Expression str = (*arguments)[0];
7390 str = interpret(str, istate);
7391 if (exceptionOrCantInterpret(str))
7393 return foreachApplyUtf(pue, istate, str, (*arguments)[1], rvs);
7400 private Expression evaluatePostblit(InterState* istate, Expression e)
7402 auto ts = e.type.baseElemOf().isTypeStruct();
7405 StructDeclaration sd = ts.sym;
7409 if (auto ale = e.isArrayLiteralExp())
7411 foreach (elem; *ale.elements)
7413 if (auto ex = evaluatePostblit(istate, elem))
7418 if (e.op == EXP.structLiteral)
7422 e = interpretFunction(&ue, sd.postblit, istate, null, e);
7425 if (exceptionOrCantInterpret(e))
7432 private Expression evaluateDtor(InterState* istate, Expression e)
7434 auto ts = e.type.baseElemOf().isTypeStruct();
7437 StructDeclaration sd = ts.sym;
7442 if (auto ale = e.isArrayLiteralExp())
7444 foreach_reverse (elem; *ale.elements)
7445 e = evaluateDtor(istate, elem);
7447 else if (e.op == EXP.structLiteral)
7450 e = interpretFunction(&ue, sd.dtor, istate, null, e);
7454 if (exceptionOrCantInterpret(e))
7463 /*************************** CTFE Sanity Checks ***************************/
7464 /* Setter functions for CTFE variable values.
7465 * These functions exist to check for compiler CTFE bugs.
7467 private bool hasValue(VarDeclaration vd)
7469 return vd.ctfeAdrOnStack != VarDeclaration.AdrOnStackNone &&
7470 getValue(vd) !is null;
7473 // Don't check for validity
7474 private void setValueWithoutChecking(VarDeclaration vd, Expression newval)
7476 ctfeGlobals.stack.setValue(vd, newval);
7479 private void setValue(VarDeclaration vd, Expression newval)
7481 //printf("setValue() vd: %s newval: %s\n", vd.toChars(), newval.toChars());
7484 if (!((vd.storage_class & (STC.out_ | STC.ref_)) ? isCtfeReferenceValid(newval) : isCtfeValueValid(newval)))
7486 printf("[%s] vd = %s %s, newval = %s\n", vd.loc.toChars(), vd.type.toChars(), vd.toChars(), newval.toChars());
7489 assert((vd.storage_class & (STC.out_ | STC.ref_)) ? isCtfeReferenceValid(newval) : isCtfeValueValid(newval));
7490 ctfeGlobals.stack.setValue(vd, newval);
7494 * Removes `_d_HookTraceImpl` if found from `ce` and `fd`.
7495 * This is needed for the CTFE interception code to be able to find hooks that are called though the hook's `*Trace`
7498 * This is done by replacing `_d_HookTraceImpl!(T, Hook, errMsg)(..., parameters)` with `Hook(parameters)`.
7500 * ce = The CallExp that possible will be be replaced
7501 * fd = Fully resolve function declaration that `ce` would call
7503 private void removeHookTraceImpl(ref CallExp ce, ref FuncDeclaration fd)
7505 if (fd.ident != Id._d_HookTraceImpl)
7510 // Get the Hook from the second template parameter
7511 TemplateInstance templateInstance = fd.parent.isTemplateInstance;
7512 RootObject hook = (*templateInstance.tiargs)[1];
7513 assert(hook.dyncast() == DYNCAST.dsymbol, "Expected _d_HookTraceImpl's second template parameter to be an alias to the hook!");
7514 fd = (cast(Dsymbol)hook).isFuncDeclaration;
7516 // Remove the first three trace parameters
7517 auto arguments = new Expressions();
7518 arguments.reserve(ce.arguments.dim - 3);
7519 arguments.pushSlice((*ce.arguments)[3 .. $]);
7521 ce = ctfeEmplaceExp!CallExp(ce.loc, ctfeEmplaceExp!VarExp(ce.loc, fd, false), arguments);
7523 if (global.params.verbose)
7524 message("strip %s =>\n %s", oldCE.toChars(), ce.toChars());