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