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