1
/**
2
 * Defines declarations of various attributes.
3
 *
4
 * The term 'attribute' refers to things that can apply to a larger scope than a single declaration.
5
 * Among them are:
6
 * - Alignment (`align(8)`)
7
 * - User defined attributes (`@UDA`)
8
 * - Function Attributes (`@safe`)
9
 * - Storage classes (`static`, `__gshared`)
10
 * - Mixin declarations  (`mixin("int x;")`)
11
 * - Conditional compilation (`static if`, `static foreach`)
12
 * - Linkage (`extern(C)`)
13
 * - Anonymous structs / unions
14
 * - Protection (`private`, `public`)
15
 * - Deprecated declarations (`@deprecated`)
16
 *
17
 * Copyright:   Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved
18
 * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
19
 * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
20
 * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/attrib.d, _attrib.d)
21
 * Documentation:  https://dlang.org/phobos/dmd_attrib.html
22
 * Coverage:    https://codecov.io/gh/dlang/dmd/src/master/src/dmd/attrib.d
23
 */
24

25
module dmd.attrib;
26

27
import dmd.aggregate;
28
import dmd.arraytypes;
29
import dmd.cond;
30
import dmd.declaration;
31
import dmd.dmodule;
32
import dmd.dscope;
33
import dmd.dsymbol;
34
import dmd.dsymbolsem : dsymbolSemantic;
35
import dmd.expression;
36
import dmd.expressionsem : arrayExpressionSemantic;
37
import dmd.func;
38
import dmd.globals;
39
import dmd.hdrgen : protectionToBuffer;
40
import dmd.id;
41
import dmd.identifier;
42
import dmd.mtype;
43
import dmd.objc; // for objc.addSymbols
44
import dmd.root.outbuffer;
45
import dmd.target; // for target.systemLinkage
46
import dmd.tokens;
47
import dmd.visitor;
48

49
/***********************************************************
50
 * Abstract attribute applied to Dsymbol's used as a common
51
 * ancestor for storage classes (StorageClassDeclaration),
52
 * linkage (LinkageDeclaration) and others.
53
 */
54
extern (C++) abstract class AttribDeclaration : Dsymbol
55
{
56
    Dsymbols* decl;     /// Dsymbol's affected by this AttribDeclaration
57

58 1
    extern (D) this(Dsymbols* decl)
59
    {
60 1
        this.decl = decl;
61
    }
62

63 1
    extern (D) this(const ref Loc loc, Identifier ident, Dsymbols* decl)
64
    {
65 1
        super(loc, ident);
66 1
        this.decl = decl;
67
    }
68

69
    Dsymbols* include(Scope* sc)
70
    {
71 1
        if (errors)
72 1
            return null;
73

74 1
        return decl;
75
    }
76

77
    /****************************************
78
     * Create a new scope if one or more given attributes
79
     * are different from the sc's.
80
     * If the returned scope != sc, the caller should pop
81
     * the scope after it used.
82
     */
83
    extern (D) static Scope* createNewScope(Scope* sc, StorageClass stc, LINK linkage,
84
        CPPMANGLE cppmangle, Prot protection, int explicitProtection,
85
        AlignDeclaration aligndecl, PINLINE inlining)
86
    {
87 1
        Scope* sc2 = sc;
88 1
        if (stc != sc.stc ||
89 1
            linkage != sc.linkage ||
90 1
            cppmangle != sc.cppmangle ||
91 1
            !protection.isSubsetOf(sc.protection) ||
92 1
            explicitProtection != sc.explicitProtection ||
93 1
            aligndecl !is sc.aligndecl ||
94 1
            inlining != sc.inlining)
95
        {
96
            // create new one for changes
97 1
            sc2 = sc.copy();
98 1
            sc2.stc = stc;
99 1
            sc2.linkage = linkage;
100 1
            sc2.cppmangle = cppmangle;
101 1
            sc2.protection = protection;
102 1
            sc2.explicitProtection = explicitProtection;
103 1
            sc2.aligndecl = aligndecl;
104 1
            sc2.inlining = inlining;
105
        }
106 1
        return sc2;
107
    }
108

109
    /****************************************
110
     * A hook point to supply scope for members.
111
     * addMember, setScope, importAll, semantic, semantic2 and semantic3 will use this.
112
     */
113
    Scope* newScope(Scope* sc)
114
    {
115 1
        return sc;
116
    }
117

118
    override void addMember(Scope* sc, ScopeDsymbol sds)
119
    {
120 1
        Dsymbols* d = include(sc);
121 1
        if (d)
122
        {
123 1
            Scope* sc2 = newScope(sc);
124 1
            d.foreachDsymbol( s => s.addMember(sc2, sds) );
125 1
            if (sc2 != sc)
126 1
                sc2.pop();
127
        }
128
    }
129

130
    override void setScope(Scope* sc)
131
    {
132 1
        Dsymbols* d = include(sc);
133
        //printf("\tAttribDeclaration::setScope '%s', d = %p\n",toChars(), d);
134 1
        if (d)
135
        {
136 1
            Scope* sc2 = newScope(sc);
137 1
            d.foreachDsymbol( s => s.setScope(sc2) );
138 1
            if (sc2 != sc)
139 1
                sc2.pop();
140
        }
141
    }
142

143
    override void importAll(Scope* sc)
144
    {
145 1
        Dsymbols* d = include(sc);
146
        //printf("\tAttribDeclaration::importAll '%s', d = %p\n", toChars(), d);
147 1
        if (d)
148
        {
149 1
            Scope* sc2 = newScope(sc);
150 1
            d.foreachDsymbol( s => s.importAll(sc2) );
151 1
            if (sc2 != sc)
152 1
                sc2.pop();
153
        }
154
    }
155

156
    override void addComment(const(char)* comment)
157
    {
158
        //printf("AttribDeclaration::addComment %s\n", comment);
159 1
        if (comment)
160
        {
161 1
            include(null).foreachDsymbol( s => s.addComment(comment) );
162
        }
163
    }
164

165
    override const(char)* kind() const
166
    {
167 0
        return "attribute";
168
    }
169

170
    override bool oneMember(Dsymbol* ps, Identifier ident)
171
    {
172 1
        Dsymbols* d = include(null);
173 1
        return Dsymbol.oneMembers(d, ps, ident);
174
    }
175

176
    override void setFieldOffset(AggregateDeclaration ad, uint* poffset, bool isunion)
177
    {
178 1
        include(null).foreachDsymbol( s => s.setFieldOffset(ad, poffset, isunion) );
179
    }
180

181
    override final bool hasPointers()
182
    {
183 1
        return include(null).foreachDsymbol( (s) { return s.hasPointers(); } ) != 0;
184
    }
185

186
    override final bool hasStaticCtorOrDtor()
187
    {
188 1
        return include(null).foreachDsymbol( (s) { return s.hasStaticCtorOrDtor(); } ) != 0;
189
    }
190

191
    override final void checkCtorConstInit()
192
    {
193 1
        include(null).foreachDsymbol( s => s.checkCtorConstInit() );
194
    }
195

196
    /****************************************
197
     */
198
    override final void addLocalClass(ClassDeclarations* aclasses)
199
    {
200 1
        include(null).foreachDsymbol( s => s.addLocalClass(aclasses) );
201
    }
202

203
    override final void addObjcSymbols(ClassDeclarations* classes, ClassDeclarations* categories)
204
    {
205 0
        objc.addSymbols(this, classes, categories);
206
    }
207

208
    override final inout(AttribDeclaration) isAttribDeclaration() inout
209
    {
210 1
        return this;
211
    }
212

213
    override void accept(Visitor v)
214
    {
215 0
        v.visit(this);
216
    }
217
}
218

