xref: /netbsd-src/external/gpl3/gcc/dist/gcc/d/dmd/semantic2.d (revision 0a3071956a3a9fdebdbf7f338cf2d439b45fc728)
1 /**
2  * Performs the semantic2 stage, which deals with initializer expressions.
3  *
4  * Copyright:   Copyright (C) 1999-2022 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  */
semantic2(Dsymbol dsym,Scope * sc)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;
this(Scope * sc)86     this(Scope* sc)
87     {
88         this.sc = sc;
89     }
90 
visit(Dsymbol)91     override void visit(Dsymbol) {}
92 
visit(StaticAssert sa)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.msg)
114         {
115             sc = sc.startCTFE();
116             sa.msg = sa.msg.expressionSemantic(sc);
117             sa.msg = resolveProperties(sc, sa.msg);
118             sc = sc.endCTFE();
119             sa.msg = sa.msg.ctfeInterpret();
120             if (StringExp se = sa.msg.toStringExp())
121             {
122                 // same with pragma(msg)
123                 const slice = se.toUTF8(sc).peekString();
124                 error(sa.loc, "static assert:  \"%.*s\"", cast(int)slice.length, slice.ptr);
125             }
126             else
127                 error(sa.loc, "static assert:  %s", sa.msg.toChars());
128         }
129         else
130             error(sa.loc, "static assert:  `%s` is false", sa.exp.toChars());
131         if (sc.tinst)
132             sc.tinst.printInstantiationTrace();
133         if (!global.gag)
134             fatal();
135     }
136 
visit(TemplateInstance tempinst)137     override void visit(TemplateInstance tempinst)
138     {
139         if (tempinst.semanticRun >= PASS.semantic2)
140             return;
141         tempinst.semanticRun = PASS.semantic2;
142         static if (LOG)
143         {
144             printf("+TemplateInstance.semantic2('%s')\n", tempinst.toChars());
145             scope(exit) printf("-TemplateInstance.semantic2('%s')\n", tempinst.toChars());
146         }
147         if (tempinst.errors || !tempinst.members)
148             return;
149 
150         TemplateDeclaration tempdecl = tempinst.tempdecl.isTemplateDeclaration();
151         assert(tempdecl);
152 
153         sc = tempdecl._scope;
154         assert(sc);
155         sc = sc.push(tempinst.argsym);
156         sc = sc.push(tempinst);
157         sc.tinst = tempinst;
158         sc.minst = tempinst.minst;
159 
160         int needGagging = (tempinst.gagged && !global.gag);
161         uint olderrors = global.errors;
162         int oldGaggedErrors = -1; // dead-store to prevent spurious warning
163         if (needGagging)
164             oldGaggedErrors = global.startGagging();
165 
166         for (size_t i = 0; i < tempinst.members.dim; i++)
167         {
168             Dsymbol s = (*tempinst.members)[i];
169             static if (LOG)
170             {
171                 printf("\tmember '%s', kind = '%s'\n", s.toChars(), s.kind());
172             }
173             s.semantic2(sc);
174             if (tempinst.gagged && global.errors != olderrors)
175                 break;
176         }
177 
178         if (global.errors != olderrors)
179         {
180             if (!tempinst.errors)
181             {
182                 if (!tempdecl.literal)
183                     tempinst.error(tempinst.loc, "error instantiating");
184                 if (tempinst.tinst)
185                     tempinst.tinst.printInstantiationTrace();
186             }
187             tempinst.errors = true;
188         }
189         if (needGagging)
190             global.endGagging(oldGaggedErrors);
191 
192         sc = sc.pop();
193         sc.pop();
194     }
195 
visit(TemplateMixin tmix)196     override void visit(TemplateMixin tmix)
197     {
198         if (tmix.semanticRun >= PASS.semantic2)
199             return;
200         tmix.semanticRun = PASS.semantic2;
201         static if (LOG)
202         {
203             printf("+TemplateMixin.semantic2('%s')\n", tmix.toChars());
204             scope(exit) printf("-TemplateMixin.semantic2('%s')\n", tmix.toChars());
205         }
206         if (!tmix.members)
207             return;
208 
209         assert(sc);
210         sc = sc.push(tmix.argsym);
211         sc = sc.push(tmix);
212         sc.tinst = tmix;
213         sc.minst = tmix.minst;
214         for (size_t i = 0; i < tmix.members.dim; i++)
215         {
216             Dsymbol s = (*tmix.members)[i];
217             static if (LOG)
218             {
219                 printf("\tmember '%s', kind = '%s'\n", s.toChars(), s.kind());
220             }
221             s.semantic2(sc);
222         }
223         sc = sc.pop();
224         sc.pop();
225     }
226 
visit(VarDeclaration vd)227     override void visit(VarDeclaration vd)
228     {
229         if (vd.semanticRun < PASS.semanticdone && vd.inuse)
230             return;
231 
232         //printf("VarDeclaration::semantic2('%s')\n", toChars());
233 
234         if (vd.aliassym)        // if it's a tuple
235         {
236             vd.aliassym.accept(this);
237             vd.semanticRun = PASS.semantic2done;
238             return;
239         }
240 
241         UserAttributeDeclaration.checkGNUABITag(vd, vd._linkage);
242 
243         if (vd._init && !vd.toParent().isFuncDeclaration())
244         {
245             vd.inuse++;
246 
247             /* https://issues.dlang.org/show_bug.cgi?id=20280
248              *
249              * Template instances may import modules that have not
250              * finished semantic1.
251              */
252             if (!vd.type)
253                 vd.dsymbolSemantic(sc);
254 
255 
256             // https://issues.dlang.org/show_bug.cgi?id=14166
257             // https://issues.dlang.org/show_bug.cgi?id=20417
258             // Don't run CTFE for the temporary variables inside typeof or __traits(compiles)
259             vd._init = vd._init.initializerSemantic(sc, vd.type, sc.intypeof == 1 || sc.flags & SCOPE.compile ? INITnointerpret : INITinterpret);
260             vd.inuse--;
261         }
262         if (vd._init && vd.storage_class & STC.manifest)
263         {
264             /* Cannot initializer enums with CTFE classreferences and addresses of struct literals.
265              * Scan initializer looking for them. Issue error if found.
266              */
267             if (ExpInitializer ei = vd._init.isExpInitializer())
268             {
269                 static bool hasInvalidEnumInitializer(Expression e)
270                 {
271                     static bool arrayHasInvalidEnumInitializer(Expressions* elems)
272                     {
273                         foreach (e; *elems)
274                         {
275                             if (e && hasInvalidEnumInitializer(e))
276                                 return true;
277                         }
278                         return false;
279                     }
280 
281                     if (e.op == EXP.classReference)
282                         return true;
283                     if (e.op == EXP.address && (cast(AddrExp)e).e1.op == EXP.structLiteral)
284                         return true;
285                     if (e.op == EXP.arrayLiteral)
286                         return arrayHasInvalidEnumInitializer((cast(ArrayLiteralExp)e).elements);
287                     if (e.op == EXP.structLiteral)
288                         return arrayHasInvalidEnumInitializer((cast(StructLiteralExp)e).elements);
289                     if (e.op == EXP.assocArrayLiteral)
290                     {
291                         AssocArrayLiteralExp ae = cast(AssocArrayLiteralExp)e;
292                         return arrayHasInvalidEnumInitializer(ae.values) ||
293                                arrayHasInvalidEnumInitializer(ae.keys);
294                     }
295                     return false;
296                 }
297 
298                 if (hasInvalidEnumInitializer(ei.exp))
299                     vd.error(": Unable to initialize enum with class or pointer to struct. Use static const variable instead.");
300             }
301         }
302         else if (vd._init && vd.isThreadlocal())
303         {
304             // Cannot initialize a thread-local class or pointer to struct variable with a literal
305             // that itself is a thread-local reference and would need dynamic initialization also.
306             if ((vd.type.ty == Tclass) && vd.type.isMutable() && !vd.type.isShared())
307             {
308                 ExpInitializer ei = vd._init.isExpInitializer();
309                 if (ei && ei.exp.op == EXP.classReference)
310                     vd.error("is a thread-local class and cannot have a static initializer. Use `static this()` to initialize instead.");
311             }
312             else if (vd.type.ty == Tpointer && vd.type.nextOf().ty == Tstruct && vd.type.nextOf().isMutable() && !vd.type.nextOf().isShared())
313             {
314                 ExpInitializer ei = vd._init.isExpInitializer();
315                 if (ei && ei.exp.op == EXP.address && (cast(AddrExp)ei.exp).e1.op == EXP.structLiteral)
316                     vd.error("is a thread-local pointer to struct and cannot have a static initializer. Use `static this()` to initialize instead.");
317             }
318         }
319         vd.semanticRun = PASS.semantic2done;
320     }
321 
visit(Module mod)322     override void visit(Module mod)
323     {
324         //printf("Module::semantic2('%s'): parent = %p\n", toChars(), parent);
325         if (mod.semanticRun != PASS.semanticdone) // semantic() not completed yet - could be recursive call
326             return;
327         mod.semanticRun = PASS.semantic2;
328         // Note that modules get their own scope, from scratch.
329         // This is so regardless of where in the syntax a module
330         // gets imported, it is unaffected by context.
331         Scope* sc = Scope.createGlobal(mod); // create root scope
332         //printf("Module = %p\n", sc.scopesym);
333         if (mod.members)
334         {
335             // Pass 2 semantic routines: do initializers and function bodies
336             for (size_t i = 0; i < mod.members.dim; i++)
337             {
338                 Dsymbol s = (*mod.members)[i];
339                 s.semantic2(sc);
340             }
341         }
342         if (mod.userAttribDecl)
343         {
344             mod.userAttribDecl.semantic2(sc);
345         }
346         sc = sc.pop();
347         sc.pop();
348         mod.semanticRun = PASS.semantic2done;
349         //printf("-Module::semantic2('%s'): parent = %p\n", toChars(), parent);
350     }
351 
visit(FuncDeclaration fd)352     override void visit(FuncDeclaration fd)
353     {
354         if (fd.semanticRun >= PASS.semantic2done)
355             return;
356 
357         if (fd.semanticRun < PASS.semanticdone && !fd.errors)
358         {
359             /* https://issues.dlang.org/show_bug.cgi?id=21614
360              *
361              * Template instances may import modules that have not
362              * finished semantic1.
363              */
364             fd.dsymbolSemantic(sc);
365         }
366         assert(fd.semanticRun <= PASS.semantic2);
367         fd.semanticRun = PASS.semantic2;
368 
369         //printf("FuncDeclaration::semantic2 [%s] fd: %s type: %s\n", fd.loc.toChars(), fd.toChars(), fd.type ? fd.type.toChars() : "".ptr);
370 
371         // Only check valid functions which have a body to avoid errors
372         // for multiple declarations, e.g.
373         // void foo();
374         // void foo();
375         if (fd.fbody && fd.overnext && !fd.errors)
376         {
377             // Always starts the lookup from 'this', because the conflicts with
378             // previous overloads are already reported.
379             alias f1 = fd;
380             auto tf1 = cast(TypeFunction) f1.type;
381             auto parent1 = f1.toParent2();
382             const linkage1 = f1.resolvedLinkage();
383 
384             overloadApply(f1, (Dsymbol s)
385             {
386                 auto f2 = s.isFuncDeclaration();
387                 if (!f2 || f1 == f2 || f2.errors)
388                     return 0;
389 
390                 // Don't have to check conflict between declaration and definition.
391                 if (f2.fbody is null)
392                     return 0;
393 
394                 // Functions with different manglings can never conflict
395                 if (linkage1 != f2.resolvedLinkage())
396                     return 0;
397 
398                 // Functions with different names never conflict
399                 // (they can form overloads sets introduced by an alias)
400                 if (f1.ident != f2.ident)
401                     return 0;
402 
403                 // Functions with different parents never conflict
404                 // (E.g. when aliasing a free function into a struct)
405                 if (parent1 != f2.toParent2())
406                     return 0;
407 
408                 /* Check for overload merging with base class member functions.
409                  *
410                  *  class B { void foo() {} }
411                  *  class D : B {
412                  *    override void foo() {}    // B.foo appears as f2
413                  *    alias foo = B.foo;
414                  *  }
415                  */
416                 if (f1.overrides(f2))
417                     return 0;
418 
419                 auto tf2 = cast(TypeFunction) f2.type;
420 
421                 // Overloading based on storage classes
422                 if (tf1.mod != tf2.mod || ((f1.storage_class ^ f2.storage_class) & STC.static_))
423                     return 0;
424 
425                 const sameAttr = tf1.attributesEqual(tf2);
426                 const sameParams = tf1.parameterList == tf2.parameterList;
427 
428                 // Allow the hack to declare overloads with different parameters/STC's
429                 // @@@DEPRECATED_2.104@@@
430                 // Deprecated in 2020-08, make this an error in 2.104
431                 if (parent1.isModule() &&
432                     linkage1 != LINK.d && linkage1 != LINK.cpp &&
433                     (!sameAttr || !sameParams)
434                 )
435                 {
436                     f2.deprecation("cannot overload `extern(%s)` function at %s",
437                             linkageToChars(f1._linkage),
438                             f1.loc.toChars());
439                     return 0;
440                 }
441 
442                 // Different parameters don't conflict in extern(C++/D)
443                 if (!sameParams)
444                     return 0;
445 
446                 // Different attributes don't conflict in extern(D)
447                 if (!sameAttr && linkage1 == LINK.d)
448                     return 0;
449 
450                 error(f2.loc, "%s `%s%s` conflicts with previous declaration at %s",
451                         f2.kind(),
452                         f2.toPrettyChars(),
453                         parametersTypeToChars(tf2.parameterList),
454                         f1.loc.toChars());
455                 f2.type = Type.terror;
456                 f2.errors = true;
457                 return 0;
458             });
459         }
460         if (!fd.type || fd.type.ty != Tfunction)
461             return;
462         TypeFunction f = cast(TypeFunction) fd.type;
463 
464         UserAttributeDeclaration.checkGNUABITag(fd, fd._linkage);
465         //semantic for parameters' UDAs
466         foreach (i, param; f.parameterList)
467         {
468             if (param && param.userAttribDecl)
469                 param.userAttribDecl.semantic2(sc);
470         }
471     }
472 
visit(Import i)473     override void visit(Import i)
474     {
475         //printf("Import::semantic2('%s')\n", toChars());
476         if (!i.mod)
477             return;
478 
479         i.mod.semantic2(null);
480         if (i.mod.needmoduleinfo)
481         {
482             //printf("module5 %s because of %s\n", sc._module.toChars(), mod.toChars());
483             if (sc)
484                 sc._module.needmoduleinfo = 1;
485         }
486     }
487 
visit(Nspace ns)488     override void visit(Nspace ns)
489     {
490         if (ns.semanticRun >= PASS.semantic2)
491             return;
492         ns.semanticRun = PASS.semantic2;
493         static if (LOG)
494         {
495             printf("+Nspace::semantic2('%s')\n", ns.toChars());
496             scope(exit) printf("-Nspace::semantic2('%s')\n", ns.toChars());
497         }
498         UserAttributeDeclaration.checkGNUABITag(ns, LINK.cpp);
499         if (!ns.members)
500             return;
501 
502         assert(sc);
503         sc = sc.push(ns);
504         sc.linkage = LINK.cpp;
505         foreach (s; *ns.members)
506         {
507             static if (LOG)
508             {
509                 printf("\tmember '%s', kind = '%s'\n", s.toChars(), s.kind());
510             }
511             s.semantic2(sc);
512         }
513         sc.pop();
514     }
515 
visit(AttribDeclaration ad)516     override void visit(AttribDeclaration ad)
517     {
518         Dsymbols* d = ad.include(sc);
519         if (!d)
520             return;
521 
522         Scope* sc2 = ad.newScope(sc);
523         for (size_t i = 0; i < d.dim; i++)
524         {
525             Dsymbol s = (*d)[i];
526             s.semantic2(sc2);
527         }
528         if (sc2 != sc)
529             sc2.pop();
530     }
531 
532     /**
533      * Run the DeprecatedDeclaration's semantic2 phase then its members.
534      *
535      * The message set via a `DeprecatedDeclaration` can be either of:
536      * - a string literal
537      * - an enum
538      * - a static immutable
539      * So we need to call ctfe to resolve it.
540      * Afterward forwards to the members' semantic2.
541      */
visit(DeprecatedDeclaration dd)542     override void visit(DeprecatedDeclaration dd)
543     {
544         getMessage(dd);
545         visit(cast(AttribDeclaration)dd);
546     }
547 
visit(AlignDeclaration ad)548     override void visit(AlignDeclaration ad)
549     {
550         ad.getAlignment(sc);
551         visit(cast(AttribDeclaration)ad);
552     }
553 
visit(CPPNamespaceDeclaration decl)554     override void visit(CPPNamespaceDeclaration decl)
555     {
556         UserAttributeDeclaration.checkGNUABITag(decl, LINK.cpp);
557         visit(cast(AttribDeclaration)decl);
558     }
559 
visit(UserAttributeDeclaration uad)560     override void visit(UserAttributeDeclaration uad)
561     {
562         if (!uad.decl || !uad.atts || !uad.atts.dim || !uad._scope)
563             return visit(cast(AttribDeclaration)uad);
564 
565         Expression* lastTag;
566         static void eval(Scope* sc, Expressions* exps, ref Expression* lastTag)
567         {
568             foreach (ref Expression e; *exps)
569             {
570                 if (!e)
571                     continue;
572 
573                 e = e.expressionSemantic(sc);
574                 if (definitelyValueParameter(e))
575                     e = e.ctfeInterpret();
576                 if (e.op == EXP.tuple)
577                 {
578                     TupleExp te = cast(TupleExp)e;
579                     eval(sc, te.exps, lastTag);
580                 }
581 
582                 // Handles compiler-recognized `core.attribute.gnuAbiTag`
583                 if (UserAttributeDeclaration.isGNUABITag(e))
584                     doGNUABITagSemantic(e, lastTag);
585             }
586         }
587 
588         uad._scope = null;
589         eval(sc, uad.atts, lastTag);
590         visit(cast(AttribDeclaration)uad);
591     }
592 
visit(AggregateDeclaration ad)593     override void visit(AggregateDeclaration ad)
594     {
595         //printf("AggregateDeclaration::semantic2(%s) type = %s, errors = %d\n", ad.toChars(), ad.type.toChars(), ad.errors);
596         if (!ad.members)
597             return;
598 
599         if (ad._scope)
600         {
601             ad.error("has forward references");
602             return;
603         }
604 
605         UserAttributeDeclaration.checkGNUABITag(
606             ad, ad.classKind == ClassKind.cpp ? LINK.cpp : LINK.d);
607 
608         auto sc2 = ad.newScope(sc);
609 
610         ad.determineSize(ad.loc);
611 
612         for (size_t i = 0; i < ad.members.dim; i++)
613         {
614             Dsymbol s = (*ad.members)[i];
615             //printf("\t[%d] %s\n", i, s.toChars());
616             s.semantic2(sc2);
617         }
618 
619         sc2.pop();
620     }
621 
visit(ClassDeclaration cd)622     override void visit(ClassDeclaration cd)
623     {
624         /// Checks that the given class implements all methods of its interfaces.
625         static void checkInterfaceImplementations(ClassDeclaration cd)
626         {
627             foreach (base; cd.interfaces)
628             {
629                 // first entry is ClassInfo reference
630                 auto methods = base.sym.vtbl[base.sym.vtblOffset .. $];
631 
632                 foreach (m; methods)
633                 {
634                     auto ifd = m.isFuncDeclaration;
635                     assert(ifd);
636 
637                     if (ifd.objc.isOptional)
638                         continue;
639 
640                     auto type = ifd.type.toTypeFunction();
641                     auto fd = cd.findFunc(ifd.ident, type);
642 
643                     if (fd && !fd.isAbstract)
644                     {
645                         //printf("            found\n");
646                         // Check that calling conventions match
647                         if (fd._linkage != ifd._linkage)
648                             fd.error("linkage doesn't match interface function");
649 
650                         // Check that it is current
651                         //printf("newinstance = %d fd.toParent() = %s ifd.toParent() = %s\n",
652                             //newinstance, fd.toParent().toChars(), ifd.toParent().toChars());
653                         if (fd.toParent() != cd && ifd.toParent() == base.sym)
654                             cd.error("interface function `%s` is not implemented", ifd.toFullSignature());
655                     }
656                     else
657                     {
658                         //printf("            not found %p\n", fd);
659                         // BUG: should mark this class as abstract?
660                         if (!cd.isAbstract())
661                             cd.error("interface function `%s` is not implemented", ifd.toFullSignature());
662                     }
663                 }
664             }
665         }
666 
667         if (cd.semanticRun >= PASS.semantic2done)
668             return;
669         assert(cd.semanticRun <= PASS.semantic2);
670         cd.semanticRun = PASS.semantic2;
671 
672         checkInterfaceImplementations(cd);
673         visit(cast(AggregateDeclaration) cd);
674     }
675 
visit(InterfaceDeclaration cd)676     override void visit(InterfaceDeclaration cd)
677     {
678         visit(cast(AggregateDeclaration) cd);
679     }
680 
visit(TupleDeclaration td)681     override void visit(TupleDeclaration td)
682     {
683         td.foreachVar((s) { s.accept(this); });
684     }
685 }
686 
687 /**
688  * Perform semantic analysis specific to the GNU ABI tags
689  *
690  * The GNU ABI tags are a feature introduced in C++11, specific to g++
691  * and the Itanium ABI.
692  * They are mandatory for C++ interfacing, simply because the templated struct
693  *`std::basic_string`, of which the ubiquitous `std::string` is a instantiation
694  * of, uses them.
695  *
696  * Params:
697  *   e = Expression to perform semantic on
698  *       See `Semantic2Visitor.visit(UserAttributeDeclaration)`
699  *   lastTag = When `!is null`, we already saw an ABI tag.
700  *            To simplify implementation and reflection code,
701  *            only one ABI tag object is allowed per symbol
702  *            (but it can have multiple tags as it's an array exp).
703  */
doGNUABITagSemantic(ref Expression e,ref Expression * lastTag)704 private void doGNUABITagSemantic(ref Expression e, ref Expression* lastTag)
705 {
706     import dmd.dmangle;
707 
708     // When `@gnuAbiTag` is used, the type will be the UDA, not the struct literal
709     if (e.op == EXP.type)
710     {
711         e.error("`@%s` at least one argument expected", Id.udaGNUAbiTag.toChars());
712         return;
713     }
714 
715     // Definition is in `core.attributes`. If it's not a struct literal,
716     // it shouldn't have passed semantic, hence the `assert`.
717     auto sle = e.isStructLiteralExp();
718     if (sle is null)
719     {
720         assert(global.errors);
721         return;
722     }
723     // The definition of `gnuAttributes` only have 1 member, `string[] tags`
724     assert(sle.elements && sle.elements.length == 1);
725     // `gnuAbiTag`'s constructor is defined as `this(string[] tags...)`
726     auto ale = (*sle.elements)[0].isArrayLiteralExp();
727     if (ale is null)
728     {
729         e.error("`@%s` at least one argument expected", Id.udaGNUAbiTag.toChars());
730         return;
731     }
732 
733     // Check that it's the only tag on the symbol
734     if (lastTag !is null)
735     {
736         const str1 = (*lastTag.isStructLiteralExp().elements)[0].toString();
737         const str2 = ale.toString();
738         e.error("only one `@%s` allowed per symbol", Id.udaGNUAbiTag.toChars());
739         e.errorSupplemental("instead of `@%s @%s`, use `@%s(%.*s, %.*s)`",
740             lastTag.toChars(), e.toChars(), Id.udaGNUAbiTag.toChars(),
741             // Avoid [ ... ]
742             cast(int)str1.length - 2, str1.ptr + 1,
743             cast(int)str2.length - 2, str2.ptr + 1);
744         return;
745     }
746     lastTag = &e;
747 
748     // We already know we have a valid array literal of strings.
749     // Now checks that elements are valid.
750     foreach (idx, elem; *ale.elements)
751     {
752         const str = elem.toStringExp().peekString();
753         if (!str.length)
754         {
755             e.error("argument `%d` to `@%s` cannot be %s", cast(int)(idx + 1),
756                     Id.udaGNUAbiTag.toChars(),
757                     elem.isNullExp() ? "`null`".ptr : "empty".ptr);
758             continue;
759         }
760 
761         foreach (c; str)
762         {
763             if (!c.isValidMangling())
764             {
765                 e.error("`@%s` char `0x%02x` not allowed in mangling",
766                         Id.udaGNUAbiTag.toChars(), c);
767                 break;
768             }
769         }
770         // Valid element
771     }
772     // Since ABI tags need to be sorted, we sort them in place
773     // It might be surprising for users that inspects the UDAs,
774     // but it's a concession to practicality.
775     // Casts are unfortunately necessary as `implicitConvTo` is not
776     // `const` (and nor is `StringExp`, by extension).
777     static int predicate(const scope Expression* e1, const scope Expression* e2) nothrow
778     {
779         scope(failure) assert(0, "An exception was thrown");
780         return (cast(Expression*)e1).toStringExp().compare((cast(Expression*)e2).toStringExp());
781     }
782     ale.elements.sort!predicate;
783 }
784