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