]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/d/dmd/dinterpret.d
d: Merge upstream dmd 3982604c5, druntime bc58b1e9, phobos 12329adb6.
[thirdparty/gcc.git] / gcc / d / dmd / dinterpret.d
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-2021 by The D Language Foundation, All Rights Reserved
7 * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
8 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
9 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dinterpret.d, _dinterpret.d)
10 * Documentation: https://dlang.org/phobos/dmd_dinterpret.html
11 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/dinterpret.d
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.statement;
50 import dmd.tokens;
51 import dmd.utf;
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 */
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 result = copyRegionExp(result);
103
104 if (!CTFEExp.isCantExp(result))
105 result = scrubReturnValue(e.loc, result);
106 if (CTFEExp.isCantExp(result))
107 result = ErrorExp.get();
108
109 ctfeGlobals.region.release(rgnpos);
110
111 return result;
112 }
113
114 /* Run CTFE on the expression, but allow the expression to be a TypeExp
115 * or a tuple containing a TypeExp. (This is required by pragma(msg)).
116 */
117 public Expression ctfeInterpretForPragmaMsg(Expression e)
118 {
119 if (e.op == EXP.error || e.op == EXP.type)
120 return e;
121
122 // It's also OK for it to be a function declaration (happens only with
123 // __traits(getOverloads))
124 if (auto ve = e.isVarExp())
125 if (ve.var.isFuncDeclaration())
126 {
127 return e;
128 }
129
130 auto tup = e.isTupleExp();
131 if (!tup)
132 return e.ctfeInterpret();
133
134 // Tuples need to be treated separately, since they are
135 // allowed to contain a TypeExp in this case.
136
137 Expressions* expsx = null;
138 foreach (i, g; *tup.exps)
139 {
140 auto h = ctfeInterpretForPragmaMsg(g);
141 if (h != g)
142 {
143 if (!expsx)
144 {
145 expsx = tup.exps.copy();
146 }
147 (*expsx)[i] = h;
148 }
149 }
150 if (expsx)
151 {
152 auto te = new TupleExp(e.loc, expsx);
153 expandTuples(te.exps);
154 te.type = new TypeTuple(te.exps);
155 return te;
156 }
157 return e;
158 }
159
160 public extern (C++) Expression getValue(VarDeclaration vd)
161 {
162 return ctfeGlobals.stack.getValue(vd);
163 }
164
165 /*************************************************
166 * Allocate an Expression in the ctfe region.
167 * Params:
168 * T = type of Expression to allocate
169 * args = arguments to Expression's constructor
170 * Returns:
171 * allocated Expression
172 */
173 T ctfeEmplaceExp(T : Expression, Args...)(Args args)
174 {
175 if (mem.isGCEnabled)
176 return new T(args);
177 auto p = ctfeGlobals.region.malloc(__traits(classInstanceSize, T));
178 emplaceExp!T(p, args);
179 return cast(T)p;
180 }
181
182 // CTFE diagnostic information
183 public extern (C++) void printCtfePerformanceStats()
184 {
185 debug (SHOWPERFORMANCE)
186 {
187 printf(" ---- CTFE Performance ----\n");
188 printf("max call depth = %d\tmax stack = %d\n", ctfeGlobals.maxCallDepth, ctfeGlobals.stack.maxStackUsage());
189 printf("array allocs = %d\tassignments = %d\n\n", ctfeGlobals.numArrayAllocs, ctfeGlobals.numAssignments);
190 }
191 }
192
193 /**************************
194 */
195
196 void incArrayAllocs()
197 {
198 ++ctfeGlobals.numArrayAllocs;
199 }
200
201 /* ================================================ Implementation ======================================= */
202
203 private:
204
205 /***************
206 * Collect together globals used by CTFE
207 */
208 struct CtfeGlobals
209 {
210 Region region;
211
212 CtfeStack stack;
213
214 int callDepth = 0; // current number of recursive calls
215
216 // When printing a stack trace, suppress this number of calls
217 int stackTraceCallsToSuppress = 0;
218
219 int maxCallDepth = 0; // highest number of recursive calls
220 int numArrayAllocs = 0; // Number of allocated arrays
221 int numAssignments = 0; // total number of assignments executed
222 }
223
224 __gshared CtfeGlobals ctfeGlobals;
225
226 enum CTFEGoal : int
227 {
228 RValue, /// Must return an Rvalue (== CTFE value)
229 LValue, /// Must return an Lvalue (== CTFE reference)
230 Nothing, /// The return value is not required
231 }
232
233 //debug = LOG;
234 //debug = LOGASSIGN;
235 //debug = LOGCOMPILE;
236 //debug = SHOWPERFORMANCE;
237
238 // Maximum allowable recursive function calls in CTFE
239 enum CTFE_RECURSION_LIMIT = 1000;
240
241 /**
242 The values of all CTFE variables
243 */
244 struct CtfeStack
245 {
246 private:
247 /* The stack. Every declaration we encounter is pushed here,
248 * together with the VarDeclaration, and the previous
249 * stack address of that variable, so that we can restore it
250 * when we leave the stack frame.
251 * Note that when a function is forward referenced, the interpreter must
252 * run semantic3, and that may start CTFE again with a NULL istate. Thus
253 * the stack might not be empty when CTFE begins.
254 *
255 * Ctfe Stack addresses are just 0-based integers, but we save
256 * them as 'void *' because Array can only do pointers.
257 */
258 Expressions values; // values on the stack
259 VarDeclarations vars; // corresponding variables
260 Array!(void*) savedId; // id of the previous state of that var
261
262 Array!(void*) frames; // all previous frame pointers
263 Expressions savedThis; // all previous values of localThis
264
265 /* Global constants get saved here after evaluation, so we never
266 * have to redo them. This saves a lot of time and memory.
267 */
268 Expressions globalValues; // values of global constants
269
270 size_t framepointer; // current frame pointer
271 size_t maxStackPointer; // most stack we've ever used
272 Expression localThis; // value of 'this', or NULL if none
273
274 public:
275 extern (C++) size_t stackPointer()
276 {
277 return values.dim;
278 }
279
280 // The current value of 'this', or NULL if none
281 extern (C++) Expression getThis()
282 {
283 return localThis;
284 }
285
286 // Largest number of stack positions we've used
287 extern (C++) size_t maxStackUsage()
288 {
289 return maxStackPointer;
290 }
291
292 // Start a new stack frame, using the provided 'this'.
293 extern (C++) void startFrame(Expression thisexp)
294 {
295 frames.push(cast(void*)cast(size_t)framepointer);
296 savedThis.push(localThis);
297 framepointer = stackPointer();
298 localThis = thisexp;
299 }
300
301 extern (C++) void endFrame()
302 {
303 size_t oldframe = cast(size_t)frames[frames.dim - 1];
304 localThis = savedThis[savedThis.dim - 1];
305 popAll(framepointer);
306 framepointer = oldframe;
307 frames.setDim(frames.dim - 1);
308 savedThis.setDim(savedThis.dim - 1);
309 }
310
311 extern (C++) bool isInCurrentFrame(VarDeclaration v)
312 {
313 if (v.isDataseg() && !v.isCTFE())
314 return false; // It's a global
315 return v.ctfeAdrOnStack >= framepointer;
316 }
317
318 extern (C++) Expression getValue(VarDeclaration v)
319 {
320 //printf("getValue() %s\n", v.toChars());
321 if ((v.isDataseg() || v.storage_class & STC.manifest) && !v.isCTFE())
322 {
323 assert(v.ctfeAdrOnStack < globalValues.dim);
324 return globalValues[v.ctfeAdrOnStack];
325 }
326 assert(v.ctfeAdrOnStack < stackPointer());
327 return values[v.ctfeAdrOnStack];
328 }
329
330 extern (C++) void setValue(VarDeclaration v, Expression e)
331 {
332 //printf("setValue() %s : %s\n", v.toChars(), e.toChars());
333 assert(!v.isDataseg() || v.isCTFE());
334 assert(v.ctfeAdrOnStack < stackPointer());
335 values[v.ctfeAdrOnStack] = e;
336 }
337
338 extern (C++) void push(VarDeclaration v)
339 {
340 //printf("push() %s\n", v.toChars());
341 assert(!v.isDataseg() || v.isCTFE());
342 if (v.ctfeAdrOnStack != VarDeclaration.AdrOnStackNone && v.ctfeAdrOnStack >= framepointer)
343 {
344 // Already exists in this frame, reuse it.
345 values[v.ctfeAdrOnStack] = null;
346 return;
347 }
348 savedId.push(cast(void*)cast(size_t)v.ctfeAdrOnStack);
349 v.ctfeAdrOnStack = cast(uint)values.dim;
350 vars.push(v);
351 values.push(null);
352 }
353
354 extern (C++) void pop(VarDeclaration v)
355 {
356 assert(!v.isDataseg() || v.isCTFE());
357 assert(!v.isReference());
358 const oldid = v.ctfeAdrOnStack;
359 v.ctfeAdrOnStack = cast(uint)cast(size_t)savedId[oldid];
360 if (v.ctfeAdrOnStack == values.dim - 1)
361 {
362 values.pop();
363 vars.pop();
364 savedId.pop();
365 }
366 }
367
368 extern (C++) void popAll(size_t stackpointer)
369 {
370 if (stackPointer() > maxStackPointer)
371 maxStackPointer = stackPointer();
372 assert(values.dim >= stackpointer);
373 for (size_t i = stackpointer; i < values.dim; ++i)
374 {
375 VarDeclaration v = vars[i];
376 v.ctfeAdrOnStack = cast(uint)cast(size_t)savedId[i];
377 }
378 values.setDim(stackpointer);
379 vars.setDim(stackpointer);
380 savedId.setDim(stackpointer);
381 }
382
383 extern (C++) void saveGlobalConstant(VarDeclaration v, Expression e)
384 {
385 assert(v._init && (v.isConst() || v.isImmutable() || v.storage_class & STC.manifest) && !v.isCTFE());
386 v.ctfeAdrOnStack = cast(uint)globalValues.dim;
387 globalValues.push(copyRegionExp(e));
388 }
389 }
390
391 private struct InterState
392 {
393 InterState* caller; // calling function's InterState
394 FuncDeclaration fd; // function being interpreted
395 Statement start; // if !=NULL, start execution at this statement
396
397 /* target of CTFEExp result; also
398 * target of labelled CTFEExp or
399 * CTFEExp. (null if no label).
400 */
401 Statement gotoTarget;
402 }
403
404 /*************************************
405 * Attempt to interpret a function given the arguments.
406 * Params:
407 * pue = storage for result
408 * fd = function being called
409 * istate = state for calling function (NULL if none)
410 * arguments = function arguments
411 * thisarg = 'this', if a needThis() function, NULL if not.
412 *
413 * Returns:
414 * result expression if successful, EXP.cantExpression if not,
415 * or CTFEExp if function returned void.
416 */
417 private Expression interpretFunction(UnionExp* pue, FuncDeclaration fd, InterState* istate, Expressions* arguments, Expression thisarg)
418 {
419 debug (LOG)
420 {
421 printf("\n********\n%s FuncDeclaration::interpret(istate = %p) %s\n", fd.loc.toChars(), istate, fd.toChars());
422 }
423 assert(pue);
424 if (fd.semanticRun == PASS.semantic3)
425 {
426 fd.error("circular dependency. Functions cannot be interpreted while being compiled");
427 return CTFEExp.cantexp;
428 }
429 if (!fd.functionSemantic3())
430 return CTFEExp.cantexp;
431 if (fd.semanticRun < PASS.semantic3done)
432 {
433 fd.error("circular dependency. Functions cannot be interpreted while being compiled");
434 return CTFEExp.cantexp;
435 }
436
437 auto tf = fd.type.toBasetype().isTypeFunction();
438 if (tf.parameterList.varargs != VarArg.none && arguments &&
439 ((fd.parameters && arguments.dim != fd.parameters.dim) || (!fd.parameters && arguments.dim)))
440 {
441 fd.error("C-style variadic functions are not yet implemented in CTFE");
442 return CTFEExp.cantexp;
443 }
444
445 // Nested functions always inherit the 'this' pointer from the parent,
446 // except for delegates. (Note that the 'this' pointer may be null).
447 // Func literals report isNested() even if they are in global scope,
448 // so we need to check that the parent is a function.
449 if (fd.isNested() && fd.toParentLocal().isFuncDeclaration() && !thisarg && istate)
450 thisarg = ctfeGlobals.stack.getThis();
451
452 if (fd.needThis() && !thisarg)
453 {
454 // error, no this. Prevent segfault.
455 // Here should be unreachable by the strict 'this' check in front-end.
456 fd.error("need `this` to access member `%s`", fd.toChars());
457 return CTFEExp.cantexp;
458 }
459
460 // Place to hold all the arguments to the function while
461 // we are evaluating them.
462 size_t dim = arguments ? arguments.dim : 0;
463 assert((fd.parameters ? fd.parameters.dim : 0) == dim);
464
465 /* Evaluate all the arguments to the function,
466 * store the results in eargs[]
467 */
468 Expressions eargs = Expressions(dim);
469 for (size_t i = 0; i < dim; i++)
470 {
471 Expression earg = (*arguments)[i];
472 Parameter fparam = tf.parameterList[i];
473
474 if (fparam.isReference())
475 {
476 if (!istate && (fparam.storageClass & STC.out_))
477 {
478 // initializing an out parameter involves writing to it.
479 earg.error("global `%s` cannot be passed as an `out` parameter at compile time", earg.toChars());
480 return CTFEExp.cantexp;
481 }
482 // Convert all reference arguments into lvalue references
483 earg = interpretRegion(earg, istate, CTFEGoal.LValue);
484 if (CTFEExp.isCantExp(earg))
485 return earg;
486 }
487 else if (fparam.storageClass & STC.lazy_)
488 {
489 }
490 else
491 {
492 /* Value parameters
493 */
494 Type ta = fparam.type.toBasetype();
495 if (ta.ty == Tsarray)
496 if (auto eaddr = earg.isAddrExp())
497 {
498 /* Static arrays are passed by a simple pointer.
499 * Skip past this to get at the actual arg.
500 */
501 earg = eaddr.e1;
502 }
503
504 earg = interpretRegion(earg, istate);
505 if (CTFEExp.isCantExp(earg))
506 return earg;
507
508 /* Struct literals are passed by value, but we don't need to
509 * copy them if they are passed as const
510 */
511 if (earg.op == EXP.structLiteral && !(fparam.storageClass & (STC.const_ | STC.immutable_)))
512 earg = copyLiteral(earg).copy();
513 }
514 if (auto tee = earg.isThrownExceptionExp())
515 {
516 if (istate)
517 return tee;
518 tee.generateUncaughtError();
519 return CTFEExp.cantexp;
520 }
521 eargs[i] = earg;
522 }
523
524 // Now that we've evaluated all the arguments, we can start the frame
525 // (this is the moment when the 'call' actually takes place).
526 InterState istatex;
527 istatex.caller = istate;
528 istatex.fd = fd;
529
530 if (fd.isThis2)
531 {
532 Expression arg0 = thisarg;
533 if (arg0 && arg0.type.ty == Tstruct)
534 {
535 Type t = arg0.type.pointerTo();
536 arg0 = ctfeEmplaceExp!AddrExp(arg0.loc, arg0);
537 arg0.type = t;
538 }
539 auto elements = new Expressions(2);
540 (*elements)[0] = arg0;
541 (*elements)[1] = ctfeGlobals.stack.getThis();
542 Type t2 = Type.tvoidptr.sarrayOf(2);
543 const loc = thisarg ? thisarg.loc : fd.loc;
544 thisarg = ctfeEmplaceExp!ArrayLiteralExp(loc, t2, elements);
545 thisarg = ctfeEmplaceExp!AddrExp(loc, thisarg);
546 thisarg.type = t2.pointerTo();
547 }
548
549 ctfeGlobals.stack.startFrame(thisarg);
550 if (fd.vthis && thisarg)
551 {
552 ctfeGlobals.stack.push(fd.vthis);
553 setValue(fd.vthis, thisarg);
554 }
555
556 for (size_t i = 0; i < dim; i++)
557 {
558 Expression earg = eargs[i];
559 Parameter fparam = tf.parameterList[i];
560 VarDeclaration v = (*fd.parameters)[i];
561 debug (LOG)
562 {
563 printf("arg[%zu] = %s\n", i, earg.toChars());
564 }
565 ctfeGlobals.stack.push(v);
566
567 if (fparam.isReference() && earg.op == EXP.variable &&
568 earg.isVarExp().var.toParent2() == fd)
569 {
570 VarDeclaration vx = earg.isVarExp().var.isVarDeclaration();
571 if (!vx)
572 {
573 fd.error("cannot interpret `%s` as a `ref` parameter", earg.toChars());
574 return CTFEExp.cantexp;
575 }
576
577 /* vx is a variable that is declared in fd.
578 * It means that fd is recursively called. e.g.
579 *
580 * void fd(int n, ref int v = dummy) {
581 * int vx;
582 * if (n == 1) fd(2, vx);
583 * }
584 * fd(1);
585 *
586 * The old value of vx on the stack in fd(1)
587 * should be saved at the start of fd(2, vx) call.
588 */
589 const oldadr = vx.ctfeAdrOnStack;
590
591 ctfeGlobals.stack.push(vx);
592 assert(!hasValue(vx)); // vx is made uninitialized
593
594 // https://issues.dlang.org/show_bug.cgi?id=14299
595 // v.ctfeAdrOnStack should be saved already
596 // in the stack before the overwrite.
597 v.ctfeAdrOnStack = oldadr;
598 assert(hasValue(v)); // ref parameter v should refer existing value.
599 }
600 else
601 {
602 // Value parameters and non-trivial references
603 setValueWithoutChecking(v, earg);
604 }
605 debug (LOG)
606 {
607 printf("interpreted arg[%zu] = %s\n", i, earg.toChars());
608 showCtfeExpr(earg);
609 }
610 debug (LOGASSIGN)
611 {
612 printf("interpreted arg[%zu] = %s\n", i, earg.toChars());
613 showCtfeExpr(earg);
614 }
615 }
616
617 if (fd.vresult)
618 ctfeGlobals.stack.push(fd.vresult);
619
620 // Enter the function
621 ++ctfeGlobals.callDepth;
622 if (ctfeGlobals.callDepth > ctfeGlobals.maxCallDepth)
623 ctfeGlobals.maxCallDepth = ctfeGlobals.callDepth;
624
625 Expression e = null;
626 while (1)
627 {
628 if (ctfeGlobals.callDepth > CTFE_RECURSION_LIMIT)
629 {
630 // This is a compiler error. It must not be suppressed.
631 global.gag = 0;
632 fd.error("CTFE recursion limit exceeded");
633 e = CTFEExp.cantexp;
634 break;
635 }
636 e = interpret(pue, fd.fbody, &istatex);
637 if (CTFEExp.isCantExp(e))
638 {
639 debug (LOG)
640 {
641 printf("function body failed to interpret\n");
642 }
643 }
644
645 if (istatex.start)
646 {
647 fd.error("CTFE internal error: failed to resume at statement `%s`", istatex.start.toChars());
648 return CTFEExp.cantexp;
649 }
650
651 /* This is how we deal with a recursive statement AST
652 * that has arbitrary goto statements in it.
653 * Bubble up a 'result' which is the target of the goto
654 * statement, then go recursively down the AST looking
655 * for that statement, then execute starting there.
656 */
657 if (CTFEExp.isGotoExp(e))
658 {
659 istatex.start = istatex.gotoTarget; // set starting statement
660 istatex.gotoTarget = null;
661 }
662 else
663 {
664 assert(!e || (e.op != EXP.continue_ && e.op != EXP.break_));
665 break;
666 }
667 }
668 // If fell off the end of a void function, return void
669 if (!e && tf.next.ty == Tvoid)
670 e = CTFEExp.voidexp;
671 if (tf.isref && e.op == EXP.variable && e.isVarExp().var == fd.vthis)
672 e = thisarg;
673 if (tf.isref && fd.isThis2 && e.op == EXP.index)
674 {
675 auto ie = e.isIndexExp();
676 auto pe = ie.e1.isPtrExp();
677 auto ve = !pe ? null : pe.e1.isVarExp();
678 if (ve && ve.var == fd.vthis)
679 {
680 auto ne = ie.e2.isIntegerExp();
681 assert(ne);
682 auto ale = thisarg.isAddrExp().e1.isArrayLiteralExp();
683 e = (*ale.elements)[cast(size_t)ne.getInteger()];
684 if (auto ae = e.isAddrExp())
685 {
686 e = ae.e1;
687 }
688 }
689 }
690 assert(e !is null);
691
692 // Leave the function
693 --ctfeGlobals.callDepth;
694
695 ctfeGlobals.stack.endFrame();
696
697 // If it generated an uncaught exception, report error.
698 if (!istate && e.isThrownExceptionExp())
699 {
700 if (e == pue.exp())
701 e = pue.copy();
702 e.isThrownExceptionExp().generateUncaughtError();
703 e = CTFEExp.cantexp;
704 }
705
706 return e;
707 }
708
709 /// used to collect coverage information in ctfe
710 void incUsageCtfe(InterState* istate, const ref Loc loc)
711 {
712 if (global.params.ctfe_cov && istate)
713 {
714 auto line = loc.linnum;
715 auto mod = istate.fd.getModule();
716
717 ++mod.ctfe_cov[line];
718 }
719 }
720
721 private extern (C++) final class Interpreter : Visitor
722 {
723 alias visit = Visitor.visit;
724 public:
725 InterState* istate;
726 CTFEGoal goal;
727 Expression result;
728 UnionExp* pue; // storage for `result`
729
730 extern (D) this(UnionExp* pue, InterState* istate, CTFEGoal goal)
731 {
732 this.pue = pue;
733 this.istate = istate;
734 this.goal = goal;
735 }
736
737 // If e is EXP.throw_exception or EXP.cantExpression,
738 // set it to 'result' and returns true.
739 bool exceptionOrCant(Expression e)
740 {
741 if (exceptionOrCantInterpret(e))
742 {
743 // Make sure e is not pointing to a stack temporary
744 result = (e.op == EXP.cantExpression) ? CTFEExp.cantexp : e;
745 return true;
746 }
747 return false;
748 }
749
750 static Expressions* copyArrayOnWrite(Expressions* exps, Expressions* original)
751 {
752 if (exps is original)
753 {
754 if (!original)
755 exps = new Expressions();
756 else
757 exps = original.copy();
758 ++ctfeGlobals.numArrayAllocs;
759 }
760 return exps;
761 }
762
763 /******************************** Statement ***************************/
764
765 override void visit(Statement s)
766 {
767 debug (LOG)
768 {
769 printf("%s Statement::interpret()\n", s.loc.toChars());
770 }
771 if (istate.start)
772 {
773 if (istate.start != s)
774 return;
775 istate.start = null;
776 }
777
778 s.error("statement `%s` cannot be interpreted at compile time", s.toChars());
779 result = CTFEExp.cantexp;
780 }
781
782 override void visit(ExpStatement s)
783 {
784 debug (LOG)
785 {
786 printf("%s ExpStatement::interpret(%s)\n", s.loc.toChars(), s.exp ? s.exp.toChars() : "");
787 }
788 if (istate.start)
789 {
790 if (istate.start != s)
791 return;
792 istate.start = null;
793 }
794 if (s.exp && s.exp.hasCode)
795 incUsageCtfe(istate, s.loc);
796
797 Expression e = interpret(pue, s.exp, istate, CTFEGoal.Nothing);
798 if (exceptionOrCant(e))
799 return;
800 }
801
802 override void visit(CompoundStatement s)
803 {
804 debug (LOG)
805 {
806 printf("%s CompoundStatement::interpret()\n", s.loc.toChars());
807 }
808 if (istate.start == s)
809 istate.start = null;
810
811 const dim = s.statements ? s.statements.dim : 0;
812 foreach (i; 0 .. dim)
813 {
814 Statement sx = (*s.statements)[i];
815 result = interpret(pue, sx, istate);
816 if (result)
817 break;
818 }
819 debug (LOG)
820 {
821 printf("%s -CompoundStatement::interpret() %p\n", s.loc.toChars(), result);
822 }
823 }
824
825 override void visit(UnrolledLoopStatement s)
826 {
827 debug (LOG)
828 {
829 printf("%s UnrolledLoopStatement::interpret()\n", s.loc.toChars());
830 }
831 if (istate.start == s)
832 istate.start = null;
833
834 const dim = s.statements ? s.statements.dim : 0;
835 foreach (i; 0 .. dim)
836 {
837 Statement sx = (*s.statements)[i];
838 Expression e = interpret(pue, sx, istate);
839 if (!e) // succeeds to interpret, or goto target was not found
840 continue;
841 if (exceptionOrCant(e))
842 return;
843 if (e.op == EXP.break_)
844 {
845 if (istate.gotoTarget && istate.gotoTarget != s)
846 {
847 result = e; // break at a higher level
848 return;
849 }
850 istate.gotoTarget = null;
851 result = null;
852 return;
853 }
854 if (e.op == EXP.continue_)
855 {
856 if (istate.gotoTarget && istate.gotoTarget != s)
857 {
858 result = e; // continue at a higher level
859 return;
860 }
861 istate.gotoTarget = null;
862 continue;
863 }
864
865 // expression from return statement, or thrown exception
866 result = e;
867 break;
868 }
869 }
870
871 override void visit(IfStatement s)
872 {
873 debug (LOG)
874 {
875 printf("%s IfStatement::interpret(%s)\n", s.loc.toChars(), s.condition.toChars());
876 }
877 incUsageCtfe(istate, s.loc);
878 if (istate.start == s)
879 istate.start = null;
880 if (istate.start)
881 {
882 Expression e = null;
883 e = interpret(s.ifbody, istate);
884 if (!e && istate.start)
885 e = interpret(s.elsebody, istate);
886 result = e;
887 return;
888 }
889
890 UnionExp ue = void;
891 Expression e = interpret(&ue, s.condition, istate);
892 assert(e);
893 if (exceptionOrCant(e))
894 return;
895
896 if (isTrueBool(e))
897 result = interpret(pue, s.ifbody, istate);
898 else if (e.toBool().hasValue(false))
899 result = interpret(pue, s.elsebody, istate);
900 else
901 {
902 // no error, or assert(0)?
903 result = CTFEExp.cantexp;
904 }
905 }
906
907 override void visit(ScopeStatement s)
908 {
909 debug (LOG)
910 {
911 printf("%s ScopeStatement::interpret()\n", s.loc.toChars());
912 }
913 if (istate.start == s)
914 istate.start = null;
915
916 result = interpret(pue, s.statement, istate);
917 }
918
919 /**
920 Given an expression e which is about to be returned from the current
921 function, generate an error if it contains pointers to local variables.
922
923 Only checks expressions passed by value (pointers to local variables
924 may already be stored in members of classes, arrays, or AAs which
925 were passed as mutable function parameters).
926 Returns:
927 true if it is safe to return, false if an error was generated.
928 */
929 static bool stopPointersEscaping(const ref Loc loc, Expression e)
930 {
931 if (!e.type.hasPointers())
932 return true;
933 if (isPointer(e.type))
934 {
935 Expression x = e;
936 if (auto eaddr = e.isAddrExp())
937 x = eaddr.e1;
938 VarDeclaration v;
939 while (x.op == EXP.variable && (v = (cast(VarExp)x).var.isVarDeclaration()) !is null)
940 {
941 if (v.storage_class & STC.ref_)
942 {
943 x = getValue(v);
944 if (auto eaddr = e.isAddrExp())
945 eaddr.e1 = x;
946 continue;
947 }
948 if (ctfeGlobals.stack.isInCurrentFrame(v))
949 {
950 error(loc, "returning a pointer to a local stack variable");
951 return false;
952 }
953 else
954 break;
955 }
956 // TODO: If it is a EXP.dotVariable or EXP.index, we should check that it is not
957 // pointing to a local struct or static array.
958 }
959 if (auto se = e.isStructLiteralExp())
960 {
961 return stopPointersEscapingFromArray(loc, se.elements);
962 }
963 if (auto ale = e.isArrayLiteralExp())
964 {
965 return stopPointersEscapingFromArray(loc, ale.elements);
966 }
967 if (auto aae = e.isAssocArrayLiteralExp())
968 {
969 if (!stopPointersEscapingFromArray(loc, aae.keys))
970 return false;
971 return stopPointersEscapingFromArray(loc, aae.values);
972 }
973 return true;
974 }
975
976 // Check all elements of an array for escaping local variables. Return false if error
977 static bool stopPointersEscapingFromArray(const ref Loc loc, Expressions* elems)
978 {
979 foreach (e; *elems)
980 {
981 if (e && !stopPointersEscaping(loc, e))
982 return false;
983 }
984 return true;
985 }
986
987 override void visit(ReturnStatement s)
988 {
989 debug (LOG)
990 {
991 printf("%s ReturnStatement::interpret(%s)\n", s.loc.toChars(), s.exp ? s.exp.toChars() : "");
992 }
993 if (istate.start)
994 {
995 if (istate.start != s)
996 return;
997 istate.start = null;
998 }
999
1000 if (!s.exp)
1001 {
1002 result = CTFEExp.voidexp;
1003 return;
1004 }
1005
1006 incUsageCtfe(istate, s.loc);
1007 assert(istate && istate.fd && istate.fd.type && istate.fd.type.ty == Tfunction);
1008 TypeFunction tf = cast(TypeFunction)istate.fd.type;
1009
1010 /* If the function returns a ref AND it's been called from an assignment,
1011 * we need to return an lvalue. Otherwise, just do an (rvalue) interpret.
1012 */
1013 if (tf.isref)
1014 {
1015 result = interpret(pue, s.exp, istate, CTFEGoal.LValue);
1016 return;
1017 }
1018 if (tf.next && tf.next.ty == Tdelegate && istate.fd.closureVars.dim > 0)
1019 {
1020 // To support this, we need to copy all the closure vars
1021 // into the delegate literal.
1022 s.error("closures are not yet supported in CTFE");
1023 result = CTFEExp.cantexp;
1024 return;
1025 }
1026
1027 // We need to treat pointers specially, because EXP.symbolOffset can be used to
1028 // return a value OR a pointer
1029 Expression e = interpret(pue, s.exp, istate);
1030 if (exceptionOrCant(e))
1031 return;
1032
1033 // Disallow returning pointers to stack-allocated variables (bug 7876)
1034 if (!stopPointersEscaping(s.loc, e))
1035 {
1036 result = CTFEExp.cantexp;
1037 return;
1038 }
1039
1040 if (needToCopyLiteral(e))
1041 e = copyLiteral(e).copy();
1042 debug (LOGASSIGN)
1043 {
1044 printf("RETURN %s\n", s.loc.toChars());
1045 showCtfeExpr(e);
1046 }
1047 result = e;
1048 }
1049
1050 static Statement findGotoTarget(InterState* istate, Identifier ident)
1051 {
1052 Statement target = null;
1053 if (ident)
1054 {
1055 LabelDsymbol label = istate.fd.searchLabel(ident);
1056 assert(label && label.statement);
1057 LabelStatement ls = label.statement;
1058 target = ls.gotoTarget ? ls.gotoTarget : ls.statement;
1059 }
1060 return target;
1061 }
1062
1063 override void visit(BreakStatement s)
1064 {
1065 debug (LOG)
1066 {
1067 printf("%s BreakStatement::interpret()\n", s.loc.toChars());
1068 }
1069 incUsageCtfe(istate, s.loc);
1070 if (istate.start)
1071 {
1072 if (istate.start != s)
1073 return;
1074 istate.start = null;
1075 }
1076
1077 istate.gotoTarget = findGotoTarget(istate, s.ident);
1078 result = CTFEExp.breakexp;
1079 }
1080
1081 override void visit(ContinueStatement s)
1082 {
1083 debug (LOG)
1084 {
1085 printf("%s ContinueStatement::interpret()\n", s.loc.toChars());
1086 }
1087 incUsageCtfe(istate, s.loc);
1088 if (istate.start)
1089 {
1090 if (istate.start != s)
1091 return;
1092 istate.start = null;
1093 }
1094
1095 istate.gotoTarget = findGotoTarget(istate, s.ident);
1096 result = CTFEExp.continueexp;
1097 }
1098
1099 override void visit(WhileStatement s)
1100 {
1101 debug (LOG)
1102 {
1103 printf("WhileStatement::interpret()\n");
1104 }
1105 assert(0); // rewritten to ForStatement
1106 }
1107
1108 override void visit(DoStatement s)
1109 {
1110 debug (LOG)
1111 {
1112 printf("%s DoStatement::interpret()\n", s.loc.toChars());
1113 }
1114 if (istate.start == s)
1115 istate.start = null;
1116
1117 while (1)
1118 {
1119 Expression e = interpret(s._body, istate);
1120 if (!e && istate.start) // goto target was not found
1121 return;
1122 assert(!istate.start);
1123
1124 if (exceptionOrCant(e))
1125 return;
1126 if (e && e.op == EXP.break_)
1127 {
1128 if (istate.gotoTarget && istate.gotoTarget != s)
1129 {
1130 result = e; // break at a higher level
1131 return;
1132 }
1133 istate.gotoTarget = null;
1134 break;
1135 }
1136 if (e && e.op == EXP.continue_)
1137 {
1138 if (istate.gotoTarget && istate.gotoTarget != s)
1139 {
1140 result = e; // continue at a higher level
1141 return;
1142 }
1143 istate.gotoTarget = null;
1144 e = null;
1145 }
1146 if (e)
1147 {
1148 result = e; // bubbled up from ReturnStatement
1149 return;
1150 }
1151
1152 UnionExp ue = void;
1153 incUsageCtfe(istate, s.condition.loc);
1154 e = interpret(&ue, s.condition, istate);
1155 if (exceptionOrCant(e))
1156 return;
1157 if (!e.isConst())
1158 {
1159 result = CTFEExp.cantexp;
1160 return;
1161 }
1162 if (e.toBool().hasValue(false))
1163 break;
1164 assert(isTrueBool(e));
1165 }
1166 assert(result is null);
1167 }
1168
1169 override void visit(ForStatement s)
1170 {
1171 debug (LOG)
1172 {
1173 printf("%s ForStatement::interpret()\n", s.loc.toChars());
1174 }
1175 if (istate.start == s)
1176 istate.start = null;
1177
1178 UnionExp ueinit = void;
1179 Expression ei = interpret(&ueinit, s._init, istate);
1180 if (exceptionOrCant(ei))
1181 return;
1182 assert(!ei); // s.init never returns from function, or jumps out from it
1183
1184 while (1)
1185 {
1186 if (s.condition && !istate.start)
1187 {
1188 UnionExp ue = void;
1189 incUsageCtfe(istate, s.condition.loc);
1190 Expression e = interpret(&ue, s.condition, istate);
1191 if (exceptionOrCant(e))
1192 return;
1193 if (e.toBool().hasValue(false))
1194 break;
1195 assert(isTrueBool(e));
1196 }
1197
1198 Expression e = interpret(pue, s._body, istate);
1199 if (!e && istate.start) // goto target was not found
1200 return;
1201 assert(!istate.start);
1202
1203 if (exceptionOrCant(e))
1204 return;
1205 if (e && e.op == EXP.break_)
1206 {
1207 if (istate.gotoTarget && istate.gotoTarget != s)
1208 {
1209 result = e; // break at a higher level
1210 return;
1211 }
1212 istate.gotoTarget = null;
1213 break;
1214 }
1215 if (e && e.op == EXP.continue_)
1216 {
1217 if (istate.gotoTarget && istate.gotoTarget != s)
1218 {
1219 result = e; // continue at a higher level
1220 return;
1221 }
1222 istate.gotoTarget = null;
1223 e = null;
1224 }
1225 if (e)
1226 {
1227 result = e; // bubbled up from ReturnStatement
1228 return;
1229 }
1230
1231 UnionExp uei = void;
1232 if (s.increment)
1233 incUsageCtfe(istate, s.increment.loc);
1234 e = interpret(&uei, s.increment, istate, CTFEGoal.Nothing);
1235 if (exceptionOrCant(e))
1236 return;
1237 }
1238 assert(result is null);
1239 }
1240
1241 override void visit(ForeachStatement s)
1242 {
1243 assert(0); // rewritten to ForStatement
1244 }
1245
1246 override void visit(ForeachRangeStatement s)
1247 {
1248 assert(0); // rewritten to ForStatement
1249 }
1250
1251 override void visit(SwitchStatement s)
1252 {
1253 debug (LOG)
1254 {
1255 printf("%s SwitchStatement::interpret()\n", s.loc.toChars());
1256 }
1257 incUsageCtfe(istate, s.loc);
1258 if (istate.start == s)
1259 istate.start = null;
1260 if (istate.start)
1261 {
1262 Expression e = interpret(s._body, istate);
1263 if (istate.start) // goto target was not found
1264 return;
1265 if (exceptionOrCant(e))
1266 return;
1267 if (e && e.op == EXP.break_)
1268 {
1269 if (istate.gotoTarget && istate.gotoTarget != s)
1270 {
1271 result = e; // break at a higher level
1272 return;
1273 }
1274 istate.gotoTarget = null;
1275 e = null;
1276 }
1277 result = e;
1278 return;
1279 }
1280
1281 UnionExp uecond = void;
1282 Expression econdition = interpret(&uecond, s.condition, istate);
1283 if (exceptionOrCant(econdition))
1284 return;
1285
1286 Statement scase = null;
1287 if (s.cases)
1288 foreach (cs; *s.cases)
1289 {
1290 UnionExp uecase = void;
1291 Expression ecase = interpret(&uecase, cs.exp, istate);
1292 if (exceptionOrCant(ecase))
1293 return;
1294 if (ctfeEqual(cs.exp.loc, EXP.equal, econdition, ecase))
1295 {
1296 scase = cs;
1297 break;
1298 }
1299 }
1300 if (!scase)
1301 {
1302 if (s.hasNoDefault)
1303 s.error("no `default` or `case` for `%s` in `switch` statement", econdition.toChars());
1304 scase = s.sdefault;
1305 }
1306
1307 assert(scase);
1308
1309 /* Jump to scase
1310 */
1311 istate.start = scase;
1312 Expression e = interpret(pue, s._body, istate);
1313 assert(!istate.start); // jump must not fail
1314 if (e && e.op == EXP.break_)
1315 {
1316 if (istate.gotoTarget && istate.gotoTarget != s)
1317 {
1318 result = e; // break at a higher level
1319 return;
1320 }
1321 istate.gotoTarget = null;
1322 e = null;
1323 }
1324 result = e;
1325 }
1326
1327 override void visit(CaseStatement s)
1328 {
1329 debug (LOG)
1330 {
1331 printf("%s CaseStatement::interpret(%s) this = %p\n", s.loc.toChars(), s.exp.toChars(), s);
1332 }
1333 incUsageCtfe(istate, s.loc);
1334 if (istate.start == s)
1335 istate.start = null;
1336
1337 result = interpret(pue, s.statement, istate);
1338 }
1339
1340 override void visit(DefaultStatement s)
1341 {
1342 debug (LOG)
1343 {
1344 printf("%s DefaultStatement::interpret()\n", s.loc.toChars());
1345 }
1346 incUsageCtfe(istate, s.loc);
1347 if (istate.start == s)
1348 istate.start = null;
1349
1350 result = interpret(pue, s.statement, istate);
1351 }
1352
1353 override void visit(GotoStatement s)
1354 {
1355 debug (LOG)
1356 {
1357 printf("%s GotoStatement::interpret()\n", s.loc.toChars());
1358 }
1359 if (istate.start)
1360 {
1361 if (istate.start != s)
1362 return;
1363 istate.start = null;
1364 }
1365 incUsageCtfe(istate, s.loc);
1366
1367 assert(s.label && s.label.statement);
1368 istate.gotoTarget = s.label.statement;
1369 result = CTFEExp.gotoexp;
1370 }
1371
1372 override void visit(GotoCaseStatement s)
1373 {
1374 debug (LOG)
1375 {
1376 printf("%s GotoCaseStatement::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.cs);
1387 istate.gotoTarget = s.cs;
1388 result = CTFEExp.gotoexp;
1389 }
1390
1391 override void visit(GotoDefaultStatement s)
1392 {
1393 debug (LOG)
1394 {
1395 printf("%s GotoDefaultStatement::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.sw && s.sw.sdefault);
1406 istate.gotoTarget = s.sw.sdefault;
1407 result = CTFEExp.gotoexp;
1408 }
1409
1410 override void visit(LabelStatement s)
1411 {
1412 debug (LOG)
1413 {
1414 printf("%s LabelStatement::interpret()\n", s.loc.toChars());
1415 }
1416 if (istate.start == s)
1417 istate.start = null;
1418
1419 result = interpret(pue, s.statement, istate);
1420 }
1421
1422 override void visit(TryCatchStatement s)
1423 {
1424 debug (LOG)
1425 {
1426 printf("%s TryCatchStatement::interpret()\n", s.loc.toChars());
1427 }
1428 if (istate.start == s)
1429 istate.start = null;
1430 if (istate.start)
1431 {
1432 Expression e = null;
1433 e = interpret(pue, s._body, istate);
1434 foreach (ca; *s.catches)
1435 {
1436 if (e || !istate.start) // goto target was found
1437 break;
1438 e = interpret(pue, ca.handler, istate);
1439 }
1440 result = e;
1441 return;
1442 }
1443
1444 Expression e = interpret(s._body, istate);
1445
1446 // An exception was thrown
1447 if (e && e.isThrownExceptionExp())
1448 {
1449 ThrownExceptionExp ex = e.isThrownExceptionExp();
1450 Type extype = ex.thrown.originalClass().type;
1451
1452 // Search for an appropriate catch clause.
1453 foreach (ca; *s.catches)
1454 {
1455 Type catype = ca.type;
1456 if (!catype.equals(extype) && !catype.isBaseOf(extype, null))
1457 continue;
1458
1459 // Execute the handler
1460 if (ca.var)
1461 {
1462 ctfeGlobals.stack.push(ca.var);
1463 setValue(ca.var, ex.thrown);
1464 }
1465 e = interpret(ca.handler, istate);
1466 if (CTFEExp.isGotoExp(e))
1467 {
1468 /* This is an optimization that relies on the locality of the jump target.
1469 * If the label is in the same catch handler, the following scan
1470 * would find it quickly and can reduce jump cost.
1471 * Otherwise, the catch block may be unnnecessary scanned again
1472 * so it would make CTFE speed slower.
1473 */
1474 InterState istatex = *istate;
1475 istatex.start = istate.gotoTarget; // set starting statement
1476 istatex.gotoTarget = null;
1477 Expression eh = interpret(ca.handler, &istatex);
1478 if (!istatex.start)
1479 {
1480 istate.gotoTarget = null;
1481 e = eh;
1482 }
1483 }
1484 break;
1485 }
1486 }
1487 result = e;
1488 }
1489
1490 static bool isAnErrorException(ClassDeclaration cd)
1491 {
1492 return cd == ClassDeclaration.errorException || ClassDeclaration.errorException.isBaseOf(cd, null);
1493 }
1494
1495 static ThrownExceptionExp chainExceptions(ThrownExceptionExp oldest, ThrownExceptionExp newest)
1496 {
1497 debug (LOG)
1498 {
1499 printf("Collided exceptions %s %s\n", oldest.thrown.toChars(), newest.thrown.toChars());
1500 }
1501 // Little sanity check to make sure it's really a Throwable
1502 ClassReferenceExp boss = oldest.thrown;
1503 const next = 4; // index of Throwable.next
1504 assert((*boss.value.elements)[next].type.ty == Tclass); // Throwable.next
1505 ClassReferenceExp collateral = newest.thrown;
1506 if (isAnErrorException(collateral.originalClass()) && !isAnErrorException(boss.originalClass()))
1507 {
1508 /* Find the index of the Error.bypassException field
1509 */
1510 auto bypass = next + 1;
1511 if ((*collateral.value.elements)[bypass].type.ty == Tuns32)
1512 bypass += 1; // skip over _refcount field
1513 assert((*collateral.value.elements)[bypass].type.ty == Tclass);
1514
1515 // The new exception bypass the existing chain
1516 (*collateral.value.elements)[bypass] = boss;
1517 return newest;
1518 }
1519 while ((*boss.value.elements)[next].op == EXP.classReference)
1520 {
1521 boss = cast(ClassReferenceExp)(*boss.value.elements)[next];
1522 }
1523 (*boss.value.elements)[next] = collateral;
1524 return oldest;
1525 }
1526
1527 override void visit(TryFinallyStatement s)
1528 {
1529 debug (LOG)
1530 {
1531 printf("%s TryFinallyStatement::interpret()\n", s.loc.toChars());
1532 }
1533 if (istate.start == s)
1534 istate.start = null;
1535 if (istate.start)
1536 {
1537 Expression e = null;
1538 e = interpret(pue, s._body, istate);
1539 // Jump into/out from finalbody is disabled in semantic analysis.
1540 // and jump inside will be handled by the ScopeStatement == finalbody.
1541 result = e;
1542 return;
1543 }
1544
1545 Expression ex = interpret(s._body, istate);
1546 if (CTFEExp.isCantExp(ex))
1547 {
1548 result = ex;
1549 return;
1550 }
1551 while (CTFEExp.isGotoExp(ex))
1552 {
1553 // If the goto target is within the body, we must not interpret the finally statement,
1554 // because that will call destructors for objects within the scope, which we should not do.
1555 InterState istatex = *istate;
1556 istatex.start = istate.gotoTarget; // set starting statement
1557 istatex.gotoTarget = null;
1558 Expression bex = interpret(s._body, &istatex);
1559 if (istatex.start)
1560 {
1561 // The goto target is outside the current scope.
1562 break;
1563 }
1564 // The goto target was within the body.
1565 if (CTFEExp.isCantExp(bex))
1566 {
1567 result = bex;
1568 return;
1569 }
1570 *istate = istatex;
1571 ex = bex;
1572 }
1573
1574 Expression ey = interpret(s.finalbody, istate);
1575 if (CTFEExp.isCantExp(ey))
1576 {
1577 result = ey;
1578 return;
1579 }
1580 if (ey && ey.isThrownExceptionExp())
1581 {
1582 // Check for collided exceptions
1583 if (ex && ex.isThrownExceptionExp())
1584 ex = chainExceptions(ex.isThrownExceptionExp(), ey.isThrownExceptionExp());
1585 else
1586 ex = ey;
1587 }
1588 result = ex;
1589 }
1590
1591 override void visit(ThrowStatement s)
1592 {
1593 debug (LOG)
1594 {
1595 printf("%s ThrowStatement::interpret()\n", s.loc.toChars());
1596 }
1597 if (istate.start)
1598 {
1599 if (istate.start != s)
1600 return;
1601 istate.start = null;
1602 }
1603
1604 incUsageCtfe(istate, s.loc);
1605
1606 Expression e = interpretRegion(s.exp, istate);
1607 if (exceptionOrCant(e))
1608 return;
1609
1610 assert(e.op == EXP.classReference);
1611 result = ctfeEmplaceExp!ThrownExceptionExp(s.loc, e.isClassReferenceExp());
1612 }
1613
1614 override void visit(ScopeGuardStatement s)
1615 {
1616 assert(0);
1617 }
1618
1619 override void visit(WithStatement s)
1620 {
1621 debug (LOG)
1622 {
1623 printf("%s WithStatement::interpret()\n", s.loc.toChars());
1624 }
1625 if (istate.start == s)
1626 istate.start = null;
1627 if (istate.start)
1628 {
1629 result = s._body ? interpret(s._body, istate) : null;
1630 return;
1631 }
1632
1633 // If it is with(Enum) {...}, just execute the body.
1634 if (s.exp.op == EXP.scope_ || s.exp.op == EXP.type)
1635 {
1636 result = interpret(pue, s._body, istate);
1637 return;
1638 }
1639
1640 incUsageCtfe(istate, s.loc);
1641
1642 Expression e = interpret(s.exp, istate);
1643 if (exceptionOrCant(e))
1644 return;
1645
1646 if (s.wthis.type.ty == Tpointer && s.exp.type.ty != Tpointer)
1647 {
1648 e = ctfeEmplaceExp!AddrExp(s.loc, e, s.wthis.type);
1649 }
1650 ctfeGlobals.stack.push(s.wthis);
1651 setValue(s.wthis, e);
1652 e = interpret(s._body, istate);
1653 if (CTFEExp.isGotoExp(e))
1654 {
1655 /* This is an optimization that relies on the locality of the jump target.
1656 * If the label is in the same WithStatement, the following scan
1657 * would find it quickly and can reduce jump cost.
1658 * Otherwise, the statement body may be unnnecessary scanned again
1659 * so it would make CTFE speed slower.
1660 */
1661 InterState istatex = *istate;
1662 istatex.start = istate.gotoTarget; // set starting statement
1663 istatex.gotoTarget = null;
1664 Expression ex = interpret(s._body, &istatex);
1665 if (!istatex.start)
1666 {
1667 istate.gotoTarget = null;
1668 e = ex;
1669 }
1670 }
1671 ctfeGlobals.stack.pop(s.wthis);
1672 result = e;
1673 }
1674
1675 override void visit(AsmStatement s)
1676 {
1677 debug (LOG)
1678 {
1679 printf("%s AsmStatement::interpret()\n", s.loc.toChars());
1680 }
1681 if (istate.start)
1682 {
1683 if (istate.start != s)
1684 return;
1685 istate.start = null;
1686 }
1687 s.error("`asm` statements cannot be interpreted at compile time");
1688 result = CTFEExp.cantexp;
1689 }
1690
1691 override void visit(ImportStatement s)
1692 {
1693 debug (LOG)
1694 {
1695 printf("ImportStatement::interpret()\n");
1696 }
1697 if (istate.start)
1698 {
1699 if (istate.start != s)
1700 return;
1701 istate.start = null;
1702 }
1703 }
1704
1705 /******************************** Expression ***************************/
1706
1707 override void visit(Expression e)
1708 {
1709 debug (LOG)
1710 {
1711 printf("%s Expression::interpret() '%s' %s\n", e.loc.toChars(), EXPtoString(e.op).ptr, e.toChars());
1712 printf("type = %s\n", e.type.toChars());
1713 showCtfeExpr(e);
1714 }
1715 e.error("cannot interpret `%s` at compile time", e.toChars());
1716 result = CTFEExp.cantexp;
1717 }
1718
1719 override void visit(TypeExp e)
1720 {
1721 debug (LOG)
1722 {
1723 printf("%s TypeExp.interpret() %s\n", e.loc.toChars(), e.toChars());
1724 }
1725 result = e;
1726 }
1727
1728 override void visit(ThisExp e)
1729 {
1730 debug (LOG)
1731 {
1732 printf("%s ThisExp::interpret() %s\n", e.loc.toChars(), e.toChars());
1733 }
1734 if (goal == CTFEGoal.LValue)
1735 {
1736 // We might end up here with istate being zero
1737 // https://issues.dlang.org/show_bug.cgi?id=16382
1738 if (istate && istate.fd.vthis)
1739 {
1740 result = ctfeEmplaceExp!VarExp(e.loc, istate.fd.vthis);
1741 if (istate.fd.isThis2)
1742 {
1743 result = ctfeEmplaceExp!PtrExp(e.loc, result);
1744 result.type = Type.tvoidptr.sarrayOf(2);
1745 result = ctfeEmplaceExp!IndexExp(e.loc, result, IntegerExp.literal!0);
1746 }
1747 result.type = e.type;
1748 }
1749 else
1750 result = e;
1751 return;
1752 }
1753
1754 result = ctfeGlobals.stack.getThis();
1755 if (result)
1756 {
1757 if (istate && istate.fd.isThis2)
1758 {
1759 assert(result.op == EXP.address);
1760 result = (cast(AddrExp)result).e1;
1761 assert(result.op == EXP.arrayLiteral);
1762 result = (*(cast(ArrayLiteralExp)result).elements)[0];
1763 if (e.type.ty == Tstruct)
1764 {
1765 result = (cast(AddrExp)result).e1;
1766 }
1767 return;
1768 }
1769 assert(result.op == EXP.structLiteral || result.op == EXP.classReference || result.op == EXP.type);
1770 return;
1771 }
1772 e.error("value of `this` is not known at compile time");
1773 result = CTFEExp.cantexp;
1774 }
1775
1776 override void visit(NullExp e)
1777 {
1778 result = e;
1779 }
1780
1781 override void visit(IntegerExp e)
1782 {
1783 debug (LOG)
1784 {
1785 printf("%s IntegerExp::interpret() %s\n", e.loc.toChars(), e.toChars());
1786 }
1787 result = e;
1788 }
1789
1790 override void visit(RealExp e)
1791 {
1792 debug (LOG)
1793 {
1794 printf("%s RealExp::interpret() %s\n", e.loc.toChars(), e.toChars());
1795 }
1796 result = e;
1797 }
1798
1799 override void visit(ComplexExp e)
1800 {
1801 result = e;
1802 }
1803
1804 override void visit(StringExp e)
1805 {
1806 debug (LOG)
1807 {
1808 printf("%s StringExp::interpret() %s\n", e.loc.toChars(), e.toChars());
1809 }
1810 /* Attempts to modify string literals are prevented
1811 * in BinExp::interpretAssignCommon.
1812 */
1813 result = e;
1814 }
1815
1816 override void visit(FuncExp e)
1817 {
1818 debug (LOG)
1819 {
1820 printf("%s FuncExp::interpret() %s\n", e.loc.toChars(), e.toChars());
1821 }
1822 result = e;
1823 }
1824
1825 override void visit(SymOffExp e)
1826 {
1827 debug (LOG)
1828 {
1829 printf("%s SymOffExp::interpret() %s\n", e.loc.toChars(), e.toChars());
1830 }
1831 if (e.var.isFuncDeclaration() && e.offset == 0)
1832 {
1833 result = e;
1834 return;
1835 }
1836 if (isTypeInfo_Class(e.type) && e.offset == 0)
1837 {
1838 result = e;
1839 return;
1840 }
1841 if (e.type.ty != Tpointer)
1842 {
1843 // Probably impossible
1844 e.error("cannot interpret `%s` at compile time", e.toChars());
1845 result = CTFEExp.cantexp;
1846 return;
1847 }
1848 Type pointee = (cast(TypePointer)e.type).next;
1849 if (e.var.isThreadlocal())
1850 {
1851 e.error("cannot take address of thread-local variable %s at compile time", e.var.toChars());
1852 result = CTFEExp.cantexp;
1853 return;
1854 }
1855 // Check for taking an address of a shared variable.
1856 // If the shared variable is an array, the offset might not be zero.
1857 Type fromType = null;
1858 if (e.var.type.ty == Tarray || e.var.type.ty == Tsarray)
1859 {
1860 fromType = (cast(TypeArray)e.var.type).next;
1861 }
1862 if (e.var.isDataseg() && ((e.offset == 0 && isSafePointerCast(e.var.type, pointee)) || (fromType && isSafePointerCast(fromType, pointee))))
1863 {
1864 result = e;
1865 return;
1866 }
1867
1868 Expression val = getVarExp(e.loc, istate, e.var, goal);
1869 if (exceptionOrCant(val))
1870 return;
1871 if (val.type.ty == Tarray || val.type.ty == Tsarray)
1872 {
1873 // Check for unsupported type painting operations
1874 Type elemtype = (cast(TypeArray)val.type).next;
1875 d_uns64 elemsize = elemtype.size();
1876
1877 // It's OK to cast from fixed length to fixed length array, eg &int[n] to int[d]*.
1878 if (val.type.ty == Tsarray && pointee.ty == Tsarray && elemsize == pointee.nextOf().size())
1879 {
1880 size_t d = cast(size_t)(cast(TypeSArray)pointee).dim.toInteger();
1881 Expression elwr = ctfeEmplaceExp!IntegerExp(e.loc, e.offset / elemsize, Type.tsize_t);
1882 Expression eupr = ctfeEmplaceExp!IntegerExp(e.loc, e.offset / elemsize + d, Type.tsize_t);
1883
1884 // Create a CTFE pointer &val[ofs..ofs+d]
1885 auto se = ctfeEmplaceExp!SliceExp(e.loc, val, elwr, eupr);
1886 se.type = pointee;
1887 emplaceExp!(AddrExp)(pue, e.loc, se, e.type);
1888 result = pue.exp();
1889 return;
1890 }
1891
1892 if (!isSafePointerCast(elemtype, pointee))
1893 {
1894 // It's also OK to cast from &string to string*.
1895 if (e.offset == 0 && isSafePointerCast(e.var.type, pointee))
1896 {
1897 // Create a CTFE pointer &var
1898 auto ve = ctfeEmplaceExp!VarExp(e.loc, e.var);
1899 ve.type = elemtype;
1900 emplaceExp!(AddrExp)(pue, e.loc, ve, e.type);
1901 result = pue.exp();
1902 return;
1903 }
1904 e.error("reinterpreting cast from `%s` to `%s` is not supported in CTFE", val.type.toChars(), e.type.toChars());
1905 result = CTFEExp.cantexp;
1906 return;
1907 }
1908
1909 const dinteger_t sz = pointee.size();
1910 dinteger_t indx = e.offset / sz;
1911 assert(sz * indx == e.offset);
1912 Expression aggregate = null;
1913 if (val.op == EXP.arrayLiteral || val.op == EXP.string_)
1914 {
1915 aggregate = val;
1916 }
1917 else if (auto se = val.isSliceExp())
1918 {
1919 aggregate = se.e1;
1920 UnionExp uelwr = void;
1921 Expression lwr = interpret(&uelwr, se.lwr, istate);
1922 indx += lwr.toInteger();
1923 }
1924 if (aggregate)
1925 {
1926 // Create a CTFE pointer &aggregate[ofs]
1927 auto ofs = ctfeEmplaceExp!IntegerExp(e.loc, indx, Type.tsize_t);
1928 auto ei = ctfeEmplaceExp!IndexExp(e.loc, aggregate, ofs);
1929 ei.type = elemtype;
1930 emplaceExp!(AddrExp)(pue, e.loc, ei, e.type);
1931 result = pue.exp();
1932 return;
1933 }
1934 }
1935 else if (e.offset == 0 && isSafePointerCast(e.var.type, pointee))
1936 {
1937 // Create a CTFE pointer &var
1938 auto ve = ctfeEmplaceExp!VarExp(e.loc, e.var);
1939 ve.type = e.var.type;
1940 emplaceExp!(AddrExp)(pue, e.loc, ve, e.type);
1941 result = pue.exp();
1942 return;
1943 }
1944
1945 e.error("cannot convert `&%s` to `%s` at compile time", e.var.type.toChars(), e.type.toChars());
1946 result = CTFEExp.cantexp;
1947 }
1948
1949 override void visit(AddrExp e)
1950 {
1951 debug (LOG)
1952 {
1953 printf("%s AddrExp::interpret() %s\n", e.loc.toChars(), e.toChars());
1954 }
1955 if (auto ve = e.e1.isVarExp())
1956 {
1957 Declaration decl = ve.var;
1958
1959 // We cannot take the address of an imported symbol at compile time
1960 if (decl.isImportedSymbol()) {
1961 e.error("cannot take address of imported symbol `%s` at compile time", decl.toChars());
1962 result = CTFEExp.cantexp;
1963 return;
1964 }
1965
1966 if (decl.isDataseg()) {
1967 // Normally this is already done by optimize()
1968 // Do it here in case optimize(WANTvalue) wasn't run before CTFE
1969 emplaceExp!(SymOffExp)(pue, e.loc, (cast(VarExp)e.e1).var, 0);
1970 result = pue.exp();
1971 result.type = e.type;
1972 return;
1973 }
1974 }
1975 auto er = interpret(e.e1, istate, CTFEGoal.LValue);
1976 if (auto ve = er.isVarExp())
1977 if (ve.var == istate.fd.vthis)
1978 er = interpret(er, istate);
1979
1980 if (exceptionOrCant(er))
1981 return;
1982
1983 // Return a simplified address expression
1984 emplaceExp!(AddrExp)(pue, e.loc, er, e.type);
1985 result = pue.exp();
1986 }
1987
1988 override void visit(DelegateExp e)
1989 {
1990 debug (LOG)
1991 {
1992 printf("%s DelegateExp::interpret() %s\n", e.loc.toChars(), e.toChars());
1993 }
1994 // TODO: Really we should create a CTFE-only delegate expression
1995 // of a pointer and a funcptr.
1996
1997 // If it is &nestedfunc, just return it
1998 // TODO: We should save the context pointer
1999 if (auto ve1 = e.e1.isVarExp())
2000 if (ve1.var == e.func)
2001 {
2002 result = e;
2003 return;
2004 }
2005
2006 auto er = interpret(pue, e.e1, istate);
2007 if (exceptionOrCant(er))
2008 return;
2009 if (er == e.e1)
2010 {
2011 // If it has already been CTFE'd, just return it
2012 result = e;
2013 }
2014 else
2015 {
2016 er = (er == pue.exp()) ? pue.copy() : er;
2017 emplaceExp!(DelegateExp)(pue, e.loc, er, e.func, false);
2018 result = pue.exp();
2019 result.type = e.type;
2020 }
2021 }
2022
2023 static Expression getVarExp(const ref Loc loc, InterState* istate, Declaration d, CTFEGoal goal)
2024 {
2025 Expression e = CTFEExp.cantexp;
2026 if (VarDeclaration v = d.isVarDeclaration())
2027 {
2028 /* Magic variable __ctfe always returns true when interpreting
2029 */
2030 if (v.ident == Id.ctfe)
2031 return IntegerExp.createBool(true);
2032
2033 if (!v.originalType && v.semanticRun < PASS.semanticdone) // semantic() not yet run
2034 {
2035 v.dsymbolSemantic(null);
2036 if (v.type.ty == Terror)
2037 return CTFEExp.cantexp;
2038 }
2039
2040 if ((v.isConst() || v.isImmutable() || v.storage_class & STC.manifest) && !hasValue(v) && v._init && !v.isCTFE())
2041 {
2042 if (v.inuse)
2043 {
2044 error(loc, "circular initialization of %s `%s`", v.kind(), v.toPrettyChars());
2045 return CTFEExp.cantexp;
2046 }
2047 if (v._scope)
2048 {
2049 v.inuse++;
2050 v._init = v._init.initializerSemantic(v._scope, v.type, INITinterpret); // might not be run on aggregate members
2051 v.inuse--;
2052 }
2053 e = v._init.initializerToExpression(v.type);
2054 if (!e)
2055 return CTFEExp.cantexp;
2056 assert(e.type);
2057
2058 if (e.op == EXP.construct || e.op == EXP.blit)
2059 {
2060 AssignExp ae = cast(AssignExp)e;
2061 e = ae.e2;
2062 }
2063
2064 if (e.op == EXP.error)
2065 {
2066 // FIXME: Ultimately all errors should be detected in prior semantic analysis stage.
2067 }
2068 else if (v.isDataseg() || (v.storage_class & STC.manifest))
2069 {
2070 /* https://issues.dlang.org/show_bug.cgi?id=14304
2071 * e is a value that is not yet owned by CTFE.
2072 * Mark as "cached", and use it directly during interpretation.
2073 */
2074 e = scrubCacheValue(e);
2075 ctfeGlobals.stack.saveGlobalConstant(v, e);
2076 }
2077 else
2078 {
2079 v.inuse++;
2080 e = interpret(e, istate);
2081 v.inuse--;
2082 if (CTFEExp.isCantExp(e) && !global.gag && !ctfeGlobals.stackTraceCallsToSuppress)
2083 errorSupplemental(loc, "while evaluating %s.init", v.toChars());
2084 if (exceptionOrCantInterpret(e))
2085 return e;
2086 }
2087 }
2088 else if (v.isCTFE() && !hasValue(v))
2089 {
2090 if (v._init && v.type.size() != 0)
2091 {
2092 if (v._init.isVoidInitializer())
2093 {
2094 // var should have been initialized when it was created
2095 error(loc, "CTFE internal error: trying to access uninitialized var");
2096 assert(0);
2097 }
2098 e = v._init.initializerToExpression();
2099 }
2100 else
2101 // Zero-length arrays don't have an initializer
2102 e = v.type.defaultInitLiteral(e.loc);
2103
2104 e = interpret(e, istate);
2105 }
2106 else if (!(v.isDataseg() || v.storage_class & STC.manifest) && !v.isCTFE() && !istate)
2107 {
2108 error(loc, "variable `%s` cannot be read at compile time", v.toChars());
2109 return CTFEExp.cantexp;
2110 }
2111 else
2112 {
2113 e = hasValue(v) ? getValue(v) : null;
2114 if (!e)
2115 {
2116 // Zero-length arrays don't have an initializer
2117 if (v.type.size() == 0)
2118 e = v.type.defaultInitLiteral(loc);
2119 else if (!v.isCTFE() && v.isDataseg())
2120 {
2121 error(loc, "static variable `%s` cannot be read at compile time", v.toChars());
2122 return CTFEExp.cantexp;
2123 }
2124 else
2125 {
2126 assert(!(v._init && v._init.isVoidInitializer()));
2127 // CTFE initiated from inside a function
2128 error(loc, "variable `%s` cannot be read at compile time", v.toChars());
2129 return CTFEExp.cantexp;
2130 }
2131 }
2132 if (auto vie = e.isVoidInitExp())
2133 {
2134 error(loc, "cannot read uninitialized variable `%s` in ctfe", v.toPrettyChars());
2135 errorSupplemental(vie.var.loc, "`%s` was uninitialized and used before set", vie.var.toChars());
2136 return CTFEExp.cantexp;
2137 }
2138 if (goal != CTFEGoal.LValue && v.isReference())
2139 e = interpret(e, istate, goal);
2140 }
2141 if (!e)
2142 e = CTFEExp.cantexp;
2143 }
2144 else if (SymbolDeclaration s = d.isSymbolDeclaration())
2145 {
2146 // exclude void[]-typed `__traits(initSymbol)`
2147 if (auto ta = s.type.toBasetype().isTypeDArray())
2148 {
2149 assert(ta.next.ty == Tvoid);
2150 error(loc, "cannot determine the address of the initializer symbol during CTFE");
2151 return CTFEExp.cantexp;
2152 }
2153
2154 // Struct static initializers, for example
2155 e = s.dsym.type.defaultInitLiteral(loc);
2156 if (e.op == EXP.error)
2157 error(loc, "CTFE failed because of previous errors in `%s.init`", s.toChars());
2158 e = e.expressionSemantic(null);
2159 if (e.op == EXP.error)
2160 e = CTFEExp.cantexp;
2161 else // Convert NULL to CTFEExp
2162 e = interpret(e, istate, goal);
2163 }
2164 else
2165 error(loc, "cannot interpret declaration `%s` at compile time", d.toChars());
2166 return e;
2167 }
2168
2169 override void visit(VarExp e)
2170 {
2171 debug (LOG)
2172 {
2173 printf("%s VarExp::interpret() `%s`, goal = %d\n", e.loc.toChars(), e.toChars(), goal);
2174 }
2175 if (e.var.isFuncDeclaration())
2176 {
2177 result = e;
2178 return;
2179 }
2180
2181 if (goal == CTFEGoal.LValue)
2182 {
2183 if (auto v = e.var.isVarDeclaration())
2184 {
2185 if (!hasValue(v))
2186 {
2187 // Compile-time known non-CTFE variable from an outer context
2188 // e.g. global or from a ref argument
2189 if (v.isConst() || v.isImmutable())
2190 {
2191 result = getVarExp(e.loc, istate, v, goal);
2192 return;
2193 }
2194
2195 if (!v.isCTFE() && v.isDataseg())
2196 e.error("static variable `%s` cannot be read at compile time", v.toChars());
2197 else // CTFE initiated from inside a function
2198 e.error("variable `%s` cannot be read at compile time", v.toChars());
2199 result = CTFEExp.cantexp;
2200 return;
2201 }
2202
2203 if (v.storage_class & (STC.out_ | STC.ref_))
2204 {
2205 // Strip off the nest of ref variables
2206 Expression ev = getValue(v);
2207 if (ev.op == EXP.variable ||
2208 ev.op == EXP.index ||
2209 (ev.op == EXP.slice && ev.type.toBasetype().ty == Tsarray) ||
2210 ev.op == EXP.dotVariable)
2211 {
2212 result = interpret(pue, ev, istate, goal);
2213 return;
2214 }
2215 }
2216 }
2217 result = e;
2218 return;
2219 }
2220 result = getVarExp(e.loc, istate, e.var, goal);
2221 if (exceptionOrCant(result))
2222 return;
2223
2224 // Visit the default initializer for noreturn variables
2225 // (Custom initializers would abort the current function call and exit above)
2226 if (result.type.ty == Tnoreturn)
2227 {
2228 result.accept(this);
2229 return;
2230 }
2231
2232 if ((e.var.storage_class & (STC.ref_ | STC.out_)) == 0 && e.type.baseElemOf().ty != Tstruct)
2233 {
2234 /* Ultimately, STC.ref_|STC.out_ check should be enough to see the
2235 * necessity of type repainting. But currently front-end paints
2236 * non-ref struct variables by the const type.
2237 *
2238 * auto foo(ref const S cs);
2239 * S s;
2240 * foo(s); // VarExp('s') will have const(S)
2241 */
2242 // A VarExp may include an implicit cast. It must be done explicitly.
2243 result = paintTypeOntoLiteral(pue, e.type, result);
2244 }
2245 }
2246
2247 override void visit(DeclarationExp e)
2248 {
2249 debug (LOG)
2250 {
2251 printf("%s DeclarationExp::interpret() %s\n", e.loc.toChars(), e.toChars());
2252 }
2253 Dsymbol s = e.declaration;
2254 while (s.isAttribDeclaration())
2255 {
2256 auto ad = cast(AttribDeclaration)s;
2257 assert(ad.decl && ad.decl.dim == 1); // Currently, only one allowed when parsing
2258 s = (*ad.decl)[0];
2259 }
2260 if (VarDeclaration v = s.isVarDeclaration())
2261 {
2262 if (TupleDeclaration td = v.toAlias().isTupleDeclaration())
2263 {
2264 result = null;
2265
2266 // Reserve stack space for all tuple members
2267 if (!td.objects)
2268 return;
2269 foreach (o; *td.objects)
2270 {
2271 Expression ex = isExpression(o);
2272 DsymbolExp ds = ex ? ex.isDsymbolExp() : null;
2273 VarDeclaration v2 = ds ? ds.s.isVarDeclaration() : null;
2274 assert(v2);
2275 if (v2.isDataseg() && !v2.isCTFE())
2276 continue;
2277
2278 ctfeGlobals.stack.push(v2);
2279 if (v2._init)
2280 {
2281 Expression einit;
2282 if (ExpInitializer ie = v2._init.isExpInitializer())
2283 {
2284 einit = interpretRegion(ie.exp, istate, goal);
2285 if (exceptionOrCant(einit))
2286 return;
2287 }
2288 else if (v2._init.isVoidInitializer())
2289 {
2290 einit = voidInitLiteral(v2.type, v2).copy();
2291 }
2292 else
2293 {
2294 e.error("declaration `%s` is not yet implemented in CTFE", e.toChars());
2295 result = CTFEExp.cantexp;
2296 return;
2297 }
2298 setValue(v2, einit);
2299 }
2300 }
2301 return;
2302 }
2303 if (v.isStatic())
2304 {
2305 // Just ignore static variables which aren't read or written yet
2306 result = null;
2307 return;
2308 }
2309 if (!(v.isDataseg() || v.storage_class & STC.manifest) || v.isCTFE())
2310 ctfeGlobals.stack.push(v);
2311 if (v._init)
2312 {
2313 if (ExpInitializer ie = v._init.isExpInitializer())
2314 {
2315 result = interpretRegion(ie.exp, istate, goal);
2316 }
2317 else if (v._init.isVoidInitializer())
2318 {
2319 result = voidInitLiteral(v.type, v).copy();
2320 // There is no AssignExp for void initializers,
2321 // so set it here.
2322 setValue(v, result);
2323 }
2324 else
2325 {
2326 e.error("declaration `%s` is not yet implemented in CTFE", e.toChars());
2327 result = CTFEExp.cantexp;
2328 }
2329 }
2330 else if (v.type.size() == 0)
2331 {
2332 // Zero-length arrays don't need an initializer
2333 result = v.type.defaultInitLiteral(e.loc);
2334 }
2335 else
2336 {
2337 e.error("variable `%s` cannot be modified at compile time", v.toChars());
2338 result = CTFEExp.cantexp;
2339 }
2340 return;
2341 }
2342 if (s.isTemplateMixin() || s.isTupleDeclaration())
2343 {
2344 // These can be made to work, too lazy now
2345 e.error("declaration `%s` is not yet implemented in CTFE", e.toChars());
2346 result = CTFEExp.cantexp;
2347 return;
2348 }
2349
2350 // Others should not contain executable code, so are trivial to evaluate
2351 result = null;
2352 debug (LOG)
2353 {
2354 printf("-DeclarationExp::interpret(%s): %p\n", e.toChars(), result);
2355 }
2356 }
2357
2358 override void visit(TypeidExp e)
2359 {
2360 debug (LOG)
2361 {
2362 printf("%s TypeidExp::interpret() %s\n", e.loc.toChars(), e.toChars());
2363 }
2364 if (Type t = isType(e.obj))
2365 {
2366 result = e;
2367 return;
2368 }
2369 if (Expression ex = isExpression(e.obj))
2370 {
2371 result = interpret(pue, ex, istate);
2372 if (exceptionOrCant(ex))
2373 return;
2374
2375 if (result.op == EXP.null_)
2376 {
2377 e.error("null pointer dereference evaluating typeid. `%s` is `null`", ex.toChars());
2378 result = CTFEExp.cantexp;
2379 return;
2380 }
2381 if (result.op != EXP.classReference)
2382 {
2383 e.error("CTFE internal error: determining classinfo");
2384 result = CTFEExp.cantexp;
2385 return;
2386 }
2387
2388 ClassDeclaration cd = (cast(ClassReferenceExp)result).originalClass();
2389 assert(cd);
2390
2391 emplaceExp!(TypeidExp)(pue, e.loc, cd.type);
2392 result = pue.exp();
2393 result.type = e.type;
2394 return;
2395 }
2396 visit(cast(Expression)e);
2397 }
2398
2399 override void visit(TupleExp e)
2400 {
2401 debug (LOG)
2402 {
2403 printf("%s TupleExp::interpret() %s\n", e.loc.toChars(), e.toChars());
2404 }
2405 if (exceptionOrCant(interpretRegion(e.e0, istate, CTFEGoal.Nothing)))
2406 return;
2407
2408 auto expsx = e.exps;
2409 foreach (i, exp; *expsx)
2410 {
2411 Expression ex = interpretRegion(exp, istate);
2412 if (exceptionOrCant(ex))
2413 return;
2414
2415 // A tuple of assignments can contain void (Bug 5676).
2416 if (goal == CTFEGoal.Nothing)
2417 continue;
2418 if (ex.op == EXP.voidExpression)
2419 {
2420 e.error("CTFE internal error: void element `%s` in tuple", exp.toChars());
2421 assert(0);
2422 }
2423
2424 /* If any changes, do Copy On Write
2425 */
2426 if (ex !is exp)
2427 {
2428 expsx = copyArrayOnWrite(expsx, e.exps);
2429 (*expsx)[i] = copyRegionExp(ex);
2430 }
2431 }
2432
2433 if (expsx !is e.exps)
2434 {
2435 expandTuples(expsx);
2436 emplaceExp!(TupleExp)(pue, e.loc, expsx);
2437 result = pue.exp();
2438 result.type = new TypeTuple(expsx);
2439 }
2440 else
2441 result = e;
2442 }
2443
2444 override void visit(ArrayLiteralExp e)
2445 {
2446 debug (LOG)
2447 {
2448 printf("%s ArrayLiteralExp::interpret() %s\n", e.loc.toChars(), e.toChars());
2449 }
2450 if (e.ownedByCtfe >= OwnedBy.ctfe) // We've already interpreted all the elements
2451 {
2452 result = e;
2453 return;
2454 }
2455
2456 Type tn = e.type.toBasetype().nextOf().toBasetype();
2457 bool wantCopy = (tn.ty == Tsarray || tn.ty == Tstruct);
2458
2459 auto basis = interpretRegion(e.basis, istate);
2460 if (exceptionOrCant(basis))
2461 return;
2462
2463 auto expsx = e.elements;
2464 size_t dim = expsx ? expsx.dim : 0;
2465 for (size_t i = 0; i < dim; i++)
2466 {
2467 Expression exp = (*expsx)[i];
2468 Expression ex;
2469 if (!exp)
2470 {
2471 ex = copyLiteral(basis).copy();
2472 }
2473 else
2474 {
2475 // segfault bug 6250
2476 assert(exp.op != EXP.index || (cast(IndexExp)exp).e1 != e);
2477
2478 ex = interpretRegion(exp, istate);
2479 if (exceptionOrCant(ex))
2480 return;
2481
2482 /* Each elements should have distinct CTFE memory.
2483 * int[1] z = 7;
2484 * int[1][] pieces = [z,z]; // here
2485 */
2486 if (wantCopy)
2487 ex = copyLiteral(ex).copy();
2488 }
2489
2490 /* If any changes, do Copy On Write
2491 */
2492 if (ex !is exp)
2493 {
2494 expsx = copyArrayOnWrite(expsx, e.elements);
2495 (*expsx)[i] = ex;
2496 }
2497 }
2498
2499 if (expsx !is e.elements)
2500 {
2501 // todo: all tuple expansions should go in semantic phase.
2502 expandTuples(expsx);
2503 if (expsx.dim != dim)
2504 {
2505 e.error("CTFE internal error: invalid array literal");
2506 result = CTFEExp.cantexp;
2507 return;
2508 }
2509 emplaceExp!(ArrayLiteralExp)(pue, e.loc, e.type, basis, expsx);
2510 auto ale = cast(ArrayLiteralExp)pue.exp();
2511 ale.ownedByCtfe = OwnedBy.ctfe;
2512 result = ale;
2513 }
2514 else if ((cast(TypeNext)e.type).next.mod & (MODFlags.const_ | MODFlags.immutable_))
2515 {
2516 // If it's immutable, we don't need to dup it
2517 result = e;
2518 }
2519 else
2520 {
2521 *pue = copyLiteral(e);
2522 result = pue.exp();
2523 }
2524 }
2525
2526 override void visit(AssocArrayLiteralExp e)
2527 {
2528 debug (LOG)
2529 {
2530 printf("%s AssocArrayLiteralExp::interpret() %s\n", e.loc.toChars(), e.toChars());
2531 }
2532 if (e.ownedByCtfe >= OwnedBy.ctfe) // We've already interpreted all the elements
2533 {
2534 result = e;
2535 return;
2536 }
2537
2538 auto keysx = e.keys;
2539 auto valuesx = e.values;
2540 foreach (i, ekey; *keysx)
2541 {
2542 auto evalue = (*valuesx)[i];
2543
2544 auto ek = interpretRegion(ekey, istate);
2545 if (exceptionOrCant(ek))
2546 return;
2547 auto ev = interpretRegion(evalue, istate);
2548 if (exceptionOrCant(ev))
2549 return;
2550
2551 /* If any changes, do Copy On Write
2552 */
2553 if (ek !is ekey ||
2554 ev !is evalue)
2555 {
2556 keysx = copyArrayOnWrite(keysx, e.keys);
2557 valuesx = copyArrayOnWrite(valuesx, e.values);
2558 (*keysx)[i] = ek;
2559 (*valuesx)[i] = ev;
2560 }
2561 }
2562 if (keysx !is e.keys)
2563 expandTuples(keysx);
2564 if (valuesx !is e.values)
2565 expandTuples(valuesx);
2566 if (keysx.dim != valuesx.dim)
2567 {
2568 e.error("CTFE internal error: invalid AA");
2569 result = CTFEExp.cantexp;
2570 return;
2571 }
2572
2573 /* Remove duplicate keys
2574 */
2575 for (size_t i = 1; i < keysx.dim; i++)
2576 {
2577 auto ekey = (*keysx)[i - 1];
2578 for (size_t j = i; j < keysx.dim; j++)
2579 {
2580 auto ekey2 = (*keysx)[j];
2581 if (!ctfeEqual(e.loc, EXP.equal, ekey, ekey2))
2582 continue;
2583
2584 // Remove ekey
2585 keysx = copyArrayOnWrite(keysx, e.keys);
2586 valuesx = copyArrayOnWrite(valuesx, e.values);
2587 keysx.remove(i - 1);
2588 valuesx.remove(i - 1);
2589
2590 i -= 1; // redo the i'th iteration
2591 break;
2592 }
2593 }
2594
2595 if (keysx !is e.keys ||
2596 valuesx !is e.values)
2597 {
2598 assert(keysx !is e.keys &&
2599 valuesx !is e.values);
2600 auto aae = ctfeEmplaceExp!AssocArrayLiteralExp(e.loc, keysx, valuesx);
2601 aae.type = e.type;
2602 aae.ownedByCtfe = OwnedBy.ctfe;
2603 result = aae;
2604 }
2605 else
2606 {
2607 *pue = copyLiteral(e);
2608 result = pue.exp();
2609 }
2610 }
2611
2612 override void visit(StructLiteralExp e)
2613 {
2614 debug (LOG)
2615 {
2616 printf("%s StructLiteralExp::interpret() %s ownedByCtfe = %d\n", e.loc.toChars(), e.toChars(), e.ownedByCtfe);
2617 }
2618 if (e.ownedByCtfe >= OwnedBy.ctfe)
2619 {
2620 result = e;
2621 return;
2622 }
2623
2624 size_t dim = e.elements ? e.elements.dim : 0;
2625 auto expsx = e.elements;
2626
2627 if (dim != e.sd.fields.dim)
2628 {
2629 // guaranteed by AggregateDeclaration.fill and TypeStruct.defaultInitLiteral
2630 const nvthis = e.sd.fields.dim - e.sd.nonHiddenFields();
2631 assert(e.sd.fields.dim - dim == nvthis);
2632
2633 /* If a nested struct has no initialized hidden pointer,
2634 * set it to null to match the runtime behaviour.
2635 */
2636 foreach (const i; 0 .. nvthis)
2637 {
2638 auto ne = ctfeEmplaceExp!NullExp(e.loc);
2639 auto vthis = i == 0 ? e.sd.vthis : e.sd.vthis2;
2640 ne.type = vthis.type;
2641
2642 expsx = copyArrayOnWrite(expsx, e.elements);
2643 expsx.push(ne);
2644 ++dim;
2645 }
2646 }
2647 assert(dim == e.sd.fields.dim);
2648
2649 foreach (i; 0 .. dim)
2650 {
2651 auto v = e.sd.fields[i];
2652 Expression exp = (*expsx)[i];
2653 Expression ex;
2654 if (!exp)
2655 {
2656 ex = voidInitLiteral(v.type, v).copy();
2657 }
2658 else
2659 {
2660 ex = interpretRegion(exp, istate);
2661 if (exceptionOrCant(ex))
2662 return;
2663 if ((v.type.ty != ex.type.ty) && v.type.ty == Tsarray)
2664 {
2665 // Block assignment from inside struct literals
2666 auto tsa = cast(TypeSArray)v.type;
2667 auto len = cast(size_t)tsa.dim.toInteger();
2668 UnionExp ue = void;
2669 ex = createBlockDuplicatedArrayLiteral(&ue, ex.loc, v.type, ex, len);
2670 if (ex == ue.exp())
2671 ex = ue.copy();
2672 }
2673 }
2674
2675 /* If any changes, do Copy On Write
2676 */
2677 if (ex !is exp)
2678 {
2679 expsx = copyArrayOnWrite(expsx, e.elements);
2680 (*expsx)[i] = ex;
2681 }
2682 }
2683
2684 if (expsx !is e.elements)
2685 {
2686 expandTuples(expsx);
2687 if (expsx.dim != e.sd.fields.dim)
2688 {
2689 e.error("CTFE internal error: invalid struct literal");
2690 result = CTFEExp.cantexp;
2691 return;
2692 }
2693 emplaceExp!(StructLiteralExp)(pue, e.loc, e.sd, expsx);
2694 auto sle = cast(StructLiteralExp)pue.exp();
2695 sle.type = e.type;
2696 sle.ownedByCtfe = OwnedBy.ctfe;
2697 sle.origin = e.origin;
2698 result = sle;
2699 }
2700 else
2701 {
2702 *pue = copyLiteral(e);
2703 result = pue.exp();
2704 }
2705 }
2706
2707 // Create an array literal of type 'newtype' with dimensions given by
2708 // 'arguments'[argnum..$]
2709 static Expression recursivelyCreateArrayLiteral(UnionExp* pue, const ref Loc loc, Type newtype, InterState* istate, Expressions* arguments, int argnum)
2710 {
2711 Expression lenExpr = interpret(pue, (*arguments)[argnum], istate);
2712 if (exceptionOrCantInterpret(lenExpr))
2713 return lenExpr;
2714 size_t len = cast(size_t)lenExpr.toInteger();
2715 Type elemType = (cast(TypeArray)newtype).next;
2716 if (elemType.ty == Tarray && argnum < arguments.dim - 1)
2717 {
2718 Expression elem = recursivelyCreateArrayLiteral(pue, loc, elemType, istate, arguments, argnum + 1);
2719 if (exceptionOrCantInterpret(elem))
2720 return elem;
2721
2722 auto elements = new Expressions(len);
2723 foreach (ref element; *elements)
2724 element = copyLiteral(elem).copy();
2725 emplaceExp!(ArrayLiteralExp)(pue, loc, newtype, elements);
2726 auto ae = cast(ArrayLiteralExp)pue.exp();
2727 ae.ownedByCtfe = OwnedBy.ctfe;
2728 return ae;
2729 }
2730 assert(argnum == arguments.dim - 1);
2731 if (elemType.ty.isSomeChar)
2732 {
2733 const ch = cast(dchar)elemType.defaultInitLiteral(loc).toInteger();
2734 const sz = cast(ubyte)elemType.size();
2735 return createBlockDuplicatedStringLiteral(pue, loc, newtype, ch, len, sz);
2736 }
2737 else
2738 {
2739 auto el = interpret(elemType.defaultInitLiteral(loc), istate);
2740 return createBlockDuplicatedArrayLiteral(pue, loc, newtype, el, len);
2741 }
2742 }
2743
2744 override void visit(NewExp e)
2745 {
2746 debug (LOG)
2747 {
2748 printf("%s NewExp::interpret() %s\n", e.loc.toChars(), e.toChars());
2749 }
2750
2751 Expression epre = interpret(pue, e.argprefix, istate, CTFEGoal.Nothing);
2752 if (exceptionOrCant(epre))
2753 return;
2754
2755 if (e.newtype.ty == Tarray && e.arguments)
2756 {
2757 result = recursivelyCreateArrayLiteral(pue, e.loc, e.newtype, istate, e.arguments, 0);
2758 return;
2759 }
2760 if (auto ts = e.newtype.toBasetype().isTypeStruct())
2761 {
2762 if (e.member)
2763 {
2764 Expression se = e.newtype.defaultInitLiteral(e.loc);
2765 se = interpret(se, istate);
2766 if (exceptionOrCant(se))
2767 return;
2768 result = interpretFunction(pue, e.member, istate, e.arguments, se);
2769
2770 // Repaint as same as CallExp::interpret() does.
2771 result.loc = e.loc;
2772 }
2773 else
2774 {
2775 StructDeclaration sd = ts.sym;
2776 auto exps = new Expressions();
2777 exps.reserve(sd.fields.dim);
2778 if (e.arguments)
2779 {
2780 exps.setDim(e.arguments.dim);
2781 foreach (i, ex; *e.arguments)
2782 {
2783 ex = interpretRegion(ex, istate);
2784 if (exceptionOrCant(ex))
2785 return;
2786 (*exps)[i] = ex;
2787 }
2788 }
2789 sd.fill(e.loc, exps, false);
2790
2791 auto se = ctfeEmplaceExp!StructLiteralExp(e.loc, sd, exps, e.newtype);
2792 se.origin = se;
2793 se.type = e.newtype;
2794 se.ownedByCtfe = OwnedBy.ctfe;
2795 result = interpret(pue, se, istate);
2796 }
2797 if (exceptionOrCant(result))
2798 return;
2799 Expression ev = (result == pue.exp()) ? pue.copy() : result;
2800 emplaceExp!(AddrExp)(pue, e.loc, ev, e.type);
2801 result = pue.exp();
2802 return;
2803 }
2804 if (auto tc = e.newtype.toBasetype().isTypeClass())
2805 {
2806 ClassDeclaration cd = tc.sym;
2807 size_t totalFieldCount = 0;
2808 for (ClassDeclaration c = cd; c; c = c.baseClass)
2809 totalFieldCount += c.fields.dim;
2810 auto elems = new Expressions(totalFieldCount);
2811 size_t fieldsSoFar = totalFieldCount;
2812 for (ClassDeclaration c = cd; c; c = c.baseClass)
2813 {
2814 fieldsSoFar -= c.fields.dim;
2815 foreach (i, v; c.fields)
2816 {
2817 if (v.inuse)
2818 {
2819 e.error("circular reference to `%s`", v.toPrettyChars());
2820 result = CTFEExp.cantexp;
2821 return;
2822 }
2823 Expression m;
2824 if (v._init)
2825 {
2826 if (v._init.isVoidInitializer())
2827 m = voidInitLiteral(v.type, v).copy();
2828 else
2829 m = v.getConstInitializer(true);
2830 }
2831 else
2832 m = v.type.defaultInitLiteral(e.loc);
2833 if (exceptionOrCant(m))
2834 return;
2835 (*elems)[fieldsSoFar + i] = copyLiteral(m).copy();
2836 }
2837 }
2838 // Hack: we store a ClassDeclaration instead of a StructDeclaration.
2839 // We probably won't get away with this.
2840 // auto se = new StructLiteralExp(e.loc, cast(StructDeclaration)cd, elems, e.newtype);
2841 auto se = ctfeEmplaceExp!StructLiteralExp(e.loc, cast(StructDeclaration)cd, elems, e.newtype);
2842 se.origin = se;
2843 se.ownedByCtfe = OwnedBy.ctfe;
2844 Expression eref = ctfeEmplaceExp!ClassReferenceExp(e.loc, se, e.type);
2845 if (e.member)
2846 {
2847 // Call constructor
2848 if (!e.member.fbody)
2849 {
2850 Expression ctorfail = evaluateIfBuiltin(pue, istate, e.loc, e.member, e.arguments, eref);
2851 if (ctorfail)
2852 {
2853 if (exceptionOrCant(ctorfail))
2854 return;
2855 result = eref;
2856 return;
2857 }
2858 e.member.error("`%s` cannot be constructed at compile time, because the constructor has no available source code", e.newtype.toChars());
2859 result = CTFEExp.cantexp;
2860 return;
2861 }
2862 UnionExp ue = void;
2863 Expression ctorfail = interpretFunction(&ue, e.member, istate, e.arguments, eref);
2864 if (exceptionOrCant(ctorfail))
2865 return;
2866
2867 /* https://issues.dlang.org/show_bug.cgi?id=14465
2868 * Repaint the loc, because a super() call
2869 * in the constructor modifies the loc of ClassReferenceExp
2870 * in CallExp::interpret().
2871 */
2872 eref.loc = e.loc;
2873 }
2874 result = eref;
2875 return;
2876 }
2877 if (e.newtype.toBasetype().isscalar())
2878 {
2879 Expression newval;
2880 if (e.arguments && e.arguments.dim)
2881 newval = (*e.arguments)[0];
2882 else
2883 newval = e.newtype.defaultInitLiteral(e.loc);
2884 newval = interpretRegion(newval, istate);
2885 if (exceptionOrCant(newval))
2886 return;
2887
2888 // Create a CTFE pointer &[newval][0]
2889 auto elements = new Expressions(1);
2890 (*elements)[0] = newval;
2891 auto ae = ctfeEmplaceExp!ArrayLiteralExp(e.loc, e.newtype.arrayOf(), elements);
2892 ae.ownedByCtfe = OwnedBy.ctfe;
2893
2894 auto ei = ctfeEmplaceExp!IndexExp(e.loc, ae, ctfeEmplaceExp!IntegerExp(Loc.initial, 0, Type.tsize_t));
2895 ei.type = e.newtype;
2896 emplaceExp!(AddrExp)(pue, e.loc, ei, e.type);
2897 result = pue.exp();
2898 return;
2899 }
2900 e.error("cannot interpret `%s` at compile time", e.toChars());
2901 result = CTFEExp.cantexp;
2902 }
2903
2904 override void visit(UnaExp e)
2905 {
2906 debug (LOG)
2907 {
2908 printf("%s UnaExp::interpret() %s\n", e.loc.toChars(), e.toChars());
2909 }
2910 UnionExp ue = void;
2911 Expression e1 = interpret(&ue, e.e1, istate);
2912 if (exceptionOrCant(e1))
2913 return;
2914 switch (e.op)
2915 {
2916 case EXP.negate:
2917 *pue = Neg(e.type, e1);
2918 break;
2919
2920 case EXP.tilde:
2921 *pue = Com(e.type, e1);
2922 break;
2923
2924 case EXP.not:
2925 *pue = Not(e.type, e1);
2926 break;
2927
2928 default:
2929 assert(0);
2930 }
2931 result = (*pue).exp();
2932 }
2933
2934 override void visit(DotTypeExp e)
2935 {
2936 debug (LOG)
2937 {
2938 printf("%s DotTypeExp::interpret() %s\n", e.loc.toChars(), e.toChars());
2939 }
2940 UnionExp ue = void;
2941 Expression e1 = interpret(&ue, e.e1, istate);
2942 if (exceptionOrCant(e1))
2943 return;
2944 if (e1 == e.e1)
2945 result = e; // optimize: reuse this CTFE reference
2946 else
2947 {
2948 auto edt = cast(DotTypeExp)e.copy();
2949 edt.e1 = (e1 == ue.exp()) ? e1.copy() : e1; // don't return pointer to ue
2950 result = edt;
2951 }
2952 }
2953
2954 extern (D) private void interpretCommon(BinExp e, fp_t fp)
2955 {
2956 debug (LOG)
2957 {
2958 printf("%s BinExp::interpretCommon() %s\n", e.loc.toChars(), e.toChars());
2959 }
2960 if (e.e1.type.ty == Tpointer && e.e2.type.ty == Tpointer && e.op == EXP.min)
2961 {
2962 UnionExp ue1 = void;
2963 Expression e1 = interpret(&ue1, e.e1, istate);
2964 if (exceptionOrCant(e1))
2965 return;
2966 UnionExp ue2 = void;
2967 Expression e2 = interpret(&ue2, e.e2, istate);
2968 if (exceptionOrCant(e2))
2969 return;
2970 *pue = pointerDifference(e.loc, e.type, e1, e2);
2971 result = (*pue).exp();
2972 return;
2973 }
2974 if (e.e1.type.ty == Tpointer && e.e2.type.isintegral())
2975 {
2976 UnionExp ue1 = void;
2977 Expression e1 = interpret(&ue1, e.e1, istate);
2978 if (exceptionOrCant(e1))
2979 return;
2980 UnionExp ue2 = void;
2981 Expression e2 = interpret(&ue2, e.e2, istate);
2982 if (exceptionOrCant(e2))
2983 return;
2984 *pue = pointerArithmetic(e.loc, e.op, e.type, e1, e2);
2985 result = (*pue).exp();
2986 return;
2987 }
2988 if (e.e2.type.ty == Tpointer && e.e1.type.isintegral() && e.op == EXP.add)
2989 {
2990 UnionExp ue1 = void;
2991 Expression e1 = interpret(&ue1, e.e1, istate);
2992 if (exceptionOrCant(e1))
2993 return;
2994 UnionExp ue2 = void;
2995 Expression e2 = interpret(&ue2, e.e2, istate);
2996 if (exceptionOrCant(e2))
2997 return;
2998 *pue = pointerArithmetic(e.loc, e.op, e.type, e2, e1);
2999 result = (*pue).exp();
3000 return;
3001 }
3002 if (e.e1.type.ty == Tpointer || e.e2.type.ty == Tpointer)
3003 {
3004 e.error("pointer expression `%s` cannot be interpreted at compile time", e.toChars());
3005 result = CTFEExp.cantexp;
3006 return;
3007 }
3008
3009 bool evalOperand(UnionExp* pue, Expression ex, out Expression er)
3010 {
3011 er = interpret(pue, ex, istate);
3012 if (exceptionOrCant(er))
3013 return false;
3014 return true;
3015 }
3016
3017 UnionExp ue1 = void;
3018 Expression e1;
3019 if (!evalOperand(&ue1, e.e1, e1))
3020 return;
3021
3022 UnionExp ue2 = void;
3023 Expression e2;
3024 if (!evalOperand(&ue2, e.e2, e2))
3025 return;
3026
3027 if (e.op == EXP.rightShift || e.op == EXP.leftShift || e.op == EXP.unsignedRightShift)
3028 {
3029 const sinteger_t i2 = e2.toInteger();
3030 const d_uns64 sz = e1.type.size() * 8;
3031 if (i2 < 0 || i2 >= sz)
3032 {
3033 e.error("shift by %lld is outside the range 0..%llu", i2, cast(ulong)sz - 1);
3034 result = CTFEExp.cantexp;
3035 return;
3036 }
3037 }
3038
3039 /******************************************
3040 * Perform the operation fp on operands e1 and e2.
3041 */
3042 UnionExp evaluate(Loc loc, Type type, Expression e1, Expression e2)
3043 {
3044 UnionExp ue = void;
3045 auto ae1 = e1.isArrayLiteralExp();
3046 auto ae2 = e2.isArrayLiteralExp();
3047 if (ae1 || ae2)
3048 {
3049 /* Cases:
3050 * 1. T[] op T[]
3051 * 2. T op T[]
3052 * 3. T[] op T
3053 */
3054 if (ae1 && e2.implicitConvTo(e1.type.toBasetype().nextOf())) // case 3
3055 ae2 = null;
3056 else if (ae2 && e1.implicitConvTo(e2.type.toBasetype().nextOf())) // case 2
3057 ae1 = null;
3058 // else case 1
3059
3060 auto aex = ae1 ? ae1 : ae2;
3061 if (!aex.elements)
3062 {
3063 emplaceExp!ArrayLiteralExp(&ue, loc, type, cast(Expressions*) null);
3064 return ue;
3065 }
3066 const length = aex.elements.length;
3067 Expressions* elements = new Expressions(length);
3068
3069 emplaceExp!ArrayLiteralExp(&ue, loc, type, elements);
3070 foreach (i; 0 .. length)
3071 {
3072 Expression e1x = ae1 ? ae1[i] : e1;
3073 Expression e2x = ae2 ? ae2[i] : e2;
3074 UnionExp uex = evaluate(loc, e1x.type, e1x, e2x);
3075 // This can be made more efficient by making use of ue.basis
3076 (*elements)[i] = uex.copy();
3077 }
3078 return ue;
3079 }
3080
3081 if (e1.isConst() != 1)
3082 {
3083 // The following should really be an assert()
3084 e1.error("CTFE internal error: non-constant value `%s`", e1.toChars());
3085 emplaceExp!CTFEExp(&ue, EXP.cantExpression);
3086 return ue;
3087 }
3088 if (e2.isConst() != 1)
3089 {
3090 e2.error("CTFE internal error: non-constant value `%s`", e2.toChars());
3091 emplaceExp!CTFEExp(&ue, EXP.cantExpression);
3092 return ue;
3093 }
3094
3095 return (*fp)(loc, type, e1, e2);
3096 }
3097
3098 *pue = evaluate(e.loc, e.type, e1, e2);
3099 result = (*pue).exp();
3100 if (CTFEExp.isCantExp(result))
3101 e.error("`%s` cannot be interpreted at compile time", e.toChars());
3102 }
3103
3104 extern (D) private void interpretCompareCommon(BinExp e, fp2_t fp)
3105 {
3106 debug (LOG)
3107 {
3108 printf("%s BinExp::interpretCompareCommon() %s\n", e.loc.toChars(), e.toChars());
3109 }
3110 UnionExp ue1 = void;
3111 UnionExp ue2 = void;
3112 if (e.e1.type.ty == Tpointer && e.e2.type.ty == Tpointer)
3113 {
3114 Expression e1 = interpret(&ue1, e.e1, istate);
3115 if (exceptionOrCant(e1))
3116 return;
3117 Expression e2 = interpret(&ue2, e.e2, istate);
3118 if (exceptionOrCant(e2))
3119 return;
3120 //printf("e1 = %s %s, e2 = %s %s\n", e1.type.toChars(), e1.toChars(), e2.type.toChars(), e2.toChars());
3121 dinteger_t ofs1, ofs2;
3122 Expression agg1 = getAggregateFromPointer(e1, &ofs1);
3123 Expression agg2 = getAggregateFromPointer(e2, &ofs2);
3124 //printf("agg1 = %p %s, agg2 = %p %s\n", agg1, agg1.toChars(), agg2, agg2.toChars());
3125 const cmp = comparePointers(e.op, agg1, ofs1, agg2, ofs2);
3126 if (cmp == -1)
3127 {
3128 char dir = (e.op == EXP.greaterThan || e.op == EXP.greaterOrEqual) ? '<' : '>';
3129 e.error("the ordering of pointers to unrelated memory blocks is indeterminate in CTFE. To check if they point to the same memory block, use both `>` and `<` inside `&&` or `||`, eg `%s && %s %c= %s + 1`", e.toChars(), e.e1.toChars(), dir, e.e2.toChars());
3130 result = CTFEExp.cantexp;
3131 return;
3132 }
3133 if (e.type.equals(Type.tbool))
3134 result = IntegerExp.createBool(cmp != 0);
3135 else
3136 {
3137 emplaceExp!(IntegerExp)(pue, e.loc, cmp, e.type);
3138 result = (*pue).exp();
3139 }
3140 return;
3141 }
3142 Expression e1 = interpret(&ue1, e.e1, istate);
3143 if (exceptionOrCant(e1))
3144 return;
3145 if (!isCtfeComparable(e1))
3146 {
3147 e.error("cannot compare `%s` at compile time", e1.toChars());
3148 result = CTFEExp.cantexp;
3149 return;
3150 }
3151 Expression e2 = interpret(&ue2, e.e2, istate);
3152 if (exceptionOrCant(e2))
3153 return;
3154 if (!isCtfeComparable(e2))
3155 {
3156 e.error("cannot compare `%s` at compile time", e2.toChars());
3157 result = CTFEExp.cantexp;
3158 return;
3159 }
3160 const cmp = (*fp)(e.loc, e.op, e1, e2);
3161 if (e.type.equals(Type.tbool))
3162 result = IntegerExp.createBool(cmp);
3163 else
3164 {
3165 emplaceExp!(IntegerExp)(pue, e.loc, cmp, e.type);
3166 result = (*pue).exp();
3167 }
3168 }
3169
3170 override void visit(BinExp e)
3171 {
3172 switch (e.op)
3173 {
3174 case EXP.add:
3175 interpretCommon(e, &Add);
3176 return;
3177
3178 case EXP.min:
3179 interpretCommon(e, &Min);
3180 return;
3181
3182 case EXP.mul:
3183 interpretCommon(e, &Mul);
3184 return;
3185
3186 case EXP.div:
3187 interpretCommon(e, &Div);
3188 return;
3189
3190 case EXP.mod:
3191 interpretCommon(e, &Mod);
3192 return;
3193
3194 case EXP.leftShift:
3195 interpretCommon(e, &Shl);
3196 return;
3197
3198 case EXP.rightShift:
3199 interpretCommon(e, &Shr);
3200 return;
3201
3202 case EXP.unsignedRightShift:
3203 interpretCommon(e, &Ushr);
3204 return;
3205
3206 case EXP.and:
3207 interpretCommon(e, &And);
3208 return;
3209
3210 case EXP.or:
3211 interpretCommon(e, &Or);
3212 return;
3213
3214 case EXP.xor:
3215 interpretCommon(e, &Xor);
3216 return;
3217
3218 case EXP.pow:
3219 interpretCommon(e, &Pow);
3220 return;
3221
3222 case EXP.equal:
3223 case EXP.notEqual:
3224 interpretCompareCommon(e, &ctfeEqual);
3225 return;
3226
3227 case EXP.identity:
3228 case EXP.notIdentity:
3229 interpretCompareCommon(e, &ctfeIdentity);
3230 return;
3231
3232 case EXP.lessThan:
3233 case EXP.lessOrEqual:
3234 case EXP.greaterThan:
3235 case EXP.greaterOrEqual:
3236 interpretCompareCommon(e, &ctfeCmp);
3237 return;
3238
3239 default:
3240 printf("be = '%s' %s at [%s]\n", EXPtoString(e.op).ptr, e.toChars(), e.loc.toChars());
3241 assert(0);
3242 }
3243 }
3244
3245 /* Helper functions for BinExp::interpretAssignCommon
3246 */
3247 // Returns the variable which is eventually modified, or NULL if an rvalue.
3248 // thisval is the current value of 'this'.
3249 static VarDeclaration findParentVar(Expression e)
3250 {
3251 for (;;)
3252 {
3253 if (auto ve = e.isVarExp())
3254 {
3255 VarDeclaration v = ve.var.isVarDeclaration();
3256 assert(v);
3257 return v;
3258 }
3259 if (auto ie = e.isIndexExp())
3260 e = ie.e1;
3261 else if (auto dve = e.isDotVarExp())
3262 e = dve.e1;
3263 else if (auto dtie = e.isDotTemplateInstanceExp())
3264 e = dtie.e1;
3265 else if (auto se = e.isSliceExp())
3266 e = se.e1;
3267 else
3268 return null;
3269 }
3270 }
3271
3272 extern (D) private void interpretAssignCommon(BinExp e, fp_t fp, int post = 0)
3273 {
3274 debug (LOG)
3275 {
3276 printf("%s BinExp::interpretAssignCommon() %s\n", e.loc.toChars(), e.toChars());
3277 }
3278 result = CTFEExp.cantexp;
3279
3280 Expression e1 = e.e1;
3281 if (!istate)
3282 {
3283 e.error("value of `%s` is not known at compile time", e1.toChars());
3284 return;
3285 }
3286
3287 ++ctfeGlobals.numAssignments;
3288
3289 /* Before we begin, we need to know if this is a reference assignment
3290 * (dynamic array, AA, or class) or a value assignment.
3291 * Determining this for slice assignments are tricky: we need to know
3292 * if it is a block assignment (a[] = e) rather than a direct slice
3293 * assignment (a[] = b[]). Note that initializers of multi-dimensional
3294 * static arrays can have 2D block assignments (eg, int[7][7] x = 6;).
3295 * So we need to recurse to determine if it is a block assignment.
3296 */
3297 bool isBlockAssignment = false;
3298 if (e1.op == EXP.slice)
3299 {
3300 // a[] = e can have const e. So we compare the naked types.
3301 Type tdst = e1.type.toBasetype();
3302 Type tsrc = e.e2.type.toBasetype();
3303 while (tdst.ty == Tsarray || tdst.ty == Tarray)
3304 {
3305 tdst = (cast(TypeArray)tdst).next.toBasetype();
3306 if (tsrc.equivalent(tdst))
3307 {
3308 isBlockAssignment = true;
3309 break;
3310 }
3311 }
3312 }
3313
3314 // ---------------------------------------
3315 // Deal with reference assignment
3316 // ---------------------------------------
3317 // If it is a construction of a ref variable, it is a ref assignment
3318 if ((e.op == EXP.construct || e.op == EXP.blit) &&
3319 ((cast(AssignExp)e).memset == MemorySet.referenceInit))
3320 {
3321 assert(!fp);
3322
3323 Expression newval = interpretRegion(e.e2, istate, CTFEGoal.LValue);
3324 if (exceptionOrCant(newval))
3325 return;
3326
3327 VarDeclaration v = (cast(VarExp)e1).var.isVarDeclaration();
3328 setValue(v, newval);
3329
3330 // Get the value to return. Note that 'newval' is an Lvalue,
3331 // so if we need an Rvalue, we have to interpret again.
3332 if (goal == CTFEGoal.RValue)
3333 result = interpretRegion(newval, istate);
3334 else
3335 result = e1; // VarExp is a CTFE reference
3336 return;
3337 }
3338
3339 if (fp)
3340 {
3341 while (e1.op == EXP.cast_)
3342 {
3343 CastExp ce = cast(CastExp)e1;
3344 e1 = ce.e1;
3345 }
3346 }
3347
3348 // ---------------------------------------
3349 // Interpret left hand side
3350 // ---------------------------------------
3351 AssocArrayLiteralExp existingAA = null;
3352 Expression lastIndex = null;
3353 Expression oldval = null;
3354 if (e1.op == EXP.index && (cast(IndexExp)e1).e1.type.toBasetype().ty == Taarray)
3355 {
3356 // ---------------------------------------
3357 // Deal with AA index assignment
3358 // ---------------------------------------
3359 /* This needs special treatment if the AA doesn't exist yet.
3360 * There are two special cases:
3361 * (1) If the AA is itself an index of another AA, we may need to create
3362 * multiple nested AA literals before we can insert the new value.
3363 * (2) If the ultimate AA is null, no insertion happens at all. Instead,
3364 * we create nested AA literals, and change it into a assignment.
3365 */
3366 IndexExp ie = cast(IndexExp)e1;
3367 int depth = 0; // how many nested AA indices are there?
3368 while (ie.e1.op == EXP.index && (cast(IndexExp)ie.e1).e1.type.toBasetype().ty == Taarray)
3369 {
3370 assert(ie.modifiable);
3371 ie = cast(IndexExp)ie.e1;
3372 ++depth;
3373 }
3374
3375 // Get the AA value to be modified.
3376 Expression aggregate = interpretRegion(ie.e1, istate);
3377 if (exceptionOrCant(aggregate))
3378 return;
3379 if ((existingAA = aggregate.isAssocArrayLiteralExp()) !is null)
3380 {
3381 // Normal case, ultimate parent AA already exists
3382 // We need to walk from the deepest index up, checking that an AA literal
3383 // already exists on each level.
3384 lastIndex = interpretRegion((cast(IndexExp)e1).e2, istate);
3385 lastIndex = resolveSlice(lastIndex); // only happens with AA assignment
3386 if (exceptionOrCant(lastIndex))
3387 return;
3388
3389 while (depth > 0)
3390 {
3391 // Walk the syntax tree to find the indexExp at this depth
3392 IndexExp xe = cast(IndexExp)e1;
3393 foreach (d; 0 .. depth)
3394 xe = cast(IndexExp)xe.e1;
3395
3396 Expression ekey = interpretRegion(xe.e2, istate);
3397 if (exceptionOrCant(ekey))
3398 return;
3399 UnionExp ekeyTmp = void;
3400 ekey = resolveSlice(ekey, &ekeyTmp); // only happens with AA assignment
3401
3402 // Look up this index in it up in the existing AA, to get the next level of AA.
3403 AssocArrayLiteralExp newAA = cast(AssocArrayLiteralExp)findKeyInAA(e.loc, existingAA, ekey);
3404 if (exceptionOrCant(newAA))
3405 return;
3406 if (!newAA)
3407 {
3408 // Doesn't exist yet, create an empty AA...
3409 auto keysx = new Expressions();
3410 auto valuesx = new Expressions();
3411 newAA = ctfeEmplaceExp!AssocArrayLiteralExp(e.loc, keysx, valuesx);
3412 newAA.type = xe.type;
3413 newAA.ownedByCtfe = OwnedBy.ctfe;
3414 //... and insert it into the existing AA.
3415 existingAA.keys.push(ekey);
3416 existingAA.values.push(newAA);
3417 }
3418 existingAA = newAA;
3419 --depth;
3420 }
3421
3422 if (fp)
3423 {
3424 oldval = findKeyInAA(e.loc, existingAA, lastIndex);
3425 if (!oldval)
3426 oldval = copyLiteral(e.e1.type.defaultInitLiteral(e.loc)).copy();
3427 }
3428 }
3429 else
3430 {
3431 /* The AA is currently null. 'aggregate' is actually a reference to
3432 * whatever contains it. It could be anything: var, dotvarexp, ...
3433 * We rewrite the assignment from:
3434 * aa[i][j] op= newval;
3435 * into:
3436 * aa = [i:[j:T.init]];
3437 * aa[j] op= newval;
3438 */
3439 oldval = copyLiteral(e.e1.type.defaultInitLiteral(e.loc)).copy();
3440
3441 Expression newaae = oldval;
3442 while (e1.op == EXP.index && (cast(IndexExp)e1).e1.type.toBasetype().ty == Taarray)
3443 {
3444 Expression ekey = interpretRegion((cast(IndexExp)e1).e2, istate);
3445 if (exceptionOrCant(ekey))
3446 return;
3447 ekey = resolveSlice(ekey); // only happens with AA assignment
3448
3449 auto keysx = new Expressions();
3450 auto valuesx = new Expressions();
3451 keysx.push(ekey);
3452 valuesx.push(newaae);
3453
3454 auto aae = ctfeEmplaceExp!AssocArrayLiteralExp(e.loc, keysx, valuesx);
3455 aae.type = (cast(IndexExp)e1).e1.type;
3456 aae.ownedByCtfe = OwnedBy.ctfe;
3457 if (!existingAA)
3458 {
3459 existingAA = aae;
3460 lastIndex = ekey;
3461 }
3462 newaae = aae;
3463 e1 = (cast(IndexExp)e1).e1;
3464 }
3465
3466 // We must set to aggregate with newaae
3467 e1 = interpretRegion(e1, istate, CTFEGoal.LValue);
3468 if (exceptionOrCant(e1))
3469 return;
3470 e1 = assignToLvalue(e, e1, newaae);
3471 if (exceptionOrCant(e1))
3472 return;
3473 }
3474 assert(existingAA && lastIndex);
3475 e1 = null; // stomp
3476 }
3477 else if (e1.op == EXP.arrayLength)
3478 {
3479 oldval = interpretRegion(e1, istate);
3480 if (exceptionOrCant(oldval))
3481 return;
3482 }
3483 else if (e.op == EXP.construct || e.op == EXP.blit)
3484 {
3485 // Unless we have a simple var assignment, we're
3486 // only modifying part of the variable. So we need to make sure
3487 // that the parent variable exists.
3488 VarDeclaration ultimateVar = findParentVar(e1);
3489 if (auto ve = e1.isVarExp())
3490 {
3491 VarDeclaration v = ve.var.isVarDeclaration();
3492 assert(v);
3493 if (v.storage_class & STC.out_)
3494 goto L1;
3495 }
3496 else if (ultimateVar && !getValue(ultimateVar))
3497 {
3498 Expression ex = interpretRegion(ultimateVar.type.defaultInitLiteral(e.loc), istate);
3499 if (exceptionOrCant(ex))
3500 return;
3501 setValue(ultimateVar, ex);
3502 }
3503 else
3504 goto L1;
3505 }
3506 else
3507 {
3508 L1:
3509 e1 = interpretRegion(e1, istate, CTFEGoal.LValue);
3510 if (exceptionOrCant(e1))
3511 return;
3512
3513 if (e1.op == EXP.index && (cast(IndexExp)e1).e1.type.toBasetype().ty == Taarray)
3514 {
3515 IndexExp ie = cast(IndexExp)e1;
3516 assert(ie.e1.op == EXP.assocArrayLiteral);
3517 existingAA = cast(AssocArrayLiteralExp)ie.e1;
3518 lastIndex = ie.e2;
3519 }
3520 }
3521
3522 // ---------------------------------------
3523 // Interpret right hand side
3524 // ---------------------------------------
3525 Expression newval = interpretRegion(e.e2, istate);
3526 if (exceptionOrCant(newval))
3527 return;
3528 if (e.op == EXP.blit && newval.op == EXP.int64)
3529 {
3530 Type tbn = e.type.baseElemOf();
3531 if (tbn.ty == Tstruct)
3532 {
3533 /* Look for special case of struct being initialized with 0.
3534 */
3535 newval = e.type.defaultInitLiteral(e.loc);
3536 if (newval.op == EXP.error)
3537 {
3538 result = CTFEExp.cantexp;
3539 return;
3540 }
3541 newval = interpretRegion(newval, istate); // copy and set ownedByCtfe flag
3542 if (exceptionOrCant(newval))
3543 return;
3544 }
3545 }
3546
3547 // ----------------------------------------------------
3548 // Deal with read-modify-write assignments.
3549 // Set 'newval' to the final assignment value
3550 // Also determine the return value (except for slice
3551 // assignments, which are more complicated)
3552 // ----------------------------------------------------
3553 if (fp)
3554 {
3555 if (!oldval)
3556 {
3557 // Load the left hand side after interpreting the right hand side.
3558 oldval = interpretRegion(e1, istate);
3559 if (exceptionOrCant(oldval))
3560 return;
3561 }
3562
3563 if (e.e1.type.ty != Tpointer)
3564 {
3565 // ~= can create new values (see bug 6052)
3566 if (e.op == EXP.concatenateAssign || e.op == EXP.concatenateElemAssign || e.op == EXP.concatenateDcharAssign)
3567 {
3568 // We need to dup it and repaint the type. For a dynamic array
3569 // we can skip duplication, because it gets copied later anyway.
3570 if (newval.type.ty != Tarray)
3571 {
3572 newval = copyLiteral(newval).copy();
3573 newval.type = e.e2.type; // repaint type
3574 }
3575 else
3576 {
3577 newval = paintTypeOntoLiteral(e.e2.type, newval);
3578 newval = resolveSlice(newval);
3579 }
3580 }
3581 oldval = resolveSlice(oldval);
3582
3583 newval = (*fp)(e.loc, e.type, oldval, newval).copy();
3584 }
3585 else if (e.e2.type.isintegral() &&
3586 (e.op == EXP.addAssign ||
3587 e.op == EXP.minAssign ||
3588 e.op == EXP.plusPlus ||
3589 e.op == EXP.minusMinus))
3590 {
3591 newval = pointerArithmetic(e.loc, e.op, e.type, oldval, newval).copy();
3592 }
3593 else
3594 {
3595 e.error("pointer expression `%s` cannot be interpreted at compile time", e.toChars());
3596 result = CTFEExp.cantexp;
3597 return;
3598 }
3599 if (exceptionOrCant(newval))
3600 {
3601 if (CTFEExp.isCantExp(newval))
3602 e.error("cannot interpret `%s` at compile time", e.toChars());
3603 return;
3604 }
3605 }
3606
3607 if (existingAA)
3608 {
3609 if (existingAA.ownedByCtfe != OwnedBy.ctfe)
3610 {
3611 e.error("cannot modify read-only constant `%s`", existingAA.toChars());
3612 result = CTFEExp.cantexp;
3613 return;
3614 }
3615
3616 //printf("\t+L%d existingAA = %s, lastIndex = %s, oldval = %s, newval = %s\n",
3617 // __LINE__, existingAA.toChars(), lastIndex.toChars(), oldval ? oldval.toChars() : NULL, newval.toChars());
3618 assignAssocArrayElement(e.loc, existingAA, lastIndex, newval);
3619
3620 // Determine the return value
3621 result = ctfeCast(pue, e.loc, e.type, e.type, fp && post ? oldval : newval);
3622 return;
3623 }
3624 if (e1.op == EXP.arrayLength)
3625 {
3626 /* Change the assignment from:
3627 * arr.length = n;
3628 * into:
3629 * arr = new_length_array; (result is n)
3630 */
3631
3632 // Determine the return value
3633 result = ctfeCast(pue, e.loc, e.type, e.type, fp && post ? oldval : newval);
3634 if (exceptionOrCant(result))
3635 return;
3636
3637 if (result == pue.exp())
3638 result = pue.copy();
3639
3640 size_t oldlen = cast(size_t)oldval.toInteger();
3641 size_t newlen = cast(size_t)newval.toInteger();
3642 if (oldlen == newlen) // no change required -- we're done!
3643 return;
3644
3645 // We have changed it into a reference assignment
3646 // Note that returnValue is still the new length.
3647 e1 = (cast(ArrayLengthExp)e1).e1;
3648 Type t = e1.type.toBasetype();
3649 if (t.ty != Tarray)
3650 {
3651 e.error("`%s` is not yet supported at compile time", e.toChars());
3652 result = CTFEExp.cantexp;
3653 return;
3654 }
3655 e1 = interpretRegion(e1, istate, CTFEGoal.LValue);
3656 if (exceptionOrCant(e1))
3657 return;
3658
3659 if (oldlen != 0) // Get the old array literal.
3660 oldval = interpretRegion(e1, istate);
3661 UnionExp utmp = void;
3662 oldval = resolveSlice(oldval, &utmp);
3663
3664 newval = changeArrayLiteralLength(e.loc, cast(TypeArray)t, oldval, oldlen, newlen).copy();
3665
3666 e1 = assignToLvalue(e, e1, newval);
3667 if (exceptionOrCant(e1))
3668 return;
3669
3670 return;
3671 }
3672
3673 if (!isBlockAssignment)
3674 {
3675 newval = ctfeCast(pue, e.loc, e.type, e.type, newval);
3676 if (exceptionOrCant(newval))
3677 return;
3678 if (newval == pue.exp())
3679 newval = pue.copy();
3680
3681 // Determine the return value
3682 if (goal == CTFEGoal.LValue) // https://issues.dlang.org/show_bug.cgi?id=14371
3683 result = e1;
3684 else
3685 {
3686 result = ctfeCast(pue, e.loc, e.type, e.type, fp && post ? oldval : newval);
3687 if (result == pue.exp())
3688 result = pue.copy();
3689 }
3690 if (exceptionOrCant(result))
3691 return;
3692 }
3693 if (exceptionOrCant(newval))
3694 return;
3695
3696 debug (LOGASSIGN)
3697 {
3698 printf("ASSIGN: %s=%s\n", e1.toChars(), newval.toChars());
3699 showCtfeExpr(newval);
3700 }
3701
3702 /* Block assignment or element-wise assignment.
3703 */
3704 if (e1.op == EXP.slice ||
3705 e1.op == EXP.vector ||
3706 e1.op == EXP.arrayLiteral ||
3707 e1.op == EXP.string_ ||
3708 e1.op == EXP.null_ && e1.type.toBasetype().ty == Tarray)
3709 {
3710 // Note that slice assignments don't support things like ++, so
3711 // we don't need to remember 'returnValue'.
3712 result = interpretAssignToSlice(pue, e, e1, newval, isBlockAssignment);
3713 if (exceptionOrCant(result))
3714 return;
3715 if (auto se = e.e1.isSliceExp())
3716 {
3717 Expression e1x = interpretRegion(se.e1, istate, CTFEGoal.LValue);
3718 if (auto dve = e1x.isDotVarExp())
3719 {
3720 auto ex = dve.e1;
3721 auto sle = ex.op == EXP.structLiteral ? (cast(StructLiteralExp)ex)
3722 : ex.op == EXP.classReference ? (cast(ClassReferenceExp)ex).value
3723 : null;
3724 auto v = dve.var.isVarDeclaration();
3725 if (!sle || !v)
3726 {
3727 e.error("CTFE internal error: dotvar slice assignment");
3728 result = CTFEExp.cantexp;
3729 return;
3730 }
3731 stompOverlappedFields(sle, v);
3732 }
3733 }
3734 return;
3735 }
3736 assert(result);
3737
3738 /* Assignment to a CTFE reference.
3739 */
3740 if (Expression ex = assignToLvalue(e, e1, newval))
3741 result = ex;
3742
3743 return;
3744 }
3745
3746 /* Set all sibling fields which overlap with v to VoidExp.
3747 */
3748 private void stompOverlappedFields(StructLiteralExp sle, VarDeclaration v)
3749 {
3750 if (!v.overlapped)
3751 return;
3752 foreach (size_t i, v2; sle.sd.fields)
3753 {
3754 if (v is v2 || !v.isOverlappedWith(v2))
3755 continue;
3756 auto e = (*sle.elements)[i];
3757 if (e.op != EXP.void_)
3758 (*sle.elements)[i] = voidInitLiteral(e.type, v).copy();
3759 }
3760 }
3761
3762 private Expression assignToLvalue(BinExp e, Expression e1, Expression newval)
3763 {
3764 //printf("assignToLvalue() e: %s e1: %s newval: %s\n", e.toChars(), e1.toChars(), newval.toChars());
3765 VarDeclaration vd = null;
3766 Expression* payload = null; // dead-store to prevent spurious warning
3767 Expression oldval;
3768
3769 if (auto ve = e1.isVarExp())
3770 {
3771 vd = ve.var.isVarDeclaration();
3772 oldval = getValue(vd);
3773 }
3774 else if (auto dve = e1.isDotVarExp())
3775 {
3776 /* Assignment to member variable of the form:
3777 * e.v = newval
3778 */
3779 auto ex = dve.e1;
3780 auto sle = ex.op == EXP.structLiteral ? (cast(StructLiteralExp)ex)
3781 : ex.op == EXP.classReference ? (cast(ClassReferenceExp)ex).value
3782 : null;
3783 auto v = (cast(DotVarExp)e1).var.isVarDeclaration();
3784 if (!sle || !v)
3785 {
3786 e.error("CTFE internal error: dotvar assignment");
3787 return CTFEExp.cantexp;
3788 }
3789 if (sle.ownedByCtfe != OwnedBy.ctfe)
3790 {
3791 e.error("cannot modify read-only constant `%s`", sle.toChars());
3792 return CTFEExp.cantexp;
3793 }
3794
3795 int fieldi = ex.op == EXP.structLiteral ? findFieldIndexByName(sle.sd, v)
3796 : (cast(ClassReferenceExp)ex).findFieldIndexByName(v);
3797 if (fieldi == -1)
3798 {
3799 e.error("CTFE internal error: cannot find field `%s` in `%s`", v.toChars(), ex.toChars());
3800 return CTFEExp.cantexp;
3801 }
3802 assert(0 <= fieldi && fieldi < sle.elements.dim);
3803
3804 // If it's a union, set all other members of this union to void
3805 stompOverlappedFields(sle, v);
3806
3807 payload = &(*sle.elements)[fieldi];
3808 oldval = *payload;
3809 }
3810 else if (auto ie = e1.isIndexExp())
3811 {
3812 assert(ie.e1.type.toBasetype().ty != Taarray);
3813
3814 Expression aggregate;
3815 uinteger_t indexToModify;
3816 if (!resolveIndexing(ie, istate, &aggregate, &indexToModify, true))
3817 {
3818 return CTFEExp.cantexp;
3819 }
3820 size_t index = cast(size_t)indexToModify;
3821
3822 if (auto existingSE = aggregate.isStringExp())
3823 {
3824 if (existingSE.ownedByCtfe != OwnedBy.ctfe)
3825 {
3826 e.error("cannot modify read-only string literal `%s`", ie.e1.toChars());
3827 return CTFEExp.cantexp;
3828 }
3829 existingSE.setCodeUnit(index, cast(dchar)newval.toInteger());
3830 return null;
3831 }
3832 if (aggregate.op != EXP.arrayLiteral)
3833 {
3834 e.error("index assignment `%s` is not yet supported in CTFE ", e.toChars());
3835 return CTFEExp.cantexp;
3836 }
3837
3838 ArrayLiteralExp existingAE = cast(ArrayLiteralExp)aggregate;
3839 if (existingAE.ownedByCtfe != OwnedBy.ctfe)
3840 {
3841 e.error("cannot modify read-only constant `%s`", existingAE.toChars());
3842 return CTFEExp.cantexp;
3843 }
3844
3845 payload = &(*existingAE.elements)[index];
3846 oldval = *payload;
3847 }
3848 else
3849 {
3850 e.error("`%s` cannot be evaluated at compile time", e.toChars());
3851 return CTFEExp.cantexp;
3852 }
3853
3854 Type t1b = e1.type.toBasetype();
3855 bool wantCopy = t1b.baseElemOf().ty == Tstruct;
3856
3857 if (auto ve = newval.isVectorExp())
3858 {
3859 // Ensure ve is an array literal, and not a broadcast
3860 if (ve.e1.op == EXP.int64 || ve.e1.op == EXP.float64) // if broadcast
3861 {
3862 UnionExp ue = void;
3863 Expression ex = interpretVectorToArray(&ue, ve);
3864 ve.e1 = (ex == ue.exp()) ? ue.copy() : ex;
3865 }
3866 }
3867
3868 if (newval.op == EXP.structLiteral && oldval)
3869 {
3870 assert(oldval.op == EXP.structLiteral || oldval.op == EXP.arrayLiteral || oldval.op == EXP.string_);
3871 newval = copyLiteral(newval).copy();
3872 assignInPlace(oldval, newval);
3873 }
3874 else if (wantCopy && e.op == EXP.assign)
3875 {
3876 // Currently postblit/destructor calls on static array are done
3877 // in the druntime internal functions so they don't appear in AST.
3878 // Therefore interpreter should handle them specially.
3879
3880 assert(oldval);
3881 version (all) // todo: instead we can directly access to each elements of the slice
3882 {
3883 newval = resolveSlice(newval);
3884 if (CTFEExp.isCantExp(newval))
3885 {
3886 e.error("CTFE internal error: assignment `%s`", e.toChars());
3887 return CTFEExp.cantexp;
3888 }
3889 }
3890 assert(oldval.op == EXP.arrayLiteral);
3891 assert(newval.op == EXP.arrayLiteral);
3892
3893 Expressions* oldelems = (cast(ArrayLiteralExp)oldval).elements;
3894 Expressions* newelems = (cast(ArrayLiteralExp)newval).elements;
3895 assert(oldelems.dim == newelems.dim);
3896
3897 Type elemtype = oldval.type.nextOf();
3898 foreach (i, ref oldelem; *oldelems)
3899 {
3900 Expression newelem = paintTypeOntoLiteral(elemtype, (*newelems)[i]);
3901 // https://issues.dlang.org/show_bug.cgi?id=9245
3902 if (e.e2.isLvalue())
3903 {
3904 if (Expression ex = evaluatePostblit(istate, newelem))
3905 return ex;
3906 }
3907 // https://issues.dlang.org/show_bug.cgi?id=13661
3908 if (Expression ex = evaluateDtor(istate, oldelem))
3909 return ex;
3910 oldelem = newelem;
3911 }
3912 }
3913 else
3914 {
3915 // e1 has its own payload, so we have to create a new literal.
3916 if (wantCopy)
3917 newval = copyLiteral(newval).copy();
3918
3919 if (t1b.ty == Tsarray && e.op == EXP.construct && e.e2.isLvalue())
3920 {
3921 // https://issues.dlang.org/show_bug.cgi?id=9245
3922 if (Expression ex = evaluatePostblit(istate, newval))
3923 return ex;
3924 }
3925
3926 oldval = newval;
3927 }
3928
3929 if (vd)
3930 setValue(vd, oldval);
3931 else
3932 *payload = oldval;
3933
3934 // Blit assignment should return the newly created value.
3935 if (e.op == EXP.blit)
3936 return oldval;
3937
3938 return null;
3939 }
3940
3941 /*************
3942 * Deal with assignments of the form:
3943 * dest[] = newval
3944 * dest[low..upp] = newval
3945 * where newval has already been interpreted
3946 *
3947 * This could be a slice assignment or a block assignment, and
3948 * dest could be either an array literal, or a string.
3949 *
3950 * Returns EXP.cantExpression on failure. If there are no errors,
3951 * it returns aggregate[low..upp], except that as an optimisation,
3952 * if goal == CTFEGoal.Nothing, it will return NULL
3953 */
3954 private Expression interpretAssignToSlice(UnionExp* pue, BinExp e, Expression e1, Expression newval, bool isBlockAssignment)
3955 {
3956 dinteger_t lowerbound;
3957 dinteger_t upperbound;
3958 dinteger_t firstIndex;
3959
3960 Expression aggregate;
3961
3962 if (auto se = e1.isSliceExp())
3963 {
3964 // ------------------------------
3965 // aggregate[] = newval
3966 // aggregate[low..upp] = newval
3967 // ------------------------------
3968 version (all) // should be move in interpretAssignCommon as the evaluation of e1
3969 {
3970 Expression oldval = interpretRegion(se.e1, istate);
3971
3972 // Set the $ variable
3973 uinteger_t dollar = resolveArrayLength(oldval);
3974 if (se.lengthVar)
3975 {
3976 Expression dollarExp = ctfeEmplaceExp!IntegerExp(e1.loc, dollar, Type.tsize_t);
3977 ctfeGlobals.stack.push(se.lengthVar);
3978 setValue(se.lengthVar, dollarExp);
3979 }
3980 Expression lwr = interpretRegion(se.lwr, istate);
3981 if (exceptionOrCantInterpret(lwr))
3982 {
3983 if (se.lengthVar)
3984 ctfeGlobals.stack.pop(se.lengthVar);
3985 return lwr;
3986 }
3987 Expression upr = interpretRegion(se.upr, istate);
3988 if (exceptionOrCantInterpret(upr))
3989 {
3990 if (se.lengthVar)
3991 ctfeGlobals.stack.pop(se.lengthVar);
3992 return upr;
3993 }
3994 if (se.lengthVar)
3995 ctfeGlobals.stack.pop(se.lengthVar); // $ is defined only in [L..U]
3996
3997 const dim = dollar;
3998 lowerbound = lwr ? lwr.toInteger() : 0;
3999 upperbound = upr ? upr.toInteger() : dim;
4000
4001 if (lowerbound < 0 || dim < upperbound)
4002 {
4003 e.error("array bounds `[0..%llu]` exceeded in slice `[%llu..%llu]`",
4004 ulong(dim), ulong(lowerbound), ulong(upperbound));
4005 return CTFEExp.cantexp;
4006 }
4007 }
4008 aggregate = oldval;
4009 firstIndex = lowerbound;
4010
4011 if (auto oldse = aggregate.isSliceExp())
4012 {
4013 // Slice of a slice --> change the bounds
4014 if (oldse.upr.toInteger() < upperbound + oldse.lwr.toInteger())
4015 {
4016 e.error("slice `[%llu..%llu]` exceeds array bounds `[0..%llu]`",
4017 ulong(lowerbound), ulong(upperbound), oldse.upr.toInteger() - oldse.lwr.toInteger());
4018 return CTFEExp.cantexp;
4019 }
4020 aggregate = oldse.e1;
4021 firstIndex = lowerbound + oldse.lwr.toInteger();
4022 }
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 = cast(SliceExp)newval;
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 = (cast(ArrayLiteralExp)aggr2).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, cast(StringExp)newval, cast(size_t)firstIndex);
4230 return newval;
4231 }
4232 if (newval.op == EXP.arrayLiteral && !isBlockAssignment)
4233 {
4234 Expressions* oldelems = existingAE.elements;
4235 Expressions* newelems = (cast(ArrayLiteralExp)newval).elements;
4236 Type elemtype = existingAE.type.nextOf();
4237 bool needsPostblit = e.op != EXP.blit && e.e2.isLvalue();
4238 foreach (j, newelem; *newelems)
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(cast(ArrayLiteralExp)(*w)[k]))
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
4341 override void visit(AssignExp e)
4342 {
4343 interpretAssignCommon(e, null);
4344 }
4345
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
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 */
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 = (cast(NotExp)e).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 = (cast(BinExp)e).e1;
4447 *p2 = (cast(BinExp)e).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 */
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
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.
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
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.semantic3Errors)
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
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
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
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 */
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
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
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
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
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
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"), (cast(SymOffExp)agg).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 = (cast(SliceExp)e1).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
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, cast(AssocArrayLiteralExp)e1, 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
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 (iupr > (len + 1) || iupr < ilwr)
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 (ilwr > iupr || iupr > up1 - lo1)
5599 {
5600 e.error("slice `[%llu..%llu]` exceeds array bounds `[%llu..%llu]`", ilwr, iupr, lo1, up1);
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 (iupr < ilwr || dollar < 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
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, cast(AssocArrayLiteralExp)e2, 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
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
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 = cast(ClassReferenceExp)result;
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 case Tpointer:
5784 tb = (cast(TypePointer)tb).next.toBasetype();
5785 if (tb.ty == Tstruct)
5786 {
5787 if (result.op != EXP.address ||
5788 (cast(AddrExp)result).e1.op != EXP.structLiteral)
5789 {
5790 e.error("`delete` on invalid struct pointer `%s`", result.toChars());
5791 result = CTFEExp.cantexp;
5792 return;
5793 }
5794
5795 auto sd = (cast(TypeStruct)tb).sym;
5796 auto sle = cast(StructLiteralExp)(cast(AddrExp)result).e1;
5797
5798 if (sd.dtor)
5799 {
5800 result = interpretFunction(pue, sd.dtor, istate, null, sle);
5801 if (exceptionOrCant(result))
5802 return;
5803 }
5804 }
5805 break;
5806
5807 case Tarray:
5808 auto tv = tb.nextOf().baseElemOf();
5809 if (tv.ty == Tstruct)
5810 {
5811 if (result.op != EXP.arrayLiteral)
5812 {
5813 e.error("`delete` on invalid struct array `%s`", result.toChars());
5814 result = CTFEExp.cantexp;
5815 return;
5816 }
5817
5818 auto sd = (cast(TypeStruct)tv).sym;
5819
5820 if (sd.dtor)
5821 {
5822 auto ale = cast(ArrayLiteralExp)result;
5823 foreach (el; *ale.elements)
5824 {
5825 result = interpretFunction(pue, sd.dtor, istate, null, el);
5826 if (exceptionOrCant(result))
5827 return;
5828 }
5829 }
5830 }
5831 break;
5832
5833 default:
5834 assert(0);
5835 }
5836 result = CTFEExp.voidexp;
5837 }
5838
5839 override void visit(CastExp e)
5840 {
5841 debug (LOG)
5842 {
5843 printf("%s CastExp::interpret() %s\n", e.loc.toChars(), e.toChars());
5844 }
5845 Expression e1 = interpretRegion(e.e1, istate, goal);
5846 if (exceptionOrCant(e1))
5847 return;
5848 // If the expression has been cast to void, do nothing.
5849 if (e.to.ty == Tvoid)
5850 {
5851 result = CTFEExp.voidexp;
5852 return;
5853 }
5854 if (e.to.ty == Tpointer && e1.op != EXP.null_)
5855 {
5856 Type pointee = (cast(TypePointer)e.type).next;
5857 // Implement special cases of normally-unsafe casts
5858 if (e1.op == EXP.int64)
5859 {
5860 // Happens with Windows HANDLEs, for example.
5861 result = paintTypeOntoLiteral(pue, e.to, e1);
5862 return;
5863 }
5864
5865 bool castToSarrayPointer = false;
5866 bool castBackFromVoid = false;
5867 if (e1.type.ty == Tarray || e1.type.ty == Tsarray || e1.type.ty == Tpointer)
5868 {
5869 // Check for unsupported type painting operations
5870 // For slices, we need the type being sliced,
5871 // since it may have already been type painted
5872 Type elemtype = e1.type.nextOf();
5873 if (auto se = e1.isSliceExp())
5874 elemtype = se.e1.type.nextOf();
5875
5876 // Allow casts from X* to void *, and X** to void** for any X.
5877 // But don't allow cast from X* to void**.
5878 // So, we strip all matching * from source and target to find X.
5879 // Allow casts to X* from void* only if the 'void' was originally an X;
5880 // we check this later on.
5881 Type ultimatePointee = pointee;
5882 Type ultimateSrc = elemtype;
5883 while (ultimatePointee.ty == Tpointer && ultimateSrc.ty == Tpointer)
5884 {
5885 ultimatePointee = ultimatePointee.nextOf();
5886 ultimateSrc = ultimateSrc.nextOf();
5887 }
5888 if (ultimatePointee.ty == Tsarray && ultimatePointee.nextOf().equivalent(ultimateSrc))
5889 {
5890 castToSarrayPointer = true;
5891 }
5892 else if (ultimatePointee.ty != Tvoid && ultimateSrc.ty != Tvoid && !isSafePointerCast(elemtype, pointee))
5893 {
5894 e.error("reinterpreting cast from `%s*` to `%s*` is not supported in CTFE", elemtype.toChars(), pointee.toChars());
5895 result = CTFEExp.cantexp;
5896 return;
5897 }
5898 if (ultimateSrc.ty == Tvoid)
5899 castBackFromVoid = true;
5900 }
5901
5902 if (auto se = e1.isSliceExp())
5903 {
5904 if (se.e1.op == EXP.null_)
5905 {
5906 result = paintTypeOntoLiteral(pue, e.type, se.e1);
5907 return;
5908 }
5909 // Create a CTFE pointer &aggregate[1..2]
5910 auto ei = ctfeEmplaceExp!IndexExp(e.loc, se.e1, se.lwr);
5911 ei.type = e.type.nextOf();
5912 emplaceExp!(AddrExp)(pue, e.loc, ei, e.type);
5913 result = pue.exp();
5914 return;
5915 }
5916 if (e1.op == EXP.arrayLiteral || e1.op == EXP.string_)
5917 {
5918 // Create a CTFE pointer &[1,2,3][0] or &"abc"[0]
5919 auto ei = ctfeEmplaceExp!IndexExp(e.loc, e1, ctfeEmplaceExp!IntegerExp(e.loc, 0, Type.tsize_t));
5920 ei.type = e.type.nextOf();
5921 emplaceExp!(AddrExp)(pue, e.loc, ei, e.type);
5922 result = pue.exp();
5923 return;
5924 }
5925 if (e1.op == EXP.index && !(cast(IndexExp)e1).e1.type.equals(e1.type))
5926 {
5927 // type painting operation
5928 IndexExp ie = cast(IndexExp)e1;
5929 if (castBackFromVoid)
5930 {
5931 // get the original type. For strings, it's just the type...
5932 Type origType = ie.e1.type.nextOf();
5933 // ..but for arrays of type void*, it's the type of the element
5934 if (ie.e1.op == EXP.arrayLiteral && ie.e2.op == EXP.int64)
5935 {
5936 ArrayLiteralExp ale = cast(ArrayLiteralExp)ie.e1;
5937 const indx = cast(size_t)ie.e2.toInteger();
5938 if (indx < ale.elements.dim)
5939 {
5940 if (Expression xx = (*ale.elements)[indx])
5941 {
5942 if (auto iex = xx.isIndexExp())
5943 origType = iex.e1.type.nextOf();
5944 else if (auto ae = xx.isAddrExp())
5945 origType = ae.e1.type;
5946 else if (auto ve = xx.isVarExp())
5947 origType = ve.var.type;
5948 }
5949 }
5950 }
5951 if (!isSafePointerCast(origType, pointee))
5952 {
5953 e.error("using `void*` to reinterpret cast from `%s*` to `%s*` is not supported in CTFE", origType.toChars(), pointee.toChars());
5954 result = CTFEExp.cantexp;
5955 return;
5956 }
5957 }
5958 emplaceExp!(IndexExp)(pue, e1.loc, ie.e1, ie.e2);
5959 result = pue.exp();
5960 result.type = e.type;
5961 return;
5962 }
5963
5964 if (auto ae = e1.isAddrExp())
5965 {
5966 Type origType = ae.e1.type;
5967 if (isSafePointerCast(origType, pointee))
5968 {
5969 emplaceExp!(AddrExp)(pue, e.loc, ae.e1, e.type);
5970 result = pue.exp();
5971 return;
5972 }
5973
5974 if (castToSarrayPointer && pointee.toBasetype().ty == Tsarray && ae.e1.op == EXP.index)
5975 {
5976 // &val[idx]
5977 dinteger_t dim = (cast(TypeSArray)pointee.toBasetype()).dim.toInteger();
5978 IndexExp ie = cast(IndexExp)ae.e1;
5979 Expression lwr = ie.e2;
5980 Expression upr = ctfeEmplaceExp!IntegerExp(ie.e2.loc, ie.e2.toInteger() + dim, Type.tsize_t);
5981
5982 // Create a CTFE pointer &val[idx..idx+dim]
5983 auto er = ctfeEmplaceExp!SliceExp(e.loc, ie.e1, lwr, upr);
5984 er.type = pointee;
5985 emplaceExp!(AddrExp)(pue, e.loc, er, e.type);
5986 result = pue.exp();
5987 return;
5988 }
5989 }
5990
5991 if (e1.op == EXP.variable || e1.op == EXP.symbolOffset)
5992 {
5993 // type painting operation
5994 Type origType = (cast(SymbolExp)e1).var.type;
5995 if (castBackFromVoid && !isSafePointerCast(origType, pointee))
5996 {
5997 e.error("using `void*` to reinterpret cast from `%s*` to `%s*` is not supported in CTFE", origType.toChars(), pointee.toChars());
5998 result = CTFEExp.cantexp;
5999 return;
6000 }
6001 if (auto ve = e1.isVarExp())
6002 emplaceExp!(VarExp)(pue, e.loc, ve.var);
6003 else
6004 emplaceExp!(SymOffExp)(pue, e.loc, (cast(SymOffExp)e1).var, (cast(SymOffExp)e1).offset);
6005 result = pue.exp();
6006 result.type = e.to;
6007 return;
6008 }
6009
6010 // Check if we have a null pointer (eg, inside a struct)
6011 e1 = interpretRegion(e1, istate);
6012 if (e1.op != EXP.null_)
6013 {
6014 e.error("pointer cast from `%s` to `%s` is not supported at compile time", e1.type.toChars(), e.to.toChars());
6015 result = CTFEExp.cantexp;
6016 return;
6017 }
6018 }
6019 if (e.to.ty == Tsarray && e.e1.type.ty == Tvector)
6020 {
6021 // Special handling for: cast(float[4])__vector([w, x, y, z])
6022 e1 = interpretRegion(e.e1, istate);
6023 if (exceptionOrCant(e1))
6024 return;
6025 assert(e1.op == EXP.vector);
6026 e1 = interpretVectorToArray(pue, e1.isVectorExp());
6027 }
6028 if (e.to.ty == Tarray && e1.op == EXP.slice)
6029 {
6030 // Note that the slice may be void[], so when checking for dangerous
6031 // casts, we need to use the original type, which is se.e1.
6032 SliceExp se = cast(SliceExp)e1;
6033 if (!isSafePointerCast(se.e1.type.nextOf(), e.to.nextOf()))
6034 {
6035 e.error("array cast from `%s` to `%s` is not supported at compile time", se.e1.type.toChars(), e.to.toChars());
6036 result = CTFEExp.cantexp;
6037 return;
6038 }
6039 emplaceExp!(SliceExp)(pue, e1.loc, se.e1, se.lwr, se.upr);
6040 result = pue.exp();
6041 result.type = e.to;
6042 return;
6043 }
6044 // Disallow array type painting, except for conversions between built-in
6045 // types of identical size.
6046 if ((e.to.ty == Tsarray || e.to.ty == Tarray) && (e1.type.ty == Tsarray || e1.type.ty == Tarray) && !isSafePointerCast(e1.type.nextOf(), e.to.nextOf()))
6047 {
6048 e.error("array cast from `%s` to `%s` is not supported at compile time", e1.type.toChars(), e.to.toChars());
6049 result = CTFEExp.cantexp;
6050 return;
6051 }
6052 if (e.to.ty == Tsarray)
6053 e1 = resolveSlice(e1);
6054
6055 auto tobt = e.to.toBasetype();
6056 if (tobt.ty == Tbool && e1.type.ty == Tpointer)
6057 {
6058 emplaceExp!(IntegerExp)(pue, e.loc, e1.op != EXP.null_, e.to);
6059 result = pue.exp();
6060 return;
6061 }
6062 else if (tobt.isTypeBasic() && e1.op == EXP.null_)
6063 {
6064 if (tobt.isintegral())
6065 emplaceExp!(IntegerExp)(pue, e.loc, 0, e.to);
6066 else if (tobt.isreal())
6067 emplaceExp!(RealExp)(pue, e.loc, CTFloat.zero, e.to);
6068 result = pue.exp();
6069 return;
6070 }
6071 result = ctfeCast(pue, e.loc, e.type, e.to, e1);
6072 }
6073
6074 override void visit(AssertExp e)
6075 {
6076 debug (LOG)
6077 {
6078 printf("%s AssertExp::interpret() %s\n", e.loc.toChars(), e.toChars());
6079 }
6080 Expression e1 = interpret(pue, e.e1, istate);
6081 if (exceptionOrCant(e1))
6082 return;
6083 if (isTrueBool(e1))
6084 {
6085 }
6086 else if (e1.toBool().hasValue(false))
6087 {
6088 if (e.msg)
6089 {
6090 UnionExp ue = void;
6091 result = interpret(&ue, e.msg, istate);
6092 if (exceptionOrCant(result))
6093 return;
6094 e.error("`%s`", result.toChars());
6095 }
6096 else
6097 e.error("`%s` failed", e.toChars());
6098 result = CTFEExp.cantexp;
6099 return;
6100 }
6101 else
6102 {
6103 e.error("`%s` is not a compile time boolean expression", e1.toChars());
6104 result = CTFEExp.cantexp;
6105 return;
6106 }
6107 result = e1;
6108 return;
6109 }
6110
6111 override void visit(PtrExp e)
6112 {
6113 debug (LOG)
6114 {
6115 printf("%s PtrExp::interpret() %s\n", e.loc.toChars(), e.toChars());
6116 }
6117 // Check for int<->float and long<->double casts.
6118 if (auto soe1 = e.e1.isSymOffExp())
6119 if (soe1.offset == 0 && soe1.var.isVarDeclaration() && isFloatIntPaint(e.type, soe1.var.type))
6120 {
6121 // *(cast(int*)&v), where v is a float variable
6122 result = paintFloatInt(pue, getVarExp(e.loc, istate, soe1.var, CTFEGoal.RValue), e.type);
6123 return;
6124 }
6125
6126 if (auto ce1 = e.e1.isCastExp())
6127 if (auto ae11 = ce1.e1.isAddrExp())
6128 {
6129 // *(cast(int*)&x), where x is a float expression
6130 Expression x = ae11.e1;
6131 if (isFloatIntPaint(e.type, x.type))
6132 {
6133 result = paintFloatInt(pue, interpretRegion(x, istate), e.type);
6134 return;
6135 }
6136 }
6137
6138 // Constant fold *(&structliteral + offset)
6139 if (auto ae = e.e1.isAddExp())
6140 {
6141 if (ae.e1.op == EXP.address && ae.e2.op == EXP.int64)
6142 {
6143 AddrExp ade = cast(AddrExp)ae.e1;
6144 Expression ex = interpretRegion(ade.e1, istate);
6145 if (exceptionOrCant(ex))
6146 return;
6147 if (auto se = ex.isStructLiteralExp())
6148 {
6149 dinteger_t offset = ae.e2.toInteger();
6150 result = se.getField(e.type, cast(uint)offset);
6151 if (result)
6152 return;
6153 }
6154 }
6155 }
6156
6157 // It's possible we have an array bounds error. We need to make sure it
6158 // errors with this line number, not the one where the pointer was set.
6159 result = interpretRegion(e.e1, istate);
6160 if (exceptionOrCant(result))
6161 return;
6162
6163 if (result.op == EXP.function_)
6164 return;
6165 if (auto soe = result.isSymOffExp())
6166 {
6167 if (soe.offset == 0 && soe.var.isFuncDeclaration())
6168 return;
6169 e.error("cannot dereference pointer to static variable `%s` at compile time", soe.var.toChars());
6170 result = CTFEExp.cantexp;
6171 return;
6172 }
6173
6174 if (result.isStringExp())
6175 return;
6176
6177 if (result.op != EXP.address)
6178 {
6179 if (result.op == EXP.null_)
6180 e.error("dereference of null pointer `%s`", e.e1.toChars());
6181 else
6182 e.error("dereference of invalid pointer `%s`", result.toChars());
6183 result = CTFEExp.cantexp;
6184 return;
6185 }
6186
6187 // *(&x) ==> x
6188 result = (cast(AddrExp)result).e1;
6189
6190 if (result.op == EXP.slice && e.type.toBasetype().ty == Tsarray)
6191 {
6192 /* aggr[lwr..upr]
6193 * upr may exceed the upper boundary of aggr, but the check is deferred
6194 * until those out-of-bounds elements will be touched.
6195 */
6196 return;
6197 }
6198 result = interpret(pue, result, istate, goal);
6199 if (exceptionOrCant(result))
6200 return;
6201
6202 debug (LOG)
6203 {
6204 if (CTFEExp.isCantExp(result))
6205 printf("PtrExp::interpret() %s = CTFEExp::cantexp\n", e.toChars());
6206 }
6207 }
6208
6209 override void visit(DotVarExp e)
6210 {
6211 void notImplementedYet()
6212 {
6213 e.error("`%s.%s` is not yet implemented at compile time", e.e1.toChars(), e.var.toChars());
6214 result = CTFEExp.cantexp;
6215 return;
6216 }
6217
6218 debug (LOG)
6219 {
6220 printf("%s DotVarExp::interpret() %s, goal = %d\n", e.loc.toChars(), e.toChars(), goal);
6221 }
6222 Expression ex = interpretRegion(e.e1, istate);
6223 if (exceptionOrCant(ex))
6224 return;
6225
6226 if (FuncDeclaration f = e.var.isFuncDeclaration())
6227 {
6228 if (ex == e.e1)
6229 result = e; // optimize: reuse this CTFE reference
6230 else
6231 {
6232 emplaceExp!(DotVarExp)(pue, e.loc, ex, f, false);
6233 result = pue.exp();
6234 result.type = e.type;
6235 }
6236 return;
6237 }
6238
6239 VarDeclaration v = e.var.isVarDeclaration();
6240 if (!v)
6241 {
6242 e.error("CTFE internal error: `%s`", e.toChars());
6243 result = CTFEExp.cantexp;
6244 return;
6245 }
6246
6247 if (ex.op == EXP.null_)
6248 {
6249 if (ex.type.toBasetype().ty == Tclass)
6250 e.error("class `%s` is `null` and cannot be dereferenced", e.e1.toChars());
6251 else
6252 e.error("CTFE internal error: null this `%s`", e.e1.toChars());
6253 result = CTFEExp.cantexp;
6254 return;
6255 }
6256
6257 StructLiteralExp se;
6258 int i;
6259
6260 if (ex.op != EXP.structLiteral && ex.op != EXP.classReference && ex.op != EXP.typeid_)
6261 {
6262 return notImplementedYet();
6263 }
6264
6265 // We can't use getField, because it makes a copy
6266 if (ex.op == EXP.classReference)
6267 {
6268 se = (cast(ClassReferenceExp)ex).value;
6269 i = (cast(ClassReferenceExp)ex).findFieldIndexByName(v);
6270 }
6271 else if (ex.op == EXP.typeid_)
6272 {
6273 if (v.ident == Identifier.idPool("name"))
6274 {
6275 if (auto t = isType(ex.isTypeidExp().obj))
6276 {
6277 auto sym = t.toDsymbol(null);
6278 if (auto ident = (sym ? sym.ident : null))
6279 {
6280 result = new StringExp(e.loc, ident.toString());
6281 result.expressionSemantic(null);
6282 return ;
6283 }
6284 }
6285 }
6286 return notImplementedYet();
6287 }
6288 else
6289 {
6290 se = cast(StructLiteralExp)ex;
6291 i = findFieldIndexByName(se.sd, v);
6292 }
6293 if (i == -1)
6294 {
6295 e.error("couldn't find field `%s` of type `%s` in `%s`", v.toChars(), e.type.toChars(), se.toChars());
6296 result = CTFEExp.cantexp;
6297 return;
6298 }
6299
6300 // https://issues.dlang.org/show_bug.cgi?id=19897
6301 // https://issues.dlang.org/show_bug.cgi?id=20710
6302 // Zero-elements fields don't have an initializer. See: scrubArray function
6303 if ((*se.elements)[i] is null)
6304 (*se.elements)[i] = voidInitLiteral(e.type, v).copy();
6305
6306 if (goal == CTFEGoal.LValue)
6307 {
6308 // just return the (simplified) dotvar expression as a CTFE reference
6309 if (e.e1 == ex)
6310 result = e;
6311 else
6312 {
6313 emplaceExp!(DotVarExp)(pue, e.loc, ex, v);
6314 result = pue.exp();
6315 result.type = e.type;
6316 }
6317 return;
6318 }
6319
6320 result = (*se.elements)[i];
6321 if (!result)
6322 {
6323 e.error("Internal Compiler Error: null field `%s`", v.toChars());
6324 result = CTFEExp.cantexp;
6325 return;
6326 }
6327 if (auto vie = result.isVoidInitExp())
6328 {
6329 const s = vie.var.toChars();
6330 if (v.overlapped)
6331 {
6332 e.error("reinterpretation through overlapped field `%s` is not allowed in CTFE", s);
6333 result = CTFEExp.cantexp;
6334 return;
6335 }
6336 e.error("cannot read uninitialized variable `%s` in CTFE", s);
6337 result = CTFEExp.cantexp;
6338 return;
6339 }
6340
6341 if (v.type.ty != result.type.ty && v.type.ty == Tsarray)
6342 {
6343 // Block assignment from inside struct literals
6344 auto tsa = cast(TypeSArray)v.type;
6345 auto len = cast(size_t)tsa.dim.toInteger();
6346 UnionExp ue = void;
6347 result = createBlockDuplicatedArrayLiteral(&ue, e.loc, v.type, result, len);
6348 if (result == ue.exp())
6349 result = ue.copy();
6350 (*se.elements)[i] = result;
6351 }
6352 debug (LOG)
6353 {
6354 if (CTFEExp.isCantExp(result))
6355 printf("DotVarExp::interpret() %s = CTFEExp::cantexp\n", e.toChars());
6356 }
6357 }
6358
6359 override void visit(RemoveExp e)
6360 {
6361 debug (LOG)
6362 {
6363 printf("%s RemoveExp::interpret() %s\n", e.loc.toChars(), e.toChars());
6364 }
6365 Expression agg = interpret(e.e1, istate);
6366 if (exceptionOrCant(agg))
6367 return;
6368 Expression index = interpret(e.e2, istate);
6369 if (exceptionOrCant(index))
6370 return;
6371 if (agg.op == EXP.null_)
6372 {
6373 result = CTFEExp.voidexp;
6374 return;
6375 }
6376
6377 AssocArrayLiteralExp aae = agg.isAssocArrayLiteralExp();
6378 Expressions* keysx = aae.keys;
6379 Expressions* valuesx = aae.values;
6380 size_t removed = 0;
6381 foreach (j, evalue; *valuesx)
6382 {
6383 Expression ekey = (*keysx)[j];
6384 int eq = ctfeEqual(e.loc, EXP.equal, ekey, index);
6385 if (eq)
6386 ++removed;
6387 else if (removed != 0)
6388 {
6389 (*keysx)[j - removed] = ekey;
6390 (*valuesx)[j - removed] = evalue;
6391 }
6392 }
6393 valuesx.dim = valuesx.dim - removed;
6394 keysx.dim = keysx.dim - removed;
6395 result = IntegerExp.createBool(removed != 0);
6396 }
6397
6398 override void visit(ClassReferenceExp e)
6399 {
6400 //printf("ClassReferenceExp::interpret() %s\n", e.value.toChars());
6401 result = e;
6402 }
6403
6404 override void visit(VoidInitExp e)
6405 {
6406 e.error("CTFE internal error: trying to read uninitialized variable");
6407 assert(0);
6408 }
6409
6410 override void visit(ThrownExceptionExp e)
6411 {
6412 assert(0); // This should never be interpreted
6413 }
6414 }
6415
6416 /********************************************
6417 * Interpret the expression.
6418 * Params:
6419 * pue = non-null pointer to temporary storage that can be used to store the return value
6420 * e = Expression to interpret
6421 * istate = context
6422 * goal = what the result will be used for
6423 * Returns:
6424 * resulting expression
6425 */
6426
6427 Expression interpret(UnionExp* pue, Expression e, InterState* istate, CTFEGoal goal = CTFEGoal.RValue)
6428 {
6429 if (!e)
6430 return null;
6431 scope Interpreter v = new Interpreter(pue, istate, goal);
6432 e.accept(v);
6433 Expression ex = v.result;
6434 assert(goal == CTFEGoal.Nothing || ex !is null);
6435 return ex;
6436 }
6437
6438 ///
6439 Expression interpret(Expression e, InterState* istate, CTFEGoal goal = CTFEGoal.RValue)
6440 {
6441 UnionExp ue = void;
6442 auto result = interpret(&ue, e, istate, goal);
6443 if (result == ue.exp())
6444 result = ue.copy();
6445 return result;
6446 }
6447
6448 /*****************************
6449 * Same as interpret(), but return result allocated in Region.
6450 * Params:
6451 * e = Expression to interpret
6452 * istate = context
6453 * goal = what the result will be used for
6454 * Returns:
6455 * resulting expression
6456 */
6457 Expression interpretRegion(Expression e, InterState* istate, CTFEGoal goal = CTFEGoal.RValue)
6458 {
6459 UnionExp ue = void;
6460 auto result = interpret(&ue, e, istate, goal);
6461 auto uexp = ue.exp();
6462 if (result != uexp)
6463 return result;
6464 if (mem.isGCEnabled)
6465 return ue.copy();
6466
6467 // mimicking UnionExp.copy, but with region allocation
6468 switch (uexp.op)
6469 {
6470 case EXP.cantExpression: return CTFEExp.cantexp;
6471 case EXP.voidExpression: return CTFEExp.voidexp;
6472 case EXP.break_: return CTFEExp.breakexp;
6473 case EXP.continue_: return CTFEExp.continueexp;
6474 case EXP.goto_: return CTFEExp.gotoexp;
6475 default: break;
6476 }
6477 auto p = ctfeGlobals.region.malloc(uexp.size);
6478 return cast(Expression)memcpy(p, cast(void*)uexp, uexp.size);
6479 }
6480
6481 /***********************************
6482 * Interpret the statement.
6483 * Params:
6484 * pue = non-null pointer to temporary storage that can be used to store the return value
6485 * s = Statement to interpret
6486 * istate = context
6487 * Returns:
6488 * NULL continue to next statement
6489 * EXP.cantExpression cannot interpret statement at compile time
6490 * !NULL expression from return statement, or thrown exception
6491 */
6492 Expression interpret(UnionExp* pue, Statement s, InterState* istate)
6493 {
6494 if (!s)
6495 return null;
6496 scope Interpreter v = new Interpreter(pue, istate, CTFEGoal.Nothing);
6497 s.accept(v);
6498 return v.result;
6499 }
6500
6501 ///
6502 Expression interpret(Statement s, InterState* istate)
6503 {
6504 UnionExp ue = void;
6505 auto result = interpret(&ue, s, istate);
6506 if (result == ue.exp())
6507 result = ue.copy();
6508 return result;
6509 }
6510
6511 /**
6512 * All results destined for use outside of CTFE need to have their CTFE-specific
6513 * features removed.
6514 * In particular,
6515 * 1. all slices must be resolved.
6516 * 2. all .ownedByCtfe set to OwnedBy.code
6517 */
6518 private Expression scrubReturnValue(const ref Loc loc, Expression e)
6519 {
6520 /* Returns: true if e is void,
6521 * or is an array literal or struct literal of void elements.
6522 */
6523 static bool isVoid(const Expression e, bool checkArrayType = false) pure
6524 {
6525 if (e.op == EXP.void_)
6526 return true;
6527
6528 static bool isEntirelyVoid(const Expressions* elems)
6529 {
6530 foreach (e; *elems)
6531 {
6532 // It can be NULL for performance reasons,
6533 // see StructLiteralExp::interpret().
6534 if (e && !isVoid(e))
6535 return false;
6536 }
6537 return true;
6538 }
6539
6540 if (auto sle = e.isStructLiteralExp())
6541 return isEntirelyVoid(sle.elements);
6542
6543 if (checkArrayType && e.type.ty != Tsarray)
6544 return false;
6545
6546 if (auto ale = e.isArrayLiteralExp())
6547 return isEntirelyVoid(ale.elements);
6548
6549 return false;
6550 }
6551
6552
6553 /* Scrub all elements of elems[].
6554 * Returns: null for success, error Expression for failure
6555 */
6556 Expression scrubArray(Expressions* elems, bool structlit = false)
6557 {
6558 foreach (ref e; *elems)
6559 {
6560 // It can be NULL for performance reasons,
6561 // see StructLiteralExp::interpret().
6562 if (!e)
6563 continue;
6564
6565 // A struct .init may contain void members.
6566 // Static array members are a weird special case https://issues.dlang.org/show_bug.cgi?id=10994
6567 if (structlit && isVoid(e, true))
6568 {
6569 e = null;
6570 }
6571 else
6572 {
6573 e = scrubReturnValue(loc, e);
6574 if (CTFEExp.isCantExp(e) || e.op == EXP.error)
6575 return e;
6576 }
6577 }
6578 return null;
6579 }
6580
6581 Expression scrubSE(StructLiteralExp sle)
6582 {
6583 sle.ownedByCtfe = OwnedBy.code;
6584 if (!(sle.stageflags & stageScrub))
6585 {
6586 const old = sle.stageflags;
6587 sle.stageflags |= stageScrub; // prevent infinite recursion
6588 if (auto ex = scrubArray(sle.elements, true))
6589 return ex;
6590 sle.stageflags = old;
6591 }
6592 return null;
6593 }
6594
6595 if (e.op == EXP.classReference)
6596 {
6597 StructLiteralExp sle = (cast(ClassReferenceExp)e).value;
6598 if (auto ex = scrubSE(sle))
6599 return ex;
6600 }
6601 else if (auto vie = e.isVoidInitExp())
6602 {
6603 error(loc, "uninitialized variable `%s` cannot be returned from CTFE", vie.var.toChars());
6604 return ErrorExp.get();
6605 }
6606
6607 e = resolveSlice(e);
6608
6609 if (auto sle = e.isStructLiteralExp())
6610 {
6611 if (auto ex = scrubSE(sle))
6612 return ex;
6613 }
6614 else if (auto se = e.isStringExp())
6615 {
6616 se.ownedByCtfe = OwnedBy.code;
6617 }
6618 else if (auto ale = e.isArrayLiteralExp())
6619 {
6620 ale.ownedByCtfe = OwnedBy.code;
6621 if (auto ex = scrubArray(ale.elements))
6622 return ex;
6623 }
6624 else if (auto aae = e.isAssocArrayLiteralExp())
6625 {
6626 aae.ownedByCtfe = OwnedBy.code;
6627 if (auto ex = scrubArray(aae.keys))
6628 return ex;
6629 if (auto ex = scrubArray(aae.values))
6630 return ex;
6631 aae.type = toBuiltinAAType(aae.type);
6632 }
6633 else if (auto ve = e.isVectorExp())
6634 {
6635 ve.ownedByCtfe = OwnedBy.code;
6636 if (auto ale = ve.e1.isArrayLiteralExp())
6637 {
6638 ale.ownedByCtfe = OwnedBy.code;
6639 if (auto ex = scrubArray(ale.elements))
6640 return ex;
6641 }
6642 }
6643 return e;
6644 }
6645
6646 /**************************************
6647 * Transitively set all .ownedByCtfe to OwnedBy.cache
6648 */
6649 private Expression scrubCacheValue(Expression e)
6650 {
6651 if (!e)
6652 return e;
6653
6654 Expression scrubArrayCache(Expressions* elems)
6655 {
6656 foreach (ref e; *elems)
6657 e = scrubCacheValue(e);
6658 return null;
6659 }
6660
6661 Expression scrubSE(StructLiteralExp sle)
6662 {
6663 sle.ownedByCtfe = OwnedBy.cache;
6664 if (!(sle.stageflags & stageScrub))
6665 {
6666 const old = sle.stageflags;
6667 sle.stageflags |= stageScrub; // prevent infinite recursion
6668 if (auto ex = scrubArrayCache(sle.elements))
6669 return ex;
6670 sle.stageflags = old;
6671 }
6672 return null;
6673 }
6674
6675 if (e.op == EXP.classReference)
6676 {
6677 if (auto ex = scrubSE((cast(ClassReferenceExp)e).value))
6678 return ex;
6679 }
6680 else if (auto sle = e.isStructLiteralExp())
6681 {
6682 if (auto ex = scrubSE(sle))
6683 return ex;
6684 }
6685 else if (auto se = e.isStringExp())
6686 {
6687 se.ownedByCtfe = OwnedBy.cache;
6688 }
6689 else if (auto ale = e.isArrayLiteralExp())
6690 {
6691 ale.ownedByCtfe = OwnedBy.cache;
6692 if (Expression ex = scrubArrayCache(ale.elements))
6693 return ex;
6694 }
6695 else if (auto aae = e.isAssocArrayLiteralExp())
6696 {
6697 aae.ownedByCtfe = OwnedBy.cache;
6698 if (auto ex = scrubArrayCache(aae.keys))
6699 return ex;
6700 if (auto ex = scrubArrayCache(aae.values))
6701 return ex;
6702 }
6703 else if (auto ve = e.isVectorExp())
6704 {
6705 ve.ownedByCtfe = OwnedBy.cache;
6706 if (auto ale = ve.e1.isArrayLiteralExp())
6707 {
6708 ale.ownedByCtfe = OwnedBy.cache;
6709 if (auto ex = scrubArrayCache(ale.elements))
6710 return ex;
6711 }
6712 }
6713 return e;
6714 }
6715
6716 /********************************************
6717 * Transitively replace all Expressions allocated in ctfeGlobals.region
6718 * with Mem owned copies.
6719 * Params:
6720 * e = possible ctfeGlobals.region owned expression
6721 * Returns:
6722 * Mem owned expression
6723 */
6724 private Expression copyRegionExp(Expression e)
6725 {
6726 if (!e)
6727 return e;
6728
6729 static void copyArray(Expressions* elems)
6730 {
6731 foreach (ref e; *elems)
6732 {
6733 auto ex = e;
6734 e = null;
6735 e = copyRegionExp(ex);
6736 }
6737 }
6738
6739 static void copySE(StructLiteralExp sle)
6740 {
6741 if (1 || !(sle.stageflags & stageScrub))
6742 {
6743 const old = sle.stageflags;
6744 sle.stageflags |= stageScrub; // prevent infinite recursion
6745 copyArray(sle.elements);
6746 sle.stageflags = old;
6747 }
6748 }
6749
6750 switch (e.op)
6751 {
6752 case EXP.classReference:
6753 {
6754 auto cre = e.isClassReferenceExp();
6755 cre.value = copyRegionExp(cre.value).isStructLiteralExp();
6756 break;
6757 }
6758
6759 case EXP.structLiteral:
6760 {
6761 auto sle = e.isStructLiteralExp();
6762
6763 /* The following is to take care of updating sle.origin correctly,
6764 * which may have multiple objects pointing to it.
6765 */
6766 if (sle.isOriginal && !ctfeGlobals.region.contains(cast(void*)sle.origin))
6767 {
6768 /* This means sle has already been moved out of the region,
6769 * and sle.origin is the new location.
6770 */
6771 return sle.origin;
6772 }
6773 copySE(sle);
6774 sle.isOriginal = sle is sle.origin;
6775
6776 auto slec = ctfeGlobals.region.contains(cast(void*)e)
6777 ? e.copy().isStructLiteralExp() // move sle out of region to slec
6778 : sle;
6779
6780 if (ctfeGlobals.region.contains(cast(void*)sle.origin))
6781 {
6782 auto sleo = sle.origin == sle ? slec : sle.origin.copy().isStructLiteralExp();
6783 sle.origin = sleo;
6784 slec.origin = sleo;
6785 }
6786 return slec;
6787 }
6788
6789 case EXP.arrayLiteral:
6790 {
6791 auto ale = e.isArrayLiteralExp();
6792 ale.basis = copyRegionExp(ale.basis);
6793 copyArray(ale.elements);
6794 break;
6795 }
6796
6797 case EXP.assocArrayLiteral:
6798 copyArray(e.isAssocArrayLiteralExp().keys);
6799 copyArray(e.isAssocArrayLiteralExp().values);
6800 break;
6801
6802 case EXP.slice:
6803 {
6804 auto se = e.isSliceExp();
6805 se.e1 = copyRegionExp(se.e1);
6806 se.upr = copyRegionExp(se.upr);
6807 se.lwr = copyRegionExp(se.lwr);
6808 break;
6809 }
6810
6811 case EXP.tuple:
6812 {
6813 auto te = e.isTupleExp();
6814 te.e0 = copyRegionExp(te.e0);
6815 copyArray(te.exps);
6816 break;
6817 }
6818
6819 case EXP.address:
6820 case EXP.delegate_:
6821 case EXP.vector:
6822 case EXP.dotVariable:
6823 {
6824 UnaExp ue = cast(UnaExp)e;
6825 ue.e1 = copyRegionExp(ue.e1);
6826 break;
6827 }
6828
6829 case EXP.index:
6830 {
6831 BinExp be = cast(BinExp)e;
6832 be.e1 = copyRegionExp(be.e1);
6833 be.e2 = copyRegionExp(be.e2);
6834 break;
6835 }
6836
6837 case EXP.this_:
6838 case EXP.super_:
6839 case EXP.variable:
6840 case EXP.type:
6841 case EXP.function_:
6842 case EXP.typeid_:
6843 case EXP.string_:
6844 case EXP.int64:
6845 case EXP.error:
6846 case EXP.float64:
6847 case EXP.complex80:
6848 case EXP.null_:
6849 case EXP.void_:
6850 case EXP.symbolOffset:
6851 case EXP.char_:
6852 break;
6853
6854 case EXP.cantExpression:
6855 case EXP.voidExpression:
6856 case EXP.showCtfeContext:
6857 return e;
6858
6859 default:
6860 printf("e: %s, %s\n", EXPtoString(e.op).ptr, e.toChars());
6861 assert(0);
6862 }
6863
6864 if (ctfeGlobals.region.contains(cast(void*)e))
6865 {
6866 return e.copy();
6867 }
6868 return e;
6869 }
6870
6871 /******************************* Special Functions ***************************/
6872
6873 private Expression interpret_length(UnionExp* pue, InterState* istate, Expression earg)
6874 {
6875 //printf("interpret_length()\n");
6876 earg = interpret(pue, earg, istate);
6877 if (exceptionOrCantInterpret(earg))
6878 return earg;
6879 dinteger_t len = 0;
6880 if (auto aae = earg.isAssocArrayLiteralExp())
6881 len = aae.keys.dim;
6882 else
6883 assert(earg.op == EXP.null_);
6884 emplaceExp!(IntegerExp)(pue, earg.loc, len, Type.tsize_t);
6885 return pue.exp();
6886 }
6887
6888 private Expression interpret_keys(UnionExp* pue, InterState* istate, Expression earg, Type returnType)
6889 {
6890 debug (LOG)
6891 {
6892 printf("interpret_keys()\n");
6893 }
6894 earg = interpret(pue, earg, istate);
6895 if (exceptionOrCantInterpret(earg))
6896 return earg;
6897 if (earg.op == EXP.null_)
6898 {
6899 emplaceExp!(NullExp)(pue, earg.loc, earg.type);
6900 return pue.exp();
6901 }
6902 if (earg.op != EXP.assocArrayLiteral && earg.type.toBasetype().ty != Taarray)
6903 return null;
6904 AssocArrayLiteralExp aae = earg.isAssocArrayLiteralExp();
6905 auto ae = ctfeEmplaceExp!ArrayLiteralExp(aae.loc, returnType, aae.keys);
6906 ae.ownedByCtfe = aae.ownedByCtfe;
6907 *pue = copyLiteral(ae);
6908 return pue.exp();
6909 }
6910
6911 private Expression interpret_values(UnionExp* pue, InterState* istate, Expression earg, Type returnType)
6912 {
6913 debug (LOG)
6914 {
6915 printf("interpret_values()\n");
6916 }
6917 earg = interpret(pue, earg, istate);
6918 if (exceptionOrCantInterpret(earg))
6919 return earg;
6920 if (earg.op == EXP.null_)
6921 {
6922 emplaceExp!(NullExp)(pue, earg.loc, earg.type);
6923 return pue.exp();
6924 }
6925 if (earg.op != EXP.assocArrayLiteral && earg.type.toBasetype().ty != Taarray)
6926 return null;
6927 auto aae = earg.isAssocArrayLiteralExp();
6928 auto ae = ctfeEmplaceExp!ArrayLiteralExp(aae.loc, returnType, aae.values);
6929 ae.ownedByCtfe = aae.ownedByCtfe;
6930 //printf("result is %s\n", e.toChars());
6931 *pue = copyLiteral(ae);
6932 return pue.exp();
6933 }
6934
6935 private Expression interpret_dup(UnionExp* pue, InterState* istate, Expression earg)
6936 {
6937 debug (LOG)
6938 {
6939 printf("interpret_dup()\n");
6940 }
6941 earg = interpret(pue, earg, istate);
6942 if (exceptionOrCantInterpret(earg))
6943 return earg;
6944 if (earg.op == EXP.null_)
6945 {
6946 emplaceExp!(NullExp)(pue, earg.loc, earg.type);
6947 return pue.exp();
6948 }
6949 if (earg.op != EXP.assocArrayLiteral && earg.type.toBasetype().ty != Taarray)
6950 return null;
6951 auto aae = copyLiteral(earg).copy().isAssocArrayLiteralExp();
6952 for (size_t i = 0; i < aae.keys.dim; i++)
6953 {
6954 if (Expression e = evaluatePostblit(istate, (*aae.keys)[i]))
6955 return e;
6956 if (Expression e = evaluatePostblit(istate, (*aae.values)[i]))
6957 return e;
6958 }
6959 aae.type = earg.type.mutableOf(); // repaint type from const(int[int]) to const(int)[int]
6960 //printf("result is %s\n", aae.toChars());
6961 return aae;
6962 }
6963
6964 // signature is int delegate(ref Value) OR int delegate(ref Key, ref Value)
6965 private Expression interpret_aaApply(UnionExp* pue, InterState* istate, Expression aa, Expression deleg)
6966 {
6967 aa = interpret(aa, istate);
6968 if (exceptionOrCantInterpret(aa))
6969 return aa;
6970 if (aa.op != EXP.assocArrayLiteral)
6971 {
6972 emplaceExp!(IntegerExp)(pue, deleg.loc, 0, Type.tsize_t);
6973 return pue.exp();
6974 }
6975
6976 FuncDeclaration fd = null;
6977 Expression pthis = null;
6978 if (auto de = deleg.isDelegateExp())
6979 {
6980 fd = de.func;
6981 pthis = de.e1;
6982 }
6983 else if (auto fe = deleg.isFuncExp())
6984 fd = fe.fd;
6985
6986 assert(fd && fd.fbody);
6987 assert(fd.parameters);
6988 size_t numParams = fd.parameters.dim;
6989 assert(numParams == 1 || numParams == 2);
6990
6991 Parameter fparam = fd.type.isTypeFunction().parameterList[numParams - 1];
6992 const wantRefValue = fparam.isReference();
6993
6994 Expressions args = Expressions(numParams);
6995
6996 AssocArrayLiteralExp ae = cast(AssocArrayLiteralExp)aa;
6997 if (!ae.keys || ae.keys.dim == 0)
6998 return ctfeEmplaceExp!IntegerExp(deleg.loc, 0, Type.tsize_t);
6999 Expression eresult;
7000
7001 for (size_t i = 0; i < ae.keys.dim; ++i)
7002 {
7003 Expression ekey = (*ae.keys)[i];
7004 Expression evalue = (*ae.values)[i];
7005 if (wantRefValue)
7006 {
7007 Type t = evalue.type;
7008 evalue = ctfeEmplaceExp!IndexExp(deleg.loc, ae, ekey);
7009 evalue.type = t;
7010 }
7011 args[numParams - 1] = evalue;
7012 if (numParams == 2)
7013 args[0] = ekey;
7014
7015 UnionExp ue = void;
7016 eresult = interpretFunction(&ue, fd, istate, &args, pthis);
7017 if (eresult == ue.exp())
7018 eresult = ue.copy();
7019 if (exceptionOrCantInterpret(eresult))
7020 return eresult;
7021
7022 if (eresult.isIntegerExp().getInteger() != 0)
7023 return eresult;
7024 }
7025 return eresult;
7026 }
7027
7028 /* Decoding UTF strings for foreach loops. Duplicates the functionality of
7029 * the twelve _aApplyXXn functions in aApply.d in the runtime.
7030 */
7031 private Expression foreachApplyUtf(UnionExp* pue, InterState* istate, Expression str, Expression deleg, bool rvs)
7032 {
7033 debug (LOG)
7034 {
7035 printf("foreachApplyUtf(%s, %s)\n", str.toChars(), deleg.toChars());
7036 }
7037 FuncDeclaration fd = null;
7038 Expression pthis = null;
7039 if (auto de = deleg.isDelegateExp())
7040 {
7041 fd = de.func;
7042 pthis = de.e1;
7043 }
7044 else if (auto fe = deleg.isFuncExp())
7045 fd = fe.fd;
7046
7047 assert(fd && fd.fbody);
7048 assert(fd.parameters);
7049 size_t numParams = fd.parameters.dim;
7050 assert(numParams == 1 || numParams == 2);
7051 Type charType = (*fd.parameters)[numParams - 1].type;
7052 Type indexType = numParams == 2 ? (*fd.parameters)[0].type : Type.tsize_t;
7053 size_t len = cast(size_t)resolveArrayLength(str);
7054 if (len == 0)
7055 {
7056 emplaceExp!(IntegerExp)(pue, deleg.loc, 0, indexType);
7057 return pue.exp();
7058 }
7059
7060 UnionExp strTmp = void;
7061 str = resolveSlice(str, &strTmp);
7062
7063 auto se = str.isStringExp();
7064 auto ale = str.isArrayLiteralExp();
7065 if (!se && !ale)
7066 {
7067 str.error("CTFE internal error: cannot foreach `%s`", str.toChars());
7068 return CTFEExp.cantexp;
7069 }
7070 Expressions args = Expressions(numParams);
7071
7072 Expression eresult = null; // ded-store to prevent spurious warning
7073
7074 // Buffers for encoding; also used for decoding array literals
7075 char[4] utf8buf = void;
7076 wchar[2] utf16buf = void;
7077
7078 size_t start = rvs ? len : 0;
7079 size_t end = rvs ? 0 : len;
7080 for (size_t indx = start; indx != end;)
7081 {
7082 // Step 1: Decode the next dchar from the string.
7083
7084 string errmsg = null; // Used for reporting decoding errors
7085 dchar rawvalue; // Holds the decoded dchar
7086 size_t currentIndex = indx; // The index of the decoded character
7087
7088 if (ale)
7089 {
7090 // If it is an array literal, copy the code points into the buffer
7091 size_t buflen = 1; // #code points in the buffer
7092 size_t n = 1; // #code points in this char
7093 size_t sz = cast(size_t)ale.type.nextOf().size();
7094
7095 switch (sz)
7096 {
7097 case 1:
7098 if (rvs)
7099 {
7100 // find the start of the string
7101 --indx;
7102 buflen = 1;
7103 while (indx > 0 && buflen < 4)
7104 {
7105 Expression r = (*ale.elements)[indx];
7106 char x = cast(char)r.isIntegerExp().getInteger();
7107 if ((x & 0xC0) != 0x80)
7108 break;
7109 --indx;
7110 ++buflen;
7111 }
7112 }
7113 else
7114 buflen = (indx + 4 > len) ? len - indx : 4;
7115 for (size_t i = 0; i < buflen; ++i)
7116 {
7117 Expression r = (*ale.elements)[indx + i];
7118 utf8buf[i] = cast(char)r.isIntegerExp().getInteger();
7119 }
7120 n = 0;
7121 errmsg = utf_decodeChar(utf8buf[0 .. buflen], n, rawvalue);
7122 break;
7123
7124 case 2:
7125 if (rvs)
7126 {
7127 // find the start of the string
7128 --indx;
7129 buflen = 1;
7130 Expression r = (*ale.elements)[indx];
7131 ushort x = cast(ushort)r.isIntegerExp().getInteger();
7132 if (indx > 0 && x >= 0xDC00 && x <= 0xDFFF)
7133 {
7134 --indx;
7135 ++buflen;
7136 }
7137 }
7138 else
7139 buflen = (indx + 2 > len) ? len - indx : 2;
7140 for (size_t i = 0; i < buflen; ++i)
7141 {
7142 Expression r = (*ale.elements)[indx + i];
7143 utf16buf[i] = cast(ushort)r.isIntegerExp().getInteger();
7144 }
7145 n = 0;
7146 errmsg = utf_decodeWchar(utf16buf[0 .. buflen], n, rawvalue);
7147 break;
7148
7149 case 4:
7150 {
7151 if (rvs)
7152 --indx;
7153 Expression r = (*ale.elements)[indx];
7154 rawvalue = cast(dchar)r.isIntegerExp().getInteger();
7155 n = 1;
7156 }
7157 break;
7158
7159 default:
7160 assert(0);
7161 }
7162 if (!rvs)
7163 indx += n;
7164 }
7165 else
7166 {
7167 // String literals
7168 size_t saveindx; // used for reverse iteration
7169
7170 switch (se.sz)
7171 {
7172 case 1:
7173 {
7174 if (rvs)
7175 {
7176 // find the start of the string
7177 --indx;
7178 while (indx > 0 && ((se.getCodeUnit(indx) & 0xC0) == 0x80))
7179 --indx;
7180 saveindx = indx;
7181 }
7182 auto slice = se.peekString();
7183 errmsg = utf_decodeChar(slice, indx, rawvalue);
7184 if (rvs)
7185 indx = saveindx;
7186 break;
7187 }
7188
7189 case 2:
7190 if (rvs)
7191 {
7192 // find the start
7193 --indx;
7194 auto wc = se.getCodeUnit(indx);
7195 if (wc >= 0xDC00 && wc <= 0xDFFF)
7196 --indx;
7197 saveindx = indx;
7198 }
7199 const slice = se.peekWstring();
7200 errmsg = utf_decodeWchar(slice, indx, rawvalue);
7201 if (rvs)
7202 indx = saveindx;
7203 break;
7204
7205 case 4:
7206 if (rvs)
7207 --indx;
7208 rawvalue = se.getCodeUnit(indx);
7209 if (!rvs)
7210 ++indx;
7211 break;
7212
7213 default:
7214 assert(0);
7215 }
7216 }
7217 if (errmsg)
7218 {
7219 deleg.error("`%.*s`", cast(int)errmsg.length, errmsg.ptr);
7220 return CTFEExp.cantexp;
7221 }
7222
7223 // Step 2: encode the dchar in the target encoding
7224
7225 int charlen = 1; // How many codepoints are involved?
7226 switch (charType.size())
7227 {
7228 case 1:
7229 charlen = utf_codeLengthChar(rawvalue);
7230 utf_encodeChar(&utf8buf[0], rawvalue);
7231 break;
7232 case 2:
7233 charlen = utf_codeLengthWchar(rawvalue);
7234 utf_encodeWchar(&utf16buf[0], rawvalue);
7235 break;
7236 case 4:
7237 break;
7238 default:
7239 assert(0);
7240 }
7241 if (rvs)
7242 currentIndex = indx;
7243
7244 // Step 3: call the delegate once for each code point
7245
7246 // The index only needs to be set once
7247 if (numParams == 2)
7248 args[0] = ctfeEmplaceExp!IntegerExp(deleg.loc, currentIndex, indexType);
7249
7250 Expression val = null;
7251
7252 foreach (k; 0 .. charlen)
7253 {
7254 dchar codepoint;
7255 switch (charType.size())
7256 {
7257 case 1:
7258 codepoint = utf8buf[k];
7259 break;
7260 case 2:
7261 codepoint = utf16buf[k];
7262 break;
7263 case 4:
7264 codepoint = rawvalue;
7265 break;
7266 default:
7267 assert(0);
7268 }
7269 val = ctfeEmplaceExp!IntegerExp(str.loc, codepoint, charType);
7270
7271 args[numParams - 1] = val;
7272
7273 UnionExp ue = void;
7274 eresult = interpretFunction(&ue, fd, istate, &args, pthis);
7275 if (eresult == ue.exp())
7276 eresult = ue.copy();
7277 if (exceptionOrCantInterpret(eresult))
7278 return eresult;
7279 if (eresult.isIntegerExp().getInteger() != 0)
7280 return eresult;
7281 }
7282 }
7283 return eresult;
7284 }
7285
7286 /* If this is a built-in function, return the interpreted result,
7287 * Otherwise, return NULL.
7288 */
7289 private Expression evaluateIfBuiltin(UnionExp* pue, InterState* istate, const ref Loc loc, FuncDeclaration fd, Expressions* arguments, Expression pthis)
7290 {
7291 Expression e = null;
7292 size_t nargs = arguments ? arguments.dim : 0;
7293 if (!pthis)
7294 {
7295 if (isBuiltin(fd) != BUILTIN.unimp)
7296 {
7297 Expressions args = Expressions(nargs);
7298 foreach (i, ref arg; args)
7299 {
7300 Expression earg = (*arguments)[i];
7301 earg = interpret(earg, istate);
7302 if (exceptionOrCantInterpret(earg))
7303 return earg;
7304 arg = earg;
7305 }
7306 e = eval_builtin(loc, fd, &args);
7307 if (!e)
7308 {
7309 error(loc, "cannot evaluate unimplemented builtin `%s` at compile time", fd.toChars());
7310 e = CTFEExp.cantexp;
7311 }
7312 }
7313 }
7314 if (!pthis)
7315 {
7316 if (nargs == 1 || nargs == 3)
7317 {
7318 Expression firstarg = (*arguments)[0];
7319 if (auto firstAAtype = firstarg.type.toBasetype().isTypeAArray())
7320 {
7321 const id = fd.ident;
7322 if (nargs == 1)
7323 {
7324 if (id == Id.aaLen)
7325 return interpret_length(pue, istate, firstarg);
7326
7327 if (fd.toParent2().ident == Id.object)
7328 {
7329 if (id == Id.keys)
7330 return interpret_keys(pue, istate, firstarg, firstAAtype.index.arrayOf());
7331 if (id == Id.values)
7332 return interpret_values(pue, istate, firstarg, firstAAtype.nextOf().arrayOf());
7333 if (id == Id.rehash)
7334 return interpret(pue, firstarg, istate);
7335 if (id == Id.dup)
7336 return interpret_dup(pue, istate, firstarg);
7337 }
7338 }
7339 else // (nargs == 3)
7340 {
7341 if (id == Id._aaApply)
7342 return interpret_aaApply(pue, istate, firstarg, (*arguments)[2]);
7343 if (id == Id._aaApply2)
7344 return interpret_aaApply(pue, istate, firstarg, (*arguments)[2]);
7345 }
7346 }
7347 }
7348 }
7349 if (pthis && !fd.fbody && fd.isCtorDeclaration() && fd.parent && fd.parent.parent && fd.parent.parent.ident == Id.object)
7350 {
7351 if (pthis.op == EXP.classReference && fd.parent.ident == Id.Throwable)
7352 {
7353 // At present, the constructors just copy their arguments into the struct.
7354 // But we might need some magic if stack tracing gets added to druntime.
7355 StructLiteralExp se = (cast(ClassReferenceExp)pthis).value;
7356 assert(arguments.dim <= se.elements.dim);
7357 foreach (i, arg; *arguments)
7358 {
7359 auto elem = interpret(arg, istate);
7360 if (exceptionOrCantInterpret(elem))
7361 return elem;
7362 (*se.elements)[i] = elem;
7363 }
7364 return CTFEExp.voidexp;
7365 }
7366 }
7367 if (nargs == 1 && !pthis && (fd.ident == Id.criticalenter || fd.ident == Id.criticalexit))
7368 {
7369 // Support synchronized{} as a no-op
7370 return CTFEExp.voidexp;
7371 }
7372 if (!pthis)
7373 {
7374 const idlen = fd.ident.toString().length;
7375 const id = fd.ident.toChars();
7376 if (nargs == 2 && (idlen == 10 || idlen == 11) && !strncmp(id, "_aApply", 7))
7377 {
7378 // Functions from aApply.d and aApplyR.d in the runtime
7379 bool rvs = (idlen == 11); // true if foreach_reverse
7380 char c = id[idlen - 3]; // char width: 'c', 'w', or 'd'
7381 char s = id[idlen - 2]; // string width: 'c', 'w', or 'd'
7382 char n = id[idlen - 1]; // numParams: 1 or 2.
7383 // There are 12 combinations
7384 if ((n == '1' || n == '2') &&
7385 (c == 'c' || c == 'w' || c == 'd') &&
7386 (s == 'c' || s == 'w' || s == 'd') &&
7387 c != s)
7388 {
7389 Expression str = (*arguments)[0];
7390 str = interpret(str, istate);
7391 if (exceptionOrCantInterpret(str))
7392 return str;
7393 return foreachApplyUtf(pue, istate, str, (*arguments)[1], rvs);
7394 }
7395 }
7396 }
7397 return e;
7398 }
7399
7400 private Expression evaluatePostblit(InterState* istate, Expression e)
7401 {
7402 auto ts = e.type.baseElemOf().isTypeStruct();
7403 if (!ts)
7404 return null;
7405 StructDeclaration sd = ts.sym;
7406 if (!sd.postblit)
7407 return null;
7408
7409 if (auto ale = e.isArrayLiteralExp())
7410 {
7411 foreach (elem; *ale.elements)
7412 {
7413 if (auto ex = evaluatePostblit(istate, elem))
7414 return ex;
7415 }
7416 return null;
7417 }
7418 if (e.op == EXP.structLiteral)
7419 {
7420 // e.__postblit()
7421 UnionExp ue = void;
7422 e = interpretFunction(&ue, sd.postblit, istate, null, e);
7423 if (e == ue.exp())
7424 e = ue.copy();
7425 if (exceptionOrCantInterpret(e))
7426 return e;
7427 return null;
7428 }
7429 assert(0);
7430 }
7431
7432 private Expression evaluateDtor(InterState* istate, Expression e)
7433 {
7434 auto ts = e.type.baseElemOf().isTypeStruct();
7435 if (!ts)
7436 return null;
7437 StructDeclaration sd = ts.sym;
7438 if (!sd.dtor)
7439 return null;
7440
7441 UnionExp ue = void;
7442 if (auto ale = e.isArrayLiteralExp())
7443 {
7444 foreach_reverse (elem; *ale.elements)
7445 e = evaluateDtor(istate, elem);
7446 }
7447 else if (e.op == EXP.structLiteral)
7448 {
7449 // e.__dtor()
7450 e = interpretFunction(&ue, sd.dtor, istate, null, e);
7451 }
7452 else
7453 assert(0);
7454 if (exceptionOrCantInterpret(e))
7455 {
7456 if (e == ue.exp())
7457 e = ue.copy();
7458 return e;
7459 }
7460 return null;
7461 }
7462
7463 /*************************** CTFE Sanity Checks ***************************/
7464 /* Setter functions for CTFE variable values.
7465 * These functions exist to check for compiler CTFE bugs.
7466 */
7467 private bool hasValue(VarDeclaration vd)
7468 {
7469 return vd.ctfeAdrOnStack != VarDeclaration.AdrOnStackNone &&
7470 getValue(vd) !is null;
7471 }
7472
7473 // Don't check for validity
7474 private void setValueWithoutChecking(VarDeclaration vd, Expression newval)
7475 {
7476 ctfeGlobals.stack.setValue(vd, newval);
7477 }
7478
7479 private void setValue(VarDeclaration vd, Expression newval)
7480 {
7481 //printf("setValue() vd: %s newval: %s\n", vd.toChars(), newval.toChars());
7482 version (none)
7483 {
7484 if (!((vd.storage_class & (STC.out_ | STC.ref_)) ? isCtfeReferenceValid(newval) : isCtfeValueValid(newval)))
7485 {
7486 printf("[%s] vd = %s %s, newval = %s\n", vd.loc.toChars(), vd.type.toChars(), vd.toChars(), newval.toChars());
7487 }
7488 }
7489 assert((vd.storage_class & (STC.out_ | STC.ref_)) ? isCtfeReferenceValid(newval) : isCtfeValueValid(newval));
7490 ctfeGlobals.stack.setValue(vd, newval);
7491 }
7492
7493 /**
7494 * Removes `_d_HookTraceImpl` if found from `ce` and `fd`.
7495 * This is needed for the CTFE interception code to be able to find hooks that are called though the hook's `*Trace`
7496 * wrapper.
7497 *
7498 * This is done by replacing `_d_HookTraceImpl!(T, Hook, errMsg)(..., parameters)` with `Hook(parameters)`.
7499 * Parameters:
7500 * ce = The CallExp that possible will be be replaced
7501 * fd = Fully resolve function declaration that `ce` would call
7502 */
7503 private void removeHookTraceImpl(ref CallExp ce, ref FuncDeclaration fd)
7504 {
7505 if (fd.ident != Id._d_HookTraceImpl)
7506 return;
7507
7508 auto oldCE = ce;
7509
7510 // Get the Hook from the second template parameter
7511 TemplateInstance templateInstance = fd.parent.isTemplateInstance;
7512 RootObject hook = (*templateInstance.tiargs)[1];
7513 assert(hook.dyncast() == DYNCAST.dsymbol, "Expected _d_HookTraceImpl's second template parameter to be an alias to the hook!");
7514 fd = (cast(Dsymbol)hook).isFuncDeclaration;
7515
7516 // Remove the first three trace parameters
7517 auto arguments = new Expressions();
7518 arguments.reserve(ce.arguments.dim - 3);
7519 arguments.pushSlice((*ce.arguments)[3 .. $]);
7520
7521 ce = ctfeEmplaceExp!CallExp(ce.loc, ctfeEmplaceExp!VarExp(ce.loc, fd, false), arguments);
7522
7523 if (global.params.verbose)
7524 message("strip %s =>\n %s", oldCE.toChars(), ce.toChars());
7525 }