219
/***********************************************************
220
 * Storage classes applied to Dsymbols, e.g. `const int i;`
221
 *
222
 * <stc> <decl...>
223
 */
224
extern (C++) class StorageClassDeclaration : AttribDeclaration
225
{
226
    StorageClass stc;
227

228 1
    extern (D) this(StorageClass stc, Dsymbols* decl)
229
    {
230 1
        super(decl);
231 1
        this.stc = stc;
232
    }
233

234
    override Dsymbol syntaxCopy(Dsymbol s)
235
    {
236 1
        assert(!s);
237 1
        return new StorageClassDeclaration(stc, Dsymbol.arraySyntaxCopy(decl));
238
    }
239

240
    override Scope* newScope(Scope* sc)
241
    {
242 1
        StorageClass scstc = sc.stc;
243
        /* These sets of storage classes are mutually exclusive,
244
         * so choose the innermost or most recent one.
245
         */
246 1
        if (stc & (STC.auto_ | STC.scope_ | STC.static_ | STC.extern_ | STC.manifest))
247 1
            scstc &= ~(STC.auto_ | STC.scope_ | STC.static_ | STC.extern_ | STC.manifest);
248 1
        if (stc & (STC.auto_ | STC.scope_ | STC.static_ | STC.tls | STC.manifest | STC.gshared))
249 1
            scstc &= ~(STC.auto_ | STC.scope_ | STC.static_ | STC.tls | STC.manifest | STC.gshared);
250 1
        if (stc & (STC.const_ | STC.immutable_ | STC.manifest))
251 1
            scstc &= ~(STC.const_ | STC.immutable_ | STC.manifest);
252 1
        if (stc & (STC.gshared | STC.shared_ | STC.tls))
253 1
            scstc &= ~(STC.gshared | STC.shared_ | STC.tls);
254 1
        if (stc & (STC.safe | STC.trusted | STC.system))
255 1
            scstc &= ~(STC.safe | STC.trusted | STC.system);
256 1
        scstc |= stc;
257
        //printf("scstc = x%llx\n", scstc);
258 1
        return createNewScope(sc, scstc, sc.linkage, sc.cppmangle,
259
            sc.protection, sc.explicitProtection, sc.aligndecl, sc.inlining);
260
    }
261

262
    override final bool oneMember(Dsymbol* ps, Identifier ident)
263
    {
264 1
        bool t = Dsymbol.oneMembers(decl, ps, ident);
265 1
        if (t && *ps)
266
        {
267
            /* This is to deal with the following case:
268
             * struct Tick {
269
             *   template to(T) { const T to() { ... } }
270
             * }
271
             * For eponymous function templates, the 'const' needs to get attached to 'to'
272
             * before the semantic analysis of 'to', so that template overloading based on the
273
             * 'this' pointer can be successful.
274
             */
275 1
            FuncDeclaration fd = (*ps).isFuncDeclaration();
276 1
            if (fd)
277
            {
278
                /* Use storage_class2 instead of storage_class otherwise when we do .di generation
279
                 * we'll wind up with 'const const' rather than 'const'.
280
                 */
281
                /* Don't think we need to worry about mutually exclusive storage classes here
282
                 */
283 1
                fd.storage_class2 |= stc;
284
            }
285
        }
286 1
        return t;
287
    }
288

289
    override void addMember(Scope* sc, ScopeDsymbol sds)
290
    {
291 1
        Dsymbols* d = include(sc);
292 1
        if (d)
293
        {
294 1
            Scope* sc2 = newScope(sc);
295

296 1
            d.foreachDsymbol( (s)
297
            {
298
                //printf("\taddMember %s to %s\n", s.toChars(), sds.toChars());
299
                // STC.local needs to be attached before the member is added to the scope (because it influences the parent symbol)
300 1
                if (auto decl = s.isDeclaration())
301
                {
302 1
                    decl.storage_class |= stc & STC.local;
303 1
                    if (auto sdecl = s.isStorageClassDeclaration()) // TODO: why is this not enough to deal with the nested case?
304
                    {
305 0
                        sdecl.stc |= stc & STC.local;
306
                    }
307
                }
308 1
                s.addMember(sc2, sds);
309
            });
310

311 1
            if (sc2 != sc)
312 1
                sc2.pop();
313
        }
314

315
    }
316

317
    override inout(StorageClassDeclaration) isStorageClassDeclaration() inout
318
    {
319 0
        return this;
320
    }
321

322
    override void accept(Visitor v)
323
    {
324 1
        v.visit(this);
325
    }
326
}
327

328
/***********************************************************
329
 * Deprecation with an additional message applied to Dsymbols,
330
 * e.g. `deprecated("Superseeded by foo") int bar;`.
331
 * (Note that `deprecated int bar;` is currently represented as a
332
 * StorageClassDeclaration with STC.deprecated_)
333
 *
334
 * `deprecated(<msg>) <decl...>`
335
 */
336
extern (C++) final class DeprecatedDeclaration : StorageClassDeclaration
337
{
338
    Expression msg;         /// deprecation message
339
    const(char)* msgstr;    /// cached string representation of msg
340

341 1
    extern (D) this(Expression msg, Dsymbols* decl)
342
    {
343 1
        super(STC.deprecated_, decl);
344 1
        this.msg = msg;
345
    }
346

347
    override Dsymbol syntaxCopy(Dsymbol s)
348
    {
349 1
        assert(!s);
350 1
        return new DeprecatedDeclaration(msg.syntaxCopy(), Dsymbol.arraySyntaxCopy(decl));
351
    }
352

353
    /**
354
     * Provides a new scope with `STC.deprecated_` and `Scope.depdecl` set
355
     *
356
     * Calls `StorageClassDeclaration.newScope` (as it must be called or copied
357
     * in any function overriding `newScope`), then set the `Scope`'s depdecl.
358
     *
359
     * Returns:
360
     *   Always a new scope, to use for this `DeprecatedDeclaration`'s members.
361
     */
362
    override Scope* newScope(Scope* sc)
363
    {
364 1
        auto scx = super.newScope(sc);
365
        // The enclosing scope is deprecated as well
366 1
        if (scx == sc)
367 1
            scx = sc.push();
368 1
        scx.depdecl = this;
369 1
        return scx;
370
    }
371

372
    override void setScope(Scope* sc)
373
    {
374
        //printf("DeprecatedDeclaration::setScope() %p\n", this);
375 1
        if (decl)
376 1
            Dsymbol.setScope(sc); // for forward reference
377 1
        return AttribDeclaration.setScope(sc);
378
    }
379

380
    override void accept(Visitor v)
381
    {
382 1
        v.visit(this);
383
    }
384
}
385

