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