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 1
    scope v = new Semantic2Visitor(sc);
78 1
    dsym.accept(v);
79
}
80

81
private extern(C++) final class Semantic2Visitor : Visitor
82
{
83
    alias visit = Visitor.visit;
84
    Scope* sc;
85 1
    this(Scope* sc)
86
    {
87 1
        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 1
        auto sds = new ScopeDsymbol();
96 1
        sc = sc.push(sds);
97 1
        sc.tinst = null;
98 1
        sc.minst = null;
99

100
        import dmd.staticcond;
101 1
        bool errors;
102 1
        bool result = evalStaticCondition(sc, sa.exp, sa.exp, errors);
103 1
        sc = sc.pop();
104 1
        if (errors)
105
        {
106 1
            errorSupplemental(sa.loc, "while evaluating: `static assert(%s)`", sa.exp.toChars());
107
        }
108 1
        else if (!result)
109
        {
110 1
            if (sa.msg)
111
            {
112 1
                sc = sc.startCTFE();
113 1
                sa.msg = sa.msg.expressionSemantic(sc);
114 1
                sa.msg = resolveProperties(sc, sa.msg);
115 1
                sc = sc.endCTFE();
116 1
                sa.msg = sa.msg.ctfeInterpret();
117 1
                if (StringExp se = sa.msg.toStringExp())
118
                {
119
                    // same with pragma(msg)
120 1
                    const slice = se.toUTF8(sc).peekString();
121 1
                    error(sa.loc, "static assert:  \"%.*s\"", cast(int)slice.length, slice.ptr);
122
                }
123
                else
124 0
                    error(sa.loc, "static assert:  %s", sa.msg.toChars());
125
            }
126
            else
127 1
                error(sa.loc, "static assert:  `%s` is false", sa.exp.toChars());
128 1
            if (sc.tinst)
129 1
                sc.tinst.printInstantiationTrace();
130 1
            if (!global.gag)
131 1
                fatal();
132
        }
133
    }
134

135
    override void visit(TemplateInstance tempinst)
136
    {
137 1
        if (tempinst.semanticRun >= PASS.semantic2)
138 1
            return;
139 1
        tempinst.semanticRun = PASS.semantic2;
140
        static if (LOG)
141
        {
142
            printf("+TemplateInstance.semantic2('%s')\n", tempinst.toChars());
143
        }
144 1
        if (!tempinst.errors && tempinst.members)
145
        {
146 1
            TemplateDeclaration tempdecl = tempinst.tempdecl.isTemplateDeclaration();
147 1
            assert(tempdecl);
148

149 1
            sc = tempdecl._scope;
150 1
            assert(sc);
151 1
            sc = sc.push(tempinst.argsym);
152 1
            sc = sc.push(tempinst);
153 1
            sc.tinst = tempinst;
154 1
            sc.minst = tempinst.minst;
155

156 1
            int needGagging = (tempinst.gagged && !global.gag);
157 1
            uint olderrors = global.errors;
158 1
            int oldGaggedErrors = -1; // dead-store to prevent spurious warning
159 1
            if (needGagging)
160 1
                oldGaggedErrors = global.startGagging();
161

162 1
            for (size_t i = 0; i < tempinst.members.dim; i++)
163
            {
164 1
                Dsymbol s = (*tempinst.members)[i];
165
                static if (LOG)
166
                {
167
                    printf("\tmember '%s', kind = '%s'\n", s.toChars(), s.kind());
168
                }
169 1
                s.semantic2(sc);
170 1
                if (tempinst.gagged && global.errors != olderrors)
171 1
                    break;
172
            }
173

174 1
            if (global.errors != olderrors)
175
            {
176 1
                if (!tempinst.errors)
177
                {
178 1
                    if (!tempdecl.literal)
179 1
                        tempinst.error(tempinst.loc, "error instantiating");
180 1
                    if (tempinst.tinst)
181 1
                        tempinst.tinst.printInstantiationTrace();
182
                }
183 1
                tempinst.errors = true;
184
            }
185 1
            if (needGagging)
186 1
                global.endGagging(oldGaggedErrors);
187

188 1
            sc = sc.pop();
189 1
            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 1
        if (tmix.semanticRun >= PASS.semantic2)
200 1
            return;
201 1
        tmix.semanticRun = PASS.semantic2;
202
        static if (LOG)
203
        {
204
            printf("+TemplateMixin.semantic2('%s')\n", tmix.toChars());
205
        }
206 1
        if (tmix.members)
207
        {
208 1
            assert(sc);
209 1
            sc = sc.push(tmix.argsym);
210 1
            sc = sc.push(tmix);
211 1
            for (size_t i = 0; i < tmix.members.dim; i++)
212
            {
213 1
                Dsymbol s = (*tmix.members)[i];
214
                static if (LOG)
215
                {
216
                    printf("\tmember '%s', kind = '%s'\n", s.toChars(), s.kind());
217
                }
218 1
                s.semantic2(sc);
219
            }
220 1
            sc = sc.pop();
221 1
            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 1
        if (vd.semanticRun < PASS.semanticdone && vd.inuse)
232 1
            return;
233

234
        //printf("VarDeclaration::semantic2('%s')\n", toChars());
235

236 1
        if (vd.aliassym)        // if it's a tuple
237
        {
238 1
            vd.aliassym.accept(this);
239 1
            vd.semanticRun = PASS.semantic2done;
240 1
            return;
241
        }
242

243 1
        UserAttributeDeclaration.checkGNUABITag(vd, vd.linkage);
244

245 1
        if (vd._init && !vd.toParent().isFuncDeclaration())
246
        {
247 1
            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 1
            if (!vd.type)
255 0
                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 1
            vd._init = vd._init.initializerSemantic(sc, vd.type, sc.intypeof == 1 || sc.flags & SCOPE.compile ? INITnointerpret : INITinterpret);
262 1
            vd.inuse--;
263
        }
264 1
        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 1
            if (ExpInitializer ei = vd._init.isExpInitializer())
270
            {
271
                static bool hasInvalidEnumInitializer(Expression e)
272
                {
273
                    static bool arrayHasInvalidEnumInitializer(Expressions* elems)
274
                    {
275 1
                        foreach (e; *elems)
276
                        {
277 1
                            if (e && hasInvalidEnumInitializer(e))
278 1
                                return true;
279
                        }
280 1
                        return false;
281
                    }
282

283 1
                    if (e.op == TOK.classReference)
284 1
                        return true;
285 1
                    if (e.op == TOK.address && (cast(AddrExp)e).e1.op == TOK.structLiteral)
286 1
                        return true;
287 1
                    if (e.op == TOK.arrayLiteral)
288 1
                        return arrayHasInvalidEnumInitializer((cast(ArrayLiteralExp)e).elements);
289 1
                    if (e.op == TOK.structLiteral)
290 1
                        return arrayHasInvalidEnumInitializer((cast(StructLiteralExp)e).elements);
291 1
                    if (e.op == TOK.assocArrayLiteral)
292
                    {
293 1
                        AssocArrayLiteralExp ae = cast(AssocArrayLiteralExp)e;
294 1
                        return arrayHasInvalidEnumInitializer(ae.values) ||
295 1
                               arrayHasInvalidEnumInitializer(ae.keys);
296
                    }
297 1
                    return false;
298
                }
299

300 1
                if (hasInvalidEnumInitializer(ei.exp))
301 1
                    vd.error(": Unable to initialize enum with class or pointer to struct. Use static const variable instead.");
302
            }
303
        }
304 1
        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 1
            if ((vd.type.ty == Tclass) && vd.type.isMutable() && !vd.type.isShared())
309
            {
310 1
                ExpInitializer ei = vd._init.isExpInitializer();
311 1
                if (ei && ei.exp.op == TOK.classReference)
312 1
                    vd.error("is a thread-local class and cannot have a static initializer. Use `static this()` to initialize instead.");
313
            }
314 1
            else if (vd.type.ty == Tpointer && vd.type.nextOf().ty == Tstruct && vd.type.nextOf().isMutable() && !vd.type.nextOf().isShared())
315
            {
316 1
                ExpInitializer ei = vd._init.isExpInitializer();
317 1
                if (ei && ei.exp.op == TOK.address && (cast(AddrExp)ei.exp).e1.op == TOK.structLiteral)
318 1
                    vd.error("is a thread-local pointer to struct and cannot have a static initializer. Use `static this()` to initialize instead.");
319
            }
320
        }
321 1
        vd.semanticRun = PASS.semantic2done;
322
    }
323

324
    override void visit(Module mod)
325
    {
326
        //printf("Module::semantic2('%s'): parent = %p\n", toChars(), parent);
327 1
        if (mod.semanticRun != PASS.semanticdone) // semantic() not completed yet - could be recursive call
328 1
            return;
329 1
        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 1
        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 1
        for (size_t i = 0; i < mod.members.dim; i++)
337
        {
338 1
            Dsymbol s = (*mod.members)[i];
339 1
            s.semantic2(sc);
340
        }
341 1
        if (mod.userAttribDecl)
342
        {
343 1
            mod.userAttribDecl.semantic2(sc);
344
        }
345 1
        sc = sc.pop();
346 1
        sc.pop();
347 1
        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 1
        if (fd.semanticRun >= PASS.semantic2done)
356 1
            return;
357 1
        assert(fd.semanticRun <= PASS.semantic2);
358 1
        fd.semanticRun = PASS.semantic2;
359

360
        //printf("FuncDeclaration::semantic2 [%s] fd0 = %s %s\n", loc.toChars(), toChars(), type.toChars());
361

362
        // Only check valid functions which have a body to avoid errors
363
        // for multiple declarations, e.g.
364
        // void foo();
365
        // void foo();
366 1
        if (fd.fbody && fd.overnext && !fd.errors)
367
        {
368 1
            OutBuffer buf1;
369 1
            OutBuffer buf2;
370

371
            // Always starts the lookup from 'this', because the conflicts with
372
            // previous overloads are already reported.
373
            alias f1 = fd;
374 1
            auto tf1 = cast(TypeFunction) f1.type;
375 1
            mangleToFuncSignature(buf1, f1);
376

377 1
            overloadApply(f1, (Dsymbol s)
378
            {
379 1
                auto f2 = s.isFuncDeclaration();
380 1
                if (!f2 || f1 == f2 || f2.errors)
381 1
                    return 0;
382

383
                // Don't have to check conflict between declaration and definition.
384 1
                if (f2.fbody is null)
385 1
                    return 0;
386

387
                /* Check for overload merging with base class member functions.
388
                 *
389
                 *  class B { void foo() {} }
390
                 *  class D : B {
391
                 *    override void foo() {}    // B.foo appears as f2
392
                 *    alias foo = B.foo;
393
                 *  }
394
                 */
395 1
                if (f1.overrides(f2))
396 1
                    return 0;
397

398 1
                auto tf2 = cast(TypeFunction) f2.type;
399

400
                // extern (C) functions always conflict each other.
401 1
                if (f1.ident == f2.ident &&
402 1
                    f1.toParent2() == f2.toParent2() &&
403 1
                    (f1.linkage != LINK.d && f1.linkage != LINK.cpp) &&
404 1
                    (f2.linkage != LINK.d && f2.linkage != LINK.cpp) &&
405

406
                    // But allow the hack to declare overloads with different parameters/STC's
407 1
                    (!tf1.attributesEqual(tf2) || tf1.parameterList != tf2.parameterList))
408
                {
409
                    // @@@DEPRECATED_2.094@@@
410
                    // Deprecated in 2020-08, make this an error in 2.104
411 1
                    f2.deprecation("cannot overload `extern(%s)` function at %s",
412
                            linkageToChars(f1.linkage),
413
                            f1.loc.toChars());
414

415
                    // Enable this when turning the deprecation into an error
416
                    // f2.type = Type.terror;
417
                    // f2.errors = true;
418 1
                    return 0;
419
                }
420

421 1
                buf2.reset();
422 1
                mangleToFuncSignature(buf2, f2);
423

424 1
                auto s1 = buf1.peekChars();
425 1
                auto s2 = buf2.peekChars();
426

427
                //printf("+%s\n\ts1 = %s\n\ts2 = %s @ [%s]\n", toChars(), s1, s2, f2.loc.toChars());
428 1
                if (strcmp(s1, s2) == 0)
429
                {
430 1
                    error(f2.loc, "%s `%s%s` conflicts with previous declaration at %s",
431
                            f2.kind(),
432
                            f2.toPrettyChars(),
433
                            parametersTypeToChars(tf2.parameterList),
434
                            f1.loc.toChars());
435 1
                    f2.type = Type.terror;
436 1
                    f2.errors = true;
437
                }
438 1
                return 0;
439
            });
440
        }
441 1
        if (!fd.type || fd.type.ty != Tfunction)
442 1
            return;
443 1
        TypeFunction f = cast(TypeFunction) fd.type;
444

445 1
        UserAttributeDeclaration.checkGNUABITag(fd, fd.linkage);
446
        //semantic for parameters' UDAs
447 1
        foreach (i, param; f.parameterList)
448
        {
449 1
            if (param && param.userAttribDecl)
450 1
                param.userAttribDecl.semantic2(sc);
451
        }
452
    }
453

454
    override void visit(Import i)
455
    {
456
        //printf("Import::semantic2('%s')\n", toChars());
457 1
        if (i.mod)
458
        {
459 1
            i.mod.semantic2(null);
460 1
            if (i.mod.needmoduleinfo)
461
            {
462
                //printf("module5 %s because of %s\n", sc.module.toChars(), mod.toChars());
463 1
                if (sc)
464 1
                    sc._module.needmoduleinfo = 1;
465
            }
466
        }
467
    }
468

469
    override void visit(Nspace ns)
470
    {
471 1
        if (ns.semanticRun >= PASS.semantic2)
472 0
            return;
473 1
        ns.semanticRun = PASS.semantic2;
474
        static if (LOG)
475
        {
476
            printf("+Nspace::semantic2('%s')\n", ns.toChars());
477
        }
478 1
        UserAttributeDeclaration.checkGNUABITag(ns, LINK.cpp);
479 1
        if (ns.members)
480
        {
481 1
            assert(sc);
482 1
            sc = sc.push(ns);
483 1
            sc.linkage = LINK.cpp;
484 1
            foreach (s; *ns.members)
485
            {
486
                static if (LOG)
487
                {
488
                    printf("\tmember '%s', kind = '%s'\n", s.toChars(), s.kind());
489
                }
490 1
                s.semantic2(sc);
491
            }
492 1
            sc.pop();
493
        }
494
        static if (LOG)
495
        {
496
            printf("-Nspace::semantic2('%s')\n", ns.toChars());
497
        }
498
    }
499

500
    override void visit(AttribDeclaration ad)
501
    {
502 1
        Dsymbols* d = ad.include(sc);
503 1
        if (d)
504
        {
505 1
            Scope* sc2 = ad.newScope(sc);
506 1
            for (size_t i = 0; i < d.dim; i++)
507
            {
508 1
                Dsymbol s = (*d)[i];
509 1
                s.semantic2(sc2);
510
            }
511 1
            if (sc2 != sc)
512 1
                sc2.pop();
513
        }
514
    }
515

516
    /**
517
     * Run the DeprecatedDeclaration's semantic2 phase then its members.
518
     *
519
     * The message set via a `DeprecatedDeclaration` can be either of:
520
     * - a string literal
521
     * - an enum
522
     * - a static immutable
523
     * So we need to call ctfe to resolve it.
524
     * Afterward forwards to the members' semantic2.
525
     */
526
    override void visit(DeprecatedDeclaration dd)
527
    {
528 1
        getMessage(dd);
529 1
        visit(cast(AttribDeclaration)dd);
530
    }
531

532
    override void visit(AlignDeclaration ad)
533
    {
534 1
        ad.getAlignment(sc);
535 1
        visit(cast(AttribDeclaration)ad);
536
    }
537

538
    override void visit(CPPNamespaceDeclaration decl)
539
    {
540 1
        UserAttributeDeclaration.checkGNUABITag(decl, LINK.cpp);
541 1
        visit(cast(AttribDeclaration)decl);
542
    }
543

544
    override void visit(UserAttributeDeclaration uad)
545
    {
546 1
        if (uad.decl && uad.atts && uad.atts.dim && uad._scope)
547
        {
548 1
            Expression* lastTag;
549
            static void eval(Scope* sc, Expressions* exps, ref Expression* lastTag)
550
            {
551 1
                foreach (ref Expression e; *exps)
552
                {
553 1
                    if (e)
554
                    {
555 1
                        e = e.expressionSemantic(sc);
556 1
                        if (definitelyValueParameter(e))
557 1
                            e = e.ctfeInterpret();
558 1
                        if (e.op == TOK.tuple)
559
                        {
560 1
                            TupleExp te = cast(TupleExp)e;
561 1
                            eval(sc, te.exps, lastTag);
562
                        }
563

564
                        // Handles compiler-recognized `core.attribute.gnuAbiTag`
565 1
                        if (UserAttributeDeclaration.isGNUABITag(e))
566 1
                            doGNUABITagSemantic(e, lastTag);
567
                    }
568
                }
569
            }
570

571 1
            uad._scope = null;
572 1
            eval(sc, uad.atts, lastTag);
573
        }
574 1
        visit(cast(AttribDeclaration)uad);
575
    }
576

577
    override void visit(AggregateDeclaration ad)
578
    {
579
        //printf("AggregateDeclaration::semantic2(%s) type = %s, errors = %d\n", ad.toChars(), ad.type.toChars(), ad.errors);
580 1
        if (!ad.members)
581 1
            return;
582

583 1
        if (ad._scope)
584
        {
585 0
            ad.error("has forward references");
586 0
            return;
587
        }
588

589 1
        UserAttributeDeclaration.checkGNUABITag(
590 1
            ad, ad.classKind == ClassKind.cpp ? LINK.cpp : LINK.d);
591

592 1
        auto sc2 = ad.newScope(sc);
593

594 1
        ad.determineSize(ad.loc);
595

596 1
        for (size_t i = 0; i < ad.members.dim; i++)
597
        {
598 1
            Dsymbol s = (*ad.members)[i];
599
            //printf("\t[%d] %s\n", i, s.toChars());
600 1
            s.semantic2(sc2);
601
        }
602

603 1
        sc2.pop();
604
    }
605
}
606

