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