1 /** 2 * Semantic analysis of expressions. 3 * 4 * Specification: ($LINK2 https://dlang.org/spec/expression.html, Expressions) 5 * 6 * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved 7 * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) 8 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 9 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/expressionsem.d, _expressionsem.d) 10 * Documentation: https://dlang.org/phobos/dmd_expressionsem.html 11 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/expressionsem.d 12 */ 13 14 module dmd.expressionsem; 15 16 import core.stdc.stdio; 17 18 import dmd.access; 19 import dmd.aggregate; 20 import dmd.aliasthis; 21 import dmd.arrayop; 22 import dmd.arraytypes; 23 import dmd.attrib; 24 import dmd.astcodegen; 25 import dmd.canthrow; 26 import dmd.chkformat; 27 import dmd.ctorflow; 28 import dmd.dscope; 29 import dmd.dsymbol; 30 import dmd.declaration; 31 import dmd.dclass; 32 import dmd.dcast; 33 import dmd.delegatize; 34 import dmd.denum; 35 import dmd.dimport; 36 import dmd.dinterpret; 37 import dmd.dmangle; 38 import dmd.dmodule; 39 import dmd.dstruct; 40 import dmd.dsymbolsem; 41 import dmd.dtemplate; 42 import dmd.errors; 43 import dmd.escape; 44 import dmd.expression; 45 import dmd.func; 46 import dmd.globals; 47 import dmd.hdrgen; 48 import dmd.id; 49 import dmd.identifier; 50 import dmd.imphint; 51 import dmd.init; 52 import dmd.initsem; 53 import dmd.inline; 54 import dmd.intrange; 55 import dmd.mtype; 56 import dmd.nspace; 57 import dmd.opover; 58 import dmd.optimize; 59 import dmd.parse; 60 import dmd.printast; 61 import dmd.root.ctfloat; 62 import dmd.root.file; 63 import dmd.root.filename; 64 import dmd.root.outbuffer; 65 import dmd.root.rootobject; 66 import dmd.root.string; 67 import dmd.semantic2; 68 import dmd.semantic3; 69 import dmd.sideeffect; 70 import dmd.safe; 71 import dmd.target; 72 import dmd.tokens; 73 import dmd.traits; 74 import dmd.typesem; 75 import dmd.typinf; 76 import dmd.utf; 77 import dmd.utils; 78 import dmd.visitor; 79 80 enum LOGSEMANTIC = false; 81 82 /******************************************************** 83 * Perform semantic analysis and CTFE on expressions to produce 84 * a string. 85 * Params: 86 * buf = append generated string to buffer 87 * sc = context 88 * exps = array of Expressions 89 * Returns: 90 * true on error 91 */ 92 bool expressionsToString(ref OutBuffer buf, Scope* sc, Expressions* exps) 93 { 94 if (!exps) 95 return false; 96 97 foreach (ex; *exps) 98 { 99 if (!ex) 100 continue; 101 auto sc2 = sc.startCTFE(); 102 auto e2 = ex.expressionSemantic(sc2); 103 auto e3 = resolveProperties(sc2, e2); 104 sc2.endCTFE(); 105 106 // allowed to contain types as well as expressions 107 auto e4 = ctfeInterpretForPragmaMsg(e3); 108 if (!e4 || e4.op == TOK.error) 109 return true; 110 111 // expand tuple 112 if (auto te = e4.isTupleExp()) 113 { 114 if (expressionsToString(buf, sc, te.exps)) 115 return true; 116 continue; 117 } 118 // char literals exp `.toStringExp` return `null` but we cant override it 119 // because in most contexts we don't want the conversion to succeed. 120 IntegerExp ie = e4.isIntegerExp(); 121 const ty = (ie && ie.type) ? ie.type.ty : Terror; 122 if (ty.isSomeChar) 123 { 124 auto tsa = new TypeSArray(ie.type, IntegerExp.literal!1); 125 e4 = new ArrayLiteralExp(ex.loc, tsa, ie); 126 } 127 128 if (StringExp se = e4.toStringExp()) 129 buf.writestring(se.toUTF8(sc).peekString()); 130 else 131 buf.writestring(e4.toString()); 132 } 133 return false; 134 } 135 136 137 /*********************************************************** 138 * Resolve `exp` as a compile-time known string. 139 * Params: 140 * sc = scope 141 * exp = Expression which expected as a string 142 * s = What the string is expected for, will be used in error diagnostic. 143 * Returns: 144 * String literal, or `null` if error happens. 145 */ 146 StringExp semanticString(Scope *sc, Expression exp, const char* s) 147 { 148 sc = sc.startCTFE(); 149 exp = exp.expressionSemantic(sc); 150 exp = resolveProperties(sc, exp); 151 sc = sc.endCTFE(); 152 153 if (exp.op == TOK.error) 154 return null; 155 156 auto e = exp; 157 if (exp.type.isString()) 158 { 159 e = e.ctfeInterpret(); 160 if (e.op == TOK.error) 161 return null; 162 } 163 164 auto se = e.toStringExp(); 165 if (!se) 166 { 167 exp.error("`string` expected for %s, not `(%s)` of type `%s`", 168 s, exp.toChars(), exp.type.toChars()); 169 return null; 170 } 171 return se; 172 } 173 174 private Expression extractOpDollarSideEffect(Scope* sc, UnaExp ue) 175 { 176 Expression e0; 177 Expression e1 = Expression.extractLast(ue.e1, e0); 178 // https://issues.dlang.org/show_bug.cgi?id=12585 179 // Extract the side effect part if ue.e1 is comma. 180 181 if ((sc.flags & SCOPE.ctfe) ? hasSideEffect(e1) : !isTrivialExp(e1)) // match logic in extractSideEffect() 182 { 183 /* Even if opDollar is needed, 'e1' should be evaluate only once. So 184 * Rewrite: 185 * e1.opIndex( ... use of $ ... ) 186 * e1.opSlice( ... use of $ ... ) 187 * as: 188 * (ref __dop = e1, __dop).opIndex( ... __dop.opDollar ...) 189 * (ref __dop = e1, __dop).opSlice( ... __dop.opDollar ...) 190 */ 191 e1 = extractSideEffect(sc, "__dop", e0, e1, false); 192 assert(e1.op == TOK.variable); 193 VarExp ve = cast(VarExp)e1; 194 ve.var.storage_class |= STC.exptemp; // lifetime limited to expression 195 } 196 ue.e1 = e1; 197 return e0; 198 } 199 200 /************************************** 201 * Runs semantic on ae.arguments. Declares temporary variables 202 * if '$' was used. 203 */ 204 Expression resolveOpDollar(Scope* sc, ArrayExp ae, Expression* pe0) 205 { 206 assert(!ae.lengthVar); 207 *pe0 = null; 208 AggregateDeclaration ad = isAggregate(ae.e1.type); 209 Dsymbol slice = search_function(ad, Id.slice); 210 //printf("slice = %s %s\n", slice.kind(), slice.toChars()); 211 foreach (i, e; *ae.arguments) 212 { 213 if (i == 0) 214 *pe0 = extractOpDollarSideEffect(sc, ae); 215 216 if (e.op == TOK.interval && !(slice && slice.isTemplateDeclaration())) 217 { 218 Lfallback: 219 if (ae.arguments.dim == 1) 220 return null; 221 ae.error("multi-dimensional slicing requires template `opSlice`"); 222 return ErrorExp.get(); 223 } 224 //printf("[%d] e = %s\n", i, e.toChars()); 225 226 // Create scope for '$' variable for this dimension 227 auto sym = new ArrayScopeSymbol(sc, ae); 228 sym.parent = sc.scopesym; 229 sc = sc.push(sym); 230 ae.lengthVar = null; // Create it only if required 231 ae.currentDimension = i; // Dimension for $, if required 232 233 e = e.expressionSemantic(sc); 234 e = resolveProperties(sc, e); 235 236 if (ae.lengthVar && sc.func) 237 { 238 // If $ was used, declare it now 239 Expression de = new DeclarationExp(ae.loc, ae.lengthVar); 240 de = de.expressionSemantic(sc); 241 *pe0 = Expression.combine(*pe0, de); 242 } 243 sc = sc.pop(); 244 245 if (e.op == TOK.interval) 246 { 247 IntervalExp ie = cast(IntervalExp)e; 248 249 auto tiargs = new Objects(); 250 Expression edim = new IntegerExp(ae.loc, i, Type.tsize_t); 251 edim = edim.expressionSemantic(sc); 252 tiargs.push(edim); 253 254 auto fargs = new Expressions(2); 255 (*fargs)[0] = ie.lwr; 256 (*fargs)[1] = ie.upr; 257 258 uint xerrors = global.startGagging(); 259 sc = sc.push(); 260 FuncDeclaration fslice = resolveFuncCall(ae.loc, sc, slice, tiargs, ae.e1.type, fargs, FuncResolveFlag.quiet); 261 sc = sc.pop(); 262 global.endGagging(xerrors); 263 if (!fslice) 264 goto Lfallback; 265 266 e = new DotTemplateInstanceExp(ae.loc, ae.e1, slice.ident, tiargs); 267 e = new CallExp(ae.loc, e, fargs); 268 e = e.expressionSemantic(sc); 269 } 270 271 if (!e.type) 272 { 273 ae.error("`%s` has no value", e.toChars()); 274 e = ErrorExp.get(); 275 } 276 if (e.op == TOK.error) 277 return e; 278 279 (*ae.arguments)[i] = e; 280 } 281 return ae; 282 } 283 284 /************************************** 285 * Runs semantic on se.lwr and se.upr. Declares a temporary variable 286 * if '$' was used. 287 * Returns: 288 * ae, or ErrorExp if errors occurred 289 */ 290 Expression resolveOpDollar(Scope* sc, ArrayExp ae, IntervalExp ie, Expression* pe0) 291 { 292 //assert(!ae.lengthVar); 293 if (!ie) 294 return ae; 295 296 VarDeclaration lengthVar = ae.lengthVar; 297 bool errors = false; 298 299 // create scope for '$' 300 auto sym = new ArrayScopeSymbol(sc, ae); 301 sym.parent = sc.scopesym; 302 sc = sc.push(sym); 303 304 Expression sem(Expression e) 305 { 306 e = e.expressionSemantic(sc); 307 e = resolveProperties(sc, e); 308 if (!e.type) 309 { 310 ae.error("`%s` has no value", e.toChars()); 311 errors = true; 312 } 313 return e; 314 } 315 316 ie.lwr = sem(ie.lwr); 317 ie.upr = sem(ie.upr); 318 319 if (lengthVar != ae.lengthVar && sc.func) 320 { 321 // If $ was used, declare it now 322 Expression de = new DeclarationExp(ae.loc, ae.lengthVar); 323 de = de.expressionSemantic(sc); 324 *pe0 = Expression.combine(*pe0, de); 325 } 326 327 sc = sc.pop(); 328 329 return errors ? ErrorExp.get() : ae; 330 } 331 332 /****************************** 333 * Perform semantic() on an array of Expressions. 334 */ 335 bool arrayExpressionSemantic(Expressions* exps, Scope* sc, bool preserveErrors = false) 336 { 337 bool err = false; 338 if (exps) 339 { 340 foreach (ref e; *exps) 341 { 342 if (e) 343 { 344 auto e2 = e.expressionSemantic(sc); 345 if (e2.op == TOK.error) 346 err = true; 347 if (preserveErrors || e2.op != TOK.error) 348 e = e2; 349 } 350 } 351 } 352 return err; 353 } 354 355 /****************************** 356 * Check the tail CallExp is really property function call. 357 * Bugs: 358 * This doesn't appear to do anything. 359 */ 360 private bool checkPropertyCall(Expression e) 361 { 362 e = lastComma(e); 363 364 if (e.op == TOK.call) 365 { 366 CallExp ce = cast(CallExp)e; 367 TypeFunction tf; 368 if (ce.f) 369 { 370 tf = cast(TypeFunction)ce.f.type; 371 /* If a forward reference to ce.f, try to resolve it 372 */ 373 if (!tf.deco && ce.f.semanticRun < PASS.semanticdone) 374 { 375 ce.f.dsymbolSemantic(null); 376 tf = cast(TypeFunction)ce.f.type; 377 } 378 } 379 else if (ce.e1.type.ty == Tfunction) 380 tf = cast(TypeFunction)ce.e1.type; 381 else if (ce.e1.type.ty == Tdelegate) 382 tf = cast(TypeFunction)ce.e1.type.nextOf(); 383 else if (ce.e1.type.ty == Tpointer && ce.e1.type.nextOf().ty == Tfunction) 384 tf = cast(TypeFunction)ce.e1.type.nextOf(); 385 else 386 assert(0); 387 } 388 return false; 389 } 390 391 /****************************** 392 * Find symbol in accordance with the UFCS name look up rule 393 */ 394 private Expression searchUFCS(Scope* sc, UnaExp ue, Identifier ident) 395 { 396 //printf("searchUFCS(ident = %s)\n", ident.toChars()); 397 Loc loc = ue.loc; 398 399 // TODO: merge with Scope.search.searchScopes() 400 Dsymbol searchScopes(int flags) 401 { 402 Dsymbol s = null; 403 for (Scope* scx = sc; scx; scx = scx.enclosing) 404 { 405 if (!scx.scopesym) 406 continue; 407 if (scx.scopesym.isModule()) 408 flags |= SearchUnqualifiedModule; // tell Module.search() that SearchLocalsOnly is to be obeyed 409 s = scx.scopesym.search(loc, ident, flags); 410 if (s) 411 { 412 // overload set contains only module scope symbols. 413 if (s.isOverloadSet()) 414 break; 415 // selective/renamed imports also be picked up 416 if (AliasDeclaration ad = s.isAliasDeclaration()) 417 { 418 if (ad._import) 419 break; 420 } 421 // See only module scope symbols for UFCS target. 422 Dsymbol p = s.toParent2(); 423 if (p && p.isModule()) 424 break; 425 } 426 s = null; 427 428 // Stop when we hit a module, but keep going if that is not just under the global scope 429 if (scx.scopesym.isModule() && !(scx.enclosing && !scx.enclosing.enclosing)) 430 break; 431 } 432 return s; 433 } 434 435 int flags = 0; 436 Dsymbol s; 437 438 if (sc.flags & SCOPE.ignoresymbolvisibility) 439 flags |= IgnoreSymbolVisibility; 440 441 // First look in local scopes 442 s = searchScopes(flags | SearchLocalsOnly); 443 if (!s) 444 { 445 // Second look in imported modules 446 s = searchScopes(flags | SearchImportsOnly); 447 } 448 449 if (!s) 450 return ue.e1.type.Type.getProperty(sc, loc, ident, 0); 451 452 FuncDeclaration f = s.isFuncDeclaration(); 453 if (f) 454 { 455 TemplateDeclaration td = getFuncTemplateDecl(f); 456 if (td) 457 { 458 if (td.overroot) 459 td = td.overroot; 460 s = td; 461 } 462 } 463 464 if (ue.op == TOK.dotTemplateInstance) 465 { 466 DotTemplateInstanceExp dti = cast(DotTemplateInstanceExp)ue; 467 auto ti = new TemplateInstance(loc, s.ident, dti.ti.tiargs); 468 if (!ti.updateTempDecl(sc, s)) 469 return ErrorExp.get(); 470 return new ScopeExp(loc, ti); 471 } 472 else 473 { 474 //printf("-searchUFCS() %s\n", s.toChars()); 475 return new DsymbolExp(loc, s); 476 } 477 } 478 479 /****************************** 480 * Pull out callable entity with UFCS. 481 */ 482 private Expression resolveUFCS(Scope* sc, CallExp ce) 483 { 484 Loc loc = ce.loc; 485 Expression eleft; 486 Expression e; 487 488 if (ce.e1.op == TOK.dotIdentifier) 489 { 490 DotIdExp die = cast(DotIdExp)ce.e1; 491 Identifier ident = die.ident; 492 493 Expression ex = die.semanticX(sc); 494 if (ex != die) 495 { 496 ce.e1 = ex; 497 return null; 498 } 499 eleft = die.e1; 500 501 Type t = eleft.type.toBasetype(); 502 if (t.ty == Tarray || t.ty == Tsarray || t.ty == Tnull || (t.isTypeBasic() && t.ty != Tvoid)) 503 { 504 /* Built-in types and arrays have no callable properties, so do shortcut. 505 * It is necessary in: e.init() 506 */ 507 } 508 else if (t.ty == Taarray) 509 { 510 if (ident == Id.remove) 511 { 512 /* Transform: 513 * aa.remove(arg) into delete aa[arg] 514 */ 515 if (!ce.arguments || ce.arguments.dim != 1) 516 { 517 ce.error("expected key as argument to `aa.remove()`"); 518 return ErrorExp.get(); 519 } 520 if (!eleft.type.isMutable()) 521 { 522 ce.error("cannot remove key from `%s` associative array `%s`", MODtoChars(t.mod), eleft.toChars()); 523 return ErrorExp.get(); 524 } 525 Expression key = (*ce.arguments)[0]; 526 key = key.expressionSemantic(sc); 527 key = resolveProperties(sc, key); 528 529 TypeAArray taa = cast(TypeAArray)t; 530 key = key.implicitCastTo(sc, taa.index); 531 532 if (key.checkValue() || key.checkSharedAccess(sc)) 533 return ErrorExp.get(); 534 535 semanticTypeInfo(sc, taa.index); 536 537 return new RemoveExp(loc, eleft, key); 538 } 539 } 540 else 541 { 542 if (Expression ey = die.semanticY(sc, 1)) 543 { 544 if (ey.op == TOK.error) 545 return ey; 546 ce.e1 = ey; 547 if (isDotOpDispatch(ey)) 548 { 549 uint errors = global.startGagging(); 550 e = ce.syntaxCopy().expressionSemantic(sc); 551 if (!global.endGagging(errors)) 552 return e; 553 554 // even opDispatch and UFCS must have valid arguments, 555 // so now that we've seen indication of a problem, 556 // check them for issues. 557 Expressions* originalArguments = Expression.arraySyntaxCopy(ce.arguments); 558 559 if (arrayExpressionSemantic(originalArguments, sc)) 560 return ErrorExp.get(); 561 562 /* fall down to UFCS */ 563 } 564 else 565 return null; 566 } 567 } 568 569 /* https://issues.dlang.org/show_bug.cgi?id=13953 570 * 571 * If a struct has an alias this to an associative array 572 * and remove is used on a struct instance, we have to 573 * check first if there is a remove function that can be called 574 * on the struct. If not we must check the alias this. 575 * 576 * struct A 577 * { 578 * string[string] a; 579 * alias a this; 580 * } 581 * 582 * void fun() 583 * { 584 * A s; 585 * s.remove("foo"); 586 * } 587 */ 588 const errors = global.startGagging(); 589 e = searchUFCS(sc, die, ident); 590 // if there were any errors and the identifier was remove 591 if (global.endGagging(errors)) 592 { 593 if (ident == Id.remove) 594 { 595 // check alias this 596 Expression alias_e = resolveAliasThis(sc, die.e1, 1); 597 if (alias_e && alias_e != die.e1) 598 { 599 die.e1 = alias_e; 600 CallExp ce2 = ce.syntaxCopy(); 601 ce2.e1 = die; 602 e = cast(CallExp)ce2.trySemantic(sc); 603 if (e) 604 return e; 605 } 606 } 607 // if alias this did not work out, print the initial errors 608 searchUFCS(sc, die, ident); 609 } 610 } 611 else if (ce.e1.op == TOK.dotTemplateInstance) 612 { 613 DotTemplateInstanceExp dti = cast(DotTemplateInstanceExp)ce.e1; 614 if (Expression ey = dti.semanticY(sc, 1)) 615 { 616 ce.e1 = ey; 617 return null; 618 } 619 eleft = dti.e1; 620 e = searchUFCS(sc, dti, dti.ti.name); 621 } 622 else 623 return null; 624 625 // Rewrite 626 ce.e1 = e; 627 if (!ce.arguments) 628 ce.arguments = new Expressions(); 629 ce.arguments.shift(eleft); 630 631 return null; 632 } 633 634 /****************************** 635 * Pull out property with UFCS. 636 */ 637 private Expression resolveUFCSProperties(Scope* sc, Expression e1, Expression e2 = null) 638 { 639 Loc loc = e1.loc; 640 Expression eleft; 641 Expression e; 642 643 if (e1.op == TOK.dotIdentifier) 644 { 645 DotIdExp die = cast(DotIdExp)e1; 646 eleft = die.e1; 647 e = searchUFCS(sc, die, die.ident); 648 } 649 else if (e1.op == TOK.dotTemplateInstance) 650 { 651 DotTemplateInstanceExp dti; 652 dti = cast(DotTemplateInstanceExp)e1; 653 eleft = dti.e1; 654 e = searchUFCS(sc, dti, dti.ti.name); 655 } 656 else 657 return null; 658 659 if (e is null) 660 return null; 661 662 // Rewrite 663 if (e2) 664 { 665 // run semantic without gagging 666 e2 = e2.expressionSemantic(sc); 667 668 /* f(e1) = e2 669 */ 670 Expression ex = e.copy(); 671 auto a1 = new Expressions(1); 672 (*a1)[0] = eleft; 673 ex = new CallExp(loc, ex, a1); 674 auto e1PassSemantic = ex.trySemantic(sc); 675 676 /* f(e1, e2) 677 */ 678 auto a2 = new Expressions(2); 679 (*a2)[0] = eleft; 680 (*a2)[1] = e2; 681 e = new CallExp(loc, e, a2); 682 e = e.trySemantic(sc); 683 if (!e1PassSemantic && !e) 684 { 685 /* https://issues.dlang.org/show_bug.cgi?id=20448 686 * 687 * If both versions have failed to pass semantic, 688 * f(e1) = e2 gets priority in error printing 689 * because f might be a templated function that 690 * failed to instantiate and we have to print 691 * the instantiation errors. 692 */ 693 return e1.expressionSemantic(sc); 694 } 695 else if (ex && !e) 696 { 697 checkPropertyCall(ex); 698 ex = new AssignExp(loc, ex, e2); 699 return ex.expressionSemantic(sc); 700 } 701 else 702 { 703 // strict setter prints errors if fails 704 e = e.expressionSemantic(sc); 705 } 706 checkPropertyCall(e); 707 return e; 708 } 709 else 710 { 711 /* f(e1) 712 */ 713 auto arguments = new Expressions(1); 714 (*arguments)[0] = eleft; 715 e = new CallExp(loc, e, arguments); 716 e = e.expressionSemantic(sc); 717 checkPropertyCall(e); 718 return e.expressionSemantic(sc); 719 } 720 } 721 722 /****************************** 723 * If e1 is a property function (template), resolve it. 724 */ 725 Expression resolvePropertiesOnly(Scope* sc, Expression e1) 726 { 727 //printf("e1 = %s %s\n", Token::toChars(e1.op), e1.toChars()); 728 729 Expression handleOverloadSet(OverloadSet os) 730 { 731 assert(os); 732 foreach (s; os.a) 733 { 734 auto fd = s.isFuncDeclaration(); 735 auto td = s.isTemplateDeclaration(); 736 if (fd) 737 { 738 if ((cast(TypeFunction)fd.type).isproperty) 739 return resolveProperties(sc, e1); 740 } 741 else if (td && td.onemember && (fd = td.onemember.isFuncDeclaration()) !is null) 742 { 743 if ((cast(TypeFunction)fd.type).isproperty || 744 (fd.storage_class2 & STC.property) || 745 (td._scope.stc & STC.property)) 746 return resolveProperties(sc, e1); 747 } 748 } 749 return e1; 750 } 751 752 Expression handleTemplateDecl(TemplateDeclaration td) 753 { 754 assert(td); 755 if (td.onemember) 756 { 757 if (auto fd = td.onemember.isFuncDeclaration()) 758 { 759 if ((cast(TypeFunction)fd.type).isproperty || 760 (fd.storage_class2 & STC.property) || 761 (td._scope.stc & STC.property)) 762 return resolveProperties(sc, e1); 763 } 764 } 765 return e1; 766 } 767 768 Expression handleFuncDecl(FuncDeclaration fd) 769 { 770 assert(fd); 771 if ((cast(TypeFunction)fd.type).isproperty) 772 return resolveProperties(sc, e1); 773 return e1; 774 } 775 776 if (auto de = e1.isDotExp()) 777 { 778 if (auto os = de.e2.isOverExp()) 779 return handleOverloadSet(os.vars); 780 } 781 else if (auto oe = e1.isOverExp()) 782 return handleOverloadSet(oe.vars); 783 else if (auto dti = e1.isDotTemplateInstanceExp()) 784 { 785 if (dti.ti.tempdecl) 786 if (auto td = dti.ti.tempdecl.isTemplateDeclaration()) 787 return handleTemplateDecl(td); 788 } 789 else if (auto dte = e1.isDotTemplateExp()) 790 return handleTemplateDecl(dte.td); 791 else if (e1.op == TOK.scope_) 792 { 793 Dsymbol s = (cast(ScopeExp)e1).sds; 794 TemplateInstance ti = s.isTemplateInstance(); 795 if (ti && !ti.semanticRun && ti.tempdecl) 796 if (auto td = ti.tempdecl.isTemplateDeclaration()) 797 return handleTemplateDecl(td); 798 } 799 else if (e1.op == TOK.template_) 800 return handleTemplateDecl((cast(TemplateExp)e1).td); 801 else if (e1.op == TOK.dotVariable && e1.type.ty == Tfunction) 802 { 803 DotVarExp dve = cast(DotVarExp)e1; 804 return handleFuncDecl(dve.var.isFuncDeclaration()); 805 } 806 else if (e1.op == TOK.variable && e1.type && e1.type.ty == Tfunction && (sc.intypeof || !(cast(VarExp)e1).var.needThis())) 807 return handleFuncDecl((cast(VarExp)e1).var.isFuncDeclaration()); 808 return e1; 809 } 810 811 /**************************************** 812 * Turn symbol `s` into the expression it represents. 813 * 814 * Params: 815 * s = symbol to resolve 816 * loc = location of use of `s` 817 * sc = context 818 * hasOverloads = applies if `s` represents a function. 819 * true means it's overloaded and will be resolved later, 820 * false means it's the exact function symbol. 821 * Returns: 822 * `s` turned into an expression, `ErrorExp` if an error occurred 823 */ 824 Expression symbolToExp(Dsymbol s, const ref Loc loc, Scope *sc, bool hasOverloads) 825 { 826 static if (LOGSEMANTIC) 827 { 828 printf("DsymbolExp::resolve(%s %s)\n", s.kind(), s.toChars()); 829 } 830 831 Lagain: 832 Expression e; 833 834 //printf("DsymbolExp:: %p '%s' is a symbol\n", this, toChars()); 835 //printf("s = '%s', s.kind = '%s'\n", s.toChars(), s.kind()); 836 Dsymbol olds = s; 837 Declaration d = s.isDeclaration(); 838 if (d && (d.storage_class & STC.templateparameter)) 839 { 840 s = s.toAlias(); 841 } 842 else 843 { 844 if (!s.isFuncDeclaration()) // functions are checked after overloading 845 { 846 s.checkDeprecated(loc, sc); 847 if (d) 848 d.checkDisabled(loc, sc); 849 } 850 851 // https://issues.dlang.org/show_bug.cgi?id=12023 852 // if 's' is a tuple variable, the tuple is returned. 853 s = s.toAlias(); 854 855 //printf("s = '%s', s.kind = '%s', s.needThis() = %p\n", s.toChars(), s.kind(), s.needThis()); 856 if (s != olds && !s.isFuncDeclaration()) 857 { 858 s.checkDeprecated(loc, sc); 859 if (d) 860 d.checkDisabled(loc, sc); 861 } 862 } 863 864 if (auto em = s.isEnumMember()) 865 { 866 return em.getVarExp(loc, sc); 867 } 868 if (auto v = s.isVarDeclaration()) 869 { 870 //printf("Identifier '%s' is a variable, type '%s'\n", s.toChars(), v.type.toChars()); 871 if (sc.intypeof == 1 && !v.inuse) 872 v.dsymbolSemantic(sc); 873 if (!v.type || // during variable type inference 874 !v.type.deco && v.inuse) // during variable type semantic 875 { 876 if (v.inuse) // variable type depends on the variable itself 877 error(loc, "circular reference to %s `%s`", v.kind(), v.toPrettyChars()); 878 else // variable type cannot be determined 879 error(loc, "forward reference to %s `%s`", v.kind(), v.toPrettyChars()); 880 return ErrorExp.get(); 881 } 882 if (v.type.ty == Terror) 883 return ErrorExp.get(); 884 885 if ((v.storage_class & STC.manifest) && v._init) 886 { 887 if (v.inuse) 888 { 889 error(loc, "circular initialization of %s `%s`", v.kind(), v.toPrettyChars()); 890 return ErrorExp.get(); 891 } 892 e = v.expandInitializer(loc); 893 v.inuse++; 894 e = e.expressionSemantic(sc); 895 v.inuse--; 896 return e; 897 } 898 899 // Change the ancestor lambdas to delegate before hasThis(sc) call. 900 if (v.checkNestedReference(sc, loc)) 901 return ErrorExp.get(); 902 903 if (v.needThis() && hasThis(sc)) 904 e = new DotVarExp(loc, new ThisExp(loc), v); 905 else 906 e = new VarExp(loc, v); 907 e = e.expressionSemantic(sc); 908 return e; 909 } 910 if (auto fld = s.isFuncLiteralDeclaration()) 911 { 912 //printf("'%s' is a function literal\n", fld.toChars()); 913 e = new FuncExp(loc, fld); 914 return e.expressionSemantic(sc); 915 } 916 if (auto f = s.isFuncDeclaration()) 917 { 918 f = f.toAliasFunc(); 919 if (!f.functionSemantic()) 920 return ErrorExp.get(); 921 922 if (!hasOverloads && f.checkForwardRef(loc)) 923 return ErrorExp.get(); 924 925 auto fd = s.isFuncDeclaration(); 926 fd.type = f.type; 927 return new VarExp(loc, fd, hasOverloads); 928 } 929 if (OverDeclaration od = s.isOverDeclaration()) 930 { 931 e = new VarExp(loc, od, true); 932 e.type = Type.tvoid; 933 return e; 934 } 935 if (OverloadSet o = s.isOverloadSet()) 936 { 937 //printf("'%s' is an overload set\n", o.toChars()); 938 return new OverExp(loc, o); 939 } 940 941 if (Import imp = s.isImport()) 942 { 943 if (!imp.pkg) 944 { 945 .error(loc, "forward reference of import `%s`", imp.toChars()); 946 return ErrorExp.get(); 947 } 948 auto ie = new ScopeExp(loc, imp.pkg); 949 return ie.expressionSemantic(sc); 950 } 951 if (Package pkg = s.isPackage()) 952 { 953 auto ie = new ScopeExp(loc, pkg); 954 return ie.expressionSemantic(sc); 955 } 956 if (Module mod = s.isModule()) 957 { 958 auto ie = new ScopeExp(loc, mod); 959 return ie.expressionSemantic(sc); 960 } 961 if (Nspace ns = s.isNspace()) 962 { 963 auto ie = new ScopeExp(loc, ns); 964 return ie.expressionSemantic(sc); 965 } 966 967 if (Type t = s.getType()) 968 { 969 return (new TypeExp(loc, t)).expressionSemantic(sc); 970 } 971 972 if (TupleDeclaration tup = s.isTupleDeclaration()) 973 { 974 if (tup.needThis() && hasThis(sc)) 975 e = new DotVarExp(loc, new ThisExp(loc), tup); 976 else 977 e = new TupleExp(loc, tup); 978 e = e.expressionSemantic(sc); 979 return e; 980 } 981 982 if (TemplateInstance ti = s.isTemplateInstance()) 983 { 984 ti.dsymbolSemantic(sc); 985 if (!ti.inst || ti.errors) 986 return ErrorExp.get(); 987 s = ti.toAlias(); 988 if (!s.isTemplateInstance()) 989 goto Lagain; 990 e = new ScopeExp(loc, ti); 991 e = e.expressionSemantic(sc); 992 return e; 993 } 994 if (TemplateDeclaration td = s.isTemplateDeclaration()) 995 { 996 Dsymbol p = td.toParentLocal(); 997 FuncDeclaration fdthis = hasThis(sc); 998 AggregateDeclaration ad = p ? p.isAggregateDeclaration() : null; 999 if (fdthis && ad && fdthis.isMemberLocal() == ad && (td._scope.stc & STC.static_) == 0) 1000 { 1001 e = new DotTemplateExp(loc, new ThisExp(loc), td); 1002 } 1003 else 1004 e = new TemplateExp(loc, td); 1005 e = e.expressionSemantic(sc); 1006 return e; 1007 } 1008 1009 .error(loc, "%s `%s` is not a variable", s.kind(), s.toChars()); 1010 return ErrorExp.get(); 1011 } 1012 1013 /************************************************************* 1014 * Given var, get the 1015 * right `this` pointer if var is in an outer class, but our 1016 * existing `this` pointer is in an inner class. 1017 * Params: 1018 * loc = location to use for error messages 1019 * sc = context 1020 * ad = struct or class we need the correct `this` for 1021 * e1 = existing `this` 1022 * var = the specific member of ad we're accessing 1023 * flag = if true, return `null` instead of throwing an error 1024 * Returns: 1025 * Expression representing the `this` for the var 1026 */ 1027 private Expression getRightThis(const ref Loc loc, Scope* sc, AggregateDeclaration ad, Expression e1, Dsymbol var, int flag = 0) 1028 { 1029 //printf("\ngetRightThis(e1 = %s, ad = %s, var = %s)\n", e1.toChars(), ad.toChars(), var.toChars()); 1030 L1: 1031 Type t = e1.type.toBasetype(); 1032 //printf("e1.type = %s, var.type = %s\n", e1.type.toChars(), var.type.toChars()); 1033 1034 if (e1.op == TOK.objcClassReference) 1035 { 1036 // We already have an Objective-C class reference, just use that as 'this'. 1037 return e1; 1038 } 1039 else if (ad && ad.isClassDeclaration && ad.isClassDeclaration.classKind == ClassKind.objc && 1040 var.isFuncDeclaration && var.isFuncDeclaration.isStatic && 1041 var.isFuncDeclaration.objc.selector) 1042 { 1043 return new ObjcClassReferenceExp(e1.loc, cast(ClassDeclaration) ad); 1044 } 1045 1046 /* Access of a member which is a template parameter in dual-scope scenario 1047 * class A { inc(alias m)() { ++m; } } // `m` needs `this` of `B` 1048 * class B {int m; inc() { new A().inc!m(); } } 1049 */ 1050 if (e1.op == TOK.this_) 1051 { 1052 FuncDeclaration f = hasThis(sc); 1053 if (f && f.isThis2) 1054 { 1055 if (f.followInstantiationContext(ad)) 1056 { 1057 e1 = new VarExp(loc, f.vthis); 1058 e1 = new PtrExp(loc, e1); 1059 e1 = new IndexExp(loc, e1, IntegerExp.literal!1); 1060 e1 = getThisSkipNestedFuncs(loc, sc, f.toParent2(), ad, e1, t, var); 1061 if (e1.op == TOK.error) 1062 return e1; 1063 goto L1; 1064 } 1065 } 1066 } 1067 1068 /* If e1 is not the 'this' pointer for ad 1069 */ 1070 if (ad && 1071 !(t.ty == Tpointer && t.nextOf().ty == Tstruct && (cast(TypeStruct)t.nextOf()).sym == ad) && 1072 !(t.ty == Tstruct && (cast(TypeStruct)t).sym == ad)) 1073 { 1074 ClassDeclaration cd = ad.isClassDeclaration(); 1075 ClassDeclaration tcd = t.isClassHandle(); 1076 1077 /* e1 is the right this if ad is a base class of e1 1078 */ 1079 if (!cd || !tcd || !(tcd == cd || cd.isBaseOf(tcd, null))) 1080 { 1081 /* Only classes can be inner classes with an 'outer' 1082 * member pointing to the enclosing class instance 1083 */ 1084 if (tcd && tcd.isNested()) 1085 { 1086 /* e1 is the 'this' pointer for an inner class: tcd. 1087 * Rewrite it as the 'this' pointer for the outer class. 1088 */ 1089 auto vthis = tcd.followInstantiationContext(ad) ? tcd.vthis2 : tcd.vthis; 1090 e1 = new DotVarExp(loc, e1, vthis); 1091 e1.type = vthis.type; 1092 e1.type = e1.type.addMod(t.mod); 1093 // Do not call ensureStaticLinkTo() 1094 //e1 = e1.semantic(sc); 1095 1096 // Skip up over nested functions, and get the enclosing 1097 // class type. 1098 e1 = getThisSkipNestedFuncs(loc, sc, tcd.toParentP(ad), ad, e1, t, var); 1099 if (e1.op == TOK.error) 1100 return e1; 1101 goto L1; 1102 } 1103 1104 /* Can't find a path from e1 to ad 1105 */ 1106 if (flag) 1107 return null; 1108 e1.error("`this` for `%s` needs to be type `%s` not type `%s`", var.toChars(), ad.toChars(), t.toChars()); 1109 return ErrorExp.get(); 1110 } 1111 } 1112 return e1; 1113 } 1114 1115 /*************************************** 1116 * Pull out any properties. 1117 */ 1118 private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 = null) 1119 { 1120 //printf("resolvePropertiesX, e1 = %s %s, e2 = %s\n", Token.toChars(e1.op), e1.toChars(), e2 ? e2.toChars() : null); 1121 Loc loc = e1.loc; 1122 1123 OverloadSet os; 1124 Dsymbol s; 1125 Objects* tiargs; 1126 Type tthis; 1127 if (e1.op == TOK.dot) 1128 { 1129 DotExp de = cast(DotExp)e1; 1130 if (de.e2.op == TOK.overloadSet) 1131 { 1132 tiargs = null; 1133 tthis = de.e1.type; 1134 os = (cast(OverExp)de.e2).vars; 1135 goto Los; 1136 } 1137 } 1138 else if (e1.op == TOK.overloadSet) 1139 { 1140 tiargs = null; 1141 tthis = null; 1142 os = (cast(OverExp)e1).vars; 1143 Los: 1144 assert(os); 1145 FuncDeclaration fd = null; 1146 if (e2) 1147 { 1148 e2 = e2.expressionSemantic(sc); 1149 if (e2.op == TOK.error) 1150 return ErrorExp.get(); 1151 e2 = resolveProperties(sc, e2); 1152 1153 Expressions a; 1154 a.push(e2); 1155 1156 for (size_t i = 0; i < os.a.dim; i++) 1157 { 1158 if (FuncDeclaration f = resolveFuncCall(loc, sc, os.a[i], tiargs, tthis, &a, FuncResolveFlag.quiet)) 1159 { 1160 if (f.errors) 1161 return ErrorExp.get(); 1162 fd = f; 1163 assert(fd.type.ty == Tfunction); 1164 } 1165 } 1166 if (fd) 1167 { 1168 Expression e = new CallExp(loc, e1, e2); 1169 return e.expressionSemantic(sc); 1170 } 1171 } 1172 { 1173 for (size_t i = 0; i < os.a.dim; i++) 1174 { 1175 if (FuncDeclaration f = resolveFuncCall(loc, sc, os.a[i], tiargs, tthis, null, FuncResolveFlag.quiet)) 1176 { 1177 if (f.errors) 1178 return ErrorExp.get(); 1179 fd = f; 1180 assert(fd.type.ty == Tfunction); 1181 TypeFunction tf = cast(TypeFunction)fd.type; 1182 if (!tf.isref && e2) 1183 { 1184 error(loc, "%s is not an lvalue", e1.toChars()); 1185 return ErrorExp.get(); 1186 } 1187 } 1188 } 1189 if (fd) 1190 { 1191 Expression e = new CallExp(loc, e1); 1192 if (e2) 1193 e = new AssignExp(loc, e, e2); 1194 return e.expressionSemantic(sc); 1195 } 1196 } 1197 if (e2) 1198 goto Leprop; 1199 } 1200 else if (e1.op == TOK.dotTemplateInstance) 1201 { 1202 DotTemplateInstanceExp dti = cast(DotTemplateInstanceExp)e1; 1203 if (!dti.findTempDecl(sc)) 1204 goto Leprop; 1205 if (!dti.ti.semanticTiargs(sc)) 1206 goto Leprop; 1207 tiargs = dti.ti.tiargs; 1208 tthis = dti.e1.type; 1209 if ((os = dti.ti.tempdecl.isOverloadSet()) !is null) 1210 goto Los; 1211 if ((s = dti.ti.tempdecl) !is null) 1212 goto Lfd; 1213 } 1214 else if (e1.op == TOK.dotTemplateDeclaration) 1215 { 1216 DotTemplateExp dte = cast(DotTemplateExp)e1; 1217 s = dte.td; 1218 tiargs = null; 1219 tthis = dte.e1.type; 1220 goto Lfd; 1221 } 1222 else if (e1.op == TOK.scope_) 1223 { 1224 s = (cast(ScopeExp)e1).sds; 1225 TemplateInstance ti = s.isTemplateInstance(); 1226 if (ti && !ti.semanticRun && ti.tempdecl) 1227 { 1228 //assert(ti.needsTypeInference(sc)); 1229 if (!ti.semanticTiargs(sc)) 1230 goto Leprop; 1231 tiargs = ti.tiargs; 1232 tthis = null; 1233 if ((os = ti.tempdecl.isOverloadSet()) !is null) 1234 goto Los; 1235 if ((s = ti.tempdecl) !is null) 1236 goto Lfd; 1237 } 1238 } 1239 else if (e1.op == TOK.template_) 1240 { 1241 s = (cast(TemplateExp)e1).td; 1242 tiargs = null; 1243 tthis = null; 1244 goto Lfd; 1245 } 1246 else if (e1.op == TOK.dotVariable && e1.type && (e1.type.toBasetype().ty == Tfunction || (cast(DotVarExp)e1).var.isOverDeclaration())) 1247 { 1248 DotVarExp dve = cast(DotVarExp)e1; 1249 s = dve.var; 1250 tiargs = null; 1251 tthis = dve.e1.type; 1252 goto Lfd; 1253 } 1254 else if (e1.op == TOK.variable && e1.type && (e1.type.toBasetype().ty == Tfunction || (cast(VarExp)e1).var.isOverDeclaration())) 1255 { 1256 s = (cast(VarExp)e1).var; 1257 tiargs = null; 1258 tthis = null; 1259 Lfd: 1260 assert(s); 1261 if (e2) 1262 { 1263 e2 = e2.expressionSemantic(sc); 1264 if (e2.op == TOK.error) 1265 return ErrorExp.get(); 1266 e2 = resolveProperties(sc, e2); 1267 1268 Expressions a; 1269 a.push(e2); 1270 1271 FuncDeclaration fd = resolveFuncCall(loc, sc, s, tiargs, tthis, &a, FuncResolveFlag.quiet); 1272 if (fd && fd.type) 1273 { 1274 if (fd.errors) 1275 return ErrorExp.get(); 1276 if (!checkSymbolAccess(sc, fd)) 1277 { 1278 // @@@DEPRECATED_2020-10@@@ 1279 // When turning into error, uncomment the return statement 1280 TypeFunction tf = cast(TypeFunction)fd.type; 1281 deprecation(loc, "Function `%s` of type `%s` is not accessible from module `%s`", 1282 fd.toPrettyChars(), tf.toChars, sc._module.toChars); 1283 //return ErrorExp.get(); 1284 } 1285 assert(fd.type.ty == Tfunction); 1286 Expression e = new CallExp(loc, e1, e2); 1287 return e.expressionSemantic(sc); 1288 } 1289 } 1290 { 1291 FuncDeclaration fd = resolveFuncCall(loc, sc, s, tiargs, tthis, null, FuncResolveFlag.quiet); 1292 if (fd && fd.type) 1293 { 1294 if (fd.errors) 1295 return ErrorExp.get(); 1296 assert(fd.type.ty == Tfunction); 1297 TypeFunction tf = cast(TypeFunction)fd.type; 1298 if (!e2 || tf.isref) 1299 { 1300 if (!checkSymbolAccess(sc, fd)) 1301 { 1302 // @@@DEPRECATED_2020-10@@@ 1303 // When turning into error, uncomment the return statement 1304 deprecation(loc, "Function `%s` of type `%s` is not accessible from module `%s`", 1305 fd.toPrettyChars(), tf.toChars, sc._module.toChars); 1306 //return ErrorExp.get(); 1307 } 1308 Expression e = new CallExp(loc, e1); 1309 if (e2) 1310 e = new AssignExp(loc, e, e2); 1311 return e.expressionSemantic(sc); 1312 } 1313 } 1314 } 1315 if (FuncDeclaration fd = s.isFuncDeclaration()) 1316 { 1317 // Keep better diagnostic message for invalid property usage of functions 1318 assert(fd.type.ty == Tfunction); 1319 Expression e = new CallExp(loc, e1, e2); 1320 return e.expressionSemantic(sc); 1321 } 1322 if (e2) 1323 goto Leprop; 1324 } 1325 if (e1.op == TOK.variable) 1326 { 1327 VarExp ve = cast(VarExp)e1; 1328 VarDeclaration v = ve.var.isVarDeclaration(); 1329 if (v && ve.checkPurity(sc, v)) 1330 return ErrorExp.get(); 1331 } 1332 if (e2) 1333 return null; 1334 1335 if (e1.type && e1.op != TOK.type) // function type is not a property 1336 { 1337 /* Look for e1 being a lazy parameter; rewrite as delegate call 1338 * only if the symbol wasn't already treated as a delegate 1339 */ 1340 auto ve = e1.isVarExp(); 1341 if (ve && ve.var.storage_class & STC.lazy_ && !ve.delegateWasExtracted) 1342 { 1343 Expression e = new CallExp(loc, e1); 1344 return e.expressionSemantic(sc); 1345 } 1346 else if (e1.op == TOK.dotVariable) 1347 { 1348 // Check for reading overlapped pointer field in @safe code. 1349 if (checkUnsafeAccess(sc, e1, true, true)) 1350 return ErrorExp.get(); 1351 } 1352 else if (e1.op == TOK.dot) 1353 { 1354 e1.error("expression has no value"); 1355 return ErrorExp.get(); 1356 } 1357 else if (e1.op == TOK.call) 1358 { 1359 CallExp ce = cast(CallExp)e1; 1360 // Check for reading overlapped pointer field in @safe code. 1361 if (checkUnsafeAccess(sc, ce.e1, true, true)) 1362 return ErrorExp.get(); 1363 } 1364 } 1365 1366 if (!e1.type) 1367 { 1368 error(loc, "cannot resolve type for %s", e1.toChars()); 1369 e1 = ErrorExp.get(); 1370 } 1371 return e1; 1372 1373 Leprop: 1374 error(loc, "not a property %s", e1.toChars()); 1375 return ErrorExp.get(); 1376 } 1377 1378 extern (C++) Expression resolveProperties(Scope* sc, Expression e) 1379 { 1380 //printf("resolveProperties(%s)\n", e.toChars()); 1381 e = resolvePropertiesX(sc, e); 1382 if (e.checkRightThis(sc)) 1383 return ErrorExp.get(); 1384 return e; 1385 } 1386 1387 /**************************************** 1388 * The common type is determined by applying ?: to each pair. 1389 * Output: 1390 * exps[] properties resolved, implicitly cast to common type, rewritten in place 1391 * Returns: 1392 * The common type, or `null` if an error has occured 1393 */ 1394 private Type arrayExpressionToCommonType(Scope* sc, ref Expressions exps) 1395 { 1396 /* Still have a problem with: 1397 * ubyte[][] = [ cast(ubyte[])"hello", [1]]; 1398 * which works if the array literal is initialized top down with the ubyte[][] 1399 * type, but fails with this function doing bottom up typing. 1400 */ 1401 1402 //printf("arrayExpressionToCommonType()\n"); 1403 scope IntegerExp integerexp = IntegerExp.literal!0; 1404 scope CondExp condexp = new CondExp(Loc.initial, integerexp, null, null); 1405 1406 Type t0 = null; 1407 Expression e0 = null; 1408 size_t j0 = ~0; 1409 bool foundType; 1410 1411 for (size_t i = 0; i < exps.dim; i++) 1412 { 1413 Expression e = exps[i]; 1414 if (!e) 1415 continue; 1416 1417 e = resolveProperties(sc, e); 1418 if (!e.type) 1419 { 1420 e.error("`%s` has no value", e.toChars()); 1421 t0 = Type.terror; 1422 continue; 1423 } 1424 if (e.op == TOK.type) 1425 { 1426 foundType = true; // do not break immediately, there might be more errors 1427 e.checkValue(); // report an error "type T has no value" 1428 t0 = Type.terror; 1429 continue; 1430 } 1431 if (e.type.ty == Tvoid) 1432 { 1433 // void expressions do not concur to the determination of the common 1434 // type. 1435 continue; 1436 } 1437 if (checkNonAssignmentArrayOp(e)) 1438 { 1439 t0 = Type.terror; 1440 continue; 1441 } 1442 1443 e = doCopyOrMove(sc, e); 1444 1445 if (!foundType && t0 && !t0.equals(e.type)) 1446 { 1447 /* This applies ?: to merge the types. It's backwards; 1448 * ?: should call this function to merge types. 1449 */ 1450 condexp.type = null; 1451 condexp.e1 = e0; 1452 condexp.e2 = e; 1453 condexp.loc = e.loc; 1454 Expression ex = condexp.expressionSemantic(sc); 1455 if (ex.op == TOK.error) 1456 e = ex; 1457 else if (e.op == TOK.function_ || e.op == TOK.delegate_) 1458 { 1459 // https://issues.dlang.org/show_bug.cgi?id=21285 1460 // Functions and delegates don't convert correctly with castTo below 1461 exps[j0] = condexp.e1; 1462 e = condexp.e2; 1463 } 1464 else 1465 { 1466 // Convert to common type 1467 exps[j0] = condexp.e1.castTo(sc, condexp.type); 1468 e = condexp.e2.castTo(sc, condexp.type); 1469 } 1470 } 1471 j0 = i; 1472 e0 = e; 1473 t0 = e.type; 1474 if (e.op != TOK.error) 1475 exps[i] = e; 1476 } 1477 1478 // [] is typed as void[] 1479 if (!t0) 1480 return Type.tvoid; 1481 1482 // It's an error, don't do the cast 1483 if (t0.ty == Terror) 1484 return null; 1485 1486 for (size_t i = 0; i < exps.dim; i++) 1487 { 1488 Expression e = exps[i]; 1489 if (!e) 1490 continue; 1491 1492 e = e.implicitCastTo(sc, t0); 1493 if (e.op == TOK.error) 1494 { 1495 /* https://issues.dlang.org/show_bug.cgi?id=13024 1496 * a workaround for the bug in typeMerge - 1497 * it should paint e1 and e2 by deduced common type, 1498 * but doesn't in this particular case. 1499 */ 1500 return null; 1501 } 1502 exps[i] = e; 1503 } 1504 return t0; 1505 } 1506 1507 private Expression opAssignToOp(const ref Loc loc, TOK op, Expression e1, Expression e2) 1508 { 1509 Expression e; 1510 switch (op) 1511 { 1512 case TOK.addAssign: 1513 e = new AddExp(loc, e1, e2); 1514 break; 1515 1516 case TOK.minAssign: 1517 e = new MinExp(loc, e1, e2); 1518 break; 1519 1520 case TOK.mulAssign: 1521 e = new MulExp(loc, e1, e2); 1522 break; 1523 1524 case TOK.divAssign: 1525 e = new DivExp(loc, e1, e2); 1526 break; 1527 1528 case TOK.modAssign: 1529 e = new ModExp(loc, e1, e2); 1530 break; 1531 1532 case TOK.andAssign: 1533 e = new AndExp(loc, e1, e2); 1534 break; 1535 1536 case TOK.orAssign: 1537 e = new OrExp(loc, e1, e2); 1538 break; 1539 1540 case TOK.xorAssign: 1541 e = new XorExp(loc, e1, e2); 1542 break; 1543 1544 case TOK.leftShiftAssign: 1545 e = new ShlExp(loc, e1, e2); 1546 break; 1547 1548 case TOK.rightShiftAssign: 1549 e = new ShrExp(loc, e1, e2); 1550 break; 1551 1552 case TOK.unsignedRightShiftAssign: 1553 e = new UshrExp(loc, e1, e2); 1554 break; 1555 1556 default: 1557 assert(0); 1558 } 1559 return e; 1560 } 1561 1562 /********************* 1563 * Rewrite: 1564 * array.length op= e2 1565 * as: 1566 * array.length = array.length op e2 1567 * or: 1568 * auto tmp = &array; 1569 * (*tmp).length = (*tmp).length op e2 1570 */ 1571 private Expression rewriteOpAssign(BinExp exp) 1572 { 1573 Expression e; 1574 1575 assert(exp.e1.op == TOK.arrayLength); 1576 ArrayLengthExp ale = cast(ArrayLengthExp)exp.e1; 1577 if (ale.e1.op == TOK.variable) 1578 { 1579 e = opAssignToOp(exp.loc, exp.op, ale, exp.e2); 1580 e = new AssignExp(exp.loc, ale.syntaxCopy(), e); 1581 } 1582 else 1583 { 1584 /* auto tmp = &array; 1585 * (*tmp).length = (*tmp).length op e2 1586 */ 1587 auto tmp = copyToTemp(0, "__arraylength", new AddrExp(ale.loc, ale.e1)); 1588 1589 Expression e1 = new ArrayLengthExp(ale.loc, new PtrExp(ale.loc, new VarExp(ale.loc, tmp))); 1590 Expression elvalue = e1.syntaxCopy(); 1591 e = opAssignToOp(exp.loc, exp.op, e1, exp.e2); 1592 e = new AssignExp(exp.loc, elvalue, e); 1593 e = new CommaExp(exp.loc, new DeclarationExp(ale.loc, tmp), e); 1594 } 1595 return e; 1596 } 1597 1598 /**************************************** 1599 * Preprocess arguments to function. 1600 * Input: 1601 * reportErrors whether or not to report errors here. Some callers are not 1602 * checking actual function params, so they'll do their own error reporting 1603 * Output: 1604 * exps[] tuples expanded, properties resolved, rewritten in place 1605 * Returns: 1606 * true a semantic error occurred 1607 */ 1608 private bool preFunctionParameters(Scope* sc, Expressions* exps, const bool reportErrors = true) 1609 { 1610 bool err = false; 1611 if (exps) 1612 { 1613 expandTuples(exps); 1614 1615 for (size_t i = 0; i < exps.dim; i++) 1616 { 1617 Expression arg = (*exps)[i]; 1618 arg = resolveProperties(sc, arg); 1619 if (arg.op == TOK.type) 1620 { 1621 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684 1622 arg = resolveAliasThis(sc, arg); 1623 1624 if (arg.op == TOK.type) 1625 { 1626 if (reportErrors) 1627 { 1628 arg.error("cannot pass type `%s` as a function argument", arg.toChars()); 1629 arg = ErrorExp.get(); 1630 } 1631 err = true; 1632 } 1633 } 1634 else if (arg.type.toBasetype().ty == Tfunction) 1635 { 1636 if (reportErrors) 1637 { 1638 arg.error("cannot pass function `%s` as a function argument", arg.toChars()); 1639 arg = ErrorExp.get(); 1640 } 1641 err = true; 1642 } 1643 else if (checkNonAssignmentArrayOp(arg)) 1644 { 1645 arg = ErrorExp.get(); 1646 err = true; 1647 } 1648 (*exps)[i] = arg; 1649 } 1650 } 1651 return err; 1652 } 1653 1654 /******************************************** 1655 * Issue an error if default construction is disabled for type t. 1656 * Default construction is required for arrays and 'out' parameters. 1657 * Returns: 1658 * true an error was issued 1659 */ 1660 private bool checkDefCtor(Loc loc, Type t) 1661 { 1662 t = t.baseElemOf(); 1663 if (t.ty == Tstruct) 1664 { 1665 StructDeclaration sd = (cast(TypeStruct)t).sym; 1666 if (sd.noDefaultCtor) 1667 { 1668 sd.error(loc, "default construction is disabled"); 1669 return true; 1670 } 1671 } 1672 return false; 1673 } 1674 1675 /**************************************** 1676 * Now that we know the exact type of the function we're calling, 1677 * the arguments[] need to be adjusted: 1678 * 1. implicitly convert argument to the corresponding parameter type 1679 * 2. add default arguments for any missing arguments 1680 * 3. do default promotions on arguments corresponding to ... 1681 * 4. add hidden _arguments[] argument 1682 * 5. call copy constructor for struct value arguments 1683 * Params: 1684 * loc = location of function call 1685 * sc = context 1686 * tf = type of the function 1687 * ethis = `this` argument, `null` if none or not known 1688 * tthis = type of `this` argument, `null` if no `this` argument 1689 * arguments = array of actual arguments to function call 1690 * fd = the function being called, `null` if called indirectly 1691 * prettype = set to return type of function 1692 * peprefix = set to expression to execute before `arguments[]` are evaluated, `null` if none 1693 * Returns: 1694 * true errors happened 1695 */ 1696 private bool functionParameters(const ref Loc loc, Scope* sc, 1697 TypeFunction tf, Expression ethis, Type tthis, Expressions* arguments, FuncDeclaration fd, 1698 Type* prettype, Expression* peprefix) 1699 { 1700 //printf("functionParameters() %s\n", fd ? fd.toChars() : ""); 1701 assert(arguments); 1702 assert(fd || tf.next); 1703 size_t nargs = arguments ? arguments.dim : 0; 1704 const size_t nparams = tf.parameterList.length; 1705 const olderrors = global.errors; 1706 bool err = false; 1707 *prettype = Type.terror; 1708 Expression eprefix = null; 1709 *peprefix = null; 1710 1711 if (nargs > nparams && tf.parameterList.varargs == VarArg.none) 1712 { 1713 error(loc, "expected %llu arguments, not %llu for non-variadic function type `%s`", cast(ulong)nparams, cast(ulong)nargs, tf.toChars()); 1714 return true; 1715 } 1716 1717 // If inferring return type, and semantic3() needs to be run if not already run 1718 if (!tf.next && fd.inferRetType) 1719 { 1720 fd.functionSemantic(); 1721 } 1722 else if (fd && fd.parent) 1723 { 1724 TemplateInstance ti = fd.parent.isTemplateInstance(); 1725 if (ti && ti.tempdecl) 1726 { 1727 fd.functionSemantic3(); 1728 } 1729 } 1730 1731 /* If calling a pragma(inline, true) function, 1732 * set flag to later scan for inlines. 1733 */ 1734 if (fd && fd.inlining == PINLINE.always) 1735 { 1736 if (sc._module) 1737 sc._module.hasAlwaysInlines = true; 1738 if (sc.func) 1739 sc.func.hasAlwaysInlines = true; 1740 } 1741 1742 const isCtorCall = fd && fd.needThis() && fd.isCtorDeclaration(); 1743 1744 const size_t n = (nargs > nparams) ? nargs : nparams; // n = max(nargs, nparams) 1745 1746 /* If the function return type has wildcards in it, we'll need to figure out the actual type 1747 * based on the actual argument types. 1748 * Start with the `this` argument, later on merge into wildmatch the mod bits of the rest 1749 * of the arguments. 1750 */ 1751 MOD wildmatch = (tthis && !isCtorCall) ? tthis.Type.deduceWild(tf, false) : 0; 1752 1753 bool done = false; 1754 foreach (const i; 0 .. n) 1755 { 1756 Expression arg = (i < nargs) ? (*arguments)[i] : null; 1757 1758 if (i < nparams) 1759 { 1760 bool errorArgs() 1761 { 1762 error(loc, "expected %llu function arguments, not %llu", cast(ulong)nparams, cast(ulong)nargs); 1763 return true; 1764 } 1765 1766 Parameter p = tf.parameterList[i]; 1767 1768 if (!arg) 1769 { 1770 if (!p.defaultArg) 1771 { 1772 if (tf.parameterList.varargs == VarArg.typesafe && i + 1 == nparams) 1773 goto L2; 1774 return errorArgs(); 1775 } 1776 arg = p.defaultArg; 1777 arg = inlineCopy(arg, sc); 1778 // __FILE__, __LINE__, __MODULE__, __FUNCTION__, and __PRETTY_FUNCTION__ 1779 arg = arg.resolveLoc(loc, sc); 1780 arguments.push(arg); 1781 nargs++; 1782 } 1783 else 1784 { 1785 if (isDefaultInitOp(arg.op)) 1786 { 1787 arg = arg.resolveLoc(loc, sc); 1788 (*arguments)[i] = arg; 1789 } 1790 } 1791 1792 1793 if (tf.parameterList.varargs == VarArg.typesafe && i + 1 == nparams) // https://dlang.org/spec/function.html#variadic 1794 { 1795 //printf("\t\tvarargs == 2, p.type = '%s'\n", p.type.toChars()); 1796 { 1797 MATCH m; 1798 if ((m = arg.implicitConvTo(p.type)) > MATCH.nomatch) 1799 { 1800 if (p.type.nextOf() && arg.implicitConvTo(p.type.nextOf()) >= m) 1801 goto L2; 1802 else if (nargs != nparams) 1803 return errorArgs(); 1804 goto L1; 1805 } 1806 } 1807 L2: 1808 Type tb = p.type.toBasetype(); 1809 switch (tb.ty) 1810 { 1811 case Tsarray: 1812 case Tarray: 1813 { 1814 /* Create a static array variable v of type arg.type: 1815 * T[dim] __arrayArg = [ arguments[i], ..., arguments[nargs-1] ]; 1816 * 1817 * The array literal in the initializer of the hidden variable 1818 * is now optimized. 1819 * https://issues.dlang.org/show_bug.cgi?id=2356 1820 */ 1821 Type tbn = (cast(TypeArray)tb).next; // array element type 1822 Type tret = p.isLazyArray(); 1823 1824 auto elements = new Expressions(nargs - i); 1825 foreach (u; 0 .. elements.dim) 1826 { 1827 Expression a = (*arguments)[i + u]; 1828 if (tret && a.implicitConvTo(tret)) 1829 { 1830 // p is a lazy array of delegates, tret is return type of the delegates 1831 a = a.implicitCastTo(sc, tret) 1832 .optimize(WANTvalue) 1833 .toDelegate(tret, sc); 1834 } 1835 else 1836 a = a.implicitCastTo(sc, tbn); 1837 a = a.addDtorHook(sc); 1838 (*elements)[u] = a; 1839 } 1840 // https://issues.dlang.org/show_bug.cgi?id=14395 1841 // Convert to a static array literal, or its slice. 1842 arg = new ArrayLiteralExp(loc, tbn.sarrayOf(nargs - i), elements); 1843 if (tb.ty == Tarray) 1844 { 1845 arg = new SliceExp(loc, arg, null, null); 1846 arg.type = p.type; 1847 } 1848 break; 1849 } 1850 case Tclass: 1851 { 1852 /* Set arg to be: 1853 * new Tclass(arg0, arg1, ..., argn) 1854 */ 1855 auto args = new Expressions(nargs - i); 1856 foreach (u; i .. nargs) 1857 (*args)[u - i] = (*arguments)[u]; 1858 arg = new NewExp(loc, null, null, p.type, args); 1859 break; 1860 } 1861 default: 1862 if (!arg) 1863 { 1864 error(loc, "not enough arguments"); 1865 return true; 1866 } 1867 break; 1868 } 1869 arg = arg.expressionSemantic(sc); 1870 //printf("\targ = '%s'\n", arg.toChars()); 1871 arguments.setDim(i + 1); 1872 (*arguments)[i] = arg; 1873 nargs = i + 1; 1874 done = true; 1875 } 1876 1877 L1: 1878 if (!(p.storageClass & STC.lazy_ && p.type.ty == Tvoid)) 1879 { 1880 const isRef = (p.storageClass & (STC.ref_ | STC.out_)) != 0; 1881 if (ubyte wm = arg.type.deduceWild(p.type, isRef)) 1882 { 1883 wildmatch = wildmatch ? MODmerge(wildmatch, wm) : wm; 1884 //printf("[%d] p = %s, a = %s, wm = %d, wildmatch = %d\n", i, p.type.toChars(), arg.type.toChars(), wm, wildmatch); 1885 } 1886 } 1887 } 1888 if (done) 1889 break; 1890 } 1891 if ((wildmatch == MODFlags.mutable || wildmatch == MODFlags.immutable_) && 1892 tf.next && tf.next.hasWild() && 1893 (tf.isref || !tf.next.implicitConvTo(tf.next.immutableOf()))) 1894 { 1895 bool errorInout(MOD wildmatch) 1896 { 1897 const(char)* s = wildmatch == MODFlags.mutable ? "mutable" : MODtoChars(wildmatch); 1898 error(loc, "modify `inout` to `%s` is not allowed inside `inout` function", s); 1899 return true; 1900 } 1901 1902 if (fd) 1903 { 1904 /* If the called function may return the reference to 1905 * outer inout data, it should be rejected. 1906 * 1907 * void foo(ref inout(int) x) { 1908 * ref inout(int) bar(inout(int)) { return x; } 1909 * struct S { 1910 * ref inout(int) bar() inout { return x; } 1911 * ref inout(int) baz(alias a)() inout { return x; } 1912 * } 1913 * bar(int.init) = 1; // bad! 1914 * S().bar() = 1; // bad! 1915 * } 1916 * void test() { 1917 * int a; 1918 * auto s = foo(a); 1919 * s.baz!a() = 1; // bad! 1920 * } 1921 * 1922 */ 1923 bool checkEnclosingWild(Dsymbol s) 1924 { 1925 bool checkWild(Dsymbol s) 1926 { 1927 if (!s) 1928 return false; 1929 if (auto ad = s.isAggregateDeclaration()) 1930 { 1931 if (ad.isNested()) 1932 return checkEnclosingWild(s); 1933 } 1934 else if (auto ff = s.isFuncDeclaration()) 1935 { 1936 if ((cast(TypeFunction)ff.type).iswild) 1937 return errorInout(wildmatch); 1938 1939 if (ff.isNested() || ff.isThis()) 1940 return checkEnclosingWild(s); 1941 } 1942 return false; 1943 } 1944 1945 Dsymbol ctx0 = s.toParent2(); 1946 Dsymbol ctx1 = s.toParentLocal(); 1947 if (checkWild(ctx0)) 1948 return true; 1949 if (ctx0 != ctx1) 1950 return checkWild(ctx1); 1951 return false; 1952 } 1953 if ((fd.isThis() || fd.isNested()) && checkEnclosingWild(fd)) 1954 return true; 1955 } 1956 else if (tf.isWild()) 1957 return errorInout(wildmatch); 1958 } 1959 1960 Expression firstArg = ((tf.next && tf.next.ty == Tvoid || isCtorCall) && 1961 tthis && 1962 tthis.isMutable() && tthis.toBasetype().ty == Tstruct && 1963 tthis.hasPointers()) 1964 ? ethis : null; 1965 1966 assert(nargs >= nparams); 1967 foreach (const i, arg; (*arguments)[0 .. nargs]) 1968 { 1969 assert(arg); 1970 if (i < nparams) 1971 { 1972 Parameter p = tf.parameterList[i]; 1973 Type targ = arg.type; // keep original type for isCopyable() because alias this 1974 // resolution may hide an uncopyable type 1975 1976 if (!(p.storageClass & STC.lazy_ && p.type.ty == Tvoid)) 1977 { 1978 Type tprm = p.type.hasWild() 1979 ? p.type.substWildTo(wildmatch) 1980 : p.type; 1981 1982 const hasCopyCtor = (arg.type.ty == Tstruct) && (cast(TypeStruct)arg.type).sym.hasCopyCtor; 1983 const typesMatch = arg.type.mutableOf().unSharedOf().equals(tprm.mutableOf().unSharedOf()); 1984 if (!((hasCopyCtor && typesMatch) || tprm.equals(arg.type))) 1985 { 1986 //printf("arg.type = %s, p.type = %s\n", arg.type.toChars(), p.type.toChars()); 1987 arg = arg.implicitCastTo(sc, tprm); 1988 arg = arg.optimize(WANTvalue, p.isReference()); 1989 } 1990 } 1991 1992 // Support passing rvalue to `in` parameters 1993 if ((p.storageClass & (STC.in_ | STC.ref_)) == (STC.in_ | STC.ref_)) 1994 { 1995 if (!arg.isLvalue()) 1996 { 1997 auto v = copyToTemp(STC.exptemp, "__rvalue", arg); 1998 Expression ev = new DeclarationExp(arg.loc, v); 1999 ev = new CommaExp(arg.loc, ev, new VarExp(arg.loc, v)); 2000 arg = ev.expressionSemantic(sc); 2001 } 2002 arg = arg.toLvalue(sc, arg); 2003 2004 // Look for mutable misaligned pointer, etc., in @safe mode 2005 err |= checkUnsafeAccess(sc, arg, false, true); 2006 } 2007 else if (p.storageClass & STC.ref_) 2008 { 2009 if (global.params.rvalueRefParam && 2010 !arg.isLvalue() && 2011 targ.isCopyable()) 2012 { /* allow rvalues to be passed to ref parameters by copying 2013 * them to a temp, then pass the temp as the argument 2014 */ 2015 auto v = copyToTemp(0, "__rvalue", arg); 2016 Expression ev = new DeclarationExp(arg.loc, v); 2017 ev = new CommaExp(arg.loc, ev, new VarExp(arg.loc, v)); 2018 arg = ev.expressionSemantic(sc); 2019 } 2020 arg = arg.toLvalue(sc, arg); 2021 2022 // Look for mutable misaligned pointer, etc., in @safe mode 2023 err |= checkUnsafeAccess(sc, arg, false, true); 2024 } 2025 else if (p.storageClass & STC.out_) 2026 { 2027 Type t = arg.type; 2028 if (!t.isMutable() || !t.isAssignable()) // check blit assignable 2029 { 2030 arg.error("cannot modify struct `%s` with immutable members", arg.toChars()); 2031 err = true; 2032 } 2033 else 2034 { 2035 // Look for misaligned pointer, etc., in @safe mode 2036 err |= checkUnsafeAccess(sc, arg, false, true); 2037 err |= checkDefCtor(arg.loc, t); // t must be default constructible 2038 } 2039 arg = arg.toLvalue(sc, arg); 2040 } 2041 else if (p.storageClass & STC.lazy_) 2042 { 2043 // Convert lazy argument to a delegate 2044 auto t = (p.type.ty == Tvoid) ? p.type : arg.type; 2045 arg = toDelegate(arg, t, sc); 2046 } 2047 //printf("arg: %s\n", arg.toChars()); 2048 //printf("type: %s\n", arg.type.toChars()); 2049 //printf("param: %s\n", p.toChars()); 2050 2051 if (firstArg && p.storageClass & STC.return_) 2052 { 2053 /* Argument value can be assigned to firstArg. 2054 * Check arg to see if it matters. 2055 */ 2056 if (global.params.vsafe) 2057 err |= checkParamArgumentReturn(sc, firstArg, arg, false); 2058 } 2059 else if (tf.parameterEscapes(tthis, p)) 2060 { 2061 /* Argument value can escape from the called function. 2062 * Check arg to see if it matters. 2063 */ 2064 if (global.params.vsafe) 2065 err |= checkParamArgumentEscape(sc, fd, p, arg, false, false); 2066 } 2067 else 2068 { 2069 /* Argument value cannot escape from the called function. 2070 */ 2071 Expression a = arg; 2072 if (a.op == TOK.cast_) 2073 a = (cast(CastExp)a).e1; 2074 2075 ArrayLiteralExp ale; 2076 if (p.type.toBasetype().ty == Tarray && !(p.storageClass & STC.return_) && 2077 (ale = a.isArrayLiteralExp()) !is null) 2078 { 2079 // allocate the array literal as temporary static array on the stack 2080 ale.type = ale.type.nextOf().sarrayOf(ale.elements ? ale.elements.length : 0); 2081 auto tmp = copyToTemp(0, "__arrayliteral_on_stack", ale); 2082 auto declareTmp = new DeclarationExp(ale.loc, tmp); 2083 auto castToSlice = new CastExp(ale.loc, new VarExp(ale.loc, tmp), p.type); 2084 arg = CommaExp.combine(declareTmp, castToSlice); 2085 arg = arg.expressionSemantic(sc); 2086 } 2087 else if (a.op == TOK.function_) 2088 { 2089 /* Function literals can only appear once, so if this 2090 * appearance was scoped, there cannot be any others. 2091 */ 2092 FuncExp fe = cast(FuncExp)a; 2093 fe.fd.tookAddressOf = 0; 2094 } 2095 else if (a.op == TOK.delegate_) 2096 { 2097 /* For passing a delegate to a scoped parameter, 2098 * this doesn't count as taking the address of it. 2099 * We only worry about 'escaping' references to the function. 2100 */ 2101 DelegateExp de = cast(DelegateExp)a; 2102 if (de.e1.op == TOK.variable) 2103 { 2104 VarExp ve = cast(VarExp)de.e1; 2105 FuncDeclaration f = ve.var.isFuncDeclaration(); 2106 if (f) 2107 { 2108 if (f.tookAddressOf) 2109 --f.tookAddressOf; 2110 //printf("--tookAddressOf = %d\n", f.tookAddressOf); 2111 } 2112 } 2113 } 2114 } 2115 if (!p.isReference()) 2116 err |= arg.checkSharedAccess(sc); 2117 2118 arg = arg.optimize(WANTvalue, p.isReference()); 2119 2120 /* Determine if this parameter is the "first reference" parameter through which 2121 * later "return" arguments can be stored. 2122 */ 2123 if (i == 0 && !tthis && p.isReference() && p.type && 2124 (tf.next && tf.next.ty == Tvoid || isCtorCall)) 2125 { 2126 Type tb = p.type.baseElemOf(); 2127 if (tb.isMutable() && tb.hasPointers()) 2128 { 2129 firstArg = arg; 2130 } 2131 } 2132 } 2133 else 2134 { 2135 // These will be the trailing ... arguments 2136 // If not D linkage, do promotions 2137 if (tf.linkage != LINK.d) 2138 { 2139 // Promote bytes, words, etc., to ints 2140 arg = integralPromotions(arg, sc); 2141 2142 // Promote floats to doubles 2143 switch (arg.type.ty) 2144 { 2145 case Tfloat32: 2146 arg = arg.castTo(sc, Type.tfloat64); 2147 break; 2148 2149 case Timaginary32: 2150 arg = arg.castTo(sc, Type.timaginary64); 2151 break; 2152 2153 default: 2154 break; 2155 } 2156 if (tf.parameterList.varargs == VarArg.variadic) 2157 { 2158 const(char)* p = tf.linkage == LINK.c ? "extern(C)" : "extern(C++)"; 2159 if (arg.type.ty == Tarray) 2160 { 2161 arg.error("cannot pass dynamic arrays to `%s` vararg functions", p); 2162 err = true; 2163 } 2164 if (arg.type.ty == Tsarray) 2165 { 2166 arg.error("cannot pass static arrays to `%s` vararg functions", p); 2167 err = true; 2168 } 2169 } 2170 } 2171 2172 // Do not allow types that need destructors or copy constructors. 2173 if (arg.type.needsDestruction()) 2174 { 2175 arg.error("cannot pass types that need destruction as variadic arguments"); 2176 err = true; 2177 } 2178 if (arg.type.needsCopyOrPostblit()) 2179 { 2180 arg.error("cannot pass types with postblits or copy constructors as variadic arguments"); 2181 err = true; 2182 } 2183 2184 // Convert static arrays to dynamic arrays 2185 // BUG: I don't think this is right for D2 2186 Type tb = arg.type.toBasetype(); 2187 if (tb.ty == Tsarray) 2188 { 2189 TypeSArray ts = cast(TypeSArray)tb; 2190 Type ta = ts.next.arrayOf(); 2191 if (ts.size(arg.loc) == 0) 2192 arg = new NullExp(arg.loc, ta); 2193 else 2194 arg = arg.castTo(sc, ta); 2195 } 2196 if (tb.ty == Tstruct) 2197 { 2198 //arg = callCpCtor(sc, arg); 2199 } 2200 // Give error for overloaded function addresses 2201 if (arg.op == TOK.symbolOffset) 2202 { 2203 SymOffExp se = cast(SymOffExp)arg; 2204 if (se.hasOverloads && !se.var.isFuncDeclaration().isUnique()) 2205 { 2206 arg.error("function `%s` is overloaded", arg.toChars()); 2207 err = true; 2208 } 2209 } 2210 err |= arg.checkValue(); 2211 err |= arg.checkSharedAccess(sc); 2212 arg = arg.optimize(WANTvalue); 2213 } 2214 (*arguments)[i] = arg; 2215 } 2216 2217 /* If calling C scanf(), printf(), or any variants, check the format string against the arguments 2218 */ 2219 const isVa_list = tf.parameterList.varargs == VarArg.none; 2220 if (fd && fd.flags & FUNCFLAG.printf) 2221 { 2222 if (auto se = (*arguments)[nparams - 1 - isVa_list].isStringExp()) 2223 { 2224 checkPrintfFormat(se.loc, se.peekString(), (*arguments)[nparams .. nargs], isVa_list); 2225 } 2226 } 2227 else if (fd && fd.flags & FUNCFLAG.scanf) 2228 { 2229 if (auto se = (*arguments)[nparams - 1 - isVa_list].isStringExp()) 2230 { 2231 checkScanfFormat(se.loc, se.peekString(), (*arguments)[nparams .. nargs], isVa_list); 2232 } 2233 } 2234 else 2235 { 2236 // TODO: not checking the "v" functions yet (for those, check format string only, not args) 2237 } 2238 2239 /* Remaining problems: 2240 * 1. order of evaluation - some function push L-to-R, others R-to-L. Until we resolve what array assignment does (which is 2241 * implemented by calling a function) we'll defer this for now. 2242 * 2. value structs (or static arrays of them) that need to be copy constructed 2243 * 3. value structs (or static arrays of them) that have destructors, and subsequent arguments that may throw before the 2244 * function gets called. 2245 * 4. value structs need to be destructed after the function call for platforms where the caller destroys the arguments. 2246 * 2, 3 and 4 are handled by doing the argument construction in 'eprefix' so that if a later argument throws, they are cleaned 2247 * up properly. Pushing arguments on the stack then cannot fail. 2248 */ 2249 { 2250 /* TODO: tackle problem 1) 2251 */ 2252 const bool leftToRight = true; // TODO: Any cases that need rightToLeft? 2253 if (!leftToRight) 2254 assert(nargs == nparams); // no variadics for RTL order, as they would probably be evaluated LTR and so add complexity 2255 2256 /* Does Problem (4) apply? 2257 */ 2258 const bool callerDestroysArgs = !target.isCalleeDestroyingArgs(tf); 2259 2260 const ptrdiff_t start = (leftToRight ? 0 : cast(ptrdiff_t)nargs - 1); 2261 const ptrdiff_t end = (leftToRight ? cast(ptrdiff_t)nargs : -1); 2262 const ptrdiff_t step = (leftToRight ? 1 : -1); 2263 2264 /* Compute indices of last throwing argument and first arg needing destruction. 2265 * Used to not set up destructors unless an arg needs destruction on a throw 2266 * in a later argument. 2267 */ 2268 ptrdiff_t lastthrow = -1; // last argument that may throw 2269 ptrdiff_t firstdtor = -1; // first argument that needs destruction 2270 ptrdiff_t lastdtor = -1; // last argument that needs destruction 2271 for (ptrdiff_t i = start; i != end; i += step) 2272 { 2273 Expression arg = (*arguments)[i]; 2274 if (canThrow(arg, sc.func, false)) 2275 lastthrow = i; 2276 if (arg.type.needsDestruction()) 2277 { 2278 Parameter p = (i >= nparams ? null : tf.parameterList[i]); 2279 if (!(p && (p.storageClass & (STC.lazy_ | STC.ref_ | STC.out_)))) 2280 { 2281 if (firstdtor == -1) 2282 firstdtor = i; 2283 lastdtor = i; 2284 } 2285 } 2286 } 2287 2288 /* Do we need 'eprefix' for problems 3 or 4? 2289 */ 2290 const bool needsPrefix = callerDestroysArgs 2291 ? firstdtor >= 0 // true if any argument needs destruction 2292 : firstdtor >= 0 && lastthrow >= 0 && 2293 (lastthrow - firstdtor) * step > 0; // last throw after first destruction 2294 const ptrdiff_t lastPrefix = callerDestroysArgs 2295 ? lastdtor // up to last argument requiring destruction 2296 : lastthrow; // up to last potentially throwing argument 2297 2298 /* Problem 3: initialize 'eprefix' by declaring the gate 2299 */ 2300 VarDeclaration gate; 2301 if (needsPrefix && !callerDestroysArgs) 2302 { 2303 // eprefix => bool __gate [= false] 2304 Identifier idtmp = Identifier.generateId("__gate"); 2305 gate = new VarDeclaration(loc, Type.tbool, idtmp, null); 2306 gate.storage_class |= STC.temp | STC.ctfe | STC.volatile_; 2307 gate.dsymbolSemantic(sc); 2308 2309 auto ae = new DeclarationExp(loc, gate); 2310 eprefix = ae.expressionSemantic(sc); 2311 } 2312 2313 for (ptrdiff_t i = start; i != end; i += step) 2314 { 2315 Expression arg = (*arguments)[i]; 2316 //printf("arg[%d]: %s\n", cast(int)i, arg.toChars()); 2317 2318 Parameter parameter = (i >= nparams ? null : tf.parameterList[i]); 2319 const bool isRef = parameter && parameter.isReference(); 2320 const bool isLazy = (parameter && (parameter.storageClass & STC.lazy_)); 2321 2322 /* Skip lazy parameters 2323 */ 2324 if (isLazy) 2325 continue; 2326 2327 /* Do we have 'eprefix' and aren't past 'lastPrefix' yet? 2328 * Then declare a temporary variable for this arg and append that declaration 2329 * to 'eprefix', which will implicitly take care of potential problem 2) for 2330 * this arg. 2331 * 'eprefix' will therefore finally contain all args up to and including 'lastPrefix', 2332 * excluding all lazy parameters. 2333 */ 2334 if (needsPrefix && (lastPrefix - i) * step >= 0) 2335 { 2336 const bool needsDtor = !isRef && arg.type.needsDestruction() && 2337 // Problem 3: last throwing arg doesn't require dtor patching 2338 (callerDestroysArgs || i != lastPrefix); 2339 2340 /* Declare temporary 'auto __pfx = arg' (needsDtor) or 'auto __pfy = arg' (!needsDtor) 2341 */ 2342 auto tmp = copyToTemp(0, 2343 needsDtor ? "__pfx" : "__pfy", 2344 !isRef ? arg : arg.addressOf()); 2345 tmp.dsymbolSemantic(sc); 2346 2347 if (callerDestroysArgs) 2348 { 2349 /* Problem 4: Normal temporary, destructed after the call 2350 */ 2351 if (needsDtor) 2352 tmp.isArgDtorVar = true; // mark it so that the backend passes it by ref to the function being called 2353 } 2354 else 2355 { 2356 /* Problem 3: Modify the destructor so it only runs if gate==false, 2357 * i.e., only if there was a throw while constructing the args 2358 */ 2359 if (!needsDtor) 2360 { 2361 if (tmp.edtor) 2362 { 2363 assert(i == lastPrefix); 2364 tmp.edtor = null; 2365 } 2366 } 2367 else 2368 { 2369 // edtor => (__gate || edtor) 2370 assert(tmp.edtor); 2371 Expression e = tmp.edtor; 2372 e = new LogicalExp(e.loc, TOK.orOr, new VarExp(e.loc, gate), e); 2373 tmp.edtor = e.expressionSemantic(sc); 2374 //printf("edtor: %s\n", tmp.edtor.toChars()); 2375 } 2376 } 2377 2378 // eprefix => (eprefix, auto __pfx/y = arg) 2379 auto ae = new DeclarationExp(loc, tmp); 2380 eprefix = Expression.combine(eprefix, ae.expressionSemantic(sc)); 2381 2382 // arg => __pfx/y 2383 arg = new VarExp(loc, tmp); 2384 arg = arg.expressionSemantic(sc); 2385 if (isRef) 2386 { 2387 arg = new PtrExp(loc, arg); 2388 arg = arg.expressionSemantic(sc); 2389 } 2390 2391 /* Problem 3: Last throwing arg? 2392 * Then finalize eprefix => (eprefix, gate = true), i.e., disable the 2393 * dtors right after constructing the last throwing arg. 2394 * From now on, the callee will take care of destructing the args because 2395 * the args are implicitly moved into function parameters. 2396 */ 2397 if (!callerDestroysArgs && i == lastPrefix) 2398 { 2399 auto e = new AssignExp(gate.loc, new VarExp(gate.loc, gate), IntegerExp.createBool(true)); 2400 eprefix = Expression.combine(eprefix, e.expressionSemantic(sc)); 2401 } 2402 } 2403 else // not part of 'eprefix' 2404 { 2405 /* Handle problem 2) by calling the copy constructor for value structs 2406 * (or static arrays of them) if appropriate. 2407 */ 2408 Type tv = arg.type.baseElemOf(); 2409 if (!isRef && tv.ty == Tstruct) 2410 arg = doCopyOrMove(sc, arg, parameter ? parameter.type : null); 2411 } 2412 2413 (*arguments)[i] = arg; 2414 } 2415 } 2416 //if (eprefix) printf("eprefix: %s\n", eprefix.toChars()); 2417 2418 /* Test compliance with DIP1021 2419 */ 2420 if (global.params.useDIP1021 && 2421 tf.trust != TRUST.system && tf.trust != TRUST.trusted) 2422 err |= checkMutableArguments(sc, fd, tf, ethis, arguments, false); 2423 2424 // If D linkage and variadic, add _arguments[] as first argument 2425 if (tf.isDstyleVariadic()) 2426 { 2427 assert(arguments.dim >= nparams); 2428 2429 auto args = new Parameters(arguments.dim - nparams); 2430 for (size_t i = 0; i < arguments.dim - nparams; i++) 2431 { 2432 auto arg = new Parameter(STC.in_, (*arguments)[nparams + i].type, null, null, null); 2433 (*args)[i] = arg; 2434 } 2435 auto tup = new TypeTuple(args); 2436 Expression e = (new TypeidExp(loc, tup)).expressionSemantic(sc); 2437 arguments.insert(0, e); 2438 } 2439 2440 /* Determine function return type: tret 2441 */ 2442 Type tret = tf.next; 2443 if (isCtorCall) 2444 { 2445 //printf("[%s] fd = %s %s, %d %d %d\n", loc.toChars(), fd.toChars(), fd.type.toChars(), 2446 // wildmatch, tf.isWild(), fd.isReturnIsolated()); 2447 if (!tthis) 2448 { 2449 assert(sc.intypeof || global.errors); 2450 tthis = fd.isThis().type.addMod(fd.type.mod); 2451 } 2452 if (tf.isWild() && !fd.isReturnIsolated()) 2453 { 2454 if (wildmatch) 2455 tret = tret.substWildTo(wildmatch); 2456 int offset; 2457 if (!tret.implicitConvTo(tthis) && !(MODimplicitConv(tret.mod, tthis.mod) && tret.isBaseOf(tthis, &offset) && offset == 0)) 2458 { 2459 const(char)* s1 = tret.isNaked() ? " mutable" : tret.modToChars(); 2460 const(char)* s2 = tthis.isNaked() ? " mutable" : tthis.modToChars(); 2461 .error(loc, "`inout` constructor `%s` creates%s object, not%s", fd.toPrettyChars(), s1, s2); 2462 err = true; 2463 } 2464 } 2465 tret = tthis; 2466 } 2467 else if (wildmatch && tret) 2468 { 2469 /* Adjust function return type based on wildmatch 2470 */ 2471 //printf("wildmatch = x%x, tret = %s\n", wildmatch, tret.toChars()); 2472 tret = tret.substWildTo(wildmatch); 2473 } 2474 2475 *prettype = tret; 2476 *peprefix = eprefix; 2477 return (err || olderrors != global.errors); 2478 } 2479 2480 /** 2481 * Determines whether a symbol represents a module or package 2482 * (Used as a helper for is(type == module) and is(type == package)) 2483 * 2484 * Params: 2485 * sym = the symbol to be checked 2486 * 2487 * Returns: 2488 * the symbol which `sym` represents (or `null` if it doesn't represent a `Package`) 2489 */ 2490 Package resolveIsPackage(Dsymbol sym) 2491 { 2492 Package pkg; 2493 if (Import imp = sym.isImport()) 2494 { 2495 if (imp.pkg is null) 2496 { 2497 .error(sym.loc, "Internal Compiler Error: unable to process forward-referenced import `%s`", 2498 imp.toChars()); 2499 assert(0); 2500 } 2501 pkg = imp.pkg; 2502 } 2503 else if (auto mod = sym.isModule()) 2504 pkg = mod.isPackageFile ? mod.pkg : sym.isPackage(); 2505 else 2506 pkg = sym.isPackage(); 2507 if (pkg) 2508 pkg.resolvePKGunknown(); 2509 return pkg; 2510 } 2511 2512 private Module loadStdMath() 2513 { 2514 __gshared Import impStdMath = null; 2515 __gshared Identifier[1] stdID; 2516 if (!impStdMath) 2517 { 2518 stdID[0] = Id.std; 2519 auto s = new Import(Loc.initial, stdID[], Id.math, null, false); 2520 // Module.load will call fatal() if there's no std.math available. 2521 // Gag the error here, pushing the error handling to the caller. 2522 uint errors = global.startGagging(); 2523 s.load(null); 2524 if (s.mod) 2525 { 2526 s.mod.importAll(null); 2527 s.mod.dsymbolSemantic(null); 2528 } 2529 global.endGagging(errors); 2530 impStdMath = s; 2531 } 2532 return impStdMath.mod; 2533 } 2534 2535 private extern (C++) final class ExpressionSemanticVisitor : Visitor 2536 { 2537 alias visit = Visitor.visit; 2538 2539 Scope* sc; 2540 Expression result; 2541 2542 this(Scope* sc) 2543 { 2544 this.sc = sc; 2545 } 2546 2547 private void setError() 2548 { 2549 result = ErrorExp.get(); 2550 } 2551 2552 /************************** 2553 * Semantically analyze Expression. 2554 * Determine types, fold constants, etc. 2555 */ 2556 override void visit(Expression e) 2557 { 2558 static if (LOGSEMANTIC) 2559 { 2560 printf("Expression::semantic() %s\n", e.toChars()); 2561 } 2562 if (e.type) 2563 e.type = e.type.typeSemantic(e.loc, sc); 2564 else 2565 e.type = Type.tvoid; 2566 result = e; 2567 } 2568 2569 override void visit(IntegerExp e) 2570 { 2571 assert(e.type); 2572 if (e.type.ty == Terror) 2573 return setError(); 2574 2575 assert(e.type.deco); 2576 e.setInteger(e.getInteger()); 2577 result = e; 2578 } 2579 2580 override void visit(RealExp e) 2581 { 2582 if (!e.type) 2583 e.type = Type.tfloat64; 2584 else 2585 e.type = e.type.typeSemantic(e.loc, sc); 2586 result = e; 2587 } 2588 2589 override void visit(ComplexExp e) 2590 { 2591 if (!e.type) 2592 e.type = Type.tcomplex80; 2593 else 2594 e.type = e.type.typeSemantic(e.loc, sc); 2595 result = e; 2596 } 2597 2598 override void visit(IdentifierExp exp) 2599 { 2600 static if (LOGSEMANTIC) 2601 { 2602 printf("IdentifierExp::semantic('%s')\n", exp.ident.toChars()); 2603 } 2604 if (exp.type) // This is used as the dummy expression 2605 { 2606 result = exp; 2607 return; 2608 } 2609 2610 Dsymbol scopesym; 2611 Dsymbol s = sc.search(exp.loc, exp.ident, &scopesym); 2612 if (s) 2613 { 2614 if (s.errors) 2615 return setError(); 2616 2617 Expression e; 2618 2619 /* See if the symbol was a member of an enclosing 'with' 2620 */ 2621 WithScopeSymbol withsym = scopesym.isWithScopeSymbol(); 2622 if (withsym && withsym.withstate.wthis && symbolIsVisible(sc, s)) 2623 { 2624 /* Disallow shadowing 2625 */ 2626 // First find the scope of the with 2627 Scope* scwith = sc; 2628 while (scwith.scopesym != scopesym) 2629 { 2630 scwith = scwith.enclosing; 2631 assert(scwith); 2632 } 2633 // Look at enclosing scopes for symbols with the same name, 2634 // in the same function 2635 for (Scope* scx = scwith; scx && scx.func == scwith.func; scx = scx.enclosing) 2636 { 2637 Dsymbol s2; 2638 if (scx.scopesym && scx.scopesym.symtab && (s2 = scx.scopesym.symtab.lookup(s.ident)) !is null && s != s2) 2639 { 2640 exp.error("with symbol `%s` is shadowing local symbol `%s`", s.toPrettyChars(), s2.toPrettyChars()); 2641 return setError(); 2642 } 2643 } 2644 s = s.toAlias(); 2645 2646 // Same as wthis.ident 2647 // TODO: DotIdExp.semantic will find 'ident' from 'wthis' again. 2648 // The redudancy should be removed. 2649 e = new VarExp(exp.loc, withsym.withstate.wthis); 2650 e = new DotIdExp(exp.loc, e, exp.ident); 2651 e = e.expressionSemantic(sc); 2652 } 2653 else 2654 { 2655 if (withsym) 2656 { 2657 if (withsym.withstate.exp.type.ty != Tvoid) 2658 { 2659 // 'with (exp)' is a type expression 2660 // or 's' is not visible there (for error message) 2661 e = new TypeExp(exp.loc, withsym.withstate.exp.type); 2662 } 2663 else 2664 { 2665 // 'with (exp)' is a Package/Module 2666 e = withsym.withstate.exp; 2667 } 2668 e = new DotIdExp(exp.loc, e, exp.ident); 2669 result = e.expressionSemantic(sc); 2670 return; 2671 } 2672 2673 /* If f is really a function template, 2674 * then replace f with the function template declaration. 2675 */ 2676 FuncDeclaration f = s.isFuncDeclaration(); 2677 if (f) 2678 { 2679 TemplateDeclaration td = getFuncTemplateDecl(f); 2680 if (td) 2681 { 2682 if (td.overroot) // if not start of overloaded list of TemplateDeclaration's 2683 td = td.overroot; // then get the start 2684 e = new TemplateExp(exp.loc, td, f); 2685 e = e.expressionSemantic(sc); 2686 result = e; 2687 return; 2688 } 2689 } 2690 2691 if (global.params.fixAliasThis) 2692 { 2693 ExpressionDsymbol expDsym = scopesym.isExpressionDsymbol(); 2694 if (expDsym) 2695 { 2696 //printf("expDsym = %s\n", expDsym.exp.toChars()); 2697 result = expDsym.exp.expressionSemantic(sc); 2698 return; 2699 } 2700 } 2701 // Haven't done overload resolution yet, so pass 1 2702 e = symbolToExp(s, exp.loc, sc, true); 2703 } 2704 result = e; 2705 return; 2706 } 2707 2708 if (!global.params.fixAliasThis && hasThis(sc)) 2709 { 2710 for (AggregateDeclaration ad = sc.getStructClassScope(); ad;) 2711 { 2712 if (ad.aliasthis) 2713 { 2714 Expression e; 2715 e = new ThisExp(exp.loc); 2716 e = new DotIdExp(exp.loc, e, ad.aliasthis.ident); 2717 e = new DotIdExp(exp.loc, e, exp.ident); 2718 e = e.trySemantic(sc); 2719 if (e) 2720 { 2721 result = e; 2722 return; 2723 } 2724 } 2725 2726 auto cd = ad.isClassDeclaration(); 2727 if (cd && cd.baseClass && cd.baseClass != ClassDeclaration.object) 2728 { 2729 ad = cd.baseClass; 2730 continue; 2731 } 2732 break; 2733 } 2734 } 2735 2736 if (exp.ident == Id.ctfe) 2737 { 2738 if (sc.flags & SCOPE.ctfe) 2739 { 2740 exp.error("variable `__ctfe` cannot be read at compile time"); 2741 return setError(); 2742 } 2743 2744 // Create the magic __ctfe bool variable 2745 auto vd = new VarDeclaration(exp.loc, Type.tbool, Id.ctfe, null); 2746 vd.storage_class |= STC.temp; 2747 vd.semanticRun = PASS.semanticdone; 2748 Expression e = new VarExp(exp.loc, vd); 2749 e = e.expressionSemantic(sc); 2750 result = e; 2751 return; 2752 } 2753 2754 // If we've reached this point and are inside a with() scope then we may 2755 // try one last attempt by checking whether the 'wthis' object supports 2756 // dynamic dispatching via opDispatch. 2757 // This is done by rewriting this expression as wthis.ident. 2758 // The innermost with() scope of the hierarchy to satisfy the condition 2759 // above wins. 2760 // https://issues.dlang.org/show_bug.cgi?id=6400 2761 for (Scope* sc2 = sc; sc2; sc2 = sc2.enclosing) 2762 { 2763 if (!sc2.scopesym) 2764 continue; 2765 2766 if (auto ss = sc2.scopesym.isWithScopeSymbol()) 2767 { 2768 if (ss.withstate.wthis) 2769 { 2770 Expression e; 2771 e = new VarExp(exp.loc, ss.withstate.wthis); 2772 e = new DotIdExp(exp.loc, e, exp.ident); 2773 e = e.trySemantic(sc); 2774 if (e) 2775 { 2776 result = e; 2777 return; 2778 } 2779 } 2780 // Try Type.opDispatch (so the static version) 2781 else if (ss.withstate.exp && ss.withstate.exp.op == TOK.type) 2782 { 2783 if (Type t = ss.withstate.exp.isTypeExp().type) 2784 { 2785 Expression e; 2786 e = new TypeExp(exp.loc, t); 2787 e = new DotIdExp(exp.loc, e, exp.ident); 2788 e = e.trySemantic(sc); 2789 if (e) 2790 { 2791 result = e; 2792 return; 2793 } 2794 } 2795 } 2796 } 2797 } 2798 2799 /* Look for what user might have meant 2800 */ 2801 if (const n = importHint(exp.ident.toString())) 2802 exp.error("`%s` is not defined, perhaps `import %.*s;` is needed?", exp.ident.toChars(), cast(int)n.length, n.ptr); 2803 else if (auto s2 = sc.search_correct(exp.ident)) 2804 exp.error("undefined identifier `%s`, did you mean %s `%s`?", exp.ident.toChars(), s2.kind(), s2.toChars()); 2805 else if (const p = Scope.search_correct_C(exp.ident)) 2806 exp.error("undefined identifier `%s`, did you mean `%s`?", exp.ident.toChars(), p); 2807 else 2808 exp.error("undefined identifier `%s`", exp.ident.toChars()); 2809 2810 result = ErrorExp.get(); 2811 } 2812 2813 override void visit(DsymbolExp e) 2814 { 2815 result = symbolToExp(e.s, e.loc, sc, e.hasOverloads); 2816 } 2817 2818 override void visit(ThisExp e) 2819 { 2820 static if (LOGSEMANTIC) 2821 { 2822 printf("ThisExp::semantic()\n"); 2823 } 2824 if (e.type) 2825 { 2826 result = e; 2827 return; 2828 } 2829 2830 FuncDeclaration fd = hasThis(sc); // fd is the uplevel function with the 'this' variable 2831 AggregateDeclaration ad; 2832 2833 /* Special case for typeof(this) and typeof(super) since both 2834 * should work even if they are not inside a non-static member function 2835 */ 2836 if (!fd && sc.intypeof == 1) 2837 { 2838 // Find enclosing struct or class 2839 for (Dsymbol s = sc.getStructClassScope(); 1; s = s.parent) 2840 { 2841 if (!s) 2842 { 2843 e.error("`%s` is not in a class or struct scope", e.toChars()); 2844 goto Lerr; 2845 } 2846 ClassDeclaration cd = s.isClassDeclaration(); 2847 if (cd) 2848 { 2849 e.type = cd.type; 2850 result = e; 2851 return; 2852 } 2853 StructDeclaration sd = s.isStructDeclaration(); 2854 if (sd) 2855 { 2856 e.type = sd.type; 2857 result = e; 2858 return; 2859 } 2860 } 2861 } 2862 if (!fd) 2863 goto Lerr; 2864 2865 assert(fd.vthis); 2866 e.var = fd.vthis; 2867 assert(e.var.parent); 2868 ad = fd.isMemberLocal(); 2869 if (!ad) 2870 ad = fd.isMember2(); 2871 assert(ad); 2872 e.type = ad.type.addMod(e.var.type.mod); 2873 2874 if (e.var.checkNestedReference(sc, e.loc)) 2875 return setError(); 2876 2877 result = e; 2878 return; 2879 2880 Lerr: 2881 e.error("`this` is only defined in non-static member functions, not `%s`", sc.parent.toChars()); 2882 result = ErrorExp.get(); 2883 } 2884 2885 override void visit(SuperExp e) 2886 { 2887 static if (LOGSEMANTIC) 2888 { 2889 printf("SuperExp::semantic('%s')\n", e.toChars()); 2890 } 2891 if (e.type) 2892 { 2893 result = e; 2894 return; 2895 } 2896 2897 FuncDeclaration fd = hasThis(sc); 2898 ClassDeclaration cd; 2899 Dsymbol s; 2900 2901 /* Special case for typeof(this) and typeof(super) since both 2902 * should work even if they are not inside a non-static member function 2903 */ 2904 if (!fd && sc.intypeof == 1) 2905 { 2906 // Find enclosing class 2907 for (s = sc.getStructClassScope(); 1; s = s.parent) 2908 { 2909 if (!s) 2910 { 2911 e.error("`%s` is not in a class scope", e.toChars()); 2912 goto Lerr; 2913 } 2914 cd = s.isClassDeclaration(); 2915 if (cd) 2916 { 2917 cd = cd.baseClass; 2918 if (!cd) 2919 { 2920 e.error("class `%s` has no `super`", s.toChars()); 2921 goto Lerr; 2922 } 2923 e.type = cd.type; 2924 result = e; 2925 return; 2926 } 2927 } 2928 } 2929 if (!fd) 2930 goto Lerr; 2931 2932 e.var = fd.vthis; 2933 assert(e.var && e.var.parent); 2934 2935 s = fd.toParentDecl(); 2936 if (s.isTemplateDeclaration()) // allow inside template constraint 2937 s = s.toParent(); 2938 assert(s); 2939 cd = s.isClassDeclaration(); 2940 //printf("parent is %s %s\n", fd.toParent().kind(), fd.toParent().toChars()); 2941 if (!cd) 2942 goto Lerr; 2943 if (!cd.baseClass) 2944 { 2945 e.error("no base class for `%s`", cd.toChars()); 2946 e.type = cd.type.addMod(e.var.type.mod); 2947 } 2948 else 2949 { 2950 e.type = cd.baseClass.type; 2951 e.type = e.type.castMod(e.var.type.mod); 2952 } 2953 2954 if (e.var.checkNestedReference(sc, e.loc)) 2955 return setError(); 2956 2957 result = e; 2958 return; 2959 2960 Lerr: 2961 e.error("`super` is only allowed in non-static class member functions"); 2962 result = ErrorExp.get(); 2963 } 2964 2965 override void visit(NullExp e) 2966 { 2967 static if (LOGSEMANTIC) 2968 { 2969 printf("NullExp::semantic('%s')\n", e.toChars()); 2970 } 2971 // NULL is the same as (void *)0 2972 if (e.type) 2973 { 2974 result = e; 2975 return; 2976 } 2977 e.type = Type.tnull; 2978 result = e; 2979 } 2980 2981 override void visit(StringExp e) 2982 { 2983 static if (LOGSEMANTIC) 2984 { 2985 printf("StringExp::semantic() %s\n", e.toChars()); 2986 } 2987 if (e.type) 2988 { 2989 result = e; 2990 return; 2991 } 2992 2993 OutBuffer buffer; 2994 size_t newlen = 0; 2995 size_t u; 2996 dchar c; 2997 2998 switch (e.postfix) 2999 { 3000 case 'd': 3001 for (u = 0; u < e.len;) 3002 { 3003 if (const p = utf_decodeChar(e.peekString(), u, c)) 3004 { 3005 e.error("%.*s", cast(int)p.length, p.ptr); 3006 return setError(); 3007 } 3008 else 3009 { 3010 buffer.write4(c); 3011 newlen++; 3012 } 3013 } 3014 buffer.write4(0); 3015 e.setData(buffer.extractData(), newlen, 4); 3016 e.type = new TypeDArray(Type.tdchar.immutableOf()); 3017 e.committed = 1; 3018 break; 3019 3020 case 'w': 3021 for (u = 0; u < e.len;) 3022 { 3023 if (const p = utf_decodeChar(e.peekString(), u, c)) 3024 { 3025 e.error("%.*s", cast(int)p.length, p.ptr); 3026 return setError(); 3027 } 3028 else 3029 { 3030 buffer.writeUTF16(c); 3031 newlen++; 3032 if (c >= 0x10000) 3033 newlen++; 3034 } 3035 } 3036 buffer.writeUTF16(0); 3037 e.setData(buffer.extractData(), newlen, 2); 3038 e.type = new TypeDArray(Type.twchar.immutableOf()); 3039 e.committed = 1; 3040 break; 3041 3042 case 'c': 3043 e.committed = 1; 3044 goto default; 3045 3046 default: 3047 e.type = new TypeDArray(Type.tchar.immutableOf()); 3048 break; 3049 } 3050 e.type = e.type.typeSemantic(e.loc, sc); 3051 //type = type.immutableOf(); 3052 //printf("type = %s\n", type.toChars()); 3053 3054 result = e; 3055 } 3056 3057 override void visit(TupleExp exp) 3058 { 3059 static if (LOGSEMANTIC) 3060 { 3061 printf("+TupleExp::semantic(%s)\n", exp.toChars()); 3062 } 3063 if (exp.type) 3064 { 3065 result = exp; 3066 return; 3067 } 3068 3069 if (exp.e0) 3070 exp.e0 = exp.e0.expressionSemantic(sc); 3071 3072 // Run semantic() on each argument 3073 bool err = false; 3074 for (size_t i = 0; i < exp.exps.dim; i++) 3075 { 3076 Expression e = (*exp.exps)[i]; 3077 e = e.expressionSemantic(sc); 3078 if (!e.type) 3079 { 3080 exp.error("`%s` has no value", e.toChars()); 3081 err = true; 3082 } 3083 else if (e.op == TOK.error) 3084 err = true; 3085 else 3086 (*exp.exps)[i] = e; 3087 } 3088 if (err) 3089 return setError(); 3090 3091 expandTuples(exp.exps); 3092 3093 exp.type = new TypeTuple(exp.exps); 3094 exp.type = exp.type.typeSemantic(exp.loc, sc); 3095 //printf("-TupleExp::semantic(%s)\n", toChars()); 3096 result = exp; 3097 } 3098 3099 override void visit(ArrayLiteralExp e) 3100 { 3101 static if (LOGSEMANTIC) 3102 { 3103 printf("ArrayLiteralExp::semantic('%s')\n", e.toChars()); 3104 } 3105 if (e.type) 3106 { 3107 result = e; 3108 return; 3109 } 3110 3111 /* Perhaps an empty array literal [ ] should be rewritten as null? 3112 */ 3113 3114 if (e.basis) 3115 e.basis = e.basis.expressionSemantic(sc); 3116 if (arrayExpressionSemantic(e.elements, sc) || (e.basis && e.basis.op == TOK.error)) 3117 return setError(); 3118 3119 expandTuples(e.elements); 3120 3121 if (e.basis) 3122 e.elements.push(e.basis); 3123 Type t0 = arrayExpressionToCommonType(sc, *e.elements); 3124 if (e.basis) 3125 e.basis = e.elements.pop(); 3126 if (t0 is null) 3127 return setError(); 3128 3129 e.type = t0.arrayOf(); 3130 e.type = e.type.typeSemantic(e.loc, sc); 3131 3132 /* Disallow array literals of type void being used. 3133 */ 3134 if (e.elements.dim > 0 && t0.ty == Tvoid) 3135 { 3136 e.error("`%s` of type `%s` has no value", e.toChars(), e.type.toChars()); 3137 return setError(); 3138 } 3139 3140 if (global.params.useTypeInfo && Type.dtypeinfo) 3141 semanticTypeInfo(sc, e.type); 3142 3143 result = e; 3144 } 3145 3146 override void visit(AssocArrayLiteralExp e) 3147 { 3148 static if (LOGSEMANTIC) 3149 { 3150 printf("AssocArrayLiteralExp::semantic('%s')\n", e.toChars()); 3151 } 3152 if (e.type) 3153 { 3154 result = e; 3155 return; 3156 } 3157 3158 // Run semantic() on each element 3159 bool err_keys = arrayExpressionSemantic(e.keys, sc); 3160 bool err_vals = arrayExpressionSemantic(e.values, sc); 3161 if (err_keys || err_vals) 3162 return setError(); 3163 3164 expandTuples(e.keys); 3165 expandTuples(e.values); 3166 if (e.keys.dim != e.values.dim) 3167 { 3168 e.error("number of keys is %llu, must match number of values %llu", 3169 cast(ulong) e.keys.dim, cast(ulong) e.values.dim); 3170 return setError(); 3171 } 3172 3173 Type tkey = arrayExpressionToCommonType(sc, *e.keys); 3174 Type tvalue = arrayExpressionToCommonType(sc, *e.values); 3175 if (tkey is null || tvalue is null) 3176 return setError(); 3177 3178 e.type = new TypeAArray(tvalue, tkey); 3179 e.type = e.type.typeSemantic(e.loc, sc); 3180 3181 semanticTypeInfo(sc, e.type); 3182 3183 if (global.params.vsafe) 3184 { 3185 if (checkAssocArrayLiteralEscape(sc, e, false)) 3186 return setError(); 3187 } 3188 3189 result = e; 3190 } 3191 3192 override void visit(StructLiteralExp e) 3193 { 3194 static if (LOGSEMANTIC) 3195 { 3196 printf("StructLiteralExp::semantic('%s')\n", e.toChars()); 3197 } 3198 if (e.type) 3199 { 3200 result = e; 3201 return; 3202 } 3203 3204 e.sd.size(e.loc); 3205 if (e.sd.sizeok != Sizeok.done) 3206 return setError(); 3207 3208 // run semantic() on each element 3209 if (arrayExpressionSemantic(e.elements, sc)) 3210 return setError(); 3211 3212 expandTuples(e.elements); 3213 3214 /* Fit elements[] to the corresponding type of field[]. 3215 */ 3216 if (!e.sd.fit(e.loc, sc, e.elements, e.stype)) 3217 return setError(); 3218 3219 /* Fill out remainder of elements[] with default initializers for fields[] 3220 */ 3221 if (!e.sd.fill(e.loc, e.elements, false)) 3222 { 3223 /* An error in the initializer needs to be recorded as an error 3224 * in the enclosing function or template, since the initializer 3225 * will be part of the stuct declaration. 3226 */ 3227 global.increaseErrorCount(); 3228 return setError(); 3229 } 3230 3231 if (checkFrameAccess(e.loc, sc, e.sd, e.elements.dim)) 3232 return setError(); 3233 3234 e.type = e.stype ? e.stype : e.sd.type; 3235 result = e; 3236 } 3237 3238 override void visit(TypeExp exp) 3239 { 3240 if (exp.type.ty == Terror) 3241 return setError(); 3242 3243 //printf("TypeExp::semantic(%s)\n", exp.type.toChars()); 3244 Expression e; 3245 Type t; 3246 Dsymbol s; 3247 3248 dmd.typesem.resolve(exp.type, exp.loc, sc, e, t, s, true); 3249 if (e) 3250 { 3251 // `(Type)` is actually `(var)` so if `(var)` is a member requiring `this` 3252 // then rewrite as `(this.var)` in case it would be followed by a DotVar 3253 // to fix https://issues.dlang.org/show_bug.cgi?id=9490 3254 VarExp ve = e.isVarExp(); 3255 if (ve && ve.var && exp.parens && !ve.var.isStatic() && !(sc.stc & STC.static_) && 3256 sc.func && sc.func.needThis && ve.var.toParent2().isAggregateDeclaration()) 3257 { 3258 // printf("apply fix for issue 9490: add `this.` to `%s`...\n", e.toChars()); 3259 e = new DotVarExp(exp.loc, new ThisExp(exp.loc), ve.var, false); 3260 } 3261 //printf("e = %s %s\n", Token::toChars(e.op), e.toChars()); 3262 e = e.expressionSemantic(sc); 3263 } 3264 else if (t) 3265 { 3266 //printf("t = %d %s\n", t.ty, t.toChars()); 3267 exp.type = t.typeSemantic(exp.loc, sc); 3268 e = exp; 3269 } 3270 else if (s) 3271 { 3272 //printf("s = %s %s\n", s.kind(), s.toChars()); 3273 e = symbolToExp(s, exp.loc, sc, true); 3274 } 3275 else 3276 assert(0); 3277 3278 if (global.params.vcomplex) 3279 exp.type.checkComplexTransition(exp.loc, sc); 3280 3281 result = e; 3282 } 3283 3284 override void visit(ScopeExp exp) 3285 { 3286 static if (LOGSEMANTIC) 3287 { 3288 printf("+ScopeExp::semantic(%p '%s')\n", exp, exp.toChars()); 3289 } 3290 if (exp.type) 3291 { 3292 result = exp; 3293 return; 3294 } 3295 3296 ScopeDsymbol sds2 = exp.sds; 3297 TemplateInstance ti = sds2.isTemplateInstance(); 3298 while (ti) 3299 { 3300 WithScopeSymbol withsym; 3301 if (!ti.findTempDecl(sc, &withsym) || !ti.semanticTiargs(sc)) 3302 return setError(); 3303 if (withsym && withsym.withstate.wthis) 3304 { 3305 Expression e = new VarExp(exp.loc, withsym.withstate.wthis); 3306 e = new DotTemplateInstanceExp(exp.loc, e, ti); 3307 result = e.expressionSemantic(sc); 3308 return; 3309 } 3310 if (ti.needsTypeInference(sc)) 3311 { 3312 if (TemplateDeclaration td = ti.tempdecl.isTemplateDeclaration()) 3313 { 3314 Dsymbol p = td.toParentLocal(); 3315 FuncDeclaration fdthis = hasThis(sc); 3316 AggregateDeclaration ad = p ? p.isAggregateDeclaration() : null; 3317 if (fdthis && ad && fdthis.isMemberLocal() == ad && (td._scope.stc & STC.static_) == 0) 3318 { 3319 Expression e = new DotTemplateInstanceExp(exp.loc, new ThisExp(exp.loc), ti); 3320 result = e.expressionSemantic(sc); 3321 return; 3322 } 3323 } 3324 else if (OverloadSet os = ti.tempdecl.isOverloadSet()) 3325 { 3326 FuncDeclaration fdthis = hasThis(sc); 3327 AggregateDeclaration ad = os.parent.isAggregateDeclaration(); 3328 if (fdthis && ad && fdthis.isMemberLocal() == ad) 3329 { 3330 Expression e = new DotTemplateInstanceExp(exp.loc, new ThisExp(exp.loc), ti); 3331 result = e.expressionSemantic(sc); 3332 return; 3333 } 3334 } 3335 // ti is an instance which requires IFTI. 3336 exp.sds = ti; 3337 exp.type = Type.tvoid; 3338 result = exp; 3339 return; 3340 } 3341 ti.dsymbolSemantic(sc); 3342 if (!ti.inst || ti.errors) 3343 return setError(); 3344 3345 Dsymbol s = ti.toAlias(); 3346 if (s == ti) 3347 { 3348 exp.sds = ti; 3349 exp.type = Type.tvoid; 3350 result = exp; 3351 return; 3352 } 3353 sds2 = s.isScopeDsymbol(); 3354 if (sds2) 3355 { 3356 ti = sds2.isTemplateInstance(); 3357 //printf("+ sds2 = %s, '%s'\n", sds2.kind(), sds2.toChars()); 3358 continue; 3359 } 3360 3361 if (auto v = s.isVarDeclaration()) 3362 { 3363 if (!v.type) 3364 { 3365 exp.error("forward reference of %s `%s`", v.kind(), v.toChars()); 3366 return setError(); 3367 } 3368 if ((v.storage_class & STC.manifest) && v._init) 3369 { 3370 /* When an instance that will be converted to a constant exists, 3371 * the instance representation "foo!tiargs" is treated like a 3372 * variable name, and its recursive appearance check (note that 3373 * it's equivalent with a recursive instantiation of foo) is done 3374 * separately from the circular initialization check for the 3375 * eponymous enum variable declaration. 3376 * 3377 * template foo(T) { 3378 * enum bool foo = foo; // recursive definition check (v.inuse) 3379 * } 3380 * template bar(T) { 3381 * enum bool bar = bar!T; // recursive instantiation check (ti.inuse) 3382 * } 3383 */ 3384 if (ti.inuse) 3385 { 3386 exp.error("recursive expansion of %s `%s`", ti.kind(), ti.toPrettyChars()); 3387 return setError(); 3388 } 3389 v.checkDeprecated(exp.loc, sc); 3390 auto e = v.expandInitializer(exp.loc); 3391 ti.inuse++; 3392 e = e.expressionSemantic(sc); 3393 ti.inuse--; 3394 result = e; 3395 return; 3396 } 3397 } 3398 3399 //printf("s = %s, '%s'\n", s.kind(), s.toChars()); 3400 auto e = symbolToExp(s, exp.loc, sc, true); 3401 //printf("-1ScopeExp::semantic()\n"); 3402 result = e; 3403 return; 3404 } 3405 3406 //printf("sds2 = %s, '%s'\n", sds2.kind(), sds2.toChars()); 3407 //printf("\tparent = '%s'\n", sds2.parent.toChars()); 3408 sds2.dsymbolSemantic(sc); 3409 3410 // (Aggregate|Enum)Declaration 3411 if (auto t = sds2.getType()) 3412 { 3413 result = (new TypeExp(exp.loc, t)).expressionSemantic(sc); 3414 return; 3415 } 3416 3417 if (auto td = sds2.isTemplateDeclaration()) 3418 { 3419 result = (new TemplateExp(exp.loc, td)).expressionSemantic(sc); 3420 return; 3421 } 3422 3423 exp.sds = sds2; 3424 exp.type = Type.tvoid; 3425 //printf("-2ScopeExp::semantic() %s\n", toChars()); 3426 result = exp; 3427 } 3428 3429 override void visit(NewExp exp) 3430 { 3431 static if (LOGSEMANTIC) 3432 { 3433 printf("NewExp::semantic() %s\n", exp.toChars()); 3434 if (exp.thisexp) 3435 printf("\tthisexp = %s\n", exp.thisexp.toChars()); 3436 printf("\tnewtype: %s\n", exp.newtype.toChars()); 3437 } 3438 if (exp.type) // if semantic() already run 3439 { 3440 result = exp; 3441 return; 3442 } 3443 3444 //for error messages if the argument in [] is not convertible to size_t 3445 const originalNewtype = exp.newtype; 3446 3447 // https://issues.dlang.org/show_bug.cgi?id=11581 3448 // With the syntax `new T[edim]` or `thisexp.new T[edim]`, 3449 // T should be analyzed first and edim should go into arguments iff it's 3450 // not a tuple. 3451 Expression edim = null; 3452 if (!exp.arguments && exp.newtype.ty == Tsarray) 3453 { 3454 edim = (cast(TypeSArray)exp.newtype).dim; 3455 exp.newtype = (cast(TypeNext)exp.newtype).next; 3456 } 3457 3458 ClassDeclaration cdthis = null; 3459 if (exp.thisexp) 3460 { 3461 exp.thisexp = exp.thisexp.expressionSemantic(sc); 3462 if (exp.thisexp.op == TOK.error) 3463 return setError(); 3464 3465 cdthis = exp.thisexp.type.isClassHandle(); 3466 if (!cdthis) 3467 { 3468 exp.error("`this` for nested class must be a class type, not `%s`", exp.thisexp.type.toChars()); 3469 return setError(); 3470 } 3471 3472 sc = sc.push(cdthis); 3473 exp.type = exp.newtype.typeSemantic(exp.loc, sc); 3474 sc = sc.pop(); 3475 } 3476 else 3477 { 3478 exp.type = exp.newtype.typeSemantic(exp.loc, sc); 3479 } 3480 if (exp.type.ty == Terror) 3481 return setError(); 3482 3483 if (edim) 3484 { 3485 if (exp.type.toBasetype().ty == Ttuple) 3486 { 3487 // --> new T[edim] 3488 exp.type = new TypeSArray(exp.type, edim); 3489 exp.type = exp.type.typeSemantic(exp.loc, sc); 3490 if (exp.type.ty == Terror) 3491 return setError(); 3492 } 3493 else 3494 { 3495 // --> new T[](edim) 3496 exp.arguments = new Expressions(); 3497 exp.arguments.push(edim); 3498 exp.type = exp.type.arrayOf(); 3499 } 3500 } 3501 3502 exp.newtype = exp.type; // in case type gets cast to something else 3503 Type tb = exp.type.toBasetype(); 3504 //printf("tb: %s, deco = %s\n", tb.toChars(), tb.deco); 3505 if (arrayExpressionSemantic(exp.newargs, sc) || 3506 preFunctionParameters(sc, exp.newargs)) 3507 { 3508 return setError(); 3509 } 3510 if (arrayExpressionSemantic(exp.arguments, sc)) 3511 { 3512 return setError(); 3513 } 3514 //https://issues.dlang.org/show_bug.cgi?id=20547 3515 //exp.arguments are the "parameters" to [], not to a real function 3516 //so the errors that come from preFunctionParameters are misleading 3517 if (originalNewtype.ty == Tsarray) 3518 { 3519 if (preFunctionParameters(sc, exp.arguments, false)) 3520 { 3521 exp.error("cannot create a `%s` with `new`", originalNewtype.toChars()); 3522 return setError(); 3523 } 3524 } 3525 else if (preFunctionParameters(sc, exp.arguments)) 3526 { 3527 return setError(); 3528 } 3529 3530 if (exp.thisexp && tb.ty != Tclass) 3531 { 3532 exp.error("`.new` is only for allocating nested classes, not `%s`", tb.toChars()); 3533 return setError(); 3534 } 3535 3536 const size_t nargs = exp.arguments ? exp.arguments.dim : 0; 3537 Expression newprefix = null; 3538 3539 if (tb.ty == Tclass) 3540 { 3541 auto cd = (cast(TypeClass)tb).sym; 3542 cd.size(exp.loc); 3543 if (cd.sizeok != Sizeok.done) 3544 return setError(); 3545 if (!cd.ctor) 3546 cd.ctor = cd.searchCtor(); 3547 if (cd.noDefaultCtor && !nargs && !cd.defaultCtor) 3548 { 3549 exp.error("default construction is disabled for type `%s`", cd.type.toChars()); 3550 return setError(); 3551 } 3552 3553 if (cd.isInterfaceDeclaration()) 3554 { 3555 exp.error("cannot create instance of interface `%s`", cd.toChars()); 3556 return setError(); 3557 } 3558 3559 if (cd.isAbstract()) 3560 { 3561 exp.error("cannot create instance of abstract class `%s`", cd.toChars()); 3562 for (size_t i = 0; i < cd.vtbl.dim; i++) 3563 { 3564 FuncDeclaration fd = cd.vtbl[i].isFuncDeclaration(); 3565 if (fd && fd.isAbstract()) 3566 { 3567 errorSupplemental(exp.loc, "function `%s` is not implemented", 3568 fd.toFullSignature()); 3569 } 3570 } 3571 return setError(); 3572 } 3573 // checkDeprecated() is already done in newtype.typeSemantic(). 3574 3575 if (cd.isNested()) 3576 { 3577 /* We need a 'this' pointer for the nested class. 3578 * Ensure we have the right one. 3579 */ 3580 Dsymbol s = cd.toParentLocal(); 3581 3582 //printf("cd isNested, parent = %s '%s'\n", s.kind(), s.toPrettyChars()); 3583 if (auto cdn = s.isClassDeclaration()) 3584 { 3585 if (!cdthis) 3586 { 3587 // Supply an implicit 'this' and try again 3588 exp.thisexp = new ThisExp(exp.loc); 3589 for (Dsymbol sp = sc.parent; 1; sp = sp.toParentLocal()) 3590 { 3591 if (!sp) 3592 { 3593 exp.error("outer class `%s` `this` needed to `new` nested class `%s`", 3594 cdn.toChars(), cd.toChars()); 3595 return setError(); 3596 } 3597 ClassDeclaration cdp = sp.isClassDeclaration(); 3598 if (!cdp) 3599 continue; 3600 if (cdp == cdn || cdn.isBaseOf(cdp, null)) 3601 break; 3602 // Add a '.outer' and try again 3603 exp.thisexp = new DotIdExp(exp.loc, exp.thisexp, Id.outer); 3604 } 3605 3606 exp.thisexp = exp.thisexp.expressionSemantic(sc); 3607 if (exp.thisexp.op == TOK.error) 3608 return setError(); 3609 cdthis = exp.thisexp.type.isClassHandle(); 3610 } 3611 if (cdthis != cdn && !cdn.isBaseOf(cdthis, null)) 3612 { 3613 //printf("cdthis = %s\n", cdthis.toChars()); 3614 exp.error("`this` for nested class must be of type `%s`, not `%s`", 3615 cdn.toChars(), exp.thisexp.type.toChars()); 3616 return setError(); 3617 } 3618 if (!MODimplicitConv(exp.thisexp.type.mod, exp.newtype.mod)) 3619 { 3620 exp.error("nested type `%s` should have the same or weaker constancy as enclosing type `%s`", 3621 exp.newtype.toChars(), exp.thisexp.type.toChars()); 3622 return setError(); 3623 } 3624 } 3625 else if (exp.thisexp) 3626 { 3627 exp.error("`.new` is only for allocating nested classes"); 3628 return setError(); 3629 } 3630 else if (auto fdn = s.isFuncDeclaration()) 3631 { 3632 // make sure the parent context fdn of cd is reachable from sc 3633 if (!ensureStaticLinkTo(sc.parent, fdn)) 3634 { 3635 exp.error("outer function context of `%s` is needed to `new` nested class `%s`", 3636 fdn.toPrettyChars(), cd.toPrettyChars()); 3637 return setError(); 3638 } 3639 } 3640 else 3641 assert(0); 3642 } 3643 else if (exp.thisexp) 3644 { 3645 exp.error("`.new` is only for allocating nested classes"); 3646 return setError(); 3647 } 3648 3649 if (cd.vthis2) 3650 { 3651 if (AggregateDeclaration ad2 = cd.isMember2()) 3652 { 3653 Expression te = new ThisExp(exp.loc).expressionSemantic(sc); 3654 if (te.op != TOK.error) 3655 te = getRightThis(exp.loc, sc, ad2, te, cd); 3656 if (te.op == TOK.error) 3657 { 3658 exp.error("need `this` of type `%s` needed to `new` nested class `%s`", ad2.toChars(), cd.toChars()); 3659 return setError(); 3660 } 3661 } 3662 } 3663 3664 if (cd.aggNew) 3665 { 3666 // Prepend the size argument to newargs[] 3667 Expression e = new IntegerExp(exp.loc, cd.size(exp.loc), Type.tsize_t); 3668 if (!exp.newargs) 3669 exp.newargs = new Expressions(); 3670 exp.newargs.shift(e); 3671 3672 FuncDeclaration f = resolveFuncCall(exp.loc, sc, cd.aggNew, null, tb, exp.newargs, FuncResolveFlag.standard); 3673 if (!f || f.errors) 3674 return setError(); 3675 3676 checkFunctionAttributes(exp, sc, f); 3677 checkAccess(cd, exp.loc, sc, f); 3678 3679 TypeFunction tf = cast(TypeFunction)f.type; 3680 Type rettype; 3681 if (functionParameters(exp.loc, sc, tf, null, null, exp.newargs, f, &rettype, &newprefix)) 3682 return setError(); 3683 3684 exp.allocator = f.isNewDeclaration(); 3685 assert(exp.allocator); 3686 } 3687 else 3688 { 3689 if (exp.newargs && exp.newargs.dim) 3690 { 3691 exp.error("no allocator for `%s`", cd.toChars()); 3692 return setError(); 3693 } 3694 } 3695 3696 if (cd.ctor) 3697 { 3698 FuncDeclaration f = resolveFuncCall(exp.loc, sc, cd.ctor, null, tb, exp.arguments, FuncResolveFlag.standard); 3699 if (!f || f.errors) 3700 return setError(); 3701 3702 checkFunctionAttributes(exp, sc, f); 3703 checkAccess(cd, exp.loc, sc, f); 3704 3705 TypeFunction tf = cast(TypeFunction)f.type; 3706 if (!exp.arguments) 3707 exp.arguments = new Expressions(); 3708 if (functionParameters(exp.loc, sc, tf, null, exp.type, exp.arguments, f, &exp.type, &exp.argprefix)) 3709 return setError(); 3710 3711 exp.member = f.isCtorDeclaration(); 3712 assert(exp.member); 3713 } 3714 else 3715 { 3716 if (nargs) 3717 { 3718 exp.error("no constructor for `%s`", cd.toChars()); 3719 return setError(); 3720 } 3721 3722 // https://issues.dlang.org/show_bug.cgi?id=19941 3723 // Run semantic on all field initializers to resolve any forward 3724 // references. This is the same as done for structs in sd.fill(). 3725 for (ClassDeclaration c = cd; c; c = c.baseClass) 3726 { 3727 foreach (v; c.fields) 3728 { 3729 if (v.inuse || v._scope is null || v._init is null || 3730 v._init.isVoidInitializer()) 3731 continue; 3732 v.inuse++; 3733 v._init = v._init.initializerSemantic(v._scope, v.type, INITinterpret); 3734 v.inuse--; 3735 } 3736 } 3737 } 3738 } 3739 else if (tb.ty == Tstruct) 3740 { 3741 auto sd = (cast(TypeStruct)tb).sym; 3742 sd.size(exp.loc); 3743 if (sd.sizeok != Sizeok.done) 3744 return setError(); 3745 if (!sd.ctor) 3746 sd.ctor = sd.searchCtor(); 3747 if (sd.noDefaultCtor && !nargs) 3748 { 3749 exp.error("default construction is disabled for type `%s`", sd.type.toChars()); 3750 return setError(); 3751 } 3752 // checkDeprecated() is already done in newtype.typeSemantic(). 3753 3754 if (sd.aggNew) 3755 { 3756 // Prepend the uint size argument to newargs[] 3757 Expression e = new IntegerExp(exp.loc, sd.size(exp.loc), Type.tsize_t); 3758 if (!exp.newargs) 3759 exp.newargs = new Expressions(); 3760 exp.newargs.shift(e); 3761 3762 FuncDeclaration f = resolveFuncCall(exp.loc, sc, sd.aggNew, null, tb, exp.newargs, FuncResolveFlag.standard); 3763 if (!f || f.errors) 3764 return setError(); 3765 3766 checkFunctionAttributes(exp, sc, f); 3767 checkAccess(sd, exp.loc, sc, f); 3768 3769 TypeFunction tf = cast(TypeFunction)f.type; 3770 Type rettype; 3771 if (functionParameters(exp.loc, sc, tf, null, null, exp.newargs, f, &rettype, &newprefix)) 3772 return setError(); 3773 3774 exp.allocator = f.isNewDeclaration(); 3775 assert(exp.allocator); 3776 } 3777 else 3778 { 3779 if (exp.newargs && exp.newargs.dim) 3780 { 3781 exp.error("no allocator for `%s`", sd.toChars()); 3782 return setError(); 3783 } 3784 } 3785 3786 if (sd.ctor && nargs) 3787 { 3788 FuncDeclaration f = resolveFuncCall(exp.loc, sc, sd.ctor, null, tb, exp.arguments, FuncResolveFlag.standard); 3789 if (!f || f.errors) 3790 return setError(); 3791 3792 checkFunctionAttributes(exp, sc, f); 3793 checkAccess(sd, exp.loc, sc, f); 3794 3795 TypeFunction tf = cast(TypeFunction)f.type; 3796 if (!exp.arguments) 3797 exp.arguments = new Expressions(); 3798 if (functionParameters(exp.loc, sc, tf, null, exp.type, exp.arguments, f, &exp.type, &exp.argprefix)) 3799 return setError(); 3800 3801 exp.member = f.isCtorDeclaration(); 3802 assert(exp.member); 3803 3804 if (checkFrameAccess(exp.loc, sc, sd, sd.fields.dim)) 3805 return setError(); 3806 } 3807 else 3808 { 3809 if (!exp.arguments) 3810 exp.arguments = new Expressions(); 3811 3812 if (!sd.fit(exp.loc, sc, exp.arguments, tb)) 3813 return setError(); 3814 3815 if (!sd.fill(exp.loc, exp.arguments, false)) 3816 return setError(); 3817 3818 if (checkFrameAccess(exp.loc, sc, sd, exp.arguments ? exp.arguments.dim : 0)) 3819 return setError(); 3820 3821 /* Since a `new` allocation may escape, check each of the arguments for escaping 3822 */ 3823 if (global.params.vsafe) 3824 { 3825 foreach (arg; *exp.arguments) 3826 { 3827 if (arg && checkNewEscape(sc, arg, false)) 3828 return setError(); 3829 } 3830 } 3831 } 3832 3833 exp.type = exp.type.pointerTo(); 3834 } 3835 else if (tb.ty == Tarray) 3836 { 3837 if (!nargs) 3838 { 3839 // https://issues.dlang.org/show_bug.cgi?id=20422 3840 // Without this check the compiler would give a misleading error 3841 exp.error("missing length argument for array"); 3842 return setError(); 3843 } 3844 3845 Type tn = tb.nextOf().baseElemOf(); 3846 Dsymbol s = tn.toDsymbol(sc); 3847 AggregateDeclaration ad = s ? s.isAggregateDeclaration() : null; 3848 if (ad && ad.noDefaultCtor) 3849 { 3850 exp.error("default construction is disabled for type `%s`", tb.nextOf().toChars()); 3851 return setError(); 3852 } 3853 for (size_t i = 0; i < nargs; i++) 3854 { 3855 if (tb.ty != Tarray) 3856 { 3857 exp.error("too many arguments for array"); 3858 return setError(); 3859 } 3860 3861 Expression arg = (*exp.arguments)[i]; 3862 arg = resolveProperties(sc, arg); 3863 arg = arg.implicitCastTo(sc, Type.tsize_t); 3864 if (arg.op == TOK.error) 3865 return setError(); 3866 arg = arg.optimize(WANTvalue); 3867 if (arg.op == TOK.int64 && cast(sinteger_t)arg.toInteger() < 0) 3868 { 3869 exp.error("negative array index `%s`", arg.toChars()); 3870 return setError(); 3871 } 3872 (*exp.arguments)[i] = arg; 3873 tb = (cast(TypeDArray)tb).next.toBasetype(); 3874 } 3875 } 3876 else if (tb.isscalar()) 3877 { 3878 if (!nargs) 3879 { 3880 } 3881 else if (nargs == 1) 3882 { 3883 Expression e = (*exp.arguments)[0]; 3884 e = e.implicitCastTo(sc, tb); 3885 (*exp.arguments)[0] = e; 3886 } 3887 else 3888 { 3889 exp.error("more than one argument for construction of `%s`", exp.type.toChars()); 3890 return setError(); 3891 } 3892 3893 exp.type = exp.type.pointerTo(); 3894 } 3895 else 3896 { 3897 exp.error("cannot create a `%s` with `new`", exp.type.toChars()); 3898 return setError(); 3899 } 3900 3901 //printf("NewExp: '%s'\n", toChars()); 3902 //printf("NewExp:type '%s'\n", type.toChars()); 3903 semanticTypeInfo(sc, exp.type); 3904 3905 if (newprefix) 3906 { 3907 result = Expression.combine(newprefix, exp); 3908 return; 3909 } 3910 result = exp; 3911 } 3912 3913 override void visit(NewAnonClassExp e) 3914 { 3915 static if (LOGSEMANTIC) 3916 { 3917 printf("NewAnonClassExp::semantic() %s\n", e.toChars()); 3918 //printf("thisexp = %p\n", thisexp); 3919 //printf("type: %s\n", type.toChars()); 3920 } 3921 3922 Expression d = new DeclarationExp(e.loc, e.cd); 3923 sc = sc.push(); // just create new scope 3924 sc.flags &= ~SCOPE.ctfe; // temporary stop CTFE 3925 d = d.expressionSemantic(sc); 3926 sc = sc.pop(); 3927 3928 if (!e.cd.errors && sc.intypeof && !sc.parent.inNonRoot()) 3929 { 3930 ScopeDsymbol sds = sc.tinst ? cast(ScopeDsymbol)sc.tinst : sc._module; 3931 if (!sds.members) 3932 sds.members = new Dsymbols(); 3933 sds.members.push(e.cd); 3934 } 3935 3936 Expression n = new NewExp(e.loc, e.thisexp, e.newargs, e.cd.type, e.arguments); 3937 3938 Expression c = new CommaExp(e.loc, d, n); 3939 result = c.expressionSemantic(sc); 3940 } 3941 3942 override void visit(SymOffExp e) 3943 { 3944 static if (LOGSEMANTIC) 3945 { 3946 printf("SymOffExp::semantic('%s')\n", e.toChars()); 3947 } 3948 //var.dsymbolSemantic(sc); 3949 if (!e.type) 3950 e.type = e.var.type.pointerTo(); 3951 3952 if (auto v = e.var.isVarDeclaration()) 3953 { 3954 if (v.checkNestedReference(sc, e.loc)) 3955 return setError(); 3956 } 3957 else if (auto f = e.var.isFuncDeclaration()) 3958 { 3959 if (f.checkNestedReference(sc, e.loc)) 3960 return setError(); 3961 } 3962 3963 result = e; 3964 } 3965 3966 override void visit(VarExp e) 3967 { 3968 static if (LOGSEMANTIC) 3969 { 3970 printf("VarExp::semantic(%s)\n", e.toChars()); 3971 } 3972 3973 auto vd = e.var.isVarDeclaration(); 3974 auto fd = e.var.isFuncDeclaration(); 3975 3976 if (fd) 3977 { 3978 //printf("L%d fd = %s\n", __LINE__, f.toChars()); 3979 if (!fd.functionSemantic()) 3980 return setError(); 3981 } 3982 3983 if (!e.type) 3984 e.type = e.var.type; 3985 if (e.type && !e.type.deco) 3986 { 3987 auto decl = e.var.isDeclaration(); 3988 if (decl) 3989 decl.inuse++; 3990 e.type = e.type.typeSemantic(e.loc, sc); 3991 if (decl) 3992 decl.inuse--; 3993 } 3994 3995 /* Fix for 1161 doesn't work because it causes visibility 3996 * problems when instantiating imported templates passing private 3997 * variables as alias template parameters. 3998 */ 3999 //checkAccess(loc, sc, NULL, var); 4000 4001 if (vd) 4002 { 4003 if (vd.checkNestedReference(sc, e.loc)) 4004 return setError(); 4005 4006 // https://issues.dlang.org/show_bug.cgi?id=12025 4007 // If the variable is not actually used in runtime code, 4008 // the purity violation error is redundant. 4009 //checkPurity(sc, vd); 4010 } 4011 else if (fd) 4012 { 4013 // TODO: If fd isn't yet resolved its overload, the checkNestedReference 4014 // call would cause incorrect validation. 4015 // Maybe here should be moved in CallExp, or AddrExp for functions. 4016 if (fd.checkNestedReference(sc, e.loc)) 4017 return setError(); 4018 } 4019 else if (auto od = e.var.isOverDeclaration()) 4020 { 4021 e.type = Type.tvoid; // ambiguous type? 4022 } 4023 4024 result = e; 4025 } 4026 4027 override void visit(FuncExp exp) 4028 { 4029 static if (LOGSEMANTIC) 4030 { 4031 printf("FuncExp::semantic(%s)\n", exp.toChars()); 4032 if (exp.fd.treq) 4033 printf(" treq = %s\n", exp.fd.treq.toChars()); 4034 } 4035 4036 if (exp.type) 4037 { 4038 result = exp; 4039 return; 4040 } 4041 4042 Expression e = exp; 4043 uint olderrors; 4044 4045 sc = sc.push(); // just create new scope 4046 sc.flags &= ~SCOPE.ctfe; // temporary stop CTFE 4047 sc.visibility = Visibility(Visibility.Kind.public_); // https://issues.dlang.org/show_bug.cgi?id=12506 4048 4049 /* fd.treq might be incomplete type, 4050 * so should not semantic it. 4051 * void foo(T)(T delegate(int) dg){} 4052 * foo(a=>a); // in IFTI, treq == T delegate(int) 4053 */ 4054 //if (fd.treq) 4055 // fd.treq = fd.treq.dsymbolSemantic(loc, sc); 4056 4057 exp.genIdent(sc); 4058 4059 // Set target of return type inference 4060 if (exp.fd.treq && !exp.fd.type.nextOf()) 4061 { 4062 TypeFunction tfv = null; 4063 if (exp.fd.treq.ty == Tdelegate || (exp.fd.treq.ty == Tpointer && exp.fd.treq.nextOf().ty == Tfunction)) 4064 tfv = cast(TypeFunction)exp.fd.treq.nextOf(); 4065 if (tfv) 4066 { 4067 TypeFunction tfl = cast(TypeFunction)exp.fd.type; 4068 tfl.next = tfv.nextOf(); 4069 } 4070 } 4071 4072 //printf("td = %p, treq = %p\n", td, fd.treq); 4073 if (exp.td) 4074 { 4075 assert(exp.td.parameters && exp.td.parameters.dim); 4076 exp.td.dsymbolSemantic(sc); 4077 exp.type = Type.tvoid; // temporary type 4078 4079 if (exp.fd.treq) // defer type determination 4080 { 4081 FuncExp fe; 4082 if (exp.matchType(exp.fd.treq, sc, &fe) > MATCH.nomatch) 4083 e = fe; 4084 else 4085 e = ErrorExp.get(); 4086 } 4087 goto Ldone; 4088 } 4089 4090 olderrors = global.errors; 4091 exp.fd.dsymbolSemantic(sc); 4092 if (olderrors == global.errors) 4093 { 4094 exp.fd.semantic2(sc); 4095 if (olderrors == global.errors) 4096 exp.fd.semantic3(sc); 4097 } 4098 if (olderrors != global.errors) 4099 { 4100 if (exp.fd.type && exp.fd.type.ty == Tfunction && !exp.fd.type.nextOf()) 4101 (cast(TypeFunction)exp.fd.type).next = Type.terror; 4102 e = ErrorExp.get(); 4103 goto Ldone; 4104 } 4105 4106 // Type is a "delegate to" or "pointer to" the function literal 4107 if ((exp.fd.isNested() && exp.fd.tok == TOK.delegate_) || (exp.tok == TOK.reserved && exp.fd.treq && exp.fd.treq.ty == Tdelegate)) 4108 { 4109 exp.type = new TypeDelegate(exp.fd.type); 4110 exp.type = exp.type.typeSemantic(exp.loc, sc); 4111 4112 exp.fd.tok = TOK.delegate_; 4113 } 4114 else 4115 { 4116 exp.type = new TypePointer(exp.fd.type); 4117 exp.type = exp.type.typeSemantic(exp.loc, sc); 4118 //type = fd.type.pointerTo(); 4119 4120 /* A lambda expression deduced to function pointer might become 4121 * to a delegate literal implicitly. 4122 * 4123 * auto foo(void function() fp) { return 1; } 4124 * assert(foo({}) == 1); 4125 * 4126 * So, should keep fd.tok == TOKreserve if fd.treq == NULL. 4127 */ 4128 if (exp.fd.treq && exp.fd.treq.ty == Tpointer) 4129 { 4130 // change to non-nested 4131 exp.fd.tok = TOK.function_; 4132 exp.fd.vthis = null; 4133 } 4134 } 4135 exp.fd.tookAddressOf++; 4136 4137 Ldone: 4138 sc = sc.pop(); 4139 result = e; 4140 } 4141 4142 /** 4143 * Perform semantic analysis on function literals 4144 * 4145 * Test the following construct: 4146 * --- 4147 * (x, y, z) { return x + y + z; }(42, 84, 1992); 4148 * --- 4149 */ 4150 Expression callExpSemantic(FuncExp exp, Scope* sc, Expressions* arguments) 4151 { 4152 if ((!exp.type || exp.type == Type.tvoid) && exp.td && arguments && arguments.dim) 4153 { 4154 for (size_t k = 0; k < arguments.dim; k++) 4155 { 4156 Expression checkarg = (*arguments)[k]; 4157 if (checkarg.op == TOK.error) 4158 return checkarg; 4159 } 4160 4161 exp.genIdent(sc); 4162 4163 assert(exp.td.parameters && exp.td.parameters.dim); 4164 exp.td.dsymbolSemantic(sc); 4165 4166 TypeFunction tfl = cast(TypeFunction)exp.fd.type; 4167 size_t dim = tfl.parameterList.length; 4168 if (arguments.dim < dim) 4169 { 4170 // Default arguments are always typed, so they don't need inference. 4171 Parameter p = tfl.parameterList[arguments.dim]; 4172 if (p.defaultArg) 4173 dim = arguments.dim; 4174 } 4175 4176 if ((tfl.parameterList.varargs == VarArg.none && arguments.dim > dim) || 4177 arguments.dim < dim) 4178 { 4179 OutBuffer buf; 4180 foreach (idx, ref arg; *arguments) 4181 buf.printf("%s%s", (idx ? ", ".ptr : "".ptr), arg.type.toChars()); 4182 exp.error("function literal `%s%s` is not callable using argument types `(%s)`", 4183 exp.fd.toChars(), parametersTypeToChars(tfl.parameterList), 4184 buf.peekChars()); 4185 exp.errorSupplemental("too %s arguments, expected `%d`, got `%d`", 4186 arguments.dim < dim ? "few".ptr : "many".ptr, 4187 cast(int)dim, cast(int)arguments.dim); 4188 return ErrorExp.get(); 4189 } 4190 4191 auto tiargs = new Objects(); 4192 tiargs.reserve(exp.td.parameters.dim); 4193 4194 for (size_t i = 0; i < exp.td.parameters.dim; i++) 4195 { 4196 TemplateParameter tp = (*exp.td.parameters)[i]; 4197 assert(dim <= tfl.parameterList.length); 4198 foreach (u, p; tfl.parameterList) 4199 { 4200 if (u == dim) 4201 break; 4202 4203 if (p.type.ty == Tident && (cast(TypeIdentifier)p.type).ident == tp.ident) 4204 { 4205 Expression e = (*arguments)[u]; 4206 tiargs.push(e.type); 4207 break; 4208 } 4209 } 4210 } 4211 4212 auto ti = new TemplateInstance(exp.loc, exp.td, tiargs); 4213 return (new ScopeExp(exp.loc, ti)).expressionSemantic(sc); 4214 } 4215 return exp.expressionSemantic(sc); 4216 } 4217 4218 override void visit(CallExp exp) 4219 { 4220 static if (LOGSEMANTIC) 4221 { 4222 printf("CallExp::semantic() %s\n", exp.toChars()); 4223 } 4224 if (exp.type) 4225 { 4226 result = exp; 4227 return; // semantic() already run 4228 } 4229 4230 Objects* tiargs = null; // initial list of template arguments 4231 Expression ethis = null; 4232 Type tthis = null; 4233 Expression e1org = exp.e1; 4234 4235 if (exp.e1.op == TOK.comma) 4236 { 4237 /* Rewrite (a,b)(args) as (a,(b(args))) 4238 */ 4239 auto ce = cast(CommaExp)exp.e1; 4240 exp.e1 = ce.e2; 4241 ce.e2 = exp; 4242 result = ce.expressionSemantic(sc); 4243 return; 4244 } 4245 if (exp.e1.op == TOK.delegate_) 4246 { 4247 DelegateExp de = cast(DelegateExp)exp.e1; 4248 exp.e1 = new DotVarExp(de.loc, de.e1, de.func, de.hasOverloads); 4249 visit(exp); 4250 return; 4251 } 4252 if (exp.e1.op == TOK.function_) 4253 { 4254 if (arrayExpressionSemantic(exp.arguments, sc) || preFunctionParameters(sc, exp.arguments)) 4255 return setError(); 4256 4257 // Run e1 semantic even if arguments have any errors 4258 FuncExp fe = cast(FuncExp)exp.e1; 4259 exp.e1 = callExpSemantic(fe, sc, exp.arguments); 4260 if (exp.e1.op == TOK.error) 4261 { 4262 result = exp.e1; 4263 return; 4264 } 4265 } 4266 4267 if (Expression ex = resolveUFCS(sc, exp)) 4268 { 4269 result = ex; 4270 return; 4271 } 4272 4273 /* This recognizes: 4274 * foo!(tiargs)(funcargs) 4275 */ 4276 if (exp.e1.op == TOK.scope_) 4277 { 4278 ScopeExp se = cast(ScopeExp)exp.e1; 4279 TemplateInstance ti = se.sds.isTemplateInstance(); 4280 if (ti) 4281 { 4282 /* Attempt to instantiate ti. If that works, go with it. 4283 * If not, go with partial explicit specialization. 4284 */ 4285 WithScopeSymbol withsym; 4286 if (!ti.findTempDecl(sc, &withsym) || !ti.semanticTiargs(sc)) 4287 return setError(); 4288 if (withsym && withsym.withstate.wthis) 4289 { 4290 exp.e1 = new VarExp(exp.e1.loc, withsym.withstate.wthis); 4291 exp.e1 = new DotTemplateInstanceExp(exp.e1.loc, exp.e1, ti); 4292 goto Ldotti; 4293 } 4294 if (ti.needsTypeInference(sc, 1)) 4295 { 4296 /* Go with partial explicit specialization 4297 */ 4298 tiargs = ti.tiargs; 4299 assert(ti.tempdecl); 4300 if (TemplateDeclaration td = ti.tempdecl.isTemplateDeclaration()) 4301 exp.e1 = new TemplateExp(exp.loc, td); 4302 else if (OverDeclaration od = ti.tempdecl.isOverDeclaration()) 4303 exp.e1 = new VarExp(exp.loc, od); 4304 else 4305 exp.e1 = new OverExp(exp.loc, ti.tempdecl.isOverloadSet()); 4306 } 4307 else 4308 { 4309 Expression e1x = exp.e1.expressionSemantic(sc); 4310 if (e1x.op == TOK.error) 4311 { 4312 result = e1x; 4313 return; 4314 } 4315 exp.e1 = e1x; 4316 } 4317 } 4318 } 4319 4320 /* This recognizes: 4321 * expr.foo!(tiargs)(funcargs) 4322 */ 4323 Ldotti: 4324 if (exp.e1.op == TOK.dotTemplateInstance && !exp.e1.type) 4325 { 4326 DotTemplateInstanceExp se = cast(DotTemplateInstanceExp)exp.e1; 4327 TemplateInstance ti = se.ti; 4328 { 4329 /* Attempt to instantiate ti. If that works, go with it. 4330 * If not, go with partial explicit specialization. 4331 */ 4332 if (!se.findTempDecl(sc) || !ti.semanticTiargs(sc)) 4333 return setError(); 4334 if (ti.needsTypeInference(sc, 1)) 4335 { 4336 /* Go with partial explicit specialization 4337 */ 4338 tiargs = ti.tiargs; 4339 assert(ti.tempdecl); 4340 if (TemplateDeclaration td = ti.tempdecl.isTemplateDeclaration()) 4341 exp.e1 = new DotTemplateExp(exp.loc, se.e1, td); 4342 else if (OverDeclaration od = ti.tempdecl.isOverDeclaration()) 4343 { 4344 exp.e1 = new DotVarExp(exp.loc, se.e1, od, true); 4345 } 4346 else 4347 exp.e1 = new DotExp(exp.loc, se.e1, new OverExp(exp.loc, ti.tempdecl.isOverloadSet())); 4348 } 4349 else 4350 { 4351 Expression e1x = exp.e1.expressionSemantic(sc); 4352 if (e1x.op == TOK.error) 4353 { 4354 result = e1x; 4355 return; 4356 } 4357 exp.e1 = e1x; 4358 } 4359 } 4360 } 4361 4362 Lagain: 4363 //printf("Lagain: %s\n", toChars()); 4364 exp.f = null; 4365 if (exp.e1.op == TOK.this_ || exp.e1.op == TOK.super_) 4366 { 4367 // semantic() run later for these 4368 } 4369 else 4370 { 4371 if (exp.e1.op == TOK.dotIdentifier) 4372 { 4373 DotIdExp die = cast(DotIdExp)exp.e1; 4374 exp.e1 = die.expressionSemantic(sc); 4375 /* Look for e1 having been rewritten to expr.opDispatch!(string) 4376 * We handle such earlier, so go back. 4377 * Note that in the rewrite, we carefully did not run semantic() on e1 4378 */ 4379 if (exp.e1.op == TOK.dotTemplateInstance && !exp.e1.type) 4380 { 4381 goto Ldotti; 4382 } 4383 } 4384 else 4385 { 4386 __gshared int nest; 4387 if (++nest > global.recursionLimit) 4388 { 4389 exp.error("recursive evaluation of `%s`", exp.toChars()); 4390 --nest; 4391 return setError(); 4392 } 4393 Expression ex = unaSemantic(exp, sc); 4394 --nest; 4395 if (ex) 4396 { 4397 result = ex; 4398 return; 4399 } 4400 } 4401 4402 /* Look for e1 being a lazy parameter 4403 */ 4404 if (exp.e1.op == TOK.variable) 4405 { 4406 VarExp ve = cast(VarExp)exp.e1; 4407 if (ve.var.storage_class & STC.lazy_) 4408 { 4409 // lazy parameters can be called without violating purity and safety 4410 Type tw = ve.var.type; 4411 Type tc = ve.var.type.substWildTo(MODFlags.const_); 4412 auto tf = new TypeFunction(ParameterList(), tc, LINK.d, STC.safe | STC.pure_); 4413 (tf = cast(TypeFunction)tf.typeSemantic(exp.loc, sc)).next = tw; // hack for bug7757 4414 auto t = new TypeDelegate(tf); 4415 ve.type = t.typeSemantic(exp.loc, sc); 4416 } 4417 VarDeclaration v = ve.var.isVarDeclaration(); 4418 if (v && ve.checkPurity(sc, v)) 4419 return setError(); 4420 } 4421 4422 if (exp.e1.op == TOK.symbolOffset && (cast(SymOffExp)exp.e1).hasOverloads) 4423 { 4424 SymOffExp se = cast(SymOffExp)exp.e1; 4425 exp.e1 = new VarExp(se.loc, se.var, true); 4426 exp.e1 = exp.e1.expressionSemantic(sc); 4427 } 4428 else if (exp.e1.op == TOK.dot) 4429 { 4430 DotExp de = cast(DotExp)exp.e1; 4431 4432 if (de.e2.op == TOK.overloadSet) 4433 { 4434 ethis = de.e1; 4435 tthis = de.e1.type; 4436 exp.e1 = de.e2; 4437 } 4438 } 4439 else if (exp.e1.op == TOK.star && exp.e1.type.ty == Tfunction) 4440 { 4441 // Rewrite (*fp)(arguments) to fp(arguments) 4442 exp.e1 = (cast(PtrExp)exp.e1).e1; 4443 } 4444 } 4445 4446 Type t1 = exp.e1.type ? exp.e1.type.toBasetype() : null; 4447 4448 if (exp.e1.op == TOK.error) 4449 { 4450 result = exp.e1; 4451 return; 4452 } 4453 if (arrayExpressionSemantic(exp.arguments, sc) || preFunctionParameters(sc, exp.arguments)) 4454 return setError(); 4455 4456 // Check for call operator overload 4457 if (t1) 4458 { 4459 if (t1.ty == Tstruct) 4460 { 4461 auto sd = (cast(TypeStruct)t1).sym; 4462 sd.size(exp.loc); // Resolve forward references to construct object 4463 if (sd.sizeok != Sizeok.done) 4464 return setError(); 4465 if (!sd.ctor) 4466 sd.ctor = sd.searchCtor(); 4467 /* If `sd.ctor` is a generated copy constructor, this means that it 4468 is the single constructor that this struct has. In order to not 4469 disable default construction, the ctor is nullified. The side effect 4470 of this is that the generated copy constructor cannot be called 4471 explicitly, but that is ok, because when calling a constructor the 4472 default constructor should have priority over the generated copy 4473 constructor. 4474 */ 4475 if (sd.ctor) 4476 { 4477 auto ctor = sd.ctor.isCtorDeclaration(); 4478 if (ctor && ctor.isCpCtor && ctor.generated) 4479 sd.ctor = null; 4480 } 4481 4482 // First look for constructor 4483 if (exp.e1.op == TOK.type && sd.ctor) 4484 { 4485 if (!sd.noDefaultCtor && !(exp.arguments && exp.arguments.dim)) 4486 goto Lx; 4487 4488 /* https://issues.dlang.org/show_bug.cgi?id=20695 4489 If all constructors are copy constructors, then 4490 try default construction. 4491 */ 4492 if (!sd.hasRegularCtor) 4493 goto Lx; 4494 4495 auto sle = new StructLiteralExp(exp.loc, sd, null, exp.e1.type); 4496 if (!sd.fill(exp.loc, sle.elements, true)) 4497 return setError(); 4498 if (checkFrameAccess(exp.loc, sc, sd, sle.elements.dim)) 4499 return setError(); 4500 4501 // https://issues.dlang.org/show_bug.cgi?id=14556 4502 // Set concrete type to avoid further redundant semantic(). 4503 sle.type = exp.e1.type; 4504 4505 /* Constructor takes a mutable object, so don't use 4506 * the immutable initializer symbol. 4507 */ 4508 sle.useStaticInit = false; 4509 4510 Expression e = sle; 4511 if (auto cf = sd.ctor.isCtorDeclaration()) 4512 { 4513 e = new DotVarExp(exp.loc, e, cf, true); 4514 } 4515 else if (auto td = sd.ctor.isTemplateDeclaration()) 4516 { 4517 e = new DotIdExp(exp.loc, e, td.ident); 4518 } 4519 else if (auto os = sd.ctor.isOverloadSet()) 4520 { 4521 e = new DotExp(exp.loc, e, new OverExp(exp.loc, os)); 4522 } 4523 else 4524 assert(0); 4525 e = new CallExp(exp.loc, e, exp.arguments); 4526 e = e.expressionSemantic(sc); 4527 result = e; 4528 return; 4529 } 4530 // No constructor, look for overload of opCall 4531 if (search_function(sd, Id.call)) 4532 goto L1; 4533 // overload of opCall, therefore it's a call 4534 if (exp.e1.op != TOK.type) 4535 { 4536 if (sd.aliasthis && !(exp.att1 && exp.e1.type.equivalent(exp.att1))) 4537 { 4538 if (!exp.att1 && exp.e1.type.checkAliasThisRec()) 4539 exp.att1 = exp.e1.type; 4540 exp.e1 = resolveAliasThis(sc, exp.e1); 4541 goto Lagain; 4542 } 4543 exp.error("%s `%s` does not overload ()", sd.kind(), sd.toChars()); 4544 return setError(); 4545 } 4546 4547 /* It's a struct literal 4548 */ 4549 Lx: 4550 Expression e = new StructLiteralExp(exp.loc, sd, exp.arguments, exp.e1.type); 4551 e = e.expressionSemantic(sc); 4552 result = e; 4553 return; 4554 } 4555 else if (t1.ty == Tclass) 4556 { 4557 L1: 4558 // Rewrite as e1.call(arguments) 4559 Expression e = new DotIdExp(exp.loc, exp.e1, Id.call); 4560 e = new CallExp(exp.loc, e, exp.arguments); 4561 e = e.expressionSemantic(sc); 4562 result = e; 4563 return; 4564 } 4565 else if (exp.e1.op == TOK.type && t1.isscalar()) 4566 { 4567 Expression e; 4568 4569 // Make sure to use the the enum type itself rather than its 4570 // base type 4571 // https://issues.dlang.org/show_bug.cgi?id=16346 4572 if (exp.e1.type.ty == Tenum) 4573 { 4574 t1 = exp.e1.type; 4575 } 4576 4577 if (!exp.arguments || exp.arguments.dim == 0) 4578 { 4579 e = t1.defaultInitLiteral(exp.loc); 4580 } 4581 else if (exp.arguments.dim == 1) 4582 { 4583 e = (*exp.arguments)[0]; 4584 e = e.implicitCastTo(sc, t1); 4585 e = new CastExp(exp.loc, e, t1); 4586 } 4587 else 4588 { 4589 exp.error("more than one argument for construction of `%s`", t1.toChars()); 4590 return setError(); 4591 } 4592 e = e.expressionSemantic(sc); 4593 result = e; 4594 return; 4595 } 4596 } 4597 4598 static FuncDeclaration resolveOverloadSet(Loc loc, Scope* sc, 4599 OverloadSet os, Objects* tiargs, Type tthis, Expressions* arguments) 4600 { 4601 FuncDeclaration f = null; 4602 foreach (s; os.a) 4603 { 4604 if (tiargs && s.isFuncDeclaration()) 4605 continue; 4606 if (auto f2 = resolveFuncCall(loc, sc, s, tiargs, tthis, arguments, FuncResolveFlag.quiet)) 4607 { 4608 if (f2.errors) 4609 return null; 4610 if (f) 4611 { 4612 /* Error if match in more than one overload set, 4613 * even if one is a 'better' match than the other. 4614 */ 4615 ScopeDsymbol.multiplyDefined(loc, f, f2); 4616 } 4617 else 4618 f = f2; 4619 } 4620 } 4621 if (!f) 4622 .error(loc, "no overload matches for `%s`", os.toChars()); 4623 else if (f.errors) 4624 f = null; 4625 return f; 4626 } 4627 4628 bool isSuper = false; 4629 if (exp.e1.op == TOK.dotVariable && t1.ty == Tfunction || exp.e1.op == TOK.dotTemplateDeclaration) 4630 { 4631 UnaExp ue = cast(UnaExp)exp.e1; 4632 4633 Expression ue1 = ue.e1; 4634 Expression ue1old = ue1; // need for 'right this' check 4635 VarDeclaration v; 4636 if (ue1.op == TOK.variable && (v = (cast(VarExp)ue1).var.isVarDeclaration()) !is null && v.needThis()) 4637 { 4638 ue.e1 = new TypeExp(ue1.loc, ue1.type); 4639 ue1 = null; 4640 } 4641 4642 DotVarExp dve; 4643 DotTemplateExp dte; 4644 Dsymbol s; 4645 if (exp.e1.op == TOK.dotVariable) 4646 { 4647 dve = cast(DotVarExp)exp.e1; 4648 dte = null; 4649 s = dve.var; 4650 tiargs = null; 4651 } 4652 else 4653 { 4654 dve = null; 4655 dte = cast(DotTemplateExp)exp.e1; 4656 s = dte.td; 4657 } 4658 4659 // Do overload resolution 4660 exp.f = resolveFuncCall(exp.loc, sc, s, tiargs, ue1 ? ue1.type : null, exp.arguments, FuncResolveFlag.standard); 4661 if (!exp.f || exp.f.errors || exp.f.type.ty == Terror) 4662 return setError(); 4663 4664 if (exp.f.interfaceVirtual) 4665 { 4666 /* Cast 'this' to the type of the interface, and replace f with the interface's equivalent 4667 */ 4668 auto b = exp.f.interfaceVirtual; 4669 auto ad2 = b.sym; 4670 ue.e1 = ue.e1.castTo(sc, ad2.type.addMod(ue.e1.type.mod)); 4671 ue.e1 = ue.e1.expressionSemantic(sc); 4672 ue1 = ue.e1; 4673 auto vi = exp.f.findVtblIndex(&ad2.vtbl, cast(int)ad2.vtbl.dim); 4674 assert(vi >= 0); 4675 exp.f = ad2.vtbl[vi].isFuncDeclaration(); 4676 assert(exp.f); 4677 } 4678 if (exp.f.needThis()) 4679 { 4680 AggregateDeclaration ad = exp.f.toParentLocal().isAggregateDeclaration(); 4681 ue.e1 = getRightThis(exp.loc, sc, ad, ue.e1, exp.f); 4682 if (ue.e1.op == TOK.error) 4683 { 4684 result = ue.e1; 4685 return; 4686 } 4687 ethis = ue.e1; 4688 tthis = ue.e1.type; 4689 if (!(exp.f.type.ty == Tfunction && (cast(TypeFunction)exp.f.type).isScopeQual)) 4690 { 4691 if (global.params.vsafe && checkParamArgumentEscape(sc, exp.f, null, ethis, false, false)) 4692 return setError(); 4693 } 4694 } 4695 4696 /* Cannot call public functions from inside invariant 4697 * (because then the invariant would have infinite recursion) 4698 */ 4699 if (sc.func && sc.func.isInvariantDeclaration() && ue.e1.op == TOK.this_ && exp.f.addPostInvariant()) 4700 { 4701 exp.error("cannot call `public`/`export` function `%s` from invariant", exp.f.toChars()); 4702 return setError(); 4703 } 4704 4705 if (!exp.ignoreAttributes) 4706 checkFunctionAttributes(exp, sc, exp.f); 4707 checkAccess(exp.loc, sc, ue.e1, exp.f); 4708 if (!exp.f.needThis()) 4709 { 4710 exp.e1 = Expression.combine(ue.e1, new VarExp(exp.loc, exp.f, false)); 4711 } 4712 else 4713 { 4714 if (ue1old.checkRightThis(sc)) 4715 return setError(); 4716 if (exp.e1.op == TOK.dotVariable) 4717 { 4718 dve.var = exp.f; 4719 exp.e1.type = exp.f.type; 4720 } 4721 else 4722 { 4723 exp.e1 = new DotVarExp(exp.loc, dte.e1, exp.f, false); 4724 exp.e1 = exp.e1.expressionSemantic(sc); 4725 if (exp.e1.op == TOK.error) 4726 return setError(); 4727 ue = cast(UnaExp)exp.e1; 4728 } 4729 version (none) 4730 { 4731 printf("ue.e1 = %s\n", ue.e1.toChars()); 4732 printf("f = %s\n", exp.f.toChars()); 4733 printf("t1 = %s\n", t1.toChars()); 4734 printf("e1 = %s\n", exp.e1.toChars()); 4735 printf("e1.type = %s\n", exp.e1.type.toChars()); 4736 } 4737 4738 // See if we need to adjust the 'this' pointer 4739 AggregateDeclaration ad = exp.f.isThis(); 4740 ClassDeclaration cd = ue.e1.type.isClassHandle(); 4741 if (ad && cd && ad.isClassDeclaration()) 4742 { 4743 if (ue.e1.op == TOK.dotType) 4744 { 4745 ue.e1 = (cast(DotTypeExp)ue.e1).e1; 4746 exp.directcall = true; 4747 } 4748 else if (ue.e1.op == TOK.super_) 4749 exp.directcall = true; 4750 else if ((cd.storage_class & STC.final_) != 0) // https://issues.dlang.org/show_bug.cgi?id=14211 4751 exp.directcall = true; 4752 4753 if (ad != cd) 4754 { 4755 ue.e1 = ue.e1.castTo(sc, ad.type.addMod(ue.e1.type.mod)); 4756 ue.e1 = ue.e1.expressionSemantic(sc); 4757 } 4758 } 4759 } 4760 // If we've got a pointer to a function then deference it 4761 // https://issues.dlang.org/show_bug.cgi?id=16483 4762 if (exp.e1.type.ty == Tpointer && exp.e1.type.nextOf().ty == Tfunction) 4763 { 4764 Expression e = new PtrExp(exp.loc, exp.e1); 4765 e.type = exp.e1.type.nextOf(); 4766 exp.e1 = e; 4767 } 4768 t1 = exp.e1.type; 4769 } 4770 else if (exp.e1.op == TOK.super_ || exp.e1.op == TOK.this_) 4771 { 4772 auto ad = sc.func ? sc.func.isThis() : null; 4773 auto cd = ad ? ad.isClassDeclaration() : null; 4774 4775 isSuper = exp.e1.op == TOK.super_; 4776 if (isSuper) 4777 { 4778 // Base class constructor call 4779 if (!cd || !cd.baseClass || !sc.func.isCtorDeclaration()) 4780 { 4781 exp.error("super class constructor call must be in a constructor"); 4782 return setError(); 4783 } 4784 if (!cd.baseClass.ctor) 4785 { 4786 exp.error("no super class constructor for `%s`", cd.baseClass.toChars()); 4787 return setError(); 4788 } 4789 } 4790 else 4791 { 4792 // `this` call expression must be inside a 4793 // constructor 4794 if (!ad || !sc.func.isCtorDeclaration()) 4795 { 4796 exp.error("constructor call must be in a constructor"); 4797 return setError(); 4798 } 4799 4800 // https://issues.dlang.org/show_bug.cgi?id=18719 4801 // If `exp` is a call expression to another constructor 4802 // then it means that all struct/class fields will be 4803 // initialized after this call. 4804 foreach (ref field; sc.ctorflow.fieldinit) 4805 { 4806 field.csx |= CSX.this_ctor; 4807 } 4808 } 4809 4810 if (!sc.intypeof && !(sc.ctorflow.callSuper & CSX.halt)) 4811 { 4812 if (sc.inLoop || sc.ctorflow.callSuper & CSX.label) 4813 exp.error("constructor calls not allowed in loops or after labels"); 4814 if (sc.ctorflow.callSuper & (CSX.super_ctor | CSX.this_ctor)) 4815 exp.error("multiple constructor calls"); 4816 if ((sc.ctorflow.callSuper & CSX.return_) && !(sc.ctorflow.callSuper & CSX.any_ctor)) 4817 exp.error("an earlier `return` statement skips constructor"); 4818 sc.ctorflow.callSuper |= CSX.any_ctor | (isSuper ? CSX.super_ctor : CSX.this_ctor); 4819 } 4820 4821 tthis = ad.type.addMod(sc.func.type.mod); 4822 auto ctor = isSuper ? cd.baseClass.ctor : ad.ctor; 4823 if (auto os = ctor.isOverloadSet()) 4824 exp.f = resolveOverloadSet(exp.loc, sc, os, null, tthis, exp.arguments); 4825 else 4826 exp.f = resolveFuncCall(exp.loc, sc, ctor, null, tthis, exp.arguments, FuncResolveFlag.standard); 4827 4828 if (!exp.f || exp.f.errors) 4829 return setError(); 4830 4831 checkFunctionAttributes(exp, sc, exp.f); 4832 checkAccess(exp.loc, sc, null, exp.f); 4833 4834 exp.e1 = new DotVarExp(exp.e1.loc, exp.e1, exp.f, false); 4835 exp.e1 = exp.e1.expressionSemantic(sc); 4836 // https://issues.dlang.org/show_bug.cgi?id=21095 4837 if (exp.e1.op == TOK.error) 4838 return setError(); 4839 t1 = exp.e1.type; 4840 4841 // BUG: this should really be done by checking the static 4842 // call graph 4843 if (exp.f == sc.func) 4844 { 4845 exp.error("cyclic constructor call"); 4846 return setError(); 4847 } 4848 } 4849 else if (exp.e1.op == TOK.overloadSet) 4850 { 4851 auto os = (cast(OverExp)exp.e1).vars; 4852 exp.f = resolveOverloadSet(exp.loc, sc, os, tiargs, tthis, exp.arguments); 4853 if (!exp.f) 4854 return setError(); 4855 if (ethis) 4856 exp.e1 = new DotVarExp(exp.loc, ethis, exp.f, false); 4857 else 4858 exp.e1 = new VarExp(exp.loc, exp.f, false); 4859 goto Lagain; 4860 } 4861 else if (!t1) 4862 { 4863 exp.error("function expected before `()`, not `%s`", exp.e1.toChars()); 4864 return setError(); 4865 } 4866 else if (t1.ty == Terror) 4867 { 4868 return setError(); 4869 } 4870 else if (t1.ty != Tfunction) 4871 { 4872 TypeFunction tf; 4873 const(char)* p; 4874 Dsymbol s; 4875 exp.f = null; 4876 if (exp.e1.op == TOK.function_) 4877 { 4878 // function literal that direct called is always inferred. 4879 assert((cast(FuncExp)exp.e1).fd); 4880 exp.f = (cast(FuncExp)exp.e1).fd; 4881 tf = cast(TypeFunction)exp.f.type; 4882 p = "function literal"; 4883 } 4884 else if (t1.ty == Tdelegate) 4885 { 4886 TypeDelegate td = cast(TypeDelegate)t1; 4887 assert(td.next.ty == Tfunction); 4888 tf = cast(TypeFunction)td.next; 4889 p = "delegate"; 4890 } 4891 else if (t1.ty == Tpointer && (cast(TypePointer)t1).next.ty == Tfunction) 4892 { 4893 tf = cast(TypeFunction)(cast(TypePointer)t1).next; 4894 p = "function pointer"; 4895 } 4896 else if (exp.e1.op == TOK.dotVariable && (cast(DotVarExp)exp.e1).var.isOverDeclaration()) 4897 { 4898 DotVarExp dve = cast(DotVarExp)exp.e1; 4899 exp.f = resolveFuncCall(exp.loc, sc, dve.var, tiargs, dve.e1.type, exp.arguments, FuncResolveFlag.overloadOnly); 4900 if (!exp.f) 4901 return setError(); 4902 if (exp.f.needThis()) 4903 { 4904 dve.var = exp.f; 4905 dve.type = exp.f.type; 4906 dve.hasOverloads = false; 4907 goto Lagain; 4908 } 4909 exp.e1 = new VarExp(dve.loc, exp.f, false); 4910 Expression e = new CommaExp(exp.loc, dve.e1, exp); 4911 result = e.expressionSemantic(sc); 4912 return; 4913 } 4914 else if (exp.e1.op == TOK.variable && (cast(VarExp)exp.e1).var.isOverDeclaration()) 4915 { 4916 s = (cast(VarExp)exp.e1).var; 4917 goto L2; 4918 } 4919 else if (exp.e1.op == TOK.template_) 4920 { 4921 s = (cast(TemplateExp)exp.e1).td; 4922 L2: 4923 exp.f = resolveFuncCall(exp.loc, sc, s, tiargs, null, exp.arguments, FuncResolveFlag.standard); 4924 if (!exp.f || exp.f.errors) 4925 return setError(); 4926 if (exp.f.needThis()) 4927 { 4928 if (hasThis(sc)) 4929 { 4930 // Supply an implicit 'this', as in 4931 // this.ident 4932 exp.e1 = new DotVarExp(exp.loc, (new ThisExp(exp.loc)).expressionSemantic(sc), exp.f, false); 4933 goto Lagain; 4934 } 4935 else if (isNeedThisScope(sc, exp.f)) 4936 { 4937 exp.error("need `this` for `%s` of type `%s`", exp.f.toChars(), exp.f.type.toChars()); 4938 return setError(); 4939 } 4940 } 4941 exp.e1 = new VarExp(exp.e1.loc, exp.f, false); 4942 goto Lagain; 4943 } 4944 else 4945 { 4946 exp.error("function expected before `()`, not `%s` of type `%s`", exp.e1.toChars(), exp.e1.type.toChars()); 4947 return setError(); 4948 } 4949 4950 const(char)* failMessage; 4951 Expression[] fargs = exp.arguments ? (*exp.arguments)[] : null; 4952 if (!tf.callMatch(null, fargs, 0, &failMessage, sc)) 4953 { 4954 OutBuffer buf; 4955 buf.writeByte('('); 4956 argExpTypesToCBuffer(&buf, exp.arguments); 4957 buf.writeByte(')'); 4958 if (tthis) 4959 tthis.modToBuffer(&buf); 4960 4961 //printf("tf = %s, args = %s\n", tf.deco, (*arguments)[0].type.deco); 4962 .error(exp.loc, "%s `%s%s` is not callable using argument types `%s`", 4963 p, exp.e1.toChars(), parametersTypeToChars(tf.parameterList), buf.peekChars()); 4964 if (failMessage) 4965 errorSupplemental(exp.loc, "%s", failMessage); 4966 return setError(); 4967 } 4968 // Purity and safety check should run after testing arguments matching 4969 if (exp.f) 4970 { 4971 exp.checkPurity(sc, exp.f); 4972 exp.checkSafety(sc, exp.f); 4973 exp.checkNogc(sc, exp.f); 4974 if (exp.f.checkNestedReference(sc, exp.loc)) 4975 return setError(); 4976 } 4977 else if (sc.func && sc.intypeof != 1 && !(sc.flags & (SCOPE.ctfe | SCOPE.debug_))) 4978 { 4979 bool err = false; 4980 if (!tf.purity && sc.func.setImpure()) 4981 { 4982 exp.error("`pure` %s `%s` cannot call impure %s `%s`", 4983 sc.func.kind(), sc.func.toPrettyChars(), p, exp.e1.toChars()); 4984 err = true; 4985 } 4986 if (!tf.isnogc && sc.func.setGC()) 4987 { 4988 exp.error("`@nogc` %s `%s` cannot call non-@nogc %s `%s`", 4989 sc.func.kind(), sc.func.toPrettyChars(), p, exp.e1.toChars()); 4990 err = true; 4991 } 4992 if (tf.trust <= TRUST.system && sc.func.setUnsafe()) 4993 { 4994 exp.error("`@safe` %s `%s` cannot call `@system` %s `%s`", 4995 sc.func.kind(), sc.func.toPrettyChars(), p, exp.e1.toChars()); 4996 err = true; 4997 } 4998 if (err) 4999 return setError(); 5000 } 5001 5002 if (t1.ty == Tpointer) 5003 { 5004 Expression e = new PtrExp(exp.loc, exp.e1); 5005 e.type = tf; 5006 exp.e1 = e; 5007 } 5008 t1 = tf; 5009 } 5010 else if (exp.e1.op == TOK.variable) 5011 { 5012 // Do overload resolution 5013 VarExp ve = cast(VarExp)exp.e1; 5014 5015 exp.f = ve.var.isFuncDeclaration(); 5016 assert(exp.f); 5017 tiargs = null; 5018 5019 if (exp.f.overnext) 5020 exp.f = resolveFuncCall(exp.loc, sc, exp.f, tiargs, null, exp.arguments, FuncResolveFlag.overloadOnly); 5021 else 5022 { 5023 exp.f = exp.f.toAliasFunc(); 5024 TypeFunction tf = cast(TypeFunction)exp.f.type; 5025 const(char)* failMessage; 5026 Expression[] fargs = exp.arguments ? (*exp.arguments)[] : null; 5027 if (!tf.callMatch(null, fargs, 0, &failMessage, sc)) 5028 { 5029 OutBuffer buf; 5030 buf.writeByte('('); 5031 argExpTypesToCBuffer(&buf, exp.arguments); 5032 buf.writeByte(')'); 5033 5034 //printf("tf = %s, args = %s\n", tf.deco, (*arguments)[0].type.deco); 5035 .error(exp.loc, "%s `%s%s` is not callable using argument types `%s`", 5036 exp.f.kind(), exp.f.toPrettyChars(), parametersTypeToChars(tf.parameterList), buf.peekChars()); 5037 if (failMessage) 5038 errorSupplemental(exp.loc, "%s", failMessage); 5039 exp.f = null; 5040 } 5041 } 5042 if (!exp.f || exp.f.errors) 5043 return setError(); 5044 5045 if (exp.f.needThis()) 5046 { 5047 // Change the ancestor lambdas to delegate before hasThis(sc) call. 5048 if (exp.f.checkNestedReference(sc, exp.loc)) 5049 return setError(); 5050 5051 if (hasThis(sc)) 5052 { 5053 // Supply an implicit 'this', as in 5054 // this.ident 5055 exp.e1 = new DotVarExp(exp.loc, (new ThisExp(exp.loc)).expressionSemantic(sc), ve.var); 5056 // Note: we cannot use f directly, because further overload resolution 5057 // through the supplied 'this' may cause different result. 5058 goto Lagain; 5059 } 5060 else if (isNeedThisScope(sc, exp.f)) 5061 { 5062 exp.error("need `this` for `%s` of type `%s`", exp.f.toChars(), exp.f.type.toChars()); 5063 return setError(); 5064 } 5065 } 5066 5067 checkFunctionAttributes(exp, sc, exp.f); 5068 checkAccess(exp.loc, sc, null, exp.f); 5069 if (exp.f.checkNestedReference(sc, exp.loc)) 5070 return setError(); 5071 5072 ethis = null; 5073 tthis = null; 5074 5075 if (ve.hasOverloads) 5076 { 5077 exp.e1 = new VarExp(ve.loc, exp.f, false); 5078 exp.e1.type = exp.f.type; 5079 } 5080 t1 = exp.f.type; 5081 } 5082 assert(t1.ty == Tfunction); 5083 5084 Expression argprefix; 5085 if (!exp.arguments) 5086 exp.arguments = new Expressions(); 5087 if (functionParameters(exp.loc, sc, cast(TypeFunction)t1, ethis, tthis, exp.arguments, exp.f, &exp.type, &argprefix)) 5088 return setError(); 5089 5090 if (!exp.type) 5091 { 5092 exp.e1 = e1org; // https://issues.dlang.org/show_bug.cgi?id=10922 5093 // avoid recursive expression printing 5094 exp.error("forward reference to inferred return type of function call `%s`", exp.toChars()); 5095 return setError(); 5096 } 5097 5098 if (exp.f && exp.f.tintro) 5099 { 5100 Type t = exp.type; 5101 int offset = 0; 5102 TypeFunction tf = cast(TypeFunction)exp.f.tintro; 5103 if (tf.next.isBaseOf(t, &offset) && offset) 5104 { 5105 exp.type = tf.next; 5106 result = Expression.combine(argprefix, exp.castTo(sc, t)); 5107 return; 5108 } 5109 } 5110 5111 // Handle the case of a direct lambda call 5112 if (exp.f && exp.f.isFuncLiteralDeclaration() && sc.func && !sc.intypeof) 5113 { 5114 exp.f.tookAddressOf = 0; 5115 } 5116 5117 result = Expression.combine(argprefix, exp); 5118 5119 if (isSuper) 5120 { 5121 auto ad = sc.func ? sc.func.isThis() : null; 5122 auto cd = ad ? ad.isClassDeclaration() : null; 5123 if (cd && cd.classKind == ClassKind.cpp && exp.f && !exp.f.fbody) 5124 { 5125 // if super is defined in C++, it sets the vtable pointer to the base class 5126 // so we have to restore it, but still return 'this' from super() call: 5127 // (auto __vptrTmp = this.__vptr, auto __superTmp = super()), (this.__vptr = __vptrTmp, __superTmp) 5128 Loc loc = exp.loc; 5129 5130 auto vptr = new DotIdExp(loc, new ThisExp(loc), Id.__vptr); 5131 auto vptrTmpDecl = copyToTemp(0, "__vptrTmp", vptr); 5132 auto declareVptrTmp = new DeclarationExp(loc, vptrTmpDecl); 5133 5134 auto superTmpDecl = copyToTemp(0, "__superTmp", result); 5135 auto declareSuperTmp = new DeclarationExp(loc, superTmpDecl); 5136 5137 auto declareTmps = new CommaExp(loc, declareVptrTmp, declareSuperTmp); 5138 5139 auto restoreVptr = new AssignExp(loc, vptr.syntaxCopy(), new VarExp(loc, vptrTmpDecl)); 5140 5141 Expression e = new CommaExp(loc, declareTmps, new CommaExp(loc, restoreVptr, new VarExp(loc, superTmpDecl))); 5142 result = e.expressionSemantic(sc); 5143 } 5144 } 5145 5146 // declare dual-context container 5147 if (exp.f && exp.f.isThis2 && !sc.intypeof && sc.func) 5148 { 5149 // check access to second `this` 5150 if (AggregateDeclaration ad2 = exp.f.isMember2()) 5151 { 5152 Expression te = new ThisExp(exp.loc).expressionSemantic(sc); 5153 if (te.op != TOK.error) 5154 te = getRightThis(exp.loc, sc, ad2, te, exp.f); 5155 if (te.op == TOK.error) 5156 { 5157 exp.error("need `this` of type `%s` to call function `%s`", ad2.toChars(), exp.f.toChars()); 5158 return setError(); 5159 } 5160 } 5161 VarDeclaration vthis2 = makeThis2Argument(exp.loc, sc, exp.f); exp.vthis2 = vthis2; 5162 Expression de = new DeclarationExp(exp.loc, vthis2); 5163 result = Expression.combine(de, result); 5164 result = result.expressionSemantic(sc); 5165 } 5166 } 5167 5168 override void visit(DeclarationExp e) 5169 { 5170 if (e.type) 5171 { 5172 result = e; 5173 return; 5174 } 5175 static if (LOGSEMANTIC) 5176 { 5177 printf("DeclarationExp::semantic() %s\n", e.toChars()); 5178 } 5179 5180 uint olderrors = global.errors; 5181 5182 /* This is here to support extern(linkage) declaration, 5183 * where the extern(linkage) winds up being an AttribDeclaration 5184 * wrapper. 5185 */ 5186 Dsymbol s = e.declaration; 5187 5188 while (1) 5189 { 5190 AttribDeclaration ad = s.isAttribDeclaration(); 5191 if (ad) 5192 { 5193 if (ad.decl && ad.decl.dim == 1) 5194 { 5195 s = (*ad.decl)[0]; 5196 continue; 5197 } 5198 } 5199 break; 5200 } 5201 5202 VarDeclaration v = s.isVarDeclaration(); 5203 if (v) 5204 { 5205 // Do semantic() on initializer first, so: 5206 // int a = a; 5207 // will be illegal. 5208 e.declaration.dsymbolSemantic(sc); 5209 s.parent = sc.parent; 5210 } 5211 5212 //printf("inserting '%s' %p into sc = %p\n", s.toChars(), s, sc); 5213 // Insert into both local scope and function scope. 5214 // Must be unique in both. 5215 if (s.ident) 5216 { 5217 if (!sc.insert(s)) 5218 { 5219 auto conflict = sc.search(Loc.initial, s.ident, null); 5220 e.error("declaration `%s` is already defined", s.toPrettyChars()); 5221 errorSupplemental(conflict.loc, "`%s` `%s` is defined here", 5222 conflict.kind(), conflict.toChars()); 5223 return setError(); 5224 } 5225 else if (sc.func) 5226 { 5227 // https://issues.dlang.org/show_bug.cgi?id=11720 5228 // include Dataseg variables 5229 if ((s.isFuncDeclaration() || 5230 s.isAggregateDeclaration() || 5231 s.isEnumDeclaration() || 5232 s.isTemplateDeclaration() || 5233 v && v.isDataseg()) && !sc.func.localsymtab.insert(s)) 5234 { 5235 // Get the previous symbol 5236 Dsymbol originalSymbol = sc.func.localsymtab.lookup(s.ident); 5237 5238 // Perturb the name mangling so that the symbols can co-exist 5239 // instead of colliding 5240 s.localNum = cast(ushort)(originalSymbol.localNum + 1); 5241 assert(s.localNum); // 65535 should be enough for anyone 5242 5243 // Replace originalSymbol with s, which updates the localCount 5244 sc.func.localsymtab.update(s); 5245 5246 // The mangling change only works for D mangling 5247 } 5248 // else 5249 { 5250 /* https://issues.dlang.org/show_bug.cgi?id=21272 5251 * If we are in a foreach body we need to extract the 5252 * function containing the foreach 5253 */ 5254 FuncDeclaration fes_enclosing_func; 5255 if (sc.func && sc.func.fes) 5256 fes_enclosing_func = sc.enclosing.enclosing.func; 5257 5258 // Disallow shadowing 5259 for (Scope* scx = sc.enclosing; scx && (scx.func == sc.func || (fes_enclosing_func && scx.func == fes_enclosing_func)); scx = scx.enclosing) 5260 { 5261 Dsymbol s2; 5262 if (scx.scopesym && scx.scopesym.symtab && (s2 = scx.scopesym.symtab.lookup(s.ident)) !is null && s != s2) 5263 { 5264 // allow STC.local symbols to be shadowed 5265 // TODO: not really an optimal design 5266 auto decl = s2.isDeclaration(); 5267 if (!decl || !(decl.storage_class & STC.local)) 5268 { 5269 if (sc.func.fes) 5270 { 5271 e.deprecation("%s `%s` is shadowing %s `%s`. Rename the `foreach` variable.", s.kind(), s.ident.toChars(), s2.kind(), s2.toPrettyChars()); 5272 } 5273 else 5274 { 5275 e.error("%s `%s` is shadowing %s `%s`", s.kind(), s.ident.toChars(), s2.kind(), s2.toPrettyChars()); 5276 return setError(); 5277 } 5278 } 5279 } 5280 } 5281 } 5282 } 5283 } 5284 if (!s.isVarDeclaration()) 5285 { 5286 Scope* sc2 = sc; 5287 if (sc2.stc & (STC.pure_ | STC.nothrow_ | STC.nogc)) 5288 sc2 = sc.push(); 5289 sc2.stc &= ~(STC.pure_ | STC.nothrow_ | STC.nogc); 5290 e.declaration.dsymbolSemantic(sc2); 5291 if (sc2 != sc) 5292 sc2.pop(); 5293 s.parent = sc.parent; 5294 } 5295 if (global.errors == olderrors) 5296 { 5297 e.declaration.semantic2(sc); 5298 if (global.errors == olderrors) 5299 { 5300 e.declaration.semantic3(sc); 5301 } 5302 } 5303 // todo: error in declaration should be propagated. 5304 5305 e.type = Type.tvoid; 5306 result = e; 5307 } 5308 5309 override void visit(TypeidExp exp) 5310 { 5311 static if (LOGSEMANTIC) 5312 { 5313 printf("TypeidExp::semantic() %s\n", exp.toChars()); 5314 } 5315 Type ta = isType(exp.obj); 5316 Expression ea = isExpression(exp.obj); 5317 Dsymbol sa = isDsymbol(exp.obj); 5318 //printf("ta %p ea %p sa %p\n", ta, ea, sa); 5319 5320 if (ta) 5321 { 5322 dmd.typesem.resolve(ta, exp.loc, sc, ea, ta, sa, true); 5323 } 5324 5325 if (ea) 5326 { 5327 if (auto sym = getDsymbol(ea)) 5328 ea = symbolToExp(sym, exp.loc, sc, false); 5329 else 5330 ea = ea.expressionSemantic(sc); 5331 ea = resolveProperties(sc, ea); 5332 ta = ea.type; 5333 if (ea.op == TOK.type) 5334 ea = null; 5335 } 5336 5337 if (!ta) 5338 { 5339 //printf("ta %p ea %p sa %p\n", ta, ea, sa); 5340 exp.error("no type for `typeid(%s)`", ea ? ea.toChars() : (sa ? sa.toChars() : "")); 5341 return setError(); 5342 } 5343 5344 if (global.params.vcomplex) 5345 ta.checkComplexTransition(exp.loc, sc); 5346 5347 Expression e; 5348 auto tb = ta.toBasetype(); 5349 if (ea && tb.ty == Tclass) 5350 { 5351 if (tb.toDsymbol(sc).isClassDeclaration().classKind == ClassKind.cpp) 5352 { 5353 error(exp.loc, "Runtime type information is not supported for `extern(C++)` classes"); 5354 e = ErrorExp.get(); 5355 } 5356 else if (!Type.typeinfoclass) 5357 { 5358 error(exp.loc, "`object.TypeInfo_Class` could not be found, but is implicitly used"); 5359 e = ErrorExp.get(); 5360 } 5361 else 5362 { 5363 /* Get the dynamic type, which is .classinfo 5364 */ 5365 ea = ea.expressionSemantic(sc); 5366 e = new TypeidExp(ea.loc, ea); 5367 e.type = Type.typeinfoclass.type; 5368 } 5369 } 5370 else if (ta.ty == Terror) 5371 { 5372 e = ErrorExp.get(); 5373 } 5374 else 5375 { 5376 // Handle this in the glue layer 5377 e = new TypeidExp(exp.loc, ta); 5378 e.type = getTypeInfoType(exp.loc, ta, sc); 5379 5380 semanticTypeInfo(sc, ta); 5381 5382 if (ea) 5383 { 5384 e = new CommaExp(exp.loc, ea, e); // execute ea 5385 e = e.expressionSemantic(sc); 5386 } 5387 } 5388 result = e; 5389 } 5390 5391 override void visit(TraitsExp e) 5392 { 5393 result = semanticTraits(e, sc); 5394 } 5395 5396 override void visit(HaltExp e) 5397 { 5398 static if (LOGSEMANTIC) 5399 { 5400 printf("HaltExp::semantic()\n"); 5401 } 5402 e.type = Type.tvoid; 5403 result = e; 5404 } 5405 5406 override void visit(IsExp e) 5407 { 5408 /* is(targ id tok tspec) 5409 * is(targ id : tok2) 5410 * is(targ id == tok2) 5411 */ 5412 Type tded = null; 5413 5414 void yes() 5415 { 5416 //printf("yes\n"); 5417 if (!e.id) 5418 { 5419 result = IntegerExp.createBool(true); 5420 return; 5421 } 5422 5423 Dsymbol s; 5424 Tuple tup = isTuple(tded); 5425 if (tup) 5426 s = new TupleDeclaration(e.loc, e.id, &tup.objects); 5427 else 5428 s = new AliasDeclaration(e.loc, e.id, tded); 5429 s.dsymbolSemantic(sc); 5430 5431 /* The reason for the !tup is unclear. It fails Phobos unittests if it is not there. 5432 * More investigation is needed. 5433 */ 5434 if (!tup && !sc.insert(s)) 5435 { 5436 auto conflict = sc.search(Loc.initial, s.ident, null); 5437 e.error("declaration `%s` is already defined", s.toPrettyChars()); 5438 errorSupplemental(conflict.loc, "`%s` `%s` is defined here", 5439 conflict.kind(), conflict.toChars()); 5440 } 5441 5442 unSpeculative(sc, s); 5443 5444 result = IntegerExp.createBool(true); 5445 } 5446 void no() 5447 { 5448 result = IntegerExp.createBool(false); 5449 //printf("no\n"); 5450 } 5451 5452 static if (LOGSEMANTIC) 5453 { 5454 printf("IsExp::semantic(%s)\n", e.toChars()); 5455 } 5456 if (e.id && !(sc.flags & SCOPE.condition)) 5457 { 5458 e.error("can only declare type aliases within `static if` conditionals or `static assert`s"); 5459 return setError(); 5460 } 5461 5462 if (e.tok2 == TOK.package_ || e.tok2 == TOK.module_) // These is() expressions are special because they can work on modules, not just types. 5463 { 5464 const oldErrors = global.startGagging(); 5465 Dsymbol sym = e.targ.toDsymbol(sc); 5466 global.endGagging(oldErrors); 5467 5468 if (sym is null) 5469 return no(); 5470 Package p = resolveIsPackage(sym); 5471 if (p is null) 5472 return no(); 5473 if (e.tok2 == TOK.package_ && p.isModule()) // Note that isModule() will return null for package modules because they're not actually instances of Module. 5474 return no(); 5475 else if(e.tok2 == TOK.module_ && !(p.isModule() || p.isPackageMod())) 5476 return no(); 5477 tded = e.targ; 5478 return yes(); 5479 } 5480 5481 { 5482 Scope* sc2 = sc.copy(); // keep sc.flags 5483 sc2.tinst = null; 5484 sc2.minst = null; 5485 sc2.flags |= SCOPE.fullinst; 5486 Type t = e.targ.trySemantic(e.loc, sc2); 5487 sc2.pop(); 5488 if (!t) // errors, so condition is false 5489 return no(); 5490 e.targ = t; 5491 } 5492 5493 if (e.tok2 != TOK.reserved) 5494 { 5495 switch (e.tok2) 5496 { 5497 case TOK.struct_: 5498 if (e.targ.ty != Tstruct) 5499 return no(); 5500 if ((cast(TypeStruct)e.targ).sym.isUnionDeclaration()) 5501 return no(); 5502 tded = e.targ; 5503 break; 5504 5505 case TOK.union_: 5506 if (e.targ.ty != Tstruct) 5507 return no(); 5508 if (!(cast(TypeStruct)e.targ).sym.isUnionDeclaration()) 5509 return no(); 5510 tded = e.targ; 5511 break; 5512 5513 case TOK.class_: 5514 if (e.targ.ty != Tclass) 5515 return no(); 5516 if ((cast(TypeClass)e.targ).sym.isInterfaceDeclaration()) 5517 return no(); 5518 tded = e.targ; 5519 break; 5520 5521 case TOK.interface_: 5522 if (e.targ.ty != Tclass) 5523 return no(); 5524 if (!(cast(TypeClass)e.targ).sym.isInterfaceDeclaration()) 5525 return no(); 5526 tded = e.targ; 5527 break; 5528 5529 case TOK.const_: 5530 if (!e.targ.isConst()) 5531 return no(); 5532 tded = e.targ; 5533 break; 5534 5535 case TOK.immutable_: 5536 if (!e.targ.isImmutable()) 5537 return no(); 5538 tded = e.targ; 5539 break; 5540 5541 case TOK.shared_: 5542 if (!e.targ.isShared()) 5543 return no(); 5544 tded = e.targ; 5545 break; 5546 5547 case TOK.inout_: 5548 if (!e.targ.isWild()) 5549 return no(); 5550 tded = e.targ; 5551 break; 5552 5553 case TOK.super_: 5554 // If class or interface, get the base class and interfaces 5555 if (e.targ.ty != Tclass) 5556 return no(); 5557 else 5558 { 5559 ClassDeclaration cd = (cast(TypeClass)e.targ).sym; 5560 auto args = new Parameters(); 5561 args.reserve(cd.baseclasses.dim); 5562 if (cd.semanticRun < PASS.semanticdone) 5563 cd.dsymbolSemantic(null); 5564 for (size_t i = 0; i < cd.baseclasses.dim; i++) 5565 { 5566 BaseClass* b = (*cd.baseclasses)[i]; 5567 args.push(new Parameter(STC.in_, b.type, null, null, null)); 5568 } 5569 tded = new TypeTuple(args); 5570 } 5571 break; 5572 5573 case TOK.enum_: 5574 if (e.targ.ty != Tenum) 5575 return no(); 5576 if (e.id) 5577 tded = (cast(TypeEnum)e.targ).sym.getMemtype(e.loc); 5578 else 5579 tded = e.targ; 5580 5581 if (tded.ty == Terror) 5582 return setError(); 5583 break; 5584 5585 case TOK.delegate_: 5586 if (e.targ.ty != Tdelegate) 5587 return no(); 5588 tded = (cast(TypeDelegate)e.targ).next; // the underlying function type 5589 break; 5590 5591 case TOK.function_: 5592 case TOK.parameters: 5593 { 5594 if (e.targ.ty != Tfunction) 5595 return no(); 5596 tded = e.targ; 5597 5598 /* Generate tuple from function parameter types. 5599 */ 5600 assert(tded.ty == Tfunction); 5601 auto tdedf = tded.isTypeFunction(); 5602 auto args = new Parameters(); 5603 foreach (i, arg; tdedf.parameterList) 5604 { 5605 assert(arg && arg.type); 5606 /* If one of the default arguments was an error, 5607 don't return an invalid tuple 5608 */ 5609 if (e.tok2 == TOK.parameters && arg.defaultArg && arg.defaultArg.op == TOK.error) 5610 return setError(); 5611 args.push(new Parameter(arg.storageClass, arg.type, (e.tok2 == TOK.parameters) ? arg.ident : null, (e.tok2 == TOK.parameters) ? arg.defaultArg : null, arg.userAttribDecl)); 5612 } 5613 tded = new TypeTuple(args); 5614 break; 5615 } 5616 case TOK.return_: 5617 /* Get the 'return type' for the function, 5618 * delegate, or pointer to function. 5619 */ 5620 if (e.targ.ty == Tfunction) 5621 tded = (cast(TypeFunction)e.targ).next; 5622 else if (e.targ.ty == Tdelegate) 5623 { 5624 tded = (cast(TypeDelegate)e.targ).next; 5625 tded = (cast(TypeFunction)tded).next; 5626 } 5627 else if (e.targ.ty == Tpointer && (cast(TypePointer)e.targ).next.ty == Tfunction) 5628 { 5629 tded = (cast(TypePointer)e.targ).next; 5630 tded = (cast(TypeFunction)tded).next; 5631 } 5632 else 5633 return no(); 5634 break; 5635 5636 case TOK.argumentTypes: 5637 /* Generate a type tuple of the equivalent types used to determine if a 5638 * function argument of this type can be passed in registers. 5639 * The results of this are highly platform dependent, and intended 5640 * primarly for use in implementing va_arg(). 5641 */ 5642 tded = target.toArgTypes(e.targ); 5643 if (!tded) 5644 return no(); 5645 // not valid for a parameter 5646 break; 5647 5648 case TOK.vector: 5649 if (e.targ.ty != Tvector) 5650 return no(); 5651 tded = (cast(TypeVector)e.targ).basetype; 5652 break; 5653 5654 default: 5655 assert(0); 5656 } 5657 5658 // https://issues.dlang.org/show_bug.cgi?id=18753 5659 if (tded) 5660 return yes(); 5661 return no(); 5662 } 5663 else if (e.tspec && !e.id && !(e.parameters && e.parameters.dim)) 5664 { 5665 /* Evaluate to true if targ matches tspec 5666 * is(targ == tspec) 5667 * is(targ : tspec) 5668 */ 5669 e.tspec = e.tspec.typeSemantic(e.loc, sc); 5670 //printf("targ = %s, %s\n", e.targ.toChars(), e.targ.deco); 5671 //printf("tspec = %s, %s\n", e.tspec.toChars(), e.tspec.deco); 5672 5673 if (e.tok == TOK.colon) 5674 { 5675 // current scope is itself deprecated, or deprecations are not errors 5676 const bool deprecationAllowed = sc.isDeprecated 5677 || global.params.useDeprecated != DiagnosticReporting.error; 5678 const bool preventAliasThis = e.targ.hasDeprecatedAliasThis && !deprecationAllowed; 5679 5680 if (preventAliasThis && e.targ.ty == Tstruct) 5681 { 5682 if ((cast(TypeStruct) e.targ).implicitConvToWithoutAliasThis(e.tspec)) 5683 return yes(); 5684 else 5685 return no(); 5686 } 5687 else if (preventAliasThis && e.targ.ty == Tclass) 5688 { 5689 if ((cast(TypeClass) e.targ).implicitConvToWithoutAliasThis(e.tspec)) 5690 return yes(); 5691 else 5692 return no(); 5693 } 5694 else if (e.targ.implicitConvTo(e.tspec)) 5695 return yes(); 5696 else 5697 return no(); 5698 } 5699 else /* == */ 5700 { 5701 if (e.targ.equals(e.tspec)) 5702 return yes(); 5703 else 5704 return no(); 5705 } 5706 } 5707 else if (e.tspec) 5708 { 5709 /* Evaluate to true if targ matches tspec. 5710 * If true, declare id as an alias for the specialized type. 5711 * is(targ == tspec, tpl) 5712 * is(targ : tspec, tpl) 5713 * is(targ id == tspec) 5714 * is(targ id : tspec) 5715 * is(targ id == tspec, tpl) 5716 * is(targ id : tspec, tpl) 5717 */ 5718 Identifier tid = e.id ? e.id : Identifier.generateId("__isexp_id"); 5719 e.parameters.insert(0, new TemplateTypeParameter(e.loc, tid, null, null)); 5720 5721 Objects dedtypes = Objects(e.parameters.dim); 5722 dedtypes.zero(); 5723 5724 MATCH m = deduceType(e.targ, sc, e.tspec, e.parameters, &dedtypes, null, 0, e.tok == TOK.equal); 5725 //printf("targ: %s\n", targ.toChars()); 5726 //printf("tspec: %s\n", tspec.toChars()); 5727 if (m <= MATCH.nomatch || (m != MATCH.exact && e.tok == TOK.equal)) 5728 { 5729 return no(); 5730 } 5731 else 5732 { 5733 tded = cast(Type)dedtypes[0]; 5734 if (!tded) 5735 tded = e.targ; 5736 Objects tiargs = Objects(1); 5737 tiargs[0] = e.targ; 5738 5739 /* Declare trailing parameters 5740 */ 5741 for (size_t i = 1; i < e.parameters.dim; i++) 5742 { 5743 TemplateParameter tp = (*e.parameters)[i]; 5744 Declaration s = null; 5745 5746 m = tp.matchArg(e.loc, sc, &tiargs, i, e.parameters, &dedtypes, &s); 5747 if (m <= MATCH.nomatch) 5748 return no(); 5749 s.dsymbolSemantic(sc); 5750 if (!sc.insert(s)) 5751 { 5752 auto conflict = sc.search(Loc.initial, s.ident, null); 5753 e.error("declaration `%s` is already defined", s.toPrettyChars()); 5754 errorSupplemental(conflict.loc, "`%s` `%s` is defined here", 5755 conflict.kind(), conflict.toChars()); 5756 } 5757 5758 unSpeculative(sc, s); 5759 } 5760 return yes(); 5761 } 5762 } 5763 else if (e.id) 5764 { 5765 /* Declare id as an alias for type targ. Evaluate to true 5766 * is(targ id) 5767 */ 5768 tded = e.targ; 5769 } 5770 return yes(); 5771 } 5772 5773 override void visit(BinAssignExp exp) 5774 { 5775 if (exp.type) 5776 { 5777 result = exp; 5778 return; 5779 } 5780 5781 Expression e = exp.op_overload(sc); 5782 if (e) 5783 { 5784 result = e; 5785 return; 5786 } 5787 5788 if (exp.e1.op == TOK.arrayLength) 5789 { 5790 // arr.length op= e2; 5791 e = rewriteOpAssign(exp); 5792 e = e.expressionSemantic(sc); 5793 result = e; 5794 return; 5795 } 5796 if (exp.e1.op == TOK.slice || exp.e1.type.ty == Tarray || exp.e1.type.ty == Tsarray) 5797 { 5798 if (checkNonAssignmentArrayOp(exp.e1)) 5799 return setError(); 5800 5801 if (exp.e1.op == TOK.slice) 5802 (cast(SliceExp)exp.e1).arrayop = true; 5803 5804 // T[] op= ... 5805 if (exp.e2.implicitConvTo(exp.e1.type.nextOf())) 5806 { 5807 // T[] op= T 5808 exp.e2 = exp.e2.castTo(sc, exp.e1.type.nextOf()); 5809 } 5810 else if (Expression ex = typeCombine(exp, sc)) 5811 { 5812 result = ex; 5813 return; 5814 } 5815 exp.type = exp.e1.type; 5816 result = arrayOp(exp, sc); 5817 return; 5818 } 5819 5820 exp.e1 = exp.e1.expressionSemantic(sc); 5821 exp.e1 = exp.e1.optimize(WANTvalue, /*keepLvalue*/ true); 5822 exp.e1 = exp.e1.modifiableLvalue(sc, exp.e1); 5823 exp.type = exp.e1.type; 5824 5825 if (auto ad = isAggregate(exp.e1.type)) 5826 { 5827 if (const s = search_function(ad, Id.opOpAssign)) 5828 { 5829 error(exp.loc, "none of the `opOpAssign` overloads of `%s` are callable for `%s` of type `%s`", ad.toChars(), exp.e1.toChars(), exp.e1.type.toChars()); 5830 return setError(); 5831 } 5832 } 5833 if (exp.e1.checkScalar() || 5834 exp.e1.checkReadModifyWrite(exp.op, exp.e2) || 5835 exp.e1.checkSharedAccess(sc)) 5836 return setError(); 5837 5838 int arith = (exp.op == TOK.addAssign || exp.op == TOK.minAssign || exp.op == TOK.mulAssign || exp.op == TOK.divAssign || exp.op == TOK.modAssign || exp.op == TOK.powAssign); 5839 int bitwise = (exp.op == TOK.andAssign || exp.op == TOK.orAssign || exp.op == TOK.xorAssign); 5840 int shift = (exp.op == TOK.leftShiftAssign || exp.op == TOK.rightShiftAssign || exp.op == TOK.unsignedRightShiftAssign); 5841 5842 if (bitwise && exp.type.toBasetype().ty == Tbool) 5843 exp.e2 = exp.e2.implicitCastTo(sc, exp.type); 5844 else if (exp.checkNoBool()) 5845 return setError(); 5846 5847 if ((exp.op == TOK.addAssign || exp.op == TOK.minAssign) && exp.e1.type.toBasetype().ty == Tpointer && exp.e2.type.toBasetype().isintegral()) 5848 { 5849 result = scaleFactor(exp, sc); 5850 return; 5851 } 5852 5853 if (Expression ex = typeCombine(exp, sc)) 5854 { 5855 result = ex; 5856 return; 5857 } 5858 5859 if (arith && (exp.checkArithmeticBin() || exp.checkSharedAccessBin(sc))) 5860 return setError(); 5861 if ((bitwise || shift) && (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc))) 5862 return setError(); 5863 5864 if (shift) 5865 { 5866 if (exp.e2.type.toBasetype().ty != Tvector) 5867 exp.e2 = exp.e2.castTo(sc, Type.tshiftcnt); 5868 } 5869 5870 if (!target.isVectorOpSupported(exp.type.toBasetype(), exp.op, exp.e2.type.toBasetype())) 5871 { 5872 result = exp.incompatibleTypes(); 5873 return; 5874 } 5875 5876 if (exp.e1.op == TOK.error || exp.e2.op == TOK.error) 5877 return setError(); 5878 5879 e = exp.checkOpAssignTypes(sc); 5880 if (e.op == TOK.error) 5881 { 5882 result = e; 5883 return; 5884 } 5885 5886 assert(e.op == TOK.assign || e == exp); 5887 result = (cast(BinExp)e).reorderSettingAAElem(sc); 5888 } 5889 5890 private Expression compileIt(MixinExp exp) 5891 { 5892 OutBuffer buf; 5893 if (expressionsToString(buf, sc, exp.exps)) 5894 return null; 5895 5896 uint errors = global.errors; 5897 const len = buf.length; 5898 const str = buf.extractChars()[0 .. len]; 5899 scope p = new Parser!ASTCodegen(exp.loc, sc._module, str, false); 5900 p.nextToken(); 5901 //printf("p.loc.linnum = %d\n", p.loc.linnum); 5902 5903 Expression e = p.parseExpression(); 5904 p.reportDiagnostics(); 5905 if (global.errors != errors) 5906 return null; 5907 5908 if (p.token.value != TOK.endOfFile) 5909 { 5910 exp.error("incomplete mixin expression `%s`", str.ptr); 5911 return null; 5912 } 5913 return e; 5914 } 5915 5916 override void visit(MixinExp exp) 5917 { 5918 /* https://dlang.org/spec/expression.html#mixin_expressions 5919 */ 5920 5921 static if (LOGSEMANTIC) 5922 { 5923 printf("MixinExp::semantic('%s')\n", exp.toChars()); 5924 } 5925 5926 auto e = compileIt(exp); 5927 if (!e) 5928 return setError(); 5929 result = e.expressionSemantic(sc); 5930 } 5931 5932 override void visit(ImportExp e) 5933 { 5934 static if (LOGSEMANTIC) 5935 { 5936 printf("ImportExp::semantic('%s')\n", e.toChars()); 5937 } 5938 5939 auto se = semanticString(sc, e.e1, "file name argument"); 5940 if (!se) 5941 return setError(); 5942 se = se.toUTF8(sc); 5943 5944 auto namez = se.toStringz().ptr; 5945 if (!global.filePath) 5946 { 5947 e.error("need `-J` switch to import text file `%s`", namez); 5948 return setError(); 5949 } 5950 5951 /* Be wary of CWE-22: Improper Limitation of a Pathname to a Restricted Directory 5952 * ('Path Traversal') attacks. 5953 * http://cwe.mitre.org/data/definitions/22.html 5954 */ 5955 5956 if (FileName.absolute(namez)) 5957 { 5958 e.error("absolute path is not allowed in import expression: `%s`", se.toChars()); 5959 return setError(); 5960 } 5961 5962 auto idxReserved = FileName.findReservedChar(namez); 5963 if (idxReserved != size_t.max) 5964 { 5965 e.error("`%s` is not a valid filename on this platform", se.toChars()); 5966 e.errorSupplemental("Character `'%c'` is reserved and cannot be used", namez[idxReserved]); 5967 return setError(); 5968 } 5969 5970 if (FileName.refersToParentDir(namez)) 5971 { 5972 e.error("path refers to parent (`..`) directory: `%s`", se.toChars()); 5973 return setError(); 5974 } 5975 5976 auto name = FileName.searchPath(global.filePath, namez, false); 5977 if (!name) 5978 { 5979 e.error("file `%s` cannot be found or not in a path specified with `-J`", se.toChars()); 5980 e.errorSupplemental("Path(s) searched (as provided by `-J`):"); 5981 foreach (idx, path; *global.filePath) 5982 { 5983 const attr = FileName.exists(path); 5984 const(char)* err = attr == 2 ? "" : 5985 (attr == 1 ? " (not a directory)" : " (path not found)"); 5986 e.errorSupplemental("[%zu]: `%s`%s", idx, path, err); 5987 } 5988 return setError(); 5989 } 5990 5991 sc._module.contentImportedFiles.push(name); 5992 if (global.params.verbose) 5993 { 5994 const slice = se.peekString(); 5995 message("file %.*s\t(%s)", cast(int)slice.length, slice.ptr, name); 5996 } 5997 if (global.params.moduleDeps !is null) 5998 { 5999 OutBuffer* ob = global.params.moduleDeps; 6000 Module imod = sc.instantiatingModule(); 6001 6002 if (!global.params.moduleDepsFile) 6003 ob.writestring("depsFile "); 6004 ob.writestring(imod.toPrettyChars()); 6005 ob.writestring(" ("); 6006 escapePath(ob, imod.srcfile.toChars()); 6007 ob.writestring(") : "); 6008 if (global.params.moduleDepsFile) 6009 ob.writestring("string : "); 6010 ob.write(se.peekString()); 6011 ob.writestring(" ("); 6012 escapePath(ob, name); 6013 ob.writestring(")"); 6014 ob.writenl(); 6015 } 6016 if (global.params.emitMakeDeps) 6017 { 6018 global.params.makeDeps.push(name); 6019 } 6020 6021 { 6022 auto readResult = File.read(name); 6023 if (!readResult.success) 6024 { 6025 e.error("cannot read file `%s`", name); 6026 return setError(); 6027 } 6028 else 6029 { 6030 // take ownership of buffer (probably leaking) 6031 auto data = readResult.extractSlice(); 6032 se = new StringExp(e.loc, data); 6033 } 6034 } 6035 result = se.expressionSemantic(sc); 6036 } 6037 6038 override void visit(AssertExp exp) 6039 { 6040 // https://dlang.org/spec/expression.html#assert_expressions 6041 static if (LOGSEMANTIC) 6042 { 6043 printf("AssertExp::semantic('%s')\n", exp.toChars()); 6044 } 6045 6046 const generateMsg = !exp.msg && global.params.checkAction == CHECKACTION.context; 6047 Expression temporariesPrefix; 6048 6049 if (generateMsg) 6050 // no message - use assert expression as msg 6051 { 6052 if (!verifyHookExist(exp.loc, *sc, Id._d_assert_fail, "generating assert messages")) 6053 return setError(); 6054 6055 /* 6056 { 6057 auto a = e1, b = e2; 6058 assert(a == b, _d_assert_fail!"=="(a, b)); 6059 }() 6060 */ 6061 6062 /* 6063 Stores the result of an operand expression into a temporary 6064 if necessary, e.g. if it is an impure fuction call containing side 6065 effects as in https://issues.dlang.org/show_bug.cgi?id=20114 6066 6067 Params: 6068 op = an expression which may require a temporary (added to 6069 `temporariesPrefix`: `auto tmp = op`) and will be replaced 6070 by `tmp` if necessary 6071 6072 Returns: (possibly replaced) `op` 6073 */ 6074 Expression maybePromoteToTmp(ref Expression op) 6075 { 6076 // https://issues.dlang.org/show_bug.cgi?id=20989 6077 // Flag that _d_assert_fail will never dereference `array.ptr` to avoid safety 6078 // errors for `assert(!array.ptr)` => `_d_assert_fail!"!"(array.ptr)` 6079 { 6080 auto die = op.isDotIdExp(); 6081 if (die && die.ident == Id.ptr) 6082 die.noderef = true; 6083 } 6084 6085 op = op.expressionSemantic(sc); 6086 op = resolveProperties(sc, op); 6087 6088 // Create a temporary for expressions with side effects 6089 // Defensively assume that function calls may have side effects even 6090 // though it's not detected by hasSideEffect (e.g. `debug puts("Hello")` ) 6091 // Rewriting CallExp's also avoids some issues with the inliner/debug generation 6092 if (op.hasSideEffect(true)) 6093 { 6094 // https://issues.dlang.org/show_bug.cgi?id=21590 6095 // Don't create unnecessary temporaries and detect `assert(a = b)` 6096 if (op.isAssignExp() || op.isBinAssignExp()) 6097 { 6098 auto left = (cast(BinExp) op).e1; 6099 6100 // Find leftmost expression to handle other rewrites, 6101 // e.g. --(++a) => a += 1 -= 1 6102 while (left.isAssignExp() || left.isBinAssignExp()) 6103 left = (cast(BinExp) left).e1; 6104 6105 // Only use the assignee if it's a variable and skip 6106 // other lvalues (e.g. ref's returned by functions) 6107 if (left.isVarExp()) 6108 return left; 6109 6110 // Sanity check that `op` can be converted to boolean 6111 op.toBoolean(sc); 6112 } 6113 6114 const stc = op.isLvalue() ? STC.ref_ : 0; 6115 auto tmp = copyToTemp(stc, "__assertOp", op); 6116 tmp.dsymbolSemantic(sc); 6117 6118 auto decl = new DeclarationExp(op.loc, tmp); 6119 temporariesPrefix = Expression.combine(temporariesPrefix, decl); 6120 6121 op = new VarExp(op.loc, tmp); 6122 op = op.expressionSemantic(sc); 6123 } 6124 return op; 6125 } 6126 6127 // if the assert condition is a mixin expression, try to compile it 6128 if (auto ce = exp.e1.isMixinExp()) 6129 { 6130 if (auto e1 = compileIt(ce)) 6131 exp.e1 = e1; 6132 } 6133 6134 Expressions* es; 6135 Objects* tiargs; 6136 Loc loc = exp.e1.loc; 6137 6138 const tok = exp.e1.op; 6139 bool isEqualsCallExpression; 6140 if (tok == TOK.call) 6141 { 6142 const callExp = cast(CallExp) exp.e1; 6143 6144 // https://issues.dlang.org/show_bug.cgi?id=20331 6145 // callExp.f may be null if the assert contains a call to 6146 // a function pointer or literal 6147 if (const callExpFunc = callExp.f) 6148 { 6149 const callExpIdent = callExpFunc.ident; 6150 isEqualsCallExpression = callExpIdent == Id.__equals || 6151 callExpIdent == Id.eq; 6152 } 6153 } 6154 if (tok == TOK.equal || tok == TOK.notEqual || 6155 tok == TOK.lessThan || tok == TOK.greaterThan || 6156 tok == TOK.lessOrEqual || tok == TOK.greaterOrEqual || 6157 tok == TOK.identity || tok == TOK.notIdentity || 6158 tok == TOK.in_ || 6159 isEqualsCallExpression) 6160 { 6161 es = new Expressions(3); 6162 tiargs = new Objects(1); 6163 6164 if (isEqualsCallExpression) 6165 { 6166 auto callExp = cast(CallExp) exp.e1; 6167 auto args = callExp.arguments; 6168 6169 // structs with opEquals get rewritten to a DotVarExp: 6170 // a.opEquals(b) 6171 // https://issues.dlang.org/show_bug.cgi?id=20100 6172 if (args.length == 1) 6173 { 6174 auto dv = callExp.e1.isDotVarExp(); 6175 assert(dv); 6176 6177 // runtime args 6178 (*es)[1] = maybePromoteToTmp(dv.e1); 6179 (*es)[2] = maybePromoteToTmp((*args)[0]); 6180 } 6181 else 6182 { 6183 // runtime args 6184 (*es)[1] = maybePromoteToTmp((*args)[0]); 6185 (*es)[2] = maybePromoteToTmp((*args)[1]); 6186 } 6187 } 6188 else 6189 { 6190 auto binExp = cast(EqualExp) exp.e1; 6191 6192 // runtime args 6193 (*es)[1] = maybePromoteToTmp(binExp.e1); 6194 (*es)[2] = maybePromoteToTmp(binExp.e2); 6195 } 6196 6197 // template args 6198 Expression comp = new StringExp(loc, isEqualsCallExpression ? "==" : Token.toString(exp.e1.op)); 6199 comp = comp.expressionSemantic(sc); 6200 (*es)[0] = comp; 6201 (*tiargs)[0] = (*es)[1].type; 6202 } 6203 6204 // Format exp.e1 before any additional boolean conversion 6205 // Ignore &&/|| because "assert(...) failed" is more informative than "false != true" 6206 else if (tok != TOK.andAnd && tok != TOK.orOr) 6207 { 6208 es = new Expressions(2); 6209 tiargs = new Objects(1); 6210 6211 if (auto ne = exp.e1.isNotExp()) 6212 { 6213 // Fetch the (potential non-bool) expression and fold 6214 // (n) negations into (n % 2) negations, e.g. !!a => a 6215 for (bool neg = true; ; neg = !neg) 6216 { 6217 if (auto ne2 = ne.e1.isNotExp()) 6218 ne = ne2; 6219 else 6220 { 6221 (*es)[0] = new StringExp(loc, neg ? "!" : ""); 6222 (*es)[1] = maybePromoteToTmp(ne.e1); 6223 break; 6224 } 6225 } 6226 } 6227 else 6228 { // Simply format exp.e1 6229 (*es)[0] = new StringExp(loc, ""); 6230 (*es)[1] = maybePromoteToTmp(exp.e1); 6231 } 6232 6233 (*tiargs)[0] = (*es)[1].type; 6234 6235 // Passing __ctfe to auto ref infers ref and aborts compilation: 6236 // "cannot modify compiler-generated variable __ctfe" 6237 auto ve = (*es)[1].isVarExp(); 6238 if (ve && ve.var.ident == Id.ctfe) 6239 { 6240 exp.msg = new StringExp(loc, "assert(__ctfe) failed!"); 6241 goto LSkip; 6242 } 6243 } 6244 else 6245 { 6246 OutBuffer buf; 6247 buf.printf("%s failed", exp.toChars()); 6248 exp.msg = new StringExp(Loc.initial, buf.extractSlice()); 6249 goto LSkip; 6250 } 6251 6252 Expression __assertFail = new IdentifierExp(exp.loc, Id.empty); 6253 auto assertFail = new DotIdExp(loc, __assertFail, Id.object); 6254 6255 auto dt = new DotTemplateInstanceExp(loc, assertFail, Id._d_assert_fail, tiargs); 6256 auto ec = CallExp.create(loc, dt, es); 6257 exp.msg = ec; 6258 } 6259 6260 LSkip: 6261 if (Expression ex = unaSemantic(exp, sc)) 6262 { 6263 result = ex; 6264 return; 6265 } 6266 6267 exp.e1 = resolveProperties(sc, exp.e1); 6268 // BUG: see if we can do compile time elimination of the Assert 6269 exp.e1 = exp.e1.optimize(WANTvalue); 6270 exp.e1 = exp.e1.toBoolean(sc); 6271 6272 if (exp.e1.op == TOK.error) 6273 { 6274 result = exp.e1; 6275 return; 6276 } 6277 6278 if (exp.msg) 6279 { 6280 exp.msg = expressionSemantic(exp.msg, sc); 6281 exp.msg = resolveProperties(sc, exp.msg); 6282 exp.msg = exp.msg.implicitCastTo(sc, Type.tchar.constOf().arrayOf()); 6283 exp.msg = exp.msg.optimize(WANTvalue); 6284 checkParamArgumentEscape(sc, null, null, exp.msg, true, false); 6285 } 6286 6287 if (exp.msg && exp.msg.op == TOK.error) 6288 { 6289 result = exp.msg; 6290 return; 6291 } 6292 6293 auto f1 = checkNonAssignmentArrayOp(exp.e1); 6294 auto f2 = exp.msg && checkNonAssignmentArrayOp(exp.msg); 6295 if (f1 || f2) 6296 return setError(); 6297 6298 if (exp.e1.isBool(false)) 6299 { 6300 /* This is an `assert(0)` which means halt program execution 6301 */ 6302 FuncDeclaration fd = sc.parent.isFuncDeclaration(); 6303 if (fd) 6304 fd.hasReturnExp |= 4; 6305 sc.ctorflow.orCSX(CSX.halt); 6306 6307 if (global.params.useAssert == CHECKENABLE.off) 6308 { 6309 Expression e = new HaltExp(exp.loc); 6310 e = e.expressionSemantic(sc); 6311 result = e; 6312 return; 6313 } 6314 } 6315 6316 exp.type = Type.tvoid; 6317 6318 result = !temporariesPrefix 6319 ? exp 6320 : Expression.combine(temporariesPrefix, exp).expressionSemantic(sc); 6321 } 6322 6323 override void visit(DotIdExp exp) 6324 { 6325 static if (LOGSEMANTIC) 6326 { 6327 printf("DotIdExp::semantic(this = %p, '%s')\n", exp, exp.toChars()); 6328 //printf("e1.op = %d, '%s'\n", e1.op, Token::toChars(e1.op)); 6329 } 6330 Expression e = exp.semanticY(sc, 1); 6331 if (e && isDotOpDispatch(e)) 6332 { 6333 uint errors = global.startGagging(); 6334 e = resolvePropertiesX(sc, e); 6335 if (global.endGagging(errors)) 6336 e = null; /* fall down to UFCS */ 6337 else 6338 { 6339 result = e; 6340 return; 6341 } 6342 } 6343 if (!e) // if failed to find the property 6344 { 6345 /* If ident is not a valid property, rewrite: 6346 * e1.ident 6347 * as: 6348 * .ident(e1) 6349 */ 6350 e = resolveUFCSProperties(sc, exp); 6351 } 6352 result = e; 6353 } 6354 6355 override void visit(DotTemplateExp e) 6356 { 6357 if (Expression ex = unaSemantic(e, sc)) 6358 { 6359 result = ex; 6360 return; 6361 } 6362 result = e; 6363 } 6364 6365 override void visit(DotVarExp exp) 6366 { 6367 static if (LOGSEMANTIC) 6368 { 6369 printf("DotVarExp::semantic('%s')\n", exp.toChars()); 6370 } 6371 if (exp.type) 6372 { 6373 result = exp; 6374 return; 6375 } 6376 6377 exp.var = exp.var.toAlias().isDeclaration(); 6378 6379 exp.e1 = exp.e1.expressionSemantic(sc); 6380 6381 if (auto tup = exp.var.isTupleDeclaration()) 6382 { 6383 /* Replace: 6384 * e1.tuple(a, b, c) 6385 * with: 6386 * tuple(e1.a, e1.b, e1.c) 6387 */ 6388 Expression e0; 6389 Expression ev = sc.func ? extractSideEffect(sc, "__tup", e0, exp.e1) : exp.e1; 6390 6391 auto exps = new Expressions(); 6392 exps.reserve(tup.objects.dim); 6393 for (size_t i = 0; i < tup.objects.dim; i++) 6394 { 6395 RootObject o = (*tup.objects)[i]; 6396 Expression e; 6397 Declaration var; 6398 if (o.dyncast() == DYNCAST.expression) 6399 { 6400 e = cast(Expression)o; 6401 if (auto se = e.isDsymbolExp()) 6402 var = se.s.isDeclaration(); 6403 else if (auto ve = e.isVarExp()) 6404 if (!ve.var.isFuncDeclaration()) 6405 // Exempt functions for backwards compatibility reasons. 6406 // See: https://issues.dlang.org/show_bug.cgi?id=20470#c1 6407 var = ve.var; 6408 } 6409 else if (o.dyncast() == DYNCAST.dsymbol) 6410 { 6411 Dsymbol s = cast(Dsymbol) o; 6412 Declaration d = s.isDeclaration(); 6413 if (!d || d.isFuncDeclaration()) 6414 // Exempt functions for backwards compatibility reasons. 6415 // See: https://issues.dlang.org/show_bug.cgi?id=20470#c1 6416 e = new DsymbolExp(exp.loc, s); 6417 else 6418 var = d; 6419 } 6420 else if (o.dyncast() == DYNCAST.type) 6421 { 6422 e = new TypeExp(exp.loc, cast(Type)o); 6423 } 6424 else 6425 { 6426 exp.error("`%s` is not an expression", o.toChars()); 6427 return setError(); 6428 } 6429 if (var) 6430 e = new DotVarExp(exp.loc, ev, var); 6431 exps.push(e); 6432 } 6433 6434 Expression e = new TupleExp(exp.loc, e0, exps); 6435 e = e.expressionSemantic(sc); 6436 result = e; 6437 return; 6438 } 6439 6440 exp.e1 = exp.e1.addDtorHook(sc); 6441 6442 Type t1 = exp.e1.type; 6443 6444 if (FuncDeclaration fd = exp.var.isFuncDeclaration()) 6445 { 6446 // for functions, do checks after overload resolution 6447 if (!fd.functionSemantic()) 6448 return setError(); 6449 6450 /* https://issues.dlang.org/show_bug.cgi?id=13843 6451 * If fd obviously has no overloads, we should 6452 * normalize AST, and it will give a chance to wrap fd with FuncExp. 6453 */ 6454 if ((fd.isNested() && !fd.isThis()) || fd.isFuncLiteralDeclaration()) 6455 { 6456 // (e1, fd) 6457 auto e = symbolToExp(fd, exp.loc, sc, false); 6458 result = Expression.combine(exp.e1, e); 6459 return; 6460 } 6461 6462 exp.type = fd.type; 6463 assert(exp.type); 6464 } 6465 else if (OverDeclaration od = exp.var.isOverDeclaration()) 6466 { 6467 exp.type = Type.tvoid; // ambiguous type? 6468 } 6469 else 6470 { 6471 exp.type = exp.var.type; 6472 if (!exp.type && global.errors) // var is goofed up, just return error. 6473 return setError(); 6474 assert(exp.type); 6475 6476 if (t1.ty == Tpointer) 6477 t1 = t1.nextOf(); 6478 6479 exp.type = exp.type.addMod(t1.mod); 6480 6481 Dsymbol vparent = exp.var.toParent(); 6482 AggregateDeclaration ad = vparent ? vparent.isAggregateDeclaration() : null; 6483 if (Expression e1x = getRightThis(exp.loc, sc, ad, exp.e1, exp.var, 1)) 6484 exp.e1 = e1x; 6485 else 6486 { 6487 /* Later checkRightThis will report correct error for invalid field variable access. 6488 */ 6489 Expression e = new VarExp(exp.loc, exp.var); 6490 e = e.expressionSemantic(sc); 6491 result = e; 6492 return; 6493 } 6494 checkAccess(exp.loc, sc, exp.e1, exp.var); 6495 6496 VarDeclaration v = exp.var.isVarDeclaration(); 6497 if (v && (v.isDataseg() || (v.storage_class & STC.manifest))) 6498 { 6499 Expression e = expandVar(WANTvalue, v); 6500 if (e) 6501 { 6502 result = e; 6503 return; 6504 } 6505 } 6506 6507 if (v && (v.isDataseg() || // fix https://issues.dlang.org/show_bug.cgi?id=8238 6508 (!v.needThis() && v.semanticRun > PASS.init))) // fix https://issues.dlang.org/show_bug.cgi?id=17258 6509 { 6510 // (e1, v) 6511 checkAccess(exp.loc, sc, exp.e1, v); 6512 Expression e = new VarExp(exp.loc, v); 6513 e = new CommaExp(exp.loc, exp.e1, e); 6514 e = e.expressionSemantic(sc); 6515 result = e; 6516 return; 6517 } 6518 } 6519 //printf("-DotVarExp::semantic('%s')\n", toChars()); 6520 result = exp; 6521 } 6522 6523 override void visit(DotTemplateInstanceExp exp) 6524 { 6525 static if (LOGSEMANTIC) 6526 { 6527 printf("DotTemplateInstanceExp::semantic('%s')\n", exp.toChars()); 6528 } 6529 // Indicate we need to resolve by UFCS. 6530 Expression e = exp.semanticY(sc, 1); 6531 if (!e) 6532 e = resolveUFCSProperties(sc, exp); 6533 result = e; 6534 } 6535 6536 override void visit(DelegateExp e) 6537 { 6538 static if (LOGSEMANTIC) 6539 { 6540 printf("DelegateExp::semantic('%s')\n", e.toChars()); 6541 } 6542 if (e.type) 6543 { 6544 result = e; 6545 return; 6546 } 6547 6548 e.e1 = e.e1.expressionSemantic(sc); 6549 6550 e.type = new TypeDelegate(e.func.type); 6551 e.type = e.type.typeSemantic(e.loc, sc); 6552 6553 FuncDeclaration f = e.func.toAliasFunc(); 6554 AggregateDeclaration ad = f.toParentLocal().isAggregateDeclaration(); 6555 if (f.needThis()) 6556 e.e1 = getRightThis(e.loc, sc, ad, e.e1, f); 6557 if (e.e1.op == TOK.error) 6558 return setError(); 6559 6560 /* A delegate takes the address of e.e1 in order to set the .ptr field 6561 * https://issues.dlang.org/show_bug.cgi?id=18575 6562 */ 6563 if (global.params.vsafe && e.e1.type.toBasetype().ty == Tstruct) 6564 { 6565 if (auto v = expToVariable(e.e1)) 6566 { 6567 if (!checkAddressVar(sc, e.e1, v)) 6568 return setError(); 6569 } 6570 } 6571 6572 if (f.type.ty == Tfunction) 6573 { 6574 TypeFunction tf = cast(TypeFunction)f.type; 6575 if (!MODmethodConv(e.e1.type.mod, f.type.mod)) 6576 { 6577 OutBuffer thisBuf, funcBuf; 6578 MODMatchToBuffer(&thisBuf, e.e1.type.mod, tf.mod); 6579 MODMatchToBuffer(&funcBuf, tf.mod, e.e1.type.mod); 6580 e.error("%smethod `%s` is not callable using a %s`%s`", 6581 funcBuf.peekChars(), f.toPrettyChars(), thisBuf.peekChars(), e.e1.toChars()); 6582 return setError(); 6583 } 6584 } 6585 if (ad && ad.isClassDeclaration() && ad.type != e.e1.type) 6586 { 6587 // A downcast is required for interfaces 6588 // https://issues.dlang.org/show_bug.cgi?id=3706 6589 e.e1 = new CastExp(e.loc, e.e1, ad.type); 6590 e.e1 = e.e1.expressionSemantic(sc); 6591 } 6592 result = e; 6593 // declare dual-context container 6594 if (f.isThis2 && !sc.intypeof && sc.func) 6595 { 6596 // check access to second `this` 6597 if (AggregateDeclaration ad2 = f.isMember2()) 6598 { 6599 Expression te = new ThisExp(e.loc).expressionSemantic(sc); 6600 if (te.op != TOK.error) 6601 te = getRightThis(e.loc, sc, ad2, te, f); 6602 if (te.op == TOK.error) 6603 { 6604 e.error("need `this` of type `%s` to make delegate from function `%s`", ad2.toChars(), f.toChars()); 6605 return setError(); 6606 } 6607 } 6608 VarDeclaration vthis2 = makeThis2Argument(e.loc, sc, f); 6609 e.vthis2 = vthis2; 6610 Expression de = new DeclarationExp(e.loc, vthis2); 6611 result = Expression.combine(de, result); 6612 result = result.expressionSemantic(sc); 6613 } 6614 } 6615 6616 override void visit(DotTypeExp exp) 6617 { 6618 static if (LOGSEMANTIC) 6619 { 6620 printf("DotTypeExp::semantic('%s')\n", exp.toChars()); 6621 } 6622 if (exp.type) 6623 { 6624 result = exp; 6625 return; 6626 } 6627 6628 if (auto e = unaSemantic(exp, sc)) 6629 { 6630 result = e; 6631 return; 6632 } 6633 6634 exp.type = exp.sym.getType().addMod(exp.e1.type.mod); 6635 result = exp; 6636 } 6637 6638 override void visit(AddrExp exp) 6639 { 6640 static if (LOGSEMANTIC) 6641 { 6642 printf("AddrExp::semantic('%s')\n", exp.toChars()); 6643 } 6644 if (exp.type) 6645 { 6646 result = exp; 6647 return; 6648 } 6649 6650 if (Expression ex = unaSemantic(exp, sc)) 6651 { 6652 result = ex; 6653 return; 6654 } 6655 6656 int wasCond = exp.e1.op == TOK.question; 6657 6658 if (exp.e1.op == TOK.dotTemplateInstance) 6659 { 6660 DotTemplateInstanceExp dti = cast(DotTemplateInstanceExp)exp.e1; 6661 TemplateInstance ti = dti.ti; 6662 { 6663 //assert(ti.needsTypeInference(sc)); 6664 ti.dsymbolSemantic(sc); 6665 if (!ti.inst || ti.errors) // if template failed to expand 6666 return setError(); 6667 6668 Dsymbol s = ti.toAlias(); 6669 FuncDeclaration f = s.isFuncDeclaration(); 6670 if (f) 6671 { 6672 exp.e1 = new DotVarExp(exp.e1.loc, dti.e1, f); 6673 exp.e1 = exp.e1.expressionSemantic(sc); 6674 } 6675 } 6676 } 6677 else if (exp.e1.op == TOK.scope_) 6678 { 6679 TemplateInstance ti = (cast(ScopeExp)exp.e1).sds.isTemplateInstance(); 6680 if (ti) 6681 { 6682 //assert(ti.needsTypeInference(sc)); 6683 ti.dsymbolSemantic(sc); 6684 if (!ti.inst || ti.errors) // if template failed to expand 6685 return setError(); 6686 6687 Dsymbol s = ti.toAlias(); 6688 FuncDeclaration f = s.isFuncDeclaration(); 6689 if (f) 6690 { 6691 exp.e1 = new VarExp(exp.e1.loc, f); 6692 exp.e1 = exp.e1.expressionSemantic(sc); 6693 } 6694 } 6695 } 6696 /* https://issues.dlang.org/show_bug.cgi?id=809 6697 * 6698 * If the address of a lazy variable is taken, 6699 * the expression is rewritten so that the type 6700 * of it is the delegate type. This means that 6701 * the symbol is not going to represent a call 6702 * to the delegate anymore, but rather, the 6703 * actual symbol. 6704 */ 6705 if (auto ve = exp.e1.isVarExp()) 6706 { 6707 if (ve.var.storage_class & STC.lazy_) 6708 { 6709 exp.e1 = exp.e1.expressionSemantic(sc); 6710 exp.e1 = resolveProperties(sc, exp.e1); 6711 if (auto callExp = exp.e1.isCallExp()) 6712 { 6713 if (callExp.e1.type.toBasetype().ty == Tdelegate) 6714 { 6715 /* https://issues.dlang.org/show_bug.cgi?id=20551 6716 * 6717 * Cannot take address of lazy parameter in @safe code 6718 * because it might end up being a pointer to undefined 6719 * memory. 6720 */ 6721 if (sc.func && !sc.intypeof && !(sc.flags & SCOPE.debug_) && sc.func.setUnsafe()) 6722 { 6723 exp.error("cannot take address of lazy parameter `%s` in `@safe` function `%s`", 6724 ve.toChars(), sc.func.toChars()); 6725 setError(); 6726 } 6727 else 6728 { 6729 VarExp ve2 = callExp.e1.isVarExp(); 6730 ve2.delegateWasExtracted = true; 6731 ve2.var.storage_class |= STC.scope_; 6732 result = ve2; 6733 } 6734 return; 6735 } 6736 } 6737 } 6738 } 6739 6740 exp.e1 = exp.e1.toLvalue(sc, null); 6741 if (exp.e1.op == TOK.error) 6742 { 6743 result = exp.e1; 6744 return; 6745 } 6746 if (checkNonAssignmentArrayOp(exp.e1)) 6747 return setError(); 6748 6749 if (!exp.e1.type) 6750 { 6751 exp.error("cannot take address of `%s`", exp.e1.toChars()); 6752 return setError(); 6753 } 6754 6755 bool hasOverloads; 6756 if (auto f = isFuncAddress(exp, &hasOverloads)) 6757 { 6758 if (!hasOverloads && f.checkForwardRef(exp.loc)) 6759 return setError(); 6760 } 6761 else if (!exp.e1.type.deco) 6762 { 6763 if (exp.e1.op == TOK.variable) 6764 { 6765 VarExp ve = cast(VarExp)exp.e1; 6766 Declaration d = ve.var; 6767 exp.error("forward reference to %s `%s`", d.kind(), d.toChars()); 6768 } 6769 else 6770 exp.error("forward reference to `%s`", exp.e1.toChars()); 6771 return setError(); 6772 } 6773 6774 exp.type = exp.e1.type.pointerTo(); 6775 6776 // See if this should really be a delegate 6777 if (exp.e1.op == TOK.dotVariable) 6778 { 6779 DotVarExp dve = cast(DotVarExp)exp.e1; 6780 FuncDeclaration f = dve.var.isFuncDeclaration(); 6781 if (f) 6782 { 6783 f = f.toAliasFunc(); // FIXME, should see overloads 6784 // https://issues.dlang.org/show_bug.cgi?id=1983 6785 if (!dve.hasOverloads) 6786 f.tookAddressOf++; 6787 6788 Expression e; 6789 if (f.needThis()) 6790 e = new DelegateExp(exp.loc, dve.e1, f, dve.hasOverloads); 6791 else // It is a function pointer. Convert &v.f() --> (v, &V.f()) 6792 e = new CommaExp(exp.loc, dve.e1, new AddrExp(exp.loc, new VarExp(exp.loc, f, dve.hasOverloads))); 6793 e = e.expressionSemantic(sc); 6794 result = e; 6795 return; 6796 } 6797 6798 // Look for misaligned pointer in @safe mode 6799 if (checkUnsafeAccess(sc, dve, !exp.type.isMutable(), true)) 6800 return setError(); 6801 6802 if (global.params.vsafe) 6803 { 6804 if (VarDeclaration v = expToVariable(dve.e1)) 6805 { 6806 if (!checkAddressVar(sc, exp.e1, v)) 6807 return setError(); 6808 } 6809 } 6810 } 6811 else if (exp.e1.op == TOK.variable) 6812 { 6813 VarExp ve = cast(VarExp)exp.e1; 6814 VarDeclaration v = ve.var.isVarDeclaration(); 6815 if (v) 6816 { 6817 if (!checkAddressVar(sc, exp.e1, v)) 6818 return setError(); 6819 6820 ve.checkPurity(sc, v); 6821 } 6822 FuncDeclaration f = ve.var.isFuncDeclaration(); 6823 if (f) 6824 { 6825 /* Because nested functions cannot be overloaded, 6826 * mark here that we took its address because castTo() 6827 * may not be called with an exact match. 6828 */ 6829 if (!ve.hasOverloads || (f.isNested() && !f.needThis())) 6830 f.tookAddressOf++; 6831 if (f.isNested() && !f.needThis()) 6832 { 6833 if (f.isFuncLiteralDeclaration()) 6834 { 6835 if (!f.FuncDeclaration.isNested()) 6836 { 6837 /* Supply a 'null' for a this pointer if no this is available 6838 */ 6839 Expression e = new DelegateExp(exp.loc, new NullExp(exp.loc, Type.tnull), f, ve.hasOverloads); 6840 e = e.expressionSemantic(sc); 6841 result = e; 6842 return; 6843 } 6844 } 6845 Expression e = new DelegateExp(exp.loc, exp.e1, f, ve.hasOverloads); 6846 e = e.expressionSemantic(sc); 6847 result = e; 6848 return; 6849 } 6850 if (f.needThis()) 6851 { 6852 if (hasThis(sc)) 6853 { 6854 /* Should probably supply 'this' after overload resolution, 6855 * not before. 6856 */ 6857 Expression ethis = new ThisExp(exp.loc); 6858 Expression e = new DelegateExp(exp.loc, ethis, f, ve.hasOverloads); 6859 e = e.expressionSemantic(sc); 6860 result = e; 6861 return; 6862 } 6863 if (sc.func && !sc.intypeof) 6864 { 6865 if (!(sc.flags & SCOPE.debug_) && sc.func.setUnsafe()) 6866 { 6867 exp.error("`this` reference necessary to take address of member `%s` in `@safe` function `%s`", f.toChars(), sc.func.toChars()); 6868 } 6869 } 6870 } 6871 } 6872 } 6873 else if ((exp.e1.op == TOK.this_ || exp.e1.op == TOK.super_) && global.params.vsafe) 6874 { 6875 if (VarDeclaration v = expToVariable(exp.e1)) 6876 { 6877 if (!checkAddressVar(sc, exp.e1, v)) 6878 return setError(); 6879 } 6880 } 6881 else if (exp.e1.op == TOK.call) 6882 { 6883 CallExp ce = cast(CallExp)exp.e1; 6884 if (ce.e1.type.ty == Tfunction) 6885 { 6886 TypeFunction tf = cast(TypeFunction)ce.e1.type; 6887 if (tf.isref && sc.func && !sc.intypeof && !(sc.flags & SCOPE.debug_) && sc.func.setUnsafe()) 6888 { 6889 exp.error("cannot take address of `ref return` of `%s()` in `@safe` function `%s`", 6890 ce.e1.toChars(), sc.func.toChars()); 6891 } 6892 } 6893 } 6894 else if (exp.e1.op == TOK.index) 6895 { 6896 /* For: 6897 * int[3] a; 6898 * &a[i] 6899 * check 'a' the same as for a regular variable 6900 */ 6901 if (VarDeclaration v = expToVariable(exp.e1)) 6902 { 6903 if (global.params.vsafe && !checkAddressVar(sc, exp.e1, v)) 6904 return setError(); 6905 6906 exp.e1.checkPurity(sc, v); 6907 } 6908 } 6909 else if (wasCond) 6910 { 6911 /* a ? b : c was transformed to *(a ? &b : &c), but we still 6912 * need to do safety checks 6913 */ 6914 assert(exp.e1.op == TOK.star); 6915 PtrExp pe = cast(PtrExp)exp.e1; 6916 assert(pe.e1.op == TOK.question); 6917 CondExp ce = cast(CondExp)pe.e1; 6918 assert(ce.e1.op == TOK.address); 6919 assert(ce.e2.op == TOK.address); 6920 6921 // Re-run semantic on the address expressions only 6922 ce.e1.type = null; 6923 ce.e1 = ce.e1.expressionSemantic(sc); 6924 ce.e2.type = null; 6925 ce.e2 = ce.e2.expressionSemantic(sc); 6926 } 6927 result = exp.optimize(WANTvalue); 6928 } 6929 6930 override void visit(PtrExp exp) 6931 { 6932 static if (LOGSEMANTIC) 6933 { 6934 printf("PtrExp::semantic('%s')\n", exp.toChars()); 6935 } 6936 if (exp.type) 6937 { 6938 result = exp; 6939 return; 6940 } 6941 6942 Expression e = exp.op_overload(sc); 6943 if (e) 6944 { 6945 result = e; 6946 return; 6947 } 6948 6949 Type tb = exp.e1.type.toBasetype(); 6950 switch (tb.ty) 6951 { 6952 case Tpointer: 6953 exp.type = (cast(TypePointer)tb).next; 6954 break; 6955 6956 case Tsarray: 6957 case Tarray: 6958 if (isNonAssignmentArrayOp(exp.e1)) 6959 goto default; 6960 exp.error("using `*` on an array is no longer supported; use `*(%s).ptr` instead", exp.e1.toChars()); 6961 exp.type = (cast(TypeArray)tb).next; 6962 exp.e1 = exp.e1.castTo(sc, exp.type.pointerTo()); 6963 break; 6964 6965 case Terror: 6966 return setError(); 6967 6968 case Tnull: 6969 exp.type = Type.tnoreturn; // typeof(*null) is bottom type 6970 break; 6971 6972 default: 6973 exp.error("can only `*` a pointer, not a `%s`", exp.e1.type.toChars()); 6974 goto case Terror; 6975 } 6976 6977 if (exp.checkValue()) 6978 return setError(); 6979 6980 result = exp; 6981 } 6982 6983 override void visit(NegExp exp) 6984 { 6985 static if (LOGSEMANTIC) 6986 { 6987 printf("NegExp::semantic('%s')\n", exp.toChars()); 6988 } 6989 if (exp.type) 6990 { 6991 result = exp; 6992 return; 6993 } 6994 6995 Expression e = exp.op_overload(sc); 6996 if (e) 6997 { 6998 result = e; 6999 return; 7000 } 7001 7002 fix16997(sc, exp); 7003 exp.type = exp.e1.type; 7004 Type tb = exp.type.toBasetype(); 7005 if (tb.ty == Tarray || tb.ty == Tsarray) 7006 { 7007 if (!isArrayOpValid(exp.e1)) 7008 { 7009 result = arrayOpInvalidError(exp); 7010 return; 7011 } 7012 result = exp; 7013 return; 7014 } 7015 if (!target.isVectorOpSupported(tb, exp.op)) 7016 { 7017 result = exp.incompatibleTypes(); 7018 return; 7019 } 7020 if (exp.e1.checkNoBool()) 7021 return setError(); 7022 if (exp.e1.checkArithmetic() || 7023 exp.e1.checkSharedAccess(sc)) 7024 return setError(); 7025 7026 result = exp; 7027 } 7028 7029 override void visit(UAddExp exp) 7030 { 7031 static if (LOGSEMANTIC) 7032 { 7033 printf("UAddExp::semantic('%s')\n", exp.toChars()); 7034 } 7035 assert(!exp.type); 7036 7037 Expression e = exp.op_overload(sc); 7038 if (e) 7039 { 7040 result = e; 7041 return; 7042 } 7043 7044 fix16997(sc, exp); 7045 if (!target.isVectorOpSupported(exp.e1.type.toBasetype(), exp.op)) 7046 { 7047 result = exp.incompatibleTypes(); 7048 return; 7049 } 7050 if (exp.e1.checkNoBool()) 7051 return setError(); 7052 if (exp.e1.checkArithmetic()) 7053 return setError(); 7054 if (exp.e1.checkSharedAccess(sc)) 7055 return setError(); 7056 7057 result = exp.e1; 7058 } 7059 7060 override void visit(ComExp exp) 7061 { 7062 if (exp.type) 7063 { 7064 result = exp; 7065 return; 7066 } 7067 7068 Expression e = exp.op_overload(sc); 7069 if (e) 7070 { 7071 result = e; 7072 return; 7073 } 7074 7075 fix16997(sc, exp); 7076 exp.type = exp.e1.type; 7077 Type tb = exp.type.toBasetype(); 7078 if (tb.ty == Tarray || tb.ty == Tsarray) 7079 { 7080 if (!isArrayOpValid(exp.e1)) 7081 { 7082 result = arrayOpInvalidError(exp); 7083 return; 7084 } 7085 result = exp; 7086 return; 7087 } 7088 if (!target.isVectorOpSupported(tb, exp.op)) 7089 { 7090 result = exp.incompatibleTypes(); 7091 return; 7092 } 7093 if (exp.e1.checkNoBool()) 7094 return setError(); 7095 if (exp.e1.checkIntegral() || 7096 exp.e1.checkSharedAccess(sc)) 7097 return setError(); 7098 7099 result = exp; 7100 } 7101 7102 override void visit(NotExp e) 7103 { 7104 if (e.type) 7105 { 7106 result = e; 7107 return; 7108 } 7109 7110 e.setNoderefOperand(); 7111 7112 // Note there is no operator overload 7113 if (Expression ex = unaSemantic(e, sc)) 7114 { 7115 result = ex; 7116 return; 7117 } 7118 7119 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684 7120 if (e.e1.op == TOK.type) 7121 e.e1 = resolveAliasThis(sc, e.e1); 7122 7123 e.e1 = resolveProperties(sc, e.e1); 7124 e.e1 = e.e1.toBoolean(sc); 7125 if (e.e1.type == Type.terror) 7126 { 7127 result = e.e1; 7128 return; 7129 } 7130 7131 if (!target.isVectorOpSupported(e.e1.type.toBasetype(), e.op)) 7132 { 7133 result = e.incompatibleTypes(); 7134 } 7135 // https://issues.dlang.org/show_bug.cgi?id=13910 7136 // Today NotExp can take an array as its operand. 7137 if (checkNonAssignmentArrayOp(e.e1)) 7138 return setError(); 7139 7140 e.type = Type.tbool; 7141 result = e; 7142 } 7143 7144 override void visit(DeleteExp exp) 7145 { 7146 if (!sc.isDeprecated) 7147 { 7148 // @@@DEPRECATED_2019-02@@@ 7149 // 1. Deprecation for 1 year 7150 // 2. Error for 1 year 7151 // 3. Removal of keyword, "delete" can be used for other identities 7152 if (!exp.isRAII) 7153 deprecation(exp.loc, "The `delete` keyword has been deprecated. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead."); 7154 } 7155 7156 if (Expression ex = unaSemantic(exp, sc)) 7157 { 7158 result = ex; 7159 return; 7160 } 7161 exp.e1 = resolveProperties(sc, exp.e1); 7162 exp.e1 = exp.e1.modifiableLvalue(sc, null); 7163 if (exp.e1.op == TOK.error) 7164 { 7165 result = exp.e1; 7166 return; 7167 } 7168 exp.type = Type.tvoid; 7169 7170 AggregateDeclaration ad = null; 7171 Type tb = exp.e1.type.toBasetype(); 7172 switch (tb.ty) 7173 { 7174 case Tclass: 7175 { 7176 auto cd = (cast(TypeClass)tb).sym; 7177 if (cd.isCOMinterface()) 7178 { 7179 /* Because COM classes are deleted by IUnknown.Release() 7180 */ 7181 exp.error("cannot `delete` instance of COM interface `%s`", cd.toChars()); 7182 return setError(); 7183 } 7184 ad = cd; 7185 break; 7186 } 7187 case Tpointer: 7188 tb = (cast(TypePointer)tb).next.toBasetype(); 7189 if (tb.ty == Tstruct) 7190 { 7191 ad = (cast(TypeStruct)tb).sym; 7192 semanticTypeInfo(sc, tb); 7193 } 7194 break; 7195 7196 case Tarray: 7197 { 7198 Type tv = tb.nextOf().baseElemOf(); 7199 if (tv.ty == Tstruct) 7200 { 7201 ad = (cast(TypeStruct)tv).sym; 7202 if (ad.dtor) 7203 semanticTypeInfo(sc, ad.type); 7204 } 7205 break; 7206 } 7207 default: 7208 exp.error("cannot delete type `%s`", exp.e1.type.toChars()); 7209 return setError(); 7210 } 7211 7212 bool err = false; 7213 if (ad) 7214 { 7215 if (ad.dtor) 7216 { 7217 err |= !ad.dtor.functionSemantic(); 7218 err |= exp.checkPurity(sc, ad.dtor); 7219 err |= exp.checkSafety(sc, ad.dtor); 7220 err |= exp.checkNogc(sc, ad.dtor); 7221 } 7222 if (err) 7223 return setError(); 7224 } 7225 7226 if (!sc.intypeof && sc.func && 7227 !exp.isRAII && 7228 !(sc.flags & SCOPE.debug_) && 7229 sc.func.setUnsafe()) 7230 { 7231 exp.error("`%s` is not `@safe` but is used in `@safe` function `%s`", exp.toChars(), sc.func.toChars()); 7232 err = true; 7233 } 7234 if (err) 7235 return setError(); 7236 7237 result = exp; 7238 } 7239 7240 override void visit(CastExp exp) 7241 { 7242 static if (LOGSEMANTIC) 7243 { 7244 printf("CastExp::semantic('%s')\n", exp.toChars()); 7245 } 7246 //static int x; assert(++x < 10); 7247 if (exp.type) 7248 { 7249 result = exp; 7250 return; 7251 } 7252 7253 if (exp.to) 7254 { 7255 exp.to = exp.to.typeSemantic(exp.loc, sc); 7256 if (exp.to == Type.terror) 7257 return setError(); 7258 7259 if (!exp.to.hasPointers()) 7260 exp.setNoderefOperand(); 7261 7262 // When e1 is a template lambda, this cast may instantiate it with 7263 // the type 'to'. 7264 exp.e1 = inferType(exp.e1, exp.to); 7265 } 7266 7267 if (auto e = unaSemantic(exp, sc)) 7268 { 7269 result = e; 7270 return; 7271 } 7272 7273 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684 7274 if (exp.e1.op == TOK.type) 7275 exp.e1 = resolveAliasThis(sc, exp.e1); 7276 7277 auto e1x = resolveProperties(sc, exp.e1); 7278 if (e1x.op == TOK.error) 7279 { 7280 result = e1x; 7281 return; 7282 } 7283 if (e1x.checkType()) 7284 return setError(); 7285 exp.e1 = e1x; 7286 7287 if (!exp.e1.type) 7288 { 7289 exp.error("cannot cast `%s`", exp.e1.toChars()); 7290 return setError(); 7291 } 7292 7293 // https://issues.dlang.org/show_bug.cgi?id=19954 7294 if (exp.e1.type.ty == Ttuple) 7295 { 7296 TupleExp te = exp.e1.isTupleExp(); 7297 if (te.exps.dim == 1) 7298 exp.e1 = (*te.exps)[0]; 7299 } 7300 7301 // only allow S(x) rewrite if cast specified S explicitly. 7302 // See https://issues.dlang.org/show_bug.cgi?id=18545 7303 const bool allowImplicitConstruction = exp.to !is null; 7304 7305 if (!exp.to) // Handle cast(const) and cast(immutable), etc. 7306 { 7307 exp.to = exp.e1.type.castMod(exp.mod); 7308 exp.to = exp.to.typeSemantic(exp.loc, sc); 7309 7310 if (exp.to == Type.terror) 7311 return setError(); 7312 } 7313 7314 if (exp.to.ty == Ttuple) 7315 { 7316 exp.error("cannot cast `%s` to tuple type `%s`", exp.e1.toChars(), exp.to.toChars()); 7317 return setError(); 7318 } 7319 7320 // cast(void) is used to mark e1 as unused, so it is safe 7321 if (exp.to.ty == Tvoid) 7322 { 7323 exp.type = exp.to; 7324 result = exp; 7325 return; 7326 } 7327 7328 if (!exp.to.equals(exp.e1.type) && exp.mod == cast(ubyte)~0) 7329 { 7330 if (Expression e = exp.op_overload(sc)) 7331 { 7332 result = e.implicitCastTo(sc, exp.to); 7333 return; 7334 } 7335 } 7336 7337 Type t1b = exp.e1.type.toBasetype(); 7338 Type tob = exp.to.toBasetype(); 7339 7340 if (allowImplicitConstruction && tob.ty == Tstruct && !tob.equals(t1b)) 7341 { 7342 /* Look to replace: 7343 * cast(S)t 7344 * with: 7345 * S(t) 7346 */ 7347 7348 // Rewrite as to.call(e1) 7349 Expression e = new TypeExp(exp.loc, exp.to); 7350 e = new CallExp(exp.loc, e, exp.e1); 7351 e = e.trySemantic(sc); 7352 if (e) 7353 { 7354 result = e; 7355 return; 7356 } 7357 } 7358 7359 if (!t1b.equals(tob) && (t1b.ty == Tarray || t1b.ty == Tsarray)) 7360 { 7361 if (checkNonAssignmentArrayOp(exp.e1)) 7362 return setError(); 7363 } 7364 7365 // Look for casting to a vector type 7366 if (tob.ty == Tvector && t1b.ty != Tvector) 7367 { 7368 result = new VectorExp(exp.loc, exp.e1, exp.to); 7369 result = result.expressionSemantic(sc); 7370 return; 7371 } 7372 7373 Expression ex = exp.e1.castTo(sc, exp.to); 7374 if (ex.op == TOK.error) 7375 { 7376 result = ex; 7377 return; 7378 } 7379 7380 // Check for unsafe casts 7381 if (!sc.intypeof && 7382 !(sc.flags & SCOPE.debug_) && 7383 !isSafeCast(ex, t1b, tob) && 7384 (!sc.func && sc.stc & STC.safe || sc.func && sc.func.setUnsafe())) 7385 { 7386 exp.error("cast from `%s` to `%s` not allowed in safe code", exp.e1.type.toChars(), exp.to.toChars()); 7387 return setError(); 7388 } 7389 7390 // `object.__ArrayCast` is a rewrite of an old runtime hook `_d_arraycast`. `_d_arraycast` was not built 7391 // to handle certain casts. Those casts which `object.__ArrayCast` does not support are filtered out. 7392 // See `e2ir.toElemCast` for other types of casts. If `object.__ArrayCast` is improved to support more 7393 // casts these conditions and potentially some logic in `e2ir.toElemCast` can be removed. 7394 if (tob.ty == Tarray) 7395 { 7396 // https://issues.dlang.org/show_bug.cgi?id=19840 7397 if (auto ad = isAggregate(t1b)) 7398 { 7399 if (ad.aliasthis) 7400 { 7401 Expression e = resolveAliasThis(sc, exp.e1); 7402 e = new CastExp(exp.loc, e, exp.to); 7403 result = e.expressionSemantic(sc); 7404 return; 7405 } 7406 } 7407 7408 if(t1b.ty == Tarray && exp.e1.op != TOK.arrayLiteral && (sc.flags & SCOPE.ctfe) == 0) 7409 { 7410 auto tFrom = t1b.nextOf(); 7411 auto tTo = tob.nextOf(); 7412 7413 // https://issues.dlang.org/show_bug.cgi?id=20130 7414 if (exp.e1.op != TOK.string_ || !ex.isStringExp) 7415 { 7416 const uint fromSize = cast(uint)tFrom.size(); 7417 const uint toSize = cast(uint)tTo.size(); 7418 7419 // If array element sizes do not match, we must adjust the dimensions 7420 if (fromSize != toSize) 7421 { 7422 if (!verifyHookExist(exp.loc, *sc, Id.__ArrayCast, "casting array of structs")) 7423 return setError(); 7424 7425 // A runtime check is needed in case arrays don't line up. That check should 7426 // be done in the implementation of `object.__ArrayCast` 7427 if (toSize == 0 || (fromSize % toSize) != 0) 7428 { 7429 // lower to `object.__ArrayCast!(TFrom, TTo)(from)` 7430 7431 // fully qualify as `object.__ArrayCast` 7432 Expression id = new IdentifierExp(exp.loc, Id.empty); 7433 auto dotid = new DotIdExp(exp.loc, id, Id.object); 7434 7435 auto tiargs = new Objects(); 7436 tiargs.push(tFrom); 7437 tiargs.push(tTo); 7438 auto dt = new DotTemplateInstanceExp(exp.loc, dotid, Id.__ArrayCast, tiargs); 7439 7440 auto arguments = new Expressions(); 7441 arguments.push(exp.e1); 7442 Expression ce = new CallExp(exp.loc, dt, arguments); 7443 7444 result = expressionSemantic(ce, sc); 7445 return; 7446 } 7447 } 7448 } 7449 } 7450 } 7451 7452 result = ex; 7453 } 7454 7455 override void visit(VectorExp exp) 7456 { 7457 static if (LOGSEMANTIC) 7458 { 7459 printf("VectorExp::semantic('%s')\n", exp.toChars()); 7460 } 7461 if (exp.type) 7462 { 7463 result = exp; 7464 return; 7465 } 7466 7467 exp.e1 = exp.e1.expressionSemantic(sc); 7468 exp.type = exp.to.typeSemantic(exp.loc, sc); 7469 if (exp.e1.op == TOK.error || exp.type.ty == Terror) 7470 { 7471 result = exp.e1; 7472 return; 7473 } 7474 7475 Type tb = exp.type.toBasetype(); 7476 assert(tb.ty == Tvector); 7477 TypeVector tv = cast(TypeVector)tb; 7478 Type te = tv.elementType(); 7479 exp.dim = cast(int)(tv.size(exp.loc) / te.size(exp.loc)); 7480 7481 bool checkElem(Expression elem) 7482 { 7483 if (elem.isConst() == 1) 7484 return false; 7485 7486 exp.error("constant expression expected, not `%s`", elem.toChars()); 7487 return true; 7488 } 7489 7490 exp.e1 = exp.e1.optimize(WANTvalue); 7491 bool res; 7492 if (exp.e1.op == TOK.arrayLiteral) 7493 { 7494 foreach (i; 0 .. exp.dim) 7495 { 7496 // Do not stop on first error - check all AST nodes even if error found 7497 res |= checkElem(exp.e1.isArrayLiteralExp()[i]); 7498 } 7499 } 7500 else if (exp.e1.type.ty == Tvoid) 7501 checkElem(exp.e1); 7502 7503 result = res ? ErrorExp.get() : exp; 7504 } 7505 7506 override void visit(VectorArrayExp e) 7507 { 7508 static if (LOGSEMANTIC) 7509 { 7510 printf("VectorArrayExp::semantic('%s')\n", e.toChars()); 7511 } 7512 if (!e.type) 7513 { 7514 unaSemantic(e, sc); 7515 e.e1 = resolveProperties(sc, e.e1); 7516 7517 if (e.e1.op == TOK.error) 7518 { 7519 result = e.e1; 7520 return; 7521 } 7522 assert(e.e1.type.ty == Tvector); 7523 e.type = e.e1.type.isTypeVector().basetype; 7524 } 7525 result = e; 7526 } 7527 7528 override void visit(SliceExp exp) 7529 { 7530 static if (LOGSEMANTIC) 7531 { 7532 printf("SliceExp::semantic('%s')\n", exp.toChars()); 7533 } 7534 if (exp.type) 7535 { 7536 result = exp; 7537 return; 7538 } 7539 7540 // operator overloading should be handled in ArrayExp already. 7541 if (Expression ex = unaSemantic(exp, sc)) 7542 { 7543 result = ex; 7544 return; 7545 } 7546 exp.e1 = resolveProperties(sc, exp.e1); 7547 if (exp.e1.op == TOK.type && exp.e1.type.ty != Ttuple) 7548 { 7549 if (exp.lwr || exp.upr) 7550 { 7551 exp.error("cannot slice type `%s`", exp.e1.toChars()); 7552 return setError(); 7553 } 7554 Expression e = new TypeExp(exp.loc, exp.e1.type.arrayOf()); 7555 result = e.expressionSemantic(sc); 7556 return; 7557 } 7558 if (!exp.lwr && !exp.upr) 7559 { 7560 if (exp.e1.op == TOK.arrayLiteral) 7561 { 7562 // Convert [a,b,c][] to [a,b,c] 7563 Type t1b = exp.e1.type.toBasetype(); 7564 Expression e = exp.e1; 7565 if (t1b.ty == Tsarray) 7566 { 7567 e = e.copy(); 7568 e.type = t1b.nextOf().arrayOf(); 7569 } 7570 result = e; 7571 return; 7572 } 7573 if (exp.e1.op == TOK.slice) 7574 { 7575 // Convert e[][] to e[] 7576 SliceExp se = cast(SliceExp)exp.e1; 7577 if (!se.lwr && !se.upr) 7578 { 7579 result = se; 7580 return; 7581 } 7582 } 7583 if (isArrayOpOperand(exp.e1)) 7584 { 7585 // Convert (a[]+b[])[] to a[]+b[] 7586 result = exp.e1; 7587 return; 7588 } 7589 } 7590 if (exp.e1.op == TOK.error) 7591 { 7592 result = exp.e1; 7593 return; 7594 } 7595 if (exp.e1.type.ty == Terror) 7596 return setError(); 7597 7598 Type t1b = exp.e1.type.toBasetype(); 7599 if (t1b.ty == Tpointer) 7600 { 7601 if ((cast(TypePointer)t1b).next.ty == Tfunction) 7602 { 7603 exp.error("cannot slice function pointer `%s`", exp.e1.toChars()); 7604 return setError(); 7605 } 7606 if (!exp.lwr || !exp.upr) 7607 { 7608 exp.error("need upper and lower bound to slice pointer"); 7609 return setError(); 7610 } 7611 if (sc.func && !sc.intypeof && !(sc.flags & SCOPE.debug_) && sc.func.setUnsafe()) 7612 { 7613 exp.error("pointer slicing not allowed in safe functions"); 7614 return setError(); 7615 } 7616 } 7617 else if (t1b.ty == Tarray) 7618 { 7619 } 7620 else if (t1b.ty == Tsarray) 7621 { 7622 if (!exp.arrayop && global.params.vsafe) 7623 { 7624 /* Slicing a static array is like taking the address of it. 7625 * Perform checks as if e[] was &e 7626 */ 7627 if (VarDeclaration v = expToVariable(exp.e1)) 7628 { 7629 if (exp.e1.op == TOK.dotVariable) 7630 { 7631 DotVarExp dve = cast(DotVarExp)exp.e1; 7632 if ((dve.e1.op == TOK.this_ || dve.e1.op == TOK.super_) && 7633 !(v.storage_class & STC.ref_)) 7634 { 7635 // because it's a class 7636 v = null; 7637 } 7638 } 7639 7640 if (v && !checkAddressVar(sc, exp.e1, v)) 7641 return setError(); 7642 } 7643 } 7644 } 7645 else if (t1b.ty == Ttuple) 7646 { 7647 if (!exp.lwr && !exp.upr) 7648 { 7649 result = exp.e1; 7650 return; 7651 } 7652 if (!exp.lwr || !exp.upr) 7653 { 7654 exp.error("need upper and lower bound to slice tuple"); 7655 return setError(); 7656 } 7657 } 7658 else if (t1b.ty == Tvector) 7659 { 7660 // Convert e1 to corresponding static array 7661 TypeVector tv1 = cast(TypeVector)t1b; 7662 t1b = tv1.basetype; 7663 t1b = t1b.castMod(tv1.mod); 7664 exp.e1.type = t1b; 7665 } 7666 else 7667 { 7668 exp.error("`%s` cannot be sliced with `[]`", t1b.ty == Tvoid ? exp.e1.toChars() : t1b.toChars()); 7669 return setError(); 7670 } 7671 7672 /* Run semantic on lwr and upr. 7673 */ 7674 Scope* scx = sc; 7675 if (t1b.ty == Tsarray || t1b.ty == Tarray || t1b.ty == Ttuple) 7676 { 7677 // Create scope for 'length' variable 7678 ScopeDsymbol sym = new ArrayScopeSymbol(sc, exp); 7679 sym.parent = sc.scopesym; 7680 sc = sc.push(sym); 7681 } 7682 if (exp.lwr) 7683 { 7684 if (t1b.ty == Ttuple) 7685 sc = sc.startCTFE(); 7686 exp.lwr = exp.lwr.expressionSemantic(sc); 7687 exp.lwr = resolveProperties(sc, exp.lwr); 7688 if (t1b.ty == Ttuple) 7689 sc = sc.endCTFE(); 7690 exp.lwr = exp.lwr.implicitCastTo(sc, Type.tsize_t); 7691 } 7692 if (exp.upr) 7693 { 7694 if (t1b.ty == Ttuple) 7695 sc = sc.startCTFE(); 7696 exp.upr = exp.upr.expressionSemantic(sc); 7697 exp.upr = resolveProperties(sc, exp.upr); 7698 if (t1b.ty == Ttuple) 7699 sc = sc.endCTFE(); 7700 exp.upr = exp.upr.implicitCastTo(sc, Type.tsize_t); 7701 } 7702 if (sc != scx) 7703 sc = sc.pop(); 7704 if (exp.lwr && exp.lwr.type == Type.terror || exp.upr && exp.upr.type == Type.terror) 7705 return setError(); 7706 7707 if (t1b.ty == Ttuple) 7708 { 7709 exp.lwr = exp.lwr.ctfeInterpret(); 7710 exp.upr = exp.upr.ctfeInterpret(); 7711 uinteger_t i1 = exp.lwr.toUInteger(); 7712 uinteger_t i2 = exp.upr.toUInteger(); 7713 7714 TupleExp te; 7715 TypeTuple tup; 7716 size_t length; 7717 if (exp.e1.op == TOK.tuple) // slicing an expression tuple 7718 { 7719 te = cast(TupleExp)exp.e1; 7720 tup = null; 7721 length = te.exps.dim; 7722 } 7723 else if (exp.e1.op == TOK.type) // slicing a type tuple 7724 { 7725 te = null; 7726 tup = cast(TypeTuple)t1b; 7727 length = Parameter.dim(tup.arguments); 7728 } 7729 else 7730 assert(0); 7731 7732 if (i2 < i1 || length < i2) 7733 { 7734 exp.error("string slice `[%llu .. %llu]` is out of bounds", i1, i2); 7735 return setError(); 7736 } 7737 7738 size_t j1 = cast(size_t)i1; 7739 size_t j2 = cast(size_t)i2; 7740 Expression e; 7741 if (exp.e1.op == TOK.tuple) 7742 { 7743 auto exps = new Expressions(j2 - j1); 7744 for (size_t i = 0; i < j2 - j1; i++) 7745 { 7746 (*exps)[i] = (*te.exps)[j1 + i]; 7747 } 7748 e = new TupleExp(exp.loc, te.e0, exps); 7749 } 7750 else 7751 { 7752 auto args = new Parameters(); 7753 args.reserve(j2 - j1); 7754 for (size_t i = j1; i < j2; i++) 7755 { 7756 Parameter arg = Parameter.getNth(tup.arguments, i); 7757 args.push(arg); 7758 } 7759 e = new TypeExp(exp.e1.loc, new TypeTuple(args)); 7760 } 7761 e = e.expressionSemantic(sc); 7762 result = e; 7763 return; 7764 } 7765 7766 exp.type = t1b.nextOf().arrayOf(); 7767 // Allow typedef[] -> typedef[] 7768 if (exp.type.equals(t1b)) 7769 exp.type = exp.e1.type; 7770 7771 // We might know $ now 7772 setLengthVarIfKnown(exp.lengthVar, t1b); 7773 7774 if (exp.lwr && exp.upr) 7775 { 7776 exp.lwr = exp.lwr.optimize(WANTvalue); 7777 exp.upr = exp.upr.optimize(WANTvalue); 7778 7779 IntRange lwrRange = getIntRange(exp.lwr); 7780 IntRange uprRange = getIntRange(exp.upr); 7781 7782 if (t1b.ty == Tsarray || t1b.ty == Tarray) 7783 { 7784 Expression el = new ArrayLengthExp(exp.loc, exp.e1); 7785 el = el.expressionSemantic(sc); 7786 el = el.optimize(WANTvalue); 7787 if (el.op == TOK.int64) 7788 { 7789 // Array length is known at compile-time. Upper is in bounds if it fits length. 7790 dinteger_t length = el.toInteger(); 7791 auto bounds = IntRange(SignExtendedNumber(0), SignExtendedNumber(length)); 7792 exp.upperIsInBounds = bounds.contains(uprRange); 7793 } 7794 else if (exp.upr.op == TOK.int64 && exp.upr.toInteger() == 0) 7795 { 7796 // Upper slice expression is '0'. Value is always in bounds. 7797 exp.upperIsInBounds = true; 7798 } 7799 else if (exp.upr.op == TOK.variable && (cast(VarExp)exp.upr).var.ident == Id.dollar) 7800 { 7801 // Upper slice expression is '$'. Value is always in bounds. 7802 exp.upperIsInBounds = true; 7803 } 7804 } 7805 else if (t1b.ty == Tpointer) 7806 { 7807 exp.upperIsInBounds = true; 7808 } 7809 else 7810 assert(0); 7811 7812 exp.lowerIsLessThanUpper = (lwrRange.imax <= uprRange.imin); 7813 7814 //printf("upperIsInBounds = %d lowerIsLessThanUpper = %d\n", exp.upperIsInBounds, exp.lowerIsLessThanUpper); 7815 } 7816 7817 result = exp; 7818 } 7819 7820 override void visit(ArrayLengthExp e) 7821 { 7822 static if (LOGSEMANTIC) 7823 { 7824 printf("ArrayLengthExp::semantic('%s')\n", e.toChars()); 7825 } 7826 if (e.type) 7827 { 7828 result = e; 7829 return; 7830 } 7831 7832 if (Expression ex = unaSemantic(e, sc)) 7833 { 7834 result = ex; 7835 return; 7836 } 7837 e.e1 = resolveProperties(sc, e.e1); 7838 7839 e.type = Type.tsize_t; 7840 result = e; 7841 } 7842 7843 override void visit(ArrayExp exp) 7844 { 7845 static if (LOGSEMANTIC) 7846 { 7847 printf("ArrayExp::semantic('%s')\n", exp.toChars()); 7848 } 7849 assert(!exp.type); 7850 Expression e = exp.op_overload(sc); 7851 if (e) 7852 { 7853 result = e; 7854 return; 7855 } 7856 7857 if (isAggregate(exp.e1.type)) 7858 exp.error("no `[]` operator overload for type `%s`", exp.e1.type.toChars()); 7859 else if (exp.e1.op == TOK.type && exp.e1.type.ty != Ttuple) 7860 exp.error("static array of `%s` with multiple lengths not allowed", exp.e1.type.toChars()); 7861 else if (isIndexableNonAggregate(exp.e1.type)) 7862 exp.error("only one index allowed to index `%s`", exp.e1.type.toChars()); 7863 else 7864 exp.error("cannot use `[]` operator on expression of type `%s`", exp.e1.type.toChars()); 7865 7866 result = ErrorExp.get(); 7867 } 7868 7869 override void visit(DotExp exp) 7870 { 7871 static if (LOGSEMANTIC) 7872 { 7873 printf("DotExp::semantic('%s')\n", exp.toChars()); 7874 if (exp.type) 7875 printf("\ttype = %s\n", exp.type.toChars()); 7876 } 7877 exp.e1 = exp.e1.expressionSemantic(sc); 7878 exp.e2 = exp.e2.expressionSemantic(sc); 7879 7880 if (exp.e1.op == TOK.type) 7881 { 7882 result = exp.e2; 7883 return; 7884 } 7885 if (exp.e2.op == TOK.type) 7886 { 7887 result = exp.e2; 7888 return; 7889 } 7890 if (exp.e2.op == TOK.template_) 7891 { 7892 auto td = (cast(TemplateExp)exp.e2).td; 7893 Expression e = new DotTemplateExp(exp.loc, exp.e1, td); 7894 result = e.expressionSemantic(sc); 7895 return; 7896 } 7897 if (!exp.type || exp.e1.op == TOK.this_) 7898 exp.type = exp.e2.type; 7899 result = exp; 7900 } 7901 7902 override void visit(CommaExp e) 7903 { 7904 if (e.type) 7905 { 7906 result = e; 7907 return; 7908 } 7909 7910 // Allow `((a,b),(x,y))` 7911 if (e.allowCommaExp) 7912 { 7913 CommaExp.allow(e.e1); 7914 CommaExp.allow(e.e2); 7915 } 7916 7917 if (Expression ex = binSemanticProp(e, sc)) 7918 { 7919 result = ex; 7920 return; 7921 } 7922 e.e1 = e.e1.addDtorHook(sc); 7923 7924 if (checkNonAssignmentArrayOp(e.e1)) 7925 return setError(); 7926 7927 e.type = e.e2.type; 7928 if (e.type is Type.tvoid) 7929 discardValue(e.e1); 7930 else if (!e.allowCommaExp && !e.isGenerated) 7931 e.error("Using the result of a comma expression is not allowed"); 7932 result = e; 7933 } 7934 7935 override void visit(IntervalExp e) 7936 { 7937 static if (LOGSEMANTIC) 7938 { 7939 printf("IntervalExp::semantic('%s')\n", e.toChars()); 7940 } 7941 if (e.type) 7942 { 7943 result = e; 7944 return; 7945 } 7946 7947 Expression le = e.lwr; 7948 le = le.expressionSemantic(sc); 7949 le = resolveProperties(sc, le); 7950 7951 Expression ue = e.upr; 7952 ue = ue.expressionSemantic(sc); 7953 ue = resolveProperties(sc, ue); 7954 7955 if (le.op == TOK.error) 7956 { 7957 result = le; 7958 return; 7959 } 7960 if (ue.op == TOK.error) 7961 { 7962 result = ue; 7963 return; 7964 } 7965 7966 e.lwr = le; 7967 e.upr = ue; 7968 7969 e.type = Type.tvoid; 7970 result = e; 7971 } 7972 7973 override void visit(DelegatePtrExp e) 7974 { 7975 static if (LOGSEMANTIC) 7976 { 7977 printf("DelegatePtrExp::semantic('%s')\n", e.toChars()); 7978 } 7979 if (!e.type) 7980 { 7981 unaSemantic(e, sc); 7982 e.e1 = resolveProperties(sc, e.e1); 7983 7984 if (e.e1.op == TOK.error) 7985 { 7986 result = e.e1; 7987 return; 7988 } 7989 e.type = Type.tvoidptr; 7990 } 7991 result = e; 7992 } 7993 7994 override void visit(DelegateFuncptrExp e) 7995 { 7996 static if (LOGSEMANTIC) 7997 { 7998 printf("DelegateFuncptrExp::semantic('%s')\n", e.toChars()); 7999 } 8000 if (!e.type) 8001 { 8002 unaSemantic(e, sc); 8003 e.e1 = resolveProperties(sc, e.e1); 8004 if (e.e1.op == TOK.error) 8005 { 8006 result = e.e1; 8007 return; 8008 } 8009 e.type = e.e1.type.nextOf().pointerTo(); 8010 } 8011 result = e; 8012 } 8013 8014 override void visit(IndexExp exp) 8015 { 8016 static if (LOGSEMANTIC) 8017 { 8018 printf("IndexExp::semantic('%s')\n", exp.toChars()); 8019 } 8020 if (exp.type) 8021 { 8022 result = exp; 8023 return; 8024 } 8025 8026 // operator overloading should be handled in ArrayExp already. 8027 if (!exp.e1.type) 8028 exp.e1 = exp.e1.expressionSemantic(sc); 8029 assert(exp.e1.type); // semantic() should already be run on it 8030 if (exp.e1.op == TOK.type && exp.e1.type.ty != Ttuple) 8031 { 8032 exp.e2 = exp.e2.expressionSemantic(sc); 8033 exp.e2 = resolveProperties(sc, exp.e2); 8034 Type nt; 8035 if (exp.e2.op == TOK.type) 8036 nt = new TypeAArray(exp.e1.type, exp.e2.type); 8037 else 8038 nt = new TypeSArray(exp.e1.type, exp.e2); 8039 Expression e = new TypeExp(exp.loc, nt); 8040 result = e.expressionSemantic(sc); 8041 return; 8042 } 8043 if (exp.e1.op == TOK.error) 8044 { 8045 result = exp.e1; 8046 return; 8047 } 8048 if (exp.e1.type.ty == Terror) 8049 return setError(); 8050 8051 // Note that unlike C we do not implement the int[ptr] 8052 8053 Type t1b = exp.e1.type.toBasetype(); 8054 8055 if (t1b.ty == Tvector) 8056 { 8057 // Convert e1 to corresponding static array 8058 TypeVector tv1 = cast(TypeVector)t1b; 8059 t1b = tv1.basetype; 8060 t1b = t1b.castMod(tv1.mod); 8061 exp.e1.type = t1b; 8062 } 8063 8064 /* Run semantic on e2 8065 */ 8066 Scope* scx = sc; 8067 if (t1b.ty == Tsarray || t1b.ty == Tarray || t1b.ty == Ttuple) 8068 { 8069 // Create scope for 'length' variable 8070 ScopeDsymbol sym = new ArrayScopeSymbol(sc, exp); 8071 sym.parent = sc.scopesym; 8072 sc = sc.push(sym); 8073 } 8074 if (t1b.ty == Ttuple) 8075 sc = sc.startCTFE(); 8076 exp.e2 = exp.e2.expressionSemantic(sc); 8077 exp.e2 = resolveProperties(sc, exp.e2); 8078 if (t1b.ty == Ttuple) 8079 sc = sc.endCTFE(); 8080 if (exp.e2.op == TOK.tuple) 8081 { 8082 TupleExp te = cast(TupleExp)exp.e2; 8083 if (te.exps && te.exps.dim == 1) 8084 exp.e2 = Expression.combine(te.e0, (*te.exps)[0]); // bug 4444 fix 8085 } 8086 if (sc != scx) 8087 sc = sc.pop(); 8088 if (exp.e2.type == Type.terror) 8089 return setError(); 8090 8091 if (checkNonAssignmentArrayOp(exp.e1)) 8092 return setError(); 8093 8094 switch (t1b.ty) 8095 { 8096 case Tpointer: 8097 if ((cast(TypePointer)t1b).next.ty == Tfunction) 8098 { 8099 exp.error("cannot index function pointer `%s`", exp.e1.toChars()); 8100 return setError(); 8101 } 8102 exp.e2 = exp.e2.implicitCastTo(sc, Type.tsize_t); 8103 if (exp.e2.type == Type.terror) 8104 return setError(); 8105 exp.e2 = exp.e2.optimize(WANTvalue); 8106 if (exp.e2.op == TOK.int64 && exp.e2.toInteger() == 0) 8107 { 8108 } 8109 else if (sc.func && !(sc.flags & SCOPE.debug_) && sc.func.setUnsafe()) 8110 { 8111 exp.error("safe function `%s` cannot index pointer `%s`", sc.func.toPrettyChars(), exp.e1.toChars()); 8112 return setError(); 8113 } 8114 exp.type = (cast(TypeNext)t1b).next; 8115 break; 8116 8117 case Tarray: 8118 exp.e2 = exp.e2.implicitCastTo(sc, Type.tsize_t); 8119 if (exp.e2.type == Type.terror) 8120 return setError(); 8121 exp.type = (cast(TypeNext)t1b).next; 8122 break; 8123 8124 case Tsarray: 8125 { 8126 exp.e2 = exp.e2.implicitCastTo(sc, Type.tsize_t); 8127 if (exp.e2.type == Type.terror) 8128 return setError(); 8129 exp.type = t1b.nextOf(); 8130 break; 8131 } 8132 case Taarray: 8133 { 8134 TypeAArray taa = cast(TypeAArray)t1b; 8135 /* We can skip the implicit conversion if they differ only by 8136 * constness 8137 * https://issues.dlang.org/show_bug.cgi?id=2684 8138 * see also bug https://issues.dlang.org/show_bug.cgi?id=2954 b 8139 */ 8140 if (!arrayTypeCompatibleWithoutCasting(exp.e2.type, taa.index)) 8141 { 8142 exp.e2 = exp.e2.implicitCastTo(sc, taa.index); // type checking 8143 if (exp.e2.type == Type.terror) 8144 return setError(); 8145 } 8146 8147 semanticTypeInfo(sc, taa); 8148 8149 exp.type = taa.next; 8150 break; 8151 } 8152 case Ttuple: 8153 { 8154 exp.e2 = exp.e2.implicitCastTo(sc, Type.tsize_t); 8155 if (exp.e2.type == Type.terror) 8156 return setError(); 8157 8158 exp.e2 = exp.e2.ctfeInterpret(); 8159 uinteger_t index = exp.e2.toUInteger(); 8160 8161 TupleExp te; 8162 TypeTuple tup; 8163 size_t length; 8164 if (exp.e1.op == TOK.tuple) 8165 { 8166 te = cast(TupleExp)exp.e1; 8167 tup = null; 8168 length = te.exps.dim; 8169 } 8170 else if (exp.e1.op == TOK.type) 8171 { 8172 te = null; 8173 tup = cast(TypeTuple)t1b; 8174 length = Parameter.dim(tup.arguments); 8175 } 8176 else 8177 assert(0); 8178 8179 if (length <= index) 8180 { 8181 exp.error("array index `[%llu]` is outside array bounds `[0 .. %llu]`", index, cast(ulong)length); 8182 return setError(); 8183 } 8184 Expression e; 8185 if (exp.e1.op == TOK.tuple) 8186 { 8187 e = (*te.exps)[cast(size_t)index]; 8188 e = Expression.combine(te.e0, e); 8189 } 8190 else 8191 e = new TypeExp(exp.e1.loc, Parameter.getNth(tup.arguments, cast(size_t)index).type); 8192 result = e; 8193 return; 8194 } 8195 default: 8196 exp.error("`%s` must be an array or pointer type, not `%s`", exp.e1.toChars(), exp.e1.type.toChars()); 8197 return setError(); 8198 } 8199 8200 // We might know $ now 8201 setLengthVarIfKnown(exp.lengthVar, t1b); 8202 8203 if (t1b.ty == Tsarray || t1b.ty == Tarray) 8204 { 8205 Expression el = new ArrayLengthExp(exp.loc, exp.e1); 8206 el = el.expressionSemantic(sc); 8207 el = el.optimize(WANTvalue); 8208 if (el.op == TOK.int64) 8209 { 8210 exp.e2 = exp.e2.optimize(WANTvalue); 8211 dinteger_t length = el.toInteger(); 8212 if (length) 8213 { 8214 auto bounds = IntRange(SignExtendedNumber(0), SignExtendedNumber(length - 1)); 8215 exp.indexIsInBounds = bounds.contains(getIntRange(exp.e2)); 8216 } 8217 } 8218 } 8219 8220 result = exp; 8221 } 8222 8223 override void visit(PostExp exp) 8224 { 8225 static if (LOGSEMANTIC) 8226 { 8227 printf("PostExp::semantic('%s')\n", exp.toChars()); 8228 } 8229 if (exp.type) 8230 { 8231 result = exp; 8232 return; 8233 } 8234 8235 if (Expression ex = binSemantic(exp, sc)) 8236 { 8237 result = ex; 8238 return; 8239 } 8240 Expression e1x = resolveProperties(sc, exp.e1); 8241 if (e1x.op == TOK.error) 8242 { 8243 result = e1x; 8244 return; 8245 } 8246 exp.e1 = e1x; 8247 8248 Expression e = exp.op_overload(sc); 8249 if (e) 8250 { 8251 result = e; 8252 return; 8253 } 8254 8255 if (exp.e1.checkReadModifyWrite(exp.op)) 8256 return setError(); 8257 8258 if (exp.e1.op == TOK.slice) 8259 { 8260 const(char)* s = exp.op == TOK.plusPlus ? "increment" : "decrement"; 8261 exp.error("cannot post-%s array slice `%s`, use pre-%s instead", s, exp.e1.toChars(), s); 8262 return setError(); 8263 } 8264 8265 exp.e1 = exp.e1.optimize(WANTvalue, /*keepLvalue*/ true); 8266 8267 Type t1 = exp.e1.type.toBasetype(); 8268 if (t1.ty == Tclass || t1.ty == Tstruct || exp.e1.op == TOK.arrayLength) 8269 { 8270 /* Check for operator overloading, 8271 * but rewrite in terms of ++e instead of e++ 8272 */ 8273 8274 /* If e1 is not trivial, take a reference to it 8275 */ 8276 Expression de = null; 8277 if (exp.e1.op != TOK.variable && exp.e1.op != TOK.arrayLength) 8278 { 8279 // ref v = e1; 8280 auto v = copyToTemp(STC.ref_, "__postref", exp.e1); 8281 de = new DeclarationExp(exp.loc, v); 8282 exp.e1 = new VarExp(exp.e1.loc, v); 8283 } 8284 8285 /* Rewrite as: 8286 * auto tmp = e1; ++e1; tmp 8287 */ 8288 auto tmp = copyToTemp(0, "__pitmp", exp.e1); 8289 Expression ea = new DeclarationExp(exp.loc, tmp); 8290 8291 Expression eb = exp.e1.syntaxCopy(); 8292 eb = new PreExp(exp.op == TOK.plusPlus ? TOK.prePlusPlus : TOK.preMinusMinus, exp.loc, eb); 8293 8294 Expression ec = new VarExp(exp.loc, tmp); 8295 8296 // Combine de,ea,eb,ec 8297 if (de) 8298 ea = new CommaExp(exp.loc, de, ea); 8299 e = new CommaExp(exp.loc, ea, eb); 8300 e = new CommaExp(exp.loc, e, ec); 8301 e = e.expressionSemantic(sc); 8302 result = e; 8303 return; 8304 } 8305 8306 exp.e1 = exp.e1.modifiableLvalue(sc, exp.e1); 8307 8308 e = exp; 8309 if (exp.e1.checkScalar() || 8310 exp.e1.checkSharedAccess(sc)) 8311 return setError(); 8312 if (exp.e1.checkNoBool()) 8313 return setError(); 8314 8315 if (exp.e1.type.ty == Tpointer) 8316 e = scaleFactor(exp, sc); 8317 else 8318 exp.e2 = exp.e2.castTo(sc, exp.e1.type); 8319 e.type = exp.e1.type; 8320 result = e; 8321 } 8322 8323 override void visit(PreExp exp) 8324 { 8325 Expression e = exp.op_overload(sc); 8326 // printf("PreExp::semantic('%s')\n", toChars()); 8327 if (e) 8328 { 8329 result = e; 8330 return; 8331 } 8332 8333 // Rewrite as e1+=1 or e1-=1 8334 if (exp.op == TOK.prePlusPlus) 8335 e = new AddAssignExp(exp.loc, exp.e1, IntegerExp.literal!1); 8336 else 8337 e = new MinAssignExp(exp.loc, exp.e1, IntegerExp.literal!1); 8338 result = e.expressionSemantic(sc); 8339 } 8340 8341 /* 8342 * Get the expression initializer for a specific struct 8343 * 8344 * Params: 8345 * sd = the struct for which the expression initializer is needed 8346 * loc = the location of the initializer 8347 * sc = the scope where the expression is located 8348 * t = the type of the expression 8349 * 8350 * Returns: 8351 * The expression initializer or error expression if any errors occured 8352 */ 8353 private Expression getInitExp(StructDeclaration sd, Loc loc, Scope* sc, Type t) 8354 { 8355 if (sd.zeroInit && !sd.isNested()) 8356 { 8357 // https://issues.dlang.org/show_bug.cgi?id=14606 8358 // Always use BlitExp for the special expression: (struct = 0) 8359 return IntegerExp.literal!0; 8360 } 8361 8362 if (sd.isNested()) 8363 { 8364 auto sle = new StructLiteralExp(loc, sd, null, t); 8365 if (!sd.fill(loc, sle.elements, true)) 8366 return ErrorExp.get(); 8367 if (checkFrameAccess(loc, sc, sd, sle.elements.dim)) 8368 return ErrorExp.get(); 8369 8370 sle.type = t; 8371 return sle; 8372 } 8373 8374 return t.defaultInit(loc); 8375 } 8376 8377 override void visit(AssignExp exp) 8378 { 8379 static if (LOGSEMANTIC) 8380 { 8381 printf("AssignExp::semantic('%s')\n", exp.toChars()); 8382 } 8383 //printf("exp.e1.op = %d, '%s'\n", exp.e1.op, Token.toChars(exp.e1.op)); 8384 //printf("exp.e2.op = %d, '%s'\n", exp.e2.op, Token.toChars(exp.e2.op)); 8385 8386 void setResult(Expression e, int line = __LINE__) 8387 { 8388 //printf("line %d\n", line); 8389 result = e; 8390 } 8391 8392 if (exp.type) 8393 { 8394 return setResult(exp); 8395 } 8396 8397 Expression e1old = exp.e1; 8398 8399 if (auto e2comma = exp.e2.isCommaExp()) 8400 { 8401 if (!e2comma.isGenerated) 8402 exp.error("Using the result of a comma expression is not allowed"); 8403 8404 /* Rewrite to get rid of the comma from rvalue 8405 * e1=(e0,e2) => e0,(e1=e2) 8406 */ 8407 Expression e0; 8408 exp.e2 = Expression.extractLast(e2comma, e0); 8409 Expression e = Expression.combine(e0, exp); 8410 return setResult(e.expressionSemantic(sc)); 8411 } 8412 8413 /* Look for operator overloading of a[arguments] = e2. 8414 * Do it before e1.expressionSemantic() otherwise the ArrayExp will have been 8415 * converted to unary operator overloading already. 8416 */ 8417 if (auto ae = exp.e1.isArrayExp()) 8418 { 8419 Expression res; 8420 8421 ae.e1 = ae.e1.expressionSemantic(sc); 8422 ae.e1 = resolveProperties(sc, ae.e1); 8423 Expression ae1old = ae.e1; 8424 8425 const(bool) maybeSlice = 8426 (ae.arguments.dim == 0 || 8427 ae.arguments.dim == 1 && (*ae.arguments)[0].op == TOK.interval); 8428 8429 IntervalExp ie = null; 8430 if (maybeSlice && ae.arguments.dim) 8431 { 8432 assert((*ae.arguments)[0].op == TOK.interval); 8433 ie = cast(IntervalExp)(*ae.arguments)[0]; 8434 } 8435 while (true) 8436 { 8437 if (ae.e1.op == TOK.error) 8438 return setResult(ae.e1); 8439 8440 Expression e0 = null; 8441 Expression ae1save = ae.e1; 8442 ae.lengthVar = null; 8443 8444 Type t1b = ae.e1.type.toBasetype(); 8445 AggregateDeclaration ad = isAggregate(t1b); 8446 if (!ad) 8447 break; 8448 if (search_function(ad, Id.indexass)) 8449 { 8450 // Deal with $ 8451 res = resolveOpDollar(sc, ae, &e0); 8452 if (!res) // a[i..j] = e2 might be: a.opSliceAssign(e2, i, j) 8453 goto Lfallback; 8454 if (res.op == TOK.error) 8455 return setResult(res); 8456 8457 res = exp.e2.expressionSemantic(sc); 8458 if (res.op == TOK.error) 8459 return setResult(res); 8460 exp.e2 = res; 8461 8462 /* Rewrite (a[arguments] = e2) as: 8463 * a.opIndexAssign(e2, arguments) 8464 */ 8465 Expressions* a = ae.arguments.copy(); 8466 a.insert(0, exp.e2); 8467 res = new DotIdExp(exp.loc, ae.e1, Id.indexass); 8468 res = new CallExp(exp.loc, res, a); 8469 if (maybeSlice) // a[] = e2 might be: a.opSliceAssign(e2) 8470 res = res.trySemantic(sc); 8471 else 8472 res = res.expressionSemantic(sc); 8473 if (res) 8474 return setResult(Expression.combine(e0, res)); 8475 } 8476 8477 Lfallback: 8478 if (maybeSlice && search_function(ad, Id.sliceass)) 8479 { 8480 // Deal with $ 8481 res = resolveOpDollar(sc, ae, ie, &e0); 8482 if (res.op == TOK.error) 8483 return setResult(res); 8484 8485 res = exp.e2.expressionSemantic(sc); 8486 if (res.op == TOK.error) 8487 return setResult(res); 8488 8489 exp.e2 = res; 8490 8491 /* Rewrite (a[i..j] = e2) as: 8492 * a.opSliceAssign(e2, i, j) 8493 */ 8494 auto a = new Expressions(); 8495 a.push(exp.e2); 8496 if (ie) 8497 { 8498 a.push(ie.lwr); 8499 a.push(ie.upr); 8500 } 8501 res = new DotIdExp(exp.loc, ae.e1, Id.sliceass); 8502 res = new CallExp(exp.loc, res, a); 8503 res = res.expressionSemantic(sc); 8504 return setResult(Expression.combine(e0, res)); 8505 } 8506 8507 // No operator overloading member function found yet, but 8508 // there might be an alias this to try. 8509 if (ad.aliasthis && !(ae.att1 && t1b.equivalent(ae.att1))) 8510 { 8511 if (!ae.att1 && t1b.checkAliasThisRec()) 8512 ae.att1 = t1b; 8513 8514 /* Rewrite (a[arguments] op e2) as: 8515 * a.aliasthis[arguments] op e2 8516 */ 8517 ae.e1 = resolveAliasThis(sc, ae1save, true); 8518 if (ae.e1) 8519 continue; 8520 } 8521 break; 8522 } 8523 ae.e1 = ae1old; // recovery 8524 ae.lengthVar = null; 8525 } 8526 8527 /* Run this.e1 semantic. 8528 */ 8529 { 8530 Expression e1x = exp.e1; 8531 8532 /* With UFCS, e.f = value 8533 * Could mean: 8534 * .f(e, value) 8535 * or: 8536 * .f(e) = value 8537 */ 8538 if (auto dti = e1x.isDotTemplateInstanceExp()) 8539 { 8540 Expression e = dti.semanticY(sc, 1); 8541 if (!e) 8542 { 8543 return setResult(resolveUFCSProperties(sc, e1x, exp.e2)); 8544 } 8545 8546 e1x = e; 8547 } 8548 else if (auto die = e1x.isDotIdExp()) 8549 { 8550 Expression e = die.semanticY(sc, 1); 8551 if (e && isDotOpDispatch(e)) 8552 { 8553 /* https://issues.dlang.org/show_bug.cgi?id=19687 8554 * 8555 * On this branch, e2 is semantically analyzed in resolvePropertiesX, 8556 * but that call is done with gagged errors. That is the only time when 8557 * semantic gets ran on e2, that is why the error never gets to be printed. 8558 * In order to make sure that UFCS is tried with correct parameters, e2 8559 * needs to have semantic ran on it. 8560 */ 8561 exp.e2 = exp.e2.expressionSemantic(sc); 8562 uint errors = global.startGagging(); 8563 e = resolvePropertiesX(sc, e, exp.e2); 8564 if (global.endGagging(errors)) 8565 e = null; /* fall down to UFCS */ 8566 else 8567 return setResult(e); 8568 } 8569 if (!e) 8570 return setResult(resolveUFCSProperties(sc, e1x, exp.e2)); 8571 e1x = e; 8572 } 8573 else 8574 { 8575 if (auto se = e1x.isSliceExp()) 8576 se.arrayop = true; 8577 8578 e1x = e1x.expressionSemantic(sc); 8579 } 8580 8581 /* We have f = value. 8582 * Could mean: 8583 * f(value) 8584 * or: 8585 * f() = value 8586 */ 8587 if (Expression e = resolvePropertiesX(sc, e1x, exp.e2)) 8588 return setResult(e); 8589 8590 if (e1x.checkRightThis(sc)) 8591 { 8592 return setError(); 8593 } 8594 exp.e1 = e1x; 8595 assert(exp.e1.type); 8596 } 8597 Type t1 = exp.e1.type.toBasetype(); 8598 8599 /* Run this.e2 semantic. 8600 * Different from other binary expressions, the analysis of e2 8601 * depends on the result of e1 in assignments. 8602 */ 8603 { 8604 Expression e2x = inferType(exp.e2, t1.baseElemOf()); 8605 e2x = e2x.expressionSemantic(sc); 8606 e2x = resolveProperties(sc, e2x); 8607 if (e2x.op == TOK.type) 8608 e2x = resolveAliasThis(sc, e2x); //https://issues.dlang.org/show_bug.cgi?id=17684 8609 if (e2x.op == TOK.error) 8610 return setResult(e2x); 8611 if (e2x.checkValue() || e2x.checkSharedAccess(sc)) 8612 return setError(); 8613 exp.e2 = e2x; 8614 } 8615 8616 /* Rewrite tuple assignment as a tuple of assignments. 8617 */ 8618 { 8619 Expression e2x = exp.e2; 8620 8621 Ltupleassign: 8622 if (exp.e1.op == TOK.tuple && e2x.op == TOK.tuple) 8623 { 8624 TupleExp tup1 = cast(TupleExp)exp.e1; 8625 TupleExp tup2 = cast(TupleExp)e2x; 8626 size_t dim = tup1.exps.dim; 8627 Expression e = null; 8628 if (dim != tup2.exps.dim) 8629 { 8630 exp.error("mismatched tuple lengths, %d and %d", cast(int)dim, cast(int)tup2.exps.dim); 8631 return setError(); 8632 } 8633 if (dim == 0) 8634 { 8635 e = IntegerExp.literal!0; 8636 e = new CastExp(exp.loc, e, Type.tvoid); // avoid "has no effect" error 8637 e = Expression.combine(tup1.e0, tup2.e0, e); 8638 } 8639 else 8640 { 8641 auto exps = new Expressions(dim); 8642 for (size_t i = 0; i < dim; i++) 8643 { 8644 Expression ex1 = (*tup1.exps)[i]; 8645 Expression ex2 = (*tup2.exps)[i]; 8646 (*exps)[i] = new AssignExp(exp.loc, ex1, ex2); 8647 } 8648 e = new TupleExp(exp.loc, Expression.combine(tup1.e0, tup2.e0), exps); 8649 } 8650 return setResult(e.expressionSemantic(sc)); 8651 } 8652 8653 /* Look for form: e1 = e2.aliasthis. 8654 */ 8655 if (exp.e1.op == TOK.tuple) 8656 { 8657 TupleDeclaration td = isAliasThisTuple(e2x); 8658 if (!td) 8659 goto Lnomatch; 8660 8661 assert(exp.e1.type.ty == Ttuple); 8662 TypeTuple tt = cast(TypeTuple)exp.e1.type; 8663 8664 Expression e0; 8665 Expression ev = extractSideEffect(sc, "__tup", e0, e2x); 8666 8667 auto iexps = new Expressions(); 8668 iexps.push(ev); 8669 for (size_t u = 0; u < iexps.dim; u++) 8670 { 8671 Lexpand: 8672 Expression e = (*iexps)[u]; 8673 8674 Parameter arg = Parameter.getNth(tt.arguments, u); 8675 //printf("[%d] iexps.dim = %d, ", u, iexps.dim); 8676 //printf("e = (%s %s, %s), ", Token::tochars[e.op], e.toChars(), e.type.toChars()); 8677 //printf("arg = (%s, %s)\n", arg.toChars(), arg.type.toChars()); 8678 8679 if (!arg || !e.type.implicitConvTo(arg.type)) 8680 { 8681 // expand initializer to tuple 8682 if (expandAliasThisTuples(iexps, u) != -1) 8683 { 8684 if (iexps.dim <= u) 8685 break; 8686 goto Lexpand; 8687 } 8688 goto Lnomatch; 8689 } 8690 } 8691 e2x = new TupleExp(e2x.loc, e0, iexps); 8692 e2x = e2x.expressionSemantic(sc); 8693 if (e2x.op == TOK.error) 8694 { 8695 result = e2x; 8696 return; 8697 } 8698 // Do not need to overwrite this.e2 8699 goto Ltupleassign; 8700 } 8701 Lnomatch: 8702 } 8703 8704 if (exp.op == TOK.assign) // skip TOK.blit and TOK.construct, which are initializations 8705 exp.e1.checkSharedAccess(sc); 8706 8707 /* Inside constructor, if this is the first assignment of object field, 8708 * rewrite this to initializing the field. 8709 */ 8710 if (exp.op == TOK.assign 8711 && exp.e1.checkModifiable(sc) == Modifiable.initialization) 8712 { 8713 //printf("[%s] change to init - %s\n", exp.loc.toChars(), exp.toChars()); 8714 auto t = exp.type; 8715 exp = new ConstructExp(exp.loc, exp.e1, exp.e2); 8716 exp.type = t; 8717 8718 // @@@DEPRECATED_2020-06@@@ 8719 // When removing, alter `checkModifiable` to return the correct value. 8720 if (sc.func.isStaticCtorDeclaration() && !sc.func.isSharedStaticCtorDeclaration() && 8721 exp.e1.type.isImmutable()) 8722 { 8723 deprecation(exp.loc, "initialization of `immutable` variable from `static this` is deprecated."); 8724 deprecationSupplemental(exp.loc, "Use `shared static this` instead."); 8725 } 8726 8727 // https://issues.dlang.org/show_bug.cgi?id=13515 8728 // set Index::modifiable flag for complex AA element initialization 8729 if (auto ie1 = exp.e1.isIndexExp()) 8730 { 8731 Expression e1x = ie1.markSettingAAElem(); 8732 if (e1x.op == TOK.error) 8733 { 8734 result = e1x; 8735 return; 8736 } 8737 } 8738 } 8739 else if (exp.op == TOK.construct && exp.e1.op == TOK.variable && 8740 (cast(VarExp)exp.e1).var.storage_class & (STC.out_ | STC.ref_)) 8741 { 8742 exp.memset = MemorySet.referenceInit; 8743 } 8744 8745 /* If it is an assignment from a 'foreign' type, 8746 * check for operator overloading. 8747 */ 8748 if (exp.memset == MemorySet.referenceInit) 8749 { 8750 // If this is an initialization of a reference, 8751 // do nothing 8752 } 8753 else if (t1.ty == Tstruct) 8754 { 8755 auto e1x = exp.e1; 8756 auto e2x = exp.e2; 8757 auto sd = (cast(TypeStruct)t1).sym; 8758 8759 if (exp.op == TOK.construct) 8760 { 8761 Type t2 = e2x.type.toBasetype(); 8762 if (t2.ty == Tstruct && sd == (cast(TypeStruct)t2).sym) 8763 { 8764 sd.size(exp.loc); 8765 if (sd.sizeok != Sizeok.done) 8766 return setError(); 8767 if (!sd.ctor) 8768 sd.ctor = sd.searchCtor(); 8769 8770 // https://issues.dlang.org/show_bug.cgi?id=15661 8771 // Look for the form from last of comma chain. 8772 auto e2y = lastComma(e2x); 8773 8774 CallExp ce = (e2y.op == TOK.call) ? cast(CallExp)e2y : null; 8775 DotVarExp dve = (ce && ce.e1.op == TOK.dotVariable) 8776 ? cast(DotVarExp)ce.e1 : null; 8777 if (sd.ctor && ce && dve && dve.var.isCtorDeclaration() && 8778 // https://issues.dlang.org/show_bug.cgi?id=19389 8779 dve.e1.op != TOK.dotVariable && 8780 e2y.type.implicitConvTo(t1)) 8781 { 8782 /* Look for form of constructor call which is: 8783 * __ctmp.ctor(arguments...) 8784 */ 8785 8786 /* Before calling the constructor, initialize 8787 * variable with a bit copy of the default 8788 * initializer 8789 */ 8790 Expression einit = getInitExp(sd, exp.loc, sc, t1); 8791 if (einit.op == TOK.error) 8792 { 8793 result = einit; 8794 return; 8795 } 8796 8797 auto ae = new BlitExp(exp.loc, exp.e1, einit); 8798 ae.type = e1x.type; 8799 8800 /* Replace __ctmp being constructed with e1. 8801 * We need to copy constructor call expression, 8802 * because it may be used in other place. 8803 */ 8804 auto dvx = cast(DotVarExp)dve.copy(); 8805 dvx.e1 = e1x; 8806 auto cx = cast(CallExp)ce.copy(); 8807 cx.e1 = dvx; 8808 if (checkConstructorEscape(sc, cx, false)) 8809 return setError(); 8810 8811 Expression e0; 8812 Expression.extractLast(e2x, e0); 8813 8814 auto e = Expression.combine(e0, ae, cx); 8815 e = e.expressionSemantic(sc); 8816 result = e; 8817 return; 8818 } 8819 // https://issues.dlang.org/show_bug.cgi?id=21586 8820 // Rewrite CondExp or e1 will miss direct construction, e.g. 8821 // e1 = a ? S(1) : ...; -> AST: e1 = a ? (S(0)).this(1) : ...; 8822 // a temporary created and an extra destructor call. 8823 // AST will be rewritten to: 8824 // a ? e1 = 0, e1.this(1) : ...; -> blitting plus construction 8825 if (e2x.op == TOK.question) 8826 { 8827 /* Rewrite as: 8828 * a ? e1 = b : e1 = c; 8829 */ 8830 CondExp econd = cast(CondExp)e2x; 8831 Expression ea1 = new ConstructExp(econd.e1.loc, e1x, econd.e1); 8832 Expression ea2 = new ConstructExp(econd.e2.loc, e1x, econd.e2); 8833 Expression e = new CondExp(exp.loc, econd.econd, ea1, ea2); 8834 result = e.expressionSemantic(sc); 8835 return; 8836 } 8837 if (sd.postblit || sd.hasCopyCtor) 8838 { 8839 /* We have a copy constructor for this 8840 */ 8841 8842 if (e2x.isLvalue()) 8843 { 8844 if (sd.hasCopyCtor) 8845 { 8846 /* Rewrite as: 8847 * e1 = init, e1.copyCtor(e2); 8848 */ 8849 Expression einit = new BlitExp(exp.loc, exp.e1, getInitExp(sd, exp.loc, sc, t1)); 8850 einit.type = e1x.type; 8851 8852 Expression e; 8853 e = new DotIdExp(exp.loc, e1x, Id.ctor); 8854 e = new CallExp(exp.loc, e, e2x); 8855 e = new CommaExp(exp.loc, einit, e); 8856 8857 //printf("e: %s\n", e.toChars()); 8858 8859 result = e.expressionSemantic(sc); 8860 return; 8861 } 8862 else 8863 { 8864 if (!e2x.type.implicitConvTo(e1x.type)) 8865 { 8866 exp.error("conversion error from `%s` to `%s`", 8867 e2x.type.toChars(), e1x.type.toChars()); 8868 return setError(); 8869 } 8870 8871 /* Rewrite as: 8872 * (e1 = e2).postblit(); 8873 * 8874 * Blit assignment e1 = e2 returns a reference to the original e1, 8875 * then call the postblit on it. 8876 */ 8877 Expression e = e1x.copy(); 8878 e.type = e.type.mutableOf(); 8879 if (e.type.isShared && !sd.type.isShared) 8880 e.type = e.type.unSharedOf(); 8881 e = new BlitExp(exp.loc, e, e2x); 8882 e = new DotVarExp(exp.loc, e, sd.postblit, false); 8883 e = new CallExp(exp.loc, e); 8884 result = e.expressionSemantic(sc); 8885 return; 8886 } 8887 } 8888 else 8889 { 8890 /* The struct value returned from the function is transferred 8891 * so should not call the destructor on it. 8892 */ 8893 e2x = valueNoDtor(e2x); 8894 } 8895 } 8896 8897 // https://issues.dlang.org/show_bug.cgi?id=19251 8898 // if e2 cannot be converted to e1.type, maybe there is an alias this 8899 if (!e2x.implicitConvTo(t1)) 8900 { 8901 AggregateDeclaration ad2 = isAggregate(e2x.type); 8902 if (ad2 && ad2.aliasthis && !(exp.att2 && e2x.type.equivalent(exp.att2))) 8903 { 8904 if (!exp.att2 && exp.e2.type.checkAliasThisRec()) 8905 exp.att2 = exp.e2.type; 8906 /* Rewrite (e1 op e2) as: 8907 * (e1 op e2.aliasthis) 8908 */ 8909 exp.e2 = new DotIdExp(exp.e2.loc, exp.e2, ad2.aliasthis.ident); 8910 result = exp.expressionSemantic(sc); 8911 return; 8912 } 8913 } 8914 } 8915 else if (!e2x.implicitConvTo(t1)) 8916 { 8917 sd.size(exp.loc); 8918 if (sd.sizeok != Sizeok.done) 8919 return setError(); 8920 if (!sd.ctor) 8921 sd.ctor = sd.searchCtor(); 8922 8923 if (sd.ctor) 8924 { 8925 /* Look for implicit constructor call 8926 * Rewrite as: 8927 * e1 = init, e1.ctor(e2) 8928 */ 8929 8930 /* Fix Issue 5153 : https://issues.dlang.org/show_bug.cgi?id=5153 8931 * Using `new` to initialize a struct object is a common mistake, but 8932 * the error message from the compiler is not very helpful in that 8933 * case. If exp.e2 is a NewExp and the type of new is the same as 8934 * the type as exp.e1 (struct in this case), then we know for sure 8935 * that the user wants to instantiate a struct. This is done to avoid 8936 * issuing an error when the user actually wants to call a constructor 8937 * which receives a class object. 8938 * 8939 * Foo f = new Foo2(0); is a valid expression if Foo has a constructor 8940 * which receives an instance of a Foo2 class 8941 */ 8942 if (exp.e2.op == TOK.new_) 8943 { 8944 auto newExp = cast(NewExp)(exp.e2); 8945 if (newExp.newtype && newExp.newtype == t1) 8946 { 8947 error(exp.loc, "cannot implicitly convert expression `%s` of type `%s` to `%s`", 8948 newExp.toChars(), newExp.type.toChars(), t1.toChars()); 8949 errorSupplemental(exp.loc, "Perhaps remove the `new` keyword?"); 8950 return setError(); 8951 } 8952 } 8953 8954 Expression einit = new BlitExp(exp.loc, e1x, getInitExp(sd, exp.loc, sc, t1)); 8955 einit.type = e1x.type; 8956 8957 Expression e; 8958 e = new DotIdExp(exp.loc, e1x, Id.ctor); 8959 e = new CallExp(exp.loc, e, e2x); 8960 e = new CommaExp(exp.loc, einit, e); 8961 e = e.expressionSemantic(sc); 8962 result = e; 8963 return; 8964 } 8965 if (search_function(sd, Id.call)) 8966 { 8967 /* Look for static opCall 8968 * https://issues.dlang.org/show_bug.cgi?id=2702 8969 * Rewrite as: 8970 * e1 = typeof(e1).opCall(arguments) 8971 */ 8972 e2x = typeDotIdExp(e2x.loc, e1x.type, Id.call); 8973 e2x = new CallExp(exp.loc, e2x, exp.e2); 8974 8975 e2x = e2x.expressionSemantic(sc); 8976 e2x = resolveProperties(sc, e2x); 8977 if (e2x.op == TOK.error) 8978 { 8979 result = e2x; 8980 return; 8981 } 8982 if (e2x.checkValue() || e2x.checkSharedAccess(sc)) 8983 return setError(); 8984 } 8985 } 8986 else // https://issues.dlang.org/show_bug.cgi?id=11355 8987 { 8988 AggregateDeclaration ad2 = isAggregate(e2x.type); 8989 if (ad2 && ad2.aliasthis && !(exp.att2 && e2x.type.equivalent(exp.att2))) 8990 { 8991 if (!exp.att2 && exp.e2.type.checkAliasThisRec()) 8992 exp.att2 = exp.e2.type; 8993 /* Rewrite (e1 op e2) as: 8994 * (e1 op e2.aliasthis) 8995 */ 8996 exp.e2 = new DotIdExp(exp.e2.loc, exp.e2, ad2.aliasthis.ident); 8997 result = exp.expressionSemantic(sc); 8998 return; 8999 } 9000 } 9001 } 9002 else if (exp.op == TOK.assign) 9003 { 9004 if (e1x.op == TOK.index && (cast(IndexExp)e1x).e1.type.toBasetype().ty == Taarray) 9005 { 9006 /* 9007 * Rewrite: 9008 * aa[key] = e2; 9009 * as: 9010 * ref __aatmp = aa; 9011 * ref __aakey = key; 9012 * ref __aaval = e2; 9013 * (__aakey in __aatmp 9014 * ? __aatmp[__aakey].opAssign(__aaval) 9015 * : ConstructExp(__aatmp[__aakey], __aaval)); 9016 */ 9017 // ensure we keep the expr modifiable 9018 Expression esetting = (cast(IndexExp)e1x).markSettingAAElem(); 9019 if (esetting.op == TOK.error) 9020 { 9021 result = esetting; 9022 return; 9023 } 9024 assert(esetting.op == TOK.index); 9025 IndexExp ie = cast(IndexExp) esetting; 9026 Type t2 = e2x.type.toBasetype(); 9027 9028 Expression e0 = null; 9029 Expression ea = extractSideEffect(sc, "__aatmp", e0, ie.e1); 9030 Expression ek = extractSideEffect(sc, "__aakey", e0, ie.e2); 9031 Expression ev = extractSideEffect(sc, "__aaval", e0, e2x); 9032 9033 AssignExp ae = cast(AssignExp)exp.copy(); 9034 ae.e1 = new IndexExp(exp.loc, ea, ek); 9035 ae.e1 = ae.e1.expressionSemantic(sc); 9036 ae.e1 = ae.e1.optimize(WANTvalue); 9037 ae.e2 = ev; 9038 Expression e = ae.op_overload(sc); 9039 if (e) 9040 { 9041 Expression ey = null; 9042 if (t2.ty == Tstruct && sd == t2.toDsymbol(sc)) 9043 { 9044 ey = ev; 9045 } 9046 else if (!ev.implicitConvTo(ie.type) && sd.ctor) 9047 { 9048 // Look for implicit constructor call 9049 // Rewrite as S().ctor(e2) 9050 ey = new StructLiteralExp(exp.loc, sd, null); 9051 ey = new DotIdExp(exp.loc, ey, Id.ctor); 9052 ey = new CallExp(exp.loc, ey, ev); 9053 ey = ey.trySemantic(sc); 9054 } 9055 if (ey) 9056 { 9057 Expression ex; 9058 ex = new IndexExp(exp.loc, ea, ek); 9059 ex = ex.expressionSemantic(sc); 9060 ex = ex.optimize(WANTvalue); 9061 ex = ex.modifiableLvalue(sc, ex); // allocate new slot 9062 9063 ey = new ConstructExp(exp.loc, ex, ey); 9064 ey = ey.expressionSemantic(sc); 9065 if (ey.op == TOK.error) 9066 { 9067 result = ey; 9068 return; 9069 } 9070 ex = e; 9071 9072 // https://issues.dlang.org/show_bug.cgi?id=14144 9073 // The whole expression should have the common type 9074 // of opAssign() return and assigned AA entry. 9075 // Even if there's no common type, expression should be typed as void. 9076 if (!typeMerge(sc, TOK.question, ex, ey)) 9077 { 9078 ex = new CastExp(ex.loc, ex, Type.tvoid); 9079 ey = new CastExp(ey.loc, ey, Type.tvoid); 9080 } 9081 e = new CondExp(exp.loc, new InExp(exp.loc, ek, ea), ex, ey); 9082 } 9083 e = Expression.combine(e0, e); 9084 e = e.expressionSemantic(sc); 9085 result = e; 9086 return; 9087 } 9088 } 9089 else 9090 { 9091 Expression e = exp.op_overload(sc); 9092 if (e) 9093 { 9094 result = e; 9095 return; 9096 } 9097 } 9098 } 9099 else 9100 assert(exp.op == TOK.blit); 9101 9102 exp.e1 = e1x; 9103 exp.e2 = e2x; 9104 } 9105 else if (t1.ty == Tclass) 9106 { 9107 // Disallow assignment operator overloads for same type 9108 if (exp.op == TOK.assign && !exp.e2.implicitConvTo(exp.e1.type)) 9109 { 9110 Expression e = exp.op_overload(sc); 9111 if (e) 9112 { 9113 result = e; 9114 return; 9115 } 9116 } 9117 } 9118 else if (t1.ty == Tsarray) 9119 { 9120 // SliceExp cannot have static array type without context inference. 9121 assert(exp.e1.op != TOK.slice); 9122 Expression e1x = exp.e1; 9123 Expression e2x = exp.e2; 9124 9125 if (e2x.implicitConvTo(e1x.type)) 9126 { 9127 if (exp.op != TOK.blit && (e2x.op == TOK.slice && (cast(UnaExp)e2x).e1.isLvalue() || e2x.op == TOK.cast_ && (cast(UnaExp)e2x).e1.isLvalue() || e2x.op != TOK.slice && e2x.isLvalue())) 9128 { 9129 if (e1x.checkPostblit(sc, t1)) 9130 return setError(); 9131 } 9132 9133 // e2 matches to t1 because of the implicit length match, so 9134 if (isUnaArrayOp(e2x.op) || isBinArrayOp(e2x.op)) 9135 { 9136 // convert e1 to e1[] 9137 // e.g. e1[] = a[] + b[]; 9138 auto sle = new SliceExp(e1x.loc, e1x, null, null); 9139 sle.arrayop = true; 9140 e1x = sle.expressionSemantic(sc); 9141 } 9142 else 9143 { 9144 // convert e2 to t1 later 9145 // e.g. e1 = [1, 2, 3]; 9146 } 9147 } 9148 else 9149 { 9150 if (e2x.implicitConvTo(t1.nextOf().arrayOf()) > MATCH.nomatch) 9151 { 9152 uinteger_t dim1 = (cast(TypeSArray)t1).dim.toInteger(); 9153 uinteger_t dim2 = dim1; 9154 if (auto ale = e2x.isArrayLiteralExp()) 9155 { 9156 dim2 = ale.elements ? ale.elements.dim : 0; 9157 } 9158 else if (auto se = e2x.isSliceExp()) 9159 { 9160 Type tx = toStaticArrayType(se); 9161 if (tx) 9162 dim2 = (cast(TypeSArray)tx).dim.toInteger(); 9163 } 9164 if (dim1 != dim2) 9165 { 9166 exp.error("mismatched array lengths, %d and %d", cast(int)dim1, cast(int)dim2); 9167 return setError(); 9168 } 9169 } 9170 9171 // May be block or element-wise assignment, so 9172 // convert e1 to e1[] 9173 if (exp.op != TOK.assign) 9174 { 9175 // If multidimensional static array, treat as one large array 9176 // 9177 // Find the appropriate array type depending on the assignment, e.g. 9178 // int[3] = int => int[3] 9179 // int[3][2] = int => int[6] 9180 // int[3][2] = int[] => int[3][2] 9181 // int[3][2][4] + int => int[24] 9182 // int[3][2][4] + int[] => int[3][8] 9183 ulong dim = t1.isTypeSArray().dim.toUInteger(); 9184 auto type = t1.nextOf(); 9185 9186 for (TypeSArray tsa; (tsa = type.isTypeSArray()) !is null; ) 9187 { 9188 import core.checkedint : mulu; 9189 9190 // Accumulate skipped dimensions 9191 bool overflow = false; 9192 dim = mulu(dim, tsa.dim.toUInteger(), overflow); 9193 if (overflow || dim >= uint.max) 9194 { 9195 // dym exceeds maximum array size 9196 exp.error("static array `%s` size overflowed to %llu", 9197 e1x.type.toChars(), cast(ulong) dim); 9198 return setError(); 9199 } 9200 9201 // Move to the element type 9202 type = tsa.nextOf().toBasetype(); 9203 9204 // Rewrite ex1 as a static array if a matching type was found 9205 if (e2x.implicitConvTo(type) > MATCH.nomatch) 9206 { 9207 e1x.type = type.sarrayOf(dim); 9208 break; 9209 } 9210 } 9211 } 9212 auto sle = new SliceExp(e1x.loc, e1x, null, null); 9213 sle.arrayop = true; 9214 e1x = sle.expressionSemantic(sc); 9215 } 9216 if (e1x.op == TOK.error) 9217 return setResult(e1x); 9218 if (e2x.op == TOK.error) 9219 return setResult(e2x); 9220 9221 exp.e1 = e1x; 9222 exp.e2 = e2x; 9223 t1 = e1x.type.toBasetype(); 9224 } 9225 /* Check the mutability of e1. 9226 */ 9227 if (auto ale = exp.e1.isArrayLengthExp()) 9228 { 9229 // e1 is not an lvalue, but we let code generator handle it 9230 9231 auto ale1x = ale.e1.modifiableLvalue(sc, exp.e1); 9232 if (ale1x.op == TOK.error) 9233 return setResult(ale1x); 9234 ale.e1 = ale1x; 9235 9236 Type tn = ale.e1.type.toBasetype().nextOf(); 9237 checkDefCtor(ale.loc, tn); 9238 9239 Identifier hook = global.params.tracegc ? Id._d_arraysetlengthTTrace : Id._d_arraysetlengthT; 9240 if (!verifyHookExist(exp.loc, *sc, Id._d_arraysetlengthTImpl, "resizing arrays")) 9241 return setError(); 9242 9243 // use slice expression when arr.length = 0 to avoid runtime call 9244 if(exp.e2.isConst() && exp.e2.toUInteger() == 0) 9245 { 9246 IntervalExp ie = new IntervalExp(ale.loc, exp.e2, exp.e2); 9247 Expression se = new SliceExp(ale.loc, ale.e1, ie); 9248 Expression as = new AssignExp(ale.loc, ale.e1, se); 9249 auto res = as.expressionSemantic(sc); 9250 return setResult(res); 9251 } 9252 9253 // Lower to object._d_arraysetlengthTImpl!(typeof(e1))._d_arraysetlengthT{,Trace}(e1, e2) 9254 Expression id = new IdentifierExp(ale.loc, Id.empty); 9255 id = new DotIdExp(ale.loc, id, Id.object); 9256 auto tiargs = new Objects(); 9257 tiargs.push(ale.e1.type); 9258 id = new DotTemplateInstanceExp(ale.loc, id, Id._d_arraysetlengthTImpl, tiargs); 9259 id = new DotIdExp(ale.loc, id, hook); 9260 id = id.expressionSemantic(sc); 9261 9262 auto arguments = new Expressions(); 9263 arguments.reserve(5); 9264 if (global.params.tracegc) 9265 { 9266 auto funcname = (sc.callsc && sc.callsc.func) ? sc.callsc.func.toPrettyChars() : sc.func.toPrettyChars(); 9267 arguments.push(new StringExp(exp.loc, exp.loc.filename.toDString())); 9268 arguments.push(new IntegerExp(exp.loc, exp.loc.linnum, Type.tint32)); 9269 arguments.push(new StringExp(exp.loc, funcname.toDString())); 9270 } 9271 arguments.push(ale.e1); 9272 arguments.push(exp.e2); 9273 9274 Expression ce = new CallExp(ale.loc, id, arguments); 9275 auto res = ce.expressionSemantic(sc); 9276 // if (global.params.verbose) 9277 // message("lowered %s =>\n %s", exp.toChars(), res.toChars()); 9278 return setResult(res); 9279 } 9280 else if (auto se = exp.e1.isSliceExp()) 9281 { 9282 Type tn = se.type.nextOf(); 9283 const fun = sc.func; 9284 if (exp.op == TOK.assign && !tn.isMutable() && 9285 // allow modifiation in module ctor, see 9286 // https://issues.dlang.org/show_bug.cgi?id=9884 9287 (!fun || (fun && !fun.isStaticCtorDeclaration()))) 9288 { 9289 exp.error("slice `%s` is not mutable", se.toChars()); 9290 return setError(); 9291 } 9292 9293 if (exp.op == TOK.assign && !tn.baseElemOf().isAssignable()) 9294 { 9295 exp.error("slice `%s` is not mutable, struct `%s` has immutable members", 9296 exp.e1.toChars(), tn.baseElemOf().toChars()); 9297 result = ErrorExp.get(); 9298 return; 9299 } 9300 9301 // For conditional operator, both branches need conversion. 9302 while (se.e1.op == TOK.slice) 9303 se = cast(SliceExp)se.e1; 9304 if (se.e1.op == TOK.question && se.e1.type.toBasetype().ty == Tsarray) 9305 { 9306 se.e1 = se.e1.modifiableLvalue(sc, exp.e1); 9307 if (se.e1.op == TOK.error) 9308 return setResult(se.e1); 9309 } 9310 } 9311 else 9312 { 9313 if (t1.ty == Tsarray && exp.op == TOK.assign) 9314 { 9315 Type tn = exp.e1.type.nextOf(); 9316 if (tn && !tn.baseElemOf().isAssignable()) 9317 { 9318 exp.error("array `%s` is not mutable, struct `%s` has immutable members", 9319 exp.e1.toChars(), tn.baseElemOf().toChars()); 9320 result = ErrorExp.get(); 9321 return; 9322 } 9323 } 9324 9325 Expression e1x = exp.e1; 9326 9327 // Try to do a decent error message with the expression 9328 // before it got constant folded 9329 9330 e1x = e1x.optimize(WANTvalue, /*keepLvalue*/ true); 9331 9332 if (exp.op == TOK.assign) 9333 e1x = e1x.modifiableLvalue(sc, e1old); 9334 9335 if (e1x.op == TOK.error) 9336 { 9337 result = e1x; 9338 return; 9339 } 9340 exp.e1 = e1x; 9341 } 9342 9343 /* Tweak e2 based on the type of e1. 9344 */ 9345 Expression e2x = exp.e2; 9346 Type t2 = e2x.type.toBasetype(); 9347 9348 // If it is a array, get the element type. Note that it may be 9349 // multi-dimensional. 9350 Type telem = t1; 9351 while (telem.ty == Tarray) 9352 telem = telem.nextOf(); 9353 9354 if (exp.e1.op == TOK.slice && t1.nextOf() && 9355 (telem.ty != Tvoid || e2x.op == TOK.null_) && 9356 e2x.implicitConvTo(t1.nextOf())) 9357 { 9358 // Check for block assignment. If it is of type void[], void[][], etc, 9359 // '= null' is the only allowable block assignment (Bug 7493) 9360 exp.memset = MemorySet.blockAssign; // make it easy for back end to tell what this is 9361 e2x = e2x.implicitCastTo(sc, t1.nextOf()); 9362 if (exp.op != TOK.blit && e2x.isLvalue() && exp.e1.checkPostblit(sc, t1.nextOf())) 9363 return setError(); 9364 } 9365 else if (exp.e1.op == TOK.slice && 9366 (t2.ty == Tarray || t2.ty == Tsarray) && 9367 t2.nextOf().implicitConvTo(t1.nextOf())) 9368 { 9369 // Check element-wise assignment. 9370 9371 /* If assigned elements number is known at compile time, 9372 * check the mismatch. 9373 */ 9374 SliceExp se1 = cast(SliceExp)exp.e1; 9375 TypeSArray tsa1 = cast(TypeSArray)toStaticArrayType(se1); 9376 TypeSArray tsa2 = null; 9377 if (auto ale = e2x.isArrayLiteralExp()) 9378 tsa2 = cast(TypeSArray)t2.nextOf().sarrayOf(ale.elements.dim); 9379 else if (auto se = e2x.isSliceExp()) 9380 tsa2 = cast(TypeSArray)toStaticArrayType(se); 9381 else 9382 tsa2 = t2.isTypeSArray(); 9383 if (tsa1 && tsa2) 9384 { 9385 uinteger_t dim1 = tsa1.dim.toInteger(); 9386 uinteger_t dim2 = tsa2.dim.toInteger(); 9387 if (dim1 != dim2) 9388 { 9389 exp.error("mismatched array lengths, %d and %d", cast(int)dim1, cast(int)dim2); 9390 return setError(); 9391 } 9392 } 9393 9394 if (exp.op != TOK.blit && 9395 (e2x.op == TOK.slice && (cast(UnaExp)e2x).e1.isLvalue() || 9396 e2x.op == TOK.cast_ && (cast(UnaExp)e2x).e1.isLvalue() || 9397 e2x.op != TOK.slice && e2x.isLvalue())) 9398 { 9399 if (exp.e1.checkPostblit(sc, t1.nextOf())) 9400 return setError(); 9401 } 9402 9403 if (0 && global.params.warnings != DiagnosticReporting.off && !global.gag && exp.op == TOK.assign && 9404 e2x.op != TOK.slice && e2x.op != TOK.assign && 9405 e2x.op != TOK.arrayLiteral && e2x.op != TOK.string_ && 9406 !(e2x.op == TOK.add || e2x.op == TOK.min || 9407 e2x.op == TOK.mul || e2x.op == TOK.div || 9408 e2x.op == TOK.mod || e2x.op == TOK.xor || 9409 e2x.op == TOK.and || e2x.op == TOK.or || 9410 e2x.op == TOK.pow || 9411 e2x.op == TOK.tilde || e2x.op == TOK.negate)) 9412 { 9413 const(char)* e1str = exp.e1.toChars(); 9414 const(char)* e2str = e2x.toChars(); 9415 exp.warning("explicit element-wise assignment `%s = (%s)[]` is better than `%s = %s`", e1str, e2str, e1str, e2str); 9416 } 9417 9418 Type t2n = t2.nextOf(); 9419 Type t1n = t1.nextOf(); 9420 int offset; 9421 if (t2n.equivalent(t1n) || 9422 t1n.isBaseOf(t2n, &offset) && offset == 0) 9423 { 9424 /* Allow copy of distinct qualifier elements. 9425 * eg. 9426 * char[] dst; const(char)[] src; 9427 * dst[] = src; 9428 * 9429 * class C {} class D : C {} 9430 * C[2] ca; D[] da; 9431 * ca[] = da; 9432 */ 9433 if (isArrayOpValid(e2x)) 9434 { 9435 // Don't add CastExp to keep AST for array operations 9436 e2x = e2x.copy(); 9437 e2x.type = exp.e1.type.constOf(); 9438 } 9439 else 9440 e2x = e2x.castTo(sc, exp.e1.type.constOf()); 9441 } 9442 else 9443 { 9444 /* https://issues.dlang.org/show_bug.cgi?id=15778 9445 * A string literal has an array type of immutable 9446 * elements by default, and normally it cannot be convertible to 9447 * array type of mutable elements. But for element-wise assignment, 9448 * elements need to be const at best. So we should give a chance 9449 * to change code unit size for polysemous string literal. 9450 */ 9451 if (e2x.op == TOK.string_) 9452 e2x = e2x.implicitCastTo(sc, exp.e1.type.constOf()); 9453 else 9454 e2x = e2x.implicitCastTo(sc, exp.e1.type); 9455 } 9456 if (t1n.toBasetype.ty == Tvoid && t2n.toBasetype.ty == Tvoid) 9457 { 9458 if (!sc.intypeof && sc.func && !(sc.flags & SCOPE.debug_) && sc.func.setUnsafe()) 9459 { 9460 exp.error("cannot copy `void[]` to `void[]` in `@safe` code"); 9461 return setError(); 9462 } 9463 } 9464 } 9465 else 9466 { 9467 if (0 && global.params.warnings != DiagnosticReporting.off && !global.gag && exp.op == TOK.assign && 9468 t1.ty == Tarray && t2.ty == Tsarray && 9469 e2x.op != TOK.slice && 9470 t2.implicitConvTo(t1)) 9471 { 9472 // Disallow ar[] = sa (Converted to ar[] = sa[]) 9473 // Disallow da = sa (Converted to da = sa[]) 9474 const(char)* e1str = exp.e1.toChars(); 9475 const(char)* e2str = e2x.toChars(); 9476 const(char)* atypestr = exp.e1.op == TOK.slice ? "element-wise" : "slice"; 9477 exp.warning("explicit %s assignment `%s = (%s)[]` is better than `%s = %s`", atypestr, e1str, e2str, e1str, e2str); 9478 } 9479 if (exp.op == TOK.blit) 9480 e2x = e2x.castTo(sc, exp.e1.type); 9481 else 9482 { 9483 e2x = e2x.implicitCastTo(sc, exp.e1.type); 9484 9485 // Fix Issue 13435: https://issues.dlang.org/show_bug.cgi?id=13435 9486 9487 // If the implicit cast has failed and the assign expression is 9488 // the initialization of a struct member field 9489 if (e2x.op == TOK.error && exp.op == TOK.construct && t1.ty == Tstruct) 9490 { 9491 scope sd = (cast(TypeStruct)t1).sym; 9492 Dsymbol opAssign = search_function(sd, Id.assign); 9493 9494 // and the struct defines an opAssign 9495 if (opAssign) 9496 { 9497 // offer more information about the cause of the problem 9498 errorSupplemental(exp.loc, 9499 "`%s` is the first assignment of `%s` therefore it represents its initialization", 9500 exp.toChars(), exp.e1.toChars()); 9501 errorSupplemental(exp.loc, 9502 "`opAssign` methods are not used for initialization, but for subsequent assignments"); 9503 } 9504 } 9505 } 9506 } 9507 if (e2x.op == TOK.error) 9508 { 9509 result = e2x; 9510 return; 9511 } 9512 exp.e2 = e2x; 9513 t2 = exp.e2.type.toBasetype(); 9514 9515 /* Look for array operations 9516 */ 9517 if ((t2.ty == Tarray || t2.ty == Tsarray) && isArrayOpValid(exp.e2)) 9518 { 9519 // Look for valid array operations 9520 if (exp.memset != MemorySet.blockAssign && 9521 exp.e1.op == TOK.slice && 9522 (isUnaArrayOp(exp.e2.op) || isBinArrayOp(exp.e2.op))) 9523 { 9524 exp.type = exp.e1.type; 9525 if (exp.op == TOK.construct) // https://issues.dlang.org/show_bug.cgi?id=10282 9526 // tweak mutability of e1 element 9527 exp.e1.type = exp.e1.type.nextOf().mutableOf().arrayOf(); 9528 result = arrayOp(exp, sc); 9529 return; 9530 } 9531 9532 // Drop invalid array operations in e2 9533 // d = a[] + b[], d = (a[] + b[])[0..2], etc 9534 if (checkNonAssignmentArrayOp(exp.e2, exp.memset != MemorySet.blockAssign && exp.op == TOK.assign)) 9535 return setError(); 9536 9537 // Remains valid array assignments 9538 // d = d[], d = [1,2,3], etc 9539 } 9540 9541 /* Don't allow assignment to classes that were allocated on the stack with: 9542 * scope Class c = new Class(); 9543 */ 9544 if (exp.e1.op == TOK.variable && exp.op == TOK.assign) 9545 { 9546 VarExp ve = cast(VarExp)exp.e1; 9547 VarDeclaration vd = ve.var.isVarDeclaration(); 9548 if (vd && (vd.onstack || vd.mynew)) 9549 { 9550 assert(t1.ty == Tclass); 9551 exp.error("cannot rebind scope variables"); 9552 } 9553 } 9554 9555 if (exp.e1.op == TOK.variable && (cast(VarExp)exp.e1).var.ident == Id.ctfe) 9556 { 9557 exp.error("cannot modify compiler-generated variable `__ctfe`"); 9558 } 9559 9560 exp.type = exp.e1.type; 9561 assert(exp.type); 9562 auto res = exp.op == TOK.assign ? exp.reorderSettingAAElem(sc) : exp; 9563 checkAssignEscape(sc, res, false); 9564 return setResult(res); 9565 } 9566 9567 override void visit(PowAssignExp exp) 9568 { 9569 if (exp.type) 9570 { 9571 result = exp; 9572 return; 9573 } 9574 9575 Expression e = exp.op_overload(sc); 9576 if (e) 9577 { 9578 result = e; 9579 return; 9580 } 9581 9582 if (exp.e1.checkReadModifyWrite(exp.op, exp.e2)) 9583 return setError(); 9584 9585 assert(exp.e1.type && exp.e2.type); 9586 if (exp.e1.op == TOK.slice || exp.e1.type.ty == Tarray || exp.e1.type.ty == Tsarray) 9587 { 9588 if (checkNonAssignmentArrayOp(exp.e1)) 9589 return setError(); 9590 9591 // T[] ^^= ... 9592 if (exp.e2.implicitConvTo(exp.e1.type.nextOf())) 9593 { 9594 // T[] ^^= T 9595 exp.e2 = exp.e2.castTo(sc, exp.e1.type.nextOf()); 9596 } 9597 else if (Expression ex = typeCombine(exp, sc)) 9598 { 9599 result = ex; 9600 return; 9601 } 9602 9603 // Check element types are arithmetic 9604 Type tb1 = exp.e1.type.nextOf().toBasetype(); 9605 Type tb2 = exp.e2.type.toBasetype(); 9606 if (tb2.ty == Tarray || tb2.ty == Tsarray) 9607 tb2 = tb2.nextOf().toBasetype(); 9608 if ((tb1.isintegral() || tb1.isfloating()) && (tb2.isintegral() || tb2.isfloating())) 9609 { 9610 exp.type = exp.e1.type; 9611 result = arrayOp(exp, sc); 9612 return; 9613 } 9614 } 9615 else 9616 { 9617 exp.e1 = exp.e1.modifiableLvalue(sc, exp.e1); 9618 } 9619 9620 if ((exp.e1.type.isintegral() || exp.e1.type.isfloating()) && (exp.e2.type.isintegral() || exp.e2.type.isfloating())) 9621 { 9622 Expression e0 = null; 9623 e = exp.reorderSettingAAElem(sc); 9624 e = Expression.extractLast(e, e0); 9625 assert(e == exp); 9626 9627 if (exp.e1.op == TOK.variable) 9628 { 9629 // Rewrite: e1 = e1 ^^ e2 9630 e = new PowExp(exp.loc, exp.e1.syntaxCopy(), exp.e2); 9631 e = new AssignExp(exp.loc, exp.e1, e); 9632 } 9633 else 9634 { 9635 // Rewrite: ref tmp = e1; tmp = tmp ^^ e2 9636 auto v = copyToTemp(STC.ref_, "__powtmp", exp.e1); 9637 auto de = new DeclarationExp(exp.e1.loc, v); 9638 auto ve = new VarExp(exp.e1.loc, v); 9639 e = new PowExp(exp.loc, ve, exp.e2); 9640 e = new AssignExp(exp.loc, new VarExp(exp.e1.loc, v), e); 9641 e = new CommaExp(exp.loc, de, e); 9642 } 9643 e = Expression.combine(e0, e); 9644 e = e.expressionSemantic(sc); 9645 result = e; 9646 return; 9647 } 9648 result = exp.incompatibleTypes(); 9649 } 9650 9651 override void visit(CatAssignExp exp) 9652 { 9653 if (exp.type) 9654 { 9655 result = exp; 9656 return; 9657 } 9658 9659 //printf("CatAssignExp::semantic() %s\n", exp.toChars()); 9660 Expression e = exp.op_overload(sc); 9661 if (e) 9662 { 9663 result = e; 9664 return; 9665 } 9666 9667 if (exp.e1.op == TOK.slice) 9668 { 9669 SliceExp se = cast(SliceExp)exp.e1; 9670 if (se.e1.type.toBasetype().ty == Tsarray) 9671 { 9672 exp.error("cannot append to static array `%s`", se.e1.type.toChars()); 9673 return setError(); 9674 } 9675 } 9676 9677 exp.e1 = exp.e1.modifiableLvalue(sc, exp.e1); 9678 if (exp.e1.op == TOK.error) 9679 { 9680 result = exp.e1; 9681 return; 9682 } 9683 if (exp.e2.op == TOK.error) 9684 { 9685 result = exp.e2; 9686 return; 9687 } 9688 9689 if (checkNonAssignmentArrayOp(exp.e2)) 9690 return setError(); 9691 9692 Type tb1 = exp.e1.type.toBasetype(); 9693 Type tb1next = tb1.nextOf(); 9694 Type tb2 = exp.e2.type.toBasetype(); 9695 9696 /* Possibilities: 9697 * TOK.concatenateAssign: appending T[] to T[] 9698 * TOK.concatenateElemAssign: appending T to T[] 9699 * TOK.concatenateDcharAssign: appending dchar to T[] 9700 */ 9701 if ((tb1.ty == Tarray) && 9702 (tb2.ty == Tarray || tb2.ty == Tsarray) && 9703 (exp.e2.implicitConvTo(exp.e1.type) || 9704 (tb2.nextOf().implicitConvTo(tb1next) && 9705 (tb2.nextOf().size(Loc.initial) == tb1next.size(Loc.initial))))) 9706 { 9707 // TOK.concatenateAssign 9708 assert(exp.op == TOK.concatenateAssign); 9709 if (exp.e1.checkPostblit(sc, tb1next)) 9710 return setError(); 9711 9712 exp.e2 = exp.e2.castTo(sc, exp.e1.type); 9713 } 9714 else if ((tb1.ty == Tarray) && exp.e2.implicitConvTo(tb1next)) 9715 { 9716 /* https://issues.dlang.org/show_bug.cgi?id=19782 9717 * 9718 * If e2 is implicitly convertible to tb1next, the conversion 9719 * might be done through alias this, in which case, e2 needs to 9720 * be modified accordingly (e2 => e2.aliasthis). 9721 */ 9722 if (tb2.ty == Tstruct && (cast(TypeStruct)tb2).implicitConvToThroughAliasThis(tb1next)) 9723 goto Laliasthis; 9724 if (tb2.ty == Tclass && (cast(TypeClass)tb2).implicitConvToThroughAliasThis(tb1next)) 9725 goto Laliasthis; 9726 // Append element 9727 if (exp.e2.checkPostblit(sc, tb2)) 9728 return setError(); 9729 9730 if (checkNewEscape(sc, exp.e2, false)) 9731 return setError(); 9732 9733 exp = new CatElemAssignExp(exp.loc, exp.type, exp.e1, exp.e2.castTo(sc, tb1next)); 9734 exp.e2 = doCopyOrMove(sc, exp.e2); 9735 } 9736 else if (tb1.ty == Tarray && 9737 (tb1next.ty == Tchar || tb1next.ty == Twchar) && 9738 exp.e2.type.ty != tb1next.ty && 9739 exp.e2.implicitConvTo(Type.tdchar)) 9740 { 9741 // Append dchar to char[] or wchar[] 9742 exp = new CatDcharAssignExp(exp.loc, exp.type, exp.e1, exp.e2.castTo(sc, Type.tdchar)); 9743 9744 /* Do not allow appending wchar to char[] because if wchar happens 9745 * to be a surrogate pair, nothing good can result. 9746 */ 9747 } 9748 else 9749 { 9750 // Try alias this on first operand 9751 static Expression tryAliasThisForLhs(BinAssignExp exp, Scope* sc) 9752 { 9753 AggregateDeclaration ad1 = isAggregate(exp.e1.type); 9754 if (!ad1 || !ad1.aliasthis) 9755 return null; 9756 9757 /* Rewrite (e1 op e2) as: 9758 * (e1.aliasthis op e2) 9759 */ 9760 if (exp.att1 && exp.e1.type.equivalent(exp.att1)) 9761 return null; 9762 //printf("att %s e1 = %s\n", Token::toChars(e.op), e.e1.type.toChars()); 9763 Expression e1 = new DotIdExp(exp.loc, exp.e1, ad1.aliasthis.ident); 9764 BinExp be = cast(BinExp)exp.copy(); 9765 if (!be.att1 && exp.e1.type.checkAliasThisRec()) 9766 be.att1 = exp.e1.type; 9767 be.e1 = e1; 9768 return be.trySemantic(sc); 9769 } 9770 9771 // Try alias this on second operand 9772 static Expression tryAliasThisForRhs(BinAssignExp exp, Scope* sc) 9773 { 9774 AggregateDeclaration ad2 = isAggregate(exp.e2.type); 9775 if (!ad2 || !ad2.aliasthis) 9776 return null; 9777 /* Rewrite (e1 op e2) as: 9778 * (e1 op e2.aliasthis) 9779 */ 9780 if (exp.att2 && exp.e2.type.equivalent(exp.att2)) 9781 return null; 9782 //printf("att %s e2 = %s\n", Token::toChars(e.op), e.e2.type.toChars()); 9783 Expression e2 = new DotIdExp(exp.loc, exp.e2, ad2.aliasthis.ident); 9784 BinExp be = cast(BinExp)exp.copy(); 9785 if (!be.att2 && exp.e2.type.checkAliasThisRec()) 9786 be.att2 = exp.e2.type; 9787 be.e2 = e2; 9788 return be.trySemantic(sc); 9789 } 9790 9791 Laliasthis: 9792 result = tryAliasThisForLhs(exp, sc); 9793 if (result) 9794 return; 9795 9796 result = tryAliasThisForRhs(exp, sc); 9797 if (result) 9798 return; 9799 9800 exp.error("cannot append type `%s` to type `%s`", tb2.toChars(), tb1.toChars()); 9801 return setError(); 9802 } 9803 9804 if (exp.e2.checkValue() || exp.e2.checkSharedAccess(sc)) 9805 return setError(); 9806 9807 exp.type = exp.e1.type; 9808 auto res = exp.reorderSettingAAElem(sc); 9809 if ((exp.op == TOK.concatenateElemAssign || exp.op == TOK.concatenateDcharAssign) && global.params.vsafe) 9810 checkAssignEscape(sc, res, false); 9811 result = res; 9812 } 9813 9814 override void visit(AddExp exp) 9815 { 9816 static if (LOGSEMANTIC) 9817 { 9818 printf("AddExp::semantic('%s')\n", exp.toChars()); 9819 } 9820 if (exp.type) 9821 { 9822 result = exp; 9823 return; 9824 } 9825 9826 if (Expression ex = binSemanticProp(exp, sc)) 9827 { 9828 result = ex; 9829 return; 9830 } 9831 Expression e = exp.op_overload(sc); 9832 if (e) 9833 { 9834 result = e; 9835 return; 9836 } 9837 9838 Type tb1 = exp.e1.type.toBasetype(); 9839 Type tb2 = exp.e2.type.toBasetype(); 9840 9841 bool err = false; 9842 if (tb1.ty == Tdelegate || tb1.ty == Tpointer && tb1.nextOf().ty == Tfunction) 9843 { 9844 err |= exp.e1.checkArithmetic() || exp.e1.checkSharedAccess(sc); 9845 } 9846 if (tb2.ty == Tdelegate || tb2.ty == Tpointer && tb2.nextOf().ty == Tfunction) 9847 { 9848 err |= exp.e2.checkArithmetic() || exp.e2.checkSharedAccess(sc); 9849 } 9850 if (err) 9851 return setError(); 9852 9853 if (tb1.ty == Tpointer && exp.e2.type.isintegral() || tb2.ty == Tpointer && exp.e1.type.isintegral()) 9854 { 9855 result = scaleFactor(exp, sc); 9856 return; 9857 } 9858 9859 if (tb1.ty == Tpointer && tb2.ty == Tpointer) 9860 { 9861 result = exp.incompatibleTypes(); 9862 return; 9863 } 9864 9865 if (Expression ex = typeCombine(exp, sc)) 9866 { 9867 result = ex; 9868 return; 9869 } 9870 9871 Type tb = exp.type.toBasetype(); 9872 if (tb.ty == Tarray || tb.ty == Tsarray) 9873 { 9874 if (!isArrayOpValid(exp)) 9875 { 9876 result = arrayOpInvalidError(exp); 9877 return; 9878 } 9879 result = exp; 9880 return; 9881 } 9882 9883 tb1 = exp.e1.type.toBasetype(); 9884 if (!target.isVectorOpSupported(tb1, exp.op, tb2)) 9885 { 9886 result = exp.incompatibleTypes(); 9887 return; 9888 } 9889 if ((tb1.isreal() && exp.e2.type.isimaginary()) || (tb1.isimaginary() && exp.e2.type.isreal())) 9890 { 9891 switch (exp.type.toBasetype().ty) 9892 { 9893 case Tfloat32: 9894 case Timaginary32: 9895 exp.type = Type.tcomplex32; 9896 break; 9897 9898 case Tfloat64: 9899 case Timaginary64: 9900 exp.type = Type.tcomplex64; 9901 break; 9902 9903 case Tfloat80: 9904 case Timaginary80: 9905 exp.type = Type.tcomplex80; 9906 break; 9907 9908 default: 9909 assert(0); 9910 } 9911 } 9912 result = exp; 9913 } 9914 9915 override void visit(MinExp exp) 9916 { 9917 static if (LOGSEMANTIC) 9918 { 9919 printf("MinExp::semantic('%s')\n", exp.toChars()); 9920 } 9921 if (exp.type) 9922 { 9923 result = exp; 9924 return; 9925 } 9926 9927 if (Expression ex = binSemanticProp(exp, sc)) 9928 { 9929 result = ex; 9930 return; 9931 } 9932 Expression e = exp.op_overload(sc); 9933 if (e) 9934 { 9935 result = e; 9936 return; 9937 } 9938 9939 Type t1 = exp.e1.type.toBasetype(); 9940 Type t2 = exp.e2.type.toBasetype(); 9941 9942 bool err = false; 9943 if (t1.ty == Tdelegate || t1.ty == Tpointer && t1.nextOf().ty == Tfunction) 9944 { 9945 err |= exp.e1.checkArithmetic() || exp.e1.checkSharedAccess(sc); 9946 } 9947 if (t2.ty == Tdelegate || t2.ty == Tpointer && t2.nextOf().ty == Tfunction) 9948 { 9949 err |= exp.e2.checkArithmetic() || exp.e2.checkSharedAccess(sc); 9950 } 9951 if (err) 9952 return setError(); 9953 9954 if (t1.ty == Tpointer) 9955 { 9956 if (t2.ty == Tpointer) 9957 { 9958 // https://dlang.org/spec/expression.html#add_expressions 9959 // "If both operands are pointers, and the operator is -, the pointers are 9960 // subtracted and the result is divided by the size of the type pointed to 9961 // by the operands. It is an error if the pointers point to different types." 9962 Type p1 = t1.nextOf(); 9963 Type p2 = t2.nextOf(); 9964 9965 if (!p1.equivalent(p2)) 9966 { 9967 // Deprecation to remain for at least a year, after which this should be 9968 // changed to an error 9969 // See https://github.com/dlang/dmd/pull/7332 9970 deprecation(exp.loc, 9971 "cannot subtract pointers to different types: `%s` and `%s`.", 9972 t1.toChars(), t2.toChars()); 9973 } 9974 9975 // Need to divide the result by the stride 9976 // Replace (ptr - ptr) with (ptr - ptr) / stride 9977 d_int64 stride; 9978 9979 // make sure pointer types are compatible 9980 if (Expression ex = typeCombine(exp, sc)) 9981 { 9982 result = ex; 9983 return; 9984 } 9985 9986 exp.type = Type.tptrdiff_t; 9987 stride = t2.nextOf().size(); 9988 if (stride == 0) 9989 { 9990 e = new IntegerExp(exp.loc, 0, Type.tptrdiff_t); 9991 } 9992 else 9993 { 9994 e = new DivExp(exp.loc, exp, new IntegerExp(Loc.initial, stride, Type.tptrdiff_t)); 9995 e.type = Type.tptrdiff_t; 9996 } 9997 } 9998 else if (t2.isintegral()) 9999 e = scaleFactor(exp, sc); 10000 else 10001 { 10002 exp.error("can't subtract `%s` from pointer", t2.toChars()); 10003 e = ErrorExp.get(); 10004 } 10005 result = e; 10006 return; 10007 } 10008 if (t2.ty == Tpointer) 10009 { 10010 exp.type = exp.e2.type; 10011 exp.error("can't subtract pointer from `%s`", exp.e1.type.toChars()); 10012 return setError(); 10013 } 10014 10015 if (Expression ex = typeCombine(exp, sc)) 10016 { 10017 result = ex; 10018 return; 10019 } 10020 10021 Type tb = exp.type.toBasetype(); 10022 if (tb.ty == Tarray || tb.ty == Tsarray) 10023 { 10024 if (!isArrayOpValid(exp)) 10025 { 10026 result = arrayOpInvalidError(exp); 10027 return; 10028 } 10029 result = exp; 10030 return; 10031 } 10032 10033 t1 = exp.e1.type.toBasetype(); 10034 t2 = exp.e2.type.toBasetype(); 10035 if (!target.isVectorOpSupported(t1, exp.op, t2)) 10036 { 10037 result = exp.incompatibleTypes(); 10038 return; 10039 } 10040 if ((t1.isreal() && t2.isimaginary()) || (t1.isimaginary() && t2.isreal())) 10041 { 10042 switch (exp.type.ty) 10043 { 10044 case Tfloat32: 10045 case Timaginary32: 10046 exp.type = Type.tcomplex32; 10047 break; 10048 10049 case Tfloat64: 10050 case Timaginary64: 10051 exp.type = Type.tcomplex64; 10052 break; 10053 10054 case Tfloat80: 10055 case Timaginary80: 10056 exp.type = Type.tcomplex80; 10057 break; 10058 10059 default: 10060 assert(0); 10061 } 10062 } 10063 result = exp; 10064 return; 10065 } 10066 10067 override void visit(CatExp exp) 10068 { 10069 // https://dlang.org/spec/expression.html#cat_expressions 10070 //printf("CatExp.semantic() %s\n", toChars()); 10071 if (exp.type) 10072 { 10073 result = exp; 10074 return; 10075 } 10076 10077 if (Expression ex = binSemanticProp(exp, sc)) 10078 { 10079 result = ex; 10080 return; 10081 } 10082 Expression e = exp.op_overload(sc); 10083 if (e) 10084 { 10085 result = e; 10086 return; 10087 } 10088 10089 Type tb1 = exp.e1.type.toBasetype(); 10090 Type tb2 = exp.e2.type.toBasetype(); 10091 10092 auto f1 = checkNonAssignmentArrayOp(exp.e1); 10093 auto f2 = checkNonAssignmentArrayOp(exp.e2); 10094 if (f1 || f2) 10095 return setError(); 10096 10097 /* BUG: Should handle things like: 10098 * char c; 10099 * c ~ ' ' 10100 * ' ' ~ c; 10101 */ 10102 10103 Type tb1next = tb1.nextOf(); 10104 Type tb2next = tb2.nextOf(); 10105 10106 // Check for: array ~ array 10107 if (tb1next && tb2next && (tb1next.implicitConvTo(tb2next) >= MATCH.constant || tb2next.implicitConvTo(tb1next) >= MATCH.constant || exp.e1.op == TOK.arrayLiteral && exp.e1.implicitConvTo(tb2) || exp.e2.op == TOK.arrayLiteral && exp.e2.implicitConvTo(tb1))) 10108 { 10109 /* https://issues.dlang.org/show_bug.cgi?id=9248 10110 * Here to avoid the case of: 10111 * void*[] a = [cast(void*)1]; 10112 * void*[] b = [cast(void*)2]; 10113 * a ~ b; 10114 * becoming: 10115 * a ~ [cast(void*)b]; 10116 */ 10117 10118 /* https://issues.dlang.org/show_bug.cgi?id=14682 10119 * Also to avoid the case of: 10120 * int[][] a; 10121 * a ~ []; 10122 * becoming: 10123 * a ~ cast(int[])[]; 10124 */ 10125 goto Lpeer; 10126 } 10127 10128 // Check for: array ~ element 10129 if ((tb1.ty == Tsarray || tb1.ty == Tarray) && tb2.ty != Tvoid) 10130 { 10131 if (exp.e1.op == TOK.arrayLiteral) 10132 { 10133 exp.e2 = doCopyOrMove(sc, exp.e2); 10134 // https://issues.dlang.org/show_bug.cgi?id=14686 10135 // Postblit call appears in AST, and this is 10136 // finally translated to an ArrayLiteralExp in below optimize(). 10137 } 10138 else if (exp.e1.op == TOK.string_) 10139 { 10140 // No postblit call exists on character (integer) value. 10141 } 10142 else 10143 { 10144 if (exp.e2.checkPostblit(sc, tb2)) 10145 return setError(); 10146 // Postblit call will be done in runtime helper function 10147 } 10148 10149 if (exp.e1.op == TOK.arrayLiteral && exp.e1.implicitConvTo(tb2.arrayOf())) 10150 { 10151 exp.e1 = exp.e1.implicitCastTo(sc, tb2.arrayOf()); 10152 exp.type = tb2.arrayOf(); 10153 goto L2elem; 10154 } 10155 if (exp.e2.implicitConvTo(tb1next) >= MATCH.convert) 10156 { 10157 exp.e2 = exp.e2.implicitCastTo(sc, tb1next); 10158 exp.type = tb1next.arrayOf(); 10159 L2elem: 10160 if (tb2.ty == Tarray || tb2.ty == Tsarray) 10161 { 10162 // Make e2 into [e2] 10163 exp.e2 = new ArrayLiteralExp(exp.e2.loc, exp.type, exp.e2); 10164 } 10165 else if (checkNewEscape(sc, exp.e2, false)) 10166 return setError(); 10167 result = exp.optimize(WANTvalue); 10168 return; 10169 } 10170 } 10171 // Check for: element ~ array 10172 if ((tb2.ty == Tsarray || tb2.ty == Tarray) && tb1.ty != Tvoid) 10173 { 10174 if (exp.e2.op == TOK.arrayLiteral) 10175 { 10176 exp.e1 = doCopyOrMove(sc, exp.e1); 10177 } 10178 else if (exp.e2.op == TOK.string_) 10179 { 10180 } 10181 else 10182 { 10183 if (exp.e1.checkPostblit(sc, tb1)) 10184 return setError(); 10185 } 10186 10187 if (exp.e2.op == TOK.arrayLiteral && exp.e2.implicitConvTo(tb1.arrayOf())) 10188 { 10189 exp.e2 = exp.e2.implicitCastTo(sc, tb1.arrayOf()); 10190 exp.type = tb1.arrayOf(); 10191 goto L1elem; 10192 } 10193 if (exp.e1.implicitConvTo(tb2next) >= MATCH.convert) 10194 { 10195 exp.e1 = exp.e1.implicitCastTo(sc, tb2next); 10196 exp.type = tb2next.arrayOf(); 10197 L1elem: 10198 if (tb1.ty == Tarray || tb1.ty == Tsarray) 10199 { 10200 // Make e1 into [e1] 10201 exp.e1 = new ArrayLiteralExp(exp.e1.loc, exp.type, exp.e1); 10202 } 10203 else if (checkNewEscape(sc, exp.e1, false)) 10204 return setError(); 10205 result = exp.optimize(WANTvalue); 10206 return; 10207 } 10208 } 10209 10210 Lpeer: 10211 if ((tb1.ty == Tsarray || tb1.ty == Tarray) && (tb2.ty == Tsarray || tb2.ty == Tarray) && (tb1next.mod || tb2next.mod) && (tb1next.mod != tb2next.mod)) 10212 { 10213 Type t1 = tb1next.mutableOf().constOf().arrayOf(); 10214 Type t2 = tb2next.mutableOf().constOf().arrayOf(); 10215 if (exp.e1.op == TOK.string_ && !(cast(StringExp)exp.e1).committed) 10216 exp.e1.type = t1; 10217 else 10218 exp.e1 = exp.e1.castTo(sc, t1); 10219 if (exp.e2.op == TOK.string_ && !(cast(StringExp)exp.e2).committed) 10220 exp.e2.type = t2; 10221 else 10222 exp.e2 = exp.e2.castTo(sc, t2); 10223 } 10224 10225 if (Expression ex = typeCombine(exp, sc)) 10226 { 10227 result = ex; 10228 return; 10229 } 10230 exp.type = exp.type.toHeadMutable(); 10231 10232 Type tb = exp.type.toBasetype(); 10233 if (tb.ty == Tsarray) 10234 exp.type = tb.nextOf().arrayOf(); 10235 if (exp.type.ty == Tarray && tb1next && tb2next && tb1next.mod != tb2next.mod) 10236 { 10237 exp.type = exp.type.nextOf().toHeadMutable().arrayOf(); 10238 } 10239 if (Type tbn = tb.nextOf()) 10240 { 10241 if (exp.checkPostblit(sc, tbn)) 10242 return setError(); 10243 } 10244 Type t1 = exp.e1.type.toBasetype(); 10245 Type t2 = exp.e2.type.toBasetype(); 10246 if ((t1.ty == Tarray || t1.ty == Tsarray) && 10247 (t2.ty == Tarray || t2.ty == Tsarray)) 10248 { 10249 // Normalize to ArrayLiteralExp or StringExp as far as possible 10250 e = exp.optimize(WANTvalue); 10251 } 10252 else 10253 { 10254 //printf("(%s) ~ (%s)\n", e1.toChars(), e2.toChars()); 10255 result = exp.incompatibleTypes(); 10256 return; 10257 } 10258 10259 result = e; 10260 } 10261 10262 override void visit(MulExp exp) 10263 { 10264 version (none) 10265 { 10266 printf("MulExp::semantic() %s\n", exp.toChars()); 10267 } 10268 if (exp.type) 10269 { 10270 result = exp; 10271 return; 10272 } 10273 10274 if (Expression ex = binSemanticProp(exp, sc)) 10275 { 10276 result = ex; 10277 return; 10278 } 10279 Expression e = exp.op_overload(sc); 10280 if (e) 10281 { 10282 result = e; 10283 return; 10284 } 10285 10286 if (Expression ex = typeCombine(exp, sc)) 10287 { 10288 result = ex; 10289 return; 10290 } 10291 10292 Type tb = exp.type.toBasetype(); 10293 if (tb.ty == Tarray || tb.ty == Tsarray) 10294 { 10295 if (!isArrayOpValid(exp)) 10296 { 10297 result = arrayOpInvalidError(exp); 10298 return; 10299 } 10300 result = exp; 10301 return; 10302 } 10303 10304 if (exp.checkArithmeticBin() || exp.checkSharedAccessBin(sc)) 10305 return setError(); 10306 10307 if (exp.type.isfloating()) 10308 { 10309 Type t1 = exp.e1.type; 10310 Type t2 = exp.e2.type; 10311 10312 if (t1.isreal()) 10313 { 10314 exp.type = t2; 10315 } 10316 else if (t2.isreal()) 10317 { 10318 exp.type = t1; 10319 } 10320 else if (t1.isimaginary()) 10321 { 10322 if (t2.isimaginary()) 10323 { 10324 switch (t1.toBasetype().ty) 10325 { 10326 case Timaginary32: 10327 exp.type = Type.tfloat32; 10328 break; 10329 10330 case Timaginary64: 10331 exp.type = Type.tfloat64; 10332 break; 10333 10334 case Timaginary80: 10335 exp.type = Type.tfloat80; 10336 break; 10337 10338 default: 10339 assert(0); 10340 } 10341 10342 // iy * iv = -yv 10343 exp.e1.type = exp.type; 10344 exp.e2.type = exp.type; 10345 e = new NegExp(exp.loc, exp); 10346 e = e.expressionSemantic(sc); 10347 result = e; 10348 return; 10349 } 10350 else 10351 exp.type = t2; // t2 is complex 10352 } 10353 else if (t2.isimaginary()) 10354 { 10355 exp.type = t1; // t1 is complex 10356 } 10357 } 10358 else if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype())) 10359 { 10360 result = exp.incompatibleTypes(); 10361 return; 10362 } 10363 result = exp; 10364 } 10365 10366 override void visit(DivExp exp) 10367 { 10368 if (exp.type) 10369 { 10370 result = exp; 10371 return; 10372 } 10373 10374 if (Expression ex = binSemanticProp(exp, sc)) 10375 { 10376 result = ex; 10377 return; 10378 } 10379 Expression e = exp.op_overload(sc); 10380 if (e) 10381 { 10382 result = e; 10383 return; 10384 } 10385 10386 if (Expression ex = typeCombine(exp, sc)) 10387 { 10388 result = ex; 10389 return; 10390 } 10391 10392 Type tb = exp.type.toBasetype(); 10393 if (tb.ty == Tarray || tb.ty == Tsarray) 10394 { 10395 if (!isArrayOpValid(exp)) 10396 { 10397 result = arrayOpInvalidError(exp); 10398 return; 10399 } 10400 result = exp; 10401 return; 10402 } 10403 10404 if (exp.checkArithmeticBin() || exp.checkSharedAccessBin(sc)) 10405 return setError(); 10406 10407 if (exp.type.isfloating()) 10408 { 10409 Type t1 = exp.e1.type; 10410 Type t2 = exp.e2.type; 10411 10412 if (t1.isreal()) 10413 { 10414 exp.type = t2; 10415 if (t2.isimaginary()) 10416 { 10417 // x/iv = i(-x/v) 10418 exp.e2.type = t1; 10419 e = new NegExp(exp.loc, exp); 10420 e = e.expressionSemantic(sc); 10421 result = e; 10422 return; 10423 } 10424 } 10425 else if (t2.isreal()) 10426 { 10427 exp.type = t1; 10428 } 10429 else if (t1.isimaginary()) 10430 { 10431 if (t2.isimaginary()) 10432 { 10433 switch (t1.toBasetype().ty) 10434 { 10435 case Timaginary32: 10436 exp.type = Type.tfloat32; 10437 break; 10438 10439 case Timaginary64: 10440 exp.type = Type.tfloat64; 10441 break; 10442 10443 case Timaginary80: 10444 exp.type = Type.tfloat80; 10445 break; 10446 10447 default: 10448 assert(0); 10449 } 10450 } 10451 else 10452 exp.type = t2; // t2 is complex 10453 } 10454 else if (t2.isimaginary()) 10455 { 10456 exp.type = t1; // t1 is complex 10457 } 10458 } 10459 else if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype())) 10460 { 10461 result = exp.incompatibleTypes(); 10462 return; 10463 } 10464 result = exp; 10465 } 10466 10467 override void visit(ModExp exp) 10468 { 10469 if (exp.type) 10470 { 10471 result = exp; 10472 return; 10473 } 10474 10475 if (Expression ex = binSemanticProp(exp, sc)) 10476 { 10477 result = ex; 10478 return; 10479 } 10480 Expression e = exp.op_overload(sc); 10481 if (e) 10482 { 10483 result = e; 10484 return; 10485 } 10486 10487 if (Expression ex = typeCombine(exp, sc)) 10488 { 10489 result = ex; 10490 return; 10491 } 10492 10493 Type tb = exp.type.toBasetype(); 10494 if (tb.ty == Tarray || tb.ty == Tsarray) 10495 { 10496 if (!isArrayOpValid(exp)) 10497 { 10498 result = arrayOpInvalidError(exp); 10499 return; 10500 } 10501 result = exp; 10502 return; 10503 } 10504 if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype())) 10505 { 10506 result = exp.incompatibleTypes(); 10507 return; 10508 } 10509 10510 if (exp.checkArithmeticBin() || exp.checkSharedAccessBin(sc)) 10511 return setError(); 10512 10513 if (exp.type.isfloating()) 10514 { 10515 exp.type = exp.e1.type; 10516 if (exp.e2.type.iscomplex()) 10517 { 10518 exp.error("cannot perform modulo complex arithmetic"); 10519 return setError(); 10520 } 10521 } 10522 result = exp; 10523 } 10524 10525 override void visit(PowExp exp) 10526 { 10527 if (exp.type) 10528 { 10529 result = exp; 10530 return; 10531 } 10532 10533 //printf("PowExp::semantic() %s\n", toChars()); 10534 if (Expression ex = binSemanticProp(exp, sc)) 10535 { 10536 result = ex; 10537 return; 10538 } 10539 Expression e = exp.op_overload(sc); 10540 if (e) 10541 { 10542 result = e; 10543 return; 10544 } 10545 10546 if (Expression ex = typeCombine(exp, sc)) 10547 { 10548 result = ex; 10549 return; 10550 } 10551 10552 Type tb = exp.type.toBasetype(); 10553 if (tb.ty == Tarray || tb.ty == Tsarray) 10554 { 10555 if (!isArrayOpValid(exp)) 10556 { 10557 result = arrayOpInvalidError(exp); 10558 return; 10559 } 10560 result = exp; 10561 return; 10562 } 10563 10564 if (exp.checkArithmeticBin() || exp.checkSharedAccessBin(sc)) 10565 return setError(); 10566 10567 if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype())) 10568 { 10569 result = exp.incompatibleTypes(); 10570 return; 10571 } 10572 10573 // First, attempt to fold the expression. 10574 e = exp.optimize(WANTvalue); 10575 if (e.op != TOK.pow) 10576 { 10577 e = e.expressionSemantic(sc); 10578 result = e; 10579 return; 10580 } 10581 10582 Module mmath = loadStdMath(); 10583 if (!mmath) 10584 { 10585 e.error("`%s` requires `std.math` for `^^` operators", e.toChars()); 10586 return setError(); 10587 } 10588 e = new ScopeExp(exp.loc, mmath); 10589 10590 if (exp.e2.op == TOK.float64 && exp.e2.toReal() == CTFloat.half) 10591 { 10592 // Replace e1 ^^ 0.5 with .std.math.sqrt(e1) 10593 e = new CallExp(exp.loc, new DotIdExp(exp.loc, e, Id._sqrt), exp.e1); 10594 } 10595 else 10596 { 10597 // Replace e1 ^^ e2 with .std.math.pow(e1, e2) 10598 e = new CallExp(exp.loc, new DotIdExp(exp.loc, e, Id._pow), exp.e1, exp.e2); 10599 } 10600 e = e.expressionSemantic(sc); 10601 result = e; 10602 return; 10603 } 10604 10605 override void visit(ShlExp exp) 10606 { 10607 //printf("ShlExp::semantic(), type = %p\n", type); 10608 if (exp.type) 10609 { 10610 result = exp; 10611 return; 10612 } 10613 10614 if (Expression ex = binSemanticProp(exp, sc)) 10615 { 10616 result = ex; 10617 return; 10618 } 10619 Expression e = exp.op_overload(sc); 10620 if (e) 10621 { 10622 result = e; 10623 return; 10624 } 10625 10626 if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc)) 10627 return setError(); 10628 10629 if (!target.isVectorOpSupported(exp.e1.type.toBasetype(), exp.op, exp.e2.type.toBasetype())) 10630 { 10631 result = exp.incompatibleTypes(); 10632 return; 10633 } 10634 exp.e1 = integralPromotions(exp.e1, sc); 10635 if (exp.e2.type.toBasetype().ty != Tvector) 10636 exp.e2 = exp.e2.castTo(sc, Type.tshiftcnt); 10637 10638 exp.type = exp.e1.type; 10639 result = exp; 10640 } 10641 10642 override void visit(ShrExp exp) 10643 { 10644 if (exp.type) 10645 { 10646 result = exp; 10647 return; 10648 } 10649 10650 if (Expression ex = binSemanticProp(exp, sc)) 10651 { 10652 result = ex; 10653 return; 10654 } 10655 Expression e = exp.op_overload(sc); 10656 if (e) 10657 { 10658 result = e; 10659 return; 10660 } 10661 10662 if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc)) 10663 return setError(); 10664 10665 if (!target.isVectorOpSupported(exp.e1.type.toBasetype(), exp.op, exp.e2.type.toBasetype())) 10666 { 10667 result = exp.incompatibleTypes(); 10668 return; 10669 } 10670 exp.e1 = integralPromotions(exp.e1, sc); 10671 if (exp.e2.type.toBasetype().ty != Tvector) 10672 exp.e2 = exp.e2.castTo(sc, Type.tshiftcnt); 10673 10674 exp.type = exp.e1.type; 10675 result = exp; 10676 } 10677 10678 override void visit(UshrExp exp) 10679 { 10680 if (exp.type) 10681 { 10682 result = exp; 10683 return; 10684 } 10685 10686 if (Expression ex = binSemanticProp(exp, sc)) 10687 { 10688 result = ex; 10689 return; 10690 } 10691 Expression e = exp.op_overload(sc); 10692 if (e) 10693 { 10694 result = e; 10695 return; 10696 } 10697 10698 if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc)) 10699 return setError(); 10700 10701 if (!target.isVectorOpSupported(exp.e1.type.toBasetype(), exp.op, exp.e2.type.toBasetype())) 10702 { 10703 result = exp.incompatibleTypes(); 10704 return; 10705 } 10706 exp.e1 = integralPromotions(exp.e1, sc); 10707 if (exp.e2.type.toBasetype().ty != Tvector) 10708 exp.e2 = exp.e2.castTo(sc, Type.tshiftcnt); 10709 10710 exp.type = exp.e1.type; 10711 result = exp; 10712 } 10713 10714 override void visit(AndExp exp) 10715 { 10716 if (exp.type) 10717 { 10718 result = exp; 10719 return; 10720 } 10721 10722 if (Expression ex = binSemanticProp(exp, sc)) 10723 { 10724 result = ex; 10725 return; 10726 } 10727 Expression e = exp.op_overload(sc); 10728 if (e) 10729 { 10730 result = e; 10731 return; 10732 } 10733 10734 if (exp.e1.type.toBasetype().ty == Tbool && exp.e2.type.toBasetype().ty == Tbool) 10735 { 10736 exp.type = exp.e1.type; 10737 result = exp; 10738 return; 10739 } 10740 10741 if (Expression ex = typeCombine(exp, sc)) 10742 { 10743 result = ex; 10744 return; 10745 } 10746 10747 Type tb = exp.type.toBasetype(); 10748 if (tb.ty == Tarray || tb.ty == Tsarray) 10749 { 10750 if (!isArrayOpValid(exp)) 10751 { 10752 result = arrayOpInvalidError(exp); 10753 return; 10754 } 10755 result = exp; 10756 return; 10757 } 10758 if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype())) 10759 { 10760 result = exp.incompatibleTypes(); 10761 return; 10762 } 10763 if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc)) 10764 return setError(); 10765 10766 result = exp; 10767 } 10768 10769 override void visit(OrExp exp) 10770 { 10771 if (exp.type) 10772 { 10773 result = exp; 10774 return; 10775 } 10776 10777 if (Expression ex = binSemanticProp(exp, sc)) 10778 { 10779 result = ex; 10780 return; 10781 } 10782 Expression e = exp.op_overload(sc); 10783 if (e) 10784 { 10785 result = e; 10786 return; 10787 } 10788 10789 if (exp.e1.type.toBasetype().ty == Tbool && exp.e2.type.toBasetype().ty == Tbool) 10790 { 10791 exp.type = exp.e1.type; 10792 result = exp; 10793 return; 10794 } 10795 10796 if (Expression ex = typeCombine(exp, sc)) 10797 { 10798 result = ex; 10799 return; 10800 } 10801 10802 Type tb = exp.type.toBasetype(); 10803 if (tb.ty == Tarray || tb.ty == Tsarray) 10804 { 10805 if (!isArrayOpValid(exp)) 10806 { 10807 result = arrayOpInvalidError(exp); 10808 return; 10809 } 10810 result = exp; 10811 return; 10812 } 10813 if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype())) 10814 { 10815 result = exp.incompatibleTypes(); 10816 return; 10817 } 10818 if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc)) 10819 return setError(); 10820 10821 result = exp; 10822 } 10823 10824 override void visit(XorExp exp) 10825 { 10826 if (exp.type) 10827 { 10828 result = exp; 10829 return; 10830 } 10831 10832 if (Expression ex = binSemanticProp(exp, sc)) 10833 { 10834 result = ex; 10835 return; 10836 } 10837 Expression e = exp.op_overload(sc); 10838 if (e) 10839 { 10840 result = e; 10841 return; 10842 } 10843 10844 if (exp.e1.type.toBasetype().ty == Tbool && exp.e2.type.toBasetype().ty == Tbool) 10845 { 10846 exp.type = exp.e1.type; 10847 result = exp; 10848 return; 10849 } 10850 10851 if (Expression ex = typeCombine(exp, sc)) 10852 { 10853 result = ex; 10854 return; 10855 } 10856 10857 Type tb = exp.type.toBasetype(); 10858 if (tb.ty == Tarray || tb.ty == Tsarray) 10859 { 10860 if (!isArrayOpValid(exp)) 10861 { 10862 result = arrayOpInvalidError(exp); 10863 return; 10864 } 10865 result = exp; 10866 return; 10867 } 10868 if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype())) 10869 { 10870 result = exp.incompatibleTypes(); 10871 return; 10872 } 10873 if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc)) 10874 return setError(); 10875 10876 result = exp; 10877 } 10878 10879 override void visit(LogicalExp exp) 10880 { 10881 static if (LOGSEMANTIC) 10882 { 10883 printf("LogicalExp::semantic() %s\n", exp.toChars()); 10884 } 10885 10886 if (exp.type) 10887 { 10888 result = exp; 10889 return; 10890 } 10891 10892 exp.setNoderefOperands(); 10893 10894 Expression e1x = exp.e1.expressionSemantic(sc); 10895 10896 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684 10897 if (e1x.op == TOK.type) 10898 e1x = resolveAliasThis(sc, e1x); 10899 10900 e1x = resolveProperties(sc, e1x); 10901 e1x = e1x.toBoolean(sc); 10902 10903 if (sc.flags & SCOPE.condition) 10904 { 10905 /* If in static if, don't evaluate e2 if we don't have to. 10906 */ 10907 e1x = e1x.optimize(WANTvalue); 10908 if (e1x.isBool(exp.op == TOK.orOr)) 10909 { 10910 result = IntegerExp.createBool(exp.op == TOK.orOr); 10911 return; 10912 } 10913 } 10914 10915 CtorFlow ctorflow = sc.ctorflow.clone(); 10916 Expression e2x = exp.e2.expressionSemantic(sc); 10917 sc.merge(exp.loc, ctorflow); 10918 ctorflow.freeFieldinit(); 10919 10920 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684 10921 if (e2x.op == TOK.type) 10922 e2x = resolveAliasThis(sc, e2x); 10923 10924 e2x = resolveProperties(sc, e2x); 10925 10926 auto f1 = checkNonAssignmentArrayOp(e1x); 10927 auto f2 = checkNonAssignmentArrayOp(e2x); 10928 if (f1 || f2) 10929 return setError(); 10930 10931 // Unless the right operand is 'void', the expression is converted to 'bool'. 10932 if (e2x.type.ty != Tvoid) 10933 e2x = e2x.toBoolean(sc); 10934 10935 if (e2x.op == TOK.type || e2x.op == TOK.scope_) 10936 { 10937 exp.error("`%s` is not an expression", exp.e2.toChars()); 10938 return setError(); 10939 } 10940 if (e1x.op == TOK.error) 10941 { 10942 result = e1x; 10943 return; 10944 } 10945 if (e2x.op == TOK.error) 10946 { 10947 result = e2x; 10948 return; 10949 } 10950 10951 // The result type is 'bool', unless the right operand has type 'void'. 10952 if (e2x.type.ty == Tvoid) 10953 exp.type = Type.tvoid; 10954 else 10955 exp.type = Type.tbool; 10956 10957 exp.e1 = e1x; 10958 exp.e2 = e2x; 10959 result = exp; 10960 } 10961 10962 10963 override void visit(CmpExp exp) 10964 { 10965 static if (LOGSEMANTIC) 10966 { 10967 printf("CmpExp::semantic('%s')\n", exp.toChars()); 10968 } 10969 if (exp.type) 10970 { 10971 result = exp; 10972 return; 10973 } 10974 10975 exp.setNoderefOperands(); 10976 10977 if (Expression ex = binSemanticProp(exp, sc)) 10978 { 10979 result = ex; 10980 return; 10981 } 10982 Type t1 = exp.e1.type.toBasetype(); 10983 Type t2 = exp.e2.type.toBasetype(); 10984 if (t1.ty == Tclass && exp.e2.op == TOK.null_ || t2.ty == Tclass && exp.e1.op == TOK.null_) 10985 { 10986 exp.error("do not use `null` when comparing class types"); 10987 return setError(); 10988 } 10989 10990 TOK cmpop; 10991 if (auto e = exp.op_overload(sc, &cmpop)) 10992 { 10993 if (!e.type.isscalar() && e.type.equals(exp.e1.type)) 10994 { 10995 exp.error("recursive `opCmp` expansion"); 10996 return setError(); 10997 } 10998 if (e.op == TOK.call) 10999 { 11000 e = new CmpExp(cmpop, exp.loc, e, IntegerExp.literal!0); 11001 e = e.expressionSemantic(sc); 11002 } 11003 result = e; 11004 return; 11005 } 11006 11007 if (Expression ex = typeCombine(exp, sc)) 11008 { 11009 result = ex; 11010 return; 11011 } 11012 11013 auto f1 = checkNonAssignmentArrayOp(exp.e1); 11014 auto f2 = checkNonAssignmentArrayOp(exp.e2); 11015 if (f1 || f2) 11016 return setError(); 11017 11018 exp.type = Type.tbool; 11019 11020 // Special handling for array comparisons 11021 Expression arrayLowering = null; 11022 t1 = exp.e1.type.toBasetype(); 11023 t2 = exp.e2.type.toBasetype(); 11024 if ((t1.ty == Tarray || t1.ty == Tsarray || t1.ty == Tpointer) && (t2.ty == Tarray || t2.ty == Tsarray || t2.ty == Tpointer)) 11025 { 11026 Type t1next = t1.nextOf(); 11027 Type t2next = t2.nextOf(); 11028 if (t1next.implicitConvTo(t2next) < MATCH.constant && t2next.implicitConvTo(t1next) < MATCH.constant && (t1next.ty != Tvoid && t2next.ty != Tvoid)) 11029 { 11030 exp.error("array comparison type mismatch, `%s` vs `%s`", t1next.toChars(), t2next.toChars()); 11031 return setError(); 11032 } 11033 if ((t1.ty == Tarray || t1.ty == Tsarray) && (t2.ty == Tarray || t2.ty == Tsarray)) 11034 { 11035 if (!verifyHookExist(exp.loc, *sc, Id.__cmp, "comparing arrays")) 11036 return setError(); 11037 11038 // Lower to object.__cmp(e1, e2) 11039 Expression al = new IdentifierExp(exp.loc, Id.empty); 11040 al = new DotIdExp(exp.loc, al, Id.object); 11041 al = new DotIdExp(exp.loc, al, Id.__cmp); 11042 al = al.expressionSemantic(sc); 11043 11044 auto arguments = new Expressions(2); 11045 (*arguments)[0] = exp.e1; 11046 (*arguments)[1] = exp.e2; 11047 11048 al = new CallExp(exp.loc, al, arguments); 11049 al = new CmpExp(exp.op, exp.loc, al, IntegerExp.literal!0); 11050 11051 arrayLowering = al; 11052 } 11053 } 11054 else if (t1.ty == Tstruct || t2.ty == Tstruct || (t1.ty == Tclass && t2.ty == Tclass)) 11055 { 11056 if (t2.ty == Tstruct) 11057 exp.error("need member function `opCmp()` for %s `%s` to compare", t2.toDsymbol(sc).kind(), t2.toChars()); 11058 else 11059 exp.error("need member function `opCmp()` for %s `%s` to compare", t1.toDsymbol(sc).kind(), t1.toChars()); 11060 return setError(); 11061 } 11062 else if (t1.iscomplex() || t2.iscomplex()) 11063 { 11064 exp.error("compare not defined for complex operands"); 11065 return setError(); 11066 } 11067 else if (t1.ty == Taarray || t2.ty == Taarray) 11068 { 11069 exp.error("`%s` is not defined for associative arrays", Token.toChars(exp.op)); 11070 return setError(); 11071 } 11072 else if (!target.isVectorOpSupported(t1, exp.op, t2)) 11073 { 11074 result = exp.incompatibleTypes(); 11075 return; 11076 } 11077 else 11078 { 11079 bool r1 = exp.e1.checkValue() || exp.e1.checkSharedAccess(sc); 11080 bool r2 = exp.e2.checkValue() || exp.e2.checkSharedAccess(sc); 11081 if (r1 || r2) 11082 return setError(); 11083 } 11084 11085 //printf("CmpExp: %s, type = %s\n", e.toChars(), e.type.toChars()); 11086 if (arrayLowering) 11087 { 11088 arrayLowering = arrayLowering.expressionSemantic(sc); 11089 result = arrayLowering; 11090 return; 11091 } 11092 result = exp; 11093 return; 11094 } 11095 11096 override void visit(InExp exp) 11097 { 11098 if (exp.type) 11099 { 11100 result = exp; 11101 return; 11102 } 11103 11104 if (Expression ex = binSemanticProp(exp, sc)) 11105 { 11106 result = ex; 11107 return; 11108 } 11109 Expression e = exp.op_overload(sc); 11110 if (e) 11111 { 11112 result = e; 11113 return; 11114 } 11115 11116 Type t2b = exp.e2.type.toBasetype(); 11117 switch (t2b.ty) 11118 { 11119 case Taarray: 11120 { 11121 TypeAArray ta = cast(TypeAArray)t2b; 11122 11123 // Special handling for array keys 11124 if (!arrayTypeCompatibleWithoutCasting(exp.e1.type, ta.index)) 11125 { 11126 // Convert key to type of key 11127 exp.e1 = exp.e1.implicitCastTo(sc, ta.index); 11128 } 11129 11130 semanticTypeInfo(sc, ta.index); 11131 11132 // Return type is pointer to value 11133 exp.type = ta.nextOf().pointerTo(); 11134 break; 11135 } 11136 11137 case Terror: 11138 return setError(); 11139 11140 default: 11141 result = exp.incompatibleTypes(); 11142 return; 11143 } 11144 result = exp; 11145 } 11146 11147 override void visit(RemoveExp e) 11148 { 11149 if (Expression ex = binSemantic(e, sc)) 11150 { 11151 result = ex; 11152 return; 11153 } 11154 result = e; 11155 } 11156 11157 override void visit(EqualExp exp) 11158 { 11159 //printf("EqualExp::semantic('%s')\n", exp.toChars()); 11160 if (exp.type) 11161 { 11162 result = exp; 11163 return; 11164 } 11165 11166 exp.setNoderefOperands(); 11167 11168 if (auto e = binSemanticProp(exp, sc)) 11169 { 11170 result = e; 11171 return; 11172 } 11173 if (exp.e1.op == TOK.type || exp.e2.op == TOK.type) 11174 { 11175 /* https://issues.dlang.org/show_bug.cgi?id=12520 11176 * empty tuples are represented as types so special cases are added 11177 * so that they can be compared for equality with tuples of values. 11178 */ 11179 static auto extractTypeTupAndExpTup(Expression e) 11180 { 11181 static struct Result { bool ttEmpty; bool te; } 11182 auto tt = e.op == TOK.type ? e.isTypeExp().type.isTypeTuple() : null; 11183 return Result(tt && (!tt.arguments || !tt.arguments.dim), e.isTupleExp() !is null); 11184 } 11185 auto tups1 = extractTypeTupAndExpTup(exp.e1); 11186 auto tups2 = extractTypeTupAndExpTup(exp.e2); 11187 // AliasSeq!() == AliasSeq!(<at least a value>) 11188 if (tups1.ttEmpty && tups2.te) 11189 { 11190 result = IntegerExp.createBool(exp.op != TOK.equal); 11191 return; 11192 } 11193 // AliasSeq!(<at least a value>) == AliasSeq!() 11194 else if (tups1.te && tups2.ttEmpty) 11195 { 11196 result = IntegerExp.createBool(exp.op != TOK.equal); 11197 return; 11198 } 11199 // AliasSeq!() == AliasSeq!() 11200 else if (tups1.ttEmpty && tups2.ttEmpty) 11201 { 11202 result = IntegerExp.createBool(exp.op == TOK.equal); 11203 return; 11204 } 11205 // otherwise, two types are really not comparable 11206 result = exp.incompatibleTypes(); 11207 return; 11208 } 11209 11210 { 11211 auto t1 = exp.e1.type; 11212 auto t2 = exp.e2.type; 11213 if (t1.ty == Tenum && t2.ty == Tenum && !t1.equivalent(t2)) 11214 exp.error("Comparison between different enumeration types `%s` and `%s`; If this behavior is intended consider using `std.conv.asOriginalType`", 11215 t1.toChars(), t2.toChars()); 11216 } 11217 11218 /* Before checking for operator overloading, check to see if we're 11219 * comparing the addresses of two statics. If so, we can just see 11220 * if they are the same symbol. 11221 */ 11222 if (exp.e1.op == TOK.address && exp.e2.op == TOK.address) 11223 { 11224 AddrExp ae1 = cast(AddrExp)exp.e1; 11225 AddrExp ae2 = cast(AddrExp)exp.e2; 11226 if (ae1.e1.op == TOK.variable && ae2.e1.op == TOK.variable) 11227 { 11228 VarExp ve1 = cast(VarExp)ae1.e1; 11229 VarExp ve2 = cast(VarExp)ae2.e1; 11230 if (ve1.var == ve2.var) 11231 { 11232 // They are the same, result is 'true' for ==, 'false' for != 11233 result = IntegerExp.createBool(exp.op == TOK.equal); 11234 return; 11235 } 11236 } 11237 } 11238 11239 Type t1 = exp.e1.type.toBasetype(); 11240 Type t2 = exp.e2.type.toBasetype(); 11241 11242 // Indicates whether the comparison of the 2 specified array types 11243 // requires an object.__equals() lowering. 11244 static bool needsDirectEq(Type t1, Type t2, Scope* sc) 11245 { 11246 Type t1n = t1.nextOf().toBasetype(); 11247 Type t2n = t2.nextOf().toBasetype(); 11248 if ((t1n.ty.isSomeChar && t2n.ty.isSomeChar) || 11249 (t1n.ty == Tvoid || t2n.ty == Tvoid)) 11250 { 11251 return false; 11252 } 11253 if (t1n.constOf() != t2n.constOf()) 11254 return true; 11255 11256 Type t = t1n; 11257 while (t.toBasetype().nextOf()) 11258 t = t.nextOf().toBasetype(); 11259 if (auto ts = t.isTypeStruct()) 11260 { 11261 // semanticTypeInfo() makes sure hasIdentityEquals has been computed 11262 if (global.params.useTypeInfo && Type.dtypeinfo) 11263 semanticTypeInfo(sc, ts); 11264 11265 return ts.sym.hasIdentityEquals; // has custom opEquals 11266 } 11267 11268 return false; 11269 } 11270 11271 if (auto e = exp.op_overload(sc)) 11272 { 11273 result = e; 11274 return; 11275 } 11276 11277 11278 const isArrayComparison = (t1.ty == Tarray || t1.ty == Tsarray) && 11279 (t2.ty == Tarray || t2.ty == Tsarray); 11280 const needsArrayLowering = isArrayComparison && needsDirectEq(t1, t2, sc); 11281 11282 if (!needsArrayLowering) 11283 { 11284 if (auto e = typeCombine(exp, sc)) 11285 { 11286 result = e; 11287 return; 11288 } 11289 } 11290 11291 auto f1 = checkNonAssignmentArrayOp(exp.e1); 11292 auto f2 = checkNonAssignmentArrayOp(exp.e2); 11293 if (f1 || f2) 11294 return setError(); 11295 11296 exp.type = Type.tbool; 11297 11298 if (!isArrayComparison) 11299 { 11300 if (exp.e1.type != exp.e2.type && exp.e1.type.isfloating() && exp.e2.type.isfloating()) 11301 { 11302 // Cast both to complex 11303 exp.e1 = exp.e1.castTo(sc, Type.tcomplex80); 11304 exp.e2 = exp.e2.castTo(sc, Type.tcomplex80); 11305 } 11306 } 11307 11308 // lower some array comparisons to object.__equals(e1, e2) 11309 if (needsArrayLowering || (t1.ty == Tarray && t2.ty == Tarray)) 11310 { 11311 //printf("Lowering to __equals %s %s\n", exp.e1.toChars(), exp.e2.toChars()); 11312 11313 if (!verifyHookExist(exp.loc, *sc, Id.__equals, "equal checks on arrays")) 11314 return setError(); 11315 11316 Expression __equals = new IdentifierExp(exp.loc, Id.empty); 11317 Identifier id = Identifier.idPool("__equals"); 11318 __equals = new DotIdExp(exp.loc, __equals, Id.object); 11319 __equals = new DotIdExp(exp.loc, __equals, id); 11320 11321 auto arguments = new Expressions(2); 11322 (*arguments)[0] = exp.e1; 11323 (*arguments)[1] = exp.e2; 11324 11325 __equals = new CallExp(exp.loc, __equals, arguments); 11326 if (exp.op == TOK.notEqual) 11327 { 11328 __equals = new NotExp(exp.loc, __equals); 11329 } 11330 __equals = __equals.trySemantic(sc); // for better error message 11331 if (!__equals) 11332 { 11333 exp.error("incompatible types for array comparison: `%s` and `%s`", 11334 exp.e1.type.toChars(), exp.e2.type.toChars()); 11335 __equals = ErrorExp.get(); 11336 } 11337 11338 result = __equals; 11339 return; 11340 } 11341 11342 if (exp.e1.type.toBasetype().ty == Taarray) 11343 semanticTypeInfo(sc, exp.e1.type.toBasetype()); 11344 11345 11346 if (!target.isVectorOpSupported(t1, exp.op, t2)) 11347 { 11348 result = exp.incompatibleTypes(); 11349 return; 11350 } 11351 11352 result = exp; 11353 } 11354 11355 override void visit(IdentityExp exp) 11356 { 11357 if (exp.type) 11358 { 11359 result = exp; 11360 return; 11361 } 11362 11363 exp.setNoderefOperands(); 11364 11365 if (auto e = binSemanticProp(exp, sc)) 11366 { 11367 result = e; 11368 return; 11369 } 11370 11371 if (auto e = typeCombine(exp, sc)) 11372 { 11373 result = e; 11374 return; 11375 } 11376 11377 auto f1 = checkNonAssignmentArrayOp(exp.e1); 11378 auto f2 = checkNonAssignmentArrayOp(exp.e2); 11379 if (f1 || f2) 11380 return setError(); 11381 11382 if (exp.e1.op == TOK.type || exp.e2.op == TOK.type) 11383 { 11384 result = exp.incompatibleTypes(); 11385 return; 11386 } 11387 11388 exp.type = Type.tbool; 11389 11390 if (exp.e1.type != exp.e2.type && exp.e1.type.isfloating() && exp.e2.type.isfloating()) 11391 { 11392 // Cast both to complex 11393 exp.e1 = exp.e1.castTo(sc, Type.tcomplex80); 11394 exp.e2 = exp.e2.castTo(sc, Type.tcomplex80); 11395 } 11396 11397 auto tb1 = exp.e1.type.toBasetype(); 11398 auto tb2 = exp.e2.type.toBasetype(); 11399 if (!target.isVectorOpSupported(tb1, exp.op, tb2)) 11400 { 11401 result = exp.incompatibleTypes(); 11402 return; 11403 } 11404 11405 if (exp.e1.op == TOK.call) 11406 exp.e1 = (cast(CallExp)exp.e1).addDtorHook(sc); 11407 if (exp.e2.op == TOK.call) 11408 exp.e2 = (cast(CallExp)exp.e2).addDtorHook(sc); 11409 11410 if (exp.e1.type.toBasetype().ty == Tsarray || 11411 exp.e2.type.toBasetype().ty == Tsarray) 11412 exp.deprecation("identity comparison of static arrays " 11413 ~ "implicitly coerces them to slices, " 11414 ~ "which are compared by reference"); 11415 11416 result = exp; 11417 } 11418 11419 override void visit(CondExp exp) 11420 { 11421 static if (LOGSEMANTIC) 11422 { 11423 printf("CondExp::semantic('%s')\n", exp.toChars()); 11424 } 11425 if (exp.type) 11426 { 11427 result = exp; 11428 return; 11429 } 11430 11431 if (exp.econd.op == TOK.dotIdentifier) 11432 (cast(DotIdExp)exp.econd).noderef = true; 11433 11434 Expression ec = exp.econd.expressionSemantic(sc); 11435 ec = resolveProperties(sc, ec); 11436 ec = ec.toBoolean(sc); 11437 11438 CtorFlow ctorflow_root = sc.ctorflow.clone(); 11439 Expression e1x = exp.e1.expressionSemantic(sc); 11440 e1x = resolveProperties(sc, e1x); 11441 11442 CtorFlow ctorflow1 = sc.ctorflow; 11443 sc.ctorflow = ctorflow_root; 11444 Expression e2x = exp.e2.expressionSemantic(sc); 11445 e2x = resolveProperties(sc, e2x); 11446 11447 sc.merge(exp.loc, ctorflow1); 11448 ctorflow1.freeFieldinit(); 11449 11450 if (ec.op == TOK.error) 11451 { 11452 result = ec; 11453 return; 11454 } 11455 if (ec.type == Type.terror) 11456 return setError(); 11457 exp.econd = ec; 11458 11459 if (e1x.op == TOK.error) 11460 { 11461 result = e1x; 11462 return; 11463 } 11464 if (e1x.type == Type.terror) 11465 return setError(); 11466 exp.e1 = e1x; 11467 11468 if (e2x.op == TOK.error) 11469 { 11470 result = e2x; 11471 return; 11472 } 11473 if (e2x.type == Type.terror) 11474 return setError(); 11475 exp.e2 = e2x; 11476 11477 auto f0 = checkNonAssignmentArrayOp(exp.econd); 11478 auto f1 = checkNonAssignmentArrayOp(exp.e1); 11479 auto f2 = checkNonAssignmentArrayOp(exp.e2); 11480 if (f0 || f1 || f2) 11481 return setError(); 11482 11483 Type t1 = exp.e1.type; 11484 Type t2 = exp.e2.type; 11485 // If either operand is void the result is void, we have to cast both 11486 // the expression to void so that we explicitly discard the expression 11487 // value if any 11488 // https://issues.dlang.org/show_bug.cgi?id=16598 11489 if (t1.ty == Tvoid || t2.ty == Tvoid) 11490 { 11491 exp.type = Type.tvoid; 11492 exp.e1 = exp.e1.castTo(sc, exp.type); 11493 exp.e2 = exp.e2.castTo(sc, exp.type); 11494 } 11495 else if (t1 == t2) 11496 exp.type = t1; 11497 else 11498 { 11499 if (Expression ex = typeCombine(exp, sc)) 11500 { 11501 result = ex; 11502 return; 11503 } 11504 11505 switch (exp.e1.type.toBasetype().ty) 11506 { 11507 case Tcomplex32: 11508 case Tcomplex64: 11509 case Tcomplex80: 11510 exp.e2 = exp.e2.castTo(sc, exp.e1.type); 11511 break; 11512 default: 11513 break; 11514 } 11515 switch (exp.e2.type.toBasetype().ty) 11516 { 11517 case Tcomplex32: 11518 case Tcomplex64: 11519 case Tcomplex80: 11520 exp.e1 = exp.e1.castTo(sc, exp.e2.type); 11521 break; 11522 default: 11523 break; 11524 } 11525 if (exp.type.toBasetype().ty == Tarray) 11526 { 11527 exp.e1 = exp.e1.castTo(sc, exp.type); 11528 exp.e2 = exp.e2.castTo(sc, exp.type); 11529 } 11530 } 11531 exp.type = exp.type.merge2(); 11532 version (none) 11533 { 11534 printf("res: %s\n", exp.type.toChars()); 11535 printf("e1 : %s\n", exp.e1.type.toChars()); 11536 printf("e2 : %s\n", exp.e2.type.toChars()); 11537 } 11538 11539 /* https://issues.dlang.org/show_bug.cgi?id=14696 11540 * If either e1 or e2 contain temporaries which need dtor, 11541 * make them conditional. 11542 * Rewrite: 11543 * cond ? (__tmp1 = ..., __tmp1) : (__tmp2 = ..., __tmp2) 11544 * to: 11545 * (auto __cond = cond) ? (... __tmp1) : (... __tmp2) 11546 * and replace edtors of __tmp1 and __tmp2 with: 11547 * __tmp1.edtor --> __cond && __tmp1.dtor() 11548 * __tmp2.edtor --> __cond || __tmp2.dtor() 11549 */ 11550 exp.hookDtors(sc); 11551 11552 result = exp; 11553 } 11554 11555 override void visit(FileInitExp e) 11556 { 11557 //printf("FileInitExp::semantic()\n"); 11558 e.type = Type.tstring; 11559 result = e; 11560 } 11561 11562 override void visit(LineInitExp e) 11563 { 11564 e.type = Type.tint32; 11565 result = e; 11566 } 11567 11568 override void visit(ModuleInitExp e) 11569 { 11570 //printf("ModuleInitExp::semantic()\n"); 11571 e.type = Type.tstring; 11572 result = e; 11573 } 11574 11575 override void visit(FuncInitExp e) 11576 { 11577 //printf("FuncInitExp::semantic()\n"); 11578 e.type = Type.tstring; 11579 if (sc.func) 11580 { 11581 result = e.resolveLoc(Loc.initial, sc); 11582 return; 11583 } 11584 result = e; 11585 } 11586 11587 override void visit(PrettyFuncInitExp e) 11588 { 11589 //printf("PrettyFuncInitExp::semantic()\n"); 11590 e.type = Type.tstring; 11591 if (sc.func) 11592 { 11593 result = e.resolveLoc(Loc.initial, sc); 11594 return; 11595 } 11596 11597 result = e; 11598 } 11599 } 11600 11601 /********************************** 11602 * Try to run semantic routines. 11603 * If they fail, return NULL. 11604 */ 11605 Expression trySemantic(Expression exp, Scope* sc) 11606 { 11607 //printf("+trySemantic(%s)\n", exp.toChars()); 11608 uint errors = global.startGagging(); 11609 Expression e = expressionSemantic(exp, sc); 11610 if (global.endGagging(errors)) 11611 { 11612 e = null; 11613 } 11614 //printf("-trySemantic(%s)\n", exp.toChars()); 11615 return e; 11616 } 11617 11618 /************************** 11619 * Helper function for easy error propagation. 11620 * If error occurs, returns ErrorExp. Otherwise returns NULL. 11621 */ 11622 Expression unaSemantic(UnaExp e, Scope* sc) 11623 { 11624 static if (LOGSEMANTIC) 11625 { 11626 printf("UnaExp::semantic('%s')\n", e.toChars()); 11627 } 11628 Expression e1x = e.e1.expressionSemantic(sc); 11629 if (e1x.op == TOK.error) 11630 return e1x; 11631 e.e1 = e1x; 11632 return null; 11633 } 11634 11635 /************************** 11636 * Helper function for easy error propagation. 11637 * If error occurs, returns ErrorExp. Otherwise returns NULL. 11638 */ 11639 Expression binSemantic(BinExp e, Scope* sc) 11640 { 11641 static if (LOGSEMANTIC) 11642 { 11643 printf("BinExp::semantic('%s')\n", e.toChars()); 11644 } 11645 Expression e1x = e.e1.expressionSemantic(sc); 11646 Expression e2x = e.e2.expressionSemantic(sc); 11647 11648 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684 11649 if (e1x.op == TOK.type) 11650 e1x = resolveAliasThis(sc, e1x); 11651 if (e2x.op == TOK.type) 11652 e2x = resolveAliasThis(sc, e2x); 11653 11654 if (e1x.op == TOK.error) 11655 return e1x; 11656 if (e2x.op == TOK.error) 11657 return e2x; 11658 e.e1 = e1x; 11659 e.e2 = e2x; 11660 return null; 11661 } 11662 11663 Expression binSemanticProp(BinExp e, Scope* sc) 11664 { 11665 if (Expression ex = binSemantic(e, sc)) 11666 return ex; 11667 Expression e1x = resolveProperties(sc, e.e1); 11668 Expression e2x = resolveProperties(sc, e.e2); 11669 if (e1x.op == TOK.error) 11670 return e1x; 11671 if (e2x.op == TOK.error) 11672 return e2x; 11673 e.e1 = e1x; 11674 e.e2 = e2x; 11675 return null; 11676 } 11677 11678 // entrypoint for semantic ExpressionSemanticVisitor 11679 extern (C++) Expression expressionSemantic(Expression e, Scope* sc) 11680 { 11681 scope v = new ExpressionSemanticVisitor(sc); 11682 e.accept(v); 11683 return v.result; 11684 } 11685 11686 Expression semanticX(DotIdExp exp, Scope* sc) 11687 { 11688 //printf("DotIdExp::semanticX(this = %p, '%s')\n", this, toChars()); 11689 if (Expression ex = unaSemantic(exp, sc)) 11690 return ex; 11691 11692 if (exp.ident == Id._mangleof) 11693 { 11694 // symbol.mangleof 11695 Dsymbol ds; 11696 switch (exp.e1.op) 11697 { 11698 case TOK.scope_: 11699 ds = (cast(ScopeExp)exp.e1).sds; 11700 goto L1; 11701 case TOK.variable: 11702 ds = (cast(VarExp)exp.e1).var; 11703 goto L1; 11704 case TOK.dotVariable: 11705 ds = (cast(DotVarExp)exp.e1).var; 11706 goto L1; 11707 case TOK.overloadSet: 11708 ds = (cast(OverExp)exp.e1).vars; 11709 goto L1; 11710 case TOK.template_: 11711 { 11712 TemplateExp te = cast(TemplateExp)exp.e1; 11713 ds = te.fd ? cast(Dsymbol)te.fd : te.td; 11714 } 11715 L1: 11716 { 11717 assert(ds); 11718 if (auto f = ds.isFuncDeclaration()) 11719 { 11720 if (f.checkForwardRef(exp.loc)) 11721 { 11722 return ErrorExp.get(); 11723 } 11724 if (f.flags & (FUNCFLAG.purityInprocess | FUNCFLAG.safetyInprocess | 11725 FUNCFLAG.nothrowInprocess | FUNCFLAG.nogcInprocess)) 11726 { 11727 f.error(exp.loc, "cannot retrieve its `.mangleof` while inferring attributes"); 11728 return ErrorExp.get(); 11729 } 11730 } 11731 OutBuffer buf; 11732 mangleToBuffer(ds, &buf); 11733 Expression e = new StringExp(exp.loc, buf.extractSlice()); 11734 e = e.expressionSemantic(sc); 11735 return e; 11736 } 11737 default: 11738 break; 11739 } 11740 } 11741 11742 if (exp.e1.op == TOK.variable && exp.e1.type.toBasetype().ty == Tsarray && exp.ident == Id.length) 11743 { 11744 // bypass checkPurity 11745 return exp.e1.type.dotExp(sc, exp.e1, exp.ident, exp.noderef ? DotExpFlag.noDeref : 0); 11746 } 11747 11748 if (exp.e1.op == TOK.dot) 11749 { 11750 } 11751 else 11752 { 11753 exp.e1 = resolvePropertiesX(sc, exp.e1); 11754 } 11755 if (exp.e1.op == TOK.tuple && exp.ident == Id.offsetof) 11756 { 11757 /* 'distribute' the .offsetof to each of the tuple elements. 11758 */ 11759 TupleExp te = cast(TupleExp)exp.e1; 11760 auto exps = new Expressions(te.exps.dim); 11761 for (size_t i = 0; i < exps.dim; i++) 11762 { 11763 Expression e = (*te.exps)[i]; 11764 e = e.expressionSemantic(sc); 11765 e = new DotIdExp(e.loc, e, Id.offsetof); 11766 (*exps)[i] = e; 11767 } 11768 // Don't evaluate te.e0 in runtime 11769 Expression e = new TupleExp(exp.loc, null, exps); 11770 e = e.expressionSemantic(sc); 11771 return e; 11772 } 11773 if (exp.e1.op == TOK.tuple && exp.ident == Id.length) 11774 { 11775 TupleExp te = cast(TupleExp)exp.e1; 11776 // Don't evaluate te.e0 in runtime 11777 Expression e = new IntegerExp(exp.loc, te.exps.dim, Type.tsize_t); 11778 return e; 11779 } 11780 11781 // https://issues.dlang.org/show_bug.cgi?id=14416 11782 // Template has no built-in properties except for 'stringof'. 11783 if ((exp.e1.op == TOK.dotTemplateDeclaration || exp.e1.op == TOK.template_) && exp.ident != Id.stringof) 11784 { 11785 exp.error("template `%s` does not have property `%s`", exp.e1.toChars(), exp.ident.toChars()); 11786 return ErrorExp.get(); 11787 } 11788 if (!exp.e1.type) 11789 { 11790 exp.error("expression `%s` does not have property `%s`", exp.e1.toChars(), exp.ident.toChars()); 11791 return ErrorExp.get(); 11792 } 11793 11794 return exp; 11795 } 11796 11797 // Resolve e1.ident without seeing UFCS. 11798 // If flag == 1, stop "not a property" error and return NULL. 11799 Expression semanticY(DotIdExp exp, Scope* sc, int flag) 11800 { 11801 //printf("DotIdExp::semanticY(this = %p, '%s')\n", exp, exp.toChars()); 11802 11803 //{ static int z; fflush(stdout); if (++z == 10) *(char*)0=0; } 11804 11805 /* Special case: rewrite this.id and super.id 11806 * to be classtype.id and baseclasstype.id 11807 * if we have no this pointer. 11808 */ 11809 if ((exp.e1.op == TOK.this_ || exp.e1.op == TOK.super_) && !hasThis(sc)) 11810 { 11811 if (AggregateDeclaration ad = sc.getStructClassScope()) 11812 { 11813 if (exp.e1.op == TOK.this_) 11814 { 11815 exp.e1 = new TypeExp(exp.e1.loc, ad.type); 11816 } 11817 else 11818 { 11819 ClassDeclaration cd = ad.isClassDeclaration(); 11820 if (cd && cd.baseClass) 11821 exp.e1 = new TypeExp(exp.e1.loc, cd.baseClass.type); 11822 } 11823 } 11824 } 11825 11826 Expression e = semanticX(exp, sc); 11827 if (e != exp) 11828 return e; 11829 11830 Expression eleft; 11831 Expression eright; 11832 if (exp.e1.op == TOK.dot) 11833 { 11834 DotExp de = cast(DotExp)exp.e1; 11835 eleft = de.e1; 11836 eright = de.e2; 11837 } 11838 else 11839 { 11840 eleft = null; 11841 eright = exp.e1; 11842 } 11843 11844 Type t1b = exp.e1.type.toBasetype(); 11845 11846 if (eright.op == TOK.scope_) // also used for template alias's 11847 { 11848 ScopeExp ie = cast(ScopeExp)eright; 11849 11850 int flags = SearchLocalsOnly; 11851 /* Disable access to another module's private imports. 11852 * The check for 'is sds our current module' is because 11853 * the current module should have access to its own imports. 11854 */ 11855 if (ie.sds.isModule() && ie.sds != sc._module) 11856 flags |= IgnorePrivateImports; 11857 if (sc.flags & SCOPE.ignoresymbolvisibility) 11858 flags |= IgnoreSymbolVisibility; 11859 Dsymbol s = ie.sds.search(exp.loc, exp.ident, flags); 11860 /* Check for visibility before resolving aliases because public 11861 * aliases to private symbols are public. 11862 */ 11863 if (s && !(sc.flags & SCOPE.ignoresymbolvisibility) && !symbolIsVisible(sc._module, s)) 11864 { 11865 s = null; 11866 } 11867 if (s) 11868 { 11869 auto p = s.isPackage(); 11870 if (p && checkAccess(sc, p)) 11871 { 11872 s = null; 11873 } 11874 } 11875 if (s) 11876 { 11877 // if 's' is a tuple variable, the tuple is returned. 11878 s = s.toAlias(); 11879 11880 exp.checkDeprecated(sc, s); 11881 exp.checkDisabled(sc, s); 11882 11883 EnumMember em = s.isEnumMember(); 11884 if (em) 11885 { 11886 return em.getVarExp(exp.loc, sc); 11887 } 11888 VarDeclaration v = s.isVarDeclaration(); 11889 if (v) 11890 { 11891 //printf("DotIdExp:: Identifier '%s' is a variable, type '%s'\n", toChars(), v.type.toChars()); 11892 if (!v.type || 11893 !v.type.deco && v.inuse) 11894 { 11895 if (v.inuse) 11896 exp.error("circular reference to %s `%s`", v.kind(), v.toPrettyChars()); 11897 else 11898 exp.error("forward reference to %s `%s`", v.kind(), v.toPrettyChars()); 11899 return ErrorExp.get(); 11900 } 11901 if (v.type.ty == Terror) 11902 return ErrorExp.get(); 11903 11904 if ((v.storage_class & STC.manifest) && v._init && !exp.wantsym) 11905 { 11906 /* Normally, the replacement of a symbol with its initializer is supposed to be in semantic2(). 11907 * Introduced by https://github.com/dlang/dmd/pull/5588 which should probably 11908 * be reverted. `wantsym` is the hack to work around the problem. 11909 */ 11910 if (v.inuse) 11911 { 11912 error(exp.loc, "circular initialization of %s `%s`", v.kind(), v.toPrettyChars()); 11913 return ErrorExp.get(); 11914 } 11915 e = v.expandInitializer(exp.loc); 11916 v.inuse++; 11917 e = e.expressionSemantic(sc); 11918 v.inuse--; 11919 return e; 11920 } 11921 11922 if (v.needThis()) 11923 { 11924 if (!eleft) 11925 eleft = new ThisExp(exp.loc); 11926 e = new DotVarExp(exp.loc, eleft, v); 11927 e = e.expressionSemantic(sc); 11928 } 11929 else 11930 { 11931 e = new VarExp(exp.loc, v); 11932 if (eleft) 11933 { 11934 e = new CommaExp(exp.loc, eleft, e); 11935 e.type = v.type; 11936 } 11937 } 11938 e = e.deref(); 11939 return e.expressionSemantic(sc); 11940 } 11941 11942 FuncDeclaration f = s.isFuncDeclaration(); 11943 if (f) 11944 { 11945 //printf("it's a function\n"); 11946 if (!f.functionSemantic()) 11947 return ErrorExp.get(); 11948 if (f.needThis()) 11949 { 11950 if (!eleft) 11951 eleft = new ThisExp(exp.loc); 11952 e = new DotVarExp(exp.loc, eleft, f, true); 11953 e = e.expressionSemantic(sc); 11954 } 11955 else 11956 { 11957 e = new VarExp(exp.loc, f, true); 11958 if (eleft) 11959 { 11960 e = new CommaExp(exp.loc, eleft, e); 11961 e.type = f.type; 11962 } 11963 } 11964 return e; 11965 } 11966 if (auto td = s.isTemplateDeclaration()) 11967 { 11968 if (eleft) 11969 e = new DotTemplateExp(exp.loc, eleft, td); 11970 else 11971 e = new TemplateExp(exp.loc, td); 11972 e = e.expressionSemantic(sc); 11973 return e; 11974 } 11975 if (OverDeclaration od = s.isOverDeclaration()) 11976 { 11977 e = new VarExp(exp.loc, od, true); 11978 if (eleft) 11979 { 11980 e = new CommaExp(exp.loc, eleft, e); 11981 e.type = Type.tvoid; // ambiguous type? 11982 } 11983 return e; 11984 } 11985 OverloadSet o = s.isOverloadSet(); 11986 if (o) 11987 { 11988 //printf("'%s' is an overload set\n", o.toChars()); 11989 return new OverExp(exp.loc, o); 11990 } 11991 11992 if (auto t = s.getType()) 11993 { 11994 return (new TypeExp(exp.loc, t)).expressionSemantic(sc); 11995 } 11996 11997 TupleDeclaration tup = s.isTupleDeclaration(); 11998 if (tup) 11999 { 12000 if (eleft) 12001 { 12002 e = new DotVarExp(exp.loc, eleft, tup); 12003 e = e.expressionSemantic(sc); 12004 return e; 12005 } 12006 e = new TupleExp(exp.loc, tup); 12007 e = e.expressionSemantic(sc); 12008 return e; 12009 } 12010 12011 ScopeDsymbol sds = s.isScopeDsymbol(); 12012 if (sds) 12013 { 12014 //printf("it's a ScopeDsymbol %s\n", ident.toChars()); 12015 e = new ScopeExp(exp.loc, sds); 12016 e = e.expressionSemantic(sc); 12017 if (eleft) 12018 e = new DotExp(exp.loc, eleft, e); 12019 return e; 12020 } 12021 12022 Import imp = s.isImport(); 12023 if (imp) 12024 { 12025 ie = new ScopeExp(exp.loc, imp.pkg); 12026 return ie.expressionSemantic(sc); 12027 } 12028 // BUG: handle other cases like in IdentifierExp::semantic() 12029 debug 12030 { 12031 printf("s = '%s', kind = '%s'\n", s.toChars(), s.kind()); 12032 } 12033 assert(0); 12034 } 12035 else if (exp.ident == Id.stringof) 12036 { 12037 e = new StringExp(exp.loc, ie.toString()); 12038 e = e.expressionSemantic(sc); 12039 return e; 12040 } 12041 if (ie.sds.isPackage() || ie.sds.isImport() || ie.sds.isModule()) 12042 { 12043 flag = 0; 12044 } 12045 if (flag) 12046 return null; 12047 s = ie.sds.search_correct(exp.ident); 12048 if (s && symbolIsVisible(sc, s)) 12049 { 12050 if (s.isPackage()) 12051 exp.error("undefined identifier `%s` in %s `%s`, perhaps add `static import %s;`", exp.ident.toChars(), ie.sds.kind(), ie.sds.toPrettyChars(), s.toPrettyChars()); 12052 else 12053 exp.error("undefined identifier `%s` in %s `%s`, did you mean %s `%s`?", exp.ident.toChars(), ie.sds.kind(), ie.sds.toPrettyChars(), s.kind(), s.toChars()); 12054 } 12055 else 12056 exp.error("undefined identifier `%s` in %s `%s`", exp.ident.toChars(), ie.sds.kind(), ie.sds.toPrettyChars()); 12057 return ErrorExp.get(); 12058 } 12059 else if (t1b.ty == Tpointer && exp.e1.type.ty != Tenum && exp.ident != Id._init && exp.ident != Id.__sizeof && exp.ident != Id.__xalignof && exp.ident != Id.offsetof && exp.ident != Id._mangleof && exp.ident != Id.stringof) 12060 { 12061 Type t1bn = t1b.nextOf(); 12062 if (flag) 12063 { 12064 AggregateDeclaration ad = isAggregate(t1bn); 12065 if (ad && !ad.members) // https://issues.dlang.org/show_bug.cgi?id=11312 12066 return null; 12067 } 12068 12069 /* Rewrite: 12070 * p.ident 12071 * as: 12072 * (*p).ident 12073 */ 12074 if (flag && t1bn.ty == Tvoid) 12075 return null; 12076 e = new PtrExp(exp.loc, exp.e1); 12077 e = e.expressionSemantic(sc); 12078 return e.type.dotExp(sc, e, exp.ident, flag | (exp.noderef ? DotExpFlag.noDeref : 0)); 12079 } 12080 else 12081 { 12082 if (exp.e1.op == TOK.type || exp.e1.op == TOK.template_) 12083 flag = 0; 12084 e = exp.e1.type.dotExp(sc, exp.e1, exp.ident, flag | (exp.noderef ? DotExpFlag.noDeref : 0)); 12085 if (e) 12086 e = e.expressionSemantic(sc); 12087 return e; 12088 } 12089 } 12090 12091 // Resolve e1.ident!tiargs without seeing UFCS. 12092 // If flag == 1, stop "not a property" error and return NULL. 12093 Expression semanticY(DotTemplateInstanceExp exp, Scope* sc, int flag) 12094 { 12095 static if (LOGSEMANTIC) 12096 { 12097 printf("DotTemplateInstanceExpY::semantic('%s')\n", exp.toChars()); 12098 } 12099 12100 static Expression errorExp() 12101 { 12102 return ErrorExp.get(); 12103 } 12104 12105 Expression e1 = exp.e1; 12106 12107 if (exp.ti.tempdecl && exp.ti.tempdecl.parent && exp.ti.tempdecl.parent.isTemplateMixin()) 12108 { 12109 // if 'ti.tempdecl' happens to be found in a mixin template don't lose that info 12110 // and do the symbol search in that context (Issue: 19476) 12111 auto tm = cast(TemplateMixin)exp.ti.tempdecl.parent; 12112 e1 = new DotExp(exp.e1.loc, exp.e1, new ScopeExp(tm.loc, tm)); 12113 } 12114 12115 auto die = new DotIdExp(exp.loc, e1, exp.ti.name); 12116 12117 Expression e = die.semanticX(sc); 12118 if (e == die) 12119 { 12120 exp.e1 = die.e1; // take back 12121 Type t1b = exp.e1.type.toBasetype(); 12122 if (t1b.ty == Tarray || t1b.ty == Tsarray || t1b.ty == Taarray || t1b.ty == Tnull || (t1b.isTypeBasic() && t1b.ty != Tvoid)) 12123 { 12124 /* No built-in type has templatized properties, so do shortcut. 12125 * It is necessary in: 1024.max!"a < b" 12126 */ 12127 if (flag) 12128 return null; 12129 } 12130 e = die.semanticY(sc, flag); 12131 if (flag) 12132 { 12133 if (!e || 12134 isDotOpDispatch(e)) 12135 { 12136 /* opDispatch!tiargs would be a function template that needs IFTI, 12137 * so it's not a template 12138 */ 12139 return null; 12140 } 12141 } 12142 } 12143 assert(e); 12144 12145 if (e.op == TOK.error) 12146 return e; 12147 if (e.op == TOK.dotVariable) 12148 { 12149 DotVarExp dve = cast(DotVarExp)e; 12150 if (FuncDeclaration fd = dve.var.isFuncDeclaration()) 12151 { 12152 if (TemplateDeclaration td = fd.findTemplateDeclRoot()) 12153 { 12154 e = new DotTemplateExp(dve.loc, dve.e1, td); 12155 e = e.expressionSemantic(sc); 12156 } 12157 } 12158 else if (OverDeclaration od = dve.var.isOverDeclaration()) 12159 { 12160 exp.e1 = dve.e1; // pull semantic() result 12161 12162 if (!exp.findTempDecl(sc)) 12163 goto Lerr; 12164 if (exp.ti.needsTypeInference(sc)) 12165 return exp; 12166 exp.ti.dsymbolSemantic(sc); 12167 if (!exp.ti.inst || exp.ti.errors) // if template failed to expand 12168 return errorExp(); 12169 12170 if (Declaration v = exp.ti.toAlias().isDeclaration()) 12171 { 12172 if (v.type && !v.type.deco) 12173 v.type = v.type.typeSemantic(v.loc, sc); 12174 return new DotVarExp(exp.loc, exp.e1, v) 12175 .expressionSemantic(sc); 12176 } 12177 return new DotExp(exp.loc, exp.e1, new ScopeExp(exp.loc, exp.ti)) 12178 .expressionSemantic(sc); 12179 } 12180 } 12181 else if (e.op == TOK.variable) 12182 { 12183 VarExp ve = cast(VarExp)e; 12184 if (FuncDeclaration fd = ve.var.isFuncDeclaration()) 12185 { 12186 if (TemplateDeclaration td = fd.findTemplateDeclRoot()) 12187 { 12188 e = new TemplateExp(ve.loc, td) 12189 .expressionSemantic(sc); 12190 } 12191 } 12192 else if (OverDeclaration od = ve.var.isOverDeclaration()) 12193 { 12194 exp.ti.tempdecl = od; 12195 return new ScopeExp(exp.loc, exp.ti) 12196 .expressionSemantic(sc); 12197 } 12198 } 12199 12200 if (e.op == TOK.dotTemplateDeclaration) 12201 { 12202 DotTemplateExp dte = cast(DotTemplateExp)e; 12203 exp.e1 = dte.e1; // pull semantic() result 12204 12205 exp.ti.tempdecl = dte.td; 12206 if (!exp.ti.semanticTiargs(sc)) 12207 return errorExp(); 12208 if (exp.ti.needsTypeInference(sc)) 12209 return exp; 12210 exp.ti.dsymbolSemantic(sc); 12211 if (!exp.ti.inst || exp.ti.errors) // if template failed to expand 12212 return errorExp(); 12213 12214 if (Declaration v = exp.ti.toAlias().isDeclaration()) 12215 { 12216 if (v.isFuncDeclaration() || v.isVarDeclaration()) 12217 { 12218 return new DotVarExp(exp.loc, exp.e1, v) 12219 .expressionSemantic(sc); 12220 } 12221 } 12222 return new DotExp(exp.loc, exp.e1, new ScopeExp(exp.loc, exp.ti)) 12223 .expressionSemantic(sc); 12224 } 12225 else if (e.op == TOK.template_) 12226 { 12227 exp.ti.tempdecl = (cast(TemplateExp)e).td; 12228 return new ScopeExp(exp.loc, exp.ti) 12229 .expressionSemantic(sc); 12230 } 12231 else if (e.op == TOK.dot) 12232 { 12233 DotExp de = cast(DotExp)e; 12234 12235 if (de.e2.op == TOK.overloadSet) 12236 { 12237 if (!exp.findTempDecl(sc) || !exp.ti.semanticTiargs(sc)) 12238 { 12239 return errorExp(); 12240 } 12241 if (exp.ti.needsTypeInference(sc)) 12242 return exp; 12243 exp.ti.dsymbolSemantic(sc); 12244 if (!exp.ti.inst || exp.ti.errors) // if template failed to expand 12245 return errorExp(); 12246 12247 if (Declaration v = exp.ti.toAlias().isDeclaration()) 12248 { 12249 if (v.type && !v.type.deco) 12250 v.type = v.type.typeSemantic(v.loc, sc); 12251 return new DotVarExp(exp.loc, exp.e1, v) 12252 .expressionSemantic(sc); 12253 } 12254 return new DotExp(exp.loc, exp.e1, new ScopeExp(exp.loc, exp.ti)) 12255 .expressionSemantic(sc); 12256 } 12257 } 12258 else if (e.op == TOK.overloadSet) 12259 { 12260 OverExp oe = cast(OverExp)e; 12261 exp.ti.tempdecl = oe.vars; 12262 return new ScopeExp(exp.loc, exp.ti) 12263 .expressionSemantic(sc); 12264 } 12265 12266 Lerr: 12267 exp.error("`%s` isn't a template", e.toChars()); 12268 return errorExp(); 12269 } 12270 12271 /*************************************** 12272 * If expression is shared, check that we can access it. 12273 * Give error message if not. 12274 * 12275 * Params: 12276 * e = expression to check 12277 * sc = context 12278 * returnRef = Whether this expression is for a `return` statement 12279 * off a `ref` function, in which case a single level 12280 * of dereference is allowed (e.g. `shared(int)*`). 12281 * Returns: 12282 * true on error 12283 */ 12284 bool checkSharedAccess(Expression e, Scope* sc, bool returnRef = false) 12285 { 12286 if (!global.params.noSharedAccess || 12287 sc.intypeof || 12288 sc.flags & SCOPE.ctfe) 12289 { 12290 return false; 12291 } 12292 12293 //printf("checkSharedAccess() %s\n", e.toChars()); 12294 12295 static extern(C++) final class SharedCheckVisitor : SemanticTimeTransitiveVisitor 12296 { 12297 /// In case we don't know which expression triggered it, 12298 /// e.g. for `visit(Type)` overload 12299 Expression original; 12300 /// Where the result is stored (`true` == error) 12301 bool result; 12302 /// Whether we should allow one level of dereferencing 12303 bool allowRef; 12304 12305 /// Ctor 12306 this(Expression oe, bool allowRef_) 12307 { 12308 this.original = oe; 12309 this.allowRef = allowRef_; 12310 } 12311 12312 void sharedError(Expression e) 12313 { 12314 // https://dlang.org/phobos/core_atomic.html 12315 e.error("direct access to shared `%s` is not allowed, see `core.atomic`", e.toChars()); 12316 this.result = true; 12317 } 12318 12319 /// Introduce base class overrides 12320 alias visit = SemanticTimeTransitiveVisitor.visit; 12321 12322 // Error by default 12323 override void visit(Expression e) 12324 { 12325 if (e.type.isShared()) 12326 this.sharedError(e); 12327 } 12328 12329 /// Ditto 12330 override void visit(Type t) 12331 { 12332 // Note: This handles things like `new shared(Throwable).msg`, 12333 // where accessing `msg` would violate `shared`. 12334 if (t.isShared()) 12335 this.sharedError(this.original); 12336 } 12337 12338 // Those have no indirections / can be ignored 12339 override void visit(ErrorExp e) {} 12340 override void visit(ComplexExp e) {} 12341 override void visit(IntegerExp e) {} 12342 override void visit(NullExp e) {} 12343 12344 override void visit(VarExp e) 12345 { 12346 if (!this.allowRef && e.var.type.isShared()) 12347 this.sharedError(e); 12348 } 12349 12350 override void visit(AddrExp e) 12351 { 12352 this.allowRef = true; 12353 e.e1.accept(this); 12354 } 12355 12356 override void visit(PtrExp e) 12357 { 12358 if (!this.allowRef && e.type.isShared()) 12359 return this.sharedError(e); 12360 12361 if (e.e1.type.isShared()) 12362 return this.sharedError(e); 12363 12364 this.allowRef = false; 12365 e.e1.accept(this); 12366 } 12367 12368 override void visit(DotVarExp e) 12369 { 12370 if (!this.allowRef && e.type.isShared()) 12371 return this.sharedError(e); 12372 12373 // Allow to use `DotVarExp` within value types 12374 if (e.e1.type.ty == Tsarray || e.e1.type.ty == Tstruct) 12375 return e.e1.accept(this); 12376 12377 // If we end up with a single `VarExp`, it might be a `ref` param 12378 // `shared ref T` param == `shared(T)*`. 12379 if (auto ve = e.e1.isVarExp()) 12380 { 12381 this.allowRef = this.allowRef && (ve.var.storage_class & STC.ref_); 12382 return e.e1.accept(this); 12383 } 12384 12385 this.allowRef = false; 12386 return e.e1.accept(this); 12387 } 12388 12389 override void visit(IndexExp e) 12390 { 12391 if (!this.allowRef && e.type.isShared()) 12392 return this.sharedError(e); 12393 12394 if (e.e1.type.isShared()) 12395 return this.sharedError(e); 12396 12397 this.allowRef = false; 12398 e.e1.accept(this); 12399 } 12400 12401 override void visit(CommaExp e) 12402 { 12403 // Cannot be `return ref` since we can't use the return, 12404 // but it's better to show that error than an unrelated `shared` one 12405 this.allowRef = true; 12406 e.e2.accept(this); 12407 } 12408 } 12409 12410 scope visitor = new SharedCheckVisitor(e, returnRef); 12411 e.accept(visitor); 12412 return visitor.result; 12413 } 12414 12415 12416 12417 /**************************************************** 12418 * Determine if `exp`, which gets its address taken, can do so safely. 12419 * Params: 12420 * sc = context 12421 * exp = expression having its address taken 12422 * v = the variable getting its address taken 12423 * Returns: 12424 * `true` if ok, `false` for error 12425 */ 12426 bool checkAddressVar(Scope* sc, Expression exp, VarDeclaration v) 12427 { 12428 //printf("checkAddressVar(exp: %s, v: %s)\n", exp.toChars(), v.toChars()); 12429 if (v) 12430 { 12431 if (!v.canTakeAddressOf()) 12432 { 12433 exp.error("cannot take address of `%s`", exp.toChars()); 12434 return false; 12435 } 12436 if (sc.func && !sc.intypeof && !v.isDataseg()) 12437 { 12438 const(char)* p = v.isParameter() ? "parameter" : "local"; 12439 if (global.params.vsafe) 12440 { 12441 // Taking the address of v means it cannot be set to 'scope' later 12442 v.storage_class &= ~STC.maybescope; 12443 v.doNotInferScope = true; 12444 if (exp.type.hasPointers() && v.storage_class & STC.scope_ && 12445 !(sc.flags & SCOPE.debug_) && sc.func.setUnsafe()) 12446 { 12447 exp.error("cannot take address of `scope` %s `%s` in `@safe` function `%s`", p, v.toChars(), sc.func.toChars()); 12448 return false; 12449 } 12450 } 12451 else if (!(sc.flags & SCOPE.debug_) && 12452 sc.func.setUnsafe()) 12453 { 12454 exp.error("cannot take address of %s `%s` in `@safe` function `%s`", p, v.toChars(), sc.func.toChars()); 12455 return false; 12456 } 12457 } 12458 } 12459 return true; 12460 } 12461 12462 /******************************* 12463 * Checks the attributes of a function. 12464 * Purity (`pure`), safety (`@safe`), no GC allocations(`@nogc`) 12465 * and usage of `deprecated` and `@disabled`-ed symbols are checked. 12466 * 12467 * Params: 12468 * exp = expression to check attributes for 12469 * sc = scope of the function 12470 * f = function to be checked 12471 * Returns: `true` if error occur. 12472 */ 12473 private bool checkFunctionAttributes(Expression exp, Scope* sc, FuncDeclaration f) 12474 { 12475 with(exp) 12476 { 12477 bool error = checkDisabled(sc, f); 12478 error |= checkDeprecated(sc, f); 12479 error |= checkPurity(sc, f); 12480 error |= checkSafety(sc, f); 12481 error |= checkNogc(sc, f); 12482 return error; 12483 } 12484 } 12485 12486 /******************************* 12487 * Helper function for `getRightThis()`. 12488 * Gets `this` of the next outer aggregate. 12489 * Params: 12490 * loc = location to use for error messages 12491 * sc = context 12492 * s = the parent symbol of the existing `this` 12493 * ad = struct or class we need the correct `this` for 12494 * e1 = existing `this` 12495 * t = type of the existing `this` 12496 * var = the specific member of ad we're accessing 12497 * flag = if true, return `null` instead of throwing an error 12498 * Returns: 12499 * Expression representing the `this` for the var 12500 */ 12501 Expression getThisSkipNestedFuncs(const ref Loc loc, Scope* sc, Dsymbol s, AggregateDeclaration ad, Expression e1, Type t, Dsymbol var, bool flag = false) 12502 { 12503 int n = 0; 12504 while (s && s.isFuncDeclaration()) 12505 { 12506 FuncDeclaration f = s.isFuncDeclaration(); 12507 if (f.vthis) 12508 { 12509 n++; 12510 e1 = new VarExp(loc, f.vthis); 12511 if (f.isThis2) 12512 { 12513 // (*__this)[i] 12514 if (n > 1) 12515 e1 = e1.expressionSemantic(sc); 12516 e1 = new PtrExp(loc, e1); 12517 uint i = f.followInstantiationContext(ad); 12518 e1 = new IndexExp(loc, e1, new IntegerExp(i)); 12519 s = f.toParentP(ad); 12520 continue; 12521 } 12522 } 12523 else 12524 { 12525 if (flag) 12526 return null; 12527 e1.error("need `this` of type `%s` to access member `%s` from static function `%s`", ad.toChars(), var.toChars(), f.toChars()); 12528 e1 = ErrorExp.get(); 12529 return e1; 12530 } 12531 s = s.toParent2(); 12532 } 12533 if (n > 1 || e1.op == TOK.index) 12534 e1 = e1.expressionSemantic(sc); 12535 if (s && e1.type.equivalent(Type.tvoidptr)) 12536 { 12537 if (auto sad = s.isAggregateDeclaration()) 12538 { 12539 Type ta = sad.handleType(); 12540 if (ta.ty == Tstruct) 12541 ta = ta.pointerTo(); 12542 e1.type = ta; 12543 } 12544 } 12545 e1.type = e1.type.addMod(t.mod); 12546 return e1; 12547 } 12548 12549 /******************************* 12550 * Make a dual-context container for use as a `this` argument. 12551 * Params: 12552 * loc = location to use for error messages 12553 * sc = current scope 12554 * fd = target function that will take the `this` argument 12555 * Returns: 12556 * Temporary closure variable. 12557 * Note: 12558 * The function `fd` is added to the nested references of the 12559 * newly created variable such that a closure is made for the variable when 12560 * the address of `fd` is taken. 12561 */ 12562 VarDeclaration makeThis2Argument(const ref Loc loc, Scope* sc, FuncDeclaration fd) 12563 { 12564 Type tthis2 = Type.tvoidptr.sarrayOf(2); 12565 VarDeclaration vthis2 = new VarDeclaration(loc, tthis2, Identifier.generateId("__this"), null); 12566 vthis2.storage_class |= STC.temp; 12567 vthis2.dsymbolSemantic(sc); 12568 vthis2.parent = sc.parent; 12569 // make it a closure var 12570 assert(sc.func); 12571 sc.func.closureVars.push(vthis2); 12572 // add `fd` to the nested refs 12573 vthis2.nestedrefs.push(fd); 12574 return vthis2; 12575 } 12576 12577 /******************************* 12578 * Make sure that the runtime hook `id` exists. 12579 * Params: 12580 * loc = location to use for error messages 12581 * sc = current scope 12582 * id = the hook identifier 12583 * description = what the hook does 12584 * module_ = what module the hook is located in 12585 * Returns: 12586 * a `bool` indicating if the hook is present. 12587 */ 12588 bool verifyHookExist(const ref Loc loc, ref Scope sc, Identifier id, string description, Identifier module_ = Id.object) 12589 { 12590 auto rootSymbol = sc.search(loc, Id.empty, null); 12591 if (auto moduleSymbol = rootSymbol.search(loc, module_)) 12592 if (moduleSymbol.search(loc, id)) 12593 return true; 12594 error(loc, "`%s.%s` not found. The current runtime does not support %.*s, or the runtime is corrupt.", module_.toChars(), id.toChars(), cast(int)description.length, description.ptr); 12595 return false; 12596 }