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.root.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 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 tempinst.error(tempinst.loc, "error instantiating"); 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.varDecl = vd; 249 scope(exit) sc.varDecl = null; 250 251 if (vd.aliasTuple) // if it's a tuple 252 { 253 vd.aliasTuple.accept(this); 254 vd.semanticRun = PASS.semantic2done; 255 return; 256 } 257 258 UserAttributeDeclaration.checkGNUABITag(vd, vd._linkage); 259 260 if (vd._init && !vd.toParent().isFuncDeclaration()) 261 { 262 vd.inuse++; 263 264 /* https://issues.dlang.org/show_bug.cgi?id=20280 265 * 266 * Template instances may import modules that have not 267 * finished semantic1. 268 */ 269 if (!vd.type) 270 vd.dsymbolSemantic(sc); 271 272 273 // https://issues.dlang.org/show_bug.cgi?id=14166 274 // https://issues.dlang.org/show_bug.cgi?id=20417 275 // Don't run CTFE for the temporary variables inside typeof or __traits(compiles) 276 vd._init = vd._init.initializerSemantic(sc, vd.type, sc.intypeof == 1 || sc.flags & SCOPE.compile ? INITnointerpret : INITinterpret); 277 vd.inuse--; 278 } 279 if (vd._init && vd.storage_class & STC.manifest) 280 { 281 /* Cannot initializer enums with CTFE classreferences and addresses of struct literals. 282 * Scan initializer looking for them. Issue error if found. 283 */ 284 if (ExpInitializer ei = vd._init.isExpInitializer()) 285 { 286 static bool hasInvalidEnumInitializer(Expression e) 287 { 288 static bool arrayHasInvalidEnumInitializer(Expressions* elems) 289 { 290 foreach (e; *elems) 291 { 292 if (e && hasInvalidEnumInitializer(e)) 293 return true; 294 } 295 return false; 296 } 297 298 if (e.op == EXP.classReference) 299 return true; 300 if (e.op == EXP.address && (cast(AddrExp)e).e1.op == EXP.structLiteral) 301 return true; 302 if (e.op == EXP.arrayLiteral) 303 return arrayHasInvalidEnumInitializer((cast(ArrayLiteralExp)e).elements); 304 if (e.op == EXP.structLiteral) 305 return arrayHasInvalidEnumInitializer((cast(StructLiteralExp)e).elements); 306 if (e.op == EXP.assocArrayLiteral) 307 { 308 AssocArrayLiteralExp ae = cast(AssocArrayLiteralExp)e; 309 return arrayHasInvalidEnumInitializer(ae.values) || 310 arrayHasInvalidEnumInitializer(ae.keys); 311 } 312 return false; 313 } 314 315 if (hasInvalidEnumInitializer(ei.exp)) 316 vd.error(": Unable to initialize enum with class or pointer to struct. Use static const variable instead."); 317 } 318 } 319 else if (vd._init && vd.isThreadlocal()) 320 { 321 // Cannot initialize a thread-local class or pointer to struct variable with a literal 322 // that itself is a thread-local reference and would need dynamic initialization also. 323 if ((vd.type.ty == Tclass) && vd.type.isMutable() && !vd.type.isShared()) 324 { 325 ExpInitializer ei = vd._init.isExpInitializer(); 326 if (ei && ei.exp.op == EXP.classReference) 327 vd.error("is a thread-local class and cannot have a static initializer. Use `static this()` to initialize instead."); 328 } 329 else if (vd.type.ty == Tpointer && vd.type.nextOf().ty == Tstruct && vd.type.nextOf().isMutable() && !vd.type.nextOf().isShared()) 330 { 331 ExpInitializer ei = vd._init.isExpInitializer(); 332 if (ei && ei.exp.op == EXP.address && (cast(AddrExp)ei.exp).e1.op == EXP.structLiteral) 333 vd.error("is a thread-local pointer to struct and cannot have a static initializer. Use `static this()` to initialize instead."); 334 } 335 } 336 vd.semanticRun = PASS.semantic2done; 337 } 338 339 override void visit(Module mod) 340 { 341 //printf("Module::semantic2('%s'): parent = %p\n", toChars(), parent); 342 if (mod.semanticRun != PASS.semanticdone) // semantic() not completed yet - could be recursive call 343 return; 344 mod.semanticRun = PASS.semantic2; 345 // Note that modules get their own scope, from scratch. 346 // This is so regardless of where in the syntax a module 347 // gets imported, it is unaffected by context. 348 Scope* sc = Scope.createGlobal(mod); // create root scope 349 //printf("Module = %p\n", sc.scopesym); 350 if (mod.members) 351 { 352 // Pass 2 semantic routines: do initializers and function bodies 353 for (size_t i = 0; i < mod.members.length; i++) 354 { 355 Dsymbol s = (*mod.members)[i]; 356 s.semantic2(sc); 357 } 358 } 359 if (mod.userAttribDecl) 360 { 361 mod.userAttribDecl.semantic2(sc); 362 } 363 sc = sc.pop(); 364 sc.pop(); 365 mod.semanticRun = PASS.semantic2done; 366 //printf("-Module::semantic2('%s'): parent = %p\n", toChars(), parent); 367 } 368 369 override void visit(FuncDeclaration fd) 370 { 371 if (fd.semanticRun >= PASS.semantic2done) 372 return; 373 374 if (fd.semanticRun < PASS.semanticdone && !fd.errors) 375 { 376 /* https://issues.dlang.org/show_bug.cgi?id=21614 377 * 378 * Template instances may import modules that have not 379 * finished semantic1. 380 */ 381 fd.dsymbolSemantic(sc); 382 } 383 assert(fd.semanticRun <= PASS.semantic2); 384 fd.semanticRun = PASS.semantic2; 385 386 //printf("FuncDeclaration::semantic2 [%s] fd: %s type: %s\n", fd.loc.toChars(), fd.toChars(), fd.type ? fd.type.toChars() : "".ptr); 387 388 // Only check valid functions which have a body to avoid errors 389 // for multiple declarations, e.g. 390 // void foo(); 391 // void foo(); 392 if (fd.fbody && fd.overnext && !fd.errors) 393 { 394 // Always starts the lookup from 'this', because the conflicts with 395 // previous overloads are already reported. 396 alias f1 = fd; 397 auto tf1 = cast(TypeFunction) f1.type; 398 auto parent1 = f1.toParent2(); 399 const linkage1 = f1.resolvedLinkage(); 400 401 overloadApply(f1, (Dsymbol s) 402 { 403 auto f2 = s.isFuncDeclaration(); 404 if (!f2 || f1 == f2 || f2.errors) 405 return 0; 406 407 // Don't have to check conflict between declaration and definition. 408 if (f2.fbody is null) 409 return 0; 410 411 // Functions with different manglings can never conflict 412 if (linkage1 != f2.resolvedLinkage()) 413 return 0; 414 415 // Functions with different names never conflict 416 // (they can form overloads sets introduced by an alias) 417 if (f1.ident != f2.ident) 418 return 0; 419 420 // Functions with different parents never conflict 421 // (E.g. when aliasing a free function into a struct) 422 if (parent1 != f2.toParent2()) 423 return 0; 424 425 /* Check for overload merging with base class member functions. 426 * 427 * class B { void foo() {} } 428 * class D : B { 429 * override void foo() {} // B.foo appears as f2 430 * alias foo = B.foo; 431 * } 432 */ 433 if (f1.overrides(f2)) 434 return 0; 435 436 auto tf2 = cast(TypeFunction) f2.type; 437 438 // Overloading based on storage classes 439 if (tf1.mod != tf2.mod || ((f1.storage_class ^ f2.storage_class) & STC.static_)) 440 return 0; 441 442 // @@@DEPRECATED_2.112@@@ 443 // This test doesn't catch identical functions that differ only 444 // in explicit/implicit `@system` - a deprecation has now been 445 // added below, remove `false` after deprecation period is over. 446 const sameAttr = tf1.attributesEqual(tf2, false); 447 const sameParams = tf1.parameterList == tf2.parameterList; 448 449 // Allow the hack to declare overloads with different parameters/STC's 450 // @@@DEPRECATED_2.104@@@ 451 // Deprecated in 2020-08, make this an error in 2.104 452 if (parent1.isModule() && 453 linkage1 != LINK.d && linkage1 != LINK.cpp && 454 (!sameAttr || !sameParams) 455 ) 456 { 457 f2.deprecation("cannot overload `extern(%s)` function at %s", 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 f2.deprecation("cannot overload `extern(%s)` function at %s", 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 ad.error("has forward references"); 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 // first entry is ClassInfo reference 663 auto methods = base.sym.vtbl[base.sym.vtblOffset .. $]; 664 665 foreach (m; methods) 666 { 667 auto ifd = m.isFuncDeclaration; 668 assert(ifd); 669 670 if (ifd.objc.isOptional) 671 continue; 672 673 auto type = ifd.type.toTypeFunction(); 674 auto fd = cd.findFunc(ifd.ident, type); 675 676 if (fd && !fd.isAbstract) 677 { 678 //printf(" found\n"); 679 // Check that calling conventions match 680 if (fd._linkage != ifd._linkage) 681 fd.error("linkage doesn't match interface function"); 682 683 // Check that it is current 684 //printf("newinstance = %d fd.toParent() = %s ifd.toParent() = %s\n", 685 //newinstance, fd.toParent().toChars(), ifd.toParent().toChars()); 686 if (fd.toParent() != cd && ifd.toParent() == base.sym) 687 cd.error("interface function `%s` is not implemented", ifd.toFullSignature()); 688 } 689 else 690 { 691 //printf(" not found %p\n", fd); 692 // BUG: should mark this class as abstract? 693 if (!cd.isAbstract()) 694 cd.error("interface function `%s` is not implemented", ifd.toFullSignature()); 695 } 696 } 697 } 698 } 699 700 if (cd.semanticRun >= PASS.semantic2done) 701 return; 702 assert(cd.semanticRun <= PASS.semantic2); 703 cd.semanticRun = PASS.semantic2; 704 705 checkInterfaceImplementations(cd); 706 visit(cast(AggregateDeclaration) cd); 707 } 708 709 override void visit(InterfaceDeclaration cd) 710 { 711 visit(cast(AggregateDeclaration) cd); 712 } 713 714 override void visit(TupleDeclaration td) 715 { 716 td.foreachVar((s) { s.accept(this); }); 717 } 718 } 719 720 /** 721 * Perform semantic analysis specific to the GNU ABI tags 722 * 723 * The GNU ABI tags are a feature introduced in C++11, specific to g++ 724 * and the Itanium ABI. 725 * They are mandatory for C++ interfacing, simply because the templated struct 726 *`std::basic_string`, of which the ubiquitous `std::string` is a instantiation 727 * of, uses them. 728 * 729 * Params: 730 * e = Expression to perform semantic on 731 * See `Semantic2Visitor.visit(UserAttributeDeclaration)` 732 * lastTag = When `!is null`, we already saw an ABI tag. 733 * To simplify implementation and reflection code, 734 * only one ABI tag object is allowed per symbol 735 * (but it can have multiple tags as it's an array exp). 736 */ 737 private void doGNUABITagSemantic(ref Expression e, ref Expression* lastTag) 738 { 739 import dmd.dmangle; 740 741 // When `@gnuAbiTag` is used, the type will be the UDA, not the struct literal 742 if (e.op == EXP.type) 743 { 744 e.error("`@%s` at least one argument expected", Id.udaGNUAbiTag.toChars()); 745 return; 746 } 747 748 // Definition is in `core.attributes`. If it's not a struct literal, 749 // it shouldn't have passed semantic, hence the `assert`. 750 auto sle = e.isStructLiteralExp(); 751 if (sle is null) 752 { 753 assert(global.errors); 754 return; 755 } 756 // The definition of `gnuAttributes` only have 1 member, `string[] tags` 757 assert(sle.elements && sle.elements.length == 1); 758 // `gnuAbiTag`'s constructor is defined as `this(string[] tags...)` 759 auto ale = (*sle.elements)[0].isArrayLiteralExp(); 760 if (ale is null) 761 { 762 e.error("`@%s` at least one argument expected", Id.udaGNUAbiTag.toChars()); 763 return; 764 } 765 766 // Check that it's the only tag on the symbol 767 if (lastTag !is null) 768 { 769 const str1 = (*lastTag.isStructLiteralExp().elements)[0].toString(); 770 const str2 = ale.toString(); 771 e.error("only one `@%s` allowed per symbol", Id.udaGNUAbiTag.toChars()); 772 e.errorSupplemental("instead of `@%s @%s`, use `@%s(%.*s, %.*s)`", 773 lastTag.toChars(), e.toChars(), Id.udaGNUAbiTag.toChars(), 774 // Avoid [ ... ] 775 cast(int)str1.length - 2, str1.ptr + 1, 776 cast(int)str2.length - 2, str2.ptr + 1); 777 return; 778 } 779 lastTag = &e; 780 781 // We already know we have a valid array literal of strings. 782 // Now checks that elements are valid. 783 foreach (idx, elem; *ale.elements) 784 { 785 const str = elem.toStringExp().peekString(); 786 if (!str.length) 787 { 788 e.error("argument `%d` to `@%s` cannot be %s", cast(int)(idx + 1), 789 Id.udaGNUAbiTag.toChars(), 790 elem.isNullExp() ? "`null`".ptr : "empty".ptr); 791 continue; 792 } 793 794 foreach (c; str) 795 { 796 if (!c.isValidMangling()) 797 { 798 e.error("`@%s` char `0x%02x` not allowed in mangling", 799 Id.udaGNUAbiTag.toChars(), c); 800 break; 801 } 802 } 803 // Valid element 804 } 805 // Since ABI tags need to be sorted, we sort them in place 806 // It might be surprising for users that inspects the UDAs, 807 // but it's a concession to practicality. 808 // Casts are unfortunately necessary as `implicitConvTo` is not 809 // `const` (and nor is `StringExp`, by extension). 810 static int predicate(const scope Expression* e1, const scope Expression* e2) nothrow 811 { 812 scope(failure) assert(0, "An exception was thrown"); 813 return (cast(Expression*)e1).toStringExp().compare((cast(Expression*)e2).toStringExp()); 814 } 815 ale.elements.sort!predicate; 816 }