1 /** 2 * Compiler implementation of the 3 * $(LINK2 http://www.dlang.org, D programming language). 4 * 5 * Copyright: Copyright (c) 1999-2016 by Digital Mars, All Rights Reserved 6 * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) 7 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 8 * Source: $(DMDSRC _expression.d) 9 */ 10 11 module ddmd.expression; 12 13 import core.stdc.stdarg; 14 import core.stdc.stdio; 15 import core.stdc..string; 16 17 import ddmd.access; 18 import ddmd.aggregate; 19 import ddmd.aliasthis; 20 import ddmd.apply; 21 import ddmd.argtypes; 22 import ddmd.arrayop; 23 import ddmd.arraytypes; 24 import ddmd.attrib; 25 import ddmd.gluelayer; 26 import ddmd.canthrow; 27 import ddmd.complex; 28 import ddmd.constfold; 29 import ddmd.ctfeexpr; 30 import ddmd.dcast; 31 import ddmd.dclass; 32 import ddmd.declaration; 33 import ddmd.delegatize; 34 import ddmd.denum; 35 import ddmd.dimport; 36 import ddmd.dinterpret; 37 import ddmd.dmangle; 38 import ddmd.dmodule; 39 import ddmd.dscope; 40 import ddmd.dstruct; 41 import ddmd.dsymbol; 42 import ddmd.dtemplate; 43 import ddmd.errors; 44 import ddmd.func; 45 import ddmd.globals; 46 import ddmd.hdrgen; 47 import ddmd.id; 48 import ddmd.identifier; 49 import ddmd.imphint; 50 import ddmd.inline; 51 import ddmd.intrange; 52 import ddmd.mtype; 53 import ddmd.nspace; 54 import ddmd.opover; 55 import ddmd.optimize; 56 import ddmd.parse; 57 import ddmd.root.ctfloat; 58 import ddmd.root.file; 59 import ddmd.root.filename; 60 import ddmd.root.outbuffer; 61 import ddmd.root.rmem; 62 import ddmd.root.rootobject; 63 import ddmd.safe; 64 import ddmd.sideeffect; 65 import ddmd.target; 66 import ddmd.tokens; 67 import ddmd.traits; 68 import ddmd.typinf; 69 import ddmd.utf; 70 import ddmd.utils; 71 import ddmd.visitor; 72 73 enum LOGSEMANTIC = false; 74 void emplaceExp(T : Expression, Args...)(void* p, Args args) 75 { 76 scope tmp = new T(args); 77 memcpy(p, cast(void*)tmp, __traits(classInstanceSize, T)); 78 } 79 80 void emplaceExp(T : UnionExp)(T* p, Expression e) 81 { 82 memcpy(p, cast(void*)e, e.size); 83 } 84 85 /************************************************************* 86 * Given var, we need to get the 87 * right 'this' pointer if var is in an outer class, but our 88 * existing 'this' pointer is in an inner class. 89 * Input: 90 * e1 existing 'this' 91 * ad struct or class we need the correct 'this' for 92 * var the specific member of ad we're accessing 93 */ 94 extern (C++) Expression getRightThis(Loc loc, Scope* sc, AggregateDeclaration ad, Expression e1, Declaration var, int flag = 0) 95 { 96 //printf("\ngetRightThis(e1 = %s, ad = %s, var = %s)\n", e1->toChars(), ad->toChars(), var->toChars()); 97 L1: 98 Type t = e1.type.toBasetype(); 99 //printf("e1->type = %s, var->type = %s\n", e1->type->toChars(), var->type->toChars()); 100 101 /* If e1 is not the 'this' pointer for ad 102 */ 103 if (ad && !(t.ty == Tpointer && t.nextOf().ty == Tstruct && (cast(TypeStruct)t.nextOf()).sym == ad) && !(t.ty == Tstruct && (cast(TypeStruct)t).sym == ad)) 104 { 105 ClassDeclaration cd = ad.isClassDeclaration(); 106 ClassDeclaration tcd = t.isClassHandle(); 107 108 /* e1 is the right this if ad is a base class of e1 109 */ 110 if (!cd || !tcd || !(tcd == cd || cd.isBaseOf(tcd, null))) 111 { 112 /* Only classes can be inner classes with an 'outer' 113 * member pointing to the enclosing class instance 114 */ 115 if (tcd && tcd.isNested()) 116 { 117 /* e1 is the 'this' pointer for an inner class: tcd. 118 * Rewrite it as the 'this' pointer for the outer class. 119 */ 120 e1 = new DotVarExp(loc, e1, tcd.vthis); 121 e1.type = tcd.vthis.type; 122 e1.type = e1.type.addMod(t.mod); 123 // Do not call checkNestedRef() 124 //e1 = e1->semantic(sc); 125 126 // Skip up over nested functions, and get the enclosing 127 // class type. 128 int n = 0; 129 Dsymbol s; 130 for (s = tcd.toParent(); s && s.isFuncDeclaration(); s = s.toParent()) 131 { 132 FuncDeclaration f = s.isFuncDeclaration(); 133 if (f.vthis) 134 { 135 //printf("rewriting e1 to %s's this\n", f->toChars()); 136 n++; 137 e1 = new VarExp(loc, f.vthis); 138 } 139 else 140 { 141 e1.error("need 'this' of type %s to access member %s from static function %s", ad.toChars(), var.toChars(), f.toChars()); 142 e1 = new ErrorExp(); 143 return e1; 144 } 145 } 146 if (s && s.isClassDeclaration()) 147 { 148 e1.type = s.isClassDeclaration().type; 149 e1.type = e1.type.addMod(t.mod); 150 if (n > 1) 151 e1 = e1.semantic(sc); 152 } 153 else 154 e1 = e1.semantic(sc); 155 goto L1; 156 } 157 158 /* Can't find a path from e1 to ad 159 */ 160 if (flag) 161 return null; 162 e1.error("this for %s needs to be type %s not type %s", var.toChars(), ad.toChars(), t.toChars()); 163 return new ErrorExp(); 164 } 165 } 166 return e1; 167 } 168 169 /***************************************** 170 * Determine if 'this' is available. 171 * If it is, return the FuncDeclaration that has it. 172 */ 173 extern (C++) FuncDeclaration hasThis(Scope* sc) 174 { 175 //printf("hasThis()\n"); 176 Dsymbol p = sc.parent; 177 while (p && p.isTemplateMixin()) 178 p = p.parent; 179 FuncDeclaration fdthis = p ? p.isFuncDeclaration() : null; 180 //printf("fdthis = %p, '%s'\n", fdthis, fdthis ? fdthis->toChars() : ""); 181 182 // Go upwards until we find the enclosing member function 183 FuncDeclaration fd = fdthis; 184 while (1) 185 { 186 if (!fd) 187 { 188 goto Lno; 189 } 190 if (!fd.isNested()) 191 break; 192 193 Dsymbol parent = fd.parent; 194 while (1) 195 { 196 if (!parent) 197 goto Lno; 198 TemplateInstance ti = parent.isTemplateInstance(); 199 if (ti) 200 parent = ti.parent; 201 else 202 break; 203 } 204 fd = parent.isFuncDeclaration(); 205 } 206 207 if (!fd.isThis()) 208 { 209 //printf("test '%s'\n", fd->toChars()); 210 goto Lno; 211 } 212 213 assert(fd.vthis); 214 return fd; 215 216 Lno: 217 return null; // don't have 'this' available 218 } 219 220 extern (C++) bool isNeedThisScope(Scope* sc, Declaration d) 221 { 222 if (sc.intypeof == 1) 223 return false; 224 225 AggregateDeclaration ad = d.isThis(); 226 if (!ad) 227 return false; 228 //printf("d = %s, ad = %s\n", d.toChars(), ad.toChars()); 229 230 for (Dsymbol s = sc.parent; s; s = s.toParent2()) 231 { 232 //printf("\ts = %s %s, toParent2() = %p\n", s.kind(), s.toChars(), s.toParent2()); 233 if (AggregateDeclaration ad2 = s.isAggregateDeclaration()) 234 { 235 if (ad2 == ad) 236 return false; 237 else if (ad2.isNested()) 238 continue; 239 else 240 return true; 241 } 242 if (FuncDeclaration f = s.isFuncDeclaration()) 243 { 244 if (f.isMember2()) 245 break; 246 } 247 } 248 return true; 249 } 250 251 /*************************************** 252 * Pull out any properties. 253 */ 254 extern (C++) Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 = null) 255 { 256 //printf("resolvePropertiesX, e1 = %s %s, e2 = %s\n", Token.toChars(e1.op), e1.toChars(), e2 ? e2.toChars() : null); 257 Loc loc = e1.loc; 258 259 OverloadSet os; 260 Dsymbol s; 261 Objects* tiargs; 262 Type tthis; 263 if (e1.op == TOKdot) 264 { 265 DotExp de = cast(DotExp)e1; 266 if (de.e2.op == TOKoverloadset) 267 { 268 tiargs = null; 269 tthis = de.e1.type; 270 os = (cast(OverExp)de.e2).vars; 271 goto Los; 272 } 273 } 274 else if (e1.op == TOKoverloadset) 275 { 276 tiargs = null; 277 tthis = null; 278 os = (cast(OverExp)e1).vars; 279 Los: 280 assert(os); 281 FuncDeclaration fd = null; 282 if (e2) 283 { 284 e2 = e2.semantic(sc); 285 if (e2.op == TOKerror) 286 return new ErrorExp(); 287 e2 = resolveProperties(sc, e2); 288 289 Expressions a; 290 a.push(e2); 291 292 for (size_t i = 0; i < os.a.dim; i++) 293 { 294 FuncDeclaration f = resolveFuncCall(loc, sc, os.a[i], tiargs, tthis, &a, 1); 295 if (f) 296 { 297 if (f.errors) 298 return new ErrorExp(); 299 fd = f; 300 assert(fd.type.ty == Tfunction); 301 TypeFunction tf = cast(TypeFunction)fd.type; 302 } 303 } 304 if (fd) 305 { 306 Expression e = new CallExp(loc, e1, e2); 307 return e.semantic(sc); 308 } 309 } 310 { 311 for (size_t i = 0; i < os.a.dim; i++) 312 { 313 FuncDeclaration f = resolveFuncCall(loc, sc, os.a[i], tiargs, tthis, null, 1); 314 if (f) 315 { 316 if (f.errors) 317 return new ErrorExp(); 318 fd = f; 319 assert(fd.type.ty == Tfunction); 320 TypeFunction tf = cast(TypeFunction)fd.type; 321 if (!tf.isref && e2) 322 goto Leproplvalue; 323 } 324 } 325 if (fd) 326 { 327 Expression e = new CallExp(loc, e1); 328 if (e2) 329 e = new AssignExp(loc, e, e2); 330 return e.semantic(sc); 331 } 332 } 333 if (e2) 334 goto Leprop; 335 } 336 else if (e1.op == TOKdotti) 337 { 338 DotTemplateInstanceExp dti = cast(DotTemplateInstanceExp)e1; 339 if (!dti.findTempDecl(sc)) 340 goto Leprop; 341 if (!dti.ti.semanticTiargs(sc)) 342 goto Leprop; 343 tiargs = dti.ti.tiargs; 344 tthis = dti.e1.type; 345 if ((os = dti.ti.tempdecl.isOverloadSet()) !is null) 346 goto Los; 347 if ((s = dti.ti.tempdecl) !is null) 348 goto Lfd; 349 } 350 else if (e1.op == TOKdottd) 351 { 352 DotTemplateExp dte = cast(DotTemplateExp)e1; 353 s = dte.td; 354 tiargs = null; 355 tthis = dte.e1.type; 356 goto Lfd; 357 } 358 else if (e1.op == TOKscope) 359 { 360 s = (cast(ScopeExp)e1).sds; 361 TemplateInstance ti = s.isTemplateInstance(); 362 if (ti && !ti.semanticRun && ti.tempdecl) 363 { 364 //assert(ti.needsTypeInference(sc)); 365 if (!ti.semanticTiargs(sc)) 366 goto Leprop; 367 tiargs = ti.tiargs; 368 tthis = null; 369 if ((os = ti.tempdecl.isOverloadSet()) !is null) 370 goto Los; 371 if ((s = ti.tempdecl) !is null) 372 goto Lfd; 373 } 374 } 375 else if (e1.op == TOKtemplate) 376 { 377 s = (cast(TemplateExp)e1).td; 378 tiargs = null; 379 tthis = null; 380 goto Lfd; 381 } 382 else if (e1.op == TOKdotvar && e1.type && e1.type.toBasetype().ty == Tfunction) 383 { 384 DotVarExp dve = cast(DotVarExp)e1; 385 s = dve.var.isFuncDeclaration(); 386 tiargs = null; 387 tthis = dve.e1.type; 388 goto Lfd; 389 } 390 else if (e1.op == TOKvar && e1.type && e1.type.toBasetype().ty == Tfunction) 391 { 392 s = (cast(VarExp)e1).var.isFuncDeclaration(); 393 tiargs = null; 394 tthis = null; 395 Lfd: 396 assert(s); 397 if (e2) 398 { 399 e2 = e2.semantic(sc); 400 if (e2.op == TOKerror) 401 return new ErrorExp(); 402 e2 = resolveProperties(sc, e2); 403 404 Expressions a; 405 a.push(e2); 406 407 FuncDeclaration fd = resolveFuncCall(loc, sc, s, tiargs, tthis, &a, 1); 408 if (fd && fd.type) 409 { 410 if (fd.errors) 411 return new ErrorExp(); 412 assert(fd.type.ty == Tfunction); 413 TypeFunction tf = cast(TypeFunction)fd.type; 414 Expression e = new CallExp(loc, e1, e2); 415 return e.semantic(sc); 416 } 417 } 418 { 419 FuncDeclaration fd = resolveFuncCall(loc, sc, s, tiargs, tthis, null, 1); 420 if (fd && fd.type) 421 { 422 if (fd.errors) 423 return new ErrorExp(); 424 assert(fd.type.ty == Tfunction); 425 TypeFunction tf = cast(TypeFunction)fd.type; 426 if (!e2 || tf.isref) 427 { 428 Expression e = new CallExp(loc, e1); 429 if (e2) 430 e = new AssignExp(loc, e, e2); 431 return e.semantic(sc); 432 } 433 } 434 } 435 if (FuncDeclaration fd = s.isFuncDeclaration()) 436 { 437 // Keep better diagnostic message for invalid property usage of functions 438 assert(fd.type.ty == Tfunction); 439 TypeFunction tf = cast(TypeFunction)fd.type; 440 Expression e = new CallExp(loc, e1, e2); 441 return e.semantic(sc); 442 } 443 if (e2) 444 goto Leprop; 445 } 446 if (e1.op == TOKvar) 447 { 448 VarExp ve = cast(VarExp)e1; 449 VarDeclaration v = ve.var.isVarDeclaration(); 450 if (v && ve.checkPurity(sc, v)) 451 return new ErrorExp(); 452 } 453 if (e2) 454 return null; 455 456 if (e1.type && e1.op != TOKtype) // function type is not a property 457 { 458 /* Look for e1 being a lazy parameter; rewrite as delegate call 459 */ 460 if (e1.op == TOKvar) 461 { 462 VarExp ve = cast(VarExp)e1; 463 if (ve.var.storage_class & STClazy) 464 { 465 Expression e = new CallExp(loc, e1); 466 return e.semantic(sc); 467 } 468 } 469 else if (e1.op == TOKdotvar) 470 { 471 // Check for reading overlapped pointer field in @safe code. 472 if (checkUnsafeAccess(sc, e1, true, true)) 473 return new ErrorExp(); 474 } 475 else if (e1.op == TOKdot) 476 { 477 e1.error("expression has no value"); 478 return new ErrorExp(); 479 } 480 else if (e1.op == TOKcall) 481 { 482 CallExp ce = cast(CallExp)e1; 483 // Check for reading overlapped pointer field in @safe code. 484 if (checkUnsafeAccess(sc, ce.e1, true, true)) 485 return new ErrorExp(); 486 } 487 } 488 489 if (!e1.type) 490 { 491 error(loc, "cannot resolve type for %s", e1.toChars()); 492 e1 = new ErrorExp(); 493 } 494 return e1; 495 496 Leprop: 497 error(loc, "not a property %s", e1.toChars()); 498 return new ErrorExp(); 499 500 Leproplvalue: 501 error(loc, "%s is not an lvalue", e1.toChars()); 502 return new ErrorExp(); 503 } 504 505 extern (C++) Expression resolveProperties(Scope* sc, Expression e) 506 { 507 //printf("resolveProperties(%s)\n", e->toChars()); 508 e = resolvePropertiesX(sc, e); 509 if (e.checkRightThis(sc)) 510 return new ErrorExp(); 511 return e; 512 } 513 514 /****************************** 515 * Check the tail CallExp is really property function call. 516 */ 517 extern (C++) bool checkPropertyCall(Expression e, Expression emsg) 518 { 519 while (e.op == TOKcomma) 520 e = (cast(CommaExp)e).e2; 521 522 if (e.op == TOKcall) 523 { 524 CallExp ce = cast(CallExp)e; 525 TypeFunction tf; 526 if (ce.f) 527 { 528 tf = cast(TypeFunction)ce.f.type; 529 /* If a forward reference to ce->f, try to resolve it 530 */ 531 if (!tf.deco && ce.f._scope) 532 { 533 ce.f.semantic(ce.f._scope); 534 tf = cast(TypeFunction)ce.f.type; 535 } 536 } 537 else if (ce.e1.type.ty == Tfunction) 538 tf = cast(TypeFunction)ce.e1.type; 539 else if (ce.e1.type.ty == Tdelegate) 540 tf = cast(TypeFunction)ce.e1.type.nextOf(); 541 else if (ce.e1.type.ty == Tpointer && ce.e1.type.nextOf().ty == Tfunction) 542 tf = cast(TypeFunction)ce.e1.type.nextOf(); 543 else 544 assert(0); 545 } 546 return false; 547 } 548 549 /****************************** 550 * If e1 is a property function (template), resolve it. 551 */ 552 extern (C++) Expression resolvePropertiesOnly(Scope* sc, Expression e1) 553 { 554 //printf("e1 = %s %s\n", Token::toChars(e1->op), e1->toChars()); 555 OverloadSet os; 556 FuncDeclaration fd; 557 TemplateDeclaration td; 558 559 if (e1.op == TOKdot) 560 { 561 DotExp de = cast(DotExp)e1; 562 if (de.e2.op == TOKoverloadset) 563 { 564 os = (cast(OverExp)de.e2).vars; 565 goto Los; 566 } 567 } 568 else if (e1.op == TOKoverloadset) 569 { 570 os = (cast(OverExp)e1).vars; 571 Los: 572 assert(os); 573 for (size_t i = 0; i < os.a.dim; i++) 574 { 575 Dsymbol s = os.a[i]; 576 fd = s.isFuncDeclaration(); 577 td = s.isTemplateDeclaration(); 578 if (fd) 579 { 580 if ((cast(TypeFunction)fd.type).isproperty) 581 return resolveProperties(sc, e1); 582 } 583 else if (td && td.onemember && (fd = td.onemember.isFuncDeclaration()) !is null) 584 { 585 if ((cast(TypeFunction)fd.type).isproperty || (fd.storage_class2 & STCproperty) || (td._scope.stc & STCproperty)) 586 { 587 return resolveProperties(sc, e1); 588 } 589 } 590 } 591 } 592 else if (e1.op == TOKdotti) 593 { 594 DotTemplateInstanceExp dti = cast(DotTemplateInstanceExp)e1; 595 if (dti.ti.tempdecl && (td = dti.ti.tempdecl.isTemplateDeclaration()) !is null) 596 goto Ltd; 597 } 598 else if (e1.op == TOKdottd) 599 { 600 td = (cast(DotTemplateExp)e1).td; 601 goto Ltd; 602 } 603 else if (e1.op == TOKscope) 604 { 605 Dsymbol s = (cast(ScopeExp)e1).sds; 606 TemplateInstance ti = s.isTemplateInstance(); 607 if (ti && !ti.semanticRun && ti.tempdecl) 608 { 609 if ((td = ti.tempdecl.isTemplateDeclaration()) !is null) 610 goto Ltd; 611 } 612 } 613 else if (e1.op == TOKtemplate) 614 { 615 td = (cast(TemplateExp)e1).td; 616 Ltd: 617 assert(td); 618 if (td.onemember && (fd = td.onemember.isFuncDeclaration()) !is null) 619 { 620 if ((cast(TypeFunction)fd.type).isproperty || (fd.storage_class2 & STCproperty) || (td._scope.stc & STCproperty)) 621 { 622 return resolveProperties(sc, e1); 623 } 624 } 625 } 626 else if (e1.op == TOKdotvar && e1.type.ty == Tfunction) 627 { 628 DotVarExp dve = cast(DotVarExp)e1; 629 fd = dve.var.isFuncDeclaration(); 630 goto Lfd; 631 } 632 else if (e1.op == TOKvar && e1.type.ty == Tfunction && (sc.intypeof || !(cast(VarExp)e1).var.needThis())) 633 { 634 fd = (cast(VarExp)e1).var.isFuncDeclaration(); 635 Lfd: 636 assert(fd); 637 if ((cast(TypeFunction)fd.type).isproperty) 638 return resolveProperties(sc, e1); 639 } 640 return e1; 641 } 642 643 /****************************** 644 * Find symbol in accordance with the UFCS name look up rule 645 */ 646 extern (C++) Expression searchUFCS(Scope* sc, UnaExp ue, Identifier ident) 647 { 648 //printf("searchUFCS(ident = %s)\n", ident.toChars()); 649 Loc loc = ue.loc; 650 651 // TODO: merge with Scope.search.searchScopes() 652 Dsymbol searchScopes(int flags) 653 { 654 Dsymbol s = null; 655 for (Scope* scx = sc; scx; scx = scx.enclosing) 656 { 657 if (!scx.scopesym) 658 continue; 659 if (scx.scopesym.isModule()) 660 flags |= SearchUnqualifiedModule; // tell Module.search() that SearchLocalsOnly is to be obeyed 661 s = scx.scopesym.search(loc, ident, flags); 662 if (s) 663 { 664 // overload set contains only module scope symbols. 665 if (s.isOverloadSet()) 666 break; 667 // selective/renamed imports also be picked up 668 if (AliasDeclaration ad = s.isAliasDeclaration()) 669 { 670 if (ad._import) 671 break; 672 } 673 // See only module scope symbols for UFCS target. 674 Dsymbol p = s.toParent2(); 675 if (p && p.isModule()) 676 break; 677 } 678 s = null; 679 680 // Stop when we hit a module, but keep going if that is not just under the global scope 681 if (scx.scopesym.isModule() && !(scx.enclosing && !scx.enclosing.enclosing)) 682 break; 683 } 684 return s; 685 } 686 687 int flags = 0; 688 Dsymbol s; 689 690 Dsymbol sold = void; 691 if (global.params.bug10378 || global.params.check10378) 692 { 693 sold = searchScopes(flags | IgnoreSymbolVisibility); 694 if (!global.params.check10378) 695 { 696 s = sold; 697 goto Lsearchdone; 698 } 699 } 700 701 // First look in local scopes 702 s = searchScopes(flags | SearchLocalsOnly); 703 if (!s) 704 { 705 // Second look in imported modules 706 s = searchScopes(flags | SearchImportsOnly); 707 708 /** Still find private symbols, so that symbols that weren't access 709 * checked by the compiler remain usable. Once the deprecation is over, 710 * this should be moved to search_correct instead. 711 */ 712 if (!s) 713 { 714 s = searchScopes(flags | SearchLocalsOnly | IgnoreSymbolVisibility); 715 if (!s) 716 s = searchScopes(flags | SearchImportsOnly | IgnoreSymbolVisibility); 717 718 if (s) 719 .deprecation(loc, "%s is not visible from module %s", s.toPrettyChars(), sc._module.toChars()); 720 } 721 } 722 if (global.params.check10378) 723 { 724 alias snew = s; 725 if (sold !is snew) 726 Scope.deprecation10378(loc, sold, snew); 727 if (global.params.bug10378) 728 s = sold; 729 } 730 Lsearchdone: 731 732 if (!s) 733 return ue.e1.type.Type.getProperty(loc, ident, 0); 734 735 FuncDeclaration f = s.isFuncDeclaration(); 736 if (f) 737 { 738 TemplateDeclaration td = getFuncTemplateDecl(f); 739 if (td) 740 { 741 if (td.overroot) 742 td = td.overroot; 743 s = td; 744 } 745 } 746 747 if (ue.op == TOKdotti) 748 { 749 DotTemplateInstanceExp dti = cast(DotTemplateInstanceExp)ue; 750 auto ti = new TemplateInstance(loc, s.ident, dti.ti.tiargs); 751 if (!ti.updateTempDecl(sc, s)) 752 return new ErrorExp(); 753 return new ScopeExp(loc, ti); 754 } 755 else 756 { 757 //printf("-searchUFCS() %s\n", s.toChars()); 758 return new DsymbolExp(loc, s); 759 } 760 } 761 762 /****************************** 763 * check e is exp.opDispatch!(tiargs) or not 764 * It's used to switch to UFCS the semantic analysis path 765 */ 766 extern (C++) bool isDotOpDispatch(Expression e) 767 { 768 return e.op == TOKdotti && (cast(DotTemplateInstanceExp)e).ti.name == Id.opDispatch; 769 } 770 771 /****************************** 772 * Pull out callable entity with UFCS. 773 */ 774 extern (C++) Expression resolveUFCS(Scope* sc, CallExp ce) 775 { 776 Loc loc = ce.loc; 777 Expression eleft; 778 Expression e; 779 780 if (ce.e1.op == TOKdotid) 781 { 782 DotIdExp die = cast(DotIdExp)ce.e1; 783 Identifier ident = die.ident; 784 785 Expression ex = die.semanticX(sc); 786 if (ex != die) 787 { 788 ce.e1 = ex; 789 return null; 790 } 791 eleft = die.e1; 792 793 Type t = eleft.type.toBasetype(); 794 if (t.ty == Tarray || t.ty == Tsarray || t.ty == Tnull || (t.isTypeBasic() && t.ty != Tvoid)) 795 { 796 /* Built-in types and arrays have no callable properties, so do shortcut. 797 * It is necessary in: e.init() 798 */ 799 } 800 else if (t.ty == Taarray) 801 { 802 if (ident == Id.remove) 803 { 804 /* Transform: 805 * aa.remove(arg) into delete aa[arg] 806 */ 807 if (!ce.arguments || ce.arguments.dim != 1) 808 { 809 ce.error("expected key as argument to aa.remove()"); 810 return new ErrorExp(); 811 } 812 if (!eleft.type.isMutable()) 813 { 814 ce.error("cannot remove key from %s associative array %s", MODtoChars(t.mod), eleft.toChars()); 815 return new ErrorExp(); 816 } 817 Expression key = (*ce.arguments)[0]; 818 key = key.semantic(sc); 819 key = resolveProperties(sc, key); 820 821 TypeAArray taa = cast(TypeAArray)t; 822 key = key.implicitCastTo(sc, taa.index); 823 824 if (key.checkValue()) 825 return new ErrorExp(); 826 827 semanticTypeInfo(sc, taa.index); 828 829 return new RemoveExp(loc, eleft, key); 830 } 831 } 832 else 833 { 834 if (Expression ey = die.semanticY(sc, 1)) 835 { 836 if (ey.op == TOKerror) 837 return ey; 838 ce.e1 = ey; 839 if (isDotOpDispatch(ey)) 840 { 841 uint errors = global.startGagging(); 842 e = ce.syntaxCopy().semantic(sc); 843 if (!global.endGagging(errors)) 844 return e; 845 /* fall down to UFCS */ 846 } 847 else 848 return null; 849 } 850 } 851 e = searchUFCS(sc, die, ident); 852 } 853 else if (ce.e1.op == TOKdotti) 854 { 855 DotTemplateInstanceExp dti = cast(DotTemplateInstanceExp)ce.e1; 856 if (Expression ey = dti.semanticY(sc, 1)) 857 { 858 ce.e1 = ey; 859 return null; 860 } 861 eleft = dti.e1; 862 e = searchUFCS(sc, dti, dti.ti.name); 863 } 864 else 865 return null; 866 867 // Rewrite 868 ce.e1 = e; 869 if (!ce.arguments) 870 ce.arguments = new Expressions(); 871 ce.arguments.shift(eleft); 872 873 return null; 874 } 875 876 /****************************** 877 * Pull out property with UFCS. 878 */ 879 extern (C++) Expression resolveUFCSProperties(Scope* sc, Expression e1, Expression e2 = null) 880 { 881 Loc loc = e1.loc; 882 Expression eleft; 883 Expression e; 884 885 if (e1.op == TOKdotid) 886 { 887 DotIdExp die = cast(DotIdExp)e1; 888 eleft = die.e1; 889 e = searchUFCS(sc, die, die.ident); 890 } 891 else if (e1.op == TOKdotti) 892 { 893 DotTemplateInstanceExp dti; 894 dti = cast(DotTemplateInstanceExp)e1; 895 eleft = dti.e1; 896 e = searchUFCS(sc, dti, dti.ti.name); 897 } 898 else 899 return null; 900 901 // Rewrite 902 if (e2) 903 { 904 // run semantic without gagging 905 e2 = e2.semantic(sc); 906 907 /* f(e1) = e2 908 */ 909 Expression ex = e.copy(); 910 auto a1 = new Expressions(); 911 a1.setDim(1); 912 (*a1)[0] = eleft; 913 ex = new CallExp(loc, ex, a1); 914 ex = ex.trySemantic(sc); 915 916 /* f(e1, e2) 917 */ 918 auto a2 = new Expressions(); 919 a2.setDim(2); 920 (*a2)[0] = eleft; 921 (*a2)[1] = e2; 922 e = new CallExp(loc, e, a2); 923 if (ex) 924 { 925 // if fallback setter exists, gag errors 926 e = e.trySemantic(sc); 927 if (!e) 928 { 929 checkPropertyCall(ex, e1); 930 ex = new AssignExp(loc, ex, e2); 931 return ex.semantic(sc); 932 } 933 } 934 else 935 { 936 // strict setter prints errors if fails 937 e = e.semantic(sc); 938 } 939 checkPropertyCall(e, e1); 940 return e; 941 } 942 else 943 { 944 /* f(e1) 945 */ 946 auto arguments = new Expressions(); 947 arguments.setDim(1); 948 (*arguments)[0] = eleft; 949 e = new CallExp(loc, e, arguments); 950 e = e.semantic(sc); 951 checkPropertyCall(e, e1); 952 return e.semantic(sc); 953 } 954 } 955 956 /****************************** 957 * Perform semantic() on an array of Expressions. 958 */ 959 extern (C++) bool arrayExpressionSemantic(Expressions* exps, Scope* sc, bool preserveErrors = false) 960 { 961 bool err = false; 962 if (exps) 963 { 964 for (size_t i = 0; i < exps.dim; i++) 965 { 966 Expression e = (*exps)[i]; 967 if (e) 968 { 969 e = e.semantic(sc); 970 if (e.op == TOKerror) 971 err = true; 972 if (preserveErrors || e.op != TOKerror) 973 (*exps)[i] = e; 974 } 975 } 976 } 977 return err; 978 } 979 980 /**************************************** 981 * Expand tuples. 982 * Input: 983 * exps aray of Expressions 984 * Output: 985 * exps rewritten in place 986 */ 987 extern (C++) void expandTuples(Expressions* exps) 988 { 989 //printf("expandTuples()\n"); 990 if (exps) 991 { 992 for (size_t i = 0; i < exps.dim; i++) 993 { 994 Expression arg = (*exps)[i]; 995 if (!arg) 996 continue; 997 998 // Look for tuple with 0 members 999 if (arg.op == TOKtype) 1000 { 1001 TypeExp e = cast(TypeExp)arg; 1002 if (e.type.toBasetype().ty == Ttuple) 1003 { 1004 TypeTuple tt = cast(TypeTuple)e.type.toBasetype(); 1005 if (!tt.arguments || tt.arguments.dim == 0) 1006 { 1007 exps.remove(i); 1008 if (i == exps.dim) 1009 return; 1010 i--; 1011 continue; 1012 } 1013 } 1014 } 1015 1016 // Inline expand all the tuples 1017 while (arg.op == TOKtuple) 1018 { 1019 TupleExp te = cast(TupleExp)arg; 1020 exps.remove(i); // remove arg 1021 exps.insert(i, te.exps); // replace with tuple contents 1022 if (i == exps.dim) 1023 return; // empty tuple, no more arguments 1024 (*exps)[i] = Expression.combine(te.e0, (*exps)[i]); 1025 arg = (*exps)[i]; 1026 } 1027 } 1028 } 1029 } 1030 1031 /**************************************** 1032 * Expand alias this tuples. 1033 */ 1034 extern (C++) TupleDeclaration isAliasThisTuple(Expression e) 1035 { 1036 if (!e.type) 1037 return null; 1038 1039 Type t = e.type.toBasetype(); 1040 Lagain: 1041 if (Dsymbol s = t.toDsymbol(null)) 1042 { 1043 AggregateDeclaration ad = s.isAggregateDeclaration(); 1044 if (ad) 1045 { 1046 s = ad.aliasthis; 1047 if (s && s.isVarDeclaration()) 1048 { 1049 TupleDeclaration td = s.isVarDeclaration().toAlias().isTupleDeclaration(); 1050 if (td && td.isexp) 1051 return td; 1052 } 1053 if (Type att = t.aliasthisOf()) 1054 { 1055 t = att; 1056 goto Lagain; 1057 } 1058 } 1059 } 1060 return null; 1061 } 1062 1063 extern (C++) int expandAliasThisTuples(Expressions* exps, size_t starti = 0) 1064 { 1065 if (!exps || exps.dim == 0) 1066 return -1; 1067 1068 for (size_t u = starti; u < exps.dim; u++) 1069 { 1070 Expression exp = (*exps)[u]; 1071 TupleDeclaration td = isAliasThisTuple(exp); 1072 if (td) 1073 { 1074 exps.remove(u); 1075 for (size_t i = 0; i < td.objects.dim; ++i) 1076 { 1077 Expression e = isExpression((*td.objects)[i]); 1078 assert(e); 1079 assert(e.op == TOKdsymbol); 1080 DsymbolExp se = cast(DsymbolExp)e; 1081 Declaration d = se.s.isDeclaration(); 1082 assert(d); 1083 e = new DotVarExp(exp.loc, exp, d); 1084 assert(d.type); 1085 e.type = d.type; 1086 exps.insert(u + i, e); 1087 } 1088 version (none) 1089 { 1090 printf("expansion ->\n"); 1091 for (size_t i = 0; i < exps.dim; ++i) 1092 { 1093 Expression e = (*exps)[i]; 1094 printf("\texps[%d] e = %s %s\n", i, Token.tochars[e.op], e.toChars()); 1095 } 1096 } 1097 return cast(int)u; 1098 } 1099 } 1100 return -1; 1101 } 1102 1103 /**************************************** 1104 * The common type is determined by applying ?: to each pair. 1105 * Output: 1106 * exps[] properties resolved, implicitly cast to common type, rewritten in place 1107 * *pt if pt is not NULL, set to the common type 1108 * Returns: 1109 * true a semantic error was detected 1110 */ 1111 extern (C++) bool arrayExpressionToCommonType(Scope* sc, Expressions* exps, Type* pt) 1112 { 1113 /* Still have a problem with: 1114 * ubyte[][] = [ cast(ubyte[])"hello", [1]]; 1115 * which works if the array literal is initialized top down with the ubyte[][] 1116 * type, but fails with this function doing bottom up typing. 1117 */ 1118 1119 //printf("arrayExpressionToCommonType()\n"); 1120 scope IntegerExp integerexp = new IntegerExp(0); 1121 scope CondExp condexp = new CondExp(Loc(), integerexp, null, null); 1122 1123 Type t0 = null; 1124 Expression e0 = null; 1125 size_t j0 = ~0; 1126 1127 for (size_t i = 0; i < exps.dim; i++) 1128 { 1129 Expression e = (*exps)[i]; 1130 if (!e) 1131 continue; 1132 1133 e = resolveProperties(sc, e); 1134 if (!e.type) 1135 { 1136 e.error("%s has no value", e.toChars()); 1137 t0 = Type.terror; 1138 continue; 1139 } 1140 if (e.op == TOKtype) 1141 { 1142 e.checkValue(); // report an error "type T has no value" 1143 t0 = Type.terror; 1144 continue; 1145 } 1146 if (checkNonAssignmentArrayOp(e)) 1147 { 1148 t0 = Type.terror; 1149 continue; 1150 } 1151 1152 e = doCopyOrMove(sc, e); 1153 1154 if (t0 && !t0.equals(e.type)) 1155 { 1156 /* This applies ?: to merge the types. It's backwards; 1157 * ?: should call this function to merge types. 1158 */ 1159 condexp.type = null; 1160 condexp.e1 = e0; 1161 condexp.e2 = e; 1162 condexp.loc = e.loc; 1163 Expression ex = condexp.semantic(sc); 1164 if (ex.op == TOKerror) 1165 e = ex; 1166 else 1167 { 1168 (*exps)[j0] = condexp.e1; 1169 e = condexp.e2; 1170 } 1171 } 1172 j0 = i; 1173 e0 = e; 1174 t0 = e.type; 1175 if (e.op != TOKerror) 1176 (*exps)[i] = e; 1177 } 1178 1179 if (!t0) 1180 t0 = Type.tvoid; // [] is typed as void[] 1181 else if (t0.ty != Terror) 1182 { 1183 for (size_t i = 0; i < exps.dim; i++) 1184 { 1185 Expression e = (*exps)[i]; 1186 if (!e) 1187 continue; 1188 1189 e = e.implicitCastTo(sc, t0); 1190 //assert(e->op != TOKerror); 1191 if (e.op == TOKerror) 1192 { 1193 /* Bugzilla 13024: a workaround for the bug in typeMerge - 1194 * it should paint e1 and e2 by deduced common type, 1195 * but doesn't in this particular case. 1196 */ 1197 t0 = Type.terror; 1198 break; 1199 } 1200 (*exps)[i] = e; 1201 } 1202 } 1203 if (pt) 1204 *pt = t0; 1205 1206 return (t0 == Type.terror); 1207 } 1208 1209 /**************************************** 1210 * Get TemplateDeclaration enclosing FuncDeclaration. 1211 */ 1212 extern (C++) TemplateDeclaration getFuncTemplateDecl(Dsymbol s) 1213 { 1214 FuncDeclaration f = s.isFuncDeclaration(); 1215 if (f && f.parent) 1216 { 1217 TemplateInstance ti = f.parent.isTemplateInstance(); 1218 if (ti && !ti.isTemplateMixin() && ti.tempdecl && (cast(TemplateDeclaration)ti.tempdecl).onemember && ti.tempdecl.ident == f.ident) 1219 { 1220 return cast(TemplateDeclaration)ti.tempdecl; 1221 } 1222 } 1223 return null; 1224 } 1225 1226 /**************************************** 1227 * Preprocess arguments to function. 1228 * Output: 1229 * exps[] tuples expanded, properties resolved, rewritten in place 1230 * Returns: 1231 * true a semantic error occurred 1232 */ 1233 extern (C++) bool preFunctionParameters(Loc loc, Scope* sc, Expressions* exps) 1234 { 1235 bool err = false; 1236 if (exps) 1237 { 1238 expandTuples(exps); 1239 1240 for (size_t i = 0; i < exps.dim; i++) 1241 { 1242 Expression arg = (*exps)[i]; 1243 arg = resolveProperties(sc, arg); 1244 if (arg.op == TOKtype) 1245 { 1246 arg.error("cannot pass type %s as a function argument", arg.toChars()); 1247 arg = new ErrorExp(); 1248 err = true; 1249 } 1250 else if (checkNonAssignmentArrayOp(arg)) 1251 { 1252 arg = new ErrorExp(); 1253 err = true; 1254 } 1255 (*exps)[i] = arg; 1256 } 1257 } 1258 return err; 1259 } 1260 1261 /************************************************ 1262 * If we want the value of this expression, but do not want to call 1263 * the destructor on it. 1264 */ 1265 extern (C++) Expression valueNoDtor(Expression e) 1266 { 1267 if (e.op == TOKcall) 1268 { 1269 /* The struct value returned from the function is transferred 1270 * so do not call the destructor on it. 1271 * Recognize: 1272 * ((S _ctmp = S.init), _ctmp).this(...) 1273 * and make sure the destructor is not called on _ctmp 1274 * BUG: if e is a CommaExp, we should go down the right side. 1275 */ 1276 CallExp ce = cast(CallExp)e; 1277 if (ce.e1.op == TOKdotvar) 1278 { 1279 DotVarExp dve = cast(DotVarExp)ce.e1; 1280 if (dve.var.isCtorDeclaration()) 1281 { 1282 // It's a constructor call 1283 if (dve.e1.op == TOKcomma) 1284 { 1285 CommaExp comma = cast(CommaExp)dve.e1; 1286 if (comma.e2.op == TOKvar) 1287 { 1288 VarExp ve = cast(VarExp)comma.e2; 1289 VarDeclaration ctmp = ve.var.isVarDeclaration(); 1290 if (ctmp) 1291 { 1292 ctmp.storage_class |= STCnodtor; 1293 assert(!ce.isLvalue()); 1294 } 1295 } 1296 } 1297 } 1298 } 1299 } 1300 else if (e.op == TOKvar) 1301 { 1302 auto vtmp = (cast(VarExp)e).var.isVarDeclaration(); 1303 if (vtmp && (vtmp.storage_class & STCrvalue)) 1304 { 1305 vtmp.storage_class |= STCnodtor; 1306 } 1307 } 1308 return e; 1309 } 1310 1311 /******************************************** 1312 * Issue an error if default construction is disabled for type t. 1313 * Default construction is required for arrays and 'out' parameters. 1314 * Returns: 1315 * true an error was issued 1316 */ 1317 extern (C++) bool checkDefCtor(Loc loc, Type t) 1318 { 1319 t = t.baseElemOf(); 1320 if (t.ty == Tstruct) 1321 { 1322 StructDeclaration sd = (cast(TypeStruct)t).sym; 1323 if (sd.noDefaultCtor) 1324 { 1325 sd.error(loc, "default construction is disabled"); 1326 return true; 1327 } 1328 } 1329 return false; 1330 } 1331 1332 /********************************************* 1333 * If e is an instance of a struct, and that struct has a copy constructor, 1334 * rewrite e as: 1335 * (tmp = e),tmp 1336 * Input: 1337 * sc just used to specify the scope of created temporary variable 1338 */ 1339 extern (C++) Expression callCpCtor(Scope* sc, Expression e) 1340 { 1341 Type tv = e.type.baseElemOf(); 1342 if (tv.ty == Tstruct) 1343 { 1344 StructDeclaration sd = (cast(TypeStruct)tv).sym; 1345 if (sd.postblit) 1346 { 1347 /* Create a variable tmp, and replace the argument e with: 1348 * (tmp = e),tmp 1349 * and let AssignExp() handle the construction. 1350 * This is not the most efficent, ideally tmp would be constructed 1351 * directly onto the stack. 1352 */ 1353 auto tmp = copyToTemp(STCrvalue, "__copytmp", e); 1354 tmp.storage_class |= STCnodtor; 1355 tmp.semantic(sc); 1356 Expression de = new DeclarationExp(e.loc, tmp); 1357 Expression ve = new VarExp(e.loc, tmp); 1358 de.type = Type.tvoid; 1359 ve.type = e.type; 1360 e = Expression.combine(de, ve); 1361 } 1362 } 1363 return e; 1364 } 1365 1366 /************************************************ 1367 * Handle the postblit call on lvalue, or the move of rvalue. 1368 */ 1369 extern (C++) Expression doCopyOrMove(Scope *sc, Expression e) 1370 { 1371 if (e.op == TOKquestion) 1372 { 1373 auto ce = cast(CondExp)e; 1374 ce.e1 = doCopyOrMove(sc, ce.e1); 1375 ce.e2 = doCopyOrMove(sc, ce.e2); 1376 } 1377 else 1378 { 1379 e = e.isLvalue() ? callCpCtor(sc, e) : valueNoDtor(e); 1380 } 1381 return e; 1382 } 1383 1384 /**************************************** 1385 * Now that we know the exact type of the function we're calling, 1386 * the arguments[] need to be adjusted: 1387 * 1. implicitly convert argument to the corresponding parameter type 1388 * 2. add default arguments for any missing arguments 1389 * 3. do default promotions on arguments corresponding to ... 1390 * 4. add hidden _arguments[] argument 1391 * 5. call copy constructor for struct value arguments 1392 * Input: 1393 * tf type of the function 1394 * fd the function being called, NULL if called indirectly 1395 * Output: 1396 * *prettype return type of function 1397 * *peprefix expression to execute before arguments[] are evaluated, NULL if none 1398 * Returns: 1399 * true errors happened 1400 */ 1401 extern (C++) bool functionParameters(Loc loc, Scope* sc, TypeFunction tf, Type tthis, Expressions* arguments, FuncDeclaration fd, Type* prettype, Expression* peprefix) 1402 { 1403 //printf("functionParameters()\n"); 1404 assert(arguments); 1405 assert(fd || tf.next); 1406 size_t nargs = arguments ? arguments.dim : 0; 1407 size_t nparams = Parameter.dim(tf.parameters); 1408 uint olderrors = global.errors; 1409 bool err = false; 1410 *prettype = Type.terror; 1411 Expression eprefix = null; 1412 *peprefix = null; 1413 1414 if (nargs > nparams && tf.varargs == 0) 1415 { 1416 error(loc, "expected %llu arguments, not %llu for non-variadic function type %s", cast(ulong)nparams, cast(ulong)nargs, tf.toChars()); 1417 return true; 1418 } 1419 1420 // If inferring return type, and semantic3() needs to be run if not already run 1421 if (!tf.next && fd.inferRetType) 1422 { 1423 fd.functionSemantic(); 1424 } 1425 else if (fd && fd.parent) 1426 { 1427 TemplateInstance ti = fd.parent.isTemplateInstance(); 1428 if (ti && ti.tempdecl) 1429 { 1430 fd.functionSemantic3(); 1431 } 1432 } 1433 bool isCtorCall = fd && fd.needThis() && fd.isCtorDeclaration(); 1434 1435 size_t n = (nargs > nparams) ? nargs : nparams; // n = max(nargs, nparams) 1436 1437 /* If the function return type has wildcards in it, we'll need to figure out the actual type 1438 * based on the actual argument types. 1439 */ 1440 MOD wildmatch = 0; 1441 if (tthis && tf.isWild() && !isCtorCall) 1442 { 1443 Type t = tthis; 1444 if (t.isImmutable()) 1445 wildmatch = MODimmutable; 1446 else if (t.isWildConst()) 1447 wildmatch = MODwildconst; 1448 else if (t.isWild()) 1449 wildmatch = MODwild; 1450 else if (t.isConst()) 1451 wildmatch = MODconst; 1452 else 1453 wildmatch = MODmutable; 1454 } 1455 1456 int done = 0; 1457 for (size_t i = 0; i < n; i++) 1458 { 1459 Expression arg; 1460 1461 if (i < nargs) 1462 arg = (*arguments)[i]; 1463 else 1464 arg = null; 1465 1466 if (i < nparams) 1467 { 1468 Parameter p = Parameter.getNth(tf.parameters, i); 1469 1470 if (!arg) 1471 { 1472 if (!p.defaultArg) 1473 { 1474 if (tf.varargs == 2 && i + 1 == nparams) 1475 goto L2; 1476 error(loc, "expected %llu function arguments, not %llu", cast(ulong)nparams, cast(ulong)nargs); 1477 return true; 1478 } 1479 arg = p.defaultArg; 1480 arg = inlineCopy(arg, sc); 1481 // __FILE__, __LINE__, __MODULE__, __FUNCTION__, and __PRETTY_FUNCTION__ 1482 arg = arg.resolveLoc(loc, sc); 1483 arguments.push(arg); 1484 nargs++; 1485 } 1486 1487 if (tf.varargs == 2 && i + 1 == nparams) 1488 { 1489 //printf("\t\tvarargs == 2, p->type = '%s'\n", p->type->toChars()); 1490 { 1491 MATCH m; 1492 if ((m = arg.implicitConvTo(p.type)) > MATCHnomatch) 1493 { 1494 if (p.type.nextOf() && arg.implicitConvTo(p.type.nextOf()) >= m) 1495 goto L2; 1496 else if (nargs != nparams) 1497 { 1498 error(loc, "expected %llu function arguments, not %llu", cast(ulong)nparams, cast(ulong)nargs); 1499 return true; 1500 } 1501 goto L1; 1502 } 1503 } 1504 L2: 1505 Type tb = p.type.toBasetype(); 1506 Type tret = p.isLazyArray(); 1507 switch (tb.ty) 1508 { 1509 case Tsarray: 1510 case Tarray: 1511 { 1512 /* Create a static array variable v of type arg->type: 1513 * T[dim] __arrayArg = [ arguments[i], ..., arguments[nargs-1] ]; 1514 * 1515 * The array literal in the initializer of the hidden variable 1516 * is now optimized. See Bugzilla 2356. 1517 */ 1518 Type tbn = (cast(TypeArray)tb).next; 1519 Type tsa = tbn.sarrayOf(nargs - i); 1520 1521 auto elements = new Expressions(); 1522 elements.setDim(nargs - i); 1523 for (size_t u = 0; u < elements.dim; u++) 1524 { 1525 Expression a = (*arguments)[i + u]; 1526 if (tret && a.implicitConvTo(tret)) 1527 { 1528 a = a.implicitCastTo(sc, tret); 1529 a = a.optimize(WANTvalue); 1530 a = toDelegate(a, a.type, sc); 1531 } 1532 else 1533 a = a.implicitCastTo(sc, tbn); 1534 (*elements)[u] = a; 1535 } 1536 // Bugzilla 14395: Convert to a static array literal, or its slice. 1537 arg = new ArrayLiteralExp(loc, elements); 1538 arg.type = tsa; 1539 if (tb.ty == Tarray) 1540 { 1541 arg = new SliceExp(loc, arg, null, null); 1542 arg.type = p.type; 1543 } 1544 break; 1545 } 1546 case Tclass: 1547 { 1548 /* Set arg to be: 1549 * new Tclass(arg0, arg1, ..., argn) 1550 */ 1551 auto args = new Expressions(); 1552 args.setDim(nargs - i); 1553 for (size_t u = i; u < nargs; u++) 1554 (*args)[u - i] = (*arguments)[u]; 1555 arg = new NewExp(loc, null, null, p.type, args); 1556 break; 1557 } 1558 default: 1559 if (!arg) 1560 { 1561 error(loc, "not enough arguments"); 1562 return true; 1563 } 1564 break; 1565 } 1566 arg = arg.semantic(sc); 1567 //printf("\targ = '%s'\n", arg->toChars()); 1568 arguments.setDim(i + 1); 1569 (*arguments)[i] = arg; 1570 nargs = i + 1; 1571 done = 1; 1572 } 1573 1574 L1: 1575 if (!(p.storageClass & STClazy && p.type.ty == Tvoid)) 1576 { 1577 bool isRef = (p.storageClass & (STCref | STCout)) != 0; 1578 if (ubyte wm = arg.type.deduceWild(p.type, isRef)) 1579 { 1580 if (wildmatch) 1581 wildmatch = MODmerge(wildmatch, wm); 1582 else 1583 wildmatch = wm; 1584 //printf("[%d] p = %s, a = %s, wm = %d, wildmatch = %d\n", i, p->type->toChars(), arg->type->toChars(), wm, wildmatch); 1585 } 1586 } 1587 } 1588 if (done) 1589 break; 1590 } 1591 if ((wildmatch == MODmutable || wildmatch == MODimmutable) && tf.next.hasWild() && (tf.isref || !tf.next.implicitConvTo(tf.next.immutableOf()))) 1592 { 1593 if (fd) 1594 { 1595 /* If the called function may return the reference to 1596 * outer inout data, it should be rejected. 1597 * 1598 * void foo(ref inout(int) x) { 1599 * ref inout(int) bar(inout(int)) { return x; } 1600 * struct S { ref inout(int) bar() inout { return x; } } 1601 * bar(int.init) = 1; // bad! 1602 * S().bar() = 1; // bad! 1603 * } 1604 */ 1605 Dsymbol s = null; 1606 if (fd.isThis() || fd.isNested()) 1607 s = fd.toParent2(); 1608 for (; s; s = s.toParent2()) 1609 { 1610 if (auto ad = s.isAggregateDeclaration()) 1611 { 1612 if (ad.isNested()) 1613 continue; 1614 break; 1615 } 1616 if (auto ff = s.isFuncDeclaration()) 1617 { 1618 if ((cast(TypeFunction)ff.type).iswild) 1619 goto Linouterr; 1620 1621 if (ff.isNested() || ff.isThis()) 1622 continue; 1623 } 1624 break; 1625 } 1626 } 1627 else if (tf.isWild()) 1628 { 1629 Linouterr: 1630 const(char)* s = wildmatch == MODmutable ? "mutable" : MODtoChars(wildmatch); 1631 error(loc, "modify inout to %s is not allowed inside inout function", s); 1632 return true; 1633 } 1634 } 1635 1636 assert(nargs >= nparams); 1637 for (size_t i = 0; i < nargs; i++) 1638 { 1639 Expression arg = (*arguments)[i]; 1640 assert(arg); 1641 if (i < nparams) 1642 { 1643 Parameter p = Parameter.getNth(tf.parameters, i); 1644 if (!(p.storageClass & STClazy && p.type.ty == Tvoid)) 1645 { 1646 Type tprm = p.type; 1647 if (p.type.hasWild()) 1648 tprm = p.type.substWildTo(wildmatch); 1649 if (!tprm.equals(arg.type)) 1650 { 1651 //printf("arg->type = %s, p->type = %s\n", arg->type->toChars(), p->type->toChars()); 1652 arg = arg.implicitCastTo(sc, tprm); 1653 arg = arg.optimize(WANTvalue, (p.storageClass & (STCref | STCout)) != 0); 1654 } 1655 } 1656 if (p.storageClass & STCref) 1657 { 1658 arg = arg.toLvalue(sc, arg); 1659 1660 // Look for mutable misaligned pointer, etc., in @safe mode 1661 err |= checkUnsafeAccess(sc, arg, false, true); 1662 } 1663 else if (p.storageClass & STCout) 1664 { 1665 Type t = arg.type; 1666 if (!t.isMutable() || !t.isAssignable()) // check blit assignable 1667 { 1668 arg.error("cannot modify struct %s with immutable members", arg.toChars()); 1669 err = true; 1670 } 1671 else 1672 { 1673 // Look for misaligned pointer, etc., in @safe mode 1674 err |= checkUnsafeAccess(sc, arg, false, true); 1675 err |= checkDefCtor(arg.loc, t); // t must be default constructible 1676 } 1677 arg = arg.toLvalue(sc, arg); 1678 } 1679 else if (p.storageClass & STClazy) 1680 { 1681 // Convert lazy argument to a delegate 1682 if (p.type.ty == Tvoid) 1683 arg = toDelegate(arg, p.type, sc); 1684 else 1685 arg = toDelegate(arg, arg.type, sc); 1686 } 1687 //printf("arg: %s\n", arg->toChars()); 1688 //printf("type: %s\n", arg->type->toChars()); 1689 1690 /* Look for arguments that cannot 'escape' from the called 1691 * function. 1692 */ 1693 if (!tf.parameterEscapes(p)) 1694 { 1695 Expression a = arg; 1696 if (a.op == TOKcast) 1697 a = (cast(CastExp)a).e1; 1698 if (a.op == TOKfunction) 1699 { 1700 /* Function literals can only appear once, so if this 1701 * appearance was scoped, there cannot be any others. 1702 */ 1703 FuncExp fe = cast(FuncExp)a; 1704 fe.fd.tookAddressOf = 0; 1705 } 1706 else if (a.op == TOKdelegate) 1707 { 1708 /* For passing a delegate to a scoped parameter, 1709 * this doesn't count as taking the address of it. 1710 * We only worry about 'escaping' references to the function. 1711 */ 1712 DelegateExp de = cast(DelegateExp)a; 1713 if (de.e1.op == TOKvar) 1714 { 1715 VarExp ve = cast(VarExp)de.e1; 1716 FuncDeclaration f = ve.var.isFuncDeclaration(); 1717 if (f) 1718 { 1719 f.tookAddressOf--; 1720 //printf("--tookAddressOf = %d\n", f.tookAddressOf); 1721 } 1722 } 1723 } 1724 } 1725 arg = arg.optimize(WANTvalue, (p.storageClass & (STCref | STCout)) != 0); 1726 } 1727 else 1728 { 1729 // These will be the trailing ... arguments 1730 // If not D linkage, do promotions 1731 if (tf.linkage != LINKd) 1732 { 1733 // Promote bytes, words, etc., to ints 1734 arg = integralPromotions(arg, sc); 1735 1736 // Promote floats to doubles 1737 switch (arg.type.ty) 1738 { 1739 case Tfloat32: 1740 arg = arg.castTo(sc, Type.tfloat64); 1741 break; 1742 1743 case Timaginary32: 1744 arg = arg.castTo(sc, Type.timaginary64); 1745 break; 1746 1747 default: 1748 break; 1749 } 1750 if (tf.varargs == 1) 1751 { 1752 const(char)* p = tf.linkage == LINKc ? "extern(C)" : "extern(C++)"; 1753 if (arg.type.ty == Tarray) 1754 { 1755 arg.error("cannot pass dynamic arrays to %s vararg functions", p); 1756 err = true; 1757 } 1758 if (arg.type.ty == Tsarray) 1759 { 1760 arg.error("cannot pass static arrays to %s vararg functions", p); 1761 err = true; 1762 } 1763 } 1764 } 1765 1766 // Do not allow types that need destructors 1767 if (arg.type.needsDestruction()) 1768 { 1769 arg.error("cannot pass types that need destruction as variadic arguments"); 1770 err = true; 1771 } 1772 1773 // Convert static arrays to dynamic arrays 1774 // BUG: I don't think this is right for D2 1775 Type tb = arg.type.toBasetype(); 1776 if (tb.ty == Tsarray) 1777 { 1778 TypeSArray ts = cast(TypeSArray)tb; 1779 Type ta = ts.next.arrayOf(); 1780 if (ts.size(arg.loc) == 0) 1781 arg = new NullExp(arg.loc, ta); 1782 else 1783 arg = arg.castTo(sc, ta); 1784 } 1785 if (tb.ty == Tstruct) 1786 { 1787 //arg = callCpCtor(sc, arg); 1788 } 1789 // Give error for overloaded function addresses 1790 if (arg.op == TOKsymoff) 1791 { 1792 SymOffExp se = cast(SymOffExp)arg; 1793 if (se.hasOverloads && !se.var.isFuncDeclaration().isUnique()) 1794 { 1795 arg.error("function %s is overloaded", arg.toChars()); 1796 err = true; 1797 } 1798 } 1799 if (arg.checkValue()) 1800 err = true; 1801 arg = arg.optimize(WANTvalue); 1802 } 1803 (*arguments)[i] = arg; 1804 } 1805 1806 /* Remaining problems: 1807 * 1. order of evaluation - some function push L-to-R, others R-to-L. Until we resolve what array assignment does (which is 1808 * implemented by calling a function) we'll defer this for now. 1809 * 2. value structs (or static arrays of them) that need to be copy constructed 1810 * 3. value structs (or static arrays of them) that have destructors, and subsequent arguments that may throw before the 1811 * function gets called (functions normally destroy their parameters) 1812 * 2 and 3 are handled by doing the argument construction in 'eprefix' so that if a later argument throws, they are cleaned 1813 * up properly. Pushing arguments on the stack then cannot fail. 1814 */ 1815 if (1) 1816 { 1817 /* TODO: tackle problem 1) 1818 */ 1819 const bool leftToRight = true; // TODO: something like !fd.isArrayOp 1820 if (!leftToRight) 1821 assert(nargs == nparams); // no variadics for RTL order, as they would probably be evaluated LTR and so add complexity 1822 1823 const ptrdiff_t start = (leftToRight ? 0 : cast(ptrdiff_t)nargs - 1); 1824 const ptrdiff_t end = (leftToRight ? cast(ptrdiff_t)nargs : -1); 1825 const ptrdiff_t step = (leftToRight ? 1 : -1); 1826 1827 /* Compute indices of last throwing argument and first arg needing destruction. 1828 * Used to not set up destructors unless an arg needs destruction on a throw 1829 * in a later argument. 1830 */ 1831 ptrdiff_t lastthrow = -1; 1832 ptrdiff_t firstdtor = -1; 1833 for (ptrdiff_t i = start; i != end; i += step) 1834 { 1835 Expression arg = (*arguments)[i]; 1836 if (canThrow(arg, sc.func, false)) 1837 lastthrow = i; 1838 if (firstdtor == -1 && arg.type.needsDestruction()) 1839 { 1840 Parameter p = (i >= nparams ? null : Parameter.getNth(tf.parameters, i)); 1841 if (!(p && (p.storageClass & (STClazy | STCref | STCout)))) 1842 firstdtor = i; 1843 } 1844 } 1845 1846 /* Does problem 3) apply to this call? 1847 */ 1848 const bool needsPrefix = (firstdtor >= 0 && lastthrow >= 0 1849 && (lastthrow - firstdtor) * step > 0); 1850 1851 /* If so, initialize 'eprefix' by declaring the gate 1852 */ 1853 VarDeclaration gate = null; 1854 if (needsPrefix) 1855 { 1856 // eprefix => bool __gate [= false] 1857 Identifier idtmp = Identifier.generateId("__gate"); 1858 gate = new VarDeclaration(loc, Type.tbool, idtmp, null); 1859 gate.storage_class |= STCtemp | STCctfe | STCvolatile; 1860 gate.semantic(sc); 1861 1862 auto ae = new DeclarationExp(loc, gate); 1863 eprefix = ae.semantic(sc); 1864 } 1865 1866 for (ptrdiff_t i = start; i != end; i += step) 1867 { 1868 Expression arg = (*arguments)[i]; 1869 1870 Parameter parameter = (i >= nparams ? null : Parameter.getNth(tf.parameters, i)); 1871 const bool isRef = (parameter && (parameter.storageClass & (STCref | STCout))); 1872 const bool isLazy = (parameter && (parameter.storageClass & STClazy)); 1873 1874 /* Skip lazy parameters 1875 */ 1876 if (isLazy) 1877 continue; 1878 1879 /* Do we have a gate? Then we have a prefix and we're not yet past the last throwing arg. 1880 * Declare a temporary variable for this arg and append that declaration to 'eprefix', 1881 * which will implicitly take care of potential problem 2) for this arg. 1882 * 'eprefix' will therefore finally contain all args up to and including the last 1883 * potentially throwing arg, excluding all lazy parameters. 1884 */ 1885 if (gate) 1886 { 1887 const bool needsDtor = (!isRef && arg.type.needsDestruction() && i != lastthrow); 1888 1889 /* Declare temporary 'auto __pfx = arg' (needsDtor) or 'auto __pfy = arg' (!needsDtor) 1890 */ 1891 auto tmp = copyToTemp(0, 1892 needsDtor ? "__pfx" : "__pfy", 1893 !isRef ? arg : arg.addressOf()); 1894 tmp.semantic(sc); 1895 1896 /* Modify the destructor so it only runs if gate==false, i.e., 1897 * only if there was a throw while constructing the args 1898 */ 1899 if (!needsDtor) 1900 { 1901 if (tmp.edtor) 1902 { 1903 assert(i == lastthrow); 1904 tmp.edtor = null; 1905 } 1906 } 1907 else 1908 { 1909 // edtor => (__gate || edtor) 1910 assert(tmp.edtor); 1911 Expression e = tmp.edtor; 1912 e = new OrOrExp(e.loc, new VarExp(e.loc, gate), e); 1913 tmp.edtor = e.semantic(sc); 1914 //printf("edtor: %s\n", tmp.edtor.toChars()); 1915 } 1916 1917 // eprefix => (eprefix, auto __pfx/y = arg) 1918 auto ae = new DeclarationExp(loc, tmp); 1919 eprefix = Expression.combine(eprefix, ae.semantic(sc)); 1920 1921 // arg => __pfx/y 1922 arg = new VarExp(loc, tmp); 1923 arg = arg.semantic(sc); 1924 if (isRef) 1925 { 1926 arg = new PtrExp(loc, arg); 1927 arg = arg.semantic(sc); 1928 } 1929 1930 /* Last throwing arg? Then finalize eprefix => (eprefix, gate = true), 1931 * i.e., disable the dtors right after constructing the last throwing arg. 1932 * From now on, the callee will take care of destructing the args because 1933 * the args are implicitly moved into function parameters. 1934 * 1935 * Set gate to null to let the next iterations know they don't need to 1936 * append to eprefix anymore. 1937 */ 1938 if (i == lastthrow) 1939 { 1940 auto e = new AssignExp(gate.loc, new VarExp(gate.loc, gate), new IntegerExp(gate.loc, 1, Type.tbool)); 1941 eprefix = Expression.combine(eprefix, e.semantic(sc)); 1942 gate = null; 1943 } 1944 } 1945 else 1946 { 1947 /* No gate, no prefix to append to. 1948 * Handle problem 2) by calling the copy constructor for value structs 1949 * (or static arrays of them) if appropriate. 1950 */ 1951 Type tv = arg.type.baseElemOf(); 1952 if (!isRef && tv.ty == Tstruct) 1953 arg = doCopyOrMove(sc, arg); 1954 } 1955 1956 (*arguments)[i] = arg; 1957 } 1958 } 1959 //if (eprefix) printf("eprefix: %s\n", eprefix->toChars()); 1960 1961 // If D linkage and variadic, add _arguments[] as first argument 1962 if (tf.linkage == LINKd && tf.varargs == 1) 1963 { 1964 assert(arguments.dim >= nparams); 1965 1966 auto args = new Parameters(); 1967 args.setDim(arguments.dim - nparams); 1968 for (size_t i = 0; i < arguments.dim - nparams; i++) 1969 { 1970 auto arg = new Parameter(STCin, (*arguments)[nparams + i].type, null, null); 1971 (*args)[i] = arg; 1972 } 1973 auto tup = new TypeTuple(args); 1974 Expression e = new TypeidExp(loc, tup); 1975 e = e.semantic(sc); 1976 arguments.insert(0, e); 1977 } 1978 1979 Type tret = tf.next; 1980 if (isCtorCall) 1981 { 1982 //printf("[%s] fd = %s %s, %d %d %d\n", loc.toChars(), fd->toChars(), fd->type->toChars(), 1983 // wildmatch, tf->isWild(), fd->isolateReturn()); 1984 if (!tthis) 1985 { 1986 assert(sc.intypeof || global.errors); 1987 tthis = fd.isThis().type.addMod(fd.type.mod); 1988 } 1989 if (tf.isWild() && !fd.isolateReturn()) 1990 { 1991 if (wildmatch) 1992 tret = tret.substWildTo(wildmatch); 1993 int offset; 1994 if (!tret.implicitConvTo(tthis) && !(MODimplicitConv(tret.mod, tthis.mod) && tret.isBaseOf(tthis, &offset) && offset == 0)) 1995 { 1996 const(char)* s1 = tret.isNaked() ? " mutable" : tret.modToChars(); 1997 const(char)* s2 = tthis.isNaked() ? " mutable" : tthis.modToChars(); 1998 .error(loc, "inout constructor %s creates%s object, not%s", fd.toPrettyChars(), s1, s2); 1999 err = true; 2000 } 2001 } 2002 tret = tthis; 2003 } 2004 else if (wildmatch && tret) 2005 { 2006 /* Adjust function return type based on wildmatch 2007 */ 2008 //printf("wildmatch = x%x, tret = %s\n", wildmatch, tret.toChars()); 2009 tret = tret.substWildTo(wildmatch); 2010 } 2011 *prettype = tret; 2012 *peprefix = eprefix; 2013 return (err || olderrors != global.errors); 2014 } 2015 2016 /****************************************************************/ 2017 /* A type meant as a union of all the Expression types, 2018 * to serve essentially as a Variant that will sit on the stack 2019 * during CTFE to reduce memory consumption. 2020 */ 2021 struct UnionExp 2022 { 2023 // yes, default constructor does nothing 2024 extern (D) this(Expression e) 2025 { 2026 memcpy(&this, cast(void*)e, e.size); 2027 } 2028 2029 /* Extract pointer to Expression 2030 */ 2031 extern (C++) Expression exp() 2032 { 2033 return cast(Expression)&u; 2034 } 2035 2036 /* Convert to an allocated Expression 2037 */ 2038 extern (C++) Expression copy() 2039 { 2040 Expression e = exp(); 2041 //if (e->size > sizeof(u)) printf("%s\n", Token::toChars(e->op)); 2042 assert(e.size <= u.sizeof); 2043 if (e.op == TOKcantexp) 2044 return CTFEExp.cantexp; 2045 if (e.op == TOKvoidexp) 2046 return CTFEExp.voidexp; 2047 if (e.op == TOKbreak) 2048 return CTFEExp.breakexp; 2049 if (e.op == TOKcontinue) 2050 return CTFEExp.continueexp; 2051 if (e.op == TOKgoto) 2052 return CTFEExp.gotoexp; 2053 return e.copy(); 2054 } 2055 2056 private: 2057 union __AnonStruct__u 2058 { 2059 char[__traits(classInstanceSize, Expression)] exp; 2060 char[__traits(classInstanceSize, IntegerExp)] integerexp; 2061 char[__traits(classInstanceSize, ErrorExp)] errorexp; 2062 char[__traits(classInstanceSize, RealExp)] realexp; 2063 char[__traits(classInstanceSize, ComplexExp)] complexexp; 2064 char[__traits(classInstanceSize, SymOffExp)] symoffexp; 2065 char[__traits(classInstanceSize, StringExp)] stringexp; 2066 char[__traits(classInstanceSize, ArrayLiteralExp)] arrayliteralexp; 2067 char[__traits(classInstanceSize, AssocArrayLiteralExp)] assocarrayliteralexp; 2068 char[__traits(classInstanceSize, StructLiteralExp)] structliteralexp; 2069 char[__traits(classInstanceSize, NullExp)] nullexp; 2070 char[__traits(classInstanceSize, DotVarExp)] dotvarexp; 2071 char[__traits(classInstanceSize, AddrExp)] addrexp; 2072 char[__traits(classInstanceSize, IndexExp)] indexexp; 2073 char[__traits(classInstanceSize, SliceExp)] sliceexp; 2074 // Ensure that the union is suitably aligned. 2075 real_t for_alignment_only; 2076 } 2077 2078 __AnonStruct__u u; 2079 } 2080 2081 /******************************** 2082 * Test to see if two reals are the same. 2083 * Regard NaN's as equivalent. 2084 * Regard +0 and -0 as different. 2085 */ 2086 extern (C++) int RealEquals(real_t x1, real_t x2) 2087 { 2088 return (CTFloat.isNaN(x1) && CTFloat.isNaN(x2)) || CTFloat.isIdentical(x1, x2); 2089 } 2090 2091 /************************ TypeDotIdExp ************************************/ 2092 /* Things like: 2093 * int.size 2094 * foo.size 2095 * (foo).size 2096 * cast(foo).size 2097 */ 2098 extern (C++) DotIdExp typeDotIdExp(Loc loc, Type type, Identifier ident) 2099 { 2100 return new DotIdExp(loc, new TypeExp(loc, type), ident); 2101 } 2102 2103 /*********************************************** 2104 * Mark variable v as modified if it is inside a constructor that var 2105 * is a field in. 2106 */ 2107 extern (C++) int modifyFieldVar(Loc loc, Scope* sc, VarDeclaration var, Expression e1) 2108 { 2109 //printf("modifyFieldVar(var = %s)\n", var->toChars()); 2110 Dsymbol s = sc.func; 2111 while (1) 2112 { 2113 FuncDeclaration fd = null; 2114 if (s) 2115 fd = s.isFuncDeclaration(); 2116 if (fd && 2117 ((fd.isCtorDeclaration() && var.isField()) || 2118 (fd.isStaticCtorDeclaration() && !var.isField())) && 2119 fd.toParent2() == var.toParent2() && 2120 (!e1 || e1.op == TOKthis)) 2121 { 2122 bool result = true; 2123 2124 var.ctorinit = true; 2125 //printf("setting ctorinit\n"); 2126 2127 if (var.isField() && sc.fieldinit && !sc.intypeof) 2128 { 2129 assert(e1); 2130 auto mustInit = ((var.storage_class & STCnodefaultctor) != 0 || 2131 var.type.needsNested()); 2132 2133 auto dim = sc.fieldinit_dim; 2134 auto ad = fd.isMember2(); 2135 assert(ad); 2136 size_t i; 2137 for (i = 0; i < dim; i++) // same as findFieldIndexByName in ctfeexp.c ? 2138 { 2139 if (ad.fields[i] == var) 2140 break; 2141 } 2142 assert(i < dim); 2143 uint fi = sc.fieldinit[i]; 2144 2145 if (fi & CSXthis_ctor) 2146 { 2147 if (var.type.isMutable() && e1.type.isMutable()) 2148 result = false; 2149 else 2150 { 2151 const(char)* modStr = !var.type.isMutable() ? MODtoChars(var.type.mod) : MODtoChars(e1.type.mod); 2152 .error(loc, "%s field '%s' initialized multiple times", modStr, var.toChars()); 2153 } 2154 } 2155 else if (sc.noctor || (fi & CSXlabel)) 2156 { 2157 if (!mustInit && var.type.isMutable() && e1.type.isMutable()) 2158 result = false; 2159 else 2160 { 2161 const(char)* modStr = !var.type.isMutable() ? MODtoChars(var.type.mod) : MODtoChars(e1.type.mod); 2162 .error(loc, "%s field '%s' initialization is not allowed in loops or after labels", modStr, var.toChars()); 2163 } 2164 } 2165 2166 sc.fieldinit[i] |= CSXthis_ctor; 2167 if (var.overlapped) // Bugzilla 15258 2168 { 2169 foreach (j, v; ad.fields) 2170 { 2171 if (v is var || !var.isOverlappedWith(v)) 2172 continue; 2173 v.ctorinit = true; 2174 sc.fieldinit[j] = CSXthis_ctor; 2175 } 2176 } 2177 } 2178 else if (fd != sc.func) 2179 { 2180 if (var.type.isMutable()) 2181 result = false; 2182 else if (sc.func.fes) 2183 { 2184 const(char)* p = var.isField() ? "field" : var.kind(); 2185 .error(loc, "%s %s '%s' initialization is not allowed in foreach loop", 2186 MODtoChars(var.type.mod), p, var.toChars()); 2187 } 2188 else 2189 { 2190 const(char)* p = var.isField() ? "field" : var.kind(); 2191 .error(loc, "%s %s '%s' initialization is not allowed in nested function '%s'", 2192 MODtoChars(var.type.mod), p, var.toChars(), sc.func.toChars()); 2193 } 2194 } 2195 return result; 2196 } 2197 else 2198 { 2199 if (s) 2200 { 2201 s = s.toParent2(); 2202 continue; 2203 } 2204 } 2205 break; 2206 } 2207 return false; 2208 } 2209 2210 extern (C++) Expression opAssignToOp(Loc loc, TOK op, Expression e1, Expression e2) 2211 { 2212 Expression e; 2213 switch (op) 2214 { 2215 case TOKaddass: 2216 e = new AddExp(loc, e1, e2); 2217 break; 2218 2219 case TOKminass: 2220 e = new MinExp(loc, e1, e2); 2221 break; 2222 2223 case TOKmulass: 2224 e = new MulExp(loc, e1, e2); 2225 break; 2226 2227 case TOKdivass: 2228 e = new DivExp(loc, e1, e2); 2229 break; 2230 2231 case TOKmodass: 2232 e = new ModExp(loc, e1, e2); 2233 break; 2234 2235 case TOKandass: 2236 e = new AndExp(loc, e1, e2); 2237 break; 2238 2239 case TOKorass: 2240 e = new OrExp(loc, e1, e2); 2241 break; 2242 2243 case TOKxorass: 2244 e = new XorExp(loc, e1, e2); 2245 break; 2246 2247 case TOKshlass: 2248 e = new ShlExp(loc, e1, e2); 2249 break; 2250 2251 case TOKshrass: 2252 e = new ShrExp(loc, e1, e2); 2253 break; 2254 2255 case TOKushrass: 2256 e = new UshrExp(loc, e1, e2); 2257 break; 2258 2259 default: 2260 assert(0); 2261 } 2262 return e; 2263 } 2264 2265 /****************************************************************/ 2266 2267 extern (C++) Expression extractOpDollarSideEffect(Scope* sc, UnaExp ue) 2268 { 2269 Expression e0; 2270 Expression e1 = Expression.extractLast(ue.e1, &e0); 2271 // Bugzilla 12585: Extract the side effect part if ue->e1 is comma. 2272 2273 if (!isTrivialExp(e1)) 2274 { 2275 /* Even if opDollar is needed, 'e1' should be evaluate only once. So 2276 * Rewrite: 2277 * e1.opIndex( ... use of $ ... ) 2278 * e1.opSlice( ... use of $ ... ) 2279 * as: 2280 * (ref __dop = e1, __dop).opIndex( ... __dop.opDollar ...) 2281 * (ref __dop = e1, __dop).opSlice( ... __dop.opDollar ...) 2282 */ 2283 e1 = extractSideEffect(sc, "__dop", e0, e1, false); 2284 assert(e1.op == TOKvar); 2285 VarExp ve = cast(VarExp)e1; 2286 ve.var.storage_class |= STCexptemp; // lifetime limited to expression 2287 } 2288 ue.e1 = e1; 2289 return e0; 2290 } 2291 2292 /************************************** 2293 * Runs semantic on ae->arguments. Declares temporary variables 2294 * if '$' was used. 2295 */ 2296 extern (C++) Expression resolveOpDollar(Scope* sc, ArrayExp ae, Expression* pe0) 2297 { 2298 assert(!ae.lengthVar); 2299 *pe0 = null; 2300 AggregateDeclaration ad = isAggregate(ae.e1.type); 2301 Dsymbol slice = search_function(ad, Id.slice); 2302 //printf("slice = %s %s\n", slice->kind(), slice->toChars()); 2303 for (size_t i = 0; i < ae.arguments.dim; i++) 2304 { 2305 if (i == 0) 2306 *pe0 = extractOpDollarSideEffect(sc, ae); 2307 2308 Expression e = (*ae.arguments)[i]; 2309 if (e.op == TOKinterval && !(slice && slice.isTemplateDeclaration())) 2310 { 2311 Lfallback: 2312 if (ae.arguments.dim == 1) 2313 return null; 2314 ae.error("multi-dimensional slicing requires template opSlice"); 2315 return new ErrorExp(); 2316 } 2317 //printf("[%d] e = %s\n", i, e->toChars()); 2318 2319 // Create scope for '$' variable for this dimension 2320 auto sym = new ArrayScopeSymbol(sc, ae); 2321 sym.loc = ae.loc; 2322 sym.parent = sc.scopesym; 2323 sc = sc.push(sym); 2324 ae.lengthVar = null; // Create it only if required 2325 ae.currentDimension = i; // Dimension for $, if required 2326 2327 e = e.semantic(sc); 2328 e = resolveProperties(sc, e); 2329 2330 if (ae.lengthVar && sc.func) 2331 { 2332 // If $ was used, declare it now 2333 Expression de = new DeclarationExp(ae.loc, ae.lengthVar); 2334 de = de.semantic(sc); 2335 *pe0 = Expression.combine(*pe0, de); 2336 } 2337 sc = sc.pop(); 2338 2339 if (e.op == TOKinterval) 2340 { 2341 IntervalExp ie = cast(IntervalExp)e; 2342 2343 auto tiargs = new Objects(); 2344 Expression edim = new IntegerExp(ae.loc, i, Type.tsize_t); 2345 edim = edim.semantic(sc); 2346 tiargs.push(edim); 2347 2348 auto fargs = new Expressions(); 2349 fargs.push(ie.lwr); 2350 fargs.push(ie.upr); 2351 2352 uint xerrors = global.startGagging(); 2353 sc = sc.push(); 2354 FuncDeclaration fslice = resolveFuncCall(ae.loc, sc, slice, tiargs, ae.e1.type, fargs, 1); 2355 sc = sc.pop(); 2356 global.endGagging(xerrors); 2357 if (!fslice) 2358 goto Lfallback; 2359 2360 e = new DotTemplateInstanceExp(ae.loc, ae.e1, slice.ident, tiargs); 2361 e = new CallExp(ae.loc, e, fargs); 2362 e = e.semantic(sc); 2363 } 2364 2365 if (!e.type) 2366 { 2367 ae.error("%s has no value", e.toChars()); 2368 e = new ErrorExp(); 2369 } 2370 if (e.op == TOKerror) 2371 return e; 2372 2373 (*ae.arguments)[i] = e; 2374 } 2375 return ae; 2376 } 2377 2378 /************************************** 2379 * Runs semantic on se->lwr and se->upr. Declares a temporary variable 2380 * if '$' was used. 2381 */ 2382 extern (C++) Expression resolveOpDollar(Scope* sc, ArrayExp ae, IntervalExp ie, Expression* pe0) 2383 { 2384 //assert(!ae->lengthVar); 2385 if (!ie) 2386 return ae; 2387 2388 VarDeclaration lengthVar = ae.lengthVar; 2389 2390 // create scope for '$' 2391 auto sym = new ArrayScopeSymbol(sc, ae); 2392 sym.loc = ae.loc; 2393 sym.parent = sc.scopesym; 2394 sc = sc.push(sym); 2395 2396 for (size_t i = 0; i < 2; ++i) 2397 { 2398 Expression e = i == 0 ? ie.lwr : ie.upr; 2399 e = e.semantic(sc); 2400 e = resolveProperties(sc, e); 2401 if (!e.type) 2402 { 2403 ae.error("%s has no value", e.toChars()); 2404 return new ErrorExp(); 2405 } 2406 (i == 0 ? ie.lwr : ie.upr) = e; 2407 } 2408 2409 if (lengthVar != ae.lengthVar && sc.func) 2410 { 2411 // If $ was used, declare it now 2412 Expression de = new DeclarationExp(ae.loc, ae.lengthVar); 2413 de = de.semantic(sc); 2414 *pe0 = Expression.combine(*pe0, de); 2415 } 2416 2417 sc = sc.pop(); 2418 2419 return ae; 2420 } 2421 2422 /*********************************************************** 2423 * Resolve `exp` as a compile-time known string. 2424 * Params: 2425 * sc = scope 2426 * exp = Expression which expected as a string 2427 * s = What the string is expected for, will be used in error diagnostic. 2428 * Returns: 2429 * String literal, or `null` if error happens. 2430 */ 2431 StringExp semanticString(Scope *sc, Expression exp, const char* s) 2432 { 2433 sc = sc.startCTFE(); 2434 exp = exp.semantic(sc); 2435 exp = resolveProperties(sc, exp); 2436 sc = sc.endCTFE(); 2437 2438 if (exp.op == TOKerror) 2439 return null; 2440 2441 auto e = exp; 2442 if (exp.type.isString()) 2443 { 2444 e = e.ctfeInterpret(); 2445 if (e.op == TOKerror) 2446 return null; 2447 } 2448 2449 auto se = e.toStringExp(); 2450 if (!se) 2451 { 2452 exp.error("string expected for %s, not (%s) of type %s", 2453 s, exp.toChars(), exp.type.toChars()); 2454 return null; 2455 } 2456 return se; 2457 } 2458 2459 enum OwnedBy : int 2460 { 2461 OWNEDcode, // normal code expression in AST 2462 OWNEDctfe, // value expression for CTFE 2463 OWNEDcache, // constant value cached for CTFE 2464 } 2465 2466 alias OWNEDcode = OwnedBy.OWNEDcode; 2467 alias OWNEDctfe = OwnedBy.OWNEDctfe; 2468 alias OWNEDcache = OwnedBy.OWNEDcache; 2469 2470 enum WANTvalue = 0; // default 2471 enum WANTexpand = 1; // expand const/immutable variables if possible 2472 2473 /*********************************************************** 2474 */ 2475 extern (C++) abstract class Expression : RootObject 2476 { 2477 Loc loc; // file location 2478 Type type; // !=null means that semantic() has been run 2479 TOK op; // to minimize use of dynamic_cast 2480 ubyte size; // # of bytes in Expression so we can copy() it 2481 ubyte parens; // if this is a parenthesized expression 2482 2483 final extern (D) this(Loc loc, TOK op, int size) 2484 { 2485 //printf("Expression::Expression(op = %d) this = %p\n", op, this); 2486 this.loc = loc; 2487 this.op = op; 2488 this.size = cast(ubyte)size; 2489 } 2490 2491 static void _init() 2492 { 2493 CTFEExp.cantexp = new CTFEExp(TOKcantexp); 2494 CTFEExp.voidexp = new CTFEExp(TOKvoidexp); 2495 CTFEExp.breakexp = new CTFEExp(TOKbreak); 2496 CTFEExp.continueexp = new CTFEExp(TOKcontinue); 2497 CTFEExp.gotoexp = new CTFEExp(TOKgoto); 2498 } 2499 2500 /********************************* 2501 * Does *not* do a deep copy. 2502 */ 2503 final Expression copy() 2504 { 2505 Expression e; 2506 if (!size) 2507 { 2508 debug 2509 { 2510 fprintf(stderr, "No expression copy for: %s\n", toChars()); 2511 printf("op = %d\n", op); 2512 print(); 2513 } 2514 assert(0); 2515 } 2516 e = cast(Expression)mem.xmalloc(size); 2517 //printf("Expression::copy(op = %d) e = %p\n", op, e); 2518 return cast(Expression)memcpy(cast(void*)e, cast(void*)this, size); 2519 } 2520 2521 Expression syntaxCopy() 2522 { 2523 //printf("Expression::syntaxCopy()\n"); 2524 //print(); 2525 return copy(); 2526 } 2527 2528 /************************** 2529 * Semantically analyze Expression. 2530 * Determine types, fold constants, etc. 2531 */ 2532 Expression semantic(Scope* sc) 2533 { 2534 static if (LOGSEMANTIC) 2535 { 2536 printf("Expression::semantic() %s\n", toChars()); 2537 } 2538 if (type) 2539 type = type.semantic(loc, sc); 2540 else 2541 type = Type.tvoid; 2542 return this; 2543 } 2544 2545 /********************************** 2546 * Try to run semantic routines. 2547 * If they fail, return NULL. 2548 */ 2549 final Expression trySemantic(Scope* sc) 2550 { 2551 //printf("+trySemantic(%s)\n", toChars()); 2552 uint errors = global.startGagging(); 2553 Expression e = semantic(sc); 2554 if (global.endGagging(errors)) 2555 { 2556 e = null; 2557 } 2558 //printf("-trySemantic(%s)\n", toChars()); 2559 return e; 2560 } 2561 2562 // kludge for template.isExpression() 2563 override final int dyncast() 2564 { 2565 return DYNCAST_EXPRESSION; 2566 } 2567 2568 override final void print() 2569 { 2570 fprintf(stderr, "%s\n", toChars()); 2571 fflush(stderr); 2572 } 2573 2574 override const(char)* toChars() 2575 { 2576 OutBuffer buf; 2577 HdrGenState hgs; 2578 toCBuffer(this, &buf, &hgs); 2579 return buf.extractString(); 2580 } 2581 2582 /******************** 2583 * Print AST data structure in a nice format. 2584 * Params: 2585 * indent = indentation level 2586 */ 2587 void printAST(int indent = 0) 2588 { 2589 foreach (i; 0 .. indent) 2590 printf(" "); 2591 printf("%s %s\n", Token.toChars(op), type ? type.toChars() : ""); 2592 } 2593 2594 final void error(const(char)* format, ...) const 2595 { 2596 if (type != Type.terror) 2597 { 2598 va_list ap; 2599 va_start(ap, format); 2600 .verror(loc, format, ap); 2601 va_end(ap); 2602 } 2603 } 2604 2605 final void warning(const(char)* format, ...) const 2606 { 2607 if (type != Type.terror) 2608 { 2609 va_list ap; 2610 va_start(ap, format); 2611 .vwarning(loc, format, ap); 2612 va_end(ap); 2613 } 2614 } 2615 2616 final void deprecation(const(char)* format, ...) const 2617 { 2618 if (type != Type.terror) 2619 { 2620 va_list ap; 2621 va_start(ap, format); 2622 .vdeprecation(loc, format, ap); 2623 va_end(ap); 2624 } 2625 } 2626 2627 /********************************** 2628 * Combine e1 and e2 by CommaExp if both are not NULL. 2629 */ 2630 static Expression combine(Expression e1, Expression e2) 2631 { 2632 if (e1) 2633 { 2634 if (e2) 2635 { 2636 e1 = new CommaExp(e1.loc, e1, e2); 2637 e1.type = e2.type; 2638 } 2639 } 2640 else 2641 e1 = e2; 2642 return e1; 2643 } 2644 2645 /********************************** 2646 * If 'e' is a tree of commas, returns the leftmost expression 2647 * by stripping off it from the tree. The remained part of the tree 2648 * is returned via *pe0. 2649 * Otherwise 'e' is directly returned and *pe0 is set to NULL. 2650 */ 2651 static Expression extractLast(Expression e, Expression* pe0) 2652 { 2653 if (e.op != TOKcomma) 2654 { 2655 *pe0 = null; 2656 return e; 2657 } 2658 2659 CommaExp ce = cast(CommaExp)e; 2660 if (ce.e2.op != TOKcomma) 2661 { 2662 *pe0 = ce.e1; 2663 return ce.e2; 2664 } 2665 else 2666 { 2667 *pe0 = e; 2668 2669 Expression* pce = &ce.e2; 2670 while ((cast(CommaExp)(*pce)).e2.op == TOKcomma) 2671 { 2672 pce = &(cast(CommaExp)(*pce)).e2; 2673 } 2674 assert((*pce).op == TOKcomma); 2675 ce = cast(CommaExp)(*pce); 2676 *pce = ce.e1; 2677 2678 return ce.e2; 2679 } 2680 } 2681 2682 static Expressions* arraySyntaxCopy(Expressions* exps) 2683 { 2684 Expressions* a = null; 2685 if (exps) 2686 { 2687 a = new Expressions(); 2688 a.setDim(exps.dim); 2689 for (size_t i = 0; i < a.dim; i++) 2690 { 2691 Expression e = (*exps)[i]; 2692 (*a)[i] = e ? e.syntaxCopy() : null; 2693 } 2694 } 2695 return a; 2696 } 2697 2698 dinteger_t toInteger() 2699 { 2700 //printf("Expression %s\n", Token::toChars(op)); 2701 error("integer constant expression expected instead of %s", toChars()); 2702 return 0; 2703 } 2704 2705 uinteger_t toUInteger() 2706 { 2707 //printf("Expression %s\n", Token::toChars(op)); 2708 return cast(uinteger_t)toInteger(); 2709 } 2710 2711 real_t toReal() 2712 { 2713 error("floating point constant expression expected instead of %s", toChars()); 2714 return CTFloat.zero; 2715 } 2716 2717 real_t toImaginary() 2718 { 2719 error("floating point constant expression expected instead of %s", toChars()); 2720 return CTFloat.zero; 2721 } 2722 2723 complex_t toComplex() 2724 { 2725 error("floating point constant expression expected instead of %s", toChars()); 2726 return complex_t(CTFloat.zero); 2727 } 2728 2729 StringExp toStringExp() 2730 { 2731 return null; 2732 } 2733 2734 /*************************************** 2735 * Return !=0 if expression is an lvalue. 2736 */ 2737 bool isLvalue() 2738 { 2739 return false; 2740 } 2741 2742 /******************************* 2743 * Give error if we're not an lvalue. 2744 * If we can, convert expression to be an lvalue. 2745 */ 2746 Expression toLvalue(Scope* sc, Expression e) 2747 { 2748 if (!e) 2749 e = this; 2750 else if (!loc.filename) 2751 loc = e.loc; 2752 2753 if (e.op == TOKtype) 2754 error("%s '%s' is a type, not an lvalue", e.type.kind(), e.type.toChars()); 2755 else 2756 error("%s is not an lvalue", e.toChars()); 2757 2758 return new ErrorExp(); 2759 } 2760 2761 Expression modifiableLvalue(Scope* sc, Expression e) 2762 { 2763 //printf("Expression::modifiableLvalue() %s, type = %s\n", toChars(), type->toChars()); 2764 // See if this expression is a modifiable lvalue (i.e. not const) 2765 if (checkModifiable(sc) == 1) 2766 { 2767 assert(type); 2768 if (!type.isMutable()) 2769 { 2770 error("cannot modify %s expression %s", MODtoChars(type.mod), toChars()); 2771 return new ErrorExp(); 2772 } 2773 else if (!type.isAssignable()) 2774 { 2775 error("cannot modify struct %s %s with immutable members", toChars(), type.toChars()); 2776 return new ErrorExp(); 2777 } 2778 } 2779 return toLvalue(sc, e); 2780 } 2781 2782 final Expression implicitCastTo(Scope* sc, Type t) 2783 { 2784 return .implicitCastTo(this, sc, t); 2785 } 2786 2787 final MATCH implicitConvTo(Type t) 2788 { 2789 return .implicitConvTo(this, t); 2790 } 2791 2792 final Expression castTo(Scope* sc, Type t) 2793 { 2794 return .castTo(this, sc, t); 2795 } 2796 2797 /**************************************** 2798 * Resolve __FILE__, __LINE__, __MODULE__, __FUNCTION__, __PRETTY_FUNCTION__ to loc. 2799 */ 2800 Expression resolveLoc(Loc loc, Scope* sc) 2801 { 2802 return this; 2803 } 2804 2805 /**************************************** 2806 * Check that the expression has a valid type. 2807 * If not, generates an error "... has no type". 2808 * Returns: 2809 * true if the expression is not valid. 2810 * Note: 2811 * When this function returns true, `checkValue()` should also return true. 2812 */ 2813 bool checkType() 2814 { 2815 return false; 2816 } 2817 2818 /**************************************** 2819 * Check that the expression has a valid value. 2820 * If not, generates an error "... has no value". 2821 * Returns: 2822 * true if the expression is not valid or has void type. 2823 */ 2824 bool checkValue() 2825 { 2826 if (type && type.toBasetype().ty == Tvoid) 2827 { 2828 error("expression %s is void and has no value", toChars()); 2829 //print(); assert(0); 2830 if (!global.gag) 2831 type = Type.terror; 2832 return true; 2833 } 2834 return false; 2835 } 2836 2837 final bool checkScalar() 2838 { 2839 if (op == TOKerror) 2840 return true; 2841 if (type.toBasetype().ty == Terror) 2842 return true; 2843 if (!type.isscalar()) 2844 { 2845 error("'%s' is not a scalar, it is a %s", toChars(), type.toChars()); 2846 return true; 2847 } 2848 return checkValue(); 2849 } 2850 2851 final bool checkNoBool() 2852 { 2853 if (op == TOKerror) 2854 return true; 2855 if (type.toBasetype().ty == Terror) 2856 return true; 2857 if (type.toBasetype().ty == Tbool) 2858 { 2859 error("operation not allowed on bool '%s'", toChars()); 2860 return true; 2861 } 2862 return false; 2863 } 2864 2865 final bool checkIntegral() 2866 { 2867 if (op == TOKerror) 2868 return true; 2869 if (type.toBasetype().ty == Terror) 2870 return true; 2871 if (!type.isintegral()) 2872 { 2873 error("'%s' is not of integral type, it is a %s", toChars(), type.toChars()); 2874 return true; 2875 } 2876 return checkValue(); 2877 } 2878 2879 final bool checkArithmetic() 2880 { 2881 if (op == TOKerror) 2882 return true; 2883 if (type.toBasetype().ty == Terror) 2884 return true; 2885 if (!type.isintegral() && !type.isfloating()) 2886 { 2887 error("'%s' is not of arithmetic type, it is a %s", toChars(), type.toChars()); 2888 return true; 2889 } 2890 return checkValue(); 2891 } 2892 2893 final void checkDeprecated(Scope* sc, Dsymbol s) 2894 { 2895 s.checkDeprecated(loc, sc); 2896 } 2897 2898 /********************************************* 2899 * Calling function f. 2900 * Check the purity, i.e. if we're in a pure function 2901 * we can only call other pure functions. 2902 * Returns true if error occurs. 2903 */ 2904 final bool checkPurity(Scope* sc, FuncDeclaration f) 2905 { 2906 if (!sc.func) 2907 return false; 2908 if (sc.func == f) 2909 return false; 2910 if (sc.intypeof == 1) 2911 return false; 2912 if (sc.flags & (SCOPEctfe | SCOPEdebug)) 2913 return false; 2914 2915 /* Given: 2916 * void f() { 2917 * pure void g() { 2918 * /+pure+/ void h() { 2919 * /+pure+/ void i() { } 2920 * } 2921 * } 2922 * } 2923 * g() can call h() but not f() 2924 * i() can call h() and g() but not f() 2925 */ 2926 2927 // Find the closest pure parent of the calling function 2928 FuncDeclaration outerfunc = sc.func; 2929 FuncDeclaration calledparent = f; 2930 2931 if (outerfunc.isInstantiated()) 2932 { 2933 // The attributes of outerfunc should be inferred from the call of f. 2934 } 2935 else if (f.isInstantiated()) 2936 { 2937 // The attributes of f are inferred from its body. 2938 } 2939 else if (f.isFuncLiteralDeclaration()) 2940 { 2941 // The attributes of f are always inferred in its declared place. 2942 } 2943 else 2944 { 2945 /* Today, static local functions are impure by default, but they cannot 2946 * violate purity of enclosing functions. 2947 * 2948 * auto foo() pure { // non instantiated funciton 2949 * static auto bar() { // static, without pure attribute 2950 * impureFunc(); // impure call 2951 * // Although impureFunc is called inside bar, f(= impureFunc) 2952 * // is not callable inside pure outerfunc(= foo <- bar). 2953 * } 2954 * 2955 * bar(); 2956 * // Although bar is called inside foo, f(= bar) is callable 2957 * // bacause calledparent(= foo) is same with outerfunc(= foo). 2958 * } 2959 */ 2960 2961 while (outerfunc.toParent2() && outerfunc.isPureBypassingInference() == PUREimpure && outerfunc.toParent2().isFuncDeclaration()) 2962 { 2963 outerfunc = outerfunc.toParent2().isFuncDeclaration(); 2964 if (outerfunc.type.ty == Terror) 2965 return true; 2966 } 2967 while (calledparent.toParent2() && calledparent.isPureBypassingInference() == PUREimpure && calledparent.toParent2().isFuncDeclaration()) 2968 { 2969 calledparent = calledparent.toParent2().isFuncDeclaration(); 2970 if (calledparent.type.ty == Terror) 2971 return true; 2972 } 2973 } 2974 2975 // If the caller has a pure parent, then either the called func must be pure, 2976 // OR, they must have the same pure parent. 2977 if (!f.isPure() && calledparent != outerfunc) 2978 { 2979 FuncDeclaration ff = outerfunc; 2980 if (sc.flags & SCOPEcompile ? ff.isPureBypassingInference() >= PUREweak : ff.setImpure()) 2981 { 2982 error("pure %s '%s' cannot call impure %s '%s'", 2983 ff.kind(), ff.toPrettyChars(), f.kind(), f.toPrettyChars()); 2984 return true; 2985 } 2986 } 2987 return false; 2988 } 2989 2990 /******************************************* 2991 * Accessing variable v. 2992 * Check for purity and safety violations. 2993 * Returns true if error occurs. 2994 */ 2995 final bool checkPurity(Scope* sc, VarDeclaration v) 2996 { 2997 //printf("v = %s %s\n", v->type->toChars(), v->toChars()); 2998 /* Look for purity and safety violations when accessing variable v 2999 * from current function. 3000 */ 3001 if (!sc.func) 3002 return false; 3003 if (sc.intypeof == 1) 3004 return false; // allow violations inside typeof(expression) 3005 if (sc.flags & (SCOPEctfe | SCOPEdebug)) 3006 return false; // allow violations inside compile-time evaluated expressions and debug conditionals 3007 if (v.ident == Id.ctfe) 3008 return false; // magic variable never violates pure and safe 3009 if (v.isImmutable()) 3010 return false; // always safe and pure to access immutables... 3011 if (v.isConst() && !v.isRef() && (v.isDataseg() || v.isParameter()) && v.type.implicitConvTo(v.type.immutableOf())) 3012 return false; // or const global/parameter values which have no mutable indirections 3013 if (v.storage_class & STCmanifest) 3014 return false; // ...or manifest constants 3015 3016 bool err = false; 3017 if (v.isDataseg()) 3018 { 3019 // Bugzilla 7533: Accessing implicit generated __gate is pure. 3020 if (v.ident == Id.gate) 3021 return false; 3022 3023 /* Accessing global mutable state. 3024 * Therefore, this function and all its immediately enclosing 3025 * functions must be pure. 3026 */ 3027 /* Today, static local functions are impure by default, but they cannot 3028 * violate purity of enclosing functions. 3029 * 3030 * auto foo() pure { // non instantiated funciton 3031 * static auto bar() { // static, without pure attribute 3032 * globalData++; // impure access 3033 * // Although globalData is accessed inside bar, 3034 * // it is not accessible inside pure foo. 3035 * } 3036 * } 3037 */ 3038 for (Dsymbol s = sc.func; s; s = s.toParent2()) 3039 { 3040 FuncDeclaration ff = s.isFuncDeclaration(); 3041 if (!ff) 3042 break; 3043 if (sc.flags & SCOPEcompile ? ff.isPureBypassingInference() >= PUREweak : ff.setImpure()) 3044 { 3045 error("pure %s '%s' cannot access mutable static data '%s'", 3046 ff.kind(), ff.toPrettyChars(), v.toChars()); 3047 err = true; 3048 break; 3049 } 3050 3051 /* If the enclosing is an instantiated function or a lambda, its 3052 * attribute inference result is preferred. 3053 */ 3054 if (ff.isInstantiated()) 3055 break; 3056 if (ff.isFuncLiteralDeclaration()) 3057 break; 3058 } 3059 } 3060 else 3061 { 3062 /* Given: 3063 * void f() { 3064 * int fx; 3065 * pure void g() { 3066 * int gx; 3067 * /+pure+/ void h() { 3068 * int hx; 3069 * /+pure+/ void i() { } 3070 * } 3071 * } 3072 * } 3073 * i() can modify hx and gx but not fx 3074 */ 3075 3076 Dsymbol vparent = v.toParent2(); 3077 for (Dsymbol s = sc.func; !err && s; s = s.toParent2()) 3078 { 3079 if (s == vparent) 3080 break; 3081 3082 if (AggregateDeclaration ad = s.isAggregateDeclaration()) 3083 { 3084 if (ad.isNested()) 3085 continue; 3086 break; 3087 } 3088 FuncDeclaration ff = s.isFuncDeclaration(); 3089 if (!ff) 3090 break; 3091 if (ff.isNested() || ff.isThis()) 3092 { 3093 if (ff.type.isImmutable() || 3094 ff.type.isShared() && !MODimplicitConv(ff.type.mod, v.type.mod)) 3095 { 3096 OutBuffer ffbuf; 3097 OutBuffer vbuf; 3098 MODMatchToBuffer(&ffbuf, ff.type.mod, v.type.mod); 3099 MODMatchToBuffer(&vbuf, v.type.mod, ff.type.mod); 3100 error("%s%s '%s' cannot access %sdata '%s'", 3101 ffbuf.peekString(), ff.kind(), ff.toPrettyChars(), vbuf.peekString(), v.toChars()); 3102 err = true; 3103 break; 3104 } 3105 continue; 3106 } 3107 break; 3108 } 3109 } 3110 3111 /* Do not allow safe functions to access __gshared data 3112 */ 3113 if (v.storage_class & STCgshared) 3114 { 3115 if (sc.func.setUnsafe()) 3116 { 3117 error("safe %s '%s' cannot access __gshared data '%s'", 3118 sc.func.kind(), sc.func.toChars(), v.toChars()); 3119 err = true; 3120 } 3121 } 3122 3123 return err; 3124 } 3125 3126 /********************************************* 3127 * Calling function f. 3128 * Check the safety, i.e. if we're in a @safe function 3129 * we can only call @safe or @trusted functions. 3130 * Returns true if error occurs. 3131 */ 3132 final bool checkSafety(Scope* sc, FuncDeclaration f) 3133 { 3134 if (!sc.func) 3135 return false; 3136 if (sc.func == f) 3137 return false; 3138 if (sc.intypeof == 1) 3139 return false; 3140 if (sc.flags & SCOPEctfe) 3141 return false; 3142 3143 if (!f.isSafe() && !f.isTrusted()) 3144 { 3145 if (sc.flags & SCOPEcompile ? sc.func.isSafeBypassingInference() : sc.func.setUnsafe()) 3146 { 3147 if (loc.linnum == 0) // e.g. implicitly generated dtor 3148 loc = sc.func.loc; 3149 error("@safe %s '%s' cannot call @system %s '%s'", 3150 sc.func.kind(), sc.func.toPrettyChars(), f.kind(), f.toPrettyChars()); 3151 return true; 3152 } 3153 } 3154 return false; 3155 } 3156 3157 /********************************************* 3158 * Calling function f. 3159 * Check the @nogc-ness, i.e. if we're in a @nogc function 3160 * we can only call other @nogc functions. 3161 * Returns true if error occurs. 3162 */ 3163 final bool checkNogc(Scope* sc, FuncDeclaration f) 3164 { 3165 if (!sc.func) 3166 return false; 3167 if (sc.func == f) 3168 return false; 3169 if (sc.intypeof == 1) 3170 return false; 3171 if (sc.flags & SCOPEctfe) 3172 return false; 3173 3174 if (!f.isNogc()) 3175 { 3176 if (sc.flags & SCOPEcompile ? sc.func.isNogcBypassingInference() : sc.func.setGC()) 3177 { 3178 if (loc.linnum == 0) // e.g. implicitly generated dtor 3179 loc = sc.func.loc; 3180 error("@nogc %s '%s' cannot call non-@nogc %s '%s'", 3181 sc.func.kind(), sc.func.toPrettyChars(), f.kind(), f.toPrettyChars()); 3182 return true; 3183 } 3184 } 3185 return false; 3186 } 3187 3188 /******************************************** 3189 * Check that the postblit is callable if t is an array of structs. 3190 * Returns true if error happens. 3191 */ 3192 final bool checkPostblit(Scope* sc, Type t) 3193 { 3194 t = t.baseElemOf(); 3195 if (t.ty == Tstruct) 3196 { 3197 // Bugzilla 11395: Require TypeInfo generation for array concatenation 3198 semanticTypeInfo(sc, t); 3199 3200 StructDeclaration sd = (cast(TypeStruct)t).sym; 3201 if (sd.postblit) 3202 { 3203 if (sd.postblit.storage_class & STCdisable) 3204 { 3205 sd.error(loc, "is not copyable because it is annotated with @disable"); 3206 return true; 3207 } 3208 //checkDeprecated(sc, sd->postblit); // necessary? 3209 checkPurity(sc, sd.postblit); 3210 checkSafety(sc, sd.postblit); 3211 checkNogc(sc, sd.postblit); 3212 //checkAccess(sd, loc, sc, sd->postblit); // necessary? 3213 return false; 3214 } 3215 } 3216 return false; 3217 } 3218 3219 final bool checkRightThis(Scope* sc) 3220 { 3221 if (op == TOKerror) 3222 return true; 3223 if (op == TOKvar && type.ty != Terror) 3224 { 3225 VarExp ve = cast(VarExp)this; 3226 if (isNeedThisScope(sc, ve.var)) 3227 { 3228 //printf("checkRightThis sc->intypeof = %d, ad = %p, func = %p, fdthis = %p\n", 3229 // sc->intypeof, sc->getStructClassScope(), func, fdthis); 3230 error("need 'this' for '%s' of type '%s'", ve.var.toChars(), ve.var.type.toChars()); 3231 return true; 3232 } 3233 } 3234 return false; 3235 } 3236 3237 /******************************* 3238 * Check whether the expression allows RMW operations, error with rmw operator diagnostic if not. 3239 * ex is the RHS expression, or NULL if ++/-- is used (for diagnostics) 3240 * Returns true if error occurs. 3241 */ 3242 final bool checkReadModifyWrite(TOK rmwOp, Expression ex = null) 3243 { 3244 //printf("Expression::checkReadModifyWrite() %s %s", toChars(), ex ? ex->toChars() : ""); 3245 if (!type || !type.isShared()) 3246 return false; 3247 3248 // atomicOp uses opAssign (+=/-=) rather than opOp (++/--) for the CT string literal. 3249 switch (rmwOp) 3250 { 3251 case TOKplusplus: 3252 case TOKpreplusplus: 3253 rmwOp = TOKaddass; 3254 break; 3255 case TOKminusminus: 3256 case TOKpreminusminus: 3257 rmwOp = TOKminass; 3258 break; 3259 default: 3260 break; 3261 } 3262 3263 deprecation("read-modify-write operations are not allowed for shared variables. Use core.atomic.atomicOp!\"%s\"(%s, %s) instead.", Token.toChars(rmwOp), toChars(), ex ? ex.toChars() : "1"); 3264 return false; 3265 3266 // note: enable when deprecation becomes an error. 3267 // return true; 3268 } 3269 3270 /*************************************** 3271 * Parameters: 3272 * sc: scope 3273 * flag: 1: do not issue error message for invalid modification 3274 * Returns: 3275 * 0: is not modifiable 3276 * 1: is modifiable in default == being related to type->isMutable() 3277 * 2: is modifiable, because this is a part of initializing. 3278 */ 3279 int checkModifiable(Scope* sc, int flag = 0) 3280 { 3281 return type ? 1 : 0; // default modifiable 3282 } 3283 3284 /***************************** 3285 * If expression can be tested for true or false, 3286 * returns the modified expression. 3287 * Otherwise returns ErrorExp. 3288 */ 3289 Expression toBoolean(Scope* sc) 3290 { 3291 // Default is 'yes' - do nothing 3292 debug 3293 { 3294 if (!type) 3295 print(); 3296 assert(type); 3297 } 3298 Expression e = this; 3299 Type t = type; 3300 Type tb = type.toBasetype(); 3301 Type att = null; 3302 Lagain: 3303 // Structs can be converted to bool using opCast(bool)() 3304 if (tb.ty == Tstruct) 3305 { 3306 AggregateDeclaration ad = (cast(TypeStruct)tb).sym; 3307 /* Don't really need to check for opCast first, but by doing so we 3308 * get better error messages if it isn't there. 3309 */ 3310 Dsymbol fd = search_function(ad, Id._cast); 3311 if (fd) 3312 { 3313 e = new CastExp(loc, e, Type.tbool); 3314 e = e.semantic(sc); 3315 return e; 3316 } 3317 3318 // Forward to aliasthis. 3319 if (ad.aliasthis && tb != att) 3320 { 3321 if (!att && tb.checkAliasThisRec()) 3322 att = tb; 3323 e = resolveAliasThis(sc, e); 3324 t = e.type; 3325 tb = e.type.toBasetype(); 3326 goto Lagain; 3327 } 3328 } 3329 3330 if (!t.isBoolean()) 3331 { 3332 if (tb != Type.terror) 3333 error("expression %s of type %s does not have a boolean value", toChars(), t.toChars()); 3334 return new ErrorExp(); 3335 } 3336 return e; 3337 } 3338 3339 /************************************************ 3340 * Destructors are attached to VarDeclarations. 3341 * Hence, if expression returns a temp that needs a destructor, 3342 * make sure and create a VarDeclaration for that temp. 3343 */ 3344 Expression addDtorHook(Scope* sc) 3345 { 3346 return this; 3347 } 3348 3349 /****************************** 3350 * Take address of expression. 3351 */ 3352 final Expression addressOf() 3353 { 3354 //printf("Expression::addressOf()\n"); 3355 debug 3356 { 3357 assert(op == TOKerror || isLvalue()); 3358 } 3359 Expression e = new AddrExp(loc, this); 3360 e.type = type.pointerTo(); 3361 return e; 3362 } 3363 3364 /****************************** 3365 * If this is a reference, dereference it. 3366 */ 3367 final Expression deref() 3368 { 3369 //printf("Expression::deref()\n"); 3370 // type could be null if forward referencing an 'auto' variable 3371 if (type && type.ty == Treference) 3372 { 3373 Expression e = new PtrExp(loc, this); 3374 e.type = (cast(TypeReference)type).next; 3375 return e; 3376 } 3377 return this; 3378 } 3379 3380 final Expression optimize(int result, bool keepLvalue = false) 3381 { 3382 return Expression_optimize(this, result, keepLvalue); 3383 } 3384 3385 // Entry point for CTFE. 3386 // A compile-time result is required. Give an error if not possible 3387 final Expression ctfeInterpret() 3388 { 3389 return .ctfeInterpret(this); 3390 } 3391 3392 final int isConst() 3393 { 3394 return .isConst(this); 3395 } 3396 3397 /******************************** 3398 * Does this expression statically evaluate to a boolean 'result' (true or false)? 3399 */ 3400 bool isBool(bool result) 3401 { 3402 return false; 3403 } 3404 3405 final Expression op_overload(Scope* sc) 3406 { 3407 return .op_overload(this, sc); 3408 } 3409 3410 void accept(Visitor v) 3411 { 3412 v.visit(this); 3413 } 3414 } 3415 3416 /*********************************************************** 3417 */ 3418 extern (C++) final class IntegerExp : Expression 3419 { 3420 dinteger_t value; 3421 3422 extern (D) this(Loc loc, dinteger_t value, Type type) 3423 { 3424 super(loc, TOKint64, __traits(classInstanceSize, IntegerExp)); 3425 //printf("IntegerExp(value = %lld, type = '%s')\n", value, type ? type->toChars() : ""); 3426 assert(type); 3427 if (!type.isscalar()) 3428 { 3429 //printf("%s, loc = %d\n", toChars(), loc.linnum); 3430 if (type.ty != Terror) 3431 error("integral constant must be scalar type, not %s", type.toChars()); 3432 type = Type.terror; 3433 } 3434 this.type = type; 3435 setInteger(value); 3436 } 3437 3438 extern (D) this(dinteger_t value) 3439 { 3440 super(Loc(), TOKint64, __traits(classInstanceSize, IntegerExp)); 3441 this.type = Type.tint32; 3442 this.value = cast(d_int32)value; 3443 } 3444 3445 override bool equals(RootObject o) 3446 { 3447 if (this == o) 3448 return true; 3449 if ((cast(Expression)o).op == TOKint64) 3450 { 3451 IntegerExp ne = cast(IntegerExp)o; 3452 if (type.toHeadMutable().equals(ne.type.toHeadMutable()) && value == ne.value) 3453 { 3454 return true; 3455 } 3456 } 3457 return false; 3458 } 3459 3460 override Expression semantic(Scope* sc) 3461 { 3462 assert(type); 3463 if (type.ty == Terror) 3464 return new ErrorExp(); 3465 assert(type.deco); 3466 normalize(); 3467 return this; 3468 } 3469 3470 override dinteger_t toInteger() 3471 { 3472 normalize(); // necessary until we fix all the paints of 'type' 3473 return value; 3474 } 3475 3476 override real_t toReal() 3477 { 3478 normalize(); // necessary until we fix all the paints of 'type' 3479 Type t = type.toBasetype(); 3480 if (t.ty == Tuns64) 3481 return real_t(cast(d_uns64)value); 3482 else 3483 return real_t(cast(d_int64)value); 3484 } 3485 3486 override real_t toImaginary() 3487 { 3488 return CTFloat.zero; 3489 } 3490 3491 override complex_t toComplex() 3492 { 3493 return complex_t(toReal()); 3494 } 3495 3496 override bool isBool(bool result) 3497 { 3498 bool r = toInteger() != 0; 3499 return result ? r : !r; 3500 } 3501 3502 override Expression toLvalue(Scope* sc, Expression e) 3503 { 3504 if (!e) 3505 e = this; 3506 else if (!loc.filename) 3507 loc = e.loc; 3508 e.error("constant %s is not an lvalue", e.toChars()); 3509 return new ErrorExp(); 3510 } 3511 3512 override void accept(Visitor v) 3513 { 3514 v.visit(this); 3515 } 3516 3517 dinteger_t getInteger() 3518 { 3519 return value; 3520 } 3521 3522 void setInteger(dinteger_t value) 3523 { 3524 this.value = value; 3525 normalize(); 3526 } 3527 3528 private: 3529 void normalize() 3530 { 3531 /* 'Normalize' the value of the integer to be in range of the type 3532 */ 3533 switch (type.toBasetype().ty) 3534 { 3535 case Tbool: 3536 value = (value != 0); 3537 break; 3538 3539 case Tint8: 3540 value = cast(d_int8)value; 3541 break; 3542 3543 case Tchar: 3544 case Tuns8: 3545 value = cast(d_uns8)value; 3546 break; 3547 3548 case Tint16: 3549 value = cast(d_int16)value; 3550 break; 3551 3552 case Twchar: 3553 case Tuns16: 3554 value = cast(d_uns16)value; 3555 break; 3556 3557 case Tint32: 3558 value = cast(d_int32)value; 3559 break; 3560 3561 case Tdchar: 3562 case Tuns32: 3563 value = cast(d_uns32)value; 3564 break; 3565 3566 case Tint64: 3567 value = cast(d_int64)value; 3568 break; 3569 3570 case Tuns64: 3571 value = cast(d_uns64)value; 3572 break; 3573 3574 case Tpointer: 3575 if (Target.ptrsize == 4) 3576 value = cast(d_uns32)value; 3577 else if (Target.ptrsize == 8) 3578 value = cast(d_uns64)value; 3579 else 3580 assert(0); 3581 break; 3582 3583 default: 3584 break; 3585 } 3586 } 3587 } 3588 3589 /*********************************************************** 3590 * Use this expression for error recovery. 3591 * It should behave as a 'sink' to prevent further cascaded error messages. 3592 */ 3593 extern (C++) final class ErrorExp : Expression 3594 { 3595 extern (D) this() 3596 { 3597 super(Loc(), TOKerror, __traits(classInstanceSize, ErrorExp)); 3598 type = Type.terror; 3599 } 3600 3601 override Expression toLvalue(Scope* sc, Expression e) 3602 { 3603 return this; 3604 } 3605 3606 override void accept(Visitor v) 3607 { 3608 v.visit(this); 3609 } 3610 3611 extern (C++) static __gshared ErrorExp errorexp; // handy shared value 3612 } 3613 3614 /*********************************************************** 3615 */ 3616 extern (C++) final class RealExp : Expression 3617 { 3618 real_t value; 3619 3620 extern (D) this(Loc loc, real_t value, Type type) 3621 { 3622 super(loc, TOKfloat64, __traits(classInstanceSize, RealExp)); 3623 //printf("RealExp::RealExp(%Lg)\n", value); 3624 this.value = value; 3625 this.type = type; 3626 } 3627 3628 override bool equals(RootObject o) 3629 { 3630 if (this == o) 3631 return true; 3632 if ((cast(Expression)o).op == TOKfloat64) 3633 { 3634 RealExp ne = cast(RealExp)o; 3635 if (type.toHeadMutable().equals(ne.type.toHeadMutable()) && RealEquals(value, ne.value)) 3636 { 3637 return true; 3638 } 3639 } 3640 return false; 3641 } 3642 3643 override Expression semantic(Scope* sc) 3644 { 3645 if (!type) 3646 type = Type.tfloat64; 3647 else 3648 type = type.semantic(loc, sc); 3649 return this; 3650 } 3651 3652 override dinteger_t toInteger() 3653 { 3654 return cast(sinteger_t)toReal(); 3655 } 3656 3657 override uinteger_t toUInteger() 3658 { 3659 return cast(uinteger_t)toReal(); 3660 } 3661 3662 override real_t toReal() 3663 { 3664 return type.isreal() ? value : CTFloat.zero; 3665 } 3666 3667 override real_t toImaginary() 3668 { 3669 return type.isreal() ? CTFloat.zero : value; 3670 } 3671 3672 override complex_t toComplex() 3673 { 3674 return complex_t(toReal(), toImaginary()); 3675 } 3676 3677 override bool isBool(bool result) 3678 { 3679 return result ? cast(bool)value : !cast(bool)value; 3680 } 3681 3682 override void accept(Visitor v) 3683 { 3684 v.visit(this); 3685 } 3686 } 3687 3688 /*********************************************************** 3689 */ 3690 extern (C++) final class ComplexExp : Expression 3691 { 3692 complex_t value; 3693 3694 extern (D) this(Loc loc, complex_t value, Type type) 3695 { 3696 super(loc, TOKcomplex80, __traits(classInstanceSize, ComplexExp)); 3697 this.value = value; 3698 this.type = type; 3699 //printf("ComplexExp::ComplexExp(%s)\n", toChars()); 3700 } 3701 3702 override bool equals(RootObject o) 3703 { 3704 if (this == o) 3705 return true; 3706 if ((cast(Expression)o).op == TOKcomplex80) 3707 { 3708 ComplexExp ne = cast(ComplexExp)o; 3709 if (type.toHeadMutable().equals(ne.type.toHeadMutable()) && RealEquals(creall(value), creall(ne.value)) && RealEquals(cimagl(value), cimagl(ne.value))) 3710 { 3711 return true; 3712 } 3713 } 3714 return false; 3715 } 3716 3717 override Expression semantic(Scope* sc) 3718 { 3719 if (!type) 3720 type = Type.tcomplex80; 3721 else 3722 type = type.semantic(loc, sc); 3723 return this; 3724 } 3725 3726 override dinteger_t toInteger() 3727 { 3728 return cast(sinteger_t)toReal(); 3729 } 3730 3731 override uinteger_t toUInteger() 3732 { 3733 return cast(uinteger_t)toReal(); 3734 } 3735 3736 override real_t toReal() 3737 { 3738 return creall(value); 3739 } 3740 3741 override real_t toImaginary() 3742 { 3743 return cimagl(value); 3744 } 3745 3746 override complex_t toComplex() 3747 { 3748 return value; 3749 } 3750 3751 override bool isBool(bool result) 3752 { 3753 if (result) 3754 return cast(bool)value; 3755 else 3756 return !value; 3757 } 3758 3759 override void accept(Visitor v) 3760 { 3761 v.visit(this); 3762 } 3763 } 3764 3765 /*********************************************************** 3766 */ 3767 extern (C++) class IdentifierExp : Expression 3768 { 3769 Identifier ident; 3770 3771 final extern (D) this(Loc loc, Identifier ident) 3772 { 3773 super(loc, TOKidentifier, __traits(classInstanceSize, IdentifierExp)); 3774 this.ident = ident; 3775 } 3776 3777 static IdentifierExp create(Loc loc, Identifier ident) 3778 { 3779 return new IdentifierExp(loc, ident); 3780 } 3781 3782 override final Expression semantic(Scope* sc) 3783 { 3784 static if (LOGSEMANTIC) 3785 { 3786 printf("IdentifierExp::semantic('%s')\n", ident.toChars()); 3787 } 3788 if (type) // This is used as the dummy expression 3789 return this; 3790 3791 Dsymbol scopesym; 3792 Dsymbol s = sc.search(loc, ident, &scopesym); 3793 if (s) 3794 { 3795 if (s.errors) 3796 return new ErrorExp(); 3797 3798 Expression e; 3799 3800 /* See if the symbol was a member of an enclosing 'with' 3801 */ 3802 WithScopeSymbol withsym = scopesym.isWithScopeSymbol(); 3803 if (withsym && withsym.withstate.wthis) 3804 { 3805 /* Disallow shadowing 3806 */ 3807 // First find the scope of the with 3808 Scope* scwith = sc; 3809 while (scwith.scopesym != scopesym) 3810 { 3811 scwith = scwith.enclosing; 3812 assert(scwith); 3813 } 3814 // Look at enclosing scopes for symbols with the same name, 3815 // in the same function 3816 for (Scope* scx = scwith; scx && scx.func == scwith.func; scx = scx.enclosing) 3817 { 3818 Dsymbol s2; 3819 if (scx.scopesym && scx.scopesym.symtab && (s2 = scx.scopesym.symtab.lookup(s.ident)) !is null && s != s2) 3820 { 3821 error("with symbol %s is shadowing local symbol %s", s.toPrettyChars(), s2.toPrettyChars()); 3822 return new ErrorExp(); 3823 } 3824 } 3825 s = s.toAlias(); 3826 3827 // Same as wthis.ident 3828 // TODO: DotIdExp.semantic will find 'ident' from 'wthis' again. 3829 // The redudancy should be removed. 3830 e = new VarExp(loc, withsym.withstate.wthis); 3831 e = new DotIdExp(loc, e, ident); 3832 e = e.semantic(sc); 3833 } 3834 else 3835 { 3836 if (withsym) 3837 { 3838 Declaration d = s.isDeclaration(); 3839 if (d) 3840 checkAccess(loc, sc, null, d); 3841 } 3842 3843 /* If f is really a function template, 3844 * then replace f with the function template declaration. 3845 */ 3846 FuncDeclaration f = s.isFuncDeclaration(); 3847 if (f) 3848 { 3849 TemplateDeclaration td = getFuncTemplateDecl(f); 3850 if (td) 3851 { 3852 if (td.overroot) // if not start of overloaded list of TemplateDeclaration's 3853 td = td.overroot; // then get the start 3854 e = new TemplateExp(loc, td, f); 3855 e = e.semantic(sc); 3856 return e; 3857 } 3858 } 3859 // Haven't done overload resolution yet, so pass 1 3860 e = DsymbolExp.resolve(loc, sc, s, true); 3861 } 3862 return e; 3863 } 3864 3865 if (hasThis(sc)) 3866 { 3867 AggregateDeclaration ad = sc.getStructClassScope(); 3868 if (ad && ad.aliasthis) 3869 { 3870 Expression e; 3871 e = new IdentifierExp(loc, Id.This); 3872 e = new DotIdExp(loc, e, ad.aliasthis.ident); 3873 e = new DotIdExp(loc, e, ident); 3874 e = e.trySemantic(sc); 3875 if (e) 3876 return e; 3877 } 3878 } 3879 3880 if (ident == Id.ctfe) 3881 { 3882 if (sc.flags & SCOPEctfe) 3883 { 3884 error("variable __ctfe cannot be read at compile time"); 3885 return new ErrorExp(); 3886 } 3887 3888 // Create the magic __ctfe bool variable 3889 auto vd = new VarDeclaration(loc, Type.tbool, Id.ctfe, null); 3890 vd.storage_class |= STCtemp; 3891 Expression e = new VarExp(loc, vd); 3892 e = e.semantic(sc); 3893 return e; 3894 } 3895 3896 const(char)* n = importHint(ident.toChars()); 3897 if (n) 3898 error("'%s' is not defined, perhaps you need to import %s; ?", ident.toChars(), n); 3899 else 3900 { 3901 s = sc.search_correct(ident); 3902 if (s) 3903 error("undefined identifier '%s', did you mean %s '%s'?", ident.toChars(), s.kind(), s.toChars()); 3904 else 3905 error("undefined identifier '%s'", ident.toChars()); 3906 } 3907 return new ErrorExp(); 3908 } 3909 3910 override final bool isLvalue() 3911 { 3912 return true; 3913 } 3914 3915 override final Expression toLvalue(Scope* sc, Expression e) 3916 { 3917 return this; 3918 } 3919 3920 override void accept(Visitor v) 3921 { 3922 v.visit(this); 3923 } 3924 } 3925 3926 /*********************************************************** 3927 */ 3928 extern (C++) final class DollarExp : IdentifierExp 3929 { 3930 extern (D) this(Loc loc) 3931 { 3932 super(loc, Id.dollar); 3933 } 3934 3935 override void accept(Visitor v) 3936 { 3937 v.visit(this); 3938 } 3939 } 3940 3941 /*********************************************************** 3942 * Won't be generated by parser. 3943 * A placeholder expression to call DsymbolExp.resolve on specific symbol. 3944 */ 3945 extern (C++) final class DsymbolExp : Expression 3946 { 3947 Dsymbol s; 3948 bool hasOverloads; 3949 3950 extern (D) this(Loc loc, Dsymbol s, bool hasOverloads = true) 3951 { 3952 super(loc, TOKdsymbol, __traits(classInstanceSize, DsymbolExp)); 3953 this.s = s; 3954 this.hasOverloads = hasOverloads; 3955 } 3956 3957 override Expression semantic(Scope* sc) 3958 { 3959 return resolve(loc ,sc, s, hasOverloads); 3960 } 3961 3962 /**************************************** 3963 * Resolve a symbol `s` and wraps it in an expression object. 3964 * Params: 3965 * hasOverloads = works if the aliased symbol is a function. 3966 * true: it's overloaded and will be resolved later. 3967 * false: it's exact function symbol. 3968 */ 3969 static Expression resolve(Loc loc, Scope *sc, Dsymbol s, bool hasOverloads) 3970 { 3971 static if (LOGSEMANTIC) 3972 { 3973 printf("DsymbolExp::resolve(%s %s)\n", s.kind(), s.toChars()); 3974 } 3975 3976 Lagain: 3977 Expression e; 3978 3979 //printf("DsymbolExp:: %p '%s' is a symbol\n", this, toChars()); 3980 //printf("s = '%s', s.kind = '%s'\n", s.toChars(), s.kind()); 3981 Dsymbol olds = s; 3982 Declaration d = s.isDeclaration(); 3983 if (d && (d.storage_class & STCtemplateparameter)) 3984 { 3985 s = s.toAlias(); 3986 } 3987 else 3988 { 3989 if (!s.isFuncDeclaration()) // functions are checked after overloading 3990 s.checkDeprecated(loc, sc); 3991 3992 // Bugzilla 12023: if 's' is a tuple variable, the tuple is returned. 3993 s = s.toAlias(); 3994 3995 //printf("s = '%s', s.kind = '%s', s.needThis() = %p\n", s.toChars(), s.kind(), s.needThis()); 3996 if (s != olds && !s.isFuncDeclaration()) 3997 s.checkDeprecated(loc, sc); 3998 } 3999 4000 if (auto em = s.isEnumMember()) 4001 { 4002 return em.getVarExp(loc, sc); 4003 } 4004 if (auto v = s.isVarDeclaration()) 4005 { 4006 //printf("Identifier '%s' is a variable, type '%s'\n", s.toChars(), v.type.toChars()); 4007 if (!v.type || // during variable type inference 4008 !v.type.deco && v.inuse) // during variable type semantic 4009 { 4010 if (v.inuse) // variable type depends on the variable itself 4011 .error(loc, "circular reference to %s '%s'", v.kind(), v.toPrettyChars()); 4012 else // variable type cannot be determined 4013 .error(loc, "forward reference to %s '%s'", v.kind(), v.toPrettyChars()); 4014 return new ErrorExp(); 4015 } 4016 if (v.type.ty == Terror) 4017 return new ErrorExp(); 4018 4019 if ((v.storage_class & STCmanifest) && v._init) 4020 { 4021 if (v.inuse) 4022 { 4023 .error(loc, "circular initialization of %s '%s'", v.kind(), v.toPrettyChars()); 4024 return new ErrorExp(); 4025 } 4026 e = v.expandInitializer(loc); 4027 v.inuse++; 4028 e = e.semantic(sc); 4029 v.inuse--; 4030 return e; 4031 } 4032 4033 // Change the ancestor lambdas to delegate before hasThis(sc) call. 4034 if (v.checkNestedReference(sc, loc)) 4035 return new ErrorExp(); 4036 4037 if (v.needThis() && hasThis(sc)) 4038 e = new DotVarExp(loc, new ThisExp(loc), v); 4039 else 4040 e = new VarExp(loc, v); 4041 e = e.semantic(sc); 4042 return e; 4043 } 4044 if (auto fld = s.isFuncLiteralDeclaration()) 4045 { 4046 //printf("'%s' is a function literal\n", fld.toChars()); 4047 e = new FuncExp(loc, fld); 4048 return e.semantic(sc); 4049 } 4050 if (auto f = s.isFuncDeclaration()) 4051 { 4052 f = f.toAliasFunc(); 4053 if (!f.functionSemantic()) 4054 return new ErrorExp(); 4055 4056 if (!hasOverloads && f.checkForwardRef(loc)) 4057 return new ErrorExp(); 4058 4059 auto fd = s.isFuncDeclaration(); 4060 fd.type = f.type; 4061 return new VarExp(loc, fd, hasOverloads); 4062 } 4063 if (OverDeclaration od = s.isOverDeclaration()) 4064 { 4065 e = new VarExp(loc, od, true); 4066 e.type = Type.tvoid; 4067 return e; 4068 } 4069 if (OverloadSet o = s.isOverloadSet()) 4070 { 4071 //printf("'%s' is an overload set\n", o.toChars()); 4072 return new OverExp(loc, o); 4073 } 4074 4075 if (Import imp = s.isImport()) 4076 { 4077 if (!imp.pkg) 4078 { 4079 .error(loc, "forward reference of import %s", imp.toChars()); 4080 return new ErrorExp(); 4081 } 4082 auto ie = new ScopeExp(loc, imp.pkg); 4083 return ie.semantic(sc); 4084 } 4085 if (Package pkg = s.isPackage()) 4086 { 4087 auto ie = new ScopeExp(loc, pkg); 4088 return ie.semantic(sc); 4089 } 4090 if (Module mod = s.isModule()) 4091 { 4092 auto ie = new ScopeExp(loc, mod); 4093 return ie.semantic(sc); 4094 } 4095 if (Nspace ns = s.isNspace()) 4096 { 4097 auto ie = new ScopeExp(loc, ns); 4098 return ie.semantic(sc); 4099 } 4100 4101 if (Type t = s.getType()) 4102 { 4103 return (new TypeExp(loc, t)).semantic(sc); 4104 } 4105 4106 if (TupleDeclaration tup = s.isTupleDeclaration()) 4107 { 4108 if (tup.needThis() && hasThis(sc)) 4109 e = new DotVarExp(loc, new ThisExp(loc), tup); 4110 else 4111 e = new TupleExp(loc, tup); 4112 e = e.semantic(sc); 4113 return e; 4114 } 4115 4116 if (TemplateInstance ti = s.isTemplateInstance()) 4117 { 4118 ti.semantic(sc); 4119 if (!ti.inst || ti.errors) 4120 return new ErrorExp(); 4121 s = ti.toAlias(); 4122 if (!s.isTemplateInstance()) 4123 goto Lagain; 4124 e = new ScopeExp(loc, ti); 4125 e = e.semantic(sc); 4126 return e; 4127 } 4128 if (TemplateDeclaration td = s.isTemplateDeclaration()) 4129 { 4130 Dsymbol p = td.toParent2(); 4131 FuncDeclaration fdthis = hasThis(sc); 4132 AggregateDeclaration ad = p ? p.isAggregateDeclaration() : null; 4133 if (fdthis && ad && isAggregate(fdthis.vthis.type) == ad && (td._scope.stc & STCstatic) == 0) 4134 { 4135 e = new DotTemplateExp(loc, new ThisExp(loc), td); 4136 } 4137 else 4138 e = new TemplateExp(loc, td); 4139 e = e.semantic(sc); 4140 return e; 4141 } 4142 4143 .error(loc, "%s '%s' is not a variable", s.kind(), s.toChars()); 4144 return new ErrorExp(); 4145 } 4146 4147 override bool isLvalue() 4148 { 4149 return true; 4150 } 4151 4152 override Expression toLvalue(Scope* sc, Expression e) 4153 { 4154 return this; 4155 } 4156 4157 override void accept(Visitor v) 4158 { 4159 v.visit(this); 4160 } 4161 } 4162 4163 /*********************************************************** 4164 */ 4165 extern (C++) class ThisExp : Expression 4166 { 4167 VarDeclaration var; 4168 4169 final extern (D) this(Loc loc) 4170 { 4171 super(loc, TOKthis, __traits(classInstanceSize, ThisExp)); 4172 //printf("ThisExp::ThisExp() loc = %d\n", loc.linnum); 4173 } 4174 4175 override Expression semantic(Scope* sc) 4176 { 4177 static if (LOGSEMANTIC) 4178 { 4179 printf("ThisExp::semantic()\n"); 4180 } 4181 if (type) 4182 return this; 4183 4184 FuncDeclaration fd = hasThis(sc); // fd is the uplevel function with the 'this' variable 4185 4186 /* Special case for typeof(this) and typeof(super) since both 4187 * should work even if they are not inside a non-static member function 4188 */ 4189 if (!fd && sc.intypeof == 1) 4190 { 4191 // Find enclosing struct or class 4192 for (Dsymbol s = sc.getStructClassScope(); 1; s = s.parent) 4193 { 4194 if (!s) 4195 { 4196 error("%s is not in a class or struct scope", toChars()); 4197 goto Lerr; 4198 } 4199 ClassDeclaration cd = s.isClassDeclaration(); 4200 if (cd) 4201 { 4202 type = cd.type; 4203 return this; 4204 } 4205 StructDeclaration sd = s.isStructDeclaration(); 4206 if (sd) 4207 { 4208 type = sd.type; 4209 return this; 4210 } 4211 } 4212 } 4213 if (!fd) 4214 goto Lerr; 4215 4216 assert(fd.vthis); 4217 var = fd.vthis; 4218 assert(var.parent); 4219 type = var.type; 4220 if (var.checkNestedReference(sc, loc)) 4221 return new ErrorExp(); 4222 if (!sc.intypeof) 4223 sc.callSuper |= CSXthis; 4224 return this; 4225 4226 Lerr: 4227 error("'this' is only defined in non-static member functions, not %s", sc.parent.toChars()); 4228 return new ErrorExp(); 4229 } 4230 4231 override final bool isBool(bool result) 4232 { 4233 return result ? true : false; 4234 } 4235 4236 override final bool isLvalue() 4237 { 4238 // Class `this` should be an rvalue; struct `this` should be an lvalue. 4239 return type.toBasetype().ty != Tclass; 4240 } 4241 4242 override final Expression toLvalue(Scope* sc, Expression e) 4243 { 4244 if (type.toBasetype().ty == Tclass) 4245 { 4246 // Class `this` is an rvalue; struct `this` is an lvalue. 4247 return Expression.toLvalue(sc, e); 4248 } 4249 return this; 4250 } 4251 4252 override void accept(Visitor v) 4253 { 4254 v.visit(this); 4255 } 4256 } 4257 4258 /*********************************************************** 4259 */ 4260 extern (C++) final class SuperExp : ThisExp 4261 { 4262 extern (D) this(Loc loc) 4263 { 4264 super(loc); 4265 op = TOKsuper; 4266 } 4267 4268 override Expression semantic(Scope* sc) 4269 { 4270 static if (LOGSEMANTIC) 4271 { 4272 printf("SuperExp::semantic('%s')\n", toChars()); 4273 } 4274 if (type) 4275 return this; 4276 4277 FuncDeclaration fd = hasThis(sc); 4278 ClassDeclaration cd; 4279 Dsymbol s; 4280 4281 /* Special case for typeof(this) and typeof(super) since both 4282 * should work even if they are not inside a non-static member function 4283 */ 4284 if (!fd && sc.intypeof == 1) 4285 { 4286 // Find enclosing class 4287 for (s = sc.getStructClassScope(); 1; s = s.parent) 4288 { 4289 if (!s) 4290 { 4291 error("%s is not in a class scope", toChars()); 4292 goto Lerr; 4293 } 4294 cd = s.isClassDeclaration(); 4295 if (cd) 4296 { 4297 cd = cd.baseClass; 4298 if (!cd) 4299 { 4300 error("class %s has no 'super'", s.toChars()); 4301 goto Lerr; 4302 } 4303 type = cd.type; 4304 return this; 4305 } 4306 } 4307 } 4308 if (!fd) 4309 goto Lerr; 4310 4311 var = fd.vthis; 4312 assert(var && var.parent); 4313 4314 s = fd.toParent(); 4315 while (s && s.isTemplateInstance()) 4316 s = s.toParent(); 4317 if (s.isTemplateDeclaration()) // allow inside template constraint 4318 s = s.toParent(); 4319 assert(s); 4320 cd = s.isClassDeclaration(); 4321 //printf("parent is %s %s\n", fd->toParent()->kind(), fd->toParent()->toChars()); 4322 if (!cd) 4323 goto Lerr; 4324 if (!cd.baseClass) 4325 { 4326 error("no base class for %s", cd.toChars()); 4327 type = var.type; 4328 } 4329 else 4330 { 4331 type = cd.baseClass.type; 4332 type = type.castMod(var.type.mod); 4333 } 4334 4335 if (var.checkNestedReference(sc, loc)) 4336 return new ErrorExp(); 4337 4338 if (!sc.intypeof) 4339 sc.callSuper |= CSXsuper; 4340 return this; 4341 4342 Lerr: 4343 error("'super' is only allowed in non-static class member functions"); 4344 return new ErrorExp(); 4345 } 4346 4347 override void accept(Visitor v) 4348 { 4349 v.visit(this); 4350 } 4351 } 4352 4353 /*********************************************************** 4354 */ 4355 extern (C++) final class NullExp : Expression 4356 { 4357 ubyte committed; // !=0 if type is committed 4358 4359 extern (D) this(Loc loc, Type type = null) 4360 { 4361 super(loc, TOKnull, __traits(classInstanceSize, NullExp)); 4362 this.type = type; 4363 } 4364 4365 override bool equals(RootObject o) 4366 { 4367 if (o && o.dyncast() == DYNCAST_EXPRESSION) 4368 { 4369 Expression e = cast(Expression)o; 4370 if (e.op == TOKnull && type.equals(e.type)) 4371 { 4372 return true; 4373 } 4374 } 4375 return false; 4376 } 4377 4378 override Expression semantic(Scope* sc) 4379 { 4380 static if (LOGSEMANTIC) 4381 { 4382 printf("NullExp::semantic('%s')\n", toChars()); 4383 } 4384 // NULL is the same as (void *)0 4385 if (type) 4386 return this; 4387 type = Type.tnull; 4388 return this; 4389 } 4390 4391 override bool isBool(bool result) 4392 { 4393 return result ? false : true; 4394 } 4395 4396 override StringExp toStringExp() 4397 { 4398 if (implicitConvTo(Type.tstring)) 4399 { 4400 auto se = new StringExp(loc, cast(char*)mem.xcalloc(1, 1), 0); 4401 se.type = Type.tstring; 4402 return se; 4403 } 4404 return null; 4405 } 4406 4407 override void accept(Visitor v) 4408 { 4409 v.visit(this); 4410 } 4411 } 4412 4413 /*********************************************************** 4414 */ 4415 extern (C++) final class StringExp : Expression 4416 { 4417 union 4418 { 4419 char* string; // if sz == 1 4420 wchar* wstring; // if sz == 2 4421 dchar* dstring; // if sz == 4 4422 } // (const if ownedByCtfe == OWNEDcode) 4423 size_t len; // number of code units 4424 ubyte sz = 1; // 1: char, 2: wchar, 4: dchar 4425 ubyte committed; // !=0 if type is committed 4426 char postfix = 0; // 'c', 'w', 'd' 4427 OwnedBy ownedByCtfe = OWNEDcode; 4428 4429 extern (D) this(Loc loc, char* string) 4430 { 4431 super(loc, TOKstring, __traits(classInstanceSize, StringExp)); 4432 this.string = string; 4433 this.len = strlen(string); 4434 this.sz = 1; // work around LDC bug #1286 4435 } 4436 4437 extern (D) this(Loc loc, void* string, size_t len) 4438 { 4439 super(loc, TOKstring, __traits(classInstanceSize, StringExp)); 4440 this.string = cast(char*)string; 4441 this.len = len; 4442 this.sz = 1; // work around LDC bug #1286 4443 } 4444 4445 extern (D) this(Loc loc, void* string, size_t len, char postfix) 4446 { 4447 super(loc, TOKstring, __traits(classInstanceSize, StringExp)); 4448 this.string = cast(char*)string; 4449 this.len = len; 4450 this.postfix = postfix; 4451 this.sz = 1; // work around LDC bug #1286 4452 } 4453 4454 static StringExp create(Loc loc, char* s) 4455 { 4456 return new StringExp(loc, s); 4457 } 4458 4459 override bool equals(RootObject o) 4460 { 4461 //printf("StringExp::equals('%s') %s\n", o->toChars(), toChars()); 4462 if (o && o.dyncast() == DYNCAST_EXPRESSION) 4463 { 4464 Expression e = cast(Expression)o; 4465 if (e.op == TOKstring) 4466 { 4467 return compare(o) == 0; 4468 } 4469 } 4470 return false; 4471 } 4472 4473 override Expression semantic(Scope* sc) 4474 { 4475 static if (LOGSEMANTIC) 4476 { 4477 printf("StringExp::semantic() %s\n", toChars()); 4478 } 4479 if (type) 4480 return this; 4481 4482 OutBuffer buffer; 4483 size_t newlen = 0; 4484 const(char)* p; 4485 size_t u; 4486 dchar c; 4487 4488 switch (postfix) 4489 { 4490 case 'd': 4491 for (u = 0; u < len;) 4492 { 4493 p = utf_decodeChar(string, len, u, c); 4494 if (p) 4495 { 4496 error("%s", p); 4497 return new ErrorExp(); 4498 } 4499 else 4500 { 4501 buffer.write4(c); 4502 newlen++; 4503 } 4504 } 4505 buffer.write4(0); 4506 dstring = cast(dchar*)buffer.extractData(); 4507 len = newlen; 4508 sz = 4; 4509 type = new TypeDArray(Type.tdchar.immutableOf()); 4510 committed = 1; 4511 break; 4512 4513 case 'w': 4514 for (u = 0; u < len;) 4515 { 4516 p = utf_decodeChar(string, len, u, c); 4517 if (p) 4518 { 4519 error("%s", p); 4520 return new ErrorExp(); 4521 } 4522 else 4523 { 4524 buffer.writeUTF16(c); 4525 newlen++; 4526 if (c >= 0x10000) 4527 newlen++; 4528 } 4529 } 4530 buffer.writeUTF16(0); 4531 wstring = cast(wchar*)buffer.extractData(); 4532 len = newlen; 4533 sz = 2; 4534 type = new TypeDArray(Type.twchar.immutableOf()); 4535 committed = 1; 4536 break; 4537 4538 case 'c': 4539 committed = 1; 4540 goto default; 4541 4542 default: 4543 type = new TypeDArray(Type.tchar.immutableOf()); 4544 break; 4545 } 4546 type = type.semantic(loc, sc); 4547 //type = type->immutableOf(); 4548 //printf("type = %s\n", type->toChars()); 4549 4550 return this; 4551 } 4552 4553 /********************************** 4554 * Return the number of code units the string would be if it were re-encoded 4555 * as tynto. 4556 * Params: 4557 * tynto = code unit type of the target encoding 4558 * Returns: 4559 * number of code units 4560 */ 4561 final size_t numberOfCodeUnits(int tynto = 0) const 4562 { 4563 int encSize; 4564 switch (tynto) 4565 { 4566 case 0: return len; 4567 case Tchar: encSize = 1; break; 4568 case Twchar: encSize = 2; break; 4569 case Tdchar: encSize = 4; break; 4570 default: 4571 assert(0); 4572 } 4573 if (sz == encSize) 4574 return len; 4575 4576 size_t result = 0; 4577 dchar c; 4578 4579 switch (sz) 4580 { 4581 case 1: 4582 for (size_t u = 0; u < len;) 4583 { 4584 if (const p = utf_decodeChar(string, len, u, c)) 4585 { 4586 error("%s", p); 4587 return 0; 4588 } 4589 result += utf_codeLength(encSize, c); 4590 } 4591 break; 4592 4593 case 2: 4594 for (size_t u = 0; u < len;) 4595 { 4596 if (const p = utf_decodeWchar(wstring, len, u, c)) 4597 { 4598 error("%s", p); 4599 return 0; 4600 } 4601 result += utf_codeLength(encSize, c); 4602 } 4603 break; 4604 4605 case 4: 4606 foreach (u; 0 .. len) 4607 { 4608 result += utf_codeLength(encSize, dstring[u]); 4609 } 4610 break; 4611 4612 default: 4613 assert(0); 4614 } 4615 return result; 4616 } 4617 4618 /********************************************** 4619 * Write the contents of the string to dest. 4620 * Use numberOfCodeUnits() to determine size of result. 4621 * Params: 4622 * dest = destination 4623 * tyto = encoding type of the result 4624 * zero = add terminating 0 4625 */ 4626 void writeTo(void* dest, bool zero, int tyto = 0) const 4627 { 4628 int encSize; 4629 switch (tyto) 4630 { 4631 case 0: encSize = sz; break; 4632 case Tchar: encSize = 1; break; 4633 case Twchar: encSize = 2; break; 4634 case Tdchar: encSize = 4; break; 4635 default: 4636 assert(0); 4637 } 4638 if (sz == encSize) 4639 { 4640 memcpy(dest, string, len * sz); 4641 if (zero) 4642 memset(dest + len * sz, 0, sz); 4643 } 4644 else 4645 assert(0); 4646 } 4647 4648 /********************************************* 4649 * Get the code unit at index i 4650 * Params: 4651 * i = index 4652 * Returns: 4653 * code unit at index i 4654 */ 4655 final dchar getCodeUnit(size_t i) const pure 4656 { 4657 assert(i < len); 4658 final switch (sz) 4659 { 4660 case 1: 4661 return string[i]; 4662 case 2: 4663 return wstring[i]; 4664 case 4: 4665 return dstring[i]; 4666 } 4667 } 4668 4669 /********************************************* 4670 * Set the code unit at index i to c 4671 * Params: 4672 * i = index 4673 * c = code unit to set it to 4674 */ 4675 final void setCodeUnit(size_t i, dchar c) 4676 { 4677 assert(i < len); 4678 final switch (sz) 4679 { 4680 case 1: 4681 string[i] = cast(char)c; 4682 break; 4683 case 2: 4684 wstring[i] = cast(wchar)c; 4685 break; 4686 case 4: 4687 dstring[i] = c; 4688 break; 4689 } 4690 } 4691 4692 /************************************************** 4693 * If the string data is UTF-8 and can be accessed directly, 4694 * return a pointer to it. 4695 * Do not assume a terminating 0. 4696 * Returns: 4697 * pointer to string data if possible, null if not 4698 */ 4699 char* toPtr() 4700 { 4701 return (sz == 1) ? string : null; 4702 } 4703 4704 override StringExp toStringExp() 4705 { 4706 return this; 4707 } 4708 4709 /**************************************** 4710 * Convert string to char[]. 4711 */ 4712 StringExp toUTF8(Scope* sc) 4713 { 4714 if (sz != 1) 4715 { 4716 // Convert to UTF-8 string 4717 committed = 0; 4718 Expression e = castTo(sc, Type.tchar.arrayOf()); 4719 e = e.optimize(WANTvalue); 4720 assert(e.op == TOKstring); 4721 StringExp se = cast(StringExp)e; 4722 assert(se.sz == 1); 4723 return se; 4724 } 4725 return this; 4726 } 4727 4728 override int compare(RootObject obj) 4729 { 4730 //printf("StringExp::compare()\n"); 4731 // Used to sort case statement expressions so we can do an efficient lookup 4732 StringExp se2 = cast(StringExp)obj; 4733 4734 // This is a kludge so isExpression() in template.c will return 5 4735 // for StringExp's. 4736 if (!se2) 4737 return 5; 4738 4739 assert(se2.op == TOKstring); 4740 4741 size_t len1 = len; 4742 size_t len2 = se2.len; 4743 4744 //printf("sz = %d, len1 = %d, len2 = %d\n", sz, (int)len1, (int)len2); 4745 if (len1 == len2) 4746 { 4747 switch (sz) 4748 { 4749 case 1: 4750 return memcmp(string, se2..string, len1); 4751 4752 case 2: 4753 { 4754 wchar* s1 = cast(wchar*)string; 4755 wchar* s2 = cast(wchar*)se2..string; 4756 for (size_t u = 0; u < len; u++) 4757 { 4758 if (s1[u] != s2[u]) 4759 return s1[u] - s2[u]; 4760 } 4761 } 4762 break; 4763 case 4: 4764 { 4765 dchar* s1 = cast(dchar*)string; 4766 dchar* s2 = cast(dchar*)se2..string; 4767 for (size_t u = 0; u < len; u++) 4768 { 4769 if (s1[u] != s2[u]) 4770 return s1[u] - s2[u]; 4771 } 4772 } 4773 break; 4774 default: 4775 assert(0); 4776 } 4777 } 4778 return cast(int)(len1 - len2); 4779 } 4780 4781 override bool isBool(bool result) 4782 { 4783 return result ? true : false; 4784 } 4785 4786 override bool isLvalue() 4787 { 4788 /* string literal is rvalue in default, but 4789 * conversion to reference of static array is only allowed. 4790 */ 4791 return (type && type.toBasetype().ty == Tsarray); 4792 } 4793 4794 override Expression toLvalue(Scope* sc, Expression e) 4795 { 4796 //printf("StringExp::toLvalue(%s) type = %s\n", toChars(), type ? type->toChars() : NULL); 4797 return (type && type.toBasetype().ty == Tsarray) ? this : Expression.toLvalue(sc, e); 4798 } 4799 4800 override Expression modifiableLvalue(Scope* sc, Expression e) 4801 { 4802 error("cannot modify string literal %s", toChars()); 4803 return new ErrorExp(); 4804 } 4805 4806 uint charAt(uinteger_t i) const 4807 { 4808 uint value; 4809 switch (sz) 4810 { 4811 case 1: 4812 value = (cast(char*)string)[cast(size_t)i]; 4813 break; 4814 4815 case 2: 4816 value = (cast(ushort*)string)[cast(size_t)i]; 4817 break; 4818 4819 case 4: 4820 value = (cast(uint*)string)[cast(size_t)i]; 4821 break; 4822 4823 default: 4824 assert(0); 4825 } 4826 return value; 4827 } 4828 4829 /******************************** 4830 * Convert string contents to a 0 terminated string, 4831 * allocated by mem.xmalloc(). 4832 */ 4833 extern (D) final const(char)[] toStringz() const 4834 { 4835 auto nbytes = len * sz; 4836 char* s = cast(char*)mem.xmalloc(nbytes + sz); 4837 writeTo(s, true); 4838 return s[0 .. nbytes]; 4839 } 4840 4841 extern (D) const(char)[] peekSlice() const 4842 { 4843 assert(sz == 1); 4844 return this.string[0 .. len]; 4845 } 4846 4847 override void accept(Visitor v) 4848 { 4849 v.visit(this); 4850 } 4851 } 4852 4853 /*********************************************************** 4854 */ 4855 extern (C++) final class TupleExp : Expression 4856 { 4857 /* Tuple-field access may need to take out its side effect part. 4858 * For example: 4859 * foo().tupleof 4860 * is rewritten as: 4861 * (ref __tup = foo(); tuple(__tup.field0, __tup.field1, ...)) 4862 * The declaration of temporary variable __tup will be stored in TupleExp.e0. 4863 */ 4864 Expression e0; 4865 4866 Expressions* exps; 4867 4868 extern (D) this(Loc loc, Expression e0, Expressions* exps) 4869 { 4870 super(loc, TOKtuple, __traits(classInstanceSize, TupleExp)); 4871 //printf("TupleExp(this = %p)\n", this); 4872 this.e0 = e0; 4873 this.exps = exps; 4874 } 4875 4876 extern (D) this(Loc loc, Expressions* exps) 4877 { 4878 super(loc, TOKtuple, __traits(classInstanceSize, TupleExp)); 4879 //printf("TupleExp(this = %p)\n", this); 4880 this.exps = exps; 4881 } 4882 4883 extern (D) this(Loc loc, TupleDeclaration tup) 4884 { 4885 super(loc, TOKtuple, __traits(classInstanceSize, TupleExp)); 4886 this.exps = new Expressions(); 4887 4888 this.exps.reserve(tup.objects.dim); 4889 for (size_t i = 0; i < tup.objects.dim; i++) 4890 { 4891 RootObject o = (*tup.objects)[i]; 4892 if (Dsymbol s = getDsymbol(o)) 4893 { 4894 /* If tuple element represents a symbol, translate to DsymbolExp 4895 * to supply implicit 'this' if needed later. 4896 */ 4897 Expression e = new DsymbolExp(loc, s); 4898 this.exps.push(e); 4899 } 4900 else if (o.dyncast() == DYNCAST_EXPRESSION) 4901 { 4902 auto e = (cast(Expression)o).copy(); 4903 e.loc = loc; // Bugzilla 15669 4904 this.exps.push(e); 4905 } 4906 else if (o.dyncast() == DYNCAST_TYPE) 4907 { 4908 Type t = cast(Type)o; 4909 Expression e = new TypeExp(loc, t); 4910 this.exps.push(e); 4911 } 4912 else 4913 { 4914 error("%s is not an expression", o.toChars()); 4915 } 4916 } 4917 } 4918 4919 override Expression syntaxCopy() 4920 { 4921 return new TupleExp(loc, e0 ? e0.syntaxCopy() : null, arraySyntaxCopy(exps)); 4922 } 4923 4924 override bool equals(RootObject o) 4925 { 4926 if (this == o) 4927 return true; 4928 if ((cast(Expression)o).op == TOKtuple) 4929 { 4930 TupleExp te = cast(TupleExp)o; 4931 if (exps.dim != te.exps.dim) 4932 return false; 4933 if (e0 && !e0.equals(te.e0) || !e0 && te.e0) 4934 return false; 4935 for (size_t i = 0; i < exps.dim; i++) 4936 { 4937 Expression e1 = (*exps)[i]; 4938 Expression e2 = (*te.exps)[i]; 4939 if (!e1.equals(e2)) 4940 return false; 4941 } 4942 return true; 4943 } 4944 return false; 4945 } 4946 4947 override Expression semantic(Scope* sc) 4948 { 4949 static if (LOGSEMANTIC) 4950 { 4951 printf("+TupleExp::semantic(%s)\n", toChars()); 4952 } 4953 if (type) 4954 return this; 4955 4956 if (e0) 4957 e0 = e0.semantic(sc); 4958 4959 // Run semantic() on each argument 4960 bool err = false; 4961 for (size_t i = 0; i < exps.dim; i++) 4962 { 4963 Expression e = (*exps)[i]; 4964 e = e.semantic(sc); 4965 if (!e.type) 4966 { 4967 error("%s has no value", e.toChars()); 4968 err = true; 4969 } 4970 else if (e.op == TOKerror) 4971 err = true; 4972 else 4973 (*exps)[i] = e; 4974 } 4975 if (err) 4976 return new ErrorExp(); 4977 4978 expandTuples(exps); 4979 4980 type = new TypeTuple(exps); 4981 type = type.semantic(loc, sc); 4982 //printf("-TupleExp::semantic(%s)\n", toChars()); 4983 return this; 4984 } 4985 4986 override void accept(Visitor v) 4987 { 4988 v.visit(this); 4989 } 4990 } 4991 4992 /*********************************************************** 4993 * [ e1, e2, e3, ... ] 4994 */ 4995 extern (C++) final class ArrayLiteralExp : Expression 4996 { 4997 /** If !is null, elements[] can be sparse and basis is used for the 4998 * "default" element value. In other words, non-null elements[i] overrides 4999 * this 'basis' value. 5000 */ 5001 Expression basis; 5002 5003 Expressions* elements; 5004 OwnedBy ownedByCtfe = OWNEDcode; 5005 5006 extern (D) this(Loc loc, Expressions* elements) 5007 { 5008 super(loc, TOKarrayliteral, __traits(classInstanceSize, ArrayLiteralExp)); 5009 this.elements = elements; 5010 } 5011 5012 extern (D) this(Loc loc, Expression e) 5013 { 5014 super(loc, TOKarrayliteral, __traits(classInstanceSize, ArrayLiteralExp)); 5015 elements = new Expressions(); 5016 elements.push(e); 5017 } 5018 5019 extern (D) this(Loc loc, Expression basis, Expressions* elements) 5020 { 5021 super(loc, TOKarrayliteral, __traits(classInstanceSize, ArrayLiteralExp)); 5022 this.basis = basis; 5023 this.elements = elements; 5024 } 5025 5026 override Expression syntaxCopy() 5027 { 5028 return new ArrayLiteralExp(loc, 5029 basis ? basis.syntaxCopy() : null, 5030 arraySyntaxCopy(elements)); 5031 } 5032 5033 override bool equals(RootObject o) 5034 { 5035 if (this == o) 5036 return true; 5037 if (o && o.dyncast() == DYNCAST_EXPRESSION && (cast(Expression)o).op == TOKarrayliteral) 5038 { 5039 ArrayLiteralExp ae = cast(ArrayLiteralExp)o; 5040 if (elements.dim != ae.elements.dim) 5041 return false; 5042 if (elements.dim == 0 && !type.equals(ae.type)) 5043 { 5044 return false; 5045 } 5046 for (size_t i = 0; i < elements.dim; i++) 5047 { 5048 Expression e1 = (*elements)[i]; 5049 Expression e2 = (*ae.elements)[i]; 5050 if (!e1) 5051 e1 = basis; 5052 if (!e2) 5053 e2 = ae.basis; 5054 if (e1 != e2 && (!e1 || !e2 || !e1.equals(e2))) 5055 return false; 5056 } 5057 return true; 5058 } 5059 return false; 5060 } 5061 5062 final Expression getElement(size_t i) 5063 { 5064 auto el = (*elements)[i]; 5065 if (!el) 5066 el = basis; 5067 return el; 5068 } 5069 5070 /** Copy element `Expressions` in the parameters when they're `ArrayLiteralExp`s. 5071 * Params: 5072 * e1 = If it's ArrayLiteralExp, its `elements` will be copied. 5073 * Otherwise, `e1` itself will be pushed into the new `Expressions`. 5074 * e2 = If it's not `null`, it will be pushed/appended to the new 5075 * `Expressions` by the same way with `e1`. 5076 * Returns: 5077 * Newly allocated `Expresions. Note that it points the original 5078 * `Expression` values in e1 and e2. 5079 */ 5080 static Expressions* copyElements(Expression e1, Expression e2 = null) 5081 { 5082 auto elems = new Expressions(); 5083 5084 void append(ArrayLiteralExp ale) 5085 { 5086 if (!ale.elements) 5087 return; 5088 auto d = elems.dim; 5089 elems.append(ale.elements); 5090 foreach (ref el; (*elems)[][d .. elems.dim]) 5091 { 5092 if (!el) 5093 el = ale.basis; 5094 } 5095 } 5096 5097 if (e1.op == TOKarrayliteral) 5098 append(cast(ArrayLiteralExp)e1); 5099 else 5100 elems.push(e1); 5101 5102 if (e2) 5103 { 5104 if (e2.op == TOKarrayliteral) 5105 append(cast(ArrayLiteralExp)e2); 5106 else 5107 elems.push(e2); 5108 } 5109 5110 return elems; 5111 } 5112 5113 override Expression semantic(Scope* sc) 5114 { 5115 static if (LOGSEMANTIC) 5116 { 5117 printf("ArrayLiteralExp::semantic('%s')\n", toChars()); 5118 } 5119 if (type) 5120 return this; 5121 5122 /* Perhaps an empty array literal [ ] should be rewritten as null? 5123 */ 5124 5125 if (basis) 5126 basis = basis.semantic(sc); 5127 if (arrayExpressionSemantic(elements, sc) || (basis && basis.op == TOKerror)) 5128 return new ErrorExp(); 5129 5130 expandTuples(elements); 5131 5132 Type t0; 5133 if (basis) 5134 elements.push(basis); 5135 bool err = arrayExpressionToCommonType(sc, elements, &t0); 5136 if (basis) 5137 basis = elements.pop(); 5138 if (err) 5139 return new ErrorExp(); 5140 5141 type = t0.arrayOf(); 5142 type = type.semantic(loc, sc); 5143 5144 /* Disallow array literals of type void being used. 5145 */ 5146 if (elements.dim > 0 && t0.ty == Tvoid) 5147 { 5148 error("%s of type %s has no value", toChars(), type.toChars()); 5149 return new ErrorExp(); 5150 } 5151 5152 semanticTypeInfo(sc, type); 5153 5154 return this; 5155 } 5156 5157 override bool isBool(bool result) 5158 { 5159 size_t dim = elements ? elements.dim : 0; 5160 return result ? (dim != 0) : (dim == 0); 5161 } 5162 5163 override StringExp toStringExp() 5164 { 5165 TY telem = type.nextOf().toBasetype().ty; 5166 if (telem == Tchar || telem == Twchar || telem == Tdchar || (telem == Tvoid && (!elements || elements.dim == 0))) 5167 { 5168 ubyte sz = 1; 5169 if (telem == Twchar) 5170 sz = 2; 5171 else if (telem == Tdchar) 5172 sz = 4; 5173 5174 OutBuffer buf; 5175 if (elements) 5176 { 5177 for (size_t i = 0; i < elements.dim; ++i) 5178 { 5179 auto ch = getElement(i); 5180 if (ch.op != TOKint64) 5181 return null; 5182 if (sz == 1) 5183 buf.writeByte(cast(uint)ch.toInteger()); 5184 else if (sz == 2) 5185 buf.writeword(cast(uint)ch.toInteger()); 5186 else 5187 buf.write4(cast(uint)ch.toInteger()); 5188 } 5189 } 5190 char prefix; 5191 if (sz == 1) 5192 { 5193 prefix = 'c'; 5194 buf.writeByte(0); 5195 } 5196 else if (sz == 2) 5197 { 5198 prefix = 'w'; 5199 buf.writeword(0); 5200 } 5201 else 5202 { 5203 prefix = 'd'; 5204 buf.write4(0); 5205 } 5206 5207 const(size_t) len = buf.offset / sz - 1; 5208 auto se = new StringExp(loc, buf.extractData(), len, prefix); 5209 se.sz = sz; 5210 se.type = type; 5211 return se; 5212 } 5213 return null; 5214 } 5215 5216 override void accept(Visitor v) 5217 { 5218 v.visit(this); 5219 } 5220 } 5221 5222 /*********************************************************** 5223 * [ key0 : value0, key1 : value1, ... ] 5224 */ 5225 extern (C++) final class AssocArrayLiteralExp : Expression 5226 { 5227 Expressions* keys; 5228 Expressions* values; 5229 OwnedBy ownedByCtfe = OWNEDcode; 5230 5231 extern (D) this(Loc loc, Expressions* keys, Expressions* values) 5232 { 5233 super(loc, TOKassocarrayliteral, __traits(classInstanceSize, AssocArrayLiteralExp)); 5234 assert(keys.dim == values.dim); 5235 this.keys = keys; 5236 this.values = values; 5237 } 5238 5239 override bool equals(RootObject o) 5240 { 5241 if (this == o) 5242 return true; 5243 if (o && o.dyncast() == DYNCAST_EXPRESSION && (cast(Expression)o).op == TOKassocarrayliteral) 5244 { 5245 AssocArrayLiteralExp ae = cast(AssocArrayLiteralExp)o; 5246 if (keys.dim != ae.keys.dim) 5247 return false; 5248 size_t count = 0; 5249 for (size_t i = 0; i < keys.dim; i++) 5250 { 5251 for (size_t j = 0; j < ae.keys.dim; j++) 5252 { 5253 if ((*keys)[i].equals((*ae.keys)[j])) 5254 { 5255 if (!(*values)[i].equals((*ae.values)[j])) 5256 return false; 5257 ++count; 5258 } 5259 } 5260 } 5261 return count == keys.dim; 5262 } 5263 return false; 5264 } 5265 5266 override Expression syntaxCopy() 5267 { 5268 return new AssocArrayLiteralExp(loc, arraySyntaxCopy(keys), arraySyntaxCopy(values)); 5269 } 5270 5271 override Expression semantic(Scope* sc) 5272 { 5273 static if (LOGSEMANTIC) 5274 { 5275 printf("AssocArrayLiteralExp::semantic('%s')\n", toChars()); 5276 } 5277 if (type) 5278 return this; 5279 5280 // Run semantic() on each element 5281 bool err_keys = arrayExpressionSemantic(keys, sc); 5282 bool err_vals = arrayExpressionSemantic(values, sc); 5283 if (err_keys || err_vals) 5284 return new ErrorExp(); 5285 5286 expandTuples(keys); 5287 expandTuples(values); 5288 if (keys.dim != values.dim) 5289 { 5290 error("number of keys is %u, must match number of values %u", keys.dim, values.dim); 5291 return new ErrorExp(); 5292 } 5293 5294 Type tkey = null; 5295 Type tvalue = null; 5296 err_keys = arrayExpressionToCommonType(sc, keys, &tkey); 5297 err_vals = arrayExpressionToCommonType(sc, values, &tvalue); 5298 if (err_keys || err_vals) 5299 return new ErrorExp(); 5300 5301 if (tkey == Type.terror || tvalue == Type.terror) 5302 return new ErrorExp(); 5303 5304 type = new TypeAArray(tvalue, tkey); 5305 type = type.semantic(loc, sc); 5306 5307 semanticTypeInfo(sc, type); 5308 5309 return this; 5310 } 5311 5312 override bool isBool(bool result) 5313 { 5314 size_t dim = keys.dim; 5315 return result ? (dim != 0) : (dim == 0); 5316 } 5317 5318 override void accept(Visitor v) 5319 { 5320 v.visit(this); 5321 } 5322 } 5323 5324 enum stageScrub = 0x1; /// scrubReturnValue is running 5325 enum stageSearchPointers = 0x2; /// hasNonConstPointers is running 5326 enum stageOptimize = 0x4; /// optimize is running 5327 enum stageApply = 0x8; /// apply is running 5328 enum stageInlineScan = 0x10; /// inlineScan is running 5329 enum stageToCBuffer = 0x20; /// toCBuffer is running 5330 5331 /*********************************************************** 5332 * sd( e1, e2, e3, ... ) 5333 */ 5334 extern (C++) final class StructLiteralExp : Expression 5335 { 5336 StructDeclaration sd; /// which aggregate this is for 5337 Expressions* elements; /// parallels sd.fields[] with null entries for fields to skip 5338 Type stype; /// final type of result (can be different from sd's type) 5339 5340 bool useStaticInit; /// if this is true, use the StructDeclaration's init symbol 5341 Symbol* sym; /// back end symbol to initialize with literal 5342 5343 OwnedBy ownedByCtfe = OWNEDcode; 5344 5345 /** pointer to the origin instance of the expression. 5346 * once a new expression is created, origin is set to 'this'. 5347 * anytime when an expression copy is created, 'origin' pointer is set to 5348 * 'origin' pointer value of the original expression. 5349 */ 5350 StructLiteralExp origin; 5351 5352 /// those fields need to prevent a infinite recursion when one field of struct initialized with 'this' pointer. 5353 StructLiteralExp inlinecopy; 5354 5355 /** anytime when recursive function is calling, 'stageflags' marks with bit flag of 5356 * current stage and unmarks before return from this function. 5357 * 'inlinecopy' uses similar 'stageflags' and from multiple evaluation 'doInline' 5358 * (with infinite recursion) of this expression. 5359 */ 5360 int stageflags; 5361 5362 extern (D) this(Loc loc, StructDeclaration sd, Expressions* elements, Type stype = null) 5363 { 5364 super(loc, TOKstructliteral, __traits(classInstanceSize, StructLiteralExp)); 5365 this.sd = sd; 5366 if (!elements) 5367 elements = new Expressions(); 5368 this.elements = elements; 5369 this.stype = stype; 5370 this.origin = this; 5371 //printf("StructLiteralExp::StructLiteralExp(%s)\n", toChars()); 5372 } 5373 5374 static StructLiteralExp create(Loc loc, StructDeclaration sd, void* elements, Type stype = null) 5375 { 5376 return new StructLiteralExp(loc, sd, cast(Expressions*)elements, stype); 5377 } 5378 5379 override bool equals(RootObject o) 5380 { 5381 if (this == o) 5382 return true; 5383 if (o && o.dyncast() == DYNCAST_EXPRESSION && (cast(Expression)o).op == TOKstructliteral) 5384 { 5385 StructLiteralExp se = cast(StructLiteralExp)o; 5386 if (!type.equals(se.type)) 5387 return false; 5388 if (elements.dim != se.elements.dim) 5389 return false; 5390 for (size_t i = 0; i < elements.dim; i++) 5391 { 5392 Expression e1 = (*elements)[i]; 5393 Expression e2 = (*se.elements)[i]; 5394 if (e1 != e2 && (!e1 || !e2 || !e1.equals(e2))) 5395 return false; 5396 } 5397 return true; 5398 } 5399 return false; 5400 } 5401 5402 override Expression syntaxCopy() 5403 { 5404 auto exp = new StructLiteralExp(loc, sd, arraySyntaxCopy(elements), type ? type : stype); 5405 exp.origin = this; 5406 return exp; 5407 } 5408 5409 override Expression semantic(Scope* sc) 5410 { 5411 static if (LOGSEMANTIC) 5412 { 5413 printf("StructLiteralExp::semantic('%s')\n", toChars()); 5414 } 5415 if (type) 5416 return this; 5417 5418 sd.size(loc); 5419 if (sd.sizeok != SIZEOKdone) 5420 return new ErrorExp(); 5421 5422 if (arrayExpressionSemantic(elements, sc)) // run semantic() on each element 5423 return new ErrorExp(); 5424 5425 expandTuples(elements); 5426 5427 /* Fit elements[] to the corresponding type of field[]. 5428 */ 5429 if (!sd.fit(loc, sc, elements, stype)) 5430 return new ErrorExp(); 5431 5432 /* Fill out remainder of elements[] with default initializers for fields[] 5433 */ 5434 if (!sd.fill(loc, elements, false)) 5435 { 5436 /* An error in the initializer needs to be recorded as an error 5437 * in the enclosing function or template, since the initializer 5438 * will be part of the stuct declaration. 5439 */ 5440 global.increaseErrorCount(); 5441 return new ErrorExp(); 5442 } 5443 5444 if (checkFrameAccess(loc, sc, sd, elements.dim)) 5445 return new ErrorExp(); 5446 5447 type = stype ? stype : sd.type; 5448 return this; 5449 } 5450 5451 /************************************** 5452 * Gets expression at offset of type. 5453 * Returns NULL if not found. 5454 */ 5455 Expression getField(Type type, uint offset) 5456 { 5457 //printf("StructLiteralExp::getField(this = %s, type = %s, offset = %u)\n", 5458 // /*toChars()*/"", type->toChars(), offset); 5459 Expression e = null; 5460 int i = getFieldIndex(type, offset); 5461 5462 if (i != -1) 5463 { 5464 //printf("\ti = %d\n", i); 5465 if (i == sd.fields.dim - 1 && sd.isNested()) 5466 return null; 5467 5468 assert(i < elements.dim); 5469 e = (*elements)[i]; 5470 if (e) 5471 { 5472 //printf("e = %s, e->type = %s\n", e->toChars(), e->type->toChars()); 5473 5474 /* If type is a static array, and e is an initializer for that array, 5475 * then the field initializer should be an array literal of e. 5476 */ 5477 if (e.type.castMod(0) != type.castMod(0) && type.ty == Tsarray) 5478 { 5479 TypeSArray tsa = cast(TypeSArray)type; 5480 size_t length = cast(size_t)tsa.dim.toInteger(); 5481 auto z = new Expressions(); 5482 z.setDim(length); 5483 for (size_t q = 0; q < length; ++q) 5484 (*z)[q] = e.copy(); 5485 e = new ArrayLiteralExp(loc, z); 5486 e.type = type; 5487 } 5488 else 5489 { 5490 e = e.copy(); 5491 e.type = type; 5492 } 5493 if (useStaticInit && e.op == TOKstructliteral && e.type.needsNested()) 5494 { 5495 StructLiteralExp se = cast(StructLiteralExp)e; 5496 se.useStaticInit = true; 5497 } 5498 } 5499 } 5500 return e; 5501 } 5502 5503 /************************************ 5504 * Get index of field. 5505 * Returns -1 if not found. 5506 */ 5507 int getFieldIndex(Type type, uint offset) 5508 { 5509 /* Find which field offset is by looking at the field offsets 5510 */ 5511 if (elements.dim) 5512 { 5513 for (size_t i = 0; i < sd.fields.dim; i++) 5514 { 5515 VarDeclaration v = sd.fields[i]; 5516 if (offset == v.offset && type.size() == v.type.size()) 5517 { 5518 /* context field might not be filled. */ 5519 if (i == sd.fields.dim - 1 && sd.isNested()) 5520 return cast(int)i; 5521 Expression e = (*elements)[i]; 5522 if (e) 5523 { 5524 return cast(int)i; 5525 } 5526 break; 5527 } 5528 } 5529 } 5530 return -1; 5531 } 5532 5533 override Expression addDtorHook(Scope* sc) 5534 { 5535 /* If struct requires a destructor, rewrite as: 5536 * (S tmp = S()),tmp 5537 * so that the destructor can be hung on tmp. 5538 */ 5539 if (sd.dtor && sc.func) 5540 { 5541 /* Make an identifier for the temporary of the form: 5542 * __sl%s%d, where %s is the struct name 5543 */ 5544 const(size_t) len = 10; 5545 char[len + 1] buf; 5546 buf[len] = 0; 5547 strcpy(buf.ptr, "__sl"); 5548 strncat(buf.ptr, sd.ident.toChars(), len - 4 - 1); 5549 assert(buf[len] == 0); 5550 5551 auto tmp = copyToTemp(0, buf.ptr, this); 5552 Expression ae = new DeclarationExp(loc, tmp); 5553 Expression e = new CommaExp(loc, ae, new VarExp(loc, tmp)); 5554 e = e.semantic(sc); 5555 return e; 5556 } 5557 return this; 5558 } 5559 5560 override void accept(Visitor v) 5561 { 5562 v.visit(this); 5563 } 5564 } 5565 5566 /*********************************************************** 5567 * Mainly just a placeholder 5568 */ 5569 extern (C++) final class TypeExp : Expression 5570 { 5571 extern (D) this(Loc loc, Type type) 5572 { 5573 super(loc, TOKtype, __traits(classInstanceSize, TypeExp)); 5574 //printf("TypeExp::TypeExp(%s)\n", type->toChars()); 5575 this.type = type; 5576 } 5577 5578 override Expression syntaxCopy() 5579 { 5580 return new TypeExp(loc, type.syntaxCopy()); 5581 } 5582 5583 override Expression semantic(Scope* sc) 5584 { 5585 if (type.ty == Terror) 5586 return new ErrorExp(); 5587 5588 //printf("TypeExp::semantic(%s)\n", type->toChars()); 5589 Expression e; 5590 Type t; 5591 Dsymbol s; 5592 5593 type.resolve(loc, sc, &e, &t, &s, true); 5594 if (e) 5595 { 5596 //printf("e = %s %s\n", Token::toChars(e->op), e->toChars()); 5597 e = e.semantic(sc); 5598 } 5599 else if (t) 5600 { 5601 //printf("t = %d %s\n", t->ty, t->toChars()); 5602 type = t.semantic(loc, sc); 5603 e = this; 5604 } 5605 else if (s) 5606 { 5607 //printf("s = %s %s\n", s->kind(), s->toChars()); 5608 e = DsymbolExp.resolve(loc, sc, s, true); 5609 } 5610 else 5611 assert(0); 5612 5613 if (global.params.vcomplex) 5614 type.checkComplexTransition(loc); 5615 5616 return e; 5617 } 5618 5619 override bool checkType() 5620 { 5621 error("type %s is not an expression", toChars()); 5622 return true; 5623 } 5624 5625 override bool checkValue() 5626 { 5627 error("type %s has no value", toChars()); 5628 return true; 5629 } 5630 5631 override void accept(Visitor v) 5632 { 5633 v.visit(this); 5634 } 5635 } 5636 5637 /*********************************************************** 5638 * Mainly just a placeholder of 5639 * Package, Module, Nspace, and TemplateInstance (including TemplateMixin) 5640 * 5641 * A template instance that requires IFTI: 5642 * foo!tiargs(fargs) // foo!tiargs 5643 * is left until CallExp::semantic() or resolveProperties() 5644 */ 5645 extern (C++) final class ScopeExp : Expression 5646 { 5647 ScopeDsymbol sds; 5648 5649 extern (D) this(Loc loc, ScopeDsymbol sds) 5650 { 5651 super(loc, TOKscope, __traits(classInstanceSize, ScopeExp)); 5652 //printf("ScopeExp::ScopeExp(sds = '%s')\n", sds.toChars()); 5653 //static int count; if (++count == 38) *(char*)0=0; 5654 this.sds = sds; 5655 assert(!sds.isTemplateDeclaration()); // instead, you should use TemplateExp 5656 } 5657 5658 override Expression syntaxCopy() 5659 { 5660 return new ScopeExp(loc, cast(ScopeDsymbol)sds.syntaxCopy(null)); 5661 } 5662 5663 override Expression semantic(Scope* sc) 5664 { 5665 static if (LOGSEMANTIC) 5666 { 5667 printf("+ScopeExp::semantic(%p '%s')\n", this, toChars()); 5668 } 5669 if (type) 5670 return this; 5671 5672 ScopeDsymbol sds2 = sds; 5673 TemplateInstance ti = sds2.isTemplateInstance(); 5674 while (ti) 5675 { 5676 WithScopeSymbol withsym; 5677 if (!ti.findTempDecl(sc, &withsym) || !ti.semanticTiargs(sc)) 5678 { 5679 return new ErrorExp(); 5680 } 5681 if (withsym && withsym.withstate.wthis) 5682 { 5683 Expression e = new VarExp(loc, withsym.withstate.wthis); 5684 e = new DotTemplateInstanceExp(loc, e, ti); 5685 return e.semantic(sc); 5686 } 5687 if (ti.needsTypeInference(sc)) 5688 { 5689 if (TemplateDeclaration td = ti.tempdecl.isTemplateDeclaration()) 5690 { 5691 Dsymbol p = td.toParent2(); 5692 FuncDeclaration fdthis = hasThis(sc); 5693 AggregateDeclaration ad = p ? p.isAggregateDeclaration() : null; 5694 if (fdthis && ad && isAggregate(fdthis.vthis.type) == ad && (td._scope.stc & STCstatic) == 0) 5695 { 5696 Expression e = new DotTemplateInstanceExp(loc, new ThisExp(loc), ti.name, ti.tiargs); 5697 return e.semantic(sc); 5698 } 5699 } 5700 else if (OverloadSet os = ti.tempdecl.isOverloadSet()) 5701 { 5702 FuncDeclaration fdthis = hasThis(sc); 5703 AggregateDeclaration ad = os.parent.isAggregateDeclaration(); 5704 if (fdthis && ad && isAggregate(fdthis.vthis.type) == ad) 5705 { 5706 Expression e = new DotTemplateInstanceExp(loc, new ThisExp(loc), ti.name, ti.tiargs); 5707 return e.semantic(sc); 5708 } 5709 } 5710 // ti is an instance which requires IFTI. 5711 sds = ti; 5712 type = Type.tvoid; 5713 return this; 5714 } 5715 ti.semantic(sc); 5716 if (!ti.inst || ti.errors) 5717 return new ErrorExp(); 5718 5719 Dsymbol s = ti.toAlias(); 5720 if (s == ti) 5721 { 5722 sds = ti; 5723 type = Type.tvoid; 5724 return this; 5725 } 5726 sds2 = s.isScopeDsymbol(); 5727 if (sds2) 5728 { 5729 ti = sds2.isTemplateInstance(); 5730 //printf("+ sds2 = %s, '%s'\n", sds2.kind(), sds2.toChars()); 5731 continue; 5732 } 5733 5734 if (auto v = s.isVarDeclaration()) 5735 { 5736 if (!v.type) 5737 { 5738 error("forward reference of %s %s", v.kind(), v.toChars()); 5739 return new ErrorExp(); 5740 } 5741 if ((v.storage_class & STCmanifest) && v._init) 5742 { 5743 /* When an instance that will be converted to a constant exists, 5744 * the instance representation "foo!tiargs" is treated like a 5745 * variable name, and its recursive appearance check (note that 5746 * it's equivalent with a recursive instantiation of foo) is done 5747 * separately from the circular initialization check for the 5748 * eponymous enum variable declaration. 5749 * 5750 * template foo(T) { 5751 * enum bool foo = foo; // recursive definition check (v.inuse) 5752 * } 5753 * template bar(T) { 5754 * enum bool bar = bar!T; // recursive instantiation check (ti.inuse) 5755 * } 5756 */ 5757 if (ti.inuse) 5758 { 5759 error("recursive expansion of %s '%s'", ti.kind(), ti.toPrettyChars()); 5760 return new ErrorExp(); 5761 } 5762 auto e = v.expandInitializer(loc); 5763 ti.inuse++; 5764 e = e.semantic(sc); 5765 ti.inuse--; 5766 return e; 5767 } 5768 } 5769 5770 //printf("s = %s, '%s'\n", s.kind(), s.toChars()); 5771 auto e = DsymbolExp.resolve(loc, sc, s, true); 5772 //printf("-1ScopeExp::semantic()\n"); 5773 return e; 5774 } 5775 5776 //printf("sds2 = %s, '%s'\n", sds2.kind(), sds2.toChars()); 5777 //printf("\tparent = '%s'\n", sds2.parent.toChars()); 5778 sds2.semantic(sc); 5779 5780 if (auto t = sds2.getType()) // (Aggregate|Enum)Declaration 5781 return (new TypeExp(loc, t)).semantic(sc); 5782 5783 if (auto td = sds2.isTemplateDeclaration()) 5784 return (new TemplateExp(loc, td)).semantic(sc); 5785 5786 sds = sds2; 5787 type = Type.tvoid; 5788 //printf("-2ScopeExp::semantic() %s\n", toChars()); 5789 return this; 5790 } 5791 5792 override bool checkType() 5793 { 5794 if (sds.isPackage()) 5795 { 5796 error("%s %s has no type", sds.kind(), sds.toChars()); 5797 return true; 5798 } 5799 if (auto ti = sds.isTemplateInstance()) 5800 { 5801 //assert(ti.needsTypeInference(sc)); 5802 if (ti.tempdecl && 5803 ti.semantictiargsdone && 5804 ti.semanticRun == PASSinit) 5805 { 5806 error("partial %s %s has no type", sds.kind(), toChars()); 5807 return true; 5808 } 5809 } 5810 return false; 5811 } 5812 5813 override bool checkValue() 5814 { 5815 error("%s %s has no value", sds.kind(), sds.toChars()); 5816 return true; 5817 } 5818 5819 override void accept(Visitor v) 5820 { 5821 v.visit(this); 5822 } 5823 } 5824 5825 /*********************************************************** 5826 * Mainly just a placeholder 5827 */ 5828 extern (C++) final class TemplateExp : Expression 5829 { 5830 TemplateDeclaration td; 5831 FuncDeclaration fd; 5832 5833 extern (D) this(Loc loc, TemplateDeclaration td, FuncDeclaration fd = null) 5834 { 5835 super(loc, TOKtemplate, __traits(classInstanceSize, TemplateExp)); 5836 //printf("TemplateExp(): %s\n", td->toChars()); 5837 this.td = td; 5838 this.fd = fd; 5839 } 5840 5841 override bool isLvalue() 5842 { 5843 return fd !is null; 5844 } 5845 5846 override Expression toLvalue(Scope* sc, Expression e) 5847 { 5848 if (!fd) 5849 return Expression.toLvalue(sc, e); 5850 5851 assert(sc); 5852 return DsymbolExp.resolve(loc, sc, fd, true); 5853 } 5854 5855 override bool checkType() 5856 { 5857 error("%s %s has no type", td.kind(), toChars()); 5858 return true; 5859 } 5860 5861 override bool checkValue() 5862 { 5863 error("%s %s has no value", td.kind(), toChars()); 5864 return true; 5865 } 5866 5867 override void accept(Visitor v) 5868 { 5869 v.visit(this); 5870 } 5871 } 5872 5873 /*********************************************************** 5874 * thisexp.new(newargs) newtype(arguments) 5875 */ 5876 extern (C++) final class NewExp : Expression 5877 { 5878 Expression thisexp; // if !=null, 'this' for class being allocated 5879 Expressions* newargs; // Array of Expression's to call new operator 5880 Type newtype; 5881 Expressions* arguments; // Array of Expression's 5882 Expression argprefix; // expression to be evaluated just before arguments[] 5883 CtorDeclaration member; // constructor function 5884 NewDeclaration allocator; // allocator function 5885 int onstack; // allocate on stack 5886 5887 extern (D) this(Loc loc, Expression thisexp, Expressions* newargs, Type newtype, Expressions* arguments) 5888 { 5889 super(loc, TOKnew, __traits(classInstanceSize, NewExp)); 5890 this.thisexp = thisexp; 5891 this.newargs = newargs; 5892 this.newtype = newtype; 5893 this.arguments = arguments; 5894 } 5895 5896 override Expression syntaxCopy() 5897 { 5898 return new NewExp(loc, 5899 thisexp ? thisexp.syntaxCopy() : null, 5900 arraySyntaxCopy(newargs), 5901 newtype.syntaxCopy(), 5902 arraySyntaxCopy(arguments)); 5903 } 5904 5905 override Expression semantic(Scope* sc) 5906 { 5907 static if (LOGSEMANTIC) 5908 { 5909 printf("NewExp::semantic() %s\n", toChars()); 5910 if (thisexp) 5911 printf("\tthisexp = %s\n", thisexp.toChars()); 5912 printf("\tnewtype: %s\n", newtype.toChars()); 5913 } 5914 if (type) // if semantic() already run 5915 return this; 5916 5917 // Bugzilla 11581: With the syntax `new T[edim]` or `thisexp.new T[edim]`, 5918 // T should be analyzed first and edim should go into arguments iff it's 5919 // not a tuple. 5920 Expression edim = null; 5921 if (!arguments && newtype.ty == Tsarray) 5922 { 5923 edim = (cast(TypeSArray)newtype).dim; 5924 newtype = (cast(TypeNext)newtype).next; 5925 } 5926 5927 ClassDeclaration cdthis = null; 5928 if (thisexp) 5929 { 5930 thisexp = thisexp.semantic(sc); 5931 if (thisexp.op == TOKerror) 5932 return new ErrorExp(); 5933 cdthis = thisexp.type.isClassHandle(); 5934 if (!cdthis) 5935 { 5936 error("'this' for nested class must be a class type, not %s", thisexp.type.toChars()); 5937 return new ErrorExp(); 5938 } 5939 5940 sc = sc.push(cdthis); 5941 type = newtype.semantic(loc, sc); 5942 sc = sc.pop(); 5943 } 5944 else 5945 { 5946 type = newtype.semantic(loc, sc); 5947 } 5948 if (type.ty == Terror) 5949 return new ErrorExp(); 5950 5951 if (edim) 5952 { 5953 if (type.toBasetype().ty == Ttuple) 5954 { 5955 // --> new T[edim] 5956 type = new TypeSArray(type, edim); 5957 type = type.semantic(loc, sc); 5958 if (type.ty == Terror) 5959 return new ErrorExp(); 5960 } 5961 else 5962 { 5963 // --> new T[](edim) 5964 arguments = new Expressions(); 5965 arguments.push(edim); 5966 type = type.arrayOf(); 5967 } 5968 } 5969 5970 newtype = type; // in case type gets cast to something else 5971 Type tb = type.toBasetype(); 5972 //printf("tb: %s, deco = %s\n", tb.toChars(), tb.deco); 5973 5974 if (arrayExpressionSemantic(newargs, sc) || 5975 preFunctionParameters(loc, sc, newargs)) 5976 { 5977 return new ErrorExp(); 5978 } 5979 if (arrayExpressionSemantic(arguments, sc) || 5980 preFunctionParameters(loc, sc, arguments)) 5981 { 5982 return new ErrorExp(); 5983 } 5984 5985 if (thisexp && tb.ty != Tclass) 5986 { 5987 error("e.new is only for allocating nested classes, not %s", tb.toChars()); 5988 return new ErrorExp(); 5989 } 5990 5991 size_t nargs = arguments ? arguments.dim : 0; 5992 Expression newprefix = null; 5993 5994 if (tb.ty == Tclass) 5995 { 5996 auto cd = (cast(TypeClass)tb).sym; 5997 cd.size(loc); 5998 if (cd.sizeok != SIZEOKdone) 5999 return new ErrorExp(); 6000 if (!cd.ctor) 6001 cd.ctor = cd.searchCtor(); 6002 if (cd.noDefaultCtor && !nargs && !cd.defaultCtor) 6003 { 6004 error("default construction is disabled for type %s", cd.type.toChars()); 6005 return new ErrorExp(); 6006 } 6007 6008 if (cd.isInterfaceDeclaration()) 6009 { 6010 error("cannot create instance of interface %s", cd.toChars()); 6011 return new ErrorExp(); 6012 } 6013 if (cd.isAbstract()) 6014 { 6015 error("cannot create instance of abstract class %s", cd.toChars()); 6016 for (size_t i = 0; i < cd.vtbl.dim; i++) 6017 { 6018 FuncDeclaration fd = cd.vtbl[i].isFuncDeclaration(); 6019 if (fd && fd.isAbstract()) 6020 { 6021 errorSupplemental(loc, "function '%s' is not implemented", 6022 fd.toFullSignature()); 6023 } 6024 } 6025 return new ErrorExp(); 6026 } 6027 // checkDeprecated() is already done in newtype->semantic(). 6028 6029 if (cd.isNested()) 6030 { 6031 /* We need a 'this' pointer for the nested class. 6032 * Ensure we have the right one. 6033 */ 6034 Dsymbol s = cd.toParent2(); 6035 6036 //printf("cd isNested, parent = %s '%s'\n", s.kind(), s.toPrettyChars()); 6037 if (auto cdn = s.isClassDeclaration()) 6038 { 6039 if (!cdthis) 6040 { 6041 // Supply an implicit 'this' and try again 6042 thisexp = new ThisExp(loc); 6043 for (Dsymbol sp = sc.parent; 1; sp = sp.parent) 6044 { 6045 if (!sp) 6046 { 6047 error("outer class %s 'this' needed to 'new' nested class %s", 6048 cdn.toChars(), cd.toChars()); 6049 return new ErrorExp(); 6050 } 6051 ClassDeclaration cdp = sp.isClassDeclaration(); 6052 if (!cdp) 6053 continue; 6054 if (cdp == cdn || cdn.isBaseOf(cdp, null)) 6055 break; 6056 // Add a '.outer' and try again 6057 thisexp = new DotIdExp(loc, thisexp, Id.outer); 6058 } 6059 6060 thisexp = thisexp.semantic(sc); 6061 if (thisexp.op == TOKerror) 6062 return new ErrorExp(); 6063 cdthis = thisexp.type.isClassHandle(); 6064 } 6065 if (cdthis != cdn && !cdn.isBaseOf(cdthis, null)) 6066 { 6067 //printf("cdthis = %s\n", cdthis.toChars()); 6068 error("'this' for nested class must be of type %s, not %s", 6069 cdn.toChars(), thisexp.type.toChars()); 6070 return new ErrorExp(); 6071 } 6072 if (!MODimplicitConv(thisexp.type.mod, newtype.mod)) 6073 { 6074 error("nested type %s should have the same or weaker constancy as enclosing type %s", 6075 newtype.toChars(), thisexp.type.toChars()); 6076 return new ErrorExp(); 6077 } 6078 } 6079 else if (thisexp) 6080 { 6081 error("e.new is only for allocating nested classes"); 6082 return new ErrorExp(); 6083 } 6084 else if (auto fdn = s.isFuncDeclaration()) 6085 { 6086 // make sure the parent context fdn of cd is reachable from sc 6087 if (checkNestedRef(sc.parent, fdn)) 6088 { 6089 error("outer function context of %s is needed to 'new' nested class %s", 6090 fdn.toPrettyChars(), cd.toPrettyChars()); 6091 return new ErrorExp(); 6092 } 6093 } 6094 else 6095 assert(0); 6096 } 6097 else if (thisexp) 6098 { 6099 error("e.new is only for allocating nested classes"); 6100 return new ErrorExp(); 6101 } 6102 6103 if (cd.aggNew) 6104 { 6105 // Prepend the size argument to newargs[] 6106 Expression e = new IntegerExp(loc, cd.size(loc), Type.tsize_t); 6107 if (!newargs) 6108 newargs = new Expressions(); 6109 newargs.shift(e); 6110 6111 FuncDeclaration f = resolveFuncCall(loc, sc, cd.aggNew, null, tb, newargs); 6112 if (!f || f.errors) 6113 return new ErrorExp(); 6114 checkDeprecated(sc, f); 6115 checkPurity(sc, f); 6116 checkSafety(sc, f); 6117 checkNogc(sc, f); 6118 checkAccess(cd, loc, sc, f); 6119 6120 TypeFunction tf = cast(TypeFunction)f.type; 6121 Type rettype; 6122 if (functionParameters(loc, sc, tf, null, newargs, f, &rettype, &newprefix)) 6123 return new ErrorExp(); 6124 6125 allocator = f.isNewDeclaration(); 6126 assert(allocator); 6127 } 6128 else 6129 { 6130 if (newargs && newargs.dim) 6131 { 6132 error("no allocator for %s", cd.toChars()); 6133 return new ErrorExp(); 6134 } 6135 } 6136 6137 if (cd.ctor) 6138 { 6139 FuncDeclaration f = resolveFuncCall(loc, sc, cd.ctor, null, tb, arguments, 0); 6140 if (!f || f.errors) 6141 return new ErrorExp(); 6142 checkDeprecated(sc, f); 6143 checkPurity(sc, f); 6144 checkSafety(sc, f); 6145 checkNogc(sc, f); 6146 checkAccess(cd, loc, sc, f); 6147 6148 TypeFunction tf = cast(TypeFunction)f.type; 6149 if (!arguments) 6150 arguments = new Expressions(); 6151 if (functionParameters(loc, sc, tf, type, arguments, f, &type, &argprefix)) 6152 return new ErrorExp(); 6153 6154 member = f.isCtorDeclaration(); 6155 assert(member); 6156 } 6157 else 6158 { 6159 if (nargs) 6160 { 6161 error("no constructor for %s", cd.toChars()); 6162 return new ErrorExp(); 6163 } 6164 } 6165 } 6166 else if (tb.ty == Tstruct) 6167 { 6168 auto sd = (cast(TypeStruct)tb).sym; 6169 sd.size(loc); 6170 if (sd.sizeok != SIZEOKdone) 6171 return new ErrorExp(); 6172 if (!sd.ctor) 6173 sd.ctor = sd.searchCtor(); 6174 if (sd.noDefaultCtor && !nargs) 6175 { 6176 error("default construction is disabled for type %s", sd.type.toChars()); 6177 return new ErrorExp(); 6178 } 6179 // checkDeprecated() is already done in newtype->semantic(). 6180 6181 if (sd.aggNew) 6182 { 6183 // Prepend the uint size argument to newargs[] 6184 Expression e = new IntegerExp(loc, sd.size(loc), Type.tsize_t); 6185 if (!newargs) 6186 newargs = new Expressions(); 6187 newargs.shift(e); 6188 6189 FuncDeclaration f = resolveFuncCall(loc, sc, sd.aggNew, null, tb, newargs); 6190 if (!f || f.errors) 6191 return new ErrorExp(); 6192 checkDeprecated(sc, f); 6193 checkPurity(sc, f); 6194 checkSafety(sc, f); 6195 checkNogc(sc, f); 6196 checkAccess(sd, loc, sc, f); 6197 6198 TypeFunction tf = cast(TypeFunction)f.type; 6199 Type rettype; 6200 if (functionParameters(loc, sc, tf, null, newargs, f, &rettype, &newprefix)) 6201 return new ErrorExp(); 6202 6203 allocator = f.isNewDeclaration(); 6204 assert(allocator); 6205 } 6206 else 6207 { 6208 if (newargs && newargs.dim) 6209 { 6210 error("no allocator for %s", sd.toChars()); 6211 return new ErrorExp(); 6212 } 6213 } 6214 6215 if (sd.ctor && nargs) 6216 { 6217 FuncDeclaration f = resolveFuncCall(loc, sc, sd.ctor, null, tb, arguments, 0); 6218 if (!f || f.errors) 6219 return new ErrorExp(); 6220 checkDeprecated(sc, f); 6221 checkPurity(sc, f); 6222 checkSafety(sc, f); 6223 checkNogc(sc, f); 6224 checkAccess(sd, loc, sc, f); 6225 6226 TypeFunction tf = cast(TypeFunction)f.type; 6227 if (!arguments) 6228 arguments = new Expressions(); 6229 if (functionParameters(loc, sc, tf, type, arguments, f, &type, &argprefix)) 6230 return new ErrorExp(); 6231 6232 member = f.isCtorDeclaration(); 6233 assert(member); 6234 6235 if (checkFrameAccess(loc, sc, sd, sd.fields.dim)) 6236 return new ErrorExp(); 6237 } 6238 else 6239 { 6240 if (!arguments) 6241 arguments = new Expressions(); 6242 6243 if (!sd.fit(loc, sc, arguments, tb)) 6244 return new ErrorExp(); 6245 6246 if (!sd.fill(loc, arguments, false)) 6247 return new ErrorExp(); 6248 6249 if (checkFrameAccess(loc, sc, sd, arguments ? arguments.dim : 0)) 6250 return new ErrorExp(); 6251 } 6252 6253 type = type.pointerTo(); 6254 } 6255 else if (tb.ty == Tarray && nargs) 6256 { 6257 Type tn = tb.nextOf().baseElemOf(); 6258 Dsymbol s = tn.toDsymbol(sc); 6259 AggregateDeclaration ad = s ? s.isAggregateDeclaration() : null; 6260 if (ad && ad.noDefaultCtor) 6261 { 6262 error("default construction is disabled for type %s", tb.nextOf().toChars()); 6263 return new ErrorExp(); 6264 } 6265 for (size_t i = 0; i < nargs; i++) 6266 { 6267 if (tb.ty != Tarray) 6268 { 6269 error("too many arguments for array"); 6270 return new ErrorExp(); 6271 } 6272 6273 Expression arg = (*arguments)[i]; 6274 arg = resolveProperties(sc, arg); 6275 arg = arg.implicitCastTo(sc, Type.tsize_t); 6276 arg = arg.optimize(WANTvalue); 6277 if (arg.op == TOKint64 && cast(sinteger_t)arg.toInteger() < 0) 6278 { 6279 error("negative array index %s", arg.toChars()); 6280 return new ErrorExp(); 6281 } 6282 (*arguments)[i] = arg; 6283 tb = (cast(TypeDArray)tb).next.toBasetype(); 6284 } 6285 } 6286 else if (tb.isscalar()) 6287 { 6288 if (!nargs) 6289 { 6290 } 6291 else if (nargs == 1) 6292 { 6293 Expression e = (*arguments)[0]; 6294 e = e.implicitCastTo(sc, tb); 6295 (*arguments)[0] = e; 6296 } 6297 else 6298 { 6299 error("more than one argument for construction of %s", type.toChars()); 6300 return new ErrorExp(); 6301 } 6302 6303 type = type.pointerTo(); 6304 } 6305 else 6306 { 6307 error("new can only create structs, dynamic arrays or class objects, not %s's", type.toChars()); 6308 return new ErrorExp(); 6309 } 6310 6311 //printf("NewExp: '%s'\n", toChars()); 6312 //printf("NewExp:type '%s'\n", type->toChars()); 6313 semanticTypeInfo(sc, type); 6314 6315 if (newprefix) 6316 return combine(newprefix, this); 6317 return this; 6318 } 6319 6320 override void accept(Visitor v) 6321 { 6322 v.visit(this); 6323 } 6324 } 6325 6326 /*********************************************************** 6327 * thisexp.new(newargs) class baseclasses { } (arguments) 6328 */ 6329 extern (C++) final class NewAnonClassExp : Expression 6330 { 6331 Expression thisexp; // if !=null, 'this' for class being allocated 6332 Expressions* newargs; // Array of Expression's to call new operator 6333 ClassDeclaration cd; // class being instantiated 6334 Expressions* arguments; // Array of Expression's to call class constructor 6335 6336 extern (D) this(Loc loc, Expression thisexp, Expressions* newargs, ClassDeclaration cd, Expressions* arguments) 6337 { 6338 super(loc, TOKnewanonclass, __traits(classInstanceSize, NewAnonClassExp)); 6339 this.thisexp = thisexp; 6340 this.newargs = newargs; 6341 this.cd = cd; 6342 this.arguments = arguments; 6343 } 6344 6345 override Expression syntaxCopy() 6346 { 6347 return new NewAnonClassExp(loc, thisexp ? thisexp.syntaxCopy() : null, arraySyntaxCopy(newargs), cast(ClassDeclaration)cd.syntaxCopy(null), arraySyntaxCopy(arguments)); 6348 } 6349 6350 override Expression semantic(Scope* sc) 6351 { 6352 static if (LOGSEMANTIC) 6353 { 6354 printf("NewAnonClassExp::semantic() %s\n", toChars()); 6355 //printf("thisexp = %p\n", thisexp); 6356 //printf("type: %s\n", type->toChars()); 6357 } 6358 6359 Expression d = new DeclarationExp(loc, cd); 6360 sc = sc.push(); // just create new scope 6361 sc.flags &= ~SCOPEctfe; // temporary stop CTFE 6362 d = d.semantic(sc); 6363 sc = sc.pop(); 6364 6365 if (!cd.errors && sc.intypeof && !sc.parent.inNonRoot()) 6366 { 6367 ScopeDsymbol sds = sc.tinst ? cast(ScopeDsymbol)sc.tinst : sc._module; 6368 sds.members.push(cd); 6369 } 6370 6371 Expression n = new NewExp(loc, thisexp, newargs, cd.type, arguments); 6372 6373 Expression c = new CommaExp(loc, d, n); 6374 return c.semantic(sc); 6375 } 6376 6377 override void accept(Visitor v) 6378 { 6379 v.visit(this); 6380 } 6381 } 6382 6383 /*********************************************************** 6384 */ 6385 extern (C++) class SymbolExp : Expression 6386 { 6387 Declaration var; 6388 bool hasOverloads; 6389 6390 final extern (D) this(Loc loc, TOK op, int size, Declaration var, bool hasOverloads) 6391 { 6392 super(loc, op, size); 6393 assert(var); 6394 this.var = var; 6395 this.hasOverloads = hasOverloads; 6396 } 6397 6398 override void accept(Visitor v) 6399 { 6400 v.visit(this); 6401 } 6402 6403 override void printAST(int indent) 6404 { 6405 Expression.printAST(indent); 6406 foreach (i; 0 .. indent + 2) 6407 printf(" "); 6408 printf(".var: %s\n", var ? var.toChars() : ""); 6409 } 6410 } 6411 6412 /*********************************************************** 6413 * Offset from symbol 6414 */ 6415 extern (C++) final class SymOffExp : SymbolExp 6416 { 6417 dinteger_t offset; 6418 6419 extern (D) this(Loc loc, Declaration var, dinteger_t offset, bool hasOverloads = true) 6420 { 6421 if (auto v = var.isVarDeclaration()) 6422 { 6423 // FIXME: This error report will never be handled anyone. 6424 // It should be done before the SymOffExp construction. 6425 if (v.needThis()) 6426 .error(loc, "need 'this' for address of %s", v.toChars()); 6427 hasOverloads = false; 6428 } 6429 super(loc, TOKsymoff, __traits(classInstanceSize, SymOffExp), var, hasOverloads); 6430 this.offset = offset; 6431 } 6432 6433 override Expression semantic(Scope* sc) 6434 { 6435 static if (LOGSEMANTIC) 6436 { 6437 printf("SymOffExp::semantic('%s')\n", toChars()); 6438 } 6439 //var->semantic(sc); 6440 if (!type) 6441 type = var.type.pointerTo(); 6442 6443 if (auto v = var.isVarDeclaration()) 6444 { 6445 if (v.checkNestedReference(sc, loc)) 6446 return new ErrorExp(); 6447 } 6448 else if (auto f = var.isFuncDeclaration()) 6449 { 6450 if (f.checkNestedReference(sc, loc)) 6451 return new ErrorExp(); 6452 } 6453 6454 return this; 6455 } 6456 6457 override bool isBool(bool result) 6458 { 6459 return result ? true : false; 6460 } 6461 6462 override void accept(Visitor v) 6463 { 6464 v.visit(this); 6465 } 6466 } 6467 6468 /*********************************************************** 6469 * Variable 6470 */ 6471 extern (C++) final class VarExp : SymbolExp 6472 { 6473 extern (D) this(Loc loc, Declaration var, bool hasOverloads = true) 6474 { 6475 if (var.isVarDeclaration()) 6476 hasOverloads = false; 6477 6478 super(loc, TOKvar, __traits(classInstanceSize, VarExp), var, hasOverloads); 6479 //printf("VarExp(this = %p, '%s', loc = %s)\n", this, var->toChars(), loc.toChars()); 6480 //if (strcmp(var->ident->toChars(), "func") == 0) assert(0); 6481 this.type = var.type; 6482 } 6483 6484 static VarExp create(Loc loc, Declaration var, bool hasOverloads = true) 6485 { 6486 return new VarExp(loc, var, hasOverloads); 6487 } 6488 6489 override bool equals(RootObject o) 6490 { 6491 if (this == o) 6492 return true; 6493 if ((cast(Expression)o).op == TOKvar) 6494 { 6495 VarExp ne = cast(VarExp)o; 6496 if (type.toHeadMutable().equals(ne.type.toHeadMutable()) && var == ne.var) 6497 { 6498 return true; 6499 } 6500 } 6501 return false; 6502 } 6503 6504 override Expression semantic(Scope* sc) 6505 { 6506 static if (LOGSEMANTIC) 6507 { 6508 printf("VarExp::semantic(%s)\n", toChars()); 6509 } 6510 if (auto fd = var.isFuncDeclaration()) 6511 { 6512 //printf("L%d fd = %s\n", __LINE__, f->toChars()); 6513 if (!fd.functionSemantic()) 6514 return new ErrorExp(); 6515 } 6516 6517 if (!type) 6518 type = var.type; 6519 if (type && !type.deco) 6520 type = type.semantic(loc, sc); 6521 6522 /* Fix for 1161 doesn't work because it causes protection 6523 * problems when instantiating imported templates passing private 6524 * variables as alias template parameters. 6525 */ 6526 //checkAccess(loc, sc, NULL, var); 6527 6528 if (auto vd = var.isVarDeclaration()) 6529 { 6530 if (vd.checkNestedReference(sc, loc)) 6531 return new ErrorExp(); 6532 6533 // Bugzilla 12025: If the variable is not actually used in runtime code, 6534 // the purity violation error is redundant. 6535 //checkPurity(sc, vd); 6536 } 6537 else if (auto fd = var.isFuncDeclaration()) 6538 { 6539 // TODO: If fd isn't yet resolved its overload, the checkNestedReference 6540 // call would cause incorrect validation. 6541 // Maybe here should be moved in CallExp, or AddrExp for functions. 6542 if (fd.checkNestedReference(sc, loc)) 6543 return new ErrorExp(); 6544 } 6545 else if (auto od = var.isOverDeclaration()) 6546 { 6547 type = Type.tvoid; // ambiguous type? 6548 } 6549 6550 return this; 6551 } 6552 6553 override int checkModifiable(Scope* sc, int flag) 6554 { 6555 //printf("VarExp::checkModifiable %s", toChars()); 6556 assert(type); 6557 return var.checkModify(loc, sc, type, null, flag); 6558 } 6559 6560 bool checkReadModifyWrite(); 6561 6562 override bool isLvalue() 6563 { 6564 if (var.storage_class & (STClazy | STCrvalue | STCmanifest)) 6565 return false; 6566 return true; 6567 } 6568 6569 override Expression toLvalue(Scope* sc, Expression e) 6570 { 6571 if (var.storage_class & STCmanifest) 6572 { 6573 error("manifest constant '%s' is not lvalue", var.toChars()); 6574 return new ErrorExp(); 6575 } 6576 if (var.storage_class & STClazy) 6577 { 6578 error("lazy variables cannot be lvalues"); 6579 return new ErrorExp(); 6580 } 6581 if (var.ident == Id.ctfe) 6582 { 6583 error("compiler-generated variable __ctfe is not an lvalue"); 6584 return new ErrorExp(); 6585 } 6586 if (var.ident == Id.dollar) // Bugzilla 13574 6587 { 6588 error("'$' is not an lvalue"); 6589 return new ErrorExp(); 6590 } 6591 return this; 6592 } 6593 6594 override Expression modifiableLvalue(Scope* sc, Expression e) 6595 { 6596 //printf("VarExp::modifiableLvalue('%s')\n", var->toChars()); 6597 if (var.storage_class & STCmanifest) 6598 { 6599 error("cannot modify manifest constant '%s'", toChars()); 6600 return new ErrorExp(); 6601 } 6602 // See if this expression is a modifiable lvalue (i.e. not const) 6603 return Expression.modifiableLvalue(sc, e); 6604 } 6605 6606 override void accept(Visitor v) 6607 { 6608 v.visit(this); 6609 } 6610 } 6611 6612 /*********************************************************** 6613 * Overload Set 6614 */ 6615 extern (C++) final class OverExp : Expression 6616 { 6617 OverloadSet vars; 6618 6619 extern (D) this(Loc loc, OverloadSet s) 6620 { 6621 super(loc, TOKoverloadset, __traits(classInstanceSize, OverExp)); 6622 //printf("OverExp(this = %p, '%s')\n", this, var->toChars()); 6623 vars = s; 6624 type = Type.tvoid; 6625 } 6626 6627 override bool isLvalue() 6628 { 6629 return true; 6630 } 6631 6632 override Expression toLvalue(Scope* sc, Expression e) 6633 { 6634 return this; 6635 } 6636 6637 override void accept(Visitor v) 6638 { 6639 v.visit(this); 6640 } 6641 } 6642 6643 /*********************************************************** 6644 * Function/Delegate literal 6645 */ 6646 extern (C++) final class FuncExp : Expression 6647 { 6648 FuncLiteralDeclaration fd; 6649 TemplateDeclaration td; 6650 TOK tok; 6651 6652 extern (D) this(Loc loc, Dsymbol s) 6653 { 6654 super(loc, TOKfunction, __traits(classInstanceSize, FuncExp)); 6655 this.td = s.isTemplateDeclaration(); 6656 this.fd = s.isFuncLiteralDeclaration(); 6657 if (td) 6658 { 6659 assert(td.literal); 6660 assert(td.members && td.members.dim == 1); 6661 fd = (*td.members)[0].isFuncLiteralDeclaration(); 6662 } 6663 tok = fd.tok; // save original kind of function/delegate/(infer) 6664 assert(fd.fbody); 6665 } 6666 6667 override bool equals(RootObject o) 6668 { 6669 if (this == o) 6670 return true; 6671 if (o.dyncast() != DYNCAST_EXPRESSION) 6672 return false; 6673 if ((cast(Expression)o).op == TOKfunction) 6674 { 6675 FuncExp fe = cast(FuncExp)o; 6676 return fd == fe.fd; 6677 } 6678 return false; 6679 } 6680 6681 void genIdent(Scope* sc) 6682 { 6683 if (fd.ident == Id.empty) 6684 { 6685 const(char)* s; 6686 if (fd.fes) 6687 s = "__foreachbody"; 6688 else if (fd.tok == TOKreserved) 6689 s = "__lambda"; 6690 else if (fd.tok == TOKdelegate) 6691 s = "__dgliteral"; 6692 else 6693 s = "__funcliteral"; 6694 6695 DsymbolTable symtab; 6696 if (FuncDeclaration func = sc.parent.isFuncDeclaration()) 6697 { 6698 if (func.localsymtab is null) 6699 { 6700 // Inside template constraint, symtab is not set yet. 6701 // Initialize it lazily. 6702 func.localsymtab = new DsymbolTable(); 6703 } 6704 symtab = func.localsymtab; 6705 } 6706 else 6707 { 6708 ScopeDsymbol sds = sc.parent.isScopeDsymbol(); 6709 if (!sds.symtab) 6710 { 6711 // Inside template constraint, symtab may not be set yet. 6712 // Initialize it lazily. 6713 assert(sds.isTemplateInstance()); 6714 sds.symtab = new DsymbolTable(); 6715 } 6716 symtab = sds.symtab; 6717 } 6718 assert(symtab); 6719 Identifier id = Identifier.generateId(s, symtab.len() + 1); 6720 fd.ident = id; 6721 if (td) 6722 td.ident = id; 6723 symtab.insert(td ? cast(Dsymbol)td : cast(Dsymbol)fd); 6724 } 6725 } 6726 6727 override Expression syntaxCopy() 6728 { 6729 if (td) 6730 return new FuncExp(loc, td.syntaxCopy(null)); 6731 else if (fd.semanticRun == PASSinit) 6732 return new FuncExp(loc, fd.syntaxCopy(null)); 6733 else // Bugzilla 13481: Prevent multiple semantic analysis of lambda body. 6734 return new FuncExp(loc, fd); 6735 } 6736 6737 override Expression semantic(Scope* sc) 6738 { 6739 static if (LOGSEMANTIC) 6740 { 6741 printf("FuncExp::semantic(%s)\n", toChars()); 6742 if (fd.treq) 6743 printf(" treq = %s\n", fd.treq.toChars()); 6744 } 6745 Expression e = this; 6746 6747 sc = sc.push(); // just create new scope 6748 sc.flags &= ~SCOPEctfe; // temporary stop CTFE 6749 sc.protection = Prot(PROTpublic); // Bugzilla 12506 6750 6751 if (!type || type == Type.tvoid) 6752 { 6753 /* fd->treq might be incomplete type, 6754 * so should not semantic it. 6755 * void foo(T)(T delegate(int) dg){} 6756 * foo(a=>a); // in IFTI, treq == T delegate(int) 6757 */ 6758 //if (fd->treq) 6759 // fd->treq = fd->treq->semantic(loc, sc); 6760 6761 genIdent(sc); 6762 6763 // Set target of return type inference 6764 if (fd.treq && !fd.type.nextOf()) 6765 { 6766 TypeFunction tfv = null; 6767 if (fd.treq.ty == Tdelegate || (fd.treq.ty == Tpointer && fd.treq.nextOf().ty == Tfunction)) 6768 tfv = cast(TypeFunction)fd.treq.nextOf(); 6769 if (tfv) 6770 { 6771 TypeFunction tfl = cast(TypeFunction)fd.type; 6772 tfl.next = tfv.nextOf(); 6773 } 6774 } 6775 6776 //printf("td = %p, treq = %p\n", td, fd->treq); 6777 if (td) 6778 { 6779 assert(td.parameters && td.parameters.dim); 6780 td.semantic(sc); 6781 type = Type.tvoid; // temporary type 6782 6783 if (fd.treq) // defer type determination 6784 { 6785 FuncExp fe; 6786 if (matchType(fd.treq, sc, &fe) > MATCHnomatch) 6787 e = fe; 6788 else 6789 e = new ErrorExp(); 6790 } 6791 goto Ldone; 6792 } 6793 6794 uint olderrors = global.errors; 6795 fd.semantic(sc); 6796 if (olderrors == global.errors) 6797 { 6798 fd.semantic2(sc); 6799 if (olderrors == global.errors) 6800 fd.semantic3(sc); 6801 } 6802 if (olderrors != global.errors) 6803 { 6804 if (fd.type && fd.type.ty == Tfunction && !fd.type.nextOf()) 6805 (cast(TypeFunction)fd.type).next = Type.terror; 6806 e = new ErrorExp(); 6807 goto Ldone; 6808 } 6809 6810 // Type is a "delegate to" or "pointer to" the function literal 6811 if ((fd.isNested() && fd.tok == TOKdelegate) || (tok == TOKreserved && fd.treq && fd.treq.ty == Tdelegate)) 6812 { 6813 type = new TypeDelegate(fd.type); 6814 type = type.semantic(loc, sc); 6815 6816 fd.tok = TOKdelegate; 6817 } 6818 else 6819 { 6820 type = new TypePointer(fd.type); 6821 type = type.semantic(loc, sc); 6822 //type = fd->type->pointerTo(); 6823 6824 /* A lambda expression deduced to function pointer might become 6825 * to a delegate literal implicitly. 6826 * 6827 * auto foo(void function() fp) { return 1; } 6828 * assert(foo({}) == 1); 6829 * 6830 * So, should keep fd->tok == TOKreserve if fd->treq == NULL. 6831 */ 6832 if (fd.treq && fd.treq.ty == Tpointer) 6833 { 6834 // change to non-nested 6835 fd.tok = TOKfunction; 6836 fd.vthis = null; 6837 } 6838 } 6839 fd.tookAddressOf++; 6840 } 6841 6842 Ldone: 6843 sc = sc.pop(); 6844 return e; 6845 } 6846 6847 // used from CallExp::semantic() 6848 Expression semantic(Scope* sc, Expressions* arguments) 6849 { 6850 if ((!type || type == Type.tvoid) && td && arguments && arguments.dim) 6851 { 6852 for (size_t k = 0; k < arguments.dim; k++) 6853 { 6854 Expression checkarg = (*arguments)[k]; 6855 if (checkarg.op == TOKerror) 6856 return checkarg; 6857 } 6858 6859 genIdent(sc); 6860 6861 assert(td.parameters && td.parameters.dim); 6862 td.semantic(sc); 6863 6864 TypeFunction tfl = cast(TypeFunction)fd.type; 6865 size_t dim = Parameter.dim(tfl.parameters); 6866 if (arguments.dim < dim) 6867 { 6868 // Default arguments are always typed, so they don't need inference. 6869 Parameter p = Parameter.getNth(tfl.parameters, arguments.dim); 6870 if (p.defaultArg) 6871 dim = arguments.dim; 6872 } 6873 6874 if ((!tfl.varargs && arguments.dim == dim) || (tfl.varargs && arguments.dim >= dim)) 6875 { 6876 auto tiargs = new Objects(); 6877 tiargs.reserve(td.parameters.dim); 6878 6879 for (size_t i = 0; i < td.parameters.dim; i++) 6880 { 6881 TemplateParameter tp = (*td.parameters)[i]; 6882 for (size_t u = 0; u < dim; u++) 6883 { 6884 Parameter p = Parameter.getNth(tfl.parameters, u); 6885 if (p.type.ty == Tident && (cast(TypeIdentifier)p.type).ident == tp.ident) 6886 { 6887 Expression e = (*arguments)[u]; 6888 tiargs.push(e.type); 6889 u = dim; // break inner loop 6890 } 6891 } 6892 } 6893 6894 auto ti = new TemplateInstance(loc, td, tiargs); 6895 return (new ScopeExp(loc, ti)).semantic(sc); 6896 } 6897 error("cannot infer function literal type"); 6898 return new ErrorExp(); 6899 } 6900 return semantic(sc); 6901 } 6902 6903 MATCH matchType(Type to, Scope* sc, FuncExp* presult, int flag = 0) 6904 { 6905 //printf("FuncExp::matchType('%s'), to=%s\n", type ? type->toChars() : "null", to->toChars()); 6906 if (presult) 6907 *presult = null; 6908 6909 TypeFunction tof = null; 6910 if (to.ty == Tdelegate) 6911 { 6912 if (tok == TOKfunction) 6913 { 6914 if (!flag) 6915 error("cannot match function literal to delegate type '%s'", to.toChars()); 6916 return MATCHnomatch; 6917 } 6918 tof = cast(TypeFunction)to.nextOf(); 6919 } 6920 else if (to.ty == Tpointer && to.nextOf().ty == Tfunction) 6921 { 6922 if (tok == TOKdelegate) 6923 { 6924 if (!flag) 6925 error("cannot match delegate literal to function pointer type '%s'", to.toChars()); 6926 return MATCHnomatch; 6927 } 6928 tof = cast(TypeFunction)to.nextOf(); 6929 } 6930 6931 if (td) 6932 { 6933 if (!tof) 6934 { 6935 L1: 6936 if (!flag) 6937 error("cannot infer parameter types from %s", to.toChars()); 6938 return MATCHnomatch; 6939 } 6940 6941 // Parameter types inference from 'tof' 6942 assert(td._scope); 6943 TypeFunction tf = cast(TypeFunction)fd.type; 6944 //printf("\ttof = %s\n", tof->toChars()); 6945 //printf("\ttf = %s\n", tf->toChars()); 6946 size_t dim = Parameter.dim(tf.parameters); 6947 6948 if (Parameter.dim(tof.parameters) != dim || tof.varargs != tf.varargs) 6949 goto L1; 6950 6951 auto tiargs = new Objects(); 6952 tiargs.reserve(td.parameters.dim); 6953 6954 for (size_t i = 0; i < td.parameters.dim; i++) 6955 { 6956 TemplateParameter tp = (*td.parameters)[i]; 6957 size_t u = 0; 6958 for (; u < dim; u++) 6959 { 6960 Parameter p = Parameter.getNth(tf.parameters, u); 6961 if (p.type.ty == Tident && (cast(TypeIdentifier)p.type).ident == tp.ident) 6962 { 6963 break; 6964 } 6965 } 6966 assert(u < dim); 6967 Parameter pto = Parameter.getNth(tof.parameters, u); 6968 Type t = pto.type; 6969 if (t.ty == Terror) 6970 goto L1; 6971 tiargs.push(t); 6972 } 6973 6974 // Set target of return type inference 6975 if (!tf.next && tof.next) 6976 fd.treq = to; 6977 6978 auto ti = new TemplateInstance(loc, td, tiargs); 6979 Expression ex = (new ScopeExp(loc, ti)).semantic(td._scope); 6980 6981 // Reset inference target for the later re-semantic 6982 fd.treq = null; 6983 6984 if (ex.op == TOKerror) 6985 return MATCHnomatch; 6986 if (ex.op != TOKfunction) 6987 goto L1; 6988 return (cast(FuncExp)ex).matchType(to, sc, presult, flag); 6989 } 6990 6991 if (!tof || !tof.next) 6992 return MATCHnomatch; 6993 6994 assert(type && type != Type.tvoid); 6995 TypeFunction tfx = cast(TypeFunction)fd.type; 6996 bool convertMatch = (type.ty != to.ty); 6997 6998 if (fd.inferRetType && tfx.next.implicitConvTo(tof.next) == MATCHconvert) 6999 { 7000 /* If return type is inferred and covariant return, 7001 * tweak return statements to required return type. 7002 * 7003 * interface I {} 7004 * class C : Object, I{} 7005 * 7006 * I delegate() dg = delegate() { return new class C(); } 7007 */ 7008 convertMatch = true; 7009 7010 auto tfy = new TypeFunction(tfx.parameters, tof.next, tfx.varargs, tfx.linkage, STCundefined); 7011 tfy.mod = tfx.mod; 7012 tfy.isnothrow = tfx.isnothrow; 7013 tfy.isnogc = tfx.isnogc; 7014 tfy.purity = tfx.purity; 7015 tfy.isproperty = tfx.isproperty; 7016 tfy.isref = tfx.isref; 7017 tfy.iswild = tfx.iswild; 7018 tfy.deco = tfy.merge().deco; 7019 7020 tfx = tfy; 7021 } 7022 Type tx; 7023 if (tok == TOKdelegate || tok == TOKreserved && (type.ty == Tdelegate || type.ty == Tpointer && to.ty == Tdelegate)) 7024 { 7025 // Allow conversion from implicit function pointer to delegate 7026 tx = new TypeDelegate(tfx); 7027 tx.deco = tx.merge().deco; 7028 } 7029 else 7030 { 7031 assert(tok == TOKfunction || tok == TOKreserved && type.ty == Tpointer); 7032 tx = tfx.pointerTo(); 7033 } 7034 //printf("\ttx = %s, to = %s\n", tx->toChars(), to->toChars()); 7035 7036 MATCH m = tx.implicitConvTo(to); 7037 if (m > MATCHnomatch) 7038 { 7039 // MATCHexact: exact type match 7040 // MATCHconst: covairiant type match (eg. attributes difference) 7041 // MATCHconvert: context conversion 7042 m = convertMatch ? MATCHconvert : tx.equals(to) ? MATCHexact : MATCHconst; 7043 7044 if (presult) 7045 { 7046 (*presult) = cast(FuncExp)copy(); 7047 (*presult).type = to; 7048 7049 // Bugzilla 12508: Tweak function body for covariant returns. 7050 (*presult).fd.modifyReturns(sc, tof.next); 7051 } 7052 } 7053 else if (!flag) 7054 { 7055 error("cannot implicitly convert expression (%s) of type %s to %s", toChars(), tx.toChars(), to.toChars()); 7056 } 7057 return m; 7058 } 7059 7060 override const(char)* toChars() 7061 { 7062 return fd.toChars(); 7063 } 7064 7065 override bool checkType() 7066 { 7067 if (td) 7068 { 7069 error("template lambda has no type"); 7070 return true; 7071 } 7072 return false; 7073 } 7074 7075 override bool checkValue() 7076 { 7077 if (td) 7078 { 7079 error("template lambda has no value"); 7080 return true; 7081 } 7082 return false; 7083 } 7084 7085 override void accept(Visitor v) 7086 { 7087 v.visit(this); 7088 } 7089 } 7090 7091 /*********************************************************** 7092 * Declaration of a symbol 7093 * 7094 * D grammar allows declarations only as statements. However in AST representation 7095 * it can be part of any expression. This is used, for example, during internal 7096 * syntax re-writes to inject hidden symbols. 7097 */ 7098 extern (C++) final class DeclarationExp : Expression 7099 { 7100 Dsymbol declaration; 7101 7102 extern (D) this(Loc loc, Dsymbol declaration) 7103 { 7104 super(loc, TOKdeclaration, __traits(classInstanceSize, DeclarationExp)); 7105 this.declaration = declaration; 7106 } 7107 7108 override Expression syntaxCopy() 7109 { 7110 return new DeclarationExp(loc, declaration.syntaxCopy(null)); 7111 } 7112 7113 override Expression semantic(Scope* sc) 7114 { 7115 if (type) 7116 return this; 7117 static if (LOGSEMANTIC) 7118 { 7119 printf("DeclarationExp::semantic() %s\n", toChars()); 7120 } 7121 7122 uint olderrors = global.errors; 7123 7124 /* This is here to support extern(linkage) declaration, 7125 * where the extern(linkage) winds up being an AttribDeclaration 7126 * wrapper. 7127 */ 7128 Dsymbol s = declaration; 7129 7130 while (1) 7131 { 7132 AttribDeclaration ad = s.isAttribDeclaration(); 7133 if (ad) 7134 { 7135 if (ad.decl && ad.decl.dim == 1) 7136 { 7137 s = (*ad.decl)[0]; 7138 continue; 7139 } 7140 } 7141 break; 7142 } 7143 7144 VarDeclaration v = s.isVarDeclaration(); 7145 if (v) 7146 { 7147 // Do semantic() on initializer first, so: 7148 // int a = a; 7149 // will be illegal. 7150 declaration.semantic(sc); 7151 s.parent = sc.parent; 7152 } 7153 7154 //printf("inserting '%s' %p into sc = %p\n", s->toChars(), s, sc); 7155 // Insert into both local scope and function scope. 7156 // Must be unique in both. 7157 if (s.ident) 7158 { 7159 if (!sc.insert(s)) 7160 { 7161 error("declaration %s is already defined", s.toPrettyChars()); 7162 return new ErrorExp(); 7163 } 7164 else if (sc.func) 7165 { 7166 // Bugzilla 11720 - include Dataseg variables 7167 if ((s.isFuncDeclaration() || 7168 s.isAggregateDeclaration() || 7169 s.isEnumDeclaration() || 7170 v && v.isDataseg()) && !sc.func.localsymtab.insert(s)) 7171 { 7172 error("declaration %s is already defined in another scope in %s", s.toPrettyChars(), sc.func.toChars()); 7173 return new ErrorExp(); 7174 } 7175 else 7176 { 7177 // Disallow shadowing 7178 for (Scope* scx = sc.enclosing; scx && scx.func == sc.func; scx = scx.enclosing) 7179 { 7180 Dsymbol s2; 7181 if (scx.scopesym && scx.scopesym.symtab && (s2 = scx.scopesym.symtab.lookup(s.ident)) !is null && s != s2) 7182 { 7183 error("%s %s is shadowing %s %s", s.kind(), s.ident.toChars(), s2.kind(), s2.toPrettyChars()); 7184 return new ErrorExp(); 7185 } 7186 } 7187 } 7188 } 7189 } 7190 if (!s.isVarDeclaration()) 7191 { 7192 Scope* sc2 = sc; 7193 if (sc2.stc & (STCpure | STCnothrow | STCnogc)) 7194 sc2 = sc.push(); 7195 sc2.stc &= ~(STCpure | STCnothrow | STCnogc); 7196 declaration.semantic(sc2); 7197 if (sc2 != sc) 7198 sc2.pop(); 7199 s.parent = sc.parent; 7200 } 7201 if (global.errors == olderrors) 7202 { 7203 declaration.semantic2(sc); 7204 if (global.errors == olderrors) 7205 { 7206 declaration.semantic3(sc); 7207 } 7208 } 7209 // todo: error in declaration should be propagated. 7210 7211 type = Type.tvoid; 7212 return this; 7213 } 7214 7215 override void accept(Visitor v) 7216 { 7217 v.visit(this); 7218 } 7219 } 7220 7221 /*********************************************************** 7222 * typeid(int) 7223 */ 7224 extern (C++) final class TypeidExp : Expression 7225 { 7226 RootObject obj; 7227 7228 extern (D) this(Loc loc, RootObject o) 7229 { 7230 super(loc, TOKtypeid, __traits(classInstanceSize, TypeidExp)); 7231 this.obj = o; 7232 } 7233 7234 override Expression syntaxCopy() 7235 { 7236 return new TypeidExp(loc, objectSyntaxCopy(obj)); 7237 } 7238 7239 override Expression semantic(Scope* sc) 7240 { 7241 static if (LOGSEMANTIC) 7242 { 7243 printf("TypeidExp::semantic() %s\n", toChars()); 7244 } 7245 Type ta = isType(obj); 7246 Expression ea = isExpression(obj); 7247 Dsymbol sa = isDsymbol(obj); 7248 //printf("ta %p ea %p sa %p\n", ta, ea, sa); 7249 7250 if (ta) 7251 { 7252 ta.resolve(loc, sc, &ea, &ta, &sa, true); 7253 } 7254 7255 if (ea) 7256 { 7257 if (auto sym = getDsymbol(ea)) 7258 ea = DsymbolExp.resolve(loc, sc, sym, false); 7259 else 7260 ea = ea.semantic(sc); 7261 ea = resolveProperties(sc, ea); 7262 ta = ea.type; 7263 if (ea.op == TOKtype) 7264 ea = null; 7265 } 7266 7267 if (!ta) 7268 { 7269 //printf("ta %p ea %p sa %p\n", ta, ea, sa); 7270 error("no type for typeid(%s)", ea ? ea.toChars() : (sa ? sa.toChars() : "")); 7271 return new ErrorExp(); 7272 } 7273 7274 if (global.params.vcomplex) 7275 ta.checkComplexTransition(loc); 7276 7277 Expression e; 7278 if (ea && ta.toBasetype().ty == Tclass) 7279 { 7280 /* Get the dynamic type, which is .classinfo 7281 */ 7282 ea = ea.semantic(sc); 7283 e = new TypeidExp(ea.loc, ea); 7284 e.type = Type.typeinfoclass.type; 7285 } 7286 else if (ta.ty == Terror) 7287 { 7288 e = new ErrorExp(); 7289 } 7290 else 7291 { 7292 // Handle this in the glue layer 7293 e = new TypeidExp(loc, ta); 7294 e.type = getTypeInfoType(ta, sc); 7295 7296 semanticTypeInfo(sc, ta); 7297 7298 if (ea) 7299 { 7300 e = new CommaExp(loc, ea, e); // execute ea 7301 e = e.semantic(sc); 7302 } 7303 } 7304 return e; 7305 } 7306 7307 override void accept(Visitor v) 7308 { 7309 v.visit(this); 7310 } 7311 } 7312 7313 /*********************************************************** 7314 * __traits(identifier, args...) 7315 */ 7316 extern (C++) final class TraitsExp : Expression 7317 { 7318 Identifier ident; 7319 Objects* args; 7320 7321 extern (D) this(Loc loc, Identifier ident, Objects* args) 7322 { 7323 super(loc, TOKtraits, __traits(classInstanceSize, TraitsExp)); 7324 this.ident = ident; 7325 this.args = args; 7326 } 7327 7328 override Expression syntaxCopy() 7329 { 7330 return new TraitsExp(loc, ident, TemplateInstance.arraySyntaxCopy(args)); 7331 } 7332 7333 override Expression semantic(Scope* sc) 7334 { 7335 return semanticTraits(this, sc); 7336 } 7337 7338 override void accept(Visitor v) 7339 { 7340 v.visit(this); 7341 } 7342 } 7343 7344 /*********************************************************** 7345 */ 7346 extern (C++) final class HaltExp : Expression 7347 { 7348 extern (D) this(Loc loc) 7349 { 7350 super(loc, TOKhalt, __traits(classInstanceSize, HaltExp)); 7351 } 7352 7353 override Expression semantic(Scope* sc) 7354 { 7355 static if (LOGSEMANTIC) 7356 { 7357 printf("HaltExp::semantic()\n"); 7358 } 7359 type = Type.tvoid; 7360 return this; 7361 } 7362 7363 override void accept(Visitor v) 7364 { 7365 v.visit(this); 7366 } 7367 } 7368 7369 /*********************************************************** 7370 * is(targ id tok tspec) 7371 * is(targ id == tok2) 7372 */ 7373 extern (C++) final class IsExp : Expression 7374 { 7375 Type targ; 7376 Identifier id; // can be null 7377 TOK tok; // ':' or '==' 7378 Type tspec; // can be null 7379 TOK tok2; // 'struct', 'union', etc. 7380 TemplateParameters* parameters; 7381 7382 extern (D) this(Loc loc, Type targ, Identifier id, TOK tok, Type tspec, TOK tok2, TemplateParameters* parameters) 7383 { 7384 super(loc, TOKis, __traits(classInstanceSize, IsExp)); 7385 this.targ = targ; 7386 this.id = id; 7387 this.tok = tok; 7388 this.tspec = tspec; 7389 this.tok2 = tok2; 7390 this.parameters = parameters; 7391 } 7392 7393 override Expression syntaxCopy() 7394 { 7395 // This section is identical to that in TemplateDeclaration::syntaxCopy() 7396 TemplateParameters* p = null; 7397 if (parameters) 7398 { 7399 p = new TemplateParameters(); 7400 p.setDim(parameters.dim); 7401 for (size_t i = 0; i < p.dim; i++) 7402 (*p)[i] = (*parameters)[i].syntaxCopy(); 7403 } 7404 return new IsExp(loc, targ.syntaxCopy(), id, tok, tspec ? tspec.syntaxCopy() : null, tok2, p); 7405 } 7406 7407 override Expression semantic(Scope* sc) 7408 { 7409 /* is(targ id tok tspec) 7410 * is(targ id : tok2) 7411 * is(targ id == tok2) 7412 */ 7413 7414 //printf("IsExp::semantic(%s)\n", toChars()); 7415 if (id && !(sc.flags & SCOPEcondition)) 7416 { 7417 error("can only declare type aliases within static if conditionals or static asserts"); 7418 return new ErrorExp(); 7419 } 7420 7421 Type tded = null; 7422 Scope* sc2 = sc.copy(); // keep sc->flags 7423 sc2.tinst = null; 7424 sc2.minst = null; 7425 sc2.flags |= SCOPEfullinst; 7426 Type t = targ.trySemantic(loc, sc2); 7427 sc2.pop(); 7428 if (!t) 7429 goto Lno; 7430 // errors, so condition is false 7431 targ = t; 7432 if (tok2 != TOKreserved) 7433 { 7434 switch (tok2) 7435 { 7436 case TOKstruct: 7437 if (targ.ty != Tstruct) 7438 goto Lno; 7439 if ((cast(TypeStruct)targ).sym.isUnionDeclaration()) 7440 goto Lno; 7441 tded = targ; 7442 break; 7443 7444 case TOKunion: 7445 if (targ.ty != Tstruct) 7446 goto Lno; 7447 if (!(cast(TypeStruct)targ).sym.isUnionDeclaration()) 7448 goto Lno; 7449 tded = targ; 7450 break; 7451 7452 case TOKclass: 7453 if (targ.ty != Tclass) 7454 goto Lno; 7455 if ((cast(TypeClass)targ).sym.isInterfaceDeclaration()) 7456 goto Lno; 7457 tded = targ; 7458 break; 7459 7460 case TOKinterface: 7461 if (targ.ty != Tclass) 7462 goto Lno; 7463 if (!(cast(TypeClass)targ).sym.isInterfaceDeclaration()) 7464 goto Lno; 7465 tded = targ; 7466 break; 7467 7468 case TOKconst: 7469 if (!targ.isConst()) 7470 goto Lno; 7471 tded = targ; 7472 break; 7473 7474 case TOKimmutable: 7475 if (!targ.isImmutable()) 7476 goto Lno; 7477 tded = targ; 7478 break; 7479 7480 case TOKshared: 7481 if (!targ.isShared()) 7482 goto Lno; 7483 tded = targ; 7484 break; 7485 7486 case TOKwild: 7487 if (!targ.isWild()) 7488 goto Lno; 7489 tded = targ; 7490 break; 7491 7492 case TOKsuper: 7493 // If class or interface, get the base class and interfaces 7494 if (targ.ty != Tclass) 7495 goto Lno; 7496 else 7497 { 7498 ClassDeclaration cd = (cast(TypeClass)targ).sym; 7499 auto args = new Parameters(); 7500 args.reserve(cd.baseclasses.dim); 7501 if (cd._scope && !cd.symtab) 7502 cd.semantic(cd._scope); 7503 for (size_t i = 0; i < cd.baseclasses.dim; i++) 7504 { 7505 BaseClass* b = (*cd.baseclasses)[i]; 7506 args.push(new Parameter(STCin, b.type, null, null)); 7507 } 7508 tded = new TypeTuple(args); 7509 } 7510 break; 7511 7512 case TOKenum: 7513 if (targ.ty != Tenum) 7514 goto Lno; 7515 if (id) 7516 tded = (cast(TypeEnum)targ).sym.getMemtype(loc); 7517 else 7518 tded = targ; 7519 if (tded.ty == Terror) 7520 return new ErrorExp(); 7521 break; 7522 7523 case TOKdelegate: 7524 if (targ.ty != Tdelegate) 7525 goto Lno; 7526 tded = (cast(TypeDelegate)targ).next; // the underlying function type 7527 break; 7528 7529 case TOKfunction: 7530 case TOKparameters: 7531 { 7532 if (targ.ty != Tfunction) 7533 goto Lno; 7534 tded = targ; 7535 7536 /* Generate tuple from function parameter types. 7537 */ 7538 assert(tded.ty == Tfunction); 7539 Parameters* params = (cast(TypeFunction)tded).parameters; 7540 size_t dim = Parameter.dim(params); 7541 auto args = new Parameters(); 7542 args.reserve(dim); 7543 for (size_t i = 0; i < dim; i++) 7544 { 7545 Parameter arg = Parameter.getNth(params, i); 7546 assert(arg && arg.type); 7547 /* If one of the default arguments was an error, 7548 don't return an invalid tuple 7549 */ 7550 if (tok2 == TOKparameters && arg.defaultArg && arg.defaultArg.op == TOKerror) 7551 return new ErrorExp(); 7552 args.push(new Parameter(arg.storageClass, arg.type, (tok2 == TOKparameters) ? arg.ident : null, (tok2 == TOKparameters) ? arg.defaultArg : null)); 7553 } 7554 tded = new TypeTuple(args); 7555 break; 7556 } 7557 case TOKreturn: 7558 /* Get the 'return type' for the function, 7559 * delegate, or pointer to function. 7560 */ 7561 if (targ.ty == Tfunction) 7562 tded = (cast(TypeFunction)targ).next; 7563 else if (targ.ty == Tdelegate) 7564 { 7565 tded = (cast(TypeDelegate)targ).next; 7566 tded = (cast(TypeFunction)tded).next; 7567 } 7568 else if (targ.ty == Tpointer && (cast(TypePointer)targ).next.ty == Tfunction) 7569 { 7570 tded = (cast(TypePointer)targ).next; 7571 tded = (cast(TypeFunction)tded).next; 7572 } 7573 else 7574 goto Lno; 7575 break; 7576 7577 case TOKargTypes: 7578 /* Generate a type tuple of the equivalent types used to determine if a 7579 * function argument of this type can be passed in registers. 7580 * The results of this are highly platform dependent, and intended 7581 * primarly for use in implementing va_arg(). 7582 */ 7583 tded = toArgTypes(targ); 7584 if (!tded) 7585 goto Lno; 7586 // not valid for a parameter 7587 break; 7588 7589 default: 7590 assert(0); 7591 } 7592 goto Lyes; 7593 } 7594 else if (tspec && !id && !(parameters && parameters.dim)) 7595 { 7596 /* Evaluate to true if targ matches tspec 7597 * is(targ == tspec) 7598 * is(targ : tspec) 7599 */ 7600 tspec = tspec.semantic(loc, sc); 7601 //printf("targ = %s, %s\n", targ->toChars(), targ->deco); 7602 //printf("tspec = %s, %s\n", tspec->toChars(), tspec->deco); 7603 7604 if (tok == TOKcolon) 7605 { 7606 if (targ.implicitConvTo(tspec)) 7607 goto Lyes; 7608 else 7609 goto Lno; 7610 } 7611 else /* == */ 7612 { 7613 if (targ.equals(tspec)) 7614 goto Lyes; 7615 else 7616 goto Lno; 7617 } 7618 } 7619 else if (tspec) 7620 { 7621 /* Evaluate to true if targ matches tspec. 7622 * If true, declare id as an alias for the specialized type. 7623 * is(targ == tspec, tpl) 7624 * is(targ : tspec, tpl) 7625 * is(targ id == tspec) 7626 * is(targ id : tspec) 7627 * is(targ id == tspec, tpl) 7628 * is(targ id : tspec, tpl) 7629 */ 7630 Identifier tid = id ? id : Identifier.generateId("__isexp_id"); 7631 parameters.insert(0, new TemplateTypeParameter(loc, tid, null, null)); 7632 7633 Objects dedtypes; 7634 dedtypes.setDim(parameters.dim); 7635 dedtypes.zero(); 7636 7637 MATCH m = deduceType(targ, sc, tspec, parameters, &dedtypes); 7638 //printf("targ: %s\n", targ->toChars()); 7639 //printf("tspec: %s\n", tspec->toChars()); 7640 if (m <= MATCHnomatch || (m != MATCHexact && tok == TOKequal)) 7641 { 7642 goto Lno; 7643 } 7644 else 7645 { 7646 tded = cast(Type)dedtypes[0]; 7647 if (!tded) 7648 tded = targ; 7649 Objects tiargs; 7650 tiargs.setDim(1); 7651 tiargs[0] = targ; 7652 7653 /* Declare trailing parameters 7654 */ 7655 for (size_t i = 1; i < parameters.dim; i++) 7656 { 7657 TemplateParameter tp = (*parameters)[i]; 7658 Declaration s = null; 7659 7660 m = tp.matchArg(loc, sc, &tiargs, i, parameters, &dedtypes, &s); 7661 if (m <= MATCHnomatch) 7662 goto Lno; 7663 s.semantic(sc); 7664 if (sc.sds) 7665 s.addMember(sc, sc.sds); 7666 else if (!sc.insert(s)) 7667 error("declaration %s is already defined", s.toChars()); 7668 7669 unSpeculative(sc, s); 7670 } 7671 goto Lyes; 7672 } 7673 } 7674 else if (id) 7675 { 7676 /* Declare id as an alias for type targ. Evaluate to true 7677 * is(targ id) 7678 */ 7679 tded = targ; 7680 goto Lyes; 7681 } 7682 7683 Lyes: 7684 if (id) 7685 { 7686 Dsymbol s; 7687 Tuple tup = isTuple(tded); 7688 if (tup) 7689 s = new TupleDeclaration(loc, id, &tup.objects); 7690 else 7691 s = new AliasDeclaration(loc, id, tded); 7692 s.semantic(sc); 7693 7694 /* The reason for the !tup is unclear. It fails Phobos unittests if it is not there. 7695 * More investigation is needed. 7696 */ 7697 if (!tup && !sc.insert(s)) 7698 error("declaration %s is already defined", s.toChars()); 7699 if (sc.sds) 7700 s.addMember(sc, sc.sds); 7701 7702 unSpeculative(sc, s); 7703 } 7704 //printf("Lyes\n"); 7705 return new IntegerExp(loc, 1, Type.tbool); 7706 7707 Lno: 7708 //printf("Lno\n"); 7709 return new IntegerExp(loc, 0, Type.tbool); 7710 } 7711 7712 override void accept(Visitor v) 7713 { 7714 v.visit(this); 7715 } 7716 } 7717 7718 /*********************************************************** 7719 */ 7720 extern (C++) class UnaExp : Expression 7721 { 7722 Expression e1; 7723 Type att1; // Save alias this type to detect recursion 7724 7725 final extern (D) this(Loc loc, TOK op, int size, Expression e1) 7726 { 7727 super(loc, op, size); 7728 this.e1 = e1; 7729 } 7730 7731 override Expression syntaxCopy() 7732 { 7733 UnaExp e = cast(UnaExp)copy(); 7734 e.type = null; 7735 e.e1 = e.e1.syntaxCopy(); 7736 return e; 7737 } 7738 7739 override abstract Expression semantic(Scope* sc); 7740 7741 /************************** 7742 * Helper function for easy error propagation. 7743 * If error occurs, returns ErrorExp. Otherwise returns NULL. 7744 */ 7745 final Expression unaSemantic(Scope* sc) 7746 { 7747 static if (LOGSEMANTIC) 7748 { 7749 printf("UnaExp::semantic('%s')\n", toChars()); 7750 } 7751 Expression e1x = e1.semantic(sc); 7752 if (e1x.op == TOKerror) 7753 return e1x; 7754 e1 = e1x; 7755 return null; 7756 } 7757 7758 /********************* 7759 * Mark the operand as will never be dereferenced, 7760 * which is useful info for @safe checks. 7761 * Do before semantic() on operands rewrites them. 7762 */ 7763 final void setNoderefOperand() 7764 { 7765 if (e1.op == TOKdotid) 7766 (cast(DotIdExp)e1).noderef = true; 7767 7768 } 7769 7770 override final Expression resolveLoc(Loc loc, Scope* sc) 7771 { 7772 e1 = e1.resolveLoc(loc, sc); 7773 return this; 7774 } 7775 7776 override void accept(Visitor v) 7777 { 7778 v.visit(this); 7779 } 7780 7781 override void printAST(int indent) 7782 { 7783 Expression.printAST(indent); 7784 e1.printAST(indent + 2); 7785 } 7786 } 7787 7788 extern (C++) alias fp_t = UnionExp function(Loc loc, Type, Expression, Expression); 7789 extern (C++) alias fp2_t = int function(Loc loc, TOK, Expression, Expression); 7790 7791 /*********************************************************** 7792 */ 7793 extern (C++) abstract class BinExp : Expression 7794 { 7795 Expression e1; 7796 Expression e2; 7797 Type att1; // Save alias this type to detect recursion 7798 Type att2; // Save alias this type to detect recursion 7799 7800 final extern (D) this(Loc loc, TOK op, int size, Expression e1, Expression e2) 7801 { 7802 super(loc, op, size); 7803 this.e1 = e1; 7804 this.e2 = e2; 7805 } 7806 7807 override Expression syntaxCopy() 7808 { 7809 BinExp e = cast(BinExp)copy(); 7810 e.type = null; 7811 e.e1 = e.e1.syntaxCopy(); 7812 e.e2 = e.e2.syntaxCopy(); 7813 return e; 7814 } 7815 7816 override abstract Expression semantic(Scope* sc); 7817 7818 /************************** 7819 * Helper function for easy error propagation. 7820 * If error occurs, returns ErrorExp. Otherwise returns NULL. 7821 */ 7822 final Expression binSemantic(Scope* sc) 7823 { 7824 static if (LOGSEMANTIC) 7825 { 7826 printf("BinExp::semantic('%s')\n", toChars()); 7827 } 7828 Expression e1x = e1.semantic(sc); 7829 Expression e2x = e2.semantic(sc); 7830 if (e1x.op == TOKerror) 7831 return e1x; 7832 if (e2x.op == TOKerror) 7833 return e2x; 7834 e1 = e1x; 7835 e2 = e2x; 7836 return null; 7837 } 7838 7839 final Expression binSemanticProp(Scope* sc) 7840 { 7841 if (Expression ex = binSemantic(sc)) 7842 return ex; 7843 Expression e1x = resolveProperties(sc, e1); 7844 Expression e2x = resolveProperties(sc, e2); 7845 if (e1x.op == TOKerror) 7846 return e1x; 7847 if (e2x.op == TOKerror) 7848 return e2x; 7849 e1 = e1x; 7850 e2 = e2x; 7851 return null; 7852 } 7853 7854 final Expression incompatibleTypes() 7855 { 7856 if (e1.type.toBasetype() != Type.terror && e2.type.toBasetype() != Type.terror) 7857 { 7858 // CondExp uses 'a ? b : c' but we're comparing 'b : c' 7859 TOK thisOp = (op == TOKquestion) ? TOKcolon : op; 7860 if (e1.op == TOKtype || e2.op == TOKtype) 7861 { 7862 error("incompatible types for ((%s) %s (%s)): cannot use '%s' with types", e1.toChars(), Token.toChars(thisOp), e2.toChars(), Token.toChars(op)); 7863 } 7864 else 7865 { 7866 error("incompatible types for ((%s) %s (%s)): '%s' and '%s'", e1.toChars(), Token.toChars(thisOp), e2.toChars(), e1.type.toChars(), e2.type.toChars()); 7867 } 7868 return new ErrorExp(); 7869 } 7870 return this; 7871 } 7872 7873 final Expression checkOpAssignTypes(Scope* sc) 7874 { 7875 // At that point t1 and t2 are the merged types. type is the original type of the lhs. 7876 Type t1 = e1.type; 7877 Type t2 = e2.type; 7878 7879 // T opAssign floating yields a floating. Prevent truncating conversions (float to int). 7880 // See issue 3841. 7881 // Should we also prevent double to float (type->isfloating() && type->size() < t2 ->size()) ? 7882 if (op == TOKaddass || op == TOKminass || 7883 op == TOKmulass || op == TOKdivass || op == TOKmodass || 7884 op == TOKpowass) 7885 { 7886 if ((type.isintegral() && t2.isfloating())) 7887 { 7888 warning("%s %s %s is performing truncating conversion", type.toChars(), Token.toChars(op), t2.toChars()); 7889 } 7890 } 7891 7892 // generate an error if this is a nonsensical *=,/=, or %=, eg real *= imaginary 7893 if (op == TOKmulass || op == TOKdivass || op == TOKmodass) 7894 { 7895 // Any multiplication by an imaginary or complex number yields a complex result. 7896 // r *= c, i*=c, r*=i, i*=i are all forbidden operations. 7897 const(char)* opstr = Token.toChars(op); 7898 if (t1.isreal() && t2.iscomplex()) 7899 { 7900 error("%s %s %s is undefined. Did you mean %s %s %s.re ?", t1.toChars(), opstr, t2.toChars(), t1.toChars(), opstr, t2.toChars()); 7901 return new ErrorExp(); 7902 } 7903 else if (t1.isimaginary() && t2.iscomplex()) 7904 { 7905 error("%s %s %s is undefined. Did you mean %s %s %s.im ?", t1.toChars(), opstr, t2.toChars(), t1.toChars(), opstr, t2.toChars()); 7906 return new ErrorExp(); 7907 } 7908 else if ((t1.isreal() || t1.isimaginary()) && t2.isimaginary()) 7909 { 7910 error("%s %s %s is an undefined operation", t1.toChars(), opstr, t2.toChars()); 7911 return new ErrorExp(); 7912 } 7913 } 7914 7915 // generate an error if this is a nonsensical += or -=, eg real += imaginary 7916 if (op == TOKaddass || op == TOKminass) 7917 { 7918 // Addition or subtraction of a real and an imaginary is a complex result. 7919 // Thus, r+=i, r+=c, i+=r, i+=c are all forbidden operations. 7920 if ((t1.isreal() && (t2.isimaginary() || t2.iscomplex())) || (t1.isimaginary() && (t2.isreal() || t2.iscomplex()))) 7921 { 7922 error("%s %s %s is undefined (result is complex)", t1.toChars(), Token.toChars(op), t2.toChars()); 7923 return new ErrorExp(); 7924 } 7925 if (type.isreal() || type.isimaginary()) 7926 { 7927 assert(global.errors || t2.isfloating()); 7928 e2 = e2.castTo(sc, t1); 7929 } 7930 } 7931 if (op == TOKmulass) 7932 { 7933 if (t2.isfloating()) 7934 { 7935 if (t1.isreal()) 7936 { 7937 if (t2.isimaginary() || t2.iscomplex()) 7938 { 7939 e2 = e2.castTo(sc, t1); 7940 } 7941 } 7942 else if (t1.isimaginary()) 7943 { 7944 if (t2.isimaginary() || t2.iscomplex()) 7945 { 7946 switch (t1.ty) 7947 { 7948 case Timaginary32: 7949 t2 = Type.tfloat32; 7950 break; 7951 7952 case Timaginary64: 7953 t2 = Type.tfloat64; 7954 break; 7955 7956 case Timaginary80: 7957 t2 = Type.tfloat80; 7958 break; 7959 7960 default: 7961 assert(0); 7962 } 7963 e2 = e2.castTo(sc, t2); 7964 } 7965 } 7966 } 7967 } 7968 else if (op == TOKdivass) 7969 { 7970 if (t2.isimaginary()) 7971 { 7972 if (t1.isreal()) 7973 { 7974 // x/iv = i(-x/v) 7975 // Therefore, the result is 0 7976 e2 = new CommaExp(loc, e2, new RealExp(loc, CTFloat.zero, t1)); 7977 e2.type = t1; 7978 Expression e = new AssignExp(loc, e1, e2); 7979 e.type = t1; 7980 return e; 7981 } 7982 else if (t1.isimaginary()) 7983 { 7984 Type t3; 7985 switch (t1.ty) 7986 { 7987 case Timaginary32: 7988 t3 = Type.tfloat32; 7989 break; 7990 7991 case Timaginary64: 7992 t3 = Type.tfloat64; 7993 break; 7994 7995 case Timaginary80: 7996 t3 = Type.tfloat80; 7997 break; 7998 7999 default: 8000 assert(0); 8001 } 8002 e2 = e2.castTo(sc, t3); 8003 Expression e = new AssignExp(loc, e1, e2); 8004 e.type = t1; 8005 return e; 8006 } 8007 } 8008 } 8009 else if (op == TOKmodass) 8010 { 8011 if (t2.iscomplex()) 8012 { 8013 error("cannot perform modulo complex arithmetic"); 8014 return new ErrorExp(); 8015 } 8016 } 8017 return this; 8018 } 8019 8020 final bool checkIntegralBin() 8021 { 8022 bool r1 = e1.checkIntegral(); 8023 bool r2 = e2.checkIntegral(); 8024 return (r1 || r2); 8025 } 8026 8027 final bool checkArithmeticBin() 8028 { 8029 bool r1 = e1.checkArithmetic(); 8030 bool r2 = e2.checkArithmetic(); 8031 return (r1 || r2); 8032 } 8033 8034 /********************* 8035 * Mark the operands as will never be dereferenced, 8036 * which is useful info for @safe checks. 8037 * Do before semantic() on operands rewrites them. 8038 */ 8039 final void setNoderefOperands() 8040 { 8041 if (e1.op == TOKdotid) 8042 (cast(DotIdExp)e1).noderef = true; 8043 if (e2.op == TOKdotid) 8044 (cast(DotIdExp)e2).noderef = true; 8045 8046 } 8047 8048 final Expression reorderSettingAAElem(Scope* sc) 8049 { 8050 BinExp be = this; 8051 8052 if (be.e1.op != TOKindex) 8053 return be; 8054 auto ie = cast(IndexExp)be.e1; 8055 if (ie.e1.type.toBasetype().ty != Taarray) 8056 return be; 8057 8058 /* Fix evaluation order of setting AA element. (Bugzilla 3825) 8059 * Rewrite: 8060 * aa[k1][k2][k3] op= val; 8061 * as: 8062 * auto ref __aatmp = aa; 8063 * auto ref __aakey3 = k1, __aakey2 = k2, __aakey1 = k3; 8064 * auto ref __aaval = val; 8065 * __aatmp[__aakey3][__aakey2][__aakey1] op= __aaval; // assignment 8066 */ 8067 8068 Expression e0; 8069 while (1) 8070 { 8071 Expression de; 8072 ie.e2 = extractSideEffect(sc, "__aakey", de, ie.e2); 8073 e0 = Expression.combine(de, e0); 8074 8075 Expression ie1 = ie.e1; 8076 if (ie1.op != TOKindex || 8077 (cast(IndexExp)ie1).e1.type.toBasetype().ty != Taarray) 8078 { 8079 break; 8080 } 8081 ie = cast(IndexExp)ie1; 8082 } 8083 assert(ie.e1.type.toBasetype().ty == Taarray); 8084 8085 Expression de; 8086 ie.e1 = extractSideEffect(sc, "__aatmp", de, ie.e1); 8087 e0 = Expression.combine(de, e0); 8088 8089 be.e2 = extractSideEffect(sc, "__aaval", e0, be.e2, true); 8090 8091 //printf("-e0 = %s, be = %s\n", e0.toChars(), be.toChars()); 8092 return Expression.combine(e0, be); 8093 } 8094 8095 override void accept(Visitor v) 8096 { 8097 v.visit(this); 8098 } 8099 8100 override void printAST(int indent) 8101 { 8102 Expression.printAST(indent); 8103 e1.printAST(indent + 2); 8104 e2.printAST(indent + 2); 8105 } 8106 } 8107 8108 /*********************************************************** 8109 */ 8110 extern (C++) class BinAssignExp : BinExp 8111 { 8112 final extern (D) this(Loc loc, TOK op, int size, Expression e1, Expression e2) 8113 { 8114 super(loc, op, size, e1, e2); 8115 } 8116 8117 override Expression semantic(Scope* sc) 8118 { 8119 if (type) 8120 return this; 8121 8122 Expression e = op_overload(sc); 8123 if (e) 8124 return e; 8125 8126 if (e1.checkReadModifyWrite(op, e2)) 8127 return new ErrorExp(); 8128 8129 if (e1.op == TOKarraylength) 8130 { 8131 // arr.length op= e2; 8132 e = ArrayLengthExp.rewriteOpAssign(this); 8133 e = e.semantic(sc); 8134 return e; 8135 } 8136 if (e1.op == TOKslice || e1.type.ty == Tarray || e1.type.ty == Tsarray) 8137 { 8138 // T[] op= ... 8139 if (e2.implicitConvTo(e1.type.nextOf())) 8140 { 8141 // T[] op= T 8142 e2 = e2.castTo(sc, e1.type.nextOf()); 8143 } 8144 else if (Expression ex = typeCombine(this, sc)) 8145 return ex; 8146 type = e1.type; 8147 return arrayOp(this, sc); 8148 } 8149 8150 e1 = e1.semantic(sc); 8151 e1 = e1.optimize(WANTvalue); 8152 e1 = e1.modifiableLvalue(sc, e1); 8153 type = e1.type; 8154 if (checkScalar()) 8155 return new ErrorExp(); 8156 8157 int arith = (op == TOKaddass || op == TOKminass || op == TOKmulass || op == TOKdivass || op == TOKmodass || op == TOKpowass); 8158 int bitwise = (op == TOKandass || op == TOKorass || op == TOKxorass); 8159 int shift = (op == TOKshlass || op == TOKshrass || op == TOKushrass); 8160 8161 if (bitwise && type.toBasetype().ty == Tbool) 8162 e2 = e2.implicitCastTo(sc, type); 8163 else if (checkNoBool()) 8164 return new ErrorExp(); 8165 8166 if ((op == TOKaddass || op == TOKminass) && e1.type.toBasetype().ty == Tpointer && e2.type.toBasetype().isintegral()) 8167 return scaleFactor(this, sc); 8168 8169 if (Expression ex = typeCombine(this, sc)) 8170 return ex; 8171 8172 if (arith && checkArithmeticBin()) 8173 return new ErrorExp(); 8174 if ((bitwise || shift) && checkIntegralBin()) 8175 return new ErrorExp(); 8176 if (shift) 8177 { 8178 e2 = e2.castTo(sc, Type.tshiftcnt); 8179 } 8180 8181 // vectors 8182 if (shift && (e1.type.toBasetype().ty == Tvector || e2.type.toBasetype().ty == Tvector)) 8183 return incompatibleTypes(); 8184 8185 int isvector = type.toBasetype().ty == Tvector; 8186 8187 if (op == TOKmulass && isvector && !e2.type.isfloating() && (cast(TypeVector)type.toBasetype()).elementType().size(loc) != 2) 8188 return incompatibleTypes(); // Only short[8] and ushort[8] work with multiply 8189 8190 if (op == TOKdivass && isvector && !e1.type.isfloating()) 8191 return incompatibleTypes(); 8192 8193 if (op == TOKmodass && isvector) 8194 return incompatibleTypes(); 8195 8196 if (e1.op == TOKerror || e2.op == TOKerror) 8197 return new ErrorExp(); 8198 8199 e = checkOpAssignTypes(sc); 8200 if (e.op == TOKerror) 8201 return e; 8202 8203 assert(e.op == TOKassign || e == this); 8204 return (cast(BinExp)e).reorderSettingAAElem(sc); 8205 } 8206 8207 override final bool isLvalue() 8208 { 8209 return true; 8210 } 8211 8212 override final Expression toLvalue(Scope* sc, Expression ex) 8213 { 8214 // Lvalue-ness will be handled in glue layer. 8215 return this; 8216 } 8217 8218 override final Expression modifiableLvalue(Scope* sc, Expression e) 8219 { 8220 // should check e1->checkModifiable() ? 8221 return toLvalue(sc, this); 8222 } 8223 8224 override void accept(Visitor v) 8225 { 8226 v.visit(this); 8227 } 8228 } 8229 8230 /*********************************************************** 8231 */ 8232 extern (C++) final class CompileExp : UnaExp 8233 { 8234 extern (D) this(Loc loc, Expression e) 8235 { 8236 super(loc, TOKmixin, __traits(classInstanceSize, CompileExp), e); 8237 } 8238 8239 override Expression semantic(Scope* sc) 8240 { 8241 static if (LOGSEMANTIC) 8242 { 8243 printf("CompileExp::semantic('%s')\n", toChars()); 8244 } 8245 8246 auto se = semanticString(sc, e1, "argument to mixin"); 8247 if (!se) 8248 return new ErrorExp(); 8249 se = se.toUTF8(sc); 8250 8251 uint errors = global.errors; 8252 scope Parser p = new Parser(loc, sc._module, se.toStringz(), false); 8253 p.nextToken(); 8254 //printf("p.loc.linnum = %d\n", p.loc.linnum); 8255 8256 Expression e = p.parseExpression(); 8257 if (p.errors) 8258 { 8259 assert(global.errors != errors); // should have caught all these cases 8260 return new ErrorExp(); 8261 } 8262 if (p.token.value != TOKeof) 8263 { 8264 error("incomplete mixin expression (%s)", se.toChars()); 8265 return new ErrorExp(); 8266 } 8267 8268 return e.semantic(sc); 8269 } 8270 8271 override void accept(Visitor v) 8272 { 8273 v.visit(this); 8274 } 8275 } 8276 8277 /*********************************************************** 8278 */ 8279 extern (C++) final class ImportExp : UnaExp 8280 { 8281 extern (D) this(Loc loc, Expression e) 8282 { 8283 super(loc, TOKimport, __traits(classInstanceSize, ImportExp), e); 8284 } 8285 8286 override Expression semantic(Scope* sc) 8287 { 8288 static if (LOGSEMANTIC) 8289 { 8290 printf("ImportExp::semantic('%s')\n", toChars()); 8291 } 8292 8293 auto se = semanticString(sc, e1, "file name argument"); 8294 if (!se) 8295 return new ErrorExp(); 8296 se = se.toUTF8(sc); 8297 8298 auto namez = se.toStringz().ptr; 8299 if (!global.params.fileImppath) 8300 { 8301 error("need -Jpath switch to import text file %s", namez); 8302 return new ErrorExp(); 8303 } 8304 8305 /* Be wary of CWE-22: Improper Limitation of a Pathname to a Restricted Directory 8306 * ('Path Traversal') attacks. 8307 * http://cwe.mitre.org/data/definitions/22.html 8308 */ 8309 8310 auto name = FileName.safeSearchPath(global.filePath, namez); 8311 if (!name) 8312 { 8313 error("file %s cannot be found or not in a path specified with -J", se.toChars()); 8314 return new ErrorExp(); 8315 } 8316 8317 if (global.params.verbose) 8318 fprintf(global.stdmsg, "file %.*s\t(%s)\n", cast(int)se.len, se..string, name); 8319 if (global.params.moduleDeps !is null) 8320 { 8321 OutBuffer* ob = global.params.moduleDeps; 8322 Module imod = sc.instantiatingModule(); 8323 8324 if (!global.params.moduleDepsFile) 8325 ob.writestring("depsFile "); 8326 ob.writestring(imod.toPrettyChars()); 8327 ob.writestring(" ("); 8328 escapePath(ob, imod.srcfile.toChars()); 8329 ob.writestring(") : "); 8330 if (global.params.moduleDepsFile) 8331 ob.writestring("string : "); 8332 ob.write(se..string, se.len); 8333 ob.writestring(" ("); 8334 escapePath(ob, name); 8335 ob.writestring(")"); 8336 ob.writenl(); 8337 } 8338 8339 { 8340 auto f = File(name); 8341 if (f.read()) 8342 { 8343 error("cannot read file %s", f.toChars()); 8344 return new ErrorExp(); 8345 } 8346 else 8347 { 8348 f._ref = 1; 8349 se = new StringExp(loc, f.buffer, f.len); 8350 } 8351 } 8352 return se.semantic(sc); 8353 } 8354 8355 override void accept(Visitor v) 8356 { 8357 v.visit(this); 8358 } 8359 } 8360 8361 /*********************************************************** 8362 */ 8363 extern (C++) final class AssertExp : UnaExp 8364 { 8365 Expression msg; 8366 8367 extern (D) this(Loc loc, Expression e, Expression msg = null) 8368 { 8369 super(loc, TOKassert, __traits(classInstanceSize, AssertExp), e); 8370 this.msg = msg; 8371 } 8372 8373 override Expression syntaxCopy() 8374 { 8375 return new AssertExp(loc, e1.syntaxCopy(), msg ? msg.syntaxCopy() : null); 8376 } 8377 8378 override Expression semantic(Scope* sc) 8379 { 8380 static if (LOGSEMANTIC) 8381 { 8382 printf("AssertExp::semantic('%s')\n", toChars()); 8383 } 8384 8385 if (Expression ex = unaSemantic(sc)) 8386 return ex; 8387 e1 = resolveProperties(sc, e1); 8388 // BUG: see if we can do compile time elimination of the Assert 8389 e1 = e1.optimize(WANTvalue); 8390 e1 = e1.toBoolean(sc); 8391 8392 if (msg) 8393 { 8394 msg = msg.semantic(sc); 8395 msg = resolveProperties(sc, msg); 8396 msg = msg.implicitCastTo(sc, Type.tchar.constOf().arrayOf()); 8397 msg = msg.optimize(WANTvalue); 8398 } 8399 8400 if (e1.op == TOKerror) 8401 return e1; 8402 if (msg && msg.op == TOKerror) 8403 return msg; 8404 8405 auto f1 = checkNonAssignmentArrayOp(e1); 8406 auto f2 = msg && checkNonAssignmentArrayOp(msg); 8407 if (f1 || f2) 8408 return new ErrorExp(); 8409 8410 if (e1.isBool(false)) 8411 { 8412 FuncDeclaration fd = sc.parent.isFuncDeclaration(); 8413 if (fd) 8414 fd.hasReturnExp |= 4; 8415 sc.callSuper |= CSXhalt; 8416 if (sc.fieldinit) 8417 { 8418 for (size_t i = 0; i < sc.fieldinit_dim; i++) 8419 sc.fieldinit[i] |= CSXhalt; 8420 } 8421 8422 if (!global.params.useAssert) 8423 { 8424 Expression e = new HaltExp(loc); 8425 e = e.semantic(sc); 8426 return e; 8427 } 8428 } 8429 type = Type.tvoid; 8430 return this; 8431 } 8432 8433 override void accept(Visitor v) 8434 { 8435 v.visit(this); 8436 } 8437 } 8438 8439 /*********************************************************** 8440 */ 8441 extern (C++) final class DotIdExp : UnaExp 8442 { 8443 Identifier ident; 8444 bool noderef; // true if the result of the expression will never be dereferenced 8445 8446 extern (D) this(Loc loc, Expression e, Identifier ident) 8447 { 8448 super(loc, TOKdotid, __traits(classInstanceSize, DotIdExp), e); 8449 this.ident = ident; 8450 } 8451 8452 static DotIdExp create(Loc loc, Expression e, Identifier ident) 8453 { 8454 return new DotIdExp(loc, e, ident); 8455 } 8456 8457 override Expression semantic(Scope* sc) 8458 { 8459 static if (LOGSEMANTIC) 8460 { 8461 printf("DotIdExp::semantic(this = %p, '%s')\n", this, toChars()); 8462 //printf("e1->op = %d, '%s'\n", e1->op, Token::toChars(e1->op)); 8463 } 8464 Expression e = semanticY(sc, 1); 8465 if (e && isDotOpDispatch(e)) 8466 { 8467 uint errors = global.startGagging(); 8468 e = resolvePropertiesX(sc, e); 8469 if (global.endGagging(errors)) 8470 e = null; /* fall down to UFCS */ 8471 else 8472 return e; 8473 } 8474 if (!e) // if failed to find the property 8475 { 8476 /* If ident is not a valid property, rewrite: 8477 * e1.ident 8478 * as: 8479 * .ident(e1) 8480 */ 8481 e = resolveUFCSProperties(sc, this); 8482 } 8483 return e; 8484 } 8485 8486 // Run semantic in e1 8487 Expression semanticX(Scope* sc) 8488 { 8489 //printf("DotIdExp::semanticX(this = %p, '%s')\n", this, toChars()); 8490 if (Expression ex = unaSemantic(sc)) 8491 return ex; 8492 8493 if (ident == Id._mangleof) 8494 { 8495 // symbol.mangleof 8496 Dsymbol ds; 8497 switch (e1.op) 8498 { 8499 case TOKscope: 8500 ds = (cast(ScopeExp)e1).sds; 8501 goto L1; 8502 case TOKvar: 8503 ds = (cast(VarExp)e1).var; 8504 goto L1; 8505 case TOKdotvar: 8506 ds = (cast(DotVarExp)e1).var; 8507 goto L1; 8508 case TOKoverloadset: 8509 ds = (cast(OverExp)e1).vars; 8510 goto L1; 8511 case TOKtemplate: 8512 { 8513 TemplateExp te = cast(TemplateExp)e1; 8514 ds = te.fd ? cast(Dsymbol)te.fd : te.td; 8515 } 8516 L1: 8517 { 8518 assert(ds); 8519 if (auto f = ds.isFuncDeclaration()) 8520 { 8521 if (f.checkForwardRef(loc)) 8522 return new ErrorExp(); 8523 } 8524 OutBuffer buf; 8525 mangleToBuffer(ds, &buf); 8526 const s = buf.peekSlice(); 8527 Expression e = new StringExp(loc, buf.extractString(), s.length); 8528 e = e.semantic(sc); 8529 return e; 8530 } 8531 default: 8532 break; 8533 } 8534 } 8535 8536 if (e1.op == TOKvar && e1.type.toBasetype().ty == Tsarray && ident == Id.length) 8537 { 8538 // bypass checkPurity 8539 return e1.type.dotExp(sc, e1, ident, noderef ? Type.DotExpFlag.noDeref : 0); 8540 } 8541 8542 if (e1.op == TOKdot) 8543 { 8544 } 8545 else 8546 { 8547 e1 = resolvePropertiesX(sc, e1); 8548 } 8549 if (e1.op == TOKtuple && ident == Id.offsetof) 8550 { 8551 /* 'distribute' the .offsetof to each of the tuple elements. 8552 */ 8553 TupleExp te = cast(TupleExp)e1; 8554 auto exps = new Expressions(); 8555 exps.setDim(te.exps.dim); 8556 for (size_t i = 0; i < exps.dim; i++) 8557 { 8558 Expression e = (*te.exps)[i]; 8559 e = e.semantic(sc); 8560 e = new DotIdExp(e.loc, e, Id.offsetof); 8561 (*exps)[i] = e; 8562 } 8563 // Don't evaluate te->e0 in runtime 8564 Expression e = new TupleExp(loc, null, exps); 8565 e = e.semantic(sc); 8566 return e; 8567 } 8568 if (e1.op == TOKtuple && ident == Id.length) 8569 { 8570 TupleExp te = cast(TupleExp)e1; 8571 // Don't evaluate te->e0 in runtime 8572 Expression e = new IntegerExp(loc, te.exps.dim, Type.tsize_t); 8573 return e; 8574 } 8575 8576 // Bugzilla 14416: Template has no built-in properties except for 'stringof'. 8577 if ((e1.op == TOKdottd || e1.op == TOKtemplate) && ident != Id.stringof) 8578 { 8579 error("template %s does not have property '%s'", e1.toChars(), ident.toChars()); 8580 return new ErrorExp(); 8581 } 8582 if (!e1.type) 8583 { 8584 error("expression %s does not have property '%s'", e1.toChars(), ident.toChars()); 8585 return new ErrorExp(); 8586 } 8587 8588 return this; 8589 } 8590 8591 // Resolve e1.ident without seeing UFCS. 8592 // If flag == 1, stop "not a property" error and return NULL. 8593 Expression semanticY(Scope* sc, int flag) 8594 { 8595 //printf("DotIdExp::semanticY(this = %p, '%s')\n", this, toChars()); 8596 8597 //{ static int z; fflush(stdout); if (++z == 10) *(char*)0=0; } 8598 8599 /* Special case: rewrite this.id and super.id 8600 * to be classtype.id and baseclasstype.id 8601 * if we have no this pointer. 8602 */ 8603 if ((e1.op == TOKthis || e1.op == TOKsuper) && !hasThis(sc)) 8604 { 8605 if (AggregateDeclaration ad = sc.getStructClassScope()) 8606 { 8607 if (e1.op == TOKthis) 8608 { 8609 e1 = new TypeExp(e1.loc, ad.type); 8610 } 8611 else 8612 { 8613 ClassDeclaration cd = ad.isClassDeclaration(); 8614 if (cd && cd.baseClass) 8615 e1 = new TypeExp(e1.loc, cd.baseClass.type); 8616 } 8617 } 8618 } 8619 8620 Expression e = semanticX(sc); 8621 if (e != this) 8622 return e; 8623 8624 Expression eleft; 8625 Expression eright; 8626 if (e1.op == TOKdot) 8627 { 8628 DotExp de = cast(DotExp)e1; 8629 eleft = de.e1; 8630 eright = de.e2; 8631 } 8632 else 8633 { 8634 eleft = null; 8635 eright = e1; 8636 } 8637 8638 Type t1b = e1.type.toBasetype(); 8639 8640 if (eright.op == TOKscope) // also used for template alias's 8641 { 8642 ScopeExp ie = cast(ScopeExp)eright; 8643 8644 /* Disable access to another module's private imports. 8645 * The check for 'is sds our current module' is because 8646 * the current module should have access to its own imports. 8647 */ 8648 Dsymbol s = ie.sds.search(loc, ident, 8649 (ie.sds.isModule() && ie.sds != sc._module) ? IgnorePrivateImports | SearchLocalsOnly : SearchLocalsOnly); 8650 /* Check for visibility before resolving aliases because public 8651 * aliases to private symbols are public. 8652 */ 8653 if (s && !symbolIsVisible(sc._module, s)) 8654 { 8655 if (s.isDeclaration()) 8656 .error(loc, "%s is not visible from module %s", s.toPrettyChars(), sc._module.toChars()); 8657 else 8658 .deprecation(loc, "%s is not visible from module %s", s.toPrettyChars(), sc._module.toChars()); 8659 // s = null; 8660 } 8661 if (s) 8662 { 8663 if (auto p = s.isPackage()) 8664 checkAccess(loc, sc, p); 8665 8666 // if 's' is a tuple variable, the tuple is returned. 8667 s = s.toAlias(); 8668 8669 checkDeprecated(sc, s); 8670 8671 EnumMember em = s.isEnumMember(); 8672 if (em) 8673 { 8674 return em.getVarExp(loc, sc); 8675 } 8676 VarDeclaration v = s.isVarDeclaration(); 8677 if (v) 8678 { 8679 //printf("DotIdExp:: Identifier '%s' is a variable, type '%s'\n", toChars(), v->type->toChars()); 8680 if (!v.type || 8681 !v.type.deco && v.inuse) 8682 { 8683 if (v.inuse) 8684 error("circular reference to %s '%s'", v.kind(), v.toPrettyChars()); 8685 else 8686 error("forward reference to %s '%s'", v.kind(), v.toPrettyChars()); 8687 return new ErrorExp(); 8688 } 8689 if (v.type.ty == Terror) 8690 return new ErrorExp(); 8691 8692 if ((v.storage_class & STCmanifest) && v._init) 8693 { 8694 if (v.inuse) 8695 { 8696 .error(loc, "circular initialization of %s '%s'", v.kind(), v.toPrettyChars()); 8697 return new ErrorExp(); 8698 } 8699 e = v.expandInitializer(loc); 8700 v.inuse++; 8701 e = e.semantic(sc); 8702 v.inuse--; 8703 return e; 8704 } 8705 8706 if (v.needThis()) 8707 { 8708 if (!eleft) 8709 eleft = new ThisExp(loc); 8710 e = new DotVarExp(loc, eleft, v); 8711 e = e.semantic(sc); 8712 } 8713 else 8714 { 8715 e = new VarExp(loc, v); 8716 if (eleft) 8717 { 8718 e = new CommaExp(loc, eleft, e); 8719 e.type = v.type; 8720 } 8721 } 8722 e = e.deref(); 8723 return e.semantic(sc); 8724 } 8725 8726 FuncDeclaration f = s.isFuncDeclaration(); 8727 if (f) 8728 { 8729 //printf("it's a function\n"); 8730 if (!f.functionSemantic()) 8731 return new ErrorExp(); 8732 if (f.needThis()) 8733 { 8734 if (!eleft) 8735 eleft = new ThisExp(loc); 8736 e = new DotVarExp(loc, eleft, f, true); 8737 e = e.semantic(sc); 8738 } 8739 else 8740 { 8741 e = new VarExp(loc, f, true); 8742 if (eleft) 8743 { 8744 e = new CommaExp(loc, eleft, e); 8745 e.type = f.type; 8746 } 8747 } 8748 return e; 8749 } 8750 if (auto td = s.isTemplateDeclaration()) 8751 { 8752 if (eleft) 8753 e = new DotTemplateExp(loc, eleft, td); 8754 else 8755 e = new TemplateExp(loc, td); 8756 e = e.semantic(sc); 8757 return e; 8758 } 8759 if (OverDeclaration od = s.isOverDeclaration()) 8760 { 8761 e = new VarExp(loc, od, true); 8762 if (eleft) 8763 { 8764 e = new CommaExp(loc, eleft, e); 8765 e.type = Type.tvoid; // ambiguous type? 8766 } 8767 return e; 8768 } 8769 OverloadSet o = s.isOverloadSet(); 8770 if (o) 8771 { 8772 //printf("'%s' is an overload set\n", o->toChars()); 8773 return new OverExp(loc, o); 8774 } 8775 8776 if (auto t = s.getType()) 8777 { 8778 return (new TypeExp(loc, t)).semantic(sc); 8779 } 8780 8781 TupleDeclaration tup = s.isTupleDeclaration(); 8782 if (tup) 8783 { 8784 if (eleft) 8785 { 8786 e = new DotVarExp(loc, eleft, tup); 8787 e = e.semantic(sc); 8788 return e; 8789 } 8790 e = new TupleExp(loc, tup); 8791 e = e.semantic(sc); 8792 return e; 8793 } 8794 8795 ScopeDsymbol sds = s.isScopeDsymbol(); 8796 if (sds) 8797 { 8798 //printf("it's a ScopeDsymbol %s\n", ident->toChars()); 8799 e = new ScopeExp(loc, sds); 8800 e = e.semantic(sc); 8801 if (eleft) 8802 e = new DotExp(loc, eleft, e); 8803 return e; 8804 } 8805 8806 Import imp = s.isImport(); 8807 if (imp) 8808 { 8809 ie = new ScopeExp(loc, imp.pkg); 8810 return ie.semantic(sc); 8811 } 8812 // BUG: handle other cases like in IdentifierExp::semantic() 8813 debug 8814 { 8815 printf("s = '%s', kind = '%s'\n", s.toChars(), s.kind()); 8816 } 8817 assert(0); 8818 } 8819 else if (ident == Id.stringof) 8820 { 8821 const p = ie.toChars(); 8822 e = new StringExp(loc, cast(char*)p, strlen(p)); 8823 e = e.semantic(sc); 8824 return e; 8825 } 8826 if (ie.sds.isPackage() || ie.sds.isImport() || ie.sds.isModule()) 8827 { 8828 flag = 0; 8829 } 8830 if (flag) 8831 return null; 8832 s = ie.sds.search_correct(ident); 8833 if (s) 8834 error("undefined identifier '%s' in %s '%s', did you mean %s '%s'?", ident.toChars(), ie.sds.kind(), ie.sds.toPrettyChars(), s.kind(), s.toChars()); 8835 else 8836 error("undefined identifier '%s' in %s '%s'", ident.toChars(), ie.sds.kind(), ie.sds.toPrettyChars()); 8837 return new ErrorExp(); 8838 } 8839 else if (t1b.ty == Tpointer && e1.type.ty != Tenum && ident != Id._init && ident != Id.__sizeof && ident != Id.__xalignof && ident != Id.offsetof && ident != Id._mangleof && ident != Id.stringof) 8840 { 8841 Type t1bn = t1b.nextOf(); 8842 if (flag) 8843 { 8844 AggregateDeclaration ad = isAggregate(t1bn); 8845 if (ad && !ad.members) // Bugzilla 11312 8846 return null; 8847 } 8848 8849 /* Rewrite: 8850 * p.ident 8851 * as: 8852 * (*p).ident 8853 */ 8854 if (flag && t1bn.ty == Tvoid) 8855 return null; 8856 e = new PtrExp(loc, e1); 8857 e = e.semantic(sc); 8858 return e.type.dotExp(sc, e, ident, flag | (noderef ? Type.DotExpFlag.noDeref : 0)); 8859 } 8860 else 8861 { 8862 if (e1.op == TOKtype || e1.op == TOKtemplate) 8863 flag = 0; 8864 e = e1.type.dotExp(sc, e1, ident, flag | (noderef ? Type.DotExpFlag.noDeref : 0)); 8865 if (!flag || e) 8866 e = e.semantic(sc); 8867 return e; 8868 } 8869 } 8870 8871 override void accept(Visitor v) 8872 { 8873 v.visit(this); 8874 } 8875 } 8876 8877 /*********************************************************** 8878 * Mainly just a placeholder 8879 */ 8880 extern (C++) final class DotTemplateExp : UnaExp 8881 { 8882 TemplateDeclaration td; 8883 8884 extern (D) this(Loc loc, Expression e, TemplateDeclaration td) 8885 { 8886 super(loc, TOKdottd, __traits(classInstanceSize, DotTemplateExp), e); 8887 this.td = td; 8888 } 8889 8890 override Expression semantic(Scope* sc) 8891 { 8892 if (Expression ex = unaSemantic(sc)) 8893 return ex; 8894 return this; 8895 } 8896 8897 override void accept(Visitor v) 8898 { 8899 v.visit(this); 8900 } 8901 } 8902 8903 /*********************************************************** 8904 */ 8905 extern (C++) final class DotVarExp : UnaExp 8906 { 8907 Declaration var; 8908 bool hasOverloads; 8909 8910 extern (D) this(Loc loc, Expression e, Declaration var, bool hasOverloads = true) 8911 { 8912 if (var.isVarDeclaration()) 8913 hasOverloads = false; 8914 8915 super(loc, TOKdotvar, __traits(classInstanceSize, DotVarExp), e); 8916 //printf("DotVarExp()\n"); 8917 this.var = var; 8918 this.hasOverloads = hasOverloads; 8919 } 8920 8921 override Expression semantic(Scope* sc) 8922 { 8923 static if (LOGSEMANTIC) 8924 { 8925 printf("DotVarExp::semantic('%s')\n", toChars()); 8926 } 8927 if (type) 8928 return this; 8929 8930 var = var.toAlias().isDeclaration(); 8931 8932 e1 = e1.semantic(sc); 8933 8934 if (auto tup = var.isTupleDeclaration()) 8935 { 8936 /* Replace: 8937 * e1.tuple(a, b, c) 8938 * with: 8939 * tuple(e1.a, e1.b, e1.c) 8940 */ 8941 Expression e0; 8942 Expression ev = extractSideEffect(sc, "__tup", e0, e1); 8943 8944 auto exps = new Expressions(); 8945 exps.reserve(tup.objects.dim); 8946 for (size_t i = 0; i < tup.objects.dim; i++) 8947 { 8948 RootObject o = (*tup.objects)[i]; 8949 Expression e; 8950 if (o.dyncast() == DYNCAST_EXPRESSION) 8951 { 8952 e = cast(Expression)o; 8953 if (e.op == TOKdsymbol) 8954 { 8955 Dsymbol s = (cast(DsymbolExp)e).s; 8956 e = new DotVarExp(loc, ev, s.isDeclaration()); 8957 } 8958 } 8959 else if (o.dyncast() == DYNCAST_DSYMBOL) 8960 { 8961 e = new DsymbolExp(loc, cast(Dsymbol)o); 8962 } 8963 else if (o.dyncast() == DYNCAST_TYPE) 8964 { 8965 e = new TypeExp(loc, cast(Type)o); 8966 } 8967 else 8968 { 8969 error("%s is not an expression", o.toChars()); 8970 return new ErrorExp(); 8971 } 8972 exps.push(e); 8973 } 8974 8975 Expression e = new TupleExp(loc, e0, exps); 8976 e = e.semantic(sc); 8977 return e; 8978 } 8979 8980 e1 = e1.addDtorHook(sc); 8981 8982 Type t1 = e1.type; 8983 8984 if (FuncDeclaration fd = var.isFuncDeclaration()) 8985 { 8986 // for functions, do checks after overload resolution 8987 if (!fd.functionSemantic()) 8988 return new ErrorExp(); 8989 8990 /* Bugzilla 13843: If fd obviously has no overloads, we should 8991 * normalize AST, and it will give a chance to wrap fd with FuncExp. 8992 */ 8993 if (fd.isNested() || fd.isFuncLiteralDeclaration()) 8994 { 8995 // (e1, fd) 8996 auto e = DsymbolExp.resolve(loc, sc, fd, false); 8997 return Expression.combine(e1, e); 8998 } 8999 9000 type = fd.type; 9001 assert(type); 9002 } 9003 else if (OverDeclaration od = var.isOverDeclaration()) 9004 { 9005 type = Type.tvoid; // ambiguous type? 9006 } 9007 else 9008 { 9009 type = var.type; 9010 if (!type && global.errors) 9011 { 9012 // var is goofed up, just return 0 9013 return new ErrorExp(); 9014 } 9015 assert(type); 9016 9017 if (t1.ty == Tpointer) 9018 t1 = t1.nextOf(); 9019 9020 type = type.addMod(t1.mod); 9021 9022 Dsymbol vparent = var.toParent(); 9023 AggregateDeclaration ad = vparent ? vparent.isAggregateDeclaration() : null; 9024 if (Expression e1x = getRightThis(loc, sc, ad, e1, var, 1)) 9025 e1 = e1x; 9026 else 9027 { 9028 /* Later checkRightThis will report correct error for invalid field variable access. 9029 */ 9030 Expression e = new VarExp(loc, var); 9031 e = e.semantic(sc); 9032 return e; 9033 } 9034 checkAccess(loc, sc, e1, var); 9035 9036 VarDeclaration v = var.isVarDeclaration(); 9037 if (v && (v.isDataseg() || (v.storage_class & STCmanifest))) 9038 { 9039 Expression e = expandVar(WANTvalue, v); 9040 if (e) 9041 return e; 9042 } 9043 9044 if (v && v.isDataseg()) // fix bugzilla 8238 9045 { 9046 // (e1, v) 9047 checkAccess(loc, sc, e1, v); 9048 Expression e = new VarExp(loc, v); 9049 e = new CommaExp(loc, e1, e); 9050 e = e.semantic(sc); 9051 return e; 9052 } 9053 } 9054 //printf("-DotVarExp::semantic('%s')\n", toChars()); 9055 return this; 9056 } 9057 9058 override int checkModifiable(Scope* sc, int flag) 9059 { 9060 //printf("DotVarExp::checkModifiable %s %s\n", toChars(), type.toChars()); 9061 if (checkUnsafeAccess(sc, this, false, !flag)) 9062 return 2; 9063 9064 if (e1.op == TOKthis) 9065 return var.checkModify(loc, sc, type, e1, flag); 9066 9067 //printf("\te1 = %s\n", e1.toChars()); 9068 return e1.checkModifiable(sc, flag); 9069 } 9070 9071 bool checkReadModifyWrite(); 9072 9073 override bool isLvalue() 9074 { 9075 return true; 9076 } 9077 9078 override Expression toLvalue(Scope* sc, Expression e) 9079 { 9080 //printf("DotVarExp::toLvalue(%s)\n", toChars()); 9081 return this; 9082 } 9083 9084 override Expression modifiableLvalue(Scope* sc, Expression e) 9085 { 9086 version (none) 9087 { 9088 printf("DotVarExp::modifiableLvalue(%s)\n", toChars()); 9089 printf("e1->type = %s\n", e1.type.toChars()); 9090 printf("var->type = %s\n", var.type.toChars()); 9091 } 9092 9093 return Expression.modifiableLvalue(sc, e); 9094 } 9095 9096 override void accept(Visitor v) 9097 { 9098 v.visit(this); 9099 } 9100 } 9101 9102 /*********************************************************** 9103 * foo.bar!(args) 9104 */ 9105 extern (C++) final class DotTemplateInstanceExp : UnaExp 9106 { 9107 TemplateInstance ti; 9108 9109 extern (D) this(Loc loc, Expression e, Identifier name, Objects* tiargs) 9110 { 9111 super(loc, TOKdotti, __traits(classInstanceSize, DotTemplateInstanceExp), e); 9112 //printf("DotTemplateInstanceExp()\n"); 9113 this.ti = new TemplateInstance(loc, name, tiargs); 9114 } 9115 9116 extern (D) this(Loc loc, Expression e, TemplateInstance ti) 9117 { 9118 super(loc, TOKdotti, __traits(classInstanceSize, DotTemplateInstanceExp), e); 9119 this.ti = ti; 9120 } 9121 9122 override Expression syntaxCopy() 9123 { 9124 return new DotTemplateInstanceExp(loc, e1.syntaxCopy(), ti.name, TemplateInstance.arraySyntaxCopy(ti.tiargs)); 9125 } 9126 9127 bool findTempDecl(Scope* sc) 9128 { 9129 static if (LOGSEMANTIC) 9130 { 9131 printf("DotTemplateInstanceExp::findTempDecl('%s')\n", toChars()); 9132 } 9133 if (ti.tempdecl) 9134 return true; 9135 9136 Expression e = new DotIdExp(loc, e1, ti.name); 9137 e = e.semantic(sc); 9138 if (e.op == TOKdot) 9139 e = (cast(DotExp)e).e2; 9140 9141 Dsymbol s = null; 9142 switch (e.op) 9143 { 9144 case TOKoverloadset: 9145 s = (cast(OverExp)e).vars; 9146 break; 9147 9148 case TOKdottd: 9149 s = (cast(DotTemplateExp)e).td; 9150 break; 9151 9152 case TOKscope: 9153 s = (cast(ScopeExp)e).sds; 9154 break; 9155 9156 case TOKdotvar: 9157 s = (cast(DotVarExp)e).var; 9158 break; 9159 9160 case TOKvar: 9161 s = (cast(VarExp)e).var; 9162 break; 9163 9164 default: 9165 return false; 9166 } 9167 return ti.updateTempDecl(sc, s); 9168 } 9169 9170 override Expression semantic(Scope* sc) 9171 { 9172 static if (LOGSEMANTIC) 9173 { 9174 printf("DotTemplateInstanceExp::semantic('%s')\n", toChars()); 9175 } 9176 // Indicate we need to resolve by UFCS. 9177 Expression e = semanticY(sc, 1); 9178 if (!e) 9179 e = resolveUFCSProperties(sc, this); 9180 return e; 9181 } 9182 9183 // Resolve e1.ident!tiargs without seeing UFCS. 9184 // If flag == 1, stop "not a property" error and return NULL. 9185 Expression semanticY(Scope* sc, int flag) 9186 { 9187 static if (LOGSEMANTIC) 9188 { 9189 printf("DotTemplateInstanceExpY::semantic('%s')\n", toChars()); 9190 } 9191 9192 auto die = new DotIdExp(loc, e1, ti.name); 9193 9194 Expression e = die.semanticX(sc); 9195 if (e == die) 9196 { 9197 e1 = die.e1; // take back 9198 Type t1b = e1.type.toBasetype(); 9199 if (t1b.ty == Tarray || t1b.ty == Tsarray || t1b.ty == Taarray || t1b.ty == Tnull || (t1b.isTypeBasic() && t1b.ty != Tvoid)) 9200 { 9201 /* No built-in type has templatized properties, so do shortcut. 9202 * It is necessary in: 1024.max!"a < b" 9203 */ 9204 if (flag) 9205 return null; 9206 } 9207 e = die.semanticY(sc, flag); 9208 if (flag && e && isDotOpDispatch(e)) 9209 { 9210 /* opDispatch!tiargs would be a function template that needs IFTI, 9211 * so it's not a template 9212 */ 9213 e = null; /* fall down to UFCS */ 9214 } 9215 if (flag && !e) 9216 return null; 9217 } 9218 assert(e); 9219 9220 L1: 9221 if (e.op == TOKerror) 9222 return e; 9223 if (e.op == TOKdotvar) 9224 { 9225 DotVarExp dve = cast(DotVarExp)e; 9226 if (FuncDeclaration fd = dve.var.isFuncDeclaration()) 9227 { 9228 TemplateDeclaration td = fd.findTemplateDeclRoot(); 9229 if (td) 9230 { 9231 e = new DotTemplateExp(dve.loc, dve.e1, td); 9232 e = e.semantic(sc); 9233 } 9234 } 9235 else if (OverDeclaration od = dve.var.isOverDeclaration()) 9236 { 9237 e1 = dve.e1; // pull semantic() result 9238 9239 if (!findTempDecl(sc)) 9240 goto Lerr; 9241 if (ti.needsTypeInference(sc)) 9242 return this; 9243 ti.semantic(sc); 9244 if (!ti.inst || ti.errors) // if template failed to expand 9245 return new ErrorExp(); 9246 9247 Dsymbol s = ti.toAlias(); 9248 Declaration v = s.isDeclaration(); 9249 if (v) 9250 { 9251 if (v.type && !v.type.deco) 9252 v.type = v.type.semantic(v.loc, sc); 9253 e = new DotVarExp(loc, e1, v); 9254 e = e.semantic(sc); 9255 return e; 9256 } 9257 e = new ScopeExp(loc, ti); 9258 e = new DotExp(loc, e1, e); 9259 e = e.semantic(sc); 9260 return e; 9261 } 9262 } 9263 else if (e.op == TOKvar) 9264 { 9265 VarExp ve = cast(VarExp)e; 9266 if (FuncDeclaration fd = ve.var.isFuncDeclaration()) 9267 { 9268 TemplateDeclaration td = fd.findTemplateDeclRoot(); 9269 if (td) 9270 { 9271 e = new TemplateExp(ve.loc, td); 9272 e = e.semantic(sc); 9273 } 9274 } 9275 else if (OverDeclaration od = ve.var.isOverDeclaration()) 9276 { 9277 ti.tempdecl = od; 9278 e = new ScopeExp(loc, ti); 9279 e = e.semantic(sc); 9280 return e; 9281 } 9282 } 9283 if (e.op == TOKdottd) 9284 { 9285 DotTemplateExp dte = cast(DotTemplateExp)e; 9286 e1 = dte.e1; // pull semantic() result 9287 9288 ti.tempdecl = dte.td; 9289 if (!ti.semanticTiargs(sc)) 9290 return new ErrorExp(); 9291 if (ti.needsTypeInference(sc)) 9292 return this; 9293 ti.semantic(sc); 9294 if (!ti.inst || ti.errors) // if template failed to expand 9295 return new ErrorExp(); 9296 9297 Dsymbol s = ti.toAlias(); 9298 Declaration v = s.isDeclaration(); 9299 if (v && (v.isFuncDeclaration() || v.isVarDeclaration())) 9300 { 9301 e = new DotVarExp(loc, e1, v); 9302 e = e.semantic(sc); 9303 return e; 9304 } 9305 e = new ScopeExp(loc, ti); 9306 e = new DotExp(loc, e1, e); 9307 e = e.semantic(sc); 9308 return e; 9309 } 9310 else if (e.op == TOKtemplate) 9311 { 9312 ti.tempdecl = (cast(TemplateExp)e).td; 9313 e = new ScopeExp(loc, ti); 9314 e = e.semantic(sc); 9315 return e; 9316 } 9317 else if (e.op == TOKdot) 9318 { 9319 DotExp de = cast(DotExp)e; 9320 9321 if (de.e2.op == TOKoverloadset) 9322 { 9323 if (!findTempDecl(sc) || !ti.semanticTiargs(sc)) 9324 { 9325 return new ErrorExp(); 9326 } 9327 if (ti.needsTypeInference(sc)) 9328 return this; 9329 ti.semantic(sc); 9330 if (!ti.inst || ti.errors) // if template failed to expand 9331 return new ErrorExp(); 9332 9333 Dsymbol s = ti.toAlias(); 9334 Declaration v = s.isDeclaration(); 9335 if (v) 9336 { 9337 if (v.type && !v.type.deco) 9338 v.type = v.type.semantic(v.loc, sc); 9339 e = new DotVarExp(loc, e1, v); 9340 e = e.semantic(sc); 9341 return e; 9342 } 9343 e = new ScopeExp(loc, ti); 9344 e = new DotExp(loc, e1, e); 9345 e = e.semantic(sc); 9346 return e; 9347 } 9348 } 9349 else if (e.op == TOKoverloadset) 9350 { 9351 OverExp oe = cast(OverExp)e; 9352 ti.tempdecl = oe.vars; 9353 e = new ScopeExp(loc, ti); 9354 e = e.semantic(sc); 9355 return e; 9356 } 9357 9358 Lerr: 9359 error("%s isn't a template", e.toChars()); 9360 return new ErrorExp(); 9361 } 9362 9363 override void accept(Visitor v) 9364 { 9365 v.visit(this); 9366 } 9367 } 9368 9369 /*********************************************************** 9370 */ 9371 extern (C++) final class DelegateExp : UnaExp 9372 { 9373 FuncDeclaration func; 9374 bool hasOverloads; 9375 9376 extern (D) this(Loc loc, Expression e, FuncDeclaration f, bool hasOverloads = true) 9377 { 9378 super(loc, TOKdelegate, __traits(classInstanceSize, DelegateExp), e); 9379 this.func = f; 9380 this.hasOverloads = hasOverloads; 9381 } 9382 9383 override Expression semantic(Scope* sc) 9384 { 9385 static if (LOGSEMANTIC) 9386 { 9387 printf("DelegateExp::semantic('%s')\n", toChars()); 9388 } 9389 if (type) 9390 return this; 9391 9392 e1 = e1.semantic(sc); 9393 9394 type = new TypeDelegate(func.type); 9395 type = type.semantic(loc, sc); 9396 9397 FuncDeclaration f = func.toAliasFunc(); 9398 AggregateDeclaration ad = f.toParent().isAggregateDeclaration(); 9399 if (f.needThis()) 9400 e1 = getRightThis(loc, sc, ad, e1, f); 9401 if (f.type.ty == Tfunction) 9402 { 9403 TypeFunction tf = cast(TypeFunction)f.type; 9404 if (!MODimplicitConv(e1.type.mod, f.type.mod)) 9405 { 9406 OutBuffer thisBuf, funcBuf; 9407 MODMatchToBuffer(&thisBuf, e1.type.mod, tf.mod); 9408 MODMatchToBuffer(&funcBuf, tf.mod, e1.type.mod); 9409 error("%smethod %s is not callable using a %s%s", 9410 funcBuf.peekString(), f.toPrettyChars(), thisBuf.peekString(), e1.toChars()); 9411 return new ErrorExp(); 9412 } 9413 } 9414 if (ad && ad.isClassDeclaration() && ad.type != e1.type) 9415 { 9416 // A downcast is required for interfaces, see Bugzilla 3706 9417 e1 = new CastExp(loc, e1, ad.type); 9418 e1 = e1.semantic(sc); 9419 } 9420 return this; 9421 } 9422 9423 override void accept(Visitor v) 9424 { 9425 v.visit(this); 9426 } 9427 9428 override void printAST(int indent) 9429 { 9430 UnaExp.printAST(indent); 9431 foreach (i; 0 .. indent + 2) 9432 printf(" "); 9433 printf(".func: %s\n", func ? func.toChars() : ""); 9434 } 9435 } 9436 9437 /*********************************************************** 9438 */ 9439 extern (C++) final class DotTypeExp : UnaExp 9440 { 9441 Dsymbol sym; // symbol that represents a type 9442 9443 extern (D) this(Loc loc, Expression e, Dsymbol s) 9444 { 9445 super(loc, TOKdottype, __traits(classInstanceSize, DotTypeExp), e); 9446 this.sym = s; 9447 } 9448 9449 override Expression semantic(Scope* sc) 9450 { 9451 static if (LOGSEMANTIC) 9452 { 9453 printf("DotTypeExp::semantic('%s')\n", toChars()); 9454 } 9455 if (type) 9456 return this; 9457 9458 if (auto e = unaSemantic(sc)) 9459 return e; 9460 9461 type = sym.getType().addMod(e1.type.mod); 9462 return this; 9463 } 9464 9465 override void accept(Visitor v) 9466 { 9467 v.visit(this); 9468 } 9469 } 9470 9471 /*********************************************************** 9472 */ 9473 extern (C++) final class CallExp : UnaExp 9474 { 9475 Expressions* arguments; // function arguments 9476 FuncDeclaration f; // symbol to call 9477 bool directcall; // true if a virtual call is devirtualized 9478 9479 extern (D) this(Loc loc, Expression e, Expressions* exps) 9480 { 9481 super(loc, TOKcall, __traits(classInstanceSize, CallExp), e); 9482 this.arguments = exps; 9483 } 9484 9485 extern (D) this(Loc loc, Expression e) 9486 { 9487 super(loc, TOKcall, __traits(classInstanceSize, CallExp), e); 9488 } 9489 9490 extern (D) this(Loc loc, Expression e, Expression earg1) 9491 { 9492 super(loc, TOKcall, __traits(classInstanceSize, CallExp), e); 9493 auto arguments = new Expressions(); 9494 if (earg1) 9495 { 9496 arguments.setDim(1); 9497 (*arguments)[0] = earg1; 9498 } 9499 this.arguments = arguments; 9500 } 9501 9502 extern (D) this(Loc loc, Expression e, Expression earg1, Expression earg2) 9503 { 9504 super(loc, TOKcall, __traits(classInstanceSize, CallExp), e); 9505 auto arguments = new Expressions(); 9506 arguments.setDim(2); 9507 (*arguments)[0] = earg1; 9508 (*arguments)[1] = earg2; 9509 this.arguments = arguments; 9510 } 9511 9512 static CallExp create(Loc loc, Expression e, Expressions* exps) 9513 { 9514 return new CallExp(loc, e, exps); 9515 } 9516 9517 static CallExp create(Loc loc, Expression e) 9518 { 9519 return new CallExp(loc, e); 9520 } 9521 9522 static CallExp create(Loc loc, Expression e, Expression earg1) 9523 { 9524 return new CallExp(loc, e, earg1); 9525 } 9526 9527 override Expression syntaxCopy() 9528 { 9529 return new CallExp(loc, e1.syntaxCopy(), arraySyntaxCopy(arguments)); 9530 } 9531 9532 override Expression semantic(Scope* sc) 9533 { 9534 static if (LOGSEMANTIC) 9535 { 9536 printf("CallExp::semantic() %s\n", toChars()); 9537 } 9538 if (type) 9539 return this; // semantic() already run 9540 version (none) 9541 { 9542 if (arguments && arguments.dim) 9543 { 9544 Expression earg = (*arguments)[0]; 9545 earg.print(); 9546 if (earg.type) 9547 earg.type.print(); 9548 } 9549 } 9550 9551 Type t1; 9552 Objects* tiargs = null; // initial list of template arguments 9553 Expression ethis = null; 9554 Type tthis = null; 9555 Expression e1org = e1; 9556 9557 if (e1.op == TOKcomma) 9558 { 9559 /* Rewrite (a,b)(args) as (a,(b(args))) 9560 */ 9561 auto ce = cast(CommaExp)e1; 9562 e1 = ce.e2; 9563 ce.e2 = this; 9564 return ce.semantic(sc); 9565 } 9566 if (e1.op == TOKdelegate) 9567 { 9568 DelegateExp de = cast(DelegateExp)e1; 9569 e1 = new DotVarExp(de.loc, de.e1, de.func, de.hasOverloads); 9570 return semantic(sc); 9571 } 9572 if (e1.op == TOKfunction) 9573 { 9574 if (arrayExpressionSemantic(arguments, sc) || preFunctionParameters(loc, sc, arguments)) 9575 { 9576 return new ErrorExp(); 9577 } 9578 9579 // Run e1 semantic even if arguments have any errors 9580 FuncExp fe = cast(FuncExp)e1; 9581 e1 = fe.semantic(sc, arguments); 9582 if (e1.op == TOKerror) 9583 return e1; 9584 } 9585 9586 if (Expression ex = resolveUFCS(sc, this)) 9587 return ex; 9588 9589 /* This recognizes: 9590 * foo!(tiargs)(funcargs) 9591 */ 9592 if (e1.op == TOKscope) 9593 { 9594 ScopeExp se = cast(ScopeExp)e1; 9595 TemplateInstance ti = se.sds.isTemplateInstance(); 9596 if (ti) 9597 { 9598 /* Attempt to instantiate ti. If that works, go with it. 9599 * If not, go with partial explicit specialization. 9600 */ 9601 WithScopeSymbol withsym; 9602 if (!ti.findTempDecl(sc, &withsym) || !ti.semanticTiargs(sc)) 9603 { 9604 return new ErrorExp(); 9605 } 9606 if (withsym && withsym.withstate.wthis) 9607 { 9608 e1 = new VarExp(e1.loc, withsym.withstate.wthis); 9609 e1 = new DotTemplateInstanceExp(e1.loc, e1, ti); 9610 goto Ldotti; 9611 } 9612 if (ti.needsTypeInference(sc, 1)) 9613 { 9614 /* Go with partial explicit specialization 9615 */ 9616 tiargs = ti.tiargs; 9617 assert(ti.tempdecl); 9618 if (TemplateDeclaration td = ti.tempdecl.isTemplateDeclaration()) 9619 e1 = new TemplateExp(loc, td); 9620 else if (OverDeclaration od = ti.tempdecl.isOverDeclaration()) 9621 e1 = new VarExp(loc, od); 9622 else 9623 e1 = new OverExp(loc, ti.tempdecl.isOverloadSet()); 9624 } 9625 else 9626 { 9627 Expression e1x = e1.semantic(sc); 9628 if (e1x.op == TOKerror) 9629 return e1x; 9630 e1 = e1x; 9631 } 9632 } 9633 } 9634 9635 /* This recognizes: 9636 * expr.foo!(tiargs)(funcargs) 9637 */ 9638 Ldotti: 9639 if (e1.op == TOKdotti && !e1.type) 9640 { 9641 DotTemplateInstanceExp se = cast(DotTemplateInstanceExp)e1; 9642 TemplateInstance ti = se.ti; 9643 { 9644 /* Attempt to instantiate ti. If that works, go with it. 9645 * If not, go with partial explicit specialization. 9646 */ 9647 if (!se.findTempDecl(sc) || !ti.semanticTiargs(sc)) 9648 { 9649 return new ErrorExp(); 9650 } 9651 if (ti.needsTypeInference(sc, 1)) 9652 { 9653 /* Go with partial explicit specialization 9654 */ 9655 tiargs = ti.tiargs; 9656 assert(ti.tempdecl); 9657 if (TemplateDeclaration td = ti.tempdecl.isTemplateDeclaration()) 9658 e1 = new DotTemplateExp(loc, se.e1, td); 9659 else if (OverDeclaration od = ti.tempdecl.isOverDeclaration()) 9660 { 9661 e1 = new DotVarExp(loc, se.e1, od, true); 9662 } 9663 else 9664 e1 = new DotExp(loc, se.e1, new OverExp(loc, ti.tempdecl.isOverloadSet())); 9665 } 9666 else 9667 { 9668 Expression e1x = e1.semantic(sc); 9669 if (e1x.op == TOKerror) 9670 return e1x; 9671 e1 = e1x; 9672 } 9673 } 9674 } 9675 9676 Lagain: 9677 //printf("Lagain: %s\n", toChars()); 9678 f = null; 9679 if (e1.op == TOKthis || e1.op == TOKsuper) 9680 { 9681 // semantic() run later for these 9682 } 9683 else 9684 { 9685 if (e1.op == TOKdotid) 9686 { 9687 DotIdExp die = cast(DotIdExp)e1; 9688 e1 = die.semantic(sc); 9689 /* Look for e1 having been rewritten to expr.opDispatch!(string) 9690 * We handle such earlier, so go back. 9691 * Note that in the rewrite, we carefully did not run semantic() on e1 9692 */ 9693 if (e1.op == TOKdotti && !e1.type) 9694 { 9695 goto Ldotti; 9696 } 9697 } 9698 else 9699 { 9700 static __gshared int nest; 9701 if (++nest > 500) 9702 { 9703 error("recursive evaluation of %s", toChars()); 9704 --nest; 9705 return new ErrorExp(); 9706 } 9707 Expression ex = unaSemantic(sc); 9708 --nest; 9709 if (ex) 9710 return ex; 9711 } 9712 9713 /* Look for e1 being a lazy parameter 9714 */ 9715 if (e1.op == TOKvar) 9716 { 9717 VarExp ve = cast(VarExp)e1; 9718 if (ve.var.storage_class & STClazy) 9719 { 9720 // lazy paramaters can be called without violating purity and safety 9721 Type tw = ve.var.type; 9722 Type tc = ve.var.type.substWildTo(MODconst); 9723 auto tf = new TypeFunction(null, tc, 0, LINKd, STCsafe | STCpure); 9724 (tf = cast(TypeFunction)tf.semantic(loc, sc)).next = tw; // hack for bug7757 9725 auto t = new TypeDelegate(tf); 9726 ve.type = t.semantic(loc, sc); 9727 } 9728 VarDeclaration v = ve.var.isVarDeclaration(); 9729 if (v && ve.checkPurity(sc, v)) 9730 return new ErrorExp(); 9731 } 9732 9733 if (e1.op == TOKsymoff && (cast(SymOffExp)e1).hasOverloads) 9734 { 9735 SymOffExp se = cast(SymOffExp)e1; 9736 e1 = new VarExp(se.loc, se.var, true); 9737 e1 = e1.semantic(sc); 9738 } 9739 else if (e1.op == TOKdot) 9740 { 9741 DotExp de = cast(DotExp)e1; 9742 9743 if (de.e2.op == TOKoverloadset) 9744 { 9745 ethis = de.e1; 9746 tthis = de.e1.type; 9747 e1 = de.e2; 9748 } 9749 } 9750 else if (e1.op == TOKstar && e1.type.ty == Tfunction) 9751 { 9752 // Rewrite (*fp)(arguments) to fp(arguments) 9753 e1 = (cast(PtrExp)e1).e1; 9754 } 9755 } 9756 9757 t1 = e1.type ? e1.type.toBasetype() : null; 9758 9759 if (e1.op == TOKerror) 9760 return e1; 9761 if (arrayExpressionSemantic(arguments, sc) || preFunctionParameters(loc, sc, arguments)) 9762 { 9763 return new ErrorExp(); 9764 } 9765 9766 // Check for call operator overload 9767 if (t1) 9768 { 9769 if (t1.ty == Tstruct) 9770 { 9771 auto sd = (cast(TypeStruct)t1).sym; 9772 sd.size(loc); // Resolve forward references to construct object 9773 if (sd.sizeok != SIZEOKdone) 9774 return new ErrorExp(); 9775 if (!sd.ctor) 9776 sd.ctor = sd.searchCtor(); 9777 9778 // First look for constructor 9779 if (e1.op == TOKtype && sd.ctor) 9780 { 9781 if (!sd.noDefaultCtor && !(arguments && arguments.dim)) 9782 goto Lx; 9783 9784 auto sle = new StructLiteralExp(loc, sd, null, e1.type); 9785 if (!sd.fill(loc, sle.elements, true)) 9786 return new ErrorExp(); 9787 if (checkFrameAccess(loc, sc, sd, sle.elements.dim)) 9788 return new ErrorExp(); 9789 9790 // Bugzilla 14556: Set concrete type to avoid further redundant semantic(). 9791 sle.type = e1.type; 9792 9793 /* Constructor takes a mutable object, so don't use 9794 * the immutable initializer symbol. 9795 */ 9796 sle.useStaticInit = false; 9797 9798 Expression e = sle; 9799 if (auto cf = sd.ctor.isCtorDeclaration()) 9800 { 9801 e = new DotVarExp(loc, e, cf, true); 9802 } 9803 else if (auto td = sd.ctor.isTemplateDeclaration()) 9804 { 9805 e = new DotTemplateExp(loc, e, td); 9806 } 9807 else if (auto os = sd.ctor.isOverloadSet()) 9808 { 9809 e = new DotExp(loc, e, new OverExp(loc, os)); 9810 } 9811 else 9812 assert(0); 9813 e = new CallExp(loc, e, arguments); 9814 e = e.semantic(sc); 9815 return e; 9816 } 9817 // No constructor, look for overload of opCall 9818 if (search_function(sd, Id.call)) 9819 goto L1; 9820 // overload of opCall, therefore it's a call 9821 if (e1.op != TOKtype) 9822 { 9823 if (sd.aliasthis && e1.type != att1) 9824 { 9825 if (!att1 && e1.type.checkAliasThisRec()) 9826 att1 = e1.type; 9827 e1 = resolveAliasThis(sc, e1); 9828 goto Lagain; 9829 } 9830 error("%s %s does not overload ()", sd.kind(), sd.toChars()); 9831 return new ErrorExp(); 9832 } 9833 9834 /* It's a struct literal 9835 */ 9836 Lx: 9837 Expression e = new StructLiteralExp(loc, sd, arguments, e1.type); 9838 e = e.semantic(sc); 9839 return e; 9840 } 9841 else if (t1.ty == Tclass) 9842 { 9843 L1: 9844 // Rewrite as e1.call(arguments) 9845 Expression e = new DotIdExp(loc, e1, Id.call); 9846 e = new CallExp(loc, e, arguments); 9847 e = e.semantic(sc); 9848 return e; 9849 } 9850 else if (e1.op == TOKtype && t1.isscalar()) 9851 { 9852 Expression e; 9853 if (!arguments || arguments.dim == 0) 9854 { 9855 e = t1.defaultInitLiteral(loc); 9856 } 9857 else if (arguments.dim == 1) 9858 { 9859 e = (*arguments)[0]; 9860 e = e.implicitCastTo(sc, t1); 9861 e = new CastExp(loc, e, t1); 9862 } 9863 else 9864 { 9865 error("more than one argument for construction of %s", t1.toChars()); 9866 e = new ErrorExp(); 9867 } 9868 e = e.semantic(sc); 9869 return e; 9870 } 9871 } 9872 9873 static FuncDeclaration resolveOverloadSet(Loc loc, Scope* sc, 9874 OverloadSet os, Objects* tiargs, Type tthis, Expressions* arguments) 9875 { 9876 FuncDeclaration f = null; 9877 foreach (s; os.a) 9878 { 9879 if (tiargs && s.isFuncDeclaration()) 9880 continue; 9881 if (auto f2 = resolveFuncCall(loc, sc, s, tiargs, tthis, arguments, 1)) 9882 { 9883 if (f2.errors) 9884 return null; 9885 if (f) 9886 { 9887 /* Error if match in more than one overload set, 9888 * even if one is a 'better' match than the other. 9889 */ 9890 ScopeDsymbol.multiplyDefined(loc, f, f2); 9891 } 9892 else 9893 f = f2; 9894 } 9895 } 9896 if (!f) 9897 .error(loc, "no overload matches for %s", os.toChars()); 9898 else if (f.errors) 9899 f = null; 9900 return f; 9901 } 9902 9903 if (e1.op == TOKdotvar && t1.ty == Tfunction || e1.op == TOKdottd) 9904 { 9905 UnaExp ue = cast(UnaExp)e1; 9906 9907 Expression ue1 = ue.e1; 9908 Expression ue1old = ue1; // need for 'right this' check 9909 VarDeclaration v; 9910 if (ue1.op == TOKvar && (v = (cast(VarExp)ue1).var.isVarDeclaration()) !is null && v.needThis()) 9911 { 9912 ue.e1 = new TypeExp(ue1.loc, ue1.type); 9913 ue1 = null; 9914 } 9915 9916 DotVarExp dve; 9917 DotTemplateExp dte; 9918 Dsymbol s; 9919 if (e1.op == TOKdotvar) 9920 { 9921 dve = cast(DotVarExp)e1; 9922 dte = null; 9923 s = dve.var; 9924 tiargs = null; 9925 } 9926 else 9927 { 9928 dve = null; 9929 dte = cast(DotTemplateExp)e1; 9930 s = dte.td; 9931 } 9932 9933 // Do overload resolution 9934 f = resolveFuncCall(loc, sc, s, tiargs, ue1 ? ue1.type : null, arguments); 9935 if (!f || f.errors || f.type.ty == Terror) 9936 return new ErrorExp(); 9937 9938 if (f.interfaceVirtual) 9939 { 9940 /* Cast 'this' to the type of the interface, and replace f with the interface's equivalent 9941 */ 9942 auto b = f.interfaceVirtual; 9943 auto ad2 = b.sym; 9944 ue.e1 = ue.e1.castTo(sc, ad2.type.addMod(ue.e1.type.mod)); 9945 ue.e1 = ue.e1.semantic(sc); 9946 ue1 = ue.e1; 9947 auto vi = f.findVtblIndex(&ad2.vtbl, cast(int)ad2.vtbl.dim); 9948 assert(vi >= 0); 9949 f = ad2.vtbl[vi].isFuncDeclaration(); 9950 assert(f); 9951 } 9952 if (f.needThis()) 9953 { 9954 AggregateDeclaration ad = f.toParent2().isAggregateDeclaration(); 9955 ue.e1 = getRightThis(loc, sc, ad, ue.e1, f); 9956 if (ue.e1.op == TOKerror) 9957 return ue.e1; 9958 ethis = ue.e1; 9959 tthis = ue.e1.type; 9960 } 9961 9962 /* Cannot call public functions from inside invariant 9963 * (because then the invariant would have infinite recursion) 9964 */ 9965 if (sc.func && sc.func.isInvariantDeclaration() && ue.e1.op == TOKthis && f.addPostInvariant()) 9966 { 9967 error("cannot call public/export function %s from invariant", f.toChars()); 9968 return new ErrorExp(); 9969 } 9970 9971 checkDeprecated(sc, f); 9972 checkPurity(sc, f); 9973 checkSafety(sc, f); 9974 checkNogc(sc, f); 9975 checkAccess(loc, sc, ue.e1, f); 9976 if (!f.needThis()) 9977 { 9978 e1 = Expression.combine(ue.e1, new VarExp(loc, f, false)); 9979 } 9980 else 9981 { 9982 if (ue1old.checkRightThis(sc)) 9983 return new ErrorExp(); 9984 if (e1.op == TOKdotvar) 9985 { 9986 dve.var = f; 9987 e1.type = f.type; 9988 } 9989 else 9990 { 9991 e1 = new DotVarExp(loc, dte.e1, f, false); 9992 e1 = e1.semantic(sc); 9993 if (e1.op == TOKerror) 9994 return new ErrorExp(); 9995 ue = cast(UnaExp)e1; 9996 } 9997 version (none) 9998 { 9999 printf("ue->e1 = %s\n", ue.e1.toChars()); 10000 printf("f = %s\n", f.toChars()); 10001 printf("t = %s\n", t.toChars()); 10002 printf("e1 = %s\n", e1.toChars()); 10003 printf("e1->type = %s\n", e1.type.toChars()); 10004 } 10005 10006 // See if we need to adjust the 'this' pointer 10007 AggregateDeclaration ad = f.isThis(); 10008 ClassDeclaration cd = ue.e1.type.isClassHandle(); 10009 if (ad && cd && ad.isClassDeclaration()) 10010 { 10011 if (ue.e1.op == TOKdottype) 10012 { 10013 ue.e1 = (cast(DotTypeExp)ue.e1).e1; 10014 directcall = true; 10015 } 10016 else if (ue.e1.op == TOKsuper) 10017 directcall = true; 10018 else if ((cd.storage_class & STCfinal) != 0) // Bugzilla 14211 10019 directcall = true; 10020 10021 if (ad != cd) 10022 { 10023 ue.e1 = ue.e1.castTo(sc, ad.type.addMod(ue.e1.type.mod)); 10024 ue.e1 = ue.e1.semantic(sc); 10025 } 10026 } 10027 } 10028 t1 = e1.type; 10029 } 10030 else if (e1.op == TOKsuper) 10031 { 10032 // Base class constructor call 10033 auto ad = sc.func ? sc.func.isThis() : null; 10034 auto cd = ad ? ad.isClassDeclaration() : null; 10035 if (!cd || !cd.baseClass || !sc.func.isCtorDeclaration()) 10036 { 10037 error("super class constructor call must be in a constructor"); 10038 return new ErrorExp(); 10039 } 10040 if (!cd.baseClass.ctor) 10041 { 10042 error("no super class constructor for %s", cd.baseClass.toChars()); 10043 return new ErrorExp(); 10044 } 10045 10046 if (!sc.intypeof && !(sc.callSuper & CSXhalt)) 10047 { 10048 if (sc.noctor || sc.callSuper & CSXlabel) 10049 error("constructor calls not allowed in loops or after labels"); 10050 if (sc.callSuper & (CSXsuper_ctor | CSXthis_ctor)) 10051 error("multiple constructor calls"); 10052 if ((sc.callSuper & CSXreturn) && !(sc.callSuper & CSXany_ctor)) 10053 error("an earlier return statement skips constructor"); 10054 sc.callSuper |= CSXany_ctor | CSXsuper_ctor; 10055 } 10056 10057 tthis = cd.type.addMod(sc.func.type.mod); 10058 if (auto os = cd.baseClass.ctor.isOverloadSet()) 10059 f = resolveOverloadSet(loc, sc, os, null, tthis, arguments); 10060 else 10061 f = resolveFuncCall(loc, sc, cd.baseClass.ctor, null, tthis, arguments, 0); 10062 if (!f || f.errors) 10063 return new ErrorExp(); 10064 checkDeprecated(sc, f); 10065 checkPurity(sc, f); 10066 checkSafety(sc, f); 10067 checkNogc(sc, f); 10068 checkAccess(loc, sc, null, f); 10069 10070 e1 = new DotVarExp(e1.loc, e1, f, false); 10071 e1 = e1.semantic(sc); 10072 t1 = e1.type; 10073 } 10074 else if (e1.op == TOKthis) 10075 { 10076 // same class constructor call 10077 auto ad = sc.func ? sc.func.isThis() : null; 10078 if (!ad || !sc.func.isCtorDeclaration()) 10079 { 10080 error("constructor call must be in a constructor"); 10081 return new ErrorExp(); 10082 } 10083 10084 if (!sc.intypeof && !(sc.callSuper & CSXhalt)) 10085 { 10086 if (sc.noctor || sc.callSuper & CSXlabel) 10087 error("constructor calls not allowed in loops or after labels"); 10088 if (sc.callSuper & (CSXsuper_ctor | CSXthis_ctor)) 10089 error("multiple constructor calls"); 10090 if ((sc.callSuper & CSXreturn) && !(sc.callSuper & CSXany_ctor)) 10091 error("an earlier return statement skips constructor"); 10092 sc.callSuper |= CSXany_ctor | CSXthis_ctor; 10093 } 10094 10095 tthis = ad.type.addMod(sc.func.type.mod); 10096 if (auto os = ad.ctor.isOverloadSet()) 10097 f = resolveOverloadSet(loc, sc, os, null, tthis, arguments); 10098 else 10099 f = resolveFuncCall(loc, sc, ad.ctor, null, tthis, arguments, 0); 10100 if (!f || f.errors) 10101 return new ErrorExp(); 10102 checkDeprecated(sc, f); 10103 checkPurity(sc, f); 10104 checkSafety(sc, f); 10105 checkNogc(sc, f); 10106 //checkAccess(loc, sc, NULL, f); // necessary? 10107 10108 e1 = new DotVarExp(e1.loc, e1, f, false); 10109 e1 = e1.semantic(sc); 10110 t1 = e1.type; 10111 10112 // BUG: this should really be done by checking the static 10113 // call graph 10114 if (f == sc.func) 10115 { 10116 error("cyclic constructor call"); 10117 return new ErrorExp(); 10118 } 10119 } 10120 else if (e1.op == TOKoverloadset) 10121 { 10122 auto os = (cast(OverExp)e1).vars; 10123 f = resolveOverloadSet(loc, sc, os, tiargs, tthis, arguments); 10124 if (!f) 10125 return new ErrorExp(); 10126 if (ethis) 10127 e1 = new DotVarExp(loc, ethis, f, false); 10128 else 10129 e1 = new VarExp(loc, f, false); 10130 goto Lagain; 10131 } 10132 else if (!t1) 10133 { 10134 error("function expected before (), not '%s'", e1.toChars()); 10135 return new ErrorExp(); 10136 } 10137 else if (t1.ty == Terror) 10138 { 10139 return new ErrorExp(); 10140 } 10141 else if (t1.ty != Tfunction) 10142 { 10143 TypeFunction tf; 10144 const(char)* p; 10145 Dsymbol s; 10146 f = null; 10147 if (e1.op == TOKfunction) 10148 { 10149 // function literal that direct called is always inferred. 10150 assert((cast(FuncExp)e1).fd); 10151 f = (cast(FuncExp)e1).fd; 10152 tf = cast(TypeFunction)f.type; 10153 p = "function literal"; 10154 } 10155 else if (t1.ty == Tdelegate) 10156 { 10157 TypeDelegate td = cast(TypeDelegate)t1; 10158 assert(td.next.ty == Tfunction); 10159 tf = cast(TypeFunction)td.next; 10160 p = "delegate"; 10161 } 10162 else if (t1.ty == Tpointer && (cast(TypePointer)t1).next.ty == Tfunction) 10163 { 10164 tf = cast(TypeFunction)(cast(TypePointer)t1).next; 10165 p = "function pointer"; 10166 } 10167 else if (e1.op == TOKdotvar && (cast(DotVarExp)e1).var.isOverDeclaration()) 10168 { 10169 DotVarExp dve = cast(DotVarExp)e1; 10170 f = resolveFuncCall(loc, sc, dve.var, tiargs, dve.e1.type, arguments, 2); 10171 if (!f) 10172 return new ErrorExp(); 10173 if (f.needThis()) 10174 { 10175 dve.var = f; 10176 dve.type = f.type; 10177 dve.hasOverloads = false; 10178 goto Lagain; 10179 } 10180 e1 = new VarExp(dve.loc, f, false); 10181 Expression e = new CommaExp(loc, dve.e1, this); 10182 return e.semantic(sc); 10183 } 10184 else if (e1.op == TOKvar && (cast(VarExp)e1).var.isOverDeclaration()) 10185 { 10186 s = (cast(VarExp)e1).var; 10187 goto L2; 10188 } 10189 else if (e1.op == TOKtemplate) 10190 { 10191 s = (cast(TemplateExp)e1).td; 10192 L2: 10193 f = resolveFuncCall(loc, sc, s, tiargs, null, arguments); 10194 if (!f || f.errors) 10195 return new ErrorExp(); 10196 if (f.needThis()) 10197 { 10198 if (hasThis(sc)) 10199 { 10200 // Supply an implicit 'this', as in 10201 // this.ident 10202 e1 = new DotVarExp(loc, (new ThisExp(loc)).semantic(sc), f, false); 10203 goto Lagain; 10204 } 10205 else if (isNeedThisScope(sc, f)) 10206 { 10207 error("need 'this' for '%s' of type '%s'", f.toChars(), f.type.toChars()); 10208 return new ErrorExp(); 10209 } 10210 } 10211 e1 = new VarExp(e1.loc, f, false); 10212 goto Lagain; 10213 } 10214 else 10215 { 10216 error("function expected before (), not %s of type %s", e1.toChars(), e1.type.toChars()); 10217 return new ErrorExp(); 10218 } 10219 10220 if (!tf.callMatch(null, arguments)) 10221 { 10222 OutBuffer buf; 10223 buf.writeByte('('); 10224 argExpTypesToCBuffer(&buf, arguments); 10225 buf.writeByte(')'); 10226 if (tthis) 10227 tthis.modToBuffer(&buf); 10228 10229 //printf("tf = %s, args = %s\n", tf->deco, (*arguments)[0]->type->deco); 10230 .error(loc, "%s %s %s is not callable using argument types %s", p, e1.toChars(), parametersTypeToChars(tf.parameters, tf.varargs), buf.peekString()); 10231 10232 return new ErrorExp(); 10233 } 10234 // Purity and safety check should run after testing arguments matching 10235 if (f) 10236 { 10237 checkPurity(sc, f); 10238 checkSafety(sc, f); 10239 checkNogc(sc, f); 10240 if (f.checkNestedReference(sc, loc)) 10241 return new ErrorExp(); 10242 } 10243 else if (sc.func && sc.intypeof != 1 && !(sc.flags & SCOPEctfe)) 10244 { 10245 bool err = false; 10246 if (!tf.purity && !(sc.flags & SCOPEdebug) && sc.func.setImpure()) 10247 { 10248 error("pure %s '%s' cannot call impure %s '%s'", 10249 sc.func.kind(), sc.func.toPrettyChars(), p, e1.toChars()); 10250 err = true; 10251 } 10252 if (!tf.isnogc && sc.func.setGC()) 10253 { 10254 error("@nogc %s '%s' cannot call non-@nogc %s '%s'", 10255 sc.func.kind(), sc.func.toPrettyChars(), p, e1.toChars()); 10256 err = true; 10257 } 10258 if (tf.trust <= TRUSTsystem && sc.func.setUnsafe()) 10259 { 10260 error("@safe %s '%s' cannot call @system %s '%s'", 10261 sc.func.kind(), sc.func.toPrettyChars(), p, e1.toChars()); 10262 err = true; 10263 } 10264 if (err) 10265 return new ErrorExp(); 10266 } 10267 10268 if (t1.ty == Tpointer) 10269 { 10270 Expression e = new PtrExp(loc, e1); 10271 e.type = tf; 10272 e1 = e; 10273 } 10274 t1 = tf; 10275 } 10276 else if (e1.op == TOKvar) 10277 { 10278 // Do overload resolution 10279 VarExp ve = cast(VarExp)e1; 10280 10281 f = ve.var.isFuncDeclaration(); 10282 assert(f); 10283 tiargs = null; 10284 10285 if (ve.hasOverloads) 10286 f = resolveFuncCall(loc, sc, f, tiargs, null, arguments, 2); 10287 else 10288 { 10289 f = f.toAliasFunc(); 10290 TypeFunction tf = cast(TypeFunction)f.type; 10291 if (!tf.callMatch(null, arguments)) 10292 { 10293 OutBuffer buf; 10294 buf.writeByte('('); 10295 argExpTypesToCBuffer(&buf, arguments); 10296 buf.writeByte(')'); 10297 10298 //printf("tf = %s, args = %s\n", tf->deco, (*arguments)[0]->type->deco); 10299 .error(loc, "%s %s is not callable using argument types %s", e1.toChars(), parametersTypeToChars(tf.parameters, tf.varargs), buf.peekString()); 10300 10301 f = null; 10302 } 10303 } 10304 if (!f || f.errors) 10305 return new ErrorExp(); 10306 10307 if (f.needThis()) 10308 { 10309 // Change the ancestor lambdas to delegate before hasThis(sc) call. 10310 if (f.checkNestedReference(sc, loc)) 10311 return new ErrorExp(); 10312 10313 if (hasThis(sc)) 10314 { 10315 // Supply an implicit 'this', as in 10316 // this.ident 10317 e1 = new DotVarExp(loc, (new ThisExp(loc)).semantic(sc), ve.var); 10318 // Note: we cannot use f directly, because further overload resolution 10319 // through the supplied 'this' may cause different result. 10320 goto Lagain; 10321 } 10322 else if (isNeedThisScope(sc, f)) 10323 { 10324 error("need 'this' for '%s' of type '%s'", f.toChars(), f.type.toChars()); 10325 return new ErrorExp(); 10326 } 10327 } 10328 10329 checkDeprecated(sc, f); 10330 checkPurity(sc, f); 10331 checkSafety(sc, f); 10332 checkNogc(sc, f); 10333 checkAccess(loc, sc, null, f); 10334 if (f.checkNestedReference(sc, loc)) 10335 return new ErrorExp(); 10336 10337 ethis = null; 10338 tthis = null; 10339 10340 if (ve.hasOverloads) 10341 { 10342 e1 = new VarExp(ve.loc, f, false); 10343 e1.type = f.type; 10344 } 10345 t1 = f.type; 10346 } 10347 assert(t1.ty == Tfunction); 10348 10349 Expression argprefix; 10350 if (!arguments) 10351 arguments = new Expressions(); 10352 if (functionParameters(loc, sc, cast(TypeFunction)t1, tthis, arguments, f, &type, &argprefix)) 10353 return new ErrorExp(); 10354 10355 if (!type) 10356 { 10357 e1 = e1org; // Bugzilla 10922, avoid recursive expression printing 10358 error("forward reference to inferred return type of function call '%s'", toChars()); 10359 return new ErrorExp(); 10360 } 10361 10362 if (f && f.tintro) 10363 { 10364 Type t = type; 10365 int offset = 0; 10366 TypeFunction tf = cast(TypeFunction)f.tintro; 10367 if (tf.next.isBaseOf(t, &offset) && offset) 10368 { 10369 type = tf.next; 10370 return combine(argprefix, castTo(sc, t)); 10371 } 10372 } 10373 10374 // Handle the case of a direct lambda call 10375 if (f && f.isFuncLiteralDeclaration() && sc.func && !sc.intypeof) 10376 { 10377 f.tookAddressOf = 0; 10378 } 10379 10380 return combine(argprefix, this); 10381 } 10382 10383 override bool isLvalue() 10384 { 10385 Type tb = e1.type.toBasetype(); 10386 if (tb.ty == Tdelegate || tb.ty == Tpointer) 10387 tb = tb.nextOf(); 10388 if (tb.ty == Tfunction && (cast(TypeFunction)tb).isref) 10389 { 10390 if (e1.op == TOKdotvar) 10391 if ((cast(DotVarExp)e1).var.isCtorDeclaration()) 10392 return false; 10393 return true; // function returns a reference 10394 } 10395 return false; 10396 } 10397 10398 override Expression toLvalue(Scope* sc, Expression e) 10399 { 10400 if (isLvalue()) 10401 return this; 10402 return Expression.toLvalue(sc, e); 10403 } 10404 10405 override Expression addDtorHook(Scope* sc) 10406 { 10407 /* Only need to add dtor hook if it's a type that needs destruction. 10408 * Use same logic as VarDeclaration::callScopeDtor() 10409 */ 10410 10411 if (e1.type && e1.type.ty == Tfunction) 10412 { 10413 TypeFunction tf = cast(TypeFunction)e1.type; 10414 if (tf.isref) 10415 return this; 10416 } 10417 10418 Type tv = type.baseElemOf(); 10419 if (tv.ty == Tstruct) 10420 { 10421 TypeStruct ts = cast(TypeStruct)tv; 10422 StructDeclaration sd = ts.sym; 10423 if (sd.dtor) 10424 { 10425 /* Type needs destruction, so declare a tmp 10426 * which the back end will recognize and call dtor on 10427 */ 10428 auto tmp = copyToTemp(0, "__tmpfordtor", this); 10429 auto de = new DeclarationExp(loc, tmp); 10430 auto ve = new VarExp(loc, tmp); 10431 Expression e = new CommaExp(loc, de, new VarExp(loc, tmp)); 10432 e = e.semantic(sc); 10433 return e; 10434 } 10435 } 10436 return this; 10437 } 10438 10439 override void accept(Visitor v) 10440 { 10441 v.visit(this); 10442 } 10443 } 10444 10445 FuncDeclaration isFuncAddress(Expression e, bool* hasOverloads = null) 10446 { 10447 if (e.op == TOKaddress) 10448 { 10449 auto ae1 = (cast(AddrExp)e).e1; 10450 if (ae1.op == TOKvar) 10451 { 10452 auto ve = cast(VarExp)ae1; 10453 if (hasOverloads) 10454 *hasOverloads = ve.hasOverloads; 10455 return ve.var.isFuncDeclaration(); 10456 } 10457 if (ae1.op == TOKdotvar) 10458 { 10459 auto dve = cast(DotVarExp)ae1; 10460 if (hasOverloads) 10461 *hasOverloads = dve.hasOverloads; 10462 return dve.var.isFuncDeclaration(); 10463 } 10464 } 10465 else 10466 { 10467 if (e.op == TOKsymoff) 10468 { 10469 auto soe = cast(SymOffExp)e; 10470 if (hasOverloads) 10471 *hasOverloads = soe.hasOverloads; 10472 return soe.var.isFuncDeclaration(); 10473 } 10474 if (e.op == TOKdelegate) 10475 { 10476 auto dge = cast(DelegateExp)e; 10477 if (hasOverloads) 10478 *hasOverloads = dge.hasOverloads; 10479 return dge.func.isFuncDeclaration(); 10480 } 10481 } 10482 return null; 10483 } 10484 10485 /*********************************************************** 10486 */ 10487 extern (C++) final class AddrExp : UnaExp 10488 { 10489 extern (D) this(Loc loc, Expression e) 10490 { 10491 super(loc, TOKaddress, __traits(classInstanceSize, AddrExp), e); 10492 } 10493 10494 override Expression semantic(Scope* sc) 10495 { 10496 static if (LOGSEMANTIC) 10497 { 10498 printf("AddrExp::semantic('%s')\n", toChars()); 10499 } 10500 if (type) 10501 return this; 10502 10503 if (Expression ex = unaSemantic(sc)) 10504 return ex; 10505 10506 int wasCond = e1.op == TOKquestion; 10507 10508 if (e1.op == TOKdotti) 10509 { 10510 DotTemplateInstanceExp dti = cast(DotTemplateInstanceExp)e1; 10511 TemplateInstance ti = dti.ti; 10512 { 10513 //assert(ti.needsTypeInference(sc)); 10514 ti.semantic(sc); 10515 if (!ti.inst || ti.errors) // if template failed to expand 10516 return new ErrorExp(); 10517 Dsymbol s = ti.toAlias(); 10518 FuncDeclaration f = s.isFuncDeclaration(); 10519 if (f) 10520 { 10521 e1 = new DotVarExp(e1.loc, dti.e1, f); 10522 e1 = e1.semantic(sc); 10523 } 10524 } 10525 } 10526 else if (e1.op == TOKscope) 10527 { 10528 TemplateInstance ti = (cast(ScopeExp)e1).sds.isTemplateInstance(); 10529 if (ti) 10530 { 10531 //assert(ti.needsTypeInference(sc)); 10532 ti.semantic(sc); 10533 if (!ti.inst || ti.errors) // if template failed to expand 10534 return new ErrorExp(); 10535 Dsymbol s = ti.toAlias(); 10536 FuncDeclaration f = s.isFuncDeclaration(); 10537 if (f) 10538 { 10539 e1 = new VarExp(e1.loc, f); 10540 e1 = e1.semantic(sc); 10541 } 10542 } 10543 } 10544 e1 = e1.toLvalue(sc, null); 10545 if (e1.op == TOKerror) 10546 return e1; 10547 if (checkNonAssignmentArrayOp(e1)) 10548 return new ErrorExp(); 10549 10550 if (!e1.type) 10551 { 10552 error("cannot take address of %s", e1.toChars()); 10553 return new ErrorExp(); 10554 } 10555 10556 bool hasOverloads; 10557 if (auto f = isFuncAddress(this, &hasOverloads)) 10558 { 10559 if (!hasOverloads && f.checkForwardRef(loc)) 10560 return new ErrorExp(); 10561 } 10562 else if (!e1.type.deco) 10563 { 10564 if (e1.op == TOKvar) 10565 { 10566 VarExp ve = cast(VarExp)e1; 10567 Declaration d = ve.var; 10568 error("forward reference to %s %s", d.kind(), d.toChars()); 10569 } 10570 else 10571 error("forward reference to %s", e1.toChars()); 10572 return new ErrorExp(); 10573 } 10574 10575 type = e1.type.pointerTo(); 10576 10577 // See if this should really be a delegate 10578 if (e1.op == TOKdotvar) 10579 { 10580 DotVarExp dve = cast(DotVarExp)e1; 10581 FuncDeclaration f = dve.var.isFuncDeclaration(); 10582 if (f) 10583 { 10584 f = f.toAliasFunc(); // FIXME, should see overloads - Bugzilla 1983 10585 if (!dve.hasOverloads) 10586 f.tookAddressOf++; 10587 10588 Expression e; 10589 if (f.needThis()) 10590 e = new DelegateExp(loc, dve.e1, f, dve.hasOverloads); 10591 else // It is a function pointer. Convert &v.f() --> (v, &V.f()) 10592 e = new CommaExp(loc, dve.e1, new AddrExp(loc, new VarExp(loc, f, dve.hasOverloads))); 10593 e = e.semantic(sc); 10594 return e; 10595 } 10596 10597 // Look for misaligned pointer in @safe mode 10598 if (checkUnsafeAccess(sc, dve, !type.isMutable(), true)) 10599 return new ErrorExp(); 10600 } 10601 else if (e1.op == TOKvar) 10602 { 10603 VarExp ve = cast(VarExp)e1; 10604 VarDeclaration v = ve.var.isVarDeclaration(); 10605 if (v) 10606 { 10607 if (!v.canTakeAddressOf()) 10608 { 10609 error("cannot take address of %s", e1.toChars()); 10610 return new ErrorExp(); 10611 } 10612 if (sc.func && !sc.intypeof && !v.isDataseg()) 10613 { 10614 if (sc.func.setUnsafe()) 10615 { 10616 const(char)* p = v.isParameter() ? "parameter" : "local"; 10617 error("cannot take address of %s %s in @safe function %s", p, v.toChars(), sc.func.toChars()); 10618 } 10619 } 10620 10621 ve.checkPurity(sc, v); 10622 } 10623 FuncDeclaration f = ve.var.isFuncDeclaration(); 10624 if (f) 10625 { 10626 /* Because nested functions cannot be overloaded, 10627 * mark here that we took its address because castTo() 10628 * may not be called with an exact match. 10629 */ 10630 if (!ve.hasOverloads || f.isNested()) 10631 f.tookAddressOf++; 10632 if (f.isNested()) 10633 { 10634 if (f.isFuncLiteralDeclaration()) 10635 { 10636 if (!f.FuncDeclaration.isNested()) 10637 { 10638 /* Supply a 'null' for a this pointer if no this is available 10639 */ 10640 Expression e = new DelegateExp(loc, new NullExp(loc, Type.tnull), f, ve.hasOverloads); 10641 e = e.semantic(sc); 10642 return e; 10643 } 10644 } 10645 Expression e = new DelegateExp(loc, e1, f, ve.hasOverloads); 10646 e = e.semantic(sc); 10647 return e; 10648 } 10649 if (f.needThis()) 10650 { 10651 if (hasThis(sc)) 10652 { 10653 /* Should probably supply 'this' after overload resolution, 10654 * not before. 10655 */ 10656 Expression ethis = new ThisExp(loc); 10657 Expression e = new DelegateExp(loc, ethis, f, ve.hasOverloads); 10658 e = e.semantic(sc); 10659 return e; 10660 } 10661 if (sc.func && !sc.intypeof) 10662 { 10663 if (sc.func.setUnsafe()) 10664 { 10665 error("'this' reference necessary to take address of member %s in @safe function %s", f.toChars(), sc.func.toChars()); 10666 } 10667 } 10668 } 10669 } 10670 } 10671 else if (e1.op == TOKcall) 10672 { 10673 CallExp ce = cast(CallExp)e1; 10674 if (ce.e1.type.ty == Tfunction) 10675 { 10676 TypeFunction tf = cast(TypeFunction)ce.e1.type; 10677 if (tf.isref && sc.func && !sc.intypeof && sc.func.setUnsafe()) 10678 { 10679 error("cannot take address of ref return of %s() in @safe function %s", 10680 ce.e1.toChars(), sc.func.toChars()); 10681 } 10682 } 10683 } 10684 else if (wasCond) 10685 { 10686 /* a ? b : c was transformed to *(a ? &b : &c), but we still 10687 * need to do safety checks 10688 */ 10689 assert(e1.op == TOKstar); 10690 PtrExp pe = cast(PtrExp)e1; 10691 assert(pe.e1.op == TOKquestion); 10692 CondExp ce = cast(CondExp)pe.e1; 10693 assert(ce.e1.op == TOKaddress); 10694 assert(ce.e2.op == TOKaddress); 10695 10696 // Re-run semantic on the address expressions only 10697 ce.e1.type = null; 10698 ce.e1 = ce.e1.semantic(sc); 10699 ce.e2.type = null; 10700 ce.e2 = ce.e2.semantic(sc); 10701 } 10702 return optimize(WANTvalue); 10703 } 10704 10705 override void accept(Visitor v) 10706 { 10707 v.visit(this); 10708 } 10709 } 10710 10711 /*********************************************************** 10712 */ 10713 extern (C++) final class PtrExp : UnaExp 10714 { 10715 extern (D) this(Loc loc, Expression e) 10716 { 10717 super(loc, TOKstar, __traits(classInstanceSize, PtrExp), e); 10718 //if (e->type) 10719 // type = ((TypePointer *)e->type)->next; 10720 } 10721 10722 extern (D) this(Loc loc, Expression e, Type t) 10723 { 10724 super(loc, TOKstar, __traits(classInstanceSize, PtrExp), e); 10725 type = t; 10726 } 10727 10728 override Expression semantic(Scope* sc) 10729 { 10730 static if (LOGSEMANTIC) 10731 { 10732 printf("PtrExp::semantic('%s')\n", toChars()); 10733 } 10734 if (type) 10735 return this; 10736 10737 Expression e = op_overload(sc); 10738 if (e) 10739 return e; 10740 10741 Type tb = e1.type.toBasetype(); 10742 switch (tb.ty) 10743 { 10744 case Tpointer: 10745 type = (cast(TypePointer)tb).next; 10746 break; 10747 10748 case Tsarray: 10749 case Tarray: 10750 if (isNonAssignmentArrayOp(e1)) 10751 goto default; 10752 error("using * on an array is no longer supported; use *(%s).ptr instead", e1.toChars()); 10753 type = (cast(TypeArray)tb).next; 10754 e1 = e1.castTo(sc, type.pointerTo()); 10755 break; 10756 10757 default: 10758 error("can only * a pointer, not a '%s'", e1.type.toChars()); 10759 goto case Terror; 10760 case Terror: 10761 return new ErrorExp(); 10762 } 10763 if (checkValue()) 10764 return new ErrorExp(); 10765 10766 return this; 10767 } 10768 10769 override int checkModifiable(Scope* sc, int flag) 10770 { 10771 if (e1.op == TOKsymoff) 10772 { 10773 SymOffExp se = cast(SymOffExp)e1; 10774 return se.var.checkModify(loc, sc, type, null, flag); 10775 } 10776 else if (e1.op == TOKaddress) 10777 { 10778 AddrExp ae = cast(AddrExp)e1; 10779 return ae.e1.checkModifiable(sc, flag); 10780 } 10781 return 1; 10782 } 10783 10784 override bool isLvalue() 10785 { 10786 return true; 10787 } 10788 10789 override Expression toLvalue(Scope* sc, Expression e) 10790 { 10791 return this; 10792 } 10793 10794 override Expression modifiableLvalue(Scope* sc, Expression e) 10795 { 10796 //printf("PtrExp::modifiableLvalue() %s, type %s\n", toChars(), type->toChars()); 10797 return Expression.modifiableLvalue(sc, e); 10798 } 10799 10800 override void accept(Visitor v) 10801 { 10802 v.visit(this); 10803 } 10804 } 10805 10806 /*********************************************************** 10807 */ 10808 extern (C++) final class NegExp : UnaExp 10809 { 10810 extern (D) this(Loc loc, Expression e) 10811 { 10812 super(loc, TOKneg, __traits(classInstanceSize, NegExp), e); 10813 } 10814 10815 override Expression semantic(Scope* sc) 10816 { 10817 static if (LOGSEMANTIC) 10818 { 10819 printf("NegExp::semantic('%s')\n", toChars()); 10820 } 10821 if (type) 10822 return this; 10823 10824 Expression e = op_overload(sc); 10825 if (e) 10826 return e; 10827 10828 type = e1.type; 10829 Type tb = type.toBasetype(); 10830 if (tb.ty == Tarray || tb.ty == Tsarray) 10831 { 10832 if (!isArrayOpValid(e1)) 10833 { 10834 error("invalid array operation %s (possible missing [])", toChars()); 10835 return new ErrorExp(); 10836 } 10837 return this; 10838 } 10839 10840 if (e1.checkNoBool()) 10841 return new ErrorExp(); 10842 if (e1.checkArithmetic()) 10843 return new ErrorExp(); 10844 10845 return this; 10846 } 10847 10848 override void accept(Visitor v) 10849 { 10850 v.visit(this); 10851 } 10852 } 10853 10854 /*********************************************************** 10855 */ 10856 extern (C++) final class UAddExp : UnaExp 10857 { 10858 extern (D) this(Loc loc, Expression e) 10859 { 10860 super(loc, TOKuadd, __traits(classInstanceSize, UAddExp), e); 10861 } 10862 10863 override Expression semantic(Scope* sc) 10864 { 10865 static if (LOGSEMANTIC) 10866 { 10867 printf("UAddExp::semantic('%s')\n", toChars()); 10868 } 10869 assert(!type); 10870 10871 Expression e = op_overload(sc); 10872 if (e) 10873 return e; 10874 10875 if (e1.checkNoBool()) 10876 return new ErrorExp(); 10877 if (e1.checkArithmetic()) 10878 return new ErrorExp(); 10879 10880 return e1; 10881 } 10882 10883 override void accept(Visitor v) 10884 { 10885 v.visit(this); 10886 } 10887 } 10888 10889 /*********************************************************** 10890 */ 10891 extern (C++) final class ComExp : UnaExp 10892 { 10893 extern (D) this(Loc loc, Expression e) 10894 { 10895 super(loc, TOKtilde, __traits(classInstanceSize, ComExp), e); 10896 } 10897 10898 override Expression semantic(Scope* sc) 10899 { 10900 if (type) 10901 return this; 10902 10903 Expression e = op_overload(sc); 10904 if (e) 10905 return e; 10906 10907 type = e1.type; 10908 Type tb = type.toBasetype(); 10909 if (tb.ty == Tarray || tb.ty == Tsarray) 10910 { 10911 if (!isArrayOpValid(e1)) 10912 { 10913 error("invalid array operation %s (possible missing [])", toChars()); 10914 return new ErrorExp(); 10915 } 10916 return this; 10917 } 10918 10919 if (e1.checkNoBool()) 10920 return new ErrorExp(); 10921 if (e1.checkIntegral()) 10922 return new ErrorExp(); 10923 10924 return this; 10925 } 10926 10927 override void accept(Visitor v) 10928 { 10929 v.visit(this); 10930 } 10931 } 10932 10933 /*********************************************************** 10934 */ 10935 extern (C++) final class NotExp : UnaExp 10936 { 10937 extern (D) this(Loc loc, Expression e) 10938 { 10939 super(loc, TOKnot, __traits(classInstanceSize, NotExp), e); 10940 } 10941 10942 override Expression semantic(Scope* sc) 10943 { 10944 if (type) 10945 return this; 10946 10947 setNoderefOperand(); 10948 10949 // Note there is no operator overload 10950 if (Expression ex = unaSemantic(sc)) 10951 return ex; 10952 e1 = resolveProperties(sc, e1); 10953 e1 = e1.toBoolean(sc); 10954 if (e1.type == Type.terror) 10955 return e1; 10956 10957 // Bugzilla 13910: Today NotExp can take an array as its operand. 10958 if (checkNonAssignmentArrayOp(e1)) 10959 return new ErrorExp(); 10960 10961 type = Type.tbool; 10962 return this; 10963 } 10964 10965 override void accept(Visitor v) 10966 { 10967 v.visit(this); 10968 } 10969 } 10970 10971 /*********************************************************** 10972 */ 10973 extern (C++) final class DeleteExp : UnaExp 10974 { 10975 extern (D) this(Loc loc, Expression e) 10976 { 10977 super(loc, TOKdelete, __traits(classInstanceSize, DeleteExp), e); 10978 } 10979 10980 override Expression semantic(Scope* sc) 10981 { 10982 if (Expression ex = unaSemantic(sc)) 10983 return ex; 10984 e1 = resolveProperties(sc, e1); 10985 e1 = e1.modifiableLvalue(sc, null); 10986 if (e1.op == TOKerror) 10987 return e1; 10988 type = Type.tvoid; 10989 10990 AggregateDeclaration ad = null; 10991 Type tb = e1.type.toBasetype(); 10992 switch (tb.ty) 10993 { 10994 case Tclass: 10995 { 10996 auto cd = (cast(TypeClass)tb).sym; 10997 if (cd.isCOMinterface()) 10998 { 10999 /* Because COM classes are deleted by IUnknown.Release() 11000 */ 11001 error("cannot delete instance of COM interface %s", cd.toChars()); 11002 return new ErrorExp(); 11003 } 11004 11005 ad = cd; 11006 break; 11007 } 11008 case Tpointer: 11009 tb = (cast(TypePointer)tb).next.toBasetype(); 11010 if (tb.ty == Tstruct) 11011 { 11012 ad = (cast(TypeStruct)tb).sym; 11013 auto f = ad.aggDelete; 11014 auto fd = ad.dtor; 11015 if (!f) 11016 { 11017 semanticTypeInfo(sc, tb); 11018 break; 11019 } 11020 11021 /* Construct: 11022 * ea = copy e1 to a tmp to do side effects only once 11023 * eb = call destructor 11024 * ec = call deallocator 11025 */ 11026 Expression ea = null; 11027 Expression eb = null; 11028 Expression ec = null; 11029 VarDeclaration v = null; 11030 if (fd && f) 11031 { 11032 v = copyToTemp(0, "__tmpea", e1); 11033 v.semantic(sc); 11034 ea = new DeclarationExp(loc, v); 11035 ea.type = v.type; 11036 } 11037 if (fd) 11038 { 11039 Expression e = ea ? new VarExp(loc, v) : e1; 11040 e = new DotVarExp(Loc(), e, fd, false); 11041 eb = new CallExp(loc, e); 11042 eb = eb.semantic(sc); 11043 } 11044 if (f) 11045 { 11046 Type tpv = Type.tvoid.pointerTo(); 11047 Expression e = ea ? new VarExp(loc, v) : e1.castTo(sc, tpv); 11048 e = new CallExp(loc, new VarExp(loc, f, false), e); 11049 ec = e.semantic(sc); 11050 } 11051 ea = combine(ea, eb); 11052 ea = combine(ea, ec); 11053 assert(ea); 11054 return ea; 11055 } 11056 break; 11057 11058 case Tarray: 11059 { 11060 Type tv = tb.nextOf().baseElemOf(); 11061 if (tv.ty == Tstruct) 11062 { 11063 ad = (cast(TypeStruct)tv).sym; 11064 if (ad.dtor) 11065 semanticTypeInfo(sc, ad.type); 11066 } 11067 break; 11068 } 11069 default: 11070 error("cannot delete type %s", e1.type.toChars()); 11071 return new ErrorExp(); 11072 } 11073 11074 bool err = false; 11075 if (ad) 11076 { 11077 if (ad.dtor) 11078 { 11079 err |= checkPurity(sc, ad.dtor); 11080 err |= checkSafety(sc, ad.dtor); 11081 err |= checkNogc(sc, ad.dtor); 11082 } 11083 if (ad.aggDelete && tb.ty != Tarray) 11084 { 11085 err |= checkPurity(sc, ad.aggDelete); 11086 err |= checkSafety(sc, ad.aggDelete); 11087 err |= checkNogc(sc, ad.aggDelete); 11088 } 11089 if (err) 11090 return new ErrorExp(); 11091 } 11092 11093 // unsafe 11094 if (!sc.intypeof && sc.func && sc.func.setUnsafe()) 11095 { 11096 error("%s is not @safe but is used in @safe function %s", toChars(), sc.func.toChars()); 11097 err = true; 11098 } 11099 if (err) 11100 return new ErrorExp(); 11101 11102 return this; 11103 } 11104 11105 override Expression toBoolean(Scope* sc) 11106 { 11107 error("delete does not give a boolean result"); 11108 return new ErrorExp(); 11109 } 11110 11111 override void accept(Visitor v) 11112 { 11113 v.visit(this); 11114 } 11115 } 11116 11117 /*********************************************************** 11118 * Possible to cast to one type while painting to another type 11119 */ 11120 extern (C++) final class CastExp : UnaExp 11121 { 11122 Type to; // type to cast to 11123 ubyte mod = cast(ubyte)~0; // MODxxxxx 11124 11125 extern (D) this(Loc loc, Expression e, Type t) 11126 { 11127 super(loc, TOKcast, __traits(classInstanceSize, CastExp), e); 11128 this.to = t; 11129 } 11130 11131 /* For cast(const) and cast(immutable) 11132 */ 11133 extern (D) this(Loc loc, Expression e, ubyte mod) 11134 { 11135 super(loc, TOKcast, __traits(classInstanceSize, CastExp), e); 11136 this.mod = mod; 11137 } 11138 11139 override Expression syntaxCopy() 11140 { 11141 return to ? new CastExp(loc, e1.syntaxCopy(), to.syntaxCopy()) : new CastExp(loc, e1.syntaxCopy(), mod); 11142 } 11143 11144 override Expression semantic(Scope* sc) 11145 { 11146 static if (LOGSEMANTIC) 11147 { 11148 printf("CastExp::semantic('%s')\n", toChars()); 11149 } 11150 //static int x; assert(++x < 10); 11151 if (type) 11152 return this; 11153 11154 if (to) 11155 { 11156 to = to.semantic(loc, sc); 11157 if (to == Type.terror) 11158 return new ErrorExp(); 11159 11160 if (!to.hasPointers()) 11161 setNoderefOperand(); 11162 11163 // When e1 is a template lambda, this cast may instantiate it with 11164 // the type 'to'. 11165 e1 = inferType(e1, to); 11166 } 11167 11168 if (auto e = unaSemantic(sc)) 11169 return e; 11170 auto e1x = resolveProperties(sc, e1); 11171 if (e1x.op == TOKerror) 11172 return e1x; 11173 if (e1x.checkType()) 11174 return new ErrorExp(); 11175 e1 = e1x; 11176 11177 if (!e1.type) 11178 { 11179 error("cannot cast %s", e1.toChars()); 11180 return new ErrorExp(); 11181 } 11182 11183 if (!to) // Handle cast(const) and cast(immutable), etc. 11184 { 11185 to = e1.type.castMod(mod); 11186 to = to.semantic(loc, sc); 11187 if (to == Type.terror) 11188 return new ErrorExp(); 11189 } 11190 11191 if (to.ty == Ttuple) 11192 { 11193 error("cannot cast %s to tuple type %s", e1.toChars(), to.toChars()); 11194 return new ErrorExp(); 11195 } 11196 11197 // cast(void) is used to mark e1 as unused, so it is safe 11198 if (to.ty == Tvoid) 11199 { 11200 type = to; 11201 return this; 11202 } 11203 11204 if (!to.equals(e1.type) && mod == cast(ubyte)~0) 11205 { 11206 if (Expression e = op_overload(sc)) 11207 return e.implicitCastTo(sc, to); 11208 } 11209 11210 Type t1b = e1.type.toBasetype(); 11211 Type tob = to.toBasetype(); 11212 11213 if (tob.ty == Tstruct && !tob.equals(t1b)) 11214 { 11215 /* Look to replace: 11216 * cast(S)t 11217 * with: 11218 * S(t) 11219 */ 11220 11221 // Rewrite as to.call(e1) 11222 Expression e = new TypeExp(loc, to); 11223 e = new CallExp(loc, e, e1); 11224 e = e.trySemantic(sc); 11225 if (e) 11226 return e; 11227 } 11228 11229 if (!t1b.equals(tob) && (t1b.ty == Tarray || t1b.ty == Tsarray)) 11230 { 11231 if (checkNonAssignmentArrayOp(e1)) 11232 return new ErrorExp(); 11233 } 11234 11235 // Look for casting to a vector type 11236 if (tob.ty == Tvector && t1b.ty != Tvector) 11237 { 11238 return new VectorExp(loc, e1, to); 11239 } 11240 11241 Expression ex = e1.castTo(sc, to); 11242 if (ex.op == TOKerror) 11243 return ex; 11244 11245 // Check for unsafe casts 11246 if (sc.func && !sc.intypeof && 11247 !isSafeCast(ex, t1b, tob) && 11248 sc.func.setUnsafe()) 11249 { 11250 error("cast from %s to %s not allowed in safe code", e1.type.toChars(), to.toChars()); 11251 return new ErrorExp(); 11252 } 11253 11254 return ex; 11255 } 11256 11257 override void accept(Visitor v) 11258 { 11259 v.visit(this); 11260 } 11261 } 11262 11263 /*********************************************************** 11264 */ 11265 extern (C++) final class VectorExp : UnaExp 11266 { 11267 TypeVector to; // the target vector type before semantic() 11268 uint dim = ~0; // number of elements in the vector 11269 11270 extern (D) this(Loc loc, Expression e, Type t) 11271 { 11272 super(loc, TOKvector, __traits(classInstanceSize, VectorExp), e); 11273 assert(t.ty == Tvector); 11274 to = cast(TypeVector)t; 11275 } 11276 11277 override Expression syntaxCopy() 11278 { 11279 return new VectorExp(loc, e1.syntaxCopy(), to.syntaxCopy()); 11280 } 11281 11282 override Expression semantic(Scope* sc) 11283 { 11284 static if (LOGSEMANTIC) 11285 { 11286 printf("VectorExp::semantic('%s')\n", toChars()); 11287 } 11288 if (type) 11289 return this; 11290 11291 e1 = e1.semantic(sc); 11292 type = to.semantic(loc, sc); 11293 if (e1.op == TOKerror || type.ty == Terror) 11294 return e1; 11295 11296 Type tb = type.toBasetype(); 11297 assert(tb.ty == Tvector); 11298 TypeVector tv = cast(TypeVector)tb; 11299 Type te = tv.elementType(); 11300 dim = cast(int)(tv.size(loc) / te.size(loc)); 11301 11302 bool checkElem(Expression elem) 11303 { 11304 if (elem.isConst() == 1) 11305 return false; 11306 11307 error("constant expression expected, not %s", elem.toChars()); 11308 return true; 11309 } 11310 11311 e1 = e1.optimize(WANTvalue); 11312 bool result; 11313 if (e1.op == TOKarrayliteral) 11314 { 11315 foreach (i; 0 .. dim) 11316 { 11317 // Do not stop on first error - check all AST nodes even if error found 11318 result |= checkElem((cast(ArrayLiteralExp)e1).getElement(i)); 11319 } 11320 } 11321 else 11322 result = checkElem(e1); 11323 11324 return result ? new ErrorExp() : this; 11325 } 11326 11327 override void accept(Visitor v) 11328 { 11329 v.visit(this); 11330 } 11331 } 11332 11333 /*********************************************************** 11334 */ 11335 extern (C++) final class SliceExp : UnaExp 11336 { 11337 Expression upr; // null if implicit 0 11338 Expression lwr; // null if implicit [length - 1] 11339 VarDeclaration lengthVar; 11340 bool upperIsInBounds; // true if upr <= e1.length 11341 bool lowerIsLessThanUpper; // true if lwr <= upr 11342 11343 /************************************************************/ 11344 extern (D) this(Loc loc, Expression e1, IntervalExp ie) 11345 { 11346 super(loc, TOKslice, __traits(classInstanceSize, SliceExp), e1); 11347 this.upr = ie ? ie.upr : null; 11348 this.lwr = ie ? ie.lwr : null; 11349 } 11350 11351 extern (D) this(Loc loc, Expression e1, Expression lwr, Expression upr) 11352 { 11353 super(loc, TOKslice, __traits(classInstanceSize, SliceExp), e1); 11354 this.upr = upr; 11355 this.lwr = lwr; 11356 } 11357 11358 override Expression syntaxCopy() 11359 { 11360 auto se = new SliceExp(loc, e1.syntaxCopy(), lwr ? lwr.syntaxCopy() : null, upr ? upr.syntaxCopy() : null); 11361 se.lengthVar = this.lengthVar; // bug7871 11362 return se; 11363 } 11364 11365 override Expression semantic(Scope* sc) 11366 { 11367 static if (LOGSEMANTIC) 11368 { 11369 printf("SliceExp::semantic('%s')\n", toChars()); 11370 } 11371 if (type) 11372 return this; 11373 11374 // operator overloading should be handled in ArrayExp already. 11375 if (Expression ex = unaSemantic(sc)) 11376 return ex; 11377 e1 = resolveProperties(sc, e1); 11378 if (e1.op == TOKtype && e1.type.ty != Ttuple) 11379 { 11380 if (lwr || upr) 11381 { 11382 error("cannot slice type '%s'", e1.toChars()); 11383 return new ErrorExp(); 11384 } 11385 Expression e = new TypeExp(loc, e1.type.arrayOf()); 11386 return e.semantic(sc); 11387 } 11388 if (!lwr && !upr) 11389 { 11390 if (e1.op == TOKarrayliteral) 11391 { 11392 // Convert [a,b,c][] to [a,b,c] 11393 Type t1b = e1.type.toBasetype(); 11394 Expression e = e1; 11395 if (t1b.ty == Tsarray) 11396 { 11397 e = e.copy(); 11398 e.type = t1b.nextOf().arrayOf(); 11399 } 11400 return e; 11401 } 11402 if (e1.op == TOKslice) 11403 { 11404 // Convert e[][] to e[] 11405 SliceExp se = cast(SliceExp)e1; 11406 if (!se.lwr && !se.upr) 11407 return se; 11408 } 11409 if (isArrayOpOperand(e1)) 11410 { 11411 // Convert (a[]+b[])[] to a[]+b[] 11412 return e1; 11413 } 11414 } 11415 if (e1.op == TOKerror) 11416 return e1; 11417 if (e1.type.ty == Terror) 11418 return new ErrorExp(); 11419 11420 Type t1b = e1.type.toBasetype(); 11421 if (t1b.ty == Tpointer) 11422 { 11423 if ((cast(TypePointer)t1b).next.ty == Tfunction) 11424 { 11425 error("cannot slice function pointer %s", e1.toChars()); 11426 return new ErrorExp(); 11427 } 11428 if (!lwr || !upr) 11429 { 11430 error("need upper and lower bound to slice pointer"); 11431 return new ErrorExp(); 11432 } 11433 if (sc.func && !sc.intypeof && sc.func.setUnsafe()) 11434 { 11435 error("pointer slicing not allowed in safe functions"); 11436 return new ErrorExp(); 11437 } 11438 } 11439 else if (t1b.ty == Tarray) 11440 { 11441 } 11442 else if (t1b.ty == Tsarray) 11443 { 11444 } 11445 else if (t1b.ty == Ttuple) 11446 { 11447 if (!lwr && !upr) 11448 return e1; 11449 if (!lwr || !upr) 11450 { 11451 error("need upper and lower bound to slice tuple"); 11452 return new ErrorExp(); 11453 } 11454 } 11455 else 11456 { 11457 error("%s cannot be sliced with []", t1b.ty == Tvoid ? e1.toChars() : t1b.toChars()); 11458 return new ErrorExp(); 11459 } 11460 11461 /* Run semantic on lwr and upr. 11462 */ 11463 Scope* scx = sc; 11464 if (t1b.ty == Tsarray || t1b.ty == Tarray || t1b.ty == Ttuple) 11465 { 11466 // Create scope for 'length' variable 11467 ScopeDsymbol sym = new ArrayScopeSymbol(sc, this); 11468 sym.loc = loc; 11469 sym.parent = sc.scopesym; 11470 sc = sc.push(sym); 11471 } 11472 if (lwr) 11473 { 11474 if (t1b.ty == Ttuple) 11475 sc = sc.startCTFE(); 11476 lwr = lwr.semantic(sc); 11477 lwr = resolveProperties(sc, lwr); 11478 if (t1b.ty == Ttuple) 11479 sc = sc.endCTFE(); 11480 lwr = lwr.implicitCastTo(sc, Type.tsize_t); 11481 } 11482 if (upr) 11483 { 11484 if (t1b.ty == Ttuple) 11485 sc = sc.startCTFE(); 11486 upr = upr.semantic(sc); 11487 upr = resolveProperties(sc, upr); 11488 if (t1b.ty == Ttuple) 11489 sc = sc.endCTFE(); 11490 upr = upr.implicitCastTo(sc, Type.tsize_t); 11491 } 11492 if (sc != scx) 11493 sc = sc.pop(); 11494 if (lwr && lwr.type == Type.terror || upr && upr.type == Type.terror) 11495 { 11496 return new ErrorExp(); 11497 } 11498 11499 if (t1b.ty == Ttuple) 11500 { 11501 lwr = lwr.ctfeInterpret(); 11502 upr = upr.ctfeInterpret(); 11503 uinteger_t i1 = lwr.toUInteger(); 11504 uinteger_t i2 = upr.toUInteger(); 11505 11506 TupleExp te; 11507 TypeTuple tup; 11508 size_t length; 11509 if (e1.op == TOKtuple) // slicing an expression tuple 11510 { 11511 te = cast(TupleExp)e1; 11512 tup = null; 11513 length = te.exps.dim; 11514 } 11515 else if (e1.op == TOKtype) // slicing a type tuple 11516 { 11517 te = null; 11518 tup = cast(TypeTuple)t1b; 11519 length = Parameter.dim(tup.arguments); 11520 } 11521 else 11522 assert(0); 11523 11524 if (i2 < i1 || length < i2) 11525 { 11526 error("string slice [%llu .. %llu] is out of bounds", i1, i2); 11527 return new ErrorExp(); 11528 } 11529 11530 size_t j1 = cast(size_t)i1; 11531 size_t j2 = cast(size_t)i2; 11532 Expression e; 11533 if (e1.op == TOKtuple) 11534 { 11535 auto exps = new Expressions(); 11536 exps.setDim(j2 - j1); 11537 for (size_t i = 0; i < j2 - j1; i++) 11538 { 11539 (*exps)[i] = (*te.exps)[j1 + i]; 11540 } 11541 e = new TupleExp(loc, te.e0, exps); 11542 } 11543 else 11544 { 11545 auto args = new Parameters(); 11546 args.reserve(j2 - j1); 11547 for (size_t i = j1; i < j2; i++) 11548 { 11549 Parameter arg = Parameter.getNth(tup.arguments, i); 11550 args.push(arg); 11551 } 11552 e = new TypeExp(e1.loc, new TypeTuple(args)); 11553 } 11554 e = e.semantic(sc); 11555 return e; 11556 } 11557 11558 type = t1b.nextOf().arrayOf(); 11559 // Allow typedef[] -> typedef[] 11560 if (type.equals(t1b)) 11561 type = e1.type; 11562 11563 if (lwr && upr) 11564 { 11565 lwr = lwr.optimize(WANTvalue); 11566 upr = upr.optimize(WANTvalue); 11567 11568 IntRange lwrRange = getIntRange(lwr); 11569 IntRange uprRange = getIntRange(upr); 11570 11571 if (t1b.ty == Tsarray || t1b.ty == Tarray) 11572 { 11573 Expression el = new ArrayLengthExp(loc, e1); 11574 el = el.semantic(sc); 11575 el = el.optimize(WANTvalue); 11576 if (el.op == TOKint64) 11577 { 11578 dinteger_t length = el.toInteger(); 11579 auto bounds = IntRange(SignExtendedNumber(0), SignExtendedNumber(length)); 11580 this.upperIsInBounds = bounds.contains(uprRange); 11581 } 11582 } 11583 else if (t1b.ty == Tpointer) 11584 { 11585 this.upperIsInBounds = true; 11586 } 11587 else 11588 assert(0); 11589 11590 this.lowerIsLessThanUpper = (lwrRange.imax <= uprRange.imin); 11591 11592 //printf("upperIsInBounds = %d lowerIsLessThanUpper = %d\n", upperIsInBounds, lowerIsLessThanUpper); 11593 } 11594 11595 return this; 11596 } 11597 11598 override int checkModifiable(Scope* sc, int flag) 11599 { 11600 //printf("SliceExp::checkModifiable %s\n", toChars()); 11601 if (e1.type.ty == Tsarray || (e1.op == TOKindex && e1.type.ty != Tarray) || e1.op == TOKslice) 11602 { 11603 return e1.checkModifiable(sc, flag); 11604 } 11605 return 1; 11606 } 11607 11608 override bool isLvalue() 11609 { 11610 /* slice expression is rvalue in default, but 11611 * conversion to reference of static array is only allowed. 11612 */ 11613 return (type && type.toBasetype().ty == Tsarray); 11614 } 11615 11616 override Expression toLvalue(Scope* sc, Expression e) 11617 { 11618 //printf("SliceExp::toLvalue(%s) type = %s\n", toChars(), type ? type->toChars() : NULL); 11619 return (type && type.toBasetype().ty == Tsarray) ? this : Expression.toLvalue(sc, e); 11620 } 11621 11622 override Expression modifiableLvalue(Scope* sc, Expression e) 11623 { 11624 error("slice expression %s is not a modifiable lvalue", toChars()); 11625 return this; 11626 } 11627 11628 override bool isBool(bool result) 11629 { 11630 return e1.isBool(result); 11631 } 11632 11633 override void accept(Visitor v) 11634 { 11635 v.visit(this); 11636 } 11637 } 11638 11639 /*********************************************************** 11640 */ 11641 extern (C++) final class ArrayLengthExp : UnaExp 11642 { 11643 extern (D) this(Loc loc, Expression e1) 11644 { 11645 super(loc, TOKarraylength, __traits(classInstanceSize, ArrayLengthExp), e1); 11646 } 11647 11648 override Expression semantic(Scope* sc) 11649 { 11650 static if (LOGSEMANTIC) 11651 { 11652 printf("ArrayLengthExp::semantic('%s')\n", toChars()); 11653 } 11654 if (type) 11655 return this; 11656 11657 if (Expression ex = unaSemantic(sc)) 11658 return ex; 11659 e1 = resolveProperties(sc, e1); 11660 11661 type = Type.tsize_t; 11662 return this; 11663 } 11664 11665 /********************* 11666 * Rewrite: 11667 * array.length op= e2 11668 * as: 11669 * array.length = array.length op e2 11670 * or: 11671 * auto tmp = &array; 11672 * (*tmp).length = (*tmp).length op e2 11673 */ 11674 static Expression rewriteOpAssign(BinExp exp) 11675 { 11676 Expression e; 11677 11678 assert(exp.e1.op == TOKarraylength); 11679 ArrayLengthExp ale = cast(ArrayLengthExp)exp.e1; 11680 if (ale.e1.op == TOKvar) 11681 { 11682 e = opAssignToOp(exp.loc, exp.op, ale, exp.e2); 11683 e = new AssignExp(exp.loc, ale.syntaxCopy(), e); 11684 } 11685 else 11686 { 11687 /* auto tmp = &array; 11688 * (*tmp).length = (*tmp).length op e2 11689 */ 11690 auto tmp = copyToTemp(0, "__arraylength", new AddrExp(ale.loc, ale.e1)); 11691 11692 Expression e1 = new ArrayLengthExp(ale.loc, new PtrExp(ale.loc, new VarExp(ale.loc, tmp))); 11693 Expression elvalue = e1.syntaxCopy(); 11694 e = opAssignToOp(exp.loc, exp.op, e1, exp.e2); 11695 e = new AssignExp(exp.loc, elvalue, e); 11696 e = new CommaExp(exp.loc, new DeclarationExp(ale.loc, tmp), e); 11697 } 11698 return e; 11699 } 11700 11701 override void accept(Visitor v) 11702 { 11703 v.visit(this); 11704 } 11705 } 11706 11707 /*********************************************************** 11708 * e1 [ a0, a1, a2, a3 ,... ] 11709 */ 11710 extern (C++) final class ArrayExp : UnaExp 11711 { 11712 Expressions* arguments; // Array of Expression's 11713 size_t currentDimension; // for opDollar 11714 VarDeclaration lengthVar; 11715 11716 extern (D) this(Loc loc, Expression e1, Expression index = null) 11717 { 11718 super(loc, TOKarray, __traits(classInstanceSize, ArrayExp), e1); 11719 arguments = new Expressions(); 11720 if (index) 11721 arguments.push(index); 11722 } 11723 11724 extern (D) this(Loc loc, Expression e1, Expressions* args) 11725 { 11726 super(loc, TOKarray, __traits(classInstanceSize, ArrayExp), e1); 11727 arguments = args; 11728 } 11729 11730 override Expression syntaxCopy() 11731 { 11732 auto ae = new ArrayExp(loc, e1.syntaxCopy(), arraySyntaxCopy(arguments)); 11733 ae.lengthVar = this.lengthVar; // bug7871 11734 return ae; 11735 } 11736 11737 override Expression semantic(Scope* sc) 11738 { 11739 static if (LOGSEMANTIC) 11740 { 11741 printf("ArrayExp::semantic('%s')\n", toChars()); 11742 } 11743 assert(!type); 11744 Expression e = op_overload(sc); 11745 if (e) 11746 return e; 11747 11748 if (isAggregate(e1.type)) 11749 error("no [] operator overload for type %s", e1.type.toChars()); 11750 else 11751 error("only one index allowed to index %s", e1.type.toChars()); 11752 return new ErrorExp(); 11753 } 11754 11755 override bool isLvalue() 11756 { 11757 if (type && type.toBasetype().ty == Tvoid) 11758 return false; 11759 return true; 11760 } 11761 11762 override Expression toLvalue(Scope* sc, Expression e) 11763 { 11764 if (type && type.toBasetype().ty == Tvoid) 11765 error("voids have no value"); 11766 return this; 11767 } 11768 11769 override void accept(Visitor v) 11770 { 11771 v.visit(this); 11772 } 11773 } 11774 11775 /*********************************************************** 11776 */ 11777 extern (C++) final class DotExp : BinExp 11778 { 11779 extern (D) this(Loc loc, Expression e1, Expression e2) 11780 { 11781 super(loc, TOKdot, __traits(classInstanceSize, DotExp), e1, e2); 11782 } 11783 11784 override Expression semantic(Scope* sc) 11785 { 11786 static if (LOGSEMANTIC) 11787 { 11788 printf("DotExp::semantic('%s')\n", toChars()); 11789 if (type) 11790 printf("\ttype = %s\n", type.toChars()); 11791 } 11792 e1 = e1.semantic(sc); 11793 e2 = e2.semantic(sc); 11794 11795 if (e1.op == TOKtype) 11796 return e2; 11797 if (e2.op == TOKtype) 11798 return e2; 11799 11800 if (e2.op == TOKtemplate) 11801 { 11802 auto td = (cast(TemplateExp)e2).td; 11803 Expression e = new DotTemplateExp(loc, e1, td); 11804 return e.semantic(sc); 11805 } 11806 if (!type) 11807 type = e2.type; 11808 return this; 11809 } 11810 11811 override void accept(Visitor v) 11812 { 11813 v.visit(this); 11814 } 11815 } 11816 11817 /*********************************************************** 11818 */ 11819 extern (C++) final class CommaExp : BinExp 11820 { 11821 /// This is needed because AssignExp rewrites CommaExp, hence it needs 11822 /// to trigger the deprecation. 11823 const bool isGenerated; 11824 11825 /// Temporary variable to enable / disable deprecation of comma expression 11826 /// depending on the context. 11827 /// Since most constructor calls are rewritting, the only place where 11828 /// false will be passed will be from the parser. 11829 bool allowCommaExp; 11830 11831 11832 extern (D) this(Loc loc, Expression e1, Expression e2, bool generated = true) 11833 { 11834 super(loc, TOKcomma, __traits(classInstanceSize, CommaExp), e1, e2); 11835 allowCommaExp = isGenerated = generated; 11836 } 11837 11838 override Expression semantic(Scope* sc) 11839 { 11840 if (type) 11841 return this; 11842 11843 // Allow `((a,b),(x,y))` 11844 if (allowCommaExp) 11845 { 11846 CommaExp.allow(e1); 11847 CommaExp.allow(e2); 11848 } 11849 11850 if (Expression ex = binSemanticProp(sc)) 11851 return ex; 11852 e1 = e1.addDtorHook(sc); 11853 11854 if (checkNonAssignmentArrayOp(e1)) 11855 return new ErrorExp(); 11856 11857 type = e2.type; 11858 if (type !is Type.tvoid && !allowCommaExp && !isGenerated) 11859 deprecation("Using the result of a comma expression is deprecated"); 11860 return this; 11861 } 11862 11863 override int checkModifiable(Scope* sc, int flag) 11864 { 11865 return e2.checkModifiable(sc, flag); 11866 } 11867 11868 override bool isLvalue() 11869 { 11870 return e2.isLvalue(); 11871 } 11872 11873 override Expression toLvalue(Scope* sc, Expression e) 11874 { 11875 e2 = e2.toLvalue(sc, null); 11876 return this; 11877 } 11878 11879 override Expression modifiableLvalue(Scope* sc, Expression e) 11880 { 11881 e2 = e2.modifiableLvalue(sc, e); 11882 return this; 11883 } 11884 11885 override bool isBool(bool result) 11886 { 11887 return e2.isBool(result); 11888 } 11889 11890 override Expression toBoolean(Scope* sc) 11891 { 11892 auto ex2 = e2.toBoolean(sc); 11893 if (ex2.op == TOKerror) 11894 return ex2; 11895 e2 = ex2; 11896 return this; 11897 } 11898 11899 override Expression addDtorHook(Scope* sc) 11900 { 11901 e2 = e2.addDtorHook(sc); 11902 return this; 11903 } 11904 11905 override void accept(Visitor v) 11906 { 11907 v.visit(this); 11908 } 11909 11910 /** 11911 * If the argument is a CommaExp, set a flag to prevent deprecation messages 11912 * 11913 * It's impossible to know from CommaExp.semantic if the result will 11914 * be used, hence when there is a result (type != void), a deprecation 11915 * message is always emitted. 11916 * However, some construct can produce a result but won't use it 11917 * (ExpStatement and for loop increment). Those should call this function 11918 * to prevent unwanted deprecations to be emitted. 11919 * 11920 * Params: 11921 * exp = An expression that discards its result. 11922 * If the argument is null or not a CommaExp, nothing happens. 11923 */ 11924 static void allow(Expression exp) 11925 { 11926 if (exp && exp.op == TOK.TOKcomma) 11927 (cast(CommaExp)exp).allowCommaExp = true; 11928 } 11929 } 11930 11931 /*********************************************************** 11932 * Mainly just a placeholder 11933 */ 11934 extern (C++) final class IntervalExp : Expression 11935 { 11936 Expression lwr; 11937 Expression upr; 11938 11939 extern (D) this(Loc loc, Expression lwr, Expression upr) 11940 { 11941 super(loc, TOKinterval, __traits(classInstanceSize, IntervalExp)); 11942 this.lwr = lwr; 11943 this.upr = upr; 11944 } 11945 11946 override Expression syntaxCopy() 11947 { 11948 return new IntervalExp(loc, lwr.syntaxCopy(), upr.syntaxCopy()); 11949 } 11950 11951 override Expression semantic(Scope* sc) 11952 { 11953 static if (LOGSEMANTIC) 11954 { 11955 printf("IntervalExp::semantic('%s')\n", toChars()); 11956 } 11957 if (type) 11958 return this; 11959 11960 Expression le = lwr; 11961 le = le.semantic(sc); 11962 le = resolveProperties(sc, le); 11963 11964 Expression ue = upr; 11965 ue = ue.semantic(sc); 11966 ue = resolveProperties(sc, ue); 11967 11968 if (le.op == TOKerror) 11969 return le; 11970 if (ue.op == TOKerror) 11971 return ue; 11972 11973 lwr = le; 11974 upr = ue; 11975 11976 type = Type.tvoid; 11977 return this; 11978 } 11979 11980 override Expression modifiableLvalue(Scope* sc, Expression e) 11981 { 11982 if (sc.func.setUnsafe()) 11983 { 11984 error("cannot modify delegate pointer in @safe code %s", toChars()); 11985 return new ErrorExp(); 11986 } 11987 return Expression.modifiableLvalue(sc, e); 11988 } 11989 11990 override void accept(Visitor v) 11991 { 11992 v.visit(this); 11993 } 11994 } 11995 11996 extern (C++) final class DelegatePtrExp : UnaExp 11997 { 11998 extern (D) this(Loc loc, Expression e1) 11999 { 12000 super(loc, TOKdelegateptr, __traits(classInstanceSize, DelegatePtrExp), e1); 12001 } 12002 12003 override Expression semantic(Scope* sc) 12004 { 12005 static if (LOGSEMANTIC) 12006 { 12007 printf("DelegatePtrExp::semantic('%s')\n", toChars()); 12008 } 12009 if (!type) 12010 { 12011 unaSemantic(sc); 12012 e1 = resolveProperties(sc, e1); 12013 12014 if (e1.op == TOKerror) 12015 return e1; 12016 type = Type.tvoidptr; 12017 } 12018 return this; 12019 } 12020 12021 override bool isLvalue() 12022 { 12023 return e1.isLvalue(); 12024 } 12025 12026 override Expression toLvalue(Scope* sc, Expression e) 12027 { 12028 e1 = e1.toLvalue(sc, e); 12029 return this; 12030 } 12031 12032 override Expression modifiableLvalue(Scope* sc, Expression e) 12033 { 12034 if (sc.func.setUnsafe()) 12035 { 12036 error("cannot modify delegate pointer in @safe code %s", toChars()); 12037 return new ErrorExp(); 12038 } 12039 return Expression.modifiableLvalue(sc, e); 12040 } 12041 12042 override void accept(Visitor v) 12043 { 12044 v.visit(this); 12045 } 12046 } 12047 12048 /*********************************************************** 12049 */ 12050 extern (C++) final class DelegateFuncptrExp : UnaExp 12051 { 12052 extern (D) this(Loc loc, Expression e1) 12053 { 12054 super(loc, TOKdelegatefuncptr, __traits(classInstanceSize, DelegateFuncptrExp), e1); 12055 } 12056 12057 override Expression semantic(Scope* sc) 12058 { 12059 static if (LOGSEMANTIC) 12060 { 12061 printf("DelegateFuncptrExp::semantic('%s')\n", toChars()); 12062 } 12063 if (!type) 12064 { 12065 unaSemantic(sc); 12066 e1 = resolveProperties(sc, e1); 12067 if (e1.op == TOKerror) 12068 return e1; 12069 type = e1.type.nextOf().pointerTo(); 12070 } 12071 return this; 12072 } 12073 12074 override bool isLvalue() 12075 { 12076 return e1.isLvalue(); 12077 } 12078 12079 override Expression toLvalue(Scope* sc, Expression e) 12080 { 12081 e1 = e1.toLvalue(sc, e); 12082 return this; 12083 } 12084 12085 override Expression modifiableLvalue(Scope* sc, Expression e) 12086 { 12087 if (sc.func.setUnsafe()) 12088 { 12089 error("cannot modify delegate function pointer in @safe code %s", toChars()); 12090 return new ErrorExp(); 12091 } 12092 return Expression.modifiableLvalue(sc, e); 12093 } 12094 12095 override void accept(Visitor v) 12096 { 12097 v.visit(this); 12098 } 12099 } 12100 12101 /*********************************************************** 12102 * e1 [ e2 ] 12103 */ 12104 extern (C++) final class IndexExp : BinExp 12105 { 12106 VarDeclaration lengthVar; 12107 bool modifiable = false; // assume it is an rvalue 12108 bool indexIsInBounds; // true if 0 <= e2 && e2 <= e1.length - 1 12109 12110 extern (D) this(Loc loc, Expression e1, Expression e2) 12111 { 12112 super(loc, TOKindex, __traits(classInstanceSize, IndexExp), e1, e2); 12113 //printf("IndexExp::IndexExp('%s')\n", toChars()); 12114 } 12115 12116 override Expression syntaxCopy() 12117 { 12118 auto ie = new IndexExp(loc, e1.syntaxCopy(), e2.syntaxCopy()); 12119 ie.lengthVar = this.lengthVar; // bug7871 12120 return ie; 12121 } 12122 12123 override Expression semantic(Scope* sc) 12124 { 12125 static if (LOGSEMANTIC) 12126 { 12127 printf("IndexExp::semantic('%s')\n", toChars()); 12128 } 12129 if (type) 12130 return this; 12131 12132 // operator overloading should be handled in ArrayExp already. 12133 if (!e1.type) 12134 e1 = e1.semantic(sc); 12135 assert(e1.type); // semantic() should already be run on it 12136 if (e1.op == TOKtype && e1.type.ty != Ttuple) 12137 { 12138 e2 = e2.semantic(sc); 12139 e2 = resolveProperties(sc, e2); 12140 Type nt; 12141 if (e2.op == TOKtype) 12142 nt = new TypeAArray(e1.type, e2.type); 12143 else 12144 nt = new TypeSArray(e1.type, e2); 12145 Expression e = new TypeExp(loc, nt); 12146 return e.semantic(sc); 12147 } 12148 if (e1.op == TOKerror) 12149 return e1; 12150 if (e1.type.ty == Terror) 12151 return new ErrorExp(); 12152 12153 // Note that unlike C we do not implement the int[ptr] 12154 12155 Type t1b = e1.type.toBasetype(); 12156 12157 /* Run semantic on e2 12158 */ 12159 Scope* scx = sc; 12160 if (t1b.ty == Tsarray || t1b.ty == Tarray || t1b.ty == Ttuple) 12161 { 12162 // Create scope for 'length' variable 12163 ScopeDsymbol sym = new ArrayScopeSymbol(sc, this); 12164 sym.loc = loc; 12165 sym.parent = sc.scopesym; 12166 sc = sc.push(sym); 12167 } 12168 if (t1b.ty == Ttuple) 12169 sc = sc.startCTFE(); 12170 e2 = e2.semantic(sc); 12171 e2 = resolveProperties(sc, e2); 12172 if (t1b.ty == Ttuple) 12173 sc = sc.endCTFE(); 12174 if (e2.op == TOKtuple) 12175 { 12176 TupleExp te = cast(TupleExp)e2; 12177 if (te.exps && te.exps.dim == 1) 12178 e2 = Expression.combine(te.e0, (*te.exps)[0]); // bug 4444 fix 12179 } 12180 if (sc != scx) 12181 sc = sc.pop(); 12182 if (e2.type == Type.terror) 12183 return new ErrorExp(); 12184 12185 if (checkNonAssignmentArrayOp(e1)) 12186 return new ErrorExp(); 12187 12188 switch (t1b.ty) 12189 { 12190 case Tpointer: 12191 if ((cast(TypePointer)t1b).next.ty == Tfunction) 12192 { 12193 error("cannot index function pointer %s", e1.toChars()); 12194 return new ErrorExp(); 12195 } 12196 e2 = e2.implicitCastTo(sc, Type.tsize_t); 12197 if (e2.type == Type.terror) 12198 return new ErrorExp(); 12199 e2 = e2.optimize(WANTvalue); 12200 if (e2.op == TOKint64 && e2.toInteger() == 0) 12201 { 12202 } 12203 else if (sc.func && sc.func.setUnsafe()) 12204 { 12205 error("safe function '%s' cannot index pointer '%s'", sc.func.toPrettyChars(), e1.toChars()); 12206 return new ErrorExp(); 12207 } 12208 type = (cast(TypeNext)t1b).next; 12209 break; 12210 12211 case Tarray: 12212 e2 = e2.implicitCastTo(sc, Type.tsize_t); 12213 if (e2.type == Type.terror) 12214 return new ErrorExp(); 12215 type = (cast(TypeNext)t1b).next; 12216 break; 12217 12218 case Tsarray: 12219 { 12220 e2 = e2.implicitCastTo(sc, Type.tsize_t); 12221 if (e2.type == Type.terror) 12222 return new ErrorExp(); 12223 type = t1b.nextOf(); 12224 break; 12225 } 12226 case Taarray: 12227 { 12228 TypeAArray taa = cast(TypeAArray)t1b; 12229 /* We can skip the implicit conversion if they differ only by 12230 * constness (Bugzilla 2684, see also bug 2954b) 12231 */ 12232 if (!arrayTypeCompatibleWithoutCasting(e2.loc, e2.type, taa.index)) 12233 { 12234 e2 = e2.implicitCastTo(sc, taa.index); // type checking 12235 if (e2.type == Type.terror) 12236 return new ErrorExp(); 12237 } 12238 12239 semanticTypeInfo(sc, taa); 12240 12241 type = taa.next; 12242 break; 12243 } 12244 case Ttuple: 12245 { 12246 e2 = e2.implicitCastTo(sc, Type.tsize_t); 12247 if (e2.type == Type.terror) 12248 return new ErrorExp(); 12249 e2 = e2.ctfeInterpret(); 12250 uinteger_t index = e2.toUInteger(); 12251 12252 TupleExp te; 12253 TypeTuple tup; 12254 size_t length; 12255 if (e1.op == TOKtuple) 12256 { 12257 te = cast(TupleExp)e1; 12258 tup = null; 12259 length = te.exps.dim; 12260 } 12261 else if (e1.op == TOKtype) 12262 { 12263 te = null; 12264 tup = cast(TypeTuple)t1b; 12265 length = Parameter.dim(tup.arguments); 12266 } 12267 else 12268 assert(0); 12269 12270 if (length <= index) 12271 { 12272 error("array index [%llu] is outside array bounds [0 .. %llu]", index, cast(ulong)length); 12273 return new ErrorExp(); 12274 } 12275 Expression e; 12276 if (e1.op == TOKtuple) 12277 { 12278 e = (*te.exps)[cast(size_t)index]; 12279 e = combine(te.e0, e); 12280 } 12281 else 12282 e = new TypeExp(e1.loc, Parameter.getNth(tup.arguments, cast(size_t)index).type); 12283 return e; 12284 } 12285 default: 12286 error("%s must be an array or pointer type, not %s", e1.toChars(), e1.type.toChars()); 12287 return new ErrorExp(); 12288 } 12289 12290 if (t1b.ty == Tsarray || t1b.ty == Tarray) 12291 { 12292 Expression el = new ArrayLengthExp(loc, e1); 12293 el = el.semantic(sc); 12294 el = el.optimize(WANTvalue); 12295 if (el.op == TOKint64) 12296 { 12297 e2 = e2.optimize(WANTvalue); 12298 dinteger_t length = el.toInteger(); 12299 if (length) 12300 { 12301 auto bounds = IntRange(SignExtendedNumber(0), SignExtendedNumber(length - 1)); 12302 indexIsInBounds = bounds.contains(getIntRange(e2)); 12303 } 12304 } 12305 } 12306 12307 return this; 12308 } 12309 12310 override int checkModifiable(Scope* sc, int flag) 12311 { 12312 if (e1.type.ty == Tsarray || e1.type.ty == Taarray || (e1.op == TOKindex && e1.type.ty != Tarray) || e1.op == TOKslice) 12313 { 12314 return e1.checkModifiable(sc, flag); 12315 } 12316 return 1; 12317 } 12318 12319 override bool isLvalue() 12320 { 12321 return true; 12322 } 12323 12324 override Expression toLvalue(Scope* sc, Expression e) 12325 { 12326 return this; 12327 } 12328 12329 override Expression modifiableLvalue(Scope* sc, Expression e) 12330 { 12331 //printf("IndexExp::modifiableLvalue(%s)\n", toChars()); 12332 Expression ex = markSettingAAElem(); 12333 if (ex.op == TOKerror) 12334 return ex; 12335 12336 return Expression.modifiableLvalue(sc, e); 12337 } 12338 12339 Expression markSettingAAElem() 12340 { 12341 if (e1.type.toBasetype().ty == Taarray) 12342 { 12343 Type t2b = e2.type.toBasetype(); 12344 if (t2b.ty == Tarray && t2b.nextOf().isMutable()) 12345 { 12346 error("associative arrays can only be assigned values with immutable keys, not %s", e2.type.toChars()); 12347 return new ErrorExp(); 12348 } 12349 modifiable = true; 12350 12351 if (e1.op == TOKindex) 12352 { 12353 Expression ex = (cast(IndexExp)e1).markSettingAAElem(); 12354 if (ex.op == TOKerror) 12355 return ex; 12356 assert(ex == e1); 12357 } 12358 } 12359 return this; 12360 } 12361 12362 override void accept(Visitor v) 12363 { 12364 v.visit(this); 12365 } 12366 } 12367 12368 /*********************************************************** 12369 * For both i++ and i-- 12370 */ 12371 extern (C++) final class PostExp : BinExp 12372 { 12373 extern (D) this(TOK op, Loc loc, Expression e) 12374 { 12375 super(loc, op, __traits(classInstanceSize, PostExp), e, new IntegerExp(loc, 1, Type.tint32)); 12376 } 12377 12378 override Expression semantic(Scope* sc) 12379 { 12380 static if (LOGSEMANTIC) 12381 { 12382 printf("PostExp::semantic('%s')\n", toChars()); 12383 } 12384 if (type) 12385 return this; 12386 12387 if (Expression ex = binSemantic(sc)) 12388 return ex; 12389 Expression e1x = resolveProperties(sc, e1); 12390 if (e1x.op == TOKerror) 12391 return e1x; 12392 e1 = e1x; 12393 12394 Expression e = op_overload(sc); 12395 if (e) 12396 return e; 12397 12398 if (e1.checkReadModifyWrite(op)) 12399 return new ErrorExp(); 12400 if (e1.op == TOKslice) 12401 { 12402 const(char)* s = op == TOKplusplus ? "increment" : "decrement"; 12403 error("cannot post-%s array slice '%s', use pre-%s instead", s, e1.toChars(), s); 12404 return new ErrorExp(); 12405 } 12406 12407 e1 = e1.optimize(WANTvalue); 12408 12409 Type t1 = e1.type.toBasetype(); 12410 if (t1.ty == Tclass || t1.ty == Tstruct || e1.op == TOKarraylength) 12411 { 12412 /* Check for operator overloading, 12413 * but rewrite in terms of ++e instead of e++ 12414 */ 12415 12416 /* If e1 is not trivial, take a reference to it 12417 */ 12418 Expression de = null; 12419 if (e1.op != TOKvar && e1.op != TOKarraylength) 12420 { 12421 // ref v = e1; 12422 auto v = copyToTemp(STCref, "__postref", e1); 12423 de = new DeclarationExp(loc, v); 12424 e1 = new VarExp(e1.loc, v); 12425 } 12426 12427 /* Rewrite as: 12428 * auto tmp = e1; ++e1; tmp 12429 */ 12430 auto tmp = copyToTemp(0, "__pitmp", e1); 12431 Expression ea = new DeclarationExp(loc, tmp); 12432 12433 Expression eb = e1.syntaxCopy(); 12434 eb = new PreExp(op == TOKplusplus ? TOKpreplusplus : TOKpreminusminus, loc, eb); 12435 12436 Expression ec = new VarExp(loc, tmp); 12437 12438 // Combine de,ea,eb,ec 12439 if (de) 12440 ea = new CommaExp(loc, de, ea); 12441 e = new CommaExp(loc, ea, eb); 12442 e = new CommaExp(loc, e, ec); 12443 e = e.semantic(sc); 12444 return e; 12445 } 12446 12447 e1 = e1.modifiableLvalue(sc, e1); 12448 12449 e = this; 12450 if (e1.checkScalar()) 12451 return new ErrorExp(); 12452 if (e1.checkNoBool()) 12453 return new ErrorExp(); 12454 12455 if (e1.type.ty == Tpointer) 12456 e = scaleFactor(this, sc); 12457 else 12458 e2 = e2.castTo(sc, e1.type); 12459 e.type = e1.type; 12460 return e; 12461 } 12462 12463 override void accept(Visitor v) 12464 { 12465 v.visit(this); 12466 } 12467 } 12468 12469 /*********************************************************** 12470 * For both ++i and --i 12471 */ 12472 extern (C++) final class PreExp : UnaExp 12473 { 12474 extern (D) this(TOK op, Loc loc, Expression e) 12475 { 12476 super(loc, op, __traits(classInstanceSize, PreExp), e); 12477 } 12478 12479 override Expression semantic(Scope* sc) 12480 { 12481 Expression e = op_overload(sc); 12482 // printf("PreExp::semantic('%s')\n", toChars()); 12483 if (e) 12484 return e; 12485 12486 // Rewrite as e1+=1 or e1-=1 12487 if (op == TOKpreplusplus) 12488 e = new AddAssignExp(loc, e1, new IntegerExp(loc, 1, Type.tint32)); 12489 else 12490 e = new MinAssignExp(loc, e1, new IntegerExp(loc, 1, Type.tint32)); 12491 return e.semantic(sc); 12492 } 12493 12494 override void accept(Visitor v) 12495 { 12496 v.visit(this); 12497 } 12498 } 12499 12500 enum MemorySet 12501 { 12502 blockAssign = 1, // setting the contents of an array 12503 referenceInit = 2, // setting the reference of STCref variable 12504 } 12505 12506 /*********************************************************** 12507 */ 12508 extern (C++) class AssignExp : BinExp 12509 { 12510 int memset; // combination of MemorySet flags 12511 12512 /************************************************************/ 12513 /* op can be TOKassign, TOKconstruct, or TOKblit */ 12514 final extern (D) this(Loc loc, Expression e1, Expression e2) 12515 { 12516 super(loc, TOKassign, __traits(classInstanceSize, AssignExp), e1, e2); 12517 } 12518 12519 override final Expression semantic(Scope* sc) 12520 { 12521 static if (LOGSEMANTIC) 12522 { 12523 printf("AssignExp::semantic('%s')\n", toChars()); 12524 } 12525 //printf("e1->op = %d, '%s'\n", e1->op, Token::toChars(e1->op)); 12526 //printf("e2->op = %d, '%s'\n", e2->op, Token::toChars(e2->op)); 12527 if (type) 12528 return this; 12529 12530 Expression e1old = e1; 12531 12532 if (e2.op == TOKcomma) 12533 { 12534 /* Rewrite to get rid of the comma from rvalue 12535 */ 12536 if (!(cast(CommaExp)e2).isGenerated) 12537 deprecation("Using the result of a comma expression is deprecated"); 12538 Expression e0; 12539 e2 = Expression.extractLast(e2, &e0); 12540 Expression e = Expression.combine(e0, this); 12541 return e.semantic(sc); 12542 } 12543 12544 /* Look for operator overloading of a[arguments] = e2. 12545 * Do it before e1->semantic() otherwise the ArrayExp will have been 12546 * converted to unary operator overloading already. 12547 */ 12548 if (e1.op == TOKarray) 12549 { 12550 Expression result; 12551 12552 ArrayExp ae = cast(ArrayExp)e1; 12553 ae.e1 = ae.e1.semantic(sc); 12554 ae.e1 = resolveProperties(sc, ae.e1); 12555 Expression ae1old = ae.e1; 12556 12557 const(bool) maybeSlice = 12558 (ae.arguments.dim == 0 || 12559 ae.arguments.dim == 1 && (*ae.arguments)[0].op == TOKinterval); 12560 12561 IntervalExp ie = null; 12562 if (maybeSlice && ae.arguments.dim) 12563 { 12564 assert((*ae.arguments)[0].op == TOKinterval); 12565 ie = cast(IntervalExp)(*ae.arguments)[0]; 12566 } 12567 while (true) 12568 { 12569 if (ae.e1.op == TOKerror) 12570 return ae.e1; 12571 Expression e0 = null; 12572 Expression ae1save = ae.e1; 12573 ae.lengthVar = null; 12574 12575 Type t1b = ae.e1.type.toBasetype(); 12576 AggregateDeclaration ad = isAggregate(t1b); 12577 if (!ad) 12578 break; 12579 if (search_function(ad, Id.indexass)) 12580 { 12581 // Deal with $ 12582 result = resolveOpDollar(sc, ae, &e0); 12583 if (!result) // a[i..j] = e2 might be: a.opSliceAssign(e2, i, j) 12584 goto Lfallback; 12585 if (result.op == TOKerror) 12586 return result; 12587 12588 result = e2.semantic(sc); 12589 if (result.op == TOKerror) 12590 return result; 12591 e2 = result; 12592 12593 /* Rewrite (a[arguments] = e2) as: 12594 * a.opIndexAssign(e2, arguments) 12595 */ 12596 Expressions* a = ae.arguments.copy(); 12597 a.insert(0, e2); 12598 result = new DotIdExp(loc, ae.e1, Id.indexass); 12599 result = new CallExp(loc, result, a); 12600 if (maybeSlice) // a[] = e2 might be: a.opSliceAssign(e2) 12601 result = result.trySemantic(sc); 12602 else 12603 result = result.semantic(sc); 12604 if (result) 12605 { 12606 result = Expression.combine(e0, result); 12607 return result; 12608 } 12609 } 12610 12611 Lfallback: 12612 if (maybeSlice && search_function(ad, Id.sliceass)) 12613 { 12614 // Deal with $ 12615 result = resolveOpDollar(sc, ae, ie, &e0); 12616 if (result.op == TOKerror) 12617 return result; 12618 12619 result = e2.semantic(sc); 12620 if (result.op == TOKerror) 12621 return result; 12622 e2 = result; 12623 12624 /* Rewrite (a[i..j] = e2) as: 12625 * a.opSliceAssign(e2, i, j) 12626 */ 12627 auto a = new Expressions(); 12628 a.push(e2); 12629 if (ie) 12630 { 12631 a.push(ie.lwr); 12632 a.push(ie.upr); 12633 } 12634 result = new DotIdExp(loc, ae.e1, Id.sliceass); 12635 result = new CallExp(loc, result, a); 12636 result = result.semantic(sc); 12637 result = Expression.combine(e0, result); 12638 return result; 12639 } 12640 12641 // No operator overloading member function found yet, but 12642 // there might be an alias this to try. 12643 if (ad.aliasthis && t1b != ae.att1) 12644 { 12645 if (!ae.att1 && t1b.checkAliasThisRec()) 12646 ae.att1 = t1b; 12647 12648 /* Rewrite (a[arguments] op e2) as: 12649 * a.aliasthis[arguments] op e2 12650 */ 12651 ae.e1 = resolveAliasThis(sc, ae1save, true); 12652 if (ae.e1) 12653 continue; 12654 } 12655 break; 12656 } 12657 ae.e1 = ae1old; // recovery 12658 ae.lengthVar = null; 12659 } 12660 12661 /* Run this->e1 semantic. 12662 */ 12663 { 12664 Expression e1x = e1; 12665 12666 /* With UFCS, e.f = value 12667 * Could mean: 12668 * .f(e, value) 12669 * or: 12670 * .f(e) = value 12671 */ 12672 if (e1x.op == TOKdotti) 12673 { 12674 DotTemplateInstanceExp dti = cast(DotTemplateInstanceExp)e1x; 12675 Expression e = dti.semanticY(sc, 1); 12676 if (!e) 12677 return resolveUFCSProperties(sc, e1x, e2); 12678 e1x = e; 12679 } 12680 else if (e1x.op == TOKdotid) 12681 { 12682 DotIdExp die = cast(DotIdExp)e1x; 12683 Expression e = die.semanticY(sc, 1); 12684 if (e && isDotOpDispatch(e)) 12685 { 12686 uint errors = global.startGagging(); 12687 e = resolvePropertiesX(sc, e, e2); 12688 if (global.endGagging(errors)) 12689 e = null; /* fall down to UFCS */ 12690 else 12691 return e; 12692 } 12693 if (!e) 12694 return resolveUFCSProperties(sc, e1x, e2); 12695 e1x = e; 12696 } 12697 else 12698 e1x = e1x.semantic(sc); 12699 12700 /* We have f = value. 12701 * Could mean: 12702 * f(value) 12703 * or: 12704 * f() = value 12705 */ 12706 if (Expression e = resolvePropertiesX(sc, e1x, e2)) 12707 return e; 12708 if (e1x.checkRightThis(sc)) 12709 return new ErrorExp(); 12710 e1 = e1x; 12711 assert(e1.type); 12712 } 12713 Type t1 = e1.type.toBasetype(); 12714 12715 /* Run this->e2 semantic. 12716 * Different from other binary expressions, the analysis of e2 12717 * depends on the result of e1 in assignments. 12718 */ 12719 { 12720 Expression e2x = inferType(e2, t1.baseElemOf()); 12721 e2x = e2x.semantic(sc); 12722 e2x = resolveProperties(sc, e2x); 12723 if (e2x.op == TOKerror) 12724 return e2x; 12725 if (e2x.checkValue()) 12726 return new ErrorExp(); 12727 e2 = e2x; 12728 } 12729 12730 /* Rewrite tuple assignment as a tuple of assignments. 12731 */ 12732 { 12733 Expression e2x = e2; 12734 12735 Ltupleassign: 12736 if (e1.op == TOKtuple && e2x.op == TOKtuple) 12737 { 12738 TupleExp tup1 = cast(TupleExp)e1; 12739 TupleExp tup2 = cast(TupleExp)e2x; 12740 size_t dim = tup1.exps.dim; 12741 Expression e = null; 12742 if (dim != tup2.exps.dim) 12743 { 12744 error("mismatched tuple lengths, %d and %d", cast(int)dim, cast(int)tup2.exps.dim); 12745 return new ErrorExp(); 12746 } 12747 if (dim == 0) 12748 { 12749 e = new IntegerExp(loc, 0, Type.tint32); 12750 e = new CastExp(loc, e, Type.tvoid); // avoid "has no effect" error 12751 e = combine(combine(tup1.e0, tup2.e0), e); 12752 } 12753 else 12754 { 12755 auto exps = new Expressions(); 12756 exps.setDim(dim); 12757 for (size_t i = 0; i < dim; i++) 12758 { 12759 Expression ex1 = (*tup1.exps)[i]; 12760 Expression ex2 = (*tup2.exps)[i]; 12761 (*exps)[i] = new AssignExp(loc, ex1, ex2); 12762 } 12763 e = new TupleExp(loc, combine(tup1.e0, tup2.e0), exps); 12764 } 12765 return e.semantic(sc); 12766 } 12767 12768 /* Look for form: e1 = e2->aliasthis. 12769 */ 12770 if (e1.op == TOKtuple) 12771 { 12772 TupleDeclaration td = isAliasThisTuple(e2x); 12773 if (!td) 12774 goto Lnomatch; 12775 12776 assert(e1.type.ty == Ttuple); 12777 TypeTuple tt = cast(TypeTuple)e1.type; 12778 12779 Expression e0; 12780 Expression ev = extractSideEffect(sc, "__tup", e0, e2x); 12781 12782 auto iexps = new Expressions(); 12783 iexps.push(ev); 12784 for (size_t u = 0; u < iexps.dim; u++) 12785 { 12786 Lexpand: 12787 Expression e = (*iexps)[u]; 12788 12789 Parameter arg = Parameter.getNth(tt.arguments, u); 12790 //printf("[%d] iexps->dim = %d, ", u, iexps->dim); 12791 //printf("e = (%s %s, %s), ", Token::tochars[e->op], e->toChars(), e->type->toChars()); 12792 //printf("arg = (%s, %s)\n", arg->toChars(), arg->type->toChars()); 12793 12794 if (!arg || !e.type.implicitConvTo(arg.type)) 12795 { 12796 // expand initializer to tuple 12797 if (expandAliasThisTuples(iexps, u) != -1) 12798 { 12799 if (iexps.dim <= u) 12800 break; 12801 goto Lexpand; 12802 } 12803 goto Lnomatch; 12804 } 12805 } 12806 e2x = new TupleExp(e2x.loc, e0, iexps); 12807 e2x = e2x.semantic(sc); 12808 if (e2x.op == TOKerror) 12809 return e2x; 12810 // Do not need to overwrite this->e2 12811 goto Ltupleassign; 12812 } 12813 Lnomatch: 12814 } 12815 12816 /* Inside constructor, if this is the first assignment of object field, 12817 * rewrite this to initializing the field. 12818 */ 12819 if (op == TOKassign && e1.checkModifiable(sc) == 2) 12820 { 12821 //printf("[%s] change to init - %s\n", loc.toChars(), toChars()); 12822 op = TOKconstruct; 12823 12824 // Bugzilla 13515: set Index::modifiable flag for complex AA element initialization 12825 if (e1.op == TOKindex) 12826 { 12827 Expression e1x = (cast(IndexExp)e1).markSettingAAElem(); 12828 if (e1x.op == TOKerror) 12829 return e1x; 12830 } 12831 } 12832 else if (op == TOKconstruct && e1.op == TOKvar && 12833 (cast(VarExp)e1).var.storage_class & (STCout | STCref)) 12834 { 12835 memset |= MemorySet.referenceInit; 12836 } 12837 12838 /* If it is an assignment from a 'foreign' type, 12839 * check for operator overloading. 12840 */ 12841 if (memset & MemorySet.referenceInit) 12842 { 12843 // If this is an initialization of a reference, 12844 // do nothing 12845 } 12846 else if (t1.ty == Tstruct) 12847 { 12848 auto e1x = e1; 12849 auto e2x = e2; 12850 auto sd = (cast(TypeStruct)t1).sym; 12851 12852 if (op == TOKconstruct) 12853 { 12854 Type t2 = e2x.type.toBasetype(); 12855 if (t2.ty == Tstruct && sd == (cast(TypeStruct)t2).sym) 12856 { 12857 sd.size(loc); 12858 if (sd.sizeok != SIZEOKdone) 12859 return new ErrorExp(); 12860 if (!sd.ctor) 12861 sd.ctor = sd.searchCtor(); 12862 12863 // Bugzilla 15661: Look for the form from last of comma chain. 12864 auto e2y = e2x; 12865 while (e2y.op == TOKcomma) 12866 e2y = (cast(CommaExp)e2y).e2; 12867 12868 CallExp ce = (e2y.op == TOKcall) ? cast(CallExp)e2y : null; 12869 DotVarExp dve = (ce && ce.e1.op == TOKdotvar) 12870 ? cast(DotVarExp)ce.e1 : null; 12871 if (sd.ctor && ce && dve && dve.var.isCtorDeclaration() && 12872 e2y.type.implicitConvTo(t1)) 12873 { 12874 /* Look for form of constructor call which is: 12875 * __ctmp.ctor(arguments...) 12876 */ 12877 12878 /* Before calling the constructor, initialize 12879 * variable with a bit copy of the default 12880 * initializer 12881 */ 12882 Expression einit; 12883 if (sd.zeroInit == 1 && !sd.isNested()) 12884 { 12885 // Bugzilla 14606: Always use BlitExp for the special expression: (struct = 0) 12886 einit = new IntegerExp(loc, 0, Type.tint32); 12887 } 12888 else if (sd.isNested()) 12889 { 12890 auto sle = new StructLiteralExp(loc, sd, null, t1); 12891 if (!sd.fill(loc, sle.elements, true)) 12892 return new ErrorExp(); 12893 if (checkFrameAccess(loc, sc, sd, sle.elements.dim)) 12894 return new ErrorExp(); 12895 sle.type = t1; 12896 12897 einit = sle; 12898 } 12899 else 12900 { 12901 einit = t1.defaultInit(loc); 12902 } 12903 auto ae = new BlitExp(loc, e1, einit); 12904 ae.type = e1x.type; 12905 12906 /* Replace __ctmp being constructed with e1. 12907 * We need to copy constructor call expression, 12908 * because it may be used in other place. 12909 */ 12910 auto dvx = cast(DotVarExp)dve.copy(); 12911 dvx.e1 = e1x; 12912 auto cx = cast(CallExp)ce.copy(); 12913 cx.e1 = dvx; 12914 12915 Expression e0; 12916 extractLast(e2x, &e0); 12917 12918 auto e = combine(ae, cx); 12919 e = combine(e0, e); 12920 e = e.semantic(sc); 12921 return e; 12922 } 12923 if (sd.postblit) 12924 { 12925 /* We have a copy constructor for this 12926 */ 12927 if (e2x.op == TOKquestion) 12928 { 12929 /* Rewrite as: 12930 * a ? e1 = b : e1 = c; 12931 */ 12932 CondExp econd = cast(CondExp)e2x; 12933 Expression ea1 = new ConstructExp(econd.e1.loc, e1x, econd.e1); 12934 Expression ea2 = new ConstructExp(econd.e1.loc, e1x, econd.e2); 12935 Expression e = new CondExp(loc, econd.econd, ea1, ea2); 12936 return e.semantic(sc); 12937 } 12938 12939 if (e2x.isLvalue()) 12940 { 12941 if (!e2x.type.implicitConvTo(e1x.type)) 12942 { 12943 error("conversion error from %s to %s", 12944 e2x.type.toChars(), e1x.type.toChars()); 12945 return new ErrorExp(); 12946 } 12947 12948 /* Rewrite as: 12949 * (e1 = e2).postblit(); 12950 * 12951 * Blit assignment e1 = e2 returns a reference to the original e1, 12952 * then call the postblit on it. 12953 */ 12954 Expression e = e1x.copy(); 12955 e.type = e.type.mutableOf(); 12956 e = new BlitExp(loc, e, e2x); 12957 e = new DotVarExp(loc, e, sd.postblit, false); 12958 e = new CallExp(loc, e); 12959 return e.semantic(sc); 12960 } 12961 else 12962 { 12963 /* The struct value returned from the function is transferred 12964 * so should not call the destructor on it. 12965 */ 12966 e2x = valueNoDtor(e2x); 12967 } 12968 } 12969 } 12970 else if (!e2x.implicitConvTo(t1)) 12971 { 12972 sd.size(loc); 12973 if (sd.sizeok != SIZEOKdone) 12974 return new ErrorExp(); 12975 if (!sd.ctor) 12976 sd.ctor = sd.searchCtor(); 12977 12978 if (sd.ctor) 12979 { 12980 /* Look for implicit constructor call 12981 * Rewrite as: 12982 * e1 = init, e1.ctor(e2) 12983 */ 12984 Expression einit; 12985 einit = new BlitExp(loc, e1x, e1x.type.defaultInit(loc)); 12986 einit.type = e1x.type; 12987 12988 Expression e; 12989 e = new DotIdExp(loc, e1x, Id.ctor); 12990 e = new CallExp(loc, e, e2x); 12991 e = new CommaExp(loc, einit, e); 12992 e = e.semantic(sc); 12993 return e; 12994 } 12995 if (search_function(sd, Id.call)) 12996 { 12997 /* Look for static opCall 12998 * (See bugzilla 2702 for more discussion) 12999 * Rewrite as: 13000 * e1 = typeof(e1).opCall(arguments) 13001 */ 13002 e2x = typeDotIdExp(e2x.loc, e1x.type, Id.call); 13003 e2x = new CallExp(loc, e2x, this.e2); 13004 13005 e2x = e2x.semantic(sc); 13006 e2x = resolveProperties(sc, e2x); 13007 if (e2x.op == TOKerror) 13008 return e2x; 13009 if (e2x.checkValue()) 13010 return new ErrorExp(); 13011 } 13012 } 13013 else // Bugzilla 11355 13014 { 13015 AggregateDeclaration ad2 = isAggregate(e2x.type); 13016 if (ad2 && ad2.aliasthis && !(att2 && e2x.type == att2)) 13017 { 13018 if (!att2 && e2.type.checkAliasThisRec()) 13019 att2 = e2.type; 13020 /* Rewrite (e1 op e2) as: 13021 * (e1 op e2.aliasthis) 13022 */ 13023 e2 = new DotIdExp(e2.loc, e2, ad2.aliasthis.ident); 13024 return semantic(sc); 13025 } 13026 } 13027 } 13028 else if (op == TOKassign) 13029 { 13030 if (e1x.op == TOKindex && (cast(IndexExp)e1x).e1.type.toBasetype().ty == Taarray) 13031 { 13032 /* 13033 * Rewrite: 13034 * aa[key] = e2; 13035 * as: 13036 * ref __aatmp = aa; 13037 * ref __aakey = key; 13038 * ref __aaval = e2; 13039 * (__aakey in __aatmp 13040 * ? __aatmp[__aakey].opAssign(__aaval) 13041 * : ConstructExp(__aatmp[__aakey], __aaval)); 13042 */ 13043 IndexExp ie = cast(IndexExp)e1x; 13044 Type t2 = e2x.type.toBasetype(); 13045 13046 Expression e0 = null; 13047 Expression ea = extractSideEffect(sc, "__aatmp", e0, ie.e1); 13048 Expression ek = extractSideEffect(sc, "__aakey", e0, ie.e2); 13049 Expression ev = extractSideEffect(sc, "__aaval", e0, e2x); 13050 13051 AssignExp ae = cast(AssignExp)copy(); 13052 ae.e1 = new IndexExp(loc, ea, ek); 13053 ae.e1 = ae.e1.semantic(sc); 13054 ae.e1 = ae.e1.optimize(WANTvalue); 13055 ae.e2 = ev; 13056 Expression e = ae.op_overload(sc); 13057 if (e) 13058 { 13059 Expression ey = null; 13060 if (t2.ty == Tstruct && sd == t2.toDsymbol(sc)) 13061 { 13062 ey = ev; 13063 } 13064 else if (!ev.implicitConvTo(ie.type) && sd.ctor) 13065 { 13066 // Look for implicit constructor call 13067 // Rewrite as S().ctor(e2) 13068 ey = new StructLiteralExp(loc, sd, null); 13069 ey = new DotIdExp(loc, ey, Id.ctor); 13070 ey = new CallExp(loc, ey, ev); 13071 ey = ey.trySemantic(sc); 13072 } 13073 if (ey) 13074 { 13075 Expression ex; 13076 ex = new IndexExp(loc, ea, ek); 13077 ex = ex.semantic(sc); 13078 ex = ex.optimize(WANTvalue); 13079 ex = ex.modifiableLvalue(sc, ex); // allocate new slot 13080 13081 ey = new ConstructExp(loc, ex, ey); 13082 ey = ey.semantic(sc); 13083 if (ey.op == TOKerror) 13084 return ey; 13085 ex = e; 13086 13087 // Bugzilla 14144: The whole expression should have the common type 13088 // of opAssign() return and assigned AA entry. 13089 // Even if there's no common type, expression should be typed as void. 13090 Type t = null; 13091 if (!typeMerge(sc, TOKquestion, &t, &ex, &ey)) 13092 { 13093 ex = new CastExp(ex.loc, ex, Type.tvoid); 13094 ey = new CastExp(ey.loc, ey, Type.tvoid); 13095 } 13096 e = new CondExp(loc, new InExp(loc, ek, ea), ex, ey); 13097 } 13098 e = combine(e0, e); 13099 e = e.semantic(sc); 13100 return e; 13101 } 13102 } 13103 else 13104 { 13105 Expression e = op_overload(sc); 13106 if (e) 13107 return e; 13108 } 13109 } 13110 else 13111 assert(op == TOKblit); 13112 13113 e1 = e1x; 13114 e2 = e2x; 13115 } 13116 else if (t1.ty == Tclass) 13117 { 13118 // Disallow assignment operator overloads for same type 13119 if (op == TOKassign && !e2.implicitConvTo(e1.type)) 13120 { 13121 Expression e = op_overload(sc); 13122 if (e) 13123 return e; 13124 } 13125 } 13126 else if (t1.ty == Tsarray) 13127 { 13128 // SliceExp cannot have static array type without context inference. 13129 assert(e1.op != TOKslice); 13130 Expression e1x = e1; 13131 Expression e2x = e2; 13132 13133 if (e2x.implicitConvTo(e1x.type)) 13134 { 13135 if (op != TOKblit && (e2x.op == TOKslice && (cast(UnaExp)e2x).e1.isLvalue() || e2x.op == TOKcast && (cast(UnaExp)e2x).e1.isLvalue() || e2x.op != TOKslice && e2x.isLvalue())) 13136 { 13137 if (e1x.checkPostblit(sc, t1)) 13138 return new ErrorExp(); 13139 } 13140 13141 // e2 matches to t1 because of the implicit length match, so 13142 if (isUnaArrayOp(e2x.op) || isBinArrayOp(e2x.op)) 13143 { 13144 // convert e1 to e1[] 13145 // e.g. e1[] = a[] + b[]; 13146 e1x = new SliceExp(e1x.loc, e1x, null, null); 13147 e1x = e1x.semantic(sc); 13148 } 13149 else 13150 { 13151 // convert e2 to t1 later 13152 // e.g. e1 = [1, 2, 3]; 13153 } 13154 } 13155 else 13156 { 13157 if (e2x.implicitConvTo(t1.nextOf().arrayOf()) > MATCHnomatch) 13158 { 13159 uinteger_t dim1 = (cast(TypeSArray)t1).dim.toInteger(); 13160 uinteger_t dim2 = dim1; 13161 if (e2x.op == TOKarrayliteral) 13162 { 13163 ArrayLiteralExp ale = cast(ArrayLiteralExp)e2x; 13164 dim2 = ale.elements ? ale.elements.dim : 0; 13165 } 13166 else if (e2x.op == TOKslice) 13167 { 13168 Type tx = toStaticArrayType(cast(SliceExp)e2x); 13169 if (tx) 13170 dim2 = (cast(TypeSArray)tx).dim.toInteger(); 13171 } 13172 if (dim1 != dim2) 13173 { 13174 error("mismatched array lengths, %d and %d", cast(int)dim1, cast(int)dim2); 13175 return new ErrorExp(); 13176 } 13177 } 13178 13179 // May be block or element-wise assignment, so 13180 // convert e1 to e1[] 13181 if (op != TOKassign) 13182 { 13183 // If multidimensional static array, treat as one large array 13184 dinteger_t dim = (cast(TypeSArray)t1).dim.toInteger(); 13185 Type t = t1; 13186 while (1) 13187 { 13188 t = t.nextOf().toBasetype(); 13189 if (t.ty != Tsarray) 13190 break; 13191 dim *= (cast(TypeSArray)t).dim.toInteger(); 13192 e1x.type = t.nextOf().sarrayOf(dim); 13193 } 13194 } 13195 e1x = new SliceExp(e1x.loc, e1x, null, null); 13196 e1x = e1x.semantic(sc); 13197 } 13198 if (e1x.op == TOKerror) 13199 return e1x; 13200 if (e2x.op == TOKerror) 13201 return e2x; 13202 13203 e1 = e1x; 13204 e2 = e2x; 13205 t1 = e1x.type.toBasetype(); 13206 } 13207 /* Check the mutability of e1. 13208 */ 13209 if (e1.op == TOKarraylength) 13210 { 13211 // e1 is not an lvalue, but we let code generator handle it 13212 ArrayLengthExp ale = cast(ArrayLengthExp)e1; 13213 13214 Expression ale1x = ale.e1; 13215 ale1x = ale1x.modifiableLvalue(sc, e1); 13216 if (ale1x.op == TOKerror) 13217 return ale1x; 13218 ale.e1 = ale1x; 13219 13220 Type tn = ale.e1.type.toBasetype().nextOf(); 13221 checkDefCtor(ale.loc, tn); 13222 semanticTypeInfo(sc, tn); 13223 } 13224 else if (e1.op == TOKslice) 13225 { 13226 Type tn = e1.type.nextOf(); 13227 if (op == TOKassign && !tn.isMutable()) 13228 { 13229 error("slice %s is not mutable", e1.toChars()); 13230 return new ErrorExp(); 13231 } 13232 13233 // For conditional operator, both branches need conversion. 13234 SliceExp se = cast(SliceExp)e1; 13235 while (se.e1.op == TOKslice) 13236 se = cast(SliceExp)se.e1; 13237 if (se.e1.op == TOKquestion && se.e1.type.toBasetype().ty == Tsarray) 13238 { 13239 se.e1 = se.e1.modifiableLvalue(sc, e1); 13240 if (se.e1.op == TOKerror) 13241 return se.e1; 13242 } 13243 } 13244 else 13245 { 13246 Expression e1x = e1; 13247 13248 // Try to do a decent error message with the expression 13249 // before it got constant folded 13250 13251 if (e1x.op != TOKvar) 13252 e1x = e1x.optimize(WANTvalue); 13253 13254 if (op == TOKassign) 13255 e1x = e1x.modifiableLvalue(sc, e1old); 13256 13257 if (e1x.op == TOKerror) 13258 return e1x; 13259 e1 = e1x; 13260 } 13261 13262 /* Tweak e2 based on the type of e1. 13263 */ 13264 Expression e2x = e2; 13265 Type t2 = e2x.type.toBasetype(); 13266 13267 // If it is a array, get the element type. Note that it may be 13268 // multi-dimensional. 13269 Type telem = t1; 13270 while (telem.ty == Tarray) 13271 telem = telem.nextOf(); 13272 13273 if (e1.op == TOKslice && t1.nextOf() && 13274 (telem.ty != Tvoid || e2x.op == TOKnull) && 13275 e2x.implicitConvTo(t1.nextOf())) 13276 { 13277 // Check for block assignment. If it is of type void[], void[][], etc, 13278 // '= null' is the only allowable block assignment (Bug 7493) 13279 memset |= MemorySet.blockAssign; // make it easy for back end to tell what this is 13280 e2x = e2x.implicitCastTo(sc, t1.nextOf()); 13281 if (op != TOKblit && e2x.isLvalue() && e1.checkPostblit(sc, t1.nextOf())) 13282 { 13283 return new ErrorExp(); 13284 } 13285 } 13286 else if (e1.op == TOKslice && 13287 (t2.ty == Tarray || t2.ty == Tsarray) && 13288 t2.nextOf().implicitConvTo(t1.nextOf())) 13289 { 13290 // Check element-wise assignment. 13291 13292 /* If assigned elements number is known at compile time, 13293 * check the mismatch. 13294 */ 13295 SliceExp se1 = cast(SliceExp)e1; 13296 TypeSArray tsa1 = cast(TypeSArray)toStaticArrayType(se1); 13297 TypeSArray tsa2 = null; 13298 if (e2x.op == TOKarrayliteral) 13299 tsa2 = cast(TypeSArray)t2.nextOf().sarrayOf((cast(ArrayLiteralExp)e2x).elements.dim); 13300 else if (e2x.op == TOKslice) 13301 tsa2 = cast(TypeSArray)toStaticArrayType(cast(SliceExp)e2x); 13302 else if (t2.ty == Tsarray) 13303 tsa2 = cast(TypeSArray)t2; 13304 if (tsa1 && tsa2) 13305 { 13306 uinteger_t dim1 = tsa1.dim.toInteger(); 13307 uinteger_t dim2 = tsa2.dim.toInteger(); 13308 if (dim1 != dim2) 13309 { 13310 error("mismatched array lengths, %d and %d", cast(int)dim1, cast(int)dim2); 13311 return new ErrorExp(); 13312 } 13313 } 13314 13315 if (op != TOKblit && 13316 (e2x.op == TOKslice && (cast(UnaExp)e2x).e1.isLvalue() || 13317 e2x.op == TOKcast && (cast(UnaExp)e2x).e1.isLvalue() || 13318 e2x.op != TOKslice && e2x.isLvalue())) 13319 { 13320 if (e1.checkPostblit(sc, t1.nextOf())) 13321 return new ErrorExp(); 13322 } 13323 13324 if (0 && global.params.warnings && !global.gag && op == TOKassign && 13325 e2x.op != TOKslice && e2x.op != TOKassign && 13326 e2x.op != TOKarrayliteral && e2x.op != TOKstring && 13327 !(e2x.op == TOKadd || e2x.op == TOKmin || 13328 e2x.op == TOKmul || e2x.op == TOKdiv || 13329 e2x.op == TOKmod || e2x.op == TOKxor || 13330 e2x.op == TOKand || e2x.op == TOKor || 13331 e2x.op == TOKpow || 13332 e2x.op == TOKtilde || e2x.op == TOKneg)) 13333 { 13334 const(char)* e1str = e1.toChars(); 13335 const(char)* e2str = e2x.toChars(); 13336 warning("explicit element-wise assignment %s = (%s)[] is better than %s = %s", e1str, e2str, e1str, e2str); 13337 } 13338 13339 Type t2n = t2.nextOf(); 13340 Type t1n = t1.nextOf(); 13341 int offset; 13342 if (t2n.equivalent(t1n) || 13343 t1n.isBaseOf(t2n, &offset) && offset == 0) 13344 { 13345 /* Allow copy of distinct qualifier elements. 13346 * eg. 13347 * char[] dst; const(char)[] src; 13348 * dst[] = src; 13349 * 13350 * class C {} class D : C {} 13351 * C[2] ca; D[] da; 13352 * ca[] = da; 13353 */ 13354 if (isArrayOpValid(e2x)) 13355 { 13356 // Don't add CastExp to keep AST for array operations 13357 e2x = e2x.copy(); 13358 e2x.type = e1.type.constOf(); 13359 } 13360 else 13361 e2x = e2x.castTo(sc, e1.type.constOf()); 13362 } 13363 else 13364 { 13365 /* Bugzilla 15778: A string literal has an array type of immutable 13366 * elements by default, and normally it cannot be convertible to 13367 * array type of mutable elements. But for element-wise assignment, 13368 * elements need to be const at best. So we should give a chance 13369 * to change code unit size for polysemous string literal. 13370 */ 13371 if (e2x.op == TOKstring) 13372 e2x = e2x.implicitCastTo(sc, e1.type.constOf()); 13373 else 13374 e2x = e2x.implicitCastTo(sc, e1.type); 13375 } 13376 if (t1n.toBasetype.ty == Tvoid && t2n.toBasetype.ty == Tvoid) 13377 { 13378 if (!sc.intypeof && sc.func && sc.func.setUnsafe()) 13379 { 13380 error("cannot copy void[] to void[] in @safe code"); 13381 return new ErrorExp(); 13382 } 13383 } 13384 } 13385 else 13386 { 13387 if (0 && global.params.warnings && !global.gag && op == TOKassign && 13388 t1.ty == Tarray && t2.ty == Tsarray && 13389 e2x.op != TOKslice && 13390 t2.implicitConvTo(t1)) 13391 { 13392 // Disallow ar[] = sa (Converted to ar[] = sa[]) 13393 // Disallow da = sa (Converted to da = sa[]) 13394 const(char)* e1str = e1.toChars(); 13395 const(char)* e2str = e2x.toChars(); 13396 const(char)* atypestr = e1.op == TOKslice ? "element-wise" : "slice"; 13397 warning("explicit %s assignment %s = (%s)[] is better than %s = %s", atypestr, e1str, e2str, e1str, e2str); 13398 } 13399 if (op == TOKblit) 13400 e2x = e2x.castTo(sc, e1.type); 13401 else 13402 e2x = e2x.implicitCastTo(sc, e1.type); 13403 } 13404 if (e2x.op == TOKerror) 13405 return e2x; 13406 e2 = e2x; 13407 t2 = e2.type.toBasetype(); 13408 13409 /* Look for array operations 13410 */ 13411 if ((t2.ty == Tarray || t2.ty == Tsarray) && isArrayOpValid(e2)) 13412 { 13413 // Look for valid array operations 13414 if (!(memset & MemorySet.blockAssign) && 13415 e1.op == TOKslice && 13416 (isUnaArrayOp(e2.op) || isBinArrayOp(e2.op))) 13417 { 13418 type = e1.type; 13419 if (op == TOKconstruct) // Bugzilla 10282: tweak mutability of e1 element 13420 e1.type = e1.type.nextOf().mutableOf().arrayOf(); 13421 return arrayOp(this, sc); 13422 } 13423 13424 // Drop invalid array operations in e2 13425 // d = a[] + b[], d = (a[] + b[])[0..2], etc 13426 if (checkNonAssignmentArrayOp(e2, !(memset & MemorySet.blockAssign) && op == TOKassign)) 13427 return new ErrorExp(); 13428 13429 // Remains valid array assignments 13430 // d = d[], d = [1,2,3], etc 13431 } 13432 13433 /* Don't allow assignment to classes that were allocated on the stack with: 13434 * scope Class c = new Class(); 13435 */ 13436 if (e1.op == TOKvar && op == TOKassign) 13437 { 13438 VarExp ve = cast(VarExp)e1; 13439 VarDeclaration vd = ve.var.isVarDeclaration(); 13440 if (vd && (vd.onstack || vd.mynew)) 13441 { 13442 assert(t1.ty == Tclass); 13443 error("cannot rebind scope variables"); 13444 } 13445 } 13446 13447 if (e1.op == TOKvar && (cast(VarExp)e1).var.ident == Id.ctfe) 13448 { 13449 error("cannot modify compiler-generated variable __ctfe"); 13450 } 13451 13452 type = e1.type; 13453 assert(type); 13454 return op == TOKassign ? reorderSettingAAElem(sc) : this; 13455 } 13456 13457 override final bool isLvalue() 13458 { 13459 // Array-op 'x[] = y[]' should make an rvalue. 13460 // Setting array length 'x.length = v' should make an rvalue. 13461 if (e1.op == TOKslice || e1.op == TOKarraylength) 13462 { 13463 return false; 13464 } 13465 return true; 13466 } 13467 13468 override final Expression toLvalue(Scope* sc, Expression ex) 13469 { 13470 if (e1.op == TOKslice || e1.op == TOKarraylength) 13471 { 13472 return Expression.toLvalue(sc, ex); 13473 } 13474 13475 /* In front-end level, AssignExp should make an lvalue of e1. 13476 * Taking the address of e1 will be handled in low level layer, 13477 * so this function does nothing. 13478 */ 13479 return this; 13480 } 13481 13482 override final Expression toBoolean(Scope* sc) 13483 { 13484 // Things like: 13485 // if (a = b) ... 13486 // are usually mistakes. 13487 13488 error("assignment cannot be used as a condition, perhaps == was meant?"); 13489 return new ErrorExp(); 13490 } 13491 13492 override void accept(Visitor v) 13493 { 13494 v.visit(this); 13495 } 13496 } 13497 13498 /*********************************************************** 13499 */ 13500 extern (C++) final class ConstructExp : AssignExp 13501 { 13502 extern (D) this(Loc loc, Expression e1, Expression e2) 13503 { 13504 super(loc, e1, e2); 13505 op = TOKconstruct; 13506 } 13507 13508 // Internal use only. If `v` is a reference variable, the assinment 13509 // will become a reference initialization automatically. 13510 extern (D) this(Loc loc, VarDeclaration v, Expression e2) 13511 { 13512 auto ve = new VarExp(loc, v); 13513 assert(v.type && ve.type); 13514 13515 super(loc, ve, e2); 13516 op = TOKconstruct; 13517 13518 if (v.storage_class & (STCref | STCout)) 13519 memset |= MemorySet.referenceInit; 13520 } 13521 13522 override void accept(Visitor v) 13523 { 13524 v.visit(this); 13525 } 13526 } 13527 13528 /*********************************************************** 13529 */ 13530 extern (C++) final class BlitExp : AssignExp 13531 { 13532 extern (D) this(Loc loc, Expression e1, Expression e2) 13533 { 13534 super(loc, e1, e2); 13535 op = TOKblit; 13536 } 13537 13538 // Internal use only. If `v` is a reference variable, the assinment 13539 // will become a reference rebinding automatically. 13540 extern (D) this(Loc loc, VarDeclaration v, Expression e2) 13541 { 13542 auto ve = new VarExp(loc, v); 13543 assert(v.type && ve.type); 13544 13545 super(loc, ve, e2); 13546 op = TOKblit; 13547 13548 if (v.storage_class & (STCref | STCout)) 13549 memset |= MemorySet.referenceInit; 13550 } 13551 13552 override void accept(Visitor v) 13553 { 13554 v.visit(this); 13555 } 13556 } 13557 13558 /*********************************************************** 13559 */ 13560 extern (C++) final class AddAssignExp : BinAssignExp 13561 { 13562 extern (D) this(Loc loc, Expression e1, Expression e2) 13563 { 13564 super(loc, TOKaddass, __traits(classInstanceSize, AddAssignExp), e1, e2); 13565 } 13566 13567 override void accept(Visitor v) 13568 { 13569 v.visit(this); 13570 } 13571 } 13572 13573 /*********************************************************** 13574 */ 13575 extern (C++) final class MinAssignExp : BinAssignExp 13576 { 13577 extern (D) this(Loc loc, Expression e1, Expression e2) 13578 { 13579 super(loc, TOKminass, __traits(classInstanceSize, MinAssignExp), e1, e2); 13580 } 13581 13582 override void accept(Visitor v) 13583 { 13584 v.visit(this); 13585 } 13586 } 13587 13588 /*********************************************************** 13589 */ 13590 extern (C++) final class MulAssignExp : BinAssignExp 13591 { 13592 extern (D) this(Loc loc, Expression e1, Expression e2) 13593 { 13594 super(loc, TOKmulass, __traits(classInstanceSize, MulAssignExp), e1, e2); 13595 } 13596 13597 override void accept(Visitor v) 13598 { 13599 v.visit(this); 13600 } 13601 } 13602 13603 /*********************************************************** 13604 */ 13605 extern (C++) final class DivAssignExp : BinAssignExp 13606 { 13607 extern (D) this(Loc loc, Expression e1, Expression e2) 13608 { 13609 super(loc, TOKdivass, __traits(classInstanceSize, DivAssignExp), e1, e2); 13610 } 13611 13612 override void accept(Visitor v) 13613 { 13614 v.visit(this); 13615 } 13616 } 13617 13618 /*********************************************************** 13619 */ 13620 extern (C++) final class ModAssignExp : BinAssignExp 13621 { 13622 extern (D) this(Loc loc, Expression e1, Expression e2) 13623 { 13624 super(loc, TOKmodass, __traits(classInstanceSize, ModAssignExp), e1, e2); 13625 } 13626 13627 override void accept(Visitor v) 13628 { 13629 v.visit(this); 13630 } 13631 } 13632 13633 /*********************************************************** 13634 */ 13635 extern (C++) final class AndAssignExp : BinAssignExp 13636 { 13637 extern (D) this(Loc loc, Expression e1, Expression e2) 13638 { 13639 super(loc, TOKandass, __traits(classInstanceSize, AndAssignExp), e1, e2); 13640 } 13641 13642 override void accept(Visitor v) 13643 { 13644 v.visit(this); 13645 } 13646 } 13647 13648 /*********************************************************** 13649 */ 13650 extern (C++) final class OrAssignExp : BinAssignExp 13651 { 13652 extern (D) this(Loc loc, Expression e1, Expression e2) 13653 { 13654 super(loc, TOKorass, __traits(classInstanceSize, OrAssignExp), e1, e2); 13655 } 13656 13657 override void accept(Visitor v) 13658 { 13659 v.visit(this); 13660 } 13661 } 13662 13663 /*********************************************************** 13664 */ 13665 extern (C++) final class XorAssignExp : BinAssignExp 13666 { 13667 extern (D) this(Loc loc, Expression e1, Expression e2) 13668 { 13669 super(loc, TOKxorass, __traits(classInstanceSize, XorAssignExp), e1, e2); 13670 } 13671 13672 override void accept(Visitor v) 13673 { 13674 v.visit(this); 13675 } 13676 } 13677 13678 /*********************************************************** 13679 */ 13680 extern (C++) final class PowAssignExp : BinAssignExp 13681 { 13682 extern (D) this(Loc loc, Expression e1, Expression e2) 13683 { 13684 super(loc, TOKpowass, __traits(classInstanceSize, PowAssignExp), e1, e2); 13685 } 13686 13687 override Expression semantic(Scope* sc) 13688 { 13689 if (type) 13690 return this; 13691 13692 Expression e = op_overload(sc); 13693 if (e) 13694 return e; 13695 13696 if (e1.checkReadModifyWrite(op, e2)) 13697 return new ErrorExp(); 13698 13699 assert(e1.type && e2.type); 13700 if (e1.op == TOKslice || e1.type.ty == Tarray || e1.type.ty == Tsarray) 13701 { 13702 // T[] ^^= ... 13703 if (e2.implicitConvTo(e1.type.nextOf())) 13704 { 13705 // T[] ^^= T 13706 e2 = e2.castTo(sc, e1.type.nextOf()); 13707 } 13708 else if (Expression ex = typeCombine(this, sc)) 13709 return ex; 13710 13711 // Check element types are arithmetic 13712 Type tb1 = e1.type.nextOf().toBasetype(); 13713 Type tb2 = e2.type.toBasetype(); 13714 if (tb2.ty == Tarray || tb2.ty == Tsarray) 13715 tb2 = tb2.nextOf().toBasetype(); 13716 if ((tb1.isintegral() || tb1.isfloating()) && (tb2.isintegral() || tb2.isfloating())) 13717 { 13718 type = e1.type; 13719 return arrayOp(this, sc); 13720 } 13721 } 13722 else 13723 { 13724 e1 = e1.modifiableLvalue(sc, e1); 13725 } 13726 13727 if ((e1.type.isintegral() || e1.type.isfloating()) && (e2.type.isintegral() || e2.type.isfloating())) 13728 { 13729 Expression e0 = null; 13730 e = reorderSettingAAElem(sc); 13731 e = extractLast(e, &e0); 13732 assert(e == this); 13733 13734 if (e1.op == TOKvar) 13735 { 13736 // Rewrite: e1 = e1 ^^ e2 13737 e = new PowExp(loc, e1.syntaxCopy(), e2); 13738 e = new AssignExp(loc, e1, e); 13739 } 13740 else 13741 { 13742 // Rewrite: ref tmp = e1; tmp = tmp ^^ e2 13743 auto v = copyToTemp(STCref, "__powtmp", e1); 13744 auto de = new DeclarationExp(e1.loc, v); 13745 auto ve = new VarExp(e1.loc, v); 13746 e = new PowExp(loc, ve, e2); 13747 e = new AssignExp(loc, new VarExp(e1.loc, v), e); 13748 e = new CommaExp(loc, de, e); 13749 } 13750 e = Expression.combine(e0, e); 13751 e = e.semantic(sc); 13752 if (e.type.toBasetype().ty == Tvector) 13753 return incompatibleTypes(); 13754 return e; 13755 } 13756 return incompatibleTypes(); 13757 } 13758 13759 override void accept(Visitor v) 13760 { 13761 v.visit(this); 13762 } 13763 } 13764 13765 /*********************************************************** 13766 */ 13767 extern (C++) final class ShlAssignExp : BinAssignExp 13768 { 13769 extern (D) this(Loc loc, Expression e1, Expression e2) 13770 { 13771 super(loc, TOKshlass, __traits(classInstanceSize, ShlAssignExp), e1, e2); 13772 } 13773 13774 override void accept(Visitor v) 13775 { 13776 v.visit(this); 13777 } 13778 } 13779 13780 /*********************************************************** 13781 */ 13782 extern (C++) final class ShrAssignExp : BinAssignExp 13783 { 13784 extern (D) this(Loc loc, Expression e1, Expression e2) 13785 { 13786 super(loc, TOKshrass, __traits(classInstanceSize, ShrAssignExp), e1, e2); 13787 } 13788 13789 override void accept(Visitor v) 13790 { 13791 v.visit(this); 13792 } 13793 } 13794 13795 /*********************************************************** 13796 */ 13797 extern (C++) final class UshrAssignExp : BinAssignExp 13798 { 13799 extern (D) this(Loc loc, Expression e1, Expression e2) 13800 { 13801 super(loc, TOKushrass, __traits(classInstanceSize, UshrAssignExp), e1, e2); 13802 } 13803 13804 override void accept(Visitor v) 13805 { 13806 v.visit(this); 13807 } 13808 } 13809 13810 /*********************************************************** 13811 */ 13812 extern (C++) final class CatAssignExp : BinAssignExp 13813 { 13814 extern (D) this(Loc loc, Expression e1, Expression e2) 13815 { 13816 super(loc, TOKcatass, __traits(classInstanceSize, CatAssignExp), e1, e2); 13817 } 13818 13819 override Expression semantic(Scope* sc) 13820 { 13821 if (type) 13822 return this; 13823 13824 //printf("CatAssignExp::semantic() %s\n", toChars()); 13825 Expression e = op_overload(sc); 13826 if (e) 13827 return e; 13828 13829 if (e1.op == TOKslice) 13830 { 13831 SliceExp se = cast(SliceExp)e1; 13832 if (se.e1.type.toBasetype().ty == Tsarray) 13833 { 13834 error("cannot append to static array %s", se.e1.type.toChars()); 13835 return new ErrorExp(); 13836 } 13837 } 13838 13839 e1 = e1.modifiableLvalue(sc, e1); 13840 if (e1.op == TOKerror) 13841 return e1; 13842 if (e2.op == TOKerror) 13843 return e2; 13844 13845 if (checkNonAssignmentArrayOp(e2)) 13846 return new ErrorExp(); 13847 13848 Type tb1 = e1.type.toBasetype(); 13849 Type tb1next = tb1.nextOf(); 13850 Type tb2 = e2.type.toBasetype(); 13851 13852 if ((tb1.ty == Tarray) && 13853 (tb2.ty == Tarray || tb2.ty == Tsarray) && 13854 (e2.implicitConvTo(e1.type) || 13855 (tb2.nextOf().implicitConvTo(tb1next) && 13856 (tb2.nextOf().size(Loc()) == tb1next.size(Loc()))))) 13857 { 13858 // Append array 13859 if (e1.checkPostblit(sc, tb1next)) 13860 return new ErrorExp(); 13861 e2 = e2.castTo(sc, e1.type); 13862 } 13863 else if ((tb1.ty == Tarray) && e2.implicitConvTo(tb1next)) 13864 { 13865 // Append element 13866 if (e2.checkPostblit(sc, tb2)) 13867 return new ErrorExp(); 13868 e2 = e2.castTo(sc, tb1next); 13869 e2 = doCopyOrMove(sc, e2); 13870 } 13871 else if (tb1.ty == Tarray && 13872 (tb1next.ty == Tchar || tb1next.ty == Twchar) && 13873 e2.type.ty != tb1next.ty && 13874 e2.implicitConvTo(Type.tdchar)) 13875 { 13876 // Append dchar to char[] or wchar[] 13877 e2 = e2.castTo(sc, Type.tdchar); 13878 13879 /* Do not allow appending wchar to char[] because if wchar happens 13880 * to be a surrogate pair, nothing good can result. 13881 */ 13882 } 13883 else 13884 { 13885 error("cannot append type %s to type %s", tb2.toChars(), tb1.toChars()); 13886 return new ErrorExp(); 13887 } 13888 if (e2.checkValue()) 13889 return new ErrorExp(); 13890 13891 type = e1.type; 13892 return reorderSettingAAElem(sc); 13893 } 13894 13895 override void accept(Visitor v) 13896 { 13897 v.visit(this); 13898 } 13899 } 13900 13901 /*********************************************************** 13902 */ 13903 extern (C++) final class AddExp : BinExp 13904 { 13905 extern (D) this(Loc loc, Expression e1, Expression e2) 13906 { 13907 super(loc, TOKadd, __traits(classInstanceSize, AddExp), e1, e2); 13908 } 13909 13910 override Expression semantic(Scope* sc) 13911 { 13912 static if (LOGSEMANTIC) 13913 { 13914 printf("AddExp::semantic('%s')\n", toChars()); 13915 } 13916 if (type) 13917 return this; 13918 13919 if (Expression ex = binSemanticProp(sc)) 13920 return ex; 13921 Expression e = op_overload(sc); 13922 if (e) 13923 return e; 13924 13925 Type tb1 = e1.type.toBasetype(); 13926 Type tb2 = e2.type.toBasetype(); 13927 13928 bool err = false; 13929 if (tb1.ty == Tdelegate || tb1.ty == Tpointer && tb1.nextOf().ty == Tfunction) 13930 { 13931 err |= e1.checkArithmetic(); 13932 } 13933 if (tb2.ty == Tdelegate || tb2.ty == Tpointer && tb2.nextOf().ty == Tfunction) 13934 { 13935 err |= e2.checkArithmetic(); 13936 } 13937 if (err) 13938 return new ErrorExp(); 13939 13940 if (tb1.ty == Tpointer && e2.type.isintegral() || tb2.ty == Tpointer && e1.type.isintegral()) 13941 { 13942 return scaleFactor(this, sc); 13943 } 13944 13945 if (tb1.ty == Tpointer && tb2.ty == Tpointer) 13946 { 13947 return incompatibleTypes(); 13948 } 13949 13950 if (Expression ex = typeCombine(this, sc)) 13951 return ex; 13952 13953 Type tb = type.toBasetype(); 13954 if (tb.ty == Tarray || tb.ty == Tsarray) 13955 { 13956 if (!isArrayOpValid(this)) 13957 { 13958 error("invalid array operation %s (possible missing [])", toChars()); 13959 return new ErrorExp(); 13960 } 13961 return this; 13962 } 13963 13964 tb1 = e1.type.toBasetype(); 13965 if (tb1.ty == Tvector && !tb1.isscalar()) 13966 { 13967 return incompatibleTypes(); 13968 } 13969 if ((tb1.isreal() && e2.type.isimaginary()) || (tb1.isimaginary() && e2.type.isreal())) 13970 { 13971 switch (type.toBasetype().ty) 13972 { 13973 case Tfloat32: 13974 case Timaginary32: 13975 type = Type.tcomplex32; 13976 break; 13977 13978 case Tfloat64: 13979 case Timaginary64: 13980 type = Type.tcomplex64; 13981 break; 13982 13983 case Tfloat80: 13984 case Timaginary80: 13985 type = Type.tcomplex80; 13986 break; 13987 13988 default: 13989 assert(0); 13990 } 13991 } 13992 return this; 13993 } 13994 13995 override void accept(Visitor v) 13996 { 13997 v.visit(this); 13998 } 13999 } 14000 14001 /*********************************************************** 14002 */ 14003 extern (C++) final class MinExp : BinExp 14004 { 14005 extern (D) this(Loc loc, Expression e1, Expression e2) 14006 { 14007 super(loc, TOKmin, __traits(classInstanceSize, MinExp), e1, e2); 14008 } 14009 14010 override Expression semantic(Scope* sc) 14011 { 14012 static if (LOGSEMANTIC) 14013 { 14014 printf("MinExp::semantic('%s')\n", toChars()); 14015 } 14016 if (type) 14017 return this; 14018 14019 if (Expression ex = binSemanticProp(sc)) 14020 return ex; 14021 Expression e = op_overload(sc); 14022 if (e) 14023 return e; 14024 14025 Type t1 = e1.type.toBasetype(); 14026 Type t2 = e2.type.toBasetype(); 14027 14028 bool err = false; 14029 if (t1.ty == Tdelegate || t1.ty == Tpointer && t1.nextOf().ty == Tfunction) 14030 { 14031 err |= e1.checkArithmetic(); 14032 } 14033 if (t2.ty == Tdelegate || t2.ty == Tpointer && t2.nextOf().ty == Tfunction) 14034 { 14035 err |= e2.checkArithmetic(); 14036 } 14037 if (err) 14038 return new ErrorExp(); 14039 14040 if (t1.ty == Tpointer) 14041 { 14042 if (t2.ty == Tpointer) 14043 { 14044 // Need to divide the result by the stride 14045 // Replace (ptr - ptr) with (ptr - ptr) / stride 14046 d_int64 stride; 14047 14048 // make sure pointer types are compatible 14049 if (Expression ex = typeCombine(this, sc)) 14050 return ex; 14051 14052 type = Type.tptrdiff_t; 14053 stride = t2.nextOf().size(); 14054 if (stride == 0) 14055 { 14056 e = new IntegerExp(loc, 0, Type.tptrdiff_t); 14057 } 14058 else 14059 { 14060 e = new DivExp(loc, this, new IntegerExp(Loc(), stride, Type.tptrdiff_t)); 14061 e.type = Type.tptrdiff_t; 14062 } 14063 } 14064 else if (t2.isintegral()) 14065 e = scaleFactor(this, sc); 14066 else 14067 { 14068 error("can't subtract %s from pointer", t2.toChars()); 14069 e = new ErrorExp(); 14070 } 14071 return e; 14072 } 14073 if (t2.ty == Tpointer) 14074 { 14075 type = e2.type; 14076 error("can't subtract pointer from %s", e1.type.toChars()); 14077 return new ErrorExp(); 14078 } 14079 14080 if (Expression ex = typeCombine(this, sc)) 14081 return ex; 14082 14083 Type tb = type.toBasetype(); 14084 if (tb.ty == Tarray || tb.ty == Tsarray) 14085 { 14086 if (!isArrayOpValid(this)) 14087 { 14088 error("invalid array operation %s (possible missing [])", toChars()); 14089 return new ErrorExp(); 14090 } 14091 return this; 14092 } 14093 14094 t1 = e1.type.toBasetype(); 14095 t2 = e2.type.toBasetype(); 14096 if (t1.ty == Tvector && !t1.isscalar()) 14097 { 14098 return incompatibleTypes(); 14099 } 14100 if ((t1.isreal() && t2.isimaginary()) || (t1.isimaginary() && t2.isreal())) 14101 { 14102 switch (type.ty) 14103 { 14104 case Tfloat32: 14105 case Timaginary32: 14106 type = Type.tcomplex32; 14107 break; 14108 14109 case Tfloat64: 14110 case Timaginary64: 14111 type = Type.tcomplex64; 14112 break; 14113 14114 case Tfloat80: 14115 case Timaginary80: 14116 type = Type.tcomplex80; 14117 break; 14118 14119 default: 14120 assert(0); 14121 } 14122 } 14123 return this; 14124 } 14125 14126 override void accept(Visitor v) 14127 { 14128 v.visit(this); 14129 } 14130 } 14131 14132 /*********************************************************** 14133 */ 14134 extern (C++) final class CatExp : BinExp 14135 { 14136 extern (D) this(Loc loc, Expression e1, Expression e2) 14137 { 14138 super(loc, TOKcat, __traits(classInstanceSize, CatExp), e1, e2); 14139 } 14140 14141 override Expression semantic(Scope* sc) 14142 { 14143 //printf("CatExp::semantic() %s\n", toChars()); 14144 if (type) 14145 return this; 14146 14147 if (Expression ex = binSemanticProp(sc)) 14148 return ex; 14149 Expression e = op_overload(sc); 14150 if (e) 14151 return e; 14152 14153 Type tb1 = e1.type.toBasetype(); 14154 Type tb2 = e2.type.toBasetype(); 14155 14156 auto f1 = checkNonAssignmentArrayOp(e1); 14157 auto f2 = checkNonAssignmentArrayOp(e2); 14158 if (f1 || f2) 14159 return new ErrorExp(); 14160 14161 /* BUG: Should handle things like: 14162 * char c; 14163 * c ~ ' ' 14164 * ' ' ~ c; 14165 */ 14166 14167 version (none) 14168 { 14169 e1.type.print(); 14170 e2.type.print(); 14171 } 14172 Type tb1next = tb1.nextOf(); 14173 Type tb2next = tb2.nextOf(); 14174 14175 // Check for: array ~ array 14176 if (tb1next && tb2next && (tb1next.implicitConvTo(tb2next) >= MATCHconst || tb2next.implicitConvTo(tb1next) >= MATCHconst || e1.op == TOKarrayliteral && e1.implicitConvTo(tb2) || e2.op == TOKarrayliteral && e2.implicitConvTo(tb1))) 14177 { 14178 /* Bugzilla 9248: Here to avoid the case of: 14179 * void*[] a = [cast(void*)1]; 14180 * void*[] b = [cast(void*)2]; 14181 * a ~ b; 14182 * becoming: 14183 * a ~ [cast(void*)b]; 14184 */ 14185 14186 /* Bugzilla 14682: Also to avoid the case of: 14187 * int[][] a; 14188 * a ~ []; 14189 * becoming: 14190 * a ~ cast(int[])[]; 14191 */ 14192 goto Lpeer; 14193 } 14194 14195 // Check for: array ~ element 14196 if ((tb1.ty == Tsarray || tb1.ty == Tarray) && tb2.ty != Tvoid) 14197 { 14198 if (e1.op == TOKarrayliteral) 14199 { 14200 e2 = doCopyOrMove(sc, e2); 14201 // Bugzilla 14686: Postblit call appears in AST, and this is 14202 // finally translated to an ArrayLiteralExp in below optimize(). 14203 } 14204 else if (e1.op == TOKstring) 14205 { 14206 // No postblit call exists on character (integer) value. 14207 } 14208 else 14209 { 14210 if (e2.checkPostblit(sc, tb2)) 14211 return new ErrorExp(); 14212 // Postblit call will be done in runtime helper function 14213 } 14214 14215 if (e1.op == TOKarrayliteral && e1.implicitConvTo(tb2.arrayOf())) 14216 { 14217 e1 = e1.implicitCastTo(sc, tb2.arrayOf()); 14218 type = tb2.arrayOf(); 14219 goto L2elem; 14220 } 14221 if (e2.implicitConvTo(tb1next) >= MATCHconvert) 14222 { 14223 e2 = e2.implicitCastTo(sc, tb1next); 14224 type = tb1next.arrayOf(); 14225 L2elem: 14226 if (tb2.ty == Tarray || tb2.ty == Tsarray) 14227 { 14228 // Make e2 into [e2] 14229 e2 = new ArrayLiteralExp(e2.loc, e2); 14230 e2.type = type; 14231 } 14232 return optimize(WANTvalue); 14233 } 14234 } 14235 // Check for: element ~ array 14236 if ((tb2.ty == Tsarray || tb2.ty == Tarray) && tb1.ty != Tvoid) 14237 { 14238 if (e2.op == TOKarrayliteral) 14239 { 14240 e1 = doCopyOrMove(sc, e1); 14241 } 14242 else if (e2.op == TOKstring) 14243 { 14244 } 14245 else 14246 { 14247 if (e1.checkPostblit(sc, tb1)) 14248 return new ErrorExp(); 14249 } 14250 14251 if (e2.op == TOKarrayliteral && e2.implicitConvTo(tb1.arrayOf())) 14252 { 14253 e2 = e2.implicitCastTo(sc, tb1.arrayOf()); 14254 type = tb1.arrayOf(); 14255 goto L1elem; 14256 } 14257 if (e1.implicitConvTo(tb2next) >= MATCHconvert) 14258 { 14259 e1 = e1.implicitCastTo(sc, tb2next); 14260 type = tb2next.arrayOf(); 14261 L1elem: 14262 if (tb1.ty == Tarray || tb1.ty == Tsarray) 14263 { 14264 // Make e1 into [e1] 14265 e1 = new ArrayLiteralExp(e1.loc, e1); 14266 e1.type = type; 14267 } 14268 return optimize(WANTvalue); 14269 } 14270 } 14271 14272 Lpeer: 14273 if ((tb1.ty == Tsarray || tb1.ty == Tarray) && (tb2.ty == Tsarray || tb2.ty == Tarray) && (tb1next.mod || tb2next.mod) && (tb1next.mod != tb2next.mod)) 14274 { 14275 Type t1 = tb1next.mutableOf().constOf().arrayOf(); 14276 Type t2 = tb2next.mutableOf().constOf().arrayOf(); 14277 if (e1.op == TOKstring && !(cast(StringExp)e1).committed) 14278 e1.type = t1; 14279 else 14280 e1 = e1.castTo(sc, t1); 14281 if (e2.op == TOKstring && !(cast(StringExp)e2).committed) 14282 e2.type = t2; 14283 else 14284 e2 = e2.castTo(sc, t2); 14285 } 14286 14287 if (Expression ex = typeCombine(this, sc)) 14288 return ex; 14289 type = type.toHeadMutable(); 14290 14291 Type tb = type.toBasetype(); 14292 if (tb.ty == Tsarray) 14293 type = tb.nextOf().arrayOf(); 14294 if (type.ty == Tarray && tb1next && tb2next && tb1next.mod != tb2next.mod) 14295 { 14296 type = type.nextOf().toHeadMutable().arrayOf(); 14297 } 14298 if (Type tbn = tb.nextOf()) 14299 { 14300 if (checkPostblit(sc, tbn)) 14301 return new ErrorExp(); 14302 } 14303 version (none) 14304 { 14305 e1.type.print(); 14306 e2.type.print(); 14307 type.print(); 14308 print(); 14309 } 14310 Type t1 = e1.type.toBasetype(); 14311 Type t2 = e2.type.toBasetype(); 14312 if ((t1.ty == Tarray || t1.ty == Tsarray) && 14313 (t2.ty == Tarray || t2.ty == Tsarray)) 14314 { 14315 // Normalize to ArrayLiteralExp or StringExp as far as possible 14316 e = optimize(WANTvalue); 14317 } 14318 else 14319 { 14320 //printf("(%s) ~ (%s)\n", e1->toChars(), e2->toChars()); 14321 return incompatibleTypes(); 14322 } 14323 14324 return e; 14325 } 14326 14327 override void accept(Visitor v) 14328 { 14329 v.visit(this); 14330 } 14331 } 14332 14333 /*********************************************************** 14334 */ 14335 extern (C++) final class MulExp : BinExp 14336 { 14337 extern (D) this(Loc loc, Expression e1, Expression e2) 14338 { 14339 super(loc, TOKmul, __traits(classInstanceSize, MulExp), e1, e2); 14340 } 14341 14342 override Expression semantic(Scope* sc) 14343 { 14344 version (none) 14345 { 14346 printf("MulExp::semantic() %s\n", toChars()); 14347 } 14348 if (type) 14349 return this; 14350 14351 if (Expression ex = binSemanticProp(sc)) 14352 return ex; 14353 Expression e = op_overload(sc); 14354 if (e) 14355 return e; 14356 14357 if (Expression ex = typeCombine(this, sc)) 14358 return ex; 14359 14360 Type tb = type.toBasetype(); 14361 if (tb.ty == Tarray || tb.ty == Tsarray) 14362 { 14363 if (!isArrayOpValid(this)) 14364 { 14365 error("invalid array operation %s (possible missing [])", toChars()); 14366 return new ErrorExp(); 14367 } 14368 return this; 14369 } 14370 14371 if (checkArithmeticBin()) 14372 return new ErrorExp(); 14373 14374 if (type.isfloating()) 14375 { 14376 Type t1 = e1.type; 14377 Type t2 = e2.type; 14378 14379 if (t1.isreal()) 14380 { 14381 type = t2; 14382 } 14383 else if (t2.isreal()) 14384 { 14385 type = t1; 14386 } 14387 else if (t1.isimaginary()) 14388 { 14389 if (t2.isimaginary()) 14390 { 14391 switch (t1.toBasetype().ty) 14392 { 14393 case Timaginary32: 14394 type = Type.tfloat32; 14395 break; 14396 14397 case Timaginary64: 14398 type = Type.tfloat64; 14399 break; 14400 14401 case Timaginary80: 14402 type = Type.tfloat80; 14403 break; 14404 14405 default: 14406 assert(0); 14407 } 14408 14409 // iy * iv = -yv 14410 e1.type = type; 14411 e2.type = type; 14412 e = new NegExp(loc, this); 14413 e = e.semantic(sc); 14414 return e; 14415 } 14416 else 14417 type = t2; // t2 is complex 14418 } 14419 else if (t2.isimaginary()) 14420 { 14421 type = t1; // t1 is complex 14422 } 14423 } 14424 else if (tb.ty == Tvector && (cast(TypeVector)tb).elementType().size(loc) != 2) 14425 { 14426 // Only short[8] and ushort[8] work with multiply 14427 return incompatibleTypes(); 14428 } 14429 return this; 14430 } 14431 14432 override void accept(Visitor v) 14433 { 14434 v.visit(this); 14435 } 14436 } 14437 14438 /*********************************************************** 14439 */ 14440 extern (C++) final class DivExp : BinExp 14441 { 14442 extern (D) this(Loc loc, Expression e1, Expression e2) 14443 { 14444 super(loc, TOKdiv, __traits(classInstanceSize, DivExp), e1, e2); 14445 } 14446 14447 override Expression semantic(Scope* sc) 14448 { 14449 if (type) 14450 return this; 14451 14452 if (Expression ex = binSemanticProp(sc)) 14453 return ex; 14454 Expression e = op_overload(sc); 14455 if (e) 14456 return e; 14457 14458 if (Expression ex = typeCombine(this, sc)) 14459 return ex; 14460 14461 Type tb = type.toBasetype(); 14462 if (tb.ty == Tarray || tb.ty == Tsarray) 14463 { 14464 if (!isArrayOpValid(this)) 14465 { 14466 error("invalid array operation %s (possible missing [])", toChars()); 14467 return new ErrorExp(); 14468 } 14469 return this; 14470 } 14471 14472 if (checkArithmeticBin()) 14473 return new ErrorExp(); 14474 14475 if (type.isfloating()) 14476 { 14477 Type t1 = e1.type; 14478 Type t2 = e2.type; 14479 14480 if (t1.isreal()) 14481 { 14482 type = t2; 14483 if (t2.isimaginary()) 14484 { 14485 // x/iv = i(-x/v) 14486 e2.type = t1; 14487 e = new NegExp(loc, this); 14488 e = e.semantic(sc); 14489 return e; 14490 } 14491 } 14492 else if (t2.isreal()) 14493 { 14494 type = t1; 14495 } 14496 else if (t1.isimaginary()) 14497 { 14498 if (t2.isimaginary()) 14499 { 14500 switch (t1.toBasetype().ty) 14501 { 14502 case Timaginary32: 14503 type = Type.tfloat32; 14504 break; 14505 14506 case Timaginary64: 14507 type = Type.tfloat64; 14508 break; 14509 14510 case Timaginary80: 14511 type = Type.tfloat80; 14512 break; 14513 14514 default: 14515 assert(0); 14516 } 14517 } 14518 else 14519 type = t2; // t2 is complex 14520 } 14521 else if (t2.isimaginary()) 14522 { 14523 type = t1; // t1 is complex 14524 } 14525 } 14526 else if (tb.ty == Tvector) 14527 { 14528 return incompatibleTypes(); 14529 } 14530 return this; 14531 } 14532 14533 override void accept(Visitor v) 14534 { 14535 v.visit(this); 14536 } 14537 } 14538 14539 /*********************************************************** 14540 */ 14541 extern (C++) final class ModExp : BinExp 14542 { 14543 extern (D) this(Loc loc, Expression e1, Expression e2) 14544 { 14545 super(loc, TOKmod, __traits(classInstanceSize, ModExp), e1, e2); 14546 } 14547 14548 override Expression semantic(Scope* sc) 14549 { 14550 if (type) 14551 return this; 14552 14553 if (Expression ex = binSemanticProp(sc)) 14554 return ex; 14555 Expression e = op_overload(sc); 14556 if (e) 14557 return e; 14558 14559 if (Expression ex = typeCombine(this, sc)) 14560 return ex; 14561 14562 Type tb = type.toBasetype(); 14563 if (tb.ty == Tarray || tb.ty == Tsarray) 14564 { 14565 if (!isArrayOpValid(this)) 14566 { 14567 error("invalid array operation %s (possible missing [])", toChars()); 14568 return new ErrorExp(); 14569 } 14570 return this; 14571 } 14572 if (tb.ty == Tvector) 14573 { 14574 return incompatibleTypes(); 14575 } 14576 14577 if (checkArithmeticBin()) 14578 return new ErrorExp(); 14579 14580 if (type.isfloating()) 14581 { 14582 type = e1.type; 14583 if (e2.type.iscomplex()) 14584 { 14585 error("cannot perform modulo complex arithmetic"); 14586 return new ErrorExp(); 14587 } 14588 } 14589 return this; 14590 } 14591 14592 override void accept(Visitor v) 14593 { 14594 v.visit(this); 14595 } 14596 } 14597 14598 /*********************************************************** 14599 */ 14600 extern (C++) final class PowExp : BinExp 14601 { 14602 extern (D) this(Loc loc, Expression e1, Expression e2) 14603 { 14604 super(loc, TOKpow, __traits(classInstanceSize, PowExp), e1, e2); 14605 } 14606 14607 override Expression semantic(Scope* sc) 14608 { 14609 if (type) 14610 return this; 14611 14612 //printf("PowExp::semantic() %s\n", toChars()); 14613 if (Expression ex = binSemanticProp(sc)) 14614 return ex; 14615 Expression e = op_overload(sc); 14616 if (e) 14617 return e; 14618 14619 if (Expression ex = typeCombine(this, sc)) 14620 return ex; 14621 14622 Type tb = type.toBasetype(); 14623 if (tb.ty == Tarray || tb.ty == Tsarray) 14624 { 14625 if (!isArrayOpValid(this)) 14626 { 14627 error("invalid array operation %s (possible missing [])", toChars()); 14628 return new ErrorExp(); 14629 } 14630 return this; 14631 } 14632 14633 if (checkArithmeticBin()) 14634 return new ErrorExp(); 14635 14636 // For built-in numeric types, there are several cases. 14637 // TODO: backend support, especially for e1 ^^ 2. 14638 14639 // First, attempt to fold the expression. 14640 e = optimize(WANTvalue); 14641 if (e.op != TOKpow) 14642 { 14643 e = e.semantic(sc); 14644 return e; 14645 } 14646 14647 // Determine if we're raising to an integer power. 14648 sinteger_t intpow = 0; 14649 if (e2.op == TOKint64 && (cast(sinteger_t)e2.toInteger() == 2 || cast(sinteger_t)e2.toInteger() == 3)) 14650 intpow = e2.toInteger(); 14651 else if (e2.op == TOKfloat64 && (e2.toReal() == real_t(cast(sinteger_t)e2.toReal()))) 14652 intpow = cast(sinteger_t)e2.toReal(); 14653 14654 // Deal with x^^2, x^^3 immediately, since they are of practical importance. 14655 if (intpow == 2 || intpow == 3) 14656 { 14657 // Replace x^^2 with (tmp = x, tmp*tmp) 14658 // Replace x^^3 with (tmp = x, tmp*tmp*tmp) 14659 auto tmp = copyToTemp(0, "__powtmp", e1); 14660 Expression de = new DeclarationExp(loc, tmp); 14661 Expression ve = new VarExp(loc, tmp); 14662 14663 /* Note that we're reusing ve. This should be ok. 14664 */ 14665 Expression me = new MulExp(loc, ve, ve); 14666 if (intpow == 3) 14667 me = new MulExp(loc, me, ve); 14668 e = new CommaExp(loc, de, me); 14669 e = e.semantic(sc); 14670 return e; 14671 } 14672 14673 Module mmath = loadStdMath(); 14674 if (!mmath) 14675 { 14676 //error("requires std.math for ^^ operators"); 14677 //fatal(); 14678 // Leave handling of PowExp to the backend, or throw 14679 // an error gracefully if no backend support exists. 14680 if (Expression ex = typeCombine(this, sc)) 14681 return ex; 14682 return this; 14683 } 14684 e = new ScopeExp(loc, mmath); 14685 14686 if (e2.op == TOKfloat64 && e2.toReal() == CTFloat.half) 14687 { 14688 // Replace e1 ^^ 0.5 with .std.math.sqrt(x) 14689 e = new CallExp(loc, new DotIdExp(loc, e, Id._sqrt), e1); 14690 } 14691 else 14692 { 14693 // Replace e1 ^^ e2 with .std.math.pow(e1, e2) 14694 e = new CallExp(loc, new DotIdExp(loc, e, Id._pow), e1, e2); 14695 } 14696 e = e.semantic(sc); 14697 return e; 14698 } 14699 14700 override void accept(Visitor v) 14701 { 14702 v.visit(this); 14703 } 14704 } 14705 14706 extern (C++) Module loadStdMath() 14707 { 14708 static __gshared Import impStdMath = null; 14709 if (!impStdMath) 14710 { 14711 auto a = new Identifiers(); 14712 a.push(Id.std); 14713 auto s = new Import(Loc(), a, Id.math, null, false); 14714 s.load(null); 14715 if (s.mod) 14716 { 14717 s.mod.importAll(null); 14718 s.mod.semantic(null); 14719 } 14720 impStdMath = s; 14721 } 14722 return impStdMath.mod; 14723 } 14724 14725 /*********************************************************** 14726 */ 14727 extern (C++) final class ShlExp : BinExp 14728 { 14729 extern (D) this(Loc loc, Expression e1, Expression e2) 14730 { 14731 super(loc, TOKshl, __traits(classInstanceSize, ShlExp), e1, e2); 14732 } 14733 14734 override Expression semantic(Scope* sc) 14735 { 14736 //printf("ShlExp::semantic(), type = %p\n", type); 14737 if (type) 14738 return this; 14739 14740 if (Expression ex = binSemanticProp(sc)) 14741 return ex; 14742 Expression e = op_overload(sc); 14743 if (e) 14744 return e; 14745 14746 if (checkIntegralBin()) 14747 return new ErrorExp(); 14748 if (e1.type.toBasetype().ty == Tvector || e2.type.toBasetype().ty == Tvector) 14749 { 14750 return incompatibleTypes(); 14751 } 14752 e1 = integralPromotions(e1, sc); 14753 e2 = e2.castTo(sc, Type.tshiftcnt); 14754 14755 type = e1.type; 14756 return this; 14757 } 14758 14759 override void accept(Visitor v) 14760 { 14761 v.visit(this); 14762 } 14763 } 14764 14765 /*********************************************************** 14766 */ 14767 extern (C++) final class ShrExp : BinExp 14768 { 14769 extern (D) this(Loc loc, Expression e1, Expression e2) 14770 { 14771 super(loc, TOKshr, __traits(classInstanceSize, ShrExp), e1, e2); 14772 } 14773 14774 override Expression semantic(Scope* sc) 14775 { 14776 if (type) 14777 return this; 14778 14779 if (Expression ex = binSemanticProp(sc)) 14780 return ex; 14781 Expression e = op_overload(sc); 14782 if (e) 14783 return e; 14784 14785 if (checkIntegralBin()) 14786 return new ErrorExp(); 14787 if (e1.type.toBasetype().ty == Tvector || e2.type.toBasetype().ty == Tvector) 14788 { 14789 return incompatibleTypes(); 14790 } 14791 e1 = integralPromotions(e1, sc); 14792 e2 = e2.castTo(sc, Type.tshiftcnt); 14793 14794 type = e1.type; 14795 return this; 14796 } 14797 14798 override void accept(Visitor v) 14799 { 14800 v.visit(this); 14801 } 14802 } 14803 14804 /*********************************************************** 14805 */ 14806 extern (C++) final class UshrExp : BinExp 14807 { 14808 extern (D) this(Loc loc, Expression e1, Expression e2) 14809 { 14810 super(loc, TOKushr, __traits(classInstanceSize, UshrExp), e1, e2); 14811 } 14812 14813 override Expression semantic(Scope* sc) 14814 { 14815 if (type) 14816 return this; 14817 14818 if (Expression ex = binSemanticProp(sc)) 14819 return ex; 14820 Expression e = op_overload(sc); 14821 if (e) 14822 return e; 14823 14824 if (checkIntegralBin()) 14825 return new ErrorExp(); 14826 if (e1.type.toBasetype().ty == Tvector || e2.type.toBasetype().ty == Tvector) 14827 { 14828 return incompatibleTypes(); 14829 } 14830 14831 e1 = integralPromotions(e1, sc); 14832 e2 = e2.castTo(sc, Type.tshiftcnt); 14833 14834 type = e1.type; 14835 return this; 14836 } 14837 14838 override void accept(Visitor v) 14839 { 14840 v.visit(this); 14841 } 14842 } 14843 14844 /*********************************************************** 14845 */ 14846 extern (C++) final class AndExp : BinExp 14847 { 14848 extern (D) this(Loc loc, Expression e1, Expression e2) 14849 { 14850 super(loc, TOKand, __traits(classInstanceSize, AndExp), e1, e2); 14851 } 14852 14853 override Expression semantic(Scope* sc) 14854 { 14855 if (type) 14856 return this; 14857 14858 if (Expression ex = binSemanticProp(sc)) 14859 return ex; 14860 Expression e = op_overload(sc); 14861 if (e) 14862 return e; 14863 14864 if (e1.type.toBasetype().ty == Tbool && e2.type.toBasetype().ty == Tbool) 14865 { 14866 type = e1.type; 14867 return this; 14868 } 14869 14870 if (Expression ex = typeCombine(this, sc)) 14871 return ex; 14872 14873 Type tb = type.toBasetype(); 14874 if (tb.ty == Tarray || tb.ty == Tsarray) 14875 { 14876 if (!isArrayOpValid(this)) 14877 { 14878 error("invalid array operation %s (possible missing [])", toChars()); 14879 return new ErrorExp(); 14880 } 14881 return this; 14882 } 14883 14884 if (checkIntegralBin()) 14885 return new ErrorExp(); 14886 14887 return this; 14888 } 14889 14890 override void accept(Visitor v) 14891 { 14892 v.visit(this); 14893 } 14894 } 14895 14896 /*********************************************************** 14897 */ 14898 extern (C++) final class OrExp : BinExp 14899 { 14900 extern (D) this(Loc loc, Expression e1, Expression e2) 14901 { 14902 super(loc, TOKor, __traits(classInstanceSize, OrExp), e1, e2); 14903 } 14904 14905 override Expression semantic(Scope* sc) 14906 { 14907 if (type) 14908 return this; 14909 14910 if (Expression ex = binSemanticProp(sc)) 14911 return ex; 14912 Expression e = op_overload(sc); 14913 if (e) 14914 return e; 14915 14916 if (e1.type.toBasetype().ty == Tbool && e2.type.toBasetype().ty == Tbool) 14917 { 14918 type = e1.type; 14919 return this; 14920 } 14921 14922 if (Expression ex = typeCombine(this, sc)) 14923 return ex; 14924 14925 Type tb = type.toBasetype(); 14926 if (tb.ty == Tarray || tb.ty == Tsarray) 14927 { 14928 if (!isArrayOpValid(this)) 14929 { 14930 error("invalid array operation %s (possible missing [])", toChars()); 14931 return new ErrorExp(); 14932 } 14933 return this; 14934 } 14935 14936 if (checkIntegralBin()) 14937 return new ErrorExp(); 14938 14939 return this; 14940 } 14941 14942 override void accept(Visitor v) 14943 { 14944 v.visit(this); 14945 } 14946 } 14947 14948 /*********************************************************** 14949 */ 14950 extern (C++) final class XorExp : BinExp 14951 { 14952 extern (D) this(Loc loc, Expression e1, Expression e2) 14953 { 14954 super(loc, TOKxor, __traits(classInstanceSize, XorExp), e1, e2); 14955 } 14956 14957 override Expression semantic(Scope* sc) 14958 { 14959 if (type) 14960 return this; 14961 14962 if (Expression ex = binSemanticProp(sc)) 14963 return ex; 14964 Expression e = op_overload(sc); 14965 if (e) 14966 return e; 14967 14968 if (e1.type.toBasetype().ty == Tbool && e2.type.toBasetype().ty == Tbool) 14969 { 14970 type = e1.type; 14971 return this; 14972 } 14973 14974 if (Expression ex = typeCombine(this, sc)) 14975 return ex; 14976 14977 Type tb = type.toBasetype(); 14978 if (tb.ty == Tarray || tb.ty == Tsarray) 14979 { 14980 if (!isArrayOpValid(this)) 14981 { 14982 error("invalid array operation %s (possible missing [])", toChars()); 14983 return new ErrorExp(); 14984 } 14985 return this; 14986 } 14987 14988 if (checkIntegralBin()) 14989 return new ErrorExp(); 14990 14991 return this; 14992 } 14993 14994 override void accept(Visitor v) 14995 { 14996 v.visit(this); 14997 } 14998 } 14999 15000 /*********************************************************** 15001 */ 15002 extern (C++) final class OrOrExp : BinExp 15003 { 15004 extern (D) this(Loc loc, Expression e1, Expression e2) 15005 { 15006 super(loc, TOKoror, __traits(classInstanceSize, OrOrExp), e1, e2); 15007 } 15008 15009 override Expression semantic(Scope* sc) 15010 { 15011 if (type) 15012 return this; 15013 15014 setNoderefOperands(); 15015 15016 // same as for AndAnd 15017 e1 = e1.semantic(sc); 15018 e1 = resolveProperties(sc, e1); 15019 e1 = e1.toBoolean(sc); 15020 uint cs1 = sc.callSuper; 15021 15022 if (sc.flags & SCOPEcondition) 15023 { 15024 /* If in static if, don't evaluate e2 if we don't have to. 15025 */ 15026 e1 = e1.optimize(WANTvalue); 15027 if (e1.isBool(true)) 15028 { 15029 return new IntegerExp(loc, 1, Type.tbool); 15030 } 15031 } 15032 15033 e2 = e2.semantic(sc); 15034 sc.mergeCallSuper(loc, cs1); 15035 e2 = resolveProperties(sc, e2); 15036 15037 auto f1 = checkNonAssignmentArrayOp(e1); 15038 auto f2 = checkNonAssignmentArrayOp(e2); 15039 if (f1 || f2) 15040 return new ErrorExp(); 15041 15042 if (e2.type.ty == Tvoid) 15043 type = Type.tvoid; 15044 else 15045 { 15046 e2 = e2.toBoolean(sc); 15047 type = Type.tbool; 15048 } 15049 if (e2.op == TOKtype || e2.op == TOKscope) 15050 { 15051 error("%s is not an expression", e2.toChars()); 15052 return new ErrorExp(); 15053 } 15054 if (e1.op == TOKerror) 15055 return e1; 15056 if (e2.op == TOKerror) 15057 return e2; 15058 15059 return this; 15060 } 15061 15062 override Expression toBoolean(Scope* sc) 15063 { 15064 auto ex2 = e2.toBoolean(sc); 15065 if (ex2.op == TOKerror) 15066 return ex2; 15067 e2 = ex2; 15068 return this; 15069 } 15070 15071 override void accept(Visitor v) 15072 { 15073 v.visit(this); 15074 } 15075 } 15076 15077 /*********************************************************** 15078 */ 15079 extern (C++) final class AndAndExp : BinExp 15080 { 15081 extern (D) this(Loc loc, Expression e1, Expression e2) 15082 { 15083 super(loc, TOKandand, __traits(classInstanceSize, AndAndExp), e1, e2); 15084 } 15085 15086 override Expression semantic(Scope* sc) 15087 { 15088 if (type) 15089 return this; 15090 15091 setNoderefOperands(); 15092 15093 // same as for OrOr 15094 e1 = e1.semantic(sc); 15095 e1 = resolveProperties(sc, e1); 15096 e1 = e1.toBoolean(sc); 15097 uint cs1 = sc.callSuper; 15098 15099 if (sc.flags & SCOPEcondition) 15100 { 15101 /* If in static if, don't evaluate e2 if we don't have to. 15102 */ 15103 e1 = e1.optimize(WANTvalue); 15104 if (e1.isBool(false)) 15105 { 15106 return new IntegerExp(loc, 0, Type.tbool); 15107 } 15108 } 15109 15110 e2 = e2.semantic(sc); 15111 sc.mergeCallSuper(loc, cs1); 15112 e2 = resolveProperties(sc, e2); 15113 15114 auto f1 = checkNonAssignmentArrayOp(e1); 15115 auto f2 = checkNonAssignmentArrayOp(e2); 15116 if (f1 || f2) 15117 return new ErrorExp(); 15118 15119 if (e2.type.ty == Tvoid) 15120 type = Type.tvoid; 15121 else 15122 { 15123 e2 = e2.toBoolean(sc); 15124 type = Type.tbool; 15125 } 15126 if (e2.op == TOKtype || e2.op == TOKscope) 15127 { 15128 error("%s is not an expression", e2.toChars()); 15129 return new ErrorExp(); 15130 } 15131 if (e1.op == TOKerror) 15132 return e1; 15133 if (e2.op == TOKerror) 15134 return e2; 15135 15136 return this; 15137 } 15138 15139 override Expression toBoolean(Scope* sc) 15140 { 15141 auto ex2 = e2.toBoolean(sc); 15142 if (ex2.op == TOKerror) 15143 return ex2; 15144 e2 = ex2; 15145 return this; 15146 } 15147 15148 override void accept(Visitor v) 15149 { 15150 v.visit(this); 15151 } 15152 } 15153 15154 /*********************************************************** 15155 */ 15156 extern (C++) final class CmpExp : BinExp 15157 { 15158 extern (D) this(TOK op, Loc loc, Expression e1, Expression e2) 15159 { 15160 super(loc, op, __traits(classInstanceSize, CmpExp), e1, e2); 15161 } 15162 15163 override Expression semantic(Scope* sc) 15164 { 15165 static if (LOGSEMANTIC) 15166 { 15167 printf("CmpExp::semantic('%s')\n", toChars()); 15168 } 15169 if (type) 15170 return this; 15171 15172 setNoderefOperands(); 15173 15174 if (Expression ex = binSemanticProp(sc)) 15175 return ex; 15176 Type t1 = e1.type.toBasetype(); 15177 Type t2 = e2.type.toBasetype(); 15178 if (t1.ty == Tclass && e2.op == TOKnull || t2.ty == Tclass && e1.op == TOKnull) 15179 { 15180 error("do not use null when comparing class types"); 15181 return new ErrorExp(); 15182 } 15183 15184 Expression e = op_overload(sc); 15185 if (e) 15186 { 15187 if (!e.type.isscalar() && e.type.equals(e1.type)) 15188 { 15189 error("recursive opCmp expansion"); 15190 return new ErrorExp(); 15191 } 15192 if (e.op == TOKcall) 15193 { 15194 e = new CmpExp(op, loc, e, new IntegerExp(loc, 0, Type.tint32)); 15195 e = e.semantic(sc); 15196 } 15197 return e; 15198 } 15199 15200 if (Expression ex = typeCombine(this, sc)) 15201 return ex; 15202 15203 auto f1 = checkNonAssignmentArrayOp(e1); 15204 auto f2 = checkNonAssignmentArrayOp(e2); 15205 if (f1 || f2) 15206 return new ErrorExp(); 15207 15208 type = Type.tbool; 15209 15210 // Special handling for array comparisons 15211 t1 = e1.type.toBasetype(); 15212 t2 = e2.type.toBasetype(); 15213 if ((t1.ty == Tarray || t1.ty == Tsarray || t1.ty == Tpointer) && (t2.ty == Tarray || t2.ty == Tsarray || t2.ty == Tpointer)) 15214 { 15215 Type t1next = t1.nextOf(); 15216 Type t2next = t2.nextOf(); 15217 if (t1next.implicitConvTo(t2next) < MATCHconst && t2next.implicitConvTo(t1next) < MATCHconst && (t1next.ty != Tvoid && t2next.ty != Tvoid)) 15218 { 15219 error("array comparison type mismatch, %s vs %s", t1next.toChars(), t2next.toChars()); 15220 return new ErrorExp(); 15221 } 15222 if ((t1.ty == Tarray || t1.ty == Tsarray) && (t2.ty == Tarray || t2.ty == Tsarray)) 15223 { 15224 semanticTypeInfo(sc, t1.nextOf()); 15225 } 15226 } 15227 else if (t1.ty == Tstruct || t2.ty == Tstruct || (t1.ty == Tclass && t2.ty == Tclass)) 15228 { 15229 if (t2.ty == Tstruct) 15230 error("need member function opCmp() for %s %s to compare", t2.toDsymbol(sc).kind(), t2.toChars()); 15231 else 15232 error("need member function opCmp() for %s %s to compare", t1.toDsymbol(sc).kind(), t1.toChars()); 15233 return new ErrorExp(); 15234 } 15235 else if (t1.iscomplex() || t2.iscomplex()) 15236 { 15237 error("compare not defined for complex operands"); 15238 return new ErrorExp(); 15239 } 15240 else if (t1.ty == Taarray || t2.ty == Taarray) 15241 { 15242 error("%s is not defined for associative arrays", Token.toChars(op)); 15243 return new ErrorExp(); 15244 } 15245 else if (t1.ty == Tvector) 15246 { 15247 return incompatibleTypes(); 15248 } 15249 else 15250 { 15251 bool r1 = e1.checkValue(); 15252 bool r2 = e2.checkValue(); 15253 if (r1 || r2) 15254 return new ErrorExp(); 15255 } 15256 15257 TOK altop; 15258 switch (op) 15259 { 15260 // Refer rel_integral[] table 15261 case TOKunord: 15262 altop = TOKerror; 15263 break; 15264 15265 case TOKlg: 15266 altop = TOKnotequal; 15267 break; 15268 15269 case TOKleg: 15270 altop = TOKerror; 15271 break; 15272 15273 case TOKule: 15274 altop = TOKle; 15275 break; 15276 15277 case TOKul: 15278 altop = TOKlt; 15279 break; 15280 15281 case TOKuge: 15282 altop = TOKge; 15283 break; 15284 15285 case TOKug: 15286 altop = TOKgt; 15287 break; 15288 15289 case TOKue: 15290 altop = TOKequal; 15291 break; 15292 15293 default: 15294 altop = TOKreserved; 15295 break; 15296 } 15297 if (altop == TOKerror && (t1.ty == Tarray || t1.ty == Tsarray || t2.ty == Tarray || t2.ty == Tsarray)) 15298 { 15299 error("'%s' is not defined for array comparisons", Token.toChars(op)); 15300 return new ErrorExp(); 15301 } 15302 if (altop != TOKreserved) 15303 { 15304 if (!t1.isfloating()) 15305 { 15306 if (altop == TOKerror) 15307 { 15308 const(char)* s = op == TOKunord ? "false" : "true"; 15309 error("floating point operator '%s' always returns %s for non-floating comparisons", Token.toChars(op), s); 15310 } 15311 else 15312 { 15313 error("use '%s' for non-floating comparisons rather than floating point operator '%s'", Token.toChars(altop), Token.toChars(op)); 15314 } 15315 } 15316 else 15317 { 15318 error("use std.math.isNaN to deal with NaN operands rather than floating point operator '%s'", Token.toChars(op)); 15319 } 15320 return new ErrorExp(); 15321 } 15322 15323 //printf("CmpExp: %s, type = %s\n", e->toChars(), e->type->toChars()); 15324 return this; 15325 } 15326 15327 override void accept(Visitor v) 15328 { 15329 v.visit(this); 15330 } 15331 } 15332 15333 /*********************************************************** 15334 */ 15335 extern (C++) final class InExp : BinExp 15336 { 15337 extern (D) this(Loc loc, Expression e1, Expression e2) 15338 { 15339 super(loc, TOKin, __traits(classInstanceSize, InExp), e1, e2); 15340 } 15341 15342 override Expression semantic(Scope* sc) 15343 { 15344 if (type) 15345 return this; 15346 15347 if (Expression ex = binSemanticProp(sc)) 15348 return ex; 15349 Expression e = op_overload(sc); 15350 if (e) 15351 return e; 15352 15353 Type t2b = e2.type.toBasetype(); 15354 switch (t2b.ty) 15355 { 15356 case Taarray: 15357 { 15358 TypeAArray ta = cast(TypeAArray)t2b; 15359 15360 // Special handling for array keys 15361 if (!arrayTypeCompatible(e1.loc, e1.type, ta.index)) 15362 { 15363 // Convert key to type of key 15364 e1 = e1.implicitCastTo(sc, ta.index); 15365 } 15366 15367 semanticTypeInfo(sc, ta.index); 15368 15369 // Return type is pointer to value 15370 type = ta.nextOf().pointerTo(); 15371 break; 15372 } 15373 default: 15374 error("rvalue of in expression must be an associative array, not %s", e2.type.toChars()); 15375 goto case Terror; 15376 case Terror: 15377 return new ErrorExp(); 15378 } 15379 return this; 15380 } 15381 15382 override void accept(Visitor v) 15383 { 15384 v.visit(this); 15385 } 15386 } 15387 15388 /*********************************************************** 15389 * This deletes the key e1 from the associative array e2 15390 */ 15391 extern (C++) final class RemoveExp : BinExp 15392 { 15393 extern (D) this(Loc loc, Expression e1, Expression e2) 15394 { 15395 super(loc, TOKremove, __traits(classInstanceSize, RemoveExp), e1, e2); 15396 type = Type.tbool; 15397 } 15398 15399 override Expression semantic(Scope* sc) 15400 { 15401 if (Expression ex = binSemantic(sc)) 15402 return ex; 15403 return this; 15404 } 15405 15406 override void accept(Visitor v) 15407 { 15408 v.visit(this); 15409 } 15410 } 15411 15412 /*********************************************************** 15413 * == and != 15414 */ 15415 extern (C++) final class EqualExp : BinExp 15416 { 15417 extern (D) this(TOK op, Loc loc, Expression e1, Expression e2) 15418 { 15419 super(loc, op, __traits(classInstanceSize, EqualExp), e1, e2); 15420 assert(op == TOKequal || op == TOKnotequal); 15421 } 15422 15423 override Expression semantic(Scope* sc) 15424 { 15425 //printf("EqualExp::semantic('%s')\n", toChars()); 15426 if (type) 15427 return this; 15428 15429 setNoderefOperands(); 15430 15431 if (auto e = binSemanticProp(sc)) 15432 return e; 15433 if (e1.op == TOKtype || e2.op == TOKtype) 15434 return incompatibleTypes(); 15435 15436 /* Before checking for operator overloading, check to see if we're 15437 * comparing the addresses of two statics. If so, we can just see 15438 * if they are the same symbol. 15439 */ 15440 if (e1.op == TOKaddress && e2.op == TOKaddress) 15441 { 15442 AddrExp ae1 = cast(AddrExp)e1; 15443 AddrExp ae2 = cast(AddrExp)e2; 15444 if (ae1.e1.op == TOKvar && ae2.e1.op == TOKvar) 15445 { 15446 VarExp ve1 = cast(VarExp)ae1.e1; 15447 VarExp ve2 = cast(VarExp)ae2.e1; 15448 if (ve1.var == ve2.var) 15449 { 15450 // They are the same, result is 'true' for ==, 'false' for != 15451 return new IntegerExp(loc, (op == TOKequal), Type.tbool); 15452 } 15453 } 15454 } 15455 15456 if (auto e = op_overload(sc)) 15457 return e; 15458 15459 if (auto e = typeCombine(this, sc)) 15460 return e; 15461 15462 auto f1 = checkNonAssignmentArrayOp(e1); 15463 auto f2 = checkNonAssignmentArrayOp(e2); 15464 if (f1 || f2) 15465 return new ErrorExp(); 15466 15467 type = Type.tbool; 15468 15469 // Special handling for array comparisons 15470 if (!arrayTypeCompatible(loc, e1.type, e2.type)) 15471 { 15472 if (e1.type != e2.type && e1.type.isfloating() && e2.type.isfloating()) 15473 { 15474 // Cast both to complex 15475 e1 = e1.castTo(sc, Type.tcomplex80); 15476 e2 = e2.castTo(sc, Type.tcomplex80); 15477 } 15478 } 15479 if (e1.type.toBasetype().ty == Taarray) 15480 semanticTypeInfo(sc, e1.type.toBasetype()); 15481 15482 if (e1.type.toBasetype().ty == Tvector) 15483 return incompatibleTypes(); 15484 15485 return this; 15486 } 15487 15488 override void accept(Visitor v) 15489 { 15490 v.visit(this); 15491 } 15492 } 15493 15494 /*********************************************************** 15495 * is and !is 15496 */ 15497 extern (C++) final class IdentityExp : BinExp 15498 { 15499 extern (D) this(TOK op, Loc loc, Expression e1, Expression e2) 15500 { 15501 super(loc, op, __traits(classInstanceSize, IdentityExp), e1, e2); 15502 } 15503 15504 override Expression semantic(Scope* sc) 15505 { 15506 if (type) 15507 return this; 15508 15509 setNoderefOperands(); 15510 15511 if (auto e = binSemanticProp(sc)) 15512 return e; 15513 15514 if (auto e = typeCombine(this, sc)) 15515 return e; 15516 15517 auto f1 = checkNonAssignmentArrayOp(e1); 15518 auto f2 = checkNonAssignmentArrayOp(e2); 15519 if (f1 || f2) 15520 return new ErrorExp(); 15521 15522 type = Type.tbool; 15523 15524 if (e1.type != e2.type && e1.type.isfloating() && e2.type.isfloating()) 15525 { 15526 // Cast both to complex 15527 e1 = e1.castTo(sc, Type.tcomplex80); 15528 e2 = e2.castTo(sc, Type.tcomplex80); 15529 } 15530 15531 if (e1.type.toBasetype().ty == Tvector) 15532 return incompatibleTypes(); 15533 15534 if (e1.type.toBasetype().ty == Tsarray || 15535 e2.type.toBasetype().ty == Tsarray) 15536 deprecation("identity comparison of static arrays " 15537 "implicitly coerces them to slices, " 15538 "which are compared by reference"); 15539 15540 return this; 15541 } 15542 15543 override void accept(Visitor v) 15544 { 15545 v.visit(this); 15546 } 15547 } 15548 15549 /*********************************************************** 15550 */ 15551 extern (C++) final class CondExp : BinExp 15552 { 15553 Expression econd; 15554 15555 extern (D) this(Loc loc, Expression econd, Expression e1, Expression e2) 15556 { 15557 super(loc, TOKquestion, __traits(classInstanceSize, CondExp), e1, e2); 15558 this.econd = econd; 15559 } 15560 15561 override Expression syntaxCopy() 15562 { 15563 return new CondExp(loc, econd.syntaxCopy(), e1.syntaxCopy(), e2.syntaxCopy()); 15564 } 15565 15566 override Expression semantic(Scope* sc) 15567 { 15568 static if (LOGSEMANTIC) 15569 { 15570 printf("CondExp::semantic('%s')\n", toChars()); 15571 } 15572 if (type) 15573 return this; 15574 15575 if (econd.op == TOKdotid) 15576 (cast(DotIdExp)econd).noderef = true; 15577 15578 Expression ec = econd.semantic(sc); 15579 ec = resolveProperties(sc, ec); 15580 ec = ec.toBoolean(sc); 15581 15582 uint cs0 = sc.callSuper; 15583 uint* fi0 = sc.saveFieldInit(); 15584 Expression e1x = e1.semantic(sc); 15585 e1x = resolveProperties(sc, e1x); 15586 15587 uint cs1 = sc.callSuper; 15588 uint* fi1 = sc.fieldinit; 15589 sc.callSuper = cs0; 15590 sc.fieldinit = fi0; 15591 Expression e2x = e2.semantic(sc); 15592 e2x = resolveProperties(sc, e2x); 15593 15594 sc.mergeCallSuper(loc, cs1); 15595 sc.mergeFieldInit(loc, fi1); 15596 15597 if (ec.op == TOKerror) 15598 return ec; 15599 if (ec.type == Type.terror) 15600 return new ErrorExp(); 15601 econd = ec; 15602 15603 if (e1x.op == TOKerror) 15604 return e1x; 15605 if (e1x.type == Type.terror) 15606 return new ErrorExp(); 15607 e1 = e1x; 15608 15609 if (e2x.op == TOKerror) 15610 return e2x; 15611 if (e2x.type == Type.terror) 15612 return new ErrorExp(); 15613 e2 = e2x; 15614 15615 auto f0 = checkNonAssignmentArrayOp(econd); 15616 auto f1 = checkNonAssignmentArrayOp(e1); 15617 auto f2 = checkNonAssignmentArrayOp(e2); 15618 if (f0 || f1 || f2) 15619 return new ErrorExp(); 15620 15621 // If either operand is void, the result is void 15622 Type t1 = e1.type; 15623 Type t2 = e2.type; 15624 if (t1.ty == Tvoid || t2.ty == Tvoid) 15625 type = Type.tvoid; 15626 else if (t1 == t2) 15627 type = t1; 15628 else 15629 { 15630 if (Expression ex = typeCombine(this, sc)) 15631 return ex; 15632 15633 switch (e1.type.toBasetype().ty) 15634 { 15635 case Tcomplex32: 15636 case Tcomplex64: 15637 case Tcomplex80: 15638 e2 = e2.castTo(sc, e1.type); 15639 break; 15640 default: 15641 break; 15642 } 15643 switch (e2.type.toBasetype().ty) 15644 { 15645 case Tcomplex32: 15646 case Tcomplex64: 15647 case Tcomplex80: 15648 e1 = e1.castTo(sc, e2.type); 15649 break; 15650 default: 15651 break; 15652 } 15653 if (type.toBasetype().ty == Tarray) 15654 { 15655 e1 = e1.castTo(sc, type); 15656 e2 = e2.castTo(sc, type); 15657 } 15658 } 15659 type = type.merge2(); 15660 version (none) 15661 { 15662 printf("res: %s\n", type.toChars()); 15663 printf("e1 : %s\n", e1.type.toChars()); 15664 printf("e2 : %s\n", e2.type.toChars()); 15665 } 15666 15667 /* Bugzilla 14696: If either e1 or e2 contain temporaries which need dtor, 15668 * make them conditional. 15669 * Rewrite: 15670 * cond ? (__tmp1 = ..., __tmp1) : (__tmp2 = ..., __tmp2) 15671 * to: 15672 * (auto __cond = cond) ? (... __tmp1) : (... __tmp2) 15673 * and replace edtors of __tmp1 and __tmp2 with: 15674 * __tmp1->edtor --> __cond && __tmp1.dtor() 15675 * __tmp2->edtor --> __cond || __tmp2.dtor() 15676 */ 15677 hookDtors(sc); 15678 15679 return this; 15680 } 15681 15682 override int checkModifiable(Scope* sc, int flag) 15683 { 15684 return e1.checkModifiable(sc, flag) && e2.checkModifiable(sc, flag); 15685 } 15686 15687 override bool isLvalue() 15688 { 15689 return e1.isLvalue() && e2.isLvalue(); 15690 } 15691 15692 override Expression toLvalue(Scope* sc, Expression ex) 15693 { 15694 // convert (econd ? e1 : e2) to *(econd ? &e1 : &e2) 15695 CondExp e = cast(CondExp)copy(); 15696 e.e1 = e1.toLvalue(sc, null).addressOf(); 15697 e.e2 = e2.toLvalue(sc, null).addressOf(); 15698 e.type = type.pointerTo(); 15699 return new PtrExp(loc, e, type); 15700 } 15701 15702 override Expression modifiableLvalue(Scope* sc, Expression e) 15703 { 15704 //error("conditional expression %s is not a modifiable lvalue", toChars()); 15705 e1 = e1.modifiableLvalue(sc, e1); 15706 e2 = e2.modifiableLvalue(sc, e2); 15707 return toLvalue(sc, this); 15708 } 15709 15710 override Expression toBoolean(Scope* sc) 15711 { 15712 auto ex1 = e1.toBoolean(sc); 15713 auto ex2 = e2.toBoolean(sc); 15714 if (ex1.op == TOKerror) 15715 return ex1; 15716 if (ex2.op == TOKerror) 15717 return ex2; 15718 e1 = ex1; 15719 e2 = ex2; 15720 return this; 15721 } 15722 15723 void hookDtors(Scope* sc) 15724 { 15725 extern (C++) final class DtorVisitor : StoppableVisitor 15726 { 15727 alias visit = super.visit; 15728 public: 15729 Scope* sc; 15730 CondExp ce; 15731 VarDeclaration vcond; 15732 bool isThen; 15733 15734 extern (D) this(Scope* sc, CondExp ce) 15735 { 15736 this.sc = sc; 15737 this.ce = ce; 15738 } 15739 15740 override void visit(Expression e) 15741 { 15742 //printf("(e = %s)\n", e->toChars()); 15743 } 15744 15745 override void visit(DeclarationExp e) 15746 { 15747 auto v = e.declaration.isVarDeclaration(); 15748 if (v && !v.isDataseg()) 15749 { 15750 if (v._init) 15751 { 15752 if (auto ei = v._init.isExpInitializer()) 15753 ei.exp.accept(this); 15754 } 15755 15756 if (v.needsScopeDtor()) 15757 { 15758 if (!vcond) 15759 { 15760 vcond = copyToTemp(STCvolatile, "__cond", ce.econd); 15761 vcond.semantic(sc); 15762 15763 Expression de = new DeclarationExp(ce.econd.loc, vcond); 15764 de = de.semantic(sc); 15765 15766 Expression ve = new VarExp(ce.econd.loc, vcond); 15767 ce.econd = Expression.combine(de, ve); 15768 } 15769 15770 //printf("\t++v = %s, v->edtor = %s\n", v->toChars(), v->edtor->toChars()); 15771 Expression ve = new VarExp(vcond.loc, vcond); 15772 if (isThen) 15773 v.edtor = new AndAndExp(v.edtor.loc, ve, v.edtor); 15774 else 15775 v.edtor = new OrOrExp(v.edtor.loc, ve, v.edtor); 15776 v.edtor = v.edtor.semantic(sc); 15777 //printf("\t--v = %s, v->edtor = %s\n", v->toChars(), v->edtor->toChars()); 15778 } 15779 } 15780 } 15781 } 15782 15783 scope DtorVisitor v = new DtorVisitor(sc, this); 15784 //printf("+%s\n", toChars()); 15785 v.isThen = true; 15786 walkPostorder(e1, v); 15787 v.isThen = false; 15788 walkPostorder(e2, v); 15789 //printf("-%s\n", toChars()); 15790 } 15791 15792 override void accept(Visitor v) 15793 { 15794 v.visit(this); 15795 } 15796 } 15797 15798 /*********************************************************** 15799 */ 15800 extern (C++) class DefaultInitExp : Expression 15801 { 15802 TOK subop; // which of the derived classes this is 15803 15804 final extern (D) this(Loc loc, TOK subop, int size) 15805 { 15806 super(loc, TOKdefault, size); 15807 this.subop = subop; 15808 } 15809 15810 override void accept(Visitor v) 15811 { 15812 v.visit(this); 15813 } 15814 } 15815 15816 /*********************************************************** 15817 */ 15818 extern (C++) final class FileInitExp : DefaultInitExp 15819 { 15820 extern (D) this(Loc loc, TOK tok) 15821 { 15822 super(loc, tok, __traits(classInstanceSize, FileInitExp)); 15823 } 15824 15825 override Expression semantic(Scope* sc) 15826 { 15827 //printf("FileInitExp::semantic()\n"); 15828 type = Type.tstring; 15829 return this; 15830 } 15831 15832 override Expression resolveLoc(Loc loc, Scope* sc) 15833 { 15834 //printf("FileInitExp::resolve() %s\n", toChars()); 15835 const(char)* s = loc.filename ? loc.filename : sc._module.ident.toChars(); 15836 Expression e = new StringExp(loc, cast(char*)s); 15837 e = e.semantic(sc); 15838 e = e.castTo(sc, type); 15839 return e; 15840 } 15841 15842 override void accept(Visitor v) 15843 { 15844 v.visit(this); 15845 } 15846 } 15847 15848 /*********************************************************** 15849 */ 15850 extern (C++) final class LineInitExp : DefaultInitExp 15851 { 15852 extern (D) this(Loc loc) 15853 { 15854 super(loc, TOKline, __traits(classInstanceSize, LineInitExp)); 15855 } 15856 15857 override Expression semantic(Scope* sc) 15858 { 15859 type = Type.tint32; 15860 return this; 15861 } 15862 15863 override Expression resolveLoc(Loc loc, Scope* sc) 15864 { 15865 Expression e = new IntegerExp(loc, loc.linnum, Type.tint32); 15866 e = e.castTo(sc, type); 15867 return e; 15868 } 15869 15870 override void accept(Visitor v) 15871 { 15872 v.visit(this); 15873 } 15874 } 15875 15876 /*********************************************************** 15877 */ 15878 extern (C++) final class ModuleInitExp : DefaultInitExp 15879 { 15880 extern (D) this(Loc loc) 15881 { 15882 super(loc, TOKmodulestring, __traits(classInstanceSize, ModuleInitExp)); 15883 } 15884 15885 override Expression semantic(Scope* sc) 15886 { 15887 //printf("ModuleInitExp::semantic()\n"); 15888 type = Type.tstring; 15889 return this; 15890 } 15891 15892 override Expression resolveLoc(Loc loc, Scope* sc) 15893 { 15894 const(char)* s; 15895 if (sc.callsc) 15896 s = sc.callsc._module.toPrettyChars(); 15897 else 15898 s = sc._module.toPrettyChars(); 15899 Expression e = new StringExp(loc, cast(char*)s); 15900 e = e.semantic(sc); 15901 e = e.castTo(sc, type); 15902 return e; 15903 } 15904 15905 override void accept(Visitor v) 15906 { 15907 v.visit(this); 15908 } 15909 } 15910 15911 /*********************************************************** 15912 */ 15913 extern (C++) final class FuncInitExp : DefaultInitExp 15914 { 15915 extern (D) this(Loc loc) 15916 { 15917 super(loc, TOKfuncstring, __traits(classInstanceSize, FuncInitExp)); 15918 } 15919 15920 override Expression semantic(Scope* sc) 15921 { 15922 //printf("FuncInitExp::semantic()\n"); 15923 type = Type.tstring; 15924 if (sc.func) 15925 return this.resolveLoc(Loc(), sc); 15926 return this; 15927 } 15928 15929 override Expression resolveLoc(Loc loc, Scope* sc) 15930 { 15931 const(char)* s; 15932 if (sc.callsc && sc.callsc.func) 15933 s = sc.callsc.func.Dsymbol.toPrettyChars(); 15934 else if (sc.func) 15935 s = sc.func.Dsymbol.toPrettyChars(); 15936 else 15937 s = ""; 15938 Expression e = new StringExp(loc, cast(char*)s); 15939 e = e.semantic(sc); 15940 e = e.castTo(sc, type); 15941 return e; 15942 } 15943 15944 override void accept(Visitor v) 15945 { 15946 v.visit(this); 15947 } 15948 } 15949 15950 /*********************************************************** 15951 */ 15952 extern (C++) final class PrettyFuncInitExp : DefaultInitExp 15953 { 15954 extern (D) this(Loc loc) 15955 { 15956 super(loc, TOKprettyfunc, __traits(classInstanceSize, PrettyFuncInitExp)); 15957 } 15958 15959 override Expression semantic(Scope* sc) 15960 { 15961 //printf("PrettyFuncInitExp::semantic()\n"); 15962 type = Type.tstring; 15963 if (sc.func) 15964 return this.resolveLoc(Loc(), sc); 15965 return this; 15966 } 15967 15968 override Expression resolveLoc(Loc loc, Scope* sc) 15969 { 15970 FuncDeclaration fd; 15971 if (sc.callsc && sc.callsc.func) 15972 fd = sc.callsc.func; 15973 else 15974 fd = sc.func; 15975 15976 const(char)* s; 15977 if (fd) 15978 { 15979 const(char)* funcStr = fd.Dsymbol.toPrettyChars(); 15980 OutBuffer buf; 15981 functionToBufferWithIdent(cast(TypeFunction)fd.type, &buf, funcStr); 15982 s = buf.extractString(); 15983 } 15984 else 15985 { 15986 s = ""; 15987 } 15988 15989 Expression e = new StringExp(loc, cast(char*)s); 15990 e = e.semantic(sc); 15991 e = e.castTo(sc, type); 15992 return e; 15993 } 15994 15995 override void accept(Visitor v) 15996 { 15997 v.visit(this); 15998 } 15999 }