1
/**
2
 * Struct and union declarations.
3
 *
4
 * Specification: $(LINK2 https://dlang.org/spec/struct.html, Structs, Unions)
5
 *
6
 * Copyright:   Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved
7
 * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
8
 * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
9
 * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/dstruct.d, _dstruct.d)
10
 * Documentation:  https://dlang.org/phobos/dmd_dstruct.html
11
 * Coverage:    https://codecov.io/gh/dlang/dmd/src/master/src/dmd/dstruct.d
12
 */
13

14
module dmd.dstruct;
15

16
import dmd.aggregate;
17
import dmd.arraytypes;
18
import dmd.declaration;
19
import dmd.dmodule;
20
import dmd.dscope;
21
import dmd.dsymbol;
22
import dmd.dsymbolsem;
23
import dmd.dtemplate;
24
import dmd.errors;
25
import dmd.expression;
26
import dmd.expressionsem;
27
import dmd.func;
28
import dmd.globals;
29
import dmd.id;
30
import dmd.identifier;
31
import dmd.mtype;
32
import dmd.opover;
33
import dmd.semantic3;
34
import dmd.target;
35
import dmd.tokens;
36
import dmd.typesem;
37
import dmd.typinf;
38
import dmd.visitor;
39

40
/***************************************
41
 * Search sd for a member function of the form:
42
 *   `extern (D) string toString();`
43
 * Params:
44
 *   sd = struct declaration to search
45
 * Returns:
46
 *   FuncDeclaration of `toString()` if found, `null` if not
47
 */
48
extern (C++) FuncDeclaration search_toString(StructDeclaration sd)
49
{
50 1
    Dsymbol s = search_function(sd, Id.tostring);
51 1
    FuncDeclaration fd = s ? s.isFuncDeclaration() : null;
52 1
    if (fd)
53
    {
54 1
        __gshared TypeFunction tftostring;
55 1
        if (!tftostring)
56
        {
57 1
            tftostring = new TypeFunction(ParameterList(), Type.tstring, LINK.d);
58 1
            tftostring = tftostring.merge().toTypeFunction();
59
        }
60 1
        fd = fd.overloadExactMatch(tftostring);
61
    }
62 1
    return fd;
63
}
64

65
/***************************************
66
 * Request additional semantic analysis for TypeInfo generation.
67
 * Params:
68
 *      sc = context
69
 *      t = type that TypeInfo is being generated for
70
 */
