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