1
/**
2
 * Defines a `Dsymbol` representing an aggregate, which is a `struct`, `union` or `class`.
3
 *
4
 * Specification: $(LINK2 https://dlang.org/spec/struct.html, Structs, Unions),
5
 *                $(LINK2 https://dlang.org/spec/class.html, Class).
6
 *
7
 * Copyright:   Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved
8
 * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
9
 * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
10
 * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/aggregate.d, _aggregate.d)
11
 * Documentation:  https://dlang.org/phobos/dmd_aggregate.html
12
 * Coverage:    https://codecov.io/gh/dlang/dmd/src/master/src/dmd/aggregate.d
13
 */
14

15
module dmd.aggregate;
16

17
import core.stdc.stdio;
18
import core.checkedint;
19

20
import dmd.aliasthis;
21
import dmd.apply;
22
import dmd.arraytypes;
23
import dmd.gluelayer : Symbol;
24
import dmd.declaration;
25
import dmd.dscope;
26
import dmd.dstruct;
27
import dmd.dsymbol;
28
import dmd.dsymbolsem;
29
import dmd.dtemplate;
30
import dmd.errors;
31
import dmd.expression;
32
import dmd.func;
33
import dmd.globals;
34
import dmd.id;
35
import dmd.identifier;
36
import dmd.mtype;
37
import dmd.tokens;
38
import dmd.typesem : defaultInit;
39
import dmd.visitor;
40

41
enum Sizeok : int
42
{
43
    none,           /// size of aggregate is not yet able to compute
44
    fwd,            /// size of aggregate is ready to compute
45
    inProcess,      /// in the midst of computing the size
46
    done,           /// size of aggregate is set correctly
47
}
48

49
enum Baseok : int
50
{
51
    none,             /// base classes not computed yet
52
    start,            /// in process of resolving base classes
53
    done,             /// all base classes are resolved
54
    semanticdone,     /// all base classes semantic done
55
}
56

57
/**
58
 * The ClassKind enum is used in AggregateDeclaration AST nodes to
59
 * specify the linkage type of the struct/class/interface or if it
60
 * is an anonymous class. If the class is anonymous it is also
61
 * considered to be a D class.
62
 */
63
enum ClassKind : int
64
{
65
    /// the aggregate is a d(efault) class
66
    d,
67
    /// the aggregate is a C++ struct/class/interface
68
    cpp,
69
    /// the aggregate is an Objective-C class/interface
70
    objc,
71
}
72

73
/***********************************************************
74
 * Abstract aggregate as a common ancestor for Class- and StructDeclaration.
75
 */
