1 /** 2 * Compiler implementation of the 3 * $(LINK2 http://www.dlang.org, D programming language). 4 * 5 * Copyright: Copyright (c) 1999-2016 by Digital Mars, All Rights Reserved 6 * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) 7 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 8 * Source: $(DMDSRC _ctfeexpr.d) 9 */ 10 11 module ddmd.ctfeexpr; 12 13 import core.stdc.stdio; 14 import core.stdc..string; 15 import ddmd.arraytypes; 16 import ddmd.complex; 17 import ddmd.constfold; 18 import ddmd.dclass; 19 import ddmd.declaration; 20 import ddmd.dinterpret; 21 import ddmd.dstruct; 22 import ddmd.dtemplate; 23 import ddmd.errors; 24 import ddmd.expression; 25 import ddmd.func; 26 import ddmd.globals; 27 import ddmd.mtype; 28 import ddmd.root.ctfloat; 29 import ddmd.root.port; 30 import ddmd.root.rmem; 31 import ddmd.target; 32 import ddmd.tokens; 33 import ddmd.visitor; 34 35 /*********************************************************** 36 * Global status of the CTFE engine. Mostly used for performance diagnostics 37 */ 38 struct CtfeStatus 39 { 40 extern (C++) static __gshared int callDepth = 0; // current number of recursive calls 41 42 // When printing a stack trace, suppress this number of calls 43 extern (C++) static __gshared int stackTraceCallsToSuppress = 0; 44 45 extern (C++) static __gshared int maxCallDepth = 0; // highest number of recursive calls 46 extern (C++) static __gshared int numArrayAllocs = 0; // Number of allocated arrays 47 extern (C++) static __gshared int numAssignments = 0; // total number of assignments executed 48 } 49 50 /*********************************************************** 51 * A reference to a class, or an interface. We need this when we 52 * point to a base class (we must record what the type is). 53 */ 54 extern (C++) final class ClassReferenceExp : Expression 55 { 56 StructLiteralExp value; 57 58 extern (D) this(Loc loc, StructLiteralExp lit, Type type) 59 { 60 super(loc, TOKclassreference, __traits(classInstanceSize, ClassReferenceExp)); 61 assert(lit && lit.sd && lit.sd.isClassDeclaration()); 62 this.value = lit; 63 this.type = type; 64 } 65 66 ClassDeclaration originalClass() 67 { 68 return value.sd.isClassDeclaration(); 69 } 70 71 // Return index of the field, or -1 if not found 72 int getFieldIndex(Type fieldtype, uint fieldoffset) 73 { 74 ClassDeclaration cd = originalClass(); 75 uint fieldsSoFar = 0; 76 for (size_t j = 0; j < value.elements.dim; j++) 77 { 78 while (j - fieldsSoFar >= cd.fields.dim) 79 { 80 fieldsSoFar += cd.fields.dim; 81 cd = cd.baseClass; 82 } 83 VarDeclaration v2 = cd.fields[j - fieldsSoFar]; 84 if (fieldoffset == v2.offset && fieldtype.size() == v2.type.size()) 85 { 86 return cast(int)(value.elements.dim - fieldsSoFar - cd.fields.dim + (j - fieldsSoFar)); 87 } 88 } 89 return -1; 90 } 91 92 // Return index of the field, or -1 if not found 93 // Same as getFieldIndex, but checks for a direct match with the VarDeclaration 94 int findFieldIndexByName(VarDeclaration v) 95 { 96 ClassDeclaration cd = originalClass(); 97 size_t fieldsSoFar = 0; 98 for (size_t j = 0; j < value.elements.dim; j++) 99 { 100 while (j - fieldsSoFar >= cd.fields.dim) 101 { 102 fieldsSoFar += cd.fields.dim; 103 cd = cd.baseClass; 104 } 105 VarDeclaration v2 = cd.fields[j - fieldsSoFar]; 106 if (v == v2) 107 { 108 return cast(int)(value.elements.dim - fieldsSoFar - cd.fields.dim + (j - fieldsSoFar)); 109 } 110 } 111 return -1; 112 } 113 114 override void accept(Visitor v) 115 { 116 v.visit(this); 117 } 118 } 119 120 /*********************************************************** 121 * An uninitialized value 122 */ 123 extern (C++) final class VoidInitExp : Expression 124 { 125 VarDeclaration var; 126 127 extern (D) this(VarDeclaration var, Type type) 128 { 129 super(var.loc, TOKvoid, __traits(classInstanceSize, VoidInitExp)); 130 this.var = var; 131 this.type = var.type; 132 } 133 134 override const(char)* toChars() const 135 { 136 return "void"; 137 } 138 139 override void accept(Visitor v) 140 { 141 v.visit(this); 142 } 143 } 144 145 // Return index of the field, or -1 if not found 146 // Same as getFieldIndex, but checks for a direct match with the VarDeclaration 147 extern (C++) int findFieldIndexByName(StructDeclaration sd, VarDeclaration v) 148 { 149 for (size_t i = 0; i < sd.fields.dim; ++i) 150 { 151 if (sd.fields[i] == v) 152 return cast(int)i; 153 } 154 return -1; 155 } 156 157 /*********************************************************** 158 * Fake class which holds the thrown exception. 159 * Used for implementing exception handling. 160 */ 161 extern (C++) final class ThrownExceptionExp : Expression 162 { 163 ClassReferenceExp thrown; // the thing being tossed 164 165 extern (D) this(Loc loc, ClassReferenceExp victim) 166 { 167 super(loc, TOKthrownexception, __traits(classInstanceSize, ThrownExceptionExp)); 168 this.thrown = victim; 169 this.type = victim.type; 170 } 171 172 override const(char)* toChars() const 173 { 174 return "CTFE ThrownException"; 175 } 176 177 // Generate an error message when this exception is not caught 178 void generateUncaughtError() 179 { 180 Expression e = resolveSlice((*thrown.value.elements)[0]); 181 StringExp se = e.toStringExp(); 182 thrown.error("uncaught CTFE exception %s(%s)", thrown.type.toChars(), se ? se.toChars() : e.toChars()); 183 /* Also give the line where the throw statement was. We won't have it 184 * in the case where the ThrowStatement is generated internally 185 * (eg, in ScopeStatement) 186 */ 187 if (loc.filename && !loc.equals(thrown.loc)) 188 errorSupplemental(loc, "thrown from here"); 189 } 190 191 override void accept(Visitor v) 192 { 193 v.visit(this); 194 } 195 } 196 197 /*********************************************************** 198 * This type is only used by the interpreter. 199 */ 200 extern (C++) final class CTFEExp : Expression 201 { 202 extern (D) this(TOK tok) 203 { 204 super(Loc(), tok, __traits(classInstanceSize, CTFEExp)); 205 type = Type.tvoid; 206 } 207 208 override const(char)* toChars() const 209 { 210 switch (op) 211 { 212 case TOKcantexp: 213 return "<cant>"; 214 case TOKvoidexp: 215 return "<void>"; 216 case TOKbreak: 217 return "<break>"; 218 case TOKcontinue: 219 return "<continue>"; 220 case TOKgoto: 221 return "<goto>"; 222 default: 223 assert(0); 224 } 225 } 226 227 extern (C++) static __gshared CTFEExp cantexp; 228 extern (C++) static __gshared CTFEExp voidexp; 229 extern (C++) static __gshared CTFEExp breakexp; 230 extern (C++) static __gshared CTFEExp continueexp; 231 extern (C++) static __gshared CTFEExp gotoexp; 232 233 static bool isCantExp(Expression e) 234 { 235 return e && e.op == TOKcantexp; 236 } 237 238 static bool isGotoExp(Expression e) 239 { 240 return e && e.op == TOKgoto; 241 } 242 } 243 244 // True if 'e' is CTFEExp::cantexp, or an exception 245 extern (C++) bool exceptionOrCantInterpret(Expression e) 246 { 247 return e && (e.op == TOKcantexp || e.op == TOKthrownexception); 248 } 249 250 /************** Aggregate literals (AA/string/array/struct) ******************/ 251 // Given expr, which evaluates to an array/AA/string literal, 252 // return true if it needs to be copied 253 extern (C++) bool needToCopyLiteral(Expression expr) 254 { 255 for (;;) 256 { 257 switch (expr.op) 258 { 259 case TOKarrayliteral: 260 return (cast(ArrayLiteralExp)expr).ownedByCtfe == OWNEDcode; 261 case TOKassocarrayliteral: 262 return (cast(AssocArrayLiteralExp)expr).ownedByCtfe == OWNEDcode; 263 case TOKstructliteral: 264 return (cast(StructLiteralExp)expr).ownedByCtfe == OWNEDcode; 265 case TOKstring: 266 case TOKthis: 267 case TOKvar: 268 return false; 269 case TOKassign: 270 return false; 271 case TOKindex: 272 case TOKdotvar: 273 case TOKslice: 274 case TOKcast: 275 expr = (cast(UnaExp)expr).e1; 276 continue; 277 case TOKcat: 278 return needToCopyLiteral((cast(BinExp)expr).e1) || needToCopyLiteral((cast(BinExp)expr).e2); 279 case TOKcatass: 280 expr = (cast(BinExp)expr).e2; 281 continue; 282 default: 283 return false; 284 } 285 } 286 } 287 288 extern (C++) Expressions* copyLiteralArray(Expressions* oldelems, Expression basis = null) 289 { 290 if (!oldelems) 291 return oldelems; 292 CtfeStatus.numArrayAllocs++; 293 auto newelems = new Expressions(); 294 newelems.setDim(oldelems.dim); 295 for (size_t i = 0; i < oldelems.dim; i++) 296 { 297 auto el = (*oldelems)[i]; 298 if (!el) 299 el = basis; 300 (*newelems)[i] = copyLiteral(el).copy(); 301 } 302 return newelems; 303 } 304 305 // Make a copy of the ArrayLiteral, AALiteral, String, or StructLiteral. 306 // This value will be used for in-place modification. 307 extern (C++) UnionExp copyLiteral(Expression e) 308 { 309 UnionExp ue; 310 if (e.op == TOKstring) // syntaxCopy doesn't make a copy for StringExp! 311 { 312 StringExp se = cast(StringExp)e; 313 char* s = cast(char*)mem.xcalloc(se.len + 1, se.sz); 314 memcpy(s, se..string, se.len * se.sz); 315 emplaceExp!(StringExp)(&ue, se.loc, s, se.len); 316 StringExp se2 = cast(StringExp)ue.exp(); 317 se2.committed = se.committed; 318 se2.postfix = se.postfix; 319 se2.type = se.type; 320 se2.sz = se.sz; 321 se2.ownedByCtfe = OWNEDctfe; 322 return ue; 323 } 324 if (e.op == TOKarrayliteral) 325 { 326 auto ale = cast(ArrayLiteralExp)e; 327 auto basis = ale.basis ? copyLiteral(ale.basis).copy() : null; 328 auto elements = copyLiteralArray(ale.elements, ale.basis); 329 330 emplaceExp!(ArrayLiteralExp)(&ue, e.loc, elements); 331 332 ArrayLiteralExp r = cast(ArrayLiteralExp)ue.exp(); 333 r.type = e.type; 334 r.ownedByCtfe = OWNEDctfe; 335 return ue; 336 } 337 if (e.op == TOKassocarrayliteral) 338 { 339 AssocArrayLiteralExp aae = cast(AssocArrayLiteralExp)e; 340 emplaceExp!(AssocArrayLiteralExp)(&ue, e.loc, copyLiteralArray(aae.keys), copyLiteralArray(aae.values)); 341 AssocArrayLiteralExp r = cast(AssocArrayLiteralExp)ue.exp(); 342 r.type = e.type; 343 r.ownedByCtfe = OWNEDctfe; 344 return ue; 345 } 346 if (e.op == TOKstructliteral) 347 { 348 /* syntaxCopy doesn't work for struct literals, because of a nasty special 349 * case: block assignment is permitted inside struct literals, eg, 350 * an int[4] array can be initialized with a single int. 351 */ 352 auto sle = cast(StructLiteralExp)e; 353 auto oldelems = sle.elements; 354 auto newelems = new Expressions(); 355 newelems.setDim(oldelems.dim); 356 foreach (i, ref el; *newelems) 357 { 358 // We need the struct definition to detect block assignment 359 auto v = sle.sd.fields[i]; 360 auto m = (*oldelems)[i]; 361 362 // If it is a void assignment, use the default initializer 363 if (!m) 364 m = voidInitLiteral(v.type, v).copy(); 365 366 if (v.type.ty == Tarray || v.type.ty == Taarray) 367 { 368 // Don't have to copy array references 369 } 370 else 371 { 372 // Buzilla 15681: Copy the source element always. 373 m = copyLiteral(m).copy(); 374 375 // Block assignment from inside struct literals 376 if (v.type.ty != m.type.ty && v.type.ty == Tsarray) 377 { 378 auto tsa = cast(TypeSArray)v.type; 379 auto len = cast(size_t)tsa.dim.toInteger(); 380 m = createBlockDuplicatedArrayLiteral(e.loc, v.type, m, len); 381 } 382 } 383 el = m; 384 } 385 emplaceExp!(StructLiteralExp)(&ue, e.loc, sle.sd, newelems, sle.stype); 386 auto r = cast(StructLiteralExp)ue.exp(); 387 r.type = e.type; 388 r.ownedByCtfe = OWNEDctfe; 389 r.origin = (cast(StructLiteralExp)e).origin; 390 return ue; 391 } 392 if (e.op == TOKfunction || e.op == TOKdelegate || e.op == TOKsymoff || e.op == TOKnull || e.op == TOKvar || e.op == TOKdotvar || e.op == TOKint64 || e.op == TOKfloat64 || e.op == TOKchar || e.op == TOKcomplex80 || e.op == TOKvoid || e.op == TOKvector || e.op == TOKtypeid) 393 { 394 // Simple value types 395 // Keep e1 for DelegateExp and DotVarExp 396 emplaceExp!(UnionExp)(&ue, e); 397 Expression r = ue.exp(); 398 r.type = e.type; 399 return ue; 400 } 401 if (isPointer(e.type)) 402 { 403 // For pointers, we only do a shallow copy. 404 if (e.op == TOKaddress) 405 emplaceExp!(AddrExp)(&ue, e.loc, (cast(AddrExp)e).e1); 406 else if (e.op == TOKindex) 407 emplaceExp!(IndexExp)(&ue, e.loc, (cast(IndexExp)e).e1, (cast(IndexExp)e).e2); 408 else if (e.op == TOKdotvar) 409 { 410 emplaceExp!(DotVarExp)(&ue, e.loc, (cast(DotVarExp)e).e1, (cast(DotVarExp)e).var, (cast(DotVarExp)e).hasOverloads); 411 } 412 else 413 assert(0); 414 Expression r = ue.exp(); 415 r.type = e.type; 416 return ue; 417 } 418 if (e.op == TOKslice) 419 { 420 SliceExp se = cast(SliceExp)e; 421 if (se.type.toBasetype().ty == Tsarray) 422 { 423 // same with resolveSlice() 424 if (se.e1.op == TOKnull) 425 { 426 emplaceExp!(NullExp)(&ue, se.loc, se.type); 427 return ue; 428 } 429 ue = Slice(se.type, se.e1, se.lwr, se.upr); 430 assert(ue.exp().op == TOKarrayliteral); 431 ArrayLiteralExp r = cast(ArrayLiteralExp)ue.exp(); 432 r.elements = copyLiteralArray(r.elements); 433 r.ownedByCtfe = OWNEDctfe; 434 return ue; 435 } 436 else 437 { 438 // Array slices only do a shallow copy 439 emplaceExp!(SliceExp)(&ue, e.loc, se.e1, se.lwr, se.upr); 440 Expression r = ue.exp(); 441 r.type = e.type; 442 return ue; 443 } 444 } 445 if (e.op == TOKclassreference) 446 { 447 emplaceExp!(ClassReferenceExp)(&ue, e.loc, (cast(ClassReferenceExp)e).value, e.type); 448 return ue; 449 } 450 if (e.op == TOKerror) 451 { 452 emplaceExp!(UnionExp)(&ue, e); 453 return ue; 454 } 455 e.error("CTFE internal error: literal %s", e.toChars()); 456 assert(0); 457 } 458 459 /* Deal with type painting. 460 * Type painting is a major nuisance: we can't just set 461 * e->type = type, because that would change the original literal. 462 * But, we can't simply copy the literal either, because that would change 463 * the values of any pointers. 464 */ 465 extern (C++) Expression paintTypeOntoLiteral(Type type, Expression lit) 466 { 467 if (lit.type.equals(type)) 468 return lit; 469 return paintTypeOntoLiteralCopy(type, lit).copy(); 470 } 471 472 extern (C++) UnionExp paintTypeOntoLiteralCopy(Type type, Expression lit) 473 { 474 UnionExp ue; 475 if (lit.type.equals(type)) 476 { 477 emplaceExp!(UnionExp)(&ue, lit); 478 return ue; 479 } 480 // If it is a cast to inout, retain the original type of the referenced part. 481 if (type.hasWild() && type.hasPointers()) 482 { 483 emplaceExp!(UnionExp)(&ue, lit); 484 ue.exp().type = type; 485 return ue; 486 } 487 if (lit.op == TOKslice) 488 { 489 SliceExp se = cast(SliceExp)lit; 490 emplaceExp!(SliceExp)(&ue, lit.loc, se.e1, se.lwr, se.upr); 491 } 492 else if (lit.op == TOKindex) 493 { 494 IndexExp ie = cast(IndexExp)lit; 495 emplaceExp!(IndexExp)(&ue, lit.loc, ie.e1, ie.e2); 496 } 497 else if (lit.op == TOKarrayliteral) 498 { 499 emplaceExp!(SliceExp)(&ue, lit.loc, lit, new IntegerExp(Loc(), 0, Type.tsize_t), ArrayLength(Type.tsize_t, lit).copy()); 500 } 501 else if (lit.op == TOKstring) 502 { 503 // For strings, we need to introduce another level of indirection 504 emplaceExp!(SliceExp)(&ue, lit.loc, lit, new IntegerExp(Loc(), 0, Type.tsize_t), ArrayLength(Type.tsize_t, lit).copy()); 505 } 506 else if (lit.op == TOKassocarrayliteral) 507 { 508 AssocArrayLiteralExp aae = cast(AssocArrayLiteralExp)lit; 509 // TODO: we should be creating a reference to this AAExp, not 510 // just a ref to the keys and values. 511 OwnedBy wasOwned = aae.ownedByCtfe; 512 emplaceExp!(AssocArrayLiteralExp)(&ue, lit.loc, aae.keys, aae.values); 513 aae = cast(AssocArrayLiteralExp)ue.exp(); 514 aae.ownedByCtfe = wasOwned; 515 } 516 else 517 { 518 // Can't type paint from struct to struct*; this needs another 519 // level of indirection 520 if (lit.op == TOKstructliteral && isPointer(type)) 521 lit.error("CTFE internal error: painting %s", type.toChars()); 522 ue = copyLiteral(lit); 523 } 524 ue.exp().type = type; 525 return ue; 526 } 527 528 extern (C++) Expression resolveSlice(Expression e) 529 { 530 if (e.op != TOKslice) 531 return e; 532 SliceExp se = cast(SliceExp)e; 533 if (se.e1.op == TOKnull) 534 return se.e1; 535 return Slice(e.type, se.e1, se.lwr, se.upr).copy(); 536 } 537 538 /* Determine the array length, without interpreting it. 539 * e must be an array literal, or a slice 540 * It's very wasteful to resolve the slice when we only 541 * need the length. 542 */ 543 extern (C++) uinteger_t resolveArrayLength(Expression e) 544 { 545 if (e.op == TOKvector) 546 e = (cast(VectorExp)e).e1; 547 if (e.op == TOKnull) 548 return 0; 549 if (e.op == TOKslice) 550 { 551 uinteger_t ilo = (cast(SliceExp)e).lwr.toInteger(); 552 uinteger_t iup = (cast(SliceExp)e).upr.toInteger(); 553 return iup - ilo; 554 } 555 if (e.op == TOKstring) 556 { 557 return (cast(StringExp)e).len; 558 } 559 if (e.op == TOKarrayliteral) 560 { 561 ArrayLiteralExp ale = cast(ArrayLiteralExp)e; 562 return ale.elements ? ale.elements.dim : 0; 563 } 564 if (e.op == TOKassocarrayliteral) 565 { 566 AssocArrayLiteralExp ale = cast(AssocArrayLiteralExp)e; 567 return ale.keys.dim; 568 } 569 assert(0); 570 } 571 572 /****************************** 573 * Helper for NewExp 574 * Create an array literal consisting of 'elem' duplicated 'dim' times. 575 * Params: 576 * loc = source location where the interpretation occurs 577 * type = target type of the result 578 * elem = the source of array element, it will be owned by the result 579 * dim = element number of the result 580 * Returns: 581 * Constructed ArrayLiteralExp 582 */ 583 extern (C++) ArrayLiteralExp createBlockDuplicatedArrayLiteral(Loc loc, Type type, Expression elem, size_t dim) 584 { 585 if (type.ty == Tsarray && type.nextOf().ty == Tsarray && elem.type.ty != Tsarray) 586 { 587 // If it is a multidimensional array literal, do it recursively 588 auto tsa = cast(TypeSArray)type.nextOf(); 589 auto len = cast(size_t)tsa.dim.toInteger(); 590 elem = createBlockDuplicatedArrayLiteral(loc, type.nextOf(), elem, len); 591 } 592 593 // Buzilla 15681 594 auto tb = elem.type.toBasetype(); 595 const mustCopy = tb.ty == Tstruct || tb.ty == Tsarray; 596 597 auto elements = new Expressions(); 598 elements.setDim(dim); 599 foreach (i, ref el; *elements) 600 { 601 el = mustCopy && i ? copyLiteral(elem).copy() : elem; 602 } 603 auto ale = new ArrayLiteralExp(loc, elements); 604 ale.type = type; 605 ale.ownedByCtfe = OWNEDctfe; 606 return ale; 607 } 608 609 /****************************** 610 * Helper for NewExp 611 * Create a string literal consisting of 'value' duplicated 'dim' times. 612 */ 613 extern (C++) StringExp createBlockDuplicatedStringLiteral(Loc loc, Type type, dchar value, size_t dim, ubyte sz) 614 { 615 auto s = cast(char*)mem.xcalloc(dim, sz); 616 foreach (elemi; 0 .. dim) 617 { 618 switch (sz) 619 { 620 case 1: 621 s[elemi] = cast(char)value; 622 break; 623 case 2: 624 (cast(wchar*)s)[elemi] = cast(wchar)value; 625 break; 626 case 4: 627 (cast(dchar*)s)[elemi] = value; 628 break; 629 default: 630 assert(0); 631 } 632 } 633 auto se = new StringExp(loc, s, dim); 634 se.type = type; 635 se.sz = sz; 636 se.committed = true; 637 se.ownedByCtfe = OWNEDctfe; 638 return se; 639 } 640 641 // Return true if t is an AA 642 extern (C++) bool isAssocArray(Type t) 643 { 644 t = t.toBasetype(); 645 if (t.ty == Taarray) 646 return true; 647 return false; 648 } 649 650 // Given a template AA type, extract the corresponding built-in AA type 651 extern (C++) TypeAArray toBuiltinAAType(Type t) 652 { 653 t = t.toBasetype(); 654 if (t.ty == Taarray) 655 return cast(TypeAArray)t; 656 assert(0); 657 } 658 659 /************** TypeInfo operations ************************************/ 660 // Return true if type is TypeInfo_Class 661 extern (C++) bool isTypeInfo_Class(Type type) 662 { 663 return type.ty == Tclass && (Type.dtypeinfo == (cast(TypeClass)type).sym || Type.dtypeinfo.isBaseOf((cast(TypeClass)type).sym, null)); 664 } 665 666 /************** Pointer operations ************************************/ 667 // Return true if t is a pointer (not a function pointer) 668 extern (C++) bool isPointer(Type t) 669 { 670 Type tb = t.toBasetype(); 671 return tb.ty == Tpointer && tb.nextOf().ty != Tfunction; 672 } 673 674 // For CTFE only. Returns true if 'e' is true or a non-null pointer. 675 extern (C++) bool isTrueBool(Expression e) 676 { 677 return e.isBool(true) || ((e.type.ty == Tpointer || e.type.ty == Tclass) && e.op != TOKnull); 678 } 679 680 /* Is it safe to convert from srcPointee* to destPointee* ? 681 * srcPointee is the genuine type (never void). 682 * destPointee may be void. 683 */ 684 extern (C++) bool isSafePointerCast(Type srcPointee, Type destPointee) 685 { 686 // It's safe to cast S** to D** if it's OK to cast S* to D* 687 while (srcPointee.ty == Tpointer && destPointee.ty == Tpointer) 688 { 689 srcPointee = srcPointee.nextOf(); 690 destPointee = destPointee.nextOf(); 691 } 692 // It's OK if both are the same (modulo const) 693 if (srcPointee.constConv(destPointee)) 694 return true; 695 // It's OK if function pointers differ only in safe/pure/nothrow 696 if (srcPointee.ty == Tfunction && destPointee.ty == Tfunction) 697 return srcPointee.covariant(destPointee) == 1; 698 // it's OK to cast to void* 699 if (destPointee.ty == Tvoid) 700 return true; 701 // It's OK to cast from V[K] to void* 702 if (srcPointee.ty == Taarray && destPointee == Type.tvoidptr) 703 return true; 704 // It's OK if they are the same size (static array of) integers, eg: 705 // int* --> uint* 706 // int[5][] --> uint[5][] 707 if (srcPointee.ty == Tsarray && destPointee.ty == Tsarray) 708 { 709 if (srcPointee.size() != destPointee.size()) 710 return false; 711 srcPointee = srcPointee.baseElemOf(); 712 destPointee = destPointee.baseElemOf(); 713 } 714 return srcPointee.isintegral() && destPointee.isintegral() && srcPointee.size() == destPointee.size(); 715 } 716 717 extern (C++) Expression getAggregateFromPointer(Expression e, dinteger_t* ofs) 718 { 719 *ofs = 0; 720 if (e.op == TOKaddress) 721 e = (cast(AddrExp)e).e1; 722 if (e.op == TOKsymoff) 723 *ofs = (cast(SymOffExp)e).offset; 724 if (e.op == TOKdotvar) 725 { 726 Expression ex = (cast(DotVarExp)e).e1; 727 VarDeclaration v = (cast(DotVarExp)e).var.isVarDeclaration(); 728 assert(v); 729 StructLiteralExp se = ex.op == TOKclassreference ? (cast(ClassReferenceExp)ex).value : cast(StructLiteralExp)ex; 730 // We can't use getField, because it makes a copy 731 uint i; 732 if (ex.op == TOKclassreference) 733 i = (cast(ClassReferenceExp)ex).getFieldIndex(e.type, v.offset); 734 else 735 i = se.getFieldIndex(e.type, v.offset); 736 e = (*se.elements)[i]; 737 } 738 if (e.op == TOKindex) 739 { 740 IndexExp ie = cast(IndexExp)e; 741 // Note that each AA element is part of its own memory block 742 if ((ie.e1.type.ty == Tarray || ie.e1.type.ty == Tsarray || ie.e1.op == TOKstring || ie.e1.op == TOKarrayliteral) && ie.e2.op == TOKint64) 743 { 744 *ofs = ie.e2.toInteger(); 745 return ie.e1; 746 } 747 } 748 if (e.op == TOKslice && e.type.toBasetype().ty == Tsarray) 749 { 750 SliceExp se = cast(SliceExp)e; 751 if ((se.e1.type.ty == Tarray || se.e1.type.ty == Tsarray || se.e1.op == TOKstring || se.e1.op == TOKarrayliteral) && se.lwr.op == TOKint64) 752 { 753 *ofs = se.lwr.toInteger(); 754 return se.e1; 755 } 756 } 757 return e; 758 } 759 760 /** Return true if agg1 and agg2 are pointers to the same memory block 761 */ 762 extern (C++) bool pointToSameMemoryBlock(Expression agg1, Expression agg2) 763 { 764 if (agg1 == agg2) 765 return true; 766 // For integers cast to pointers, we regard them as non-comparable 767 // unless they are identical. (This may be overly strict). 768 if (agg1.op == TOKint64 && agg2.op == TOKint64 && agg1.toInteger() == agg2.toInteger()) 769 { 770 return true; 771 } 772 // Note that type painting can occur with VarExp, so we 773 // must compare the variables being pointed to. 774 if (agg1.op == TOKvar && agg2.op == TOKvar && (cast(VarExp)agg1).var == (cast(VarExp)agg2).var) 775 { 776 return true; 777 } 778 if (agg1.op == TOKsymoff && agg2.op == TOKsymoff && (cast(SymOffExp)agg1).var == (cast(SymOffExp)agg2).var) 779 { 780 return true; 781 } 782 return false; 783 } 784 785 // return e1 - e2 as an integer, or error if not possible 786 extern (C++) UnionExp pointerDifference(Loc loc, Type type, Expression e1, Expression e2) 787 { 788 UnionExp ue; 789 dinteger_t ofs1, ofs2; 790 Expression agg1 = getAggregateFromPointer(e1, &ofs1); 791 Expression agg2 = getAggregateFromPointer(e2, &ofs2); 792 if (agg1 == agg2) 793 { 794 Type pointee = (cast(TypePointer)agg1.type).next; 795 dinteger_t sz = pointee.size(); 796 emplaceExp!(IntegerExp)(&ue, loc, (ofs1 - ofs2) * sz, type); 797 } 798 else if (agg1.op == TOKstring && agg2.op == TOKstring) 799 { 800 if ((cast(StringExp)agg1).string == (cast(StringExp)agg2).string) 801 { 802 Type pointee = (cast(TypePointer)agg1.type).next; 803 dinteger_t sz = pointee.size(); 804 emplaceExp!(IntegerExp)(&ue, loc, (ofs1 - ofs2) * sz, type); 805 } 806 } 807 else if (agg1.op == TOKsymoff && agg2.op == TOKsymoff && (cast(SymOffExp)agg1).var == (cast(SymOffExp)agg2).var) 808 { 809 emplaceExp!(IntegerExp)(&ue, loc, ofs1 - ofs2, type); 810 } 811 else 812 { 813 error(loc, "%s - %s cannot be interpreted at compile time: cannot subtract pointers to two different memory blocks", e1.toChars(), e2.toChars()); 814 emplaceExp!(CTFEExp)(&ue, TOKcantexp); 815 } 816 return ue; 817 } 818 819 // Return eptr op e2, where eptr is a pointer, e2 is an integer, 820 // and op is TOKadd or TOKmin 821 extern (C++) UnionExp pointerArithmetic(Loc loc, TOK op, Type type, Expression eptr, Expression e2) 822 { 823 UnionExp ue; 824 if (eptr.type.nextOf().ty == Tvoid) 825 { 826 error(loc, "cannot perform arithmetic on void* pointers at compile time"); 827 Lcant: 828 emplaceExp!(CTFEExp)(&ue, TOKcantexp); 829 return ue; 830 } 831 dinteger_t ofs1; 832 if (eptr.op == TOKaddress) 833 eptr = (cast(AddrExp)eptr).e1; 834 Expression agg1 = getAggregateFromPointer(eptr, &ofs1); 835 if (agg1.op == TOKsymoff) 836 { 837 if ((cast(SymOffExp)agg1).var.type.ty != Tsarray) 838 { 839 error(loc, "cannot perform pointer arithmetic on arrays of unknown length at compile time"); 840 goto Lcant; 841 } 842 } 843 else if (agg1.op != TOKstring && agg1.op != TOKarrayliteral) 844 { 845 error(loc, "cannot perform pointer arithmetic on non-arrays at compile time"); 846 goto Lcant; 847 } 848 dinteger_t ofs2 = e2.toInteger(); 849 Type pointee = (cast(TypeNext)agg1.type.toBasetype()).next; 850 dinteger_t sz = pointee.size(); 851 sinteger_t indx; 852 dinteger_t len; 853 if (agg1.op == TOKsymoff) 854 { 855 indx = ofs1 / sz; 856 len = (cast(TypeSArray)(cast(SymOffExp)agg1).var.type).dim.toInteger(); 857 } 858 else 859 { 860 Expression dollar = ArrayLength(Type.tsize_t, agg1).copy(); 861 assert(!CTFEExp.isCantExp(dollar)); 862 indx = ofs1; 863 len = dollar.toInteger(); 864 } 865 if (op == TOKadd || op == TOKaddass || op == TOKplusplus) 866 indx += ofs2 / sz; 867 else if (op == TOKmin || op == TOKminass || op == TOKminusminus) 868 indx -= ofs2 / sz; 869 else 870 { 871 error(loc, "CTFE internal error: bad pointer operation"); 872 goto Lcant; 873 } 874 if (indx < 0 || len < indx) 875 { 876 error(loc, "cannot assign pointer to index %lld inside memory block [0..%lld]", indx, len); 877 goto Lcant; 878 } 879 if (agg1.op == TOKsymoff) 880 { 881 emplaceExp!(SymOffExp)(&ue, loc, (cast(SymOffExp)agg1).var, indx * sz); 882 SymOffExp se = cast(SymOffExp)ue.exp(); 883 se.type = type; 884 return ue; 885 } 886 if (agg1.op != TOKarrayliteral && agg1.op != TOKstring) 887 { 888 error(loc, "CTFE internal error: pointer arithmetic %s", agg1.toChars()); 889 goto Lcant; 890 } 891 if (eptr.type.toBasetype().ty == Tsarray) 892 { 893 dinteger_t dim = (cast(TypeSArray)eptr.type.toBasetype()).dim.toInteger(); 894 // Create a CTFE pointer &agg1[indx .. indx+dim] 895 auto se = new SliceExp(loc, agg1, new IntegerExp(loc, indx, Type.tsize_t), new IntegerExp(loc, indx + dim, Type.tsize_t)); 896 se.type = type.toBasetype().nextOf(); 897 emplaceExp!(AddrExp)(&ue, loc, se); 898 ue.exp().type = type; 899 return ue; 900 } 901 // Create a CTFE pointer &agg1[indx] 902 auto ofs = new IntegerExp(loc, indx, Type.tsize_t); 903 Expression ie = new IndexExp(loc, agg1, ofs); 904 ie.type = type.toBasetype().nextOf(); // Bugzilla 13992 905 emplaceExp!(AddrExp)(&ue, loc, ie); 906 ue.exp().type = type; 907 return ue; 908 } 909 910 // Return 1 if true, 0 if false 911 // -1 if comparison is illegal because they point to non-comparable memory blocks 912 extern (C++) int comparePointers(Loc loc, TOK op, Type type, Expression agg1, dinteger_t ofs1, Expression agg2, dinteger_t ofs2) 913 { 914 if (pointToSameMemoryBlock(agg1, agg2)) 915 { 916 int n; 917 switch (op) 918 { 919 case TOKlt: 920 n = (ofs1 < ofs2); 921 break; 922 case TOKle: 923 n = (ofs1 <= ofs2); 924 break; 925 case TOKgt: 926 n = (ofs1 > ofs2); 927 break; 928 case TOKge: 929 n = (ofs1 >= ofs2); 930 break; 931 case TOKidentity: 932 case TOKequal: 933 n = (ofs1 == ofs2); 934 break; 935 case TOKnotidentity: 936 case TOKnotequal: 937 n = (ofs1 != ofs2); 938 break; 939 default: 940 assert(0); 941 } 942 return n; 943 } 944 bool null1 = (agg1.op == TOKnull); 945 bool null2 = (agg2.op == TOKnull); 946 int cmp; 947 if (null1 || null2) 948 { 949 switch (op) 950 { 951 case TOKlt: 952 cmp = null1 && !null2; 953 break; 954 case TOKgt: 955 cmp = !null1 && null2; 956 break; 957 case TOKle: 958 cmp = null1; 959 break; 960 case TOKge: 961 cmp = null2; 962 break; 963 case TOKidentity: 964 case TOKequal: 965 case TOKnotidentity: // 'cmp' gets inverted below 966 case TOKnotequal: 967 cmp = (null1 == null2); 968 break; 969 default: 970 assert(0); 971 } 972 } 973 else 974 { 975 switch (op) 976 { 977 case TOKidentity: 978 case TOKequal: 979 case TOKnotidentity: // 'cmp' gets inverted below 980 case TOKnotequal: 981 cmp = 0; 982 break; 983 default: 984 return -1; // memory blocks are different 985 } 986 } 987 if (op == TOKnotidentity || op == TOKnotequal) 988 cmp ^= 1; 989 return cmp; 990 } 991 992 // True if conversion from type 'from' to 'to' involves a reinterpret_cast 993 // floating point -> integer or integer -> floating point 994 extern (C++) bool isFloatIntPaint(Type to, Type from) 995 { 996 return from.size() == to.size() && (from.isintegral() && to.isfloating() || from.isfloating() && to.isintegral()); 997 } 998 999 // Reinterpret float/int value 'fromVal' as a float/integer of type 'to'. 1000 extern (C++) Expression paintFloatInt(Expression fromVal, Type to) 1001 { 1002 if (exceptionOrCantInterpret(fromVal)) 1003 return fromVal; 1004 assert(to.size() == 4 || to.size() == 8); 1005 return Target.paintAsType(fromVal, to); 1006 } 1007 1008 /******** Constant folding, with support for CTFE ***************************/ 1009 /// Return true if non-pointer expression e can be compared 1010 /// with >,is, ==, etc, using ctfeCmp, ctfeEqual, ctfeIdentity 1011 extern (C++) bool isCtfeComparable(Expression e) 1012 { 1013 if (e.op == TOKslice) 1014 e = (cast(SliceExp)e).e1; 1015 if (e.isConst() != 1) 1016 { 1017 if (e.op == TOKnull || e.op == TOKstring || e.op == TOKfunction || e.op == TOKdelegate || e.op == TOKarrayliteral || e.op == TOKstructliteral || e.op == TOKassocarrayliteral || e.op == TOKclassreference) 1018 { 1019 return true; 1020 } 1021 // Bugzilla 14123: TypeInfo object is comparable in CTFE 1022 if (e.op == TOKtypeid) 1023 return true; 1024 return false; 1025 } 1026 return true; 1027 } 1028 1029 /// Map TOK comparison ops 1030 private bool numCmp(N)(TOK op, N n1, N n2) 1031 { 1032 switch (op) 1033 { 1034 case TOKlt: 1035 return n1 < n2; 1036 case TOKle: 1037 return n1 <= n2; 1038 case TOKgt: 1039 return n1 > n2; 1040 case TOKge: 1041 return n1 >= n2; 1042 1043 default: 1044 assert(0); 1045 } 1046 } 1047 1048 /// Returns cmp OP 0; where OP is ==, !=, <, >=, etc. Result is 0 or 1 1049 extern (C++) int specificCmp(TOK op, int rawCmp) 1050 { 1051 return numCmp!int(op, rawCmp, 0); 1052 } 1053 1054 /// Returns e1 OP e2; where OP is ==, !=, <, >=, etc. Result is 0 or 1 1055 extern (C++) int intUnsignedCmp(TOK op, dinteger_t n1, dinteger_t n2) 1056 { 1057 return numCmp!dinteger_t(op, n1, n2); 1058 } 1059 1060 /// Returns e1 OP e2; where OP is ==, !=, <, >=, etc. Result is 0 or 1 1061 extern (C++) int intSignedCmp(TOK op, sinteger_t n1, sinteger_t n2) 1062 { 1063 return numCmp!sinteger_t(op, n1, n2); 1064 } 1065 1066 /// Returns e1 OP e2; where OP is ==, !=, <, >=, etc. Result is 0 or 1 1067 extern (C++) int realCmp(TOK op, real_t r1, real_t r2) 1068 { 1069 // Don't rely on compiler, handle NAN arguments separately 1070 if (CTFloat.isNaN(r1) || CTFloat.isNaN(r2)) // if unordered 1071 { 1072 switch (op) 1073 { 1074 case TOKlt: 1075 case TOKle: 1076 case TOKgt: 1077 case TOKge: 1078 return 0; 1079 1080 default: 1081 assert(0); 1082 } 1083 } 1084 else 1085 { 1086 return numCmp!real_t(op, r1, r2); 1087 } 1088 } 1089 1090 /* Conceptually the same as memcmp(e1, e2). 1091 * e1 and e2 may be strings, arrayliterals, or slices. 1092 * For string types, return <0 if e1 < e2, 0 if e1==e2, >0 if e1 > e2. 1093 * For all other types, return 0 if e1 == e2, !=0 if e1 != e2. 1094 */ 1095 extern (C++) int ctfeCmpArrays(Loc loc, Expression e1, Expression e2, uinteger_t len) 1096 { 1097 // Resolve slices, if necessary 1098 uinteger_t lo1 = 0; 1099 uinteger_t lo2 = 0; 1100 Expression x = e1; 1101 if (x.op == TOKslice) 1102 { 1103 lo1 = (cast(SliceExp)x).lwr.toInteger(); 1104 x = (cast(SliceExp)x).e1; 1105 } 1106 StringExp se1 = (x.op == TOKstring) ? cast(StringExp)x : null; 1107 ArrayLiteralExp ae1 = (x.op == TOKarrayliteral) ? cast(ArrayLiteralExp)x : null; 1108 x = e2; 1109 if (x.op == TOKslice) 1110 { 1111 lo2 = (cast(SliceExp)x).lwr.toInteger(); 1112 x = (cast(SliceExp)x).e1; 1113 } 1114 StringExp se2 = (x.op == TOKstring) ? cast(StringExp)x : null; 1115 ArrayLiteralExp ae2 = (x.op == TOKarrayliteral) ? cast(ArrayLiteralExp)x : null; 1116 // Now both must be either TOKarrayliteral or TOKstring 1117 if (se1 && se2) 1118 return sliceCmpStringWithString(se1, se2, cast(size_t)lo1, cast(size_t)lo2, cast(size_t)len); 1119 if (se1 && ae2) 1120 return sliceCmpStringWithArray(se1, ae2, cast(size_t)lo1, cast(size_t)lo2, cast(size_t)len); 1121 if (se2 && ae1) 1122 return -sliceCmpStringWithArray(se2, ae1, cast(size_t)lo2, cast(size_t)lo1, cast(size_t)len); 1123 assert(ae1 && ae2); 1124 // Comparing two array literals. This case is potentially recursive. 1125 // If they aren't strings, we just need an equality check rather than 1126 // a full cmp. 1127 bool needCmp = ae1.type.nextOf().isintegral(); 1128 for (size_t i = 0; i < cast(size_t)len; i++) 1129 { 1130 Expression ee1 = (*ae1.elements)[cast(size_t)(lo1 + i)]; 1131 Expression ee2 = (*ae2.elements)[cast(size_t)(lo2 + i)]; 1132 if (needCmp) 1133 { 1134 sinteger_t c = ee1.toInteger() - ee2.toInteger(); 1135 if (c > 0) 1136 return 1; 1137 if (c < 0) 1138 return -1; 1139 } 1140 else 1141 { 1142 if (ctfeRawCmp(loc, ee1, ee2)) 1143 return 1; 1144 } 1145 } 1146 return 0; 1147 } 1148 1149 /* Given a delegate expression e, return .funcptr. 1150 * If e is NullExp, return NULL. 1151 */ 1152 extern (C++) FuncDeclaration funcptrOf(Expression e) 1153 { 1154 assert(e.type.ty == Tdelegate); 1155 if (e.op == TOKdelegate) 1156 return (cast(DelegateExp)e).func; 1157 if (e.op == TOKfunction) 1158 return (cast(FuncExp)e).fd; 1159 assert(e.op == TOKnull); 1160 return null; 1161 } 1162 1163 extern (C++) bool isArray(Expression e) 1164 { 1165 return e.op == TOKarrayliteral || e.op == TOKstring || e.op == TOKslice || e.op == TOKnull; 1166 } 1167 1168 /* For strings, return <0 if e1 < e2, 0 if e1==e2, >0 if e1 > e2. 1169 * For all other types, return 0 if e1 == e2, !=0 if e1 != e2. 1170 */ 1171 extern (C++) int ctfeRawCmp(Loc loc, Expression e1, Expression e2) 1172 { 1173 if (e1.op == TOKclassreference || e2.op == TOKclassreference) 1174 { 1175 if (e1.op == TOKclassreference && e2.op == TOKclassreference && (cast(ClassReferenceExp)e1).value == (cast(ClassReferenceExp)e2).value) 1176 return 0; 1177 return 1; 1178 } 1179 if (e1.op == TOKtypeid && e2.op == TOKtypeid) 1180 { 1181 // printf("e1: %s\n", e1->toChars()); 1182 // printf("e2: %s\n", e2->toChars()); 1183 Type t1 = isType((cast(TypeidExp)e1).obj); 1184 Type t2 = isType((cast(TypeidExp)e2).obj); 1185 assert(t1); 1186 assert(t2); 1187 return t1 != t2; 1188 } 1189 // null == null, regardless of type 1190 if (e1.op == TOKnull && e2.op == TOKnull) 1191 return 0; 1192 if (e1.type.ty == Tpointer && e2.type.ty == Tpointer) 1193 { 1194 // Can only be an equality test. 1195 dinteger_t ofs1, ofs2; 1196 Expression agg1 = getAggregateFromPointer(e1, &ofs1); 1197 Expression agg2 = getAggregateFromPointer(e2, &ofs2); 1198 if ((agg1 == agg2) || (agg1.op == TOKvar && agg2.op == TOKvar && (cast(VarExp)agg1).var == (cast(VarExp)agg2).var)) 1199 { 1200 if (ofs1 == ofs2) 1201 return 0; 1202 } 1203 return 1; 1204 } 1205 if (e1.type.ty == Tdelegate && e2.type.ty == Tdelegate) 1206 { 1207 // If .funcptr isn't the same, they are not equal 1208 if (funcptrOf(e1) != funcptrOf(e2)) 1209 return 1; 1210 // If both are delegate literals, assume they have the 1211 // same closure pointer. TODO: We don't support closures yet! 1212 if (e1.op == TOKfunction && e2.op == TOKfunction) 1213 return 0; 1214 assert(e1.op == TOKdelegate && e2.op == TOKdelegate); 1215 // Same .funcptr. Do they have the same .ptr? 1216 Expression ptr1 = (cast(DelegateExp)e1).e1; 1217 Expression ptr2 = (cast(DelegateExp)e2).e1; 1218 dinteger_t ofs1, ofs2; 1219 Expression agg1 = getAggregateFromPointer(ptr1, &ofs1); 1220 Expression agg2 = getAggregateFromPointer(ptr2, &ofs2); 1221 // If they are TOKvar, it means they are FuncDeclarations 1222 if ((agg1 == agg2 && ofs1 == ofs2) || (agg1.op == TOKvar && agg2.op == TOKvar && (cast(VarExp)agg1).var == (cast(VarExp)agg2).var)) 1223 { 1224 return 0; 1225 } 1226 return 1; 1227 } 1228 if (isArray(e1) && isArray(e2)) 1229 { 1230 uinteger_t len1 = resolveArrayLength(e1); 1231 uinteger_t len2 = resolveArrayLength(e2); 1232 // workaround for dmc optimizer bug calculating wrong len for 1233 // uinteger_t len = (len1 < len2 ? len1 : len2); 1234 // if (len == 0) ... 1235 if (len1 > 0 && len2 > 0) 1236 { 1237 uinteger_t len = (len1 < len2 ? len1 : len2); 1238 int res = ctfeCmpArrays(loc, e1, e2, len); 1239 if (res != 0) 1240 return res; 1241 } 1242 return cast(int)(len1 - len2); 1243 } 1244 if (e1.type.isintegral()) 1245 { 1246 return e1.toInteger() != e2.toInteger(); 1247 } 1248 real_t r1 = 0; 1249 real_t r2 = 0; 1250 if (e1.type.isreal()) 1251 { 1252 r1 = e1.toReal(); 1253 r2 = e2.toReal(); 1254 goto L1; 1255 } 1256 else if (e1.type.isimaginary()) 1257 { 1258 r1 = e1.toImaginary(); 1259 r2 = e2.toImaginary(); 1260 L1: 1261 if (CTFloat.isNaN(r1) || CTFloat.isNaN(r2)) // if unordered 1262 { 1263 return 1; 1264 } 1265 else 1266 { 1267 return (r1 != r2); 1268 } 1269 } 1270 else if (e1.type.iscomplex()) 1271 { 1272 return e1.toComplex() != e2.toComplex(); 1273 } 1274 if (e1.op == TOKstructliteral && e2.op == TOKstructliteral) 1275 { 1276 StructLiteralExp es1 = cast(StructLiteralExp)e1; 1277 StructLiteralExp es2 = cast(StructLiteralExp)e2; 1278 // For structs, we only need to return 0 or 1 (< and > aren't legal). 1279 if (es1.sd != es2.sd) 1280 return 1; 1281 else if ((!es1.elements || !es1.elements.dim) && (!es2.elements || !es2.elements.dim)) 1282 return 0; // both arrays are empty 1283 else if (!es1.elements || !es2.elements) 1284 return 1; 1285 else if (es1.elements.dim != es2.elements.dim) 1286 return 1; 1287 else 1288 { 1289 for (size_t i = 0; i < es1.elements.dim; i++) 1290 { 1291 Expression ee1 = (*es1.elements)[i]; 1292 Expression ee2 = (*es2.elements)[i]; 1293 if (ee1 == ee2) 1294 continue; 1295 if (!ee1 || !ee2) 1296 return 1; 1297 int cmp = ctfeRawCmp(loc, ee1, ee2); 1298 if (cmp) 1299 return 1; 1300 } 1301 return 0; // All elements are equal 1302 } 1303 } 1304 if (e1.op == TOKassocarrayliteral && e2.op == TOKassocarrayliteral) 1305 { 1306 AssocArrayLiteralExp es1 = cast(AssocArrayLiteralExp)e1; 1307 AssocArrayLiteralExp es2 = cast(AssocArrayLiteralExp)e2; 1308 size_t dim = es1.keys.dim; 1309 if (es2.keys.dim != dim) 1310 return 1; 1311 bool* used = cast(bool*)mem.xmalloc(bool.sizeof * dim); 1312 memset(used, 0, bool.sizeof * dim); 1313 for (size_t i = 0; i < dim; ++i) 1314 { 1315 Expression k1 = (*es1.keys)[i]; 1316 Expression v1 = (*es1.values)[i]; 1317 Expression v2 = null; 1318 for (size_t j = 0; j < dim; ++j) 1319 { 1320 if (used[j]) 1321 continue; 1322 Expression k2 = (*es2.keys)[j]; 1323 if (ctfeRawCmp(loc, k1, k2)) 1324 continue; 1325 used[j] = true; 1326 v2 = (*es2.values)[j]; 1327 break; 1328 } 1329 if (!v2 || ctfeRawCmp(loc, v1, v2)) 1330 { 1331 mem.xfree(used); 1332 return 1; 1333 } 1334 } 1335 mem.xfree(used); 1336 return 0; 1337 } 1338 error(loc, "CTFE internal error: bad compare"); 1339 assert(0); 1340 } 1341 1342 /// Evaluate ==, !=. Resolves slices before comparing. Returns 0 or 1 1343 extern (C++) int ctfeEqual(Loc loc, TOK op, Expression e1, Expression e2) 1344 { 1345 int cmp = !ctfeRawCmp(loc, e1, e2); 1346 if (op == TOKnotequal) 1347 cmp ^= 1; 1348 return cmp; 1349 } 1350 1351 /// Evaluate is, !is. Resolves slices before comparing. Returns 0 or 1 1352 extern (C++) int ctfeIdentity(Loc loc, TOK op, Expression e1, Expression e2) 1353 { 1354 //printf("ctfeIdentity op = '%s', e1 = %s %s, e2 = %s %s\n", Token::toChars(op), 1355 // Token::toChars(e1->op), e1->toChars(), Token::toChars(e2->op), e1->toChars()); 1356 int cmp; 1357 if (e1.op == TOKnull) 1358 { 1359 cmp = (e2.op == TOKnull); 1360 } 1361 else if (e2.op == TOKnull) 1362 { 1363 cmp = 0; 1364 } 1365 else if (e1.op == TOKsymoff && e2.op == TOKsymoff) 1366 { 1367 SymOffExp es1 = cast(SymOffExp)e1; 1368 SymOffExp es2 = cast(SymOffExp)e2; 1369 cmp = (es1.var == es2.var && es1.offset == es2.offset); 1370 } 1371 else if (e1.type.isreal()) 1372 cmp = RealEquals(e1.toReal(), e2.toReal()); 1373 else if (e1.type.isimaginary()) 1374 cmp = RealEquals(e1.toImaginary(), e2.toImaginary()); 1375 else if (e1.type.iscomplex()) 1376 { 1377 complex_t v1 = e1.toComplex(); 1378 complex_t v2 = e2.toComplex(); 1379 cmp = RealEquals(creall(v1), creall(v2)) && RealEquals(cimagl(v1), cimagl(v1)); 1380 } 1381 else 1382 cmp = !ctfeRawCmp(loc, e1, e2); 1383 if (op == TOKnotidentity || op == TOKnotequal) 1384 cmp ^= 1; 1385 return cmp; 1386 } 1387 1388 /// Evaluate >,<=, etc. Resolves slices before comparing. Returns 0 or 1 1389 extern (C++) int ctfeCmp(Loc loc, TOK op, Expression e1, Expression e2) 1390 { 1391 Type t1 = e1.type.toBasetype(); 1392 Type t2 = e2.type.toBasetype(); 1393 1394 if (t1.isString() && t2.isString()) 1395 return specificCmp(op, ctfeRawCmp(loc, e1, e2)); 1396 else if (t1.isreal()) 1397 return realCmp(op, e1.toReal(), e2.toReal()); 1398 else if (t1.isimaginary()) 1399 return realCmp(op, e1.toImaginary(), e2.toImaginary()); 1400 else if (t1.isunsigned() || t2.isunsigned()) 1401 return intUnsignedCmp(op, e1.toInteger(), e2.toInteger()); 1402 else 1403 return intSignedCmp(op, e1.toInteger(), e2.toInteger()); 1404 } 1405 1406 extern (C++) UnionExp ctfeCat(Loc loc, Type type, Expression e1, Expression e2) 1407 { 1408 Type t1 = e1.type.toBasetype(); 1409 Type t2 = e2.type.toBasetype(); 1410 UnionExp ue; 1411 if (e2.op == TOKstring && e1.op == TOKarrayliteral && t1.nextOf().isintegral()) 1412 { 1413 // [chars] ~ string => string (only valid for CTFE) 1414 StringExp es1 = cast(StringExp)e2; 1415 ArrayLiteralExp es2 = cast(ArrayLiteralExp)e1; 1416 size_t len = es1.len + es2.elements.dim; 1417 ubyte sz = es1.sz; 1418 void* s = mem.xmalloc((len + 1) * sz); 1419 memcpy(cast(char*)s + sz * es2.elements.dim, es1..string, es1.len * sz); 1420 for (size_t i = 0; i < es2.elements.dim; i++) 1421 { 1422 Expression es2e = (*es2.elements)[i]; 1423 if (es2e.op != TOKint64) 1424 { 1425 emplaceExp!(CTFEExp)(&ue, TOKcantexp); 1426 return ue; 1427 } 1428 dinteger_t v = es2e.toInteger(); 1429 Port.valcpy(cast(char*)s + i * sz, v, sz); 1430 } 1431 // Add terminating 0 1432 memset(cast(char*)s + len * sz, 0, sz); 1433 emplaceExp!(StringExp)(&ue, loc, s, len); 1434 StringExp es = cast(StringExp)ue.exp(); 1435 es.sz = sz; 1436 es.committed = 0; 1437 es.type = type; 1438 return ue; 1439 } 1440 if (e1.op == TOKstring && e2.op == TOKarrayliteral && t2.nextOf().isintegral()) 1441 { 1442 // string ~ [chars] => string (only valid for CTFE) 1443 // Concatenate the strings 1444 StringExp es1 = cast(StringExp)e1; 1445 ArrayLiteralExp es2 = cast(ArrayLiteralExp)e2; 1446 size_t len = es1.len + es2.elements.dim; 1447 ubyte sz = es1.sz; 1448 void* s = mem.xmalloc((len + 1) * sz); 1449 memcpy(s, es1..string, es1.len * sz); 1450 for (size_t i = 0; i < es2.elements.dim; i++) 1451 { 1452 Expression es2e = (*es2.elements)[i]; 1453 if (es2e.op != TOKint64) 1454 { 1455 emplaceExp!(CTFEExp)(&ue, TOKcantexp); 1456 return ue; 1457 } 1458 dinteger_t v = es2e.toInteger(); 1459 Port.valcpy(cast(char*)s + (es1.len + i) * sz, v, sz); 1460 } 1461 // Add terminating 0 1462 memset(cast(char*)s + len * sz, 0, sz); 1463 emplaceExp!(StringExp)(&ue, loc, s, len); 1464 StringExp es = cast(StringExp)ue.exp(); 1465 es.sz = sz; 1466 es.committed = 0; //es1->committed; 1467 es.type = type; 1468 return ue; 1469 } 1470 if (e1.op == TOKarrayliteral && e2.op == TOKarrayliteral && t1.nextOf().equals(t2.nextOf())) 1471 { 1472 // [ e1 ] ~ [ e2 ] ---> [ e1, e2 ] 1473 ArrayLiteralExp es1 = cast(ArrayLiteralExp)e1; 1474 ArrayLiteralExp es2 = cast(ArrayLiteralExp)e2; 1475 emplaceExp!(ArrayLiteralExp)(&ue, es1.loc, copyLiteralArray(es1.elements)); 1476 es1 = cast(ArrayLiteralExp)ue.exp(); 1477 es1.elements.insert(es1.elements.dim, copyLiteralArray(es2.elements)); 1478 es1.type = type; 1479 return ue; 1480 } 1481 if (e1.op == TOKarrayliteral && e2.op == TOKnull && t1.nextOf().equals(t2.nextOf())) 1482 { 1483 // [ e1 ] ~ null ----> [ e1 ].dup 1484 ue = paintTypeOntoLiteralCopy(type, copyLiteral(e1).copy()); 1485 return ue; 1486 } 1487 if (e1.op == TOKnull && e2.op == TOKarrayliteral && t1.nextOf().equals(t2.nextOf())) 1488 { 1489 // null ~ [ e2 ] ----> [ e2 ].dup 1490 ue = paintTypeOntoLiteralCopy(type, copyLiteral(e2).copy()); 1491 return ue; 1492 } 1493 ue = Cat(type, e1, e2); 1494 return ue; 1495 } 1496 1497 /* Given an AA literal 'ae', and a key 'e2': 1498 * Return ae[e2] if present, or NULL if not found. 1499 */ 1500 extern (C++) Expression findKeyInAA(Loc loc, AssocArrayLiteralExp ae, Expression e2) 1501 { 1502 /* Search the keys backwards, in case there are duplicate keys 1503 */ 1504 for (size_t i = ae.keys.dim; i;) 1505 { 1506 i--; 1507 Expression ekey = (*ae.keys)[i]; 1508 int eq = ctfeEqual(loc, TOKequal, ekey, e2); 1509 if (eq) 1510 { 1511 return (*ae.values)[i]; 1512 } 1513 } 1514 return null; 1515 } 1516 1517 /* Same as for constfold.Index, except that it only works for static arrays, 1518 * dynamic arrays, and strings. We know that e1 is an 1519 * interpreted CTFE expression, so it cannot have side-effects. 1520 */ 1521 extern (C++) Expression ctfeIndex(Loc loc, Type type, Expression e1, uinteger_t indx) 1522 { 1523 //printf("ctfeIndex(e1 = %s)\n", e1->toChars()); 1524 assert(e1.type); 1525 if (e1.op == TOKstring) 1526 { 1527 StringExp es1 = cast(StringExp)e1; 1528 if (indx >= es1.len) 1529 { 1530 error(loc, "string index %llu is out of bounds [0 .. %llu]", indx, cast(ulong)es1.len); 1531 return CTFEExp.cantexp; 1532 } 1533 return new IntegerExp(loc, es1.charAt(indx), type); 1534 } 1535 assert(e1.op == TOKarrayliteral); 1536 { 1537 ArrayLiteralExp ale = cast(ArrayLiteralExp)e1; 1538 if (indx >= ale.elements.dim) 1539 { 1540 error(loc, "array index %llu is out of bounds %s[0 .. %llu]", indx, e1.toChars(), cast(ulong)ale.elements.dim); 1541 return CTFEExp.cantexp; 1542 } 1543 Expression e = (*ale.elements)[cast(size_t)indx]; 1544 return paintTypeOntoLiteral(type, e); 1545 } 1546 } 1547 1548 extern (C++) Expression ctfeCast(Loc loc, Type type, Type to, Expression e) 1549 { 1550 if (e.op == TOKnull) 1551 return paintTypeOntoLiteral(to, e); 1552 if (e.op == TOKclassreference) 1553 { 1554 // Disallow reinterpreting class casts. Do this by ensuring that 1555 // the original class can implicitly convert to the target class 1556 ClassDeclaration originalClass = (cast(ClassReferenceExp)e).originalClass(); 1557 if (originalClass.type.implicitConvTo(to.mutableOf())) 1558 return paintTypeOntoLiteral(to, e); 1559 else 1560 return new NullExp(loc, to); 1561 } 1562 // Allow TypeInfo type painting 1563 if (isTypeInfo_Class(e.type) && e.type.implicitConvTo(to)) 1564 return paintTypeOntoLiteral(to, e); 1565 // Allow casting away const for struct literals 1566 if (e.op == TOKstructliteral && e.type.toBasetype().castMod(0) == to.toBasetype().castMod(0)) 1567 { 1568 return paintTypeOntoLiteral(to, e); 1569 } 1570 Expression r; 1571 if (e.type.equals(type) && type.equals(to)) 1572 { 1573 // necessary not to change e's address for pointer comparisons 1574 r = e; 1575 } 1576 else if (to.toBasetype().ty == Tarray && type.toBasetype().ty == Tarray && to.toBasetype().nextOf().size() == type.toBasetype().nextOf().size()) 1577 { 1578 // Bugzilla 12495: Array reinterpret casts: eg. string to immutable(ubyte)[] 1579 return paintTypeOntoLiteral(to, e); 1580 } 1581 else 1582 { 1583 r = Cast(loc, type, to, e).copy(); 1584 } 1585 if (CTFEExp.isCantExp(r)) 1586 error(loc, "cannot cast %s to %s at compile time", e.toChars(), to.toChars()); 1587 if (e.op == TOKarrayliteral) 1588 (cast(ArrayLiteralExp)e).ownedByCtfe = OWNEDctfe; 1589 if (e.op == TOKstring) 1590 (cast(StringExp)e).ownedByCtfe = OWNEDctfe; 1591 return r; 1592 } 1593 1594 /******** Assignment helper functions ***************************/ 1595 /* Set dest = src, where both dest and src are container value literals 1596 * (ie, struct literals, or static arrays (can be an array literal or a string)) 1597 * Assignment is recursively in-place. 1598 * Purpose: any reference to a member of 'dest' will remain valid after the 1599 * assignment. 1600 */ 1601 extern (C++) void assignInPlace(Expression dest, Expression src) 1602 { 1603 assert(dest.op == TOKstructliteral || dest.op == TOKarrayliteral || dest.op == TOKstring); 1604 Expressions* oldelems; 1605 Expressions* newelems; 1606 if (dest.op == TOKstructliteral) 1607 { 1608 assert(dest.op == src.op); 1609 oldelems = (cast(StructLiteralExp)dest).elements; 1610 newelems = (cast(StructLiteralExp)src).elements; 1611 if ((cast(StructLiteralExp)dest).sd.isNested() && oldelems.dim == newelems.dim - 1) 1612 oldelems.push(null); 1613 } 1614 else if (dest.op == TOKarrayliteral && src.op == TOKarrayliteral) 1615 { 1616 oldelems = (cast(ArrayLiteralExp)dest).elements; 1617 newelems = (cast(ArrayLiteralExp)src).elements; 1618 } 1619 else if (dest.op == TOKstring && src.op == TOKstring) 1620 { 1621 sliceAssignStringFromString(cast(StringExp)dest, cast(StringExp)src, 0); 1622 return; 1623 } 1624 else if (dest.op == TOKarrayliteral && src.op == TOKstring) 1625 { 1626 sliceAssignArrayLiteralFromString(cast(ArrayLiteralExp)dest, cast(StringExp)src, 0); 1627 return; 1628 } 1629 else if (src.op == TOKarrayliteral && dest.op == TOKstring) 1630 { 1631 sliceAssignStringFromArrayLiteral(cast(StringExp)dest, cast(ArrayLiteralExp)src, 0); 1632 return; 1633 } 1634 else 1635 assert(0); 1636 assert(oldelems.dim == newelems.dim); 1637 for (size_t i = 0; i < oldelems.dim; ++i) 1638 { 1639 Expression e = (*newelems)[i]; 1640 Expression o = (*oldelems)[i]; 1641 if (e.op == TOKstructliteral) 1642 { 1643 assert(o.op == e.op); 1644 assignInPlace(o, e); 1645 } 1646 else if (e.type.ty == Tsarray && e.op != TOKvoid && o.type.ty == Tsarray) 1647 { 1648 assignInPlace(o, e); 1649 } 1650 else 1651 { 1652 (*oldelems)[i] = (*newelems)[i]; 1653 } 1654 } 1655 } 1656 1657 // Duplicate the elements array, then set field 'indexToChange' = newelem. 1658 extern (C++) Expressions* changeOneElement(Expressions* oldelems, size_t indexToChange, Expression newelem) 1659 { 1660 auto expsx = new Expressions(); 1661 ++CtfeStatus.numArrayAllocs; 1662 expsx.setDim(oldelems.dim); 1663 for (size_t j = 0; j < expsx.dim; j++) 1664 { 1665 if (j == indexToChange) 1666 (*expsx)[j] = newelem; 1667 else 1668 (*expsx)[j] = (*oldelems)[j]; 1669 } 1670 return expsx; 1671 } 1672 1673 // Create a new struct literal, which is the same as se except that se.field[offset] = elem 1674 extern (C++) Expression modifyStructField(Type type, StructLiteralExp se, size_t offset, Expression newval) 1675 { 1676 int fieldi = se.getFieldIndex(newval.type, cast(uint)offset); 1677 if (fieldi == -1) 1678 return CTFEExp.cantexp; 1679 /* Create new struct literal reflecting updated fieldi 1680 */ 1681 Expressions* expsx = changeOneElement(se.elements, fieldi, newval); 1682 auto ee = new StructLiteralExp(se.loc, se.sd, expsx); 1683 ee.type = se.type; 1684 ee.ownedByCtfe = OWNEDctfe; 1685 return ee; 1686 } 1687 1688 // Given an AA literal aae, set aae[index] = newval and return newval. 1689 extern (C++) Expression assignAssocArrayElement(Loc loc, AssocArrayLiteralExp aae, Expression index, Expression newval) 1690 { 1691 /* Create new associative array literal reflecting updated key/value 1692 */ 1693 Expressions* keysx = aae.keys; 1694 Expressions* valuesx = aae.values; 1695 int updated = 0; 1696 for (size_t j = valuesx.dim; j;) 1697 { 1698 j--; 1699 Expression ekey = (*aae.keys)[j]; 1700 int eq = ctfeEqual(loc, TOKequal, ekey, index); 1701 if (eq) 1702 { 1703 (*valuesx)[j] = newval; 1704 updated = 1; 1705 } 1706 } 1707 if (!updated) 1708 { 1709 // Append index/newval to keysx[]/valuesx[] 1710 valuesx.push(newval); 1711 keysx.push(index); 1712 } 1713 return newval; 1714 } 1715 1716 /// Given array literal oldval of type ArrayLiteralExp or StringExp, of length 1717 /// oldlen, change its length to newlen. If the newlen is longer than oldlen, 1718 /// all new elements will be set to the default initializer for the element type. 1719 extern (C++) UnionExp changeArrayLiteralLength(Loc loc, TypeArray arrayType, Expression oldval, size_t oldlen, size_t newlen) 1720 { 1721 UnionExp ue; 1722 Type elemType = arrayType.next; 1723 assert(elemType); 1724 Expression defaultElem = elemType.defaultInitLiteral(loc); 1725 auto elements = new Expressions(); 1726 elements.setDim(newlen); 1727 // Resolve slices 1728 size_t indxlo = 0; 1729 if (oldval.op == TOKslice) 1730 { 1731 indxlo = cast(size_t)(cast(SliceExp)oldval).lwr.toInteger(); 1732 oldval = (cast(SliceExp)oldval).e1; 1733 } 1734 size_t copylen = oldlen < newlen ? oldlen : newlen; 1735 if (oldval.op == TOKstring) 1736 { 1737 StringExp oldse = cast(StringExp)oldval; 1738 void* s = mem.xcalloc(newlen + 1, oldse.sz); 1739 memcpy(s, oldse..string, copylen * oldse.sz); 1740 uint defaultValue = cast(uint)defaultElem.toInteger(); 1741 for (size_t elemi = copylen; elemi < newlen; ++elemi) 1742 { 1743 switch (oldse.sz) 1744 { 1745 case 1: 1746 (cast(char*)s)[cast(size_t)(indxlo + elemi)] = cast(char)defaultValue; 1747 break; 1748 case 2: 1749 (cast(wchar*)s)[cast(size_t)(indxlo + elemi)] = cast(wchar)defaultValue; 1750 break; 1751 case 4: 1752 (cast(dchar*)s)[cast(size_t)(indxlo + elemi)] = cast(dchar)defaultValue; 1753 break; 1754 default: 1755 assert(0); 1756 } 1757 } 1758 emplaceExp!(StringExp)(&ue, loc, s, newlen); 1759 StringExp se = cast(StringExp)ue.exp(); 1760 se.type = arrayType; 1761 se.sz = oldse.sz; 1762 se.committed = oldse.committed; 1763 se.ownedByCtfe = OWNEDctfe; 1764 } 1765 else 1766 { 1767 if (oldlen != 0) 1768 { 1769 assert(oldval.op == TOKarrayliteral); 1770 ArrayLiteralExp ae = cast(ArrayLiteralExp)oldval; 1771 for (size_t i = 0; i < copylen; i++) 1772 (*elements)[i] = (*ae.elements)[indxlo + i]; 1773 } 1774 if (elemType.ty == Tstruct || elemType.ty == Tsarray) 1775 { 1776 /* If it is an aggregate literal representing a value type, 1777 * we need to create a unique copy for each element 1778 */ 1779 for (size_t i = copylen; i < newlen; i++) 1780 (*elements)[i] = copyLiteral(defaultElem).copy(); 1781 } 1782 else 1783 { 1784 for (size_t i = copylen; i < newlen; i++) 1785 (*elements)[i] = defaultElem; 1786 } 1787 emplaceExp!(ArrayLiteralExp)(&ue, loc, elements); 1788 ArrayLiteralExp aae = cast(ArrayLiteralExp)ue.exp(); 1789 aae.type = arrayType; 1790 aae.ownedByCtfe = OWNEDctfe; 1791 } 1792 return ue; 1793 } 1794 1795 /*************************** CTFE Sanity Checks ***************************/ 1796 extern (C++) bool isCtfeValueValid(Expression newval) 1797 { 1798 Type tb = newval.type.toBasetype(); 1799 if (newval.op == TOKint64 || newval.op == TOKfloat64 || newval.op == TOKchar || newval.op == TOKcomplex80) 1800 { 1801 return tb.isscalar(); 1802 } 1803 if (newval.op == TOKnull) 1804 { 1805 return tb.ty == Tnull || tb.ty == Tpointer || tb.ty == Tarray || tb.ty == Taarray || tb.ty == Tclass; 1806 } 1807 if (newval.op == TOKstring) 1808 return true; // CTFE would directly use the StringExp in AST. 1809 if (newval.op == TOKarrayliteral) 1810 return true; //((ArrayLiteralExp *)newval)->ownedByCtfe; 1811 if (newval.op == TOKassocarrayliteral) 1812 return true; //((AssocArrayLiteralExp *)newval)->ownedByCtfe; 1813 if (newval.op == TOKstructliteral) 1814 return true; //((StructLiteralExp *)newval)->ownedByCtfe; 1815 if (newval.op == TOKclassreference) 1816 return true; 1817 if (newval.op == TOKvector) 1818 return true; // vector literal 1819 if (newval.op == TOKfunction) 1820 return true; // function literal or delegate literal 1821 if (newval.op == TOKdelegate) 1822 { 1823 // &struct.func or &clasinst.func 1824 // &nestedfunc 1825 Expression ethis = (cast(DelegateExp)newval).e1; 1826 return (ethis.op == TOKstructliteral || ethis.op == TOKclassreference || ethis.op == TOKvar && (cast(VarExp)ethis).var == (cast(DelegateExp)newval).func); 1827 } 1828 if (newval.op == TOKsymoff) 1829 { 1830 // function pointer, or pointer to static variable 1831 Declaration d = (cast(SymOffExp)newval).var; 1832 return d.isFuncDeclaration() || d.isDataseg(); 1833 } 1834 if (newval.op == TOKtypeid) 1835 { 1836 // always valid 1837 return true; 1838 } 1839 if (newval.op == TOKaddress) 1840 { 1841 // e1 should be a CTFE reference 1842 Expression e1 = (cast(AddrExp)newval).e1; 1843 return tb.ty == Tpointer && (e1.op == TOKstructliteral && isCtfeValueValid(e1) || e1.op == TOKvar || e1.op == TOKdotvar && isCtfeReferenceValid(e1) || e1.op == TOKindex && isCtfeReferenceValid(e1) || e1.op == TOKslice && e1.type.toBasetype().ty == Tsarray); 1844 } 1845 if (newval.op == TOKslice) 1846 { 1847 // e1 should be an array aggregate 1848 SliceExp se = cast(SliceExp)newval; 1849 assert(se.lwr && se.lwr.op == TOKint64); 1850 assert(se.upr && se.upr.op == TOKint64); 1851 return (tb.ty == Tarray || tb.ty == Tsarray) && (se.e1.op == TOKstring || se.e1.op == TOKarrayliteral); 1852 } 1853 if (newval.op == TOKvoid) 1854 return true; // uninitialized value 1855 newval.error("CTFE internal error: illegal CTFE value %s", newval.toChars()); 1856 return false; 1857 } 1858 1859 extern (C++) bool isCtfeReferenceValid(Expression newval) 1860 { 1861 if (newval.op == TOKthis) 1862 return true; 1863 if (newval.op == TOKvar) 1864 { 1865 VarDeclaration v = (cast(VarExp)newval).var.isVarDeclaration(); 1866 assert(v); 1867 // Must not be a reference to a reference 1868 return true; 1869 } 1870 if (newval.op == TOKindex) 1871 { 1872 Expression eagg = (cast(IndexExp)newval).e1; 1873 return eagg.op == TOKstring || eagg.op == TOKarrayliteral || eagg.op == TOKassocarrayliteral; 1874 } 1875 if (newval.op == TOKdotvar) 1876 { 1877 Expression eagg = (cast(DotVarExp)newval).e1; 1878 return (eagg.op == TOKstructliteral || eagg.op == TOKclassreference) && isCtfeValueValid(eagg); 1879 } 1880 // Internally a ref variable may directly point a stack memory. 1881 // e.g. ref int v = 1; 1882 return isCtfeValueValid(newval); 1883 } 1884 1885 // Used for debugging only 1886 extern (C++) void showCtfeExpr(Expression e, int level = 0) 1887 { 1888 for (int i = level; i > 0; --i) 1889 printf(" "); 1890 Expressions* elements = null; 1891 // We need the struct definition to detect block assignment 1892 StructDeclaration sd = null; 1893 ClassDeclaration cd = null; 1894 if (e.op == TOKstructliteral) 1895 { 1896 elements = (cast(StructLiteralExp)e).elements; 1897 sd = (cast(StructLiteralExp)e).sd; 1898 printf("STRUCT type = %s %p:\n", e.type.toChars(), e); 1899 } 1900 else if (e.op == TOKclassreference) 1901 { 1902 elements = (cast(ClassReferenceExp)e).value.elements; 1903 cd = (cast(ClassReferenceExp)e).originalClass(); 1904 printf("CLASS type = %s %p:\n", e.type.toChars(), (cast(ClassReferenceExp)e).value); 1905 } 1906 else if (e.op == TOKarrayliteral) 1907 { 1908 elements = (cast(ArrayLiteralExp)e).elements; 1909 printf("ARRAY LITERAL type=%s %p:\n", e.type.toChars(), e); 1910 } 1911 else if (e.op == TOKassocarrayliteral) 1912 { 1913 printf("AA LITERAL type=%s %p:\n", e.type.toChars(), e); 1914 } 1915 else if (e.op == TOKstring) 1916 { 1917 printf("STRING %s %p\n", e.toChars(), (cast(StringExp)e).string); 1918 } 1919 else if (e.op == TOKslice) 1920 { 1921 printf("SLICE %p: %s\n", e, e.toChars()); 1922 showCtfeExpr((cast(SliceExp)e).e1, level + 1); 1923 } 1924 else if (e.op == TOKvar) 1925 { 1926 printf("VAR %p %s\n", e, e.toChars()); 1927 VarDeclaration v = (cast(VarExp)e).var.isVarDeclaration(); 1928 if (v && getValue(v)) 1929 showCtfeExpr(getValue(v), level + 1); 1930 } 1931 else if (e.op == TOKaddress) 1932 { 1933 // This is potentially recursive. We mustn't try to print the thing we're pointing to. 1934 printf("POINTER %p to %p: %s\n", e, (cast(AddrExp)e).e1, e.toChars()); 1935 } 1936 else 1937 printf("VALUE %p: %s\n", e, e.toChars()); 1938 if (elements) 1939 { 1940 size_t fieldsSoFar = 0; 1941 for (size_t i = 0; i < elements.dim; i++) 1942 { 1943 Expression z = null; 1944 VarDeclaration v = null; 1945 if (i > 15) 1946 { 1947 printf("...(total %d elements)\n", cast(int)elements.dim); 1948 return; 1949 } 1950 if (sd) 1951 { 1952 v = sd.fields[i]; 1953 z = (*elements)[i]; 1954 } 1955 else if (cd) 1956 { 1957 while (i - fieldsSoFar >= cd.fields.dim) 1958 { 1959 fieldsSoFar += cd.fields.dim; 1960 cd = cd.baseClass; 1961 for (int j = level; j > 0; --j) 1962 printf(" "); 1963 printf(" BASE CLASS: %s\n", cd.toChars()); 1964 } 1965 v = cd.fields[i - fieldsSoFar]; 1966 assert((elements.dim + i) >= (fieldsSoFar + cd.fields.dim)); 1967 size_t indx = (elements.dim - fieldsSoFar) - cd.fields.dim + i; 1968 assert(indx < elements.dim); 1969 z = (*elements)[indx]; 1970 } 1971 if (!z) 1972 { 1973 for (int j = level; j > 0; --j) 1974 printf(" "); 1975 printf(" void\n"); 1976 continue; 1977 } 1978 if (v) 1979 { 1980 // If it is a void assignment, use the default initializer 1981 if ((v.type.ty != z.type.ty) && v.type.ty == Tsarray) 1982 { 1983 for (int j = level; --j;) 1984 printf(" "); 1985 printf(" field: block initalized static array\n"); 1986 continue; 1987 } 1988 } 1989 showCtfeExpr(z, level + 1); 1990 } 1991 } 1992 } 1993 1994 /*************************** Void initialization ***************************/ 1995 extern (C++) UnionExp voidInitLiteral(Type t, VarDeclaration var) 1996 { 1997 UnionExp ue; 1998 if (t.ty == Tsarray) 1999 { 2000 TypeSArray tsa = cast(TypeSArray)t; 2001 Expression elem = voidInitLiteral(tsa.next, var).copy(); 2002 // For aggregate value types (structs, static arrays) we must 2003 // create an a separate copy for each element. 2004 bool mustCopy = (elem.op == TOKarrayliteral || elem.op == TOKstructliteral); 2005 auto elements = new Expressions(); 2006 size_t d = cast(size_t)tsa.dim.toInteger(); 2007 elements.setDim(d); 2008 for (size_t i = 0; i < d; i++) 2009 { 2010 if (mustCopy && i > 0) 2011 elem = copyLiteral(elem).copy(); 2012 (*elements)[i] = elem; 2013 } 2014 emplaceExp!(ArrayLiteralExp)(&ue, var.loc, elements); 2015 ArrayLiteralExp ae = cast(ArrayLiteralExp)ue.exp(); 2016 ae.type = tsa; 2017 ae.ownedByCtfe = OWNEDctfe; 2018 } 2019 else if (t.ty == Tstruct) 2020 { 2021 TypeStruct ts = cast(TypeStruct)t; 2022 auto exps = new Expressions(); 2023 exps.setDim(ts.sym.fields.dim); 2024 for (size_t i = 0; i < ts.sym.fields.dim; i++) 2025 { 2026 (*exps)[i] = voidInitLiteral(ts.sym.fields[i].type, ts.sym.fields[i]).copy(); 2027 } 2028 emplaceExp!(StructLiteralExp)(&ue, var.loc, ts.sym, exps); 2029 StructLiteralExp se = cast(StructLiteralExp)ue.exp(); 2030 se.type = ts; 2031 se.ownedByCtfe = OWNEDctfe; 2032 } 2033 else 2034 emplaceExp!(VoidInitExp)(&ue, var, t); 2035 return ue; 2036 }