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 if (!td.objects)
2295 return;
2296 foreach (o; *td.objects)
2297 {
2298 Expression ex = isExpression(o);
2299 DsymbolExp ds = ex ? ex.isDsymbolExp() : null;
2300 VarDeclaration v2 = ds ? ds.s.isVarDeclaration() : null;
2301 assert(v2);
2302 if (v2.isDataseg() && !v2.isCTFE())
2303 continue;
2304
2305 ctfeGlobals.stack.push(v2);
2306 if (v2._init)
2307 {
2308 Expression einit;
2309 if (ExpInitializer ie = v2._init.isExpInitializer())
2310 {
2311 einit = interpretRegion(ie.exp, istate, goal);
2312 if (exceptionOrCant(einit))
2313 return;
2314 }
2315 else if (v2._init.isVoidInitializer())
2316 {
2317 einit = voidInitLiteral(v2.type, v2).copy();
2318 }
2319 else
2320 {
2321 e.error("declaration `%s` is not yet implemented in CTFE", e.toChars());
2322 result = CTFEExp.cantexp;
2323 return;
2324 }
2325 setValue(v2, einit);
2326 }
2327 }
2328 return;
2329 }
2330 if (v.isStatic())
2331 {
2332 // Just ignore static variables which aren't read or written yet
2333 result = null;
2334 return;
2335 }
2336 if (!(v.isDataseg() || v.storage_class & STC.manifest) || v.isCTFE())
2337 ctfeGlobals.stack.push(v);
2338 if (v._init)
2339 {
2340 if (ExpInitializer ie = v._init.isExpInitializer())
2341 {
2342 result = interpretRegion(ie.exp, istate, goal);
2343 }
2344 else if (v._init.isVoidInitializer())
2345 {
2346 result = voidInitLiteral(v.type, v).copy();
2347 // There is no AssignExp for void initializers,
2348 // so set it here.
2349 setValue(v, result);
2350 }
2351 else
2352 {
2353 e.error("declaration `%s` is not yet implemented in CTFE", e.toChars());
2354 result = CTFEExp.cantexp;
2355 }
2356 }
2357 else if (v.type.size() == 0)
2358 {
2359 // Zero-length arrays don't need an initializer
2360 result = v.type.defaultInitLiteral(e.loc);
2361 }
2362 else
2363 {
2364 e.error("variable `%s` cannot be modified at compile time", v.toChars());
2365 result = CTFEExp.cantexp;
2366 }
2367 return;
2368 }
2369 if (s.isTemplateMixin() || s.isTupleDeclaration())
2370 {
2371 // These can be made to work, too lazy now
2372 e.error("declaration `%s` is not yet implemented in CTFE", e.toChars());
2373 result = CTFEExp.cantexp;
2374 return;
2375 }
2376
2377 // Others should not contain executable code, so are trivial to evaluate
2378 result = null;
2379 debug (LOG)
2380 {
2381 printf("-DeclarationExp::interpret(%s): %p\n", e.toChars(), result);
2382 }
2383 }
2384
visit(TypeidExp e)2385 override void visit(TypeidExp e)
2386 {
2387 debug (LOG)
2388 {
2389 printf("%s TypeidExp::interpret() %s\n", e.loc.toChars(), e.toChars());
2390 }
2391 if (Type t = isType(e.obj))
2392 {
2393 result = e;
2394 return;
2395 }
2396 if (Expression ex = isExpression(e.obj))
2397 {
2398 result = interpret(pue, ex, istate);
2399 if (exceptionOrCant(ex))
2400 return;
2401
2402 if (result.op == EXP.null_)
2403 {
2404 e.error("null pointer dereference evaluating typeid. `%s` is `null`", ex.toChars());
2405 result = CTFEExp.cantexp;
2406 return;
2407 }
2408 if (result.op != EXP.classReference)
2409 {
2410 e.error("CTFE internal error: determining classinfo");
2411 result = CTFEExp.cantexp;
2412 return;
2413 }
2414
2415 ClassDeclaration cd = result.isClassReferenceExp().originalClass();
2416 assert(cd);
2417
2418 emplaceExp!(TypeidExp)(pue, e.loc, cd.type);
2419 result = pue.exp();
2420 result.type = e.type;
2421 return;
2422 }
2423 visit(cast(Expression)e);
2424 }
2425
visit(TupleExp e)2426 override void visit(TupleExp e)
2427 {
2428 debug (LOG)
2429 {
2430 printf("%s TupleExp::interpret() %s\n", e.loc.toChars(), e.toChars());
2431 }
2432 if (exceptionOrCant(interpretRegion(e.e0, istate, CTFEGoal.Nothing)))
2433 return;
2434
2435 auto expsx = e.exps;
2436 foreach (i, exp; *expsx)
2437 {
2438 Expression ex = interpretRegion(exp, istate);
2439 if (exceptionOrCant(ex))
2440 return;
2441
2442 // A tuple of assignments can contain void (Bug 5676).
2443 if (goal == CTFEGoal.Nothing)
2444 continue;
2445 if (ex.op == EXP.voidExpression)
2446 {
2447 e.error("CTFE internal error: void element `%s` in tuple", exp.toChars());
2448 assert(0);
2449 }
2450
2451 /* If any changes, do Copy On Write
2452 */
2453 if (ex !is exp)
2454 {
2455 expsx = copyArrayOnWrite(expsx, e.exps);
2456 (*expsx)[i] = copyRegionExp(ex);
2457 }
2458 }
2459
2460 if (expsx !is e.exps)
2461 {
2462 expandTuples(expsx);
2463 emplaceExp!(TupleExp)(pue, e.loc, expsx);
2464 result = pue.exp();
2465 result.type = new TypeTuple(expsx);
2466 }
2467 else
2468 result = e;
2469 }
2470
visit(ArrayLiteralExp e)2471 override void visit(ArrayLiteralExp e)
2472 {
2473 debug (LOG)
2474 {
2475 printf("%s ArrayLiteralExp::interpret() %s\n", e.loc.toChars(), e.toChars());
2476 }
2477 if (e.ownedByCtfe >= OwnedBy.ctfe) // We've already interpreted all the elements
2478 {
2479 result = e;
2480 return;
2481 }
2482
2483 Type tn = e.type.toBasetype().nextOf().toBasetype();
2484 bool wantCopy = (tn.ty == Tsarray || tn.ty == Tstruct);
2485
2486 auto basis = interpretRegion(e.basis, istate);
2487 if (exceptionOrCant(basis))
2488 return;
2489
2490 auto expsx = e.elements;
2491 size_t dim = expsx ? expsx.dim : 0;
2492 for (size_t i = 0; i < dim; i++)
2493 {
2494 Expression exp = (*expsx)[i];
2495 Expression ex;
2496 if (!exp)
2497 {
2498 ex = copyLiteral(basis).copy();
2499 }
2500 else
2501 {
2502 // segfault bug 6250
2503 assert(exp.op != EXP.index || exp.isIndexExp().e1 != e);
2504
2505 ex = interpretRegion(exp, istate);
2506 if (exceptionOrCant(ex))
2507 return;
2508
2509 /* Each elements should have distinct CTFE memory.
2510 * int[1] z = 7;
2511 * int[1][] pieces = [z,z]; // here
2512 */
2513 if (wantCopy)
2514 ex = copyLiteral(ex).copy();
2515 }
2516
2517 /* If any changes, do Copy On Write
2518 */
2519 if (ex !is exp)
2520 {
2521 expsx = copyArrayOnWrite(expsx, e.elements);
2522 (*expsx)[i] = ex;
2523 }
2524 }
2525
2526 if (expsx !is e.elements)
2527 {
2528 // todo: all tuple expansions should go in semantic phase.
2529 expandTuples(expsx);
2530 if (expsx.dim != dim)
2531 {
2532 e.error("CTFE internal error: invalid array literal");
2533 result = CTFEExp.cantexp;
2534 return;
2535 }
2536 emplaceExp!(ArrayLiteralExp)(pue, e.loc, e.type, basis, expsx);
2537 auto ale = pue.exp().isArrayLiteralExp();
2538 ale.ownedByCtfe = OwnedBy.ctfe;
2539 result = ale;
2540 }
2541 else if ((cast(TypeNext)e.type).next.mod & (MODFlags.const_ | MODFlags.immutable_))
2542 {
2543 // If it's immutable, we don't need to dup it
2544 result = e;
2545 }
2546 else
2547 {
2548 *pue = copyLiteral(e);
2549 result = pue.exp();
2550 }
2551 }
2552
visit(AssocArrayLiteralExp e)2553 override void visit(AssocArrayLiteralExp e)
2554 {
2555 debug (LOG)
2556 {
2557 printf("%s AssocArrayLiteralExp::interpret() %s\n", e.loc.toChars(), e.toChars());
2558 }
2559 if (e.ownedByCtfe >= OwnedBy.ctfe) // We've already interpreted all the elements
2560 {
2561 result = e;
2562 return;
2563 }
2564
2565 auto keysx = e.keys;
2566 auto valuesx = e.values;
2567 foreach (i, ekey; *keysx)
2568 {
2569 auto evalue = (*valuesx)[i];
2570
2571 auto ek = interpretRegion(ekey, istate);
2572 if (exceptionOrCant(ek))
2573 return;
2574 auto ev = interpretRegion(evalue, istate);
2575 if (exceptionOrCant(ev))
2576 return;
2577
2578 /* If any changes, do Copy On Write
2579 */
2580 if (ek !is ekey ||
2581 ev !is evalue)
2582 {
2583 keysx = copyArrayOnWrite(keysx, e.keys);
2584 valuesx = copyArrayOnWrite(valuesx, e.values);
2585 (*keysx)[i] = ek;
2586 (*valuesx)[i] = ev;
2587 }
2588 }
2589 if (keysx !is e.keys)
2590 expandTuples(keysx);
2591 if (valuesx !is e.values)
2592 expandTuples(valuesx);
2593 if (keysx.dim != valuesx.dim)
2594 {
2595 e.error("CTFE internal error: invalid AA");
2596 result = CTFEExp.cantexp;
2597 return;
2598 }
2599
2600 /* Remove duplicate keys
2601 */
2602 for (size_t i = 1; i < keysx.dim; i++)
2603 {
2604 auto ekey = (*keysx)[i - 1];
2605 for (size_t j = i; j < keysx.dim; j++)
2606 {
2607 auto ekey2 = (*keysx)[j];
2608 if (!ctfeEqual(e.loc, EXP.equal, ekey, ekey2))
2609 continue;
2610
2611 // Remove ekey
2612 keysx = copyArrayOnWrite(keysx, e.keys);
2613 valuesx = copyArrayOnWrite(valuesx, e.values);
2614 keysx.remove(i - 1);
2615 valuesx.remove(i - 1);
2616
2617 i -= 1; // redo the i'th iteration
2618 break;
2619 }
2620 }
2621
2622 if (keysx !is e.keys ||
2623 valuesx !is e.values)
2624 {
2625 assert(keysx !is e.keys &&
2626 valuesx !is e.values);
2627 auto aae = ctfeEmplaceExp!AssocArrayLiteralExp(e.loc, keysx, valuesx);
2628 aae.type = e.type;
2629 aae.ownedByCtfe = OwnedBy.ctfe;
2630 result = aae;
2631 }
2632 else
2633 {
2634 *pue = copyLiteral(e);
2635 result = pue.exp();
2636 }
2637 }
2638
visit(StructLiteralExp e)2639 override void visit(StructLiteralExp e)
2640 {
2641 debug (LOG)
2642 {
2643 printf("%s StructLiteralExp::interpret() %s ownedByCtfe = %d\n", e.loc.toChars(), e.toChars(), e.ownedByCtfe);
2644 }
2645 if (e.ownedByCtfe >= OwnedBy.ctfe)
2646 {
2647 result = e;
2648 return;
2649 }
2650
2651 size_t dim = e.elements ? e.elements.dim : 0;
2652 auto expsx = e.elements;
2653
2654 if (dim != e.sd.fields.dim)
2655 {
2656 // guaranteed by AggregateDeclaration.fill and TypeStruct.defaultInitLiteral
2657 const nvthis = e.sd.fields.dim - e.sd.nonHiddenFields();
2658 assert(e.sd.fields.dim - dim == nvthis);
2659
2660 /* If a nested struct has no initialized hidden pointer,
2661 * set it to null to match the runtime behaviour.
2662 */
2663 foreach (const i; 0 .. nvthis)
2664 {
2665 auto ne = ctfeEmplaceExp!NullExp(e.loc);
2666 auto vthis = i == 0 ? e.sd.vthis : e.sd.vthis2;
2667 ne.type = vthis.type;
2668
2669 expsx = copyArrayOnWrite(expsx, e.elements);
2670 expsx.push(ne);
2671 ++dim;
2672 }
2673 }
2674 assert(dim == e.sd.fields.dim);
2675
2676 foreach (i; 0 .. dim)
2677 {
2678 auto v = e.sd.fields[i];
2679 Expression exp = (*expsx)[i];
2680 Expression ex;
2681 if (!exp)
2682 {
2683 ex = voidInitLiteral(v.type, v).copy();
2684 }
2685 else
2686 {
2687 ex = interpretRegion(exp, istate);
2688 if (exceptionOrCant(ex))
2689 return;
2690 if ((v.type.ty != ex.type.ty) && v.type.ty == Tsarray)
2691 {
2692 // Block assignment from inside struct literals
2693 auto tsa = cast(TypeSArray)v.type;
2694 auto len = cast(size_t)tsa.dim.toInteger();
2695 UnionExp ue = void;
2696 ex = createBlockDuplicatedArrayLiteral(&ue, ex.loc, v.type, ex, len);
2697 if (ex == ue.exp())
2698 ex = ue.copy();
2699 }
2700 }
2701
2702 /* If any changes, do Copy On Write
2703 */
2704 if (ex !is exp)
2705 {
2706 expsx = copyArrayOnWrite(expsx, e.elements);
2707 (*expsx)[i] = ex;
2708 }
2709 }
2710
2711 if (expsx !is e.elements)
2712 {
2713 expandTuples(expsx);
2714 if (expsx.dim != e.sd.fields.dim)
2715 {
2716 e.error("CTFE internal error: invalid struct literal");
2717 result = CTFEExp.cantexp;
2718 return;
2719 }
2720 emplaceExp!(StructLiteralExp)(pue, e.loc, e.sd, expsx);
2721 auto sle = pue.exp().isStructLiteralExp();
2722 sle.type = e.type;
2723 sle.ownedByCtfe = OwnedBy.ctfe;
2724 sle.origin = e.origin;
2725 result = sle;
2726 }
2727 else
2728 {
2729 *pue = copyLiteral(e);
2730 result = pue.exp();
2731 }
2732 }
2733
2734 // Create an array literal of type 'newtype' with dimensions given by
2735 // 'arguments'[argnum..$]
recursivelyCreateArrayLiteral(UnionExp * pue,const ref Loc loc,Type newtype,InterState * istate,Expressions * arguments,int argnum)2736 static Expression recursivelyCreateArrayLiteral(UnionExp* pue, const ref Loc loc, Type newtype, InterState* istate, Expressions* arguments, int argnum)
2737 {
2738 Expression lenExpr = interpret(pue, (*arguments)[argnum], istate);
2739 if (exceptionOrCantInterpret(lenExpr))
2740 return lenExpr;
2741 size_t len = cast(size_t)lenExpr.toInteger();
2742 Type elemType = (cast(TypeArray)newtype).next;
2743 if (elemType.ty == Tarray && argnum < arguments.dim - 1)
2744 {
2745 Expression elem = recursivelyCreateArrayLiteral(pue, loc, elemType, istate, arguments, argnum + 1);
2746 if (exceptionOrCantInterpret(elem))
2747 return elem;
2748
2749 auto elements = new Expressions(len);
2750 foreach (ref element; *elements)
2751 element = copyLiteral(elem).copy();
2752 emplaceExp!(ArrayLiteralExp)(pue, loc, newtype, elements);
2753 auto ae = pue.exp().isArrayLiteralExp();
2754 ae.ownedByCtfe = OwnedBy.ctfe;
2755 return ae;
2756 }
2757 assert(argnum == arguments.dim - 1);
2758 if (elemType.ty.isSomeChar)
2759 {
2760 const ch = cast(dchar)elemType.defaultInitLiteral(loc).toInteger();
2761 const sz = cast(ubyte)elemType.size();
2762 return createBlockDuplicatedStringLiteral(pue, loc, newtype, ch, len, sz);
2763 }
2764 else
2765 {
2766 auto el = interpret(elemType.defaultInitLiteral(loc), istate);
2767 return createBlockDuplicatedArrayLiteral(pue, loc, newtype, el, len);
2768 }
2769 }
2770
visit(NewExp e)2771 override void visit(NewExp e)
2772 {
2773 debug (LOG)
2774 {
2775 printf("%s NewExp::interpret() %s\n", e.loc.toChars(), e.toChars());
2776 }
2777
2778 Expression epre = interpret(pue, e.argprefix, istate, CTFEGoal.Nothing);
2779 if (exceptionOrCant(epre))
2780 return;
2781
2782 if (e.newtype.ty == Tarray && e.arguments)
2783 {
2784 result = recursivelyCreateArrayLiteral(pue, e.loc, e.newtype, istate, e.arguments, 0);
2785 return;
2786 }
2787 if (auto ts = e.newtype.toBasetype().isTypeStruct())
2788 {
2789 if (e.member)
2790 {
2791 Expression se = e.newtype.defaultInitLiteral(e.loc);
2792 se = interpret(se, istate);
2793 if (exceptionOrCant(se))
2794 return;
2795 result = interpretFunction(pue, e.member, istate, e.arguments, se);
2796
2797 // Repaint as same as CallExp::interpret() does.
2798 result.loc = e.loc;
2799 }
2800 else
2801 {
2802 StructDeclaration sd = ts.sym;
2803 auto exps = new Expressions();
2804 exps.reserve(sd.fields.dim);
2805 if (e.arguments)
2806 {
2807 exps.setDim(e.arguments.dim);
2808 foreach (i, ex; *e.arguments)
2809 {
2810 ex = interpretRegion(ex, istate);
2811 if (exceptionOrCant(ex))
2812 return;
2813 (*exps)[i] = ex;
2814 }
2815 }
2816 sd.fill(e.loc, exps, false);
2817
2818 auto se = ctfeEmplaceExp!StructLiteralExp(e.loc, sd, exps, e.newtype);
2819 se.origin = se;
2820 se.type = e.newtype;
2821 se.ownedByCtfe = OwnedBy.ctfe;
2822 result = interpret(pue, se, istate);
2823 }
2824 if (exceptionOrCant(result))
2825 return;
2826 Expression ev = (result == pue.exp()) ? pue.copy() : result;
2827 emplaceExp!(AddrExp)(pue, e.loc, ev, e.type);
2828 result = pue.exp();
2829 return;
2830 }
2831 if (auto tc = e.newtype.toBasetype().isTypeClass())
2832 {
2833 ClassDeclaration cd = tc.sym;
2834 size_t totalFieldCount = 0;
2835 for (ClassDeclaration c = cd; c; c = c.baseClass)
2836 totalFieldCount += c.fields.dim;
2837 auto elems = new Expressions(totalFieldCount);
2838 size_t fieldsSoFar = totalFieldCount;
2839 for (ClassDeclaration c = cd; c; c = c.baseClass)
2840 {
2841 fieldsSoFar -= c.fields.dim;
2842 foreach (i, v; c.fields)
2843 {
2844 if (v.inuse)
2845 {
2846 e.error("circular reference to `%s`", v.toPrettyChars());
2847 result = CTFEExp.cantexp;
2848 return;
2849 }
2850 Expression m;
2851 if (v._init)
2852 {
2853 if (v._init.isVoidInitializer())
2854 m = voidInitLiteral(v.type, v).copy();
2855 else
2856 m = v.getConstInitializer(true);
2857 }
2858 else
2859 m = v.type.defaultInitLiteral(e.loc);
2860 if (exceptionOrCant(m))
2861 return;
2862 (*elems)[fieldsSoFar + i] = copyLiteral(m).copy();
2863 }
2864 }
2865 // Hack: we store a ClassDeclaration instead of a StructDeclaration.
2866 // We probably won't get away with this.
2867 // auto se = new StructLiteralExp(e.loc, cast(StructDeclaration)cd, elems, e.newtype);
2868 auto se = ctfeEmplaceExp!StructLiteralExp(e.loc, cast(StructDeclaration)cd, elems, e.newtype);
2869 se.origin = se;
2870 se.ownedByCtfe = OwnedBy.ctfe;
2871 Expression eref = ctfeEmplaceExp!ClassReferenceExp(e.loc, se, e.type);
2872 if (e.member)
2873 {
2874 // Call constructor
2875 if (!e.member.fbody)
2876 {
2877 Expression ctorfail = evaluateIfBuiltin(pue, istate, e.loc, e.member, e.arguments, eref);
2878 if (ctorfail)
2879 {
2880 if (exceptionOrCant(ctorfail))
2881 return;
2882 result = eref;
2883 return;
2884 }
2885 e.member.error("`%s` cannot be constructed at compile time, because the constructor has no available source code", e.newtype.toChars());
2886 result = CTFEExp.cantexp;
2887 return;
2888 }
2889 UnionExp ue = void;
2890 Expression ctorfail = interpretFunction(&ue, e.member, istate, e.arguments, eref);
2891 if (exceptionOrCant(ctorfail))
2892 return;
2893
2894 /* https://issues.dlang.org/show_bug.cgi?id=14465
2895 * Repaint the loc, because a super() call
2896 * in the constructor modifies the loc of ClassReferenceExp
2897 * in CallExp::interpret().
2898 */
2899 eref.loc = e.loc;
2900 }
2901 result = eref;
2902 return;
2903 }
2904 if (e.newtype.toBasetype().isscalar())
2905 {
2906 Expression newval;
2907 if (e.arguments && e.arguments.dim)
2908 newval = (*e.arguments)[0];
2909 else
2910 newval = e.newtype.defaultInitLiteral(e.loc);
2911 newval = interpretRegion(newval, istate);
2912 if (exceptionOrCant(newval))
2913 return;
2914
2915 // Create a CTFE pointer &[newval][0]
2916 auto elements = new Expressions(1);
2917 (*elements)[0] = newval;
2918 auto ae = ctfeEmplaceExp!ArrayLiteralExp(e.loc, e.newtype.arrayOf(), elements);
2919 ae.ownedByCtfe = OwnedBy.ctfe;
2920
2921 auto ei = ctfeEmplaceExp!IndexExp(e.loc, ae, ctfeEmplaceExp!IntegerExp(Loc.initial, 0, Type.tsize_t));
2922 ei.type = e.newtype;
2923 emplaceExp!(AddrExp)(pue, e.loc, ei, e.type);
2924 result = pue.exp();
2925 return;
2926 }
2927 e.error("cannot interpret `%s` at compile time", e.toChars());
2928 result = CTFEExp.cantexp;
2929 }
2930
visit(UnaExp e)2931 override void visit(UnaExp e)
2932 {
2933 debug (LOG)
2934 {
2935 printf("%s UnaExp::interpret() %s\n", e.loc.toChars(), e.toChars());
2936 }
2937 UnionExp ue = void;
2938 Expression e1 = interpret(&ue, e.e1, istate);
2939 if (exceptionOrCant(e1))
2940 return;
2941 switch (e.op)
2942 {
2943 case EXP.negate:
2944 *pue = Neg(e.type, e1);
2945 break;
2946
2947 case EXP.tilde:
2948 *pue = Com(e.type, e1);
2949 break;
2950
2951 case EXP.not:
2952 *pue = Not(e.type, e1);
2953 break;
2954
2955 default:
2956 assert(0);
2957 }
2958 result = (*pue).exp();
2959 }
2960
visit(DotTypeExp e)2961 override void visit(DotTypeExp e)
2962 {
2963 debug (LOG)
2964 {
2965 printf("%s DotTypeExp::interpret() %s\n", e.loc.toChars(), e.toChars());
2966 }
2967 UnionExp ue = void;
2968 Expression e1 = interpret(&ue, e.e1, istate);
2969 if (exceptionOrCant(e1))
2970 return;
2971 if (e1 == e.e1)
2972 result = e; // optimize: reuse this CTFE reference
2973 else
2974 {
2975 auto edt = e.copy().isDotTypeExp();
2976 edt.e1 = (e1 == ue.exp()) ? e1.copy() : e1; // don't return pointer to ue
2977 result = edt;
2978 }
2979 }
2980
interpretCommon(BinExp e,fp_t fp)2981 extern (D) private void interpretCommon(BinExp e, fp_t fp)
2982 {
2983 debug (LOG)
2984 {
2985 printf("%s BinExp::interpretCommon() %s\n", e.loc.toChars(), e.toChars());
2986 }
2987 if (e.e1.type.ty == Tpointer && e.e2.type.ty == Tpointer && e.op == EXP.min)
2988 {
2989 UnionExp ue1 = void;
2990 Expression e1 = interpret(&ue1, e.e1, istate);
2991 if (exceptionOrCant(e1))
2992 return;
2993 UnionExp ue2 = void;
2994 Expression e2 = interpret(&ue2, e.e2, istate);
2995 if (exceptionOrCant(e2))
2996 return;
2997 result = pointerDifference(pue, e.loc, e.type, e1, e2);
2998 return;
2999 }
3000 if (e.e1.type.ty == Tpointer && e.e2.type.isintegral())
3001 {
3002 UnionExp ue1 = void;
3003 Expression e1 = interpret(&ue1, e.e1, istate);
3004 if (exceptionOrCant(e1))
3005 return;
3006 UnionExp ue2 = void;
3007 Expression e2 = interpret(&ue2, e.e2, istate);
3008 if (exceptionOrCant(e2))
3009 return;
3010 result = pointerArithmetic(pue, e.loc, e.op, e.type, e1, e2);
3011 return;
3012 }
3013 if (e.e2.type.ty == Tpointer && e.e1.type.isintegral() && e.op == EXP.add)
3014 {
3015 UnionExp ue1 = void;
3016 Expression e1 = interpret(&ue1, e.e1, istate);
3017 if (exceptionOrCant(e1))
3018 return;
3019 UnionExp ue2 = void;
3020 Expression e2 = interpret(&ue2, e.e2, istate);
3021 if (exceptionOrCant(e2))
3022 return;
3023 result = pointerArithmetic(pue, e.loc, e.op, e.type, e2, e1);
3024 return;
3025 }
3026 if (e.e1.type.ty == Tpointer || e.e2.type.ty == Tpointer)
3027 {
3028 e.error("pointer expression `%s` cannot be interpreted at compile time", e.toChars());
3029 result = CTFEExp.cantexp;
3030 return;
3031 }
3032
3033 bool evalOperand(UnionExp* pue, Expression ex, out Expression er)
3034 {
3035 er = interpret(pue, ex, istate);
3036 if (exceptionOrCant(er))
3037 return false;
3038 return true;
3039 }
3040
3041 UnionExp ue1 = void;
3042 Expression e1;
3043 if (!evalOperand(&ue1, e.e1, e1))
3044 return;
3045
3046 UnionExp ue2 = void;
3047 Expression e2;
3048 if (!evalOperand(&ue2, e.e2, e2))
3049 return;
3050
3051 if (e.op == EXP.rightShift || e.op == EXP.leftShift || e.op == EXP.unsignedRightShift)
3052 {
3053 const sinteger_t i2 = e2.toInteger();
3054 const uinteger_t sz = e1.type.size() * 8;
3055 if (i2 < 0 || i2 >= sz)
3056 {
3057 e.error("shift by %lld is outside the range 0..%llu", i2, cast(ulong)sz - 1);
3058 result = CTFEExp.cantexp;
3059 return;
3060 }
3061 }
3062
3063 /******************************************
3064 * Perform the operation fp on operands e1 and e2.
3065 */
3066 UnionExp evaluate(Loc loc, Type type, Expression e1, Expression e2)
3067 {
3068 UnionExp ue = void;
3069 auto ae1 = e1.isArrayLiteralExp();
3070 auto ae2 = e2.isArrayLiteralExp();
3071 if (ae1 || ae2)
3072 {
3073 /* Cases:
3074 * 1. T[] op T[]
3075 * 2. T op T[]
3076 * 3. T[] op T
3077 */
3078 if (ae1 && e2.implicitConvTo(e1.type.toBasetype().nextOf())) // case 3
3079 ae2 = null;
3080 else if (ae2 && e1.implicitConvTo(e2.type.toBasetype().nextOf())) // case 2
3081 ae1 = null;
3082 // else case 1
3083
3084 auto aex = ae1 ? ae1 : ae2;
3085 if (!aex.elements)
3086 {
3087 emplaceExp!ArrayLiteralExp(&ue, loc, type, cast(Expressions*) null);
3088 return ue;
3089 }
3090 const length = aex.elements.length;
3091 Expressions* elements = new Expressions(length);
3092
3093 emplaceExp!ArrayLiteralExp(&ue, loc, type, elements);
3094 foreach (i; 0 .. length)
3095 {
3096 Expression e1x = ae1 ? ae1[i] : e1;
3097 Expression e2x = ae2 ? ae2[i] : e2;
3098 UnionExp uex = evaluate(loc, e1x.type, e1x, e2x);
3099 // This can be made more efficient by making use of ue.basis
3100 (*elements)[i] = uex.copy();
3101 }
3102 return ue;
3103 }
3104
3105 if (e1.isConst() != 1)
3106 {
3107 // The following should really be an assert()
3108 e1.error("CTFE internal error: non-constant value `%s`", e1.toChars());
3109 emplaceExp!CTFEExp(&ue, EXP.cantExpression);
3110 return ue;
3111 }
3112 if (e2.isConst() != 1)
3113 {
3114 e2.error("CTFE internal error: non-constant value `%s`", e2.toChars());
3115 emplaceExp!CTFEExp(&ue, EXP.cantExpression);
3116 return ue;
3117 }
3118
3119 return (*fp)(loc, type, e1, e2);
3120 }
3121
3122 *pue = evaluate(e.loc, e.type, e1, e2);
3123 result = (*pue).exp();
3124 if (CTFEExp.isCantExp(result))
3125 e.error("`%s` cannot be interpreted at compile time", e.toChars());
3126 }
3127
interpretCompareCommon(BinExp e,fp2_t fp)3128 extern (D) private void interpretCompareCommon(BinExp e, fp2_t fp)
3129 {
3130 debug (LOG)
3131 {
3132 printf("%s BinExp::interpretCompareCommon() %s\n", e.loc.toChars(), e.toChars());
3133 }
3134 UnionExp ue1 = void;
3135 UnionExp ue2 = void;
3136 if (e.e1.type.ty == Tpointer && e.e2.type.ty == Tpointer)
3137 {
3138 Expression e1 = interpret(&ue1, e.e1, istate);
3139 if (exceptionOrCant(e1))
3140 return;
3141 Expression e2 = interpret(&ue2, e.e2, istate);
3142 if (exceptionOrCant(e2))
3143 return;
3144 //printf("e1 = %s %s, e2 = %s %s\n", e1.type.toChars(), e1.toChars(), e2.type.toChars(), e2.toChars());
3145 dinteger_t ofs1, ofs2;
3146 Expression agg1 = getAggregateFromPointer(e1, &ofs1);
3147 Expression agg2 = getAggregateFromPointer(e2, &ofs2);
3148 //printf("agg1 = %p %s, agg2 = %p %s\n", agg1, agg1.toChars(), agg2, agg2.toChars());
3149 const cmp = comparePointers(e.op, agg1, ofs1, agg2, ofs2);
3150 if (cmp == -1)
3151 {
3152 char dir = (e.op == EXP.greaterThan || e.op == EXP.greaterOrEqual) ? '<' : '>';
3153 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());
3154 result = CTFEExp.cantexp;
3155 return;
3156 }
3157 if (e.type.equals(Type.tbool))
3158 result = IntegerExp.createBool(cmp != 0);
3159 else
3160 {
3161 emplaceExp!(IntegerExp)(pue, e.loc, cmp, e.type);
3162 result = (*pue).exp();
3163 }
3164 return;
3165 }
3166 Expression e1 = interpret(&ue1, e.e1, istate);
3167 if (exceptionOrCant(e1))
3168 return;
3169 if (!isCtfeComparable(e1))
3170 {
3171 e.error("cannot compare `%s` at compile time", e1.toChars());
3172 result = CTFEExp.cantexp;
3173 return;
3174 }
3175 Expression e2 = interpret(&ue2, e.e2, istate);
3176 if (exceptionOrCant(e2))
3177 return;
3178 if (!isCtfeComparable(e2))
3179 {
3180 e.error("cannot compare `%s` at compile time", e2.toChars());
3181 result = CTFEExp.cantexp;
3182 return;
3183 }
3184 const cmp = (*fp)(e.loc, e.op, e1, e2);
3185 if (e.type.equals(Type.tbool))
3186 result = IntegerExp.createBool(cmp);
3187 else
3188 {
3189 emplaceExp!(IntegerExp)(pue, e.loc, cmp, e.type);
3190 result = (*pue).exp();
3191 }
3192 }
3193
visit(BinExp e)3194 override void visit(BinExp e)
3195 {
3196 switch (e.op)
3197 {
3198 case EXP.add:
3199 interpretCommon(e, &Add);
3200 return;
3201
3202 case EXP.min:
3203 interpretCommon(e, &Min);
3204 return;
3205
3206 case EXP.mul:
3207 interpretCommon(e, &Mul);
3208 return;
3209
3210 case EXP.div:
3211 interpretCommon(e, &Div);
3212 return;
3213
3214 case EXP.mod:
3215 interpretCommon(e, &Mod);
3216 return;
3217
3218 case EXP.leftShift:
3219 interpretCommon(e, &Shl);
3220 return;
3221
3222 case EXP.rightShift:
3223 interpretCommon(e, &Shr);
3224 return;
3225
3226 case EXP.unsignedRightShift:
3227 interpretCommon(e, &Ushr);
3228 return;
3229
3230 case EXP.and:
3231 interpretCommon(e, &And);
3232 return;
3233
3234 case EXP.or:
3235 interpretCommon(e, &Or);
3236 return;
3237
3238 case EXP.xor:
3239 interpretCommon(e, &Xor);
3240 return;
3241
3242 case EXP.pow:
3243 interpretCommon(e, &Pow);
3244 return;
3245
3246 case EXP.equal:
3247 case EXP.notEqual:
3248 interpretCompareCommon(e, &ctfeEqual);
3249 return;
3250
3251 case EXP.identity:
3252 case EXP.notIdentity:
3253 interpretCompareCommon(e, &ctfeIdentity);
3254 return;
3255
3256 case EXP.lessThan:
3257 case EXP.lessOrEqual:
3258 case EXP.greaterThan:
3259 case EXP.greaterOrEqual:
3260 interpretCompareCommon(e, &ctfeCmp);
3261 return;
3262
3263 default:
3264 printf("be = '%s' %s at [%s]\n", EXPtoString(e.op).ptr, e.toChars(), e.loc.toChars());
3265 assert(0);
3266 }
3267 }
3268
3269 /* Helper functions for BinExp::interpretAssignCommon
3270 */
3271 // Returns the variable which is eventually modified, or NULL if an rvalue.
3272 // thisval is the current value of 'this'.
findParentVar(Expression e)3273 static VarDeclaration findParentVar(Expression e)
3274 {
3275 for (;;)
3276 {
3277 if (auto ve = e.isVarExp())
3278 {
3279 VarDeclaration v = ve.var.isVarDeclaration();
3280 assert(v);
3281 return v;
3282 }
3283 if (auto ie = e.isIndexExp())
3284 e = ie.e1;
3285 else if (auto dve = e.isDotVarExp())
3286 e = dve.e1;
3287 else if (auto dtie = e.isDotTemplateInstanceExp())
3288 e = dtie.e1;
3289 else if (auto se = e.isSliceExp())
3290 e = se.e1;
3291 else
3292 return null;
3293 }
3294 }
3295
3296 extern (D) private void interpretAssignCommon(BinExp e, fp_t fp, int post = 0)
3297 {
debug(LOG)3298 debug (LOG)
3299 {
3300 printf("%s BinExp::interpretAssignCommon() %s\n", e.loc.toChars(), e.toChars());
3301 }
3302 result = CTFEExp.cantexp;
3303
3304 Expression e1 = e.e1;
3305 if (!istate)
3306 {
3307 e.error("value of `%s` is not known at compile time", e1.toChars());
3308 return;
3309 }
3310
3311 ++ctfeGlobals.numAssignments;
3312
3313 /* Before we begin, we need to know if this is a reference assignment
3314 * (dynamic array, AA, or class) or a value assignment.
3315 * Determining this for slice assignments are tricky: we need to know
3316 * if it is a block assignment (a[] = e) rather than a direct slice
3317 * assignment (a[] = b[]). Note that initializers of multi-dimensional
3318 * static arrays can have 2D block assignments (eg, int[7][7] x = 6;).
3319 * So we need to recurse to determine if it is a block assignment.
3320 */
3321 bool isBlockAssignment = false;
3322 if (e1.op == EXP.slice)
3323 {
3324 // a[] = e can have const e. So we compare the naked types.
3325 Type tdst = e1.type.toBasetype();
3326 Type tsrc = e.e2.type.toBasetype();
3327 while (tdst.ty == Tsarray || tdst.ty == Tarray)
3328 {
3329 tdst = (cast(TypeArray)tdst).next.toBasetype();
3330 if (tsrc.equivalent(tdst))
3331 {
3332 isBlockAssignment = true;
3333 break;
3334 }
3335 }
3336 }
3337
3338 // ---------------------------------------
3339 // Deal with reference assignment
3340 // ---------------------------------------
3341 // If it is a construction of a ref variable, it is a ref assignment
3342 if ((e.op == EXP.construct || e.op == EXP.blit) &&
3343 ((cast(AssignExp)e).memset == MemorySet.referenceInit))
3344 {
3345 assert(!fp);
3346
3347 Expression newval = interpretRegion(e.e2, istate, CTFEGoal.LValue);
3348 if (exceptionOrCant(newval))
3349 return;
3350
3351 VarDeclaration v = e1.isVarExp().var.isVarDeclaration();
3352 setValue(v, newval);
3353
3354 // Get the value to return. Note that 'newval' is an Lvalue,
3355 // so if we need an Rvalue, we have to interpret again.
3356 if (goal == CTFEGoal.RValue)
3357 result = interpretRegion(newval, istate);
3358 else
3359 result = e1; // VarExp is a CTFE reference
3360 return;
3361 }
3362
3363 if (fp)
3364 {
3365 while (e1.op == EXP.cast_)
3366 {
3367 CastExp ce = e1.isCastExp();
3368 e1 = ce.e1;
3369 }
3370 }
3371
3372 // ---------------------------------------
3373 // Interpret left hand side
3374 // ---------------------------------------
3375 AssocArrayLiteralExp existingAA = null;
3376 Expression lastIndex = null;
3377 Expression oldval = null;
3378 if (e1.op == EXP.index && e1.isIndexExp().e1.type.toBasetype().ty == Taarray)
3379 {
3380 // ---------------------------------------
3381 // Deal with AA index assignment
3382 // ---------------------------------------
3383 /* This needs special treatment if the AA doesn't exist yet.
3384 * There are two special cases:
3385 * (1) If the AA is itself an index of another AA, we may need to create
3386 * multiple nested AA literals before we can insert the new value.
3387 * (2) If the ultimate AA is null, no insertion happens at all. Instead,
3388 * we create nested AA literals, and change it into a assignment.
3389 */
3390 IndexExp ie = e1.isIndexExp();
3391 int depth = 0; // how many nested AA indices are there?
3392 while (ie.e1.op == EXP.index && ie.e1.isIndexExp().e1.type.toBasetype().ty == Taarray)
3393 {
3394 assert(ie.modifiable);
3395 ie = ie.e1.isIndexExp();
3396 ++depth;
3397 }
3398
3399 // Get the AA value to be modified.
3400 Expression aggregate = interpretRegion(ie.e1, istate);
3401 if (exceptionOrCant(aggregate))
3402 return;
3403 if ((existingAA = aggregate.isAssocArrayLiteralExp()) !is null)
3404 {
3405 // Normal case, ultimate parent AA already exists
3406 // We need to walk from the deepest index up, checking that an AA literal
3407 // already exists on each level.
3408 lastIndex = interpretRegion(e1.isIndexExp().e2, istate);
3409 lastIndex = resolveSlice(lastIndex); // only happens with AA assignment
3410 if (exceptionOrCant(lastIndex))
3411 return;
3412
3413 while (depth > 0)
3414 {
3415 // Walk the syntax tree to find the indexExp at this depth
3416 IndexExp xe = e1.isIndexExp();
3417 foreach (d; 0 .. depth)
3418 xe = xe.e1.isIndexExp();
3419
3420 Expression ekey = interpretRegion(xe.e2, istate);
3421 if (exceptionOrCant(ekey))
3422 return;
3423 UnionExp ekeyTmp = void;
3424 ekey = resolveSlice(ekey, &ekeyTmp); // only happens with AA assignment
3425
3426 // Look up this index in it up in the existing AA, to get the next level of AA.
3427 AssocArrayLiteralExp newAA = cast(AssocArrayLiteralExp)findKeyInAA(e.loc, existingAA, ekey);
3428 if (exceptionOrCant(newAA))
3429 return;
3430 if (!newAA)
3431 {
3432 // Doesn't exist yet, create an empty AA...
3433 auto keysx = new Expressions();
3434 auto valuesx = new Expressions();
3435 newAA = ctfeEmplaceExp!AssocArrayLiteralExp(e.loc, keysx, valuesx);
3436 newAA.type = xe.type;
3437 newAA.ownedByCtfe = OwnedBy.ctfe;
3438 //... and insert it into the existing AA.
3439 existingAA.keys.push(ekey);
3440 existingAA.values.push(newAA);
3441 }
3442 existingAA = newAA;
3443 --depth;
3444 }
3445
3446 if (fp)
3447 {
3448 oldval = findKeyInAA(e.loc, existingAA, lastIndex);
3449 if (!oldval)
3450 oldval = copyLiteral(e.e1.type.defaultInitLiteral(e.loc)).copy();
3451 }
3452 }
3453 else
3454 {
3455 /* The AA is currently null. 'aggregate' is actually a reference to
3456 * whatever contains it. It could be anything: var, dotvarexp, ...
3457 * We rewrite the assignment from:
3458 * aa[i][j] op= newval;
3459 * into:
3460 * aa = [i:[j:T.init]];
3461 * aa[j] op= newval;
3462 */
3463 oldval = copyLiteral(e.e1.type.defaultInitLiteral(e.loc)).copy();
3464
3465 Expression newaae = oldval;
3466 while (e1.op == EXP.index && e1.isIndexExp().e1.type.toBasetype().ty == Taarray)
3467 {
3468 Expression ekey = interpretRegion(e1.isIndexExp().e2, istate);
3469 if (exceptionOrCant(ekey))
3470 return;
3471 ekey = resolveSlice(ekey); // only happens with AA assignment
3472
3473 auto keysx = new Expressions();
3474 auto valuesx = new Expressions();
3475 keysx.push(ekey);
3476 valuesx.push(newaae);
3477
3478 auto aae = ctfeEmplaceExp!AssocArrayLiteralExp(e.loc, keysx, valuesx);
3479 aae.type = e1.isIndexExp().e1.type;
3480 aae.ownedByCtfe = OwnedBy.ctfe;
3481 if (!existingAA)
3482 {
3483 existingAA = aae;
3484 lastIndex = ekey;
3485 }
3486 newaae = aae;
3487 e1 = e1.isIndexExp().e1;
3488 }
3489
3490 // We must set to aggregate with newaae
3491 e1 = interpretRegion(e1, istate, CTFEGoal.LValue);
3492 if (exceptionOrCant(e1))
3493 return;
3494 e1 = assignToLvalue(e, e1, newaae);
3495 if (exceptionOrCant(e1))
3496 return;
3497 }
3498 assert(existingAA && lastIndex);
3499 e1 = null; // stomp
3500 }
3501 else if (e1.op == EXP.arrayLength)
3502 {
3503 oldval = interpretRegion(e1, istate);
3504 if (exceptionOrCant(oldval))
3505 return;
3506 }
3507 else if (e.op == EXP.construct || e.op == EXP.blit)
3508 {
3509 // Unless we have a simple var assignment, we're
3510 // only modifying part of the variable. So we need to make sure
3511 // that the parent variable exists.
3512 VarDeclaration ultimateVar = findParentVar(e1);
3513 if (auto ve = e1.isVarExp())
3514 {
3515 VarDeclaration v = ve.var.isVarDeclaration();
3516 assert(v);
3517 if (v.storage_class & STC.out_)
3518 goto L1;
3519 }
3520 else if (ultimateVar && !getValue(ultimateVar))
3521 {
3522 Expression ex = interpretRegion(ultimateVar.type.defaultInitLiteral(e.loc), istate);
3523 if (exceptionOrCant(ex))
3524 return;
3525 setValue(ultimateVar, ex);
3526 }
3527 else
3528 goto L1;
3529 }
3530 else
3531 {
3532 L1:
3533 e1 = interpretRegion(e1, istate, CTFEGoal.LValue);
3534 if (exceptionOrCant(e1))
3535 return;
3536
3537 if (e1.op == EXP.index && e1.isIndexExp().e1.type.toBasetype().ty == Taarray)
3538 {
3539 IndexExp ie = e1.isIndexExp();
3540 assert(ie.e1.op == EXP.assocArrayLiteral);
3541 existingAA = ie.e1.isAssocArrayLiteralExp();
3542 lastIndex = ie.e2;
3543 }
3544 }
3545
3546 // ---------------------------------------
3547 // Interpret right hand side
3548 // ---------------------------------------
3549 Expression newval = interpretRegion(e.e2, istate);
3550 if (exceptionOrCant(newval))
3551 return;
3552 if (e.op == EXP.blit && newval.op == EXP.int64)
3553 {
3554 Type tbn = e.type.baseElemOf();
3555 if (tbn.ty == Tstruct)
3556 {
3557 /* Look for special case of struct being initialized with 0.
3558 */
3559 newval = e.type.defaultInitLiteral(e.loc);
3560 if (newval.op == EXP.error)
3561 {
3562 result = CTFEExp.cantexp;
3563 return;
3564 }
3565 newval = interpretRegion(newval, istate); // copy and set ownedByCtfe flag
3566 if (exceptionOrCant(newval))
3567 return;
3568 }
3569 }
3570
3571 // ----------------------------------------------------
3572 // Deal with read-modify-write assignments.
3573 // Set 'newval' to the final assignment value
3574 // Also determine the return value (except for slice
3575 // assignments, which are more complicated)
3576 // ----------------------------------------------------
3577 if (fp)
3578 {
3579 if (!oldval)
3580 {
3581 // Load the left hand side after interpreting the right hand side.
3582 oldval = interpretRegion(e1, istate);
3583 if (exceptionOrCant(oldval))
3584 return;
3585 }
3586
3587 if (e.e1.type.ty != Tpointer)
3588 {
3589 // ~= can create new values (see bug 6052)
3590 if (e.op == EXP.concatenateAssign || e.op == EXP.concatenateElemAssign || e.op == EXP.concatenateDcharAssign)
3591 {
3592 // We need to dup it and repaint the type. For a dynamic array
3593 // we can skip duplication, because it gets copied later anyway.
3594 if (newval.type.ty != Tarray)
3595 {
3596 newval = copyLiteral(newval).copy();
3597 newval.type = e.e2.type; // repaint type
3598 }
3599 else
3600 {
3601 newval = paintTypeOntoLiteral(e.e2.type, newval);
3602 newval = resolveSlice(newval);
3603 }
3604 }
3605 oldval = resolveSlice(oldval);
3606
3607 newval = (*fp)(e.loc, e.type, oldval, newval).copy();
3608 }
3609 else if (e.e2.type.isintegral() &&
3610 (e.op == EXP.addAssign ||
3611 e.op == EXP.minAssign ||
3612 e.op == EXP.plusPlus ||
3613 e.op == EXP.minusMinus))
3614 {
3615 newval = pointerArithmetic(pue, e.loc, e.op, e.type, oldval, newval).copy();
3616 if (newval == pue.exp())
3617 newval = pue.copy();
3618 }
3619 else
3620 {
3621 e.error("pointer expression `%s` cannot be interpreted at compile time", e.toChars());
3622 result = CTFEExp.cantexp;
3623 return;
3624 }
3625 if (exceptionOrCant(newval))
3626 {
3627 if (CTFEExp.isCantExp(newval))
3628 e.error("cannot interpret `%s` at compile time", e.toChars());
3629 return;
3630 }
3631 }
3632
3633 if (existingAA)
3634 {
3635 if (existingAA.ownedByCtfe != OwnedBy.ctfe)
3636 {
3637 e.error("cannot modify read-only constant `%s`", existingAA.toChars());
3638 result = CTFEExp.cantexp;
3639 return;
3640 }
3641
3642 //printf("\t+L%d existingAA = %s, lastIndex = %s, oldval = %s, newval = %s\n",
3643 // __LINE__, existingAA.toChars(), lastIndex.toChars(), oldval ? oldval.toChars() : NULL, newval.toChars());
3644 assignAssocArrayElement(e.loc, existingAA, lastIndex, newval);
3645
3646 // Determine the return value
3647 result = ctfeCast(pue, e.loc, e.type, e.type, fp && post ? oldval : newval);
3648 return;
3649 }
3650 if (e1.op == EXP.arrayLength)
3651 {
3652 /* Change the assignment from:
3653 * arr.length = n;
3654 * into:
3655 * arr = new_length_array; (result is n)
3656 */
3657
3658 // Determine the return value
3659 result = ctfeCast(pue, e.loc, e.type, e.type, fp && post ? oldval : newval);
3660 if (exceptionOrCant(result))
3661 return;
3662
3663 if (result == pue.exp())
3664 result = pue.copy();
3665
3666 size_t oldlen = cast(size_t)oldval.toInteger();
3667 size_t newlen = cast(size_t)newval.toInteger();
3668 if (oldlen == newlen) // no change required -- we're done!
3669 return;
3670
3671 // We have changed it into a reference assignment
3672 // Note that returnValue is still the new length.
3673 e1 = e1.isArrayLengthExp().e1;
3674 Type t = e1.type.toBasetype();
3675 if (t.ty != Tarray)
3676 {
3677 e.error("`%s` is not yet supported at compile time", e.toChars());
3678 result = CTFEExp.cantexp;
3679 return;
3680 }
3681 e1 = interpretRegion(e1, istate, CTFEGoal.LValue);
3682 if (exceptionOrCant(e1))
3683 return;
3684
3685 if (oldlen != 0) // Get the old array literal.
3686 oldval = interpretRegion(e1, istate);
3687 UnionExp utmp = void;
3688 oldval = resolveSlice(oldval, &utmp);
3689
3690 newval = changeArrayLiteralLength(pue, e.loc, cast(TypeArray)t, oldval, oldlen, newlen);
3691 if (newval == pue.exp())
3692 newval = pue.copy();
3693
3694 e1 = assignToLvalue(e, e1, newval);
3695 if (exceptionOrCant(e1))
3696 return;
3697
3698 return;
3699 }
3700
3701 if (!isBlockAssignment)
3702 {
3703 newval = ctfeCast(pue, e.loc, e.type, e.type, newval);
3704 if (exceptionOrCant(newval))
3705 return;
3706 if (newval == pue.exp())
3707 newval = pue.copy();
3708
3709 // Determine the return value
3710 if (goal == CTFEGoal.LValue) // https://issues.dlang.org/show_bug.cgi?id=14371
3711 result = e1;
3712 else
3713 {
3714 result = ctfeCast(pue, e.loc, e.type, e.type, fp && post ? oldval : newval);
3715 if (result == pue.exp())
3716 result = pue.copy();
3717 }
3718 if (exceptionOrCant(result))
3719 return;
3720 }
3721 if (exceptionOrCant(newval))
3722 return;
3723
debug(LOGASSIGN)3724 debug (LOGASSIGN)
3725 {
3726 printf("ASSIGN: %s=%s\n", e1.toChars(), newval.toChars());
3727 showCtfeExpr(newval);
3728 }
3729
3730 /* Block assignment or element-wise assignment.
3731 */
3732 if (e1.op == EXP.slice ||
3733 e1.op == EXP.vector ||
3734 e1.op == EXP.arrayLiteral ||
3735 e1.op == EXP.string_ ||
3736 e1.op == EXP.null_ && e1.type.toBasetype().ty == Tarray)
3737 {
3738 // Note that slice assignments don't support things like ++, so
3739 // we don't need to remember 'returnValue'.
3740 result = interpretAssignToSlice(pue, e, e1, newval, isBlockAssignment);
3741 if (exceptionOrCant(result))
3742 return;
3743 if (auto se = e.e1.isSliceExp())
3744 {
3745 Expression e1x = interpretRegion(se.e1, istate, CTFEGoal.LValue);
3746 if (auto dve = e1x.isDotVarExp())
3747 {
3748 auto ex = dve.e1;
3749 auto sle = ex.op == EXP.structLiteral ? ex.isStructLiteralExp()
3750 : ex.op == EXP.classReference ? ex.isClassReferenceExp().value
3751 : null;
3752 auto v = dve.var.isVarDeclaration();
3753 if (!sle || !v)
3754 {
3755 e.error("CTFE internal error: dotvar slice assignment");
3756 result = CTFEExp.cantexp;
3757 return;
3758 }
3759 stompOverlappedFields(sle, v);
3760 }
3761 }
3762 return;
3763 }
3764 assert(result);
3765
3766 /* Assignment to a CTFE reference.
3767 */
3768 if (Expression ex = assignToLvalue(e, e1, newval))
3769 result = ex;
3770
3771 return;
3772 }
3773
3774 /* Set all sibling fields which overlap with v to VoidExp.
3775 */
stompOverlappedFields(StructLiteralExp sle,VarDeclaration v)3776 private void stompOverlappedFields(StructLiteralExp sle, VarDeclaration v)
3777 {
3778 if (!v.overlapped)
3779 return;
3780 foreach (size_t i, v2; sle.sd.fields)
3781 {
3782 if (v is v2 || !v.isOverlappedWith(v2))
3783 continue;
3784 auto e = (*sle.elements)[i];
3785 if (e.op != EXP.void_)
3786 (*sle.elements)[i] = voidInitLiteral(e.type, v).copy();
3787 }
3788 }
3789
assignToLvalue(BinExp e,Expression e1,Expression newval)3790 private Expression assignToLvalue(BinExp e, Expression e1, Expression newval)
3791 {
3792 //printf("assignToLvalue() e: %s e1: %s newval: %s\n", e.toChars(), e1.toChars(), newval.toChars());
3793 VarDeclaration vd = null;
3794 Expression* payload = null; // dead-store to prevent spurious warning
3795 Expression oldval;
3796
3797 if (auto ve = e1.isVarExp())
3798 {
3799 vd = ve.var.isVarDeclaration();
3800 oldval = getValue(vd);
3801 }
3802 else if (auto dve = e1.isDotVarExp())
3803 {
3804 /* Assignment to member variable of the form:
3805 * e.v = newval
3806 */
3807 auto ex = dve.e1;
3808 auto sle = ex.op == EXP.structLiteral ? ex.isStructLiteralExp()
3809 : ex.op == EXP.classReference ? ex.isClassReferenceExp().value
3810 : null;
3811 auto v = e1.isDotVarExp().var.isVarDeclaration();
3812 if (!sle || !v)
3813 {
3814 e.error("CTFE internal error: dotvar assignment");
3815 return CTFEExp.cantexp;
3816 }
3817 if (sle.ownedByCtfe != OwnedBy.ctfe)
3818 {
3819 e.error("cannot modify read-only constant `%s`", sle.toChars());
3820 return CTFEExp.cantexp;
3821 }
3822
3823 int fieldi = ex.op == EXP.structLiteral ? findFieldIndexByName(sle.sd, v)
3824 : ex.isClassReferenceExp().findFieldIndexByName(v);
3825 if (fieldi == -1)
3826 {
3827 e.error("CTFE internal error: cannot find field `%s` in `%s`", v.toChars(), ex.toChars());
3828 return CTFEExp.cantexp;
3829 }
3830 assert(0 <= fieldi && fieldi < sle.elements.dim);
3831
3832 // If it's a union, set all other members of this union to void
3833 stompOverlappedFields(sle, v);
3834
3835 payload = &(*sle.elements)[fieldi];
3836 oldval = *payload;
3837 if (auto ival = newval.isIntegerExp())
3838 {
3839 if (auto bf = v.isBitFieldDeclaration())
3840 {
3841 sinteger_t value = ival.toInteger();
3842 if (bf.type.isunsigned())
3843 value &= (1L << bf.fieldWidth) - 1; // zero extra bits
3844 else
3845 { // sign extend extra bits
3846 value = value << (64 - bf.fieldWidth);
3847 value = value >> (64 - bf.fieldWidth);
3848 }
3849 ival.setInteger(value);
3850 }
3851 }
3852 }
3853 else if (auto ie = e1.isIndexExp())
3854 {
3855 assert(ie.e1.type.toBasetype().ty != Taarray);
3856
3857 Expression aggregate;
3858 uinteger_t indexToModify;
3859 if (!resolveIndexing(ie, istate, &aggregate, &indexToModify, true))
3860 {
3861 return CTFEExp.cantexp;
3862 }
3863 size_t index = cast(size_t)indexToModify;
3864
3865 if (auto existingSE = aggregate.isStringExp())
3866 {
3867 if (existingSE.ownedByCtfe != OwnedBy.ctfe)
3868 {
3869 e.error("cannot modify read-only string literal `%s`", ie.e1.toChars());
3870 return CTFEExp.cantexp;
3871 }
3872 existingSE.setCodeUnit(index, cast(dchar)newval.toInteger());
3873 return null;
3874 }
3875 if (aggregate.op != EXP.arrayLiteral)
3876 {
3877 e.error("index assignment `%s` is not yet supported in CTFE ", e.toChars());
3878 return CTFEExp.cantexp;
3879 }
3880
3881 ArrayLiteralExp existingAE = aggregate.isArrayLiteralExp();
3882 if (existingAE.ownedByCtfe != OwnedBy.ctfe)
3883 {
3884 e.error("cannot modify read-only constant `%s`", existingAE.toChars());
3885 return CTFEExp.cantexp;
3886 }
3887
3888 payload = &(*existingAE.elements)[index];
3889 oldval = *payload;
3890 }
3891 else
3892 {
3893 e.error("`%s` cannot be evaluated at compile time", e.toChars());
3894 return CTFEExp.cantexp;
3895 }
3896
3897 Type t1b = e1.type.toBasetype();
3898 bool wantCopy = t1b.baseElemOf().ty == Tstruct;
3899
3900 if (auto ve = newval.isVectorExp())
3901 {
3902 // Ensure ve is an array literal, and not a broadcast
3903 if (ve.e1.op == EXP.int64 || ve.e1.op == EXP.float64) // if broadcast
3904 {
3905 UnionExp ue = void;
3906 Expression ex = interpretVectorToArray(&ue, ve);
3907 ve.e1 = (ex == ue.exp()) ? ue.copy() : ex;
3908 }
3909 }
3910
3911 if (newval.op == EXP.structLiteral && oldval)
3912 {
3913 assert(oldval.op == EXP.structLiteral || oldval.op == EXP.arrayLiteral || oldval.op == EXP.string_);
3914 newval = copyLiteral(newval).copy();
3915 assignInPlace(oldval, newval);
3916 }
3917 else if (wantCopy && e.op == EXP.assign)
3918 {
3919 // Currently postblit/destructor calls on static array are done
3920 // in the druntime internal functions so they don't appear in AST.
3921 // Therefore interpreter should handle them specially.
3922
3923 assert(oldval);
3924 version (all) // todo: instead we can directly access to each elements of the slice
3925 {
3926 newval = resolveSlice(newval);
3927 if (CTFEExp.isCantExp(newval))
3928 {
3929 e.error("CTFE internal error: assignment `%s`", e.toChars());
3930 return CTFEExp.cantexp;
3931 }
3932 }
3933 assert(oldval.op == EXP.arrayLiteral);
3934 assert(newval.op == EXP.arrayLiteral);
3935
3936 Expressions* oldelems = oldval.isArrayLiteralExp().elements;
3937 Expressions* newelems = newval.isArrayLiteralExp().elements;
3938 assert(oldelems.dim == newelems.dim);
3939
3940 Type elemtype = oldval.type.nextOf();
3941 foreach (i, ref oldelem; *oldelems)
3942 {
3943 Expression newelem = paintTypeOntoLiteral(elemtype, (*newelems)[i]);
3944 // https://issues.dlang.org/show_bug.cgi?id=9245
3945 if (e.e2.isLvalue())
3946 {
3947 if (Expression ex = evaluatePostblit(istate, newelem))
3948 return ex;
3949 }
3950 // https://issues.dlang.org/show_bug.cgi?id=13661
3951 if (Expression ex = evaluateDtor(istate, oldelem))
3952 return ex;
3953 oldelem = newelem;
3954 }
3955 }
3956 else
3957 {
3958 // e1 has its own payload, so we have to create a new literal.
3959 if (wantCopy)
3960 newval = copyLiteral(newval).copy();
3961
3962 if (t1b.ty == Tsarray && e.op == EXP.construct && e.e2.isLvalue())
3963 {
3964 // https://issues.dlang.org/show_bug.cgi?id=9245
3965 if (Expression ex = evaluatePostblit(istate, newval))
3966 return ex;
3967 }
3968
3969 oldval = newval;
3970 }
3971
3972 if (vd)
3973 setValue(vd, oldval);
3974 else
3975 *payload = oldval;
3976
3977 // Blit assignment should return the newly created value.
3978 if (e.op == EXP.blit)
3979 return oldval;
3980
3981 return null;
3982 }
3983
3984 /*************
3985 * Deal with assignments of the form:
3986 * dest[] = newval
3987 * dest[low..upp] = newval
3988 * where newval has already been interpreted
3989 *
3990 * This could be a slice assignment or a block assignment, and
3991 * dest could be either an array literal, or a string.
3992 *
3993 * Returns EXP.cantExpression on failure. If there are no errors,
3994 * it returns aggregate[low..upp], except that as an optimisation,
3995 * if goal == CTFEGoal.Nothing, it will return NULL
3996 */
interpretAssignToSlice(UnionExp * pue,BinExp e,Expression e1,Expression newval,bool isBlockAssignment)3997 private Expression interpretAssignToSlice(UnionExp* pue, BinExp e, Expression e1, Expression newval, bool isBlockAssignment)
3998 {
3999 dinteger_t lowerbound;
4000 dinteger_t upperbound;
4001 dinteger_t firstIndex;
4002
4003 Expression aggregate;
4004
4005 if (auto se = e1.isSliceExp())
4006 {
4007 // ------------------------------
4008 // aggregate[] = newval
4009 // aggregate[low..upp] = newval
4010 // ------------------------------
4011 aggregate = interpretRegion(se.e1, istate);
4012 lowerbound = se.lwr ? se.lwr.toInteger() : 0;
4013 upperbound = se.upr ? se.upr.toInteger() : resolveArrayLength(aggregate);
4014
4015 // Slice of a slice --> change the bounds
4016 if (auto oldse = aggregate.isSliceExp())
4017 {
4018 aggregate = oldse.e1;
4019 firstIndex = lowerbound + oldse.lwr.toInteger();
4020 }
4021 else
4022 firstIndex = lowerbound;
4023 }
4024 else
4025 {
4026 if (auto ale = e1.isArrayLiteralExp())
4027 {
4028 lowerbound = 0;
4029 upperbound = ale.elements.dim;
4030 }
4031 else if (auto se = e1.isStringExp())
4032 {
4033 lowerbound = 0;
4034 upperbound = se.len;
4035 }
4036 else if (e1.op == EXP.null_)
4037 {
4038 lowerbound = 0;
4039 upperbound = 0;
4040 }
4041 else if (VectorExp ve = e1.isVectorExp())
4042 {
4043 // ve is not handled but a proper error message is returned
4044 // this is to prevent https://issues.dlang.org/show_bug.cgi?id=20042
4045 lowerbound = 0;
4046 upperbound = ve.dim;
4047 }
4048 else
4049 assert(0);
4050
4051 aggregate = e1;
4052 firstIndex = lowerbound;
4053 }
4054 if (upperbound == lowerbound)
4055 return newval;
4056
4057 // For slice assignment, we check that the lengths match.
4058 if (!isBlockAssignment)
4059 {
4060 const srclen = resolveArrayLength(newval);
4061 if (srclen != (upperbound - lowerbound))
4062 {
4063 e.error("array length mismatch assigning `[0..%llu]` to `[%llu..%llu]`",
4064 ulong(srclen), ulong(lowerbound), ulong(upperbound));
4065 return CTFEExp.cantexp;
4066 }
4067 }
4068
4069 if (auto existingSE = aggregate.isStringExp())
4070 {
4071 if (existingSE.ownedByCtfe != OwnedBy.ctfe)
4072 {
4073 e.error("cannot modify read-only string literal `%s`", existingSE.toChars());
4074 return CTFEExp.cantexp;
4075 }
4076
4077 if (auto se = newval.isSliceExp())
4078 {
4079 auto aggr2 = se.e1;
4080 const srclower = se.lwr.toInteger();
4081 const srcupper = se.upr.toInteger();
4082
4083 if (aggregate == aggr2 &&
4084 lowerbound < srcupper && srclower < upperbound)
4085 {
4086 e.error("overlapping slice assignment `[%llu..%llu] = [%llu..%llu]`",
4087 ulong(lowerbound), ulong(upperbound), ulong(srclower), ulong(srcupper));
4088 return CTFEExp.cantexp;
4089 }
4090 version (all) // todo: instead we can directly access to each elements of the slice
4091 {
4092 Expression orignewval = newval;
4093 newval = resolveSlice(newval);
4094 if (CTFEExp.isCantExp(newval))
4095 {
4096 e.error("CTFE internal error: slice `%s`", orignewval.toChars());
4097 return CTFEExp.cantexp;
4098 }
4099 }
4100 assert(newval.op != EXP.slice);
4101 }
4102 if (auto se = newval.isStringExp())
4103 {
4104 sliceAssignStringFromString(existingSE, se, cast(size_t)firstIndex);
4105 return newval;
4106 }
4107 if (auto ale = newval.isArrayLiteralExp())
4108 {
4109 /* Mixed slice: it was initialized as a string literal.
4110 * Now a slice of it is being set with an array literal.
4111 */
4112 sliceAssignStringFromArrayLiteral(existingSE, ale, cast(size_t)firstIndex);
4113 return newval;
4114 }
4115
4116 // String literal block slice assign
4117 const value = cast(dchar)newval.toInteger();
4118 foreach (i; 0 .. upperbound - lowerbound)
4119 {
4120 existingSE.setCodeUnit(cast(size_t)(i + firstIndex), value);
4121 }
4122 if (goal == CTFEGoal.Nothing)
4123 return null; // avoid creating an unused literal
4124 auto retslice = ctfeEmplaceExp!SliceExp(e.loc, existingSE,
4125 ctfeEmplaceExp!IntegerExp(e.loc, firstIndex, Type.tsize_t),
4126 ctfeEmplaceExp!IntegerExp(e.loc, firstIndex + upperbound - lowerbound, Type.tsize_t));
4127 retslice.type = e.type;
4128 return interpret(pue, retslice, istate);
4129 }
4130 if (auto existingAE = aggregate.isArrayLiteralExp())
4131 {
4132 if (existingAE.ownedByCtfe != OwnedBy.ctfe)
4133 {
4134 e.error("cannot modify read-only constant `%s`", existingAE.toChars());
4135 return CTFEExp.cantexp;
4136 }
4137
4138 if (newval.op == EXP.slice && !isBlockAssignment)
4139 {
4140 auto se = newval.isSliceExp();
4141 auto aggr2 = se.e1;
4142 const srclower = se.lwr.toInteger();
4143 const srcupper = se.upr.toInteger();
4144 const wantCopy = (newval.type.toBasetype().nextOf().baseElemOf().ty == Tstruct);
4145
4146 //printf("oldval = %p %s[%d..%u]\nnewval = %p %s[%llu..%llu] wantCopy = %d\n",
4147 // aggregate, aggregate.toChars(), lowerbound, upperbound,
4148 // aggr2, aggr2.toChars(), srclower, srcupper, wantCopy);
4149 if (wantCopy)
4150 {
4151 // Currently overlapping for struct array is allowed.
4152 // The order of elements processing depends on the overlapping.
4153 // https://issues.dlang.org/show_bug.cgi?id=14024
4154 assert(aggr2.op == EXP.arrayLiteral);
4155 Expressions* oldelems = existingAE.elements;
4156 Expressions* newelems = aggr2.isArrayLiteralExp().elements;
4157
4158 Type elemtype = aggregate.type.nextOf();
4159 bool needsPostblit = e.e2.isLvalue();
4160
4161 if (aggregate == aggr2 && srclower < lowerbound && lowerbound < srcupper)
4162 {
4163 // reverse order
4164 for (auto i = upperbound - lowerbound; 0 < i--;)
4165 {
4166 Expression oldelem = (*oldelems)[cast(size_t)(i + firstIndex)];
4167 Expression newelem = (*newelems)[cast(size_t)(i + srclower)];
4168 newelem = copyLiteral(newelem).copy();
4169 newelem.type = elemtype;
4170 if (needsPostblit)
4171 {
4172 if (Expression x = evaluatePostblit(istate, newelem))
4173 return x;
4174 }
4175 if (Expression x = evaluateDtor(istate, oldelem))
4176 return x;
4177 (*oldelems)[cast(size_t)(lowerbound + i)] = newelem;
4178 }
4179 }
4180 else
4181 {
4182 // normal order
4183 for (auto i = 0; i < upperbound - lowerbound; i++)
4184 {
4185 Expression oldelem = (*oldelems)[cast(size_t)(i + firstIndex)];
4186 Expression newelem = (*newelems)[cast(size_t)(i + srclower)];
4187 newelem = copyLiteral(newelem).copy();
4188 newelem.type = elemtype;
4189 if (needsPostblit)
4190 {
4191 if (Expression x = evaluatePostblit(istate, newelem))
4192 return x;
4193 }
4194 if (Expression x = evaluateDtor(istate, oldelem))
4195 return x;
4196 (*oldelems)[cast(size_t)(lowerbound + i)] = newelem;
4197 }
4198 }
4199
4200 //assert(0);
4201 return newval; // oldval?
4202 }
4203 if (aggregate == aggr2 &&
4204 lowerbound < srcupper && srclower < upperbound)
4205 {
4206 e.error("overlapping slice assignment `[%llu..%llu] = [%llu..%llu]`",
4207 ulong(lowerbound), ulong(upperbound), ulong(srclower), ulong(srcupper));
4208 return CTFEExp.cantexp;
4209 }
4210 version (all) // todo: instead we can directly access to each elements of the slice
4211 {
4212 Expression orignewval = newval;
4213 newval = resolveSlice(newval);
4214 if (CTFEExp.isCantExp(newval))
4215 {
4216 e.error("CTFE internal error: slice `%s`", orignewval.toChars());
4217 return CTFEExp.cantexp;
4218 }
4219 }
4220 // no overlapping
4221 //length?
4222 assert(newval.op != EXP.slice);
4223 }
4224 if (newval.op == EXP.string_ && !isBlockAssignment)
4225 {
4226 /* Mixed slice: it was initialized as an array literal of chars/integers.
4227 * Now a slice of it is being set with a string.
4228 */
4229 sliceAssignArrayLiteralFromString(existingAE, newval.isStringExp(), cast(size_t)firstIndex);
4230 return newval;
4231 }
4232 if (newval.op == EXP.arrayLiteral && !isBlockAssignment)
4233 {
4234 Expressions* oldelems = existingAE.elements;
4235 Expressions* newelems = newval.isArrayLiteralExp().elements;
4236 Type elemtype = existingAE.type.nextOf();
4237 bool needsPostblit = e.op != EXP.blit && e.e2.isLvalue();
4238 foreach (j, newelem; *newelems)
4239 {
4240 newelem = paintTypeOntoLiteral(elemtype, newelem);
4241 if (needsPostblit)
4242 {
4243 Expression x = evaluatePostblit(istate, newelem);
4244 if (exceptionOrCantInterpret(x))
4245 return x;
4246 }
4247 (*oldelems)[cast(size_t)(j + firstIndex)] = newelem;
4248 }
4249 return newval;
4250 }
4251
4252 /* Block assignment, initialization of static arrays
4253 * x[] = newval
4254 * x may be a multidimensional static array. (Note that this
4255 * only happens with array literals, never with strings).
4256 */
4257 struct RecursiveBlock
4258 {
4259 InterState* istate;
4260 Expression newval;
4261 bool refCopy;
4262 bool needsPostblit;
4263 bool needsDtor;
4264
4265 extern (C++) Expression assignTo(ArrayLiteralExp ae)
4266 {
4267 return assignTo(ae, 0, ae.elements.dim);
4268 }
4269
4270 extern (C++) Expression assignTo(ArrayLiteralExp ae, size_t lwr, size_t upr)
4271 {
4272 Expressions* w = ae.elements;
4273 assert(ae.type.ty == Tsarray || ae.type.ty == Tarray);
4274 bool directblk = (cast(TypeArray)ae.type).next.equivalent(newval.type);
4275 for (size_t k = lwr; k < upr; k++)
4276 {
4277 if (!directblk && (*w)[k].op == EXP.arrayLiteral)
4278 {
4279 // Multidimensional array block assign
4280 if (Expression ex = assignTo((*w)[k].isArrayLiteralExp()))
4281 return ex;
4282 }
4283 else if (refCopy)
4284 {
4285 (*w)[k] = newval;
4286 }
4287 else if (!needsPostblit && !needsDtor)
4288 {
4289 assignInPlace((*w)[k], newval);
4290 }
4291 else
4292 {
4293 Expression oldelem = (*w)[k];
4294 Expression tmpelem = needsDtor ? copyLiteral(oldelem).copy() : null;
4295 assignInPlace(oldelem, newval);
4296 if (needsPostblit)
4297 {
4298 if (Expression ex = evaluatePostblit(istate, oldelem))
4299 return ex;
4300 }
4301 if (needsDtor)
4302 {
4303 // https://issues.dlang.org/show_bug.cgi?id=14860
4304 if (Expression ex = evaluateDtor(istate, tmpelem))
4305 return ex;
4306 }
4307 }
4308 }
4309 return null;
4310 }
4311 }
4312
4313 Type tn = newval.type.toBasetype();
4314 bool wantRef = (tn.ty == Tarray || isAssocArray(tn) || tn.ty == Tclass);
4315 bool cow = newval.op != EXP.structLiteral && newval.op != EXP.arrayLiteral && newval.op != EXP.string_;
4316 Type tb = tn.baseElemOf();
4317 StructDeclaration sd = (tb.ty == Tstruct ? (cast(TypeStruct)tb).sym : null);
4318
4319 RecursiveBlock rb;
4320 rb.istate = istate;
4321 rb.newval = newval;
4322 rb.refCopy = wantRef || cow;
4323 rb.needsPostblit = sd && sd.postblit && e.op != EXP.blit && e.e2.isLvalue();
4324 rb.needsDtor = sd && sd.dtor && e.op == EXP.assign;
4325 if (Expression ex = rb.assignTo(existingAE, cast(size_t)lowerbound, cast(size_t)upperbound))
4326 return ex;
4327
4328 if (goal == CTFEGoal.Nothing)
4329 return null; // avoid creating an unused literal
4330 auto retslice = ctfeEmplaceExp!SliceExp(e.loc, existingAE,
4331 ctfeEmplaceExp!IntegerExp(e.loc, firstIndex, Type.tsize_t),
4332 ctfeEmplaceExp!IntegerExp(e.loc, firstIndex + upperbound - lowerbound, Type.tsize_t));
4333 retslice.type = e.type;
4334 return interpret(pue, retslice, istate);
4335 }
4336
4337 e.error("slice operation `%s = %s` cannot be evaluated at compile time", e1.toChars(), newval.toChars());
4338 return CTFEExp.cantexp;
4339 }
4340
visit(AssignExp e)4341 override void visit(AssignExp e)
4342 {
4343 interpretAssignCommon(e, null);
4344 }
4345
visit(BinAssignExp e)4346 override void visit(BinAssignExp e)
4347 {
4348 switch (e.op)
4349 {
4350 case EXP.addAssign:
4351 interpretAssignCommon(e, &Add);
4352 return;
4353
4354 case EXP.minAssign:
4355 interpretAssignCommon(e, &Min);
4356 return;
4357
4358 case EXP.concatenateAssign:
4359 case EXP.concatenateElemAssign:
4360 case EXP.concatenateDcharAssign:
4361 interpretAssignCommon(e, &ctfeCat);
4362 return;
4363
4364 case EXP.mulAssign:
4365 interpretAssignCommon(e, &Mul);
4366 return;
4367
4368 case EXP.divAssign:
4369 interpretAssignCommon(e, &Div);
4370 return;
4371
4372 case EXP.modAssign:
4373 interpretAssignCommon(e, &Mod);
4374 return;
4375
4376 case EXP.leftShiftAssign:
4377 interpretAssignCommon(e, &Shl);
4378 return;
4379
4380 case EXP.rightShiftAssign:
4381 interpretAssignCommon(e, &Shr);
4382 return;
4383
4384 case EXP.unsignedRightShiftAssign:
4385 interpretAssignCommon(e, &Ushr);
4386 return;
4387
4388 case EXP.andAssign:
4389 interpretAssignCommon(e, &And);
4390 return;
4391
4392 case EXP.orAssign:
4393 interpretAssignCommon(e, &Or);
4394 return;
4395
4396 case EXP.xorAssign:
4397 interpretAssignCommon(e, &Xor);
4398 return;
4399
4400 case EXP.powAssign:
4401 interpretAssignCommon(e, &Pow);
4402 return;
4403
4404 default:
4405 assert(0);
4406 }
4407 }
4408
visit(PostExp e)4409 override void visit(PostExp e)
4410 {
4411 debug (LOG)
4412 {
4413 printf("%s PostExp::interpret() %s\n", e.loc.toChars(), e.toChars());
4414 }
4415 if (e.op == EXP.plusPlus)
4416 interpretAssignCommon(e, &Add, 1);
4417 else
4418 interpretAssignCommon(e, &Min, 1);
4419 debug (LOG)
4420 {
4421 if (CTFEExp.isCantExp(result))
4422 printf("PostExp::interpret() CANT\n");
4423 }
4424 }
4425
4426 /* Return 1 if e is a p1 > p2 or p1 >= p2 pointer comparison;
4427 * -1 if e is a p1 < p2 or p1 <= p2 pointer comparison;
4428 * 0 otherwise
4429 */
isPointerCmpExp(Expression e,Expression * p1,Expression * p2)4430 static int isPointerCmpExp(Expression e, Expression* p1, Expression* p2)
4431 {
4432 int ret = 1;
4433 while (e.op == EXP.not)
4434 {
4435 ret *= -1;
4436 e = e.isNotExp().e1;
4437 }
4438 switch (e.op)
4439 {
4440 case EXP.lessThan:
4441 case EXP.lessOrEqual:
4442 ret *= -1;
4443 goto case; /+ fall through +/
4444 case EXP.greaterThan:
4445 case EXP.greaterOrEqual:
4446 *p1 = e.isBinExp().e1;
4447 *p2 = e.isBinExp().e2;
4448 if (!(isPointer((*p1).type) && isPointer((*p2).type)))
4449 ret = 0;
4450 break;
4451
4452 default:
4453 ret = 0;
4454 break;
4455 }
4456 return ret;
4457 }
4458
4459 /** If this is a four pointer relation, evaluate it, else return NULL.
4460 *
4461 * This is an expression of the form (p1 > q1 && p2 < q2) or (p1 < q1 || p2 > q2)
4462 * where p1, p2 are expressions yielding pointers to memory block p,
4463 * and q1, q2 are expressions yielding pointers to memory block q.
4464 * This expression is valid even if p and q are independent memory
4465 * blocks and are therefore not normally comparable; the && form returns true
4466 * if [p1..p2] lies inside [q1..q2], and false otherwise; the || form returns
4467 * true if [p1..p2] lies outside [q1..q2], and false otherwise.
4468 *
4469 * Within the expression, any ordering of p1, p2, q1, q2 is permissible;
4470 * the comparison operators can be any of >, <, <=, >=, provided that
4471 * both directions (p > q and p < q) are checked. Additionally the
4472 * relational sub-expressions can be negated, eg
4473 * (!(q1 < p1) && p2 <= q2) is valid.
4474 */
interpretFourPointerRelation(UnionExp * pue,BinExp e)4475 private void interpretFourPointerRelation(UnionExp* pue, BinExp e)
4476 {
4477 assert(e.op == EXP.andAnd || e.op == EXP.orOr);
4478
4479 /* It can only be an isInside expression, if both e1 and e2 are
4480 * directional pointer comparisons.
4481 * Note that this check can be made statically; it does not depends on
4482 * any runtime values. This allows a JIT implementation to compile a
4483 * special AndAndPossiblyInside, keeping the normal AndAnd case efficient.
4484 */
4485
4486 // Save the pointer expressions and the comparison directions,
4487 // so we can use them later.
4488 Expression p1 = null;
4489 Expression p2 = null;
4490 Expression p3 = null;
4491 Expression p4 = null;
4492 int dir1 = isPointerCmpExp(e.e1, &p1, &p2);
4493 int dir2 = isPointerCmpExp(e.e2, &p3, &p4);
4494 if (dir1 == 0 || dir2 == 0)
4495 {
4496 result = null;
4497 return;
4498 }
4499
4500 //printf("FourPointerRelation %s\n", toChars());
4501
4502 UnionExp ue1 = void;
4503 UnionExp ue2 = void;
4504 UnionExp ue3 = void;
4505 UnionExp ue4 = void;
4506
4507 // Evaluate the first two pointers
4508 p1 = interpret(&ue1, p1, istate);
4509 if (exceptionOrCant(p1))
4510 return;
4511 p2 = interpret(&ue2, p2, istate);
4512 if (exceptionOrCant(p2))
4513 return;
4514 dinteger_t ofs1, ofs2;
4515 Expression agg1 = getAggregateFromPointer(p1, &ofs1);
4516 Expression agg2 = getAggregateFromPointer(p2, &ofs2);
4517
4518 if (!pointToSameMemoryBlock(agg1, agg2) && agg1.op != EXP.null_ && agg2.op != EXP.null_)
4519 {
4520 // Here it is either CANT_INTERPRET,
4521 // or an IsInside comparison returning false.
4522 p3 = interpret(&ue3, p3, istate);
4523 if (CTFEExp.isCantExp(p3))
4524 return;
4525 // Note that it is NOT legal for it to throw an exception!
4526 Expression except = null;
4527 if (exceptionOrCantInterpret(p3))
4528 except = p3;
4529 else
4530 {
4531 p4 = interpret(&ue4, p4, istate);
4532 if (CTFEExp.isCantExp(p4))
4533 {
4534 result = p4;
4535 return;
4536 }
4537 if (exceptionOrCantInterpret(p4))
4538 except = p4;
4539 }
4540 if (except)
4541 {
4542 e.error("comparison `%s` of pointers to unrelated memory blocks remains indeterminate at compile time because exception `%s` was thrown while evaluating `%s`", e.e1.toChars(), except.toChars(), e.e2.toChars());
4543 result = CTFEExp.cantexp;
4544 return;
4545 }
4546 dinteger_t ofs3, ofs4;
4547 Expression agg3 = getAggregateFromPointer(p3, &ofs3);
4548 Expression agg4 = getAggregateFromPointer(p4, &ofs4);
4549 // The valid cases are:
4550 // p1 > p2 && p3 > p4 (same direction, also for < && <)
4551 // p1 > p2 && p3 < p4 (different direction, also < && >)
4552 // Changing any > into >= doesn't affect the result
4553 if ((dir1 == dir2 && pointToSameMemoryBlock(agg1, agg4) && pointToSameMemoryBlock(agg2, agg3)) ||
4554 (dir1 != dir2 && pointToSameMemoryBlock(agg1, agg3) && pointToSameMemoryBlock(agg2, agg4)))
4555 {
4556 // it's a legal two-sided comparison
4557 emplaceExp!(IntegerExp)(pue, e.loc, (e.op == EXP.andAnd) ? 0 : 1, e.type);
4558 result = pue.exp();
4559 return;
4560 }
4561 // It's an invalid four-pointer comparison. Either the second
4562 // comparison is in the same direction as the first, or else
4563 // more than two memory blocks are involved (either two independent
4564 // invalid comparisons are present, or else agg3 == agg4).
4565 e.error("comparison `%s` of pointers to unrelated memory blocks is indeterminate at compile time, even when combined with `%s`.", e.e1.toChars(), e.e2.toChars());
4566 result = CTFEExp.cantexp;
4567 return;
4568 }
4569 // The first pointer expression didn't need special treatment, so we
4570 // we need to interpret the entire expression exactly as a normal && or ||.
4571 // This is easy because we haven't evaluated e2 at all yet, and we already
4572 // know it will return a bool.
4573 // But we mustn't evaluate the pointer expressions in e1 again, in case
4574 // they have side-effects.
4575 bool nott = false;
4576 Expression ex = e.e1;
4577 while (1)
4578 {
4579 if (auto ne = ex.isNotExp())
4580 {
4581 nott = !nott;
4582 ex = ne.e1;
4583 }
4584 else
4585 break;
4586 }
4587
4588 /** Negate relational operator, eg >= becomes <
4589 * Params:
4590 * op = comparison operator to negate
4591 * Returns:
4592 * negate operator
4593 */
4594 static EXP negateRelation(EXP op) pure
4595 {
4596 switch (op)
4597 {
4598 case EXP.greaterOrEqual: op = EXP.lessThan; break;
4599 case EXP.greaterThan: op = EXP.lessOrEqual; break;
4600 case EXP.lessOrEqual: op = EXP.greaterThan; break;
4601 case EXP.lessThan: op = EXP.greaterOrEqual; break;
4602 default: assert(0);
4603 }
4604 return op;
4605 }
4606
4607 const EXP cmpop = nott ? negateRelation(ex.op) : ex.op;
4608 const cmp = comparePointers(cmpop, agg1, ofs1, agg2, ofs2);
4609 // We already know this is a valid comparison.
4610 assert(cmp >= 0);
4611 if (e.op == EXP.andAnd && cmp == 1 || e.op == EXP.orOr && cmp == 0)
4612 {
4613 result = interpret(pue, e.e2, istate);
4614 return;
4615 }
4616 emplaceExp!(IntegerExp)(pue, e.loc, (e.op == EXP.andAnd) ? 0 : 1, e.type);
4617 result = pue.exp();
4618 }
4619
visit(LogicalExp e)4620 override void visit(LogicalExp e)
4621 {
4622 debug (LOG)
4623 {
4624 printf("%s LogicalExp::interpret() %s\n", e.loc.toChars(), e.toChars());
4625 }
4626 // Check for an insidePointer expression, evaluate it if so
4627 interpretFourPointerRelation(pue, e);
4628 if (result)
4629 return;
4630
4631 UnionExp ue1 = void;
4632 result = interpret(&ue1, e.e1, istate);
4633 if (exceptionOrCant(result))
4634 return;
4635
4636 bool res;
4637 const andand = e.op == EXP.andAnd;
4638 if (andand ? result.toBool().hasValue(false) : isTrueBool(result))
4639 res = !andand;
4640 else if (andand ? isTrueBool(result) : result.toBool().hasValue(false))
4641 {
4642 UnionExp ue2 = void;
4643 result = interpret(&ue2, e.e2, istate);
4644 if (exceptionOrCant(result))
4645 return;
4646 if (result.op == EXP.voidExpression)
4647 {
4648 assert(e.type.ty == Tvoid);
4649 result = null;
4650 return;
4651 }
4652 if (result.toBool().hasValue(false))
4653 res = false;
4654 else if (isTrueBool(result))
4655 res = true;
4656 else
4657 {
4658 e.error("`%s` does not evaluate to a `bool`", result.toChars());
4659 result = CTFEExp.cantexp;
4660 return;
4661 }
4662 }
4663 else
4664 {
4665 e.error("`%s` cannot be interpreted as a `bool`", result.toChars());
4666 result = CTFEExp.cantexp;
4667 return;
4668 }
4669 incUsageCtfe(istate, e.e2.loc);
4670
4671 if (goal != CTFEGoal.Nothing)
4672 {
4673 if (e.type.equals(Type.tbool))
4674 result = IntegerExp.createBool(res);
4675 else
4676 {
4677 emplaceExp!(IntegerExp)(pue, e.loc, res, e.type);
4678 result = pue.exp();
4679 }
4680 }
4681 }
4682
4683
4684 // Print a stack trace, starting from callingExp which called fd.
4685 // To shorten the stack trace, try to detect recursion.
showCtfeBackTrace(CallExp callingExp,FuncDeclaration fd)4686 private void showCtfeBackTrace(CallExp callingExp, FuncDeclaration fd)
4687 {
4688 if (ctfeGlobals.stackTraceCallsToSuppress > 0)
4689 {
4690 --ctfeGlobals.stackTraceCallsToSuppress;
4691 return;
4692 }
4693 errorSupplemental(callingExp.loc, "called from here: `%s`", callingExp.toChars());
4694 // Quit if it's not worth trying to compress the stack trace
4695 if (ctfeGlobals.callDepth < 6 || global.params.verbose)
4696 return;
4697 // Recursion happens if the current function already exists in the call stack.
4698 int numToSuppress = 0;
4699 int recurseCount = 0;
4700 int depthSoFar = 0;
4701 InterState* lastRecurse = istate;
4702 for (InterState* cur = istate; cur; cur = cur.caller)
4703 {
4704 if (cur.fd == fd)
4705 {
4706 ++recurseCount;
4707 numToSuppress = depthSoFar;
4708 lastRecurse = cur;
4709 }
4710 ++depthSoFar;
4711 }
4712 // We need at least three calls to the same function, to make compression worthwhile
4713 if (recurseCount < 2)
4714 return;
4715 // We found a useful recursion. Print all the calls involved in the recursion
4716 errorSupplemental(fd.loc, "%d recursive calls to function `%s`", recurseCount, fd.toChars());
4717 for (InterState* cur = istate; cur.fd != fd; cur = cur.caller)
4718 {
4719 errorSupplemental(cur.fd.loc, "recursively called from function `%s`", cur.fd.toChars());
4720 }
4721 // We probably didn't enter the recursion in this function.
4722 // Go deeper to find the real beginning.
4723 InterState* cur = istate;
4724 while (lastRecurse.caller && cur.fd == lastRecurse.caller.fd)
4725 {
4726 cur = cur.caller;
4727 lastRecurse = lastRecurse.caller;
4728 ++numToSuppress;
4729 }
4730 ctfeGlobals.stackTraceCallsToSuppress = numToSuppress;
4731 }
4732
visit(CallExp e)4733 override void visit(CallExp e)
4734 {
4735 debug (LOG)
4736 {
4737 printf("%s CallExp::interpret() %s\n", e.loc.toChars(), e.toChars());
4738 }
4739 Expression pthis = null;
4740 FuncDeclaration fd = null;
4741
4742 Expression ecall = interpretRegion(e.e1, istate);
4743 if (exceptionOrCant(ecall))
4744 return;
4745
4746 if (auto dve = ecall.isDotVarExp())
4747 {
4748 // Calling a member function
4749 pthis = dve.e1;
4750 fd = dve.var.isFuncDeclaration();
4751 assert(fd);
4752
4753 if (auto dte = pthis.isDotTypeExp())
4754 pthis = dte.e1;
4755 }
4756 else if (auto ve = ecall.isVarExp())
4757 {
4758 fd = ve.var.isFuncDeclaration();
4759 assert(fd);
4760
4761 // If `_d_HookTraceImpl` is found, resolve the underlying hook and replace `e` and `fd` with it.
4762 removeHookTraceImpl(e, fd);
4763
4764 if (fd.ident == Id.__ArrayPostblit || fd.ident == Id.__ArrayDtor)
4765 {
4766 assert(e.arguments.dim == 1);
4767 Expression ea = (*e.arguments)[0];
4768 // printf("1 ea = %s %s\n", ea.type.toChars(), ea.toChars());
4769 if (auto se = ea.isSliceExp())
4770 ea = se.e1;
4771 if (auto ce = ea.isCastExp())
4772 ea = ce.e1;
4773
4774 // printf("2 ea = %s, %s %s\n", ea.type.toChars(), EXPtoString(ea.op).ptr, ea.toChars());
4775 if (ea.op == EXP.variable || ea.op == EXP.symbolOffset)
4776 result = getVarExp(e.loc, istate, (cast(SymbolExp)ea).var, CTFEGoal.RValue);
4777 else if (auto ae = ea.isAddrExp())
4778 result = interpretRegion(ae.e1, istate);
4779
4780 // https://issues.dlang.org/show_bug.cgi?id=18871
4781 // https://issues.dlang.org/show_bug.cgi?id=18819
4782 else if (auto ale = ea.isArrayLiteralExp())
4783 result = interpretRegion(ale, istate);
4784
4785 else
4786 assert(0);
4787 if (CTFEExp.isCantExp(result))
4788 return;
4789
4790 if (fd.ident == Id.__ArrayPostblit)
4791 result = evaluatePostblit(istate, result);
4792 else
4793 result = evaluateDtor(istate, result);
4794 if (!result)
4795 result = CTFEExp.voidexp;
4796 return;
4797 }
4798 else if (fd.ident == Id._d_arraysetlengthT)
4799 {
4800 // In expressionsem.d `ea.length = eb;` got lowered to `_d_arraysetlengthT(ea, eb);`.
4801 // The following code will rewrite it back to `ea.length = eb` and then interpret that expression.
4802 assert(e.arguments.dim == 2);
4803
4804 Expression ea = (*e.arguments)[0];
4805 Expression eb = (*e.arguments)[1];
4806
4807 auto ale = ctfeEmplaceExp!ArrayLengthExp(e.loc, ea);
4808 ale.type = Type.tsize_t;
4809 AssignExp ae = ctfeEmplaceExp!AssignExp(e.loc, ale, eb);
4810 ae.type = ea.type;
4811
4812 // if (global.params.verbose)
4813 // message("interpret %s =>\n %s", e.toChars(), ae.toChars());
4814 result = interpretRegion(ae, istate);
4815 return;
4816 }
4817 else if (fd.ident == Id._d_arrayctor || fd.ident == Id._d_arraysetctor)
4818 {
4819 // In expressionsem.d `T[x] ea = eb;` was lowered to `_d_array{,set}ctor(ea[], eb[]);`.
4820 // The following code will rewrite it back to `ea = eb` and then interpret that expression.
4821 if (fd.ident == Id._d_arraysetctor)
4822 assert(e.arguments.dim == 2);
4823 else
4824 assert(e.arguments.dim == 3);
4825
4826 Expression ea = (*e.arguments)[0];
4827 if (ea.isCastExp)
4828 ea = ea.isCastExp.e1;
4829
4830 Expression eb = (*e.arguments)[1];
4831 if (eb.isCastExp && fd.ident == Id._d_arrayctor)
4832 eb = eb.isCastExp.e1;
4833
4834 ConstructExp ce = new ConstructExp(e.loc, ea, eb);
4835 ce.type = ea.type;
4836
4837 result = interpret(ce, istate);
4838 return;
4839 }
4840 }
4841 else if (auto soe = ecall.isSymOffExp())
4842 {
4843 fd = soe.var.isFuncDeclaration();
4844 assert(fd && soe.offset == 0);
4845 }
4846 else if (auto de = ecall.isDelegateExp())
4847 {
4848 // Calling a delegate
4849 fd = de.func;
4850 pthis = de.e1;
4851
4852 // Special handling for: &nestedfunc --> DelegateExp(VarExp(nestedfunc), nestedfunc)
4853 if (auto ve = pthis.isVarExp())
4854 if (ve.var == fd)
4855 pthis = null; // context is not necessary for CTFE
4856 }
4857 else if (auto fe = ecall.isFuncExp())
4858 {
4859 // Calling a delegate literal
4860 fd = fe.fd;
4861 }
4862 else
4863 {
4864 // delegate.funcptr()
4865 // others
4866 e.error("cannot call `%s` at compile time", e.toChars());
4867 result = CTFEExp.cantexp;
4868 return;
4869 }
4870 if (!fd)
4871 {
4872 e.error("CTFE internal error: cannot evaluate `%s` at compile time", e.toChars());
4873 result = CTFEExp.cantexp;
4874 return;
4875 }
4876 if (pthis)
4877 {
4878 // Member function call
4879
4880 // Currently this is satisfied because closure is not yet supported.
4881 assert(!fd.isNested() || fd.needThis());
4882
4883 if (pthis.op == EXP.typeid_)
4884 {
4885 pthis.error("static variable `%s` cannot be read at compile time", pthis.toChars());
4886 result = CTFEExp.cantexp;
4887 return;
4888 }
4889 assert(pthis);
4890
4891 if (pthis.op == EXP.null_)
4892 {
4893 assert(pthis.type.toBasetype().ty == Tclass);
4894 e.error("function call through null class reference `%s`", pthis.toChars());
4895 result = CTFEExp.cantexp;
4896 return;
4897 }
4898
4899 assert(pthis.op == EXP.structLiteral || pthis.op == EXP.classReference || pthis.op == EXP.type);
4900
4901 if (fd.isVirtual() && !e.directcall)
4902 {
4903 // Make a virtual function call.
4904 // Get the function from the vtable of the original class
4905 ClassDeclaration cd = pthis.isClassReferenceExp().originalClass();
4906
4907 // We can't just use the vtable index to look it up, because
4908 // vtables for interfaces don't get populated until the glue layer.
4909 fd = cd.findFunc(fd.ident, fd.type.isTypeFunction());
4910 assert(fd);
4911 }
4912 }
4913
4914 if (fd && fd.semanticRun >= PASS.semantic3done && fd.hasSemantic3Errors())
4915 {
4916 e.error("CTFE failed because of previous errors in `%s`", fd.toChars());
4917 result = CTFEExp.cantexp;
4918 return;
4919 }
4920
4921 // Check for built-in functions
4922 result = evaluateIfBuiltin(pue, istate, e.loc, fd, e.arguments, pthis);
4923 if (result)
4924 return;
4925
4926 if (!fd.fbody)
4927 {
4928 e.error("`%s` cannot be interpreted at compile time, because it has no available source code", fd.toChars());
4929 result = CTFEExp.showcontext;
4930 return;
4931 }
4932
4933 result = interpretFunction(pue, fd, istate, e.arguments, pthis);
4934 if (result.op == EXP.voidExpression)
4935 return;
4936 if (!exceptionOrCantInterpret(result))
4937 {
4938 if (goal != CTFEGoal.LValue) // Peel off CTFE reference if it's unnecessary
4939 {
4940 if (result == pue.exp())
4941 result = pue.copy();
4942 result = interpret(pue, result, istate);
4943 }
4944 }
4945 if (!exceptionOrCantInterpret(result))
4946 {
4947 result = paintTypeOntoLiteral(pue, e.type, result);
4948 result.loc = e.loc;
4949 }
4950 else if (CTFEExp.isCantExp(result) && !global.gag)
4951 showCtfeBackTrace(e, fd); // Print a stack trace.
4952 }
4953
visit(CommaExp e)4954 override void visit(CommaExp e)
4955 {
4956 debug (LOG)
4957 {
4958 printf("%s CommaExp::interpret() %s\n", e.loc.toChars(), e.toChars());
4959 }
4960
4961 // If it creates a variable, and there's no context for
4962 // the variable to be created in, we need to create one now.
4963 InterState istateComma;
4964 if (!istate && firstComma(e.e1).op == EXP.declaration)
4965 {
4966 ctfeGlobals.stack.startFrame(null);
4967 istate = &istateComma;
4968 }
4969
4970 void endTempStackFrame()
4971 {
4972 // If we created a temporary stack frame, end it now.
4973 if (istate == &istateComma)
4974 ctfeGlobals.stack.endFrame();
4975 }
4976
4977 result = CTFEExp.cantexp;
4978
4979 // If the comma returns a temporary variable, it needs to be an lvalue
4980 // (this is particularly important for struct constructors)
4981 if (e.e1.op == EXP.declaration &&
4982 e.e2.op == EXP.variable &&
4983 e.e1.isDeclarationExp().declaration == e.e2.isVarExp().var &&
4984 e.e2.isVarExp().var.storage_class & STC.ctfe)
4985 {
4986 VarExp ve = e.e2.isVarExp();
4987 VarDeclaration v = ve.var.isVarDeclaration();
4988 ctfeGlobals.stack.push(v);
4989 if (!v._init && !getValue(v))
4990 {
4991 setValue(v, copyLiteral(v.type.defaultInitLiteral(e.loc)).copy());
4992 }
4993 if (!getValue(v))
4994 {
4995 Expression newval = v._init.initializerToExpression();
4996 // Bug 4027. Copy constructors are a weird case where the
4997 // initializer is a void function (the variable is modified
4998 // through a reference parameter instead).
4999 newval = interpretRegion(newval, istate);
5000 if (exceptionOrCant(newval))
5001 return endTempStackFrame();
5002 if (newval.op != EXP.voidExpression)
5003 {
5004 // v isn't necessarily null.
5005 setValueWithoutChecking(v, copyLiteral(newval).copy());
5006 }
5007 }
5008 }
5009 else
5010 {
5011 UnionExp ue = void;
5012 auto e1 = interpret(&ue, e.e1, istate, CTFEGoal.Nothing);
5013 if (exceptionOrCant(e1))
5014 return endTempStackFrame();
5015 }
5016 result = interpret(pue, e.e2, istate, goal);
5017 return endTempStackFrame();
5018 }
5019
visit(CondExp e)5020 override void visit(CondExp e)
5021 {
5022 debug (LOG)
5023 {
5024 printf("%s CondExp::interpret() %s\n", e.loc.toChars(), e.toChars());
5025 }
5026 UnionExp uecond = void;
5027 Expression econd;
5028 econd = interpret(&uecond, e.econd, istate);
5029 if (exceptionOrCant(econd))
5030 return;
5031
5032 if (isPointer(e.econd.type))
5033 {
5034 if (econd.op != EXP.null_)
5035 {
5036 econd = IntegerExp.createBool(true);
5037 }
5038 }
5039
5040 if (isTrueBool(econd))
5041 {
5042 result = interpret(pue, e.e1, istate, goal);
5043 incUsageCtfe(istate, e.e1.loc);
5044 }
5045 else if (econd.toBool().hasValue(false))
5046 {
5047 result = interpret(pue, e.e2, istate, goal);
5048 incUsageCtfe(istate, e.e2.loc);
5049 }
5050 else
5051 {
5052 e.error("`%s` does not evaluate to boolean result at compile time", e.econd.toChars());
5053 result = CTFEExp.cantexp;
5054 }
5055 }
5056
visit(ArrayLengthExp e)5057 override void visit(ArrayLengthExp e)
5058 {
5059 debug (LOG)
5060 {
5061 printf("%s ArrayLengthExp::interpret() %s\n", e.loc.toChars(), e.toChars());
5062 }
5063 UnionExp ue1;
5064 Expression e1 = interpret(&ue1, e.e1, istate);
5065 assert(e1);
5066 if (exceptionOrCant(e1))
5067 return;
5068 if (e1.op != EXP.string_ && e1.op != EXP.arrayLiteral && e1.op != EXP.slice && e1.op != EXP.null_)
5069 {
5070 e.error("`%s` cannot be evaluated at compile time", e.toChars());
5071 result = CTFEExp.cantexp;
5072 return;
5073 }
5074 emplaceExp!(IntegerExp)(pue, e.loc, resolveArrayLength(e1), e.type);
5075 result = pue.exp();
5076 }
5077
5078 /**
5079 * Interpret the vector expression as an array literal.
5080 * Params:
5081 * pue = non-null pointer to temporary storage that can be used to store the return value
5082 * e = Expression to interpret
5083 * Returns:
5084 * resulting array literal or 'e' if unable to interpret
5085 */
interpretVectorToArray(UnionExp * pue,VectorExp e)5086 static Expression interpretVectorToArray(UnionExp* pue, VectorExp e)
5087 {
5088 if (auto ale = e.e1.isArrayLiteralExp())
5089 return ale; // it's already an array literal
5090 if (e.e1.op == EXP.int64 || e.e1.op == EXP.float64)
5091 {
5092 // Convert literal __vector(int) -> __vector([array])
5093 auto elements = new Expressions(e.dim);
5094 foreach (ref element; *elements)
5095 element = copyLiteral(e.e1).copy();
5096 auto type = (e.type.ty == Tvector) ? e.type.isTypeVector().basetype : e.type.isTypeSArray();
5097 assert(type);
5098 emplaceExp!(ArrayLiteralExp)(pue, e.loc, type, elements);
5099 auto ale = pue.exp().isArrayLiteralExp();
5100 ale.ownedByCtfe = OwnedBy.ctfe;
5101 return ale;
5102 }
5103 return e;
5104 }
5105
visit(VectorExp e)5106 override void visit(VectorExp e)
5107 {
5108 debug (LOG)
5109 {
5110 printf("%s VectorExp::interpret() %s\n", e.loc.toChars(), e.toChars());
5111 }
5112 if (e.ownedByCtfe >= OwnedBy.ctfe) // We've already interpreted all the elements
5113 {
5114 result = e;
5115 return;
5116 }
5117 Expression e1 = interpret(pue, e.e1, istate);
5118 assert(e1);
5119 if (exceptionOrCant(e1))
5120 return;
5121 if (e1.op != EXP.arrayLiteral && e1.op != EXP.int64 && e1.op != EXP.float64)
5122 {
5123 e.error("`%s` cannot be evaluated at compile time", e.toChars());
5124 result = CTFEExp.cantexp;
5125 return;
5126 }
5127 if (e1 == pue.exp())
5128 e1 = pue.copy();
5129 emplaceExp!(VectorExp)(pue, e.loc, e1, e.to);
5130 auto ve = pue.exp().isVectorExp();
5131 ve.type = e.type;
5132 ve.dim = e.dim;
5133 ve.ownedByCtfe = OwnedBy.ctfe;
5134 result = ve;
5135 }
5136
visit(VectorArrayExp e)5137 override void visit(VectorArrayExp e)
5138 {
5139 debug (LOG)
5140 {
5141 printf("%s VectorArrayExp::interpret() %s\n", e.loc.toChars(), e.toChars());
5142 }
5143 Expression e1 = interpret(pue, e.e1, istate);
5144 assert(e1);
5145 if (exceptionOrCant(e1))
5146 return;
5147 if (auto ve = e1.isVectorExp())
5148 {
5149 result = interpretVectorToArray(pue, ve);
5150 if (result.op != EXP.vector)
5151 return;
5152 }
5153 e.error("`%s` cannot be evaluated at compile time", e.toChars());
5154 result = CTFEExp.cantexp;
5155 }
5156
visit(DelegatePtrExp e)5157 override void visit(DelegatePtrExp e)
5158 {
5159 debug (LOG)
5160 {
5161 printf("%s DelegatePtrExp::interpret() %s\n", e.loc.toChars(), e.toChars());
5162 }
5163 Expression e1 = interpret(pue, e.e1, istate);
5164 assert(e1);
5165 if (exceptionOrCant(e1))
5166 return;
5167 e.error("`%s` cannot be evaluated at compile time", e.toChars());
5168 result = CTFEExp.cantexp;
5169 }
5170
visit(DelegateFuncptrExp e)5171 override void visit(DelegateFuncptrExp e)
5172 {
5173 debug (LOG)
5174 {
5175 printf("%s DelegateFuncptrExp::interpret() %s\n", e.loc.toChars(), e.toChars());
5176 }
5177 Expression e1 = interpret(pue, e.e1, istate);
5178 assert(e1);
5179 if (exceptionOrCant(e1))
5180 return;
5181 e.error("`%s` cannot be evaluated at compile time", e.toChars());
5182 result = CTFEExp.cantexp;
5183 }
5184
resolveIndexing(IndexExp e,InterState * istate,Expression * pagg,uinteger_t * pidx,bool modify)5185 static bool resolveIndexing(IndexExp e, InterState* istate, Expression* pagg, uinteger_t* pidx, bool modify)
5186 {
5187 assert(e.e1.type.toBasetype().ty != Taarray);
5188
5189 if (e.e1.type.toBasetype().ty == Tpointer)
5190 {
5191 // Indexing a pointer. Note that there is no $ in this case.
5192 Expression e1 = interpretRegion(e.e1, istate);
5193 if (exceptionOrCantInterpret(e1))
5194 return false;
5195
5196 Expression e2 = interpretRegion(e.e2, istate);
5197 if (exceptionOrCantInterpret(e2))
5198 return false;
5199 sinteger_t indx = e2.toInteger();
5200
5201 dinteger_t ofs;
5202 Expression agg = getAggregateFromPointer(e1, &ofs);
5203
5204 if (agg.op == EXP.null_)
5205 {
5206 e.error("cannot index through null pointer `%s`", e.e1.toChars());
5207 return false;
5208 }
5209 if (agg.op == EXP.int64)
5210 {
5211 e.error("cannot index through invalid pointer `%s` of value `%s`", e.e1.toChars(), e1.toChars());
5212 return false;
5213 }
5214 // Pointer to a non-array variable
5215 if (agg.op == EXP.symbolOffset)
5216 {
5217 e.error("mutable variable `%s` cannot be %s at compile time, even through a pointer", cast(char*)(modify ? "modified" : "read"), agg.isSymOffExp().var.toChars());
5218 return false;
5219 }
5220
5221 if (agg.op == EXP.arrayLiteral || agg.op == EXP.string_)
5222 {
5223 dinteger_t len = resolveArrayLength(agg);
5224 if (ofs + indx >= len)
5225 {
5226 e.error("pointer index `[%lld]` exceeds allocated memory block `[0..%lld]`", ofs + indx, len);
5227 return false;
5228 }
5229 }
5230 else
5231 {
5232 if (ofs + indx != 0)
5233 {
5234 e.error("pointer index `[%lld]` lies outside memory block `[0..1]`", ofs + indx);
5235 return false;
5236 }
5237 }
5238 *pagg = agg;
5239 *pidx = ofs + indx;
5240 return true;
5241 }
5242
5243 Expression e1 = interpretRegion(e.e1, istate);
5244 if (exceptionOrCantInterpret(e1))
5245 return false;
5246 if (e1.op == EXP.null_)
5247 {
5248 e.error("cannot index null array `%s`", e.e1.toChars());
5249 return false;
5250 }
5251 if (auto ve = e1.isVectorExp())
5252 {
5253 UnionExp ue = void;
5254 e1 = interpretVectorToArray(&ue, ve);
5255 e1 = (e1 == ue.exp()) ? ue.copy() : e1;
5256 }
5257
5258 // Set the $ variable, and find the array literal to modify
5259 dinteger_t len;
5260 if (e1.op == EXP.variable && e1.type.toBasetype().ty == Tsarray)
5261 len = e1.type.toBasetype().isTypeSArray().dim.toInteger();
5262 else
5263 {
5264 if (e1.op != EXP.arrayLiteral && e1.op != EXP.string_ && e1.op != EXP.slice && e1.op != EXP.vector)
5265 {
5266 e.error("cannot determine length of `%s` at compile time", e.e1.toChars());
5267 return false;
5268 }
5269 len = resolveArrayLength(e1);
5270 }
5271
5272 if (e.lengthVar)
5273 {
5274 Expression dollarExp = ctfeEmplaceExp!IntegerExp(e.loc, len, Type.tsize_t);
5275 ctfeGlobals.stack.push(e.lengthVar);
5276 setValue(e.lengthVar, dollarExp);
5277 }
5278 Expression e2 = interpretRegion(e.e2, istate);
5279 if (e.lengthVar)
5280 ctfeGlobals.stack.pop(e.lengthVar); // $ is defined only inside []
5281 if (exceptionOrCantInterpret(e2))
5282 return false;
5283 if (e2.op != EXP.int64)
5284 {
5285 e.error("CTFE internal error: non-integral index `[%s]`", e.e2.toChars());
5286 return false;
5287 }
5288
5289 if (auto se = e1.isSliceExp())
5290 {
5291 // Simplify index of slice: agg[lwr..upr][indx] --> agg[indx']
5292 uinteger_t index = e2.toInteger();
5293 uinteger_t ilwr = se.lwr.toInteger();
5294 uinteger_t iupr = se.upr.toInteger();
5295
5296 if (index > iupr - ilwr)
5297 {
5298 e.error("index %llu exceeds array length %llu", index, iupr - ilwr);
5299 return false;
5300 }
5301 *pagg = e1.isSliceExp().e1;
5302 *pidx = index + ilwr;
5303 }
5304 else
5305 {
5306 *pagg = e1;
5307 *pidx = e2.toInteger();
5308 if (len <= *pidx)
5309 {
5310 e.error("array index %lld is out of bounds `[0..%lld]`", *pidx, len);
5311 return false;
5312 }
5313 }
5314 return true;
5315 }
5316
visit(IndexExp e)5317 override void visit(IndexExp e)
5318 {
5319 debug (LOG)
5320 {
5321 printf("%s IndexExp::interpret() %s, goal = %d\n", e.loc.toChars(), e.toChars(), goal);
5322 }
5323 if (e.e1.type.toBasetype().ty == Tpointer)
5324 {
5325 Expression agg;
5326 uinteger_t indexToAccess;
5327 if (!resolveIndexing(e, istate, &agg, &indexToAccess, false))
5328 {
5329 result = CTFEExp.cantexp;
5330 return;
5331 }
5332 if (agg.op == EXP.arrayLiteral || agg.op == EXP.string_)
5333 {
5334 if (goal == CTFEGoal.LValue)
5335 {
5336 // if we need a reference, IndexExp shouldn't be interpreting
5337 // the expression to a value, it should stay as a reference
5338 emplaceExp!(IndexExp)(pue, e.loc, agg, ctfeEmplaceExp!IntegerExp(e.e2.loc, indexToAccess, e.e2.type));
5339 result = pue.exp();
5340 result.type = e.type;
5341 return;
5342 }
5343 result = ctfeIndex(pue, e.loc, e.type, agg, indexToAccess);
5344 return;
5345 }
5346 else
5347 {
5348 assert(indexToAccess == 0);
5349 result = interpretRegion(agg, istate, goal);
5350 if (exceptionOrCant(result))
5351 return;
5352 result = paintTypeOntoLiteral(pue, e.type, result);
5353 return;
5354 }
5355 }
5356
5357 if (e.e1.type.toBasetype().ty == Taarray)
5358 {
5359 Expression e1 = interpretRegion(e.e1, istate);
5360 if (exceptionOrCant(e1))
5361 return;
5362 if (e1.op == EXP.null_)
5363 {
5364 if (goal == CTFEGoal.LValue && e1.type.ty == Taarray && e.modifiable)
5365 {
5366 assert(0); // does not reach here?
5367 }
5368 e.error("cannot index null array `%s`", e.e1.toChars());
5369 result = CTFEExp.cantexp;
5370 return;
5371 }
5372 Expression e2 = interpretRegion(e.e2, istate);
5373 if (exceptionOrCant(e2))
5374 return;
5375
5376 if (goal == CTFEGoal.LValue)
5377 {
5378 // Pointer or reference of a scalar type
5379 if (e1 == e.e1 && e2 == e.e2)
5380 result = e;
5381 else
5382 {
5383 emplaceExp!(IndexExp)(pue, e.loc, e1, e2);
5384 result = pue.exp();
5385 result.type = e.type;
5386 }
5387 return;
5388 }
5389
5390 assert(e1.op == EXP.assocArrayLiteral);
5391 UnionExp e2tmp = void;
5392 e2 = resolveSlice(e2, &e2tmp);
5393 result = findKeyInAA(e.loc, e1.isAssocArrayLiteralExp(), e2);
5394 if (!result)
5395 {
5396 e.error("key `%s` not found in associative array `%s`", e2.toChars(), e.e1.toChars());
5397 result = CTFEExp.cantexp;
5398 }
5399 return;
5400 }
5401
5402 Expression agg;
5403 uinteger_t indexToAccess;
5404 if (!resolveIndexing(e, istate, &agg, &indexToAccess, false))
5405 {
5406 result = CTFEExp.cantexp;
5407 return;
5408 }
5409
5410 if (goal == CTFEGoal.LValue)
5411 {
5412 Expression e2 = ctfeEmplaceExp!IntegerExp(e.e2.loc, indexToAccess, Type.tsize_t);
5413 emplaceExp!(IndexExp)(pue, e.loc, agg, e2);
5414 result = pue.exp();
5415 result.type = e.type;
5416 return;
5417 }
5418
5419 result = ctfeIndex(pue, e.loc, e.type, agg, indexToAccess);
5420 if (exceptionOrCant(result))
5421 return;
5422 if (result.op == EXP.void_)
5423 {
5424 e.error("`%s` is used before initialized", e.toChars());
5425 errorSupplemental(result.loc, "originally uninitialized here");
5426 result = CTFEExp.cantexp;
5427 return;
5428 }
5429 if (result == pue.exp())
5430 result = result.copy();
5431 }
5432
visit(SliceExp e)5433 override void visit(SliceExp e)
5434 {
5435 debug (LOG)
5436 {
5437 printf("%s SliceExp::interpret() %s\n", e.loc.toChars(), e.toChars());
5438 }
5439 if (e.e1.type.toBasetype().ty == Tpointer)
5440 {
5441 // Slicing a pointer. Note that there is no $ in this case.
5442 Expression e1 = interpretRegion(e.e1, istate);
5443 if (exceptionOrCant(e1))
5444 return;
5445 if (e1.op == EXP.int64)
5446 {
5447 e.error("cannot slice invalid pointer `%s` of value `%s`", e.e1.toChars(), e1.toChars());
5448 result = CTFEExp.cantexp;
5449 return;
5450 }
5451
5452 /* Evaluate lower and upper bounds of slice
5453 */
5454 Expression lwr = interpretRegion(e.lwr, istate);
5455 if (exceptionOrCant(lwr))
5456 return;
5457 Expression upr = interpretRegion(e.upr, istate);
5458 if (exceptionOrCant(upr))
5459 return;
5460 uinteger_t ilwr = lwr.toInteger();
5461 uinteger_t iupr = upr.toInteger();
5462
5463 dinteger_t ofs;
5464 Expression agg = getAggregateFromPointer(e1, &ofs);
5465 ilwr += ofs;
5466 iupr += ofs;
5467 if (agg.op == EXP.null_)
5468 {
5469 if (iupr == ilwr)
5470 {
5471 result = ctfeEmplaceExp!NullExp(e.loc);
5472 result.type = e.type;
5473 return;
5474 }
5475 e.error("cannot slice null pointer `%s`", e.e1.toChars());
5476 result = CTFEExp.cantexp;
5477 return;
5478 }
5479 if (agg.op == EXP.symbolOffset)
5480 {
5481 e.error("slicing pointers to static variables is not supported in CTFE");
5482 result = CTFEExp.cantexp;
5483 return;
5484 }
5485 if (agg.op != EXP.arrayLiteral && agg.op != EXP.string_)
5486 {
5487 e.error("pointer `%s` cannot be sliced at compile time (it does not point to an array)", e.e1.toChars());
5488 result = CTFEExp.cantexp;
5489 return;
5490 }
5491 assert(agg.op == EXP.arrayLiteral || agg.op == EXP.string_);
5492 dinteger_t len = ArrayLength(Type.tsize_t, agg).exp().toInteger();
5493 //Type *pointee = ((TypePointer *)agg.type)->next;
5494 if (sliceBoundsCheck(0, len, ilwr, iupr))
5495 {
5496 e.error("pointer slice `[%lld..%lld]` exceeds allocated memory block `[0..%lld]`", ilwr, iupr, len);
5497 result = CTFEExp.cantexp;
5498 return;
5499 }
5500 if (ofs != 0)
5501 {
5502 lwr = ctfeEmplaceExp!IntegerExp(e.loc, ilwr, lwr.type);
5503 upr = ctfeEmplaceExp!IntegerExp(e.loc, iupr, upr.type);
5504 }
5505 emplaceExp!(SliceExp)(pue, e.loc, agg, lwr, upr);
5506 result = pue.exp();
5507 result.type = e.type;
5508 return;
5509 }
5510
5511 CTFEGoal goal1 = CTFEGoal.RValue;
5512 if (goal == CTFEGoal.LValue)
5513 {
5514 if (e.e1.type.toBasetype().ty == Tsarray)
5515 if (auto ve = e.e1.isVarExp())
5516 if (auto vd = ve.var.isVarDeclaration())
5517 if (vd.storage_class & STC.ref_)
5518 goal1 = CTFEGoal.LValue;
5519 }
5520 Expression e1 = interpret(e.e1, istate, goal1);
5521 if (exceptionOrCant(e1))
5522 return;
5523
5524 if (!e.lwr)
5525 {
5526 result = paintTypeOntoLiteral(pue, e.type, e1);
5527 return;
5528 }
5529 if (auto ve = e1.isVectorExp())
5530 {
5531 e1 = interpretVectorToArray(pue, ve);
5532 e1 = (e1 == pue.exp()) ? pue.copy() : e1;
5533 }
5534
5535 /* Set dollar to the length of the array
5536 */
5537 uinteger_t dollar;
5538 if ((e1.op == EXP.variable || e1.op == EXP.dotVariable) && e1.type.toBasetype().ty == Tsarray)
5539 dollar = e1.type.toBasetype().isTypeSArray().dim.toInteger();
5540 else
5541 {
5542 if (e1.op != EXP.arrayLiteral && e1.op != EXP.string_ && e1.op != EXP.null_ && e1.op != EXP.slice && e1.op != EXP.vector)
5543 {
5544 e.error("cannot determine length of `%s` at compile time", e1.toChars());
5545 result = CTFEExp.cantexp;
5546 return;
5547 }
5548 dollar = resolveArrayLength(e1);
5549 }
5550
5551 /* Set the $ variable
5552 */
5553 if (e.lengthVar)
5554 {
5555 auto dollarExp = ctfeEmplaceExp!IntegerExp(e.loc, dollar, Type.tsize_t);
5556 ctfeGlobals.stack.push(e.lengthVar);
5557 setValue(e.lengthVar, dollarExp);
5558 }
5559
5560 /* Evaluate lower and upper bounds of slice
5561 */
5562 Expression lwr = interpretRegion(e.lwr, istate);
5563 if (exceptionOrCant(lwr))
5564 {
5565 if (e.lengthVar)
5566 ctfeGlobals.stack.pop(e.lengthVar);
5567 return;
5568 }
5569 Expression upr = interpretRegion(e.upr, istate);
5570 if (exceptionOrCant(upr))
5571 {
5572 if (e.lengthVar)
5573 ctfeGlobals.stack.pop(e.lengthVar);
5574 return;
5575 }
5576 if (e.lengthVar)
5577 ctfeGlobals.stack.pop(e.lengthVar); // $ is defined only inside [L..U]
5578
5579 uinteger_t ilwr = lwr.toInteger();
5580 uinteger_t iupr = upr.toInteger();
5581 if (e1.op == EXP.null_)
5582 {
5583 if (ilwr == 0 && iupr == 0)
5584 {
5585 result = e1;
5586 return;
5587 }
5588 e1.error("slice `[%llu..%llu]` is out of bounds", ilwr, iupr);
5589 result = CTFEExp.cantexp;
5590 return;
5591 }
5592 if (auto se = e1.isSliceExp())
5593 {
5594 // Simplify slice of slice:
5595 // aggregate[lo1..up1][lwr..upr] ---> aggregate[lwr'..upr']
5596 uinteger_t lo1 = se.lwr.toInteger();
5597 uinteger_t up1 = se.upr.toInteger();
5598 if (sliceBoundsCheck(0, up1 - lo1, ilwr, iupr))
5599 {
5600 e.error("slice `[%llu..%llu]` exceeds array bounds `[0..%llu]`", ilwr, iupr, up1 - lo1);
5601 result = CTFEExp.cantexp;
5602 return;
5603 }
5604 ilwr += lo1;
5605 iupr += lo1;
5606 emplaceExp!(SliceExp)(pue, e.loc, se.e1,
5607 ctfeEmplaceExp!IntegerExp(e.loc, ilwr, lwr.type),
5608 ctfeEmplaceExp!IntegerExp(e.loc, iupr, upr.type));
5609 result = pue.exp();
5610 result.type = e.type;
5611 return;
5612 }
5613 if (e1.op == EXP.arrayLiteral || e1.op == EXP.string_)
5614 {
5615 if (sliceBoundsCheck(0, dollar, ilwr, iupr))
5616 {
5617 e.error("slice `[%lld..%lld]` exceeds array bounds `[0..%lld]`", ilwr, iupr, dollar);
5618 result = CTFEExp.cantexp;
5619 return;
5620 }
5621 }
5622 emplaceExp!(SliceExp)(pue, e.loc, e1, lwr, upr);
5623 result = pue.exp();
5624 result.type = e.type;
5625 }
5626
visit(InExp e)5627 override void visit(InExp e)
5628 {
5629 debug (LOG)
5630 {
5631 printf("%s InExp::interpret() %s\n", e.loc.toChars(), e.toChars());
5632 }
5633 Expression e1 = interpretRegion(e.e1, istate);
5634 if (exceptionOrCant(e1))
5635 return;
5636 Expression e2 = interpretRegion(e.e2, istate);
5637 if (exceptionOrCant(e2))
5638 return;
5639 if (e2.op == EXP.null_)
5640 {
5641 emplaceExp!(NullExp)(pue, e.loc, e.type);
5642 result = pue.exp();
5643 return;
5644 }
5645 if (e2.op != EXP.assocArrayLiteral)
5646 {
5647 e.error("`%s` cannot be interpreted at compile time", e.toChars());
5648 result = CTFEExp.cantexp;
5649 return;
5650 }
5651
5652 e1 = resolveSlice(e1);
5653 result = findKeyInAA(e.loc, e2.isAssocArrayLiteralExp(), e1);
5654 if (exceptionOrCant(result))
5655 return;
5656 if (!result)
5657 {
5658 emplaceExp!(NullExp)(pue, e.loc, e.type);
5659 result = pue.exp();
5660 }
5661 else
5662 {
5663 // Create a CTFE pointer &aa[index]
5664 result = ctfeEmplaceExp!IndexExp(e.loc, e2, e1);
5665 result.type = e.type.nextOf();
5666 emplaceExp!(AddrExp)(pue, e.loc, result, e.type);
5667 result = pue.exp();
5668 }
5669 }
5670
visit(CatExp e)5671 override void visit(CatExp e)
5672 {
5673 debug (LOG)
5674 {
5675 printf("%s CatExp::interpret() %s\n", e.loc.toChars(), e.toChars());
5676 }
5677
5678 UnionExp ue1 = void;
5679 Expression e1 = interpret(&ue1, e.e1, istate);
5680 if (exceptionOrCant(e1))
5681 return;
5682
5683 UnionExp ue2 = void;
5684 Expression e2 = interpret(&ue2, e.e2, istate);
5685 if (exceptionOrCant(e2))
5686 return;
5687
5688 UnionExp e1tmp = void;
5689 e1 = resolveSlice(e1, &e1tmp);
5690
5691 UnionExp e2tmp = void;
5692 e2 = resolveSlice(e2, &e2tmp);
5693
5694 /* e1 and e2 can't go on the stack because of x~[y] and [x]~y will
5695 * result in [x,y] and then x or y is on the stack.
5696 * But if they are both strings, we can, because it isn't the x~[y] case.
5697 */
5698 if (!(e1.op == EXP.string_ && e2.op == EXP.string_))
5699 {
5700 if (e1 == ue1.exp())
5701 e1 = ue1.copy();
5702 if (e2 == ue2.exp())
5703 e2 = ue2.copy();
5704 }
5705
5706 *pue = ctfeCat(e.loc, e.type, e1, e2);
5707 result = pue.exp();
5708
5709 if (CTFEExp.isCantExp(result))
5710 {
5711 e.error("`%s` cannot be interpreted at compile time", e.toChars());
5712 return;
5713 }
5714 // We know we still own it, because we interpreted both e1 and e2
5715 if (auto ale = result.isArrayLiteralExp())
5716 {
5717 ale.ownedByCtfe = OwnedBy.ctfe;
5718
5719 // https://issues.dlang.org/show_bug.cgi?id=14686
5720 foreach (elem; *ale.elements)
5721 {
5722 Expression ex = evaluatePostblit(istate, elem);
5723 if (exceptionOrCant(ex))
5724 return;
5725 }
5726 }
5727 else if (auto se = result.isStringExp())
5728 se.ownedByCtfe = OwnedBy.ctfe;
5729 }
5730
visit(DeleteExp e)5731 override void visit(DeleteExp e)
5732 {
5733 debug (LOG)
5734 {
5735 printf("%s DeleteExp::interpret() %s\n", e.loc.toChars(), e.toChars());
5736 }
5737 result = interpretRegion(e.e1, istate);
5738 if (exceptionOrCant(result))
5739 return;
5740
5741 if (result.op == EXP.null_)
5742 {
5743 result = CTFEExp.voidexp;
5744 return;
5745 }
5746
5747 auto tb = e.e1.type.toBasetype();
5748 switch (tb.ty)
5749 {
5750 case Tclass:
5751 if (result.op != EXP.classReference)
5752 {
5753 e.error("`delete` on invalid class reference `%s`", result.toChars());
5754 result = CTFEExp.cantexp;
5755 return;
5756 }
5757
5758 auto cre = result.isClassReferenceExp();
5759 auto cd = cre.originalClass();
5760
5761 // Find dtor(s) in inheritance chain
5762 do
5763 {
5764 if (cd.dtor)
5765 {
5766 result = interpretFunction(pue, cd.dtor, istate, null, cre);
5767 if (exceptionOrCant(result))
5768 return;
5769
5770 // Dtors of Non-extern(D) classes use implicit chaining (like structs)
5771 import dmd.aggregate : ClassKind;
5772 if (cd.classKind != ClassKind.d)
5773 break;
5774 }
5775
5776 // Emulate manual chaining as done in rt_finalize2
5777 cd = cd.baseClass;
5778
5779 } while (cd); // Stop after Object
5780
5781 break;
5782
5783 default:
5784 assert(0);
5785 }
5786 result = CTFEExp.voidexp;
5787 }
5788
visit(CastExp e)5789 override void visit(CastExp e)
5790 {
5791 debug (LOG)
5792 {
5793 printf("%s CastExp::interpret() %s\n", e.loc.toChars(), e.toChars());
5794 }
5795 Expression e1 = interpretRegion(e.e1, istate, goal);
5796 if (exceptionOrCant(e1))
5797 return;
5798 // If the expression has been cast to void, do nothing.
5799 if (e.to.ty == Tvoid)
5800 {
5801 result = CTFEExp.voidexp;
5802 return;
5803 }
5804 if (e.to.ty == Tpointer && e1.op != EXP.null_)
5805 {
5806 Type pointee = (cast(TypePointer)e.type).next;
5807 // Implement special cases of normally-unsafe casts
5808 if (e1.op == EXP.int64)
5809 {
5810 // Happens with Windows HANDLEs, for example.
5811 result = paintTypeOntoLiteral(pue, e.to, e1);
5812 return;
5813 }
5814
5815 bool castToSarrayPointer = false;
5816 bool castBackFromVoid = false;
5817 if (e1.type.ty == Tarray || e1.type.ty == Tsarray || e1.type.ty == Tpointer)
5818 {
5819 // Check for unsupported type painting operations
5820 // For slices, we need the type being sliced,
5821 // since it may have already been type painted
5822 Type elemtype = e1.type.nextOf();
5823 if (auto se = e1.isSliceExp())
5824 elemtype = se.e1.type.nextOf();
5825
5826 // Allow casts from X* to void *, and X** to void** for any X.
5827 // But don't allow cast from X* to void**.
5828 // So, we strip all matching * from source and target to find X.
5829 // Allow casts to X* from void* only if the 'void' was originally an X;
5830 // we check this later on.
5831 Type ultimatePointee = pointee;
5832 Type ultimateSrc = elemtype;
5833 while (ultimatePointee.ty == Tpointer && ultimateSrc.ty == Tpointer)
5834 {
5835 ultimatePointee = ultimatePointee.nextOf();
5836 ultimateSrc = ultimateSrc.nextOf();
5837 }
5838 if (ultimatePointee.ty == Tsarray && ultimatePointee.nextOf().equivalent(ultimateSrc))
5839 {
5840 castToSarrayPointer = true;
5841 }
5842 else if (ultimatePointee.ty != Tvoid && ultimateSrc.ty != Tvoid && !isSafePointerCast(elemtype, pointee))
5843 {
5844 e.error("reinterpreting cast from `%s*` to `%s*` is not supported in CTFE", elemtype.toChars(), pointee.toChars());
5845 result = CTFEExp.cantexp;
5846 return;
5847 }
5848 if (ultimateSrc.ty == Tvoid)
5849 castBackFromVoid = true;
5850 }
5851
5852 if (auto se = e1.isSliceExp())
5853 {
5854 if (se.e1.op == EXP.null_)
5855 {
5856 result = paintTypeOntoLiteral(pue, e.type, se.e1);
5857 return;
5858 }
5859 // Create a CTFE pointer &aggregate[1..2]
5860 auto ei = ctfeEmplaceExp!IndexExp(e.loc, se.e1, se.lwr);
5861 ei.type = e.type.nextOf();
5862 emplaceExp!(AddrExp)(pue, e.loc, ei, e.type);
5863 result = pue.exp();
5864 return;
5865 }
5866 if (e1.op == EXP.arrayLiteral || e1.op == EXP.string_)
5867 {
5868 // Create a CTFE pointer &[1,2,3][0] or &"abc"[0]
5869 auto ei = ctfeEmplaceExp!IndexExp(e.loc, e1, ctfeEmplaceExp!IntegerExp(e.loc, 0, Type.tsize_t));
5870 ei.type = e.type.nextOf();
5871 emplaceExp!(AddrExp)(pue, e.loc, ei, e.type);
5872 result = pue.exp();
5873 return;
5874 }
5875 if (e1.op == EXP.index && !e1.isIndexExp().e1.type.equals(e1.type))
5876 {
5877 // type painting operation
5878 IndexExp ie = e1.isIndexExp();
5879 if (castBackFromVoid)
5880 {
5881 // get the original type. For strings, it's just the type...
5882 Type origType = ie.e1.type.nextOf();
5883 // ..but for arrays of type void*, it's the type of the element
5884 if (ie.e1.op == EXP.arrayLiteral && ie.e2.op == EXP.int64)
5885 {
5886 ArrayLiteralExp ale = ie.e1.isArrayLiteralExp();
5887 const indx = cast(size_t)ie.e2.toInteger();
5888 if (indx < ale.elements.dim)
5889 {
5890 if (Expression xx = (*ale.elements)[indx])
5891 {
5892 if (auto iex = xx.isIndexExp())
5893 origType = iex.e1.type.nextOf();
5894 else if (auto ae = xx.isAddrExp())
5895 origType = ae.e1.type;
5896 else if (auto ve = xx.isVarExp())
5897 origType = ve.var.type;
5898 }
5899 }
5900 }
5901 if (!isSafePointerCast(origType, pointee))
5902 {
5903 e.error("using `void*` to reinterpret cast from `%s*` to `%s*` is not supported in CTFE", origType.toChars(), pointee.toChars());
5904 result = CTFEExp.cantexp;
5905 return;
5906 }
5907 }
5908 emplaceExp!(IndexExp)(pue, e1.loc, ie.e1, ie.e2);
5909 result = pue.exp();
5910 result.type = e.type;
5911 return;
5912 }
5913
5914 if (auto ae = e1.isAddrExp())
5915 {
5916 Type origType = ae.e1.type;
5917 if (isSafePointerCast(origType, pointee))
5918 {
5919 emplaceExp!(AddrExp)(pue, e.loc, ae.e1, e.type);
5920 result = pue.exp();
5921 return;
5922 }
5923
5924 if (castToSarrayPointer && pointee.toBasetype().ty == Tsarray && ae.e1.op == EXP.index)
5925 {
5926 // &val[idx]
5927 dinteger_t dim = (cast(TypeSArray)pointee.toBasetype()).dim.toInteger();
5928 IndexExp ie = ae.e1.isIndexExp();
5929 Expression lwr = ie.e2;
5930 Expression upr = ctfeEmplaceExp!IntegerExp(ie.e2.loc, ie.e2.toInteger() + dim, Type.tsize_t);
5931
5932 // Create a CTFE pointer &val[idx..idx+dim]
5933 auto er = ctfeEmplaceExp!SliceExp(e.loc, ie.e1, lwr, upr);
5934 er.type = pointee;
5935 emplaceExp!(AddrExp)(pue, e.loc, er, e.type);
5936 result = pue.exp();
5937 return;
5938 }
5939 }
5940
5941 if (e1.op == EXP.variable || e1.op == EXP.symbolOffset)
5942 {
5943 // type painting operation
5944 Type origType = (cast(SymbolExp)e1).var.type;
5945 if (castBackFromVoid && !isSafePointerCast(origType, pointee))
5946 {
5947 e.error("using `void*` to reinterpret cast from `%s*` to `%s*` is not supported in CTFE", origType.toChars(), pointee.toChars());
5948 result = CTFEExp.cantexp;
5949 return;
5950 }
5951 if (auto ve = e1.isVarExp())
5952 emplaceExp!(VarExp)(pue, e.loc, ve.var);
5953 else
5954 emplaceExp!(SymOffExp)(pue, e.loc, e1.isSymOffExp().var, e1.isSymOffExp().offset);
5955 result = pue.exp();
5956 result.type = e.to;
5957 return;
5958 }
5959
5960 // Check if we have a null pointer (eg, inside a struct)
5961 e1 = interpretRegion(e1, istate);
5962 if (e1.op != EXP.null_)
5963 {
5964 e.error("pointer cast from `%s` to `%s` is not supported at compile time", e1.type.toChars(), e.to.toChars());
5965 result = CTFEExp.cantexp;
5966 return;
5967 }
5968 }
5969 if (e.to.ty == Tsarray && e.e1.type.ty == Tvector)
5970 {
5971 // Special handling for: cast(float[4])__vector([w, x, y, z])
5972 e1 = interpretRegion(e.e1, istate);
5973 if (exceptionOrCant(e1))
5974 return;
5975 assert(e1.op == EXP.vector);
5976 e1 = interpretVectorToArray(pue, e1.isVectorExp());
5977 }
5978 if (e.to.ty == Tarray && e1.op == EXP.slice)
5979 {
5980 // Note that the slice may be void[], so when checking for dangerous
5981 // casts, we need to use the original type, which is se.e1.
5982 SliceExp se = e1.isSliceExp();
5983 if (!isSafePointerCast(se.e1.type.nextOf(), e.to.nextOf()))
5984 {
5985 e.error("array cast from `%s` to `%s` is not supported at compile time", se.e1.type.toChars(), e.to.toChars());
5986 result = CTFEExp.cantexp;
5987 return;
5988 }
5989 emplaceExp!(SliceExp)(pue, e1.loc, se.e1, se.lwr, se.upr);
5990 result = pue.exp();
5991 result.type = e.to;
5992 return;
5993 }
5994 // Disallow array type painting, except for conversions between built-in
5995 // types of identical size.
5996 if ((e.to.ty == Tsarray || e.to.ty == Tarray) && (e1.type.ty == Tsarray || e1.type.ty == Tarray) && !isSafePointerCast(e1.type.nextOf(), e.to.nextOf()))
5997 {
5998 e.error("array cast from `%s` to `%s` is not supported at compile time", e1.type.toChars(), e.to.toChars());
5999 result = CTFEExp.cantexp;
6000 return;
6001 }
6002 if (e.to.ty == Tsarray)
6003 e1 = resolveSlice(e1);
6004
6005 auto tobt = e.to.toBasetype();
6006 if (tobt.ty == Tbool && e1.type.ty == Tpointer)
6007 {
6008 emplaceExp!(IntegerExp)(pue, e.loc, e1.op != EXP.null_, e.to);
6009 result = pue.exp();
6010 return;
6011 }
6012 else if (tobt.isTypeBasic() && e1.op == EXP.null_)
6013 {
6014 if (tobt.isintegral())
6015 emplaceExp!(IntegerExp)(pue, e.loc, 0, e.to);
6016 else if (tobt.isreal())
6017 emplaceExp!(RealExp)(pue, e.loc, CTFloat.zero, e.to);
6018 result = pue.exp();
6019 return;
6020 }
6021 result = ctfeCast(pue, e.loc, e.type, e.to, e1, true);
6022 }
6023
visit(AssertExp e)6024 override void visit(AssertExp e)
6025 {
6026 debug (LOG)
6027 {
6028 printf("%s AssertExp::interpret() %s\n", e.loc.toChars(), e.toChars());
6029 }
6030 Expression e1 = interpret(pue, e.e1, istate);
6031 if (exceptionOrCant(e1))
6032 return;
6033 if (isTrueBool(e1))
6034 {
6035 }
6036 else if (e1.toBool().hasValue(false))
6037 {
6038 if (e.msg)
6039 {
6040 UnionExp ue = void;
6041 result = interpret(&ue, e.msg, istate);
6042 if (exceptionOrCant(result))
6043 return;
6044 e.error("`%s`", result.toChars());
6045 }
6046 else
6047 e.error("`%s` failed", e.toChars());
6048 result = CTFEExp.cantexp;
6049 return;
6050 }
6051 else
6052 {
6053 e.error("`%s` is not a compile time boolean expression", e1.toChars());
6054 result = CTFEExp.cantexp;
6055 return;
6056 }
6057 result = e1;
6058 return;
6059 }
6060
visit(ThrowExp te)6061 override void visit(ThrowExp te)
6062 {
6063 debug (LOG)
6064 {
6065 printf("%s ThrowExpression::interpret()\n", e.loc.toChars());
6066 }
6067 interpretThrow(te.e1, te.loc);
6068 }
6069
visit(PtrExp e)6070 override void visit(PtrExp e)
6071 {
6072 debug (LOG)
6073 {
6074 printf("%s PtrExp::interpret() %s\n", e.loc.toChars(), e.toChars());
6075 }
6076 // Check for int<->float and long<->double casts.
6077 if (auto soe1 = e.e1.isSymOffExp())
6078 if (soe1.offset == 0 && soe1.var.isVarDeclaration() && isFloatIntPaint(e.type, soe1.var.type))
6079 {
6080 // *(cast(int*)&v), where v is a float variable
6081 result = paintFloatInt(pue, getVarExp(e.loc, istate, soe1.var, CTFEGoal.RValue), e.type);
6082 return;
6083 }
6084
6085 if (auto ce1 = e.e1.isCastExp())
6086 if (auto ae11 = ce1.e1.isAddrExp())
6087 {
6088 // *(cast(int*)&x), where x is a float expression
6089 Expression x = ae11.e1;
6090 if (isFloatIntPaint(e.type, x.type))
6091 {
6092 result = paintFloatInt(pue, interpretRegion(x, istate), e.type);
6093 return;
6094 }
6095 }
6096
6097 // Constant fold *(&structliteral + offset)
6098 if (auto ae = e.e1.isAddExp())
6099 {
6100 if (ae.e1.op == EXP.address && ae.e2.op == EXP.int64)
6101 {
6102 AddrExp ade = ae.e1.isAddrExp();
6103 Expression ex = interpretRegion(ade.e1, istate);
6104 if (exceptionOrCant(ex))
6105 return;
6106 if (auto se = ex.isStructLiteralExp())
6107 {
6108 dinteger_t offset = ae.e2.toInteger();
6109 result = se.getField(e.type, cast(uint)offset);
6110 if (result)
6111 return;
6112 }
6113 }
6114 }
6115
6116 // It's possible we have an array bounds error. We need to make sure it
6117 // errors with this line number, not the one where the pointer was set.
6118 result = interpretRegion(e.e1, istate);
6119 if (exceptionOrCant(result))
6120 return;
6121
6122 if (result.op == EXP.function_)
6123 return;
6124 if (auto soe = result.isSymOffExp())
6125 {
6126 if (soe.offset == 0 && soe.var.isFuncDeclaration())
6127 return;
6128 e.error("cannot dereference pointer to static variable `%s` at compile time", soe.var.toChars());
6129 result = CTFEExp.cantexp;
6130 return;
6131 }
6132
6133 if (result.isStringExp())
6134 return;
6135
6136 if (result.op != EXP.address)
6137 {
6138 if (result.op == EXP.null_)
6139 e.error("dereference of null pointer `%s`", e.e1.toChars());
6140 else
6141 e.error("dereference of invalid pointer `%s`", result.toChars());
6142 result = CTFEExp.cantexp;
6143 return;
6144 }
6145
6146 // *(&x) ==> x
6147 result = result.isAddrExp().e1;
6148
6149 if (result.op == EXP.slice && e.type.toBasetype().ty == Tsarray)
6150 {
6151 /* aggr[lwr..upr]
6152 * upr may exceed the upper boundary of aggr, but the check is deferred
6153 * until those out-of-bounds elements will be touched.
6154 */
6155 return;
6156 }
6157 result = interpret(pue, result, istate, goal);
6158 if (exceptionOrCant(result))
6159 return;
6160
6161 debug (LOG)
6162 {
6163 if (CTFEExp.isCantExp(result))
6164 printf("PtrExp::interpret() %s = CTFEExp::cantexp\n", e.toChars());
6165 }
6166 }
6167
visit(DotVarExp e)6168 override void visit(DotVarExp e)
6169 {
6170 void notImplementedYet()
6171 {
6172 e.error("`%s.%s` is not yet implemented at compile time", e.e1.toChars(), e.var.toChars());
6173 result = CTFEExp.cantexp;
6174 return;
6175 }
6176
6177 debug (LOG)
6178 {
6179 printf("%s DotVarExp::interpret() %s, goal = %d\n", e.loc.toChars(), e.toChars(), goal);
6180 }
6181 Expression ex = interpretRegion(e.e1, istate);
6182 if (exceptionOrCant(ex))
6183 return;
6184
6185 if (FuncDeclaration f = e.var.isFuncDeclaration())
6186 {
6187 if (ex == e.e1)
6188 result = e; // optimize: reuse this CTFE reference
6189 else
6190 {
6191 emplaceExp!(DotVarExp)(pue, e.loc, ex, f, false);
6192 result = pue.exp();
6193 result.type = e.type;
6194 }
6195 return;
6196 }
6197
6198 VarDeclaration v = e.var.isVarDeclaration();
6199 if (!v)
6200 {
6201 e.error("CTFE internal error: `%s`", e.toChars());
6202 result = CTFEExp.cantexp;
6203 return;
6204 }
6205
6206 if (ex.op == EXP.null_)
6207 {
6208 if (ex.type.toBasetype().ty == Tclass)
6209 e.error("class `%s` is `null` and cannot be dereferenced", e.e1.toChars());
6210 else
6211 e.error("CTFE internal error: null this `%s`", e.e1.toChars());
6212 result = CTFEExp.cantexp;
6213 return;
6214 }
6215
6216 StructLiteralExp se;
6217 int i;
6218
6219 if (ex.op != EXP.structLiteral && ex.op != EXP.classReference && ex.op != EXP.typeid_)
6220 {
6221 return notImplementedYet();
6222 }
6223
6224 // We can't use getField, because it makes a copy
6225 if (ex.op == EXP.classReference)
6226 {
6227 se = ex.isClassReferenceExp().value;
6228 i = ex.isClassReferenceExp().findFieldIndexByName(v);
6229 }
6230 else if (ex.op == EXP.typeid_)
6231 {
6232 if (v.ident == Identifier.idPool("name"))
6233 {
6234 if (auto t = isType(ex.isTypeidExp().obj))
6235 {
6236 auto sym = t.toDsymbol(null);
6237 if (auto ident = (sym ? sym.ident : null))
6238 {
6239 result = new StringExp(e.loc, ident.toString());
6240 result.expressionSemantic(null);
6241 return ;
6242 }
6243 }
6244 }
6245 return notImplementedYet();
6246 }
6247 else
6248 {
6249 se = ex.isStructLiteralExp();
6250 i = findFieldIndexByName(se.sd, v);
6251 }
6252 if (i == -1)
6253 {
6254 e.error("couldn't find field `%s` of type `%s` in `%s`", v.toChars(), e.type.toChars(), se.toChars());
6255 result = CTFEExp.cantexp;
6256 return;
6257 }
6258
6259 // https://issues.dlang.org/show_bug.cgi?id=19897
6260 // https://issues.dlang.org/show_bug.cgi?id=20710
6261 // Zero-elements fields don't have an initializer. See: scrubArray function
6262 if ((*se.elements)[i] is null)
6263 (*se.elements)[i] = voidInitLiteral(e.type, v).copy();
6264
6265 if (goal == CTFEGoal.LValue)
6266 {
6267 // just return the (simplified) dotvar expression as a CTFE reference
6268 if (e.e1 == ex)
6269 result = e;
6270 else
6271 {
6272 emplaceExp!(DotVarExp)(pue, e.loc, ex, v);
6273 result = pue.exp();
6274 result.type = e.type;
6275 }
6276 return;
6277 }
6278
6279 result = (*se.elements)[i];
6280 if (!result)
6281 {
6282 e.error("Internal Compiler Error: null field `%s`", v.toChars());
6283 result = CTFEExp.cantexp;
6284 return;
6285 }
6286 if (auto vie = result.isVoidInitExp())
6287 {
6288 const s = vie.var.toChars();
6289 if (v.overlapped)
6290 {
6291 e.error("reinterpretation through overlapped field `%s` is not allowed in CTFE", s);
6292 result = CTFEExp.cantexp;
6293 return;
6294 }
6295 e.error("cannot read uninitialized variable `%s` in CTFE", s);
6296 result = CTFEExp.cantexp;
6297 return;
6298 }
6299
6300 if (v.type.ty != result.type.ty && v.type.ty == Tsarray)
6301 {
6302 // Block assignment from inside struct literals
6303 auto tsa = cast(TypeSArray)v.type;
6304 auto len = cast(size_t)tsa.dim.toInteger();
6305 UnionExp ue = void;
6306 result = createBlockDuplicatedArrayLiteral(&ue, e.loc, v.type, result, len);
6307 if (result == ue.exp())
6308 result = ue.copy();
6309 (*se.elements)[i] = result;
6310 }
6311 debug (LOG)
6312 {
6313 if (CTFEExp.isCantExp(result))
6314 printf("DotVarExp::interpret() %s = CTFEExp::cantexp\n", e.toChars());
6315 }
6316 }
6317
visit(RemoveExp e)6318 override void visit(RemoveExp e)
6319 {
6320 debug (LOG)
6321 {
6322 printf("%s RemoveExp::interpret() %s\n", e.loc.toChars(), e.toChars());
6323 }
6324 Expression agg = interpret(e.e1, istate);
6325 if (exceptionOrCant(agg))
6326 return;
6327 Expression index = interpret(e.e2, istate);
6328 if (exceptionOrCant(index))
6329 return;
6330 if (agg.op == EXP.null_)
6331 {
6332 result = CTFEExp.voidexp;
6333 return;
6334 }
6335
6336 AssocArrayLiteralExp aae = agg.isAssocArrayLiteralExp();
6337 Expressions* keysx = aae.keys;
6338 Expressions* valuesx = aae.values;
6339 size_t removed = 0;
6340 foreach (j, evalue; *valuesx)
6341 {
6342 Expression ekey = (*keysx)[j];
6343 int eq = ctfeEqual(e.loc, EXP.equal, ekey, index);
6344 if (eq)
6345 ++removed;
6346 else if (removed != 0)
6347 {
6348 (*keysx)[j - removed] = ekey;
6349 (*valuesx)[j - removed] = evalue;
6350 }
6351 }
6352 valuesx.dim = valuesx.dim - removed;
6353 keysx.dim = keysx.dim - removed;
6354 result = IntegerExp.createBool(removed != 0);
6355 }
6356
visit(ClassReferenceExp e)6357 override void visit(ClassReferenceExp e)
6358 {
6359 //printf("ClassReferenceExp::interpret() %s\n", e.value.toChars());
6360 result = e;
6361 }
6362
visit(VoidInitExp e)6363 override void visit(VoidInitExp e)
6364 {
6365 e.error("CTFE internal error: trying to read uninitialized variable");
6366 assert(0);
6367 }
6368
visit(ThrownExceptionExp e)6369 override void visit(ThrownExceptionExp e)
6370 {
6371 assert(0); // This should never be interpreted
6372 }
6373 }
6374
6375 /********************************************
6376 * Interpret the expression.
6377 * Params:
6378 * pue = non-null pointer to temporary storage that can be used to store the return value
6379 * e = Expression to interpret
6380 * istate = context
6381 * goal = what the result will be used for
6382 * Returns:
6383 * resulting expression
6384 */
6385
6386 Expression interpret(UnionExp* pue, Expression e, InterState* istate, CTFEGoal goal = CTFEGoal.RValue)
6387 {
6388 if (!e)
6389 return null;
6390 scope Interpreter v = new Interpreter(pue, istate, goal);
6391 e.accept(v);
6392 Expression ex = v.result;
6393 assert(goal == CTFEGoal.Nothing || ex !is null);
6394 return ex;
6395 }
6396
6397 ///
6398 Expression interpret(Expression e, InterState* istate, CTFEGoal goal = CTFEGoal.RValue)
6399 {
6400 UnionExp ue = void;
6401 auto result = interpret(&ue, e, istate, goal);
6402 if (result == ue.exp())
6403 result = ue.copy();
6404 return result;
6405 }
6406
6407 /*****************************
6408 * Same as interpret(), but return result allocated in Region.
6409 * Params:
6410 * e = Expression to interpret
6411 * istate = context
6412 * goal = what the result will be used for
6413 * Returns:
6414 * resulting expression
6415 */
6416 Expression interpretRegion(Expression e, InterState* istate, CTFEGoal goal = CTFEGoal.RValue)
6417 {
6418 UnionExp ue = void;
6419 auto result = interpret(&ue, e, istate, goal);
6420 auto uexp = ue.exp();
6421 if (result != uexp)
6422 return result;
6423 if (mem.isGCEnabled)
6424 return ue.copy();
6425
6426 // mimicking UnionExp.copy, but with region allocation
6427 switch (uexp.op)
6428 {
6429 case EXP.cantExpression: return CTFEExp.cantexp;
6430 case EXP.voidExpression: return CTFEExp.voidexp;
6431 case EXP.break_: return CTFEExp.breakexp;
6432 case EXP.continue_: return CTFEExp.continueexp;
6433 case EXP.goto_: return CTFEExp.gotoexp;
6434 default: break;
6435 }
6436 auto p = ctfeGlobals.region.malloc(uexp.size);
6437 return cast(Expression)memcpy(p, cast(void*)uexp, uexp.size);
6438 }
6439
6440 /***********************************
6441 * Interpret the statement.
6442 * Params:
6443 * pue = non-null pointer to temporary storage that can be used to store the return value
6444 * s = Statement to interpret
6445 * istate = context
6446 * Returns:
6447 * NULL continue to next statement
6448 * EXP.cantExpression cannot interpret statement at compile time
6449 * !NULL expression from return statement, or thrown exception
6450 */
interpret(UnionExp * pue,Statement s,InterState * istate)6451 Expression interpret(UnionExp* pue, Statement s, InterState* istate)
6452 {
6453 if (!s)
6454 return null;
6455 scope Interpreter v = new Interpreter(pue, istate, CTFEGoal.Nothing);
6456 s.accept(v);
6457 return v.result;
6458 }
6459
6460 ///
interpret(Statement s,InterState * istate)6461 Expression interpret(Statement s, InterState* istate)
6462 {
6463 UnionExp ue = void;
6464 auto result = interpret(&ue, s, istate);
6465 if (result == ue.exp())
6466 result = ue.copy();
6467 return result;
6468 }
6469
6470 /**
6471 * All results destined for use outside of CTFE need to have their CTFE-specific
6472 * features removed.
6473 * In particular,
6474 * 1. all slices must be resolved.
6475 * 2. all .ownedByCtfe set to OwnedBy.code
6476 */
scrubReturnValue(const ref Loc loc,Expression e)6477 private Expression scrubReturnValue(const ref Loc loc, Expression e)
6478 {
6479 /* Returns: true if e is void,
6480 * or is an array literal or struct literal of void elements.
6481 */
6482 static bool isVoid(const Expression e, bool checkArrayType = false) pure
6483 {
6484 if (e.op == EXP.void_)
6485 return true;
6486
6487 static bool isEntirelyVoid(const Expressions* elems)
6488 {
6489 foreach (e; *elems)
6490 {
6491 // It can be NULL for performance reasons,
6492 // see StructLiteralExp::interpret().
6493 if (e && !isVoid(e))
6494 return false;
6495 }
6496 return true;
6497 }
6498
6499 if (auto sle = e.isStructLiteralExp())
6500 return isEntirelyVoid(sle.elements);
6501
6502 if (checkArrayType && e.type.ty != Tsarray)
6503 return false;
6504
6505 if (auto ale = e.isArrayLiteralExp())
6506 return isEntirelyVoid(ale.elements);
6507
6508 return false;
6509 }
6510
6511
6512 /* Scrub all elements of elems[].
6513 * Returns: null for success, error Expression for failure
6514 */
6515 Expression scrubArray(Expressions* elems, bool structlit = false)
6516 {
6517 foreach (ref e; *elems)
6518 {
6519 // It can be NULL for performance reasons,
6520 // see StructLiteralExp::interpret().
6521 if (!e)
6522 continue;
6523
6524 // A struct .init may contain void members.
6525 // Static array members are a weird special case https://issues.dlang.org/show_bug.cgi?id=10994
6526 if (structlit && isVoid(e, true))
6527 {
6528 e = null;
6529 }
6530 else
6531 {
6532 e = scrubReturnValue(loc, e);
6533 if (CTFEExp.isCantExp(e) || e.op == EXP.error)
6534 return e;
6535 }
6536 }
6537 return null;
6538 }
6539
6540 Expression scrubSE(StructLiteralExp sle)
6541 {
6542 sle.ownedByCtfe = OwnedBy.code;
6543 if (!(sle.stageflags & stageScrub))
6544 {
6545 const old = sle.stageflags;
6546 sle.stageflags |= stageScrub; // prevent infinite recursion
6547 if (auto ex = scrubArray(sle.elements, true))
6548 return ex;
6549 sle.stageflags = old;
6550 }
6551 return null;
6552 }
6553
6554 if (e.op == EXP.classReference)
6555 {
6556 StructLiteralExp sle = e.isClassReferenceExp().value;
6557 if (auto ex = scrubSE(sle))
6558 return ex;
6559 }
6560 else if (auto vie = e.isVoidInitExp())
6561 {
6562 error(loc, "uninitialized variable `%s` cannot be returned from CTFE", vie.var.toChars());
6563 return ErrorExp.get();
6564 }
6565
6566 e = resolveSlice(e);
6567
6568 if (auto sle = e.isStructLiteralExp())
6569 {
6570 if (auto ex = scrubSE(sle))
6571 return ex;
6572 }
6573 else if (auto se = e.isStringExp())
6574 {
6575 se.ownedByCtfe = OwnedBy.code;
6576 }
6577 else if (auto ale = e.isArrayLiteralExp())
6578 {
6579 ale.ownedByCtfe = OwnedBy.code;
6580 if (auto ex = scrubArray(ale.elements))
6581 return ex;
6582 }
6583 else if (auto aae = e.isAssocArrayLiteralExp())
6584 {
6585 aae.ownedByCtfe = OwnedBy.code;
6586 if (auto ex = scrubArray(aae.keys))
6587 return ex;
6588 if (auto ex = scrubArray(aae.values))
6589 return ex;
6590 aae.type = toBuiltinAAType(aae.type);
6591 }
6592 else if (auto ve = e.isVectorExp())
6593 {
6594 ve.ownedByCtfe = OwnedBy.code;
6595 if (auto ale = ve.e1.isArrayLiteralExp())
6596 {
6597 ale.ownedByCtfe = OwnedBy.code;
6598 if (auto ex = scrubArray(ale.elements))
6599 return ex;
6600 }
6601 }
6602 return e;
6603 }
6604
6605 /**************************************
6606 * Transitively set all .ownedByCtfe to OwnedBy.cache
6607 */
scrubCacheValue(Expression e)6608 private Expression scrubCacheValue(Expression e)
6609 {
6610 if (!e)
6611 return e;
6612
6613 Expression scrubArrayCache(Expressions* elems)
6614 {
6615 foreach (ref e; *elems)
6616 e = scrubCacheValue(e);
6617 return null;
6618 }
6619
6620 Expression scrubSE(StructLiteralExp sle)
6621 {
6622 sle.ownedByCtfe = OwnedBy.cache;
6623 if (!(sle.stageflags & stageScrub))
6624 {
6625 const old = sle.stageflags;
6626 sle.stageflags |= stageScrub; // prevent infinite recursion
6627 if (auto ex = scrubArrayCache(sle.elements))
6628 return ex;
6629 sle.stageflags = old;
6630 }
6631 return null;
6632 }
6633
6634 if (e.op == EXP.classReference)
6635 {
6636 if (auto ex = scrubSE(e.isClassReferenceExp().value))
6637 return ex;
6638 }
6639 else if (auto sle = e.isStructLiteralExp())
6640 {
6641 if (auto ex = scrubSE(sle))
6642 return ex;
6643 }
6644 else if (auto se = e.isStringExp())
6645 {
6646 se.ownedByCtfe = OwnedBy.cache;
6647 }
6648 else if (auto ale = e.isArrayLiteralExp())
6649 {
6650 ale.ownedByCtfe = OwnedBy.cache;
6651 if (Expression ex = scrubArrayCache(ale.elements))
6652 return ex;
6653 }
6654 else if (auto aae = e.isAssocArrayLiteralExp())
6655 {
6656 aae.ownedByCtfe = OwnedBy.cache;
6657 if (auto ex = scrubArrayCache(aae.keys))
6658 return ex;
6659 if (auto ex = scrubArrayCache(aae.values))
6660 return ex;
6661 }
6662 else if (auto ve = e.isVectorExp())
6663 {
6664 ve.ownedByCtfe = OwnedBy.cache;
6665 if (auto ale = ve.e1.isArrayLiteralExp())
6666 {
6667 ale.ownedByCtfe = OwnedBy.cache;
6668 if (auto ex = scrubArrayCache(ale.elements))
6669 return ex;
6670 }
6671 }
6672 return e;
6673 }
6674
6675 /********************************************
6676 * Transitively replace all Expressions allocated in ctfeGlobals.region
6677 * with Mem owned copies.
6678 * Params:
6679 * e = possible ctfeGlobals.region owned expression
6680 * Returns:
6681 * Mem owned expression
6682 */
copyRegionExp(Expression e)6683 private Expression copyRegionExp(Expression e)
6684 {
6685 if (!e)
6686 return e;
6687
6688 static void copyArray(Expressions* elems)
6689 {
6690 foreach (ref e; *elems)
6691 {
6692 auto ex = e;
6693 e = null;
6694 e = copyRegionExp(ex);
6695 }
6696 }
6697
6698 static void copySE(StructLiteralExp sle)
6699 {
6700 if (1 || !(sle.stageflags & stageScrub))
6701 {
6702 const old = sle.stageflags;
6703 sle.stageflags |= stageScrub; // prevent infinite recursion
6704 copyArray(sle.elements);
6705 sle.stageflags = old;
6706 }
6707 }
6708
6709 switch (e.op)
6710 {
6711 case EXP.classReference:
6712 {
6713 auto cre = e.isClassReferenceExp();
6714 cre.value = copyRegionExp(cre.value).isStructLiteralExp();
6715 break;
6716 }
6717
6718 case EXP.structLiteral:
6719 {
6720 auto sle = e.isStructLiteralExp();
6721
6722 /* The following is to take care of updating sle.origin correctly,
6723 * which may have multiple objects pointing to it.
6724 */
6725 if (sle.isOriginal && !ctfeGlobals.region.contains(cast(void*)sle.origin))
6726 {
6727 /* This means sle has already been moved out of the region,
6728 * and sle.origin is the new location.
6729 */
6730 return sle.origin;
6731 }
6732 copySE(sle);
6733 sle.isOriginal = sle is sle.origin;
6734
6735 auto slec = ctfeGlobals.region.contains(cast(void*)e)
6736 ? e.copy().isStructLiteralExp() // move sle out of region to slec
6737 : sle;
6738
6739 if (ctfeGlobals.region.contains(cast(void*)sle.origin))
6740 {
6741 auto sleo = sle.origin == sle ? slec : sle.origin.copy().isStructLiteralExp();
6742 sle.origin = sleo;
6743 slec.origin = sleo;
6744 }
6745 return slec;
6746 }
6747
6748 case EXP.arrayLiteral:
6749 {
6750 auto ale = e.isArrayLiteralExp();
6751 ale.basis = copyRegionExp(ale.basis);
6752 copyArray(ale.elements);
6753 break;
6754 }
6755
6756 case EXP.assocArrayLiteral:
6757 copyArray(e.isAssocArrayLiteralExp().keys);
6758 copyArray(e.isAssocArrayLiteralExp().values);
6759 break;
6760
6761 case EXP.slice:
6762 {
6763 auto se = e.isSliceExp();
6764 se.e1 = copyRegionExp(se.e1);
6765 se.upr = copyRegionExp(se.upr);
6766 se.lwr = copyRegionExp(se.lwr);
6767 break;
6768 }
6769
6770 case EXP.tuple:
6771 {
6772 auto te = e.isTupleExp();
6773 te.e0 = copyRegionExp(te.e0);
6774 copyArray(te.exps);
6775 break;
6776 }
6777
6778 case EXP.address:
6779 case EXP.delegate_:
6780 case EXP.vector:
6781 case EXP.dotVariable:
6782 {
6783 UnaExp ue = e.isUnaExp();
6784 ue.e1 = copyRegionExp(ue.e1);
6785 break;
6786 }
6787
6788 case EXP.index:
6789 {
6790 BinExp be = e.isBinExp();
6791 be.e1 = copyRegionExp(be.e1);
6792 be.e2 = copyRegionExp(be.e2);
6793 break;
6794 }
6795
6796 case EXP.this_:
6797 case EXP.super_:
6798 case EXP.variable:
6799 case EXP.type:
6800 case EXP.function_:
6801 case EXP.typeid_:
6802 case EXP.string_:
6803 case EXP.int64:
6804 case EXP.error:
6805 case EXP.float64:
6806 case EXP.complex80:
6807 case EXP.null_:
6808 case EXP.void_:
6809 case EXP.symbolOffset:
6810 case EXP.char_:
6811 break;
6812
6813 case EXP.cantExpression:
6814 case EXP.voidExpression:
6815 case EXP.showCtfeContext:
6816 return e;
6817
6818 default:
6819 printf("e: %s, %s\n", EXPtoString(e.op).ptr, e.toChars());
6820 assert(0);
6821 }
6822
6823 if (ctfeGlobals.region.contains(cast(void*)e))
6824 {
6825 return e.copy();
6826 }
6827 return e;
6828 }
6829
6830 /******************************* Special Functions ***************************/
6831
interpret_length(UnionExp * pue,InterState * istate,Expression earg)6832 private Expression interpret_length(UnionExp* pue, InterState* istate, Expression earg)
6833 {
6834 //printf("interpret_length()\n");
6835 earg = interpret(pue, earg, istate);
6836 if (exceptionOrCantInterpret(earg))
6837 return earg;
6838 dinteger_t len = 0;
6839 if (auto aae = earg.isAssocArrayLiteralExp())
6840 len = aae.keys.dim;
6841 else
6842 assert(earg.op == EXP.null_);
6843 emplaceExp!(IntegerExp)(pue, earg.loc, len, Type.tsize_t);
6844 return pue.exp();
6845 }
6846
interpret_keys(UnionExp * pue,InterState * istate,Expression earg,Type returnType)6847 private Expression interpret_keys(UnionExp* pue, InterState* istate, Expression earg, Type returnType)
6848 {
6849 debug (LOG)
6850 {
6851 printf("interpret_keys()\n");
6852 }
6853 earg = interpret(pue, earg, istate);
6854 if (exceptionOrCantInterpret(earg))
6855 return earg;
6856 if (earg.op == EXP.null_)
6857 {
6858 emplaceExp!(NullExp)(pue, earg.loc, earg.type);
6859 return pue.exp();
6860 }
6861 if (earg.op != EXP.assocArrayLiteral && earg.type.toBasetype().ty != Taarray)
6862 return null;
6863 AssocArrayLiteralExp aae = earg.isAssocArrayLiteralExp();
6864 auto ae = ctfeEmplaceExp!ArrayLiteralExp(aae.loc, returnType, aae.keys);
6865 ae.ownedByCtfe = aae.ownedByCtfe;
6866 *pue = copyLiteral(ae);
6867 return pue.exp();
6868 }
6869
interpret_values(UnionExp * pue,InterState * istate,Expression earg,Type returnType)6870 private Expression interpret_values(UnionExp* pue, InterState* istate, Expression earg, Type returnType)
6871 {
6872 debug (LOG)
6873 {
6874 printf("interpret_values()\n");
6875 }
6876 earg = interpret(pue, earg, istate);
6877 if (exceptionOrCantInterpret(earg))
6878 return earg;
6879 if (earg.op == EXP.null_)
6880 {
6881 emplaceExp!(NullExp)(pue, earg.loc, earg.type);
6882 return pue.exp();
6883 }
6884 if (earg.op != EXP.assocArrayLiteral && earg.type.toBasetype().ty != Taarray)
6885 return null;
6886 auto aae = earg.isAssocArrayLiteralExp();
6887 auto ae = ctfeEmplaceExp!ArrayLiteralExp(aae.loc, returnType, aae.values);
6888 ae.ownedByCtfe = aae.ownedByCtfe;
6889 //printf("result is %s\n", e.toChars());
6890 *pue = copyLiteral(ae);
6891 return pue.exp();
6892 }
6893
interpret_dup(UnionExp * pue,InterState * istate,Expression earg)6894 private Expression interpret_dup(UnionExp* pue, InterState* istate, Expression earg)
6895 {
6896 debug (LOG)
6897 {
6898 printf("interpret_dup()\n");
6899 }
6900 earg = interpret(pue, earg, istate);
6901 if (exceptionOrCantInterpret(earg))
6902 return earg;
6903 if (earg.op == EXP.null_)
6904 {
6905 emplaceExp!(NullExp)(pue, earg.loc, earg.type);
6906 return pue.exp();
6907 }
6908 if (earg.op != EXP.assocArrayLiteral && earg.type.toBasetype().ty != Taarray)
6909 return null;
6910 auto aae = copyLiteral(earg).copy().isAssocArrayLiteralExp();
6911 for (size_t i = 0; i < aae.keys.dim; i++)
6912 {
6913 if (Expression e = evaluatePostblit(istate, (*aae.keys)[i]))
6914 return e;
6915 if (Expression e = evaluatePostblit(istate, (*aae.values)[i]))
6916 return e;
6917 }
6918 aae.type = earg.type.mutableOf(); // repaint type from const(int[int]) to const(int)[int]
6919 //printf("result is %s\n", aae.toChars());
6920 return aae;
6921 }
6922
6923 // signature is int delegate(ref Value) OR int delegate(ref Key, ref Value)
interpret_aaApply(UnionExp * pue,InterState * istate,Expression aa,Expression deleg)6924 private Expression interpret_aaApply(UnionExp* pue, InterState* istate, Expression aa, Expression deleg)
6925 {
6926 aa = interpret(aa, istate);
6927 if (exceptionOrCantInterpret(aa))
6928 return aa;
6929 if (aa.op != EXP.assocArrayLiteral)
6930 {
6931 emplaceExp!(IntegerExp)(pue, deleg.loc, 0, Type.tsize_t);
6932 return pue.exp();
6933 }
6934
6935 FuncDeclaration fd = null;
6936 Expression pthis = null;
6937 if (auto de = deleg.isDelegateExp())
6938 {
6939 fd = de.func;
6940 pthis = de.e1;
6941 }
6942 else if (auto fe = deleg.isFuncExp())
6943 fd = fe.fd;
6944
6945 assert(fd && fd.fbody);
6946 assert(fd.parameters);
6947 size_t numParams = fd.parameters.dim;
6948 assert(numParams == 1 || numParams == 2);
6949
6950 Parameter fparam = fd.type.isTypeFunction().parameterList[numParams - 1];
6951 const wantRefValue = fparam.isReference();
6952
6953 Expressions args = Expressions(numParams);
6954
6955 AssocArrayLiteralExp ae = aa.isAssocArrayLiteralExp();
6956 if (!ae.keys || ae.keys.dim == 0)
6957 return ctfeEmplaceExp!IntegerExp(deleg.loc, 0, Type.tsize_t);
6958 Expression eresult;
6959
6960 for (size_t i = 0; i < ae.keys.dim; ++i)
6961 {
6962 Expression ekey = (*ae.keys)[i];
6963 Expression evalue = (*ae.values)[i];
6964 if (wantRefValue)
6965 {
6966 Type t = evalue.type;
6967 evalue = ctfeEmplaceExp!IndexExp(deleg.loc, ae, ekey);
6968 evalue.type = t;
6969 }
6970 args[numParams - 1] = evalue;
6971 if (numParams == 2)
6972 args[0] = ekey;
6973
6974 UnionExp ue = void;
6975 eresult = interpretFunction(&ue, fd, istate, &args, pthis);
6976 if (eresult == ue.exp())
6977 eresult = ue.copy();
6978 if (exceptionOrCantInterpret(eresult))
6979 return eresult;
6980
6981 if (eresult.isIntegerExp().getInteger() != 0)
6982 return eresult;
6983 }
6984 return eresult;
6985 }
6986
6987 /* Decoding UTF strings for foreach loops. Duplicates the functionality of
6988 * the twelve _aApplyXXn functions in aApply.d in the runtime.
6989 */
foreachApplyUtf(UnionExp * pue,InterState * istate,Expression str,Expression deleg,bool rvs)6990 private Expression foreachApplyUtf(UnionExp* pue, InterState* istate, Expression str, Expression deleg, bool rvs)
6991 {
6992 debug (LOG)
6993 {
6994 printf("foreachApplyUtf(%s, %s)\n", str.toChars(), deleg.toChars());
6995 }
6996 FuncDeclaration fd = null;
6997 Expression pthis = null;
6998 if (auto de = deleg.isDelegateExp())
6999 {
7000 fd = de.func;
7001 pthis = de.e1;
7002 }
7003 else if (auto fe = deleg.isFuncExp())
7004 fd = fe.fd;
7005
7006 assert(fd && fd.fbody);
7007 assert(fd.parameters);
7008 size_t numParams = fd.parameters.dim;
7009 assert(numParams == 1 || numParams == 2);
7010 Type charType = (*fd.parameters)[numParams - 1].type;
7011 Type indexType = numParams == 2 ? (*fd.parameters)[0].type : Type.tsize_t;
7012 size_t len = cast(size_t)resolveArrayLength(str);
7013 if (len == 0)
7014 {
7015 emplaceExp!(IntegerExp)(pue, deleg.loc, 0, indexType);
7016 return pue.exp();
7017 }
7018
7019 UnionExp strTmp = void;
7020 str = resolveSlice(str, &strTmp);
7021
7022 auto se = str.isStringExp();
7023 auto ale = str.isArrayLiteralExp();
7024 if (!se && !ale)
7025 {
7026 str.error("CTFE internal error: cannot foreach `%s`", str.toChars());
7027 return CTFEExp.cantexp;
7028 }
7029 Expressions args = Expressions(numParams);
7030
7031 Expression eresult = null; // ded-store to prevent spurious warning
7032
7033 // Buffers for encoding; also used for decoding array literals
7034 char[4] utf8buf = void;
7035 wchar[2] utf16buf = void;
7036
7037 size_t start = rvs ? len : 0;
7038 size_t end = rvs ? 0 : len;
7039 for (size_t indx = start; indx != end;)
7040 {
7041 // Step 1: Decode the next dchar from the string.
7042
7043 string errmsg = null; // Used for reporting decoding errors
7044 dchar rawvalue; // Holds the decoded dchar
7045 size_t currentIndex = indx; // The index of the decoded character
7046
7047 if (ale)
7048 {
7049 // If it is an array literal, copy the code points into the buffer
7050 size_t buflen = 1; // #code points in the buffer
7051 size_t n = 1; // #code points in this char
7052 size_t sz = cast(size_t)ale.type.nextOf().size();
7053
7054 switch (sz)
7055 {
7056 case 1:
7057 if (rvs)
7058 {
7059 // find the start of the string
7060 --indx;
7061 buflen = 1;
7062 while (indx > 0 && buflen < 4)
7063 {
7064 Expression r = (*ale.elements)[indx];
7065 char x = cast(char)r.isIntegerExp().getInteger();
7066 if ((x & 0xC0) != 0x80)
7067 break;
7068 --indx;
7069 ++buflen;
7070 }
7071 }
7072 else
7073 buflen = (indx + 4 > len) ? len - indx : 4;
7074 for (size_t i = 0; i < buflen; ++i)
7075 {
7076 Expression r = (*ale.elements)[indx + i];
7077 utf8buf[i] = cast(char)r.isIntegerExp().getInteger();
7078 }
7079 n = 0;
7080 errmsg = utf_decodeChar(utf8buf[0 .. buflen], n, rawvalue);
7081 break;
7082
7083 case 2:
7084 if (rvs)
7085 {
7086 // find the start of the string
7087 --indx;
7088 buflen = 1;
7089 Expression r = (*ale.elements)[indx];
7090 ushort x = cast(ushort)r.isIntegerExp().getInteger();
7091 if (indx > 0 && x >= 0xDC00 && x <= 0xDFFF)
7092 {
7093 --indx;
7094 ++buflen;
7095 }
7096 }
7097 else
7098 buflen = (indx + 2 > len) ? len - indx : 2;
7099 for (size_t i = 0; i < buflen; ++i)
7100 {
7101 Expression r = (*ale.elements)[indx + i];
7102 utf16buf[i] = cast(ushort)r.isIntegerExp().getInteger();
7103 }
7104 n = 0;
7105 errmsg = utf_decodeWchar(utf16buf[0 .. buflen], n, rawvalue);
7106 break;
7107
7108 case 4:
7109 {
7110 if (rvs)
7111 --indx;
7112 Expression r = (*ale.elements)[indx];
7113 rawvalue = cast(dchar)r.isIntegerExp().getInteger();
7114 n = 1;
7115 }
7116 break;
7117
7118 default:
7119 assert(0);
7120 }
7121 if (!rvs)
7122 indx += n;
7123 }
7124 else
7125 {
7126 // String literals
7127 size_t saveindx; // used for reverse iteration
7128
7129 switch (se.sz)
7130 {
7131 case 1:
7132 {
7133 if (rvs)
7134 {
7135 // find the start of the string
7136 --indx;
7137 while (indx > 0 && ((se.getCodeUnit(indx) & 0xC0) == 0x80))
7138 --indx;
7139 saveindx = indx;
7140 }
7141 auto slice = se.peekString();
7142 errmsg = utf_decodeChar(slice, indx, rawvalue);
7143 if (rvs)
7144 indx = saveindx;
7145 break;
7146 }
7147
7148 case 2:
7149 if (rvs)
7150 {
7151 // find the start
7152 --indx;
7153 auto wc = se.getCodeUnit(indx);
7154 if (wc >= 0xDC00 && wc <= 0xDFFF)
7155 --indx;
7156 saveindx = indx;
7157 }
7158 const slice = se.peekWstring();
7159 errmsg = utf_decodeWchar(slice, indx, rawvalue);
7160 if (rvs)
7161 indx = saveindx;
7162 break;
7163
7164 case 4:
7165 if (rvs)
7166 --indx;
7167 rawvalue = se.getCodeUnit(indx);
7168 if (!rvs)
7169 ++indx;
7170 break;
7171
7172 default:
7173 assert(0);
7174 }
7175 }
7176 if (errmsg)
7177 {
7178 deleg.error("`%.*s`", cast(int)errmsg.length, errmsg.ptr);
7179 return CTFEExp.cantexp;
7180 }
7181
7182 // Step 2: encode the dchar in the target encoding
7183
7184 int charlen = 1; // How many codepoints are involved?
7185 switch (charType.size())
7186 {
7187 case 1:
7188 charlen = utf_codeLengthChar(rawvalue);
7189 utf_encodeChar(&utf8buf[0], rawvalue);
7190 break;
7191 case 2:
7192 charlen = utf_codeLengthWchar(rawvalue);
7193 utf_encodeWchar(&utf16buf[0], rawvalue);
7194 break;
7195 case 4:
7196 break;
7197 default:
7198 assert(0);
7199 }
7200 if (rvs)
7201 currentIndex = indx;
7202
7203 // Step 3: call the delegate once for each code point
7204
7205 // The index only needs to be set once
7206 if (numParams == 2)
7207 args[0] = ctfeEmplaceExp!IntegerExp(deleg.loc, currentIndex, indexType);
7208
7209 Expression val = null;
7210
7211 foreach (k; 0 .. charlen)
7212 {
7213 dchar codepoint;
7214 switch (charType.size())
7215 {
7216 case 1:
7217 codepoint = utf8buf[k];
7218 break;
7219 case 2:
7220 codepoint = utf16buf[k];
7221 break;
7222 case 4:
7223 codepoint = rawvalue;
7224 break;
7225 default:
7226 assert(0);
7227 }
7228 val = ctfeEmplaceExp!IntegerExp(str.loc, codepoint, charType);
7229
7230 args[numParams - 1] = val;
7231
7232 UnionExp ue = void;
7233 eresult = interpretFunction(&ue, fd, istate, &args, pthis);
7234 if (eresult == ue.exp())
7235 eresult = ue.copy();
7236 if (exceptionOrCantInterpret(eresult))
7237 return eresult;
7238 if (eresult.isIntegerExp().getInteger() != 0)
7239 return eresult;
7240 }
7241 }
7242 return eresult;
7243 }
7244
7245 /* If this is a built-in function, return the interpreted result,
7246 * Otherwise, return NULL.
7247 */
evaluateIfBuiltin(UnionExp * pue,InterState * istate,const ref Loc loc,FuncDeclaration fd,Expressions * arguments,Expression pthis)7248 private Expression evaluateIfBuiltin(UnionExp* pue, InterState* istate, const ref Loc loc, FuncDeclaration fd, Expressions* arguments, Expression pthis)
7249 {
7250 Expression e = null;
7251 size_t nargs = arguments ? arguments.dim : 0;
7252 if (!pthis)
7253 {
7254 if (isBuiltin(fd) != BUILTIN.unimp)
7255 {
7256 Expressions args = Expressions(nargs);
7257 foreach (i, ref arg; args)
7258 {
7259 Expression earg = (*arguments)[i];
7260 earg = interpret(earg, istate);
7261 if (exceptionOrCantInterpret(earg))
7262 return earg;
7263 arg = earg;
7264 }
7265 e = eval_builtin(loc, fd, &args);
7266 if (!e)
7267 {
7268 error(loc, "cannot evaluate unimplemented builtin `%s` at compile time", fd.toChars());
7269 e = CTFEExp.cantexp;
7270 }
7271 }
7272 }
7273 if (!pthis)
7274 {
7275 if (nargs == 1 || nargs == 3)
7276 {
7277 Expression firstarg = (*arguments)[0];
7278 if (auto firstAAtype = firstarg.type.toBasetype().isTypeAArray())
7279 {
7280 const id = fd.ident;
7281 if (nargs == 1)
7282 {
7283 if (id == Id.aaLen)
7284 return interpret_length(pue, istate, firstarg);
7285
7286 if (fd.toParent2().ident == Id.object)
7287 {
7288 if (id == Id.keys)
7289 return interpret_keys(pue, istate, firstarg, firstAAtype.index.arrayOf());
7290 if (id == Id.values)
7291 return interpret_values(pue, istate, firstarg, firstAAtype.nextOf().arrayOf());
7292 if (id == Id.rehash)
7293 return interpret(pue, firstarg, istate);
7294 if (id == Id.dup)
7295 return interpret_dup(pue, istate, firstarg);
7296 }
7297 }
7298 else // (nargs == 3)
7299 {
7300 if (id == Id._aaApply)
7301 return interpret_aaApply(pue, istate, firstarg, (*arguments)[2]);
7302 if (id == Id._aaApply2)
7303 return interpret_aaApply(pue, istate, firstarg, (*arguments)[2]);
7304 }
7305 }
7306 }
7307 }
7308 if (pthis && !fd.fbody && fd.isCtorDeclaration() && fd.parent && fd.parent.parent && fd.parent.parent.ident == Id.object)
7309 {
7310 if (pthis.op == EXP.classReference && fd.parent.ident == Id.Throwable)
7311 {
7312 // At present, the constructors just copy their arguments into the struct.
7313 // But we might need some magic if stack tracing gets added to druntime.
7314 StructLiteralExp se = pthis.isClassReferenceExp().value;
7315 assert(arguments.dim <= se.elements.dim);
7316 foreach (i, arg; *arguments)
7317 {
7318 auto elem = interpret(arg, istate);
7319 if (exceptionOrCantInterpret(elem))
7320 return elem;
7321 (*se.elements)[i] = elem;
7322 }
7323 return CTFEExp.voidexp;
7324 }
7325 }
7326 if (nargs == 1 && !pthis && (fd.ident == Id.criticalenter || fd.ident == Id.criticalexit))
7327 {
7328 // Support synchronized{} as a no-op
7329 return CTFEExp.voidexp;
7330 }
7331 if (!pthis)
7332 {
7333 const idlen = fd.ident.toString().length;
7334 const id = fd.ident.toChars();
7335 if (nargs == 2 && (idlen == 10 || idlen == 11) && !strncmp(id, "_aApply", 7))
7336 {
7337 // Functions from aApply.d and aApplyR.d in the runtime
7338 bool rvs = (idlen == 11); // true if foreach_reverse
7339 char c = id[idlen - 3]; // char width: 'c', 'w', or 'd'
7340 char s = id[idlen - 2]; // string width: 'c', 'w', or 'd'
7341 char n = id[idlen - 1]; // numParams: 1 or 2.
7342 // There are 12 combinations
7343 if ((n == '1' || n == '2') &&
7344 (c == 'c' || c == 'w' || c == 'd') &&
7345 (s == 'c' || s == 'w' || s == 'd') &&
7346 c != s)
7347 {
7348 Expression str = (*arguments)[0];
7349 str = interpret(str, istate);
7350 if (exceptionOrCantInterpret(str))
7351 return str;
7352 return foreachApplyUtf(pue, istate, str, (*arguments)[1], rvs);
7353 }
7354 }
7355 }
7356 return e;
7357 }
7358
evaluatePostblit(InterState * istate,Expression e)7359 private Expression evaluatePostblit(InterState* istate, Expression e)
7360 {
7361 auto ts = e.type.baseElemOf().isTypeStruct();
7362 if (!ts)
7363 return null;
7364 StructDeclaration sd = ts.sym;
7365 if (!sd.postblit)
7366 return null;
7367
7368 if (auto ale = e.isArrayLiteralExp())
7369 {
7370 foreach (elem; *ale.elements)
7371 {
7372 if (auto ex = evaluatePostblit(istate, elem))
7373 return ex;
7374 }
7375 return null;
7376 }
7377 if (e.op == EXP.structLiteral)
7378 {
7379 // e.__postblit()
7380 UnionExp ue = void;
7381 e = interpretFunction(&ue, sd.postblit, istate, null, e);
7382 if (e == ue.exp())
7383 e = ue.copy();
7384 if (exceptionOrCantInterpret(e))
7385 return e;
7386 return null;
7387 }
7388 assert(0);
7389 }
7390
evaluateDtor(InterState * istate,Expression e)7391 private Expression evaluateDtor(InterState* istate, Expression e)
7392 {
7393 auto ts = e.type.baseElemOf().isTypeStruct();
7394 if (!ts)
7395 return null;
7396 StructDeclaration sd = ts.sym;
7397 if (!sd.dtor)
7398 return null;
7399
7400 UnionExp ue = void;
7401 if (auto ale = e.isArrayLiteralExp())
7402 {
7403 foreach_reverse (elem; *ale.elements)
7404 e = evaluateDtor(istate, elem);
7405 }
7406 else if (e.op == EXP.structLiteral)
7407 {
7408 // e.__dtor()
7409 e = interpretFunction(&ue, sd.dtor, istate, null, e);
7410 }
7411 else
7412 assert(0);
7413 if (exceptionOrCantInterpret(e))
7414 {
7415 if (e == ue.exp())
7416 e = ue.copy();
7417 return e;
7418 }
7419 return null;
7420 }
7421
7422 /*************************** CTFE Sanity Checks ***************************/
7423 /* Setter functions for CTFE variable values.
7424 * These functions exist to check for compiler CTFE bugs.
7425 */
hasValue(VarDeclaration vd)7426 private bool hasValue(VarDeclaration vd)
7427 {
7428 return vd.ctfeAdrOnStack != VarDeclaration.AdrOnStackNone &&
7429 getValue(vd) !is null;
7430 }
7431
7432 // Don't check for validity
setValueWithoutChecking(VarDeclaration vd,Expression newval)7433 private void setValueWithoutChecking(VarDeclaration vd, Expression newval)
7434 {
7435 ctfeGlobals.stack.setValue(vd, newval);
7436 }
7437
setValue(VarDeclaration vd,Expression newval)7438 private void setValue(VarDeclaration vd, Expression newval)
7439 {
7440 //printf("setValue() vd: %s newval: %s\n", vd.toChars(), newval.toChars());
7441 version (none)
7442 {
7443 if (!((vd.storage_class & (STC.out_ | STC.ref_)) ? isCtfeReferenceValid(newval) : isCtfeValueValid(newval)))
7444 {
7445 printf("[%s] vd = %s %s, newval = %s\n", vd.loc.toChars(), vd.type.toChars(), vd.toChars(), newval.toChars());
7446 }
7447 }
7448 assert((vd.storage_class & (STC.out_ | STC.ref_)) ? isCtfeReferenceValid(newval) : isCtfeValueValid(newval));
7449 ctfeGlobals.stack.setValue(vd, newval);
7450 }
7451
7452 /**
7453 * Removes `_d_HookTraceImpl` if found from `ce` and `fd`.
7454 * This is needed for the CTFE interception code to be able to find hooks that are called though the hook's `*Trace`
7455 * wrapper.
7456 *
7457 * This is done by replacing `_d_HookTraceImpl!(T, Hook, errMsg)(..., parameters)` with `Hook(parameters)`.
7458 * Parameters:
7459 * ce = The CallExp that possible will be be replaced
7460 * fd = Fully resolve function declaration that `ce` would call
7461 */
removeHookTraceImpl(ref CallExp ce,ref FuncDeclaration fd)7462 private void removeHookTraceImpl(ref CallExp ce, ref FuncDeclaration fd)
7463 {
7464 if (fd.ident != Id._d_HookTraceImpl)
7465 return;
7466
7467 auto oldCE = ce;
7468
7469 // Get the Hook from the second template parameter
7470 TemplateInstance templateInstance = fd.parent.isTemplateInstance;
7471 RootObject hook = (*templateInstance.tiargs)[1];
7472 assert(hook.dyncast() == DYNCAST.dsymbol, "Expected _d_HookTraceImpl's second template parameter to be an alias to the hook!");
7473 fd = (cast(Dsymbol)hook).isFuncDeclaration;
7474
7475 // Remove the first three trace parameters
7476 auto arguments = new Expressions();
7477 arguments.reserve(ce.arguments.dim - 3);
7478 arguments.pushSlice((*ce.arguments)[3 .. $]);
7479
7480 ce = ctfeEmplaceExp!CallExp(ce.loc, ctfeEmplaceExp!VarExp(ce.loc, fd, false), arguments);
7481
7482 if (global.params.verbose)
7483 message("strip %s =>\n %s", oldCE.toChars(), ce.toChars());
7484 }
7485