71
extern (C++) void semanticTypeInfo(Scope* sc, Type t)
72
{
73 1
    if (sc)
74
    {
75 1
        if (sc.intypeof)
76 1
            return;
77 1
        if (sc.flags & (SCOPE.ctfe | SCOPE.compile))
78 1
            return;
79
    }
80

81 1
    if (!t)
82 1
        return;
83

84
    void visitVector(TypeVector t)
85
    {
86 1
        semanticTypeInfo(sc, t.basetype);
87
    }
88

89
    void visitAArray(TypeAArray t)
90
    {
91 1
        semanticTypeInfo(sc, t.index);
92 1
        semanticTypeInfo(sc, t.next);
93
    }
94

95
    void visitStruct(TypeStruct t)
96
    {
97
        //printf("semanticTypeInfo.visit(TypeStruct = %s)\n", t.toChars());
98 1
        StructDeclaration sd = t.sym;
99

100
        /* Step 1: create TypeInfoDeclaration
101
         */
102 1
        if (!sc) // inline may request TypeInfo.
103
        {
104 1
            Scope scx;
105 1
            scx._module = sd.getModule();
106 1
            getTypeInfoType(sd.loc, t, &scx);
107 1
            sd.requestTypeInfo = true;
108
        }
109 1
        else if (!sc.minst)
110
        {
111
            // don't yet have to generate TypeInfo instance if
112
            // the typeid(T) expression exists in speculative scope.
113
        }
114
        else
115
        {
116 1
            getTypeInfoType(sd.loc, t, sc);
117 1
            sd.requestTypeInfo = true;
118

119
            // https://issues.dlang.org/show_bug.cgi?id=15149
120
            // if the typeid operand type comes from a
121
            // result of auto function, it may be yet speculative.
122
            // unSpeculative(sc, sd);
123
        }
124

125
        /* Step 2: If the TypeInfo generation requires sd.semantic3, run it later.
126
         * This should be done even if typeid(T) exists in speculative scope.
127
         * Because it may appear later in non-speculative scope.
128
         */
129 1
        if (!sd.members)
130 1
            return; // opaque struct
131 1
        if (!sd.xeq && !sd.xcmp && !sd.postblit && !sd.dtor && !sd.xhash && !search_toString(sd))
132 1
            return; // none of TypeInfo-specific members
133

134
        // If the struct is in a non-root module, run semantic3 to get
135
        // correct symbols for the member function.
136 1
        if (sd.semanticRun >= PASS.semantic3)
137
        {
138
            // semantic3 is already done
139
        }
140 1
        else if (TemplateInstance ti = sd.isInstantiated())
141
        {
142 1
            if (ti.minst && !ti.minst.isRoot())
143 1
                Module.addDeferredSemantic3(sd);
144
        }
145
        else
146
        {
147 1
            if (sd.inNonRoot())
148
            {
149
                //printf("deferred sem3 for TypeInfo - sd = %s, inNonRoot = %d\n", sd.toChars(), sd.inNonRoot());
150 1
                Module.addDeferredSemantic3(sd);
151
            }
152
        }
153
    }
154

155
    void visitTuple(TypeTuple t)
156
    {
157 1
        if (t.arguments)
158
        {
159 1
            foreach (arg; *t.arguments)
160
            {
161 1
                semanticTypeInfo(sc, arg.type);
162
            }
163
        }
164
    }
165

166
    /* Note structural similarity of this Type walker to that in isSpeculativeType()
167
     */
168

169 1
    Type tb = t.toBasetype();
170 1
    switch (tb.ty)
171
    {
172 1
        case Tvector:   visitVector(tb.isTypeVector()); break;
173 1
        case Taarray:   visitAArray(tb.isTypeAArray()); break;
174 1
        case Tstruct:   visitStruct(tb.isTypeStruct()); break;
175 1
        case Ttuple:    visitTuple (tb.isTypeTuple());  break;
176

177 1
        case Tclass:
178 1
        case Tenum:     break;
179

180 1
        default:        semanticTypeInfo(sc, tb.nextOf()); break;
181
    }
182
}
183

184
enum StructFlags : int
185
{
186
    none        = 0x0,
187
    hasPointers = 0x1, // NB: should use noPointers as in ClassFlags
188
}
189

190
enum StructPOD : int
191
{
192
    no,    // struct is not POD
193
    yes,   // struct is POD
194
    fwd,   // POD not yet computed
195
}
196

197
/***********************************************************
198
 * All `struct` declarations are an instance of this.
199
 */
