1 /** 2 * Semantic analysis of expressions. 3 * 4 * Specification: ($LINK2 https://dlang.org/spec/expression.html, Expressions) 5 * 6 * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved 7 * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) 8 * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 9 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/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.astenums; 26 import dmd.canthrow; 27 import dmd.chkformat; 28 import dmd.ctorflow; 29 import dmd.dscope; 30 import dmd.dsymbol; 31 import dmd.declaration; 32 import dmd.dclass; 33 import dmd.dcast; 34 import dmd.delegatize; 35 import dmd.denum; 36 import dmd.dimport; 37 import dmd.dinterpret; 38 import dmd.dmangle; 39 import dmd.dmodule; 40 import dmd.dstruct; 41 import dmd.dsymbolsem; 42 import dmd.dtemplate; 43 import dmd.errors; 44 import dmd.escape; 45 import dmd.expression; 46 import dmd.file_manager; 47 import dmd.func; 48 import dmd.globals; 49 import dmd.hdrgen; 50 import dmd.id; 51 import dmd.identifier; 52 import dmd.imphint; 53 import dmd.importc; 54 import dmd.init; 55 import dmd.initsem; 56 import dmd.inline; 57 import dmd.intrange; 58 import dmd.location; 59 import dmd.mtype; 60 import dmd.mustuse; 61 import dmd.nspace; 62 import dmd.opover; 63 import dmd.optimize; 64 import dmd.parse; 65 import dmd.printast; 66 import dmd.root.array; 67 import dmd.root.ctfloat; 68 import dmd.root.filename; 69 import dmd.common.outbuffer; 70 import dmd.root.rootobject; 71 import dmd.root.string; 72 import dmd.root.utf; 73 import dmd.semantic2; 74 import dmd.semantic3; 75 import dmd.sideeffect; 76 import dmd.safe; 77 import dmd.target; 78 import dmd.tokens; 79 import dmd.traits; 80 import dmd.typesem; 81 import dmd.typinf; 82 import dmd.utils; 83 import dmd.visitor; 84 85 enum LOGSEMANTIC = false; 86 87 /******************************************************** 88 * Perform semantic analysis and CTFE on expressions to produce 89 * a string. 90 * Params: 91 * buf = append generated string to buffer 92 * sc = context 93 * exps = array of Expressions 94 * Returns: 95 * true on error 96 */ 97 bool expressionsToString(ref OutBuffer buf, Scope* sc, Expressions* exps) 98 { 99 if (!exps) 100 return false; 101 102 foreach (ex; *exps) 103 { 104 if (!ex) 105 continue; 106 auto sc2 = sc.startCTFE(); 107 sc2.tinst = null; 108 sc2.minst = null; // prevents emission of any instantiated templates to object file 109 auto e2 = ex.expressionSemantic(sc2); 110 auto e3 = resolveProperties(sc2, e2); 111 sc2.endCTFE(); 112 113 // allowed to contain types as well as expressions 114 auto e4 = ctfeInterpretForPragmaMsg(e3); 115 if (!e4 || e4.op == EXP.error) 116 return true; 117 118 // expand tuple 119 if (auto te = e4.isTupleExp()) 120 { 121 if (expressionsToString(buf, sc, te.exps)) 122 return true; 123 continue; 124 } 125 // char literals exp `.toStringExp` return `null` but we cant override it 126 // because in most contexts we don't want the conversion to succeed. 127 IntegerExp ie = e4.isIntegerExp(); 128 const ty = (ie && ie.type) ? ie.type.ty : Terror; 129 if (ty.isSomeChar) 130 { 131 auto tsa = new TypeSArray(ie.type, IntegerExp.literal!1); 132 e4 = new ArrayLiteralExp(ex.loc, tsa, ie); 133 } 134 135 if (StringExp se = e4.toStringExp()) 136 buf.writestring(se.toUTF8(sc).peekString()); 137 else 138 buf.writestring(e4.toString()); 139 } 140 return false; 141 } 142 143 144 /*********************************************************** 145 * Resolve `exp` as a compile-time known string. 146 * Params: 147 * sc = scope 148 * exp = Expression which expected as a string 149 * s = What the string is expected for, will be used in error diagnostic. 150 * Returns: 151 * String literal, or `null` if error happens. 152 */ 153 StringExp semanticString(Scope *sc, Expression exp, const char* s) 154 { 155 sc = sc.startCTFE(); 156 exp = exp.expressionSemantic(sc); 157 exp = resolveProperties(sc, exp); 158 sc = sc.endCTFE(); 159 160 if (exp.op == EXP.error) 161 return null; 162 163 auto e = exp; 164 if (exp.type.isString()) 165 { 166 e = e.ctfeInterpret(); 167 if (e.op == EXP.error) 168 return null; 169 } 170 171 auto se = e.toStringExp(); 172 if (!se) 173 { 174 exp.error("`string` expected for %s, not `(%s)` of type `%s`", 175 s, exp.toChars(), exp.type.toChars()); 176 return null; 177 } 178 return se; 179 } 180 181 private Expression extractOpDollarSideEffect(Scope* sc, UnaExp ue) 182 { 183 Expression e0; 184 Expression e1 = Expression.extractLast(ue.e1, e0); 185 // https://issues.dlang.org/show_bug.cgi?id=12585 186 // Extract the side effect part if ue.e1 is comma. 187 188 if ((sc.flags & SCOPE.ctfe) ? hasSideEffect(e1) : !isTrivialExp(e1)) // match logic in extractSideEffect() 189 { 190 /* Even if opDollar is needed, 'e1' should be evaluate only once. So 191 * Rewrite: 192 * e1.opIndex( ... use of $ ... ) 193 * e1.opSlice( ... use of $ ... ) 194 * as: 195 * (ref __dop = e1, __dop).opIndex( ... __dop.opDollar ...) 196 * (ref __dop = e1, __dop).opSlice( ... __dop.opDollar ...) 197 */ 198 e1 = extractSideEffect(sc, "__dop", e0, e1, false); 199 assert(e1.isVarExp()); 200 e1.isVarExp().var.storage_class |= STC.exptemp; // lifetime limited to expression 201 } 202 ue.e1 = e1; 203 return e0; 204 } 205 206 /************************************** 207 * Runs semantic on ae.arguments. Declares temporary variables 208 * if '$' was used. 209 */ 210 Expression resolveOpDollar(Scope* sc, ArrayExp ae, Expression* pe0) 211 { 212 assert(!ae.lengthVar); 213 *pe0 = null; 214 AggregateDeclaration ad = isAggregate(ae.e1.type); 215 Dsymbol slice = search_function(ad, Id.slice); 216 //printf("slice = %s %s\n", slice.kind(), slice.toChars()); 217 foreach (i, e; *ae.arguments) 218 { 219 if (i == 0) 220 *pe0 = extractOpDollarSideEffect(sc, ae); 221 222 if (e.op == EXP.interval && !(slice && slice.isTemplateDeclaration())) 223 { 224 Lfallback: 225 if (ae.arguments.length == 1) 226 return null; 227 ae.error("multi-dimensional slicing requires template `opSlice`"); 228 return ErrorExp.get(); 229 } 230 //printf("[%d] e = %s\n", i, e.toChars()); 231 232 // Create scope for '$' variable for this dimension 233 auto sym = new ArrayScopeSymbol(sc, ae); 234 sym.parent = sc.scopesym; 235 sc = sc.push(sym); 236 ae.lengthVar = null; // Create it only if required 237 ae.currentDimension = i; // Dimension for $, if required 238 239 e = e.expressionSemantic(sc); 240 e = resolveProperties(sc, e); 241 242 if (ae.lengthVar && sc.func) 243 { 244 // If $ was used, declare it now 245 Expression de = new DeclarationExp(ae.loc, ae.lengthVar); 246 de = de.expressionSemantic(sc); 247 *pe0 = Expression.combine(*pe0, de); 248 } 249 sc = sc.pop(); 250 251 if (auto ie = e.isIntervalExp()) 252 { 253 auto tiargs = new Objects(); 254 Expression edim = new IntegerExp(ae.loc, i, Type.tsize_t); 255 edim = edim.expressionSemantic(sc); 256 tiargs.push(edim); 257 258 auto fargs = new Expressions(2); 259 (*fargs)[0] = ie.lwr; 260 (*fargs)[1] = ie.upr; 261 262 uint xerrors = global.startGagging(); 263 sc = sc.push(); 264 FuncDeclaration fslice = resolveFuncCall(ae.loc, sc, slice, tiargs, ae.e1.type, ArgumentList(fargs), FuncResolveFlag.quiet); 265 sc = sc.pop(); 266 global.endGagging(xerrors); 267 if (!fslice) 268 goto Lfallback; 269 270 e = new DotTemplateInstanceExp(ae.loc, ae.e1, slice.ident, tiargs); 271 e = new CallExp(ae.loc, e, fargs); 272 e = e.expressionSemantic(sc); 273 } 274 275 if (!e.type) 276 { 277 ae.error("`%s` has no value", e.toChars()); 278 e = ErrorExp.get(); 279 } 280 if (e.op == EXP.error) 281 return e; 282 283 (*ae.arguments)[i] = e; 284 } 285 return ae; 286 } 287 288 /************************************** 289 * Runs semantic on se.lwr and se.upr. Declares a temporary variable 290 * if '$' was used. 291 * Returns: 292 * ae, or ErrorExp if errors occurred 293 */ 294 Expression resolveOpDollar(Scope* sc, ArrayExp ae, IntervalExp ie, Expression* pe0) 295 { 296 //assert(!ae.lengthVar); 297 if (!ie) 298 return ae; 299 300 VarDeclaration lengthVar = ae.lengthVar; 301 bool errors = false; 302 303 // create scope for '$' 304 auto sym = new ArrayScopeSymbol(sc, ae); 305 sym.parent = sc.scopesym; 306 sc = sc.push(sym); 307 308 Expression sem(Expression e) 309 { 310 e = e.expressionSemantic(sc); 311 e = resolveProperties(sc, e); 312 if (!e.type) 313 { 314 ae.error("`%s` has no value", e.toChars()); 315 errors = true; 316 } 317 return e; 318 } 319 320 ie.lwr = sem(ie.lwr); 321 ie.upr = sem(ie.upr); 322 323 if (ie.lwr.isErrorExp() || ie.upr.isErrorExp()) 324 errors = true; 325 326 if (lengthVar != ae.lengthVar && sc.func) 327 { 328 // If $ was used, declare it now 329 Expression de = new DeclarationExp(ae.loc, ae.lengthVar); 330 de = de.expressionSemantic(sc); 331 *pe0 = Expression.combine(*pe0, de); 332 } 333 334 sc = sc.pop(); 335 336 return errors ? ErrorExp.get() : ae; 337 } 338 339 /****************************** 340 * Perform semantic() on an array of Expressions. 341 */ 342 extern(D) bool arrayExpressionSemantic( 343 Expression[] exps, Scope* sc, bool preserveErrors = false) 344 { 345 bool err = false; 346 foreach (ref e; exps) 347 { 348 if (e is null) continue; 349 auto e2 = e.expressionSemantic(sc); 350 if (e2.op == EXP.error) 351 err = true; 352 if (preserveErrors || e2.op != EXP.error) 353 e = e2; 354 } 355 return err; 356 } 357 358 /* 359 Checks if `exp` contains a direct access to a `noreturn` 360 variable. If that is the case, an `assert(0)` expression 361 is generated and returned. This function should be called 362 only after semantic analysis has been performed on `exp`. 363 364 Params: 365 exp = expression that is checked 366 367 Returns: 368 An `assert(0)` expression if `exp` contains a `noreturn` 369 variable access, `exp` otherwise. 370 */ 371 372 Expression checkNoreturnVarAccess(Expression exp) 373 { 374 assert(exp.type); 375 376 Expression result = exp; 377 if (exp.type.isTypeNoreturn() && !exp.isAssertExp() && 378 !exp.isThrowExp() && !exp.isCallExp()) 379 { 380 auto msg = new StringExp(exp.loc, "Accessed expression of type `noreturn`"); 381 msg.type = Type.tstring; 382 result = new AssertExp(exp.loc, IntegerExp.literal!0, msg); 383 result.type = exp.type; 384 } 385 386 return result; 387 } 388 389 /****************************** 390 * Check the tail CallExp is really property function call. 391 * Bugs: 392 * This doesn't appear to do anything. 393 */ 394 private bool checkPropertyCall(Expression e) 395 { 396 e = lastComma(e); 397 398 if (auto ce = e.isCallExp()) 399 { 400 if (ce.f) 401 { 402 auto tf = ce.f.type.isTypeFunction(); 403 /* If a forward reference to ce.f, try to resolve it 404 */ 405 if (!tf.deco && ce.f.semanticRun < PASS.semanticdone) 406 { 407 ce.f.dsymbolSemantic(null); 408 tf = ce.f.type.isTypeFunction(); 409 } 410 } 411 else if (!ce.e1.type.isFunction_Delegate_PtrToFunction()) 412 assert(0); 413 } 414 return false; 415 } 416 417 /****************************** 418 * Find symbol in accordance with the UFCS name look up rule 419 */ 420 private Expression searchUFCS(Scope* sc, UnaExp ue, Identifier ident) 421 { 422 //printf("searchUFCS(ident = %s)\n", ident.toChars()); 423 Loc loc = ue.loc; 424 425 // TODO: merge with Scope.search.searchScopes() 426 Dsymbol searchScopes(int flags) 427 { 428 Dsymbol s = null; 429 for (Scope* scx = sc; scx; scx = scx.enclosing) 430 { 431 if (!scx.scopesym) 432 continue; 433 if (scx.scopesym.isModule()) 434 flags |= SearchUnqualifiedModule; // tell Module.search() that SearchLocalsOnly is to be obeyed 435 s = scx.scopesym.search(loc, ident, flags); 436 if (s) 437 { 438 // overload set contains only module scope symbols. 439 if (s.isOverloadSet()) 440 break; 441 // selective/renamed imports also be picked up 442 if (AliasDeclaration ad = s.isAliasDeclaration()) 443 { 444 if (ad._import) 445 break; 446 } 447 // See only module scope symbols for UFCS target. 448 Dsymbol p = s.toParent2(); 449 if (p && p.isModule()) 450 break; 451 } 452 s = null; 453 454 // Stop when we hit a module, but keep going if that is not just under the global scope 455 if (scx.scopesym.isModule() && !(scx.enclosing && !scx.enclosing.enclosing)) 456 break; 457 } 458 return s; 459 } 460 461 int flags = 0; 462 Dsymbol s; 463 464 if (sc.flags & SCOPE.ignoresymbolvisibility) 465 flags |= IgnoreSymbolVisibility; 466 467 // First look in local scopes 468 s = searchScopes(flags | SearchLocalsOnly); 469 if (!s) 470 { 471 // Second look in imported modules 472 s = searchScopes(flags | SearchImportsOnly); 473 } 474 475 if (!s) 476 return ue.e1.type.getProperty(sc, loc, ident, 0, ue.e1); 477 478 FuncDeclaration f = s.isFuncDeclaration(); 479 if (f) 480 { 481 TemplateDeclaration td = getFuncTemplateDecl(f); 482 if (td) 483 { 484 if (td.overroot) 485 td = td.overroot; 486 s = td; 487 } 488 } 489 490 if (auto dti = ue.isDotTemplateInstanceExp()) 491 { 492 auto ti = new TemplateInstance(loc, s.ident, dti.ti.tiargs); 493 if (!ti.updateTempDecl(sc, s)) 494 return ErrorExp.get(); 495 return new ScopeExp(loc, ti); 496 } 497 else 498 { 499 //printf("-searchUFCS() %s\n", s.toChars()); 500 return new DsymbolExp(loc, s); 501 } 502 } 503 504 /****************************** 505 * Pull out callable entity with UFCS. 506 */ 507 private Expression resolveUFCS(Scope* sc, CallExp ce) 508 { 509 Loc loc = ce.loc; 510 Expression eleft; 511 Expression e; 512 513 if (auto die = ce.e1.isDotIdExp()) 514 { 515 Identifier ident = die.ident; 516 517 Expression ex = die.dotIdSemanticPropX(sc); 518 if (ex != die) 519 { 520 ce.e1 = ex; 521 return null; 522 } 523 eleft = die.e1; 524 525 Type t = eleft.type.toBasetype(); 526 if (t.ty == Tarray || t.ty == Tsarray || t.ty == Tnull || (t.isTypeBasic() && t.ty != Tvoid)) 527 { 528 /* Built-in types and arrays have no callable properties, so do shortcut. 529 * It is necessary in: e.init() 530 */ 531 } 532 else if (t.ty == Taarray) 533 { 534 if (ident == Id.remove) 535 { 536 /* Transform: 537 * aa.remove(arg) into delete aa[arg] 538 */ 539 if (!ce.arguments || ce.arguments.length != 1) 540 { 541 ce.error("expected key as argument to `aa.remove()`"); 542 return ErrorExp.get(); 543 } 544 if (!eleft.type.isMutable()) 545 { 546 ce.error("cannot remove key from `%s` associative array `%s`", MODtoChars(t.mod), eleft.toChars()); 547 return ErrorExp.get(); 548 } 549 Expression key = (*ce.arguments)[0]; 550 key = key.expressionSemantic(sc); 551 key = resolveProperties(sc, key); 552 553 TypeAArray taa = t.isTypeAArray(); 554 key = key.implicitCastTo(sc, taa.index); 555 556 if (key.checkValue() || key.checkSharedAccess(sc)) 557 return ErrorExp.get(); 558 559 semanticTypeInfo(sc, taa.index); 560 561 return new RemoveExp(loc, eleft, key); 562 } 563 } 564 else 565 { 566 if (Expression ey = die.dotIdSemanticProp(sc, 1)) 567 { 568 if (ey.op == EXP.error) 569 return ey; 570 ce.e1 = ey; 571 if (isDotOpDispatch(ey)) 572 { 573 // even opDispatch and UFCS must have valid arguments, 574 // so now that we've seen indication of a problem, 575 // check them for issues. 576 Expressions* originalArguments = Expression.arraySyntaxCopy(ce.arguments); 577 578 uint errors = global.startGagging(); 579 e = ce.expressionSemantic(sc); 580 if (!global.endGagging(errors)) 581 return e; 582 583 if (arrayExpressionSemantic(originalArguments.peekSlice(), sc)) 584 return ErrorExp.get(); 585 586 /* fall down to UFCS */ 587 } 588 else 589 return null; 590 } 591 } 592 593 /* https://issues.dlang.org/show_bug.cgi?id=13953 594 * 595 * If a struct has an alias this to an associative array 596 * and remove is used on a struct instance, we have to 597 * check first if there is a remove function that can be called 598 * on the struct. If not we must check the alias this. 599 * 600 * struct A 601 * { 602 * string[string] a; 603 * alias a this; 604 * } 605 * 606 * void fun() 607 * { 608 * A s; 609 * s.remove("foo"); 610 * } 611 */ 612 const errors = global.startGagging(); 613 e = searchUFCS(sc, die, ident); 614 // if there were any errors and the identifier was remove 615 if (global.endGagging(errors)) 616 { 617 if (ident == Id.remove) 618 { 619 // check alias this 620 Expression alias_e = resolveAliasThis(sc, die.e1, 1); 621 if (alias_e && alias_e != die.e1) 622 { 623 die.e1 = alias_e; 624 CallExp ce2 = ce.syntaxCopy(); 625 ce2.e1 = die; 626 e = ce2.isCallExp().trySemantic(sc); 627 if (e) 628 return e; 629 } 630 } 631 // if alias this did not work out, print the initial errors 632 searchUFCS(sc, die, ident); 633 } 634 } 635 else if (auto dti = ce.e1.isDotTemplateInstanceExp()) 636 { 637 if (Expression ey = dti.dotTemplateSemanticProp(sc, DotExpFlag.gag)) 638 { 639 ce.e1 = ey; 640 return null; 641 } 642 eleft = dti.e1; 643 e = searchUFCS(sc, dti, dti.ti.name); 644 } 645 else 646 return null; 647 648 // Rewrite 649 ce.e1 = e; 650 if (!ce.arguments) 651 ce.arguments = new Expressions(); 652 ce.arguments.shift(eleft); 653 if (!ce.names) 654 ce.names = new Identifiers(); 655 ce.names.shift(null); 656 657 return null; 658 } 659 660 /****************************** 661 * Pull out property with UFCS. 662 */ 663 private Expression resolveUFCSProperties(Scope* sc, Expression e1, Expression e2 = null) 664 { 665 Loc loc = e1.loc; 666 Expression eleft; 667 Expression e; 668 669 if (auto die = e1.isDotIdExp()) 670 { 671 eleft = die.e1; 672 e = searchUFCS(sc, die, die.ident); 673 } 674 else if (auto dti = e1.isDotTemplateInstanceExp()) 675 { 676 eleft = dti.e1; 677 e = searchUFCS(sc, dti, dti.ti.name); 678 } 679 else 680 return null; 681 682 if (e is null) 683 return null; 684 685 // Rewrite 686 if (e2) 687 { 688 // run semantic without gagging 689 e2 = e2.expressionSemantic(sc); 690 691 /* f(e1) = e2 692 */ 693 Expression ex = e.copy(); 694 auto a1 = new Expressions(1); 695 (*a1)[0] = eleft; 696 ex = new CallExp(loc, ex, a1); 697 auto e1PassSemantic = ex.trySemantic(sc); 698 699 /* f(e1, e2) 700 */ 701 auto a2 = new Expressions(2); 702 (*a2)[0] = eleft; 703 (*a2)[1] = e2; 704 e = new CallExp(loc, e, a2); 705 e = e.trySemantic(sc); 706 if (!e1PassSemantic && !e) 707 { 708 /* https://issues.dlang.org/show_bug.cgi?id=20448 709 * 710 * If both versions have failed to pass semantic, 711 * f(e1) = e2 gets priority in error printing 712 * because f might be a templated function that 713 * failed to instantiate and we have to print 714 * the instantiation errors. 715 */ 716 return e1.expressionSemantic(sc); 717 } 718 else if (ex && !e) 719 { 720 checkPropertyCall(ex); 721 ex = new AssignExp(loc, ex, e2); 722 return ex.expressionSemantic(sc); 723 } 724 else 725 { 726 // strict setter prints errors if fails 727 e = e.expressionSemantic(sc); 728 } 729 checkPropertyCall(e); 730 return e; 731 } 732 else 733 { 734 /* f(e1) 735 */ 736 auto arguments = new Expressions(1); 737 (*arguments)[0] = eleft; 738 e = new CallExp(loc, e, arguments); 739 e = e.expressionSemantic(sc); 740 checkPropertyCall(e); 741 return e.expressionSemantic(sc); 742 } 743 } 744 745 /****************************** 746 * If e1 is a property function (template), resolve it. 747 */ 748 Expression resolvePropertiesOnly(Scope* sc, Expression e1) 749 { 750 //printf("e1 = %s %s\n", Token.toChars(e1.op), e1.toChars()); 751 752 Expression handleOverloadSet(OverloadSet os) 753 { 754 assert(os); 755 foreach (s; os.a) 756 { 757 auto fd = s.isFuncDeclaration(); 758 auto td = s.isTemplateDeclaration(); 759 if (fd) 760 { 761 if (fd.type.isTypeFunction().isproperty) 762 return resolveProperties(sc, e1); 763 } 764 else if (td && td.onemember && (fd = td.onemember.isFuncDeclaration()) !is null) 765 { 766 if (fd.type.isTypeFunction().isproperty || 767 (fd.storage_class2 & STC.property) || 768 (td._scope.stc & STC.property)) 769 return resolveProperties(sc, e1); 770 } 771 } 772 return e1; 773 } 774 775 Expression handleTemplateDecl(TemplateDeclaration td) 776 { 777 assert(td); 778 if (td.onemember) 779 { 780 if (auto fd = td.onemember.isFuncDeclaration()) 781 { 782 if (fd.type.isTypeFunction().isproperty || 783 (fd.storage_class2 & STC.property) || 784 (td._scope.stc & STC.property)) 785 return resolveProperties(sc, e1); 786 } 787 } 788 return e1; 789 } 790 791 Expression handleFuncDecl(FuncDeclaration fd) 792 { 793 assert(fd); 794 if (fd.type.isTypeFunction().isproperty) 795 return resolveProperties(sc, e1); 796 return e1; 797 } 798 799 if (auto de = e1.isDotExp()) 800 { 801 if (auto os = de.e2.isOverExp()) 802 return handleOverloadSet(os.vars); 803 } 804 else if (auto oe = e1.isOverExp()) 805 return handleOverloadSet(oe.vars); 806 else if (auto dti = e1.isDotTemplateInstanceExp()) 807 { 808 if (dti.ti.tempdecl) 809 if (auto td = dti.ti.tempdecl.isTemplateDeclaration()) 810 return handleTemplateDecl(td); 811 } 812 else if (auto dte = e1.isDotTemplateExp()) 813 return handleTemplateDecl(dte.td); 814 else if (auto se = e1.isScopeExp()) 815 { 816 Dsymbol s = se.sds; 817 TemplateInstance ti = s.isTemplateInstance(); 818 if (ti && !ti.semanticRun && ti.tempdecl) 819 if (auto td = ti.tempdecl.isTemplateDeclaration()) 820 return handleTemplateDecl(td); 821 } 822 else if (auto et = e1.isTemplateExp()) 823 return handleTemplateDecl(et.td); 824 else if (e1.isDotVarExp() && e1.type.isTypeFunction()) 825 { 826 DotVarExp dve = e1.isDotVarExp(); 827 return handleFuncDecl(dve.var.isFuncDeclaration()); 828 } 829 else if (e1.isVarExp() && e1.type && e1.type.isTypeFunction() && (sc.intypeof || !e1.isVarExp().var.needThis())) 830 return handleFuncDecl(e1.isVarExp().var.isFuncDeclaration()); 831 return e1; 832 } 833 834 /**************************************** 835 * Turn symbol `s` into the expression it represents. 836 * 837 * Params: 838 * s = symbol to resolve 839 * loc = location of use of `s` 840 * sc = context 841 * hasOverloads = applies if `s` represents a function. 842 * true means it's overloaded and will be resolved later, 843 * false means it's the exact function symbol. 844 * Returns: 845 * `s` turned into an expression, `ErrorExp` if an error occurred 846 */ 847 Expression symbolToExp(Dsymbol s, const ref Loc loc, Scope *sc, bool hasOverloads) 848 { 849 static if (LOGSEMANTIC) 850 { 851 printf("DsymbolExp::resolve(%s %s)\n", s.kind(), s.toChars()); 852 } 853 854 Lagain: 855 Expression e; 856 857 //printf("DsymbolExp:: %p '%s' is a symbol\n", this, toChars()); 858 //printf("s = '%s', s.kind = '%s'\n", s.toChars(), s.kind()); 859 Dsymbol olds = s; 860 Declaration d = s.isDeclaration(); 861 if (d && (d.storage_class & STC.templateparameter)) 862 { 863 s = s.toAlias(); 864 } 865 else 866 { 867 // functions are checked after overloading 868 // templates are checked after matching constraints 869 if (!s.isFuncDeclaration() && !s.isTemplateDeclaration()) 870 { 871 s.checkDeprecated(loc, sc); 872 if (d) 873 d.checkDisabled(loc, sc); 874 } 875 876 // https://issues.dlang.org/show_bug.cgi?id=12023 877 // if 's' is a tuple variable, the tuple is returned. 878 s = s.toAlias(); 879 880 //printf("s = '%s', s.kind = '%s', s.needThis() = %p\n", s.toChars(), s.kind(), s.needThis()); 881 if (s != olds && !s.isFuncDeclaration() && !s.isTemplateDeclaration()) 882 { 883 s.checkDeprecated(loc, sc); 884 if (d) 885 d.checkDisabled(loc, sc); 886 } 887 888 if (auto sd = s.isDeclaration()) 889 { 890 if (sd.isSystem()) 891 { 892 if (sc.setUnsafePreview(global.params.systemVariables, false, loc, 893 "cannot access `@system` variable `%s` in @safe code", sd)) 894 { 895 return ErrorExp.get(); 896 } 897 } 898 } 899 } 900 901 if (auto em = s.isEnumMember()) 902 { 903 return em.getVarExp(loc, sc); 904 } 905 if (auto v = s.isVarDeclaration()) 906 { 907 //printf("Identifier '%s' is a variable, type '%s'\n", s.toChars(), v.type.toChars()); 908 if (sc.intypeof == 1 && !v.inuse) 909 v.dsymbolSemantic(sc); 910 if (!v.type || // during variable type inference 911 !v.type.deco && v.inuse) // during variable type semantic 912 { 913 if (v.inuse) // variable type depends on the variable itself 914 error(loc, "circular reference to %s `%s`", v.kind(), v.toPrettyChars()); 915 else // variable type cannot be determined 916 error(loc, "forward reference to %s `%s`", v.kind(), v.toPrettyChars()); 917 return ErrorExp.get(); 918 } 919 if (v.type.ty == Terror) 920 return ErrorExp.get(); 921 922 if ((v.storage_class & STC.manifest) && v._init) 923 { 924 if (v.inuse) 925 { 926 error(loc, "circular initialization of %s `%s`", v.kind(), v.toPrettyChars()); 927 return ErrorExp.get(); 928 } 929 e = v.expandInitializer(loc); 930 v.inuse++; 931 e = e.expressionSemantic(sc); 932 v.inuse--; 933 return e; 934 } 935 936 // We need to run semantics to correctly set 'STC.field' if it is a member variable 937 // that could be forward referenced. This is needed for 'v.needThis()' to work 938 if (v.isThis()) 939 v.dsymbolSemantic(sc); 940 941 // Change the ancestor lambdas to delegate before hasThis(sc) call. 942 if (v.checkNestedReference(sc, loc)) 943 return ErrorExp.get(); 944 945 if (v.needThis() && hasThis(sc)) 946 e = new DotVarExp(loc, new ThisExp(loc), v); 947 else 948 e = new VarExp(loc, v); 949 e = e.expressionSemantic(sc); 950 return e; 951 } 952 if (auto fld = s.isFuncLiteralDeclaration()) 953 { 954 //printf("'%s' is a function literal\n", fld.toChars()); 955 e = new FuncExp(loc, fld); 956 return e.expressionSemantic(sc); 957 } 958 if (auto f = s.isFuncDeclaration()) 959 { 960 f = f.toAliasFunc(); 961 if (!f.functionSemantic()) 962 return ErrorExp.get(); 963 964 if (!hasOverloads && f.checkForwardRef(loc)) 965 return ErrorExp.get(); 966 967 auto fd = s.isFuncDeclaration(); 968 fd.type = f.type; 969 return new VarExp(loc, fd, hasOverloads); 970 } 971 if (OverDeclaration od = s.isOverDeclaration()) 972 { 973 e = new VarExp(loc, od, true); 974 e.type = Type.tvoid; 975 return e; 976 } 977 if (OverloadSet o = s.isOverloadSet()) 978 { 979 //printf("'%s' is an overload set\n", o.toChars()); 980 return new OverExp(loc, o); 981 } 982 983 if (Import imp = s.isImport()) 984 { 985 if (!imp.pkg) 986 { 987 .error(loc, "forward reference of import `%s`", imp.toChars()); 988 return ErrorExp.get(); 989 } 990 auto ie = new ScopeExp(loc, imp.pkg); 991 return ie.expressionSemantic(sc); 992 } 993 if (Package pkg = s.isPackage()) 994 { 995 auto ie = new ScopeExp(loc, pkg); 996 return ie.expressionSemantic(sc); 997 } 998 if (Module mod = s.isModule()) 999 { 1000 auto ie = new ScopeExp(loc, mod); 1001 return ie.expressionSemantic(sc); 1002 } 1003 if (Nspace ns = s.isNspace()) 1004 { 1005 auto ie = new ScopeExp(loc, ns); 1006 return ie.expressionSemantic(sc); 1007 } 1008 1009 if (Type t = s.getType()) 1010 { 1011 return (new TypeExp(loc, t)).expressionSemantic(sc); 1012 } 1013 1014 if (TupleDeclaration tup = s.isTupleDeclaration()) 1015 { 1016 if (tup.needThis() && hasThis(sc)) 1017 e = new DotVarExp(loc, new ThisExp(loc), tup); 1018 else 1019 e = new TupleExp(loc, tup); 1020 e = e.expressionSemantic(sc); 1021 return e; 1022 } 1023 1024 if (TemplateInstance ti = s.isTemplateInstance()) 1025 { 1026 ti.dsymbolSemantic(sc); 1027 if (!ti.inst || ti.errors) 1028 return ErrorExp.get(); 1029 s = ti.toAlias(); 1030 if (!s.isTemplateInstance()) 1031 goto Lagain; 1032 e = new ScopeExp(loc, ti); 1033 e = e.expressionSemantic(sc); 1034 return e; 1035 } 1036 if (TemplateDeclaration td = s.isTemplateDeclaration()) 1037 { 1038 Dsymbol p = td.toParentLocal(); 1039 FuncDeclaration fdthis = hasThis(sc); 1040 AggregateDeclaration ad = p ? p.isAggregateDeclaration() : null; 1041 if (fdthis && ad && fdthis.isMemberLocal() == ad && (td._scope.stc & STC.static_) == 0) 1042 { 1043 e = new DotTemplateExp(loc, new ThisExp(loc), td); 1044 } 1045 else 1046 e = new TemplateExp(loc, td); 1047 e = e.expressionSemantic(sc); 1048 return e; 1049 } 1050 1051 .error(loc, "%s `%s` is not a variable", s.kind(), s.toChars()); 1052 return ErrorExp.get(); 1053 } 1054 1055 /************************************************************* 1056 * Given var, get the 1057 * right `this` pointer if var is in an outer class, but our 1058 * existing `this` pointer is in an inner class. 1059 * Params: 1060 * loc = location to use for error messages 1061 * sc = context 1062 * ad = struct or class we need the correct `this` for 1063 * e1 = existing `this` 1064 * var = the specific member of ad we're accessing 1065 * flag = if true, return `null` instead of throwing an error 1066 * Returns: 1067 * Expression representing the `this` for the var 1068 */ 1069 private Expression getRightThis(const ref Loc loc, Scope* sc, AggregateDeclaration ad, Expression e1, Dsymbol var, int flag = 0) 1070 { 1071 //printf("\ngetRightThis(e1 = %s, ad = %s, var = %s)\n", e1.toChars(), ad.toChars(), var.toChars()); 1072 L1: 1073 Type t = e1.type.toBasetype(); 1074 //printf("e1.type = %s, var.type = %s\n", e1.type.toChars(), var.type.toChars()); 1075 1076 if (e1.op == EXP.objcClassReference) 1077 { 1078 // We already have an Objective-C class reference, just use that as 'this'. 1079 return e1; 1080 } 1081 else if (ad && ad.isClassDeclaration && ad.isClassDeclaration.classKind == ClassKind.objc && 1082 var.isFuncDeclaration && var.isFuncDeclaration.isStatic && 1083 var.isFuncDeclaration.objc.selector) 1084 { 1085 return new ObjcClassReferenceExp(e1.loc, ad.isClassDeclaration()); 1086 } 1087 1088 /* Access of a member which is a template parameter in dual-scope scenario 1089 * class A { inc(alias m)() { ++m; } } // `m` needs `this` of `B` 1090 * class B {int m; inc() { new A().inc!m(); } } 1091 */ 1092 if (e1.op == EXP.this_) 1093 { 1094 FuncDeclaration f = hasThis(sc); 1095 if (f && f.hasDualContext()) 1096 { 1097 if (f.followInstantiationContext(ad)) 1098 { 1099 e1 = new VarExp(loc, f.vthis); 1100 e1 = new PtrExp(loc, e1); 1101 e1 = new IndexExp(loc, e1, IntegerExp.literal!1); 1102 e1 = getThisSkipNestedFuncs(loc, sc, f.toParent2(), ad, e1, t, var); 1103 if (e1.op == EXP.error) 1104 return e1; 1105 goto L1; 1106 } 1107 } 1108 } 1109 1110 /* If e1 is not the 'this' pointer for ad 1111 */ 1112 if (ad && 1113 !(t.isTypePointer() && t.nextOf().isTypeStruct() && t.nextOf().isTypeStruct().sym == ad) && 1114 !(t.isTypeStruct() && t.isTypeStruct().sym == ad)) 1115 { 1116 ClassDeclaration cd = ad.isClassDeclaration(); 1117 ClassDeclaration tcd = t.isClassHandle(); 1118 1119 /* e1 is the right this if ad is a base class of e1 1120 */ 1121 if (!cd || !tcd || !(tcd == cd || cd.isBaseOf(tcd, null))) 1122 { 1123 /* Only classes can be inner classes with an 'outer' 1124 * member pointing to the enclosing class instance 1125 */ 1126 if (tcd && tcd.isNested()) 1127 { 1128 /* e1 is the 'this' pointer for an inner class: tcd. 1129 * Rewrite it as the 'this' pointer for the outer class. 1130 */ 1131 auto vthis = tcd.followInstantiationContext(ad) ? tcd.vthis2 : tcd.vthis; 1132 e1 = new DotVarExp(loc, e1, vthis); 1133 e1.type = vthis.type; 1134 e1.type = e1.type.addMod(t.mod); 1135 // Do not call ensureStaticLinkTo() 1136 //e1 = e1.semantic(sc); 1137 1138 // Skip up over nested functions, and get the enclosing 1139 // class type. 1140 e1 = getThisSkipNestedFuncs(loc, sc, tcd.toParentP(ad), ad, e1, t, var); 1141 if (e1.op == EXP.error) 1142 return e1; 1143 goto L1; 1144 } 1145 1146 /* Can't find a path from e1 to ad 1147 */ 1148 if (flag) 1149 return null; 1150 e1.error("`this` for `%s` needs to be type `%s` not type `%s`", var.toChars(), ad.toChars(), t.toChars()); 1151 return ErrorExp.get(); 1152 } 1153 } 1154 return e1; 1155 } 1156 1157 /* 1158 * Check whether `outerFunc` and `calledFunc` have the same `this`. 1159 * If `calledFunc` is the member of a base class of the class that contains 1160 * `outerFunc` we consider that they have the same this. 1161 * 1162 * This function is used to test whether `this` needs to be prepended to 1163 * a function call or function symbol. For example: 1164 * 1165 * struct X 1166 * { 1167 * void gun() {} 1168 * } 1169 * struct A 1170 * { 1171 * void fun() {} 1172 * void sun() 1173 * { 1174 * fun(); 1175 * X.gun(); // error 1176 * } 1177 * } 1178 * 1179 * When `fun` is called, `outerfunc` = `sun` and `calledFunc = `fun`. 1180 * `sun` is a member of `A` and `fun` is also a member of `A`, therefore 1181 * `this` can be prepended to `fun`. When `gun` is called (it will result 1182 * in an error, but that is not relevant here), which is a member of `X`, 1183 * no `this` is needed because the outer function does not have the same 1184 * `this` as `gun`. 1185 * 1186 * Returns: 1187 * `true` if outerFunc and calledFunc may use the same `this` pointer. 1188 * `false` otherwise. 1189 */ 1190 private bool haveSameThis(FuncDeclaration outerFunc, FuncDeclaration calledFunc) 1191 { 1192 auto thisAd = outerFunc.isMemberLocal(); 1193 if (!thisAd) 1194 return false; 1195 1196 auto requiredAd = calledFunc.isMemberLocal(); 1197 if (!requiredAd) 1198 return false; 1199 1200 if (thisAd == requiredAd) 1201 return true; 1202 1203 // outerfunc is the member of a base class that contains calledFunc, 1204 // then we consider that they have the same this. 1205 auto cd = requiredAd.isClassDeclaration(); 1206 if (!cd) 1207 return false; 1208 1209 if (cd.isBaseOf2(thisAd.isClassDeclaration())) 1210 return true; 1211 1212 // if outerfunc is the member of a nested aggregate, then let 1213 // getRightThis take care of this. 1214 if (thisAd.isNested()) 1215 return true; 1216 1217 return false; 1218 } 1219 1220 /*************************************** 1221 * Pull out any properties. 1222 */ 1223 private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 = null, BinExp saveAtts = null) 1224 { 1225 //printf("resolvePropertiesX, e1 = %s %s, e2 = %s\n", EXPtoString(e1.op).ptr, e1.toChars(), e2 ? e2.toChars() : null); 1226 Loc loc = e1.loc; 1227 1228 OverloadSet os; 1229 Dsymbol s; 1230 Objects* tiargs; 1231 Type tthis; 1232 if (auto de = e1.isDotExp()) 1233 { 1234 if (auto oe = de.e2.isOverExp()) 1235 { 1236 tiargs = null; 1237 tthis = de.e1.type; 1238 os = oe.vars; 1239 goto Los; 1240 } 1241 } 1242 else if (e1.isOverExp()) 1243 { 1244 tiargs = null; 1245 tthis = null; 1246 os = e1.isOverExp().vars; 1247 Los: 1248 assert(os); 1249 FuncDeclaration fd = null; 1250 if (e2) 1251 { 1252 e2 = e2.expressionSemantic(sc); 1253 if (e2.op == EXP.error) 1254 return ErrorExp.get(); 1255 e2 = resolveProperties(sc, e2); 1256 1257 Expressions a; 1258 a.push(e2); 1259 1260 for (size_t i = 0; i < os.a.length; i++) 1261 { 1262 if (FuncDeclaration f = resolveFuncCall(loc, sc, os.a[i], tiargs, tthis, ArgumentList(&a), FuncResolveFlag.quiet)) 1263 { 1264 if (f.errors) 1265 return ErrorExp.get(); 1266 fd = f; 1267 assert(fd.type.ty == Tfunction); 1268 } 1269 } 1270 if (fd) 1271 { 1272 Expression e = new CallExp(loc, e1, e2); 1273 return e.expressionSemantic(sc); 1274 } 1275 } 1276 { 1277 for (size_t i = 0; i < os.a.length; i++) 1278 { 1279 if (FuncDeclaration f = resolveFuncCall(loc, sc, os.a[i], tiargs, tthis, ArgumentList(), FuncResolveFlag.quiet)) 1280 { 1281 if (f.errors) 1282 return ErrorExp.get(); 1283 fd = f; 1284 assert(fd.type.ty == Tfunction); 1285 auto tf = fd.type.isTypeFunction(); 1286 if (!tf.isref && e2) 1287 { 1288 error(loc, "%s is not an lvalue", e1.toChars()); 1289 return ErrorExp.get(); 1290 } 1291 } 1292 } 1293 if (fd) 1294 { 1295 Expression e = new CallExp(loc, e1); 1296 if (e2) 1297 { 1298 e = new AssignExp(loc, e, e2); 1299 if (saveAtts) 1300 { 1301 (cast(BinExp)e).att1 = saveAtts.att1; 1302 (cast(BinExp)e).att2 = saveAtts.att2; 1303 } 1304 } 1305 return e.expressionSemantic(sc); 1306 } 1307 } 1308 if (e2) 1309 goto Leprop; 1310 } 1311 else if (auto dti = e1.isDotTemplateInstanceExp()) 1312 { 1313 if (!dti.findTempDecl(sc)) 1314 goto Leprop; 1315 if (!dti.ti.semanticTiargs(sc)) 1316 goto Leprop; 1317 tiargs = dti.ti.tiargs; 1318 tthis = dti.e1.type; 1319 if ((os = dti.ti.tempdecl.isOverloadSet()) !is null) 1320 goto Los; 1321 if ((s = dti.ti.tempdecl) !is null) 1322 goto Lfd; 1323 } 1324 else if (auto dte = e1.isDotTemplateExp()) 1325 { 1326 s = dte.td; 1327 tiargs = null; 1328 tthis = dte.e1.type; 1329 goto Lfd; 1330 } 1331 else if (auto se = e1.isScopeExp()) 1332 { 1333 s = se.sds; 1334 TemplateInstance ti = s.isTemplateInstance(); 1335 if (ti && !ti.semanticRun && ti.tempdecl) 1336 { 1337 //assert(ti.needsTypeInference(sc)); 1338 if (!ti.semanticTiargs(sc)) 1339 goto Leprop; 1340 tiargs = ti.tiargs; 1341 tthis = null; 1342 if ((os = ti.tempdecl.isOverloadSet()) !is null) 1343 goto Los; 1344 if ((s = ti.tempdecl) !is null) 1345 goto Lfd; 1346 } 1347 } 1348 else if (auto te = e1.isTemplateExp()) 1349 { 1350 s = te.td; 1351 tiargs = null; 1352 tthis = null; 1353 goto Lfd; 1354 } 1355 else if (e1.isDotVarExp() && e1.type && (e1.type.toBasetype().isTypeFunction() || e1.isDotVarExp().var.isOverDeclaration())) 1356 { 1357 DotVarExp dve = e1.isDotVarExp(); 1358 s = dve.var; 1359 tiargs = null; 1360 tthis = dve.e1.type; 1361 goto Lfd; 1362 } 1363 else if (sc && sc.flags & SCOPE.Cfile && e1.isVarExp() && !e2) 1364 { 1365 // ImportC: do not implicitly call function if no ( ) are present 1366 } 1367 else if (e1.isVarExp() && e1.type && (e1.type.toBasetype().isTypeFunction() || e1.isVarExp().var.isOverDeclaration())) 1368 { 1369 s = e1.isVarExp().var; 1370 tiargs = null; 1371 tthis = null; 1372 Lfd: 1373 assert(s); 1374 if (e2) 1375 { 1376 e2 = e2.expressionSemantic(sc); 1377 if (e2.op == EXP.error) 1378 return ErrorExp.get(); 1379 e2 = resolveProperties(sc, e2); 1380 1381 Expressions a; 1382 a.push(e2); 1383 1384 FuncDeclaration fd = resolveFuncCall(loc, sc, s, tiargs, tthis, ArgumentList(&a), FuncResolveFlag.quiet); 1385 if (fd && fd.type) 1386 { 1387 if (fd.errors) 1388 return ErrorExp.get(); 1389 if (!checkSymbolAccess(sc, fd)) 1390 { 1391 // @@@DEPRECATED_2.105@@@ 1392 // When turning into error, uncomment the return statement 1393 TypeFunction tf = fd.type.isTypeFunction(); 1394 deprecation(loc, "function `%s` of type `%s` is not accessible from module `%s`", 1395 fd.toPrettyChars(), tf.toChars, sc._module.toChars); 1396 //return ErrorExp.get(); 1397 } 1398 assert(fd.type.ty == Tfunction); 1399 Expression e = new CallExp(loc, e1, e2); 1400 return e.expressionSemantic(sc); 1401 } 1402 } 1403 { 1404 FuncDeclaration fd = resolveFuncCall(loc, sc, s, tiargs, tthis, ArgumentList(), FuncResolveFlag.quiet); 1405 if (fd && fd.type) 1406 { 1407 if (fd.errors) 1408 return ErrorExp.get(); 1409 TypeFunction tf = fd.type.isTypeFunction(); 1410 if (!e2 || tf.isref) 1411 { 1412 if (!checkSymbolAccess(sc, fd)) 1413 { 1414 // @@@DEPRECATED_2.105@@@ 1415 // When turning into error, uncomment the return statement 1416 deprecation(loc, "function `%s` of type `%s` is not accessible from module `%s`", 1417 fd.toPrettyChars(), tf.toChars, sc._module.toChars); 1418 //return ErrorExp.get(); 1419 } 1420 Expression e = new CallExp(loc, e1); 1421 if (e2) 1422 { 1423 e = new AssignExp(loc, e, e2); 1424 if (saveAtts) 1425 { 1426 (cast(BinExp)e).att1 = saveAtts.att1; 1427 (cast(BinExp)e).att2 = saveAtts.att2; 1428 } 1429 } 1430 return e.expressionSemantic(sc); 1431 } 1432 } 1433 } 1434 if (FuncDeclaration fd = s.isFuncDeclaration()) 1435 { 1436 // Keep better diagnostic message for invalid property usage of functions 1437 assert(fd.type.ty == Tfunction); 1438 Expression e = new CallExp(loc, e1, e2); 1439 return e.expressionSemantic(sc); 1440 } 1441 if (e2) 1442 goto Leprop; 1443 } 1444 if (auto ve = e1.isVarExp()) 1445 { 1446 if (auto v = ve.var.isVarDeclaration()) 1447 { 1448 if (ve.checkPurity(sc, v)) 1449 return ErrorExp.get(); 1450 } 1451 } 1452 if (e2) 1453 return null; 1454 1455 if (e1.type && !e1.isTypeExp()) // function type is not a property 1456 { 1457 /* Look for e1 being a lazy parameter; rewrite as delegate call 1458 * only if the symbol wasn't already treated as a delegate 1459 */ 1460 auto ve = e1.isVarExp(); 1461 if (ve && ve.var.storage_class & STC.lazy_ && !ve.delegateWasExtracted) 1462 { 1463 Expression e = new CallExp(loc, e1); 1464 return e.expressionSemantic(sc); 1465 } 1466 else if (e1.isDotVarExp()) 1467 { 1468 // Check for reading overlapped pointer field in @safe code. 1469 if (checkUnsafeAccess(sc, e1, true, true)) 1470 return ErrorExp.get(); 1471 } 1472 else if (auto ce = e1.isCallExp()) 1473 { 1474 // Check for reading overlapped pointer field in @safe code. 1475 if (checkUnsafeAccess(sc, ce.e1, true, true)) 1476 return ErrorExp.get(); 1477 } 1478 } 1479 1480 if (!e1.type) 1481 { 1482 error(loc, "cannot resolve type for %s", e1.toChars()); 1483 e1 = ErrorExp.get(); 1484 } 1485 return e1; 1486 1487 Leprop: 1488 error(loc, "not a property %s", e1.toChars()); 1489 return ErrorExp.get(); 1490 } 1491 1492 extern (C++) Expression resolveProperties(Scope* sc, Expression e) 1493 { 1494 //printf("resolveProperties(%s)\n", e.toChars()); 1495 e = resolvePropertiesX(sc, e); 1496 if (e.checkRightThis(sc)) 1497 return ErrorExp.get(); 1498 return e; 1499 } 1500 1501 /**************************************** 1502 * The common type is determined by applying ?: to each pair. 1503 * Output: 1504 * exps[] properties resolved, implicitly cast to common type, rewritten in place 1505 * Returns: 1506 * The common type, or `null` if an error has occured 1507 */ 1508 private Type arrayExpressionToCommonType(Scope* sc, ref Expressions exps) 1509 { 1510 /* Still have a problem with: 1511 * ubyte[][] = [ cast(ubyte[])"hello", [1]]; 1512 * which works if the array literal is initialized top down with the ubyte[][] 1513 * type, but fails with this function doing bottom up typing. 1514 */ 1515 1516 //printf("arrayExpressionToCommonType()\n"); 1517 scope IntegerExp integerexp = IntegerExp.literal!0; 1518 scope CondExp condexp = new CondExp(Loc.initial, integerexp, null, null); 1519 1520 Type t0 = null; 1521 Expression e0 = null; 1522 bool foundType; 1523 1524 for (size_t i = 0; i < exps.length; i++) 1525 { 1526 Expression e = exps[i]; 1527 if (!e) 1528 continue; 1529 1530 e = resolveProperties(sc, e); 1531 if (!e.type) 1532 { 1533 e.error("`%s` has no value", e.toChars()); 1534 t0 = Type.terror; 1535 continue; 1536 } 1537 if (e.op == EXP.type) 1538 { 1539 foundType = true; // do not break immediately, there might be more errors 1540 e.checkValue(); // report an error "type T has no value" 1541 t0 = Type.terror; 1542 continue; 1543 } 1544 if (e.type.ty == Tvoid) 1545 { 1546 // void expressions do not concur to the determination of the common 1547 // type. 1548 continue; 1549 } 1550 if (checkNonAssignmentArrayOp(e)) 1551 { 1552 t0 = Type.terror; 1553 continue; 1554 } 1555 1556 e = doCopyOrMove(sc, e); 1557 1558 if (!foundType && t0 && !t0.equals(e.type)) 1559 { 1560 /* This applies ?: to merge the types. It's backwards; 1561 * ?: should call this function to merge types. 1562 */ 1563 condexp.type = null; 1564 condexp.e1 = e0; 1565 condexp.e2 = e; 1566 condexp.loc = e.loc; 1567 Expression ex = condexp.expressionSemantic(sc); 1568 if (ex.op == EXP.error) 1569 e = ex; 1570 else 1571 { 1572 // Convert to common type 1573 exps[i] = condexp.e1.castTo(sc, condexp.type); 1574 e = condexp.e2.castTo(sc, condexp.type); 1575 } 1576 } 1577 e0 = e; 1578 t0 = e.type; 1579 if (e.op != EXP.error) 1580 exps[i] = e; 1581 } 1582 1583 // [] is typed as void[] 1584 if (!t0) 1585 return Type.tvoid; 1586 1587 // It's an error, don't do the cast 1588 if (t0.ty == Terror) 1589 return null; 1590 1591 for (size_t i = 0; i < exps.length; i++) 1592 { 1593 Expression e = exps[i]; 1594 if (!e) 1595 continue; 1596 1597 e = e.implicitCastTo(sc, t0); 1598 if (e.op == EXP.error) 1599 { 1600 /* https://issues.dlang.org/show_bug.cgi?id=13024 1601 * a workaround for the bug in typeMerge - 1602 * it should paint e1 and e2 by deduced common type, 1603 * but doesn't in this particular case. 1604 */ 1605 return null; 1606 } 1607 exps[i] = e; 1608 } 1609 return t0; 1610 } 1611 1612 private Expression opAssignToOp(const ref Loc loc, EXP op, Expression e1, Expression e2) 1613 { 1614 Expression e; 1615 switch (op) 1616 { 1617 case EXP.addAssign: 1618 e = new AddExp(loc, e1, e2); 1619 break; 1620 1621 case EXP.minAssign: 1622 e = new MinExp(loc, e1, e2); 1623 break; 1624 1625 case EXP.mulAssign: 1626 e = new MulExp(loc, e1, e2); 1627 break; 1628 1629 case EXP.divAssign: 1630 e = new DivExp(loc, e1, e2); 1631 break; 1632 1633 case EXP.modAssign: 1634 e = new ModExp(loc, e1, e2); 1635 break; 1636 1637 case EXP.andAssign: 1638 e = new AndExp(loc, e1, e2); 1639 break; 1640 1641 case EXP.orAssign: 1642 e = new OrExp(loc, e1, e2); 1643 break; 1644 1645 case EXP.xorAssign: 1646 e = new XorExp(loc, e1, e2); 1647 break; 1648 1649 case EXP.leftShiftAssign: 1650 e = new ShlExp(loc, e1, e2); 1651 break; 1652 1653 case EXP.rightShiftAssign: 1654 e = new ShrExp(loc, e1, e2); 1655 break; 1656 1657 case EXP.unsignedRightShiftAssign: 1658 e = new UshrExp(loc, e1, e2); 1659 break; 1660 1661 default: 1662 assert(0); 1663 } 1664 return e; 1665 } 1666 1667 /********************* 1668 * Rewrite: 1669 * array.length op= e2 1670 */ 1671 private Expression rewriteOpAssign(BinExp exp) 1672 { 1673 ArrayLengthExp ale = exp.e1.isArrayLengthExp(); 1674 if (ale.e1.isVarExp()) 1675 { 1676 // array.length = array.length op e2 1677 Expression e = opAssignToOp(exp.loc, exp.op, ale, exp.e2); 1678 e = new AssignExp(exp.loc, ale.syntaxCopy(), e); 1679 return e; 1680 } 1681 else 1682 { 1683 // (ref tmp = array;), tmp.length = tmp.length op e2 1684 auto tmp = copyToTemp(STC.ref_, "__arraylength", ale.e1); 1685 Expression e1 = new ArrayLengthExp(ale.loc, new VarExp(ale.loc, tmp)); 1686 Expression elvalue = e1.syntaxCopy(); 1687 Expression e = opAssignToOp(exp.loc, exp.op, e1, exp.e2); 1688 e = new AssignExp(exp.loc, elvalue, e); 1689 e = new CommaExp(exp.loc, new DeclarationExp(ale.loc, tmp), e); 1690 return e; 1691 } 1692 } 1693 1694 /**************************************** 1695 * Preprocess arguments to function. 1696 * 1697 * Tuples in argumentList get expanded, properties resolved, rewritten in place 1698 * 1699 * Params: 1700 * sc = scope 1701 * argumentList = arguments to function 1702 * reportErrors = whether or not to report errors here. Some callers are not 1703 * checking actual function params, so they'll do their own error reporting 1704 * Returns: 1705 * `true` when a semantic error occurred 1706 */ 1707 private bool preFunctionParameters(Scope* sc, ArgumentList argumentList, const bool reportErrors = true) 1708 { 1709 Expressions* exps = argumentList.arguments; 1710 bool err = false; 1711 if (exps) 1712 { 1713 expandTuples(exps, argumentList.names); 1714 1715 for (size_t i = 0; i < exps.length; i++) 1716 { 1717 Expression arg = (*exps)[i]; 1718 arg = resolveProperties(sc, arg); 1719 arg = arg.arrayFuncConv(sc); 1720 if (arg.op == EXP.type) 1721 { 1722 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684 1723 arg = resolveAliasThis(sc, arg); 1724 1725 if (arg.op == EXP.type) 1726 { 1727 if (reportErrors) 1728 { 1729 arg.error("cannot pass type `%s` as a function argument", arg.toChars()); 1730 arg = ErrorExp.get(); 1731 } 1732 err = true; 1733 } 1734 } 1735 else if (arg.type.toBasetype().ty == Tfunction) 1736 { 1737 if (reportErrors) 1738 { 1739 arg.error("cannot pass function `%s` as a function argument", arg.toChars()); 1740 arg = ErrorExp.get(); 1741 } 1742 err = true; 1743 } 1744 else if (checkNonAssignmentArrayOp(arg)) 1745 { 1746 arg = ErrorExp.get(); 1747 err = true; 1748 } 1749 (*exps)[i] = arg; 1750 } 1751 } 1752 return err; 1753 } 1754 1755 /******************************************** 1756 * Issue an error if default construction is disabled for type t. 1757 * Default construction is required for arrays and 'out' parameters. 1758 * Returns: 1759 * true an error was issued 1760 */ 1761 private bool checkDefCtor(Loc loc, Type t) 1762 { 1763 if (auto ts = t.baseElemOf().isTypeStruct()) 1764 { 1765 StructDeclaration sd = ts.sym; 1766 if (sd.noDefaultCtor) 1767 { 1768 sd.error(loc, "default construction is disabled"); 1769 return true; 1770 } 1771 } 1772 return false; 1773 } 1774 1775 /**************************************** 1776 * Now that we know the exact type of the function we're calling, 1777 * the arguments[] need to be adjusted: 1778 * 1. implicitly convert argument to the corresponding parameter type 1779 * 2. add default arguments for any missing arguments 1780 * 3. do default promotions on arguments corresponding to ... 1781 * 4. add hidden _arguments[] argument 1782 * 5. call copy constructor for struct value arguments 1783 * Params: 1784 * loc = location of function call 1785 * sc = context 1786 * tf = type of the function 1787 * ethis = `this` argument, `null` if none or not known 1788 * tthis = type of `this` argument, `null` if no `this` argument 1789 * argumentsList = array of actual arguments to function call 1790 * fd = the function being called, `null` if called indirectly 1791 * prettype = set to return type of function 1792 * peprefix = set to expression to execute before `arguments[]` are evaluated, `null` if none 1793 * Returns: 1794 * true errors happened 1795 */ 1796 private bool functionParameters(const ref Loc loc, Scope* sc, 1797 TypeFunction tf, Expression ethis, Type tthis, ArgumentList argumentList, FuncDeclaration fd, 1798 Type* prettype, Expression* peprefix) 1799 { 1800 Expressions* arguments = argumentList.arguments; 1801 //printf("functionParameters() %s\n", fd ? fd.toChars() : ""); 1802 assert(arguments); 1803 assert(fd || tf.next); 1804 const size_t nparams = tf.parameterList.length; 1805 const olderrors = global.errors; 1806 bool err = false; 1807 Expression eprefix = null; 1808 *peprefix = null; 1809 1810 if (argumentList.names) 1811 { 1812 const(char)* msg = null; 1813 auto resolvedArgs = tf.resolveNamedArgs(argumentList, &msg); 1814 if (!resolvedArgs) 1815 { 1816 // while errors are usually already caught by `tf.callMatch`, 1817 // this can happen when calling `typeof(freefunc)` 1818 if (msg) 1819 error(loc, "%s", msg); 1820 return true; 1821 } 1822 // note: the argument list should be mutated with named arguments / default arguments, 1823 // so we can't simply change the pointer like `arguments = resolvedArgs;` 1824 arguments.setDim(0); 1825 arguments.pushSlice((*resolvedArgs)[]); 1826 } 1827 size_t nargs = arguments ? arguments.length : 0; 1828 1829 if (nargs > nparams && tf.parameterList.varargs == VarArg.none) 1830 { 1831 error(loc, "expected %llu arguments, not %llu for non-variadic function type `%s`", cast(ulong)nparams, cast(ulong)nargs, tf.toChars()); 1832 return true; 1833 } 1834 1835 // If inferring return type, and semantic3() needs to be run if not already run 1836 if (!tf.next && fd.inferRetType) 1837 { 1838 fd.functionSemantic(); 1839 } 1840 else if (fd && fd.parent) 1841 { 1842 TemplateInstance ti = fd.parent.isTemplateInstance(); 1843 if (ti && ti.tempdecl) 1844 { 1845 fd.functionSemantic3(); 1846 } 1847 } 1848 1849 /* If calling a pragma(inline, true) function, 1850 * set flag to later scan for inlines. 1851 */ 1852 if (fd && fd.inlining == PINLINE.always) 1853 { 1854 if (sc._module) 1855 sc._module.hasAlwaysInlines = true; 1856 if (sc.func) 1857 sc.func.hasAlwaysInlines = true; 1858 } 1859 1860 const isCtorCall = fd && fd.needThis() && fd.isCtorDeclaration(); 1861 1862 const size_t n = (nargs > nparams) ? nargs : nparams; // n = max(nargs, nparams) 1863 1864 /* If the function return type has wildcards in it, we'll need to figure out the actual type 1865 * based on the actual argument types. 1866 * Start with the `this` argument, later on merge into wildmatch the mod bits of the rest 1867 * of the arguments. 1868 */ 1869 MOD wildmatch = (tthis && !isCtorCall) ? tthis.Type.deduceWild(tf, false) : 0; 1870 1871 bool done = false; 1872 foreach (const i; 0 .. n) 1873 { 1874 Expression arg = (i < nargs) ? (*arguments)[i] : null; 1875 1876 if (i < nparams) 1877 { 1878 bool errorArgs() 1879 { 1880 error(loc, "expected %llu function arguments, not %llu", cast(ulong)nparams, cast(ulong)nargs); 1881 return true; 1882 } 1883 1884 Parameter p = tf.parameterList[i]; 1885 1886 if (!arg) 1887 { 1888 if (!p.defaultArg) 1889 { 1890 if (tf.parameterList.varargs == VarArg.typesafe && i + 1 == nparams) 1891 goto L2; 1892 return errorArgs(); 1893 } 1894 arg = p.defaultArg; 1895 if (!arg.type) 1896 arg = arg.expressionSemantic(sc); 1897 arg = inlineCopy(arg, sc); 1898 // __FILE__, __LINE__, __MODULE__, __FUNCTION__, and __PRETTY_FUNCTION__ 1899 arg = arg.resolveLoc(loc, sc); 1900 if (i >= nargs) 1901 { 1902 arguments.push(arg); 1903 nargs++; 1904 } 1905 else 1906 (*arguments)[i] = arg; 1907 } 1908 else 1909 { 1910 if (isDefaultInitOp(arg.op)) 1911 { 1912 arg = arg.resolveLoc(loc, sc); 1913 (*arguments)[i] = arg; 1914 } 1915 } 1916 1917 1918 if (tf.parameterList.varargs == VarArg.typesafe && i + 1 == nparams) // https://dlang.org/spec/function.html#variadic 1919 { 1920 //printf("\t\tvarargs == 2, p.type = '%s'\n", p.type.toChars()); 1921 { 1922 MATCH m; 1923 if ((m = arg.implicitConvTo(p.type)) > MATCH.nomatch) 1924 { 1925 if (p.type.nextOf() && arg.implicitConvTo(p.type.nextOf()) >= m) 1926 goto L2; 1927 else if (nargs != nparams) 1928 return errorArgs(); 1929 goto L1; 1930 } 1931 } 1932 L2: 1933 Type tb = p.type.toBasetype(); 1934 switch (tb.ty) 1935 { 1936 case Tsarray: 1937 case Tarray: 1938 { 1939 /* Create a static array variable v of type arg.type: 1940 * T[dim] __arrayArg = [ arguments[i], ..., arguments[nargs-1] ]; 1941 * 1942 * The array literal in the initializer of the hidden variable 1943 * is now optimized. 1944 * https://issues.dlang.org/show_bug.cgi?id=2356 1945 */ 1946 Type tbn = (cast(TypeArray)tb).next; // array element type 1947 Type tret = p.isLazyArray(); 1948 1949 auto elements = new Expressions(nargs - i); 1950 foreach (u; 0 .. elements.length) 1951 { 1952 Expression a = (*arguments)[i + u]; 1953 if (tret && a.implicitConvTo(tret)) 1954 { 1955 // p is a lazy array of delegates, tret is return type of the delegates 1956 a = a.implicitCastTo(sc, tret) 1957 .optimize(WANTvalue) 1958 .toDelegate(tret, sc); 1959 } 1960 else 1961 a = a.implicitCastTo(sc, tbn); 1962 a = a.addDtorHook(sc); 1963 (*elements)[u] = a; 1964 } 1965 // https://issues.dlang.org/show_bug.cgi?id=14395 1966 // Convert to a static array literal, or its slice. 1967 arg = new ArrayLiteralExp(loc, tbn.sarrayOf(nargs - i), elements); 1968 if (tb.ty == Tarray) 1969 { 1970 arg = new SliceExp(loc, arg, null, null); 1971 arg.type = p.type; 1972 } 1973 break; 1974 } 1975 case Tclass: 1976 { 1977 /* Set arg to be: 1978 * new Tclass(arg0, arg1, ..., argn) 1979 */ 1980 auto args = new Expressions(nargs - i); 1981 foreach (u; i .. nargs) 1982 (*args)[u - i] = (*arguments)[u]; 1983 arg = new NewExp(loc, null, p.type, args); 1984 break; 1985 } 1986 default: 1987 if (!arg) 1988 { 1989 error(loc, "not enough arguments"); 1990 return true; 1991 } 1992 break; 1993 } 1994 arg = arg.expressionSemantic(sc); 1995 //printf("\targ = '%s'\n", arg.toChars()); 1996 arguments.setDim(i + 1); 1997 (*arguments)[i] = arg; 1998 nargs = i + 1; 1999 done = true; 2000 } 2001 2002 L1: 2003 if (!(p.isLazy() && p.type.ty == Tvoid)) 2004 { 2005 if (ubyte wm = arg.type.deduceWild(p.type, p.isReference())) 2006 { 2007 wildmatch = wildmatch ? MODmerge(wildmatch, wm) : wm; 2008 //printf("[%d] p = %s, a = %s, wm = %d, wildmatch = %d\n", i, p.type.toChars(), arg.type.toChars(), wm, wildmatch); 2009 } 2010 } 2011 } 2012 if (done) 2013 break; 2014 } 2015 if ((wildmatch == MODFlags.mutable || wildmatch == MODFlags.immutable_) && 2016 tf.next && tf.next.hasWild() && 2017 (tf.isref || !tf.next.implicitConvTo(tf.next.immutableOf()))) 2018 { 2019 bool errorInout(MOD wildmatch) 2020 { 2021 const(char)* s = wildmatch == MODFlags.mutable ? "mutable" : MODtoChars(wildmatch); 2022 error(loc, "modify `inout` to `%s` is not allowed inside `inout` function", s); 2023 return true; 2024 } 2025 2026 if (fd) 2027 { 2028 /* If the called function may return the reference to 2029 * outer inout data, it should be rejected. 2030 * 2031 * void foo(ref inout(int) x) { 2032 * ref inout(int) bar(inout(int)) { return x; } 2033 * struct S { 2034 * ref inout(int) bar() inout { return x; } 2035 * ref inout(int) baz(alias a)() inout { return x; } 2036 * } 2037 * bar(int.init) = 1; // bad! 2038 * S().bar() = 1; // bad! 2039 * } 2040 * void test() { 2041 * int a; 2042 * auto s = foo(a); 2043 * s.baz!a() = 1; // bad! 2044 * } 2045 * 2046 */ 2047 bool checkEnclosingWild(Dsymbol s) 2048 { 2049 bool checkWild(Dsymbol s) 2050 { 2051 if (!s) 2052 return false; 2053 if (auto ad = s.isAggregateDeclaration()) 2054 { 2055 if (ad.isNested()) 2056 return checkEnclosingWild(s); 2057 } 2058 else if (auto ff = s.isFuncDeclaration()) 2059 { 2060 if (ff.type.isTypeFunction().iswild) 2061 return errorInout(wildmatch); 2062 2063 if (ff.isNested() || ff.isThis()) 2064 return checkEnclosingWild(s); 2065 } 2066 return false; 2067 } 2068 2069 Dsymbol ctx0 = s.toParent2(); 2070 Dsymbol ctx1 = s.toParentLocal(); 2071 if (checkWild(ctx0)) 2072 return true; 2073 if (ctx0 != ctx1) 2074 return checkWild(ctx1); 2075 return false; 2076 } 2077 if ((fd.isThis() || fd.isNested()) && checkEnclosingWild(fd)) 2078 return true; 2079 } 2080 else if (tf.isWild()) 2081 return errorInout(wildmatch); 2082 } 2083 2084 Expression firstArg = null; 2085 final switch (returnParamDest(tf, tthis)) 2086 { 2087 case ReturnParamDest.returnVal: 2088 break; 2089 case ReturnParamDest.firstArg: 2090 firstArg = nargs > 0 ? (*arguments)[0] : null; 2091 break; 2092 case ReturnParamDest.this_: 2093 firstArg = ethis; 2094 break; 2095 } 2096 2097 assert(nargs >= nparams); 2098 foreach (const i, arg; (*arguments)[0 .. nargs]) 2099 { 2100 assert(arg); 2101 if (i < nparams) 2102 { 2103 Parameter p = tf.parameterList[i]; 2104 Type targ = arg.type; // keep original type for isCopyable() because alias this 2105 // resolution may hide an uncopyable type 2106 2107 if (!(p.isLazy() && p.type.ty == Tvoid)) 2108 { 2109 Type tprm = p.type.hasWild() 2110 ? p.type.substWildTo(wildmatch) 2111 : p.type; 2112 2113 const hasCopyCtor = arg.type.isTypeStruct() && arg.type.isTypeStruct().sym.hasCopyCtor; 2114 const typesMatch = arg.type.mutableOf().unSharedOf().equals(tprm.mutableOf().unSharedOf()); 2115 if (!((hasCopyCtor && typesMatch) || tprm.equals(arg.type))) 2116 { 2117 //printf("arg.type = %s, p.type = %s\n", arg.type.toChars(), p.type.toChars()); 2118 arg = arg.implicitCastTo(sc, tprm); 2119 arg = arg.optimize(WANTvalue, p.isReference()); 2120 } 2121 } 2122 2123 // Support passing rvalue to `in` parameters 2124 if ((p.storageClass & (STC.in_ | STC.ref_)) == (STC.in_ | STC.ref_)) 2125 { 2126 if (!arg.isLvalue()) 2127 { 2128 auto v = copyToTemp(STC.exptemp, "__rvalue", arg); 2129 Expression ev = new DeclarationExp(arg.loc, v); 2130 ev = new CommaExp(arg.loc, ev, new VarExp(arg.loc, v)); 2131 arg = ev.expressionSemantic(sc); 2132 } 2133 arg = arg.toLvalue(sc, arg); 2134 2135 // Look for mutable misaligned pointer, etc., in @safe mode 2136 err |= checkUnsafeAccess(sc, arg, false, true); 2137 } 2138 else if (p.storageClass & STC.ref_) 2139 { 2140 if (global.params.rvalueRefParam == FeatureState.enabled && 2141 !arg.isLvalue() && 2142 targ.isCopyable()) 2143 { /* allow rvalues to be passed to ref parameters by copying 2144 * them to a temp, then pass the temp as the argument 2145 */ 2146 auto v = copyToTemp(0, "__rvalue", arg); 2147 Expression ev = new DeclarationExp(arg.loc, v); 2148 ev = new CommaExp(arg.loc, ev, new VarExp(arg.loc, v)); 2149 arg = ev.expressionSemantic(sc); 2150 } 2151 arg = arg.toLvalue(sc, arg); 2152 2153 // Look for mutable misaligned pointer, etc., in @safe mode 2154 err |= checkUnsafeAccess(sc, arg, false, true); 2155 } 2156 else if (p.storageClass & STC.out_) 2157 { 2158 Type t = arg.type; 2159 if (!t.isMutable() || !t.isAssignable()) // check blit assignable 2160 { 2161 arg.error("cannot modify struct `%s` with immutable members", arg.toChars()); 2162 err = true; 2163 } 2164 else 2165 { 2166 // Look for misaligned pointer, etc., in @safe mode 2167 err |= checkUnsafeAccess(sc, arg, false, true); 2168 err |= checkDefCtor(arg.loc, t); // t must be default constructible 2169 } 2170 arg = arg.toLvalue(sc, arg); 2171 } 2172 else if (p.isLazy()) 2173 { 2174 // Convert lazy argument to a delegate 2175 auto t = (p.type.ty == Tvoid) ? p.type : arg.type; 2176 arg = toDelegate(arg, t, sc); 2177 } 2178 //printf("arg: %s\n", arg.toChars()); 2179 //printf("type: %s\n", arg.type.toChars()); 2180 //printf("param: %s\n", p.toChars()); 2181 2182 const pStc = tf.parameterStorageClass(tthis, p); 2183 2184 if (firstArg && (pStc & STC.return_)) 2185 { 2186 /* Argument value can be assigned to firstArg. 2187 * Check arg to see if it matters. 2188 */ 2189 err |= checkParamArgumentReturn(sc, firstArg, arg, p, false); 2190 } 2191 // Allow 'lazy' to imply 'scope' - lazy parameters can be passed along 2192 // as lazy parameters to the next function, but that isn't escaping. 2193 // The arguments of `_d_arraycatnTX` are already handled in 2194 // expressionsem.d, via `checkNewEscape`. Without `-dip1000`, the 2195 // check does not return an error, so the lowering of `a ~ b` to 2196 // `_d_arraycatnTX(a, b)` still occurs. 2197 else if (!(pStc & STC.lazy_) && (!fd || fd.ident != Id._d_arraycatnTX)) 2198 { 2199 /* Argument value can escape from the called function. 2200 * Check arg to see if it matters. 2201 */ 2202 VarDeclaration vPar = fd ? (fd.parameters ? (*fd.parameters)[i] : null) : null; 2203 err |= checkParamArgumentEscape(sc, fd, p.ident, vPar, cast(STC) pStc, arg, false, false); 2204 } 2205 2206 // Turning heap allocations into stack allocations is dangerous without dip1000, since `scope` inference 2207 // may be unreliable when scope violations only manifest as deprecation warnings. 2208 // However, existing `@nogc` code may rely on it, so still do it when the parameter is explicitly marked `scope` 2209 const explicitScope = p.isLazy() || 2210 ((p.storageClass & STC.scope_) && !(p.storageClass & STC.scopeinferred)); 2211 if ((pStc & (STC.scope_ | STC.lazy_)) && 2212 ((global.params.useDIP1000 == FeatureState.enabled) || explicitScope) && 2213 !(pStc & STC.return_)) 2214 { 2215 /* Argument value cannot escape from the called function. 2216 */ 2217 Expression a = arg; 2218 if (auto ce = a.isCastExp()) 2219 a = ce.e1; 2220 2221 ArrayLiteralExp ale; 2222 if (p.type.toBasetype().ty == Tarray && 2223 (ale = a.isArrayLiteralExp()) !is null && ale.elements && ale.elements.length > 0) 2224 { 2225 // allocate the array literal as temporary static array on the stack 2226 ale.type = ale.type.nextOf().sarrayOf(ale.elements.length); 2227 auto tmp = copyToTemp(0, "__arrayliteral_on_stack", ale); 2228 tmp.storage_class |= STC.exptemp; 2229 auto declareTmp = new DeclarationExp(ale.loc, tmp); 2230 auto castToSlice = new CastExp(ale.loc, new VarExp(ale.loc, tmp), 2231 p.type.substWildTo(MODFlags.mutable)); 2232 arg = CommaExp.combine(declareTmp, castToSlice); 2233 arg = arg.expressionSemantic(sc); 2234 } 2235 else if (auto fe = a.isFuncExp()) 2236 { 2237 /* Function literals can only appear once, so if this 2238 * appearance was scoped, there cannot be any others. 2239 */ 2240 fe.fd.tookAddressOf = 0; 2241 } 2242 else if (auto de = a.isDelegateExp()) 2243 { 2244 /* For passing a delegate to a scoped parameter, 2245 * this doesn't count as taking the address of it. 2246 * We only worry about 'escaping' references to the function. 2247 */ 2248 if (auto ve = de.e1.isVarExp()) 2249 { 2250 if (auto f = ve.var.isFuncDeclaration()) 2251 { 2252 if (f.tookAddressOf) 2253 --f.tookAddressOf; 2254 //printf("--tookAddressOf = %d\n", f.tookAddressOf); 2255 } 2256 } 2257 } 2258 } 2259 if (!p.isReference()) 2260 err |= arg.checkSharedAccess(sc); 2261 2262 arg = arg.optimize(WANTvalue, p.isReference()); 2263 } 2264 else 2265 { 2266 // These will be the trailing ... arguments 2267 // If not D linkage, do promotions 2268 if (tf.linkage != LINK.d) 2269 { 2270 // Promote bytes, words, etc., to ints 2271 arg = integralPromotions(arg, sc); 2272 2273 // Promote floats to doubles 2274 switch (arg.type.ty) 2275 { 2276 case Tfloat32: 2277 arg = arg.castTo(sc, Type.tfloat64); 2278 break; 2279 2280 case Timaginary32: 2281 arg = arg.castTo(sc, Type.timaginary64); 2282 break; 2283 2284 default: 2285 break; 2286 } 2287 if (tf.parameterList.varargs == VarArg.variadic || 2288 tf.parameterList.varargs == VarArg.KRvariadic) 2289 { 2290 const(char)* p = tf.linkage == LINK.c ? "extern(C)" : "extern(C++)"; 2291 if (arg.type.ty == Tarray) 2292 { 2293 arg.error("cannot pass dynamic arrays to `%s` vararg functions", p); 2294 err = true; 2295 } 2296 if (arg.type.ty == Tsarray) 2297 { 2298 arg.error("cannot pass static arrays to `%s` vararg functions", p); 2299 err = true; 2300 } 2301 } 2302 } 2303 2304 // Do not allow types that need destructors or copy constructors. 2305 if (arg.type.needsDestruction()) 2306 { 2307 arg.error("cannot pass types that need destruction as variadic arguments"); 2308 err = true; 2309 } 2310 if (arg.type.needsCopyOrPostblit()) 2311 { 2312 arg.error("cannot pass types with postblits or copy constructors as variadic arguments"); 2313 err = true; 2314 } 2315 2316 // Convert static arrays to dynamic arrays 2317 // BUG: I don't think this is right for D2 2318 Type tb = arg.type.toBasetype(); 2319 if (auto ts = tb.isTypeSArray()) 2320 { 2321 Type ta = ts.next.arrayOf(); 2322 if (ts.size(arg.loc) == 0) 2323 arg = new NullExp(arg.loc, ta); 2324 else 2325 arg = arg.castTo(sc, ta); 2326 } 2327 if (tb.ty == Tstruct) 2328 { 2329 //arg = callCpCtor(sc, arg); 2330 } 2331 // Give error for overloaded function addresses 2332 if (auto se = arg.isSymOffExp()) 2333 { 2334 if (se.hasOverloads && !se.var.isFuncDeclaration().isUnique()) 2335 { 2336 arg.error("function `%s` is overloaded", arg.toChars()); 2337 err = true; 2338 } 2339 } 2340 err |= arg.checkValue(); 2341 err |= arg.checkSharedAccess(sc); 2342 arg = arg.optimize(WANTvalue); 2343 } 2344 (*arguments)[i] = arg; 2345 } 2346 2347 /* If calling C scanf(), printf(), or any variants, check the format string against the arguments 2348 */ 2349 const isVa_list = tf.parameterList.varargs == VarArg.none; 2350 if (fd && fd.printf) 2351 { 2352 if (auto se = (*arguments)[nparams - 1 - isVa_list].isStringExp()) 2353 { 2354 checkPrintfFormat(se.loc, se.peekString(), (*arguments)[nparams .. nargs], isVa_list); 2355 } 2356 } 2357 else if (fd && fd.scanf) 2358 { 2359 if (auto se = (*arguments)[nparams - 1 - isVa_list].isStringExp()) 2360 { 2361 checkScanfFormat(se.loc, se.peekString(), (*arguments)[nparams .. nargs], isVa_list); 2362 } 2363 } 2364 else 2365 { 2366 // TODO: not checking the "v" functions yet (for those, check format string only, not args) 2367 } 2368 2369 /* Remaining problems: 2370 * 1. value structs (or static arrays of them) that need to be copy constructed 2371 * 2. value structs (or static arrays of them) that have destructors, and subsequent arguments that may throw before the 2372 * function gets called. 2373 * 3. value structs need to be destructed after the function call for platforms where the caller destroys the arguments. 2374 * Those are handled by doing the argument construction in 'eprefix' so that if a later argument throws, they are cleaned 2375 * up properly. Pushing arguments on the stack then cannot fail. 2376 */ 2377 { 2378 /* Does Problem (3) apply? 2379 */ 2380 const bool callerDestroysArgs = !target.isCalleeDestroyingArgs(tf); 2381 2382 /* Compute indices of last throwing argument and first arg needing destruction. 2383 * Used to not set up destructors unless an arg needs destruction on a throw 2384 * in a later argument. 2385 */ 2386 ptrdiff_t lastthrow = -1; // last argument that may throw 2387 ptrdiff_t firstdtor = -1; // first argument that needs destruction 2388 ptrdiff_t lastdtor = -1; // last argument that needs destruction 2389 for (ptrdiff_t i = 0; i != nargs; i++) 2390 { 2391 Expression arg = (*arguments)[i]; 2392 if (canThrow(arg, sc.func, false)) 2393 lastthrow = i; 2394 if (arg.type.needsDestruction()) 2395 { 2396 Parameter p = (i >= nparams ? null : tf.parameterList[i]); 2397 if (!(p && (p.isLazy() || p.isReference()))) 2398 { 2399 if (firstdtor == -1) 2400 firstdtor = i; 2401 lastdtor = i; 2402 } 2403 } 2404 } 2405 2406 /* Do we need 'eprefix' for problems 2 or 3? 2407 */ 2408 const bool needsPrefix = callerDestroysArgs 2409 ? firstdtor >= 0 // true if any argument needs destruction 2410 : firstdtor >= 0 && lastthrow >= 0 && 2411 (lastthrow - firstdtor) > 0; // last throw after first destruction 2412 const ptrdiff_t lastPrefix = callerDestroysArgs 2413 ? lastdtor // up to last argument requiring destruction 2414 : lastthrow; // up to last potentially throwing argument 2415 2416 /* Problem 3: initialize 'eprefix' by declaring the gate 2417 */ 2418 VarDeclaration gate; 2419 if (needsPrefix && !callerDestroysArgs) 2420 { 2421 // eprefix => bool __gate [= false] 2422 Identifier idtmp = Identifier.generateId("__gate"); 2423 gate = new VarDeclaration(loc, Type.tbool, idtmp, null); 2424 gate.storage_class |= STC.temp | STC.ctfe | STC.volatile_; 2425 gate.dsymbolSemantic(sc); 2426 2427 auto ae = new DeclarationExp(loc, gate); 2428 eprefix = ae.expressionSemantic(sc); 2429 } 2430 2431 for (ptrdiff_t i = 0; i != nargs; i++) 2432 { 2433 Expression arg = (*arguments)[i]; 2434 //printf("arg[%d]: %s\n", cast(int)i, arg.toChars()); 2435 2436 Parameter parameter = (i >= nparams ? null : tf.parameterList[i]); 2437 const bool isRef = parameter && parameter.isReference(); 2438 const bool isLazy = parameter && parameter.isLazy(); 2439 2440 /* Skip lazy parameters 2441 */ 2442 if (isLazy) 2443 continue; 2444 2445 /* Do we have 'eprefix' and aren't past 'lastPrefix' yet? 2446 * Then declare a temporary variable for this arg and append that declaration 2447 * to 'eprefix', which will implicitly take care of potential problem 1) for 2448 * this arg. 2449 * 'eprefix' will therefore finally contain all args up to and including 'lastPrefix', 2450 * excluding all lazy parameters. 2451 */ 2452 if (needsPrefix && (lastPrefix - i) >= 0) 2453 { 2454 const bool needsDtor = !isRef && arg.type.needsDestruction() && 2455 // Problem 3: last throwing arg doesn't require dtor patching 2456 (callerDestroysArgs || i != lastPrefix); 2457 2458 /* Declare temporary 'auto __pfx = arg' (needsDtor) or 'auto __pfy = arg' (!needsDtor) 2459 */ 2460 auto tmp = copyToTemp( 2461 (parameter ? parameter.storageClass : tf.parameterList.stc) & (STC.scope_), 2462 needsDtor ? "__pfx" : "__pfy", 2463 !isRef ? arg : arg.addressOf()); 2464 tmp.dsymbolSemantic(sc); 2465 2466 if (callerDestroysArgs) 2467 { 2468 /* Problem 4: Normal temporary, destructed after the call 2469 */ 2470 if (needsDtor) 2471 tmp.isArgDtorVar = true; // mark it so that the backend passes it by ref to the function being called 2472 } 2473 else 2474 { 2475 /* Problem 2: Modify the destructor so it only runs if gate==false, 2476 * i.e., only if there was a throw while constructing the args 2477 */ 2478 if (!needsDtor) 2479 { 2480 if (tmp.edtor) 2481 { 2482 assert(i == lastPrefix); 2483 tmp.edtor = null; 2484 } 2485 } 2486 else 2487 { 2488 // edtor => (__gate || edtor) 2489 assert(tmp.edtor); 2490 Expression e = tmp.edtor; 2491 e = new LogicalExp(e.loc, EXP.orOr, new VarExp(e.loc, gate), e); 2492 tmp.edtor = e.expressionSemantic(sc); 2493 //printf("edtor: %s\n", tmp.edtor.toChars()); 2494 } 2495 } 2496 2497 // eprefix => (eprefix, auto __pfx/y = arg) 2498 auto ae = new DeclarationExp(loc, tmp); 2499 eprefix = Expression.combine(eprefix, ae.expressionSemantic(sc)); 2500 2501 // arg => __pfx/y 2502 arg = new VarExp(loc, tmp); 2503 arg = arg.expressionSemantic(sc); 2504 if (isRef) 2505 { 2506 arg = new PtrExp(loc, arg); 2507 arg = arg.expressionSemantic(sc); 2508 } 2509 2510 /* Problem 2: Last throwing arg? 2511 * Then finalize eprefix => (eprefix, gate = true), i.e., disable the 2512 * dtors right after constructing the last throwing arg. 2513 * From now on, the callee will take care of destructing the args because 2514 * the args are implicitly moved into function parameters. 2515 */ 2516 if (!callerDestroysArgs && i == lastPrefix) 2517 { 2518 auto e = new AssignExp(gate.loc, new VarExp(gate.loc, gate), IntegerExp.createBool(true)); 2519 eprefix = Expression.combine(eprefix, e.expressionSemantic(sc)); 2520 } 2521 } 2522 else // not part of 'eprefix' 2523 { 2524 /* Handle problem 1) by calling the copy constructor for value structs 2525 * (or static arrays of them) if appropriate. 2526 */ 2527 Type tv = arg.type.baseElemOf(); 2528 if (!isRef && tv.ty == Tstruct) 2529 arg = doCopyOrMove(sc, arg, parameter ? parameter.type : null); 2530 } 2531 2532 (*arguments)[i] = arg; 2533 } 2534 } 2535 //if (eprefix) printf("eprefix: %s\n", eprefix.toChars()); 2536 2537 /* Test compliance with DIP1021 Argument Ownership and Function Calls 2538 */ 2539 if (global.params.useDIP1021 && (tf.trust == TRUST.safe || tf.trust == TRUST.default_) || 2540 tf.islive) 2541 err |= checkMutableArguments(sc, fd, tf, ethis, arguments, false); 2542 2543 // If D linkage and variadic, add _arguments[] as first argument 2544 if (tf.isDstyleVariadic()) 2545 { 2546 assert(arguments.length >= nparams); 2547 2548 auto args = new Parameters(arguments.length - nparams); 2549 for (size_t i = 0; i < arguments.length - nparams; i++) 2550 { 2551 auto arg = new Parameter(STC.in_, (*arguments)[nparams + i].type, null, null, null); 2552 (*args)[i] = arg; 2553 } 2554 auto tup = new TypeTuple(args); 2555 Expression e = (new TypeidExp(loc, tup)).expressionSemantic(sc); 2556 arguments.insert(0, e); 2557 } 2558 2559 /* Determine function return type: tret 2560 */ 2561 Type tret = tf.next; 2562 if (isCtorCall) 2563 { 2564 //printf("[%s] fd = %s %s, %d %d %d\n", loc.toChars(), fd.toChars(), fd.type.toChars(), 2565 // wildmatch, tf.isWild(), fd.isReturnIsolated()); 2566 if (!tthis) 2567 { 2568 assert(sc.intypeof || global.errors); 2569 tthis = fd.isThis().type.addMod(fd.type.mod); 2570 } 2571 if (tf.isWild() && !fd.isReturnIsolated()) 2572 { 2573 if (wildmatch) 2574 tret = tret.substWildTo(wildmatch); 2575 int offset; 2576 if (!tret.implicitConvTo(tthis) && !(MODimplicitConv(tret.mod, tthis.mod) && tret.isBaseOf(tthis, &offset) && offset == 0)) 2577 { 2578 const(char)* s1 = tret.isNaked() ? " mutable" : tret.modToChars(); 2579 const(char)* s2 = tthis.isNaked() ? " mutable" : tthis.modToChars(); 2580 .error(loc, "`inout` constructor `%s` creates%s object, not%s", fd.toPrettyChars(), s1, s2); 2581 err = true; 2582 } 2583 } 2584 tret = tthis; 2585 } 2586 else if (wildmatch && tret) 2587 { 2588 /* Adjust function return type based on wildmatch 2589 */ 2590 //printf("wildmatch = x%x, tret = %s\n", wildmatch, tret.toChars()); 2591 tret = tret.substWildTo(wildmatch); 2592 } 2593 2594 *prettype = tret; 2595 *peprefix = eprefix; 2596 return (err || olderrors != global.errors); 2597 } 2598 2599 /** 2600 * Determines whether a symbol represents a module or package 2601 * (Used as a helper for is(type == module) and is(type == package)) 2602 * 2603 * Params: 2604 * sym = the symbol to be checked 2605 * 2606 * Returns: 2607 * the symbol which `sym` represents (or `null` if it doesn't represent a `Package`) 2608 */ 2609 Package resolveIsPackage(Dsymbol sym) 2610 { 2611 Package pkg; 2612 if (Import imp = sym.isImport()) 2613 { 2614 if (imp.pkg is null) 2615 { 2616 .error(sym.loc, "internal compiler error: unable to process forward-referenced import `%s`", 2617 imp.toChars()); 2618 assert(0); 2619 } 2620 pkg = imp.pkg; 2621 } 2622 else if (auto mod = sym.isModule()) 2623 pkg = mod.isPackageFile ? mod.pkg : sym.isPackage(); 2624 else 2625 pkg = sym.isPackage(); 2626 if (pkg) 2627 pkg.resolvePKGunknown(); 2628 return pkg; 2629 } 2630 2631 2632 private extern (C++) final class ExpressionSemanticVisitor : Visitor 2633 { 2634 alias visit = Visitor.visit; 2635 2636 Scope* sc; 2637 Expression result; 2638 2639 this(Scope* sc) scope 2640 { 2641 this.sc = sc; 2642 } 2643 2644 private void setError() 2645 { 2646 result = ErrorExp.get(); 2647 } 2648 2649 /************************** 2650 * Semantically analyze Expression. 2651 * Determine types, fold constants, etc. 2652 */ 2653 override void visit(Expression e) 2654 { 2655 static if (LOGSEMANTIC) 2656 { 2657 printf("Expression::semantic() %s\n", e.toChars()); 2658 } 2659 if (e.type) 2660 e.type = e.type.typeSemantic(e.loc, sc); 2661 else 2662 e.type = Type.tvoid; 2663 result = e; 2664 } 2665 2666 override void visit(IntegerExp e) 2667 { 2668 assert(e.type); 2669 if (e.type.ty == Terror) 2670 return setError(); 2671 2672 assert(e.type.deco); 2673 e.setInteger(e.getInteger()); 2674 result = e; 2675 } 2676 2677 override void visit(RealExp e) 2678 { 2679 if (!e.type) 2680 e.type = Type.tfloat64; 2681 else if (e.type.isimaginary && sc.flags & SCOPE.Cfile) 2682 { 2683 /* Convert to core.stdc.config.complex 2684 */ 2685 Type t = getComplexLibraryType(e.loc, sc, e.type.ty); 2686 if (t.ty == Terror) 2687 return setError(); 2688 2689 Type tf; 2690 switch (e.type.ty) 2691 { 2692 case Timaginary32: tf = Type.tfloat32; break; 2693 case Timaginary64: tf = Type.tfloat64; break; 2694 case Timaginary80: tf = Type.tfloat80; break; 2695 default: 2696 assert(0); 2697 } 2698 2699 /* Construct ts{re : 0.0, im : e} 2700 */ 2701 TypeStruct ts = t.isTypeStruct; 2702 Expressions* elements = new Expressions(2); 2703 (*elements)[0] = new RealExp(e.loc, CTFloat.zero, tf); 2704 (*elements)[1] = new RealExp(e.loc, e.toImaginary(), tf); 2705 Expression sle = new StructLiteralExp(e.loc, ts.sym, elements); 2706 result = sle.expressionSemantic(sc); 2707 return; 2708 } 2709 else 2710 e.type = e.type.typeSemantic(e.loc, sc); 2711 result = e; 2712 } 2713 2714 override void visit(ComplexExp e) 2715 { 2716 if (!e.type) 2717 e.type = Type.tcomplex80; 2718 else 2719 e.type = e.type.typeSemantic(e.loc, sc); 2720 result = e; 2721 } 2722 2723 override void visit(IdentifierExp exp) 2724 { 2725 static if (LOGSEMANTIC) 2726 { 2727 printf("IdentifierExp::semantic('%s')\n", exp.ident.toChars()); 2728 } 2729 if (exp.type) // This is used as the dummy expression 2730 { 2731 result = exp; 2732 return; 2733 } 2734 2735 Dsymbol scopesym; 2736 Dsymbol s = sc.search(exp.loc, exp.ident, &scopesym); 2737 if (s) 2738 { 2739 if (s.errors) 2740 return setError(); 2741 2742 Expression e; 2743 2744 /* See if the symbol was a member of an enclosing 'with' 2745 */ 2746 WithScopeSymbol withsym = scopesym.isWithScopeSymbol(); 2747 if (withsym && withsym.withstate.wthis && symbolIsVisible(sc, s)) 2748 { 2749 /* Disallow shadowing 2750 */ 2751 // First find the scope of the with 2752 Scope* scwith = sc; 2753 while (scwith.scopesym != scopesym) 2754 { 2755 scwith = scwith.enclosing; 2756 assert(scwith); 2757 } 2758 // Look at enclosing scopes for symbols with the same name, 2759 // in the same function 2760 for (Scope* scx = scwith; scx && scx.func == scwith.func; scx = scx.enclosing) 2761 { 2762 Dsymbol s2; 2763 if (scx.scopesym && scx.scopesym.symtab && (s2 = scx.scopesym.symtab.lookup(s.ident)) !is null && s != s2) 2764 { 2765 exp.error("with symbol `%s` is shadowing local symbol `%s`", s.toPrettyChars(), s2.toPrettyChars()); 2766 return setError(); 2767 } 2768 } 2769 s = s.toAlias(); 2770 2771 // Same as wthis.ident 2772 // TODO: DotIdExp.semantic will find 'ident' from 'wthis' again. 2773 // The redudancy should be removed. 2774 e = new VarExp(exp.loc, withsym.withstate.wthis); 2775 e = new DotIdExp(exp.loc, e, exp.ident); 2776 e = e.expressionSemantic(sc); 2777 } 2778 else 2779 { 2780 if (withsym) 2781 { 2782 if (withsym.withstate.exp.type.ty != Tvoid) 2783 { 2784 // 'with (exp)' is a type expression 2785 // or 's' is not visible there (for error message) 2786 e = new TypeExp(exp.loc, withsym.withstate.exp.type); 2787 } 2788 else 2789 { 2790 // 'with (exp)' is a Package/Module 2791 e = withsym.withstate.exp; 2792 } 2793 e = new DotIdExp(exp.loc, e, exp.ident); 2794 result = e.expressionSemantic(sc); 2795 return; 2796 } 2797 2798 /* If f is really a function template, 2799 * then replace f with the function template declaration. 2800 */ 2801 FuncDeclaration f = s.isFuncDeclaration(); 2802 if (f) 2803 { 2804 TemplateDeclaration td = getFuncTemplateDecl(f); 2805 if (td) 2806 { 2807 if (td.overroot) // if not start of overloaded list of TemplateDeclaration's 2808 td = td.overroot; // then get the start 2809 e = new TemplateExp(exp.loc, td, f); 2810 e = e.expressionSemantic(sc); 2811 result = e; 2812 return; 2813 } 2814 } 2815 2816 if (global.params.fixAliasThis) 2817 { 2818 ExpressionDsymbol expDsym = scopesym.isExpressionDsymbol(); 2819 if (expDsym) 2820 { 2821 //printf("expDsym = %s\n", expDsym.exp.toChars()); 2822 result = expDsym.exp.expressionSemantic(sc); 2823 return; 2824 } 2825 } 2826 // Haven't done overload resolution yet, so pass 1 2827 e = symbolToExp(s, exp.loc, sc, true); 2828 } 2829 result = e; 2830 return; 2831 } 2832 2833 if (!global.params.fixAliasThis && hasThis(sc)) 2834 { 2835 for (AggregateDeclaration ad = sc.getStructClassScope(); ad;) 2836 { 2837 if (ad.aliasthis) 2838 { 2839 Expression e; 2840 e = new ThisExp(exp.loc); 2841 e = new DotIdExp(exp.loc, e, ad.aliasthis.ident); 2842 e = new DotIdExp(exp.loc, e, exp.ident); 2843 e = e.trySemantic(sc); 2844 if (e) 2845 { 2846 result = e; 2847 return; 2848 } 2849 } 2850 2851 auto cd = ad.isClassDeclaration(); 2852 if (cd && cd.baseClass && cd.baseClass != ClassDeclaration.object) 2853 { 2854 ad = cd.baseClass; 2855 continue; 2856 } 2857 break; 2858 } 2859 } 2860 2861 if (exp.ident == Id.ctfe) 2862 { 2863 if (sc.flags & SCOPE.ctfe) 2864 { 2865 exp.error("variable `__ctfe` cannot be read at compile time"); 2866 return setError(); 2867 } 2868 2869 // Create the magic __ctfe bool variable 2870 auto vd = new VarDeclaration(exp.loc, Type.tbool, Id.ctfe, null); 2871 vd.storage_class |= STC.temp; 2872 vd.semanticRun = PASS.semanticdone; 2873 Expression e = new VarExp(exp.loc, vd); 2874 e = e.expressionSemantic(sc); 2875 result = e; 2876 return; 2877 } 2878 2879 // If we've reached this point and are inside a with() scope then we may 2880 // try one last attempt by checking whether the 'wthis' object supports 2881 // dynamic dispatching via opDispatch. 2882 // This is done by rewriting this expression as wthis.ident. 2883 // The innermost with() scope of the hierarchy to satisfy the condition 2884 // above wins. 2885 // https://issues.dlang.org/show_bug.cgi?id=6400 2886 for (Scope* sc2 = sc; sc2; sc2 = sc2.enclosing) 2887 { 2888 if (!sc2.scopesym) 2889 continue; 2890 2891 if (auto ss = sc2.scopesym.isWithScopeSymbol()) 2892 { 2893 if (ss.withstate.wthis) 2894 { 2895 Expression e; 2896 e = new VarExp(exp.loc, ss.withstate.wthis); 2897 e = new DotIdExp(exp.loc, e, exp.ident); 2898 e = e.trySemantic(sc); 2899 if (e) 2900 { 2901 result = e; 2902 return; 2903 } 2904 } 2905 // Try Type.opDispatch (so the static version) 2906 else if (ss.withstate.exp && ss.withstate.exp.op == EXP.type) 2907 { 2908 if (Type t = ss.withstate.exp.isTypeExp().type) 2909 { 2910 Expression e; 2911 e = new TypeExp(exp.loc, t); 2912 e = new DotIdExp(exp.loc, e, exp.ident); 2913 e = e.trySemantic(sc); 2914 if (e) 2915 { 2916 result = e; 2917 return; 2918 } 2919 } 2920 } 2921 } 2922 } 2923 2924 /* Look for what user might have meant 2925 */ 2926 if (const n = importHint(exp.ident.toString())) 2927 exp.error("`%s` is not defined, perhaps `import %.*s;` is needed?", exp.ident.toChars(), cast(int)n.length, n.ptr); 2928 else if (auto s2 = sc.search_correct(exp.ident)) 2929 exp.error("undefined identifier `%s`, did you mean %s `%s`?", exp.ident.toChars(), s2.kind(), s2.toChars()); 2930 else if (const p = Scope.search_correct_C(exp.ident)) 2931 exp.error("undefined identifier `%s`, did you mean `%s`?", exp.ident.toChars(), p); 2932 else if (exp.ident == Id.dollar) 2933 exp.error("undefined identifier `$`"); 2934 else 2935 exp.error("undefined identifier `%s`", exp.ident.toChars()); 2936 2937 result = ErrorExp.get(); 2938 } 2939 2940 override void visit(DsymbolExp e) 2941 { 2942 result = symbolToExp(e.s, e.loc, sc, e.hasOverloads); 2943 } 2944 2945 override void visit(ThisExp e) 2946 { 2947 static if (LOGSEMANTIC) 2948 { 2949 printf("ThisExp::semantic()\n"); 2950 } 2951 if (e.type) 2952 { 2953 result = e; 2954 return; 2955 } 2956 2957 FuncDeclaration fd = hasThis(sc); // fd is the uplevel function with the 'this' variable 2958 AggregateDeclaration ad; 2959 2960 /* Special case for typeof(this) and typeof(super) since both 2961 * should work even if they are not inside a non-static member function 2962 */ 2963 if (!fd && sc.intypeof == 1) 2964 { 2965 // Find enclosing struct or class 2966 for (Dsymbol s = sc.getStructClassScope(); 1; s = s.parent) 2967 { 2968 if (!s) 2969 { 2970 e.error("`%s` is not in a class or struct scope", e.toChars()); 2971 return setError(); 2972 } 2973 ClassDeclaration cd = s.isClassDeclaration(); 2974 if (cd) 2975 { 2976 e.type = cd.type; 2977 result = e; 2978 return; 2979 } 2980 StructDeclaration sd = s.isStructDeclaration(); 2981 if (sd) 2982 { 2983 e.type = sd.type; 2984 result = e; 2985 return; 2986 } 2987 } 2988 } 2989 if (!fd) 2990 { 2991 e.error("`this` is only defined in non-static member functions, not `%s`", sc.parent.toChars()); 2992 return setError(); 2993 } 2994 2995 assert(fd.vthis); 2996 e.var = fd.vthis; 2997 assert(e.var.parent); 2998 ad = fd.isMemberLocal(); 2999 if (!ad) 3000 ad = fd.isMember2(); 3001 assert(ad); 3002 e.type = ad.type.addMod(e.var.type.mod); 3003 3004 if (e.var.checkNestedReference(sc, e.loc)) 3005 return setError(); 3006 3007 result = e; 3008 } 3009 3010 override void visit(SuperExp e) 3011 { 3012 static if (LOGSEMANTIC) 3013 { 3014 printf("SuperExp::semantic('%s')\n", e.toChars()); 3015 } 3016 if (e.type) 3017 { 3018 result = e; 3019 return; 3020 } 3021 3022 FuncDeclaration fd = hasThis(sc); 3023 ClassDeclaration cd; 3024 Dsymbol s; 3025 3026 /* Special case for typeof(this) and typeof(super) since both 3027 * should work even if they are not inside a non-static member function 3028 */ 3029 if (!fd && sc.intypeof == 1) 3030 { 3031 // Find enclosing class 3032 for (s = sc.getStructClassScope(); 1; s = s.parent) 3033 { 3034 if (!s) 3035 { 3036 e.error("`%s` is not in a class scope", e.toChars()); 3037 return setError(); 3038 } 3039 cd = s.isClassDeclaration(); 3040 if (cd) 3041 { 3042 cd = cd.baseClass; 3043 if (!cd) 3044 { 3045 e.error("class `%s` has no `super`", s.toChars()); 3046 return setError(); 3047 } 3048 e.type = cd.type; 3049 result = e; 3050 return; 3051 } 3052 } 3053 } 3054 if (!fd) 3055 goto Lerr; 3056 3057 e.var = fd.vthis; 3058 assert(e.var && e.var.parent); 3059 3060 s = fd.toParentDecl(); 3061 if (s.isTemplateDeclaration()) // allow inside template constraint 3062 s = s.toParent(); 3063 assert(s); 3064 cd = s.isClassDeclaration(); 3065 //printf("parent is %s %s\n", fd.toParent().kind(), fd.toParent().toChars()); 3066 if (!cd) 3067 goto Lerr; 3068 if (!cd.baseClass) 3069 { 3070 e.error("no base class for `%s`", cd.toChars()); 3071 e.type = cd.type.addMod(e.var.type.mod); 3072 } 3073 else 3074 { 3075 e.type = cd.baseClass.type; 3076 e.type = e.type.castMod(e.var.type.mod); 3077 } 3078 3079 if (e.var.checkNestedReference(sc, e.loc)) 3080 return setError(); 3081 3082 result = e; 3083 return; 3084 3085 Lerr: 3086 e.error("`super` is only allowed in non-static class member functions"); 3087 result = ErrorExp.get(); 3088 } 3089 3090 override void visit(NullExp e) 3091 { 3092 static if (LOGSEMANTIC) 3093 { 3094 printf("NullExp::semantic('%s')\n", e.toChars()); 3095 } 3096 // NULL is the same as (void *)0 3097 if (e.type) 3098 { 3099 result = e; 3100 return; 3101 } 3102 e.type = Type.tnull; 3103 result = e; 3104 } 3105 3106 override void visit(StringExp e) 3107 { 3108 static if (LOGSEMANTIC) 3109 { 3110 printf("StringExp::semantic() %s\n", e.toChars()); 3111 } 3112 if (e.type) 3113 { 3114 result = e; 3115 return; 3116 } 3117 3118 OutBuffer buffer; 3119 size_t newlen = 0; 3120 size_t u; 3121 dchar c; 3122 3123 switch (e.postfix) 3124 { 3125 case 'd': 3126 for (u = 0; u < e.len;) 3127 { 3128 if (const p = utf_decodeChar(e.peekString(), u, c)) 3129 { 3130 e.error("%.*s", cast(int)p.length, p.ptr); 3131 return setError(); 3132 } 3133 else 3134 { 3135 buffer.write4(c); 3136 newlen++; 3137 } 3138 } 3139 buffer.write4(0); 3140 e.setData(buffer.extractData(), newlen, 4); 3141 if (sc && sc.flags & SCOPE.Cfile) 3142 e.type = Type.tuns32.sarrayOf(e.len + 1); 3143 else 3144 e.type = Type.tdchar.immutableOf().arrayOf(); 3145 e.committed = true; 3146 break; 3147 3148 case 'w': 3149 for (u = 0; u < e.len;) 3150 { 3151 if (const p = utf_decodeChar(e.peekString(), u, c)) 3152 { 3153 e.error("%.*s", cast(int)p.length, p.ptr); 3154 return setError(); 3155 } 3156 else 3157 { 3158 buffer.writeUTF16(c); 3159 newlen++; 3160 if (c >= 0x10000) 3161 newlen++; 3162 } 3163 } 3164 buffer.writeUTF16(0); 3165 e.setData(buffer.extractData(), newlen, 2); 3166 if (sc && sc.flags & SCOPE.Cfile) 3167 e.type = Type.tuns16.sarrayOf(e.len + 1); 3168 else 3169 e.type = Type.twchar.immutableOf().arrayOf(); 3170 e.committed = true; 3171 break; 3172 3173 case 'c': 3174 e.committed = true; 3175 goto default; 3176 3177 default: 3178 if (sc && sc.flags & SCOPE.Cfile) 3179 e.type = Type.tchar.sarrayOf(e.len + 1); 3180 else 3181 e.type = Type.tchar.immutableOf().arrayOf(); 3182 break; 3183 } 3184 e.type = e.type.typeSemantic(e.loc, sc); 3185 //type = type.immutableOf(); 3186 //printf("type = %s\n", type.toChars()); 3187 3188 result = e; 3189 } 3190 3191 override void visit(TupleExp exp) 3192 { 3193 static if (LOGSEMANTIC) 3194 { 3195 printf("+TupleExp::semantic(%s)\n", exp.toChars()); 3196 } 3197 if (exp.type) 3198 { 3199 result = exp; 3200 return; 3201 } 3202 3203 if (exp.e0) 3204 exp.e0 = exp.e0.expressionSemantic(sc); 3205 3206 // Run semantic() on each argument 3207 bool err = false; 3208 for (size_t i = 0; i < exp.exps.length; i++) 3209 { 3210 Expression e = (*exp.exps)[i]; 3211 e = e.expressionSemantic(sc); 3212 if (!e.type) 3213 { 3214 exp.error("`%s` has no value", e.toChars()); 3215 err = true; 3216 } 3217 else if (e.op == EXP.error) 3218 err = true; 3219 else 3220 (*exp.exps)[i] = e; 3221 } 3222 if (err) 3223 return setError(); 3224 3225 expandTuples(exp.exps); 3226 3227 exp.type = new TypeTuple(exp.exps); 3228 exp.type = exp.type.typeSemantic(exp.loc, sc); 3229 //printf("-TupleExp::semantic(%s)\n", toChars()); 3230 result = exp; 3231 } 3232 3233 override void visit(ArrayLiteralExp e) 3234 { 3235 static if (LOGSEMANTIC) 3236 { 3237 printf("ArrayLiteralExp::semantic('%s')\n", e.toChars()); 3238 } 3239 if (e.type) 3240 { 3241 result = e; 3242 return; 3243 } 3244 3245 /* Perhaps an empty array literal [ ] should be rewritten as null? 3246 */ 3247 3248 if (e.basis) 3249 e.basis = e.basis.expressionSemantic(sc); 3250 if (arrayExpressionSemantic(e.elements.peekSlice(), sc) || (e.basis && e.basis.op == EXP.error)) 3251 return setError(); 3252 3253 expandTuples(e.elements); 3254 3255 if (e.basis) 3256 e.elements.push(e.basis); 3257 Type t0 = arrayExpressionToCommonType(sc, *e.elements); 3258 if (e.basis) 3259 e.basis = e.elements.pop(); 3260 if (t0 is null) 3261 return setError(); 3262 3263 e.type = t0.arrayOf(); 3264 e.type = e.type.typeSemantic(e.loc, sc); 3265 3266 /* Disallow array literals of type void being used. 3267 */ 3268 if (e.elements.length > 0 && t0.ty == Tvoid) 3269 { 3270 e.error("`%s` of type `%s` has no value", e.toChars(), e.type.toChars()); 3271 return setError(); 3272 } 3273 3274 if (global.params.useTypeInfo && Type.dtypeinfo) 3275 semanticTypeInfo(sc, e.type); 3276 3277 result = e; 3278 } 3279 3280 override void visit(AssocArrayLiteralExp e) 3281 { 3282 static if (LOGSEMANTIC) 3283 { 3284 printf("AssocArrayLiteralExp::semantic('%s')\n", e.toChars()); 3285 } 3286 if (e.type) 3287 { 3288 result = e; 3289 return; 3290 } 3291 3292 // Run semantic() on each element 3293 bool err_keys = arrayExpressionSemantic(e.keys.peekSlice(), sc); 3294 bool err_vals = arrayExpressionSemantic(e.values.peekSlice(), sc); 3295 if (err_keys || err_vals) 3296 return setError(); 3297 3298 expandTuples(e.keys); 3299 expandTuples(e.values); 3300 if (e.keys.length != e.values.length) 3301 { 3302 e.error("number of keys is %llu, must match number of values %llu", 3303 cast(ulong) e.keys.length, cast(ulong) e.values.length); 3304 return setError(); 3305 } 3306 3307 Type tkey = arrayExpressionToCommonType(sc, *e.keys); 3308 Type tvalue = arrayExpressionToCommonType(sc, *e.values); 3309 if (tkey is null || tvalue is null) 3310 return setError(); 3311 3312 e.type = new TypeAArray(tvalue, tkey); 3313 e.type = e.type.typeSemantic(e.loc, sc); 3314 3315 semanticTypeInfo(sc, e.type); 3316 3317 if (checkAssocArrayLiteralEscape(sc, e, false)) 3318 return setError(); 3319 3320 result = e; 3321 } 3322 3323 override void visit(StructLiteralExp e) 3324 { 3325 static if (LOGSEMANTIC) 3326 { 3327 printf("StructLiteralExp::semantic('%s')\n", e.toChars()); 3328 } 3329 if (e.type) 3330 { 3331 result = e; 3332 return; 3333 } 3334 3335 e.sd.size(e.loc); 3336 if (e.sd.sizeok != Sizeok.done) 3337 return setError(); 3338 3339 // run semantic() on each element 3340 if (arrayExpressionSemantic(e.elements.peekSlice(), sc)) 3341 return setError(); 3342 3343 expandTuples(e.elements); 3344 3345 /* Fit elements[] to the corresponding type of field[]. 3346 */ 3347 if (!e.sd.fit(e.loc, sc, e.elements, e.stype)) 3348 return setError(); 3349 3350 /* Fill out remainder of elements[] with default initializers for fields[] 3351 */ 3352 if (!e.sd.fill(e.loc, *e.elements, false)) 3353 { 3354 /* An error in the initializer needs to be recorded as an error 3355 * in the enclosing function or template, since the initializer 3356 * will be part of the stuct declaration. 3357 */ 3358 global.increaseErrorCount(); 3359 return setError(); 3360 } 3361 3362 if (checkFrameAccess(e.loc, sc, e.sd, e.elements.length)) 3363 return setError(); 3364 3365 e.type = e.stype ? e.stype : e.sd.type; 3366 result = e; 3367 } 3368 3369 override void visit(CompoundLiteralExp cle) 3370 { 3371 static if (LOGSEMANTIC) 3372 { 3373 printf("CompoundLiteralExp::semantic('%s')\n", cle.toChars()); 3374 } 3375 Type t = cle.type.typeSemantic(cle.loc, sc); 3376 auto init = initializerSemantic(cle.initializer, sc, t, INITnointerpret); 3377 auto e = initializerToExpression(init, t, (sc.flags & SCOPE.Cfile) != 0); 3378 if (!e) 3379 { 3380 error(cle.loc, "cannot convert initializer `%s` to expression", init.toChars()); 3381 return setError(); 3382 } 3383 result = e; 3384 return; 3385 } 3386 3387 override void visit(TypeExp exp) 3388 { 3389 if (exp.type.ty == Terror) 3390 return setError(); 3391 3392 //printf("TypeExp::semantic(%s)\n", exp.type.toChars()); 3393 Expression e; 3394 Type t; 3395 Dsymbol s; 3396 3397 dmd.typesem.resolve(exp.type, exp.loc, sc, e, t, s, true); 3398 if (e) 3399 { 3400 // `(Type)` is actually `(var)` so if `(var)` is a member requiring `this` 3401 // then rewrite as `(this.var)` in case it would be followed by a DotVar 3402 // to fix https://issues.dlang.org/show_bug.cgi?id=9490 3403 VarExp ve = e.isVarExp(); 3404 if (ve && ve.var && exp.parens && !ve.var.isStatic() && !(sc.stc & STC.static_) && 3405 sc.func && sc.func.needThis && ve.var.isMember2()) 3406 { 3407 // printf("apply fix for issue 9490: add `this.` to `%s`...\n", e.toChars()); 3408 e = new DotVarExp(exp.loc, new ThisExp(exp.loc), ve.var, false); 3409 } 3410 //printf("e = %s %s\n", Token.toChars(e.op), e.toChars()); 3411 e = e.expressionSemantic(sc); 3412 } 3413 else if (t) 3414 { 3415 //printf("t = %d %s\n", t.ty, t.toChars()); 3416 exp.type = t.typeSemantic(exp.loc, sc); 3417 e = exp; 3418 } 3419 else if (s) 3420 { 3421 //printf("s = %s %s\n", s.kind(), s.toChars()); 3422 e = symbolToExp(s, exp.loc, sc, true); 3423 } 3424 else 3425 assert(0); 3426 3427 exp.type.checkComplexTransition(exp.loc, sc); 3428 3429 result = e; 3430 } 3431 3432 override void visit(ScopeExp exp) 3433 { 3434 static if (LOGSEMANTIC) 3435 { 3436 printf("+ScopeExp::semantic(%p '%s')\n", exp, exp.toChars()); 3437 } 3438 if (exp.type) 3439 { 3440 result = exp; 3441 return; 3442 } 3443 3444 ScopeDsymbol sds2 = exp.sds; 3445 TemplateInstance ti = sds2.isTemplateInstance(); 3446 while (ti) 3447 { 3448 WithScopeSymbol withsym; 3449 if (!ti.findTempDecl(sc, &withsym) || !ti.semanticTiargs(sc)) 3450 return setError(); 3451 if (withsym && withsym.withstate.wthis) 3452 { 3453 Expression e = new VarExp(exp.loc, withsym.withstate.wthis); 3454 e = new DotTemplateInstanceExp(exp.loc, e, ti); 3455 result = e.expressionSemantic(sc); 3456 return; 3457 } 3458 if (ti.needsTypeInference(sc)) 3459 { 3460 if (TemplateDeclaration td = ti.tempdecl.isTemplateDeclaration()) 3461 { 3462 Dsymbol p = td.toParentLocal(); 3463 FuncDeclaration fdthis = hasThis(sc); 3464 AggregateDeclaration ad = p ? p.isAggregateDeclaration() : null; 3465 if (fdthis && ad && fdthis.isMemberLocal() == ad && (td._scope.stc & STC.static_) == 0) 3466 { 3467 Expression e = new DotTemplateInstanceExp(exp.loc, new ThisExp(exp.loc), ti); 3468 result = e.expressionSemantic(sc); 3469 return; 3470 } 3471 } 3472 else if (OverloadSet os = ti.tempdecl.isOverloadSet()) 3473 { 3474 FuncDeclaration fdthis = hasThis(sc); 3475 AggregateDeclaration ad = os.parent.isAggregateDeclaration(); 3476 if (fdthis && ad && fdthis.isMemberLocal() == ad) 3477 { 3478 Expression e = new DotTemplateInstanceExp(exp.loc, new ThisExp(exp.loc), ti); 3479 result = e.expressionSemantic(sc); 3480 return; 3481 } 3482 } 3483 // ti is an instance which requires IFTI. 3484 exp.sds = ti; 3485 exp.type = Type.tvoid; 3486 result = exp; 3487 return; 3488 } 3489 ti.dsymbolSemantic(sc); 3490 if (!ti.inst || ti.errors) 3491 return setError(); 3492 3493 Dsymbol s = ti.toAlias(); 3494 if (s == ti) 3495 { 3496 exp.sds = ti; 3497 exp.type = Type.tvoid; 3498 result = exp; 3499 return; 3500 } 3501 sds2 = s.isScopeDsymbol(); 3502 if (sds2) 3503 { 3504 ti = sds2.isTemplateInstance(); 3505 //printf("+ sds2 = %s, '%s'\n", sds2.kind(), sds2.toChars()); 3506 continue; 3507 } 3508 3509 if (auto v = s.isVarDeclaration()) 3510 { 3511 if (!v.type) 3512 { 3513 exp.error("forward reference of %s `%s`", v.kind(), v.toChars()); 3514 return setError(); 3515 } 3516 if ((v.storage_class & STC.manifest) && v._init) 3517 { 3518 /* When an instance that will be converted to a constant exists, 3519 * the instance representation "foo!tiargs" is treated like a 3520 * variable name, and its recursive appearance check (note that 3521 * it's equivalent with a recursive instantiation of foo) is done 3522 * separately from the circular initialization check for the 3523 * eponymous enum variable declaration. 3524 * 3525 * template foo(T) { 3526 * enum bool foo = foo; // recursive definition check (v.inuse) 3527 * } 3528 * template bar(T) { 3529 * enum bool bar = bar!T; // recursive instantiation check (ti.inuse) 3530 * } 3531 */ 3532 if (ti.inuse) 3533 { 3534 exp.error("recursive expansion of %s `%s`", ti.kind(), ti.toPrettyChars()); 3535 return setError(); 3536 } 3537 v.checkDeprecated(exp.loc, sc); 3538 auto e = v.expandInitializer(exp.loc); 3539 ti.inuse++; 3540 e = e.expressionSemantic(sc); 3541 ti.inuse--; 3542 result = e; 3543 return; 3544 } 3545 } 3546 3547 //printf("s = %s, '%s'\n", s.kind(), s.toChars()); 3548 auto e = symbolToExp(s, exp.loc, sc, true); 3549 //printf("-1ScopeExp::semantic()\n"); 3550 result = e; 3551 return; 3552 } 3553 3554 //printf("sds2 = %s, '%s'\n", sds2.kind(), sds2.toChars()); 3555 //printf("\tparent = '%s'\n", sds2.parent.toChars()); 3556 sds2.dsymbolSemantic(sc); 3557 3558 // (Aggregate|Enum)Declaration 3559 if (auto t = sds2.getType()) 3560 { 3561 result = (new TypeExp(exp.loc, t)).expressionSemantic(sc); 3562 return; 3563 } 3564 3565 if (auto td = sds2.isTemplateDeclaration()) 3566 { 3567 result = (new TemplateExp(exp.loc, td)).expressionSemantic(sc); 3568 return; 3569 } 3570 3571 exp.sds = sds2; 3572 exp.type = Type.tvoid; 3573 //printf("-2ScopeExp::semantic() %s\n", toChars()); 3574 result = exp; 3575 } 3576 3577 override void visit(NewExp exp) 3578 { 3579 static if (LOGSEMANTIC) 3580 { 3581 printf("NewExp::semantic() %s\n", exp.toChars()); 3582 if (exp.thisexp) 3583 printf("\tthisexp = %s\n", exp.thisexp.toChars()); 3584 printf("\tnewtype: %s\n", exp.newtype.toChars()); 3585 } 3586 if (exp.type) // if semantic() already run 3587 { 3588 result = exp; 3589 return; 3590 } 3591 3592 //for error messages if the argument in [] is not convertible to size_t 3593 const originalNewtype = exp.newtype; 3594 3595 // https://issues.dlang.org/show_bug.cgi?id=11581 3596 // With the syntax `new T[edim]` or `thisexp.new T[edim]`, 3597 // T should be analyzed first and edim should go into arguments iff it's 3598 // not a tuple. 3599 Expression edim = null; 3600 if (!exp.arguments && exp.newtype.isTypeSArray()) 3601 { 3602 auto ts = exp.newtype.isTypeSArray(); 3603 // check `new Value[Key]` 3604 ts.dim = ts.dim.expressionSemantic(sc); 3605 if (ts.dim.op == EXP.type) 3606 { 3607 exp.newtype = new TypeAArray(ts.next, ts.dim.isTypeExp().type); 3608 } 3609 else 3610 { 3611 edim = ts.dim; 3612 exp.newtype = ts.next; 3613 } 3614 } 3615 3616 ClassDeclaration cdthis = null; 3617 if (exp.thisexp) 3618 { 3619 exp.thisexp = exp.thisexp.expressionSemantic(sc); 3620 if (exp.thisexp.op == EXP.error) 3621 return setError(); 3622 3623 cdthis = exp.thisexp.type.isClassHandle(); 3624 if (!cdthis) 3625 { 3626 exp.error("`this` for nested class must be a class type, not `%s`", exp.thisexp.type.toChars()); 3627 return setError(); 3628 } 3629 3630 sc = sc.push(cdthis); 3631 exp.type = exp.newtype.typeSemantic(exp.loc, sc); 3632 sc = sc.pop(); 3633 } 3634 else 3635 { 3636 exp.type = exp.newtype.typeSemantic(exp.loc, sc); 3637 } 3638 if (exp.type.ty == Terror) 3639 return setError(); 3640 3641 if (edim) 3642 { 3643 if (exp.type.toBasetype().ty == Ttuple) 3644 { 3645 // --> new T[edim] 3646 exp.type = new TypeSArray(exp.type, edim); 3647 exp.type = exp.type.typeSemantic(exp.loc, sc); 3648 if (exp.type.ty == Terror) 3649 return setError(); 3650 } 3651 else 3652 { 3653 // --> new T[](edim) 3654 exp.arguments = new Expressions(); 3655 exp.arguments.push(edim); 3656 exp.type = exp.type.arrayOf(); 3657 } 3658 } 3659 3660 exp.newtype = exp.type; // in case type gets cast to something else 3661 Type tb = exp.type.toBasetype(); 3662 //printf("tb: %s, deco = %s\n", tb.toChars(), tb.deco); 3663 if (arrayExpressionSemantic(exp.arguments.peekSlice(), sc)) 3664 { 3665 return setError(); 3666 } 3667 if (preFunctionParameters(sc, exp.argumentList)) 3668 { 3669 return setError(); 3670 } 3671 3672 if (exp.thisexp && tb.ty != Tclass) 3673 { 3674 exp.error("`.new` is only for allocating nested classes, not `%s`", tb.toChars()); 3675 return setError(); 3676 } 3677 3678 const size_t nargs = exp.arguments ? exp.arguments.length : 0; 3679 Expression newprefix = null; 3680 3681 if (auto tc = tb.isTypeClass()) 3682 { 3683 auto cd = tc.sym; 3684 if (cd.errors) 3685 return setError(); 3686 cd.size(exp.loc); 3687 if (cd.sizeok != Sizeok.done) 3688 return setError(); 3689 if (!cd.ctor) 3690 cd.ctor = cd.searchCtor(); 3691 if (cd.noDefaultCtor && !nargs && !cd.defaultCtor) 3692 { 3693 exp.error("default construction is disabled for type `%s`", cd.type.toChars()); 3694 return setError(); 3695 } 3696 3697 if (cd.isInterfaceDeclaration()) 3698 { 3699 exp.error("cannot create instance of interface `%s`", cd.toChars()); 3700 return setError(); 3701 } 3702 3703 if (cd.isAbstract()) 3704 { 3705 exp.error("cannot create instance of abstract class `%s`", cd.toChars()); 3706 for (size_t i = 0; i < cd.vtbl.length; i++) 3707 { 3708 FuncDeclaration fd = cd.vtbl[i].isFuncDeclaration(); 3709 if (fd && fd.isAbstract()) 3710 { 3711 errorSupplemental(exp.loc, "function `%s` is not implemented", 3712 fd.toFullSignature()); 3713 } 3714 } 3715 return setError(); 3716 } 3717 // checkDeprecated() is already done in newtype.typeSemantic(). 3718 3719 if (cd.isNested()) 3720 { 3721 /* We need a 'this' pointer for the nested class. 3722 * Ensure we have the right one. 3723 */ 3724 Dsymbol s = cd.toParentLocal(); 3725 3726 //printf("cd isNested, parent = %s '%s'\n", s.kind(), s.toPrettyChars()); 3727 if (auto cdn = s.isClassDeclaration()) 3728 { 3729 if (!cdthis) 3730 { 3731 void noReferenceToOuterClass() 3732 { 3733 if (cd.isAnonymous) 3734 exp.error("cannot construct anonymous nested class because no implicit `this` reference to outer class is available"); 3735 else 3736 exp.error("cannot construct nested class `%s` because no implicit `this` reference to outer class `%s` is available", 3737 cd.toChars(), cdn.toChars()); 3738 return setError(); 3739 } 3740 3741 if (!sc.hasThis) 3742 return noReferenceToOuterClass(); 3743 3744 // Supply an implicit 'this' and try again 3745 exp.thisexp = new ThisExp(exp.loc); 3746 for (Dsymbol sp = sc.parent; 1; sp = sp.toParentLocal()) 3747 { 3748 if (!sp) 3749 return noReferenceToOuterClass(); 3750 ClassDeclaration cdp = sp.isClassDeclaration(); 3751 if (!cdp) 3752 continue; 3753 if (cdp == cdn || cdn.isBaseOf(cdp, null)) 3754 break; 3755 // Add a '.outer' and try again 3756 exp.thisexp = new DotIdExp(exp.loc, exp.thisexp, Id.outer); 3757 } 3758 3759 exp.thisexp = exp.thisexp.expressionSemantic(sc); 3760 if (exp.thisexp.op == EXP.error) 3761 return setError(); 3762 cdthis = exp.thisexp.type.isClassHandle(); 3763 } 3764 if (cdthis != cdn && !cdn.isBaseOf(cdthis, null)) 3765 { 3766 //printf("cdthis = %s\n", cdthis.toChars()); 3767 exp.error("`this` for nested class must be of type `%s`, not `%s`", 3768 cdn.toChars(), exp.thisexp.type.toChars()); 3769 return setError(); 3770 } 3771 if (!MODimplicitConv(exp.thisexp.type.mod, exp.newtype.mod)) 3772 { 3773 exp.error("nested type `%s` should have the same or weaker constancy as enclosing type `%s`", 3774 exp.newtype.toChars(), exp.thisexp.type.toChars()); 3775 return setError(); 3776 } 3777 } 3778 else if (exp.thisexp) 3779 { 3780 exp.error("`.new` is only for allocating nested classes"); 3781 return setError(); 3782 } 3783 else if (auto fdn = s.isFuncDeclaration()) 3784 { 3785 // make sure the parent context fdn of cd is reachable from sc 3786 if (!ensureStaticLinkTo(sc.parent, fdn)) 3787 { 3788 exp.error("outer function context of `%s` is needed to `new` nested class `%s`", 3789 fdn.toPrettyChars(), cd.toPrettyChars()); 3790 return setError(); 3791 } 3792 } 3793 else 3794 assert(0); 3795 } 3796 else if (exp.thisexp) 3797 { 3798 exp.error("`.new` is only for allocating nested classes"); 3799 return setError(); 3800 } 3801 3802 if (cd.vthis2) 3803 { 3804 if (AggregateDeclaration ad2 = cd.isMember2()) 3805 { 3806 Expression te = new ThisExp(exp.loc).expressionSemantic(sc); 3807 if (te.op != EXP.error) 3808 te = getRightThis(exp.loc, sc, ad2, te, cd); 3809 if (te.op == EXP.error) 3810 { 3811 exp.error("need `this` of type `%s` needed to `new` nested class `%s`", ad2.toChars(), cd.toChars()); 3812 return setError(); 3813 } 3814 } 3815 } 3816 3817 if (cd.disableNew && !exp.onstack) 3818 { 3819 exp.error("cannot allocate `class %s` with `new` because it is annotated with `@disable new()`", 3820 originalNewtype.toChars()); 3821 return setError(); 3822 } 3823 3824 if (cd.ctor) 3825 { 3826 FuncDeclaration f = resolveFuncCall(exp.loc, sc, cd.ctor, null, tb, exp.argumentList, FuncResolveFlag.standard); 3827 if (!f || f.errors) 3828 return setError(); 3829 3830 checkFunctionAttributes(exp, sc, f); 3831 checkAccess(cd, exp.loc, sc, f); 3832 3833 TypeFunction tf = f.type.isTypeFunction(); 3834 if (!exp.arguments) 3835 exp.arguments = new Expressions(); 3836 if (functionParameters(exp.loc, sc, tf, null, exp.type, exp.argumentList, f, &exp.type, &exp.argprefix)) 3837 return setError(); 3838 3839 exp.member = f.isCtorDeclaration(); 3840 assert(exp.member); 3841 } 3842 else 3843 { 3844 if (nargs) 3845 { 3846 exp.error("no constructor for `%s`", cd.toChars()); 3847 return setError(); 3848 } 3849 3850 // https://issues.dlang.org/show_bug.cgi?id=19941 3851 // Run semantic on all field initializers to resolve any forward 3852 // references. This is the same as done for structs in sd.fill(). 3853 for (ClassDeclaration c = cd; c; c = c.baseClass) 3854 { 3855 foreach (v; c.fields) 3856 { 3857 if (v.inuse || v._scope is null || v._init is null || 3858 v._init.isVoidInitializer()) 3859 continue; 3860 v.inuse++; 3861 v._init = v._init.initializerSemantic(v._scope, v.type, INITinterpret); 3862 v.inuse--; 3863 } 3864 } 3865 } 3866 3867 // When using `@nogc` exception handling, lower `throw new E(args)` to 3868 // `throw (__tmp = _d_newThrowable!E(), __tmp.__ctor(args), __tmp)`. 3869 if (global.params.ehnogc && exp.thrownew && 3870 !cd.isCOMclass() && !cd.isCPPclass()) 3871 { 3872 assert(cd.ctor); 3873 3874 Expression id = new IdentifierExp(exp.loc, Id.empty); 3875 id = new DotIdExp(exp.loc, id, Id.object); 3876 3877 auto tiargs = new Objects(); 3878 tiargs.push(exp.newtype); 3879 id = new DotTemplateInstanceExp(exp.loc, id, Id._d_newThrowable, tiargs); 3880 id = new CallExp(exp.loc, id).expressionSemantic(sc); 3881 3882 Expression idVal; 3883 Expression tmp = extractSideEffect(sc, "__tmpThrowable", idVal, id, true); 3884 // auto castTmp = new CastExp(exp.loc, tmp, exp.type); 3885 3886 auto ctor = new DotIdExp(exp.loc, tmp, Id.ctor).expressionSemantic(sc); 3887 auto ctorCall = new CallExp(exp.loc, ctor, exp.arguments); 3888 3889 id = Expression.combine(idVal, exp.argprefix).expressionSemantic(sc); 3890 id = Expression.combine(id, ctorCall).expressionSemantic(sc); 3891 // id = Expression.combine(id, castTmp).expressionSemantic(sc); 3892 3893 result = id.expressionSemantic(sc); 3894 return; 3895 } 3896 else if (sc.needsCodegen() && // interpreter doesn't need this lowered 3897 !exp.onstack && !exp.type.isscope()) // these won't use the GC 3898 { 3899 /* replace `new T(arguments)` with `core.lifetime._d_newclassT!T(arguments)` 3900 * or `_d_newclassTTrace` 3901 */ 3902 auto hook = global.params.tracegc ? Id._d_newclassTTrace : Id._d_newclassT; 3903 if (!verifyHookExist(exp.loc, *sc, hook, "new class")) 3904 return setError(); 3905 3906 Expression id = new IdentifierExp(exp.loc, Id.empty); 3907 id = new DotIdExp(exp.loc, id, Id.object); 3908 3909 auto tiargs = new Objects(); 3910 auto t = exp.newtype.unqualify(MODFlags.wild); // remove `inout` 3911 tiargs.push(t); 3912 id = new DotTemplateInstanceExp(exp.loc, id, hook, tiargs); 3913 auto arguments = new Expressions(); 3914 if (global.params.tracegc) 3915 { 3916 auto funcname = (sc.callsc && sc.callsc.func) ? 3917 sc.callsc.func.toPrettyChars() : sc.func.toPrettyChars(); 3918 arguments.push(new StringExp(exp.loc, exp.loc.filename.toDString())); 3919 arguments.push(new IntegerExp(exp.loc, exp.loc.linnum, Type.tint32)); 3920 arguments.push(new StringExp(exp.loc, funcname.toDString())); 3921 } 3922 id = new CallExp(exp.loc, id, arguments); 3923 3924 exp.lowering = id.expressionSemantic(sc); 3925 } 3926 } 3927 else if (auto ts = tb.isTypeStruct()) 3928 { 3929 auto sd = ts.sym; 3930 sd.size(exp.loc); 3931 if (sd.sizeok != Sizeok.done) 3932 return setError(); 3933 if (!sd.ctor) 3934 sd.ctor = sd.searchCtor(); 3935 if (sd.noDefaultCtor && !nargs) 3936 { 3937 exp.error("default construction is disabled for type `%s`", sd.type.toChars()); 3938 return setError(); 3939 } 3940 // checkDeprecated() is already done in newtype.typeSemantic(). 3941 3942 if (sd.disableNew) 3943 { 3944 exp.error("cannot allocate `struct %s` with `new` because it is annotated with `@disable new()`", 3945 originalNewtype.toChars()); 3946 return setError(); 3947 } 3948 3949 // https://issues.dlang.org/show_bug.cgi?id=22639 3950 // If the new expression has arguments, we either should call a 3951 // regular constructor of a copy constructor if the first argument 3952 // is the same type as the struct 3953 if (nargs && (sd.hasRegularCtor() || (sd.ctor && (*exp.arguments)[0].type.mutableOf() == sd.type.mutableOf()))) 3954 { 3955 FuncDeclaration f = resolveFuncCall(exp.loc, sc, sd.ctor, null, tb, exp.argumentList, FuncResolveFlag.standard); 3956 if (!f || f.errors) 3957 return setError(); 3958 3959 checkFunctionAttributes(exp, sc, f); 3960 checkAccess(sd, exp.loc, sc, f); 3961 3962 TypeFunction tf = f.type.isTypeFunction(); 3963 if (!exp.arguments) 3964 exp.arguments = new Expressions(); 3965 if (functionParameters(exp.loc, sc, tf, null, exp.type, exp.argumentList, f, &exp.type, &exp.argprefix)) 3966 return setError(); 3967 3968 exp.member = f.isCtorDeclaration(); 3969 assert(exp.member); 3970 3971 if (checkFrameAccess(exp.loc, sc, sd, sd.fields.length)) 3972 return setError(); 3973 } 3974 else 3975 { 3976 if (exp.names) 3977 { 3978 exp.arguments = resolveStructLiteralNamedArgs(sd, exp.type, sc, exp.loc, 3979 exp.names ? (*exp.names)[] : null, 3980 (size_t i, Type t) => (*exp.arguments)[i], 3981 i => (*exp.arguments)[i].loc 3982 ); 3983 if (!exp.arguments) 3984 return setError(); 3985 } 3986 else if (!exp.arguments) 3987 { 3988 exp.arguments = new Expressions(); 3989 } 3990 3991 if (!sd.fit(exp.loc, sc, exp.arguments, tb)) 3992 return setError(); 3993 3994 if (!sd.fill(exp.loc, *exp.arguments, false)) 3995 return setError(); 3996 3997 if (checkFrameAccess(exp.loc, sc, sd, exp.arguments ? exp.arguments.length : 0)) 3998 return setError(); 3999 4000 /* Since a `new` allocation may escape, check each of the arguments for escaping 4001 */ 4002 foreach (arg; *exp.arguments) 4003 { 4004 if (arg && checkNewEscape(sc, arg, false)) 4005 return setError(); 4006 } 4007 } 4008 4009 exp.type = exp.type.pointerTo(); 4010 } 4011 else if (tb.ty == Tarray) 4012 { 4013 if (!nargs) 4014 { 4015 // https://issues.dlang.org/show_bug.cgi?id=20422 4016 // Without this check the compiler would give a misleading error 4017 exp.error("missing length argument for array"); 4018 return setError(); 4019 } 4020 4021 Type tn = tb.nextOf().baseElemOf(); 4022 Dsymbol s = tn.toDsymbol(sc); 4023 AggregateDeclaration ad = s ? s.isAggregateDeclaration() : null; 4024 if (ad && ad.noDefaultCtor) 4025 { 4026 exp.error("default construction is disabled for type `%s`", tb.nextOf().toChars()); 4027 return setError(); 4028 } 4029 for (size_t i = 0; i < nargs; i++) 4030 { 4031 if (tb.ty != Tarray) 4032 { 4033 exp.error("too many arguments for array"); 4034 return setError(); 4035 } 4036 4037 Expression arg = (*exp.arguments)[i]; 4038 if (exp.names && (*exp.names)[i]) 4039 { 4040 exp.error("no named argument `%s` allowed for array dimension", (*exp.names)[i].toChars()); 4041 return setError(); 4042 } 4043 4044 arg = resolveProperties(sc, arg); 4045 arg = arg.implicitCastTo(sc, Type.tsize_t); 4046 if (arg.op == EXP.error) 4047 return setError(); 4048 arg = arg.optimize(WANTvalue); 4049 if (arg.op == EXP.int64 && cast(sinteger_t)arg.toInteger() < 0) 4050 { 4051 exp.error("negative array index `%s`", arg.toChars()); 4052 return setError(); 4053 } 4054 (*exp.arguments)[i] = arg; 4055 tb = tb.isTypeDArray().next.toBasetype(); 4056 } 4057 } 4058 else if (tb.isscalar()) 4059 { 4060 if (!nargs) 4061 { 4062 } 4063 else if (nargs == 1) 4064 { 4065 if (exp.names && (*exp.names)[0]) 4066 { 4067 exp.error("no named argument `%s` allowed for scalar", (*exp.names)[0].toChars()); 4068 return setError(); 4069 } 4070 Expression e = (*exp.arguments)[0]; 4071 e = e.implicitCastTo(sc, tb); 4072 (*exp.arguments)[0] = e; 4073 } 4074 else 4075 { 4076 exp.error("more than one argument for construction of `%s`", exp.type.toChars()); 4077 return setError(); 4078 } 4079 4080 exp.type = exp.type.pointerTo(); 4081 } 4082 else if (tb.ty == Taarray) 4083 { 4084 // e.g. `new Alias(args)` 4085 if (nargs) 4086 { 4087 exp.error("`new` cannot take arguments for an associative array"); 4088 return setError(); 4089 } 4090 } 4091 else 4092 { 4093 exp.error("cannot create a `%s` with `new`", exp.type.toChars()); 4094 return setError(); 4095 } 4096 4097 //printf("NewExp: '%s'\n", toChars()); 4098 //printf("NewExp:type '%s'\n", type.toChars()); 4099 semanticTypeInfo(sc, exp.type); 4100 4101 if (newprefix) 4102 { 4103 result = Expression.combine(newprefix, exp); 4104 return; 4105 } 4106 result = exp; 4107 } 4108 4109 override void visit(NewAnonClassExp e) 4110 { 4111 static if (LOGSEMANTIC) 4112 { 4113 printf("NewAnonClassExp::semantic() %s\n", e.toChars()); 4114 //printf("thisexp = %p\n", thisexp); 4115 //printf("type: %s\n", type.toChars()); 4116 } 4117 4118 Expression d = new DeclarationExp(e.loc, e.cd); 4119 sc = sc.push(); // just create new scope 4120 sc.flags &= ~SCOPE.ctfe; // temporary stop CTFE 4121 d = d.expressionSemantic(sc); 4122 sc = sc.pop(); 4123 4124 if (!e.cd.errors && sc.intypeof && !sc.parent.inNonRoot()) 4125 { 4126 ScopeDsymbol sds = sc.tinst ? cast(ScopeDsymbol)sc.tinst : sc._module; 4127 if (!sds.members) 4128 sds.members = new Dsymbols(); 4129 sds.members.push(e.cd); 4130 } 4131 4132 Expression n = new NewExp(e.loc, e.thisexp, e.cd.type, e.arguments); 4133 4134 Expression c = new CommaExp(e.loc, d, n); 4135 result = c.expressionSemantic(sc); 4136 } 4137 4138 override void visit(SymOffExp e) 4139 { 4140 static if (LOGSEMANTIC) 4141 { 4142 printf("SymOffExp::semantic('%s')\n", e.toChars()); 4143 } 4144 //var.dsymbolSemantic(sc); 4145 if (!e.type) 4146 e.type = e.var.type.pointerTo(); 4147 4148 if (auto v = e.var.isVarDeclaration()) 4149 { 4150 if (v.checkNestedReference(sc, e.loc)) 4151 return setError(); 4152 } 4153 else if (auto f = e.var.isFuncDeclaration()) 4154 { 4155 if (f.checkNestedReference(sc, e.loc)) 4156 return setError(); 4157 } 4158 4159 result = e; 4160 } 4161 4162 override void visit(VarExp e) 4163 { 4164 static if (LOGSEMANTIC) 4165 { 4166 printf("VarExp::semantic(%s)\n", e.toChars()); 4167 } 4168 4169 auto vd = e.var.isVarDeclaration(); 4170 auto fd = e.var.isFuncDeclaration(); 4171 4172 if (fd) 4173 { 4174 //printf("L%d fd = %s\n", __LINE__, f.toChars()); 4175 if (!fd.functionSemantic()) 4176 return setError(); 4177 } 4178 4179 if (!e.type) 4180 e.type = e.var.type; 4181 if (e.type && !e.type.deco) 4182 { 4183 auto decl = e.var.isDeclaration(); 4184 if (decl) 4185 decl.inuse++; 4186 e.type = e.type.typeSemantic(e.loc, sc); 4187 if (decl) 4188 decl.inuse--; 4189 } 4190 4191 /* Fix for 1161 doesn't work because it causes visibility 4192 * problems when instantiating imported templates passing private 4193 * variables as alias template parameters. 4194 */ 4195 //checkAccess(loc, sc, NULL, var); 4196 4197 if (vd) 4198 { 4199 if (vd.checkNestedReference(sc, e.loc)) 4200 return setError(); 4201 4202 // https://issues.dlang.org/show_bug.cgi?id=12025 4203 // If the variable is not actually used in runtime code, 4204 // the purity violation error is redundant. 4205 //checkPurity(sc, vd); 4206 } 4207 else if (fd) 4208 { 4209 // TODO: If fd isn't yet resolved its overload, the checkNestedReference 4210 // call would cause incorrect validation. 4211 // Maybe here should be moved in CallExp, or AddrExp for functions. 4212 if (fd.checkNestedReference(sc, e.loc)) 4213 return setError(); 4214 } 4215 else if (auto od = e.var.isOverDeclaration()) 4216 { 4217 e.type = Type.tvoid; // ambiguous type? 4218 } 4219 4220 result = e; 4221 } 4222 4223 override void visit(FuncExp exp) 4224 { 4225 static if (LOGSEMANTIC) 4226 { 4227 printf("FuncExp::semantic(%s)\n", exp.toChars()); 4228 if (exp.fd.treq) 4229 printf(" treq = %s\n", exp.fd.treq.toChars()); 4230 } 4231 4232 if (exp.type) 4233 { 4234 result = exp; 4235 return; 4236 } 4237 4238 Expression e = exp; 4239 uint olderrors; 4240 4241 sc = sc.push(); // just create new scope 4242 sc.flags &= ~SCOPE.ctfe; // temporary stop CTFE 4243 sc.visibility = Visibility(Visibility.Kind.public_); // https://issues.dlang.org/show_bug.cgi?id=12506 4244 4245 /* fd.treq might be incomplete type, 4246 * so should not semantic it. 4247 * void foo(T)(T delegate(int) dg){} 4248 * foo(a=>a); // in IFTI, treq == T delegate(int) 4249 */ 4250 //if (fd.treq) 4251 // fd.treq = fd.treq.dsymbolSemantic(loc, sc); 4252 4253 exp.genIdent(sc); 4254 4255 // Set target of return type inference 4256 if (exp.fd.treq && !exp.fd.type.nextOf()) 4257 { 4258 TypeFunction tfv = null; 4259 if (exp.fd.treq.ty == Tdelegate || exp.fd.treq.isPtrToFunction()) 4260 tfv = cast(TypeFunction)exp.fd.treq.nextOf(); 4261 if (tfv) 4262 { 4263 TypeFunction tfl = cast(TypeFunction)exp.fd.type; 4264 tfl.next = tfv.nextOf(); 4265 } 4266 } 4267 4268 //printf("td = %p, treq = %p\n", td, fd.treq); 4269 if (exp.td) 4270 { 4271 assert(exp.td.parameters && exp.td.parameters.length); 4272 exp.td.dsymbolSemantic(sc); 4273 exp.type = Type.tvoid; // temporary type 4274 4275 if (exp.fd.treq) // defer type determination 4276 { 4277 FuncExp fe; 4278 if (exp.matchType(exp.fd.treq, sc, &fe) > MATCH.nomatch) 4279 e = fe; 4280 else 4281 e = ErrorExp.get(); 4282 } 4283 goto Ldone; 4284 } 4285 4286 olderrors = global.errors; 4287 exp.fd.dsymbolSemantic(sc); 4288 if (olderrors == global.errors) 4289 { 4290 exp.fd.semantic2(sc); 4291 if (olderrors == global.errors) 4292 exp.fd.semantic3(sc); 4293 } 4294 if (olderrors != global.errors) 4295 { 4296 if (exp.fd.type && exp.fd.type.ty == Tfunction && !exp.fd.type.nextOf()) 4297 (cast(TypeFunction)exp.fd.type).next = Type.terror; 4298 e = ErrorExp.get(); 4299 goto Ldone; 4300 } 4301 4302 // Type is a "delegate to" or "pointer to" the function literal 4303 if ((exp.fd.isNested() && exp.fd.tok == TOK.delegate_) || (exp.tok == TOK.reserved && exp.fd.treq && exp.fd.treq.ty == Tdelegate)) 4304 { 4305 // https://issues.dlang.org/show_bug.cgi?id=22686 4306 // if the delegate return type is an error 4307 // abort semantic of the FuncExp and propagate 4308 // the error 4309 if (exp.fd.type.isTypeError()) 4310 { 4311 e = ErrorExp.get(); 4312 goto Ldone; 4313 } 4314 exp.type = new TypeDelegate(exp.fd.type.isTypeFunction()); 4315 exp.type = exp.type.typeSemantic(exp.loc, sc); 4316 4317 exp.fd.tok = TOK.delegate_; 4318 } 4319 else 4320 { 4321 exp.type = new TypePointer(exp.fd.type); 4322 exp.type = exp.type.typeSemantic(exp.loc, sc); 4323 //type = fd.type.pointerTo(); 4324 4325 /* A lambda expression deduced to function pointer might become 4326 * to a delegate literal implicitly. 4327 * 4328 * auto foo(void function() fp) { return 1; } 4329 * assert(foo({}) == 1); 4330 * 4331 * So, should keep fd.tok == TOK.reserve if fd.treq == NULL. 4332 */ 4333 if (exp.fd.treq && exp.fd.treq.ty == Tpointer) 4334 { 4335 // change to non-nested 4336 exp.fd.tok = TOK.function_; 4337 exp.fd.vthis = null; 4338 } 4339 } 4340 exp.fd.tookAddressOf++; 4341 4342 Ldone: 4343 sc = sc.pop(); 4344 result = e; 4345 } 4346 4347 /** 4348 * Perform semantic analysis on function literals 4349 * 4350 * Test the following construct: 4351 * --- 4352 * (x, y, z) { return x + y + z; }(42, 84, 1992); 4353 * --- 4354 */ 4355 Expression callExpSemantic(FuncExp exp, Scope* sc, Expressions* arguments) 4356 { 4357 if ((!exp.type || exp.type == Type.tvoid) && exp.td && arguments && arguments.length) 4358 { 4359 for (size_t k = 0; k < arguments.length; k++) 4360 { 4361 Expression checkarg = (*arguments)[k]; 4362 if (checkarg.op == EXP.error) 4363 return checkarg; 4364 } 4365 4366 exp.genIdent(sc); 4367 4368 assert(exp.td.parameters && exp.td.parameters.length); 4369 exp.td.dsymbolSemantic(sc); 4370 4371 TypeFunction tfl = cast(TypeFunction)exp.fd.type; 4372 size_t dim = tfl.parameterList.length; 4373 if (arguments.length < dim) 4374 { 4375 // Default arguments are always typed, so they don't need inference. 4376 Parameter p = tfl.parameterList[arguments.length]; 4377 if (p.defaultArg) 4378 dim = arguments.length; 4379 } 4380 4381 if ((tfl.parameterList.varargs == VarArg.none && arguments.length > dim) || 4382 arguments.length < dim) 4383 { 4384 OutBuffer buf; 4385 foreach (idx, ref arg; *arguments) 4386 buf.printf("%s%s", (idx ? ", ".ptr : "".ptr), arg.type.toChars()); 4387 exp.error("function literal `%s%s` is not callable using argument types `(%s)`", 4388 exp.fd.toChars(), parametersTypeToChars(tfl.parameterList), 4389 buf.peekChars()); 4390 exp.errorSupplemental("too %s arguments, expected %d, got %d", 4391 arguments.length < dim ? "few".ptr : "many".ptr, 4392 cast(int)dim, cast(int)arguments.length); 4393 return ErrorExp.get(); 4394 } 4395 4396 auto tiargs = new Objects(); 4397 tiargs.reserve(exp.td.parameters.length); 4398 4399 for (size_t i = 0; i < exp.td.parameters.length; i++) 4400 { 4401 TemplateParameter tp = (*exp.td.parameters)[i]; 4402 assert(dim <= tfl.parameterList.length); 4403 foreach (u, p; tfl.parameterList) 4404 { 4405 if (u == dim) 4406 break; 4407 4408 if (p.type.ty == Tident && (cast(TypeIdentifier)p.type).ident == tp.ident) 4409 { 4410 Expression e = (*arguments)[u]; 4411 tiargs.push(e.type); 4412 break; 4413 } 4414 } 4415 } 4416 4417 auto ti = new TemplateInstance(exp.loc, exp.td, tiargs); 4418 return (new ScopeExp(exp.loc, ti)).expressionSemantic(sc); 4419 } 4420 return exp.expressionSemantic(sc); 4421 } 4422 4423 override void visit(CallExp exp) 4424 { 4425 static if (LOGSEMANTIC) 4426 { 4427 printf("CallExp::semantic() %s\n", exp.toChars()); 4428 } 4429 if (exp.type) 4430 { 4431 result = exp; 4432 return; // semantic() already run 4433 } 4434 4435 Objects* tiargs = null; // initial list of template arguments 4436 Expression ethis = null; 4437 Type tthis = null; 4438 Expression e1org = exp.e1; 4439 4440 if (auto ce = exp.e1.isCommaExp()) 4441 { 4442 /* Rewrite (a,b)(args) as (a,(b(args))) 4443 */ 4444 exp.e1 = ce.e2; 4445 ce.e2 = exp; 4446 result = ce.expressionSemantic(sc); 4447 return; 4448 } 4449 if (DelegateExp de = exp.e1.isDelegateExp()) 4450 { 4451 exp.e1 = new DotVarExp(de.loc, de.e1, de.func, de.hasOverloads); 4452 visit(exp); 4453 return; 4454 } 4455 if (FuncExp fe = exp.e1.isFuncExp()) 4456 { 4457 if (arrayExpressionSemantic(exp.arguments.peekSlice(), sc) || 4458 preFunctionParameters(sc, exp.argumentList)) 4459 return setError(); 4460 4461 // Run e1 semantic even if arguments have any errors 4462 exp.e1 = callExpSemantic(fe, sc, exp.arguments); 4463 if (exp.e1.op == EXP.error) 4464 { 4465 result = exp.e1; 4466 return; 4467 } 4468 } 4469 if (sc.flags & SCOPE.Cfile) 4470 { 4471 /* See if need to rewrite the AST because of cast/call ambiguity 4472 */ 4473 if (auto e = castCallAmbiguity(exp, sc)) 4474 { 4475 result = expressionSemantic(e, sc); 4476 return; 4477 } 4478 } 4479 4480 if (Expression ex = resolveUFCS(sc, exp)) 4481 { 4482 result = ex; 4483 return; 4484 } 4485 4486 /* This recognizes: 4487 * foo!(tiargs)(funcargs) 4488 */ 4489 if (ScopeExp se = exp.e1.isScopeExp()) 4490 { 4491 TemplateInstance ti = se.sds.isTemplateInstance(); 4492 if (ti) 4493 { 4494 /* Attempt to instantiate ti. If that works, go with it. 4495 * If not, go with partial explicit specialization. 4496 */ 4497 WithScopeSymbol withsym; 4498 if (!ti.findTempDecl(sc, &withsym) || !ti.semanticTiargs(sc)) 4499 return setError(); 4500 if (withsym && withsym.withstate.wthis) 4501 { 4502 exp.e1 = new VarExp(exp.e1.loc, withsym.withstate.wthis); 4503 exp.e1 = new DotTemplateInstanceExp(exp.e1.loc, exp.e1, ti); 4504 goto Ldotti; 4505 } 4506 if (ti.needsTypeInference(sc, 1)) 4507 { 4508 /* Go with partial explicit specialization 4509 */ 4510 tiargs = ti.tiargs; 4511 assert(ti.tempdecl); 4512 if (TemplateDeclaration td = ti.tempdecl.isTemplateDeclaration()) 4513 exp.e1 = new TemplateExp(exp.loc, td); 4514 else if (OverDeclaration od = ti.tempdecl.isOverDeclaration()) 4515 exp.e1 = new VarExp(exp.loc, od); 4516 else 4517 exp.e1 = new OverExp(exp.loc, ti.tempdecl.isOverloadSet()); 4518 } 4519 else 4520 { 4521 Expression e1x = exp.e1.expressionSemantic(sc); 4522 if (e1x.op == EXP.error) 4523 { 4524 result = e1x; 4525 return; 4526 } 4527 exp.e1 = e1x; 4528 } 4529 } 4530 } 4531 4532 /* This recognizes: 4533 * expr.foo!(tiargs)(funcargs) 4534 */ 4535 Ldotti: 4536 if (DotTemplateInstanceExp se = exp.e1.isDotTemplateInstanceExp()) 4537 { 4538 TemplateInstance ti = se.ti; 4539 { 4540 /* Attempt to instantiate ti. If that works, go with it. 4541 * If not, go with partial explicit specialization. 4542 */ 4543 if (!se.findTempDecl(sc) || !ti.semanticTiargs(sc)) 4544 return setError(); 4545 if (ti.needsTypeInference(sc, 1)) 4546 { 4547 /* Go with partial explicit specialization 4548 */ 4549 tiargs = ti.tiargs; 4550 assert(ti.tempdecl); 4551 if (TemplateDeclaration td = ti.tempdecl.isTemplateDeclaration()) 4552 exp.e1 = new DotTemplateExp(exp.loc, se.e1, td); 4553 else if (OverDeclaration od = ti.tempdecl.isOverDeclaration()) 4554 { 4555 exp.e1 = new DotVarExp(exp.loc, se.e1, od, true); 4556 } 4557 else 4558 exp.e1 = new DotExp(exp.loc, se.e1, new OverExp(exp.loc, ti.tempdecl.isOverloadSet())); 4559 } 4560 else 4561 { 4562 Expression e1x = exp.e1.expressionSemantic(sc); 4563 if (e1x.op == EXP.error) 4564 { 4565 result = e1x; 4566 return; 4567 } 4568 exp.e1 = e1x; 4569 } 4570 } 4571 } 4572 4573 Type att = null; 4574 Lagain: 4575 //printf("Lagain: %s\n", toChars()); 4576 exp.f = null; 4577 if (exp.e1.op == EXP.this_ || exp.e1.op == EXP.super_) 4578 { 4579 // semantic() run later for these 4580 } 4581 else 4582 { 4583 if (DotIdExp die = exp.e1.isDotIdExp()) 4584 { 4585 exp.e1 = die.expressionSemantic(sc); 4586 /* Look for e1 having been rewritten to expr.opDispatch!(string) 4587 * We handle such earlier, so go back. 4588 * Note that in the rewrite, we carefully did not run semantic() on e1 4589 */ 4590 if (exp.e1.op == EXP.dotTemplateInstance) 4591 { 4592 goto Ldotti; 4593 } 4594 } 4595 else 4596 { 4597 __gshared int nest; 4598 if (++nest > global.recursionLimit) 4599 { 4600 exp.error("recursive evaluation of `%s`", exp.toChars()); 4601 --nest; 4602 return setError(); 4603 } 4604 Expression ex = unaSemantic(exp, sc); 4605 --nest; 4606 if (ex) 4607 { 4608 result = ex; 4609 return; 4610 } 4611 } 4612 4613 /* Look for e1 being a lazy parameter 4614 */ 4615 if (VarExp ve = exp.e1.isVarExp()) 4616 { 4617 if (ve.var.storage_class & STC.lazy_) 4618 { 4619 // lazy parameters can be called without violating purity and safety 4620 Type tw = ve.var.type; 4621 Type tc = ve.var.type.substWildTo(MODFlags.const_); 4622 auto tf = new TypeFunction(ParameterList(), tc, LINK.d, STC.safe | STC.pure_); 4623 (tf = cast(TypeFunction)tf.typeSemantic(exp.loc, sc)).next = tw; // hack for bug7757 4624 auto t = new TypeDelegate(tf); 4625 ve.type = t.typeSemantic(exp.loc, sc); 4626 } 4627 VarDeclaration v = ve.var.isVarDeclaration(); 4628 if (v && ve.checkPurity(sc, v)) 4629 return setError(); 4630 } 4631 4632 if (exp.e1.op == EXP.symbolOffset && (cast(SymOffExp)exp.e1).hasOverloads) 4633 { 4634 SymOffExp se = cast(SymOffExp)exp.e1; 4635 exp.e1 = new VarExp(se.loc, se.var, true); 4636 exp.e1 = exp.e1.expressionSemantic(sc); 4637 } 4638 else if (DotExp de = exp.e1.isDotExp()) 4639 { 4640 if (de.e2.op == EXP.overloadSet) 4641 { 4642 ethis = de.e1; 4643 tthis = de.e1.type; 4644 exp.e1 = de.e2; 4645 } 4646 } 4647 else if (exp.e1.op == EXP.star && exp.e1.type.ty == Tfunction) 4648 { 4649 // Rewrite (*fp)(arguments) to fp(arguments) 4650 exp.e1 = (cast(PtrExp)exp.e1).e1; 4651 } 4652 else if (exp.e1.op == EXP.type && (sc && sc.flags & SCOPE.Cfile)) 4653 { 4654 const numArgs = exp.arguments ? exp.arguments.length : 0; 4655 4656 /* Ambiguous cases arise from CParser where there is not enough 4657 * information to determine if we have a function call or declaration. 4658 * type-name ( identifier ) ; 4659 * identifier ( identifier ) ; 4660 * If exp.e1 is a type-name, then this is a declaration. C11 does not 4661 * have type construction syntax, so don't convert this to a cast(). 4662 */ 4663 if (numArgs == 1) 4664 { 4665 Expression arg = (*exp.arguments)[0]; 4666 if (auto ie = (*exp.arguments)[0].isIdentifierExp()) 4667 { 4668 TypeExp te = cast(TypeExp)exp.e1; 4669 auto initializer = new VoidInitializer(ie.loc); 4670 Dsymbol s = new VarDeclaration(ie.loc, te.type, ie.ident, initializer); 4671 auto decls = new Dsymbols(1); 4672 (*decls)[0] = s; 4673 s = new LinkDeclaration(s.loc, LINK.c, decls); 4674 result = new DeclarationExp(exp.loc, s); 4675 result = result.expressionSemantic(sc); 4676 } 4677 else 4678 { 4679 arg.error("identifier or `(` expected"); 4680 result = ErrorExp.get(); 4681 } 4682 return; 4683 } 4684 exp.error("identifier or `(` expected before `)`"); 4685 result = ErrorExp.get(); 4686 return; 4687 } 4688 } 4689 4690 Type t1 = exp.e1.type ? exp.e1.type.toBasetype() : null; 4691 4692 if (exp.e1.op == EXP.error) 4693 { 4694 result = exp.e1; 4695 return; 4696 } 4697 if (arrayExpressionSemantic(exp.arguments.peekSlice(), sc) || 4698 preFunctionParameters(sc, exp.argumentList)) 4699 return setError(); 4700 4701 // Check for call operator overload 4702 if (t1) 4703 { 4704 if (t1.ty == Tstruct) 4705 { 4706 auto sd = (cast(TypeStruct)t1).sym; 4707 sd.size(exp.loc); // Resolve forward references to construct object 4708 if (sd.sizeok != Sizeok.done) 4709 return setError(); 4710 if (!sd.ctor) 4711 sd.ctor = sd.searchCtor(); 4712 /* If `sd.ctor` is a generated copy constructor, this means that it 4713 is the single constructor that this struct has. In order to not 4714 disable default construction, the ctor is nullified. The side effect 4715 of this is that the generated copy constructor cannot be called 4716 explicitly, but that is ok, because when calling a constructor the 4717 default constructor should have priority over the generated copy 4718 constructor. 4719 */ 4720 if (sd.ctor) 4721 { 4722 auto ctor = sd.ctor.isCtorDeclaration(); 4723 if (ctor && ctor.isCpCtor && ctor.isGenerated()) 4724 sd.ctor = null; 4725 } 4726 4727 // First look for constructor 4728 if (exp.e1.op == EXP.type && sd.ctor) 4729 { 4730 if (!sd.noDefaultCtor && !(exp.arguments && exp.arguments.length)) 4731 goto Lx; 4732 4733 /* https://issues.dlang.org/show_bug.cgi?id=20695 4734 If all constructors are copy constructors, then 4735 try default construction. 4736 */ 4737 if (!sd.hasRegularCtor && 4738 // https://issues.dlang.org/show_bug.cgi?id=22639 4739 // we might still have a copy constructor that could be called 4740 (*exp.arguments)[0].type.mutableOf != sd.type.mutableOf()) 4741 goto Lx; 4742 4743 auto sle = new StructLiteralExp(exp.loc, sd, null, exp.e1.type); 4744 if (!sd.fill(exp.loc, *sle.elements, true)) 4745 return setError(); 4746 if (checkFrameAccess(exp.loc, sc, sd, sle.elements.length)) 4747 return setError(); 4748 4749 // https://issues.dlang.org/show_bug.cgi?id=14556 4750 // Set concrete type to avoid further redundant semantic(). 4751 sle.type = exp.e1.type; 4752 4753 /* Constructor takes a mutable object, so don't use 4754 * the immutable initializer symbol. 4755 */ 4756 sle.useStaticInit = false; 4757 4758 Expression e = sle; 4759 if (auto cf = sd.ctor.isCtorDeclaration()) 4760 { 4761 e = new DotVarExp(exp.loc, e, cf, true); 4762 } 4763 else if (auto td = sd.ctor.isTemplateDeclaration()) 4764 { 4765 e = new DotIdExp(exp.loc, e, td.ident); 4766 } 4767 else if (auto os = sd.ctor.isOverloadSet()) 4768 { 4769 e = new DotExp(exp.loc, e, new OverExp(exp.loc, os)); 4770 } 4771 else 4772 assert(0); 4773 e = new CallExp(exp.loc, e, exp.arguments); 4774 e = e.expressionSemantic(sc); 4775 result = e; 4776 return; 4777 } 4778 // No constructor, look for overload of opCall 4779 if (search_function(sd, Id.call)) 4780 goto L1; 4781 // overload of opCall, therefore it's a call 4782 if (exp.e1.op != EXP.type) 4783 { 4784 if (sd.aliasthis && !isRecursiveAliasThis(att, exp.e1.type)) 4785 { 4786 exp.e1 = resolveAliasThis(sc, exp.e1); 4787 goto Lagain; 4788 } 4789 exp.error("%s `%s` does not overload ()", sd.kind(), sd.toChars()); 4790 return setError(); 4791 } 4792 4793 /* It's a struct literal 4794 */ 4795 Lx: 4796 Expressions* resolvedArgs = exp.arguments; 4797 if (exp.names) 4798 { 4799 resolvedArgs = resolveStructLiteralNamedArgs(sd, exp.e1.type, sc, exp.loc, 4800 (*exp.names)[], 4801 (size_t i, Type t) => (*exp.arguments)[i], 4802 i => (*exp.arguments)[i].loc 4803 ); 4804 if (!resolvedArgs) 4805 { 4806 result = ErrorExp.get(); 4807 return; 4808 } 4809 } 4810 4811 Expression e = new StructLiteralExp(exp.loc, sd, resolvedArgs, exp.e1.type); 4812 e = e.expressionSemantic(sc); 4813 result = e; 4814 return; 4815 } 4816 else if (t1.ty == Tclass) 4817 { 4818 L1: 4819 // Rewrite as e1.call(arguments) 4820 Expression e = new DotIdExp(exp.loc, exp.e1, Id.call); 4821 e = new CallExp(exp.loc, e, exp.arguments, exp.names); 4822 e = e.expressionSemantic(sc); 4823 result = e; 4824 return; 4825 } 4826 else if (exp.e1.op == EXP.type && t1.isscalar()) 4827 { 4828 Expression e; 4829 4830 // Make sure to use the enum type itself rather than its 4831 // base type 4832 // https://issues.dlang.org/show_bug.cgi?id=16346 4833 if (exp.e1.type.ty == Tenum) 4834 { 4835 t1 = exp.e1.type; 4836 } 4837 4838 if (!exp.arguments || exp.arguments.length == 0) 4839 { 4840 e = t1.defaultInitLiteral(exp.loc); 4841 } 4842 else if (exp.arguments.length == 1) 4843 { 4844 e = (*exp.arguments)[0]; 4845 e = e.implicitCastTo(sc, t1); 4846 e = new CastExp(exp.loc, e, t1); 4847 } 4848 else 4849 { 4850 exp.error("more than one argument for construction of `%s`", t1.toChars()); 4851 return setError(); 4852 } 4853 e = e.expressionSemantic(sc); 4854 result = e; 4855 return; 4856 } 4857 } 4858 4859 FuncDeclaration resolveOverloadSet(Loc loc, Scope* sc, 4860 OverloadSet os, Objects* tiargs, Type tthis, ArgumentList argumentList) 4861 { 4862 FuncDeclaration f = null; 4863 foreach (s; os.a) 4864 { 4865 if (tiargs && s.isFuncDeclaration()) 4866 continue; 4867 if (auto f2 = resolveFuncCall(loc, sc, s, tiargs, tthis, argumentList, FuncResolveFlag.quiet)) 4868 { 4869 if (f2.errors) 4870 return null; 4871 if (f) 4872 { 4873 /* Match in more than one overload set, 4874 * even if one is a 'better' match than the other. 4875 */ 4876 if (f.isCsymbol() && f2.isCsymbol()) 4877 { 4878 /* C has global name space, so just pick one, such as f. 4879 * If f and f2 are not compatible, that's how C rolls. 4880 */ 4881 } 4882 else 4883 ScopeDsymbol.multiplyDefined(loc, f, f2); // issue error 4884 } 4885 else 4886 f = f2; 4887 } 4888 } 4889 if (!f) 4890 { 4891 .error(loc, "no overload matches for `%s`", exp.toChars()); 4892 errorSupplemental(loc, "Candidates are:"); 4893 foreach (s; os.a) 4894 { 4895 overloadApply(s, (ds){ 4896 if (auto fd = ds.isFuncDeclaration()) 4897 .errorSupplemental(ds.loc, "%s%s", fd.toChars(), 4898 fd.type.toTypeFunction().parameterList.parametersTypeToChars()); 4899 else 4900 .errorSupplemental(ds.loc, "%s", ds.toChars()); 4901 return 0; 4902 }); 4903 } 4904 } 4905 else if (f.errors) 4906 f = null; 4907 return f; 4908 } 4909 4910 bool isSuper = false; 4911 if (exp.e1.op == EXP.dotVariable && t1.ty == Tfunction || exp.e1.op == EXP.dotTemplateDeclaration) 4912 { 4913 UnaExp ue = cast(UnaExp)exp.e1; 4914 4915 Expression ue1old = ue.e1; // need for 'right this' check 4916 DotVarExp dve; 4917 DotTemplateExp dte; 4918 Dsymbol s; 4919 if (exp.e1.op == EXP.dotVariable) 4920 { 4921 dve = cast(DotVarExp)exp.e1; 4922 dte = null; 4923 s = dve.var; 4924 tiargs = null; 4925 } 4926 else 4927 { 4928 dve = null; 4929 dte = cast(DotTemplateExp)exp.e1; 4930 s = dte.td; 4931 } 4932 4933 // Do overload resolution 4934 exp.f = resolveFuncCall(exp.loc, sc, s, tiargs, ue.e1.type, exp.argumentList, FuncResolveFlag.standard); 4935 if (!exp.f || exp.f.errors || exp.f.type.ty == Terror) 4936 return setError(); 4937 4938 if (exp.f.interfaceVirtual) 4939 { 4940 /* Cast 'this' to the type of the interface, and replace f with the interface's equivalent 4941 */ 4942 auto b = exp.f.interfaceVirtual; 4943 auto ad2 = b.sym; 4944 ue.e1 = ue.e1.castTo(sc, ad2.type.addMod(ue.e1.type.mod)); 4945 ue.e1 = ue.e1.expressionSemantic(sc); 4946 auto vi = exp.f.findVtblIndex(&ad2.vtbl, cast(int)ad2.vtbl.length); 4947 assert(vi >= 0); 4948 exp.f = ad2.vtbl[vi].isFuncDeclaration(); 4949 assert(exp.f); 4950 } 4951 if (exp.f.needThis()) 4952 { 4953 AggregateDeclaration ad = exp.f.isMemberLocal(); 4954 ue.e1 = getRightThis(exp.loc, sc, ad, ue.e1, exp.f); 4955 if (ue.e1.op == EXP.error) 4956 { 4957 result = ue.e1; 4958 return; 4959 } 4960 ethis = ue.e1; 4961 tthis = ue.e1.type; 4962 if (!(exp.f.type.ty == Tfunction && (cast(TypeFunction)exp.f.type).isScopeQual)) 4963 { 4964 if (checkParamArgumentEscape(sc, exp.f, Id.This, exp.f.vthis, STC.undefined_, ethis, false, false)) 4965 return setError(); 4966 } 4967 } 4968 4969 /* Cannot call public functions from inside invariant 4970 * (because then the invariant would have infinite recursion) 4971 */ 4972 if (sc.func && sc.func.isInvariantDeclaration() && ue.e1.op == EXP.this_ && exp.f.addPostInvariant()) 4973 { 4974 exp.error("cannot call `public`/`export` function `%s` from invariant", exp.f.toChars()); 4975 return setError(); 4976 } 4977 4978 if (!exp.ignoreAttributes) 4979 checkFunctionAttributes(exp, sc, exp.f); 4980 checkAccess(exp.loc, sc, ue.e1, exp.f); 4981 if (!exp.f.needThis()) 4982 { 4983 exp.e1 = Expression.combine(ue.e1, new VarExp(exp.loc, exp.f, false)); 4984 } 4985 else 4986 { 4987 if (ue1old.checkRightThis(sc)) 4988 return setError(); 4989 if (exp.e1.op == EXP.dotVariable) 4990 { 4991 dve.var = exp.f; 4992 exp.e1.type = exp.f.type; 4993 } 4994 else 4995 { 4996 exp.e1 = new DotVarExp(exp.loc, dte.e1, exp.f, false); 4997 exp.e1 = exp.e1.expressionSemantic(sc); 4998 if (exp.e1.op == EXP.error) 4999 return setError(); 5000 ue = cast(UnaExp)exp.e1; 5001 } 5002 version (none) 5003 { 5004 printf("ue.e1 = %s\n", ue.e1.toChars()); 5005 printf("f = %s\n", exp.f.toChars()); 5006 printf("t1 = %s\n", t1.toChars()); 5007 printf("e1 = %s\n", exp.e1.toChars()); 5008 printf("e1.type = %s\n", exp.e1.type.toChars()); 5009 } 5010 5011 // See if we need to adjust the 'this' pointer 5012 AggregateDeclaration ad = exp.f.isThis(); 5013 ClassDeclaration cd = ue.e1.type.isClassHandle(); 5014 if (ad && cd && ad.isClassDeclaration()) 5015 { 5016 if (ue.e1.op == EXP.dotType) 5017 { 5018 ue.e1 = (cast(DotTypeExp)ue.e1).e1; 5019 exp.directcall = true; 5020 } 5021 else if (ue.e1.op == EXP.super_) 5022 exp.directcall = true; 5023 else if ((cd.storage_class & STC.final_) != 0) // https://issues.dlang.org/show_bug.cgi?id=14211 5024 exp.directcall = true; 5025 5026 if (ad != cd) 5027 { 5028 ue.e1 = ue.e1.castTo(sc, ad.type.addMod(ue.e1.type.mod)); 5029 ue.e1 = ue.e1.expressionSemantic(sc); 5030 } 5031 } 5032 } 5033 // If we've got a pointer to a function then deference it 5034 // https://issues.dlang.org/show_bug.cgi?id=16483 5035 if (exp.e1.type.isPtrToFunction()) 5036 { 5037 Expression e = new PtrExp(exp.loc, exp.e1); 5038 e.type = exp.e1.type.nextOf(); 5039 exp.e1 = e; 5040 } 5041 t1 = exp.e1.type; 5042 } 5043 else if (exp.e1.op == EXP.super_ || exp.e1.op == EXP.this_) 5044 { 5045 auto ad = sc.func ? sc.func.isThis() : null; 5046 auto cd = ad ? ad.isClassDeclaration() : null; 5047 5048 isSuper = exp.e1.op == EXP.super_; 5049 if (isSuper) 5050 { 5051 // Base class constructor call 5052 if (!cd || !cd.baseClass || !sc.func.isCtorDeclaration()) 5053 { 5054 exp.error("super class constructor call must be in a constructor"); 5055 return setError(); 5056 } 5057 if (!cd.baseClass.ctor) 5058 { 5059 exp.error("no super class constructor for `%s`", cd.baseClass.toChars()); 5060 return setError(); 5061 } 5062 } 5063 else 5064 { 5065 // `this` call expression must be inside a 5066 // constructor 5067 if (!ad || !sc.func.isCtorDeclaration()) 5068 { 5069 exp.error("constructor call must be in a constructor"); 5070 return setError(); 5071 } 5072 5073 // https://issues.dlang.org/show_bug.cgi?id=18719 5074 // If `exp` is a call expression to another constructor 5075 // then it means that all struct/class fields will be 5076 // initialized after this call. 5077 foreach (ref field; sc.ctorflow.fieldinit) 5078 { 5079 field.csx |= CSX.this_ctor; 5080 } 5081 } 5082 5083 if (!sc.intypeof && !(sc.ctorflow.callSuper & CSX.halt)) 5084 { 5085 if (sc.inLoop || sc.ctorflow.callSuper & CSX.label) 5086 exp.error("constructor calls not allowed in loops or after labels"); 5087 if (sc.ctorflow.callSuper & (CSX.super_ctor | CSX.this_ctor)) 5088 exp.error("multiple constructor calls"); 5089 if ((sc.ctorflow.callSuper & CSX.return_) && !(sc.ctorflow.callSuper & CSX.any_ctor)) 5090 exp.error("an earlier `return` statement skips constructor"); 5091 sc.ctorflow.callSuper |= CSX.any_ctor | (isSuper ? CSX.super_ctor : CSX.this_ctor); 5092 } 5093 5094 tthis = ad.type.addMod(sc.func.type.mod); 5095 auto ctor = isSuper ? cd.baseClass.ctor : ad.ctor; 5096 if (auto os = ctor.isOverloadSet()) 5097 exp.f = resolveOverloadSet(exp.loc, sc, os, null, tthis, exp.argumentList); 5098 else 5099 exp.f = resolveFuncCall(exp.loc, sc, ctor, null, tthis, exp.argumentList, FuncResolveFlag.standard); 5100 5101 if (!exp.f || exp.f.errors) 5102 return setError(); 5103 5104 checkFunctionAttributes(exp, sc, exp.f); 5105 checkAccess(exp.loc, sc, null, exp.f); 5106 5107 exp.e1 = new DotVarExp(exp.e1.loc, exp.e1, exp.f, false); 5108 exp.e1 = exp.e1.expressionSemantic(sc); 5109 // https://issues.dlang.org/show_bug.cgi?id=21095 5110 if (exp.e1.op == EXP.error) 5111 return setError(); 5112 t1 = exp.e1.type; 5113 5114 // BUG: this should really be done by checking the static 5115 // call graph 5116 if (exp.f == sc.func) 5117 { 5118 exp.error("cyclic constructor call"); 5119 return setError(); 5120 } 5121 } 5122 else if (auto oe = exp.e1.isOverExp()) 5123 { 5124 exp.f = resolveOverloadSet(exp.loc, sc, oe.vars, tiargs, tthis, exp.argumentList); 5125 if (!exp.f) 5126 return setError(); 5127 if (ethis) 5128 exp.e1 = new DotVarExp(exp.loc, ethis, exp.f, false); 5129 else 5130 exp.e1 = new VarExp(exp.loc, exp.f, false); 5131 goto Lagain; 5132 } 5133 else if (!t1) 5134 { 5135 exp.error("function expected before `()`, not `%s`", exp.e1.toChars()); 5136 return setError(); 5137 } 5138 else if (t1.ty == Terror) 5139 { 5140 return setError(); 5141 } 5142 else if (t1.ty != Tfunction) 5143 { 5144 TypeFunction tf; 5145 const(char)* p; 5146 Dsymbol s; 5147 exp.f = null; 5148 if (auto fe = exp.e1.isFuncExp()) 5149 { 5150 // function literal that direct called is always inferred. 5151 assert(fe.fd); 5152 exp.f = fe.fd; 5153 tf = cast(TypeFunction)exp.f.type; 5154 p = "function literal"; 5155 } 5156 else if (t1.ty == Tdelegate) 5157 { 5158 TypeDelegate td = cast(TypeDelegate)t1; 5159 assert(td.next.ty == Tfunction); 5160 tf = cast(TypeFunction)td.next; 5161 p = "delegate"; 5162 } 5163 else if (auto tfx = t1.isPtrToFunction()) 5164 { 5165 tf = tfx; 5166 p = "function pointer"; 5167 } 5168 else if (exp.e1.op == EXP.dotVariable && (cast(DotVarExp)exp.e1).var.isOverDeclaration()) 5169 { 5170 DotVarExp dve = cast(DotVarExp)exp.e1; 5171 exp.f = resolveFuncCall(exp.loc, sc, dve.var, tiargs, dve.e1.type, exp.argumentList, FuncResolveFlag.overloadOnly); 5172 if (!exp.f) 5173 return setError(); 5174 if (exp.f.needThis()) 5175 { 5176 dve.var = exp.f; 5177 dve.type = exp.f.type; 5178 dve.hasOverloads = false; 5179 goto Lagain; 5180 } 5181 exp.e1 = new VarExp(dve.loc, exp.f, false); 5182 Expression e = new CommaExp(exp.loc, dve.e1, exp); 5183 result = e.expressionSemantic(sc); 5184 return; 5185 } 5186 else if (exp.e1.op == EXP.variable && (cast(VarExp)exp.e1).var.isOverDeclaration()) 5187 { 5188 s = (cast(VarExp)exp.e1).var; 5189 goto L2; 5190 } 5191 else if (exp.e1.op == EXP.template_) 5192 { 5193 s = (cast(TemplateExp)exp.e1).td; 5194 L2: 5195 exp.f = resolveFuncCall(exp.loc, sc, s, tiargs, null, exp.argumentList, FuncResolveFlag.standard); 5196 if (!exp.f || exp.f.errors) 5197 return setError(); 5198 if (exp.f.needThis()) 5199 { 5200 if (hasThis(sc)) 5201 { 5202 // Supply an implicit 'this', as in 5203 // this.ident 5204 exp.e1 = new DotVarExp(exp.loc, (new ThisExp(exp.loc)).expressionSemantic(sc), exp.f, false); 5205 goto Lagain; 5206 } 5207 else if (isNeedThisScope(sc, exp.f)) 5208 { 5209 exp.error("need `this` for `%s` of type `%s`", exp.f.toChars(), exp.f.type.toChars()); 5210 return setError(); 5211 } 5212 } 5213 exp.e1 = new VarExp(exp.e1.loc, exp.f, false); 5214 goto Lagain; 5215 } 5216 else 5217 { 5218 exp.error("function expected before `()`, not `%s` of type `%s`", exp.e1.toChars(), exp.e1.type.toChars()); 5219 return setError(); 5220 } 5221 5222 const(char)* failMessage; 5223 if (!tf.callMatch(null, exp.argumentList, 0, &failMessage, sc)) 5224 { 5225 OutBuffer buf; 5226 buf.writeByte('('); 5227 argExpTypesToCBuffer(&buf, exp.arguments); 5228 buf.writeByte(')'); 5229 if (tthis) 5230 tthis.modToBuffer(&buf); 5231 5232 //printf("tf = %s, args = %s\n", tf.deco, (*arguments)[0].type.deco); 5233 .error(exp.loc, "%s `%s%s` is not callable using argument types `%s`", 5234 p, exp.e1.toChars(), parametersTypeToChars(tf.parameterList), buf.peekChars()); 5235 if (failMessage) 5236 errorSupplemental(exp.loc, "%s", failMessage); 5237 return setError(); 5238 } 5239 // Purity and safety check should run after testing arguments matching 5240 if (exp.f) 5241 { 5242 exp.checkPurity(sc, exp.f); 5243 exp.checkSafety(sc, exp.f); 5244 exp.checkNogc(sc, exp.f); 5245 if (exp.f.checkNestedReference(sc, exp.loc)) 5246 return setError(); 5247 } 5248 else if (sc.func && sc.intypeof != 1 && !(sc.flags & (SCOPE.ctfe | SCOPE.debug_))) 5249 { 5250 bool err = false; 5251 if (!tf.purity && sc.func.setImpure(exp.loc, "`pure` %s `%s` cannot call impure `%s`", exp.e1)) 5252 { 5253 exp.error("`pure` %s `%s` cannot call impure %s `%s`", 5254 sc.func.kind(), sc.func.toPrettyChars(), p, exp.e1.toChars()); 5255 err = true; 5256 } 5257 if (!tf.isnogc && sc.func.setGC(exp.loc, "`@nogc` %s `%s` cannot call non-@nogc `%s`", exp.e1)) 5258 { 5259 exp.error("`@nogc` %s `%s` cannot call non-@nogc %s `%s`", 5260 sc.func.kind(), sc.func.toPrettyChars(), p, exp.e1.toChars()); 5261 err = true; 5262 } 5263 if (tf.trust <= TRUST.system && sc.setUnsafe(true, exp.loc, 5264 "`@safe` function `%s` cannot call `@system` `%s`", sc.func, exp.e1)) 5265 { 5266 exp.error("`@safe` %s `%s` cannot call `@system` %s `%s`", 5267 sc.func.kind(), sc.func.toPrettyChars(), p, exp.e1.toChars()); 5268 err = true; 5269 } 5270 if (err) 5271 return setError(); 5272 } 5273 5274 if (t1.ty == Tpointer) 5275 { 5276 Expression e = new PtrExp(exp.loc, exp.e1); 5277 e.type = tf; 5278 exp.e1 = e; 5279 } 5280 t1 = tf; 5281 } 5282 else if (VarExp ve = exp.e1.isVarExp()) 5283 { 5284 // Do overload resolution 5285 exp.f = ve.var.isFuncDeclaration(); 5286 assert(exp.f); 5287 tiargs = null; 5288 5289 if (exp.f.overnext) 5290 exp.f = resolveFuncCall(exp.loc, sc, exp.f, tiargs, null, exp.argumentList, FuncResolveFlag.overloadOnly); 5291 else 5292 { 5293 exp.f = exp.f.toAliasFunc(); 5294 TypeFunction tf = cast(TypeFunction)exp.f.type; 5295 const(char)* failMessage; 5296 if (!tf.callMatch(null, exp.argumentList, 0, &failMessage, sc)) 5297 { 5298 OutBuffer buf; 5299 buf.writeByte('('); 5300 argExpTypesToCBuffer(&buf, exp.arguments); 5301 buf.writeByte(')'); 5302 5303 //printf("tf = %s, args = %s\n", tf.deco, (*arguments)[0].type.deco); 5304 .error(exp.loc, "%s `%s%s` is not callable using argument types `%s`", 5305 exp.f.kind(), exp.f.toPrettyChars(), parametersTypeToChars(tf.parameterList), buf.peekChars()); 5306 if (failMessage) 5307 errorSupplemental(exp.loc, "%s", failMessage); 5308 exp.f = null; 5309 } 5310 } 5311 if (!exp.f || exp.f.errors) 5312 return setError(); 5313 5314 if (exp.f.needThis()) 5315 { 5316 // Change the ancestor lambdas to delegate before hasThis(sc) call. 5317 if (exp.f.checkNestedReference(sc, exp.loc)) 5318 return setError(); 5319 5320 auto memberFunc = hasThis(sc); 5321 if (memberFunc && haveSameThis(memberFunc, exp.f)) 5322 { 5323 // Supply an implicit 'this', as in 5324 // this.ident 5325 exp.e1 = new DotVarExp(exp.loc, (new ThisExp(exp.loc)).expressionSemantic(sc), ve.var); 5326 // Note: we cannot use f directly, because further overload resolution 5327 // through the supplied 'this' may cause different result. 5328 goto Lagain; 5329 } 5330 else if (isNeedThisScope(sc, exp.f)) 5331 { 5332 // At this point it is possible that `exp.f` had an ambiguity error that was 5333 // silenced because the previous call to `resolveFuncCall` was done using 5334 // `FuncResolveFlag.overloadOnly`. To make sure that a proper error message 5335 // is printed, redo the call with `FuncResolveFlag.standard`. 5336 // 5337 // https://issues.dlang.org/show_bug.cgi?id=22157 5338 if (exp.f.overnext) 5339 exp.f = resolveFuncCall(exp.loc, sc, exp.f, tiargs, null, exp.argumentList, FuncResolveFlag.standard); 5340 5341 if (!exp.f || exp.f.errors) 5342 return setError(); 5343 5344 // If no error is printed, it means that `f` is the single matching overload 5345 // and it needs `this`. 5346 exp.error("need `this` for `%s` of type `%s`", exp.f.toChars(), exp.f.type.toChars()); 5347 return setError(); 5348 } 5349 } 5350 5351 checkFunctionAttributes(exp, sc, exp.f); 5352 checkAccess(exp.loc, sc, null, exp.f); 5353 if (exp.f.checkNestedReference(sc, exp.loc)) 5354 return setError(); 5355 5356 ethis = null; 5357 tthis = null; 5358 5359 if (ve.hasOverloads) 5360 { 5361 exp.e1 = new VarExp(ve.loc, exp.f, false); 5362 exp.e1.type = exp.f.type; 5363 } 5364 t1 = exp.f.type; 5365 } 5366 assert(t1.ty == Tfunction); 5367 5368 Expression argprefix; 5369 if (!exp.arguments) 5370 exp.arguments = new Expressions(); 5371 if (functionParameters(exp.loc, sc, cast(TypeFunction)t1, ethis, tthis, exp.argumentList, exp.f, &exp.type, &argprefix)) 5372 return setError(); 5373 5374 if (!exp.type) 5375 { 5376 exp.e1 = e1org; // https://issues.dlang.org/show_bug.cgi?id=10922 5377 // avoid recursive expression printing 5378 exp.error("forward reference to inferred return type of function call `%s`", exp.toChars()); 5379 return setError(); 5380 } 5381 5382 if (exp.f && exp.f.tintro) 5383 { 5384 Type t = exp.type; 5385 int offset = 0; 5386 TypeFunction tf = cast(TypeFunction)exp.f.tintro; 5387 if (tf.next.isBaseOf(t, &offset) && offset) 5388 { 5389 exp.type = tf.next; 5390 result = Expression.combine(argprefix, exp.castTo(sc, t)); 5391 return; 5392 } 5393 } 5394 5395 // Handle the case of a direct lambda call 5396 if (exp.f && exp.f.isFuncLiteralDeclaration() && sc.func && !sc.intypeof) 5397 { 5398 exp.f.tookAddressOf = 0; 5399 } 5400 5401 result = Expression.combine(argprefix, exp); 5402 5403 if (isSuper) 5404 { 5405 auto ad = sc.func ? sc.func.isThis() : null; 5406 auto cd = ad ? ad.isClassDeclaration() : null; 5407 if (cd && cd.classKind == ClassKind.cpp && exp.f && !exp.f.fbody) 5408 { 5409 // if super is defined in C++, it sets the vtable pointer to the base class 5410 // so we have to restore it, but still return 'this' from super() call: 5411 // (auto __vptrTmp = this.__vptr, auto __superTmp = super()), (this.__vptr = __vptrTmp, __superTmp) 5412 Loc loc = exp.loc; 5413 5414 auto vptr = new DotIdExp(loc, new ThisExp(loc), Id.__vptr); 5415 auto vptrTmpDecl = copyToTemp(0, "__vptrTmp", vptr); 5416 auto declareVptrTmp = new DeclarationExp(loc, vptrTmpDecl); 5417 5418 auto superTmpDecl = copyToTemp(0, "__superTmp", result); 5419 auto declareSuperTmp = new DeclarationExp(loc, superTmpDecl); 5420 5421 auto declareTmps = new CommaExp(loc, declareVptrTmp, declareSuperTmp); 5422 5423 auto restoreVptr = new AssignExp(loc, vptr.syntaxCopy(), new VarExp(loc, vptrTmpDecl)); 5424 5425 Expression e = new CommaExp(loc, declareTmps, new CommaExp(loc, restoreVptr, new VarExp(loc, superTmpDecl))); 5426 result = e.expressionSemantic(sc); 5427 } 5428 } 5429 5430 // declare dual-context container 5431 if (exp.f && exp.f.hasDualContext() && !sc.intypeof && sc.func) 5432 { 5433 // check access to second `this` 5434 if (AggregateDeclaration ad2 = exp.f.isMember2()) 5435 { 5436 Expression te = new ThisExp(exp.loc).expressionSemantic(sc); 5437 if (te.op != EXP.error) 5438 te = getRightThis(exp.loc, sc, ad2, te, exp.f); 5439 if (te.op == EXP.error) 5440 { 5441 exp.error("need `this` of type `%s` to call function `%s`", ad2.toChars(), exp.f.toChars()); 5442 return setError(); 5443 } 5444 } 5445 exp.vthis2 = makeThis2Argument(exp.loc, sc, exp.f); 5446 Expression de = new DeclarationExp(exp.loc, exp.vthis2); 5447 result = Expression.combine(de, result); 5448 result = result.expressionSemantic(sc); 5449 } 5450 } 5451 5452 override void visit(DeclarationExp e) 5453 { 5454 if (e.type) 5455 { 5456 result = e; 5457 return; 5458 } 5459 static if (LOGSEMANTIC) 5460 { 5461 printf("DeclarationExp::semantic() %s\n", e.toChars()); 5462 } 5463 5464 uint olderrors = global.errors; 5465 5466 /* This is here to support extern(linkage) declaration, 5467 * where the extern(linkage) winds up being an AttribDeclaration 5468 * wrapper. 5469 */ 5470 Dsymbol s = e.declaration; 5471 5472 while (1) 5473 { 5474 AttribDeclaration ad = s.isAttribDeclaration(); 5475 if (ad) 5476 { 5477 if (ad.decl && ad.decl.length == 1) 5478 { 5479 s = (*ad.decl)[0]; 5480 continue; 5481 } 5482 } 5483 break; 5484 } 5485 5486 //printf("inserting '%s' %p into sc = %p\n", s.toChars(), s, sc); 5487 // Insert into both local scope and function scope. 5488 // Must be unique in both. 5489 if (s.ident) 5490 { 5491 VarDeclaration v = s.isVarDeclaration(); 5492 if (v) 5493 { 5494 if (sc.flags & SCOPE.Cfile) 5495 { 5496 /* Do semantic() on the type before inserting v into the symbol table 5497 */ 5498 if (!v.originalType) 5499 v.originalType = v.type.syntaxCopy(); 5500 Scope* sc2 = sc.push(); 5501 sc2.stc |= v.storage_class & STC.FUNCATTR; 5502 sc2.linkage = LINK.c; // account for the extern(C) in front of the declaration 5503 v.inuse++; 5504 v.type = v.type.typeSemantic(v.loc, sc2); 5505 v.inuse--; 5506 sc2.pop(); 5507 } 5508 else 5509 { 5510 /* Do semantic() on initializer first so this will be illegal: 5511 * int a = a; 5512 */ 5513 e.declaration.dsymbolSemantic(sc); 5514 s.parent = sc.parent; 5515 } 5516 } 5517 5518 if (!sc.insert(s)) 5519 { 5520 auto conflict = sc.search(Loc.initial, s.ident, null); 5521 e.error("declaration `%s` is already defined", s.toPrettyChars()); 5522 errorSupplemental(conflict.loc, "`%s` `%s` is defined here", 5523 conflict.kind(), conflict.toChars()); 5524 return setError(); 5525 } 5526 5527 if (v && (sc.flags & SCOPE.Cfile)) 5528 { 5529 /* Do semantic() on initializer last so this will be legal: 5530 * int a = a; 5531 */ 5532 e.declaration.dsymbolSemantic(sc); 5533 s.parent = sc.parent; 5534 } 5535 5536 if (sc.func) 5537 { 5538 // https://issues.dlang.org/show_bug.cgi?id=11720 5539 if ((s.isFuncDeclaration() || 5540 s.isAggregateDeclaration() || 5541 s.isEnumDeclaration() || 5542 s.isTemplateDeclaration() || 5543 v 5544 ) && !sc.func.localsymtab.insert(s)) 5545 { 5546 // Get the previous symbol 5547 Dsymbol originalSymbol = sc.func.localsymtab.lookup(s.ident); 5548 5549 // Perturb the name mangling so that the symbols can co-exist 5550 // instead of colliding 5551 s.localNum = cast(ushort)(originalSymbol.localNum + 1); 5552 // 65535 should be enough for anyone 5553 if (!s.localNum) 5554 { 5555 e.error("more than 65535 symbols with name `%s` generated", s.ident.toChars()); 5556 return setError(); 5557 } 5558 5559 // Replace originalSymbol with s, which updates the localCount 5560 sc.func.localsymtab.update(s); 5561 5562 // The mangling change only works for D mangling 5563 } 5564 5565 if (!(sc.flags & SCOPE.Cfile)) 5566 { 5567 /* https://issues.dlang.org/show_bug.cgi?id=21272 5568 * If we are in a foreach body we need to extract the 5569 * function containing the foreach 5570 */ 5571 FuncDeclaration fes_enclosing_func; 5572 if (sc.func && sc.func.fes) 5573 fes_enclosing_func = sc.enclosing.enclosing.func; 5574 5575 // Disallow shadowing 5576 for (Scope* scx = sc.enclosing; scx && (scx.func == sc.func || (fes_enclosing_func && scx.func == fes_enclosing_func)); scx = scx.enclosing) 5577 { 5578 Dsymbol s2; 5579 if (scx.scopesym && scx.scopesym.symtab && (s2 = scx.scopesym.symtab.lookup(s.ident)) !is null && s != s2) 5580 { 5581 // allow STC.local symbols to be shadowed 5582 // TODO: not really an optimal design 5583 auto decl = s2.isDeclaration(); 5584 if (!decl || !(decl.storage_class & STC.local)) 5585 { 5586 if (sc.func.fes) 5587 { 5588 e.deprecation("%s `%s` is shadowing %s `%s`. Rename the `foreach` variable.", s.kind(), s.ident.toChars(), s2.kind(), s2.toPrettyChars()); 5589 } 5590 else 5591 { 5592 e.error("%s `%s` is shadowing %s `%s`", s.kind(), s.ident.toChars(), s2.kind(), s2.toPrettyChars()); 5593 return setError(); 5594 } 5595 } 5596 } 5597 } 5598 } 5599 } 5600 } 5601 if (!s.isVarDeclaration()) 5602 { 5603 Scope* sc2 = sc; 5604 if (sc2.stc & (STC.pure_ | STC.nothrow_ | STC.nogc)) 5605 sc2 = sc.push(); 5606 sc2.stc &= ~(STC.pure_ | STC.nothrow_ | STC.nogc); 5607 e.declaration.dsymbolSemantic(sc2); 5608 if (sc2 != sc) 5609 sc2.pop(); 5610 s.parent = sc.parent; 5611 } 5612 if (global.errors == olderrors) 5613 { 5614 e.declaration.semantic2(sc); 5615 if (global.errors == olderrors) 5616 { 5617 e.declaration.semantic3(sc); 5618 } 5619 } 5620 // todo: error in declaration should be propagated. 5621 5622 e.type = Type.tvoid; 5623 result = e; 5624 } 5625 5626 override void visit(TypeidExp exp) 5627 { 5628 static if (LOGSEMANTIC) 5629 { 5630 printf("TypeidExp::semantic() %s\n", exp.toChars()); 5631 } 5632 Type ta = isType(exp.obj); 5633 Expression ea = isExpression(exp.obj); 5634 Dsymbol sa = isDsymbol(exp.obj); 5635 //printf("ta %p ea %p sa %p\n", ta, ea, sa); 5636 5637 if (ta) 5638 { 5639 dmd.typesem.resolve(ta, exp.loc, sc, ea, ta, sa, true); 5640 } 5641 5642 if (ea) 5643 { 5644 if (auto sym = getDsymbol(ea)) 5645 ea = symbolToExp(sym, exp.loc, sc, false); 5646 else 5647 ea = ea.expressionSemantic(sc); 5648 ea = resolveProperties(sc, ea); 5649 ta = ea.type; 5650 if (ea.op == EXP.type) 5651 ea = null; 5652 } 5653 5654 if (!ta) 5655 { 5656 //printf("ta %p ea %p sa %p\n", ta, ea, sa); 5657 exp.error("no type for `typeid(%s)`", ea ? ea.toChars() : (sa ? sa.toChars() : "")); 5658 return setError(); 5659 } 5660 5661 ta.checkComplexTransition(exp.loc, sc); 5662 5663 Expression e; 5664 auto tb = ta.toBasetype(); 5665 if (ea && tb.ty == Tclass) 5666 { 5667 if (tb.toDsymbol(sc).isClassDeclaration().classKind == ClassKind.cpp) 5668 { 5669 error(exp.loc, "runtime type information is not supported for `extern(C++)` classes"); 5670 e = ErrorExp.get(); 5671 } 5672 else if (!Type.typeinfoclass) 5673 { 5674 error(exp.loc, "`object.TypeInfo_Class` could not be found, but is implicitly used"); 5675 e = ErrorExp.get(); 5676 } 5677 else 5678 { 5679 /* Get the dynamic type, which is .classinfo 5680 */ 5681 ea = ea.expressionSemantic(sc); 5682 e = new TypeidExp(ea.loc, ea); 5683 e.type = Type.typeinfoclass.type; 5684 } 5685 } 5686 else if (ta.ty == Terror) 5687 { 5688 e = ErrorExp.get(); 5689 } 5690 else 5691 { 5692 // Handle this in the glue layer 5693 e = new TypeidExp(exp.loc, ta); 5694 5695 bool genObjCode = true; 5696 5697 // https://issues.dlang.org/show_bug.cgi?id=23650 5698 // We generate object code for typeinfo, required 5699 // by typeid, only if in non-speculative context 5700 if (sc.flags & SCOPE.compile) 5701 { 5702 genObjCode = false; 5703 } 5704 5705 e.type = getTypeInfoType(exp.loc, ta, sc, genObjCode); 5706 semanticTypeInfo(sc, ta); 5707 5708 if (ea) 5709 { 5710 e = new CommaExp(exp.loc, ea, e); // execute ea 5711 e = e.expressionSemantic(sc); 5712 } 5713 } 5714 result = e; 5715 } 5716 5717 override void visit(TraitsExp e) 5718 { 5719 result = semanticTraits(e, sc); 5720 } 5721 5722 override void visit(HaltExp e) 5723 { 5724 static if (LOGSEMANTIC) 5725 { 5726 printf("HaltExp::semantic()\n"); 5727 } 5728 e.type = Type.tnoreturn; 5729 result = e; 5730 } 5731 5732 override void visit(IsExp e) 5733 { 5734 /* is(targ id tok tspec) 5735 * is(targ id : tok2) 5736 * is(targ id == tok2) 5737 */ 5738 Type tded = null; 5739 5740 void yes() 5741 { 5742 //printf("yes\n"); 5743 if (!e.id) 5744 { 5745 result = IntegerExp.createBool(true); 5746 return; 5747 } 5748 5749 Dsymbol s; 5750 Tuple tup = isTuple(tded); 5751 if (tup) 5752 s = new TupleDeclaration(e.loc, e.id, &tup.objects); 5753 else 5754 s = new AliasDeclaration(e.loc, e.id, tded); 5755 s.dsymbolSemantic(sc); 5756 5757 /* The reason for the !tup is unclear. It fails Phobos unittests if it is not there. 5758 * More investigation is needed. 5759 */ 5760 if (!tup && !sc.insert(s)) 5761 { 5762 auto conflict = sc.search(Loc.initial, s.ident, null); 5763 e.error("declaration `%s` is already defined", s.toPrettyChars()); 5764 errorSupplemental(conflict.loc, "`%s` `%s` is defined here", 5765 conflict.kind(), conflict.toChars()); 5766 } 5767 5768 unSpeculative(sc, s); 5769 5770 result = IntegerExp.createBool(true); 5771 } 5772 void no() 5773 { 5774 result = IntegerExp.createBool(false); 5775 //printf("no\n"); 5776 } 5777 5778 static if (LOGSEMANTIC) 5779 { 5780 printf("IsExp::semantic(%s)\n", e.toChars()); 5781 } 5782 if (e.id && !(sc.flags & SCOPE.condition)) 5783 { 5784 e.error("can only declare type aliases within `static if` conditionals or `static assert`s"); 5785 return setError(); 5786 } 5787 5788 if (e.tok2 == TOK.package_ || e.tok2 == TOK.module_) // These is() expressions are special because they can work on modules, not just types. 5789 { 5790 const oldErrors = global.startGagging(); 5791 Dsymbol sym = e.targ.toDsymbol(sc); 5792 global.endGagging(oldErrors); 5793 5794 if (sym is null) 5795 return no(); 5796 Package p = resolveIsPackage(sym); 5797 if (p is null) 5798 return no(); 5799 if (e.tok2 == TOK.package_ && p.isModule()) // Note that isModule() will return null for package modules because they're not actually instances of Module. 5800 return no(); 5801 else if(e.tok2 == TOK.module_ && !(p.isModule() || p.isPackageMod())) 5802 return no(); 5803 tded = e.targ; 5804 return yes(); 5805 } 5806 5807 { 5808 Scope* sc2 = sc.copy(); // keep sc.flags 5809 sc2.tinst = null; 5810 sc2.minst = null; 5811 sc2.flags |= SCOPE.fullinst; 5812 Type t = e.targ.trySemantic(e.loc, sc2); 5813 sc2.pop(); 5814 if (!t) // errors, so condition is false 5815 return no(); 5816 e.targ = t; 5817 } 5818 5819 if (e.tok2 != TOK.reserved) 5820 { 5821 switch (e.tok2) 5822 { 5823 case TOK.struct_: 5824 if (e.targ.ty != Tstruct) 5825 return no(); 5826 if ((cast(TypeStruct)e.targ).sym.isUnionDeclaration()) 5827 return no(); 5828 tded = e.targ; 5829 break; 5830 5831 case TOK.union_: 5832 if (e.targ.ty != Tstruct) 5833 return no(); 5834 if (!(cast(TypeStruct)e.targ).sym.isUnionDeclaration()) 5835 return no(); 5836 tded = e.targ; 5837 break; 5838 5839 case TOK.class_: 5840 if (e.targ.ty != Tclass) 5841 return no(); 5842 if ((cast(TypeClass)e.targ).sym.isInterfaceDeclaration()) 5843 return no(); 5844 tded = e.targ; 5845 break; 5846 5847 case TOK.interface_: 5848 if (e.targ.ty != Tclass) 5849 return no(); 5850 if (!(cast(TypeClass)e.targ).sym.isInterfaceDeclaration()) 5851 return no(); 5852 tded = e.targ; 5853 break; 5854 5855 case TOK.const_: 5856 if (!e.targ.isConst()) 5857 return no(); 5858 tded = e.targ; 5859 break; 5860 5861 case TOK.immutable_: 5862 if (!e.targ.isImmutable()) 5863 return no(); 5864 tded = e.targ; 5865 break; 5866 5867 case TOK.shared_: 5868 if (!e.targ.isShared()) 5869 return no(); 5870 tded = e.targ; 5871 break; 5872 5873 case TOK.inout_: 5874 if (!e.targ.isWild()) 5875 return no(); 5876 tded = e.targ; 5877 break; 5878 5879 case TOK.super_: 5880 // If class or interface, get the base class and interfaces 5881 if (e.targ.ty != Tclass) 5882 return no(); 5883 else 5884 { 5885 ClassDeclaration cd = (cast(TypeClass)e.targ).sym; 5886 auto args = new Parameters(); 5887 args.reserve(cd.baseclasses.length); 5888 if (cd.semanticRun < PASS.semanticdone) 5889 cd.dsymbolSemantic(null); 5890 for (size_t i = 0; i < cd.baseclasses.length; i++) 5891 { 5892 BaseClass* b = (*cd.baseclasses)[i]; 5893 args.push(new Parameter(STC.in_, b.type, null, null, null)); 5894 } 5895 tded = new TypeTuple(args); 5896 } 5897 break; 5898 5899 case TOK.enum_: 5900 if (e.targ.ty != Tenum) 5901 return no(); 5902 if (e.id) 5903 tded = (cast(TypeEnum)e.targ).sym.getMemtype(e.loc); 5904 else 5905 tded = e.targ; 5906 5907 if (tded.ty == Terror) 5908 return setError(); 5909 break; 5910 5911 case TOK.delegate_: 5912 if (e.targ.ty != Tdelegate) 5913 return no(); 5914 tded = (cast(TypeDelegate)e.targ).next; // the underlying function type 5915 break; 5916 5917 case TOK.function_: 5918 case TOK.parameters: 5919 { 5920 if (e.targ.ty != Tfunction) 5921 return no(); 5922 tded = e.targ; 5923 5924 /* Generate tuple from function parameter types. 5925 */ 5926 assert(tded.ty == Tfunction); 5927 auto tdedf = tded.isTypeFunction(); 5928 auto args = new Parameters(); 5929 foreach (i, arg; tdedf.parameterList) 5930 { 5931 assert(arg && arg.type); 5932 /* If one of the default arguments was an error, 5933 don't return an invalid tuple 5934 */ 5935 if (e.tok2 == TOK.parameters && arg.defaultArg && arg.defaultArg.op == EXP.error) 5936 return setError(); 5937 args.push(new Parameter(arg.storageClass, arg.type, (e.tok2 == TOK.parameters) ? arg.ident : null, (e.tok2 == TOK.parameters) ? arg.defaultArg : null, arg.userAttribDecl)); 5938 } 5939 tded = new TypeTuple(args); 5940 break; 5941 } 5942 case TOK.return_: 5943 /* Get the 'return type' for the function, 5944 * delegate, or pointer to function. 5945 */ 5946 if (auto tf = e.targ.isFunction_Delegate_PtrToFunction()) 5947 tded = tf.next; 5948 else 5949 return no(); 5950 break; 5951 5952 case TOK.argumentTypes: 5953 /* Generate a type tuple of the equivalent types used to determine if a 5954 * function argument of this type can be passed in registers. 5955 * The results of this are highly platform dependent, and intended 5956 * primarly for use in implementing va_arg(). 5957 */ 5958 tded = target.toArgTypes(e.targ); 5959 if (!tded) 5960 return no(); 5961 // not valid for a parameter 5962 break; 5963 5964 case TOK.vector: 5965 if (e.targ.ty != Tvector) 5966 return no(); 5967 tded = (cast(TypeVector)e.targ).basetype; 5968 break; 5969 5970 default: 5971 assert(0); 5972 } 5973 5974 // https://issues.dlang.org/show_bug.cgi?id=18753 5975 if (tded) 5976 return yes(); 5977 return no(); 5978 } 5979 else if (e.tspec && !e.id && !(e.parameters && e.parameters.length)) 5980 { 5981 /* Evaluate to true if targ matches tspec 5982 * is(targ == tspec) 5983 * is(targ : tspec) 5984 */ 5985 e.tspec = e.tspec.typeSemantic(e.loc, sc); 5986 //printf("targ = %s, %s\n", e.targ.toChars(), e.targ.deco); 5987 //printf("tspec = %s, %s\n", e.tspec.toChars(), e.tspec.deco); 5988 5989 if (e.tok == TOK.colon) 5990 { 5991 // current scope is itself deprecated, or deprecations are not errors 5992 const bool deprecationAllowed = sc.isDeprecated 5993 || global.params.useDeprecated != DiagnosticReporting.error; 5994 const bool preventAliasThis = e.targ.hasDeprecatedAliasThis && !deprecationAllowed; 5995 5996 if (preventAliasThis && e.targ.ty == Tstruct) 5997 { 5998 if ((cast(TypeStruct) e.targ).implicitConvToWithoutAliasThis(e.tspec)) 5999 return yes(); 6000 else 6001 return no(); 6002 } 6003 else if (preventAliasThis && e.targ.ty == Tclass) 6004 { 6005 if ((cast(TypeClass) e.targ).implicitConvToWithoutAliasThis(e.tspec)) 6006 return yes(); 6007 else 6008 return no(); 6009 } 6010 else if (e.targ.implicitConvTo(e.tspec)) 6011 return yes(); 6012 else 6013 return no(); 6014 } 6015 else /* == */ 6016 { 6017 if (e.targ.equals(e.tspec)) 6018 return yes(); 6019 else 6020 return no(); 6021 } 6022 } 6023 else if (e.tspec) 6024 { 6025 /* Evaluate to true if targ matches tspec. 6026 * If true, declare id as an alias for the specialized type. 6027 * is(targ == tspec, tpl) 6028 * is(targ : tspec, tpl) 6029 * is(targ id == tspec) 6030 * is(targ id : tspec) 6031 * is(targ id == tspec, tpl) 6032 * is(targ id : tspec, tpl) 6033 */ 6034 Identifier tid = e.id ? e.id : Identifier.generateId("__isexp_id"); 6035 e.parameters.insert(0, new TemplateTypeParameter(e.loc, tid, null, null)); 6036 6037 Objects dedtypes = Objects(e.parameters.length); 6038 dedtypes.zero(); 6039 6040 MATCH m = deduceType(e.targ, sc, e.tspec, e.parameters, &dedtypes, null, 0, e.tok == TOK.equal); 6041 6042 if (m == MATCH.nomatch || (m != MATCH.exact && e.tok == TOK.equal)) 6043 { 6044 return no(); 6045 } 6046 else 6047 { 6048 tded = cast(Type)dedtypes[0]; 6049 if (!tded) 6050 tded = e.targ; 6051 Objects tiargs = Objects(1); 6052 tiargs[0] = e.targ; 6053 6054 /* Declare trailing parameters 6055 */ 6056 for (size_t i = 1; i < e.parameters.length; i++) 6057 { 6058 TemplateParameter tp = (*e.parameters)[i]; 6059 Declaration s = null; 6060 6061 m = tp.matchArg(e.loc, sc, &tiargs, i, e.parameters, &dedtypes, &s); 6062 if (m == MATCH.nomatch) 6063 return no(); 6064 s.dsymbolSemantic(sc); 6065 if (!sc.insert(s)) 6066 { 6067 auto conflict = sc.search(Loc.initial, s.ident, null); 6068 e.error("declaration `%s` is already defined", s.toPrettyChars()); 6069 errorSupplemental(conflict.loc, "`%s` `%s` is defined here", 6070 conflict.kind(), conflict.toChars()); 6071 } 6072 6073 unSpeculative(sc, s); 6074 } 6075 return yes(); 6076 } 6077 } 6078 else if (e.id) 6079 { 6080 /* Declare id as an alias for type targ. Evaluate to true 6081 * is(targ id) 6082 */ 6083 tded = e.targ; 6084 } 6085 return yes(); 6086 } 6087 6088 override void visit(BinAssignExp exp) 6089 { 6090 if (exp.type) 6091 { 6092 result = exp; 6093 return; 6094 } 6095 6096 Expression e = exp.op_overload(sc); 6097 if (e) 6098 { 6099 result = e; 6100 return; 6101 } 6102 6103 if (exp.e1.op == EXP.arrayLength) 6104 { 6105 // arr.length op= e2; 6106 e = rewriteOpAssign(exp); 6107 e = e.expressionSemantic(sc); 6108 result = e; 6109 return; 6110 } 6111 if (exp.e1.op == EXP.slice || exp.e1.type.ty == Tarray || exp.e1.type.ty == Tsarray) 6112 { 6113 if (checkNonAssignmentArrayOp(exp.e1)) 6114 return setError(); 6115 6116 if (exp.e1.op == EXP.slice) 6117 (cast(SliceExp)exp.e1).arrayop = true; 6118 6119 // T[] op= ... 6120 if (exp.e2.implicitConvTo(exp.e1.type.nextOf())) 6121 { 6122 // T[] op= T 6123 exp.e2 = exp.e2.castTo(sc, exp.e1.type.nextOf()); 6124 } 6125 else if (Expression ex = typeCombine(exp, sc)) 6126 { 6127 result = ex; 6128 return; 6129 } 6130 exp.type = exp.e1.type; 6131 result = arrayOp(exp, sc); 6132 return; 6133 } 6134 6135 exp.e1 = exp.e1.expressionSemantic(sc); 6136 exp.e1 = exp.e1.modifiableLvalue(sc, exp.e1); 6137 exp.e1 = exp.e1.optimize(WANTvalue, /*keepLvalue*/ true); 6138 exp.type = exp.e1.type; 6139 6140 if (auto ad = isAggregate(exp.e1.type)) 6141 { 6142 if (const s = search_function(ad, Id.opOpAssign)) 6143 { 6144 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()); 6145 return setError(); 6146 } 6147 } 6148 if (exp.e1.checkScalar() || 6149 exp.e1.checkReadModifyWrite(exp.op, exp.e2) || 6150 exp.e1.checkSharedAccess(sc)) 6151 return setError(); 6152 6153 int arith = (exp.op == EXP.addAssign || exp.op == EXP.minAssign || exp.op == EXP.mulAssign || exp.op == EXP.divAssign || exp.op == EXP.modAssign || exp.op == EXP.powAssign); 6154 int bitwise = (exp.op == EXP.andAssign || exp.op == EXP.orAssign || exp.op == EXP.xorAssign); 6155 int shift = (exp.op == EXP.leftShiftAssign || exp.op == EXP.rightShiftAssign || exp.op == EXP.unsignedRightShiftAssign); 6156 6157 if (bitwise && exp.type.toBasetype().ty == Tbool) 6158 exp.e2 = exp.e2.implicitCastTo(sc, exp.type); 6159 else if (exp.checkNoBool()) 6160 return setError(); 6161 6162 if ((exp.op == EXP.addAssign || exp.op == EXP.minAssign) && exp.e1.type.toBasetype().ty == Tpointer && exp.e2.type.toBasetype().isintegral()) 6163 { 6164 result = scaleFactor(exp, sc); 6165 return; 6166 } 6167 6168 if (Expression ex = typeCombine(exp, sc)) 6169 { 6170 result = ex; 6171 return; 6172 } 6173 6174 if (arith && (exp.checkArithmeticBin() || exp.checkSharedAccessBin(sc))) 6175 return setError(); 6176 if ((bitwise || shift) && (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc))) 6177 return setError(); 6178 6179 if (shift) 6180 { 6181 if (exp.e2.type.toBasetype().ty != Tvector) 6182 exp.e2 = exp.e2.castTo(sc, Type.tshiftcnt); 6183 } 6184 6185 if (!target.isVectorOpSupported(exp.type.toBasetype(), exp.op, exp.e2.type.toBasetype())) 6186 { 6187 result = exp.incompatibleTypes(); 6188 return; 6189 } 6190 6191 if (exp.e1.op == EXP.error || exp.e2.op == EXP.error) 6192 return setError(); 6193 6194 e = exp.checkOpAssignTypes(sc); 6195 if (e.op == EXP.error) 6196 { 6197 result = e; 6198 return; 6199 } 6200 6201 assert(e.op == EXP.assign || e == exp); 6202 result = (cast(BinExp)e).reorderSettingAAElem(sc); 6203 } 6204 6205 private Expression compileIt(MixinExp exp) 6206 { 6207 OutBuffer buf; 6208 if (expressionsToString(buf, sc, exp.exps)) 6209 return null; 6210 6211 uint errors = global.errors; 6212 const len = buf.length; 6213 const str = buf.extractChars()[0 .. len]; 6214 const bool doUnittests = global.params.useUnitTests || global.params.ddoc.doOutput || global.params.dihdr.doOutput; 6215 auto loc = adjustLocForMixin(str, exp.loc, global.params.mixinOut); 6216 scope p = new Parser!ASTCodegen(loc, sc._module, str, false, global.errorSink, &global.compileEnv, doUnittests); 6217 p.transitionIn = global.params.vin; 6218 p.nextToken(); 6219 //printf("p.loc.linnum = %d\n", p.loc.linnum); 6220 6221 Expression e = p.parseExpression(); 6222 if (global.errors != errors) 6223 return null; 6224 6225 if (p.token.value != TOK.endOfFile) 6226 { 6227 exp.error("incomplete mixin expression `%s`", str.ptr); 6228 return null; 6229 } 6230 return e; 6231 } 6232 6233 override void visit(MixinExp exp) 6234 { 6235 /* https://dlang.org/spec/expression.html#mixin_expressions 6236 */ 6237 6238 static if (LOGSEMANTIC) 6239 { 6240 printf("MixinExp::semantic('%s')\n", exp.toChars()); 6241 } 6242 6243 auto e = compileIt(exp); 6244 if (!e) 6245 return setError(); 6246 result = e.expressionSemantic(sc); 6247 } 6248 6249 override void visit(ImportExp e) 6250 { 6251 static if (LOGSEMANTIC) 6252 { 6253 printf("ImportExp::semantic('%s')\n", e.toChars()); 6254 } 6255 6256 auto se = semanticString(sc, e.e1, "file name argument"); 6257 if (!se) 6258 return setError(); 6259 se = se.toUTF8(sc); 6260 6261 auto namez = se.toStringz(); 6262 if (!global.filePath) 6263 { 6264 e.error("need `-J` switch to import text file `%s`", namez.ptr); 6265 return setError(); 6266 } 6267 6268 /* Be wary of CWE-22: Improper Limitation of a Pathname to a Restricted Directory 6269 * ('Path Traversal') attacks. 6270 * https://cwe.mitre.org/data/definitions/22.html 6271 */ 6272 6273 if (FileName.absolute(namez)) 6274 { 6275 e.error("absolute path is not allowed in import expression: `%s`", se.toChars()); 6276 return setError(); 6277 } 6278 6279 auto idxReserved = FileName.findReservedChar(namez); 6280 if (idxReserved != size_t.max) 6281 { 6282 e.error("`%s` is not a valid filename on this platform", se.toChars()); 6283 e.errorSupplemental("Character `'%c'` is reserved and cannot be used", namez[idxReserved]); 6284 return setError(); 6285 } 6286 6287 if (FileName.refersToParentDir(namez)) 6288 { 6289 e.error("path refers to parent (`..`) directory: `%s`", se.toChars()); 6290 return setError(); 6291 } 6292 6293 auto resolvedNamez = FileName.searchPath(global.filePath, namez, false); 6294 if (!resolvedNamez) 6295 { 6296 e.error("file `%s` cannot be found or not in a path specified with `-J`", se.toChars()); 6297 e.errorSupplemental("Path(s) searched (as provided by `-J`):"); 6298 foreach (idx, path; *global.filePath) 6299 { 6300 const attr = FileName.exists(path); 6301 const(char)* err = attr == 2 ? "" : 6302 (attr == 1 ? " (not a directory)" : " (path not found)"); 6303 e.errorSupplemental("[%llu]: `%s`%s", cast(ulong)idx, path, err); 6304 } 6305 return setError(); 6306 } 6307 6308 sc._module.contentImportedFiles.push(resolvedNamez.ptr); 6309 if (global.params.verbose) 6310 { 6311 const slice = se.peekString(); 6312 message("file %.*s\t(%s)", cast(int)slice.length, slice.ptr, resolvedNamez.ptr); 6313 } 6314 if (global.params.moduleDeps.buffer !is null) 6315 { 6316 OutBuffer* ob = global.params.moduleDeps.buffer; 6317 Module imod = sc._module; 6318 6319 if (!global.params.moduleDeps.name) 6320 ob.writestring("depsFile "); 6321 ob.writestring(imod.toPrettyChars()); 6322 ob.writestring(" ("); 6323 escapePath(ob, imod.srcfile.toChars()); 6324 ob.writestring(") : "); 6325 if (global.params.moduleDeps.name) 6326 ob.writestring("string : "); 6327 ob.write(se.peekString()); 6328 ob.writestring(" ("); 6329 escapePath(ob, resolvedNamez.ptr); 6330 ob.writestring(")"); 6331 ob.writenl(); 6332 } 6333 if (global.params.makeDeps.doOutput) 6334 { 6335 global.params.makeDeps.files.push(resolvedNamez.ptr); 6336 } 6337 6338 { 6339 auto fileName = FileName(resolvedNamez); 6340 if (auto fmResult = global.fileManager.lookup(fileName)) 6341 { 6342 se = new StringExp(e.loc, fmResult); 6343 } 6344 else 6345 { 6346 e.error("cannot read file `%s`", resolvedNamez.ptr); 6347 return setError(); 6348 } 6349 } 6350 result = se.expressionSemantic(sc); 6351 } 6352 6353 override void visit(AssertExp exp) 6354 { 6355 // https://dlang.org/spec/expression.html#assert_expressions 6356 static if (LOGSEMANTIC) 6357 { 6358 printf("AssertExp::semantic('%s')\n", exp.toChars()); 6359 } 6360 6361 const generateMsg = !exp.msg && 6362 sc.needsCodegen() && // let ctfe interpreter handle the error message 6363 global.params.checkAction == CHECKACTION.context && 6364 global.params.useAssert == CHECKENABLE.on; 6365 Expression temporariesPrefix; 6366 6367 if (generateMsg) 6368 // no message - use assert expression as msg 6369 { 6370 if (!verifyHookExist(exp.loc, *sc, Id._d_assert_fail, "generating assert messages")) 6371 return setError(); 6372 6373 /* 6374 { 6375 auto a = e1, b = e2; 6376 assert(a == b, _d_assert_fail!"=="(a, b)); 6377 }() 6378 */ 6379 6380 /* 6381 Stores the result of an operand expression into a temporary 6382 if necessary, e.g. if it is an impure fuction call containing side 6383 effects as in https://issues.dlang.org/show_bug.cgi?id=20114 6384 6385 Params: 6386 op = an expression which may require a temporary (added to 6387 `temporariesPrefix`: `auto tmp = op`) and will be replaced 6388 by `tmp` if necessary 6389 6390 Returns: (possibly replaced) `op` 6391 */ 6392 Expression maybePromoteToTmp(ref Expression op) 6393 { 6394 // https://issues.dlang.org/show_bug.cgi?id=20989 6395 // Flag that _d_assert_fail will never dereference `array.ptr` to avoid safety 6396 // errors for `assert(!array.ptr)` => `_d_assert_fail!"!"(array.ptr)` 6397 { 6398 auto die = op.isDotIdExp(); 6399 if (die && die.ident == Id.ptr) 6400 die.noderef = true; 6401 } 6402 6403 op = op.expressionSemantic(sc); 6404 op = resolveProperties(sc, op); 6405 6406 // Detect assert's using static operator overloads (e.g. `"var" in environment`) 6407 if (auto te = op.isTypeExp()) 6408 { 6409 // Replace the TypeExp with it's textual representation 6410 // Including "..." in the error message isn't quite right but 6411 // proper solutions require more drastic changes, e.g. directly 6412 // using miniFormat and combine instead of calling _d_assert_fail 6413 auto name = new StringExp(te.loc, te.toString()); 6414 return name.expressionSemantic(sc); 6415 } 6416 6417 // Create a temporary for expressions with side effects 6418 // Defensively assume that function calls may have side effects even 6419 // though it's not detected by hasSideEffect (e.g. `debug puts("Hello")` ) 6420 // Rewriting CallExp's also avoids some issues with the inliner/debug generation 6421 if (op.hasSideEffect(true)) 6422 { 6423 // Don't create an invalid temporary for void-expressions 6424 // Further semantic will issue an appropriate error 6425 if (op.type.ty == Tvoid) 6426 return op; 6427 6428 // https://issues.dlang.org/show_bug.cgi?id=21590 6429 // Don't create unnecessary temporaries and detect `assert(a = b)` 6430 if (op.isAssignExp() || op.isBinAssignExp()) 6431 { 6432 auto left = (cast(BinExp) op).e1; 6433 6434 // Find leftmost expression to handle other rewrites, 6435 // e.g. --(++a) => a += 1 -= 1 6436 while (left.isAssignExp() || left.isBinAssignExp()) 6437 left = (cast(BinExp) left).e1; 6438 6439 // Only use the assignee if it's a variable and skip 6440 // other lvalues (e.g. ref's returned by functions) 6441 if (left.isVarExp()) 6442 return left; 6443 6444 // Sanity check that `op` can be converted to boolean 6445 // But don't raise errors for assignments enclosed in another expression 6446 if (op is exp.e1) 6447 op.toBoolean(sc); 6448 } 6449 6450 // Tuples with side-effects already receive a temporary during semantic 6451 if (op.type.isTypeTuple()) 6452 { 6453 auto te = op.isTupleExp(); 6454 assert(te); 6455 6456 // Create a new tuple without the associated temporary 6457 auto res = new TupleExp(op.loc, te.exps); 6458 return res.expressionSemantic(sc); 6459 } 6460 6461 const stc = op.isLvalue() ? STC.ref_ : 0; 6462 auto tmp = copyToTemp(stc, "__assertOp", op); 6463 tmp.dsymbolSemantic(sc); 6464 6465 auto decl = new DeclarationExp(op.loc, tmp); 6466 temporariesPrefix = Expression.combine(temporariesPrefix, decl); 6467 6468 op = new VarExp(op.loc, tmp); 6469 op = op.expressionSemantic(sc); 6470 } 6471 return op; 6472 } 6473 6474 // if the assert condition is a mixin expression, try to compile it 6475 if (auto ce = exp.e1.isMixinExp()) 6476 { 6477 if (auto e1 = compileIt(ce)) 6478 exp.e1 = e1; 6479 } 6480 6481 Expressions* es; 6482 Objects* tiargs; 6483 Loc loc = exp.e1.loc; 6484 6485 const op = exp.e1.op; 6486 bool isEqualsCallExpression; 6487 if (const callExp = exp.e1.isCallExp()) 6488 { 6489 // https://issues.dlang.org/show_bug.cgi?id=20331 6490 // callExp.f may be null if the assert contains a call to 6491 // a function pointer or literal 6492 if (const callExpFunc = callExp.f) 6493 { 6494 const callExpIdent = callExpFunc.ident; 6495 isEqualsCallExpression = callExpIdent == Id.__equals || 6496 callExpIdent == Id.eq; 6497 } 6498 } 6499 if (op == EXP.equal || op == EXP.notEqual || 6500 op == EXP.lessThan || op == EXP.greaterThan || 6501 op == EXP.lessOrEqual || op == EXP.greaterOrEqual || 6502 op == EXP.identity || op == EXP.notIdentity || 6503 op == EXP.in_ || 6504 isEqualsCallExpression) 6505 { 6506 es = new Expressions(3); 6507 tiargs = new Objects(1); 6508 6509 if (isEqualsCallExpression) 6510 { 6511 auto callExp = cast(CallExp) exp.e1; 6512 auto args = callExp.arguments; 6513 6514 // structs with opEquals get rewritten to a DotVarExp: 6515 // a.opEquals(b) 6516 // https://issues.dlang.org/show_bug.cgi?id=20100 6517 if (args.length == 1) 6518 { 6519 auto dv = callExp.e1.isDotVarExp(); 6520 assert(dv); 6521 6522 // runtime args 6523 (*es)[1] = maybePromoteToTmp(dv.e1); 6524 (*es)[2] = maybePromoteToTmp((*args)[0]); 6525 } 6526 else 6527 { 6528 // runtime args 6529 (*es)[1] = maybePromoteToTmp((*args)[0]); 6530 (*es)[2] = maybePromoteToTmp((*args)[1]); 6531 } 6532 } 6533 else 6534 { 6535 auto binExp = cast(EqualExp) exp.e1; 6536 6537 // runtime args 6538 (*es)[1] = maybePromoteToTmp(binExp.e1); 6539 (*es)[2] = maybePromoteToTmp(binExp.e2); 6540 } 6541 6542 // template args 6543 Expression comp = new StringExp(loc, isEqualsCallExpression ? "==" : EXPtoString(exp.e1.op)); 6544 comp = comp.expressionSemantic(sc); 6545 (*es)[0] = comp; 6546 (*tiargs)[0] = (*es)[1].type; 6547 } 6548 6549 // Format exp.e1 before any additional boolean conversion 6550 // Ignore &&/|| because "assert(...) failed" is more informative than "false != true" 6551 else if (op != EXP.andAnd && op != EXP.orOr) 6552 { 6553 es = new Expressions(2); 6554 tiargs = new Objects(1); 6555 6556 if (auto ne = exp.e1.isNotExp()) 6557 { 6558 // Fetch the (potential non-bool) expression and fold 6559 // (n) negations into (n % 2) negations, e.g. !!a => a 6560 for (bool neg = true; ; neg = !neg) 6561 { 6562 if (auto ne2 = ne.e1.isNotExp()) 6563 ne = ne2; 6564 else 6565 { 6566 (*es)[0] = new StringExp(loc, neg ? "!" : ""); 6567 (*es)[1] = maybePromoteToTmp(ne.e1); 6568 break; 6569 } 6570 } 6571 } 6572 else 6573 { // Simply format exp.e1 6574 (*es)[0] = new StringExp(loc, ""); 6575 (*es)[1] = maybePromoteToTmp(exp.e1); 6576 } 6577 6578 (*tiargs)[0] = (*es)[1].type; 6579 6580 // Passing __ctfe to auto ref infers ref and aborts compilation: 6581 // "cannot modify compiler-generated variable __ctfe" 6582 auto ve = (*es)[1].isVarExp(); 6583 if (ve && ve.var.ident == Id.ctfe) 6584 { 6585 exp.msg = new StringExp(loc, "assert(__ctfe) failed!"); 6586 goto LSkip; 6587 } 6588 } 6589 else 6590 { 6591 OutBuffer buf; 6592 buf.printf("%s failed", exp.toChars()); 6593 exp.msg = new StringExp(Loc.initial, buf.extractSlice()); 6594 goto LSkip; 6595 } 6596 6597 Expression __assertFail = new IdentifierExp(exp.loc, Id.empty); 6598 auto assertFail = new DotIdExp(loc, __assertFail, Id.object); 6599 6600 auto dt = new DotTemplateInstanceExp(loc, assertFail, Id._d_assert_fail, tiargs); 6601 auto ec = CallExp.create(loc, dt, es); 6602 exp.msg = ec; 6603 } 6604 6605 LSkip: 6606 if (Expression ex = unaSemantic(exp, sc)) 6607 { 6608 result = ex; 6609 return; 6610 } 6611 6612 exp.e1 = resolveProperties(sc, exp.e1); 6613 // BUG: see if we can do compile time elimination of the Assert 6614 exp.e1 = exp.e1.optimize(WANTvalue); 6615 exp.e1 = exp.e1.toBoolean(sc); 6616 6617 if (exp.e1.op == EXP.error) 6618 { 6619 result = exp.e1; 6620 return; 6621 } 6622 6623 if (exp.msg) 6624 { 6625 exp.msg = expressionSemantic(exp.msg, sc); 6626 exp.msg = resolveProperties(sc, exp.msg); 6627 exp.msg = exp.msg.implicitCastTo(sc, Type.tchar.constOf().arrayOf()); 6628 exp.msg = exp.msg.optimize(WANTvalue); 6629 checkParamArgumentEscape(sc, null, null, null, STC.undefined_, exp.msg, true, false); 6630 } 6631 6632 if (exp.msg && exp.msg.op == EXP.error) 6633 { 6634 result = exp.msg; 6635 return; 6636 } 6637 6638 auto f1 = checkNonAssignmentArrayOp(exp.e1); 6639 auto f2 = exp.msg && checkNonAssignmentArrayOp(exp.msg); 6640 if (f1 || f2) 6641 return setError(); 6642 6643 if (exp.e1.toBool().hasValue(false)) 6644 { 6645 /* This is an `assert(0)` which means halt program execution 6646 */ 6647 FuncDeclaration fd = sc.parent.isFuncDeclaration(); 6648 if (fd) 6649 fd.hasReturnExp |= 4; 6650 sc.ctorflow.orCSX(CSX.halt); 6651 6652 if (global.params.useAssert == CHECKENABLE.off) 6653 { 6654 Expression e = new HaltExp(exp.loc); 6655 e = e.expressionSemantic(sc); 6656 result = e; 6657 return; 6658 } 6659 6660 // Only override the type when it isn't already some flavour of noreturn, 6661 // e.g. when this assert was generated by defaultInitLiteral 6662 if (!exp.type || !exp.type.isTypeNoreturn()) 6663 exp.type = Type.tnoreturn; 6664 } 6665 else 6666 exp.type = Type.tvoid; 6667 6668 result = !temporariesPrefix 6669 ? exp 6670 : Expression.combine(temporariesPrefix, exp).expressionSemantic(sc); 6671 } 6672 6673 override void visit(ThrowExp te) 6674 { 6675 import dmd.statementsem; 6676 6677 if (throwSemantic(te.loc, te.e1, sc)) 6678 result = te; 6679 else 6680 setError(); 6681 } 6682 6683 override void visit(DotIdExp exp) 6684 { 6685 static if (LOGSEMANTIC) 6686 { 6687 printf("DotIdExp::semantic(this = %p, '%s')\n", exp, exp.toChars()); 6688 //printf("e1.op = %d, '%s'\n", e1.op, Token.toChars(e1.op)); 6689 } 6690 6691 if (sc.flags & SCOPE.Cfile) 6692 { 6693 /* See if need to rewrite the AST because of cast/call ambiguity 6694 */ 6695 if (auto e = castCallAmbiguity(exp, sc)) 6696 { 6697 result = expressionSemantic(e, sc); 6698 return; 6699 } 6700 6701 if (exp.arrow) // ImportC only 6702 exp.e1 = exp.e1.expressionSemantic(sc).arrayFuncConv(sc); 6703 6704 if (exp.ident == Id.__xalignof && exp.e1.isTypeExp()) 6705 { 6706 // C11 6.5.3 says _Alignof only applies to types 6707 Expression e; 6708 Type t; 6709 Dsymbol s; 6710 dmd.typesem.resolve(exp.e1.type, exp.e1.loc, sc, e, t, s, true); 6711 if (e) 6712 { 6713 exp.e1.error("argument to `_Alignof` must be a type"); 6714 return setError(); 6715 } 6716 else if (t) 6717 { 6718 // Note similarity to getProperty() implementation of __xalignof 6719 const explicitAlignment = t.alignment(); 6720 const naturalAlignment = t.alignsize(); 6721 const actualAlignment = (explicitAlignment.isDefault() ? naturalAlignment : explicitAlignment.get()); 6722 result = new IntegerExp(exp.loc, actualAlignment, Type.tsize_t); 6723 } 6724 else if (s) 6725 { 6726 exp.e1.error("argument to `_Alignof` must be a type"); 6727 return setError(); 6728 } 6729 else 6730 assert(0); 6731 return; 6732 } 6733 6734 if (exp.ident != Id.__sizeof) 6735 { 6736 result = fieldLookup(exp.e1, sc, exp.ident); 6737 return; 6738 } 6739 } 6740 6741 Expression e = exp.dotIdSemanticProp(sc, 1); 6742 6743 if (e && isDotOpDispatch(e)) 6744 { 6745 auto ode = e; 6746 uint errors = global.startGagging(); 6747 e = resolvePropertiesX(sc, e); 6748 // Any error or if 'e' is not resolved, go to UFCS 6749 if (global.endGagging(errors) || e is ode) 6750 e = null; /* fall down to UFCS */ 6751 else 6752 { 6753 result = e; 6754 return; 6755 } 6756 } 6757 if (!e) // if failed to find the property 6758 { 6759 /* If ident is not a valid property, rewrite: 6760 * e1.ident 6761 * as: 6762 * .ident(e1) 6763 */ 6764 e = resolveUFCSProperties(sc, exp); 6765 } 6766 result = e; 6767 } 6768 6769 override void visit(DotTemplateExp e) 6770 { 6771 if (e.type) 6772 { 6773 result = e; 6774 return; 6775 } 6776 if (Expression ex = unaSemantic(e, sc)) 6777 { 6778 result = ex; 6779 return; 6780 } 6781 // 'void' like TemplateExp 6782 e.type = Type.tvoid; 6783 result = e; 6784 } 6785 6786 override void visit(DotVarExp exp) 6787 { 6788 static if (LOGSEMANTIC) 6789 { 6790 printf("DotVarExp::semantic('%s')\n", exp.toChars()); 6791 } 6792 if (exp.type) 6793 { 6794 result = exp; 6795 return; 6796 } 6797 6798 exp.var = exp.var.toAlias().isDeclaration(); 6799 6800 exp.e1 = exp.e1.expressionSemantic(sc); 6801 6802 if (auto tup = exp.var.isTupleDeclaration()) 6803 { 6804 /* Replace: 6805 * e1.tuple(a, b, c) 6806 * with: 6807 * tuple(e1.a, e1.b, e1.c) 6808 */ 6809 Expression e0; 6810 Expression ev = sc.func ? extractSideEffect(sc, "__tup", e0, exp.e1) : exp.e1; 6811 6812 auto exps = new Expressions(); 6813 exps.reserve(tup.objects.length); 6814 for (size_t i = 0; i < tup.objects.length; i++) 6815 { 6816 RootObject o = (*tup.objects)[i]; 6817 Expression e; 6818 Declaration var; 6819 switch (o.dyncast()) with (DYNCAST) 6820 { 6821 case expression: 6822 e = cast(Expression)o; 6823 if (auto se = e.isDsymbolExp()) 6824 var = se.s.isDeclaration(); 6825 else if (auto ve = e.isVarExp()) 6826 if (!ve.var.isFuncDeclaration()) 6827 // Exempt functions for backwards compatibility reasons. 6828 // See: https://issues.dlang.org/show_bug.cgi?id=20470#c1 6829 var = ve.var; 6830 break; 6831 case dsymbol: 6832 Dsymbol s = cast(Dsymbol) o; 6833 Declaration d = s.isDeclaration(); 6834 if (!d || d.isFuncDeclaration()) 6835 // Exempt functions for backwards compatibility reasons. 6836 // See: https://issues.dlang.org/show_bug.cgi?id=20470#c1 6837 e = new DsymbolExp(exp.loc, s); 6838 else 6839 var = d; 6840 break; 6841 case type: 6842 e = new TypeExp(exp.loc, cast(Type)o); 6843 break; 6844 default: 6845 exp.error("`%s` is not an expression", o.toChars()); 6846 return setError(); 6847 } 6848 if (var) 6849 e = new DotVarExp(exp.loc, ev, var); 6850 exps.push(e); 6851 } 6852 6853 Expression e = new TupleExp(exp.loc, e0, exps); 6854 e = e.expressionSemantic(sc); 6855 result = e; 6856 return; 6857 } 6858 else if (auto ad = exp.var.isAliasDeclaration()) 6859 { 6860 if (auto t = ad.getType()) 6861 { 6862 result = new TypeExp(exp.loc, t).expressionSemantic(sc); 6863 return; 6864 } 6865 } 6866 6867 exp.e1 = exp.e1.addDtorHook(sc); 6868 6869 Type t1 = exp.e1.type; 6870 6871 if (FuncDeclaration fd = exp.var.isFuncDeclaration()) 6872 { 6873 // for functions, do checks after overload resolution 6874 if (!fd.functionSemantic()) 6875 return setError(); 6876 6877 /* https://issues.dlang.org/show_bug.cgi?id=13843 6878 * If fd obviously has no overloads, we should 6879 * normalize AST, and it will give a chance to wrap fd with FuncExp. 6880 */ 6881 if ((fd.isNested() && !fd.isThis()) || fd.isFuncLiteralDeclaration()) 6882 { 6883 // (e1, fd) 6884 auto e = symbolToExp(fd, exp.loc, sc, false); 6885 result = Expression.combine(exp.e1, e); 6886 return; 6887 } 6888 6889 exp.type = fd.type; 6890 assert(exp.type); 6891 } 6892 else if (OverDeclaration od = exp.var.isOverDeclaration()) 6893 { 6894 exp.type = Type.tvoid; // ambiguous type? 6895 } 6896 else 6897 { 6898 exp.type = exp.var.type; 6899 if (!exp.type && global.errors) // var is goofed up, just return error. 6900 return setError(); 6901 assert(exp.type); 6902 6903 if (t1.ty == Tpointer) 6904 t1 = t1.nextOf(); 6905 6906 exp.type = exp.type.addMod(t1.mod); 6907 6908 // https://issues.dlang.org/show_bug.cgi?id=23109 6909 // Run semantic on the DotVarExp type 6910 if (auto handle = exp.type.isClassHandle()) 6911 { 6912 if (handle.semanticRun < PASS.semanticdone && !handle.isBaseInfoComplete()) 6913 handle.dsymbolSemantic(null); 6914 } 6915 6916 Dsymbol vparent = exp.var.toParent(); 6917 AggregateDeclaration ad = vparent ? vparent.isAggregateDeclaration() : null; 6918 if (Expression e1x = getRightThis(exp.loc, sc, ad, exp.e1, exp.var, 1)) 6919 exp.e1 = e1x; 6920 else 6921 { 6922 /* Later checkRightThis will report correct error for invalid field variable access. 6923 */ 6924 Expression e = new VarExp(exp.loc, exp.var); 6925 e = e.expressionSemantic(sc); 6926 result = e; 6927 return; 6928 } 6929 checkAccess(exp.loc, sc, exp.e1, exp.var); 6930 6931 VarDeclaration v = exp.var.isVarDeclaration(); 6932 if (v && (v.isDataseg() || (v.storage_class & STC.manifest))) 6933 { 6934 Expression e = expandVar(WANTvalue, v); 6935 if (e) 6936 { 6937 result = e; 6938 return; 6939 } 6940 } 6941 6942 if (v && (v.isDataseg() || // fix https://issues.dlang.org/show_bug.cgi?id=8238 6943 (!v.needThis() && v.semanticRun > PASS.initial))) // fix https://issues.dlang.org/show_bug.cgi?id=17258 6944 { 6945 // (e1, v) 6946 checkAccess(exp.loc, sc, exp.e1, v); 6947 Expression e = new VarExp(exp.loc, v); 6948 e = new CommaExp(exp.loc, exp.e1, e); 6949 e = e.expressionSemantic(sc); 6950 result = e; 6951 return; 6952 } 6953 } 6954 //printf("-DotVarExp::semantic('%s')\n", toChars()); 6955 result = exp; 6956 } 6957 6958 override void visit(DotTemplateInstanceExp exp) 6959 { 6960 static if (LOGSEMANTIC) 6961 { 6962 printf("DotTemplateInstanceExp::semantic('%s')\n", exp.toChars()); 6963 } 6964 if (exp.type) 6965 { 6966 result = exp; 6967 return; 6968 } 6969 // Indicate we need to resolve by UFCS. 6970 Expression e = exp.dotTemplateSemanticProp(sc, DotExpFlag.gag); 6971 if (!e) 6972 e = resolveUFCSProperties(sc, exp); 6973 if (e is exp) 6974 e.type = Type.tvoid; // Unresolved type, because it needs inference 6975 result = e; 6976 } 6977 6978 override void visit(DelegateExp e) 6979 { 6980 static if (LOGSEMANTIC) 6981 { 6982 printf("DelegateExp::semantic('%s')\n", e.toChars()); 6983 } 6984 if (e.type) 6985 { 6986 result = e; 6987 return; 6988 } 6989 6990 e.e1 = e.e1.expressionSemantic(sc); 6991 6992 e.type = new TypeDelegate(e.func.type.isTypeFunction()); 6993 e.type = e.type.typeSemantic(e.loc, sc); 6994 6995 FuncDeclaration f = e.func.toAliasFunc(); 6996 AggregateDeclaration ad = f.isMemberLocal(); 6997 if (f.needThis()) 6998 e.e1 = getRightThis(e.loc, sc, ad, e.e1, f); 6999 7000 if (f.type.ty == Tfunction) 7001 { 7002 TypeFunction tf = cast(TypeFunction)f.type; 7003 if (!MODmethodConv(e.e1.type.mod, f.type.mod)) 7004 { 7005 OutBuffer thisBuf, funcBuf; 7006 MODMatchToBuffer(&thisBuf, e.e1.type.mod, tf.mod); 7007 MODMatchToBuffer(&funcBuf, tf.mod, e.e1.type.mod); 7008 e.error("%smethod `%s` is not callable using a %s`%s`", 7009 funcBuf.peekChars(), f.toPrettyChars(), thisBuf.peekChars(), e.e1.toChars()); 7010 return setError(); 7011 } 7012 } 7013 if (ad && ad.isClassDeclaration() && ad.type != e.e1.type) 7014 { 7015 // A downcast is required for interfaces 7016 // https://issues.dlang.org/show_bug.cgi?id=3706 7017 e.e1 = new CastExp(e.loc, e.e1, ad.type); 7018 e.e1 = e.e1.expressionSemantic(sc); 7019 } 7020 result = e; 7021 // declare dual-context container 7022 if (f.hasDualContext() && !sc.intypeof && sc.func) 7023 { 7024 // check access to second `this` 7025 if (AggregateDeclaration ad2 = f.isMember2()) 7026 { 7027 Expression te = new ThisExp(e.loc).expressionSemantic(sc); 7028 if (te.op != EXP.error) 7029 te = getRightThis(e.loc, sc, ad2, te, f); 7030 if (te.op == EXP.error) 7031 { 7032 e.error("need `this` of type `%s` to make delegate from function `%s`", ad2.toChars(), f.toChars()); 7033 return setError(); 7034 } 7035 } 7036 VarDeclaration vthis2 = makeThis2Argument(e.loc, sc, f); 7037 e.vthis2 = vthis2; 7038 Expression de = new DeclarationExp(e.loc, vthis2); 7039 result = Expression.combine(de, result); 7040 result = result.expressionSemantic(sc); 7041 } 7042 } 7043 7044 override void visit(DotTypeExp exp) 7045 { 7046 static if (LOGSEMANTIC) 7047 { 7048 printf("DotTypeExp::semantic('%s')\n", exp.toChars()); 7049 } 7050 if (exp.type) 7051 { 7052 result = exp; 7053 return; 7054 } 7055 7056 if (auto e = unaSemantic(exp, sc)) 7057 { 7058 result = e; 7059 return; 7060 } 7061 7062 exp.type = exp.sym.getType().addMod(exp.e1.type.mod); 7063 result = exp; 7064 } 7065 7066 override void visit(AddrExp exp) 7067 { 7068 static if (LOGSEMANTIC) 7069 { 7070 printf("AddrExp::semantic('%s')\n", exp.toChars()); 7071 } 7072 if (exp.type) 7073 { 7074 result = exp; 7075 return; 7076 } 7077 7078 if (Expression ex = unaSemantic(exp, sc)) 7079 { 7080 result = ex; 7081 return; 7082 } 7083 7084 if (sc.flags & SCOPE.Cfile) 7085 { 7086 /* Special handling for &"string"/&(T[]){0, 1} 7087 * since C regards string/array literals as lvalues 7088 */ 7089 auto e = exp.e1; 7090 if(e.isStringExp() || e.isArrayLiteralExp()) 7091 { 7092 e.type = typeSemantic(e.type, Loc.initial, sc); 7093 // if type is already a pointer exp is an illegal expression of the form `&(&"")` 7094 if (!e.type.isTypePointer()) 7095 { 7096 e.type = e.type.pointerTo(); 7097 result = e; 7098 return; 7099 } 7100 else 7101 { 7102 // `toLvalue` call further below is upon exp.e1, omitting & from the error message 7103 exp.toLvalue(sc, null); 7104 return setError(); 7105 } 7106 } 7107 } 7108 7109 int wasCond = exp.e1.op == EXP.question; 7110 7111 if (exp.e1.op == EXP.dotTemplateInstance) 7112 { 7113 DotTemplateInstanceExp dti = cast(DotTemplateInstanceExp)exp.e1; 7114 TemplateInstance ti = dti.ti; 7115 { 7116 //assert(ti.needsTypeInference(sc)); 7117 ti.dsymbolSemantic(sc); 7118 if (!ti.inst || ti.errors) // if template failed to expand 7119 return setError(); 7120 7121 Dsymbol s = ti.toAlias(); 7122 FuncDeclaration f = s.isFuncDeclaration(); 7123 if (f) 7124 { 7125 exp.e1 = new DotVarExp(exp.e1.loc, dti.e1, f); 7126 exp.e1 = exp.e1.expressionSemantic(sc); 7127 } 7128 } 7129 } 7130 else if (exp.e1.op == EXP.scope_) 7131 { 7132 TemplateInstance ti = (cast(ScopeExp)exp.e1).sds.isTemplateInstance(); 7133 if (ti) 7134 { 7135 //assert(ti.needsTypeInference(sc)); 7136 ti.dsymbolSemantic(sc); 7137 if (!ti.inst || ti.errors) // if template failed to expand 7138 return setError(); 7139 7140 Dsymbol s = ti.toAlias(); 7141 FuncDeclaration f = s.isFuncDeclaration(); 7142 if (f) 7143 { 7144 exp.e1 = new VarExp(exp.e1.loc, f); 7145 exp.e1 = exp.e1.expressionSemantic(sc); 7146 } 7147 } 7148 } 7149 /* https://issues.dlang.org/show_bug.cgi?id=809 7150 * 7151 * If the address of a lazy variable is taken, 7152 * the expression is rewritten so that the type 7153 * of it is the delegate type. This means that 7154 * the symbol is not going to represent a call 7155 * to the delegate anymore, but rather, the 7156 * actual symbol. 7157 */ 7158 if (auto ve = exp.e1.isVarExp()) 7159 { 7160 if (ve.var.storage_class & STC.lazy_) 7161 { 7162 exp.e1 = exp.e1.expressionSemantic(sc); 7163 exp.e1 = resolveProperties(sc, exp.e1); 7164 if (auto callExp = exp.e1.isCallExp()) 7165 { 7166 if (callExp.e1.type.toBasetype().ty == Tdelegate) 7167 { 7168 /* https://issues.dlang.org/show_bug.cgi?id=20551 7169 * 7170 * Cannot take address of lazy parameter in @safe code 7171 * because it might end up being a pointer to undefined 7172 * memory. 7173 */ 7174 if (1) 7175 { 7176 if (sc.setUnsafe(false, exp.loc, 7177 "cannot take address of lazy parameter `%s` in `@safe` function `%s`", ve, sc.func)) 7178 { 7179 setError(); 7180 return; 7181 } 7182 } 7183 VarExp ve2 = callExp.e1.isVarExp(); 7184 ve2.delegateWasExtracted = true; 7185 ve2.var.storage_class |= STC.scope_; 7186 result = ve2; 7187 return; 7188 } 7189 } 7190 } 7191 } 7192 7193 exp.e1 = exp.e1.toLvalue(sc, null); 7194 if (exp.e1.op == EXP.error) 7195 { 7196 result = exp.e1; 7197 return; 7198 } 7199 if (checkNonAssignmentArrayOp(exp.e1)) 7200 return setError(); 7201 7202 if (!exp.e1.type) 7203 { 7204 exp.error("cannot take address of `%s`", exp.e1.toChars()); 7205 return setError(); 7206 } 7207 if (!checkAddressable(exp, sc)) 7208 return setError(); 7209 7210 bool hasOverloads; 7211 if (auto f = isFuncAddress(exp, &hasOverloads)) 7212 { 7213 if (!hasOverloads && f.checkForwardRef(exp.loc)) 7214 return setError(); 7215 } 7216 else if (!exp.e1.type.deco) 7217 { 7218 // try to resolve the type 7219 exp.e1.type = exp.e1.type.typeSemantic(exp.e1.loc, null); 7220 if (!exp.e1.type.deco) // still couldn't resolve it 7221 { 7222 if (auto ve = exp.e1.isVarExp()) 7223 { 7224 Declaration d = ve.var; 7225 exp.error("forward reference to %s `%s`", d.kind(), d.toChars()); 7226 } 7227 else 7228 exp.error("forward reference to type `%s` of expression `%s`", exp.e1.type.toChars(), exp.e1.toChars()); 7229 return setError(); 7230 } 7231 } 7232 7233 exp.type = exp.e1.type.pointerTo(); 7234 7235 // See if this should really be a delegate 7236 if (exp.e1.op == EXP.dotVariable) 7237 { 7238 DotVarExp dve = cast(DotVarExp)exp.e1; 7239 FuncDeclaration f = dve.var.isFuncDeclaration(); 7240 if (f) 7241 { 7242 f = f.toAliasFunc(); // FIXME, should see overloads 7243 // https://issues.dlang.org/show_bug.cgi?id=1983 7244 if (!dve.hasOverloads) 7245 f.tookAddressOf++; 7246 7247 Expression e; 7248 if (f.needThis()) 7249 e = new DelegateExp(exp.loc, dve.e1, f, dve.hasOverloads); 7250 else // It is a function pointer. Convert &v.f() --> (v, &V.f()) 7251 e = new CommaExp(exp.loc, dve.e1, new AddrExp(exp.loc, new VarExp(exp.loc, f, dve.hasOverloads))); 7252 e = e.expressionSemantic(sc); 7253 result = e; 7254 return; 7255 } 7256 7257 // Look for misaligned pointer in @safe mode 7258 if (checkUnsafeAccess(sc, dve, !exp.type.isMutable(), true)) 7259 return setError(); 7260 } 7261 else if (exp.e1.op == EXP.variable) 7262 { 7263 VarExp ve = cast(VarExp)exp.e1; 7264 VarDeclaration v = ve.var.isVarDeclaration(); 7265 if (v) 7266 { 7267 if (!checkAddressVar(sc, exp.e1, v)) 7268 return setError(); 7269 7270 ve.checkPurity(sc, v); 7271 } 7272 FuncDeclaration f = ve.var.isFuncDeclaration(); 7273 if (f) 7274 { 7275 /* Because nested functions cannot be overloaded, 7276 * mark here that we took its address because castTo() 7277 * may not be called with an exact match. 7278 * 7279 * https://issues.dlang.org/show_bug.cgi?id=19285 : 7280 * We also need to make sure we aren't inside a typeof. Ideally the compiler 7281 * would do typeof(...) semantic analysis speculatively then collect information 7282 * about what it used rather than relying on what are effectively semantically-global 7283 * variables but it doesn't. 7284 */ 7285 if (!sc.isFromSpeculativeSemanticContext() && (!ve.hasOverloads || (f.isNested() && !f.needThis()))) 7286 { 7287 // TODO: Refactor to use a proper interface that can keep track of causes. 7288 f.tookAddressOf++; 7289 } 7290 7291 if (f.isNested() && !f.needThis()) 7292 { 7293 if (f.isFuncLiteralDeclaration()) 7294 { 7295 if (!f.FuncDeclaration.isNested()) 7296 { 7297 /* Supply a 'null' for a this pointer if no this is available 7298 */ 7299 Expression e = new DelegateExp(exp.loc, new NullExp(exp.loc, Type.tnull), f, ve.hasOverloads); 7300 e = e.expressionSemantic(sc); 7301 result = e; 7302 return; 7303 } 7304 } 7305 Expression e = new DelegateExp(exp.loc, exp.e1, f, ve.hasOverloads); 7306 e = e.expressionSemantic(sc); 7307 result = e; 7308 return; 7309 } 7310 if (f.needThis()) 7311 { 7312 auto memberFunc = hasThis(sc); 7313 if (memberFunc && haveSameThis(memberFunc, f)) 7314 { 7315 /* Should probably supply 'this' after overload resolution, 7316 * not before. 7317 */ 7318 Expression ethis = new ThisExp(exp.loc); 7319 Expression e = new DelegateExp(exp.loc, ethis, f, ve.hasOverloads); 7320 e = e.expressionSemantic(sc); 7321 result = e; 7322 return; 7323 } 7324 if (sc.func && !sc.intypeof && !(sc.flags & SCOPE.debug_)) 7325 { 7326 sc.setUnsafe(false, exp.loc, 7327 "`this` reference necessary to take address of member `%s` in `@safe` function `%s`", 7328 f, sc.func); 7329 } 7330 } 7331 } 7332 } 7333 else if (exp.e1.op == EXP.index) 7334 { 7335 /* For: 7336 * int[3] a; 7337 * &a[i] 7338 * check 'a' the same as for a regular variable 7339 */ 7340 if (VarDeclaration v = expToVariable(exp.e1)) 7341 { 7342 exp.e1.checkPurity(sc, v); 7343 } 7344 } 7345 else if (wasCond) 7346 { 7347 /* a ? b : c was transformed to *(a ? &b : &c), but we still 7348 * need to do safety checks 7349 */ 7350 assert(exp.e1.op == EXP.star); 7351 PtrExp pe = cast(PtrExp)exp.e1; 7352 assert(pe.e1.op == EXP.question); 7353 CondExp ce = cast(CondExp)pe.e1; 7354 assert(ce.e1.op == EXP.address); 7355 assert(ce.e2.op == EXP.address); 7356 7357 // Re-run semantic on the address expressions only 7358 ce.e1.type = null; 7359 ce.e1 = ce.e1.expressionSemantic(sc); 7360 ce.e2.type = null; 7361 ce.e2 = ce.e2.expressionSemantic(sc); 7362 } 7363 result = exp.optimize(WANTvalue); 7364 } 7365 7366 override void visit(PtrExp exp) 7367 { 7368 static if (LOGSEMANTIC) 7369 { 7370 printf("PtrExp::semantic('%s')\n", exp.toChars()); 7371 } 7372 if (exp.type) 7373 { 7374 result = exp; 7375 return; 7376 } 7377 7378 Expression e = exp.op_overload(sc); 7379 if (e) 7380 { 7381 result = e; 7382 return; 7383 } 7384 7385 exp.e1 = exp.e1.arrayFuncConv(sc); 7386 7387 Type tb = exp.e1.type.toBasetype(); 7388 switch (tb.ty) 7389 { 7390 case Tpointer: 7391 exp.type = (cast(TypePointer)tb).next; 7392 break; 7393 7394 case Tsarray: 7395 case Tarray: 7396 if (isNonAssignmentArrayOp(exp.e1)) 7397 goto default; 7398 exp.error("using `*` on an array is no longer supported; use `*(%s).ptr` instead", exp.e1.toChars()); 7399 exp.type = (cast(TypeArray)tb).next; 7400 exp.e1 = exp.e1.castTo(sc, exp.type.pointerTo()); 7401 break; 7402 7403 case Terror: 7404 return setError(); 7405 7406 case Tnull: 7407 exp.type = Type.tnoreturn; // typeof(*null) is bottom type 7408 break; 7409 7410 default: 7411 exp.error("can only `*` a pointer, not a `%s`", exp.e1.type.toChars()); 7412 goto case Terror; 7413 } 7414 7415 if (sc.flags & SCOPE.Cfile && exp.type && exp.type.toBasetype().ty == Tvoid) 7416 { 7417 // https://issues.dlang.org/show_bug.cgi?id=23752 7418 // `&*((void*)(0))` is allowed in C 7419 result = exp; 7420 return; 7421 } 7422 7423 if (exp.checkValue()) 7424 return setError(); 7425 7426 result = exp; 7427 } 7428 7429 override void visit(NegExp exp) 7430 { 7431 static if (LOGSEMANTIC) 7432 { 7433 printf("NegExp::semantic('%s')\n", exp.toChars()); 7434 } 7435 if (exp.type) 7436 { 7437 result = exp; 7438 return; 7439 } 7440 7441 Expression e = exp.op_overload(sc); 7442 if (e) 7443 { 7444 result = e; 7445 return; 7446 } 7447 7448 fix16997(sc, exp); 7449 exp.type = exp.e1.type; 7450 Type tb = exp.type.toBasetype(); 7451 if (tb.ty == Tarray || tb.ty == Tsarray) 7452 { 7453 if (!isArrayOpValid(exp.e1)) 7454 { 7455 result = arrayOpInvalidError(exp); 7456 return; 7457 } 7458 result = exp; 7459 return; 7460 } 7461 if (!target.isVectorOpSupported(tb, exp.op)) 7462 { 7463 result = exp.incompatibleTypes(); 7464 return; 7465 } 7466 if (exp.e1.checkNoBool()) 7467 return setError(); 7468 if (exp.e1.checkArithmetic() || 7469 exp.e1.checkSharedAccess(sc)) 7470 return setError(); 7471 7472 result = exp; 7473 } 7474 7475 override void visit(UAddExp exp) 7476 { 7477 static if (LOGSEMANTIC) 7478 { 7479 printf("UAddExp::semantic('%s')\n", exp.toChars()); 7480 } 7481 assert(!exp.type); 7482 7483 Expression e = exp.op_overload(sc); 7484 if (e) 7485 { 7486 result = e; 7487 return; 7488 } 7489 7490 fix16997(sc, exp); 7491 if (!target.isVectorOpSupported(exp.e1.type.toBasetype(), exp.op)) 7492 { 7493 result = exp.incompatibleTypes(); 7494 return; 7495 } 7496 if (exp.e1.checkNoBool()) 7497 return setError(); 7498 if (exp.e1.checkArithmetic()) 7499 return setError(); 7500 if (exp.e1.checkSharedAccess(sc)) 7501 return setError(); 7502 7503 result = exp.e1; 7504 } 7505 7506 override void visit(ComExp exp) 7507 { 7508 if (exp.type) 7509 { 7510 result = exp; 7511 return; 7512 } 7513 7514 Expression e = exp.op_overload(sc); 7515 if (e) 7516 { 7517 result = e; 7518 return; 7519 } 7520 7521 fix16997(sc, exp); 7522 exp.type = exp.e1.type; 7523 Type tb = exp.type.toBasetype(); 7524 if (tb.ty == Tarray || tb.ty == Tsarray) 7525 { 7526 if (!isArrayOpValid(exp.e1)) 7527 { 7528 result = arrayOpInvalidError(exp); 7529 return; 7530 } 7531 result = exp; 7532 return; 7533 } 7534 if (!target.isVectorOpSupported(tb, exp.op)) 7535 { 7536 result = exp.incompatibleTypes(); 7537 return; 7538 } 7539 if (exp.e1.checkNoBool()) 7540 return setError(); 7541 if (exp.e1.checkIntegral() || 7542 exp.e1.checkSharedAccess(sc)) 7543 return setError(); 7544 7545 result = exp; 7546 } 7547 7548 override void visit(NotExp e) 7549 { 7550 if (e.type) 7551 { 7552 result = e; 7553 return; 7554 } 7555 7556 e.setNoderefOperand(); 7557 7558 // Note there is no operator overload 7559 if (Expression ex = unaSemantic(e, sc)) 7560 { 7561 result = ex; 7562 return; 7563 } 7564 7565 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684 7566 if (e.e1.op == EXP.type) 7567 e.e1 = resolveAliasThis(sc, e.e1); 7568 7569 e.e1 = resolveProperties(sc, e.e1); 7570 e.e1 = e.e1.toBoolean(sc); 7571 if (e.e1.type == Type.terror) 7572 { 7573 result = e.e1; 7574 return; 7575 } 7576 7577 if (!target.isVectorOpSupported(e.e1.type.toBasetype(), e.op)) 7578 { 7579 result = e.incompatibleTypes(); 7580 } 7581 // https://issues.dlang.org/show_bug.cgi?id=13910 7582 // Today NotExp can take an array as its operand. 7583 if (checkNonAssignmentArrayOp(e.e1)) 7584 return setError(); 7585 7586 e.type = (sc && sc.flags & SCOPE.Cfile) ? Type.tint32 : Type.tbool; 7587 result = e; 7588 } 7589 7590 override void visit(DeleteExp exp) 7591 { 7592 // @@@DEPRECATED_2.109@@@ 7593 // 1. Deprecated since 2.079 7594 // 2. Error since 2.099 7595 // 3. Removal of keyword, "delete" can be used for other identities 7596 if (!exp.isRAII) 7597 { 7598 error(exp.loc, "the `delete` keyword is obsolete"); 7599 errorSupplemental(exp.loc, "use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead"); 7600 return setError(); 7601 } 7602 7603 Expression e = exp; 7604 7605 if (Expression ex = unaSemantic(exp, sc)) 7606 { 7607 result = ex; 7608 return; 7609 } 7610 exp.e1 = resolveProperties(sc, exp.e1); 7611 exp.e1 = exp.e1.modifiableLvalue(sc, null); 7612 if (exp.e1.op == EXP.error) 7613 { 7614 result = exp.e1; 7615 return; 7616 } 7617 exp.type = Type.tvoid; 7618 7619 Type tb = exp.e1.type.toBasetype(); 7620 7621 /* Now that `delete` in user code is an error, we only get here when 7622 * `isRAII` has been set to true for the deletion of a `scope class`. */ 7623 if (tb.ty != Tclass) 7624 { 7625 exp.error("cannot delete type `%s`", exp.e1.type.toChars()); 7626 return setError(); 7627 } 7628 7629 ClassDeclaration cd = (cast(TypeClass)tb).sym; 7630 if (cd.isCOMinterface()) 7631 { 7632 /* Because COM classes are deleted by IUnknown.Release() 7633 */ 7634 exp.error("cannot `delete` instance of COM interface `%s`", cd.toChars()); 7635 return setError(); 7636 } 7637 7638 bool err = false; 7639 if (cd.dtor) 7640 { 7641 err |= !cd.dtor.functionSemantic(); 7642 err |= exp.checkPurity(sc, cd.dtor); 7643 err |= exp.checkSafety(sc, cd.dtor); 7644 err |= exp.checkNogc(sc, cd.dtor); 7645 } 7646 if (err) 7647 return setError(); 7648 7649 result = e; 7650 } 7651 7652 override void visit(CastExp exp) 7653 { 7654 static if (LOGSEMANTIC) 7655 { 7656 printf("CastExp::semantic('%s')\n", exp.toChars()); 7657 } 7658 //static int x; assert(++x < 10); 7659 if (exp.type) 7660 { 7661 result = exp; 7662 return; 7663 } 7664 7665 if ((sc && sc.flags & SCOPE.Cfile) && 7666 exp.to && (exp.to.ty == Tident || exp.to.ty == Tsarray) && 7667 (exp.e1.op == EXP.address || exp.e1.op == EXP.star || 7668 exp.e1.op == EXP.uadd || exp.e1.op == EXP.negate)) 7669 { 7670 /* Ambiguous cases arise from CParser if type-name is just an identifier. 7671 * ( identifier ) cast-expression 7672 * ( identifier [expression]) cast-expression 7673 * If we determine that `identifier` is a variable, and cast-expression 7674 * is one of the unary operators (& * + -), then rewrite this cast 7675 * as a binary expression. 7676 */ 7677 Loc loc = exp.loc; 7678 Type t; 7679 Expression e; 7680 Dsymbol s; 7681 exp.to.resolve(loc, sc, e, t, s); 7682 if (e !is null) 7683 { 7684 if (auto ex = exp.e1.isAddrExp()) // (ident) &exp -> (ident & exp) 7685 result = new AndExp(loc, e, ex.e1); 7686 else if (auto ex = exp.e1.isPtrExp()) // (ident) *exp -> (ident * exp) 7687 result = new MulExp(loc, e, ex.e1); 7688 else if (auto ex = exp.e1.isUAddExp()) // (ident) +exp -> (ident + exp) 7689 result = new AddExp(loc, e, ex.e1); 7690 else if (auto ex = exp.e1.isNegExp()) // (ident) -exp -> (ident - exp) 7691 result = new MinExp(loc, e, ex.e1); 7692 7693 assert(result); 7694 result = result.expressionSemantic(sc); 7695 return; 7696 } 7697 } 7698 7699 if (exp.to) 7700 { 7701 exp.to = exp.to.typeSemantic(exp.loc, sc); 7702 if (exp.to == Type.terror) 7703 return setError(); 7704 7705 if (!exp.to.hasPointers()) 7706 exp.setNoderefOperand(); 7707 7708 // When e1 is a template lambda, this cast may instantiate it with 7709 // the type 'to'. 7710 exp.e1 = inferType(exp.e1, exp.to); 7711 } 7712 7713 if (auto e = unaSemantic(exp, sc)) 7714 { 7715 result = e; 7716 return; 7717 } 7718 7719 if (exp.to && !exp.to.isTypeSArray() && !exp.to.isTypeFunction()) 7720 exp.e1 = exp.e1.arrayFuncConv(sc); 7721 7722 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684 7723 if (exp.e1.op == EXP.type) 7724 exp.e1 = resolveAliasThis(sc, exp.e1); 7725 7726 auto e1x = resolveProperties(sc, exp.e1); 7727 if (e1x.op == EXP.error) 7728 { 7729 result = e1x; 7730 return; 7731 } 7732 if (e1x.checkType()) 7733 return setError(); 7734 exp.e1 = e1x; 7735 7736 if (!exp.e1.type) 7737 { 7738 exp.error("cannot cast `%s`", exp.e1.toChars()); 7739 return setError(); 7740 } 7741 7742 // https://issues.dlang.org/show_bug.cgi?id=19954 7743 if (exp.e1.type.ty == Ttuple) 7744 { 7745 if (exp.to) 7746 { 7747 if (TypeTuple tt = exp.to.isTypeTuple()) 7748 { 7749 if (exp.e1.type.implicitConvTo(tt)) 7750 { 7751 result = exp.e1.castTo(sc, tt); 7752 return; 7753 } 7754 } 7755 } 7756 TupleExp te = exp.e1.isTupleExp(); 7757 if (te.exps.length == 1) 7758 exp.e1 = (*te.exps)[0]; 7759 } 7760 7761 // only allow S(x) rewrite if cast specified S explicitly. 7762 // See https://issues.dlang.org/show_bug.cgi?id=18545 7763 const bool allowImplicitConstruction = exp.to !is null; 7764 7765 if (!exp.to) // Handle cast(const) and cast(immutable), etc. 7766 { 7767 exp.to = exp.e1.type.castMod(exp.mod); 7768 exp.to = exp.to.typeSemantic(exp.loc, sc); 7769 7770 if (exp.to == Type.terror) 7771 return setError(); 7772 } 7773 7774 if (exp.to.ty == Ttuple) 7775 { 7776 exp.error("cannot cast `%s` of type `%s` to tuple type `%s`", exp.e1.toChars(), exp.e1.type.toChars(), exp.to.toChars()); 7777 return setError(); 7778 } 7779 7780 // cast(void) is used to mark e1 as unused, so it is safe 7781 if (exp.to.ty == Tvoid) 7782 { 7783 exp.type = exp.to; 7784 result = exp; 7785 return; 7786 } 7787 7788 if (!exp.to.equals(exp.e1.type) && exp.mod == cast(ubyte)~0) 7789 { 7790 if (Expression e = exp.op_overload(sc)) 7791 { 7792 result = e.implicitCastTo(sc, exp.to); 7793 return; 7794 } 7795 } 7796 7797 Type t1b = exp.e1.type.toBasetype(); 7798 Type tob = exp.to.toBasetype(); 7799 7800 if (allowImplicitConstruction && tob.ty == Tstruct && !tob.equals(t1b)) 7801 { 7802 /* Look to replace: 7803 * cast(S)t 7804 * with: 7805 * S(t) 7806 */ 7807 7808 // Rewrite as to.call(e1) 7809 Expression e = new TypeExp(exp.loc, exp.to); 7810 e = new CallExp(exp.loc, e, exp.e1); 7811 e = e.trySemantic(sc); 7812 if (e) 7813 { 7814 result = e; 7815 return; 7816 } 7817 } 7818 7819 if (!t1b.equals(tob) && (t1b.ty == Tarray || t1b.ty == Tsarray)) 7820 { 7821 if (checkNonAssignmentArrayOp(exp.e1)) 7822 return setError(); 7823 } 7824 7825 // Look for casting to a vector type 7826 if (tob.ty == Tvector && t1b.ty != Tvector) 7827 { 7828 result = new VectorExp(exp.loc, exp.e1, exp.to); 7829 result = result.expressionSemantic(sc); 7830 return; 7831 } 7832 7833 Expression ex = exp.e1.castTo(sc, exp.to); 7834 if (ex.op == EXP.error) 7835 { 7836 result = ex; 7837 return; 7838 } 7839 7840 // Check for unsafe casts 7841 if (!isSafeCast(ex, t1b, tob)) 7842 { 7843 if (sc.setUnsafe(false, exp.loc, "cast from `%s` to `%s` not allowed in safe code", exp.e1.type, exp.to)) 7844 { 7845 return setError(); 7846 } 7847 } 7848 7849 // `object.__ArrayCast` is a rewrite of an old runtime hook `_d_arraycast`. `_d_arraycast` was not built 7850 // to handle certain casts. Those casts which `object.__ArrayCast` does not support are filtered out. 7851 // See `e2ir.toElemCast` for other types of casts. If `object.__ArrayCast` is improved to support more 7852 // casts these conditions and potentially some logic in `e2ir.toElemCast` can be removed. 7853 if (tob.ty == Tarray) 7854 { 7855 // https://issues.dlang.org/show_bug.cgi?id=19840 7856 if (auto ad = isAggregate(t1b)) 7857 { 7858 if (ad.aliasthis) 7859 { 7860 Expression e = resolveAliasThis(sc, exp.e1); 7861 e = new CastExp(exp.loc, e, exp.to); 7862 result = e.expressionSemantic(sc); 7863 return; 7864 } 7865 } 7866 7867 if(t1b.ty == Tarray && exp.e1.op != EXP.arrayLiteral && sc.needsCodegen()) 7868 { 7869 auto tFrom = t1b.nextOf(); 7870 auto tTo = tob.nextOf(); 7871 7872 // https://issues.dlang.org/show_bug.cgi?id=20130 7873 if (exp.e1.op != EXP.string_ || !ex.isStringExp) 7874 { 7875 const uint fromSize = cast(uint)tFrom.size(); 7876 const uint toSize = cast(uint)tTo.size(); 7877 if (fromSize == SIZE_INVALID || toSize == SIZE_INVALID) 7878 return setError(); 7879 7880 // If array element sizes do not match, we must adjust the dimensions 7881 if (fromSize != toSize) 7882 { 7883 if (!verifyHookExist(exp.loc, *sc, Id.__ArrayCast, "casting array of structs")) 7884 return setError(); 7885 7886 // A runtime check is needed in case arrays don't line up. That check should 7887 // be done in the implementation of `object.__ArrayCast` 7888 if (toSize == 0 || (fromSize % toSize) != 0) 7889 { 7890 // lower to `object.__ArrayCast!(TFrom, TTo)(from)` 7891 7892 // fully qualify as `object.__ArrayCast` 7893 Expression id = new IdentifierExp(exp.loc, Id.empty); 7894 auto dotid = new DotIdExp(exp.loc, id, Id.object); 7895 7896 auto tiargs = new Objects(); 7897 tiargs.push(tFrom); 7898 tiargs.push(tTo); 7899 auto dt = new DotTemplateInstanceExp(exp.loc, dotid, Id.__ArrayCast, tiargs); 7900 7901 auto arguments = new Expressions(); 7902 arguments.push(exp.e1); 7903 Expression ce = new CallExp(exp.loc, dt, arguments); 7904 7905 result = expressionSemantic(ce, sc); 7906 return; 7907 } 7908 } 7909 } 7910 } 7911 } 7912 7913 if (sc && sc.flags & SCOPE.Cfile) 7914 { 7915 /* C11 6.5.4-5: A cast does not yield an lvalue. 7916 * So ensure that castTo does not strip away the cast so that this 7917 * can be enforced in other semantic visitor methods. 7918 */ 7919 if (!ex.isCastExp()) 7920 { 7921 ex = new CastExp(exp.loc, ex, exp.to); 7922 ex.type = exp.to; 7923 } 7924 } 7925 result = ex; 7926 } 7927 7928 override void visit(VectorExp exp) 7929 { 7930 static if (LOGSEMANTIC) 7931 { 7932 printf("VectorExp::semantic('%s')\n", exp.toChars()); 7933 } 7934 if (exp.type) 7935 { 7936 result = exp; 7937 return; 7938 } 7939 7940 exp.e1 = exp.e1.expressionSemantic(sc); 7941 exp.type = exp.to.typeSemantic(exp.loc, sc); 7942 if (exp.e1.op == EXP.error || exp.type.ty == Terror) 7943 { 7944 result = exp.e1; 7945 return; 7946 } 7947 7948 Type tb = exp.type.toBasetype(); 7949 assert(tb.ty == Tvector); 7950 TypeVector tv = cast(TypeVector)tb; 7951 Type te = tv.elementType(); 7952 exp.dim = cast(int)(tv.size(exp.loc) / te.size(exp.loc)); 7953 7954 bool checkElem(Expression elem) 7955 { 7956 if (elem.isConst() == 1) 7957 return false; 7958 7959 exp.error("constant expression expected, not `%s`", elem.toChars()); 7960 return true; 7961 } 7962 7963 exp.e1 = exp.e1.optimize(WANTvalue); 7964 bool res; 7965 if (exp.e1.op == EXP.arrayLiteral) 7966 { 7967 foreach (i; 0 .. exp.dim) 7968 { 7969 // Do not stop on first error - check all AST nodes even if error found 7970 res |= checkElem(exp.e1.isArrayLiteralExp()[i]); 7971 } 7972 } 7973 else if (exp.e1.type.ty == Tvoid) 7974 checkElem(exp.e1); 7975 7976 result = res ? ErrorExp.get() : exp; 7977 } 7978 7979 override void visit(VectorArrayExp e) 7980 { 7981 static if (LOGSEMANTIC) 7982 { 7983 printf("VectorArrayExp::semantic('%s')\n", e.toChars()); 7984 } 7985 if (!e.type) 7986 { 7987 unaSemantic(e, sc); 7988 e.e1 = resolveProperties(sc, e.e1); 7989 7990 if (e.e1.op == EXP.error) 7991 { 7992 result = e.e1; 7993 return; 7994 } 7995 assert(e.e1.type.ty == Tvector); 7996 e.type = e.e1.type.isTypeVector().basetype; 7997 } 7998 result = e; 7999 } 8000 8001 override void visit(SliceExp exp) 8002 { 8003 static if (LOGSEMANTIC) 8004 { 8005 printf("SliceExp::semantic('%s')\n", exp.toChars()); 8006 } 8007 if (exp.type) 8008 { 8009 result = exp; 8010 return; 8011 } 8012 8013 // operator overloading should be handled in ArrayExp already. 8014 if (Expression ex = unaSemantic(exp, sc)) 8015 { 8016 result = ex; 8017 return; 8018 } 8019 exp.e1 = resolveProperties(sc, exp.e1); 8020 if (exp.e1.op == EXP.type && exp.e1.type.ty != Ttuple) 8021 { 8022 if (exp.lwr || exp.upr) 8023 { 8024 exp.error("cannot slice type `%s`", exp.e1.toChars()); 8025 return setError(); 8026 } 8027 Expression e = new TypeExp(exp.loc, exp.e1.type.arrayOf()); 8028 result = e.expressionSemantic(sc); 8029 return; 8030 } 8031 if (!exp.lwr && !exp.upr) 8032 { 8033 if (exp.e1.op == EXP.arrayLiteral) 8034 { 8035 // Convert [a,b,c][] to [a,b,c] 8036 Type t1b = exp.e1.type.toBasetype(); 8037 Expression e = exp.e1; 8038 if (t1b.ty == Tsarray) 8039 { 8040 e = e.copy(); 8041 e.type = t1b.nextOf().arrayOf(); 8042 } 8043 result = e; 8044 return; 8045 } 8046 if (exp.e1.op == EXP.slice) 8047 { 8048 // Convert e[][] to e[] 8049 SliceExp se = cast(SliceExp)exp.e1; 8050 if (!se.lwr && !se.upr) 8051 { 8052 result = se; 8053 return; 8054 } 8055 } 8056 if (isArrayOpOperand(exp.e1)) 8057 { 8058 // Convert (a[]+b[])[] to a[]+b[] 8059 result = exp.e1; 8060 return; 8061 } 8062 } 8063 if (exp.e1.op == EXP.error) 8064 { 8065 result = exp.e1; 8066 return; 8067 } 8068 if (exp.e1.type.ty == Terror) 8069 return setError(); 8070 8071 Type t1b = exp.e1.type.toBasetype(); 8072 if (auto tp = t1b.isTypePointer()) 8073 { 8074 if (t1b.isPtrToFunction()) 8075 { 8076 exp.error("cannot slice function pointer `%s`", exp.e1.toChars()); 8077 return setError(); 8078 } 8079 if (!exp.lwr || !exp.upr) 8080 { 8081 exp.error("upper and lower bounds are needed to slice a pointer"); 8082 if (auto ad = isAggregate(tp.next.toBasetype())) 8083 { 8084 auto s = search_function(ad, Id.index); 8085 if (!s) s = search_function(ad, Id.slice); 8086 if (s) 8087 { 8088 auto fd = s.isFuncDeclaration(); 8089 if ((fd && !fd.getParameterList().length) || s.isTemplateDeclaration()) 8090 { 8091 exp.errorSupplemental( 8092 "pointer `%s` points to an aggregate that defines an `%s`, perhaps you meant `(*%s)[]`", 8093 exp.e1.toChars(), 8094 s.ident.toChars(), 8095 exp.e1.toChars() 8096 ); 8097 } 8098 8099 } 8100 } 8101 8102 return setError(); 8103 } 8104 if (sc.setUnsafe(false, exp.loc, "pointer slicing not allowed in safe functions")) 8105 return setError(); 8106 } 8107 else if (t1b.ty == Tarray) 8108 { 8109 } 8110 else if (t1b.ty == Tsarray) 8111 { 8112 } 8113 else if (t1b.ty == Ttuple) 8114 { 8115 if (!exp.lwr && !exp.upr) 8116 { 8117 result = exp.e1; 8118 return; 8119 } 8120 if (!exp.lwr || !exp.upr) 8121 { 8122 exp.error("need upper and lower bound to slice tuple"); 8123 return setError(); 8124 } 8125 } 8126 else if (t1b.ty == Tvector && exp.e1.isLvalue()) 8127 { 8128 // Convert e1 to corresponding static array 8129 TypeVector tv1 = cast(TypeVector)t1b; 8130 t1b = tv1.basetype; 8131 t1b = t1b.castMod(tv1.mod); 8132 exp.e1.type = t1b; 8133 } 8134 else 8135 { 8136 exp.error("`%s` cannot be sliced with `[]`", t1b.ty == Tvoid ? exp.e1.toChars() : t1b.toChars()); 8137 return setError(); 8138 } 8139 8140 /* Run semantic on lwr and upr. 8141 */ 8142 Scope* scx = sc; 8143 if (t1b.ty == Tsarray || t1b.ty == Tarray || t1b.ty == Ttuple) 8144 { 8145 // Create scope for 'length' variable 8146 ScopeDsymbol sym = new ArrayScopeSymbol(sc, exp); 8147 sym.parent = sc.scopesym; 8148 sc = sc.push(sym); 8149 } 8150 if (exp.lwr) 8151 { 8152 if (t1b.ty == Ttuple) 8153 sc = sc.startCTFE(); 8154 exp.lwr = exp.lwr.expressionSemantic(sc); 8155 exp.lwr = resolveProperties(sc, exp.lwr); 8156 if (t1b.ty == Ttuple) 8157 sc = sc.endCTFE(); 8158 exp.lwr = exp.lwr.implicitCastTo(sc, Type.tsize_t); 8159 } 8160 if (exp.upr) 8161 { 8162 if (t1b.ty == Ttuple) 8163 sc = sc.startCTFE(); 8164 exp.upr = exp.upr.expressionSemantic(sc); 8165 exp.upr = resolveProperties(sc, exp.upr); 8166 if (t1b.ty == Ttuple) 8167 sc = sc.endCTFE(); 8168 exp.upr = exp.upr.implicitCastTo(sc, Type.tsize_t); 8169 } 8170 if (sc != scx) 8171 sc = sc.pop(); 8172 if (exp.lwr && exp.lwr.type == Type.terror || exp.upr && exp.upr.type == Type.terror) 8173 return setError(); 8174 8175 if (t1b.ty == Ttuple) 8176 { 8177 exp.lwr = exp.lwr.ctfeInterpret(); 8178 exp.upr = exp.upr.ctfeInterpret(); 8179 uinteger_t i1 = exp.lwr.toUInteger(); 8180 uinteger_t i2 = exp.upr.toUInteger(); 8181 8182 TupleExp te; 8183 TypeTuple tup; 8184 size_t length; 8185 if (exp.e1.op == EXP.tuple) // slicing an expression tuple 8186 { 8187 te = cast(TupleExp)exp.e1; 8188 tup = null; 8189 length = te.exps.length; 8190 } 8191 else if (exp.e1.op == EXP.type) // slicing a type tuple 8192 { 8193 te = null; 8194 tup = cast(TypeTuple)t1b; 8195 length = Parameter.dim(tup.arguments); 8196 } 8197 else 8198 assert(0); 8199 8200 if (i2 < i1 || length < i2) 8201 { 8202 exp.error("string slice `[%llu .. %llu]` is out of bounds", i1, i2); 8203 return setError(); 8204 } 8205 8206 size_t j1 = cast(size_t)i1; 8207 size_t j2 = cast(size_t)i2; 8208 Expression e; 8209 if (exp.e1.op == EXP.tuple) 8210 { 8211 auto exps = new Expressions(j2 - j1); 8212 for (size_t i = 0; i < j2 - j1; i++) 8213 { 8214 (*exps)[i] = (*te.exps)[j1 + i]; 8215 } 8216 e = new TupleExp(exp.loc, te.e0, exps); 8217 } 8218 else 8219 { 8220 auto args = new Parameters(); 8221 args.reserve(j2 - j1); 8222 for (size_t i = j1; i < j2; i++) 8223 { 8224 Parameter arg = Parameter.getNth(tup.arguments, i); 8225 args.push(arg); 8226 } 8227 e = new TypeExp(exp.e1.loc, new TypeTuple(args)); 8228 } 8229 e = e.expressionSemantic(sc); 8230 result = e; 8231 return; 8232 } 8233 8234 exp.type = t1b.nextOf().arrayOf(); 8235 // Allow typedef[] -> typedef[] 8236 if (exp.type.equals(t1b)) 8237 exp.type = exp.e1.type; 8238 8239 // We might know $ now 8240 setLengthVarIfKnown(exp.lengthVar, t1b); 8241 8242 if (exp.lwr && exp.upr) 8243 { 8244 exp.lwr = exp.lwr.optimize(WANTvalue); 8245 exp.upr = exp.upr.optimize(WANTvalue); 8246 8247 IntRange lwrRange = getIntRange(exp.lwr); 8248 IntRange uprRange = getIntRange(exp.upr); 8249 8250 if (t1b.ty == Tsarray || t1b.ty == Tarray) 8251 { 8252 Expression el = new ArrayLengthExp(exp.loc, exp.e1); 8253 el = el.expressionSemantic(sc); 8254 el = el.optimize(WANTvalue); 8255 if (el.op == EXP.int64) 8256 { 8257 // Array length is known at compile-time. Upper is in bounds if it fits length. 8258 dinteger_t length = el.toInteger(); 8259 auto bounds = IntRange(SignExtendedNumber(0), SignExtendedNumber(length)); 8260 exp.upperIsInBounds = bounds.contains(uprRange); 8261 } 8262 else if (exp.upr.op == EXP.int64 && exp.upr.toInteger() == 0) 8263 { 8264 // Upper slice expression is '0'. Value is always in bounds. 8265 exp.upperIsInBounds = true; 8266 } 8267 else if (exp.upr.op == EXP.variable && (cast(VarExp)exp.upr).var.ident == Id.dollar) 8268 { 8269 // Upper slice expression is '$'. Value is always in bounds. 8270 exp.upperIsInBounds = true; 8271 } 8272 } 8273 else if (t1b.ty == Tpointer) 8274 { 8275 exp.upperIsInBounds = true; 8276 } 8277 else 8278 assert(0); 8279 8280 exp.lowerIsLessThanUpper = (lwrRange.imax <= uprRange.imin); 8281 8282 //printf("upperIsInBounds = %d lowerIsLessThanUpper = %d\n", exp.upperIsInBounds, exp.lowerIsLessThanUpper); 8283 } 8284 8285 result = exp; 8286 } 8287 8288 override void visit(ArrayLengthExp e) 8289 { 8290 static if (LOGSEMANTIC) 8291 { 8292 printf("ArrayLengthExp::semantic('%s')\n", e.toChars()); 8293 } 8294 if (e.type) 8295 { 8296 result = e; 8297 return; 8298 } 8299 8300 if (Expression ex = unaSemantic(e, sc)) 8301 { 8302 result = ex; 8303 return; 8304 } 8305 e.e1 = resolveProperties(sc, e.e1); 8306 8307 e.type = Type.tsize_t; 8308 result = e; 8309 } 8310 8311 override void visit(ArrayExp exp) 8312 { 8313 static if (LOGSEMANTIC) 8314 { 8315 printf("ArrayExp::semantic('%s')\n", exp.toChars()); 8316 } 8317 assert(!exp.type); 8318 8319 if (sc.flags & SCOPE.Cfile) 8320 { 8321 /* See if need to rewrite the AST because of cast/call ambiguity 8322 */ 8323 if (auto e = castCallAmbiguity(exp, sc)) 8324 { 8325 result = expressionSemantic(e, sc); 8326 return; 8327 } 8328 } 8329 8330 result = exp.carraySemantic(sc); // C semantics 8331 if (result) 8332 return; 8333 8334 Expression e = exp.op_overload(sc); 8335 if (e) 8336 { 8337 result = e; 8338 return; 8339 } 8340 8341 if (isAggregate(exp.e1.type)) 8342 exp.error("no `[]` operator overload for type `%s`", exp.e1.type.toChars()); 8343 else if (exp.e1.op == EXP.type && exp.e1.type.ty != Ttuple) 8344 exp.error("static array of `%s` with multiple lengths not allowed", exp.e1.type.toChars()); 8345 else if (isIndexableNonAggregate(exp.e1.type)) 8346 exp.error("only one index allowed to index `%s`", exp.e1.type.toChars()); 8347 else 8348 exp.error("cannot use `[]` operator on expression of type `%s`", exp.e1.type.toChars()); 8349 8350 result = ErrorExp.get(); 8351 } 8352 8353 override void visit(DotExp exp) 8354 { 8355 static if (LOGSEMANTIC) 8356 { 8357 printf("DotExp::semantic('%s')\n", exp.toChars()); 8358 if (exp.type) 8359 printf("\ttype = %s\n", exp.type.toChars()); 8360 } 8361 exp.e1 = exp.e1.expressionSemantic(sc); 8362 exp.e2 = exp.e2.expressionSemantic(sc); 8363 8364 if (exp.e1.op == EXP.type) 8365 { 8366 result = exp.e2; 8367 return; 8368 } 8369 if (exp.e2.op == EXP.type) 8370 { 8371 result = exp.e2; 8372 return; 8373 } 8374 if (auto te = exp.e2.isTemplateExp()) 8375 { 8376 Expression e = new DotTemplateExp(exp.loc, exp.e1, te.td); 8377 result = e.expressionSemantic(sc); 8378 return; 8379 } 8380 if (!exp.type) 8381 exp.type = exp.e2.type; 8382 result = exp; 8383 } 8384 8385 override void visit(CommaExp e) 8386 { 8387 //printf("Semantic.CommaExp() %s\n", e.toChars()); 8388 if (e.type) 8389 { 8390 result = e; 8391 return; 8392 } 8393 8394 // Allow `((a,b),(x,y))` 8395 if (e.allowCommaExp) 8396 { 8397 CommaExp.allow(e.e1); 8398 CommaExp.allow(e.e2); 8399 } 8400 8401 if (Expression ex = binSemanticProp(e, sc)) 8402 { 8403 result = ex; 8404 return; 8405 } 8406 e.e1 = e.e1.addDtorHook(sc); 8407 8408 if (checkNonAssignmentArrayOp(e.e1)) 8409 return setError(); 8410 8411 // Comma expressions trigger this conversion 8412 e.e2 = e.e2.arrayFuncConv(sc); 8413 8414 e.type = e.e2.type; 8415 result = e; 8416 8417 if (sc.flags & SCOPE.Cfile) 8418 return; 8419 8420 if (e.type is Type.tvoid) 8421 { 8422 checkMustUse(e.e1, sc); 8423 discardValue(e.e1); 8424 } 8425 else if (!e.allowCommaExp && !e.isGenerated) 8426 e.error("using the result of a comma expression is not allowed"); 8427 } 8428 8429 override void visit(IntervalExp e) 8430 { 8431 static if (LOGSEMANTIC) 8432 { 8433 printf("IntervalExp::semantic('%s')\n", e.toChars()); 8434 } 8435 if (e.type) 8436 { 8437 result = e; 8438 return; 8439 } 8440 8441 Expression le = e.lwr; 8442 le = le.expressionSemantic(sc); 8443 le = resolveProperties(sc, le); 8444 8445 Expression ue = e.upr; 8446 ue = ue.expressionSemantic(sc); 8447 ue = resolveProperties(sc, ue); 8448 8449 if (le.op == EXP.error) 8450 { 8451 result = le; 8452 return; 8453 } 8454 if (ue.op == EXP.error) 8455 { 8456 result = ue; 8457 return; 8458 } 8459 8460 e.lwr = le; 8461 e.upr = ue; 8462 8463 e.type = Type.tvoid; 8464 result = e; 8465 } 8466 8467 override void visit(DelegatePtrExp e) 8468 { 8469 static if (LOGSEMANTIC) 8470 { 8471 printf("DelegatePtrExp::semantic('%s')\n", e.toChars()); 8472 } 8473 if (!e.type) 8474 { 8475 unaSemantic(e, sc); 8476 e.e1 = resolveProperties(sc, e.e1); 8477 8478 if (e.e1.op == EXP.error) 8479 { 8480 result = e.e1; 8481 return; 8482 } 8483 e.type = Type.tvoidptr; 8484 } 8485 result = e; 8486 } 8487 8488 override void visit(DelegateFuncptrExp e) 8489 { 8490 static if (LOGSEMANTIC) 8491 { 8492 printf("DelegateFuncptrExp::semantic('%s')\n", e.toChars()); 8493 } 8494 if (!e.type) 8495 { 8496 unaSemantic(e, sc); 8497 e.e1 = resolveProperties(sc, e.e1); 8498 if (e.e1.op == EXP.error) 8499 { 8500 result = e.e1; 8501 return; 8502 } 8503 e.type = e.e1.type.nextOf().pointerTo(); 8504 } 8505 result = e; 8506 } 8507 8508 override void visit(IndexExp exp) 8509 { 8510 static if (LOGSEMANTIC) 8511 { 8512 printf("IndexExp::semantic('%s')\n", exp.toChars()); 8513 } 8514 if (exp.type) 8515 { 8516 result = exp; 8517 return; 8518 } 8519 8520 // operator overloading should be handled in ArrayExp already. 8521 if (!exp.e1.type) 8522 exp.e1 = exp.e1.expressionSemantic(sc).arrayFuncConv(sc); 8523 assert(exp.e1.type); // semantic() should already be run on it 8524 if (exp.e1.op == EXP.type && exp.e1.type.ty != Ttuple) 8525 { 8526 exp.e2 = exp.e2.expressionSemantic(sc); 8527 exp.e2 = resolveProperties(sc, exp.e2); 8528 Type nt; 8529 if (exp.e2.op == EXP.type) 8530 nt = new TypeAArray(exp.e1.type, exp.e2.type); 8531 else 8532 nt = new TypeSArray(exp.e1.type, exp.e2); 8533 Expression e = new TypeExp(exp.loc, nt); 8534 result = e.expressionSemantic(sc); 8535 return; 8536 } 8537 if (exp.e1.op == EXP.error) 8538 { 8539 result = exp.e1; 8540 return; 8541 } 8542 if (exp.e1.type.ty == Terror) 8543 return setError(); 8544 8545 // Note that unlike C we do not implement the int[ptr] 8546 8547 Type t1b = exp.e1.type.toBasetype(); 8548 8549 if (TypeVector tv1 = t1b.isTypeVector()) 8550 { 8551 // Convert e1 to corresponding static array 8552 t1b = tv1.basetype; 8553 t1b = t1b.castMod(tv1.mod); 8554 exp.e1 = exp.e1.castTo(sc, t1b); 8555 } 8556 if (t1b.ty == Tsarray || t1b.ty == Tarray) 8557 { 8558 if (!checkAddressable(exp, sc)) 8559 return setError(); 8560 } 8561 8562 /* Run semantic on e2 8563 */ 8564 Scope* scx = sc; 8565 if (t1b.ty == Tsarray || t1b.ty == Tarray || t1b.ty == Ttuple) 8566 { 8567 // Create scope for 'length' variable 8568 ScopeDsymbol sym = new ArrayScopeSymbol(sc, exp); 8569 sym.parent = sc.scopesym; 8570 sc = sc.push(sym); 8571 } 8572 if (t1b.ty == Ttuple) 8573 sc = sc.startCTFE(); 8574 exp.e2 = exp.e2.expressionSemantic(sc).arrayFuncConv(sc); 8575 exp.e2 = resolveProperties(sc, exp.e2); 8576 if (t1b.ty == Ttuple) 8577 sc = sc.endCTFE(); 8578 if (exp.e2.op == EXP.tuple) 8579 { 8580 TupleExp te = cast(TupleExp)exp.e2; 8581 if (te.exps && te.exps.length == 1) 8582 exp.e2 = Expression.combine(te.e0, (*te.exps)[0]); // bug 4444 fix 8583 } 8584 if (sc != scx) 8585 sc = sc.pop(); 8586 if (exp.e2.type == Type.terror) 8587 return setError(); 8588 8589 if (checkNonAssignmentArrayOp(exp.e1)) 8590 return setError(); 8591 8592 switch (t1b.ty) 8593 { 8594 case Tpointer: 8595 if (t1b.isPtrToFunction()) 8596 { 8597 exp.error("cannot index function pointer `%s`", exp.e1.toChars()); 8598 return setError(); 8599 } 8600 exp.e2 = exp.e2.implicitCastTo(sc, Type.tsize_t); 8601 if (exp.e2.type == Type.terror) 8602 return setError(); 8603 exp.e2 = exp.e2.optimize(WANTvalue); 8604 if (exp.e2.op == EXP.int64 && exp.e2.toInteger() == 0) 8605 { 8606 } 8607 else if (sc.setUnsafe(false, exp.loc, "`@safe` function `%s` cannot index pointer `%s`", sc.func, exp.e1)) 8608 { 8609 return setError(); 8610 } 8611 exp.type = (cast(TypeNext)t1b).next; 8612 break; 8613 8614 case Tarray: 8615 exp.e2 = exp.e2.implicitCastTo(sc, Type.tsize_t); 8616 if (exp.e2.type == Type.terror) 8617 return setError(); 8618 exp.type = (cast(TypeNext)t1b).next; 8619 break; 8620 8621 case Tsarray: 8622 { 8623 exp.e2 = exp.e2.implicitCastTo(sc, Type.tsize_t); 8624 if (exp.e2.type == Type.terror) 8625 return setError(); 8626 exp.type = t1b.nextOf(); 8627 break; 8628 } 8629 case Taarray: 8630 { 8631 TypeAArray taa = cast(TypeAArray)t1b; 8632 /* We can skip the implicit conversion if they differ only by 8633 * constness 8634 * https://issues.dlang.org/show_bug.cgi?id=2684 8635 * see also bug https://issues.dlang.org/show_bug.cgi?id=2954 b 8636 */ 8637 if (!arrayTypeCompatibleWithoutCasting(exp.e2.type, taa.index)) 8638 { 8639 exp.e2 = exp.e2.implicitCastTo(sc, taa.index); // type checking 8640 if (exp.e2.type == Type.terror) 8641 return setError(); 8642 } 8643 8644 semanticTypeInfo(sc, taa); 8645 checkNewEscape(sc, exp.e2, false); 8646 8647 exp.type = taa.next; 8648 break; 8649 } 8650 case Ttuple: 8651 { 8652 exp.e2 = exp.e2.implicitCastTo(sc, Type.tsize_t); 8653 if (exp.e2.type == Type.terror) 8654 return setError(); 8655 8656 exp.e2 = exp.e2.ctfeInterpret(); 8657 uinteger_t index = exp.e2.toUInteger(); 8658 8659 TupleExp te; 8660 TypeTuple tup; 8661 size_t length; 8662 if (exp.e1.op == EXP.tuple) 8663 { 8664 te = cast(TupleExp)exp.e1; 8665 tup = null; 8666 length = te.exps.length; 8667 } 8668 else if (exp.e1.op == EXP.type) 8669 { 8670 te = null; 8671 tup = cast(TypeTuple)t1b; 8672 length = Parameter.dim(tup.arguments); 8673 } 8674 else 8675 assert(0); 8676 8677 if (length <= index) 8678 { 8679 exp.error("array index `[%llu]` is outside array bounds `[0 .. %llu]`", index, cast(ulong)length); 8680 return setError(); 8681 } 8682 Expression e; 8683 if (exp.e1.op == EXP.tuple) 8684 { 8685 e = (*te.exps)[cast(size_t)index]; 8686 e = Expression.combine(te.e0, e); 8687 } 8688 else 8689 e = new TypeExp(exp.e1.loc, Parameter.getNth(tup.arguments, cast(size_t)index).type); 8690 result = e; 8691 return; 8692 } 8693 default: 8694 exp.error("`%s` must be an array or pointer type, not `%s`", exp.e1.toChars(), exp.e1.type.toChars()); 8695 return setError(); 8696 } 8697 8698 // We might know $ now 8699 setLengthVarIfKnown(exp.lengthVar, t1b); 8700 8701 if (t1b.ty == Tsarray || t1b.ty == Tarray) 8702 { 8703 Expression el = new ArrayLengthExp(exp.loc, exp.e1); 8704 el = el.expressionSemantic(sc); 8705 el = el.optimize(WANTvalue); 8706 if (el.op == EXP.int64) 8707 { 8708 exp.e2 = exp.e2.optimize(WANTvalue); 8709 dinteger_t length = el.toInteger(); 8710 if (length) 8711 { 8712 auto bounds = IntRange(SignExtendedNumber(0), SignExtendedNumber(length - 1)); 8713 // OR it in, because it might already be set for C array indexing 8714 exp.indexIsInBounds |= bounds.contains(getIntRange(exp.e2)); 8715 } 8716 else if (sc.flags & SCOPE.Cfile && t1b.ty == Tsarray) 8717 { 8718 if (auto ve = exp.e1.isVarExp()) 8719 { 8720 /* Rewrite 0-length C array ve[exp.e2] as *(ve + exp.e2) 8721 */ 8722 auto vp = ve.castTo(sc, t1b.isTypeSArray().next.pointerTo()); 8723 auto e = new AddExp(exp.loc, vp, exp.e2); 8724 auto pe = new PtrExp(exp.loc, e); 8725 result = pe.expressionSemantic(sc).optimize(WANTvalue); 8726 return; 8727 } 8728 } 8729 } 8730 } 8731 8732 result = exp; 8733 } 8734 8735 override void visit(PostExp exp) 8736 { 8737 static if (LOGSEMANTIC) 8738 { 8739 printf("PostExp::semantic('%s')\n", exp.toChars()); 8740 } 8741 if (exp.type) 8742 { 8743 result = exp; 8744 return; 8745 } 8746 8747 if (sc.flags & SCOPE.Cfile) 8748 { 8749 /* See if need to rewrite the AST because of cast/call ambiguity 8750 */ 8751 if (auto e = castCallAmbiguity(exp, sc)) 8752 { 8753 result = expressionSemantic(e, sc); 8754 return; 8755 } 8756 } 8757 8758 if (Expression ex = binSemantic(exp, sc)) 8759 { 8760 result = ex; 8761 return; 8762 } 8763 Expression e1x = resolveProperties(sc, exp.e1); 8764 if (e1x.op == EXP.error) 8765 { 8766 result = e1x; 8767 return; 8768 } 8769 exp.e1 = e1x; 8770 8771 Expression e = exp.op_overload(sc); 8772 if (e) 8773 { 8774 result = e; 8775 return; 8776 } 8777 8778 if (exp.e1.checkReadModifyWrite(exp.op)) 8779 return setError(); 8780 8781 if (exp.e1.op == EXP.slice) 8782 { 8783 const(char)* s = exp.op == EXP.plusPlus ? "increment" : "decrement"; 8784 exp.error("cannot post-%s array slice `%s`, use pre-%s instead", s, exp.e1.toChars(), s); 8785 return setError(); 8786 } 8787 8788 Type t1 = exp.e1.type.toBasetype(); 8789 if (t1.ty == Tclass || t1.ty == Tstruct || exp.e1.op == EXP.arrayLength) 8790 { 8791 /* Check for operator overloading, 8792 * but rewrite in terms of ++e instead of e++ 8793 */ 8794 8795 /* If e1 is not trivial, take a reference to it 8796 */ 8797 Expression de = null; 8798 if (exp.e1.op != EXP.variable && exp.e1.op != EXP.arrayLength) 8799 { 8800 // ref v = e1; 8801 auto v = copyToTemp(STC.ref_, "__postref", exp.e1); 8802 de = new DeclarationExp(exp.loc, v); 8803 exp.e1 = new VarExp(exp.e1.loc, v); 8804 } 8805 8806 /* Rewrite as: 8807 * auto tmp = e1; ++e1; tmp 8808 */ 8809 auto tmp = copyToTemp(0, "__pitmp", exp.e1); 8810 Expression ea = new DeclarationExp(exp.loc, tmp); 8811 8812 Expression eb = exp.e1.syntaxCopy(); 8813 eb = new PreExp(exp.op == EXP.plusPlus ? EXP.prePlusPlus : EXP.preMinusMinus, exp.loc, eb); 8814 8815 Expression ec = new VarExp(exp.loc, tmp); 8816 8817 // Combine de,ea,eb,ec 8818 if (de) 8819 ea = new CommaExp(exp.loc, de, ea); 8820 e = new CommaExp(exp.loc, ea, eb); 8821 e = new CommaExp(exp.loc, e, ec); 8822 e = e.expressionSemantic(sc); 8823 result = e; 8824 return; 8825 } 8826 8827 exp.e1 = exp.e1.modifiableLvalue(sc, exp.e1); 8828 exp.e1 = exp.e1.optimize(WANTvalue, /*keepLvalue*/ true); 8829 8830 e = exp; 8831 if (exp.e1.checkScalar() || 8832 exp.e1.checkSharedAccess(sc)) 8833 return setError(); 8834 if (exp.e1.checkNoBool()) 8835 return setError(); 8836 8837 if (exp.e1.type.ty == Tpointer) 8838 e = scaleFactor(exp, sc); 8839 else 8840 exp.e2 = exp.e2.castTo(sc, exp.e1.type); 8841 e.type = exp.e1.type; 8842 result = e; 8843 } 8844 8845 override void visit(PreExp exp) 8846 { 8847 Expression e = exp.op_overload(sc); 8848 // printf("PreExp::semantic('%s')\n", toChars()); 8849 if (e) 8850 { 8851 result = e; 8852 return; 8853 } 8854 8855 // Rewrite as e1+=1 or e1-=1 8856 if (exp.op == EXP.prePlusPlus) 8857 e = new AddAssignExp(exp.loc, exp.e1, IntegerExp.literal!1); 8858 else 8859 e = new MinAssignExp(exp.loc, exp.e1, IntegerExp.literal!1); 8860 result = e.expressionSemantic(sc); 8861 } 8862 8863 /* 8864 * Get the expression initializer for a specific struct 8865 * 8866 * Params: 8867 * sd = the struct for which the expression initializer is needed 8868 * loc = the location of the initializer 8869 * sc = the scope where the expression is located 8870 * t = the type of the expression 8871 * 8872 * Returns: 8873 * The expression initializer or error expression if any errors occured 8874 */ 8875 private Expression getInitExp(StructDeclaration sd, Loc loc, Scope* sc, Type t) 8876 { 8877 if (sd.zeroInit && !sd.isNested()) 8878 { 8879 // https://issues.dlang.org/show_bug.cgi?id=14606 8880 // Always use BlitExp for the special expression: (struct = 0) 8881 return IntegerExp.literal!0; 8882 } 8883 8884 if (sd.isNested()) 8885 { 8886 auto sle = new StructLiteralExp(loc, sd, null, t); 8887 if (!sd.fill(loc, *sle.elements, true)) 8888 return ErrorExp.get(); 8889 if (checkFrameAccess(loc, sc, sd, sle.elements.length)) 8890 return ErrorExp.get(); 8891 8892 sle.type = t; 8893 return sle; 8894 } 8895 8896 return t.defaultInit(loc); 8897 } 8898 8899 override void visit(AssignExp exp) 8900 { 8901 static if (LOGSEMANTIC) 8902 { 8903 if (exp.op == EXP.blit) printf("BlitExp.toElem('%s')\n", exp.toChars()); 8904 if (exp.op == EXP.assign) printf("AssignExp.toElem('%s')\n", exp.toChars()); 8905 if (exp.op == EXP.construct) printf("ConstructExp.toElem('%s')\n", exp.toChars()); 8906 } 8907 8908 void setResult(Expression e, int line = __LINE__) 8909 { 8910 //printf("line %d\n", line); 8911 result = e; 8912 } 8913 8914 if (exp.type) 8915 { 8916 return setResult(exp); 8917 } 8918 8919 Expression e1old = exp.e1; 8920 8921 if (auto e2comma = exp.e2.isCommaExp()) 8922 { 8923 if (!e2comma.isGenerated && !(sc.flags & SCOPE.Cfile)) 8924 exp.error("using the result of a comma expression is not allowed"); 8925 8926 /* Rewrite to get rid of the comma from rvalue 8927 * e1=(e0,e2) => e0,(e1=e2) 8928 */ 8929 Expression e0; 8930 exp.e2 = Expression.extractLast(e2comma, e0); 8931 Expression e = Expression.combine(e0, exp); 8932 return setResult(e.expressionSemantic(sc)); 8933 } 8934 8935 /* Look for operator overloading of a[arguments] = e2. 8936 * Do it before e1.expressionSemantic() otherwise the ArrayExp will have been 8937 * converted to unary operator overloading already. 8938 */ 8939 if (auto ae = exp.e1.isArrayExp()) 8940 { 8941 Expression res; 8942 8943 ae.e1 = ae.e1.expressionSemantic(sc); 8944 ae.e1 = resolveProperties(sc, ae.e1); 8945 Expression ae1old = ae.e1; 8946 8947 const(bool) maybeSlice = 8948 (ae.arguments.length == 0 || 8949 ae.arguments.length == 1 && (*ae.arguments)[0].op == EXP.interval); 8950 8951 IntervalExp ie = null; 8952 if (maybeSlice && ae.arguments.length) 8953 { 8954 assert((*ae.arguments)[0].op == EXP.interval); 8955 ie = cast(IntervalExp)(*ae.arguments)[0]; 8956 } 8957 Type att = null; // first cyclic `alias this` type 8958 while (true) 8959 { 8960 if (ae.e1.op == EXP.error) 8961 return setResult(ae.e1); 8962 8963 Expression e0 = null; 8964 Expression ae1save = ae.e1; 8965 ae.lengthVar = null; 8966 8967 Type t1b = ae.e1.type.toBasetype(); 8968 AggregateDeclaration ad = isAggregate(t1b); 8969 if (!ad) 8970 break; 8971 if (search_function(ad, Id.indexass)) 8972 { 8973 // Deal with $ 8974 res = resolveOpDollar(sc, ae, &e0); 8975 if (!res) // a[i..j] = e2 might be: a.opSliceAssign(e2, i, j) 8976 goto Lfallback; 8977 if (res.op == EXP.error) 8978 return setResult(res); 8979 8980 res = exp.e2.expressionSemantic(sc); 8981 if (res.op == EXP.error) 8982 return setResult(res); 8983 exp.e2 = res; 8984 8985 /* Rewrite (a[arguments] = e2) as: 8986 * a.opIndexAssign(e2, arguments) 8987 */ 8988 Expressions* a = ae.arguments.copy(); 8989 a.insert(0, exp.e2); 8990 res = new DotIdExp(exp.loc, ae.e1, Id.indexass); 8991 res = new CallExp(exp.loc, res, a); 8992 if (maybeSlice) // a[] = e2 might be: a.opSliceAssign(e2) 8993 res = res.trySemantic(sc); 8994 else 8995 res = res.expressionSemantic(sc); 8996 if (res) 8997 return setResult(Expression.combine(e0, res)); 8998 } 8999 9000 Lfallback: 9001 if (maybeSlice && search_function(ad, Id.sliceass)) 9002 { 9003 // Deal with $ 9004 res = resolveOpDollar(sc, ae, ie, &e0); 9005 if (res.op == EXP.error) 9006 return setResult(res); 9007 9008 res = exp.e2.expressionSemantic(sc); 9009 if (res.op == EXP.error) 9010 return setResult(res); 9011 9012 exp.e2 = res; 9013 9014 /* Rewrite (a[i..j] = e2) as: 9015 * a.opSliceAssign(e2, i, j) 9016 */ 9017 auto a = new Expressions(); 9018 a.push(exp.e2); 9019 if (ie) 9020 { 9021 a.push(ie.lwr); 9022 a.push(ie.upr); 9023 } 9024 res = new DotIdExp(exp.loc, ae.e1, Id.sliceass); 9025 res = new CallExp(exp.loc, res, a); 9026 res = res.expressionSemantic(sc); 9027 return setResult(Expression.combine(e0, res)); 9028 } 9029 9030 // No operator overloading member function found yet, but 9031 // there might be an alias this to try. 9032 if (ad.aliasthis && !isRecursiveAliasThis(att, ae.e1.type)) 9033 { 9034 /* Rewrite (a[arguments] op e2) as: 9035 * a.aliasthis[arguments] op e2 9036 */ 9037 ae.e1 = resolveAliasThis(sc, ae1save, true); 9038 if (ae.e1) 9039 continue; 9040 } 9041 break; 9042 } 9043 ae.e1 = ae1old; // recovery 9044 ae.lengthVar = null; 9045 } 9046 9047 /* Run this.e1 semantic. 9048 */ 9049 { 9050 Expression e1x = exp.e1; 9051 9052 /* With UFCS, e.f = value 9053 * Could mean: 9054 * .f(e, value) 9055 * or: 9056 * .f(e) = value 9057 */ 9058 if (auto dti = e1x.isDotTemplateInstanceExp()) 9059 { 9060 Expression e = dti.dotTemplateSemanticProp(sc, DotExpFlag.gag); 9061 if (!e) 9062 { 9063 return setResult(resolveUFCSProperties(sc, e1x, exp.e2)); 9064 } 9065 9066 e1x = e; 9067 } 9068 else if (sc.flags & SCOPE.Cfile && e1x.isDotIdExp()) 9069 { 9070 auto die = e1x.isDotIdExp(); 9071 e1x = fieldLookup(die.e1, sc, die.ident); 9072 } 9073 else if (auto die = e1x.isDotIdExp()) 9074 { 9075 Expression e = die.dotIdSemanticProp(sc, 1); 9076 if (e && isDotOpDispatch(e)) 9077 { 9078 /* https://issues.dlang.org/show_bug.cgi?id=19687 9079 * 9080 * On this branch, e2 is semantically analyzed in resolvePropertiesX, 9081 * but that call is done with gagged errors. That is the only time when 9082 * semantic gets ran on e2, that is why the error never gets to be printed. 9083 * In order to make sure that UFCS is tried with correct parameters, e2 9084 * needs to have semantic ran on it. 9085 */ 9086 auto ode = e; 9087 exp.e2 = exp.e2.expressionSemantic(sc); 9088 uint errors = global.startGagging(); 9089 e = resolvePropertiesX(sc, e, exp.e2); 9090 // Any error or if 'e' is not resolved, go to UFCS 9091 if (global.endGagging(errors) || e is ode) 9092 e = null; /* fall down to UFCS */ 9093 else 9094 return setResult(e); 9095 } 9096 if (!e) 9097 return setResult(resolveUFCSProperties(sc, e1x, exp.e2)); 9098 e1x = e; 9099 } 9100 else 9101 { 9102 if (auto se = e1x.isSliceExp()) 9103 se.arrayop = true; 9104 9105 e1x = e1x.expressionSemantic(sc); 9106 } 9107 9108 /* We have f = value. 9109 * Could mean: 9110 * f(value) 9111 * or: 9112 * f() = value 9113 */ 9114 if (Expression e = resolvePropertiesX(sc, e1x, exp.e2, exp)) 9115 return setResult(e); 9116 9117 if (e1x.checkRightThis(sc)) 9118 { 9119 return setError(); 9120 } 9121 exp.e1 = e1x; 9122 assert(exp.e1.type); 9123 } 9124 Type t1 = exp.e1.type.isTypeEnum() ? exp.e1.type : exp.e1.type.toBasetype(); 9125 9126 /* Run this.e2 semantic. 9127 * Different from other binary expressions, the analysis of e2 9128 * depends on the result of e1 in assignments. 9129 */ 9130 { 9131 Expression e2x = inferType(exp.e2, t1.baseElemOf()); 9132 e2x = e2x.expressionSemantic(sc); 9133 if (!t1.isTypeSArray()) 9134 e2x = e2x.arrayFuncConv(sc); 9135 e2x = resolveProperties(sc, e2x); 9136 if (e2x.op == EXP.type) 9137 e2x = resolveAliasThis(sc, e2x); //https://issues.dlang.org/show_bug.cgi?id=17684 9138 if (e2x.op == EXP.error) 9139 return setResult(e2x); 9140 // We delay checking the value for structs/classes as these might have 9141 // an opAssign defined. 9142 if ((t1.ty != Tstruct && t1.ty != Tclass && e2x.checkValue()) || 9143 e2x.checkSharedAccess(sc)) 9144 return setError(); 9145 9146 auto etmp = checkNoreturnVarAccess(e2x); 9147 if (etmp != e2x) 9148 return setResult(etmp); 9149 9150 exp.e2 = e2x; 9151 } 9152 9153 /* Rewrite tuple assignment as a tuple of assignments. 9154 */ 9155 { 9156 Expression e2x = exp.e2; 9157 9158 Ltupleassign: 9159 if (exp.e1.op == EXP.tuple && e2x.op == EXP.tuple) 9160 { 9161 TupleExp tup1 = cast(TupleExp)exp.e1; 9162 TupleExp tup2 = cast(TupleExp)e2x; 9163 size_t dim = tup1.exps.length; 9164 Expression e = null; 9165 if (dim != tup2.exps.length) 9166 { 9167 exp.error("mismatched tuple lengths, %d and %d", cast(int)dim, cast(int)tup2.exps.length); 9168 return setError(); 9169 } 9170 if (dim == 0) 9171 { 9172 e = IntegerExp.literal!0; 9173 e = new CastExp(exp.loc, e, Type.tvoid); // avoid "has no effect" error 9174 e = Expression.combine(tup1.e0, tup2.e0, e); 9175 } 9176 else 9177 { 9178 auto exps = new Expressions(dim); 9179 for (size_t i = 0; i < dim; i++) 9180 { 9181 Expression ex1 = (*tup1.exps)[i]; 9182 Expression ex2 = (*tup2.exps)[i]; 9183 (*exps)[i] = new AssignExp(exp.loc, ex1, ex2); 9184 } 9185 e = new TupleExp(exp.loc, Expression.combine(tup1.e0, tup2.e0), exps); 9186 } 9187 return setResult(e.expressionSemantic(sc)); 9188 } 9189 9190 /* Look for form: e1 = e2.aliasthis. 9191 */ 9192 if (exp.e1.op == EXP.tuple) 9193 { 9194 TupleDeclaration td = isAliasThisTuple(e2x); 9195 if (!td) 9196 goto Lnomatch; 9197 9198 assert(exp.e1.type.ty == Ttuple); 9199 TypeTuple tt = cast(TypeTuple)exp.e1.type; 9200 9201 Expression e0; 9202 Expression ev = extractSideEffect(sc, "__tup", e0, e2x); 9203 9204 auto iexps = new Expressions(); 9205 iexps.push(ev); 9206 for (size_t u = 0; u < iexps.length; u++) 9207 { 9208 Lexpand: 9209 Expression e = (*iexps)[u]; 9210 9211 Parameter arg = Parameter.getNth(tt.arguments, u); 9212 //printf("[%d] iexps.length = %d, ", u, iexps.length); 9213 //printf("e = (%s %s, %s), ", Token.toChars[e.op], e.toChars(), e.type.toChars()); 9214 //printf("arg = (%s, %s)\n", arg.toChars(), arg.type.toChars()); 9215 9216 if (!arg || !e.type.implicitConvTo(arg.type)) 9217 { 9218 // expand initializer to tuple 9219 if (expandAliasThisTuples(iexps, u) != -1) 9220 { 9221 if (iexps.length <= u) 9222 break; 9223 goto Lexpand; 9224 } 9225 goto Lnomatch; 9226 } 9227 } 9228 e2x = new TupleExp(e2x.loc, e0, iexps); 9229 e2x = e2x.expressionSemantic(sc); 9230 if (e2x.op == EXP.error) 9231 { 9232 result = e2x; 9233 return; 9234 } 9235 // Do not need to overwrite this.e2 9236 goto Ltupleassign; 9237 } 9238 Lnomatch: 9239 } 9240 9241 /* Inside constructor, if this is the first assignment of object field, 9242 * rewrite this to initializing the field. 9243 */ 9244 if (exp.op == EXP.assign 9245 && exp.e1.checkModifiable(sc) == Modifiable.initialization) 9246 { 9247 //printf("[%s] change to init - %s\n", exp.loc.toChars(), exp.toChars()); 9248 auto t = exp.type; 9249 exp = new ConstructExp(exp.loc, exp.e1, exp.e2); 9250 exp.type = t; 9251 9252 // https://issues.dlang.org/show_bug.cgi?id=13515 9253 // set Index::modifiable flag for complex AA element initialization 9254 if (auto ie1 = exp.e1.isIndexExp()) 9255 { 9256 Expression e1x = ie1.markSettingAAElem(); 9257 if (e1x.op == EXP.error) 9258 { 9259 result = e1x; 9260 return; 9261 } 9262 } 9263 } 9264 else if (exp.op == EXP.construct && exp.e1.op == EXP.variable && 9265 (cast(VarExp)exp.e1).var.storage_class & (STC.out_ | STC.ref_)) 9266 { 9267 exp.memset = MemorySet.referenceInit; 9268 } 9269 9270 if (exp.op == EXP.assign) // skip EXP.blit and EXP.construct, which are initializations 9271 { 9272 exp.e1.checkSharedAccess(sc); 9273 checkUnsafeAccess(sc, exp.e1, false, true); 9274 } 9275 9276 checkUnsafeAccess(sc, exp.e2, true, true); // Initializer must always be checked 9277 9278 /* If it is an assignment from a 'foreign' type, 9279 * check for operator overloading. 9280 */ 9281 if (exp.memset == MemorySet.referenceInit) 9282 { 9283 // If this is an initialization of a reference, 9284 // do nothing 9285 } 9286 else if (t1.ty == Tstruct) 9287 { 9288 auto e1x = exp.e1; 9289 auto e2x = exp.e2; 9290 auto sd = (cast(TypeStruct)t1).sym; 9291 9292 if (exp.op == EXP.construct) 9293 { 9294 Type t2 = e2x.type.toBasetype(); 9295 if (t2.ty == Tstruct && sd == (cast(TypeStruct)t2).sym) 9296 { 9297 sd.size(exp.loc); 9298 if (sd.sizeok != Sizeok.done) 9299 return setError(); 9300 if (!sd.ctor) 9301 sd.ctor = sd.searchCtor(); 9302 9303 // https://issues.dlang.org/show_bug.cgi?id=15661 9304 // Look for the form from last of comma chain. 9305 auto e2y = lastComma(e2x); 9306 9307 CallExp ce = (e2y.op == EXP.call) ? cast(CallExp)e2y : null; 9308 DotVarExp dve = (ce && ce.e1.op == EXP.dotVariable) 9309 ? cast(DotVarExp)ce.e1 : null; 9310 if (sd.ctor && ce && dve && dve.var.isCtorDeclaration() && 9311 // https://issues.dlang.org/show_bug.cgi?id=19389 9312 dve.e1.op != EXP.dotVariable && 9313 e2y.type.implicitConvTo(t1)) 9314 { 9315 /* Look for form of constructor call which is: 9316 * __ctmp.ctor(arguments...) 9317 */ 9318 9319 /* Before calling the constructor, initialize 9320 * variable with a bit copy of the default 9321 * initializer 9322 */ 9323 Expression einit = getInitExp(sd, exp.loc, sc, t1); 9324 if (einit.op == EXP.error) 9325 { 9326 result = einit; 9327 return; 9328 } 9329 9330 auto ae = new BlitExp(exp.loc, exp.e1, einit); 9331 ae.type = e1x.type; 9332 9333 /* Replace __ctmp being constructed with e1. 9334 * We need to copy constructor call expression, 9335 * because it may be used in other place. 9336 */ 9337 auto dvx = cast(DotVarExp)dve.copy(); 9338 dvx.e1 = e1x; 9339 auto cx = cast(CallExp)ce.copy(); 9340 cx.e1 = dvx; 9341 if (checkConstructorEscape(sc, cx, false)) 9342 return setError(); 9343 9344 Expression e0; 9345 Expression.extractLast(e2x, e0); 9346 9347 auto e = Expression.combine(e0, ae, cx); 9348 e = e.expressionSemantic(sc); 9349 result = e; 9350 return; 9351 } 9352 // https://issues.dlang.org/show_bug.cgi?id=21586 9353 // Rewrite CondExp or e1 will miss direct construction, e.g. 9354 // e1 = a ? S(1) : ...; -> AST: e1 = a ? (S(0)).this(1) : ...; 9355 // a temporary created and an extra destructor call. 9356 // AST will be rewritten to: 9357 // a ? e1 = 0, e1.this(1) : ...; -> blitting plus construction 9358 if (e2x.op == EXP.question) 9359 { 9360 /* Rewrite as: 9361 * a ? e1 = b : e1 = c; 9362 */ 9363 CondExp econd = cast(CondExp)e2x; 9364 Expression ea1 = new ConstructExp(econd.e1.loc, e1x, econd.e1); 9365 Expression ea2 = new ConstructExp(econd.e2.loc, e1x, econd.e2); 9366 Expression e = new CondExp(exp.loc, econd.econd, ea1, ea2); 9367 result = e.expressionSemantic(sc); 9368 return; 9369 } 9370 if (sd.postblit || sd.hasCopyCtor) 9371 { 9372 /* We have a copy constructor for this 9373 */ 9374 9375 if (e2x.isLvalue()) 9376 { 9377 if (sd.hasCopyCtor) 9378 { 9379 /* Rewrite as: 9380 * e1 = init, e1.copyCtor(e2); 9381 */ 9382 Expression einit = new BlitExp(exp.loc, exp.e1, getInitExp(sd, exp.loc, sc, t1)); 9383 einit.type = e1x.type; 9384 9385 Expression e; 9386 e = new DotIdExp(exp.loc, e1x, Id.ctor); 9387 e = new CallExp(exp.loc, e, e2x); 9388 e = new CommaExp(exp.loc, einit, e); 9389 9390 //printf("e: %s\n", e.toChars()); 9391 9392 result = e.expressionSemantic(sc); 9393 return; 9394 } 9395 else 9396 { 9397 if (!e2x.type.implicitConvTo(e1x.type)) 9398 { 9399 exp.error("conversion error from `%s` to `%s`", 9400 e2x.type.toChars(), e1x.type.toChars()); 9401 return setError(); 9402 } 9403 9404 /* Rewrite as: 9405 * (e1 = e2).postblit(); 9406 * 9407 * Blit assignment e1 = e2 returns a reference to the original e1, 9408 * then call the postblit on it. 9409 */ 9410 Expression e = e1x.copy(); 9411 e.type = e.type.mutableOf(); 9412 if (e.type.isShared && !sd.type.isShared) 9413 e.type = e.type.unSharedOf(); 9414 e = new BlitExp(exp.loc, e, e2x); 9415 e = new DotVarExp(exp.loc, e, sd.postblit, false); 9416 e = new CallExp(exp.loc, e); 9417 result = e.expressionSemantic(sc); 9418 return; 9419 } 9420 } 9421 else 9422 { 9423 /* The struct value returned from the function is transferred 9424 * so should not call the destructor on it. 9425 */ 9426 e2x = valueNoDtor(e2x); 9427 } 9428 } 9429 9430 // https://issues.dlang.org/show_bug.cgi?id=19251 9431 // if e2 cannot be converted to e1.type, maybe there is an alias this 9432 if (!e2x.implicitConvTo(t1)) 9433 { 9434 AggregateDeclaration ad2 = isAggregate(e2x.type); 9435 if (ad2 && ad2.aliasthis && !isRecursiveAliasThis(exp.att2, exp.e2.type)) 9436 { 9437 /* Rewrite (e1 op e2) as: 9438 * (e1 op e2.aliasthis) 9439 */ 9440 exp.e2 = new DotIdExp(exp.e2.loc, exp.e2, ad2.aliasthis.ident); 9441 result = exp.expressionSemantic(sc); 9442 return; 9443 } 9444 } 9445 } 9446 else if (!e2x.implicitConvTo(t1)) 9447 { 9448 sd.size(exp.loc); 9449 if (sd.sizeok != Sizeok.done) 9450 return setError(); 9451 if (!sd.ctor) 9452 sd.ctor = sd.searchCtor(); 9453 9454 if (sd.ctor) 9455 { 9456 /* Look for implicit constructor call 9457 * Rewrite as: 9458 * e1 = init, e1.ctor(e2) 9459 */ 9460 9461 /* Fix Issue 5153 : https://issues.dlang.org/show_bug.cgi?id=5153 9462 * Using `new` to initialize a struct object is a common mistake, but 9463 * the error message from the compiler is not very helpful in that 9464 * case. If exp.e2 is a NewExp and the type of new is the same as 9465 * the type as exp.e1 (struct in this case), then we know for sure 9466 * that the user wants to instantiate a struct. This is done to avoid 9467 * issuing an error when the user actually wants to call a constructor 9468 * which receives a class object. 9469 * 9470 * Foo f = new Foo2(0); is a valid expression if Foo has a constructor 9471 * which receives an instance of a Foo2 class 9472 */ 9473 if (exp.e2.op == EXP.new_) 9474 { 9475 auto newExp = cast(NewExp)(exp.e2); 9476 if (newExp.newtype && newExp.newtype == t1) 9477 { 9478 error(exp.loc, "cannot implicitly convert expression `%s` of type `%s` to `%s`", 9479 newExp.toChars(), newExp.type.toChars(), t1.toChars()); 9480 errorSupplemental(exp.loc, "Perhaps remove the `new` keyword?"); 9481 return setError(); 9482 } 9483 } 9484 9485 Expression einit = new BlitExp(exp.loc, e1x, getInitExp(sd, exp.loc, sc, t1)); 9486 einit.type = e1x.type; 9487 9488 Expression e; 9489 e = new DotIdExp(exp.loc, e1x, Id.ctor); 9490 e = new CallExp(exp.loc, e, e2x); 9491 e = new CommaExp(exp.loc, einit, e); 9492 e = e.expressionSemantic(sc); 9493 result = e; 9494 return; 9495 } 9496 if (search_function(sd, Id.call)) 9497 { 9498 /* Look for static opCall 9499 * https://issues.dlang.org/show_bug.cgi?id=2702 9500 * Rewrite as: 9501 * e1 = typeof(e1).opCall(arguments) 9502 */ 9503 e2x = typeDotIdExp(e2x.loc, e1x.type, Id.call); 9504 e2x = new CallExp(exp.loc, e2x, exp.e2); 9505 9506 e2x = e2x.expressionSemantic(sc); 9507 e2x = resolveProperties(sc, e2x); 9508 if (e2x.op == EXP.error) 9509 { 9510 result = e2x; 9511 return; 9512 } 9513 if (e2x.checkValue() || e2x.checkSharedAccess(sc)) 9514 return setError(); 9515 } 9516 } 9517 else // https://issues.dlang.org/show_bug.cgi?id=11355 9518 { 9519 AggregateDeclaration ad2 = isAggregate(e2x.type); 9520 if (ad2 && ad2.aliasthis && !isRecursiveAliasThis(exp.att2, exp.e2.type)) 9521 { 9522 /* Rewrite (e1 op e2) as: 9523 * (e1 op e2.aliasthis) 9524 */ 9525 exp.e2 = new DotIdExp(exp.e2.loc, exp.e2, ad2.aliasthis.ident); 9526 result = exp.expressionSemantic(sc); 9527 return; 9528 } 9529 } 9530 } 9531 else if (exp.op == EXP.assign) 9532 { 9533 if (e1x.op == EXP.index && (cast(IndexExp)e1x).e1.type.toBasetype().ty == Taarray) 9534 { 9535 /* 9536 * Rewrite: 9537 * aa[key] = e2; 9538 * as: 9539 * ref __aatmp = aa; 9540 * ref __aakey = key; 9541 * ref __aaval = e2; 9542 * (__aakey in __aatmp 9543 * ? __aatmp[__aakey].opAssign(__aaval) 9544 * : ConstructExp(__aatmp[__aakey], __aaval)); 9545 */ 9546 // ensure we keep the expr modifiable 9547 Expression esetting = (cast(IndexExp)e1x).markSettingAAElem(); 9548 if (esetting.op == EXP.error) 9549 { 9550 result = esetting; 9551 return; 9552 } 9553 assert(esetting.op == EXP.index); 9554 IndexExp ie = cast(IndexExp) esetting; 9555 Type t2 = e2x.type.toBasetype(); 9556 9557 Expression e0 = null; 9558 Expression ea = extractSideEffect(sc, "__aatmp", e0, ie.e1); 9559 Expression ek = extractSideEffect(sc, "__aakey", e0, ie.e2); 9560 Expression ev = extractSideEffect(sc, "__aaval", e0, e2x); 9561 9562 AssignExp ae = cast(AssignExp)exp.copy(); 9563 ae.e1 = new IndexExp(exp.loc, ea, ek); 9564 ae.e1 = ae.e1.expressionSemantic(sc); 9565 ae.e1 = ae.e1.optimize(WANTvalue); 9566 ae.e2 = ev; 9567 Expression e = ae.op_overload(sc); 9568 if (e) 9569 { 9570 Expression ey = null; 9571 if (t2.ty == Tstruct && sd == t2.toDsymbol(sc)) 9572 { 9573 ey = ev; 9574 } 9575 else if (!ev.implicitConvTo(ie.type) && sd.ctor) 9576 { 9577 // Look for implicit constructor call 9578 // Rewrite as S().ctor(e2) 9579 ey = new StructLiteralExp(exp.loc, sd, null); 9580 ey = new DotIdExp(exp.loc, ey, Id.ctor); 9581 ey = new CallExp(exp.loc, ey, ev); 9582 ey = ey.trySemantic(sc); 9583 } 9584 if (ey) 9585 { 9586 Expression ex; 9587 ex = new IndexExp(exp.loc, ea, ek); 9588 ex = ex.expressionSemantic(sc); 9589 ex = ex.modifiableLvalue(sc, ex); // allocate new slot 9590 ex = ex.optimize(WANTvalue); 9591 9592 ey = new ConstructExp(exp.loc, ex, ey); 9593 ey = ey.expressionSemantic(sc); 9594 if (ey.op == EXP.error) 9595 { 9596 result = ey; 9597 return; 9598 } 9599 ex = e; 9600 9601 // https://issues.dlang.org/show_bug.cgi?id=14144 9602 // The whole expression should have the common type 9603 // of opAssign() return and assigned AA entry. 9604 // Even if there's no common type, expression should be typed as void. 9605 if (!typeMerge(sc, EXP.question, ex, ey)) 9606 { 9607 ex = new CastExp(ex.loc, ex, Type.tvoid); 9608 ey = new CastExp(ey.loc, ey, Type.tvoid); 9609 } 9610 e = new CondExp(exp.loc, new InExp(exp.loc, ek, ea), ex, ey); 9611 } 9612 e = Expression.combine(e0, e); 9613 e = e.expressionSemantic(sc); 9614 result = e; 9615 return; 9616 } 9617 } 9618 else 9619 { 9620 Expression e = exp.op_overload(sc); 9621 if (e) 9622 { 9623 result = e; 9624 return; 9625 } 9626 } 9627 } 9628 else 9629 assert(exp.op == EXP.blit); 9630 9631 if (e2x.checkValue()) 9632 return setError(); 9633 9634 exp.e1 = e1x; 9635 exp.e2 = e2x; 9636 } 9637 else if (t1.ty == Tclass) 9638 { 9639 // Disallow assignment operator overloads for same type 9640 if (exp.op == EXP.assign && !exp.e2.implicitConvTo(exp.e1.type)) 9641 { 9642 Expression e = exp.op_overload(sc); 9643 if (e) 9644 { 9645 result = e; 9646 return; 9647 } 9648 } 9649 if (exp.e2.checkValue()) 9650 return setError(); 9651 } 9652 else if (t1.ty == Tsarray) 9653 { 9654 // SliceExp cannot have static array type without context inference. 9655 assert(exp.e1.op != EXP.slice); 9656 Expression e1x = exp.e1; 9657 Expression e2x = exp.e2; 9658 9659 /* C strings come through as static arrays. May need to adjust the size of the 9660 * string to match the size of e1. 9661 */ 9662 Type t2 = e2x.type.toBasetype(); 9663 if (sc.flags & SCOPE.Cfile && e2x.isStringExp() && t2.isTypeSArray()) 9664 { 9665 uinteger_t dim1 = t1.isTypeSArray().dim.toInteger(); 9666 uinteger_t dim2 = t2.isTypeSArray().dim.toInteger(); 9667 if (dim1 + 1 == dim2 || dim2 < dim1) 9668 { 9669 auto tsa2 = t2.isTypeSArray(); 9670 auto newt = tsa2.next.sarrayOf(dim1).immutableOf(); 9671 e2x = castTo(e2x, sc, newt); 9672 exp.e2 = e2x; 9673 } 9674 } 9675 9676 if (e2x.implicitConvTo(e1x.type)) 9677 { 9678 if (exp.op != EXP.blit && (e2x.op == EXP.slice && (cast(UnaExp)e2x).e1.isLvalue() || e2x.op == EXP.cast_ && (cast(UnaExp)e2x).e1.isLvalue() || e2x.op != EXP.slice && e2x.isLvalue())) 9679 { 9680 if (e1x.checkPostblit(sc, t1)) 9681 return setError(); 9682 } 9683 9684 // e2 matches to t1 because of the implicit length match, so 9685 if (isUnaArrayOp(e2x.op) || isBinArrayOp(e2x.op)) 9686 { 9687 // convert e1 to e1[] 9688 // e.g. e1[] = a[] + b[]; 9689 auto sle = new SliceExp(e1x.loc, e1x, null, null); 9690 sle.arrayop = true; 9691 e1x = sle.expressionSemantic(sc); 9692 } 9693 else 9694 { 9695 // convert e2 to t1 later 9696 // e.g. e1 = [1, 2, 3]; 9697 } 9698 } 9699 else 9700 { 9701 if (e2x.implicitConvTo(t1.nextOf().arrayOf()) > MATCH.nomatch) 9702 { 9703 uinteger_t dim1 = (cast(TypeSArray)t1).dim.toInteger(); 9704 uinteger_t dim2 = dim1; 9705 if (auto ale = e2x.isArrayLiteralExp()) 9706 { 9707 dim2 = ale.elements ? ale.elements.length : 0; 9708 } 9709 else if (auto se = e2x.isSliceExp()) 9710 { 9711 Type tx = toStaticArrayType(se); 9712 if (tx) 9713 dim2 = (cast(TypeSArray)tx).dim.toInteger(); 9714 } 9715 if (dim1 != dim2) 9716 { 9717 exp.error("mismatched array lengths, %d and %d", cast(int)dim1, cast(int)dim2); 9718 return setError(); 9719 } 9720 } 9721 9722 // May be block or element-wise assignment, so 9723 // convert e1 to e1[] 9724 if (exp.op != EXP.assign) 9725 { 9726 // If multidimensional static array, treat as one large array 9727 // 9728 // Find the appropriate array type depending on the assignment, e.g. 9729 // int[3] = int => int[3] 9730 // int[3][2] = int => int[6] 9731 // int[3][2] = int[] => int[3][2] 9732 // int[3][2][4] + int => int[24] 9733 // int[3][2][4] + int[] => int[3][8] 9734 ulong dim = t1.isTypeSArray().dim.toUInteger(); 9735 auto type = t1.nextOf(); 9736 9737 for (TypeSArray tsa; (tsa = type.isTypeSArray()) !is null; ) 9738 { 9739 import core.checkedint : mulu; 9740 9741 // Accumulate skipped dimensions 9742 bool overflow = false; 9743 dim = mulu(dim, tsa.dim.toUInteger(), overflow); 9744 if (overflow || dim >= uint.max) 9745 { 9746 // dym exceeds maximum array size 9747 exp.error("static array `%s` size overflowed to %llu", 9748 e1x.type.toChars(), cast(ulong) dim); 9749 return setError(); 9750 } 9751 9752 // Move to the element type 9753 type = tsa.nextOf().toBasetype(); 9754 9755 // Rewrite ex1 as a static array if a matching type was found 9756 if (e2x.implicitConvTo(type) > MATCH.nomatch) 9757 { 9758 e1x.type = type.sarrayOf(dim); 9759 break; 9760 } 9761 } 9762 } 9763 auto sle = new SliceExp(e1x.loc, e1x, null, null); 9764 sle.arrayop = true; 9765 e1x = sle.expressionSemantic(sc); 9766 } 9767 if (e1x.op == EXP.error) 9768 return setResult(e1x); 9769 if (e2x.op == EXP.error) 9770 return setResult(e2x); 9771 9772 exp.e1 = e1x; 9773 exp.e2 = e2x; 9774 t1 = e1x.type.toBasetype(); 9775 } 9776 /* Check the mutability of e1. 9777 */ 9778 if (auto ale = exp.e1.isArrayLengthExp()) 9779 { 9780 // e1 is not an lvalue, but we let code generator handle it 9781 9782 auto ale1x = ale.e1.modifiableLvalue(sc, exp.e1); 9783 if (ale1x.op == EXP.error) 9784 return setResult(ale1x); 9785 ale.e1 = ale1x; 9786 9787 Type tn = ale.e1.type.toBasetype().nextOf(); 9788 checkDefCtor(ale.loc, tn); 9789 9790 Identifier hook = global.params.tracegc ? Id._d_arraysetlengthTTrace : Id._d_arraysetlengthT; 9791 if (!verifyHookExist(exp.loc, *sc, Id._d_arraysetlengthTImpl, "resizing arrays")) 9792 return setError(); 9793 9794 exp.e2 = exp.e2.expressionSemantic(sc); 9795 auto lc = lastComma(exp.e2); 9796 lc = lc.optimize(WANTvalue); 9797 // use slice expression when arr.length = 0 to avoid runtime call 9798 if(lc.op == EXP.int64 && lc.toInteger() == 0) 9799 { 9800 Expression se = new SliceExp(ale.loc, ale.e1, lc, lc); 9801 Expression as = new AssignExp(ale.loc, ale.e1, se); 9802 as = as.expressionSemantic(sc); 9803 auto res = Expression.combine(as, exp.e2); 9804 res.type = ale.type; 9805 return setResult(res); 9806 } 9807 9808 if (!sc.needsCodegen()) // if compile time creature only 9809 { 9810 exp.type = Type.tsize_t; 9811 return setResult(exp); 9812 } 9813 9814 // Lower to object._d_arraysetlengthTImpl!(typeof(e1))._d_arraysetlengthT{,Trace}(e1, e2) 9815 Expression id = new IdentifierExp(ale.loc, Id.empty); 9816 id = new DotIdExp(ale.loc, id, Id.object); 9817 auto tiargs = new Objects(); 9818 tiargs.push(ale.e1.type); 9819 id = new DotTemplateInstanceExp(ale.loc, id, Id._d_arraysetlengthTImpl, tiargs); 9820 id = new DotIdExp(ale.loc, id, hook); 9821 id = id.expressionSemantic(sc); 9822 9823 auto arguments = new Expressions(); 9824 arguments.reserve(5); 9825 if (global.params.tracegc) 9826 { 9827 auto funcname = (sc.callsc && sc.callsc.func) ? sc.callsc.func.toPrettyChars() : sc.func.toPrettyChars(); 9828 arguments.push(new StringExp(exp.loc, exp.loc.filename.toDString())); 9829 arguments.push(new IntegerExp(exp.loc, exp.loc.linnum, Type.tint32)); 9830 arguments.push(new StringExp(exp.loc, funcname.toDString())); 9831 } 9832 arguments.push(ale.e1); 9833 arguments.push(exp.e2); 9834 9835 Expression ce = new CallExp(ale.loc, id, arguments).expressionSemantic(sc); 9836 auto res = new LoweredAssignExp(exp, ce); 9837 // if (global.params.verbose) 9838 // message("lowered %s =>\n %s", exp.toChars(), res.toChars()); 9839 res.type = Type.tsize_t; 9840 return setResult(res); 9841 } 9842 else if (auto se = exp.e1.isSliceExp()) 9843 { 9844 Type tn = se.type.nextOf(); 9845 const fun = sc.func; 9846 if (exp.op == EXP.assign && !tn.isMutable() && 9847 // allow modifiation in module ctor, see 9848 // https://issues.dlang.org/show_bug.cgi?id=9884 9849 (!fun || (fun && !fun.isStaticCtorDeclaration()))) 9850 { 9851 exp.error("slice `%s` is not mutable", se.toChars()); 9852 return setError(); 9853 } 9854 9855 if (exp.op == EXP.assign && !tn.baseElemOf().isAssignable()) 9856 { 9857 exp.error("slice `%s` is not mutable, struct `%s` has immutable members", 9858 exp.e1.toChars(), tn.baseElemOf().toChars()); 9859 result = ErrorExp.get(); 9860 return; 9861 } 9862 9863 // For conditional operator, both branches need conversion. 9864 while (se.e1.op == EXP.slice) 9865 se = cast(SliceExp)se.e1; 9866 if (se.e1.op == EXP.question && se.e1.type.toBasetype().ty == Tsarray) 9867 { 9868 se.e1 = se.e1.modifiableLvalue(sc, exp.e1); 9869 if (se.e1.op == EXP.error) 9870 return setResult(se.e1); 9871 } 9872 } 9873 else 9874 { 9875 if (t1.ty == Tsarray && exp.op == EXP.assign) 9876 { 9877 Type tn = exp.e1.type.nextOf(); 9878 if (tn && !tn.baseElemOf().isAssignable()) 9879 { 9880 exp.error("array `%s` is not mutable, struct `%s` has immutable members", 9881 exp.e1.toChars(), tn.baseElemOf().toChars()); 9882 result = ErrorExp.get(); 9883 return; 9884 } 9885 } 9886 9887 Expression e1x = exp.e1; 9888 9889 // Try to do a decent error message with the expression 9890 // before it gets constant folded 9891 if (exp.op == EXP.assign) 9892 e1x = e1x.modifiableLvalue(sc, e1old); 9893 9894 e1x = e1x.optimize(WANTvalue, /*keepLvalue*/ true); 9895 9896 if (e1x.op == EXP.error) 9897 { 9898 result = e1x; 9899 return; 9900 } 9901 exp.e1 = e1x; 9902 } 9903 9904 /* Tweak e2 based on the type of e1. 9905 */ 9906 Expression e2x = exp.e2; 9907 Type t2 = e2x.type.toBasetype(); 9908 9909 // If it is a array, get the element type. Note that it may be 9910 // multi-dimensional. 9911 Type telem = t1; 9912 while (telem.ty == Tarray) 9913 telem = telem.nextOf(); 9914 9915 if (exp.e1.op == EXP.slice && t1.nextOf() && 9916 (telem.ty != Tvoid || e2x.op == EXP.null_) && 9917 e2x.implicitConvTo(t1.nextOf())) 9918 { 9919 // Check for block assignment. If it is of type void[], void[][], etc, 9920 // '= null' is the only allowable block assignment (Bug 7493) 9921 exp.memset = MemorySet.blockAssign; // make it easy for back end to tell what this is 9922 e2x = e2x.implicitCastTo(sc, t1.nextOf()); 9923 if (exp.op != EXP.blit && e2x.isLvalue() && exp.e1.checkPostblit(sc, t1.nextOf())) 9924 return setError(); 9925 } 9926 else if (exp.e1.op == EXP.slice && 9927 (t2.ty == Tarray || t2.ty == Tsarray) && 9928 t2.nextOf().implicitConvTo(t1.nextOf())) 9929 { 9930 // Check element-wise assignment. 9931 9932 /* If assigned elements number is known at compile time, 9933 * check the mismatch. 9934 */ 9935 SliceExp se1 = cast(SliceExp)exp.e1; 9936 TypeSArray tsa1 = cast(TypeSArray)toStaticArrayType(se1); 9937 TypeSArray tsa2 = null; 9938 if (auto ale = e2x.isArrayLiteralExp()) 9939 tsa2 = cast(TypeSArray)t2.nextOf().sarrayOf(ale.elements.length); 9940 else if (auto se = e2x.isSliceExp()) 9941 tsa2 = cast(TypeSArray)toStaticArrayType(se); 9942 else 9943 tsa2 = t2.isTypeSArray(); 9944 9945 if (tsa1 && tsa2) 9946 { 9947 uinteger_t dim1 = tsa1.dim.toInteger(); 9948 uinteger_t dim2 = tsa2.dim.toInteger(); 9949 if (dim1 != dim2) 9950 { 9951 exp.error("mismatched array lengths %d and %d for assignment `%s`", cast(int)dim1, cast(int)dim2, exp.toChars()); 9952 return setError(); 9953 } 9954 } 9955 9956 if (exp.op != EXP.blit && 9957 (e2x.op == EXP.slice && (cast(UnaExp)e2x).e1.isLvalue() || 9958 e2x.op == EXP.cast_ && (cast(UnaExp)e2x).e1.isLvalue() || 9959 e2x.op != EXP.slice && e2x.isLvalue())) 9960 { 9961 if (exp.e1.checkPostblit(sc, t1.nextOf())) 9962 return setError(); 9963 } 9964 9965 if (0 && global.params.warnings != DiagnosticReporting.off && !global.gag && exp.op == EXP.assign && 9966 e2x.op != EXP.slice && e2x.op != EXP.assign && 9967 e2x.op != EXP.arrayLiteral && e2x.op != EXP.string_ && 9968 !(e2x.op == EXP.add || e2x.op == EXP.min || 9969 e2x.op == EXP.mul || e2x.op == EXP.div || 9970 e2x.op == EXP.mod || e2x.op == EXP.xor || 9971 e2x.op == EXP.and || e2x.op == EXP.or || 9972 e2x.op == EXP.pow || 9973 e2x.op == EXP.tilde || e2x.op == EXP.negate)) 9974 { 9975 const(char)* e1str = exp.e1.toChars(); 9976 const(char)* e2str = e2x.toChars(); 9977 exp.warning("explicit element-wise assignment `%s = (%s)[]` is better than `%s = %s`", e1str, e2str, e1str, e2str); 9978 } 9979 9980 Type t2n = t2.nextOf(); 9981 Type t1n = t1.nextOf(); 9982 int offset; 9983 if (t2n.equivalent(t1n) || 9984 t1n.isBaseOf(t2n, &offset) && offset == 0) 9985 { 9986 /* Allow copy of distinct qualifier elements. 9987 * eg. 9988 * char[] dst; const(char)[] src; 9989 * dst[] = src; 9990 * 9991 * class C {} class D : C {} 9992 * C[2] ca; D[] da; 9993 * ca[] = da; 9994 */ 9995 if (isArrayOpValid(e2x)) 9996 { 9997 // Don't add CastExp to keep AST for array operations 9998 e2x = e2x.copy(); 9999 e2x.type = exp.e1.type.constOf(); 10000 } 10001 else 10002 e2x = e2x.castTo(sc, exp.e1.type.constOf()); 10003 } 10004 else 10005 { 10006 /* https://issues.dlang.org/show_bug.cgi?id=15778 10007 * A string literal has an array type of immutable 10008 * elements by default, and normally it cannot be convertible to 10009 * array type of mutable elements. But for element-wise assignment, 10010 * elements need to be const at best. So we should give a chance 10011 * to change code unit size for polysemous string literal. 10012 */ 10013 if (e2x.op == EXP.string_) 10014 e2x = e2x.implicitCastTo(sc, exp.e1.type.constOf()); 10015 else 10016 e2x = e2x.implicitCastTo(sc, exp.e1.type); 10017 } 10018 if (t1n.toBasetype.ty == Tvoid && t2n.toBasetype.ty == Tvoid) 10019 { 10020 if (sc.setUnsafe(false, exp.loc, "cannot copy `void[]` to `void[]` in `@safe` code")) 10021 return setError(); 10022 } 10023 } 10024 else 10025 { 10026 if (0 && global.params.warnings != DiagnosticReporting.off && !global.gag && exp.op == EXP.assign && 10027 t1.ty == Tarray && t2.ty == Tsarray && 10028 e2x.op != EXP.slice && 10029 t2.implicitConvTo(t1)) 10030 { 10031 // Disallow ar[] = sa (Converted to ar[] = sa[]) 10032 // Disallow da = sa (Converted to da = sa[]) 10033 const(char)* e1str = exp.e1.toChars(); 10034 const(char)* e2str = e2x.toChars(); 10035 const(char)* atypestr = exp.e1.op == EXP.slice ? "element-wise" : "slice"; 10036 exp.warning("explicit %s assignment `%s = (%s)[]` is better than `%s = %s`", atypestr, e1str, e2str, e1str, e2str); 10037 } 10038 if (exp.op == EXP.blit) 10039 e2x = e2x.castTo(sc, exp.e1.type); 10040 else 10041 { 10042 e2x = e2x.implicitCastTo(sc, exp.e1.type); 10043 10044 // Fix Issue 13435: https://issues.dlang.org/show_bug.cgi?id=13435 10045 10046 // If the implicit cast has failed and the assign expression is 10047 // the initialization of a struct member field 10048 if (e2x.op == EXP.error && exp.op == EXP.construct && t1.ty == Tstruct) 10049 { 10050 scope sd = (cast(TypeStruct)t1).sym; 10051 Dsymbol opAssign = search_function(sd, Id.assign); 10052 10053 // and the struct defines an opAssign 10054 if (opAssign) 10055 { 10056 // offer more information about the cause of the problem 10057 errorSupplemental(exp.loc, 10058 "`%s` is the first assignment of `%s` therefore it represents its initialization", 10059 exp.toChars(), exp.e1.toChars()); 10060 errorSupplemental(exp.loc, 10061 "`opAssign` methods are not used for initialization, but for subsequent assignments"); 10062 } 10063 } 10064 } 10065 } 10066 if (e2x.op == EXP.error) 10067 { 10068 result = e2x; 10069 return; 10070 } 10071 exp.e2 = e2x; 10072 t2 = exp.e2.type.toBasetype(); 10073 10074 /* Look for array operations 10075 */ 10076 if ((t2.ty == Tarray || t2.ty == Tsarray) && isArrayOpValid(exp.e2)) 10077 { 10078 // Look for valid array operations 10079 if (exp.memset != MemorySet.blockAssign && 10080 exp.e1.op == EXP.slice && 10081 (isUnaArrayOp(exp.e2.op) || isBinArrayOp(exp.e2.op))) 10082 { 10083 exp.type = exp.e1.type; 10084 if (exp.op == EXP.construct) // https://issues.dlang.org/show_bug.cgi?id=10282 10085 // tweak mutability of e1 element 10086 exp.e1.type = exp.e1.type.nextOf().mutableOf().arrayOf(); 10087 result = arrayOp(exp, sc); 10088 return; 10089 } 10090 10091 // Drop invalid array operations in e2 10092 // d = a[] + b[], d = (a[] + b[])[0..2], etc 10093 if (checkNonAssignmentArrayOp(exp.e2, exp.memset != MemorySet.blockAssign && exp.op == EXP.assign)) 10094 return setError(); 10095 10096 // Remains valid array assignments 10097 // d = d[], d = [1,2,3], etc 10098 } 10099 10100 /* Don't allow assignment to classes that were allocated on the stack with: 10101 * scope Class c = new Class(); 10102 */ 10103 if (exp.e1.op == EXP.variable && exp.op == EXP.assign) 10104 { 10105 VarExp ve = cast(VarExp)exp.e1; 10106 VarDeclaration vd = ve.var.isVarDeclaration(); 10107 if (vd && vd.onstack) 10108 { 10109 assert(t1.ty == Tclass); 10110 exp.error("cannot rebind scope variables"); 10111 } 10112 } 10113 10114 if (exp.e1.op == EXP.variable && (cast(VarExp)exp.e1).var.ident == Id.ctfe) 10115 { 10116 exp.error("cannot modify compiler-generated variable `__ctfe`"); 10117 } 10118 10119 exp.type = exp.e1.type; 10120 assert(exp.type); 10121 auto assignElem = exp.e2; 10122 auto res = exp.op == EXP.assign ? exp.reorderSettingAAElem(sc) : exp; 10123 /* https://issues.dlang.org/show_bug.cgi?id=22366 10124 * 10125 * `reorderSettingAAElem` creates a tree of comma expressions, however, 10126 * `checkAssignExp` expects only AssignExps. 10127 */ 10128 if (res == exp) // no `AA[k] = v` rewrite was performed 10129 checkAssignEscape(sc, res, false, false); 10130 else 10131 checkNewEscape(sc, assignElem, false); // assigning to AA puts it on heap 10132 10133 if (auto ae = res.isConstructExp()) 10134 { 10135 Type t1b = ae.e1.type.toBasetype(); 10136 if (t1b.ty != Tsarray && t1b.ty != Tarray) 10137 return setResult(res); 10138 10139 // only non-trivial array constructions may need to be lowered (non-POD elements basically) 10140 Type t1e = t1b.nextOf(); 10141 TypeStruct ts = t1e.baseElemOf().isTypeStruct(); 10142 if (!ts || (!ts.sym.postblit && !ts.sym.hasCopyCtor && !ts.sym.dtor)) 10143 return setResult(res); 10144 10145 // don't lower ref-constructions etc. 10146 if (!(t1b.ty == Tsarray || ae.e1.isSliceExp) || 10147 (ae.e1.isVarExp && ae.e1.isVarExp.var.isVarDeclaration.isReference)) 10148 return setResult(res); 10149 10150 // Construction from an equivalent other array? 10151 // Only lower with lvalue RHS elements; let the glue layer move rvalue elements. 10152 Type t2b = ae.e2.type.toBasetype(); 10153 // skip over a (possibly implicit) cast of a static array RHS to a slice 10154 Expression rhs = ae.e2; 10155 Type rhsType = t2b; 10156 if (t2b.ty == Tarray) 10157 { 10158 if (auto ce = rhs.isCastExp()) 10159 { 10160 auto ct = ce.e1.type.toBasetype(); 10161 if (ct.ty == Tsarray) 10162 { 10163 rhs = ce.e1; 10164 rhsType = ct; 10165 } 10166 } 10167 } 10168 10169 if (!sc.needsCodegen()) // interpreter can handle these 10170 return setResult(res); 10171 10172 const lowerToArrayCtor = 10173 ( (rhsType.ty == Tarray && !rhs.isArrayLiteralExp) || 10174 (rhsType.ty == Tsarray && rhs.isLvalue) ) && 10175 t1e.equivalent(t2b.nextOf); 10176 10177 // Construction from a single element? 10178 // If the RHS is an rvalue, then we'll need to make a temporary for it (copied multiple times). 10179 const lowerToArraySetCtor = !lowerToArrayCtor && t1e.equivalent(t2b); 10180 10181 if (lowerToArrayCtor || lowerToArraySetCtor) 10182 { 10183 auto func = lowerToArrayCtor ? Id._d_arrayctor : Id._d_arraysetctor; 10184 const other = lowerToArrayCtor ? "other array" : "value"; 10185 if (!verifyHookExist(exp.loc, *sc, func, "construct array with " ~ other, Id.object)) 10186 return setError(); 10187 10188 // Lower to object._d_array{,set}ctor(e1, e2) 10189 Expression id = new IdentifierExp(exp.loc, Id.empty); 10190 id = new DotIdExp(exp.loc, id, Id.object); 10191 id = new DotIdExp(exp.loc, id, func); 10192 10193 auto arguments = new Expressions(); 10194 arguments.push(new CastExp(ae.loc, ae.e1, t1e.arrayOf).expressionSemantic(sc)); 10195 if (lowerToArrayCtor) 10196 { 10197 arguments.push(new CastExp(ae.loc, rhs, t2b.nextOf.arrayOf).expressionSemantic(sc)); 10198 Expression ce = new CallExp(exp.loc, id, arguments); 10199 res = ce.expressionSemantic(sc); 10200 } 10201 else 10202 { 10203 Expression e0; 10204 // promote an rvalue RHS element to a temporary, it's passed by ref to _d_arraysetctor 10205 if (!ae.e2.isLvalue) 10206 { 10207 auto vd = copyToTemp(STC.scope_, "__setctor", ae.e2); 10208 e0 = new DeclarationExp(vd.loc, vd).expressionSemantic(sc); 10209 arguments.push(new VarExp(vd.loc, vd).expressionSemantic(sc)); 10210 } 10211 else 10212 arguments.push(ae.e2); 10213 10214 Expression ce = new CallExp(exp.loc, id, arguments); 10215 res = Expression.combine(e0, ce).expressionSemantic(sc); 10216 } 10217 10218 if (global.params.verbose) 10219 message("lowered %s =>\n %s", exp.toChars(), res.toChars()); 10220 } 10221 } 10222 else if (auto ae = res.isAssignExp()) 10223 res = lowerArrayAssign(ae); 10224 else if (auto ce = res.isCommaExp()) 10225 { 10226 if (auto ae1 = ce.e1.isAssignExp()) 10227 ce.e1 = lowerArrayAssign(ae1, true); 10228 if (auto ae2 = ce.e2.isAssignExp()) 10229 ce.e2 = lowerArrayAssign(ae2, true); 10230 } 10231 10232 return setResult(res); 10233 } 10234 10235 /*************************************** 10236 * Lower AssignExp to `_d_array{setassign,assign_l,assign_r}` if needed. 10237 * 10238 * Params: 10239 * ae = the AssignExp to be lowered 10240 * fromCommaExp = indicates whether `ae` is part of a CommaExp or not, 10241 * so no unnecessary temporay variable is created. 10242 * Returns: 10243 * a CommaExp contiaining call a to `_d_array{setassign,assign_l,assign_r}` 10244 * if needed or `ae` otherwise 10245 */ 10246 private Expression lowerArrayAssign(AssignExp ae, bool fromCommaExp = false) 10247 { 10248 Type t1b = ae.e1.type.toBasetype(); 10249 if (t1b.ty != Tsarray && t1b.ty != Tarray) 10250 return ae; 10251 10252 const isArrayAssign = (ae.e1.isSliceExp() || ae.e1.type.ty == Tsarray) && 10253 (ae.e2.type.ty == Tsarray || ae.e2.type.ty == Tarray) && 10254 (ae.e1.type.nextOf() && ae.e2.type.nextOf() && ae.e1.type.nextOf.mutableOf.equals(ae.e2.type.nextOf.mutableOf())); 10255 10256 const isArraySetAssign = (ae.e1.isSliceExp() || ae.e1.type.ty == Tsarray) && 10257 (ae.e1.type.nextOf() && ae.e2.type.implicitConvTo(ae.e1.type.nextOf())); 10258 10259 if (!isArrayAssign && !isArraySetAssign) 10260 return ae; 10261 10262 const ts = t1b.nextOf().baseElemOf().isTypeStruct(); 10263 if (!ts || (!ts.sym.postblit && !ts.sym.dtor)) 10264 return ae; 10265 10266 Expression res; 10267 Identifier func = isArraySetAssign ? Id._d_arraysetassign : 10268 ae.e2.isLvalue() || ae.e2.isSliceExp() ? Id._d_arrayassign_l : Id._d_arrayassign_r; 10269 10270 // Lower to `.object._d_array{setassign,assign_l,assign_r}(e1, e2)`` 10271 Expression id = new IdentifierExp(ae.loc, Id.empty); 10272 id = new DotIdExp(ae.loc, id, Id.object); 10273 id = new DotIdExp(ae.loc, id, func); 10274 10275 auto arguments = new Expressions(); 10276 arguments.push(new CastExp(ae.loc, ae.e1, ae.e1.type.nextOf.arrayOf) 10277 .expressionSemantic(sc)); 10278 10279 Expression eValue2, value2 = ae.e2; 10280 if (isArrayAssign && value2.isLvalue()) 10281 value2 = new CastExp(ae.loc, ae.e2, ae.e2.type.nextOf.arrayOf()) 10282 .expressionSemantic(sc); 10283 else if (!fromCommaExp && 10284 (isArrayAssign || (isArraySetAssign && !value2.isLvalue()))) 10285 { 10286 // Rvalues from CommaExps were introduced in `visit(AssignExp)` 10287 // and are temporary variables themselves. Rvalues from trivial 10288 // SliceExps are simply passed by reference without any copying. 10289 10290 // `__assigntmp` will be destroyed together with the array `ae.e1`. 10291 // When `ae.e2` is a variadic arg array, it is also `scope`, so 10292 // `__assigntmp` may also be scope. 10293 StorageClass stc = STC.nodtor; 10294 if (isArrayAssign) 10295 stc |= STC.rvalue | STC.scope_; 10296 10297 auto vd = copyToTemp(stc, "__assigntmp", ae.e2); 10298 eValue2 = new DeclarationExp(vd.loc, vd).expressionSemantic(sc); 10299 value2 = new VarExp(vd.loc, vd).expressionSemantic(sc); 10300 } 10301 arguments.push(value2); 10302 10303 Expression ce = new CallExp(ae.loc, id, arguments); 10304 res = Expression.combine(eValue2, ce).expressionSemantic(sc); 10305 if (isArrayAssign) 10306 res = Expression.combine(res, ae.e1).expressionSemantic(sc); 10307 10308 if (global.params.verbose) 10309 message("lowered %s =>\n %s", ae.toChars(), res.toChars()); 10310 10311 return res; 10312 } 10313 10314 override void visit(PowAssignExp exp) 10315 { 10316 if (exp.type) 10317 { 10318 result = exp; 10319 return; 10320 } 10321 10322 Expression e = exp.op_overload(sc); 10323 if (e) 10324 { 10325 result = e; 10326 return; 10327 } 10328 10329 if (exp.e1.checkReadModifyWrite(exp.op, exp.e2)) 10330 return setError(); 10331 10332 assert(exp.e1.type && exp.e2.type); 10333 if (exp.e1.op == EXP.slice || exp.e1.type.ty == Tarray || exp.e1.type.ty == Tsarray) 10334 { 10335 if (checkNonAssignmentArrayOp(exp.e1)) 10336 return setError(); 10337 10338 // T[] ^^= ... 10339 if (exp.e2.implicitConvTo(exp.e1.type.nextOf())) 10340 { 10341 // T[] ^^= T 10342 exp.e2 = exp.e2.castTo(sc, exp.e1.type.nextOf()); 10343 } 10344 else if (Expression ex = typeCombine(exp, sc)) 10345 { 10346 result = ex; 10347 return; 10348 } 10349 10350 // Check element types are arithmetic 10351 Type tb1 = exp.e1.type.nextOf().toBasetype(); 10352 Type tb2 = exp.e2.type.toBasetype(); 10353 if (tb2.ty == Tarray || tb2.ty == Tsarray) 10354 tb2 = tb2.nextOf().toBasetype(); 10355 if ((tb1.isintegral() || tb1.isfloating()) && (tb2.isintegral() || tb2.isfloating())) 10356 { 10357 exp.type = exp.e1.type; 10358 result = arrayOp(exp, sc); 10359 return; 10360 } 10361 } 10362 else 10363 { 10364 exp.e1 = exp.e1.modifiableLvalue(sc, exp.e1); 10365 } 10366 10367 if ((exp.e1.type.isintegral() || exp.e1.type.isfloating()) && (exp.e2.type.isintegral() || exp.e2.type.isfloating())) 10368 { 10369 Expression e0 = null; 10370 e = exp.reorderSettingAAElem(sc); 10371 e = Expression.extractLast(e, e0); 10372 assert(e == exp); 10373 10374 if (exp.e1.op == EXP.variable) 10375 { 10376 // Rewrite: e1 = e1 ^^ e2 10377 e = new PowExp(exp.loc, exp.e1.syntaxCopy(), exp.e2); 10378 e = new AssignExp(exp.loc, exp.e1, e); 10379 } 10380 else 10381 { 10382 // Rewrite: ref tmp = e1; tmp = tmp ^^ e2 10383 auto v = copyToTemp(STC.ref_, "__powtmp", exp.e1); 10384 auto de = new DeclarationExp(exp.e1.loc, v); 10385 auto ve = new VarExp(exp.e1.loc, v); 10386 e = new PowExp(exp.loc, ve, exp.e2); 10387 e = new AssignExp(exp.loc, new VarExp(exp.e1.loc, v), e); 10388 e = new CommaExp(exp.loc, de, e); 10389 } 10390 e = Expression.combine(e0, e); 10391 e = e.expressionSemantic(sc); 10392 result = e; 10393 return; 10394 } 10395 result = exp.incompatibleTypes(); 10396 } 10397 10398 override void visit(CatAssignExp exp) 10399 { 10400 if (exp.type) 10401 { 10402 result = exp; 10403 return; 10404 } 10405 10406 //printf("CatAssignExp::semantic() %s\n", exp.toChars()); 10407 Expression e = exp.op_overload(sc); 10408 if (e) 10409 { 10410 result = e; 10411 return; 10412 } 10413 10414 if (SliceExp se = exp.e1.isSliceExp()) 10415 { 10416 if (se.e1.type.toBasetype().ty == Tsarray) 10417 { 10418 exp.error("cannot append to static array `%s`", se.e1.type.toChars()); 10419 return setError(); 10420 } 10421 } 10422 10423 exp.e1 = exp.e1.modifiableLvalue(sc, exp.e1); 10424 if (exp.e1.op == EXP.error) 10425 { 10426 result = exp.e1; 10427 return; 10428 } 10429 if (exp.e2.op == EXP.error) 10430 { 10431 result = exp.e2; 10432 return; 10433 } 10434 10435 if (checkNonAssignmentArrayOp(exp.e2)) 10436 return setError(); 10437 10438 Type tb1 = exp.e1.type.toBasetype(); 10439 Type tb1next = tb1.nextOf(); 10440 Type tb2 = exp.e2.type.toBasetype(); 10441 10442 /* Possibilities: 10443 * EXP.concatenateAssign: appending T[] to T[] 10444 * EXP.concatenateElemAssign: appending T to T[] 10445 * EXP.concatenateDcharAssign: appending dchar to T[] 10446 */ 10447 if ((tb1.ty == Tarray) && 10448 (tb2.ty == Tarray || tb2.ty == Tsarray) && 10449 (exp.e2.implicitConvTo(exp.e1.type) || 10450 (tb2.nextOf().implicitConvTo(tb1next) && 10451 (tb2.nextOf().size(Loc.initial) == tb1next.size(Loc.initial))))) 10452 { 10453 // EXP.concatenateAssign 10454 assert(exp.op == EXP.concatenateAssign); 10455 if (exp.e1.checkPostblit(sc, tb1next)) 10456 return setError(); 10457 10458 exp.e2 = exp.e2.castTo(sc, exp.e1.type); 10459 } 10460 else if ((tb1.ty == Tarray) && exp.e2.implicitConvTo(tb1next)) 10461 { 10462 /* https://issues.dlang.org/show_bug.cgi?id=19782 10463 * 10464 * If e2 is implicitly convertible to tb1next, the conversion 10465 * might be done through alias this, in which case, e2 needs to 10466 * be modified accordingly (e2 => e2.aliasthis). 10467 */ 10468 if (tb2.ty == Tstruct && (cast(TypeStruct)tb2).implicitConvToThroughAliasThis(tb1next)) 10469 goto Laliasthis; 10470 if (tb2.ty == Tclass && (cast(TypeClass)tb2).implicitConvToThroughAliasThis(tb1next)) 10471 goto Laliasthis; 10472 // Append element 10473 if (exp.e2.checkPostblit(sc, tb2)) 10474 return setError(); 10475 10476 if (checkNewEscape(sc, exp.e2, false)) 10477 return setError(); 10478 10479 exp = new CatElemAssignExp(exp.loc, exp.type, exp.e1, exp.e2.castTo(sc, tb1next)); 10480 exp.e2 = doCopyOrMove(sc, exp.e2); 10481 } 10482 else if (tb1.ty == Tarray && 10483 (tb1next.ty == Tchar || tb1next.ty == Twchar) && 10484 exp.e2.type.ty != tb1next.ty && 10485 exp.e2.implicitConvTo(Type.tdchar)) 10486 { 10487 // Append dchar to char[] or wchar[] 10488 exp = new CatDcharAssignExp(exp.loc, exp.type, exp.e1, exp.e2.castTo(sc, Type.tdchar)); 10489 10490 /* Do not allow appending wchar to char[] because if wchar happens 10491 * to be a surrogate pair, nothing good can result. 10492 */ 10493 } 10494 else 10495 { 10496 // Try alias this on first operand 10497 static Expression tryAliasThisForLhs(BinAssignExp exp, Scope* sc) 10498 { 10499 AggregateDeclaration ad1 = isAggregate(exp.e1.type); 10500 if (!ad1 || !ad1.aliasthis) 10501 return null; 10502 10503 /* Rewrite (e1 op e2) as: 10504 * (e1.aliasthis op e2) 10505 */ 10506 if (isRecursiveAliasThis(exp.att1, exp.e1.type)) 10507 return null; 10508 //printf("att %s e1 = %s\n", Token.toChars(e.op), e.e1.type.toChars()); 10509 Expression e1 = new DotIdExp(exp.loc, exp.e1, ad1.aliasthis.ident); 10510 BinExp be = cast(BinExp)exp.copy(); 10511 be.e1 = e1; 10512 return be.trySemantic(sc); 10513 } 10514 10515 // Try alias this on second operand 10516 static Expression tryAliasThisForRhs(BinAssignExp exp, Scope* sc) 10517 { 10518 AggregateDeclaration ad2 = isAggregate(exp.e2.type); 10519 if (!ad2 || !ad2.aliasthis) 10520 return null; 10521 /* Rewrite (e1 op e2) as: 10522 * (e1 op e2.aliasthis) 10523 */ 10524 if (isRecursiveAliasThis(exp.att2, exp.e2.type)) 10525 return null; 10526 //printf("att %s e2 = %s\n", Token.toChars(e.op), e.e2.type.toChars()); 10527 Expression e2 = new DotIdExp(exp.loc, exp.e2, ad2.aliasthis.ident); 10528 BinExp be = cast(BinExp)exp.copy(); 10529 be.e2 = e2; 10530 return be.trySemantic(sc); 10531 } 10532 10533 Laliasthis: 10534 result = tryAliasThisForLhs(exp, sc); 10535 if (result) 10536 return; 10537 10538 result = tryAliasThisForRhs(exp, sc); 10539 if (result) 10540 return; 10541 10542 exp.error("cannot append type `%s` to type `%s`", tb2.toChars(), tb1.toChars()); 10543 return setError(); 10544 } 10545 10546 if (exp.e2.checkValue() || exp.e2.checkSharedAccess(sc)) 10547 return setError(); 10548 10549 exp.type = exp.e1.type; 10550 auto assignElem = exp.e2; 10551 auto res = exp.reorderSettingAAElem(sc); 10552 if (res != exp) // `AA[k] = v` rewrite was performed 10553 checkNewEscape(sc, assignElem, false); 10554 else if (exp.op == EXP.concatenateElemAssign || exp.op == EXP.concatenateDcharAssign) 10555 checkAssignEscape(sc, res, false, false); 10556 10557 result = res; 10558 10559 if ((exp.op == EXP.concatenateAssign || exp.op == EXP.concatenateElemAssign) && 10560 sc.needsCodegen()) 10561 { 10562 // if aa ordering is triggered, `res` will be a CommaExp 10563 // and `.e2` will be the rewritten original expression. 10564 10565 // `output` will point to the expression that the lowering will overwrite 10566 Expression* output; 10567 if (auto comma = res.isCommaExp()) 10568 { 10569 output = &comma.e2; 10570 // manual cast because it could be either CatAssignExp or CatElemAssignExp 10571 exp = cast(CatAssignExp)comma.e2; 10572 } 10573 else 10574 { 10575 output = &result; 10576 exp = cast(CatAssignExp)result; 10577 } 10578 10579 if (exp.op == EXP.concatenateAssign) 10580 { 10581 Identifier hook = global.params.tracegc ? Id._d_arrayappendTTrace : Id._d_arrayappendT; 10582 10583 if (!verifyHookExist(exp.loc, *sc, hook, "appending array to arrays", Id.object)) 10584 return setError(); 10585 10586 // Lower to object._d_arrayappendT{,Trace}({file, line, funcname}, e1, e2) 10587 Expression id = new IdentifierExp(exp.loc, Id.empty); 10588 id = new DotIdExp(exp.loc, id, Id.object); 10589 id = new DotIdExp(exp.loc, id, hook); 10590 10591 auto arguments = new Expressions(); 10592 arguments.reserve(5); 10593 if (global.params.tracegc) 10594 { 10595 auto funcname = (sc.callsc && sc.callsc.func) ? sc.callsc.func.toPrettyChars() : sc.func.toPrettyChars(); 10596 arguments.push(new StringExp(exp.loc, exp.loc.filename.toDString())); 10597 arguments.push(new IntegerExp(exp.loc, exp.loc.linnum, Type.tint32)); 10598 arguments.push(new StringExp(exp.loc, funcname.toDString())); 10599 } 10600 10601 arguments.push(exp.e1); 10602 arguments.push(exp.e2); 10603 Expression ce = new CallExp(exp.loc, id, arguments); 10604 *output = ce.expressionSemantic(sc); 10605 } 10606 else if (exp.op == EXP.concatenateElemAssign) 10607 { 10608 /* Do not lower concats to the indices array returned by 10609 *`static foreach`, as this array is only used at compile-time. 10610 */ 10611 if (auto ve = exp.e1.isVarExp) 10612 { 10613 import core.stdc.ctype : isdigit; 10614 // The name of the indices array that static foreach loops uses. 10615 // See dmd.cond.lowerNonArrayAggregate 10616 enum varName = "__res"; 10617 const(char)[] id = ve.var.ident.toString; 10618 if (ve.var.storage_class & STC.temp && id.length > varName.length && 10619 id[0 .. varName.length] == varName && id[varName.length].isdigit) 10620 return; 10621 } 10622 10623 Identifier hook = global.params.tracegc ? Id._d_arrayappendcTXTrace : Id._d_arrayappendcTX; 10624 if (!verifyHookExist(exp.loc, *sc, Id._d_arrayappendcTXImpl, "appending element to arrays", Id.object)) 10625 return setError(); 10626 10627 // Lower to object._d_arrayappendcTXImpl!(typeof(e1))._d_arrayappendcTX{,Trace}(e1, 1), e1[$-1]=e2 10628 Expression id = new IdentifierExp(exp.loc, Id.empty); 10629 id = new DotIdExp(exp.loc, id, Id.object); 10630 auto tiargs = new Objects(); 10631 tiargs.push(exp.e1.type); 10632 id = new DotTemplateInstanceExp(exp.loc, id, Id._d_arrayappendcTXImpl, tiargs); 10633 id = new DotIdExp(exp.loc, id, hook); 10634 10635 auto arguments = new Expressions(); 10636 arguments.reserve(5); 10637 if (global.params.tracegc) 10638 { 10639 auto funcname = (sc.callsc && sc.callsc.func) ? sc.callsc.func.toPrettyChars() : sc.func.toPrettyChars(); 10640 arguments.push(new StringExp(exp.loc, exp.loc.filename.toDString())); 10641 arguments.push(new IntegerExp(exp.loc, exp.loc.linnum, Type.tint32)); 10642 arguments.push(new StringExp(exp.loc, funcname.toDString())); 10643 } 10644 10645 Expression eValue1; 10646 Expression value1 = extractSideEffect(sc, "__appendtmp", eValue1, exp.e1); 10647 10648 arguments.push(value1); 10649 arguments.push(new IntegerExp(exp.loc, 1, Type.tsize_t)); 10650 10651 Expression ce = new CallExp(exp.loc, id, arguments); 10652 10653 Expression eValue2; 10654 Expression value2 = exp.e2; 10655 if (!value2.isVarExp() && !value2.isConst()) 10656 { 10657 /* Before the template hook, this check was performed in e2ir.d 10658 * for expressions like `a ~= a[$-1]`. Here, $ will be modified 10659 * by calling `_d_arrayappendcT`, so we need to save `a[$-1]` in 10660 * a temporary variable. 10661 */ 10662 value2 = extractSideEffect(sc, "__appendtmp", eValue2, value2, true); 10663 exp.e2 = value2; 10664 10665 // `__appendtmp*` will be destroyed together with the array `exp.e1`. 10666 auto vd = eValue2.isDeclarationExp().declaration.isVarDeclaration(); 10667 vd.storage_class |= STC.nodtor; 10668 // Be more explicit that this "declaration" is local to the expression 10669 vd.storage_class |= STC.exptemp; 10670 } 10671 10672 auto ale = new ArrayLengthExp(exp.loc, value1); 10673 auto elem = new IndexExp(exp.loc, value1, new MinExp(exp.loc, ale, IntegerExp.literal!1)); 10674 auto ae = new ConstructExp(exp.loc, elem, value2); 10675 10676 auto e0 = Expression.combine(ce, ae).expressionSemantic(sc); 10677 e0 = Expression.combine(e0, value1); 10678 e0 = Expression.combine(eValue1, e0); 10679 10680 e0 = Expression.combine(eValue2, e0); 10681 10682 *output = e0.expressionSemantic(sc); 10683 } 10684 } 10685 10686 } 10687 10688 override void visit(AddExp exp) 10689 { 10690 static if (LOGSEMANTIC) 10691 { 10692 printf("AddExp::semantic('%s')\n", exp.toChars()); 10693 } 10694 if (exp.type) 10695 { 10696 result = exp; 10697 return; 10698 } 10699 10700 if (Expression ex = binSemanticProp(exp, sc)) 10701 { 10702 result = ex; 10703 return; 10704 } 10705 Expression e = exp.op_overload(sc); 10706 if (e) 10707 { 10708 result = e; 10709 return; 10710 } 10711 10712 /* ImportC: convert arrays to pointers, functions to pointers to functions 10713 */ 10714 exp.e1 = exp.e1.arrayFuncConv(sc); 10715 exp.e2 = exp.e2.arrayFuncConv(sc); 10716 10717 Type tb1 = exp.e1.type.toBasetype(); 10718 Type tb2 = exp.e2.type.toBasetype(); 10719 10720 bool err = false; 10721 if (tb1.ty == Tdelegate || tb1.isPtrToFunction()) 10722 { 10723 err |= exp.e1.checkArithmetic() || exp.e1.checkSharedAccess(sc); 10724 } 10725 if (tb2.ty == Tdelegate || tb2.isPtrToFunction()) 10726 { 10727 err |= exp.e2.checkArithmetic() || exp.e2.checkSharedAccess(sc); 10728 } 10729 if (err) 10730 return setError(); 10731 10732 if (tb1.ty == Tpointer && exp.e2.type.isintegral() || tb2.ty == Tpointer && exp.e1.type.isintegral()) 10733 { 10734 result = scaleFactor(exp, sc); 10735 return; 10736 } 10737 10738 if (tb1.ty == Tpointer && tb2.ty == Tpointer) 10739 { 10740 result = exp.incompatibleTypes(); 10741 return; 10742 } 10743 10744 if (Expression ex = typeCombine(exp, sc)) 10745 { 10746 result = ex; 10747 return; 10748 } 10749 10750 Type tb = exp.type.toBasetype(); 10751 if (tb.ty == Tarray || tb.ty == Tsarray) 10752 { 10753 if (!isArrayOpValid(exp)) 10754 { 10755 result = arrayOpInvalidError(exp); 10756 return; 10757 } 10758 result = exp; 10759 return; 10760 } 10761 10762 tb1 = exp.e1.type.toBasetype(); 10763 if (!target.isVectorOpSupported(tb1, exp.op, tb2)) 10764 { 10765 result = exp.incompatibleTypes(); 10766 return; 10767 } 10768 if ((tb1.isreal() && exp.e2.type.isimaginary()) || (tb1.isimaginary() && exp.e2.type.isreal())) 10769 { 10770 switch (exp.type.toBasetype().ty) 10771 { 10772 case Tfloat32: 10773 case Timaginary32: 10774 exp.type = Type.tcomplex32; 10775 break; 10776 10777 case Tfloat64: 10778 case Timaginary64: 10779 exp.type = Type.tcomplex64; 10780 break; 10781 10782 case Tfloat80: 10783 case Timaginary80: 10784 exp.type = Type.tcomplex80; 10785 break; 10786 10787 default: 10788 assert(0); 10789 } 10790 } 10791 result = exp; 10792 } 10793 10794 override void visit(MinExp exp) 10795 { 10796 static if (LOGSEMANTIC) 10797 { 10798 printf("MinExp::semantic('%s')\n", exp.toChars()); 10799 } 10800 if (exp.type) 10801 { 10802 result = exp; 10803 return; 10804 } 10805 10806 if (Expression ex = binSemanticProp(exp, sc)) 10807 { 10808 result = ex; 10809 return; 10810 } 10811 Expression e = exp.op_overload(sc); 10812 if (e) 10813 { 10814 result = e; 10815 return; 10816 } 10817 10818 /* ImportC: convert arrays to pointers, functions to pointers to functions 10819 */ 10820 exp.e1 = exp.e1.arrayFuncConv(sc); 10821 exp.e2 = exp.e2.arrayFuncConv(sc); 10822 10823 Type t1 = exp.e1.type.toBasetype(); 10824 Type t2 = exp.e2.type.toBasetype(); 10825 10826 bool err = false; 10827 if (t1.ty == Tdelegate || t1.isPtrToFunction()) 10828 { 10829 err |= exp.e1.checkArithmetic() || exp.e1.checkSharedAccess(sc); 10830 } 10831 if (t2.ty == Tdelegate || t2.isPtrToFunction()) 10832 { 10833 err |= exp.e2.checkArithmetic() || exp.e2.checkSharedAccess(sc); 10834 } 10835 if (err) 10836 return setError(); 10837 10838 if (t1.ty == Tpointer) 10839 { 10840 if (t2.ty == Tpointer) 10841 { 10842 // https://dlang.org/spec/expression.html#add_expressions 10843 // "If both operands are pointers, and the operator is -, the pointers are 10844 // subtracted and the result is divided by the size of the type pointed to 10845 // by the operands. It is an error if the pointers point to different types." 10846 Type p1 = t1.nextOf(); 10847 Type p2 = t2.nextOf(); 10848 10849 if (!p1.equivalent(p2)) 10850 { 10851 // Deprecation to remain for at least a year, after which this should be 10852 // changed to an error 10853 // See https://github.com/dlang/dmd/pull/7332 10854 deprecation(exp.loc, 10855 "cannot subtract pointers to different types: `%s` and `%s`.", 10856 t1.toChars(), t2.toChars()); 10857 } 10858 10859 // Need to divide the result by the stride 10860 // Replace (ptr - ptr) with (ptr - ptr) / stride 10861 long stride; 10862 10863 // make sure pointer types are compatible 10864 if (Expression ex = typeCombine(exp, sc)) 10865 { 10866 result = ex; 10867 return; 10868 } 10869 10870 exp.type = Type.tptrdiff_t; 10871 stride = t2.nextOf().size(); 10872 if (stride == 0) 10873 { 10874 e = new IntegerExp(exp.loc, 0, Type.tptrdiff_t); 10875 } 10876 else if (stride == cast(long)SIZE_INVALID) 10877 e = ErrorExp.get(); 10878 else 10879 { 10880 e = new DivExp(exp.loc, exp, new IntegerExp(Loc.initial, stride, Type.tptrdiff_t)); 10881 e.type = Type.tptrdiff_t; 10882 } 10883 } 10884 else if (t2.isintegral()) 10885 e = scaleFactor(exp, sc); 10886 else 10887 { 10888 exp.error("can't subtract `%s` from pointer", t2.toChars()); 10889 e = ErrorExp.get(); 10890 } 10891 result = e; 10892 return; 10893 } 10894 if (t2.ty == Tpointer) 10895 { 10896 exp.type = exp.e2.type; 10897 exp.error("can't subtract pointer from `%s`", exp.e1.type.toChars()); 10898 return setError(); 10899 } 10900 10901 if (Expression ex = typeCombine(exp, sc)) 10902 { 10903 result = ex; 10904 return; 10905 } 10906 10907 Type tb = exp.type.toBasetype(); 10908 if (tb.ty == Tarray || tb.ty == Tsarray) 10909 { 10910 if (!isArrayOpValid(exp)) 10911 { 10912 result = arrayOpInvalidError(exp); 10913 return; 10914 } 10915 result = exp; 10916 return; 10917 } 10918 10919 t1 = exp.e1.type.toBasetype(); 10920 t2 = exp.e2.type.toBasetype(); 10921 if (!target.isVectorOpSupported(t1, exp.op, t2)) 10922 { 10923 result = exp.incompatibleTypes(); 10924 return; 10925 } 10926 if ((t1.isreal() && t2.isimaginary()) || (t1.isimaginary() && t2.isreal())) 10927 { 10928 switch (exp.type.ty) 10929 { 10930 case Tfloat32: 10931 case Timaginary32: 10932 exp.type = Type.tcomplex32; 10933 break; 10934 10935 case Tfloat64: 10936 case Timaginary64: 10937 exp.type = Type.tcomplex64; 10938 break; 10939 10940 case Tfloat80: 10941 case Timaginary80: 10942 exp.type = Type.tcomplex80; 10943 break; 10944 10945 default: 10946 assert(0); 10947 } 10948 } 10949 result = exp; 10950 return; 10951 } 10952 10953 /** 10954 * If the given expression is a `CatExp`, the function tries to lower it to 10955 * `_d_arraycatnTX`. 10956 * 10957 * Params: 10958 * ee = the `CatExp` to lower 10959 * Returns: 10960 * `_d_arraycatnTX(e1, e2, ..., en)` if `ee` is `e1 ~ e2 ~ ... en` 10961 * `ee` otherwise 10962 */ 10963 private Expression lowerToArrayCat(CatExp exp) 10964 { 10965 // String literals are concatenated by the compiler. No lowering is needed. 10966 if ((exp.e1.isStringExp() && (exp.e2.isIntegerExp() || exp.e2.isStringExp())) || 10967 (exp.e2.isStringExp() && (exp.e1.isIntegerExp() || exp.e1.isStringExp()))) 10968 return exp; 10969 10970 Identifier hook = global.params.tracegc ? Id._d_arraycatnTXTrace : Id._d_arraycatnTX; 10971 if (!verifyHookExist(exp.loc, *sc, hook, "concatenating arrays")) 10972 { 10973 setError(); 10974 return result; 10975 } 10976 10977 void handleCatArgument(Expressions *arguments, Expression e) 10978 { 10979 if (auto ce = e.isCatExp()) 10980 { 10981 Expression lowering = ce.lowering; 10982 10983 /* Skip `file`, `line`, and `funcname` if the hook of the parent 10984 * `CatExp` is `_d_arraycatnTXTrace`. 10985 */ 10986 if (auto callExp = isRuntimeHook(lowering, hook)) 10987 { 10988 if (hook == Id._d_arraycatnTX) 10989 arguments.pushSlice((*callExp.arguments)[]); 10990 else 10991 arguments.pushSlice((*callExp.arguments)[3 .. $]); 10992 } 10993 } 10994 else 10995 arguments.push(e); 10996 } 10997 10998 auto arguments = new Expressions(); 10999 if (global.params.tracegc) 11000 { 11001 auto funcname = (sc.callsc && sc.callsc.func) ? 11002 sc.callsc.func.toPrettyChars() : sc.func.toPrettyChars(); 11003 arguments.push(new StringExp(exp.loc, exp.loc.filename.toDString())); 11004 arguments.push(new IntegerExp(exp.loc, exp.loc.linnum, Type.tint32)); 11005 arguments.push(new StringExp(exp.loc, funcname.toDString())); 11006 } 11007 11008 handleCatArgument(arguments, exp.e1); 11009 handleCatArgument(arguments, exp.e2); 11010 11011 Expression id = new IdentifierExp(exp.loc, Id.empty); 11012 id = new DotIdExp(exp.loc, id, Id.object); 11013 11014 auto tiargs = new Objects(); 11015 tiargs.push(exp.type); 11016 id = new DotTemplateInstanceExp(exp.loc, id, hook, tiargs); 11017 id = new CallExp(exp.loc, id, arguments); 11018 return id.expressionSemantic(sc); 11019 } 11020 11021 void trySetCatExpLowering(Expression exp) 11022 { 11023 /* `_d_arraycatnTX` canot be used with `-betterC`, but `CatExp`s may be 11024 * used with `-betterC`, but only during CTFE. 11025 */ 11026 if (global.params.betterC || !sc.needsCodegen()) 11027 return; 11028 11029 if (auto ce = exp.isCatExp()) 11030 ce.lowering = lowerToArrayCat(ce); 11031 } 11032 11033 override void visit(CatExp exp) 11034 { 11035 // https://dlang.org/spec/expression.html#cat_expressions 11036 //printf("CatExp.semantic() %s\n", toChars()); 11037 if (exp.type) 11038 { 11039 result = exp; 11040 return; 11041 } 11042 11043 if (Expression ex = binSemanticProp(exp, sc)) 11044 { 11045 result = ex; 11046 return; 11047 } 11048 Expression e = exp.op_overload(sc); 11049 if (e) 11050 { 11051 result = e; 11052 return; 11053 } 11054 11055 Type tb1 = exp.e1.type.toBasetype(); 11056 Type tb2 = exp.e2.type.toBasetype(); 11057 11058 auto f1 = checkNonAssignmentArrayOp(exp.e1); 11059 auto f2 = checkNonAssignmentArrayOp(exp.e2); 11060 if (f1 || f2) 11061 return setError(); 11062 11063 Type tb1next = tb1.nextOf(); 11064 Type tb2next = tb2.nextOf(); 11065 11066 // Check for: array ~ array 11067 if (tb1next && tb2next && (tb1next.implicitConvTo(tb2next) >= MATCH.constant || tb2next.implicitConvTo(tb1next) >= MATCH.constant || exp.e1.op == EXP.arrayLiteral && exp.e1.implicitConvTo(tb2) || exp.e2.op == EXP.arrayLiteral && exp.e2.implicitConvTo(tb1))) 11068 { 11069 /* https://issues.dlang.org/show_bug.cgi?id=9248 11070 * Here to avoid the case of: 11071 * void*[] a = [cast(void*)1]; 11072 * void*[] b = [cast(void*)2]; 11073 * a ~ b; 11074 * becoming: 11075 * a ~ [cast(void*)b]; 11076 */ 11077 11078 /* https://issues.dlang.org/show_bug.cgi?id=14682 11079 * Also to avoid the case of: 11080 * int[][] a; 11081 * a ~ []; 11082 * becoming: 11083 * a ~ cast(int[])[]; 11084 */ 11085 goto Lpeer; 11086 } 11087 11088 // Check for: array ~ element 11089 if ((tb1.ty == Tsarray || tb1.ty == Tarray) && tb2.ty != Tvoid) 11090 { 11091 if (exp.e1.op == EXP.arrayLiteral) 11092 { 11093 exp.e2 = doCopyOrMove(sc, exp.e2); 11094 // https://issues.dlang.org/show_bug.cgi?id=14686 11095 // Postblit call appears in AST, and this is 11096 // finally translated to an ArrayLiteralExp in below optimize(). 11097 } 11098 else if (exp.e1.op == EXP.string_) 11099 { 11100 // No postblit call exists on character (integer) value. 11101 } 11102 else 11103 { 11104 if (exp.e2.checkPostblit(sc, tb2)) 11105 return setError(); 11106 // Postblit call will be done in runtime helper function 11107 } 11108 11109 if (exp.e1.op == EXP.arrayLiteral && exp.e1.implicitConvTo(tb2.arrayOf())) 11110 { 11111 exp.e1 = exp.e1.implicitCastTo(sc, tb2.arrayOf()); 11112 exp.type = tb2.arrayOf(); 11113 goto L2elem; 11114 } 11115 if (exp.e2.implicitConvTo(tb1next) >= MATCH.convert) 11116 { 11117 exp.e2 = exp.e2.implicitCastTo(sc, tb1next); 11118 exp.type = tb1next.arrayOf(); 11119 L2elem: 11120 if (checkNewEscape(sc, exp.e2, false)) 11121 return setError(); 11122 result = exp.optimize(WANTvalue); 11123 trySetCatExpLowering(result); 11124 return; 11125 } 11126 } 11127 // Check for: element ~ array 11128 if ((tb2.ty == Tsarray || tb2.ty == Tarray) && tb1.ty != Tvoid) 11129 { 11130 if (exp.e2.op == EXP.arrayLiteral) 11131 { 11132 exp.e1 = doCopyOrMove(sc, exp.e1); 11133 } 11134 else if (exp.e2.op == EXP.string_) 11135 { 11136 } 11137 else 11138 { 11139 if (exp.e1.checkPostblit(sc, tb1)) 11140 return setError(); 11141 } 11142 11143 if (exp.e2.op == EXP.arrayLiteral && exp.e2.implicitConvTo(tb1.arrayOf())) 11144 { 11145 exp.e2 = exp.e2.implicitCastTo(sc, tb1.arrayOf()); 11146 exp.type = tb1.arrayOf(); 11147 goto L1elem; 11148 } 11149 if (exp.e1.implicitConvTo(tb2next) >= MATCH.convert) 11150 { 11151 exp.e1 = exp.e1.implicitCastTo(sc, tb2next); 11152 exp.type = tb2next.arrayOf(); 11153 L1elem: 11154 if (checkNewEscape(sc, exp.e1, false)) 11155 return setError(); 11156 result = exp.optimize(WANTvalue); 11157 trySetCatExpLowering(result); 11158 return; 11159 } 11160 } 11161 11162 Lpeer: 11163 if ((tb1.ty == Tsarray || tb1.ty == Tarray) && (tb2.ty == Tsarray || tb2.ty == Tarray) && (tb1next.mod || tb2next.mod) && (tb1next.mod != tb2next.mod)) 11164 { 11165 Type t1 = tb1next.mutableOf().constOf().arrayOf(); 11166 Type t2 = tb2next.mutableOf().constOf().arrayOf(); 11167 if (exp.e1.op == EXP.string_ && !(cast(StringExp)exp.e1).committed) 11168 exp.e1.type = t1; 11169 else 11170 exp.e1 = exp.e1.castTo(sc, t1); 11171 if (exp.e2.op == EXP.string_ && !(cast(StringExp)exp.e2).committed) 11172 exp.e2.type = t2; 11173 else 11174 exp.e2 = exp.e2.castTo(sc, t2); 11175 } 11176 11177 if (Expression ex = typeCombine(exp, sc)) 11178 { 11179 result = ex; 11180 trySetCatExpLowering(result); 11181 return; 11182 } 11183 exp.type = exp.type.toHeadMutable(); 11184 11185 Type tb = exp.type.toBasetype(); 11186 if (tb.ty == Tsarray) 11187 exp.type = tb.nextOf().arrayOf(); 11188 if (exp.type.ty == Tarray && tb1next && tb2next && tb1next.mod != tb2next.mod) 11189 { 11190 exp.type = exp.type.nextOf().toHeadMutable().arrayOf(); 11191 } 11192 if (Type tbn = tb.nextOf()) 11193 { 11194 if (exp.checkPostblit(sc, tbn)) 11195 return setError(); 11196 } 11197 Type t1 = exp.e1.type.toBasetype(); 11198 Type t2 = exp.e2.type.toBasetype(); 11199 if ((t1.ty == Tarray || t1.ty == Tsarray) && 11200 (t2.ty == Tarray || t2.ty == Tsarray)) 11201 { 11202 // Normalize to ArrayLiteralExp or StringExp as far as possible 11203 e = exp.optimize(WANTvalue); 11204 } 11205 else 11206 { 11207 //printf("(%s) ~ (%s)\n", e1.toChars(), e2.toChars()); 11208 result = exp.incompatibleTypes(); 11209 return; 11210 } 11211 11212 result = e; 11213 trySetCatExpLowering(result); 11214 } 11215 11216 override void visit(MulExp exp) 11217 { 11218 version (none) 11219 { 11220 printf("MulExp::semantic() %s\n", exp.toChars()); 11221 } 11222 if (exp.type) 11223 { 11224 result = exp; 11225 return; 11226 } 11227 11228 if (Expression ex = binSemanticProp(exp, sc)) 11229 { 11230 result = ex; 11231 return; 11232 } 11233 Expression e = exp.op_overload(sc); 11234 if (e) 11235 { 11236 result = e; 11237 return; 11238 } 11239 11240 if (Expression ex = typeCombine(exp, sc)) 11241 { 11242 result = ex; 11243 return; 11244 } 11245 11246 Type tb = exp.type.toBasetype(); 11247 if (tb.ty == Tarray || tb.ty == Tsarray) 11248 { 11249 if (!isArrayOpValid(exp)) 11250 { 11251 result = arrayOpInvalidError(exp); 11252 return; 11253 } 11254 result = exp; 11255 return; 11256 } 11257 11258 if (exp.checkArithmeticBin() || exp.checkSharedAccessBin(sc)) 11259 return setError(); 11260 11261 if (exp.type.isfloating()) 11262 { 11263 Type t1 = exp.e1.type; 11264 Type t2 = exp.e2.type; 11265 11266 if (t1.isreal()) 11267 { 11268 exp.type = t2; 11269 } 11270 else if (t2.isreal()) 11271 { 11272 exp.type = t1; 11273 } 11274 else if (t1.isimaginary()) 11275 { 11276 if (t2.isimaginary()) 11277 { 11278 switch (t1.toBasetype().ty) 11279 { 11280 case Timaginary32: 11281 exp.type = Type.tfloat32; 11282 break; 11283 11284 case Timaginary64: 11285 exp.type = Type.tfloat64; 11286 break; 11287 11288 case Timaginary80: 11289 exp.type = Type.tfloat80; 11290 break; 11291 11292 default: 11293 assert(0); 11294 } 11295 11296 // iy * iv = -yv 11297 exp.e1.type = exp.type; 11298 exp.e2.type = exp.type; 11299 e = new NegExp(exp.loc, exp); 11300 e = e.expressionSemantic(sc); 11301 result = e; 11302 return; 11303 } 11304 else 11305 exp.type = t2; // t2 is complex 11306 } 11307 else if (t2.isimaginary()) 11308 { 11309 exp.type = t1; // t1 is complex 11310 } 11311 } 11312 else if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype())) 11313 { 11314 result = exp.incompatibleTypes(); 11315 return; 11316 } 11317 result = exp; 11318 } 11319 11320 override void visit(DivExp exp) 11321 { 11322 if (exp.type) 11323 { 11324 result = exp; 11325 return; 11326 } 11327 11328 if (Expression ex = binSemanticProp(exp, sc)) 11329 { 11330 result = ex; 11331 return; 11332 } 11333 Expression e = exp.op_overload(sc); 11334 if (e) 11335 { 11336 result = e; 11337 return; 11338 } 11339 11340 if (Expression ex = typeCombine(exp, sc)) 11341 { 11342 result = ex; 11343 return; 11344 } 11345 11346 Type tb = exp.type.toBasetype(); 11347 if (tb.ty == Tarray || tb.ty == Tsarray) 11348 { 11349 if (!isArrayOpValid(exp)) 11350 { 11351 result = arrayOpInvalidError(exp); 11352 return; 11353 } 11354 result = exp; 11355 return; 11356 } 11357 11358 if (exp.checkArithmeticBin() || exp.checkSharedAccessBin(sc)) 11359 return setError(); 11360 11361 if (exp.type.isfloating()) 11362 { 11363 Type t1 = exp.e1.type; 11364 Type t2 = exp.e2.type; 11365 11366 if (t1.isreal()) 11367 { 11368 exp.type = t2; 11369 if (t2.isimaginary()) 11370 { 11371 // x/iv = i(-x/v) 11372 exp.e2.type = t1; 11373 e = new NegExp(exp.loc, exp); 11374 e = e.expressionSemantic(sc); 11375 result = e; 11376 return; 11377 } 11378 } 11379 else if (t2.isreal()) 11380 { 11381 exp.type = t1; 11382 } 11383 else if (t1.isimaginary()) 11384 { 11385 if (t2.isimaginary()) 11386 { 11387 switch (t1.toBasetype().ty) 11388 { 11389 case Timaginary32: 11390 exp.type = Type.tfloat32; 11391 break; 11392 11393 case Timaginary64: 11394 exp.type = Type.tfloat64; 11395 break; 11396 11397 case Timaginary80: 11398 exp.type = Type.tfloat80; 11399 break; 11400 11401 default: 11402 assert(0); 11403 } 11404 } 11405 else 11406 exp.type = t2; // t2 is complex 11407 } 11408 else if (t2.isimaginary()) 11409 { 11410 exp.type = t1; // t1 is complex 11411 } 11412 } 11413 else if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype())) 11414 { 11415 result = exp.incompatibleTypes(); 11416 return; 11417 } 11418 result = exp; 11419 } 11420 11421 override void visit(ModExp exp) 11422 { 11423 if (exp.type) 11424 { 11425 result = exp; 11426 return; 11427 } 11428 11429 if (Expression ex = binSemanticProp(exp, sc)) 11430 { 11431 result = ex; 11432 return; 11433 } 11434 Expression e = exp.op_overload(sc); 11435 if (e) 11436 { 11437 result = e; 11438 return; 11439 } 11440 11441 if (Expression ex = typeCombine(exp, sc)) 11442 { 11443 result = ex; 11444 return; 11445 } 11446 11447 Type tb = exp.type.toBasetype(); 11448 if (tb.ty == Tarray || tb.ty == Tsarray) 11449 { 11450 if (!isArrayOpValid(exp)) 11451 { 11452 result = arrayOpInvalidError(exp); 11453 return; 11454 } 11455 result = exp; 11456 return; 11457 } 11458 if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype())) 11459 { 11460 result = exp.incompatibleTypes(); 11461 return; 11462 } 11463 11464 if (exp.checkArithmeticBin() || exp.checkSharedAccessBin(sc)) 11465 return setError(); 11466 11467 if (exp.type.isfloating()) 11468 { 11469 exp.type = exp.e1.type; 11470 if (exp.e2.type.iscomplex()) 11471 { 11472 exp.error("cannot perform modulo complex arithmetic"); 11473 return setError(); 11474 } 11475 } 11476 result = exp; 11477 } 11478 11479 override void visit(PowExp exp) 11480 { 11481 if (exp.type) 11482 { 11483 result = exp; 11484 return; 11485 } 11486 11487 //printf("PowExp::semantic() %s\n", toChars()); 11488 if (Expression ex = binSemanticProp(exp, sc)) 11489 { 11490 result = ex; 11491 return; 11492 } 11493 Expression e = exp.op_overload(sc); 11494 if (e) 11495 { 11496 result = e; 11497 return; 11498 } 11499 11500 if (Expression ex = typeCombine(exp, sc)) 11501 { 11502 result = ex; 11503 return; 11504 } 11505 11506 Type tb = exp.type.toBasetype(); 11507 if (tb.ty == Tarray || tb.ty == Tsarray) 11508 { 11509 if (!isArrayOpValid(exp)) 11510 { 11511 result = arrayOpInvalidError(exp); 11512 return; 11513 } 11514 result = exp; 11515 return; 11516 } 11517 11518 if (exp.checkArithmeticBin() || exp.checkSharedAccessBin(sc)) 11519 return setError(); 11520 11521 if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype())) 11522 { 11523 result = exp.incompatibleTypes(); 11524 return; 11525 } 11526 11527 // First, attempt to fold the expression. 11528 e = exp.optimize(WANTvalue); 11529 if (e.op != EXP.pow) 11530 { 11531 e = e.expressionSemantic(sc); 11532 result = e; 11533 return; 11534 } 11535 11536 Module mmath = Module.loadStdMath(); 11537 if (!mmath) 11538 { 11539 e.error("`%s` requires `std.math` for `^^` operators", e.toChars()); 11540 return setError(); 11541 } 11542 e = new ScopeExp(exp.loc, mmath); 11543 11544 if (exp.e2.op == EXP.float64 && exp.e2.toReal() == CTFloat.half) 11545 { 11546 // Replace e1 ^^ 0.5 with .std.math.sqrt(e1) 11547 e = new CallExp(exp.loc, new DotIdExp(exp.loc, e, Id._sqrt), exp.e1); 11548 } 11549 else 11550 { 11551 // Replace e1 ^^ e2 with .std.math.pow(e1, e2) 11552 e = new CallExp(exp.loc, new DotIdExp(exp.loc, e, Id._pow), exp.e1, exp.e2); 11553 } 11554 e = e.expressionSemantic(sc); 11555 result = e; 11556 return; 11557 } 11558 11559 override void visit(ShlExp exp) 11560 { 11561 //printf("ShlExp::semantic(), type = %p\n", type); 11562 if (exp.type) 11563 { 11564 result = exp; 11565 return; 11566 } 11567 11568 if (Expression ex = binSemanticProp(exp, sc)) 11569 { 11570 result = ex; 11571 return; 11572 } 11573 Expression e = exp.op_overload(sc); 11574 if (e) 11575 { 11576 result = e; 11577 return; 11578 } 11579 11580 if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc)) 11581 return setError(); 11582 11583 if (!target.isVectorOpSupported(exp.e1.type.toBasetype(), exp.op, exp.e2.type.toBasetype())) 11584 { 11585 result = exp.incompatibleTypes(); 11586 return; 11587 } 11588 exp.e1 = integralPromotions(exp.e1, sc); 11589 if (exp.e2.type.toBasetype().ty != Tvector) 11590 exp.e2 = exp.e2.castTo(sc, Type.tshiftcnt); 11591 11592 exp.type = exp.e1.type; 11593 result = exp; 11594 } 11595 11596 override void visit(ShrExp exp) 11597 { 11598 if (exp.type) 11599 { 11600 result = exp; 11601 return; 11602 } 11603 11604 if (Expression ex = binSemanticProp(exp, sc)) 11605 { 11606 result = ex; 11607 return; 11608 } 11609 Expression e = exp.op_overload(sc); 11610 if (e) 11611 { 11612 result = e; 11613 return; 11614 } 11615 11616 if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc)) 11617 return setError(); 11618 11619 if (!target.isVectorOpSupported(exp.e1.type.toBasetype(), exp.op, exp.e2.type.toBasetype())) 11620 { 11621 result = exp.incompatibleTypes(); 11622 return; 11623 } 11624 exp.e1 = integralPromotions(exp.e1, sc); 11625 if (exp.e2.type.toBasetype().ty != Tvector) 11626 exp.e2 = exp.e2.castTo(sc, Type.tshiftcnt); 11627 11628 exp.type = exp.e1.type; 11629 result = exp; 11630 } 11631 11632 override void visit(UshrExp exp) 11633 { 11634 if (exp.type) 11635 { 11636 result = exp; 11637 return; 11638 } 11639 11640 if (Expression ex = binSemanticProp(exp, sc)) 11641 { 11642 result = ex; 11643 return; 11644 } 11645 Expression e = exp.op_overload(sc); 11646 if (e) 11647 { 11648 result = e; 11649 return; 11650 } 11651 11652 if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc)) 11653 return setError(); 11654 11655 if (!target.isVectorOpSupported(exp.e1.type.toBasetype(), exp.op, exp.e2.type.toBasetype())) 11656 { 11657 result = exp.incompatibleTypes(); 11658 return; 11659 } 11660 exp.e1 = integralPromotions(exp.e1, sc); 11661 if (exp.e2.type.toBasetype().ty != Tvector) 11662 exp.e2 = exp.e2.castTo(sc, Type.tshiftcnt); 11663 11664 exp.type = exp.e1.type; 11665 result = exp; 11666 } 11667 11668 override void visit(AndExp exp) 11669 { 11670 if (exp.type) 11671 { 11672 result = exp; 11673 return; 11674 } 11675 11676 if (Expression ex = binSemanticProp(exp, sc)) 11677 { 11678 result = ex; 11679 return; 11680 } 11681 Expression e = exp.op_overload(sc); 11682 if (e) 11683 { 11684 result = e; 11685 return; 11686 } 11687 11688 if (exp.e1.type.toBasetype().ty == Tbool && exp.e2.type.toBasetype().ty == Tbool) 11689 { 11690 exp.type = exp.e1.type; 11691 result = exp; 11692 return; 11693 } 11694 11695 if (Expression ex = typeCombine(exp, sc)) 11696 { 11697 result = ex; 11698 return; 11699 } 11700 11701 Type tb = exp.type.toBasetype(); 11702 if (tb.ty == Tarray || tb.ty == Tsarray) 11703 { 11704 if (!isArrayOpValid(exp)) 11705 { 11706 result = arrayOpInvalidError(exp); 11707 return; 11708 } 11709 result = exp; 11710 return; 11711 } 11712 if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype())) 11713 { 11714 result = exp.incompatibleTypes(); 11715 return; 11716 } 11717 if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc)) 11718 return setError(); 11719 11720 result = exp; 11721 } 11722 11723 override void visit(OrExp exp) 11724 { 11725 if (exp.type) 11726 { 11727 result = exp; 11728 return; 11729 } 11730 11731 if (Expression ex = binSemanticProp(exp, sc)) 11732 { 11733 result = ex; 11734 return; 11735 } 11736 Expression e = exp.op_overload(sc); 11737 if (e) 11738 { 11739 result = e; 11740 return; 11741 } 11742 11743 if (exp.e1.type.toBasetype().ty == Tbool && exp.e2.type.toBasetype().ty == Tbool) 11744 { 11745 exp.type = exp.e1.type; 11746 result = exp; 11747 return; 11748 } 11749 11750 if (Expression ex = typeCombine(exp, sc)) 11751 { 11752 result = ex; 11753 return; 11754 } 11755 11756 Type tb = exp.type.toBasetype(); 11757 if (tb.ty == Tarray || tb.ty == Tsarray) 11758 { 11759 if (!isArrayOpValid(exp)) 11760 { 11761 result = arrayOpInvalidError(exp); 11762 return; 11763 } 11764 result = exp; 11765 return; 11766 } 11767 if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype())) 11768 { 11769 result = exp.incompatibleTypes(); 11770 return; 11771 } 11772 if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc)) 11773 return setError(); 11774 11775 result = exp; 11776 } 11777 11778 override void visit(XorExp exp) 11779 { 11780 if (exp.type) 11781 { 11782 result = exp; 11783 return; 11784 } 11785 11786 if (Expression ex = binSemanticProp(exp, sc)) 11787 { 11788 result = ex; 11789 return; 11790 } 11791 Expression e = exp.op_overload(sc); 11792 if (e) 11793 { 11794 result = e; 11795 return; 11796 } 11797 11798 if (exp.e1.type.toBasetype().ty == Tbool && exp.e2.type.toBasetype().ty == Tbool) 11799 { 11800 exp.type = exp.e1.type; 11801 result = exp; 11802 return; 11803 } 11804 11805 if (Expression ex = typeCombine(exp, sc)) 11806 { 11807 result = ex; 11808 return; 11809 } 11810 11811 Type tb = exp.type.toBasetype(); 11812 if (tb.ty == Tarray || tb.ty == Tsarray) 11813 { 11814 if (!isArrayOpValid(exp)) 11815 { 11816 result = arrayOpInvalidError(exp); 11817 return; 11818 } 11819 result = exp; 11820 return; 11821 } 11822 if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype())) 11823 { 11824 result = exp.incompatibleTypes(); 11825 return; 11826 } 11827 if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc)) 11828 return setError(); 11829 11830 result = exp; 11831 } 11832 11833 override void visit(LogicalExp exp) 11834 { 11835 static if (LOGSEMANTIC) 11836 { 11837 printf("LogicalExp::semantic() %s\n", exp.toChars()); 11838 } 11839 11840 if (exp.type) 11841 { 11842 result = exp; 11843 return; 11844 } 11845 11846 exp.setNoderefOperands(); 11847 11848 Expression e1x = exp.e1.expressionSemantic(sc); 11849 11850 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684 11851 if (e1x.op == EXP.type) 11852 e1x = resolveAliasThis(sc, e1x); 11853 11854 e1x = resolveProperties(sc, e1x); 11855 e1x = e1x.toBoolean(sc); 11856 11857 if (sc.flags & SCOPE.condition) 11858 { 11859 /* If in static if, don't evaluate e2 if we don't have to. 11860 */ 11861 e1x = e1x.optimize(WANTvalue); 11862 if (e1x.toBool().hasValue(exp.op == EXP.orOr)) 11863 { 11864 if (sc.flags & SCOPE.Cfile) 11865 result = new IntegerExp(exp.op == EXP.orOr); 11866 else 11867 result = IntegerExp.createBool(exp.op == EXP.orOr); 11868 return; 11869 } 11870 } 11871 11872 CtorFlow ctorflow = sc.ctorflow.clone(); 11873 Expression e2x = exp.e2.expressionSemantic(sc); 11874 sc.merge(exp.loc, ctorflow); 11875 ctorflow.freeFieldinit(); 11876 11877 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684 11878 if (e2x.op == EXP.type) 11879 e2x = resolveAliasThis(sc, e2x); 11880 11881 e2x = resolveProperties(sc, e2x); 11882 11883 auto f1 = checkNonAssignmentArrayOp(e1x); 11884 auto f2 = checkNonAssignmentArrayOp(e2x); 11885 if (f1 || f2) 11886 return setError(); 11887 11888 // Unless the right operand is 'void', the expression is converted to 'bool'. 11889 if (e2x.type.ty != Tvoid) 11890 e2x = e2x.toBoolean(sc); 11891 11892 if (e2x.op == EXP.type || e2x.op == EXP.scope_) 11893 { 11894 exp.error("`%s` is not an expression", exp.e2.toChars()); 11895 return setError(); 11896 } 11897 if (e1x.op == EXP.error || e1x.type.ty == Tnoreturn) 11898 { 11899 result = e1x; 11900 return; 11901 } 11902 if (e2x.op == EXP.error) 11903 { 11904 result = e2x; 11905 return; 11906 } 11907 11908 // The result type is 'bool', unless the right operand has type 'void'. 11909 if (e2x.type.ty == Tvoid) 11910 exp.type = Type.tvoid; 11911 else 11912 exp.type = (sc && sc.flags & SCOPE.Cfile) ? Type.tint32 : Type.tbool; 11913 11914 exp.e1 = e1x; 11915 exp.e2 = e2x; 11916 result = exp; 11917 } 11918 11919 11920 override void visit(CmpExp exp) 11921 { 11922 static if (LOGSEMANTIC) 11923 { 11924 printf("CmpExp::semantic('%s')\n", exp.toChars()); 11925 } 11926 if (exp.type) 11927 { 11928 result = exp; 11929 return; 11930 } 11931 11932 exp.setNoderefOperands(); 11933 11934 if (Expression ex = binSemanticProp(exp, sc)) 11935 { 11936 result = ex; 11937 return; 11938 } 11939 Type t1 = exp.e1.type.toBasetype(); 11940 Type t2 = exp.e2.type.toBasetype(); 11941 if (t1.ty == Tclass && exp.e2.op == EXP.null_ || t2.ty == Tclass && exp.e1.op == EXP.null_) 11942 { 11943 exp.error("do not use `null` when comparing class types"); 11944 return setError(); 11945 } 11946 11947 11948 EXP cmpop = exp.op; 11949 if (auto e = exp.op_overload(sc, &cmpop)) 11950 { 11951 if (!e.type.isscalar() && e.type.equals(exp.e1.type)) 11952 { 11953 exp.error("recursive `opCmp` expansion"); 11954 return setError(); 11955 } 11956 if (e.op == EXP.call) 11957 { 11958 11959 if (t1.ty == Tclass && t2.ty == Tclass) 11960 { 11961 // Lower to object.__cmp(e1, e2) 11962 Expression cl = new IdentifierExp(exp.loc, Id.empty); 11963 cl = new DotIdExp(exp.loc, cl, Id.object); 11964 cl = new DotIdExp(exp.loc, cl, Id.__cmp); 11965 cl = cl.expressionSemantic(sc); 11966 11967 auto arguments = new Expressions(); 11968 // Check if op_overload found a better match by calling e2.opCmp(e1) 11969 // If the operands were swapped, then the result must be reversed 11970 // e1.opCmp(e2) == -e2.opCmp(e1) 11971 // cmpop takes care of this 11972 if (exp.op == cmpop) 11973 { 11974 arguments.push(exp.e1); 11975 arguments.push(exp.e2); 11976 } 11977 else 11978 { 11979 // Use better match found by op_overload 11980 arguments.push(exp.e2); 11981 arguments.push(exp.e1); 11982 } 11983 11984 cl = new CallExp(exp.loc, cl, arguments); 11985 cl = new CmpExp(cmpop, exp.loc, cl, new IntegerExp(0)); 11986 result = cl.expressionSemantic(sc); 11987 return; 11988 } 11989 11990 e = new CmpExp(cmpop, exp.loc, e, IntegerExp.literal!0); 11991 e = e.expressionSemantic(sc); 11992 } 11993 result = e; 11994 return; 11995 } 11996 11997 11998 if (Expression ex = typeCombine(exp, sc)) 11999 { 12000 result = ex; 12001 return; 12002 } 12003 12004 auto f1 = checkNonAssignmentArrayOp(exp.e1); 12005 auto f2 = checkNonAssignmentArrayOp(exp.e2); 12006 if (f1 || f2) 12007 return setError(); 12008 12009 exp.type = (sc && sc.flags & SCOPE.Cfile) ? Type.tint32 : Type.tbool; 12010 12011 // Special handling for array comparisons 12012 Expression arrayLowering = null; 12013 t1 = exp.e1.type.toBasetype(); 12014 t2 = exp.e2.type.toBasetype(); 12015 if ((t1.ty == Tarray || t1.ty == Tsarray || t1.ty == Tpointer) && (t2.ty == Tarray || t2.ty == Tsarray || t2.ty == Tpointer)) 12016 { 12017 Type t1next = t1.nextOf(); 12018 Type t2next = t2.nextOf(); 12019 if (t1next.implicitConvTo(t2next) < MATCH.constant && t2next.implicitConvTo(t1next) < MATCH.constant && (t1next.ty != Tvoid && t2next.ty != Tvoid)) 12020 { 12021 exp.error("array comparison type mismatch, `%s` vs `%s`", t1next.toChars(), t2next.toChars()); 12022 return setError(); 12023 } 12024 12025 if (sc.needsCodegen() && 12026 (t1.ty == Tarray || t1.ty == Tsarray) && 12027 (t2.ty == Tarray || t2.ty == Tsarray)) 12028 { 12029 if (!verifyHookExist(exp.loc, *sc, Id.__cmp, "comparing arrays")) 12030 return setError(); 12031 12032 // Lower to object.__cmp(e1, e2) 12033 Expression al = new IdentifierExp(exp.loc, Id.empty); 12034 al = new DotIdExp(exp.loc, al, Id.object); 12035 al = new DotIdExp(exp.loc, al, Id.__cmp); 12036 al = al.expressionSemantic(sc); 12037 12038 auto arguments = new Expressions(2); 12039 (*arguments)[0] = exp.e1; 12040 (*arguments)[1] = exp.e2; 12041 12042 al = new CallExp(exp.loc, al, arguments); 12043 al = new CmpExp(exp.op, exp.loc, al, IntegerExp.literal!0); 12044 12045 arrayLowering = al; 12046 } 12047 } 12048 else if (t1.ty == Tstruct || t2.ty == Tstruct || (t1.ty == Tclass && t2.ty == Tclass)) 12049 { 12050 if (t2.ty == Tstruct) 12051 exp.error("need member function `opCmp()` for %s `%s` to compare", t2.toDsymbol(sc).kind(), t2.toChars()); 12052 else 12053 exp.error("need member function `opCmp()` for %s `%s` to compare", t1.toDsymbol(sc).kind(), t1.toChars()); 12054 return setError(); 12055 } 12056 else if (t1.iscomplex() || t2.iscomplex()) 12057 { 12058 exp.error("compare not defined for complex operands"); 12059 return setError(); 12060 } 12061 else if (t1.ty == Taarray || t2.ty == Taarray) 12062 { 12063 exp.error("`%s` is not defined for associative arrays", EXPtoString(exp.op).ptr); 12064 return setError(); 12065 } 12066 else if (!target.isVectorOpSupported(t1, exp.op, t2)) 12067 { 12068 result = exp.incompatibleTypes(); 12069 return; 12070 } 12071 else 12072 { 12073 bool r1 = exp.e1.checkValue() || exp.e1.checkSharedAccess(sc); 12074 bool r2 = exp.e2.checkValue() || exp.e2.checkSharedAccess(sc); 12075 if (r1 || r2) 12076 return setError(); 12077 } 12078 12079 //printf("CmpExp: %s, type = %s\n", e.toChars(), e.type.toChars()); 12080 if (arrayLowering) 12081 { 12082 arrayLowering = arrayLowering.expressionSemantic(sc); 12083 result = arrayLowering; 12084 return; 12085 } 12086 12087 if (auto tv = t1.isTypeVector()) 12088 exp.type = tv.toBooleanVector(); 12089 12090 result = exp; 12091 return; 12092 } 12093 12094 override void visit(InExp exp) 12095 { 12096 if (exp.type) 12097 { 12098 result = exp; 12099 return; 12100 } 12101 12102 if (Expression ex = binSemanticProp(exp, sc)) 12103 { 12104 result = ex; 12105 return; 12106 } 12107 Expression e = exp.op_overload(sc); 12108 if (e) 12109 { 12110 result = e; 12111 return; 12112 } 12113 12114 Type t2b = exp.e2.type.toBasetype(); 12115 switch (t2b.ty) 12116 { 12117 case Taarray: 12118 { 12119 TypeAArray ta = cast(TypeAArray)t2b; 12120 12121 // Special handling for array keys 12122 if (!arrayTypeCompatibleWithoutCasting(exp.e1.type, ta.index)) 12123 { 12124 // Convert key to type of key 12125 exp.e1 = exp.e1.implicitCastTo(sc, ta.index); 12126 } 12127 12128 semanticTypeInfo(sc, ta.index); 12129 12130 // Return type is pointer to value 12131 exp.type = ta.nextOf().pointerTo(); 12132 break; 12133 } 12134 12135 case Terror: 12136 return setError(); 12137 12138 case Tarray, Tsarray: 12139 result = exp.incompatibleTypes(); 12140 exp.errorSupplemental("`in` is only allowed on associative arrays"); 12141 const(char)* slice = (t2b.ty == Tsarray) ? "[]" : ""; 12142 exp.errorSupplemental("perhaps use `std.algorithm.find(%s, %s%s)` instead", 12143 exp.e1.toChars(), exp.e2.toChars(), slice); 12144 return; 12145 12146 default: 12147 result = exp.incompatibleTypes(); 12148 return; 12149 } 12150 result = exp; 12151 } 12152 12153 override void visit(RemoveExp e) 12154 { 12155 if (Expression ex = binSemantic(e, sc)) 12156 { 12157 result = ex; 12158 return; 12159 } 12160 result = e; 12161 } 12162 12163 override void visit(EqualExp exp) 12164 { 12165 //printf("EqualExp::semantic('%s')\n", exp.toChars()); 12166 if (exp.type) 12167 { 12168 result = exp; 12169 return; 12170 } 12171 12172 exp.setNoderefOperands(); 12173 12174 if (auto e = binSemanticProp(exp, sc)) 12175 { 12176 result = e; 12177 return; 12178 } 12179 if (exp.e1.op == EXP.type || exp.e2.op == EXP.type) 12180 { 12181 /* https://issues.dlang.org/show_bug.cgi?id=12520 12182 * empty tuples are represented as types so special cases are added 12183 * so that they can be compared for equality with tuples of values. 12184 */ 12185 static auto extractTypeTupAndExpTup(Expression e) 12186 { 12187 static struct Result { bool ttEmpty; bool te; } 12188 auto tt = e.op == EXP.type ? e.isTypeExp().type.isTypeTuple() : null; 12189 return Result(tt && (!tt.arguments || !tt.arguments.length), e.isTupleExp() !is null); 12190 } 12191 auto tups1 = extractTypeTupAndExpTup(exp.e1); 12192 auto tups2 = extractTypeTupAndExpTup(exp.e2); 12193 // AliasSeq!() == AliasSeq!(<at least a value>) 12194 if (tups1.ttEmpty && tups2.te) 12195 { 12196 result = IntegerExp.createBool(exp.op != EXP.equal); 12197 return; 12198 } 12199 // AliasSeq!(<at least a value>) == AliasSeq!() 12200 else if (tups1.te && tups2.ttEmpty) 12201 { 12202 result = IntegerExp.createBool(exp.op != EXP.equal); 12203 return; 12204 } 12205 // AliasSeq!() == AliasSeq!() 12206 else if (tups1.ttEmpty && tups2.ttEmpty) 12207 { 12208 result = IntegerExp.createBool(exp.op == EXP.equal); 12209 return; 12210 } 12211 // otherwise, two types are really not comparable 12212 result = exp.incompatibleTypes(); 12213 return; 12214 } 12215 12216 { 12217 auto t1 = exp.e1.type; 12218 auto t2 = exp.e2.type; 12219 if (t1.ty == Tenum && t2.ty == Tenum && !t1.equivalent(t2)) 12220 exp.error("comparison between different enumeration types `%s` and `%s`; If this behavior is intended consider using `std.conv.asOriginalType`", 12221 t1.toChars(), t2.toChars()); 12222 } 12223 12224 /* Before checking for operator overloading, check to see if we're 12225 * comparing the addresses of two statics. If so, we can just see 12226 * if they are the same symbol. 12227 */ 12228 if (exp.e1.op == EXP.address && exp.e2.op == EXP.address) 12229 { 12230 AddrExp ae1 = cast(AddrExp)exp.e1; 12231 AddrExp ae2 = cast(AddrExp)exp.e2; 12232 if (ae1.e1.op == EXP.variable && ae2.e1.op == EXP.variable) 12233 { 12234 VarExp ve1 = cast(VarExp)ae1.e1; 12235 VarExp ve2 = cast(VarExp)ae2.e1; 12236 if (ve1.var == ve2.var) 12237 { 12238 // They are the same, result is 'true' for ==, 'false' for != 12239 result = IntegerExp.createBool(exp.op == EXP.equal); 12240 return; 12241 } 12242 } 12243 } 12244 12245 Type t1 = exp.e1.type.toBasetype(); 12246 Type t2 = exp.e2.type.toBasetype(); 12247 12248 // Indicates whether the comparison of the 2 specified array types 12249 // requires an object.__equals() lowering. 12250 static bool needsDirectEq(Type t1, Type t2, Scope* sc) 12251 { 12252 Type t1n = t1.nextOf().toBasetype(); 12253 Type t2n = t2.nextOf().toBasetype(); 12254 if ((t1n.ty.isSomeChar && t2n.ty.isSomeChar) || 12255 (t1n.ty == Tvoid || t2n.ty == Tvoid)) 12256 { 12257 return false; 12258 } 12259 if (t1n.constOf() != t2n.constOf()) 12260 return true; 12261 12262 Type t = t1n; 12263 while (t.toBasetype().nextOf()) 12264 t = t.nextOf().toBasetype(); 12265 if (auto ts = t.isTypeStruct()) 12266 { 12267 // semanticTypeInfo() makes sure hasIdentityEquals has been computed 12268 if (global.params.useTypeInfo && Type.dtypeinfo) 12269 semanticTypeInfo(sc, ts); 12270 12271 return ts.sym.hasIdentityEquals; // has custom opEquals 12272 } 12273 12274 return false; 12275 } 12276 12277 if (auto e = exp.op_overload(sc)) 12278 { 12279 result = e; 12280 return; 12281 } 12282 12283 12284 const isArrayComparison = (t1.ty == Tarray || t1.ty == Tsarray) && 12285 (t2.ty == Tarray || t2.ty == Tsarray); 12286 const needsArrayLowering = isArrayComparison && needsDirectEq(t1, t2, sc); 12287 12288 if (!needsArrayLowering) 12289 { 12290 // https://issues.dlang.org/show_bug.cgi?id=23783 12291 if (exp.e1.checkSharedAccess(sc) || exp.e2.checkSharedAccess(sc)) 12292 return setError(); 12293 if (auto e = typeCombine(exp, sc)) 12294 { 12295 result = e; 12296 return; 12297 } 12298 } 12299 12300 auto f1 = checkNonAssignmentArrayOp(exp.e1); 12301 auto f2 = checkNonAssignmentArrayOp(exp.e2); 12302 if (f1 || f2) 12303 return setError(); 12304 12305 exp.type = (sc && sc.flags & SCOPE.Cfile) ? Type.tint32 : Type.tbool; 12306 12307 if (!isArrayComparison) 12308 { 12309 if (exp.e1.type != exp.e2.type && exp.e1.type.isfloating() && exp.e2.type.isfloating()) 12310 { 12311 // Cast both to complex 12312 exp.e1 = exp.e1.castTo(sc, Type.tcomplex80); 12313 exp.e2 = exp.e2.castTo(sc, Type.tcomplex80); 12314 } 12315 } 12316 12317 // lower some array comparisons to object.__equals(e1, e2) 12318 if (needsArrayLowering || (t1.ty == Tarray && t2.ty == Tarray)) 12319 { 12320 //printf("Lowering to __equals %s %s\n", exp.e1.toChars(), exp.e2.toChars()); 12321 12322 // https://issues.dlang.org/show_bug.cgi?id=22390 12323 // Equality comparison between array of noreturns simply lowers to length equality comparison 12324 if (t1.nextOf.isTypeNoreturn() && t2.nextOf.isTypeNoreturn()) 12325 { 12326 Expression exp_l1 = new DotIdExp(exp.e1.loc, exp.e1, Id.length); 12327 Expression exp_l2 = new DotIdExp(exp.e2.loc, exp.e2, Id.length); 12328 auto e = new EqualExp(EXP.equal, exp.loc, exp_l1, exp_l2); 12329 result = e.expressionSemantic(sc); 12330 return; 12331 } 12332 12333 if (!verifyHookExist(exp.loc, *sc, Id.__equals, "equal checks on arrays")) 12334 return setError(); 12335 12336 Expression __equals = new IdentifierExp(exp.loc, Id.empty); 12337 Identifier id = Identifier.idPool("__equals"); 12338 __equals = new DotIdExp(exp.loc, __equals, Id.object); 12339 __equals = new DotIdExp(exp.loc, __equals, id); 12340 12341 /* https://issues.dlang.org/show_bug.cgi?id=23674 12342 * 12343 * Optimize before creating the call expression to the 12344 * druntime hook as the optimizer may output errors 12345 * that will get swallowed otherwise. 12346 */ 12347 exp.e1 = exp.e1.optimize(WANTvalue); 12348 exp.e2 = exp.e2.optimize(WANTvalue); 12349 12350 auto arguments = new Expressions(2); 12351 (*arguments)[0] = exp.e1; 12352 (*arguments)[1] = exp.e2; 12353 12354 __equals = new CallExp(exp.loc, __equals, arguments); 12355 if (exp.op == EXP.notEqual) 12356 { 12357 __equals = new NotExp(exp.loc, __equals); 12358 } 12359 __equals = __equals.trySemantic(sc); // for better error message 12360 if (!__equals) 12361 { 12362 exp.error("incompatible types for array comparison: `%s` and `%s`", 12363 exp.e1.type.toChars(), exp.e2.type.toChars()); 12364 __equals = ErrorExp.get(); 12365 } 12366 12367 result = __equals; 12368 return; 12369 } 12370 12371 if (exp.e1.type.toBasetype().ty == Taarray) 12372 semanticTypeInfo(sc, exp.e1.type.toBasetype()); 12373 12374 12375 if (!target.isVectorOpSupported(t1, exp.op, t2)) 12376 { 12377 result = exp.incompatibleTypes(); 12378 return; 12379 } 12380 12381 if (auto tv = t1.isTypeVector()) 12382 exp.type = tv.toBooleanVector(); 12383 12384 result = exp; 12385 } 12386 12387 override void visit(IdentityExp exp) 12388 { 12389 if (exp.type) 12390 { 12391 result = exp; 12392 return; 12393 } 12394 12395 exp.setNoderefOperands(); 12396 12397 if (auto e = binSemanticProp(exp, sc)) 12398 { 12399 result = e; 12400 return; 12401 } 12402 12403 if (auto e = typeCombine(exp, sc)) 12404 { 12405 result = e; 12406 return; 12407 } 12408 12409 auto f1 = checkNonAssignmentArrayOp(exp.e1); 12410 auto f2 = checkNonAssignmentArrayOp(exp.e2); 12411 if (f1 || f2) 12412 return setError(); 12413 12414 if (exp.e1.op == EXP.type || exp.e2.op == EXP.type) 12415 { 12416 result = exp.incompatibleTypes(); 12417 return; 12418 } 12419 12420 exp.type = Type.tbool; 12421 12422 if (exp.e1.type != exp.e2.type && exp.e1.type.isfloating() && exp.e2.type.isfloating()) 12423 { 12424 // Cast both to complex 12425 exp.e1 = exp.e1.castTo(sc, Type.tcomplex80); 12426 exp.e2 = exp.e2.castTo(sc, Type.tcomplex80); 12427 } 12428 12429 auto tb1 = exp.e1.type.toBasetype(); 12430 auto tb2 = exp.e2.type.toBasetype(); 12431 if (!target.isVectorOpSupported(tb1, exp.op, tb2)) 12432 { 12433 result = exp.incompatibleTypes(); 12434 return; 12435 } 12436 12437 if (exp.e1.op == EXP.call) 12438 exp.e1 = (cast(CallExp)exp.e1).addDtorHook(sc); 12439 if (exp.e2.op == EXP.call) 12440 exp.e2 = (cast(CallExp)exp.e2).addDtorHook(sc); 12441 12442 if (exp.e1.type.toBasetype().ty == Tsarray || 12443 exp.e2.type.toBasetype().ty == Tsarray) 12444 exp.deprecation("identity comparison of static arrays " 12445 ~ "implicitly coerces them to slices, " 12446 ~ "which are compared by reference"); 12447 12448 result = exp; 12449 } 12450 12451 override void visit(CondExp exp) 12452 { 12453 static if (LOGSEMANTIC) 12454 { 12455 printf("CondExp::semantic('%s')\n", exp.toChars()); 12456 } 12457 if (exp.type) 12458 { 12459 result = exp; 12460 return; 12461 } 12462 12463 if (auto die = exp.econd.isDotIdExp()) 12464 die.noderef = true; 12465 12466 Expression ec = exp.econd.expressionSemantic(sc); 12467 ec = resolveProperties(sc, ec); 12468 ec = ec.toBoolean(sc); 12469 12470 CtorFlow ctorflow_root = sc.ctorflow.clone(); 12471 Expression e1x = exp.e1.expressionSemantic(sc).arrayFuncConv(sc); 12472 e1x = resolveProperties(sc, e1x); 12473 12474 CtorFlow ctorflow1 = sc.ctorflow; 12475 sc.ctorflow = ctorflow_root; 12476 Expression e2x = exp.e2.expressionSemantic(sc).arrayFuncConv(sc); 12477 e2x = resolveProperties(sc, e2x); 12478 12479 sc.merge(exp.loc, ctorflow1); 12480 ctorflow1.freeFieldinit(); 12481 12482 if (ec.op == EXP.error) 12483 { 12484 result = ec; 12485 return; 12486 } 12487 if (ec.type == Type.terror) 12488 return setError(); 12489 exp.econd = ec; 12490 12491 if (e1x.op == EXP.error) 12492 { 12493 result = e1x; 12494 return; 12495 } 12496 if (e1x.type == Type.terror) 12497 return setError(); 12498 exp.e1 = e1x; 12499 12500 if (e2x.op == EXP.error) 12501 { 12502 result = e2x; 12503 return; 12504 } 12505 if (e2x.type == Type.terror) 12506 return setError(); 12507 exp.e2 = e2x; 12508 12509 auto f0 = checkNonAssignmentArrayOp(exp.econd); 12510 auto f1 = checkNonAssignmentArrayOp(exp.e1); 12511 auto f2 = checkNonAssignmentArrayOp(exp.e2); 12512 if (f0 || f1 || f2) 12513 return setError(); 12514 12515 Type t1 = exp.e1.type; 12516 Type t2 = exp.e2.type; 12517 12518 // https://issues.dlang.org/show_bug.cgi?id=23767 12519 // `cast(void*) 0` should be treated as `null` so the ternary expression 12520 // gets the pointer type of the other branch 12521 if (sc.flags & SCOPE.Cfile) 12522 { 12523 static void rewriteCNull(ref Expression e, ref Type t) 12524 { 12525 if (!t.isTypePointer()) 12526 return; 12527 if (auto ie = e.optimize(WANTvalue).isIntegerExp()) 12528 { 12529 if (ie.getInteger() == 0) 12530 { 12531 e = new NullExp(e.loc, Type.tnull); 12532 t = Type.tnull; 12533 } 12534 } 12535 } 12536 rewriteCNull(exp.e1, t1); 12537 rewriteCNull(exp.e2, t2); 12538 } 12539 12540 if (t1.ty == Tnoreturn) 12541 { 12542 exp.type = t2; 12543 exp.e1 = specialNoreturnCast(exp.e1, exp.type); 12544 } 12545 else if (t2.ty == Tnoreturn) 12546 { 12547 exp.type = t1; 12548 exp.e2 = specialNoreturnCast(exp.e2, exp.type); 12549 } 12550 // If either operand is void the result is void, we have to cast both 12551 // the expression to void so that we explicitly discard the expression 12552 // value if any 12553 // https://issues.dlang.org/show_bug.cgi?id=16598 12554 else if (t1.ty == Tvoid || t2.ty == Tvoid) 12555 { 12556 exp.type = Type.tvoid; 12557 exp.e1 = exp.e1.castTo(sc, exp.type); 12558 exp.e2 = exp.e2.castTo(sc, exp.type); 12559 } 12560 else if (t1 == t2) 12561 exp.type = t1; 12562 else 12563 { 12564 if (Expression ex = typeCombine(exp, sc)) 12565 { 12566 result = ex; 12567 return; 12568 } 12569 12570 switch (exp.e1.type.toBasetype().ty) 12571 { 12572 case Tcomplex32: 12573 case Tcomplex64: 12574 case Tcomplex80: 12575 exp.e2 = exp.e2.castTo(sc, exp.e1.type); 12576 break; 12577 default: 12578 break; 12579 } 12580 switch (exp.e2.type.toBasetype().ty) 12581 { 12582 case Tcomplex32: 12583 case Tcomplex64: 12584 case Tcomplex80: 12585 exp.e1 = exp.e1.castTo(sc, exp.e2.type); 12586 break; 12587 default: 12588 break; 12589 } 12590 if (exp.type.toBasetype().ty == Tarray) 12591 { 12592 exp.e1 = exp.e1.castTo(sc, exp.type); 12593 exp.e2 = exp.e2.castTo(sc, exp.type); 12594 } 12595 } 12596 exp.type = exp.type.merge2(); 12597 version (none) 12598 { 12599 printf("res: %s\n", exp.type.toChars()); 12600 printf("e1 : %s\n", exp.e1.type.toChars()); 12601 printf("e2 : %s\n", exp.e2.type.toChars()); 12602 } 12603 12604 /* https://issues.dlang.org/show_bug.cgi?id=14696 12605 * If either e1 or e2 contain temporaries which need dtor, 12606 * make them conditional. 12607 * Rewrite: 12608 * cond ? (__tmp1 = ..., __tmp1) : (__tmp2 = ..., __tmp2) 12609 * to: 12610 * (auto __cond = cond) ? (... __tmp1) : (... __tmp2) 12611 * and replace edtors of __tmp1 and __tmp2 with: 12612 * __tmp1.edtor --> __cond && __tmp1.dtor() 12613 * __tmp2.edtor --> __cond || __tmp2.dtor() 12614 */ 12615 exp.hookDtors(sc); 12616 12617 result = exp; 12618 } 12619 12620 override void visit(GenericExp exp) 12621 { 12622 static if (LOGSEMANTIC) 12623 { 12624 printf("GenericExp::semantic('%s')\n", exp.toChars()); 12625 } 12626 // C11 6.5.1.1 Generic Selection 12627 12628 auto ec = exp.cntlExp.expressionSemantic(sc).arrayFuncConv(sc); 12629 bool errors = ec.isErrorExp() !is null; 12630 auto tc = ec.type; 12631 12632 auto types = (*exp.types)[]; 12633 foreach (i, ref t; types) 12634 { 12635 if (!t) 12636 continue; // `default:` case 12637 t = t.typeSemantic(ec.loc, sc); 12638 if (t.isTypeError()) 12639 { 12640 errors = true; 12641 continue; 12642 } 12643 12644 /* C11 6.5.1-2 duplicate check 12645 */ 12646 /* C11 distinguishes int, long, and long long. But D doesn't, so depending on the 12647 * C target, a long may have the same type as `int` in the D type system. 12648 * So, skip checks when this may be the case. Later pick the first match 12649 */ 12650 if ( 12651 (t.ty == Tint32 || t.ty == Tuns32) && target.c.longsize == 4 || 12652 (t.ty == Tint64 || t.ty == Tuns64) && target.c.longsize == 8 || 12653 (t.ty == Tfloat64 || t.ty == Timaginary64 || t.ty == Tcomplex64) && target.c.long_doublesize == 8 12654 ) 12655 continue; 12656 12657 foreach (t2; types[0 .. i]) 12658 { 12659 if (t2 && t2.equals(t)) 12660 { 12661 error(ec.loc, "generic association type `%s` can only appear once", t.toChars()); 12662 errors = true; 12663 break; 12664 } 12665 } 12666 } 12667 12668 auto exps = (*exp.exps)[]; 12669 foreach (ref e; exps) 12670 { 12671 e = e.expressionSemantic(sc); 12672 if (e.isErrorExp()) 12673 errors = true; 12674 } 12675 12676 if (errors) 12677 return setError(); 12678 12679 enum size_t None = ~0; 12680 size_t imatch = None; 12681 size_t idefault = None; 12682 foreach (const i, t; types) 12683 { 12684 if (t) 12685 { 12686 /* if tc is compatible with t, it's a match 12687 * C11 6.2.7 defines a compatible type as being the same type, including qualifiers 12688 */ 12689 if (tc.equals(t)) 12690 { 12691 assert(imatch == None); 12692 imatch = i; 12693 break; // pick first match 12694 } 12695 } 12696 else 12697 idefault = i; // multiple defaults are not allowed, and are caught by cparse 12698 } 12699 12700 if (imatch == None) 12701 imatch = idefault; 12702 if (imatch == None) 12703 { 12704 error(exp.loc, "no compatible generic association type for controlling expression type `%s`", tc.toChars()); 12705 return setError(); 12706 } 12707 12708 result = exps[imatch]; 12709 } 12710 12711 override void visit(FileInitExp e) 12712 { 12713 //printf("FileInitExp::semantic()\n"); 12714 e.type = Type.tstring; 12715 result = e; 12716 } 12717 12718 override void visit(LineInitExp e) 12719 { 12720 e.type = Type.tint32; 12721 result = e; 12722 } 12723 12724 override void visit(ModuleInitExp e) 12725 { 12726 //printf("ModuleInitExp::semantic()\n"); 12727 e.type = Type.tstring; 12728 result = e; 12729 } 12730 12731 override void visit(FuncInitExp e) 12732 { 12733 //printf("FuncInitExp::semantic()\n"); 12734 e.type = Type.tstring; 12735 if (sc.func) 12736 { 12737 result = e.resolveLoc(Loc.initial, sc); 12738 return; 12739 } 12740 result = e; 12741 } 12742 12743 override void visit(PrettyFuncInitExp e) 12744 { 12745 //printf("PrettyFuncInitExp::semantic()\n"); 12746 e.type = Type.tstring; 12747 if (sc.func) 12748 { 12749 result = e.resolveLoc(Loc.initial, sc); 12750 return; 12751 } 12752 12753 result = e; 12754 } 12755 } 12756 12757 /********************************** 12758 * Try to run semantic routines. 12759 * If they fail, return NULL. 12760 */ 12761 Expression trySemantic(Expression exp, Scope* sc) 12762 { 12763 //printf("+trySemantic(%s)\n", exp.toChars()); 12764 uint errors = global.startGagging(); 12765 Expression e = expressionSemantic(exp, sc); 12766 if (global.endGagging(errors)) 12767 { 12768 e = null; 12769 } 12770 //printf("-trySemantic(%s)\n", exp.toChars()); 12771 return e; 12772 } 12773 12774 /************************** 12775 * Helper function for easy error propagation. 12776 * If error occurs, returns ErrorExp. Otherwise returns NULL. 12777 */ 12778 Expression unaSemantic(UnaExp e, Scope* sc) 12779 { 12780 static if (LOGSEMANTIC) 12781 { 12782 printf("UnaExp::semantic('%s')\n", e.toChars()); 12783 } 12784 Expression e1x = e.e1.expressionSemantic(sc); 12785 if (e1x.op == EXP.error) 12786 return e1x; 12787 e.e1 = e1x; 12788 return null; 12789 } 12790 12791 /************************** 12792 * Helper function for easy error propagation. 12793 * If error occurs, returns ErrorExp. Otherwise returns NULL. 12794 */ 12795 Expression binSemantic(BinExp e, Scope* sc) 12796 { 12797 static if (LOGSEMANTIC) 12798 { 12799 printf("BinExp::semantic('%s')\n", e.toChars()); 12800 } 12801 Expression e1x = e.e1.expressionSemantic(sc); 12802 Expression e2x = e.e2.expressionSemantic(sc); 12803 12804 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684 12805 if (e1x.op == EXP.type) 12806 e1x = resolveAliasThis(sc, e1x); 12807 if (e2x.op == EXP.type) 12808 e2x = resolveAliasThis(sc, e2x); 12809 12810 if (e1x.op == EXP.error) 12811 return e1x; 12812 if (e2x.op == EXP.error) 12813 return e2x; 12814 e.e1 = e1x; 12815 e.e2 = e2x; 12816 return null; 12817 } 12818 12819 Expression binSemanticProp(BinExp e, Scope* sc) 12820 { 12821 if (Expression ex = binSemantic(e, sc)) 12822 return ex; 12823 Expression e1x = resolveProperties(sc, e.e1); 12824 Expression e2x = resolveProperties(sc, e.e2); 12825 if (e1x.op == EXP.error) 12826 return e1x; 12827 if (e2x.op == EXP.error) 12828 return e2x; 12829 e.e1 = e1x; 12830 e.e2 = e2x; 12831 return null; 12832 } 12833 12834 // entrypoint for semantic ExpressionSemanticVisitor 12835 extern (C++) Expression expressionSemantic(Expression e, Scope* sc) 12836 { 12837 scope v = new ExpressionSemanticVisitor(sc); 12838 e.accept(v); 12839 return v.result; 12840 } 12841 12842 private Expression dotIdSemanticPropX(DotIdExp exp, Scope* sc) 12843 { 12844 //printf("DotIdExp::semanticX(this = %p, '%s')\n", this, toChars()); 12845 if (Expression ex = unaSemantic(exp, sc)) 12846 return ex; 12847 12848 if (!(sc.flags & SCOPE.Cfile) && exp.ident == Id._mangleof) 12849 { 12850 // symbol.mangleof 12851 12852 // return mangleof as an Expression 12853 static Expression dotMangleof(const ref Loc loc, Scope* sc, Dsymbol ds) 12854 { 12855 assert(ds); 12856 if (auto f = ds.isFuncDeclaration()) 12857 { 12858 if (f.checkForwardRef(loc)) 12859 return ErrorExp.get(); 12860 12861 if (f.purityInprocess || f.safetyInprocess || f.nothrowInprocess || f.nogcInprocess) 12862 { 12863 f.error(loc, "cannot retrieve its `.mangleof` while inferring attributes"); 12864 return ErrorExp.get(); 12865 } 12866 } 12867 OutBuffer buf; 12868 mangleToBuffer(ds, &buf); 12869 Expression e = new StringExp(loc, buf.extractSlice()); 12870 return e.expressionSemantic(sc); 12871 } 12872 12873 Dsymbol ds; 12874 switch (exp.e1.op) 12875 { 12876 case EXP.scope_: return dotMangleof(exp.loc, sc, exp.e1.isScopeExp().sds); 12877 case EXP.variable: return dotMangleof(exp.loc, sc, exp.e1.isVarExp().var); 12878 case EXP.dotVariable: return dotMangleof(exp.loc, sc, exp.e1.isDotVarExp().var); 12879 case EXP.overloadSet: return dotMangleof(exp.loc, sc, exp.e1.isOverExp().vars); 12880 case EXP.template_: 12881 { 12882 TemplateExp te = exp.e1.isTemplateExp(); 12883 return dotMangleof(exp.loc, sc, ds = te.fd ? te.fd.isDsymbol() : te.td); 12884 } 12885 12886 default: 12887 break; 12888 } 12889 } 12890 12891 if (exp.e1.isVarExp() && exp.e1.type.toBasetype().isTypeSArray() && exp.ident == Id.length) 12892 { 12893 // bypass checkPurity 12894 return exp.e1.type.dotExp(sc, exp.e1, exp.ident, cast(DotExpFlag) (exp.noderef * DotExpFlag.noDeref)); 12895 } 12896 12897 if (!exp.e1.isDotExp()) 12898 { 12899 exp.e1 = resolvePropertiesX(sc, exp.e1); 12900 } 12901 12902 if (auto te = exp.e1.isTupleExp()) 12903 { 12904 if (exp.ident == Id.offsetof) 12905 { 12906 /* 'distribute' the .offsetof to each of the tuple elements. 12907 */ 12908 auto exps = new Expressions(te.exps.length); 12909 foreach (i, e; (*te.exps)[]) 12910 { 12911 (*exps)[i] = new DotIdExp(e.loc, e, Id.offsetof); 12912 } 12913 // Don't evaluate te.e0 in runtime 12914 Expression e = new TupleExp(exp.loc, null, exps); 12915 e = e.expressionSemantic(sc); 12916 return e; 12917 } 12918 if (exp.ident == Id.length) 12919 { 12920 // Don't evaluate te.e0 in runtime 12921 return new IntegerExp(exp.loc, te.exps.length, Type.tsize_t); 12922 } 12923 } 12924 12925 // https://issues.dlang.org/show_bug.cgi?id=14416 12926 // Template has no built-in properties except for 'stringof'. 12927 if ((exp.e1.isDotTemplateExp() || exp.e1.isTemplateExp()) && exp.ident != Id.stringof) 12928 { 12929 exp.error("template `%s` does not have property `%s`", exp.e1.toChars(), exp.ident.toChars()); 12930 return ErrorExp.get(); 12931 } 12932 if (!exp.e1.type) 12933 { 12934 exp.error("expression `%s` does not have property `%s`", exp.e1.toChars(), exp.ident.toChars()); 12935 return ErrorExp.get(); 12936 } 12937 12938 return exp; 12939 } 12940 12941 /****************************** 12942 * Resolve properties, i.e. `e1.ident`, without seeing UFCS. 12943 * Params: 12944 * exp = expression to resolve 12945 * sc = context 12946 * gag = do not emit error messages, just return `null` 12947 * Returns: 12948 * resolved expression, null if error 12949 */ 12950 Expression dotIdSemanticProp(DotIdExp exp, Scope* sc, bool gag) 12951 { 12952 //printf("DotIdExp::semanticY(this = %p, '%s')\n", exp, exp.toChars()); 12953 12954 //{ static int z; fflush(stdout); if (++z == 10) *(char*)0=0; } 12955 12956 const cfile = (sc.flags & SCOPE.Cfile) != 0; 12957 12958 /* Special case: rewrite this.id and super.id 12959 * to be classtype.id and baseclasstype.id 12960 * if we have no this pointer. 12961 */ 12962 if ((exp.e1.isThisExp() || exp.e1.isSuperExp()) && !hasThis(sc)) 12963 { 12964 if (AggregateDeclaration ad = sc.getStructClassScope()) 12965 { 12966 if (exp.e1.isThisExp()) 12967 { 12968 exp.e1 = new TypeExp(exp.e1.loc, ad.type); 12969 } 12970 else 12971 { 12972 if (auto cd = ad.isClassDeclaration()) 12973 { 12974 if (cd.baseClass) 12975 exp.e1 = new TypeExp(exp.e1.loc, cd.baseClass.type); 12976 } 12977 } 12978 } 12979 } 12980 12981 { 12982 Expression e = dotIdSemanticPropX(exp, sc); 12983 if (e != exp) 12984 return e; 12985 } 12986 12987 Expression eleft; 12988 Expression eright; 12989 if (auto de = exp.e1.isDotExp()) 12990 { 12991 eleft = de.e1; 12992 eright = de.e2; 12993 } 12994 else 12995 { 12996 eleft = null; 12997 eright = exp.e1; 12998 } 12999 13000 Type t1b = exp.e1.type.toBasetype(); 13001 13002 if (auto ie = eright.isScopeExp()) // also used for template alias's 13003 { 13004 auto flags = SearchLocalsOnly; 13005 /* Disable access to another module's private imports. 13006 * The check for 'is sds our current module' is because 13007 * the current module should have access to its own imports. 13008 */ 13009 if (ie.sds.isModule() && ie.sds != sc._module) 13010 flags |= IgnorePrivateImports; 13011 if (sc.flags & SCOPE.ignoresymbolvisibility) 13012 flags |= IgnoreSymbolVisibility; 13013 Dsymbol s = ie.sds.search(exp.loc, exp.ident, flags); 13014 /* Check for visibility before resolving aliases because public 13015 * aliases to private symbols are public. 13016 */ 13017 if (s && !(sc.flags & SCOPE.ignoresymbolvisibility) && !symbolIsVisible(sc._module, s)) 13018 { 13019 s = null; 13020 } 13021 if (s) 13022 { 13023 auto p = s.isPackage(); 13024 if (p && checkAccess(sc, p)) 13025 { 13026 s = null; 13027 } 13028 } 13029 if (s) 13030 { 13031 // if 's' is a tuple variable, the tuple is returned. 13032 s = s.toAlias(); 13033 13034 exp.checkDeprecated(sc, s); 13035 exp.checkDisabled(sc, s); 13036 13037 if (auto em = s.isEnumMember()) 13038 { 13039 return em.getVarExp(exp.loc, sc); 13040 } 13041 if (auto v = s.isVarDeclaration()) 13042 { 13043 //printf("DotIdExp:: Identifier '%s' is a variable, type '%s'\n", toChars(), v.type.toChars()); 13044 if (!v.type || 13045 !v.type.deco && v.inuse) 13046 { 13047 if (v.inuse) 13048 exp.error("circular reference to %s `%s`", v.kind(), v.toPrettyChars()); 13049 else 13050 exp.error("forward reference to %s `%s`", v.kind(), v.toPrettyChars()); 13051 return ErrorExp.get(); 13052 } 13053 if (v.type.isTypeError()) 13054 return ErrorExp.get(); 13055 13056 if ((v.storage_class & STC.manifest) && v._init && !exp.wantsym) 13057 { 13058 /* Normally, the replacement of a symbol with its initializer is supposed to be in semantic2(). 13059 * Introduced by https://github.com/dlang/dmd/pull/5588 which should probably 13060 * be reverted. `wantsym` is the hack to work around the problem. 13061 */ 13062 if (v.inuse) 13063 { 13064 error(exp.loc, "circular initialization of %s `%s`", v.kind(), v.toPrettyChars()); 13065 return ErrorExp.get(); 13066 } 13067 auto e = v.expandInitializer(exp.loc); 13068 v.inuse++; 13069 e = e.expressionSemantic(sc); 13070 v.inuse--; 13071 return e; 13072 } 13073 13074 Expression e; 13075 if (v.needThis()) 13076 { 13077 if (!eleft) 13078 eleft = new ThisExp(exp.loc); 13079 e = new DotVarExp(exp.loc, eleft, v); 13080 e = e.expressionSemantic(sc); 13081 } 13082 else 13083 { 13084 e = new VarExp(exp.loc, v); 13085 if (eleft) 13086 { 13087 e = new CommaExp(exp.loc, eleft, e); 13088 e.type = v.type; 13089 } 13090 } 13091 e = e.deref(); 13092 return e.expressionSemantic(sc); 13093 } 13094 13095 if (auto f = s.isFuncDeclaration()) 13096 { 13097 //printf("it's a function\n"); 13098 if (!f.functionSemantic()) 13099 return ErrorExp.get(); 13100 Expression e; 13101 if (f.needThis()) 13102 { 13103 if (!eleft) 13104 eleft = new ThisExp(exp.loc); 13105 e = new DotVarExp(exp.loc, eleft, f, true); 13106 e = e.expressionSemantic(sc); 13107 } 13108 else 13109 { 13110 e = new VarExp(exp.loc, f, true); 13111 if (eleft) 13112 { 13113 e = new CommaExp(exp.loc, eleft, e); 13114 e.type = f.type; 13115 } 13116 } 13117 return e; 13118 } 13119 if (auto td = s.isTemplateDeclaration()) 13120 { 13121 Expression e; 13122 if (eleft) 13123 e = new DotTemplateExp(exp.loc, eleft, td); 13124 else 13125 e = new TemplateExp(exp.loc, td); 13126 e = e.expressionSemantic(sc); 13127 return e; 13128 } 13129 if (OverDeclaration od = s.isOverDeclaration()) 13130 { 13131 Expression e = new VarExp(exp.loc, od, true); 13132 if (eleft) 13133 { 13134 e = new CommaExp(exp.loc, eleft, e); 13135 e.type = Type.tvoid; // ambiguous type? 13136 } 13137 return e.expressionSemantic(sc); 13138 } 13139 if (auto o = s.isOverloadSet()) 13140 { 13141 //printf("'%s' is an overload set\n", o.toChars()); 13142 return new OverExp(exp.loc, o); 13143 } 13144 13145 if (auto t = s.getType()) 13146 { 13147 return (new TypeExp(exp.loc, t)).expressionSemantic(sc); 13148 } 13149 13150 if (auto tup = s.isTupleDeclaration()) 13151 { 13152 if (eleft) 13153 { 13154 Expression e = new DotVarExp(exp.loc, eleft, tup); 13155 e = e.expressionSemantic(sc); 13156 return e; 13157 } 13158 Expression e = new TupleExp(exp.loc, tup); 13159 e = e.expressionSemantic(sc); 13160 return e; 13161 } 13162 13163 if (auto sds = s.isScopeDsymbol()) 13164 { 13165 //printf("it's a ScopeDsymbol %s\n", ident.toChars()); 13166 Expression e = new ScopeExp(exp.loc, sds); 13167 e = e.expressionSemantic(sc); 13168 if (eleft) 13169 e = new DotExp(exp.loc, eleft, e); 13170 return e; 13171 } 13172 13173 if (auto imp = s.isImport()) 13174 { 13175 Expression se = new ScopeExp(exp.loc, imp.pkg); 13176 return se.expressionSemantic(sc); 13177 } 13178 13179 if (auto attr = s.isAttribDeclaration()) 13180 { 13181 if (auto sm = ie.sds.search(exp.loc, exp.ident, flags)) 13182 { 13183 auto es = new DsymbolExp(exp.loc, sm); 13184 return es; 13185 } 13186 } 13187 13188 // BUG: handle other cases like in IdentifierExp::semantic() 13189 debug 13190 { 13191 printf("s = %p '%s', kind = '%s'\n", s, s.toChars(), s.kind()); 13192 } 13193 assert(0); 13194 } 13195 else if (exp.ident == Id.stringof) 13196 { 13197 Expression e = new StringExp(exp.loc, ie.toString()); 13198 e = e.expressionSemantic(sc); 13199 return e; 13200 } 13201 if (ie.sds.isPackage() || ie.sds.isImport() || ie.sds.isModule()) 13202 { 13203 gag = false; 13204 } 13205 if (gag) 13206 return null; 13207 s = ie.sds.search_correct(exp.ident); 13208 if (s && symbolIsVisible(sc, s)) 13209 { 13210 if (s.isPackage()) 13211 exp.error("undefined identifier `%s` in %s `%s`, perhaps add `static import %s;`", exp.ident.toChars(), ie.sds.kind(), ie.sds.toPrettyChars(), s.toPrettyChars()); 13212 else 13213 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()); 13214 } 13215 else 13216 exp.error("undefined identifier `%s` in %s `%s`", exp.ident.toChars(), ie.sds.kind(), ie.sds.toPrettyChars()); 13217 return ErrorExp.get(); 13218 } 13219 else if (t1b.ty == Tpointer && exp.e1.type.ty != Tenum && 13220 !( 13221 exp.ident == Id.__sizeof || 13222 exp.ident == Id.__xalignof || 13223 !cfile && 13224 (exp.ident == Id._mangleof || 13225 exp.ident == Id.offsetof || 13226 exp.ident == Id._init || 13227 exp.ident == Id.stringof) 13228 )) 13229 { 13230 Type t1bn = t1b.nextOf(); 13231 if (gag) 13232 { 13233 if (AggregateDeclaration ad = isAggregate(t1bn)) 13234 { 13235 if (!ad.members) // https://issues.dlang.org/show_bug.cgi?id=11312 13236 return null; 13237 } 13238 } 13239 13240 /* Rewrite: 13241 * p.ident 13242 * as: 13243 * (*p).ident 13244 */ 13245 if (gag && t1bn.ty == Tvoid) 13246 return null; 13247 Expression e = new PtrExp(exp.loc, exp.e1); 13248 e = e.expressionSemantic(sc); 13249 const newFlag = cast(DotExpFlag) (gag * DotExpFlag.gag | exp.noderef * DotExpFlag.noDeref); 13250 return e.type.dotExp(sc, e, exp.ident, newFlag); 13251 } 13252 else if (exp.ident == Id.__xalignof && 13253 exp.e1.isVarExp() && 13254 exp.e1.isVarExp().var.isVarDeclaration() && 13255 !exp.e1.isVarExp().var.isVarDeclaration().alignment.isUnknown()) 13256 { 13257 // For `x.alignof` get the alignment of the variable, not the alignment of its type 13258 const explicitAlignment = exp.e1.isVarExp().var.isVarDeclaration().alignment; 13259 const naturalAlignment = exp.e1.type.alignsize(); 13260 const actualAlignment = explicitAlignment.isDefault() ? naturalAlignment : explicitAlignment.get(); 13261 Expression e = new IntegerExp(exp.loc, actualAlignment, Type.tsize_t); 13262 return e; 13263 } 13264 else if ((exp.ident == Id.max || exp.ident == Id.min) && 13265 exp.e1.isVarExp() && 13266 exp.e1.isVarExp().var.isBitFieldDeclaration()) 13267 { 13268 // For `x.max` and `x.min` get the max/min of the bitfield, not the max/min of its type 13269 auto bf = exp.e1.isVarExp().var.isBitFieldDeclaration(); 13270 return new IntegerExp(exp.loc, bf.getMinMax(exp.ident), bf.type); 13271 } 13272 else if ((exp.ident == Id.max || exp.ident == Id.min) && 13273 exp.e1.isDotVarExp() && 13274 exp.e1.isDotVarExp().var.isBitFieldDeclaration()) 13275 { 13276 // For `x.max` and `x.min` get the max/min of the bitfield, not the max/min of its type 13277 auto bf = exp.e1.isDotVarExp().var.isBitFieldDeclaration(); 13278 return new IntegerExp(exp.loc, bf.getMinMax(exp.ident), bf.type); 13279 } 13280 else 13281 { 13282 if (exp.e1.isTypeExp() || exp.e1.isTemplateExp()) 13283 gag = false; 13284 13285 const flag = cast(DotExpFlag) (exp.noderef * DotExpFlag.noDeref | gag * DotExpFlag.gag); 13286 13287 Expression e = exp.e1.type.dotExp(sc, exp.e1, exp.ident, flag); 13288 if (e) 13289 { 13290 e = e.expressionSemantic(sc); 13291 } 13292 return e; 13293 } 13294 } 13295 13296 /** 13297 * Resolve `e1.ident!tiargs` without seeing UFCS. 13298 * Params: 13299 * exp = the `DotTemplateInstanceExp` to resolve 13300 * sc = the semantic scope 13301 * gag = stop "not a property" error and return `null`. 13302 * Returns: 13303 * `null` if error or not found, or the resolved expression. 13304 */ 13305 Expression dotTemplateSemanticProp(DotTemplateInstanceExp exp, Scope* sc, bool gag) 13306 { 13307 static if (LOGSEMANTIC) 13308 { 13309 printf("DotTemplateInstanceExpY::semantic('%s')\n", exp.toChars()); 13310 } 13311 13312 static Expression errorExp() 13313 { 13314 return ErrorExp.get(); 13315 } 13316 13317 Expression e1 = exp.e1; 13318 13319 if (exp.ti.tempdecl && exp.ti.tempdecl.parent && exp.ti.tempdecl.parent.isTemplateMixin()) 13320 { 13321 // if 'ti.tempdecl' happens to be found in a mixin template don't lose that info 13322 // and do the symbol search in that context (Issue: 19476) 13323 auto tm = cast(TemplateMixin)exp.ti.tempdecl.parent; 13324 e1 = new DotExp(exp.e1.loc, exp.e1, new ScopeExp(tm.loc, tm)); 13325 } 13326 13327 auto die = new DotIdExp(exp.loc, e1, exp.ti.name); 13328 13329 Expression e = die.dotIdSemanticPropX(sc); 13330 if (e == die) 13331 { 13332 exp.e1 = die.e1; // take back 13333 Type t1b = exp.e1.type.toBasetype(); 13334 if (t1b.ty == Tarray || t1b.ty == Tsarray || t1b.ty == Taarray || t1b.ty == Tnull || (t1b.isTypeBasic() && t1b.ty != Tvoid)) 13335 { 13336 /* No built-in type has templatized properties, so do shortcut. 13337 * It is necessary in: 1024.max!"a < b" 13338 */ 13339 if (gag) 13340 return null; 13341 } 13342 e = die.dotIdSemanticProp(sc, gag); 13343 if (gag) 13344 { 13345 if (!e || 13346 isDotOpDispatch(e)) 13347 { 13348 /* opDispatch!tiargs would be a function template that needs IFTI, 13349 * so it's not a template 13350 */ 13351 return null; 13352 } 13353 } 13354 } 13355 assert(e); 13356 13357 if (e.op == EXP.error) 13358 return e; 13359 if (DotVarExp dve = e.isDotVarExp()) 13360 { 13361 if (FuncDeclaration fd = dve.var.isFuncDeclaration()) 13362 { 13363 if (TemplateDeclaration td = fd.findTemplateDeclRoot()) 13364 { 13365 e = new DotTemplateExp(dve.loc, dve.e1, td); 13366 e = e.expressionSemantic(sc); 13367 } 13368 } 13369 else if (OverDeclaration od = dve.var.isOverDeclaration()) 13370 { 13371 exp.e1 = dve.e1; // pull semantic() result 13372 13373 if (!exp.findTempDecl(sc)) 13374 goto Lerr; 13375 if (exp.ti.needsTypeInference(sc)) 13376 return exp; 13377 exp.ti.dsymbolSemantic(sc); 13378 if (!exp.ti.inst || exp.ti.errors) // if template failed to expand 13379 return errorExp(); 13380 13381 if (Declaration v = exp.ti.toAlias().isDeclaration()) 13382 { 13383 if (v.type && !v.type.deco) 13384 v.type = v.type.typeSemantic(v.loc, sc); 13385 return new DotVarExp(exp.loc, exp.e1, v) 13386 .expressionSemantic(sc); 13387 } 13388 return new DotExp(exp.loc, exp.e1, new ScopeExp(exp.loc, exp.ti)) 13389 .expressionSemantic(sc); 13390 } 13391 } 13392 else if (e.op == EXP.variable) 13393 { 13394 VarExp ve = cast(VarExp)e; 13395 if (FuncDeclaration fd = ve.var.isFuncDeclaration()) 13396 { 13397 if (TemplateDeclaration td = fd.findTemplateDeclRoot()) 13398 { 13399 e = new TemplateExp(ve.loc, td) 13400 .expressionSemantic(sc); 13401 } 13402 } 13403 else if (OverDeclaration od = ve.var.isOverDeclaration()) 13404 { 13405 exp.ti.tempdecl = od; 13406 return new ScopeExp(exp.loc, exp.ti) 13407 .expressionSemantic(sc); 13408 } 13409 } 13410 13411 if (DotTemplateExp dte = e.isDotTemplateExp()) 13412 { 13413 exp.e1 = dte.e1; // pull semantic() result 13414 13415 exp.ti.tempdecl = dte.td; 13416 if (!exp.ti.semanticTiargs(sc)) 13417 return errorExp(); 13418 if (exp.ti.needsTypeInference(sc)) 13419 return exp; 13420 exp.ti.dsymbolSemantic(sc); 13421 if (!exp.ti.inst || exp.ti.errors) // if template failed to expand 13422 return errorExp(); 13423 13424 if (Declaration v = exp.ti.toAlias().isDeclaration()) 13425 { 13426 return new DotVarExp(exp.loc, exp.e1, v) 13427 .expressionSemantic(sc); 13428 } 13429 return new DotExp(exp.loc, exp.e1, new ScopeExp(exp.loc, exp.ti)) 13430 .expressionSemantic(sc); 13431 } 13432 else if (e.op == EXP.template_) 13433 { 13434 exp.ti.tempdecl = (cast(TemplateExp)e).td; 13435 return new ScopeExp(exp.loc, exp.ti) 13436 .expressionSemantic(sc); 13437 } 13438 else if (DotExp de = e.isDotExp()) 13439 { 13440 if (de.e2.op == EXP.overloadSet) 13441 { 13442 if (!exp.findTempDecl(sc) || !exp.ti.semanticTiargs(sc)) 13443 { 13444 return errorExp(); 13445 } 13446 if (exp.ti.needsTypeInference(sc)) 13447 return exp; 13448 exp.ti.dsymbolSemantic(sc); 13449 if (!exp.ti.inst || exp.ti.errors) // if template failed to expand 13450 return errorExp(); 13451 13452 if (Declaration v = exp.ti.toAlias().isDeclaration()) 13453 { 13454 if (v.type && !v.type.deco) 13455 v.type = v.type.typeSemantic(v.loc, sc); 13456 return new DotVarExp(exp.loc, exp.e1, v) 13457 .expressionSemantic(sc); 13458 } 13459 return new DotExp(exp.loc, exp.e1, new ScopeExp(exp.loc, exp.ti)) 13460 .expressionSemantic(sc); 13461 } 13462 } 13463 else if (OverExp oe = e.isOverExp()) 13464 { 13465 exp.ti.tempdecl = oe.vars; 13466 return new ScopeExp(exp.loc, exp.ti) 13467 .expressionSemantic(sc); 13468 } 13469 13470 Lerr: 13471 exp.error("`%s` isn't a template", e.toChars()); 13472 return errorExp(); 13473 } 13474 13475 /*************************************** 13476 * If expression is shared, check that we can access it. 13477 * Give error message if not. 13478 * 13479 * Params: 13480 * e = expression to check 13481 * sc = context 13482 * returnRef = Whether this expression is for a `return` statement 13483 * off a `ref` function, in which case a single level 13484 * of dereference is allowed (e.g. `shared(int)*`). 13485 * Returns: 13486 * true on error 13487 */ 13488 bool checkSharedAccess(Expression e, Scope* sc, bool returnRef = false) 13489 { 13490 if (global.params.noSharedAccess != FeatureState.enabled || 13491 !sc || 13492 sc.intypeof || 13493 sc.flags & SCOPE.ctfe) 13494 { 13495 return false; 13496 } 13497 13498 //printf("checkSharedAccess() `%s` returnRef: %d\n", e.toChars(), returnRef); 13499 13500 bool check(Expression e, bool allowRef) 13501 { 13502 bool sharedError(Expression e) 13503 { 13504 // https://dlang.org/phobos/core_atomic.html 13505 e.error("direct access to shared `%s` is not allowed, see `core.atomic`", e.toChars()); 13506 return true; 13507 } 13508 13509 // Error by default 13510 bool visit(Expression e) 13511 { 13512 // https://issues.dlang.org/show_bug.cgi?id=23639 13513 // Should be able to cast(shared) 13514 if (!e.isCastExp() && e.type.isShared()) 13515 return sharedError(e); 13516 return false; 13517 } 13518 13519 bool visitNew(NewExp e) 13520 { 13521 if (e.thisexp) 13522 check(e.thisexp, false); 13523 return false; 13524 } 13525 13526 bool visitVar(VarExp e) 13527 { 13528 // https://issues.dlang.org/show_bug.cgi?id=20908 13529 // direct access to init symbols is ok as they 13530 // cannot be modified. 13531 if (e.var.isSymbolDeclaration()) 13532 return false; 13533 13534 // https://issues.dlang.org/show_bug.cgi?id=22626 13535 // Synchronized functions don't need to use core.atomic 13536 // when accessing `this`. 13537 if (sc.func && sc.func.isSynchronized()) 13538 { 13539 if (e.var.isThisDeclaration()) 13540 return false; 13541 else 13542 return sharedError(e); 13543 } 13544 else if (!allowRef && e.var.type.isShared()) 13545 return sharedError(e); 13546 13547 return false; 13548 } 13549 13550 bool visitAddr(AddrExp e) 13551 { 13552 return check(e.e1, true); 13553 } 13554 13555 bool visitPtr(PtrExp e) 13556 { 13557 if (!allowRef && e.type.isShared()) 13558 return sharedError(e); 13559 13560 if (e.e1.type.isShared()) 13561 return sharedError(e); 13562 13563 return check(e.e1, false); 13564 } 13565 13566 bool visitDotVar(DotVarExp e) 13567 { 13568 //printf("dotvarexp = %s\n", e.toChars()); 13569 if (e.type.isShared()) 13570 { 13571 if (e.e1.isThisExp()) 13572 { 13573 // https://issues.dlang.org/show_bug.cgi?id=22626 13574 if (sc.func && sc.func.isSynchronized()) 13575 return false; 13576 13577 // https://issues.dlang.org/show_bug.cgi?id=23790 13578 if (e.e1.type.isTypeStruct()) 13579 return false; 13580 } 13581 13582 auto fd = e.var.isFuncDeclaration(); 13583 const sharedFunc = fd && fd.type.isShared; 13584 if (!allowRef && !sharedFunc) 13585 return sharedError(e); 13586 13587 // Allow using `DotVarExp` within value types 13588 if (e.e1.type.isTypeSArray() || e.e1.type.isTypeStruct()) 13589 return check(e.e1, allowRef); 13590 13591 // If we end up with a single `VarExp`, it might be a `ref` param 13592 // `shared ref T` param == `shared(T)*`. 13593 if (auto ve = e.e1.isVarExp()) 13594 { 13595 return check(e.e1, allowRef && (ve.var.storage_class & STC.ref_)); 13596 } 13597 13598 return sharedError(e); 13599 } 13600 13601 return check(e.e1, false); 13602 } 13603 13604 bool visitIndex(IndexExp e) 13605 { 13606 if (!allowRef && e.type.isShared()) 13607 return sharedError(e); 13608 13609 if (e.e1.type.isShared()) 13610 return sharedError(e); 13611 13612 return check(e.e1, false); 13613 } 13614 13615 bool visitComma(CommaExp e) 13616 { 13617 // Cannot be `return ref` since we can't use the return, 13618 // but it's better to show that error than an unrelated `shared` one 13619 return check(e.e2, true); 13620 } 13621 13622 switch (e.op) 13623 { 13624 default: return visit(e); 13625 13626 // Those have no indirections / can be ignored 13627 case EXP.call: 13628 case EXP.error: 13629 case EXP.complex80: 13630 case EXP.int64: 13631 case EXP.null_: return false; 13632 13633 case EXP.variable: return visitVar(e.isVarExp()); 13634 case EXP.new_: return visitNew(e.isNewExp()); 13635 case EXP.address: return visitAddr(e.isAddrExp()); 13636 case EXP.star: return visitPtr(e.isPtrExp()); 13637 case EXP.dotVariable: return visitDotVar(e.isDotVarExp()); 13638 case EXP.index: return visitIndex(e.isIndexExp()); 13639 } 13640 } 13641 13642 return check(e, returnRef); 13643 } 13644 13645 13646 13647 /**************************************************** 13648 * Determine if `exp`, which gets its address taken, can do so safely. 13649 * Params: 13650 * sc = context 13651 * exp = expression having its address taken 13652 * v = the variable getting its address taken 13653 * Returns: 13654 * `true` if ok, `false` for error 13655 */ 13656 bool checkAddressVar(Scope* sc, Expression exp, VarDeclaration v) 13657 { 13658 //printf("checkAddressVar(exp: %s, v: %s)\n", exp.toChars(), v.toChars()); 13659 if (v is null) 13660 return true; 13661 13662 if (!v.canTakeAddressOf()) 13663 { 13664 exp.error("cannot take address of `%s`", exp.toChars()); 13665 return false; 13666 } 13667 if (sc.func && !sc.intypeof && !v.isDataseg()) 13668 { 13669 if (global.params.useDIP1000 != FeatureState.enabled && 13670 !(v.storage_class & STC.temp) && 13671 sc.setUnsafe(false, exp.loc, "cannot take address of local `%s` in `@safe` function `%s`", v, sc.func)) 13672 { 13673 return false; 13674 } 13675 } 13676 return true; 13677 } 13678 13679 /************************************** 13680 * This check ensures that the object in `exp` can have its address taken, or 13681 * issue a diagnostic error. 13682 * Params: 13683 * e = expression to check 13684 * sc = context 13685 * Returns: 13686 * true if the expression is addressable 13687 */ 13688 bool checkAddressable(Expression e, Scope* sc) 13689 { 13690 Expression ex = e; 13691 while (true) 13692 { 13693 switch (ex.op) 13694 { 13695 case EXP.dotVariable: 13696 // https://issues.dlang.org/show_bug.cgi?id=22749 13697 // Error about taking address of any bit-field, regardless of 13698 // whether SCOPE.Cfile is set. 13699 if (auto bf = ex.isDotVarExp().var.isBitFieldDeclaration()) 13700 { 13701 e.error("cannot take address of bit-field `%s`", bf.toChars()); 13702 return false; 13703 } 13704 goto case EXP.cast_; 13705 13706 case EXP.index: 13707 ex = ex.isBinExp().e1; 13708 continue; 13709 13710 case EXP.address: 13711 case EXP.array: 13712 case EXP.cast_: 13713 ex = ex.isUnaExp().e1; 13714 continue; 13715 13716 case EXP.variable: 13717 if (sc.flags & SCOPE.Cfile) 13718 { 13719 // C11 6.5.3.2: A variable that has its address taken cannot be 13720 // stored in a register. 13721 // C11 6.3.2.1: An array that has its address computed with `[]` 13722 // or cast to an lvalue pointer cannot be stored in a register. 13723 if (ex.isVarExp().var.storage_class & STC.register) 13724 { 13725 if (e.isIndexExp()) 13726 e.error("cannot index through register variable `%s`", ex.toChars()); 13727 else 13728 e.error("cannot take address of register variable `%s`", ex.toChars()); 13729 return false; 13730 } 13731 } 13732 break; 13733 13734 default: 13735 break; 13736 } 13737 break; 13738 } 13739 return true; 13740 } 13741 13742 13743 /******************************* 13744 * Checks the attributes of a function. 13745 * Purity (`pure`), safety (`@safe`), no GC allocations(`@nogc`) 13746 * and usage of `deprecated` and `@disabled`-ed symbols are checked. 13747 * 13748 * Params: 13749 * exp = expression to check attributes for 13750 * sc = scope of the function 13751 * f = function to be checked 13752 * Returns: `true` if error occur. 13753 */ 13754 private bool checkFunctionAttributes(Expression exp, Scope* sc, FuncDeclaration f) 13755 { 13756 with(exp) 13757 { 13758 bool error = checkDisabled(sc, f); 13759 error |= checkDeprecated(sc, f); 13760 error |= checkPurity(sc, f); 13761 error |= checkSafety(sc, f); 13762 error |= checkNogc(sc, f); 13763 return error; 13764 } 13765 } 13766 13767 /******************************* 13768 * Helper function for `getRightThis()`. 13769 * Gets `this` of the next outer aggregate. 13770 * Params: 13771 * loc = location to use for error messages 13772 * sc = context 13773 * s = the parent symbol of the existing `this` 13774 * ad = struct or class we need the correct `this` for 13775 * e1 = existing `this` 13776 * t = type of the existing `this` 13777 * var = the specific member of ad we're accessing 13778 * flag = if true, return `null` instead of throwing an error 13779 * Returns: 13780 * Expression representing the `this` for the var 13781 */ 13782 Expression getThisSkipNestedFuncs(const ref Loc loc, Scope* sc, Dsymbol s, AggregateDeclaration ad, Expression e1, Type t, Dsymbol var, bool flag = false) 13783 { 13784 int n = 0; 13785 while (s && s.isFuncDeclaration()) 13786 { 13787 FuncDeclaration f = s.isFuncDeclaration(); 13788 if (f.vthis) 13789 { 13790 n++; 13791 e1 = new VarExp(loc, f.vthis); 13792 if (f.hasDualContext()) 13793 { 13794 // (*__this)[i] 13795 if (n > 1) 13796 e1 = e1.expressionSemantic(sc); 13797 e1 = new PtrExp(loc, e1); 13798 uint i = f.followInstantiationContext(ad); 13799 e1 = new IndexExp(loc, e1, new IntegerExp(i)); 13800 s = f.toParentP(ad); 13801 continue; 13802 } 13803 } 13804 else 13805 { 13806 if (flag) 13807 return null; 13808 e1.error("need `this` of type `%s` to access member `%s` from static function `%s`", ad.toChars(), var.toChars(), f.toChars()); 13809 e1 = ErrorExp.get(); 13810 return e1; 13811 } 13812 s = s.toParent2(); 13813 } 13814 if (n > 1 || e1.op == EXP.index) 13815 e1 = e1.expressionSemantic(sc); 13816 if (s && e1.type.equivalent(Type.tvoidptr)) 13817 { 13818 if (auto sad = s.isAggregateDeclaration()) 13819 { 13820 Type ta = sad.handleType(); 13821 if (ta.ty == Tstruct) 13822 ta = ta.pointerTo(); 13823 e1.type = ta; 13824 } 13825 } 13826 e1.type = e1.type.addMod(t.mod); 13827 return e1; 13828 } 13829 13830 /******************************* 13831 * Make a dual-context container for use as a `this` argument. 13832 * Params: 13833 * loc = location to use for error messages 13834 * sc = current scope 13835 * fd = target function that will take the `this` argument 13836 * Returns: 13837 * Temporary closure variable. 13838 * Note: 13839 * The function `fd` is added to the nested references of the 13840 * newly created variable such that a closure is made for the variable when 13841 * the address of `fd` is taken. 13842 */ 13843 VarDeclaration makeThis2Argument(const ref Loc loc, Scope* sc, FuncDeclaration fd) 13844 { 13845 Type tthis2 = Type.tvoidptr.sarrayOf(2); 13846 VarDeclaration vthis2 = new VarDeclaration(loc, tthis2, Identifier.generateId("__this"), null); 13847 vthis2.storage_class |= STC.temp; 13848 vthis2.dsymbolSemantic(sc); 13849 vthis2.parent = sc.parent; 13850 // make it a closure var 13851 assert(sc.func); 13852 sc.func.closureVars.push(vthis2); 13853 // add `fd` to the nested refs 13854 vthis2.nestedrefs.push(fd); 13855 return vthis2; 13856 } 13857 13858 /******************************* 13859 * Make sure that the runtime hook `id` exists. 13860 * Params: 13861 * loc = location to use for error messages 13862 * sc = current scope 13863 * id = the hook identifier 13864 * description = what the hook does 13865 * module_ = what module the hook is located in 13866 * Returns: 13867 * a `bool` indicating if the hook is present. 13868 */ 13869 bool verifyHookExist(const ref Loc loc, ref Scope sc, Identifier id, string description, Identifier module_ = Id.object) 13870 { 13871 auto rootSymbol = sc.search(loc, Id.empty, null); 13872 if (auto moduleSymbol = rootSymbol.search(loc, module_)) 13873 if (moduleSymbol.search(loc, id)) 13874 return true; 13875 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); 13876 return false; 13877 } 13878 13879 /*************************************** 13880 * Fit elements[] to the corresponding types of the `sd`'s fields. 13881 * 13882 * Params: 13883 * sd = the struct declaration 13884 * loc = location to use for error messages 13885 * sc = context 13886 * elements = explicit arguments used to construct object 13887 * stype = the constructed object type. 13888 * Returns: 13889 * false if any errors occur, 13890 * otherwise true and elements[] are rewritten for the output. 13891 */ 13892 private bool fit(StructDeclaration sd, const ref Loc loc, Scope* sc, Expressions* elements, Type stype) 13893 { 13894 if (!elements) 13895 return true; 13896 13897 const nfields = sd.nonHiddenFields(); 13898 size_t offset = 0; 13899 for (size_t i = 0; i < elements.length; i++) 13900 { 13901 Expression e = (*elements)[i]; 13902 if (!e) 13903 continue; 13904 13905 e = resolveProperties(sc, e); 13906 if (i >= nfields) 13907 { 13908 if (i < sd.fields.length && e.op == EXP.null_) 13909 { 13910 // CTFE sometimes creates null as hidden pointer; we'll allow this. 13911 continue; 13912 } 13913 .error(loc, "more initializers than fields (%llu) of `%s`", cast(ulong)nfields, sd.toChars()); 13914 return false; 13915 } 13916 VarDeclaration v = sd.fields[i]; 13917 if (v.offset < offset) 13918 { 13919 .error(loc, "overlapping initialization for `%s`", v.toChars()); 13920 if (!sd.isUnionDeclaration()) 13921 { 13922 enum errorMsg = "`struct` initializers that contain anonymous unions" ~ 13923 " must initialize only the first member of a `union`. All subsequent" ~ 13924 " non-overlapping fields are default initialized"; 13925 .errorSupplemental(loc, errorMsg); 13926 } 13927 return false; 13928 } 13929 const vsize = v.type.size(); 13930 if (vsize == SIZE_INVALID) 13931 return false; 13932 offset = cast(uint)(v.offset + vsize); 13933 13934 Type t = v.type; 13935 if (stype) 13936 t = t.addMod(stype.mod); 13937 Type origType = t; 13938 Type tb = t.toBasetype(); 13939 13940 const hasPointers = tb.hasPointers(); 13941 if (hasPointers) 13942 { 13943 if ((!stype.alignment.isDefault() && stype.alignment.get() < target.ptrsize || 13944 (v.offset & (target.ptrsize - 1))) && 13945 (sc.setUnsafe(false, loc, 13946 "field `%s.%s` cannot assign to misaligned pointers in `@safe` code", sd, v))) 13947 { 13948 return false; 13949 } 13950 } 13951 13952 /* Look for case of initializing a static array with a too-short 13953 * string literal, such as: 13954 * char[5] foo = "abc"; 13955 * Allow this by doing an explicit cast, which will lengthen the string 13956 * literal. 13957 */ 13958 if (e.op == EXP.string_ && tb.ty == Tsarray) 13959 { 13960 StringExp se = cast(StringExp)e; 13961 Type typeb = se.type.toBasetype(); 13962 TY tynto = tb.nextOf().ty; 13963 if (!se.committed && 13964 (typeb.ty == Tarray || typeb.ty == Tsarray) && tynto.isSomeChar && 13965 se.numberOfCodeUnits(tynto) < (cast(TypeSArray)tb).dim.toInteger()) 13966 { 13967 e = se.castTo(sc, t); 13968 goto L1; 13969 } 13970 } 13971 13972 while (!e.implicitConvTo(t) && tb.ty == Tsarray) 13973 { 13974 /* Static array initialization, as in: 13975 * T[3][5] = e; 13976 */ 13977 t = tb.nextOf(); 13978 tb = t.toBasetype(); 13979 } 13980 if (!e.implicitConvTo(t)) 13981 t = origType; // restore type for better diagnostic 13982 13983 e = e.implicitCastTo(sc, t); 13984 L1: 13985 if (e.op == EXP.error) 13986 return false; 13987 13988 (*elements)[i] = doCopyOrMove(sc, e); 13989 } 13990 return true; 13991 } 13992 13993 13994 /** 13995 * Returns `em` as a VariableExp 13996 * Params: 13997 * em = the EnumMember to wrap 13998 * loc = location of use of em 13999 * sc = scope of use of em 14000 * Returns: 14001 * VarExp referenceing `em` or ErrorExp if `em` if disabled/deprecated 14002 */ 14003 Expression getVarExp(EnumMember em, const ref Loc loc, Scope* sc) 14004 { 14005 dsymbolSemantic(em, sc); 14006 if (em.errors) 14007 return ErrorExp.get(); 14008 em.checkDisabled(loc, sc); 14009 14010 if (em.depdecl && !em.depdecl._scope) 14011 em.depdecl._scope = sc; 14012 em.checkDeprecated(loc, sc); 14013 14014 if (em.errors) 14015 return ErrorExp.get(); 14016 Expression e = new VarExp(loc, em); 14017 e = e.expressionSemantic(sc); 14018 if (!(sc.flags & SCOPE.Cfile) && em.isCsymbol()) 14019 { 14020 /* C11 types them as int. But if in D file, 14021 * type qualified names as the enum 14022 */ 14023 e.type = em.parent.isEnumDeclaration().type; 14024 assert(e.type); 14025 } 14026 return e; 14027 } 14028 14029 14030 /***************************** 14031 * Try to treat `exp` as a boolean, 14032 * Params: 14033 * exp = the expression 14034 * sc = scope to evalute `exp` in 14035 * Returns: 14036 * Modified expression on success, ErrorExp on error 14037 */ 14038 Expression toBoolean(Expression exp, Scope* sc) 14039 { 14040 switch(exp.op) 14041 { 14042 case EXP.delete_: 14043 exp.error("`delete` does not give a boolean result"); 14044 return ErrorExp.get(); 14045 14046 case EXP.comma: 14047 auto ce = exp.isCommaExp(); 14048 auto ex2 = ce.e2.toBoolean(sc); 14049 if (ex2.op == EXP.error) 14050 return ex2; 14051 ce.e2 = ex2; 14052 ce.type = ce.e2.type; 14053 return ce; 14054 14055 case EXP.assign: 14056 case EXP.construct: 14057 case EXP.blit: 14058 case EXP.loweredAssignExp: 14059 if (sc.flags & SCOPE.Cfile) 14060 return exp; 14061 // Things like: 14062 // if (a = b) ... 14063 // are usually mistakes. 14064 exp.error("assignment cannot be used as a condition, perhaps `==` was meant?"); 14065 return ErrorExp.get(); 14066 14067 //LogicalExp 14068 case EXP.andAnd: 14069 case EXP.orOr: 14070 auto le = exp.isLogicalExp(); 14071 auto ex2 = le.e2.toBoolean(sc); 14072 if (ex2.op == EXP.error) 14073 return ex2; 14074 le.e2 = ex2; 14075 return le; 14076 14077 case EXP.question: 14078 auto ce = exp.isCondExp(); 14079 auto ex1 = ce.e1.toBoolean(sc); 14080 auto ex2 = ce.e2.toBoolean(sc); 14081 if (ex1.op == EXP.error) 14082 return ex1; 14083 if (ex2.op == EXP.error) 14084 return ex2; 14085 ce.e1 = ex1; 14086 ce.e2 = ex2; 14087 return ce; 14088 14089 14090 default: 14091 // Default is 'yes' - do nothing 14092 Expression e = arrayFuncConv(exp, sc); 14093 Type t = e.type; 14094 Type tb = t.toBasetype(); 14095 Type att = null; 14096 14097 while (1) 14098 { 14099 // Structs can be converted to bool using opCast(bool)() 14100 if (auto ts = tb.isTypeStruct()) 14101 { 14102 AggregateDeclaration ad = ts.sym; 14103 /* Don't really need to check for opCast first, but by doing so we 14104 * get better error messages if it isn't there. 14105 */ 14106 if (Dsymbol fd = search_function(ad, Id._cast)) 14107 { 14108 e = new CastExp(exp.loc, e, Type.tbool); 14109 e = e.expressionSemantic(sc); 14110 return e; 14111 } 14112 14113 // Forward to aliasthis. 14114 if (ad.aliasthis && !isRecursiveAliasThis(att, tb)) 14115 { 14116 e = resolveAliasThis(sc, e); 14117 t = e.type; 14118 tb = e.type.toBasetype(); 14119 continue; 14120 } 14121 } 14122 break; 14123 } 14124 14125 if (!t.isBoolean()) 14126 { 14127 if (tb != Type.terror) 14128 exp.error("expression `%s` of type `%s` does not have a boolean value", 14129 exp.toChars(), t.toChars()); 14130 return ErrorExp.get(); 14131 } 14132 return e; 14133 } 14134 }