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