1 /**
2 * The entry point for CTFE.
3 *
4 * Specification: ($LINK2 https://dlang.org/spec/function.html#interpretation, Compile Time Function Execution (CTFE))
5 *
6 * Copyright: Copyright (C) 1999-2022 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
12 */
13
14 module dmd.dinterpret;
15
16 import core.stdc.stdio;
17 import core.stdc.stdlib;
18 import core.stdc.string;
19 import dmd.apply;
20 import dmd.arraytypes;
21 import dmd.astenums;
22 import dmd.attrib;
23 import dmd.builtin;
24 import dmd.constfold;
25 import dmd.ctfeexpr;
26 import dmd.dclass;
27 import dmd.declaration;
28 import dmd.dstruct;
29 import dmd.dsymbol;
30 import dmd.dsymbolsem;
31 import dmd.dtemplate;
32 import dmd.errors;
33 import dmd.expression;
34 import dmd.expressionsem;
35 import dmd.func;
36 import dmd.globals;
37 import dmd.hdrgen;
38 import dmd.id;
39 import dmd.identifier;
40 import dmd.init;
41 import dmd.initsem;
42 import dmd.mtype;
43 import dmd.printast;
44 import dmd.root.rmem;
45 import dmd.root.array;
46 import dmd.root.ctfloat;
47 import dmd.root.region;
48 import dmd.root.rootobject;
49 import dmd.root.utf;
50 import dmd.statement;
51 import dmd.tokens;
52 import dmd.visitor;
53
54 /*************************************
55 * Entry point for CTFE.
56 * A compile-time result is required. Give an error if not possible.
57 *
58 * `e` must be semantically valid expression. In other words, it should not
59 * contain any `ErrorExp`s in it. But, CTFE interpretation will cross over
60 * functions and may invoke a function that contains `ErrorStatement` in its body.
61 * If that, the "CTFE failed because of previous errors" error is raised.
62 */
ctfeInterpret(Expression e)63 public Expression ctfeInterpret(Expression e)
64 {
65 switch (e.op)
66 {
67 case EXP.int64:
68 case EXP.float64:
69 case EXP.complex80:
70 case EXP.null_:
71 case EXP.void_:
72 case EXP.string_:
73 case EXP.this_:
74 case EXP.super_:
75 case EXP.type:
76 case EXP.typeid_:
77 case EXP.template_: // non-eponymous template/instance
78 case EXP.scope_: // ditto
79 case EXP.dotTemplateDeclaration: // ditto, e.e1 doesn't matter here
80 case EXP.dotTemplateInstance: // ditto
81 case EXP.dot: // ditto
82 if (e.type.ty == Terror)
83 return ErrorExp.get();
84 goto case EXP.error;
85
86 case EXP.error:
87 return e;
88
89 default:
90 break;
91 }
92
93 assert(e.type); // https://issues.dlang.org/show_bug.cgi?id=14642
94 //assert(e.type.ty != Terror); // FIXME
95 if (e.type.ty == Terror)
96 return ErrorExp.get();
97
98 auto rgnpos = ctfeGlobals.region.savePos();
99
100 Expression result = interpret(e, null);
101
102 // Report an error if the expression contained a `ThrowException` and
103 // hence generated an uncaught exception
104 if (auto tee = result.isThrownExceptionExp())
105 {
106 tee.generateUncaughtError();
107 result = CTFEExp.cantexp;
108 }
109 else
110 result = copyRegionExp(result);
111
112 if (!CTFEExp.isCantExp(result))
113 result = scrubReturnValue(e.loc, result);
114 if (CTFEExp.isCantExp(result))
115 result = ErrorExp.get();
116
117 ctfeGlobals.region.release(rgnpos);
118
119 return result;
120 }
121
122 /* Run CTFE on the expression, but allow the expression to be a TypeExp
123 * or a tuple containing a TypeExp. (This is required by pragma(msg)).
124 */
ctfeInterpretForPragmaMsg(Expression e)125 public Expression ctfeInterpretForPragmaMsg(Expression e)
126 {
127 if (e.op == EXP.error || e.op == EXP.type)
128 return e;
129
130 // It's also OK for it to be a function declaration (happens only with
131 // __traits(getOverloads))
132 if (auto ve = e.isVarExp())
133 if (ve.var.isFuncDeclaration())
134 {
135 return e;
136 }
137
138 auto tup = e.isTupleExp();
139 if (!tup)
140 return e.ctfeInterpret();
141
142 // Tuples need to be treated separately, since they are
143 // allowed to contain a TypeExp in this case.
144
145 Expressions* expsx = null;
146 foreach (i, g; *tup.exps)
147 {
148 auto h = ctfeInterpretForPragmaMsg(g);
149 if (h != g)
150 {
151 if (!expsx)
152 {
153 expsx = tup.exps.copy();
154 }
155 (*expsx)[i] = h;
156 }
157 }
158 if (expsx)
159 {
160 auto te = new TupleExp(e.loc, expsx);
161 expandTuples(te.exps);
162 te.type = new TypeTuple(te.exps);
163 return te;
164 }
165 return e;
166 }
167
getValue(VarDeclaration vd)168 public extern (C++) Expression getValue(VarDeclaration vd)
169 {
170 return ctfeGlobals.stack.getValue(vd);
171 }
172
173 /*************************************************
174 * Allocate an Expression in the ctfe region.
175 * Params:
176 * T = type of Expression to allocate
177 * args = arguments to Expression's constructor
178 * Returns:
179 * allocated Expression
180 */
181 T ctfeEmplaceExp(T : Expression, Args...)(Args args)
182 {
183 if (mem.isGCEnabled)
184 return new T(args);
185 auto p = ctfeGlobals.region.malloc(__traits(classInstanceSize, T));
186 emplaceExp!T(p, args);
187 return cast(T)p;
188 }
189
190 // CTFE diagnostic information
printCtfePerformanceStats()191 public extern (C++) void printCtfePerformanceStats()
192 {
193 debug (SHOWPERFORMANCE)
194 {
195 printf(" ---- CTFE Performance ----\n");
196 printf("max call depth = %d\tmax stack = %d\n", ctfeGlobals.maxCallDepth, ctfeGlobals.stack.maxStackUsage());
197 printf("array allocs = %d\tassignments = %d\n\n", ctfeGlobals.numArrayAllocs, ctfeGlobals.numAssignments);
198 }
199 }
200
201 /**************************
202 */
203
incArrayAllocs()204 void incArrayAllocs()
205 {
206 ++ctfeGlobals.numArrayAllocs;
207 }
208
209 /* ================================================ Implementation ======================================= */
210
211 private:
212
213 /***************
214 * Collect together globals used by CTFE
215 */
216 struct CtfeGlobals
217 {
218 Region region;
219
220 CtfeStack stack;
221
222 int callDepth = 0; // current number of recursive calls
223
224 // When printing a stack trace, suppress this number of calls
225 int stackTraceCallsToSuppress = 0;
226
227 int maxCallDepth = 0; // highest number of recursive calls
228 int numArrayAllocs = 0; // Number of allocated arrays
229 int numAssignments = 0; // total number of assignments executed
230 }
231
232 __gshared CtfeGlobals ctfeGlobals;
233
234 enum CTFEGoal : int
235 {
236 RValue, /// Must return an Rvalue (== CTFE value)
237 LValue, /// Must return an Lvalue (== CTFE reference)
238 Nothing, /// The return value is not required
239 }
240
241 //debug = LOG;
242 //debug = LOGASSIGN;
243 //debug = LOGCOMPILE;
244 //debug = SHOWPERFORMANCE;
245
246 // Maximum allowable recursive function calls in CTFE
247 enum CTFE_RECURSION_LIMIT = 1000;
248
249 /**
250 The values of all CTFE variables
251 */
252 struct CtfeStack
253 {
254 private:
255 /* The stack. Every declaration we encounter is pushed here,
256 * together with the VarDeclaration, and the previous
257 * stack address of that variable, so that we can restore it
258 * when we leave the stack frame.
259 * Note that when a function is forward referenced, the interpreter must
260 * run semantic3, and that may start CTFE again with a NULL istate. Thus
261 * the stack might not be empty when CTFE begins.
262 *
263 * Ctfe Stack addresses are just 0-based integers, but we save
264 * them as 'void *' because Array can only do pointers.
265 */
266 Expressions values; // values on the stack
267 VarDeclarations vars; // corresponding variables
268 Array!(void*) savedId; // id of the previous state of that var
269
270 Array!(void*) frames; // all previous frame pointers
271 Expressions savedThis; // all previous values of localThis
272
273 /* Global constants get saved here after evaluation, so we never
274 * have to redo them. This saves a lot of time and memory.
275 */
276 Expressions globalValues; // values of global constants
277
278 size_t framepointer; // current frame pointer
279 size_t maxStackPointer; // most stack we've ever used
280 Expression localThis; // value of 'this', or NULL if none
281
282 public:
stackPointerCtfeStack283 extern (C++) size_t stackPointer()
284 {
285 return values.dim;
286 }
287
288 // The current value of 'this', or NULL if none
getThisCtfeStack289 extern (C++) Expression getThis()
290 {
291 return localThis;
292 }
293
294 // Largest number of stack positions we've used
maxStackUsageCtfeStack295 extern (C++) size_t maxStackUsage()
296 {
297 return maxStackPointer;
298 }
299
300 // Start a new stack frame, using the provided 'this'.
startFrameCtfeStack301 extern (C++) void startFrame(Expression thisexp)
302 {
303 frames.push(cast(void*)cast(size_t)framepointer);
304 savedThis.push(localThis);
305 framepointer = stackPointer();
306 localThis = thisexp;
307 }
308
endFrameCtfeStack309 extern (C++) void endFrame()
310 {
311 size_t oldframe = cast(size_t)frames[frames.dim - 1];
312 localThis = savedThis[savedThis.dim - 1];
313 popAll(framepointer);
314 framepointer = oldframe;
315 frames.setDim(frames.dim - 1);
316 savedThis.setDim(savedThis.dim - 1);
317 }
318
isInCurrentFrameCtfeStack319 extern (C++) bool isInCurrentFrame(VarDeclaration v)
320 {
321 if (v.isDataseg() && !v.isCTFE())
322 return false; // It's a global
323 return v.ctfeAdrOnStack >= framepointer;
324 }
325
getValueCtfeStack326 extern (C++) Expression getValue(VarDeclaration v)
327 {
328 //printf("getValue() %s\n", v.toChars());
329 if ((v.isDataseg() || v.storage_class & STC.manifest) && !v.isCTFE())
330 {
331 assert(v.ctfeAdrOnStack < globalValues.dim);
332 return globalValues[v.ctfeAdrOnStack];
333 }
334 assert(v.ctfeAdrOnStack < stackPointer());
335 return values[v.ctfeAdrOnStack];
336 }
337
setValueCtfeStack338 extern (C++) void setValue(VarDeclaration v, Expression e)
339 {
340 //printf("setValue() %s : %s\n", v.toChars(), e.toChars());
341 assert(!v.isDataseg() || v.isCTFE());
342 assert(v.ctfeAdrOnStack < stackPointer());
343 values[v.ctfeAdrOnStack] = e;
344 }
345
pushCtfeStack346 extern (C++) void push(VarDeclaration v)
347 {
348 //printf("push() %s\n", v.toChars());
349 assert(!v.isDataseg() || v.isCTFE());
350 if (v.ctfeAdrOnStack != VarDeclaration.AdrOnStackNone && v.ctfeAdrOnStack >= framepointer)
351 {
352 // Already exists in this frame, reuse it.
353 values[v.ctfeAdrOnStack] = null;
354 return;
355 }
356 savedId.push(cast(void*)cast(size_t)v.ctfeAdrOnStack);
357 v.ctfeAdrOnStack = cast(uint)values.dim;
358 vars.push(v);
359 values.push(null);
360 }
361
popCtfeStack362 extern (C++) void pop(VarDeclaration v)
363 {
364 assert(!v.isDataseg() || v.isCTFE());
365 assert(!v.isReference());
366 const oldid = v.ctfeAdrOnStack;
367 v.ctfeAdrOnStack = cast(uint)cast(size_t)savedId[oldid];
368 if (v.ctfeAdrOnStack == values.dim - 1)
369 {
370 values.pop();
371 vars.pop();
372 savedId.pop();
373 }
374 }
375
popAllCtfeStack376 extern (C++) void popAll(size_t stackpointer)
377 {
378 if (stackPointer() > maxStackPointer)
379 maxStackPointer = stackPointer();
380 assert(values.dim >= stackpointer);
381 for (size_t i = stackpointer; i < values.dim; ++i)
382 {
383 VarDeclaration v = vars[i];
384 v.ctfeAdrOnStack = cast(uint)cast(size_t)savedId[i];
385 }
386 values.setDim(stackpointer);
387 vars.setDim(stackpointer);
388 savedId.setDim(stackpointer);
389 }
390
saveGlobalConstantCtfeStack391 extern (C++) void saveGlobalConstant(VarDeclaration v, Expression e)
392 {
393 assert(v._init && (v.isConst() || v.isImmutable() || v.storage_class & STC.manifest) && !v.isCTFE());
394 v.ctfeAdrOnStack = cast(uint)globalValues.dim;
395 globalValues.push(copyRegionExp(e));
396 }
397 }
398
399 private struct InterState
400 {
401 InterState* caller; // calling function's InterState
402 FuncDeclaration fd; // function being interpreted
403 Statement start; // if !=NULL, start execution at this statement
404
405 /* target of CTFEExp result; also
406 * target of labelled CTFEExp or
407 * CTFEExp. (null if no label).
408 */
409 Statement gotoTarget;
410 }
411
412 /*************************************
413 * Attempt to interpret a function given the arguments.
414 * Params:
415 * pue = storage for result
416 * fd = function being called
417 * istate = state for calling function (NULL if none)
418 * arguments = function arguments
419 * thisarg = 'this', if a needThis() function, NULL if not.
420 *
421 * Returns:
422 * result expression if successful, EXP.cantExpression if not,
423 * or CTFEExp if function returned void.
424 */
interpretFunction(UnionExp * pue,FuncDeclaration fd,InterState * istate,Expressions * arguments,Expression thisarg)425 private Expression interpretFunction(UnionExp* pue, FuncDeclaration fd, InterState* istate, Expressions* arguments, Expression thisarg)
426 {
427 debug (LOG)
428 {
429 printf("\n********\n%s FuncDeclaration::interpret(istate = %p) %s\n", fd.loc.toChars(), istate, fd.toChars());
430 }
431 assert(pue);
432 if (fd.semanticRun == PASS.semantic3)
433 {
434 fd.error("circular dependency. Functions cannot be interpreted while being compiled");
435 return CTFEExp.cantexp;
436 }
437 if (!fd.functionSemantic3())
438 return CTFEExp.cantexp;
439 if (fd.semanticRun < PASS.semantic3done)
440 {
441 fd.error("circular dependency. Functions cannot be interpreted while being compiled");
442 return CTFEExp.cantexp;
443 }
444
445 auto tf = fd.type.toBasetype().isTypeFunction();
446 if (tf.parameterList.varargs != VarArg.none && arguments &&
447 ((fd.parameters && arguments.dim != fd.parameters.dim) || (!fd.parameters && arguments.dim)))
448 {
449 fd.error("C-style variadic functions are not yet implemented in CTFE");
450 return CTFEExp.cantexp;
451 }
452
453 // Nested functions always inherit the 'this' pointer from the parent,
454 // except for delegates. (Note that the 'this' pointer may be null).
455 // Func literals report isNested() even if they are in global scope,
456 // so we need to check that the parent is a function.
457 if (fd.isNested() && fd.toParentLocal().isFuncDeclaration() && !thisarg && istate)
458 thisarg = ctfeGlobals.stack.getThis();
459
460 if (fd.needThis() && !thisarg)
461 {
462 // error, no this. Prevent segfault.
463 // Here should be unreachable by the strict 'this' check in front-end.
464 fd.error("need `this` to access member `%s`", fd.toChars());
465 return CTFEExp.cantexp;
466 }
467
468 // Place to hold all the arguments to the function while
469 // we are evaluating them.
470 size_t dim = arguments ? arguments.dim : 0;
471 assert((fd.parameters ? fd.parameters.dim : 0) == dim);
472
473 /* Evaluate all the arguments to the function,
474 * store the results in eargs[]
475 */
476 Expressions eargs = Expressions(dim);
477 for (size_t i = 0; i < dim; i++)
478 {
479 Expression earg = (*arguments)[i];
480 Parameter fparam = tf.parameterList[i];
481
482 if (fparam.isReference())
483 {
484 if (!istate && (fparam.storageClass & STC.out_))
485 {
486 // initializing an out parameter involves writing to it.
487 earg.error("global `%s` cannot be passed as an `out` parameter at compile time", earg.toChars());
488 return CTFEExp.cantexp;
489 }
490 // Convert all reference arguments into lvalue references
491 earg = interpretRegion(earg, istate, CTFEGoal.LValue);
492 if (CTFEExp.isCantExp(earg))
493 return earg;
494 }
495 else if (fparam.storageClass & STC.lazy_)
496 {
497 }
498 else
499 {
500 /* Value parameters
501 */
502 Type ta = fparam.type.toBasetype();
503 if (ta.ty == Tsarray)
504 if (auto eaddr = earg.isAddrExp())
505 {
506 /* Static arrays are passed by a simple pointer.
507 * Skip past this to get at the actual arg.
508 */
509 earg = eaddr.e1;
510 }
511
512 earg = interpretRegion(earg, istate);
513 if (CTFEExp.isCantExp(earg))
514 return earg;
515
516 /* Struct literals are passed by value, but we don't need to
517 * copy them if they are passed as const
518 */
519 if (earg.op == EXP.structLiteral && !(fparam.storageClass & (STC.const_ | STC.immutable_)))
520 earg = copyLiteral(earg).copy();
521 }
522 if (auto tee = earg.isThrownExceptionExp())
523 {
524 if (istate)
525 return tee;
526 tee.generateUncaughtError();
527 return CTFEExp.cantexp;
528 }
529 eargs[i] = earg;
530 }
531
532 // Now that we've evaluated all the arguments, we can start the frame
533 // (this is the moment when the 'call' actually takes place).
534 InterState istatex;
535 istatex.caller = istate;
536 istatex.fd = fd;
537
538 if (fd.hasDualContext())
539 {
540 Expression arg0 = thisarg;
541 if (arg0 && arg0.type.ty == Tstruct)
542 {
543 Type t = arg0.type.pointerTo();
544 arg0 = ctfeEmplaceExp!AddrExp(arg0.loc, arg0);
545 arg0.type = t;
546 }
547 auto elements = new Expressions(2);
548 (*elements)[0] = arg0;
549 (*elements)[1] = ctfeGlobals.stack.getThis();
550 Type t2 = Type.tvoidptr.sarrayOf(2);
551 const loc = thisarg ? thisarg.loc : fd.loc;
552 thisarg = ctfeEmplaceExp!ArrayLiteralExp(loc, t2, elements);
553 thisarg = ctfeEmplaceExp!AddrExp(loc, thisarg);
554 thisarg.type = t2.pointerTo();
555 }
556
557 ctfeGlobals.stack.startFrame(thisarg);
558 if (fd.vthis && thisarg)
559 {
560 ctfeGlobals.stack.push(fd.vthis);
561 setValue(fd.vthis, thisarg);
562 }
563
564 for (size_t i = 0; i < dim; i++)
565 {
566 Expression earg = eargs[i];
567 Parameter fparam = tf.parameterList[i];
568 VarDeclaration v = (*fd.parameters)[i];
569 debug (LOG)
570 {
571 printf("arg[%zu] = %s\n", i, earg.toChars());
572 }
573 ctfeGlobals.stack.push(v);
574
575 if (fparam.isReference() && earg.op == EXP.variable &&
576 earg.isVarExp().var.toParent2() == fd)
577 {
578 VarDeclaration vx = earg.isVarExp().var.isVarDeclaration();
579 if (!vx)
580 {
581 fd.error("cannot interpret `%s` as a `ref` parameter", earg.toChars());
582 return CTFEExp.cantexp;
583 }
584
585 /* vx is a variable that is declared in fd.
586 * It means that fd is recursively called. e.g.
587 *
588 * void fd(int n, ref int v = dummy) {
589 * int vx;
590 * if (n == 1) fd(2, vx);
591 * }
592 * fd(1);
593 *
594 * The old value of vx on the stack in fd(1)
595 * should be saved at the start of fd(2, vx) call.
596 */
597 const oldadr = vx.ctfeAdrOnStack;
598
599 ctfeGlobals.stack.push(vx);
600 assert(!hasValue(vx)); // vx is made uninitialized
601
602 // https://issues.dlang.org/show_bug.cgi?id=14299
603 // v.ctfeAdrOnStack should be saved already
604 // in the stack before the overwrite.
605 v.ctfeAdrOnStack = oldadr;
606 assert(hasValue(v)); // ref parameter v should refer existing value.
607 }
608 else
609 {
610 // Value parameters and non-trivial references
611 setValueWithoutChecking(v, earg);
612 }
613 debug (LOG)
614 {
615 printf("interpreted arg[%zu] = %s\n", i, earg.toChars());
616 showCtfeExpr(earg);
617 }
618 debug (LOGASSIGN)
619 {
620 printf("interpreted arg[%zu] = %s\n", i, earg.toChars());
621 showCtfeExpr(earg);
622 }
623 }
624
625 if (fd.vresult)
626 ctfeGlobals.stack.push(fd.vresult);
627
628 // Enter the function
629 ++ctfeGlobals.callDepth;
630 if (ctfeGlobals.callDepth > ctfeGlobals.maxCallDepth)
631 ctfeGlobals.maxCallDepth = ctfeGlobals.callDepth;
632
633 Expression e = null;
634 while (1)
635 {
636 if (ctfeGlobals.callDepth > CTFE_RECURSION_LIMIT)
637 {
638 // This is a compiler error. It must not be suppressed.
639 global.gag = 0;
640 fd.error("CTFE recursion limit exceeded");
641 e = CTFEExp.cantexp;
642 break;
643 }
644 e = interpret(pue, fd.fbody, &istatex);
645 if (CTFEExp.isCantExp(e))
646 {
647 debug (LOG)
648 {
649 printf("function body failed to interpret\n");
650 }
651 }
652
653 if (istatex.start)
654 {
655 fd.error("CTFE internal error: failed to resume at statement `%s`", istatex.start.toChars());
656 return CTFEExp.cantexp;
657 }
658
659 /* This is how we deal with a recursive statement AST
660 * that has arbitrary goto statements in it.
661 * Bubble up a 'result' which is the target of the goto
662 * statement, then go recursively down the AST looking
663 * for that statement, then execute starting there.
664 */
665 if (CTFEExp.isGotoExp(e))
666 {
667 istatex.start = istatex.gotoTarget; // set starting statement
668 istatex.gotoTarget = null;
669 }
670 else
671 {
672 assert(!e || (e.op != EXP.continue_ && e.op != EXP.break_));
673 break;
674 }
675 }
676 // If fell off the end of a void function, return void
677 if (!e)
678 {
679 if (tf.next.ty == Tvoid)
680 e = CTFEExp.voidexp;
681 else
682 {
683 /* missing a return statement can happen with C functions
684 * https://issues.dlang.org/show_bug.cgi?id=23056
685 */
686 fd.error("no return value from function");
687 e = CTFEExp.cantexp;
688 }
689 }
690
691 if (tf.isref && e.op == EXP.variable && e.isVarExp().var == fd.vthis)
692 e = thisarg;
693 if (tf.isref && fd.hasDualContext() && e.op == EXP.index)
694 {
695 auto ie = e.isIndexExp();
696 auto pe = ie.e1.isPtrExp();
697 auto ve = !pe ? null : pe.e1.isVarExp();
698 if (ve && ve.var == fd.vthis)
699 {
700 auto ne = ie.e2.isIntegerExp();
701 assert(ne);
702 auto ale = thisarg.isAddrExp().e1.isArrayLiteralExp();
703 e = (*ale.elements)[cast(size_t)ne.getInteger()];
704 if (auto ae = e.isAddrExp())
705 {
706 e = ae.e1;
707 }
708 }
709 }
710
711 // Leave the function
712 --ctfeGlobals.callDepth;
713
714 ctfeGlobals.stack.endFrame();
715
716 // If it generated an uncaught exception, report error.
717 if (!istate && e.isThrownExceptionExp())
718 {
719 if (e == pue.exp())
720 e = pue.copy();
721 e.isThrownExceptionExp().generateUncaughtError();
722 e = CTFEExp.cantexp;
723 }
724
725 return e;
726 }
727
728 /// used to collect coverage information in ctfe
incUsageCtfe(InterState * istate,const ref Loc loc)729 void incUsageCtfe(InterState* istate, const ref Loc loc)
730 {
731 if (global.params.ctfe_cov && istate)
732 {
733 auto line = loc.linnum;
734 auto mod = istate.fd.getModule();
735
736 ++mod.ctfe_cov[line];
737 }
738 }
739
740 private extern (C++) final class Interpreter : Visitor
741 {
742 alias visit = Visitor.visit;
743 public:
744 InterState* istate;
745 CTFEGoal goal;
746 Expression result;
747 UnionExp* pue; // storage for `result`
748
this(UnionExp * pue,InterState * istate,CTFEGoal goal)749 extern (D) this(UnionExp* pue, InterState* istate, CTFEGoal goal)
750 {
751 this.pue = pue;
752 this.istate = istate;
753 this.goal = goal;
754 }
755
756 // If e is EXP.throw_exception or EXP.cantExpression,
757 // set it to 'result' and returns true.
exceptionOrCant(Expression e)758 bool exceptionOrCant(Expression e)
759 {
760 if (exceptionOrCantInterpret(e))
761 {
762 // Make sure e is not pointing to a stack temporary
763 result = (e.op == EXP.cantExpression) ? CTFEExp.cantexp : e;
764 return true;
765 }
766 return false;
767 }
768
copyArrayOnWrite(Expressions * exps,Expressions * original)769 static Expressions* copyArrayOnWrite(Expressions* exps, Expressions* original)
770 {
771 if (exps is original)
772 {
773 if (!original)
774 exps = new Expressions();
775 else
776 exps = original.copy();
777 ++ctfeGlobals.numArrayAllocs;
778 }
779 return exps;
780 }
781
782 /******************************** Statement ***************************/
783
visit(Statement s)784 override void visit(Statement s)
785 {
786 debug (LOG)
787 {
788 printf("%s Statement::interpret()\n", s.loc.toChars());
789 }
790 if (istate.start)
791 {
792 if (istate.start != s)
793 return;
794 istate.start = null;
795 }
796
797 s.error("statement `%s` cannot be interpreted at compile time", s.toChars());
798 result = CTFEExp.cantexp;
799 }
800
visit(ExpStatement s)801 override void visit(ExpStatement s)
802 {
803 debug (LOG)
804 {
805 printf("%s ExpStatement::interpret(%s)\n", s.loc.toChars(), s.exp ? s.exp.toChars() : "");
806 }
807 if (istate.start)
808 {
809 if (istate.start != s)
810 return;
811 istate.start = null;
812 }
813 if (s.exp && s.exp.hasCode)
814 incUsageCtfe(istate, s.loc);
815
816 Expression e = interpret(pue, s.exp, istate, CTFEGoal.Nothing);
817 if (exceptionOrCant(e))
818 return;
819 }
820
visit(CompoundStatement s)821 override void visit(CompoundStatement s)
822 {
823 debug (LOG)
824 {
825 printf("%s CompoundStatement::interpret()\n", s.loc.toChars());
826 }
827 if (istate.start == s)
828 istate.start = null;
829
830 const dim = s.statements ? s.statements.dim : 0;
831 foreach (i; 0 .. dim)
832 {
833 Statement sx = (*s.statements)[i];
834 result = interpret(pue, sx, istate);
835 if (result)
836 break;
837 }
838 debug (LOG)
839 {
840 printf("%s -CompoundStatement::interpret() %p\n", s.loc.toChars(), result);
841 }
842 }
843
visit(UnrolledLoopStatement s)844 override void visit(UnrolledLoopStatement s)
845 {
846 debug (LOG)
847 {
848 printf("%s UnrolledLoopStatement::interpret()\n", s.loc.toChars());
849 }
850 if (istate.start == s)
851 istate.start = null;
852
853 const dim = s.statements ? s.statements.dim : 0;
854 foreach (i; 0 .. dim)
855 {
856 Statement sx = (*s.statements)[i];
857 Expression e = interpret(pue, sx, istate);
858 if (!e) // succeeds to interpret, or goto target was not found
859 continue;
860 if (exceptionOrCant(e))
861 return;
862 if (e.op == EXP.break_)
863 {
864 if (istate.gotoTarget && istate.gotoTarget != s)
865 {
866 result = e; // break at a higher level
867 return;
868 }
869 istate.gotoTarget = null;
870 result = null;
871 return;
872 }
873 if (e.op == EXP.continue_)
874 {
875 if (istate.gotoTarget && istate.gotoTarget != s)
876 {
877 result = e; // continue at a higher level
878 return;
879 }
880 istate.gotoTarget = null;
881 continue;
882 }
883
884 // expression from return statement, or thrown exception
885 result = e;
886 break;
887 }
888 }
889
visit(IfStatement s)890 override void visit(IfStatement s)
891 {
892 debug (LOG)
893 {
894 printf("%s IfStatement::interpret(%s)\n", s.loc.toChars(), s.condition.toChars());
895 }
896 incUsageCtfe(istate, s.loc);
897 if (istate.start == s)
898 istate.start = null;
899 if (istate.start)
900 {
901 Expression e = null;
902 e = interpret(s.ifbody, istate);
903 if (!e && istate.start)
904 e = interpret(s.elsebody, istate);
905 result = e;
906 return;
907 }
908
909 UnionExp ue = void;
910 Expression e = interpret(&ue, s.condition, istate);
911 assert(e);
912 if (exceptionOrCant(e))
913 return;
914
915 if (isTrueBool(e))
916 result = interpret(pue, s.ifbody, istate);
917 else if (e.toBool().hasValue(false))
918 result = interpret(pue, s.elsebody, istate);
919 else
920 {
921 // no error, or assert(0)?
922 result = CTFEExp.cantexp;
923 }
924 }
925
visit(ScopeStatement s)926 override void visit(ScopeStatement s)
927 {
928 debug (LOG)
929 {
930 printf("%s ScopeStatement::interpret()\n", s.loc.toChars());
931 }
932 if (istate.start == s)
933 istate.start = null;
934
935 result = interpret(pue, s.statement, istate);
936 }
937
938 /**
939 Given an expression e which is about to be returned from the current
940 function, generate an error if it contains pointers to local variables.
941
942 Only checks expressions passed by value (pointers to local variables
943 may already be stored in members of classes, arrays, or AAs which
944 were passed as mutable function parameters).
945 Returns:
946 true if it is safe to return, false if an error was generated.
947 */
stopPointersEscaping(const ref Loc loc,Expression e)948 static bool stopPointersEscaping(const ref Loc loc, Expression e)
949 {
950 if (!e.type.hasPointers())
951 return true;
952 if (isPointer(e.type))
953 {
954 Expression x = e;
955 if (auto eaddr = e.isAddrExp())
956 x = eaddr.e1;
957 VarDeclaration v;
958 while (x.op == EXP.variable && (v = x.isVarExp().var.isVarDeclaration()) !is null)
959 {
960 if (v.storage_class & STC.ref_)
961 {
962 x = getValue(v);
963 if (auto eaddr = e.isAddrExp())
964 eaddr.e1 = x;
965 continue;
966 }
967 if (ctfeGlobals.stack.isInCurrentFrame(v))
968 {
969 error(loc, "returning a pointer to a local stack variable");
970 return false;
971 }
972 else
973 break;
974 }
975 // TODO: If it is a EXP.dotVariable or EXP.index, we should check that it is not
976 // pointing to a local struct or static array.
977 }
978 if (auto se = e.isStructLiteralExp())
979 {
980 return stopPointersEscapingFromArray(loc, se.elements);
981 }
982 if (auto ale = e.isArrayLiteralExp())
983 {
984 return stopPointersEscapingFromArray(loc, ale.elements);
985 }
986 if (auto aae = e.isAssocArrayLiteralExp())
987 {
988 if (!stopPointersEscapingFromArray(loc, aae.keys))
989 return false;
990 return stopPointersEscapingFromArray(loc, aae.values);
991 }
992 return true;
993 }
994
995 // Check all elements of an array for escaping local variables. Return false if error
stopPointersEscapingFromArray(const ref Loc loc,Expressions * elems)996 static bool stopPointersEscapingFromArray(const ref Loc loc, Expressions* elems)
997 {
998 foreach (e; *elems)
999 {
1000 if (e && !stopPointersEscaping(loc, e))
1001 return false;
1002 }
1003 return true;
1004 }
1005
visit(ReturnStatement s)1006 override void visit(ReturnStatement s)
1007 {
1008 debug (LOG)
1009 {
1010 printf("%s ReturnStatement::interpret(%s)\n", s.loc.toChars(), s.exp ? s.exp.toChars() : "");
1011 }
1012 if (istate.start)
1013 {
1014 if (istate.start != s)
1015 return;
1016 istate.start = null;
1017 }
1018
1019 if (!s.exp)
1020 {
1021 result = CTFEExp.voidexp;
1022 return;
1023 }
1024
1025 incUsageCtfe(istate, s.loc);
1026 assert(istate && istate.fd && istate.fd.type && istate.fd.type.ty == Tfunction);
1027 TypeFunction tf = cast(TypeFunction)istate.fd.type;
1028
1029 /* If the function returns a ref AND it's been called from an assignment,
1030 * we need to return an lvalue. Otherwise, just do an (rvalue) interpret.
1031 */
1032 if (tf.isref)
1033 {
1034 result = interpret(pue, s.exp, istate, CTFEGoal.LValue);
1035 return;
1036 }
1037 if (tf.next && tf.next.ty == Tdelegate && istate.fd.closureVars.dim > 0)
1038 {
1039 // To support this, we need to copy all the closure vars
1040 // into the delegate literal.
1041 s.error("closures are not yet supported in CTFE");
1042 result = CTFEExp.cantexp;
1043 return;
1044 }
1045
1046 // We need to treat pointers specially, because EXP.symbolOffset can be used to
1047 // return a value OR a pointer
1048 Expression e = interpret(pue, s.exp, istate);
1049 if (exceptionOrCant(e))
1050 return;
1051
1052 // Disallow returning pointers to stack-allocated variables (bug 7876)
1053 if (!stopPointersEscaping(s.loc, e))
1054 {
1055 result = CTFEExp.cantexp;
1056 return;
1057 }
1058
1059 if (needToCopyLiteral(e))
1060 e = copyLiteral(e).copy();
1061 debug (LOGASSIGN)
1062 {
1063 printf("RETURN %s\n", s.loc.toChars());
1064 showCtfeExpr(e);
1065 }
1066 result = e;
1067 }
1068
findGotoTarget(InterState * istate,Identifier ident)1069 static Statement findGotoTarget(InterState* istate, Identifier ident)
1070 {
1071 Statement target = null;
1072 if (ident)
1073 {
1074 LabelDsymbol label = istate.fd.searchLabel(ident);
1075 assert(label && label.statement);
1076 LabelStatement ls = label.statement;
1077 target = ls.gotoTarget ? ls.gotoTarget : ls.statement;
1078 }
1079 return target;
1080 }
1081
visit(BreakStatement s)1082 override void visit(BreakStatement s)
1083 {
1084 debug (LOG)
1085 {
1086 printf("%s BreakStatement::interpret()\n", s.loc.toChars());
1087 }
1088 incUsageCtfe(istate, s.loc);
1089 if (istate.start)
1090 {
1091 if (istate.start != s)
1092 return;
1093 istate.start = null;
1094 }
1095
1096 istate.gotoTarget = findGotoTarget(istate, s.ident);
1097 result = CTFEExp.breakexp;
1098 }
1099
visit(ContinueStatement s)1100 override void visit(ContinueStatement s)
1101 {
1102 debug (LOG)
1103 {
1104 printf("%s ContinueStatement::interpret()\n", s.loc.toChars());
1105 }
1106 incUsageCtfe(istate, s.loc);
1107 if (istate.start)
1108 {
1109 if (istate.start != s)
1110 return;
1111 istate.start = null;
1112 }
1113
1114 istate.gotoTarget = findGotoTarget(istate, s.ident);
1115 result = CTFEExp.continueexp;
1116 }
1117
visit(WhileStatement s)1118 override void visit(WhileStatement s)
1119 {
1120 debug (LOG)
1121 {
1122 printf("WhileStatement::interpret()\n");
1123 }
1124 assert(0); // rewritten to ForStatement
1125 }
1126
visit(DoStatement s)1127 override void visit(DoStatement s)
1128 {
1129 debug (LOG)
1130 {
1131 printf("%s DoStatement::interpret()\n", s.loc.toChars());
1132 }
1133 if (istate.start == s)
1134 istate.start = null;
1135
1136 while (1)
1137 {
1138 Expression e = interpret(s._body, istate);
1139 if (!e && istate.start) // goto target was not found
1140 return;
1141 assert(!istate.start);
1142
1143 if (exceptionOrCant(e))
1144 return;
1145 if (e && e.op == EXP.break_)
1146 {
1147 if (istate.gotoTarget && istate.gotoTarget != s)
1148 {
1149 result = e; // break at a higher level
1150 return;
1151 }
1152 istate.gotoTarget = null;
1153 break;
1154 }
1155 if (e && e.op == EXP.continue_)
1156 {
1157 if (istate.gotoTarget && istate.gotoTarget != s)
1158 {
1159 result = e; // continue at a higher level
1160 return;
1161 }
1162 istate.gotoTarget = null;
1163 e = null;
1164 }
1165 if (e)
1166 {
1167 result = e; // bubbled up from ReturnStatement
1168 return;
1169 }
1170
1171 UnionExp ue = void;
1172 incUsageCtfe(istate, s.condition.loc);
1173 e = interpret(&ue, s.condition, istate);
1174 if (exceptionOrCant(e))
1175 return;
1176 if (!e.isConst())
1177 {
1178 result = CTFEExp.cantexp;
1179 return;
1180 }
1181 if (e.toBool().hasValue(false))
1182 break;
1183 assert(isTrueBool(e));
1184 }
1185 assert(result is null);
1186 }
1187
visit(ForStatement s)1188 override void visit(ForStatement s)
1189 {
1190 debug (LOG)
1191 {
1192 printf("%s ForStatement::interpret()\n", s.loc.toChars());
1193 }
1194 if (istate.start == s)
1195 istate.start = null;
1196
1197 UnionExp ueinit = void;
1198 Expression ei = interpret(&ueinit, s._init, istate);
1199 if (exceptionOrCant(ei))
1200 return;
1201 assert(!ei); // s.init never returns from function, or jumps out from it
1202
1203 while (1)
1204 {
1205 if (s.condition && !istate.start)
1206 {
1207 UnionExp ue = void;
1208 incUsageCtfe(istate, s.condition.loc);
1209 Expression e = interpret(&ue, s.condition, istate);
1210 if (exceptionOrCant(e))
1211 return;
1212 if (e.toBool().hasValue(false))
1213 break;
1214 assert(isTrueBool(e));
1215 }
1216
1217 Expression e = interpret(pue, s._body, istate);
1218 if (!e && istate.start) // goto target was not found
1219 return;
1220 assert(!istate.start);
1221
1222 if (exceptionOrCant(e))
1223 return;
1224 if (e && e.op == EXP.break_)
1225 {
1226 if (istate.gotoTarget && istate.gotoTarget != s)
1227 {
1228 result = e; // break at a higher level
1229 return;
1230 }
1231 istate.gotoTarget = null;
1232 break;
1233 }
1234 if (e && e.op == EXP.continue_)
1235 {
1236 if (istate.gotoTarget && istate.gotoTarget != s)
1237 {
1238 result = e; // continue at a higher level
1239 return;
1240 }
1241 istate.gotoTarget = null;
1242 e = null;
1243 }
1244 if (e)
1245 {
1246 result = e; // bubbled up from ReturnStatement
1247 return;
1248 }
1249
1250 UnionExp uei = void;
1251 if (s.increment)
1252 incUsageCtfe(istate, s.increment.loc);
1253 e = interpret(&uei, s.increment, istate, CTFEGoal.Nothing);
1254 if (exceptionOrCant(e))
1255 return;
1256 }
1257 assert(result is null);
1258 }
1259
visit(ForeachStatement s)1260 override void visit(ForeachStatement s)
1261 {
1262 assert(0); // rewritten to ForStatement
1263 }
1264
visit(ForeachRangeStatement s)1265 override void visit(ForeachRangeStatement s)
1266 {
1267 assert(0); // rewritten to ForStatement
1268 }
1269
visit(SwitchStatement s)1270 override void visit(SwitchStatement s)
1271 {
1272 debug (LOG)
1273 {
1274 printf("%s SwitchStatement::interpret()\n", s.loc.toChars());
1275 }
1276 incUsageCtfe(istate, s.loc);
1277 if (istate.start == s)
1278 istate.start = null;
1279 if (istate.start)
1280 {
1281 Expression e = interpret(s._body, istate);
1282 if (istate.start) // goto target was not found
1283 return;
1284 if (exceptionOrCant(e))
1285 return;
1286 if (e && e.op == EXP.break_)
1287 {
1288 if (istate.gotoTarget && istate.gotoTarget != s)
1289 {
1290 result = e; // break at a higher level
1291 return;
1292 }
1293 istate.gotoTarget = null;
1294 e = null;
1295 }
1296 result = e;
1297 return;
1298 }
1299
1300 UnionExp uecond = void;
1301 Expression econdition = interpret(&uecond, s.condition, istate);
1302 if (exceptionOrCant(econdition))
1303 return;
1304
1305 Statement scase = null;
1306 if (s.cases)
1307 foreach (cs; *s.cases)
1308 {
1309 UnionExp uecase = void;
1310 Expression ecase = interpret(&uecase, cs.exp, istate);
1311 if (exceptionOrCant(ecase))
1312 return;
1313 if (ctfeEqual(cs.exp.loc, EXP.equal, econdition, ecase))
1314 {
1315 scase = cs;
1316 break;
1317 }
1318 }
1319 if (!scase)
1320 {
1321 if (s.hasNoDefault)
1322 s.error("no `default` or `case` for `%s` in `switch` statement", econdition.toChars());
1323 scase = s.sdefault;
1324 }
1325
1326 assert(scase);
1327
1328 /* Jump to scase
1329 */
1330 istate.start = scase;
1331 Expression e = interpret(pue, s._body, istate);
1332 assert(!istate.start); // jump must not fail
1333 if (e && e.op == EXP.break_)
1334 {
1335 if (istate.gotoTarget && istate.gotoTarget != s)
1336 {
1337 result = e; // break at a higher level
1338 return;
1339 }
1340 istate.gotoTarget = null;
1341 e = null;
1342 }
1343 result = e;
1344 }
1345
visit(CaseStatement s)1346 override void visit(CaseStatement s)
1347 {
1348 debug (LOG)
1349 {
1350 printf("%s CaseStatement::interpret(%s) this = %p\n", s.loc.toChars(), s.exp.toChars(), s);
1351 }
1352 incUsageCtfe(istate, s.loc);
1353 if (istate.start == s)
1354 istate.start = null;
1355
1356 result = interpret(pue, s.statement, istate);
1357 }
1358
visit(DefaultStatement s)1359 override void visit(DefaultStatement s)
1360 {
1361 debug (LOG)
1362 {
1363 printf("%s DefaultStatement::interpret()\n", s.loc.toChars());
1364 }
1365 incUsageCtfe(istate, s.loc);
1366 if (istate.start == s)
1367 istate.start = null;
1368
1369 result = interpret(pue, s.statement, istate);
1370 }
1371
visit(GotoStatement s)1372 override void visit(GotoStatement s)
1373 {
1374 debug (LOG)
1375 {
1376 printf("%s GotoStatement::interpret()\n", s.loc.toChars());
1377 }
1378 if (istate.start)
1379 {
1380 if (istate.start != s)
1381 return;
1382 istate.start = null;
1383 }
1384 incUsageCtfe(istate, s.loc);
1385
1386 assert(s.label && s.label.statement);
1387 istate.gotoTarget = s.label.statement;
1388 result = CTFEExp.gotoexp;
1389 }
1390
visit(GotoCaseStatement s)1391 override void visit(GotoCaseStatement s)
1392 {
1393 debug (LOG)
1394 {
1395 printf("%s GotoCaseStatement::interpret()\n", s.loc.toChars());
1396 }
1397 if (istate.start)
1398 {
1399 if (istate.start != s)
1400 return;
1401 istate.start = null;
1402 }
1403 incUsageCtfe(istate, s.loc);
1404
1405 assert(s.cs);
1406 istate.gotoTarget = s.cs;
1407 result = CTFEExp.gotoexp;
1408 }
1409
visit(GotoDefaultStatement s)1410 override void visit(GotoDefaultStatement s)
1411 {
1412 debug (LOG)
1413 {
1414 printf("%s GotoDefaultStatement::interpret()\n", s.loc.toChars());
1415 }
1416 if (istate.start)
1417 {
1418 if (istate.start != s)
1419 return;
1420 istate.start = null;
1421 }
1422 incUsageCtfe(istate, s.loc);
1423
1424 assert(s.sw && s.sw.sdefault);
1425 istate.gotoTarget = s.sw.sdefault;
1426 result = CTFEExp.gotoexp;
1427 }
1428
visit(LabelStatement s)1429 override void visit(LabelStatement s)
1430 {
1431 debug (LOG)
1432 {
1433 printf("%s LabelStatement::interpret()\n", s.loc.toChars());
1434 }
1435 if (istate.start == s)
1436 istate.start = null;
1437
1438 result = interpret(pue, s.statement, istate);
1439 }
1440
visit(TryCatchStatement s)1441 override void visit(TryCatchStatement s)
1442 {
1443 debug (LOG)
1444 {
1445 printf("%s TryCatchStatement::interpret()\n", s.loc.toChars());
1446 }
1447 if (istate.start == s)
1448 istate.start = null;
1449 if (istate.start)
1450 {
1451 Expression e = null;
1452 e = interpret(pue, s._body, istate);
1453 foreach (ca; *s.catches)
1454 {
1455 if (e || !istate.start) // goto target was found
1456 break;
1457 e = interpret(pue, ca.handler, istate);
1458 }
1459 result = e;
1460 return;
1461 }
1462
1463 Expression e = interpret(s._body, istate);
1464
1465 // An exception was thrown
1466 if (e && e.isThrownExceptionExp())
1467 {
1468 ThrownExceptionExp ex = e.isThrownExceptionExp();
1469 Type extype = ex.thrown.originalClass().type;
1470
1471 // Search for an appropriate catch clause.
1472 foreach (ca; *s.catches)
1473 {
1474 Type catype = ca.type;
1475 if (!catype.equals(extype) && !catype.isBaseOf(extype, null))
1476 continue;
1477
1478 // Execute the handler
1479 if (ca.var)
1480 {
1481 ctfeGlobals.stack.push(ca.var);
1482 setValue(ca.var, ex.thrown);
1483 }
1484 e = interpret(ca.handler, istate);
1485 if (CTFEExp.isGotoExp(e))
1486 {
1487 /* This is an optimization that relies on the locality of the jump target.
1488 * If the label is in the same catch handler, the following scan
1489 * would find it quickly and can reduce jump cost.
1490 * Otherwise, the catch block may be unnnecessary scanned again
1491 * so it would make CTFE speed slower.
1492 */
1493 InterState istatex = *istate;
1494 istatex.start = istate.gotoTarget; // set starting statement
1495 istatex.gotoTarget = null;
1496 Expression eh = interpret(ca.handler, &istatex);
1497 if (!istatex.start)
1498 {
1499 istate.gotoTarget = null;
1500 e = eh;
1501 }
1502 }
1503 break;
1504 }
1505 }
1506 result = e;
1507 }
1508
isAnErrorException(ClassDeclaration cd)1509 static bool isAnErrorException(ClassDeclaration cd)
1510 {
1511 return cd == ClassDeclaration.errorException || ClassDeclaration.errorException.isBaseOf(cd, null);
1512 }
1513
chainExceptions(ThrownExceptionExp oldest,ThrownExceptionExp newest)1514 static ThrownExceptionExp chainExceptions(ThrownExceptionExp oldest, ThrownExceptionExp newest)
1515 {
1516 debug (LOG)
1517 {
1518 printf("Collided exceptions %s %s\n", oldest.thrown.toChars(), newest.thrown.toChars());
1519 }
1520 // Little sanity check to make sure it's really a Throwable
1521 ClassReferenceExp boss = oldest.thrown;
1522 const next = 4; // index of Throwable.next
1523 assert((*boss.value.elements)[next].type.ty == Tclass); // Throwable.next
1524 ClassReferenceExp collateral = newest.thrown;
1525 if (isAnErrorException(collateral.originalClass()) && !isAnErrorException(boss.originalClass()))
1526 {
1527 /* Find the index of the Error.bypassException field
1528 */
1529 auto bypass = next + 1;
1530 if ((*collateral.value.elements)[bypass].type.ty == Tuns32)
1531 bypass += 1; // skip over _refcount field
1532 assert((*collateral.value.elements)[bypass].type.ty == Tclass);
1533
1534 // The new exception bypass the existing chain
1535 (*collateral.value.elements)[bypass] = boss;
1536 return newest;
1537 }
1538 while ((*boss.value.elements)[next].op == EXP.classReference)
1539 {
1540 boss = (*boss.value.elements)[next].isClassReferenceExp();
1541 }
1542 (*boss.value.elements)[next] = collateral;
1543 return oldest;
1544 }
1545
visit(TryFinallyStatement s)1546 override void visit(TryFinallyStatement s)
1547 {
1548 debug (LOG)
1549 {
1550 printf("%s TryFinallyStatement::interpret()\n", s.loc.toChars());
1551 }
1552 if (istate.start == s)
1553 istate.start = null;
1554 if (istate.start)
1555 {
1556 Expression e = null;
1557 e = interpret(pue, s._body, istate);
1558 // Jump into/out from finalbody is disabled in semantic analysis.
1559 // and jump inside will be handled by the ScopeStatement == finalbody.
1560 result = e;
1561 return;
1562 }
1563
1564 Expression ex = interpret(s._body, istate);
1565 if (CTFEExp.isCantExp(ex))
1566 {
1567 result = ex;
1568 return;
1569 }
1570 while (CTFEExp.isGotoExp(ex))
1571 {
1572 // If the goto target is within the body, we must not interpret the finally statement,
1573 // because that will call destructors for objects within the scope, which we should not do.
1574 InterState istatex = *istate;
1575 istatex.start = istate.gotoTarget; // set starting statement
1576 istatex.gotoTarget = null;
1577 Expression bex = interpret(s._body, &istatex);
1578 if (istatex.start)
1579 {
1580 // The goto target is outside the current scope.
1581 break;
1582 }
1583 // The goto target was within the body.
1584 if (CTFEExp.isCantExp(bex))
1585 {
1586 result = bex;
1587 return;
1588 }
1589 *istate = istatex;
1590 ex = bex;
1591 }
1592
1593 Expression ey = interpret(s.finalbody, istate);
1594 if (CTFEExp.isCantExp(ey))
1595 {
1596 result = ey;
1597 return;
1598 }
1599 if (ey && ey.isThrownExceptionExp())
1600 {
1601 // Check for collided exceptions
1602 if (ex && ex.isThrownExceptionExp())
1603 ex = chainExceptions(ex.isThrownExceptionExp(), ey.isThrownExceptionExp());
1604 else
1605 ex = ey;
1606 }
1607 result = ex;
1608 }
1609
visit(ThrowStatement s)1610 override void visit(ThrowStatement s)
1611 {
1612 debug (LOG)
1613 {
1614 printf("%s ThrowStatement::interpret()\n", s.loc.toChars());
1615 }
1616 if (istate.start)
1617 {
1618 if (istate.start != s)
1619 return;
1620 istate.start = null;
1621 }
1622
1623 interpretThrow(s.exp, s.loc);
1624 }
1625
1626 /// Interpret `throw <exp>` found at the specified location `loc`
interpretThrow(Expression exp,const ref Loc loc)1627 private void interpretThrow(Expression exp, const ref Loc loc)
1628 {
1629 incUsageCtfe(istate, loc);
1630
1631 Expression e = interpretRegion(exp, istate);
1632 if (exceptionOrCant(e))
1633 return;
1634
1635 assert(e.op == EXP.classReference);
1636 result = ctfeEmplaceExp!ThrownExceptionExp(loc, e.isClassReferenceExp());
1637 }
1638
visit(ScopeGuardStatement s)1639 override void visit(ScopeGuardStatement s)
1640 {
1641 assert(0);
1642 }
1643
visit(WithStatement s)1644 override void visit(WithStatement s)
1645 {
1646 debug (LOG)
1647 {
1648 printf("%s WithStatement::interpret()\n", s.loc.toChars());
1649 }
1650 if (istate.start == s)
1651 istate.start = null;
1652 if (istate.start)
1653 {
1654 result = s._body ? interpret(s._body, istate) : null;
1655 return;
1656 }
1657
1658 // If it is with(Enum) {...}, just execute the body.
1659 if (s.exp.op == EXP.scope_ || s.exp.op == EXP.type)
1660 {
1661 result = interpret(pue, s._body, istate);
1662 return;
1663 }
1664
1665 incUsageCtfe(istate, s.loc);
1666
1667 Expression e = interpret(s.exp, istate);
1668 if (exceptionOrCant(e))
1669 return;
1670
1671 if (s.wthis.type.ty == Tpointer && s.exp.type.ty != Tpointer)
1672 {
1673 e = ctfeEmplaceExp!AddrExp(s.loc, e, s.wthis.type);
1674 }
1675 ctfeGlobals.stack.push(s.wthis);
1676 setValue(s.wthis, e);
1677 e = interpret(s._body, istate);
1678 if (CTFEExp.isGotoExp(e))
1679 {
1680 /* This is an optimization that relies on the locality of the jump target.
1681 * If the label is in the same WithStatement, the following scan
1682 * would find it quickly and can reduce jump cost.
1683 * Otherwise, the statement body may be unnnecessary scanned again
1684 * so it would make CTFE speed slower.
1685 */
1686 InterState istatex = *istate;
1687 istatex.start = istate.gotoTarget; // set starting statement
1688 istatex.gotoTarget = null;
1689 Expression ex = interpret(s._body, &istatex);
1690 if (!istatex.start)
1691 {
1692 istate.gotoTarget = null;
1693 e = ex;
1694 }
1695 }
1696 ctfeGlobals.stack.pop(s.wthis);
1697 result = e;
1698 }
1699
visit(AsmStatement s)1700 override void visit(AsmStatement s)
1701 {
1702 debug (LOG)
1703 {
1704 printf("%s AsmStatement::interpret()\n", s.loc.toChars());
1705 }
1706 if (istate.start)
1707 {
1708 if (istate.start != s)
1709 return;
1710 istate.start = null;
1711 }
1712 s.error("`asm` statements cannot be interpreted at compile time");
1713 result = CTFEExp.cantexp;
1714 }
1715
visit(ImportStatement s)1716 override void visit(ImportStatement s)
1717 {
1718 debug (LOG)
1719 {
1720 printf("ImportStatement::interpret()\n");
1721 }
1722 if (istate.start)
1723 {
1724 if (istate.start != s)
1725 return;
1726 istate.start = null;
1727 }
1728 }
1729
1730 /******************************** Expression ***************************/
1731
visit(Expression e)1732 override void visit(Expression e)
1733 {
1734 debug (LOG)
1735 {
1736 printf("%s Expression::interpret() '%s' %s\n", e.loc.toChars(), EXPtoString(e.op).ptr, e.toChars());
1737 printf("type = %s\n", e.type.toChars());
1738 showCtfeExpr(e);
1739 }
1740 e.error("cannot interpret `%s` at compile time", e.toChars());
1741 result = CTFEExp.cantexp;
1742 }
1743
visit(TypeExp e)1744 override void visit(TypeExp e)
1745 {
1746 debug (LOG)
1747 {
1748 printf("%s TypeExp.interpret() %s\n", e.loc.toChars(), e.toChars());
1749 }
1750 result = e;
1751 }
1752
visit(ThisExp e)1753 override void visit(ThisExp e)
1754 {
1755 debug (LOG)
1756 {
1757 printf("%s ThisExp::interpret() %s\n", e.loc.toChars(), e.toChars());
1758 }
1759 if (goal == CTFEGoal.LValue)
1760 {
1761 // We might end up here with istate being zero
1762 // https://issues.dlang.org/show_bug.cgi?id=16382
1763 if (istate && istate.fd.vthis)
1764 {
1765 result = ctfeEmplaceExp!VarExp(e.loc, istate.fd.vthis);
1766 if (istate.fd.hasDualContext())
1767 {
1768 result = ctfeEmplaceExp!PtrExp(e.loc, result);
1769 result.type = Type.tvoidptr.sarrayOf(2);
1770 result = ctfeEmplaceExp!IndexExp(e.loc, result, IntegerExp.literal!0);
1771 }
1772 result.type = e.type;
1773 }
1774 else
1775 result = e;
1776 return;
1777 }
1778
1779 result = ctfeGlobals.stack.getThis();
1780 if (result)
1781 {
1782 if (istate && istate.fd.hasDualContext())
1783 {
1784 assert(result.op == EXP.address);
1785 result = result.isAddrExp().e1;
1786 assert(result.op == EXP.arrayLiteral);
1787 result = (*result.isArrayLiteralExp().elements)[0];
1788 if (e.type.ty == Tstruct)
1789 {
1790 result = result.isAddrExp().e1;
1791 }
1792 return;
1793 }
1794 assert(result.op == EXP.structLiteral || result.op == EXP.classReference || result.op == EXP.type);
1795 return;
1796 }
1797 e.error("value of `this` is not known at compile time");
1798 result = CTFEExp.cantexp;
1799 }
1800
visit(NullExp e)1801 override void visit(NullExp e)
1802 {
1803 result = e;
1804 }
1805
visit(IntegerExp e)1806 override void visit(IntegerExp e)
1807 {
1808 debug (LOG)
1809 {
1810 printf("%s IntegerExp::interpret() %s\n", e.loc.toChars(), e.toChars());
1811 }
1812 result = e;
1813 }
1814
visit(RealExp e)1815 override void visit(RealExp e)
1816 {
1817 debug (LOG)
1818 {
1819 printf("%s RealExp::interpret() %s\n", e.loc.toChars(), e.toChars());
1820 }
1821 result = e;
1822 }
1823
visit(ComplexExp e)1824 override void visit(ComplexExp e)
1825 {
1826 result = e;
1827 }
1828
visit(StringExp e)1829 override void visit(StringExp e)
1830 {
1831 debug (LOG)
1832 {
1833 printf("%s StringExp::interpret() %s\n", e.loc.toChars(), e.toChars());
1834 }
1835 /* Attempts to modify string literals are prevented
1836 * in BinExp::interpretAssignCommon.
1837 */
1838 result = e;
1839 }
1840
visit(FuncExp e)1841 override void visit(FuncExp e)
1842 {
1843 debug (LOG)
1844 {
1845 printf("%s FuncExp::interpret() %s\n", e.loc.toChars(), e.toChars());
1846 }
1847 result = e;
1848 }
1849
visit(SymOffExp e)1850 override void visit(SymOffExp e)
1851 {
1852 debug (LOG)
1853 {
1854 printf("%s SymOffExp::interpret() %s\n", e.loc.toChars(), e.toChars());
1855 }
1856 if (e.var.isFuncDeclaration() && e.offset == 0)
1857 {
1858 result = e;
1859 return;
1860 }
1861 if (isTypeInfo_Class(e.type) && e.offset == 0)
1862 {
1863 result = e;
1864 return;
1865 }
1866 if (e.type.ty != Tpointer)
1867 {
1868 // Probably impossible
1869 e.error("cannot interpret `%s` at compile time", e.toChars());
1870 result = CTFEExp.cantexp;
1871 return;
1872 }
1873 Type pointee = (cast(TypePointer)e.type).next;
1874 if (e.var.isThreadlocal())
1875 {
1876 e.error("cannot take address of thread-local variable %s at compile time", e.var.toChars());
1877 result = CTFEExp.cantexp;
1878 return;
1879 }
1880 // Check for taking an address of a shared variable.
1881 // If the shared variable is an array, the offset might not be zero.
1882 Type fromType = null;
1883 if (e.var.type.ty == Tarray || e.var.type.ty == Tsarray)
1884 {
1885 fromType = (cast(TypeArray)e.var.type).next;
1886 }
1887 if (e.var.isDataseg() && ((e.offset == 0 && isSafePointerCast(e.var.type, pointee)) ||
1888 (fromType && isSafePointerCast(fromType, pointee)) ||
1889 (e.var.isCsymbol() && e.offset + pointee.size() <= e.var.type.size())))
1890 {
1891 result = e;
1892 return;
1893 }
1894
1895 Expression val = getVarExp(e.loc, istate, e.var, goal);
1896 if (exceptionOrCant(val))
1897 return;
1898 if (val.type.ty == Tarray || val.type.ty == Tsarray)
1899 {
1900 // Check for unsupported type painting operations
1901 Type elemtype = (cast(TypeArray)val.type).next;
1902 const elemsize = elemtype.size();
1903
1904 // It's OK to cast from fixed length to fixed length array, eg &int[n] to int[d]*.
1905 if (val.type.ty == Tsarray && pointee.ty == Tsarray && elemsize == pointee.nextOf().size())
1906 {
1907 size_t d = cast(size_t)(cast(TypeSArray)pointee).dim.toInteger();
1908 Expression elwr = ctfeEmplaceExp!IntegerExp(e.loc, e.offset / elemsize, Type.tsize_t);
1909 Expression eupr = ctfeEmplaceExp!IntegerExp(e.loc, e.offset / elemsize + d, Type.tsize_t);
1910
1911 // Create a CTFE pointer &val[ofs..ofs+d]
1912 auto se = ctfeEmplaceExp!SliceExp(e.loc, val, elwr, eupr);
1913 se.type = pointee;
1914 emplaceExp!(AddrExp)(pue, e.loc, se, e.type);
1915 result = pue.exp();
1916 return;
1917 }
1918
1919 if (!isSafePointerCast(elemtype, pointee))
1920 {
1921 // It's also OK to cast from &string to string*.
1922 if (e.offset == 0 && isSafePointerCast(e.var.type, pointee))
1923 {
1924 // Create a CTFE pointer &var
1925 auto ve = ctfeEmplaceExp!VarExp(e.loc, e.var);
1926 ve.type = elemtype;
1927 emplaceExp!(AddrExp)(pue, e.loc, ve, e.type);
1928 result = pue.exp();
1929 return;
1930 }
1931 e.error("reinterpreting cast from `%s` to `%s` is not supported in CTFE", val.type.toChars(), e.type.toChars());
1932 result = CTFEExp.cantexp;
1933 return;
1934 }
1935
1936 const dinteger_t sz = pointee.size();
1937 dinteger_t indx = e.offset / sz;
1938 assert(sz * indx == e.offset);
1939 Expression aggregate = null;
1940 if (val.op == EXP.arrayLiteral || val.op == EXP.string_)
1941 {
1942 aggregate = val;
1943 }
1944 else if (auto se = val.isSliceExp())
1945 {
1946 aggregate = se.e1;
1947 UnionExp uelwr = void;
1948 Expression lwr = interpret(&uelwr, se.lwr, istate);
1949 indx += lwr.toInteger();
1950 }
1951 if (aggregate)
1952 {
1953 // Create a CTFE pointer &aggregate[ofs]
1954 auto ofs = ctfeEmplaceExp!IntegerExp(e.loc, indx, Type.tsize_t);
1955 auto ei = ctfeEmplaceExp!IndexExp(e.loc, aggregate, ofs);
1956 ei.type = elemtype;
1957 emplaceExp!(AddrExp)(pue, e.loc, ei, e.type);
1958 result = pue.exp();
1959 return;
1960 }
1961 }
1962 else if (e.offset == 0 && isSafePointerCast(e.var.type, pointee))
1963 {
1964 // Create a CTFE pointer &var
1965 auto ve = ctfeEmplaceExp!VarExp(e.loc, e.var);
1966 ve.type = e.var.type;
1967 emplaceExp!(AddrExp)(pue, e.loc, ve, e.type);
1968 result = pue.exp();
1969 return;
1970 }
1971
1972 e.error("cannot convert `&%s` to `%s` at compile time", e.var.type.toChars(), e.type.toChars());
1973 result = CTFEExp.cantexp;
1974 }
1975
visit(AddrExp e)1976 override void visit(AddrExp e)
1977 {
1978 debug (LOG)
1979 {
1980 printf("%s AddrExp::interpret() %s\n", e.loc.toChars(), e.toChars());
1981 }
1982 if (auto ve = e.e1.isVarExp())
1983 {
1984 Declaration decl = ve.var;
1985
1986 // We cannot take the address of an imported symbol at compile time
1987 if (decl.isImportedSymbol()) {
1988 e.error("cannot take address of imported symbol `%s` at compile time", decl.toChars());
1989 result = CTFEExp.cantexp;
1990 return;
1991 }
1992
1993 if (decl.isDataseg()) {
1994 // Normally this is already done by optimize()
1995 // Do it here in case optimize(WANTvalue) wasn't run before CTFE
1996 emplaceExp!(SymOffExp)(pue, e.loc, e.e1.isVarExp().var, 0);
1997 result = pue.exp();
1998 result.type = e.type;
1999 return;
2000 }
2001 }
2002 auto er = interpret(e.e1, istate, CTFEGoal.LValue);
2003 if (auto ve = er.isVarExp())
2004 if (ve.var == istate.fd.vthis)
2005 er = interpret(er, istate);
2006
2007 if (exceptionOrCant(er))
2008 return;
2009
2010 // Return a simplified address expression
2011 emplaceExp!(AddrExp)(pue, e.loc, er, e.type);
2012 result = pue.exp();
2013 }
2014
visit(DelegateExp e)2015 override void visit(DelegateExp e)
2016 {
2017 debug (LOG)
2018 {
2019 printf("%s DelegateExp::interpret() %s\n", e.loc.toChars(), e.toChars());
2020 }
2021 // TODO: Really we should create a CTFE-only delegate expression
2022 // of a pointer and a funcptr.
2023
2024 // If it is &nestedfunc, just return it
2025 // TODO: We should save the context pointer
2026 if (auto ve1 = e.e1.isVarExp())
2027 if (ve1.var == e.func)
2028 {
2029 result = e;
2030 return;
2031 }
2032
2033 auto er = interpret(pue, e.e1, istate);
2034 if (exceptionOrCant(er))
2035 return;
2036 if (er == e.e1)
2037 {
2038 // If it has already been CTFE'd, just return it
2039 result = e;
2040 }
2041 else
2042 {
2043 er = (er == pue.exp()) ? pue.copy() : er;
2044 emplaceExp!(DelegateExp)(pue, e.loc, er, e.func, false);
2045 result = pue.exp();
2046 result.type = e.type;
2047 }
2048 }
2049
getVarExp(const ref Loc loc,InterState * istate,Declaration d,CTFEGoal goal)2050 static Expression getVarExp(const ref Loc loc, InterState* istate, Declaration d, CTFEGoal goal)
2051 {
2052 Expression e = CTFEExp.cantexp;
2053 if (VarDeclaration v = d.isVarDeclaration())
2054 {
2055 /* Magic variable __ctfe always returns true when interpreting
2056 */
2057 if (v.ident == Id.ctfe)
2058 return IntegerExp.createBool(true);
2059
2060 if (!v.originalType && v.semanticRun < PASS.semanticdone) // semantic() not yet run
2061 {
2062 v.dsymbolSemantic(null);
2063 if (v.type.ty == Terror)
2064 return CTFEExp.cantexp;
2065 }
2066
2067 if ((v.isConst() || v.isImmutable() || v.storage_class & STC.manifest) && !hasValue(v) && v._init && !v.isCTFE())
2068 {
2069 if (v.inuse)
2070 {
2071 error(loc, "circular initialization of %s `%s`", v.kind(), v.toPrettyChars());
2072 return CTFEExp.cantexp;
2073 }
2074 if (v._scope)
2075 {
2076 v.inuse++;
2077 v._init = v._init.initializerSemantic(v._scope, v.type, INITinterpret); // might not be run on aggregate members
2078 v.inuse--;
2079 }
2080 e = v._init.initializerToExpression(v.type);
2081 if (!e)
2082 return CTFEExp.cantexp;
2083 assert(e.type);
2084
2085 if (e.op == EXP.construct || e.op == EXP.blit)
2086 {
2087 AssignExp ae = cast(AssignExp)e;
2088 e = ae.e2;
2089 }
2090
2091 if (e.op == EXP.error)
2092 {
2093 // FIXME: Ultimately all errors should be detected in prior semantic analysis stage.
2094 }
2095 else if (v.isDataseg() || (v.storage_class & STC.manifest))
2096 {
2097 /* https://issues.dlang.org/show_bug.cgi?id=14304
2098 * e is a value that is not yet owned by CTFE.
2099 * Mark as "cached", and use it directly during interpretation.
2100 */
2101 e = scrubCacheValue(e);
2102 ctfeGlobals.stack.saveGlobalConstant(v, e);
2103 }
2104 else
2105 {
2106 v.inuse++;
2107 e = interpret(e, istate);
2108 v.inuse--;
2109 if (CTFEExp.isCantExp(e) && !global.gag && !ctfeGlobals.stackTraceCallsToSuppress)
2110 errorSupplemental(loc, "while evaluating %s.init", v.toChars());
2111 if (exceptionOrCantInterpret(e))
2112 return e;
2113 }
2114 }
2115 else if (v.isCTFE() && !hasValue(v))
2116 {
2117 if (v._init && v.type.size() != 0)
2118 {
2119 if (v._init.isVoidInitializer())
2120 {
2121 // var should have been initialized when it was created
2122 error(loc, "CTFE internal error: trying to access uninitialized var");
2123 assert(0);
2124 }
2125 e = v._init.initializerToExpression();
2126 }
2127 else
2128 // Zero-length arrays don't have an initializer
2129 e = v.type.defaultInitLiteral(e.loc);
2130
2131 e = interpret(e, istate);
2132 }
2133 else if (!(v.isDataseg() || v.storage_class & STC.manifest) && !v.isCTFE() && !istate)
2134 {
2135 error(loc, "variable `%s` cannot be read at compile time", v.toChars());
2136 return CTFEExp.cantexp;
2137 }
2138 else
2139 {
2140 e = hasValue(v) ? getValue(v) : null;
2141 if (!e)
2142 {
2143 // Zero-length arrays don't have an initializer
2144 if (v.type.size() == 0)
2145 e = v.type.defaultInitLiteral(loc);
2146 else if (!v.isCTFE() && v.isDataseg())
2147 {
2148 error(loc, "static variable `%s` cannot be read at compile time", v.toChars());
2149 return CTFEExp.cantexp;
2150 }
2151 else
2152 {
2153 assert(!(v._init && v._init.isVoidInitializer()));
2154 // CTFE initiated from inside a function
2155 error(loc, "variable `%s` cannot be read at compile time", v.toChars());
2156 return CTFEExp.cantexp;
2157 }
2158 }
2159 if (auto vie = e.isVoidInitExp())
2160 {
2161 error(loc, "cannot read uninitialized variable `%s` in ctfe", v.toPrettyChars());
2162 errorSupplemental(vie.var.loc, "`%s` was uninitialized and used before set", vie.var.toChars());
2163 return CTFEExp.cantexp;
2164 }
2165 if (goal != CTFEGoal.LValue && v.isReference())
2166 e = interpret(e, istate, goal);
2167 }
2168 if (!e)
2169 e = CTFEExp.cantexp;
2170 }
2171 else if (SymbolDeclaration s = d.isSymbolDeclaration())
2172 {
2173 // exclude void[]-typed `__traits(initSymbol)`
2174 if (auto ta = s.type.toBasetype().isTypeDArray())
2175 {
2176 assert(ta.next.ty == Tvoid);
2177 error(loc, "cannot determine the address of the initializer symbol during CTFE");
2178 return CTFEExp.cantexp;
2179 }
2180
2181 // Struct static initializers, for example
2182 e = s.dsym.type.defaultInitLiteral(loc);
2183 if (e.op == EXP.error)
2184 error(loc, "CTFE failed because of previous errors in `%s.init`", s.toChars());
2185 e = e.expressionSemantic(null);
2186 if (e.op == EXP.error)
2187 e = CTFEExp.cantexp;
2188 else // Convert NULL to CTFEExp
2189 e = interpret(e, istate, goal);
2190 }
2191 else
2192 error(loc, "cannot interpret declaration `%s` at compile time", d.toChars());
2193 return e;
2194 }
2195
visit(VarExp e)2196 override void visit(VarExp e)
2197 {
2198 debug (LOG)
2199 {
2200 printf("%s VarExp::interpret() `%s`, goal = %d\n", e.loc.toChars(), e.toChars(), goal);
2201 }
2202 if (e.var.isFuncDeclaration())
2203 {
2204 result = e;
2205 return;
2206 }
2207
2208 if (goal == CTFEGoal.LValue)
2209 {
2210 if (auto v = e.var.isVarDeclaration())
2211 {
2212 if (!hasValue(v))
2213 {
2214 // Compile-time known non-CTFE variable from an outer context
2215 // e.g. global or from a ref argument
2216 if (v.isConst() || v.isImmutable())
2217 {
2218 result = getVarExp(e.loc, istate, v, goal);
2219 return;
2220 }
2221
2222 if (!v.isCTFE() && v.isDataseg())
2223 e.error("static variable `%s` cannot be read at compile time", v.toChars());
2224 else // CTFE initiated from inside a function
2225 e.error("variable `%s` cannot be read at compile time", v.toChars());
2226 result = CTFEExp.cantexp;
2227 return;
2228 }
2229
2230 if (v.storage_class & (STC.out_ | STC.ref_))
2231 {
2232 // Strip off the nest of ref variables
2233 Expression ev = getValue(v);
2234 if (ev.op == EXP.variable ||
2235 ev.op == EXP.index ||
2236 (ev.op == EXP.slice && ev.type.toBasetype().ty == Tsarray) ||
2237 ev.op == EXP.dotVariable)
2238 {
2239 result = interpret(pue, ev, istate, goal);
2240 return;
2241 }
2242 }
2243 }
2244 result = e;
2245 return;
2246 }
2247 result = getVarExp(e.loc, istate, e.var, goal);
2248 if (exceptionOrCant(result))
2249 return;
2250
2251 // Visit the default initializer for noreturn variables
2252 // (Custom initializers would abort the current function call and exit above)
2253 if (result.type.ty == Tnoreturn)
2254 {
2255 result.accept(this);
2256 return;
2257 }
2258
2259 if ((e.var.storage_class & (STC.ref_ | STC.out_)) == 0 && e.type.baseElemOf().ty != Tstruct)
2260 {
2261 /* Ultimately, STC.ref_|STC.out_ check should be enough to see the
2262 * necessity of type repainting. But currently front-end paints
2263 * non-ref struct variables by the const type.
2264 *
2265 * auto foo(ref const S cs);
2266 * S s;
2267 * foo(s); // VarExp('s') will have const(S)
2268 */
2269 // A VarExp may include an implicit cast. It must be done explicitly.
2270 result = paintTypeOntoLiteral(pue, e.type, result);
2271 }
2272 }
2273
visit(DeclarationExp e)2274 override void visit(DeclarationExp e)
2275 {
2276 debug (LOG)
2277 {
2278 printf("%s DeclarationExp::interpret() %s\n", e.loc.toChars(), e.toChars());
2279 }
2280 Dsymbol s = e.declaration;
2281 while (s.isAttribDeclaration())
2282 {
2283 auto ad = cast(AttribDeclaration)s;
2284 assert(ad.decl && ad.decl.dim == 1); // Currently, only one allowed when parsing
2285 s = (*ad.decl)[0];
2286 }
2287 if (VarDeclaration v = s.isVarDeclaration())
2288 {
2289 if (TupleDeclaration td = v.toAlias().isTupleDeclaration())
2290 {
2291 result = null;
2292
2293 // Reserve stack space for all tuple members
2294 td.foreachVar((s)
2295 {
2296 VarDeclaration v2 = s.isVarDeclaration();
2297 assert(v2);
2298 if (v2.isDataseg() && !v2.isCTFE())
2299 return 0;
2300
2301 ctfeGlobals.stack.push(v2);
2302 if (v2._init)
2303 {
2304 Expression einit;
2305 if (ExpInitializer ie = v2._init.isExpInitializer())
2306 {
2307 einit = interpretRegion(ie.exp, istate, goal);
2308 if (exceptionOrCant(einit))
2309 return 1;
2310 }
2311 else if (v2._init.isVoidInitializer())
2312 {
2313 einit = voidInitLiteral(v2.type, v2).copy();
2314 }
2315 else
2316 {
2317 e.error("declaration `%s` is not yet implemented in CTFE", e.toChars());
2318 result = CTFEExp.cantexp;
2319 return 1;
2320 }
2321 setValue(v2, einit);
2322 }
2323 return 0;
2324 });
2325 return;
2326 }
2327 if (v.isStatic())
2328 {
2329 // Just ignore static variables which aren't read or written yet
2330 result = null;
2331 return;
2332 }
2333 if (!(v.isDataseg() || v.storage_class & STC.manifest) || v.isCTFE())
2334 ctfeGlobals.stack.push(v);
2335 if (v._init)
2336 {
2337 if (ExpInitializer ie = v._init.isExpInitializer())
2338 {
2339 result = interpretRegion(ie.exp, istate, goal);
2340 }
2341 else if (v._init.isVoidInitializer())
2342 {
2343 result = voidInitLiteral(v.type, v).copy();
2344 // There is no AssignExp for void initializers,
2345 // so set it here.
2346 setValue(v, result);
2347 }
2348 else
2349 {
2350 e.error("declaration `%s` is not yet implemented in CTFE", e.toChars());
2351 result = CTFEExp.cantexp;
2352 }
2353 }
2354 else if (v.type.size() == 0)
2355 {
2356 // Zero-length arrays don't need an initializer
2357 result = v.type.defaultInitLiteral(e.loc);
2358 }
2359 else
2360 {
2361 e.error("variable `%s` cannot be modified at compile time", v.toChars());
2362 result = CTFEExp.cantexp;
2363 }
2364 return;
2365 }
2366 if (s.isTemplateMixin() || s.isTupleDeclaration())
2367 {
2368 // These can be made to work, too lazy now
2369 e.error("declaration `%s` is not yet implemented in CTFE", e.toChars());
2370 result = CTFEExp.cantexp;
2371 return;
2372 }
2373
2374 // Others should not contain executable code, so are trivial to evaluate
2375 result = null;
2376 debug (LOG)
2377 {
2378 printf("-DeclarationExp::interpret(%s): %p\n", e.toChars(), result);
2379 }
2380 }
2381
visit(TypeidExp e)2382 override void visit(TypeidExp e)
2383 {
2384 debug (LOG)
2385 {
2386 printf("%s TypeidExp::interpret() %s\n", e.loc.toChars(), e.toChars());
2387 }
2388 if (Type t = isType(e.obj))
2389 {
2390 result = e;
2391 return;
2392 }
2393 if (Expression ex = isExpression(e.obj))
2394 {
2395 result = interpret(pue, ex, istate);
2396 if (exceptionOrCant(ex))
2397 return;
2398
2399 if (result.op == EXP.null_)
2400 {
2401 e.error("null pointer dereference evaluating typeid. `%s` is `null`", ex.toChars());
2402 result = CTFEExp.cantexp;
2403 return;
2404 }
2405 if (result.op != EXP.classReference)
2406 {
2407 e.error("CTFE internal error: determining classinfo");
2408 result = CTFEExp.cantexp;
2409 return;
2410 }
2411
2412 ClassDeclaration cd = result.isClassReferenceExp().originalClass();
2413 assert(cd);
2414
2415 emplaceExp!(TypeidExp)(pue, e.loc, cd.type);
2416 result = pue.exp();
2417 result.type = e.type;
2418 return;
2419 }
2420 visit(cast(Expression)e);
2421 }
2422
visit(TupleExp e)2423 override void visit(TupleExp e)
2424 {
2425 debug (LOG)
2426 {
2427 printf("%s TupleExp::interpret() %s\n", e.loc.toChars(), e.toChars());
2428 }
2429 if (exceptionOrCant(interpretRegion(e.e0, istate, CTFEGoal.Nothing)))
2430 return;
2431
2432 auto expsx = e.exps;
2433 foreach (i, exp; *expsx)
2434 {
2435 Expression ex = interpretRegion(exp, istate);
2436 if (exceptionOrCant(ex))
2437 return;
2438
2439 // A tuple of assignments can contain void (Bug 5676).
2440 if (goal == CTFEGoal.Nothing)
2441 continue;
2442 if (ex.op == EXP.voidExpression)
2443 {
2444 e.error("CTFE internal error: void element `%s` in tuple", exp.toChars());
2445 assert(0);
2446 }
2447
2448 /* If any changes, do Copy On Write
2449 */
2450 if (ex !is exp)
2451 {
2452 expsx = copyArrayOnWrite(expsx, e.exps);
2453 (*expsx)[i] = copyRegionExp(ex);
2454 }
2455 }
2456
2457 if (expsx !is e.exps)
2458 {
2459 expandTuples(expsx);
2460 emplaceExp!(TupleExp)(pue, e.loc, expsx);
2461 result = pue.exp();
2462 result.type = new TypeTuple(expsx);
2463 }
2464 else
2465 result = e;
2466 }
2467
visit(ArrayLiteralExp e)2468 override void visit(ArrayLiteralExp e)
2469 {
2470 debug (LOG)
2471 {
2472 printf("%s ArrayLiteralExp::interpret() %s\n", e.loc.toChars(), e.toChars());
2473 }
2474 if (e.ownedByCtfe >= OwnedBy.ctfe) // We've already interpreted all the elements
2475 {
2476 result = e;
2477 return;
2478 }
2479
2480 Type tn = e.type.toBasetype().nextOf().toBasetype();
2481 bool wantCopy = (tn.ty == Tsarray || tn.ty == Tstruct);
2482
2483 auto basis = interpretRegion(e.basis, istate);
2484 if (exceptionOrCant(basis))
2485 return;
2486
2487 auto expsx = e.elements;
2488 size_t dim = expsx ? expsx.dim : 0;
2489 for (size_t i = 0; i < dim; i++)
2490 {
2491 Expression exp = (*expsx)[i];
2492 Expression ex;
2493 if (!exp)
2494 {
2495 ex = copyLiteral(basis).copy();
2496 }
2497 else
2498 {
2499 // segfault bug 6250
2500 assert(exp.op != EXP.index || exp.isIndexExp().e1 != e);
2501
2502 ex = interpretRegion(exp, istate);
2503 if (exceptionOrCant(ex))
2504 return;
2505
2506 /* Each elements should have distinct CTFE memory.
2507 * int[1] z = 7;
2508 * int[1][] pieces = [z,z]; // here
2509 */
2510 if (wantCopy)
2511 ex = copyLiteral(ex).copy();
2512 }
2513
2514 /* If any changes, do Copy On Write
2515 */
2516 if (ex !is exp)
2517 {
2518 expsx = copyArrayOnWrite(expsx, e.elements);
2519 (*expsx)[i] = ex;
2520 }
2521 }
2522
2523 if (expsx !is e.elements)
2524 {
2525 // todo: all tuple expansions should go in semantic phase.
2526 expandTuples(expsx);
2527 if (expsx.dim != dim)
2528 {
2529 e.error("CTFE internal error: invalid array literal");
2530 result = CTFEExp.cantexp;
2531 return;
2532 }
2533 emplaceExp!(ArrayLiteralExp)(pue, e.loc, e.type, basis, expsx);
2534 auto ale = pue.exp().isArrayLiteralExp();
2535 ale.ownedByCtfe = OwnedBy.ctfe;
2536 result = ale;
2537 }
2538 else if ((cast(TypeNext)e.type).next.mod & (MODFlags.const_ | MODFlags.immutable_))
2539 {
2540 // If it's immutable, we don't need to dup it
2541 result = e;
2542 }
2543 else
2544 {
2545 *pue = copyLiteral(e);
2546 result = pue.exp();
2547 }
2548 }
2549
visit(AssocArrayLiteralExp e)2550 override void visit(AssocArrayLiteralExp e)
2551 {
2552 debug (LOG)
2553 {
2554 printf("%s AssocArrayLiteralExp::interpret() %s\n", e.loc.toChars(), e.toChars());
2555 }
2556 if (e.ownedByCtfe >= OwnedBy.ctfe) // We've already interpreted all the elements
2557 {
2558 result = e;
2559 return;
2560 }
2561
2562 auto keysx = e.keys;
2563 auto valuesx = e.values;
2564 foreach (i, ekey; *keysx)
2565 {
2566 auto evalue = (*valuesx)[i];
2567
2568 auto ek = interpretRegion(ekey, istate);
2569 if (exceptionOrCant(ek))
2570 return;
2571 auto ev = interpretRegion(evalue, istate);
2572 if (exceptionOrCant(ev))
2573 return;
2574
2575 /* If any changes, do Copy On Write
2576 */
2577 if (ek !is ekey ||
2578 ev !is evalue)
2579 {
2580 keysx = copyArrayOnWrite(keysx, e.keys);
2581 valuesx = copyArrayOnWrite(valuesx, e.values);
2582 (*keysx)[i] = ek;
2583 (*valuesx)[i] = ev;
2584 }
2585 }
2586 if (keysx !is e.keys)
2587 expandTuples(keysx);
2588 if (valuesx !is e.values)
2589 expandTuples(valuesx);
2590 if (keysx.dim != valuesx.dim)
2591 {
2592 e.error("CTFE internal error: invalid AA");
2593 result = CTFEExp.cantexp;
2594 return;
2595 }
2596
2597 /* Remove duplicate keys
2598 */
2599 for (size_t i = 1; i < keysx.dim; i++)
2600 {
2601 auto ekey = (*keysx)[i - 1];
2602 for (size_t j = i; j < keysx.dim; j++)
2603 {
2604 auto ekey2 = (*keysx)[j];
2605 if (!ctfeEqual(e.loc, EXP.equal, ekey, ekey2))
2606 continue;
2607
2608 // Remove ekey
2609 keysx = copyArrayOnWrite(keysx, e.keys);
2610 valuesx = copyArrayOnWrite(valuesx, e.values);
2611 keysx.remove(i - 1);
2612 valuesx.remove(i - 1);
2613
2614 i -= 1; // redo the i'th iteration
2615 break;
2616 }
2617 }
2618
2619 if (keysx !is e.keys ||
2620 valuesx !is e.values)
2621 {
2622 assert(keysx !is e.keys &&
2623 valuesx !is e.values);
2624 auto aae = ctfeEmplaceExp!AssocArrayLiteralExp(e.loc, keysx, valuesx);
2625 aae.type = e.type;
2626 aae.ownedByCtfe = OwnedBy.ctfe;
2627 result = aae;
2628 }
2629 else
2630 {
2631 *pue = copyLiteral(e);
2632 result = pue.exp();
2633 }
2634 }
2635
visit(StructLiteralExp e)2636 override void visit(StructLiteralExp e)
2637 {
2638 debug (LOG)
2639 {
2640 printf("%s StructLiteralExp::interpret() %s ownedByCtfe = %d\n", e.loc.toChars(), e.toChars(), e.ownedByCtfe);
2641 }
2642 if (e.ownedByCtfe >= OwnedBy.ctfe)
2643 {
2644 result = e;
2645 return;
2646 }
2647
2648 size_t dim = e.elements ? e.elements.dim : 0;
2649 auto expsx = e.elements;
2650
2651 if (dim != e.sd.fields.dim)
2652 {
2653 // guaranteed by AggregateDeclaration.fill and TypeStruct.defaultInitLiteral
2654 const nvthis = e.sd.fields.dim - e.sd.nonHiddenFields();
2655 assert(e.sd.fields.dim - dim == nvthis);
2656
2657 /* If a nested struct has no initialized hidden pointer,
2658 * set it to null to match the runtime behaviour.
2659 */
2660 foreach (const i; 0 .. nvthis)
2661 {
2662 auto ne = ctfeEmplaceExp!NullExp(e.loc);
2663 auto vthis = i == 0 ? e.sd.vthis : e.sd.vthis2;
2664 ne.type = vthis.type;
2665
2666 expsx = copyArrayOnWrite(expsx, e.elements);
2667 expsx.push(ne);
2668 ++dim;
2669 }
2670 }
2671 assert(dim == e.sd.fields.dim);
2672
2673 foreach (i; 0 .. dim)
2674 {
2675 auto v = e.sd.fields[i];
2676 Expression exp = (*expsx)[i];
2677 Expression ex;
2678 if (!exp)
2679 {
2680 ex = voidInitLiteral(v.type, v).copy();
2681 }
2682 else
2683 {
2684 ex = interpretRegion(exp, istate);
2685 if (exceptionOrCant(ex))
2686 return;
2687 if ((v.type.ty != ex.type.ty) && v.type.ty == Tsarray)
2688 {
2689 // Block assignment from inside struct literals
2690 auto tsa = cast(TypeSArray)v.type;
2691 auto len = cast(size_t)tsa.dim.toInteger();
2692 UnionExp ue = void;
2693 ex = createBlockDuplicatedArrayLiteral(&ue, ex.loc, v.type, ex, len);
2694 if (ex == ue.exp())
2695 ex = ue.copy();
2696 }
2697 }
2698
2699 /* If any changes, do Copy On Write
2700 */
2701 if (ex !is exp)
2702 {
2703 expsx = copyArrayOnWrite(expsx, e.elements);
2704 (*expsx)[i] = ex;
2705 }
2706 }
2707
2708 if (expsx !is e.elements)
2709 {
2710 expandTuples(expsx);
2711 if (expsx.dim != e.sd.fields.dim)
2712 {
2713 e.error("CTFE internal error: invalid struct literal");
2714 result = CTFEExp.cantexp;
2715 return;
2716 }
2717 emplaceExp!(StructLiteralExp)(pue, e.loc, e.sd, expsx);
2718 auto sle = pue.exp().isStructLiteralExp();
2719 sle.type = e.type;
2720 sle.ownedByCtfe = OwnedBy.ctfe;
2721 sle.origin = e.origin;
2722 result = sle;
2723 }
2724 else
2725 {
2726 *pue = copyLiteral(e);
2727 result = pue.exp();
2728 }
2729 }
2730
2731 // Create an array literal of type 'newtype' with dimensions given by
2732 // 'arguments'[argnum..$]
recursivelyCreateArrayLiteral(UnionExp * pue,const ref Loc loc,Type newtype,InterState * istate,Expressions * arguments,int argnum)2733 static Expression recursivelyCreateArrayLiteral(UnionExp* pue, const ref Loc loc, Type newtype, InterState* istate, Expressions* arguments, int argnum)
2734 {
2735 Expression lenExpr = interpret(pue, (*arguments)[argnum], istate);
2736 if (exceptionOrCantInterpret(lenExpr))
2737 return lenExpr;
2738 size_t len = cast(size_t)lenExpr.toInteger();
2739 Type elemType = (cast(TypeArray)newtype).next;
2740 if (elemType.ty == Tarray && argnum < arguments.dim - 1)
2741 {
2742 Expression elem = recursivelyCreateArrayLiteral(pue, loc, elemType, istate, arguments, argnum + 1);
2743 if (exceptionOrCantInterpret(elem))
2744 return elem;
2745
2746 auto elements = new Expressions(len);
2747 foreach (ref element; *elements)
2748 element = copyLiteral(elem).copy();
2749 emplaceExp!(ArrayLiteralExp)(pue, loc, newtype, elements);
2750 auto ae = pue.exp().isArrayLiteralExp();
2751 ae.ownedByCtfe = OwnedBy.ctfe;
2752 return ae;
2753 }
2754 assert(argnum == arguments.dim - 1);
2755 if (elemType.ty.isSomeChar)
2756 {
2757 const ch = cast(dchar)elemType.defaultInitLiteral(loc).toInteger();
2758 const sz = cast(ubyte)elemType.size();
2759 return createBlockDuplicatedStringLiteral(pue, loc, newtype, ch, len, sz);
2760 }
2761 else
2762 {
2763 auto el = interpret(elemType.defaultInitLiteral(loc), istate);
2764 return createBlockDuplicatedArrayLiteral(pue, loc, newtype, el, len);
2765 }
2766 }
2767
visit(NewExp e)2768 override void visit(NewExp e)
2769 {
2770 debug (LOG)
2771 {
2772 printf("%s NewExp::interpret() %s\n", e.loc.toChars(), e.toChars());
2773 }
2774
2775 Expression epre = interpret(pue, e.argprefix, istate, CTFEGoal.Nothing);
2776 if (exceptionOrCant(epre))
2777 return;
2778
2779 if (e.newtype.ty == Tarray && e.arguments)
2780 {
2781 result = recursivelyCreateArrayLiteral(pue, e.loc, e.newtype, istate, e.arguments, 0);
2782 return;
2783 }
2784 if (auto ts = e.newtype.toBasetype().isTypeStruct())
2785 {
2786 if (e.member)
2787 {
2788 Expression se = e.newtype.defaultInitLiteral(e.loc);
2789 se = interpret(se, istate);
2790 if (exceptionOrCant(se))
2791 return;
2792 result = interpretFunction(pue, e.member, istate, e.arguments, se);
2793
2794 // Repaint as same as CallExp::interpret() does.
2795 result.loc = e.loc;
2796 }
2797 else
2798 {
2799 StructDeclaration sd = ts.sym;
2800 auto exps = new Expressions();
2801 exps.reserve(sd.fields.dim);
2802 if (e.arguments)
2803 {
2804 exps.setDim(e.arguments.dim);
2805 foreach (i, ex; *e.arguments)
2806 {
2807 ex = interpretRegion(ex, istate);
2808 if (exceptionOrCant(ex))
2809 return;
2810 (*exps)[i] = ex;
2811 }
2812 }
2813 sd.fill(e.loc, exps, false);
2814
2815 auto se = ctfeEmplaceExp!StructLiteralExp(e.loc, sd, exps, e.newtype);
2816 se.origin = se;
2817 se.type = e.newtype;
2818 se.ownedByCtfe = OwnedBy.ctfe;
2819 result = interpret(pue, se, istate);
2820 }
2821 if (exceptionOrCant(result))
2822 return;
2823 Expression ev = (result == pue.exp()) ? pue.copy() : result;
2824 emplaceExp!(AddrExp)(pue, e.loc, ev, e.type);
2825 result = pue.exp();
2826 return;
2827 }
2828 if (auto tc = e.newtype.toBasetype().isTypeClass())
2829 {
2830 ClassDeclaration cd = tc.sym;
2831 size_t totalFieldCount = 0;
2832 for (ClassDeclaration c = cd; c; c = c.baseClass)
2833 totalFieldCount += c.fields.dim;
2834 auto elems = new Expressions(totalFieldCount);
2835 size_t fieldsSoFar = totalFieldCount;
2836 for (ClassDeclaration c = cd; c; c = c.baseClass)
2837 {
2838 fieldsSoFar -= c.fields.dim;
2839 foreach (i, v; c.fields)
2840 {
2841 if (v.inuse)
2842 {
2843 e.error("circular reference to `%s`", v.toPrettyChars());
2844 result = CTFEExp.cantexp;
2845 return;
2846 }
2847 Expression m;
2848 if (v._init)
2849 {
2850 if (v._init.isVoidInitializer())
2851 m = voidInitLiteral(v.type, v).copy();
2852 else
2853 m = v.getConstInitializer(true);
2854 }
2855 else
2856 m = v.type.defaultInitLiteral(e.loc);
2857 if (exceptionOrCant(m))
2858 return;
2859 (*elems)[fieldsSoFar + i] = copyLiteral(m).copy();
2860 }
2861 }
2862 // Hack: we store a ClassDeclaration instead of a StructDeclaration.
2863 // We probably won't get away with this.
2864 // auto se = new StructLiteralExp(e.loc, cast(StructDeclaration)cd, elems, e.newtype);
2865 auto se = ctfeEmplaceExp!StructLiteralExp(e.loc, cast(StructDeclaration)cd, elems, e.newtype);
2866 se.origin = se;
2867 se.ownedByCtfe = OwnedBy.ctfe;
2868 Expression eref = ctfeEmplaceExp!ClassReferenceExp(e.loc, se, e.type);
2869 if (e.member)
2870 {
2871 // Call constructor
2872 if (!e.member.fbody)
2873 {
2874 Expression ctorfail = evaluateIfBuiltin(pue, istate, e.loc, e.member, e.arguments, eref);
2875 if (ctorfail)
2876 {
2877 if (exceptionOrCant(ctorfail))
2878 return;
2879 result = eref;
2880 return;
2881 }
2882 e.member.error("`%s` cannot be constructed at compile time, because the constructor has no available source code", e.newtype.toChars());
2883 result = CTFEExp.cantexp;
2884 return;
2885 }
2886 UnionExp ue = void;
2887 Expression ctorfail = interpretFunction(&ue, e.member, istate, e.arguments, eref);
2888 if (exceptionOrCant(ctorfail))
2889 return;
2890
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().
2895 */
2896 eref.loc = e.loc;
2897 }
2898 result = eref;
2899 return;
2900 }
2901 if (e.newtype.toBasetype().isscalar())
2902 {
2903 Expression newval;
2904 if (e.arguments && e.arguments.dim)
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;
2911
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;
2917
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;
2923 }
2924 e.error("cannot interpret `%s` at compile time", e.toChars());
2925 result = CTFEExp.cantexp;
2926 }
2927
visit(UnaExp e)2928 override void visit(UnaExp e)
2929 {
2930 debug (LOG)
2931 {
2932 printf("%s UnaExp::interpret() %s\n", e.loc.toChars(), e.toChars());
2933 }
2934 UnionExp ue = void;
2935 Expression e1 = interpret(&ue, e.e1, istate);
2936 if (exceptionOrCant(e1))
2937 return;
2938 switch (e.op)
2939 {
2940 case EXP.negate:
2941 *pue = Neg(e.type, e1);
2942 break;
2943
2944 case EXP.tilde:
2945 *pue = Com(e.type, e1);
2946 break;
2947
2948 case EXP.not:
2949 *pue = Not(e.type, e1);
2950 break;
2951
2952 default:
2953 assert(0);
2954 }
2955 result = (*pue).exp();
2956 }
2957
visit(DotTypeExp e)2958 override void visit(DotTypeExp e)
2959 {
2960 debug (LOG)
2961 {
2962 printf("%s DotTypeExp::interpret() %s\n", e.loc.toChars(), e.toChars());
2963 }
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
2971 {
2972 auto edt = e.copy().isDotTypeExp();
2973 edt.e1 = (e1 == ue.exp()) ? e1.copy() : e1; // don't return pointer to ue
2974 result = edt;
2975 }
2976 }
2977
interpretCommon(BinExp e,fp_t fp)2978 extern (D) private void interpretCommon(BinExp e, fp_t fp)
2979 {
2980 debug (LOG)
2981 {
2982 printf("%s BinExp::interpretCommon() %s\n", e.loc.toChars(), e.toChars());
2983 }
2984 if (e.e1.type.ty == Tpointer && e.e2.type.ty == Tpointer && e.op == EXP.min)
2985 {
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;
2996 }
2997 if (e.e1.type.ty == Tpointer && e.e2.type.isintegral())
2998 {
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;
3009 }
3010 if (e.e2.type.ty == Tpointer && e.e1.type.isintegral() && e.op == EXP.add)
3011 {
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;
3022 }
3023 if (e.e1.type.ty == Tpointer || e.e2.type.ty == Tpointer)
3024 {
3025 e.error("pointer expression `%s` cannot be interpreted at compile time", e.toChars());
3026 result = CTFEExp.cantexp;
3027 return;
3028 }
3029
3030 bool evalOperand(UnionExp* pue, Expression ex, out Expression er)
3031 {
3032 er = interpret(pue, ex, istate);
3033 if (exceptionOrCant(er))
3034 return false;
3035 return true;
3036 }
3037
3038 UnionExp ue1 = void;
3039 Expression e1;
3040 if (!evalOperand(&ue1, e.e1, e1))
3041 return;
3042
3043 UnionExp ue2 = void;
3044 Expression e2;
3045 if (!evalOperand(&ue2, e.e2, e2))
3046 return;
3047
3048 if (e.op == EXP.rightShift || e.op == EXP.leftShift || e.op == EXP.unsignedRightShift)
3049 {
3050 const sinteger_t i2 = e2.toInteger();
3051 const uinteger_t sz = e1.type.size() * 8;
3052 if (i2 < 0 || i2 >= sz)
3053 {
3054 e.error("shift by %lld is outside the range 0..%llu", i2, cast(ulong)sz - 1);
3055 result = CTFEExp.cantexp;
3056 return;
3057 }
3058 }
3059
3060 /******************************************
3061 * Perform the operation fp on operands e1 and e2.
3062 */
3063 UnionExp evaluate(Loc loc, Type type, Expression e1, Expression e2)
3064 {
3065 UnionExp ue = void;
3066 auto ae1 = e1.isArrayLiteralExp();
3067 auto ae2 = e2.isArrayLiteralExp();
3068 if (ae1 || ae2)
3069 {
3070 /* Cases:
3071 * 1. T[] op T[]
3072 * 2. T op T[]
3073 * 3. T[] op T
3074 */
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
3080
3081 auto aex = ae1 ? ae1 : ae2;
3082 if (!aex.elements)
3083 {
3084 emplaceExp!ArrayLiteralExp(&ue, loc, type, cast(Expressions*) null);
3085 return ue;
3086 }
3087 const length = aex.elements.length;
3088 Expressions* elements = new Expressions(length);
3089
3090 emplaceExp!ArrayLiteralExp(&ue, loc, type, elements);
3091 foreach (i; 0 .. length)
3092 {
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();
3098 }
3099 return ue;
3100 }
3101
3102 if (e1.isConst() != 1)
3103 {
3104 // The following should really be an assert()
3105 e1.error("CTFE internal error: non-constant value `%s`", e1.toChars());
3106 emplaceExp!CTFEExp(&ue, EXP.cantExpression);
3107 return ue;
3108 }
3109 if (e2.isConst() != 1)
3110 {
3111 e2.error("CTFE internal error: non-constant value `%s`", e2.toChars());
3112 emplaceExp!CTFEExp(&ue, EXP.cantExpression);
3113 return ue;
3114 }
3115
3116 return (*fp)(loc, type, e1, e2);
3117 }
3118
3119 *pue = evaluate(e.loc, e.type, e1, e2);
3120 result = (*pue).exp();
3121 if (CTFEExp.isCantExp(result))
3122 e.error("`%s` cannot be interpreted at compile time", e.toChars());
3123 }
3124
interpretCompareCommon(BinExp e,fp2_t fp)3125 extern (D) private void interpretCompareCommon(BinExp e, fp2_t fp)
3126 {
3127 debug (LOG)
3128 {
3129 printf("%s BinExp::interpretCompareCommon() %s\n", e.loc.toChars(), e.toChars());
3130 }
3131 UnionExp ue1 = void;
3132 UnionExp ue2 = void;
3133 if (e.e1.type.ty == Tpointer && e.e2.type.ty == Tpointer)
3134 {
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)
3148 {
3149 char dir = (e.op == EXP.greaterThan || e.op == EXP.greaterOrEqual) ? '<' : '>';
3150 e.error("the ordering of pointers to unrelated memory blocks is indeterminate in CTFE. To check if they point to the same memory block, use both `>` and `<` inside `&&` or `||`, eg `%s && %s %c= %s + 1`", e.toChars(), e.e1.toChars(), dir, e.e2.toChars());
3151 result = CTFEExp.cantexp;
3152 return;
3153 }
3154 if (e.type.equals(Type.tbool))
3155 result = IntegerExp.createBool(cmp != 0);
3156 else
3157 {
3158 emplaceExp!(IntegerExp)(pue, e.loc, cmp, e.type);
3159 result = (*pue).exp();
3160 }
3161 return;
3162 }
3163 Expression e1 = interpret(&ue1, e.e1, istate);
3164 if (exceptionOrCant(e1))
3165 return;
3166 if (!isCtfeComparable(e1))
3167 {
3168 e.error("cannot compare `%s` at compile time", e1.toChars());
3169 result = CTFEExp.cantexp;
3170 return;
3171 }
3172 Expression e2 = interpret(&ue2, e.e2, istate);
3173 if (exceptionOrCant(e2))
3174 return;
3175 if (!isCtfeComparable(e2))
3176 {
3177 e.error("cannot compare `%s` at compile time", e2.toChars());
3178 result = CTFEExp.cantexp;
3179 return;
3180 }
3181 const cmp = (*fp)(e.loc, e.op, e1, e2);
3182 if (e.type.equals(Type.tbool))
3183 result = IntegerExp.createBool(cmp);
3184 else
3185 {
3186 emplaceExp!(IntegerExp)(pue, e.loc, cmp, e.type);
3187 result = (*pue).exp();
3188 }
3189 }
3190
visit(BinExp e)3191 override void visit(BinExp e)
3192 {
3193 switch (e.op)
3194 {
3195 case EXP.add:
3196 interpretCommon(e, &Add);
3197 return;
3198
3199 case EXP.min:
3200 interpretCommon(e, &Min);
3201 return;
3202
3203 case EXP.mul:
3204 interpretCommon(e, &Mul);
3205 return;
3206
3207 case EXP.div:
3208 interpretCommon(e, &Div);
3209 return;
3210
3211 case EXP.mod:
3212 interpretCommon(e, &Mod);
3213 return;
3214
3215 case EXP.leftShift:
3216 interpretCommon(e, &Shl);
3217 return;
3218
3219 case EXP.rightShift:
3220 interpretCommon(e, &Shr);
3221 return;
3222
3223 case EXP.unsignedRightShift:
3224 interpretCommon(e, &Ushr);
3225 return;
3226
3227 case EXP.and:
3228 interpretCommon(e, &And);
3229 return;
3230
3231 case EXP.or:
3232 interpretCommon(e, &Or);
3233 return;
3234
3235 case EXP.xor:
3236 interpretCommon(e, &Xor);
3237 return;
3238
3239 case EXP.pow:
3240 interpretCommon(e, &Pow);
3241 return;
3242
3243 case EXP.equal:
3244 case EXP.notEqual:
3245 interpretCompareCommon(e, &ctfeEqual);
3246 return;
3247
3248 case EXP.identity:
3249 case EXP.notIdentity:
3250 interpretCompareCommon(e, &ctfeIdentity);
3251 return;
3252
3253 case EXP.lessThan:
3254 case EXP.lessOrEqual:
3255 case EXP.greaterThan:
3256 case EXP.greaterOrEqual:
3257 interpretCompareCommon(e, &ctfeCmp);
3258 return;
3259
3260 default:
3261 printf("be = '%s' %s at [%s]\n", EXPtoString(e.op).ptr, e.toChars(), e.loc.toChars());
3262 assert(0);
3263 }
3264 }
3265
3266 /* Helper functions for BinExp::interpretAssignCommon
3267 */
3268 // Returns the variable which is eventually modified, or NULL if an rvalue.
3269 // thisval is the current value of 'this'.
findParentVar(Expression e)3270 static VarDeclaration findParentVar(Expression e)
3271 {
3272 for (;;)
3273 {
3274 if (auto ve = e.isVarExp())
3275 {
3276 VarDeclaration v = ve.var.isVarDeclaration();
3277 assert(v);
3278 return v;
3279 }
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;
3290 }
3291 }
3292
3293 extern (D) private void interpretAssignCommon(BinExp e, fp_t fp, int post = 0)
3294 {
debug(LOG)3295 debug (LOG)
3296 {
3297 printf("%s BinExp::interpretAssignCommon() %s\n", e.loc.toChars(), e.toChars());
3298 }
3299 result = CTFEExp.cantexp;
3300
3301 Expression e1 = e.e1;
3302 if (!istate)
3303 {
3304 e.error("value of `%s` is not known at compile time", e1.toChars());
3305 return;
3306 }
3307
3308 ++ctfeGlobals.numAssignments;
3309
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.
3317 */
3318 bool isBlockAssignment = false;
3319 if (e1.op == EXP.slice)
3320 {
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)
3325 {
3326 tdst = (cast(TypeArray)tdst).next.toBasetype();
3327 if (tsrc.equivalent(tdst))
3328 {
3329 isBlockAssignment = true;
3330 break;
3331 }
3332 }
3333 }
3334
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))
3341 {
3342 assert(!fp);
3343
3344 Expression newval = interpretRegion(e.e2, istate, CTFEGoal.LValue);
3345 if (exceptionOrCant(newval))
3346 return;
3347
3348 VarDeclaration v = e1.isVarExp().var.isVarDeclaration();
3349 setValue(v, newval);
3350
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;
3358 }
3359
3360 if (fp)
3361 {
3362 while (e1.op == EXP.cast_)
3363 {
3364 CastExp ce = e1.isCastExp();
3365 e1 = ce.e1;
3366 }
3367 }
3368
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)
3376 {
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.
3386 */
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)
3390 {
3391 assert(ie.modifiable);
3392 ie = ie.e1.isIndexExp();
3393 ++depth;
3394 }
3395
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)
3401 {
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;
3409
3410 while (depth > 0)
3411 {
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();
3416
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
3422
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)
3428 {
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);
3438 }
3439 existingAA = newAA;
3440 --depth;
3441 }
3442
3443 if (fp)
3444 {
3445 oldval = findKeyInAA(e.loc, existingAA, lastIndex);
3446 if (!oldval)
3447 oldval = copyLiteral(e.e1.type.defaultInitLiteral(e.loc)).copy();
3448 }
3449 }
3450 else
3451 {
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;
3459 */
3460 oldval = copyLiteral(e.e1.type.defaultInitLiteral(e.loc)).copy();
3461
3462 Expression newaae = oldval;
3463 while (e1.op == EXP.index && e1.isIndexExp().e1.type.toBasetype().ty == Taarray)
3464 {
3465 Expression ekey = interpretRegion(e1.isIndexExp().e2, istate);
3466 if (exceptionOrCant(ekey))
3467 return;
3468 ekey = resolveSlice(ekey); // only happens with AA assignment
3469
3470 auto keysx = new Expressions();
3471 auto valuesx = new Expressions();
3472 keysx.push(ekey);
3473 valuesx.push(newaae);
3474
3475 auto aae = ctfeEmplaceExp!AssocArrayLiteralExp(e.loc, keysx, valuesx);
3476 aae.type = e1.isIndexExp().e1.type;
3477 aae.ownedByCtfe = OwnedBy.ctfe;
3478 if (!existingAA)
3479 {
3480 existingAA = aae;
3481 lastIndex = ekey;
3482 }
3483 newaae = aae;
3484 e1 = e1.isIndexExp().e1;
3485 }
3486
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;
3494 }
3495 assert(existingAA && lastIndex);
3496 e1 = null; // stomp
3497 }
3498 else if (e1.op == EXP.arrayLength)
3499 {
3500 oldval = interpretRegion(e1, istate);
3501 if (exceptionOrCant(oldval))
3502 return;
3503 }
3504 else if (e.op == EXP.construct || e.op == EXP.blit)
3505 {
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())
3511 {
3512 VarDeclaration v = ve.var.isVarDeclaration();
3513 assert(v);
3514 if (v.storage_class & STC.out_)
3515 goto L1;
3516 }
3517 else if (ultimateVar && !getValue(ultimateVar))
3518 {
3519 Expression ex = interpretRegion(ultimateVar.type.defaultInitLiteral(e.loc), istate);
3520 if (exceptionOrCant(ex))
3521 return;
3522 setValue(ultimateVar, ex);
3523 }
3524 else
3525 goto L1;
3526 }
3527 else
3528 {
3529 L1:
3530 e1 = interpretRegion(e1, istate, CTFEGoal.LValue);
3531 if (exceptionOrCant(e1))
3532 return;
3533
3534 if (e1.op == EXP.index && e1.isIndexExp().e1.type.toBasetype().ty == Taarray)
3535 {
3536 IndexExp ie = e1.isIndexExp();
3537 assert(ie.e1.op == EXP.assocArrayLiteral);
3538 existingAA = ie.e1.isAssocArrayLiteralExp();
3539 lastIndex = ie.e2;
3540 }
3541 }
3542
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)
3550 {
3551 Type tbn = e.type.baseElemOf();
3552 if (tbn.ty == Tstruct)
3553 {
3554 /* Look for special case of struct being initialized with 0.
3555 */
3556 newval = e.type.defaultInitLiteral(e.loc);
3557 if (newval.op == EXP.error)
3558 {
3559 result = CTFEExp.cantexp;
3560 return;
3561 }
3562 newval = interpretRegion(newval, istate); // copy and set ownedByCtfe flag
3563 if (exceptionOrCant(newval))
3564 return;
3565 }
3566 }
3567
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)
3575 {
3576 if (!oldval)
3577 {
3578 // Load the left hand side after interpreting the right hand side.
3579 oldval = interpretRegion(e1, istate);
3580 if (exceptionOrCant(oldval))
3581 return;
3582 }
3583
3584 if (e.e1.type.ty != Tpointer)
3585 {
3586 // ~= can create new values (see bug 6052)
3587 if (e.op == EXP.concatenateAssign || e.op == EXP.concatenateElemAssign || e.op == EXP.concatenateDcharAssign)
3588 {
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)
3592 {
3593 newval = copyLiteral(newval).copy();
3594 newval.type = e.e2.type; // repaint type
3595 }
3596 else
3597 {
3598 newval = paintTypeOntoLiteral(e.e2.type, newval);
3599 newval = resolveSlice(newval);
3600 }
3601 }
3602 oldval = resolveSlice(oldval);
3603
3604 newval = (*fp)(e.loc, e.type, oldval, newval).copy();
3605 }
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))
3611 {
3612 newval = pointerArithmetic(pue, e.loc, e.op, e.type, oldval, newval).copy();
3613 if (newval == pue.exp())
3614 newval = pue.copy();
3615 }
3616 else
3617 {
3618 e.error("pointer expression `%s` cannot be interpreted at compile time", e.toChars());
3619 result = CTFEExp.cantexp;
3620 return;
3621 }
3622 if (exceptionOrCant(newval))
3623 {
3624 if (CTFEExp.isCantExp(newval))
3625 e.error("cannot interpret `%s` at compile time", e.toChars());
3626 return;
3627 }
3628 }
3629
3630 if (existingAA)
3631 {
3632 if (existingAA.ownedByCtfe != OwnedBy.ctfe)
3633 {
3634 e.error("cannot modify read-only constant `%s`", existingAA.toChars());
3635 result = CTFEExp.cantexp;
3636 return;
3637 }
3638
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);
3642
3643 // Determine the return value
3644 result = ctfeCast(pue, e.loc, e.type, e.type, fp && post ? oldval : newval);
3645 return;
3646 }
3647 if (e1.op == EXP.arrayLength)
3648 {
3649 /* Change the assignment from:
3650 * arr.length = n;
3651 * into:
3652 * arr = new_length_array; (result is n)
3653 */
3654
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;
3659
3660 if (result == pue.exp())
3661 result = pue.copy();
3662
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;
3667
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)
3673 {
3674 e.error("`%s` is not yet supported at compile time", e.toChars());
3675 result = CTFEExp.cantexp;
3676 return;
3677 }
3678 e1 = interpretRegion(e1, istate, CTFEGoal.LValue);
3679 if (exceptionOrCant(e1))
3680 return;
3681
3682 if (oldlen != 0) // Get the old array literal.
3683 oldval = interpretRegion(e1, istate);
3684 UnionExp utmp = void;
3685 oldval = resolveSlice(oldval, &utmp);
3686
3687 newval = changeArrayLiteralLength(pue, e.loc, cast(TypeArray)t, oldval, oldlen, newlen);
3688 if (newval == pue.exp())
3689 newval = pue.copy();
3690
3691 e1 = assignToLvalue(e, e1, newval);
3692 if (exceptionOrCant(e1))
3693 return;
3694
3695 return;
3696 }
3697
3698 if (!isBlockAssignment)
3699 {
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();
3705
3706 // Determine the return value
3707 if (goal == CTFEGoal.LValue) // https://issues.dlang.org/show_bug.cgi?id=14371
3708 result = e1;
3709 else
3710 {
3711 result = ctfeCast(pue, e.loc, e.type, e.type, fp && post ? oldval : newval);
3712 if (result == pue.exp())
3713 result = pue.copy();
3714 }
3715 if (exceptionOrCant(result))
3716 return;
3717 }
3718 if (exceptionOrCant(newval))
3719 return;
3720
debug(LOGASSIGN)3721 debug (LOGASSIGN)
3722 {
3723 printf("ASSIGN: %s=%s\n", e1.toChars(), newval.toChars());
3724 showCtfeExpr(newval);
3725 }
3726
3727 /* Block assignment or element-wise assignment.
3728 */
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)
3734 {
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())
3741 {
3742 Expression e1x = interpretRegion(se.e1, istate, CTFEGoal.LValue);
3743 if (auto dve = e1x.isDotVarExp())
3744 {
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)
3751 {
3752 e.error("CTFE internal error: dotvar slice assignment");
3753 result = CTFEExp.cantexp;
3754 return;
3755 }
3756 stompOverlappedFields(sle, v);
3757 }
3758 }
3759 return;
3760 }
3761 assert(result);
3762
3763 /* Assignment to a CTFE reference.
3764 */
3765 if (Expression ex = assignToLvalue(e, e1, newval))
3766 result = ex;
3767
3768 return;
3769 }
3770
3771 /* Set all sibling fields which overlap with v to VoidExp.
3772 */
stompOverlappedFields(StructLiteralExp sle,VarDeclaration v)3773 private void stompOverlappedFields(StructLiteralExp sle, VarDeclaration v)
3774 {
3775 if (!v.overlapped)
3776 return;
3777 foreach (size_t i, v2; sle.sd.fields)
3778 {
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();
3784 }
3785 }
3786
assignToLvalue(BinExp e,Expression e1,Expression newval)3787 private Expression assignToLvalue(BinExp e, Expression e1, Expression newval)
3788 {
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;
3793
3794 if (auto ve = e1.isVarExp())
3795 {
3796 vd = ve.var.isVarDeclaration();
3797 oldval = getValue(vd);
3798 }
3799 else if (auto dve = e1.isDotVarExp())
3800 {
3801 /* Assignment to member variable of the form:
3802 * e.v = newval
3803 */
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)
3810 {
3811 e.error("CTFE internal error: dotvar assignment");
3812 return CTFEExp.cantexp;
3813 }
3814 if (sle.ownedByCtfe != OwnedBy.ctfe)
3815 {
3816 e.error("cannot modify read-only constant `%s`", sle.toChars());
3817 return CTFEExp.cantexp;
3818 }
3819
3820 int fieldi = ex.op == EXP.structLiteral ? findFieldIndexByName(sle.sd, v)
3821 : ex.isClassReferenceExp().findFieldIndexByName(v);
3822 if (fieldi == -1)
3823 {
3824 e.error("CTFE internal error: cannot find field `%s` in `%s`", v.toChars(), ex.toChars());
3825 return CTFEExp.cantexp;
3826 }
3827 assert(0 <= fieldi && fieldi < sle.elements.dim);
3828
3829 // If it's a union, set all other members of this union to void
3830 stompOverlappedFields(sle, v);
3831
3832 payload = &(*sle.elements)[fieldi];
3833 oldval = *payload;
3834 if (auto ival = newval.isIntegerExp())
3835 {
3836 if (auto bf = v.isBitFieldDeclaration())
3837 {
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);
3845 }
3846 ival.setInteger(value);
3847 }
3848 }
3849 }
3850 else if (auto ie = e1.isIndexExp())
3851 {
3852 assert(ie.e1.type.toBasetype().ty != Taarray);
3853
3854 Expression aggregate;
3855 uinteger_t indexToModify;
3856 if (!resolveIndexing(ie, istate, &aggregate, &indexToModify, true))
3857 {
3858 return CTFEExp.cantexp;
3859 }
3860 size_t index = cast(size_t)indexToModify;
3861
3862 if (auto existingSE = aggregate.isStringExp())
3863 {
3864 if (existingSE.ownedByCtfe != OwnedBy.ctfe)
3865 {
3866 e.error("cannot modify read-only string literal `%s`", ie.e1.toChars());
3867 return CTFEExp.cantexp;
3868 }
3869 existingSE.setCodeUnit(index, cast(dchar)newval.toInteger());
3870 return null;
3871 }
3872 if (aggregate.op != EXP.arrayLiteral)
3873 {
3874 e.error("index assignment `%s` is not yet supported in CTFE ", e.toChars());
3875 return CTFEExp.cantexp;
3876 }
3877
3878 ArrayLiteralExp existingAE = aggregate.isArrayLiteralExp();
3879 if (existingAE.ownedByCtfe != OwnedBy.ctfe)
3880 {
3881 e.error("cannot modify read-only constant `%s`", existingAE.toChars());
3882 return CTFEExp.cantexp;
3883 }
3884
3885 payload = &(*existingAE.elements)[index];
3886 oldval = *payload;
3887 }
3888 else
3889 {
3890 e.error("`%s` cannot be evaluated at compile time", e.toChars());
3891 return CTFEExp.cantexp;
3892 }
3893
3894 Type t1b = e1.type.toBasetype();
3895 bool wantCopy = t1b.baseElemOf().ty == Tstruct;
3896
3897 if (auto ve = newval.isVectorExp())
3898 {
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
3901 {
3902 UnionExp ue = void;
3903 Expression ex = interpretVectorToArray(&ue, ve);
3904 ve.e1 = (ex == ue.exp()) ? ue.copy() : ex;
3905 }
3906 }
3907
3908 if (newval.op == EXP.structLiteral && oldval)
3909 {
3910 assert(oldval.op == EXP.structLiteral || oldval.op == EXP.arrayLiteral || oldval.op == EXP.string_);
3911 newval = copyLiteral(newval).copy();
3912 assignInPlace(oldval, newval);
3913 }
3914 else if (wantCopy && e.op == EXP.assign)
3915 {
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.
3919
3920 assert(oldval);
3921 version (all) // todo: instead we can directly access to each elements of the slice
3922 {
3923 newval = resolveSlice(newval);
3924 if (CTFEExp.isCantExp(newval))
3925 {
3926 e.error("CTFE internal error: assignment `%s`", e.toChars());
3927 return CTFEExp.cantexp;
3928 }
3929 }
3930 assert(oldval.op == EXP.arrayLiteral);
3931 assert(newval.op == EXP.arrayLiteral);
3932
3933 Expressions* oldelems = oldval.isArrayLiteralExp().elements;
3934 Expressions* newelems = newval.isArrayLiteralExp().elements;
3935 assert(oldelems.dim == newelems.dim);
3936
3937 Type elemtype = oldval.type.nextOf();
3938 foreach (i, ref oldelem; *oldelems)
3939 {
3940 Expression newelem = paintTypeOntoLiteral(elemtype, (*newelems)[i]);
3941 // https://issues.dlang.org/show_bug.cgi?id=9245
3942 if (e.e2.isLvalue())
3943 {
3944 if (Expression ex = evaluatePostblit(istate, newelem))
3945 return ex;
3946 }
3947 // https://issues.dlang.org/show_bug.cgi?id=13661
3948 if (Expression ex = evaluateDtor(istate, oldelem))
3949 return ex;
3950 oldelem = newelem;
3951 }
3952 }
3953 else
3954 {
3955 // e1 has its own payload, so we have to create a new literal.
3956 if (wantCopy)
3957 newval = copyLiteral(newval).copy();
3958
3959 if (t1b.ty == Tsarray && e.op == EXP.construct && e.e2.isLvalue())
3960 {
3961 // https://issues.dlang.org/show_bug.cgi?id=9245
3962 if (Expression ex = evaluatePostblit(istate, newval))
3963 return ex;
3964 }
3965
3966 oldval = newval;
3967 }
3968
3969 if (vd)
3970 setValue(vd, oldval);
3971 else
3972 *payload = oldval;
3973
3974 // Blit assignment should return the newly created value.
3975 if (e.op == EXP.blit)
3976 return oldval;
3977
3978 return null;
3979 }
3980
3981 /*************
3982 * Deal with assignments of the form:
3983 * dest[] = newval
3984 * dest[low..upp] = newval
3985 * where newval has already been interpreted
3986 *
3987 * This could be a slice assignment or a block assignment, and
3988 * dest could be either an array literal, or a string.
3989 *
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
3993 */
interpretAssignToSlice(UnionExp * pue,BinExp e,Expression e1,Expression newval,bool isBlockAssignment)3994 private Expression interpretAssignToSlice(UnionExp* pue, BinExp e, Expression e1, Expression newval, bool isBlockAssignment)
3995 {
3996 dinteger_t lowerbound;
3997 dinteger_t upperbound;
3998 dinteger_t firstIndex;
3999
4000 Expression aggregate;
4001
4002 if (auto se = e1.isSliceExp())
4003 {
4004 // ------------------------------
4005 // aggregate[] = newval
4006 // aggregate[low..upp] = newval
4007 // ------------------------------
4008 aggregate = interpretRegion(se.e1, istate);
4009 lowerbound = se.lwr ? se.lwr.toInteger() : 0;
4010 upperbound = se.upr ? se.upr.toInteger() : resolveArrayLength(aggregate);
4011
4012 // Slice of a slice --> change the bounds
4013 if (auto oldse = aggregate.isSliceExp())
4014 {
4015 aggregate = oldse.e1;
4016 firstIndex = lowerbound + oldse.lwr.toInteger();
4017 }
4018 else
4019 firstIndex = lowerbound;
4020 }
4021 else
4022 {
4023 if (auto ale = e1.isArrayLiteralExp())
4024 {
4025 lowerbound = 0;
4026 upperbound = ale.elements.dim;
4027 }
4028 else if (auto se = e1.isStringExp())
4029 {
4030 lowerbound = 0;
4031 upperbound = se.len;
4032 }
4033 else if (e1.op == EXP.null_)
4034 {
4035 lowerbound = 0;
4036 upperbound = 0;
4037 }
4038 else if (VectorExp ve = e1.isVectorExp())
4039 {
4040 // ve is not handled but a proper error message is returned
4041 // this is to prevent https://issues.dlang.org/show_bug.cgi?id=20042
4042 lowerbound = 0;
4043 upperbound = ve.dim;
4044 }
4045 else
4046 assert(0);
4047
4048 aggregate = e1;
4049 firstIndex = lowerbound;
4050 }
4051 if (upperbound == lowerbound)
4052 return newval;
4053
4054 // For slice assignment, we check that the lengths match.
4055 if (!isBlockAssignment)
4056 {
4057 const srclen = resolveArrayLength(newval);
4058 if (srclen != (upperbound - lowerbound))
4059 {
4060 e.error("array length mismatch assigning `[0..%llu]` to `[%llu..%llu]`",
4061 ulong(srclen), ulong(lowerbound), ulong(upperbound));
4062 return CTFEExp.cantexp;
4063 }
4064 }
4065
4066 if (auto existingSE = aggregate.isStringExp())
4067 {
4068 if (existingSE.ownedByCtfe != OwnedBy.ctfe)
4069 {
4070 e.error("cannot modify read-only string literal `%s`", existingSE.toChars());
4071 return CTFEExp.cantexp;
4072 }
4073
4074 if (auto se = newval.isSliceExp())
4075 {
4076 auto aggr2 = se.e1;
4077 const srclower = se.lwr.toInteger();
4078 const srcupper = se.upr.toInteger();
4079
4080 if (aggregate == aggr2 &&
4081 lowerbound < srcupper && srclower < upperbound)
4082 {
4083 e.error("overlapping slice assignment `[%llu..%llu] = [%llu..%llu]`",
4084 ulong(lowerbound), ulong(upperbound), ulong(srclower), ulong(srcupper));
4085 return CTFEExp.cantexp;
4086 }
4087 version (all) // todo: instead we can directly access to each elements of the slice
4088 {
4089 Expression orignewval = newval;
4090 newval = resolveSlice(newval);
4091 if (CTFEExp.isCantExp(newval))
4092 {
4093 e.error("CTFE internal error: slice `%s`", orignewval.toChars());
4094 return CTFEExp.cantexp;
4095 }
4096 }
4097 assert(newval.op != EXP.slice);
4098 }
4099 if (auto se = newval.isStringExp())
4100 {
4101 sliceAssignStringFromString(existingSE, se, cast(size_t)firstIndex);
4102 return newval;
4103 }
4104 if (auto ale = newval.isArrayLiteralExp())
4105 {
4106 /* Mixed slice: it was initialized as a string literal.
4107 * Now a slice of it is being set with an array literal.
4108 */
4109 sliceAssignStringFromArrayLiteral(existingSE, ale, cast(size_t)firstIndex);
4110 return newval;
4111 }
4112
4113 // String literal block slice assign
4114 const value = cast(dchar)newval.toInteger();
4115 foreach (i; 0 .. upperbound - lowerbound)
4116 {
4117 existingSE.setCodeUnit(cast(size_t)(i + firstIndex), value);
4118 }
4119 if (goal == CTFEGoal.Nothing)
4120 return null; // avoid creating an unused literal
4121 auto retslice = ctfeEmplaceExp!SliceExp(e.loc, existingSE,
4122 ctfeEmplaceExp!IntegerExp(e.loc, firstIndex, Type.tsize_t),
4123 ctfeEmplaceExp!IntegerExp(e.loc, firstIndex + upperbound - lowerbound, Type.tsize_t));
4124 retslice.type = e.type;
4125 return interpret(pue, retslice, istate);
4126 }
4127 if (auto existingAE = aggregate.isArrayLiteralExp())
4128 {
4129 if (existingAE.ownedByCtfe != OwnedBy.ctfe)
4130 {
4131 e.error("cannot modify read-only constant `%s`", existingAE.toChars());
4132 return CTFEExp.cantexp;
4133 }
4134
4135 if (newval.op == EXP.slice && !isBlockAssignment)
4136 {
4137 auto se = newval.isSliceExp();
4138 auto aggr2 = se.e1;
4139 const srclower = se.lwr.toInteger();
4140 const srcupper = se.upr.toInteger();
4141 const wantCopy = (newval.type.toBasetype().nextOf().baseElemOf().ty == Tstruct);
4142
4143 //printf("oldval = %p %s[%d..%u]\nnewval = %p %s[%llu..%llu] wantCopy = %d\n",
4144 // aggregate, aggregate.toChars(), lowerbound, upperbound,
4145 // aggr2, aggr2.toChars(), srclower, srcupper, wantCopy);
4146 if (wantCopy)
4147 {
4148 // Currently overlapping for struct array is allowed.
4149 // The order of elements processing depends on the overlapping.
4150 // https://issues.dlang.org/show_bug.cgi?id=14024
4151 assert(aggr2.op == EXP.arrayLiteral);
4152 Expressions* oldelems = existingAE.elements;
4153 Expressions* newelems = aggr2.isArrayLiteralExp().elements;
4154
4155 Type elemtype = aggregate.type.nextOf();
4156 bool needsPostblit = e.e2.isLvalue();
4157
4158 if (aggregate == aggr2 && srclower < lowerbound && lowerbound < srcupper)
4159 {
4160 // reverse order
4161 for (auto i = upperbound - lowerbound; 0 < i--;)
4162 {
4163 Expression oldelem = (*oldelems)[cast(size_t)(i + firstIndex)];
4164 Expression newelem = (*newelems)[cast(size_t)(i + srclower)];
4165 newelem = copyLiteral(newelem).copy();
4166 newelem.type = elemtype;
4167 if (needsPostblit)
4168 {
4169 if (Expression x = evaluatePostblit(istate, newelem))
4170 return x;
4171 }
4172 if (Expression x = evaluateDtor(istate, oldelem))
4173 return x;
4174 (*oldelems)[cast(size_t)(lowerbound + i)] = newelem;
4175 }
4176 }
4177 else
4178 {
4179 // normal order
4180 for (auto i = 0; i < upperbound - lowerbound; i++)
4181 {
4182 Expression oldelem = (*oldelems)[cast(size_t)(i + firstIndex)];
4183 Expression newelem = (*newelems)[cast(size_t)(i + srclower)];
4184 newelem = copyLiteral(newelem).copy();
4185 newelem.type = elemtype;
4186 if (needsPostblit)
4187 {
4188 if (Expression x = evaluatePostblit(istate, newelem))
4189 return x;
4190 }
4191 if (Expression x = evaluateDtor(istate, oldelem))
4192 return x;
4193 (*oldelems)[cast(size_t)(lowerbound + i)] = newelem;
4194 }
4195 }
4196
4197 //assert(0);
4198 return newval; // oldval?
4199 }
4200 if (aggregate == aggr2 &&
4201 lowerbound < srcupper && srclower < upperbound)
4202 {
4203 e.error("overlapping slice assignment `[%llu..%llu] = [%llu..%llu]`",
4204 ulong(lowerbound), ulong(upperbound), ulong(srclower), ulong(srcupper));
4205 return CTFEExp.cantexp;
4206 }
4207 version (all) // todo: instead we can directly access to each elements of the slice
4208 {
4209 Expression orignewval = newval;
4210 newval = resolveSlice(newval);
4211 if (CTFEExp.isCantExp(newval))
4212 {
4213 e.error("CTFE internal error: slice `%s`", orignewval.toChars());
4214 return CTFEExp.cantexp;
4215 }
4216 }
4217 // no overlapping
4218 //length?
4219 assert(newval.op != EXP.slice);
4220 }
4221 if (newval.op == EXP.string_ && !isBlockAssignment)
4222 {
4223 /* Mixed slice: it was initialized as an array literal of chars/integers.
4224 * Now a slice of it is being set with a string.
4225 */
4226 sliceAssignArrayLiteralFromString(existingAE, newval.isStringExp(), cast(size_t)firstIndex);
4227 return newval;
4228 }
4229 if (newval.op == EXP.arrayLiteral && !isBlockAssignment)
4230 {
4231 Expressions* oldelems = existingAE.elements;
4232 Expressions* newelems = newval.isArrayLiteralExp().elements;
4233 Type elemtype = existingAE.type.nextOf();
4234 bool needsPostblit = e.op != EXP.blit && e.e2.isLvalue();
4235 foreach (j, newelem; *newelems)
4236 {
4237 newelem = paintTypeOntoLiteral(elemtype, newelem);
4238 if (needsPostblit)
4239 {
4240 Expression x = evaluatePostblit(istate, newelem);
4241 if (exceptionOrCantInterpret(x))
4242 return x;
4243 }
4244 (*oldelems)[cast(size_t)(j + firstIndex)] = newelem;
4245 }
4246 return newval;
4247 }
4248
4249 /* Block assignment, initialization of static arrays
4250 * x[] = newval
4251 * x may be a multidimensional static array. (Note that this
4252 * only happens with array literals, never with strings).
4253 */
4254 struct RecursiveBlock
4255 {
4256 InterState* istate;
4257 Expression newval;
4258 bool refCopy;
4259 bool needsPostblit;
4260 bool needsDtor;
4261
4262 extern (C++) Expression assignTo(ArrayLiteralExp ae)
4263 {
4264 return assignTo(ae, 0, ae.elements.dim);
4265 }
4266
4267 extern (C++) Expression assignTo(ArrayLiteralExp ae, size_t lwr, size_t upr)
4268 {
4269 Expressions* w = ae.elements;
4270 assert(ae.type.ty == Tsarray || ae.type.ty == Tarray);
4271 bool directblk = (cast(TypeArray)ae.type).next.equivalent(newval.type);
4272 for (size_t k = lwr; k < upr; k++)
4273 {
4274 if (!directblk && (*w)[k].op == EXP.arrayLiteral)
4275 {
4276 // Multidimensional array block assign
4277 if (Expression ex = assignTo((*w)[k].isArrayLiteralExp()))
4278 return ex;
4279 }
4280 else if (refCopy)
4281 {
4282 (*w)[k] = newval;
4283 }
4284 else if (!needsPostblit && !needsDtor)
4285 {
4286 assignInPlace((*w)[k], newval);
4287 }
4288 else
4289 {
4290 Expression oldelem = (*w)[k];
4291 Expression tmpelem = needsDtor ? copyLiteral(oldelem).copy() : null;
4292 assignInPlace(oldelem, newval);
4293 if (needsPostblit)
4294 {
4295 if (Expression ex = evaluatePostblit(istate, oldelem))
4296 return ex;
4297 }
4298 if (needsDtor)
4299 {
4300 // https://issues.dlang.org/show_bug.cgi?id=14860
4301 if (Expression ex = evaluateDtor(istate, tmpelem))
4302 return ex;
4303 }
4304 }
4305 }
4306 return null;
4307 }
4308 }
4309
4310 Type tn = newval.type.toBasetype();
4311 bool wantRef = (tn.ty == Tarray || isAssocArray(tn) || tn.ty == Tclass);
4312 bool cow = newval.op != EXP.structLiteral && newval.op != EXP.arrayLiteral && newval.op != EXP.string_;
4313 Type tb = tn.baseElemOf();
4314 StructDeclaration sd = (tb.ty == Tstruct ? (cast(TypeStruct)tb).sym : null);
4315
4316 RecursiveBlock rb;
4317 rb.istate = istate;
4318 rb.newval = newval;
4319 rb.refCopy = wantRef || cow;
4320 rb.needsPostblit = sd && sd.postblit && e.op != EXP.blit && e.e2.isLvalue();
4321 rb.needsDtor = sd && sd.dtor && e.op == EXP.assign;
4322 if (Expression ex = rb.assignTo(existingAE, cast(size_t)lowerbound, cast(size_t)upperbound))
4323 return ex;
4324
4325 if (goal == CTFEGoal.Nothing)
4326 return null; // avoid creating an unused literal
4327 auto retslice = ctfeEmplaceExp!SliceExp(e.loc, existingAE,
4328 ctfeEmplaceExp!IntegerExp(e.loc, firstIndex, Type.tsize_t),
4329 ctfeEmplaceExp!IntegerExp(e.loc, firstIndex + upperbound - lowerbound, Type.tsize_t));
4330 retslice.type = e.type;
4331 return interpret(pue, retslice, istate);
4332 }
4333
4334 e.error("slice operation `%s = %s` cannot be evaluated at compile time", e1.toChars(), newval.toChars());
4335 return CTFEExp.cantexp;
4336 }
4337
visit(AssignExp e)4338 override void visit(AssignExp e)
4339 {
4340 interpretAssignCommon(e, null);
4341 }
4342
visit(BinAssignExp e)4343 override void visit(BinAssignExp e)
4344 {
4345 switch (e.op)
4346 {
4347 case EXP.addAssign:
4348 interpretAssignCommon(e, &Add);
4349 return;
4350
4351 case EXP.minAssign:
4352 interpretAssignCommon(e, &Min);
4353 return;
4354
4355 case EXP.concatenateAssign:
4356 case EXP.concatenateElemAssign:
4357 case EXP.concatenateDcharAssign:
4358 interpretAssignCommon(e, &ctfeCat);
4359 return;
4360
4361 case EXP.mulAssign:
4362 interpretAssignCommon(e, &Mul);
4363 return;
4364
4365 case EXP.divAssign:
4366 interpretAssignCommon(e, &Div);
4367 return;
4368
4369 case EXP.modAssign:
4370 interpretAssignCommon(e, &Mod);
4371 return;
4372
4373 case EXP.leftShiftAssign:
4374 interpretAssignCommon(e, &Shl);
4375 return;
4376
4377 case EXP.rightShiftAssign:
4378 interpretAssignCommon(e, &Shr);
4379 return;
4380
4381 case EXP.unsignedRightShiftAssign:
4382 interpretAssignCommon(e, &Ushr);
4383 return;
4384
4385 case EXP.andAssign:
4386 interpretAssignCommon(e, &And);
4387 return;
4388
4389 case EXP.orAssign:
4390 interpretAssignCommon(e, &Or);
4391 return;
4392
4393 case EXP.xorAssign:
4394 interpretAssignCommon(e, &Xor);
4395 return;
4396
4397 case EXP.powAssign:
4398 interpretAssignCommon(e, &Pow);
4399 return;
4400
4401 default:
4402 assert(0);
4403 }
4404 }
4405
visit(PostExp e)4406 override void visit(PostExp e)
4407 {
4408 debug (LOG)
4409 {
4410 printf("%s PostExp::interpret() %s\n", e.loc.toChars(), e.toChars());
4411 }
4412 if (e.op == EXP.plusPlus)
4413 interpretAssignCommon(e, &Add, 1);
4414 else
4415 interpretAssignCommon(e, &Min, 1);
4416 debug (LOG)
4417 {
4418 if (CTFEExp.isCantExp(result))
4419 printf("PostExp::interpret() CANT\n");
4420 }
4421 }
4422
4423 /* Return 1 if e is a p1 > p2 or p1 >= p2 pointer comparison;
4424 * -1 if e is a p1 < p2 or p1 <= p2 pointer comparison;
4425 * 0 otherwise
4426 */
isPointerCmpExp(Expression e,Expression * p1,Expression * p2)4427 static int isPointerCmpExp(Expression e, Expression* p1, Expression* p2)
4428 {
4429 int ret = 1;
4430 while (e.op == EXP.not)
4431 {
4432 ret *= -1;
4433 e = e.isNotExp().e1;
4434 }
4435 switch (e.op)
4436 {
4437 case EXP.lessThan:
4438 case EXP.lessOrEqual:
4439 ret *= -1;
4440 goto case; /+ fall through +/
4441 case EXP.greaterThan:
4442 case EXP.greaterOrEqual:
4443 *p1 = e.isBinExp().e1;
4444 *p2 = e.isBinExp().e2;
4445 if (!(isPointer((*p1).type) && isPointer((*p2).type)))
4446 ret = 0;
4447 break;
4448
4449 default:
4450 ret = 0;
4451 break;
4452 }
4453 return ret;
4454 }
4455
4456 /** If this is a four pointer relation, evaluate it, else return NULL.
4457 *
4458 * This is an expression of the form (p1 > q1 && p2 < q2) or (p1 < q1 || p2 > q2)
4459 * where p1, p2 are expressions yielding pointers to memory block p,
4460 * and q1, q2 are expressions yielding pointers to memory block q.
4461 * This expression is valid even if p and q are independent memory
4462 * blocks and are therefore not normally comparable; the && form returns true
4463 * if [p1..p2] lies inside [q1..q2], and false otherwise; the || form returns
4464 * true if [p1..p2] lies outside [q1..q2], and false otherwise.
4465 *
4466 * Within the expression, any ordering of p1, p2, q1, q2 is permissible;
4467 * the comparison operators can be any of >, <, <=, >=, provided that
4468 * both directions (p > q and p < q) are checked. Additionally the
4469 * relational sub-expressions can be negated, eg
4470 * (!(q1 < p1) && p2 <= q2) is valid.
4471 */
interpretFourPointerRelation(UnionExp * pue,BinExp e)4472 private void interpretFourPointerRelation(UnionExp* pue, BinExp e)
4473 {
4474 assert(e.op == EXP.andAnd || e.op == EXP.orOr);
4475
4476 /* It can only be an isInside expression, if both e1 and e2 are
4477 * directional pointer comparisons.
4478 * Note that this check can be made statically; it does not depends on
4479 * any runtime values. This allows a JIT implementation to compile a
4480 * special AndAndPossiblyInside, keeping the normal AndAnd case efficient.
4481 */
4482
4483 // Save the pointer expressions and the comparison directions,
4484 // so we can use them later.
4485 Expression p1 = null;
4486 Expression p2 = null;
4487 Expression p3 = null;
4488 Expression p4 = null;
4489 int dir1 = isPointerCmpExp(e.e1, &p1, &p2);
4490 int dir2 = isPointerCmpExp(e.e2, &p3, &p4);
4491 if (dir1 == 0 || dir2 == 0)
4492 {
4493 result = null;
4494 return;
4495 }
4496
4497 //printf("FourPointerRelation %s\n", toChars());
4498
4499 UnionExp ue1 = void;
4500 UnionExp ue2 = void;
4501 UnionExp ue3 = void;
4502 UnionExp ue4 = void;
4503
4504 // Evaluate the first two pointers
4505 p1 = interpret(&ue1, p1, istate);
4506 if (exceptionOrCant(p1))
4507 return;
4508 p2 = interpret(&ue2, p2, istate);
4509 if (exceptionOrCant(p2))
4510 return;
4511 dinteger_t ofs1, ofs2;
4512 Expression agg1 = getAggregateFromPointer(p1, &ofs1);
4513 Expression agg2 = getAggregateFromPointer(p2, &ofs2);
4514
4515 if (!pointToSameMemoryBlock(agg1, agg2) && agg1.op != EXP.null_ && agg2.op != EXP.null_)
4516 {
4517 // Here it is either CANT_INTERPRET,
4518 // or an IsInside comparison returning false.
4519 p3 = interpret(&ue3, p3, istate);
4520 if (CTFEExp.isCantExp(p3))
4521 return;
4522 // Note that it is NOT legal for it to throw an exception!
4523 Expression except = null;
4524 if (exceptionOrCantInterpret(p3))
4525 except = p3;
4526 else
4527 {
4528 p4 = interpret(&ue4, p4, istate);
4529 if (CTFEExp.isCantExp(p4))
4530 {
4531 result = p4;
4532 return;
4533 }
4534 if (exceptionOrCantInterpret(p4))
4535 except = p4;
4536 }
4537 if (except)
4538 {
4539 e.error("comparison `%s` of pointers to unrelated memory blocks remains indeterminate at compile time because exception `%s` was thrown while evaluating `%s`", e.e1.toChars(), except.toChars(), e.e2.toChars());
4540 result = CTFEExp.cantexp;
4541 return;
4542 }
4543 dinteger_t ofs3, ofs4;
4544 Expression agg3 = getAggregateFromPointer(p3, &ofs3);
4545 Expression agg4 = getAggregateFromPointer(p4, &ofs4);
4546 // The valid cases are:
4547 // p1 > p2 && p3 > p4 (same direction, also for < && <)
4548 // p1 > p2 && p3 < p4 (different direction, also < && >)
4549 // Changing any > into >= doesn't affect the result
4550 if ((dir1 == dir2 && pointToSameMemoryBlock(agg1, agg4) && pointToSameMemoryBlock(agg2, agg3)) ||
4551 (dir1 != dir2 && pointToSameMemoryBlock(agg1, agg3) && pointToSameMemoryBlock(agg2, agg4)))
4552 {
4553 // it's a legal two-sided comparison
4554 emplaceExp!(IntegerExp)(pue, e.loc, (e.op == EXP.andAnd) ? 0 : 1, e.type);
4555 result = pue.exp();
4556 return;
4557 }
4558 // It's an invalid four-pointer comparison. Either the second
4559 // comparison is in the same direction as the first, or else
4560 // more than two memory blocks are involved (either two independent
4561 // invalid comparisons are present, or else agg3 == agg4).
4562 e.error("comparison `%s` of pointers to unrelated memory blocks is indeterminate at compile time, even when combined with `%s`.", e.e1.toChars(), e.e2.toChars());
4563 result = CTFEExp.cantexp;
4564 return;
4565 }
4566 // The first pointer expression didn't need special treatment, so we
4567 // we need to interpret the entire expression exactly as a normal && or ||.
4568 // This is easy because we haven't evaluated e2 at all yet, and we already
4569 // know it will return a bool.
4570 // But we mustn't evaluate the pointer expressions in e1 again, in case
4571 // they have side-effects.
4572 bool nott = false;
4573 Expression ex = e.e1;
4574 while (1)
4575 {
4576 if (auto ne = ex.isNotExp())
4577 {
4578 nott = !nott;
4579 ex = ne.e1;
4580 }
4581 else
4582 break;
4583 }
4584
4585 /** Negate relational operator, eg >= becomes <
4586 * Params:
4587 * op = comparison operator to negate
4588 * Returns:
4589 * negate operator
4590 */
4591 static EXP negateRelation(EXP op) pure
4592 {
4593 switch (op)
4594 {
4595 case EXP.greaterOrEqual: op = EXP.lessThan; break;
4596 case EXP.greaterThan: op = EXP.lessOrEqual; break;
4597 case EXP.lessOrEqual: op = EXP.greaterThan; break;
4598 case EXP.lessThan: op = EXP.greaterOrEqual; break;
4599 default: assert(0);
4600 }
4601 return op;
4602 }
4603
4604 const EXP cmpop = nott ? negateRelation(ex.op) : ex.op;
4605 const cmp = comparePointers(cmpop, agg1, ofs1, agg2, ofs2);
4606 // We already know this is a valid comparison.
4607 assert(cmp >= 0);
4608 if (e.op == EXP.andAnd && cmp == 1 || e.op == EXP.orOr && cmp == 0)
4609 {
4610 result = interpret(pue, e.e2, istate);
4611 return;
4612 }
4613 emplaceExp!(IntegerExp)(pue, e.loc, (e.op == EXP.andAnd) ? 0 : 1, e.type);
4614 result = pue.exp();
4615 }
4616
visit(LogicalExp e)4617 override void visit(LogicalExp e)
4618 {
4619 debug (LOG)
4620 {
4621 printf("%s LogicalExp::interpret() %s\n", e.loc.toChars(), e.toChars());
4622 }
4623 // Check for an insidePointer expression, evaluate it if so
4624 interpretFourPointerRelation(pue, e);
4625 if (result)
4626 return;
4627
4628 UnionExp ue1 = void;
4629 result = interpret(&ue1, e.e1, istate);
4630 if (exceptionOrCant(result))
4631 return;
4632
4633 bool res;
4634 const andand = e.op == EXP.andAnd;
4635 if (andand ? result.toBool().hasValue(false) : isTrueBool(result))
4636 res = !andand;
4637 else if (andand ? isTrueBool(result) : result.toBool().hasValue(false))
4638 {
4639 UnionExp ue2 = void;
4640 result = interpret(&ue2, e.e2, istate);
4641 if (exceptionOrCant(result))
4642 return;
4643 if (result.op == EXP.voidExpression)
4644 {
4645 assert(e.type.ty == Tvoid);
4646 result = null;
4647 return;
4648 }
4649 if (result.toBool().hasValue(false))
4650 res = false;
4651 else if (isTrueBool(result))
4652 res = true;
4653 else
4654 {
4655 e.error("`%s` does not evaluate to a `bool`", result.toChars());
4656 result = CTFEExp.cantexp;
4657 return;
4658 }
4659 }
4660 else
4661 {
4662 e.error("`%s` cannot be interpreted as a `bool`", result.toChars());
4663 result = CTFEExp.cantexp;
4664 return;
4665 }
4666 incUsageCtfe(istate, e.e2.loc);
4667
4668 if (goal != CTFEGoal.Nothing)
4669 {
4670 if (e.type.equals(Type.tbool))
4671 result = IntegerExp.createBool(res);
4672 else
4673 {
4674 emplaceExp!(IntegerExp)(pue, e.loc, res, e.type);
4675 result = pue.exp();
4676 }
4677 }
4678 }
4679
4680
4681 // Print a stack trace, starting from callingExp which called fd.
4682 // To shorten the stack trace, try to detect recursion.
showCtfeBackTrace(CallExp callingExp,FuncDeclaration fd)4683 private void showCtfeBackTrace(CallExp callingExp, FuncDeclaration fd)
4684 {
4685 if (ctfeGlobals.stackTraceCallsToSuppress > 0)
4686 {
4687 --ctfeGlobals.stackTraceCallsToSuppress;
4688 return;
4689 }
4690 errorSupplemental(callingExp.loc, "called from here: `%s`", callingExp.toChars());
4691 // Quit if it's not worth trying to compress the stack trace
4692 if (ctfeGlobals.callDepth < 6 || global.params.verbose)
4693 return;
4694 // Recursion happens if the current function already exists in the call stack.
4695 int numToSuppress = 0;
4696 int recurseCount = 0;
4697 int depthSoFar = 0;
4698 InterState* lastRecurse = istate;
4699 for (InterState* cur = istate; cur; cur = cur.caller)
4700 {
4701 if (cur.fd == fd)
4702 {
4703 ++recurseCount;
4704 numToSuppress = depthSoFar;
4705 lastRecurse = cur;
4706 }
4707 ++depthSoFar;
4708 }
4709 // We need at least three calls to the same function, to make compression worthwhile
4710 if (recurseCount < 2)
4711 return;
4712 // We found a useful recursion. Print all the calls involved in the recursion
4713 errorSupplemental(fd.loc, "%d recursive calls to function `%s`", recurseCount, fd.toChars());
4714 for (InterState* cur = istate; cur.fd != fd; cur = cur.caller)
4715 {
4716 errorSupplemental(cur.fd.loc, "recursively called from function `%s`", cur.fd.toChars());
4717 }
4718 // We probably didn't enter the recursion in this function.
4719 // Go deeper to find the real beginning.
4720 InterState* cur = istate;
4721 while (lastRecurse.caller && cur.fd == lastRecurse.caller.fd)
4722 {
4723 cur = cur.caller;
4724 lastRecurse = lastRecurse.caller;
4725 ++numToSuppress;
4726 }
4727 ctfeGlobals.stackTraceCallsToSuppress = numToSuppress;
4728 }
4729
visit(CallExp e)4730 override void visit(CallExp e)
4731 {
4732 debug (LOG)
4733 {
4734 printf("%s CallExp::interpret() %s\n", e.loc.toChars(), e.toChars());
4735 }
4736 Expression pthis = null;
4737 FuncDeclaration fd = null;
4738
4739 Expression ecall = interpretRegion(e.e1, istate);
4740 if (exceptionOrCant(ecall))
4741 return;
4742
4743 if (auto dve = ecall.isDotVarExp())
4744 {
4745 // Calling a member function
4746 pthis = dve.e1;
4747 fd = dve.var.isFuncDeclaration();
4748 assert(fd);
4749
4750 if (auto dte = pthis.isDotTypeExp())
4751 pthis = dte.e1;
4752 }
4753 else if (auto ve = ecall.isVarExp())
4754 {
4755 fd = ve.var.isFuncDeclaration();
4756 assert(fd);
4757
4758 // If `_d_HookTraceImpl` is found, resolve the underlying hook and replace `e` and `fd` with it.
4759 removeHookTraceImpl(e, fd);
4760
4761 if (fd.ident == Id.__ArrayPostblit || fd.ident == Id.__ArrayDtor)
4762 {
4763 assert(e.arguments.dim == 1);
4764 Expression ea = (*e.arguments)[0];
4765 // printf("1 ea = %s %s\n", ea.type.toChars(), ea.toChars());
4766 if (auto se = ea.isSliceExp())
4767 ea = se.e1;
4768 if (auto ce = ea.isCastExp())
4769 ea = ce.e1;
4770
4771 // printf("2 ea = %s, %s %s\n", ea.type.toChars(), EXPtoString(ea.op).ptr, ea.toChars());
4772 if (ea.op == EXP.variable || ea.op == EXP.symbolOffset)
4773 result = getVarExp(e.loc, istate, (cast(SymbolExp)ea).var, CTFEGoal.RValue);
4774 else if (auto ae = ea.isAddrExp())
4775 result = interpretRegion(ae.e1, istate);
4776
4777 // https://issues.dlang.org/show_bug.cgi?id=18871
4778 // https://issues.dlang.org/show_bug.cgi?id=18819
4779 else if (auto ale = ea.isArrayLiteralExp())
4780 result = interpretRegion(ale, istate);
4781
4782 else
4783 assert(0);
4784 if (CTFEExp.isCantExp(result))
4785 return;
4786
4787 if (fd.ident == Id.__ArrayPostblit)
4788 result = evaluatePostblit(istate, result);
4789 else
4790 result = evaluateDtor(istate, result);
4791 if (!result)
4792 result = CTFEExp.voidexp;
4793 return;
4794 }
4795 else if (fd.ident == Id._d_arraysetlengthT)
4796 {
4797 // In expressionsem.d `ea.length = eb;` got lowered to `_d_arraysetlengthT(ea, eb);`.
4798 // The following code will rewrite it back to `ea.length = eb` and then interpret that expression.
4799 assert(e.arguments.dim == 2);
4800
4801 Expression ea = (*e.arguments)[0];
4802 Expression eb = (*e.arguments)[1];
4803
4804 auto ale = ctfeEmplaceExp!ArrayLengthExp(e.loc, ea);
4805 ale.type = Type.tsize_t;
4806 AssignExp ae = ctfeEmplaceExp!AssignExp(e.loc, ale, eb);
4807 ae.type = ea.type;
4808
4809 // if (global.params.verbose)
4810 // message("interpret %s =>\n %s", e.toChars(), ae.toChars());
4811 result = interpretRegion(ae, istate);
4812 return;
4813 }
4814 else if (fd.ident == Id._d_arrayctor || fd.ident == Id._d_arraysetctor)
4815 {
4816 // In expressionsem.d `T[x] ea = eb;` was lowered to `_d_array{,set}ctor(ea[], eb[]);`.
4817 // The following code will rewrite it back to `ea = eb` and then interpret that expression.
4818 if (fd.ident == Id._d_arraysetctor)
4819 assert(e.arguments.dim == 2);
4820 else
4821 assert(e.arguments.dim == 3);
4822
4823 Expression ea = (*e.arguments)[0];
4824 if (ea.isCastExp)
4825 ea = ea.isCastExp.e1;
4826
4827 Expression eb = (*e.arguments)[1];
4828 if (eb.isCastExp && fd.ident == Id._d_arrayctor)
4829 eb = eb.isCastExp.e1;
4830
4831 ConstructExp ce = new ConstructExp(e.loc, ea, eb);
4832 ce.type = ea.type;
4833
4834 result = interpret(ce, istate);
4835 return;
4836 }
4837 }
4838 else if (auto soe = ecall.isSymOffExp())
4839 {
4840 fd = soe.var.isFuncDeclaration();
4841 assert(fd && soe.offset == 0);
4842 }
4843 else if (auto de = ecall.isDelegateExp())
4844 {
4845 // Calling a delegate
4846 fd = de.func;
4847 pthis = de.e1;
4848
4849 // Special handling for: &nestedfunc --> DelegateExp(VarExp(nestedfunc), nestedfunc)
4850 if (auto ve = pthis.isVarExp())
4851 if (ve.var == fd)
4852 pthis = null; // context is not necessary for CTFE
4853 }
4854 else if (auto fe = ecall.isFuncExp())
4855 {
4856 // Calling a delegate literal
4857 fd = fe.fd;
4858 }
4859 else
4860 {
4861 // delegate.funcptr()
4862 // others
4863 e.error("cannot call `%s` at compile time", e.toChars());
4864 result = CTFEExp.cantexp;
4865 return;
4866 }
4867 if (!fd)
4868 {
4869 e.error("CTFE internal error: cannot evaluate `%s` at compile time", e.toChars());
4870 result = CTFEExp.cantexp;
4871 return;
4872 }
4873 if (pthis)
4874 {
4875 // Member function call
4876
4877 // Currently this is satisfied because closure is not yet supported.
4878 assert(!fd.isNested() || fd.needThis());
4879
4880 if (pthis.op == EXP.typeid_)
4881 {
4882 pthis.error("static variable `%s` cannot be read at compile time", pthis.toChars());
4883 result = CTFEExp.cantexp;
4884 return;
4885 }
4886 assert(pthis);
4887
4888 if (pthis.op == EXP.null_)
4889 {
4890 assert(pthis.type.toBasetype().ty == Tclass);
4891 e.error("function call through null class reference `%s`", pthis.toChars());
4892 result = CTFEExp.cantexp;
4893 return;
4894 }
4895
4896 assert(pthis.op == EXP.structLiteral || pthis.op == EXP.classReference || pthis.op == EXP.type);
4897
4898 if (fd.isVirtual() && !e.directcall)
4899 {
4900 // Make a virtual function call.
4901 // Get the function from the vtable of the original class
4902 ClassDeclaration cd = pthis.isClassReferenceExp().originalClass();
4903
4904 // We can't just use the vtable index to look it up, because
4905 // vtables for interfaces don't get populated until the glue layer.
4906 fd = cd.findFunc(fd.ident, fd.type.isTypeFunction());
4907 assert(fd);
4908 }
4909 }
4910
4911 if (fd && fd.semanticRun >= PASS.semantic3done && fd.hasSemantic3Errors())
4912 {
4913 e.error("CTFE failed because of previous errors in `%s`", fd.toChars());
4914 result = CTFEExp.cantexp;
4915 return;
4916 }
4917
4918 // Check for built-in functions
4919 result = evaluateIfBuiltin(pue, istate, e.loc, fd, e.arguments, pthis);
4920 if (result)
4921 return;
4922
4923 if (!fd.fbody)
4924 {
4925 e.error("`%s` cannot be interpreted at compile time, because it has no available source code", fd.toChars());
4926 result = CTFEExp.showcontext;
4927 return;
4928 }
4929
4930 result = interpretFunction(pue, fd, istate, e.arguments, pthis);
4931 if (result.op == EXP.voidExpression)
4932 return;
4933 if (!exceptionOrCantInterpret(result))
4934 {
4935 if (goal != CTFEGoal.LValue) // Peel off CTFE reference if it's unnecessary
4936 {
4937 if (result == pue.exp())
4938 result = pue.copy();
4939 result = interpret(pue, result, istate);
4940 }
4941 }
4942 if (!exceptionOrCantInterpret(result))
4943 {
4944 result = paintTypeOntoLiteral(pue, e.type, result);
4945 result.loc = e.loc;
4946 }
4947 else if (CTFEExp.isCantExp(result) && !global.gag)
4948 showCtfeBackTrace(e, fd); // Print a stack trace.
4949 }
4950
visit(CommaExp e)4951 override void visit(CommaExp e)
4952 {
4953 debug (LOG)
4954 {
4955 printf("%s CommaExp::interpret() %s\n", e.loc.toChars(), e.toChars());
4956 }
4957
4958 // If it creates a variable, and there's no context for
4959 // the variable to be created in, we need to create one now.
4960 InterState istateComma;
4961 if (!istate && firstComma(e.e1).op == EXP.declaration)
4962 {
4963 ctfeGlobals.stack.startFrame(null);
4964 istate = &istateComma;
4965 }
4966
4967 void endTempStackFrame()
4968 {
4969 // If we created a temporary stack frame, end it now.
4970 if (istate == &istateComma)
4971 ctfeGlobals.stack.endFrame();
4972 }
4973
4974 result = CTFEExp.cantexp;
4975
4976 // If the comma returns a temporary variable, it needs to be an lvalue
4977 // (this is particularly important for struct constructors)
4978 if (e.e1.op == EXP.declaration &&
4979 e.e2.op == EXP.variable &&
4980 e.e1.isDeclarationExp().declaration == e.e2.isVarExp().var &&
4981 e.e2.isVarExp().var.storage_class & STC.ctfe)
4982 {
4983 VarExp ve = e.e2.isVarExp();
4984 VarDeclaration v = ve.var.isVarDeclaration();
4985 ctfeGlobals.stack.push(v);
4986 if (!v._init && !getValue(v))
4987 {
4988 setValue(v, copyLiteral(v.type.defaultInitLiteral(e.loc)).copy());
4989 }
4990 if (!getValue(v))
4991 {
4992 Expression newval = v._init.initializerToExpression();
4993 // Bug 4027. Copy constructors are a weird case where the
4994 // initializer is a void function (the variable is modified
4995 // through a reference parameter instead).
4996 newval = interpretRegion(newval, istate);
4997 if (exceptionOrCant(newval))
4998 return endTempStackFrame();
4999 if (newval.op != EXP.voidExpression)
5000 {
5001 // v isn't necessarily null.
5002 setValueWithoutChecking(v, copyLiteral(newval).copy());
5003 }
5004 }
5005 }
5006 else
5007 {
5008 UnionExp ue = void;
5009 auto e1 = interpret(&ue, e.e1, istate, CTFEGoal.Nothing);
5010 if (exceptionOrCant(e1))
5011 return endTempStackFrame();
5012 }
5013 result = interpret(pue, e.e2, istate, goal);
5014 return endTempStackFrame();
5015 }
5016
visit(CondExp e)5017 override void visit(CondExp e)
5018 {
5019 debug (LOG)
5020 {
5021 printf("%s CondExp::interpret() %s\n", e.loc.toChars(), e.toChars());
5022 }
5023 UnionExp uecond = void;
5024 Expression econd;
5025 econd = interpret(&uecond, e.econd, istate);
5026 if (exceptionOrCant(econd))
5027 return;
5028
5029 if (isPointer(e.econd.type))
5030 {
5031 if (econd.op != EXP.null_)
5032 {
5033 econd = IntegerExp.createBool(true);
5034 }
5035 }
5036
5037 if (isTrueBool(econd))
5038 {
5039 result = interpret(pue, e.e1, istate, goal);
5040 incUsageCtfe(istate, e.e1.loc);
5041 }
5042 else if (econd.toBool().hasValue(false))
5043 {
5044 result = interpret(pue, e.e2, istate, goal);
5045 incUsageCtfe(istate, e.e2.loc);
5046 }
5047 else
5048 {
5049 e.error("`%s` does not evaluate to boolean result at compile time", e.econd.toChars());
5050 result = CTFEExp.cantexp;
5051 }
5052 }
5053
visit(ArrayLengthExp e)5054 override void visit(ArrayLengthExp e)
5055 {
5056 debug (LOG)
5057 {
5058 printf("%s ArrayLengthExp::interpret() %s\n", e.loc.toChars(), e.toChars());
5059 }
5060 UnionExp ue1;
5061 Expression e1 = interpret(&ue1, e.e1, istate);
5062 assert(e1);
5063 if (exceptionOrCant(e1))
5064 return;
5065 if (e1.op != EXP.string_ && e1.op != EXP.arrayLiteral && e1.op != EXP.slice && e1.op != EXP.null_)
5066 {
5067 e.error("`%s` cannot be evaluated at compile time", e.toChars());
5068 result = CTFEExp.cantexp;
5069 return;
5070 }
5071 emplaceExp!(IntegerExp)(pue, e.loc, resolveArrayLength(e1), e.type);
5072 result = pue.exp();
5073 }
5074
5075 /**
5076 * Interpret the vector expression as an array literal.
5077 * Params:
5078 * pue = non-null pointer to temporary storage that can be used to store the return value
5079 * e = Expression to interpret
5080 * Returns:
5081 * resulting array literal or 'e' if unable to interpret
5082 */
interpretVectorToArray(UnionExp * pue,VectorExp e)5083 static Expression interpretVectorToArray(UnionExp* pue, VectorExp e)
5084 {
5085 if (auto ale = e.e1.isArrayLiteralExp())
5086 return ale; // it's already an array literal
5087 if (e.e1.op == EXP.int64 || e.e1.op == EXP.float64)
5088 {
5089 // Convert literal __vector(int) -> __vector([array])
5090 auto elements = new Expressions(e.dim);
5091 foreach (ref element; *elements)
5092 element = copyLiteral(e.e1).copy();
5093 auto type = (e.type.ty == Tvector) ? e.type.isTypeVector().basetype : e.type.isTypeSArray();
5094 assert(type);
5095 emplaceExp!(ArrayLiteralExp)(pue, e.loc, type, elements);
5096 auto ale = pue.exp().isArrayLiteralExp();
5097 ale.ownedByCtfe = OwnedBy.ctfe;
5098 return ale;
5099 }
5100 return e;
5101 }
5102
visit(VectorExp e)5103 override void visit(VectorExp e)
5104 {
5105 debug (LOG)
5106 {
5107 printf("%s VectorExp::interpret() %s\n", e.loc.toChars(), e.toChars());
5108 }
5109 if (e.ownedByCtfe >= OwnedBy.ctfe) // We've already interpreted all the elements
5110 {
5111 result = e;
5112 return;
5113 }
5114 Expression e1 = interpret(pue, e.e1, istate);
5115 assert(e1);
5116 if (exceptionOrCant(e1))
5117 return;
5118 if (e1.op != EXP.arrayLiteral && e1.op != EXP.int64 && e1.op != EXP.float64)
5119 {
5120 e.error("`%s` cannot be evaluated at compile time", e.toChars());
5121 result = CTFEExp.cantexp;
5122 return;
5123 }
5124 if (e1 == pue.exp())
5125 e1 = pue.copy();
5126 emplaceExp!(VectorExp)(pue, e.loc, e1, e.to);
5127 auto ve = pue.exp().isVectorExp();
5128 ve.type = e.type;
5129 ve.dim = e.dim;
5130 ve.ownedByCtfe = OwnedBy.ctfe;
5131 result = ve;
5132 }
5133
visit(VectorArrayExp e)5134 override void visit(VectorArrayExp e)
5135 {
5136 debug (LOG)
5137 {
5138 printf("%s VectorArrayExp::interpret() %s\n", e.loc.toChars(), e.toChars());
5139 }
5140 Expression e1 = interpret(pue, e.e1, istate);
5141 assert(e1);
5142 if (exceptionOrCant(e1))
5143 return;
5144 if (auto ve = e1.isVectorExp())
5145 {
5146 result = interpretVectorToArray(pue, ve);
5147 if (result.op != EXP.vector)
5148 return;
5149 }
5150 e.error("`%s` cannot be evaluated at compile time", e.toChars());
5151 result = CTFEExp.cantexp;
5152 }
5153
visit(DelegatePtrExp e)5154 override void visit(DelegatePtrExp e)
5155 {
5156 debug (LOG)
5157 {
5158 printf("%s DelegatePtrExp::interpret() %s\n", e.loc.toChars(), e.toChars());
5159 }
5160 Expression e1 = interpret(pue, e.e1, istate);
5161 assert(e1);
5162 if (exceptionOrCant(e1))
5163 return;
5164 e.error("`%s` cannot be evaluated at compile time", e.toChars());
5165 result = CTFEExp.cantexp;
5166 }
5167
visit(DelegateFuncptrExp e)5168 override void visit(DelegateFuncptrExp e)
5169 {
5170 debug (LOG)
5171 {
5172 printf("%s DelegateFuncptrExp::interpret() %s\n", e.loc.toChars(), e.toChars());
5173 }
5174 Expression e1 = interpret(pue, e.e1, istate);
5175 assert(e1);
5176 if (exceptionOrCant(e1))
5177 return;
5178 e.error("`%s` cannot be evaluated at compile time", e.toChars());
5179 result = CTFEExp.cantexp;
5180 }
5181
resolveIndexing(IndexExp e,InterState * istate,Expression * pagg,uinteger_t * pidx,bool modify)5182 static bool resolveIndexing(IndexExp e, InterState* istate, Expression* pagg, uinteger_t* pidx, bool modify)
5183 {
5184 assert(e.e1.type.toBasetype().ty != Taarray);
5185
5186 if (e.e1.type.toBasetype().ty == Tpointer)
5187 {
5188 // Indexing a pointer. Note that there is no $ in this case.
5189 Expression e1 = interpretRegion(e.e1, istate);
5190 if (exceptionOrCantInterpret(e1))
5191 return false;
5192
5193 Expression e2 = interpretRegion(e.e2, istate);
5194 if (exceptionOrCantInterpret(e2))
5195 return false;
5196 sinteger_t indx = e2.toInteger();
5197
5198 dinteger_t ofs;
5199 Expression agg = getAggregateFromPointer(e1, &ofs);
5200
5201 if (agg.op == EXP.null_)
5202 {
5203 e.error("cannot index through null pointer `%s`", e.e1.toChars());
5204 return false;
5205 }
5206 if (agg.op == EXP.int64)
5207 {
5208 e.error("cannot index through invalid pointer `%s` of value `%s`", e.e1.toChars(), e1.toChars());
5209 return false;
5210 }
5211 // Pointer to a non-array variable
5212 if (agg.op == EXP.symbolOffset)
5213 {
5214 e.error("mutable variable `%s` cannot be %s at compile time, even through a pointer", cast(char*)(modify ? "modified" : "read"), agg.isSymOffExp().var.toChars());
5215 return false;
5216 }
5217
5218 if (agg.op == EXP.arrayLiteral || agg.op == EXP.string_)
5219 {
5220 dinteger_t len = resolveArrayLength(agg);
5221 if (ofs + indx >= len)
5222 {
5223 e.error("pointer index `[%lld]` exceeds allocated memory block `[0..%lld]`", ofs + indx, len);
5224 return false;
5225 }
5226 }
5227 else
5228 {
5229 if (ofs + indx != 0)
5230 {
5231 e.error("pointer index `[%lld]` lies outside memory block `[0..1]`", ofs + indx);
5232 return false;
5233 }
5234 }
5235 *pagg = agg;
5236 *pidx = ofs + indx;
5237 return true;
5238 }
5239
5240 Expression e1 = interpretRegion(e.e1, istate);
5241 if (exceptionOrCantInterpret(e1))
5242 return false;
5243 if (e1.op == EXP.null_)
5244 {
5245 e.error("cannot index null array `%s`", e.e1.toChars());
5246 return false;
5247 }
5248 if (auto ve = e1.isVectorExp())
5249 {
5250 UnionExp ue = void;
5251 e1 = interpretVectorToArray(&ue, ve);
5252 e1 = (e1 == ue.exp()) ? ue.copy() : e1;
5253 }
5254
5255 // Set the $ variable, and find the array literal to modify
5256 dinteger_t len;
5257 if (e1.op == EXP.variable && e1.type.toBasetype().ty == Tsarray)
5258 len = e1.type.toBasetype().isTypeSArray().dim.toInteger();
5259 else
5260 {
5261 if (e1.op != EXP.arrayLiteral && e1.op != EXP.string_ && e1.op != EXP.slice && e1.op != EXP.vector)
5262 {
5263 e.error("cannot determine length of `%s` at compile time", e.e1.toChars());
5264 return false;
5265 }
5266 len = resolveArrayLength(e1);
5267 }
5268
5269 if (e.lengthVar)
5270 {
5271 Expression dollarExp = ctfeEmplaceExp!IntegerExp(e.loc, len, Type.tsize_t);
5272 ctfeGlobals.stack.push(e.lengthVar);
5273 setValue(e.lengthVar, dollarExp);
5274 }
5275 Expression e2 = interpretRegion(e.e2, istate);
5276 if (e.lengthVar)
5277 ctfeGlobals.stack.pop(e.lengthVar); // $ is defined only inside []
5278 if (exceptionOrCantInterpret(e2))
5279 return false;
5280 if (e2.op != EXP.int64)
5281 {
5282 e.error("CTFE internal error: non-integral index `[%s]`", e.e2.toChars());
5283 return false;
5284 }
5285
5286 if (auto se = e1.isSliceExp())
5287 {
5288 // Simplify index of slice: agg[lwr..upr][indx] --> agg[indx']
5289 uinteger_t index = e2.toInteger();
5290 uinteger_t ilwr = se.lwr.toInteger();
5291 uinteger_t iupr = se.upr.toInteger();
5292
5293 if (index > iupr - ilwr)
5294 {
5295 e.error("index %llu exceeds array length %llu", index, iupr - ilwr);
5296 return false;
5297 }
5298 *pagg = e1.isSliceExp().e1;
5299 *pidx = index + ilwr;
5300 }
5301 else
5302 {
5303 *pagg = e1;
5304 *pidx = e2.toInteger();
5305 if (len <= *pidx)
5306 {
5307 e.error("array index %lld is out of bounds `[0..%lld]`", *pidx, len);
5308 return false;
5309 }
5310 }
5311 return true;
5312 }
5313
visit(IndexExp e)5314 override void visit(IndexExp e)
5315 {
5316 debug (LOG)
5317 {
5318 printf("%s IndexExp::interpret() %s, goal = %d\n", e.loc.toChars(), e.toChars(), goal);
5319 }
5320 if (e.e1.type.toBasetype().ty == Tpointer)
5321 {
5322 Expression agg;
5323 uinteger_t indexToAccess;
5324 if (!resolveIndexing(e, istate, &agg, &indexToAccess, false))
5325 {
5326 result = CTFEExp.cantexp;
5327 return;
5328 }
5329 if (agg.op == EXP.arrayLiteral || agg.op == EXP.string_)
5330 {
5331 if (goal == CTFEGoal.LValue)
5332 {
5333 // if we need a reference, IndexExp shouldn't be interpreting
5334 // the expression to a value, it should stay as a reference
5335 emplaceExp!(IndexExp)(pue, e.loc, agg, ctfeEmplaceExp!IntegerExp(e.e2.loc, indexToAccess, e.e2.type));
5336 result = pue.exp();
5337 result.type = e.type;
5338 return;
5339 }
5340 result = ctfeIndex(pue, e.loc, e.type, agg, indexToAccess);
5341 return;
5342 }
5343 else
5344 {
5345 assert(indexToAccess == 0);
5346 result = interpretRegion(agg, istate, goal);
5347 if (exceptionOrCant(result))
5348 return;
5349 result = paintTypeOntoLiteral(pue, e.type, result);
5350 return;
5351 }
5352 }
5353
5354 if (e.e1.type.toBasetype().ty == Taarray)
5355 {
5356 Expression e1 = interpretRegion(e.e1, istate);
5357 if (exceptionOrCant(e1))
5358 return;
5359 if (e1.op == EXP.null_)
5360 {
5361 if (goal == CTFEGoal.LValue && e1.type.ty == Taarray && e.modifiable)
5362 {
5363 assert(0); // does not reach here?
5364 }
5365 e.error("cannot index null array `%s`", e.e1.toChars());
5366 result = CTFEExp.cantexp;
5367 return;
5368 }
5369 Expression e2 = interpretRegion(e.e2, istate);
5370 if (exceptionOrCant(e2))
5371 return;
5372
5373 if (goal == CTFEGoal.LValue)
5374 {
5375 // Pointer or reference of a scalar type
5376 if (e1 == e.e1 && e2 == e.e2)
5377 result = e;
5378 else
5379 {
5380 emplaceExp!(IndexExp)(pue, e.loc, e1, e2);
5381 result = pue.exp();
5382 result.type = e.type;
5383 }
5384 return;
5385 }
5386
5387 assert(e1.op == EXP.assocArrayLiteral);
5388 UnionExp e2tmp = void;
5389 e2 = resolveSlice(e2, &e2tmp);
5390 result = findKeyInAA(e.loc, e1.isAssocArrayLiteralExp(), e2);
5391 if (!result)
5392 {
5393 e.error("key `%s` not found in associative array `%s`", e2.toChars(), e.e1.toChars());
5394 result = CTFEExp.cantexp;
5395 }
5396 return;
5397 }
5398
5399 Expression agg;
5400 uinteger_t indexToAccess;
5401 if (!resolveIndexing(e, istate, &agg, &indexToAccess, false))
5402 {
5403 result = CTFEExp.cantexp;
5404 return;
5405 }
5406
5407 if (goal == CTFEGoal.LValue)
5408 {
5409 Expression e2 = ctfeEmplaceExp!IntegerExp(e.e2.loc, indexToAccess, Type.tsize_t);
5410 emplaceExp!(IndexExp)(pue, e.loc, agg, e2);
5411 result = pue.exp();
5412 result.type = e.type;
5413 return;
5414 }
5415
5416 result = ctfeIndex(pue, e.loc, e.type, agg, indexToAccess);
5417 if (exceptionOrCant(result))
5418 return;
5419 if (result.op == EXP.void_)
5420 {
5421 e.error("`%s` is used before initialized", e.toChars());
5422 errorSupplemental(result.loc, "originally uninitialized here");
5423 result = CTFEExp.cantexp;
5424 return;
5425 }
5426 if (result == pue.exp())
5427 result = result.copy();
5428 }
5429
visit(SliceExp e)5430 override void visit(SliceExp e)
5431 {
5432 debug (LOG)
5433 {
5434 printf("%s SliceExp::interpret() %s\n", e.loc.toChars(), e.toChars());
5435 }
5436 if (e.e1.type.toBasetype().ty == Tpointer)
5437 {
5438 // Slicing a pointer. Note that there is no $ in this case.
5439 Expression e1 = interpretRegion(e.e1, istate);
5440 if (exceptionOrCant(e1))
5441 return;
5442 if (e1.op == EXP.int64)
5443 {
5444 e.error("cannot slice invalid pointer `%s` of value `%s`", e.e1.toChars(), e1.toChars());
5445 result = CTFEExp.cantexp;
5446 return;
5447 }
5448
5449 /* Evaluate lower and upper bounds of slice
5450 */
5451 Expression lwr = interpretRegion(e.lwr, istate);
5452 if (exceptionOrCant(lwr))
5453 return;
5454 Expression upr = interpretRegion(e.upr, istate);
5455 if (exceptionOrCant(upr))
5456 return;
5457 uinteger_t ilwr = lwr.toInteger();
5458 uinteger_t iupr = upr.toInteger();
5459
5460 dinteger_t ofs;
5461 Expression agg = getAggregateFromPointer(e1, &ofs);
5462 ilwr += ofs;
5463 iupr += ofs;
5464 if (agg.op == EXP.null_)
5465 {
5466 if (iupr == ilwr)
5467 {
5468 result = ctfeEmplaceExp!NullExp(e.loc);
5469 result.type = e.type;
5470 return;
5471 }
5472 e.error("cannot slice null pointer `%s`", e.e1.toChars());
5473 result = CTFEExp.cantexp;
5474 return;
5475 }
5476 if (agg.op == EXP.symbolOffset)
5477 {
5478 e.error("slicing pointers to static variables is not supported in CTFE");
5479 result = CTFEExp.cantexp;
5480 return;
5481 }
5482 if (agg.op != EXP.arrayLiteral && agg.op != EXP.string_)
5483 {
5484 e.error("pointer `%s` cannot be sliced at compile time (it does not point to an array)", e.e1.toChars());
5485 result = CTFEExp.cantexp;
5486 return;
5487 }
5488 assert(agg.op == EXP.arrayLiteral || agg.op == EXP.string_);
5489 dinteger_t len = ArrayLength(Type.tsize_t, agg).exp().toInteger();
5490 //Type *pointee = ((TypePointer *)agg.type)->next;
5491 if (sliceBoundsCheck(0, len, ilwr, iupr))
5492 {
5493 e.error("pointer slice `[%lld..%lld]` exceeds allocated memory block `[0..%lld]`", ilwr, iupr, len);
5494 result = CTFEExp.cantexp;
5495 return;
5496 }
5497 if (ofs != 0)
5498 {
5499 lwr = ctfeEmplaceExp!IntegerExp(e.loc, ilwr, lwr.type);
5500 upr = ctfeEmplaceExp!IntegerExp(e.loc, iupr, upr.type);
5501 }
5502 emplaceExp!(SliceExp)(pue, e.loc, agg, lwr, upr);
5503 result = pue.exp();
5504 result.type = e.type;
5505 return;
5506 }
5507
5508 CTFEGoal goal1 = CTFEGoal.RValue;
5509 if (goal == CTFEGoal.LValue)
5510 {
5511 if (e.e1.type.toBasetype().ty == Tsarray)
5512 if (auto ve = e.e1.isVarExp())
5513 if (auto vd = ve.var.isVarDeclaration())
5514 if (vd.storage_class & STC.ref_)
5515 goal1 = CTFEGoal.LValue;
5516 }
5517 Expression e1 = interpret(e.e1, istate, goal1);
5518 if (exceptionOrCant(e1))
5519 return;
5520
5521 if (!e.lwr)
5522 {
5523 result = paintTypeOntoLiteral(pue, e.type, e1);
5524 return;
5525 }
5526 if (auto ve = e1.isVectorExp())
5527 {
5528 e1 = interpretVectorToArray(pue, ve);
5529 e1 = (e1 == pue.exp()) ? pue.copy() : e1;
5530 }
5531
5532 /* Set dollar to the length of the array
5533 */
5534 uinteger_t dollar;
5535 if ((e1.op == EXP.variable || e1.op == EXP.dotVariable) && e1.type.toBasetype().ty == Tsarray)
5536 dollar = e1.type.toBasetype().isTypeSArray().dim.toInteger();
5537 else
5538 {
5539 if (e1.op != EXP.arrayLiteral && e1.op != EXP.string_ && e1.op != EXP.null_ && e1.op != EXP.slice && e1.op != EXP.vector)
5540 {
5541 e.error("cannot determine length of `%s` at compile time", e1.toChars());
5542 result = CTFEExp.cantexp;
5543 return;
5544 }
5545 dollar = resolveArrayLength(e1);
5546 }
5547
5548 /* Set the $ variable
5549 */
5550 if (e.lengthVar)
5551 {
5552 auto dollarExp = ctfeEmplaceExp!IntegerExp(e.loc, dollar, Type.tsize_t);
5553 ctfeGlobals.stack.push(e.lengthVar);
5554 setValue(e.lengthVar, dollarExp);
5555 }
5556
5557 /* Evaluate lower and upper bounds of slice
5558 */
5559 Expression lwr = interpretRegion(e.lwr, istate);
5560 if (exceptionOrCant(lwr))
5561 {
5562 if (e.lengthVar)
5563 ctfeGlobals.stack.pop(e.lengthVar);
5564 return;
5565 }
5566 Expression upr = interpretRegion(e.upr, istate);
5567 if (exceptionOrCant(upr))
5568 {
5569 if (e.lengthVar)
5570 ctfeGlobals.stack.pop(e.lengthVar);
5571 return;
5572 }
5573 if (e.lengthVar)
5574 ctfeGlobals.stack.pop(e.lengthVar); // $ is defined only inside [L..U]
5575
5576 uinteger_t ilwr = lwr.toInteger();
5577 uinteger_t iupr = upr.toInteger();
5578 if (e1.op == EXP.null_)
5579 {
5580 if (ilwr == 0 && iupr == 0)
5581 {
5582 result = e1;
5583 return;
5584 }
5585 e1.error("slice `[%llu..%llu]` is out of bounds", ilwr, iupr);
5586 result = CTFEExp.cantexp;
5587 return;
5588 }
5589 if (auto se = e1.isSliceExp())
5590 {
5591 // Simplify slice of slice:
5592 // aggregate[lo1..up1][lwr..upr] ---> aggregate[lwr'..upr']
5593 uinteger_t lo1 = se.lwr.toInteger();
5594 uinteger_t up1 = se.upr.toInteger();
5595 if (sliceBoundsCheck(0, up1 - lo1, ilwr, iupr))
5596 {
5597 e.error("slice `[%llu..%llu]` exceeds array bounds `[0..%llu]`", ilwr, iupr, up1 - lo1);
5598 result = CTFEExp.cantexp;
5599 return;
5600 }
5601 ilwr += lo1;
5602 iupr += lo1;
5603 emplaceExp!(SliceExp)(pue, e.loc, se.e1,
5604 ctfeEmplaceExp!IntegerExp(e.loc, ilwr, lwr.type),
5605 ctfeEmplaceExp!IntegerExp(e.loc, iupr, upr.type));
5606 result = pue.exp();
5607 result.type = e.type;
5608 return;
5609 }
5610 if (e1.op == EXP.arrayLiteral || e1.op == EXP.string_)
5611 {
5612 if (sliceBoundsCheck(0, dollar, ilwr, iupr))
5613 {
5614 e.error("slice `[%lld..%lld]` exceeds array bounds `[0..%lld]`", ilwr, iupr, dollar);
5615 result = CTFEExp.cantexp;
5616 return;
5617 }
5618 }
5619 emplaceExp!(SliceExp)(pue, e.loc, e1, lwr, upr);
5620 result = pue.exp();
5621 result.type = e.type;
5622 }
5623
visit(InExp e)5624 override void visit(InExp e)
5625 {
5626 debug (LOG)
5627 {
5628 printf("%s InExp::interpret() %s\n", e.loc.toChars(), e.toChars());
5629 }
5630 Expression e1 = interpretRegion(e.e1, istate);
5631 if (exceptionOrCant(e1))
5632 return;
5633 Expression e2 = interpretRegion(e.e2, istate);
5634 if (exceptionOrCant(e2))
5635 return;
5636 if (e2.op == EXP.null_)
5637 {
5638 emplaceExp!(NullExp)(pue, e.loc, e.type);
5639 result = pue.exp();
5640 return;
5641 }
5642 if (e2.op != EXP.assocArrayLiteral)
5643 {
5644 e.error("`%s` cannot be interpreted at compile time", e.toChars());
5645 result = CTFEExp.cantexp;
5646 return;
5647 }
5648
5649 e1 = resolveSlice(e1);
5650 result = findKeyInAA(e.loc, e2.isAssocArrayLiteralExp(), e1);
5651 if (exceptionOrCant(result))
5652 return;
5653 if (!result)
5654 {
5655 emplaceExp!(NullExp)(pue, e.loc, e.type);
5656 result = pue.exp();
5657 }
5658 else
5659 {
5660 // Create a CTFE pointer &aa[index]
5661 result = ctfeEmplaceExp!IndexExp(e.loc, e2, e1);
5662 result.type = e.type.nextOf();
5663 emplaceExp!(AddrExp)(pue, e.loc, result, e.type);
5664 result = pue.exp();
5665 }
5666 }
5667
visit(CatExp e)5668 override void visit(CatExp e)
5669 {
5670 debug (LOG)
5671 {
5672 printf("%s CatExp::interpret() %s\n", e.loc.toChars(), e.toChars());
5673 }
5674
5675 UnionExp ue1 = void;
5676 Expression e1 = interpret(&ue1, e.e1, istate);
5677 if (exceptionOrCant(e1))
5678 return;
5679
5680 UnionExp ue2 = void;
5681 Expression e2 = interpret(&ue2, e.e2, istate);
5682 if (exceptionOrCant(e2))
5683 return;
5684
5685 UnionExp e1tmp = void;
5686 e1 = resolveSlice(e1, &e1tmp);
5687
5688 UnionExp e2tmp = void;
5689 e2 = resolveSlice(e2, &e2tmp);
5690
5691 /* e1 and e2 can't go on the stack because of x~[y] and [x]~y will
5692 * result in [x,y] and then x or y is on the stack.
5693 * But if they are both strings, we can, because it isn't the x~[y] case.
5694 */
5695 if (!(e1.op == EXP.string_ && e2.op == EXP.string_))
5696 {
5697 if (e1 == ue1.exp())
5698 e1 = ue1.copy();
5699 if (e2 == ue2.exp())
5700 e2 = ue2.copy();
5701 }
5702
5703 *pue = ctfeCat(e.loc, e.type, e1, e2);
5704 result = pue.exp();
5705
5706 if (CTFEExp.isCantExp(result))
5707 {
5708 e.error("`%s` cannot be interpreted at compile time", e.toChars());
5709 return;
5710 }
5711 // We know we still own it, because we interpreted both e1 and e2
5712 if (auto ale = result.isArrayLiteralExp())
5713 {
5714 ale.ownedByCtfe = OwnedBy.ctfe;
5715
5716 // https://issues.dlang.org/show_bug.cgi?id=14686
5717 foreach (elem; *ale.elements)
5718 {
5719 Expression ex = evaluatePostblit(istate, elem);
5720 if (exceptionOrCant(ex))
5721 return;
5722 }
5723 }
5724 else if (auto se = result.isStringExp())
5725 se.ownedByCtfe = OwnedBy.ctfe;
5726 }
5727
visit(DeleteExp e)5728 override void visit(DeleteExp e)
5729 {
5730 debug (LOG)
5731 {
5732 printf("%s DeleteExp::interpret() %s\n", e.loc.toChars(), e.toChars());
5733 }
5734 result = interpretRegion(e.e1, istate);
5735 if (exceptionOrCant(result))
5736 return;
5737
5738 if (result.op == EXP.null_)
5739 {
5740 result = CTFEExp.voidexp;
5741 return;
5742 }
5743
5744 auto tb = e.e1.type.toBasetype();
5745 switch (tb.ty)
5746 {
5747 case Tclass:
5748 if (result.op != EXP.classReference)
5749 {
5750 e.error("`delete` on invalid class reference `%s`", result.toChars());
5751 result = CTFEExp.cantexp;
5752 return;
5753 }
5754
5755 auto cre = result.isClassReferenceExp();
5756 auto cd = cre.originalClass();
5757
5758 // Find dtor(s) in inheritance chain
5759 do
5760 {
5761 if (cd.dtor)
5762 {
5763 result = interpretFunction(pue, cd.dtor, istate, null, cre);
5764 if (exceptionOrCant(result))
5765 return;
5766
5767 // Dtors of Non-extern(D) classes use implicit chaining (like structs)
5768 import dmd.aggregate : ClassKind;
5769 if (cd.classKind != ClassKind.d)
5770 break;
5771 }
5772
5773 // Emulate manual chaining as done in rt_finalize2
5774 cd = cd.baseClass;
5775
5776 } while (cd); // Stop after Object
5777
5778 break;
5779
5780 default:
5781 assert(0);
5782 }
5783 result = CTFEExp.voidexp;
5784 }
5785
visit(CastExp e)5786 override void visit(CastExp e)
5787 {
5788 debug (LOG)
5789 {
5790 printf("%s CastExp::interpret() %s\n", e.loc.toChars(), e.toChars());
5791 }
5792 Expression e1 = interpretRegion(e.e1, istate, goal);
5793 if (exceptionOrCant(e1))
5794 return;
5795 // If the expression has been cast to void, do nothing.
5796 if (e.to.ty == Tvoid)
5797 {
5798 result = CTFEExp.voidexp;
5799 return;
5800 }
5801 if (e.to.ty == Tpointer && e1.op != EXP.null_)
5802 {
5803 Type pointee = (cast(TypePointer)e.type).next;
5804 // Implement special cases of normally-unsafe casts
5805 if (e1.op == EXP.int64)
5806 {
5807 // Happens with Windows HANDLEs, for example.
5808 result = paintTypeOntoLiteral(pue, e.to, e1);
5809 return;
5810 }
5811
5812 bool castToSarrayPointer = false;
5813 bool castBackFromVoid = false;
5814 if (e1.type.ty == Tarray || e1.type.ty == Tsarray || e1.type.ty == Tpointer)
5815 {
5816 // Check for unsupported type painting operations
5817 // For slices, we need the type being sliced,
5818 // since it may have already been type painted
5819 Type elemtype = e1.type.nextOf();
5820 if (auto se = e1.isSliceExp())
5821 elemtype = se.e1.type.nextOf();
5822
5823 // Allow casts from X* to void *, and X** to void** for any X.
5824 // But don't allow cast from X* to void**.
5825 // So, we strip all matching * from source and target to find X.
5826 // Allow casts to X* from void* only if the 'void' was originally an X;
5827 // we check this later on.
5828 Type ultimatePointee = pointee;
5829 Type ultimateSrc = elemtype;
5830 while (ultimatePointee.ty == Tpointer && ultimateSrc.ty == Tpointer)
5831 {
5832 ultimatePointee = ultimatePointee.nextOf();
5833 ultimateSrc = ultimateSrc.nextOf();
5834 }
5835 if (ultimatePointee.ty == Tsarray && ultimatePointee.nextOf().equivalent(ultimateSrc))
5836 {
5837 castToSarrayPointer = true;
5838 }
5839 else if (ultimatePointee.ty != Tvoid && ultimateSrc.ty != Tvoid && !isSafePointerCast(elemtype, pointee))
5840 {
5841 e.error("reinterpreting cast from `%s*` to `%s*` is not supported in CTFE", elemtype.toChars(), pointee.toChars());
5842 result = CTFEExp.cantexp;
5843 return;
5844 }
5845 if (ultimateSrc.ty == Tvoid)
5846 castBackFromVoid = true;
5847 }
5848
5849 if (auto se = e1.isSliceExp())
5850 {
5851 if (se.e1.op == EXP.null_)
5852 {
5853 result = paintTypeOntoLiteral(pue, e.type, se.e1);
5854 return;
5855 }
5856 // Create a CTFE pointer &aggregate[1..2]
5857 auto ei = ctfeEmplaceExp!IndexExp(e.loc, se.e1, se.lwr);
5858 ei.type = e.type.nextOf();
5859 emplaceExp!(AddrExp)(pue, e.loc, ei, e.type);
5860 result = pue.exp();
5861 return;
5862 }
5863 if (e1.op == EXP.arrayLiteral || e1.op == EXP.string_)
5864 {
5865 // Create a CTFE pointer &[1,2,3][0] or &"abc"[0]
5866 auto ei = ctfeEmplaceExp!IndexExp(e.loc, e1, ctfeEmplaceExp!IntegerExp(e.loc, 0, Type.tsize_t));
5867 ei.type = e.type.nextOf();
5868 emplaceExp!(AddrExp)(pue, e.loc, ei, e.type);
5869 result = pue.exp();
5870 return;
5871 }
5872 if (e1.op == EXP.index && !e1.isIndexExp().e1.type.equals(e1.type))
5873 {
5874 // type painting operation
5875 IndexExp ie = e1.isIndexExp();
5876 if (castBackFromVoid)
5877 {
5878 // get the original type. For strings, it's just the type...
5879 Type origType = ie.e1.type.nextOf();
5880 // ..but for arrays of type void*, it's the type of the element
5881 if (ie.e1.op == EXP.arrayLiteral && ie.e2.op == EXP.int64)
5882 {
5883 ArrayLiteralExp ale = ie.e1.isArrayLiteralExp();
5884 const indx = cast(size_t)ie.e2.toInteger();
5885 if (indx < ale.elements.dim)
5886 {
5887 if (Expression xx = (*ale.elements)[indx])
5888 {
5889 if (auto iex = xx.isIndexExp())
5890 origType = iex.e1.type.nextOf();
5891 else if (auto ae = xx.isAddrExp())
5892 origType = ae.e1.type;
5893 else if (auto ve = xx.isVarExp())
5894 origType = ve.var.type;
5895 }
5896 }
5897 }
5898 if (!isSafePointerCast(origType, pointee))
5899 {
5900 e.error("using `void*` to reinterpret cast from `%s*` to `%s*` is not supported in CTFE", origType.toChars(), pointee.toChars());
5901 result = CTFEExp.cantexp;
5902 return;
5903 }
5904 }
5905 emplaceExp!(IndexExp)(pue, e1.loc, ie.e1, ie.e2);
5906 result = pue.exp();
5907 result.type = e.type;
5908 return;
5909 }
5910
5911 if (auto ae = e1.isAddrExp())
5912 {
5913 Type origType = ae.e1.type;
5914 if (isSafePointerCast(origType, pointee))
5915 {
5916 emplaceExp!(AddrExp)(pue, e.loc, ae.e1, e.type);
5917 result = pue.exp();
5918 return;
5919 }
5920
5921 if (castToSarrayPointer && pointee.toBasetype().ty == Tsarray && ae.e1.op == EXP.index)
5922 {
5923 // &val[idx]
5924 dinteger_t dim = (cast(TypeSArray)pointee.toBasetype()).dim.toInteger();
5925 IndexExp ie = ae.e1.isIndexExp();
5926 Expression lwr = ie.e2;
5927 Expression upr = ctfeEmplaceExp!IntegerExp(ie.e2.loc, ie.e2.toInteger() + dim, Type.tsize_t);
5928
5929 // Create a CTFE pointer &val[idx..idx+dim]
5930 auto er = ctfeEmplaceExp!SliceExp(e.loc, ie.e1, lwr, upr);
5931 er.type = pointee;
5932 emplaceExp!(AddrExp)(pue, e.loc, er, e.type);
5933 result = pue.exp();
5934 return;
5935 }
5936 }
5937
5938 if (e1.op == EXP.variable || e1.op == EXP.symbolOffset)
5939 {
5940 // type painting operation
5941 Type origType = (cast(SymbolExp)e1).var.type;
5942 if (castBackFromVoid && !isSafePointerCast(origType, pointee))
5943 {
5944 e.error("using `void*` to reinterpret cast from `%s*` to `%s*` is not supported in CTFE", origType.toChars(), pointee.toChars());
5945 result = CTFEExp.cantexp;
5946 return;
5947 }
5948 if (auto ve = e1.isVarExp())
5949 emplaceExp!(VarExp)(pue, e.loc, ve.var);
5950 else
5951 emplaceExp!(SymOffExp)(pue, e.loc, e1.isSymOffExp().var, e1.isSymOffExp().offset);
5952 result = pue.exp();
5953 result.type = e.to;
5954 return;
5955 }
5956
5957 // Check if we have a null pointer (eg, inside a struct)
5958 e1 = interpretRegion(e1, istate);
5959 if (e1.op != EXP.null_)
5960 {
5961 e.error("pointer cast from `%s` to `%s` is not supported at compile time", e1.type.toChars(), e.to.toChars());
5962 result = CTFEExp.cantexp;
5963 return;
5964 }
5965 }
5966 if (e.to.ty == Tsarray && e.e1.type.ty == Tvector)
5967 {
5968 // Special handling for: cast(float[4])__vector([w, x, y, z])
5969 e1 = interpretRegion(e.e1, istate);
5970 if (exceptionOrCant(e1))
5971 return;
5972 assert(e1.op == EXP.vector);
5973 e1 = interpretVectorToArray(pue, e1.isVectorExp());
5974 }
5975 if (e.to.ty == Tarray && e1.op == EXP.slice)
5976 {
5977 // Note that the slice may be void[], so when checking for dangerous
5978 // casts, we need to use the original type, which is se.e1.
5979 SliceExp se = e1.isSliceExp();
5980 if (!isSafePointerCast(se.e1.type.nextOf(), e.to.nextOf()))
5981 {
5982 e.error("array cast from `%s` to `%s` is not supported at compile time", se.e1.type.toChars(), e.to.toChars());
5983 result = CTFEExp.cantexp;
5984 return;
5985 }
5986 emplaceExp!(SliceExp)(pue, e1.loc, se.e1, se.lwr, se.upr);
5987 result = pue.exp();
5988 result.type = e.to;
5989 return;
5990 }
5991 // Disallow array type painting, except for conversions between built-in
5992 // types of identical size.
5993 if ((e.to.ty == Tsarray || e.to.ty == Tarray) && (e1.type.ty == Tsarray || e1.type.ty == Tarray) && !isSafePointerCast(e1.type.nextOf(), e.to.nextOf()))
5994 {
5995 e.error("array cast from `%s` to `%s` is not supported at compile time", e1.type.toChars(), e.to.toChars());
5996 result = CTFEExp.cantexp;
5997 return;
5998 }
5999 if (e.to.ty == Tsarray)
6000 e1 = resolveSlice(e1);
6001
6002 auto tobt = e.to.toBasetype();
6003 if (tobt.ty == Tbool && e1.type.ty == Tpointer)
6004 {
6005 emplaceExp!(IntegerExp)(pue, e.loc, e1.op != EXP.null_, e.to);
6006 result = pue.exp();
6007 return;
6008 }
6009 else if (tobt.isTypeBasic() && e1.op == EXP.null_)
6010 {
6011 if (tobt.isintegral())
6012 emplaceExp!(IntegerExp)(pue, e.loc, 0, e.to);
6013 else if (tobt.isreal())
6014 emplaceExp!(RealExp)(pue, e.loc, CTFloat.zero, e.to);
6015 result = pue.exp();
6016 return;
6017 }
6018 result = ctfeCast(pue, e.loc, e.type, e.to, e1, true);
6019 }
6020
visit(AssertExp e)6021 override void visit(AssertExp e)
6022 {
6023 debug (LOG)
6024 {
6025 printf("%s AssertExp::interpret() %s\n", e.loc.toChars(), e.toChars());
6026 }
6027 Expression e1 = interpret(pue, e.e1, istate);
6028 if (exceptionOrCant(e1))
6029 return;
6030 if (isTrueBool(e1))
6031 {
6032 }
6033 else if (e1.toBool().hasValue(false))
6034 {
6035 if (e.msg)
6036 {
6037 UnionExp ue = void;
6038 result = interpret(&ue, e.msg, istate);
6039 if (exceptionOrCant(result))
6040 return;
6041 e.error("`%s`", result.toChars());
6042 }
6043 else
6044 e.error("`%s` failed", e.toChars());
6045 result = CTFEExp.cantexp;
6046 return;
6047 }
6048 else
6049 {
6050 e.error("`%s` is not a compile time boolean expression", e1.toChars());
6051 result = CTFEExp.cantexp;
6052 return;
6053 }
6054 result = e1;
6055 return;
6056 }
6057
visit(ThrowExp te)6058 override void visit(ThrowExp te)
6059 {
6060 debug (LOG)
6061 {
6062 printf("%s ThrowExpression::interpret()\n", e.loc.toChars());
6063 }
6064 interpretThrow(te.e1, te.loc);
6065 }
6066
visit(PtrExp e)6067 override void visit(PtrExp e)
6068 {
6069 debug (LOG)
6070 {
6071 printf("%s PtrExp::interpret() %s\n", e.loc.toChars(), e.toChars());
6072 }
6073 // Check for int<->float and long<->double casts.
6074 if (auto soe1 = e.e1.isSymOffExp())
6075 if (soe1.offset == 0 && soe1.var.isVarDeclaration() && isFloatIntPaint(e.type, soe1.var.type))
6076 {
6077 // *(cast(int*)&v), where v is a float variable
6078 result = paintFloatInt(pue, getVarExp(e.loc, istate, soe1.var, CTFEGoal.RValue), e.type);
6079 return;
6080 }
6081
6082 if (auto ce1 = e.e1.isCastExp())
6083 if (auto ae11 = ce1.e1.isAddrExp())
6084 {
6085 // *(cast(int*)&x), where x is a float expression
6086 Expression x = ae11.e1;
6087 if (isFloatIntPaint(e.type, x.type))
6088 {
6089 result = paintFloatInt(pue, interpretRegion(x, istate), e.type);
6090 return;
6091 }
6092 }
6093
6094 // Constant fold *(&structliteral + offset)
6095 if (auto ae = e.e1.isAddExp())
6096 {
6097 if (ae.e1.op == EXP.address && ae.e2.op == EXP.int64)
6098 {
6099 AddrExp ade = ae.e1.isAddrExp();
6100 Expression ex = interpretRegion(ade.e1, istate);
6101 if (exceptionOrCant(ex))
6102 return;
6103 if (auto se = ex.isStructLiteralExp())
6104 {
6105 dinteger_t offset = ae.e2.toInteger();
6106 result = se.getField(e.type, cast(uint)offset);
6107 if (result)
6108 return;
6109 }
6110 }
6111 }
6112
6113 // It's possible we have an array bounds error. We need to make sure it
6114 // errors with this line number, not the one where the pointer was set.
6115 result = interpretRegion(e.e1, istate);
6116 if (exceptionOrCant(result))
6117 return;
6118
6119 if (result.op == EXP.function_)
6120 return;
6121 if (auto soe = result.isSymOffExp())
6122 {
6123 if (soe.offset == 0 && soe.var.isFuncDeclaration())
6124 return;
6125 e.error("cannot dereference pointer to static variable `%s` at compile time", soe.var.toChars());
6126 result = CTFEExp.cantexp;
6127 return;
6128 }
6129
6130 if (result.isStringExp())
6131 return;
6132
6133 if (result.op != EXP.address)
6134 {
6135 if (result.op == EXP.null_)
6136 e.error("dereference of null pointer `%s`", e.e1.toChars());
6137 else
6138 e.error("dereference of invalid pointer `%s`", result.toChars());
6139 result = CTFEExp.cantexp;
6140 return;
6141 }
6142
6143 // *(&x) ==> x
6144 result = result.isAddrExp().e1;
6145
6146 if (result.op == EXP.slice && e.type.toBasetype().ty == Tsarray)
6147 {
6148 /* aggr[lwr..upr]
6149 * upr may exceed the upper boundary of aggr, but the check is deferred
6150 * until those out-of-bounds elements will be touched.
6151 */
6152 return;
6153 }
6154 result = interpret(pue, result, istate, goal);
6155 if (exceptionOrCant(result))
6156 return;
6157
6158 debug (LOG)
6159 {
6160 if (CTFEExp.isCantExp(result))
6161 printf("PtrExp::interpret() %s = CTFEExp::cantexp\n", e.toChars());
6162 }
6163 }
6164
visit(DotVarExp e)6165 override void visit(DotVarExp e)
6166 {
6167 void notImplementedYet()
6168 {
6169 e.error("`%s.%s` is not yet implemented at compile time", e.e1.toChars(), e.var.toChars());
6170 result = CTFEExp.cantexp;
6171 return;
6172 }
6173
6174 debug (LOG)
6175 {
6176 printf("%s DotVarExp::interpret() %s, goal = %d\n", e.loc.toChars(), e.toChars(), goal);
6177 }
6178 Expression ex = interpretRegion(e.e1, istate);
6179 if (exceptionOrCant(ex))
6180 return;
6181
6182 if (FuncDeclaration f = e.var.isFuncDeclaration())
6183 {
6184 if (ex == e.e1)
6185 result = e; // optimize: reuse this CTFE reference
6186 else
6187 {
6188 emplaceExp!(DotVarExp)(pue, e.loc, ex, f, false);
6189 result = pue.exp();
6190 result.type = e.type;
6191 }
6192 return;
6193 }
6194
6195 VarDeclaration v = e.var.isVarDeclaration();
6196 if (!v)
6197 {
6198 e.error("CTFE internal error: `%s`", e.toChars());
6199 result = CTFEExp.cantexp;
6200 return;
6201 }
6202
6203 if (ex.op == EXP.null_)
6204 {
6205 if (ex.type.toBasetype().ty == Tclass)
6206 e.error("class `%s` is `null` and cannot be dereferenced", e.e1.toChars());
6207 else
6208 e.error("CTFE internal error: null this `%s`", e.e1.toChars());
6209 result = CTFEExp.cantexp;
6210 return;
6211 }
6212
6213 StructLiteralExp se;
6214 int i;
6215
6216 if (ex.op != EXP.structLiteral && ex.op != EXP.classReference && ex.op != EXP.typeid_)
6217 {
6218 return notImplementedYet();
6219 }
6220
6221 // We can't use getField, because it makes a copy
6222 if (ex.op == EXP.classReference)
6223 {
6224 se = ex.isClassReferenceExp().value;
6225 i = ex.isClassReferenceExp().findFieldIndexByName(v);
6226 }
6227 else if (ex.op == EXP.typeid_)
6228 {
6229 if (v.ident == Identifier.idPool("name"))
6230 {
6231 if (auto t = isType(ex.isTypeidExp().obj))
6232 {
6233 auto sym = t.toDsymbol(null);
6234 if (auto ident = (sym ? sym.ident : null))
6235 {
6236 result = new StringExp(e.loc, ident.toString());
6237 result.expressionSemantic(null);
6238 return ;
6239 }
6240 }
6241 }
6242 return notImplementedYet();
6243 }
6244 else
6245 {
6246 se = ex.isStructLiteralExp();
6247 i = findFieldIndexByName(se.sd, v);
6248 }
6249 if (i == -1)
6250 {
6251 e.error("couldn't find field `%s` of type `%s` in `%s`", v.toChars(), e.type.toChars(), se.toChars());
6252 result = CTFEExp.cantexp;
6253 return;
6254 }
6255
6256 // https://issues.dlang.org/show_bug.cgi?id=19897
6257 // https://issues.dlang.org/show_bug.cgi?id=20710
6258 // Zero-elements fields don't have an initializer. See: scrubArray function
6259 if ((*se.elements)[i] is null)
6260 (*se.elements)[i] = voidInitLiteral(e.type, v).copy();
6261
6262 if (goal == CTFEGoal.LValue)
6263 {
6264 // just return the (simplified) dotvar expression as a CTFE reference
6265 if (e.e1 == ex)
6266 result = e;
6267 else
6268 {
6269 emplaceExp!(DotVarExp)(pue, e.loc, ex, v);
6270 result = pue.exp();
6271 result.type = e.type;
6272 }
6273 return;
6274 }
6275
6276 result = (*se.elements)[i];
6277 if (!result)
6278 {
6279 e.error("Internal Compiler Error: null field `%s`", v.toChars());
6280 result = CTFEExp.cantexp;
6281 return;
6282 }
6283 if (auto vie = result.isVoidInitExp())
6284 {
6285 const s = vie.var.toChars();
6286 if (v.overlapped)
6287 {
6288 e.error("reinterpretation through overlapped field `%s` is not allowed in CTFE", s);
6289 result = CTFEExp.cantexp;
6290 return;
6291 }
6292 e.error("cannot read uninitialized variable `%s` in CTFE", s);
6293 result = CTFEExp.cantexp;
6294 return;
6295 }
6296
6297 if (v.type.ty != result.type.ty && v.type.ty == Tsarray)
6298 {
6299 // Block assignment from inside struct literals
6300 auto tsa = cast(TypeSArray)v.type;
6301 auto len = cast(size_t)tsa.dim.toInteger();
6302 UnionExp ue = void;
6303 result = createBlockDuplicatedArrayLiteral(&ue, e.loc, v.type, result, len);
6304 if (result == ue.exp())
6305 result = ue.copy();
6306 (*se.elements)[i] = result;
6307 }
6308 debug (LOG)
6309 {
6310 if (CTFEExp.isCantExp(result))
6311 printf("DotVarExp::interpret() %s = CTFEExp::cantexp\n", e.toChars());
6312 }
6313 }
6314
visit(RemoveExp e)6315 override void visit(RemoveExp e)
6316 {
6317 debug (LOG)
6318 {
6319 printf("%s RemoveExp::interpret() %s\n", e.loc.toChars(), e.toChars());
6320 }
6321 Expression agg = interpret(e.e1, istate);
6322 if (exceptionOrCant(agg))
6323 return;
6324 Expression index = interpret(e.e2, istate);
6325 if (exceptionOrCant(index))
6326 return;
6327 if (agg.op == EXP.null_)
6328 {
6329 result = CTFEExp.voidexp;
6330 return;
6331 }
6332
6333 AssocArrayLiteralExp aae = agg.isAssocArrayLiteralExp();
6334 Expressions* keysx = aae.keys;
6335 Expressions* valuesx = aae.values;
6336 size_t removed = 0;
6337 foreach (j, evalue; *valuesx)
6338 {
6339 Expression ekey = (*keysx)[j];
6340 int eq = ctfeEqual(e.loc, EXP.equal, ekey, index);
6341 if (eq)
6342 ++removed;
6343 else if (removed != 0)
6344 {
6345 (*keysx)[j - removed] = ekey;
6346 (*valuesx)[j - removed] = evalue;
6347 }
6348 }
6349 valuesx.dim = valuesx.dim - removed;
6350 keysx.dim = keysx.dim - removed;
6351 result = IntegerExp.createBool(removed != 0);
6352 }
6353
visit(ClassReferenceExp e)6354 override void visit(ClassReferenceExp e)
6355 {
6356 //printf("ClassReferenceExp::interpret() %s\n", e.value.toChars());
6357 result = e;
6358 }
6359
visit(VoidInitExp e)6360 override void visit(VoidInitExp e)
6361 {
6362 e.error("CTFE internal error: trying to read uninitialized variable");
6363 assert(0);
6364 }
6365
visit(ThrownExceptionExp e)6366 override void visit(ThrownExceptionExp e)
6367 {
6368 assert(0); // This should never be interpreted
6369 }
6370 }
6371
6372 /********************************************
6373 * Interpret the expression.
6374 * Params:
6375 * pue = non-null pointer to temporary storage that can be used to store the return value
6376 * e = Expression to interpret
6377 * istate = context
6378 * goal = what the result will be used for
6379 * Returns:
6380 * resulting expression
6381 */
6382
6383 Expression interpret(UnionExp* pue, Expression e, InterState* istate, CTFEGoal goal = CTFEGoal.RValue)
6384 {
6385 if (!e)
6386 return null;
6387 scope Interpreter v = new Interpreter(pue, istate, goal);
6388 e.accept(v);
6389 Expression ex = v.result;
6390 assert(goal == CTFEGoal.Nothing || ex !is null);
6391 return ex;
6392 }
6393
6394 ///
6395 Expression interpret(Expression e, InterState* istate, CTFEGoal goal = CTFEGoal.RValue)
6396 {
6397 UnionExp ue = void;
6398 auto result = interpret(&ue, e, istate, goal);
6399 if (result == ue.exp())
6400 result = ue.copy();
6401 return result;
6402 }
6403
6404 /*****************************
6405 * Same as interpret(), but return result allocated in Region.
6406 * Params:
6407 * e = Expression to interpret
6408 * istate = context
6409 * goal = what the result will be used for
6410 * Returns:
6411 * resulting expression
6412 */
6413 Expression interpretRegion(Expression e, InterState* istate, CTFEGoal goal = CTFEGoal.RValue)
6414 {
6415 UnionExp ue = void;
6416 auto result = interpret(&ue, e, istate, goal);
6417 auto uexp = ue.exp();
6418 if (result != uexp)
6419 return result;
6420 if (mem.isGCEnabled)
6421 return ue.copy();
6422
6423 // mimicking UnionExp.copy, but with region allocation
6424 switch (uexp.op)
6425 {
6426 case EXP.cantExpression: return CTFEExp.cantexp;
6427 case EXP.voidExpression: return CTFEExp.voidexp;
6428 case EXP.break_: return CTFEExp.breakexp;
6429 case EXP.continue_: return CTFEExp.continueexp;
6430 case EXP.goto_: return CTFEExp.gotoexp;
6431 default: break;
6432 }
6433 auto p = ctfeGlobals.region.malloc(uexp.size);
6434 return cast(Expression)memcpy(p, cast(void*)uexp, uexp.size);
6435 }
6436
6437 /***********************************
6438 * Interpret the statement.
6439 * Params:
6440 * pue = non-null pointer to temporary storage that can be used to store the return value
6441 * s = Statement to interpret
6442 * istate = context
6443 * Returns:
6444 * NULL continue to next statement
6445 * EXP.cantExpression cannot interpret statement at compile time
6446 * !NULL expression from return statement, or thrown exception
6447 */
interpret(UnionExp * pue,Statement s,InterState * istate)6448 Expression interpret(UnionExp* pue, Statement s, InterState* istate)
6449 {
6450 if (!s)
6451 return null;
6452 scope Interpreter v = new Interpreter(pue, istate, CTFEGoal.Nothing);
6453 s.accept(v);
6454 return v.result;
6455 }
6456
6457 ///
interpret(Statement s,InterState * istate)6458 Expression interpret(Statement s, InterState* istate)
6459 {
6460 UnionExp ue = void;
6461 auto result = interpret(&ue, s, istate);
6462 if (result == ue.exp())
6463 result = ue.copy();
6464 return result;
6465 }
6466
6467 /**
6468 * All results destined for use outside of CTFE need to have their CTFE-specific
6469 * features removed.
6470 * In particular,
6471 * 1. all slices must be resolved.
6472 * 2. all .ownedByCtfe set to OwnedBy.code
6473 */
scrubReturnValue(const ref Loc loc,Expression e)6474 private Expression scrubReturnValue(const ref Loc loc, Expression e)
6475 {
6476 /* Returns: true if e is void,
6477 * or is an array literal or struct literal of void elements.
6478 */
6479 static bool isVoid(const Expression e, bool checkArrayType = false) pure
6480 {
6481 if (e.op == EXP.void_)
6482 return true;
6483
6484 static bool isEntirelyVoid(const Expressions* elems)
6485 {
6486 foreach (e; *elems)
6487 {
6488 // It can be NULL for performance reasons,
6489 // see StructLiteralExp::interpret().
6490 if (e && !isVoid(e))
6491 return false;
6492 }
6493 return true;
6494 }
6495
6496 if (auto sle = e.isStructLiteralExp())
6497 return isEntirelyVoid(sle.elements);
6498
6499 if (checkArrayType && e.type.ty != Tsarray)
6500 return false;
6501
6502 if (auto ale = e.isArrayLiteralExp())
6503 return isEntirelyVoid(ale.elements);
6504
6505 return false;
6506 }
6507
6508
6509 /* Scrub all elements of elems[].
6510 * Returns: null for success, error Expression for failure
6511 */
6512 Expression scrubArray(Expressions* elems, bool structlit = false)
6513 {
6514 foreach (ref e; *elems)
6515 {
6516 // It can be NULL for performance reasons,
6517 // see StructLiteralExp::interpret().
6518 if (!e)
6519 continue;
6520
6521 // A struct .init may contain void members.
6522 // Static array members are a weird special case https://issues.dlang.org/show_bug.cgi?id=10994
6523 if (structlit && isVoid(e, true))
6524 {
6525 e = null;
6526 }
6527 else
6528 {
6529 e = scrubReturnValue(loc, e);
6530 if (CTFEExp.isCantExp(e) || e.op == EXP.error)
6531 return e;
6532 }
6533 }
6534 return null;
6535 }
6536
6537 Expression scrubSE(StructLiteralExp sle)
6538 {
6539 sle.ownedByCtfe = OwnedBy.code;
6540 if (!(sle.stageflags & stageScrub))
6541 {
6542 const old = sle.stageflags;
6543 sle.stageflags |= stageScrub; // prevent infinite recursion
6544 if (auto ex = scrubArray(sle.elements, true))
6545 return ex;
6546 sle.stageflags = old;
6547 }
6548 return null;
6549 }
6550
6551 if (e.op == EXP.classReference)
6552 {
6553 StructLiteralExp sle = e.isClassReferenceExp().value;
6554 if (auto ex = scrubSE(sle))
6555 return ex;
6556 }
6557 else if (auto vie = e.isVoidInitExp())
6558 {
6559 error(loc, "uninitialized variable `%s` cannot be returned from CTFE", vie.var.toChars());
6560 return ErrorExp.get();
6561 }
6562
6563 e = resolveSlice(e);
6564
6565 if (auto sle = e.isStructLiteralExp())
6566 {
6567 if (auto ex = scrubSE(sle))
6568 return ex;
6569 }
6570 else if (auto se = e.isStringExp())
6571 {
6572 se.ownedByCtfe = OwnedBy.code;
6573 }
6574 else if (auto ale = e.isArrayLiteralExp())
6575 {
6576 ale.ownedByCtfe = OwnedBy.code;
6577 if (auto ex = scrubArray(ale.elements))
6578 return ex;
6579 }
6580 else if (auto aae = e.isAssocArrayLiteralExp())
6581 {
6582 aae.ownedByCtfe = OwnedBy.code;
6583 if (auto ex = scrubArray(aae.keys))
6584 return ex;
6585 if (auto ex = scrubArray(aae.values))
6586 return ex;
6587 aae.type = toBuiltinAAType(aae.type);
6588 }
6589 else if (auto ve = e.isVectorExp())
6590 {
6591 ve.ownedByCtfe = OwnedBy.code;
6592 if (auto ale = ve.e1.isArrayLiteralExp())
6593 {
6594 ale.ownedByCtfe = OwnedBy.code;
6595 if (auto ex = scrubArray(ale.elements))
6596 return ex;
6597 }
6598 }
6599 return e;
6600 }
6601
6602 /**************************************
6603 * Transitively set all .ownedByCtfe to OwnedBy.cache
6604 */
scrubCacheValue(Expression e)6605 private Expression scrubCacheValue(Expression e)
6606 {
6607 if (!e)
6608 return e;
6609
6610 Expression scrubArrayCache(Expressions* elems)
6611 {
6612 foreach (ref e; *elems)
6613 e = scrubCacheValue(e);
6614 return null;
6615 }
6616
6617 Expression scrubSE(StructLiteralExp sle)
6618 {
6619 sle.ownedByCtfe = OwnedBy.cache;
6620 if (!(sle.stageflags & stageScrub))
6621 {
6622 const old = sle.stageflags;
6623 sle.stageflags |= stageScrub; // prevent infinite recursion
6624 if (auto ex = scrubArrayCache(sle.elements))
6625 return ex;
6626 sle.stageflags = old;
6627 }
6628 return null;
6629 }
6630
6631 if (e.op == EXP.classReference)
6632 {
6633 if (auto ex = scrubSE(e.isClassReferenceExp().value))
6634 return ex;
6635 }
6636 else if (auto sle = e.isStructLiteralExp())
6637 {
6638 if (auto ex = scrubSE(sle))
6639 return ex;
6640 }
6641 else if (auto se = e.isStringExp())
6642 {
6643 se.ownedByCtfe = OwnedBy.cache;
6644 }
6645 else if (auto ale = e.isArrayLiteralExp())
6646 {
6647 ale.ownedByCtfe = OwnedBy.cache;
6648 if (Expression ex = scrubArrayCache(ale.elements))
6649 return ex;
6650 }
6651 else if (auto aae = e.isAssocArrayLiteralExp())
6652 {
6653 aae.ownedByCtfe = OwnedBy.cache;
6654 if (auto ex = scrubArrayCache(aae.keys))
6655 return ex;
6656 if (auto ex = scrubArrayCache(aae.values))
6657 return ex;
6658 }
6659 else if (auto ve = e.isVectorExp())
6660 {
6661 ve.ownedByCtfe = OwnedBy.cache;
6662 if (auto ale = ve.e1.isArrayLiteralExp())
6663 {
6664 ale.ownedByCtfe = OwnedBy.cache;
6665 if (auto ex = scrubArrayCache(ale.elements))
6666 return ex;
6667 }
6668 }
6669 return e;
6670 }
6671
6672 /********************************************
6673 * Transitively replace all Expressions allocated in ctfeGlobals.region
6674 * with Mem owned copies.
6675 * Params:
6676 * e = possible ctfeGlobals.region owned expression
6677 * Returns:
6678 * Mem owned expression
6679 */
copyRegionExp(Expression e)6680 private Expression copyRegionExp(Expression e)
6681 {
6682 if (!e)
6683 return e;
6684
6685 static void copyArray(Expressions* elems)
6686 {
6687 foreach (ref e; *elems)
6688 {
6689 auto ex = e;
6690 e = null;
6691 e = copyRegionExp(ex);
6692 }
6693 }
6694
6695 static void copySE(StructLiteralExp sle)
6696 {
6697 if (1 || !(sle.stageflags & stageScrub))
6698 {
6699 const old = sle.stageflags;
6700 sle.stageflags |= stageScrub; // prevent infinite recursion
6701 copyArray(sle.elements);
6702 sle.stageflags = old;
6703 }
6704 }
6705
6706 switch (e.op)
6707 {
6708 case EXP.classReference:
6709 {
6710 auto cre = e.isClassReferenceExp();
6711 cre.value = copyRegionExp(cre.value).isStructLiteralExp();
6712 break;
6713 }
6714
6715 case EXP.structLiteral:
6716 {
6717 auto sle = e.isStructLiteralExp();
6718
6719 /* The following is to take care of updating sle.origin correctly,
6720 * which may have multiple objects pointing to it.
6721 */
6722 if (sle.isOriginal && !ctfeGlobals.region.contains(cast(void*)sle.origin))
6723 {
6724 /* This means sle has already been moved out of the region,
6725 * and sle.origin is the new location.
6726 */
6727 return sle.origin;
6728 }
6729 copySE(sle);
6730 sle.isOriginal = sle is sle.origin;
6731
6732 auto slec = ctfeGlobals.region.contains(cast(void*)e)
6733 ? e.copy().isStructLiteralExp() // move sle out of region to slec
6734 : sle;
6735
6736 if (ctfeGlobals.region.contains(cast(void*)sle.origin))
6737 {
6738 auto sleo = sle.origin == sle ? slec : sle.origin.copy().isStructLiteralExp();
6739 sle.origin = sleo;
6740 slec.origin = sleo;
6741 }
6742 return slec;
6743 }
6744
6745 case EXP.arrayLiteral:
6746 {
6747 auto ale = e.isArrayLiteralExp();
6748 ale.basis = copyRegionExp(ale.basis);
6749 copyArray(ale.elements);
6750 break;
6751 }
6752
6753 case EXP.assocArrayLiteral:
6754 copyArray(e.isAssocArrayLiteralExp().keys);
6755 copyArray(e.isAssocArrayLiteralExp().values);
6756 break;
6757
6758 case EXP.slice:
6759 {
6760 auto se = e.isSliceExp();
6761 se.e1 = copyRegionExp(se.e1);
6762 se.upr = copyRegionExp(se.upr);
6763 se.lwr = copyRegionExp(se.lwr);
6764 break;
6765 }
6766
6767 case EXP.tuple:
6768 {
6769 auto te = e.isTupleExp();
6770 te.e0 = copyRegionExp(te.e0);
6771 copyArray(te.exps);
6772 break;
6773 }
6774
6775 case EXP.address:
6776 case EXP.delegate_:
6777 case EXP.vector:
6778 case EXP.dotVariable:
6779 {
6780 UnaExp ue = e.isUnaExp();
6781 ue.e1 = copyRegionExp(ue.e1);
6782 break;
6783 }
6784
6785 case EXP.index:
6786 {
6787 BinExp be = e.isBinExp();
6788 be.e1 = copyRegionExp(be.e1);
6789 be.e2 = copyRegionExp(be.e2);
6790 break;
6791 }
6792
6793 case EXP.this_:
6794 case EXP.super_:
6795 case EXP.variable:
6796 case EXP.type:
6797 case EXP.function_:
6798 case EXP.typeid_:
6799 case EXP.string_:
6800 case EXP.int64:
6801 case EXP.error:
6802 case EXP.float64:
6803 case EXP.complex80:
6804 case EXP.null_:
6805 case EXP.void_:
6806 case EXP.symbolOffset:
6807 case EXP.char_:
6808 break;
6809
6810 case EXP.cantExpression:
6811 case EXP.voidExpression:
6812 case EXP.showCtfeContext:
6813 return e;
6814
6815 default:
6816 printf("e: %s, %s\n", EXPtoString(e.op).ptr, e.toChars());
6817 assert(0);
6818 }
6819
6820 if (ctfeGlobals.region.contains(cast(void*)e))
6821 {
6822 return e.copy();
6823 }
6824 return e;
6825 }
6826
6827 /******************************* Special Functions ***************************/
6828
interpret_length(UnionExp * pue,InterState * istate,Expression earg)6829 private Expression interpret_length(UnionExp* pue, InterState* istate, Expression earg)
6830 {
6831 //printf("interpret_length()\n");
6832 earg = interpret(pue, earg, istate);
6833 if (exceptionOrCantInterpret(earg))
6834 return earg;
6835 dinteger_t len = 0;
6836 if (auto aae = earg.isAssocArrayLiteralExp())
6837 len = aae.keys.dim;
6838 else
6839 assert(earg.op == EXP.null_);
6840 emplaceExp!(IntegerExp)(pue, earg.loc, len, Type.tsize_t);
6841 return pue.exp();
6842 }
6843
interpret_keys(UnionExp * pue,InterState * istate,Expression earg,Type returnType)6844 private Expression interpret_keys(UnionExp* pue, InterState* istate, Expression earg, Type returnType)
6845 {
6846 debug (LOG)
6847 {
6848 printf("interpret_keys()\n");
6849 }
6850 earg = interpret(pue, earg, istate);
6851 if (exceptionOrCantInterpret(earg))
6852 return earg;
6853 if (earg.op == EXP.null_)
6854 {
6855 emplaceExp!(NullExp)(pue, earg.loc, earg.type);
6856 return pue.exp();
6857 }
6858 if (earg.op != EXP.assocArrayLiteral && earg.type.toBasetype().ty != Taarray)
6859 return null;
6860 AssocArrayLiteralExp aae = earg.isAssocArrayLiteralExp();
6861 auto ae = ctfeEmplaceExp!ArrayLiteralExp(aae.loc, returnType, aae.keys);
6862 ae.ownedByCtfe = aae.ownedByCtfe;
6863 *pue = copyLiteral(ae);
6864 return pue.exp();
6865 }
6866
interpret_values(UnionExp * pue,InterState * istate,Expression earg,Type returnType)6867 private Expression interpret_values(UnionExp* pue, InterState* istate, Expression earg, Type returnType)
6868 {
6869 debug (LOG)
6870 {
6871 printf("interpret_values()\n");
6872 }
6873 earg = interpret(pue, earg, istate);
6874 if (exceptionOrCantInterpret(earg))
6875 return earg;
6876 if (earg.op == EXP.null_)
6877 {
6878 emplaceExp!(NullExp)(pue, earg.loc, earg.type);
6879 return pue.exp();
6880 }
6881 if (earg.op != EXP.assocArrayLiteral && earg.type.toBasetype().ty != Taarray)
6882 return null;
6883 auto aae = earg.isAssocArrayLiteralExp();
6884 auto ae = ctfeEmplaceExp!ArrayLiteralExp(aae.loc, returnType, aae.values);
6885 ae.ownedByCtfe = aae.ownedByCtfe;
6886 //printf("result is %s\n", e.toChars());
6887 *pue = copyLiteral(ae);
6888 return pue.exp();
6889 }
6890
interpret_dup(UnionExp * pue,InterState * istate,Expression earg)6891 private Expression interpret_dup(UnionExp* pue, InterState* istate, Expression earg)
6892 {
6893 debug (LOG)
6894 {
6895 printf("interpret_dup()\n");
6896 }
6897 earg = interpret(pue, earg, istate);
6898 if (exceptionOrCantInterpret(earg))
6899 return earg;
6900 if (earg.op == EXP.null_)
6901 {
6902 emplaceExp!(NullExp)(pue, earg.loc, earg.type);
6903 return pue.exp();
6904 }
6905 if (earg.op != EXP.assocArrayLiteral && earg.type.toBasetype().ty != Taarray)
6906 return null;
6907 auto aae = copyLiteral(earg).copy().isAssocArrayLiteralExp();
6908 for (size_t i = 0; i < aae.keys.dim; i++)
6909 {
6910 if (Expression e = evaluatePostblit(istate, (*aae.keys)[i]))
6911 return e;
6912 if (Expression e = evaluatePostblit(istate, (*aae.values)[i]))
6913 return e;
6914 }
6915 aae.type = earg.type.mutableOf(); // repaint type from const(int[int]) to const(int)[int]
6916 //printf("result is %s\n", aae.toChars());
6917 return aae;
6918 }
6919
6920 // signature is int delegate(ref Value) OR int delegate(ref Key, ref Value)
interpret_aaApply(UnionExp * pue,InterState * istate,Expression aa,Expression deleg)6921 private Expression interpret_aaApply(UnionExp* pue, InterState* istate, Expression aa, Expression deleg)
6922 {
6923 aa = interpret(aa, istate);
6924 if (exceptionOrCantInterpret(aa))
6925 return aa;
6926 if (aa.op != EXP.assocArrayLiteral)
6927 {
6928 emplaceExp!(IntegerExp)(pue, deleg.loc, 0, Type.tsize_t);
6929 return pue.exp();
6930 }
6931
6932 FuncDeclaration fd = null;
6933 Expression pthis = null;
6934 if (auto de = deleg.isDelegateExp())
6935 {
6936 fd = de.func;
6937 pthis = de.e1;
6938 }
6939 else if (auto fe = deleg.isFuncExp())
6940 fd = fe.fd;
6941
6942 assert(fd && fd.fbody);
6943 assert(fd.parameters);
6944 size_t numParams = fd.parameters.dim;
6945 assert(numParams == 1 || numParams == 2);
6946
6947 Parameter fparam = fd.type.isTypeFunction().parameterList[numParams - 1];
6948 const wantRefValue = fparam.isReference();
6949
6950 Expressions args = Expressions(numParams);
6951
6952 AssocArrayLiteralExp ae = aa.isAssocArrayLiteralExp();
6953 if (!ae.keys || ae.keys.dim == 0)
6954 return ctfeEmplaceExp!IntegerExp(deleg.loc, 0, Type.tsize_t);
6955 Expression eresult;
6956
6957 for (size_t i = 0; i < ae.keys.dim; ++i)
6958 {
6959 Expression ekey = (*ae.keys)[i];
6960 Expression evalue = (*ae.values)[i];
6961 if (wantRefValue)
6962 {
6963 Type t = evalue.type;
6964 evalue = ctfeEmplaceExp!IndexExp(deleg.loc, ae, ekey);
6965 evalue.type = t;
6966 }
6967 args[numParams - 1] = evalue;
6968 if (numParams == 2)
6969 args[0] = ekey;
6970
6971 UnionExp ue = void;
6972 eresult = interpretFunction(&ue, fd, istate, &args, pthis);
6973 if (eresult == ue.exp())
6974 eresult = ue.copy();
6975 if (exceptionOrCantInterpret(eresult))
6976 return eresult;
6977
6978 if (eresult.isIntegerExp().getInteger() != 0)
6979 return eresult;
6980 }
6981 return eresult;
6982 }
6983
6984 /* Decoding UTF strings for foreach loops. Duplicates the functionality of
6985 * the twelve _aApplyXXn functions in aApply.d in the runtime.
6986 */
foreachApplyUtf(UnionExp * pue,InterState * istate,Expression str,Expression deleg,bool rvs)6987 private Expression foreachApplyUtf(UnionExp* pue, InterState* istate, Expression str, Expression deleg, bool rvs)
6988 {
6989 debug (LOG)
6990 {
6991 printf("foreachApplyUtf(%s, %s)\n", str.toChars(), deleg.toChars());
6992 }
6993 FuncDeclaration fd = null;
6994 Expression pthis = null;
6995 if (auto de = deleg.isDelegateExp())
6996 {
6997 fd = de.func;
6998 pthis = de.e1;
6999 }
7000 else if (auto fe = deleg.isFuncExp())
7001 fd = fe.fd;
7002
7003 assert(fd && fd.fbody);
7004 assert(fd.parameters);
7005 size_t numParams = fd.parameters.dim;
7006 assert(numParams == 1 || numParams == 2);
7007 Type charType = (*fd.parameters)[numParams - 1].type;
7008 Type indexType = numParams == 2 ? (*fd.parameters)[0].type : Type.tsize_t;
7009 size_t len = cast(size_t)resolveArrayLength(str);
7010 if (len == 0)
7011 {
7012 emplaceExp!(IntegerExp)(pue, deleg.loc, 0, indexType);
7013 return pue.exp();
7014 }
7015
7016 UnionExp strTmp = void;
7017 str = resolveSlice(str, &strTmp);
7018
7019 auto se = str.isStringExp();
7020 auto ale = str.isArrayLiteralExp();
7021 if (!se && !ale)
7022 {
7023 str.error("CTFE internal error: cannot foreach `%s`", str.toChars());
7024 return CTFEExp.cantexp;
7025 }
7026 Expressions args = Expressions(numParams);
7027
7028 Expression eresult = null; // ded-store to prevent spurious warning
7029
7030 // Buffers for encoding; also used for decoding array literals
7031 char[4] utf8buf = void;
7032 wchar[2] utf16buf = void;
7033
7034 size_t start = rvs ? len : 0;
7035 size_t end = rvs ? 0 : len;
7036 for (size_t indx = start; indx != end;)
7037 {
7038 // Step 1: Decode the next dchar from the string.
7039
7040 string errmsg = null; // Used for reporting decoding errors
7041 dchar rawvalue; // Holds the decoded dchar
7042 size_t currentIndex = indx; // The index of the decoded character
7043
7044 if (ale)
7045 {
7046 // If it is an array literal, copy the code points into the buffer
7047 size_t buflen = 1; // #code points in the buffer
7048 size_t n = 1; // #code points in this char
7049 size_t sz = cast(size_t)ale.type.nextOf().size();
7050
7051 switch (sz)
7052 {
7053 case 1:
7054 if (rvs)
7055 {
7056 // find the start of the string
7057 --indx;
7058 buflen = 1;
7059 while (indx > 0 && buflen < 4)
7060 {
7061 Expression r = (*ale.elements)[indx];
7062 char x = cast(char)r.isIntegerExp().getInteger();
7063 if ((x & 0xC0) != 0x80)
7064 break;
7065 --indx;
7066 ++buflen;
7067 }
7068 }
7069 else
7070 buflen = (indx + 4 > len) ? len - indx : 4;
7071 for (size_t i = 0; i < buflen; ++i)
7072 {
7073 Expression r = (*ale.elements)[indx + i];
7074 utf8buf[i] = cast(char)r.isIntegerExp().getInteger();
7075 }
7076 n = 0;
7077 errmsg = utf_decodeChar(utf8buf[0 .. buflen], n, rawvalue);
7078 break;
7079
7080 case 2:
7081 if (rvs)
7082 {
7083 // find the start of the string
7084 --indx;
7085 buflen = 1;
7086 Expression r = (*ale.elements)[indx];
7087 ushort x = cast(ushort)r.isIntegerExp().getInteger();
7088 if (indx > 0 && x >= 0xDC00 && x <= 0xDFFF)
7089 {
7090 --indx;
7091 ++buflen;
7092 }
7093 }
7094 else
7095 buflen = (indx + 2 > len) ? len - indx : 2;
7096 for (size_t i = 0; i < buflen; ++i)
7097 {
7098 Expression r = (*ale.elements)[indx + i];
7099 utf16buf[i] = cast(ushort)r.isIntegerExp().getInteger();
7100 }
7101 n = 0;
7102 errmsg = utf_decodeWchar(utf16buf[0 .. buflen], n, rawvalue);
7103 break;
7104
7105 case 4:
7106 {
7107 if (rvs)
7108 --indx;
7109 Expression r = (*ale.elements)[indx];
7110 rawvalue = cast(dchar)r.isIntegerExp().getInteger();
7111 n = 1;
7112 }
7113 break;
7114
7115 default:
7116 assert(0);
7117 }
7118 if (!rvs)
7119 indx += n;
7120 }
7121 else
7122 {
7123 // String literals
7124 size_t saveindx; // used for reverse iteration
7125
7126 switch (se.sz)
7127 {
7128 case 1:
7129 {
7130 if (rvs)
7131 {
7132 // find the start of the string
7133 --indx;
7134 while (indx > 0 && ((se.getCodeUnit(indx) & 0xC0) == 0x80))
7135 --indx;
7136 saveindx = indx;
7137 }
7138 auto slice = se.peekString();
7139 errmsg = utf_decodeChar(slice, indx, rawvalue);
7140 if (rvs)
7141 indx = saveindx;
7142 break;
7143 }
7144
7145 case 2:
7146 if (rvs)
7147 {
7148 // find the start
7149 --indx;
7150 auto wc = se.getCodeUnit(indx);
7151 if (wc >= 0xDC00 && wc <= 0xDFFF)
7152 --indx;
7153 saveindx = indx;
7154 }
7155 const slice = se.peekWstring();
7156 errmsg = utf_decodeWchar(slice, indx, rawvalue);
7157 if (rvs)
7158 indx = saveindx;
7159 break;
7160
7161 case 4:
7162 if (rvs)
7163 --indx;
7164 rawvalue = se.getCodeUnit(indx);
7165 if (!rvs)
7166 ++indx;
7167 break;
7168
7169 default:
7170 assert(0);
7171 }
7172 }
7173 if (errmsg)
7174 {
7175 deleg.error("`%.*s`", cast(int)errmsg.length, errmsg.ptr);
7176 return CTFEExp.cantexp;
7177 }
7178
7179 // Step 2: encode the dchar in the target encoding
7180
7181 int charlen = 1; // How many codepoints are involved?
7182 switch (charType.size())
7183 {
7184 case 1:
7185 charlen = utf_codeLengthChar(rawvalue);
7186 utf_encodeChar(&utf8buf[0], rawvalue);
7187 break;
7188 case 2:
7189 charlen = utf_codeLengthWchar(rawvalue);
7190 utf_encodeWchar(&utf16buf[0], rawvalue);
7191 break;
7192 case 4:
7193 break;
7194 default:
7195 assert(0);
7196 }
7197 if (rvs)
7198 currentIndex = indx;
7199
7200 // Step 3: call the delegate once for each code point
7201
7202 // The index only needs to be set once
7203 if (numParams == 2)
7204 args[0] = ctfeEmplaceExp!IntegerExp(deleg.loc, currentIndex, indexType);
7205
7206 Expression val = null;
7207
7208 foreach (k; 0 .. charlen)
7209 {
7210 dchar codepoint;
7211 switch (charType.size())
7212 {
7213 case 1:
7214 codepoint = utf8buf[k];
7215 break;
7216 case 2:
7217 codepoint = utf16buf[k];
7218 break;
7219 case 4:
7220 codepoint = rawvalue;
7221 break;
7222 default:
7223 assert(0);
7224 }
7225 val = ctfeEmplaceExp!IntegerExp(str.loc, codepoint, charType);
7226
7227 args[numParams - 1] = val;
7228
7229 UnionExp ue = void;
7230 eresult = interpretFunction(&ue, fd, istate, &args, pthis);
7231 if (eresult == ue.exp())
7232 eresult = ue.copy();
7233 if (exceptionOrCantInterpret(eresult))
7234 return eresult;
7235 if (eresult.isIntegerExp().getInteger() != 0)
7236 return eresult;
7237 }
7238 }
7239 return eresult;
7240 }
7241
7242 /* If this is a built-in function, return the interpreted result,
7243 * Otherwise, return NULL.
7244 */
evaluateIfBuiltin(UnionExp * pue,InterState * istate,const ref Loc loc,FuncDeclaration fd,Expressions * arguments,Expression pthis)7245 private Expression evaluateIfBuiltin(UnionExp* pue, InterState* istate, const ref Loc loc, FuncDeclaration fd, Expressions* arguments, Expression pthis)
7246 {
7247 Expression e = null;
7248 size_t nargs = arguments ? arguments.dim : 0;
7249 if (!pthis)
7250 {
7251 if (isBuiltin(fd) != BUILTIN.unimp)
7252 {
7253 Expressions args = Expressions(nargs);
7254 foreach (i, ref arg; args)
7255 {
7256 Expression earg = (*arguments)[i];
7257 earg = interpret(earg, istate);
7258 if (exceptionOrCantInterpret(earg))
7259 return earg;
7260 arg = earg;
7261 }
7262 e = eval_builtin(loc, fd, &args);
7263 if (!e)
7264 {
7265 error(loc, "cannot evaluate unimplemented builtin `%s` at compile time", fd.toChars());
7266 e = CTFEExp.cantexp;
7267 }
7268 }
7269 }
7270 if (!pthis)
7271 {
7272 if (nargs == 1 || nargs == 3)
7273 {
7274 Expression firstarg = (*arguments)[0];
7275 if (auto firstAAtype = firstarg.type.toBasetype().isTypeAArray())
7276 {
7277 const id = fd.ident;
7278 if (nargs == 1)
7279 {
7280 if (id == Id.aaLen)
7281 return interpret_length(pue, istate, firstarg);
7282
7283 if (fd.toParent2().ident == Id.object)
7284 {
7285 if (id == Id.keys)
7286 return interpret_keys(pue, istate, firstarg, firstAAtype.index.arrayOf());
7287 if (id == Id.values)
7288 return interpret_values(pue, istate, firstarg, firstAAtype.nextOf().arrayOf());
7289 if (id == Id.rehash)
7290 return interpret(pue, firstarg, istate);
7291 if (id == Id.dup)
7292 return interpret_dup(pue, istate, firstarg);
7293 }
7294 }
7295 else // (nargs == 3)
7296 {
7297 if (id == Id._aaApply)
7298 return interpret_aaApply(pue, istate, firstarg, (*arguments)[2]);
7299 if (id == Id._aaApply2)
7300 return interpret_aaApply(pue, istate, firstarg, (*arguments)[2]);
7301 }
7302 }
7303 }
7304 }
7305 if (pthis && !fd.fbody && fd.isCtorDeclaration() && fd.parent && fd.parent.parent && fd.parent.parent.ident == Id.object)
7306 {
7307 if (pthis.op == EXP.classReference && fd.parent.ident == Id.Throwable)
7308 {
7309 // At present, the constructors just copy their arguments into the struct.
7310 // But we might need some magic if stack tracing gets added to druntime.
7311 StructLiteralExp se = pthis.isClassReferenceExp().value;
7312 assert(arguments.dim <= se.elements.dim);
7313 foreach (i, arg; *arguments)
7314 {
7315 auto elem = interpret(arg, istate);
7316 if (exceptionOrCantInterpret(elem))
7317 return elem;
7318 (*se.elements)[i] = elem;
7319 }
7320 return CTFEExp.voidexp;
7321 }
7322 }
7323 if (nargs == 1 && !pthis && (fd.ident == Id.criticalenter || fd.ident == Id.criticalexit))
7324 {
7325 // Support synchronized{} as a no-op
7326 return CTFEExp.voidexp;
7327 }
7328 if (!pthis)
7329 {
7330 const idlen = fd.ident.toString().length;
7331 const id = fd.ident.toChars();
7332 if (nargs == 2 && (idlen == 10 || idlen == 11) && !strncmp(id, "_aApply", 7))
7333 {
7334 // Functions from aApply.d and aApplyR.d in the runtime
7335 bool rvs = (idlen == 11); // true if foreach_reverse
7336 char c = id[idlen - 3]; // char width: 'c', 'w', or 'd'
7337 char s = id[idlen - 2]; // string width: 'c', 'w', or 'd'
7338 char n = id[idlen - 1]; // numParams: 1 or 2.
7339 // There are 12 combinations
7340 if ((n == '1' || n == '2') &&
7341 (c == 'c' || c == 'w' || c == 'd') &&
7342 (s == 'c' || s == 'w' || s == 'd') &&
7343 c != s)
7344 {
7345 Expression str = (*arguments)[0];
7346 str = interpret(str, istate);
7347 if (exceptionOrCantInterpret(str))
7348 return str;
7349 return foreachApplyUtf(pue, istate, str, (*arguments)[1], rvs);
7350 }
7351 }
7352 }
7353 return e;
7354 }
7355
evaluatePostblit(InterState * istate,Expression e)7356 private Expression evaluatePostblit(InterState* istate, Expression e)
7357 {
7358 auto ts = e.type.baseElemOf().isTypeStruct();
7359 if (!ts)
7360 return null;
7361 StructDeclaration sd = ts.sym;
7362 if (!sd.postblit)
7363 return null;
7364
7365 if (auto ale = e.isArrayLiteralExp())
7366 {
7367 foreach (elem; *ale.elements)
7368 {
7369 if (auto ex = evaluatePostblit(istate, elem))
7370 return ex;
7371 }
7372 return null;
7373 }
7374 if (e.op == EXP.structLiteral)
7375 {
7376 // e.__postblit()
7377 UnionExp ue = void;
7378 e = interpretFunction(&ue, sd.postblit, istate, null, e);
7379 if (e == ue.exp())
7380 e = ue.copy();
7381 if (exceptionOrCantInterpret(e))
7382 return e;
7383 return null;
7384 }
7385 assert(0);
7386 }
7387
evaluateDtor(InterState * istate,Expression e)7388 private Expression evaluateDtor(InterState* istate, Expression e)
7389 {
7390 auto ts = e.type.baseElemOf().isTypeStruct();
7391 if (!ts)
7392 return null;
7393 StructDeclaration sd = ts.sym;
7394 if (!sd.dtor)
7395 return null;
7396
7397 UnionExp ue = void;
7398 if (auto ale = e.isArrayLiteralExp())
7399 {
7400 foreach_reverse (elem; *ale.elements)
7401 e = evaluateDtor(istate, elem);
7402 }
7403 else if (e.op == EXP.structLiteral)
7404 {
7405 // e.__dtor()
7406 e = interpretFunction(&ue, sd.dtor, istate, null, e);
7407 }
7408 else
7409 assert(0);
7410 if (exceptionOrCantInterpret(e))
7411 {
7412 if (e == ue.exp())
7413 e = ue.copy();
7414 return e;
7415 }
7416 return null;
7417 }
7418
7419 /*************************** CTFE Sanity Checks ***************************/
7420 /* Setter functions for CTFE variable values.
7421 * These functions exist to check for compiler CTFE bugs.
7422 */
hasValue(VarDeclaration vd)7423 private bool hasValue(VarDeclaration vd)
7424 {
7425 return vd.ctfeAdrOnStack != VarDeclaration.AdrOnStackNone &&
7426 getValue(vd) !is null;
7427 }
7428
7429 // Don't check for validity
setValueWithoutChecking(VarDeclaration vd,Expression newval)7430 private void setValueWithoutChecking(VarDeclaration vd, Expression newval)
7431 {
7432 ctfeGlobals.stack.setValue(vd, newval);
7433 }
7434
setValue(VarDeclaration vd,Expression newval)7435 private void setValue(VarDeclaration vd, Expression newval)
7436 {
7437 //printf("setValue() vd: %s newval: %s\n", vd.toChars(), newval.toChars());
7438 version (none)
7439 {
7440 if (!((vd.storage_class & (STC.out_ | STC.ref_)) ? isCtfeReferenceValid(newval) : isCtfeValueValid(newval)))
7441 {
7442 printf("[%s] vd = %s %s, newval = %s\n", vd.loc.toChars(), vd.type.toChars(), vd.toChars(), newval.toChars());
7443 }
7444 }
7445 assert((vd.storage_class & (STC.out_ | STC.ref_)) ? isCtfeReferenceValid(newval) : isCtfeValueValid(newval));
7446 ctfeGlobals.stack.setValue(vd, newval);
7447 }
7448
7449 /**
7450 * Removes `_d_HookTraceImpl` if found from `ce` and `fd`.
7451 * This is needed for the CTFE interception code to be able to find hooks that are called though the hook's `*Trace`
7452 * wrapper.
7453 *
7454 * This is done by replacing `_d_HookTraceImpl!(T, Hook, errMsg)(..., parameters)` with `Hook(parameters)`.
7455 * Parameters:
7456 * ce = The CallExp that possible will be be replaced
7457 * fd = Fully resolve function declaration that `ce` would call
7458 */
removeHookTraceImpl(ref CallExp ce,ref FuncDeclaration fd)7459 private void removeHookTraceImpl(ref CallExp ce, ref FuncDeclaration fd)
7460 {
7461 if (fd.ident != Id._d_HookTraceImpl)
7462 return;
7463
7464 auto oldCE = ce;
7465
7466 // Get the Hook from the second template parameter
7467 TemplateInstance templateInstance = fd.parent.isTemplateInstance;
7468 RootObject hook = (*templateInstance.tiargs)[1];
7469 assert(hook.dyncast() == DYNCAST.dsymbol, "Expected _d_HookTraceImpl's second template parameter to be an alias to the hook!");
7470 fd = (cast(Dsymbol)hook).isFuncDeclaration;
7471
7472 // Remove the first three trace parameters
7473 auto arguments = new Expressions();
7474 arguments.reserve(ce.arguments.dim - 3);
7475 arguments.pushSlice((*ce.arguments)[3 .. $]);
7476
7477 ce = ctfeEmplaceExp!CallExp(ce.loc, ctfeEmplaceExp!VarExp(ce.loc, fd, false), arguments);
7478
7479 if (global.params.verbose)
7480 message("strip %s =>\n %s", oldCE.toChars(), ce.toChars());
7481 }
7482