1 /**
2  * Performs the semantic2 stage, which deals with initializer expressions.
3  *
4  * Copyright:   Copyright (C) 1999-2020 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         import dmd.dmangle : mangleToFuncSignature;
354 
355         if (fd.semanticRun >= PASS.semantic2done)
356             return;
357         assert(fd.semanticRun <= PASS.semantic2);
358         fd.semanticRun = PASS.semantic2;
359 
360         //printf("FuncDeclaration::semantic2 [%s] fd0 = %s %s\n", loc.toChars(), toChars(), type.toChars());
361 
362         // https://issues.dlang.org/show_bug.cgi?id=18385
363         // Disable for 2.079, s.t. a deprecation cycle can be started with 2.080
364         if (0)
365         if (fd.overnext && !fd.errors)
366         {
367             OutBuffer buf1;
368             OutBuffer buf2;
369 
370             // Always starts the lookup from 'this', because the conflicts with
371             // previous overloads are already reported.
372             auto f1 = fd;
373             mangleToFuncSignature(buf1, f1);
374 
375             overloadApply(f1, (Dsymbol s)
376             {
377                 auto f2 = s.isFuncDeclaration();
378                 if (!f2 || f1 == f2 || f2.errors)
379                     return 0;
380 
381                 // Don't have to check conflict between declaration and definition.
382                 if ((f1.fbody !is null) != (f2.fbody !is null))
383                     return 0;
384 
385                 /* Check for overload merging with base class member functions.
386                  *
387                  *  class B { void foo() {} }
388                  *  class D : B {
389                  *    override void foo() {}    // B.foo appears as f2
390                  *    alias foo = B.foo;
391                  *  }
392                  */
393                 if (f1.overrides(f2))
394                     return 0;
395 
396                 // extern (C) functions always conflict each other.
397                 if (f1.ident == f2.ident &&
398                     f1.toParent2() == f2.toParent2() &&
399                     (f1.linkage != LINK.d && f1.linkage != LINK.cpp) &&
400                     (f2.linkage != LINK.d && f2.linkage != LINK.cpp))
401                 {
402                     /* Allow the hack that is actually used in druntime,
403                      * to ignore function attributes for extern (C) functions.
404                      * TODO: Must be reconsidered in the future.
405                      *  BUG: https://issues.dlang.org/show_bug.cgi?id=18206
406                      *
407                      *  extern(C):
408                      *  alias sigfn_t  = void function(int);
409                      *  alias sigfn_t2 = void function(int) nothrow @nogc;
410                      *  sigfn_t  bsd_signal(int sig, sigfn_t  func);
411                      *  sigfn_t2 bsd_signal(int sig, sigfn_t2 func) nothrow @nogc;  // no error
412                      */
413                     if (f1.fbody is null || f2.fbody is null)
414                         return 0;
415 
416                     auto tf2 = cast(TypeFunction)f2.type;
417                     error(f2.loc, "%s `%s%s` cannot be overloaded with %s`extern(%s)` function at %s",
418                             f2.kind(),
419                             f2.toPrettyChars(),
420                             parametersTypeToChars(tf2.parameterList),
421                             (f1.linkage == f2.linkage ? "another " : "").ptr,
422                             linkageToChars(f1.linkage), f1.loc.toChars());
423                     f2.type = Type.terror;
424                     f2.errors = true;
425                     return 0;
426                 }
427 
428                 buf2.reset();
429                 mangleToFuncSignature(buf2, f2);
430 
431                 auto s1 = buf1.peekChars();
432                 auto s2 = buf2.peekChars();
433 
434                 //printf("+%s\n\ts1 = %s\n\ts2 = %s @ [%s]\n", toChars(), s1, s2, f2.loc.toChars());
435                 if (strcmp(s1, s2) == 0)
436                 {
437                     auto tf2 = cast(TypeFunction)f2.type;
438                     error(f2.loc, "%s `%s%s` conflicts with previous declaration at %s",
439                             f2.kind(),
440                             f2.toPrettyChars(),
441                             parametersTypeToChars(tf2.parameterList),
442                             f1.loc.toChars());
443                     f2.type = Type.terror;
444                     f2.errors = true;
445                 }
446                 return 0;
447             });
448         }
449         if (!fd.type || fd.type.ty != Tfunction)
450             return;
451         TypeFunction f = cast(TypeFunction) fd.type;
452 
453         UserAttributeDeclaration.checkGNUABITag(fd, fd.linkage);
454         //semantic for parameters' UDAs
455         foreach (i; 0 .. f.parameterList.length)
456         {
457             Parameter param = f.parameterList[i];
458             if (param && param.userAttribDecl)
459                 param.userAttribDecl.semantic2(sc);
460         }
461     }
462 
463     override void visit(Import i)
464     {
465         //printf("Import::semantic2('%s')\n", toChars());
466         if (i.mod)
467         {
468             i.mod.semantic2(null);
469             if (i.mod.needmoduleinfo)
470             {
471                 //printf("module5 %s because of %s\n", sc.module.toChars(), mod.toChars());
472                 if (sc)
473                     sc._module.needmoduleinfo = 1;
474             }
475         }
476     }
477 
478     override void visit(Nspace ns)
479     {
480         if (ns.semanticRun >= PASS.semantic2)
481             return;
482         ns.semanticRun = PASS.semantic2;
483         static if (LOG)
484         {
485             printf("+Nspace::semantic2('%s')\n", ns.toChars());
486         }
487         UserAttributeDeclaration.checkGNUABITag(ns, LINK.cpp);
488         if (ns.members)
489         {
490             assert(sc);
491             sc = sc.push(ns);
492             sc.linkage = LINK.cpp;
493             foreach (s; *ns.members)
494             {
495                 static if (LOG)
496                 {
497                     printf("\tmember '%s', kind = '%s'\n", s.toChars(), s.kind());
498                 }
499                 s.semantic2(sc);
500             }
501             sc.pop();
502         }
503         static if (LOG)
504         {
505             printf("-Nspace::semantic2('%s')\n", ns.toChars());
506         }
507     }
508 
509     override void visit(AttribDeclaration ad)
510     {
511         Dsymbols* d = ad.include(sc);
512         if (d)
513         {
514             Scope* sc2 = ad.newScope(sc);
515             for (size_t i = 0; i < d.dim; i++)
516             {
517                 Dsymbol s = (*d)[i];
518                 s.semantic2(sc2);
519             }
520             if (sc2 != sc)
521                 sc2.pop();
522         }
523     }
524 
525     /**
526      * Run the DeprecatedDeclaration's semantic2 phase then its members.
527      *
528      * The message set via a `DeprecatedDeclaration` can be either of:
529      * - a string literal
530      * - an enum
531      * - a static immutable
532      * So we need to call ctfe to resolve it.
533      * Afterward forwards to the members' semantic2.
534      */
535     override void visit(DeprecatedDeclaration dd)
536     {
537         getMessage(dd);
538         visit(cast(AttribDeclaration)dd);
539     }
540 
541     override void visit(AlignDeclaration ad)
542     {
543         ad.getAlignment(sc);
544         visit(cast(AttribDeclaration)ad);
545     }
546 
547     override void visit(CPPNamespaceDeclaration decl)
548     {
549         UserAttributeDeclaration.checkGNUABITag(decl, LINK.cpp);
550         visit(cast(AttribDeclaration)decl);
551     }
552 
553     override void visit(UserAttributeDeclaration uad)
554     {
555         if (uad.decl && uad.atts && uad.atts.dim && uad._scope)
556         {
557             Expression* lastTag;
558             static void eval(Scope* sc, Expressions* exps, ref Expression* lastTag)
559             {
560                 foreach (ref Expression e; *exps)
561                 {
562                     if (e)
563                     {
564                         e = e.expressionSemantic(sc);
565                         if (definitelyValueParameter(e))
566                             e = e.ctfeInterpret();
567                         if (e.op == TOK.tuple)
568                         {
569                             TupleExp te = cast(TupleExp)e;
570                             eval(sc, te.exps, lastTag);
571                         }
572 
573                         // Handles compiler-recognized `core.attribute.gnuAbiTag`
574                         if (UserAttributeDeclaration.isGNUABITag(e))
575                             doGNUABITagSemantic(e, lastTag);
576                     }
577                 }
578             }
579 
580             uad._scope = null;
581             eval(sc, uad.atts, lastTag);
582         }
583         visit(cast(AttribDeclaration)uad);
584     }
585 
586     override void visit(AggregateDeclaration ad)
587     {
588         //printf("AggregateDeclaration::semantic2(%s) type = %s, errors = %d\n", ad.toChars(), ad.type.toChars(), ad.errors);
589         if (!ad.members)
590             return;
591 
592         if (ad._scope)
593         {
594             ad.error("has forward references");
595             return;
596         }
597 
598         UserAttributeDeclaration.checkGNUABITag(
599             ad, ad.classKind == ClassKind.cpp ? LINK.cpp : LINK.d);
600 
601         auto sc2 = ad.newScope(sc);
602 
603         ad.determineSize(ad.loc);
604 
605         for (size_t i = 0; i < ad.members.dim; i++)
606         {
607             Dsymbol s = (*ad.members)[i];
608             //printf("\t[%d] %s\n", i, s.toChars());
609             s.semantic2(sc2);
610         }
611 
612         sc2.pop();
613     }
614 }
615 
616 /**
617  * Perform semantic analysis specific to the GNU ABI tags
618  *
619  * The GNU ABI tags are a feature introduced in C++11, specific to g++
620  * and the Itanium ABI.
621  * They are mandatory for C++ interfacing, simply because the templated struct
622  *`std::basic_string`, of which the ubiquitous `std::string` is a instantiation
623  * of, uses them.
624  *
625  * Params:
626  *   e = Expression to perform semantic on
627  *       See `Semantic2Visitor.visit(UserAttributeDeclaration)`
628  *   lastTag = When `!is null`, we already saw an ABI tag.
629  *            To simplify implementation and reflection code,
630  *            only one ABI tag object is allowed per symbol
631  *            (but it can have multiple tags as it's an array exp).
632  */
633 private void doGNUABITagSemantic(ref Expression e, ref Expression* lastTag)
634 {
635     import dmd.dmangle;
636 
637     // When `@gnuAbiTag` is used, the type will be the UDA, not the struct literal
638     if (e.op == TOK.type)
639     {
640         e.error("`@%s` at least one argument expected", Id.udaGNUAbiTag.toChars());
641         return;
642     }
643 
644     // Definition is in `core.attributes`. If it's not a struct literal,
645     // it shouldn't have passed semantic, hence the `assert`.
646     auto sle = e.isStructLiteralExp();
647     if (sle is null)
648     {
649         assert(global.errors);
650         return;
651     }
652     // The definition of `gnuAttributes` only have 1 member, `string[] tags`
653     assert(sle.elements && sle.elements.length == 1);
654     // `gnuAbiTag`'s constructor is defined as `this(string[] tags...)`
655     auto ale = (*sle.elements)[0].isArrayLiteralExp();
656     if (ale is null)
657     {
658         e.error("`@%s` at least one argument expected", Id.udaGNUAbiTag.toChars());
659         return;
660     }
661 
662     // Check that it's the only tag on the symbol
663     if (lastTag !is null)
664     {
665         const str1 = (*lastTag.isStructLiteralExp().elements)[0].toString();
666         const str2 = ale.toString();
667         e.error("only one `@%s` allowed per symbol", Id.udaGNUAbiTag.toChars());
668         e.errorSupplemental("instead of `@%s @%s`, use `@%s(%.*s, %.*s)`",
669             lastTag.toChars(), e.toChars(), Id.udaGNUAbiTag.toChars(),
670             // Avoid [ ... ]
671             cast(int)str1.length - 2, str1.ptr + 1,
672             cast(int)str2.length - 2, str2.ptr + 1);
673         return;
674     }
675     lastTag = &e;
676 
677     // We already know we have a valid array literal of strings.
678     // Now checks that elements are valid.
679     foreach (idx, elem; *ale.elements)
680     {
681         const str = elem.toStringExp().peekString();
682         if (!str.length)
683         {
684             e.error("argument `%d` to `@%s` cannot be %s", cast(int)(idx + 1),
685                     Id.udaGNUAbiTag.toChars(),
686                     elem.isNullExp() ? "`null`".ptr : "empty".ptr);
687             continue;
688         }
689 
690         foreach (c; str)
691         {
692             if (!c.isValidMangling())
693             {
694                 e.error("`@%s` char `0x%02x` not allowed in mangling",
695                         Id.udaGNUAbiTag.toChars(), c);
696                 break;
697             }
698         }
699         // Valid element
700     }
701     // Since ABI tags need to be sorted, we sort them in place
702     // It might be surprising for users that inspects the UDAs,
703     // but it's a concession to practicality.
704     // Casts are unfortunately necessary as `implicitConvTo` is not
705     // `const` (and nor is `StringExp`, by extension).
706     static int predicate(const scope Expression* e1, const scope Expression* e2) nothrow
707     {
708         scope(failure) assert(0, "An exception was thrown");
709         return (cast(Expression*)e1).toStringExp().compare((cast(Expression*)e2).toStringExp());
710     }
711     ale.elements.sort!predicate;
712 }