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