386
/***********************************************************
387
 * Linkage attribute applied to Dsymbols, e.g.
388
 * `extern(C) void foo()`.
389
 *
390
 * `extern(<linkage>) <decl...>`
391
 */
392
extern (C++) final class LinkDeclaration : AttribDeclaration
393
{
394
    LINK linkage; /// either explicitly set or `default_`
395

396 1
    extern (D) this(LINK linkage, Dsymbols* decl)
397
    {
398 1
        super(decl);
399
        //printf("LinkDeclaration(linkage = %d, decl = %p)\n", linkage, decl);
400 1
        this.linkage = (linkage == LINK.system) ? target.systemLinkage() : linkage;
401
    }
402

403
    static LinkDeclaration create(LINK p, Dsymbols* decl)
404
    {
405 0
        return new LinkDeclaration(p, decl);
406
    }
407

408
    override Dsymbol syntaxCopy(Dsymbol s)
409
    {
410 1
        assert(!s);
411 1
        return new LinkDeclaration(linkage, Dsymbol.arraySyntaxCopy(decl));
412
    }
413

414
    override Scope* newScope(Scope* sc)
415
    {
416 1
        return createNewScope(sc, sc.stc, this.linkage, sc.cppmangle, sc.protection, sc.explicitProtection,
417
            sc.aligndecl, sc.inlining);
418
    }
419

420
    override const(char)* toChars() const
421
    {
422 1
        return toString().ptr;
423
    }
424

425
    extern(D) override const(char)[] toString() const
426
    {
427 1
        return "extern ()";
428
    }
429

430
    override void accept(Visitor v)
431
    {
432 1
        v.visit(this);
433
    }
434
}
435

436
/***********************************************************
437
 * Attribute declaring whether an external aggregate should be mangled as
438
 * a struct or class in C++, e.g. `extern(C++, struct) class C { ... }`.
439
 * This is required for correct name mangling on MSVC targets,
440
 * see cppmanglewin.d for details.
441
 *
442
 * `extern(C++, <cppmangle>) <decl...>`
443
 */
444
extern (C++) final class CPPMangleDeclaration : AttribDeclaration
445
{
446
    CPPMANGLE cppmangle;
447

448 1
    extern (D) this(CPPMANGLE cppmangle, Dsymbols* decl)
449
    {
450 1
        super(decl);
451
        //printf("CPPMangleDeclaration(cppmangle = %d, decl = %p)\n", cppmangle, decl);
452 1
        this.cppmangle = cppmangle;
453
    }
454

455
    override Dsymbol syntaxCopy(Dsymbol s)
456
    {
457 0
        assert(!s);
458 0
        return new CPPMangleDeclaration(cppmangle, Dsymbol.arraySyntaxCopy(decl));
459
    }
460

461
    override Scope* newScope(Scope* sc)
462
    {
463 1
        return createNewScope(sc, sc.stc, LINK.cpp, cppmangle, sc.protection, sc.explicitProtection,
464
            sc.aligndecl, sc.inlining);
465
    }
466

467
    override void setScope(Scope* sc)
468
    {
469 1
        if (decl)
470 1
            Dsymbol.setScope(sc); // for forward reference
471 1
        return AttribDeclaration.setScope(sc);
472
    }
473

474
    override const(char)* toChars() const
475
    {
476 0
        return toString().ptr;
477
    }
478

479
    extern(D) override const(char)[] toString() const
480
    {
481 0
        return "extern ()";
482
    }
483

484
    override void accept(Visitor v)
485
    {
486 1
        v.visit(this);
487
    }
488
}
489

490
/**
491
 * A node to represent an `extern(C++)` namespace attribute
492
 *
493
 * There are two ways to declarate a symbol as member of a namespace:
494
 * `Nspace` and `CPPNamespaceDeclaration`.
495
 * The former creates a scope for the symbol, and inject them in the
496
 * parent scope at the same time.
497
 * The later, this class, has no semantic implications and is only
498
 * used for mangling.
499
 * Additionally, this class allows one to use reserved identifiers
500
 * (D keywords) in the namespace.
501
 *
502
 * A `CPPNamespaceDeclaration` can be created from an `Identifier`
503
 * (already resolved) or from an `Expression`, which is CTFE-ed
504
 * and can be either a `TupleExp`, in which can additional
505
 * `CPPNamespaceDeclaration` nodes are created, or a `StringExp`.
506
 *
507
 * Note that this class, like `Nspace`, matches only one identifier
508
 * part of a namespace. For the namespace `"foo::bar"`,
509
 * the will be a `CPPNamespaceDeclaration` with its `ident`
510
 * set to `"bar"`, and its `namespace` field pointing to another
511
 * `CPPNamespaceDeclaration` with its `ident` set to `"foo"`.
512
 */
513
extern (C++) final class CPPNamespaceDeclaration : AttribDeclaration
514
{
515
    /// CTFE-able expression, resolving to `TupleExp` or `StringExp`
516
    Expression exp;
517

518 0
    extern (D) this(Identifier ident, Dsymbols* decl)
519
    {
520 0
        super(decl);
521 0
        this.ident = ident;
522
    }
523

524 1
    extern (D) this(Expression exp, Dsymbols* decl)
525
    {
526 1
        super(decl);
527 1
        this.exp = exp;
528
    }
529

530 0
    extern (D) this(Identifier ident, Expression exp, Dsymbols* decl,
531
                    CPPNamespaceDeclaration parent)
532
    {
533 0
        super(decl);
534 0
        this.ident = ident;
535 0
        this.exp = exp;
536 0
        this.cppnamespace = parent;
537
    }
538

539
    override Dsymbol syntaxCopy(Dsymbol s)
540
    {
541 0
        assert(!s);
542 0
        return new CPPNamespaceDeclaration(
543
            this.ident, this.exp, Dsymbol.arraySyntaxCopy(this.decl), this.cppnamespace);
544
    }
545

546
    /**
547
     * Returns:
548
     *   A copy of the parent scope, with `this` as `namespace` and C++ linkage
549
     */
550
    override Scope* newScope(Scope* sc)
551
    {
552 1
        auto scx = sc.copy();
553 1
        scx.linkage = LINK.cpp;
554 1
        scx.namespace = this;
555 1
        return scx;
556
    }
557

558
    override const(char)* toChars() const
559
    {
560 0
        return toString().ptr;
561
    }
562

563
    extern(D) override const(char)[] toString() const
564
    {
565 0
        return "extern (C++, `namespace`)";
566
    }
567

568
    override void accept(Visitor v)
569
    {
570 1
        v.visit(this);
571
    }
572

573 1
    override inout(CPPNamespaceDeclaration) isCPPNamespaceDeclaration() inout { return this; }
574
}
575