76
extern (C++) abstract class AggregateDeclaration : ScopeDsymbol
77
{
78
    Type type;                  ///
79
    StorageClass storage_class; ///
80
    uint structsize;            /// size of struct
81
    uint alignsize;             /// size of struct for alignment purposes
82
    VarDeclarations fields;     /// VarDeclaration fields
83
    Dsymbol deferred;           /// any deferred semantic2() or semantic3() symbol
84

85
    /// specifies whether this is a D, C++, Objective-C or anonymous struct/class/interface
86
    ClassKind classKind;
87
    /// Specify whether to mangle the aggregate as a `class` or a `struct`
88
    /// This information is used by the MSVC mangler
89
    /// Only valid for class and struct. TODO: Merge with ClassKind ?
90
    CPPMANGLE cppmangle;
91

92
    /**
93
     * !=null if is nested
94
     * pointing to the dsymbol that directly enclosing it.
95
     * 1. The function that enclosing it (nested struct and class)
96
     * 2. The class that enclosing it (nested class only)
97
     * 3. If enclosing aggregate is template, its enclosing dsymbol.
98
     *
99
     * See AggregateDeclaraton::makeNested for the details.
100
     */
101
    Dsymbol enclosing;
102

103
    VarDeclaration vthis;   /// 'this' parameter if this aggregate is nested
104
    VarDeclaration vthis2;  /// 'this' parameter if this aggregate is a template and is nested
105

106
    // Special member functions
107
    FuncDeclarations invs;  /// Array of invariants
108
    FuncDeclaration inv;    /// Merged invariant calling all members of invs
109
    NewDeclaration aggNew;  /// allocator
110

111
    /// CtorDeclaration or TemplateDeclaration
112
    Dsymbol ctor;
113

114
    /// default constructor - should have no arguments, because
115
    /// it would be stored in TypeInfo_Class.defaultConstructor
116
    CtorDeclaration defaultCtor;
117

118
    AliasThis aliasthis;    /// forward unresolved lookups to aliasthis
119

120
    DtorDeclarations dtors;     /// Array of destructors
121
    DtorDeclaration dtor;       /// aggregate destructor calling dtors and member constructors
122
    DtorDeclaration primaryDtor;/// non-deleting C++ destructor, same as dtor for D
123
    DtorDeclaration tidtor;     /// aggregate destructor used in TypeInfo (must have extern(D) ABI)
124
    FuncDeclaration fieldDtor;  /// aggregate destructor for just the fields
125

126
    Expression getRTInfo;   /// pointer to GC info generated by object.RTInfo(this)
127

128
    Prot protection;                /// visibility
129
    bool noDefaultCtor;             /// no default construction
130
    Sizeok sizeok = Sizeok.none;    /// set when structsize contains valid data
131

132 1
    final extern (D) this(const ref Loc loc, Identifier id)
133
    {
134 1
        super(loc, id);
135 1
        protection = Prot(Prot.Kind.public_);
136
    }
137

138
    /***************************************
139
     * Create a new scope from sc.
140
     * semantic, semantic2 and semantic3 will use this for aggregate members.
141
     */
142
    Scope* newScope(Scope* sc)
143
    {
144 1
        auto sc2 = sc.push(this);
145 1
        sc2.stc &= STCFlowThruAggregate;
146 1
        sc2.parent = this;
147 1
        sc2.inunion = isUnionDeclaration();
148 1
        sc2.protection = Prot(Prot.Kind.public_);
149 1
        sc2.explicitProtection = 0;
150 1
        sc2.aligndecl = null;
151 1
        sc2.userAttribDecl = null;
152 1
        sc2.namespace = null;
153 1
        return sc2;
154
    }
155

156
    override final void setScope(Scope* sc)
157
    {
158
        // Might need a scope to resolve forward references. The check for
159
        // semanticRun prevents unnecessary setting of _scope during deferred
160
        // setScope phases for aggregates which already finished semantic().
161
        // See https://issues.dlang.org/show_bug.cgi?id=16607
162 1
        if (semanticRun < PASS.semanticdone)
163 1
            ScopeDsymbol.setScope(sc);
164
    }
165

166
    /***************************************
167
     * Find all instance fields, then push them into `fields`.
168
     *
169
     * Runs semantic() for all instance field variables, but also
170
     * the field types can remain yet not resolved forward references,
171
     * except direct recursive definitions.
172
     * After the process sizeok is set to Sizeok.fwd.
173
     *
174
     * Returns:
175
     *      false if any errors occur.
176
     */
177
    final bool determineFields()
178
    {
179 1
        if (_scope)
180 1
            dsymbolSemantic(this, null);
181 1
        if (sizeok != Sizeok.none)
182 1
            return true;
183

184
        //printf("determineFields() %s, fields.dim = %d\n", toChars(), fields.dim);
185
        // determineFields can be called recursively from one of the fields's v.semantic
186 1
        fields.setDim(0);
187

188
        static int func(Dsymbol s, AggregateDeclaration ad)
189
        {
190 1
            auto v = s.isVarDeclaration();
191 1
            if (!v)
192 1
                return 0;
193 1
            if (v.storage_class & STC.manifest)
194 1
                return 0;
195

196 1
            if (v.semanticRun < PASS.semanticdone)
197 1
                v.dsymbolSemantic(null);
198
            // Return in case a recursive determineFields triggered by v.semantic already finished
199 1
            if (ad.sizeok != Sizeok.none)
200 1
                return 1;
201

202 1
            if (v.aliassym)
203 1
                return 0;   // If this variable was really a tuple, skip it.
204

205 1
            if (v.storage_class & (STC.static_ | STC.extern_ | STC.tls | STC.gshared | STC.manifest | STC.ctfe | STC.templateparameter))
206 1
                return 0;
207 1
            if (!v.isField() || v.semanticRun < PASS.semanticdone)
208 1
                return 1;   // unresolvable forward reference
209

210 1
            ad.fields.push(v);
211

212 1
            if (v.storage_class & STC.ref_)
213 0
                return 0;
214 1
            auto tv = v.type.baseElemOf();
215 1
            if (tv.ty != Tstruct)
216 1
                return 0;
217 1
            if (ad == (cast(TypeStruct)tv).sym)
218
            {
219 1
                const(char)* psz = (v.type.toBasetype().ty == Tsarray) ? "static array of " : "";
220 1
                ad.error("cannot have field `%s` with %ssame struct type", v.toChars(), psz);
221 1
                ad.type = Type.terror;
222 1
                ad.errors = true;
223 1
                return 1;
224
            }
225 1
            return 0;
226
        }
227

228 1
        if (members)
229
        {
230 1
            for (size_t i = 0; i < members.dim; i++)
231
            {
232 1
                auto s = (*members)[i];
233 1
                if (s.apply(&func, this))
234
                {
235 1
                    if (sizeok != Sizeok.none)
236
                    {
237
                        // recursive determineFields already finished
238 1
                        return true;
239
                    }
240 1
                    return false;
241
                }
242
            }
243
        }
244

245 1
        if (sizeok != Sizeok.done)
246 1
            sizeok = Sizeok.fwd;
247

248 1
        return true;
249
    }
250

251
    /***************************************
252
     * Returns:
253
     *      The total number of fields minus the number of hidden fields.
254
     */
255
    final size_t nonHiddenFields()
256
    {
257 1
        return fields.dim - isNested() - (vthis2 !is null);
258
    }
259

260
    /***************************************
261
     * Collect all instance fields, then determine instance size.
262
     * Returns:
263
     *      false if failed to determine the size.
264
     */
265
    final bool determineSize(Loc loc)
266
    {
267
        //printf("AggregateDeclaration::determineSize() %s, sizeok = %d\n", toChars(), sizeok);
268

269
        // The previous instance size finalizing had:
270 1
        if (type.ty == Terror)
271 1
            return false;   // failed already
272 1
        if (sizeok == Sizeok.done)
273 1
            return true;    // succeeded
274

275 1
        if (!members)
276
        {
277 1
            error(loc, "unknown size");
278 1
            return false;
279
        }
280

281 1
        if (_scope)
282 1
            dsymbolSemantic(this, null);
283

284
        // Determine the instance size of base class first.
285 1
        if (auto cd = isClassDeclaration())
286
        {
287 1
            cd = cd.baseClass;
288 1
            if (cd && !cd.determineSize(loc))
289 0
                goto Lfail;
290
        }
291

292
        // Determine instance fields when sizeok == Sizeok.none
293 1
        if (!determineFields())
294 1
            goto Lfail;
295 1
        if (sizeok != Sizeok.done)
296 1
            finalizeSize();
297

298
        // this aggregate type has:
299 1
        if (type.ty == Terror)
300 1
            return false;   // marked as invalid during the finalizing.
301 1
        if (sizeok == Sizeok.done)
302 1
            return true;    // succeeded to calculate instance size.
303

304
    Lfail:
305
        // There's unresolvable forward reference.
306 1
        if (type != Type.terror)
307 1
            error(loc, "no size because of forward reference");
308
        // Don't cache errors from speculative semantic, might be resolvable later.
309
        // https://issues.dlang.org/show_bug.cgi?id=16574
310 1
        if (!global.gag)
311
        {
312 1
            type = Type.terror;
313 1
            errors = true;
314
        }
315 1
        return false;
316
    }
317

318
    abstract void finalizeSize();
319

320
    override final d_uns64 size(const ref Loc loc)
321
    {
322
        //printf("+AggregateDeclaration::size() %s, scope = %p, sizeok = %d\n", toChars(), _scope, sizeok);
323 1
        bool ok = determineSize(loc);
324
        //printf("-AggregateDeclaration::size() %s, scope = %p, sizeok = %d\n", toChars(), _scope, sizeok);
325 1
        return ok ? structsize : SIZE_INVALID;
326
    }
327

328
    /***************************************
329
     * Calculate field[i].overlapped and overlapUnsafe, and check that all of explicit
330
     * field initializers have unique memory space on instance.
331
     * Returns:
332
     *      true if any errors happen.
333
     */
334
    extern (D) final bool checkOverlappedFields()
335
    {
336
        //printf("AggregateDeclaration::checkOverlappedFields() %s\n", toChars());
337 1
        assert(sizeok == Sizeok.done);
338 1
        size_t nfields = fields.dim;
339 1
        if (isNested())
340
        {
341 1
            auto cd = isClassDeclaration();
342 1
            if (!cd || !cd.baseClass || !cd.baseClass.isNested())
343 1
                nfields--;
344 1
            if (vthis2 && !(cd && cd.baseClass && cd.baseClass.vthis2))
345 1
                nfields--;
346
        }
347 1
        bool errors = false;
348

349
        // Fill in missing any elements with default initializers
350 1
        foreach (i; 0 .. nfields)
351
        {
352 1
            auto vd = fields[i];
353 1
            if (vd.errors)
354
            {
355 1
                errors = true;
356 1
                continue;
357
            }
358

359 1
            const vdIsVoidInit = vd._init && vd._init.isVoidInitializer();
360

361
            // Find overlapped fields with the hole [vd.offset .. vd.offset.size()].
362 1
            foreach (j; 0 .. nfields)
363
            {
364 1
                if (i == j)
365 1
                    continue;
366 1
                auto v2 = fields[j];
367 1
                if (v2.errors)
368
                {
369 0
                    errors = true;
370 0
                    continue;
371
                }
372 1
                if (!vd.isOverlappedWith(v2))
373 1
                    continue;
374

375
                // vd and v2 are overlapping.
376 1
                vd.overlapped = true;
377 1
                v2.overlapped = true;
378

379 1
                if (!MODimplicitConv(vd.type.mod, v2.type.mod))
380 1
                    v2.overlapUnsafe = true;
381 1
                if (!MODimplicitConv(v2.type.mod, vd.type.mod))
382 1
                    vd.overlapUnsafe = true;
383

384 1
                if (i > j)
385 1
                    continue;
386

387 1
                if (!v2._init)
388 1
                    continue;
389

390 1
                if (v2._init.isVoidInitializer())
391 1
                    continue;
392

393 1
                if (vd._init && !vdIsVoidInit && v2._init)
394
                {
395 1
                    .error(loc, "overlapping default initialization for field `%s` and `%s`", v2.toChars(), vd.toChars());
396 1
                    errors = true;
397
                }
398 1
                else if (v2._init && i < j)
399
                {
400
                    // @@@DEPRECATED_v2.086@@@.
401 1
                    .deprecation(v2.loc, "union field `%s` with default initialization `%s` must be before field `%s`",
402
                        v2.toChars(), v2._init.toChars(), vd.toChars());
403
                    //errors = true;
404
                }
405
            }
406
        }
407 1
        return errors;
408
    }
409

410
    /***************************************
411
     * Fill out remainder of elements[] with default initializers for fields[].
412
     * Params:
413
     *      loc         = location
414
     *      elements    = explicit arguments which given to construct object.
415
     *      ctorinit    = true if the elements will be used for default initialization.
416
     * Returns:
417
     *      false if any errors occur.
418
     *      Otherwise, returns true and the missing arguments will be pushed in elements[].
419
     */
420
    final bool fill(Loc loc, Expressions* elements, bool ctorinit)
421
    {
422
        //printf("AggregateDeclaration::fill() %s\n", toChars());
423 1
        assert(sizeok == Sizeok.done);
424 1
        assert(elements);
425 1
        const nfields = nonHiddenFields();
426 1
        bool errors = false;
427

428 1
        size_t dim = elements.dim;
429 1
        elements.setDim(nfields);
430 1
        foreach (size_t i; dim .. nfields)
431 1
            (*elements)[i] = null;
432

433
        // Fill in missing any elements with default initializers
434 1
        foreach (i; 0 .. nfields)
435
        {
436 1
            if ((*elements)[i])
437 1
                continue;
438

439 1
            auto vd = fields[i];
440 1
            auto vx = vd;
441 1
            if (vd._init && vd._init.isVoidInitializer())
442 1
                vx = null;
443

444
            // Find overlapped fields with the hole [vd.offset .. vd.offset.size()].
445 1
            size_t fieldi = i;
446 1
            foreach (j; 0 .. nfields)
447
            {
448 1
                if (i == j)
449 1
                    continue;
450 1
                auto v2 = fields[j];
451 1
                if (!vd.isOverlappedWith(v2))
452 1
                    continue;
453

454 1
                if ((*elements)[j])
455
                {
456 1
                    vx = null;
457 1
                    break;
458
                }
459 1
                if (v2._init && v2._init.isVoidInitializer())
460 0
                    continue;
461

462
                version (all)
463
                {
464
                    /* Prefer first found non-void-initialized field
465
                     * union U { int a; int b = 2; }
466
                     * U u;    // Error: overlapping initialization for field a and b
467
                     */
468 1
                    if (!vx)
469
                    {
470 0
                        vx = v2;
471 0
                        fieldi = j;
472
                    }
473 1
                    else if (v2._init)
474
                    {
475 0
                        .error(loc, "overlapping initialization for field `%s` and `%s`", v2.toChars(), vd.toChars());
476 0
                        errors = true;
477
                    }
478
                }
479
                else
480
                {
481
                    // fixes https://issues.dlang.org/show_bug.cgi?id=1432 by enabling this path always
482

483
                    /* Prefer explicitly initialized field
484
                     * union U { int a; int b = 2; }
485
                     * U u;    // OK (u.b == 2)
486
                     */
487
                    if (!vx || !vx._init && v2._init)
488
                    {
489
                        vx = v2;
490
                        fieldi = j;
491
                    }
492
                    else if (vx != vd && !vx.isOverlappedWith(v2))
493
                    {
494
                        // Both vx and v2 fills vd, but vx and v2 does not overlap
495
                    }
496
                    else if (vx._init && v2._init)
497
                    {
498
                        .error(loc, "overlapping default initialization for field `%s` and `%s`",
499
                            v2.toChars(), vd.toChars());
500
                        errors = true;
501
                    }
502
                    else
503
                        assert(vx._init || !vx._init && !v2._init);
504
                }
505
            }
506 1
            if (vx)
507
            {
508 1
                Expression e;
509 1
                if (vx.type.size() == 0)
510
                {
511 1
                    e = null;
512
                }
513 1
                else if (vx._init)
514
                {
515 1
                    assert(!vx._init.isVoidInitializer());
516 1
                    if (vx.inuse)   // https://issues.dlang.org/show_bug.cgi?id=18057
517
                    {
518 1
                        vx.error(loc, "recursive initialization of field");
519 1
                        errors = true;
520
                    }
521
                    else
522 1
                        e = vx.getConstInitializer(false);
523
                }
524
                else
525
                {
526 1
                    if ((vx.storage_class & STC.nodefaultctor) && !ctorinit)
527
                    {
528 1
                        .error(loc, "field `%s.%s` must be initialized because it has no default constructor",
529
                            type.toChars(), vx.toChars());
530 1
                        errors = true;
531
                    }
532
                    /* https://issues.dlang.org/show_bug.cgi?id=12509
533
                     * Get the element of static array type.
534
                     */
535 1
                    Type telem = vx.type;
536 1
                    if (telem.ty == Tsarray)
537
                    {
538
                        /* We cannot use Type::baseElemOf() here.
539
                         * If the bottom of the Tsarray is an enum type, baseElemOf()
540
                         * will return the base of the enum, and its default initializer
541
                         * would be different from the enum's.
542
                         */
543 1
                        while (telem.toBasetype().ty == Tsarray)
544 1
                            telem = (cast(TypeSArray)telem.toBasetype()).next;
545 1
                        if (telem.ty == Tvoid)
546 1
                            telem = Type.tuns8.addMod(telem.mod);
547
                    }
548 1
                    if (telem.needsNested() && ctorinit)
549 1
                        e = telem.defaultInit(loc);
550
                    else
551 1
                        e = telem.defaultInitLiteral(loc);
552
                }
553 1
                (*elements)[fieldi] = e;
554
            }
555
        }
556 1
        foreach (e; *elements)
557
        {
558 1
            if (e && e.op == TOK.error)
559 1
                return false;
560
        }
561

562 1
        return !errors;
563
    }
564

565
    /****************************
566
     * Do byte or word alignment as necessary.
567
     * Align sizes of 0, as we may not know array sizes yet.
568
     * Params:
569
     *   alignment = struct alignment that is in effect
570
     *   size = alignment requirement of field
571
     *   poffset = pointer to offset to be aligned
572
     */
573
    extern (D) static void alignmember(structalign_t alignment, uint size, uint* poffset) pure nothrow @safe
574
    {
575
        //printf("alignment = %d, size = %d, offset = %d\n",alignment,size,offset);
576 1
        switch (alignment)
577
        {
578 1
        case cast(structalign_t)1:
579
            // No alignment
580 1
            break;
581

582 1
        case cast(structalign_t)STRUCTALIGN_DEFAULT:
583
            // Alignment in Target::fieldalignsize must match what the
584
            // corresponding C compiler's default alignment behavior is.
585 1
            assert(size > 0 && !(size & (size - 1)));
586 1
            *poffset = (*poffset + size - 1) & ~(size - 1);
587 1
            break;
588

589 1
        default:
590
            // Align on alignment boundary, which must be a positive power of 2
591 1
            assert(alignment > 0 && !(alignment & (alignment - 1)));
592 1
            *poffset = (*poffset + alignment - 1) & ~(alignment - 1);
593 1
            break;
594
        }
595
    }
596

597
    /****************************************
598
     * Place a member (mem) into an aggregate (agg), which can be a struct, union or class
599
     * Returns:
600
     *      offset to place field at
601
     *
602
     * nextoffset:    next location in aggregate
603
     * memsize:       size of member
604
     * memalignsize:  natural alignment of member
605
     * alignment:     alignment in effect for this member
606
     * paggsize:      size of aggregate (updated)
607
     * paggalignsize: alignment of aggregate (updated)
608
     * isunion:       the aggregate is a union
609
     */
610
    extern (D) static uint placeField(uint* nextoffset, uint memsize, uint memalignsize,
611
        structalign_t alignment, uint* paggsize, uint* paggalignsize, bool isunion)
612
    {
613 1
        uint ofs = *nextoffset;
614

615 1
        const uint actualAlignment =
616 1
            alignment == STRUCTALIGN_DEFAULT ? memalignsize : alignment;
617

618
        // Ensure no overflow
619 1
        bool overflow;
620 1
        const sz = addu(memsize, actualAlignment, overflow);
621
        addu(ofs, sz, overflow);
622 1
        if (overflow) assert(0);
623

624 1
        alignmember(alignment, memalignsize, &ofs);
625 1
        uint memoffset = ofs;
626 1
        ofs += memsize;
627 1
        if (ofs > *paggsize)
628 1
            *paggsize = ofs;
629 1
        if (!isunion)
630 1
            *nextoffset = ofs;
631

632 1
        if (*paggalignsize < actualAlignment)
633 1
            *paggalignsize = actualAlignment;
634

635 1
        return memoffset;
636
    }
637

638
    override final Type getType()
639
    {
640 1
        return type;
641
    }
642

643
    // is aggregate deprecated?
644
    override final bool isDeprecated() const
645
    {
646 1
        return !!(this.storage_class & STC.deprecated_);
647
    }
648

649
    /// Flag this aggregate as deprecated
650
    final void setDeprecated()
651
    {
652 1
        this.storage_class |= STC.deprecated_;
653
    }
654

655
    /****************************************
656
     * Returns true if there's an extra member which is the 'this'
657
     * pointer to the enclosing context (enclosing aggregate or function)
658
     */
659
    final bool isNested() const
660
    {
661 1
        return enclosing !is null;
662
    }
663

664
    /* Append vthis field (this.tupleof[$-1]) to make this aggregate type nested.
665
     */
666
    extern (D) final void makeNested()
667
    {
668 1
        if (enclosing) // if already nested
669 1
            return;
670 1
        if (sizeok == Sizeok.done)
671 1
            return;
672 1
        if (isUnionDeclaration() || isInterfaceDeclaration())
673 1
            return;
674 1
        if (storage_class & STC.static_)
675 1
            return;
676

677
        // If nested struct, add in hidden 'this' pointer to outer scope
678 1
        auto s = toParentLocal();
679 1
        if (!s)
680 0
            s = toParent2();
681 1
        if (!s)
682 0
            return;
683 1
        Type t = null;
684 1
        if (auto fd = s.isFuncDeclaration())
685
        {
686 1
            enclosing = fd;
687

688
            /* https://issues.dlang.org/show_bug.cgi?id=14422
689
             * If a nested class parent is a function, its
690
             * context pointer (== `outer`) should be void* always.
691
             */
692 1
            t = Type.tvoidptr;
693
        }
694 1
        else if (auto ad = s.isAggregateDeclaration())
695
        {
696 1
            if (isClassDeclaration() && ad.isClassDeclaration())
697
            {
698 1
                enclosing = ad;
699
            }
700 1
            else if (isStructDeclaration())
701
            {
702 1
                if (auto ti = ad.parent.isTemplateInstance())
703
                {
704 1
                    enclosing = ti.enclosing;
705
                }
706
            }
707 1
            t = ad.handleType();
708
        }
709 1
        if (enclosing)
710
        {
711
            //printf("makeNested %s, enclosing = %s\n", toChars(), enclosing.toChars());
712 1
            assert(t);
713 1
            if (t.ty == Tstruct)
714 1
                t = Type.tvoidptr; // t should not be a ref type
715

716 1
            assert(!vthis);
717 1
            vthis = new ThisDeclaration(loc, t);
718
            //vthis.storage_class |= STC.ref_;
719

720
            // Emulate vthis.addMember()
721 1
            members.push(vthis);
722

723
            // Emulate vthis.dsymbolSemantic()
724 1
            vthis.storage_class |= STC.field;
725 1
            vthis.parent = this;
726 1
            vthis.protection = Prot(Prot.Kind.public_);
727 1
            vthis.alignment = t.alignment();
728 1
            vthis.semanticRun = PASS.semanticdone;
729

730 1
            if (sizeok == Sizeok.fwd)
731 0
                fields.push(vthis);
732

733 1
            makeNested2();
734
        }
735
    }
736

737
    /* Append vthis2 field (this.tupleof[$-1]) to add a second context pointer.
738
     */
739
    extern (D) final void makeNested2()
740
    {
741 1
        if (vthis2)
742 0
            return;
743 1
        if (!vthis)
744 0
            makeNested();   // can't add second before first
745 1
        if (!vthis)
746 0
            return;
747 1
        if (sizeok == Sizeok.done)
748 0
            return;
749 1
        if (isUnionDeclaration() || isInterfaceDeclaration())
750 0
            return;
751 1
        if (storage_class & STC.static_)
752 0
            return;
753

754 1
        auto s0 = toParentLocal();
755 1
        auto s = toParent2();
756 1
        if (!s || !s0 || s == s0)
757 1
            return;
758 1
        auto cd = s.isClassDeclaration();
759 1
        Type t = cd ? cd.type : Type.tvoidptr;
760

761 1
        vthis2 = new ThisDeclaration(loc, t);
762
        //vthis2.storage_class |= STC.ref_;
763

764
        // Emulate vthis2.addMember()
765 1
        members.push(vthis2);
766

767
        // Emulate vthis2.dsymbolSemantic()
768 1
        vthis2.storage_class |= STC.field;
769 1
        vthis2.parent = this;
770 1
        vthis2.protection = Prot(Prot.Kind.public_);
771 1
        vthis2.alignment = t.alignment();
772 1
        vthis2.semanticRun = PASS.semanticdone;
773

774 1
        if (sizeok == Sizeok.fwd)
775 0
            fields.push(vthis2);
776
    }
777

778
    override final bool isExport() const
779
    {
780 1
        return protection.kind == Prot.Kind.export_;
781
    }
782

783
    /*******************************************
784
     * Look for constructor declaration.
785
     */
786
    final Dsymbol searchCtor()
787
    {
788 1
        auto s = search(Loc.initial, Id.ctor);
789 1
        if (s)
790
        {
791 1
            if (!(s.isCtorDeclaration() ||
792 1
                  s.isTemplateDeclaration() ||
793 1
                  s.isOverloadSet()))
794
            {
795 1
                s.error("is not a constructor; identifiers starting with `__` are reserved for the implementation");
796 1
                errors = true;
797 1
                s = null;
798
            }
799
        }
800 1
        if (s && s.toParent() != this)
801 1
            s = null; // search() looks through ancestor classes
802 1
        if (s)
803
        {
804
            // Finish all constructors semantics to determine this.noDefaultCtor.
805
            struct SearchCtor
806
            {
807
                extern (C++) static int fp(Dsymbol s, void* ctxt)
808
                {
809 1
                    auto f = s.isCtorDeclaration();
810 1
                    if (f && f.semanticRun == PASS.init)
811 0
                        f.dsymbolSemantic(null);
812 1
                    return 0;
813
                }
814
            }
815

816 1
            for (size_t i = 0; i < members.dim; i++)
817
            {
818 1
                auto sm = (*members)[i];
819 1
                sm.apply(&SearchCtor.fp, null);
820
            }
821
        }
822 1
        return s;
823
    }
824

825
    override final Prot prot() pure nothrow @nogc @safe
826
    {
827 1
        return protection;
828
    }
829

830
    // 'this' type
831
    final Type handleType()
832
    {
833 1
        return type;
834
    }
835

836
    // Back end
837
    Symbol* stag;   /// tag symbol for debug data
838
    Symbol* sinit;  /// initializer symbol
839

840
    override final inout(AggregateDeclaration) isAggregateDeclaration() inout
841
    {
842 1
        return this;
843
    }
844

845
    override void accept(Visitor v)
846
    {
847 0
        v.visit(this);
848
    }
849
}

Read our documentation on viewing source code .

Loading