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