200
extern (C++) class StructDeclaration : AggregateDeclaration
201
{
202
    bool zeroInit;              // !=0 if initialize with 0 fill
203
    bool hasIdentityAssign;     // true if has identity opAssign
204
    bool hasBlitAssign;         // true if opAssign is a blit
205
    bool hasIdentityEquals;     // true if has identity opEquals
206
    bool hasNoFields;           // has no fields
207
    bool hasCopyCtor;           // copy constructor
208
    // Even if struct is defined as non-root symbol, some built-in operations
209
    // (e.g. TypeidExp, NewExp, ArrayLiteralExp, etc) request its TypeInfo.
210
    // For those, today TypeInfo_Struct is generated in COMDAT.
211
    bool requestTypeInfo;
212

213
    FuncDeclarations postblits; // Array of postblit functions
214
    FuncDeclaration postblit;   // aggregate postblit
215

216
    FuncDeclaration xeq;        // TypeInfo_Struct.xopEquals
217
    FuncDeclaration xcmp;       // TypeInfo_Struct.xopCmp
218
    FuncDeclaration xhash;      // TypeInfo_Struct.xtoHash
219
    extern (C++) __gshared FuncDeclaration xerreq;   // object.xopEquals
220
    extern (C++) __gshared FuncDeclaration xerrcmp;  // object.xopCmp
221

222
    structalign_t alignment;    // alignment applied outside of the struct
223
    StructPOD ispod;            // if struct is POD
224

225
    // ABI-specific type(s) if the struct can be passed in registers
226
    TypeTuple argTypes;
227

228 1
    extern (D) this(const ref Loc loc, Identifier id, bool inObject)
229
    {
230 1
        super(loc, id);
231 1
        zeroInit = false; // assume false until we do semantic processing
232 1
        ispod = StructPOD.fwd;
233
        // For forward references
234 1
        type = new TypeStruct(this);
235

236 1
        if (inObject)
237
        {
238 1
            if (id == Id.ModuleInfo && !Module.moduleinfo)
239 1
                Module.moduleinfo = this;
240
        }
241
    }
242

243
    static StructDeclaration create(Loc loc, Identifier id, bool inObject)
244
    {
245 0
        return new StructDeclaration(loc, id, inObject);
246
    }
247

248
    override Dsymbol syntaxCopy(Dsymbol s)
249
    {
250 1
        StructDeclaration sd =
251 1
            s ? cast(StructDeclaration)s
252 1
              : new StructDeclaration(loc, ident, false);
253 1
        return ScopeDsymbol.syntaxCopy(sd);
254
    }
255

256
    final void semanticTypeInfoMembers()
257
    {
258 1
        if (xeq &&
259 1
            xeq._scope &&
260 1
            xeq.semanticRun < PASS.semantic3done)
261
        {
262 1
            uint errors = global.startGagging();
263 1
            xeq.semantic3(xeq._scope);
264 1
            if (global.endGagging(errors))
265 1
                xeq = xerreq;
266
        }
267

268 1
        if (xcmp &&
269 1
            xcmp._scope &&
270 1
            xcmp.semanticRun < PASS.semantic3done)
271
        {
272 1
            uint errors = global.startGagging();
273 1
            xcmp.semantic3(xcmp._scope);
274 1
            if (global.endGagging(errors))
275 1
                xcmp = xerrcmp;
276
        }
277

278 1
        FuncDeclaration ftostr = search_toString(this);
279 1
        if (ftostr &&
280 1
            ftostr._scope &&
281 1
            ftostr.semanticRun < PASS.semantic3done)
282
        {
283 0
            ftostr.semantic3(ftostr._scope);
284
        }
285

286 1
        if (xhash &&
287 1
            xhash._scope &&
288 1
            xhash.semanticRun < PASS.semantic3done)
289
        {
290 1
            xhash.semantic3(xhash._scope);
291
        }
292

293 1
        if (postblit &&
294 1
            postblit._scope &&
295 1
            postblit.semanticRun < PASS.semantic3done)
296
        {
297 1
            postblit.semantic3(postblit._scope);
298
        }
299

300 1
        if (dtor &&
301 1
            dtor._scope &&
302 1
            dtor.semanticRun < PASS.semantic3done)
303
        {
304 1
            dtor.semantic3(dtor._scope);
305
        }
306
    }
307

308
    override final Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly)
309
    {
310
        //printf("%s.StructDeclaration::search('%s', flags = x%x)\n", toChars(), ident.toChars(), flags);
311 1
        if (_scope && !symtab)
312 1
            dsymbolSemantic(this, _scope);
313

314 1
        if (!members || !symtab) // opaque or semantic() is not yet called
315
        {
316
            // .stringof is always defined (but may be hidden by some other symbol)
317 1
            if(ident != Id.stringof)
318 1
                error("is forward referenced when looking for `%s`", ident.toChars());
319 1
            return null;
320
        }
321

322 1
        return ScopeDsymbol.search(loc, ident, flags);
323
    }
324

325
    override const(char)* kind() const
326
    {
327 1
        return "struct";
328
    }
329

330
    override final void finalizeSize()