576
/***********************************************************
577
 * Visibility declaration for Dsymbols, e.g. `public int i;`
578
 *
579
 * `<protection> <decl...>` or
580
 * `package(<pkg_identifiers>) <decl...>` if `pkg_identifiers !is null`
581
 */
582
extern (C++) final class ProtDeclaration : AttribDeclaration
583
{
584
    Prot protection;                /// the visibility
585
    Identifiers* pkg_identifiers;   /// identifiers for `package(foo.bar)` or null
586

587
    /**
588
     * Params:
589
     *  loc = source location of attribute token
590
     *  protection = protection attribute data
591
     *  decl = declarations which are affected by this protection attribute
592
     */
593 1
    extern (D) this(const ref Loc loc, Prot protection, Dsymbols* decl)
594
    {
595 1
        super(loc, null, decl);
596 1
        this.protection = protection;
597
        //printf("decl = %p\n", decl);
598
    }
599

600
    /**
601
     * Params:
602
     *  loc = source location of attribute token
603
     *  pkg_identifiers = list of identifiers for a qualified package name
604
     *  decl = declarations which are affected by this protection attribute
605
     */
606 1
    extern (D) this(const ref Loc loc, Identifiers* pkg_identifiers, Dsymbols* decl)
607
    {
608 1
        super(loc, null, decl);
609 1
        this.protection.kind = Prot.Kind.package_;
610 1
        this.pkg_identifiers = pkg_identifiers;
611 1
        if (pkg_identifiers !is null && pkg_identifiers.dim > 0)
612
        {
613 1
            Dsymbol tmp;
614 1
            Package.resolve(pkg_identifiers, &tmp, null);
615 1
            protection.pkg = tmp ? tmp.isPackage() : null;
616
        }
617
    }
618

619
    override Dsymbol syntaxCopy(Dsymbol s)
620
    {
621 1
        assert(!s);
622 1
        if (protection.kind == Prot.Kind.package_)
623 1
            return new ProtDeclaration(this.loc, pkg_identifiers, Dsymbol.arraySyntaxCopy(decl));
624
        else
625 1
            return new ProtDeclaration(this.loc, protection, Dsymbol.arraySyntaxCopy(decl));
626
    }
627

628
    override Scope* newScope(Scope* sc)
629
    {
630 1
        if (pkg_identifiers)
631 0
            dsymbolSemantic(this, sc);
632 1
        return createNewScope(sc, sc.stc, sc.linkage, sc.cppmangle, this.protection, 1, sc.aligndecl, sc.inlining);
633
    }
634

635
    override void addMember(Scope* sc, ScopeDsymbol sds)
636
    {
637 1
        if (pkg_identifiers)
638
        {
639 1
            Dsymbol tmp;
640 1
            Package.resolve(pkg_identifiers, &tmp, null);
641 1
            protection.pkg = tmp ? tmp.isPackage() : null;
642 1
            pkg_identifiers = null;
643
        }
644 1
        if (protection.kind == Prot.Kind.package_ && protection.pkg && sc._module)
645
        {
646 1
            Module m = sc._module;
647

648
            // While isAncestorPackageOf does an equality check, the fix for issue 17441 adds a check to see if
649
            // each package's .isModule() properites are equal.
650
            //
651
            // Properties generated from `package(foo)` i.e. protection.pkg have .isModule() == null.
652
            // This breaks package declarations of the package in question if they are declared in
653
            // the same package.d file, which _do_ have a module associated with them, and hence a non-null
654
            // isModule()
655 1
            if (!m.isPackage() || !protection.pkg.ident.equals(m.isPackage().ident))
656
            {
657 1
                Package pkg = m.parent ? m.parent.isPackage() : null;
658 1
                if (!pkg || !protection.pkg.isAncestorPackageOf(pkg))
659 1
                    error("does not bind to one of ancestor packages of module `%s`", m.toPrettyChars(true));
660
            }
661
        }
662 1
        return AttribDeclaration.addMember(sc, sds);
663
    }
664

665
    override const(char)* kind() const
666
    {
667 1
        return "protection attribute";
668
    }
669

670
    override const(char)* toPrettyChars(bool)
671
    {
672 1
        assert(protection.kind > Prot.Kind.undefined);
673 1
        OutBuffer buf;
674 1
        protectionToBuffer(&buf, protection);
675 1
        return buf.extractChars();
676
    }
677

678
    override inout(ProtDeclaration) isProtDeclaration() inout
679
    {
680 1
        return this;
681
    }
682

683
    override void accept(Visitor v)
684
    {
685 1
        v.visit(this);
686
    }
687
}
688

689
/***********************************************************
690
 * Alignment attribute for aggregates, members and variables.
691
 *
692
 * `align(<ealign>) <decl...>` or
693
 * `align <decl...>` if `ealign` is null
694
 */
695
extern (C++) final class AlignDeclaration : AttribDeclaration
696
{
697
    Expression ealign;                              /// expression yielding the actual alignment
698
    enum structalign_t UNKNOWN = 0;                 /// alignment not yet computed
699
    static assert(STRUCTALIGN_DEFAULT != UNKNOWN);
700

701
    /// the actual alignment, `UNKNOWN` until it's either set to the value of `ealign`
702
    /// or `STRUCTALIGN_DEFAULT` if `ealign` is null ( / an error ocurred)
703
    structalign_t salign = UNKNOWN;
704

705

706 1
    extern (D) this(const ref Loc loc, Expression ealign, Dsymbols* decl)
707
    {
708 1
        super(loc, null, decl);
709 1
        this.ealign = ealign;
710
    }
711

712
    override Dsymbol syntaxCopy(Dsymbol s)
713
    {
714 1
        assert(!s);
715 1
        return new AlignDeclaration(loc,
716 1
            ealign ? ealign.syntaxCopy() : null,
717
            Dsymbol.arraySyntaxCopy(decl));
718
    }
719

720
    override Scope* newScope(Scope* sc)
721
    {
722 1
        return createNewScope(sc, sc.stc, sc.linkage, sc.cppmangle, sc.protection, sc.explicitProtection, this, sc.inlining);
723
    }
724

725
    override void accept(Visitor v)
726
    {
727 1
        v.visit(this);
728
    }
729
}
730

731
/***********************************************************
732
 * An anonymous struct/union (defined by `isunion`).
733
 */
