1 /** 2 * Defines the bulk of the classes which represent the AST at the expression level. 3 * 4 * Specification: ($LINK2 https://dlang.org/spec/expression.html, Expressions) 5 * 6 * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved 7 * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) 8 * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 9 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/expression.d, _expression.d) 10 * Documentation: https://dlang.org/phobos/dmd_expression.html 11 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/expression.d 12 */ 13 14 module dmd.expression; 15 16 import core.stdc.stdarg; 17 import core.stdc.stdio; 18 import core.stdc.string; 19 20 import dmd.aggregate; 21 import dmd.aliasthis; 22 import dmd.apply; 23 import dmd.arrayop; 24 import dmd.arraytypes; 25 import dmd.astenums; 26 import dmd.ast_node; 27 import dmd.gluelayer; 28 import dmd.constfold; 29 import dmd.ctfeexpr; 30 import dmd.ctorflow; 31 import dmd.dcast; 32 import dmd.dclass; 33 import dmd.declaration; 34 import dmd.delegatize; 35 import dmd.dimport; 36 import dmd.dinterpret; 37 import dmd.dmodule; 38 import dmd.dscope; 39 import dmd.dstruct; 40 import dmd.dsymbol; 41 import dmd.dsymbolsem; 42 import dmd.dtemplate; 43 import dmd.errors; 44 import dmd.escape; 45 import dmd.expressionsem; 46 import dmd.func; 47 import dmd.globals; 48 import dmd.hdrgen; 49 import dmd.id; 50 import dmd.identifier; 51 import dmd.init; 52 import dmd.inline; 53 import dmd.location; 54 import dmd.mtype; 55 import dmd.nspace; 56 import dmd.objc; 57 import dmd.opover; 58 import dmd.optimize; 59 import dmd.root.complex; 60 import dmd.root.ctfloat; 61 import dmd.root.filename; 62 import dmd.common.outbuffer; 63 import dmd.root.optional; 64 import dmd.root.rmem; 65 import dmd.root.rootobject; 66 import dmd.root.string; 67 import dmd.root.utf; 68 import dmd.safe; 69 import dmd.sideeffect; 70 import dmd.target; 71 import dmd.tokens; 72 import dmd.typesem; 73 import dmd.visitor; 74 75 enum LOGSEMANTIC = false; 76 77 void emplaceExp(T : Expression, Args...)(void* p, Args args) 78 { 79 static if (__VERSION__ < 2099) 80 const init = typeid(T).initializer; 81 else 82 const init = __traits(initSymbol, T); 83 p[0 .. __traits(classInstanceSize, T)] = init[]; 84 (cast(T)p).__ctor(args); 85 } 86 87 void emplaceExp(T : UnionExp)(T* p, Expression e) 88 { 89 memcpy(p, cast(void*)e, e.size); 90 } 91 92 /// Return value for `checkModifiable` 93 enum Modifiable 94 { 95 /// Not modifiable 96 no, 97 /// Modifiable (the type is mutable) 98 yes, 99 /// Modifiable because it is initialization 100 initialization, 101 } 102 /** 103 * Specifies how the checkModify deals with certain situations 104 */ 105 enum ModifyFlags 106 { 107 /// Issue error messages on invalid modifications of the variable 108 none, 109 /// No errors are emitted for invalid modifications 110 noError = 0x1, 111 /// The modification occurs for a subfield of the current variable 112 fieldAssign = 0x2, 113 } 114 115 /**************************************** 116 * Find the first non-comma expression. 117 * Params: 118 * e = Expressions connected by commas 119 * Returns: 120 * left-most non-comma expression 121 */ 122 inout(Expression) firstComma(inout Expression e) 123 { 124 Expression ex = cast()e; 125 while (ex.op == EXP.comma) 126 ex = (cast(CommaExp)ex).e1; 127 return cast(inout)ex; 128 129 } 130 131 /**************************************** 132 * Find the last non-comma expression. 133 * Params: 134 * e = Expressions connected by commas 135 * Returns: 136 * right-most non-comma expression 137 */ 138 139 inout(Expression) lastComma(inout Expression e) 140 { 141 Expression ex = cast()e; 142 while (ex.op == EXP.comma) 143 ex = (cast(CommaExp)ex).e2; 144 return cast(inout)ex; 145 146 } 147 148 /***************************************** 149 * Determine if `this` is available by walking up the enclosing 150 * scopes until a function is found. 151 * 152 * Params: 153 * sc = where to start looking for the enclosing function 154 * Returns: 155 * Found function if it satisfies `isThis()`, otherwise `null` 156 */ 157 FuncDeclaration hasThis(Scope* sc) 158 { 159 //printf("hasThis()\n"); 160 Dsymbol p = sc.parent; 161 while (p && p.isTemplateMixin()) 162 p = p.parent; 163 FuncDeclaration fdthis = p ? p.isFuncDeclaration() : null; 164 //printf("fdthis = %p, '%s'\n", fdthis, fdthis ? fdthis.toChars() : ""); 165 166 // Go upwards until we find the enclosing member function 167 FuncDeclaration fd = fdthis; 168 while (1) 169 { 170 if (!fd) 171 { 172 return null; 173 } 174 if (!fd.isNested() || fd.isThis() || (fd.hasDualContext() && fd.isMember2())) 175 break; 176 177 Dsymbol parent = fd.parent; 178 while (1) 179 { 180 if (!parent) 181 return null; 182 TemplateInstance ti = parent.isTemplateInstance(); 183 if (ti) 184 parent = ti.parent; 185 else 186 break; 187 } 188 fd = parent.isFuncDeclaration(); 189 } 190 191 if (!fd.isThis() && !(fd.hasDualContext() && fd.isMember2())) 192 { 193 return null; 194 } 195 196 assert(fd.vthis); 197 return fd; 198 199 } 200 201 /*********************************** 202 * Determine if a `this` is needed to access `d`. 203 * Params: 204 * sc = context 205 * d = declaration to check 206 * Returns: 207 * true means a `this` is needed 208 */ 209 bool isNeedThisScope(Scope* sc, Declaration d) 210 { 211 if (sc.intypeof == 1) 212 return false; 213 214 AggregateDeclaration ad = d.isThis(); 215 if (!ad) 216 return false; 217 //printf("d = %s, ad = %s\n", d.toChars(), ad.toChars()); 218 219 for (Dsymbol s = sc.parent; s; s = s.toParentLocal()) 220 { 221 //printf("\ts = %s %s, toParent2() = %p\n", s.kind(), s.toChars(), s.toParent2()); 222 if (AggregateDeclaration ad2 = s.isAggregateDeclaration()) 223 { 224 if (ad2 == ad) 225 return false; 226 else if (ad2.isNested()) 227 continue; 228 else 229 return true; 230 } 231 if (FuncDeclaration f = s.isFuncDeclaration()) 232 { 233 if (f.isMemberLocal()) 234 break; 235 } 236 } 237 return true; 238 } 239 240 /****************************** 241 * check e is exp.opDispatch!(tiargs) or not 242 * It's used to switch to UFCS the semantic analysis path 243 */ 244 bool isDotOpDispatch(Expression e) 245 { 246 if (auto dtie = e.isDotTemplateInstanceExp()) 247 return dtie.ti.name == Id.opDispatch; 248 return false; 249 } 250 251 /**************************************** 252 * Expand tuples in-place. 253 * 254 * Example: 255 * When there's a call `f(10, pair: AliasSeq!(20, 30), single: 40)`, the input is: 256 * `exps = [10, (20, 30), 40]` 257 * `names = [null, "pair", "single"]` 258 * The arrays will be modified to: 259 * `exps = [10, 20, 30, 40]` 260 * `names = [null, "pair", null, "single"]` 261 * 262 * Params: 263 * exps = array of Expressions 264 * names = optional array of names corresponding to Expressions 265 */ 266 extern (C++) void expandTuples(Expressions* exps, Identifiers* names = null) 267 { 268 //printf("expandTuples()\n"); 269 if (exps is null) 270 return; 271 272 if (names) 273 { 274 if (exps.length != names.length) 275 { 276 printf("exps.length = %d, names.length = %d\n", cast(int) exps.length, cast(int) names.length); 277 printf("exps = %s, names = %s\n", exps.toChars(), names.toChars()); 278 if (exps.length > 0) 279 printf("%s\n", (*exps)[0].loc.toChars()); 280 assert(0); 281 } 282 } 283 284 // At `index`, a tuple of length `length` is expanded. Insert corresponding nulls in `names`. 285 void expandNames(size_t index, size_t length) 286 { 287 if (names) 288 { 289 if (length == 0) 290 { 291 names.remove(index); 292 return; 293 } 294 foreach (i; 1 .. length) 295 { 296 names.insert(index + i, cast(Identifier) null); 297 } 298 } 299 } 300 301 for (size_t i = 0; i < exps.length; i++) 302 { 303 Expression arg = (*exps)[i]; 304 if (!arg) 305 continue; 306 307 // Look for tuple with 0 members 308 if (auto e = arg.isTypeExp()) 309 { 310 if (auto tt = e.type.toBasetype().isTypeTuple()) 311 { 312 if (!tt.arguments || tt.arguments.length == 0) 313 { 314 exps.remove(i); 315 expandNames(i, 0); 316 if (i == exps.length) 317 return; 318 } 319 else // Expand a TypeTuple 320 { 321 exps.remove(i); 322 auto texps = new Expressions(tt.arguments.length); 323 foreach (j, a; *tt.arguments) 324 (*texps)[j] = new TypeExp(e.loc, a.type); 325 exps.insert(i, texps); 326 expandNames(i, texps.length); 327 } 328 i--; 329 continue; 330 } 331 } 332 333 // Inline expand all the tuples 334 while (arg.op == EXP.tuple) 335 { 336 TupleExp te = cast(TupleExp)arg; 337 exps.remove(i); // remove arg 338 exps.insert(i, te.exps); // replace with tuple contents 339 expandNames(i, te.exps.length); 340 if (i == exps.length) 341 return; // empty tuple, no more arguments 342 (*exps)[i] = Expression.combine(te.e0, (*exps)[i]); 343 arg = (*exps)[i]; 344 } 345 } 346 } 347 348 /**************************************** 349 * Expand alias this tuples. 350 */ 351 TupleDeclaration isAliasThisTuple(Expression e) 352 { 353 if (!e.type) 354 return null; 355 356 Type t = e.type.toBasetype(); 357 while (true) 358 { 359 if (Dsymbol s = t.toDsymbol(null)) 360 { 361 if (auto ad = s.isAggregateDeclaration()) 362 { 363 s = ad.aliasthis ? ad.aliasthis.sym : null; 364 if (s && s.isVarDeclaration()) 365 { 366 TupleDeclaration td = s.isVarDeclaration().toAlias().isTupleDeclaration(); 367 if (td && td.isexp) 368 return td; 369 } 370 if (Type att = t.aliasthisOf()) 371 { 372 t = att; 373 continue; 374 } 375 } 376 } 377 return null; 378 } 379 } 380 381 int expandAliasThisTuples(Expressions* exps, size_t starti = 0) 382 { 383 if (!exps || exps.length == 0) 384 return -1; 385 386 for (size_t u = starti; u < exps.length; u++) 387 { 388 Expression exp = (*exps)[u]; 389 if (TupleDeclaration td = exp.isAliasThisTuple) 390 { 391 exps.remove(u); 392 size_t i; 393 td.foreachVar((s) 394 { 395 auto d = s.isDeclaration(); 396 auto e = new DotVarExp(exp.loc, exp, d); 397 assert(d.type); 398 e.type = d.type; 399 exps.insert(u + i, e); 400 ++i; 401 }); 402 version (none) 403 { 404 printf("expansion ->\n"); 405 foreach (e; exps) 406 { 407 printf("\texps[%d] e = %s %s\n", i, EXPtoString(e.op), e.toChars()); 408 } 409 } 410 return cast(int)u; 411 } 412 } 413 return -1; 414 } 415 416 /**************************************** 417 * If `s` is a function template, i.e. the only member of a template 418 * and that member is a function, return that template. 419 * Params: 420 * s = symbol that might be a function template 421 * Returns: 422 * template for that function, otherwise null 423 */ 424 TemplateDeclaration getFuncTemplateDecl(Dsymbol s) 425 { 426 FuncDeclaration f = s.isFuncDeclaration(); 427 if (f && f.parent) 428 { 429 if (auto ti = f.parent.isTemplateInstance()) 430 { 431 if (!ti.isTemplateMixin() && ti.tempdecl) 432 { 433 auto td = ti.tempdecl.isTemplateDeclaration(); 434 if (td.onemember && td.ident == f.ident) 435 { 436 return td; 437 } 438 } 439 } 440 } 441 return null; 442 } 443 444 /************************************************ 445 * If we want the value of this expression, but do not want to call 446 * the destructor on it. 447 */ 448 Expression valueNoDtor(Expression e) 449 { 450 auto ex = lastComma(e); 451 452 if (auto ce = ex.isCallExp()) 453 { 454 /* The struct value returned from the function is transferred 455 * so do not call the destructor on it. 456 * Recognize: 457 * ((S _ctmp = S.init), _ctmp).this(...) 458 * and make sure the destructor is not called on _ctmp 459 * BUG: if ex is a CommaExp, we should go down the right side. 460 */ 461 if (auto dve = ce.e1.isDotVarExp()) 462 { 463 if (dve.var.isCtorDeclaration()) 464 { 465 // It's a constructor call 466 if (auto comma = dve.e1.isCommaExp()) 467 { 468 if (auto ve = comma.e2.isVarExp()) 469 { 470 VarDeclaration ctmp = ve.var.isVarDeclaration(); 471 if (ctmp) 472 { 473 ctmp.storage_class |= STC.nodtor; 474 assert(!ce.isLvalue()); 475 } 476 } 477 } 478 } 479 } 480 } 481 else if (auto ve = ex.isVarExp()) 482 { 483 auto vtmp = ve.var.isVarDeclaration(); 484 if (vtmp && (vtmp.storage_class & STC.rvalue)) 485 { 486 vtmp.storage_class |= STC.nodtor; 487 } 488 } 489 return e; 490 } 491 492 /********************************************* 493 * If e is an instance of a struct, and that struct has a copy constructor, 494 * rewrite e as: 495 * (tmp = e),tmp 496 * Input: 497 * sc = just used to specify the scope of created temporary variable 498 * destinationType = the type of the object on which the copy constructor is called; 499 * may be null if the struct defines a postblit 500 */ 501 private Expression callCpCtor(Scope* sc, Expression e, Type destinationType) 502 { 503 if (auto ts = e.type.baseElemOf().isTypeStruct()) 504 { 505 StructDeclaration sd = ts.sym; 506 if (sd.postblit || sd.hasCopyCtor) 507 { 508 /* Create a variable tmp, and replace the argument e with: 509 * (tmp = e),tmp 510 * and let AssignExp() handle the construction. 511 * This is not the most efficient, ideally tmp would be constructed 512 * directly onto the stack. 513 */ 514 auto tmp = copyToTemp(STC.rvalue, "__copytmp", e); 515 if (sd.hasCopyCtor && destinationType) 516 { 517 // https://issues.dlang.org/show_bug.cgi?id=22619 518 // If the destination type is inout we can preserve it 519 // only if inside an inout function; if we are not inside 520 // an inout function, then we will preserve the type of 521 // the source 522 if (destinationType.hasWild && !(sc.func.storage_class & STC.wild)) 523 tmp.type = e.type; 524 else 525 tmp.type = destinationType; 526 } 527 tmp.storage_class |= STC.nodtor; 528 tmp.dsymbolSemantic(sc); 529 Expression de = new DeclarationExp(e.loc, tmp); 530 Expression ve = new VarExp(e.loc, tmp); 531 de.type = Type.tvoid; 532 ve.type = e.type; 533 return Expression.combine(de, ve); 534 } 535 } 536 return e; 537 } 538 539 /************************************************ 540 * Handle the postblit call on lvalue, or the move of rvalue. 541 * 542 * Params: 543 * sc = the scope where the expression is encountered 544 * e = the expression the needs to be moved or copied (source) 545 * t = if the struct defines a copy constructor, the type of the destination 546 * 547 * Returns: 548 * The expression that copy constructs or moves the value. 549 */ 550 extern (D) Expression doCopyOrMove(Scope *sc, Expression e, Type t = null) 551 { 552 if (auto ce = e.isCondExp()) 553 { 554 ce.e1 = doCopyOrMove(sc, ce.e1); 555 ce.e2 = doCopyOrMove(sc, ce.e2); 556 } 557 else 558 { 559 e = e.isLvalue() ? callCpCtor(sc, e, t) : valueNoDtor(e); 560 } 561 return e; 562 } 563 564 /****************************************************************/ 565 /* A type meant as a union of all the Expression types, 566 * to serve essentially as a Variant that will sit on the stack 567 * during CTFE to reduce memory consumption. 568 */ 569 extern (C++) struct UnionExp 570 { 571 // yes, default constructor does nothing 572 extern (D) this(Expression e) 573 { 574 memcpy(&this, cast(void*)e, e.size); 575 } 576 577 /* Extract pointer to Expression 578 */ 579 extern (C++) Expression exp() return 580 { 581 return cast(Expression)&u; 582 } 583 584 /* Convert to an allocated Expression 585 */ 586 extern (C++) Expression copy() 587 { 588 Expression e = exp(); 589 //if (e.size > sizeof(u)) printf("%s\n", EXPtoString(e.op).ptr); 590 assert(e.size <= u.sizeof); 591 switch (e.op) 592 { 593 case EXP.cantExpression: return CTFEExp.cantexp; 594 case EXP.voidExpression: return CTFEExp.voidexp; 595 case EXP.break_: return CTFEExp.breakexp; 596 case EXP.continue_: return CTFEExp.continueexp; 597 case EXP.goto_: return CTFEExp.gotoexp; 598 default: return e.copy(); 599 } 600 } 601 602 private: 603 // Ensure that the union is suitably aligned. 604 align(8) union __AnonStruct__u 605 { 606 char[__traits(classInstanceSize, Expression)] exp; 607 char[__traits(classInstanceSize, IntegerExp)] integerexp; 608 char[__traits(classInstanceSize, ErrorExp)] errorexp; 609 char[__traits(classInstanceSize, RealExp)] realexp; 610 char[__traits(classInstanceSize, ComplexExp)] complexexp; 611 char[__traits(classInstanceSize, SymOffExp)] symoffexp; 612 char[__traits(classInstanceSize, StringExp)] stringexp; 613 char[__traits(classInstanceSize, ArrayLiteralExp)] arrayliteralexp; 614 char[__traits(classInstanceSize, AssocArrayLiteralExp)] assocarrayliteralexp; 615 char[__traits(classInstanceSize, StructLiteralExp)] structliteralexp; 616 char[__traits(classInstanceSize, CompoundLiteralExp)] compoundliteralexp; 617 char[__traits(classInstanceSize, NullExp)] nullexp; 618 char[__traits(classInstanceSize, DotVarExp)] dotvarexp; 619 char[__traits(classInstanceSize, AddrExp)] addrexp; 620 char[__traits(classInstanceSize, IndexExp)] indexexp; 621 char[__traits(classInstanceSize, SliceExp)] sliceexp; 622 char[__traits(classInstanceSize, VectorExp)] vectorexp; 623 } 624 625 __AnonStruct__u u; 626 } 627 628 /******************************** 629 * Test to see if two reals are the same. 630 * Regard NaN's as equivalent. 631 * Regard +0 and -0 as different. 632 * Params: 633 * x1 = first operand 634 * x2 = second operand 635 * Returns: 636 * true if x1 is x2 637 * else false 638 */ 639 bool RealIdentical(real_t x1, real_t x2) 640 { 641 return (CTFloat.isNaN(x1) && CTFloat.isNaN(x2)) || CTFloat.isIdentical(x1, x2); 642 } 643 644 /************************ TypeDotIdExp ************************************/ 645 /* Things like: 646 * int.size 647 * foo.size 648 * (foo).size 649 * cast(foo).size 650 */ 651 DotIdExp typeDotIdExp(const ref Loc loc, Type type, Identifier ident) 652 { 653 return new DotIdExp(loc, new TypeExp(loc, type), ident); 654 } 655 656 /*************************************************** 657 * Given an Expression, find the variable it really is. 658 * 659 * For example, `a[index]` is really `a`, and `s.f` is really `s`. 660 * Params: 661 * e = Expression to look at 662 * Returns: 663 * variable if there is one, null if not 664 */ 665 VarDeclaration expToVariable(Expression e) 666 { 667 while (1) 668 { 669 switch (e.op) 670 { 671 case EXP.variable: 672 return (cast(VarExp)e).var.isVarDeclaration(); 673 674 case EXP.dotVariable: 675 e = (cast(DotVarExp)e).e1; 676 continue; 677 678 case EXP.index: 679 { 680 IndexExp ei = cast(IndexExp)e; 681 e = ei.e1; 682 Type ti = e.type.toBasetype(); 683 if (ti.ty == Tsarray) 684 continue; 685 return null; 686 } 687 688 case EXP.slice: 689 { 690 SliceExp ei = cast(SliceExp)e; 691 e = ei.e1; 692 Type ti = e.type.toBasetype(); 693 if (ti.ty == Tsarray) 694 continue; 695 return null; 696 } 697 698 case EXP.this_: 699 case EXP.super_: 700 return (cast(ThisExp)e).var.isVarDeclaration(); 701 702 default: 703 return null; 704 } 705 } 706 } 707 708 enum OwnedBy : ubyte 709 { 710 code, // normal code expression in AST 711 ctfe, // value expression for CTFE 712 cache, // constant value cached for CTFE 713 } 714 715 enum WANTvalue = 0; // default 716 enum WANTexpand = 1; // expand const/immutable variables if possible 717 718 /*********************************************************** 719 * https://dlang.org/spec/expression.html#expression 720 */ 721 extern (C++) abstract class Expression : ASTNode 722 { 723 Type type; // !=null means that semantic() has been run 724 Loc loc; // file location 725 const EXP op; // to minimize use of dynamic_cast 726 bool parens; // if this is a parenthesized expression 727 728 extern (D) this(const ref Loc loc, EXP op) scope 729 { 730 //printf("Expression::Expression(op = %d) this = %p\n", op, this); 731 this.loc = loc; 732 this.op = op; 733 } 734 735 /// Returns: class instance size of this expression (implemented manually because `extern(C++)`) 736 final size_t size() nothrow @nogc pure @safe const { return expSize[op]; } 737 738 static void _init() 739 { 740 CTFEExp.cantexp = new CTFEExp(EXP.cantExpression); 741 CTFEExp.voidexp = new CTFEExp(EXP.voidExpression); 742 CTFEExp.breakexp = new CTFEExp(EXP.break_); 743 CTFEExp.continueexp = new CTFEExp(EXP.continue_); 744 CTFEExp.gotoexp = new CTFEExp(EXP.goto_); 745 CTFEExp.showcontext = new CTFEExp(EXP.showCtfeContext); 746 } 747 748 /** 749 * Deinitializes the global state of the compiler. 750 * 751 * This can be used to restore the state set by `_init` to its original 752 * state. 753 */ 754 static void deinitialize() 755 { 756 CTFEExp.cantexp = CTFEExp.cantexp.init; 757 CTFEExp.voidexp = CTFEExp.voidexp.init; 758 CTFEExp.breakexp = CTFEExp.breakexp.init; 759 CTFEExp.continueexp = CTFEExp.continueexp.init; 760 CTFEExp.gotoexp = CTFEExp.gotoexp.init; 761 CTFEExp.showcontext = CTFEExp.showcontext.init; 762 } 763 764 /********************************* 765 * Does *not* do a deep copy. 766 */ 767 final Expression copy() 768 { 769 Expression e; 770 if (!size) 771 { 772 debug 773 { 774 fprintf(stderr, "No expression copy for: %s\n", toChars()); 775 printf("op = %d\n", op); 776 } 777 assert(0); 778 } 779 780 // memory never freed, so can use the faster bump-pointer-allocation 781 e = cast(Expression)allocmemory(size); 782 //printf("Expression::copy(op = %d) e = %p\n", op, e); 783 return cast(Expression)memcpy(cast(void*)e, cast(void*)this, size); 784 } 785 786 Expression syntaxCopy() 787 { 788 //printf("Expression::syntaxCopy()\n"); 789 //print(); 790 return copy(); 791 } 792 793 // kludge for template.isExpression() 794 override final DYNCAST dyncast() const 795 { 796 return DYNCAST.expression; 797 } 798 799 override const(char)* toChars() const 800 { 801 OutBuffer buf; 802 HdrGenState hgs; 803 toCBuffer(this, &buf, &hgs); 804 return buf.extractChars(); 805 } 806 807 static if (__VERSION__ < 2092) 808 { 809 final void error(const(char)* format, ...) const 810 { 811 if (type != Type.terror) 812 { 813 va_list ap; 814 va_start(ap, format); 815 .verror(loc, format, ap); 816 va_end(ap); 817 } 818 } 819 820 final void errorSupplemental(const(char)* format, ...) 821 { 822 if (type == Type.terror) 823 return; 824 825 va_list ap; 826 va_start(ap, format); 827 .verrorSupplemental(loc, format, ap); 828 va_end(ap); 829 } 830 831 final void warning(const(char)* format, ...) const 832 { 833 if (type != Type.terror) 834 { 835 va_list ap; 836 va_start(ap, format); 837 .vwarning(loc, format, ap); 838 va_end(ap); 839 } 840 } 841 842 final void deprecation(const(char)* format, ...) const 843 { 844 if (type != Type.terror) 845 { 846 va_list ap; 847 va_start(ap, format); 848 .vdeprecation(loc, format, ap); 849 va_end(ap); 850 } 851 } 852 } 853 else 854 { 855 pragma(printf) final void error(const(char)* format, ...) const 856 { 857 if (type != Type.terror) 858 { 859 va_list ap; 860 va_start(ap, format); 861 .verror(loc, format, ap); 862 va_end(ap); 863 } 864 } 865 866 pragma(printf) final void errorSupplemental(const(char)* format, ...) 867 { 868 if (type == Type.terror) 869 return; 870 871 va_list ap; 872 va_start(ap, format); 873 .verrorSupplemental(loc, format, ap); 874 va_end(ap); 875 } 876 877 pragma(printf) final void warning(const(char)* format, ...) const 878 { 879 if (type != Type.terror) 880 { 881 va_list ap; 882 va_start(ap, format); 883 .vwarning(loc, format, ap); 884 va_end(ap); 885 } 886 } 887 888 pragma(printf) final void deprecation(const(char)* format, ...) const 889 { 890 if (type != Type.terror) 891 { 892 va_list ap; 893 va_start(ap, format); 894 .vdeprecation(loc, format, ap); 895 va_end(ap); 896 } 897 } 898 } 899 900 /********************************** 901 * Combine e1 and e2 by CommaExp if both are not NULL. 902 */ 903 extern (D) static Expression combine(Expression e1, Expression e2) 904 { 905 if (e1) 906 { 907 if (e2) 908 { 909 e1 = new CommaExp(e1.loc, e1, e2); 910 e1.type = e2.type; 911 } 912 } 913 else 914 e1 = e2; 915 return e1; 916 } 917 918 extern (D) static Expression combine(Expression e1, Expression e2, Expression e3) 919 { 920 return combine(combine(e1, e2), e3); 921 } 922 923 extern (D) static Expression combine(Expression e1, Expression e2, Expression e3, Expression e4) 924 { 925 return combine(combine(e1, e2), combine(e3, e4)); 926 } 927 928 /********************************** 929 * If 'e' is a tree of commas, returns the rightmost expression 930 * by stripping off it from the tree. The remained part of the tree 931 * is returned via e0. 932 * Otherwise 'e' is directly returned and e0 is set to NULL. 933 */ 934 extern (D) static Expression extractLast(Expression e, out Expression e0) 935 { 936 if (e.op != EXP.comma) 937 { 938 return e; 939 } 940 941 CommaExp ce = cast(CommaExp)e; 942 if (ce.e2.op != EXP.comma) 943 { 944 e0 = ce.e1; 945 return ce.e2; 946 } 947 else 948 { 949 e0 = e; 950 951 Expression* pce = &ce.e2; 952 while ((cast(CommaExp)(*pce)).e2.op == EXP.comma) 953 { 954 pce = &(cast(CommaExp)(*pce)).e2; 955 } 956 assert((*pce).op == EXP.comma); 957 ce = cast(CommaExp)(*pce); 958 *pce = ce.e1; 959 960 return ce.e2; 961 } 962 } 963 964 extern (D) static Expressions* arraySyntaxCopy(Expressions* exps) 965 { 966 Expressions* a = null; 967 if (exps) 968 { 969 a = new Expressions(exps.length); 970 foreach (i, e; *exps) 971 { 972 (*a)[i] = e ? e.syntaxCopy() : null; 973 } 974 } 975 return a; 976 } 977 978 dinteger_t toInteger() 979 { 980 //printf("Expression %s\n", EXPtoString(op).ptr); 981 error("integer constant expression expected instead of `%s`", toChars()); 982 return 0; 983 } 984 985 uinteger_t toUInteger() 986 { 987 //printf("Expression %s\n", EXPtoString(op).ptr); 988 return cast(uinteger_t)toInteger(); 989 } 990 991 real_t toReal() 992 { 993 error("floating point constant expression expected instead of `%s`", toChars()); 994 return CTFloat.zero; 995 } 996 997 real_t toImaginary() 998 { 999 error("floating point constant expression expected instead of `%s`", toChars()); 1000 return CTFloat.zero; 1001 } 1002 1003 complex_t toComplex() 1004 { 1005 error("floating point constant expression expected instead of `%s`", toChars()); 1006 return complex_t(CTFloat.zero); 1007 } 1008 1009 StringExp toStringExp() 1010 { 1011 return null; 1012 } 1013 1014 /*************************************** 1015 * Return !=0 if expression is an lvalue. 1016 */ 1017 bool isLvalue() 1018 { 1019 return false; 1020 } 1021 1022 /******************************* 1023 * Give error if we're not an lvalue. 1024 * If we can, convert expression to be an lvalue. 1025 */ 1026 Expression toLvalue(Scope* sc, Expression e) 1027 { 1028 if (!e) 1029 e = this; 1030 else if (!loc.isValid()) 1031 loc = e.loc; 1032 1033 if (e.op == EXP.type) 1034 error("`%s` is a `%s` definition and cannot be modified", e.type.toChars(), e.type.kind()); 1035 else 1036 error("`%s` is not an lvalue and cannot be modified", e.toChars()); 1037 1038 return ErrorExp.get(); 1039 } 1040 1041 Expression modifiableLvalue(Scope* sc, Expression e) 1042 { 1043 //printf("Expression::modifiableLvalue() %s, type = %s\n", toChars(), type.toChars()); 1044 // See if this expression is a modifiable lvalue (i.e. not const) 1045 if (checkModifiable(this, sc) == Modifiable.yes) 1046 { 1047 assert(type); 1048 if (!type.isMutable()) 1049 { 1050 if (auto dve = this.isDotVarExp()) 1051 { 1052 if (isNeedThisScope(sc, dve.var)) 1053 for (Dsymbol s = sc.func; s; s = s.toParentLocal()) 1054 { 1055 FuncDeclaration ff = s.isFuncDeclaration(); 1056 if (!ff) 1057 break; 1058 if (!ff.type.isMutable) 1059 { 1060 error("cannot modify `%s` in `%s` function", toChars(), MODtoChars(type.mod)); 1061 return ErrorExp.get(); 1062 } 1063 } 1064 } 1065 error("cannot modify `%s` expression `%s`", MODtoChars(type.mod), toChars()); 1066 return ErrorExp.get(); 1067 } 1068 else if (!type.isAssignable()) 1069 { 1070 error("cannot modify struct instance `%s` of type `%s` because it contains `const` or `immutable` members", 1071 toChars(), type.toChars()); 1072 return ErrorExp.get(); 1073 } 1074 } 1075 return toLvalue(sc, e); 1076 } 1077 1078 final Expression implicitCastTo(Scope* sc, Type t) 1079 { 1080 return .implicitCastTo(this, sc, t); 1081 } 1082 1083 final MATCH implicitConvTo(Type t) 1084 { 1085 return .implicitConvTo(this, t); 1086 } 1087 1088 final Expression castTo(Scope* sc, Type t) 1089 { 1090 return .castTo(this, sc, t); 1091 } 1092 1093 /**************************************** 1094 * Resolve __FILE__, __LINE__, __MODULE__, __FUNCTION__, __PRETTY_FUNCTION__, __FILE_FULL_PATH__ to loc. 1095 */ 1096 Expression resolveLoc(const ref Loc loc, Scope* sc) 1097 { 1098 this.loc = loc; 1099 return this; 1100 } 1101 1102 /**************************************** 1103 * Check that the expression has a valid type. 1104 * If not, generates an error "... has no type". 1105 * Returns: 1106 * true if the expression is not valid. 1107 * Note: 1108 * When this function returns true, `checkValue()` should also return true. 1109 */ 1110 bool checkType() 1111 { 1112 return false; 1113 } 1114 1115 /**************************************** 1116 * Check that the expression has a valid value. 1117 * If not, generates an error "... has no value". 1118 * Returns: 1119 * true if the expression is not valid or has void type. 1120 */ 1121 bool checkValue() 1122 { 1123 if (type && type.toBasetype().ty == Tvoid) 1124 { 1125 error("expression `%s` is `void` and has no value", toChars()); 1126 //print(); assert(0); 1127 if (!global.gag) 1128 type = Type.terror; 1129 return true; 1130 } 1131 return false; 1132 } 1133 1134 extern (D) final bool checkScalar() 1135 { 1136 if (op == EXP.error) 1137 return true; 1138 if (type.toBasetype().ty == Terror) 1139 return true; 1140 if (!type.isscalar()) 1141 { 1142 error("`%s` is not a scalar, it is a `%s`", toChars(), type.toChars()); 1143 return true; 1144 } 1145 return checkValue(); 1146 } 1147 1148 extern (D) final bool checkNoBool() 1149 { 1150 if (op == EXP.error) 1151 return true; 1152 if (type.toBasetype().ty == Terror) 1153 return true; 1154 if (type.toBasetype().ty == Tbool) 1155 { 1156 error("operation not allowed on `bool` `%s`", toChars()); 1157 return true; 1158 } 1159 return false; 1160 } 1161 1162 extern (D) final bool checkIntegral() 1163 { 1164 if (op == EXP.error) 1165 return true; 1166 if (type.toBasetype().ty == Terror) 1167 return true; 1168 if (!type.isintegral()) 1169 { 1170 error("`%s` is not of integral type, it is a `%s`", toChars(), type.toChars()); 1171 return true; 1172 } 1173 return checkValue(); 1174 } 1175 1176 extern (D) final bool checkArithmetic() 1177 { 1178 if (op == EXP.error) 1179 return true; 1180 if (type.toBasetype().ty == Terror) 1181 return true; 1182 if (!type.isintegral() && !type.isfloating()) 1183 { 1184 error("`%s` is not of arithmetic type, it is a `%s`", toChars(), type.toChars()); 1185 return true; 1186 } 1187 return checkValue(); 1188 } 1189 1190 final bool checkDeprecated(Scope* sc, Dsymbol s) 1191 { 1192 return s.checkDeprecated(loc, sc); 1193 } 1194 1195 extern (D) final bool checkDisabled(Scope* sc, Dsymbol s) 1196 { 1197 if (auto d = s.isDeclaration()) 1198 { 1199 return d.checkDisabled(loc, sc); 1200 } 1201 1202 return false; 1203 } 1204 1205 /********************************************* 1206 * Calling function f. 1207 * Check the purity, i.e. if we're in a pure function 1208 * we can only call other pure functions. 1209 * Returns true if error occurs. 1210 */ 1211 extern (D) final bool checkPurity(Scope* sc, FuncDeclaration f) 1212 { 1213 if (!sc.func) 1214 return false; 1215 if (sc.func == f) 1216 return false; 1217 if (sc.intypeof == 1) 1218 return false; 1219 if (sc.flags & (SCOPE.ctfe | SCOPE.debug_)) 1220 return false; 1221 1222 // If the call has a pure parent, then the called func must be pure. 1223 if (!f.isPure() && checkImpure(sc, loc, null, f)) 1224 { 1225 error("`pure` %s `%s` cannot call impure %s `%s`", 1226 sc.func.kind(), sc.func.toPrettyChars(), f.kind(), 1227 f.toPrettyChars()); 1228 1229 if (!f.isDtorDeclaration()) 1230 errorSupplementalInferredAttr(f, /*max depth*/ 10, /*deprecation*/ false, STC.pure_); 1231 1232 checkOverridenDtor(sc, f, dd => dd.type.toTypeFunction().purity != PURE.impure, "impure"); 1233 return true; 1234 } 1235 return false; 1236 } 1237 1238 /** 1239 * Checks whether `f` is a generated `DtorDeclaration` that hides a user-defined one 1240 * which passes `check` while `f` doesn't (e.g. when the user defined dtor is pure but 1241 * the generated dtor is not). 1242 * In that case the method will identify and print all members causing the attribute 1243 * missmatch. 1244 * 1245 * Params: 1246 * sc = scope 1247 * f = potential `DtorDeclaration` 1248 * check = current check (e.g. whether it's pure) 1249 * checkName = the kind of check (e.g. `"pure"`) 1250 */ 1251 extern (D) final void checkOverridenDtor(Scope* sc, FuncDeclaration f, 1252 scope bool function(DtorDeclaration) check, const string checkName 1253 ) { 1254 auto dd = f.isDtorDeclaration(); 1255 if (!dd || !dd.isGenerated()) 1256 return; 1257 1258 // DtorDeclaration without parents should fail at an earlier stage 1259 auto ad = cast(AggregateDeclaration) f.toParent2(); 1260 assert(ad); 1261 1262 if (ad.userDtors.length) 1263 { 1264 if (!check(ad.userDtors[0])) // doesn't match check (e.g. is impure as well) 1265 return; 1266 1267 // Sanity check 1268 assert(!check(ad.fieldDtor)); 1269 } 1270 1271 dd.loc.errorSupplemental("%s`%s.~this` is %.*s because of the following field's destructors:", 1272 dd.isGenerated() ? "generated " : "".ptr, 1273 ad.toChars, 1274 cast(int) checkName.length, checkName.ptr); 1275 1276 // Search for the offending fields 1277 foreach (field; ad.fields) 1278 { 1279 // Only structs may define automatically called destructors 1280 auto ts = field.type.isTypeStruct(); 1281 if (!ts) 1282 { 1283 // But they might be part of a static array 1284 auto ta = field.type.isTypeSArray(); 1285 if (!ta) 1286 continue; 1287 1288 ts = ta.baseElemOf().isTypeStruct(); 1289 if (!ts) 1290 continue; 1291 } 1292 1293 auto fieldSym = ts.toDsymbol(sc); 1294 assert(fieldSym); // Resolving ts must succeed because missing defs. should error before 1295 1296 auto fieldSd = fieldSym.isStructDeclaration(); 1297 assert(fieldSd); // ts is a TypeStruct, this would imply a malformed ASR 1298 1299 if (fieldSd.dtor && !check(fieldSd.dtor)) 1300 { 1301 field.loc.errorSupplemental(" - %s %s", field.type.toChars(), field.toChars()); 1302 1303 if (fieldSd.dtor.isGenerated()) 1304 checkOverridenDtor(sc, fieldSd.dtor, check, checkName); 1305 else 1306 fieldSd.dtor.loc.errorSupplemental(" %.*s `%s.~this` is declared here", 1307 cast(int) checkName.length, checkName.ptr, fieldSd.toChars()); 1308 } 1309 } 1310 } 1311 1312 /******************************************* 1313 * Accessing variable v. 1314 * Check for purity and safety violations. 1315 * Returns true if error occurs. 1316 */ 1317 extern (D) final bool checkPurity(Scope* sc, VarDeclaration v) 1318 { 1319 //printf("v = %s %s\n", v.type.toChars(), v.toChars()); 1320 /* Look for purity and safety violations when accessing variable v 1321 * from current function. 1322 */ 1323 if (!sc.func) 1324 return false; 1325 if (sc.intypeof == 1) 1326 return false; // allow violations inside typeof(expression) 1327 if (sc.flags & (SCOPE.ctfe | SCOPE.debug_)) 1328 return false; // allow violations inside compile-time evaluated expressions and debug conditionals 1329 if (v.ident == Id.ctfe) 1330 return false; // magic variable never violates pure and safe 1331 if (v.isImmutable()) 1332 return false; // always safe and pure to access immutables... 1333 if (v.isConst() && !v.isReference() && (v.isDataseg() || v.isParameter()) && v.type.implicitConvTo(v.type.immutableOf())) 1334 return false; // or const global/parameter values which have no mutable indirections 1335 if (v.storage_class & STC.manifest) 1336 return false; // ...or manifest constants 1337 1338 // accessing empty structs is pure 1339 // https://issues.dlang.org/show_bug.cgi?id=18694 1340 // https://issues.dlang.org/show_bug.cgi?id=21464 1341 // https://issues.dlang.org/show_bug.cgi?id=23589 1342 if (v.type.ty == Tstruct) 1343 { 1344 StructDeclaration sd = (cast(TypeStruct)v.type).sym; 1345 if (sd.members) // not opaque 1346 { 1347 if (sd.semanticRun >= PASS.semanticdone) 1348 sd.determineSize(v.loc); 1349 if (sd.hasNoFields) 1350 return false; 1351 } 1352 } 1353 1354 bool err = false; 1355 if (v.isDataseg()) 1356 { 1357 // https://issues.dlang.org/show_bug.cgi?id=7533 1358 // Accessing implicit generated __gate is pure. 1359 if (v.ident == Id.gate) 1360 return false; 1361 1362 if (checkImpure(sc, loc, "`pure` %s `%s` cannot access mutable static data `%s`", v)) 1363 { 1364 error("`pure` %s `%s` cannot access mutable static data `%s`", 1365 sc.func.kind(), sc.func.toPrettyChars(), v.toChars()); 1366 err = true; 1367 } 1368 } 1369 else 1370 { 1371 /* Given: 1372 * void f() { 1373 * int fx; 1374 * pure void g() { 1375 * int gx; 1376 * /+pure+/ void h() { 1377 * int hx; 1378 * /+pure+/ void i() { } 1379 * } 1380 * } 1381 * } 1382 * i() can modify hx and gx but not fx 1383 */ 1384 1385 Dsymbol vparent = v.toParent2(); 1386 for (Dsymbol s = sc.func; !err && s; s = s.toParentP(vparent)) 1387 { 1388 if (s == vparent) 1389 break; 1390 1391 if (AggregateDeclaration ad = s.isAggregateDeclaration()) 1392 { 1393 if (ad.isNested()) 1394 continue; 1395 break; 1396 } 1397 FuncDeclaration ff = s.isFuncDeclaration(); 1398 if (!ff) 1399 break; 1400 if (ff.isNested() || ff.isThis()) 1401 { 1402 if (ff.type.isImmutable() || 1403 ff.type.isShared() && !MODimplicitConv(ff.type.mod, v.type.mod)) 1404 { 1405 OutBuffer ffbuf; 1406 OutBuffer vbuf; 1407 MODMatchToBuffer(&ffbuf, ff.type.mod, v.type.mod); 1408 MODMatchToBuffer(&vbuf, v.type.mod, ff.type.mod); 1409 error("%s%s `%s` cannot access %sdata `%s`", 1410 ffbuf.peekChars(), ff.kind(), ff.toPrettyChars(), vbuf.peekChars(), v.toChars()); 1411 err = true; 1412 break; 1413 } 1414 continue; 1415 } 1416 break; 1417 } 1418 } 1419 1420 /* Do not allow safe functions to access __gshared data 1421 */ 1422 if (v.storage_class & STC.gshared) 1423 { 1424 if (sc.setUnsafe(false, this.loc, 1425 "`@safe` function `%s` cannot access `__gshared` data `%s`", sc.func, v)) 1426 { 1427 err = true; 1428 } 1429 } 1430 1431 return err; 1432 } 1433 1434 /* 1435 Check if sc.func is impure or can be made impure. 1436 Returns true on error, i.e. if sc.func is pure and cannot be made impure. 1437 */ 1438 private static bool checkImpure(Scope* sc, Loc loc, const(char)* fmt, RootObject arg0) 1439 { 1440 return sc.func && (isRootTraitsCompilesScope(sc) 1441 ? sc.func.isPureBypassingInference() >= PURE.weak 1442 : sc.func.setImpure(loc, fmt, arg0)); 1443 } 1444 1445 /********************************************* 1446 * Calling function f. 1447 * Check the safety, i.e. if we're in a @safe function 1448 * we can only call @safe or @trusted functions. 1449 * Returns true if error occurs. 1450 */ 1451 extern (D) final bool checkSafety(Scope* sc, FuncDeclaration f) 1452 { 1453 if (sc.func == f) 1454 return false; 1455 if (sc.intypeof == 1) 1456 return false; 1457 if (sc.flags & SCOPE.debug_) 1458 return false; 1459 if ((sc.flags & SCOPE.ctfe) && sc.func) 1460 return false; 1461 1462 if (!sc.func) 1463 { 1464 if (sc.varDecl && !f.safetyInprocess && !f.isSafe() && !f.isTrusted()) 1465 { 1466 if (sc.varDecl.storage_class & STC.safe) 1467 { 1468 error("`@safe` variable `%s` cannot be initialized by calling `@system` function `%s`", 1469 sc.varDecl.toChars(), f.toChars()); 1470 return true; 1471 } 1472 else 1473 { 1474 sc.varDecl.storage_class |= STC.system; 1475 } 1476 } 1477 return false; 1478 } 1479 1480 if (!f.isSafe() && !f.isTrusted()) 1481 { 1482 if (isRootTraitsCompilesScope(sc) ? sc.func.isSafeBypassingInference() : sc.func.setUnsafeCall(f)) 1483 { 1484 if (!loc.isValid()) // e.g. implicitly generated dtor 1485 loc = sc.func.loc; 1486 1487 const prettyChars = f.toPrettyChars(); 1488 error("`@safe` %s `%s` cannot call `@system` %s `%s`", 1489 sc.func.kind(), sc.func.toPrettyChars(), f.kind(), 1490 prettyChars); 1491 if (!f.isDtorDeclaration) 1492 errorSupplementalInferredAttr(f, /*max depth*/ 10, /*deprecation*/ false, STC.safe); 1493 .errorSupplemental(f.loc, "`%s` is declared here", prettyChars); 1494 1495 checkOverridenDtor(sc, f, dd => dd.type.toTypeFunction().trust > TRUST.system, "@system"); 1496 1497 return true; 1498 } 1499 } 1500 else if (f.isSafe() && f.safetyViolation) 1501 { 1502 // for dip1000 by default transition, print deprecations for calling functions that will become `@system` 1503 if (sc.func.isSafeBypassingInference()) 1504 { 1505 .deprecation(this.loc, "`@safe` function `%s` calling `%s`", sc.func.toChars(), f.toChars()); 1506 errorSupplementalInferredAttr(f, 10, true, STC.safe); 1507 } 1508 else if (!sc.func.safetyViolation) 1509 { 1510 import dmd.func : AttributeViolation; 1511 sc.func.safetyViolation = new AttributeViolation(this.loc, null, f, null, null); 1512 } 1513 } 1514 return false; 1515 } 1516 1517 /********************************************* 1518 * Calling function f. 1519 * Check the @nogc-ness, i.e. if we're in a @nogc function 1520 * we can only call other @nogc functions. 1521 * Returns true if error occurs. 1522 */ 1523 extern (D) final bool checkNogc(Scope* sc, FuncDeclaration f) 1524 { 1525 if (!sc.func) 1526 return false; 1527 if (sc.func == f) 1528 return false; 1529 if (sc.intypeof == 1) 1530 return false; 1531 if (sc.flags & (SCOPE.ctfe | SCOPE.debug_)) 1532 return false; 1533 1534 if (!f.isNogc()) 1535 { 1536 if (isRootTraitsCompilesScope(sc) ? sc.func.isNogcBypassingInference() : sc.func.setGCCall(f)) 1537 { 1538 if (loc.linnum == 0) // e.g. implicitly generated dtor 1539 loc = sc.func.loc; 1540 1541 // Lowered non-@nogc'd hooks will print their own error message inside of nogc.d (NOGCVisitor.visit(CallExp e)), 1542 // so don't print anything to avoid double error messages. 1543 if (!(f.ident == Id._d_HookTraceImpl || f.ident == Id._d_arraysetlengthT 1544 || f.ident == Id._d_arrayappendT || f.ident == Id._d_arrayappendcTX 1545 || f.ident == Id._d_arraycatnTX || f.ident == Id._d_newclassT)) 1546 { 1547 error("`@nogc` %s `%s` cannot call non-@nogc %s `%s`", 1548 sc.func.kind(), sc.func.toPrettyChars(), f.kind(), f.toPrettyChars()); 1549 1550 if (!f.isDtorDeclaration) 1551 f.errorSupplementalInferredAttr(/*max depth*/ 10, /*deprecation*/ false, STC.nogc); 1552 } 1553 1554 checkOverridenDtor(sc, f, dd => dd.type.toTypeFunction().isnogc, "non-@nogc"); 1555 1556 return true; 1557 } 1558 } 1559 return false; 1560 } 1561 1562 /******************************************** 1563 * Check that the postblit is callable if t is an array of structs. 1564 * Returns true if error happens. 1565 */ 1566 extern (D) final bool checkPostblit(Scope* sc, Type t) 1567 { 1568 if (auto ts = t.baseElemOf().isTypeStruct()) 1569 { 1570 if (global.params.useTypeInfo && Type.dtypeinfo) 1571 { 1572 // https://issues.dlang.org/show_bug.cgi?id=11395 1573 // Require TypeInfo generation for array concatenation 1574 semanticTypeInfo(sc, t); 1575 } 1576 1577 StructDeclaration sd = ts.sym; 1578 if (sd.postblit) 1579 { 1580 if (sd.postblit.checkDisabled(loc, sc)) 1581 return true; 1582 1583 //checkDeprecated(sc, sd.postblit); // necessary? 1584 checkPurity(sc, sd.postblit); 1585 checkSafety(sc, sd.postblit); 1586 checkNogc(sc, sd.postblit); 1587 //checkAccess(sd, loc, sc, sd.postblit); // necessary? 1588 return false; 1589 } 1590 } 1591 return false; 1592 } 1593 1594 extern (D) final bool checkRightThis(Scope* sc) 1595 { 1596 if (op == EXP.error) 1597 return true; 1598 if (op == EXP.variable && type.ty != Terror) 1599 { 1600 VarExp ve = cast(VarExp)this; 1601 if (isNeedThisScope(sc, ve.var)) 1602 { 1603 //printf("checkRightThis sc.intypeof = %d, ad = %p, func = %p, fdthis = %p\n", 1604 // sc.intypeof, sc.getStructClassScope(), func, fdthis); 1605 error("need `this` for `%s` of type `%s`", ve.var.toChars(), ve.var.type.toChars()); 1606 return true; 1607 } 1608 } 1609 return false; 1610 } 1611 1612 /******************************* 1613 * Check whether the expression allows RMW operations, error with rmw operator diagnostic if not. 1614 * ex is the RHS expression, or NULL if ++/-- is used (for diagnostics) 1615 * Returns true if error occurs. 1616 */ 1617 extern (D) final bool checkReadModifyWrite(EXP rmwOp, Expression ex = null) 1618 { 1619 //printf("Expression::checkReadModifyWrite() %s %s", toChars(), ex ? ex.toChars() : ""); 1620 if (!type || !type.isShared() || type.isTypeStruct() || type.isTypeClass()) 1621 return false; 1622 1623 // atomicOp uses opAssign (+=/-=) rather than opOp (++/--) for the CT string literal. 1624 switch (rmwOp) 1625 { 1626 case EXP.plusPlus: 1627 case EXP.prePlusPlus: 1628 rmwOp = EXP.addAssign; 1629 break; 1630 case EXP.minusMinus: 1631 case EXP.preMinusMinus: 1632 rmwOp = EXP.minAssign; 1633 break; 1634 default: 1635 break; 1636 } 1637 1638 error("read-modify-write operations are not allowed for `shared` variables"); 1639 errorSupplemental("Use `core.atomic.atomicOp!\"%s\"(%s, %s)` instead", 1640 EXPtoString(rmwOp).ptr, toChars(), ex ? ex.toChars() : "1"); 1641 return true; 1642 } 1643 1644 /************************************************ 1645 * Destructors are attached to VarDeclarations. 1646 * Hence, if expression returns a temp that needs a destructor, 1647 * make sure and create a VarDeclaration for that temp. 1648 */ 1649 Expression addDtorHook(Scope* sc) 1650 { 1651 return this; 1652 } 1653 1654 /****************************** 1655 * Take address of expression. 1656 */ 1657 final Expression addressOf() 1658 { 1659 //printf("Expression::addressOf()\n"); 1660 debug 1661 { 1662 assert(op == EXP.error || isLvalue()); 1663 } 1664 Expression e = new AddrExp(loc, this, type.pointerTo()); 1665 return e; 1666 } 1667 1668 /****************************** 1669 * If this is a reference, dereference it. 1670 */ 1671 final Expression deref() 1672 { 1673 //printf("Expression::deref()\n"); 1674 // type could be null if forward referencing an 'auto' variable 1675 if (type) 1676 if (auto tr = type.isTypeReference()) 1677 { 1678 Expression e = new PtrExp(loc, this, tr.next); 1679 return e; 1680 } 1681 return this; 1682 } 1683 1684 final Expression optimize(int result, bool keepLvalue = false) 1685 { 1686 return Expression_optimize(this, result, keepLvalue); 1687 } 1688 1689 // Entry point for CTFE. 1690 // A compile-time result is required. Give an error if not possible 1691 final Expression ctfeInterpret() 1692 { 1693 return .ctfeInterpret(this); 1694 } 1695 1696 final int isConst() 1697 { 1698 return .isConst(this); 1699 } 1700 1701 /****** 1702 * Identical, not just equal. I.e. NaNs with different bit patterns are not identical 1703 */ 1704 bool isIdentical(const Expression e) const 1705 { 1706 return equals(e); 1707 } 1708 1709 1710 /// Statically evaluate this expression to a `bool` if possible 1711 /// Returns: an optional thath either contains the value or is empty 1712 Optional!bool toBool() 1713 { 1714 return typeof(return)(); 1715 } 1716 1717 bool hasCode() 1718 { 1719 return true; 1720 } 1721 1722 final pure inout nothrow @nogc @safe 1723 { 1724 inout(IntegerExp) isIntegerExp() { return op == EXP.int64 ? cast(typeof(return))this : null; } 1725 inout(ErrorExp) isErrorExp() { return op == EXP.error ? cast(typeof(return))this : null; } 1726 inout(VoidInitExp) isVoidInitExp() { return op == EXP.void_ ? cast(typeof(return))this : null; } 1727 inout(RealExp) isRealExp() { return op == EXP.float64 ? cast(typeof(return))this : null; } 1728 inout(ComplexExp) isComplexExp() { return op == EXP.complex80 ? cast(typeof(return))this : null; } 1729 inout(IdentifierExp) isIdentifierExp() { return op == EXP.identifier ? cast(typeof(return))this : null; } 1730 inout(DollarExp) isDollarExp() { return op == EXP.dollar ? cast(typeof(return))this : null; } 1731 inout(DsymbolExp) isDsymbolExp() { return op == EXP.dSymbol ? cast(typeof(return))this : null; } 1732 inout(ThisExp) isThisExp() { return op == EXP.this_ ? cast(typeof(return))this : null; } 1733 inout(SuperExp) isSuperExp() { return op == EXP.super_ ? cast(typeof(return))this : null; } 1734 inout(NullExp) isNullExp() { return op == EXP.null_ ? cast(typeof(return))this : null; } 1735 inout(StringExp) isStringExp() { return op == EXP.string_ ? cast(typeof(return))this : null; } 1736 inout(TupleExp) isTupleExp() { return op == EXP.tuple ? cast(typeof(return))this : null; } 1737 inout(ArrayLiteralExp) isArrayLiteralExp() { return op == EXP.arrayLiteral ? cast(typeof(return))this : null; } 1738 inout(AssocArrayLiteralExp) isAssocArrayLiteralExp() { return op == EXP.assocArrayLiteral ? cast(typeof(return))this : null; } 1739 inout(StructLiteralExp) isStructLiteralExp() { return op == EXP.structLiteral ? cast(typeof(return))this : null; } 1740 inout(CompoundLiteralExp) isCompoundLiteralExp() { return op == EXP.compoundLiteral ? cast(typeof(return))this : null; } 1741 inout(TypeExp) isTypeExp() { return op == EXP.type ? cast(typeof(return))this : null; } 1742 inout(ScopeExp) isScopeExp() { return op == EXP.scope_ ? cast(typeof(return))this : null; } 1743 inout(TemplateExp) isTemplateExp() { return op == EXP.template_ ? cast(typeof(return))this : null; } 1744 inout(NewExp) isNewExp() { return op == EXP.new_ ? cast(typeof(return))this : null; } 1745 inout(NewAnonClassExp) isNewAnonClassExp() { return op == EXP.newAnonymousClass ? cast(typeof(return))this : null; } 1746 inout(SymOffExp) isSymOffExp() { return op == EXP.symbolOffset ? cast(typeof(return))this : null; } 1747 inout(VarExp) isVarExp() { return op == EXP.variable ? cast(typeof(return))this : null; } 1748 inout(OverExp) isOverExp() { return op == EXP.overloadSet ? cast(typeof(return))this : null; } 1749 inout(FuncExp) isFuncExp() { return op == EXP.function_ ? cast(typeof(return))this : null; } 1750 inout(DeclarationExp) isDeclarationExp() { return op == EXP.declaration ? cast(typeof(return))this : null; } 1751 inout(TypeidExp) isTypeidExp() { return op == EXP.typeid_ ? cast(typeof(return))this : null; } 1752 inout(TraitsExp) isTraitsExp() { return op == EXP.traits ? cast(typeof(return))this : null; } 1753 inout(HaltExp) isHaltExp() { return op == EXP.halt ? cast(typeof(return))this : null; } 1754 inout(IsExp) isExp() { return op == EXP.is_ ? cast(typeof(return))this : null; } 1755 inout(MixinExp) isMixinExp() { return op == EXP.mixin_ ? cast(typeof(return))this : null; } 1756 inout(ImportExp) isImportExp() { return op == EXP.import_ ? cast(typeof(return))this : null; } 1757 inout(AssertExp) isAssertExp() { return op == EXP.assert_ ? cast(typeof(return))this : null; } 1758 inout(ThrowExp) isThrowExp() { return op == EXP.throw_ ? cast(typeof(return))this : null; } 1759 inout(DotIdExp) isDotIdExp() { return op == EXP.dotIdentifier ? cast(typeof(return))this : null; } 1760 inout(DotTemplateExp) isDotTemplateExp() { return op == EXP.dotTemplateDeclaration ? cast(typeof(return))this : null; } 1761 inout(DotVarExp) isDotVarExp() { return op == EXP.dotVariable ? cast(typeof(return))this : null; } 1762 inout(DotTemplateInstanceExp) isDotTemplateInstanceExp() { return op == EXP.dotTemplateInstance ? cast(typeof(return))this : null; } 1763 inout(DelegateExp) isDelegateExp() { return op == EXP.delegate_ ? cast(typeof(return))this : null; } 1764 inout(DotTypeExp) isDotTypeExp() { return op == EXP.dotType ? cast(typeof(return))this : null; } 1765 inout(CallExp) isCallExp() { return op == EXP.call ? cast(typeof(return))this : null; } 1766 inout(AddrExp) isAddrExp() { return op == EXP.address ? cast(typeof(return))this : null; } 1767 inout(PtrExp) isPtrExp() { return op == EXP.star ? cast(typeof(return))this : null; } 1768 inout(NegExp) isNegExp() { return op == EXP.negate ? cast(typeof(return))this : null; } 1769 inout(UAddExp) isUAddExp() { return op == EXP.uadd ? cast(typeof(return))this : null; } 1770 inout(ComExp) isComExp() { return op == EXP.tilde ? cast(typeof(return))this : null; } 1771 inout(NotExp) isNotExp() { return op == EXP.not ? cast(typeof(return))this : null; } 1772 inout(DeleteExp) isDeleteExp() { return op == EXP.delete_ ? cast(typeof(return))this : null; } 1773 inout(CastExp) isCastExp() { return op == EXP.cast_ ? cast(typeof(return))this : null; } 1774 inout(VectorExp) isVectorExp() { return op == EXP.vector ? cast(typeof(return))this : null; } 1775 inout(VectorArrayExp) isVectorArrayExp() { return op == EXP.vectorArray ? cast(typeof(return))this : null; } 1776 inout(SliceExp) isSliceExp() { return op == EXP.slice ? cast(typeof(return))this : null; } 1777 inout(ArrayLengthExp) isArrayLengthExp() { return op == EXP.arrayLength ? cast(typeof(return))this : null; } 1778 inout(ArrayExp) isArrayExp() { return op == EXP.array ? cast(typeof(return))this : null; } 1779 inout(DotExp) isDotExp() { return op == EXP.dot ? cast(typeof(return))this : null; } 1780 inout(CommaExp) isCommaExp() { return op == EXP.comma ? cast(typeof(return))this : null; } 1781 inout(IntervalExp) isIntervalExp() { return op == EXP.interval ? cast(typeof(return))this : null; } 1782 inout(DelegatePtrExp) isDelegatePtrExp() { return op == EXP.delegatePointer ? cast(typeof(return))this : null; } 1783 inout(DelegateFuncptrExp) isDelegateFuncptrExp() { return op == EXP.delegateFunctionPointer ? cast(typeof(return))this : null; } 1784 inout(IndexExp) isIndexExp() { return op == EXP.index ? cast(typeof(return))this : null; } 1785 inout(PostExp) isPostExp() { return (op == EXP.plusPlus || op == EXP.minusMinus) ? cast(typeof(return))this : null; } 1786 inout(PreExp) isPreExp() { return (op == EXP.prePlusPlus || op == EXP.preMinusMinus) ? cast(typeof(return))this : null; } 1787 inout(AssignExp) isAssignExp() { return op == EXP.assign ? cast(typeof(return))this : null; } 1788 inout(LoweredAssignExp) isLoweredAssignExp() { return op == EXP.loweredAssignExp ? cast(typeof(return))this : null; } 1789 inout(ConstructExp) isConstructExp() { return op == EXP.construct ? cast(typeof(return))this : null; } 1790 inout(BlitExp) isBlitExp() { return op == EXP.blit ? cast(typeof(return))this : null; } 1791 inout(AddAssignExp) isAddAssignExp() { return op == EXP.addAssign ? cast(typeof(return))this : null; } 1792 inout(MinAssignExp) isMinAssignExp() { return op == EXP.minAssign ? cast(typeof(return))this : null; } 1793 inout(MulAssignExp) isMulAssignExp() { return op == EXP.mulAssign ? cast(typeof(return))this : null; } 1794 1795 inout(DivAssignExp) isDivAssignExp() { return op == EXP.divAssign ? cast(typeof(return))this : null; } 1796 inout(ModAssignExp) isModAssignExp() { return op == EXP.modAssign ? cast(typeof(return))this : null; } 1797 inout(AndAssignExp) isAndAssignExp() { return op == EXP.andAssign ? cast(typeof(return))this : null; } 1798 inout(OrAssignExp) isOrAssignExp() { return op == EXP.orAssign ? cast(typeof(return))this : null; } 1799 inout(XorAssignExp) isXorAssignExp() { return op == EXP.xorAssign ? cast(typeof(return))this : null; } 1800 inout(PowAssignExp) isPowAssignExp() { return op == EXP.powAssign ? cast(typeof(return))this : null; } 1801 1802 inout(ShlAssignExp) isShlAssignExp() { return op == EXP.leftShiftAssign ? cast(typeof(return))this : null; } 1803 inout(ShrAssignExp) isShrAssignExp() { return op == EXP.rightShiftAssign ? cast(typeof(return))this : null; } 1804 inout(UshrAssignExp) isUshrAssignExp() { return op == EXP.unsignedRightShiftAssign ? cast(typeof(return))this : null; } 1805 1806 inout(CatAssignExp) isCatAssignExp() { return op == EXP.concatenateAssign 1807 ? cast(typeof(return))this 1808 : null; } 1809 1810 inout(CatElemAssignExp) isCatElemAssignExp() { return op == EXP.concatenateElemAssign 1811 ? cast(typeof(return))this 1812 : null; } 1813 1814 inout(CatDcharAssignExp) isCatDcharAssignExp() { return op == EXP.concatenateDcharAssign 1815 ? cast(typeof(return))this 1816 : null; } 1817 1818 inout(AddExp) isAddExp() { return op == EXP.add ? cast(typeof(return))this : null; } 1819 inout(MinExp) isMinExp() { return op == EXP.min ? cast(typeof(return))this : null; } 1820 inout(CatExp) isCatExp() { return op == EXP.concatenate ? cast(typeof(return))this : null; } 1821 inout(MulExp) isMulExp() { return op == EXP.mul ? cast(typeof(return))this : null; } 1822 inout(DivExp) isDivExp() { return op == EXP.div ? cast(typeof(return))this : null; } 1823 inout(ModExp) isModExp() { return op == EXP.mod ? cast(typeof(return))this : null; } 1824 inout(PowExp) isPowExp() { return op == EXP.pow ? cast(typeof(return))this : null; } 1825 inout(ShlExp) isShlExp() { return op == EXP.leftShift ? cast(typeof(return))this : null; } 1826 inout(ShrExp) isShrExp() { return op == EXP.rightShift ? cast(typeof(return))this : null; } 1827 inout(UshrExp) isUshrExp() { return op == EXP.unsignedRightShift ? cast(typeof(return))this : null; } 1828 inout(AndExp) isAndExp() { return op == EXP.and ? cast(typeof(return))this : null; } 1829 inout(OrExp) isOrExp() { return op == EXP.or ? cast(typeof(return))this : null; } 1830 inout(XorExp) isXorExp() { return op == EXP.xor ? cast(typeof(return))this : null; } 1831 inout(LogicalExp) isLogicalExp() { return (op == EXP.andAnd || op == EXP.orOr) ? cast(typeof(return))this : null; } 1832 //inout(CmpExp) isCmpExp() { return op == EXP. ? cast(typeof(return))this : null; } 1833 inout(InExp) isInExp() { return op == EXP.in_ ? cast(typeof(return))this : null; } 1834 inout(RemoveExp) isRemoveExp() { return op == EXP.remove ? cast(typeof(return))this : null; } 1835 inout(EqualExp) isEqualExp() { return (op == EXP.equal || op == EXP.notEqual) ? cast(typeof(return))this : null; } 1836 inout(IdentityExp) isIdentityExp() { return (op == EXP.identity || op == EXP.notIdentity) ? cast(typeof(return))this : null; } 1837 inout(CondExp) isCondExp() { return op == EXP.question ? cast(typeof(return))this : null; } 1838 inout(GenericExp) isGenericExp() { return op == EXP._Generic ? cast(typeof(return))this : null; } 1839 inout(DefaultInitExp) isDefaultInitExp() { return isDefaultInitOp(op) ? cast(typeof(return))this: null; } 1840 inout(FileInitExp) isFileInitExp() { return (op == EXP.file || op == EXP.fileFullPath) ? cast(typeof(return))this : null; } 1841 inout(LineInitExp) isLineInitExp() { return op == EXP.line ? cast(typeof(return))this : null; } 1842 inout(ModuleInitExp) isModuleInitExp() { return op == EXP.moduleString ? cast(typeof(return))this : null; } 1843 inout(FuncInitExp) isFuncInitExp() { return op == EXP.functionString ? cast(typeof(return))this : null; } 1844 inout(PrettyFuncInitExp) isPrettyFuncInitExp() { return op == EXP.prettyFunction ? cast(typeof(return))this : null; } 1845 inout(ObjcClassReferenceExp) isObjcClassReferenceExp() { return op == EXP.objcClassReference ? cast(typeof(return))this : null; } 1846 inout(ClassReferenceExp) isClassReferenceExp() { return op == EXP.classReference ? cast(typeof(return))this : null; } 1847 inout(ThrownExceptionExp) isThrownExceptionExp() { return op == EXP.thrownException ? cast(typeof(return))this : null; } 1848 1849 inout(UnaExp) isUnaExp() pure inout nothrow @nogc 1850 { 1851 return exptab[op] & EXPFLAGS.unary ? cast(typeof(return))this : null; 1852 } 1853 1854 inout(BinExp) isBinExp() pure inout nothrow @nogc 1855 { 1856 return exptab[op] & EXPFLAGS.binary ? cast(typeof(return))this : null; 1857 } 1858 1859 inout(BinAssignExp) isBinAssignExp() pure inout nothrow @nogc 1860 { 1861 return exptab[op] & EXPFLAGS.binaryAssign ? cast(typeof(return))this : null; 1862 } 1863 } 1864 1865 override void accept(Visitor v) 1866 { 1867 v.visit(this); 1868 } 1869 } 1870 1871 /*********************************************************** 1872 * A compile-time known integer value 1873 */ 1874 extern (C++) final class IntegerExp : Expression 1875 { 1876 private dinteger_t value; 1877 1878 extern (D) this(const ref Loc loc, dinteger_t value, Type type) 1879 { 1880 super(loc, EXP.int64); 1881 //printf("IntegerExp(value = %lld, type = '%s')\n", value, type ? type.toChars() : ""); 1882 assert(type); 1883 if (!type.isscalar()) 1884 { 1885 //printf("%s, loc = %d\n", toChars(), loc.linnum); 1886 if (type.ty != Terror) 1887 error("integral constant must be scalar type, not `%s`", type.toChars()); 1888 type = Type.terror; 1889 } 1890 this.type = type; 1891 this.value = normalize(type.toBasetype().ty, value); 1892 } 1893 1894 extern (D) this(dinteger_t value) 1895 { 1896 super(Loc.initial, EXP.int64); 1897 this.type = Type.tint32; 1898 this.value = cast(int)value; 1899 } 1900 1901 static IntegerExp create(const ref Loc loc, dinteger_t value, Type type) 1902 { 1903 return new IntegerExp(loc, value, type); 1904 } 1905 1906 // Same as create, but doesn't allocate memory. 1907 static void emplace(UnionExp* pue, const ref Loc loc, dinteger_t value, Type type) 1908 { 1909 emplaceExp!(IntegerExp)(pue, loc, value, type); 1910 } 1911 1912 override bool equals(const RootObject o) const 1913 { 1914 if (this == o) 1915 return true; 1916 if (auto ne = (cast(Expression)o).isIntegerExp()) 1917 { 1918 if (type.toHeadMutable().equals(ne.type.toHeadMutable()) && value == ne.value) 1919 { 1920 return true; 1921 } 1922 } 1923 return false; 1924 } 1925 1926 override dinteger_t toInteger() 1927 { 1928 // normalize() is necessary until we fix all the paints of 'type' 1929 return value = normalize(type.toBasetype().ty, value); 1930 } 1931 1932 override real_t toReal() 1933 { 1934 // normalize() is necessary until we fix all the paints of 'type' 1935 const ty = type.toBasetype().ty; 1936 const val = normalize(ty, value); 1937 value = val; 1938 return (ty == Tuns64) 1939 ? real_t(cast(ulong)val) 1940 : real_t(cast(long)val); 1941 } 1942 1943 override real_t toImaginary() 1944 { 1945 return CTFloat.zero; 1946 } 1947 1948 override complex_t toComplex() 1949 { 1950 return complex_t(toReal()); 1951 } 1952 1953 override Optional!bool toBool() 1954 { 1955 bool r = toInteger() != 0; 1956 return typeof(return)(r); 1957 } 1958 1959 override Expression toLvalue(Scope* sc, Expression e) 1960 { 1961 if (!e) 1962 e = this; 1963 else if (!loc.isValid()) 1964 loc = e.loc; 1965 e.error("cannot modify constant `%s`", e.toChars()); 1966 return ErrorExp.get(); 1967 } 1968 1969 override void accept(Visitor v) 1970 { 1971 v.visit(this); 1972 } 1973 1974 dinteger_t getInteger() 1975 { 1976 return value; 1977 } 1978 1979 void setInteger(dinteger_t value) 1980 { 1981 this.value = normalize(type.toBasetype().ty, value); 1982 } 1983 1984 extern (D) static dinteger_t normalize(TY ty, dinteger_t value) 1985 { 1986 /* 'Normalize' the value of the integer to be in range of the type 1987 */ 1988 dinteger_t result; 1989 switch (ty) 1990 { 1991 case Tbool: 1992 result = (value != 0); 1993 break; 1994 1995 case Tint8: 1996 result = cast(byte)value; 1997 break; 1998 1999 case Tchar: 2000 case Tuns8: 2001 result = cast(ubyte)value; 2002 break; 2003 2004 case Tint16: 2005 result = cast(short)value; 2006 break; 2007 2008 case Twchar: 2009 case Tuns16: 2010 result = cast(ushort)value; 2011 break; 2012 2013 case Tint32: 2014 result = cast(int)value; 2015 break; 2016 2017 case Tdchar: 2018 case Tuns32: 2019 result = cast(uint)value; 2020 break; 2021 2022 case Tint64: 2023 result = cast(long)value; 2024 break; 2025 2026 case Tuns64: 2027 result = cast(ulong)value; 2028 break; 2029 2030 case Tpointer: 2031 if (target.ptrsize == 8) 2032 goto case Tuns64; 2033 if (target.ptrsize == 4) 2034 goto case Tuns32; 2035 if (target.ptrsize == 2) 2036 goto case Tuns16; 2037 assert(0); 2038 2039 default: 2040 break; 2041 } 2042 return result; 2043 } 2044 2045 override IntegerExp syntaxCopy() 2046 { 2047 return this; 2048 } 2049 2050 /** 2051 * Use this instead of creating new instances for commonly used literals 2052 * such as 0 or 1. 2053 * 2054 * Parameters: 2055 * v = The value of the expression 2056 * Returns: 2057 * A static instance of the expression, typed as `Tint32`. 2058 */ 2059 static IntegerExp literal(int v)() 2060 { 2061 __gshared IntegerExp theConstant; 2062 if (!theConstant) 2063 theConstant = new IntegerExp(v); 2064 return theConstant; 2065 } 2066 2067 /** 2068 * Use this instead of creating new instances for commonly used bools. 2069 * 2070 * Parameters: 2071 * b = The value of the expression 2072 * Returns: 2073 * A static instance of the expression, typed as `Type.tbool`. 2074 */ 2075 static IntegerExp createBool(bool b) 2076 { 2077 __gshared IntegerExp trueExp, falseExp; 2078 if (!trueExp) 2079 { 2080 trueExp = new IntegerExp(Loc.initial, 1, Type.tbool); 2081 falseExp = new IntegerExp(Loc.initial, 0, Type.tbool); 2082 } 2083 return b ? trueExp : falseExp; 2084 } 2085 } 2086 2087 /*********************************************************** 2088 * Use this expression for error recovery. 2089 * 2090 * It should behave as a 'sink' to prevent further cascaded error messages. 2091 */ 2092 extern (C++) final class ErrorExp : Expression 2093 { 2094 private extern (D) this() 2095 { 2096 super(Loc.initial, EXP.error); 2097 type = Type.terror; 2098 } 2099 2100 static ErrorExp get () 2101 { 2102 if (errorexp is null) 2103 errorexp = new ErrorExp(); 2104 2105 if (global.errors == 0 && global.gaggedErrors == 0) 2106 { 2107 /* Unfortunately, errors can still leak out of gagged errors, 2108 * and we need to set the error count to prevent bogus code 2109 * generation. At least give a message. 2110 */ 2111 .error(Loc.initial, "unknown, please file report on issues.dlang.org"); 2112 } 2113 2114 return errorexp; 2115 } 2116 2117 override Expression toLvalue(Scope* sc, Expression e) 2118 { 2119 return this; 2120 } 2121 2122 override void accept(Visitor v) 2123 { 2124 v.visit(this); 2125 } 2126 2127 extern (C++) __gshared ErrorExp errorexp; // handy shared value 2128 } 2129 2130 2131 /*********************************************************** 2132 * An uninitialized value, 2133 * generated from void initializers. 2134 * 2135 * https://dlang.org/spec/declaration.html#void_init 2136 */ 2137 extern (C++) final class VoidInitExp : Expression 2138 { 2139 VarDeclaration var; /// the variable from where the void value came from, null if not known 2140 /// Useful for error messages 2141 2142 extern (D) this(VarDeclaration var) 2143 { 2144 super(var.loc, EXP.void_); 2145 this.var = var; 2146 this.type = var.type; 2147 } 2148 2149 override const(char)* toChars() const 2150 { 2151 return "void"; 2152 } 2153 2154 override void accept(Visitor v) 2155 { 2156 v.visit(this); 2157 } 2158 } 2159 2160 2161 /*********************************************************** 2162 * A compile-time known floating point number 2163 */ 2164 extern (C++) final class RealExp : Expression 2165 { 2166 real_t value; 2167 2168 extern (D) this(const ref Loc loc, real_t value, Type type) 2169 { 2170 super(loc, EXP.float64); 2171 //printf("RealExp::RealExp(%Lg)\n", value); 2172 this.value = value; 2173 this.type = type; 2174 } 2175 2176 static RealExp create(const ref Loc loc, real_t value, Type type) 2177 { 2178 return new RealExp(loc, value, type); 2179 } 2180 2181 // Same as create, but doesn't allocate memory. 2182 static void emplace(UnionExp* pue, const ref Loc loc, real_t value, Type type) 2183 { 2184 emplaceExp!(RealExp)(pue, loc, value, type); 2185 } 2186 2187 override bool equals(const RootObject o) const 2188 { 2189 if (this == o) 2190 return true; 2191 if (auto ne = (cast(Expression)o).isRealExp()) 2192 { 2193 if (type.toHeadMutable().equals(ne.type.toHeadMutable()) && RealIdentical(value, ne.value)) 2194 { 2195 return true; 2196 } 2197 } 2198 return false; 2199 } 2200 2201 override bool isIdentical(const Expression e) const 2202 { 2203 if (!equals(e)) 2204 return false; 2205 return CTFloat.isIdentical(value, e.isRealExp().value); 2206 } 2207 2208 override dinteger_t toInteger() 2209 { 2210 return cast(sinteger_t)toReal(); 2211 } 2212 2213 override uinteger_t toUInteger() 2214 { 2215 return cast(uinteger_t)toReal(); 2216 } 2217 2218 override real_t toReal() 2219 { 2220 return type.isreal() ? value : CTFloat.zero; 2221 } 2222 2223 override real_t toImaginary() 2224 { 2225 return type.isreal() ? CTFloat.zero : value; 2226 } 2227 2228 override complex_t toComplex() 2229 { 2230 return complex_t(toReal(), toImaginary()); 2231 } 2232 2233 override Optional!bool toBool() 2234 { 2235 return typeof(return)(!!value); 2236 } 2237 2238 override void accept(Visitor v) 2239 { 2240 v.visit(this); 2241 } 2242 } 2243 2244 /*********************************************************** 2245 * A compile-time complex number (deprecated) 2246 */ 2247 extern (C++) final class ComplexExp : Expression 2248 { 2249 complex_t value; 2250 2251 extern (D) this(const ref Loc loc, complex_t value, Type type) 2252 { 2253 super(loc, EXP.complex80); 2254 this.value = value; 2255 this.type = type; 2256 //printf("ComplexExp::ComplexExp(%s)\n", toChars()); 2257 } 2258 2259 static ComplexExp create(const ref Loc loc, complex_t value, Type type) 2260 { 2261 return new ComplexExp(loc, value, type); 2262 } 2263 2264 // Same as create, but doesn't allocate memory. 2265 static void emplace(UnionExp* pue, const ref Loc loc, complex_t value, Type type) 2266 { 2267 emplaceExp!(ComplexExp)(pue, loc, value, type); 2268 } 2269 2270 override bool equals(const RootObject o) const 2271 { 2272 if (this == o) 2273 return true; 2274 if (auto ne = (cast(Expression)o).isComplexExp()) 2275 { 2276 if (type.toHeadMutable().equals(ne.type.toHeadMutable()) && RealIdentical(creall(value), creall(ne.value)) && RealIdentical(cimagl(value), cimagl(ne.value))) 2277 { 2278 return true; 2279 } 2280 } 2281 return false; 2282 } 2283 2284 override bool isIdentical(const Expression e) const 2285 { 2286 if (!equals(e)) 2287 return false; 2288 // equals() regards different NaN values as 'equals' 2289 auto c = e.isComplexExp(); 2290 return CTFloat.isIdentical(creall(value), creall(c.value)) && 2291 CTFloat.isIdentical(cimagl(value), cimagl(c.value)); 2292 } 2293 2294 override dinteger_t toInteger() 2295 { 2296 return cast(sinteger_t)toReal(); 2297 } 2298 2299 override uinteger_t toUInteger() 2300 { 2301 return cast(uinteger_t)toReal(); 2302 } 2303 2304 override real_t toReal() 2305 { 2306 return creall(value); 2307 } 2308 2309 override real_t toImaginary() 2310 { 2311 return cimagl(value); 2312 } 2313 2314 override complex_t toComplex() 2315 { 2316 return value; 2317 } 2318 2319 override Optional!bool toBool() 2320 { 2321 return typeof(return)(!!value); 2322 } 2323 2324 override void accept(Visitor v) 2325 { 2326 v.visit(this); 2327 } 2328 } 2329 2330 /*********************************************************** 2331 * An identifier in the context of an expression (as opposed to a declaration) 2332 * 2333 * --- 2334 * int x; // VarDeclaration with Identifier 2335 * x++; // PostExp with IdentifierExp 2336 * --- 2337 */ 2338 extern (C++) class IdentifierExp : Expression 2339 { 2340 Identifier ident; 2341 2342 extern (D) this(const ref Loc loc, Identifier ident) scope 2343 { 2344 super(loc, EXP.identifier); 2345 this.ident = ident; 2346 } 2347 2348 static IdentifierExp create(const ref Loc loc, Identifier ident) 2349 { 2350 return new IdentifierExp(loc, ident); 2351 } 2352 2353 override final bool isLvalue() 2354 { 2355 return true; 2356 } 2357 2358 override final Expression toLvalue(Scope* sc, Expression e) 2359 { 2360 return this; 2361 } 2362 2363 override void accept(Visitor v) 2364 { 2365 v.visit(this); 2366 } 2367 } 2368 2369 /*********************************************************** 2370 * The dollar operator used when indexing or slicing an array. E.g `a[$]`, `a[1 .. $]` etc. 2371 * 2372 * https://dlang.org/spec/arrays.html#array-length 2373 */ 2374 extern (C++) final class DollarExp : IdentifierExp 2375 { 2376 extern (D) this(const ref Loc loc) 2377 { 2378 super(loc, Id.dollar); 2379 } 2380 2381 override void accept(Visitor v) 2382 { 2383 v.visit(this); 2384 } 2385 } 2386 2387 /*********************************************************** 2388 * Won't be generated by parser. 2389 */ 2390 extern (C++) final class DsymbolExp : Expression 2391 { 2392 Dsymbol s; 2393 bool hasOverloads; 2394 2395 extern (D) this(const ref Loc loc, Dsymbol s, bool hasOverloads = true) 2396 { 2397 super(loc, EXP.dSymbol); 2398 this.s = s; 2399 this.hasOverloads = hasOverloads; 2400 } 2401 2402 override bool isLvalue() 2403 { 2404 return true; 2405 } 2406 2407 override Expression toLvalue(Scope* sc, Expression e) 2408 { 2409 return this; 2410 } 2411 2412 override void accept(Visitor v) 2413 { 2414 v.visit(this); 2415 } 2416 } 2417 2418 /*********************************************************** 2419 * https://dlang.org/spec/expression.html#this 2420 */ 2421 extern (C++) class ThisExp : Expression 2422 { 2423 VarDeclaration var; 2424 2425 extern (D) this(const ref Loc loc) 2426 { 2427 super(loc, EXP.this_); 2428 //printf("ThisExp::ThisExp() loc = %d\n", loc.linnum); 2429 } 2430 2431 this(const ref Loc loc, const EXP tok) 2432 { 2433 super(loc, tok); 2434 //printf("ThisExp::ThisExp() loc = %d\n", loc.linnum); 2435 } 2436 2437 override ThisExp syntaxCopy() 2438 { 2439 auto r = cast(ThisExp) super.syntaxCopy(); 2440 // require new semantic (possibly new `var` etc.) 2441 r.type = null; 2442 r.var = null; 2443 return r; 2444 } 2445 2446 override Optional!bool toBool() 2447 { 2448 // `this` is never null (what about structs?) 2449 return typeof(return)(true); 2450 } 2451 2452 override final bool isLvalue() 2453 { 2454 // Class `this` should be an rvalue; struct `this` should be an lvalue. 2455 return type.toBasetype().ty != Tclass; 2456 } 2457 2458 override final Expression toLvalue(Scope* sc, Expression e) 2459 { 2460 if (type.toBasetype().ty == Tclass) 2461 { 2462 // Class `this` is an rvalue; struct `this` is an lvalue. 2463 return Expression.toLvalue(sc, e); 2464 } 2465 return this; 2466 } 2467 2468 override void accept(Visitor v) 2469 { 2470 v.visit(this); 2471 } 2472 } 2473 2474 /*********************************************************** 2475 * https://dlang.org/spec/expression.html#super 2476 */ 2477 extern (C++) final class SuperExp : ThisExp 2478 { 2479 extern (D) this(const ref Loc loc) 2480 { 2481 super(loc, EXP.super_); 2482 } 2483 2484 override void accept(Visitor v) 2485 { 2486 v.visit(this); 2487 } 2488 } 2489 2490 /*********************************************************** 2491 * A compile-time known `null` value 2492 * 2493 * https://dlang.org/spec/expression.html#null 2494 */ 2495 extern (C++) final class NullExp : Expression 2496 { 2497 extern (D) this(const ref Loc loc, Type type = null) scope 2498 { 2499 super(loc, EXP.null_); 2500 this.type = type; 2501 } 2502 2503 override bool equals(const RootObject o) const 2504 { 2505 if (auto e = o.isExpression()) 2506 { 2507 if (e.op == EXP.null_ && type.equals(e.type)) 2508 { 2509 return true; 2510 } 2511 } 2512 return false; 2513 } 2514 2515 override Optional!bool toBool() 2516 { 2517 // null in any type is false 2518 return typeof(return)(false); 2519 } 2520 2521 override StringExp toStringExp() 2522 { 2523 if (implicitConvTo(Type.tstring)) 2524 { 2525 auto se = new StringExp(loc, (cast(char*)mem.xcalloc(1, 1))[0 .. 0]); 2526 se.type = Type.tstring; 2527 return se; 2528 } 2529 return null; 2530 } 2531 2532 override void accept(Visitor v) 2533 { 2534 v.visit(this); 2535 } 2536 } 2537 2538 /*********************************************************** 2539 * https://dlang.org/spec/expression.html#string_literals 2540 */ 2541 extern (C++) final class StringExp : Expression 2542 { 2543 char postfix = NoPostfix; // 'c', 'w', 'd' 2544 OwnedBy ownedByCtfe = OwnedBy.code; 2545 private union 2546 { 2547 char* string; // if sz == 1 2548 wchar* wstring; // if sz == 2 2549 dchar* dstring; // if sz == 4 2550 } // (const if ownedByCtfe == OwnedBy.code) 2551 size_t len; // number of code units 2552 ubyte sz = 1; // 1: char, 2: wchar, 4: dchar 2553 2554 /** 2555 * Whether the string literal's type is fixed 2556 * Example: 2557 * --- 2558 * wstring x = "abc"; // OK, string literal is flexible 2559 * wstring y = cast(string) "abc"; // Error: type was committed after cast 2560 * --- 2561 */ 2562 bool committed; 2563 2564 enum char NoPostfix = 0; 2565 2566 extern (D) this(const ref Loc loc, const(void)[] string) scope 2567 { 2568 super(loc, EXP.string_); 2569 this.string = cast(char*)string.ptr; // note that this.string should be const 2570 this.len = string.length; 2571 this.sz = 1; // work around LDC bug #1286 2572 } 2573 2574 extern (D) this(const ref Loc loc, const(void)[] string, size_t len, ubyte sz, char postfix = NoPostfix) scope 2575 { 2576 super(loc, EXP.string_); 2577 this.string = cast(char*)string.ptr; // note that this.string should be const 2578 this.len = len; 2579 this.sz = sz; 2580 this.postfix = postfix; 2581 } 2582 2583 static StringExp create(const ref Loc loc, const(char)* s) 2584 { 2585 return new StringExp(loc, s.toDString()); 2586 } 2587 2588 static StringExp create(const ref Loc loc, const(void)* string, size_t len) 2589 { 2590 return new StringExp(loc, string[0 .. len]); 2591 } 2592 2593 // Same as create, but doesn't allocate memory. 2594 static void emplace(UnionExp* pue, const ref Loc loc, const(char)* s) 2595 { 2596 emplaceExp!(StringExp)(pue, loc, s.toDString()); 2597 } 2598 2599 extern (D) static void emplace(UnionExp* pue, const ref Loc loc, const(void)[] string) 2600 { 2601 emplaceExp!(StringExp)(pue, loc, string); 2602 } 2603 2604 extern (D) static void emplace(UnionExp* pue, const ref Loc loc, const(void)[] string, size_t len, ubyte sz, char postfix) 2605 { 2606 emplaceExp!(StringExp)(pue, loc, string, len, sz, postfix); 2607 } 2608 2609 override bool equals(const RootObject o) const 2610 { 2611 //printf("StringExp::equals('%s') %s\n", o.toChars(), toChars()); 2612 if (auto e = o.isExpression()) 2613 { 2614 if (auto se = e.isStringExp()) 2615 { 2616 return compare(se) == 0; 2617 } 2618 } 2619 return false; 2620 } 2621 2622 /********************************** 2623 * Return the number of code units the string would be if it were re-encoded 2624 * as tynto. 2625 * Params: 2626 * tynto = code unit type of the target encoding 2627 * Returns: 2628 * number of code units 2629 */ 2630 size_t numberOfCodeUnits(int tynto = 0) const 2631 { 2632 int encSize; 2633 switch (tynto) 2634 { 2635 case 0: return len; 2636 case Tchar: encSize = 1; break; 2637 case Twchar: encSize = 2; break; 2638 case Tdchar: encSize = 4; break; 2639 default: 2640 assert(0); 2641 } 2642 if (sz == encSize) 2643 return len; 2644 2645 size_t result = 0; 2646 dchar c; 2647 2648 switch (sz) 2649 { 2650 case 1: 2651 for (size_t u = 0; u < len;) 2652 { 2653 if (const s = utf_decodeChar(string[0 .. len], u, c)) 2654 { 2655 error("%.*s", cast(int)s.length, s.ptr); 2656 return 0; 2657 } 2658 result += utf_codeLength(encSize, c); 2659 } 2660 break; 2661 2662 case 2: 2663 for (size_t u = 0; u < len;) 2664 { 2665 if (const s = utf_decodeWchar(wstring[0 .. len], u, c)) 2666 { 2667 error("%.*s", cast(int)s.length, s.ptr); 2668 return 0; 2669 } 2670 result += utf_codeLength(encSize, c); 2671 } 2672 break; 2673 2674 case 4: 2675 foreach (u; 0 .. len) 2676 { 2677 result += utf_codeLength(encSize, dstring[u]); 2678 } 2679 break; 2680 2681 default: 2682 assert(0); 2683 } 2684 return result; 2685 } 2686 2687 /********************************************** 2688 * Write the contents of the string to dest. 2689 * Use numberOfCodeUnits() to determine size of result. 2690 * Params: 2691 * dest = destination 2692 * tyto = encoding type of the result 2693 * zero = add terminating 0 2694 */ 2695 void writeTo(void* dest, bool zero, int tyto = 0) const 2696 { 2697 int encSize; 2698 switch (tyto) 2699 { 2700 case 0: encSize = sz; break; 2701 case Tchar: encSize = 1; break; 2702 case Twchar: encSize = 2; break; 2703 case Tdchar: encSize = 4; break; 2704 default: 2705 assert(0); 2706 } 2707 if (sz == encSize) 2708 { 2709 memcpy(dest, string, len * sz); 2710 if (zero) 2711 memset(dest + len * sz, 0, sz); 2712 } 2713 else 2714 assert(0); 2715 } 2716 2717 /********************************************* 2718 * Get the code unit at index i 2719 * Params: 2720 * i = index 2721 * Returns: 2722 * code unit at index i 2723 */ 2724 dchar getCodeUnit(size_t i) const pure 2725 { 2726 assert(i < len); 2727 final switch (sz) 2728 { 2729 case 1: 2730 return string[i]; 2731 case 2: 2732 return wstring[i]; 2733 case 4: 2734 return dstring[i]; 2735 } 2736 } 2737 2738 /********************************************* 2739 * Set the code unit at index i to c 2740 * Params: 2741 * i = index 2742 * c = code unit to set it to 2743 */ 2744 void setCodeUnit(size_t i, dchar c) 2745 { 2746 assert(i < len); 2747 final switch (sz) 2748 { 2749 case 1: 2750 string[i] = cast(char)c; 2751 break; 2752 case 2: 2753 wstring[i] = cast(wchar)c; 2754 break; 2755 case 4: 2756 dstring[i] = c; 2757 break; 2758 } 2759 } 2760 2761 override StringExp toStringExp() 2762 { 2763 return this; 2764 } 2765 2766 /**************************************** 2767 * Convert string to char[]. 2768 */ 2769 StringExp toUTF8(Scope* sc) 2770 { 2771 if (sz != 1) 2772 { 2773 // Convert to UTF-8 string 2774 committed = false; 2775 Expression e = castTo(sc, Type.tchar.arrayOf()); 2776 e = e.optimize(WANTvalue); 2777 auto se = e.isStringExp(); 2778 assert(se.sz == 1); 2779 return se; 2780 } 2781 return this; 2782 } 2783 2784 /** 2785 * Compare two `StringExp` by length, then value 2786 * 2787 * The comparison is not the usual C-style comparison as seen with 2788 * `strcmp` or `memcmp`, but instead first compare based on the length. 2789 * This allows both faster lookup and sorting when comparing sparse data. 2790 * 2791 * This ordering scheme is relied on by the string-switching feature. 2792 * Code in Druntime's `core.internal.switch_` relies on this ordering 2793 * when doing a binary search among case statements. 2794 * 2795 * Both `StringExp` should be of the same encoding. 2796 * 2797 * Params: 2798 * se2 = String expression to compare `this` to 2799 * 2800 * Returns: 2801 * `0` when `this` is equal to se2, a value greater than `0` if 2802 * `this` should be considered greater than `se2`, 2803 * and a value less than `0` if `this` is lesser than `se2`. 2804 */ 2805 int compare(const StringExp se2) const nothrow pure @nogc 2806 { 2807 //printf("StringExp::compare()\n"); 2808 const len1 = len; 2809 const len2 = se2.len; 2810 2811 assert(this.sz == se2.sz, "Comparing string expressions of different sizes"); 2812 //printf("sz = %d, len1 = %d, len2 = %d\n", sz, cast(int)len1, cast(int)len2); 2813 if (len1 == len2) 2814 { 2815 switch (sz) 2816 { 2817 case 1: 2818 return memcmp(string, se2..string, len1); 2819 2820 case 2: 2821 { 2822 wchar* s1 = cast(wchar*)string; 2823 wchar* s2 = cast(wchar*)se2..string; 2824 foreach (u; 0 .. len) 2825 { 2826 if (s1[u] != s2[u]) 2827 return s1[u] - s2[u]; 2828 } 2829 } 2830 break; 2831 case 4: 2832 { 2833 dchar* s1 = cast(dchar*)string; 2834 dchar* s2 = cast(dchar*)se2..string; 2835 foreach (u; 0 .. len) 2836 { 2837 if (s1[u] != s2[u]) 2838 return s1[u] - s2[u]; 2839 } 2840 } 2841 break; 2842 default: 2843 assert(0); 2844 } 2845 } 2846 return cast(int)(len1 - len2); 2847 } 2848 2849 override Optional!bool toBool() 2850 { 2851 // Keep the old behaviour for this refactoring 2852 // Should probably match language spec instead and check for length 2853 return typeof(return)(true); 2854 } 2855 2856 override bool isLvalue() 2857 { 2858 /* string literal is rvalue in default, but 2859 * conversion to reference of static array is only allowed. 2860 */ 2861 return (type && type.toBasetype().ty == Tsarray); 2862 } 2863 2864 override Expression toLvalue(Scope* sc, Expression e) 2865 { 2866 //printf("StringExp::toLvalue(%s) type = %s\n", toChars(), type ? type.toChars() : NULL); 2867 return (type && type.toBasetype().ty == Tsarray) ? this : Expression.toLvalue(sc, e); 2868 } 2869 2870 override Expression modifiableLvalue(Scope* sc, Expression e) 2871 { 2872 error("cannot modify string literal `%s`", toChars()); 2873 return ErrorExp.get(); 2874 } 2875 2876 /******************************** 2877 * Convert string contents to a 0 terminated string, 2878 * allocated by mem.xmalloc(). 2879 */ 2880 extern (D) const(char)[] toStringz() const 2881 { 2882 auto nbytes = len * sz; 2883 char* s = cast(char*)mem.xmalloc(nbytes + sz); 2884 writeTo(s, true); 2885 return s[0 .. nbytes]; 2886 } 2887 2888 extern (D) const(char)[] peekString() const 2889 { 2890 assert(sz == 1); 2891 return this.string[0 .. len]; 2892 } 2893 2894 extern (D) const(wchar)[] peekWstring() const 2895 { 2896 assert(sz == 2); 2897 return this.wstring[0 .. len]; 2898 } 2899 2900 extern (D) const(dchar)[] peekDstring() const 2901 { 2902 assert(sz == 4); 2903 return this.dstring[0 .. len]; 2904 } 2905 2906 /******************* 2907 * Get a slice of the data. 2908 */ 2909 extern (D) const(ubyte)[] peekData() const 2910 { 2911 return cast(const(ubyte)[])this.string[0 .. len * sz]; 2912 } 2913 2914 /******************* 2915 * Borrow a slice of the data, so the caller can modify 2916 * it in-place (!) 2917 */ 2918 extern (D) ubyte[] borrowData() 2919 { 2920 return cast(ubyte[])this.string[0 .. len * sz]; 2921 } 2922 2923 /*********************** 2924 * Set new string data. 2925 * `this` becomes the new owner of the data. 2926 */ 2927 extern (D) void setData(void* s, size_t len, ubyte sz) 2928 { 2929 this.string = cast(char*)s; 2930 this.len = len; 2931 this.sz = sz; 2932 } 2933 2934 override void accept(Visitor v) 2935 { 2936 v.visit(this); 2937 } 2938 } 2939 2940 /*********************************************************** 2941 * A sequence of expressions 2942 * 2943 * --- 2944 * alias AliasSeq(T...) = T; 2945 * alias Tup = AliasSeq!(3, int, "abc"); 2946 * --- 2947 */ 2948 extern (C++) final class TupleExp : Expression 2949 { 2950 /* Tuple-field access may need to take out its side effect part. 2951 * For example: 2952 * foo().tupleof 2953 * is rewritten as: 2954 * (ref __tup = foo(); tuple(__tup.field0, __tup.field1, ...)) 2955 * The declaration of temporary variable __tup will be stored in TupleExp.e0. 2956 */ 2957 Expression e0; 2958 2959 Expressions* exps; 2960 2961 extern (D) this(const ref Loc loc, Expression e0, Expressions* exps) 2962 { 2963 super(loc, EXP.tuple); 2964 //printf("TupleExp(this = %p)\n", this); 2965 this.e0 = e0; 2966 this.exps = exps; 2967 } 2968 2969 extern (D) this(const ref Loc loc, Expressions* exps) 2970 { 2971 super(loc, EXP.tuple); 2972 //printf("TupleExp(this = %p)\n", this); 2973 this.exps = exps; 2974 } 2975 2976 extern (D) this(const ref Loc loc, TupleDeclaration tup) 2977 { 2978 super(loc, EXP.tuple); 2979 this.exps = new Expressions(); 2980 2981 this.exps.reserve(tup.objects.length); 2982 foreach (o; *tup.objects) 2983 { 2984 if (Dsymbol s = getDsymbol(o)) 2985 { 2986 /* If tuple element represents a symbol, translate to DsymbolExp 2987 * to supply implicit 'this' if needed later. 2988 */ 2989 Expression e = new DsymbolExp(loc, s); 2990 this.exps.push(e); 2991 } 2992 else if (auto eo = o.isExpression()) 2993 { 2994 auto e = eo.copy(); 2995 e.loc = loc; // https://issues.dlang.org/show_bug.cgi?id=15669 2996 this.exps.push(e); 2997 } 2998 else if (auto t = o.isType()) 2999 { 3000 Expression e = new TypeExp(loc, t); 3001 this.exps.push(e); 3002 } 3003 else 3004 { 3005 error("`%s` is not an expression", o.toChars()); 3006 } 3007 } 3008 } 3009 3010 static TupleExp create(const ref Loc loc, Expressions* exps) 3011 { 3012 return new TupleExp(loc, exps); 3013 } 3014 3015 override TupleExp syntaxCopy() 3016 { 3017 return new TupleExp(loc, e0 ? e0.syntaxCopy() : null, arraySyntaxCopy(exps)); 3018 } 3019 3020 override bool equals(const RootObject o) const 3021 { 3022 if (this == o) 3023 return true; 3024 if (auto e = o.isExpression()) 3025 if (auto te = e.isTupleExp()) 3026 { 3027 if (exps.length != te.exps.length) 3028 return false; 3029 if (e0 && !e0.equals(te.e0) || !e0 && te.e0) 3030 return false; 3031 foreach (i, e1; *exps) 3032 { 3033 auto e2 = (*te.exps)[i]; 3034 if (!e1.equals(e2)) 3035 return false; 3036 } 3037 return true; 3038 } 3039 return false; 3040 } 3041 3042 override void accept(Visitor v) 3043 { 3044 v.visit(this); 3045 } 3046 } 3047 3048 /*********************************************************** 3049 * [ e1, e2, e3, ... ] 3050 * 3051 * https://dlang.org/spec/expression.html#array_literals 3052 */ 3053 extern (C++) final class ArrayLiteralExp : Expression 3054 { 3055 OwnedBy ownedByCtfe = OwnedBy.code; 3056 bool onstack = false; 3057 3058 /** If !is null, elements[] can be sparse and basis is used for the 3059 * "default" element value. In other words, non-null elements[i] overrides 3060 * this 'basis' value. 3061 */ 3062 Expression basis; 3063 3064 Expressions* elements; 3065 3066 extern (D) this(const ref Loc loc, Type type, Expressions* elements) 3067 { 3068 super(loc, EXP.arrayLiteral); 3069 this.type = type; 3070 this.elements = elements; 3071 } 3072 3073 extern (D) this(const ref Loc loc, Type type, Expression e) 3074 { 3075 super(loc, EXP.arrayLiteral); 3076 this.type = type; 3077 elements = new Expressions(); 3078 elements.push(e); 3079 } 3080 3081 extern (D) this(const ref Loc loc, Type type, Expression basis, Expressions* elements) 3082 { 3083 super(loc, EXP.arrayLiteral); 3084 this.type = type; 3085 this.basis = basis; 3086 this.elements = elements; 3087 } 3088 3089 static ArrayLiteralExp create(const ref Loc loc, Expressions* elements) 3090 { 3091 return new ArrayLiteralExp(loc, null, elements); 3092 } 3093 3094 // Same as create, but doesn't allocate memory. 3095 static void emplace(UnionExp* pue, const ref Loc loc, Expressions* elements) 3096 { 3097 emplaceExp!(ArrayLiteralExp)(pue, loc, null, elements); 3098 } 3099 3100 override ArrayLiteralExp syntaxCopy() 3101 { 3102 return new ArrayLiteralExp(loc, 3103 null, 3104 basis ? basis.syntaxCopy() : null, 3105 arraySyntaxCopy(elements)); 3106 } 3107 3108 override bool equals(const RootObject o) const 3109 { 3110 if (this == o) 3111 return true; 3112 auto e = o.isExpression(); 3113 if (!e) 3114 return false; 3115 if (auto ae = e.isArrayLiteralExp()) 3116 { 3117 if (elements.length != ae.elements.length) 3118 return false; 3119 if (elements.length == 0 && !type.equals(ae.type)) 3120 { 3121 return false; 3122 } 3123 3124 foreach (i, e1; *elements) 3125 { 3126 auto e2 = (*ae.elements)[i]; 3127 auto e1x = e1 ? e1 : basis; 3128 auto e2x = e2 ? e2 : ae.basis; 3129 3130 if (e1x != e2x && (!e1x || !e2x || !e1x.equals(e2x))) 3131 return false; 3132 } 3133 return true; 3134 } 3135 return false; 3136 } 3137 3138 Expression getElement(size_t i) 3139 { 3140 return this[i]; 3141 } 3142 3143 Expression opIndex(size_t i) 3144 { 3145 auto el = (*elements)[i]; 3146 return el ? el : basis; 3147 } 3148 3149 override Optional!bool toBool() 3150 { 3151 size_t dim = elements ? elements.length : 0; 3152 return typeof(return)(dim != 0); 3153 } 3154 3155 override StringExp toStringExp() 3156 { 3157 TY telem = type.nextOf().toBasetype().ty; 3158 if (telem.isSomeChar || (telem == Tvoid && (!elements || elements.length == 0))) 3159 { 3160 ubyte sz = 1; 3161 if (telem == Twchar) 3162 sz = 2; 3163 else if (telem == Tdchar) 3164 sz = 4; 3165 3166 OutBuffer buf; 3167 if (elements) 3168 { 3169 foreach (i; 0 .. elements.length) 3170 { 3171 auto ch = this[i]; 3172 if (ch.op != EXP.int64) 3173 return null; 3174 if (sz == 1) 3175 buf.writeByte(cast(uint)ch.toInteger()); 3176 else if (sz == 2) 3177 buf.writeword(cast(uint)ch.toInteger()); 3178 else 3179 buf.write4(cast(uint)ch.toInteger()); 3180 } 3181 } 3182 char prefix; 3183 if (sz == 1) 3184 { 3185 prefix = 'c'; 3186 buf.writeByte(0); 3187 } 3188 else if (sz == 2) 3189 { 3190 prefix = 'w'; 3191 buf.writeword(0); 3192 } 3193 else 3194 { 3195 prefix = 'd'; 3196 buf.write4(0); 3197 } 3198 3199 const size_t len = buf.length / sz - 1; 3200 auto se = new StringExp(loc, buf.extractSlice()[0 .. len * sz], len, sz, prefix); 3201 se.sz = sz; 3202 se.type = type; 3203 return se; 3204 } 3205 return null; 3206 } 3207 3208 override void accept(Visitor v) 3209 { 3210 v.visit(this); 3211 } 3212 } 3213 3214 /*********************************************************** 3215 * [ key0 : value0, key1 : value1, ... ] 3216 * 3217 * https://dlang.org/spec/expression.html#associative_array_literals 3218 */ 3219 extern (C++) final class AssocArrayLiteralExp : Expression 3220 { 3221 OwnedBy ownedByCtfe = OwnedBy.code; 3222 3223 Expressions* keys; 3224 Expressions* values; 3225 3226 extern (D) this(const ref Loc loc, Expressions* keys, Expressions* values) 3227 { 3228 super(loc, EXP.assocArrayLiteral); 3229 assert(keys.length == values.length); 3230 this.keys = keys; 3231 this.values = values; 3232 } 3233 3234 override bool equals(const RootObject o) const 3235 { 3236 if (this == o) 3237 return true; 3238 auto e = o.isExpression(); 3239 if (!e) 3240 return false; 3241 if (auto ae = e.isAssocArrayLiteralExp()) 3242 { 3243 if (keys.length != ae.keys.length) 3244 return false; 3245 size_t count = 0; 3246 foreach (i, key; *keys) 3247 { 3248 foreach (j, akey; *ae.keys) 3249 { 3250 if (key.equals(akey)) 3251 { 3252 if (!(*values)[i].equals((*ae.values)[j])) 3253 return false; 3254 ++count; 3255 } 3256 } 3257 } 3258 return count == keys.length; 3259 } 3260 return false; 3261 } 3262 3263 override AssocArrayLiteralExp syntaxCopy() 3264 { 3265 return new AssocArrayLiteralExp(loc, arraySyntaxCopy(keys), arraySyntaxCopy(values)); 3266 } 3267 3268 override Optional!bool toBool() 3269 { 3270 size_t dim = keys.length; 3271 return typeof(return)(dim != 0); 3272 } 3273 3274 override void accept(Visitor v) 3275 { 3276 v.visit(this); 3277 } 3278 } 3279 3280 enum stageScrub = 0x1; /// scrubReturnValue is running 3281 enum stageSearchPointers = 0x2; /// hasNonConstPointers is running 3282 enum stageOptimize = 0x4; /// optimize is running 3283 enum stageApply = 0x8; /// apply is running 3284 enum stageInlineScan = 0x10; /// inlineScan is running 3285 enum stageToCBuffer = 0x20; /// toCBuffer is running 3286 3287 /*********************************************************** 3288 * sd( e1, e2, e3, ... ) 3289 */ 3290 extern (C++) final class StructLiteralExp : Expression 3291 { 3292 StructDeclaration sd; /// which aggregate this is for 3293 Expressions* elements; /// parallels sd.fields[] with null entries for fields to skip 3294 Type stype; /// final type of result (can be different from sd's type) 3295 3296 // `inlineCopy` is only used temporarily in the `inline.d` pass, 3297 // while `sym` is only used in `e2ir/s2ir/tocsym` which comes after 3298 union 3299 { 3300 Symbol* sym; /// back end symbol to initialize with literal 3301 3302 /// those fields need to prevent a infinite recursion when one field of struct initialized with 'this' pointer. 3303 StructLiteralExp inlinecopy; 3304 } 3305 3306 /** pointer to the origin instance of the expression. 3307 * once a new expression is created, origin is set to 'this'. 3308 * anytime when an expression copy is created, 'origin' pointer is set to 3309 * 'origin' pointer value of the original expression. 3310 */ 3311 StructLiteralExp origin; 3312 3313 3314 /** anytime when recursive function is calling, 'stageflags' marks with bit flag of 3315 * current stage and unmarks before return from this function. 3316 * 'inlinecopy' uses similar 'stageflags' and from multiple evaluation 'doInline' 3317 * (with infinite recursion) of this expression. 3318 */ 3319 ubyte stageflags; 3320 3321 bool useStaticInit; /// if this is true, use the StructDeclaration's init symbol 3322 bool isOriginal = false; /// used when moving instances to indicate `this is this.origin` 3323 OwnedBy ownedByCtfe = OwnedBy.code; 3324 3325 extern (D) this(const ref Loc loc, StructDeclaration sd, Expressions* elements, Type stype = null) 3326 { 3327 super(loc, EXP.structLiteral); 3328 this.sd = sd; 3329 if (!elements) 3330 elements = new Expressions(); 3331 this.elements = elements; 3332 this.stype = stype; 3333 this.origin = this; 3334 //printf("StructLiteralExp::StructLiteralExp(%s)\n", toChars()); 3335 } 3336 3337 static StructLiteralExp create(const ref Loc loc, StructDeclaration sd, void* elements, Type stype = null) 3338 { 3339 return new StructLiteralExp(loc, sd, cast(Expressions*)elements, stype); 3340 } 3341 3342 override bool equals(const RootObject o) const 3343 { 3344 if (this == o) 3345 return true; 3346 auto e = o.isExpression(); 3347 if (!e) 3348 return false; 3349 if (auto se = e.isStructLiteralExp()) 3350 { 3351 if (!type.equals(se.type)) 3352 return false; 3353 if (elements.length != se.elements.length) 3354 return false; 3355 foreach (i, e1; *elements) 3356 { 3357 auto e2 = (*se.elements)[i]; 3358 if (e1 != e2 && (!e1 || !e2 || !e1.equals(e2))) 3359 return false; 3360 } 3361 return true; 3362 } 3363 return false; 3364 } 3365 3366 override StructLiteralExp syntaxCopy() 3367 { 3368 auto exp = new StructLiteralExp(loc, sd, arraySyntaxCopy(elements), type ? type : stype); 3369 exp.origin = this; 3370 return exp; 3371 } 3372 3373 /************************************** 3374 * Gets expression at offset of type. 3375 * Returns NULL if not found. 3376 */ 3377 Expression getField(Type type, uint offset) 3378 { 3379 //printf("StructLiteralExp::getField(this = %s, type = %s, offset = %u)\n", 3380 // /*toChars()*/"", type.toChars(), offset); 3381 Expression e = null; 3382 int i = getFieldIndex(type, offset); 3383 3384 if (i != -1) 3385 { 3386 //printf("\ti = %d\n", i); 3387 if (i >= sd.nonHiddenFields()) 3388 return null; 3389 3390 assert(i < elements.length); 3391 e = (*elements)[i]; 3392 if (e) 3393 { 3394 //printf("e = %s, e.type = %s\n", e.toChars(), e.type.toChars()); 3395 3396 /* If type is a static array, and e is an initializer for that array, 3397 * then the field initializer should be an array literal of e. 3398 */ 3399 auto tsa = type.isTypeSArray(); 3400 if (tsa && e.type.castMod(0) != type.castMod(0)) 3401 { 3402 const length = cast(size_t)tsa.dim.toInteger(); 3403 auto z = new Expressions(length); 3404 foreach (ref q; *z) 3405 q = e.copy(); 3406 e = new ArrayLiteralExp(loc, type, z); 3407 } 3408 else 3409 { 3410 e = e.copy(); 3411 e.type = type; 3412 } 3413 if (useStaticInit && e.type.needsNested()) 3414 if (auto se = e.isStructLiteralExp()) 3415 { 3416 se.useStaticInit = true; 3417 } 3418 } 3419 } 3420 return e; 3421 } 3422 3423 /************************************ 3424 * Get index of field. 3425 * Returns -1 if not found. 3426 */ 3427 int getFieldIndex(Type type, uint offset) 3428 { 3429 /* Find which field offset is by looking at the field offsets 3430 */ 3431 if (elements.length) 3432 { 3433 const sz = type.size(); 3434 if (sz == SIZE_INVALID) 3435 return -1; 3436 foreach (i, v; sd.fields) 3437 { 3438 if (offset == v.offset && sz == v.type.size()) 3439 { 3440 /* context fields might not be filled. */ 3441 if (i >= sd.nonHiddenFields()) 3442 return cast(int)i; 3443 if (auto e = (*elements)[i]) 3444 { 3445 return cast(int)i; 3446 } 3447 break; 3448 } 3449 } 3450 } 3451 return -1; 3452 } 3453 3454 override Expression addDtorHook(Scope* sc) 3455 { 3456 /* If struct requires a destructor, rewrite as: 3457 * (S tmp = S()),tmp 3458 * so that the destructor can be hung on tmp. 3459 */ 3460 if (sd.dtor && sc.func) 3461 { 3462 /* Make an identifier for the temporary of the form: 3463 * __sl%s%d, where %s is the struct name 3464 */ 3465 char[10] buf = void; 3466 const prefix = "__sl"; 3467 const ident = sd.ident.toString; 3468 const fullLen = prefix.length + ident.length; 3469 const len = fullLen < buf.length ? fullLen : buf.length; 3470 buf[0 .. prefix.length] = prefix; 3471 buf[prefix.length .. len] = ident[0 .. len - prefix.length]; 3472 3473 auto tmp = copyToTemp(0, buf[0 .. len], this); 3474 Expression ae = new DeclarationExp(loc, tmp); 3475 Expression e = new CommaExp(loc, ae, new VarExp(loc, tmp)); 3476 e = e.expressionSemantic(sc); 3477 return e; 3478 } 3479 return this; 3480 } 3481 3482 override Expression toLvalue(Scope* sc, Expression e) 3483 { 3484 if (sc.flags & SCOPE.Cfile) 3485 return this; // C struct literals are lvalues 3486 else 3487 return Expression.toLvalue(sc, e); 3488 } 3489 3490 override void accept(Visitor v) 3491 { 3492 v.visit(this); 3493 } 3494 } 3495 3496 /*********************************************************** 3497 * C11 6.5.2.5 3498 * ( type-name ) { initializer-list } 3499 */ 3500 extern (C++) final class CompoundLiteralExp : Expression 3501 { 3502 Initializer initializer; /// initializer-list 3503 3504 extern (D) this(const ref Loc loc, Type type_name, Initializer initializer) 3505 { 3506 super(loc, EXP.compoundLiteral); 3507 super.type = type_name; 3508 this.initializer = initializer; 3509 //printf("CompoundLiteralExp::CompoundLiteralExp(%s)\n", toChars()); 3510 } 3511 3512 override void accept(Visitor v) 3513 { 3514 v.visit(this); 3515 } 3516 } 3517 3518 /*********************************************************** 3519 * Mainly just a placeholder 3520 */ 3521 extern (C++) final class TypeExp : Expression 3522 { 3523 extern (D) this(const ref Loc loc, Type type) 3524 { 3525 super(loc, EXP.type); 3526 //printf("TypeExp::TypeExp(%s)\n", type.toChars()); 3527 this.type = type; 3528 } 3529 3530 override TypeExp syntaxCopy() 3531 { 3532 return new TypeExp(loc, type.syntaxCopy()); 3533 } 3534 3535 override bool checkType() 3536 { 3537 error("type `%s` is not an expression", toChars()); 3538 return true; 3539 } 3540 3541 override bool checkValue() 3542 { 3543 error("type `%s` has no value", toChars()); 3544 return true; 3545 } 3546 3547 override void accept(Visitor v) 3548 { 3549 v.visit(this); 3550 } 3551 } 3552 3553 /*********************************************************** 3554 * Mainly just a placeholder of 3555 * Package, Module, Nspace, and TemplateInstance (including TemplateMixin) 3556 * 3557 * A template instance that requires IFTI: 3558 * foo!tiargs(fargs) // foo!tiargs 3559 * is left until CallExp::semantic() or resolveProperties() 3560 */ 3561 extern (C++) final class ScopeExp : Expression 3562 { 3563 ScopeDsymbol sds; 3564 3565 extern (D) this(const ref Loc loc, ScopeDsymbol sds) 3566 { 3567 super(loc, EXP.scope_); 3568 //printf("ScopeExp::ScopeExp(sds = '%s')\n", sds.toChars()); 3569 //static int count; if (++count == 38) *(char*)0=0; 3570 this.sds = sds; 3571 assert(!sds.isTemplateDeclaration()); // instead, you should use TemplateExp 3572 } 3573 3574 override ScopeExp syntaxCopy() 3575 { 3576 return new ScopeExp(loc, sds.syntaxCopy(null)); 3577 } 3578 3579 override bool checkType() 3580 { 3581 if (sds.isPackage()) 3582 { 3583 error("%s `%s` has no type", sds.kind(), sds.toChars()); 3584 return true; 3585 } 3586 if (auto ti = sds.isTemplateInstance()) 3587 { 3588 //assert(ti.needsTypeInference(sc)); 3589 if (ti.tempdecl && 3590 ti.semantictiargsdone && 3591 ti.semanticRun == PASS.initial) 3592 { 3593 error("partial %s `%s` has no type", sds.kind(), toChars()); 3594 return true; 3595 } 3596 } 3597 return false; 3598 } 3599 3600 override bool checkValue() 3601 { 3602 error("%s `%s` has no value", sds.kind(), sds.toChars()); 3603 return true; 3604 } 3605 3606 override void accept(Visitor v) 3607 { 3608 v.visit(this); 3609 } 3610 } 3611 3612 /*********************************************************** 3613 * Mainly just a placeholder 3614 */ 3615 extern (C++) final class TemplateExp : Expression 3616 { 3617 TemplateDeclaration td; 3618 FuncDeclaration fd; 3619 3620 extern (D) this(const ref Loc loc, TemplateDeclaration td, FuncDeclaration fd = null) 3621 { 3622 super(loc, EXP.template_); 3623 //printf("TemplateExp(): %s\n", td.toChars()); 3624 this.td = td; 3625 this.fd = fd; 3626 } 3627 3628 override bool isLvalue() 3629 { 3630 return fd !is null; 3631 } 3632 3633 override Expression toLvalue(Scope* sc, Expression e) 3634 { 3635 if (!fd) 3636 return Expression.toLvalue(sc, e); 3637 3638 assert(sc); 3639 return symbolToExp(fd, loc, sc, true); 3640 } 3641 3642 override bool checkType() 3643 { 3644 error("%s `%s` has no type", td.kind(), toChars()); 3645 return true; 3646 } 3647 3648 override bool checkValue() 3649 { 3650 error("%s `%s` has no value", td.kind(), toChars()); 3651 return true; 3652 } 3653 3654 override void accept(Visitor v) 3655 { 3656 v.visit(this); 3657 } 3658 } 3659 3660 /*********************************************************** 3661 * newtype(arguments) 3662 */ 3663 extern (C++) final class NewExp : Expression 3664 { 3665 Expression thisexp; // if !=null, 'this' for class being allocated 3666 Type newtype; 3667 Expressions* arguments; // Array of Expression's 3668 Identifiers* names; // Array of names corresponding to expressions 3669 3670 Expression argprefix; // expression to be evaluated just before arguments[] 3671 CtorDeclaration member; // constructor function 3672 bool onstack; // allocate on stack 3673 bool thrownew; // this NewExp is the expression of a ThrowStatement 3674 3675 Expression lowering; // lowered druntime hook: `_d_newclass` 3676 3677 /// Puts the `arguments` and `names` into an `ArgumentList` for easily passing them around. 3678 /// The fields are still separate for backwards compatibility 3679 extern (D) ArgumentList argumentList() { return ArgumentList(arguments, names); } 3680 3681 extern (D) this(const ref Loc loc, Expression thisexp, Type newtype, Expressions* arguments, Identifiers* names = null) 3682 { 3683 super(loc, EXP.new_); 3684 this.thisexp = thisexp; 3685 this.newtype = newtype; 3686 this.arguments = arguments; 3687 this.names = names; 3688 } 3689 3690 static NewExp create(const ref Loc loc, Expression thisexp, Type newtype, Expressions* arguments) 3691 { 3692 return new NewExp(loc, thisexp, newtype, arguments); 3693 } 3694 3695 override NewExp syntaxCopy() 3696 { 3697 return new NewExp(loc, 3698 thisexp ? thisexp.syntaxCopy() : null, 3699 newtype.syntaxCopy(), 3700 arraySyntaxCopy(arguments), 3701 names ? names.copy() : null); 3702 } 3703 3704 override void accept(Visitor v) 3705 { 3706 v.visit(this); 3707 } 3708 } 3709 3710 /*********************************************************** 3711 * class baseclasses { } (arguments) 3712 */ 3713 extern (C++) final class NewAnonClassExp : Expression 3714 { 3715 Expression thisexp; // if !=null, 'this' for class being allocated 3716 ClassDeclaration cd; // class being instantiated 3717 Expressions* arguments; // Array of Expression's to call class constructor 3718 3719 extern (D) this(const ref Loc loc, Expression thisexp, ClassDeclaration cd, Expressions* arguments) 3720 { 3721 super(loc, EXP.newAnonymousClass); 3722 this.thisexp = thisexp; 3723 this.cd = cd; 3724 this.arguments = arguments; 3725 } 3726 3727 override NewAnonClassExp syntaxCopy() 3728 { 3729 return new NewAnonClassExp(loc, thisexp ? thisexp.syntaxCopy() : null, cd.syntaxCopy(null), arraySyntaxCopy(arguments)); 3730 } 3731 3732 override void accept(Visitor v) 3733 { 3734 v.visit(this); 3735 } 3736 } 3737 3738 /*********************************************************** 3739 */ 3740 extern (C++) class SymbolExp : Expression 3741 { 3742 Declaration var; 3743 Dsymbol originalScope; // original scope before inlining 3744 bool hasOverloads; 3745 3746 extern (D) this(const ref Loc loc, EXP op, Declaration var, bool hasOverloads) 3747 { 3748 super(loc, op); 3749 assert(var); 3750 this.var = var; 3751 this.hasOverloads = hasOverloads; 3752 } 3753 3754 override void accept(Visitor v) 3755 { 3756 v.visit(this); 3757 } 3758 } 3759 3760 /*********************************************************** 3761 * Offset from symbol 3762 */ 3763 extern (C++) final class SymOffExp : SymbolExp 3764 { 3765 dinteger_t offset; 3766 3767 extern (D) this(const ref Loc loc, Declaration var, dinteger_t offset, bool hasOverloads = true) 3768 { 3769 if (auto v = var.isVarDeclaration()) 3770 { 3771 // FIXME: This error report will never be handled anyone. 3772 // It should be done before the SymOffExp construction. 3773 if (v.needThis()) 3774 .error(loc, "need `this` for address of `%s`", v.toChars()); 3775 hasOverloads = false; 3776 } 3777 super(loc, EXP.symbolOffset, var, hasOverloads); 3778 this.offset = offset; 3779 } 3780 3781 override Optional!bool toBool() 3782 { 3783 return typeof(return)(true); 3784 } 3785 3786 override void accept(Visitor v) 3787 { 3788 v.visit(this); 3789 } 3790 } 3791 3792 /*********************************************************** 3793 * Variable 3794 */ 3795 extern (C++) final class VarExp : SymbolExp 3796 { 3797 bool delegateWasExtracted; 3798 extern (D) this(const ref Loc loc, Declaration var, bool hasOverloads = true) 3799 { 3800 if (var.isVarDeclaration()) 3801 hasOverloads = false; 3802 3803 super(loc, EXP.variable, var, hasOverloads); 3804 //printf("VarExp(this = %p, '%s', loc = %s)\n", this, var.toChars(), loc.toChars()); 3805 //if (strcmp(var.ident.toChars(), "func") == 0) assert(0); 3806 this.type = var.type; 3807 } 3808 3809 static VarExp create(const ref Loc loc, Declaration var, bool hasOverloads = true) 3810 { 3811 return new VarExp(loc, var, hasOverloads); 3812 } 3813 3814 override bool equals(const RootObject o) const 3815 { 3816 if (this == o) 3817 return true; 3818 if (auto ne = o.isExpression().isVarExp()) 3819 { 3820 if (type.toHeadMutable().equals(ne.type.toHeadMutable()) && var == ne.var) 3821 { 3822 return true; 3823 } 3824 } 3825 return false; 3826 } 3827 3828 override bool isLvalue() 3829 { 3830 if (var.storage_class & (STC.lazy_ | STC.rvalue | STC.manifest)) 3831 return false; 3832 return true; 3833 } 3834 3835 override Expression toLvalue(Scope* sc, Expression e) 3836 { 3837 if (var.storage_class & STC.manifest) 3838 { 3839 error("manifest constant `%s` cannot be modified", var.toChars()); 3840 return ErrorExp.get(); 3841 } 3842 if (var.storage_class & STC.lazy_ && !delegateWasExtracted) 3843 { 3844 error("lazy variable `%s` cannot be modified", var.toChars()); 3845 return ErrorExp.get(); 3846 } 3847 if (var.ident == Id.ctfe) 3848 { 3849 error("cannot modify compiler-generated variable `__ctfe`"); 3850 return ErrorExp.get(); 3851 } 3852 if (var.ident == Id.dollar) // https://issues.dlang.org/show_bug.cgi?id=13574 3853 { 3854 error("cannot modify operator `$`"); 3855 return ErrorExp.get(); 3856 } 3857 return this; 3858 } 3859 3860 override Expression modifiableLvalue(Scope* sc, Expression e) 3861 { 3862 //printf("VarExp::modifiableLvalue('%s')\n", var.toChars()); 3863 if (var.storage_class & STC.manifest) 3864 { 3865 error("cannot modify manifest constant `%s`", toChars()); 3866 return ErrorExp.get(); 3867 } 3868 // See if this expression is a modifiable lvalue (i.e. not const) 3869 return Expression.modifiableLvalue(sc, e); 3870 } 3871 3872 override void accept(Visitor v) 3873 { 3874 v.visit(this); 3875 } 3876 } 3877 3878 /*********************************************************** 3879 * Overload Set 3880 */ 3881 extern (C++) final class OverExp : Expression 3882 { 3883 OverloadSet vars; 3884 3885 extern (D) this(const ref Loc loc, OverloadSet s) 3886 { 3887 super(loc, EXP.overloadSet); 3888 //printf("OverExp(this = %p, '%s')\n", this, var.toChars()); 3889 vars = s; 3890 type = Type.tvoid; 3891 } 3892 3893 override bool isLvalue() 3894 { 3895 return true; 3896 } 3897 3898 override Expression toLvalue(Scope* sc, Expression e) 3899 { 3900 return this; 3901 } 3902 3903 override void accept(Visitor v) 3904 { 3905 v.visit(this); 3906 } 3907 } 3908 3909 /*********************************************************** 3910 * Function/Delegate literal 3911 */ 3912 3913 extern (C++) final class FuncExp : Expression 3914 { 3915 FuncLiteralDeclaration fd; 3916 TemplateDeclaration td; 3917 TOK tok; // TOK.reserved, TOK.delegate_, TOK.function_ 3918 3919 extern (D) this(const ref Loc loc, Dsymbol s) 3920 { 3921 super(loc, EXP.function_); 3922 this.td = s.isTemplateDeclaration(); 3923 this.fd = s.isFuncLiteralDeclaration(); 3924 if (td) 3925 { 3926 assert(td.literal); 3927 assert(td.members && td.members.length == 1); 3928 fd = (*td.members)[0].isFuncLiteralDeclaration(); 3929 } 3930 tok = fd.tok; // save original kind of function/delegate/(infer) 3931 assert(fd.fbody); 3932 } 3933 3934 override bool equals(const RootObject o) const 3935 { 3936 if (this == o) 3937 return true; 3938 auto e = o.isExpression(); 3939 if (!e) 3940 return false; 3941 if (auto fe = e.isFuncExp()) 3942 { 3943 return fd == fe.fd; 3944 } 3945 return false; 3946 } 3947 3948 extern (D) void genIdent(Scope* sc) 3949 { 3950 if (fd.ident == Id.empty) 3951 { 3952 const(char)[] s; 3953 if (fd.fes) 3954 s = "__foreachbody"; 3955 else if (fd.tok == TOK.reserved) 3956 s = "__lambda"; 3957 else if (fd.tok == TOK.delegate_) 3958 s = "__dgliteral"; 3959 else 3960 s = "__funcliteral"; 3961 3962 DsymbolTable symtab; 3963 if (FuncDeclaration func = sc.parent.isFuncDeclaration()) 3964 { 3965 if (func.localsymtab is null) 3966 { 3967 // Inside template constraint, symtab is not set yet. 3968 // Initialize it lazily. 3969 func.localsymtab = new DsymbolTable(); 3970 } 3971 symtab = func.localsymtab; 3972 } 3973 else 3974 { 3975 ScopeDsymbol sds = sc.parent.isScopeDsymbol(); 3976 if (!sds.symtab) 3977 { 3978 // Inside template constraint, symtab may not be set yet. 3979 // Initialize it lazily. 3980 assert(sds.isTemplateInstance()); 3981 sds.symtab = new DsymbolTable(); 3982 } 3983 symtab = sds.symtab; 3984 } 3985 assert(symtab); 3986 Identifier id = Identifier.generateId(s, symtab.length() + 1); 3987 fd.ident = id; 3988 if (td) 3989 td.ident = id; 3990 symtab.insert(td ? cast(Dsymbol)td : cast(Dsymbol)fd); 3991 } 3992 } 3993 3994 override FuncExp syntaxCopy() 3995 { 3996 if (td) 3997 return new FuncExp(loc, td.syntaxCopy(null)); 3998 else if (fd.semanticRun == PASS.initial) 3999 return new FuncExp(loc, fd.syntaxCopy(null)); 4000 else // https://issues.dlang.org/show_bug.cgi?id=13481 4001 // Prevent multiple semantic analysis of lambda body. 4002 return new FuncExp(loc, fd); 4003 } 4004 4005 extern (D) MATCH matchType(Type to, Scope* sc, FuncExp* presult, int flag = 0) 4006 { 4007 4008 static MATCH cannotInfer(Expression e, Type to, int flag) 4009 { 4010 if (!flag) 4011 e.error("cannot infer parameter types from `%s`", to.toChars()); 4012 return MATCH.nomatch; 4013 } 4014 4015 //printf("FuncExp::matchType('%s'), to=%s\n", type ? type.toChars() : "null", to.toChars()); 4016 if (presult) 4017 *presult = null; 4018 4019 TypeFunction tof = null; 4020 if (to.ty == Tdelegate) 4021 { 4022 if (tok == TOK.function_) 4023 { 4024 if (!flag) 4025 error("cannot match function literal to delegate type `%s`", to.toChars()); 4026 return MATCH.nomatch; 4027 } 4028 tof = cast(TypeFunction)to.nextOf(); 4029 } 4030 else if (to.ty == Tpointer && (tof = to.nextOf().isTypeFunction()) !is null) 4031 { 4032 if (tok == TOK.delegate_) 4033 { 4034 if (!flag) 4035 error("cannot match delegate literal to function pointer type `%s`", to.toChars()); 4036 return MATCH.nomatch; 4037 } 4038 } 4039 4040 if (td) 4041 { 4042 if (!tof) 4043 { 4044 return cannotInfer(this, to, flag); 4045 } 4046 4047 // Parameter types inference from 'tof' 4048 assert(td._scope); 4049 TypeFunction tf = fd.type.isTypeFunction(); 4050 //printf("\ttof = %s\n", tof.toChars()); 4051 //printf("\ttf = %s\n", tf.toChars()); 4052 const dim = tf.parameterList.length; 4053 4054 if (tof.parameterList.length != dim || tof.parameterList.varargs != tf.parameterList.varargs) 4055 return cannotInfer(this, to, flag); 4056 4057 auto tiargs = new Objects(); 4058 tiargs.reserve(td.parameters.length); 4059 4060 foreach (tp; *td.parameters) 4061 { 4062 size_t u = 0; 4063 foreach (i, p; tf.parameterList) 4064 { 4065 if (auto ti = p.type.isTypeIdentifier()) 4066 if (ti && ti.ident == tp.ident) 4067 break; 4068 4069 ++u; 4070 } 4071 assert(u < dim); 4072 Parameter pto = tof.parameterList[u]; 4073 Type t = pto.type; 4074 if (t.ty == Terror) 4075 return cannotInfer(this, to, flag); 4076 tf.parameterList[u].storageClass = tof.parameterList[u].storageClass; 4077 tiargs.push(t); 4078 } 4079 4080 // Set target of return type inference 4081 if (!tf.next && tof.next) 4082 fd.treq = to; 4083 4084 auto ti = new TemplateInstance(loc, td, tiargs); 4085 Expression ex = (new ScopeExp(loc, ti)).expressionSemantic(td._scope); 4086 4087 // Reset inference target for the later re-semantic 4088 fd.treq = null; 4089 4090 if (ex.op == EXP.error) 4091 return MATCH.nomatch; 4092 if (auto ef = ex.isFuncExp()) 4093 return ef.matchType(to, sc, presult, flag); 4094 else 4095 return cannotInfer(this, to, flag); 4096 } 4097 4098 if (!tof || !tof.next) 4099 return MATCH.nomatch; 4100 4101 assert(type && type != Type.tvoid); 4102 if (fd.type.ty == Terror) 4103 return MATCH.nomatch; 4104 auto tfx = fd.type.isTypeFunction(); 4105 bool convertMatch = (type.ty != to.ty); 4106 4107 if (fd.inferRetType && tfx.next.implicitConvTo(tof.next) == MATCH.convert) 4108 { 4109 /* If return type is inferred and covariant return, 4110 * tweak return statements to required return type. 4111 * 4112 * interface I {} 4113 * class C : Object, I{} 4114 * 4115 * I delegate() dg = delegate() { return new class C(); } 4116 */ 4117 convertMatch = true; 4118 4119 auto tfy = new TypeFunction(tfx.parameterList, tof.next, 4120 tfx.linkage, STC.undefined_); 4121 tfy.mod = tfx.mod; 4122 tfy.trust = tfx.trust; 4123 tfy.isnothrow = tfx.isnothrow; 4124 tfy.isnogc = tfx.isnogc; 4125 tfy.purity = tfx.purity; 4126 tfy.isproperty = tfx.isproperty; 4127 tfy.isref = tfx.isref; 4128 tfy.isInOutParam = tfx.isInOutParam; 4129 tfy.isInOutQual = tfx.isInOutQual; 4130 tfy.deco = tfy.merge().deco; 4131 4132 tfx = tfy; 4133 } 4134 Type tx; 4135 if (tok == TOK.delegate_ || 4136 tok == TOK.reserved && (type.ty == Tdelegate || type.ty == Tpointer && to.ty == Tdelegate)) 4137 { 4138 // Allow conversion from implicit function pointer to delegate 4139 tx = new TypeDelegate(tfx); 4140 tx.deco = tx.merge().deco; 4141 } 4142 else 4143 { 4144 assert(tok == TOK.function_ || tok == TOK.reserved && type.ty == Tpointer || fd.errors); 4145 tx = tfx.pointerTo(); 4146 } 4147 //printf("\ttx = %s, to = %s\n", tx.toChars(), to.toChars()); 4148 4149 MATCH m = tx.implicitConvTo(to); 4150 if (m > MATCH.nomatch) 4151 { 4152 // MATCH.exact: exact type match 4153 // MATCH.constant: covairiant type match (eg. attributes difference) 4154 // MATCH.convert: context conversion 4155 m = convertMatch ? MATCH.convert : tx.equals(to) ? MATCH.exact : MATCH.constant; 4156 4157 if (presult) 4158 { 4159 (*presult) = cast(FuncExp)copy(); 4160 (*presult).type = to; 4161 4162 // https://issues.dlang.org/show_bug.cgi?id=12508 4163 // Tweak function body for covariant returns. 4164 (*presult).fd.modifyReturns(sc, tof.next); 4165 } 4166 } 4167 else if (!flag) 4168 { 4169 auto ts = toAutoQualChars(tx, to); 4170 error("cannot implicitly convert expression `%s` of type `%s` to `%s`", 4171 toChars(), ts[0], ts[1]); 4172 } 4173 return m; 4174 } 4175 4176 override const(char)* toChars() const 4177 { 4178 return fd.toChars(); 4179 } 4180 4181 override bool checkType() 4182 { 4183 if (td) 4184 { 4185 error("template lambda has no type"); 4186 return true; 4187 } 4188 return false; 4189 } 4190 4191 override bool checkValue() 4192 { 4193 if (td) 4194 { 4195 error("template lambda has no value"); 4196 return true; 4197 } 4198 return false; 4199 } 4200 4201 override void accept(Visitor v) 4202 { 4203 v.visit(this); 4204 } 4205 } 4206 4207 /*********************************************************** 4208 * Declaration of a symbol 4209 * 4210 * D grammar allows declarations only as statements. However in AST representation 4211 * it can be part of any expression. This is used, for example, during internal 4212 * syntax re-writes to inject hidden symbols. 4213 */ 4214 extern (C++) final class DeclarationExp : Expression 4215 { 4216 Dsymbol declaration; 4217 4218 extern (D) this(const ref Loc loc, Dsymbol declaration) 4219 { 4220 super(loc, EXP.declaration); 4221 this.declaration = declaration; 4222 } 4223 4224 override DeclarationExp syntaxCopy() 4225 { 4226 return new DeclarationExp(loc, declaration.syntaxCopy(null)); 4227 } 4228 4229 override bool hasCode() 4230 { 4231 if (auto vd = declaration.isVarDeclaration()) 4232 { 4233 return !(vd.storage_class & (STC.manifest | STC.static_)); 4234 } 4235 return false; 4236 } 4237 4238 override void accept(Visitor v) 4239 { 4240 v.visit(this); 4241 } 4242 } 4243 4244 /*********************************************************** 4245 * typeid(int) 4246 */ 4247 extern (C++) final class TypeidExp : Expression 4248 { 4249 RootObject obj; 4250 4251 extern (D) this(const ref Loc loc, RootObject o) 4252 { 4253 super(loc, EXP.typeid_); 4254 this.obj = o; 4255 } 4256 4257 override TypeidExp syntaxCopy() 4258 { 4259 return new TypeidExp(loc, objectSyntaxCopy(obj)); 4260 } 4261 4262 override void accept(Visitor v) 4263 { 4264 v.visit(this); 4265 } 4266 } 4267 4268 /*********************************************************** 4269 * __traits(identifier, args...) 4270 */ 4271 extern (C++) final class TraitsExp : Expression 4272 { 4273 Identifier ident; 4274 Objects* args; 4275 4276 extern (D) this(const ref Loc loc, Identifier ident, Objects* args) 4277 { 4278 super(loc, EXP.traits); 4279 this.ident = ident; 4280 this.args = args; 4281 } 4282 4283 override TraitsExp syntaxCopy() 4284 { 4285 return new TraitsExp(loc, ident, TemplateInstance.arraySyntaxCopy(args)); 4286 } 4287 4288 override void accept(Visitor v) 4289 { 4290 v.visit(this); 4291 } 4292 } 4293 4294 /*********************************************************** 4295 * Generates a halt instruction 4296 * 4297 * `assert(0)` gets rewritten to this with `CHECKACTION.halt` 4298 */ 4299 extern (C++) final class HaltExp : Expression 4300 { 4301 extern (D) this(const ref Loc loc) 4302 { 4303 super(loc, EXP.halt); 4304 } 4305 4306 override void accept(Visitor v) 4307 { 4308 v.visit(this); 4309 } 4310 } 4311 4312 /*********************************************************** 4313 * is(targ id tok tspec) 4314 * is(targ id == tok2) 4315 */ 4316 extern (C++) final class IsExp : Expression 4317 { 4318 Type targ; 4319 Identifier id; // can be null 4320 Type tspec; // can be null 4321 TemplateParameters* parameters; 4322 TOK tok; // ':' or '==' 4323 TOK tok2; // 'struct', 'union', etc. 4324 4325 extern (D) this(const ref Loc loc, Type targ, Identifier id, TOK tok, Type tspec, TOK tok2, TemplateParameters* parameters) scope 4326 { 4327 super(loc, EXP.is_); 4328 this.targ = targ; 4329 this.id = id; 4330 this.tok = tok; 4331 this.tspec = tspec; 4332 this.tok2 = tok2; 4333 this.parameters = parameters; 4334 } 4335 4336 override IsExp syntaxCopy() 4337 { 4338 // This section is identical to that in TemplateDeclaration::syntaxCopy() 4339 TemplateParameters* p = null; 4340 if (parameters) 4341 { 4342 p = new TemplateParameters(parameters.length); 4343 foreach (i, el; *parameters) 4344 (*p)[i] = el.syntaxCopy(); 4345 } 4346 return new IsExp(loc, targ.syntaxCopy(), id, tok, tspec ? tspec.syntaxCopy() : null, tok2, p); 4347 } 4348 4349 override void accept(Visitor v) 4350 { 4351 v.visit(this); 4352 } 4353 } 4354 4355 /*********************************************************** 4356 * Base class for unary operators 4357 * 4358 * https://dlang.org/spec/expression.html#unary-expression 4359 */ 4360 extern (C++) abstract class UnaExp : Expression 4361 { 4362 Expression e1; 4363 4364 extern (D) this(const ref Loc loc, EXP op, Expression e1) scope 4365 { 4366 super(loc, op); 4367 this.e1 = e1; 4368 } 4369 4370 override UnaExp syntaxCopy() 4371 { 4372 UnaExp e = cast(UnaExp)copy(); 4373 e.type = null; 4374 e.e1 = e.e1.syntaxCopy(); 4375 return e; 4376 } 4377 4378 /******************************** 4379 * The type for a unary expression is incompatible. 4380 * Print error message. 4381 * Returns: 4382 * ErrorExp 4383 */ 4384 final Expression incompatibleTypes() 4385 { 4386 if (e1.type.toBasetype() == Type.terror) 4387 return e1; 4388 4389 if (e1.op == EXP.type) 4390 { 4391 error("incompatible type for `%s(%s)`: cannot use `%s` with types", EXPtoString(op).ptr, e1.toChars(), EXPtoString(op).ptr); 4392 } 4393 else 4394 { 4395 error("incompatible type for `%s(%s)`: `%s`", EXPtoString(op).ptr, e1.toChars(), e1.type.toChars()); 4396 } 4397 return ErrorExp.get(); 4398 } 4399 4400 /********************* 4401 * Mark the operand as will never be dereferenced, 4402 * which is useful info for @safe checks. 4403 * Do before semantic() on operands rewrites them. 4404 */ 4405 final void setNoderefOperand() 4406 { 4407 if (auto edi = e1.isDotIdExp()) 4408 edi.noderef = true; 4409 4410 } 4411 4412 override final Expression resolveLoc(const ref Loc loc, Scope* sc) 4413 { 4414 e1 = e1.resolveLoc(loc, sc); 4415 return this; 4416 } 4417 4418 override void accept(Visitor v) 4419 { 4420 v.visit(this); 4421 } 4422 } 4423 4424 alias fp_t = UnionExp function(const ref Loc loc, Type, Expression, Expression); 4425 alias fp2_t = bool function(const ref Loc loc, EXP, Expression, Expression); 4426 4427 /*********************************************************** 4428 * Base class for binary operators 4429 */ 4430 extern (C++) abstract class BinExp : Expression 4431 { 4432 Expression e1; 4433 Expression e2; 4434 Type att1; // Save alias this type to detect recursion 4435 Type att2; // Save alias this type to detect recursion 4436 4437 extern (D) this(const ref Loc loc, EXP op, Expression e1, Expression e2) scope 4438 { 4439 super(loc, op); 4440 this.e1 = e1; 4441 this.e2 = e2; 4442 } 4443 4444 override BinExp syntaxCopy() 4445 { 4446 BinExp e = cast(BinExp)copy(); 4447 e.type = null; 4448 e.e1 = e.e1.syntaxCopy(); 4449 e.e2 = e.e2.syntaxCopy(); 4450 return e; 4451 } 4452 4453 /******************************** 4454 * The types for a binary expression are incompatible. 4455 * Print error message. 4456 * Returns: 4457 * ErrorExp 4458 */ 4459 final Expression incompatibleTypes() 4460 { 4461 if (e1.type.toBasetype() == Type.terror) 4462 return e1; 4463 if (e2.type.toBasetype() == Type.terror) 4464 return e2; 4465 4466 // CondExp uses 'a ? b : c' but we're comparing 'b : c' 4467 const(char)* thisOp = (op == EXP.question) ? ":" : EXPtoString(op).ptr; 4468 if (e1.op == EXP.type || e2.op == EXP.type) 4469 { 4470 error("incompatible types for `(%s) %s (%s)`: cannot use `%s` with types", 4471 e1.toChars(), thisOp, e2.toChars(), EXPtoString(op).ptr); 4472 } 4473 else if (e1.type.equals(e2.type)) 4474 { 4475 error("incompatible types for `(%s) %s (%s)`: both operands are of type `%s`", 4476 e1.toChars(), thisOp, e2.toChars(), e1.type.toChars()); 4477 } 4478 else 4479 { 4480 auto ts = toAutoQualChars(e1.type, e2.type); 4481 error("incompatible types for `(%s) %s (%s)`: `%s` and `%s`", 4482 e1.toChars(), thisOp, e2.toChars(), ts[0], ts[1]); 4483 } 4484 return ErrorExp.get(); 4485 } 4486 4487 extern (D) final Expression checkOpAssignTypes(Scope* sc) 4488 { 4489 // At that point t1 and t2 are the merged types. type is the original type of the lhs. 4490 Type t1 = e1.type; 4491 Type t2 = e2.type; 4492 4493 // T opAssign floating yields a floating. Prevent truncating conversions (float to int). 4494 // See issue 3841. 4495 // Should we also prevent double to float (type.isfloating() && type.size() < t2.size()) ? 4496 if (op == EXP.addAssign || op == EXP.minAssign || 4497 op == EXP.mulAssign || op == EXP.divAssign || op == EXP.modAssign || 4498 op == EXP.powAssign) 4499 { 4500 if ((type.isintegral() && t2.isfloating())) 4501 { 4502 warning("`%s %s %s` is performing truncating conversion", type.toChars(), EXPtoString(op).ptr, t2.toChars()); 4503 } 4504 } 4505 4506 // generate an error if this is a nonsensical *=,/=, or %=, eg real *= imaginary 4507 if (op == EXP.mulAssign || op == EXP.divAssign || op == EXP.modAssign) 4508 { 4509 // Any multiplication by an imaginary or complex number yields a complex result. 4510 // r *= c, i*=c, r*=i, i*=i are all forbidden operations. 4511 const(char)* opstr = EXPtoString(op).ptr; 4512 if (t1.isreal() && t2.iscomplex()) 4513 { 4514 error("`%s %s %s` is undefined. Did you mean `%s %s %s.re`?", t1.toChars(), opstr, t2.toChars(), t1.toChars(), opstr, t2.toChars()); 4515 return ErrorExp.get(); 4516 } 4517 else if (t1.isimaginary() && t2.iscomplex()) 4518 { 4519 error("`%s %s %s` is undefined. Did you mean `%s %s %s.im`?", t1.toChars(), opstr, t2.toChars(), t1.toChars(), opstr, t2.toChars()); 4520 return ErrorExp.get(); 4521 } 4522 else if ((t1.isreal() || t1.isimaginary()) && t2.isimaginary()) 4523 { 4524 error("`%s %s %s` is an undefined operation", t1.toChars(), opstr, t2.toChars()); 4525 return ErrorExp.get(); 4526 } 4527 } 4528 4529 // generate an error if this is a nonsensical += or -=, eg real += imaginary 4530 if (op == EXP.addAssign || op == EXP.minAssign) 4531 { 4532 // Addition or subtraction of a real and an imaginary is a complex result. 4533 // Thus, r+=i, r+=c, i+=r, i+=c are all forbidden operations. 4534 if ((t1.isreal() && (t2.isimaginary() || t2.iscomplex())) || (t1.isimaginary() && (t2.isreal() || t2.iscomplex()))) 4535 { 4536 error("`%s %s %s` is undefined (result is complex)", t1.toChars(), EXPtoString(op).ptr, t2.toChars()); 4537 return ErrorExp.get(); 4538 } 4539 if (type.isreal() || type.isimaginary()) 4540 { 4541 assert(global.errors || t2.isfloating()); 4542 e2 = e2.castTo(sc, t1); 4543 } 4544 } 4545 if (op == EXP.mulAssign) 4546 { 4547 if (t2.isfloating()) 4548 { 4549 if (t1.isreal()) 4550 { 4551 if (t2.isimaginary() || t2.iscomplex()) 4552 { 4553 e2 = e2.castTo(sc, t1); 4554 } 4555 } 4556 else if (t1.isimaginary()) 4557 { 4558 if (t2.isimaginary() || t2.iscomplex()) 4559 { 4560 switch (t1.ty) 4561 { 4562 case Timaginary32: 4563 t2 = Type.tfloat32; 4564 break; 4565 4566 case Timaginary64: 4567 t2 = Type.tfloat64; 4568 break; 4569 4570 case Timaginary80: 4571 t2 = Type.tfloat80; 4572 break; 4573 4574 default: 4575 assert(0); 4576 } 4577 e2 = e2.castTo(sc, t2); 4578 } 4579 } 4580 } 4581 } 4582 else if (op == EXP.divAssign) 4583 { 4584 if (t2.isimaginary()) 4585 { 4586 if (t1.isreal()) 4587 { 4588 // x/iv = i(-x/v) 4589 // Therefore, the result is 0 4590 e2 = new CommaExp(loc, e2, new RealExp(loc, CTFloat.zero, t1)); 4591 e2.type = t1; 4592 Expression e = new AssignExp(loc, e1, e2); 4593 e.type = t1; 4594 return e; 4595 } 4596 else if (t1.isimaginary()) 4597 { 4598 Type t3; 4599 switch (t1.ty) 4600 { 4601 case Timaginary32: 4602 t3 = Type.tfloat32; 4603 break; 4604 4605 case Timaginary64: 4606 t3 = Type.tfloat64; 4607 break; 4608 4609 case Timaginary80: 4610 t3 = Type.tfloat80; 4611 break; 4612 4613 default: 4614 assert(0); 4615 } 4616 e2 = e2.castTo(sc, t3); 4617 Expression e = new AssignExp(loc, e1, e2); 4618 e.type = t1; 4619 return e; 4620 } 4621 } 4622 } 4623 else if (op == EXP.modAssign) 4624 { 4625 if (t2.iscomplex()) 4626 { 4627 error("cannot perform modulo complex arithmetic"); 4628 return ErrorExp.get(); 4629 } 4630 } 4631 return this; 4632 } 4633 4634 extern (D) final bool checkIntegralBin() 4635 { 4636 bool r1 = e1.checkIntegral(); 4637 bool r2 = e2.checkIntegral(); 4638 return (r1 || r2); 4639 } 4640 4641 extern (D) final bool checkArithmeticBin() 4642 { 4643 bool r1 = e1.checkArithmetic(); 4644 bool r2 = e2.checkArithmetic(); 4645 return (r1 || r2); 4646 } 4647 4648 extern (D) final bool checkSharedAccessBin(Scope* sc) 4649 { 4650 const r1 = e1.checkSharedAccess(sc); 4651 const r2 = e2.checkSharedAccess(sc); 4652 return (r1 || r2); 4653 } 4654 4655 /********************* 4656 * Mark the operands as will never be dereferenced, 4657 * which is useful info for @safe checks. 4658 * Do before semantic() on operands rewrites them. 4659 */ 4660 final void setNoderefOperands() 4661 { 4662 if (auto edi = e1.isDotIdExp()) 4663 edi.noderef = true; 4664 if (auto edi = e2.isDotIdExp()) 4665 edi.noderef = true; 4666 4667 } 4668 4669 final Expression reorderSettingAAElem(Scope* sc) 4670 { 4671 BinExp be = this; 4672 4673 auto ie = be.e1.isIndexExp(); 4674 if (!ie) 4675 return be; 4676 if (ie.e1.type.toBasetype().ty != Taarray) 4677 return be; 4678 4679 /* Fix evaluation order of setting AA element 4680 * https://issues.dlang.org/show_bug.cgi?id=3825 4681 * Rewrite: 4682 * aa[k1][k2][k3] op= val; 4683 * as: 4684 * auto ref __aatmp = aa; 4685 * auto ref __aakey3 = k1, __aakey2 = k2, __aakey1 = k3; 4686 * auto ref __aaval = val; 4687 * __aatmp[__aakey3][__aakey2][__aakey1] op= __aaval; // assignment 4688 */ 4689 4690 Expression e0; 4691 while (1) 4692 { 4693 Expression de; 4694 ie.e2 = extractSideEffect(sc, "__aakey", de, ie.e2); 4695 e0 = Expression.combine(de, e0); 4696 4697 auto ie1 = ie.e1.isIndexExp(); 4698 if (!ie1 || 4699 ie1.e1.type.toBasetype().ty != Taarray) 4700 { 4701 break; 4702 } 4703 ie = ie1; 4704 } 4705 assert(ie.e1.type.toBasetype().ty == Taarray); 4706 4707 Expression de; 4708 ie.e1 = extractSideEffect(sc, "__aatmp", de, ie.e1); 4709 e0 = Expression.combine(de, e0); 4710 4711 be.e2 = extractSideEffect(sc, "__aaval", e0, be.e2, true); 4712 4713 //printf("-e0 = %s, be = %s\n", e0.toChars(), be.toChars()); 4714 return Expression.combine(e0, be); 4715 } 4716 4717 override void accept(Visitor v) 4718 { 4719 v.visit(this); 4720 } 4721 } 4722 4723 /*********************************************************** 4724 * Binary operator assignment, `+=` `-=` `*=` etc. 4725 */ 4726 extern (C++) class BinAssignExp : BinExp 4727 { 4728 extern (D) this(const ref Loc loc, EXP op, Expression e1, Expression e2) scope 4729 { 4730 super(loc, op, e1, e2); 4731 } 4732 4733 override final bool isLvalue() 4734 { 4735 return true; 4736 } 4737 4738 override final Expression toLvalue(Scope* sc, Expression ex) 4739 { 4740 // Lvalue-ness will be handled in glue layer. 4741 return this; 4742 } 4743 4744 override final Expression modifiableLvalue(Scope* sc, Expression e) 4745 { 4746 // should check e1.checkModifiable() ? 4747 return toLvalue(sc, this); 4748 } 4749 4750 override void accept(Visitor v) 4751 { 4752 v.visit(this); 4753 } 4754 } 4755 4756 /*********************************************************** 4757 * A string mixin, `mixin("x")` 4758 * 4759 * https://dlang.org/spec/expression.html#mixin_expressions 4760 */ 4761 extern (C++) final class MixinExp : Expression 4762 { 4763 Expressions* exps; 4764 4765 extern (D) this(const ref Loc loc, Expressions* exps) 4766 { 4767 super(loc, EXP.mixin_); 4768 this.exps = exps; 4769 } 4770 4771 override MixinExp syntaxCopy() 4772 { 4773 return new MixinExp(loc, arraySyntaxCopy(exps)); 4774 } 4775 4776 override bool equals(const RootObject o) const 4777 { 4778 if (this == o) 4779 return true; 4780 auto e = o.isExpression(); 4781 if (!e) 4782 return false; 4783 if (auto ce = e.isMixinExp()) 4784 { 4785 if (exps.length != ce.exps.length) 4786 return false; 4787 foreach (i, e1; *exps) 4788 { 4789 auto e2 = (*ce.exps)[i]; 4790 if (e1 != e2 && (!e1 || !e2 || !e1.equals(e2))) 4791 return false; 4792 } 4793 return true; 4794 } 4795 return false; 4796 } 4797 4798 override void accept(Visitor v) 4799 { 4800 v.visit(this); 4801 } 4802 } 4803 4804 /*********************************************************** 4805 * An import expression, `import("file.txt")` 4806 * 4807 * Not to be confused with module imports, `import std.stdio`, which is an `ImportStatement` 4808 * 4809 * https://dlang.org/spec/expression.html#import_expressions 4810 */ 4811 extern (C++) final class ImportExp : UnaExp 4812 { 4813 extern (D) this(const ref Loc loc, Expression e) 4814 { 4815 super(loc, EXP.import_, e); 4816 } 4817 4818 override void accept(Visitor v) 4819 { 4820 v.visit(this); 4821 } 4822 } 4823 4824 /*********************************************************** 4825 * An assert expression, `assert(x == y)` 4826 * 4827 * https://dlang.org/spec/expression.html#assert_expressions 4828 */ 4829 extern (C++) final class AssertExp : UnaExp 4830 { 4831 Expression msg; 4832 4833 extern (D) this(const ref Loc loc, Expression e, Expression msg = null) 4834 { 4835 super(loc, EXP.assert_, e); 4836 this.msg = msg; 4837 } 4838 4839 override AssertExp syntaxCopy() 4840 { 4841 return new AssertExp(loc, e1.syntaxCopy(), msg ? msg.syntaxCopy() : null); 4842 } 4843 4844 override void accept(Visitor v) 4845 { 4846 v.visit(this); 4847 } 4848 } 4849 4850 /*********************************************************** 4851 * `throw <e1>` as proposed by DIP 1034. 4852 * 4853 * Replacement for the deprecated `ThrowStatement` that can be nested 4854 * in other expression. 4855 */ 4856 extern (C++) final class ThrowExp : UnaExp 4857 { 4858 extern (D) this(const ref Loc loc, Expression e) 4859 { 4860 super(loc, EXP.throw_, e); 4861 this.type = Type.tnoreturn; 4862 } 4863 4864 override ThrowExp syntaxCopy() 4865 { 4866 return new ThrowExp(loc, e1.syntaxCopy()); 4867 } 4868 4869 override void accept(Visitor v) 4870 { 4871 v.visit(this); 4872 } 4873 } 4874 4875 /*********************************************************** 4876 */ 4877 extern (C++) final class DotIdExp : UnaExp 4878 { 4879 Identifier ident; 4880 bool noderef; // true if the result of the expression will never be dereferenced 4881 bool wantsym; // do not replace Symbol with its initializer during semantic() 4882 bool arrow; // ImportC: if -> instead of . 4883 4884 extern (D) this(const ref Loc loc, Expression e, Identifier ident) 4885 { 4886 super(loc, EXP.dotIdentifier, e); 4887 this.ident = ident; 4888 } 4889 4890 static DotIdExp create(const ref Loc loc, Expression e, Identifier ident) 4891 { 4892 return new DotIdExp(loc, e, ident); 4893 } 4894 4895 override void accept(Visitor v) 4896 { 4897 v.visit(this); 4898 } 4899 } 4900 4901 /*********************************************************** 4902 * Mainly just a placeholder 4903 */ 4904 extern (C++) final class DotTemplateExp : UnaExp 4905 { 4906 TemplateDeclaration td; 4907 4908 extern (D) this(const ref Loc loc, Expression e, TemplateDeclaration td) 4909 { 4910 super(loc, EXP.dotTemplateDeclaration, e); 4911 this.td = td; 4912 } 4913 4914 override bool checkType() 4915 { 4916 error("%s `%s` has no type", td.kind(), toChars()); 4917 return true; 4918 } 4919 4920 override bool checkValue() 4921 { 4922 error("%s `%s` has no value", td.kind(), toChars()); 4923 return true; 4924 } 4925 4926 override void accept(Visitor v) 4927 { 4928 v.visit(this); 4929 } 4930 } 4931 4932 /*********************************************************** 4933 */ 4934 extern (C++) final class DotVarExp : UnaExp 4935 { 4936 Declaration var; 4937 bool hasOverloads; 4938 4939 extern (D) this(const ref Loc loc, Expression e, Declaration var, bool hasOverloads = true) 4940 { 4941 if (var.isVarDeclaration()) 4942 hasOverloads = false; 4943 4944 super(loc, EXP.dotVariable, e); 4945 //printf("DotVarExp()\n"); 4946 this.var = var; 4947 this.hasOverloads = hasOverloads; 4948 } 4949 4950 override bool isLvalue() 4951 { 4952 if (e1.op != EXP.structLiteral) 4953 return true; 4954 auto vd = var.isVarDeclaration(); 4955 return !(vd && vd.isField()); 4956 } 4957 4958 override Expression toLvalue(Scope* sc, Expression e) 4959 { 4960 //printf("DotVarExp::toLvalue(%s)\n", toChars()); 4961 if (sc && sc.flags & SCOPE.Cfile) 4962 { 4963 /* C11 6.5.2.3-3: A postfix expression followed by the '.' or '->' operator 4964 * is an lvalue if the first expression is an lvalue. 4965 */ 4966 if (!e1.isLvalue()) 4967 return Expression.toLvalue(sc, e); 4968 } 4969 if (!isLvalue()) 4970 return Expression.toLvalue(sc, e); 4971 if (e1.op == EXP.this_ && sc.ctorflow.fieldinit.length && !(sc.ctorflow.callSuper & CSX.any_ctor)) 4972 { 4973 if (VarDeclaration vd = var.isVarDeclaration()) 4974 { 4975 auto ad = vd.isMember2(); 4976 if (ad && ad.fields.length == sc.ctorflow.fieldinit.length) 4977 { 4978 foreach (i, f; ad.fields) 4979 { 4980 if (f == vd) 4981 { 4982 if (!(sc.ctorflow.fieldinit[i].csx & CSX.this_ctor)) 4983 { 4984 /* If the address of vd is taken, assume it is thereby initialized 4985 * https://issues.dlang.org/show_bug.cgi?id=15869 4986 */ 4987 modifyFieldVar(loc, sc, vd, e1); 4988 } 4989 break; 4990 } 4991 } 4992 } 4993 } 4994 } 4995 return this; 4996 } 4997 4998 override Expression modifiableLvalue(Scope* sc, Expression e) 4999 { 5000 version (none) 5001 { 5002 printf("DotVarExp::modifiableLvalue(%s)\n", toChars()); 5003 printf("e1.type = %s\n", e1.type.toChars()); 5004 printf("var.type = %s\n", var.type.toChars()); 5005 } 5006 5007 return Expression.modifiableLvalue(sc, e); 5008 } 5009 5010 override void accept(Visitor v) 5011 { 5012 v.visit(this); 5013 } 5014 } 5015 5016 /*********************************************************** 5017 * foo.bar!(args) 5018 */ 5019 extern (C++) final class DotTemplateInstanceExp : UnaExp 5020 { 5021 TemplateInstance ti; 5022 5023 extern (D) this(const ref Loc loc, Expression e, Identifier name, Objects* tiargs) 5024 { 5025 super(loc, EXP.dotTemplateInstance, e); 5026 //printf("DotTemplateInstanceExp()\n"); 5027 this.ti = new TemplateInstance(loc, name, tiargs); 5028 } 5029 5030 extern (D) this(const ref Loc loc, Expression e, TemplateInstance ti) 5031 { 5032 super(loc, EXP.dotTemplateInstance, e); 5033 this.ti = ti; 5034 } 5035 5036 override DotTemplateInstanceExp syntaxCopy() 5037 { 5038 return new DotTemplateInstanceExp(loc, e1.syntaxCopy(), ti.name, TemplateInstance.arraySyntaxCopy(ti.tiargs)); 5039 } 5040 5041 bool findTempDecl(Scope* sc) 5042 { 5043 static if (LOGSEMANTIC) 5044 { 5045 printf("DotTemplateInstanceExp::findTempDecl('%s')\n", toChars()); 5046 } 5047 if (ti.tempdecl) 5048 return true; 5049 5050 Expression e = new DotIdExp(loc, e1, ti.name); 5051 e = e.expressionSemantic(sc); 5052 if (e.op == EXP.dot) 5053 e = (cast(DotExp)e).e2; 5054 5055 Dsymbol s = null; 5056 switch (e.op) 5057 { 5058 case EXP.overloadSet: 5059 s = (cast(OverExp)e).vars; 5060 break; 5061 5062 case EXP.dotTemplateDeclaration: 5063 s = (cast(DotTemplateExp)e).td; 5064 break; 5065 5066 case EXP.scope_: 5067 s = (cast(ScopeExp)e).sds; 5068 break; 5069 5070 case EXP.dotVariable: 5071 s = (cast(DotVarExp)e).var; 5072 break; 5073 5074 case EXP.variable: 5075 s = (cast(VarExp)e).var; 5076 break; 5077 5078 default: 5079 return false; 5080 } 5081 return ti.updateTempDecl(sc, s); 5082 } 5083 5084 override bool checkType() 5085 { 5086 // Same logic as ScopeExp.checkType() 5087 if (ti.tempdecl && 5088 ti.semantictiargsdone && 5089 ti.semanticRun == PASS.initial) 5090 { 5091 error("partial %s `%s` has no type", ti.kind(), toChars()); 5092 return true; 5093 } 5094 return false; 5095 } 5096 5097 override bool checkValue() 5098 { 5099 if (ti.tempdecl && 5100 ti.semantictiargsdone && 5101 ti.semanticRun == PASS.initial) 5102 5103 error("partial %s `%s` has no value", ti.kind(), toChars()); 5104 else 5105 error("%s `%s` has no value", ti.kind(), ti.toChars()); 5106 return true; 5107 } 5108 5109 override void accept(Visitor v) 5110 { 5111 v.visit(this); 5112 } 5113 } 5114 5115 /*********************************************************** 5116 */ 5117 extern (C++) final class DelegateExp : UnaExp 5118 { 5119 FuncDeclaration func; 5120 bool hasOverloads; 5121 VarDeclaration vthis2; // container for multi-context 5122 5123 extern (D) this(const ref Loc loc, Expression e, FuncDeclaration f, bool hasOverloads = true, VarDeclaration vthis2 = null) 5124 { 5125 super(loc, EXP.delegate_, e); 5126 this.func = f; 5127 this.hasOverloads = hasOverloads; 5128 this.vthis2 = vthis2; 5129 } 5130 5131 override void accept(Visitor v) 5132 { 5133 v.visit(this); 5134 } 5135 } 5136 5137 /*********************************************************** 5138 */ 5139 extern (C++) final class DotTypeExp : UnaExp 5140 { 5141 Dsymbol sym; // symbol that represents a type 5142 5143 extern (D) this(const ref Loc loc, Expression e, Dsymbol s) 5144 { 5145 super(loc, EXP.dotType, e); 5146 this.sym = s; 5147 } 5148 5149 override void accept(Visitor v) 5150 { 5151 v.visit(this); 5152 } 5153 } 5154 5155 /** 5156 * The arguments of a function call 5157 * 5158 * Contains a list of expressions. If it is a named argument, the `names` 5159 * list has a non-null entry at the same index. 5160 */ 5161 struct ArgumentList 5162 { 5163 Expressions* arguments; // function arguments 5164 Identifiers* names; // named argument identifiers 5165 5166 size_t length() const @nogc nothrow pure @safe { return arguments ? arguments.length : 0; } 5167 5168 /// Returns: whether this argument list contains any named arguments 5169 bool hasNames() const @nogc nothrow pure @safe 5170 { 5171 if (names is null) 5172 return false; 5173 foreach (name; *names) 5174 if (name !is null) 5175 return true; 5176 5177 return false; 5178 } 5179 } 5180 5181 /*********************************************************** 5182 */ 5183 extern (C++) final class CallExp : UnaExp 5184 { 5185 Expressions* arguments; // function arguments 5186 Identifiers* names; // named argument identifiers 5187 FuncDeclaration f; // symbol to call 5188 bool directcall; // true if a virtual call is devirtualized 5189 bool inDebugStatement; /// true if this was in a debug statement 5190 bool ignoreAttributes; /// don't enforce attributes (e.g. call @gc function in @nogc code) 5191 VarDeclaration vthis2; // container for multi-context 5192 5193 /// Puts the `arguments` and `names` into an `ArgumentList` for easily passing them around. 5194 /// The fields are still separate for backwards compatibility 5195 extern (D) ArgumentList argumentList() { return ArgumentList(arguments, names); } 5196 5197 extern (D) this(const ref Loc loc, Expression e, Expressions* exps, Identifiers* names = null) 5198 { 5199 super(loc, EXP.call, e); 5200 this.arguments = exps; 5201 this.names = names; 5202 } 5203 5204 extern (D) this(const ref Loc loc, Expression e) 5205 { 5206 super(loc, EXP.call, e); 5207 } 5208 5209 extern (D) this(const ref Loc loc, Expression e, Expression earg1) 5210 { 5211 super(loc, EXP.call, e); 5212 this.arguments = new Expressions(); 5213 if (earg1) 5214 this.arguments.push(earg1); 5215 } 5216 5217 extern (D) this(const ref Loc loc, Expression e, Expression earg1, Expression earg2) 5218 { 5219 super(loc, EXP.call, e); 5220 auto arguments = new Expressions(2); 5221 (*arguments)[0] = earg1; 5222 (*arguments)[1] = earg2; 5223 this.arguments = arguments; 5224 } 5225 5226 /*********************************************************** 5227 * Instatiates a new function call expression 5228 * Params: 5229 * loc = location 5230 * fd = the declaration of the function to call 5231 * earg1 = the function argument 5232 */ 5233 extern(D) this(const ref Loc loc, FuncDeclaration fd, Expression earg1) 5234 { 5235 this(loc, new VarExp(loc, fd, false), earg1); 5236 this.f = fd; 5237 } 5238 5239 static CallExp create(const ref Loc loc, Expression e, Expressions* exps) 5240 { 5241 return new CallExp(loc, e, exps); 5242 } 5243 5244 static CallExp create(const ref Loc loc, Expression e) 5245 { 5246 return new CallExp(loc, e); 5247 } 5248 5249 static CallExp create(const ref Loc loc, Expression e, Expression earg1) 5250 { 5251 return new CallExp(loc, e, earg1); 5252 } 5253 5254 /*********************************************************** 5255 * Creates a new function call expression 5256 * Params: 5257 * loc = location 5258 * fd = the declaration of the function to call 5259 * earg1 = the function argument 5260 */ 5261 static CallExp create(const ref Loc loc, FuncDeclaration fd, Expression earg1) 5262 { 5263 return new CallExp(loc, fd, earg1); 5264 } 5265 5266 override CallExp syntaxCopy() 5267 { 5268 return new CallExp(loc, e1.syntaxCopy(), arraySyntaxCopy(arguments), names ? names.copy() : null); 5269 } 5270 5271 override bool isLvalue() 5272 { 5273 Type tb = e1.type.toBasetype(); 5274 if (tb.ty == Tdelegate || tb.ty == Tpointer) 5275 tb = tb.nextOf(); 5276 auto tf = tb.isTypeFunction(); 5277 if (tf && tf.isref) 5278 { 5279 if (auto dve = e1.isDotVarExp()) 5280 if (dve.var.isCtorDeclaration()) 5281 return false; 5282 return true; // function returns a reference 5283 } 5284 return false; 5285 } 5286 5287 override Expression toLvalue(Scope* sc, Expression e) 5288 { 5289 if (isLvalue()) 5290 return this; 5291 return Expression.toLvalue(sc, e); 5292 } 5293 5294 override Expression addDtorHook(Scope* sc) 5295 { 5296 /* Only need to add dtor hook if it's a type that needs destruction. 5297 * Use same logic as VarDeclaration::callScopeDtor() 5298 */ 5299 5300 if (auto tf = e1.type.isTypeFunction()) 5301 { 5302 if (tf.isref) 5303 return this; 5304 } 5305 5306 Type tv = type.baseElemOf(); 5307 if (auto ts = tv.isTypeStruct()) 5308 { 5309 StructDeclaration sd = ts.sym; 5310 if (sd.dtor) 5311 { 5312 /* Type needs destruction, so declare a tmp 5313 * which the back end will recognize and call dtor on 5314 */ 5315 auto tmp = copyToTemp(0, Id.__tmpfordtor.toString(), this); 5316 auto de = new DeclarationExp(loc, tmp); 5317 auto ve = new VarExp(loc, tmp); 5318 Expression e = new CommaExp(loc, de, ve); 5319 e = e.expressionSemantic(sc); 5320 return e; 5321 } 5322 } 5323 return this; 5324 } 5325 5326 override void accept(Visitor v) 5327 { 5328 v.visit(this); 5329 } 5330 } 5331 5332 FuncDeclaration isFuncAddress(Expression e, bool* hasOverloads = null) 5333 { 5334 if (auto ae = e.isAddrExp()) 5335 { 5336 auto ae1 = ae.e1; 5337 if (auto ve = ae1.isVarExp()) 5338 { 5339 if (hasOverloads) 5340 *hasOverloads = ve.hasOverloads; 5341 return ve.var.isFuncDeclaration(); 5342 } 5343 if (auto dve = ae1.isDotVarExp()) 5344 { 5345 if (hasOverloads) 5346 *hasOverloads = dve.hasOverloads; 5347 return dve.var.isFuncDeclaration(); 5348 } 5349 } 5350 else 5351 { 5352 if (auto soe = e.isSymOffExp()) 5353 { 5354 if (hasOverloads) 5355 *hasOverloads = soe.hasOverloads; 5356 return soe.var.isFuncDeclaration(); 5357 } 5358 if (auto dge = e.isDelegateExp()) 5359 { 5360 if (hasOverloads) 5361 *hasOverloads = dge.hasOverloads; 5362 return dge.func.isFuncDeclaration(); 5363 } 5364 } 5365 return null; 5366 } 5367 5368 /*********************************************************** 5369 * The 'address of' operator, `&p` 5370 */ 5371 extern (C++) final class AddrExp : UnaExp 5372 { 5373 extern (D) this(const ref Loc loc, Expression e) 5374 { 5375 super(loc, EXP.address, e); 5376 } 5377 5378 extern (D) this(const ref Loc loc, Expression e, Type t) 5379 { 5380 this(loc, e); 5381 type = t; 5382 } 5383 5384 override void accept(Visitor v) 5385 { 5386 v.visit(this); 5387 } 5388 } 5389 5390 /*********************************************************** 5391 * The pointer dereference operator, `*p` 5392 */ 5393 extern (C++) final class PtrExp : UnaExp 5394 { 5395 extern (D) this(const ref Loc loc, Expression e) 5396 { 5397 super(loc, EXP.star, e); 5398 //if (e.type) 5399 // type = ((TypePointer *)e.type).next; 5400 } 5401 5402 extern (D) this(const ref Loc loc, Expression e, Type t) 5403 { 5404 super(loc, EXP.star, e); 5405 type = t; 5406 } 5407 5408 override bool isLvalue() 5409 { 5410 return true; 5411 } 5412 5413 override Expression toLvalue(Scope* sc, Expression e) 5414 { 5415 return this; 5416 } 5417 5418 override Expression modifiableLvalue(Scope* sc, Expression e) 5419 { 5420 //printf("PtrExp::modifiableLvalue() %s, type %s\n", toChars(), type.toChars()); 5421 Declaration var; 5422 if (auto se = e1.isSymOffExp()) 5423 var = se.var; 5424 else if (auto ve = e1.isVarExp()) 5425 var = ve.var; 5426 if (var && var.type.isFunction_Delegate_PtrToFunction()) 5427 { 5428 if (var.type.isTypeFunction()) 5429 error("function `%s` is not an lvalue and cannot be modified", var.toChars()); 5430 else 5431 error("function pointed to by `%s` is not an lvalue and cannot be modified", var.toChars()); 5432 return ErrorExp.get(); 5433 } 5434 return Expression.modifiableLvalue(sc, e); 5435 } 5436 5437 override void accept(Visitor v) 5438 { 5439 v.visit(this); 5440 } 5441 } 5442 5443 /*********************************************************** 5444 * The negation operator, `-x` 5445 */ 5446 extern (C++) final class NegExp : UnaExp 5447 { 5448 extern (D) this(const ref Loc loc, Expression e) 5449 { 5450 super(loc, EXP.negate, e); 5451 } 5452 5453 override void accept(Visitor v) 5454 { 5455 v.visit(this); 5456 } 5457 } 5458 5459 /*********************************************************** 5460 * The unary add operator, `+x` 5461 */ 5462 extern (C++) final class UAddExp : UnaExp 5463 { 5464 extern (D) this(const ref Loc loc, Expression e) scope 5465 { 5466 super(loc, EXP.uadd, e); 5467 } 5468 5469 override void accept(Visitor v) 5470 { 5471 v.visit(this); 5472 } 5473 } 5474 5475 /*********************************************************** 5476 * The bitwise complement operator, `~x` 5477 */ 5478 extern (C++) final class ComExp : UnaExp 5479 { 5480 extern (D) this(const ref Loc loc, Expression e) 5481 { 5482 super(loc, EXP.tilde, e); 5483 } 5484 5485 override void accept(Visitor v) 5486 { 5487 v.visit(this); 5488 } 5489 } 5490 5491 /*********************************************************** 5492 * The logical not operator, `!x` 5493 */ 5494 extern (C++) final class NotExp : UnaExp 5495 { 5496 extern (D) this(const ref Loc loc, Expression e) 5497 { 5498 super(loc, EXP.not, e); 5499 } 5500 5501 override void accept(Visitor v) 5502 { 5503 v.visit(this); 5504 } 5505 } 5506 5507 /*********************************************************** 5508 * The delete operator, `delete x` (deprecated) 5509 * 5510 * https://dlang.org/spec/expression.html#delete_expressions 5511 */ 5512 extern (C++) final class DeleteExp : UnaExp 5513 { 5514 bool isRAII; // true if called automatically as a result of scoped destruction 5515 5516 extern (D) this(const ref Loc loc, Expression e, bool isRAII) 5517 { 5518 super(loc, EXP.delete_, e); 5519 this.isRAII = isRAII; 5520 } 5521 5522 override void accept(Visitor v) 5523 { 5524 v.visit(this); 5525 } 5526 } 5527 5528 /*********************************************************** 5529 * The type cast operator, `cast(T) x` 5530 * 5531 * It's possible to cast to one type while painting to another type 5532 * 5533 * https://dlang.org/spec/expression.html#cast_expressions 5534 */ 5535 extern (C++) final class CastExp : UnaExp 5536 { 5537 Type to; // type to cast to 5538 ubyte mod = cast(ubyte)~0; // MODxxxxx 5539 5540 extern (D) this(const ref Loc loc, Expression e, Type t) 5541 { 5542 super(loc, EXP.cast_, e); 5543 this.to = t; 5544 } 5545 5546 /* For cast(const) and cast(immutable) 5547 */ 5548 extern (D) this(const ref Loc loc, Expression e, ubyte mod) 5549 { 5550 super(loc, EXP.cast_, e); 5551 this.mod = mod; 5552 } 5553 5554 override CastExp syntaxCopy() 5555 { 5556 return to ? new CastExp(loc, e1.syntaxCopy(), to.syntaxCopy()) : new CastExp(loc, e1.syntaxCopy(), mod); 5557 } 5558 5559 override bool isLvalue() 5560 { 5561 //printf("e1.type = %s, to.type = %s\n", e1.type.toChars(), to.toChars()); 5562 if (!e1.isLvalue()) 5563 return false; 5564 return (to.ty == Tsarray && (e1.type.ty == Tvector || e1.type.ty == Tsarray)) || 5565 e1.type.mutableOf().unSharedOf().equals(to.mutableOf().unSharedOf()); 5566 } 5567 5568 override Expression toLvalue(Scope* sc, Expression e) 5569 { 5570 if (sc && sc.flags & SCOPE.Cfile) 5571 { 5572 /* C11 6.5.4-5: A cast does not yield an lvalue. 5573 */ 5574 return Expression.toLvalue(sc, e); 5575 } 5576 if (isLvalue()) 5577 return this; 5578 return Expression.toLvalue(sc, e); 5579 } 5580 5581 override Expression addDtorHook(Scope* sc) 5582 { 5583 if (to.toBasetype().ty == Tvoid) // look past the cast(void) 5584 e1 = e1.addDtorHook(sc); 5585 return this; 5586 } 5587 5588 override void accept(Visitor v) 5589 { 5590 v.visit(this); 5591 } 5592 } 5593 5594 /*********************************************************** 5595 */ 5596 extern (C++) final class VectorExp : UnaExp 5597 { 5598 TypeVector to; // the target vector type before semantic() 5599 uint dim = ~0; // number of elements in the vector 5600 OwnedBy ownedByCtfe = OwnedBy.code; 5601 5602 extern (D) this(const ref Loc loc, Expression e, Type t) 5603 { 5604 super(loc, EXP.vector, e); 5605 assert(t.ty == Tvector); 5606 to = cast(TypeVector)t; 5607 } 5608 5609 static VectorExp create(const ref Loc loc, Expression e, Type t) 5610 { 5611 return new VectorExp(loc, e, t); 5612 } 5613 5614 // Same as create, but doesn't allocate memory. 5615 static void emplace(UnionExp* pue, const ref Loc loc, Expression e, Type type) 5616 { 5617 emplaceExp!(VectorExp)(pue, loc, e, type); 5618 } 5619 5620 override VectorExp syntaxCopy() 5621 { 5622 return new VectorExp(loc, e1.syntaxCopy(), to.syntaxCopy()); 5623 } 5624 5625 override void accept(Visitor v) 5626 { 5627 v.visit(this); 5628 } 5629 } 5630 5631 /*********************************************************** 5632 * e1.array property for vectors. 5633 * 5634 * https://dlang.org/spec/simd.html#properties 5635 */ 5636 extern (C++) final class VectorArrayExp : UnaExp 5637 { 5638 extern (D) this(const ref Loc loc, Expression e1) 5639 { 5640 super(loc, EXP.vectorArray, e1); 5641 } 5642 5643 override bool isLvalue() 5644 { 5645 return e1.isLvalue(); 5646 } 5647 5648 override Expression toLvalue(Scope* sc, Expression e) 5649 { 5650 e1 = e1.toLvalue(sc, e); 5651 return this; 5652 } 5653 5654 override void accept(Visitor v) 5655 { 5656 v.visit(this); 5657 } 5658 } 5659 5660 /*********************************************************** 5661 * e1 [lwr .. upr] 5662 * 5663 * https://dlang.org/spec/expression.html#slice_expressions 5664 */ 5665 extern (C++) final class SliceExp : UnaExp 5666 { 5667 Expression upr; // null if implicit 0 5668 Expression lwr; // null if implicit [length - 1] 5669 5670 VarDeclaration lengthVar; 5671 5672 private extern(D) static struct BitFields 5673 { 5674 bool upperIsInBounds; // true if upr <= e1.length 5675 bool lowerIsLessThanUpper; // true if lwr <= upr 5676 bool arrayop; // an array operation, rather than a slice 5677 } 5678 import dmd.common.bitfields : generateBitFields; 5679 mixin(generateBitFields!(BitFields, ubyte)); 5680 5681 /************************************************************/ 5682 extern (D) this(const ref Loc loc, Expression e1, IntervalExp ie) 5683 { 5684 super(loc, EXP.slice, e1); 5685 this.upr = ie ? ie.upr : null; 5686 this.lwr = ie ? ie.lwr : null; 5687 } 5688 5689 extern (D) this(const ref Loc loc, Expression e1, Expression lwr, Expression upr) 5690 { 5691 super(loc, EXP.slice, e1); 5692 this.upr = upr; 5693 this.lwr = lwr; 5694 } 5695 5696 override SliceExp syntaxCopy() 5697 { 5698 auto se = new SliceExp(loc, e1.syntaxCopy(), lwr ? lwr.syntaxCopy() : null, upr ? upr.syntaxCopy() : null); 5699 se.lengthVar = this.lengthVar; // bug7871 5700 return se; 5701 } 5702 5703 override bool isLvalue() 5704 { 5705 /* slice expression is rvalue in default, but 5706 * conversion to reference of static array is only allowed. 5707 */ 5708 return (type && type.toBasetype().ty == Tsarray); 5709 } 5710 5711 override Expression toLvalue(Scope* sc, Expression e) 5712 { 5713 //printf("SliceExp::toLvalue(%s) type = %s\n", toChars(), type ? type.toChars() : NULL); 5714 return (type && type.toBasetype().ty == Tsarray) ? this : Expression.toLvalue(sc, e); 5715 } 5716 5717 override Expression modifiableLvalue(Scope* sc, Expression e) 5718 { 5719 error("slice expression `%s` is not a modifiable lvalue", toChars()); 5720 return this; 5721 } 5722 5723 override Optional!bool toBool() 5724 { 5725 return e1.toBool(); 5726 } 5727 5728 override void accept(Visitor v) 5729 { 5730 v.visit(this); 5731 } 5732 } 5733 5734 /*********************************************************** 5735 * The `.length` property of an array 5736 */ 5737 extern (C++) final class ArrayLengthExp : UnaExp 5738 { 5739 extern (D) this(const ref Loc loc, Expression e1) 5740 { 5741 super(loc, EXP.arrayLength, e1); 5742 } 5743 5744 override void accept(Visitor v) 5745 { 5746 v.visit(this); 5747 } 5748 } 5749 5750 /*********************************************************** 5751 * e1 [ a0, a1, a2, a3 ,... ] 5752 * 5753 * https://dlang.org/spec/expression.html#index_expressions 5754 */ 5755 extern (C++) final class ArrayExp : UnaExp 5756 { 5757 Expressions* arguments; // Array of Expression's a0..an 5758 5759 size_t currentDimension; // for opDollar 5760 VarDeclaration lengthVar; 5761 5762 extern (D) this(const ref Loc loc, Expression e1, Expression index = null) 5763 { 5764 super(loc, EXP.array, e1); 5765 arguments = new Expressions(); 5766 if (index) 5767 arguments.push(index); 5768 } 5769 5770 extern (D) this(const ref Loc loc, Expression e1, Expressions* args) 5771 { 5772 super(loc, EXP.array, e1); 5773 arguments = args; 5774 } 5775 5776 override ArrayExp syntaxCopy() 5777 { 5778 auto ae = new ArrayExp(loc, e1.syntaxCopy(), arraySyntaxCopy(arguments)); 5779 ae.lengthVar = this.lengthVar; // bug7871 5780 return ae; 5781 } 5782 5783 override bool isLvalue() 5784 { 5785 if (type && type.toBasetype().ty == Tvoid) 5786 return false; 5787 return true; 5788 } 5789 5790 override Expression toLvalue(Scope* sc, Expression e) 5791 { 5792 if (type && type.toBasetype().ty == Tvoid) 5793 error("`void`s have no value"); 5794 return this; 5795 } 5796 5797 override void accept(Visitor v) 5798 { 5799 v.visit(this); 5800 } 5801 } 5802 5803 /*********************************************************** 5804 */ 5805 extern (C++) final class DotExp : BinExp 5806 { 5807 extern (D) this(const ref Loc loc, Expression e1, Expression e2) 5808 { 5809 super(loc, EXP.dot, e1, e2); 5810 } 5811 5812 override void accept(Visitor v) 5813 { 5814 v.visit(this); 5815 } 5816 } 5817 5818 /*********************************************************** 5819 */ 5820 extern (C++) final class CommaExp : BinExp 5821 { 5822 /// This is needed because AssignExp rewrites CommaExp, hence it needs 5823 /// to trigger the deprecation. 5824 const bool isGenerated; 5825 5826 /// Temporary variable to enable / disable deprecation of comma expression 5827 /// depending on the context. 5828 /// Since most constructor calls are rewritting, the only place where 5829 /// false will be passed will be from the parser. 5830 bool allowCommaExp; 5831 5832 5833 extern (D) this(const ref Loc loc, Expression e1, Expression e2, bool generated = true) 5834 { 5835 super(loc, EXP.comma, e1, e2); 5836 allowCommaExp = isGenerated = generated; 5837 } 5838 5839 override bool isLvalue() 5840 { 5841 return e2.isLvalue(); 5842 } 5843 5844 override Expression toLvalue(Scope* sc, Expression e) 5845 { 5846 e2 = e2.toLvalue(sc, null); 5847 return this; 5848 } 5849 5850 override Expression modifiableLvalue(Scope* sc, Expression e) 5851 { 5852 e2 = e2.modifiableLvalue(sc, e); 5853 return this; 5854 } 5855 5856 override Optional!bool toBool() 5857 { 5858 return e2.toBool(); 5859 } 5860 5861 override Expression addDtorHook(Scope* sc) 5862 { 5863 e2 = e2.addDtorHook(sc); 5864 return this; 5865 } 5866 5867 override void accept(Visitor v) 5868 { 5869 v.visit(this); 5870 } 5871 5872 /** 5873 * If the argument is a CommaExp, set a flag to prevent deprecation messages 5874 * 5875 * It's impossible to know from CommaExp.semantic if the result will 5876 * be used, hence when there is a result (type != void), a deprecation 5877 * message is always emitted. 5878 * However, some construct can produce a result but won't use it 5879 * (ExpStatement and for loop increment). Those should call this function 5880 * to prevent unwanted deprecations to be emitted. 5881 * 5882 * Params: 5883 * exp = An expression that discards its result. 5884 * If the argument is null or not a CommaExp, nothing happens. 5885 */ 5886 static void allow(Expression exp) 5887 { 5888 if (exp) 5889 if (auto ce = exp.isCommaExp()) 5890 ce.allowCommaExp = true; 5891 } 5892 } 5893 5894 /*********************************************************** 5895 * Mainly just a placeholder 5896 */ 5897 extern (C++) final class IntervalExp : Expression 5898 { 5899 Expression lwr; 5900 Expression upr; 5901 5902 extern (D) this(const ref Loc loc, Expression lwr, Expression upr) 5903 { 5904 super(loc, EXP.interval); 5905 this.lwr = lwr; 5906 this.upr = upr; 5907 } 5908 5909 override Expression syntaxCopy() 5910 { 5911 return new IntervalExp(loc, lwr.syntaxCopy(), upr.syntaxCopy()); 5912 } 5913 5914 override void accept(Visitor v) 5915 { 5916 v.visit(this); 5917 } 5918 } 5919 5920 /*********************************************************** 5921 * The `dg.ptr` property, pointing to the delegate's 'context' 5922 * 5923 * c.f.`DelegateFuncptrExp` for the delegate's function pointer `dg.funcptr` 5924 */ 5925 extern (C++) final class DelegatePtrExp : UnaExp 5926 { 5927 extern (D) this(const ref Loc loc, Expression e1) 5928 { 5929 super(loc, EXP.delegatePointer, e1); 5930 } 5931 5932 override bool isLvalue() 5933 { 5934 return e1.isLvalue(); 5935 } 5936 5937 override Expression toLvalue(Scope* sc, Expression e) 5938 { 5939 e1 = e1.toLvalue(sc, e); 5940 return this; 5941 } 5942 5943 override Expression modifiableLvalue(Scope* sc, Expression e) 5944 { 5945 if (sc.setUnsafe(false, this.loc, "cannot modify delegate pointer in `@safe` code `%s`", this)) 5946 { 5947 return ErrorExp.get(); 5948 } 5949 return Expression.modifiableLvalue(sc, e); 5950 } 5951 5952 override void accept(Visitor v) 5953 { 5954 v.visit(this); 5955 } 5956 } 5957 5958 /*********************************************************** 5959 * The `dg.funcptr` property, pointing to the delegate's function 5960 * 5961 * c.f.`DelegatePtrExp` for the delegate's function pointer `dg.ptr` 5962 */ 5963 extern (C++) final class DelegateFuncptrExp : UnaExp 5964 { 5965 extern (D) this(const ref Loc loc, Expression e1) 5966 { 5967 super(loc, EXP.delegateFunctionPointer, e1); 5968 } 5969 5970 override bool isLvalue() 5971 { 5972 return e1.isLvalue(); 5973 } 5974 5975 override Expression toLvalue(Scope* sc, Expression e) 5976 { 5977 e1 = e1.toLvalue(sc, e); 5978 return this; 5979 } 5980 5981 override Expression modifiableLvalue(Scope* sc, Expression e) 5982 { 5983 if (sc.setUnsafe(false, this.loc, "cannot modify delegate function pointer in `@safe` code `%s`", this)) 5984 { 5985 return ErrorExp.get(); 5986 } 5987 return Expression.modifiableLvalue(sc, e); 5988 } 5989 5990 override void accept(Visitor v) 5991 { 5992 v.visit(this); 5993 } 5994 } 5995 5996 /*********************************************************** 5997 * e1 [ e2 ] 5998 */ 5999 extern (C++) final class IndexExp : BinExp 6000 { 6001 VarDeclaration lengthVar; 6002 bool modifiable = false; // assume it is an rvalue 6003 bool indexIsInBounds; // true if 0 <= e2 && e2 <= e1.length - 1 6004 6005 extern (D) this(const ref Loc loc, Expression e1, Expression e2) 6006 { 6007 super(loc, EXP.index, e1, e2); 6008 //printf("IndexExp::IndexExp('%s')\n", toChars()); 6009 } 6010 6011 extern (D) this(const ref Loc loc, Expression e1, Expression e2, bool indexIsInBounds) 6012 { 6013 super(loc, EXP.index, e1, e2); 6014 this.indexIsInBounds = indexIsInBounds; 6015 //printf("IndexExp::IndexExp('%s')\n", toChars()); 6016 } 6017 6018 override IndexExp syntaxCopy() 6019 { 6020 auto ie = new IndexExp(loc, e1.syntaxCopy(), e2.syntaxCopy()); 6021 ie.lengthVar = this.lengthVar; // bug7871 6022 return ie; 6023 } 6024 6025 override bool isLvalue() 6026 { 6027 if (e1.op == EXP.assocArrayLiteral) 6028 return false; 6029 if (e1.type.ty == Tsarray || 6030 (e1.op == EXP.index && e1.type.ty != Tarray)) 6031 { 6032 return e1.isLvalue(); 6033 } 6034 return true; 6035 } 6036 6037 override Expression toLvalue(Scope* sc, Expression e) 6038 { 6039 if (isLvalue()) 6040 return this; 6041 return Expression.toLvalue(sc, e); 6042 } 6043 6044 override Expression modifiableLvalue(Scope* sc, Expression e) 6045 { 6046 //printf("IndexExp::modifiableLvalue(%s)\n", toChars()); 6047 Expression ex = markSettingAAElem(); 6048 if (ex.op == EXP.error) 6049 return ex; 6050 6051 return Expression.modifiableLvalue(sc, e); 6052 } 6053 6054 extern (D) Expression markSettingAAElem() 6055 { 6056 if (e1.type.toBasetype().ty == Taarray) 6057 { 6058 Type t2b = e2.type.toBasetype(); 6059 if (t2b.ty == Tarray && t2b.nextOf().isMutable()) 6060 { 6061 error("associative arrays can only be assigned values with immutable keys, not `%s`", e2.type.toChars()); 6062 return ErrorExp.get(); 6063 } 6064 modifiable = true; 6065 6066 if (auto ie = e1.isIndexExp()) 6067 { 6068 Expression ex = ie.markSettingAAElem(); 6069 if (ex.op == EXP.error) 6070 return ex; 6071 assert(ex == e1); 6072 } 6073 } 6074 return this; 6075 } 6076 6077 override void accept(Visitor v) 6078 { 6079 v.visit(this); 6080 } 6081 } 6082 6083 /*********************************************************** 6084 * The postfix increment/decrement operator, `i++` / `i--` 6085 */ 6086 extern (C++) final class PostExp : BinExp 6087 { 6088 extern (D) this(EXP op, const ref Loc loc, Expression e) 6089 { 6090 super(loc, op, e, IntegerExp.literal!1); 6091 assert(op == EXP.minusMinus || op == EXP.plusPlus); 6092 } 6093 6094 override void accept(Visitor v) 6095 { 6096 v.visit(this); 6097 } 6098 } 6099 6100 /*********************************************************** 6101 * The prefix increment/decrement operator, `++i` / `--i` 6102 */ 6103 extern (C++) final class PreExp : UnaExp 6104 { 6105 extern (D) this(EXP op, const ref Loc loc, Expression e) 6106 { 6107 super(loc, op, e); 6108 assert(op == EXP.preMinusMinus || op == EXP.prePlusPlus); 6109 } 6110 6111 override void accept(Visitor v) 6112 { 6113 v.visit(this); 6114 } 6115 } 6116 6117 enum MemorySet 6118 { 6119 none = 0, // simple assignment 6120 blockAssign = 1, // setting the contents of an array 6121 referenceInit = 2, // setting the reference of STC.ref_ variable 6122 } 6123 6124 /*********************************************************** 6125 * The assignment / initialization operator, `=` 6126 * 6127 * Note: operator assignment `op=` has a different base class, `BinAssignExp` 6128 */ 6129 extern (C++) class AssignExp : BinExp 6130 { 6131 MemorySet memset; 6132 6133 /************************************************************/ 6134 /* op can be EXP.assign, EXP.construct, or EXP.blit */ 6135 extern (D) this(const ref Loc loc, Expression e1, Expression e2) 6136 { 6137 super(loc, EXP.assign, e1, e2); 6138 } 6139 6140 this(const ref Loc loc, EXP tok, Expression e1, Expression e2) 6141 { 6142 super(loc, tok, e1, e2); 6143 } 6144 6145 override final bool isLvalue() 6146 { 6147 // Array-op 'x[] = y[]' should make an rvalue. 6148 // Setting array length 'x.length = v' should make an rvalue. 6149 if (e1.op == EXP.slice || e1.op == EXP.arrayLength) 6150 { 6151 return false; 6152 } 6153 return true; 6154 } 6155 6156 override final Expression toLvalue(Scope* sc, Expression ex) 6157 { 6158 if (e1.op == EXP.slice || e1.op == EXP.arrayLength) 6159 { 6160 return Expression.toLvalue(sc, ex); 6161 } 6162 6163 /* In front-end level, AssignExp should make an lvalue of e1. 6164 * Taking the address of e1 will be handled in low level layer, 6165 * so this function does nothing. 6166 */ 6167 return this; 6168 } 6169 6170 override void accept(Visitor v) 6171 { 6172 v.visit(this); 6173 } 6174 } 6175 6176 /*********************************************************** 6177 * When an assignment expression is lowered to a druntime call 6178 * this class is used to store the lowering. 6179 * It essentially behaves the same as an AssignExp, but it is 6180 * used to not waste space for other AssignExp that are not 6181 * lowered to anything. 6182 */ 6183 extern (C++) final class LoweredAssignExp : AssignExp 6184 { 6185 Expression lowering; 6186 extern (D) this(AssignExp exp, Expression lowering) 6187 { 6188 super(exp.loc, EXP.loweredAssignExp, exp.e1, exp.e2); 6189 this.lowering = lowering; 6190 } 6191 6192 override const(char)* toChars() const 6193 { 6194 return lowering.toChars(); 6195 } 6196 override void accept(Visitor v) 6197 { 6198 v.visit(this); 6199 } 6200 } 6201 6202 /*********************************************************** 6203 */ 6204 extern (C++) final class ConstructExp : AssignExp 6205 { 6206 extern (D) this(const ref Loc loc, Expression e1, Expression e2) 6207 { 6208 super(loc, EXP.construct, e1, e2); 6209 } 6210 6211 // Internal use only. If `v` is a reference variable, the assignment 6212 // will become a reference initialization automatically. 6213 extern (D) this(const ref Loc loc, VarDeclaration v, Expression e2) 6214 { 6215 auto ve = new VarExp(loc, v); 6216 assert(v.type && ve.type); 6217 6218 super(loc, EXP.construct, ve, e2); 6219 6220 if (v.isReference()) 6221 memset = MemorySet.referenceInit; 6222 } 6223 6224 override void accept(Visitor v) 6225 { 6226 v.visit(this); 6227 } 6228 } 6229 6230 /*********************************************************** 6231 * A bit-for-bit copy from `e2` to `e1` 6232 */ 6233 extern (C++) final class BlitExp : AssignExp 6234 { 6235 extern (D) this(const ref Loc loc, Expression e1, Expression e2) 6236 { 6237 super(loc, EXP.blit, e1, e2); 6238 } 6239 6240 // Internal use only. If `v` is a reference variable, the assinment 6241 // will become a reference rebinding automatically. 6242 extern (D) this(const ref Loc loc, VarDeclaration v, Expression e2) 6243 { 6244 auto ve = new VarExp(loc, v); 6245 assert(v.type && ve.type); 6246 6247 super(loc, EXP.blit, ve, e2); 6248 6249 if (v.isReference()) 6250 memset = MemorySet.referenceInit; 6251 } 6252 6253 override void accept(Visitor v) 6254 { 6255 v.visit(this); 6256 } 6257 } 6258 6259 /*********************************************************** 6260 * `x += y` 6261 */ 6262 extern (C++) final class AddAssignExp : BinAssignExp 6263 { 6264 extern (D) this(const ref Loc loc, Expression e1, Expression e2) 6265 { 6266 super(loc, EXP.addAssign, e1, e2); 6267 } 6268 6269 override void accept(Visitor v) 6270 { 6271 v.visit(this); 6272 } 6273 } 6274 6275 /*********************************************************** 6276 * `x -= y` 6277 */ 6278 extern (C++) final class MinAssignExp : BinAssignExp 6279 { 6280 extern (D) this(const ref Loc loc, Expression e1, Expression e2) 6281 { 6282 super(loc, EXP.minAssign, e1, e2); 6283 } 6284 6285 override void accept(Visitor v) 6286 { 6287 v.visit(this); 6288 } 6289 } 6290 6291 /*********************************************************** 6292 * `x *= y` 6293 */ 6294 extern (C++) final class MulAssignExp : BinAssignExp 6295 { 6296 extern (D) this(const ref Loc loc, Expression e1, Expression e2) 6297 { 6298 super(loc, EXP.mulAssign, e1, e2); 6299 } 6300 6301 override void accept(Visitor v) 6302 { 6303 v.visit(this); 6304 } 6305 } 6306 6307 /*********************************************************** 6308 * `x /= y` 6309 */ 6310 extern (C++) final class DivAssignExp : BinAssignExp 6311 { 6312 extern (D) this(const ref Loc loc, Expression e1, Expression e2) 6313 { 6314 super(loc, EXP.divAssign, e1, e2); 6315 } 6316 6317 override void accept(Visitor v) 6318 { 6319 v.visit(this); 6320 } 6321 } 6322 6323 /*********************************************************** 6324 * `x %= y` 6325 */ 6326 extern (C++) final class ModAssignExp : BinAssignExp 6327 { 6328 extern (D) this(const ref Loc loc, Expression e1, Expression e2) 6329 { 6330 super(loc, EXP.modAssign, e1, e2); 6331 } 6332 6333 override void accept(Visitor v) 6334 { 6335 v.visit(this); 6336 } 6337 } 6338 6339 /*********************************************************** 6340 * `x &= y` 6341 */ 6342 extern (C++) final class AndAssignExp : BinAssignExp 6343 { 6344 extern (D) this(const ref Loc loc, Expression e1, Expression e2) 6345 { 6346 super(loc, EXP.andAssign, e1, e2); 6347 } 6348 6349 override void accept(Visitor v) 6350 { 6351 v.visit(this); 6352 } 6353 } 6354 6355 /*********************************************************** 6356 * `x |= y` 6357 */ 6358 extern (C++) final class OrAssignExp : BinAssignExp 6359 { 6360 extern (D) this(const ref Loc loc, Expression e1, Expression e2) 6361 { 6362 super(loc, EXP.orAssign, e1, e2); 6363 } 6364 6365 override void accept(Visitor v) 6366 { 6367 v.visit(this); 6368 } 6369 } 6370 6371 /*********************************************************** 6372 * `x ^= y` 6373 */ 6374 extern (C++) final class XorAssignExp : BinAssignExp 6375 { 6376 extern (D) this(const ref Loc loc, Expression e1, Expression e2) 6377 { 6378 super(loc, EXP.xorAssign, e1, e2); 6379 } 6380 6381 override void accept(Visitor v) 6382 { 6383 v.visit(this); 6384 } 6385 } 6386 6387 /*********************************************************** 6388 * `x ^^= y` 6389 */ 6390 extern (C++) final class PowAssignExp : BinAssignExp 6391 { 6392 extern (D) this(const ref Loc loc, Expression e1, Expression e2) 6393 { 6394 super(loc, EXP.powAssign, e1, e2); 6395 } 6396 6397 override void accept(Visitor v) 6398 { 6399 v.visit(this); 6400 } 6401 } 6402 6403 /*********************************************************** 6404 * `x <<= y` 6405 */ 6406 extern (C++) final class ShlAssignExp : BinAssignExp 6407 { 6408 extern (D) this(const ref Loc loc, Expression e1, Expression e2) 6409 { 6410 super(loc, EXP.leftShiftAssign, e1, e2); 6411 } 6412 6413 override void accept(Visitor v) 6414 { 6415 v.visit(this); 6416 } 6417 } 6418 6419 /*********************************************************** 6420 * `x >>= y` 6421 */ 6422 extern (C++) final class ShrAssignExp : BinAssignExp 6423 { 6424 extern (D) this(const ref Loc loc, Expression e1, Expression e2) 6425 { 6426 super(loc, EXP.rightShiftAssign, e1, e2); 6427 } 6428 6429 override void accept(Visitor v) 6430 { 6431 v.visit(this); 6432 } 6433 } 6434 6435 /*********************************************************** 6436 * `x >>>= y` 6437 */ 6438 extern (C++) final class UshrAssignExp : BinAssignExp 6439 { 6440 extern (D) this(const ref Loc loc, Expression e1, Expression e2) 6441 { 6442 super(loc, EXP.unsignedRightShiftAssign, e1, e2); 6443 } 6444 6445 override void accept(Visitor v) 6446 { 6447 v.visit(this); 6448 } 6449 } 6450 6451 /*********************************************************** 6452 * The `~=` operator. 6453 * 6454 * It can have one of the following operators: 6455 * 6456 * EXP.concatenateAssign - appending T[] to T[] 6457 * EXP.concatenateElemAssign - appending T to T[] 6458 * EXP.concatenateDcharAssign - appending dchar to T[] 6459 * 6460 * The parser initially sets it to EXP.concatenateAssign, and semantic() later decides which 6461 * of the three it will be set to. 6462 */ 6463 extern (C++) class CatAssignExp : BinAssignExp 6464 { 6465 extern (D) this(const ref Loc loc, Expression e1, Expression e2) 6466 { 6467 super(loc, EXP.concatenateAssign, e1, e2); 6468 } 6469 6470 extern (D) this(const ref Loc loc, EXP tok, Expression e1, Expression e2) 6471 { 6472 super(loc, tok, e1, e2); 6473 } 6474 6475 override void accept(Visitor v) 6476 { 6477 v.visit(this); 6478 } 6479 } 6480 6481 /*********************************************************** 6482 * The `~=` operator when appending a single element 6483 */ 6484 extern (C++) final class CatElemAssignExp : CatAssignExp 6485 { 6486 extern (D) this(const ref Loc loc, Type type, Expression e1, Expression e2) 6487 { 6488 super(loc, EXP.concatenateElemAssign, e1, e2); 6489 this.type = type; 6490 } 6491 6492 override void accept(Visitor v) 6493 { 6494 v.visit(this); 6495 } 6496 } 6497 6498 /*********************************************************** 6499 * The `~=` operator when appending a single `dchar` 6500 */ 6501 extern (C++) final class CatDcharAssignExp : CatAssignExp 6502 { 6503 extern (D) this(const ref Loc loc, Type type, Expression e1, Expression e2) 6504 { 6505 super(loc, EXP.concatenateDcharAssign, e1, e2); 6506 this.type = type; 6507 } 6508 6509 override void accept(Visitor v) 6510 { 6511 v.visit(this); 6512 } 6513 } 6514 6515 /*********************************************************** 6516 * The addition operator, `x + y` 6517 * 6518 * https://dlang.org/spec/expression.html#add_expressions 6519 */ 6520 extern (C++) final class AddExp : BinExp 6521 { 6522 extern (D) this(const ref Loc loc, Expression e1, Expression e2) 6523 { 6524 super(loc, EXP.add, e1, e2); 6525 } 6526 6527 override void accept(Visitor v) 6528 { 6529 v.visit(this); 6530 } 6531 } 6532 6533 /*********************************************************** 6534 * The minus operator, `x - y` 6535 * 6536 * https://dlang.org/spec/expression.html#add_expressions 6537 */ 6538 extern (C++) final class MinExp : BinExp 6539 { 6540 extern (D) this(const ref Loc loc, Expression e1, Expression e2) 6541 { 6542 super(loc, EXP.min, e1, e2); 6543 } 6544 6545 override void accept(Visitor v) 6546 { 6547 v.visit(this); 6548 } 6549 } 6550 6551 /*********************************************************** 6552 * The concatenation operator, `x ~ y` 6553 * 6554 * https://dlang.org/spec/expression.html#cat_expressions 6555 */ 6556 extern (C++) final class CatExp : BinExp 6557 { 6558 Expression lowering; // call to druntime hook `_d_arraycatnTX` 6559 6560 extern (D) this(const ref Loc loc, Expression e1, Expression e2) scope 6561 { 6562 super(loc, EXP.concatenate, e1, e2); 6563 } 6564 6565 override Expression resolveLoc(const ref Loc loc, Scope* sc) 6566 { 6567 e1 = e1.resolveLoc(loc, sc); 6568 e2 = e2.resolveLoc(loc, sc); 6569 return this; 6570 } 6571 6572 override void accept(Visitor v) 6573 { 6574 v.visit(this); 6575 } 6576 } 6577 6578 /*********************************************************** 6579 * The multiplication operator, `x * y` 6580 * 6581 * https://dlang.org/spec/expression.html#mul_expressions 6582 */ 6583 extern (C++) final class MulExp : BinExp 6584 { 6585 extern (D) this(const ref Loc loc, Expression e1, Expression e2) 6586 { 6587 super(loc, EXP.mul, e1, e2); 6588 } 6589 6590 override void accept(Visitor v) 6591 { 6592 v.visit(this); 6593 } 6594 } 6595 6596 /*********************************************************** 6597 * The division operator, `x / y` 6598 * 6599 * https://dlang.org/spec/expression.html#mul_expressions 6600 */ 6601 extern (C++) final class DivExp : BinExp 6602 { 6603 extern (D) this(const ref Loc loc, Expression e1, Expression e2) 6604 { 6605 super(loc, EXP.div, e1, e2); 6606 } 6607 6608 override void accept(Visitor v) 6609 { 6610 v.visit(this); 6611 } 6612 } 6613 6614 /*********************************************************** 6615 * The modulo operator, `x % y` 6616 * 6617 * https://dlang.org/spec/expression.html#mul_expressions 6618 */ 6619 extern (C++) final class ModExp : BinExp 6620 { 6621 extern (D) this(const ref Loc loc, Expression e1, Expression e2) 6622 { 6623 super(loc, EXP.mod, e1, e2); 6624 } 6625 6626 override void accept(Visitor v) 6627 { 6628 v.visit(this); 6629 } 6630 } 6631 6632 /*********************************************************** 6633 * The 'power' operator, `x ^^ y` 6634 * 6635 * https://dlang.org/spec/expression.html#pow_expressions 6636 */ 6637 extern (C++) final class PowExp : BinExp 6638 { 6639 extern (D) this(const ref Loc loc, Expression e1, Expression e2) 6640 { 6641 super(loc, EXP.pow, e1, e2); 6642 } 6643 6644 override void accept(Visitor v) 6645 { 6646 v.visit(this); 6647 } 6648 } 6649 6650 /*********************************************************** 6651 * The 'shift left' operator, `x << y` 6652 * 6653 * https://dlang.org/spec/expression.html#shift_expressions 6654 */ 6655 extern (C++) final class ShlExp : BinExp 6656 { 6657 extern (D) this(const ref Loc loc, Expression e1, Expression e2) 6658 { 6659 super(loc, EXP.leftShift, e1, e2); 6660 } 6661 6662 override void accept(Visitor v) 6663 { 6664 v.visit(this); 6665 } 6666 } 6667 6668 /*********************************************************** 6669 * The 'shift right' operator, `x >> y` 6670 * 6671 * https://dlang.org/spec/expression.html#shift_expressions 6672 */ 6673 extern (C++) final class ShrExp : BinExp 6674 { 6675 extern (D) this(const ref Loc loc, Expression e1, Expression e2) 6676 { 6677 super(loc, EXP.rightShift, e1, e2); 6678 } 6679 6680 override void accept(Visitor v) 6681 { 6682 v.visit(this); 6683 } 6684 } 6685 6686 /*********************************************************** 6687 * The 'unsigned shift right' operator, `x >>> y` 6688 * 6689 * https://dlang.org/spec/expression.html#shift_expressions 6690 */ 6691 extern (C++) final class UshrExp : BinExp 6692 { 6693 extern (D) this(const ref Loc loc, Expression e1, Expression e2) 6694 { 6695 super(loc, EXP.unsignedRightShift, e1, e2); 6696 } 6697 6698 override void accept(Visitor v) 6699 { 6700 v.visit(this); 6701 } 6702 } 6703 6704 /*********************************************************** 6705 * The bitwise 'and' operator, `x & y` 6706 * 6707 * https://dlang.org/spec/expression.html#and_expressions 6708 */ 6709 extern (C++) final class AndExp : BinExp 6710 { 6711 extern (D) this(const ref Loc loc, Expression e1, Expression e2) 6712 { 6713 super(loc, EXP.and, e1, e2); 6714 } 6715 6716 override void accept(Visitor v) 6717 { 6718 v.visit(this); 6719 } 6720 } 6721 6722 /*********************************************************** 6723 * The bitwise 'or' operator, `x | y` 6724 * 6725 * https://dlang.org/spec/expression.html#or_expressions 6726 */ 6727 extern (C++) final class OrExp : BinExp 6728 { 6729 extern (D) this(const ref Loc loc, Expression e1, Expression e2) 6730 { 6731 super(loc, EXP.or, e1, e2); 6732 } 6733 6734 override void accept(Visitor v) 6735 { 6736 v.visit(this); 6737 } 6738 } 6739 6740 /*********************************************************** 6741 * The bitwise 'xor' operator, `x ^ y` 6742 * 6743 * https://dlang.org/spec/expression.html#xor_expressions 6744 */ 6745 extern (C++) final class XorExp : BinExp 6746 { 6747 extern (D) this(const ref Loc loc, Expression e1, Expression e2) 6748 { 6749 super(loc, EXP.xor, e1, e2); 6750 } 6751 6752 override void accept(Visitor v) 6753 { 6754 v.visit(this); 6755 } 6756 } 6757 6758 /*********************************************************** 6759 * The logical 'and' / 'or' operator, `X && Y` / `X || Y` 6760 * 6761 * https://dlang.org/spec/expression.html#andand_expressions 6762 * https://dlang.org/spec/expression.html#oror_expressions 6763 */ 6764 extern (C++) final class LogicalExp : BinExp 6765 { 6766 extern (D) this(const ref Loc loc, EXP op, Expression e1, Expression e2) 6767 { 6768 super(loc, op, e1, e2); 6769 assert(op == EXP.andAnd || op == EXP.orOr); 6770 } 6771 6772 override void accept(Visitor v) 6773 { 6774 v.visit(this); 6775 } 6776 } 6777 6778 /*********************************************************** 6779 * A comparison operator, `<` `<=` `>` `>=` 6780 * 6781 * `op` is one of: 6782 * EXP.lessThan, EXP.lessOrEqual, EXP.greaterThan, EXP.greaterOrEqual 6783 * 6784 * https://dlang.org/spec/expression.html#relation_expressions 6785 */ 6786 extern (C++) final class CmpExp : BinExp 6787 { 6788 extern (D) this(EXP op, const ref Loc loc, Expression e1, Expression e2) 6789 { 6790 super(loc, op, e1, e2); 6791 assert(op == EXP.lessThan || op == EXP.lessOrEqual || op == EXP.greaterThan || op == EXP.greaterOrEqual); 6792 } 6793 6794 override void accept(Visitor v) 6795 { 6796 v.visit(this); 6797 } 6798 } 6799 6800 /*********************************************************** 6801 * The `in` operator, `"a" in ["a": 1]` 6802 * 6803 * Note: `x !in y` is rewritten to `!(x in y)` in the parser 6804 * 6805 * https://dlang.org/spec/expression.html#in_expressions 6806 */ 6807 extern (C++) final class InExp : BinExp 6808 { 6809 extern (D) this(const ref Loc loc, Expression e1, Expression e2) 6810 { 6811 super(loc, EXP.in_, e1, e2); 6812 } 6813 6814 override void accept(Visitor v) 6815 { 6816 v.visit(this); 6817 } 6818 } 6819 6820 /*********************************************************** 6821 * Associative array removal, `aa.remove(arg)` 6822 * 6823 * This deletes the key e1 from the associative array e2 6824 */ 6825 extern (C++) final class RemoveExp : BinExp 6826 { 6827 extern (D) this(const ref Loc loc, Expression e1, Expression e2) 6828 { 6829 super(loc, EXP.remove, e1, e2); 6830 type = Type.tbool; 6831 } 6832 6833 override void accept(Visitor v) 6834 { 6835 v.visit(this); 6836 } 6837 } 6838 6839 /*********************************************************** 6840 * `==` and `!=` 6841 * 6842 * EXP.equal and EXP.notEqual 6843 * 6844 * https://dlang.org/spec/expression.html#equality_expressions 6845 */ 6846 extern (C++) final class EqualExp : BinExp 6847 { 6848 extern (D) this(EXP op, const ref Loc loc, Expression e1, Expression e2) 6849 { 6850 super(loc, op, e1, e2); 6851 assert(op == EXP.equal || op == EXP.notEqual); 6852 } 6853 6854 override void accept(Visitor v) 6855 { 6856 v.visit(this); 6857 } 6858 } 6859 6860 /*********************************************************** 6861 * `is` and `!is` 6862 * 6863 * EXP.identity and EXP.notIdentity 6864 * 6865 * https://dlang.org/spec/expression.html#identity_expressions 6866 */ 6867 extern (C++) final class IdentityExp : BinExp 6868 { 6869 extern (D) this(EXP op, const ref Loc loc, Expression e1, Expression e2) 6870 { 6871 super(loc, op, e1, e2); 6872 assert(op == EXP.identity || op == EXP.notIdentity); 6873 } 6874 6875 override void accept(Visitor v) 6876 { 6877 v.visit(this); 6878 } 6879 } 6880 6881 /*********************************************************** 6882 * The ternary operator, `econd ? e1 : e2` 6883 * 6884 * https://dlang.org/spec/expression.html#conditional_expressions 6885 */ 6886 extern (C++) final class CondExp : BinExp 6887 { 6888 Expression econd; 6889 6890 extern (D) this(const ref Loc loc, Expression econd, Expression e1, Expression e2) scope 6891 { 6892 super(loc, EXP.question, e1, e2); 6893 this.econd = econd; 6894 } 6895 6896 override CondExp syntaxCopy() 6897 { 6898 return new CondExp(loc, econd.syntaxCopy(), e1.syntaxCopy(), e2.syntaxCopy()); 6899 } 6900 6901 override bool isLvalue() 6902 { 6903 return e1.isLvalue() && e2.isLvalue(); 6904 } 6905 6906 override Expression toLvalue(Scope* sc, Expression ex) 6907 { 6908 // convert (econd ? e1 : e2) to *(econd ? &e1 : &e2) 6909 CondExp e = cast(CondExp)copy(); 6910 e.e1 = e1.toLvalue(sc, null).addressOf(); 6911 e.e2 = e2.toLvalue(sc, null).addressOf(); 6912 e.type = type.pointerTo(); 6913 return new PtrExp(loc, e, type); 6914 } 6915 6916 override Expression modifiableLvalue(Scope* sc, Expression e) 6917 { 6918 if (!e1.isLvalue() && !e2.isLvalue()) 6919 { 6920 error("conditional expression `%s` is not a modifiable lvalue", toChars()); 6921 return ErrorExp.get(); 6922 } 6923 e1 = e1.modifiableLvalue(sc, e1); 6924 e2 = e2.modifiableLvalue(sc, e2); 6925 return toLvalue(sc, this); 6926 } 6927 6928 void hookDtors(Scope* sc) 6929 { 6930 extern (C++) final class DtorVisitor : StoppableVisitor 6931 { 6932 alias visit = typeof(super).visit; 6933 public: 6934 Scope* sc; 6935 CondExp ce; 6936 VarDeclaration vcond; 6937 bool isThen; 6938 6939 extern (D) this(Scope* sc, CondExp ce) 6940 { 6941 this.sc = sc; 6942 this.ce = ce; 6943 } 6944 6945 override void visit(Expression e) 6946 { 6947 //printf("(e = %s)\n", e.toChars()); 6948 } 6949 6950 override void visit(DeclarationExp e) 6951 { 6952 auto v = e.declaration.isVarDeclaration(); 6953 if (v && !v.isDataseg()) 6954 { 6955 if (v._init) 6956 { 6957 if (auto ei = v._init.isExpInitializer()) 6958 walkPostorder(ei.exp, this); 6959 } 6960 6961 if (v.edtor) 6962 walkPostorder(v.edtor, this); 6963 6964 if (v.needsScopeDtor()) 6965 { 6966 if (!vcond) 6967 { 6968 vcond = copyToTemp(STC.volatile_ | STC.const_, "__cond", ce.econd); 6969 vcond.dsymbolSemantic(sc); 6970 6971 Expression de = new DeclarationExp(ce.econd.loc, vcond); 6972 de = de.expressionSemantic(sc); 6973 6974 Expression ve = new VarExp(ce.econd.loc, vcond); 6975 ce.econd = Expression.combine(de, ve); 6976 } 6977 6978 //printf("\t++v = %s, v.edtor = %s\n", v.toChars(), v.edtor.toChars()); 6979 Expression ve = new VarExp(vcond.loc, vcond); 6980 if (isThen) 6981 v.edtor = new LogicalExp(v.edtor.loc, EXP.andAnd, ve, v.edtor); 6982 else 6983 v.edtor = new LogicalExp(v.edtor.loc, EXP.orOr, ve, v.edtor); 6984 v.edtor = v.edtor.expressionSemantic(sc); 6985 //printf("\t--v = %s, v.edtor = %s\n", v.toChars(), v.edtor.toChars()); 6986 } 6987 } 6988 } 6989 } 6990 6991 scope DtorVisitor v = new DtorVisitor(sc, this); 6992 //printf("+%s\n", toChars()); 6993 v.isThen = true; 6994 walkPostorder(e1, v); 6995 v.isThen = false; 6996 walkPostorder(e2, v); 6997 //printf("-%s\n", toChars()); 6998 } 6999 7000 override void accept(Visitor v) 7001 { 7002 v.visit(this); 7003 } 7004 } 7005 7006 /// Returns: if this token is the `op` for a derived `DefaultInitExp` class. 7007 bool isDefaultInitOp(EXP op) pure nothrow @safe @nogc 7008 { 7009 return op == EXP.prettyFunction || op == EXP.functionString || 7010 op == EXP.line || op == EXP.moduleString || 7011 op == EXP.file || op == EXP.fileFullPath ; 7012 } 7013 7014 /*********************************************************** 7015 * A special keyword when used as a function's default argument 7016 * 7017 * When possible, special keywords are resolved in the parser, but when 7018 * appearing as a default argument, they result in an expression deriving 7019 * from this base class that is resolved for each function call. 7020 * 7021 * --- 7022 * const x = __LINE__; // resolved in the parser 7023 * void foo(string file = __FILE__, int line = __LINE__); // DefaultInitExp 7024 * --- 7025 * 7026 * https://dlang.org/spec/expression.html#specialkeywords 7027 */ 7028 extern (C++) class DefaultInitExp : Expression 7029 { 7030 extern (D) this(const ref Loc loc, EXP op) 7031 { 7032 super(loc, op); 7033 } 7034 7035 override void accept(Visitor v) 7036 { 7037 v.visit(this); 7038 } 7039 } 7040 7041 /*********************************************************** 7042 * The `__FILE__` token as a default argument 7043 */ 7044 extern (C++) final class FileInitExp : DefaultInitExp 7045 { 7046 extern (D) this(const ref Loc loc, EXP tok) 7047 { 7048 super(loc, tok); 7049 } 7050 7051 override Expression resolveLoc(const ref Loc loc, Scope* sc) 7052 { 7053 //printf("FileInitExp::resolve() %s\n", toChars()); 7054 const(char)* s; 7055 if (op == EXP.fileFullPath) 7056 s = FileName.toAbsolute(loc.isValid() ? loc.filename : sc._module.srcfile.toChars()); 7057 else 7058 s = loc.isValid() ? loc.filename : sc._module.ident.toChars(); 7059 7060 Expression e = new StringExp(loc, s.toDString()); 7061 e = e.expressionSemantic(sc); 7062 e = e.castTo(sc, type); 7063 return e; 7064 } 7065 7066 override void accept(Visitor v) 7067 { 7068 v.visit(this); 7069 } 7070 } 7071 7072 /*********************************************************** 7073 * The `__LINE__` token as a default argument 7074 */ 7075 extern (C++) final class LineInitExp : DefaultInitExp 7076 { 7077 extern (D) this(const ref Loc loc) 7078 { 7079 super(loc, EXP.line); 7080 } 7081 7082 override Expression resolveLoc(const ref Loc loc, Scope* sc) 7083 { 7084 Expression e = new IntegerExp(loc, loc.linnum, Type.tint32); 7085 e = e.castTo(sc, type); 7086 return e; 7087 } 7088 7089 override void accept(Visitor v) 7090 { 7091 v.visit(this); 7092 } 7093 } 7094 7095 /*********************************************************** 7096 * The `__MODULE__` token as a default argument 7097 */ 7098 extern (C++) final class ModuleInitExp : DefaultInitExp 7099 { 7100 extern (D) this(const ref Loc loc) 7101 { 7102 super(loc, EXP.moduleString); 7103 } 7104 7105 override Expression resolveLoc(const ref Loc loc, Scope* sc) 7106 { 7107 const auto s = (sc.callsc ? sc.callsc : sc)._module.toPrettyChars().toDString(); 7108 Expression e = new StringExp(loc, s); 7109 e = e.expressionSemantic(sc); 7110 e = e.castTo(sc, type); 7111 return e; 7112 } 7113 7114 override void accept(Visitor v) 7115 { 7116 v.visit(this); 7117 } 7118 } 7119 7120 /*********************************************************** 7121 * The `__FUNCTION__` token as a default argument 7122 */ 7123 extern (C++) final class FuncInitExp : DefaultInitExp 7124 { 7125 extern (D) this(const ref Loc loc) 7126 { 7127 super(loc, EXP.functionString); 7128 } 7129 7130 override Expression resolveLoc(const ref Loc loc, Scope* sc) 7131 { 7132 const(char)* s; 7133 if (sc.callsc && sc.callsc.func) 7134 s = sc.callsc.func.Dsymbol.toPrettyChars(); 7135 else if (sc.func) 7136 s = sc.func.Dsymbol.toPrettyChars(); 7137 else 7138 s = ""; 7139 Expression e = new StringExp(loc, s.toDString()); 7140 e = e.expressionSemantic(sc); 7141 e.type = Type.tstring; 7142 return e; 7143 } 7144 7145 override void accept(Visitor v) 7146 { 7147 v.visit(this); 7148 } 7149 } 7150 7151 /*********************************************************** 7152 * The `__PRETTY_FUNCTION__` token as a default argument 7153 */ 7154 extern (C++) final class PrettyFuncInitExp : DefaultInitExp 7155 { 7156 extern (D) this(const ref Loc loc) 7157 { 7158 super(loc, EXP.prettyFunction); 7159 } 7160 7161 override Expression resolveLoc(const ref Loc loc, Scope* sc) 7162 { 7163 FuncDeclaration fd = (sc.callsc && sc.callsc.func) 7164 ? sc.callsc.func 7165 : sc.func; 7166 7167 const(char)* s; 7168 if (fd) 7169 { 7170 const funcStr = fd.Dsymbol.toPrettyChars(); 7171 OutBuffer buf; 7172 functionToBufferWithIdent(fd.type.isTypeFunction(), &buf, funcStr, fd.isStatic); 7173 s = buf.extractChars(); 7174 } 7175 else 7176 { 7177 s = ""; 7178 } 7179 7180 Expression e = new StringExp(loc, s.toDString()); 7181 e = e.expressionSemantic(sc); 7182 e.type = Type.tstring; 7183 return e; 7184 } 7185 7186 override void accept(Visitor v) 7187 { 7188 v.visit(this); 7189 } 7190 } 7191 7192 /** 7193 * Objective-C class reference expression. 7194 * 7195 * Used to get the metaclass of an Objective-C class, `NSObject.Class`. 7196 */ 7197 extern (C++) final class ObjcClassReferenceExp : Expression 7198 { 7199 ClassDeclaration classDeclaration; 7200 7201 extern (D) this(const ref Loc loc, ClassDeclaration classDeclaration) 7202 { 7203 super(loc, EXP.objcClassReference); 7204 this.classDeclaration = classDeclaration; 7205 type = objc.getRuntimeMetaclass(classDeclaration).getType(); 7206 } 7207 7208 override void accept(Visitor v) 7209 { 7210 v.visit(this); 7211 } 7212 } 7213 7214 /******************* 7215 * C11 6.5.1.1 Generic Selection 7216 * For ImportC 7217 */ 7218 extern (C++) final class GenericExp : Expression 7219 { 7220 Expression cntlExp; /// controlling expression of a generic selection (not evaluated) 7221 Types* types; /// type-names for generic associations (null entry for `default`) 7222 Expressions* exps; /// 1:1 mapping of typeNames to exps 7223 7224 extern (D) this(const ref Loc loc, Expression cntlExp, Types* types, Expressions* exps) 7225 { 7226 super(loc, EXP._Generic); 7227 this.cntlExp = cntlExp; 7228 this.types = types; 7229 this.exps = exps; 7230 assert(types.length == exps.length); // must be the same and >=1 7231 } 7232 7233 override GenericExp syntaxCopy() 7234 { 7235 return new GenericExp(loc, cntlExp.syntaxCopy(), Type.arraySyntaxCopy(types), Expression.arraySyntaxCopy(exps)); 7236 } 7237 7238 override void accept(Visitor v) 7239 { 7240 v.visit(this); 7241 } 7242 } 7243 7244 /*************************************** 7245 * Parameters: 7246 * sc: scope 7247 * flag: 1: do not issue error message for invalid modification 7248 2: the exp is a DotVarExp and a subfield of the leftmost 7249 variable is modified 7250 * Returns: 7251 * Whether the type is modifiable 7252 */ 7253 extern(D) Modifiable checkModifiable(Expression exp, Scope* sc, ModifyFlags flag = ModifyFlags.none) 7254 { 7255 switch(exp.op) 7256 { 7257 case EXP.variable: 7258 auto varExp = cast(VarExp)exp; 7259 7260 //printf("VarExp::checkModifiable %s", varExp.toChars()); 7261 assert(varExp.type); 7262 return varExp.var.checkModify(varExp.loc, sc, null, flag); 7263 7264 case EXP.dotVariable: 7265 auto dotVarExp = cast(DotVarExp)exp; 7266 7267 //printf("DotVarExp::checkModifiable %s %s\n", dotVarExp.toChars(), dotVarExp.type.toChars()); 7268 if (dotVarExp.e1.op == EXP.this_) 7269 return dotVarExp.var.checkModify(dotVarExp.loc, sc, dotVarExp.e1, flag); 7270 7271 /* https://issues.dlang.org/show_bug.cgi?id=12764 7272 * If inside a constructor and an expression of type `this.field.var` 7273 * is encountered, where `field` is a struct declaration with 7274 * default construction disabled, we must make sure that 7275 * assigning to `var` does not imply that `field` was initialized 7276 */ 7277 if (sc.func && sc.func.isCtorDeclaration()) 7278 { 7279 // if inside a constructor scope and e1 of this DotVarExp 7280 // is another DotVarExp, then check if the leftmost expression is a `this` identifier 7281 if (auto dve = dotVarExp.e1.isDotVarExp()) 7282 { 7283 // Iterate the chain of DotVarExp to find `this` 7284 // Keep track whether access to fields was limited to union members 7285 // s.t. one can initialize an entire struct inside nested unions 7286 // (but not its members) 7287 bool onlyUnion = true; 7288 while (true) 7289 { 7290 auto v = dve.var.isVarDeclaration(); 7291 assert(v); 7292 7293 // Accessing union member? 7294 auto t = v.type.isTypeStruct(); 7295 if (!t || !t.sym.isUnionDeclaration()) 7296 onlyUnion = false; 7297 7298 // Another DotVarExp left? 7299 if (!dve.e1 || dve.e1.op != EXP.dotVariable) 7300 break; 7301 7302 dve = cast(DotVarExp) dve.e1; 7303 } 7304 7305 if (dve.e1.op == EXP.this_) 7306 { 7307 scope v = dve.var.isVarDeclaration(); 7308 /* if v is a struct member field with no initializer, no default construction 7309 * and v wasn't intialized before 7310 */ 7311 if (v && v.isField() && !v._init && !v.ctorinit) 7312 { 7313 if (auto ts = v.type.isTypeStruct()) 7314 { 7315 if (ts.sym.noDefaultCtor) 7316 { 7317 /* checkModify will consider that this is an initialization 7318 * of v while it is actually an assignment of a field of v 7319 */ 7320 scope modifyLevel = v.checkModify(dotVarExp.loc, sc, dve.e1, !onlyUnion ? (flag | ModifyFlags.fieldAssign) : flag); 7321 if (modifyLevel == Modifiable.initialization) 7322 { 7323 // https://issues.dlang.org/show_bug.cgi?id=22118 7324 // v is a union type field that was assigned 7325 // a variable, therefore it counts as initialization 7326 if (v.ctorinit) 7327 return Modifiable.initialization; 7328 7329 return Modifiable.yes; 7330 } 7331 return modifyLevel; 7332 } 7333 } 7334 } 7335 } 7336 } 7337 } 7338 7339 //printf("\te1 = %s\n", e1.toChars()); 7340 return dotVarExp.e1.checkModifiable(sc, flag); 7341 7342 case EXP.star: 7343 auto ptrExp = cast(PtrExp)exp; 7344 if (auto se = ptrExp.e1.isSymOffExp()) 7345 { 7346 return se.var.checkModify(ptrExp.loc, sc, null, flag); 7347 } 7348 else if (auto ae = ptrExp.e1.isAddrExp()) 7349 { 7350 return ae.e1.checkModifiable(sc, flag); 7351 } 7352 return Modifiable.yes; 7353 7354 case EXP.slice: 7355 auto sliceExp = cast(SliceExp)exp; 7356 7357 //printf("SliceExp::checkModifiable %s\n", sliceExp.toChars()); 7358 auto e1 = sliceExp.e1; 7359 if (e1.type.ty == Tsarray || (e1.op == EXP.index && e1.type.ty != Tarray) || e1.op == EXP.slice) 7360 { 7361 return e1.checkModifiable(sc, flag); 7362 } 7363 return Modifiable.yes; 7364 7365 case EXP.comma: 7366 return (cast(CommaExp)exp).e2.checkModifiable(sc, flag); 7367 7368 case EXP.index: 7369 auto indexExp = cast(IndexExp)exp; 7370 auto e1 = indexExp.e1; 7371 if (e1.type.ty == Tsarray || 7372 e1.type.ty == Taarray || 7373 (e1.op == EXP.index && e1.type.ty != Tarray) || 7374 e1.op == EXP.slice) 7375 { 7376 return e1.checkModifiable(sc, flag); 7377 } 7378 return Modifiable.yes; 7379 7380 case EXP.question: 7381 auto condExp = cast(CondExp)exp; 7382 if (condExp.e1.checkModifiable(sc, flag) != Modifiable.no 7383 && condExp.e2.checkModifiable(sc, flag) != Modifiable.no) 7384 return Modifiable.yes; 7385 return Modifiable.no; 7386 7387 default: 7388 return exp.type ? Modifiable.yes : Modifiable.no; // default modifiable 7389 } 7390 } 7391 7392 /** 7393 * Verify if the given identifier is any of 7394 * _d_array{ctor,setctor,setassign,assign_l, assign_r}. 7395 * 7396 * Params: 7397 * id = the identifier to verify 7398 * 7399 * Returns: 7400 * `true` if the identifier corresponds to a construction of assignement 7401 * runtime hook, `false` otherwise. 7402 */ 7403 bool isArrayConstructionOrAssign(const Identifier id) 7404 { 7405 import dmd.id : Id; 7406 7407 return id == Id._d_arrayctor || id == Id._d_arraysetctor || 7408 id == Id._d_arrayassign_l || id == Id._d_arrayassign_r || 7409 id == Id._d_arraysetassign; 7410 } 7411 7412 /****************************** 7413 * Provide efficient way to implement isUnaExp(), isBinExp(), isBinAssignExp() 7414 */ 7415 private immutable ubyte[EXP.max + 1] exptab = 7416 () { 7417 ubyte[EXP.max + 1] tab; 7418 with (EXPFLAGS) 7419 { 7420 foreach (i; Eunary) { tab[i] |= unary; } 7421 foreach (i; Ebinary) { tab[i] |= unary | binary; } 7422 foreach (i; EbinaryAssign) { tab[i] |= unary | binary | binaryAssign; } 7423 } 7424 return tab; 7425 } (); 7426 7427 private enum EXPFLAGS : ubyte 7428 { 7429 unary = 1, 7430 binary = 2, 7431 binaryAssign = 4, 7432 } 7433 7434 private enum Eunary = 7435 [ 7436 EXP.import_, EXP.assert_, EXP.throw_, EXP.dotIdentifier, EXP.dotTemplateDeclaration, 7437 EXP.dotVariable, EXP.dotTemplateInstance, EXP.delegate_, EXP.dotType, EXP.call, 7438 EXP.address, EXP.star, EXP.negate, EXP.uadd, EXP.tilde, EXP.not, EXP.delete_, EXP.cast_, 7439 EXP.vector, EXP.vectorArray, EXP.slice, EXP.arrayLength, EXP.array, EXP.delegatePointer, 7440 EXP.delegateFunctionPointer, EXP.preMinusMinus, EXP.prePlusPlus, 7441 ]; 7442 7443 private enum Ebinary = 7444 [ 7445 EXP.dot, EXP.comma, EXP.index, EXP.minusMinus, EXP.plusPlus, EXP.assign, 7446 EXP.add, EXP.min, EXP.concatenate, EXP.mul, EXP.div, EXP.mod, EXP.pow, EXP.leftShift, 7447 EXP.rightShift, EXP.unsignedRightShift, EXP.and, EXP.or, EXP.xor, EXP.andAnd, EXP.orOr, 7448 EXP.lessThan, EXP.lessOrEqual, EXP.greaterThan, EXP.greaterOrEqual, 7449 EXP.in_, EXP.remove, EXP.equal, EXP.notEqual, EXP.identity, EXP.notIdentity, 7450 EXP.question, 7451 EXP.construct, EXP.blit, 7452 ]; 7453 7454 private enum EbinaryAssign = 7455 [ 7456 EXP.addAssign, EXP.minAssign, EXP.mulAssign, EXP.divAssign, EXP.modAssign, 7457 EXP.andAssign, EXP.orAssign, EXP.xorAssign, EXP.powAssign, 7458 EXP.leftShiftAssign, EXP.rightShiftAssign, EXP.unsignedRightShiftAssign, 7459 EXP.concatenateAssign, EXP.concatenateElemAssign, EXP.concatenateDcharAssign, 7460 ]; 7461 7462 /// Given a member of the EXP enum, get the class instance size of the corresponding Expression class. 7463 /// Needed because the classes are `extern(C++)` 7464 private immutable ubyte[EXP.max+1] expSize = [ 7465 EXP.reserved: 0, 7466 EXP.negate: __traits(classInstanceSize, NegExp), 7467 EXP.cast_: __traits(classInstanceSize, CastExp), 7468 EXP.null_: __traits(classInstanceSize, NullExp), 7469 EXP.assert_: __traits(classInstanceSize, AssertExp), 7470 EXP.array: __traits(classInstanceSize, ArrayExp), 7471 EXP.call: __traits(classInstanceSize, CallExp), 7472 EXP.address: __traits(classInstanceSize, AddrExp), 7473 EXP.type: __traits(classInstanceSize, TypeExp), 7474 EXP.throw_: __traits(classInstanceSize, ThrowExp), 7475 EXP.new_: __traits(classInstanceSize, NewExp), 7476 EXP.delete_: __traits(classInstanceSize, DeleteExp), 7477 EXP.star: __traits(classInstanceSize, PtrExp), 7478 EXP.symbolOffset: __traits(classInstanceSize, SymOffExp), 7479 EXP.variable: __traits(classInstanceSize, VarExp), 7480 EXP.dotVariable: __traits(classInstanceSize, DotVarExp), 7481 EXP.dotIdentifier: __traits(classInstanceSize, DotIdExp), 7482 EXP.dotTemplateInstance: __traits(classInstanceSize, DotTemplateInstanceExp), 7483 EXP.dotType: __traits(classInstanceSize, DotTypeExp), 7484 EXP.slice: __traits(classInstanceSize, SliceExp), 7485 EXP.arrayLength: __traits(classInstanceSize, ArrayLengthExp), 7486 EXP.dollar: __traits(classInstanceSize, DollarExp), 7487 EXP.template_: __traits(classInstanceSize, TemplateExp), 7488 EXP.dotTemplateDeclaration: __traits(classInstanceSize, DotTemplateExp), 7489 EXP.declaration: __traits(classInstanceSize, DeclarationExp), 7490 EXP.dSymbol: __traits(classInstanceSize, DsymbolExp), 7491 EXP.typeid_: __traits(classInstanceSize, TypeidExp), 7492 EXP.uadd: __traits(classInstanceSize, UAddExp), 7493 EXP.remove: __traits(classInstanceSize, RemoveExp), 7494 EXP.newAnonymousClass: __traits(classInstanceSize, NewAnonClassExp), 7495 EXP.arrayLiteral: __traits(classInstanceSize, ArrayLiteralExp), 7496 EXP.assocArrayLiteral: __traits(classInstanceSize, AssocArrayLiteralExp), 7497 EXP.structLiteral: __traits(classInstanceSize, StructLiteralExp), 7498 EXP.classReference: __traits(classInstanceSize, ClassReferenceExp), 7499 EXP.thrownException: __traits(classInstanceSize, ThrownExceptionExp), 7500 EXP.delegatePointer: __traits(classInstanceSize, DelegatePtrExp), 7501 EXP.delegateFunctionPointer: __traits(classInstanceSize, DelegateFuncptrExp), 7502 EXP.lessThan: __traits(classInstanceSize, CmpExp), 7503 EXP.greaterThan: __traits(classInstanceSize, CmpExp), 7504 EXP.lessOrEqual: __traits(classInstanceSize, CmpExp), 7505 EXP.greaterOrEqual: __traits(classInstanceSize, CmpExp), 7506 EXP.equal: __traits(classInstanceSize, EqualExp), 7507 EXP.notEqual: __traits(classInstanceSize, EqualExp), 7508 EXP.identity: __traits(classInstanceSize, IdentityExp), 7509 EXP.notIdentity: __traits(classInstanceSize, IdentityExp), 7510 EXP.index: __traits(classInstanceSize, IndexExp), 7511 EXP.is_: __traits(classInstanceSize, IsExp), 7512 EXP.leftShift: __traits(classInstanceSize, ShlExp), 7513 EXP.rightShift: __traits(classInstanceSize, ShrExp), 7514 EXP.leftShiftAssign: __traits(classInstanceSize, ShlAssignExp), 7515 EXP.rightShiftAssign: __traits(classInstanceSize, ShrAssignExp), 7516 EXP.unsignedRightShift: __traits(classInstanceSize, UshrExp), 7517 EXP.unsignedRightShiftAssign: __traits(classInstanceSize, UshrAssignExp), 7518 EXP.concatenate: __traits(classInstanceSize, CatExp), 7519 EXP.concatenateAssign: __traits(classInstanceSize, CatAssignExp), 7520 EXP.concatenateElemAssign: __traits(classInstanceSize, CatElemAssignExp), 7521 EXP.concatenateDcharAssign: __traits(classInstanceSize, CatDcharAssignExp), 7522 EXP.add: __traits(classInstanceSize, AddExp), 7523 EXP.min: __traits(classInstanceSize, MinExp), 7524 EXP.addAssign: __traits(classInstanceSize, AddAssignExp), 7525 EXP.minAssign: __traits(classInstanceSize, MinAssignExp), 7526 EXP.mul: __traits(classInstanceSize, MulExp), 7527 EXP.div: __traits(classInstanceSize, DivExp), 7528 EXP.mod: __traits(classInstanceSize, ModExp), 7529 EXP.mulAssign: __traits(classInstanceSize, MulAssignExp), 7530 EXP.divAssign: __traits(classInstanceSize, DivAssignExp), 7531 EXP.modAssign: __traits(classInstanceSize, ModAssignExp), 7532 EXP.and: __traits(classInstanceSize, AndExp), 7533 EXP.or: __traits(classInstanceSize, OrExp), 7534 EXP.xor: __traits(classInstanceSize, XorExp), 7535 EXP.andAssign: __traits(classInstanceSize, AndAssignExp), 7536 EXP.orAssign: __traits(classInstanceSize, OrAssignExp), 7537 EXP.xorAssign: __traits(classInstanceSize, XorAssignExp), 7538 EXP.assign: __traits(classInstanceSize, AssignExp), 7539 EXP.not: __traits(classInstanceSize, NotExp), 7540 EXP.tilde: __traits(classInstanceSize, ComExp), 7541 EXP.plusPlus: __traits(classInstanceSize, PostExp), 7542 EXP.minusMinus: __traits(classInstanceSize, PostExp), 7543 EXP.construct: __traits(classInstanceSize, ConstructExp), 7544 EXP.blit: __traits(classInstanceSize, BlitExp), 7545 EXP.dot: __traits(classInstanceSize, DotExp), 7546 EXP.comma: __traits(classInstanceSize, CommaExp), 7547 EXP.question: __traits(classInstanceSize, CondExp), 7548 EXP.andAnd: __traits(classInstanceSize, LogicalExp), 7549 EXP.orOr: __traits(classInstanceSize, LogicalExp), 7550 EXP.prePlusPlus: __traits(classInstanceSize, PreExp), 7551 EXP.preMinusMinus: __traits(classInstanceSize, PreExp), 7552 EXP.identifier: __traits(classInstanceSize, IdentifierExp), 7553 EXP.string_: __traits(classInstanceSize, StringExp), 7554 EXP.this_: __traits(classInstanceSize, ThisExp), 7555 EXP.super_: __traits(classInstanceSize, SuperExp), 7556 EXP.halt: __traits(classInstanceSize, HaltExp), 7557 EXP.tuple: __traits(classInstanceSize, TupleExp), 7558 EXP.error: __traits(classInstanceSize, ErrorExp), 7559 EXP.void_: __traits(classInstanceSize, VoidInitExp), 7560 EXP.int64: __traits(classInstanceSize, IntegerExp), 7561 EXP.float64: __traits(classInstanceSize, RealExp), 7562 EXP.complex80: __traits(classInstanceSize, ComplexExp), 7563 EXP.import_: __traits(classInstanceSize, ImportExp), 7564 EXP.delegate_: __traits(classInstanceSize, DelegateExp), 7565 EXP.function_: __traits(classInstanceSize, FuncExp), 7566 EXP.mixin_: __traits(classInstanceSize, MixinExp), 7567 EXP.in_: __traits(classInstanceSize, InExp), 7568 EXP.break_: __traits(classInstanceSize, CTFEExp), 7569 EXP.continue_: __traits(classInstanceSize, CTFEExp), 7570 EXP.goto_: __traits(classInstanceSize, CTFEExp), 7571 EXP.scope_: __traits(classInstanceSize, ScopeExp), 7572 EXP.traits: __traits(classInstanceSize, TraitsExp), 7573 EXP.overloadSet: __traits(classInstanceSize, OverExp), 7574 EXP.line: __traits(classInstanceSize, LineInitExp), 7575 EXP.file: __traits(classInstanceSize, FileInitExp), 7576 EXP.fileFullPath: __traits(classInstanceSize, FileInitExp), 7577 EXP.moduleString: __traits(classInstanceSize, ModuleInitExp), 7578 EXP.functionString: __traits(classInstanceSize, FuncInitExp), 7579 EXP.prettyFunction: __traits(classInstanceSize, PrettyFuncInitExp), 7580 EXP.pow: __traits(classInstanceSize, PowExp), 7581 EXP.powAssign: __traits(classInstanceSize, PowAssignExp), 7582 EXP.vector: __traits(classInstanceSize, VectorExp), 7583 EXP.voidExpression: __traits(classInstanceSize, CTFEExp), 7584 EXP.cantExpression: __traits(classInstanceSize, CTFEExp), 7585 EXP.showCtfeContext: __traits(classInstanceSize, CTFEExp), 7586 EXP.objcClassReference: __traits(classInstanceSize, ObjcClassReferenceExp), 7587 EXP.vectorArray: __traits(classInstanceSize, VectorArrayExp), 7588 EXP.compoundLiteral: __traits(classInstanceSize, CompoundLiteralExp), 7589 EXP._Generic: __traits(classInstanceSize, GenericExp), 7590 EXP.interval: __traits(classInstanceSize, IntervalExp), 7591 EXP.loweredAssignExp : __traits(classInstanceSize, LoweredAssignExp), 7592 ];