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.errorsink; 45 import dmd.escape; 46 import dmd.expression; 47 import dmd.file_manager; 48 import dmd.func; 49 import dmd.globals; 50 import dmd.hdrgen; 51 import dmd.id; 52 import dmd.identifier; 53 import dmd.imphint; 54 import dmd.importc; 55 import dmd.init; 56 import dmd.initsem; 57 import dmd.inline; 58 import dmd.intrange; 59 import dmd.location; 60 import dmd.mtype; 61 import dmd.mustuse; 62 import dmd.nspace; 63 import dmd.objc; 64 import dmd.opover; 65 import dmd.optimize; 66 import dmd.parse; 67 import dmd.printast; 68 import dmd.postordervisitor; 69 import dmd.root.array; 70 import dmd.root.ctfloat; 71 import dmd.root.filename; 72 import dmd.common.outbuffer; 73 import dmd.rootobject; 74 import dmd.root.string; 75 import dmd.root.utf; 76 import dmd.semantic2; 77 import dmd.semantic3; 78 import dmd.sideeffect; 79 import dmd.safe; 80 import dmd.target; 81 import dmd.tokens; 82 import dmd.traits; 83 import dmd.typesem; 84 import dmd.typinf; 85 import dmd.utils; 86 import dmd.visitor; 87 88 enum LOGSEMANTIC = false; 89 90 /******************************************************** 91 * Perform semantic analysis and CTFE on expressions to produce 92 * a string. 93 * Params: 94 * buf = append generated string to buffer 95 * sc = context 96 * exps = array of Expressions 97 * Returns: 98 * true on error 99 */ 100 bool expressionsToString(ref OutBuffer buf, Scope* sc, Expressions* exps) 101 { 102 if (!exps) 103 return false; 104 105 foreach (ex; *exps) 106 { 107 if (!ex) 108 continue; 109 auto sc2 = sc.startCTFE(); 110 sc2.tinst = null; 111 sc2.minst = null; // prevents emission of any instantiated templates to object file 112 auto e2 = ex.expressionSemantic(sc2); 113 auto e3 = resolveProperties(sc2, e2); 114 sc2.endCTFE(); 115 116 // allowed to contain types as well as expressions 117 auto e4 = ctfeInterpretForPragmaMsg(e3); 118 if (!e4 || e4.op == EXP.error) 119 return true; 120 121 // expand tuple 122 if (auto te = e4.isTupleExp()) 123 { 124 if (expressionsToString(buf, sc, te.exps)) 125 return true; 126 continue; 127 } 128 // char literals exp `.toStringExp` return `null` but we cant override it 129 // because in most contexts we don't want the conversion to succeed. 130 IntegerExp ie = e4.isIntegerExp(); 131 const ty = (ie && ie.type) ? ie.type.ty : Terror; 132 if (ty.isSomeChar) 133 { 134 auto tsa = new TypeSArray(ie.type, IntegerExp.literal!1); 135 e4 = new ArrayLiteralExp(ex.loc, tsa, ie); 136 } 137 138 if (StringExp se = e4.toStringExp()) 139 buf.writestring(se.toUTF8(sc).peekString()); 140 else 141 buf.writestring(e4.toString()); 142 } 143 return false; 144 } 145 146 /***************************************** 147 * Determine if `this` is available by walking up the enclosing 148 * scopes until a function is found. 149 * 150 * Params: 151 * sc = where to start looking for the enclosing function 152 * Returns: 153 * Found function if it satisfies `isThis()`, otherwise `null` 154 */ 155 FuncDeclaration hasThis(Scope* sc) 156 { 157 //printf("hasThis()\n"); 158 Dsymbol p = sc.parent; 159 while (p && p.isTemplateMixin()) 160 p = p.parent; 161 FuncDeclaration fdthis = p ? p.isFuncDeclaration() : null; 162 //printf("fdthis = %p, '%s'\n", fdthis, fdthis ? fdthis.toChars() : ""); 163 164 // Go upwards until we find the enclosing member function 165 FuncDeclaration fd = fdthis; 166 while (1) 167 { 168 if (!fd) 169 { 170 return null; 171 } 172 if (!fd.isNested() || fd.isThis() || (fd.hasDualContext() && fd.isMember2())) 173 break; 174 175 Dsymbol parent = fd.parent; 176 while (1) 177 { 178 if (!parent) 179 return null; 180 TemplateInstance ti = parent.isTemplateInstance(); 181 if (ti) 182 parent = ti.parent; 183 else 184 break; 185 } 186 fd = parent.isFuncDeclaration(); 187 } 188 189 if (!fd.isThis() && !(fd.hasDualContext() && fd.isMember2())) 190 { 191 return null; 192 } 193 194 assert(fd.vthis); 195 return fd; 196 197 } 198 199 /*********************************************************** 200 * Resolve `exp` as a compile-time known string. 201 * Params: 202 * sc = scope 203 * exp = Expression which expected as a string 204 * s = What the string is expected for, will be used in error diagnostic. 205 * Returns: 206 * String literal, or `null` if error happens. 207 */ 208 StringExp semanticString(Scope *sc, Expression exp, const char* s) 209 { 210 sc = sc.startCTFE(); 211 exp = exp.expressionSemantic(sc); 212 exp = resolveProperties(sc, exp); 213 sc = sc.endCTFE(); 214 215 if (exp.op == EXP.error) 216 return null; 217 218 auto e = exp; 219 if (exp.type.isString()) 220 { 221 e = e.ctfeInterpret(); 222 if (e.op == EXP.error) 223 return null; 224 } 225 226 auto se = e.toStringExp(); 227 if (!se) 228 { 229 error(exp.loc, "`string` expected for %s, not `(%s)` of type `%s`", 230 s, exp.toChars(), exp.type.toChars()); 231 return null; 232 } 233 return se; 234 } 235 236 /**************************************** 237 * Convert string to char[]. 238 */ 239 StringExp toUTF8(StringExp se, Scope* sc) 240 { 241 if (se.sz != 1) 242 { 243 // Convert to UTF-8 string 244 se.committed = false; 245 Expression e = castTo(se, sc, Type.tchar.arrayOf()); 246 e = e.optimize(WANTvalue); 247 auto result = e.isStringExp(); 248 assert(result.sz == 1); 249 return result; 250 } 251 return se; 252 } 253 254 private Expression reorderSettingAAElem(BinExp exp, Scope* sc) 255 { 256 BinExp be = exp; 257 258 auto ie = be.e1.isIndexExp(); 259 if (!ie) 260 return be; 261 if (ie.e1.type.toBasetype().ty != Taarray) 262 return be; 263 264 /* Fix evaluation order of setting AA element 265 * https://issues.dlang.org/show_bug.cgi?id=3825 266 * Rewrite: 267 * aa[k1][k2][k3] op= val; 268 * as: 269 * auto ref __aatmp = aa; 270 * auto ref __aakey3 = k1, __aakey2 = k2, __aakey1 = k3; 271 * auto ref __aaval = val; 272 * __aatmp[__aakey3][__aakey2][__aakey1] op= __aaval; // assignment 273 */ 274 275 Expression e0; 276 while (1) 277 { 278 Expression de; 279 ie.e2 = extractSideEffect(sc, "__aakey", de, ie.e2); 280 e0 = Expression.combine(de, e0); 281 282 auto ie1 = ie.e1.isIndexExp(); 283 if (!ie1 || 284 ie1.e1.type.toBasetype().ty != Taarray) 285 { 286 break; 287 } 288 ie = ie1; 289 } 290 assert(ie.e1.type.toBasetype().ty == Taarray); 291 292 Expression de; 293 ie.e1 = extractSideEffect(sc, "__aatmp", de, ie.e1); 294 e0 = Expression.combine(de, e0); 295 296 be.e2 = extractSideEffect(sc, "__aaval", e0, be.e2, true); 297 298 //printf("-e0 = %s, be = %s\n", e0.toChars(), be.toChars()); 299 return Expression.combine(e0, be); 300 } 301 302 303 private Expression checkOpAssignTypes(BinExp binExp, Scope* sc) 304 { 305 auto e1 = binExp.e1; 306 auto e2 = binExp.e2; 307 auto op = binExp.op; 308 auto type = binExp.type; 309 auto loc = binExp.loc; 310 311 // At that point t1 and t2 are the merged types. type is the original type of the lhs. 312 Type t1 = e1.type; 313 Type t2 = e2.type; 314 315 // T opAssign floating yields a floating. Prevent truncating conversions (float to int). 316 // See https://issues.dlang.org/show_bug.cgi?id=3841. 317 // Should we also prevent double to float (type.isfloating() && type.size() < t2.size()) ? 318 if (op == EXP.addAssign || op == EXP.minAssign || 319 op == EXP.mulAssign || op == EXP.divAssign || op == EXP.modAssign || 320 op == EXP.powAssign) 321 { 322 if ((type.isintegral() && t2.isfloating())) 323 { 324 warning(loc, "`%s %s %s` is performing truncating conversion", type.toChars(), EXPtoString(op).ptr, t2.toChars()); 325 } 326 } 327 328 // generate an error if this is a nonsensical *=,/=, or %=, eg real *= imaginary 329 if (op == EXP.mulAssign || op == EXP.divAssign || op == EXP.modAssign) 330 { 331 // Any multiplication by an imaginary or complex number yields a complex result. 332 // r *= c, i*=c, r*=i, i*=i are all forbidden operations. 333 const(char)* opstr = EXPtoString(op).ptr; 334 if (t1.isreal() && t2.iscomplex()) 335 { 336 error(loc, "`%s %s %s` is undefined. Did you mean `%s %s %s.re`?", t1.toChars(), opstr, t2.toChars(), t1.toChars(), opstr, t2.toChars()); 337 return ErrorExp.get(); 338 } 339 else if (t1.isimaginary() && t2.iscomplex()) 340 { 341 error(loc, "`%s %s %s` is undefined. Did you mean `%s %s %s.im`?", t1.toChars(), opstr, t2.toChars(), t1.toChars(), opstr, t2.toChars()); 342 return ErrorExp.get(); 343 } 344 else if ((t1.isreal() || t1.isimaginary()) && t2.isimaginary()) 345 { 346 error(loc, "`%s %s %s` is an undefined operation", t1.toChars(), opstr, t2.toChars()); 347 return ErrorExp.get(); 348 } 349 } 350 351 // generate an error if this is a nonsensical += or -=, eg real += imaginary 352 if (op == EXP.addAssign || op == EXP.minAssign) 353 { 354 // Addition or subtraction of a real and an imaginary is a complex result. 355 // Thus, r+=i, r+=c, i+=r, i+=c are all forbidden operations. 356 if ((t1.isreal() && (t2.isimaginary() || t2.iscomplex())) || (t1.isimaginary() && (t2.isreal() || t2.iscomplex()))) 357 { 358 error(loc, "`%s %s %s` is undefined (result is complex)", t1.toChars(), EXPtoString(op).ptr, t2.toChars()); 359 return ErrorExp.get(); 360 } 361 if (type.isreal() || type.isimaginary()) 362 { 363 assert(global.errors || t2.isfloating()); 364 e2 = e2.castTo(sc, t1); 365 } 366 } 367 if (op == EXP.mulAssign) 368 { 369 if (t2.isfloating()) 370 { 371 if (t1.isreal()) 372 { 373 if (t2.isimaginary() || t2.iscomplex()) 374 { 375 e2 = e2.castTo(sc, t1); 376 } 377 } 378 else if (t1.isimaginary()) 379 { 380 if (t2.isimaginary() || t2.iscomplex()) 381 { 382 switch (t1.ty) 383 { 384 case Timaginary32: 385 t2 = Type.tfloat32; 386 break; 387 388 case Timaginary64: 389 t2 = Type.tfloat64; 390 break; 391 392 case Timaginary80: 393 t2 = Type.tfloat80; 394 break; 395 396 default: 397 assert(0); 398 } 399 e2 = e2.castTo(sc, t2); 400 } 401 } 402 } 403 } 404 else if (op == EXP.divAssign) 405 { 406 if (t2.isimaginary()) 407 { 408 if (t1.isreal()) 409 { 410 // x/iv = i(-x/v) 411 // Therefore, the result is 0 412 e2 = new CommaExp(loc, e2, new RealExp(loc, CTFloat.zero, t1)); 413 e2.type = t1; 414 Expression e = new AssignExp(loc, e1, e2); 415 e.type = t1; 416 return e; 417 } 418 else if (t1.isimaginary()) 419 { 420 Type t3; 421 switch (t1.ty) 422 { 423 case Timaginary32: 424 t3 = Type.tfloat32; 425 break; 426 427 case Timaginary64: 428 t3 = Type.tfloat64; 429 break; 430 431 case Timaginary80: 432 t3 = Type.tfloat80; 433 break; 434 435 default: 436 assert(0); 437 } 438 e2 = e2.castTo(sc, t3); 439 Expression e = new AssignExp(loc, e1, e2); 440 e.type = t1; 441 return e; 442 } 443 } 444 } 445 else if (op == EXP.modAssign) 446 { 447 if (t2.iscomplex()) 448 { 449 error(loc, "cannot perform modulo complex arithmetic"); 450 return ErrorExp.get(); 451 } 452 } 453 return binExp; 454 } 455 456 private Expression extractOpDollarSideEffect(Scope* sc, UnaExp ue) 457 { 458 Expression e0; 459 Expression e1 = Expression.extractLast(ue.e1, e0); 460 // https://issues.dlang.org/show_bug.cgi?id=12585 461 // Extract the side effect part if ue.e1 is comma. 462 463 if ((sc.flags & SCOPE.ctfe) ? hasSideEffect(e1) : !isTrivialExp(e1)) // match logic in extractSideEffect() 464 { 465 /* Even if opDollar is needed, 'e1' should be evaluate only once. So 466 * Rewrite: 467 * e1.opIndex( ... use of $ ... ) 468 * e1.opSlice( ... use of $ ... ) 469 * as: 470 * (ref __dop = e1, __dop).opIndex( ... __dop.opDollar ...) 471 * (ref __dop = e1, __dop).opSlice( ... __dop.opDollar ...) 472 */ 473 e1 = extractSideEffect(sc, "__dop", e0, e1, false); 474 assert(e1.isVarExp()); 475 e1.isVarExp().var.storage_class |= STC.exptemp; // lifetime limited to expression 476 } 477 ue.e1 = e1; 478 return e0; 479 } 480 481 /************************************** 482 * Runs semantic on ae.arguments. Declares temporary variables 483 * if '$' was used. 484 */ 485 Expression resolveOpDollar(Scope* sc, ArrayExp ae, Expression* pe0) 486 { 487 assert(!ae.lengthVar); 488 *pe0 = null; 489 AggregateDeclaration ad = isAggregate(ae.e1.type); 490 Dsymbol slice = search_function(ad, Id.slice); 491 //printf("slice = %s %s\n", slice.kind(), slice.toChars()); 492 foreach (i, e; *ae.arguments) 493 { 494 if (i == 0) 495 *pe0 = extractOpDollarSideEffect(sc, ae); 496 497 if (e.op == EXP.interval && !(slice && slice.isTemplateDeclaration())) 498 { 499 Lfallback: 500 if (ae.arguments.length == 1) 501 return null; 502 error(ae.loc, "multi-dimensional slicing requires template `opSlice`"); 503 return ErrorExp.get(); 504 } 505 //printf("[%d] e = %s\n", i, e.toChars()); 506 507 // Create scope for '$' variable for this dimension 508 auto sym = new ArrayScopeSymbol(sc, ae); 509 sym.parent = sc.scopesym; 510 sc = sc.push(sym); 511 ae.lengthVar = null; // Create it only if required 512 ae.currentDimension = i; // Dimension for $, if required 513 514 e = e.expressionSemantic(sc); 515 e = resolveProperties(sc, e); 516 517 if (ae.lengthVar && sc.func) 518 { 519 // If $ was used, declare it now 520 Expression de = new DeclarationExp(ae.loc, ae.lengthVar); 521 de = de.expressionSemantic(sc); 522 *pe0 = Expression.combine(*pe0, de); 523 } 524 sc = sc.pop(); 525 526 if (auto ie = e.isIntervalExp()) 527 { 528 auto tiargs = new Objects(); 529 Expression edim = new IntegerExp(ae.loc, i, Type.tsize_t); 530 edim = edim.expressionSemantic(sc); 531 tiargs.push(edim); 532 533 auto fargs = new Expressions(2); 534 (*fargs)[0] = ie.lwr; 535 (*fargs)[1] = ie.upr; 536 537 uint xerrors = global.startGagging(); 538 sc = sc.push(); 539 FuncDeclaration fslice = resolveFuncCall(ae.loc, sc, slice, tiargs, ae.e1.type, ArgumentList(fargs), FuncResolveFlag.quiet); 540 sc = sc.pop(); 541 global.endGagging(xerrors); 542 if (!fslice) 543 goto Lfallback; 544 545 e = new DotTemplateInstanceExp(ae.loc, ae.e1, slice.ident, tiargs); 546 e = new CallExp(ae.loc, e, fargs); 547 e = e.expressionSemantic(sc); 548 } 549 550 if (!e.type) 551 { 552 error(ae.loc, "`%s` has no value", e.toChars()); 553 e = ErrorExp.get(); 554 } 555 if (e.op == EXP.error) 556 return e; 557 558 (*ae.arguments)[i] = e; 559 } 560 return ae; 561 } 562 563 /************************************** 564 * Runs semantic on se.lwr and se.upr. Declares a temporary variable 565 * if '$' was used. 566 * Returns: 567 * ae, or ErrorExp if errors occurred 568 */ 569 Expression resolveOpDollar(Scope* sc, ArrayExp ae, IntervalExp ie, Expression* pe0) 570 { 571 //assert(!ae.lengthVar); 572 if (!ie) 573 return ae; 574 575 VarDeclaration lengthVar = ae.lengthVar; 576 bool errors = false; 577 578 // create scope for '$' 579 auto sym = new ArrayScopeSymbol(sc, ae); 580 sym.parent = sc.scopesym; 581 sc = sc.push(sym); 582 583 Expression sem(Expression e) 584 { 585 e = e.expressionSemantic(sc); 586 e = resolveProperties(sc, e); 587 if (!e.type) 588 { 589 error(ae.loc, "`%s` has no value", e.toChars()); 590 errors = true; 591 } 592 return e; 593 } 594 595 ie.lwr = sem(ie.lwr); 596 ie.upr = sem(ie.upr); 597 598 if (ie.lwr.isErrorExp() || ie.upr.isErrorExp()) 599 errors = true; 600 601 if (lengthVar != ae.lengthVar && sc.func) 602 { 603 // If $ was used, declare it now 604 Expression de = new DeclarationExp(ae.loc, ae.lengthVar); 605 de = de.expressionSemantic(sc); 606 *pe0 = Expression.combine(*pe0, de); 607 } 608 609 sc = sc.pop(); 610 611 return errors ? ErrorExp.get() : ae; 612 } 613 614 /****************************** 615 * Perform semantic() on an array of Expressions. 616 */ 617 extern(D) bool arrayExpressionSemantic( 618 Expression[] exps, Scope* sc, bool preserveErrors = false) 619 { 620 bool err = false; 621 foreach (ref e; exps) 622 { 623 if (e is null) continue; 624 auto e2 = e.expressionSemantic(sc); 625 if (e2.op == EXP.error) 626 err = true; 627 if (preserveErrors || e2.op != EXP.error) 628 e = e2; 629 } 630 return err; 631 } 632 633 /************************************************ 634 * Handle the postblit call on lvalue, or the move of rvalue. 635 * 636 * Params: 637 * sc = the scope where the expression is encountered 638 * e = the expression the needs to be moved or copied (source) 639 * t = if the struct defines a copy constructor, the type of the destination 640 * 641 * Returns: 642 * The expression that copy constructs or moves the value. 643 */ 644 extern (D) Expression doCopyOrMove(Scope *sc, Expression e, Type t = null) 645 { 646 if (auto ce = e.isCondExp()) 647 { 648 ce.e1 = doCopyOrMove(sc, ce.e1); 649 ce.e2 = doCopyOrMove(sc, ce.e2); 650 } 651 else 652 { 653 e = e.isLvalue() ? callCpCtor(sc, e, t) : valueNoDtor(e); 654 } 655 return e; 656 } 657 658 /********************************************* 659 * If e is an instance of a struct, and that struct has a copy constructor, 660 * rewrite e as: 661 * (tmp = e),tmp 662 * Input: 663 * sc = just used to specify the scope of created temporary variable 664 * destinationType = the type of the object on which the copy constructor is called; 665 * may be null if the struct defines a postblit 666 */ 667 private Expression callCpCtor(Scope* sc, Expression e, Type destinationType) 668 { 669 if (auto ts = e.type.baseElemOf().isTypeStruct()) 670 { 671 StructDeclaration sd = ts.sym; 672 if (sd.postblit || sd.hasCopyCtor) 673 { 674 /* Create a variable tmp, and replace the argument e with: 675 * (tmp = e),tmp 676 * and let AssignExp() handle the construction. 677 * This is not the most efficient, ideally tmp would be constructed 678 * directly onto the stack. 679 */ 680 auto tmp = copyToTemp(STC.rvalue, "__copytmp", e); 681 if (sd.hasCopyCtor && destinationType) 682 { 683 // https://issues.dlang.org/show_bug.cgi?id=22619 684 // If the destination type is inout we can preserve it 685 // only if inside an inout function; if we are not inside 686 // an inout function, then we will preserve the type of 687 // the source 688 if (destinationType.hasWild && !(sc.func.storage_class & STC.wild)) 689 tmp.type = e.type; 690 else 691 tmp.type = destinationType; 692 } 693 tmp.storage_class |= STC.nodtor; 694 tmp.dsymbolSemantic(sc); 695 Expression de = new DeclarationExp(e.loc, tmp); 696 Expression ve = new VarExp(e.loc, tmp); 697 de.type = Type.tvoid; 698 ve.type = e.type; 699 return Expression.combine(de, ve); 700 } 701 } 702 return e; 703 } 704 705 /************************************************ 706 * If we want the value of this expression, but do not want to call 707 * the destructor on it. 708 */ 709 Expression valueNoDtor(Expression e) 710 { 711 auto ex = lastComma(e); 712 713 if (auto ce = ex.isCallExp()) 714 { 715 /* The struct value returned from the function is transferred 716 * so do not call the destructor on it. 717 * Recognize: 718 * ((S _ctmp = S.init), _ctmp).this(...) 719 * and make sure the destructor is not called on _ctmp 720 * BUG: if ex is a CommaExp, we should go down the right side. 721 */ 722 if (auto dve = ce.e1.isDotVarExp()) 723 { 724 if (dve.var.isCtorDeclaration()) 725 { 726 // It's a constructor call 727 if (auto comma = dve.e1.isCommaExp()) 728 { 729 if (auto ve = comma.e2.isVarExp()) 730 { 731 VarDeclaration ctmp = ve.var.isVarDeclaration(); 732 if (ctmp) 733 { 734 ctmp.storage_class |= STC.nodtor; 735 assert(!ce.isLvalue()); 736 } 737 } 738 } 739 } 740 } 741 } 742 else if (auto ve = ex.isVarExp()) 743 { 744 auto vtmp = ve.var.isVarDeclaration(); 745 if (vtmp && (vtmp.storage_class & STC.rvalue)) 746 { 747 vtmp.storage_class |= STC.nodtor; 748 } 749 } 750 return e; 751 } 752 753 /* 754 Checks if `exp` contains a direct access to a `noreturn` 755 variable. If that is the case, an `assert(0)` expression 756 is generated and returned. This function should be called 757 only after semantic analysis has been performed on `exp`. 758 759 Params: 760 exp = expression that is checked 761 762 Returns: 763 An `assert(0)` expression if `exp` contains a `noreturn` 764 variable access, `exp` otherwise. 765 */ 766 767 Expression checkNoreturnVarAccess(Expression exp) 768 { 769 assert(exp.type); 770 771 Expression result = exp; 772 if (exp.type.isTypeNoreturn() && !exp.isAssertExp() && 773 !exp.isThrowExp() && !exp.isCallExp()) 774 { 775 auto msg = new StringExp(exp.loc, "Accessed expression of type `noreturn`"); 776 msg.type = Type.tstring; 777 result = new AssertExp(exp.loc, IntegerExp.literal!0, msg); 778 result.type = exp.type; 779 } 780 781 return result; 782 } 783 784 /****************************** 785 * Find symbol in accordance with the UFCS name look up rule 786 */ 787 private Expression searchUFCS(Scope* sc, UnaExp ue, Identifier ident) 788 { 789 //printf("searchUFCS(ident = %s)\n", ident.toChars()); 790 Loc loc = ue.loc; 791 792 // TODO: merge with Scope.search.searchScopes() 793 Dsymbol searchScopes(int flags) 794 { 795 Dsymbol s = null; 796 for (Scope* scx = sc; scx; scx = scx.enclosing) 797 { 798 if (!scx.scopesym) 799 continue; 800 if (scx.scopesym.isModule()) 801 flags |= SearchUnqualifiedModule; // tell Module.search() that SearchLocalsOnly is to be obeyed 802 s = scx.scopesym.search(loc, ident, flags); 803 if (s) 804 { 805 // overload set contains only module scope symbols. 806 if (s.isOverloadSet()) 807 break; 808 // selective/renamed imports also be picked up 809 if (AliasDeclaration ad = s.isAliasDeclaration()) 810 { 811 if (ad._import) 812 break; 813 } 814 // See only module scope symbols for UFCS target. 815 Dsymbol p = s.toParent2(); 816 if (p && p.isModule()) 817 break; 818 } 819 s = null; 820 821 // Stop when we hit a module, but keep going if that is not just under the global scope 822 if (scx.scopesym.isModule() && !(scx.enclosing && !scx.enclosing.enclosing)) 823 break; 824 } 825 return s; 826 } 827 828 int flags = 0; 829 Dsymbol s; 830 831 if (sc.flags & SCOPE.ignoresymbolvisibility) 832 flags |= IgnoreSymbolVisibility; 833 834 // First look in local scopes 835 s = searchScopes(flags | SearchLocalsOnly); 836 if (!s) 837 { 838 // Second look in imported modules 839 s = searchScopes(flags | SearchImportsOnly); 840 } 841 842 if (!s) 843 return ue.e1.type.getProperty(sc, loc, ident, 0, ue.e1); 844 845 FuncDeclaration f = s.isFuncDeclaration(); 846 if (f) 847 { 848 TemplateDeclaration td = getFuncTemplateDecl(f); 849 if (td) 850 { 851 if (td.overroot) 852 td = td.overroot; 853 s = td; 854 } 855 } 856 857 if (auto dti = ue.isDotTemplateInstanceExp()) 858 { 859 // https://issues.dlang.org/show_bug.cgi?id=23968 860 // Typically, deprecated alias declarations are caught 861 // when `TemplateInstance.findTempDecl` is called, 862 // however, in this case the tempdecl field is updated 863 // therefore `findTempDecl` will return immediately 864 // and not get the chance to issue the deprecation. 865 if (s.isAliasDeclaration()) 866 s.checkDeprecated(ue.loc, sc); 867 868 auto ti = new TemplateInstance(loc, s.ident, dti.ti.tiargs); 869 if (!ti.updateTempDecl(sc, s)) 870 return ErrorExp.get(); 871 return new ScopeExp(loc, ti); 872 } 873 else 874 { 875 //printf("-searchUFCS() %s\n", s.toChars()); 876 return new DsymbolExp(loc, s); 877 } 878 } 879 880 /****************************** 881 * check e is exp.opDispatch!(tiargs) or not 882 * It's used to switch to UFCS the semantic analysis path 883 */ 884 private bool isDotOpDispatch(Expression e) 885 { 886 if (auto dtie = e.isDotTemplateInstanceExp()) 887 return dtie.ti.name == Id.opDispatch; 888 return false; 889 } 890 891 private void hookDtors(CondExp ce, Scope* sc) 892 { 893 extern (C++) final class DtorVisitor : StoppableVisitor 894 { 895 alias visit = typeof(super).visit; 896 public: 897 Scope* sc; 898 CondExp ce; 899 VarDeclaration vcond; 900 bool isThen; 901 902 extern (D) this(Scope* sc, CondExp ce) @safe 903 { 904 this.sc = sc; 905 this.ce = ce; 906 } 907 908 override void visit(Expression e) 909 { 910 //printf("(e = %s)\n", e.toChars()); 911 } 912 913 override void visit(DeclarationExp e) 914 { 915 auto v = e.declaration.isVarDeclaration(); 916 if (v && !v.isDataseg()) 917 { 918 if (v._init) 919 { 920 if (auto ei = v._init.isExpInitializer()) 921 walkPostorder(ei.exp, this); 922 } 923 924 if (v.edtor) 925 walkPostorder(v.edtor, this); 926 927 if (v.needsScopeDtor()) 928 { 929 if (!vcond) 930 { 931 vcond = copyToTemp(STC.volatile_ | STC.const_, "__cond", ce.econd); 932 vcond.dsymbolSemantic(sc); 933 934 Expression de = new DeclarationExp(ce.econd.loc, vcond); 935 de = de.expressionSemantic(sc); 936 937 Expression ve = new VarExp(ce.econd.loc, vcond); 938 ce.econd = Expression.combine(de, ve); 939 } 940 941 //printf("\t++v = %s, v.edtor = %s\n", v.toChars(), v.edtor.toChars()); 942 Expression ve = new VarExp(vcond.loc, vcond); 943 if (isThen) 944 v.edtor = new LogicalExp(v.edtor.loc, EXP.andAnd, ve, v.edtor); 945 else 946 v.edtor = new LogicalExp(v.edtor.loc, EXP.orOr, ve, v.edtor); 947 v.edtor = v.edtor.expressionSemantic(sc); 948 //printf("\t--v = %s, v.edtor = %s\n", v.toChars(), v.edtor.toChars()); 949 } 950 } 951 } 952 } 953 954 scope DtorVisitor v = new DtorVisitor(sc, ce); 955 //printf("+%s\n", toChars()); 956 v.isThen = true; 957 walkPostorder(ce.e1, v); 958 v.isThen = false; 959 walkPostorder(ce.e2, v); 960 //printf("-%s\n", toChars()); 961 } 962 963 964 /****************************** 965 * Pull out callable entity with UFCS. 966 */ 967 private Expression resolveUFCS(Scope* sc, CallExp ce) 968 { 969 Loc loc = ce.loc; 970 Expression eleft; 971 Expression e; 972 973 if (auto die = ce.e1.isDotIdExp()) 974 { 975 Identifier ident = die.ident; 976 977 Expression ex = die.dotIdSemanticPropX(sc); 978 if (ex != die) 979 { 980 ce.e1 = ex; 981 return null; 982 } 983 eleft = die.e1; 984 985 Type t = eleft.type.toBasetype(); 986 if (t.ty == Tarray || t.ty == Tsarray || t.ty == Tnull || (t.isTypeBasic() && t.ty != Tvoid)) 987 { 988 /* Built-in types and arrays have no callable properties, so do shortcut. 989 * It is necessary in: e.init() 990 */ 991 } 992 else if (t.ty == Taarray) 993 { 994 if (ident == Id.remove) 995 { 996 /* Transform: 997 * aa.remove(arg) into delete aa[arg] 998 */ 999 if (!ce.arguments || ce.arguments.length != 1) 1000 { 1001 error(ce.loc, "expected key as argument to `aa.remove()`"); 1002 return ErrorExp.get(); 1003 } 1004 if (!eleft.type.isMutable()) 1005 { 1006 error(ce.loc, "cannot remove key from `%s` associative array `%s`", MODtoChars(t.mod), eleft.toChars()); 1007 return ErrorExp.get(); 1008 } 1009 Expression key = (*ce.arguments)[0]; 1010 key = key.expressionSemantic(sc); 1011 key = resolveProperties(sc, key); 1012 1013 TypeAArray taa = t.isTypeAArray(); 1014 key = key.implicitCastTo(sc, taa.index); 1015 1016 if (key.checkValue() || key.checkSharedAccess(sc)) 1017 return ErrorExp.get(); 1018 1019 semanticTypeInfo(sc, taa.index); 1020 1021 return new RemoveExp(loc, eleft, key); 1022 } 1023 } 1024 else 1025 { 1026 if (Expression ey = die.dotIdSemanticProp(sc, 1)) 1027 { 1028 if (ey.op == EXP.error) 1029 return ey; 1030 ce.e1 = ey; 1031 if (isDotOpDispatch(ey)) 1032 { 1033 // even opDispatch and UFCS must have valid arguments, 1034 // so now that we've seen indication of a problem, 1035 // check them for issues. 1036 Expressions* originalArguments = Expression.arraySyntaxCopy(ce.arguments); 1037 1038 uint errors = global.startGagging(); 1039 e = ce.expressionSemantic(sc); 1040 if (!global.endGagging(errors)) 1041 return e; 1042 1043 if (arrayExpressionSemantic(originalArguments.peekSlice(), sc)) 1044 return ErrorExp.get(); 1045 1046 /* fall down to UFCS */ 1047 } 1048 else 1049 return null; 1050 } 1051 } 1052 1053 /* https://issues.dlang.org/show_bug.cgi?id=13953 1054 * 1055 * If a struct has an alias this to an associative array 1056 * and remove is used on a struct instance, we have to 1057 * check first if there is a remove function that can be called 1058 * on the struct. If not we must check the alias this. 1059 * 1060 * struct A 1061 * { 1062 * string[string] a; 1063 * alias a this; 1064 * } 1065 * 1066 * void fun() 1067 * { 1068 * A s; 1069 * s.remove("foo"); 1070 * } 1071 */ 1072 const errors = global.startGagging(); 1073 e = searchUFCS(sc, die, ident); 1074 // if there were any errors and the identifier was remove 1075 if (global.endGagging(errors)) 1076 { 1077 if (ident == Id.remove) 1078 { 1079 // check alias this 1080 Expression alias_e = resolveAliasThis(sc, die.e1, 1); 1081 if (alias_e && alias_e != die.e1) 1082 { 1083 die.e1 = alias_e; 1084 CallExp ce2 = ce.syntaxCopy(); 1085 ce2.e1 = die; 1086 e = ce2.isCallExp().trySemantic(sc); 1087 if (e) 1088 return e; 1089 } 1090 } 1091 // if alias this did not work out, print the initial errors 1092 searchUFCS(sc, die, ident); 1093 } 1094 } 1095 else if (auto dti = ce.e1.isDotTemplateInstanceExp()) 1096 { 1097 if (Expression ey = dti.dotTemplateSemanticProp(sc, DotExpFlag.gag)) 1098 { 1099 ce.e1 = ey; 1100 return null; 1101 } 1102 eleft = dti.e1; 1103 e = searchUFCS(sc, dti, dti.ti.name); 1104 } 1105 else 1106 return null; 1107 1108 // Rewrite 1109 ce.e1 = e; 1110 if (!ce.arguments) 1111 ce.arguments = new Expressions(); 1112 ce.arguments.shift(eleft); 1113 if (!ce.names) 1114 ce.names = new Identifiers(); 1115 ce.names.shift(null); 1116 ce.isUfcsRewrite = true; 1117 return null; 1118 } 1119 1120 int expandAliasThisTuples(Expressions* exps, size_t starti = 0) 1121 { 1122 if (!exps || exps.length == 0) 1123 return -1; 1124 1125 for (size_t u = starti; u < exps.length; u++) 1126 { 1127 Expression exp = (*exps)[u]; 1128 if (TupleDeclaration td = exp.isAliasThisTuple) 1129 { 1130 exps.remove(u); 1131 size_t i; 1132 td.foreachVar((s) 1133 { 1134 auto d = s.isDeclaration(); 1135 auto e = new DotVarExp(exp.loc, exp, d); 1136 assert(d.type); 1137 e.type = d.type; 1138 exps.insert(u + i, e); 1139 ++i; 1140 }); 1141 version (none) 1142 { 1143 printf("expansion ->\n"); 1144 foreach (e; exps) 1145 { 1146 printf("\texps[%d] e = %s %s\n", i, EXPtoString(e.op), e.toChars()); 1147 } 1148 } 1149 return cast(int)u; 1150 } 1151 } 1152 return -1; 1153 } 1154 1155 /****************************** 1156 * Pull out property with UFCS. 1157 */ 1158 private Expression resolveUFCSProperties(Scope* sc, Expression e1, Expression e2 = null) 1159 { 1160 Loc loc = e1.loc; 1161 Expression eleft; 1162 Expression e; 1163 1164 if (auto die = e1.isDotIdExp()) 1165 { 1166 eleft = die.e1; 1167 e = searchUFCS(sc, die, die.ident); 1168 } 1169 else if (auto dti = e1.isDotTemplateInstanceExp()) 1170 { 1171 eleft = dti.e1; 1172 e = searchUFCS(sc, dti, dti.ti.name); 1173 } 1174 else 1175 return null; 1176 1177 if (e is null) 1178 return null; 1179 1180 // Rewrite 1181 if (e2) 1182 { 1183 // run semantic without gagging 1184 e2 = e2.expressionSemantic(sc); 1185 1186 /* f(e1) = e2 1187 */ 1188 Expression ex = e.copy(); 1189 auto a1 = new Expressions(1); 1190 (*a1)[0] = eleft; 1191 ex = new CallExp(loc, ex, a1); 1192 auto e1PassSemantic = ex.trySemantic(sc); 1193 1194 /* f(e1, e2) 1195 */ 1196 auto a2 = new Expressions(2); 1197 (*a2)[0] = eleft; 1198 (*a2)[1] = e2; 1199 e = new CallExp(loc, e, a2); 1200 e = e.trySemantic(sc); 1201 if (!e1PassSemantic && !e) 1202 { 1203 /* https://issues.dlang.org/show_bug.cgi?id=20448 1204 * 1205 * If both versions have failed to pass semantic, 1206 * f(e1) = e2 gets priority in error printing 1207 * because f might be a templated function that 1208 * failed to instantiate and we have to print 1209 * the instantiation errors. 1210 */ 1211 return e1.expressionSemantic(sc); 1212 } 1213 else if (ex && !e) 1214 { 1215 ex = new AssignExp(loc, ex, e2); 1216 return ex.expressionSemantic(sc); 1217 } 1218 else 1219 { 1220 // strict setter prints errors if fails 1221 e = e.expressionSemantic(sc); 1222 } 1223 return e; 1224 } 1225 else 1226 { 1227 /* f(e1) 1228 */ 1229 auto arguments = new Expressions(1); 1230 (*arguments)[0] = eleft; 1231 e = new CallExp(loc, e, arguments); 1232 1233 // https://issues.dlang.org/show_bug.cgi?id=24017 1234 if (sc.flags & SCOPE.debug_) 1235 e.isCallExp().inDebugStatement = true; 1236 1237 e = e.expressionSemantic(sc); 1238 return e; 1239 } 1240 } 1241 1242 /****************************** 1243 * If e1 is a property function (template), resolve it. 1244 */ 1245 Expression resolvePropertiesOnly(Scope* sc, Expression e1) 1246 { 1247 //printf("e1 = %s %s\n", Token.toChars(e1.op), e1.toChars()); 1248 1249 Expression handleOverloadSet(OverloadSet os) 1250 { 1251 assert(os); 1252 foreach (s; os.a) 1253 { 1254 auto fd = s.isFuncDeclaration(); 1255 auto td = s.isTemplateDeclaration(); 1256 if (fd) 1257 { 1258 if (fd.type.isTypeFunction().isproperty) 1259 return resolveProperties(sc, e1); 1260 } 1261 else if (td && td.onemember && (fd = td.onemember.isFuncDeclaration()) !is null) 1262 { 1263 if (fd.type.isTypeFunction().isproperty || 1264 (fd.storage_class2 & STC.property) || 1265 (td._scope.stc & STC.property)) 1266 return resolveProperties(sc, e1); 1267 } 1268 } 1269 return e1; 1270 } 1271 1272 Expression handleTemplateDecl(TemplateDeclaration td) 1273 { 1274 assert(td); 1275 if (td.onemember) 1276 { 1277 if (auto fd = td.onemember.isFuncDeclaration()) 1278 { 1279 if (fd.type.isTypeFunction().isproperty || 1280 (fd.storage_class2 & STC.property) || 1281 (td._scope.stc & STC.property)) 1282 return resolveProperties(sc, e1); 1283 } 1284 } 1285 return e1; 1286 } 1287 1288 Expression handleFuncDecl(FuncDeclaration fd) 1289 { 1290 assert(fd); 1291 if (fd.type.isTypeFunction().isproperty) 1292 return resolveProperties(sc, e1); 1293 return e1; 1294 } 1295 1296 if (auto de = e1.isDotExp()) 1297 { 1298 if (auto os = de.e2.isOverExp()) 1299 return handleOverloadSet(os.vars); 1300 } 1301 else if (auto oe = e1.isOverExp()) 1302 return handleOverloadSet(oe.vars); 1303 else if (auto dti = e1.isDotTemplateInstanceExp()) 1304 { 1305 if (dti.ti.tempdecl) 1306 if (auto td = dti.ti.tempdecl.isTemplateDeclaration()) 1307 return handleTemplateDecl(td); 1308 } 1309 else if (auto dte = e1.isDotTemplateExp()) 1310 return handleTemplateDecl(dte.td); 1311 else if (auto se = e1.isScopeExp()) 1312 { 1313 Dsymbol s = se.sds; 1314 TemplateInstance ti = s.isTemplateInstance(); 1315 if (ti && !ti.semanticRun && ti.tempdecl) 1316 if (auto td = ti.tempdecl.isTemplateDeclaration()) 1317 return handleTemplateDecl(td); 1318 } 1319 else if (auto et = e1.isTemplateExp()) 1320 return handleTemplateDecl(et.td); 1321 else if (e1.isDotVarExp() && e1.type.isTypeFunction()) 1322 { 1323 DotVarExp dve = e1.isDotVarExp(); 1324 return handleFuncDecl(dve.var.isFuncDeclaration()); 1325 } 1326 else if (e1.isVarExp() && e1.type && e1.type.isTypeFunction() && (sc.intypeof || !e1.isVarExp().var.needThis())) 1327 return handleFuncDecl(e1.isVarExp().var.isFuncDeclaration()); 1328 return e1; 1329 } 1330 1331 /**************************************** 1332 * Turn symbol `s` into the expression it represents. 1333 * 1334 * Params: 1335 * s = symbol to resolve 1336 * loc = location of use of `s` 1337 * sc = context 1338 * hasOverloads = applies if `s` represents a function. 1339 * true means it's overloaded and will be resolved later, 1340 * false means it's the exact function symbol. 1341 * Returns: 1342 * `s` turned into an expression, `ErrorExp` if an error occurred 1343 */ 1344 Expression symbolToExp(Dsymbol s, const ref Loc loc, Scope *sc, bool hasOverloads) 1345 { 1346 static if (LOGSEMANTIC) 1347 { 1348 printf("DsymbolExp::resolve(%s %s)\n", s.kind(), s.toChars()); 1349 } 1350 1351 Lagain: 1352 Expression e; 1353 1354 //printf("DsymbolExp:: %p '%s' is a symbol\n", this, toChars()); 1355 //printf("s = '%s', s.kind = '%s'\n", s.toChars(), s.kind()); 1356 Dsymbol olds = s; 1357 Declaration d = s.isDeclaration(); 1358 if (d && (d.storage_class & STC.templateparameter)) 1359 { 1360 s = s.toAlias(); 1361 } 1362 else 1363 { 1364 // functions are checked after overloading 1365 // templates are checked after matching constraints 1366 if (!s.isFuncDeclaration() && !s.isTemplateDeclaration()) 1367 { 1368 s.checkDeprecated(loc, sc); 1369 if (d) 1370 d.checkDisabled(loc, sc); 1371 } 1372 1373 // https://issues.dlang.org/show_bug.cgi?id=12023 1374 // if 's' is a tuple variable, the tuple is returned. 1375 s = s.toAlias(); 1376 1377 //printf("s = '%s', s.kind = '%s', s.needThis() = %p\n", s.toChars(), s.kind(), s.needThis()); 1378 if (s != olds && !s.isFuncDeclaration() && !s.isTemplateDeclaration()) 1379 { 1380 s.checkDeprecated(loc, sc); 1381 if (d) 1382 d.checkDisabled(loc, sc); 1383 } 1384 1385 if (auto sd = s.isDeclaration()) 1386 { 1387 if (sd.isSystem()) 1388 { 1389 if (sc.setUnsafePreview(global.params.systemVariables, false, loc, 1390 "cannot access `@system` variable `%s` in @safe code", sd)) 1391 { 1392 if (auto v = sd.isVarDeclaration()) 1393 { 1394 if (v.systemInferred) 1395 errorSupplemental(v.loc, "`%s` is inferred to be `@system` from its initializer here", v.toChars()); 1396 else 1397 errorSupplemental(v.loc, "`%s` is declared here", v.toChars()); 1398 } 1399 return ErrorExp.get(); 1400 } 1401 } 1402 } 1403 } 1404 1405 if (auto em = s.isEnumMember()) 1406 { 1407 return em.getVarExp(loc, sc); 1408 } 1409 if (auto v = s.isVarDeclaration()) 1410 { 1411 //printf("Identifier '%s' is a variable, type '%s'\n", s.toChars(), v.type.toChars()); 1412 if (sc.intypeof == 1 && !v.inuse) 1413 v.dsymbolSemantic(sc); 1414 if (!v.type || // during variable type inference 1415 !v.type.deco && v.inuse) // during variable type semantic 1416 { 1417 if (v.inuse) // variable type depends on the variable itself 1418 error(loc, "circular reference to %s `%s`", v.kind(), v.toPrettyChars()); 1419 else // variable type cannot be determined 1420 error(loc, "forward reference to %s `%s`", v.kind(), v.toPrettyChars()); 1421 return ErrorExp.get(); 1422 } 1423 if (v.type.ty == Terror) 1424 return ErrorExp.get(); 1425 1426 if ((v.storage_class & STC.manifest) && v._init) 1427 { 1428 if (v.inuse) 1429 { 1430 error(loc, "circular initialization of %s `%s`", v.kind(), v.toPrettyChars()); 1431 return ErrorExp.get(); 1432 } 1433 e = v.expandInitializer(loc); 1434 v.inuse++; 1435 e = e.expressionSemantic(sc); 1436 v.inuse--; 1437 return e; 1438 } 1439 1440 // We need to run semantics to correctly set 'STC.field' if it is a member variable 1441 // that could be forward referenced. This is needed for 'v.needThis()' to work 1442 if (v.isThis()) 1443 v.dsymbolSemantic(sc); 1444 1445 // Change the ancestor lambdas to delegate before hasThis(sc) call. 1446 if (v.checkNestedReference(sc, loc)) 1447 return ErrorExp.get(); 1448 1449 if (v.needThis() && hasThis(sc)) 1450 e = new DotVarExp(loc, new ThisExp(loc), v); 1451 else 1452 e = new VarExp(loc, v); 1453 e = e.expressionSemantic(sc); 1454 return e; 1455 } 1456 if (auto fld = s.isFuncLiteralDeclaration()) 1457 { 1458 //printf("'%s' is a function literal\n", fld.toChars()); 1459 e = new FuncExp(loc, fld); 1460 return e.expressionSemantic(sc); 1461 } 1462 if (auto f = s.isFuncDeclaration()) 1463 { 1464 f = f.toAliasFunc(); 1465 if (!f.functionSemantic()) 1466 return ErrorExp.get(); 1467 1468 if (!hasOverloads && f.checkForwardRef(loc)) 1469 return ErrorExp.get(); 1470 1471 auto fd = s.isFuncDeclaration(); 1472 fd.type = f.type; 1473 return new VarExp(loc, fd, hasOverloads); 1474 } 1475 if (OverDeclaration od = s.isOverDeclaration()) 1476 { 1477 e = new VarExp(loc, od, true); 1478 e.type = Type.tvoid; 1479 return e; 1480 } 1481 if (OverloadSet o = s.isOverloadSet()) 1482 { 1483 //printf("'%s' is an overload set\n", o.toChars()); 1484 return new OverExp(loc, o); 1485 } 1486 1487 if (Import imp = s.isImport()) 1488 { 1489 if (!imp.pkg) 1490 { 1491 .error(loc, "forward reference of import `%s`", imp.toChars()); 1492 return ErrorExp.get(); 1493 } 1494 auto ie = new ScopeExp(loc, imp.pkg); 1495 return ie.expressionSemantic(sc); 1496 } 1497 if (Package pkg = s.isPackage()) 1498 { 1499 auto ie = new ScopeExp(loc, pkg); 1500 return ie.expressionSemantic(sc); 1501 } 1502 if (Module mod = s.isModule()) 1503 { 1504 auto ie = new ScopeExp(loc, mod); 1505 return ie.expressionSemantic(sc); 1506 } 1507 if (Nspace ns = s.isNspace()) 1508 { 1509 auto ie = new ScopeExp(loc, ns); 1510 return ie.expressionSemantic(sc); 1511 } 1512 1513 if (Type t = s.getType()) 1514 { 1515 return (new TypeExp(loc, t)).expressionSemantic(sc); 1516 } 1517 1518 if (TupleDeclaration tup = s.isTupleDeclaration()) 1519 { 1520 if (tup.needThis() && hasThis(sc)) 1521 e = new DotVarExp(loc, new ThisExp(loc), tup); 1522 else 1523 e = new TupleExp(loc, tup); 1524 e = e.expressionSemantic(sc); 1525 return e; 1526 } 1527 1528 if (TemplateInstance ti = s.isTemplateInstance()) 1529 { 1530 ti.dsymbolSemantic(sc); 1531 if (!ti.inst || ti.errors) 1532 return ErrorExp.get(); 1533 s = ti.toAlias(); 1534 if (!s.isTemplateInstance()) 1535 goto Lagain; 1536 e = new ScopeExp(loc, ti); 1537 e = e.expressionSemantic(sc); 1538 return e; 1539 } 1540 if (TemplateDeclaration td = s.isTemplateDeclaration()) 1541 { 1542 Dsymbol p = td.toParentLocal(); 1543 FuncDeclaration fdthis = hasThis(sc); 1544 AggregateDeclaration ad = p ? p.isAggregateDeclaration() : null; 1545 if (fdthis && ad && fdthis.isMemberLocal() == ad && (td._scope.stc & STC.static_) == 0) 1546 { 1547 e = new DotTemplateExp(loc, new ThisExp(loc), td); 1548 } 1549 else 1550 e = new TemplateExp(loc, td); 1551 e = e.expressionSemantic(sc); 1552 return e; 1553 } 1554 1555 .error(loc, "%s `%s` is not a variable", s.kind(), s.toChars()); 1556 return ErrorExp.get(); 1557 } 1558 1559 /************************************************************* 1560 * Given var, get the 1561 * right `this` pointer if var is in an outer class, but our 1562 * existing `this` pointer is in an inner class. 1563 * Params: 1564 * loc = location to use for error messages 1565 * sc = context 1566 * ad = struct or class we need the correct `this` for 1567 * e1 = existing `this` 1568 * var = the specific member of ad we're accessing 1569 * flag = if true, return `null` instead of throwing an error 1570 * Returns: 1571 * Expression representing the `this` for the var 1572 */ 1573 private Expression getRightThis(const ref Loc loc, Scope* sc, AggregateDeclaration ad, Expression e1, Dsymbol var, int flag = 0) 1574 { 1575 //printf("\ngetRightThis(e1 = %s, ad = %s, var = %s)\n", e1.toChars(), ad.toChars(), var.toChars()); 1576 L1: 1577 Type t = e1.type.toBasetype(); 1578 //printf("e1.type = %s, var.type = %s\n", e1.type.toChars(), var.type.toChars()); 1579 1580 if (e1.op == EXP.objcClassReference) 1581 { 1582 // We already have an Objective-C class reference, just use that as 'this'. 1583 return e1; 1584 } 1585 else if (ad && ad.isClassDeclaration && ad.isClassDeclaration.classKind == ClassKind.objc && 1586 var.isFuncDeclaration && var.isFuncDeclaration.isStatic && 1587 var.isFuncDeclaration.objc.selector) 1588 { 1589 auto cls = ad.isClassDeclaration(); 1590 auto classObj = new ObjcClassReferenceExp(e1.loc, cls); 1591 classObj.type = objc.getRuntimeMetaclass(cls).getType(); 1592 return classObj; 1593 } 1594 1595 /* Access of a member which is a template parameter in dual-scope scenario 1596 * class A { inc(alias m)() { ++m; } } // `m` needs `this` of `B` 1597 * class B {int m; inc() { new A().inc!m(); } } 1598 */ 1599 if (e1.op == EXP.this_) 1600 { 1601 FuncDeclaration f = hasThis(sc); 1602 if (f && f.hasDualContext()) 1603 { 1604 if (f.followInstantiationContext(ad)) 1605 { 1606 e1 = new VarExp(loc, f.vthis); 1607 e1 = new PtrExp(loc, e1); 1608 e1 = new IndexExp(loc, e1, IntegerExp.literal!1); 1609 e1 = getThisSkipNestedFuncs(loc, sc, f.toParent2(), ad, e1, t, var); 1610 if (e1.op == EXP.error) 1611 return e1; 1612 goto L1; 1613 } 1614 } 1615 } 1616 1617 /* If e1 is not the 'this' pointer for ad 1618 */ 1619 if (ad && 1620 !(t.isTypePointer() && t.nextOf().isTypeStruct() && t.nextOf().isTypeStruct().sym == ad) && 1621 !(t.isTypeStruct() && t.isTypeStruct().sym == ad)) 1622 { 1623 ClassDeclaration cd = ad.isClassDeclaration(); 1624 ClassDeclaration tcd = t.isClassHandle(); 1625 1626 /* e1 is the right this if ad is a base class of e1 1627 */ 1628 if (!cd || !tcd || !(tcd == cd || cd.isBaseOf(tcd, null))) 1629 { 1630 /* Only classes can be inner classes with an 'outer' 1631 * member pointing to the enclosing class instance 1632 */ 1633 if (tcd && tcd.isNested()) 1634 { 1635 /* e1 is the 'this' pointer for an inner class: tcd. 1636 * Rewrite it as the 'this' pointer for the outer class. 1637 */ 1638 auto vthis = tcd.followInstantiationContext(ad) ? tcd.vthis2 : tcd.vthis; 1639 e1 = new DotVarExp(loc, e1, vthis); 1640 e1.type = vthis.type; 1641 e1.type = e1.type.addMod(t.mod); 1642 // Do not call ensureStaticLinkTo() 1643 //e1 = e1.semantic(sc); 1644 1645 // Skip up over nested functions, and get the enclosing 1646 // class type. 1647 e1 = getThisSkipNestedFuncs(loc, sc, tcd.toParentP(ad), ad, e1, t, var); 1648 if (e1.op == EXP.error) 1649 return e1; 1650 goto L1; 1651 } 1652 1653 /* Can't find a path from e1 to ad 1654 */ 1655 if (flag) 1656 return null; 1657 error(e1.loc, "`this` for `%s` needs to be type `%s` not type `%s`", var.toChars(), ad.toChars(), t.toChars()); 1658 return ErrorExp.get(); 1659 } 1660 } 1661 return e1; 1662 } 1663 1664 /* 1665 * Check whether `outerFunc` and `calledFunc` have the same `this`. 1666 * If `calledFunc` is the member of a base class of the class that contains 1667 * `outerFunc` we consider that they have the same this. 1668 * 1669 * This function is used to test whether `this` needs to be prepended to 1670 * a function call or function symbol. For example: 1671 * 1672 * struct X 1673 * { 1674 * void gun() {} 1675 * } 1676 * struct A 1677 * { 1678 * void fun() {} 1679 * void sun() 1680 * { 1681 * fun(); 1682 * X.gun(); // error 1683 * } 1684 * } 1685 * 1686 * When `fun` is called, `outerfunc` = `sun` and `calledFunc = `fun`. 1687 * `sun` is a member of `A` and `fun` is also a member of `A`, therefore 1688 * `this` can be prepended to `fun`. When `gun` is called (it will result 1689 * in an error, but that is not relevant here), which is a member of `X`, 1690 * no `this` is needed because the outer function does not have the same 1691 * `this` as `gun`. 1692 * 1693 * Returns: 1694 * `true` if outerFunc and calledFunc may use the same `this` pointer. 1695 * `false` otherwise. 1696 */ 1697 private bool haveSameThis(FuncDeclaration outerFunc, FuncDeclaration calledFunc) 1698 { 1699 // https://issues.dlang.org/show_bug.cgi?id=24013 1700 // traits(getOverloads) inserts an alias to select the overload. 1701 // When searching for the right this we need to use the aliased 1702 // overload/function, not the alias. 1703 outerFunc = outerFunc.toAliasFunc(); 1704 calledFunc = calledFunc.toAliasFunc(); 1705 1706 auto thisAd = outerFunc.isMemberLocal(); 1707 if (!thisAd) 1708 return false; 1709 1710 auto requiredAd = calledFunc.isMemberLocal(); 1711 if (!requiredAd) 1712 return false; 1713 1714 if (thisAd == requiredAd) 1715 return true; 1716 1717 // if outerfunc is the member of a nested aggregate, then let 1718 // getRightThis take care of this. 1719 if (thisAd.isNested()) 1720 return true; 1721 1722 // outerfunc is the member of a base class that contains calledFunc, 1723 // then we consider that they have the same this. 1724 auto cd = requiredAd.isClassDeclaration(); 1725 if (!cd) 1726 return false; 1727 1728 if (cd.isBaseOf2(thisAd.isClassDeclaration())) 1729 return true; 1730 1731 return false; 1732 } 1733 1734 /*************************************** 1735 * Pull out any properties. 1736 */ 1737 private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 = null, BinExp saveAtts = null) 1738 { 1739 //printf("resolvePropertiesX, e1 = %s %s, e2 = %s\n", EXPtoString(e1.op).ptr, e1.toChars(), e2 ? e2.toChars() : null); 1740 Loc loc = e1.loc; 1741 1742 OverloadSet os; 1743 Dsymbol s; 1744 Objects* tiargs; 1745 Type tthis; 1746 if (auto de = e1.isDotExp()) 1747 { 1748 if (auto oe = de.e2.isOverExp()) 1749 { 1750 tiargs = null; 1751 tthis = de.e1.type; 1752 os = oe.vars; 1753 goto Los; 1754 } 1755 } 1756 else if (e1.isOverExp()) 1757 { 1758 tiargs = null; 1759 tthis = null; 1760 os = e1.isOverExp().vars; 1761 Los: 1762 assert(os); 1763 FuncDeclaration fd = null; 1764 if (e2) 1765 { 1766 e2 = e2.expressionSemantic(sc); 1767 if (e2.op == EXP.error) 1768 return ErrorExp.get(); 1769 e2 = resolveProperties(sc, e2); 1770 1771 Expressions* a = new Expressions(); 1772 a.push(e2); 1773 1774 for (size_t i = 0; i < os.a.length; i++) 1775 { 1776 if (FuncDeclaration f = resolveFuncCall(loc, sc, os.a[i], tiargs, tthis, ArgumentList(a), FuncResolveFlag.quiet)) 1777 { 1778 if (f.errors) 1779 return ErrorExp.get(); 1780 fd = f; 1781 assert(fd.type.ty == Tfunction); 1782 } 1783 } 1784 if (fd) 1785 { 1786 Expression e = new CallExp(loc, e1, e2); 1787 return e.expressionSemantic(sc); 1788 } 1789 } 1790 { 1791 for (size_t i = 0; i < os.a.length; i++) 1792 { 1793 if (FuncDeclaration f = resolveFuncCall(loc, sc, os.a[i], tiargs, tthis, ArgumentList(), FuncResolveFlag.quiet)) 1794 { 1795 if (f.errors) 1796 return ErrorExp.get(); 1797 fd = f; 1798 assert(fd.type.ty == Tfunction); 1799 auto tf = fd.type.isTypeFunction(); 1800 if (!tf.isref && e2) 1801 { 1802 error(loc, "%s is not an lvalue", e1.toChars()); 1803 return ErrorExp.get(); 1804 } 1805 } 1806 } 1807 if (fd) 1808 { 1809 Expression e = new CallExp(loc, e1); 1810 if (e2) 1811 { 1812 e = new AssignExp(loc, e, e2); 1813 if (saveAtts) 1814 { 1815 (cast(BinExp)e).att1 = saveAtts.att1; 1816 (cast(BinExp)e).att2 = saveAtts.att2; 1817 } 1818 } 1819 return e.expressionSemantic(sc); 1820 } 1821 } 1822 if (e2) 1823 goto Leprop; 1824 } 1825 else if (auto dti = e1.isDotTemplateInstanceExp()) 1826 { 1827 if (!dti.findTempDecl(sc)) 1828 goto Leprop; 1829 if (!dti.ti.semanticTiargs(sc)) 1830 goto Leprop; 1831 tiargs = dti.ti.tiargs; 1832 tthis = dti.e1.type; 1833 if ((os = dti.ti.tempdecl.isOverloadSet()) !is null) 1834 goto Los; 1835 if ((s = dti.ti.tempdecl) !is null) 1836 goto Lfd; 1837 } 1838 else if (auto dte = e1.isDotTemplateExp()) 1839 { 1840 s = dte.td; 1841 tiargs = null; 1842 tthis = dte.e1.type; 1843 goto Lfd; 1844 } 1845 else if (auto se = e1.isScopeExp()) 1846 { 1847 s = se.sds; 1848 TemplateInstance ti = s.isTemplateInstance(); 1849 if (ti && !ti.semanticRun && ti.tempdecl) 1850 { 1851 //assert(ti.needsTypeInference(sc)); 1852 if (!ti.semanticTiargs(sc)) 1853 goto Leprop; 1854 tiargs = ti.tiargs; 1855 tthis = null; 1856 if ((os = ti.tempdecl.isOverloadSet()) !is null) 1857 goto Los; 1858 if ((s = ti.tempdecl) !is null) 1859 goto Lfd; 1860 } 1861 } 1862 else if (auto te = e1.isTemplateExp()) 1863 { 1864 s = te.td; 1865 tiargs = null; 1866 tthis = null; 1867 goto Lfd; 1868 } 1869 else if (e1.isDotVarExp() && e1.type && (e1.type.toBasetype().isTypeFunction() || e1.isDotVarExp().var.isOverDeclaration())) 1870 { 1871 DotVarExp dve = e1.isDotVarExp(); 1872 s = dve.var; 1873 tiargs = null; 1874 tthis = dve.e1.type; 1875 goto Lfd; 1876 } 1877 else if (sc && sc.flags & SCOPE.Cfile && e1.isVarExp() && !e2) 1878 { 1879 // ImportC: do not implicitly call function if no ( ) are present 1880 } 1881 else if (e1.isVarExp() && e1.type && (e1.type.toBasetype().isTypeFunction() || e1.isVarExp().var.isOverDeclaration())) 1882 { 1883 s = e1.isVarExp().var; 1884 tiargs = null; 1885 tthis = null; 1886 Lfd: 1887 assert(s); 1888 if (e2) 1889 { 1890 e2 = e2.expressionSemantic(sc); 1891 if (e2.op == EXP.error) 1892 return ErrorExp.get(); 1893 e2 = resolveProperties(sc, e2); 1894 1895 Expressions* a = new Expressions(); 1896 a.push(e2); 1897 1898 FuncDeclaration fd = resolveFuncCall(loc, sc, s, tiargs, tthis, ArgumentList(a), FuncResolveFlag.quiet); 1899 if (fd && fd.type) 1900 { 1901 if (fd.errors) 1902 return ErrorExp.get(); 1903 assert(fd.type.ty == Tfunction); 1904 Expression e = new CallExp(loc, e1, e2); 1905 return e.expressionSemantic(sc); 1906 } 1907 } 1908 { 1909 FuncDeclaration fd = resolveFuncCall(loc, sc, s, tiargs, tthis, ArgumentList(), FuncResolveFlag.quiet); 1910 if (fd && fd.type) 1911 { 1912 if (fd.errors) 1913 return ErrorExp.get(); 1914 TypeFunction tf = fd.type.isTypeFunction(); 1915 if (!e2 || tf.isref) 1916 { 1917 Expression e = new CallExp(loc, e1); 1918 if (e2) 1919 { 1920 e = new AssignExp(loc, e, e2); 1921 if (saveAtts) 1922 { 1923 (cast(BinExp)e).att1 = saveAtts.att1; 1924 (cast(BinExp)e).att2 = saveAtts.att2; 1925 } 1926 } 1927 return e.expressionSemantic(sc); 1928 } 1929 } 1930 } 1931 if (FuncDeclaration fd = s.isFuncDeclaration()) 1932 { 1933 // Keep better diagnostic message for invalid property usage of functions 1934 assert(fd.type.ty == Tfunction); 1935 Expression e = new CallExp(loc, e1, e2); 1936 return e.expressionSemantic(sc); 1937 } 1938 if (e2) 1939 goto Leprop; 1940 } 1941 if (auto ve = e1.isVarExp()) 1942 { 1943 if (auto v = ve.var.isVarDeclaration()) 1944 { 1945 if (ve.checkPurity(sc, v)) 1946 return ErrorExp.get(); 1947 } 1948 } 1949 if (e2) 1950 return null; 1951 1952 if (e1.type && !e1.isTypeExp()) // function type is not a property 1953 { 1954 /* Look for e1 being a lazy parameter; rewrite as delegate call 1955 * only if the symbol wasn't already treated as a delegate 1956 */ 1957 auto ve = e1.isVarExp(); 1958 if (ve && ve.var.storage_class & STC.lazy_ && !ve.delegateWasExtracted) 1959 { 1960 Expression e = new CallExp(loc, e1); 1961 return e.expressionSemantic(sc); 1962 } 1963 else if (e1.isDotVarExp()) 1964 { 1965 // Check for reading overlapped pointer field in @safe code. 1966 if (checkUnsafeAccess(sc, e1, true, true)) 1967 return ErrorExp.get(); 1968 } 1969 else if (auto ce = e1.isCallExp()) 1970 { 1971 // Check for reading overlapped pointer field in @safe code. 1972 if (checkUnsafeAccess(sc, ce.e1, true, true)) 1973 return ErrorExp.get(); 1974 } 1975 } 1976 1977 if (!e1.type) 1978 { 1979 error(loc, "cannot resolve type for %s", e1.toChars()); 1980 e1 = ErrorExp.get(); 1981 } 1982 return e1; 1983 1984 Leprop: 1985 error(loc, "not a property %s", e1.toChars()); 1986 return ErrorExp.get(); 1987 } 1988 1989 private bool checkRightThis(Expression e, Scope* sc) 1990 { 1991 if (e.op == EXP.error) 1992 return true; 1993 if (e.op == EXP.variable && e.type.ty != Terror) 1994 { 1995 VarExp ve = cast(VarExp)e; 1996 if (isNeedThisScope(sc, ve.var)) 1997 { 1998 //printf("checkRightThis sc.intypeof = %d, ad = %p, func = %p, fdthis = %p\n", 1999 // sc.intypeof, sc.getStructClassScope(), func, fdthis); 2000 auto t = ve.var.isThis(); 2001 assert(t); 2002 error(e.loc, "accessing non-static variable `%s` requires an instance of `%s`", ve.var.toChars(), t.toChars()); 2003 return true; 2004 } 2005 } 2006 return false; 2007 } 2008 2009 extern (C++) Expression resolveProperties(Scope* sc, Expression e) 2010 { 2011 //printf("resolveProperties(%s)\n", e.toChars()); 2012 e = resolvePropertiesX(sc, e); 2013 if (e.checkRightThis(sc)) 2014 return ErrorExp.get(); 2015 return e; 2016 } 2017 2018 /**************************************** 2019 * The common type is determined by applying ?: to each pair. 2020 * Output: 2021 * exps[] properties resolved, implicitly cast to common type, rewritten in place 2022 * Returns: 2023 * The common type, or `null` if an error has occured 2024 */ 2025 private Type arrayExpressionToCommonType(Scope* sc, ref Expressions exps) 2026 { 2027 /* Still have a problem with: 2028 * ubyte[][] = [ cast(ubyte[])"hello", [1]]; 2029 * which works if the array literal is initialized top down with the ubyte[][] 2030 * type, but fails with this function doing bottom up typing. 2031 */ 2032 2033 //printf("arrayExpressionToCommonType()\n"); 2034 scope IntegerExp integerexp = IntegerExp.literal!0; 2035 scope CondExp condexp = new CondExp(Loc.initial, integerexp, null, null); 2036 2037 Type t0 = null; 2038 Expression e0 = null; 2039 bool foundType; 2040 2041 for (size_t i = 0; i < exps.length; i++) 2042 { 2043 Expression e = exps[i]; 2044 if (!e) 2045 continue; 2046 2047 e = resolveProperties(sc, e); 2048 if (!e.type) 2049 { 2050 error(e.loc, "`%s` has no value", e.toChars()); 2051 t0 = Type.terror; 2052 continue; 2053 } 2054 if (e.op == EXP.type) 2055 { 2056 foundType = true; // do not break immediately, there might be more errors 2057 e.checkValue(); // report an error "type T has no value" 2058 t0 = Type.terror; 2059 continue; 2060 } 2061 if (e.type.ty == Tvoid) 2062 { 2063 // void expressions do not concur to the determination of the common 2064 // type. 2065 continue; 2066 } 2067 if (checkNonAssignmentArrayOp(e)) 2068 { 2069 t0 = Type.terror; 2070 continue; 2071 } 2072 2073 e = doCopyOrMove(sc, e); 2074 2075 if (!foundType && t0 && !t0.equals(e.type)) 2076 { 2077 /* This applies ?: to merge the types. It's backwards; 2078 * ?: should call this function to merge types. 2079 */ 2080 condexp.type = null; 2081 condexp.e1 = e0; 2082 condexp.e2 = e; 2083 condexp.loc = e.loc; 2084 Expression ex = condexp.expressionSemantic(sc); 2085 if (ex.op == EXP.error) 2086 e = ex; 2087 else 2088 { 2089 // Convert to common type 2090 exps[i] = condexp.e1.castTo(sc, condexp.type); 2091 e = condexp.e2.castTo(sc, condexp.type); 2092 } 2093 } 2094 e0 = e; 2095 t0 = e.type; 2096 if (e.op != EXP.error) 2097 exps[i] = e; 2098 } 2099 2100 // [] is typed as void[] 2101 if (!t0) 2102 return Type.tvoid; 2103 2104 // It's an error, don't do the cast 2105 if (t0.ty == Terror) 2106 return null; 2107 2108 for (size_t i = 0; i < exps.length; i++) 2109 { 2110 Expression e = exps[i]; 2111 if (!e) 2112 continue; 2113 2114 e = e.implicitCastTo(sc, t0); 2115 if (e.op == EXP.error) 2116 { 2117 /* https://issues.dlang.org/show_bug.cgi?id=13024 2118 * a workaround for the bug in typeMerge - 2119 * it should paint e1 and e2 by deduced common type, 2120 * but doesn't in this particular case. 2121 */ 2122 return null; 2123 } 2124 exps[i] = e; 2125 } 2126 return t0; 2127 } 2128 2129 private Expression opAssignToOp(const ref Loc loc, EXP op, Expression e1, Expression e2) @safe 2130 { 2131 Expression e; 2132 switch (op) 2133 { 2134 case EXP.addAssign: 2135 e = new AddExp(loc, e1, e2); 2136 break; 2137 2138 case EXP.minAssign: 2139 e = new MinExp(loc, e1, e2); 2140 break; 2141 2142 case EXP.mulAssign: 2143 e = new MulExp(loc, e1, e2); 2144 break; 2145 2146 case EXP.divAssign: 2147 e = new DivExp(loc, e1, e2); 2148 break; 2149 2150 case EXP.modAssign: 2151 e = new ModExp(loc, e1, e2); 2152 break; 2153 2154 case EXP.andAssign: 2155 e = new AndExp(loc, e1, e2); 2156 break; 2157 2158 case EXP.orAssign: 2159 e = new OrExp(loc, e1, e2); 2160 break; 2161 2162 case EXP.xorAssign: 2163 e = new XorExp(loc, e1, e2); 2164 break; 2165 2166 case EXP.leftShiftAssign: 2167 e = new ShlExp(loc, e1, e2); 2168 break; 2169 2170 case EXP.rightShiftAssign: 2171 e = new ShrExp(loc, e1, e2); 2172 break; 2173 2174 case EXP.unsignedRightShiftAssign: 2175 e = new UshrExp(loc, e1, e2); 2176 break; 2177 2178 default: 2179 assert(0); 2180 } 2181 return e; 2182 } 2183 2184 /********************* 2185 * Rewrite: 2186 * array.length op= e2 2187 */ 2188 private Expression rewriteOpAssign(BinExp exp) 2189 { 2190 ArrayLengthExp ale = exp.e1.isArrayLengthExp(); 2191 if (ale.e1.isVarExp()) 2192 { 2193 // array.length = array.length op e2 2194 Expression e = opAssignToOp(exp.loc, exp.op, ale, exp.e2); 2195 e = new AssignExp(exp.loc, ale.syntaxCopy(), e); 2196 return e; 2197 } 2198 else 2199 { 2200 // (ref tmp = array;), tmp.length = tmp.length op e2 2201 auto tmp = copyToTemp(STC.ref_, "__arraylength", ale.e1); 2202 Expression e1 = new ArrayLengthExp(ale.loc, new VarExp(ale.loc, tmp)); 2203 Expression elvalue = e1.syntaxCopy(); 2204 Expression e = opAssignToOp(exp.loc, exp.op, e1, exp.e2); 2205 e = new AssignExp(exp.loc, elvalue, e); 2206 e = new CommaExp(exp.loc, new DeclarationExp(ale.loc, tmp), e); 2207 return e; 2208 } 2209 } 2210 2211 /**************************************** 2212 * Preprocess arguments to function. 2213 * 2214 * Tuples in argumentList get expanded, properties resolved, rewritten in place 2215 * 2216 * Params: 2217 * sc = scope 2218 * argumentList = arguments to function 2219 * reportErrors = whether or not to report errors here. Some callers are not 2220 * checking actual function params, so they'll do their own error reporting 2221 * Returns: 2222 * `true` when a semantic error occurred 2223 */ 2224 private bool preFunctionParameters(Scope* sc, ArgumentList argumentList, const bool reportErrors = true) 2225 { 2226 Expressions* exps = argumentList.arguments; 2227 bool err = false; 2228 if (exps) 2229 { 2230 expandTuples(exps, argumentList.names); 2231 2232 for (size_t i = 0; i < exps.length; i++) 2233 { 2234 Expression arg = (*exps)[i]; 2235 arg = resolveProperties(sc, arg); 2236 arg = arg.arrayFuncConv(sc); 2237 if (arg.op == EXP.type) 2238 { 2239 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684 2240 arg = resolveAliasThis(sc, arg); 2241 2242 if (arg.op == EXP.type) 2243 { 2244 if (reportErrors) 2245 { 2246 error(arg.loc, "cannot pass type `%s` as a function argument", arg.toChars()); 2247 arg = ErrorExp.get(); 2248 } 2249 err = true; 2250 } 2251 } 2252 else if (arg.type.toBasetype().ty == Tfunction) 2253 { 2254 if (reportErrors) 2255 { 2256 error(arg.loc, "cannot pass function `%s` as a function argument", arg.toChars()); 2257 arg = ErrorExp.get(); 2258 } 2259 err = true; 2260 } 2261 else if (checkNonAssignmentArrayOp(arg)) 2262 { 2263 arg = ErrorExp.get(); 2264 err = true; 2265 } 2266 (*exps)[i] = arg; 2267 } 2268 } 2269 return err; 2270 } 2271 2272 /******************************************** 2273 * Issue an error if default construction is disabled for type t. 2274 * Default construction is required for arrays and 'out' parameters. 2275 * Returns: 2276 * true an error was issued 2277 */ 2278 private bool checkDefCtor(Loc loc, Type t) 2279 { 2280 if (auto ts = t.baseElemOf().isTypeStruct()) 2281 { 2282 StructDeclaration sd = ts.sym; 2283 if (sd.noDefaultCtor) 2284 { 2285 .error(loc, "%s `%s` default construction is disabled", sd.kind, sd.toPrettyChars); 2286 return true; 2287 } 2288 } 2289 return false; 2290 } 2291 2292 /**************************************** 2293 * Now that we know the exact type of the function we're calling, 2294 * the arguments[] need to be adjusted: 2295 * 1. implicitly convert argument to the corresponding parameter type 2296 * 2. add default arguments for any missing arguments 2297 * 3. do default promotions on arguments corresponding to ... 2298 * 4. add hidden _arguments[] argument 2299 * 5. call copy constructor for struct value arguments 2300 * Params: 2301 * loc = location of function call 2302 * sc = context 2303 * tf = type of the function 2304 * ethis = `this` argument, `null` if none or not known 2305 * tthis = type of `this` argument, `null` if no `this` argument 2306 * argumentsList = array of actual arguments to function call 2307 * fd = the function being called, `null` if called indirectly 2308 * prettype = set to return type of function 2309 * peprefix = set to expression to execute before `arguments[]` are evaluated, `null` if none 2310 * Returns: 2311 * true errors happened 2312 */ 2313 private bool functionParameters(const ref Loc loc, Scope* sc, 2314 TypeFunction tf, Expression ethis, Type tthis, ArgumentList argumentList, FuncDeclaration fd, 2315 Type* prettype, Expression* peprefix) 2316 { 2317 Expressions* arguments = argumentList.arguments; 2318 //printf("functionParameters() %s\n", fd ? fd.toChars() : ""); 2319 assert(arguments); 2320 assert(fd || tf.next); 2321 const size_t nparams = tf.parameterList.length; 2322 const olderrors = global.errors; 2323 bool err = false; 2324 Expression eprefix = null; 2325 *peprefix = null; 2326 2327 if (argumentList.names) 2328 { 2329 const(char)* msg = null; 2330 auto resolvedArgs = tf.resolveNamedArgs(argumentList, &msg); 2331 if (!resolvedArgs) 2332 { 2333 // while errors are usually already caught by `tf.callMatch`, 2334 // this can happen when calling `typeof(freefunc)` 2335 if (msg) 2336 error(loc, "%s", msg); 2337 return true; 2338 } 2339 // note: the argument list should be mutated with named arguments / default arguments, 2340 // so we can't simply change the pointer like `arguments = resolvedArgs;` 2341 arguments.setDim(0); 2342 arguments.pushSlice((*resolvedArgs)[]); 2343 } 2344 size_t nargs = arguments ? arguments.length : 0; 2345 2346 if (nargs > nparams && tf.parameterList.varargs == VarArg.none) 2347 { 2348 error(loc, "expected %llu arguments, not %llu for non-variadic function type `%s`", cast(ulong)nparams, cast(ulong)nargs, tf.toChars()); 2349 return true; 2350 } 2351 2352 // If inferring return type, and semantic3() needs to be run if not already run 2353 if (!tf.next && fd.inferRetType) 2354 { 2355 fd.functionSemantic(); 2356 } 2357 else if (fd && fd.parent) 2358 { 2359 TemplateInstance ti = fd.parent.isTemplateInstance(); 2360 if (ti && ti.tempdecl) 2361 { 2362 fd.functionSemantic3(); 2363 } 2364 } 2365 2366 /* If calling a pragma(inline, true) function, 2367 * set flag to later scan for inlines. 2368 */ 2369 if (fd && fd.inlining == PINLINE.always) 2370 { 2371 if (sc._module) 2372 sc._module.hasAlwaysInlines = true; 2373 if (sc.func) 2374 sc.func.hasAlwaysInlines = true; 2375 } 2376 2377 const isCtorCall = fd && fd.needThis() && fd.isCtorDeclaration(); 2378 2379 const size_t n = (nargs > nparams) ? nargs : nparams; // n = max(nargs, nparams) 2380 2381 /* If the function return type has wildcards in it, we'll need to figure out the actual type 2382 * based on the actual argument types. 2383 * Start with the `this` argument, later on merge into wildmatch the mod bits of the rest 2384 * of the arguments. 2385 */ 2386 MOD wildmatch = (tthis && !isCtorCall) ? tthis.Type.deduceWild(tf, false) : 0; 2387 2388 bool done = false; 2389 foreach (const i; 0 .. n) 2390 { 2391 Expression arg = (i < nargs) ? (*arguments)[i] : null; 2392 2393 if (i < nparams) 2394 { 2395 bool errorArgs() 2396 { 2397 error(loc, "expected %llu function arguments, not %llu", cast(ulong)nparams, cast(ulong)nargs); 2398 return true; 2399 } 2400 2401 Parameter p = tf.parameterList[i]; 2402 2403 if (!arg) 2404 { 2405 if (!p.defaultArg) 2406 { 2407 if (tf.parameterList.varargs == VarArg.typesafe && i + 1 == nparams) 2408 goto L2; 2409 return errorArgs(); 2410 } 2411 arg = p.defaultArg; 2412 if (!arg.type) 2413 arg = arg.expressionSemantic(sc); 2414 arg = inlineCopy(arg, sc); 2415 // __FILE__, __LINE__, __MODULE__, __FUNCTION__, and __PRETTY_FUNCTION__ 2416 arg = arg.resolveLoc(loc, sc); 2417 if (i >= nargs) 2418 { 2419 arguments.push(arg); 2420 nargs++; 2421 } 2422 else 2423 (*arguments)[i] = arg; 2424 } 2425 else 2426 { 2427 if (arg.isDefaultInitExp()) 2428 { 2429 arg = arg.resolveLoc(loc, sc); 2430 (*arguments)[i] = arg; 2431 } 2432 } 2433 2434 2435 if (tf.parameterList.varargs == VarArg.typesafe && i + 1 == nparams) // https://dlang.org/spec/function.html#variadic 2436 { 2437 //printf("\t\tvarargs == 2, p.type = '%s'\n", p.type.toChars()); 2438 { 2439 MATCH m; 2440 if ((m = arg.implicitConvTo(p.type)) > MATCH.nomatch) 2441 { 2442 if (p.type.nextOf() && arg.implicitConvTo(p.type.nextOf()) >= m) 2443 goto L2; 2444 else if (nargs != nparams) 2445 return errorArgs(); 2446 goto L1; 2447 } 2448 } 2449 L2: 2450 Type tb = p.type.toBasetype(); 2451 switch (tb.ty) 2452 { 2453 case Tsarray: 2454 case Tarray: 2455 { 2456 /* Create a static array variable v of type arg.type: 2457 * T[dim] __arrayArg = [ arguments[i], ..., arguments[nargs-1] ]; 2458 * 2459 * The array literal in the initializer of the hidden variable 2460 * is now optimized. 2461 * https://issues.dlang.org/show_bug.cgi?id=2356 2462 */ 2463 Type tbn = (cast(TypeArray)tb).next; // array element type 2464 Type tret = p.isLazyArray(); 2465 2466 auto elements = new Expressions(nargs - i); 2467 foreach (u; 0 .. elements.length) 2468 { 2469 Expression a = (*arguments)[i + u]; 2470 if (tret && a.implicitConvTo(tret)) 2471 { 2472 // p is a lazy array of delegates, tret is return type of the delegates 2473 a = a.implicitCastTo(sc, tret) 2474 .optimize(WANTvalue) 2475 .toDelegate(tret, sc); 2476 } 2477 else 2478 a = a.implicitCastTo(sc, tbn); 2479 a = a.addDtorHook(sc); 2480 (*elements)[u] = a; 2481 } 2482 // https://issues.dlang.org/show_bug.cgi?id=14395 2483 // Convert to a static array literal, or its slice. 2484 arg = new ArrayLiteralExp(loc, tbn.sarrayOf(nargs - i), elements); 2485 if (tb.ty == Tarray) 2486 { 2487 arg = new SliceExp(loc, arg, null, null); 2488 arg.type = p.type; 2489 } 2490 break; 2491 } 2492 case Tclass: 2493 { 2494 /* Set arg to be: 2495 * new Tclass(arg0, arg1, ..., argn) 2496 */ 2497 auto args = new Expressions(nargs - i); 2498 foreach (u; i .. nargs) 2499 (*args)[u - i] = (*arguments)[u]; 2500 arg = new NewExp(loc, null, p.type, args); 2501 break; 2502 } 2503 default: 2504 if (!arg) 2505 { 2506 error(loc, "not enough arguments"); 2507 return true; 2508 } 2509 break; 2510 } 2511 arg = arg.expressionSemantic(sc); 2512 //printf("\targ = '%s'\n", arg.toChars()); 2513 arguments.setDim(i + 1); 2514 (*arguments)[i] = arg; 2515 nargs = i + 1; 2516 done = true; 2517 } 2518 2519 L1: 2520 if (!(p.isLazy() && p.type.ty == Tvoid)) 2521 { 2522 if (ubyte wm = arg.type.deduceWild(p.type, p.isReference())) 2523 { 2524 wildmatch = wildmatch ? MODmerge(wildmatch, wm) : wm; 2525 //printf("[%d] p = %s, a = %s, wm = %d, wildmatch = %d\n", i, p.type.toChars(), arg.type.toChars(), wm, wildmatch); 2526 } 2527 } 2528 } 2529 if (done) 2530 break; 2531 } 2532 if ((wildmatch == MODFlags.mutable || wildmatch == MODFlags.immutable_) && 2533 tf.next && tf.next.hasWild() && 2534 (tf.isref || !tf.next.implicitConvTo(tf.next.immutableOf()))) 2535 { 2536 bool errorInout(MOD wildmatch) 2537 { 2538 const(char)* s = wildmatch == MODFlags.mutable ? "mutable" : MODtoChars(wildmatch); 2539 error(loc, "modify `inout` to `%s` is not allowed inside `inout` function", s); 2540 return true; 2541 } 2542 2543 if (fd) 2544 { 2545 /* If the called function may return the reference to 2546 * outer inout data, it should be rejected. 2547 * 2548 * void foo(ref inout(int) x) { 2549 * ref inout(int) bar(inout(int)) { return x; } 2550 * struct S { 2551 * ref inout(int) bar() inout { return x; } 2552 * ref inout(int) baz(alias a)() inout { return x; } 2553 * } 2554 * bar(int.init) = 1; // bad! 2555 * S().bar() = 1; // bad! 2556 * } 2557 * void test() { 2558 * int a; 2559 * auto s = foo(a); 2560 * s.baz!a() = 1; // bad! 2561 * } 2562 * 2563 */ 2564 bool checkEnclosingWild(Dsymbol s) 2565 { 2566 bool checkWild(Dsymbol s) 2567 { 2568 if (!s) 2569 return false; 2570 if (auto ad = s.isAggregateDeclaration()) 2571 { 2572 if (ad.isNested()) 2573 return checkEnclosingWild(s); 2574 } 2575 else if (auto ff = s.isFuncDeclaration()) 2576 { 2577 if (ff.type.isTypeFunction().iswild) 2578 return errorInout(wildmatch); 2579 2580 if (ff.isNested() || ff.isThis()) 2581 return checkEnclosingWild(s); 2582 } 2583 return false; 2584 } 2585 2586 Dsymbol ctx0 = s.toParent2(); 2587 Dsymbol ctx1 = s.toParentLocal(); 2588 if (checkWild(ctx0)) 2589 return true; 2590 if (ctx0 != ctx1) 2591 return checkWild(ctx1); 2592 return false; 2593 } 2594 if ((fd.isThis() || fd.isNested()) && checkEnclosingWild(fd)) 2595 return true; 2596 } 2597 else if (tf.isWild()) 2598 return errorInout(wildmatch); 2599 } 2600 2601 Expression firstArg = null; 2602 final switch (returnParamDest(tf, tthis)) 2603 { 2604 case ReturnParamDest.returnVal: 2605 break; 2606 case ReturnParamDest.firstArg: 2607 firstArg = nargs > 0 ? (*arguments)[0] : null; 2608 break; 2609 case ReturnParamDest.this_: 2610 firstArg = ethis; 2611 break; 2612 } 2613 2614 assert(nargs >= nparams); 2615 foreach (const i, arg; (*arguments)[0 .. nargs]) 2616 { 2617 assert(arg); 2618 if (i < nparams) 2619 { 2620 Parameter p = tf.parameterList[i]; 2621 Type targ = arg.type; // keep original type for isCopyable() because alias this 2622 // resolution may hide an uncopyable type 2623 2624 if (!(p.isLazy() && p.type.ty == Tvoid)) 2625 { 2626 Type tprm = p.type.hasWild() 2627 ? p.type.substWildTo(wildmatch) 2628 : p.type; 2629 2630 const hasCopyCtor = arg.type.isTypeStruct() && arg.type.isTypeStruct().sym.hasCopyCtor; 2631 const typesMatch = arg.type.mutableOf().unSharedOf().equals(tprm.mutableOf().unSharedOf()); 2632 if (!((hasCopyCtor && typesMatch) || tprm.equals(arg.type))) 2633 { 2634 //printf("arg.type = %s, p.type = %s\n", arg.type.toChars(), p.type.toChars()); 2635 arg = arg.implicitCastTo(sc, tprm); 2636 arg = arg.optimize(WANTvalue, p.isReference()); 2637 } 2638 } 2639 2640 // Support passing rvalue to `in` parameters 2641 if ((p.storageClass & (STC.in_ | STC.ref_)) == (STC.in_ | STC.ref_)) 2642 { 2643 if (!arg.isLvalue()) 2644 { 2645 auto v = copyToTemp(STC.exptemp, "__rvalue", arg); 2646 Expression ev = new DeclarationExp(arg.loc, v); 2647 ev = new CommaExp(arg.loc, ev, new VarExp(arg.loc, v)); 2648 arg = ev.expressionSemantic(sc); 2649 } 2650 arg = arg.toLvalue(sc, arg); 2651 2652 // Look for mutable misaligned pointer, etc., in @safe mode 2653 err |= checkUnsafeAccess(sc, arg, false, true); 2654 } 2655 else if (p.storageClass & STC.ref_) 2656 { 2657 if (global.params.rvalueRefParam == FeatureState.enabled && 2658 !arg.isLvalue() && 2659 targ.isCopyable()) 2660 { /* allow rvalues to be passed to ref parameters by copying 2661 * them to a temp, then pass the temp as the argument 2662 */ 2663 auto v = copyToTemp(0, "__rvalue", arg); 2664 Expression ev = new DeclarationExp(arg.loc, v); 2665 ev = new CommaExp(arg.loc, ev, new VarExp(arg.loc, v)); 2666 arg = ev.expressionSemantic(sc); 2667 } 2668 arg = arg.toLvalue(sc, arg); 2669 2670 // Look for mutable misaligned pointer, etc., in @safe mode 2671 err |= checkUnsafeAccess(sc, arg, false, true); 2672 } 2673 else if (p.storageClass & STC.out_) 2674 { 2675 Type t = arg.type; 2676 if (!t.isMutable() || !t.isAssignable()) // check blit assignable 2677 { 2678 error(arg.loc, "cannot modify struct `%s` with immutable members", arg.toChars()); 2679 err = true; 2680 } 2681 else 2682 { 2683 // Look for misaligned pointer, etc., in @safe mode 2684 err |= checkUnsafeAccess(sc, arg, false, true); 2685 err |= checkDefCtor(arg.loc, t); // t must be default constructible 2686 } 2687 arg = arg.toLvalue(sc, arg); 2688 } 2689 else if (p.isLazy()) 2690 { 2691 // Convert lazy argument to a delegate 2692 auto t = (p.type.ty == Tvoid) ? p.type : arg.type; 2693 arg = toDelegate(arg, t, sc); 2694 } 2695 //printf("arg: %s\n", arg.toChars()); 2696 //printf("type: %s\n", arg.type.toChars()); 2697 //printf("param: %s\n", p.toChars()); 2698 2699 const indirect = (fd is null) || (fd.isVirtual() && !fd.isFinal()); 2700 const pStc = tf.parameterStorageClass(tthis, p, fd ? &fd.outerVars : null, indirect); 2701 2702 if (firstArg && (pStc & STC.return_)) 2703 { 2704 /* Argument value can be assigned to firstArg. 2705 * Check arg to see if it matters. 2706 */ 2707 err |= checkParamArgumentReturn(sc, firstArg, arg, p, false); 2708 } 2709 // Allow 'lazy' to imply 'scope' - lazy parameters can be passed along 2710 // as lazy parameters to the next function, but that isn't escaping. 2711 // The arguments of `_d_arraycatnTX` are already handled in 2712 // expressionsem.d, via `checkNewEscape`. Without `-dip1000`, the 2713 // check does not return an error, so the lowering of `a ~ b` to 2714 // `_d_arraycatnTX(a, b)` still occurs. 2715 else if (!(pStc & STC.lazy_) && (!fd || fd.ident != Id._d_arraycatnTX)) 2716 { 2717 /* Argument value can escape from the called function. 2718 * Check arg to see if it matters. 2719 */ 2720 VarDeclaration vPar = fd ? (fd.parameters ? (*fd.parameters)[i] : null) : null; 2721 err |= checkParamArgumentEscape(sc, fd, p.ident, vPar, cast(STC) pStc, arg, false, false); 2722 } 2723 2724 // Turning heap allocations into stack allocations is dangerous without dip1000, since `scope` inference 2725 // may be unreliable when scope violations only manifest as deprecation warnings. 2726 // However, existing `@nogc` code may rely on it, so still do it when the parameter is explicitly marked `scope` 2727 const explicitScope = p.isLazy() || 2728 ((p.storageClass & STC.scope_) && !(p.storageClass & STC.scopeinferred)); 2729 if ((pStc & (STC.scope_ | STC.lazy_)) && 2730 ((global.params.useDIP1000 == FeatureState.enabled) || explicitScope) && 2731 !(pStc & STC.return_)) 2732 { 2733 /* Argument value cannot escape from the called function. 2734 */ 2735 Expression a = arg; 2736 if (auto ce = a.isCastExp()) 2737 a = ce.e1; 2738 2739 ArrayLiteralExp ale; 2740 if (p.type.toBasetype().ty == Tarray && 2741 (ale = a.isArrayLiteralExp()) !is null && ale.elements && ale.elements.length > 0) 2742 { 2743 // allocate the array literal as temporary static array on the stack 2744 ale.type = ale.type.nextOf().sarrayOf(ale.elements.length); 2745 auto tmp = copyToTemp(0, "__arrayliteral_on_stack", ale); 2746 tmp.storage_class |= STC.exptemp; 2747 auto declareTmp = new DeclarationExp(ale.loc, tmp); 2748 auto castToSlice = new CastExp(ale.loc, new VarExp(ale.loc, tmp), 2749 p.type.substWildTo(MODFlags.mutable)); 2750 arg = CommaExp.combine(declareTmp, castToSlice); 2751 arg = arg.expressionSemantic(sc); 2752 } 2753 else if (auto fe = a.isFuncExp()) 2754 { 2755 /* Function literals can only appear once, so if this 2756 * appearance was scoped, there cannot be any others. 2757 */ 2758 fe.fd.tookAddressOf = 0; 2759 } 2760 else if (auto de = a.isDelegateExp()) 2761 { 2762 /* For passing a delegate to a scoped parameter, 2763 * this doesn't count as taking the address of it. 2764 * We only worry about 'escaping' references to the function. 2765 */ 2766 if (auto ve = de.e1.isVarExp()) 2767 { 2768 if (auto f = ve.var.isFuncDeclaration()) 2769 { 2770 if (f.tookAddressOf) 2771 --f.tookAddressOf; 2772 //printf("--tookAddressOf = %d\n", f.tookAddressOf); 2773 } 2774 } 2775 } 2776 } 2777 if (!p.isReference()) 2778 err |= arg.checkSharedAccess(sc); 2779 2780 arg = arg.optimize(WANTvalue, p.isReference()); 2781 } 2782 else 2783 { 2784 // These will be the trailing ... arguments 2785 // If not D linkage, do promotions 2786 if (tf.linkage != LINK.d) 2787 { 2788 // Promote bytes, words, etc., to ints 2789 arg = integralPromotions(arg, sc); 2790 2791 // Promote floats to doubles 2792 switch (arg.type.ty) 2793 { 2794 case Tfloat32: 2795 arg = arg.castTo(sc, Type.tfloat64); 2796 break; 2797 2798 case Timaginary32: 2799 arg = arg.castTo(sc, Type.timaginary64); 2800 break; 2801 2802 default: 2803 break; 2804 } 2805 if (tf.parameterList.varargs == VarArg.variadic || 2806 tf.parameterList.varargs == VarArg.KRvariadic) 2807 { 2808 const(char)* p = tf.linkage == LINK.c ? "extern(C)" : "extern(C++)"; 2809 if (arg.type.ty == Tarray) 2810 { 2811 error(arg.loc, "cannot pass dynamic arrays to `%s` vararg functions", p); 2812 err = true; 2813 } 2814 if (arg.type.ty == Tsarray) 2815 { 2816 error(arg.loc, "cannot pass static arrays to `%s` vararg functions", p); 2817 err = true; 2818 } 2819 } 2820 } 2821 2822 // Do not allow types that need destructors or copy constructors. 2823 if (arg.type.needsDestruction()) 2824 { 2825 error(arg.loc, "cannot pass types that need destruction as variadic arguments"); 2826 err = true; 2827 } 2828 if (arg.type.needsCopyOrPostblit()) 2829 { 2830 error(arg.loc, "cannot pass types with postblits or copy constructors as variadic arguments"); 2831 err = true; 2832 } 2833 2834 // Convert static arrays to dynamic arrays 2835 // BUG: I don't think this is right for D2 2836 Type tb = arg.type.toBasetype(); 2837 if (auto ts = tb.isTypeSArray()) 2838 { 2839 Type ta = ts.next.arrayOf(); 2840 if (ts.size(arg.loc) == 0) 2841 arg = new NullExp(arg.loc, ta); 2842 else 2843 arg = arg.castTo(sc, ta); 2844 } 2845 if (tb.ty == Tstruct) 2846 { 2847 //arg = callCpCtor(sc, arg); 2848 } 2849 // Give error for overloaded function addresses 2850 if (auto se = arg.isSymOffExp()) 2851 { 2852 if (se.hasOverloads && !se.var.isFuncDeclaration().isUnique()) 2853 { 2854 error(arg.loc, "function `%s` is overloaded", arg.toChars()); 2855 err = true; 2856 } 2857 } 2858 err |= arg.checkValue(); 2859 err |= arg.checkSharedAccess(sc); 2860 err |= checkParamArgumentEscape(sc, fd, Id.dotdotdot, null, cast(STC) tf.parameterList.stc, arg, false, false); 2861 arg = arg.optimize(WANTvalue); 2862 } 2863 (*arguments)[i] = arg; 2864 } 2865 2866 /* If calling C scanf(), printf(), or any variants, check the format string against the arguments 2867 */ 2868 const isVa_list = tf.parameterList.varargs == VarArg.none; 2869 if (fd && fd.printf) 2870 { 2871 if (auto se = (*arguments)[nparams - 1 - isVa_list].isStringExp()) 2872 { 2873 checkPrintfFormat(se.loc, se.peekString(), (*arguments)[nparams .. nargs], isVa_list, sc.eSink); 2874 } 2875 } 2876 else if (fd && fd.scanf) 2877 { 2878 if (auto se = (*arguments)[nparams - 1 - isVa_list].isStringExp()) 2879 { 2880 checkScanfFormat(se.loc, se.peekString(), (*arguments)[nparams .. nargs], isVa_list, sc.eSink); 2881 } 2882 } 2883 else 2884 { 2885 // TODO: not checking the "v" functions yet (for those, check format string only, not args) 2886 } 2887 2888 /* Remaining problems: 2889 * 1. value structs (or static arrays of them) that need to be copy constructed 2890 * 2. value structs (or static arrays of them) that have destructors, and subsequent arguments that may throw before the 2891 * function gets called. 2892 * 3. value structs need to be destructed after the function call for platforms where the caller destroys the arguments. 2893 * Those are handled by doing the argument construction in 'eprefix' so that if a later argument throws, they are cleaned 2894 * up properly. Pushing arguments on the stack then cannot fail. 2895 */ 2896 { 2897 /* Does Problem (3) apply? 2898 */ 2899 const bool callerDestroysArgs = !target.isCalleeDestroyingArgs(tf); 2900 2901 /* Compute indices of last throwing argument and first arg needing destruction. 2902 * Used to not set up destructors unless an arg needs destruction on a throw 2903 * in a later argument. 2904 */ 2905 ptrdiff_t lastthrow = -1; // last argument that may throw 2906 ptrdiff_t firstdtor = -1; // first argument that needs destruction 2907 ptrdiff_t lastdtor = -1; // last argument that needs destruction 2908 for (ptrdiff_t i = 0; i != nargs; i++) 2909 { 2910 Expression arg = (*arguments)[i]; 2911 if (canThrow(arg, sc.func, null)) 2912 lastthrow = i; 2913 if (arg.type.needsDestruction()) 2914 { 2915 Parameter p = (i >= nparams ? null : tf.parameterList[i]); 2916 if (!(p && (p.isLazy() || p.isReference()))) 2917 { 2918 if (firstdtor == -1) 2919 firstdtor = i; 2920 lastdtor = i; 2921 } 2922 } 2923 } 2924 2925 /* Do we need 'eprefix' for problems 2 or 3? 2926 */ 2927 const bool needsPrefix = callerDestroysArgs 2928 ? firstdtor >= 0 // true if any argument needs destruction 2929 : firstdtor >= 0 && lastthrow >= 0 && 2930 (lastthrow - firstdtor) > 0; // last throw after first destruction 2931 const ptrdiff_t lastPrefix = callerDestroysArgs 2932 ? lastdtor // up to last argument requiring destruction 2933 : lastthrow; // up to last potentially throwing argument 2934 2935 /* Problem 3: initialize 'eprefix' by declaring the gate 2936 */ 2937 VarDeclaration gate; 2938 if (needsPrefix && !callerDestroysArgs) 2939 { 2940 // eprefix => bool __gate [= false] 2941 Identifier idtmp = Identifier.generateId("__gate"); 2942 gate = new VarDeclaration(loc, Type.tbool, idtmp, null); 2943 gate.storage_class |= STC.temp | STC.ctfe | STC.volatile_; 2944 gate.dsymbolSemantic(sc); 2945 2946 auto ae = new DeclarationExp(loc, gate); 2947 eprefix = ae.expressionSemantic(sc); 2948 } 2949 2950 for (ptrdiff_t i = 0; i != nargs; i++) 2951 { 2952 Expression arg = (*arguments)[i]; 2953 //printf("arg[%d]: %s\n", cast(int)i, arg.toChars()); 2954 2955 Parameter parameter = (i >= nparams ? null : tf.parameterList[i]); 2956 const bool isRef = parameter && parameter.isReference(); 2957 const bool isLazy = parameter && parameter.isLazy(); 2958 2959 /* Skip lazy parameters 2960 */ 2961 if (isLazy) 2962 continue; 2963 2964 /* Do we have 'eprefix' and aren't past 'lastPrefix' yet? 2965 * Then declare a temporary variable for this arg and append that declaration 2966 * to 'eprefix', which will implicitly take care of potential problem 1) for 2967 * this arg. 2968 * 'eprefix' will therefore finally contain all args up to and including 'lastPrefix', 2969 * excluding all lazy parameters. 2970 */ 2971 if (needsPrefix && (lastPrefix - i) >= 0) 2972 { 2973 const bool needsDtor = !isRef && arg.type.needsDestruction() && 2974 // Problem 3: last throwing arg doesn't require dtor patching 2975 (callerDestroysArgs || i != lastPrefix); 2976 2977 /* Declare temporary 'auto __pfx = arg' (needsDtor) or 'auto __pfy = arg' (!needsDtor) 2978 */ 2979 auto tmp = copyToTemp( 2980 (parameter ? parameter.storageClass : tf.parameterList.stc) & (STC.scope_), 2981 needsDtor ? "__pfx" : "__pfy", 2982 !isRef ? arg : arg.addressOf()); 2983 tmp.dsymbolSemantic(sc); 2984 2985 if (callerDestroysArgs) 2986 { 2987 /* Problem 4: Normal temporary, destructed after the call 2988 */ 2989 if (needsDtor) 2990 tmp.isArgDtorVar = true; // mark it so that the backend passes it by ref to the function being called 2991 } 2992 else 2993 { 2994 /* Problem 2: Modify the destructor so it only runs if gate==false, 2995 * i.e., only if there was a throw while constructing the args 2996 */ 2997 if (!needsDtor) 2998 { 2999 if (tmp.edtor) 3000 { 3001 assert(i == lastPrefix); 3002 tmp.edtor = null; 3003 } 3004 } 3005 else 3006 { 3007 // edtor => (__gate || edtor) 3008 assert(tmp.edtor); 3009 Expression e = tmp.edtor; 3010 e = new LogicalExp(e.loc, EXP.orOr, new VarExp(e.loc, gate), e); 3011 tmp.edtor = e.expressionSemantic(sc); 3012 //printf("edtor: %s\n", tmp.edtor.toChars()); 3013 } 3014 } 3015 3016 // eprefix => (eprefix, auto __pfx/y = arg) 3017 auto ae = new DeclarationExp(loc, tmp); 3018 eprefix = Expression.combine(eprefix, ae.expressionSemantic(sc)); 3019 3020 // arg => __pfx/y 3021 arg = new VarExp(loc, tmp); 3022 arg = arg.expressionSemantic(sc); 3023 if (isRef) 3024 { 3025 arg = new PtrExp(loc, arg); 3026 arg = arg.expressionSemantic(sc); 3027 } 3028 3029 /* Problem 2: Last throwing arg? 3030 * Then finalize eprefix => (eprefix, gate = true), i.e., disable the 3031 * dtors right after constructing the last throwing arg. 3032 * From now on, the callee will take care of destructing the args because 3033 * the args are implicitly moved into function parameters. 3034 */ 3035 if (!callerDestroysArgs && i == lastPrefix) 3036 { 3037 auto e = new AssignExp(gate.loc, new VarExp(gate.loc, gate), IntegerExp.createBool(true)); 3038 eprefix = Expression.combine(eprefix, e.expressionSemantic(sc)); 3039 } 3040 } 3041 else // not part of 'eprefix' 3042 { 3043 /* Handle problem 1) by calling the copy constructor for value structs 3044 * (or static arrays of them) if appropriate. 3045 */ 3046 Type tv = arg.type.baseElemOf(); 3047 if (!isRef && tv.ty == Tstruct) 3048 arg = doCopyOrMove(sc, arg, parameter ? parameter.type : null); 3049 } 3050 3051 (*arguments)[i] = arg; 3052 } 3053 } 3054 //if (eprefix) printf("eprefix: %s\n", eprefix.toChars()); 3055 3056 /* Test compliance with DIP1021 Argument Ownership and Function Calls 3057 */ 3058 if (global.params.useDIP1021 && (tf.trust == TRUST.safe || tf.trust == TRUST.default_) || 3059 tf.islive) 3060 err |= checkMutableArguments(sc, fd, tf, ethis, arguments, false); 3061 3062 // If D linkage and variadic, add _arguments[] as first argument 3063 if (tf.isDstyleVariadic()) 3064 { 3065 assert(arguments.length >= nparams); 3066 3067 auto args = new Parameters(arguments.length - nparams); 3068 for (size_t i = 0; i < arguments.length - nparams; i++) 3069 { 3070 Expression earg = (*arguments)[nparams + i]; 3071 auto arg = new Parameter(earg.loc, STC.in_, earg.type, null, null, null); 3072 (*args)[i] = arg; 3073 } 3074 auto tup = new TypeTuple(args); 3075 Expression e = (new TypeidExp(loc, tup)).expressionSemantic(sc); 3076 arguments.insert(0, e); 3077 } 3078 3079 /* Determine function return type: tret 3080 */ 3081 Type tret = tf.next; 3082 if (isCtorCall) 3083 { 3084 //printf("[%s] fd = %s %s, %d %d %d\n", loc.toChars(), fd.toChars(), fd.type.toChars(), 3085 // wildmatch, tf.isWild(), fd.isReturnIsolated()); 3086 if (!tthis) 3087 { 3088 assert(sc.intypeof || global.errors); 3089 tthis = fd.isThis().type.addMod(fd.type.mod); 3090 } 3091 if (tf.isWild() && !fd.isReturnIsolated()) 3092 { 3093 if (wildmatch) 3094 tret = tret.substWildTo(wildmatch); 3095 int offset; 3096 if (!tret.implicitConvTo(tthis) && !(MODimplicitConv(tret.mod, tthis.mod) && tret.isBaseOf(tthis, &offset) && offset == 0)) 3097 { 3098 const(char)* s1 = tret.isNaked() ? " mutable" : tret.modToChars(); 3099 const(char)* s2 = tthis.isNaked() ? " mutable" : tthis.modToChars(); 3100 .error(loc, "`inout` constructor `%s` creates%s object, not%s", fd.toPrettyChars(), s1, s2); 3101 err = true; 3102 } 3103 } 3104 tret = tthis; 3105 } 3106 else if (wildmatch && tret) 3107 { 3108 /* Adjust function return type based on wildmatch 3109 */ 3110 //printf("wildmatch = x%x, tret = %s\n", wildmatch, tret.toChars()); 3111 tret = tret.substWildTo(wildmatch); 3112 } 3113 3114 *prettype = tret; 3115 *peprefix = eprefix; 3116 return (err || olderrors != global.errors); 3117 } 3118 3119 /** 3120 * Determines whether a symbol represents a module or package 3121 * (Used as a helper for is(type == module) and is(type == package)) 3122 * 3123 * Params: 3124 * sym = the symbol to be checked 3125 * 3126 * Returns: 3127 * the symbol which `sym` represents (or `null` if it doesn't represent a `Package`) 3128 */ 3129 Package resolveIsPackage(Dsymbol sym) 3130 { 3131 Package pkg; 3132 if (Import imp = sym.isImport()) 3133 { 3134 if (imp.pkg is null) 3135 { 3136 .error(sym.loc, "internal compiler error: unable to process forward-referenced import `%s`", 3137 imp.toChars()); 3138 assert(0); 3139 } 3140 pkg = imp.pkg; 3141 } 3142 else if (auto mod = sym.isModule()) 3143 pkg = mod.isPackageFile ? mod.pkg : sym.isPackage(); 3144 else 3145 pkg = sym.isPackage(); 3146 if (pkg) 3147 pkg.resolvePKGunknown(); 3148 return pkg; 3149 } 3150 3151 3152 private extern (C++) final class ExpressionSemanticVisitor : Visitor 3153 { 3154 alias visit = Visitor.visit; 3155 3156 Scope* sc; 3157 Expression result; 3158 3159 this(Scope* sc) scope @safe 3160 { 3161 this.sc = sc; 3162 } 3163 3164 private void setError() 3165 { 3166 result = ErrorExp.get(); 3167 } 3168 3169 private void needThisError(Loc loc, FuncDeclaration f) 3170 { 3171 auto t = f.isThis(); 3172 assert(t); 3173 .error(loc, "calling non-static function `%s` requires an instance of type `%s`", f.toChars(), t.toChars()); 3174 setError(); 3175 } 3176 3177 /************************** 3178 * Semantically analyze Expression. 3179 * Determine types, fold constants, etc. 3180 */ 3181 override void visit(Expression e) 3182 { 3183 static if (LOGSEMANTIC) 3184 { 3185 printf("Expression::semantic() %s\n", e.toChars()); 3186 } 3187 if (e.type) 3188 e.type = e.type.typeSemantic(e.loc, sc); 3189 else 3190 e.type = Type.tvoid; 3191 result = e; 3192 } 3193 3194 override void visit(IntegerExp e) 3195 { 3196 assert(e.type); 3197 if (e.type.ty == Terror) 3198 return setError(); 3199 3200 assert(e.type.deco); 3201 e.setInteger(e.getInteger()); 3202 result = e; 3203 } 3204 3205 override void visit(RealExp e) 3206 { 3207 if (!e.type) 3208 e.type = Type.tfloat64; 3209 else if (e.type.isimaginary && sc.flags & SCOPE.Cfile) 3210 { 3211 /* Convert to core.stdc.config.complex 3212 */ 3213 Type t = getComplexLibraryType(e.loc, sc, e.type.ty); 3214 if (t.ty == Terror) 3215 return setError(); 3216 3217 Type tf; 3218 switch (e.type.ty) 3219 { 3220 case Timaginary32: tf = Type.tfloat32; break; 3221 case Timaginary64: tf = Type.tfloat64; break; 3222 case Timaginary80: tf = Type.tfloat80; break; 3223 default: 3224 assert(0); 3225 } 3226 3227 /* Construct ts{re : 0.0, im : e} 3228 */ 3229 TypeStruct ts = t.isTypeStruct; 3230 Expressions* elements = new Expressions(2); 3231 (*elements)[0] = new RealExp(e.loc, CTFloat.zero, tf); 3232 (*elements)[1] = new RealExp(e.loc, e.toImaginary(), tf); 3233 Expression sle = new StructLiteralExp(e.loc, ts.sym, elements); 3234 result = sle.expressionSemantic(sc); 3235 return; 3236 } 3237 else 3238 e.type = e.type.typeSemantic(e.loc, sc); 3239 result = e; 3240 } 3241 3242 override void visit(ComplexExp e) 3243 { 3244 if (!e.type) 3245 e.type = Type.tcomplex80; 3246 else 3247 e.type = e.type.typeSemantic(e.loc, sc); 3248 result = e; 3249 } 3250 3251 override void visit(IdentifierExp exp) 3252 { 3253 static if (LOGSEMANTIC) 3254 { 3255 printf("IdentifierExp::semantic('%s')\n", exp.ident.toChars()); 3256 } 3257 if (exp.type) // This is used as the dummy expression 3258 { 3259 result = exp; 3260 return; 3261 } 3262 3263 Dsymbol scopesym; 3264 Dsymbol s = sc.search(exp.loc, exp.ident, &scopesym); 3265 if (s) 3266 { 3267 if (s.errors) 3268 return setError(); 3269 3270 Expression e; 3271 3272 /* See if the symbol was a member of an enclosing 'with' 3273 */ 3274 WithScopeSymbol withsym = scopesym.isWithScopeSymbol(); 3275 if (withsym && withsym.withstate.wthis && symbolIsVisible(sc, s)) 3276 { 3277 /* Disallow shadowing 3278 */ 3279 // First find the scope of the with 3280 Scope* scwith = sc; 3281 while (scwith.scopesym != scopesym) 3282 { 3283 scwith = scwith.enclosing; 3284 assert(scwith); 3285 } 3286 // Look at enclosing scopes for symbols with the same name, 3287 // in the same function 3288 for (Scope* scx = scwith; scx && scx.func == scwith.func; scx = scx.enclosing) 3289 { 3290 Dsymbol s2; 3291 if (scx.scopesym && scx.scopesym.symtab && (s2 = scx.scopesym.symtab.lookup(s.ident)) !is null && s != s2) 3292 { 3293 error(exp.loc, "with symbol `%s` is shadowing local symbol `%s`", s.toPrettyChars(), s2.toPrettyChars()); 3294 return setError(); 3295 } 3296 } 3297 s = s.toAlias(); 3298 3299 // Same as wthis.ident 3300 // TODO: DotIdExp.semantic will find 'ident' from 'wthis' again. 3301 // The redudancy should be removed. 3302 e = new VarExp(exp.loc, withsym.withstate.wthis); 3303 e = new DotIdExp(exp.loc, e, exp.ident); 3304 e = e.expressionSemantic(sc); 3305 } 3306 else 3307 { 3308 if (withsym) 3309 { 3310 if (withsym.withstate.exp.type.ty != Tvoid) 3311 { 3312 // 'with (exp)' is a type expression 3313 // or 's' is not visible there (for error message) 3314 e = new TypeExp(exp.loc, withsym.withstate.exp.type); 3315 } 3316 else 3317 { 3318 // 'with (exp)' is a Package/Module 3319 e = withsym.withstate.exp; 3320 } 3321 e = new DotIdExp(exp.loc, e, exp.ident); 3322 result = e.expressionSemantic(sc); 3323 return; 3324 } 3325 3326 /* If f is really a function template, 3327 * then replace f with the function template declaration. 3328 */ 3329 FuncDeclaration f = s.isFuncDeclaration(); 3330 if (f) 3331 { 3332 TemplateDeclaration td = getFuncTemplateDecl(f); 3333 if (td) 3334 { 3335 if (td.overroot) // if not start of overloaded list of TemplateDeclaration's 3336 td = td.overroot; // then get the start 3337 e = new TemplateExp(exp.loc, td, f); 3338 e = e.expressionSemantic(sc); 3339 result = e; 3340 return; 3341 } 3342 } 3343 3344 if (global.params.fixAliasThis) 3345 { 3346 ExpressionDsymbol expDsym = scopesym.isExpressionDsymbol(); 3347 if (expDsym) 3348 { 3349 //printf("expDsym = %s\n", expDsym.exp.toChars()); 3350 result = expDsym.exp.expressionSemantic(sc); 3351 return; 3352 } 3353 } 3354 // Haven't done overload resolution yet, so pass 1 3355 e = symbolToExp(s, exp.loc, sc, true); 3356 } 3357 result = e; 3358 return; 3359 } 3360 3361 if (!global.params.fixAliasThis && hasThis(sc)) 3362 { 3363 for (AggregateDeclaration ad = sc.getStructClassScope(); ad;) 3364 { 3365 if (ad.aliasthis) 3366 { 3367 Expression e; 3368 e = new ThisExp(exp.loc); 3369 e = new DotIdExp(exp.loc, e, ad.aliasthis.ident); 3370 e = new DotIdExp(exp.loc, e, exp.ident); 3371 e = e.trySemantic(sc); 3372 if (e) 3373 { 3374 result = e; 3375 return; 3376 } 3377 } 3378 3379 auto cd = ad.isClassDeclaration(); 3380 if (cd && cd.baseClass && cd.baseClass != ClassDeclaration.object) 3381 { 3382 ad = cd.baseClass; 3383 continue; 3384 } 3385 break; 3386 } 3387 } 3388 3389 if (exp.ident == Id.ctfe) 3390 { 3391 if (sc.flags & SCOPE.ctfe) 3392 { 3393 error(exp.loc, "variable `__ctfe` cannot be read at compile time"); 3394 return setError(); 3395 } 3396 3397 // Create the magic __ctfe bool variable 3398 auto vd = new VarDeclaration(exp.loc, Type.tbool, Id.ctfe, null); 3399 vd.storage_class |= STC.temp; 3400 vd.semanticRun = PASS.semanticdone; 3401 Expression e = new VarExp(exp.loc, vd); 3402 e = e.expressionSemantic(sc); 3403 result = e; 3404 return; 3405 } 3406 3407 // If we've reached this point and are inside a with() scope then we may 3408 // try one last attempt by checking whether the 'wthis' object supports 3409 // dynamic dispatching via opDispatch. 3410 // This is done by rewriting this expression as wthis.ident. 3411 // The innermost with() scope of the hierarchy to satisfy the condition 3412 // above wins. 3413 // https://issues.dlang.org/show_bug.cgi?id=6400 3414 for (Scope* sc2 = sc; sc2; sc2 = sc2.enclosing) 3415 { 3416 if (!sc2.scopesym) 3417 continue; 3418 3419 if (auto ss = sc2.scopesym.isWithScopeSymbol()) 3420 { 3421 if (ss.withstate.wthis) 3422 { 3423 Expression e; 3424 e = new VarExp(exp.loc, ss.withstate.wthis); 3425 e = new DotIdExp(exp.loc, e, exp.ident); 3426 e = e.trySemantic(sc); 3427 if (e) 3428 { 3429 result = e; 3430 return; 3431 } 3432 } 3433 // Try Type.opDispatch (so the static version) 3434 else if (ss.withstate.exp && ss.withstate.exp.op == EXP.type) 3435 { 3436 if (Type t = ss.withstate.exp.isTypeExp().type) 3437 { 3438 Expression e; 3439 e = new TypeExp(exp.loc, t); 3440 e = new DotIdExp(exp.loc, e, exp.ident); 3441 e = e.trySemantic(sc); 3442 if (e) 3443 { 3444 result = e; 3445 return; 3446 } 3447 } 3448 } 3449 } 3450 } 3451 3452 /* Look for what user might have meant 3453 */ 3454 if (const n = importHint(exp.ident.toString())) 3455 error(exp.loc, "`%s` is not defined, perhaps `import %.*s;` is needed?", exp.ident.toChars(), cast(int)n.length, n.ptr); 3456 else if (auto s2 = sc.search_correct(exp.ident)) 3457 error(exp.loc, "undefined identifier `%s`, did you mean %s `%s`?", exp.ident.toChars(), s2.kind(), s2.toChars()); 3458 else if (const p = Scope.search_correct_C(exp.ident)) 3459 error(exp.loc, "undefined identifier `%s`, did you mean `%s`?", exp.ident.toChars(), p); 3460 else if (exp.ident == Id.dollar) 3461 error(exp.loc, "undefined identifier `$`"); 3462 else 3463 error(exp.loc, "undefined identifier `%s`", exp.ident.toChars()); 3464 3465 result = ErrorExp.get(); 3466 } 3467 3468 override void visit(DsymbolExp e) 3469 { 3470 result = symbolToExp(e.s, e.loc, sc, e.hasOverloads); 3471 } 3472 3473 override void visit(ThisExp e) 3474 { 3475 static if (LOGSEMANTIC) 3476 { 3477 printf("ThisExp::semantic()\n"); 3478 } 3479 if (e.type) 3480 { 3481 result = e; 3482 return; 3483 } 3484 3485 FuncDeclaration fd = hasThis(sc); // fd is the uplevel function with the 'this' variable 3486 AggregateDeclaration ad; 3487 3488 /* Special case for typeof(this) and typeof(super) since both 3489 * should work even if they are not inside a non-static member function 3490 */ 3491 if (!fd && sc.intypeof == 1) 3492 { 3493 // Find enclosing struct or class 3494 for (Dsymbol s = sc.getStructClassScope(); 1; s = s.parent) 3495 { 3496 if (!s) 3497 { 3498 error(e.loc, "`%s` is not in a class or struct scope", e.toChars()); 3499 return setError(); 3500 } 3501 ClassDeclaration cd = s.isClassDeclaration(); 3502 if (cd) 3503 { 3504 e.type = cd.type; 3505 result = e; 3506 return; 3507 } 3508 StructDeclaration sd = s.isStructDeclaration(); 3509 if (sd) 3510 { 3511 e.type = sd.type; 3512 result = e; 3513 return; 3514 } 3515 } 3516 } 3517 if (!fd) 3518 { 3519 error(e.loc, "`this` is only defined in non-static member functions, not `%s`", sc.parent.toChars()); 3520 return setError(); 3521 } 3522 3523 assert(fd.vthis); 3524 e.var = fd.vthis; 3525 assert(e.var.parent); 3526 ad = fd.isMemberLocal(); 3527 if (!ad) 3528 ad = fd.isMember2(); 3529 assert(ad); 3530 e.type = ad.type.addMod(e.var.type.mod); 3531 3532 if (e.var.checkNestedReference(sc, e.loc)) 3533 return setError(); 3534 3535 result = e; 3536 } 3537 3538 override void visit(SuperExp e) 3539 { 3540 static if (LOGSEMANTIC) 3541 { 3542 printf("SuperExp::semantic('%s')\n", e.toChars()); 3543 } 3544 if (e.type) 3545 { 3546 result = e; 3547 return; 3548 } 3549 3550 FuncDeclaration fd = hasThis(sc); 3551 ClassDeclaration cd; 3552 Dsymbol s; 3553 3554 /* Special case for typeof(this) and typeof(super) since both 3555 * should work even if they are not inside a non-static member function 3556 */ 3557 if (!fd && sc.intypeof == 1) 3558 { 3559 // Find enclosing class 3560 for (s = sc.getStructClassScope(); 1; s = s.parent) 3561 { 3562 if (!s) 3563 { 3564 error(e.loc, "`%s` is not in a class scope", e.toChars()); 3565 return setError(); 3566 } 3567 cd = s.isClassDeclaration(); 3568 if (cd) 3569 { 3570 cd = cd.baseClass; 3571 if (!cd) 3572 { 3573 error(e.loc, "class `%s` has no `super`", s.toChars()); 3574 return setError(); 3575 } 3576 e.type = cd.type; 3577 result = e; 3578 return; 3579 } 3580 } 3581 } 3582 if (!fd) 3583 goto Lerr; 3584 3585 e.var = fd.vthis; 3586 assert(e.var && e.var.parent); 3587 3588 s = fd.toParentDecl(); 3589 if (s.isTemplateDeclaration()) // allow inside template constraint 3590 s = s.toParent(); 3591 assert(s); 3592 cd = s.isClassDeclaration(); 3593 //printf("parent is %s %s\n", fd.toParent().kind(), fd.toParent().toChars()); 3594 if (!cd) 3595 goto Lerr; 3596 if (!cd.baseClass) 3597 { 3598 error(e.loc, "no base class for `%s`", cd.toChars()); 3599 e.type = cd.type.addMod(e.var.type.mod); 3600 } 3601 else 3602 { 3603 e.type = cd.baseClass.type; 3604 e.type = e.type.castMod(e.var.type.mod); 3605 } 3606 3607 if (e.var.checkNestedReference(sc, e.loc)) 3608 return setError(); 3609 3610 result = e; 3611 return; 3612 3613 Lerr: 3614 error(e.loc, "`super` is only allowed in non-static class member functions"); 3615 result = ErrorExp.get(); 3616 } 3617 3618 override void visit(NullExp e) 3619 { 3620 static if (LOGSEMANTIC) 3621 { 3622 printf("NullExp::semantic('%s')\n", e.toChars()); 3623 } 3624 // NULL is the same as (void *)0 3625 if (e.type) 3626 { 3627 result = e; 3628 return; 3629 } 3630 e.type = Type.tnull; 3631 result = e; 3632 } 3633 3634 override void visit(StringExp e) 3635 { 3636 static if (LOGSEMANTIC) 3637 { 3638 printf("StringExp::semantic() %s\n", e.toChars()); 3639 } 3640 if (e.type) 3641 { 3642 result = e; 3643 return; 3644 } 3645 3646 OutBuffer buffer; 3647 size_t newlen = 0; 3648 size_t u; 3649 dchar c; 3650 3651 switch (e.postfix) 3652 { 3653 case 'd': 3654 for (u = 0; u < e.len;) 3655 { 3656 if (const p = utf_decodeChar(e.peekString(), u, c)) 3657 { 3658 error(e.loc, "%.*s", cast(int)p.length, p.ptr); 3659 return setError(); 3660 } 3661 else 3662 { 3663 buffer.write4(c); 3664 newlen++; 3665 } 3666 } 3667 buffer.write4(0); 3668 e.setData(buffer.extractData(), newlen, 4); 3669 if (sc && sc.flags & SCOPE.Cfile) 3670 e.type = Type.tuns32.sarrayOf(e.len + 1); 3671 else 3672 e.type = Type.tdchar.immutableOf().arrayOf(); 3673 e.committed = true; 3674 break; 3675 3676 case 'w': 3677 for (u = 0; u < e.len;) 3678 { 3679 if (const p = utf_decodeChar(e.peekString(), u, c)) 3680 { 3681 error(e.loc, "%.*s", cast(int)p.length, p.ptr); 3682 return setError(); 3683 } 3684 else 3685 { 3686 buffer.writeUTF16(c); 3687 newlen++; 3688 if (c >= 0x10000) 3689 newlen++; 3690 } 3691 } 3692 buffer.writeUTF16(0); 3693 e.setData(buffer.extractData(), newlen, 2); 3694 if (sc && sc.flags & SCOPE.Cfile) 3695 e.type = Type.tuns16.sarrayOf(e.len + 1); 3696 else 3697 e.type = Type.twchar.immutableOf().arrayOf(); 3698 e.committed = true; 3699 break; 3700 3701 case 'c': 3702 e.committed = true; 3703 goto default; 3704 3705 default: 3706 if (sc && sc.flags & SCOPE.Cfile) 3707 e.type = Type.tchar.sarrayOf(e.len + 1); 3708 else 3709 e.type = Type.tchar.immutableOf().arrayOf(); 3710 break; 3711 } 3712 e.type = e.type.typeSemantic(e.loc, sc); 3713 //type = type.immutableOf(); 3714 //printf("type = %s\n", type.toChars()); 3715 3716 result = e; 3717 } 3718 3719 override void visit(TupleExp exp) 3720 { 3721 static if (LOGSEMANTIC) 3722 { 3723 printf("+TupleExp::semantic(%s)\n", exp.toChars()); 3724 } 3725 if (exp.type) 3726 { 3727 result = exp; 3728 return; 3729 } 3730 3731 if (exp.e0) 3732 exp.e0 = exp.e0.expressionSemantic(sc); 3733 3734 // Run semantic() on each argument 3735 bool err = false; 3736 for (size_t i = 0; i < exp.exps.length; i++) 3737 { 3738 Expression e = (*exp.exps)[i]; 3739 e = e.expressionSemantic(sc); 3740 if (!e.type) 3741 { 3742 error(exp.loc, "`%s` has no value", e.toChars()); 3743 err = true; 3744 } 3745 else if (e.op == EXP.error) 3746 err = true; 3747 else 3748 (*exp.exps)[i] = e; 3749 } 3750 if (err) 3751 return setError(); 3752 3753 expandTuples(exp.exps); 3754 3755 exp.type = new TypeTuple(exp.exps); 3756 exp.type = exp.type.typeSemantic(exp.loc, sc); 3757 //printf("-TupleExp::semantic(%s)\n", toChars()); 3758 result = exp; 3759 } 3760 3761 override void visit(ArrayLiteralExp e) 3762 { 3763 static if (LOGSEMANTIC) 3764 { 3765 printf("ArrayLiteralExp::semantic('%s')\n", e.toChars()); 3766 } 3767 if (e.type) 3768 { 3769 result = e; 3770 return; 3771 } 3772 3773 /* Perhaps an empty array literal [ ] should be rewritten as null? 3774 */ 3775 3776 if (e.basis) 3777 e.basis = e.basis.expressionSemantic(sc); 3778 if (arrayExpressionSemantic(e.elements.peekSlice(), sc) || (e.basis && e.basis.op == EXP.error)) 3779 return setError(); 3780 3781 expandTuples(e.elements); 3782 3783 if (e.basis) 3784 e.elements.push(e.basis); 3785 Type t0 = arrayExpressionToCommonType(sc, *e.elements); 3786 if (e.basis) 3787 e.basis = e.elements.pop(); 3788 if (t0 is null) 3789 return setError(); 3790 3791 e.type = t0.arrayOf(); 3792 e.type = e.type.typeSemantic(e.loc, sc); 3793 3794 /* Disallow array literals of type void being used. 3795 */ 3796 if (e.elements.length > 0 && t0.ty == Tvoid) 3797 { 3798 error(e.loc, "`%s` of type `%s` has no value", e.toChars(), e.type.toChars()); 3799 return setError(); 3800 } 3801 3802 if (global.params.useTypeInfo && Type.dtypeinfo) 3803 semanticTypeInfo(sc, e.type); 3804 3805 result = e; 3806 } 3807 3808 override void visit(AssocArrayLiteralExp e) 3809 { 3810 static if (LOGSEMANTIC) 3811 { 3812 printf("AssocArrayLiteralExp::semantic('%s')\n", e.toChars()); 3813 } 3814 if (e.type) 3815 { 3816 result = e; 3817 return; 3818 } 3819 3820 // Run semantic() on each element 3821 bool err_keys = arrayExpressionSemantic(e.keys.peekSlice(), sc); 3822 bool err_vals = arrayExpressionSemantic(e.values.peekSlice(), sc); 3823 if (err_keys || err_vals) 3824 return setError(); 3825 3826 expandTuples(e.keys); 3827 expandTuples(e.values); 3828 if (e.keys.length != e.values.length) 3829 { 3830 error(e.loc, "number of keys is %llu, must match number of values %llu", 3831 cast(ulong) e.keys.length, cast(ulong) e.values.length); 3832 return setError(); 3833 } 3834 3835 Type tkey = arrayExpressionToCommonType(sc, *e.keys); 3836 Type tvalue = arrayExpressionToCommonType(sc, *e.values); 3837 if (tkey is null || tvalue is null) 3838 return setError(); 3839 3840 e.type = new TypeAArray(tvalue, tkey); 3841 e.type = e.type.typeSemantic(e.loc, sc); 3842 3843 semanticTypeInfo(sc, e.type); 3844 3845 if (checkAssocArrayLiteralEscape(sc, e, false)) 3846 return setError(); 3847 3848 result = e; 3849 } 3850 3851 override void visit(StructLiteralExp e) 3852 { 3853 static if (LOGSEMANTIC) 3854 { 3855 printf("StructLiteralExp::semantic('%s')\n", e.toChars()); 3856 } 3857 if (e.type) 3858 { 3859 result = e; 3860 return; 3861 } 3862 3863 e.sd.size(e.loc); 3864 if (e.sd.sizeok != Sizeok.done) 3865 return setError(); 3866 3867 // run semantic() on each element 3868 if (arrayExpressionSemantic(e.elements.peekSlice(), sc)) 3869 return setError(); 3870 3871 expandTuples(e.elements); 3872 3873 /* Fit elements[] to the corresponding type of field[]. 3874 */ 3875 if (!e.sd.fit(e.loc, sc, e.elements, e.stype)) 3876 return setError(); 3877 3878 /* Fill out remainder of elements[] with default initializers for fields[] 3879 */ 3880 if (!e.sd.fill(e.loc, *e.elements, false)) 3881 { 3882 /* An error in the initializer needs to be recorded as an error 3883 * in the enclosing function or template, since the initializer 3884 * will be part of the stuct declaration. 3885 */ 3886 global.increaseErrorCount(); 3887 return setError(); 3888 } 3889 3890 if (checkFrameAccess(e.loc, sc, e.sd, e.elements.length)) 3891 return setError(); 3892 3893 e.type = e.stype ? e.stype : e.sd.type; 3894 result = e; 3895 } 3896 3897 override void visit(CompoundLiteralExp cle) 3898 { 3899 static if (LOGSEMANTIC) 3900 { 3901 printf("CompoundLiteralExp::semantic('%s')\n", cle.toChars()); 3902 } 3903 Type t = cle.type.typeSemantic(cle.loc, sc); 3904 auto init = initializerSemantic(cle.initializer, sc, t, INITnointerpret); 3905 auto e = initializerToExpression(init, t, (sc.flags & SCOPE.Cfile) != 0); 3906 if (!e) 3907 { 3908 error(cle.loc, "cannot convert initializer `%s` to expression", init.toChars()); 3909 return setError(); 3910 } 3911 result = e; 3912 return; 3913 } 3914 3915 override void visit(TypeExp exp) 3916 { 3917 if (exp.type.ty == Terror) 3918 return setError(); 3919 3920 //printf("TypeExp::semantic(%s)\n", exp.type.toChars()); 3921 Expression e; 3922 Type t; 3923 Dsymbol s; 3924 3925 dmd.typesem.resolve(exp.type, exp.loc, sc, e, t, s, true); 3926 if (e) 3927 { 3928 // `(Type)` is actually `(var)` so if `(var)` is a member requiring `this` 3929 // then rewrite as `(this.var)` in case it would be followed by a DotVar 3930 // to fix https://issues.dlang.org/show_bug.cgi?id=9490 3931 VarExp ve = e.isVarExp(); 3932 if (ve && ve.var && exp.parens && !ve.var.isStatic() && !(sc.stc & STC.static_) && 3933 sc.func && sc.func.needThis && ve.var.isMember2()) 3934 { 3935 // printf("apply fix for bugzilla issue 9490: add `this.` to `%s`...\n", e.toChars()); 3936 e = new DotVarExp(exp.loc, new ThisExp(exp.loc), ve.var, false); 3937 } 3938 //printf("e = %s %s\n", Token.toChars(e.op), e.toChars()); 3939 e = e.expressionSemantic(sc); 3940 } 3941 else if (t) 3942 { 3943 //printf("t = %d %s\n", t.ty, t.toChars()); 3944 exp.type = t.typeSemantic(exp.loc, sc); 3945 e = exp; 3946 } 3947 else if (s) 3948 { 3949 //printf("s = %s %s\n", s.kind(), s.toChars()); 3950 e = symbolToExp(s, exp.loc, sc, true); 3951 } 3952 else 3953 assert(0); 3954 3955 exp.type.checkComplexTransition(exp.loc, sc); 3956 3957 result = e; 3958 } 3959 3960 override void visit(ScopeExp exp) 3961 { 3962 static if (LOGSEMANTIC) 3963 { 3964 printf("+ScopeExp::semantic(%p '%s')\n", exp, exp.toChars()); 3965 } 3966 if (exp.type) 3967 { 3968 result = exp; 3969 return; 3970 } 3971 3972 ScopeDsymbol sds2 = exp.sds; 3973 TemplateInstance ti = sds2.isTemplateInstance(); 3974 while (ti) 3975 { 3976 WithScopeSymbol withsym; 3977 if (!ti.findTempDecl(sc, &withsym) || !ti.semanticTiargs(sc)) 3978 return setError(); 3979 if (withsym && withsym.withstate.wthis) 3980 { 3981 Expression e = new VarExp(exp.loc, withsym.withstate.wthis); 3982 e = new DotTemplateInstanceExp(exp.loc, e, ti); 3983 result = e.expressionSemantic(sc); 3984 return; 3985 } 3986 if (ti.needsTypeInference(sc)) 3987 { 3988 if (TemplateDeclaration td = ti.tempdecl.isTemplateDeclaration()) 3989 { 3990 Dsymbol p = td.toParentLocal(); 3991 FuncDeclaration fdthis = hasThis(sc); 3992 AggregateDeclaration ad = p ? p.isAggregateDeclaration() : null; 3993 if (fdthis && ad && fdthis.isMemberLocal() == ad && (td._scope.stc & STC.static_) == 0) 3994 { 3995 Expression e = new DotTemplateInstanceExp(exp.loc, new ThisExp(exp.loc), ti); 3996 result = e.expressionSemantic(sc); 3997 return; 3998 } 3999 } 4000 else if (OverloadSet os = ti.tempdecl.isOverloadSet()) 4001 { 4002 FuncDeclaration fdthis = hasThis(sc); 4003 AggregateDeclaration ad = os.parent.isAggregateDeclaration(); 4004 if (fdthis && ad && fdthis.isMemberLocal() == ad) 4005 { 4006 Expression e = new DotTemplateInstanceExp(exp.loc, new ThisExp(exp.loc), ti); 4007 result = e.expressionSemantic(sc); 4008 return; 4009 } 4010 } 4011 // ti is an instance which requires IFTI. 4012 exp.sds = ti; 4013 exp.type = Type.tvoid; 4014 result = exp; 4015 return; 4016 } 4017 ti.dsymbolSemantic(sc); 4018 if (!ti.inst || ti.errors) 4019 return setError(); 4020 4021 Dsymbol s = ti.toAlias(); 4022 if (s == ti) 4023 { 4024 exp.sds = ti; 4025 exp.type = Type.tvoid; 4026 result = exp; 4027 return; 4028 } 4029 sds2 = s.isScopeDsymbol(); 4030 if (sds2) 4031 { 4032 ti = sds2.isTemplateInstance(); 4033 //printf("+ sds2 = %s, '%s'\n", sds2.kind(), sds2.toChars()); 4034 continue; 4035 } 4036 4037 if (auto v = s.isVarDeclaration()) 4038 { 4039 if (!v.type) 4040 { 4041 error(exp.loc, "forward reference of %s `%s`", v.kind(), v.toChars()); 4042 return setError(); 4043 } 4044 if ((v.storage_class & STC.manifest) && v._init) 4045 { 4046 /* When an instance that will be converted to a constant exists, 4047 * the instance representation "foo!tiargs" is treated like a 4048 * variable name, and its recursive appearance check (note that 4049 * it's equivalent with a recursive instantiation of foo) is done 4050 * separately from the circular initialization check for the 4051 * eponymous enum variable declaration. 4052 * 4053 * template foo(T) { 4054 * enum bool foo = foo; // recursive definition check (v.inuse) 4055 * } 4056 * template bar(T) { 4057 * enum bool bar = bar!T; // recursive instantiation check (ti.inuse) 4058 * } 4059 */ 4060 if (ti.inuse) 4061 { 4062 error(exp.loc, "recursive expansion of %s `%s`", ti.kind(), ti.toPrettyChars()); 4063 return setError(); 4064 } 4065 v.checkDeprecated(exp.loc, sc); 4066 auto e = v.expandInitializer(exp.loc); 4067 ti.inuse++; 4068 e = e.expressionSemantic(sc); 4069 ti.inuse--; 4070 result = e; 4071 return; 4072 } 4073 } 4074 4075 //printf("s = %s, '%s'\n", s.kind(), s.toChars()); 4076 auto e = symbolToExp(s, exp.loc, sc, true); 4077 //printf("-1ScopeExp::semantic()\n"); 4078 result = e; 4079 return; 4080 } 4081 4082 //printf("sds2 = %s, '%s'\n", sds2.kind(), sds2.toChars()); 4083 //printf("\tparent = '%s'\n", sds2.parent.toChars()); 4084 sds2.dsymbolSemantic(sc); 4085 4086 // (Aggregate|Enum)Declaration 4087 if (auto t = sds2.getType()) 4088 { 4089 result = (new TypeExp(exp.loc, t)).expressionSemantic(sc); 4090 return; 4091 } 4092 4093 if (auto td = sds2.isTemplateDeclaration()) 4094 { 4095 result = (new TemplateExp(exp.loc, td)).expressionSemantic(sc); 4096 return; 4097 } 4098 4099 exp.sds = sds2; 4100 exp.type = Type.tvoid; 4101 //printf("-2ScopeExp::semantic() %s\n", toChars()); 4102 result = exp; 4103 } 4104 4105 /** 4106 * Sets the `lowering` field of a `NewExp` to a call to `_d_newitemT` unless 4107 * compiling with `-betterC` or within `__traits(compiles)`. 4108 * 4109 * Params: 4110 * ne = the `NewExp` to lower 4111 */ 4112 private void tryLowerToNewItem(NewExp ne) 4113 { 4114 if (!global.params.useGC || !sc.needsCodegen()) 4115 return; 4116 4117 auto hook = global.params.tracegc ? Id._d_newitemTTrace : Id._d_newitemT; 4118 if (!verifyHookExist(ne.loc, *sc, hook, "new struct")) 4119 return; 4120 4121 /* Lower the memory allocation and initialization of `new T()` to 4122 * `_d_newitemT!T()`. 4123 */ 4124 Expression id = new IdentifierExp(ne.loc, Id.empty); 4125 id = new DotIdExp(ne.loc, id, Id.object); 4126 auto tiargs = new Objects(); 4127 /* 4128 * Remove `inout`, `const`, `immutable` and `shared` to reduce the 4129 * number of generated `_d_newitemT` instances. 4130 */ 4131 auto t = ne.type.nextOf.unqualify(MODFlags.wild | MODFlags.const_ | 4132 MODFlags.immutable_ | MODFlags.shared_); 4133 tiargs.push(t); 4134 id = new DotTemplateInstanceExp(ne.loc, id, hook, tiargs); 4135 4136 auto arguments = new Expressions(); 4137 if (global.params.tracegc) 4138 { 4139 auto funcname = (sc.callsc && sc.callsc.func) ? 4140 sc.callsc.func.toPrettyChars() : sc.func.toPrettyChars(); 4141 arguments.push(new StringExp(ne.loc, ne.loc.filename.toDString())); 4142 arguments.push(new IntegerExp(ne.loc, ne.loc.linnum, Type.tint32)); 4143 arguments.push(new StringExp(ne.loc, funcname.toDString())); 4144 } 4145 id = new CallExp(ne.loc, id, arguments); 4146 4147 ne.lowering = id.expressionSemantic(sc); 4148 } 4149 4150 override void visit(NewExp exp) 4151 { 4152 static if (LOGSEMANTIC) 4153 { 4154 printf("NewExp::semantic() %s\n", exp.toChars()); 4155 if (exp.thisexp) 4156 printf("\tthisexp = %s\n", exp.thisexp.toChars()); 4157 printf("\tnewtype: %s\n", exp.newtype.toChars()); 4158 } 4159 if (exp.type) // if semantic() already run 4160 { 4161 result = exp; 4162 return; 4163 } 4164 4165 //for error messages if the argument in [] is not convertible to size_t 4166 const originalNewtype = exp.newtype; 4167 4168 // https://issues.dlang.org/show_bug.cgi?id=11581 4169 // With the syntax `new T[edim]` or `thisexp.new T[edim]`, 4170 // T should be analyzed first and edim should go into arguments iff it's 4171 // not a tuple. 4172 Expression edim = null; 4173 if (!exp.arguments && exp.newtype.isTypeSArray()) 4174 { 4175 auto ts = exp.newtype.isTypeSArray(); 4176 // check `new Value[Key]` 4177 ts.dim = ts.dim.expressionSemantic(sc); 4178 if (ts.dim.op == EXP.type) 4179 { 4180 exp.newtype = new TypeAArray(ts.next, ts.dim.isTypeExp().type); 4181 } 4182 else 4183 { 4184 edim = ts.dim; 4185 exp.newtype = ts.next; 4186 } 4187 } 4188 4189 ClassDeclaration cdthis = null; 4190 if (exp.thisexp) 4191 { 4192 exp.thisexp = exp.thisexp.expressionSemantic(sc); 4193 if (exp.thisexp.op == EXP.error) 4194 return setError(); 4195 4196 cdthis = exp.thisexp.type.isClassHandle(); 4197 if (!cdthis) 4198 { 4199 error(exp.loc, "`this` for nested class must be a class type, not `%s`", exp.thisexp.type.toChars()); 4200 return setError(); 4201 } 4202 4203 sc = sc.push(cdthis); 4204 exp.type = exp.newtype.typeSemantic(exp.loc, sc); 4205 sc = sc.pop(); 4206 } 4207 else 4208 { 4209 exp.type = exp.newtype.typeSemantic(exp.loc, sc); 4210 } 4211 if (exp.type.ty == Terror) 4212 return setError(); 4213 4214 if (edim) 4215 { 4216 if (exp.type.toBasetype().ty == Ttuple) 4217 { 4218 // --> new T[edim] 4219 exp.type = new TypeSArray(exp.type, edim); 4220 exp.type = exp.type.typeSemantic(exp.loc, sc); 4221 if (exp.type.ty == Terror) 4222 return setError(); 4223 } 4224 else 4225 { 4226 // --> new T[](edim) 4227 exp.arguments = new Expressions(); 4228 exp.arguments.push(edim); 4229 exp.type = exp.type.arrayOf(); 4230 } 4231 } 4232 4233 exp.newtype = exp.type; // in case type gets cast to something else 4234 Type tb = exp.type.toBasetype(); 4235 //printf("tb: %s, deco = %s\n", tb.toChars(), tb.deco); 4236 if (arrayExpressionSemantic(exp.arguments.peekSlice(), sc)) 4237 { 4238 return setError(); 4239 } 4240 if (preFunctionParameters(sc, exp.argumentList)) 4241 { 4242 return setError(); 4243 } 4244 4245 if (exp.thisexp && tb.ty != Tclass) 4246 { 4247 error(exp.loc, "`.new` is only for allocating nested classes, not `%s`", tb.toChars()); 4248 return setError(); 4249 } 4250 4251 const size_t nargs = exp.arguments ? exp.arguments.length : 0; 4252 Expression newprefix = null; 4253 4254 if (auto tc = tb.isTypeClass()) 4255 { 4256 auto cd = tc.sym; 4257 if (cd.errors) 4258 return setError(); 4259 cd.size(exp.loc); 4260 if (cd.sizeok != Sizeok.done) 4261 return setError(); 4262 if (!cd.ctor) 4263 cd.ctor = cd.searchCtor(); 4264 if (cd.noDefaultCtor && !nargs && !cd.defaultCtor) 4265 { 4266 error(exp.loc, "default construction is disabled for type `%s`", cd.type.toChars()); 4267 return setError(); 4268 } 4269 4270 if (cd.isInterfaceDeclaration()) 4271 { 4272 error(exp.loc, "cannot create instance of interface `%s`", cd.toChars()); 4273 return setError(); 4274 } 4275 4276 if (cd.isAbstract()) 4277 { 4278 error(exp.loc, "cannot create instance of abstract class `%s`", cd.toChars()); 4279 errorSupplemental(cd.loc, "class `%s` is declared here", cd.toChars()); 4280 for (size_t i = 0; i < cd.vtbl.length; i++) 4281 { 4282 FuncDeclaration fd = cd.vtbl[i].isFuncDeclaration(); 4283 if (fd && fd.isAbstract()) 4284 { 4285 errorSupplemental(fd.loc, "function `%s` is not implemented", 4286 fd.toFullSignature()); 4287 } 4288 } 4289 return setError(); 4290 } 4291 // checkDeprecated() is already done in newtype.typeSemantic(). 4292 4293 if (cd.isNested()) 4294 { 4295 /* We need a 'this' pointer for the nested class. 4296 * Ensure we have the right one. 4297 */ 4298 Dsymbol s = cd.toParentLocal(); 4299 4300 //printf("cd isNested, parent = %s '%s'\n", s.kind(), s.toPrettyChars()); 4301 if (auto cdn = s.isClassDeclaration()) 4302 { 4303 if (!cdthis) 4304 { 4305 void noReferenceToOuterClass() 4306 { 4307 if (cd.isAnonymous) 4308 error(exp.loc, "cannot construct anonymous nested class because no implicit `this` reference to outer class is available"); 4309 else 4310 error(exp.loc, "cannot construct nested class `%s` because no implicit `this` reference to outer class `%s` is available", 4311 cd.toChars(), cdn.toChars()); 4312 return setError(); 4313 } 4314 4315 if (!sc.hasThis) 4316 return noReferenceToOuterClass(); 4317 4318 // Supply an implicit 'this' and try again 4319 exp.thisexp = new ThisExp(exp.loc); 4320 for (Dsymbol sp = sc.parent; 1; sp = sp.toParentLocal()) 4321 { 4322 if (!sp) 4323 return noReferenceToOuterClass(); 4324 ClassDeclaration cdp = sp.isClassDeclaration(); 4325 if (!cdp) 4326 continue; 4327 if (cdp == cdn || cdn.isBaseOf(cdp, null)) 4328 break; 4329 // Add a '.outer' and try again 4330 exp.thisexp = new DotIdExp(exp.loc, exp.thisexp, Id.outer); 4331 } 4332 4333 exp.thisexp = exp.thisexp.expressionSemantic(sc); 4334 if (exp.thisexp.op == EXP.error) 4335 return setError(); 4336 cdthis = exp.thisexp.type.isClassHandle(); 4337 } 4338 if (cdthis != cdn && !cdn.isBaseOf(cdthis, null)) 4339 { 4340 //printf("cdthis = %s\n", cdthis.toChars()); 4341 error(exp.loc, "`this` for nested class must be of type `%s`, not `%s`", 4342 cdn.toChars(), exp.thisexp.type.toChars()); 4343 return setError(); 4344 } 4345 if (!MODimplicitConv(exp.thisexp.type.mod, exp.newtype.mod)) 4346 { 4347 error(exp.loc, "nested type `%s` should have the same or weaker constancy as enclosing type `%s`", 4348 exp.newtype.toChars(), exp.thisexp.type.toChars()); 4349 return setError(); 4350 } 4351 } 4352 else if (exp.thisexp) 4353 { 4354 error(exp.loc, "`.new` is only for allocating nested classes"); 4355 return setError(); 4356 } 4357 else if (auto fdn = s.isFuncDeclaration()) 4358 { 4359 // make sure the parent context fdn of cd is reachable from sc 4360 if (!ensureStaticLinkTo(sc.parent, fdn)) 4361 { 4362 error(exp.loc, "outer function context of `%s` is needed to `new` nested class `%s`", 4363 fdn.toPrettyChars(), cd.toPrettyChars()); 4364 return setError(); 4365 } 4366 } 4367 else 4368 assert(0); 4369 } 4370 else if (exp.thisexp) 4371 { 4372 error(exp.loc, "`.new` is only for allocating nested classes"); 4373 return setError(); 4374 } 4375 4376 if (cd.vthis2) 4377 { 4378 if (AggregateDeclaration ad2 = cd.isMember2()) 4379 { 4380 Expression te = new ThisExp(exp.loc).expressionSemantic(sc); 4381 if (te.op != EXP.error) 4382 te = getRightThis(exp.loc, sc, ad2, te, cd); 4383 if (te.op == EXP.error) 4384 { 4385 error(exp.loc, "need `this` of type `%s` needed to `new` nested class `%s`", ad2.toChars(), cd.toChars()); 4386 return setError(); 4387 } 4388 } 4389 } 4390 4391 if (cd.disableNew && !exp.onstack) 4392 { 4393 error(exp.loc, "cannot allocate `class %s` with `new` because it is annotated with `@disable new()`", 4394 originalNewtype.toChars()); 4395 return setError(); 4396 } 4397 4398 if (cd.ctor) 4399 { 4400 FuncDeclaration f = resolveFuncCall(exp.loc, sc, cd.ctor, null, tb, exp.argumentList, FuncResolveFlag.standard); 4401 if (!f || f.errors) 4402 return setError(); 4403 4404 checkFunctionAttributes(exp, sc, f); 4405 checkAccess(cd, exp.loc, sc, f); 4406 4407 TypeFunction tf = f.type.isTypeFunction(); 4408 if (!exp.arguments) 4409 exp.arguments = new Expressions(); 4410 if (functionParameters(exp.loc, sc, tf, null, exp.type, exp.argumentList, f, &exp.type, &exp.argprefix)) 4411 return setError(); 4412 4413 exp.member = f.isCtorDeclaration(); 4414 assert(exp.member); 4415 } 4416 else 4417 { 4418 if (nargs) 4419 { 4420 error(exp.loc, "no constructor for `%s`", cd.toChars()); 4421 return setError(); 4422 } 4423 4424 // https://issues.dlang.org/show_bug.cgi?id=19941 4425 // Run semantic on all field initializers to resolve any forward 4426 // references. This is the same as done for structs in sd.fill(). 4427 for (ClassDeclaration c = cd; c; c = c.baseClass) 4428 { 4429 foreach (v; c.fields) 4430 { 4431 if (v.inuse || v._scope is null || v._init is null || 4432 v._init.isVoidInitializer() || v.semanticRun >= PASS.semantic2done) 4433 continue; 4434 v.inuse++; 4435 v._init = v._init.initializerSemantic(v._scope, v.type, INITinterpret); 4436 import dmd.semantic2 : lowerStaticAAs; 4437 lowerStaticAAs(v, sc); 4438 v.inuse--; 4439 } 4440 } 4441 } 4442 4443 // When using `@nogc` exception handling, lower `throw new E(args)` to 4444 // `throw (__tmp = _d_newThrowable!E(), __tmp.__ctor(args), __tmp)`. 4445 if (global.params.ehnogc && exp.thrownew && 4446 !cd.isCOMclass() && !cd.isCPPclass()) 4447 { 4448 assert(cd.ctor); 4449 4450 Expression id = new IdentifierExp(exp.loc, Id.empty); 4451 id = new DotIdExp(exp.loc, id, Id.object); 4452 4453 auto tiargs = new Objects(); 4454 tiargs.push(exp.newtype); 4455 id = new DotTemplateInstanceExp(exp.loc, id, Id._d_newThrowable, tiargs); 4456 id = new CallExp(exp.loc, id).expressionSemantic(sc); 4457 4458 Expression idVal; 4459 Expression tmp = extractSideEffect(sc, "__tmpThrowable", idVal, id, true); 4460 // auto castTmp = new CastExp(exp.loc, tmp, exp.type); 4461 4462 auto ctor = new DotIdExp(exp.loc, tmp, Id.ctor).expressionSemantic(sc); 4463 auto ctorCall = new CallExp(exp.loc, ctor, exp.arguments); 4464 4465 id = Expression.combine(idVal, exp.argprefix).expressionSemantic(sc); 4466 id = Expression.combine(id, ctorCall).expressionSemantic(sc); 4467 // id = Expression.combine(id, castTmp).expressionSemantic(sc); 4468 4469 result = id.expressionSemantic(sc); 4470 return; 4471 } 4472 else if (sc.needsCodegen() && // interpreter doesn't need this lowered 4473 !exp.onstack && !exp.type.isscope()) // these won't use the GC 4474 { 4475 /* replace `new T(arguments)` with `core.lifetime._d_newclassT!T(arguments)` 4476 * or `_d_newclassTTrace` 4477 */ 4478 auto hook = global.params.tracegc ? Id._d_newclassTTrace : Id._d_newclassT; 4479 if (!verifyHookExist(exp.loc, *sc, hook, "new class")) 4480 return setError(); 4481 4482 Expression id = new IdentifierExp(exp.loc, Id.empty); 4483 id = new DotIdExp(exp.loc, id, Id.object); 4484 4485 auto tiargs = new Objects(); 4486 auto t = exp.newtype.unqualify(MODFlags.wild); // remove `inout` 4487 tiargs.push(t); 4488 id = new DotTemplateInstanceExp(exp.loc, id, hook, tiargs); 4489 auto arguments = new Expressions(); 4490 if (global.params.tracegc) 4491 { 4492 auto funcname = (sc.callsc && sc.callsc.func) ? 4493 sc.callsc.func.toPrettyChars() : sc.func.toPrettyChars(); 4494 arguments.push(new StringExp(exp.loc, exp.loc.filename.toDString())); 4495 arguments.push(new IntegerExp(exp.loc, exp.loc.linnum, Type.tint32)); 4496 arguments.push(new StringExp(exp.loc, funcname.toDString())); 4497 } 4498 id = new CallExp(exp.loc, id, arguments); 4499 4500 exp.lowering = id.expressionSemantic(sc); 4501 } 4502 } 4503 else if (auto ts = tb.isTypeStruct()) 4504 { 4505 auto sd = ts.sym; 4506 sd.size(exp.loc); 4507 if (sd.sizeok != Sizeok.done) 4508 return setError(); 4509 if (!sd.ctor) 4510 sd.ctor = sd.searchCtor(); 4511 if (sd.noDefaultCtor && !nargs) 4512 { 4513 error(exp.loc, "default construction is disabled for type `%s`", sd.type.toChars()); 4514 return setError(); 4515 } 4516 // checkDeprecated() is already done in newtype.typeSemantic(). 4517 4518 if (sd.disableNew) 4519 { 4520 error(exp.loc, "cannot allocate `struct %s` with `new` because it is annotated with `@disable new()`", 4521 originalNewtype.toChars()); 4522 return setError(); 4523 } 4524 4525 // https://issues.dlang.org/show_bug.cgi?id=22639 4526 // If the new expression has arguments, we either should call a 4527 // regular constructor of a copy constructor if the first argument 4528 // is the same type as the struct 4529 if (nargs && (sd.hasRegularCtor() || (sd.ctor && (*exp.arguments)[0].type.mutableOf() == sd.type.mutableOf()))) 4530 { 4531 FuncDeclaration f = resolveFuncCall(exp.loc, sc, sd.ctor, null, tb, exp.argumentList, FuncResolveFlag.standard); 4532 if (!f || f.errors) 4533 return setError(); 4534 4535 checkFunctionAttributes(exp, sc, f); 4536 checkAccess(sd, exp.loc, sc, f); 4537 4538 TypeFunction tf = f.type.isTypeFunction(); 4539 if (!exp.arguments) 4540 exp.arguments = new Expressions(); 4541 if (functionParameters(exp.loc, sc, tf, null, exp.type, exp.argumentList, f, &exp.type, &exp.argprefix)) 4542 return setError(); 4543 4544 exp.member = f.isCtorDeclaration(); 4545 assert(exp.member); 4546 4547 if (checkFrameAccess(exp.loc, sc, sd, sd.fields.length)) 4548 return setError(); 4549 } 4550 else 4551 { 4552 if (exp.names) 4553 { 4554 exp.arguments = resolveStructLiteralNamedArgs(sd, exp.type, sc, exp.loc, 4555 exp.names ? (*exp.names)[] : null, 4556 (size_t i, Type t) => (*exp.arguments)[i], 4557 i => (*exp.arguments)[i].loc 4558 ); 4559 if (!exp.arguments) 4560 return setError(); 4561 } 4562 else if (!exp.arguments) 4563 { 4564 exp.arguments = new Expressions(); 4565 } 4566 4567 if (!sd.fit(exp.loc, sc, exp.arguments, tb)) 4568 return setError(); 4569 4570 if (!sd.fill(exp.loc, *exp.arguments, false)) 4571 return setError(); 4572 4573 if (checkFrameAccess(exp.loc, sc, sd, exp.arguments ? exp.arguments.length : 0)) 4574 return setError(); 4575 4576 /* Since a `new` allocation may escape, check each of the arguments for escaping 4577 */ 4578 foreach (arg; *exp.arguments) 4579 { 4580 if (arg && checkNewEscape(sc, arg, false)) 4581 return setError(); 4582 } 4583 } 4584 4585 exp.type = exp.type.pointerTo(); 4586 tryLowerToNewItem(exp); 4587 } 4588 else if (tb.ty == Tarray) 4589 { 4590 if (!nargs) 4591 { 4592 // https://issues.dlang.org/show_bug.cgi?id=20422 4593 // Without this check the compiler would give a misleading error 4594 error(exp.loc, "missing length argument for array"); 4595 return setError(); 4596 } 4597 4598 Type tn = tb.nextOf().baseElemOf(); 4599 Dsymbol s = tn.toDsymbol(sc); 4600 AggregateDeclaration ad = s ? s.isAggregateDeclaration() : null; 4601 if (ad && ad.noDefaultCtor) 4602 { 4603 error(exp.loc, "default construction is disabled for type `%s`", tb.nextOf().toChars()); 4604 return setError(); 4605 } 4606 for (size_t i = 0; i < nargs; i++) 4607 { 4608 if (tb.ty != Tarray) 4609 { 4610 error(exp.loc, "too many arguments for array"); 4611 return setError(); 4612 } 4613 4614 Expression arg = (*exp.arguments)[i]; 4615 if (exp.names && (*exp.names)[i]) 4616 { 4617 error(exp.loc, "no named argument `%s` allowed for array dimension", (*exp.names)[i].toChars()); 4618 return setError(); 4619 } 4620 4621 arg = resolveProperties(sc, arg); 4622 arg = arg.implicitCastTo(sc, Type.tsize_t); 4623 if (arg.op == EXP.error) 4624 return setError(); 4625 arg = arg.optimize(WANTvalue); 4626 if (arg.op == EXP.int64 && (target.isLP64 ? 4627 cast(sinteger_t)arg.toInteger() : cast(int)arg.toInteger()) < 0) 4628 { 4629 error(exp.loc, "negative array dimension `%s`", (*exp.arguments)[i].toChars()); 4630 return setError(); 4631 } 4632 (*exp.arguments)[i] = arg; 4633 tb = tb.isTypeDArray().next.toBasetype(); 4634 } 4635 4636 if (nargs == 1) 4637 { 4638 if (global.params.betterC || !sc.needsCodegen()) 4639 goto LskipNewArrayLowering; 4640 4641 /* Class types may inherit base classes that have errors. 4642 * This may leak errors from the base class to the derived one 4643 * and then to the hook. Semantic analysis is performed eagerly 4644 * to a void this. 4645 */ 4646 if (auto tc = exp.type.nextOf.isTypeClass()) 4647 { 4648 tc.sym.dsymbolSemantic(sc); 4649 if (tc.sym.errors) 4650 goto LskipNewArrayLowering; 4651 } 4652 4653 auto hook = global.params.tracegc ? Id._d_newarrayTTrace : Id._d_newarrayT; 4654 if (!verifyHookExist(exp.loc, *sc, hook, "new array")) 4655 goto LskipNewArrayLowering; 4656 4657 /* Lower the memory allocation and initialization of `new T[n]` 4658 * to `_d_newarrayT!T(n)`. 4659 */ 4660 Expression lowering = new IdentifierExp(exp.loc, Id.empty); 4661 lowering = new DotIdExp(exp.loc, lowering, Id.object); 4662 auto tiargs = new Objects(); 4663 /* Remove `inout`, `const`, `immutable` and `shared` to reduce 4664 * the number of generated `_d_newarrayT` instances. 4665 */ 4666 const isShared = exp.type.nextOf.isShared(); 4667 auto t = exp.type.nextOf.unqualify(MODFlags.wild | MODFlags.const_ | 4668 MODFlags.immutable_ | MODFlags.shared_); 4669 tiargs.push(t); 4670 lowering = new DotTemplateInstanceExp(exp.loc, lowering, hook, tiargs); 4671 4672 auto arguments = new Expressions(); 4673 if (global.params.tracegc) 4674 { 4675 auto funcname = (sc.callsc && sc.callsc.func) ? 4676 sc.callsc.func.toPrettyChars() : sc.func.toPrettyChars(); 4677 arguments.push(new StringExp(exp.loc, exp.loc.filename.toDString())); 4678 arguments.push(new IntegerExp(exp.loc, exp.loc.linnum, Type.tint32)); 4679 arguments.push(new StringExp(exp.loc, funcname.toDString())); 4680 } 4681 arguments.push((*exp.arguments)[0]); 4682 arguments.push(new IntegerExp(exp.loc, isShared, Type.tbool)); 4683 4684 lowering = new CallExp(exp.loc, lowering, arguments); 4685 exp.lowering = lowering.expressionSemantic(sc); 4686 } 4687 } 4688 else if (tb.isscalar()) 4689 { 4690 if (!nargs) 4691 { 4692 } 4693 else if (nargs == 1) 4694 { 4695 if (exp.names && (*exp.names)[0]) 4696 { 4697 error(exp.loc, "no named argument `%s` allowed for scalar", (*exp.names)[0].toChars()); 4698 return setError(); 4699 } 4700 Expression e = (*exp.arguments)[0]; 4701 e = e.implicitCastTo(sc, tb); 4702 (*exp.arguments)[0] = e; 4703 } 4704 else 4705 { 4706 error(exp.loc, "more than one argument for construction of `%s`", exp.type.toChars()); 4707 return setError(); 4708 } 4709 4710 exp.type = exp.type.pointerTo(); 4711 tryLowerToNewItem(exp); 4712 } 4713 else if (tb.ty == Taarray) 4714 { 4715 // e.g. `new Alias(args)` 4716 if (nargs) 4717 { 4718 error(exp.loc, "`new` cannot take arguments for an associative array"); 4719 return setError(); 4720 } 4721 } 4722 else 4723 { 4724 error(exp.loc, "cannot create a `%s` with `new`", exp.type.toChars()); 4725 return setError(); 4726 } 4727 4728 LskipNewArrayLowering: 4729 //printf("NewExp: '%s'\n", toChars()); 4730 //printf("NewExp:type '%s'\n", type.toChars()); 4731 semanticTypeInfo(sc, exp.type); 4732 4733 if (newprefix) 4734 { 4735 result = Expression.combine(newprefix, exp); 4736 return; 4737 } 4738 result = exp; 4739 } 4740 4741 override void visit(NewAnonClassExp e) 4742 { 4743 static if (LOGSEMANTIC) 4744 { 4745 printf("NewAnonClassExp::semantic() %s\n", e.toChars()); 4746 //printf("thisexp = %p\n", thisexp); 4747 //printf("type: %s\n", type.toChars()); 4748 } 4749 4750 Expression d = new DeclarationExp(e.loc, e.cd); 4751 sc = sc.push(); // just create new scope 4752 sc.flags &= ~SCOPE.ctfe; // temporary stop CTFE 4753 d = d.expressionSemantic(sc); 4754 sc = sc.pop(); 4755 4756 if (!e.cd.errors && sc.intypeof && !sc.parent.inNonRoot()) 4757 { 4758 ScopeDsymbol sds = sc.tinst ? cast(ScopeDsymbol)sc.tinst : sc._module; 4759 if (!sds.members) 4760 sds.members = new Dsymbols(); 4761 sds.members.push(e.cd); 4762 } 4763 4764 Expression n = new NewExp(e.loc, e.thisexp, e.cd.type, e.arguments); 4765 4766 Expression c = new CommaExp(e.loc, d, n); 4767 result = c.expressionSemantic(sc); 4768 } 4769 4770 override void visit(SymOffExp e) 4771 { 4772 static if (LOGSEMANTIC) 4773 { 4774 printf("SymOffExp::semantic('%s')\n", e.toChars()); 4775 } 4776 //var.dsymbolSemantic(sc); 4777 if (!e.type) 4778 e.type = e.var.type.pointerTo(); 4779 4780 if (auto v = e.var.isVarDeclaration()) 4781 { 4782 if (v.checkNestedReference(sc, e.loc)) 4783 return setError(); 4784 } 4785 else if (auto f = e.var.isFuncDeclaration()) 4786 { 4787 if (f.checkNestedReference(sc, e.loc)) 4788 return setError(); 4789 } 4790 4791 result = e; 4792 } 4793 4794 override void visit(VarExp e) 4795 { 4796 static if (LOGSEMANTIC) 4797 { 4798 printf("VarExp::semantic(%s)\n", e.toChars()); 4799 } 4800 4801 auto vd = e.var.isVarDeclaration(); 4802 auto fd = e.var.isFuncDeclaration(); 4803 4804 if (fd) 4805 { 4806 //printf("L%d fd = %s\n", __LINE__, f.toChars()); 4807 if (!fd.functionSemantic()) 4808 return setError(); 4809 } 4810 4811 if (!e.type) 4812 e.type = e.var.type; 4813 if (e.type && !e.type.deco) 4814 { 4815 auto decl = e.var.isDeclaration(); 4816 if (decl) 4817 decl.inuse++; 4818 e.type = e.type.typeSemantic(e.loc, sc); 4819 if (decl) 4820 decl.inuse--; 4821 } 4822 4823 /* Fix for 1161 doesn't work because it causes visibility 4824 * problems when instantiating imported templates passing private 4825 * variables as alias template parameters. 4826 */ 4827 //checkAccess(loc, sc, NULL, var); 4828 4829 if (vd) 4830 { 4831 if (vd.checkNestedReference(sc, e.loc)) 4832 return setError(); 4833 4834 // https://issues.dlang.org/show_bug.cgi?id=12025 4835 // If the variable is not actually used in runtime code, 4836 // the purity violation error is redundant. 4837 //checkPurity(sc, vd); 4838 } 4839 else if (fd) 4840 { 4841 // TODO: If fd isn't yet resolved its overload, the checkNestedReference 4842 // call would cause incorrect validation. 4843 // Maybe here should be moved in CallExp, or AddrExp for functions. 4844 if (fd.checkNestedReference(sc, e.loc)) 4845 return setError(); 4846 } 4847 else if (auto od = e.var.isOverDeclaration()) 4848 { 4849 e.type = Type.tvoid; // ambiguous type? 4850 } 4851 4852 result = e; 4853 } 4854 4855 override void visit(FuncExp exp) 4856 { 4857 static if (LOGSEMANTIC) 4858 { 4859 printf("FuncExp::semantic(%s)\n", exp.toChars()); 4860 if (exp.fd.treq) 4861 printf(" treq = %s\n", exp.fd.treq.toChars()); 4862 } 4863 4864 if (exp.type) 4865 { 4866 result = exp; 4867 return; 4868 } 4869 4870 Expression e = exp; 4871 uint olderrors; 4872 4873 sc = sc.push(); // just create new scope 4874 sc.flags &= ~SCOPE.ctfe; // temporary stop CTFE 4875 sc.visibility = Visibility(Visibility.Kind.public_); // https://issues.dlang.org/show_bug.cgi?id=12506 4876 4877 /* fd.treq might be incomplete type, 4878 * so should not semantic it. 4879 * void foo(T)(T delegate(int) dg){} 4880 * foo(a=>a); // in IFTI, treq == T delegate(int) 4881 */ 4882 //if (fd.treq) 4883 // fd.treq = fd.treq.dsymbolSemantic(loc, sc); 4884 4885 exp.genIdent(sc); 4886 4887 // Set target of return type inference 4888 if (exp.fd.treq && !exp.fd.type.nextOf()) 4889 { 4890 TypeFunction tfv = null; 4891 if (exp.fd.treq.ty == Tdelegate || exp.fd.treq.isPtrToFunction()) 4892 tfv = cast(TypeFunction)exp.fd.treq.nextOf(); 4893 if (tfv) 4894 { 4895 TypeFunction tfl = cast(TypeFunction)exp.fd.type; 4896 tfl.next = tfv.nextOf(); 4897 } 4898 } 4899 4900 //printf("td = %p, treq = %p\n", td, fd.treq); 4901 if (exp.td) 4902 { 4903 assert(exp.td.parameters && exp.td.parameters.length); 4904 exp.td.dsymbolSemantic(sc); 4905 exp.type = Type.tvoid; // temporary type 4906 4907 if (exp.fd.treq) // defer type determination 4908 { 4909 FuncExp fe; 4910 if (exp.matchType(exp.fd.treq, sc, &fe, sc.eSink) > MATCH.nomatch) 4911 e = fe; 4912 else 4913 e = ErrorExp.get(); 4914 } 4915 goto Ldone; 4916 } 4917 4918 olderrors = global.errors; 4919 exp.fd.dsymbolSemantic(sc); 4920 if (olderrors == global.errors) 4921 { 4922 exp.fd.semantic2(sc); 4923 if (olderrors == global.errors) 4924 exp.fd.semantic3(sc); 4925 } 4926 if (olderrors != global.errors) 4927 { 4928 if (exp.fd.type && exp.fd.type.ty == Tfunction && !exp.fd.type.nextOf()) 4929 (cast(TypeFunction)exp.fd.type).next = Type.terror; 4930 e = ErrorExp.get(); 4931 goto Ldone; 4932 } 4933 4934 // Type is a "delegate to" or "pointer to" the function literal 4935 if ((exp.fd.isNested() && exp.fd.tok == TOK.delegate_) || (exp.tok == TOK.reserved && exp.fd.treq && exp.fd.treq.ty == Tdelegate)) 4936 { 4937 // https://issues.dlang.org/show_bug.cgi?id=22686 4938 // if the delegate return type is an error 4939 // abort semantic of the FuncExp and propagate 4940 // the error 4941 if (exp.fd.type.isTypeError()) 4942 { 4943 e = ErrorExp.get(); 4944 goto Ldone; 4945 } 4946 exp.type = new TypeDelegate(exp.fd.type.isTypeFunction()); 4947 exp.type = exp.type.typeSemantic(exp.loc, sc); 4948 4949 exp.fd.tok = TOK.delegate_; 4950 } 4951 else 4952 { 4953 exp.type = new TypePointer(exp.fd.type); 4954 exp.type = exp.type.typeSemantic(exp.loc, sc); 4955 //type = fd.type.pointerTo(); 4956 4957 /* A lambda expression deduced to function pointer might become 4958 * to a delegate literal implicitly. 4959 * 4960 * auto foo(void function() fp) { return 1; } 4961 * assert(foo({}) == 1); 4962 * 4963 * So, should keep fd.tok == TOK.reserve if fd.treq == NULL. 4964 */ 4965 if (exp.fd.treq && exp.fd.treq.ty == Tpointer) 4966 { 4967 // change to non-nested 4968 exp.fd.tok = TOK.function_; 4969 exp.fd.vthis = null; 4970 } 4971 } 4972 exp.fd.tookAddressOf++; 4973 4974 Ldone: 4975 sc = sc.pop(); 4976 result = e; 4977 } 4978 4979 /** 4980 * Perform semantic analysis on function literals 4981 * 4982 * Test the following construct: 4983 * --- 4984 * (x, y, z) { return x + y + z; }(42, 84, 1992); 4985 * --- 4986 */ 4987 Expression callExpSemantic(FuncExp exp, Scope* sc, Expressions* arguments) 4988 { 4989 if ((!exp.type || exp.type == Type.tvoid) && exp.td && arguments && arguments.length) 4990 { 4991 for (size_t k = 0; k < arguments.length; k++) 4992 { 4993 Expression checkarg = (*arguments)[k]; 4994 if (checkarg.op == EXP.error) 4995 return checkarg; 4996 } 4997 4998 exp.genIdent(sc); 4999 5000 assert(exp.td.parameters && exp.td.parameters.length); 5001 exp.td.dsymbolSemantic(sc); 5002 5003 TypeFunction tfl = cast(TypeFunction)exp.fd.type; 5004 size_t dim = tfl.parameterList.length; 5005 if (arguments.length < dim) 5006 { 5007 // Default arguments are always typed, so they don't need inference. 5008 Parameter p = tfl.parameterList[arguments.length]; 5009 if (p.defaultArg) 5010 dim = arguments.length; 5011 } 5012 5013 if ((tfl.parameterList.varargs == VarArg.none && arguments.length > dim) || 5014 arguments.length < dim) 5015 { 5016 OutBuffer buf; 5017 foreach (idx, ref arg; *arguments) 5018 buf.printf("%s%s", (idx ? ", ".ptr : "".ptr), arg.type.toChars()); 5019 error(exp.loc, "function literal `%s%s` is not callable using argument types `(%s)`", 5020 exp.fd.toChars(), parametersTypeToChars(tfl.parameterList), 5021 buf.peekChars()); 5022 errorSupplemental(exp.loc, "too %s arguments, expected %d, got %d", 5023 arguments.length < dim ? "few".ptr : "many".ptr, 5024 cast(int)dim, cast(int)arguments.length); 5025 return ErrorExp.get(); 5026 } 5027 5028 auto tiargs = new Objects(); 5029 tiargs.reserve(exp.td.parameters.length); 5030 5031 for (size_t i = 0; i < exp.td.parameters.length; i++) 5032 { 5033 TemplateParameter tp = (*exp.td.parameters)[i]; 5034 assert(dim <= tfl.parameterList.length); 5035 foreach (u, p; tfl.parameterList) 5036 { 5037 if (u == dim) 5038 break; 5039 5040 if (p.type.ty == Tident && (cast(TypeIdentifier)p.type).ident == tp.ident) 5041 { 5042 Expression e = (*arguments)[u]; 5043 tiargs.push(e.type); 5044 break; 5045 } 5046 } 5047 } 5048 5049 auto ti = new TemplateInstance(exp.loc, exp.td, tiargs); 5050 return (new ScopeExp(exp.loc, ti)).expressionSemantic(sc); 5051 } 5052 return exp.expressionSemantic(sc); 5053 } 5054 5055 override void visit(CallExp exp) 5056 { 5057 static if (LOGSEMANTIC) 5058 { 5059 printf("CallExp::semantic() %s\n", exp.toChars()); 5060 } 5061 if (exp.type) 5062 { 5063 result = exp; 5064 return; // semantic() already run 5065 } 5066 5067 Objects* tiargs = null; // initial list of template arguments 5068 Expression ethis = null; 5069 Type tthis = null; 5070 Expression e1org = exp.e1; 5071 5072 if (auto ce = exp.e1.isCommaExp()) 5073 { 5074 /* Rewrite (a,b)(args) as (a,(b(args))) 5075 */ 5076 exp.e1 = ce.e2; 5077 ce.e2 = exp; 5078 result = ce.expressionSemantic(sc); 5079 return; 5080 } 5081 if (DelegateExp de = exp.e1.isDelegateExp()) 5082 { 5083 exp.e1 = new DotVarExp(de.loc, de.e1, de.func, de.hasOverloads); 5084 visit(exp); 5085 return; 5086 } 5087 if (FuncExp fe = exp.e1.isFuncExp()) 5088 { 5089 if (arrayExpressionSemantic(exp.arguments.peekSlice(), sc) || 5090 preFunctionParameters(sc, exp.argumentList)) 5091 return setError(); 5092 5093 // Run e1 semantic even if arguments have any errors 5094 exp.e1 = callExpSemantic(fe, sc, exp.arguments); 5095 if (exp.e1.op == EXP.error) 5096 { 5097 result = exp.e1; 5098 return; 5099 } 5100 } 5101 if (sc.flags & SCOPE.Cfile) 5102 { 5103 /* See if need to rewrite the AST because of cast/call ambiguity 5104 */ 5105 if (auto e = castCallAmbiguity(exp, sc)) 5106 { 5107 result = expressionSemantic(e, sc); 5108 return; 5109 } 5110 } 5111 5112 if (Expression ex = resolveUFCS(sc, exp)) 5113 { 5114 result = ex; 5115 return; 5116 } 5117 5118 /* This recognizes: 5119 * foo!(tiargs)(funcargs) 5120 */ 5121 if (ScopeExp se = exp.e1.isScopeExp()) 5122 { 5123 TemplateInstance ti = se.sds.isTemplateInstance(); 5124 if (ti) 5125 { 5126 /* Attempt to instantiate ti. If that works, go with it. 5127 * If not, go with partial explicit specialization. 5128 */ 5129 WithScopeSymbol withsym; 5130 if (!ti.findTempDecl(sc, &withsym) || !ti.semanticTiargs(sc)) 5131 return setError(); 5132 if (withsym && withsym.withstate.wthis) 5133 { 5134 exp.e1 = new VarExp(exp.e1.loc, withsym.withstate.wthis); 5135 exp.e1 = new DotTemplateInstanceExp(exp.e1.loc, exp.e1, ti); 5136 goto Ldotti; 5137 } 5138 if (ti.needsTypeInference(sc, 1)) 5139 { 5140 /* Go with partial explicit specialization 5141 */ 5142 tiargs = ti.tiargs; 5143 assert(ti.tempdecl); 5144 if (TemplateDeclaration td = ti.tempdecl.isTemplateDeclaration()) 5145 exp.e1 = new TemplateExp(exp.loc, td); 5146 else if (OverDeclaration od = ti.tempdecl.isOverDeclaration()) 5147 exp.e1 = new VarExp(exp.loc, od); 5148 else 5149 exp.e1 = new OverExp(exp.loc, ti.tempdecl.isOverloadSet()); 5150 } 5151 else 5152 { 5153 Expression e1x = exp.e1.expressionSemantic(sc); 5154 if (e1x.op == EXP.error) 5155 { 5156 result = e1x; 5157 return; 5158 } 5159 exp.e1 = e1x; 5160 } 5161 } 5162 } 5163 5164 /* This recognizes: 5165 * expr.foo!(tiargs)(funcargs) 5166 */ 5167 Ldotti: 5168 if (DotTemplateInstanceExp se = exp.e1.isDotTemplateInstanceExp()) 5169 { 5170 TemplateInstance ti = se.ti; 5171 { 5172 /* Attempt to instantiate ti. If that works, go with it. 5173 * If not, go with partial explicit specialization. 5174 */ 5175 if (!se.findTempDecl(sc) || !ti.semanticTiargs(sc)) 5176 return setError(); 5177 if (ti.needsTypeInference(sc, 1)) 5178 { 5179 /* Go with partial explicit specialization 5180 */ 5181 tiargs = ti.tiargs; 5182 assert(ti.tempdecl); 5183 if (TemplateDeclaration td = ti.tempdecl.isTemplateDeclaration()) 5184 exp.e1 = new DotTemplateExp(exp.loc, se.e1, td); 5185 else if (OverDeclaration od = ti.tempdecl.isOverDeclaration()) 5186 { 5187 exp.e1 = new DotVarExp(exp.loc, se.e1, od, true); 5188 } 5189 else 5190 exp.e1 = new DotExp(exp.loc, se.e1, new OverExp(exp.loc, ti.tempdecl.isOverloadSet())); 5191 } 5192 else 5193 { 5194 Expression e1x = exp.e1.expressionSemantic(sc); 5195 if (e1x.op == EXP.error) 5196 { 5197 result = e1x; 5198 return; 5199 } 5200 exp.e1 = e1x; 5201 } 5202 } 5203 } 5204 5205 Type att = null; 5206 Lagain: 5207 //printf("Lagain: %s\n", toChars()); 5208 exp.f = null; 5209 if (exp.e1.op == EXP.this_ || exp.e1.op == EXP.super_) 5210 { 5211 // semantic() run later for these 5212 } 5213 else 5214 { 5215 if (DotIdExp die = exp.e1.isDotIdExp()) 5216 { 5217 exp.e1 = die.expressionSemantic(sc); 5218 /* Look for e1 having been rewritten to expr.opDispatch!(string) 5219 * We handle such earlier, so go back. 5220 * Note that in the rewrite, we carefully did not run semantic() on e1 5221 */ 5222 if (exp.e1.op == EXP.dotTemplateInstance) 5223 { 5224 goto Ldotti; 5225 } 5226 } 5227 else 5228 { 5229 __gshared int nest; 5230 if (++nest > global.recursionLimit) 5231 { 5232 error(exp.loc, "recursive evaluation of `%s`", exp.toChars()); 5233 --nest; 5234 return setError(); 5235 } 5236 Expression ex = unaSemantic(exp, sc); 5237 --nest; 5238 if (ex) 5239 { 5240 result = ex; 5241 return; 5242 } 5243 } 5244 5245 /* Look for e1 being a lazy parameter 5246 */ 5247 if (VarExp ve = exp.e1.isVarExp()) 5248 { 5249 if (ve.var.storage_class & STC.lazy_) 5250 { 5251 // lazy parameters can be called without violating purity and safety 5252 Type tw = ve.var.type; 5253 Type tc = ve.var.type.substWildTo(MODFlags.const_); 5254 auto tf = new TypeFunction(ParameterList(), tc, LINK.d, STC.safe | STC.pure_); 5255 (tf = cast(TypeFunction)tf.typeSemantic(exp.loc, sc)).next = tw; // hack for bug7757 5256 auto t = new TypeDelegate(tf); 5257 ve.type = t.typeSemantic(exp.loc, sc); 5258 } 5259 VarDeclaration v = ve.var.isVarDeclaration(); 5260 if (v && ve.checkPurity(sc, v)) 5261 return setError(); 5262 } 5263 5264 if (exp.e1.op == EXP.symbolOffset && (cast(SymOffExp)exp.e1).hasOverloads) 5265 { 5266 SymOffExp se = cast(SymOffExp)exp.e1; 5267 exp.e1 = new VarExp(se.loc, se.var, true); 5268 exp.e1 = exp.e1.expressionSemantic(sc); 5269 } 5270 else if (DotExp de = exp.e1.isDotExp()) 5271 { 5272 if (de.e2.op == EXP.overloadSet) 5273 { 5274 ethis = de.e1; 5275 tthis = de.e1.type; 5276 exp.e1 = de.e2; 5277 } 5278 } 5279 else if (exp.e1.op == EXP.star && exp.e1.type.ty == Tfunction) 5280 { 5281 // Rewrite (*fp)(arguments) to fp(arguments) 5282 exp.e1 = (cast(PtrExp)exp.e1).e1; 5283 } 5284 else if (exp.e1.op == EXP.type && (sc && sc.flags & SCOPE.Cfile)) 5285 { 5286 const numArgs = exp.arguments ? exp.arguments.length : 0; 5287 5288 /* Ambiguous cases arise from CParser where there is not enough 5289 * information to determine if we have a function call or declaration. 5290 * type-name ( identifier ) ; 5291 * identifier ( identifier ) ; 5292 * If exp.e1 is a type-name, then this is a declaration. C11 does not 5293 * have type construction syntax, so don't convert this to a cast(). 5294 */ 5295 if (numArgs == 1) 5296 { 5297 Expression arg = (*exp.arguments)[0]; 5298 if (auto ie = (*exp.arguments)[0].isIdentifierExp()) 5299 { 5300 TypeExp te = cast(TypeExp)exp.e1; 5301 auto initializer = new VoidInitializer(ie.loc); 5302 Dsymbol s = new VarDeclaration(ie.loc, te.type, ie.ident, initializer); 5303 auto decls = new Dsymbols(1); 5304 (*decls)[0] = s; 5305 s = new LinkDeclaration(s.loc, LINK.c, decls); 5306 result = new DeclarationExp(exp.loc, s); 5307 result = result.expressionSemantic(sc); 5308 } 5309 else 5310 { 5311 error(arg.loc, "identifier or `(` expected"); 5312 result = ErrorExp.get(); 5313 } 5314 return; 5315 } 5316 error(exp.loc, "identifier or `(` expected before `)`"); 5317 result = ErrorExp.get(); 5318 return; 5319 } 5320 } 5321 5322 Type t1 = exp.e1.type ? exp.e1.type.toBasetype() : null; 5323 5324 if (exp.e1.op == EXP.error) 5325 { 5326 result = exp.e1; 5327 return; 5328 } 5329 if (arrayExpressionSemantic(exp.arguments.peekSlice(), sc) || 5330 preFunctionParameters(sc, exp.argumentList)) 5331 return setError(); 5332 5333 // Check for call operator overload 5334 if (t1) 5335 { 5336 if (t1.ty == Tstruct) 5337 { 5338 auto sd = (cast(TypeStruct)t1).sym; 5339 sd.size(exp.loc); // Resolve forward references to construct object 5340 if (sd.sizeok != Sizeok.done) 5341 return setError(); 5342 if (!sd.ctor) 5343 sd.ctor = sd.searchCtor(); 5344 /* If `sd.ctor` is a generated copy constructor, this means that it 5345 is the single constructor that this struct has. In order to not 5346 disable default construction, the ctor is nullified. The side effect 5347 of this is that the generated copy constructor cannot be called 5348 explicitly, but that is ok, because when calling a constructor the 5349 default constructor should have priority over the generated copy 5350 constructor. 5351 */ 5352 if (sd.ctor) 5353 { 5354 auto ctor = sd.ctor.isCtorDeclaration(); 5355 if (ctor && ctor.isCpCtor && ctor.isGenerated()) 5356 sd.ctor = null; 5357 } 5358 5359 // First look for constructor 5360 if (exp.e1.op == EXP.type && sd.ctor) 5361 { 5362 if (!sd.noDefaultCtor && !(exp.arguments && exp.arguments.length)) 5363 goto Lx; 5364 5365 /* https://issues.dlang.org/show_bug.cgi?id=20695 5366 If all constructors are copy constructors, then 5367 try default construction. 5368 */ 5369 if (!sd.hasRegularCtor && 5370 // https://issues.dlang.org/show_bug.cgi?id=22639 5371 // we might still have a copy constructor that could be called 5372 (*exp.arguments)[0].type.mutableOf != sd.type.mutableOf()) 5373 goto Lx; 5374 5375 auto sle = new StructLiteralExp(exp.loc, sd, null, exp.e1.type); 5376 if (!sd.fill(exp.loc, *sle.elements, true)) 5377 return setError(); 5378 if (checkFrameAccess(exp.loc, sc, sd, sle.elements.length)) 5379 return setError(); 5380 5381 // https://issues.dlang.org/show_bug.cgi?id=14556 5382 // Set concrete type to avoid further redundant semantic(). 5383 sle.type = exp.e1.type; 5384 5385 /* Constructor takes a mutable object, so don't use 5386 * the immutable initializer symbol. 5387 */ 5388 sle.useStaticInit = false; 5389 5390 Expression e = sle; 5391 if (auto cf = sd.ctor.isCtorDeclaration()) 5392 { 5393 e = new DotVarExp(exp.loc, e, cf, true); 5394 } 5395 else if (auto td = sd.ctor.isTemplateDeclaration()) 5396 { 5397 e = new DotIdExp(exp.loc, e, td.ident); 5398 } 5399 else if (auto os = sd.ctor.isOverloadSet()) 5400 { 5401 e = new DotExp(exp.loc, e, new OverExp(exp.loc, os)); 5402 } 5403 else 5404 assert(0); 5405 e = new CallExp(exp.loc, e, exp.arguments); 5406 e = e.expressionSemantic(sc); 5407 result = e; 5408 return; 5409 } 5410 // No constructor, look for overload of opCall 5411 if (search_function(sd, Id.call)) 5412 goto L1; 5413 // overload of opCall, therefore it's a call 5414 if (exp.e1.op != EXP.type) 5415 { 5416 if (sd.aliasthis && !isRecursiveAliasThis(att, exp.e1.type)) 5417 { 5418 exp.e1 = resolveAliasThis(sc, exp.e1); 5419 goto Lagain; 5420 } 5421 error(exp.loc, "%s `%s` does not overload ()", sd.kind(), sd.toChars()); 5422 return setError(); 5423 } 5424 5425 /* It's a struct literal 5426 */ 5427 Lx: 5428 Expressions* resolvedArgs = exp.arguments; 5429 if (exp.names) 5430 { 5431 resolvedArgs = resolveStructLiteralNamedArgs(sd, exp.e1.type, sc, exp.loc, 5432 (*exp.names)[], 5433 (size_t i, Type t) => (*exp.arguments)[i], 5434 i => (*exp.arguments)[i].loc 5435 ); 5436 if (!resolvedArgs) 5437 { 5438 result = ErrorExp.get(); 5439 return; 5440 } 5441 } 5442 5443 Expression e = new StructLiteralExp(exp.loc, sd, resolvedArgs, exp.e1.type); 5444 e = e.expressionSemantic(sc); 5445 result = e; 5446 return; 5447 } 5448 else if (t1.ty == Tclass) 5449 { 5450 L1: 5451 // Rewrite as e1.call(arguments) 5452 Expression e = new DotIdExp(exp.loc, exp.e1, Id.call); 5453 e = new CallExp(exp.loc, e, exp.arguments, exp.names); 5454 e = e.expressionSemantic(sc); 5455 result = e; 5456 return; 5457 } 5458 else if (exp.e1.op == EXP.type && t1.isscalar()) 5459 { 5460 Expression e; 5461 5462 // Make sure to use the enum type itself rather than its 5463 // base type 5464 // https://issues.dlang.org/show_bug.cgi?id=16346 5465 if (exp.e1.type.ty == Tenum) 5466 { 5467 t1 = exp.e1.type; 5468 } 5469 5470 if (!exp.arguments || exp.arguments.length == 0) 5471 { 5472 e = t1.defaultInitLiteral(exp.loc); 5473 } 5474 else if (exp.arguments.length == 1) 5475 { 5476 e = (*exp.arguments)[0]; 5477 e = e.implicitCastTo(sc, t1); 5478 e = new CastExp(exp.loc, e, t1); 5479 } 5480 else 5481 { 5482 error(exp.loc, "more than one argument for construction of `%s`", t1.toChars()); 5483 return setError(); 5484 } 5485 e = e.expressionSemantic(sc); 5486 result = e; 5487 return; 5488 } 5489 } 5490 5491 FuncDeclaration resolveOverloadSet(Loc loc, Scope* sc, 5492 OverloadSet os, Objects* tiargs, Type tthis, ArgumentList argumentList) 5493 { 5494 FuncDeclaration f = null; 5495 foreach (s; os.a) 5496 { 5497 if (tiargs && s.isFuncDeclaration()) 5498 continue; 5499 if (auto f2 = resolveFuncCall(loc, sc, s, tiargs, tthis, argumentList, FuncResolveFlag.quiet)) 5500 { 5501 if (f2.errors) 5502 return null; 5503 if (f) 5504 { 5505 /* Match in more than one overload set, 5506 * even if one is a 'better' match than the other. 5507 */ 5508 if (f.isCsymbol() && f2.isCsymbol()) 5509 { 5510 /* C has global name space, so just pick one, such as f. 5511 * If f and f2 are not compatible, that's how C rolls. 5512 */ 5513 } 5514 else 5515 ScopeDsymbol.multiplyDefined(loc, f, f2); // issue error 5516 } 5517 else 5518 f = f2; 5519 } 5520 } 5521 if (!f) 5522 { 5523 .error(loc, "no overload matches for `%s`", exp.toChars()); 5524 errorSupplemental(loc, "Candidates are:"); 5525 foreach (s; os.a) 5526 { 5527 overloadApply(s, (ds){ 5528 if (auto fd = ds.isFuncDeclaration()) 5529 .errorSupplemental(ds.loc, "%s%s", fd.toChars(), 5530 fd.type.toTypeFunction().parameterList.parametersTypeToChars()); 5531 else 5532 .errorSupplemental(ds.loc, "%s", ds.toChars()); 5533 return 0; 5534 }); 5535 } 5536 } 5537 else if (f.errors) 5538 f = null; 5539 return f; 5540 } 5541 5542 bool isSuper = false; 5543 if (exp.e1.op == EXP.dotVariable && t1.ty == Tfunction || exp.e1.op == EXP.dotTemplateDeclaration) 5544 { 5545 UnaExp ue = cast(UnaExp)exp.e1; 5546 5547 Expression ue1old = ue.e1; // need for 'right this' check 5548 DotVarExp dve; 5549 DotTemplateExp dte; 5550 Dsymbol s; 5551 if (exp.e1.op == EXP.dotVariable) 5552 { 5553 dve = cast(DotVarExp)exp.e1; 5554 dte = null; 5555 s = dve.var; 5556 tiargs = null; 5557 } 5558 else 5559 { 5560 dve = null; 5561 dte = cast(DotTemplateExp)exp.e1; 5562 s = dte.td; 5563 } 5564 5565 // Do overload resolution 5566 exp.f = resolveFuncCall(exp.loc, sc, s, tiargs, ue.e1.type, exp.argumentList, FuncResolveFlag.standard); 5567 if (!exp.f || exp.f.errors || exp.f.type.ty == Terror) 5568 return setError(); 5569 5570 if (exp.f.interfaceVirtual) 5571 { 5572 /* Cast 'this' to the type of the interface, and replace f with the interface's equivalent 5573 */ 5574 auto b = exp.f.interfaceVirtual; 5575 auto ad2 = b.sym; 5576 ue.e1 = ue.e1.castTo(sc, ad2.type.addMod(ue.e1.type.mod)); 5577 ue.e1 = ue.e1.expressionSemantic(sc); 5578 auto vi = exp.f.findVtblIndex(&ad2.vtbl, cast(int)ad2.vtbl.length); 5579 assert(vi >= 0); 5580 exp.f = ad2.vtbl[vi].isFuncDeclaration(); 5581 assert(exp.f); 5582 } 5583 if (exp.f.needThis()) 5584 { 5585 AggregateDeclaration ad = exp.f.isMemberLocal(); 5586 ue.e1 = getRightThis(exp.loc, sc, ad, ue.e1, exp.f); 5587 if (ue.e1.op == EXP.error) 5588 { 5589 result = ue.e1; 5590 return; 5591 } 5592 ethis = ue.e1; 5593 tthis = ue.e1.type; 5594 if (!(exp.f.type.ty == Tfunction && (cast(TypeFunction)exp.f.type).isScopeQual)) 5595 { 5596 if (checkParamArgumentEscape(sc, exp.f, Id.This, exp.f.vthis, STC.undefined_, ethis, false, false)) 5597 return setError(); 5598 } 5599 } 5600 5601 /* Cannot call public functions from inside invariant 5602 * (because then the invariant would have infinite recursion) 5603 */ 5604 if (sc.func && sc.func.isInvariantDeclaration() && ue.e1.op == EXP.this_ && exp.f.addPostInvariant()) 5605 { 5606 error(exp.loc, "cannot call `public`/`export` function `%s` from invariant", exp.f.toChars()); 5607 return setError(); 5608 } 5609 5610 if (!exp.ignoreAttributes) 5611 checkFunctionAttributes(exp, sc, exp.f); 5612 5613 // Cut-down version of checkAccess() that doesn't use the "most visible" version of exp.f. 5614 // We've already selected an overload here. 5615 const parent = exp.f.toParent(); 5616 if (parent && parent.isTemplateInstance()) 5617 { 5618 // already a deprecation 5619 } 5620 else if (!checkSymbolAccess(sc, exp.f)) 5621 { 5622 error(exp.loc, "%s `%s` of type `%s` is not accessible from module `%s`", 5623 exp.f.kind(), exp.f.toPrettyChars(), exp.f.type.toChars(), sc._module.toChars); 5624 return setError(); 5625 } 5626 5627 if (!exp.f.needThis()) 5628 { 5629 exp.e1 = Expression.combine(ue.e1, new VarExp(exp.loc, exp.f, false)); 5630 } 5631 else 5632 { 5633 if (ue1old.checkRightThis(sc)) 5634 return setError(); 5635 if (exp.e1.op == EXP.dotVariable) 5636 { 5637 dve.var = exp.f; 5638 exp.e1.type = exp.f.type; 5639 } 5640 else 5641 { 5642 exp.e1 = new DotVarExp(exp.loc, dte.e1, exp.f, false); 5643 exp.e1 = exp.e1.expressionSemantic(sc); 5644 if (exp.e1.op == EXP.error) 5645 return setError(); 5646 ue = cast(UnaExp)exp.e1; 5647 } 5648 version (none) 5649 { 5650 printf("ue.e1 = %s\n", ue.e1.toChars()); 5651 printf("f = %s\n", exp.f.toChars()); 5652 printf("t1 = %s\n", t1.toChars()); 5653 printf("e1 = %s\n", exp.e1.toChars()); 5654 printf("e1.type = %s\n", exp.e1.type.toChars()); 5655 } 5656 5657 // See if we need to adjust the 'this' pointer 5658 AggregateDeclaration ad = exp.f.isThis(); 5659 ClassDeclaration cd = ue.e1.type.isClassHandle(); 5660 if (ad && cd && ad.isClassDeclaration()) 5661 { 5662 if (ue.e1.op == EXP.dotType) 5663 { 5664 ue.e1 = (cast(DotTypeExp)ue.e1).e1; 5665 exp.directcall = true; 5666 } 5667 else if (ue.e1.op == EXP.super_) 5668 exp.directcall = true; 5669 else if ((cd.storage_class & STC.final_) != 0) // https://issues.dlang.org/show_bug.cgi?id=14211 5670 exp.directcall = true; 5671 5672 if (ad != cd) 5673 { 5674 ue.e1 = ue.e1.castTo(sc, ad.type.addMod(ue.e1.type.mod)); 5675 ue.e1 = ue.e1.expressionSemantic(sc); 5676 } 5677 } 5678 } 5679 // If we've got a pointer to a function then deference it 5680 // https://issues.dlang.org/show_bug.cgi?id=16483 5681 if (exp.e1.type.isPtrToFunction()) 5682 { 5683 Expression e = new PtrExp(exp.loc, exp.e1); 5684 e.type = exp.e1.type.nextOf(); 5685 exp.e1 = e; 5686 } 5687 t1 = exp.e1.type; 5688 } 5689 else if (exp.e1.op == EXP.super_ || exp.e1.op == EXP.this_) 5690 { 5691 auto ad = sc.func ? sc.func.isThis() : null; 5692 auto cd = ad ? ad.isClassDeclaration() : null; 5693 5694 isSuper = exp.e1.op == EXP.super_; 5695 if (isSuper) 5696 { 5697 // Base class constructor call 5698 if (!cd || !cd.baseClass || !sc.func.isCtorDeclaration()) 5699 { 5700 error(exp.loc, "super class constructor call must be in a constructor"); 5701 return setError(); 5702 } 5703 if (!cd.baseClass.ctor) 5704 { 5705 error(exp.loc, "no super class constructor for `%s`", cd.baseClass.toChars()); 5706 return setError(); 5707 } 5708 } 5709 else 5710 { 5711 // `this` call expression must be inside a 5712 // constructor 5713 if (!ad || !sc.func.isCtorDeclaration()) 5714 { 5715 error(exp.loc, "constructor call must be in a constructor"); 5716 return setError(); 5717 } 5718 5719 // https://issues.dlang.org/show_bug.cgi?id=18719 5720 // If `exp` is a call expression to another constructor 5721 // then it means that all struct/class fields will be 5722 // initialized after this call. 5723 foreach (ref field; sc.ctorflow.fieldinit) 5724 { 5725 field.csx |= CSX.this_ctor; 5726 } 5727 } 5728 5729 if (!sc.intypeof && !(sc.ctorflow.callSuper & CSX.halt)) 5730 { 5731 if (sc.inLoop || sc.ctorflow.callSuper & CSX.label) 5732 error(exp.loc, "constructor calls not allowed in loops or after labels"); 5733 if (sc.ctorflow.callSuper & (CSX.super_ctor | CSX.this_ctor)) 5734 error(exp.loc, "multiple constructor calls"); 5735 if ((sc.ctorflow.callSuper & CSX.return_) && !(sc.ctorflow.callSuper & CSX.any_ctor)) 5736 error(exp.loc, "an earlier `return` statement skips constructor"); 5737 sc.ctorflow.callSuper |= CSX.any_ctor | (isSuper ? CSX.super_ctor : CSX.this_ctor); 5738 } 5739 5740 tthis = ad.type.addMod(sc.func.type.mod); 5741 auto ctor = isSuper ? cd.baseClass.ctor : ad.ctor; 5742 if (auto os = ctor.isOverloadSet()) 5743 exp.f = resolveOverloadSet(exp.loc, sc, os, null, tthis, exp.argumentList); 5744 else 5745 exp.f = resolveFuncCall(exp.loc, sc, ctor, null, tthis, exp.argumentList, FuncResolveFlag.standard); 5746 5747 if (!exp.f || exp.f.errors) 5748 return setError(); 5749 5750 checkFunctionAttributes(exp, sc, exp.f); 5751 checkAccess(exp.loc, sc, null, exp.f); 5752 5753 exp.e1 = new DotVarExp(exp.e1.loc, exp.e1, exp.f, false); 5754 exp.e1 = exp.e1.expressionSemantic(sc); 5755 // https://issues.dlang.org/show_bug.cgi?id=21095 5756 if (exp.e1.op == EXP.error) 5757 return setError(); 5758 t1 = exp.e1.type; 5759 5760 // BUG: this should really be done by checking the static 5761 // call graph 5762 if (exp.f == sc.func) 5763 { 5764 error(exp.loc, "cyclic constructor call"); 5765 return setError(); 5766 } 5767 } 5768 else if (auto oe = exp.e1.isOverExp()) 5769 { 5770 exp.f = resolveOverloadSet(exp.loc, sc, oe.vars, tiargs, tthis, exp.argumentList); 5771 if (!exp.f) 5772 return setError(); 5773 if (ethis) 5774 exp.e1 = new DotVarExp(exp.loc, ethis, exp.f, false); 5775 else 5776 exp.e1 = new VarExp(exp.loc, exp.f, false); 5777 goto Lagain; 5778 } 5779 else if (!t1) 5780 { 5781 error(exp.loc, "function expected before `()`, not `%s`", exp.e1.toChars()); 5782 return setError(); 5783 } 5784 else if (t1.ty == Terror) 5785 { 5786 return setError(); 5787 } 5788 else if (t1.ty != Tfunction) 5789 { 5790 TypeFunction tf; 5791 const(char)* p; 5792 Dsymbol s; 5793 exp.f = null; 5794 if (auto fe = exp.e1.isFuncExp()) 5795 { 5796 // function literal that direct called is always inferred. 5797 assert(fe.fd); 5798 exp.f = fe.fd; 5799 tf = cast(TypeFunction)exp.f.type; 5800 p = "function literal"; 5801 } 5802 else if (t1.ty == Tdelegate) 5803 { 5804 TypeDelegate td = cast(TypeDelegate)t1; 5805 assert(td.next.ty == Tfunction); 5806 tf = cast(TypeFunction)td.next; 5807 p = "delegate"; 5808 } 5809 else if (auto tfx = t1.isPtrToFunction()) 5810 { 5811 tf = tfx; 5812 p = "function pointer"; 5813 } 5814 else if (exp.e1.op == EXP.dotVariable && (cast(DotVarExp)exp.e1).var.isOverDeclaration()) 5815 { 5816 DotVarExp dve = cast(DotVarExp)exp.e1; 5817 exp.f = resolveFuncCall(exp.loc, sc, dve.var, tiargs, dve.e1.type, exp.argumentList, FuncResolveFlag.overloadOnly); 5818 if (!exp.f) 5819 return setError(); 5820 if (exp.f.needThis()) 5821 { 5822 dve.var = exp.f; 5823 dve.type = exp.f.type; 5824 dve.hasOverloads = false; 5825 goto Lagain; 5826 } 5827 exp.e1 = new VarExp(dve.loc, exp.f, false); 5828 Expression e = new CommaExp(exp.loc, dve.e1, exp); 5829 result = e.expressionSemantic(sc); 5830 return; 5831 } 5832 else if (exp.e1.op == EXP.variable && (cast(VarExp)exp.e1).var.isOverDeclaration()) 5833 { 5834 s = (cast(VarExp)exp.e1).var; 5835 goto L2; 5836 } 5837 else if (exp.e1.op == EXP.template_) 5838 { 5839 s = (cast(TemplateExp)exp.e1).td; 5840 L2: 5841 exp.f = resolveFuncCall(exp.loc, sc, s, tiargs, null, exp.argumentList, 5842 exp.isUfcsRewrite ? FuncResolveFlag.ufcs : FuncResolveFlag.standard); 5843 if (!exp.f || exp.f.errors) 5844 return setError(); 5845 if (exp.f.needThis()) 5846 { 5847 if (hasThis(sc)) 5848 { 5849 // Supply an implicit 'this', as in 5850 // this.ident 5851 exp.e1 = new DotVarExp(exp.loc, (new ThisExp(exp.loc)).expressionSemantic(sc), exp.f, false); 5852 goto Lagain; 5853 } 5854 else if (isNeedThisScope(sc, exp.f)) 5855 { 5856 return needThisError(exp.loc, exp.f); 5857 } 5858 } 5859 exp.e1 = new VarExp(exp.e1.loc, exp.f, false); 5860 goto Lagain; 5861 } 5862 else 5863 { 5864 error(exp.loc, "function expected before `()`, not `%s` of type `%s`", exp.e1.toChars(), exp.e1.type.toChars()); 5865 return setError(); 5866 } 5867 5868 const(char)* failMessage; 5869 if (!tf.callMatch(null, exp.argumentList, 0, &failMessage, sc)) 5870 { 5871 OutBuffer buf; 5872 buf.writeByte('('); 5873 argExpTypesToCBuffer(buf, exp.arguments); 5874 buf.writeByte(')'); 5875 if (tthis) 5876 tthis.modToBuffer(buf); 5877 5878 //printf("tf = %s, args = %s\n", tf.deco, (*arguments)[0].type.deco); 5879 .error(exp.loc, "%s `%s%s` is not callable using argument types `%s`", 5880 p, exp.e1.toChars(), parametersTypeToChars(tf.parameterList), buf.peekChars()); 5881 if (failMessage) 5882 errorSupplemental(exp.loc, "%s", failMessage); 5883 return setError(); 5884 } 5885 // Purity and safety check should run after testing arguments matching 5886 if (exp.f) 5887 { 5888 exp.checkPurity(sc, exp.f); 5889 exp.checkSafety(sc, exp.f); 5890 exp.checkNogc(sc, exp.f); 5891 if (exp.f.checkNestedReference(sc, exp.loc)) 5892 return setError(); 5893 } 5894 else if (sc.func && sc.intypeof != 1 && !(sc.flags & (SCOPE.ctfe | SCOPE.debug_))) 5895 { 5896 bool err = false; 5897 if (!tf.purity && sc.func.setImpure(exp.loc, "`pure` %s `%s` cannot call impure `%s`", exp.e1)) 5898 { 5899 error(exp.loc, "`pure` %s `%s` cannot call impure %s `%s`", 5900 sc.func.kind(), sc.func.toPrettyChars(), p, exp.e1.toChars()); 5901 err = true; 5902 } 5903 if (!tf.isnogc && sc.func.setGC(exp.loc, "`@nogc` %s `%s` cannot call non-@nogc `%s`", exp.e1)) 5904 { 5905 error(exp.loc, "`@nogc` %s `%s` cannot call non-@nogc %s `%s`", 5906 sc.func.kind(), sc.func.toPrettyChars(), p, exp.e1.toChars()); 5907 err = true; 5908 } 5909 if (tf.trust <= TRUST.system && sc.setUnsafe(true, exp.loc, 5910 "`@safe` function `%s` cannot call `@system` `%s`", sc.func, exp.e1)) 5911 { 5912 error(exp.loc, "`@safe` %s `%s` cannot call `@system` %s `%s`", 5913 sc.func.kind(), sc.func.toPrettyChars(), p, exp.e1.toChars()); 5914 err = true; 5915 } 5916 if (err) 5917 return setError(); 5918 } 5919 5920 if (t1.ty == Tpointer) 5921 { 5922 Expression e = new PtrExp(exp.loc, exp.e1); 5923 e.type = tf; 5924 exp.e1 = e; 5925 } 5926 t1 = tf; 5927 } 5928 else if (VarExp ve = exp.e1.isVarExp()) 5929 { 5930 // Do overload resolution 5931 exp.f = ve.var.isFuncDeclaration(); 5932 assert(exp.f); 5933 tiargs = null; 5934 5935 if (exp.f.overnext) 5936 exp.f = resolveFuncCall(exp.loc, sc, exp.f, tiargs, null, exp.argumentList, FuncResolveFlag.overloadOnly); 5937 else 5938 { 5939 exp.f = exp.f.toAliasFunc(); 5940 TypeFunction tf = cast(TypeFunction)exp.f.type; 5941 const(char)* failMessage; 5942 if (!tf.callMatch(null, exp.argumentList, 0, &failMessage, sc)) 5943 { 5944 OutBuffer buf; 5945 buf.writeByte('('); 5946 argExpTypesToCBuffer(buf, exp.arguments); 5947 buf.writeByte(')'); 5948 5949 //printf("tf = %s, args = %s\n", tf.deco, (*arguments)[0].type.deco); 5950 if (exp.isUfcsRewrite) 5951 { 5952 const arg = (*exp.argumentList.arguments)[0]; 5953 .error(exp.loc, "no property `%s` for `%s` of type `%s`", exp.f.ident.toChars(), arg.toChars(), arg.type.toChars()); 5954 .errorSupplemental(exp.loc, "the following error occured while looking for a UFCS match"); 5955 } 5956 5957 .error(exp.loc, "%s `%s%s` is not callable using argument types `%s`", 5958 exp.f.kind(), exp.f.toPrettyChars(), parametersTypeToChars(tf.parameterList), buf.peekChars()); 5959 if (failMessage) 5960 errorSupplemental(exp.loc, "%s", failMessage); 5961 exp.f = null; 5962 } 5963 } 5964 if (!exp.f || exp.f.errors) 5965 return setError(); 5966 5967 if (exp.f.needThis()) 5968 { 5969 // Change the ancestor lambdas to delegate before hasThis(sc) call. 5970 if (exp.f.checkNestedReference(sc, exp.loc)) 5971 return setError(); 5972 5973 auto memberFunc = hasThis(sc); 5974 if (memberFunc && haveSameThis(memberFunc, exp.f)) 5975 { 5976 // Supply an implicit 'this', as in 5977 // this.ident 5978 exp.e1 = new DotVarExp(exp.loc, (new ThisExp(exp.loc)).expressionSemantic(sc), ve.var); 5979 // Note: we cannot use f directly, because further overload resolution 5980 // through the supplied 'this' may cause different result. 5981 goto Lagain; 5982 } 5983 else if (isNeedThisScope(sc, exp.f)) 5984 { 5985 // At this point it is possible that `exp.f` had an ambiguity error that was 5986 // silenced because the previous call to `resolveFuncCall` was done using 5987 // `FuncResolveFlag.overloadOnly`. To make sure that a proper error message 5988 // is printed, redo the call with `FuncResolveFlag.standard`. 5989 // 5990 // https://issues.dlang.org/show_bug.cgi?id=22157 5991 if (exp.f.overnext) 5992 exp.f = resolveFuncCall(exp.loc, sc, exp.f, tiargs, null, exp.argumentList, FuncResolveFlag.standard); 5993 5994 if (!exp.f || exp.f.errors) 5995 return setError(); 5996 5997 // If no error is printed, it means that `f` is the single matching overload 5998 // and it needs `this`. 5999 return needThisError(exp.loc, exp.f); 6000 } 6001 } 6002 6003 checkFunctionAttributes(exp, sc, exp.f); 6004 checkAccess(exp.loc, sc, null, exp.f); 6005 if (exp.f.checkNestedReference(sc, exp.loc)) 6006 return setError(); 6007 6008 ethis = null; 6009 tthis = null; 6010 6011 if (ve.hasOverloads) 6012 { 6013 exp.e1 = new VarExp(ve.loc, exp.f, false); 6014 exp.e1.type = exp.f.type; 6015 } 6016 t1 = exp.f.type; 6017 } 6018 assert(t1.ty == Tfunction); 6019 6020 Expression argprefix; 6021 if (!exp.arguments) 6022 exp.arguments = new Expressions(); 6023 if (functionParameters(exp.loc, sc, cast(TypeFunction)t1, ethis, tthis, exp.argumentList, exp.f, &exp.type, &argprefix)) 6024 return setError(); 6025 6026 if (!exp.type) 6027 { 6028 exp.e1 = e1org; // https://issues.dlang.org/show_bug.cgi?id=10922 6029 // avoid recursive expression printing 6030 error(exp.loc, "forward reference to inferred return type of function call `%s`", exp.toChars()); 6031 return setError(); 6032 } 6033 6034 if (exp.f && exp.f.tintro) 6035 { 6036 Type t = exp.type; 6037 int offset = 0; 6038 TypeFunction tf = cast(TypeFunction)exp.f.tintro; 6039 if (tf.next.isBaseOf(t, &offset) && offset) 6040 { 6041 exp.type = tf.next; 6042 result = Expression.combine(argprefix, exp.castTo(sc, t)); 6043 return; 6044 } 6045 } 6046 6047 // Handle the case of a direct lambda call 6048 if (exp.f && exp.f.isFuncLiteralDeclaration() && sc.func && !sc.intypeof) 6049 { 6050 exp.f.tookAddressOf = 0; 6051 } 6052 6053 result = Expression.combine(argprefix, exp); 6054 6055 if (isSuper) 6056 { 6057 auto ad = sc.func ? sc.func.isThis() : null; 6058 auto cd = ad ? ad.isClassDeclaration() : null; 6059 if (cd && cd.classKind == ClassKind.cpp && exp.f && !exp.f.fbody) 6060 { 6061 // if super is defined in C++, it sets the vtable pointer to the base class 6062 // so we have to restore it, but still return 'this' from super() call: 6063 // (auto __vptrTmp = this.__vptr, auto __superTmp = super()), (this.__vptr = __vptrTmp, __superTmp) 6064 Loc loc = exp.loc; 6065 6066 auto vptr = new DotIdExp(loc, new ThisExp(loc), Id.__vptr); 6067 auto vptrTmpDecl = copyToTemp(0, "__vptrTmp", vptr); 6068 auto declareVptrTmp = new DeclarationExp(loc, vptrTmpDecl); 6069 6070 auto superTmpDecl = copyToTemp(0, "__superTmp", result); 6071 auto declareSuperTmp = new DeclarationExp(loc, superTmpDecl); 6072 6073 auto declareTmps = new CommaExp(loc, declareVptrTmp, declareSuperTmp); 6074 6075 auto restoreVptr = new AssignExp(loc, vptr.syntaxCopy(), new VarExp(loc, vptrTmpDecl)); 6076 6077 Expression e = new CommaExp(loc, declareTmps, new CommaExp(loc, restoreVptr, new VarExp(loc, superTmpDecl))); 6078 result = e.expressionSemantic(sc); 6079 } 6080 } 6081 6082 // `super.fun()` with fun being abstract and unimplemented 6083 auto supDotFun = exp.e1.isDotVarExp(); 6084 if (supDotFun && supDotFun.e1.isSuperExp() && exp.f && exp.f.isAbstract() && !exp.f.fbody) 6085 { 6086 error(exp.loc, "call to unimplemented abstract function `%s`", exp.f.toFullSignature()); 6087 errorSupplemental(exp.loc, "declared here: %s", exp.f.loc.toChars()); 6088 } 6089 6090 // declare dual-context container 6091 if (exp.f && exp.f.hasDualContext() && !sc.intypeof && sc.func) 6092 { 6093 // check access to second `this` 6094 if (AggregateDeclaration ad2 = exp.f.isMember2()) 6095 { 6096 Expression te = new ThisExp(exp.loc).expressionSemantic(sc); 6097 if (te.op != EXP.error) 6098 te = getRightThis(exp.loc, sc, ad2, te, exp.f); 6099 if (te.op == EXP.error) 6100 { 6101 error(exp.loc, "need `this` of type `%s` to call function `%s`", ad2.toChars(), exp.f.toChars()); 6102 return setError(); 6103 } 6104 } 6105 exp.vthis2 = makeThis2Argument(exp.loc, sc, exp.f); 6106 Expression de = new DeclarationExp(exp.loc, exp.vthis2); 6107 result = Expression.combine(de, result); 6108 result = result.expressionSemantic(sc); 6109 } 6110 } 6111 6112 override void visit(DeclarationExp e) 6113 { 6114 if (e.type) 6115 { 6116 result = e; 6117 return; 6118 } 6119 static if (LOGSEMANTIC) 6120 { 6121 printf("DeclarationExp::semantic() %s\n", e.toChars()); 6122 } 6123 6124 uint olderrors = global.errors; 6125 6126 /* This is here to support extern(linkage) declaration, 6127 * where the extern(linkage) winds up being an AttribDeclaration 6128 * wrapper. 6129 */ 6130 Dsymbol s = e.declaration; 6131 6132 while (1) 6133 { 6134 AttribDeclaration ad = s.isAttribDeclaration(); 6135 if (ad) 6136 { 6137 if (ad.decl && ad.decl.length == 1) 6138 { 6139 s = (*ad.decl)[0]; 6140 continue; 6141 } 6142 } 6143 break; 6144 } 6145 6146 //printf("inserting '%s' %p into sc = %p\n", s.toChars(), s, sc); 6147 // Insert into both local scope and function scope. 6148 // Must be unique in both. 6149 if (s.ident) 6150 { 6151 VarDeclaration v = s.isVarDeclaration(); 6152 if (v) 6153 { 6154 if (sc.flags & SCOPE.Cfile) 6155 { 6156 /* Do semantic() on the type before inserting v into the symbol table 6157 */ 6158 if (!v.originalType) 6159 v.originalType = v.type.syntaxCopy(); 6160 Scope* sc2 = sc.push(); 6161 sc2.stc |= v.storage_class & STC.FUNCATTR; 6162 sc2.linkage = LINK.c; // account for the extern(C) in front of the declaration 6163 v.inuse++; 6164 v.type = v.type.typeSemantic(v.loc, sc2); 6165 v.inuse--; 6166 sc2.pop(); 6167 } 6168 else 6169 { 6170 /* Do semantic() on initializer first so this will be illegal: 6171 * int a = a; 6172 */ 6173 e.declaration.dsymbolSemantic(sc); 6174 s.parent = sc.parent; 6175 } 6176 } 6177 6178 if (!sc.insert(s)) 6179 { 6180 auto conflict = sc.search(Loc.initial, s.ident, null); 6181 error(e.loc, "declaration `%s` is already defined", s.toPrettyChars()); 6182 errorSupplemental(conflict.loc, "`%s` `%s` is defined here", 6183 conflict.kind(), conflict.toChars()); 6184 return setError(); 6185 } 6186 6187 if (v && (sc.flags & SCOPE.Cfile)) 6188 { 6189 /* Do semantic() on initializer last so this will be legal: 6190 * int a = a; 6191 */ 6192 e.declaration.dsymbolSemantic(sc); 6193 s.parent = sc.parent; 6194 } 6195 6196 if (sc.func) 6197 { 6198 // https://issues.dlang.org/show_bug.cgi?id=11720 6199 if ((s.isFuncDeclaration() || 6200 s.isAggregateDeclaration() || 6201 s.isEnumDeclaration() || 6202 s.isTemplateDeclaration() || 6203 v 6204 ) && !sc.func.localsymtab.insert(s)) 6205 { 6206 // Get the previous symbol 6207 Dsymbol originalSymbol = sc.func.localsymtab.lookup(s.ident); 6208 6209 // Perturb the name mangling so that the symbols can co-exist 6210 // instead of colliding 6211 s.localNum = cast(ushort)(originalSymbol.localNum + 1); 6212 // 65535 should be enough for anyone 6213 if (!s.localNum) 6214 { 6215 error(e.loc, "more than 65535 symbols with name `%s` generated", s.ident.toChars()); 6216 return setError(); 6217 } 6218 6219 // Replace originalSymbol with s, which updates the localCount 6220 sc.func.localsymtab.update(s); 6221 6222 // The mangling change only works for D mangling 6223 } 6224 6225 if (!(sc.flags & SCOPE.Cfile)) 6226 { 6227 /* https://issues.dlang.org/show_bug.cgi?id=21272 6228 * If we are in a foreach body we need to extract the 6229 * function containing the foreach 6230 */ 6231 FuncDeclaration fes_enclosing_func; 6232 if (sc.func && sc.func.fes) 6233 fes_enclosing_func = sc.enclosing.enclosing.func; 6234 6235 // Disallow shadowing 6236 for (Scope* scx = sc.enclosing; scx && (scx.func == sc.func || (fes_enclosing_func && scx.func == fes_enclosing_func)); scx = scx.enclosing) 6237 { 6238 Dsymbol s2; 6239 if (scx.scopesym && scx.scopesym.symtab && (s2 = scx.scopesym.symtab.lookup(s.ident)) !is null && s != s2) 6240 { 6241 // allow STC.local symbols to be shadowed 6242 // TODO: not really an optimal design 6243 auto decl = s2.isDeclaration(); 6244 if (!decl || !(decl.storage_class & STC.local)) 6245 { 6246 if (sc.func.fes) 6247 { 6248 deprecation(e.loc, "%s `%s` is shadowing %s `%s`. Rename the `foreach` variable.", s.kind(), s.ident.toChars(), s2.kind(), s2.toPrettyChars()); 6249 } 6250 else 6251 { 6252 error(e.loc, "%s `%s` is shadowing %s `%s`", s.kind(), s.ident.toChars(), s2.kind(), s2.toPrettyChars()); 6253 return setError(); 6254 } 6255 } 6256 } 6257 } 6258 } 6259 } 6260 } 6261 if (!s.isVarDeclaration()) 6262 { 6263 Scope* sc2 = sc; 6264 if (sc2.stc & (STC.pure_ | STC.nothrow_ | STC.nogc)) 6265 sc2 = sc.push(); 6266 sc2.stc &= ~(STC.pure_ | STC.nothrow_ | STC.nogc); 6267 e.declaration.dsymbolSemantic(sc2); 6268 if (sc2 != sc) 6269 sc2.pop(); 6270 s.parent = sc.parent; 6271 } 6272 if (global.errors == olderrors) 6273 { 6274 e.declaration.semantic2(sc); 6275 if (global.errors == olderrors) 6276 { 6277 e.declaration.semantic3(sc); 6278 } 6279 } 6280 // todo: error in declaration should be propagated. 6281 6282 e.type = Type.tvoid; 6283 result = e; 6284 } 6285 6286 override void visit(TypeidExp exp) 6287 { 6288 static if (LOGSEMANTIC) 6289 { 6290 printf("TypeidExp::semantic() %s\n", exp.toChars()); 6291 } 6292 Type ta = isType(exp.obj); 6293 Expression ea = isExpression(exp.obj); 6294 Dsymbol sa = isDsymbol(exp.obj); 6295 //printf("ta %p ea %p sa %p\n", ta, ea, sa); 6296 6297 if (ta) 6298 { 6299 dmd.typesem.resolve(ta, exp.loc, sc, ea, ta, sa, true); 6300 } 6301 6302 if (ea) 6303 { 6304 if (auto sym = getDsymbol(ea)) 6305 ea = symbolToExp(sym, exp.loc, sc, false); 6306 else 6307 ea = ea.expressionSemantic(sc); 6308 ea = resolveProperties(sc, ea); 6309 ta = ea.type; 6310 if (ea.op == EXP.type) 6311 ea = null; 6312 } 6313 6314 if (!ta) 6315 { 6316 //printf("ta %p ea %p sa %p\n", ta, ea, sa); 6317 error(exp.loc, "no type for `typeid(%s)`", ea ? ea.toChars() : (sa ? sa.toChars() : "")); 6318 return setError(); 6319 } 6320 6321 ta.checkComplexTransition(exp.loc, sc); 6322 6323 Expression e; 6324 auto tb = ta.toBasetype(); 6325 if (ea && tb.ty == Tclass) 6326 { 6327 if (tb.toDsymbol(sc).isClassDeclaration().classKind == ClassKind.cpp) 6328 { 6329 error(exp.loc, "runtime type information is not supported for `extern(C++)` classes"); 6330 e = ErrorExp.get(); 6331 } 6332 else if (!Type.typeinfoclass) 6333 { 6334 error(exp.loc, "`object.TypeInfo_Class` could not be found, but is implicitly used"); 6335 e = ErrorExp.get(); 6336 } 6337 else 6338 { 6339 /* Get the dynamic type, which is .classinfo 6340 */ 6341 ea = ea.expressionSemantic(sc); 6342 e = new TypeidExp(ea.loc, ea); 6343 e.type = Type.typeinfoclass.type; 6344 } 6345 } 6346 else if (ta.ty == Terror) 6347 { 6348 e = ErrorExp.get(); 6349 } 6350 else 6351 { 6352 // Handle this in the glue layer 6353 e = new TypeidExp(exp.loc, ta); 6354 6355 bool genObjCode = true; 6356 6357 // https://issues.dlang.org/show_bug.cgi?id=23650 6358 // We generate object code for typeinfo, required 6359 // by typeid, only if in non-speculative context 6360 if (sc.flags & SCOPE.compile) 6361 { 6362 genObjCode = false; 6363 } 6364 6365 e.type = getTypeInfoType(exp.loc, ta, sc, genObjCode); 6366 semanticTypeInfo(sc, ta); 6367 6368 if (ea) 6369 { 6370 e = new CommaExp(exp.loc, ea, e); // execute ea 6371 e = e.expressionSemantic(sc); 6372 } 6373 } 6374 result = e; 6375 } 6376 6377 override void visit(TraitsExp e) 6378 { 6379 result = semanticTraits(e, sc); 6380 } 6381 6382 override void visit(HaltExp e) 6383 { 6384 static if (LOGSEMANTIC) 6385 { 6386 printf("HaltExp::semantic()\n"); 6387 } 6388 e.type = Type.tnoreturn; 6389 result = e; 6390 } 6391 6392 override void visit(IsExp e) 6393 { 6394 /* is(targ id tok tspec) 6395 * is(targ id : tok2) 6396 * is(targ id == tok2) 6397 */ 6398 Type tded = null; 6399 6400 void yes() 6401 { 6402 //printf("yes\n"); 6403 if (!e.id) 6404 { 6405 result = IntegerExp.createBool(true); 6406 return; 6407 } 6408 6409 Dsymbol s; 6410 Tuple tup = isTuple(tded); 6411 if (tup) 6412 s = new TupleDeclaration(e.loc, e.id, &tup.objects); 6413 else 6414 s = new AliasDeclaration(e.loc, e.id, tded); 6415 s.dsymbolSemantic(sc); 6416 6417 /* The reason for the !tup is unclear. It fails Phobos unittests if it is not there. 6418 * More investigation is needed. 6419 */ 6420 if (!tup && !sc.insert(s)) 6421 { 6422 auto conflict = sc.search(Loc.initial, s.ident, null); 6423 error(e.loc, "declaration `%s` is already defined", s.toPrettyChars()); 6424 errorSupplemental(conflict.loc, "`%s` `%s` is defined here", 6425 conflict.kind(), conflict.toChars()); 6426 } 6427 6428 unSpeculative(sc, s); 6429 6430 result = IntegerExp.createBool(true); 6431 } 6432 void no() 6433 { 6434 result = IntegerExp.createBool(false); 6435 //printf("no\n"); 6436 } 6437 6438 static if (LOGSEMANTIC) 6439 { 6440 printf("IsExp::semantic(%s)\n", e.toChars()); 6441 } 6442 if (e.id && !(sc.flags & SCOPE.condition)) 6443 { 6444 error(e.loc, "can only declare type aliases within `static if` conditionals or `static assert`s"); 6445 return setError(); 6446 } 6447 6448 if (e.tok2 == TOK.package_ || e.tok2 == TOK.module_) // These is() expressions are special because they can work on modules, not just types. 6449 { 6450 const oldErrors = global.startGagging(); 6451 Dsymbol sym = e.targ.toDsymbol(sc); 6452 global.endGagging(oldErrors); 6453 6454 if (sym is null) 6455 return no(); 6456 Package p = resolveIsPackage(sym); 6457 if (p is null) 6458 return no(); 6459 if (e.tok2 == TOK.package_ && p.isModule()) // Note that isModule() will return null for package modules because they're not actually instances of Module. 6460 return no(); 6461 else if(e.tok2 == TOK.module_ && !(p.isModule() || p.isPackageMod())) 6462 return no(); 6463 tded = e.targ; 6464 return yes(); 6465 } 6466 6467 { 6468 Scope* sc2 = sc.copy(); // keep sc.flags 6469 sc2.tinst = null; 6470 sc2.minst = null; 6471 sc2.flags |= SCOPE.fullinst; 6472 Type t = e.targ.trySemantic(e.loc, sc2); 6473 sc2.pop(); 6474 if (!t) // errors, so condition is false 6475 return no(); 6476 e.targ = t; 6477 } 6478 6479 if (e.tok2 != TOK.reserved) 6480 { 6481 switch (e.tok2) 6482 { 6483 case TOK.struct_: 6484 if (e.targ.ty != Tstruct) 6485 return no(); 6486 if ((cast(TypeStruct)e.targ).sym.isUnionDeclaration()) 6487 return no(); 6488 tded = e.targ; 6489 break; 6490 6491 case TOK.union_: 6492 if (e.targ.ty != Tstruct) 6493 return no(); 6494 if (!(cast(TypeStruct)e.targ).sym.isUnionDeclaration()) 6495 return no(); 6496 tded = e.targ; 6497 break; 6498 6499 case TOK.class_: 6500 if (e.targ.ty != Tclass) 6501 return no(); 6502 if ((cast(TypeClass)e.targ).sym.isInterfaceDeclaration()) 6503 return no(); 6504 tded = e.targ; 6505 break; 6506 6507 case TOK.interface_: 6508 if (e.targ.ty != Tclass) 6509 return no(); 6510 if (!(cast(TypeClass)e.targ).sym.isInterfaceDeclaration()) 6511 return no(); 6512 tded = e.targ; 6513 break; 6514 6515 case TOK.const_: 6516 if (!e.targ.isConst()) 6517 return no(); 6518 tded = e.targ; 6519 break; 6520 6521 case TOK.immutable_: 6522 if (!e.targ.isImmutable()) 6523 return no(); 6524 tded = e.targ; 6525 break; 6526 6527 case TOK.shared_: 6528 if (!e.targ.isShared()) 6529 return no(); 6530 tded = e.targ; 6531 break; 6532 6533 case TOK.inout_: 6534 if (!e.targ.isWild()) 6535 return no(); 6536 tded = e.targ; 6537 break; 6538 6539 case TOK.super_: 6540 // If class or interface, get the base class and interfaces 6541 if (e.targ.ty != Tclass) 6542 return no(); 6543 else 6544 { 6545 ClassDeclaration cd = (cast(TypeClass)e.targ).sym; 6546 auto args = new Parameters(); 6547 args.reserve(cd.baseclasses.length); 6548 if (cd.semanticRun < PASS.semanticdone) 6549 cd.dsymbolSemantic(null); 6550 for (size_t i = 0; i < cd.baseclasses.length; i++) 6551 { 6552 BaseClass* b = (*cd.baseclasses)[i]; 6553 args.push(new Parameter(Loc.initial, STC.in_, b.type, null, null, null)); 6554 } 6555 tded = new TypeTuple(args); 6556 } 6557 break; 6558 6559 case TOK.enum_: 6560 if (e.targ.ty != Tenum) 6561 return no(); 6562 if (e.id) 6563 tded = (cast(TypeEnum)e.targ).sym.getMemtype(e.loc); 6564 else 6565 tded = e.targ; 6566 6567 if (tded.ty == Terror) 6568 return setError(); 6569 break; 6570 6571 case TOK.delegate_: 6572 if (e.targ.ty != Tdelegate) 6573 return no(); 6574 tded = (cast(TypeDelegate)e.targ).next; // the underlying function type 6575 break; 6576 6577 case TOK.function_: 6578 if (e.targ.ty != Tfunction) 6579 return no(); 6580 goto case; 6581 case TOK.parameters: 6582 { 6583 if (auto tf = e.targ.isFunction_Delegate_PtrToFunction()) 6584 tded = tf; 6585 else 6586 return no(); 6587 6588 /* Generate tuple from function parameter types. 6589 */ 6590 auto args = new Parameters(); 6591 foreach (i, arg; tded.isTypeFunction().parameterList) 6592 { 6593 assert(arg && arg.type); 6594 /* If one of the default arguments was an error, 6595 don't return an invalid tuple 6596 */ 6597 if (e.tok2 == TOK.parameters && arg.defaultArg && arg.defaultArg.op == EXP.error) 6598 return setError(); 6599 args.push(new Parameter(arg.loc, arg.storageClass, arg.type, (e.tok2 == TOK.parameters) ? arg.ident : null, (e.tok2 == TOK.parameters) ? arg.defaultArg : null, arg.userAttribDecl)); 6600 } 6601 tded = new TypeTuple(args); 6602 break; 6603 } 6604 case TOK.return_: 6605 /* Get the 'return type' for the function, 6606 * delegate, or pointer to function. 6607 */ 6608 if (auto tf = e.targ.isFunction_Delegate_PtrToFunction()) 6609 tded = tf.next; 6610 else 6611 return no(); 6612 break; 6613 6614 case TOK.argumentTypes: 6615 /* Generate a type tuple of the equivalent types used to determine if a 6616 * function argument of this type can be passed in registers. 6617 * The results of this are highly platform dependent, and intended 6618 * primarly for use in implementing va_arg(). 6619 */ 6620 tded = target.toArgTypes(e.targ); 6621 if (!tded) 6622 return no(); 6623 // not valid for a parameter 6624 break; 6625 6626 case TOK.vector: 6627 if (e.targ.ty != Tvector) 6628 return no(); 6629 tded = (cast(TypeVector)e.targ).basetype; 6630 break; 6631 6632 default: 6633 assert(0); 6634 } 6635 6636 // https://issues.dlang.org/show_bug.cgi?id=18753 6637 if (tded) 6638 return yes(); 6639 return no(); 6640 } 6641 else if (e.tspec && !e.id && !(e.parameters && e.parameters.length)) 6642 { 6643 /* Evaluate to true if targ matches tspec 6644 * is(targ == tspec) 6645 * is(targ : tspec) 6646 */ 6647 e.tspec = e.tspec.typeSemantic(e.loc, sc); 6648 //printf("targ = %s, %s\n", e.targ.toChars(), e.targ.deco); 6649 //printf("tspec = %s, %s\n", e.tspec.toChars(), e.tspec.deco); 6650 6651 if (e.tok == TOK.colon) 6652 { 6653 // current scope is itself deprecated, or deprecations are not errors 6654 const bool deprecationAllowed = sc.isDeprecated 6655 || global.params.useDeprecated != DiagnosticReporting.error; 6656 const bool preventAliasThis = e.targ.hasDeprecatedAliasThis && !deprecationAllowed; 6657 6658 if (preventAliasThis && e.targ.ty == Tstruct) 6659 { 6660 if ((cast(TypeStruct) e.targ).implicitConvToWithoutAliasThis(e.tspec)) 6661 return yes(); 6662 else 6663 return no(); 6664 } 6665 else if (preventAliasThis && e.targ.ty == Tclass) 6666 { 6667 if ((cast(TypeClass) e.targ).implicitConvToWithoutAliasThis(e.tspec)) 6668 return yes(); 6669 else 6670 return no(); 6671 } 6672 else if (e.targ.implicitConvTo(e.tspec)) 6673 return yes(); 6674 else 6675 return no(); 6676 } 6677 else /* == */ 6678 { 6679 if (e.targ.equals(e.tspec)) 6680 return yes(); 6681 else 6682 return no(); 6683 } 6684 } 6685 else if (e.tspec) 6686 { 6687 /* Evaluate to true if targ matches tspec. 6688 * If true, declare id as an alias for the specialized type. 6689 * is(targ == tspec, tpl) 6690 * is(targ : tspec, tpl) 6691 * is(targ id == tspec) 6692 * is(targ id : tspec) 6693 * is(targ id == tspec, tpl) 6694 * is(targ id : tspec, tpl) 6695 */ 6696 Identifier tid = e.id ? e.id : Identifier.generateId("__isexp_id"); 6697 e.parameters.insert(0, new TemplateTypeParameter(e.loc, tid, null, null)); 6698 6699 Objects dedtypes = Objects(e.parameters.length); 6700 dedtypes.zero(); 6701 6702 MATCH m = deduceType(e.targ, sc, e.tspec, e.parameters, &dedtypes, null, 0, e.tok == TOK.equal); 6703 6704 if (m == MATCH.nomatch || (m != MATCH.exact && e.tok == TOK.equal)) 6705 { 6706 return no(); 6707 } 6708 else 6709 { 6710 tded = cast(Type)dedtypes[0]; 6711 if (!tded) 6712 tded = e.targ; 6713 Objects tiargs = Objects(1); 6714 tiargs[0] = e.targ; 6715 6716 /* Declare trailing parameters 6717 */ 6718 for (size_t i = 1; i < e.parameters.length; i++) 6719 { 6720 TemplateParameter tp = (*e.parameters)[i]; 6721 Declaration s = null; 6722 6723 m = tp.matchArg(e.loc, sc, &tiargs, i, e.parameters, &dedtypes, &s); 6724 if (m == MATCH.nomatch) 6725 return no(); 6726 s.dsymbolSemantic(sc); 6727 if (!sc.insert(s)) 6728 { 6729 auto conflict = sc.search(Loc.initial, s.ident, null); 6730 error(e.loc, "declaration `%s` is already defined", s.toPrettyChars()); 6731 errorSupplemental(conflict.loc, "`%s` `%s` is defined here", 6732 conflict.kind(), conflict.toChars()); 6733 } 6734 6735 unSpeculative(sc, s); 6736 } 6737 return yes(); 6738 } 6739 } 6740 else if (e.id) 6741 { 6742 /* Declare id as an alias for type targ. Evaluate to true 6743 * is(targ id) 6744 */ 6745 tded = e.targ; 6746 } 6747 return yes(); 6748 } 6749 6750 override void visit(BinAssignExp exp) 6751 { 6752 if (exp.type) 6753 { 6754 result = exp; 6755 return; 6756 } 6757 6758 Expression e = exp.op_overload(sc); 6759 if (e) 6760 { 6761 result = e; 6762 return; 6763 } 6764 6765 if (exp.e1.op == EXP.arrayLength) 6766 { 6767 // arr.length op= e2; 6768 e = rewriteOpAssign(exp); 6769 e = e.expressionSemantic(sc); 6770 result = e; 6771 return; 6772 } 6773 if (exp.e1.op == EXP.slice || exp.e1.type.ty == Tarray || exp.e1.type.ty == Tsarray) 6774 { 6775 if (checkNonAssignmentArrayOp(exp.e1)) 6776 return setError(); 6777 6778 if (exp.e1.op == EXP.slice) 6779 (cast(SliceExp)exp.e1).arrayop = true; 6780 6781 // T[] op= ... 6782 if (exp.e2.implicitConvTo(exp.e1.type.nextOf())) 6783 { 6784 // T[] op= T 6785 exp.e2 = exp.e2.castTo(sc, exp.e1.type.nextOf()); 6786 } 6787 else if (Expression ex = typeCombine(exp, sc)) 6788 { 6789 result = ex; 6790 return; 6791 } 6792 exp.type = exp.e1.type; 6793 result = arrayOp(exp, sc); 6794 return; 6795 } 6796 6797 exp.e1 = exp.e1.expressionSemantic(sc); 6798 exp.e1 = exp.e1.modifiableLvalue(sc, exp.e1); 6799 exp.e1 = exp.e1.optimize(WANTvalue, /*keepLvalue*/ true); 6800 exp.type = exp.e1.type; 6801 6802 if (auto ad = isAggregate(exp.e1.type)) 6803 { 6804 if (const s = search_function(ad, Id.opOpAssign)) 6805 { 6806 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()); 6807 return setError(); 6808 } 6809 } 6810 if (exp.e1.checkScalar() || 6811 exp.e1.checkReadModifyWrite(exp.op, exp.e2) || 6812 exp.e1.checkSharedAccess(sc)) 6813 return setError(); 6814 6815 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); 6816 int bitwise = (exp.op == EXP.andAssign || exp.op == EXP.orAssign || exp.op == EXP.xorAssign); 6817 int shift = (exp.op == EXP.leftShiftAssign || exp.op == EXP.rightShiftAssign || exp.op == EXP.unsignedRightShiftAssign); 6818 6819 if (bitwise && exp.type.toBasetype().ty == Tbool) 6820 exp.e2 = exp.e2.implicitCastTo(sc, exp.type); 6821 else if (exp.checkNoBool()) 6822 return setError(); 6823 6824 if ((exp.op == EXP.addAssign || exp.op == EXP.minAssign) && exp.e1.type.toBasetype().ty == Tpointer && exp.e2.type.toBasetype().isintegral()) 6825 { 6826 result = scaleFactor(exp, sc); 6827 return; 6828 } 6829 6830 if (Expression ex = typeCombine(exp, sc)) 6831 { 6832 result = ex; 6833 return; 6834 } 6835 6836 if (arith && (exp.checkArithmeticBin() || exp.checkSharedAccessBin(sc))) 6837 return setError(); 6838 if ((bitwise || shift) && (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc))) 6839 return setError(); 6840 6841 if (shift) 6842 { 6843 if (exp.e2.type.toBasetype().ty != Tvector) 6844 exp.e2 = exp.e2.castTo(sc, Type.tshiftcnt); 6845 } 6846 6847 if (!target.isVectorOpSupported(exp.type.toBasetype(), exp.op, exp.e2.type.toBasetype())) 6848 { 6849 result = exp.incompatibleTypes(); 6850 return; 6851 } 6852 6853 if (exp.e1.op == EXP.error || exp.e2.op == EXP.error) 6854 return setError(); 6855 6856 e = exp.checkOpAssignTypes(sc); 6857 if (e.op == EXP.error) 6858 { 6859 result = e; 6860 return; 6861 } 6862 6863 assert(e.op == EXP.assign || e == exp); 6864 result = (cast(BinExp)e).reorderSettingAAElem(sc); 6865 } 6866 6867 private Expression compileIt(MixinExp exp) 6868 { 6869 OutBuffer buf; 6870 if (expressionsToString(buf, sc, exp.exps)) 6871 return null; 6872 6873 uint errors = global.errors; 6874 const len = buf.length; 6875 const str = buf.extractChars()[0 .. len]; 6876 const bool doUnittests = global.params.useUnitTests || global.params.ddoc.doOutput || global.params.dihdr.doOutput; 6877 auto loc = adjustLocForMixin(str, exp.loc, global.params.mixinOut); 6878 scope p = new Parser!ASTCodegen(loc, sc._module, str, false, global.errorSink, &global.compileEnv, doUnittests); 6879 p.transitionIn = global.params.v.vin; 6880 p.nextToken(); 6881 //printf("p.loc.linnum = %d\n", p.loc.linnum); 6882 6883 Expression e = p.parseExpression(); 6884 if (global.errors != errors) 6885 return null; 6886 6887 if (p.token.value != TOK.endOfFile) 6888 { 6889 error(e.loc, "unexpected token `%s` after %s expression", 6890 p.token.toChars(), EXPtoString(e.op).ptr); 6891 errorSupplemental(e.loc, "while parsing string mixin expression `%s`", 6892 str.ptr); 6893 return null; 6894 } 6895 return e; 6896 } 6897 6898 override void visit(MixinExp exp) 6899 { 6900 /* https://dlang.org/spec/expression.html#mixin_expressions 6901 */ 6902 6903 static if (LOGSEMANTIC) 6904 { 6905 printf("MixinExp::semantic('%s')\n", exp.toChars()); 6906 } 6907 6908 auto e = compileIt(exp); 6909 if (!e) 6910 return setError(); 6911 result = e.expressionSemantic(sc); 6912 } 6913 6914 override void visit(ImportExp e) 6915 { 6916 static if (LOGSEMANTIC) 6917 { 6918 printf("ImportExp::semantic('%s')\n", e.toChars()); 6919 } 6920 6921 auto se = semanticString(sc, e.e1, "file name argument"); 6922 if (!se) 6923 return setError(); 6924 se = se.toUTF8(sc); 6925 6926 auto namez = se.toStringz(); 6927 if (!global.filePath) 6928 { 6929 error(e.loc, "need `-J` switch to import text file `%s`", namez.ptr); 6930 return setError(); 6931 } 6932 6933 /* Be wary of CWE-22: Improper Limitation of a Pathname to a Restricted Directory 6934 * ('Path Traversal') attacks. 6935 * https://cwe.mitre.org/data/definitions/22.html 6936 */ 6937 6938 if (FileName.absolute(namez)) 6939 { 6940 error(e.loc, "absolute path is not allowed in import expression: `%s`", se.toChars()); 6941 return setError(); 6942 } 6943 6944 auto idxReserved = FileName.findReservedChar(namez); 6945 if (idxReserved != size_t.max) 6946 { 6947 error(e.loc, "`%s` is not a valid filename on this platform", se.toChars()); 6948 errorSupplemental(e.loc, "Character `'%c'` is reserved and cannot be used", namez[idxReserved]); 6949 return setError(); 6950 } 6951 6952 if (FileName.refersToParentDir(namez)) 6953 { 6954 error(e.loc, "path refers to parent (`..`) directory: `%s`", se.toChars()); 6955 return setError(); 6956 } 6957 6958 auto resolvedNamez = FileName.searchPath(global.filePath, namez, false); 6959 if (!resolvedNamez) 6960 { 6961 error(e.loc, "file `%s` cannot be found or not in a path specified with `-J`", se.toChars()); 6962 errorSupplemental(e.loc, "Path(s) searched (as provided by `-J`):"); 6963 foreach (idx, path; *global.filePath) 6964 { 6965 const attr = FileName.exists(path); 6966 const(char)* err = attr == 2 ? "" : 6967 (attr == 1 ? " (not a directory)" : " (path not found)"); 6968 errorSupplemental(e.loc, "[%llu]: `%s`%s", cast(ulong)idx, path, err); 6969 } 6970 return setError(); 6971 } 6972 6973 sc._module.contentImportedFiles.push(resolvedNamez.ptr); 6974 if (global.params.v.verbose) 6975 { 6976 const slice = se.peekString(); 6977 message("file %.*s\t(%s)", cast(int)slice.length, slice.ptr, resolvedNamez.ptr); 6978 } 6979 if (global.params.moduleDeps.buffer !is null) 6980 { 6981 OutBuffer* ob = global.params.moduleDeps.buffer; 6982 Module imod = sc._module; 6983 6984 if (!global.params.moduleDeps.name) 6985 ob.writestring("depsFile "); 6986 ob.writestring(imod.toPrettyChars()); 6987 ob.writestring(" ("); 6988 escapePath(ob, imod.srcfile.toChars()); 6989 ob.writestring(") : "); 6990 if (global.params.moduleDeps.name) 6991 ob.writestring("string : "); 6992 ob.write(se.peekString()); 6993 ob.writestring(" ("); 6994 escapePath(ob, resolvedNamez.ptr); 6995 ob.writestring(")"); 6996 ob.writenl(); 6997 } 6998 if (global.params.makeDeps.doOutput) 6999 { 7000 global.params.makeDeps.files.push(resolvedNamez.ptr); 7001 } 7002 7003 { 7004 auto fileName = FileName(resolvedNamez); 7005 if (auto fmResult = global.fileManager.lookup(fileName)) 7006 { 7007 se = new StringExp(e.loc, fmResult); 7008 } 7009 else 7010 { 7011 error(e.loc, "cannot read file `%s`", resolvedNamez.ptr); 7012 return setError(); 7013 } 7014 } 7015 result = se.expressionSemantic(sc); 7016 } 7017 7018 override void visit(AssertExp exp) 7019 { 7020 // https://dlang.org/spec/expression.html#assert_expressions 7021 static if (LOGSEMANTIC) 7022 { 7023 printf("AssertExp::semantic('%s')\n", exp.toChars()); 7024 } 7025 7026 const generateMsg = !exp.msg && 7027 sc.needsCodegen() && // let ctfe interpreter handle the error message 7028 global.params.checkAction == CHECKACTION.context && 7029 global.params.useAssert == CHECKENABLE.on && 7030 !((exp.e1.isIntegerExp() && (exp.e1.toInteger() == 0)) || 7031 exp.e1.isNullExp()); 7032 Expression temporariesPrefix; 7033 7034 if (generateMsg) 7035 // no message - use assert expression as msg 7036 { 7037 if (!verifyHookExist(exp.loc, *sc, Id._d_assert_fail, "generating assert messages")) 7038 return setError(); 7039 7040 /* 7041 { 7042 auto a = e1, b = e2; 7043 assert(a == b, _d_assert_fail!"=="(a, b)); 7044 }() 7045 */ 7046 7047 /* 7048 Stores the result of an operand expression into a temporary 7049 if necessary, e.g. if it is an impure fuction call containing side 7050 effects as in https://issues.dlang.org/show_bug.cgi?id=20114 7051 7052 Params: 7053 op = an expression which may require a temporary (added to 7054 `temporariesPrefix`: `auto tmp = op`) and will be replaced 7055 by `tmp` if necessary 7056 7057 Returns: (possibly replaced) `op` 7058 */ 7059 Expression maybePromoteToTmp(ref Expression op) 7060 { 7061 // https://issues.dlang.org/show_bug.cgi?id=20989 7062 // Flag that _d_assert_fail will never dereference `array.ptr` to avoid safety 7063 // errors for `assert(!array.ptr)` => `_d_assert_fail!"!"(array.ptr)` 7064 { 7065 auto die = op.isDotIdExp(); 7066 if (die && die.ident == Id.ptr) 7067 die.noderef = true; 7068 } 7069 7070 op = op.expressionSemantic(sc); 7071 op = resolveProperties(sc, op); 7072 7073 // Detect assert's using static operator overloads (e.g. `"var" in environment`) 7074 if (auto te = op.isTypeExp()) 7075 { 7076 // Replace the TypeExp with it's textual representation 7077 // Including "..." in the error message isn't quite right but 7078 // proper solutions require more drastic changes, e.g. directly 7079 // using miniFormat and combine instead of calling _d_assert_fail 7080 auto name = new StringExp(te.loc, te.toString()); 7081 return name.expressionSemantic(sc); 7082 } 7083 7084 // Create a temporary for expressions with side effects 7085 // Defensively assume that function calls may have side effects even 7086 // though it's not detected by hasSideEffect (e.g. `debug puts("Hello")` ) 7087 // Rewriting CallExp's also avoids some issues with the inliner/debug generation 7088 if (op.hasSideEffect(true)) 7089 { 7090 // Don't create an invalid temporary for void-expressions 7091 // Further semantic will issue an appropriate error 7092 if (op.type.ty == Tvoid) 7093 return op; 7094 7095 // https://issues.dlang.org/show_bug.cgi?id=21590 7096 // Don't create unnecessary temporaries and detect `assert(a = b)` 7097 if (op.isAssignExp() || op.isBinAssignExp()) 7098 { 7099 auto left = (cast(BinExp) op).e1; 7100 7101 // Find leftmost expression to handle other rewrites, 7102 // e.g. --(++a) => a += 1 -= 1 7103 while (left.isAssignExp() || left.isBinAssignExp()) 7104 left = (cast(BinExp) left).e1; 7105 7106 // Only use the assignee if it's a variable and skip 7107 // other lvalues (e.g. ref's returned by functions) 7108 if (left.isVarExp()) 7109 return left; 7110 7111 // Sanity check that `op` can be converted to boolean 7112 // But don't raise errors for assignments enclosed in another expression 7113 if (op is exp.e1) 7114 op.toBoolean(sc); 7115 } 7116 7117 // Tuples with side-effects already receive a temporary during semantic 7118 if (op.type.isTypeTuple()) 7119 { 7120 auto te = op.isTupleExp(); 7121 assert(te); 7122 7123 // Create a new tuple without the associated temporary 7124 auto res = new TupleExp(op.loc, te.exps); 7125 return res.expressionSemantic(sc); 7126 } 7127 7128 const stc = op.isLvalue() ? STC.ref_ : 0; 7129 auto tmp = copyToTemp(stc, "__assertOp", op); 7130 tmp.dsymbolSemantic(sc); 7131 7132 auto decl = new DeclarationExp(op.loc, tmp); 7133 temporariesPrefix = Expression.combine(temporariesPrefix, decl); 7134 7135 op = new VarExp(op.loc, tmp); 7136 op = op.expressionSemantic(sc); 7137 } 7138 return op; 7139 } 7140 7141 // if the assert condition is a mixin expression, try to compile it 7142 if (auto ce = exp.e1.isMixinExp()) 7143 { 7144 if (auto e1 = compileIt(ce)) 7145 exp.e1 = e1; 7146 } 7147 7148 Expressions* es; 7149 Objects* tiargs; 7150 Loc loc = exp.e1.loc; 7151 7152 const op = exp.e1.op; 7153 bool isEqualsCallExpression; 7154 if (const callExp = exp.e1.isCallExp()) 7155 { 7156 // https://issues.dlang.org/show_bug.cgi?id=20331 7157 // callExp.f may be null if the assert contains a call to 7158 // a function pointer or literal 7159 if (const callExpFunc = callExp.f) 7160 { 7161 const callExpIdent = callExpFunc.ident; 7162 isEqualsCallExpression = callExpIdent == Id.__equals || 7163 callExpIdent == Id.eq; 7164 } 7165 } 7166 if (op == EXP.equal || op == EXP.notEqual || 7167 op == EXP.lessThan || op == EXP.greaterThan || 7168 op == EXP.lessOrEqual || op == EXP.greaterOrEqual || 7169 op == EXP.identity || op == EXP.notIdentity || 7170 op == EXP.in_ || 7171 isEqualsCallExpression) 7172 { 7173 es = new Expressions(3); 7174 tiargs = new Objects(1); 7175 7176 if (isEqualsCallExpression) 7177 { 7178 auto callExp = cast(CallExp) exp.e1; 7179 auto args = callExp.arguments; 7180 7181 // structs with opEquals get rewritten to a DotVarExp: 7182 // a.opEquals(b) 7183 // https://issues.dlang.org/show_bug.cgi?id=20100 7184 if (args.length == 1) 7185 { 7186 auto dv = callExp.e1.isDotVarExp(); 7187 assert(dv); 7188 7189 // runtime args 7190 (*es)[1] = maybePromoteToTmp(dv.e1); 7191 (*es)[2] = maybePromoteToTmp((*args)[0]); 7192 } 7193 else 7194 { 7195 // runtime args 7196 (*es)[1] = maybePromoteToTmp((*args)[0]); 7197 (*es)[2] = maybePromoteToTmp((*args)[1]); 7198 } 7199 } 7200 else 7201 { 7202 auto binExp = cast(EqualExp) exp.e1; 7203 7204 // runtime args 7205 (*es)[1] = maybePromoteToTmp(binExp.e1); 7206 (*es)[2] = maybePromoteToTmp(binExp.e2); 7207 } 7208 7209 // template args 7210 Expression comp = new StringExp(loc, isEqualsCallExpression ? "==" : EXPtoString(exp.e1.op)); 7211 comp = comp.expressionSemantic(sc); 7212 (*es)[0] = comp; 7213 (*tiargs)[0] = (*es)[1].type; 7214 } 7215 7216 // Format exp.e1 before any additional boolean conversion 7217 // Ignore &&/|| because "assert(...) failed" is more informative than "false != true" 7218 else if (op != EXP.andAnd && op != EXP.orOr) 7219 { 7220 es = new Expressions(2); 7221 tiargs = new Objects(1); 7222 7223 if (auto ne = exp.e1.isNotExp()) 7224 { 7225 // Fetch the (potential non-bool) expression and fold 7226 // (n) negations into (n % 2) negations, e.g. !!a => a 7227 for (bool neg = true; ; neg = !neg) 7228 { 7229 if (auto ne2 = ne.e1.isNotExp()) 7230 ne = ne2; 7231 else 7232 { 7233 (*es)[0] = new StringExp(loc, neg ? "!" : ""); 7234 (*es)[1] = maybePromoteToTmp(ne.e1); 7235 break; 7236 } 7237 } 7238 } 7239 else 7240 { // Simply format exp.e1 7241 (*es)[0] = new StringExp(loc, ""); 7242 (*es)[1] = maybePromoteToTmp(exp.e1); 7243 } 7244 7245 (*tiargs)[0] = (*es)[1].type; 7246 7247 // Passing __ctfe to auto ref infers ref and aborts compilation: 7248 // "cannot modify compiler-generated variable __ctfe" 7249 auto ve = (*es)[1].isVarExp(); 7250 if (ve && ve.var.ident == Id.ctfe) 7251 { 7252 exp.msg = new StringExp(loc, "assert(__ctfe) failed!"); 7253 goto LSkip; 7254 } 7255 } 7256 else 7257 { 7258 OutBuffer buf; 7259 buf.printf("`%s` failed", exp.toChars()); 7260 exp.msg = new StringExp(Loc.initial, buf.extractSlice()); 7261 goto LSkip; 7262 } 7263 7264 Expression __assertFail = new IdentifierExp(exp.loc, Id.empty); 7265 auto assertFail = new DotIdExp(loc, __assertFail, Id.object); 7266 7267 auto dt = new DotTemplateInstanceExp(loc, assertFail, Id._d_assert_fail, tiargs); 7268 auto ec = CallExp.create(loc, dt, es); 7269 exp.msg = ec; 7270 } 7271 7272 LSkip: 7273 if (Expression ex = unaSemantic(exp, sc)) 7274 { 7275 result = ex; 7276 return; 7277 } 7278 7279 exp.e1 = resolveProperties(sc, exp.e1); 7280 // BUG: see if we can do compile time elimination of the Assert 7281 exp.e1 = exp.e1.optimize(WANTvalue); 7282 exp.e1 = exp.e1.toBoolean(sc); 7283 7284 if (exp.e1.op == EXP.error) 7285 { 7286 result = exp.e1; 7287 return; 7288 } 7289 7290 if (exp.msg) 7291 { 7292 exp.msg = expressionSemantic(exp.msg, sc); 7293 exp.msg = resolveProperties(sc, exp.msg); 7294 exp.msg = exp.msg.implicitCastTo(sc, Type.tchar.constOf().arrayOf()); 7295 exp.msg = exp.msg.optimize(WANTvalue); 7296 checkParamArgumentEscape(sc, null, null, null, STC.undefined_, exp.msg, true, false); 7297 } 7298 7299 if (exp.msg && exp.msg.op == EXP.error) 7300 { 7301 result = exp.msg; 7302 return; 7303 } 7304 7305 auto f1 = checkNonAssignmentArrayOp(exp.e1); 7306 auto f2 = exp.msg && checkNonAssignmentArrayOp(exp.msg); 7307 if (f1 || f2) 7308 return setError(); 7309 7310 if (exp.e1.toBool().hasValue(false)) 7311 { 7312 /* This is an `assert(0)` which means halt program execution 7313 */ 7314 FuncDeclaration fd = sc.parent.isFuncDeclaration(); 7315 if (fd) 7316 fd.hasReturnExp |= 4; 7317 sc.ctorflow.orCSX(CSX.halt); 7318 7319 if (global.params.useAssert == CHECKENABLE.off) 7320 { 7321 Expression e = new HaltExp(exp.loc); 7322 e = e.expressionSemantic(sc); 7323 result = e; 7324 return; 7325 } 7326 7327 // Only override the type when it isn't already some flavour of noreturn, 7328 // e.g. when this assert was generated by defaultInitLiteral 7329 if (!exp.type || !exp.type.isTypeNoreturn()) 7330 exp.type = Type.tnoreturn; 7331 } 7332 else 7333 exp.type = Type.tvoid; 7334 7335 result = !temporariesPrefix 7336 ? exp 7337 : Expression.combine(temporariesPrefix, exp).expressionSemantic(sc); 7338 } 7339 7340 override void visit(ThrowExp te) 7341 { 7342 import dmd.statementsem; 7343 7344 if (throwSemantic(te.loc, te.e1, sc)) 7345 result = te; 7346 else 7347 setError(); 7348 } 7349 7350 override void visit(DotIdExp exp) 7351 { 7352 static if (LOGSEMANTIC) 7353 { 7354 printf("DotIdExp::semantic(this = %p, '%s')\n", exp, exp.toChars()); 7355 //printf("e1.op = %d, '%s'\n", e1.op, Token.toChars(e1.op)); 7356 } 7357 7358 if (sc.flags & SCOPE.Cfile) 7359 { 7360 /* See if need to rewrite the AST because of cast/call ambiguity 7361 */ 7362 if (auto e = castCallAmbiguity(exp, sc)) 7363 { 7364 result = expressionSemantic(e, sc); 7365 return; 7366 } 7367 7368 if (exp.arrow) // ImportC only 7369 exp.e1 = exp.e1.expressionSemantic(sc).arrayFuncConv(sc); 7370 7371 if (exp.ident == Id.__xalignof && exp.e1.isTypeExp()) 7372 { 7373 // C11 6.5.3 says _Alignof only applies to types 7374 Expression e; 7375 Type t; 7376 Dsymbol s; 7377 dmd.typesem.resolve(exp.e1.type, exp.e1.loc, sc, e, t, s, true); 7378 if (e) 7379 { 7380 error(exp.e1.loc, "argument to `_Alignof` must be a type"); 7381 return setError(); 7382 } 7383 else if (t) 7384 { 7385 // Note similarity to getProperty() implementation of __xalignof 7386 const explicitAlignment = t.alignment(); 7387 const naturalAlignment = t.alignsize(); 7388 const actualAlignment = (explicitAlignment.isDefault() ? naturalAlignment : explicitAlignment.get()); 7389 result = new IntegerExp(exp.loc, actualAlignment, Type.tsize_t); 7390 } 7391 else if (s) 7392 { 7393 error(exp.e1.loc, "argument to `_Alignof` must be a type"); 7394 return setError(); 7395 } 7396 else 7397 assert(0); 7398 return; 7399 } 7400 7401 if (exp.ident != Id.__sizeof) 7402 { 7403 result = fieldLookup(exp.e1, sc, exp.ident, exp.arrow); 7404 return; 7405 } 7406 } 7407 7408 Expression e = exp.dotIdSemanticProp(sc, 1); 7409 7410 if (e && isDotOpDispatch(e)) 7411 { 7412 auto ode = e; 7413 uint errors = global.startGagging(); 7414 e = resolvePropertiesX(sc, e); 7415 // Any error or if 'e' is not resolved, go to UFCS 7416 if (global.endGagging(errors) || e is ode) 7417 e = null; /* fall down to UFCS */ 7418 else 7419 { 7420 result = e; 7421 return; 7422 } 7423 } 7424 if (!e) // if failed to find the property 7425 { 7426 /* If ident is not a valid property, rewrite: 7427 * e1.ident 7428 * as: 7429 * .ident(e1) 7430 */ 7431 e = resolveUFCSProperties(sc, exp); 7432 } 7433 result = e; 7434 } 7435 7436 override void visit(DotTemplateExp e) 7437 { 7438 if (e.type) 7439 { 7440 result = e; 7441 return; 7442 } 7443 if (Expression ex = unaSemantic(e, sc)) 7444 { 7445 result = ex; 7446 return; 7447 } 7448 // 'void' like TemplateExp 7449 e.type = Type.tvoid; 7450 result = e; 7451 } 7452 7453 override void visit(DotVarExp exp) 7454 { 7455 static if (LOGSEMANTIC) 7456 { 7457 printf("DotVarExp::semantic('%s')\n", exp.toChars()); 7458 } 7459 if (exp.type) 7460 { 7461 result = exp; 7462 return; 7463 } 7464 7465 exp.var = exp.var.toAlias().isDeclaration(); 7466 7467 exp.e1 = exp.e1.expressionSemantic(sc); 7468 7469 if (auto tup = exp.var.isTupleDeclaration()) 7470 { 7471 /* Replace: 7472 * e1.tuple(a, b, c) 7473 * with: 7474 * tuple(e1.a, e1.b, e1.c) 7475 */ 7476 Expression e0; 7477 Expression ev = sc.func ? extractSideEffect(sc, "__tup", e0, exp.e1) : exp.e1; 7478 7479 auto exps = new Expressions(); 7480 exps.reserve(tup.objects.length); 7481 for (size_t i = 0; i < tup.objects.length; i++) 7482 { 7483 RootObject o = (*tup.objects)[i]; 7484 Expression e; 7485 Declaration var; 7486 switch (o.dyncast()) with (DYNCAST) 7487 { 7488 case expression: 7489 e = cast(Expression)o; 7490 if (auto se = e.isDsymbolExp()) 7491 var = se.s.isDeclaration(); 7492 else if (auto ve = e.isVarExp()) 7493 if (!ve.var.isFuncDeclaration()) 7494 // Exempt functions for backwards compatibility reasons. 7495 // See: https://issues.dlang.org/show_bug.cgi?id=20470#c1 7496 var = ve.var; 7497 break; 7498 case dsymbol: 7499 Dsymbol s = cast(Dsymbol) o; 7500 Declaration d = s.isDeclaration(); 7501 if (!d || d.isFuncDeclaration()) 7502 // Exempt functions for backwards compatibility reasons. 7503 // See: https://issues.dlang.org/show_bug.cgi?id=20470#c1 7504 e = new DsymbolExp(exp.loc, s); 7505 else 7506 var = d; 7507 break; 7508 case type: 7509 e = new TypeExp(exp.loc, cast(Type)o); 7510 break; 7511 default: 7512 error(exp.loc, "`%s` is not an expression", o.toChars()); 7513 return setError(); 7514 } 7515 if (var) 7516 e = new DotVarExp(exp.loc, ev, var); 7517 exps.push(e); 7518 } 7519 7520 Expression e = new TupleExp(exp.loc, e0, exps); 7521 e = e.expressionSemantic(sc); 7522 result = e; 7523 return; 7524 } 7525 else if (auto ad = exp.var.isAliasDeclaration()) 7526 { 7527 if (auto t = ad.getType()) 7528 { 7529 result = new TypeExp(exp.loc, t).expressionSemantic(sc); 7530 return; 7531 } 7532 } 7533 7534 exp.e1 = exp.e1.addDtorHook(sc); 7535 7536 Type t1 = exp.e1.type; 7537 7538 if (FuncDeclaration fd = exp.var.isFuncDeclaration()) 7539 { 7540 // for functions, do checks after overload resolution 7541 if (!fd.functionSemantic()) 7542 return setError(); 7543 7544 /* https://issues.dlang.org/show_bug.cgi?id=13843 7545 * If fd obviously has no overloads, we should 7546 * normalize AST, and it will give a chance to wrap fd with FuncExp. 7547 */ 7548 if ((fd.isNested() && !fd.isThis()) || fd.isFuncLiteralDeclaration()) 7549 { 7550 // (e1, fd) 7551 auto e = symbolToExp(fd, exp.loc, sc, false); 7552 result = Expression.combine(exp.e1, e); 7553 return; 7554 } 7555 7556 exp.type = fd.type; 7557 assert(exp.type); 7558 } 7559 else if (OverDeclaration od = exp.var.isOverDeclaration()) 7560 { 7561 exp.type = Type.tvoid; // ambiguous type? 7562 } 7563 else 7564 { 7565 exp.type = exp.var.type; 7566 if (!exp.type && global.errors) // var is goofed up, just return error. 7567 return setError(); 7568 assert(exp.type); 7569 7570 if (t1.ty == Tpointer) 7571 t1 = t1.nextOf(); 7572 7573 exp.type = exp.type.addMod(t1.mod); 7574 7575 // https://issues.dlang.org/show_bug.cgi?id=23109 7576 // Run semantic on the DotVarExp type 7577 if (auto handle = exp.type.isClassHandle()) 7578 { 7579 if (handle.semanticRun < PASS.semanticdone && !handle.isBaseInfoComplete()) 7580 handle.dsymbolSemantic(null); 7581 } 7582 7583 Dsymbol vparent = exp.var.toParent(); 7584 AggregateDeclaration ad = vparent ? vparent.isAggregateDeclaration() : null; 7585 if (Expression e1x = getRightThis(exp.loc, sc, ad, exp.e1, exp.var, 1)) 7586 exp.e1 = e1x; 7587 else 7588 { 7589 /* Later checkRightThis will report correct error for invalid field variable access. 7590 */ 7591 Expression e = new VarExp(exp.loc, exp.var); 7592 e = e.expressionSemantic(sc); 7593 result = e; 7594 return; 7595 } 7596 checkAccess(exp.loc, sc, exp.e1, exp.var); 7597 7598 VarDeclaration v = exp.var.isVarDeclaration(); 7599 if (v && (v.isDataseg() || (v.storage_class & STC.manifest))) 7600 { 7601 Expression e = expandVar(WANTvalue, v); 7602 if (e) 7603 { 7604 result = e; 7605 return; 7606 } 7607 } 7608 7609 if (v && (v.isDataseg() || // fix https://issues.dlang.org/show_bug.cgi?id=8238 7610 (!v.needThis() && v.semanticRun > PASS.initial))) // fix https://issues.dlang.org/show_bug.cgi?id=17258 7611 { 7612 // (e1, v) 7613 checkAccess(exp.loc, sc, exp.e1, v); 7614 Expression e = new VarExp(exp.loc, v); 7615 e = new CommaExp(exp.loc, exp.e1, e); 7616 e = e.expressionSemantic(sc); 7617 result = e; 7618 return; 7619 } 7620 } 7621 //printf("-DotVarExp::semantic('%s')\n", toChars()); 7622 result = exp; 7623 } 7624 7625 override void visit(DotTemplateInstanceExp exp) 7626 { 7627 static if (LOGSEMANTIC) 7628 { 7629 printf("DotTemplateInstanceExp::semantic('%s')\n", exp.toChars()); 7630 } 7631 if (exp.type) 7632 { 7633 result = exp; 7634 return; 7635 } 7636 // Indicate we need to resolve by UFCS. 7637 Expression e = exp.dotTemplateSemanticProp(sc, DotExpFlag.gag); 7638 if (!e) 7639 e = resolveUFCSProperties(sc, exp); 7640 if (e is exp) 7641 e.type = Type.tvoid; // Unresolved type, because it needs inference 7642 result = e; 7643 } 7644 7645 override void visit(DelegateExp e) 7646 { 7647 static if (LOGSEMANTIC) 7648 { 7649 printf("DelegateExp::semantic('%s')\n", e.toChars()); 7650 } 7651 if (e.type) 7652 { 7653 result = e; 7654 return; 7655 } 7656 7657 e.e1 = e.e1.expressionSemantic(sc); 7658 7659 e.type = new TypeDelegate(e.func.type.isTypeFunction()); 7660 e.type = e.type.typeSemantic(e.loc, sc); 7661 7662 FuncDeclaration f = e.func.toAliasFunc(); 7663 AggregateDeclaration ad = f.isMemberLocal(); 7664 if (f.needThis()) 7665 e.e1 = getRightThis(e.loc, sc, ad, e.e1, f); 7666 7667 if (f.type.ty == Tfunction) 7668 { 7669 TypeFunction tf = cast(TypeFunction)f.type; 7670 if (!MODmethodConv(e.e1.type.mod, f.type.mod)) 7671 { 7672 OutBuffer thisBuf, funcBuf; 7673 MODMatchToBuffer(&thisBuf, e.e1.type.mod, tf.mod); 7674 MODMatchToBuffer(&funcBuf, tf.mod, e.e1.type.mod); 7675 error(e.loc, "%smethod `%s` is not callable using a %s`%s`", 7676 funcBuf.peekChars(), f.toPrettyChars(), thisBuf.peekChars(), e.e1.toChars()); 7677 return setError(); 7678 } 7679 } 7680 if (ad && ad.isClassDeclaration() && ad.type != e.e1.type) 7681 { 7682 // A downcast is required for interfaces 7683 // https://issues.dlang.org/show_bug.cgi?id=3706 7684 e.e1 = new CastExp(e.loc, e.e1, ad.type); 7685 e.e1 = e.e1.expressionSemantic(sc); 7686 } 7687 result = e; 7688 // declare dual-context container 7689 if (f.hasDualContext() && !sc.intypeof && sc.func) 7690 { 7691 // check access to second `this` 7692 if (AggregateDeclaration ad2 = f.isMember2()) 7693 { 7694 Expression te = new ThisExp(e.loc).expressionSemantic(sc); 7695 if (te.op != EXP.error) 7696 te = getRightThis(e.loc, sc, ad2, te, f); 7697 if (te.op == EXP.error) 7698 { 7699 error(e.loc, "need `this` of type `%s` to make delegate from function `%s`", ad2.toChars(), f.toChars()); 7700 return setError(); 7701 } 7702 } 7703 VarDeclaration vthis2 = makeThis2Argument(e.loc, sc, f); 7704 e.vthis2 = vthis2; 7705 Expression de = new DeclarationExp(e.loc, vthis2); 7706 result = Expression.combine(de, result); 7707 result = result.expressionSemantic(sc); 7708 } 7709 } 7710 7711 override void visit(DotTypeExp exp) 7712 { 7713 static if (LOGSEMANTIC) 7714 { 7715 printf("DotTypeExp::semantic('%s')\n", exp.toChars()); 7716 } 7717 if (exp.type) 7718 { 7719 result = exp; 7720 return; 7721 } 7722 7723 if (auto e = unaSemantic(exp, sc)) 7724 { 7725 result = e; 7726 return; 7727 } 7728 7729 exp.type = exp.sym.getType().addMod(exp.e1.type.mod); 7730 result = exp; 7731 } 7732 7733 override void visit(AddrExp exp) 7734 { 7735 static if (LOGSEMANTIC) 7736 { 7737 printf("AddrExp::semantic('%s')\n", exp.toChars()); 7738 } 7739 if (exp.type) 7740 { 7741 result = exp; 7742 return; 7743 } 7744 7745 if (Expression ex = unaSemantic(exp, sc)) 7746 { 7747 result = ex; 7748 return; 7749 } 7750 7751 if (sc.flags & SCOPE.Cfile) 7752 { 7753 /* Special handling for &"string"/&(T[]){0, 1} 7754 * since C regards string/array literals as lvalues 7755 */ 7756 auto e = exp.e1; 7757 if(e.isStringExp() || e.isArrayLiteralExp()) 7758 { 7759 e.type = typeSemantic(e.type, Loc.initial, sc); 7760 // if type is already a pointer exp is an illegal expression of the form `&(&"")` 7761 if (!e.type.isTypePointer()) 7762 { 7763 e.type = e.type.pointerTo(); 7764 result = e; 7765 return; 7766 } 7767 else 7768 { 7769 // `toLvalue` call further below is upon exp.e1, omitting & from the error message 7770 exp.toLvalue(sc, null); 7771 return setError(); 7772 } 7773 } 7774 } 7775 7776 int wasCond = exp.e1.op == EXP.question; 7777 7778 if (exp.e1.op == EXP.dotTemplateInstance) 7779 { 7780 DotTemplateInstanceExp dti = cast(DotTemplateInstanceExp)exp.e1; 7781 TemplateInstance ti = dti.ti; 7782 { 7783 //assert(ti.needsTypeInference(sc)); 7784 ti.dsymbolSemantic(sc); 7785 if (!ti.inst || ti.errors) // if template failed to expand 7786 return setError(); 7787 7788 Dsymbol s = ti.toAlias(); 7789 FuncDeclaration f = s.isFuncDeclaration(); 7790 if (f) 7791 { 7792 exp.e1 = new DotVarExp(exp.e1.loc, dti.e1, f); 7793 exp.e1 = exp.e1.expressionSemantic(sc); 7794 } 7795 } 7796 } 7797 else if (exp.e1.op == EXP.scope_) 7798 { 7799 TemplateInstance ti = (cast(ScopeExp)exp.e1).sds.isTemplateInstance(); 7800 if (ti) 7801 { 7802 //assert(ti.needsTypeInference(sc)); 7803 ti.dsymbolSemantic(sc); 7804 if (!ti.inst || ti.errors) // if template failed to expand 7805 return setError(); 7806 7807 Dsymbol s = ti.toAlias(); 7808 FuncDeclaration f = s.isFuncDeclaration(); 7809 if (f) 7810 { 7811 exp.e1 = new VarExp(exp.e1.loc, f); 7812 exp.e1 = exp.e1.expressionSemantic(sc); 7813 } 7814 } 7815 } 7816 /* https://issues.dlang.org/show_bug.cgi?id=809 7817 * 7818 * If the address of a lazy variable is taken, 7819 * the expression is rewritten so that the type 7820 * of it is the delegate type. This means that 7821 * the symbol is not going to represent a call 7822 * to the delegate anymore, but rather, the 7823 * actual symbol. 7824 */ 7825 if (auto ve = exp.e1.isVarExp()) 7826 { 7827 if (ve.var.storage_class & STC.lazy_) 7828 { 7829 exp.e1 = exp.e1.expressionSemantic(sc); 7830 exp.e1 = resolveProperties(sc, exp.e1); 7831 if (auto callExp = exp.e1.isCallExp()) 7832 { 7833 if (callExp.e1.type.toBasetype().ty == Tdelegate) 7834 { 7835 /* https://issues.dlang.org/show_bug.cgi?id=20551 7836 * 7837 * Cannot take address of lazy parameter in @safe code 7838 * because it might end up being a pointer to undefined 7839 * memory. 7840 */ 7841 if (1) 7842 { 7843 if (sc.setUnsafe(false, exp.loc, 7844 "cannot take address of lazy parameter `%s` in `@safe` function `%s`", ve, sc.func)) 7845 { 7846 setError(); 7847 return; 7848 } 7849 } 7850 VarExp ve2 = callExp.e1.isVarExp(); 7851 ve2.delegateWasExtracted = true; 7852 ve2.var.storage_class |= STC.scope_; 7853 result = ve2; 7854 return; 7855 } 7856 } 7857 } 7858 } 7859 7860 exp.e1 = exp.e1.toLvalue(sc, null); 7861 if (exp.e1.op == EXP.error) 7862 { 7863 result = exp.e1; 7864 return; 7865 } 7866 if (checkNonAssignmentArrayOp(exp.e1)) 7867 return setError(); 7868 7869 if (!exp.e1.type) 7870 { 7871 error(exp.loc, "cannot take address of `%s`", exp.e1.toChars()); 7872 return setError(); 7873 } 7874 if (!checkAddressable(exp, sc)) 7875 return setError(); 7876 7877 bool hasOverloads; 7878 if (auto f = isFuncAddress(exp, &hasOverloads)) 7879 { 7880 if (!hasOverloads && f.checkForwardRef(exp.loc)) 7881 return setError(); 7882 } 7883 else if (!exp.e1.type.deco) 7884 { 7885 // try to resolve the type 7886 exp.e1.type = exp.e1.type.typeSemantic(exp.e1.loc, sc); 7887 if (!exp.e1.type.deco) // still couldn't resolve it 7888 { 7889 if (auto ve = exp.e1.isVarExp()) 7890 { 7891 Declaration d = ve.var; 7892 error(exp.loc, "forward reference to %s `%s`", d.kind(), d.toChars()); 7893 } 7894 else 7895 error(exp.loc, "forward reference to type `%s` of expression `%s`", exp.e1.type.toChars(), exp.e1.toChars()); 7896 return setError(); 7897 } 7898 } 7899 7900 exp.type = exp.e1.type.pointerTo(); 7901 7902 // See if this should really be a delegate 7903 if (exp.e1.op == EXP.dotVariable) 7904 { 7905 DotVarExp dve = cast(DotVarExp)exp.e1; 7906 FuncDeclaration f = dve.var.isFuncDeclaration(); 7907 if (f) 7908 { 7909 f = f.toAliasFunc(); // FIXME, should see overloads 7910 // https://issues.dlang.org/show_bug.cgi?id=1983 7911 if (!dve.hasOverloads) 7912 f.tookAddressOf++; 7913 7914 Expression e; 7915 if (f.needThis()) 7916 e = new DelegateExp(exp.loc, dve.e1, f, dve.hasOverloads); 7917 else // It is a function pointer. Convert &v.f() --> (v, &V.f()) 7918 e = new CommaExp(exp.loc, dve.e1, new AddrExp(exp.loc, new VarExp(exp.loc, f, dve.hasOverloads))); 7919 e = e.expressionSemantic(sc); 7920 result = e; 7921 return; 7922 } 7923 7924 // Look for misaligned pointer in @safe mode 7925 if (checkUnsafeAccess(sc, dve, !exp.type.isMutable(), true)) 7926 return setError(); 7927 } 7928 else if (exp.e1.op == EXP.variable) 7929 { 7930 VarExp ve = cast(VarExp)exp.e1; 7931 VarDeclaration v = ve.var.isVarDeclaration(); 7932 if (v) 7933 { 7934 if (!checkAddressVar(sc, exp.e1, v)) 7935 return setError(); 7936 7937 ve.checkPurity(sc, v); 7938 } 7939 FuncDeclaration f = ve.var.isFuncDeclaration(); 7940 if (f) 7941 { 7942 /* Because nested functions cannot be overloaded, 7943 * mark here that we took its address because castTo() 7944 * may not be called with an exact match. 7945 * 7946 * https://issues.dlang.org/show_bug.cgi?id=19285 : 7947 * We also need to make sure we aren't inside a typeof. Ideally the compiler 7948 * would do typeof(...) semantic analysis speculatively then collect information 7949 * about what it used rather than relying on what are effectively semantically-global 7950 * variables but it doesn't. 7951 */ 7952 if (!sc.isFromSpeculativeSemanticContext() && (!ve.hasOverloads || (f.isNested() && !f.needThis()))) 7953 { 7954 // TODO: Refactor to use a proper interface that can keep track of causes. 7955 f.tookAddressOf++; 7956 } 7957 7958 if (f.isNested() && !f.needThis()) 7959 { 7960 if (f.isFuncLiteralDeclaration()) 7961 { 7962 if (!f.FuncDeclaration.isNested()) 7963 { 7964 /* Supply a 'null' for a this pointer if no this is available 7965 */ 7966 Expression e = new DelegateExp(exp.loc, new NullExp(exp.loc, Type.tnull), f, ve.hasOverloads); 7967 e = e.expressionSemantic(sc); 7968 result = e; 7969 return; 7970 } 7971 } 7972 Expression e = new DelegateExp(exp.loc, exp.e1, f, ve.hasOverloads); 7973 e = e.expressionSemantic(sc); 7974 result = e; 7975 return; 7976 } 7977 if (f.needThis()) 7978 { 7979 auto memberFunc = hasThis(sc); 7980 if (memberFunc && haveSameThis(memberFunc, f)) 7981 { 7982 /* Should probably supply 'this' after overload resolution, 7983 * not before. 7984 */ 7985 Expression ethis = new ThisExp(exp.loc); 7986 Expression e = new DelegateExp(exp.loc, ethis, f, ve.hasOverloads); 7987 e = e.expressionSemantic(sc); 7988 result = e; 7989 return; 7990 } 7991 if (sc.func && !sc.intypeof && !(sc.flags & SCOPE.debug_)) 7992 { 7993 sc.setUnsafe(false, exp.loc, 7994 "`this` reference necessary to take address of member `%s` in `@safe` function `%s`", 7995 f, sc.func); 7996 } 7997 } 7998 } 7999 } 8000 else if (exp.e1.op == EXP.index) 8001 { 8002 /* For: 8003 * int[3] a; 8004 * &a[i] 8005 * check 'a' the same as for a regular variable 8006 */ 8007 if (VarDeclaration v = expToVariable(exp.e1)) 8008 { 8009 exp.e1.checkPurity(sc, v); 8010 } 8011 } 8012 else if (wasCond) 8013 { 8014 /* a ? b : c was transformed to *(a ? &b : &c), but we still 8015 * need to do safety checks 8016 */ 8017 assert(exp.e1.op == EXP.star); 8018 PtrExp pe = cast(PtrExp)exp.e1; 8019 assert(pe.e1.op == EXP.question); 8020 CondExp ce = cast(CondExp)pe.e1; 8021 assert(ce.e1.op == EXP.address); 8022 assert(ce.e2.op == EXP.address); 8023 8024 // Re-run semantic on the address expressions only 8025 ce.e1.type = null; 8026 ce.e1 = ce.e1.expressionSemantic(sc); 8027 ce.e2.type = null; 8028 ce.e2 = ce.e2.expressionSemantic(sc); 8029 } 8030 result = exp.optimize(WANTvalue); 8031 } 8032 8033 override void visit(PtrExp exp) 8034 { 8035 static if (LOGSEMANTIC) 8036 { 8037 printf("PtrExp::semantic('%s')\n", exp.toChars()); 8038 } 8039 if (exp.type) 8040 { 8041 result = exp; 8042 return; 8043 } 8044 8045 Expression e = exp.op_overload(sc); 8046 if (e) 8047 { 8048 result = e; 8049 return; 8050 } 8051 8052 exp.e1 = exp.e1.arrayFuncConv(sc); 8053 8054 Type tb = exp.e1.type.toBasetype(); 8055 switch (tb.ty) 8056 { 8057 case Tpointer: 8058 exp.type = (cast(TypePointer)tb).next; 8059 break; 8060 8061 case Tsarray: 8062 case Tarray: 8063 if (isNonAssignmentArrayOp(exp.e1)) 8064 goto default; 8065 error(exp.loc, "using `*` on an array is no longer supported; use `*(%s).ptr` instead", exp.e1.toChars()); 8066 exp.type = (cast(TypeArray)tb).next; 8067 exp.e1 = exp.e1.castTo(sc, exp.type.pointerTo()); 8068 break; 8069 8070 case Terror: 8071 return setError(); 8072 8073 case Tnull: 8074 exp.type = Type.tnoreturn; // typeof(*null) is bottom type 8075 break; 8076 8077 default: 8078 error(exp.loc, "can only `*` a pointer, not a `%s`", exp.e1.type.toChars()); 8079 goto case Terror; 8080 } 8081 8082 if (sc.flags & SCOPE.Cfile && exp.type && exp.type.toBasetype().ty == Tvoid) 8083 { 8084 // https://issues.dlang.org/show_bug.cgi?id=23752 8085 // `&*((void*)(0))` is allowed in C 8086 result = exp; 8087 return; 8088 } 8089 8090 if (exp.checkValue()) 8091 return setError(); 8092 8093 result = exp; 8094 } 8095 8096 override void visit(NegExp exp) 8097 { 8098 static if (LOGSEMANTIC) 8099 { 8100 printf("NegExp::semantic('%s')\n", exp.toChars()); 8101 } 8102 if (exp.type) 8103 { 8104 result = exp; 8105 return; 8106 } 8107 8108 Expression e = exp.op_overload(sc); 8109 if (e) 8110 { 8111 result = e; 8112 return; 8113 } 8114 8115 fix16997(sc, exp); 8116 exp.type = exp.e1.type; 8117 Type tb = exp.type.toBasetype(); 8118 if (tb.ty == Tarray || tb.ty == Tsarray) 8119 { 8120 if (!isArrayOpValid(exp.e1)) 8121 { 8122 result = arrayOpInvalidError(exp); 8123 return; 8124 } 8125 result = exp; 8126 return; 8127 } 8128 if (!target.isVectorOpSupported(tb, exp.op)) 8129 { 8130 result = exp.incompatibleTypes(); 8131 return; 8132 } 8133 if (exp.e1.checkNoBool()) 8134 return setError(); 8135 if (exp.e1.checkArithmetic(exp.op) || 8136 exp.e1.checkSharedAccess(sc)) 8137 return setError(); 8138 8139 result = exp; 8140 } 8141 8142 override void visit(UAddExp exp) 8143 { 8144 static if (LOGSEMANTIC) 8145 { 8146 printf("UAddExp::semantic('%s')\n", exp.toChars()); 8147 } 8148 assert(!exp.type); 8149 8150 Expression e = exp.op_overload(sc); 8151 if (e) 8152 { 8153 result = e; 8154 return; 8155 } 8156 8157 fix16997(sc, exp); 8158 if (!target.isVectorOpSupported(exp.e1.type.toBasetype(), exp.op)) 8159 { 8160 result = exp.incompatibleTypes(); 8161 return; 8162 } 8163 if (exp.e1.checkNoBool()) 8164 return setError(); 8165 if (exp.e1.checkArithmetic(exp.op)) 8166 return setError(); 8167 if (exp.e1.checkSharedAccess(sc)) 8168 return setError(); 8169 8170 result = exp.e1; 8171 } 8172 8173 override void visit(ComExp exp) 8174 { 8175 if (exp.type) 8176 { 8177 result = exp; 8178 return; 8179 } 8180 8181 Expression e = exp.op_overload(sc); 8182 if (e) 8183 { 8184 result = e; 8185 return; 8186 } 8187 8188 fix16997(sc, exp); 8189 exp.type = exp.e1.type; 8190 Type tb = exp.type.toBasetype(); 8191 if (tb.ty == Tarray || tb.ty == Tsarray) 8192 { 8193 if (!isArrayOpValid(exp.e1)) 8194 { 8195 result = arrayOpInvalidError(exp); 8196 return; 8197 } 8198 result = exp; 8199 return; 8200 } 8201 if (!target.isVectorOpSupported(tb, exp.op)) 8202 { 8203 result = exp.incompatibleTypes(); 8204 return; 8205 } 8206 if (exp.e1.checkNoBool()) 8207 return setError(); 8208 if (exp.e1.checkIntegral() || 8209 exp.e1.checkSharedAccess(sc)) 8210 return setError(); 8211 8212 result = exp; 8213 } 8214 8215 override void visit(NotExp e) 8216 { 8217 if (e.type) 8218 { 8219 result = e; 8220 return; 8221 } 8222 8223 e.setNoderefOperand(); 8224 8225 // Note there is no operator overload 8226 if (Expression ex = unaSemantic(e, sc)) 8227 { 8228 result = ex; 8229 return; 8230 } 8231 8232 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684 8233 if (e.e1.op == EXP.type) 8234 e.e1 = resolveAliasThis(sc, e.e1); 8235 8236 e.e1 = resolveProperties(sc, e.e1); 8237 e.e1 = e.e1.toBoolean(sc); 8238 if (e.e1.type == Type.terror) 8239 { 8240 result = e.e1; 8241 return; 8242 } 8243 8244 if (!target.isVectorOpSupported(e.e1.type.toBasetype(), e.op)) 8245 { 8246 result = e.incompatibleTypes(); 8247 } 8248 // https://issues.dlang.org/show_bug.cgi?id=13910 8249 // Today NotExp can take an array as its operand. 8250 if (checkNonAssignmentArrayOp(e.e1)) 8251 return setError(); 8252 8253 e.type = (sc && sc.flags & SCOPE.Cfile) ? Type.tint32 : Type.tbool; 8254 result = e; 8255 } 8256 8257 override void visit(DeleteExp exp) 8258 { 8259 // @@@DEPRECATED_2.109@@@ 8260 // 1. Deprecated since 2.079 8261 // 2. Error since 2.099 8262 // 3. Removal of keyword, "delete" can be used for other identities 8263 if (!exp.isRAII) 8264 { 8265 error(exp.loc, "the `delete` keyword is obsolete"); 8266 errorSupplemental(exp.loc, "use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead"); 8267 return setError(); 8268 } 8269 8270 Expression e = exp; 8271 8272 if (Expression ex = unaSemantic(exp, sc)) 8273 { 8274 result = ex; 8275 return; 8276 } 8277 exp.e1 = resolveProperties(sc, exp.e1); 8278 exp.e1 = exp.e1.modifiableLvalue(sc, null); 8279 if (exp.e1.op == EXP.error) 8280 { 8281 result = exp.e1; 8282 return; 8283 } 8284 exp.type = Type.tvoid; 8285 8286 Type tb = exp.e1.type.toBasetype(); 8287 8288 /* Now that `delete` in user code is an error, we only get here when 8289 * `isRAII` has been set to true for the deletion of a `scope class`. */ 8290 if (tb.ty != Tclass) 8291 { 8292 error(exp.loc, "cannot delete type `%s`", exp.e1.type.toChars()); 8293 return setError(); 8294 } 8295 8296 ClassDeclaration cd = (cast(TypeClass)tb).sym; 8297 if (cd.isCOMinterface()) 8298 { 8299 /* Because COM classes are deleted by IUnknown.Release() 8300 */ 8301 error(exp.loc, "cannot `delete` instance of COM interface `%s`", cd.toChars()); 8302 return setError(); 8303 } 8304 8305 bool err = false; 8306 if (cd.dtor) 8307 { 8308 err |= !cd.dtor.functionSemantic(); 8309 err |= exp.checkPurity(sc, cd.dtor); 8310 err |= exp.checkSafety(sc, cd.dtor); 8311 err |= exp.checkNogc(sc, cd.dtor); 8312 } 8313 if (err) 8314 return setError(); 8315 8316 result = e; 8317 } 8318 8319 override void visit(CastExp exp) 8320 { 8321 static if (LOGSEMANTIC) 8322 { 8323 printf("CastExp::semantic('%s')\n", exp.toChars()); 8324 } 8325 //static int x; assert(++x < 10); 8326 if (exp.type) 8327 { 8328 result = exp; 8329 return; 8330 } 8331 8332 if ((sc && sc.flags & SCOPE.Cfile) && 8333 exp.to && (exp.to.ty == Tident || exp.to.ty == Tsarray) && 8334 (exp.e1.op == EXP.address || exp.e1.op == EXP.star || 8335 exp.e1.op == EXP.uadd || exp.e1.op == EXP.negate)) 8336 { 8337 /* Ambiguous cases arise from CParser if type-name is just an identifier. 8338 * ( identifier ) cast-expression 8339 * ( identifier [expression]) cast-expression 8340 * If we determine that `identifier` is a variable, and cast-expression 8341 * is one of the unary operators (& * + -), then rewrite this cast 8342 * as a binary expression. 8343 */ 8344 Loc loc = exp.loc; 8345 Type t; 8346 Expression e; 8347 Dsymbol s; 8348 exp.to.resolve(loc, sc, e, t, s); 8349 if (e !is null) 8350 { 8351 if (auto ex = exp.e1.isAddrExp()) // (ident) &exp -> (ident & exp) 8352 result = new AndExp(loc, e, ex.e1); 8353 else if (auto ex = exp.e1.isPtrExp()) // (ident) *exp -> (ident * exp) 8354 result = new MulExp(loc, e, ex.e1); 8355 else if (auto ex = exp.e1.isUAddExp()) // (ident) +exp -> (ident + exp) 8356 result = new AddExp(loc, e, ex.e1); 8357 else if (auto ex = exp.e1.isNegExp()) // (ident) -exp -> (ident - exp) 8358 result = new MinExp(loc, e, ex.e1); 8359 8360 assert(result); 8361 result = result.expressionSemantic(sc); 8362 return; 8363 } 8364 } 8365 8366 if (exp.to) 8367 { 8368 exp.to = exp.to.typeSemantic(exp.loc, sc); 8369 if (exp.to == Type.terror) 8370 return setError(); 8371 8372 if (!exp.to.hasPointers()) 8373 exp.setNoderefOperand(); 8374 8375 // When e1 is a template lambda, this cast may instantiate it with 8376 // the type 'to'. 8377 exp.e1 = inferType(exp.e1, exp.to); 8378 } 8379 8380 if (auto e = unaSemantic(exp, sc)) 8381 { 8382 result = e; 8383 return; 8384 } 8385 8386 if (exp.to && !exp.to.isTypeSArray() && !exp.to.isTypeFunction()) 8387 exp.e1 = exp.e1.arrayFuncConv(sc); 8388 8389 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684 8390 if (exp.e1.op == EXP.type) 8391 exp.e1 = resolveAliasThis(sc, exp.e1); 8392 8393 auto e1x = resolveProperties(sc, exp.e1); 8394 if (e1x.op == EXP.error) 8395 { 8396 result = e1x; 8397 return; 8398 } 8399 if (e1x.checkType()) 8400 return setError(); 8401 exp.e1 = e1x; 8402 8403 if (!exp.e1.type) 8404 { 8405 error(exp.loc, "cannot cast `%s`", exp.e1.toChars()); 8406 return setError(); 8407 } 8408 8409 // https://issues.dlang.org/show_bug.cgi?id=19954 8410 if (exp.e1.type.ty == Ttuple) 8411 { 8412 if (exp.to) 8413 { 8414 if (TypeTuple tt = exp.to.isTypeTuple()) 8415 { 8416 if (exp.e1.type.implicitConvTo(tt)) 8417 { 8418 result = exp.e1.castTo(sc, tt); 8419 return; 8420 } 8421 } 8422 } 8423 TupleExp te = exp.e1.isTupleExp(); 8424 if (te.exps.length == 1) 8425 exp.e1 = (*te.exps)[0]; 8426 } 8427 8428 // only allow S(x) rewrite if cast specified S explicitly. 8429 // See https://issues.dlang.org/show_bug.cgi?id=18545 8430 const bool allowImplicitConstruction = exp.to !is null; 8431 8432 if (!exp.to) // Handle cast(const) and cast(immutable), etc. 8433 { 8434 exp.to = exp.e1.type.castMod(exp.mod); 8435 exp.to = exp.to.typeSemantic(exp.loc, sc); 8436 8437 if (exp.to == Type.terror) 8438 return setError(); 8439 } 8440 8441 if (exp.to.ty == Ttuple) 8442 { 8443 error(exp.loc, "cannot cast `%s` of type `%s` to type sequence `%s`", exp.e1.toChars(), exp.e1.type.toChars(), exp.to.toChars()); 8444 return setError(); 8445 } 8446 8447 // cast(void) is used to mark e1 as unused, so it is safe 8448 if (exp.to.ty == Tvoid) 8449 { 8450 exp.type = exp.to; 8451 result = exp; 8452 return; 8453 } 8454 8455 if (!exp.to.equals(exp.e1.type) && exp.mod == cast(ubyte)~0) 8456 { 8457 if (Expression e = exp.op_overload(sc)) 8458 { 8459 result = e.implicitCastTo(sc, exp.to); 8460 return; 8461 } 8462 } 8463 8464 Type t1b = exp.e1.type.toBasetype(); 8465 Type tob = exp.to.toBasetype(); 8466 8467 if (allowImplicitConstruction && tob.ty == Tstruct && !tob.equals(t1b)) 8468 { 8469 /* Look to replace: 8470 * cast(S)t 8471 * with: 8472 * S(t) 8473 */ 8474 8475 // Rewrite as to.call(e1) 8476 Expression e = new TypeExp(exp.loc, exp.to); 8477 e = new CallExp(exp.loc, e, exp.e1); 8478 e = e.trySemantic(sc); 8479 if (e) 8480 { 8481 result = e; 8482 return; 8483 } 8484 } 8485 8486 if (!t1b.equals(tob) && (t1b.ty == Tarray || t1b.ty == Tsarray)) 8487 { 8488 if (checkNonAssignmentArrayOp(exp.e1)) 8489 return setError(); 8490 } 8491 8492 // Look for casting to a vector type 8493 if (tob.ty == Tvector && t1b.ty != Tvector) 8494 { 8495 result = new VectorExp(exp.loc, exp.e1, exp.to); 8496 result = result.expressionSemantic(sc); 8497 return; 8498 } 8499 8500 Expression ex = exp.e1.castTo(sc, exp.to); 8501 if (ex.op == EXP.error) 8502 { 8503 result = ex; 8504 return; 8505 } 8506 8507 // Check for unsafe casts 8508 if (!isSafeCast(ex, t1b, tob)) 8509 { 8510 if (sc.setUnsafe(false, exp.loc, "cast from `%s` to `%s` not allowed in safe code", exp.e1.type, exp.to)) 8511 { 8512 return setError(); 8513 } 8514 } 8515 8516 // `object.__ArrayCast` is a rewrite of an old runtime hook `_d_arraycast`. `_d_arraycast` was not built 8517 // to handle certain casts. Those casts which `object.__ArrayCast` does not support are filtered out. 8518 // See `e2ir.toElemCast` for other types of casts. If `object.__ArrayCast` is improved to support more 8519 // casts these conditions and potentially some logic in `e2ir.toElemCast` can be removed. 8520 if (tob.ty == Tarray) 8521 { 8522 // https://issues.dlang.org/show_bug.cgi?id=19840 8523 if (auto ad = isAggregate(t1b)) 8524 { 8525 if (ad.aliasthis) 8526 { 8527 Expression e = resolveAliasThis(sc, exp.e1); 8528 e = new CastExp(exp.loc, e, exp.to); 8529 result = e.expressionSemantic(sc); 8530 return; 8531 } 8532 } 8533 8534 if(t1b.ty == Tarray && exp.e1.op != EXP.arrayLiteral && sc.needsCodegen()) 8535 { 8536 auto tFrom = t1b.nextOf(); 8537 auto tTo = tob.nextOf(); 8538 8539 // https://issues.dlang.org/show_bug.cgi?id=20130 8540 if (exp.e1.op != EXP.string_ || !ex.isStringExp) 8541 { 8542 const uint fromSize = cast(uint)tFrom.size(); 8543 const uint toSize = cast(uint)tTo.size(); 8544 if (fromSize == SIZE_INVALID || toSize == SIZE_INVALID) 8545 return setError(); 8546 8547 // If array element sizes do not match, we must adjust the dimensions 8548 if (fromSize != toSize) 8549 { 8550 if (!verifyHookExist(exp.loc, *sc, Id.__ArrayCast, "casting array of structs")) 8551 return setError(); 8552 8553 // A runtime check is needed in case arrays don't line up. That check should 8554 // be done in the implementation of `object.__ArrayCast` 8555 if (toSize == 0 || (fromSize % toSize) != 0) 8556 { 8557 // lower to `object.__ArrayCast!(TFrom, TTo)(from)` 8558 8559 // fully qualify as `object.__ArrayCast` 8560 Expression id = new IdentifierExp(exp.loc, Id.empty); 8561 auto dotid = new DotIdExp(exp.loc, id, Id.object); 8562 8563 auto tiargs = new Objects(); 8564 tiargs.push(tFrom); 8565 tiargs.push(tTo); 8566 auto dt = new DotTemplateInstanceExp(exp.loc, dotid, Id.__ArrayCast, tiargs); 8567 8568 auto arguments = new Expressions(); 8569 arguments.push(exp.e1); 8570 Expression ce = new CallExp(exp.loc, dt, arguments); 8571 8572 result = expressionSemantic(ce, sc); 8573 return; 8574 } 8575 } 8576 } 8577 } 8578 } 8579 8580 if (sc && sc.flags & SCOPE.Cfile) 8581 { 8582 /* C11 6.5.4-5: A cast does not yield an lvalue. 8583 * So ensure that castTo does not strip away the cast so that this 8584 * can be enforced in other semantic visitor methods. 8585 */ 8586 if (!ex.isCastExp()) 8587 { 8588 ex = new CastExp(exp.loc, ex, exp.to); 8589 ex.type = exp.to; 8590 } 8591 } 8592 result = ex; 8593 } 8594 8595 override void visit(VectorExp exp) 8596 { 8597 static if (LOGSEMANTIC) 8598 { 8599 printf("VectorExp::semantic('%s')\n", exp.toChars()); 8600 } 8601 if (exp.type) 8602 { 8603 result = exp; 8604 return; 8605 } 8606 8607 exp.e1 = exp.e1.expressionSemantic(sc); 8608 exp.type = exp.to.typeSemantic(exp.loc, sc); 8609 if (exp.e1.op == EXP.error || exp.type.ty == Terror) 8610 { 8611 result = exp.e1; 8612 return; 8613 } 8614 8615 Type tb = exp.type.toBasetype(); 8616 assert(tb.ty == Tvector); 8617 TypeVector tv = cast(TypeVector)tb; 8618 Type te = tv.elementType(); 8619 exp.dim = cast(int)(tv.size(exp.loc) / te.size(exp.loc)); 8620 8621 bool checkElem(Expression elem) 8622 { 8623 if (elem.isConst() == 1) 8624 return false; 8625 8626 error(exp.loc, "constant expression expected, not `%s`", elem.toChars()); 8627 return true; 8628 } 8629 8630 exp.e1 = exp.e1.optimize(WANTvalue); 8631 bool res; 8632 if (exp.e1.op == EXP.arrayLiteral) 8633 { 8634 foreach (i; 0 .. exp.dim) 8635 { 8636 // Do not stop on first error - check all AST nodes even if error found 8637 res |= checkElem(exp.e1.isArrayLiteralExp()[i]); 8638 } 8639 } 8640 else if (exp.e1.type.ty == Tvoid) 8641 checkElem(exp.e1); 8642 8643 result = res ? ErrorExp.get() : exp; 8644 } 8645 8646 override void visit(VectorArrayExp e) 8647 { 8648 static if (LOGSEMANTIC) 8649 { 8650 printf("VectorArrayExp::semantic('%s')\n", e.toChars()); 8651 } 8652 if (!e.type) 8653 { 8654 unaSemantic(e, sc); 8655 e.e1 = resolveProperties(sc, e.e1); 8656 8657 if (e.e1.op == EXP.error) 8658 { 8659 result = e.e1; 8660 return; 8661 } 8662 assert(e.e1.type.ty == Tvector); 8663 e.type = e.e1.type.isTypeVector().basetype; 8664 } 8665 result = e; 8666 } 8667 8668 override void visit(SliceExp exp) 8669 { 8670 static if (LOGSEMANTIC) 8671 { 8672 printf("SliceExp::semantic('%s')\n", exp.toChars()); 8673 } 8674 if (exp.type) 8675 { 8676 result = exp; 8677 return; 8678 } 8679 8680 // operator overloading should be handled in ArrayExp already. 8681 if (Expression ex = unaSemantic(exp, sc)) 8682 { 8683 result = ex; 8684 return; 8685 } 8686 exp.e1 = resolveProperties(sc, exp.e1); 8687 if (exp.e1.op == EXP.type && exp.e1.type.ty != Ttuple) 8688 { 8689 if (exp.lwr || exp.upr) 8690 { 8691 error(exp.loc, "cannot slice type `%s`", exp.e1.toChars()); 8692 return setError(); 8693 } 8694 Expression e = new TypeExp(exp.loc, exp.e1.type.arrayOf()); 8695 result = e.expressionSemantic(sc); 8696 return; 8697 } 8698 if (!exp.lwr && !exp.upr) 8699 { 8700 if (exp.e1.op == EXP.arrayLiteral) 8701 { 8702 // Convert [a,b,c][] to [a,b,c] 8703 Type t1b = exp.e1.type.toBasetype(); 8704 Expression e = exp.e1; 8705 if (t1b.ty == Tsarray) 8706 { 8707 e = e.copy(); 8708 e.type = t1b.nextOf().arrayOf(); 8709 } 8710 result = e; 8711 return; 8712 } 8713 if (exp.e1.op == EXP.slice) 8714 { 8715 // Convert e[][] to e[] 8716 SliceExp se = cast(SliceExp)exp.e1; 8717 if (!se.lwr && !se.upr) 8718 { 8719 result = se; 8720 return; 8721 } 8722 } 8723 if (isArrayOpOperand(exp.e1)) 8724 { 8725 // Convert (a[]+b[])[] to a[]+b[] 8726 result = exp.e1; 8727 return; 8728 } 8729 } 8730 if (exp.e1.op == EXP.error) 8731 { 8732 result = exp.e1; 8733 return; 8734 } 8735 if (exp.e1.type.ty == Terror) 8736 return setError(); 8737 8738 Type t1b = exp.e1.type.toBasetype(); 8739 if (auto tp = t1b.isTypePointer()) 8740 { 8741 if (t1b.isPtrToFunction()) 8742 { 8743 error(exp.loc, "cannot slice function pointer `%s`", exp.e1.toChars()); 8744 return setError(); 8745 } 8746 if (!exp.lwr || !exp.upr) 8747 { 8748 error(exp.loc, "upper and lower bounds are needed to slice a pointer"); 8749 if (auto ad = isAggregate(tp.next.toBasetype())) 8750 { 8751 auto s = search_function(ad, Id.index); 8752 if (!s) s = search_function(ad, Id.slice); 8753 if (s) 8754 { 8755 auto fd = s.isFuncDeclaration(); 8756 if ((fd && !fd.getParameterList().length) || s.isTemplateDeclaration()) 8757 { 8758 errorSupplemental(exp.loc, 8759 "pointer `%s` points to an aggregate that defines an `%s`, perhaps you meant `(*%s)[]`", 8760 exp.e1.toChars(), 8761 s.ident.toChars(), 8762 exp.e1.toChars() 8763 ); 8764 } 8765 8766 } 8767 } 8768 8769 return setError(); 8770 } 8771 if (sc.setUnsafe(false, exp.loc, "pointer slicing not allowed in safe functions")) 8772 return setError(); 8773 } 8774 else if (t1b.ty == Tarray) 8775 { 8776 } 8777 else if (t1b.ty == Tsarray) 8778 { 8779 } 8780 else if (t1b.ty == Ttuple) 8781 { 8782 if (!exp.lwr && !exp.upr) 8783 { 8784 result = exp.e1; 8785 return; 8786 } 8787 if (!exp.lwr || !exp.upr) 8788 { 8789 error(exp.loc, "need upper and lower bound to slice a sequence"); 8790 return setError(); 8791 } 8792 } 8793 else if (t1b.ty == Tvector && exp.e1.isLvalue()) 8794 { 8795 // Convert e1 to corresponding static array 8796 TypeVector tv1 = cast(TypeVector)t1b; 8797 t1b = tv1.basetype; 8798 t1b = t1b.castMod(tv1.mod); 8799 exp.e1.type = t1b; 8800 } 8801 else 8802 { 8803 error(exp.loc, "`%s` cannot be sliced with `[]`", t1b.ty == Tvoid ? exp.e1.toChars() : t1b.toChars()); 8804 return setError(); 8805 } 8806 8807 /* Run semantic on lwr and upr. 8808 */ 8809 Scope* scx = sc; 8810 if (t1b.ty == Tsarray || t1b.ty == Tarray || t1b.ty == Ttuple) 8811 { 8812 // Create scope for 'length' variable 8813 ScopeDsymbol sym = new ArrayScopeSymbol(sc, exp); 8814 sym.parent = sc.scopesym; 8815 sc = sc.push(sym); 8816 } 8817 if (exp.lwr) 8818 { 8819 if (t1b.ty == Ttuple) 8820 sc = sc.startCTFE(); 8821 exp.lwr = exp.lwr.expressionSemantic(sc); 8822 exp.lwr = resolveProperties(sc, exp.lwr); 8823 if (t1b.ty == Ttuple) 8824 sc = sc.endCTFE(); 8825 exp.lwr = exp.lwr.implicitCastTo(sc, Type.tsize_t); 8826 } 8827 if (exp.upr) 8828 { 8829 if (t1b.ty == Ttuple) 8830 sc = sc.startCTFE(); 8831 exp.upr = exp.upr.expressionSemantic(sc); 8832 exp.upr = resolveProperties(sc, exp.upr); 8833 if (t1b.ty == Ttuple) 8834 sc = sc.endCTFE(); 8835 exp.upr = exp.upr.implicitCastTo(sc, Type.tsize_t); 8836 } 8837 if (sc != scx) 8838 sc = sc.pop(); 8839 if (exp.lwr && exp.lwr.type == Type.terror || exp.upr && exp.upr.type == Type.terror) 8840 return setError(); 8841 8842 if (t1b.ty == Ttuple) 8843 { 8844 exp.lwr = exp.lwr.ctfeInterpret(); 8845 exp.upr = exp.upr.ctfeInterpret(); 8846 uinteger_t i1 = exp.lwr.toUInteger(); 8847 uinteger_t i2 = exp.upr.toUInteger(); 8848 8849 TupleExp te; 8850 TypeTuple tup; 8851 size_t length; 8852 if (exp.e1.op == EXP.tuple) // slicing an expression tuple 8853 { 8854 te = cast(TupleExp)exp.e1; 8855 tup = null; 8856 length = te.exps.length; 8857 } 8858 else if (exp.e1.op == EXP.type) // slicing a type tuple 8859 { 8860 te = null; 8861 tup = cast(TypeTuple)t1b; 8862 length = Parameter.dim(tup.arguments); 8863 } 8864 else 8865 assert(0); 8866 8867 if (i2 < i1 || length < i2) 8868 { 8869 error(exp.loc, "string slice `[%llu .. %llu]` is out of bounds", i1, i2); 8870 return setError(); 8871 } 8872 8873 size_t j1 = cast(size_t)i1; 8874 size_t j2 = cast(size_t)i2; 8875 Expression e; 8876 if (exp.e1.op == EXP.tuple) 8877 { 8878 auto exps = new Expressions(j2 - j1); 8879 for (size_t i = 0; i < j2 - j1; i++) 8880 { 8881 (*exps)[i] = (*te.exps)[j1 + i]; 8882 } 8883 e = new TupleExp(exp.loc, te.e0, exps); 8884 } 8885 else 8886 { 8887 auto args = new Parameters(); 8888 args.reserve(j2 - j1); 8889 for (size_t i = j1; i < j2; i++) 8890 { 8891 Parameter arg = Parameter.getNth(tup.arguments, i); 8892 args.push(arg); 8893 } 8894 e = new TypeExp(exp.e1.loc, new TypeTuple(args)); 8895 } 8896 e = e.expressionSemantic(sc); 8897 result = e; 8898 return; 8899 } 8900 8901 exp.type = t1b.nextOf().arrayOf(); 8902 // Allow typedef[] -> typedef[] 8903 if (exp.type.equals(t1b)) 8904 exp.type = exp.e1.type; 8905 8906 // We might know $ now 8907 setLengthVarIfKnown(exp.lengthVar, t1b); 8908 8909 if (exp.lwr && exp.upr) 8910 { 8911 exp.lwr = exp.lwr.optimize(WANTvalue); 8912 exp.upr = exp.upr.optimize(WANTvalue); 8913 8914 IntRange lwrRange = getIntRange(exp.lwr); 8915 IntRange uprRange = getIntRange(exp.upr); 8916 8917 if (t1b.ty == Tsarray || t1b.ty == Tarray) 8918 { 8919 Expression el = new ArrayLengthExp(exp.loc, exp.e1); 8920 el = el.expressionSemantic(sc); 8921 el = el.optimize(WANTvalue); 8922 if (el.op == EXP.int64) 8923 { 8924 // Array length is known at compile-time. Upper is in bounds if it fits length. 8925 dinteger_t length = el.toInteger(); 8926 auto bounds = IntRange(SignExtendedNumber(0), SignExtendedNumber(length)); 8927 exp.upperIsInBounds = bounds.contains(uprRange); 8928 } 8929 else if (exp.upr.op == EXP.int64 && exp.upr.toInteger() == 0) 8930 { 8931 // Upper slice expression is '0'. Value is always in bounds. 8932 exp.upperIsInBounds = true; 8933 } 8934 else if (exp.upr.op == EXP.variable && (cast(VarExp)exp.upr).var.ident == Id.dollar) 8935 { 8936 // Upper slice expression is '$'. Value is always in bounds. 8937 exp.upperIsInBounds = true; 8938 } 8939 } 8940 else if (t1b.ty == Tpointer) 8941 { 8942 exp.upperIsInBounds = true; 8943 } 8944 else 8945 assert(0); 8946 8947 exp.lowerIsLessThanUpper = (lwrRange.imax <= uprRange.imin); 8948 8949 //printf("upperIsInBounds = %d lowerIsLessThanUpper = %d\n", exp.upperIsInBounds, exp.lowerIsLessThanUpper); 8950 } 8951 8952 result = exp; 8953 } 8954 8955 override void visit(ArrayLengthExp e) 8956 { 8957 static if (LOGSEMANTIC) 8958 { 8959 printf("ArrayLengthExp::semantic('%s')\n", e.toChars()); 8960 } 8961 if (e.type) 8962 { 8963 result = e; 8964 return; 8965 } 8966 8967 if (Expression ex = unaSemantic(e, sc)) 8968 { 8969 result = ex; 8970 return; 8971 } 8972 e.e1 = resolveProperties(sc, e.e1); 8973 8974 e.type = Type.tsize_t; 8975 result = e; 8976 } 8977 8978 override void visit(ArrayExp exp) 8979 { 8980 static if (LOGSEMANTIC) 8981 { 8982 printf("ArrayExp::semantic('%s')\n", exp.toChars()); 8983 } 8984 assert(!exp.type); 8985 8986 if (sc.flags & SCOPE.Cfile) 8987 { 8988 /* See if need to rewrite the AST because of cast/call ambiguity 8989 */ 8990 if (auto e = castCallAmbiguity(exp, sc)) 8991 { 8992 result = expressionSemantic(e, sc); 8993 return; 8994 } 8995 } 8996 8997 result = exp.carraySemantic(sc); // C semantics 8998 if (result) 8999 return; 9000 9001 Expression e = exp.op_overload(sc); 9002 if (e) 9003 { 9004 result = e; 9005 return; 9006 } 9007 9008 if (isAggregate(exp.e1.type)) 9009 error(exp.loc, "no `[]` operator overload for type `%s`", exp.e1.type.toChars()); 9010 else if (exp.e1.op == EXP.type && exp.e1.type.ty != Ttuple) 9011 error(exp.loc, "static array of `%s` with multiple lengths not allowed", exp.e1.type.toChars()); 9012 else if (isIndexableNonAggregate(exp.e1.type)) 9013 error(exp.loc, "only one index allowed to index `%s`", exp.e1.type.toChars()); 9014 else 9015 error(exp.loc, "cannot use `[]` operator on expression of type `%s`", exp.e1.type.toChars()); 9016 9017 result = ErrorExp.get(); 9018 } 9019 9020 override void visit(DotExp exp) 9021 { 9022 static if (LOGSEMANTIC) 9023 { 9024 printf("DotExp::semantic('%s')\n", exp.toChars()); 9025 if (exp.type) 9026 printf("\ttype = %s\n", exp.type.toChars()); 9027 } 9028 exp.e1 = exp.e1.expressionSemantic(sc); 9029 exp.e2 = exp.e2.expressionSemantic(sc); 9030 9031 if (exp.e1.op == EXP.type) 9032 { 9033 result = exp.e2; 9034 return; 9035 } 9036 if (exp.e2.op == EXP.type) 9037 { 9038 result = exp.e2; 9039 return; 9040 } 9041 if (auto te = exp.e2.isTemplateExp()) 9042 { 9043 Expression e = new DotTemplateExp(exp.loc, exp.e1, te.td); 9044 result = e.expressionSemantic(sc); 9045 return; 9046 } 9047 if (!exp.type) 9048 exp.type = exp.e2.type; 9049 result = exp; 9050 } 9051 9052 override void visit(CommaExp e) 9053 { 9054 //printf("Semantic.CommaExp() %s\n", e.toChars()); 9055 if (e.type) 9056 { 9057 result = e; 9058 return; 9059 } 9060 9061 // Allow `((a,b),(x,y))` 9062 if (e.allowCommaExp) 9063 { 9064 CommaExp.allow(e.e1); 9065 CommaExp.allow(e.e2); 9066 } 9067 9068 if (Expression ex = binSemanticProp(e, sc)) 9069 { 9070 result = ex; 9071 return; 9072 } 9073 e.e1 = e.e1.addDtorHook(sc); 9074 9075 if (checkNonAssignmentArrayOp(e.e1)) 9076 return setError(); 9077 9078 // Comma expressions trigger this conversion 9079 e.e2 = e.e2.arrayFuncConv(sc); 9080 9081 e.type = e.e2.type; 9082 result = e; 9083 9084 if (sc.flags & SCOPE.Cfile) 9085 return; 9086 9087 if (e.type is Type.tvoid) 9088 { 9089 checkMustUse(e.e1, sc); 9090 discardValue(e.e1); 9091 } 9092 else if (!e.allowCommaExp && !e.isGenerated) 9093 error(e.loc, "using the result of a comma expression is not allowed"); 9094 } 9095 9096 override void visit(IntervalExp e) 9097 { 9098 static if (LOGSEMANTIC) 9099 { 9100 printf("IntervalExp::semantic('%s')\n", e.toChars()); 9101 } 9102 if (e.type) 9103 { 9104 result = e; 9105 return; 9106 } 9107 9108 Expression le = e.lwr; 9109 le = le.expressionSemantic(sc); 9110 le = resolveProperties(sc, le); 9111 9112 Expression ue = e.upr; 9113 ue = ue.expressionSemantic(sc); 9114 ue = resolveProperties(sc, ue); 9115 9116 if (le.op == EXP.error) 9117 { 9118 result = le; 9119 return; 9120 } 9121 if (ue.op == EXP.error) 9122 { 9123 result = ue; 9124 return; 9125 } 9126 9127 e.lwr = le; 9128 e.upr = ue; 9129 9130 e.type = Type.tvoid; 9131 result = e; 9132 } 9133 9134 override void visit(DelegatePtrExp e) 9135 { 9136 static if (LOGSEMANTIC) 9137 { 9138 printf("DelegatePtrExp::semantic('%s')\n", e.toChars()); 9139 } 9140 if (!e.type) 9141 { 9142 unaSemantic(e, sc); 9143 e.e1 = resolveProperties(sc, e.e1); 9144 9145 if (e.e1.op == EXP.error) 9146 { 9147 result = e.e1; 9148 return; 9149 } 9150 e.type = Type.tvoidptr; 9151 } 9152 result = e; 9153 } 9154 9155 override void visit(DelegateFuncptrExp e) 9156 { 9157 static if (LOGSEMANTIC) 9158 { 9159 printf("DelegateFuncptrExp::semantic('%s')\n", e.toChars()); 9160 } 9161 if (!e.type) 9162 { 9163 unaSemantic(e, sc); 9164 e.e1 = resolveProperties(sc, e.e1); 9165 if (e.e1.op == EXP.error) 9166 { 9167 result = e.e1; 9168 return; 9169 } 9170 e.type = e.e1.type.nextOf().pointerTo(); 9171 } 9172 result = e; 9173 } 9174 9175 override void visit(IndexExp exp) 9176 { 9177 static if (LOGSEMANTIC) 9178 { 9179 printf("IndexExp::semantic('%s')\n", exp.toChars()); 9180 } 9181 if (exp.type) 9182 { 9183 result = exp; 9184 return; 9185 } 9186 9187 // operator overloading should be handled in ArrayExp already. 9188 if (!exp.e1.type) 9189 exp.e1 = exp.e1.expressionSemantic(sc).arrayFuncConv(sc); 9190 assert(exp.e1.type); // semantic() should already be run on it 9191 if (exp.e1.op == EXP.type && exp.e1.type.ty != Ttuple) 9192 { 9193 exp.e2 = exp.e2.expressionSemantic(sc); 9194 exp.e2 = resolveProperties(sc, exp.e2); 9195 Type nt; 9196 if (exp.e2.op == EXP.type) 9197 nt = new TypeAArray(exp.e1.type, exp.e2.type); 9198 else 9199 nt = new TypeSArray(exp.e1.type, exp.e2); 9200 Expression e = new TypeExp(exp.loc, nt); 9201 result = e.expressionSemantic(sc); 9202 return; 9203 } 9204 if (exp.e1.op == EXP.error) 9205 { 9206 result = exp.e1; 9207 return; 9208 } 9209 if (exp.e1.type.ty == Terror) 9210 return setError(); 9211 9212 // Note that unlike C we do not implement the int[ptr] 9213 9214 Type t1b = exp.e1.type.toBasetype(); 9215 9216 if (TypeVector tv1 = t1b.isTypeVector()) 9217 { 9218 // Convert e1 to corresponding static array 9219 t1b = tv1.basetype; 9220 t1b = t1b.castMod(tv1.mod); 9221 exp.e1 = exp.e1.castTo(sc, t1b); 9222 } 9223 if (t1b.ty == Tsarray || t1b.ty == Tarray) 9224 { 9225 if (!checkAddressable(exp, sc)) 9226 return setError(); 9227 } 9228 9229 /* Run semantic on e2 9230 */ 9231 Scope* scx = sc; 9232 if (t1b.ty == Tsarray || t1b.ty == Tarray || t1b.ty == Ttuple) 9233 { 9234 // Create scope for 'length' variable 9235 ScopeDsymbol sym = new ArrayScopeSymbol(sc, exp); 9236 sym.parent = sc.scopesym; 9237 sc = sc.push(sym); 9238 } 9239 if (t1b.ty == Ttuple) 9240 sc = sc.startCTFE(); 9241 exp.e2 = exp.e2.expressionSemantic(sc).arrayFuncConv(sc); 9242 exp.e2 = resolveProperties(sc, exp.e2); 9243 if (t1b.ty == Ttuple) 9244 sc = sc.endCTFE(); 9245 if (exp.e2.op == EXP.tuple) 9246 { 9247 TupleExp te = cast(TupleExp)exp.e2; 9248 if (te.exps && te.exps.length == 1) 9249 exp.e2 = Expression.combine(te.e0, (*te.exps)[0]); // bug 4444 fix 9250 } 9251 if (sc != scx) 9252 sc = sc.pop(); 9253 if (exp.e2.type == Type.terror) 9254 return setError(); 9255 9256 if (checkNonAssignmentArrayOp(exp.e1)) 9257 return setError(); 9258 9259 switch (t1b.ty) 9260 { 9261 case Tpointer: 9262 if (t1b.isPtrToFunction()) 9263 { 9264 error(exp.loc, "cannot index function pointer `%s`", exp.e1.toChars()); 9265 return setError(); 9266 } 9267 exp.e2 = exp.e2.implicitCastTo(sc, Type.tsize_t); 9268 if (exp.e2.type == Type.terror) 9269 return setError(); 9270 exp.e2 = exp.e2.optimize(WANTvalue); 9271 if (exp.e2.op == EXP.int64 && exp.e2.toInteger() == 0) 9272 { 9273 } 9274 else if (sc.setUnsafe(false, exp.loc, "`@safe` function `%s` cannot index pointer `%s`", sc.func, exp.e1)) 9275 { 9276 return setError(); 9277 } 9278 exp.type = (cast(TypeNext)t1b).next; 9279 break; 9280 9281 case Tarray: 9282 exp.e2 = exp.e2.implicitCastTo(sc, Type.tsize_t); 9283 if (exp.e2.type == Type.terror) 9284 return setError(); 9285 exp.type = (cast(TypeNext)t1b).next; 9286 break; 9287 9288 case Tsarray: 9289 { 9290 exp.e2 = exp.e2.implicitCastTo(sc, Type.tsize_t); 9291 if (exp.e2.type == Type.terror) 9292 return setError(); 9293 exp.type = t1b.nextOf(); 9294 break; 9295 } 9296 case Taarray: 9297 { 9298 TypeAArray taa = cast(TypeAArray)t1b; 9299 /* We can skip the implicit conversion if they differ only by 9300 * constness 9301 * https://issues.dlang.org/show_bug.cgi?id=2684 9302 * see also bug https://issues.dlang.org/show_bug.cgi?id=2954 b 9303 */ 9304 if (!arrayTypeCompatibleWithoutCasting(exp.e2.type, taa.index)) 9305 { 9306 exp.e2 = exp.e2.implicitCastTo(sc, taa.index); // type checking 9307 if (exp.e2.type == Type.terror) 9308 return setError(); 9309 } 9310 9311 semanticTypeInfo(sc, taa); 9312 checkNewEscape(sc, exp.e2, false); 9313 9314 exp.type = taa.next; 9315 break; 9316 } 9317 case Ttuple: 9318 { 9319 exp.e2 = exp.e2.implicitCastTo(sc, Type.tsize_t); 9320 if (exp.e2.type == Type.terror) 9321 return setError(); 9322 9323 exp.e2 = exp.e2.ctfeInterpret(); 9324 uinteger_t index = exp.e2.toUInteger(); 9325 9326 TupleExp te; 9327 TypeTuple tup; 9328 size_t length; 9329 if (exp.e1.op == EXP.tuple) 9330 { 9331 te = cast(TupleExp)exp.e1; 9332 tup = null; 9333 length = te.exps.length; 9334 } 9335 else if (exp.e1.op == EXP.type) 9336 { 9337 te = null; 9338 tup = cast(TypeTuple)t1b; 9339 length = Parameter.dim(tup.arguments); 9340 } 9341 else 9342 assert(0); 9343 9344 if (length <= index) 9345 { 9346 error(exp.loc, "array index `[%llu]` is outside array bounds `[0 .. %llu]`", index, cast(ulong)length); 9347 return setError(); 9348 } 9349 Expression e; 9350 if (exp.e1.op == EXP.tuple) 9351 { 9352 e = (*te.exps)[cast(size_t)index]; 9353 e = Expression.combine(te.e0, e); 9354 } 9355 else 9356 e = new TypeExp(exp.e1.loc, Parameter.getNth(tup.arguments, cast(size_t)index).type); 9357 result = e; 9358 return; 9359 } 9360 default: 9361 error(exp.loc, "`%s` must be an array or pointer type, not `%s`", exp.e1.toChars(), exp.e1.type.toChars()); 9362 return setError(); 9363 } 9364 9365 // We might know $ now 9366 setLengthVarIfKnown(exp.lengthVar, t1b); 9367 9368 if (t1b.ty == Tsarray || t1b.ty == Tarray) 9369 { 9370 Expression el = new ArrayLengthExp(exp.loc, exp.e1); 9371 el = el.expressionSemantic(sc); 9372 el = el.optimize(WANTvalue); 9373 if (el.op == EXP.int64) 9374 { 9375 exp.e2 = exp.e2.optimize(WANTvalue); 9376 dinteger_t length = el.toInteger(); 9377 if (length) 9378 { 9379 auto bounds = IntRange(SignExtendedNumber(0), SignExtendedNumber(length - 1)); 9380 // OR it in, because it might already be set for C array indexing 9381 exp.indexIsInBounds |= bounds.contains(getIntRange(exp.e2)); 9382 } 9383 else if (sc.flags & SCOPE.Cfile && t1b.ty == Tsarray) 9384 { 9385 if (auto ve = exp.e1.isVarExp()) 9386 { 9387 /* Rewrite 0-length C array ve[exp.e2] as *(ve + exp.e2) 9388 */ 9389 auto vp = ve.castTo(sc, t1b.isTypeSArray().next.pointerTo()); 9390 auto e = new AddExp(exp.loc, vp, exp.e2); 9391 auto pe = new PtrExp(exp.loc, e); 9392 result = pe.expressionSemantic(sc).optimize(WANTvalue); 9393 return; 9394 } 9395 } 9396 } 9397 } 9398 9399 result = exp; 9400 } 9401 9402 override void visit(PostExp exp) 9403 { 9404 static if (LOGSEMANTIC) 9405 { 9406 printf("PostExp::semantic('%s')\n", exp.toChars()); 9407 } 9408 if (exp.type) 9409 { 9410 result = exp; 9411 return; 9412 } 9413 9414 if (sc.flags & SCOPE.Cfile) 9415 { 9416 /* See if need to rewrite the AST because of cast/call ambiguity 9417 */ 9418 if (auto e = castCallAmbiguity(exp, sc)) 9419 { 9420 result = expressionSemantic(e, sc); 9421 return; 9422 } 9423 } 9424 9425 if (Expression ex = binSemantic(exp, sc)) 9426 { 9427 result = ex; 9428 return; 9429 } 9430 Expression e1x = resolveProperties(sc, exp.e1); 9431 if (e1x.op == EXP.error) 9432 { 9433 result = e1x; 9434 return; 9435 } 9436 exp.e1 = e1x; 9437 9438 Expression e = exp.op_overload(sc); 9439 if (e) 9440 { 9441 result = e; 9442 return; 9443 } 9444 9445 if (exp.e1.checkReadModifyWrite(exp.op)) 9446 return setError(); 9447 9448 if (exp.e1.op == EXP.slice) 9449 { 9450 const(char)* s = exp.op == EXP.plusPlus ? "increment" : "decrement"; 9451 error(exp.loc, "cannot post-%s array slice `%s`, use pre-%s instead", s, exp.e1.toChars(), s); 9452 return setError(); 9453 } 9454 9455 Type t1 = exp.e1.type.toBasetype(); 9456 if (t1.ty == Tclass || t1.ty == Tstruct || exp.e1.op == EXP.arrayLength) 9457 { 9458 /* Check for operator overloading, 9459 * but rewrite in terms of ++e instead of e++ 9460 */ 9461 9462 /* If e1 is not trivial, take a reference to it 9463 */ 9464 Expression de = null; 9465 if (exp.e1.op != EXP.variable && exp.e1.op != EXP.arrayLength) 9466 { 9467 // ref v = e1; 9468 auto v = copyToTemp(STC.ref_, "__postref", exp.e1); 9469 de = new DeclarationExp(exp.loc, v); 9470 exp.e1 = new VarExp(exp.e1.loc, v); 9471 } 9472 9473 /* Rewrite as: 9474 * auto tmp = e1; ++e1; tmp 9475 */ 9476 auto tmp = copyToTemp(0, "__pitmp", exp.e1); 9477 Expression ea = new DeclarationExp(exp.loc, tmp); 9478 9479 Expression eb = exp.e1.syntaxCopy(); 9480 eb = new PreExp(exp.op == EXP.plusPlus ? EXP.prePlusPlus : EXP.preMinusMinus, exp.loc, eb); 9481 9482 Expression ec = new VarExp(exp.loc, tmp); 9483 9484 // Combine de,ea,eb,ec 9485 if (de) 9486 ea = new CommaExp(exp.loc, de, ea); 9487 e = new CommaExp(exp.loc, ea, eb); 9488 e = new CommaExp(exp.loc, e, ec); 9489 e = e.expressionSemantic(sc); 9490 result = e; 9491 return; 9492 } 9493 9494 exp.e1 = exp.e1.modifiableLvalue(sc, exp.e1); 9495 exp.e1 = exp.e1.optimize(WANTvalue, /*keepLvalue*/ true); 9496 9497 e = exp; 9498 if (exp.e1.checkScalar() || 9499 exp.e1.checkSharedAccess(sc)) 9500 return setError(); 9501 if (exp.e1.checkNoBool()) 9502 return setError(); 9503 9504 if (exp.e1.type.ty == Tpointer) 9505 e = scaleFactor(exp, sc); 9506 else 9507 exp.e2 = exp.e2.castTo(sc, exp.e1.type); 9508 e.type = exp.e1.type; 9509 result = e; 9510 } 9511 9512 override void visit(PreExp exp) 9513 { 9514 Expression e = exp.op_overload(sc); 9515 // printf("PreExp::semantic('%s')\n", toChars()); 9516 if (e) 9517 { 9518 result = e; 9519 return; 9520 } 9521 9522 // Rewrite as e1+=1 or e1-=1 9523 if (exp.op == EXP.prePlusPlus) 9524 e = new AddAssignExp(exp.loc, exp.e1, IntegerExp.literal!1); 9525 else 9526 e = new MinAssignExp(exp.loc, exp.e1, IntegerExp.literal!1); 9527 result = e.expressionSemantic(sc); 9528 } 9529 9530 /* 9531 * Get the expression initializer for a specific struct 9532 * 9533 * Params: 9534 * sd = the struct for which the expression initializer is needed 9535 * loc = the location of the initializer 9536 * sc = the scope where the expression is located 9537 * t = the type of the expression 9538 * 9539 * Returns: 9540 * The expression initializer or error expression if any errors occured 9541 */ 9542 private Expression getInitExp(StructDeclaration sd, Loc loc, Scope* sc, Type t) 9543 { 9544 if (sd.zeroInit && !sd.isNested()) 9545 { 9546 // https://issues.dlang.org/show_bug.cgi?id=14606 9547 // Always use BlitExp for the special expression: (struct = 0) 9548 return IntegerExp.literal!0; 9549 } 9550 9551 if (sd.isNested()) 9552 { 9553 auto sle = new StructLiteralExp(loc, sd, null, t); 9554 if (!sd.fill(loc, *sle.elements, true)) 9555 return ErrorExp.get(); 9556 if (checkFrameAccess(loc, sc, sd, sle.elements.length)) 9557 return ErrorExp.get(); 9558 9559 sle.type = t; 9560 return sle; 9561 } 9562 9563 return t.defaultInit(loc); 9564 } 9565 9566 override void visit(AssignExp exp) 9567 { 9568 static if (LOGSEMANTIC) 9569 { 9570 if (exp.op == EXP.blit) printf("BlitExp.toElem('%s')\n", exp.toChars()); 9571 if (exp.op == EXP.assign) printf("AssignExp.toElem('%s')\n", exp.toChars()); 9572 if (exp.op == EXP.construct) printf("ConstructExp.toElem('%s')\n", exp.toChars()); 9573 } 9574 9575 void setResult(Expression e, int line = __LINE__) 9576 { 9577 //printf("line %d\n", line); 9578 result = e; 9579 } 9580 9581 if (exp.type) 9582 { 9583 return setResult(exp); 9584 } 9585 9586 Expression e1old = exp.e1; 9587 9588 if (auto e2comma = exp.e2.isCommaExp()) 9589 { 9590 if (!e2comma.isGenerated && !(sc.flags & SCOPE.Cfile)) 9591 error(exp.loc, "using the result of a comma expression is not allowed"); 9592 9593 /* Rewrite to get rid of the comma from rvalue 9594 * e1=(e0,e2) => e0,(e1=e2) 9595 */ 9596 Expression e0; 9597 exp.e2 = Expression.extractLast(e2comma, e0); 9598 Expression e = Expression.combine(e0, exp); 9599 return setResult(e.expressionSemantic(sc)); 9600 } 9601 9602 /* Look for operator overloading of a[arguments] = e2. 9603 * Do it before e1.expressionSemantic() otherwise the ArrayExp will have been 9604 * converted to unary operator overloading already. 9605 */ 9606 if (auto ae = exp.e1.isArrayExp()) 9607 { 9608 Expression res; 9609 9610 ae.e1 = ae.e1.expressionSemantic(sc); 9611 ae.e1 = resolveProperties(sc, ae.e1); 9612 Expression ae1old = ae.e1; 9613 9614 const(bool) maybeSlice = 9615 (ae.arguments.length == 0 || 9616 ae.arguments.length == 1 && (*ae.arguments)[0].op == EXP.interval); 9617 9618 IntervalExp ie = null; 9619 if (maybeSlice && ae.arguments.length) 9620 { 9621 assert((*ae.arguments)[0].op == EXP.interval); 9622 ie = cast(IntervalExp)(*ae.arguments)[0]; 9623 } 9624 Type att = null; // first cyclic `alias this` type 9625 while (true) 9626 { 9627 if (ae.e1.op == EXP.error) 9628 return setResult(ae.e1); 9629 9630 Expression e0 = null; 9631 Expression ae1save = ae.e1; 9632 ae.lengthVar = null; 9633 9634 Type t1b = ae.e1.type.toBasetype(); 9635 AggregateDeclaration ad = isAggregate(t1b); 9636 if (!ad) 9637 break; 9638 if (search_function(ad, Id.indexass)) 9639 { 9640 // Deal with $ 9641 res = resolveOpDollar(sc, ae, &e0); 9642 if (!res) // a[i..j] = e2 might be: a.opSliceAssign(e2, i, j) 9643 goto Lfallback; 9644 if (res.op == EXP.error) 9645 return setResult(res); 9646 9647 res = exp.e2.expressionSemantic(sc); 9648 if (res.op == EXP.error) 9649 return setResult(res); 9650 exp.e2 = res; 9651 9652 /* Rewrite (a[arguments] = e2) as: 9653 * a.opIndexAssign(e2, arguments) 9654 */ 9655 Expressions* a = ae.arguments.copy(); 9656 a.insert(0, exp.e2); 9657 res = new DotIdExp(exp.loc, ae.e1, Id.indexass); 9658 res = new CallExp(exp.loc, res, a); 9659 if (maybeSlice) // a[] = e2 might be: a.opSliceAssign(e2) 9660 res = res.trySemantic(sc); 9661 else 9662 res = res.expressionSemantic(sc); 9663 if (res) 9664 return setResult(Expression.combine(e0, res)); 9665 } 9666 9667 Lfallback: 9668 if (maybeSlice && search_function(ad, Id.sliceass)) 9669 { 9670 // Deal with $ 9671 res = resolveOpDollar(sc, ae, ie, &e0); 9672 if (res.op == EXP.error) 9673 return setResult(res); 9674 9675 res = exp.e2.expressionSemantic(sc); 9676 if (res.op == EXP.error) 9677 return setResult(res); 9678 9679 exp.e2 = res; 9680 9681 /* Rewrite (a[i..j] = e2) as: 9682 * a.opSliceAssign(e2, i, j) 9683 */ 9684 auto a = new Expressions(); 9685 a.push(exp.e2); 9686 if (ie) 9687 { 9688 a.push(ie.lwr); 9689 a.push(ie.upr); 9690 } 9691 res = new DotIdExp(exp.loc, ae.e1, Id.sliceass); 9692 res = new CallExp(exp.loc, res, a); 9693 res = res.expressionSemantic(sc); 9694 return setResult(Expression.combine(e0, res)); 9695 } 9696 9697 // No operator overloading member function found yet, but 9698 // there might be an alias this to try. 9699 if (ad.aliasthis && !isRecursiveAliasThis(att, ae.e1.type)) 9700 { 9701 /* Rewrite (a[arguments] op e2) as: 9702 * a.aliasthis[arguments] op e2 9703 */ 9704 ae.e1 = resolveAliasThis(sc, ae1save, true); 9705 if (ae.e1) 9706 continue; 9707 } 9708 break; 9709 } 9710 ae.e1 = ae1old; // recovery 9711 ae.lengthVar = null; 9712 } 9713 9714 /* Run this.e1 semantic. 9715 */ 9716 { 9717 Expression e1x = exp.e1; 9718 9719 /* With UFCS, e.f = value 9720 * Could mean: 9721 * .f(e, value) 9722 * or: 9723 * .f(e) = value 9724 */ 9725 if (auto dti = e1x.isDotTemplateInstanceExp()) 9726 { 9727 Expression e = dti.dotTemplateSemanticProp(sc, DotExpFlag.gag); 9728 if (!e) 9729 { 9730 return setResult(resolveUFCSProperties(sc, e1x, exp.e2)); 9731 } 9732 9733 e1x = e; 9734 } 9735 else if (sc.flags & SCOPE.Cfile && e1x.isDotIdExp()) 9736 { 9737 auto die = e1x.isDotIdExp(); 9738 e1x = fieldLookup(die.e1, sc, die.ident, die.arrow); 9739 } 9740 else if (auto die = e1x.isDotIdExp()) 9741 { 9742 Expression e = die.dotIdSemanticProp(sc, 1); 9743 if (e && isDotOpDispatch(e)) 9744 { 9745 /* https://issues.dlang.org/show_bug.cgi?id=19687 9746 * 9747 * On this branch, e2 is semantically analyzed in resolvePropertiesX, 9748 * but that call is done with gagged errors. That is the only time when 9749 * semantic gets ran on e2, that is why the error never gets to be printed. 9750 * In order to make sure that UFCS is tried with correct parameters, e2 9751 * needs to have semantic ran on it. 9752 */ 9753 auto ode = e; 9754 exp.e2 = exp.e2.expressionSemantic(sc); 9755 uint errors = global.startGagging(); 9756 e = resolvePropertiesX(sc, e, exp.e2); 9757 // Any error or if 'e' is not resolved, go to UFCS 9758 if (global.endGagging(errors) || e is ode) 9759 e = null; /* fall down to UFCS */ 9760 else 9761 return setResult(e); 9762 } 9763 if (!e) 9764 return setResult(resolveUFCSProperties(sc, e1x, exp.e2)); 9765 e1x = e; 9766 } 9767 else 9768 { 9769 if (auto se = e1x.isSliceExp()) 9770 se.arrayop = true; 9771 9772 e1x = e1x.expressionSemantic(sc); 9773 } 9774 9775 /* We have f = value. 9776 * Could mean: 9777 * f(value) 9778 * or: 9779 * f() = value 9780 */ 9781 if (Expression e = resolvePropertiesX(sc, e1x, exp.e2, exp)) 9782 return setResult(e); 9783 9784 if (e1x.checkRightThis(sc)) 9785 { 9786 return setError(); 9787 } 9788 exp.e1 = e1x; 9789 assert(exp.e1.type); 9790 } 9791 Type t1 = exp.e1.type.isTypeEnum() ? exp.e1.type : exp.e1.type.toBasetype(); 9792 9793 /* Run this.e2 semantic. 9794 * Different from other binary expressions, the analysis of e2 9795 * depends on the result of e1 in assignments. 9796 */ 9797 { 9798 Expression e2x = inferType(exp.e2, t1.baseElemOf()); 9799 e2x = e2x.expressionSemantic(sc); 9800 if (!t1.isTypeSArray()) 9801 e2x = e2x.arrayFuncConv(sc); 9802 e2x = resolveProperties(sc, e2x); 9803 if (e2x.op == EXP.type) 9804 e2x = resolveAliasThis(sc, e2x); //https://issues.dlang.org/show_bug.cgi?id=17684 9805 if (e2x.op == EXP.error) 9806 return setResult(e2x); 9807 // We delay checking the value for structs/classes as these might have 9808 // an opAssign defined. 9809 if ((t1.ty != Tstruct && t1.ty != Tclass && e2x.checkValue()) || 9810 e2x.checkSharedAccess(sc)) 9811 return setError(); 9812 9813 auto etmp = checkNoreturnVarAccess(e2x); 9814 if (etmp != e2x) 9815 return setResult(etmp); 9816 9817 exp.e2 = e2x; 9818 } 9819 9820 /* Rewrite tuple assignment as a tuple of assignments. 9821 */ 9822 { 9823 Expression e2x = exp.e2; 9824 9825 Ltupleassign: 9826 if (exp.e1.op == EXP.tuple && e2x.op == EXP.tuple) 9827 { 9828 TupleExp tup1 = cast(TupleExp)exp.e1; 9829 TupleExp tup2 = cast(TupleExp)e2x; 9830 size_t dim = tup1.exps.length; 9831 Expression e = null; 9832 if (dim != tup2.exps.length) 9833 { 9834 error(exp.loc, "mismatched sequence lengths, %d and %d", cast(int)dim, cast(int)tup2.exps.length); 9835 return setError(); 9836 } 9837 if (dim == 0) 9838 { 9839 e = IntegerExp.literal!0; 9840 e = new CastExp(exp.loc, e, Type.tvoid); // avoid "has no effect" error 9841 e = Expression.combine(tup1.e0, tup2.e0, e); 9842 } 9843 else 9844 { 9845 auto exps = new Expressions(dim); 9846 for (size_t i = 0; i < dim; i++) 9847 { 9848 Expression ex1 = (*tup1.exps)[i]; 9849 Expression ex2 = (*tup2.exps)[i]; 9850 (*exps)[i] = new AssignExp(exp.loc, ex1, ex2); 9851 } 9852 e = new TupleExp(exp.loc, Expression.combine(tup1.e0, tup2.e0), exps); 9853 } 9854 return setResult(e.expressionSemantic(sc)); 9855 } 9856 9857 /* Look for form: e1 = e2.aliasthis. 9858 */ 9859 if (exp.e1.op == EXP.tuple) 9860 { 9861 TupleDeclaration td = isAliasThisTuple(e2x); 9862 if (!td) 9863 goto Lnomatch; 9864 9865 assert(exp.e1.type.ty == Ttuple); 9866 TypeTuple tt = cast(TypeTuple)exp.e1.type; 9867 9868 Expression e0; 9869 Expression ev = extractSideEffect(sc, "__tup", e0, e2x); 9870 9871 auto iexps = new Expressions(); 9872 iexps.push(ev); 9873 for (size_t u = 0; u < iexps.length; u++) 9874 { 9875 Lexpand: 9876 Expression e = (*iexps)[u]; 9877 9878 Parameter arg = Parameter.getNth(tt.arguments, u); 9879 //printf("[%d] iexps.length = %d, ", u, iexps.length); 9880 //printf("e = (%s %s, %s), ", Token.toChars[e.op], e.toChars(), e.type.toChars()); 9881 //printf("arg = (%s, %s)\n", arg.toChars(), arg.type.toChars()); 9882 9883 if (!arg || !e.type.implicitConvTo(arg.type)) 9884 { 9885 // expand initializer to tuple 9886 if (expandAliasThisTuples(iexps, u) != -1) 9887 { 9888 if (iexps.length <= u) 9889 break; 9890 goto Lexpand; 9891 } 9892 goto Lnomatch; 9893 } 9894 } 9895 e2x = new TupleExp(e2x.loc, e0, iexps); 9896 e2x = e2x.expressionSemantic(sc); 9897 if (e2x.op == EXP.error) 9898 { 9899 result = e2x; 9900 return; 9901 } 9902 // Do not need to overwrite this.e2 9903 goto Ltupleassign; 9904 } 9905 Lnomatch: 9906 } 9907 9908 /* Inside constructor, if this is the first assignment of object field, 9909 * rewrite this to initializing the field. 9910 */ 9911 if (exp.op == EXP.assign 9912 && exp.e1.checkModifiable(sc) == Modifiable.initialization) 9913 { 9914 //printf("[%s] change to init - %s\n", exp.loc.toChars(), exp.toChars()); 9915 auto t = exp.type; 9916 exp = new ConstructExp(exp.loc, exp.e1, exp.e2); 9917 exp.type = t; 9918 9919 // https://issues.dlang.org/show_bug.cgi?id=13515 9920 // set Index::modifiable flag for complex AA element initialization 9921 if (auto ie1 = exp.e1.isIndexExp()) 9922 { 9923 Expression e1x = ie1.markSettingAAElem(); 9924 if (e1x.op == EXP.error) 9925 { 9926 result = e1x; 9927 return; 9928 } 9929 } 9930 } 9931 else if (exp.op == EXP.construct && exp.e1.op == EXP.variable && 9932 (cast(VarExp)exp.e1).var.storage_class & (STC.out_ | STC.ref_)) 9933 { 9934 exp.memset = MemorySet.referenceInit; 9935 } 9936 9937 if (exp.op == EXP.assign) // skip EXP.blit and EXP.construct, which are initializations 9938 { 9939 exp.e1.checkSharedAccess(sc); 9940 checkUnsafeAccess(sc, exp.e1, false, true); 9941 } 9942 9943 checkUnsafeAccess(sc, exp.e2, true, true); // Initializer must always be checked 9944 9945 /* If it is an assignment from a 'foreign' type, 9946 * check for operator overloading. 9947 */ 9948 if (exp.memset == MemorySet.referenceInit) 9949 { 9950 // If this is an initialization of a reference, 9951 // do nothing 9952 } 9953 else if (t1.ty == Tstruct) 9954 { 9955 auto e1x = exp.e1; 9956 auto e2x = exp.e2; 9957 auto sd = (cast(TypeStruct)t1).sym; 9958 9959 if (exp.op == EXP.construct) 9960 { 9961 Type t2 = e2x.type.toBasetype(); 9962 if (t2.ty == Tstruct && sd == (cast(TypeStruct)t2).sym) 9963 { 9964 sd.size(exp.loc); 9965 if (sd.sizeok != Sizeok.done) 9966 return setError(); 9967 if (!sd.ctor) 9968 sd.ctor = sd.searchCtor(); 9969 9970 // https://issues.dlang.org/show_bug.cgi?id=15661 9971 // Look for the form from last of comma chain. 9972 auto e2y = lastComma(e2x); 9973 9974 CallExp ce = (e2y.op == EXP.call) ? cast(CallExp)e2y : null; 9975 DotVarExp dve = (ce && ce.e1.op == EXP.dotVariable) 9976 ? cast(DotVarExp)ce.e1 : null; 9977 if (sd.ctor && ce && dve && dve.var.isCtorDeclaration() && 9978 // https://issues.dlang.org/show_bug.cgi?id=19389 9979 dve.e1.op != EXP.dotVariable && 9980 e2y.type.implicitConvTo(t1)) 9981 { 9982 /* Look for form of constructor call which is: 9983 * __ctmp.ctor(arguments...) 9984 */ 9985 9986 /* Before calling the constructor, initialize 9987 * variable with a bit copy of the default 9988 * initializer 9989 */ 9990 Expression einit = getInitExp(sd, exp.loc, sc, t1); 9991 if (einit.op == EXP.error) 9992 { 9993 result = einit; 9994 return; 9995 } 9996 9997 auto ae = new BlitExp(exp.loc, exp.e1, einit); 9998 ae.type = e1x.type; 9999 10000 /* Replace __ctmp being constructed with e1. 10001 * We need to copy constructor call expression, 10002 * because it may be used in other place. 10003 */ 10004 auto dvx = cast(DotVarExp)dve.copy(); 10005 dvx.e1 = e1x; 10006 auto cx = cast(CallExp)ce.copy(); 10007 cx.e1 = dvx; 10008 if (checkConstructorEscape(sc, cx, false)) 10009 return setError(); 10010 10011 Expression e0; 10012 Expression.extractLast(e2x, e0); 10013 10014 auto e = Expression.combine(e0, ae, cx); 10015 e = e.expressionSemantic(sc); 10016 result = e; 10017 return; 10018 } 10019 // https://issues.dlang.org/show_bug.cgi?id=21586 10020 // Rewrite CondExp or e1 will miss direct construction, e.g. 10021 // e1 = a ? S(1) : ...; -> AST: e1 = a ? (S(0)).this(1) : ...; 10022 // a temporary created and an extra destructor call. 10023 // AST will be rewritten to: 10024 // a ? e1 = 0, e1.this(1) : ...; -> blitting plus construction 10025 if (e2x.op == EXP.question) 10026 { 10027 /* Rewrite as: 10028 * a ? e1 = b : e1 = c; 10029 */ 10030 CondExp econd = cast(CondExp)e2x; 10031 Expression ea1 = new ConstructExp(econd.e1.loc, e1x, econd.e1); 10032 Expression ea2 = new ConstructExp(econd.e2.loc, e1x, econd.e2); 10033 Expression e = new CondExp(exp.loc, econd.econd, ea1, ea2); 10034 result = e.expressionSemantic(sc); 10035 return; 10036 } 10037 if (sd.postblit || sd.hasCopyCtor) 10038 { 10039 /* We have a copy constructor for this 10040 */ 10041 10042 if (e2x.isLvalue()) 10043 { 10044 if (sd.hasCopyCtor) 10045 { 10046 /* Rewrite as: 10047 * e1 = init, e1.copyCtor(e2); 10048 */ 10049 Expression einit = new BlitExp(exp.loc, exp.e1, getInitExp(sd, exp.loc, sc, t1)); 10050 einit.type = e1x.type; 10051 10052 Expression e; 10053 e = new DotIdExp(exp.loc, e1x, Id.ctor); 10054 e = new CallExp(exp.loc, e, e2x); 10055 e = new CommaExp(exp.loc, einit, e); 10056 10057 //printf("e: %s\n", e.toChars()); 10058 10059 result = e.expressionSemantic(sc); 10060 return; 10061 } 10062 else 10063 { 10064 if (!e2x.type.implicitConvTo(e1x.type)) 10065 { 10066 error(exp.loc, "conversion error from `%s` to `%s`", 10067 e2x.type.toChars(), e1x.type.toChars()); 10068 return setError(); 10069 } 10070 10071 /* Rewrite as: 10072 * (e1 = e2).postblit(); 10073 * 10074 * Blit assignment e1 = e2 returns a reference to the original e1, 10075 * then call the postblit on it. 10076 */ 10077 Expression e = e1x.copy(); 10078 e.type = e.type.mutableOf(); 10079 if (e.type.isShared && !sd.type.isShared) 10080 e.type = e.type.unSharedOf(); 10081 e = new BlitExp(exp.loc, e, e2x); 10082 e = new DotVarExp(exp.loc, e, sd.postblit, false); 10083 e = new CallExp(exp.loc, e); 10084 result = e.expressionSemantic(sc); 10085 return; 10086 } 10087 } 10088 else 10089 { 10090 /* The struct value returned from the function is transferred 10091 * so should not call the destructor on it. 10092 */ 10093 e2x = valueNoDtor(e2x); 10094 } 10095 } 10096 10097 // https://issues.dlang.org/show_bug.cgi?id=19251 10098 // if e2 cannot be converted to e1.type, maybe there is an alias this 10099 if (!e2x.implicitConvTo(t1)) 10100 { 10101 AggregateDeclaration ad2 = isAggregate(e2x.type); 10102 if (ad2 && ad2.aliasthis && !isRecursiveAliasThis(exp.att2, exp.e2.type)) 10103 { 10104 /* Rewrite (e1 op e2) as: 10105 * (e1 op e2.aliasthis) 10106 */ 10107 exp.e2 = new DotIdExp(exp.e2.loc, exp.e2, ad2.aliasthis.ident); 10108 result = exp.expressionSemantic(sc); 10109 return; 10110 } 10111 } 10112 } 10113 else if (!e2x.implicitConvTo(t1)) 10114 { 10115 sd.size(exp.loc); 10116 if (sd.sizeok != Sizeok.done) 10117 return setError(); 10118 if (!sd.ctor) 10119 sd.ctor = sd.searchCtor(); 10120 10121 if (sd.ctor) 10122 { 10123 /* Look for implicit constructor call 10124 * Rewrite as: 10125 * e1 = init, e1.ctor(e2) 10126 */ 10127 10128 /* Fix Issue 5153 : https://issues.dlang.org/show_bug.cgi?id=5153 10129 * Using `new` to initialize a struct object is a common mistake, but 10130 * the error message from the compiler is not very helpful in that 10131 * case. If exp.e2 is a NewExp and the type of new is the same as 10132 * the type as exp.e1 (struct in this case), then we know for sure 10133 * that the user wants to instantiate a struct. This is done to avoid 10134 * issuing an error when the user actually wants to call a constructor 10135 * which receives a class object. 10136 * 10137 * Foo f = new Foo2(0); is a valid expression if Foo has a constructor 10138 * which receives an instance of a Foo2 class 10139 */ 10140 if (exp.e2.op == EXP.new_) 10141 { 10142 auto newExp = cast(NewExp)(exp.e2); 10143 if (newExp.newtype && newExp.newtype == t1) 10144 { 10145 error(exp.loc, "cannot implicitly convert expression `%s` of type `%s` to `%s`", 10146 newExp.toChars(), newExp.type.toChars(), t1.toChars()); 10147 errorSupplemental(exp.loc, "Perhaps remove the `new` keyword?"); 10148 return setError(); 10149 } 10150 } 10151 10152 Expression einit = new BlitExp(exp.loc, e1x, getInitExp(sd, exp.loc, sc, t1)); 10153 einit.type = e1x.type; 10154 10155 Expression e; 10156 e = new DotIdExp(exp.loc, e1x, Id.ctor); 10157 e = new CallExp(exp.loc, e, e2x); 10158 e = new CommaExp(exp.loc, einit, e); 10159 e = e.expressionSemantic(sc); 10160 result = e; 10161 return; 10162 } 10163 if (search_function(sd, Id.call)) 10164 { 10165 /* Look for static opCall 10166 * https://issues.dlang.org/show_bug.cgi?id=2702 10167 * Rewrite as: 10168 * e1 = typeof(e1).opCall(arguments) 10169 */ 10170 e2x = typeDotIdExp(e2x.loc, e1x.type, Id.call); 10171 e2x = new CallExp(exp.loc, e2x, exp.e2); 10172 10173 e2x = e2x.expressionSemantic(sc); 10174 e2x = resolveProperties(sc, e2x); 10175 if (e2x.op == EXP.error) 10176 { 10177 result = e2x; 10178 return; 10179 } 10180 if (e2x.checkValue() || e2x.checkSharedAccess(sc)) 10181 return setError(); 10182 } 10183 } 10184 else // https://issues.dlang.org/show_bug.cgi?id=11355 10185 { 10186 AggregateDeclaration ad2 = isAggregate(e2x.type); 10187 if (ad2 && ad2.aliasthis && !isRecursiveAliasThis(exp.att2, exp.e2.type)) 10188 { 10189 /* Rewrite (e1 op e2) as: 10190 * (e1 op e2.aliasthis) 10191 */ 10192 exp.e2 = new DotIdExp(exp.e2.loc, exp.e2, ad2.aliasthis.ident); 10193 result = exp.expressionSemantic(sc); 10194 return; 10195 } 10196 } 10197 } 10198 else if (exp.op == EXP.assign) 10199 { 10200 if (e1x.op == EXP.index && (cast(IndexExp)e1x).e1.type.toBasetype().ty == Taarray) 10201 { 10202 /* 10203 * Rewrite: 10204 * aa[key] = e2; 10205 * as: 10206 * ref __aatmp = aa; 10207 * ref __aakey = key; 10208 * ref __aaval = e2; 10209 * (__aakey in __aatmp 10210 * ? __aatmp[__aakey].opAssign(__aaval) 10211 * : ConstructExp(__aatmp[__aakey], __aaval)); 10212 */ 10213 // ensure we keep the expr modifiable 10214 Expression esetting = (cast(IndexExp)e1x).markSettingAAElem(); 10215 if (esetting.op == EXP.error) 10216 { 10217 result = esetting; 10218 return; 10219 } 10220 assert(esetting.op == EXP.index); 10221 IndexExp ie = cast(IndexExp) esetting; 10222 Type t2 = e2x.type.toBasetype(); 10223 10224 Expression e0 = null; 10225 Expression ea = extractSideEffect(sc, "__aatmp", e0, ie.e1); 10226 Expression ek = extractSideEffect(sc, "__aakey", e0, ie.e2); 10227 Expression ev = extractSideEffect(sc, "__aaval", e0, e2x); 10228 10229 AssignExp ae = cast(AssignExp)exp.copy(); 10230 ae.e1 = new IndexExp(exp.loc, ea, ek); 10231 ae.e1 = ae.e1.expressionSemantic(sc); 10232 ae.e1 = ae.e1.optimize(WANTvalue); 10233 ae.e2 = ev; 10234 Expression e = ae.op_overload(sc); 10235 if (e) 10236 { 10237 Expression ey = null; 10238 if (t2.ty == Tstruct && sd == t2.toDsymbol(sc)) 10239 { 10240 ey = ev; 10241 } 10242 else if (!ev.implicitConvTo(ie.type) && sd.ctor) 10243 { 10244 // Look for implicit constructor call 10245 // Rewrite as S().ctor(e2) 10246 ey = new StructLiteralExp(exp.loc, sd, null); 10247 ey = new DotIdExp(exp.loc, ey, Id.ctor); 10248 ey = new CallExp(exp.loc, ey, ev); 10249 ey = ey.trySemantic(sc); 10250 } 10251 if (ey) 10252 { 10253 Expression ex; 10254 ex = new IndexExp(exp.loc, ea, ek); 10255 ex = ex.expressionSemantic(sc); 10256 ex = ex.modifiableLvalue(sc, ex); // allocate new slot 10257 ex = ex.optimize(WANTvalue); 10258 10259 ey = new ConstructExp(exp.loc, ex, ey); 10260 ey = ey.expressionSemantic(sc); 10261 if (ey.op == EXP.error) 10262 { 10263 result = ey; 10264 return; 10265 } 10266 ex = e; 10267 10268 // https://issues.dlang.org/show_bug.cgi?id=14144 10269 // The whole expression should have the common type 10270 // of opAssign() return and assigned AA entry. 10271 // Even if there's no common type, expression should be typed as void. 10272 if (!typeMerge(sc, EXP.question, ex, ey)) 10273 { 10274 ex = new CastExp(ex.loc, ex, Type.tvoid); 10275 ey = new CastExp(ey.loc, ey, Type.tvoid); 10276 } 10277 e = new CondExp(exp.loc, new InExp(exp.loc, ek, ea), ex, ey); 10278 } 10279 e = Expression.combine(e0, e); 10280 e = e.expressionSemantic(sc); 10281 result = e; 10282 return; 10283 } 10284 } 10285 else 10286 { 10287 Expression e = exp.op_overload(sc); 10288 if (e) 10289 { 10290 result = e; 10291 return; 10292 } 10293 } 10294 } 10295 else 10296 assert(exp.op == EXP.blit); 10297 10298 if (e2x.checkValue()) 10299 return setError(); 10300 10301 exp.e1 = e1x; 10302 exp.e2 = e2x; 10303 } 10304 else if (t1.ty == Tclass) 10305 { 10306 // Disallow assignment operator overloads for same type 10307 if (exp.op == EXP.assign && !exp.e2.implicitConvTo(exp.e1.type)) 10308 { 10309 Expression e = exp.op_overload(sc); 10310 if (e) 10311 { 10312 result = e; 10313 return; 10314 } 10315 } 10316 if (exp.e2.checkValue()) 10317 return setError(); 10318 } 10319 else if (t1.ty == Tsarray) 10320 { 10321 // SliceExp cannot have static array type without context inference. 10322 assert(exp.e1.op != EXP.slice); 10323 Expression e1x = exp.e1; 10324 Expression e2x = exp.e2; 10325 10326 /* C strings come through as static arrays. May need to adjust the size of the 10327 * string to match the size of e1. 10328 */ 10329 Type t2 = e2x.type.toBasetype(); 10330 if (sc.flags & SCOPE.Cfile && e2x.isStringExp() && t2.isTypeSArray()) 10331 { 10332 uinteger_t dim1 = t1.isTypeSArray().dim.toInteger(); 10333 uinteger_t dim2 = t2.isTypeSArray().dim.toInteger(); 10334 if (dim1 + 1 == dim2 || dim2 < dim1) 10335 { 10336 auto tsa2 = t2.isTypeSArray(); 10337 auto newt = tsa2.next.sarrayOf(dim1).immutableOf(); 10338 e2x = castTo(e2x, sc, newt); 10339 exp.e2 = e2x; 10340 } 10341 } 10342 10343 if (e2x.implicitConvTo(e1x.type)) 10344 { 10345 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())) 10346 { 10347 if (e1x.checkPostblit(sc, t1)) 10348 return setError(); 10349 } 10350 10351 // e2 matches to t1 because of the implicit length match, so 10352 if (isUnaArrayOp(e2x.op) || isBinArrayOp(e2x.op)) 10353 { 10354 // convert e1 to e1[] 10355 // e.g. e1[] = a[] + b[]; 10356 auto sle = new SliceExp(e1x.loc, e1x, null, null); 10357 sle.arrayop = true; 10358 e1x = sle.expressionSemantic(sc); 10359 } 10360 else 10361 { 10362 // convert e2 to t1 later 10363 // e.g. e1 = [1, 2, 3]; 10364 } 10365 } 10366 else 10367 { 10368 if (e2x.implicitConvTo(t1.nextOf().arrayOf()) > MATCH.nomatch) 10369 { 10370 uinteger_t dim1 = (cast(TypeSArray)t1).dim.toInteger(); 10371 uinteger_t dim2 = dim1; 10372 if (auto ale = e2x.isArrayLiteralExp()) 10373 { 10374 dim2 = ale.elements ? ale.elements.length : 0; 10375 } 10376 else if (auto se = e2x.isSliceExp()) 10377 { 10378 Type tx = toStaticArrayType(se); 10379 if (tx) 10380 dim2 = (cast(TypeSArray)tx).dim.toInteger(); 10381 } 10382 if (dim1 != dim2) 10383 { 10384 error(exp.loc, "mismatched array lengths, %d and %d", cast(int)dim1, cast(int)dim2); 10385 return setError(); 10386 } 10387 } 10388 10389 // May be block or element-wise assignment, so 10390 // convert e1 to e1[] 10391 if (exp.op != EXP.assign) 10392 { 10393 // If multidimensional static array, treat as one large array 10394 // 10395 // Find the appropriate array type depending on the assignment, e.g. 10396 // int[3] = int => int[3] 10397 // int[3][2] = int => int[6] 10398 // int[3][2] = int[] => int[3][2] 10399 // int[3][2][4] + int => int[24] 10400 // int[3][2][4] + int[] => int[3][8] 10401 ulong dim = t1.isTypeSArray().dim.toUInteger(); 10402 auto type = t1.nextOf(); 10403 10404 for (TypeSArray tsa; (tsa = type.isTypeSArray()) !is null; ) 10405 { 10406 import core.checkedint : mulu; 10407 10408 // Accumulate skipped dimensions 10409 bool overflow = false; 10410 dim = mulu(dim, tsa.dim.toUInteger(), overflow); 10411 if (overflow || dim >= uint.max) 10412 { 10413 // dym exceeds maximum array size 10414 error(exp.loc, "static array `%s` size overflowed to %llu", 10415 e1x.type.toChars(), cast(ulong) dim); 10416 return setError(); 10417 } 10418 10419 // Move to the element type 10420 type = tsa.nextOf().toBasetype(); 10421 10422 // Rewrite ex1 as a static array if a matching type was found 10423 if (e2x.implicitConvTo(type) > MATCH.nomatch) 10424 { 10425 e1x.type = type.sarrayOf(dim); 10426 break; 10427 } 10428 } 10429 } 10430 auto sle = new SliceExp(e1x.loc, e1x, null, null); 10431 sle.arrayop = true; 10432 e1x = sle.expressionSemantic(sc); 10433 } 10434 if (e1x.op == EXP.error) 10435 return setResult(e1x); 10436 if (e2x.op == EXP.error) 10437 return setResult(e2x); 10438 10439 exp.e1 = e1x; 10440 exp.e2 = e2x; 10441 t1 = e1x.type.toBasetype(); 10442 } 10443 /* Check the mutability of e1. 10444 */ 10445 if (auto ale = exp.e1.isArrayLengthExp()) 10446 { 10447 // e1 is not an lvalue, but we let code generator handle it 10448 10449 auto ale1x = ale.e1.modifiableLvalue(sc, exp.e1); 10450 if (ale1x.op == EXP.error) 10451 return setResult(ale1x); 10452 ale.e1 = ale1x; 10453 10454 Type tn = ale.e1.type.toBasetype().nextOf(); 10455 checkDefCtor(ale.loc, tn); 10456 10457 Identifier hook = global.params.tracegc ? Id._d_arraysetlengthTTrace : Id._d_arraysetlengthT; 10458 if (!verifyHookExist(exp.loc, *sc, Id._d_arraysetlengthTImpl, "resizing arrays")) 10459 return setError(); 10460 10461 exp.e2 = exp.e2.expressionSemantic(sc); 10462 auto lc = lastComma(exp.e2); 10463 lc = lc.optimize(WANTvalue); 10464 // use slice expression when arr.length = 0 to avoid runtime call 10465 if(lc.op == EXP.int64 && lc.toInteger() == 0) 10466 { 10467 Expression se = new SliceExp(ale.loc, ale.e1, lc, lc); 10468 Expression as = new AssignExp(ale.loc, ale.e1, se); 10469 as = as.expressionSemantic(sc); 10470 auto res = Expression.combine(as, exp.e2); 10471 res.type = ale.type; 10472 return setResult(res); 10473 } 10474 10475 if (!sc.needsCodegen()) // if compile time creature only 10476 { 10477 exp.type = Type.tsize_t; 10478 return setResult(exp); 10479 } 10480 10481 // Lower to object._d_arraysetlengthTImpl!(typeof(e1))._d_arraysetlengthT{,Trace}(e1, e2) 10482 Expression id = new IdentifierExp(ale.loc, Id.empty); 10483 id = new DotIdExp(ale.loc, id, Id.object); 10484 auto tiargs = new Objects(); 10485 tiargs.push(ale.e1.type); 10486 id = new DotTemplateInstanceExp(ale.loc, id, Id._d_arraysetlengthTImpl, tiargs); 10487 id = new DotIdExp(ale.loc, id, hook); 10488 id = id.expressionSemantic(sc); 10489 10490 auto arguments = new Expressions(); 10491 arguments.reserve(5); 10492 if (global.params.tracegc) 10493 { 10494 auto funcname = (sc.callsc && sc.callsc.func) ? sc.callsc.func.toPrettyChars() : sc.func.toPrettyChars(); 10495 arguments.push(new StringExp(exp.loc, exp.loc.filename.toDString())); 10496 arguments.push(new IntegerExp(exp.loc, exp.loc.linnum, Type.tint32)); 10497 arguments.push(new StringExp(exp.loc, funcname.toDString())); 10498 } 10499 arguments.push(ale.e1); 10500 arguments.push(exp.e2); 10501 10502 Expression ce = new CallExp(ale.loc, id, arguments).expressionSemantic(sc); 10503 auto res = new LoweredAssignExp(exp, ce); 10504 // if (global.params.verbose) 10505 // message("lowered %s =>\n %s", exp.toChars(), res.toChars()); 10506 res.type = Type.tsize_t; 10507 return setResult(res); 10508 } 10509 else if (auto se = exp.e1.isSliceExp()) 10510 { 10511 Type tn = se.type.nextOf(); 10512 const fun = sc.func; 10513 if (exp.op == EXP.assign && !tn.isMutable() && 10514 // allow modifiation in module ctor, see 10515 // https://issues.dlang.org/show_bug.cgi?id=9884 10516 (!fun || (fun && !fun.isStaticCtorDeclaration()))) 10517 { 10518 error(exp.loc, "slice `%s` is not mutable", se.toChars()); 10519 return setError(); 10520 } 10521 10522 if (exp.op == EXP.assign && !tn.baseElemOf().isAssignable()) 10523 { 10524 error(exp.loc, "slice `%s` is not mutable, struct `%s` has immutable members", 10525 exp.e1.toChars(), tn.baseElemOf().toChars()); 10526 result = ErrorExp.get(); 10527 return; 10528 } 10529 10530 // For conditional operator, both branches need conversion. 10531 while (se.e1.op == EXP.slice) 10532 se = cast(SliceExp)se.e1; 10533 if (se.e1.op == EXP.question && se.e1.type.toBasetype().ty == Tsarray) 10534 { 10535 se.e1 = se.e1.modifiableLvalue(sc, exp.e1); 10536 if (se.e1.op == EXP.error) 10537 return setResult(se.e1); 10538 } 10539 } 10540 else 10541 { 10542 if (t1.ty == Tsarray && exp.op == EXP.assign) 10543 { 10544 Type tn = exp.e1.type.nextOf(); 10545 if (tn && !tn.baseElemOf().isAssignable()) 10546 { 10547 error(exp.loc, "array `%s` is not mutable, struct `%s` has immutable members", 10548 exp.e1.toChars(), tn.baseElemOf().toChars()); 10549 result = ErrorExp.get(); 10550 return; 10551 } 10552 } 10553 10554 Expression e1x = exp.e1; 10555 10556 // Try to do a decent error message with the expression 10557 // before it gets constant folded 10558 if (exp.op == EXP.assign) 10559 e1x = e1x.modifiableLvalue(sc, e1old); 10560 10561 e1x = e1x.optimize(WANTvalue, /*keepLvalue*/ true); 10562 10563 if (e1x.op == EXP.error) 10564 { 10565 result = e1x; 10566 return; 10567 } 10568 exp.e1 = e1x; 10569 } 10570 10571 /* Tweak e2 based on the type of e1. 10572 */ 10573 Expression e2x = exp.e2; 10574 Type t2 = e2x.type.toBasetype(); 10575 10576 // If it is a array, get the element type. Note that it may be 10577 // multi-dimensional. 10578 Type telem = t1; 10579 while (telem.ty == Tarray) 10580 telem = telem.nextOf(); 10581 10582 if (exp.e1.op == EXP.slice && t1.nextOf() && 10583 (telem.ty != Tvoid || e2x.op == EXP.null_) && 10584 e2x.implicitConvTo(t1.nextOf())) 10585 { 10586 // Check for block assignment. If it is of type void[], void[][], etc, 10587 // '= null' is the only allowable block assignment (Bug 7493) 10588 exp.memset = MemorySet.blockAssign; // make it easy for back end to tell what this is 10589 e2x = e2x.implicitCastTo(sc, t1.nextOf()); 10590 if (exp.op != EXP.blit && e2x.isLvalue() && exp.e1.checkPostblit(sc, t1.nextOf())) 10591 return setError(); 10592 } 10593 else if (exp.e1.op == EXP.slice && 10594 (t2.ty == Tarray || t2.ty == Tsarray) && 10595 t2.nextOf().implicitConvTo(t1.nextOf())) 10596 { 10597 // Check element-wise assignment. 10598 10599 /* If assigned elements number is known at compile time, 10600 * check the mismatch. 10601 */ 10602 SliceExp se1 = cast(SliceExp)exp.e1; 10603 TypeSArray tsa1 = cast(TypeSArray)toStaticArrayType(se1); 10604 TypeSArray tsa2 = null; 10605 if (auto ale = e2x.isArrayLiteralExp()) 10606 tsa2 = cast(TypeSArray)t2.nextOf().sarrayOf(ale.elements.length); 10607 else if (auto se = e2x.isSliceExp()) 10608 tsa2 = cast(TypeSArray)toStaticArrayType(se); 10609 else 10610 tsa2 = t2.isTypeSArray(); 10611 10612 if (tsa1 && tsa2) 10613 { 10614 uinteger_t dim1 = tsa1.dim.toInteger(); 10615 uinteger_t dim2 = tsa2.dim.toInteger(); 10616 if (dim1 != dim2) 10617 { 10618 error(exp.loc, "mismatched array lengths %d and %d for assignment `%s`", cast(int)dim1, cast(int)dim2, exp.toChars()); 10619 return setError(); 10620 } 10621 } 10622 10623 if (exp.op != EXP.blit && 10624 (e2x.op == EXP.slice && (cast(UnaExp)e2x).e1.isLvalue() || 10625 e2x.op == EXP.cast_ && (cast(UnaExp)e2x).e1.isLvalue() || 10626 e2x.op != EXP.slice && e2x.isLvalue())) 10627 { 10628 if (exp.e1.checkPostblit(sc, t1.nextOf())) 10629 return setError(); 10630 } 10631 10632 Type t2n = t2.nextOf(); 10633 Type t1n = t1.nextOf(); 10634 int offset; 10635 if (t2n.equivalent(t1n) || 10636 t1n.isBaseOf(t2n, &offset) && offset == 0) 10637 { 10638 /* Allow copy of distinct qualifier elements. 10639 * eg. 10640 * char[] dst; const(char)[] src; 10641 * dst[] = src; 10642 * 10643 * class C {} class D : C {} 10644 * C[2] ca; D[] da; 10645 * ca[] = da; 10646 */ 10647 if (isArrayOpValid(e2x)) 10648 { 10649 // Don't add CastExp to keep AST for array operations 10650 e2x = e2x.copy(); 10651 e2x.type = exp.e1.type.constOf(); 10652 } 10653 else 10654 e2x = e2x.castTo(sc, exp.e1.type.constOf()); 10655 } 10656 else 10657 { 10658 /* https://issues.dlang.org/show_bug.cgi?id=15778 10659 * A string literal has an array type of immutable 10660 * elements by default, and normally it cannot be convertible to 10661 * array type of mutable elements. But for element-wise assignment, 10662 * elements need to be const at best. So we should give a chance 10663 * to change code unit size for polysemous string literal. 10664 */ 10665 if (e2x.op == EXP.string_) 10666 e2x = e2x.implicitCastTo(sc, exp.e1.type.constOf()); 10667 else 10668 e2x = e2x.implicitCastTo(sc, exp.e1.type); 10669 } 10670 if (t1n.toBasetype.ty == Tvoid && t2n.toBasetype.ty == Tvoid) 10671 { 10672 if (sc.setUnsafe(false, exp.loc, "cannot copy `void[]` to `void[]` in `@safe` code")) 10673 return setError(); 10674 } 10675 } 10676 else 10677 { 10678 if (exp.op == EXP.blit) 10679 e2x = e2x.castTo(sc, exp.e1.type); 10680 else 10681 { 10682 e2x = e2x.implicitCastTo(sc, exp.e1.type); 10683 10684 // Fix Issue 13435: https://issues.dlang.org/show_bug.cgi?id=13435 10685 10686 // If the implicit cast has failed and the assign expression is 10687 // the initialization of a struct member field 10688 if (e2x.op == EXP.error && exp.op == EXP.construct && t1.ty == Tstruct) 10689 { 10690 scope sd = (cast(TypeStruct)t1).sym; 10691 Dsymbol opAssign = search_function(sd, Id.assign); 10692 10693 // and the struct defines an opAssign 10694 if (opAssign) 10695 { 10696 // offer more information about the cause of the problem 10697 errorSupplemental(exp.loc, 10698 "`%s` is the first assignment of `%s` therefore it represents its initialization", 10699 exp.toChars(), exp.e1.toChars()); 10700 errorSupplemental(exp.loc, 10701 "`opAssign` methods are not used for initialization, but for subsequent assignments"); 10702 } 10703 } 10704 } 10705 } 10706 if (e2x.op == EXP.error) 10707 { 10708 result = e2x; 10709 return; 10710 } 10711 exp.e2 = e2x; 10712 t2 = exp.e2.type.toBasetype(); 10713 10714 /* Look for array operations 10715 */ 10716 if ((t2.ty == Tarray || t2.ty == Tsarray) && isArrayOpValid(exp.e2)) 10717 { 10718 // Look for valid array operations 10719 if (exp.memset != MemorySet.blockAssign && 10720 exp.e1.op == EXP.slice && 10721 (isUnaArrayOp(exp.e2.op) || isBinArrayOp(exp.e2.op))) 10722 { 10723 exp.type = exp.e1.type; 10724 if (exp.op == EXP.construct) // https://issues.dlang.org/show_bug.cgi?id=10282 10725 // tweak mutability of e1 element 10726 exp.e1.type = exp.e1.type.nextOf().mutableOf().arrayOf(); 10727 result = arrayOp(exp, sc); 10728 return; 10729 } 10730 10731 // Drop invalid array operations in e2 10732 // d = a[] + b[], d = (a[] + b[])[0..2], etc 10733 if (checkNonAssignmentArrayOp(exp.e2, exp.memset != MemorySet.blockAssign && exp.op == EXP.assign)) 10734 return setError(); 10735 10736 // Remains valid array assignments 10737 // d = d[], d = [1,2,3], etc 10738 } 10739 10740 /* Don't allow assignment to classes that were allocated on the stack with: 10741 * scope Class c = new Class(); 10742 */ 10743 if (exp.e1.op == EXP.variable && exp.op == EXP.assign) 10744 { 10745 VarExp ve = cast(VarExp)exp.e1; 10746 VarDeclaration vd = ve.var.isVarDeclaration(); 10747 if (vd && vd.onstack) 10748 { 10749 assert(t1.ty == Tclass); 10750 error(exp.loc, "cannot rebind scope variables"); 10751 } 10752 } 10753 10754 if (exp.e1.op == EXP.variable && (cast(VarExp)exp.e1).var.ident == Id.ctfe) 10755 { 10756 error(exp.loc, "cannot modify compiler-generated variable `__ctfe`"); 10757 } 10758 10759 exp.type = exp.e1.type; 10760 assert(exp.type); 10761 auto assignElem = exp.e2; 10762 auto res = exp.op == EXP.assign ? exp.reorderSettingAAElem(sc) : exp; 10763 /* https://issues.dlang.org/show_bug.cgi?id=22366 10764 * 10765 * `reorderSettingAAElem` creates a tree of comma expressions, however, 10766 * `checkAssignExp` expects only AssignExps. 10767 */ 10768 if (res == exp) // no `AA[k] = v` rewrite was performed 10769 checkAssignEscape(sc, res, false, false); 10770 else 10771 checkNewEscape(sc, assignElem, false); // assigning to AA puts it on heap 10772 10773 if (auto ae = res.isConstructExp()) 10774 { 10775 Type t1b = ae.e1.type.toBasetype(); 10776 if (t1b.ty != Tsarray && t1b.ty != Tarray) 10777 return setResult(res); 10778 10779 // only non-trivial array constructions may need to be lowered (non-POD elements basically) 10780 Type t1e = t1b.nextOf(); 10781 TypeStruct ts = t1e.baseElemOf().isTypeStruct(); 10782 if (!ts || (!ts.sym.postblit && !ts.sym.hasCopyCtor && !ts.sym.dtor)) 10783 return setResult(res); 10784 10785 // don't lower ref-constructions etc. 10786 if (!(t1b.ty == Tsarray || ae.e1.isSliceExp) || 10787 (ae.e1.isVarExp && ae.e1.isVarExp.var.isVarDeclaration.isReference)) 10788 return setResult(res); 10789 10790 // Construction from an equivalent other array? 10791 // Only lower with lvalue RHS elements; let the glue layer move rvalue elements. 10792 Type t2b = ae.e2.type.toBasetype(); 10793 // skip over a (possibly implicit) cast of a static array RHS to a slice 10794 Expression rhs = ae.e2; 10795 Type rhsType = t2b; 10796 if (t2b.ty == Tarray) 10797 { 10798 if (auto ce = rhs.isCastExp()) 10799 { 10800 auto ct = ce.e1.type.toBasetype(); 10801 if (ct.ty == Tsarray) 10802 { 10803 rhs = ce.e1; 10804 rhsType = ct; 10805 } 10806 } 10807 } 10808 10809 if (!sc.needsCodegen()) // interpreter can handle these 10810 return setResult(res); 10811 10812 const lowerToArrayCtor = 10813 ( (rhsType.ty == Tarray && !rhs.isArrayLiteralExp) || 10814 (rhsType.ty == Tsarray && rhs.isLvalue) ) && 10815 t1e.equivalent(t2b.nextOf); 10816 10817 // Construction from a single element? 10818 // If the RHS is an rvalue, then we'll need to make a temporary for it (copied multiple times). 10819 const lowerToArraySetCtor = !lowerToArrayCtor && t1e.equivalent(t2b); 10820 10821 if (lowerToArrayCtor || lowerToArraySetCtor) 10822 { 10823 auto func = lowerToArrayCtor ? Id._d_arrayctor : Id._d_arraysetctor; 10824 const other = lowerToArrayCtor ? "other array" : "value"; 10825 if (!verifyHookExist(exp.loc, *sc, func, "construct array with " ~ other, Id.object)) 10826 return setError(); 10827 10828 // Lower to object._d_array{,set}ctor(e1, e2) 10829 Expression id = new IdentifierExp(exp.loc, Id.empty); 10830 id = new DotIdExp(exp.loc, id, Id.object); 10831 id = new DotIdExp(exp.loc, id, func); 10832 10833 auto arguments = new Expressions(); 10834 arguments.push(new CastExp(ae.loc, ae.e1, t1e.arrayOf).expressionSemantic(sc)); 10835 if (lowerToArrayCtor) 10836 { 10837 arguments.push(new CastExp(ae.loc, rhs, t2b.nextOf.arrayOf).expressionSemantic(sc)); 10838 Expression ce = new CallExp(exp.loc, id, arguments); 10839 res = ce.expressionSemantic(sc); 10840 } 10841 else 10842 { 10843 Expression e0; 10844 // promote an rvalue RHS element to a temporary, it's passed by ref to _d_arraysetctor 10845 if (!ae.e2.isLvalue) 10846 { 10847 auto vd = copyToTemp(STC.scope_, "__setctor", ae.e2); 10848 e0 = new DeclarationExp(vd.loc, vd).expressionSemantic(sc); 10849 arguments.push(new VarExp(vd.loc, vd).expressionSemantic(sc)); 10850 } 10851 else 10852 arguments.push(ae.e2); 10853 10854 Expression ce = new CallExp(exp.loc, id, arguments); 10855 res = Expression.combine(e0, ce).expressionSemantic(sc); 10856 } 10857 10858 if (global.params.v.verbose) 10859 message("lowered %s =>\n %s", exp.toChars(), res.toChars()); 10860 } 10861 } 10862 else if (auto ae = res.isAssignExp()) 10863 res = lowerArrayAssign(ae); 10864 else if (auto ce = res.isCommaExp()) 10865 { 10866 if (auto ae1 = ce.e1.isAssignExp()) 10867 ce.e1 = lowerArrayAssign(ae1, true); 10868 if (auto ae2 = ce.e2.isAssignExp()) 10869 ce.e2 = lowerArrayAssign(ae2, true); 10870 } 10871 10872 return setResult(res); 10873 } 10874 10875 /*************************************** 10876 * Lower AssignExp to `_d_array{setassign,assign_l,assign_r}` if needed. 10877 * 10878 * Params: 10879 * ae = the AssignExp to be lowered 10880 * fromCommaExp = indicates whether `ae` is part of a CommaExp or not, 10881 * so no unnecessary temporay variable is created. 10882 * Returns: 10883 * a CommaExp contiaining call a to `_d_array{setassign,assign_l,assign_r}` 10884 * if needed or `ae` otherwise 10885 */ 10886 private Expression lowerArrayAssign(AssignExp ae, bool fromCommaExp = false) 10887 { 10888 Type t1b = ae.e1.type.toBasetype(); 10889 if (t1b.ty != Tsarray && t1b.ty != Tarray) 10890 return ae; 10891 10892 const isArrayAssign = (ae.e1.isSliceExp() || ae.e1.type.ty == Tsarray) && 10893 (ae.e2.type.ty == Tsarray || ae.e2.type.ty == Tarray) && 10894 (ae.e1.type.nextOf() && ae.e2.type.nextOf() && ae.e1.type.nextOf.mutableOf.equals(ae.e2.type.nextOf.mutableOf())); 10895 10896 const isArraySetAssign = (ae.e1.isSliceExp() || ae.e1.type.ty == Tsarray) && 10897 (ae.e1.type.nextOf() && ae.e2.type.implicitConvTo(ae.e1.type.nextOf())); 10898 10899 if (!isArrayAssign && !isArraySetAssign) 10900 return ae; 10901 10902 const ts = t1b.nextOf().baseElemOf().isTypeStruct(); 10903 if (!ts || (!ts.sym.postblit && !ts.sym.dtor)) 10904 return ae; 10905 10906 Expression res; 10907 Identifier func = isArraySetAssign ? Id._d_arraysetassign : 10908 ae.e2.isLvalue() || ae.e2.isSliceExp() ? Id._d_arrayassign_l : Id._d_arrayassign_r; 10909 10910 // Lower to `.object._d_array{setassign,assign_l,assign_r}(e1, e2)`` 10911 Expression id = new IdentifierExp(ae.loc, Id.empty); 10912 id = new DotIdExp(ae.loc, id, Id.object); 10913 id = new DotIdExp(ae.loc, id, func); 10914 10915 auto arguments = new Expressions(); 10916 arguments.push(new CastExp(ae.loc, ae.e1, ae.e1.type.nextOf.arrayOf) 10917 .expressionSemantic(sc)); 10918 10919 Expression eValue2, value2 = ae.e2; 10920 if (isArrayAssign && value2.isLvalue()) 10921 value2 = new CastExp(ae.loc, ae.e2, ae.e2.type.nextOf.arrayOf()) 10922 .expressionSemantic(sc); 10923 else if (!fromCommaExp && 10924 (isArrayAssign || (isArraySetAssign && !value2.isLvalue()))) 10925 { 10926 // Rvalues from CommaExps were introduced in `visit(AssignExp)` 10927 // and are temporary variables themselves. Rvalues from trivial 10928 // SliceExps are simply passed by reference without any copying. 10929 10930 // `__assigntmp` will be destroyed together with the array `ae.e1`. 10931 // When `ae.e2` is a variadic arg array, it is also `scope`, so 10932 // `__assigntmp` may also be scope. 10933 StorageClass stc = STC.nodtor; 10934 if (isArrayAssign) 10935 stc |= STC.rvalue | STC.scope_; 10936 10937 auto vd = copyToTemp(stc, "__assigntmp", ae.e2); 10938 eValue2 = new DeclarationExp(vd.loc, vd).expressionSemantic(sc); 10939 value2 = new VarExp(vd.loc, vd).expressionSemantic(sc); 10940 } 10941 arguments.push(value2); 10942 10943 Expression ce = new CallExp(ae.loc, id, arguments); 10944 res = Expression.combine(eValue2, ce).expressionSemantic(sc); 10945 if (isArrayAssign) 10946 res = Expression.combine(res, ae.e1).expressionSemantic(sc); 10947 10948 if (global.params.v.verbose) 10949 message("lowered %s =>\n %s", ae.toChars(), res.toChars()); 10950 10951 res = new LoweredAssignExp(ae, res); 10952 res.type = ae.type; 10953 10954 return res; 10955 } 10956 10957 override void visit(PowAssignExp exp) 10958 { 10959 if (exp.type) 10960 { 10961 result = exp; 10962 return; 10963 } 10964 10965 Expression e = exp.op_overload(sc); 10966 if (e) 10967 { 10968 result = e; 10969 return; 10970 } 10971 10972 if (exp.e1.checkReadModifyWrite(exp.op, exp.e2)) 10973 return setError(); 10974 10975 assert(exp.e1.type && exp.e2.type); 10976 if (exp.e1.op == EXP.slice || exp.e1.type.ty == Tarray || exp.e1.type.ty == Tsarray) 10977 { 10978 if (checkNonAssignmentArrayOp(exp.e1)) 10979 return setError(); 10980 10981 // T[] ^^= ... 10982 if (exp.e2.implicitConvTo(exp.e1.type.nextOf())) 10983 { 10984 // T[] ^^= T 10985 exp.e2 = exp.e2.castTo(sc, exp.e1.type.nextOf()); 10986 } 10987 else if (Expression ex = typeCombine(exp, sc)) 10988 { 10989 result = ex; 10990 return; 10991 } 10992 10993 // Check element types are arithmetic 10994 Type tb1 = exp.e1.type.nextOf().toBasetype(); 10995 Type tb2 = exp.e2.type.toBasetype(); 10996 if (tb2.ty == Tarray || tb2.ty == Tsarray) 10997 tb2 = tb2.nextOf().toBasetype(); 10998 if ((tb1.isintegral() || tb1.isfloating()) && (tb2.isintegral() || tb2.isfloating())) 10999 { 11000 exp.type = exp.e1.type; 11001 result = arrayOp(exp, sc); 11002 return; 11003 } 11004 } 11005 else 11006 { 11007 exp.e1 = exp.e1.modifiableLvalue(sc, exp.e1); 11008 } 11009 11010 if ((exp.e1.type.isintegral() || exp.e1.type.isfloating()) && (exp.e2.type.isintegral() || exp.e2.type.isfloating())) 11011 { 11012 Expression e0 = null; 11013 e = exp.reorderSettingAAElem(sc); 11014 e = Expression.extractLast(e, e0); 11015 assert(e == exp); 11016 11017 if (exp.e1.op == EXP.variable) 11018 { 11019 // Rewrite: e1 = e1 ^^ e2 11020 e = new PowExp(exp.loc, exp.e1.syntaxCopy(), exp.e2); 11021 e = new AssignExp(exp.loc, exp.e1, e); 11022 } 11023 else 11024 { 11025 // Rewrite: ref tmp = e1; tmp = tmp ^^ e2 11026 auto v = copyToTemp(STC.ref_, "__powtmp", exp.e1); 11027 auto de = new DeclarationExp(exp.e1.loc, v); 11028 auto ve = new VarExp(exp.e1.loc, v); 11029 e = new PowExp(exp.loc, ve, exp.e2); 11030 e = new AssignExp(exp.loc, new VarExp(exp.e1.loc, v), e); 11031 e = new CommaExp(exp.loc, de, e); 11032 } 11033 e = Expression.combine(e0, e); 11034 e = e.expressionSemantic(sc); 11035 result = e; 11036 return; 11037 } 11038 result = exp.incompatibleTypes(); 11039 } 11040 11041 override void visit(CatAssignExp exp) 11042 { 11043 if (exp.type) 11044 { 11045 result = exp; 11046 return; 11047 } 11048 11049 //printf("CatAssignExp::semantic() %s\n", exp.toChars()); 11050 Expression e = exp.op_overload(sc); 11051 if (e) 11052 { 11053 result = e; 11054 return; 11055 } 11056 11057 if (SliceExp se = exp.e1.isSliceExp()) 11058 { 11059 if (se.e1.type.toBasetype().ty == Tsarray) 11060 { 11061 error(exp.loc, "cannot append to static array `%s`", se.e1.type.toChars()); 11062 return setError(); 11063 } 11064 } 11065 11066 exp.e1 = exp.e1.modifiableLvalue(sc, exp.e1); 11067 if (exp.e1.op == EXP.error) 11068 { 11069 result = exp.e1; 11070 return; 11071 } 11072 if (exp.e2.op == EXP.error) 11073 { 11074 result = exp.e2; 11075 return; 11076 } 11077 11078 if (checkNonAssignmentArrayOp(exp.e2)) 11079 return setError(); 11080 11081 Type tb1 = exp.e1.type.toBasetype(); 11082 Type tb1next = tb1.nextOf(); 11083 Type tb2 = exp.e2.type.toBasetype(); 11084 11085 /* Possibilities: 11086 * EXP.concatenateAssign: appending T[] to T[] 11087 * EXP.concatenateElemAssign: appending T to T[] 11088 * EXP.concatenateDcharAssign: appending dchar to T[] 11089 */ 11090 if ((tb1.ty == Tarray) && 11091 (tb2.ty == Tarray || tb2.ty == Tsarray) && 11092 (exp.e2.implicitConvTo(exp.e1.type) || 11093 (tb2.nextOf().implicitConvTo(tb1next) && 11094 (tb2.nextOf().size(Loc.initial) == tb1next.size(Loc.initial))))) 11095 { 11096 // EXP.concatenateAssign 11097 assert(exp.op == EXP.concatenateAssign); 11098 if (exp.e1.checkPostblit(sc, tb1next)) 11099 return setError(); 11100 11101 exp.e2 = exp.e2.castTo(sc, exp.e1.type); 11102 } 11103 else if ((tb1.ty == Tarray) && exp.e2.implicitConvTo(tb1next)) 11104 { 11105 /* https://issues.dlang.org/show_bug.cgi?id=19782 11106 * 11107 * If e2 is implicitly convertible to tb1next, the conversion 11108 * might be done through alias this, in which case, e2 needs to 11109 * be modified accordingly (e2 => e2.aliasthis). 11110 */ 11111 if (tb2.ty == Tstruct && (cast(TypeStruct)tb2).implicitConvToThroughAliasThis(tb1next)) 11112 goto Laliasthis; 11113 if (tb2.ty == Tclass && (cast(TypeClass)tb2).implicitConvToThroughAliasThis(tb1next)) 11114 goto Laliasthis; 11115 // Append element 11116 if (exp.e2.checkPostblit(sc, tb2)) 11117 return setError(); 11118 11119 if (checkNewEscape(sc, exp.e2, false)) 11120 return setError(); 11121 11122 exp = new CatElemAssignExp(exp.loc, exp.type, exp.e1, exp.e2.castTo(sc, tb1next)); 11123 exp.e2 = doCopyOrMove(sc, exp.e2); 11124 } 11125 else if (tb1.ty == Tarray && 11126 (tb1next.ty == Tchar || tb1next.ty == Twchar) && 11127 exp.e2.type.ty != tb1next.ty && 11128 exp.e2.implicitConvTo(Type.tdchar)) 11129 { 11130 // Append dchar to char[] or wchar[] 11131 exp = new CatDcharAssignExp(exp.loc, exp.type, exp.e1, exp.e2.castTo(sc, Type.tdchar)); 11132 11133 /* Do not allow appending wchar to char[] because if wchar happens 11134 * to be a surrogate pair, nothing good can result. 11135 */ 11136 } 11137 else 11138 { 11139 // Try alias this on first operand 11140 static Expression tryAliasThisForLhs(BinAssignExp exp, Scope* sc) 11141 { 11142 AggregateDeclaration ad1 = isAggregate(exp.e1.type); 11143 if (!ad1 || !ad1.aliasthis) 11144 return null; 11145 11146 /* Rewrite (e1 op e2) as: 11147 * (e1.aliasthis op e2) 11148 */ 11149 if (isRecursiveAliasThis(exp.att1, exp.e1.type)) 11150 return null; 11151 //printf("att %s e1 = %s\n", Token.toChars(e.op), e.e1.type.toChars()); 11152 Expression e1 = new DotIdExp(exp.loc, exp.e1, ad1.aliasthis.ident); 11153 BinExp be = cast(BinExp)exp.copy(); 11154 be.e1 = e1; 11155 return be.trySemantic(sc); 11156 } 11157 11158 // Try alias this on second operand 11159 static Expression tryAliasThisForRhs(BinAssignExp exp, Scope* sc) 11160 { 11161 AggregateDeclaration ad2 = isAggregate(exp.e2.type); 11162 if (!ad2 || !ad2.aliasthis) 11163 return null; 11164 /* Rewrite (e1 op e2) as: 11165 * (e1 op e2.aliasthis) 11166 */ 11167 if (isRecursiveAliasThis(exp.att2, exp.e2.type)) 11168 return null; 11169 //printf("att %s e2 = %s\n", Token.toChars(e.op), e.e2.type.toChars()); 11170 Expression e2 = new DotIdExp(exp.loc, exp.e2, ad2.aliasthis.ident); 11171 BinExp be = cast(BinExp)exp.copy(); 11172 be.e2 = e2; 11173 return be.trySemantic(sc); 11174 } 11175 11176 Laliasthis: 11177 result = tryAliasThisForLhs(exp, sc); 11178 if (result) 11179 return; 11180 11181 result = tryAliasThisForRhs(exp, sc); 11182 if (result) 11183 return; 11184 11185 error(exp.loc, "cannot append type `%s` to type `%s`", tb2.toChars(), tb1.toChars()); 11186 return setError(); 11187 } 11188 11189 if (exp.e2.checkValue() || exp.e2.checkSharedAccess(sc)) 11190 return setError(); 11191 11192 exp.type = exp.e1.type; 11193 auto assignElem = exp.e2; 11194 auto res = exp.reorderSettingAAElem(sc); 11195 if (res != exp) // `AA[k] = v` rewrite was performed 11196 checkNewEscape(sc, assignElem, false); 11197 else if (exp.op == EXP.concatenateElemAssign || exp.op == EXP.concatenateDcharAssign) 11198 checkAssignEscape(sc, res, false, false); 11199 11200 result = res; 11201 11202 if ((exp.op == EXP.concatenateAssign || exp.op == EXP.concatenateElemAssign) && 11203 sc.needsCodegen()) 11204 { 11205 // if aa ordering is triggered, `res` will be a CommaExp 11206 // and `.e2` will be the rewritten original expression. 11207 11208 // `output` will point to the expression that the lowering will overwrite 11209 Expression* output; 11210 if (auto comma = res.isCommaExp()) 11211 { 11212 output = &comma.e2; 11213 // manual cast because it could be either CatAssignExp or CatElemAssignExp 11214 exp = cast(CatAssignExp)comma.e2; 11215 } 11216 else 11217 { 11218 output = &result; 11219 exp = cast(CatAssignExp)result; 11220 } 11221 11222 if (exp.op == EXP.concatenateAssign) 11223 { 11224 Identifier hook = global.params.tracegc ? Id._d_arrayappendTTrace : Id._d_arrayappendT; 11225 11226 if (!verifyHookExist(exp.loc, *sc, hook, "appending array to arrays", Id.object)) 11227 return setError(); 11228 11229 // Lower to object._d_arrayappendT{,Trace}({file, line, funcname}, e1, e2) 11230 Expression id = new IdentifierExp(exp.loc, Id.empty); 11231 id = new DotIdExp(exp.loc, id, Id.object); 11232 id = new DotIdExp(exp.loc, id, hook); 11233 11234 auto arguments = new Expressions(); 11235 arguments.reserve(5); 11236 if (global.params.tracegc) 11237 { 11238 auto funcname = (sc.callsc && sc.callsc.func) ? sc.callsc.func.toPrettyChars() : sc.func.toPrettyChars(); 11239 arguments.push(new StringExp(exp.loc, exp.loc.filename.toDString())); 11240 arguments.push(new IntegerExp(exp.loc, exp.loc.linnum, Type.tint32)); 11241 arguments.push(new StringExp(exp.loc, funcname.toDString())); 11242 } 11243 11244 arguments.push(exp.e1); 11245 arguments.push(exp.e2); 11246 Expression ce = new CallExp(exp.loc, id, arguments); 11247 *output = ce.expressionSemantic(sc); 11248 } 11249 else if (exp.op == EXP.concatenateElemAssign) 11250 { 11251 /* Do not lower concats to the indices array returned by 11252 *`static foreach`, as this array is only used at compile-time. 11253 */ 11254 if (auto ve = exp.e1.isVarExp) 11255 { 11256 import core.stdc.ctype : isdigit; 11257 // The name of the indices array that static foreach loops uses. 11258 // See dmd.cond.lowerNonArrayAggregate 11259 enum varName = "__res"; 11260 const(char)[] id = ve.var.ident.toString; 11261 if (ve.var.storage_class & STC.temp && id.length > varName.length && 11262 id[0 .. varName.length] == varName && id[varName.length].isdigit) 11263 return; 11264 } 11265 11266 Identifier hook = global.params.tracegc ? Id._d_arrayappendcTXTrace : Id._d_arrayappendcTX; 11267 if (!verifyHookExist(exp.loc, *sc, Id._d_arrayappendcTXImpl, "appending element to arrays", Id.object)) 11268 return setError(); 11269 11270 // Lower to object._d_arrayappendcTXImpl!(typeof(e1))._d_arrayappendcTX{,Trace}(e1, 1), e1[$-1]=e2 11271 Expression id = new IdentifierExp(exp.loc, Id.empty); 11272 id = new DotIdExp(exp.loc, id, Id.object); 11273 auto tiargs = new Objects(); 11274 tiargs.push(exp.e1.type); 11275 id = new DotTemplateInstanceExp(exp.loc, id, Id._d_arrayappendcTXImpl, tiargs); 11276 id = new DotIdExp(exp.loc, id, hook); 11277 11278 auto arguments = new Expressions(); 11279 arguments.reserve(5); 11280 if (global.params.tracegc) 11281 { 11282 auto funcname = (sc.callsc && sc.callsc.func) ? sc.callsc.func.toPrettyChars() : sc.func.toPrettyChars(); 11283 arguments.push(new StringExp(exp.loc, exp.loc.filename.toDString())); 11284 arguments.push(new IntegerExp(exp.loc, exp.loc.linnum, Type.tint32)); 11285 arguments.push(new StringExp(exp.loc, funcname.toDString())); 11286 } 11287 11288 Expression eValue1; 11289 Expression value1 = extractSideEffect(sc, "__appendtmp", eValue1, exp.e1); 11290 11291 arguments.push(value1); 11292 arguments.push(new IntegerExp(exp.loc, 1, Type.tsize_t)); 11293 11294 Expression ce = new CallExp(exp.loc, id, arguments); 11295 11296 Expression eValue2; 11297 Expression value2 = exp.e2; 11298 if (!value2.isVarExp() && !value2.isConst()) 11299 { 11300 /* Before the template hook, this check was performed in e2ir.d 11301 * for expressions like `a ~= a[$-1]`. Here, $ will be modified 11302 * by calling `_d_arrayappendcT`, so we need to save `a[$-1]` in 11303 * a temporary variable. 11304 */ 11305 value2 = extractSideEffect(sc, "__appendtmp", eValue2, value2, true); 11306 exp.e2 = value2; 11307 11308 // `__appendtmp*` will be destroyed together with the array `exp.e1`. 11309 auto vd = eValue2.isDeclarationExp().declaration.isVarDeclaration(); 11310 vd.storage_class |= STC.nodtor; 11311 // Be more explicit that this "declaration" is local to the expression 11312 vd.storage_class |= STC.exptemp; 11313 } 11314 11315 auto ale = new ArrayLengthExp(exp.loc, value1); 11316 auto elem = new IndexExp(exp.loc, value1, new MinExp(exp.loc, ale, IntegerExp.literal!1)); 11317 auto ae = new ConstructExp(exp.loc, elem, value2); 11318 11319 auto e0 = Expression.combine(ce, ae).expressionSemantic(sc); 11320 e0 = Expression.combine(e0, value1); 11321 e0 = Expression.combine(eValue1, e0); 11322 11323 e0 = Expression.combine(eValue2, e0); 11324 11325 *output = e0.expressionSemantic(sc); 11326 } 11327 } 11328 11329 } 11330 11331 override void visit(AddExp exp) 11332 { 11333 static if (LOGSEMANTIC) 11334 { 11335 printf("AddExp::semantic('%s')\n", exp.toChars()); 11336 } 11337 if (exp.type) 11338 { 11339 result = exp; 11340 return; 11341 } 11342 11343 if (Expression ex = binSemanticProp(exp, sc)) 11344 { 11345 result = ex; 11346 return; 11347 } 11348 Expression e = exp.op_overload(sc); 11349 if (e) 11350 { 11351 result = e; 11352 return; 11353 } 11354 11355 /* ImportC: convert arrays to pointers, functions to pointers to functions 11356 */ 11357 exp.e1 = exp.e1.arrayFuncConv(sc); 11358 exp.e2 = exp.e2.arrayFuncConv(sc); 11359 11360 Type tb1 = exp.e1.type.toBasetype(); 11361 Type tb2 = exp.e2.type.toBasetype(); 11362 11363 bool err = false; 11364 if (tb1.ty == Tdelegate || tb1.isPtrToFunction()) 11365 { 11366 err |= exp.e1.checkArithmetic(exp.op) || exp.e1.checkSharedAccess(sc); 11367 } 11368 if (tb2.ty == Tdelegate || tb2.isPtrToFunction()) 11369 { 11370 err |= exp.e2.checkArithmetic(exp.op) || exp.e2.checkSharedAccess(sc); 11371 } 11372 if (err) 11373 return setError(); 11374 11375 if (tb1.ty == Tpointer && exp.e2.type.isintegral() || tb2.ty == Tpointer && exp.e1.type.isintegral()) 11376 { 11377 result = scaleFactor(exp, sc); 11378 return; 11379 } 11380 11381 if (tb1.ty == Tpointer && tb2.ty == Tpointer) 11382 { 11383 result = exp.incompatibleTypes(); 11384 return; 11385 } 11386 11387 if (Expression ex = typeCombine(exp, sc)) 11388 { 11389 result = ex; 11390 return; 11391 } 11392 11393 Type tb = exp.type.toBasetype(); 11394 if (tb.ty == Tarray || tb.ty == Tsarray) 11395 { 11396 if (!isArrayOpValid(exp)) 11397 { 11398 result = arrayOpInvalidError(exp); 11399 return; 11400 } 11401 result = exp; 11402 return; 11403 } 11404 11405 tb1 = exp.e1.type.toBasetype(); 11406 if (!target.isVectorOpSupported(tb1, exp.op, tb2)) 11407 { 11408 result = exp.incompatibleTypes(); 11409 return; 11410 } 11411 if ((tb1.isreal() && exp.e2.type.isimaginary()) || (tb1.isimaginary() && exp.e2.type.isreal())) 11412 { 11413 switch (exp.type.toBasetype().ty) 11414 { 11415 case Tfloat32: 11416 case Timaginary32: 11417 exp.type = Type.tcomplex32; 11418 break; 11419 11420 case Tfloat64: 11421 case Timaginary64: 11422 exp.type = Type.tcomplex64; 11423 break; 11424 11425 case Tfloat80: 11426 case Timaginary80: 11427 exp.type = Type.tcomplex80; 11428 break; 11429 11430 default: 11431 assert(0); 11432 } 11433 } 11434 result = exp; 11435 } 11436 11437 override void visit(MinExp exp) 11438 { 11439 static if (LOGSEMANTIC) 11440 { 11441 printf("MinExp::semantic('%s')\n", exp.toChars()); 11442 } 11443 if (exp.type) 11444 { 11445 result = exp; 11446 return; 11447 } 11448 11449 if (Expression ex = binSemanticProp(exp, sc)) 11450 { 11451 result = ex; 11452 return; 11453 } 11454 Expression e = exp.op_overload(sc); 11455 if (e) 11456 { 11457 result = e; 11458 return; 11459 } 11460 11461 /* ImportC: convert arrays to pointers, functions to pointers to functions 11462 */ 11463 exp.e1 = exp.e1.arrayFuncConv(sc); 11464 exp.e2 = exp.e2.arrayFuncConv(sc); 11465 11466 Type t1 = exp.e1.type.toBasetype(); 11467 Type t2 = exp.e2.type.toBasetype(); 11468 11469 bool err = false; 11470 if (t1.ty == Tdelegate || t1.isPtrToFunction()) 11471 { 11472 err |= exp.e1.checkArithmetic(exp.op) || exp.e1.checkSharedAccess(sc); 11473 } 11474 if (t2.ty == Tdelegate || t2.isPtrToFunction()) 11475 { 11476 err |= exp.e2.checkArithmetic(exp.op) || exp.e2.checkSharedAccess(sc); 11477 } 11478 if (err) 11479 return setError(); 11480 11481 if (t1.ty == Tpointer) 11482 { 11483 if (t2.ty == Tpointer) 11484 { 11485 // https://dlang.org/spec/expression.html#add_expressions 11486 // "If both operands are pointers, and the operator is -, the pointers are 11487 // subtracted and the result is divided by the size of the type pointed to 11488 // by the operands. It is an error if the pointers point to different types." 11489 Type p1 = t1.nextOf(); 11490 Type p2 = t2.nextOf(); 11491 11492 if (!p1.equivalent(p2)) 11493 { 11494 // Deprecation to remain for at least a year, after which this should be 11495 // changed to an error 11496 // See https://github.com/dlang/dmd/pull/7332 11497 deprecation(exp.loc, 11498 "cannot subtract pointers to different types: `%s` and `%s`.", 11499 t1.toChars(), t2.toChars()); 11500 } 11501 11502 // Need to divide the result by the stride 11503 // Replace (ptr - ptr) with (ptr - ptr) / stride 11504 long stride; 11505 11506 // make sure pointer types are compatible 11507 if (Expression ex = typeCombine(exp, sc)) 11508 { 11509 result = ex; 11510 return; 11511 } 11512 11513 exp.type = Type.tptrdiff_t; 11514 stride = t2.nextOf().size(); 11515 if (stride == 0) 11516 { 11517 e = new IntegerExp(exp.loc, 0, Type.tptrdiff_t); 11518 } 11519 else if (stride == cast(long)SIZE_INVALID) 11520 e = ErrorExp.get(); 11521 else 11522 { 11523 e = new DivExp(exp.loc, exp, new IntegerExp(Loc.initial, stride, Type.tptrdiff_t)); 11524 e.type = Type.tptrdiff_t; 11525 } 11526 } 11527 else if (t2.isintegral()) 11528 e = scaleFactor(exp, sc); 11529 else 11530 { 11531 error(exp.loc, "can't subtract `%s` from pointer", t2.toChars()); 11532 e = ErrorExp.get(); 11533 } 11534 result = e; 11535 return; 11536 } 11537 if (t2.ty == Tpointer) 11538 { 11539 exp.type = exp.e2.type; 11540 error(exp.loc, "can't subtract pointer from `%s`", exp.e1.type.toChars()); 11541 return setError(); 11542 } 11543 11544 if (Expression ex = typeCombine(exp, sc)) 11545 { 11546 result = ex; 11547 return; 11548 } 11549 11550 Type tb = exp.type.toBasetype(); 11551 if (tb.ty == Tarray || tb.ty == Tsarray) 11552 { 11553 if (!isArrayOpValid(exp)) 11554 { 11555 result = arrayOpInvalidError(exp); 11556 return; 11557 } 11558 result = exp; 11559 return; 11560 } 11561 11562 t1 = exp.e1.type.toBasetype(); 11563 t2 = exp.e2.type.toBasetype(); 11564 if (!target.isVectorOpSupported(t1, exp.op, t2)) 11565 { 11566 result = exp.incompatibleTypes(); 11567 return; 11568 } 11569 if ((t1.isreal() && t2.isimaginary()) || (t1.isimaginary() && t2.isreal())) 11570 { 11571 switch (exp.type.ty) 11572 { 11573 case Tfloat32: 11574 case Timaginary32: 11575 exp.type = Type.tcomplex32; 11576 break; 11577 11578 case Tfloat64: 11579 case Timaginary64: 11580 exp.type = Type.tcomplex64; 11581 break; 11582 11583 case Tfloat80: 11584 case Timaginary80: 11585 exp.type = Type.tcomplex80; 11586 break; 11587 11588 default: 11589 assert(0); 11590 } 11591 } 11592 result = exp; 11593 return; 11594 } 11595 11596 /** 11597 * If the given expression is a `CatExp`, the function tries to lower it to 11598 * `_d_arraycatnTX`. 11599 * 11600 * Params: 11601 * ee = the `CatExp` to lower 11602 * Returns: 11603 * `_d_arraycatnTX(e1, e2, ..., en)` if `ee` is `e1 ~ e2 ~ ... en` 11604 * `ee` otherwise 11605 */ 11606 private Expression lowerToArrayCat(CatExp exp) 11607 { 11608 // String literals are concatenated by the compiler. No lowering is needed. 11609 if ((exp.e1.isStringExp() && (exp.e2.isIntegerExp() || exp.e2.isStringExp())) || 11610 (exp.e2.isStringExp() && (exp.e1.isIntegerExp() || exp.e1.isStringExp()))) 11611 return exp; 11612 11613 bool useTraceGCHook = global.params.tracegc && sc.needsCodegen(); 11614 11615 Identifier hook = useTraceGCHook ? Id._d_arraycatnTXTrace : Id._d_arraycatnTX; 11616 if (!verifyHookExist(exp.loc, *sc, hook, "concatenating arrays")) 11617 { 11618 setError(); 11619 return result; 11620 } 11621 11622 void handleCatArgument(Expressions *arguments, Expression e) 11623 { 11624 if (auto ce = e.isCatExp()) 11625 { 11626 Expression lowering = ce.lowering; 11627 11628 /* Skip `file`, `line`, and `funcname` if the hook of the parent 11629 * `CatExp` is `_d_arraycatnTXTrace`. 11630 */ 11631 if (auto callExp = isRuntimeHook(lowering, hook)) 11632 { 11633 if (hook == Id._d_arraycatnTX) 11634 arguments.pushSlice((*callExp.arguments)[]); 11635 else 11636 arguments.pushSlice((*callExp.arguments)[3 .. $]); 11637 } 11638 } 11639 else 11640 arguments.push(e); 11641 } 11642 11643 auto arguments = new Expressions(); 11644 if (useTraceGCHook) 11645 { 11646 auto funcname = (sc.callsc && sc.callsc.func) ? 11647 sc.callsc.func.toPrettyChars() : sc.func.toPrettyChars(); 11648 arguments.push(new StringExp(exp.loc, exp.loc.filename.toDString())); 11649 arguments.push(new IntegerExp(exp.loc, exp.loc.linnum, Type.tint32)); 11650 arguments.push(new StringExp(exp.loc, funcname.toDString())); 11651 } 11652 11653 handleCatArgument(arguments, exp.e1); 11654 handleCatArgument(arguments, exp.e2); 11655 11656 Expression id = new IdentifierExp(exp.loc, Id.empty); 11657 id = new DotIdExp(exp.loc, id, Id.object); 11658 11659 auto tiargs = new Objects(); 11660 tiargs.push(exp.type); 11661 id = new DotTemplateInstanceExp(exp.loc, id, hook, tiargs); 11662 id = new CallExp(exp.loc, id, arguments); 11663 return id.expressionSemantic(sc); 11664 } 11665 11666 void trySetCatExpLowering(Expression exp) 11667 { 11668 /* `_d_arraycatnTX` canot be used with `-betterC`, but `CatExp`s may be 11669 * used with `-betterC`, but only during CTFE. 11670 */ 11671 if (!global.params.useGC) 11672 return; 11673 11674 if (auto ce = exp.isCatExp()) 11675 ce.lowering = lowerToArrayCat(ce); 11676 } 11677 11678 override void visit(CatExp exp) 11679 { 11680 // https://dlang.org/spec/expression.html#cat_expressions 11681 //printf("CatExp.semantic() %s\n", toChars()); 11682 if (exp.type) 11683 { 11684 result = exp; 11685 return; 11686 } 11687 11688 if (Expression ex = binSemanticProp(exp, sc)) 11689 { 11690 result = ex; 11691 return; 11692 } 11693 Expression e = exp.op_overload(sc); 11694 if (e) 11695 { 11696 result = e; 11697 return; 11698 } 11699 11700 Type tb1 = exp.e1.type.toBasetype(); 11701 Type tb2 = exp.e2.type.toBasetype(); 11702 11703 auto f1 = checkNonAssignmentArrayOp(exp.e1); 11704 auto f2 = checkNonAssignmentArrayOp(exp.e2); 11705 if (f1 || f2) 11706 return setError(); 11707 11708 Type tb1next = tb1.nextOf(); 11709 Type tb2next = tb2.nextOf(); 11710 11711 // Check for: array ~ array 11712 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))) 11713 { 11714 /* https://issues.dlang.org/show_bug.cgi?id=9248 11715 * Here to avoid the case of: 11716 * void*[] a = [cast(void*)1]; 11717 * void*[] b = [cast(void*)2]; 11718 * a ~ b; 11719 * becoming: 11720 * a ~ [cast(void*)b]; 11721 */ 11722 11723 /* https://issues.dlang.org/show_bug.cgi?id=14682 11724 * Also to avoid the case of: 11725 * int[][] a; 11726 * a ~ []; 11727 * becoming: 11728 * a ~ cast(int[])[]; 11729 */ 11730 goto Lpeer; 11731 } 11732 11733 // Check for: array ~ element 11734 if ((tb1.ty == Tsarray || tb1.ty == Tarray) && tb2.ty != Tvoid) 11735 { 11736 if (exp.e1.op == EXP.arrayLiteral) 11737 { 11738 exp.e2 = doCopyOrMove(sc, exp.e2); 11739 // https://issues.dlang.org/show_bug.cgi?id=14686 11740 // Postblit call appears in AST, and this is 11741 // finally translated to an ArrayLiteralExp in below optimize(). 11742 } 11743 else if (exp.e1.op == EXP.string_) 11744 { 11745 // No postblit call exists on character (integer) value. 11746 } 11747 else 11748 { 11749 if (exp.e2.checkPostblit(sc, tb2)) 11750 return setError(); 11751 // Postblit call will be done in runtime helper function 11752 } 11753 11754 if (exp.e1.op == EXP.arrayLiteral && exp.e1.implicitConvTo(tb2.arrayOf())) 11755 { 11756 exp.e1 = exp.e1.implicitCastTo(sc, tb2.arrayOf()); 11757 exp.type = tb2.arrayOf(); 11758 goto L2elem; 11759 } 11760 if (exp.e2.implicitConvTo(tb1next) >= MATCH.convert) 11761 { 11762 exp.e2 = exp.e2.implicitCastTo(sc, tb1next); 11763 exp.type = tb1next.arrayOf(); 11764 L2elem: 11765 if (checkNewEscape(sc, exp.e2, false)) 11766 return setError(); 11767 result = exp.optimize(WANTvalue); 11768 trySetCatExpLowering(result); 11769 return; 11770 } 11771 } 11772 // Check for: element ~ array 11773 if ((tb2.ty == Tsarray || tb2.ty == Tarray) && tb1.ty != Tvoid) 11774 { 11775 if (exp.e2.op == EXP.arrayLiteral) 11776 { 11777 exp.e1 = doCopyOrMove(sc, exp.e1); 11778 } 11779 else if (exp.e2.op == EXP.string_) 11780 { 11781 } 11782 else 11783 { 11784 if (exp.e1.checkPostblit(sc, tb1)) 11785 return setError(); 11786 } 11787 11788 if (exp.e2.op == EXP.arrayLiteral && exp.e2.implicitConvTo(tb1.arrayOf())) 11789 { 11790 exp.e2 = exp.e2.implicitCastTo(sc, tb1.arrayOf()); 11791 exp.type = tb1.arrayOf(); 11792 goto L1elem; 11793 } 11794 if (exp.e1.implicitConvTo(tb2next) >= MATCH.convert) 11795 { 11796 exp.e1 = exp.e1.implicitCastTo(sc, tb2next); 11797 exp.type = tb2next.arrayOf(); 11798 L1elem: 11799 if (checkNewEscape(sc, exp.e1, false)) 11800 return setError(); 11801 result = exp.optimize(WANTvalue); 11802 trySetCatExpLowering(result); 11803 return; 11804 } 11805 } 11806 11807 Lpeer: 11808 if ((tb1.ty == Tsarray || tb1.ty == Tarray) && (tb2.ty == Tsarray || tb2.ty == Tarray) && (tb1next.mod || tb2next.mod) && (tb1next.mod != tb2next.mod)) 11809 { 11810 Type t1 = tb1next.mutableOf().constOf().arrayOf(); 11811 Type t2 = tb2next.mutableOf().constOf().arrayOf(); 11812 if (exp.e1.op == EXP.string_ && !(cast(StringExp)exp.e1).committed) 11813 exp.e1.type = t1; 11814 else 11815 exp.e1 = exp.e1.castTo(sc, t1); 11816 if (exp.e2.op == EXP.string_ && !(cast(StringExp)exp.e2).committed) 11817 exp.e2.type = t2; 11818 else 11819 exp.e2 = exp.e2.castTo(sc, t2); 11820 } 11821 11822 if (Expression ex = typeCombine(exp, sc)) 11823 { 11824 result = ex; 11825 trySetCatExpLowering(result); 11826 return; 11827 } 11828 exp.type = exp.type.toHeadMutable(); 11829 11830 Type tb = exp.type.toBasetype(); 11831 if (tb.ty == Tsarray) 11832 exp.type = tb.nextOf().arrayOf(); 11833 if (exp.type.ty == Tarray && tb1next && tb2next && tb1next.mod != tb2next.mod) 11834 { 11835 exp.type = exp.type.nextOf().toHeadMutable().arrayOf(); 11836 } 11837 if (Type tbn = tb.nextOf()) 11838 { 11839 if (exp.checkPostblit(sc, tbn)) 11840 return setError(); 11841 } 11842 Type t1 = exp.e1.type.toBasetype(); 11843 Type t2 = exp.e2.type.toBasetype(); 11844 if ((t1.ty == Tarray || t1.ty == Tsarray) && 11845 (t2.ty == Tarray || t2.ty == Tsarray)) 11846 { 11847 // Normalize to ArrayLiteralExp or StringExp as far as possible 11848 e = exp.optimize(WANTvalue); 11849 } 11850 else 11851 { 11852 //printf("(%s) ~ (%s)\n", e1.toChars(), e2.toChars()); 11853 result = exp.incompatibleTypes(); 11854 return; 11855 } 11856 11857 result = e; 11858 trySetCatExpLowering(result); 11859 } 11860 11861 override void visit(MulExp exp) 11862 { 11863 version (none) 11864 { 11865 printf("MulExp::semantic() %s\n", exp.toChars()); 11866 } 11867 if (exp.type) 11868 { 11869 result = exp; 11870 return; 11871 } 11872 11873 if (Expression ex = binSemanticProp(exp, sc)) 11874 { 11875 result = ex; 11876 return; 11877 } 11878 Expression e = exp.op_overload(sc); 11879 if (e) 11880 { 11881 result = e; 11882 return; 11883 } 11884 11885 if (Expression ex = typeCombine(exp, sc)) 11886 { 11887 result = ex; 11888 return; 11889 } 11890 11891 Type tb = exp.type.toBasetype(); 11892 if (tb.ty == Tarray || tb.ty == Tsarray) 11893 { 11894 if (!isArrayOpValid(exp)) 11895 { 11896 result = arrayOpInvalidError(exp); 11897 return; 11898 } 11899 result = exp; 11900 return; 11901 } 11902 11903 if (exp.checkArithmeticBin() || exp.checkSharedAccessBin(sc)) 11904 return setError(); 11905 11906 if (exp.type.isfloating()) 11907 { 11908 Type t1 = exp.e1.type; 11909 Type t2 = exp.e2.type; 11910 11911 if (t1.isreal()) 11912 { 11913 exp.type = t2; 11914 } 11915 else if (t2.isreal()) 11916 { 11917 exp.type = t1; 11918 } 11919 else if (t1.isimaginary()) 11920 { 11921 if (t2.isimaginary()) 11922 { 11923 switch (t1.toBasetype().ty) 11924 { 11925 case Timaginary32: 11926 exp.type = Type.tfloat32; 11927 break; 11928 11929 case Timaginary64: 11930 exp.type = Type.tfloat64; 11931 break; 11932 11933 case Timaginary80: 11934 exp.type = Type.tfloat80; 11935 break; 11936 11937 default: 11938 assert(0); 11939 } 11940 11941 // iy * iv = -yv 11942 exp.e1.type = exp.type; 11943 exp.e2.type = exp.type; 11944 e = new NegExp(exp.loc, exp); 11945 e = e.expressionSemantic(sc); 11946 result = e; 11947 return; 11948 } 11949 else 11950 exp.type = t2; // t2 is complex 11951 } 11952 else if (t2.isimaginary()) 11953 { 11954 exp.type = t1; // t1 is complex 11955 } 11956 } 11957 else if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype())) 11958 { 11959 result = exp.incompatibleTypes(); 11960 return; 11961 } 11962 result = exp; 11963 } 11964 11965 override void visit(DivExp exp) 11966 { 11967 if (exp.type) 11968 { 11969 result = exp; 11970 return; 11971 } 11972 11973 if (Expression ex = binSemanticProp(exp, sc)) 11974 { 11975 result = ex; 11976 return; 11977 } 11978 Expression e = exp.op_overload(sc); 11979 if (e) 11980 { 11981 result = e; 11982 return; 11983 } 11984 11985 if (Expression ex = typeCombine(exp, sc)) 11986 { 11987 result = ex; 11988 return; 11989 } 11990 11991 Type tb = exp.type.toBasetype(); 11992 if (tb.ty == Tarray || tb.ty == Tsarray) 11993 { 11994 if (!isArrayOpValid(exp)) 11995 { 11996 result = arrayOpInvalidError(exp); 11997 return; 11998 } 11999 result = exp; 12000 return; 12001 } 12002 12003 if (exp.checkArithmeticBin() || exp.checkSharedAccessBin(sc)) 12004 return setError(); 12005 12006 if (exp.type.isfloating()) 12007 { 12008 Type t1 = exp.e1.type; 12009 Type t2 = exp.e2.type; 12010 12011 if (t1.isreal()) 12012 { 12013 exp.type = t2; 12014 if (t2.isimaginary()) 12015 { 12016 // x/iv = i(-x/v) 12017 exp.e2.type = t1; 12018 e = new NegExp(exp.loc, exp); 12019 e = e.expressionSemantic(sc); 12020 result = e; 12021 return; 12022 } 12023 } 12024 else if (t2.isreal()) 12025 { 12026 exp.type = t1; 12027 } 12028 else if (t1.isimaginary()) 12029 { 12030 if (t2.isimaginary()) 12031 { 12032 switch (t1.toBasetype().ty) 12033 { 12034 case Timaginary32: 12035 exp.type = Type.tfloat32; 12036 break; 12037 12038 case Timaginary64: 12039 exp.type = Type.tfloat64; 12040 break; 12041 12042 case Timaginary80: 12043 exp.type = Type.tfloat80; 12044 break; 12045 12046 default: 12047 assert(0); 12048 } 12049 } 12050 else 12051 exp.type = t2; // t2 is complex 12052 } 12053 else if (t2.isimaginary()) 12054 { 12055 exp.type = t1; // t1 is complex 12056 } 12057 } 12058 else if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype())) 12059 { 12060 result = exp.incompatibleTypes(); 12061 return; 12062 } 12063 result = exp; 12064 } 12065 12066 override void visit(ModExp exp) 12067 { 12068 if (exp.type) 12069 { 12070 result = exp; 12071 return; 12072 } 12073 12074 if (Expression ex = binSemanticProp(exp, sc)) 12075 { 12076 result = ex; 12077 return; 12078 } 12079 Expression e = exp.op_overload(sc); 12080 if (e) 12081 { 12082 result = e; 12083 return; 12084 } 12085 12086 if (Expression ex = typeCombine(exp, sc)) 12087 { 12088 result = ex; 12089 return; 12090 } 12091 12092 Type tb = exp.type.toBasetype(); 12093 if (tb.ty == Tarray || tb.ty == Tsarray) 12094 { 12095 if (!isArrayOpValid(exp)) 12096 { 12097 result = arrayOpInvalidError(exp); 12098 return; 12099 } 12100 result = exp; 12101 return; 12102 } 12103 if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype())) 12104 { 12105 result = exp.incompatibleTypes(); 12106 return; 12107 } 12108 12109 if (exp.checkArithmeticBin() || exp.checkSharedAccessBin(sc)) 12110 return setError(); 12111 12112 if (exp.type.isfloating()) 12113 { 12114 exp.type = exp.e1.type; 12115 if (exp.e2.type.iscomplex()) 12116 { 12117 error(exp.loc, "cannot perform modulo complex arithmetic"); 12118 return setError(); 12119 } 12120 } 12121 result = exp; 12122 } 12123 12124 override void visit(PowExp exp) 12125 { 12126 if (exp.type) 12127 { 12128 result = exp; 12129 return; 12130 } 12131 12132 //printf("PowExp::semantic() %s\n", toChars()); 12133 if (Expression ex = binSemanticProp(exp, sc)) 12134 { 12135 result = ex; 12136 return; 12137 } 12138 Expression e = exp.op_overload(sc); 12139 if (e) 12140 { 12141 result = e; 12142 return; 12143 } 12144 12145 if (Expression ex = typeCombine(exp, sc)) 12146 { 12147 result = ex; 12148 return; 12149 } 12150 12151 Type tb = exp.type.toBasetype(); 12152 if (tb.ty == Tarray || tb.ty == Tsarray) 12153 { 12154 if (!isArrayOpValid(exp)) 12155 { 12156 result = arrayOpInvalidError(exp); 12157 return; 12158 } 12159 result = exp; 12160 return; 12161 } 12162 12163 if (exp.checkArithmeticBin() || exp.checkSharedAccessBin(sc)) 12164 return setError(); 12165 12166 if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype())) 12167 { 12168 result = exp.incompatibleTypes(); 12169 return; 12170 } 12171 12172 // First, attempt to fold the expression. 12173 e = exp.optimize(WANTvalue); 12174 if (e.op != EXP.pow) 12175 { 12176 e = e.expressionSemantic(sc); 12177 result = e; 12178 return; 12179 } 12180 12181 Module mmath = Module.loadStdMath(); 12182 if (!mmath) 12183 { 12184 error(e.loc, "`%s` requires `std.math` for `^^` operators", e.toChars()); 12185 return setError(); 12186 } 12187 e = new ScopeExp(exp.loc, mmath); 12188 12189 if (exp.e2.op == EXP.float64 && exp.e2.toReal() == CTFloat.half) 12190 { 12191 // Replace e1 ^^ 0.5 with .std.math.sqrt(e1) 12192 e = new CallExp(exp.loc, new DotIdExp(exp.loc, e, Id._sqrt), exp.e1); 12193 } 12194 else 12195 { 12196 // Replace e1 ^^ e2 with .std.math.pow(e1, e2) 12197 e = new CallExp(exp.loc, new DotIdExp(exp.loc, e, Id._pow), exp.e1, exp.e2); 12198 } 12199 e = e.expressionSemantic(sc); 12200 result = e; 12201 return; 12202 } 12203 12204 override void visit(ShlExp exp) 12205 { 12206 //printf("ShlExp::semantic(), type = %p\n", type); 12207 if (exp.type) 12208 { 12209 result = exp; 12210 return; 12211 } 12212 12213 if (Expression ex = binSemanticProp(exp, sc)) 12214 { 12215 result = ex; 12216 return; 12217 } 12218 Expression e = exp.op_overload(sc); 12219 if (e) 12220 { 12221 result = e; 12222 return; 12223 } 12224 12225 if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc)) 12226 return setError(); 12227 12228 if (!target.isVectorOpSupported(exp.e1.type.toBasetype(), exp.op, exp.e2.type.toBasetype())) 12229 { 12230 result = exp.incompatibleTypes(); 12231 return; 12232 } 12233 exp.e1 = integralPromotions(exp.e1, sc); 12234 if (exp.e2.type.toBasetype().ty != Tvector) 12235 exp.e2 = exp.e2.castTo(sc, Type.tshiftcnt); 12236 12237 exp.type = exp.e1.type; 12238 result = exp; 12239 } 12240 12241 override void visit(ShrExp exp) 12242 { 12243 if (exp.type) 12244 { 12245 result = exp; 12246 return; 12247 } 12248 12249 if (Expression ex = binSemanticProp(exp, sc)) 12250 { 12251 result = ex; 12252 return; 12253 } 12254 Expression e = exp.op_overload(sc); 12255 if (e) 12256 { 12257 result = e; 12258 return; 12259 } 12260 12261 if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc)) 12262 return setError(); 12263 12264 if (!target.isVectorOpSupported(exp.e1.type.toBasetype(), exp.op, exp.e2.type.toBasetype())) 12265 { 12266 result = exp.incompatibleTypes(); 12267 return; 12268 } 12269 exp.e1 = integralPromotions(exp.e1, sc); 12270 if (exp.e2.type.toBasetype().ty != Tvector) 12271 exp.e2 = exp.e2.castTo(sc, Type.tshiftcnt); 12272 12273 exp.type = exp.e1.type; 12274 result = exp; 12275 } 12276 12277 override void visit(UshrExp exp) 12278 { 12279 if (exp.type) 12280 { 12281 result = exp; 12282 return; 12283 } 12284 12285 if (Expression ex = binSemanticProp(exp, sc)) 12286 { 12287 result = ex; 12288 return; 12289 } 12290 Expression e = exp.op_overload(sc); 12291 if (e) 12292 { 12293 result = e; 12294 return; 12295 } 12296 12297 if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc)) 12298 return setError(); 12299 12300 if (!target.isVectorOpSupported(exp.e1.type.toBasetype(), exp.op, exp.e2.type.toBasetype())) 12301 { 12302 result = exp.incompatibleTypes(); 12303 return; 12304 } 12305 exp.e1 = integralPromotions(exp.e1, sc); 12306 if (exp.e2.type.toBasetype().ty != Tvector) 12307 exp.e2 = exp.e2.castTo(sc, Type.tshiftcnt); 12308 12309 exp.type = exp.e1.type; 12310 result = exp; 12311 } 12312 12313 override void visit(AndExp exp) 12314 { 12315 if (exp.type) 12316 { 12317 result = exp; 12318 return; 12319 } 12320 12321 if (Expression ex = binSemanticProp(exp, sc)) 12322 { 12323 result = ex; 12324 return; 12325 } 12326 Expression e = exp.op_overload(sc); 12327 if (e) 12328 { 12329 result = e; 12330 return; 12331 } 12332 12333 if (exp.e1.type.toBasetype().ty == Tbool && exp.e2.type.toBasetype().ty == Tbool) 12334 { 12335 exp.type = exp.e1.type; 12336 result = exp; 12337 return; 12338 } 12339 12340 if (Expression ex = typeCombine(exp, sc)) 12341 { 12342 result = ex; 12343 return; 12344 } 12345 12346 Type tb = exp.type.toBasetype(); 12347 if (tb.ty == Tarray || tb.ty == Tsarray) 12348 { 12349 if (!isArrayOpValid(exp)) 12350 { 12351 result = arrayOpInvalidError(exp); 12352 return; 12353 } 12354 result = exp; 12355 return; 12356 } 12357 if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype())) 12358 { 12359 result = exp.incompatibleTypes(); 12360 return; 12361 } 12362 if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc)) 12363 return setError(); 12364 12365 result = exp; 12366 } 12367 12368 override void visit(OrExp exp) 12369 { 12370 if (exp.type) 12371 { 12372 result = exp; 12373 return; 12374 } 12375 12376 if (Expression ex = binSemanticProp(exp, sc)) 12377 { 12378 result = ex; 12379 return; 12380 } 12381 Expression e = exp.op_overload(sc); 12382 if (e) 12383 { 12384 result = e; 12385 return; 12386 } 12387 12388 if (exp.e1.type.toBasetype().ty == Tbool && exp.e2.type.toBasetype().ty == Tbool) 12389 { 12390 exp.type = exp.e1.type; 12391 result = exp; 12392 return; 12393 } 12394 12395 if (Expression ex = typeCombine(exp, sc)) 12396 { 12397 result = ex; 12398 return; 12399 } 12400 12401 Type tb = exp.type.toBasetype(); 12402 if (tb.ty == Tarray || tb.ty == Tsarray) 12403 { 12404 if (!isArrayOpValid(exp)) 12405 { 12406 result = arrayOpInvalidError(exp); 12407 return; 12408 } 12409 result = exp; 12410 return; 12411 } 12412 if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype())) 12413 { 12414 result = exp.incompatibleTypes(); 12415 return; 12416 } 12417 if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc)) 12418 return setError(); 12419 12420 result = exp; 12421 } 12422 12423 override void visit(XorExp exp) 12424 { 12425 if (exp.type) 12426 { 12427 result = exp; 12428 return; 12429 } 12430 12431 if (Expression ex = binSemanticProp(exp, sc)) 12432 { 12433 result = ex; 12434 return; 12435 } 12436 Expression e = exp.op_overload(sc); 12437 if (e) 12438 { 12439 result = e; 12440 return; 12441 } 12442 12443 if (exp.e1.type.toBasetype().ty == Tbool && exp.e2.type.toBasetype().ty == Tbool) 12444 { 12445 exp.type = exp.e1.type; 12446 result = exp; 12447 return; 12448 } 12449 12450 if (Expression ex = typeCombine(exp, sc)) 12451 { 12452 result = ex; 12453 return; 12454 } 12455 12456 Type tb = exp.type.toBasetype(); 12457 if (tb.ty == Tarray || tb.ty == Tsarray) 12458 { 12459 if (!isArrayOpValid(exp)) 12460 { 12461 result = arrayOpInvalidError(exp); 12462 return; 12463 } 12464 result = exp; 12465 return; 12466 } 12467 if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype())) 12468 { 12469 result = exp.incompatibleTypes(); 12470 return; 12471 } 12472 if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc)) 12473 return setError(); 12474 12475 result = exp; 12476 } 12477 12478 override void visit(LogicalExp exp) 12479 { 12480 static if (LOGSEMANTIC) 12481 { 12482 printf("LogicalExp::semantic() %s\n", exp.toChars()); 12483 } 12484 12485 if (exp.type) 12486 { 12487 result = exp; 12488 return; 12489 } 12490 12491 exp.setNoderefOperands(); 12492 12493 Expression e1x = exp.e1.expressionSemantic(sc); 12494 12495 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684 12496 if (e1x.op == EXP.type) 12497 e1x = resolveAliasThis(sc, e1x); 12498 12499 e1x = resolveProperties(sc, e1x); 12500 e1x = e1x.toBoolean(sc); 12501 12502 if (sc.flags & SCOPE.condition) 12503 { 12504 /* If in static if, don't evaluate e2 if we don't have to. 12505 */ 12506 e1x = e1x.optimize(WANTvalue); 12507 if (e1x.toBool().hasValue(exp.op == EXP.orOr)) 12508 { 12509 if (sc.flags & SCOPE.Cfile) 12510 result = new IntegerExp(exp.op == EXP.orOr); 12511 else 12512 result = IntegerExp.createBool(exp.op == EXP.orOr); 12513 return; 12514 } 12515 } 12516 12517 CtorFlow ctorflow = sc.ctorflow.clone(); 12518 Expression e2x = exp.e2.expressionSemantic(sc); 12519 sc.merge(exp.loc, ctorflow); 12520 ctorflow.freeFieldinit(); 12521 12522 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684 12523 if (e2x.op == EXP.type) 12524 e2x = resolveAliasThis(sc, e2x); 12525 12526 e2x = resolveProperties(sc, e2x); 12527 12528 auto f1 = checkNonAssignmentArrayOp(e1x); 12529 auto f2 = checkNonAssignmentArrayOp(e2x); 12530 if (f1 || f2) 12531 return setError(); 12532 12533 // Unless the right operand is 'void', the expression is converted to 'bool'. 12534 if (e2x.type.ty != Tvoid) 12535 e2x = e2x.toBoolean(sc); 12536 12537 if (e2x.op == EXP.type || e2x.op == EXP.scope_) 12538 { 12539 error(exp.loc, "`%s` is not an expression", exp.e2.toChars()); 12540 return setError(); 12541 } 12542 if (e1x.op == EXP.error || e1x.type.ty == Tnoreturn) 12543 { 12544 result = e1x; 12545 return; 12546 } 12547 if (e2x.op == EXP.error) 12548 { 12549 result = e2x; 12550 return; 12551 } 12552 12553 // The result type is 'bool', unless the right operand has type 'void'. 12554 if (e2x.type.ty == Tvoid) 12555 exp.type = Type.tvoid; 12556 else 12557 exp.type = (sc && sc.flags & SCOPE.Cfile) ? Type.tint32 : Type.tbool; 12558 12559 exp.e1 = e1x; 12560 exp.e2 = e2x; 12561 result = exp; 12562 } 12563 12564 12565 override void visit(CmpExp exp) 12566 { 12567 static if (LOGSEMANTIC) 12568 { 12569 printf("CmpExp::semantic('%s')\n", exp.toChars()); 12570 } 12571 if (exp.type) 12572 { 12573 result = exp; 12574 return; 12575 } 12576 12577 exp.setNoderefOperands(); 12578 12579 if (Expression ex = binSemanticProp(exp, sc)) 12580 { 12581 result = ex; 12582 return; 12583 } 12584 Type t1 = exp.e1.type.toBasetype(); 12585 Type t2 = exp.e2.type.toBasetype(); 12586 if (t1.ty == Tclass && exp.e2.op == EXP.null_ || t2.ty == Tclass && exp.e1.op == EXP.null_) 12587 { 12588 error(exp.loc, "do not use `null` when comparing class types"); 12589 return setError(); 12590 } 12591 12592 12593 EXP cmpop = exp.op; 12594 if (auto e = exp.op_overload(sc, &cmpop)) 12595 { 12596 if (!e.type.isscalar() && e.type.equals(exp.e1.type)) 12597 { 12598 error(exp.loc, "recursive `opCmp` expansion"); 12599 return setError(); 12600 } 12601 if (e.op == EXP.call) 12602 { 12603 12604 if (t1.ty == Tclass && t2.ty == Tclass) 12605 { 12606 // Lower to object.__cmp(e1, e2) 12607 Expression cl = new IdentifierExp(exp.loc, Id.empty); 12608 cl = new DotIdExp(exp.loc, cl, Id.object); 12609 cl = new DotIdExp(exp.loc, cl, Id.__cmp); 12610 cl = cl.expressionSemantic(sc); 12611 12612 auto arguments = new Expressions(); 12613 // Check if op_overload found a better match by calling e2.opCmp(e1) 12614 // If the operands were swapped, then the result must be reversed 12615 // e1.opCmp(e2) == -e2.opCmp(e1) 12616 // cmpop takes care of this 12617 if (exp.op == cmpop) 12618 { 12619 arguments.push(exp.e1); 12620 arguments.push(exp.e2); 12621 } 12622 else 12623 { 12624 // Use better match found by op_overload 12625 arguments.push(exp.e2); 12626 arguments.push(exp.e1); 12627 } 12628 12629 cl = new CallExp(exp.loc, cl, arguments); 12630 cl = new CmpExp(cmpop, exp.loc, cl, new IntegerExp(0)); 12631 result = cl.expressionSemantic(sc); 12632 return; 12633 } 12634 12635 e = new CmpExp(cmpop, exp.loc, e, IntegerExp.literal!0); 12636 e = e.expressionSemantic(sc); 12637 } 12638 result = e; 12639 return; 12640 } 12641 12642 12643 if (Expression ex = typeCombine(exp, sc)) 12644 { 12645 result = ex; 12646 return; 12647 } 12648 12649 auto f1 = checkNonAssignmentArrayOp(exp.e1); 12650 auto f2 = checkNonAssignmentArrayOp(exp.e2); 12651 if (f1 || f2) 12652 return setError(); 12653 12654 exp.type = (sc && sc.flags & SCOPE.Cfile) ? Type.tint32 : Type.tbool; 12655 12656 // Special handling for array comparisons 12657 Expression arrayLowering = null; 12658 t1 = exp.e1.type.toBasetype(); 12659 t2 = exp.e2.type.toBasetype(); 12660 if ((t1.ty == Tarray || t1.ty == Tsarray || t1.ty == Tpointer) && (t2.ty == Tarray || t2.ty == Tsarray || t2.ty == Tpointer)) 12661 { 12662 Type t1next = t1.nextOf(); 12663 Type t2next = t2.nextOf(); 12664 if (t1next.implicitConvTo(t2next) < MATCH.constant && t2next.implicitConvTo(t1next) < MATCH.constant && (t1next.ty != Tvoid && t2next.ty != Tvoid)) 12665 { 12666 error(exp.loc, "array comparison type mismatch, `%s` vs `%s`", t1next.toChars(), t2next.toChars()); 12667 return setError(); 12668 } 12669 12670 if ((t1.ty == Tarray || t1.ty == Tsarray) && 12671 (t2.ty == Tarray || t2.ty == Tsarray)) 12672 { 12673 if (!verifyHookExist(exp.loc, *sc, Id.__cmp, "comparing arrays")) 12674 return setError(); 12675 12676 // Lower to object.__cmp(e1, e2) 12677 Expression al = new IdentifierExp(exp.loc, Id.empty); 12678 al = new DotIdExp(exp.loc, al, Id.object); 12679 al = new DotIdExp(exp.loc, al, Id.__cmp); 12680 al = al.expressionSemantic(sc); 12681 12682 auto arguments = new Expressions(2); 12683 (*arguments)[0] = exp.e1; 12684 (*arguments)[1] = exp.e2; 12685 12686 al = new CallExp(exp.loc, al, arguments); 12687 al = new CmpExp(exp.op, exp.loc, al, IntegerExp.literal!0); 12688 12689 arrayLowering = al; 12690 } 12691 } 12692 else if (t1.ty == Tstruct || t2.ty == Tstruct || (t1.ty == Tclass && t2.ty == Tclass)) 12693 { 12694 if (t2.ty == Tstruct) 12695 error(exp.loc, "need member function `opCmp()` for %s `%s` to compare", t2.toDsymbol(sc).kind(), t2.toChars()); 12696 else 12697 error(exp.loc, "need member function `opCmp()` for %s `%s` to compare", t1.toDsymbol(sc).kind(), t1.toChars()); 12698 return setError(); 12699 } 12700 else if (t1.iscomplex() || t2.iscomplex()) 12701 { 12702 error(exp.loc, "compare not defined for complex operands"); 12703 return setError(); 12704 } 12705 else if (t1.ty == Taarray || t2.ty == Taarray) 12706 { 12707 error(exp.loc, "`%s` is not defined for associative arrays", EXPtoString(exp.op).ptr); 12708 return setError(); 12709 } 12710 else if (!target.isVectorOpSupported(t1, exp.op, t2)) 12711 { 12712 result = exp.incompatibleTypes(); 12713 return; 12714 } 12715 else 12716 { 12717 bool r1 = exp.e1.checkValue() || exp.e1.checkSharedAccess(sc); 12718 bool r2 = exp.e2.checkValue() || exp.e2.checkSharedAccess(sc); 12719 if (r1 || r2) 12720 return setError(); 12721 } 12722 12723 //printf("CmpExp: %s, type = %s\n", e.toChars(), e.type.toChars()); 12724 if (arrayLowering) 12725 { 12726 arrayLowering = arrayLowering.expressionSemantic(sc); 12727 result = arrayLowering; 12728 return; 12729 } 12730 12731 if (auto tv = t1.isTypeVector()) 12732 exp.type = tv.toBooleanVector(); 12733 12734 result = exp; 12735 return; 12736 } 12737 12738 override void visit(InExp exp) 12739 { 12740 if (exp.type) 12741 { 12742 result = exp; 12743 return; 12744 } 12745 12746 if (Expression ex = binSemanticProp(exp, sc)) 12747 { 12748 result = ex; 12749 return; 12750 } 12751 Expression e = exp.op_overload(sc); 12752 if (e) 12753 { 12754 result = e; 12755 return; 12756 } 12757 12758 Type t2b = exp.e2.type.toBasetype(); 12759 switch (t2b.ty) 12760 { 12761 case Taarray: 12762 { 12763 TypeAArray ta = cast(TypeAArray)t2b; 12764 12765 // Special handling for array keys 12766 if (!arrayTypeCompatibleWithoutCasting(exp.e1.type, ta.index)) 12767 { 12768 // Convert key to type of key 12769 exp.e1 = exp.e1.implicitCastTo(sc, ta.index); 12770 } 12771 12772 semanticTypeInfo(sc, ta.index); 12773 12774 // Return type is pointer to value 12775 exp.type = ta.nextOf().pointerTo(); 12776 break; 12777 } 12778 12779 case Terror: 12780 return setError(); 12781 12782 case Tarray, Tsarray: 12783 result = exp.incompatibleTypes(); 12784 errorSupplemental(exp.loc, "`in` is only allowed on associative arrays"); 12785 const(char)* slice = (t2b.ty == Tsarray) ? "[]" : ""; 12786 errorSupplemental(exp.loc, "perhaps use `std.algorithm.find(%s, %s%s)` instead", 12787 exp.e1.toChars(), exp.e2.toChars(), slice); 12788 return; 12789 12790 default: 12791 result = exp.incompatibleTypes(); 12792 return; 12793 } 12794 result = exp; 12795 } 12796 12797 override void visit(RemoveExp e) 12798 { 12799 if (Expression ex = binSemantic(e, sc)) 12800 { 12801 result = ex; 12802 return; 12803 } 12804 result = e; 12805 } 12806 12807 override void visit(EqualExp exp) 12808 { 12809 //printf("EqualExp::semantic('%s')\n", exp.toChars()); 12810 if (exp.type) 12811 { 12812 result = exp; 12813 return; 12814 } 12815 12816 exp.setNoderefOperands(); 12817 12818 if (auto e = binSemanticProp(exp, sc)) 12819 { 12820 result = e; 12821 return; 12822 } 12823 if (exp.e1.op == EXP.type || exp.e2.op == EXP.type) 12824 { 12825 /* https://issues.dlang.org/show_bug.cgi?id=12520 12826 * empty tuples are represented as types so special cases are added 12827 * so that they can be compared for equality with tuples of values. 12828 */ 12829 static auto extractTypeTupAndExpTup(Expression e) 12830 { 12831 static struct Result { bool ttEmpty; bool te; } 12832 auto tt = e.op == EXP.type ? e.isTypeExp().type.isTypeTuple() : null; 12833 return Result(tt && (!tt.arguments || !tt.arguments.length), e.isTupleExp() !is null); 12834 } 12835 auto tups1 = extractTypeTupAndExpTup(exp.e1); 12836 auto tups2 = extractTypeTupAndExpTup(exp.e2); 12837 // AliasSeq!() == AliasSeq!(<at least a value>) 12838 if (tups1.ttEmpty && tups2.te) 12839 { 12840 result = IntegerExp.createBool(exp.op != EXP.equal); 12841 return; 12842 } 12843 // AliasSeq!(<at least a value>) == AliasSeq!() 12844 else if (tups1.te && tups2.ttEmpty) 12845 { 12846 result = IntegerExp.createBool(exp.op != EXP.equal); 12847 return; 12848 } 12849 // AliasSeq!() == AliasSeq!() 12850 else if (tups1.ttEmpty && tups2.ttEmpty) 12851 { 12852 result = IntegerExp.createBool(exp.op == EXP.equal); 12853 return; 12854 } 12855 // otherwise, two types are really not comparable 12856 result = exp.incompatibleTypes(); 12857 return; 12858 } 12859 12860 { 12861 auto t1 = exp.e1.type; 12862 auto t2 = exp.e2.type; 12863 if (t1.ty == Tenum && t2.ty == Tenum && !t1.equivalent(t2)) 12864 error(exp.loc, "comparison between different enumeration types `%s` and `%s`; If this behavior is intended consider using `std.conv.asOriginalType`", 12865 t1.toChars(), t2.toChars()); 12866 } 12867 12868 /* Before checking for operator overloading, check to see if we're 12869 * comparing the addresses of two statics. If so, we can just see 12870 * if they are the same symbol. 12871 */ 12872 if (exp.e1.op == EXP.address && exp.e2.op == EXP.address) 12873 { 12874 AddrExp ae1 = cast(AddrExp)exp.e1; 12875 AddrExp ae2 = cast(AddrExp)exp.e2; 12876 if (ae1.e1.op == EXP.variable && ae2.e1.op == EXP.variable) 12877 { 12878 VarExp ve1 = cast(VarExp)ae1.e1; 12879 VarExp ve2 = cast(VarExp)ae2.e1; 12880 if (ve1.var == ve2.var) 12881 { 12882 // They are the same, result is 'true' for ==, 'false' for != 12883 result = IntegerExp.createBool(exp.op == EXP.equal); 12884 return; 12885 } 12886 } 12887 } 12888 12889 Type t1 = exp.e1.type.toBasetype(); 12890 Type t2 = exp.e2.type.toBasetype(); 12891 12892 // Indicates whether the comparison of the 2 specified array types 12893 // requires an object.__equals() lowering. 12894 static bool needsDirectEq(Type t1, Type t2, Scope* sc) 12895 { 12896 Type t1n = t1.nextOf().toBasetype(); 12897 Type t2n = t2.nextOf().toBasetype(); 12898 if ((t1n.ty.isSomeChar && t2n.ty.isSomeChar) || 12899 (t1n.ty == Tvoid || t2n.ty == Tvoid)) 12900 { 12901 return false; 12902 } 12903 if (t1n.constOf() != t2n.constOf()) 12904 return true; 12905 12906 Type t = t1n; 12907 while (t.toBasetype().nextOf()) 12908 t = t.nextOf().toBasetype(); 12909 if (auto ts = t.isTypeStruct()) 12910 { 12911 // semanticTypeInfo() makes sure hasIdentityEquals has been computed 12912 if (global.params.useTypeInfo && Type.dtypeinfo) 12913 semanticTypeInfo(sc, ts); 12914 12915 return ts.sym.hasIdentityEquals; // has custom opEquals 12916 } 12917 12918 return false; 12919 } 12920 12921 if (auto e = exp.op_overload(sc)) 12922 { 12923 result = e; 12924 return; 12925 } 12926 12927 12928 const isArrayComparison = (t1.ty == Tarray || t1.ty == Tsarray) && 12929 (t2.ty == Tarray || t2.ty == Tsarray); 12930 const needsArrayLowering = isArrayComparison && needsDirectEq(t1, t2, sc); 12931 12932 if (!needsArrayLowering) 12933 { 12934 // https://issues.dlang.org/show_bug.cgi?id=23783 12935 if (exp.e1.checkSharedAccess(sc) || exp.e2.checkSharedAccess(sc)) 12936 return setError(); 12937 if (auto e = typeCombine(exp, sc)) 12938 { 12939 result = e; 12940 return; 12941 } 12942 } 12943 12944 auto f1 = checkNonAssignmentArrayOp(exp.e1); 12945 auto f2 = checkNonAssignmentArrayOp(exp.e2); 12946 if (f1 || f2) 12947 return setError(); 12948 12949 exp.type = (sc && sc.flags & SCOPE.Cfile) ? Type.tint32 : Type.tbool; 12950 12951 if (!isArrayComparison) 12952 { 12953 if (exp.e1.type != exp.e2.type && exp.e1.type.isfloating() && exp.e2.type.isfloating()) 12954 { 12955 // Cast both to complex 12956 exp.e1 = exp.e1.castTo(sc, Type.tcomplex80); 12957 exp.e2 = exp.e2.castTo(sc, Type.tcomplex80); 12958 } 12959 } 12960 12961 // lower some array comparisons to object.__equals(e1, e2) 12962 if (needsArrayLowering || (t1.ty == Tarray && t2.ty == Tarray)) 12963 { 12964 //printf("Lowering to __equals %s %s\n", exp.e1.toChars(), exp.e2.toChars()); 12965 12966 // https://issues.dlang.org/show_bug.cgi?id=22390 12967 // Equality comparison between array of noreturns simply lowers to length equality comparison 12968 if (t1.nextOf.isTypeNoreturn() && t2.nextOf.isTypeNoreturn()) 12969 { 12970 Expression exp_l1 = new DotIdExp(exp.e1.loc, exp.e1, Id.length); 12971 Expression exp_l2 = new DotIdExp(exp.e2.loc, exp.e2, Id.length); 12972 auto e = new EqualExp(EXP.equal, exp.loc, exp_l1, exp_l2); 12973 result = e.expressionSemantic(sc); 12974 return; 12975 } 12976 12977 if (!verifyHookExist(exp.loc, *sc, Id.__equals, "equal checks on arrays")) 12978 return setError(); 12979 12980 Expression __equals = new IdentifierExp(exp.loc, Id.empty); 12981 Identifier id = Identifier.idPool("__equals"); 12982 __equals = new DotIdExp(exp.loc, __equals, Id.object); 12983 __equals = new DotIdExp(exp.loc, __equals, id); 12984 12985 /* https://issues.dlang.org/show_bug.cgi?id=23674 12986 * 12987 * Optimize before creating the call expression to the 12988 * druntime hook as the optimizer may output errors 12989 * that will get swallowed otherwise. 12990 */ 12991 exp.e1 = exp.e1.optimize(WANTvalue); 12992 exp.e2 = exp.e2.optimize(WANTvalue); 12993 12994 auto arguments = new Expressions(2); 12995 (*arguments)[0] = exp.e1; 12996 (*arguments)[1] = exp.e2; 12997 12998 __equals = new CallExp(exp.loc, __equals, arguments); 12999 if (exp.op == EXP.notEqual) 13000 { 13001 __equals = new NotExp(exp.loc, __equals); 13002 } 13003 __equals = __equals.trySemantic(sc); // for better error message 13004 if (!__equals) 13005 { 13006 error(exp.loc, "incompatible types for array comparison: `%s` and `%s`", 13007 exp.e1.type.toChars(), exp.e2.type.toChars()); 13008 __equals = ErrorExp.get(); 13009 } 13010 13011 result = __equals; 13012 return; 13013 } 13014 13015 if (exp.e1.type.toBasetype().ty == Taarray) 13016 semanticTypeInfo(sc, exp.e1.type.toBasetype()); 13017 13018 13019 if (!target.isVectorOpSupported(t1, exp.op, t2)) 13020 { 13021 result = exp.incompatibleTypes(); 13022 return; 13023 } 13024 13025 if (auto tv = t1.isTypeVector()) 13026 exp.type = tv.toBooleanVector(); 13027 13028 result = exp; 13029 } 13030 13031 override void visit(IdentityExp exp) 13032 { 13033 if (exp.type) 13034 { 13035 result = exp; 13036 return; 13037 } 13038 13039 exp.setNoderefOperands(); 13040 13041 if (auto e = binSemanticProp(exp, sc)) 13042 { 13043 result = e; 13044 return; 13045 } 13046 13047 if (auto e = typeCombine(exp, sc)) 13048 { 13049 result = e; 13050 return; 13051 } 13052 13053 auto f1 = checkNonAssignmentArrayOp(exp.e1); 13054 auto f2 = checkNonAssignmentArrayOp(exp.e2); 13055 if (f1 || f2) 13056 return setError(); 13057 13058 if (exp.e1.op == EXP.type || exp.e2.op == EXP.type) 13059 { 13060 result = exp.incompatibleTypes(); 13061 return; 13062 } 13063 13064 exp.type = Type.tbool; 13065 13066 if (exp.e1.type != exp.e2.type && exp.e1.type.isfloating() && exp.e2.type.isfloating()) 13067 { 13068 // Cast both to complex 13069 exp.e1 = exp.e1.castTo(sc, Type.tcomplex80); 13070 exp.e2 = exp.e2.castTo(sc, Type.tcomplex80); 13071 } 13072 13073 auto tb1 = exp.e1.type.toBasetype(); 13074 auto tb2 = exp.e2.type.toBasetype(); 13075 if (!target.isVectorOpSupported(tb1, exp.op, tb2)) 13076 { 13077 result = exp.incompatibleTypes(); 13078 return; 13079 } 13080 13081 if (exp.e1.op == EXP.call) 13082 exp.e1 = (cast(CallExp)exp.e1).addDtorHook(sc); 13083 if (exp.e2.op == EXP.call) 13084 exp.e2 = (cast(CallExp)exp.e2).addDtorHook(sc); 13085 13086 if (exp.e1.type.toBasetype().ty == Tsarray || 13087 exp.e2.type.toBasetype().ty == Tsarray) 13088 deprecation(exp.loc, "identity comparison of static arrays " 13089 ~ "implicitly coerces them to slices, " 13090 ~ "which are compared by reference"); 13091 13092 result = exp; 13093 } 13094 13095 override void visit(CondExp exp) 13096 { 13097 static if (LOGSEMANTIC) 13098 { 13099 printf("CondExp::semantic('%s')\n", exp.toChars()); 13100 } 13101 if (exp.type) 13102 { 13103 result = exp; 13104 return; 13105 } 13106 13107 if (auto die = exp.econd.isDotIdExp()) 13108 die.noderef = true; 13109 13110 Expression ec = exp.econd.expressionSemantic(sc); 13111 ec = resolveProperties(sc, ec); 13112 ec = ec.toBoolean(sc); 13113 13114 CtorFlow ctorflow_root = sc.ctorflow.clone(); 13115 Expression e1x = exp.e1.expressionSemantic(sc).arrayFuncConv(sc); 13116 e1x = resolveProperties(sc, e1x); 13117 13118 CtorFlow ctorflow1 = sc.ctorflow; 13119 sc.ctorflow = ctorflow_root; 13120 Expression e2x = exp.e2.expressionSemantic(sc).arrayFuncConv(sc); 13121 e2x = resolveProperties(sc, e2x); 13122 13123 sc.merge(exp.loc, ctorflow1); 13124 ctorflow1.freeFieldinit(); 13125 13126 if (ec.op == EXP.error) 13127 { 13128 result = ec; 13129 return; 13130 } 13131 if (ec.type == Type.terror) 13132 return setError(); 13133 exp.econd = ec; 13134 13135 if (e1x.op == EXP.error) 13136 { 13137 result = e1x; 13138 return; 13139 } 13140 if (e1x.type == Type.terror) 13141 return setError(); 13142 exp.e1 = e1x; 13143 13144 if (e2x.op == EXP.error) 13145 { 13146 result = e2x; 13147 return; 13148 } 13149 if (e2x.type == Type.terror) 13150 return setError(); 13151 exp.e2 = e2x; 13152 13153 auto f0 = checkNonAssignmentArrayOp(exp.econd); 13154 auto f1 = checkNonAssignmentArrayOp(exp.e1); 13155 auto f2 = checkNonAssignmentArrayOp(exp.e2); 13156 if (f0 || f1 || f2) 13157 return setError(); 13158 13159 Type t1 = exp.e1.type; 13160 Type t2 = exp.e2.type; 13161 13162 // https://issues.dlang.org/show_bug.cgi?id=23767 13163 // `cast(void*) 0` should be treated as `null` so the ternary expression 13164 // gets the pointer type of the other branch 13165 if (sc.flags & SCOPE.Cfile) 13166 { 13167 static void rewriteCNull(ref Expression e, ref Type t) 13168 { 13169 if (!t.isTypePointer()) 13170 return; 13171 if (auto ie = e.optimize(WANTvalue).isIntegerExp()) 13172 { 13173 if (ie.getInteger() == 0) 13174 { 13175 e = new NullExp(e.loc, Type.tnull); 13176 t = Type.tnull; 13177 } 13178 } 13179 } 13180 rewriteCNull(exp.e1, t1); 13181 rewriteCNull(exp.e2, t2); 13182 } 13183 13184 if (t1.ty == Tnoreturn) 13185 { 13186 exp.type = t2; 13187 exp.e1 = specialNoreturnCast(exp.e1, exp.type); 13188 } 13189 else if (t2.ty == Tnoreturn) 13190 { 13191 exp.type = t1; 13192 exp.e2 = specialNoreturnCast(exp.e2, exp.type); 13193 } 13194 // If either operand is void the result is void, we have to cast both 13195 // the expression to void so that we explicitly discard the expression 13196 // value if any 13197 // https://issues.dlang.org/show_bug.cgi?id=16598 13198 else if (t1.ty == Tvoid || t2.ty == Tvoid) 13199 { 13200 exp.type = Type.tvoid; 13201 exp.e1 = exp.e1.castTo(sc, exp.type); 13202 exp.e2 = exp.e2.castTo(sc, exp.type); 13203 } 13204 else if (t1 == t2) 13205 exp.type = t1; 13206 else 13207 { 13208 if (Expression ex = typeCombine(exp, sc)) 13209 { 13210 result = ex; 13211 return; 13212 } 13213 13214 switch (exp.e1.type.toBasetype().ty) 13215 { 13216 case Tcomplex32: 13217 case Tcomplex64: 13218 case Tcomplex80: 13219 exp.e2 = exp.e2.castTo(sc, exp.e1.type); 13220 break; 13221 default: 13222 break; 13223 } 13224 switch (exp.e2.type.toBasetype().ty) 13225 { 13226 case Tcomplex32: 13227 case Tcomplex64: 13228 case Tcomplex80: 13229 exp.e1 = exp.e1.castTo(sc, exp.e2.type); 13230 break; 13231 default: 13232 break; 13233 } 13234 if (exp.type.toBasetype().ty == Tarray) 13235 { 13236 exp.e1 = exp.e1.castTo(sc, exp.type); 13237 exp.e2 = exp.e2.castTo(sc, exp.type); 13238 } 13239 } 13240 exp.type = exp.type.merge2(); 13241 version (none) 13242 { 13243 printf("res: %s\n", exp.type.toChars()); 13244 printf("e1 : %s\n", exp.e1.type.toChars()); 13245 printf("e2 : %s\n", exp.e2.type.toChars()); 13246 } 13247 13248 /* https://issues.dlang.org/show_bug.cgi?id=14696 13249 * If either e1 or e2 contain temporaries which need dtor, 13250 * make them conditional. 13251 * Rewrite: 13252 * cond ? (__tmp1 = ..., __tmp1) : (__tmp2 = ..., __tmp2) 13253 * to: 13254 * (auto __cond = cond) ? (... __tmp1) : (... __tmp2) 13255 * and replace edtors of __tmp1 and __tmp2 with: 13256 * __tmp1.edtor --> __cond && __tmp1.dtor() 13257 * __tmp2.edtor --> __cond || __tmp2.dtor() 13258 */ 13259 exp.hookDtors(sc); 13260 13261 result = exp; 13262 } 13263 13264 override void visit(GenericExp exp) 13265 { 13266 static if (LOGSEMANTIC) 13267 { 13268 printf("GenericExp::semantic('%s')\n", exp.toChars()); 13269 } 13270 // C11 6.5.1.1 Generic Selection 13271 13272 auto ec = exp.cntlExp.expressionSemantic(sc).arrayFuncConv(sc); 13273 bool errors = ec.isErrorExp() !is null; 13274 auto tc = ec.type; 13275 13276 auto types = (*exp.types)[]; 13277 foreach (i, ref t; types) 13278 { 13279 if (!t) 13280 continue; // `default:` case 13281 t = t.typeSemantic(ec.loc, sc); 13282 if (t.isTypeError()) 13283 { 13284 errors = true; 13285 continue; 13286 } 13287 13288 /* C11 6.5.1-2 duplicate check 13289 */ 13290 /* C11 distinguishes int, long, and long long. But D doesn't, so depending on the 13291 * C target, a long may have the same type as `int` in the D type system. 13292 * So, skip checks when this may be the case. Later pick the first match 13293 */ 13294 if ( 13295 (t.ty == Tint32 || t.ty == Tuns32) && target.c.longsize == 4 || 13296 (t.ty == Tint64 || t.ty == Tuns64) && target.c.longsize == 8 || 13297 (t.ty == Tfloat64 || t.ty == Timaginary64 || t.ty == Tcomplex64) && target.c.long_doublesize == 8 13298 ) 13299 continue; 13300 13301 foreach (t2; types[0 .. i]) 13302 { 13303 if (t2 && t2.equals(t)) 13304 { 13305 error(ec.loc, "generic association type `%s` can only appear once", t.toChars()); 13306 errors = true; 13307 break; 13308 } 13309 } 13310 } 13311 13312 auto exps = (*exp.exps)[]; 13313 foreach (ref e; exps) 13314 { 13315 e = e.expressionSemantic(sc); 13316 if (e.isErrorExp()) 13317 errors = true; 13318 } 13319 13320 if (errors) 13321 return setError(); 13322 13323 enum size_t None = ~0; 13324 size_t imatch = None; 13325 size_t idefault = None; 13326 foreach (const i, t; types) 13327 { 13328 if (t) 13329 { 13330 /* if tc is compatible with t, it's a match 13331 * C11 6.2.7 defines a compatible type as being the same type, including qualifiers 13332 */ 13333 if (tc.equals(t)) 13334 { 13335 assert(imatch == None); 13336 imatch = i; 13337 break; // pick first match 13338 } 13339 } 13340 else 13341 idefault = i; // multiple defaults are not allowed, and are caught by cparse 13342 } 13343 13344 if (imatch == None) 13345 imatch = idefault; 13346 if (imatch == None) 13347 { 13348 error(exp.loc, "no compatible generic association type for controlling expression type `%s`", tc.toChars()); 13349 return setError(); 13350 } 13351 13352 result = exps[imatch]; 13353 } 13354 13355 override void visit(FileInitExp e) 13356 { 13357 //printf("FileInitExp::semantic()\n"); 13358 e.type = Type.tstring; 13359 result = e; 13360 } 13361 13362 override void visit(LineInitExp e) 13363 { 13364 e.type = Type.tint32; 13365 result = e; 13366 } 13367 13368 override void visit(ModuleInitExp e) 13369 { 13370 //printf("ModuleInitExp::semantic()\n"); 13371 e.type = Type.tstring; 13372 result = e; 13373 } 13374 13375 override void visit(FuncInitExp e) 13376 { 13377 //printf("FuncInitExp::semantic()\n"); 13378 e.type = Type.tstring; 13379 if (sc.func) 13380 { 13381 result = e.resolveLoc(Loc.initial, sc); 13382 return; 13383 } 13384 result = e; 13385 } 13386 13387 override void visit(PrettyFuncInitExp e) 13388 { 13389 //printf("PrettyFuncInitExp::semantic()\n"); 13390 e.type = Type.tstring; 13391 if (sc.func) 13392 { 13393 result = e.resolveLoc(Loc.initial, sc); 13394 return; 13395 } 13396 13397 result = e; 13398 } 13399 } 13400 13401 /********************************** 13402 * Try to run semantic routines. 13403 * If they fail, return NULL. 13404 */ 13405 Expression trySemantic(Expression exp, Scope* sc) 13406 { 13407 //printf("+trySemantic(%s)\n", exp.toChars()); 13408 uint errors = global.startGagging(); 13409 Expression e = expressionSemantic(exp, sc); 13410 if (global.endGagging(errors)) 13411 { 13412 e = null; 13413 } 13414 //printf("-trySemantic(%s)\n", exp.toChars()); 13415 return e; 13416 } 13417 13418 /************************** 13419 * Helper function for easy error propagation. 13420 * If error occurs, returns ErrorExp. Otherwise returns NULL. 13421 */ 13422 Expression unaSemantic(UnaExp e, Scope* sc) 13423 { 13424 static if (LOGSEMANTIC) 13425 { 13426 printf("UnaExp::semantic('%s')\n", e.toChars()); 13427 } 13428 Expression e1x = e.e1.expressionSemantic(sc); 13429 if (e1x.op == EXP.error) 13430 return e1x; 13431 e.e1 = e1x; 13432 return null; 13433 } 13434 13435 /************************** 13436 * Helper function for easy error propagation. 13437 * If error occurs, returns ErrorExp. Otherwise returns NULL. 13438 */ 13439 Expression binSemantic(BinExp e, Scope* sc) 13440 { 13441 static if (LOGSEMANTIC) 13442 { 13443 printf("BinExp::semantic('%s')\n", e.toChars()); 13444 } 13445 Expression e1x = e.e1.expressionSemantic(sc); 13446 Expression e2x = e.e2.expressionSemantic(sc); 13447 13448 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684 13449 if (e1x.op == EXP.type) 13450 e1x = resolveAliasThis(sc, e1x); 13451 if (e2x.op == EXP.type) 13452 e2x = resolveAliasThis(sc, e2x); 13453 13454 if (e1x.op == EXP.error) 13455 return e1x; 13456 if (e2x.op == EXP.error) 13457 return e2x; 13458 e.e1 = e1x; 13459 e.e2 = e2x; 13460 return null; 13461 } 13462 13463 Expression binSemanticProp(BinExp e, Scope* sc) 13464 { 13465 if (Expression ex = binSemantic(e, sc)) 13466 return ex; 13467 Expression e1x = resolveProperties(sc, e.e1); 13468 Expression e2x = resolveProperties(sc, e.e2); 13469 if (e1x.op == EXP.error) 13470 return e1x; 13471 if (e2x.op == EXP.error) 13472 return e2x; 13473 e.e1 = e1x; 13474 e.e2 = e2x; 13475 return null; 13476 } 13477 13478 // entrypoint for semantic ExpressionSemanticVisitor 13479 extern (C++) Expression expressionSemantic(Expression e, Scope* sc) 13480 { 13481 scope v = new ExpressionSemanticVisitor(sc); 13482 e.accept(v); 13483 return v.result; 13484 } 13485 13486 private Expression dotIdSemanticPropX(DotIdExp exp, Scope* sc) 13487 { 13488 //printf("DotIdExp::semanticX(this = %p, '%s')\n", this, toChars()); 13489 if (Expression ex = unaSemantic(exp, sc)) 13490 return ex; 13491 13492 if (!(sc.flags & SCOPE.Cfile) && exp.ident == Id._mangleof) 13493 { 13494 // symbol.mangleof 13495 13496 // return mangleof as an Expression 13497 static Expression dotMangleof(const ref Loc loc, Scope* sc, Dsymbol ds) 13498 { 13499 assert(ds); 13500 if (auto f = ds.isFuncDeclaration()) 13501 { 13502 if (f.checkForwardRef(loc)) 13503 return ErrorExp.get(); 13504 13505 if (f.purityInprocess || f.safetyInprocess || f.nothrowInprocess || f.nogcInprocess) 13506 { 13507 error(loc, "%s `%s` cannot retrieve its `.mangleof` while inferring attributes", f.kind, f.toPrettyChars); 13508 return ErrorExp.get(); 13509 } 13510 } 13511 OutBuffer buf; 13512 mangleToBuffer(ds, buf); 13513 Expression e = new StringExp(loc, buf.extractSlice()); 13514 return e.expressionSemantic(sc); 13515 } 13516 13517 Dsymbol ds; 13518 switch (exp.e1.op) 13519 { 13520 case EXP.scope_: return dotMangleof(exp.loc, sc, exp.e1.isScopeExp().sds); 13521 case EXP.variable: return dotMangleof(exp.loc, sc, exp.e1.isVarExp().var); 13522 case EXP.dotVariable: return dotMangleof(exp.loc, sc, exp.e1.isDotVarExp().var); 13523 case EXP.overloadSet: return dotMangleof(exp.loc, sc, exp.e1.isOverExp().vars); 13524 case EXP.template_: 13525 { 13526 TemplateExp te = exp.e1.isTemplateExp(); 13527 return dotMangleof(exp.loc, sc, ds = te.fd ? te.fd.isDsymbol() : te.td); 13528 } 13529 13530 default: 13531 break; 13532 } 13533 } 13534 13535 if (exp.e1.isVarExp() && exp.e1.type.toBasetype().isTypeSArray() && exp.ident == Id.length) 13536 { 13537 // bypass checkPurity 13538 return exp.e1.type.dotExp(sc, exp.e1, exp.ident, cast(DotExpFlag) (exp.noderef * DotExpFlag.noDeref)); 13539 } 13540 13541 if (!exp.e1.isDotExp()) 13542 { 13543 exp.e1 = resolvePropertiesX(sc, exp.e1); 13544 } 13545 13546 if (auto te = exp.e1.isTupleExp()) 13547 { 13548 if (exp.ident == Id.offsetof) 13549 { 13550 /* 'distribute' the .offsetof to each of the tuple elements. 13551 */ 13552 auto exps = new Expressions(te.exps.length); 13553 foreach (i, e; (*te.exps)[]) 13554 { 13555 (*exps)[i] = new DotIdExp(e.loc, e, Id.offsetof); 13556 } 13557 // Don't evaluate te.e0 in runtime 13558 Expression e = new TupleExp(exp.loc, null, exps); 13559 e = e.expressionSemantic(sc); 13560 return e; 13561 } 13562 if (exp.ident == Id.length) 13563 { 13564 // Don't evaluate te.e0 in runtime 13565 return new IntegerExp(exp.loc, te.exps.length, Type.tsize_t); 13566 } 13567 } 13568 13569 // https://issues.dlang.org/show_bug.cgi?id=14416 13570 // Template has no built-in properties except for 'stringof'. 13571 if ((exp.e1.isDotTemplateExp() || exp.e1.isTemplateExp()) && exp.ident != Id.stringof) 13572 { 13573 error(exp.loc, "template `%s` does not have property `%s`", exp.e1.toChars(), exp.ident.toChars()); 13574 return ErrorExp.get(); 13575 } 13576 if (!exp.e1.type) 13577 { 13578 error(exp.loc, "expression `%s` does not have property `%s`", exp.e1.toChars(), exp.ident.toChars()); 13579 return ErrorExp.get(); 13580 } 13581 13582 return exp; 13583 } 13584 13585 /****************************** 13586 * Resolve properties, i.e. `e1.ident`, without seeing UFCS. 13587 * Params: 13588 * exp = expression to resolve 13589 * sc = context 13590 * gag = do not emit error messages, just return `null` 13591 * Returns: 13592 * resolved expression, null if error 13593 */ 13594 Expression dotIdSemanticProp(DotIdExp exp, Scope* sc, bool gag) 13595 { 13596 //printf("DotIdExp::semanticY(this = %p, '%s')\n", exp, exp.toChars()); 13597 13598 //{ static int z; fflush(stdout); if (++z == 10) *(char*)0=0; } 13599 13600 const cfile = (sc.flags & SCOPE.Cfile) != 0; 13601 13602 /* Special case: rewrite this.id and super.id 13603 * to be classtype.id and baseclasstype.id 13604 * if we have no this pointer. 13605 */ 13606 if ((exp.e1.isThisExp() || exp.e1.isSuperExp()) && !hasThis(sc)) 13607 { 13608 if (AggregateDeclaration ad = sc.getStructClassScope()) 13609 { 13610 if (exp.e1.isThisExp()) 13611 { 13612 exp.e1 = new TypeExp(exp.e1.loc, ad.type); 13613 } 13614 else 13615 { 13616 if (auto cd = ad.isClassDeclaration()) 13617 { 13618 if (cd.baseClass) 13619 exp.e1 = new TypeExp(exp.e1.loc, cd.baseClass.type); 13620 } 13621 } 13622 } 13623 } 13624 13625 { 13626 Expression e = dotIdSemanticPropX(exp, sc); 13627 if (e != exp) 13628 return e; 13629 } 13630 13631 Expression eleft; 13632 Expression eright; 13633 if (auto de = exp.e1.isDotExp()) 13634 { 13635 eleft = de.e1; 13636 eright = de.e2; 13637 } 13638 else 13639 { 13640 eleft = null; 13641 eright = exp.e1; 13642 } 13643 13644 Type t1b = exp.e1.type.toBasetype(); 13645 13646 if (auto ie = eright.isScopeExp()) // also used for template alias's 13647 { 13648 auto flags = SearchLocalsOnly; 13649 /* Disable access to another module's private imports. 13650 * The check for 'is sds our current module' is because 13651 * the current module should have access to its own imports. 13652 */ 13653 if (ie.sds.isModule() && ie.sds != sc._module) 13654 flags |= IgnorePrivateImports; 13655 if (sc.flags & SCOPE.ignoresymbolvisibility) 13656 flags |= IgnoreSymbolVisibility; 13657 Dsymbol s = ie.sds.search(exp.loc, exp.ident, flags); 13658 /* Check for visibility before resolving aliases because public 13659 * aliases to private symbols are public. 13660 */ 13661 if (s && !(sc.flags & SCOPE.ignoresymbolvisibility) && !symbolIsVisible(sc._module, s)) 13662 { 13663 s = null; 13664 } 13665 if (s) 13666 { 13667 auto p = s.isPackage(); 13668 if (p && checkAccess(sc, p)) 13669 { 13670 s = null; 13671 } 13672 } 13673 if (s) 13674 { 13675 // if 's' is a tuple variable, the tuple is returned. 13676 s = s.toAlias(); 13677 13678 exp.checkDeprecated(sc, s); 13679 exp.checkDisabled(sc, s); 13680 13681 if (auto em = s.isEnumMember()) 13682 { 13683 return em.getVarExp(exp.loc, sc); 13684 } 13685 if (auto v = s.isVarDeclaration()) 13686 { 13687 //printf("DotIdExp:: Identifier '%s' is a variable, type '%s'\n", toChars(), v.type.toChars()); 13688 if (!v.type || 13689 !v.type.deco && v.inuse) 13690 { 13691 if (v.inuse) 13692 error(exp.loc, "circular reference to %s `%s`", v.kind(), v.toPrettyChars()); 13693 else 13694 error(exp.loc, "forward reference to %s `%s`", v.kind(), v.toPrettyChars()); 13695 return ErrorExp.get(); 13696 } 13697 if (v.type.isTypeError()) 13698 return ErrorExp.get(); 13699 13700 if ((v.storage_class & STC.manifest) && v._init && !exp.wantsym) 13701 { 13702 /* Normally, the replacement of a symbol with its initializer is supposed to be in semantic2(). 13703 * Introduced by https://github.com/dlang/dmd/pull/5588 which should probably 13704 * be reverted. `wantsym` is the hack to work around the problem. 13705 */ 13706 if (v.inuse) 13707 { 13708 error(exp.loc, "circular initialization of %s `%s`", v.kind(), v.toPrettyChars()); 13709 return ErrorExp.get(); 13710 } 13711 auto e = v.expandInitializer(exp.loc); 13712 v.inuse++; 13713 e = e.expressionSemantic(sc); 13714 v.inuse--; 13715 return e; 13716 } 13717 13718 Expression e; 13719 if (v.needThis()) 13720 { 13721 if (!eleft) 13722 eleft = new ThisExp(exp.loc); 13723 e = new DotVarExp(exp.loc, eleft, v); 13724 e = e.expressionSemantic(sc); 13725 } 13726 else 13727 { 13728 e = new VarExp(exp.loc, v); 13729 if (eleft) 13730 { 13731 e = new CommaExp(exp.loc, eleft, e); 13732 e.type = v.type; 13733 } 13734 } 13735 e = e.deref(); 13736 return e.expressionSemantic(sc); 13737 } 13738 13739 if (auto f = s.isFuncDeclaration()) 13740 { 13741 //printf("it's a function\n"); 13742 if (!f.functionSemantic()) 13743 return ErrorExp.get(); 13744 Expression e; 13745 if (f.needThis()) 13746 { 13747 if (!eleft) 13748 eleft = new ThisExp(exp.loc); 13749 e = new DotVarExp(exp.loc, eleft, f, true); 13750 e = e.expressionSemantic(sc); 13751 } 13752 else 13753 { 13754 e = new VarExp(exp.loc, f, true); 13755 if (eleft) 13756 { 13757 e = new CommaExp(exp.loc, eleft, e); 13758 e.type = f.type; 13759 } 13760 } 13761 return e; 13762 } 13763 if (auto td = s.isTemplateDeclaration()) 13764 { 13765 Expression e; 13766 if (eleft) 13767 e = new DotTemplateExp(exp.loc, eleft, td); 13768 else 13769 e = new TemplateExp(exp.loc, td); 13770 e = e.expressionSemantic(sc); 13771 return e; 13772 } 13773 if (OverDeclaration od = s.isOverDeclaration()) 13774 { 13775 Expression e = new VarExp(exp.loc, od, true); 13776 if (eleft) 13777 { 13778 e = new CommaExp(exp.loc, eleft, e); 13779 e.type = Type.tvoid; // ambiguous type? 13780 } 13781 return e.expressionSemantic(sc); 13782 } 13783 if (auto o = s.isOverloadSet()) 13784 { 13785 //printf("'%s' is an overload set\n", o.toChars()); 13786 return new OverExp(exp.loc, o); 13787 } 13788 13789 if (auto t = s.getType()) 13790 { 13791 return (new TypeExp(exp.loc, t)).expressionSemantic(sc); 13792 } 13793 13794 if (auto tup = s.isTupleDeclaration()) 13795 { 13796 if (eleft) 13797 { 13798 Expression e = new DotVarExp(exp.loc, eleft, tup); 13799 e = e.expressionSemantic(sc); 13800 return e; 13801 } 13802 Expression e = new TupleExp(exp.loc, tup); 13803 e = e.expressionSemantic(sc); 13804 return e; 13805 } 13806 13807 if (auto sds = s.isScopeDsymbol()) 13808 { 13809 //printf("it's a ScopeDsymbol %s\n", ident.toChars()); 13810 Expression e = new ScopeExp(exp.loc, sds); 13811 e = e.expressionSemantic(sc); 13812 if (eleft) 13813 e = new DotExp(exp.loc, eleft, e); 13814 return e; 13815 } 13816 13817 if (auto imp = s.isImport()) 13818 { 13819 Expression se = new ScopeExp(exp.loc, imp.pkg); 13820 return se.expressionSemantic(sc); 13821 } 13822 13823 if (auto attr = s.isAttribDeclaration()) 13824 { 13825 if (auto sm = ie.sds.search(exp.loc, exp.ident, flags)) 13826 { 13827 auto es = new DsymbolExp(exp.loc, sm); 13828 return es; 13829 } 13830 } 13831 13832 // BUG: handle other cases like in IdentifierExp::semantic() 13833 debug 13834 { 13835 printf("s = %p '%s', kind = '%s'\n", s, s.toChars(), s.kind()); 13836 } 13837 assert(0); 13838 } 13839 else if (exp.ident == Id.stringof) 13840 { 13841 Expression e = new StringExp(exp.loc, ie.toString()); 13842 e = e.expressionSemantic(sc); 13843 return e; 13844 } 13845 if (ie.sds.isPackage() || ie.sds.isImport() || ie.sds.isModule()) 13846 { 13847 gag = false; 13848 } 13849 if (gag) 13850 return null; 13851 s = ie.sds.search_correct(exp.ident); 13852 if (s && symbolIsVisible(sc, s)) 13853 { 13854 if (s.isPackage()) 13855 error(exp.loc, "undefined identifier `%s` in %s `%s`, perhaps add `static import %s;`", exp.ident.toChars(), ie.sds.kind(), ie.sds.toPrettyChars(), s.toPrettyChars()); 13856 else 13857 error(exp.loc, "undefined identifier `%s` in %s `%s`, did you mean %s `%s`?", exp.ident.toChars(), ie.sds.kind(), ie.sds.toPrettyChars(), s.kind(), s.toChars()); 13858 } 13859 else 13860 error(exp.loc, "undefined identifier `%s` in %s `%s`", exp.ident.toChars(), ie.sds.kind(), ie.sds.toPrettyChars()); 13861 return ErrorExp.get(); 13862 } 13863 else if (t1b.ty == Tpointer && exp.e1.type.ty != Tenum && 13864 !( 13865 exp.ident == Id.__sizeof || 13866 exp.ident == Id.__xalignof || 13867 !cfile && 13868 (exp.ident == Id._mangleof || 13869 exp.ident == Id.offsetof || 13870 exp.ident == Id._init || 13871 exp.ident == Id.stringof) 13872 )) 13873 { 13874 Type t1bn = t1b.nextOf(); 13875 if (gag) 13876 { 13877 if (AggregateDeclaration ad = isAggregate(t1bn)) 13878 { 13879 if (!ad.members) // https://issues.dlang.org/show_bug.cgi?id=11312 13880 return null; 13881 } 13882 } 13883 13884 /* Rewrite: 13885 * p.ident 13886 * as: 13887 * (*p).ident 13888 */ 13889 if (gag && t1bn.ty == Tvoid) 13890 return null; 13891 Expression e = new PtrExp(exp.loc, exp.e1); 13892 e = e.expressionSemantic(sc); 13893 const newFlag = cast(DotExpFlag) (gag * DotExpFlag.gag | exp.noderef * DotExpFlag.noDeref); 13894 return e.type.dotExp(sc, e, exp.ident, newFlag); 13895 } 13896 else if (exp.ident == Id.__xalignof && 13897 exp.e1.isVarExp() && 13898 exp.e1.isVarExp().var.isVarDeclaration() && 13899 !exp.e1.isVarExp().var.isVarDeclaration().alignment.isUnknown()) 13900 { 13901 // For `x.alignof` get the alignment of the variable, not the alignment of its type 13902 const explicitAlignment = exp.e1.isVarExp().var.isVarDeclaration().alignment; 13903 const naturalAlignment = exp.e1.type.alignsize(); 13904 const actualAlignment = explicitAlignment.isDefault() ? naturalAlignment : explicitAlignment.get(); 13905 Expression e = new IntegerExp(exp.loc, actualAlignment, Type.tsize_t); 13906 return e; 13907 } 13908 else if ((exp.ident == Id.max || exp.ident == Id.min) && 13909 exp.e1.isVarExp() && 13910 exp.e1.isVarExp().var.isBitFieldDeclaration()) 13911 { 13912 // For `x.max` and `x.min` get the max/min of the bitfield, not the max/min of its type 13913 auto bf = exp.e1.isVarExp().var.isBitFieldDeclaration(); 13914 return new IntegerExp(exp.loc, bf.getMinMax(exp.ident), bf.type); 13915 } 13916 else if ((exp.ident == Id.max || exp.ident == Id.min) && 13917 exp.e1.isDotVarExp() && 13918 exp.e1.isDotVarExp().var.isBitFieldDeclaration()) 13919 { 13920 // For `x.max` and `x.min` get the max/min of the bitfield, not the max/min of its type 13921 auto bf = exp.e1.isDotVarExp().var.isBitFieldDeclaration(); 13922 return new IntegerExp(exp.loc, bf.getMinMax(exp.ident), bf.type); 13923 } 13924 else 13925 { 13926 if (exp.e1.isTypeExp() || exp.e1.isTemplateExp()) 13927 gag = false; 13928 13929 const flag = cast(DotExpFlag) (exp.noderef * DotExpFlag.noDeref | gag * DotExpFlag.gag); 13930 13931 Expression e = exp.e1.type.dotExp(sc, exp.e1, exp.ident, flag); 13932 if (e) 13933 { 13934 e = e.expressionSemantic(sc); 13935 } 13936 return e; 13937 } 13938 } 13939 13940 /** 13941 * Resolve `e1.ident!tiargs` without seeing UFCS. 13942 * Params: 13943 * exp = the `DotTemplateInstanceExp` to resolve 13944 * sc = the semantic scope 13945 * gag = stop "not a property" error and return `null`. 13946 * Returns: 13947 * `null` if error or not found, or the resolved expression. 13948 */ 13949 Expression dotTemplateSemanticProp(DotTemplateInstanceExp exp, Scope* sc, bool gag) 13950 { 13951 static if (LOGSEMANTIC) 13952 { 13953 printf("DotTemplateInstanceExpY::semantic('%s')\n", exp.toChars()); 13954 } 13955 13956 static Expression errorExp() 13957 { 13958 return ErrorExp.get(); 13959 } 13960 13961 Expression e1 = exp.e1; 13962 13963 if (exp.ti.tempdecl && exp.ti.tempdecl.parent && exp.ti.tempdecl.parent.isTemplateMixin()) 13964 { 13965 // if 'ti.tempdecl' happens to be found in a mixin template don't lose that info 13966 // and do the symbol search in that context (Issue: 19476) 13967 auto tm = cast(TemplateMixin)exp.ti.tempdecl.parent; 13968 e1 = new DotExp(exp.e1.loc, exp.e1, new ScopeExp(tm.loc, tm)); 13969 } 13970 13971 auto die = new DotIdExp(exp.loc, e1, exp.ti.name); 13972 13973 Expression e = die.dotIdSemanticPropX(sc); 13974 if (e == die) 13975 { 13976 exp.e1 = die.e1; // take back 13977 Type t1b = exp.e1.type.toBasetype(); 13978 if (t1b.ty == Tarray || t1b.ty == Tsarray || t1b.ty == Taarray || t1b.ty == Tnull || (t1b.isTypeBasic() && t1b.ty != Tvoid)) 13979 { 13980 /* No built-in type has templatized properties, so do shortcut. 13981 * It is necessary in: 1024.max!"a < b" 13982 */ 13983 if (gag) 13984 return null; 13985 } 13986 e = die.dotIdSemanticProp(sc, gag); 13987 if (gag) 13988 { 13989 if (!e || 13990 isDotOpDispatch(e)) 13991 { 13992 /* opDispatch!tiargs would be a function template that needs IFTI, 13993 * so it's not a template 13994 */ 13995 return null; 13996 } 13997 } 13998 } 13999 assert(e); 14000 14001 if (e.op == EXP.error) 14002 return e; 14003 if (DotVarExp dve = e.isDotVarExp()) 14004 { 14005 if (FuncDeclaration fd = dve.var.isFuncDeclaration()) 14006 { 14007 if (TemplateDeclaration td = fd.findTemplateDeclRoot()) 14008 { 14009 e = new DotTemplateExp(dve.loc, dve.e1, td); 14010 e = e.expressionSemantic(sc); 14011 } 14012 } 14013 else if (OverDeclaration od = dve.var.isOverDeclaration()) 14014 { 14015 exp.e1 = dve.e1; // pull semantic() result 14016 14017 if (!exp.findTempDecl(sc)) 14018 goto Lerr; 14019 if (exp.ti.needsTypeInference(sc)) 14020 return exp; 14021 exp.ti.dsymbolSemantic(sc); 14022 if (!exp.ti.inst || exp.ti.errors) // if template failed to expand 14023 return errorExp(); 14024 14025 if (Declaration v = exp.ti.toAlias().isDeclaration()) 14026 { 14027 if (v.type && !v.type.deco) 14028 v.type = v.type.typeSemantic(v.loc, sc); 14029 return new DotVarExp(exp.loc, exp.e1, v) 14030 .expressionSemantic(sc); 14031 } 14032 return new DotExp(exp.loc, exp.e1, new ScopeExp(exp.loc, exp.ti)) 14033 .expressionSemantic(sc); 14034 } 14035 } 14036 else if (e.op == EXP.variable) 14037 { 14038 VarExp ve = cast(VarExp)e; 14039 if (FuncDeclaration fd = ve.var.isFuncDeclaration()) 14040 { 14041 if (TemplateDeclaration td = fd.findTemplateDeclRoot()) 14042 { 14043 e = new TemplateExp(ve.loc, td) 14044 .expressionSemantic(sc); 14045 } 14046 } 14047 else if (OverDeclaration od = ve.var.isOverDeclaration()) 14048 { 14049 exp.ti.tempdecl = od; 14050 return new ScopeExp(exp.loc, exp.ti) 14051 .expressionSemantic(sc); 14052 } 14053 } 14054 14055 if (DotTemplateExp dte = e.isDotTemplateExp()) 14056 { 14057 exp.e1 = dte.e1; // pull semantic() result 14058 14059 exp.ti.tempdecl = dte.td; 14060 if (!exp.ti.semanticTiargs(sc)) 14061 return errorExp(); 14062 if (exp.ti.needsTypeInference(sc)) 14063 return exp; 14064 exp.ti.dsymbolSemantic(sc); 14065 if (!exp.ti.inst || exp.ti.errors) // if template failed to expand 14066 return errorExp(); 14067 14068 if (Declaration v = exp.ti.toAlias().isDeclaration()) 14069 { 14070 return new DotVarExp(exp.loc, exp.e1, v) 14071 .expressionSemantic(sc); 14072 } 14073 return new DotExp(exp.loc, exp.e1, new ScopeExp(exp.loc, exp.ti)) 14074 .expressionSemantic(sc); 14075 } 14076 else if (e.op == EXP.template_) 14077 { 14078 exp.ti.tempdecl = (cast(TemplateExp)e).td; 14079 return new ScopeExp(exp.loc, exp.ti) 14080 .expressionSemantic(sc); 14081 } 14082 else if (DotExp de = e.isDotExp()) 14083 { 14084 if (de.e2.op == EXP.overloadSet) 14085 { 14086 if (!exp.findTempDecl(sc) || !exp.ti.semanticTiargs(sc)) 14087 { 14088 return errorExp(); 14089 } 14090 if (exp.ti.needsTypeInference(sc)) 14091 return exp; 14092 exp.ti.dsymbolSemantic(sc); 14093 if (!exp.ti.inst || exp.ti.errors) // if template failed to expand 14094 return errorExp(); 14095 14096 if (Declaration v = exp.ti.toAlias().isDeclaration()) 14097 { 14098 if (v.type && !v.type.deco) 14099 v.type = v.type.typeSemantic(v.loc, sc); 14100 return new DotVarExp(exp.loc, exp.e1, v) 14101 .expressionSemantic(sc); 14102 } 14103 return new DotExp(exp.loc, exp.e1, new ScopeExp(exp.loc, exp.ti)) 14104 .expressionSemantic(sc); 14105 } 14106 } 14107 else if (OverExp oe = e.isOverExp()) 14108 { 14109 exp.ti.tempdecl = oe.vars; 14110 return new ScopeExp(exp.loc, exp.ti) 14111 .expressionSemantic(sc); 14112 } 14113 14114 Lerr: 14115 error(exp.loc, "`%s` isn't a template", e.toChars()); 14116 return errorExp(); 14117 } 14118 14119 MATCH matchType(FuncExp funcExp, Type to, Scope* sc, FuncExp* presult, ErrorSink eSink) 14120 { 14121 auto loc = funcExp.loc; 14122 auto tok = funcExp.tok; 14123 auto td = funcExp.td; 14124 auto fd = funcExp.fd; 14125 auto type = funcExp.type; 14126 14127 MATCH cannotInfer() 14128 { 14129 eSink.error(loc, "cannot infer parameter types from `%s`", to.toChars()); 14130 return MATCH.nomatch; 14131 } 14132 14133 //printf("FuncExp::matchType('%s'), to=%s\n", type ? type.toChars() : "null", to.toChars()); 14134 if (presult) 14135 *presult = null; 14136 14137 TypeFunction tof = null; 14138 if (to.ty == Tdelegate) 14139 { 14140 if (tok == TOK.function_) 14141 { 14142 eSink.error(loc, "cannot match function literal to delegate type `%s`", to.toChars()); 14143 return MATCH.nomatch; 14144 } 14145 tof = cast(TypeFunction)to.nextOf(); 14146 } 14147 else if (to.ty == Tpointer && (tof = to.nextOf().isTypeFunction()) !is null) 14148 { 14149 if (tok == TOK.delegate_) 14150 { 14151 eSink.error(loc, "cannot match delegate literal to function pointer type `%s`", to.toChars()); 14152 return MATCH.nomatch; 14153 } 14154 } 14155 14156 if (td) 14157 { 14158 if (!tof) 14159 { 14160 return cannotInfer(); 14161 } 14162 14163 // Parameter types inference from 'tof' 14164 assert(td._scope); 14165 TypeFunction tf = fd.type.isTypeFunction(); 14166 //printf("\ttof = %s\n", tof.toChars()); 14167 //printf("\ttf = %s\n", tf.toChars()); 14168 const dim = tf.parameterList.length; 14169 14170 if (tof.parameterList.length != dim || tof.parameterList.varargs != tf.parameterList.varargs) 14171 return cannotInfer(); 14172 14173 auto tiargs = new Objects(); 14174 tiargs.reserve(td.parameters.length); 14175 14176 foreach (tp; *td.parameters) 14177 { 14178 size_t u = 0; 14179 foreach (i, p; tf.parameterList) 14180 { 14181 if (auto ti = p.type.isTypeIdentifier()) 14182 if (ti && ti.ident == tp.ident) 14183 break; 14184 14185 ++u; 14186 } 14187 assert(u < dim); 14188 Parameter pto = tof.parameterList[u]; 14189 Type t = pto.type; 14190 if (t.ty == Terror) 14191 return cannotInfer(); 14192 tf.parameterList[u].storageClass = tof.parameterList[u].storageClass; 14193 tiargs.push(t); 14194 } 14195 14196 // Set target of return type inference 14197 if (!tf.next && tof.next) 14198 fd.treq = to; 14199 14200 auto ti = new TemplateInstance(loc, td, tiargs); 14201 Expression ex = (new ScopeExp(loc, ti)).expressionSemantic(td._scope); 14202 14203 // Reset inference target for the later re-semantic 14204 fd.treq = null; 14205 14206 if (ex.op == EXP.error) 14207 return MATCH.nomatch; 14208 if (auto ef = ex.isFuncExp()) 14209 return ef.matchType(to, sc, presult, eSink); 14210 else 14211 return cannotInfer(); 14212 } 14213 14214 if (!tof || !tof.next) 14215 return MATCH.nomatch; 14216 14217 assert(type && type != Type.tvoid); 14218 if (fd.type.ty == Terror) 14219 return MATCH.nomatch; 14220 auto tfx = fd.type.isTypeFunction(); 14221 bool convertMatch = (type.ty != to.ty); 14222 14223 if (fd.inferRetType && tfx.next.implicitConvTo(tof.next) == MATCH.convert) 14224 { 14225 /* If return type is inferred and covariant return, 14226 * tweak return statements to required return type. 14227 * 14228 * interface I {} 14229 * class C : Object, I{} 14230 * 14231 * I delegate() dg = delegate() { return new class C(); } 14232 */ 14233 convertMatch = true; 14234 14235 auto tfy = new TypeFunction(tfx.parameterList, tof.next, 14236 tfx.linkage, STC.undefined_); 14237 tfy.mod = tfx.mod; 14238 tfy.trust = tfx.trust; 14239 tfy.isnothrow = tfx.isnothrow; 14240 tfy.isnogc = tfx.isnogc; 14241 tfy.purity = tfx.purity; 14242 tfy.isproperty = tfx.isproperty; 14243 tfy.isref = tfx.isref; 14244 tfy.isInOutParam = tfx.isInOutParam; 14245 tfy.isInOutQual = tfx.isInOutQual; 14246 tfy.deco = tfy.merge().deco; 14247 14248 tfx = tfy; 14249 } 14250 Type tx; 14251 if (tok == TOK.delegate_ || 14252 tok == TOK.reserved && (type.ty == Tdelegate || type.ty == Tpointer && to.ty == Tdelegate)) 14253 { 14254 // Allow conversion from implicit function pointer to delegate 14255 tx = new TypeDelegate(tfx); 14256 tx.deco = tx.merge().deco; 14257 } 14258 else 14259 { 14260 assert(tok == TOK.function_ || tok == TOK.reserved && type.ty == Tpointer || fd.errors); 14261 tx = tfx.pointerTo(); 14262 } 14263 //printf("\ttx = %s, to = %s\n", tx.toChars(), to.toChars()); 14264 14265 MATCH m = tx.implicitConvTo(to); 14266 if (m > MATCH.nomatch) 14267 { 14268 // MATCH.exact: exact type match 14269 // MATCH.constant: covairiant type match (eg. attributes difference) 14270 // MATCH.convert: context conversion 14271 m = convertMatch ? MATCH.convert : tx.equals(to) ? MATCH.exact : MATCH.constant; 14272 14273 if (presult) 14274 { 14275 (*presult) = cast(FuncExp)funcExp.copy(); 14276 (*presult).type = to; 14277 14278 // https://issues.dlang.org/show_bug.cgi?id=12508 14279 // Tweak function body for covariant returns. 14280 (*presult).fd.modifyReturns(sc, tof.next); 14281 } 14282 } 14283 else if (!cast(ErrorSinkNull)eSink) 14284 { 14285 auto ts = toAutoQualChars(tx, to); 14286 eSink.error(loc, "cannot implicitly convert expression `%s` of type `%s` to `%s`", 14287 funcExp.toChars(), ts[0], ts[1]); 14288 } 14289 return m; 14290 } 14291 14292 private bool checkSharedAccessBin(BinExp binExp, Scope* sc) 14293 { 14294 const r1 = binExp.e1.checkSharedAccess(sc); 14295 const r2 = binExp.e2.checkSharedAccess(sc); 14296 return (r1 || r2); 14297 } 14298 14299 /*************************************** 14300 * If expression is shared, check that we can access it. 14301 * Give error message if not. 14302 * 14303 * Params: 14304 * e = expression to check 14305 * sc = context 14306 * returnRef = Whether this expression is for a `return` statement 14307 * off a `ref` function, in which case a single level 14308 * of dereference is allowed (e.g. `shared(int)*`). 14309 * Returns: 14310 * true on error 14311 */ 14312 bool checkSharedAccess(Expression e, Scope* sc, bool returnRef = false) 14313 { 14314 if (global.params.noSharedAccess != FeatureState.enabled || 14315 !sc || 14316 sc.intypeof || 14317 sc.flags & SCOPE.ctfe) 14318 { 14319 return false; 14320 } 14321 14322 //printf("checkSharedAccess() `%s` returnRef: %d\n", e.toChars(), returnRef); 14323 14324 bool check(Expression e, bool allowRef) 14325 { 14326 bool sharedError(Expression e) 14327 { 14328 // https://dlang.org/phobos/core_atomic.html 14329 error(e.loc, "direct access to shared `%s` is not allowed, see `core.atomic`", e.toChars()); 14330 return true; 14331 } 14332 14333 // Error by default 14334 bool visit(Expression e) 14335 { 14336 // https://issues.dlang.org/show_bug.cgi?id=23639 14337 // Should be able to cast(shared) 14338 if (!e.isCastExp() && e.type.isShared()) 14339 return sharedError(e); 14340 return false; 14341 } 14342 14343 bool visitNew(NewExp e) 14344 { 14345 if (e.thisexp) 14346 check(e.thisexp, false); 14347 return false; 14348 } 14349 14350 bool visitVar(VarExp e) 14351 { 14352 // https://issues.dlang.org/show_bug.cgi?id=20908 14353 // direct access to init symbols is ok as they 14354 // cannot be modified. 14355 if (e.var.isSymbolDeclaration()) 14356 return false; 14357 14358 // https://issues.dlang.org/show_bug.cgi?id=22626 14359 // Synchronized functions don't need to use core.atomic 14360 // when accessing `this`. 14361 if (sc.func && sc.func.isSynchronized()) 14362 { 14363 if (e.var.isThisDeclaration()) 14364 return false; 14365 else 14366 return sharedError(e); 14367 } 14368 else if (!allowRef && e.var.type.isShared()) 14369 return sharedError(e); 14370 14371 return false; 14372 } 14373 14374 bool visitAddr(AddrExp e) 14375 { 14376 return check(e.e1, true); 14377 } 14378 14379 bool visitPtr(PtrExp e) 14380 { 14381 if (!allowRef && e.type.isShared()) 14382 return sharedError(e); 14383 14384 if (e.e1.type.isShared()) 14385 return sharedError(e); 14386 14387 return check(e.e1, false); 14388 } 14389 14390 bool visitDotVar(DotVarExp e) 14391 { 14392 //printf("dotvarexp = %s\n", e.toChars()); 14393 if (e.type.isShared()) 14394 { 14395 if (e.e1.isThisExp()) 14396 { 14397 // https://issues.dlang.org/show_bug.cgi?id=22626 14398 if (sc.func && sc.func.isSynchronized()) 14399 return false; 14400 14401 // https://issues.dlang.org/show_bug.cgi?id=23790 14402 if (e.e1.type.isTypeStruct()) 14403 return false; 14404 } 14405 14406 auto fd = e.var.isFuncDeclaration(); 14407 const sharedFunc = fd && fd.type.isShared; 14408 if (!allowRef && !sharedFunc) 14409 return sharedError(e); 14410 14411 // Allow using `DotVarExp` within value types 14412 if (e.e1.type.isTypeSArray() || e.e1.type.isTypeStruct()) 14413 return check(e.e1, allowRef); 14414 14415 // If we end up with a single `VarExp`, it might be a `ref` param 14416 // `shared ref T` param == `shared(T)*`. 14417 if (auto ve = e.e1.isVarExp()) 14418 { 14419 return check(e.e1, allowRef && (ve.var.storage_class & STC.ref_)); 14420 } 14421 14422 return sharedError(e); 14423 } 14424 14425 return check(e.e1, false); 14426 } 14427 14428 bool visitIndex(IndexExp e) 14429 { 14430 if (!allowRef && e.type.isShared()) 14431 return sharedError(e); 14432 14433 if (e.e1.type.isShared()) 14434 return sharedError(e); 14435 14436 return check(e.e1, false); 14437 } 14438 14439 bool visitComma(CommaExp e) 14440 { 14441 // Cannot be `return ref` since we can't use the return, 14442 // but it's better to show that error than an unrelated `shared` one 14443 return check(e.e2, true); 14444 } 14445 14446 switch (e.op) 14447 { 14448 default: return visit(e); 14449 14450 // Those have no indirections / can be ignored 14451 case EXP.call: 14452 case EXP.error: 14453 case EXP.complex80: 14454 case EXP.int64: 14455 case EXP.null_: return false; 14456 14457 case EXP.variable: return visitVar(e.isVarExp()); 14458 case EXP.new_: return visitNew(e.isNewExp()); 14459 case EXP.address: return visitAddr(e.isAddrExp()); 14460 case EXP.star: return visitPtr(e.isPtrExp()); 14461 case EXP.dotVariable: return visitDotVar(e.isDotVarExp()); 14462 case EXP.index: return visitIndex(e.isIndexExp()); 14463 } 14464 } 14465 14466 return check(e, returnRef); 14467 } 14468 14469 /************************************************ 14470 * Destructors are attached to VarDeclarations. 14471 * Hence, if expression returns a temp that needs a destructor, 14472 * make sure and create a VarDeclaration for that temp. 14473 */ 14474 Expression addDtorHook(Expression e, Scope* sc) 14475 { 14476 Expression visit(Expression exp) 14477 { 14478 return exp; 14479 } 14480 14481 Expression visitStructLiteral(StructLiteralExp exp) 14482 { 14483 auto sd = exp.sd; 14484 /* If struct requires a destructor, rewrite as: 14485 * (S tmp = S()),tmp 14486 * so that the destructor can be hung on tmp. 14487 */ 14488 if (sd.dtor && sc.func) 14489 { 14490 /* Make an identifier for the temporary of the form: 14491 * __sl%s%d, where %s is the struct name 14492 */ 14493 char[10] buf = void; 14494 const prefix = "__sl"; 14495 const ident = sd.ident.toString; 14496 const fullLen = prefix.length + ident.length; 14497 const len = fullLen < buf.length ? fullLen : buf.length; 14498 buf[0 .. prefix.length] = prefix; 14499 buf[prefix.length .. len] = ident[0 .. len - prefix.length]; 14500 14501 auto tmp = copyToTemp(0, buf[0 .. len], exp); 14502 Expression ae = new DeclarationExp(exp.loc, tmp); 14503 Expression e = new CommaExp(exp.loc, ae, new VarExp(exp.loc, tmp)); 14504 e = e.expressionSemantic(sc); 14505 return e; 14506 } 14507 14508 return exp; 14509 } 14510 14511 Expression visitCall(CallExp exp) 14512 { 14513 auto e1 = exp.e1; 14514 auto type = exp.type; 14515 /* Only need to add dtor hook if it's a type that needs destruction. 14516 * Use same logic as VarDeclaration::callScopeDtor() 14517 */ 14518 14519 if (auto tf = e1.type.isTypeFunction()) 14520 { 14521 if (tf.isref) 14522 return exp; 14523 } 14524 14525 Type tv = type.baseElemOf(); 14526 if (auto ts = tv.isTypeStruct()) 14527 { 14528 StructDeclaration sd = ts.sym; 14529 if (sd.dtor) 14530 { 14531 /* Type needs destruction, so declare a tmp 14532 * which the back end will recognize and call dtor on 14533 */ 14534 auto tmp = copyToTemp(0, Id.__tmpfordtor.toString(), exp); 14535 auto de = new DeclarationExp(exp.loc, tmp); 14536 auto ve = new VarExp(exp.loc, tmp); 14537 Expression e = new CommaExp(exp.loc, de, ve); 14538 e = e.expressionSemantic(sc); 14539 return e; 14540 } 14541 } 14542 14543 return exp; 14544 } 14545 14546 Expression visitCast(CastExp exp) 14547 { 14548 if (exp.to.toBasetype().ty == Tvoid) // look past the cast(void) 14549 exp.e1 = exp.e1.addDtorHook(sc); 14550 return exp; 14551 } 14552 14553 Expression visitComma(CommaExp exp) 14554 { 14555 exp.e2 = exp.e2.addDtorHook(sc); 14556 return exp; 14557 } 14558 14559 switch(e.op) 14560 { 14561 default: return visit(e); 14562 14563 case EXP.structLiteral: return visitStructLiteral(e.isStructLiteralExp()); 14564 case EXP.call: return visitCall(e.isCallExp()); 14565 case EXP.cast_: return visitCast(e.isCastExp()); 14566 case EXP.comma: return visitComma(e.isCommaExp()); 14567 } 14568 } 14569 14570 /**************************************************** 14571 * Determine if `exp`, which gets its address taken, can do so safely. 14572 * Params: 14573 * sc = context 14574 * exp = expression having its address taken 14575 * v = the variable getting its address taken 14576 * Returns: 14577 * `true` if ok, `false` for error 14578 */ 14579 bool checkAddressVar(Scope* sc, Expression exp, VarDeclaration v) 14580 { 14581 //printf("checkAddressVar(exp: %s, v: %s)\n", exp.toChars(), v.toChars()); 14582 if (v is null) 14583 return true; 14584 14585 if (!v.canTakeAddressOf()) 14586 { 14587 error(exp.loc, "cannot take address of `%s`", exp.toChars()); 14588 return false; 14589 } 14590 if (sc.func && !sc.intypeof && !v.isDataseg()) 14591 { 14592 if (global.params.useDIP1000 != FeatureState.enabled && 14593 !(v.storage_class & STC.temp) && 14594 sc.setUnsafe(false, exp.loc, "cannot take address of local `%s` in `@safe` function `%s`", v, sc.func)) 14595 { 14596 return false; 14597 } 14598 } 14599 return true; 14600 } 14601 14602 /************************************** 14603 * This check ensures that the object in `exp` can have its address taken, or 14604 * issue a diagnostic error. 14605 * Params: 14606 * e = expression to check 14607 * sc = context 14608 * Returns: 14609 * true if the expression is addressable 14610 */ 14611 bool checkAddressable(Expression e, Scope* sc) 14612 { 14613 Expression ex = e; 14614 while (true) 14615 { 14616 switch (ex.op) 14617 { 14618 case EXP.dotVariable: 14619 // https://issues.dlang.org/show_bug.cgi?id=22749 14620 // Error about taking address of any bit-field, regardless of 14621 // whether SCOPE.Cfile is set. 14622 if (auto bf = ex.isDotVarExp().var.isBitFieldDeclaration()) 14623 { 14624 error(e.loc, "cannot take address of bit-field `%s`", bf.toChars()); 14625 return false; 14626 } 14627 goto case EXP.cast_; 14628 14629 case EXP.index: 14630 ex = ex.isBinExp().e1; 14631 continue; 14632 14633 case EXP.address: 14634 case EXP.array: 14635 case EXP.cast_: 14636 ex = ex.isUnaExp().e1; 14637 continue; 14638 14639 case EXP.variable: 14640 if (sc.flags & SCOPE.Cfile) 14641 { 14642 // C11 6.5.3.2: A variable that has its address taken cannot be 14643 // stored in a register. 14644 // C11 6.3.2.1: An array that has its address computed with `[]` 14645 // or cast to an lvalue pointer cannot be stored in a register. 14646 if (ex.isVarExp().var.storage_class & STC.register) 14647 { 14648 if (e.isIndexExp()) 14649 error(e.loc, "cannot index through register variable `%s`", ex.toChars()); 14650 else 14651 error(e.loc, "cannot take address of register variable `%s`", ex.toChars()); 14652 return false; 14653 } 14654 } 14655 break; 14656 14657 default: 14658 break; 14659 } 14660 break; 14661 } 14662 return true; 14663 } 14664 14665 14666 /******************************* 14667 * Checks the attributes of a function. 14668 * Purity (`pure`), safety (`@safe`), no GC allocations(`@nogc`) 14669 * and usage of `deprecated` and `@disabled`-ed symbols are checked. 14670 * 14671 * Params: 14672 * exp = expression to check attributes for 14673 * sc = scope of the function 14674 * f = function to be checked 14675 * Returns: `true` if error occur. 14676 */ 14677 private bool checkFunctionAttributes(Expression exp, Scope* sc, FuncDeclaration f) 14678 { 14679 with(exp) 14680 { 14681 bool error = checkDisabled(sc, f); 14682 error |= checkDeprecated(sc, f); 14683 error |= checkPurity(sc, f); 14684 error |= checkSafety(sc, f); 14685 error |= checkNogc(sc, f); 14686 return error; 14687 } 14688 } 14689 14690 /******************************* 14691 * Helper function for `getRightThis()`. 14692 * Gets `this` of the next outer aggregate. 14693 * Params: 14694 * loc = location to use for error messages 14695 * sc = context 14696 * s = the parent symbol of the existing `this` 14697 * ad = struct or class we need the correct `this` for 14698 * e1 = existing `this` 14699 * t = type of the existing `this` 14700 * var = the specific member of ad we're accessing 14701 * flag = if true, return `null` instead of throwing an error 14702 * Returns: 14703 * Expression representing the `this` for the var 14704 */ 14705 Expression getThisSkipNestedFuncs(const ref Loc loc, Scope* sc, Dsymbol s, AggregateDeclaration ad, Expression e1, Type t, Dsymbol var, bool flag = false) 14706 { 14707 int n = 0; 14708 while (s && s.isFuncDeclaration()) 14709 { 14710 FuncDeclaration f = s.isFuncDeclaration(); 14711 if (f.vthis) 14712 { 14713 n++; 14714 e1 = new VarExp(loc, f.vthis); 14715 if (f.hasDualContext()) 14716 { 14717 // (*__this)[i] 14718 if (n > 1) 14719 e1 = e1.expressionSemantic(sc); 14720 e1 = new PtrExp(loc, e1); 14721 uint i = f.followInstantiationContext(ad); 14722 e1 = new IndexExp(loc, e1, new IntegerExp(i)); 14723 s = f.toParentP(ad); 14724 continue; 14725 } 14726 } 14727 else 14728 { 14729 if (flag) 14730 return null; 14731 error(e1.loc, "need `this` of type `%s` to access member `%s` from static function `%s`", ad.toChars(), var.toChars(), f.toChars()); 14732 e1 = ErrorExp.get(); 14733 return e1; 14734 } 14735 s = s.toParent2(); 14736 } 14737 if (n > 1 || e1.op == EXP.index) 14738 e1 = e1.expressionSemantic(sc); 14739 if (s && e1.type.equivalent(Type.tvoidptr)) 14740 { 14741 if (auto sad = s.isAggregateDeclaration()) 14742 { 14743 Type ta = sad.handleType(); 14744 if (ta.ty == Tstruct) 14745 ta = ta.pointerTo(); 14746 e1.type = ta; 14747 } 14748 } 14749 e1.type = e1.type.addMod(t.mod); 14750 return e1; 14751 } 14752 14753 /******************************* 14754 * Make a dual-context container for use as a `this` argument. 14755 * Params: 14756 * loc = location to use for error messages 14757 * sc = current scope 14758 * fd = target function that will take the `this` argument 14759 * Returns: 14760 * Temporary closure variable. 14761 * Note: 14762 * The function `fd` is added to the nested references of the 14763 * newly created variable such that a closure is made for the variable when 14764 * the address of `fd` is taken. 14765 */ 14766 VarDeclaration makeThis2Argument(const ref Loc loc, Scope* sc, FuncDeclaration fd) 14767 { 14768 Type tthis2 = Type.tvoidptr.sarrayOf(2); 14769 VarDeclaration vthis2 = new VarDeclaration(loc, tthis2, Identifier.generateId("__this"), null); 14770 vthis2.storage_class |= STC.temp; 14771 vthis2.dsymbolSemantic(sc); 14772 vthis2.parent = sc.parent; 14773 // make it a closure var 14774 assert(sc.func); 14775 sc.func.closureVars.push(vthis2); 14776 // add `fd` to the nested refs 14777 vthis2.nestedrefs.push(fd); 14778 return vthis2; 14779 } 14780 14781 /******************************* 14782 * Make sure that the runtime hook `id` exists. 14783 * Params: 14784 * loc = location to use for error messages 14785 * sc = current scope 14786 * id = the hook identifier 14787 * description = what the hook does 14788 * module_ = what module the hook is located in 14789 * Returns: 14790 * a `bool` indicating if the hook is present. 14791 */ 14792 bool verifyHookExist(const ref Loc loc, ref Scope sc, Identifier id, string description, Identifier module_ = Id.object) 14793 { 14794 auto rootSymbol = sc.search(loc, Id.empty, null); 14795 if (auto moduleSymbol = rootSymbol.search(loc, module_)) 14796 if (moduleSymbol.search(loc, id)) 14797 return true; 14798 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); 14799 return false; 14800 } 14801 14802 /*************************************** 14803 * Fit elements[] to the corresponding types of the `sd`'s fields. 14804 * 14805 * Params: 14806 * sd = the struct declaration 14807 * loc = location to use for error messages 14808 * sc = context 14809 * elements = explicit arguments used to construct object 14810 * stype = the constructed object type. 14811 * Returns: 14812 * false if any errors occur, 14813 * otherwise true and elements[] are rewritten for the output. 14814 */ 14815 private bool fit(StructDeclaration sd, const ref Loc loc, Scope* sc, Expressions* elements, Type stype) 14816 { 14817 if (!elements) 14818 return true; 14819 14820 const nfields = sd.nonHiddenFields(); 14821 size_t offset = 0; 14822 for (size_t i = 0; i < elements.length; i++) 14823 { 14824 Expression e = (*elements)[i]; 14825 if (!e) 14826 continue; 14827 14828 e = resolveProperties(sc, e); 14829 if (i >= nfields) 14830 { 14831 if (i < sd.fields.length && e.op == EXP.null_) 14832 { 14833 // CTFE sometimes creates null as hidden pointer; we'll allow this. 14834 continue; 14835 } 14836 .error(loc, "more initializers than fields (%llu) of `%s`", cast(ulong)nfields, sd.toChars()); 14837 return false; 14838 } 14839 VarDeclaration v = sd.fields[i]; 14840 if (v.offset < offset) 14841 { 14842 .error(loc, "overlapping initialization for `%s`", v.toChars()); 14843 if (!sd.isUnionDeclaration()) 14844 { 14845 enum errorMsg = "`struct` initializers that contain anonymous unions" ~ 14846 " must initialize only the first member of a `union`. All subsequent" ~ 14847 " non-overlapping fields are default initialized"; 14848 .errorSupplemental(loc, errorMsg); 14849 } 14850 return false; 14851 } 14852 const vsize = v.type.size(); 14853 if (vsize == SIZE_INVALID) 14854 return false; 14855 offset = cast(uint)(v.offset + vsize); 14856 14857 Type t = v.type; 14858 if (stype) 14859 t = t.addMod(stype.mod); 14860 Type origType = t; 14861 Type tb = t.toBasetype(); 14862 14863 const hasPointers = tb.hasPointers(); 14864 if (hasPointers) 14865 { 14866 if ((!stype.alignment.isDefault() && stype.alignment.get() < target.ptrsize || 14867 (v.offset & (target.ptrsize - 1))) && 14868 (sc.setUnsafe(false, loc, 14869 "field `%s.%s` cannot assign to misaligned pointers in `@safe` code", sd, v))) 14870 { 14871 return false; 14872 } 14873 } 14874 14875 /* Look for case of initializing a static array with a too-short 14876 * string literal, such as: 14877 * char[5] foo = "abc"; 14878 * Allow this by doing an explicit cast, which will lengthen the string 14879 * literal. 14880 */ 14881 if (e.op == EXP.string_ && tb.ty == Tsarray) 14882 { 14883 StringExp se = cast(StringExp)e; 14884 Type typeb = se.type.toBasetype(); 14885 TY tynto = tb.nextOf().ty; 14886 if (!se.committed && 14887 (typeb.ty == Tarray || typeb.ty == Tsarray) && tynto.isSomeChar && 14888 se.numberOfCodeUnits(tynto) < (cast(TypeSArray)tb).dim.toInteger()) 14889 { 14890 e = se.castTo(sc, t); 14891 goto L1; 14892 } 14893 } 14894 14895 while (!e.implicitConvTo(t) && tb.ty == Tsarray) 14896 { 14897 /* Static array initialization, as in: 14898 * T[3][5] = e; 14899 */ 14900 t = tb.nextOf(); 14901 tb = t.toBasetype(); 14902 } 14903 if (!e.implicitConvTo(t)) 14904 t = origType; // restore type for better diagnostic 14905 14906 e = e.implicitCastTo(sc, t); 14907 L1: 14908 if (e.op == EXP.error) 14909 return false; 14910 14911 (*elements)[i] = doCopyOrMove(sc, e); 14912 } 14913 return true; 14914 } 14915 14916 14917 /** 14918 * Returns `em` as a VariableExp 14919 * Params: 14920 * em = the EnumMember to wrap 14921 * loc = location of use of em 14922 * sc = scope of use of em 14923 * Returns: 14924 * VarExp referenceing `em` or ErrorExp if `em` if disabled/deprecated 14925 */ 14926 Expression getVarExp(EnumMember em, const ref Loc loc, Scope* sc) 14927 { 14928 dsymbolSemantic(em, sc); 14929 if (em.errors) 14930 return ErrorExp.get(); 14931 em.checkDisabled(loc, sc); 14932 14933 if (em.depdecl && !em.depdecl._scope) 14934 em.depdecl._scope = sc; 14935 em.checkDeprecated(loc, sc); 14936 14937 if (em.errors) 14938 return ErrorExp.get(); 14939 Expression e = new VarExp(loc, em); 14940 e = e.expressionSemantic(sc); 14941 if (!(sc.flags & SCOPE.Cfile) && em.isCsymbol()) 14942 { 14943 /* C11 types them as int. But if in D file, 14944 * type qualified names as the enum 14945 */ 14946 e.type = em.parent.isEnumDeclaration().type; 14947 assert(e.type); 14948 } 14949 return e; 14950 } 14951 14952 14953 /***************************** 14954 * Try to treat `exp` as a boolean, 14955 * Params: 14956 * exp = the expression 14957 * sc = scope to evalute `exp` in 14958 * Returns: 14959 * Modified expression on success, ErrorExp on error 14960 */ 14961 Expression toBoolean(Expression exp, Scope* sc) 14962 { 14963 switch(exp.op) 14964 { 14965 case EXP.delete_: 14966 error(exp.loc, "`delete` does not give a boolean result"); 14967 return ErrorExp.get(); 14968 14969 case EXP.comma: 14970 auto ce = exp.isCommaExp(); 14971 auto ex2 = ce.e2.toBoolean(sc); 14972 if (ex2.op == EXP.error) 14973 return ex2; 14974 ce.e2 = ex2; 14975 ce.type = ce.e2.type; 14976 return ce; 14977 14978 case EXP.assign: 14979 case EXP.construct: 14980 case EXP.blit: 14981 case EXP.loweredAssignExp: 14982 if (sc.flags & SCOPE.Cfile) 14983 return exp; 14984 // Things like: 14985 // if (a = b) ... 14986 // are usually mistakes. 14987 error(exp.loc, "assignment cannot be used as a condition, perhaps `==` was meant?"); 14988 return ErrorExp.get(); 14989 14990 //LogicalExp 14991 case EXP.andAnd: 14992 case EXP.orOr: 14993 auto le = exp.isLogicalExp(); 14994 auto ex2 = le.e2.toBoolean(sc); 14995 if (ex2.op == EXP.error) 14996 return ex2; 14997 le.e2 = ex2; 14998 return le; 14999 15000 case EXP.question: 15001 auto ce = exp.isCondExp(); 15002 auto ex1 = ce.e1.toBoolean(sc); 15003 auto ex2 = ce.e2.toBoolean(sc); 15004 if (ex1.op == EXP.error) 15005 return ex1; 15006 if (ex2.op == EXP.error) 15007 return ex2; 15008 ce.e1 = ex1; 15009 ce.e2 = ex2; 15010 return ce; 15011 15012 15013 default: 15014 // Default is 'yes' - do nothing 15015 Expression e = arrayFuncConv(exp, sc); 15016 Type t = e.type; 15017 Type tb = t.toBasetype(); 15018 Type att = null; 15019 15020 while (1) 15021 { 15022 // Structs can be converted to bool using opCast(bool)() 15023 if (auto ts = tb.isTypeStruct()) 15024 { 15025 AggregateDeclaration ad = ts.sym; 15026 /* Don't really need to check for opCast first, but by doing so we 15027 * get better error messages if it isn't there. 15028 */ 15029 if (Dsymbol fd = search_function(ad, Id._cast)) 15030 { 15031 e = new CastExp(exp.loc, e, Type.tbool); 15032 e = e.expressionSemantic(sc); 15033 return e; 15034 } 15035 15036 // Forward to aliasthis. 15037 if (ad.aliasthis && !isRecursiveAliasThis(att, tb)) 15038 { 15039 e = resolveAliasThis(sc, e); 15040 t = e.type; 15041 tb = e.type.toBasetype(); 15042 continue; 15043 } 15044 } 15045 break; 15046 } 15047 15048 if (!t.isBoolean()) 15049 { 15050 if (tb != Type.terror) 15051 error(exp.loc, "expression `%s` of type `%s` does not have a boolean value", 15052 exp.toChars(), t.toChars()); 15053 return ErrorExp.get(); 15054 } 15055 return e; 15056 } 15057 }