734
extern (C++) final class AnonDeclaration : AttribDeclaration
735
{
736
    bool isunion;           /// whether it's a union
737
    int sem;                /// 1 if successful semantic()
738
    uint anonoffset;        /// offset of anonymous struct
739
    uint anonstructsize;    /// size of anonymous struct
740
    uint anonalignsize;     /// size of anonymous struct for alignment purposes
741

742 1
    extern (D) this(const ref Loc loc, bool isunion, Dsymbols* decl)
743
    {
744 1
        super(loc, null, decl);
745 1
        this.isunion = isunion;
746
    }
747

748
    override Dsymbol syntaxCopy(Dsymbol s)
749
    {
750 1
        assert(!s);
751 1
        return new AnonDeclaration(loc, isunion, Dsymbol.arraySyntaxCopy(decl));
752
    }
753

754
    override void setScope(Scope* sc)
755
    {
756 1
        if (decl)
757 1
            Dsymbol.setScope(sc);
758 1
        return AttribDeclaration.setScope(sc);
759
    }
760

761
    override void setFieldOffset(AggregateDeclaration ad, uint* poffset, bool isunion)
762
    {
763
        //printf("\tAnonDeclaration::setFieldOffset %s %p\n", isunion ? "union" : "struct", this);
764 1
        if (decl)
765
        {
766
            /* This works by treating an AnonDeclaration as an aggregate 'member',
767
             * so in order to place that member we need to compute the member's
768
             * size and alignment.
769
             */
770 1
            size_t fieldstart = ad.fields.dim;
771

772
            /* Hackishly hijack ad's structsize and alignsize fields
773
             * for use in our fake anon aggregate member.
774
             */
775 1
            uint savestructsize = ad.structsize;
776 1
            uint savealignsize = ad.alignsize;
777 1
            ad.structsize = 0;
778 1
            ad.alignsize = 0;
779

780 1
            uint offset = 0;
781 1
            decl.foreachDsymbol( (s)
782
            {
783 1
                s.setFieldOffset(ad, &offset, this.isunion);
784 1
                if (this.isunion)
785 1
                    offset = 0;
786
            });
787

788
            /* https://issues.dlang.org/show_bug.cgi?id=13613
789
             * If the fields in this.members had been already
790
             * added in ad.fields, just update *poffset for the subsequent
791
             * field offset calculation.
792
             */
793 1
            if (fieldstart == ad.fields.dim)
794
            {
795 1
                ad.structsize = savestructsize;
796 1
                ad.alignsize = savealignsize;
797 1
                *poffset = ad.structsize;
798 1
                return;
799
            }
800

801 1
            anonstructsize = ad.structsize;
802 1
            anonalignsize = ad.alignsize;
803 1
            ad.structsize = savestructsize;
804 1
            ad.alignsize = savealignsize;
805

806
            // 0 sized structs are set to 1 byte
807 1
            if (anonstructsize == 0)
808
            {
809 0
                anonstructsize = 1;
810 0
                anonalignsize = 1;
811
            }
812

813 1
            assert(_scope);
814 1
            auto alignment = _scope.alignment();
815

816
            /* Given the anon 'member's size and alignment,
817
             * go ahead and place it.
818
             */
819 1
            anonoffset = AggregateDeclaration.placeField(
820
                poffset,
821
                anonstructsize, anonalignsize, alignment,
822
                &ad.structsize, &ad.alignsize,
823
                isunion);
824

825
            // Add to the anon fields the base offset of this anonymous aggregate
826
            //printf("anon fields, anonoffset = %d\n", anonoffset);
827 1
            foreach (const i; fieldstart .. ad.fields.dim)
828
            {
829 1
                VarDeclaration v = ad.fields[i];
830
                //printf("\t[%d] %s %d\n", i, v.toChars(), v.offset);
831 1
                v.offset += anonoffset;
832
            }
833
        }
834
    }
835

836
    override const(char)* kind() const
837
    {
838 1
        return (isunion ? "anonymous union" : "anonymous struct");
839
    }
840

841
    override inout(AnonDeclaration) isAnonDeclaration() inout
842
    {
843 1
        return this;
844
    }
845

846
    override void accept(Visitor v)
847
    {
848 1
        v.visit(this);
849
    }
850
}
851

852
/***********************************************************
853
 * Pragma applied to Dsymbols, e.g. `pragma(inline, true) void foo`,
854
 * but not PragmaStatement's like `pragma(msg, "hello");`.
855
 *
856
 * pragma(<ident>, <args>)
857
 */
858
extern (C++) final class PragmaDeclaration : AttribDeclaration
859
{
860
    Expressions* args;      /// parameters of this pragma
861

862 1
    extern (D) this(const ref Loc loc, Identifier ident, Expressions* args, Dsymbols* decl)
863
    {
864 1
        super(loc, ident, decl);
865 1
        this.args = args;
866
    }
867

868
    override Dsymbol syntaxCopy(Dsymbol s)
869
    {
870
        //printf("PragmaDeclaration::syntaxCopy(%s)\n", toChars());
871 1
        assert(!s);
872 1
        return new PragmaDeclaration(loc, ident, Expression.arraySyntaxCopy(args), Dsymbol.arraySyntaxCopy(decl));
873
    }
874

875
    override Scope* newScope(Scope* sc)
876
    {
877 1
        if (ident == Id.Pinline)
878
        {
879 1
            PINLINE inlining = PINLINE.default_;
880 1
            if (!args || args.dim == 0)
881 1
                inlining = PINLINE.default_;
882 1
            else if (args.dim != 1)
883
            {
884 1
                error("one boolean expression expected for `pragma(inline)`, not %llu", cast(ulong) args.dim);
885 1
                args.setDim(1);
886 1
                (*args)[0] = ErrorExp.get();
887
            }
888
            else
889
            {
890 1
                Expression e = (*args)[0];
891 1
                if (e.op != TOK.int64 || !e.type.equals(Type.tbool))
892
                {
893 1
                    if (e.op != TOK.error)
894
                    {
895 1
                        error("pragma(`inline`, `true` or `false`) expected, not `%s`", e.toChars());
896 1
                        (*args)[0] = ErrorExp.get();
897
                    }
898
                }
899 1
                else if (e.isBool(true))
900 1
                    inlining = PINLINE.always;
901 1
                else if (e.isBool(false))
902 1
                    inlining = PINLINE.never;
903
            }
904 1
            return createNewScope(sc, sc.stc, sc.linkage, sc.cppmangle, sc.protection, sc.explicitProtection, sc.aligndecl, inlining);
905
        }
906 1
        if (ident == Id.printf || ident == Id.scanf)
907
        {
908 1
            auto sc2 = sc.push();
909

910 1
            if (ident == Id.printf)
911
                // Override previous setting, never let both be set
912 1
                sc2.flags = (sc2.flags & ~SCOPE.scanf) | SCOPE.printf;
913
            else
914 1
                sc2.flags = (sc2.flags & ~SCOPE.printf) | SCOPE.scanf;
915

916 1
            return sc2;
917
        }
918 1
        return sc;
919
    }
920

921
    override const(char)* kind() const
922
    {
923 1
        return "pragma";
924
    }
925

926
    override void accept(Visitor v)
927
    {
928 1
        v.visit(this);
929
    }
930
}
931

932
/***********************************************************
933
 * A conditional compilation declaration, used for `version`
934
 * / `debug` and specialized for `static if`.
935
 *
936
 * <condition> { <decl...> } else { <elsedecl> }
937
 */