331
    {
332
        //printf("StructDeclaration::finalizeSize() %s, sizeok = %d\n", toChars(), sizeok);
333 1
        assert(sizeok != Sizeok.done);
334

335 1
        if (sizeok == Sizeok.inProcess)
336
        {
337 1
            return;
338
        }
339 1
        sizeok = Sizeok.inProcess;
340

341
        //printf("+StructDeclaration::finalizeSize() %s, fields.dim = %d, sizeok = %d\n", toChars(), fields.dim, sizeok);
342

343 1
        fields.setDim(0);   // workaround
344

345
        // Set the offsets of the fields and determine the size of the struct
346 1
        uint offset = 0;
347 1
        bool isunion = isUnionDeclaration() !is null;
348 1
        for (size_t i = 0; i < members.dim; i++)
349
        {
350 1
            Dsymbol s = (*members)[i];
351 1
            s.setFieldOffset(this, &offset, isunion);
352
        }
353 1
        if (type.ty == Terror)
354
        {
355 1
            errors = true;
356 1
            return;
357
        }
358

359
        // 0 sized struct's are set to 1 byte
360 1
        if (structsize == 0)
361
        {
362 1
            hasNoFields = true;
363 1
            structsize = 1;
364 1
            alignsize = 1;
365
        }
366

367
        // Round struct size up to next alignsize boundary.
368
        // This will ensure that arrays of structs will get their internals
369
        // aligned properly.
370 1
        if (alignment == STRUCTALIGN_DEFAULT)
371 1
            structsize = (structsize + alignsize - 1) & ~(alignsize - 1);
372
        else
373 1
            structsize = (structsize + alignment - 1) & ~(alignment - 1);
374

375 1
        sizeok = Sizeok.done;
376

377
        //printf("-StructDeclaration::finalizeSize() %s, fields.dim = %d, structsize = %d\n", toChars(), fields.dim, structsize);
378

379 1
        if (errors)
380 0
            return;
381

382
        // Calculate fields[i].overlapped
383 1
        if (checkOverlappedFields())
384
        {
385 1
            errors = true;
386 1
            return;
387
        }
388

389
        // Determine if struct is all zeros or not
390 1
        zeroInit = true;
391 1
        foreach (vd; fields)
392
        {
393 1
            if (vd._init)
394
            {
395 1
                if (vd._init.isVoidInitializer())
396
                    /* Treat as 0 for the purposes of putting the initializer
397
                     * in the BSS segment, or doing a mass set to 0
398
                     */
399 1
                    continue;
400

401
                // Zero size fields are zero initialized
402 1
                if (vd.type.size(vd.loc) == 0)
403 0
                    continue;
404

405
                // Examine init to see if it is all 0s.
406 1
                auto exp = vd.getConstInitializer();
407 1
                if (!exp || !_isZeroInit(exp))
408
                {
409 1
                    zeroInit = false;
410 1
                    break;
411
                }
412
            }
413 1
            else if (!vd.type.isZeroInit(loc))
414
            {
415 1
                zeroInit = false;
416 1
                break;
417
            }
418
        }
419

420 1
        argTypes = target.toArgTypes(type);
421
    }
422

423
    /***************************************
424
     * Fit elements[] to the corresponding types of the struct's fields.
425
     *
426
     * Params:
427
     *      loc = location to use for error messages
428
     *      sc = context
429
     *      elements = explicit arguments used to construct object
430
     *      stype = the constructed object type.
431
     * Returns:
432
     *      false if any errors occur,
433
     *      otherwise true and elements[] are rewritten for the output.
434
     */
435
    final bool fit(const ref Loc loc, Scope* sc, Expressions* elements, Type stype)
