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