938
extern (C++) class ConditionalDeclaration : AttribDeclaration
939
{
940
    Condition condition;    /// condition deciding whether decl or elsedecl applies
941
    Dsymbols* elsedecl;     /// array of Dsymbol's for else block
942

943 1
    extern (D) this(Condition condition, Dsymbols* decl, Dsymbols* elsedecl)
944
    {
945 1
        super(decl);
946
        //printf("ConditionalDeclaration::ConditionalDeclaration()\n");
947 1
        this.condition = condition;
948 1
        this.elsedecl = elsedecl;
949
    }
950

951
    override Dsymbol syntaxCopy(Dsymbol s)
952
    {
953 1
        assert(!s);
954 1
        return new ConditionalDeclaration(condition.syntaxCopy(), Dsymbol.arraySyntaxCopy(decl), Dsymbol.arraySyntaxCopy(elsedecl));
955
    }
956

957
    override final bool oneMember(Dsymbol* ps, Identifier ident)
958
    {
959
        //printf("ConditionalDeclaration::oneMember(), inc = %d\n", condition.inc);
960 1
        if (condition.inc != Include.notComputed)
961
        {
962 1
            Dsymbols* d = condition.include(null) ? decl : elsedecl;
963 1
            return Dsymbol.oneMembers(d, ps, ident);
964
        }
965
        else
966
        {
967 1
            bool res = (Dsymbol.oneMembers(decl, ps, ident) && *ps is null && Dsymbol.oneMembers(elsedecl, ps, ident) && *ps is null);
968 1
            *ps = null;
969 1
            return res;
970
        }
971
    }
972

973
    // Decide if 'then' or 'else' code should be included
974
    override Dsymbols* include(Scope* sc)
975
    {
976
        //printf("ConditionalDeclaration::include(sc = %p) scope = %p\n", sc, scope);
977

978 1
        if (errors)
979 0
            return null;
980

981 1
        assert(condition);
982 1
        return condition.include(_scope ? _scope : sc) ? decl : elsedecl;
983
    }
984

985
    override final void addComment(const(char)* comment)
986
    {
987
        /* Because addComment is called by the parser, if we called
988
         * include() it would define a version before it was used.
989
         * But it's no problem to drill down to both decl and elsedecl,
990
         * so that's the workaround.
991
         */
992 1
        if (comment)
993
        {
994 1
            decl    .foreachDsymbol( s => s.addComment(comment) );
995 1
            elsedecl.foreachDsymbol( s => s.addComment(comment) );
996
        }
997
    }
998

999
    override void setScope(Scope* sc)
1000
    {
1001 1
        include(sc).foreachDsymbol( s => s.setScope(sc) );
1002
    }
1003

1004
    override void accept(Visitor v)
1005
    {
1006 1
        v.visit(this);
1007
    }
1008
}
1009

1010
/***********************************************************
1011
 * `<scopesym> {
1012
 *      static if (<condition>) { <decl> } else { <elsedecl> }
1013
 * }`
1014
 */
1015
extern (C++) final class StaticIfDeclaration : ConditionalDeclaration
1016
{
1017
    ScopeDsymbol scopesym;          /// enclosing symbol (e.g. module) where symbols will be inserted
1018
    private bool addisdone = false; /// true if members have been added to scope
1019
    private bool onStack = false;   /// true if a call to `include` is currently active
1020

1021 1
    extern (D) this(Condition condition, Dsymbols* decl, Dsymbols* elsedecl)
1022
    {
1023 1
        super(condition, decl, elsedecl);
1024
        //printf("StaticIfDeclaration::StaticIfDeclaration()\n");
1025
    }
1026

1027
    override Dsymbol syntaxCopy(Dsymbol s)
1028
    {
1029 1
        assert(!s);
1030 1
        return new StaticIfDeclaration(condition.syntaxCopy(), Dsymbol.arraySyntaxCopy(decl), Dsymbol.arraySyntaxCopy(elsedecl));
1031
    }
1032

1033
    /****************************************
1034
     * Different from other AttribDeclaration subclasses, include() call requires
1035
     * the completion of addMember and setScope phases.
1036
     */
1037
    override Dsymbols* include(Scope* sc)
1038
    {
1039
        //printf("StaticIfDeclaration::include(sc = %p) scope = %p\n", sc, scope);
1040

1041 1
        if (errors || onStack)
1042 1
            return null;
1043 1
        onStack = true;
1044 1
        scope(exit) onStack = false;
1045

1046 1
        if (sc && condition.inc == Include.notComputed)
1047
        {
1048 1
            assert(scopesym); // addMember is already done
1049 1
            assert(_scope); // setScope is already done
1050 1
            Dsymbols* d = ConditionalDeclaration.include(_scope);
1051 1
            if (d && !addisdone)
1052
            {
1053
                // Add members lazily.
1054 1
                d.foreachDsymbol( s => s.addMember(_scope, scopesym) );
1055

1056
                // Set the member scopes lazily.
1057 1
                d.foreachDsymbol( s => s.setScope(_scope) );
1058

1059 1
                addisdone = true;
1060
            }
1061 1
            return d;
1062
        }
1063
        else
1064
        {
1065 1
            return ConditionalDeclaration.include(sc);
1066
        }
1067
    }
1068

1069
    override void addMember(Scope* sc, ScopeDsymbol sds)
1070
    {
1071
        //printf("StaticIfDeclaration::addMember() '%s'\n", toChars());
1072
        /* This is deferred until the condition evaluated later (by the include() call),
1073
         * so that expressions in the condition can refer to declarations
1074
         * in the same scope, such as:
1075
         *
1076
         * template Foo(int i)
1077
         * {
1078
         *     const int j = i + 1;
1079
         *     static if (j == 3)
1080
         *         const int k;
1081
         * }
1082
         */
1083 1
        this.scopesym = sds;
1084
    }
1085

1086
    override void setScope(Scope* sc)
1087
    {
1088
        // do not evaluate condition before semantic pass
1089
        // But do set the scope, in case we need it for forward referencing
1090 1
        Dsymbol.setScope(sc);
1091
    }
1092

1093
    override void importAll(Scope* sc)
1094
    {
1095
        // do not evaluate condition before semantic pass
1096
    }
1097

1098
    override const(char)* kind() const
1099
    {
1100 0
        return "static if";
1101
    }
1102

1103
    override void accept(Visitor v)
1104
    {
1105 1
        v.visit(this);
1106
    }
1107
}
1108

1109
/***********************************************************
1110
 * Static foreach at declaration scope, like:
1111
 *     static foreach (i; [0, 1, 2]){ }
1112
 */
1113