607
/**
608
 * Perform semantic analysis specific to the GNU ABI tags
609
 *
610
 * The GNU ABI tags are a feature introduced in C++11, specific to g++
611
 * and the Itanium ABI.
612
 * They are mandatory for C++ interfacing, simply because the templated struct
613
 *`std::basic_string`, of which the ubiquitous `std::string` is a instantiation
614
 * of, uses them.
615
 *
616
 * Params:
617
 *   e = Expression to perform semantic on
618
 *       See `Semantic2Visitor.visit(UserAttributeDeclaration)`
619
 *   lastTag = When `!is null`, we already saw an ABI tag.
620
 *            To simplify implementation and reflection code,
621
 *            only one ABI tag object is allowed per symbol
622
 *            (but it can have multiple tags as it's an array exp).
623
 */
624
private void doGNUABITagSemantic(ref Expression e, ref Expression* lastTag)
625
{
626
    import dmd.dmangle;
627

628
    // When `@gnuAbiTag` is used, the type will be the UDA, not the struct literal
629 1
    if (e.op == TOK.type)
630
    {
631 1
        e.error("`@%s` at least one argument expected", Id.udaGNUAbiTag.toChars());
632 1
        return;
633
    }
634

635
    // Definition is in `core.attributes`. If it's not a struct literal,
636
    // it shouldn't have passed semantic, hence the `assert`.
637 1
    auto sle = e.isStructLiteralExp();
638 1
    if (sle is null)
639
    {
640 0
        assert(global.errors);
641 0
        return;
642
    }
643
    // The definition of `gnuAttributes` only have 1 member, `string[] tags`
644 1
    assert(sle.elements && sle.elements.length == 1);
645
    // `gnuAbiTag`'s constructor is defined as `this(string[] tags...)`
646 1
    auto ale = (*sle.elements)[0].isArrayLiteralExp();
647 1
    if (ale is null)
648
    {
649 1
        e.error("`@%s` at least one argument expected", Id.udaGNUAbiTag.toChars());
650 1
        return;
651
    }
652

653
    // Check that it's the only tag on the symbol
654 1
    if (lastTag !is null)
655
    {
656 1
        const str1 = (*lastTag.isStructLiteralExp().elements)[0].toString();
657 1
        const str2 = ale.toString();
658 1
        e.error("only one `@%s` allowed per symbol", Id.udaGNUAbiTag.toChars());
659 1
        e.errorSupplemental("instead of `@%s @%s`, use `@%s(%.*s, %.*s)`",
660
            lastTag.toChars(), e.toChars(), Id.udaGNUAbiTag.toChars(),
661
            // Avoid [ ... ]
662
            cast(int)str1.length - 2, str1.ptr + 1,
663
            cast(int)str2.length - 2, str2.ptr + 1);
664 1
        return;
665
    }
666 1
    lastTag = &e;
667

668
    // We already know we have a valid array literal of strings.
669
    // Now checks that elements are valid.
670 1
    foreach (idx, elem; *ale.elements)
671
    {
672 1
        const str = elem.toStringExp().peekString();
673 1
        if (!str.length)
674
        {
675 1
            e.error("argument `%d` to `@%s` cannot be %s", cast(int)(idx + 1),
676
                    Id.udaGNUAbiTag.toChars(),
677 1
                    elem.isNullExp() ? "`null`".ptr : "empty".ptr);
678 1
            continue;
679
        }
680

681 1
        foreach (c; str)
682
        {
683 1
            if (!c.isValidMangling())
684
            {
685 1
                e.error("`@%s` char `0x%02x` not allowed in mangling",
686
                        Id.udaGNUAbiTag.toChars(), c);
687 1
                break;
688
            }
689
        }
690
        // Valid element
691
    }
692
    // Since ABI tags need to be sorted, we sort them in place
693
    // It might be surprising for users that inspects the UDAs,
694
    // but it's a concession to practicality.
695
    // Casts are unfortunately necessary as `implicitConvTo` is not
696
    // `const` (and nor is `StringExp`, by extension).
697
    static int predicate(const scope Expression* e1, const scope Expression* e2) nothrow
698
    {
699 0
        scope(failure) assert(0, "An exception was thrown");
700 1
        return (cast(Expression*)e1).toStringExp().compare((cast(Expression*)e2).toStringExp());
701
    }
702 1
    ale.elements.sort!predicate;
703
}

Read our documentation on viewing source code .

Loading