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