d: Merge upstream dmd, druntime 4c18eed967, phobos d945686a4.
[official-gcc.git] / gcc / d / dmd / dinterpret.d
bloba43be7d2308f4a2cdfae56a488965115f90d4a4a
1 /**
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-2023 by The D Language Foundation, All Rights Reserved
7 * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright)
8 * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
9 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/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;
19 import dmd.arraytypes;
20 import dmd.astenums;
21 import dmd.attrib;
22 import dmd.builtin;
23 import dmd.constfold;
24 import dmd.ctfeexpr;
25 import dmd.dclass;
26 import dmd.declaration;
27 import dmd.dstruct;
28 import dmd.dsymbol;
29 import dmd.dsymbolsem;
30 import dmd.dtemplate;
31 import dmd.errors;
32 import dmd.expression;
33 import dmd.expressionsem;
34 import dmd.func;
35 import dmd.globals;
36 import dmd.hdrgen;
37 import dmd.id;
38 import dmd.identifier;
39 import dmd.init;
40 import dmd.initsem;
41 import dmd.location;
42 import dmd.mtype;
43 import dmd.root.rmem;
44 import dmd.root.array;
45 import dmd.root.ctfloat;
46 import dmd.root.region;
47 import dmd.root.rootobject;
48 import dmd.root.utf;
49 import dmd.statement;
50 import dmd.tokens;
51 import dmd.visitor;
53 /*************************************
54 * Entry point for CTFE.
55 * A compile-time result is required. Give an error if not possible.
57 * `e` must be semantically valid expression. In other words, it should not
58 * contain any `ErrorExp`s in it. But, CTFE interpretation will cross over
59 * functions and may invoke a function that contains `ErrorStatement` in its body.
60 * If that, the "CTFE failed because of previous errors" error is raised.
62 public Expression ctfeInterpret(Expression e)
64 switch (e.op)
66 case EXP.int64:
67 case EXP.float64:
68 case EXP.complex80:
69 case EXP.null_:
70 case EXP.void_:
71 case EXP.string_:
72 case EXP.this_:
73 case EXP.super_:
74 case EXP.type:
75 case EXP.typeid_:
76 case EXP.template_: // non-eponymous template/instance
77 case EXP.scope_: // ditto
78 case EXP.dotTemplateDeclaration: // ditto, e.e1 doesn't matter here
79 case EXP.dotTemplateInstance: // ditto
80 case EXP.dot: // ditto
81 if (e.type.ty == Terror)
82 return ErrorExp.get();
83 goto case EXP.error;
85 case EXP.error:
86 return e;
88 default:
89 break;
92 assert(e.type); // https://issues.dlang.org/show_bug.cgi?id=14642
93 //assert(e.type.ty != Terror); // FIXME
94 if (e.type.ty == Terror)
95 return ErrorExp.get();
97 auto rgnpos = ctfeGlobals.region.savePos();
99 Expression result = interpret(e, null);
101 // Report an error if the expression contained a `ThrowException` and
102 // hence generated an uncaught exception
103 if (auto tee = result.isThrownExceptionExp())
105 tee.generateUncaughtError();
106 result = CTFEExp.cantexp;
108 else
109 result = copyRegionExp(result);
111 if (!CTFEExp.isCantExp(result))
112 result = scrubReturnValue(e.loc, result);
113 if (CTFEExp.isCantExp(result))
114 result = ErrorExp.get();
116 ctfeGlobals.region.release(rgnpos);
118 return result;
121 /* Run CTFE on the expression, but allow the expression to be a TypeExp
122 * or a tuple containing a TypeExp. (This is required by pragma(msg)).
124 public Expression ctfeInterpretForPragmaMsg(Expression e)
126 if (e.op == EXP.error || e.op == EXP.type)
127 return e;
129 // It's also OK for it to be a function declaration (happens only with
130 // __traits(getOverloads))
131 if (auto ve = e.isVarExp())
132 if (ve.var.isFuncDeclaration())
134 return e;
137 auto tup = e.isTupleExp();
138 if (!tup)
139 return e.ctfeInterpret();
141 // Tuples need to be treated separately, since they are
142 // allowed to contain a TypeExp in this case.
144 Expressions* expsx = null;
145 foreach (i, g; *tup.exps)
147 auto h = ctfeInterpretForPragmaMsg(g);
148 if (h != g)
150 if (!expsx)
152 expsx = tup.exps.copy();
154 (*expsx)[i] = h;
157 if (expsx)
159 auto te = new TupleExp(e.loc, expsx);
160 expandTuples(te.exps);
161 te.type = new TypeTuple(te.exps);
162 return te;
164 return e;
167 public Expression getValue(VarDeclaration vd)
169 return ctfeGlobals.stack.getValue(vd);
172 /*************************************************
173 * Allocate an Expression in the ctfe region.
174 * Params:
175 * T = type of Expression to allocate
176 * args = arguments to Expression's constructor
177 * Returns:
178 * allocated Expression
180 T ctfeEmplaceExp(T : Expression, Args...)(Args args)
182 if (mem.isGCEnabled)
183 return new T(args);
184 auto p = ctfeGlobals.region.malloc(__traits(classInstanceSize, T));
185 emplaceExp!T(p, args);
186 return cast(T)p;
189 // CTFE diagnostic information
190 public extern (C++) void printCtfePerformanceStats()
192 debug (SHOWPERFORMANCE)
194 printf(" ---- CTFE Performance ----\n");
195 printf("max call depth = %d\tmax stack = %d\n", ctfeGlobals.maxCallDepth, ctfeGlobals.stack.maxStackUsage());
196 printf("array allocs = %d\tassignments = %d\n\n", ctfeGlobals.numArrayAllocs, ctfeGlobals.numAssignments);
200 /**************************
203 void incArrayAllocs()
205 ++ctfeGlobals.numArrayAllocs;
208 /* ================================================ Implementation ======================================= */
210 private:
212 /***************
213 * Collect together globals used by CTFE
215 struct CtfeGlobals
217 Region region;
219 CtfeStack stack;
221 int callDepth = 0; // current number of recursive calls
223 // When printing a stack trace, suppress this number of calls
224 int stackTraceCallsToSuppress = 0;
226 int maxCallDepth = 0; // highest number of recursive calls
227 int numArrayAllocs = 0; // Number of allocated arrays
228 int numAssignments = 0; // total number of assignments executed
231 __gshared CtfeGlobals ctfeGlobals;
233 enum CTFEGoal : int
235 RValue, /// Must return an Rvalue (== CTFE value)
236 LValue, /// Must return an Lvalue (== CTFE reference)
237 Nothing, /// The return value is not required
240 //debug = LOG;
241 //debug = LOGASSIGN;
242 //debug = LOGCOMPILE;
243 //debug = SHOWPERFORMANCE;
245 // Maximum allowable recursive function calls in CTFE
246 enum CTFE_RECURSION_LIMIT = 1000;
249 The values of all CTFE variables
251 struct CtfeStack
253 private:
254 /* The stack. Every declaration we encounter is pushed here,
255 * together with the VarDeclaration, and the previous
256 * stack address of that variable, so that we can restore it
257 * when we leave the stack frame.
258 * Note that when a function is forward referenced, the interpreter must
259 * run semantic3, and that may start CTFE again with a NULL istate. Thus
260 * the stack might not be empty when CTFE begins.
262 * Ctfe Stack addresses are just 0-based integers, but we save
263 * them as 'void *' because Array can only do pointers.
265 Expressions values; // values on the stack
266 VarDeclarations vars; // corresponding variables
267 Array!(void*) savedId; // id of the previous state of that var
269 Array!(void*) frames; // all previous frame pointers
270 Expressions savedThis; // all previous values of localThis
272 /* Global constants get saved here after evaluation, so we never
273 * have to redo them. This saves a lot of time and memory.
275 Expressions globalValues; // values of global constants
277 size_t framepointer; // current frame pointer
278 size_t maxStackPointer; // most stack we've ever used
279 Expression localThis; // value of 'this', or NULL if none
281 public:
282 size_t stackPointer() @safe
284 return values.length;
287 // The current value of 'this', or NULL if none
288 Expression getThis() @safe
290 return localThis;
293 // Largest number of stack positions we've used
294 size_t maxStackUsage() @safe
296 return maxStackPointer;
299 // Start a new stack frame, using the provided 'this'.
300 void startFrame(Expression thisexp)
302 frames.push(cast(void*)cast(size_t)framepointer);
303 savedThis.push(localThis);
304 framepointer = stackPointer();
305 localThis = thisexp;
308 void endFrame()
310 size_t oldframe = cast(size_t)frames[frames.length - 1];
311 localThis = savedThis[savedThis.length - 1];
312 popAll(framepointer);
313 framepointer = oldframe;
314 frames.setDim(frames.length - 1);
315 savedThis.setDim(savedThis.length - 1);
318 bool isInCurrentFrame(VarDeclaration v)
320 if (v.isDataseg() && !v.isCTFE())
321 return false; // It's a global
322 return v.ctfeAdrOnStack >= framepointer;
325 Expression getValue(VarDeclaration v)
327 //printf("getValue() %s\n", v.toChars());
328 if ((v.isDataseg() || v.storage_class & STC.manifest) && !v.isCTFE())
330 assert(v.ctfeAdrOnStack < globalValues.length);
331 return globalValues[v.ctfeAdrOnStack];
333 assert(v.ctfeAdrOnStack < stackPointer());
334 return values[v.ctfeAdrOnStack];
337 void setValue(VarDeclaration v, Expression e)
339 //printf("setValue() %s : %s\n", v.toChars(), e.toChars());
340 assert(!v.isDataseg() || v.isCTFE());
341 assert(v.ctfeAdrOnStack < stackPointer());
342 values[v.ctfeAdrOnStack] = e;
345 void push(VarDeclaration v)
347 //printf("push() %s\n", v.toChars());
348 assert(!v.isDataseg() || v.isCTFE());
349 if (v.ctfeAdrOnStack != VarDeclaration.AdrOnStackNone && v.ctfeAdrOnStack >= framepointer)
351 // Already exists in this frame, reuse it.
352 values[v.ctfeAdrOnStack] = null;
353 return;
355 savedId.push(cast(void*)cast(size_t)v.ctfeAdrOnStack);
356 v.ctfeAdrOnStack = cast(uint)values.length;
357 vars.push(v);
358 values.push(null);
361 void pop(VarDeclaration v)
363 assert(!v.isDataseg() || v.isCTFE());
364 assert(!v.isReference());
365 const oldid = v.ctfeAdrOnStack;
366 v.ctfeAdrOnStack = cast(uint)cast(size_t)savedId[oldid];
367 if (v.ctfeAdrOnStack == values.length - 1)
369 values.pop();
370 vars.pop();
371 savedId.pop();
375 void popAll(size_t stackpointer)
377 if (stackPointer() > maxStackPointer)
378 maxStackPointer = stackPointer();
379 assert(values.length >= stackpointer);
380 for (size_t i = stackpointer; i < values.length; ++i)
382 VarDeclaration v = vars[i];
383 v.ctfeAdrOnStack = cast(uint)cast(size_t)savedId[i];
385 values.setDim(stackpointer);
386 vars.setDim(stackpointer);
387 savedId.setDim(stackpointer);
390 void saveGlobalConstant(VarDeclaration v, Expression e)
392 assert(v._init && (v.isConst() || v.isImmutable() || v.storage_class & STC.manifest) && !v.isCTFE());
393 v.ctfeAdrOnStack = cast(uint)globalValues.length;
394 globalValues.push(copyRegionExp(e));
398 private struct InterState
400 InterState* caller; // calling function's InterState
401 FuncDeclaration fd; // function being interpreted
402 Statement start; // if !=NULL, start execution at this statement
404 /* target of CTFEExp result; also
405 * target of labelled CTFEExp or
406 * CTFEExp. (null if no label).
408 Statement gotoTarget;
411 /*************************************
412 * Attempt to interpret a function given the arguments.
413 * Params:
414 * pue = storage for result
415 * fd = function being called
416 * istate = state for calling function (NULL if none)
417 * arguments = function arguments
418 * thisarg = 'this', if a needThis() function, NULL if not.
420 * Returns:
421 * result expression if successful, EXP.cantExpression if not,
422 * or CTFEExp if function returned void.
424 private Expression interpretFunction(UnionExp* pue, FuncDeclaration fd, InterState* istate, Expressions* arguments, Expression thisarg)
426 debug (LOG)
428 printf("\n********\n%s FuncDeclaration::interpret(istate = %p) %s\n", fd.loc.toChars(), istate, fd.toChars());
431 void fdError(const(char)* msg)
433 error(fd.loc, "%s `%s` %s", fd.kind, fd.toPrettyChars, msg);
436 assert(pue);
437 if (fd.semanticRun == PASS.semantic3)
439 fdError("circular dependency. Functions cannot be interpreted while being compiled");
440 return CTFEExp.cantexp;
442 if (!fd.functionSemantic3())
443 return CTFEExp.cantexp;
444 if (fd.semanticRun < PASS.semantic3done)
446 fdError("circular dependency. Functions cannot be interpreted while being compiled");
447 return CTFEExp.cantexp;
450 auto tf = fd.type.toBasetype().isTypeFunction();
451 if (tf.parameterList.varargs != VarArg.none && arguments &&
452 ((fd.parameters && arguments.length != fd.parameters.length) || (!fd.parameters && arguments.length)))
454 fdError("C-style variadic functions are not yet implemented in CTFE");
455 return CTFEExp.cantexp;
458 // Nested functions always inherit the 'this' pointer from the parent,
459 // except for delegates. (Note that the 'this' pointer may be null).
460 // Func literals report isNested() even if they are in global scope,
461 // so we need to check that the parent is a function.
462 if (fd.isNested() && fd.toParentLocal().isFuncDeclaration() && !thisarg && istate)
463 thisarg = ctfeGlobals.stack.getThis();
465 if (fd.needThis() && !thisarg)
467 // error, no this. Prevent segfault.
468 // Here should be unreachable by the strict 'this' check in front-end.
469 error(fd.loc, "%s `%s` need `this` to access member `%s`", fd.kind, fd.toPrettyChars, fd.toChars());
470 return CTFEExp.cantexp;
473 // Place to hold all the arguments to the function while
474 // we are evaluating them.
475 size_t dim = arguments ? arguments.length : 0;
476 assert((fd.parameters ? fd.parameters.length : 0) == dim);
478 /* Evaluate all the arguments to the function,
479 * store the results in eargs[]
481 Expressions eargs = Expressions(dim);
482 for (size_t i = 0; i < dim; i++)
484 Expression earg = (*arguments)[i];
485 Parameter fparam = tf.parameterList[i];
487 if (fparam.isReference())
489 if (!istate && (fparam.storageClass & STC.out_))
491 // initializing an out parameter involves writing to it.
492 error(earg.loc, "global `%s` cannot be passed as an `out` parameter at compile time", earg.toChars());
493 return CTFEExp.cantexp;
495 // Convert all reference arguments into lvalue references
496 earg = interpretRegion(earg, istate, CTFEGoal.LValue);
497 if (CTFEExp.isCantExp(earg))
498 return earg;
500 else if (fparam.isLazy())
503 else
505 /* Value parameters
507 Type ta = fparam.type.toBasetype();
508 if (ta.ty == Tsarray)
509 if (auto eaddr = earg.isAddrExp())
511 /* Static arrays are passed by a simple pointer.
512 * Skip past this to get at the actual arg.
514 earg = eaddr.e1;
517 earg = interpretRegion(earg, istate);
518 if (CTFEExp.isCantExp(earg))
519 return earg;
521 /* Struct literals are passed by value, but we don't need to
522 * copy them if they are passed as const
524 if (earg.op == EXP.structLiteral && !(fparam.storageClass & (STC.const_ | STC.immutable_)))
525 earg = copyLiteral(earg).copy();
527 if (auto tee = earg.isThrownExceptionExp())
529 if (istate)
530 return tee;
531 tee.generateUncaughtError();
532 return CTFEExp.cantexp;
534 eargs[i] = earg;
537 // Now that we've evaluated all the arguments, we can start the frame
538 // (this is the moment when the 'call' actually takes place).
539 InterState istatex;
540 istatex.caller = istate;
541 istatex.fd = fd;
543 if (fd.hasDualContext())
545 Expression arg0 = thisarg;
546 if (arg0 && arg0.type.ty == Tstruct)
548 Type t = arg0.type.pointerTo();
549 arg0 = ctfeEmplaceExp!AddrExp(arg0.loc, arg0);
550 arg0.type = t;
552 auto elements = new Expressions(2);
553 (*elements)[0] = arg0;
554 (*elements)[1] = ctfeGlobals.stack.getThis();
555 Type t2 = Type.tvoidptr.sarrayOf(2);
556 const loc = thisarg ? thisarg.loc : fd.loc;
557 thisarg = ctfeEmplaceExp!ArrayLiteralExp(loc, t2, elements);
558 thisarg = ctfeEmplaceExp!AddrExp(loc, thisarg);
559 thisarg.type = t2.pointerTo();
562 ctfeGlobals.stack.startFrame(thisarg);
563 if (fd.vthis && thisarg)
565 ctfeGlobals.stack.push(fd.vthis);
566 setValue(fd.vthis, thisarg);
569 for (size_t i = 0; i < dim; i++)
571 Expression earg = eargs[i];
572 Parameter fparam = tf.parameterList[i];
573 VarDeclaration v = (*fd.parameters)[i];
574 debug (LOG)
576 printf("arg[%zu] = %s\n", i, earg.toChars());
578 ctfeGlobals.stack.push(v);
580 if (fparam.isReference() && earg.op == EXP.variable &&
581 earg.isVarExp().var.toParent2() == fd)
583 VarDeclaration vx = earg.isVarExp().var.isVarDeclaration();
584 if (!vx)
586 error(fd.loc, "%s `%s` cannot interpret `%s` as a `ref` parameter", fd.kind, fd.toPrettyChars, earg.toChars());
587 return CTFEExp.cantexp;
590 /* vx is a variable that is declared in fd.
591 * It means that fd is recursively called. e.g.
593 * void fd(int n, ref int v = dummy) {
594 * int vx;
595 * if (n == 1) fd(2, vx);
597 * fd(1);
599 * The old value of vx on the stack in fd(1)
600 * should be saved at the start of fd(2, vx) call.
602 const oldadr = vx.ctfeAdrOnStack;
604 ctfeGlobals.stack.push(vx);
605 assert(!hasValue(vx)); // vx is made uninitialized
607 // https://issues.dlang.org/show_bug.cgi?id=14299
608 // v.ctfeAdrOnStack should be saved already
609 // in the stack before the overwrite.
610 v.ctfeAdrOnStack = oldadr;
611 assert(hasValue(v)); // ref parameter v should refer existing value.
613 else
615 // Value parameters and non-trivial references
616 setValueWithoutChecking(v, earg);
618 debug (LOG)
620 printf("interpreted arg[%zu] = %s\n", i, earg.toChars());
621 showCtfeExpr(earg);
623 debug (LOGASSIGN)
625 printf("interpreted arg[%zu] = %s\n", i, earg.toChars());
626 showCtfeExpr(earg);
630 if (fd.vresult)
631 ctfeGlobals.stack.push(fd.vresult);
633 // Enter the function
634 ++ctfeGlobals.callDepth;
635 if (ctfeGlobals.callDepth > ctfeGlobals.maxCallDepth)
636 ctfeGlobals.maxCallDepth = ctfeGlobals.callDepth;
638 Expression e = null;
639 while (1)
641 if (ctfeGlobals.callDepth > CTFE_RECURSION_LIMIT)
643 fdError("CTFE recursion limit exceeded");
644 e = CTFEExp.cantexp;
645 break;
647 e = interpretStatement(pue, fd.fbody, &istatex);
648 if (CTFEExp.isCantExp(e))
650 debug (LOG)
652 printf("function body failed to interpret\n");
656 if (istatex.start)
658 error(fd.loc, "%s `%s` CTFE internal error: failed to resume at statement `%s`", fd.kind, fd.toPrettyChars, istatex.start.toChars());
659 return CTFEExp.cantexp;
662 /* This is how we deal with a recursive statement AST
663 * that has arbitrary goto statements in it.
664 * Bubble up a 'result' which is the target of the goto
665 * statement, then go recursively down the AST looking
666 * for that statement, then execute starting there.
668 if (CTFEExp.isGotoExp(e))
670 istatex.start = istatex.gotoTarget; // set starting statement
671 istatex.gotoTarget = null;
673 else
675 assert(!e || (e.op != EXP.continue_ && e.op != EXP.break_));
676 break;
679 // If fell off the end of a void function, return void
680 if (!e)
682 if (tf.next.ty == Tvoid)
683 e = CTFEExp.voidexp;
684 else
686 /* missing a return statement can happen with C functions
687 * https://issues.dlang.org/show_bug.cgi?id=23056
689 fdError("no return value from function");
690 e = CTFEExp.cantexp;
694 if (tf.isref && e.op == EXP.variable && e.isVarExp().var == fd.vthis)
695 e = thisarg;
696 if (tf.isref && fd.hasDualContext() && e.op == EXP.index)
698 auto ie = e.isIndexExp();
699 auto pe = ie.e1.isPtrExp();
700 auto ve = !pe ? null : pe.e1.isVarExp();
701 if (ve && ve.var == fd.vthis)
703 auto ne = ie.e2.isIntegerExp();
704 assert(ne);
705 auto ale = thisarg.isAddrExp().e1.isArrayLiteralExp();
706 e = (*ale.elements)[cast(size_t)ne.getInteger()];
707 if (auto ae = e.isAddrExp())
709 e = ae.e1;
714 // Leave the function
715 --ctfeGlobals.callDepth;
717 ctfeGlobals.stack.endFrame();
719 // If it generated an uncaught exception, report error.
720 if (!istate && e.isThrownExceptionExp())
722 if (e == pue.exp())
723 e = pue.copy();
724 e.isThrownExceptionExp().generateUncaughtError();
725 e = CTFEExp.cantexp;
728 return e;
731 /// used to collect coverage information in ctfe
732 void incUsageCtfe(InterState* istate, const ref Loc loc)
734 if (global.params.ctfe_cov && istate)
736 auto line = loc.linnum;
737 auto mod = istate.fd.getModule();
739 ++mod.ctfe_cov[line];
743 /***********************************
744 * Interpret the statement.
745 * Params:
746 * s = Statement to interpret
747 * istate = context
748 * Returns:
749 * NULL continue to next statement
750 * EXP.cantExpression cannot interpret statement at compile time
751 * !NULL expression from return statement, or thrown exception
754 Expression interpretStatement(Statement s, InterState* istate)
756 UnionExp ue = void;
757 auto result = interpretStatement(&ue, s, istate);
758 if (result == ue.exp())
759 result = ue.copy();
760 return result;
764 Expression interpretStatement(UnionExp* pue, Statement s, InterState* istate)
766 Expression result;
768 // If e is EXP.throw_exception or EXP.cantExpression,
769 // set it to 'result' and returns true.
770 bool exceptionOrCant(Expression e)
772 if (exceptionOrCantInterpret(e))
774 // Make sure e is not pointing to a stack temporary
775 result = (e.op == EXP.cantExpression) ? CTFEExp.cantexp : e;
776 return true;
778 return false;
781 /******************************** Statement ***************************/
783 void visitDefaultCase(Statement s)
785 debug (LOG)
787 printf("%s Statement::interpret() %s\n", s.loc.toChars(), s.toChars());
789 if (istate.start)
791 if (istate.start != s)
792 return;
793 istate.start = null;
796 error(s.loc, "statement `%s` cannot be interpreted at compile time", s.toChars());
797 result = CTFEExp.cantexp;
800 void visitExp(ExpStatement s)
802 debug (LOG)
804 printf("%s ExpStatement::interpret(%s)\n", s.loc.toChars(), s.exp ? s.exp.toChars() : "");
806 if (istate.start)
808 if (istate.start != s)
809 return;
810 istate.start = null;
812 if (s.exp && s.exp.hasCode)
813 incUsageCtfe(istate, s.loc);
815 Expression e = interpret(pue, s.exp, istate, CTFEGoal.Nothing);
816 if (exceptionOrCant(e))
817 return;
820 void visitDtorExp(DtorExpStatement s)
822 visitExp(s);
825 void visitCompound(CompoundStatement s)
827 debug (LOG)
829 printf("%s CompoundStatement::interpret()\n", s.loc.toChars());
831 if (istate.start == s)
832 istate.start = null;
834 const dim = s.statements ? s.statements.length : 0;
835 foreach (i; 0 .. dim)
837 Statement sx = (*s.statements)[i];
838 result = interpretStatement(pue, sx, istate);
839 if (result)
840 break;
842 debug (LOG)
844 printf("%s -CompoundStatement::interpret() %p\n", s.loc.toChars(), result);
848 void visitCompoundAsm(CompoundAsmStatement s)
850 visitCompound(s);
853 void visitUnrolledLoop(UnrolledLoopStatement s)
855 debug (LOG)
857 printf("%s UnrolledLoopStatement::interpret()\n", s.loc.toChars());
859 if (istate.start == s)
860 istate.start = null;
862 const dim = s.statements ? s.statements.length : 0;
863 foreach (i; 0 .. dim)
865 Statement sx = (*s.statements)[i];
866 Expression e = interpretStatement(pue, sx, istate);
867 if (!e) // succeeds to interpret, or goto target was not found
868 continue;
869 if (exceptionOrCant(e))
870 return;
871 if (e.op == EXP.break_)
873 if (istate.gotoTarget && istate.gotoTarget != s)
875 result = e; // break at a higher level
876 return;
878 istate.gotoTarget = null;
879 result = null;
880 return;
882 if (e.op == EXP.continue_)
884 if (istate.gotoTarget && istate.gotoTarget != s)
886 result = e; // continue at a higher level
887 return;
889 istate.gotoTarget = null;
890 continue;
893 // expression from return statement, or thrown exception
894 result = e;
895 break;
899 void visitIf(IfStatement s)
901 debug (LOG)
903 printf("%s IfStatement::interpret(%s)\n", s.loc.toChars(), s.condition.toChars());
905 incUsageCtfe(istate, s.loc);
906 if (istate.start == s)
907 istate.start = null;
908 if (istate.start)
910 Expression e = null;
911 e = interpretStatement(s.ifbody, istate);
912 if (!e && istate.start)
913 e = interpretStatement(s.elsebody, istate);
914 result = e;
915 return;
918 UnionExp ue = void;
919 Expression e = interpret(&ue, s.condition, istate);
920 assert(e);
921 if (exceptionOrCant(e))
922 return;
924 if (isTrueBool(e))
925 result = interpretStatement(pue, s.ifbody, istate);
926 else if (e.toBool().hasValue(false))
927 result = interpretStatement(pue, s.elsebody, istate);
928 else
930 // no error, or assert(0)?
931 result = CTFEExp.cantexp;
935 void visitScope(ScopeStatement s)
937 debug (LOG)
939 printf("%s ScopeStatement::interpret()\n", s.loc.toChars());
941 if (istate.start == s)
942 istate.start = null;
944 result = interpretStatement(pue, s.statement, istate);
947 void visitReturn(ReturnStatement s)
949 debug (LOG)
951 printf("%s ReturnStatement::interpret(%s)\n", s.loc.toChars(), s.exp ? s.exp.toChars() : "");
953 if (istate.start)
955 if (istate.start != s)
956 return;
957 istate.start = null;
960 if (!s.exp)
962 result = CTFEExp.voidexp;
963 return;
966 incUsageCtfe(istate, s.loc);
967 assert(istate && istate.fd && istate.fd.type && istate.fd.type.ty == Tfunction);
968 TypeFunction tf = cast(TypeFunction)istate.fd.type;
970 /* If the function returns a ref AND it's been called from an assignment,
971 * we need to return an lvalue. Otherwise, just do an (rvalue) interpret.
973 if (tf.isref)
975 result = interpret(pue, s.exp, istate, CTFEGoal.LValue);
976 return;
978 if (tf.next && tf.next.ty == Tdelegate && istate.fd.closureVars.length > 0)
980 // To support this, we need to copy all the closure vars
981 // into the delegate literal.
982 error(s.loc, "closures are not yet supported in CTFE");
983 result = CTFEExp.cantexp;
984 return;
987 // We need to treat pointers specially, because EXP.symbolOffset can be used to
988 // return a value OR a pointer
989 Expression e = interpret(pue, s.exp, istate);
990 if (exceptionOrCant(e))
991 return;
994 * Interpret `return a ~= b` (i.e. `return _d_arrayappendT{,Trace}(a, b)`) as:
995 * a ~= b;
996 * return a;
997 * This is needed because `a ~= b` has to be interpreted as an lvalue, in order to avoid
998 * assigning a larger array into a smaller one, such as:
999 * `a = [1, 2], a ~= [3]` => `[1, 2] ~= [3]` => `[1, 2] = [1, 2, 3]`
1001 if (isRuntimeHook(s.exp, Id._d_arrayappendT) || isRuntimeHook(s.exp, Id._d_arrayappendTTrace))
1003 auto rs = new ReturnStatement(s.loc, e);
1004 visitReturn(rs);
1005 return;
1008 // Disallow returning pointers to stack-allocated variables (bug 7876)
1009 if (!stopPointersEscaping(s.loc, e))
1011 result = CTFEExp.cantexp;
1012 return;
1015 if (needToCopyLiteral(e))
1016 e = copyLiteral(e).copy();
1017 debug (LOGASSIGN)
1019 printf("RETURN %s\n", s.loc.toChars());
1020 showCtfeExpr(e);
1022 result = e;
1025 void visitBreak(BreakStatement s)
1027 debug (LOG)
1029 printf("%s BreakStatement::interpret()\n", s.loc.toChars());
1031 incUsageCtfe(istate, s.loc);
1032 if (istate.start)
1034 if (istate.start != s)
1035 return;
1036 istate.start = null;
1039 istate.gotoTarget = findGotoTarget(istate, s.ident);
1040 result = CTFEExp.breakexp;
1043 void visitContinue(ContinueStatement s)
1045 debug (LOG)
1047 printf("%s ContinueStatement::interpret()\n", s.loc.toChars());
1049 incUsageCtfe(istate, s.loc);
1050 if (istate.start)
1052 if (istate.start != s)
1053 return;
1054 istate.start = null;
1057 istate.gotoTarget = findGotoTarget(istate, s.ident);
1058 result = CTFEExp.continueexp;
1061 void visitWhile(WhileStatement s)
1063 debug (LOG)
1065 printf("WhileStatement::interpret()\n");
1067 assert(0); // rewritten to ForStatement
1070 void visitDo(DoStatement s)
1072 debug (LOG)
1074 printf("%s DoStatement::interpret()\n", s.loc.toChars());
1076 if (istate.start == s)
1077 istate.start = null;
1079 while (1)
1081 Expression e = interpretStatement(s._body, istate);
1082 if (!e && istate.start) // goto target was not found
1083 return;
1084 assert(!istate.start);
1086 if (exceptionOrCant(e))
1087 return;
1088 if (e && e.op == EXP.break_)
1090 if (istate.gotoTarget && istate.gotoTarget != s)
1092 result = e; // break at a higher level
1093 return;
1095 istate.gotoTarget = null;
1096 break;
1098 if (e && e.op == EXP.continue_)
1100 if (istate.gotoTarget && istate.gotoTarget != s)
1102 result = e; // continue at a higher level
1103 return;
1105 istate.gotoTarget = null;
1106 e = null;
1108 if (e)
1110 result = e; // bubbled up from ReturnStatement
1111 return;
1114 UnionExp ue = void;
1115 incUsageCtfe(istate, s.condition.loc);
1116 e = interpret(&ue, s.condition, istate);
1117 if (exceptionOrCant(e))
1118 return;
1119 if (!e.isConst())
1121 result = CTFEExp.cantexp;
1122 return;
1124 if (e.toBool().hasValue(false))
1125 break;
1126 assert(isTrueBool(e));
1128 assert(result is null);
1131 void visitFor(ForStatement s)
1133 debug (LOG)
1135 printf("%s ForStatement::interpret()\n", s.loc.toChars());
1137 if (istate.start == s)
1138 istate.start = null;
1140 UnionExp ueinit = void;
1141 Expression ei = interpretStatement(&ueinit, s._init, istate);
1142 if (exceptionOrCant(ei))
1143 return;
1144 assert(!ei); // s.init never returns from function, or jumps out from it
1146 while (1)
1148 if (s.condition && !istate.start)
1150 UnionExp ue = void;
1151 incUsageCtfe(istate, s.condition.loc);
1152 Expression e = interpret(&ue, s.condition, istate);
1153 if (exceptionOrCant(e))
1154 return;
1155 if (e.toBool().hasValue(false))
1156 break;
1157 assert(isTrueBool(e));
1160 Expression e = interpretStatement(pue, s._body, istate);
1161 if (!e && istate.start) // goto target was not found
1162 return;
1163 assert(!istate.start);
1165 if (exceptionOrCant(e))
1166 return;
1167 if (e && e.op == EXP.break_)
1169 if (istate.gotoTarget && istate.gotoTarget != s)
1171 result = e; // break at a higher level
1172 return;
1174 istate.gotoTarget = null;
1175 break;
1177 if (e && e.op == EXP.continue_)
1179 if (istate.gotoTarget && istate.gotoTarget != s)
1181 result = e; // continue at a higher level
1182 return;
1184 istate.gotoTarget = null;
1185 e = null;
1187 if (e)
1189 result = e; // bubbled up from ReturnStatement
1190 return;
1193 UnionExp uei = void;
1194 if (s.increment)
1195 incUsageCtfe(istate, s.increment.loc);
1196 e = interpret(&uei, s.increment, istate, CTFEGoal.Nothing);
1197 if (exceptionOrCant(e))
1198 return;
1200 assert(result is null);
1203 void visitForeach(ForeachStatement s)
1205 assert(0); // rewritten to ForStatement
1208 void visitForeachRange(ForeachRangeStatement s)
1210 assert(0); // rewritten to ForStatement
1213 void visitSwitch(SwitchStatement s)
1215 debug (LOG)
1217 printf("%s SwitchStatement::interpret()\n", s.loc.toChars());
1219 incUsageCtfe(istate, s.loc);
1220 if (istate.start == s)
1221 istate.start = null;
1222 if (istate.start)
1224 Expression e = interpretStatement(s._body, istate);
1225 if (istate.start) // goto target was not found
1226 return;
1227 if (exceptionOrCant(e))
1228 return;
1229 if (e && e.op == EXP.break_)
1231 if (istate.gotoTarget && istate.gotoTarget != s)
1233 result = e; // break at a higher level
1234 return;
1236 istate.gotoTarget = null;
1237 e = null;
1239 result = e;
1240 return;
1243 UnionExp uecond = void;
1244 Expression econdition = interpret(&uecond, s.condition, istate);
1245 if (exceptionOrCant(econdition))
1246 return;
1248 Statement scase = null;
1249 if (s.cases)
1250 foreach (cs; *s.cases)
1252 UnionExp uecase = void;
1253 Expression ecase = interpret(&uecase, cs.exp, istate);
1254 if (exceptionOrCant(ecase))
1255 return;
1256 if (ctfeEqual(cs.exp.loc, EXP.equal, econdition, ecase))
1258 scase = cs;
1259 break;
1262 if (!scase)
1264 if (!s.hasDefault)
1265 error(s.loc, "no `default` or `case` for `%s` in `switch` statement", econdition.toChars());
1266 scase = s.sdefault;
1269 assert(scase);
1271 /* Jump to scase
1273 istate.start = scase;
1274 Expression e = interpretStatement(pue, s._body, istate);
1275 assert(!istate.start); // jump must not fail
1276 if (e && e.op == EXP.break_)
1278 if (istate.gotoTarget && istate.gotoTarget != s)
1280 result = e; // break at a higher level
1281 return;
1283 istate.gotoTarget = null;
1284 e = null;
1286 result = e;
1289 void visitCase(CaseStatement s)
1291 debug (LOG)
1293 printf("%s CaseStatement::interpret(%s) this = %p\n", s.loc.toChars(), s.exp.toChars(), s);
1295 incUsageCtfe(istate, s.loc);
1296 if (istate.start == s)
1297 istate.start = null;
1299 result = interpretStatement(pue, s.statement, istate);
1302 void visitDefault(DefaultStatement s)
1304 debug (LOG)
1306 printf("%s DefaultStatement::interpret()\n", s.loc.toChars());
1308 incUsageCtfe(istate, s.loc);
1309 if (istate.start == s)
1310 istate.start = null;
1312 result = interpretStatement(pue, s.statement, istate);
1315 void visitGoto(GotoStatement s)
1317 debug (LOG)
1319 printf("%s GotoStatement::interpret()\n", s.loc.toChars());
1321 if (istate.start)
1323 if (istate.start != s)
1324 return;
1325 istate.start = null;
1327 incUsageCtfe(istate, s.loc);
1329 assert(s.label && s.label.statement);
1330 istate.gotoTarget = s.label.statement;
1331 result = CTFEExp.gotoexp;
1334 void visitGotoCase(GotoCaseStatement s)
1336 debug (LOG)
1338 printf("%s GotoCaseStatement::interpret()\n", s.loc.toChars());
1340 if (istate.start)
1342 if (istate.start != s)
1343 return;
1344 istate.start = null;
1346 incUsageCtfe(istate, s.loc);
1348 assert(s.cs);
1349 istate.gotoTarget = s.cs;
1350 result = CTFEExp.gotoexp;
1353 void visitGotoDefault(GotoDefaultStatement s)
1355 debug (LOG)
1357 printf("%s GotoDefaultStatement::interpret()\n", s.loc.toChars());
1359 if (istate.start)
1361 if (istate.start != s)
1362 return;
1363 istate.start = null;
1365 incUsageCtfe(istate, s.loc);
1367 assert(s.sw && s.sw.sdefault);
1368 istate.gotoTarget = s.sw.sdefault;
1369 result = CTFEExp.gotoexp;
1372 void visitLabel(LabelStatement s)
1374 debug (LOG)
1376 printf("%s LabelStatement::interpret()\n", s.loc.toChars());
1378 if (istate.start == s)
1379 istate.start = null;
1381 result = interpretStatement(pue, s.statement, istate);
1384 void visitTryCatch(TryCatchStatement s)
1386 debug (LOG)
1388 printf("%s TryCatchStatement::interpret()\n", s.loc.toChars());
1390 if (istate.start == s)
1391 istate.start = null;
1392 if (istate.start)
1394 Expression e = null;
1395 e = interpretStatement(pue, s._body, istate);
1396 foreach (ca; *s.catches)
1398 if (e || !istate.start) // goto target was found
1399 break;
1400 e = interpretStatement(pue, ca.handler, istate);
1402 result = e;
1403 return;
1406 Expression e = interpretStatement(s._body, istate);
1408 // An exception was thrown
1409 if (e && e.isThrownExceptionExp())
1411 ThrownExceptionExp ex = e.isThrownExceptionExp();
1412 Type extype = ex.thrown.originalClass().type;
1414 // Search for an appropriate catch clause.
1415 foreach (ca; *s.catches)
1417 Type catype = ca.type;
1418 if (!catype.equals(extype) && !catype.isBaseOf(extype, null))
1419 continue;
1421 // Execute the handler
1422 if (ca.var)
1424 ctfeGlobals.stack.push(ca.var);
1425 setValue(ca.var, ex.thrown);
1427 e = interpretStatement(ca.handler, istate);
1428 while (CTFEExp.isGotoExp(e))
1430 /* This is an optimization that relies on the locality of the jump target.
1431 * If the label is in the same catch handler, the following scan
1432 * would find it quickly and can reduce jump cost.
1433 * Otherwise, the catch block may be unnnecessary scanned again
1434 * so it would make CTFE speed slower.
1436 InterState istatex = *istate;
1437 istatex.start = istate.gotoTarget; // set starting statement
1438 istatex.gotoTarget = null;
1439 Expression eh = interpretStatement(ca.handler, &istatex);
1440 if (istatex.start)
1442 // The goto target is outside the current scope.
1443 break;
1445 // The goto target was within the body.
1446 if (CTFEExp.isCantExp(eh))
1448 e = eh;
1449 break;
1451 *istate = istatex;
1452 e = eh;
1454 break;
1457 result = e;
1460 void visitTryFinally(TryFinallyStatement s)
1462 debug (LOG)
1464 printf("%s TryFinallyStatement::interpret()\n", s.loc.toChars());
1466 if (istate.start == s)
1467 istate.start = null;
1468 if (istate.start)
1470 Expression e = null;
1471 e = interpretStatement(pue, s._body, istate);
1472 // Jump into/out from finalbody is disabled in semantic analysis.
1473 // and jump inside will be handled by the ScopeStatement == finalbody.
1474 result = e;
1475 return;
1478 Expression ex = interpretStatement(s._body, istate);
1479 if (CTFEExp.isCantExp(ex))
1481 result = ex;
1482 return;
1484 while (CTFEExp.isGotoExp(ex))
1486 // If the goto target is within the body, we must not interpret the finally statement,
1487 // because that will call destructors for objects within the scope, which we should not do.
1488 InterState istatex = *istate;
1489 istatex.start = istate.gotoTarget; // set starting statement
1490 istatex.gotoTarget = null;
1491 Expression bex = interpretStatement(s._body, &istatex);
1492 if (istatex.start)
1494 // The goto target is outside the current scope.
1495 break;
1497 // The goto target was within the body.
1498 if (CTFEExp.isCantExp(bex))
1500 result = bex;
1501 return;
1503 *istate = istatex;
1504 ex = bex;
1507 Expression ey = interpretStatement(s.finalbody, istate);
1508 if (CTFEExp.isCantExp(ey))
1510 result = ey;
1511 return;
1513 if (ey && ey.isThrownExceptionExp())
1515 // Check for collided exceptions
1516 if (ex && ex.isThrownExceptionExp())
1517 ex = chainExceptions(ex.isThrownExceptionExp(), ey.isThrownExceptionExp());
1518 else
1519 ex = ey;
1521 result = ex;
1524 void visitThrow(ThrowStatement s)
1526 debug (LOG)
1528 printf("%s ThrowStatement::interpret()\n", s.loc.toChars());
1530 if (istate.start)
1532 if (istate.start != s)
1533 return;
1534 istate.start = null;
1537 interpretThrow(result, s.exp, s.loc, istate);
1540 void visitScopeGuard(ScopeGuardStatement s)
1542 assert(0);
1545 void visitWith(WithStatement s)
1547 debug (LOG)
1549 printf("%s WithStatement::interpret()\n", s.loc.toChars());
1551 if (istate.start == s)
1552 istate.start = null;
1553 if (istate.start)
1555 result = s._body ? interpretStatement(s._body, istate) : null;
1556 return;
1559 // If it is with(Enum) {...}, just execute the body.
1560 if (s.exp.op == EXP.scope_ || s.exp.op == EXP.type)
1562 result = interpretStatement(pue, s._body, istate);
1563 return;
1566 incUsageCtfe(istate, s.loc);
1568 Expression e = interpret(s.exp, istate);
1569 if (exceptionOrCant(e))
1570 return;
1572 if (s.wthis.type.ty == Tpointer && s.exp.type.ty != Tpointer)
1574 e = ctfeEmplaceExp!AddrExp(s.loc, e, s.wthis.type);
1576 ctfeGlobals.stack.push(s.wthis);
1577 setValue(s.wthis, e);
1578 e = interpretStatement(s._body, istate);
1579 while (CTFEExp.isGotoExp(e))
1581 /* This is an optimization that relies on the locality of the jump target.
1582 * If the label is in the same WithStatement, the following scan
1583 * would find it quickly and can reduce jump cost.
1584 * Otherwise, the statement body may be unnnecessary scanned again
1585 * so it would make CTFE speed slower.
1587 InterState istatex = *istate;
1588 istatex.start = istate.gotoTarget; // set starting statement
1589 istatex.gotoTarget = null;
1590 Expression ex = interpretStatement(s._body, &istatex);
1591 if (istatex.start)
1593 // The goto target is outside the current scope.
1594 break;
1596 // The goto target was within the body.
1597 if (CTFEExp.isCantExp(ex))
1599 e = ex;
1600 break;
1602 *istate = istatex;
1603 e = ex;
1605 ctfeGlobals.stack.pop(s.wthis);
1606 result = e;
1609 void visitAsm(AsmStatement s)
1611 debug (LOG)
1613 printf("%s AsmStatement::interpret()\n", s.loc.toChars());
1615 if (istate.start)
1617 if (istate.start != s)
1618 return;
1619 istate.start = null;
1621 error(s.loc, "`asm` statements cannot be interpreted at compile time");
1622 result = CTFEExp.cantexp;
1625 void visitInlineAsm(InlineAsmStatement s)
1627 visitAsm(s);
1630 void visitGccAsm(GccAsmStatement s)
1632 visitAsm(s);
1635 void visitImport(ImportStatement s)
1637 debug (LOG)
1639 printf("ImportStatement::interpret()\n");
1641 if (istate.start)
1643 if (istate.start != s)
1644 return;
1645 istate.start = null;
1649 if (!s)
1650 return null;
1652 mixin VisitStatement!void visit;
1653 visit.VisitStatement(s);
1654 return result;
1659 private extern (C++) final class Interpreter : Visitor
1661 alias visit = Visitor.visit;
1662 public:
1663 InterState* istate;
1664 CTFEGoal goal;
1665 Expression result;
1666 UnionExp* pue; // storage for `result`
1668 extern (D) this(UnionExp* pue, InterState* istate, CTFEGoal goal) scope @safe
1670 this.pue = pue;
1671 this.istate = istate;
1672 this.goal = goal;
1675 // If e is EXP.throw_exception or EXP.cantExpression,
1676 // set it to 'result' and returns true.
1677 bool exceptionOrCant(Expression e)
1679 if (exceptionOrCantInterpret(e))
1681 // Make sure e is not pointing to a stack temporary
1682 result = (e.op == EXP.cantExpression) ? CTFEExp.cantexp : e;
1683 return true;
1685 return false;
1688 /******************************** Expression ***************************/
1690 override void visit(Expression e)
1692 debug (LOG)
1694 printf("%s Expression::interpret() '%s' %s\n", e.loc.toChars(), EXPtoString(e.op).ptr, e.toChars());
1695 printf("type = %s\n", e.type.toChars());
1696 showCtfeExpr(e);
1698 error(e.loc, "cannot interpret `%s` at compile time", e.toChars());
1699 result = CTFEExp.cantexp;
1702 override void visit(TypeExp e)
1704 debug (LOG)
1706 printf("%s TypeExp.interpret() %s\n", e.loc.toChars(), e.toChars());
1708 result = e;
1711 override void visit(ThisExp e)
1713 debug (LOG)
1715 printf("%s ThisExp::interpret() %s\n", e.loc.toChars(), e.toChars());
1717 if (goal == CTFEGoal.LValue)
1719 // We might end up here with istate being zero
1720 // https://issues.dlang.org/show_bug.cgi?id=16382
1721 if (istate && istate.fd.vthis)
1723 result = ctfeEmplaceExp!VarExp(e.loc, istate.fd.vthis);
1724 if (istate.fd.hasDualContext())
1726 result = ctfeEmplaceExp!PtrExp(e.loc, result);
1727 result.type = Type.tvoidptr.sarrayOf(2);
1728 result = ctfeEmplaceExp!IndexExp(e.loc, result, IntegerExp.literal!0);
1730 result.type = e.type;
1732 else
1733 result = e;
1734 return;
1737 result = ctfeGlobals.stack.getThis();
1738 if (result)
1740 if (istate && istate.fd.hasDualContext())
1742 assert(result.op == EXP.address);
1743 result = result.isAddrExp().e1;
1744 assert(result.op == EXP.arrayLiteral);
1745 result = (*result.isArrayLiteralExp().elements)[0];
1746 if (e.type.ty == Tstruct)
1748 result = result.isAddrExp().e1;
1750 return;
1752 assert(result.op == EXP.structLiteral || result.op == EXP.classReference || result.op == EXP.type);
1753 return;
1755 error(e.loc, "value of `this` is not known at compile time");
1756 result = CTFEExp.cantexp;
1759 override void visit(NullExp e)
1761 result = e;
1764 override void visit(IntegerExp e)
1766 debug (LOG)
1768 printf("%s IntegerExp::interpret() %s\n", e.loc.toChars(), e.toChars());
1770 result = e;
1773 override void visit(RealExp e)
1775 debug (LOG)
1777 printf("%s RealExp::interpret() %s\n", e.loc.toChars(), e.toChars());
1779 result = e;
1782 override void visit(ComplexExp e)
1784 result = e;
1787 override void visit(StringExp e)
1789 debug (LOG)
1791 printf("%s StringExp::interpret() %s\n", e.loc.toChars(), e.toChars());
1793 if (e.ownedByCtfe >= OwnedBy.ctfe) // We've already interpreted the string
1795 result = e;
1796 return;
1799 if (e.type.ty != Tsarray ||
1800 (cast(TypeNext)e.type).next.mod & (MODFlags.const_ | MODFlags.immutable_))
1802 // If it's immutable, we don't need to dup it. Attempts to modify
1803 // string literals are prevented in BinExp::interpretAssignCommon.
1804 result = e;
1806 else
1808 // https://issues.dlang.org/show_bug.cgi?id=20811
1809 // Create a copy of mutable string literals, so that any change in
1810 // value via an index or slice will not survive CTFE.
1811 *pue = copyLiteral(e);
1812 result = pue.exp();
1816 override void visit(FuncExp e)
1818 debug (LOG)
1820 printf("%s FuncExp::interpret() %s\n", e.loc.toChars(), e.toChars());
1822 result = e;
1825 override void visit(SymOffExp e)
1827 debug (LOG)
1829 printf("%s SymOffExp::interpret() %s\n", e.loc.toChars(), e.toChars());
1831 if (e.var.isFuncDeclaration() && e.offset == 0)
1833 result = e;
1834 return;
1836 if (isTypeInfo_Class(e.type) && e.offset == 0)
1838 result = e;
1839 return;
1841 if (e.type.ty != Tpointer)
1843 // Probably impossible
1844 error(e.loc, "cannot interpret `%s` at compile time", e.toChars());
1845 result = CTFEExp.cantexp;
1846 return;
1848 Type pointee = (cast(TypePointer)e.type).next;
1849 if (e.var.isThreadlocal())
1851 error(e.loc, "cannot take address of thread-local variable %s at compile time", e.var.toChars());
1852 result = CTFEExp.cantexp;
1853 return;
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)) ||
1863 (fromType && isSafePointerCast(fromType, pointee)) ||
1864 (e.var.isCsymbol() && e.offset + pointee.size() <= e.var.type.size())))
1866 result = e;
1867 return;
1870 Expression val = getVarExp(e.loc, istate, e.var, goal);
1871 if (exceptionOrCant(val))
1872 return;
1873 if (val.type.ty == Tarray || val.type.ty == Tsarray)
1875 // Check for unsupported type painting operations
1876 Type elemtype = (cast(TypeArray)val.type).next;
1877 const elemsize = elemtype.size();
1879 // It's OK to cast from fixed length to fixed length array, eg &int[n] to int[d]*.
1880 if (val.type.ty == Tsarray && pointee.ty == Tsarray && elemsize == pointee.nextOf().size())
1882 size_t d = cast(size_t)(cast(TypeSArray)pointee).dim.toInteger();
1883 Expression elwr = ctfeEmplaceExp!IntegerExp(e.loc, e.offset / elemsize, Type.tsize_t);
1884 Expression eupr = ctfeEmplaceExp!IntegerExp(e.loc, e.offset / elemsize + d, Type.tsize_t);
1886 // Create a CTFE pointer &val[ofs..ofs+d]
1887 auto se = ctfeEmplaceExp!SliceExp(e.loc, val, elwr, eupr);
1888 se.type = pointee;
1889 emplaceExp!(AddrExp)(pue, e.loc, se, e.type);
1890 result = pue.exp();
1891 return;
1894 if (!isSafePointerCast(elemtype, pointee))
1896 // It's also OK to cast from &string to string*.
1897 if (e.offset == 0 && isSafePointerCast(e.var.type, pointee))
1899 // Create a CTFE pointer &var
1900 auto ve = ctfeEmplaceExp!VarExp(e.loc, e.var);
1901 ve.type = elemtype;
1902 emplaceExp!(AddrExp)(pue, e.loc, ve, e.type);
1903 result = pue.exp();
1904 return;
1906 error(e.loc, "reinterpreting cast from `%s` to `%s` is not supported in CTFE", val.type.toChars(), e.type.toChars());
1907 result = CTFEExp.cantexp;
1908 return;
1911 const dinteger_t sz = pointee.size();
1912 dinteger_t indx = e.offset / sz;
1913 assert(sz * indx == e.offset);
1914 Expression aggregate = null;
1915 if (val.op == EXP.arrayLiteral || val.op == EXP.string_)
1917 aggregate = val;
1919 else if (auto se = val.isSliceExp())
1921 aggregate = se.e1;
1922 UnionExp uelwr = void;
1923 Expression lwr = interpret(&uelwr, se.lwr, istate);
1924 indx += lwr.toInteger();
1926 if (aggregate)
1928 // Create a CTFE pointer &aggregate[ofs]
1929 auto ofs = ctfeEmplaceExp!IntegerExp(e.loc, indx, Type.tsize_t);
1930 auto ei = ctfeEmplaceExp!IndexExp(e.loc, aggregate, ofs);
1931 ei.type = elemtype;
1932 emplaceExp!(AddrExp)(pue, e.loc, ei, e.type);
1933 result = pue.exp();
1934 return;
1937 else if (e.offset == 0 && isSafePointerCast(e.var.type, pointee))
1939 // Create a CTFE pointer &var
1940 auto ve = ctfeEmplaceExp!VarExp(e.loc, e.var);
1941 ve.type = e.var.type;
1942 emplaceExp!(AddrExp)(pue, e.loc, ve, e.type);
1943 result = pue.exp();
1944 return;
1947 error(e.loc, "cannot convert `&%s` to `%s` at compile time", e.var.type.toChars(), e.type.toChars());
1948 result = CTFEExp.cantexp;
1951 override void visit(AddrExp e)
1953 debug (LOG)
1955 printf("%s AddrExp::interpret() %s\n", e.loc.toChars(), e.toChars());
1957 if (auto ve = e.e1.isVarExp())
1959 Declaration decl = ve.var;
1961 // We cannot take the address of an imported symbol at compile time
1962 if (decl.isImportedSymbol()) {
1963 error(e.loc, "cannot take address of imported symbol `%s` at compile time", decl.toChars());
1964 result = CTFEExp.cantexp;
1965 return;
1968 if (decl.isDataseg()) {
1969 // Normally this is already done by optimize()
1970 // Do it here in case optimize(WANTvalue) wasn't run before CTFE
1971 emplaceExp!(SymOffExp)(pue, e.loc, e.e1.isVarExp().var, 0);
1972 result = pue.exp();
1973 result.type = e.type;
1974 return;
1977 auto er = interpret(e.e1, istate, CTFEGoal.LValue);
1978 if (auto ve = er.isVarExp())
1979 if (istate && ve.var == istate.fd.vthis)
1980 er = interpret(er, istate);
1982 if (exceptionOrCant(er))
1983 return;
1985 // Return a simplified address expression
1986 emplaceExp!(AddrExp)(pue, e.loc, er, e.type);
1987 result = pue.exp();
1990 override void visit(DelegateExp e)
1992 debug (LOG)
1994 printf("%s DelegateExp::interpret() %s\n", e.loc.toChars(), e.toChars());
1996 // TODO: Really we should create a CTFE-only delegate expression
1997 // of a pointer and a funcptr.
1999 // If it is &nestedfunc, just return it
2000 // TODO: We should save the context pointer
2001 if (auto ve1 = e.e1.isVarExp())
2002 if (ve1.var == e.func)
2004 result = e;
2005 return;
2008 auto er = interpret(pue, e.e1, istate);
2009 if (exceptionOrCant(er))
2010 return;
2011 if (er == e.e1)
2013 // If it has already been CTFE'd, just return it
2014 result = e;
2016 else
2018 er = (er == pue.exp()) ? pue.copy() : er;
2019 emplaceExp!(DelegateExp)(pue, e.loc, er, e.func, false);
2020 result = pue.exp();
2021 result.type = e.type;
2025 static Expression getVarExp(const ref Loc loc, InterState* istate, Declaration d, CTFEGoal goal)
2027 Expression e = CTFEExp.cantexp;
2028 if (VarDeclaration v = d.isVarDeclaration())
2030 /* Magic variable __ctfe always returns true when interpreting
2032 if (v.ident == Id.ctfe)
2033 return IntegerExp.createBool(true);
2035 if (!v.originalType && v.semanticRun < PASS.semanticdone) // semantic() not yet run
2037 v.dsymbolSemantic(null);
2038 if (v.type.ty == Terror)
2039 return CTFEExp.cantexp;
2042 if ((v.isConst() || v.isImmutable() || v.storage_class & STC.manifest) && !hasValue(v) && v._init && !v.isCTFE())
2044 if (v.inuse)
2046 error(loc, "circular initialization of %s `%s`", v.kind(), v.toPrettyChars());
2047 return CTFEExp.cantexp;
2049 if (v._scope)
2051 v.inuse++;
2052 v._init = v._init.initializerSemantic(v._scope, v.type, INITinterpret); // might not be run on aggregate members
2053 v.inuse--;
2055 e = v._init.initializerToExpression(v.type);
2056 if (!e)
2057 return CTFEExp.cantexp;
2058 assert(e.type);
2060 // There's a terrible hack in `dmd.dsymbolsem` that special case
2061 // a struct with all zeros to an `ExpInitializer(BlitExp(IntegerExp(0)))`
2062 // There's matching code for it in e2ir (toElem's visitAssignExp),
2063 // so we need the same hack here.
2064 // This does not trigger for global as they get a normal initializer.
2065 if (auto ts = e.type.isTypeStruct())
2066 if (auto ae = e.isBlitExp())
2067 if (ae.e2.op == EXP.int64)
2068 e = ts.defaultInitLiteral(loc);
2070 if (e.op == EXP.construct || e.op == EXP.blit)
2072 AssignExp ae = cast(AssignExp)e;
2073 e = ae.e2;
2076 if (e.op == EXP.error)
2078 // FIXME: Ultimately all errors should be detected in prior semantic analysis stage.
2080 else if (v.isDataseg() || (v.storage_class & STC.manifest))
2082 /* https://issues.dlang.org/show_bug.cgi?id=14304
2083 * e is a value that is not yet owned by CTFE.
2084 * Mark as "cached", and use it directly during interpretation.
2086 e = scrubCacheValue(e);
2087 ctfeGlobals.stack.saveGlobalConstant(v, e);
2089 else
2091 v.inuse++;
2092 e = interpret(e, istate);
2093 v.inuse--;
2094 if (CTFEExp.isCantExp(e) && !global.gag && !ctfeGlobals.stackTraceCallsToSuppress)
2095 errorSupplemental(loc, "while evaluating %s.init", v.toChars());
2096 if (exceptionOrCantInterpret(e))
2097 return e;
2100 else if (v.isCTFE() && !hasValue(v))
2102 if (v._init && v.type.size() != 0)
2104 if (v._init.isVoidInitializer())
2106 // var should have been initialized when it was created
2107 error(loc, "CTFE internal error: trying to access uninitialized var");
2108 assert(0);
2110 e = v._init.initializerToExpression();
2112 else
2113 // Zero-length arrays don't have an initializer
2114 e = v.type.defaultInitLiteral(e.loc);
2116 e = interpret(e, istate);
2118 else if (!(v.isDataseg() || v.storage_class & STC.manifest) && !v.isCTFE() && !istate)
2120 error(loc, "variable `%s` cannot be read at compile time", v.toChars());
2121 return CTFEExp.cantexp;
2123 else
2125 e = hasValue(v) ? getValue(v) : null;
2126 if (!e)
2128 // Zero-length arrays don't have an initializer
2129 if (v.type.size() == 0)
2130 e = v.type.defaultInitLiteral(loc);
2131 else if (!v.isCTFE() && v.isDataseg())
2133 error(loc, "static variable `%s` cannot be read at compile time", v.toChars());
2134 return CTFEExp.cantexp;
2136 else
2138 assert(!(v._init && v._init.isVoidInitializer()));
2139 // CTFE initiated from inside a function
2140 error(loc, "variable `%s` cannot be read at compile time", v.toChars());
2141 return CTFEExp.cantexp;
2144 if (auto vie = e.isVoidInitExp())
2146 error(loc, "cannot read uninitialized variable `%s` in ctfe", v.toPrettyChars());
2147 errorSupplemental(vie.var.loc, "`%s` was uninitialized and used before set", vie.var.toChars());
2148 return CTFEExp.cantexp;
2150 if (goal != CTFEGoal.LValue && v.isReference())
2151 e = interpret(e, istate, goal);
2153 if (!e)
2154 e = CTFEExp.cantexp;
2156 else if (SymbolDeclaration s = d.isSymbolDeclaration())
2158 // exclude void[]-typed `__traits(initSymbol)`
2159 if (auto ta = s.type.toBasetype().isTypeDArray())
2161 assert(ta.next.ty == Tvoid);
2162 error(loc, "cannot determine the address of the initializer symbol during CTFE");
2163 return CTFEExp.cantexp;
2166 // Struct static initializers, for example
2167 e = s.dsym.type.defaultInitLiteral(loc);
2168 if (e.op == EXP.error)
2169 error(loc, "CTFE failed because of previous errors in `%s.init`", s.toChars());
2170 e = e.expressionSemantic(null);
2171 if (e.op == EXP.error)
2172 e = CTFEExp.cantexp;
2173 else // Convert NULL to CTFEExp
2174 e = interpret(e, istate, goal);
2176 else
2177 error(loc, "cannot interpret declaration `%s` at compile time", d.toChars());
2178 return e;
2181 override void visit(VarExp e)
2183 debug (LOG)
2185 printf("%s VarExp::interpret() `%s`, goal = %d\n", e.loc.toChars(), e.toChars(), goal);
2187 if (e.var.isFuncDeclaration())
2189 result = e;
2190 return;
2193 if (goal == CTFEGoal.LValue)
2195 if (auto v = e.var.isVarDeclaration())
2197 if (!hasValue(v))
2199 // Compile-time known non-CTFE variable from an outer context
2200 // e.g. global or from a ref argument
2201 if (v.isConst() || v.isImmutable())
2203 result = getVarExp(e.loc, istate, v, goal);
2204 return;
2207 if (!v.isCTFE() && v.isDataseg())
2208 error(e.loc, "static variable `%s` cannot be read at compile time", v.toChars());
2209 else // CTFE initiated from inside a function
2210 error(e.loc, "variable `%s` cannot be read at compile time", v.toChars());
2211 result = CTFEExp.cantexp;
2212 return;
2215 if (v.storage_class & (STC.out_ | STC.ref_))
2217 // Strip off the nest of ref variables
2218 Expression ev = getValue(v);
2219 if (ev.op == EXP.variable ||
2220 ev.op == EXP.index ||
2221 (ev.op == EXP.slice && ev.type.toBasetype().ty == Tsarray) ||
2222 ev.op == EXP.dotVariable)
2224 result = interpret(pue, ev, istate, goal);
2225 return;
2229 result = e;
2230 return;
2232 result = getVarExp(e.loc, istate, e.var, goal);
2233 if (exceptionOrCant(result))
2234 return;
2236 // Visit the default initializer for noreturn variables
2237 // (Custom initializers would abort the current function call and exit above)
2238 if (result.type.ty == Tnoreturn)
2240 result.accept(this);
2241 return;
2244 if ((e.var.storage_class & (STC.ref_ | STC.out_)) == 0 && e.type.baseElemOf().ty != Tstruct)
2246 /* Ultimately, STC.ref_|STC.out_ check should be enough to see the
2247 * necessity of type repainting. But currently front-end paints
2248 * non-ref struct variables by the const type.
2250 * auto foo(ref const S cs);
2251 * S s;
2252 * foo(s); // VarExp('s') will have const(S)
2254 // A VarExp may include an implicit cast. It must be done explicitly.
2255 result = paintTypeOntoLiteral(pue, e.type, result);
2259 override void visit(DeclarationExp e)
2261 debug (LOG)
2263 printf("%s DeclarationExp::interpret() %s\n", e.loc.toChars(), e.toChars());
2265 Dsymbol s = e.declaration;
2266 while (s.isAttribDeclaration())
2268 auto ad = cast(AttribDeclaration)s;
2269 assert(ad.decl && ad.decl.length == 1); // Currently, only one allowed when parsing
2270 s = (*ad.decl)[0];
2272 if (VarDeclaration v = s.isVarDeclaration())
2274 if (TupleDeclaration td = v.toAlias().isTupleDeclaration())
2276 result = null;
2278 // Reserve stack space for all tuple members
2279 td.foreachVar((s)
2281 VarDeclaration v2 = s.isVarDeclaration();
2282 assert(v2);
2283 if (v2.isDataseg() && !v2.isCTFE())
2284 return 0;
2286 ctfeGlobals.stack.push(v2);
2287 if (v2._init)
2289 Expression einit;
2290 if (ExpInitializer ie = v2._init.isExpInitializer())
2292 einit = interpretRegion(ie.exp, istate, goal);
2293 if (exceptionOrCant(einit))
2294 return 1;
2296 else if (v2._init.isVoidInitializer())
2298 einit = voidInitLiteral(v2.type, v2).copy();
2300 else
2302 error(e.loc, "declaration `%s` is not yet implemented in CTFE", e.toChars());
2303 result = CTFEExp.cantexp;
2304 return 1;
2306 setValue(v2, einit);
2308 return 0;
2310 return;
2312 if (v.isStatic())
2314 // Just ignore static variables which aren't read or written yet
2315 result = null;
2316 return;
2318 if (!(v.isDataseg() || v.storage_class & STC.manifest) || v.isCTFE())
2319 ctfeGlobals.stack.push(v);
2320 if (v._init)
2322 if (ExpInitializer ie = v._init.isExpInitializer())
2324 result = interpretRegion(ie.exp, istate, goal);
2325 return;
2327 else if (v._init.isVoidInitializer())
2329 result = voidInitLiteral(v.type, v).copy();
2330 // There is no AssignExp for void initializers,
2331 // so set it here.
2332 setValue(v, result);
2333 return;
2335 else if (v._init.isArrayInitializer())
2337 result = v._init.initializerToExpression(v.type);
2338 if (result !is null)
2339 return;
2341 error(e.loc, "declaration `%s` is not yet implemented in CTFE", e.toChars());
2342 result = CTFEExp.cantexp;
2344 else if (v.type.size() == 0)
2346 // Zero-length arrays don't need an initializer
2347 result = v.type.defaultInitLiteral(e.loc);
2349 else
2351 error(e.loc, "variable `%s` cannot be modified at compile time", v.toChars());
2352 result = CTFEExp.cantexp;
2354 return;
2356 if (s.isTemplateMixin() || s.isTupleDeclaration())
2358 // These can be made to work, too lazy now
2359 error(e.loc, "declaration `%s` is not yet implemented in CTFE", e.toChars());
2360 result = CTFEExp.cantexp;
2361 return;
2364 // Others should not contain executable code, so are trivial to evaluate
2365 result = null;
2366 debug (LOG)
2368 printf("-DeclarationExp::interpret(%s): %p\n", e.toChars(), result);
2372 override void visit(TypeidExp e)
2374 debug (LOG)
2376 printf("%s TypeidExp::interpret() %s\n", e.loc.toChars(), e.toChars());
2378 if (Type t = isType(e.obj))
2380 result = e;
2381 return;
2383 if (Expression ex = isExpression(e.obj))
2385 result = interpret(pue, ex, istate);
2386 if (exceptionOrCant(ex))
2387 return;
2389 if (result.op == EXP.null_)
2391 error(e.loc, "null pointer dereference evaluating typeid. `%s` is `null`", ex.toChars());
2392 result = CTFEExp.cantexp;
2393 return;
2395 if (result.op != EXP.classReference)
2397 error(e.loc, "CTFE internal error: determining classinfo");
2398 result = CTFEExp.cantexp;
2399 return;
2402 ClassDeclaration cd = result.isClassReferenceExp().originalClass();
2403 assert(cd);
2405 emplaceExp!(TypeidExp)(pue, e.loc, cd.type);
2406 result = pue.exp();
2407 result.type = e.type;
2408 return;
2410 visit(cast(Expression)e);
2413 override void visit(TupleExp e)
2415 debug (LOG)
2417 printf("%s TupleExp::interpret() %s\n", e.loc.toChars(), e.toChars());
2419 if (exceptionOrCant(interpretRegion(e.e0, istate, CTFEGoal.Nothing)))
2420 return;
2422 auto expsx = e.exps;
2423 foreach (i, exp; *expsx)
2425 Expression ex = interpretRegion(exp, istate);
2426 if (exceptionOrCant(ex))
2427 return;
2429 // A tuple of assignments can contain void (Bug 5676).
2430 if (goal == CTFEGoal.Nothing)
2431 continue;
2432 if (ex.op == EXP.voidExpression)
2434 error(e.loc, "CTFE internal error: void element `%s` in sequence", exp.toChars());
2435 assert(0);
2438 /* If any changes, do Copy On Write
2440 if (ex !is exp)
2442 expsx = copyArrayOnWrite(expsx, e.exps);
2443 (*expsx)[i] = copyRegionExp(ex);
2447 if (expsx !is e.exps)
2449 expandTuples(expsx);
2450 emplaceExp!(TupleExp)(pue, e.loc, expsx);
2451 result = pue.exp();
2452 result.type = new TypeTuple(expsx);
2454 else
2455 result = e;
2458 override void visit(ArrayLiteralExp e)
2460 debug (LOG)
2462 printf("%s ArrayLiteralExp::interpret() %s, %s\n", e.loc.toChars(), e.type.toChars(), e.toChars());
2464 if (e.ownedByCtfe >= OwnedBy.ctfe) // We've already interpreted all the elements
2466 result = e;
2467 return;
2470 Type tb = e.type.toBasetype();
2471 Type tn = tb.nextOf().toBasetype();
2472 bool wantCopy = (tn.ty == Tsarray || tn.ty == Tstruct);
2474 auto basis = interpretRegion(e.basis, istate);
2475 if (exceptionOrCant(basis))
2476 return;
2478 auto expsx = e.elements;
2479 size_t dim = expsx ? expsx.length : 0;
2481 for (size_t i = 0; i < dim; i++)
2483 Expression exp = (*expsx)[i];
2484 Expression ex;
2485 if (!exp)
2487 ex = copyLiteral(basis).copy();
2489 else
2491 // segfault bug 6250
2492 assert(exp.op != EXP.index || exp.isIndexExp().e1 != e);
2494 ex = interpretRegion(exp, istate);
2495 if (exceptionOrCant(ex))
2496 return;
2498 /* Each elements should have distinct CTFE memory.
2499 * int[1] z = 7;
2500 * int[1][] pieces = [z,z]; // here
2502 if (wantCopy)
2503 ex = copyLiteral(ex).copy();
2506 /* If any changes, do Copy On Write
2508 if (ex !is exp)
2510 expsx = copyArrayOnWrite(expsx, e.elements);
2511 (*expsx)[i] = ex;
2515 if (expsx !is e.elements)
2517 // todo: all tuple expansions should go in semantic phase.
2518 expandTuples(expsx);
2519 if (expsx.length != dim)
2521 error(e.loc, "CTFE internal error: invalid array literal");
2522 result = CTFEExp.cantexp;
2523 return;
2525 emplaceExp!(ArrayLiteralExp)(pue, e.loc, e.type, basis, expsx);
2526 auto ale = pue.exp().isArrayLiteralExp();
2527 ale.ownedByCtfe = OwnedBy.ctfe;
2528 result = ale;
2530 else if ((cast(TypeNext)e.type).next.mod & (MODFlags.const_ | MODFlags.immutable_))
2532 // If it's immutable, we don't need to dup it
2533 result = e;
2535 else
2537 *pue = copyLiteral(e);
2538 result = pue.exp();
2542 override void visit(AssocArrayLiteralExp e)
2544 debug (LOG)
2546 printf("%s AssocArrayLiteralExp::interpret() %s\n", e.loc.toChars(), e.toChars());
2548 if (e.ownedByCtfe >= OwnedBy.ctfe) // We've already interpreted all the elements
2550 result = e;
2551 return;
2554 auto keysx = e.keys;
2555 auto valuesx = e.values;
2556 foreach (i, ekey; *keysx)
2558 auto evalue = (*valuesx)[i];
2560 auto ek = interpretRegion(ekey, istate);
2561 if (exceptionOrCant(ek))
2562 return;
2563 auto ev = interpretRegion(evalue, istate);
2564 if (exceptionOrCant(ev))
2565 return;
2567 /* If any changes, do Copy On Write
2569 if (ek !is ekey ||
2570 ev !is evalue)
2572 keysx = copyArrayOnWrite(keysx, e.keys);
2573 valuesx = copyArrayOnWrite(valuesx, e.values);
2574 (*keysx)[i] = ek;
2575 (*valuesx)[i] = ev;
2578 if (keysx !is e.keys)
2579 expandTuples(keysx);
2580 if (valuesx !is e.values)
2581 expandTuples(valuesx);
2582 if (keysx.length != valuesx.length)
2584 error(e.loc, "CTFE internal error: invalid AA");
2585 result = CTFEExp.cantexp;
2586 return;
2589 /* Remove duplicate keys
2591 for (size_t i = 1; i < keysx.length; i++)
2593 auto ekey = (*keysx)[i - 1];
2594 for (size_t j = i; j < keysx.length; j++)
2596 auto ekey2 = (*keysx)[j];
2597 if (!ctfeEqual(e.loc, EXP.equal, ekey, ekey2))
2598 continue;
2600 // Remove ekey
2601 keysx = copyArrayOnWrite(keysx, e.keys);
2602 valuesx = copyArrayOnWrite(valuesx, e.values);
2603 keysx.remove(i - 1);
2604 valuesx.remove(i - 1);
2606 i -= 1; // redo the i'th iteration
2607 break;
2611 if (keysx !is e.keys ||
2612 valuesx !is e.values)
2614 assert(keysx !is e.keys &&
2615 valuesx !is e.values);
2616 auto aae = ctfeEmplaceExp!AssocArrayLiteralExp(e.loc, keysx, valuesx);
2617 aae.type = e.type;
2618 aae.ownedByCtfe = OwnedBy.ctfe;
2619 result = aae;
2621 else
2623 *pue = copyLiteral(e);
2624 result = pue.exp();
2628 override void visit(StructLiteralExp e)
2630 debug (LOG)
2632 printf("%s StructLiteralExp::interpret() %s ownedByCtfe = %d\n", e.loc.toChars(), e.toChars(), e.ownedByCtfe);
2634 if (e.ownedByCtfe >= OwnedBy.ctfe)
2636 result = e;
2637 return;
2640 size_t dim = e.elements ? e.elements.length : 0;
2641 auto expsx = e.elements;
2643 if (dim != e.sd.fields.length)
2645 // guaranteed by AggregateDeclaration.fill and TypeStruct.defaultInitLiteral
2646 const nvthis = e.sd.fields.length - e.sd.nonHiddenFields();
2647 assert(e.sd.fields.length - dim == nvthis);
2649 /* If a nested struct has no initialized hidden pointer,
2650 * set it to null to match the runtime behaviour.
2652 foreach (const i; 0 .. nvthis)
2654 auto ne = ctfeEmplaceExp!NullExp(e.loc);
2655 auto vthis = i == 0 ? e.sd.vthis : e.sd.vthis2;
2656 ne.type = vthis.type;
2658 expsx = copyArrayOnWrite(expsx, e.elements);
2659 expsx.push(ne);
2660 ++dim;
2663 assert(dim == e.sd.fields.length);
2665 foreach (i; 0 .. dim)
2667 auto v = e.sd.fields[i];
2668 Expression exp = (*expsx)[i];
2669 Expression ex;
2670 if (!exp)
2672 ex = voidInitLiteral(v.type, v).copy();
2674 else
2676 ex = interpretRegion(exp, istate);
2677 if (exceptionOrCant(ex))
2678 return;
2679 if ((v.type.ty != ex.type.ty) && v.type.ty == Tsarray)
2681 // Block assignment from inside struct literals
2682 auto tsa = cast(TypeSArray)v.type;
2683 auto len = cast(size_t)tsa.dim.toInteger();
2684 UnionExp ue = void;
2685 ex = createBlockDuplicatedArrayLiteral(&ue, ex.loc, v.type, ex, len);
2686 if (ex == ue.exp())
2687 ex = ue.copy();
2691 /* If any changes, do Copy On Write
2693 if (ex !is exp)
2695 expsx = copyArrayOnWrite(expsx, e.elements);
2696 (*expsx)[i] = ex;
2700 if (expsx !is e.elements)
2702 expandTuples(expsx);
2703 if (expsx.length != e.sd.fields.length)
2705 error(e.loc, "CTFE internal error: invalid struct literal");
2706 result = CTFEExp.cantexp;
2707 return;
2709 emplaceExp!(StructLiteralExp)(pue, e.loc, e.sd, expsx);
2710 auto sle = pue.exp().isStructLiteralExp();
2711 sle.type = e.type;
2712 sle.ownedByCtfe = OwnedBy.ctfe;
2713 sle.origin = e.origin;
2714 result = sle;
2716 else
2718 *pue = copyLiteral(e);
2719 result = pue.exp();
2723 // Create an array literal of type 'newtype' with dimensions given by
2724 // 'arguments'[argnum..$]
2725 static Expression recursivelyCreateArrayLiteral(UnionExp* pue, const ref Loc loc, Type newtype, InterState* istate, Expressions* arguments, int argnum)
2727 Expression lenExpr = interpret(pue, (*arguments)[argnum], istate);
2728 if (exceptionOrCantInterpret(lenExpr))
2729 return lenExpr;
2730 size_t len = cast(size_t)lenExpr.toInteger();
2731 Type elemType = (cast(TypeArray)newtype).next;
2732 if (elemType.ty == Tarray && argnum < arguments.length - 1)
2734 Expression elem = recursivelyCreateArrayLiteral(pue, loc, elemType, istate, arguments, argnum + 1);
2735 if (exceptionOrCantInterpret(elem))
2736 return elem;
2738 auto elements = new Expressions(len);
2739 foreach (ref element; *elements)
2740 element = copyLiteral(elem).copy();
2741 emplaceExp!(ArrayLiteralExp)(pue, loc, newtype, elements);
2742 auto ae = pue.exp().isArrayLiteralExp();
2743 ae.ownedByCtfe = OwnedBy.ctfe;
2744 return ae;
2746 assert(argnum == arguments.length - 1);
2747 if (elemType.ty.isSomeChar)
2749 const ch = cast(dchar)elemType.defaultInitLiteral(loc).toInteger();
2750 const sz = cast(ubyte)elemType.size();
2751 return createBlockDuplicatedStringLiteral(pue, loc, newtype, ch, len, sz);
2753 else
2755 auto el = interpret(elemType.defaultInitLiteral(loc), istate);
2756 return createBlockDuplicatedArrayLiteral(pue, loc, newtype, el, len);
2760 override void visit(NewExp e)
2762 debug (LOG)
2764 printf("%s NewExp::interpret() %s\n", e.loc.toChars(), e.toChars());
2767 Expression epre = interpret(pue, e.argprefix, istate, CTFEGoal.Nothing);
2768 if (exceptionOrCant(epre))
2769 return;
2771 if (e.newtype.ty == Tarray && e.arguments)
2773 result = recursivelyCreateArrayLiteral(pue, e.loc, e.newtype, istate, e.arguments, 0);
2774 return;
2776 if (auto ts = e.newtype.toBasetype().isTypeStruct())
2778 if (e.member)
2780 Expression se = e.newtype.defaultInitLiteral(e.loc);
2781 se = interpret(se, istate);
2782 if (exceptionOrCant(se))
2783 return;
2784 result = interpretFunction(pue, e.member, istate, e.arguments, se);
2786 // Repaint as same as CallExp::interpret() does.
2787 result.loc = e.loc;
2789 else
2791 StructDeclaration sd = ts.sym;
2792 auto exps = new Expressions();
2793 exps.reserve(sd.fields.length);
2794 if (e.arguments)
2796 exps.setDim(e.arguments.length);
2797 foreach (i, ex; *e.arguments)
2799 ex = interpretRegion(ex, istate);
2800 if (exceptionOrCant(ex))
2801 return;
2802 (*exps)[i] = ex;
2805 sd.fill(e.loc, *exps, false);
2807 auto se = ctfeEmplaceExp!StructLiteralExp(e.loc, sd, exps, e.newtype);
2808 se.origin = se;
2809 se.type = e.newtype;
2810 se.ownedByCtfe = OwnedBy.ctfe;
2811 result = interpret(pue, se, istate);
2813 if (exceptionOrCant(result))
2814 return;
2815 Expression ev = (result == pue.exp()) ? pue.copy() : result;
2816 emplaceExp!(AddrExp)(pue, e.loc, ev, e.type);
2817 result = pue.exp();
2818 return;
2820 if (auto tc = e.newtype.toBasetype().isTypeClass())
2822 ClassDeclaration cd = tc.sym;
2823 size_t totalFieldCount = 0;
2824 for (ClassDeclaration c = cd; c; c = c.baseClass)
2825 totalFieldCount += c.fields.length;
2826 auto elems = new Expressions(totalFieldCount);
2827 size_t fieldsSoFar = totalFieldCount;
2828 for (ClassDeclaration c = cd; c; c = c.baseClass)
2830 fieldsSoFar -= c.fields.length;
2831 foreach (i, v; c.fields)
2833 if (v.inuse)
2835 error(e.loc, "circular reference to `%s`", v.toPrettyChars());
2836 result = CTFEExp.cantexp;
2837 return;
2839 Expression m;
2840 if (v._init)
2842 if (v._init.isVoidInitializer())
2843 m = voidInitLiteral(v.type, v).copy();
2844 else
2845 m = v.getConstInitializer(true);
2847 else if (v.type.isTypeNoreturn())
2849 // Noreturn field with default initializer
2850 (*elems)[fieldsSoFar + i] = null;
2851 continue;
2853 else
2854 m = v.type.defaultInitLiteral(e.loc);
2855 if (exceptionOrCant(m))
2856 return;
2857 (*elems)[fieldsSoFar + i] = copyLiteral(m).copy();
2860 // Hack: we store a ClassDeclaration instead of a StructDeclaration.
2861 // We probably won't get away with this.
2862 // auto se = new StructLiteralExp(e.loc, cast(StructDeclaration)cd, elems, e.newtype);
2863 auto se = ctfeEmplaceExp!StructLiteralExp(e.loc, cast(StructDeclaration)cd, elems, e.newtype);
2864 se.origin = se;
2865 se.ownedByCtfe = OwnedBy.ctfe;
2866 Expression eref = ctfeEmplaceExp!ClassReferenceExp(e.loc, se, e.type);
2867 if (e.member)
2869 // Call constructor
2870 if (!e.member.fbody)
2872 Expression ctorfail = evaluateIfBuiltin(pue, istate, e.loc, e.member, e.arguments, eref);
2873 if (ctorfail)
2875 if (exceptionOrCant(ctorfail))
2876 return;
2877 result = eref;
2878 return;
2880 auto m = e.member;
2881 error(m.loc, "%s `%s` `%s` cannot be constructed at compile time, because the constructor has no available source code",
2882 m.kind, m.toPrettyChars, e.newtype.toChars());
2883 result = CTFEExp.cantexp;
2884 return;
2886 UnionExp ue = void;
2887 Expression ctorfail = interpretFunction(&ue, e.member, istate, e.arguments, eref);
2888 if (exceptionOrCant(ctorfail))
2889 return;
2891 /* https://issues.dlang.org/show_bug.cgi?id=14465
2892 * Repaint the loc, because a super() call
2893 * in the constructor modifies the loc of ClassReferenceExp
2894 * in CallExp::interpret().
2896 eref.loc = e.loc;
2898 result = eref;
2899 return;
2901 if (e.newtype.toBasetype().isscalar())
2903 Expression newval;
2904 if (e.arguments && e.arguments.length)
2905 newval = (*e.arguments)[0];
2906 else
2907 newval = e.newtype.defaultInitLiteral(e.loc);
2908 newval = interpretRegion(newval, istate);
2909 if (exceptionOrCant(newval))
2910 return;
2912 // Create a CTFE pointer &[newval][0]
2913 auto elements = new Expressions(1);
2914 (*elements)[0] = newval;
2915 auto ae = ctfeEmplaceExp!ArrayLiteralExp(e.loc, e.newtype.arrayOf(), elements);
2916 ae.ownedByCtfe = OwnedBy.ctfe;
2918 auto ei = ctfeEmplaceExp!IndexExp(e.loc, ae, ctfeEmplaceExp!IntegerExp(Loc.initial, 0, Type.tsize_t));
2919 ei.type = e.newtype;
2920 emplaceExp!(AddrExp)(pue, e.loc, ei, e.type);
2921 result = pue.exp();
2922 return;
2924 error(e.loc, "cannot interpret `%s` at compile time", e.toChars());
2925 result = CTFEExp.cantexp;
2928 override void visit(UnaExp e)
2930 debug (LOG)
2932 printf("%s UnaExp::interpret() %s\n", e.loc.toChars(), e.toChars());
2934 UnionExp ue = void;
2935 Expression e1 = interpret(&ue, e.e1, istate);
2936 if (exceptionOrCant(e1))
2937 return;
2938 switch (e.op)
2940 case EXP.negate:
2941 *pue = Neg(e.type, e1);
2942 break;
2944 case EXP.tilde:
2945 *pue = Com(e.type, e1);
2946 break;
2948 case EXP.not:
2949 *pue = Not(e.type, e1);
2950 break;
2952 default:
2953 assert(0);
2955 result = (*pue).exp();
2958 override void visit(DotTypeExp e)
2960 debug (LOG)
2962 printf("%s DotTypeExp::interpret() %s\n", e.loc.toChars(), e.toChars());
2964 UnionExp ue = void;
2965 Expression e1 = interpret(&ue, e.e1, istate);
2966 if (exceptionOrCant(e1))
2967 return;
2968 if (e1 == e.e1)
2969 result = e; // optimize: reuse this CTFE reference
2970 else
2972 auto edt = e.copy().isDotTypeExp();
2973 edt.e1 = (e1 == ue.exp()) ? e1.copy() : e1; // don't return pointer to ue
2974 result = edt;
2978 extern (D) private void interpretCommon(BinExp e, fp_t fp)
2980 debug (LOG)
2982 printf("%s BinExp::interpretCommon() %s\n", e.loc.toChars(), e.toChars());
2984 if (e.e1.type.ty == Tpointer && e.e2.type.ty == Tpointer && e.op == EXP.min)
2986 UnionExp ue1 = void;
2987 Expression e1 = interpret(&ue1, e.e1, istate);
2988 if (exceptionOrCant(e1))
2989 return;
2990 UnionExp ue2 = void;
2991 Expression e2 = interpret(&ue2, e.e2, istate);
2992 if (exceptionOrCant(e2))
2993 return;
2994 result = pointerDifference(pue, e.loc, e.type, e1, e2);
2995 return;
2997 if (e.e1.type.ty == Tpointer && e.e2.type.isintegral())
2999 UnionExp ue1 = void;
3000 Expression e1 = interpret(&ue1, e.e1, istate);
3001 if (exceptionOrCant(e1))
3002 return;
3003 UnionExp ue2 = void;
3004 Expression e2 = interpret(&ue2, e.e2, istate);
3005 if (exceptionOrCant(e2))
3006 return;
3007 result = pointerArithmetic(pue, e.loc, e.op, e.type, e1, e2);
3008 return;
3010 if (e.e2.type.ty == Tpointer && e.e1.type.isintegral() && e.op == EXP.add)
3012 UnionExp ue1 = void;
3013 Expression e1 = interpret(&ue1, e.e1, istate);
3014 if (exceptionOrCant(e1))
3015 return;
3016 UnionExp ue2 = void;
3017 Expression e2 = interpret(&ue2, e.e2, istate);
3018 if (exceptionOrCant(e2))
3019 return;
3020 result = pointerArithmetic(pue, e.loc, e.op, e.type, e2, e1);
3021 return;
3023 if (e.e1.type.ty == Tpointer || e.e2.type.ty == Tpointer)
3025 error(e.loc, "pointer expression `%s` cannot be interpreted at compile time", e.toChars());
3026 result = CTFEExp.cantexp;
3027 return;
3030 bool evalOperand(UnionExp* pue, Expression ex, out Expression er)
3032 er = interpret(pue, ex, istate);
3033 if (exceptionOrCant(er))
3034 return false;
3035 return true;
3038 UnionExp ue1 = void;
3039 Expression e1;
3040 if (!evalOperand(&ue1, e.e1, e1))
3041 return;
3043 UnionExp ue2 = void;
3044 Expression e2;
3045 if (!evalOperand(&ue2, e.e2, e2))
3046 return;
3048 if (e.op == EXP.rightShift || e.op == EXP.leftShift || e.op == EXP.unsignedRightShift)
3050 const sinteger_t i2 = e2.toInteger();
3051 const uinteger_t sz = e1.type.size() * 8;
3052 if (i2 < 0 || i2 >= sz)
3054 error(e.loc, "shift by %lld is outside the range 0..%llu", i2, cast(ulong)sz - 1);
3055 result = CTFEExp.cantexp;
3056 return;
3060 /******************************************
3061 * Perform the operation fp on operands e1 and e2.
3063 UnionExp evaluate(Loc loc, Type type, Expression e1, Expression e2)
3065 UnionExp ue = void;
3066 auto ae1 = e1.isArrayLiteralExp();
3067 auto ae2 = e2.isArrayLiteralExp();
3068 if (ae1 || ae2)
3070 /* Cases:
3071 * 1. T[] op T[]
3072 * 2. T op T[]
3073 * 3. T[] op T
3075 if (ae1 && e2.implicitConvTo(e1.type.toBasetype().nextOf())) // case 3
3076 ae2 = null;
3077 else if (ae2 && e1.implicitConvTo(e2.type.toBasetype().nextOf())) // case 2
3078 ae1 = null;
3079 // else case 1
3081 auto aex = ae1 ? ae1 : ae2;
3082 if (!aex.elements)
3084 emplaceExp!ArrayLiteralExp(&ue, loc, type, cast(Expressions*) null);
3085 return ue;
3087 const length = aex.elements.length;
3088 Expressions* elements = new Expressions(length);
3090 emplaceExp!ArrayLiteralExp(&ue, loc, type, elements);
3091 foreach (i; 0 .. length)
3093 Expression e1x = ae1 ? ae1[i] : e1;
3094 Expression e2x = ae2 ? ae2[i] : e2;
3095 UnionExp uex = evaluate(loc, e1x.type, e1x, e2x);
3096 // This can be made more efficient by making use of ue.basis
3097 (*elements)[i] = uex.copy();
3099 return ue;
3102 if (e1.isConst() != 1)
3104 // The following should really be an assert()
3105 error(e1.loc, "CTFE internal error: non-constant value `%s`", e1.toChars());
3106 emplaceExp!CTFEExp(&ue, EXP.cantExpression);
3107 return ue;
3109 if (e2.isConst() != 1)
3111 error(e2.loc, "CTFE internal error: non-constant value `%s`", e2.toChars());
3112 emplaceExp!CTFEExp(&ue, EXP.cantExpression);
3113 return ue;
3116 return (*fp)(loc, type, e1, e2);
3119 *pue = evaluate(e.loc, e.type, e1, e2);
3120 result = (*pue).exp();
3121 if (CTFEExp.isCantExp(result))
3122 error(e.loc, "`%s` cannot be interpreted at compile time", e.toChars());
3125 extern (D) private void interpretCompareCommon(BinExp e, fp2_t fp)
3127 debug (LOG)
3129 printf("%s BinExp::interpretCompareCommon() %s\n", e.loc.toChars(), e.toChars());
3131 UnionExp ue1 = void;
3132 UnionExp ue2 = void;
3133 if (e.e1.type.ty == Tpointer && e.e2.type.ty == Tpointer)
3135 Expression e1 = interpret(&ue1, e.e1, istate);
3136 if (exceptionOrCant(e1))
3137 return;
3138 Expression e2 = interpret(&ue2, e.e2, istate);
3139 if (exceptionOrCant(e2))
3140 return;
3141 //printf("e1 = %s %s, e2 = %s %s\n", e1.type.toChars(), e1.toChars(), e2.type.toChars(), e2.toChars());
3142 dinteger_t ofs1, ofs2;
3143 Expression agg1 = getAggregateFromPointer(e1, &ofs1);
3144 Expression agg2 = getAggregateFromPointer(e2, &ofs2);
3145 //printf("agg1 = %p %s, agg2 = %p %s\n", agg1, agg1.toChars(), agg2, agg2.toChars());
3146 const cmp = comparePointers(e.op, agg1, ofs1, agg2, ofs2);
3147 if (cmp == -1)
3149 char dir = (e.op == EXP.greaterThan || e.op == EXP.greaterOrEqual) ? '<' : '>';
3150 error(e.loc, "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());
3151 result = CTFEExp.cantexp;
3152 return;
3154 if (e.type.equals(Type.tbool))
3155 result = IntegerExp.createBool(cmp != 0);
3156 else
3158 emplaceExp!(IntegerExp)(pue, e.loc, cmp, e.type);
3159 result = (*pue).exp();
3161 return;
3163 Expression e1 = interpret(&ue1, e.e1, istate);
3164 if (exceptionOrCant(e1))
3165 return;
3166 if (!isCtfeComparable(e1))
3168 error(e.loc, "cannot compare `%s` at compile time", e1.toChars());
3169 result = CTFEExp.cantexp;
3170 return;
3172 Expression e2 = interpret(&ue2, e.e2, istate);
3173 if (exceptionOrCant(e2))
3174 return;
3175 if (!isCtfeComparable(e2))
3177 error(e.loc, "cannot compare `%s` at compile time", e2.toChars());
3178 result = CTFEExp.cantexp;
3179 return;
3181 const cmp = (*fp)(e.loc, e.op, e1, e2);
3182 if (e.type.equals(Type.tbool))
3183 result = IntegerExp.createBool(cmp);
3184 else
3186 emplaceExp!(IntegerExp)(pue, e.loc, cmp, e.type);
3187 result = (*pue).exp();
3191 override void visit(BinExp e)
3193 switch (e.op)
3195 case EXP.add:
3196 interpretCommon(e, &Add);
3197 return;
3199 case EXP.min:
3200 interpretCommon(e, &Min);
3201 return;
3203 case EXP.mul:
3204 interpretCommon(e, &Mul);
3205 return;
3207 case EXP.div:
3208 interpretCommon(e, &Div);
3209 return;
3211 case EXP.mod:
3212 interpretCommon(e, &Mod);
3213 return;
3215 case EXP.leftShift:
3216 interpretCommon(e, &Shl);
3217 return;
3219 case EXP.rightShift:
3220 interpretCommon(e, &Shr);
3221 return;
3223 case EXP.unsignedRightShift:
3224 interpretCommon(e, &Ushr);
3225 return;
3227 case EXP.and:
3228 interpretCommon(e, &And);
3229 return;
3231 case EXP.or:
3232 interpretCommon(e, &Or);
3233 return;
3235 case EXP.xor:
3236 interpretCommon(e, &Xor);
3237 return;
3239 case EXP.pow:
3240 interpretCommon(e, &Pow);
3241 return;
3243 case EXP.equal:
3244 case EXP.notEqual:
3245 interpretCompareCommon(e, &ctfeEqual);
3246 return;
3248 case EXP.identity:
3249 case EXP.notIdentity:
3250 interpretCompareCommon(e, &ctfeIdentity);
3251 return;
3253 case EXP.lessThan:
3254 case EXP.lessOrEqual:
3255 case EXP.greaterThan:
3256 case EXP.greaterOrEqual:
3257 interpretCompareCommon(e, &ctfeCmp);
3258 return;
3260 default:
3261 printf("be = '%s' %s at [%s]\n", EXPtoString(e.op).ptr, e.toChars(), e.loc.toChars());
3262 assert(0);
3266 /* Helper functions for BinExp::interpretAssignCommon
3268 // Returns the variable which is eventually modified, or NULL if an rvalue.
3269 // thisval is the current value of 'this'.
3270 static VarDeclaration findParentVar(Expression e) @safe
3272 for (;;)
3274 if (auto ve = e.isVarExp())
3276 VarDeclaration v = ve.var.isVarDeclaration();
3277 assert(v);
3278 return v;
3280 if (auto ie = e.isIndexExp())
3281 e = ie.e1;
3282 else if (auto dve = e.isDotVarExp())
3283 e = dve.e1;
3284 else if (auto dtie = e.isDotTemplateInstanceExp())
3285 e = dtie.e1;
3286 else if (auto se = e.isSliceExp())
3287 e = se.e1;
3288 else
3289 return null;
3293 extern (D) private void interpretAssignCommon(BinExp e, fp_t fp, int post = 0)
3295 debug (LOG)
3297 printf("%s BinExp::interpretAssignCommon() %s\n", e.loc.toChars(), e.toChars());
3299 result = CTFEExp.cantexp;
3301 Expression e1 = e.e1;
3302 if (!istate)
3304 error(e.loc, "value of `%s` is not known at compile time", e1.toChars());
3305 return;
3308 ++ctfeGlobals.numAssignments;
3310 /* Before we begin, we need to know if this is a reference assignment
3311 * (dynamic array, AA, or class) or a value assignment.
3312 * Determining this for slice assignments are tricky: we need to know
3313 * if it is a block assignment (a[] = e) rather than a direct slice
3314 * assignment (a[] = b[]). Note that initializers of multi-dimensional
3315 * static arrays can have 2D block assignments (eg, int[7][7] x = 6;).
3316 * So we need to recurse to determine if it is a block assignment.
3318 bool isBlockAssignment = false;
3319 if (e1.op == EXP.slice)
3321 // a[] = e can have const e. So we compare the naked types.
3322 Type tdst = e1.type.toBasetype();
3323 Type tsrc = e.e2.type.toBasetype();
3324 while (tdst.ty == Tsarray || tdst.ty == Tarray)
3326 tdst = (cast(TypeArray)tdst).next.toBasetype();
3327 if (tsrc.equivalent(tdst))
3329 isBlockAssignment = true;
3330 break;
3335 // ---------------------------------------
3336 // Deal with reference assignment
3337 // ---------------------------------------
3338 // If it is a construction of a ref variable, it is a ref assignment
3339 if ((e.op == EXP.construct || e.op == EXP.blit) &&
3340 ((cast(AssignExp)e).memset == MemorySet.referenceInit))
3342 assert(!fp);
3344 Expression newval = interpretRegion(e.e2, istate, CTFEGoal.LValue);
3345 if (exceptionOrCant(newval))
3346 return;
3348 VarDeclaration v = e1.isVarExp().var.isVarDeclaration();
3349 setValue(v, newval);
3351 // Get the value to return. Note that 'newval' is an Lvalue,
3352 // so if we need an Rvalue, we have to interpret again.
3353 if (goal == CTFEGoal.RValue)
3354 result = interpretRegion(newval, istate);
3355 else
3356 result = e1; // VarExp is a CTFE reference
3357 return;
3360 if (fp)
3362 while (e1.op == EXP.cast_)
3364 CastExp ce = e1.isCastExp();
3365 e1 = ce.e1;
3369 // ---------------------------------------
3370 // Interpret left hand side
3371 // ---------------------------------------
3372 AssocArrayLiteralExp existingAA = null;
3373 Expression lastIndex = null;
3374 Expression oldval = null;
3375 if (e1.op == EXP.index && e1.isIndexExp().e1.type.toBasetype().ty == Taarray)
3377 // ---------------------------------------
3378 // Deal with AA index assignment
3379 // ---------------------------------------
3380 /* This needs special treatment if the AA doesn't exist yet.
3381 * There are two special cases:
3382 * (1) If the AA is itself an index of another AA, we may need to create
3383 * multiple nested AA literals before we can insert the new value.
3384 * (2) If the ultimate AA is null, no insertion happens at all. Instead,
3385 * we create nested AA literals, and change it into a assignment.
3387 IndexExp ie = e1.isIndexExp();
3388 int depth = 0; // how many nested AA indices are there?
3389 while (ie.e1.op == EXP.index && ie.e1.isIndexExp().e1.type.toBasetype().ty == Taarray)
3391 assert(ie.modifiable);
3392 ie = ie.e1.isIndexExp();
3393 ++depth;
3396 // Get the AA value to be modified.
3397 Expression aggregate = interpretRegion(ie.e1, istate);
3398 if (exceptionOrCant(aggregate))
3399 return;
3400 if ((existingAA = aggregate.isAssocArrayLiteralExp()) !is null)
3402 // Normal case, ultimate parent AA already exists
3403 // We need to walk from the deepest index up, checking that an AA literal
3404 // already exists on each level.
3405 lastIndex = interpretRegion(e1.isIndexExp().e2, istate);
3406 lastIndex = resolveSlice(lastIndex); // only happens with AA assignment
3407 if (exceptionOrCant(lastIndex))
3408 return;
3410 while (depth > 0)
3412 // Walk the syntax tree to find the indexExp at this depth
3413 IndexExp xe = e1.isIndexExp();
3414 foreach (d; 0 .. depth)
3415 xe = xe.e1.isIndexExp();
3417 Expression ekey = interpretRegion(xe.e2, istate);
3418 if (exceptionOrCant(ekey))
3419 return;
3420 UnionExp ekeyTmp = void;
3421 ekey = resolveSlice(ekey, &ekeyTmp); // only happens with AA assignment
3423 // Look up this index in it up in the existing AA, to get the next level of AA.
3424 AssocArrayLiteralExp newAA = cast(AssocArrayLiteralExp)findKeyInAA(e.loc, existingAA, ekey);
3425 if (exceptionOrCant(newAA))
3426 return;
3427 if (!newAA)
3429 // Doesn't exist yet, create an empty AA...
3430 auto keysx = new Expressions();
3431 auto valuesx = new Expressions();
3432 newAA = ctfeEmplaceExp!AssocArrayLiteralExp(e.loc, keysx, valuesx);
3433 newAA.type = xe.type;
3434 newAA.ownedByCtfe = OwnedBy.ctfe;
3435 //... and insert it into the existing AA.
3436 existingAA.keys.push(ekey);
3437 existingAA.values.push(newAA);
3439 existingAA = newAA;
3440 --depth;
3443 if (fp)
3445 oldval = findKeyInAA(e.loc, existingAA, lastIndex);
3446 if (!oldval)
3447 oldval = copyLiteral(e.e1.type.defaultInitLiteral(e.loc)).copy();
3450 else
3452 /* The AA is currently null. 'aggregate' is actually a reference to
3453 * whatever contains it. It could be anything: var, dotvarexp, ...
3454 * We rewrite the assignment from:
3455 * aa[i][j] op= newval;
3456 * into:
3457 * aa = [i:[j:T.init]];
3458 * aa[j] op= newval;
3460 oldval = copyLiteral(e.e1.type.defaultInitLiteral(e.loc)).copy();
3462 Expression newaae = oldval;
3463 while (e1.op == EXP.index && e1.isIndexExp().e1.type.toBasetype().ty == Taarray)
3465 Expression ekey = interpretRegion(e1.isIndexExp().e2, istate);
3466 if (exceptionOrCant(ekey))
3467 return;
3468 ekey = resolveSlice(ekey); // only happens with AA assignment
3470 auto keysx = new Expressions();
3471 auto valuesx = new Expressions();
3472 keysx.push(ekey);
3473 valuesx.push(newaae);
3475 auto aae = ctfeEmplaceExp!AssocArrayLiteralExp(e.loc, keysx, valuesx);
3476 aae.type = e1.isIndexExp().e1.type;
3477 aae.ownedByCtfe = OwnedBy.ctfe;
3478 if (!existingAA)
3480 existingAA = aae;
3481 lastIndex = ekey;
3483 newaae = aae;
3484 e1 = e1.isIndexExp().e1;
3487 // We must set to aggregate with newaae
3488 e1 = interpretRegion(e1, istate, CTFEGoal.LValue);
3489 if (exceptionOrCant(e1))
3490 return;
3491 e1 = assignToLvalue(e, e1, newaae);
3492 if (exceptionOrCant(e1))
3493 return;
3495 assert(existingAA && lastIndex);
3496 e1 = null; // stomp
3498 else if (e1.op == EXP.arrayLength)
3500 oldval = interpretRegion(e1, istate);
3501 if (exceptionOrCant(oldval))
3502 return;
3504 else if (e.op == EXP.construct || e.op == EXP.blit)
3506 // Unless we have a simple var assignment, we're
3507 // only modifying part of the variable. So we need to make sure
3508 // that the parent variable exists.
3509 VarDeclaration ultimateVar = findParentVar(e1);
3510 if (auto ve = e1.isVarExp())
3512 VarDeclaration v = ve.var.isVarDeclaration();
3513 assert(v);
3514 if (v.storage_class & STC.out_)
3515 goto L1;
3517 else if (ultimateVar && !getValue(ultimateVar))
3519 Expression ex = interpretRegion(ultimateVar.type.defaultInitLiteral(e.loc), istate);
3520 if (exceptionOrCant(ex))
3521 return;
3522 setValue(ultimateVar, ex);
3524 else
3525 goto L1;
3527 else
3530 e1 = interpretRegion(e1, istate, CTFEGoal.LValue);
3531 if (exceptionOrCant(e1))
3532 return;
3534 if (e1.op == EXP.index && e1.isIndexExp().e1.type.toBasetype().ty == Taarray)
3536 IndexExp ie = e1.isIndexExp();
3537 assert(ie.e1.op == EXP.assocArrayLiteral);
3538 existingAA = ie.e1.isAssocArrayLiteralExp();
3539 lastIndex = ie.e2;
3543 // ---------------------------------------
3544 // Interpret right hand side
3545 // ---------------------------------------
3546 Expression newval = interpretRegion(e.e2, istate);
3547 if (exceptionOrCant(newval))
3548 return;
3549 if (e.op == EXP.blit && newval.op == EXP.int64)
3551 Type tbn = e.type.baseElemOf();
3552 if (tbn.ty == Tstruct)
3554 /* Look for special case of struct being initialized with 0.
3556 newval = e.type.defaultInitLiteral(e.loc);
3557 if (newval.op == EXP.error)
3559 result = CTFEExp.cantexp;
3560 return;
3562 newval = interpretRegion(newval, istate); // copy and set ownedByCtfe flag
3563 if (exceptionOrCant(newval))
3564 return;
3568 // ----------------------------------------------------
3569 // Deal with read-modify-write assignments.
3570 // Set 'newval' to the final assignment value
3571 // Also determine the return value (except for slice
3572 // assignments, which are more complicated)
3573 // ----------------------------------------------------
3574 if (fp)
3576 if (!oldval)
3578 // Load the left hand side after interpreting the right hand side.
3579 oldval = interpretRegion(e1, istate);
3580 if (exceptionOrCant(oldval))
3581 return;
3584 if (e.e1.type.ty != Tpointer)
3586 // ~= can create new values (see bug 6052)
3587 if (e.op == EXP.concatenateAssign || e.op == EXP.concatenateElemAssign || e.op == EXP.concatenateDcharAssign)
3589 // We need to dup it and repaint the type. For a dynamic array
3590 // we can skip duplication, because it gets copied later anyway.
3591 if (newval.type.ty != Tarray)
3593 newval = copyLiteral(newval).copy();
3594 newval.type = e.e2.type; // repaint type
3596 else
3598 newval = paintTypeOntoLiteral(e.e2.type, newval);
3599 newval = resolveSlice(newval);
3602 oldval = resolveSlice(oldval);
3604 newval = (*fp)(e.loc, e.type, oldval, newval).copy();
3606 else if (e.e2.type.isintegral() &&
3607 (e.op == EXP.addAssign ||
3608 e.op == EXP.minAssign ||
3609 e.op == EXP.plusPlus ||
3610 e.op == EXP.minusMinus))
3612 newval = pointerArithmetic(pue, e.loc, e.op, e.type, oldval, newval).copy();
3613 if (newval == pue.exp())
3614 newval = pue.copy();
3616 else
3618 error(e.loc, "pointer expression `%s` cannot be interpreted at compile time", e.toChars());
3619 result = CTFEExp.cantexp;
3620 return;
3622 if (exceptionOrCant(newval))
3624 if (CTFEExp.isCantExp(newval))
3625 error(e.loc, "cannot interpret `%s` at compile time", e.toChars());
3626 return;
3630 if (existingAA)
3632 if (existingAA.ownedByCtfe != OwnedBy.ctfe)
3634 error(e.loc, "cannot modify read-only constant `%s`", existingAA.toChars());
3635 result = CTFEExp.cantexp;
3636 return;
3639 //printf("\t+L%d existingAA = %s, lastIndex = %s, oldval = %s, newval = %s\n",
3640 // __LINE__, existingAA.toChars(), lastIndex.toChars(), oldval ? oldval.toChars() : NULL, newval.toChars());
3641 assignAssocArrayElement(e.loc, existingAA, lastIndex, newval);
3643 // Determine the return value
3644 result = ctfeCast(pue, e.loc, e.type, e.type, fp && post ? oldval : newval);
3645 return;
3647 if (e1.op == EXP.arrayLength)
3649 /* Change the assignment from:
3650 * arr.length = n;
3651 * into:
3652 * arr = new_length_array; (result is n)
3655 // Determine the return value
3656 result = ctfeCast(pue, e.loc, e.type, e.type, fp && post ? oldval : newval);
3657 if (exceptionOrCant(result))
3658 return;
3660 if (result == pue.exp())
3661 result = pue.copy();
3663 size_t oldlen = cast(size_t)oldval.toInteger();
3664 size_t newlen = cast(size_t)newval.toInteger();
3665 if (oldlen == newlen) // no change required -- we're done!
3666 return;
3668 // We have changed it into a reference assignment
3669 // Note that returnValue is still the new length.
3670 e1 = e1.isArrayLengthExp().e1;
3671 Type t = e1.type.toBasetype();
3672 if (t.ty != Tarray)
3674 error(e.loc, "`%s` is not yet supported at compile time", e.toChars());
3675 result = CTFEExp.cantexp;
3676 return;
3678 e1 = interpretRegion(e1, istate, CTFEGoal.LValue);
3679 if (exceptionOrCant(e1))
3680 return;
3682 if (oldlen != 0) // Get the old array literal.
3683 oldval = interpretRegion(e1, istate);
3684 UnionExp utmp = void;
3685 oldval = resolveSlice(oldval, &utmp);
3687 newval = changeArrayLiteralLength(pue, e.loc, cast(TypeArray)t, oldval, oldlen, newlen);
3688 if (newval == pue.exp())
3689 newval = pue.copy();
3691 e1 = assignToLvalue(e, e1, newval);
3692 if (exceptionOrCant(e1))
3693 return;
3695 return;
3698 if (!isBlockAssignment)
3700 newval = ctfeCast(pue, e.loc, e.type, e.type, newval);
3701 if (exceptionOrCant(newval))
3702 return;
3703 if (newval == pue.exp())
3704 newval = pue.copy();
3706 // Determine the return value
3707 if (goal == CTFEGoal.LValue) // https://issues.dlang.org/show_bug.cgi?id=14371
3708 result = e1;
3709 else
3711 result = ctfeCast(pue, e.loc, e.type, e.type, fp && post ? oldval : newval);
3712 if (result == pue.exp())
3713 result = pue.copy();
3715 if (exceptionOrCant(result))
3716 return;
3718 if (exceptionOrCant(newval))
3719 return;
3721 debug (LOGASSIGN)
3723 printf("ASSIGN: %s=%s\n", e1.toChars(), newval.toChars());
3724 showCtfeExpr(newval);
3727 /* Block assignment or element-wise assignment.
3729 if (e1.op == EXP.slice ||
3730 e1.op == EXP.vector ||
3731 e1.op == EXP.arrayLiteral ||
3732 e1.op == EXP.string_ ||
3733 e1.op == EXP.null_ && e1.type.toBasetype().ty == Tarray)
3735 // Note that slice assignments don't support things like ++, so
3736 // we don't need to remember 'returnValue'.
3737 result = interpretAssignToSlice(pue, e, e1, newval, isBlockAssignment);
3738 if (exceptionOrCant(result))
3739 return;
3740 if (auto se = e.e1.isSliceExp())
3742 Expression e1x = interpretRegion(se.e1, istate, CTFEGoal.LValue);
3743 if (auto dve = e1x.isDotVarExp())
3745 auto ex = dve.e1;
3746 auto sle = ex.op == EXP.structLiteral ? ex.isStructLiteralExp()
3747 : ex.op == EXP.classReference ? ex.isClassReferenceExp().value
3748 : null;
3749 auto v = dve.var.isVarDeclaration();
3750 if (!sle || !v)
3752 error(e.loc, "CTFE internal error: dotvar slice assignment");
3753 result = CTFEExp.cantexp;
3754 return;
3756 stompOverlappedFields(sle, v);
3759 return;
3761 assert(result);
3763 /* Assignment to a CTFE reference.
3765 if (Expression ex = assignToLvalue(e, e1, newval))
3766 result = ex;
3768 return;
3771 /* Set all sibling fields which overlap with v to VoidExp.
3773 private void stompOverlappedFields(StructLiteralExp sle, VarDeclaration v)
3775 if (!v.overlapped)
3776 return;
3777 foreach (size_t i, v2; sle.sd.fields)
3779 if (v is v2 || !v.isOverlappedWith(v2))
3780 continue;
3781 auto e = (*sle.elements)[i];
3782 if (e.op != EXP.void_)
3783 (*sle.elements)[i] = voidInitLiteral(e.type, v).copy();
3787 private Expression assignToLvalue(BinExp e, Expression e1, Expression newval)
3789 //printf("assignToLvalue() e: %s e1: %s newval: %s\n", e.toChars(), e1.toChars(), newval.toChars());
3790 VarDeclaration vd = null;
3791 Expression* payload = null; // dead-store to prevent spurious warning
3792 Expression oldval;
3794 if (auto ve = e1.isVarExp())
3796 vd = ve.var.isVarDeclaration();
3797 oldval = getValue(vd);
3799 else if (auto dve = e1.isDotVarExp())
3801 /* Assignment to member variable of the form:
3802 * e.v = newval
3804 auto ex = dve.e1;
3805 auto sle = ex.op == EXP.structLiteral ? ex.isStructLiteralExp()
3806 : ex.op == EXP.classReference ? ex.isClassReferenceExp().value
3807 : null;
3808 auto v = e1.isDotVarExp().var.isVarDeclaration();
3809 if (!sle || !v)
3811 error(e.loc, "CTFE internal error: dotvar assignment");
3812 return CTFEExp.cantexp;
3814 if (sle.ownedByCtfe != OwnedBy.ctfe)
3816 error(e.loc, "cannot modify read-only constant `%s`", sle.toChars());
3817 return CTFEExp.cantexp;
3820 int fieldi = ex.op == EXP.structLiteral ? findFieldIndexByName(sle.sd, v)
3821 : ex.isClassReferenceExp().findFieldIndexByName(v);
3822 if (fieldi == -1)
3824 error(e.loc, "CTFE internal error: cannot find field `%s` in `%s`", v.toChars(), ex.toChars());
3825 return CTFEExp.cantexp;
3827 assert(0 <= fieldi && fieldi < sle.elements.length);
3829 // If it's a union, set all other members of this union to void
3830 stompOverlappedFields(sle, v);
3832 payload = &(*sle.elements)[fieldi];
3833 oldval = *payload;
3834 if (auto ival = newval.isIntegerExp())
3836 if (auto bf = v.isBitFieldDeclaration())
3838 sinteger_t value = ival.toInteger();
3839 if (bf.type.isunsigned())
3840 value &= (1L << bf.fieldWidth) - 1; // zero extra bits
3841 else
3842 { // sign extend extra bits
3843 value = value << (64 - bf.fieldWidth);
3844 value = value >> (64 - bf.fieldWidth);
3846 ival.setInteger(value);
3850 else if (auto ie = e1.isIndexExp())
3852 assert(ie.e1.type.toBasetype().ty != Taarray);
3854 Expression aggregate;
3855 uinteger_t indexToModify;
3856 if (!resolveIndexing(ie, istate, &aggregate, &indexToModify, true))
3858 return CTFEExp.cantexp;
3860 size_t index = cast(size_t)indexToModify;
3862 if (auto existingSE = aggregate.isStringExp())
3864 if (existingSE.ownedByCtfe != OwnedBy.ctfe)
3866 error(e.loc, "cannot modify read-only string literal `%s`", ie.e1.toChars());
3867 return CTFEExp.cantexp;
3869 existingSE.setCodeUnit(index, cast(dchar)newval.toInteger());
3870 return null;
3872 if (aggregate.op != EXP.arrayLiteral)
3874 error(e.loc, "index assignment `%s` is not yet supported in CTFE ", e.toChars());
3875 return CTFEExp.cantexp;
3878 ArrayLiteralExp existingAE = aggregate.isArrayLiteralExp();
3879 if (existingAE.ownedByCtfe != OwnedBy.ctfe)
3881 error(e.loc, "cannot modify read-only constant `%s`", existingAE.toChars());
3882 return CTFEExp.cantexp;
3885 payload = &(*existingAE.elements)[index];
3886 oldval = *payload;
3888 else
3890 error(e.loc, "`%s` cannot be evaluated at compile time", e.toChars());
3891 return CTFEExp.cantexp;
3894 Type t1b = e1.type.toBasetype();
3895 bool wantCopy = t1b.baseElemOf().ty == Tstruct;
3897 if (auto ve = newval.isVectorExp())
3899 // Ensure ve is an array literal, and not a broadcast
3900 if (ve.e1.op == EXP.int64 || ve.e1.op == EXP.float64) // if broadcast
3902 UnionExp ue = void;
3903 Expression ex = interpretVectorToArray(&ue, ve);
3904 ve.e1 = (ex == ue.exp()) ? ue.copy() : ex;
3908 if (newval.op == EXP.structLiteral && oldval)
3910 assert(oldval.op == EXP.structLiteral || oldval.op == EXP.arrayLiteral || oldval.op == EXP.string_);
3911 newval = copyLiteral(newval).copy();
3912 assignInPlace(oldval, newval);
3914 else if (wantCopy && (e.op == EXP.assign || e.op == EXP.loweredAssignExp))
3916 // Currently postblit/destructor calls on static array are done
3917 // in the druntime internal functions so they don't appear in AST.
3918 // Therefore interpreter should handle them specially.
3920 assert(oldval);
3921 version (all) // todo: instead we can directly access to each elements of the slice
3923 newval = resolveSlice(newval);
3924 if (CTFEExp.isCantExp(newval))
3926 error(e.loc, "CTFE internal error: assignment `%s`", e.toChars());
3927 return CTFEExp.cantexp;
3930 assert(oldval.op == EXP.arrayLiteral);
3931 assert(newval.op == EXP.arrayLiteral);
3933 Expressions* oldelems = oldval.isArrayLiteralExp().elements;
3934 Expressions* newelems = newval.isArrayLiteralExp().elements;
3935 assert(oldelems.length == newelems.length);
3937 Type elemtype = oldval.type.nextOf();
3938 foreach (i, ref oldelem; *oldelems)
3940 Expression newelem = paintTypeOntoLiteral(elemtype, (*newelems)[i]);
3941 // https://issues.dlang.org/show_bug.cgi?id=9245
3942 if (e.e2.isLvalue())
3944 if (Expression ex = evaluatePostblit(istate, newelem))
3945 return ex;
3947 // https://issues.dlang.org/show_bug.cgi?id=13661
3948 if (Expression ex = evaluateDtor(istate, oldelem))
3949 return ex;
3950 oldelem = newelem;
3953 else
3955 // e1 has its own payload, so we have to create a new literal.
3956 if (wantCopy)
3957 newval = copyLiteral(newval).copy();
3959 if (t1b.ty == Tsarray && e.op == EXP.construct && e.e2.isLvalue())
3961 // https://issues.dlang.org/show_bug.cgi?id=9245
3962 if (Expression ex = evaluatePostblit(istate, newval))
3963 return ex;
3966 oldval = newval;
3969 if (vd)
3970 setValue(vd, oldval);
3971 else
3972 *payload = oldval;
3974 // Blit assignment should return the newly created value.
3975 if (e.op == EXP.blit)
3976 return oldval;
3978 return null;
3981 /*************
3982 * Deal with assignments of the form:
3983 * dest[] = newval
3984 * dest[low..upp] = newval
3985 * where newval has already been interpreted
3987 * This could be a slice assignment or a block assignment, and
3988 * dest could be either an array literal, or a string.
3990 * Returns EXP.cantExpression on failure. If there are no errors,
3991 * it returns aggregate[low..upp], except that as an optimisation,
3992 * if goal == CTFEGoal.Nothing, it will return NULL
3994 private Expression interpretAssignToSlice(UnionExp* pue, BinExp e, Expression e1, Expression newval, bool isBlockAssignment)
3996 //printf("interpretAssignToSlice(e: %s e1: %s newval: %s\n", e.toChars(), e1.toChars(), newval.toChars());
3998 dinteger_t lowerbound;
3999 dinteger_t upperbound;
4000 dinteger_t firstIndex;
4002 Expression aggregate;
4004 if (auto se = e1.isSliceExp())
4006 // ------------------------------
4007 // aggregate[] = newval
4008 // aggregate[low..upp] = newval
4009 // ------------------------------
4010 aggregate = interpretRegion(se.e1, istate);
4011 lowerbound = se.lwr ? se.lwr.toInteger() : 0;
4012 upperbound = se.upr ? se.upr.toInteger() : resolveArrayLength(aggregate);
4014 // Slice of a slice --> change the bounds
4015 if (auto oldse = aggregate.isSliceExp())
4017 aggregate = oldse.e1;
4018 firstIndex = lowerbound + oldse.lwr.toInteger();
4020 else
4021 firstIndex = lowerbound;
4023 else
4025 if (auto ale = e1.isArrayLiteralExp())
4027 lowerbound = 0;
4028 upperbound = ale.elements.length;
4030 else if (auto se = e1.isStringExp())
4032 lowerbound = 0;
4033 upperbound = se.len;
4035 else if (e1.op == EXP.null_)
4037 lowerbound = 0;
4038 upperbound = 0;
4040 else if (VectorExp ve = e1.isVectorExp())
4042 // ve is not handled but a proper error message is returned
4043 // this is to prevent https://issues.dlang.org/show_bug.cgi?id=20042
4044 lowerbound = 0;
4045 upperbound = ve.dim;
4047 else
4048 assert(0);
4050 aggregate = e1;
4051 firstIndex = lowerbound;
4053 if (upperbound == lowerbound)
4054 return newval;
4056 // For slice assignment, we check that the lengths match.
4057 if (!isBlockAssignment && e1.type.ty != Tpointer)
4059 const srclen = resolveArrayLength(newval);
4060 if (srclen != (upperbound - lowerbound))
4062 error(e.loc, "array length mismatch assigning `[0..%llu]` to `[%llu..%llu]`",
4063 ulong(srclen), ulong(lowerbound), ulong(upperbound));
4064 return CTFEExp.cantexp;
4068 if (auto existingSE = aggregate.isStringExp())
4070 if (existingSE.ownedByCtfe != OwnedBy.ctfe)
4072 error(e.loc, "cannot modify read-only string literal `%s`", existingSE.toChars());
4073 return CTFEExp.cantexp;
4076 if (auto se = newval.isSliceExp())
4078 auto aggr2 = se.e1;
4079 const srclower = se.lwr.toInteger();
4080 const srcupper = se.upr.toInteger();
4082 if (aggregate == aggr2 &&
4083 lowerbound < srcupper && srclower < upperbound)
4085 error(e.loc, "overlapping slice assignment `[%llu..%llu] = [%llu..%llu]`",
4086 ulong(lowerbound), ulong(upperbound), ulong(srclower), ulong(srcupper));
4087 return CTFEExp.cantexp;
4089 version (all) // todo: instead we can directly access to each elements of the slice
4091 Expression orignewval = newval;
4092 newval = resolveSlice(newval);
4093 if (CTFEExp.isCantExp(newval))
4095 error(e.loc, "CTFE internal error: slice `%s`", orignewval.toChars());
4096 return CTFEExp.cantexp;
4099 assert(newval.op != EXP.slice);
4101 if (auto se = newval.isStringExp())
4103 sliceAssignStringFromString(existingSE, se, cast(size_t)firstIndex);
4104 return newval;
4106 if (auto ale = newval.isArrayLiteralExp())
4108 /* Mixed slice: it was initialized as a string literal.
4109 * Now a slice of it is being set with an array literal.
4111 sliceAssignStringFromArrayLiteral(existingSE, ale, cast(size_t)firstIndex);
4112 return newval;
4115 // String literal block slice assign
4116 const value = cast(dchar)newval.toInteger();
4117 foreach (i; 0 .. upperbound - lowerbound)
4119 existingSE.setCodeUnit(cast(size_t)(i + firstIndex), value);
4121 if (goal == CTFEGoal.Nothing)
4122 return null; // avoid creating an unused literal
4123 auto retslice = ctfeEmplaceExp!SliceExp(e.loc, existingSE,
4124 ctfeEmplaceExp!IntegerExp(e.loc, firstIndex, Type.tsize_t),
4125 ctfeEmplaceExp!IntegerExp(e.loc, firstIndex + upperbound - lowerbound, Type.tsize_t));
4126 retslice.type = e.type;
4127 return interpret(pue, retslice, istate);
4129 if (auto existingAE = aggregate.isArrayLiteralExp())
4131 if (existingAE.ownedByCtfe != OwnedBy.ctfe)
4133 error(e.loc, "cannot modify read-only constant `%s`", existingAE.toChars());
4134 return CTFEExp.cantexp;
4137 if (newval.op == EXP.slice && !isBlockAssignment)
4139 auto se = newval.isSliceExp();
4140 auto aggr2 = se.e1;
4141 const srclower = se.lwr.toInteger();
4142 const srcupper = se.upr.toInteger();
4143 const wantCopy = (newval.type.toBasetype().nextOf().baseElemOf().ty == Tstruct);
4145 //printf("oldval = %p %s[%d..%u]\nnewval = %p %s[%llu..%llu] wantCopy = %d\n",
4146 // aggregate, aggregate.toChars(), lowerbound, upperbound,
4147 // aggr2, aggr2.toChars(), srclower, srcupper, wantCopy);
4148 if (wantCopy)
4150 // Currently overlapping for struct array is allowed.
4151 // The order of elements processing depends on the overlapping.
4152 // https://issues.dlang.org/show_bug.cgi?id=14024
4153 assert(aggr2.op == EXP.arrayLiteral);
4154 Expressions* oldelems = existingAE.elements;
4155 Expressions* newelems = aggr2.isArrayLiteralExp().elements;
4157 Type elemtype = aggregate.type.nextOf();
4158 bool needsPostblit = e.e2.isLvalue();
4160 if (aggregate == aggr2 && srclower < lowerbound && lowerbound < srcupper)
4162 // reverse order
4163 for (auto i = upperbound - lowerbound; 0 < i--;)
4165 Expression oldelem = (*oldelems)[cast(size_t)(i + firstIndex)];
4166 Expression newelem = (*newelems)[cast(size_t)(i + srclower)];
4167 newelem = copyLiteral(newelem).copy();
4168 newelem.type = elemtype;
4169 if (needsPostblit)
4171 if (Expression x = evaluatePostblit(istate, newelem))
4172 return x;
4174 if (Expression x = evaluateDtor(istate, oldelem))
4175 return x;
4176 (*oldelems)[cast(size_t)(lowerbound + i)] = newelem;
4179 else
4181 // normal order
4182 for (auto i = 0; i < upperbound - lowerbound; i++)
4184 Expression oldelem = (*oldelems)[cast(size_t)(i + firstIndex)];
4185 Expression newelem = (*newelems)[cast(size_t)(i + srclower)];
4186 newelem = copyLiteral(newelem).copy();
4187 newelem.type = elemtype;
4188 if (needsPostblit)
4190 if (Expression x = evaluatePostblit(istate, newelem))
4191 return x;
4193 if (Expression x = evaluateDtor(istate, oldelem))
4194 return x;
4195 (*oldelems)[cast(size_t)(lowerbound + i)] = newelem;
4199 //assert(0);
4200 return newval; // oldval?
4202 if (aggregate == aggr2 &&
4203 lowerbound < srcupper && srclower < upperbound)
4205 error(e.loc, "overlapping slice assignment `[%llu..%llu] = [%llu..%llu]`",
4206 ulong(lowerbound), ulong(upperbound), ulong(srclower), ulong(srcupper));
4207 return CTFEExp.cantexp;
4209 version (all) // todo: instead we can directly access to each elements of the slice
4211 Expression orignewval = newval;
4212 newval = resolveSlice(newval);
4213 if (CTFEExp.isCantExp(newval))
4215 error(e.loc, "CTFE internal error: slice `%s`", orignewval.toChars());
4216 return CTFEExp.cantexp;
4219 // no overlapping
4220 //length?
4221 assert(newval.op != EXP.slice);
4223 if (newval.op == EXP.string_ && !isBlockAssignment)
4225 /* Mixed slice: it was initialized as an array literal of chars/integers.
4226 * Now a slice of it is being set with a string.
4228 sliceAssignArrayLiteralFromString(existingAE, newval.isStringExp(), cast(size_t)firstIndex);
4229 return newval;
4231 if (newval.op == EXP.arrayLiteral && !isBlockAssignment)
4233 Expressions* oldelems = existingAE.elements;
4234 Expressions* newelems = newval.isArrayLiteralExp().elements;
4235 Type elemtype = existingAE.type.nextOf();
4236 bool needsPostblit = e.op != EXP.blit && e.e2.isLvalue();
4237 foreach (j, newelem; *newelems)
4239 newelem = paintTypeOntoLiteral(elemtype, newelem);
4240 if (needsPostblit)
4242 Expression x = evaluatePostblit(istate, newelem);
4243 if (exceptionOrCantInterpret(x))
4244 return x;
4246 (*oldelems)[cast(size_t)(j + firstIndex)] = newelem;
4248 return newval;
4251 /* Block assignment, initialization of static arrays
4252 * x[] = newval
4253 * x may be a multidimensional static array. (Note that this
4254 * only happens with array literals, never with strings).
4256 struct RecursiveBlock
4258 InterState* istate;
4259 Expression newval;
4260 bool refCopy;
4261 bool needsPostblit;
4262 bool needsDtor;
4264 Expression assignTo(ArrayLiteralExp ae)
4266 return assignTo(ae, 0, ae.elements.length);
4269 Expression assignTo(ArrayLiteralExp ae, size_t lwr, size_t upr)
4271 Expressions* w = ae.elements;
4272 assert(ae.type.ty == Tsarray || ae.type.ty == Tarray || ae.type.ty == Tpointer);
4273 bool directblk = (cast(TypeNext)ae.type).next.equivalent(newval.type);
4274 for (size_t k = lwr; k < upr; k++)
4276 if (!directblk && (*w)[k].op == EXP.arrayLiteral)
4278 // Multidimensional array block assign
4279 if (Expression ex = assignTo((*w)[k].isArrayLiteralExp()))
4280 return ex;
4282 else if (refCopy)
4284 (*w)[k] = newval;
4286 else if (!needsPostblit && !needsDtor)
4288 assignInPlace((*w)[k], newval);
4290 else
4292 Expression oldelem = (*w)[k];
4293 Expression tmpelem = needsDtor ? copyLiteral(oldelem).copy() : null;
4294 assignInPlace(oldelem, newval);
4295 if (needsPostblit)
4297 if (Expression ex = evaluatePostblit(istate, oldelem))
4298 return ex;
4300 if (needsDtor)
4302 // https://issues.dlang.org/show_bug.cgi?id=14860
4303 if (Expression ex = evaluateDtor(istate, tmpelem))
4304 return ex;
4308 return null;
4312 Type tn = newval.type.toBasetype();
4313 bool wantRef = (tn.ty == Tarray || isAssocArray(tn) || tn.ty == Tclass);
4314 bool cow = newval.op != EXP.structLiteral && newval.op != EXP.arrayLiteral && newval.op != EXP.string_;
4315 Type tb = tn.baseElemOf();
4316 StructDeclaration sd = (tb.ty == Tstruct ? (cast(TypeStruct)tb).sym : null);
4318 RecursiveBlock rb;
4319 rb.istate = istate;
4320 rb.newval = newval;
4321 rb.refCopy = wantRef || cow;
4322 rb.needsPostblit = sd && sd.postblit && e.op != EXP.blit && e.e2.isLvalue();
4323 rb.needsDtor = sd && sd.dtor && (e.op == EXP.assign || e.op == EXP.loweredAssignExp);
4324 if (Expression ex = rb.assignTo(existingAE, cast(size_t)lowerbound, cast(size_t)upperbound))
4325 return ex;
4327 if (goal == CTFEGoal.Nothing)
4328 return null; // avoid creating an unused literal
4329 auto retslice = ctfeEmplaceExp!SliceExp(e.loc, existingAE,
4330 ctfeEmplaceExp!IntegerExp(e.loc, firstIndex, Type.tsize_t),
4331 ctfeEmplaceExp!IntegerExp(e.loc, firstIndex + upperbound - lowerbound, Type.tsize_t));
4332 retslice.type = e.type;
4333 return interpret(pue, retslice, istate);
4336 error(e.loc, "slice operation `%s = %s` cannot be evaluated at compile time", e1.toChars(), newval.toChars());
4337 return CTFEExp.cantexp;
4340 override void visit(AssignExp e)
4342 interpretAssignCommon(e, null);
4345 override void visit(BinAssignExp e)
4347 switch (e.op)
4349 case EXP.addAssign:
4350 interpretAssignCommon(e, &Add);
4351 return;
4353 case EXP.minAssign:
4354 interpretAssignCommon(e, &Min);
4355 return;
4357 case EXP.concatenateAssign:
4358 case EXP.concatenateElemAssign:
4359 case EXP.concatenateDcharAssign:
4360 interpretAssignCommon(e, &ctfeCat);
4361 return;
4363 case EXP.mulAssign:
4364 interpretAssignCommon(e, &Mul);
4365 return;
4367 case EXP.divAssign:
4368 interpretAssignCommon(e, &Div);
4369 return;
4371 case EXP.modAssign:
4372 interpretAssignCommon(e, &Mod);
4373 return;
4375 case EXP.leftShiftAssign:
4376 interpretAssignCommon(e, &Shl);
4377 return;
4379 case EXP.rightShiftAssign:
4380 interpretAssignCommon(e, &Shr);
4381 return;
4383 case EXP.unsignedRightShiftAssign:
4384 interpretAssignCommon(e, &Ushr);
4385 return;
4387 case EXP.andAssign:
4388 interpretAssignCommon(e, &And);
4389 return;
4391 case EXP.orAssign:
4392 interpretAssignCommon(e, &Or);
4393 return;
4395 case EXP.xorAssign:
4396 interpretAssignCommon(e, &Xor);
4397 return;
4399 case EXP.powAssign:
4400 interpretAssignCommon(e, &Pow);
4401 return;
4403 default:
4404 assert(0);
4408 override void visit(PostExp e)
4410 debug (LOG)
4412 printf("%s PostExp::interpret() %s\n", e.loc.toChars(), e.toChars());
4414 if (e.op == EXP.plusPlus)
4415 interpretAssignCommon(e, &Add, 1);
4416 else
4417 interpretAssignCommon(e, &Min, 1);
4418 debug (LOG)
4420 if (CTFEExp.isCantExp(result))
4421 printf("PostExp::interpret() CANT\n");
4425 /* Return 1 if e is a p1 > p2 or p1 >= p2 pointer comparison;
4426 * -1 if e is a p1 < p2 or p1 <= p2 pointer comparison;
4427 * 0 otherwise
4429 static int isPointerCmpExp(Expression e, Expression* p1, Expression* p2)
4431 int ret = 1;
4432 while (e.op == EXP.not)
4434 ret *= -1;
4435 e = e.isNotExp().e1;
4437 switch (e.op)
4439 case EXP.lessThan:
4440 case EXP.lessOrEqual:
4441 ret *= -1;
4442 goto case; /+ fall through +/
4443 case EXP.greaterThan:
4444 case EXP.greaterOrEqual:
4445 *p1 = e.isBinExp().e1;
4446 *p2 = e.isBinExp().e2;
4447 if (!(isPointer((*p1).type) && isPointer((*p2).type)))
4448 ret = 0;
4449 break;
4451 default:
4452 ret = 0;
4453 break;
4455 return ret;
4458 /** If this is a four pointer relation, evaluate it, else return NULL.
4460 * This is an expression of the form (p1 > q1 && p2 < q2) or (p1 < q1 || p2 > q2)
4461 * where p1, p2 are expressions yielding pointers to memory block p,
4462 * and q1, q2 are expressions yielding pointers to memory block q.
4463 * This expression is valid even if p and q are independent memory
4464 * blocks and are therefore not normally comparable; the && form returns true
4465 * if [p1..p2] lies inside [q1..q2], and false otherwise; the || form returns
4466 * true if [p1..p2] lies outside [q1..q2], and false otherwise.
4468 * Within the expression, any ordering of p1, p2, q1, q2 is permissible;
4469 * the comparison operators can be any of >, <, <=, >=, provided that
4470 * both directions (p > q and p < q) are checked. Additionally the
4471 * relational sub-expressions can be negated, eg
4472 * (!(q1 < p1) && p2 <= q2) is valid.
4474 private void interpretFourPointerRelation(UnionExp* pue, BinExp e)
4476 assert(e.op == EXP.andAnd || e.op == EXP.orOr);
4478 /* It can only be an isInside expression, if both e1 and e2 are
4479 * directional pointer comparisons.
4480 * Note that this check can be made statically; it does not depends on
4481 * any runtime values. This allows a JIT implementation to compile a
4482 * special AndAndPossiblyInside, keeping the normal AndAnd case efficient.
4485 // Save the pointer expressions and the comparison directions,
4486 // so we can use them later.
4487 Expression p1 = null;
4488 Expression p2 = null;
4489 Expression p3 = null;
4490 Expression p4 = null;
4491 int dir1 = isPointerCmpExp(e.e1, &p1, &p2);
4492 int dir2 = isPointerCmpExp(e.e2, &p3, &p4);
4493 if (dir1 == 0 || dir2 == 0)
4495 result = null;
4496 return;
4499 //printf("FourPointerRelation %s\n", toChars());
4501 UnionExp ue1 = void;
4502 UnionExp ue2 = void;
4503 UnionExp ue3 = void;
4504 UnionExp ue4 = void;
4506 // Evaluate the first two pointers
4507 p1 = interpret(&ue1, p1, istate);
4508 if (exceptionOrCant(p1))
4509 return;
4510 p2 = interpret(&ue2, p2, istate);
4511 if (exceptionOrCant(p2))
4512 return;
4513 dinteger_t ofs1, ofs2;
4514 Expression agg1 = getAggregateFromPointer(p1, &ofs1);
4515 Expression agg2 = getAggregateFromPointer(p2, &ofs2);
4517 if (!pointToSameMemoryBlock(agg1, agg2) && agg1.op != EXP.null_ && agg2.op != EXP.null_)
4519 // Here it is either CANT_INTERPRET,
4520 // or an IsInside comparison returning false.
4521 p3 = interpret(&ue3, p3, istate);
4522 if (CTFEExp.isCantExp(p3))
4523 return;
4524 // Note that it is NOT legal for it to throw an exception!
4525 Expression except = null;
4526 if (exceptionOrCantInterpret(p3))
4527 except = p3;
4528 else
4530 p4 = interpret(&ue4, p4, istate);
4531 if (CTFEExp.isCantExp(p4))
4533 result = p4;
4534 return;
4536 if (exceptionOrCantInterpret(p4))
4537 except = p4;
4539 if (except)
4541 error(e.loc, "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());
4542 result = CTFEExp.cantexp;
4543 return;
4545 dinteger_t ofs3, ofs4;
4546 Expression agg3 = getAggregateFromPointer(p3, &ofs3);
4547 Expression agg4 = getAggregateFromPointer(p4, &ofs4);
4548 // The valid cases are:
4549 // p1 > p2 && p3 > p4 (same direction, also for < && <)
4550 // p1 > p2 && p3 < p4 (different direction, also < && >)
4551 // Changing any > into >= doesn't affect the result
4552 if ((dir1 == dir2 && pointToSameMemoryBlock(agg1, agg4) && pointToSameMemoryBlock(agg2, agg3)) ||
4553 (dir1 != dir2 && pointToSameMemoryBlock(agg1, agg3) && pointToSameMemoryBlock(agg2, agg4)))
4555 // it's a legal two-sided comparison
4556 emplaceExp!(IntegerExp)(pue, e.loc, (e.op == EXP.andAnd) ? 0 : 1, e.type);
4557 result = pue.exp();
4558 return;
4560 // It's an invalid four-pointer comparison. Either the second
4561 // comparison is in the same direction as the first, or else
4562 // more than two memory blocks are involved (either two independent
4563 // invalid comparisons are present, or else agg3 == agg4).
4564 error(e.loc, "comparison `%s` of pointers to unrelated memory blocks is indeterminate at compile time, even when combined with `%s`.", e.e1.toChars(), e.e2.toChars());
4565 result = CTFEExp.cantexp;
4566 return;
4568 // The first pointer expression didn't need special treatment, so we
4569 // we need to interpret the entire expression exactly as a normal && or ||.
4570 // This is easy because we haven't evaluated e2 at all yet, and we already
4571 // know it will return a bool.
4572 // But we mustn't evaluate the pointer expressions in e1 again, in case
4573 // they have side-effects.
4574 bool nott = false;
4575 Expression ex = e.e1;
4576 while (1)
4578 if (auto ne = ex.isNotExp())
4580 nott = !nott;
4581 ex = ne.e1;
4583 else
4584 break;
4587 /** Negate relational operator, eg >= becomes <
4588 * Params:
4589 * op = comparison operator to negate
4590 * Returns:
4591 * negate operator
4593 static EXP negateRelation(EXP op) pure
4595 switch (op)
4597 case EXP.greaterOrEqual: op = EXP.lessThan; break;
4598 case EXP.greaterThan: op = EXP.lessOrEqual; break;
4599 case EXP.lessOrEqual: op = EXP.greaterThan; break;
4600 case EXP.lessThan: op = EXP.greaterOrEqual; break;
4601 default: assert(0);
4603 return op;
4606 const EXP cmpop = nott ? negateRelation(ex.op) : ex.op;
4607 const cmp = comparePointers(cmpop, agg1, ofs1, agg2, ofs2);
4608 // We already know this is a valid comparison.
4609 assert(cmp >= 0);
4610 if (e.op == EXP.andAnd && cmp == 1 || e.op == EXP.orOr && cmp == 0)
4612 result = interpret(pue, e.e2, istate);
4613 return;
4615 emplaceExp!(IntegerExp)(pue, e.loc, (e.op == EXP.andAnd) ? 0 : 1, e.type);
4616 result = pue.exp();
4619 override void visit(LogicalExp e)
4621 debug (LOG)
4623 printf("%s LogicalExp::interpret() %s\n", e.loc.toChars(), e.toChars());
4625 // Check for an insidePointer expression, evaluate it if so
4626 interpretFourPointerRelation(pue, e);
4627 if (result)
4628 return;
4630 UnionExp ue1 = void;
4631 result = interpret(&ue1, e.e1, istate);
4632 if (exceptionOrCant(result))
4633 return;
4635 bool res;
4636 const andand = e.op == EXP.andAnd;
4637 if (andand ? result.toBool().hasValue(false) : isTrueBool(result))
4638 res = !andand;
4639 else if (andand ? isTrueBool(result) : result.toBool().hasValue(false))
4641 UnionExp ue2 = void;
4642 result = interpret(&ue2, e.e2, istate);
4643 if (exceptionOrCant(result))
4644 return;
4645 if (result.op == EXP.voidExpression)
4647 assert(e.type.ty == Tvoid);
4648 result = null;
4649 return;
4651 if (result.toBool().hasValue(false))
4652 res = false;
4653 else if (isTrueBool(result))
4654 res = true;
4655 else
4657 error(e.loc, "`%s` does not evaluate to a `bool`", result.toChars());
4658 result = CTFEExp.cantexp;
4659 return;
4662 else
4664 error(e.loc, "`%s` cannot be interpreted as a `bool`", result.toChars());
4665 result = CTFEExp.cantexp;
4666 return;
4668 incUsageCtfe(istate, e.e2.loc);
4670 if (goal != CTFEGoal.Nothing)
4672 if (e.type.equals(Type.tbool))
4673 result = IntegerExp.createBool(res);
4674 else
4676 emplaceExp!(IntegerExp)(pue, e.loc, res, e.type);
4677 result = pue.exp();
4683 // Print a stack trace, starting from callingExp which called fd.
4684 // To shorten the stack trace, try to detect recursion.
4685 private void showCtfeBackTrace(CallExp callingExp, FuncDeclaration fd)
4687 if (ctfeGlobals.stackTraceCallsToSuppress > 0)
4689 --ctfeGlobals.stackTraceCallsToSuppress;
4690 return;
4692 errorSupplemental(callingExp.loc, "called from here: `%s`", callingExp.toChars());
4693 // Quit if it's not worth trying to compress the stack trace
4694 if (ctfeGlobals.callDepth < 6 || global.params.v.verbose)
4695 return;
4696 // Recursion happens if the current function already exists in the call stack.
4697 int numToSuppress = 0;
4698 int recurseCount = 0;
4699 int depthSoFar = 0;
4700 InterState* lastRecurse = istate;
4701 for (InterState* cur = istate; cur; cur = cur.caller)
4703 if (cur.fd == fd)
4705 ++recurseCount;
4706 numToSuppress = depthSoFar;
4707 lastRecurse = cur;
4709 ++depthSoFar;
4711 // We need at least three calls to the same function, to make compression worthwhile
4712 if (recurseCount < 2)
4713 return;
4714 // We found a useful recursion. Print all the calls involved in the recursion
4715 errorSupplemental(fd.loc, "%d recursive calls to function `%s`", recurseCount, fd.toChars());
4716 for (InterState* cur = istate; cur.fd != fd; cur = cur.caller)
4718 errorSupplemental(cur.fd.loc, "recursively called from function `%s`", cur.fd.toChars());
4720 // We probably didn't enter the recursion in this function.
4721 // Go deeper to find the real beginning.
4722 InterState* cur = istate;
4723 while (lastRecurse.caller && cur.fd == lastRecurse.caller.fd)
4725 cur = cur.caller;
4726 lastRecurse = lastRecurse.caller;
4727 ++numToSuppress;
4729 ctfeGlobals.stackTraceCallsToSuppress = numToSuppress;
4732 override void visit(CallExp e)
4734 debug (LOG)
4736 printf("%s CallExp::interpret() %s\n", e.loc.toChars(), e.toChars());
4738 Expression pthis = null;
4739 FuncDeclaration fd = null;
4741 Expression ecall = interpretRegion(e.e1, istate);
4742 if (exceptionOrCant(ecall))
4743 return;
4745 if (auto dve = ecall.isDotVarExp())
4747 // Calling a member function
4748 pthis = dve.e1;
4749 fd = dve.var.isFuncDeclaration();
4750 assert(fd);
4752 if (auto dte = pthis.isDotTypeExp())
4753 pthis = dte.e1;
4755 else if (auto ve = ecall.isVarExp())
4757 fd = ve.var.isFuncDeclaration();
4758 assert(fd);
4760 // If `_d_HookTraceImpl` is found, resolve the underlying hook and replace `e` and `fd` with it.
4761 removeHookTraceImpl(e, fd);
4763 if (fd.ident == Id.__ArrayPostblit || fd.ident == Id.__ArrayDtor)
4765 assert(e.arguments.length == 1);
4766 Expression ea = (*e.arguments)[0];
4767 // printf("1 ea = %s %s\n", ea.type.toChars(), ea.toChars());
4768 if (auto se = ea.isSliceExp())
4769 ea = se.e1;
4770 if (auto ce = ea.isCastExp())
4771 ea = ce.e1;
4773 // printf("2 ea = %s, %s %s\n", ea.type.toChars(), EXPtoString(ea.op).ptr, ea.toChars());
4774 if (ea.op == EXP.variable || ea.op == EXP.symbolOffset)
4775 result = getVarExp(e.loc, istate, (cast(SymbolExp)ea).var, CTFEGoal.RValue);
4776 else if (auto ae = ea.isAddrExp())
4777 result = interpretRegion(ae.e1, istate);
4779 // https://issues.dlang.org/show_bug.cgi?id=18871
4780 // https://issues.dlang.org/show_bug.cgi?id=18819
4781 else if (auto ale = ea.isArrayLiteralExp())
4782 result = interpretRegion(ale, istate);
4784 else
4785 assert(0);
4786 if (CTFEExp.isCantExp(result))
4787 return;
4789 if (fd.ident == Id.__ArrayPostblit)
4790 result = evaluatePostblit(istate, result);
4791 else
4792 result = evaluateDtor(istate, result);
4793 if (!result)
4794 result = CTFEExp.voidexp;
4795 return;
4797 else if (isArrayConstruction(fd.ident))
4799 // In expressionsem.d, `T[x] ea = eb;` was lowered to:
4800 // `_d_array{,set}ctor(ea[], eb[]);`.
4801 // The following code will rewrite it back to `ea = eb` and
4802 // then interpret that expression.
4804 if (fd.ident == Id._d_arrayctor)
4805 assert(e.arguments.length == 3);
4806 else
4807 assert(e.arguments.length == 2);
4809 Expression ea = (*e.arguments)[0];
4810 if (ea.isCastExp)
4811 ea = ea.isCastExp.e1;
4813 Expression eb = (*e.arguments)[1];
4814 if (eb.isCastExp() && fd.ident == Id._d_arrayctor)
4815 eb = eb.isCastExp.e1;
4817 ConstructExp ce = new ConstructExp(e.loc, ea, eb);
4818 ce.type = ea.type;
4820 ce.type = ea.type;
4821 result = interpret(ce, istate);
4823 return;
4825 else if (fd.ident == Id._d_arrayappendT || fd.ident == Id._d_arrayappendTTrace)
4827 // In expressionsem.d `ea ~= eb` was lowered to `_d_arrayappendT{,Trace}({file, line, funcname}, ea, eb);`.
4828 // The following code will rewrite it back to `ea ~= eb` and then interpret that expression.
4829 Expression lhs, rhs;
4831 if (fd.ident == Id._d_arrayappendT)
4833 assert(e.arguments.length == 2);
4834 lhs = (*e.arguments)[0];
4835 rhs = (*e.arguments)[1];
4837 else
4839 assert(e.arguments.length == 5);
4840 lhs = (*e.arguments)[3];
4841 rhs = (*e.arguments)[4];
4844 auto cae = new CatAssignExp(e.loc, lhs, rhs);
4845 cae.type = e.type;
4847 result = interpretRegion(cae, istate, CTFEGoal.LValue);
4848 return;
4850 else if (fd.ident == Id._d_arrayappendcTX)
4851 assert(0, "CTFE cannot interpret _d_arrayappendcTX!");
4853 else if (auto soe = ecall.isSymOffExp())
4855 fd = soe.var.isFuncDeclaration();
4856 assert(fd && soe.offset == 0);
4858 else if (auto de = ecall.isDelegateExp())
4860 // Calling a delegate
4861 fd = de.func;
4862 pthis = de.e1;
4864 // Special handling for: &nestedfunc --> DelegateExp(VarExp(nestedfunc), nestedfunc)
4865 if (auto ve = pthis.isVarExp())
4866 if (ve.var == fd)
4867 pthis = null; // context is not necessary for CTFE
4869 else if (auto fe = ecall.isFuncExp())
4871 // Calling a delegate literal
4872 fd = fe.fd;
4874 else
4876 // delegate.funcptr()
4877 // others
4878 error(e.loc, "cannot call `%s` at compile time", e.toChars());
4879 result = CTFEExp.cantexp;
4880 return;
4882 if (!fd)
4884 error(e.loc, "CTFE internal error: cannot evaluate `%s` at compile time", e.toChars());
4885 result = CTFEExp.cantexp;
4886 return;
4888 if (pthis)
4890 // Member function call
4892 // Currently this is satisfied because closure is not yet supported.
4893 assert(!fd.isNested() || fd.needThis());
4895 if (pthis.op == EXP.typeid_)
4897 error(pthis.loc, "static variable `%s` cannot be read at compile time", pthis.toChars());
4898 result = CTFEExp.cantexp;
4899 return;
4901 assert(pthis);
4903 if (pthis.op == EXP.null_)
4905 assert(pthis.type.toBasetype().ty == Tclass);
4906 error(e.loc, "function call through null class reference `%s`", pthis.toChars());
4907 result = CTFEExp.cantexp;
4908 return;
4911 assert(pthis.op == EXP.structLiteral || pthis.op == EXP.classReference || pthis.op == EXP.type);
4913 if (fd.isVirtual() && !e.directcall)
4915 // Make a virtual function call.
4916 // Get the function from the vtable of the original class
4917 ClassDeclaration cd = pthis.isClassReferenceExp().originalClass();
4919 // We can't just use the vtable index to look it up, because
4920 // vtables for interfaces don't get populated until the glue layer.
4921 fd = cd.findFunc(fd.ident, fd.type.isTypeFunction());
4922 assert(fd);
4926 if (fd && fd.semanticRun >= PASS.semantic3done && fd.hasSemantic3Errors())
4928 error(e.loc, "CTFE failed because of previous errors in `%s`", fd.toChars());
4929 result = CTFEExp.cantexp;
4930 return;
4933 // Check for built-in functions
4934 result = evaluateIfBuiltin(pue, istate, e.loc, fd, e.arguments, pthis);
4935 if (result)
4936 return;
4938 if (!fd.fbody)
4940 error(e.loc, "`%s` cannot be interpreted at compile time, because it has no available source code", fd.toChars());
4941 result = CTFEExp.showcontext;
4942 return;
4945 result = interpretFunction(pue, fd, istate, e.arguments, pthis);
4946 if (result.op == EXP.voidExpression)
4947 return;
4948 if (!exceptionOrCantInterpret(result))
4950 if (goal != CTFEGoal.LValue) // Peel off CTFE reference if it's unnecessary
4952 if (result == pue.exp())
4953 result = pue.copy();
4954 result = interpret(pue, result, istate);
4957 if (!exceptionOrCantInterpret(result))
4959 result = paintTypeOntoLiteral(pue, e.type, result);
4960 result.loc = e.loc;
4962 else if (CTFEExp.isCantExp(result) && !global.gag)
4963 showCtfeBackTrace(e, fd); // Print a stack trace.
4966 override void visit(CommaExp e)
4968 debug (LOG)
4970 printf("%s CommaExp::interpret() %s\n", e.loc.toChars(), e.toChars());
4973 bool isNewThrowableHook()
4975 auto de = e.e1.isDeclarationExp();
4976 if (de is null)
4977 return false;
4979 auto vd = de.declaration.isVarDeclaration();
4980 if (vd is null)
4981 return false;
4983 auto ei = vd._init.isExpInitializer();
4984 if (ei is null)
4985 return false;
4987 auto ce = ei.exp.isConstructExp();
4988 if (ce is null)
4989 return false;
4991 return isRuntimeHook(ce.e2, Id._d_newThrowable) !is null;
4994 if (auto ce = isRuntimeHook(e.e1, Id._d_arrayappendcTX))
4996 // In expressionsem.d `arr ~= elem` was lowered to
4997 // `_d_arrayappendcTX(arr, elem), arr[arr.length - 1] = elem, elem;`.
4998 // The following code will rewrite it back to `arr ~= elem`
4999 // and then interpret that expression.
5000 assert(ce.arguments.length == 2);
5002 auto arr = (*ce.arguments)[0];
5003 auto elem = e.e2.isConstructExp().e2;
5004 assert(elem);
5006 auto cae = new CatAssignExp(e.loc, arr, elem);
5007 cae.type = arr.type;
5009 result = interpret(cae, istate);
5010 return;
5012 else if (isNewThrowableHook())
5014 // In expressionsem.d `throw new Exception(args)` was lowered to
5015 // `throw (tmp = _d_newThrowable!Exception(), tmp.ctor(args), tmp)`.
5016 // The following code will rewrite it back to `throw new Exception(args)`
5017 // and then interpret this expression instead.
5018 auto ce = e.e2.isCallExp();
5019 assert(ce);
5021 auto ne = new NewExp(e.loc, null, e.type, ce.arguments);
5022 ne.type = e.e1.type;
5024 result = interpret(ne, istate);
5025 return;
5028 // If it creates a variable, and there's no context for
5029 // the variable to be created in, we need to create one now.
5030 InterState istateComma;
5031 if (!istate && firstComma(e.e1).op == EXP.declaration)
5033 ctfeGlobals.stack.startFrame(null);
5034 istate = &istateComma;
5037 void endTempStackFrame()
5039 // If we created a temporary stack frame, end it now.
5040 if (istate == &istateComma)
5041 ctfeGlobals.stack.endFrame();
5044 result = CTFEExp.cantexp;
5046 // If the comma returns a temporary variable, it needs to be an lvalue
5047 // (this is particularly important for struct constructors)
5048 if (e.e1.op == EXP.declaration &&
5049 e.e2.op == EXP.variable &&
5050 e.e1.isDeclarationExp().declaration == e.e2.isVarExp().var &&
5051 e.e2.isVarExp().var.storage_class & STC.ctfe)
5053 VarExp ve = e.e2.isVarExp();
5054 VarDeclaration v = ve.var.isVarDeclaration();
5055 ctfeGlobals.stack.push(v);
5056 if (!v._init && !getValue(v))
5058 setValue(v, copyLiteral(v.type.defaultInitLiteral(e.loc)).copy());
5060 if (!getValue(v))
5062 Expression newval = v._init.initializerToExpression();
5063 // Bug 4027. Copy constructors are a weird case where the
5064 // initializer is a void function (the variable is modified
5065 // through a reference parameter instead).
5066 newval = interpretRegion(newval, istate);
5067 if (exceptionOrCant(newval))
5068 return endTempStackFrame();
5069 if (newval.op != EXP.voidExpression)
5071 // v isn't necessarily null.
5072 setValueWithoutChecking(v, copyLiteral(newval).copy());
5076 else
5078 UnionExp ue = void;
5079 auto e1 = interpret(&ue, e.e1, istate, CTFEGoal.Nothing);
5080 if (exceptionOrCant(e1))
5081 return endTempStackFrame();
5083 result = interpret(pue, e.e2, istate, goal);
5084 return endTempStackFrame();
5087 override void visit(CondExp e)
5089 debug (LOG)
5091 printf("%s CondExp::interpret() %s\n", e.loc.toChars(), e.toChars());
5093 UnionExp uecond = void;
5094 Expression econd;
5095 econd = interpret(&uecond, e.econd, istate);
5096 if (exceptionOrCant(econd))
5097 return;
5099 if (isPointer(e.econd.type))
5101 if (econd.op != EXP.null_)
5103 econd = IntegerExp.createBool(true);
5107 if (isTrueBool(econd))
5109 result = interpret(pue, e.e1, istate, goal);
5110 incUsageCtfe(istate, e.e1.loc);
5112 else if (econd.toBool().hasValue(false))
5114 result = interpret(pue, e.e2, istate, goal);
5115 incUsageCtfe(istate, e.e2.loc);
5117 else
5119 error(e.loc, "`%s` does not evaluate to boolean result at compile time", e.econd.toChars());
5120 result = CTFEExp.cantexp;
5124 override void visit(ArrayLengthExp e)
5126 debug (LOG)
5128 printf("%s ArrayLengthExp::interpret() %s\n", e.loc.toChars(), e.toChars());
5130 UnionExp ue1;
5131 Expression e1 = interpret(&ue1, e.e1, istate);
5132 assert(e1);
5133 if (exceptionOrCant(e1))
5134 return;
5135 if (e1.op != EXP.string_ && e1.op != EXP.arrayLiteral && e1.op != EXP.slice && e1.op != EXP.null_)
5137 error(e.loc, "`%s` cannot be evaluated at compile time", e.toChars());
5138 result = CTFEExp.cantexp;
5139 return;
5141 emplaceExp!(IntegerExp)(pue, e.loc, resolveArrayLength(e1), e.type);
5142 result = pue.exp();
5146 * Interpret the vector expression as an array literal.
5147 * Params:
5148 * pue = non-null pointer to temporary storage that can be used to store the return value
5149 * e = Expression to interpret
5150 * Returns:
5151 * resulting array literal or 'e' if unable to interpret
5153 static Expression interpretVectorToArray(UnionExp* pue, VectorExp e)
5155 if (auto ale = e.e1.isArrayLiteralExp())
5156 return ale; // it's already an array literal
5157 if (e.e1.op == EXP.int64 || e.e1.op == EXP.float64)
5159 // Convert literal __vector(int) -> __vector([array])
5160 auto elements = new Expressions(e.dim);
5161 foreach (ref element; *elements)
5162 element = copyLiteral(e.e1).copy();
5163 auto type = (e.type.ty == Tvector) ? e.type.isTypeVector().basetype : e.type.isTypeSArray();
5164 assert(type);
5165 emplaceExp!(ArrayLiteralExp)(pue, e.loc, type, elements);
5166 auto ale = pue.exp().isArrayLiteralExp();
5167 ale.ownedByCtfe = OwnedBy.ctfe;
5168 return ale;
5170 return e;
5173 override void visit(VectorExp e)
5175 debug (LOG)
5177 printf("%s VectorExp::interpret() %s\n", e.loc.toChars(), e.toChars());
5179 if (e.ownedByCtfe >= OwnedBy.ctfe) // We've already interpreted all the elements
5181 result = e;
5182 return;
5184 Expression e1 = interpret(pue, e.e1, istate);
5185 assert(e1);
5186 if (exceptionOrCant(e1))
5187 return;
5188 if (e1.op != EXP.arrayLiteral && e1.op != EXP.int64 && e1.op != EXP.float64)
5190 error(e.loc, "`%s` cannot be evaluated at compile time", e.toChars());
5191 result = CTFEExp.cantexp;
5192 return;
5194 if (e1 == pue.exp())
5195 e1 = pue.copy();
5196 emplaceExp!(VectorExp)(pue, e.loc, e1, e.to);
5197 auto ve = pue.exp().isVectorExp();
5198 ve.type = e.type;
5199 ve.dim = e.dim;
5200 ve.ownedByCtfe = OwnedBy.ctfe;
5201 result = ve;
5204 override void visit(VectorArrayExp e)
5206 debug (LOG)
5208 printf("%s VectorArrayExp::interpret() %s\n", e.loc.toChars(), e.toChars());
5210 Expression e1 = interpret(pue, e.e1, istate);
5211 assert(e1);
5212 if (exceptionOrCant(e1))
5213 return;
5214 if (auto ve = e1.isVectorExp())
5216 result = interpretVectorToArray(pue, ve);
5217 if (result.op != EXP.vector)
5218 return;
5220 error(e.loc, "`%s` cannot be evaluated at compile time", e.toChars());
5221 result = CTFEExp.cantexp;
5224 override void visit(DelegatePtrExp e)
5226 debug (LOG)
5228 printf("%s DelegatePtrExp::interpret() %s\n", e.loc.toChars(), e.toChars());
5230 Expression e1 = interpret(pue, e.e1, istate);
5231 assert(e1);
5232 if (exceptionOrCant(e1))
5233 return;
5234 error(e.loc, "`%s` cannot be evaluated at compile time", e.toChars());
5235 result = CTFEExp.cantexp;
5238 override void visit(DelegateFuncptrExp e)
5240 debug (LOG)
5242 printf("%s DelegateFuncptrExp::interpret() %s\n", e.loc.toChars(), e.toChars());
5244 Expression e1 = interpret(pue, e.e1, istate);
5245 assert(e1);
5246 if (exceptionOrCant(e1))
5247 return;
5248 error(e.loc, "`%s` cannot be evaluated at compile time", e.toChars());
5249 result = CTFEExp.cantexp;
5252 static bool resolveIndexing(IndexExp e, InterState* istate, Expression* pagg, uinteger_t* pidx, bool modify)
5254 assert(e.e1.type.toBasetype().ty != Taarray);
5256 if (e.e1.type.toBasetype().ty == Tpointer)
5258 // Indexing a pointer. Note that there is no $ in this case.
5259 Expression e1 = interpretRegion(e.e1, istate);
5260 if (exceptionOrCantInterpret(e1))
5261 return false;
5263 Expression e2 = interpretRegion(e.e2, istate);
5264 if (exceptionOrCantInterpret(e2))
5265 return false;
5266 sinteger_t indx = e2.toInteger();
5268 dinteger_t ofs;
5269 Expression agg = getAggregateFromPointer(e1, &ofs);
5271 if (agg.op == EXP.null_)
5273 error(e.loc, "cannot index through null pointer `%s`", e.e1.toChars());
5274 return false;
5276 if (agg.op == EXP.int64)
5278 error(e.loc, "cannot index through invalid pointer `%s` of value `%s`", e.e1.toChars(), e1.toChars());
5279 return false;
5281 // Pointer to a non-array variable
5282 if (agg.op == EXP.symbolOffset)
5284 error(e.loc, "mutable variable `%s` cannot be %s at compile time, even through a pointer", cast(char*)(modify ? "modified" : "read"), agg.isSymOffExp().var.toChars());
5285 return false;
5288 if (agg.op == EXP.arrayLiteral || agg.op == EXP.string_)
5290 dinteger_t len = resolveArrayLength(agg);
5291 if (ofs + indx >= len)
5293 error(e.loc, "pointer index `[%lld]` exceeds allocated memory block `[0..%lld]`", ofs + indx, len);
5294 return false;
5297 else
5299 if (ofs + indx != 0)
5301 error(e.loc, "pointer index `[%lld]` lies outside memory block `[0..1]`", ofs + indx);
5302 return false;
5305 *pagg = agg;
5306 *pidx = ofs + indx;
5307 return true;
5310 Expression e1 = interpretRegion(e.e1, istate);
5311 if (exceptionOrCantInterpret(e1))
5312 return false;
5313 if (e1.op == EXP.null_)
5315 error(e.loc, "cannot index null array `%s`", e.e1.toChars());
5316 return false;
5318 if (auto ve = e1.isVectorExp())
5320 UnionExp ue = void;
5321 e1 = interpretVectorToArray(&ue, ve);
5322 e1 = (e1 == ue.exp()) ? ue.copy() : e1;
5325 // Set the $ variable, and find the array literal to modify
5326 dinteger_t len;
5327 if (e1.op == EXP.variable && e1.type.toBasetype().ty == Tsarray)
5328 len = e1.type.toBasetype().isTypeSArray().dim.toInteger();
5329 else
5331 if (e1.op != EXP.arrayLiteral && e1.op != EXP.string_ && e1.op != EXP.slice && e1.op != EXP.vector)
5333 error(e.loc, "cannot determine length of `%s` at compile time", e.e1.toChars());
5334 return false;
5336 len = resolveArrayLength(e1);
5339 if (e.lengthVar)
5341 Expression dollarExp = ctfeEmplaceExp!IntegerExp(e.loc, len, Type.tsize_t);
5342 ctfeGlobals.stack.push(e.lengthVar);
5343 setValue(e.lengthVar, dollarExp);
5345 Expression e2 = interpretRegion(e.e2, istate);
5346 if (e.lengthVar)
5347 ctfeGlobals.stack.pop(e.lengthVar); // $ is defined only inside []
5348 if (exceptionOrCantInterpret(e2))
5349 return false;
5350 if (e2.op != EXP.int64)
5352 error(e.loc, "CTFE internal error: non-integral index `[%s]`", e.e2.toChars());
5353 return false;
5356 if (auto se = e1.isSliceExp())
5358 // Simplify index of slice: agg[lwr..upr][indx] --> agg[indx']
5359 uinteger_t index = e2.toInteger();
5360 uinteger_t ilwr = se.lwr.toInteger();
5361 uinteger_t iupr = se.upr.toInteger();
5363 if (index > iupr - ilwr)
5365 error(e.loc, "index %llu exceeds array length %llu", index, iupr - ilwr);
5366 return false;
5368 *pagg = e1.isSliceExp().e1;
5369 *pidx = index + ilwr;
5371 else
5373 *pagg = e1;
5374 *pidx = e2.toInteger();
5375 if (len <= *pidx)
5377 error(e.loc, "array index %lld is out of bounds `[0..%lld]`", *pidx, len);
5378 return false;
5381 return true;
5384 override void visit(IndexExp e)
5386 debug (LOG)
5388 printf("%s IndexExp::interpret() %s, goal = %d\n", e.loc.toChars(), e.toChars(), goal);
5390 if (e.e1.type.toBasetype().ty == Tpointer)
5392 Expression agg;
5393 uinteger_t indexToAccess;
5394 if (!resolveIndexing(e, istate, &agg, &indexToAccess, false))
5396 result = CTFEExp.cantexp;
5397 return;
5399 if (agg.op == EXP.arrayLiteral || agg.op == EXP.string_)
5401 if (goal == CTFEGoal.LValue)
5403 // if we need a reference, IndexExp shouldn't be interpreting
5404 // the expression to a value, it should stay as a reference
5405 emplaceExp!(IndexExp)(pue, e.loc, agg, ctfeEmplaceExp!IntegerExp(e.e2.loc, indexToAccess, e.e2.type));
5406 result = pue.exp();
5407 result.type = e.type;
5408 return;
5410 result = ctfeIndex(pue, e.loc, e.type, agg, indexToAccess);
5411 return;
5413 else
5415 assert(indexToAccess == 0);
5416 result = interpretRegion(agg, istate, goal);
5417 if (exceptionOrCant(result))
5418 return;
5419 result = paintTypeOntoLiteral(pue, e.type, result);
5420 return;
5424 if (e.e1.type.toBasetype().ty == Taarray)
5426 Expression e1 = interpretRegion(e.e1, istate);
5427 if (exceptionOrCant(e1))
5428 return;
5429 if (e1.op == EXP.null_)
5431 if (goal == CTFEGoal.LValue && e1.type.ty == Taarray && e.modifiable)
5433 assert(0); // does not reach here?
5435 error(e.loc, "cannot index null array `%s`", e.e1.toChars());
5436 result = CTFEExp.cantexp;
5437 return;
5439 Expression e2 = interpretRegion(e.e2, istate);
5440 if (exceptionOrCant(e2))
5441 return;
5443 if (goal == CTFEGoal.LValue)
5445 // Pointer or reference of a scalar type
5446 if (e1 == e.e1 && e2 == e.e2)
5447 result = e;
5448 else
5450 emplaceExp!(IndexExp)(pue, e.loc, e1, e2);
5451 result = pue.exp();
5452 result.type = e.type;
5454 return;
5457 assert(e1.op == EXP.assocArrayLiteral);
5458 UnionExp e2tmp = void;
5459 e2 = resolveSlice(e2, &e2tmp);
5460 result = findKeyInAA(e.loc, e1.isAssocArrayLiteralExp(), e2);
5461 if (!result)
5463 error(e.loc, "key `%s` not found in associative array `%s`", e2.toChars(), e.e1.toChars());
5464 result = CTFEExp.cantexp;
5466 return;
5469 Expression agg;
5470 uinteger_t indexToAccess;
5471 if (!resolveIndexing(e, istate, &agg, &indexToAccess, false))
5473 result = CTFEExp.cantexp;
5474 return;
5477 if (goal == CTFEGoal.LValue)
5479 Expression e2 = ctfeEmplaceExp!IntegerExp(e.e2.loc, indexToAccess, Type.tsize_t);
5480 emplaceExp!(IndexExp)(pue, e.loc, agg, e2);
5481 result = pue.exp();
5482 result.type = e.type;
5483 return;
5486 result = ctfeIndex(pue, e.loc, e.type, agg, indexToAccess);
5487 if (exceptionOrCant(result))
5488 return;
5489 if (result.op == EXP.void_)
5491 error(e.loc, "`%s` is used before initialized", e.toChars());
5492 errorSupplemental(result.loc, "originally uninitialized here");
5493 result = CTFEExp.cantexp;
5494 return;
5496 if (result == pue.exp())
5497 result = result.copy();
5500 override void visit(SliceExp e)
5502 debug (LOG)
5504 printf("%s SliceExp::interpret() %s\n", e.loc.toChars(), e.toChars());
5506 if (e.e1.type.toBasetype().ty == Tpointer)
5508 // Slicing a pointer. Note that there is no $ in this case.
5509 Expression e1 = interpretRegion(e.e1, istate);
5510 if (exceptionOrCant(e1))
5511 return;
5512 if (e1.op == EXP.int64)
5514 error(e.loc, "cannot slice invalid pointer `%s` of value `%s`", e.e1.toChars(), e1.toChars());
5515 result = CTFEExp.cantexp;
5516 return;
5519 /* Evaluate lower and upper bounds of slice
5521 Expression lwr = interpretRegion(e.lwr, istate);
5522 if (exceptionOrCant(lwr))
5523 return;
5524 Expression upr = interpretRegion(e.upr, istate);
5525 if (exceptionOrCant(upr))
5526 return;
5527 uinteger_t ilwr = lwr.toInteger();
5528 uinteger_t iupr = upr.toInteger();
5530 dinteger_t ofs;
5531 Expression agg = getAggregateFromPointer(e1, &ofs);
5532 ilwr += ofs;
5533 iupr += ofs;
5534 if (agg.op == EXP.null_)
5536 if (iupr == ilwr)
5538 result = ctfeEmplaceExp!NullExp(e.loc);
5539 result.type = e.type;
5540 return;
5542 error(e.loc, "cannot slice null pointer `%s`", e.e1.toChars());
5543 result = CTFEExp.cantexp;
5544 return;
5546 if (agg.op == EXP.symbolOffset)
5548 error(e.loc, "slicing pointers to static variables is not supported in CTFE");
5549 result = CTFEExp.cantexp;
5550 return;
5552 if (agg.op != EXP.arrayLiteral && agg.op != EXP.string_)
5554 error(e.loc, "pointer `%s` cannot be sliced at compile time (it does not point to an array)", e.e1.toChars());
5555 result = CTFEExp.cantexp;
5556 return;
5558 assert(agg.op == EXP.arrayLiteral || agg.op == EXP.string_);
5559 dinteger_t len = ArrayLength(Type.tsize_t, agg).exp().toInteger();
5560 //Type *pointee = ((TypePointer *)agg.type)->next;
5561 if (sliceBoundsCheck(0, len, ilwr, iupr))
5563 error(e.loc, "pointer slice `[%lld..%lld]` exceeds allocated memory block `[0..%lld]`", ilwr, iupr, len);
5564 result = CTFEExp.cantexp;
5565 return;
5567 if (ofs != 0)
5569 lwr = ctfeEmplaceExp!IntegerExp(e.loc, ilwr, lwr.type);
5570 upr = ctfeEmplaceExp!IntegerExp(e.loc, iupr, upr.type);
5572 emplaceExp!(SliceExp)(pue, e.loc, agg, lwr, upr);
5573 result = pue.exp();
5574 result.type = e.type;
5575 return;
5578 CTFEGoal goal1 = CTFEGoal.RValue;
5579 if (goal == CTFEGoal.LValue)
5581 if (e.e1.type.toBasetype().ty == Tsarray)
5582 if (auto ve = e.e1.isVarExp())
5583 if (auto vd = ve.var.isVarDeclaration())
5584 if (vd.storage_class & STC.ref_)
5585 goal1 = CTFEGoal.LValue;
5587 Expression e1 = interpret(e.e1, istate, goal1);
5588 if (exceptionOrCant(e1))
5589 return;
5591 if (!e.lwr)
5593 result = paintTypeOntoLiteral(pue, e.type, e1);
5594 return;
5596 if (auto ve = e1.isVectorExp())
5598 e1 = interpretVectorToArray(pue, ve);
5599 e1 = (e1 == pue.exp()) ? pue.copy() : e1;
5602 /* Set dollar to the length of the array
5604 uinteger_t dollar;
5605 if ((e1.op == EXP.variable || e1.op == EXP.dotVariable) && e1.type.toBasetype().ty == Tsarray)
5606 dollar = e1.type.toBasetype().isTypeSArray().dim.toInteger();
5607 else
5609 if (e1.op != EXP.arrayLiteral && e1.op != EXP.string_ && e1.op != EXP.null_ && e1.op != EXP.slice && e1.op != EXP.vector)
5611 error(e.loc, "cannot determine length of `%s` at compile time", e1.toChars());
5612 result = CTFEExp.cantexp;
5613 return;
5615 dollar = resolveArrayLength(e1);
5618 /* Set the $ variable
5620 if (e.lengthVar)
5622 auto dollarExp = ctfeEmplaceExp!IntegerExp(e.loc, dollar, Type.tsize_t);
5623 ctfeGlobals.stack.push(e.lengthVar);
5624 setValue(e.lengthVar, dollarExp);
5627 /* Evaluate lower and upper bounds of slice
5629 Expression lwr = interpretRegion(e.lwr, istate);
5630 if (exceptionOrCant(lwr))
5632 if (e.lengthVar)
5633 ctfeGlobals.stack.pop(e.lengthVar);
5634 return;
5636 Expression upr = interpretRegion(e.upr, istate);
5637 if (exceptionOrCant(upr))
5639 if (e.lengthVar)
5640 ctfeGlobals.stack.pop(e.lengthVar);
5641 return;
5643 if (e.lengthVar)
5644 ctfeGlobals.stack.pop(e.lengthVar); // $ is defined only inside [L..U]
5646 uinteger_t ilwr = lwr.toInteger();
5647 uinteger_t iupr = upr.toInteger();
5648 if (e1.op == EXP.null_)
5650 if (ilwr == 0 && iupr == 0)
5652 result = e1;
5653 return;
5655 error(e1.loc, "slice `[%llu..%llu]` is out of bounds", ilwr, iupr);
5656 result = CTFEExp.cantexp;
5657 return;
5659 if (auto se = e1.isSliceExp())
5661 // Simplify slice of slice:
5662 // aggregate[lo1..up1][lwr..upr] ---> aggregate[lwr'..upr']
5663 uinteger_t lo1 = se.lwr.toInteger();
5664 uinteger_t up1 = se.upr.toInteger();
5665 if (sliceBoundsCheck(0, up1 - lo1, ilwr, iupr))
5667 error(e.loc, "slice `[%llu..%llu]` exceeds array bounds `[0..%llu]`", ilwr, iupr, up1 - lo1);
5668 result = CTFEExp.cantexp;
5669 return;
5671 ilwr += lo1;
5672 iupr += lo1;
5673 emplaceExp!(SliceExp)(pue, e.loc, se.e1,
5674 ctfeEmplaceExp!IntegerExp(e.loc, ilwr, lwr.type),
5675 ctfeEmplaceExp!IntegerExp(e.loc, iupr, upr.type));
5676 result = pue.exp();
5677 result.type = e.type;
5678 return;
5680 if (e1.op == EXP.arrayLiteral || e1.op == EXP.string_)
5682 if (sliceBoundsCheck(0, dollar, ilwr, iupr))
5684 error(e.loc, "slice `[%lld..%lld]` exceeds array bounds `[0..%lld]`", ilwr, iupr, dollar);
5685 result = CTFEExp.cantexp;
5686 return;
5689 emplaceExp!(SliceExp)(pue, e.loc, e1, lwr, upr);
5690 result = pue.exp();
5691 result.type = e.type;
5694 override void visit(InExp e)
5696 debug (LOG)
5698 printf("%s InExp::interpret() %s\n", e.loc.toChars(), e.toChars());
5700 Expression e1 = interpretRegion(e.e1, istate);
5701 if (exceptionOrCant(e1))
5702 return;
5703 Expression e2 = interpretRegion(e.e2, istate);
5704 if (exceptionOrCant(e2))
5705 return;
5706 if (e2.op == EXP.null_)
5708 emplaceExp!(NullExp)(pue, e.loc, e.type);
5709 result = pue.exp();
5710 return;
5712 if (e2.op != EXP.assocArrayLiteral)
5714 error(e.loc, "`%s` cannot be interpreted at compile time", e.toChars());
5715 result = CTFEExp.cantexp;
5716 return;
5719 e1 = resolveSlice(e1);
5720 result = findKeyInAA(e.loc, e2.isAssocArrayLiteralExp(), e1);
5721 if (exceptionOrCant(result))
5722 return;
5723 if (!result)
5725 emplaceExp!(NullExp)(pue, e.loc, e.type);
5726 result = pue.exp();
5728 else
5730 // Create a CTFE pointer &aa[index]
5731 result = ctfeEmplaceExp!IndexExp(e.loc, e2, e1);
5732 result.type = e.type.nextOf();
5733 emplaceExp!(AddrExp)(pue, e.loc, result, e.type);
5734 result = pue.exp();
5738 override void visit(CatExp e)
5740 debug (LOG)
5742 printf("%s CatExp::interpret() %s\n", e.loc.toChars(), e.toChars());
5745 UnionExp ue1 = void;
5746 Expression e1 = interpret(&ue1, e.e1, istate);
5747 if (exceptionOrCant(e1))
5748 return;
5750 UnionExp ue2 = void;
5751 Expression e2 = interpret(&ue2, e.e2, istate);
5752 if (exceptionOrCant(e2))
5753 return;
5755 UnionExp e1tmp = void;
5756 e1 = resolveSlice(e1, &e1tmp);
5758 UnionExp e2tmp = void;
5759 e2 = resolveSlice(e2, &e2tmp);
5761 /* e1 and e2 can't go on the stack because of x~[y] and [x]~y will
5762 * result in [x,y] and then x or y is on the stack.
5763 * But if they are both strings, we can, because it isn't the x~[y] case.
5765 if (!(e1.op == EXP.string_ && e2.op == EXP.string_))
5767 if (e1 == ue1.exp())
5768 e1 = ue1.copy();
5769 if (e2 == ue2.exp())
5770 e2 = ue2.copy();
5773 Expression prepareCatOperand(Expression exp)
5775 /* Convert `elem ~ array` to `[elem] ~ array` if `elem` is itself an
5776 * array. This is needed because interpreting the `CatExp` calls
5777 * `Cat()`, which cannot handle concatenations between different
5778 * types, except for strings and chars.
5780 auto tb = e.type.toBasetype();
5781 auto tbNext = tb.nextOf();
5782 auto expTb = exp.type.toBasetype();
5784 if (exp.type.implicitConvTo(tbNext) >= MATCH.convert &&
5785 (tb.ty == Tarray || tb.ty == Tsarray) &&
5786 (expTb.ty == Tarray || expTb.ty == Tsarray))
5787 return new ArrayLiteralExp(exp.loc, e.type, exp);
5788 return exp;
5791 *pue = ctfeCat(e.loc, e.type, prepareCatOperand(e1), prepareCatOperand(e2));
5792 result = pue.exp();
5794 if (CTFEExp.isCantExp(result))
5796 error(e.loc, "`%s` cannot be interpreted at compile time", e.toChars());
5797 return;
5799 // We know we still own it, because we interpreted both e1 and e2
5800 if (auto ale = result.isArrayLiteralExp())
5802 ale.ownedByCtfe = OwnedBy.ctfe;
5804 // https://issues.dlang.org/show_bug.cgi?id=14686
5805 foreach (elem; *ale.elements)
5807 Expression ex = evaluatePostblit(istate, elem);
5808 if (exceptionOrCant(ex))
5809 return;
5812 else if (auto se = result.isStringExp())
5813 se.ownedByCtfe = OwnedBy.ctfe;
5816 override void visit(DeleteExp e)
5818 debug (LOG)
5820 printf("%s DeleteExp::interpret() %s\n", e.loc.toChars(), e.toChars());
5822 result = interpretRegion(e.e1, istate);
5823 if (exceptionOrCant(result))
5824 return;
5826 if (result.op == EXP.null_)
5828 result = CTFEExp.voidexp;
5829 return;
5832 auto tb = e.e1.type.toBasetype();
5833 switch (tb.ty)
5835 case Tclass:
5836 if (result.op != EXP.classReference)
5838 error(e.loc, "`delete` on invalid class reference `%s`", result.toChars());
5839 result = CTFEExp.cantexp;
5840 return;
5843 auto cre = result.isClassReferenceExp();
5844 auto cd = cre.originalClass();
5846 // Find dtor(s) in inheritance chain
5849 if (cd.dtor)
5851 result = interpretFunction(pue, cd.dtor, istate, null, cre);
5852 if (exceptionOrCant(result))
5853 return;
5855 // Dtors of Non-extern(D) classes use implicit chaining (like structs)
5856 import dmd.aggregate : ClassKind;
5857 if (cd.classKind != ClassKind.d)
5858 break;
5861 // Emulate manual chaining as done in rt_finalize2
5862 cd = cd.baseClass;
5864 } while (cd); // Stop after Object
5866 break;
5868 default:
5869 assert(0);
5871 result = CTFEExp.voidexp;
5874 override void visit(CastExp e)
5876 debug (LOG)
5878 printf("%s CastExp::interpret() %s\n", e.loc.toChars(), e.toChars());
5880 Expression e1 = interpretRegion(e.e1, istate, goal);
5881 if (exceptionOrCant(e1))
5882 return;
5883 // If the expression has been cast to void, do nothing.
5884 if (e.to.ty == Tvoid)
5886 result = CTFEExp.voidexp;
5887 return;
5889 if (e.to.ty == Tpointer && e1.op != EXP.null_)
5891 Type pointee = (cast(TypePointer)e.type).next;
5892 // Implement special cases of normally-unsafe casts
5893 if (e1.op == EXP.int64)
5895 // Happens with Windows HANDLEs, for example.
5896 result = paintTypeOntoLiteral(pue, e.to, e1);
5897 return;
5900 bool castToSarrayPointer = false;
5901 bool castBackFromVoid = false;
5902 if (e1.type.ty == Tarray || e1.type.ty == Tsarray || e1.type.ty == Tpointer)
5904 // Check for unsupported type painting operations
5905 // For slices, we need the type being sliced,
5906 // since it may have already been type painted
5907 Type elemtype = e1.type.nextOf();
5908 if (auto se = e1.isSliceExp())
5909 elemtype = se.e1.type.nextOf();
5911 // Allow casts from X* to void *, and X** to void** for any X.
5912 // But don't allow cast from X* to void**.
5913 // So, we strip all matching * from source and target to find X.
5914 // Allow casts to X* from void* only if the 'void' was originally an X;
5915 // we check this later on.
5916 Type ultimatePointee = pointee;
5917 Type ultimateSrc = elemtype;
5918 while (ultimatePointee.ty == Tpointer && ultimateSrc.ty == Tpointer)
5920 ultimatePointee = ultimatePointee.nextOf();
5921 ultimateSrc = ultimateSrc.nextOf();
5923 if (ultimatePointee.ty == Tsarray && ultimatePointee.nextOf().equivalent(ultimateSrc))
5925 castToSarrayPointer = true;
5927 else if (ultimatePointee.ty != Tvoid && ultimateSrc.ty != Tvoid && !isSafePointerCast(elemtype, pointee))
5929 error(e.loc, "reinterpreting cast from `%s*` to `%s*` is not supported in CTFE", elemtype.toChars(), pointee.toChars());
5930 result = CTFEExp.cantexp;
5931 return;
5933 if (ultimateSrc.ty == Tvoid)
5934 castBackFromVoid = true;
5937 if (auto se = e1.isSliceExp())
5939 if (se.e1.op == EXP.null_)
5941 result = paintTypeOntoLiteral(pue, e.type, se.e1);
5942 return;
5944 // Create a CTFE pointer &aggregate[1..2]
5945 auto ei = ctfeEmplaceExp!IndexExp(e.loc, se.e1, se.lwr);
5946 ei.type = e.type.nextOf();
5947 emplaceExp!(AddrExp)(pue, e.loc, ei, e.type);
5948 result = pue.exp();
5949 return;
5951 if (e1.op == EXP.arrayLiteral || e1.op == EXP.string_)
5953 // Create a CTFE pointer &[1,2,3][0] or &"abc"[0]
5954 auto ei = ctfeEmplaceExp!IndexExp(e.loc, e1, ctfeEmplaceExp!IntegerExp(e.loc, 0, Type.tsize_t));
5955 ei.type = e.type.nextOf();
5956 emplaceExp!(AddrExp)(pue, e.loc, ei, e.type);
5957 result = pue.exp();
5958 return;
5960 if (e1.op == EXP.index && !e1.isIndexExp().e1.type.equals(e1.type))
5962 // type painting operation
5963 IndexExp ie = e1.isIndexExp();
5964 if (castBackFromVoid)
5966 // get the original type. For strings, it's just the type...
5967 Type origType = ie.e1.type.nextOf();
5968 // ..but for arrays of type void*, it's the type of the element
5969 if (ie.e1.op == EXP.arrayLiteral && ie.e2.op == EXP.int64)
5971 ArrayLiteralExp ale = ie.e1.isArrayLiteralExp();
5972 const indx = cast(size_t)ie.e2.toInteger();
5973 if (indx < ale.elements.length)
5975 if (Expression xx = (*ale.elements)[indx])
5977 if (auto iex = xx.isIndexExp())
5978 origType = iex.e1.type.nextOf();
5979 else if (auto ae = xx.isAddrExp())
5980 origType = ae.e1.type;
5981 else if (auto ve = xx.isVarExp())
5982 origType = ve.var.type;
5986 if (!isSafePointerCast(origType, pointee))
5988 error(e.loc, "using `void*` to reinterpret cast from `%s*` to `%s*` is not supported in CTFE", origType.toChars(), pointee.toChars());
5989 result = CTFEExp.cantexp;
5990 return;
5993 emplaceExp!(IndexExp)(pue, e1.loc, ie.e1, ie.e2);
5994 result = pue.exp();
5995 result.type = e.type;
5996 return;
5999 if (auto ae = e1.isAddrExp())
6001 Type origType = ae.e1.type;
6002 if (isSafePointerCast(origType, pointee))
6004 emplaceExp!(AddrExp)(pue, e.loc, ae.e1, e.type);
6005 result = pue.exp();
6006 return;
6009 if (castToSarrayPointer && pointee.toBasetype().ty == Tsarray && ae.e1.op == EXP.index)
6011 // &val[idx]
6012 dinteger_t dim = (cast(TypeSArray)pointee.toBasetype()).dim.toInteger();
6013 IndexExp ie = ae.e1.isIndexExp();
6014 Expression lwr = ie.e2;
6015 Expression upr = ctfeEmplaceExp!IntegerExp(ie.e2.loc, ie.e2.toInteger() + dim, Type.tsize_t);
6017 // Create a CTFE pointer &val[idx..idx+dim]
6018 auto er = ctfeEmplaceExp!SliceExp(e.loc, ie.e1, lwr, upr);
6019 er.type = pointee;
6020 emplaceExp!(AddrExp)(pue, e.loc, er, e.type);
6021 result = pue.exp();
6022 return;
6026 if (e1.op == EXP.variable || e1.op == EXP.symbolOffset)
6028 // type painting operation
6029 Type origType = (cast(SymbolExp)e1).var.type;
6030 if (castBackFromVoid && !isSafePointerCast(origType, pointee))
6032 error(e.loc, "using `void*` to reinterpret cast from `%s*` to `%s*` is not supported in CTFE", origType.toChars(), pointee.toChars());
6033 result = CTFEExp.cantexp;
6034 return;
6036 if (auto ve = e1.isVarExp())
6037 emplaceExp!(VarExp)(pue, e.loc, ve.var);
6038 else
6039 emplaceExp!(SymOffExp)(pue, e.loc, e1.isSymOffExp().var, e1.isSymOffExp().offset);
6040 result = pue.exp();
6041 result.type = e.to;
6042 return;
6045 // Check if we have a null pointer (eg, inside a struct)
6046 e1 = interpretRegion(e1, istate);
6047 if (e1.op != EXP.null_)
6049 error(e.loc, "pointer cast from `%s` to `%s` is not supported at compile time", e1.type.toChars(), e.to.toChars());
6050 result = CTFEExp.cantexp;
6051 return;
6054 if (e.to.ty == Tsarray && e.e1.type.ty == Tvector)
6056 // Special handling for: cast(float[4])__vector([w, x, y, z])
6057 e1 = interpretRegion(e.e1, istate);
6058 if (exceptionOrCant(e1))
6059 return;
6060 assert(e1.op == EXP.vector);
6061 e1 = interpretVectorToArray(pue, e1.isVectorExp());
6063 if (e.to.ty == Tarray && e1.op == EXP.slice)
6065 // Note that the slice may be void[], so when checking for dangerous
6066 // casts, we need to use the original type, which is se.e1.
6067 SliceExp se = e1.isSliceExp();
6068 if (!isSafePointerCast(se.e1.type.nextOf(), e.to.nextOf()))
6070 error(e.loc, "array cast from `%s` to `%s` is not supported at compile time", se.e1.type.toChars(), e.to.toChars());
6071 result = CTFEExp.cantexp;
6072 return;
6074 emplaceExp!(SliceExp)(pue, e1.loc, se.e1, se.lwr, se.upr);
6075 result = pue.exp();
6076 result.type = e.to;
6077 return;
6079 // Disallow array type painting, except for conversions between built-in
6080 // types of identical size.
6081 if ((e.to.ty == Tsarray || e.to.ty == Tarray) && (e1.type.ty == Tsarray || e1.type.ty == Tarray) && !isSafePointerCast(e1.type.nextOf(), e.to.nextOf()))
6083 error(e.loc, "array cast from `%s` to `%s` is not supported at compile time", e1.type.toChars(), e.to.toChars());
6084 result = CTFEExp.cantexp;
6085 return;
6087 if (e.to.ty == Tsarray)
6088 e1 = resolveSlice(e1);
6090 auto tobt = e.to.toBasetype();
6091 if (tobt.ty == Tbool && e1.type.ty == Tpointer)
6093 emplaceExp!(IntegerExp)(pue, e.loc, e1.op != EXP.null_, e.to);
6094 result = pue.exp();
6095 return;
6097 else if (tobt.isTypeBasic() && e1.op == EXP.null_)
6099 if (tobt.isintegral())
6100 emplaceExp!(IntegerExp)(pue, e.loc, 0, e.to);
6101 else if (tobt.isreal())
6102 emplaceExp!(RealExp)(pue, e.loc, CTFloat.zero, e.to);
6103 result = pue.exp();
6104 return;
6106 result = ctfeCast(pue, e.loc, e.type, e.to, e1, true);
6109 override void visit(AssertExp e)
6111 debug (LOG)
6113 printf("%s AssertExp::interpret() %s\n", e.loc.toChars(), e.toChars());
6115 Expression e1 = interpret(pue, e.e1, istate);
6116 if (exceptionOrCant(e1))
6117 return;
6118 if (isTrueBool(e1))
6121 else if (e1.toBool().hasValue(false))
6123 if (e.msg)
6125 UnionExp ue = void;
6126 result = interpret(&ue, e.msg, istate);
6127 if (exceptionOrCant(result))
6128 return;
6129 result = scrubReturnValue(e.loc, result);
6130 if (StringExp se = result.toStringExp())
6131 error(e.loc, "%s", se.toStringz().ptr);
6132 else
6133 error(e.loc, "%s", result.toChars());
6135 else
6136 error(e.loc, "`%s` failed", e.toChars());
6137 result = CTFEExp.cantexp;
6138 return;
6140 else
6142 error(e.loc, "`%s` is not a compile time boolean expression", e1.toChars());
6143 result = CTFEExp.cantexp;
6144 return;
6146 result = e1;
6147 return;
6150 override void visit(ThrowExp te)
6152 debug (LOG)
6154 printf("%s ThrowExpression::interpret()\n", te.loc.toChars());
6156 interpretThrow(result, te.e1, te.loc, istate);
6159 override void visit(PtrExp e)
6161 // Called for both lvalues and rvalues
6162 const lvalue = goal == CTFEGoal.LValue;
6163 debug (LOG)
6165 printf("%s PtrExp::interpret(%d) %s, %s\n", e.loc.toChars(), lvalue, e.type.toChars(), e.toChars());
6168 // Check for int<->float and long<->double casts.
6169 if (auto soe1 = e.e1.isSymOffExp())
6170 if (soe1.offset == 0 && soe1.var.isVarDeclaration() && isFloatIntPaint(e.type, soe1.var.type))
6172 // *(cast(int*)&v), where v is a float variable
6173 result = paintFloatInt(pue, getVarExp(e.loc, istate, soe1.var, CTFEGoal.RValue), e.type);
6174 return;
6177 if (auto ce1 = e.e1.isCastExp())
6178 if (auto ae11 = ce1.e1.isAddrExp())
6180 // *(cast(int*)&x), where x is a float expression
6181 Expression x = ae11.e1;
6182 if (isFloatIntPaint(e.type, x.type))
6184 result = paintFloatInt(pue, interpretRegion(x, istate), e.type);
6185 return;
6189 // Constant fold *(&structliteral + offset)
6190 if (auto ae = e.e1.isAddExp())
6192 if (ae.e1.op == EXP.address && ae.e2.op == EXP.int64)
6194 AddrExp ade = ae.e1.isAddrExp();
6195 Expression ex = interpretRegion(ade.e1, istate);
6196 if (exceptionOrCant(ex))
6197 return;
6198 if (auto se = ex.isStructLiteralExp())
6200 dinteger_t offset = ae.e2.toInteger();
6201 result = se.getField(e.type, cast(uint)offset);
6202 if (result)
6203 return;
6208 // It's possible we have an array bounds error. We need to make sure it
6209 // errors with this line number, not the one where the pointer was set.
6210 result = interpretRegion(e.e1, istate);
6211 if (exceptionOrCant(result))
6212 return;
6214 if (result.op == EXP.function_)
6215 return;
6216 if (auto soe = result.isSymOffExp())
6218 if (soe.offset == 0 && soe.var.isFuncDeclaration())
6219 return;
6220 error(e.loc, "cannot dereference pointer to static variable `%s` at compile time", soe.var.toChars());
6221 result = CTFEExp.cantexp;
6222 return;
6225 if (!lvalue && result.isArrayLiteralExp() &&
6226 result.type.isTypePointer())
6228 /* A pointer variable can point to an array literal like `[3]`.
6229 * Dereferencing it means accessing the first element value.
6230 * Dereference it only if result should be an rvalue
6232 auto ae = result.isArrayLiteralExp();
6233 if (ae.elements.length == 1)
6235 result = (*ae.elements)[0];
6236 return;
6239 if (result.isStringExp() || result.isArrayLiteralExp())
6240 return;
6242 if (result.op != EXP.address)
6244 if (result.op == EXP.null_)
6245 error(e.loc, "dereference of null pointer `%s`", e.e1.toChars());
6246 else
6247 error(e.loc, "dereference of invalid pointer `%s`", result.toChars());
6248 result = CTFEExp.cantexp;
6249 return;
6252 // *(&x) ==> x
6253 result = result.isAddrExp().e1;
6255 if (result.op == EXP.slice && e.type.toBasetype().ty == Tsarray)
6257 /* aggr[lwr..upr]
6258 * upr may exceed the upper boundary of aggr, but the check is deferred
6259 * until those out-of-bounds elements will be touched.
6261 return;
6263 result = interpret(pue, result, istate, goal);
6264 if (exceptionOrCant(result))
6265 return;
6267 debug (LOG)
6269 if (CTFEExp.isCantExp(result))
6270 printf("PtrExp::interpret() %s = CTFEExp::cantexp\n", e.toChars());
6274 override void visit(DotVarExp e)
6276 void notImplementedYet()
6278 error(e.loc, "`%s.%s` is not yet implemented at compile time", e.e1.toChars(), e.var.toChars());
6279 result = CTFEExp.cantexp;
6280 return;
6283 debug (LOG)
6285 printf("%s DotVarExp::interpret() %s, goal = %d\n", e.loc.toChars(), e.toChars(), goal);
6287 Expression ex = interpretRegion(e.e1, istate);
6288 if (exceptionOrCant(ex))
6289 return;
6291 if (FuncDeclaration f = e.var.isFuncDeclaration())
6293 if (ex == e.e1)
6294 result = e; // optimize: reuse this CTFE reference
6295 else
6297 emplaceExp!(DotVarExp)(pue, e.loc, ex, f, false);
6298 result = pue.exp();
6299 result.type = e.type;
6301 return;
6304 VarDeclaration v = e.var.isVarDeclaration();
6305 if (!v)
6307 error(e.loc, "CTFE internal error: `%s`", e.toChars());
6308 result = CTFEExp.cantexp;
6309 return;
6312 if (ex.op == EXP.null_)
6314 if (ex.type.toBasetype().ty == Tclass)
6315 error(e.loc, "class `%s` is `null` and cannot be dereferenced", e.e1.toChars());
6316 else
6317 error(e.loc, "CTFE internal error: null this `%s`", e.e1.toChars());
6318 result = CTFEExp.cantexp;
6319 return;
6322 StructLiteralExp se;
6323 int i;
6325 if (ex.op != EXP.structLiteral && ex.op != EXP.classReference && ex.op != EXP.typeid_)
6327 return notImplementedYet();
6330 // We can't use getField, because it makes a copy
6331 if (ex.op == EXP.classReference)
6333 se = ex.isClassReferenceExp().value;
6334 i = ex.isClassReferenceExp().findFieldIndexByName(v);
6336 else if (ex.op == EXP.typeid_)
6338 if (v.ident == Identifier.idPool("name"))
6340 if (auto t = isType(ex.isTypeidExp().obj))
6342 auto sym = t.toDsymbol(null);
6343 if (auto ident = (sym ? sym.ident : null))
6345 result = new StringExp(e.loc, ident.toString());
6346 result.expressionSemantic(null);
6347 return ;
6351 return notImplementedYet();
6353 else
6355 se = ex.isStructLiteralExp();
6356 i = findFieldIndexByName(se.sd, v);
6358 if (i == -1)
6360 error(e.loc, "couldn't find field `%s` of type `%s` in `%s`", v.toChars(), e.type.toChars(), se.toChars());
6361 result = CTFEExp.cantexp;
6362 return;
6365 // https://issues.dlang.org/show_bug.cgi?id=19897
6366 // https://issues.dlang.org/show_bug.cgi?id=20710
6367 // Zero-elements fields don't have an initializer. See: scrubArray function
6368 if ((*se.elements)[i] is null)
6369 (*se.elements)[i] = voidInitLiteral(e.type, v).copy();
6371 if (goal == CTFEGoal.LValue)
6373 // just return the (simplified) dotvar expression as a CTFE reference
6374 if (e.e1 == ex)
6375 result = e;
6376 else
6378 emplaceExp!(DotVarExp)(pue, e.loc, ex, v);
6379 result = pue.exp();
6380 result.type = e.type;
6382 return;
6385 result = (*se.elements)[i];
6386 if (!result)
6388 error(e.loc, "internal compiler error: null field `%s`", v.toChars());
6389 result = CTFEExp.cantexp;
6390 return;
6392 if (auto vie = result.isVoidInitExp())
6394 const s = vie.var.toChars();
6395 if (v.overlapped)
6397 error(e.loc, "reinterpretation through overlapped field `%s` is not allowed in CTFE", s);
6398 result = CTFEExp.cantexp;
6399 return;
6401 error(e.loc, "cannot read uninitialized variable `%s` in CTFE", s);
6402 result = CTFEExp.cantexp;
6403 return;
6406 if (v.type.ty != result.type.ty && v.type.ty == Tsarray)
6408 // Block assignment from inside struct literals
6409 auto tsa = cast(TypeSArray)v.type;
6410 auto len = cast(size_t)tsa.dim.toInteger();
6411 UnionExp ue = void;
6412 result = createBlockDuplicatedArrayLiteral(&ue, e.loc, v.type, result, len);
6413 if (result == ue.exp())
6414 result = ue.copy();
6415 (*se.elements)[i] = result;
6417 debug (LOG)
6419 if (CTFEExp.isCantExp(result))
6420 printf("DotVarExp::interpret() %s = CTFEExp::cantexp\n", e.toChars());
6424 override void visit(RemoveExp e)
6426 debug (LOG)
6428 printf("%s RemoveExp::interpret() %s\n", e.loc.toChars(), e.toChars());
6430 Expression agg = interpret(e.e1, istate);
6431 if (exceptionOrCant(agg))
6432 return;
6433 Expression index = interpret(e.e2, istate);
6434 if (exceptionOrCant(index))
6435 return;
6436 if (agg.op == EXP.null_)
6438 result = CTFEExp.voidexp;
6439 return;
6442 AssocArrayLiteralExp aae = agg.isAssocArrayLiteralExp();
6443 Expressions* keysx = aae.keys;
6444 Expressions* valuesx = aae.values;
6445 size_t removed = 0;
6446 foreach (j, evalue; *valuesx)
6448 Expression ekey = (*keysx)[j];
6449 int eq = ctfeEqual(e.loc, EXP.equal, ekey, index);
6450 if (eq)
6451 ++removed;
6452 else if (removed != 0)
6454 (*keysx)[j - removed] = ekey;
6455 (*valuesx)[j - removed] = evalue;
6458 valuesx.length = valuesx.length - removed;
6459 keysx.length = keysx.length - removed;
6460 result = IntegerExp.createBool(removed != 0);
6463 override void visit(ClassReferenceExp e)
6465 //printf("ClassReferenceExp::interpret() %s\n", e.value.toChars());
6466 result = e;
6469 override void visit(VoidInitExp e)
6471 error(e.loc, "CTFE internal error: trying to read uninitialized variable");
6472 assert(0);
6475 override void visit(ThrownExceptionExp e)
6477 assert(0); // This should never be interpreted
6481 /// Interpret `throw <exp>` found at the specified location `loc`
6482 private
6483 void interpretThrow(ref Expression result, Expression exp, const ref Loc loc, InterState* istate)
6485 incUsageCtfe(istate, loc);
6487 Expression e = interpretRegion(exp, istate);
6488 if (exceptionOrCantInterpret(e))
6490 // Make sure e is not pointing to a stack temporary
6491 result = (e.op == EXP.cantExpression) ? CTFEExp.cantexp : e;
6493 else if (e.op == EXP.classReference)
6495 result = ctfeEmplaceExp!ThrownExceptionExp(loc, e.isClassReferenceExp());
6497 else
6499 error(exp.loc, "to be thrown `%s` must be non-null", exp.toChars());
6500 result = ErrorExp.get();
6504 /*********************************************
6505 * Checks if the given expresion is a call to the runtime hook `id`.
6507 * Params:
6508 * e = the expression to check
6509 * id = the identifier of the runtime hook
6510 * Returns:
6511 * `e` cast to `CallExp` if it's the hook, `null` otherwise
6513 public CallExp isRuntimeHook(Expression e, Identifier id)
6515 if (auto ce = e.isCallExp())
6517 if (auto ve = ce.e1.isVarExp())
6519 if (auto fd = ve.var.isFuncDeclaration())
6521 // If `_d_HookTraceImpl` is found, resolve the underlying hook
6522 // and replace `e` and `fd` with it.
6523 removeHookTraceImpl(ce, fd);
6524 return fd.ident == id ? ce : null;
6529 return null;
6532 /********************************************
6533 * Interpret the expression.
6534 * Params:
6535 * pue = non-null pointer to temporary storage that can be used to store the return value
6536 * e = Expression to interpret
6537 * istate = context
6538 * goal = what the result will be used for
6539 * Returns:
6540 * resulting expression
6543 Expression interpret(UnionExp* pue, Expression e, InterState* istate, CTFEGoal goal = CTFEGoal.RValue)
6545 if (!e)
6546 return null;
6547 //printf("+interpret() e : %s, %s\n", e.type.toChars(), e.toChars());
6548 scope Interpreter v = new Interpreter(pue, istate, goal);
6549 e.accept(v);
6550 Expression ex = v.result;
6551 assert(goal == CTFEGoal.Nothing || ex !is null);
6552 //if (ex) printf("-interpret() ex: %s, %s\n", ex.type.toChars(), ex.toChars()); else printf("-interpret()\n");
6553 return ex;
6557 Expression interpret(Expression e, InterState* istate, CTFEGoal goal = CTFEGoal.RValue)
6559 UnionExp ue = void;
6560 auto result = interpret(&ue, e, istate, goal);
6561 if (result == ue.exp())
6562 result = ue.copy();
6563 return result;
6566 /*****************************
6567 * Same as interpret(), but return result allocated in Region.
6568 * Params:
6569 * e = Expression to interpret
6570 * istate = context
6571 * goal = what the result will be used for
6572 * Returns:
6573 * resulting expression
6575 Expression interpretRegion(Expression e, InterState* istate, CTFEGoal goal = CTFEGoal.RValue)
6577 UnionExp ue = void;
6578 auto result = interpret(&ue, e, istate, goal);
6579 auto uexp = ue.exp();
6580 if (result != uexp)
6581 return result;
6582 if (mem.isGCEnabled)
6583 return ue.copy();
6585 // mimicking UnionExp.copy, but with region allocation
6586 switch (uexp.op)
6588 case EXP.cantExpression: return CTFEExp.cantexp;
6589 case EXP.voidExpression: return CTFEExp.voidexp;
6590 case EXP.break_: return CTFEExp.breakexp;
6591 case EXP.continue_: return CTFEExp.continueexp;
6592 case EXP.goto_: return CTFEExp.gotoexp;
6593 default: break;
6595 auto p = ctfeGlobals.region.malloc(uexp.size);
6596 return cast(Expression)memcpy(p, cast(void*)uexp, uexp.size);
6599 private
6600 Expressions* copyArrayOnWrite(Expressions* exps, Expressions* original)
6602 if (exps is original)
6604 if (!original)
6605 exps = new Expressions();
6606 else
6607 exps = original.copy();
6608 ++ctfeGlobals.numArrayAllocs;
6610 return exps;
6614 Given an expression e which is about to be returned from the current
6615 function, generate an error if it contains pointers to local variables.
6617 Only checks expressions passed by value (pointers to local variables
6618 may already be stored in members of classes, arrays, or AAs which
6619 were passed as mutable function parameters).
6620 Returns:
6621 true if it is safe to return, false if an error was generated.
6623 private
6624 bool stopPointersEscaping(const ref Loc loc, Expression e)
6626 if (!e.type.hasPointers())
6627 return true;
6628 if (isPointer(e.type))
6630 Expression x = e;
6631 if (auto eaddr = e.isAddrExp())
6632 x = eaddr.e1;
6633 VarDeclaration v;
6634 while (x.op == EXP.variable && (v = x.isVarExp().var.isVarDeclaration()) !is null)
6636 if (v.storage_class & STC.ref_)
6638 x = getValue(v);
6639 if (auto eaddr = e.isAddrExp())
6640 eaddr.e1 = x;
6641 continue;
6643 if (ctfeGlobals.stack.isInCurrentFrame(v))
6645 error(loc, "returning a pointer to a local stack variable");
6646 return false;
6648 else
6649 break;
6651 // TODO: If it is a EXP.dotVariable or EXP.index, we should check that it is not
6652 // pointing to a local struct or static array.
6654 if (auto se = e.isStructLiteralExp())
6656 return stopPointersEscapingFromArray(loc, se.elements);
6658 if (auto ale = e.isArrayLiteralExp())
6660 return stopPointersEscapingFromArray(loc, ale.elements);
6662 if (auto aae = e.isAssocArrayLiteralExp())
6664 if (!stopPointersEscapingFromArray(loc, aae.keys))
6665 return false;
6666 return stopPointersEscapingFromArray(loc, aae.values);
6668 return true;
6671 // Check all elements of an array for escaping local variables. Return false if error
6672 private
6673 bool stopPointersEscapingFromArray(const ref Loc loc, Expressions* elems)
6675 foreach (e; *elems)
6677 if (e && !stopPointersEscaping(loc, e))
6678 return false;
6680 return true;
6683 private
6684 Statement findGotoTarget(InterState* istate, Identifier ident)
6686 Statement target = null;
6687 if (ident)
6689 LabelDsymbol label = istate.fd.searchLabel(ident);
6690 assert(label && label.statement);
6691 LabelStatement ls = label.statement;
6692 target = ls.gotoTarget ? ls.gotoTarget : ls.statement;
6694 return target;
6697 private
6698 ThrownExceptionExp chainExceptions(ThrownExceptionExp oldest, ThrownExceptionExp newest)
6700 debug (LOG)
6702 printf("Collided exceptions %s %s\n", oldest.thrown.toChars(), newest.thrown.toChars());
6704 // Little sanity check to make sure it's really a Throwable
6705 ClassReferenceExp boss = oldest.thrown;
6706 const next = 5; // index of Throwable.next
6707 assert((*boss.value.elements)[next].type.ty == Tclass); // Throwable.next
6708 ClassReferenceExp collateral = newest.thrown;
6709 if (collateral.originalClass().isErrorException() && !boss.originalClass().isErrorException())
6711 /* Find the index of the Error.bypassException field
6713 auto bypass = next + 1;
6714 if ((*collateral.value.elements)[bypass].type.ty == Tuns32)
6715 bypass += 1; // skip over _refcount field
6716 assert((*collateral.value.elements)[bypass].type.ty == Tclass);
6718 // The new exception bypass the existing chain
6719 (*collateral.value.elements)[bypass] = boss;
6720 return newest;
6722 while ((*boss.value.elements)[next].op == EXP.classReference)
6724 boss = (*boss.value.elements)[next].isClassReferenceExp();
6726 (*boss.value.elements)[next] = collateral;
6727 return oldest;
6731 * All results destined for use outside of CTFE need to have their CTFE-specific
6732 * features removed.
6733 * In particular,
6734 * 1. all slices must be resolved.
6735 * 2. all .ownedByCtfe set to OwnedBy.code
6737 private Expression scrubReturnValue(const ref Loc loc, Expression e)
6739 /* Returns: true if e is void,
6740 * or is an array literal or struct literal of void elements.
6742 static bool isVoid(const Expression e, bool checkArrayType = false) pure
6744 if (e.op == EXP.void_)
6745 return true;
6747 static bool isEntirelyVoid(const Expressions* elems)
6749 foreach (e; *elems)
6751 // It can be NULL for performance reasons,
6752 // see StructLiteralExp::interpret().
6753 if (e && !isVoid(e))
6754 return false;
6756 return true;
6759 if (auto sle = e.isStructLiteralExp())
6760 return isEntirelyVoid(sle.elements);
6762 if (checkArrayType && e.type.ty != Tsarray)
6763 return false;
6765 if (auto ale = e.isArrayLiteralExp())
6766 return isEntirelyVoid(ale.elements);
6768 return false;
6772 /* Scrub all elements of elems[].
6773 * Returns: null for success, error Expression for failure
6775 Expression scrubArray(Expressions* elems, bool structlit = false)
6777 foreach (ref e; *elems)
6779 // It can be NULL for performance reasons,
6780 // see StructLiteralExp::interpret().
6781 if (!e)
6782 continue;
6784 // A struct .init may contain void members.
6785 // Static array members are a weird special case https://issues.dlang.org/show_bug.cgi?id=10994
6786 if (structlit && isVoid(e, true))
6788 e = null;
6790 else
6792 e = scrubReturnValue(loc, e);
6793 if (CTFEExp.isCantExp(e) || e.op == EXP.error)
6794 return e;
6797 return null;
6800 Expression scrubSE(StructLiteralExp sle)
6802 sle.ownedByCtfe = OwnedBy.code;
6803 if (!(sle.stageflags & stageScrub))
6805 const old = sle.stageflags;
6806 sle.stageflags |= stageScrub; // prevent infinite recursion
6807 if (auto ex = scrubArray(sle.elements, true))
6808 return ex;
6809 sle.stageflags = old;
6811 return null;
6814 if (e.op == EXP.classReference)
6816 StructLiteralExp sle = e.isClassReferenceExp().value;
6817 if (auto ex = scrubSE(sle))
6818 return ex;
6820 else if (auto vie = e.isVoidInitExp())
6822 error(loc, "uninitialized variable `%s` cannot be returned from CTFE", vie.var.toChars());
6823 return ErrorExp.get();
6826 e = resolveSlice(e);
6828 if (auto sle = e.isStructLiteralExp())
6830 if (auto ex = scrubSE(sle))
6831 return ex;
6833 else if (auto se = e.isStringExp())
6835 se.ownedByCtfe = OwnedBy.code;
6837 else if (auto ale = e.isArrayLiteralExp())
6839 ale.ownedByCtfe = OwnedBy.code;
6840 if (auto ex = scrubArray(ale.elements))
6841 return ex;
6843 else if (auto aae = e.isAssocArrayLiteralExp())
6845 aae.ownedByCtfe = OwnedBy.code;
6846 if (auto ex = scrubArray(aae.keys))
6847 return ex;
6848 if (auto ex = scrubArray(aae.values))
6849 return ex;
6850 aae.type = toBuiltinAAType(aae.type);
6852 else if (auto ve = e.isVectorExp())
6854 ve.ownedByCtfe = OwnedBy.code;
6855 if (auto ale = ve.e1.isArrayLiteralExp())
6857 ale.ownedByCtfe = OwnedBy.code;
6858 if (auto ex = scrubArray(ale.elements))
6859 return ex;
6862 return e;
6865 /**************************************
6866 * Transitively set all .ownedByCtfe to OwnedBy.cache
6868 private Expression scrubCacheValue(Expression e)
6870 if (!e)
6871 return e;
6873 Expression scrubArrayCache(Expressions* elems)
6875 foreach (ref e; *elems)
6876 e = scrubCacheValue(e);
6877 return null;
6880 Expression scrubSE(StructLiteralExp sle)
6882 sle.ownedByCtfe = OwnedBy.cache;
6883 if (!(sle.stageflags & stageScrub))
6885 const old = sle.stageflags;
6886 sle.stageflags |= stageScrub; // prevent infinite recursion
6887 if (auto ex = scrubArrayCache(sle.elements))
6888 return ex;
6889 sle.stageflags = old;
6891 return null;
6894 if (e.op == EXP.classReference)
6896 if (auto ex = scrubSE(e.isClassReferenceExp().value))
6897 return ex;
6899 else if (auto sle = e.isStructLiteralExp())
6901 if (auto ex = scrubSE(sle))
6902 return ex;
6904 else if (auto se = e.isStringExp())
6906 se.ownedByCtfe = OwnedBy.cache;
6908 else if (auto ale = e.isArrayLiteralExp())
6910 ale.ownedByCtfe = OwnedBy.cache;
6911 if (Expression ex = scrubArrayCache(ale.elements))
6912 return ex;
6914 else if (auto aae = e.isAssocArrayLiteralExp())
6916 aae.ownedByCtfe = OwnedBy.cache;
6917 if (auto ex = scrubArrayCache(aae.keys))
6918 return ex;
6919 if (auto ex = scrubArrayCache(aae.values))
6920 return ex;
6922 else if (auto ve = e.isVectorExp())
6924 ve.ownedByCtfe = OwnedBy.cache;
6925 if (auto ale = ve.e1.isArrayLiteralExp())
6927 ale.ownedByCtfe = OwnedBy.cache;
6928 if (auto ex = scrubArrayCache(ale.elements))
6929 return ex;
6932 return e;
6935 /********************************************
6936 * Transitively replace all Expressions allocated in ctfeGlobals.region
6937 * with Mem owned copies.
6938 * Params:
6939 * e = possible ctfeGlobals.region owned expression
6940 * Returns:
6941 * Mem owned expression
6943 private Expression copyRegionExp(Expression e)
6945 if (!e)
6946 return e;
6948 static void copyArray(Expressions* elems)
6950 foreach (ref e; *elems)
6952 auto ex = e;
6953 e = null;
6954 e = copyRegionExp(ex);
6958 static void copySE(StructLiteralExp sle)
6960 if (1 || !(sle.stageflags & stageScrub))
6962 const old = sle.stageflags;
6963 sle.stageflags |= stageScrub; // prevent infinite recursion
6964 copyArray(sle.elements);
6965 sle.stageflags = old;
6969 switch (e.op)
6971 case EXP.classReference:
6973 auto cre = e.isClassReferenceExp();
6974 cre.value = copyRegionExp(cre.value).isStructLiteralExp();
6975 break;
6978 case EXP.structLiteral:
6980 auto sle = e.isStructLiteralExp();
6982 /* The following is to take care of updating sle.origin correctly,
6983 * which may have multiple objects pointing to it.
6985 if (sle.isOriginal && !ctfeGlobals.region.contains(cast(void*)sle.origin))
6987 /* This means sle has already been moved out of the region,
6988 * and sle.origin is the new location.
6990 return sle.origin;
6992 copySE(sle);
6993 sle.isOriginal = sle is sle.origin;
6995 auto slec = ctfeGlobals.region.contains(cast(void*)e)
6996 ? e.copy().isStructLiteralExp() // move sle out of region to slec
6997 : sle;
6999 if (ctfeGlobals.region.contains(cast(void*)sle.origin))
7001 auto sleo = sle.origin == sle ? slec : sle.origin.copy().isStructLiteralExp();
7002 sle.origin = sleo;
7003 slec.origin = sleo;
7005 return slec;
7008 case EXP.arrayLiteral:
7010 auto ale = e.isArrayLiteralExp();
7011 ale.basis = copyRegionExp(ale.basis);
7012 copyArray(ale.elements);
7013 break;
7016 case EXP.assocArrayLiteral:
7017 copyArray(e.isAssocArrayLiteralExp().keys);
7018 copyArray(e.isAssocArrayLiteralExp().values);
7019 break;
7021 case EXP.slice:
7023 auto se = e.isSliceExp();
7024 se.e1 = copyRegionExp(se.e1);
7025 se.upr = copyRegionExp(se.upr);
7026 se.lwr = copyRegionExp(se.lwr);
7027 break;
7030 case EXP.tuple:
7032 auto te = e.isTupleExp();
7033 te.e0 = copyRegionExp(te.e0);
7034 copyArray(te.exps);
7035 break;
7038 case EXP.address:
7039 case EXP.delegate_:
7040 case EXP.vector:
7041 case EXP.dotVariable:
7043 UnaExp ue = e.isUnaExp();
7044 ue.e1 = copyRegionExp(ue.e1);
7045 break;
7048 case EXP.index:
7050 BinExp be = e.isBinExp();
7051 be.e1 = copyRegionExp(be.e1);
7052 be.e2 = copyRegionExp(be.e2);
7053 break;
7056 case EXP.this_:
7057 case EXP.super_:
7058 case EXP.variable:
7059 case EXP.type:
7060 case EXP.function_:
7061 case EXP.typeid_:
7062 case EXP.string_:
7063 case EXP.int64:
7064 case EXP.error:
7065 case EXP.float64:
7066 case EXP.complex80:
7067 case EXP.null_:
7068 case EXP.void_:
7069 case EXP.symbolOffset:
7070 break;
7072 case EXP.cantExpression:
7073 case EXP.voidExpression:
7074 case EXP.showCtfeContext:
7075 return e;
7077 default:
7078 printf("e: %s, %s\n", EXPtoString(e.op).ptr, e.toChars());
7079 assert(0);
7082 if (ctfeGlobals.region.contains(cast(void*)e))
7084 return e.copy();
7086 return e;
7089 /******************************* Special Functions ***************************/
7091 private Expression interpret_length(UnionExp* pue, InterState* istate, Expression earg)
7093 //printf("interpret_length()\n");
7094 earg = interpret(pue, earg, istate);
7095 if (exceptionOrCantInterpret(earg))
7096 return earg;
7097 dinteger_t len = 0;
7098 if (auto aae = earg.isAssocArrayLiteralExp())
7099 len = aae.keys.length;
7100 else
7101 assert(earg.op == EXP.null_);
7102 emplaceExp!(IntegerExp)(pue, earg.loc, len, Type.tsize_t);
7103 return pue.exp();
7106 private Expression interpret_keys(UnionExp* pue, InterState* istate, Expression earg, Type returnType)
7108 debug (LOG)
7110 printf("interpret_keys()\n");
7112 earg = interpret(pue, earg, istate);
7113 if (exceptionOrCantInterpret(earg))
7114 return earg;
7115 if (earg.op == EXP.null_)
7117 emplaceExp!(NullExp)(pue, earg.loc, earg.type);
7118 return pue.exp();
7120 if (earg.op != EXP.assocArrayLiteral && earg.type.toBasetype().ty != Taarray)
7121 return null;
7122 AssocArrayLiteralExp aae = earg.isAssocArrayLiteralExp();
7123 auto ae = ctfeEmplaceExp!ArrayLiteralExp(aae.loc, returnType, aae.keys);
7124 ae.ownedByCtfe = aae.ownedByCtfe;
7125 *pue = copyLiteral(ae);
7126 return pue.exp();
7129 private Expression interpret_values(UnionExp* pue, InterState* istate, Expression earg, Type returnType)
7131 debug (LOG)
7133 printf("interpret_values()\n");
7135 earg = interpret(pue, earg, istate);
7136 if (exceptionOrCantInterpret(earg))
7137 return earg;
7138 if (earg.op == EXP.null_)
7140 emplaceExp!(NullExp)(pue, earg.loc, earg.type);
7141 return pue.exp();
7143 if (earg.op != EXP.assocArrayLiteral && earg.type.toBasetype().ty != Taarray)
7144 return null;
7145 auto aae = earg.isAssocArrayLiteralExp();
7146 auto ae = ctfeEmplaceExp!ArrayLiteralExp(aae.loc, returnType, aae.values);
7147 ae.ownedByCtfe = aae.ownedByCtfe;
7148 //printf("result is %s\n", e.toChars());
7149 *pue = copyLiteral(ae);
7150 return pue.exp();
7153 private Expression interpret_dup(UnionExp* pue, InterState* istate, Expression earg)
7155 debug (LOG)
7157 printf("interpret_dup()\n");
7159 earg = interpret(pue, earg, istate);
7160 if (exceptionOrCantInterpret(earg))
7161 return earg;
7162 if (earg.op == EXP.null_)
7164 emplaceExp!(NullExp)(pue, earg.loc, earg.type);
7165 return pue.exp();
7167 if (earg.op != EXP.assocArrayLiteral && earg.type.toBasetype().ty != Taarray)
7168 return null;
7169 auto aae = copyLiteral(earg).copy().isAssocArrayLiteralExp();
7170 for (size_t i = 0; i < aae.keys.length; i++)
7172 if (Expression e = evaluatePostblit(istate, (*aae.keys)[i]))
7173 return e;
7174 if (Expression e = evaluatePostblit(istate, (*aae.values)[i]))
7175 return e;
7177 aae.type = earg.type.mutableOf(); // repaint type from const(int[int]) to const(int)[int]
7178 //printf("result is %s\n", aae.toChars());
7179 return aae;
7182 // signature is int delegate(ref Value) OR int delegate(ref Key, ref Value)
7183 private Expression interpret_aaApply(UnionExp* pue, InterState* istate, Expression aa, Expression deleg)
7185 aa = interpret(aa, istate);
7186 if (exceptionOrCantInterpret(aa))
7187 return aa;
7188 if (aa.op != EXP.assocArrayLiteral)
7190 emplaceExp!(IntegerExp)(pue, deleg.loc, 0, Type.tsize_t);
7191 return pue.exp();
7194 FuncDeclaration fd = null;
7195 Expression pthis = null;
7196 if (auto de = deleg.isDelegateExp())
7198 fd = de.func;
7199 pthis = de.e1;
7201 else if (auto fe = deleg.isFuncExp())
7202 fd = fe.fd;
7204 assert(fd && fd.fbody);
7205 assert(fd.parameters);
7206 size_t numParams = fd.parameters.length;
7207 assert(numParams == 1 || numParams == 2);
7209 Parameter fparam = fd.type.isTypeFunction().parameterList[numParams - 1];
7210 const wantRefValue = fparam.isReference();
7212 Expressions args = Expressions(numParams);
7214 AssocArrayLiteralExp ae = aa.isAssocArrayLiteralExp();
7215 if (!ae.keys || ae.keys.length == 0)
7216 return ctfeEmplaceExp!IntegerExp(deleg.loc, 0, Type.tsize_t);
7217 Expression eresult;
7219 for (size_t i = 0; i < ae.keys.length; ++i)
7221 Expression ekey = (*ae.keys)[i];
7222 Expression evalue = (*ae.values)[i];
7223 if (wantRefValue)
7225 Type t = evalue.type;
7226 evalue = ctfeEmplaceExp!IndexExp(deleg.loc, ae, ekey);
7227 evalue.type = t;
7229 args[numParams - 1] = evalue;
7230 if (numParams == 2)
7231 args[0] = ekey;
7233 UnionExp ue = void;
7234 eresult = interpretFunction(&ue, fd, istate, &args, pthis);
7235 if (eresult == ue.exp())
7236 eresult = ue.copy();
7237 if (exceptionOrCantInterpret(eresult))
7238 return eresult;
7240 if (eresult.isIntegerExp().getInteger() != 0)
7241 return eresult;
7243 return eresult;
7246 /* Decoding UTF strings for foreach loops. Duplicates the functionality of
7247 * the twelve _aApplyXXn functions in aApply.d in the runtime.
7249 private Expression foreachApplyUtf(UnionExp* pue, InterState* istate, Expression str, Expression deleg, bool rvs)
7251 debug (LOG)
7253 printf("foreachApplyUtf(%s, %s)\n", str.toChars(), deleg.toChars());
7255 FuncDeclaration fd = null;
7256 Expression pthis = null;
7257 if (auto de = deleg.isDelegateExp())
7259 fd = de.func;
7260 pthis = de.e1;
7262 else if (auto fe = deleg.isFuncExp())
7263 fd = fe.fd;
7265 assert(fd && fd.fbody);
7266 assert(fd.parameters);
7267 size_t numParams = fd.parameters.length;
7268 assert(numParams == 1 || numParams == 2);
7269 Type charType = (*fd.parameters)[numParams - 1].type;
7270 Type indexType = numParams == 2 ? (*fd.parameters)[0].type : Type.tsize_t;
7271 size_t len = cast(size_t)resolveArrayLength(str);
7272 if (len == 0)
7274 emplaceExp!(IntegerExp)(pue, deleg.loc, 0, indexType);
7275 return pue.exp();
7278 UnionExp strTmp = void;
7279 str = resolveSlice(str, &strTmp);
7281 auto se = str.isStringExp();
7282 auto ale = str.isArrayLiteralExp();
7283 if (!se && !ale)
7285 error(str.loc, "CTFE internal error: cannot foreach `%s`", str.toChars());
7286 return CTFEExp.cantexp;
7288 Expressions args = Expressions(numParams);
7290 Expression eresult = null; // ded-store to prevent spurious warning
7292 // Buffers for encoding; also used for decoding array literals
7293 char[4] utf8buf = void;
7294 wchar[2] utf16buf = void;
7296 size_t start = rvs ? len : 0;
7297 size_t end = rvs ? 0 : len;
7298 for (size_t indx = start; indx != end;)
7300 // Step 1: Decode the next dchar from the string.
7302 string errmsg = null; // Used for reporting decoding errors
7303 dchar rawvalue; // Holds the decoded dchar
7304 size_t currentIndex = indx; // The index of the decoded character
7306 if (ale)
7308 // If it is an array literal, copy the code points into the buffer
7309 size_t buflen = 1; // #code points in the buffer
7310 size_t n = 1; // #code points in this char
7311 size_t sz = cast(size_t)ale.type.nextOf().size();
7313 switch (sz)
7315 case 1:
7316 if (rvs)
7318 // find the start of the string
7319 --indx;
7320 buflen = 1;
7321 while (indx > 0 && buflen < 4)
7323 Expression r = (*ale.elements)[indx];
7324 char x = cast(char)r.isIntegerExp().getInteger();
7325 if ((x & 0xC0) != 0x80)
7326 break;
7327 --indx;
7328 ++buflen;
7331 else
7332 buflen = (indx + 4 > len) ? len - indx : 4;
7333 for (size_t i = 0; i < buflen; ++i)
7335 Expression r = (*ale.elements)[indx + i];
7336 utf8buf[i] = cast(char)r.isIntegerExp().getInteger();
7338 n = 0;
7339 errmsg = utf_decodeChar(utf8buf[0 .. buflen], n, rawvalue);
7340 break;
7342 case 2:
7343 if (rvs)
7345 // find the start of the string
7346 --indx;
7347 buflen = 1;
7348 Expression r = (*ale.elements)[indx];
7349 ushort x = cast(ushort)r.isIntegerExp().getInteger();
7350 if (indx > 0 && x >= 0xDC00 && x <= 0xDFFF)
7352 --indx;
7353 ++buflen;
7356 else
7357 buflen = (indx + 2 > len) ? len - indx : 2;
7358 for (size_t i = 0; i < buflen; ++i)
7360 Expression r = (*ale.elements)[indx + i];
7361 utf16buf[i] = cast(ushort)r.isIntegerExp().getInteger();
7363 n = 0;
7364 errmsg = utf_decodeWchar(utf16buf[0 .. buflen], n, rawvalue);
7365 break;
7367 case 4:
7369 if (rvs)
7370 --indx;
7371 Expression r = (*ale.elements)[indx];
7372 rawvalue = cast(dchar)r.isIntegerExp().getInteger();
7373 n = 1;
7375 break;
7377 default:
7378 assert(0);
7380 if (!rvs)
7381 indx += n;
7383 else
7385 // String literals
7386 size_t saveindx; // used for reverse iteration
7388 switch (se.sz)
7390 case 1:
7392 if (rvs)
7394 // find the start of the string
7395 --indx;
7396 while (indx > 0 && ((se.getCodeUnit(indx) & 0xC0) == 0x80))
7397 --indx;
7398 saveindx = indx;
7400 auto slice = se.peekString();
7401 errmsg = utf_decodeChar(slice, indx, rawvalue);
7402 if (rvs)
7403 indx = saveindx;
7404 break;
7407 case 2:
7408 if (rvs)
7410 // find the start
7411 --indx;
7412 auto wc = se.getCodeUnit(indx);
7413 if (wc >= 0xDC00 && wc <= 0xDFFF)
7414 --indx;
7415 saveindx = indx;
7417 const slice = se.peekWstring();
7418 errmsg = utf_decodeWchar(slice, indx, rawvalue);
7419 if (rvs)
7420 indx = saveindx;
7421 break;
7423 case 4:
7424 if (rvs)
7425 --indx;
7426 rawvalue = se.getCodeUnit(indx);
7427 if (!rvs)
7428 ++indx;
7429 break;
7431 default:
7432 assert(0);
7435 if (errmsg)
7437 error(deleg.loc, "`%.*s`", cast(int)errmsg.length, errmsg.ptr);
7438 return CTFEExp.cantexp;
7441 // Step 2: encode the dchar in the target encoding
7443 int charlen = 1; // How many codepoints are involved?
7444 switch (charType.size())
7446 case 1:
7447 charlen = utf_codeLengthChar(rawvalue);
7448 utf_encodeChar(&utf8buf[0], rawvalue);
7449 break;
7450 case 2:
7451 charlen = utf_codeLengthWchar(rawvalue);
7452 utf_encodeWchar(&utf16buf[0], rawvalue);
7453 break;
7454 case 4:
7455 break;
7456 default:
7457 assert(0);
7459 if (rvs)
7460 currentIndex = indx;
7462 // Step 3: call the delegate once for each code point
7464 // The index only needs to be set once
7465 if (numParams == 2)
7466 args[0] = ctfeEmplaceExp!IntegerExp(deleg.loc, currentIndex, indexType);
7468 Expression val = null;
7470 foreach (k; 0 .. charlen)
7472 dchar codepoint;
7473 switch (charType.size())
7475 case 1:
7476 codepoint = utf8buf[k];
7477 break;
7478 case 2:
7479 codepoint = utf16buf[k];
7480 break;
7481 case 4:
7482 codepoint = rawvalue;
7483 break;
7484 default:
7485 assert(0);
7487 val = ctfeEmplaceExp!IntegerExp(str.loc, codepoint, charType);
7489 args[numParams - 1] = val;
7491 UnionExp ue = void;
7492 eresult = interpretFunction(&ue, fd, istate, &args, pthis);
7493 if (eresult == ue.exp())
7494 eresult = ue.copy();
7495 if (exceptionOrCantInterpret(eresult))
7496 return eresult;
7497 if (eresult.isIntegerExp().getInteger() != 0)
7498 return eresult;
7501 return eresult;
7504 /* If this is a built-in function, return the interpreted result,
7505 * Otherwise, return NULL.
7507 private Expression evaluateIfBuiltin(UnionExp* pue, InterState* istate, const ref Loc loc, FuncDeclaration fd, Expressions* arguments, Expression pthis)
7509 Expression e = null;
7510 size_t nargs = arguments ? arguments.length : 0;
7511 if (!pthis)
7513 if (isBuiltin(fd) != BUILTIN.unimp)
7515 Expressions args = Expressions(nargs);
7516 foreach (i, ref arg; args)
7518 Expression earg = (*arguments)[i];
7519 earg = interpret(earg, istate);
7520 if (exceptionOrCantInterpret(earg))
7521 return earg;
7522 arg = earg;
7524 e = eval_builtin(loc, fd, &args);
7525 if (!e)
7527 error(loc, "cannot evaluate unimplemented builtin `%s` at compile time", fd.toChars());
7528 e = CTFEExp.cantexp;
7532 if (!pthis)
7534 if (nargs == 1 || nargs == 3)
7536 Expression firstarg = (*arguments)[0];
7537 if (auto firstAAtype = firstarg.type.toBasetype().isTypeAArray())
7539 const id = fd.ident;
7540 if (nargs == 1)
7542 if (id == Id.aaLen)
7543 return interpret_length(pue, istate, firstarg);
7545 if (fd.toParent2().ident == Id.object)
7547 if (id == Id.keys)
7548 return interpret_keys(pue, istate, firstarg, firstAAtype.index.arrayOf());
7549 if (id == Id.values)
7550 return interpret_values(pue, istate, firstarg, firstAAtype.nextOf().arrayOf());
7551 if (id == Id.rehash)
7552 return interpret(pue, firstarg, istate);
7553 if (id == Id.dup)
7554 return interpret_dup(pue, istate, firstarg);
7557 else // (nargs == 3)
7559 if (id == Id._aaApply)
7560 return interpret_aaApply(pue, istate, firstarg, (*arguments)[2]);
7561 if (id == Id._aaApply2)
7562 return interpret_aaApply(pue, istate, firstarg, (*arguments)[2]);
7567 if (pthis && !fd.fbody && fd.isCtorDeclaration() && fd.parent && fd.parent.parent && fd.parent.parent.ident == Id.object)
7569 if (pthis.op == EXP.classReference && fd.parent.ident == Id.Throwable)
7571 // At present, the constructors just copy their arguments into the struct.
7572 // But we might need some magic if stack tracing gets added to druntime.
7573 StructLiteralExp se = pthis.isClassReferenceExp().value;
7574 assert(arguments.length <= se.elements.length);
7575 foreach (i, arg; *arguments)
7577 auto elem = interpret(arg, istate);
7578 if (exceptionOrCantInterpret(elem))
7579 return elem;
7580 (*se.elements)[i] = elem;
7582 return CTFEExp.voidexp;
7585 if (nargs == 1 && !pthis && (fd.ident == Id.criticalenter || fd.ident == Id.criticalexit))
7587 // Support synchronized{} as a no-op
7588 return CTFEExp.voidexp;
7590 if (!pthis)
7592 const idlen = fd.ident.toString().length;
7593 const id = fd.ident.toChars();
7594 if (nargs == 2 && (idlen == 10 || idlen == 11) && !strncmp(id, "_aApply", 7))
7596 // Functions from aApply.d and aApplyR.d in the runtime
7597 bool rvs = (idlen == 11); // true if foreach_reverse
7598 char c = id[idlen - 3]; // char width: 'c', 'w', or 'd'
7599 char s = id[idlen - 2]; // string width: 'c', 'w', or 'd'
7600 char n = id[idlen - 1]; // numParams: 1 or 2.
7601 // There are 12 combinations
7602 if ((n == '1' || n == '2') &&
7603 (c == 'c' || c == 'w' || c == 'd') &&
7604 (s == 'c' || s == 'w' || s == 'd') &&
7605 c != s)
7607 Expression str = (*arguments)[0];
7608 str = interpret(str, istate);
7609 if (exceptionOrCantInterpret(str))
7610 return str;
7611 return foreachApplyUtf(pue, istate, str, (*arguments)[1], rvs);
7615 return e;
7618 private Expression evaluatePostblit(InterState* istate, Expression e)
7620 auto ts = e.type.baseElemOf().isTypeStruct();
7621 if (!ts)
7622 return null;
7623 StructDeclaration sd = ts.sym;
7624 if (!sd.postblit)
7625 return null;
7627 if (auto ale = e.isArrayLiteralExp())
7629 foreach (elem; *ale.elements)
7631 if (auto ex = evaluatePostblit(istate, elem))
7632 return ex;
7634 return null;
7636 if (e.op == EXP.structLiteral)
7638 // e.__postblit()
7639 UnionExp ue = void;
7640 e = interpretFunction(&ue, sd.postblit, istate, null, e);
7641 if (e == ue.exp())
7642 e = ue.copy();
7643 if (exceptionOrCantInterpret(e))
7644 return e;
7645 return null;
7647 assert(0);
7650 private Expression evaluateDtor(InterState* istate, Expression e)
7652 auto ts = e.type.baseElemOf().isTypeStruct();
7653 if (!ts)
7654 return null;
7655 StructDeclaration sd = ts.sym;
7656 if (!sd.dtor)
7657 return null;
7659 UnionExp ue = void;
7660 if (auto ale = e.isArrayLiteralExp())
7662 foreach_reverse (elem; *ale.elements)
7663 e = evaluateDtor(istate, elem);
7665 else if (e.op == EXP.structLiteral)
7667 // e.__dtor()
7668 e = interpretFunction(&ue, sd.dtor, istate, null, e);
7670 else
7671 assert(0);
7672 if (exceptionOrCantInterpret(e))
7674 if (e == ue.exp())
7675 e = ue.copy();
7676 return e;
7678 return null;
7681 /*************************** CTFE Sanity Checks ***************************/
7682 /* Setter functions for CTFE variable values.
7683 * These functions exist to check for compiler CTFE bugs.
7685 private bool hasValue(VarDeclaration vd)
7687 return vd.ctfeAdrOnStack != VarDeclaration.AdrOnStackNone &&
7688 getValue(vd) !is null;
7691 // Don't check for validity
7692 private void setValueWithoutChecking(VarDeclaration vd, Expression newval)
7694 ctfeGlobals.stack.setValue(vd, newval);
7697 private void setValue(VarDeclaration vd, Expression newval)
7699 //printf("setValue() vd: %s newval: %s\n", vd.toChars(), newval.toChars());
7700 version (none)
7702 if (!((vd.storage_class & (STC.out_ | STC.ref_)) ? isCtfeReferenceValid(newval) : isCtfeValueValid(newval)))
7704 printf("[%s] vd = %s %s, newval = %s\n", vd.loc.toChars(), vd.type.toChars(), vd.toChars(), newval.toChars());
7707 assert((vd.storage_class & (STC.out_ | STC.ref_)) ? isCtfeReferenceValid(newval) : isCtfeValueValid(newval));
7708 ctfeGlobals.stack.setValue(vd, newval);
7712 * Removes `_d_HookTraceImpl` if found from `ce` and `fd`.
7713 * This is needed for the CTFE interception code to be able to find hooks that are called though the hook's `*Trace`
7714 * wrapper.
7716 * This is done by replacing `_d_HookTraceImpl!(T, Hook, errMsg)(..., parameters)` with `Hook(parameters)`.
7717 * Parameters:
7718 * ce = The CallExp that possible will be be replaced
7719 * fd = Fully resolve function declaration that `ce` would call
7721 private void removeHookTraceImpl(ref CallExp ce, ref FuncDeclaration fd)
7723 if (fd.ident != Id._d_HookTraceImpl)
7724 return;
7726 auto oldCE = ce;
7728 // Get the Hook from the second template parameter
7729 TemplateInstance templateInstance = fd.parent.isTemplateInstance;
7730 RootObject hook = (*templateInstance.tiargs)[1];
7731 assert(hook.isDsymbol(), "Expected _d_HookTraceImpl's second template parameter to be an alias to the hook!");
7732 fd = (cast(Dsymbol)hook).isFuncDeclaration;
7734 // Remove the first three trace parameters
7735 auto arguments = new Expressions();
7736 arguments.reserve(ce.arguments.length - 3);
7737 arguments.pushSlice((*ce.arguments)[3 .. $]);
7739 ce = ctfeEmplaceExp!CallExp(ce.loc, ctfeEmplaceExp!VarExp(ce.loc, fd, false), arguments);
7741 if (global.params.v.verbose)
7742 message("strip %s =>\n %s", oldCE.toChars(), ce.toChars());