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