1114
extern (C++) final class StaticForeachDeclaration : AttribDeclaration
1115
{
1116
    StaticForeach sfe; /// contains `static foreach` expansion logic
1117

1118
    ScopeDsymbol scopesym; /// cached enclosing scope (mimics `static if` declaration)
1119

1120
    /++
1121
     `include` can be called multiple times, but a `static foreach`
1122
     should be expanded at most once.  Achieved by caching the result
1123
     of the first call.  We need both `cached` and `cache`, because
1124
     `null` is a valid value for `cache`.
1125
     +/
1126
    bool onStack = false;
1127
    bool cached = false;
1128
    Dsymbols* cache = null;
1129

1130 1
    extern (D) this(StaticForeach sfe, Dsymbols* decl)
1131
    {
1132 1
        super(decl);
1133 1
        this.sfe = sfe;
1134
    }
1135

1136
    override Dsymbol syntaxCopy(Dsymbol s)
1137
    {
1138 1
        assert(!s);
1139 1
        return new StaticForeachDeclaration(
1140
            sfe.syntaxCopy(),
1141
            Dsymbol.arraySyntaxCopy(decl));
1142
    }
1143

1144
    override bool oneMember(Dsymbol* ps, Identifier ident)
1145
    {
1146
        // Required to support IFTI on a template that contains a
1147
        // `static foreach` declaration.  `super.oneMember` calls
1148
        // include with a `null` scope.  As `static foreach` requires
1149
        // the scope for expansion, `oneMember` can only return a
1150
        // precise result once `static foreach` has been expanded.
1151 1
        if (cached)
1152
        {
1153 1
            return super.oneMember(ps, ident);
1154
        }
1155 1
        *ps = null; // a `static foreach` declaration may in general expand to multiple symbols
1156 1
        return false;
1157
    }
1158

1159
    override Dsymbols* include(Scope* sc)
1160
    {
1161 1
        if (errors || onStack)
1162 1
            return null;
1163 1
        if (cached)
1164
        {
1165 1
            assert(!onStack);
1166 1
            return cache;
1167
        }
1168 1
        onStack = true;
1169 1
        scope(exit) onStack = false;
1170

1171 1
        if (_scope)
1172
        {
1173 1
            sfe.prepare(_scope); // lower static foreach aggregate
1174
        }
1175 1
        if (!sfe.ready())
1176
        {
1177 1
            return null; // TODO: ok?
1178
        }
1179

1180
        // expand static foreach
1181
        import dmd.statementsem: makeTupleForeach;
1182 1
        Dsymbols* d = makeTupleForeach!(true,true)(_scope, sfe.aggrfe, decl, sfe.needExpansion);
1183 1
        if (d) // process generated declarations
1184
        {
1185
            // Add members lazily.
1186 1
            d.foreachDsymbol( s => s.addMember(_scope, scopesym) );
1187

1188
            // Set the member scopes lazily.
1189 1
            d.foreachDsymbol( s => s.setScope(_scope) );
1190
        }
1191 1
        cached = true;
1192 1
        cache = d;
1193 1
        return d;
1194
    }
1195

1196
    override void addMember(Scope* sc, ScopeDsymbol sds)
1197
    {
1198
        // used only for caching the enclosing symbol
1199 1
        this.scopesym = sds;
1200
    }
1201

1202
    override void addComment(const(char)* comment)
1203
    {
1204
        // do nothing
1205
        // change this to give semantics to documentation comments on static foreach declarations
1206
    }
1207

1208
    override void setScope(Scope* sc)
1209
    {
1210
        // do not evaluate condition before semantic pass
1211
        // But do set the scope, in case we need it for forward referencing
1212 1
        Dsymbol.setScope(sc);
1213
    }
1214

1215
    override void importAll(Scope* sc)
1216
    {
1217
        // do not evaluate aggregate before semantic pass
1218
    }
1219

1220
    override const(char)* kind() const
1221
    {
1222 0
        return "static foreach";
1223
    }
1224

1225
    override void accept(Visitor v)
1226
    {
1227 1
        v.visit(this);
1228
    }
1229
}
1230

1231
/***********************************************************
1232
 * Collection of declarations that stores foreach index variables in a
1233
 * local symbol table.  Other symbols declared within are forwarded to
1234
 * another scope, like:
1235
 *
1236
 *      static foreach (i; 0 .. 10) // loop variables for different indices do not conflict.
1237
 *      { // this body is expanded into 10 ForwardingAttribDeclarations, where `i` has storage class STC.local
1238
 *          mixin("enum x" ~ to!string(i) ~ " = i"); // ok, can access current loop variable
1239
 *      }
1240
 *
1241
 *      static foreach (i; 0.. 10)
1242
 *      {
1243
 *          pragma(msg, mixin("x" ~ to!string(i))); // ok, all 10 symbols are visible as they were forwarded to the global scope
1244
 *      }
1245
 *
1246
 *      static assert (!is(typeof(i))); // loop index variable is not visible outside of the static foreach loop
1247
 *
1248
 * A StaticForeachDeclaration generates one
1249
 * ForwardingAttribDeclaration for each expansion of its body.  The
1250
 * AST of the ForwardingAttribDeclaration contains both the `static
1251
 * foreach` variables and the respective copy of the `static foreach`
1252
 * body.  The functionality is achieved by using a
1253
 * ForwardingScopeDsymbol as the parent symbol for the generated
1254
 * declarations.
1255
 */
1256

1257
extern(C++) final class ForwardingAttribDeclaration: AttribDeclaration
1258
{
1259
    ForwardingScopeDsymbol sym = null;
1260

1261 1
    this(Dsymbols* decl)
1262
    {
1263 1
        super(decl);
1264 1
        sym = new ForwardingScopeDsymbol(null);
1265 1
        sym.symtab = new DsymbolTable();
1266
    }
1267

1268
    /**************************************
1269
     * Use the ForwardingScopeDsymbol as the parent symbol for members.
1270
     */
1271
    override Scope* newScope(Scope* sc)
1272
    {
1273 1
        return sc.push(sym);
1274
    }
1275

1276
    /***************************************
1277
     * Lazily initializes the scope to forward to.
1278
     */
1279
    override void addMember(Scope* sc, ScopeDsymbol sds)
1280
    {
1281 1
        parent = sym.parent = sym.forward = sds;
1282 1
        return super.addMember(sc, sym);
1283
    }
1284

1285
    override inout(ForwardingAttribDeclaration) isForwardingAttribDeclaration() inout
1286
    {
1287 0
        return this;
1288
    }
1289

1290
    override void accept(Visitor v)
1291
    {
1292 1
        v.visit(this);
1293
    }
1294
}
1295

1296

1297
/***********************************************************
1298
 * Mixin declarations, like:
1299
 *      mixin("int x");
1300
 * https://dlang.org/spec/module.html#mixin-declaration
1301
 */