436
    {
437 1
        if (!elements)
438 0
            return true;
439

440 1
        const nfields = nonHiddenFields();
441 1
        size_t offset = 0;
442 1
        for (size_t i = 0; i < elements.dim; i++)
443
        {
444 1
            Expression e = (*elements)[i];
445 1
            if (!e)
446 0
                continue;
447

448 1
            e = resolveProperties(sc, e);
449 1
            if (i >= nfields)
450
            {
451 1
                if (i <= fields.dim && e.op == TOK.null_)
452
                {
453
                    // CTFE sometimes creates null as hidden pointer; we'll allow this.
454 1
                    continue;
455
                }
456 1
                .error(loc, "more initializers than fields (%llu) of `%s`", cast(ulong) nfields, toChars());
457 1
                return false;
458
            }
459 1
            VarDeclaration v = fields[i];
460 1
            if (v.offset < offset)
461
            {
462 1
                .error(loc, "overlapping initialization for `%s`", v.toChars());
463 1
                if (!isUnionDeclaration())
464
                {
465
                    enum errorMsg = "`struct` initializers that contain anonymous unions" ~
466
                                        " must initialize only the first member of a `union`. All subsequent" ~
467
                                        " non-overlapping fields are default initialized";
468 1
                    .errorSupplemental(loc, errorMsg);
469
                }
470 1
                return false;
471
            }
472 1
            offset = cast(uint)(v.offset + v.type.size());
473

474 1
            Type t = v.type;
475 1
            if (stype)
476 1
                t = t.addMod(stype.mod);
477 1
            Type origType = t;
478 1
            Type tb = t.toBasetype();
479

480 1
            const hasPointers = tb.hasPointers();
481 1
            if (hasPointers)
482
            {
483 1
                if ((stype.alignment() < target.ptrsize ||
484 1
                     (v.offset & (target.ptrsize - 1))) &&
485 1
                    (sc.func && sc.func.setUnsafe()))
486
                {
487 1
                    .error(loc, "field `%s.%s` cannot assign to misaligned pointers in `@safe` code",
488
                        toChars(), v.toChars());
489 1
                    return false;
490
                }
491
            }
492

493
            /* Look for case of initializing a static array with a too-short
494
             * string literal, such as:
495
             *  char[5] foo = "abc";
496
             * Allow this by doing an explicit cast, which will lengthen the string
497
             * literal.
498
             */
499 1
            if (e.op == TOK.string_ && tb.ty == Tsarray)
500
            {
501 1
                StringExp se = cast(StringExp)e;
502 1
                Type typeb = se.type.toBasetype();
503 1
                TY tynto = tb.nextOf().ty;
504 1
                if (!se.committed &&
505 1
                    (typeb.ty == Tarray || typeb.ty == Tsarray) && tynto.isSomeChar &&
506 1
                    se.numberOfCodeUnits(tynto) < (cast(TypeSArray)tb).dim.toInteger())
507
                {
508 0
                    e = se.castTo(sc, t);
509 0
                    goto L1;
510
                }
511
            }
512

513 1
            while (!e.implicitConvTo(t) && tb.ty == Tsarray)
514
            {
515
                /* Static array initialization, as in:
516
                 *  T[3][5] = e;
517
                 */
518 1
                t = tb.nextOf();
519 1
                tb = t.toBasetype();
520
            }
521 1
            if (!e.implicitConvTo(t))
522 1
                t = origType; // restore type for better diagnostic
523

524 1
            e = e.implicitCastTo(sc, t);
525
        L1:
526 1
            if (e.op == TOK.error)
527 1
                return false;
528

529 1
            (*elements)[i] = doCopyOrMove(sc, e);
530
        }
531 1
        return true;
532
    }
533

534
    /***************************************
535
     * Determine if struct is POD (Plain Old Data).
536
     *
537
     * POD is defined as:
538
     *      $(OL
539
     *      $(LI not nested)
540
     *      $(LI no postblits, destructors, or assignment operators)
541
     *      $(LI no `ref` fields or fields that are themselves non-POD)
542
     *      )
543
     * The idea being these are compatible with C structs.
544
     *
545
     * Returns:
546
     *     true if struct is POD
547
     */
548
    final bool isPOD()
549
    {
550
        // If we've already determined whether this struct is POD.
551 1
        if (ispod != StructPOD.fwd)
552 1
            return (ispod == StructPOD.yes);
553

554 1
        ispod = StructPOD.yes;
555

556 1
        if (enclosing || postblit || dtor || hasCopyCtor)
557
        {
558 1
            ispod = StructPOD.no;
559 1
            return false;
560
        }
561

562
        // Recursively check all fields are POD.
563 1
        for (size_t i = 0; i < fields.dim; i++)
564
        {
565 1
            VarDeclaration v = fields[i];
566 1
            if (v.storage_class & STC.ref_)
567
            {
568 0
                ispod = StructPOD.no;
569 0
                return false;
570
            }
571

572 1
            Type tv = v.type.baseElemOf();
573 1
            if (tv.ty == Tstruct)
574
            {
575 1
                TypeStruct ts = cast(TypeStruct)tv;
576 1
                StructDeclaration sd = ts.sym;
577 1
                if (!sd.isPOD())
578
                {
579 1
                    ispod = StructPOD.no;
580 1
                    return false;
581
                }
582
            }
583
        }
584

585 1
        return (ispod == StructPOD.yes);
586
    }
587

588
    override final inout(StructDeclaration) isStructDeclaration() inout
589
    {
590 1
        return this;
591
    }
592

593
    override void accept(Visitor v)
594
    {
595 1
        v.visit(this);
596
    }
597

598
    final uint numArgTypes() const
599
    {
600 1
        return argTypes && argTypes.arguments ? cast(uint) argTypes.arguments.dim : 0;
601
    }
602

603
    final Type argType(uint index)
604
    {
605 1
        return index < numArgTypes() ? (*argTypes.arguments)[index].type : null;
606
    }
607

608
    final bool hasNonDisabledCtor()
