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