1 /** 2 * Performs the semantic2 stage, which deals with initializer expressions. 3 * 4 * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved 5 * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) 6 * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 7 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/semantic2.d, _semantic2.d) 8 * Documentation: https://dlang.org/phobos/dmd_semantic2.html 9 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/semantic2.d 10 */ 11 12 module dmd.semantic2; 13 14 import core.stdc.stdio; 15 import core.stdc.string; 16 17 import dmd.aggregate; 18 import dmd.aliasthis; 19 import dmd.arraytypes; 20 import dmd.astcodegen; 21 import dmd.astenums; 22 import dmd.attrib; 23 import dmd.blockexit; 24 import dmd.clone; 25 import dmd.dcast; 26 import dmd.dclass; 27 import dmd.declaration; 28 import dmd.denum; 29 import dmd.dimport; 30 import dmd.dinterpret; 31 import dmd.dmodule; 32 import dmd.dscope; 33 import dmd.dstruct; 34 import dmd.dsymbol; 35 import dmd.dsymbolsem; 36 import dmd.dtemplate; 37 import dmd.dversion; 38 import dmd.errors; 39 import dmd.escape; 40 import dmd.expression; 41 import dmd.expressionsem; 42 import dmd.func; 43 import dmd.globals; 44 import dmd.id; 45 import dmd.identifier; 46 import dmd.init; 47 import dmd.initsem; 48 import dmd.hdrgen; 49 import dmd.mtype; 50 import dmd.nogc; 51 import dmd.nspace; 52 import dmd.objc; 53 import dmd.opover; 54 import dmd.parse; 55 import dmd.root.filename; 56 import dmd.common.outbuffer; 57 import dmd.root.rmem; 58 import dmd.rootobject; 59 import dmd.root.utf; 60 import dmd.sideeffect; 61 import dmd.statementsem; 62 import dmd.staticassert; 63 import dmd.tokens; 64 import dmd.statement; 65 import dmd.target; 66 import dmd.templateparamsem; 67 import dmd.typesem; 68 import dmd.visitor; 69 70 enum LOG = false; 71 72 73 /************************************* 74 * Does semantic analysis on initializers and members of aggregates. 75 */ 76 extern(C++) void semantic2(Dsymbol dsym, Scope* sc) 77 { 78 scope v = new Semantic2Visitor(sc); 79 dsym.accept(v); 80 } 81 82 private extern(C++) final class Semantic2Visitor : Visitor 83 { 84 alias visit = Visitor.visit; 85 Scope* sc; 86 this(Scope* sc) scope @safe 87 { 88 this.sc = sc; 89 } 90 91 override void visit(Dsymbol) {} 92 93 override void visit(StaticAssert sa) 94 { 95 //printf("StaticAssert::semantic2() %s\n", sa.toChars()); 96 auto sds = new ScopeDsymbol(); 97 sc = sc.push(sds); 98 sc.tinst = null; 99 sc.minst = null; 100 101 import dmd.staticcond; 102 bool errors; 103 bool result = evalStaticCondition(sc, sa.exp, sa.exp, errors); 104 sc = sc.pop(); 105 if (errors) 106 { 107 errorSupplemental(sa.loc, "while evaluating: `static assert(%s)`", sa.exp.toChars()); 108 return; 109 } 110 else if (result) 111 return; 112 113 if (sa.msgs) 114 { 115 OutBuffer msgbuf; 116 for (size_t i = 0; i < sa.msgs.length; i++) 117 { 118 Expression e = (*sa.msgs)[i]; 119 sc = sc.startCTFE(); 120 e = e.expressionSemantic(sc); 121 e = resolveProperties(sc, e); 122 sc = sc.endCTFE(); 123 e = ctfeInterpretForPragmaMsg(e); 124 if (e.op == EXP.error) 125 { 126 errorSupplemental(sa.loc, "while evaluating `static assert` argument `%s`", (*sa.msgs)[i].toChars()); 127 return; 128 } 129 StringExp se = e.toStringExp(); 130 if (se) 131 { 132 const slice = se.toUTF8(sc).peekString(); 133 // Hack to keep old formatting to avoid changing error messages everywhere 134 if (sa.msgs.length == 1) 135 msgbuf.printf("\"%.*s\"", cast(int)slice.length, slice.ptr); 136 else 137 msgbuf.printf("%.*s", cast(int)slice.length, slice.ptr); 138 } 139 else 140 msgbuf.printf("%s", e.toChars()); 141 } 142 error(sa.loc, "static assert: %s", msgbuf.extractChars()); 143 } 144 else 145 error(sa.loc, "static assert: `%s` is false", sa.exp.toChars()); 146 if (sc.tinst) 147 sc.tinst.printInstantiationTrace(); 148 if (!global.gag) 149 fatal(); 150 } 151 152 override void visit(TemplateInstance tempinst) 153 { 154 if (tempinst.semanticRun >= PASS.semantic2) 155 return; 156 tempinst.semanticRun = PASS.semantic2; 157 static if (LOG) 158 { 159 printf("+TemplateInstance.semantic2('%s')\n", tempinst.toChars()); 160 scope(exit) printf("-TemplateInstance.semantic2('%s')\n", tempinst.toChars()); 161 } 162 if (tempinst.errors || !tempinst.members) 163 return; 164 165 TemplateDeclaration tempdecl = tempinst.tempdecl.isTemplateDeclaration(); 166 assert(tempdecl); 167 168 sc = tempdecl._scope; 169 assert(sc); 170 sc = sc.push(tempinst.argsym); 171 sc = sc.push(tempinst); 172 sc.tinst = tempinst; 173 sc.minst = tempinst.minst; 174 175 int needGagging = (tempinst.gagged && !global.gag); 176 uint olderrors = global.errors; 177 int oldGaggedErrors = -1; // dead-store to prevent spurious warning 178 if (needGagging) 179 oldGaggedErrors = global.startGagging(); 180 181 for (size_t i = 0; i < tempinst.members.length; i++) 182 { 183 Dsymbol s = (*tempinst.members)[i]; 184 static if (LOG) 185 { 186 printf("\tmember '%s', kind = '%s'\n", s.toChars(), s.kind()); 187 } 188 s.semantic2(sc); 189 if (tempinst.gagged && global.errors != olderrors) 190 break; 191 } 192 193 if (global.errors != olderrors) 194 { 195 if (!tempinst.errors) 196 { 197 if (!tempdecl.literal) 198 .error(tempinst.loc, "%s `%s` error instantiating", tempinst.kind, tempinst.toPrettyChars); 199 if (tempinst.tinst) 200 tempinst.tinst.printInstantiationTrace(); 201 } 202 tempinst.errors = true; 203 } 204 if (needGagging) 205 global.endGagging(oldGaggedErrors); 206 207 sc = sc.pop(); 208 sc.pop(); 209 } 210 211 override void visit(TemplateMixin tmix) 212 { 213 if (tmix.semanticRun >= PASS.semantic2) 214 return; 215 tmix.semanticRun = PASS.semantic2; 216 static if (LOG) 217 { 218 printf("+TemplateMixin.semantic2('%s')\n", tmix.toChars()); 219 scope(exit) printf("-TemplateMixin.semantic2('%s')\n", tmix.toChars()); 220 } 221 if (!tmix.members) 222 return; 223 224 assert(sc); 225 sc = sc.push(tmix.argsym); 226 sc = sc.push(tmix); 227 sc.tinst = tmix; 228 sc.minst = tmix.minst; 229 for (size_t i = 0; i < tmix.members.length; i++) 230 { 231 Dsymbol s = (*tmix.members)[i]; 232 static if (LOG) 233 { 234 printf("\tmember '%s', kind = '%s'\n", s.toChars(), s.kind()); 235 } 236 s.semantic2(sc); 237 } 238 sc = sc.pop(); 239 sc.pop(); 240 } 241 242 override void visit(VarDeclaration vd) 243 { 244 if (vd.semanticRun < PASS.semanticdone && vd.inuse) 245 return; 246 247 //printf("VarDeclaration::semantic2('%s')\n", toChars()); 248 sc = sc.push(); 249 sc.varDecl = vd; 250 scope(exit) sc = sc.pop(); 251 252 if (vd.aliasTuple) // if it's a tuple 253 { 254 vd.aliasTuple.accept(this); 255 vd.semanticRun = PASS.semantic2done; 256 return; 257 } 258 259 UserAttributeDeclaration.checkGNUABITag(vd, vd._linkage); 260 261 if (vd._init && !vd.toParent().isFuncDeclaration()) 262 { 263 vd.inuse++; 264 265 /* https://issues.dlang.org/show_bug.cgi?id=20280 266 * 267 * Template instances may import modules that have not 268 * finished semantic1. 269 */ 270 if (!vd.type) 271 vd.dsymbolSemantic(sc); 272 273 274 // https://issues.dlang.org/show_bug.cgi?id=14166 275 // https://issues.dlang.org/show_bug.cgi?id=20417 276 // Don't run CTFE for the temporary variables inside typeof or __traits(compiles) 277 vd._init = vd._init.initializerSemantic(sc, vd.type, sc.intypeof == 1 || sc.flags & SCOPE.compile ? INITnointerpret : INITinterpret); 278 lowerStaticAAs(vd, sc); 279 vd.inuse--; 280 } 281 if (vd._init && vd.storage_class & STC.manifest) 282 { 283 /* Cannot initializer enums with CTFE classreferences and addresses of struct literals. 284 * Scan initializer looking for them. Issue error if found. 285 */ 286 if (ExpInitializer ei = vd._init.isExpInitializer()) 287 { 288 static bool hasInvalidEnumInitializer(Expression e) 289 { 290 static bool arrayHasInvalidEnumInitializer(Expressions* elems) 291 { 292 foreach (e; *elems) 293 { 294 if (e && hasInvalidEnumInitializer(e)) 295 return true; 296 } 297 return false; 298 } 299 300 if (e.op == EXP.classReference) 301 return true; 302 if (e.op == EXP.address && (cast(AddrExp)e).e1.op == EXP.structLiteral) 303 return true; 304 if (e.op == EXP.arrayLiteral) 305 return arrayHasInvalidEnumInitializer((cast(ArrayLiteralExp)e).elements); 306 if (e.op == EXP.structLiteral) 307 return arrayHasInvalidEnumInitializer((cast(StructLiteralExp)e).elements); 308 if (e.op == EXP.assocArrayLiteral) 309 { 310 AssocArrayLiteralExp ae = cast(AssocArrayLiteralExp)e; 311 return arrayHasInvalidEnumInitializer(ae.values) || 312 arrayHasInvalidEnumInitializer(ae.keys); 313 } 314 return false; 315 } 316 317 if (hasInvalidEnumInitializer(ei.exp)) 318 .error(vd.loc, "%s `%s` : Unable to initialize enum with class or pointer to struct. Use static const variable instead.", vd.kind, vd.toPrettyChars); 319 } 320 } 321 else if (vd._init && vd.isThreadlocal()) 322 { 323 // Cannot initialize a thread-local class or pointer to struct variable with a literal 324 // that itself is a thread-local reference and would need dynamic initialization also. 325 if ((vd.type.ty == Tclass) && vd.type.isMutable() && !vd.type.isShared()) 326 { 327 ExpInitializer ei = vd._init.isExpInitializer(); 328 if (ei && ei.exp.op == EXP.classReference) 329 .error(vd.loc, "%s `%s` is a thread-local class and cannot have a static initializer. Use `static this()` to initialize instead.", vd.kind, vd.toPrettyChars); 330 } 331 else if (vd.type.ty == Tpointer && vd.type.nextOf().ty == Tstruct && vd.type.nextOf().isMutable() && !vd.type.nextOf().isShared()) 332 { 333 ExpInitializer ei = vd._init.isExpInitializer(); 334 if (ei && ei.exp.op == EXP.address && (cast(AddrExp)ei.exp).e1.op == EXP.structLiteral) 335 .error(vd.loc, "%s `%s` is a thread-local pointer to struct and cannot have a static initializer. Use `static this()` to initialize instead.", vd.kind, vd.toPrettyChars); 336 } 337 } 338 vd.semanticRun = PASS.semantic2done; 339 } 340 341 override void visit(Module mod) 342 { 343 //printf("Module::semantic2('%s'): parent = %p\n", toChars(), parent); 344 if (mod.semanticRun != PASS.semanticdone) // semantic() not completed yet - could be recursive call 345 return; 346 mod.semanticRun = PASS.semantic2; 347 // Note that modules get their own scope, from scratch. 348 // This is so regardless of where in the syntax a module 349 // gets imported, it is unaffected by context. 350 Scope* sc = Scope.createGlobal(mod, global.errorSink); // create root scope 351 //printf("Module = %p\n", sc.scopesym); 352 if (mod.members) 353 { 354 // Pass 2 semantic routines: do initializers and function bodies 355 for (size_t i = 0; i < mod.members.length; i++) 356 { 357 Dsymbol s = (*mod.members)[i]; 358 s.semantic2(sc); 359 } 360 } 361 if (mod.userAttribDecl) 362 { 363 mod.userAttribDecl.semantic2(sc); 364 } 365 sc = sc.pop(); 366 sc.pop(); 367 mod.semanticRun = PASS.semantic2done; 368 //printf("-Module::semantic2('%s'): parent = %p\n", toChars(), parent); 369 } 370 371 override void visit(FuncDeclaration fd) 372 { 373 if (fd.semanticRun >= PASS.semantic2done) 374 return; 375 376 if (fd.semanticRun < PASS.semanticdone && !fd.errors) 377 { 378 /* https://issues.dlang.org/show_bug.cgi?id=21614 379 * 380 * Template instances may import modules that have not 381 * finished semantic1. 382 */ 383 fd.dsymbolSemantic(sc); 384 } 385 assert(fd.semanticRun <= PASS.semantic2); 386 fd.semanticRun = PASS.semantic2; 387 388 //printf("FuncDeclaration::semantic2 [%s] fd: %s type: %s\n", fd.loc.toChars(), fd.toChars(), fd.type ? fd.type.toChars() : "".ptr); 389 390 // Only check valid functions which have a body to avoid errors 391 // for multiple declarations, e.g. 392 // void foo(); 393 // void foo(); 394 if (fd.fbody && fd.overnext && !fd.errors) 395 { 396 // Always starts the lookup from 'this', because the conflicts with 397 // previous overloads are already reported. 398 alias f1 = fd; 399 auto tf1 = cast(TypeFunction) f1.type; 400 auto parent1 = f1.toParent2(); 401 const linkage1 = f1.resolvedLinkage(); 402 403 overloadApply(f1, (Dsymbol s) 404 { 405 auto f2 = s.isFuncDeclaration(); 406 if (!f2 || f1 == f2 || f2.errors) 407 return 0; 408 409 // Don't have to check conflict between declaration and definition. 410 if (f2.fbody is null) 411 return 0; 412 413 // Functions with different manglings can never conflict 414 if (linkage1 != f2.resolvedLinkage()) 415 return 0; 416 417 // Functions with different names never conflict 418 // (they can form overloads sets introduced by an alias) 419 if (f1.ident != f2.ident) 420 return 0; 421 422 // Functions with different parents never conflict 423 // (E.g. when aliasing a free function into a struct) 424 if (parent1 != f2.toParent2()) 425 return 0; 426 427 /* Check for overload merging with base class member functions. 428 * 429 * class B { void foo() {} } 430 * class D : B { 431 * override void foo() {} // B.foo appears as f2 432 * alias foo = B.foo; 433 * } 434 */ 435 if (f1.overrides(f2)) 436 return 0; 437 438 auto tf2 = cast(TypeFunction) f2.type; 439 440 // Overloading based on storage classes 441 if (tf1.mod != tf2.mod || ((f1.storage_class ^ f2.storage_class) & STC.static_)) 442 return 0; 443 444 // @@@DEPRECATED_2.112@@@ 445 // This test doesn't catch identical functions that differ only 446 // in explicit/implicit `@system` - a deprecation has now been 447 // added below, remove `false` after deprecation period is over. 448 const sameAttr = tf1.attributesEqual(tf2, false); 449 const sameParams = tf1.parameterList == tf2.parameterList; 450 451 // Allow the hack to declare overloads with different parameters/STC's 452 if (parent1.isModule() && 453 linkage1 != LINK.d && linkage1 != LINK.cpp && 454 (!sameAttr || !sameParams) 455 ) 456 { 457 .error(f2.loc, "%s `%s` cannot overload `extern(%s)` function at %s", f2.kind, f2.toPrettyChars, 458 linkageToChars(f1._linkage), 459 f1.loc.toChars()); 460 return 0; 461 } 462 463 // Different parameters don't conflict in extern(C++/D) 464 if (!sameParams) 465 return 0; 466 467 // Different attributes don't conflict in extern(D) 468 if (!sameAttr && linkage1 == LINK.d) 469 { 470 // @@@DEPRECATED_2.112@@@ 471 // Same as 2.104 deprecation, but also catching explicit/implicit `@system` 472 // At the end of deprecation period, fix Type.attributesEqual and remove 473 // this condition, as well as the error for extern(C) functions above. 474 if (sameAttr != tf1.attributesEqual(tf2)) 475 { 476 .deprecation(f2.loc, "%s `%s` cannot overload `extern(%s)` function at %s", f2.kind, f2.toPrettyChars, 477 linkageToChars(f1._linkage), 478 f1.loc.toChars()); 479 } 480 return 0; 481 } 482 483 .error(f2.loc, "%s `%s%s` conflicts with previous declaration at %s", 484 f2.kind(), 485 f2.toPrettyChars(), 486 parametersTypeToChars(tf2.parameterList), 487 f1.loc.toChars()); 488 f2.type = Type.terror; 489 f2.errors = true; 490 return 0; 491 }); 492 } 493 if (!fd.type || fd.type.ty != Tfunction) 494 return; 495 TypeFunction f = cast(TypeFunction) fd.type; 496 497 UserAttributeDeclaration.checkGNUABITag(fd, fd._linkage); 498 //semantic for parameters' UDAs 499 foreach (i, param; f.parameterList) 500 { 501 if (param && param.userAttribDecl) 502 param.userAttribDecl.semantic2(sc); 503 } 504 } 505 506 override void visit(Import i) 507 { 508 //printf("Import::semantic2('%s')\n", toChars()); 509 if (!i.mod) 510 return; 511 512 i.mod.semantic2(null); 513 if (i.mod.needmoduleinfo) 514 { 515 //printf("module5 %s because of %s\n", sc._module.toChars(), mod.toChars()); 516 if (sc) 517 sc._module.needmoduleinfo = 1; 518 } 519 } 520 521 override void visit(Nspace ns) 522 { 523 if (ns.semanticRun >= PASS.semantic2) 524 return; 525 ns.semanticRun = PASS.semantic2; 526 static if (LOG) 527 { 528 printf("+Nspace::semantic2('%s')\n", ns.toChars()); 529 scope(exit) printf("-Nspace::semantic2('%s')\n", ns.toChars()); 530 } 531 UserAttributeDeclaration.checkGNUABITag(ns, LINK.cpp); 532 if (!ns.members) 533 return; 534 535 assert(sc); 536 sc = sc.push(ns); 537 sc.linkage = LINK.cpp; 538 foreach (s; *ns.members) 539 { 540 static if (LOG) 541 { 542 printf("\tmember '%s', kind = '%s'\n", s.toChars(), s.kind()); 543 } 544 s.semantic2(sc); 545 } 546 sc.pop(); 547 } 548 549 override void visit(AttribDeclaration ad) 550 { 551 Dsymbols* d = ad.include(sc); 552 if (!d) 553 return; 554 555 Scope* sc2 = ad.newScope(sc); 556 for (size_t i = 0; i < d.length; i++) 557 { 558 Dsymbol s = (*d)[i]; 559 s.semantic2(sc2); 560 } 561 if (sc2 != sc) 562 sc2.pop(); 563 } 564 565 /** 566 * Run the DeprecatedDeclaration's semantic2 phase then its members. 567 * 568 * The message set via a `DeprecatedDeclaration` can be either of: 569 * - a string literal 570 * - an enum 571 * - a static immutable 572 * So we need to call ctfe to resolve it. 573 * Afterward forwards to the members' semantic2. 574 */ 575 override void visit(DeprecatedDeclaration dd) 576 { 577 getMessage(dd); 578 visit(cast(AttribDeclaration)dd); 579 } 580 581 override void visit(AlignDeclaration ad) 582 { 583 ad.getAlignment(sc); 584 visit(cast(AttribDeclaration)ad); 585 } 586 587 override void visit(CPPNamespaceDeclaration decl) 588 { 589 UserAttributeDeclaration.checkGNUABITag(decl, LINK.cpp); 590 visit(cast(AttribDeclaration)decl); 591 } 592 593 override void visit(UserAttributeDeclaration uad) 594 { 595 if (!uad.decl || !uad.atts || !uad.atts.length || !uad._scope) 596 return visit(cast(AttribDeclaration)uad); 597 598 Expression* lastTag; 599 static void eval(Scope* sc, Expressions* exps, ref Expression* lastTag) 600 { 601 foreach (ref Expression e; *exps) 602 { 603 if (!e) 604 continue; 605 606 e = e.expressionSemantic(sc); 607 if (definitelyValueParameter(e)) 608 e = e.ctfeInterpret(); 609 if (e.op == EXP.tuple) 610 { 611 TupleExp te = cast(TupleExp)e; 612 eval(sc, te.exps, lastTag); 613 } 614 615 // Handles compiler-recognized `core.attribute.gnuAbiTag` 616 if (UserAttributeDeclaration.isGNUABITag(e)) 617 doGNUABITagSemantic(e, lastTag); 618 } 619 } 620 621 uad._scope = null; 622 eval(sc, uad.atts, lastTag); 623 visit(cast(AttribDeclaration)uad); 624 } 625 626 override void visit(AggregateDeclaration ad) 627 { 628 //printf("AggregateDeclaration::semantic2(%s) type = %s, errors = %d\n", ad.toChars(), ad.type.toChars(), ad.errors); 629 if (!ad.members) 630 return; 631 632 if (ad._scope) 633 { 634 .error(ad.loc, "%s `%s` has forward references", ad.kind, ad.toPrettyChars); 635 return; 636 } 637 638 UserAttributeDeclaration.checkGNUABITag( 639 ad, ad.classKind == ClassKind.cpp ? LINK.cpp : LINK.d); 640 641 auto sc2 = ad.newScope(sc); 642 643 ad.determineSize(ad.loc); 644 645 for (size_t i = 0; i < ad.members.length; i++) 646 { 647 Dsymbol s = (*ad.members)[i]; 648 //printf("\t[%d] %s\n", i, s.toChars()); 649 s.semantic2(sc2); 650 } 651 652 sc2.pop(); 653 } 654 655 override void visit(ClassDeclaration cd) 656 { 657 /// Checks that the given class implements all methods of its interfaces. 658 static void checkInterfaceImplementations(ClassDeclaration cd) 659 { 660 foreach (base; cd.interfaces) 661 { 662 // https://issues.dlang.org/show_bug.cgi?id=22729 663 // interfaces that have errors or that 664 // inherit from interfaces that have errors 665 // might have an uninitialized vtable 666 if (!base.sym.vtbl.length) 667 continue; 668 669 // first entry is ClassInfo reference 670 auto methods = base.sym.vtbl[base.sym.vtblOffset .. $]; 671 672 foreach (m; methods) 673 { 674 auto ifd = m.isFuncDeclaration; 675 assert(ifd); 676 677 if (ifd.objc.isOptional) 678 continue; 679 680 auto type = ifd.type.toTypeFunction(); 681 auto fd = cd.findFunc(ifd.ident, type); 682 683 if (fd && !fd.isAbstract) 684 { 685 //printf(" found\n"); 686 // Check that calling conventions match 687 if (fd._linkage != ifd._linkage) 688 .error(fd.loc, "%s `%s` linkage doesn't match interface function", fd.kind, fd.toPrettyChars); 689 690 // Check that it is current 691 //printf("newinstance = %d fd.toParent() = %s ifd.toParent() = %s\n", 692 //newinstance, fd.toParent().toChars(), ifd.toParent().toChars()); 693 if (fd.toParent() != cd && ifd.toParent() == base.sym) 694 .error(cd.loc, "%s `%s` interface function `%s` is not implemented", cd.kind, cd.toPrettyChars, ifd.toFullSignature()); 695 } 696 else 697 { 698 //printf(" not found %p\n", fd); 699 // BUG: should mark this class as abstract? 700 if (!cd.isAbstract()) 701 .error(cd.loc, "%s `%s` interface function `%s` is not implemented", cd.kind, cd.toPrettyChars, ifd.toFullSignature()); 702 } 703 } 704 } 705 } 706 707 if (cd.semanticRun >= PASS.semantic2done) 708 return; 709 assert(cd.semanticRun <= PASS.semantic2); 710 cd.semanticRun = PASS.semantic2; 711 712 checkInterfaceImplementations(cd); 713 visit(cast(AggregateDeclaration) cd); 714 } 715 716 override void visit(InterfaceDeclaration cd) 717 { 718 visit(cast(AggregateDeclaration) cd); 719 } 720 721 override void visit(TupleDeclaration td) 722 { 723 td.foreachVar((s) { s.accept(this); }); 724 } 725 } 726 727 /** 728 * Perform semantic analysis specific to the GNU ABI tags 729 * 730 * The GNU ABI tags are a feature introduced in C++11, specific to g++ 731 * and the Itanium ABI. 732 * They are mandatory for C++ interfacing, simply because the templated struct 733 *`std::basic_string`, of which the ubiquitous `std::string` is a instantiation 734 * of, uses them. 735 * 736 * Params: 737 * e = Expression to perform semantic on 738 * See `Semantic2Visitor.visit(UserAttributeDeclaration)` 739 * lastTag = When `!is null`, we already saw an ABI tag. 740 * To simplify implementation and reflection code, 741 * only one ABI tag object is allowed per symbol 742 * (but it can have multiple tags as it's an array exp). 743 */ 744 private void doGNUABITagSemantic(ref Expression e, ref Expression* lastTag) 745 { 746 import dmd.dmangle; 747 748 // When `@gnuAbiTag` is used, the type will be the UDA, not the struct literal 749 if (e.op == EXP.type) 750 { 751 error(e.loc, "`@%s` at least one argument expected", Id.udaGNUAbiTag.toChars()); 752 return; 753 } 754 755 // Definition is in `core.attributes`. If it's not a struct literal, 756 // it shouldn't have passed semantic, hence the `assert`. 757 auto sle = e.isStructLiteralExp(); 758 if (sle is null) 759 { 760 assert(global.errors); 761 return; 762 } 763 // The definition of `gnuAttributes` only have 1 member, `string[] tags` 764 assert(sle.elements && sle.elements.length == 1); 765 // `gnuAbiTag`'s constructor is defined as `this(string[] tags...)` 766 auto ale = (*sle.elements)[0].isArrayLiteralExp(); 767 if (ale is null) 768 { 769 error(e.loc, "`@%s` at least one argument expected", Id.udaGNUAbiTag.toChars()); 770 return; 771 } 772 773 // Check that it's the only tag on the symbol 774 if (lastTag !is null) 775 { 776 const str1 = (*lastTag.isStructLiteralExp().elements)[0].toString(); 777 const str2 = ale.toString(); 778 error(e.loc, "only one `@%s` allowed per symbol", Id.udaGNUAbiTag.toChars()); 779 errorSupplemental(e.loc, "instead of `@%s @%s`, use `@%s(%.*s, %.*s)`", 780 lastTag.toChars(), e.toChars(), Id.udaGNUAbiTag.toChars(), 781 // Avoid [ ... ] 782 cast(int)str1.length - 2, str1.ptr + 1, 783 cast(int)str2.length - 2, str2.ptr + 1); 784 return; 785 } 786 lastTag = &e; 787 788 // We already know we have a valid array literal of strings. 789 // Now checks that elements are valid. 790 foreach (idx, elem; *ale.elements) 791 { 792 const str = elem.toStringExp().peekString(); 793 if (!str.length) 794 { 795 error(e.loc, "argument `%d` to `@%s` cannot be %s", cast(int)(idx + 1), 796 Id.udaGNUAbiTag.toChars(), 797 elem.isNullExp() ? "`null`".ptr : "empty".ptr); 798 continue; 799 } 800 801 foreach (c; str) 802 { 803 if (!c.isValidMangling()) 804 { 805 error(e.loc, "`@%s` char `0x%02x` not allowed in mangling", 806 Id.udaGNUAbiTag.toChars(), c); 807 break; 808 } 809 } 810 // Valid element 811 } 812 // Since ABI tags need to be sorted, we sort them in place 813 // It might be surprising for users that inspects the UDAs, 814 // but it's a concession to practicality. 815 // Casts are unfortunately necessary as `implicitConvTo` is not 816 // `const` (and nor is `StringExp`, by extension). 817 static int predicate(const scope Expression* e1, const scope Expression* e2) 818 { 819 return (cast(Expression*)e1).toStringExp().compare((cast(Expression*)e2).toStringExp()); 820 } 821 ale.elements.sort!predicate; 822 } 823 824 /** 825 * Try lower a variable's static Associative Array to a newaa struct. 826 * Params: 827 * vd = Variable to lower 828 * sc = Scope 829 */ 830 void lowerStaticAAs(VarDeclaration vd, Scope* sc) 831 { 832 if (vd.storage_class & STC.manifest) 833 return; 834 if (auto ei = vd._init.isExpInitializer()) 835 { 836 scope v = new StaticAAVisitor(sc); 837 v.vd = vd; 838 ei.exp.accept(v); 839 } 840 } 841 842 /// Visit Associative Array literals and lower them to structs for static initialization 843 private extern(C++) final class StaticAAVisitor : SemanticTimeTransitiveVisitor 844 { 845 alias visit = SemanticTimeTransitiveVisitor.visit; 846 Scope* sc; 847 VarDeclaration vd; 848 849 this(Scope* sc) scope @safe 850 { 851 this.sc = sc; 852 } 853 854 override void visit(AssocArrayLiteralExp aaExp) 855 { 856 if (!verifyHookExist(aaExp.loc, *sc, Id._aaAsStruct, "initializing static associative arrays", Id.object)) 857 return; 858 859 Expression hookFunc = new IdentifierExp(aaExp.loc, Id.empty); 860 hookFunc = new DotIdExp(aaExp.loc, hookFunc, Id.object); 861 hookFunc = new DotIdExp(aaExp.loc, hookFunc, Id._aaAsStruct); 862 auto arguments = new Expressions(); 863 arguments.push(aaExp.syntaxCopy()); 864 Expression loweredExp = new CallExp(aaExp.loc, hookFunc, arguments); 865 866 sc = sc.startCTFE(); 867 loweredExp = loweredExp.expressionSemantic(sc); 868 loweredExp = resolveProperties(sc, loweredExp); 869 sc = sc.endCTFE(); 870 loweredExp = loweredExp.ctfeInterpret(); 871 872 aaExp.lowering = loweredExp; 873 } 874 }