609
    {
610
        static extern (C++) class HasNonDisabledCtorVisitor : Visitor
611
        {
612
            bool result;
613

614 1
            this() {}
615

616
            alias visit = Visitor.visit;
617

618
            override void visit(CtorDeclaration cd)
619
            {
620 1
                if (!(cd.storage_class & STC.disable))
621 1
                    result = true;
622
            }
623

624
            override void visit(TemplateDeclaration td)
625
            {
626 0
                result = true;
627
            }
628

629
            override void visit(OverloadSet os)
630
            {
631 0
                for (size_t i = 0; i < os.a.dim; i++)
632 0
                    os.a[i].accept(this);
633
            }
634
        }
635

636 1
        if (!ctor)
637 1
            return false;
638 1
        scope v = new HasNonDisabledCtorVisitor();
639 1
        ctor.accept(v);
640 1
        return v.result;
641
    }
642
}
643

644
/**********************************
645
 * Determine if exp is all binary zeros.
646
 * Params:
647
 *      exp = expression to check
648
 * Returns:
649
 *      true if it's all binary 0
650
 */
651
private bool _isZeroInit(Expression exp)
652
{
653 1
    switch (exp.op)
654
    {
655 1
        case TOK.int64:
656 1
            return exp.toInteger() == 0;
657

658 1
        case TOK.null_:
659 1
        case TOK.false_:
660 1
            return true;
661

662 1
        case TOK.structLiteral:
663
        {
664 1
            auto sle = cast(StructLiteralExp) exp;
665 1
            foreach (i; 0 .. sle.sd.fields.dim)
666
            {
667 1
                auto field = sle.sd.fields[i];
668 1
                if (field.type.size(field.loc))
669
                {
670 1
                    auto e = (*sle.elements)[i];
671 1
                    if (e ? !_isZeroInit(e)
672 1
                          : !field.type.isZeroInit(field.loc))
673 1
                        return false;
674
                }
675
            }
676 1
            return true;
677
        }
678

679 1
        case TOK.arrayLiteral:
680
        {
681 1
            auto ale = cast(ArrayLiteralExp)exp;
682

683 1
            const dim = ale.elements ? ale.elements.dim : 0;
684

685 1
            if (ale.type.toBasetype().ty == Tarray) // if initializing a dynamic array
686 1
                return dim == 0;
687

688 1
            foreach (i; 0 .. dim)
689
            {
690 1
                if (!_isZeroInit(ale[i]))
691 1
                    return false;
692
            }
693

694
            /* Note that true is returned for all T[0]
695
             */
696 1
            return true;
697
        }
698

699 1
        case TOK.string_:
700
        {
701 1
            StringExp se = cast(StringExp)exp;
702

703 1
            if (se.type.toBasetype().ty == Tarray) // if initializing a dynamic array
704 1
                return se.len == 0;
705

706 1
            foreach (i; 0 .. se.len)
707
            {
708 1
                if (se.getCodeUnit(i))
709 1
                    return false;
710
            }
711 0
            return true;
712
        }
713

714 1
        case TOK.vector:
715
        {
716 1
            auto ve = cast(VectorExp) exp;
717 1
            return _isZeroInit(ve.e1);
718
        }
719

720 1
        case TOK.float64:
721 1
        case TOK.complex80:
722
        {
723
            import dmd.root.ctfloat : CTFloat;
724 1
            return (exp.toReal()      is CTFloat.zero) &&
725 1
                   (exp.toImaginary() is CTFloat.zero);
726
        }
727

728 1
        default:
729 1
            return false;
730
    }
731
}
732

733
/***********************************************************
734
 * Unions are a variation on structs.
735
 */
736
extern (C++) final class UnionDeclaration : StructDeclaration
737
{
738 1
    extern (D) this(const ref Loc loc, Identifier id)
739
    {
740 1
        super(loc, id, false);
741
    }
742

743
    override Dsymbol syntaxCopy(Dsymbol s)
744
    {
745 1
        assert(!s);
746 1
        auto ud = new UnionDeclaration(loc, ident);
747 1
        return StructDeclaration.syntaxCopy(ud);
748
    }
749

750
    override const(char)* kind() const
751
    {
752 1
        return "union";
753
    }
754

755
    override inout(UnionDeclaration) isUnionDeclaration() inout
756
    {
757 1
        return this;
758
    }
759

760
    override void accept(Visitor v)
761
    {
762 1
        v.visit(this);
763
    }
764
}

Read our documentation on viewing source code .

Loading