xref: /netbsd/external/gpl3/gcc/dist/gcc/d/dmd/aggregate.d (revision f0fbc68b)
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-2022 by The D Language Foundation, All Rights Reserved
8  * Authors:     $(LINK2 https://www.digitalmars.com, Walter Bright)
9  * License:     $(LINK2 https://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.astenums;
24 import dmd.attrib;
25 import dmd.declaration;
26 import dmd.dscope;
27 import dmd.dstruct;
28 import dmd.dsymbol;
29 import dmd.dsymbolsem;
30 import dmd.dtemplate;
31 import dmd.errors;
32 import dmd.expression;
33 import dmd.func;
34 import dmd.globals;
35 import dmd.id;
36 import dmd.identifier;
37 import dmd.mtype;
38 import dmd.tokens;
39 import dmd.typesem : defaultInit;
40 import dmd.visitor;
41 
42 /**
43  * The ClassKind enum is used in AggregateDeclaration AST nodes to
44  * specify the linkage type of the struct/class/interface or if it
45  * is an anonymous class. If the class is anonymous it is also
46  * considered to be a D class.
47  */
48 enum ClassKind : ubyte
49 {
50     /// the aggregate is a d(efault) class
51     d,
52     /// the aggregate is a C++ struct/class/interface
53     cpp,
54     /// the aggregate is an Objective-C class/interface
55     objc,
56     /// the aggregate is a C struct
57     c,
58 }
59 
60 /**
61  * Give a nice string for a class kind for error messages
62  * Params:
63  *     c = class kind
64  * Returns:
65  *     0-terminated string for `c`
66  */
toChars(ClassKind c)67 const(char)* toChars(ClassKind c)
68 {
69     final switch (c)
70     {
71         case ClassKind.d:
72             return "D";
73         case ClassKind.cpp:
74             return "C++";
75         case ClassKind.objc:
76             return "Objective-C";
77         case ClassKind.c:
78             return "C";
79     }
80 }
81 
82 /**
83  * If an aggregate has a pargma(mangle, ...) this holds the information
84  * to mangle.
85  */
86 struct MangleOverride
87 {
88     Dsymbol agg;   // The symbol to copy template parameters from (if any)
89     Identifier id; // the name to override the aggregate's with, defaults to agg.ident
90 }
91 
92 /***********************************************************
93  * Abstract aggregate as a common ancestor for Class- and StructDeclaration.
94  */
95 extern (C++) abstract class AggregateDeclaration : ScopeDsymbol
96 {
97     Type type;                  ///
98     StorageClass storage_class; ///
99     uint structsize;            /// size of struct
100     uint alignsize;             /// size of struct for alignment purposes
101     VarDeclarations fields;     /// VarDeclaration fields
102     Dsymbol deferred;           /// any deferred semantic2() or semantic3() symbol
103 
104     /// specifies whether this is a D, C++, Objective-C or anonymous struct/class/interface
105     ClassKind classKind;
106     /// Specify whether to mangle the aggregate as a `class` or a `struct`
107     /// This information is used by the MSVC mangler
108     /// Only valid for class and struct. TODO: Merge with ClassKind ?
109     CPPMANGLE cppmangle;
110 
111     /// overridden symbol with pragma(mangle, "...") if not null
112     MangleOverride* mangleOverride;
113 
114     /**
115      * !=null if is nested
116      * pointing to the dsymbol that directly enclosing it.
117      * 1. The function that enclosing it (nested struct and class)
118      * 2. The class that enclosing it (nested class only)
119      * 3. If enclosing aggregate is template, its enclosing dsymbol.
120      *
121      * See AggregateDeclaraton::makeNested for the details.
122      */
123     Dsymbol enclosing;
124 
125     VarDeclaration vthis;   /// 'this' parameter if this aggregate is nested
126     VarDeclaration vthis2;  /// 'this' parameter if this aggregate is a template and is nested
127 
128     // Special member functions
129     FuncDeclarations invs;  /// Array of invariants
130     FuncDeclaration inv;    /// Merged invariant calling all members of invs
131 
132     /// CtorDeclaration or TemplateDeclaration
133     Dsymbol ctor;
134 
135     /// default constructor - should have no arguments, because
136     /// it would be stored in TypeInfo_Class.defaultConstructor
137     CtorDeclaration defaultCtor;
138 
139     AliasThis aliasthis;    /// forward unresolved lookups to aliasthis
140 
141     DtorDeclarations userDtors; /// user-defined destructors (`~this()`) - mixins can yield multiple ones
142     DtorDeclaration aggrDtor;   /// aggregate destructor calling userDtors and fieldDtor (and base class aggregate dtor for C++ classes)
143     DtorDeclaration dtor;       /// the aggregate destructor exposed as `__xdtor` alias
144                                 /// (same as aggrDtor, except for C++ classes with virtual dtor on Windows)
145     DtorDeclaration tidtor;     /// aggregate destructor used in TypeInfo (must have extern(D) ABI)
146     DtorDeclaration fieldDtor;  /// function destructing (non-inherited) fields
147 
148     Expression getRTInfo;   /// pointer to GC info generated by object.RTInfo(this)
149 
150     ///
151     Visibility visibility;
152     bool noDefaultCtor;             /// no default construction
153     bool disableNew;                /// disallow allocations using `new`
154     Sizeok sizeok = Sizeok.none;    /// set when structsize contains valid data
155 
this(const ref Loc loc,Identifier id)156     final extern (D) this(const ref Loc loc, Identifier id)
157     {
158         super(loc, id);
159         visibility = Visibility(Visibility.Kind.public_);
160     }
161 
162     /***************************************
163      * Create a new scope from sc.
164      * semantic, semantic2 and semantic3 will use this for aggregate members.
165      */
newScope(Scope * sc)166     Scope* newScope(Scope* sc)
167     {
168         auto sc2 = sc.push(this);
169         sc2.stc &= STC.flowThruAggregate;
170         sc2.parent = this;
171         sc2.inunion = isUnionDeclaration();
172         sc2.visibility = Visibility(Visibility.Kind.public_);
173         sc2.explicitVisibility = 0;
174         sc2.aligndecl = null;
175         sc2.userAttribDecl = null;
176         sc2.namespace = null;
177         return sc2;
178     }
179 
setScope(Scope * sc)180     override final void setScope(Scope* sc)
181     {
182         // Might need a scope to resolve forward references. The check for
183         // semanticRun prevents unnecessary setting of _scope during deferred
184         // setScope phases for aggregates which already finished semantic().
185         // See https://issues.dlang.org/show_bug.cgi?id=16607
186         if (semanticRun < PASS.semanticdone)
187             ScopeDsymbol.setScope(sc);
188     }
189 
190     /***************************************
191      * Returns:
192      *      The total number of fields minus the number of hidden fields.
193      */
nonHiddenFields()194     final size_t nonHiddenFields()
195     {
196         return fields.dim - isNested() - (vthis2 !is null);
197     }
198 
199     /***************************************
200      * Collect all instance fields, then determine instance size.
201      * Returns:
202      *      false if failed to determine the size.
203      */
determineSize(const ref Loc loc)204     final bool determineSize(const ref Loc loc)
205     {
206         //printf("AggregateDeclaration::determineSize() %s, sizeok = %d\n", toChars(), sizeok);
207 
208         // The previous instance size finalizing had:
209         if (type.ty == Terror)
210             return false;   // failed already
211         if (sizeok == Sizeok.done)
212             return true;    // succeeded
213 
214         if (!members)
215         {
216             error(loc, "unknown size");
217             return false;
218         }
219 
220         if (_scope)
221             dsymbolSemantic(this, null);
222 
223         // Determine the instance size of base class first.
224         if (auto cd = isClassDeclaration())
225         {
226             cd = cd.baseClass;
227             if (cd && !cd.determineSize(loc))
228                 goto Lfail;
229         }
230 
231         // Determine instance fields when sizeok == Sizeok.none
232         if (!this.determineFields())
233             goto Lfail;
234         if (sizeok != Sizeok.done)
235             finalizeSize();
236 
237         // this aggregate type has:
238         if (type.ty == Terror)
239             return false;   // marked as invalid during the finalizing.
240         if (sizeok == Sizeok.done)
241             return true;    // succeeded to calculate instance size.
242 
243     Lfail:
244         // There's unresolvable forward reference.
245         if (type != Type.terror)
246             error(loc, "no size because of forward reference");
247         // Don't cache errors from speculative semantic, might be resolvable later.
248         // https://issues.dlang.org/show_bug.cgi?id=16574
249         if (!global.gag)
250         {
251             type = Type.terror;
252             errors = true;
253         }
254         return false;
255     }
256 
257     abstract void finalizeSize();
258 
size(const ref Loc loc)259     override final uinteger_t size(const ref Loc loc)
260     {
261         //printf("+AggregateDeclaration::size() %s, scope = %p, sizeok = %d\n", toChars(), _scope, sizeok);
262         bool ok = determineSize(loc);
263         //printf("-AggregateDeclaration::size() %s, scope = %p, sizeok = %d\n", toChars(), _scope, sizeok);
264         return ok ? structsize : SIZE_INVALID;
265     }
266 
267     /***************************************
268      * Calculate field[i].overlapped and overlapUnsafe, and check that all of explicit
269      * field initializers have unique memory space on instance.
270      * Returns:
271      *      true if any errors happen.
272      */
checkOverlappedFields()273     extern (D) final bool checkOverlappedFields()
274     {
275         //printf("AggregateDeclaration::checkOverlappedFields() %s\n", toChars());
276         assert(sizeok == Sizeok.done);
277         size_t nfields = fields.dim;
278         if (isNested())
279         {
280             auto cd = isClassDeclaration();
281             if (!cd || !cd.baseClass || !cd.baseClass.isNested())
282                 nfields--;
283             if (vthis2 && !(cd && cd.baseClass && cd.baseClass.vthis2))
284                 nfields--;
285         }
286         bool errors = false;
287 
288         // Fill in missing any elements with default initializers
289         foreach (i; 0 .. nfields)
290         {
291             auto vd = fields[i];
292             if (vd.errors)
293             {
294                 errors = true;
295                 continue;
296             }
297 
298             const vdIsVoidInit = vd._init && vd._init.isVoidInitializer();
299 
300             // Find overlapped fields with the hole [vd.offset .. vd.offset.size()].
301             foreach (j; 0 .. nfields)
302             {
303                 if (i == j)
304                     continue;
305                 auto v2 = fields[j];
306                 if (v2.errors)
307                 {
308                     errors = true;
309                     continue;
310                 }
311                 if (!vd.isOverlappedWith(v2))
312                     continue;
313 
314                 // vd and v2 are overlapping.
315                 vd.overlapped = true;
316                 v2.overlapped = true;
317 
318                 if (!MODimplicitConv(vd.type.mod, v2.type.mod))
319                     v2.overlapUnsafe = true;
320                 if (!MODimplicitConv(v2.type.mod, vd.type.mod))
321                     vd.overlapUnsafe = true;
322 
323                 if (i > j)
324                     continue;
325 
326                 if (!v2._init)
327                     continue;
328 
329                 if (v2._init.isVoidInitializer())
330                     continue;
331 
332                 if (vd._init && !vdIsVoidInit && v2._init)
333                 {
334                     .error(loc, "overlapping default initialization for field `%s` and `%s`", v2.toChars(), vd.toChars());
335                     errors = true;
336                 }
337                 else if (v2._init && i < j)
338                 {
339                     .error(v2.loc, "union field `%s` with default initialization `%s` must be before field `%s`",
340                         v2.toChars(), v2._init.toChars(), vd.toChars());
341                     errors = true;
342                 }
343             }
344         }
345         return errors;
346     }
347 
348     /***************************************
349      * Fill out remainder of elements[] with default initializers for fields[].
350      * Params:
351      *      loc         = location
352      *      elements    = explicit arguments which given to construct object.
353      *      ctorinit    = true if the elements will be used for default initialization.
354      * Returns:
355      *      false if any errors occur.
356      *      Otherwise, returns true and the missing arguments will be pushed in elements[].
357      */
fill(const ref Loc loc,Expressions * elements,bool ctorinit)358     final bool fill(const ref Loc loc, Expressions* elements, bool ctorinit)
359     {
360         //printf("AggregateDeclaration::fill() %s\n", toChars());
361         assert(sizeok == Sizeok.done);
362         assert(elements);
363         const nfields = nonHiddenFields();
364         bool errors = false;
365 
366         size_t dim = elements.dim;
367         elements.setDim(nfields);
368         foreach (size_t i; dim .. nfields)
369             (*elements)[i] = null;
370 
371         // Fill in missing any elements with default initializers
372         foreach (i; 0 .. nfields)
373         {
374             if ((*elements)[i])
375                 continue;
376 
377             auto vd = fields[i];
378             auto vx = vd;
379             if (vd._init && vd._init.isVoidInitializer())
380                 vx = null;
381 
382             // Find overlapped fields with the hole [vd.offset .. vd.offset.size()].
383             size_t fieldi = i;
384             foreach (j; 0 .. nfields)
385             {
386                 if (i == j)
387                     continue;
388                 auto v2 = fields[j];
389                 if (!vd.isOverlappedWith(v2))
390                     continue;
391 
392                 if ((*elements)[j])
393                 {
394                     vx = null;
395                     break;
396                 }
397                 if (v2._init && v2._init.isVoidInitializer())
398                     continue;
399 
400                 version (all)
401                 {
402                     /* Prefer first found non-void-initialized field
403                      * union U { int a; int b = 2; }
404                      * U u;    // Error: overlapping initialization for field a and b
405                      */
406                     if (!vx)
407                     {
408                         vx = v2;
409                         fieldi = j;
410                     }
411                     else if (v2._init)
412                     {
413                         .error(loc, "overlapping initialization for field `%s` and `%s`", v2.toChars(), vd.toChars());
414                         errors = true;
415                     }
416                 }
417                 else
418                 {
419                     // fixes https://issues.dlang.org/show_bug.cgi?id=1432 by enabling this path always
420 
421                     /* Prefer explicitly initialized field
422                      * union U { int a; int b = 2; }
423                      * U u;    // OK (u.b == 2)
424                      */
425                     if (!vx || !vx._init && v2._init)
426                     {
427                         vx = v2;
428                         fieldi = j;
429                     }
430                     else if (vx != vd && !vx.isOverlappedWith(v2))
431                     {
432                         // Both vx and v2 fills vd, but vx and v2 does not overlap
433                     }
434                     else if (vx._init && v2._init)
435                     {
436                         .error(loc, "overlapping default initialization for field `%s` and `%s`",
437                             v2.toChars(), vd.toChars());
438                         errors = true;
439                     }
440                     else
441                         assert(vx._init || !vx._init && !v2._init);
442                 }
443             }
444             if (vx)
445             {
446                 Expression e;
447                 if (vx.type.size() == 0)
448                 {
449                     e = null;
450                 }
451                 else if (vx._init)
452                 {
453                     assert(!vx._init.isVoidInitializer());
454                     if (vx.inuse)   // https://issues.dlang.org/show_bug.cgi?id=18057
455                     {
456                         vx.error(loc, "recursive initialization of field");
457                         errors = true;
458                     }
459                     else
460                         e = vx.getConstInitializer(false);
461                 }
462                 else
463                 {
464                     if ((vx.storage_class & STC.nodefaultctor) && !ctorinit)
465                     {
466                         .error(loc, "field `%s.%s` must be initialized because it has no default constructor",
467                             type.toChars(), vx.toChars());
468                         errors = true;
469                     }
470                     /* https://issues.dlang.org/show_bug.cgi?id=12509
471                      * Get the element of static array type.
472                      */
473                     Type telem = vx.type;
474                     if (telem.ty == Tsarray)
475                     {
476                         /* We cannot use Type::baseElemOf() here.
477                          * If the bottom of the Tsarray is an enum type, baseElemOf()
478                          * will return the base of the enum, and its default initializer
479                          * would be different from the enum's.
480                          */
481                         TypeSArray tsa;
482                         while ((tsa = telem.toBasetype().isTypeSArray()) !is null)
483                             telem = tsa.next;
484                         if (telem.ty == Tvoid)
485                             telem = Type.tuns8.addMod(telem.mod);
486                     }
487                     if (telem.needsNested() && ctorinit)
488                         e = telem.defaultInit(loc);
489                     else
490                         e = telem.defaultInitLiteral(loc);
491                 }
492                 (*elements)[fieldi] = e;
493             }
494         }
495         foreach (e; *elements)
496         {
497             if (e && e.op == EXP.error)
498                 return false;
499         }
500 
501         return !errors;
502     }
503 
504     /****************************
505      * Do byte or word alignment as necessary.
506      * Align sizes of 0, as we may not know array sizes yet.
507      * Params:
508      *   alignment = struct alignment that is in effect
509      *   memalignsize = natural alignment of field
510      *   poffset = pointer to offset to be aligned
511      */
alignmember(structalign_t alignment,uint memalignsize,uint * poffset)512     extern (D) static void alignmember(structalign_t alignment, uint memalignsize, uint* poffset) pure nothrow @safe
513     {
514         //debug printf("alignment = %u %d, size = %u, offset = %u\n", alignment.get(), alignment.isPack(), memalignsize, *poffset);
515         uint alignvalue;
516 
517         if (alignment.isDefault())
518         {
519             // Alignment in Target::fieldalignsize must match what the
520             // corresponding C compiler's default alignment behavior is.
521             alignvalue = memalignsize;
522         }
523         else if (alignment.isPack())    // #pragma pack semantics
524         {
525             alignvalue = alignment.get();
526             if (memalignsize < alignvalue)
527                 alignvalue = memalignsize;      // align to min(memalignsize, alignment)
528         }
529         else if (alignment.get() > 1)
530         {
531             // Align on alignment boundary, which must be a positive power of 2
532             alignvalue = alignment.get();
533         }
534         else
535             return;
536 
537         assert(alignvalue > 0 && !(alignvalue & (alignvalue - 1)));
538         *poffset = (*poffset + alignvalue - 1) & ~(alignvalue - 1);
539     }
540 
541     /****************************************
542      * Place a field (mem) into an aggregate (agg), which can be a struct, union or class
543      * Params:
544      *    nextoffset    = location just past the end of the previous field in the aggregate.
545      *                    Updated to be just past the end of this field to be placed, i.e. the future nextoffset
546      *    memsize       = size of field
547      *    memalignsize  = natural alignment of field
548      *    alignment     = alignment in effect for this field
549      *    paggsize      = size of aggregate (updated)
550      *    paggalignsize = alignment of aggregate (updated)
551      *    isunion       = the aggregate is a union
552      * Returns:
553      *    aligned offset to place field at
554      *
555      */
placeField(uint * nextoffset,uint memsize,uint memalignsize,structalign_t alignment,uint * paggsize,uint * paggalignsize,bool isunion)556     extern (D) static uint placeField(uint* nextoffset, uint memsize, uint memalignsize,
557         structalign_t alignment, uint* paggsize, uint* paggalignsize, bool isunion)
558     {
559         uint ofs = *nextoffset;
560 
561         const uint actualAlignment =
562             alignment.isDefault() || alignment.isPack() && memalignsize < alignment.get()
563                         ? memalignsize : alignment.get();
564 
565         // Ensure no overflow
566         bool overflow;
567         const sz = addu(memsize, actualAlignment, overflow);
568         addu(ofs, sz, overflow);
569         if (overflow) assert(0);
570 
571         // Skip no-op for noreturn without custom aligment
572         if (memalignsize != 0 || !alignment.isDefault())
573             alignmember(alignment, memalignsize, &ofs);
574 
575         uint memoffset = ofs;
576         ofs += memsize;
577         if (ofs > *paggsize)
578             *paggsize = ofs;
579         if (!isunion)
580             *nextoffset = ofs;
581 
582         if (*paggalignsize < actualAlignment)
583             *paggalignsize = actualAlignment;
584 
585         return memoffset;
586     }
587 
getType()588     override final Type getType()
589     {
590         /* Apply storage classes to forward references. (Issue 22254)
591          * Note: Avoid interfaces for now. Implementing qualifiers on interface
592          * definitions exposed some issues in their TypeInfo generation in DMD.
593          * Related PR: https://github.com/dlang/dmd/pull/13312
594          */
595         if (semanticRun == PASS.initial && !isInterfaceDeclaration())
596         {
597             auto stc = storage_class;
598             if (_scope)
599                 stc |= _scope.stc;
600             type = type.addSTC(stc);
601         }
602         return type;
603     }
604 
605     // is aggregate deprecated?
isDeprecated()606     override final bool isDeprecated() const
607     {
608         return !!(this.storage_class & STC.deprecated_);
609     }
610 
611     /// Flag this aggregate as deprecated
setDeprecated()612     final void setDeprecated()
613     {
614         this.storage_class |= STC.deprecated_;
615     }
616 
617     /****************************************
618      * Returns true if there's an extra member which is the 'this'
619      * pointer to the enclosing context (enclosing aggregate or function)
620      */
isNested()621     final bool isNested() const
622     {
623         return enclosing !is null;
624     }
625 
626     /* Append vthis field (this.tupleof[$-1]) to make this aggregate type nested.
627      */
makeNested()628     extern (D) final void makeNested()
629     {
630         if (enclosing) // if already nested
631             return;
632         if (sizeok == Sizeok.done)
633             return;
634         if (isUnionDeclaration() || isInterfaceDeclaration())
635             return;
636         if (storage_class & STC.static_)
637             return;
638 
639         // If nested struct, add in hidden 'this' pointer to outer scope
640         auto s = toParentLocal();
641         if (!s)
642             s = toParent2();
643         if (!s)
644             return;
645         Type t = null;
646         if (auto fd = s.isFuncDeclaration())
647         {
648             enclosing = fd;
649 
650             /* https://issues.dlang.org/show_bug.cgi?id=14422
651              * If a nested class parent is a function, its
652              * context pointer (== `outer`) should be void* always.
653              */
654             t = Type.tvoidptr;
655         }
656         else if (auto ad = s.isAggregateDeclaration())
657         {
658             if (isClassDeclaration() && ad.isClassDeclaration())
659             {
660                 enclosing = ad;
661             }
662             else if (isStructDeclaration())
663             {
664                 if (auto ti = ad.parent.isTemplateInstance())
665                 {
666                     enclosing = ti.enclosing;
667                 }
668             }
669             t = ad.handleType();
670         }
671         if (enclosing)
672         {
673             //printf("makeNested %s, enclosing = %s\n", toChars(), enclosing.toChars());
674             assert(t);
675             if (t.ty == Tstruct)
676                 t = Type.tvoidptr; // t should not be a ref type
677 
678             assert(!vthis);
679             vthis = new ThisDeclaration(loc, t);
680             //vthis.storage_class |= STC.ref_;
681 
682             // Emulate vthis.addMember()
683             members.push(vthis);
684 
685             // Emulate vthis.dsymbolSemantic()
686             vthis.storage_class |= STC.field;
687             vthis.parent = this;
688             vthis.visibility = Visibility(Visibility.Kind.public_);
689             vthis.alignment = t.alignment();
690             vthis.semanticRun = PASS.semanticdone;
691 
692             if (sizeok == Sizeok.fwd)
693                 fields.push(vthis);
694 
695             makeNested2();
696         }
697     }
698 
699     /* Append vthis2 field (this.tupleof[$-1]) to add a second context pointer.
700      */
makeNested2()701     extern (D) final void makeNested2()
702     {
703         if (vthis2)
704             return;
705         if (!vthis)
706             makeNested();   // can't add second before first
707         if (!vthis)
708             return;
709         if (sizeok == Sizeok.done)
710             return;
711         if (isUnionDeclaration() || isInterfaceDeclaration())
712             return;
713         if (storage_class & STC.static_)
714             return;
715 
716         auto s0 = toParentLocal();
717         auto s = toParent2();
718         if (!s || !s0 || s == s0)
719             return;
720         auto cd = s.isClassDeclaration();
721         Type t = cd ? cd.type : Type.tvoidptr;
722 
723         vthis2 = new ThisDeclaration(loc, t);
724         //vthis2.storage_class |= STC.ref_;
725 
726         // Emulate vthis2.addMember()
727         members.push(vthis2);
728 
729         // Emulate vthis2.dsymbolSemantic()
730         vthis2.storage_class |= STC.field;
731         vthis2.parent = this;
732         vthis2.visibility = Visibility(Visibility.Kind.public_);
733         vthis2.alignment = t.alignment();
734         vthis2.semanticRun = PASS.semanticdone;
735 
736         if (sizeok == Sizeok.fwd)
737             fields.push(vthis2);
738     }
739 
isExport()740     override final bool isExport() const
741     {
742         return visibility.kind == Visibility.Kind.export_;
743     }
744 
745     /*******************************************
746      * Look for constructor declaration.
747      */
searchCtor()748     final Dsymbol searchCtor()
749     {
750         auto s = search(Loc.initial, Id.ctor);
751         if (s)
752         {
753             if (!(s.isCtorDeclaration() ||
754                   s.isTemplateDeclaration() ||
755                   s.isOverloadSet()))
756             {
757                 s.error("is not a constructor; identifiers starting with `__` are reserved for the implementation");
758                 errors = true;
759                 s = null;
760             }
761         }
762         if (s && s.toParent() != this)
763             s = null; // search() looks through ancestor classes
764         if (s)
765         {
766             // Finish all constructors semantics to determine this.noDefaultCtor.
767             struct SearchCtor
768             {
769                 extern (C++) static int fp(Dsymbol s, void* ctxt)
770                 {
771                     auto f = s.isCtorDeclaration();
772                     if (f && f.semanticRun == PASS.initial)
773                         f.dsymbolSemantic(null);
774                     return 0;
775                 }
776             }
777 
778             for (size_t i = 0; i < members.dim; i++)
779             {
780                 auto sm = (*members)[i];
781                 sm.apply(&SearchCtor.fp, null);
782             }
783         }
784         return s;
785     }
786 
visible()787     override final Visibility visible() pure nothrow @nogc @safe
788     {
789         return visibility;
790     }
791 
792     // 'this' type
handleType()793     final Type handleType()
794     {
795         return type;
796     }
797 
798     // Does this class have an invariant function?
hasInvariant()799     final bool hasInvariant()
800     {
801         return invs.length != 0;
802     }
803 
804     // Back end
805     void* sinit;  /// initializer symbol
806 
inout(AggregateDeclaration)807     override final inout(AggregateDeclaration) isAggregateDeclaration() inout
808     {
809         return this;
810     }
811 
accept(Visitor v)812     override void accept(Visitor v)
813     {
814         v.visit(this);
815     }
816 }
817