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