1302
extern (C++) final class CompileDeclaration : AttribDeclaration
1303
{
1304
    Expressions* exps;
1305
    ScopeDsymbol scopesym;
1306
    bool compiled;
1307

1308 1
    extern (D) this(const ref Loc loc, Expressions* exps)
1309
    {
1310 1
        super(loc, null, null);
1311
        //printf("CompileDeclaration(loc = %d)\n", loc.linnum);
1312 1
        this.exps = exps;
1313
    }
1314

1315
    override Dsymbol syntaxCopy(Dsymbol s)
1316
    {
1317
        //printf("CompileDeclaration::syntaxCopy('%s')\n", toChars());
1318 1
        return new CompileDeclaration(loc, Expression.arraySyntaxCopy(exps));
1319
    }
1320

1321
    override void addMember(Scope* sc, ScopeDsymbol sds)
1322
    {
1323
        //printf("CompileDeclaration::addMember(sc = %p, sds = %p, memnum = %d)\n", sc, sds, memnum);
1324 1
        this.scopesym = sds;
1325
    }
1326

1327
    override void setScope(Scope* sc)
1328
    {
1329 1
        Dsymbol.setScope(sc);
1330
    }
1331

1332
    override const(char)* kind() const
1333
    {
1334 0
        return "mixin";
1335
    }
1336

1337
    override inout(CompileDeclaration) isCompileDeclaration() inout
1338
    {
1339 1
        return this;
1340
    }
1341

1342
    override void accept(Visitor v)
1343
    {
1344 1
        v.visit(this);
1345
    }
1346
}
1347

1348
/***********************************************************
1349
 * User defined attributes look like:
1350
 *      @foo(args, ...)
1351
 *      @(args, ...)
1352
 */
1353
extern (C++) final class UserAttributeDeclaration : AttribDeclaration
1354
{
1355
    Expressions* atts;
1356

1357 1
    extern (D) this(Expressions* atts, Dsymbols* decl)
1358
    {
1359 1
        super(decl);
1360
        //printf("UserAttributeDeclaration()\n");
1361 1
        this.atts = atts;
1362
    }
1363

1364
    override Dsymbol syntaxCopy(Dsymbol s)
1365
    {
1366
        //printf("UserAttributeDeclaration::syntaxCopy('%s')\n", toChars());
1367 1
        assert(!s);
1368 1
        return new UserAttributeDeclaration(Expression.arraySyntaxCopy(this.atts), Dsymbol.arraySyntaxCopy(decl));
1369
    }
1370

1371
    override Scope* newScope(Scope* sc)
1372
    {
1373 1
        Scope* sc2 = sc;
1374 1
        if (atts && atts.dim)
1375
        {
1376
            // create new one for changes
1377 1
            sc2 = sc.copy();
1378 1
            sc2.userAttribDecl = this;
1379
        }
1380 1
        return sc2;
1381
    }
1382

1383
    override void setScope(Scope* sc)
1384
    {
1385
        //printf("UserAttributeDeclaration::setScope() %p\n", this);
1386 1
        if (decl)
1387 1
            Dsymbol.setScope(sc); // for forward reference of UDAs
1388 1
        return AttribDeclaration.setScope(sc);
1389
    }
1390

1391
    extern (D) static Expressions* concat(Expressions* udas1, Expressions* udas2)
1392
    {
1393 1
        Expressions* udas;
1394 1
        if (!udas1 || udas1.dim == 0)
1395 1
            udas = udas2;
1396 1
        else if (!udas2 || udas2.dim == 0)
1397 1
            udas = udas1;
1398
        else
1399
        {
1400
            /* Create a new tuple that combines them
1401
             * (do not append to left operand, as this is a copy-on-write operation)
1402
             */
1403 1
            udas = new Expressions(2);
1404 1
            (*udas)[0] = new TupleExp(Loc.initial, udas1);
1405 1
            (*udas)[1] = new TupleExp(Loc.initial, udas2);
1406
        }
1407 1
        return udas;
1408
    }
1409

1410
    Expressions* getAttributes()
1411
    {
1412 1
        if (auto sc = _scope)
1413
        {
1414 1
            _scope = null;
1415 1
            arrayExpressionSemantic(atts, sc);
1416
        }
1417 1
        auto exps = new Expressions();
1418 1
        if (userAttribDecl && userAttribDecl !is this)
1419 1
            exps.push(new TupleExp(Loc.initial, userAttribDecl.getAttributes()));
1420 1
        if (atts && atts.dim)
1421 1
            exps.push(new TupleExp(Loc.initial, atts));
1422 1
        return exps;
1423
    }
1424

1425
    override const(char)* kind() const
1426
    {
1427 0
        return "UserAttribute";
1428
    }
1429

1430
    override void accept(Visitor v)
1431
    {
1432 1
        v.visit(this);
1433
    }
1434

1435
    /**
1436
     * Check if the provided expression references `core.attribute.gnuAbiTag`
1437
     *
1438
     * This should be called after semantic has been run on the expression.
1439
     * Semantic on UDA happens in semantic2 (see `dmd.semantic2`).
1440
     *
1441
     * Params:
1442
     *   e = Expression to check (usually from `UserAttributeDeclaration.atts`)
1443
     *
1444
     * Returns:
1445
     *   `true` if the expression references the compiler-recognized `gnuAbiTag`
1446
     */
1447
    static bool isGNUABITag(Expression e)
1448
    {
1449 1
        if (global.params.cplusplus < CppStdRevision.cpp11)
1450 1
            return false;
1451

1452 1
        auto ts = e.type ? e.type.isTypeStruct() : null;
1453 1
        if (!ts)
1454 1
            return false;
1455 1
        if (ts.sym.ident != Id.udaGNUAbiTag || !ts.sym.parent)
1456 0
            return false;
1457
        // Can only be defined in druntime
1458 1
        Module m = ts.sym.parent.isModule();
1459 1
        if (!m || !m.isCoreModule(Id.attribute))
1460 1
            return false;
1461 1
        return true;
1462
    }
1463

1464
    /**
1465
     * Called from a symbol's semantic to check if `gnuAbiTag` UDA
1466
     * can be applied to them
1467
     *
1468
     * Directly emits an error if the UDA doesn't work with this symbol
1469
     *
1470
     * Params:
1471
     *   sym = symbol to check for `gnuAbiTag`
1472
     *   linkage = Linkage of the symbol (Declaration.link or sc.link)
1473
     */
1474
    static void checkGNUABITag(Dsymbol sym, LINK linkage)
1475
    {
1476 1
        if (global.params.cplusplus < CppStdRevision.cpp11)
1477 1
            return;
1478

1479
        // Avoid `if` at the call site
1480 1
        if (sym.userAttribDecl is null || sym.userAttribDecl.atts is null)
1481 1
            return;
1482

1483 1
        foreach (exp; *sym.userAttribDecl.atts)
1484
        {
1485 1
            if (isGNUABITag(exp))
1486
            {
1487 1
                if (sym.isCPPNamespaceDeclaration() || sym.isNspace())
1488
                {
1489 1
                    exp.error("`@%s` cannot be applied to namespaces", Id.udaGNUAbiTag.toChars());
1490 1
                    sym.errors = true;
1491
                }
1492 1
                else if (linkage != LINK.cpp)
1493
                {
1494 1
                    exp.error("`@%s` can only apply to C++ symbols", Id.udaGNUAbiTag.toChars());
1495 1
                    sym.errors = true;
1496
                }
1497
                // Only one `@gnuAbiTag` is allowed by semantic2
1498 1
                return;
1499
            }
1500
        }
1501
    }
1502
}

Read our documentation on viewing source code .

Loading