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-2021 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 : ubyte
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 : ubyte
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 : ubyte
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     ///
129     Visibility visibility;
130     bool noDefaultCtor;             /// no default construction
131     Sizeok sizeok = Sizeok.none;    /// set when structsize contains valid data
132 
133     final extern (D) this(const ref Loc loc, Identifier id)
134     {
135         super(loc, id);
136         visibility = Visibility(Visibility.Kind.public_);
137     }
138 
139     /***************************************
140      * Create a new scope from sc.
141      * semantic, semantic2 and semantic3 will use this for aggregate members.
142      */
143     Scope* newScope(Scope* sc)
144     {
145         auto sc2 = sc.push(this);
146         sc2.stc &= STCFlowThruAggregate;
147         sc2.parent = this;
148         sc2.inunion = isUnionDeclaration();
149         sc2.visibility = Visibility(Visibility.Kind.public_);
150         sc2.explicitVisibility = 0;
151         sc2.aligndecl = null;
152         sc2.userAttribDecl = null;
153         sc2.namespace = null;
154         return sc2;
155     }
156 
157     override final void setScope(Scope* sc)
158     {
159         // Might need a scope to resolve forward references. The check for
160         // semanticRun prevents unnecessary setting of _scope during deferred
161         // setScope phases for aggregates which already finished semantic().
162         // See https://issues.dlang.org/show_bug.cgi?id=16607
163         if (semanticRun < PASS.semanticdone)
164             ScopeDsymbol.setScope(sc);
165     }
166 
167     /***************************************
168      * Find all instance fields, then push them into `fields`.
169      *
170      * Runs semantic() for all instance field variables, but also
171      * the field types can remain yet not resolved forward references,
172      * except direct recursive definitions.
173      * After the process sizeok is set to Sizeok.fwd.
174      *
175      * Returns:
176      *      false if any errors occur.
177      */
178     final bool determineFields()
179     {
180         if (_scope)
181             dsymbolSemantic(this, null);
182         if (sizeok != Sizeok.none)
183             return true;
184 
185         //printf("determineFields() %s, fields.dim = %d\n", toChars(), fields.dim);
186         // determineFields can be called recursively from one of the fields's v.semantic
187         fields.setDim(0);
188 
189         static int func(Dsymbol s, AggregateDeclaration ad)
190         {
191             auto v = s.isVarDeclaration();
192             if (!v)
193                 return 0;
194             if (v.storage_class & STC.manifest)
195                 return 0;
196 
197             if (v.semanticRun < PASS.semanticdone)
198                 v.dsymbolSemantic(null);
199             // Return in case a recursive determineFields triggered by v.semantic already finished
200             if (ad.sizeok != Sizeok.none)
201                 return 1;
202 
203             if (v.aliassym)
204                 return 0;   // If this variable was really a tuple, skip it.
205 
206             if (v.storage_class & (STC.static_ | STC.extern_ | STC.tls | STC.gshared | STC.manifest | STC.ctfe | STC.templateparameter))
207                 return 0;
208             if (!v.isField() || v.semanticRun < PASS.semanticdone)
209                 return 1;   // unresolvable forward reference
210 
211             ad.fields.push(v);
212 
213             if (v.storage_class & STC.ref_)
214                 return 0;
215             auto tv = v.type.baseElemOf();
216             if (tv.ty != Tstruct)
217                 return 0;
218             if (ad == (cast(TypeStruct)tv).sym)
219             {
220                 const(char)* psz = (v.type.toBasetype().ty == Tsarray) ? "static array of " : "";
221                 ad.error("cannot have field `%s` with %ssame struct type", v.toChars(), psz);
222                 ad.type = Type.terror;
223                 ad.errors = true;
224                 return 1;
225             }
226             return 0;
227         }
228 
229         if (members)
230         {
231             for (size_t i = 0; i < members.dim; i++)
232             {
233                 auto s = (*members)[i];
234                 if (s.apply(&func, this))
235                 {
236                     if (sizeok != Sizeok.none)
237                     {
238                         // recursive determineFields already finished
239                         return true;
240                     }
241                     return false;
242                 }
243             }
244         }
245 
246         if (sizeok != Sizeok.done)
247             sizeok = Sizeok.fwd;
248 
249         return true;
250     }
251 
252     /***************************************
253      * Returns:
254      *      The total number of fields minus the number of hidden fields.
255      */
256     final size_t nonHiddenFields()
257     {
258         return fields.dim - isNested() - (vthis2 !is null);
259     }
260 
261     /***************************************
262      * Collect all instance fields, then determine instance size.
263      * Returns:
264      *      false if failed to determine the size.
265      */
266     final bool determineSize(Loc loc)
267     {
268         //printf("AggregateDeclaration::determineSize() %s, sizeok = %d\n", toChars(), sizeok);
269 
270         // The previous instance size finalizing had:
271         if (type.ty == Terror)
272             return false;   // failed already
273         if (sizeok == Sizeok.done)
274             return true;    // succeeded
275 
276         if (!members)
277         {
278             error(loc, "unknown size");
279             return false;
280         }
281 
282         if (_scope)
283             dsymbolSemantic(this, null);
284 
285         // Determine the instance size of base class first.
286         if (auto cd = isClassDeclaration())
287         {
288             cd = cd.baseClass;
289             if (cd && !cd.determineSize(loc))
290                 goto Lfail;
291         }
292 
293         // Determine instance fields when sizeok == Sizeok.none
294         if (!determineFields())
295             goto Lfail;
296         if (sizeok != Sizeok.done)
297             finalizeSize();
298 
299         // this aggregate type has:
300         if (type.ty == Terror)
301             return false;   // marked as invalid during the finalizing.
302         if (sizeok == Sizeok.done)
303             return true;    // succeeded to calculate instance size.
304 
305     Lfail:
306         // There's unresolvable forward reference.
307         if (type != Type.terror)
308             error(loc, "no size because of forward reference");
309         // Don't cache errors from speculative semantic, might be resolvable later.
310         // https://issues.dlang.org/show_bug.cgi?id=16574
311         if (!global.gag)
312         {
313             type = Type.terror;
314             errors = true;
315         }
316         return false;
317     }
318 
319     abstract void finalizeSize();
320 
321     override final d_uns64 size(const ref Loc loc)
322     {
323         //printf("+AggregateDeclaration::size() %s, scope = %p, sizeok = %d\n", toChars(), _scope, sizeok);
324         bool ok = determineSize(loc);
325         //printf("-AggregateDeclaration::size() %s, scope = %p, sizeok = %d\n", toChars(), _scope, sizeok);
326         return ok ? structsize : SIZE_INVALID;
327     }
328 
329     /***************************************
330      * Calculate field[i].overlapped and overlapUnsafe, and check that all of explicit
331      * field initializers have unique memory space on instance.
332      * Returns:
333      *      true if any errors happen.
334      */
335     extern (D) final bool checkOverlappedFields()
336     {
337         //printf("AggregateDeclaration::checkOverlappedFields() %s\n", toChars());
338         assert(sizeok == Sizeok.done);
339         size_t nfields = fields.dim;
340         if (isNested())
341         {
342             auto cd = isClassDeclaration();
343             if (!cd || !cd.baseClass || !cd.baseClass.isNested())
344                 nfields--;
345             if (vthis2 && !(cd && cd.baseClass && cd.baseClass.vthis2))
346                 nfields--;
347         }
348         bool errors = false;
349 
350         // Fill in missing any elements with default initializers
351         foreach (i; 0 .. nfields)
352         {
353             auto vd = fields[i];
354             if (vd.errors)
355             {
356                 errors = true;
357                 continue;
358             }
359 
360             const vdIsVoidInit = vd._init && vd._init.isVoidInitializer();
361 
362             // Find overlapped fields with the hole [vd.offset .. vd.offset.size()].
363             foreach (j; 0 .. nfields)
364             {
365                 if (i == j)
366                     continue;
367                 auto v2 = fields[j];
368                 if (v2.errors)
369                 {
370                     errors = true;
371                     continue;
372                 }
373                 if (!vd.isOverlappedWith(v2))
374                     continue;
375 
376                 // vd and v2 are overlapping.
377                 vd.overlapped = true;
378                 v2.overlapped = true;
379 
380                 if (!MODimplicitConv(vd.type.mod, v2.type.mod))
381                     v2.overlapUnsafe = true;
382                 if (!MODimplicitConv(v2.type.mod, vd.type.mod))
383                     vd.overlapUnsafe = true;
384 
385                 if (i > j)
386                     continue;
387 
388                 if (!v2._init)
389                     continue;
390 
391                 if (v2._init.isVoidInitializer())
392                     continue;
393 
394                 if (vd._init && !vdIsVoidInit && v2._init)
395                 {
396                     .error(loc, "overlapping default initialization for field `%s` and `%s`", v2.toChars(), vd.toChars());
397                     errors = true;
398                 }
399                 else if (v2._init && i < j)
400                 {
401                     // @@@DEPRECATED_v2.086@@@.
402                     .deprecation(v2.loc, "union field `%s` with default initialization `%s` must be before field `%s`",
403                         v2.toChars(), v2._init.toChars(), vd.toChars());
404                     //errors = true;
405                 }
406             }
407         }
408         return errors;
409     }
410 
411     /***************************************
412      * Fill out remainder of elements[] with default initializers for fields[].
413      * Params:
414      *      loc         = location
415      *      elements    = explicit arguments which given to construct object.
416      *      ctorinit    = true if the elements will be used for default initialization.
417      * Returns:
418      *      false if any errors occur.
419      *      Otherwise, returns true and the missing arguments will be pushed in elements[].
420      */
421     final bool fill(Loc loc, Expressions* elements, bool ctorinit)
422     {
423         //printf("AggregateDeclaration::fill() %s\n", toChars());
424         assert(sizeok == Sizeok.done);
425         assert(elements);
426         const nfields = nonHiddenFields();
427         bool errors = false;
428 
429         size_t dim = elements.dim;
430         elements.setDim(nfields);
431         foreach (size_t i; dim .. nfields)
432             (*elements)[i] = null;
433 
434         // Fill in missing any elements with default initializers
435         foreach (i; 0 .. nfields)
436         {
437             if ((*elements)[i])
438                 continue;
439 
440             auto vd = fields[i];
441             auto vx = vd;
442             if (vd._init && vd._init.isVoidInitializer())
443                 vx = null;
444 
445             // Find overlapped fields with the hole [vd.offset .. vd.offset.size()].
446             size_t fieldi = i;
447             foreach (j; 0 .. nfields)
448             {
449                 if (i == j)
450                     continue;
451                 auto v2 = fields[j];
452                 if (!vd.isOverlappedWith(v2))
453                     continue;
454 
455                 if ((*elements)[j])
456                 {
457                     vx = null;
458                     break;
459                 }
460                 if (v2._init && v2._init.isVoidInitializer())
461                     continue;
462 
463                 version (all)
464                 {
465                     /* Prefer first found non-void-initialized field
466                      * union U { int a; int b = 2; }
467                      * U u;    // Error: overlapping initialization for field a and b
468                      */
469                     if (!vx)
470                     {
471                         vx = v2;
472                         fieldi = j;
473                     }
474                     else if (v2._init)
475                     {
476                         .error(loc, "overlapping initialization for field `%s` and `%s`", v2.toChars(), vd.toChars());
477                         errors = true;
478                     }
479                 }
480                 else
481                 {
482                     // fixes https://issues.dlang.org/show_bug.cgi?id=1432 by enabling this path always
483 
484                     /* Prefer explicitly initialized field
485                      * union U { int a; int b = 2; }
486                      * U u;    // OK (u.b == 2)
487                      */
488                     if (!vx || !vx._init && v2._init)
489                     {
490                         vx = v2;
491                         fieldi = j;
492                     }
493                     else if (vx != vd && !vx.isOverlappedWith(v2))
494                     {
495                         // Both vx and v2 fills vd, but vx and v2 does not overlap
496                     }
497                     else if (vx._init && v2._init)
498                     {
499                         .error(loc, "overlapping default initialization for field `%s` and `%s`",
500                             v2.toChars(), vd.toChars());
501                         errors = true;
502                     }
503                     else
504                         assert(vx._init || !vx._init && !v2._init);
505                 }
506             }
507             if (vx)
508             {
509                 Expression e;
510                 if (vx.type.size() == 0)
511                 {
512                     e = null;
513                 }
514                 else if (vx._init)
515                 {
516                     assert(!vx._init.isVoidInitializer());
517                     if (vx.inuse)   // https://issues.dlang.org/show_bug.cgi?id=18057
518                     {
519                         vx.error(loc, "recursive initialization of field");
520                         errors = true;
521                     }
522                     else
523                         e = vx.getConstInitializer(false);
524                 }
525                 else
526                 {
527                     if ((vx.storage_class & STC.nodefaultctor) && !ctorinit)
528                     {
529                         .error(loc, "field `%s.%s` must be initialized because it has no default constructor",
530                             type.toChars(), vx.toChars());
531                         errors = true;
532                     }
533                     /* https://issues.dlang.org/show_bug.cgi?id=12509
534                      * Get the element of static array type.
535                      */
536                     Type telem = vx.type;
537                     if (telem.ty == Tsarray)
538                     {
539                         /* We cannot use Type::baseElemOf() here.
540                          * If the bottom of the Tsarray is an enum type, baseElemOf()
541                          * will return the base of the enum, and its default initializer
542                          * would be different from the enum's.
543                          */
544                         while (telem.toBasetype().ty == Tsarray)
545                             telem = (cast(TypeSArray)telem.toBasetype()).next;
546                         if (telem.ty == Tvoid)
547                             telem = Type.tuns8.addMod(telem.mod);
548                     }
549                     if (telem.needsNested() && ctorinit)
550                         e = telem.defaultInit(loc);
551                     else
552                         e = telem.defaultInitLiteral(loc);
553                 }
554                 (*elements)[fieldi] = e;
555             }
556         }
557         foreach (e; *elements)
558         {
559             if (e && e.op == TOK.error)
560                 return false;
561         }
562 
563         return !errors;
564     }
565 
566     /****************************
567      * Do byte or word alignment as necessary.
568      * Align sizes of 0, as we may not know array sizes yet.
569      * Params:
570      *   alignment = struct alignment that is in effect
571      *   size = alignment requirement of field
572      *   poffset = pointer to offset to be aligned
573      */
574     extern (D) static void alignmember(structalign_t alignment, uint size, uint* poffset) pure nothrow @safe
575     {
576         //printf("alignment = %d, size = %d, offset = %d\n",alignment,size,offset);
577         switch (alignment)
578         {
579         case cast(structalign_t)1:
580             // No alignment
581             break;
582 
583         case cast(structalign_t)STRUCTALIGN_DEFAULT:
584             // Alignment in Target::fieldalignsize must match what the
585             // corresponding C compiler's default alignment behavior is.
586             assert(size > 0 && !(size & (size - 1)));
587             *poffset = (*poffset + size - 1) & ~(size - 1);
588             break;
589 
590         default:
591             // Align on alignment boundary, which must be a positive power of 2
592             assert(alignment > 0 && !(alignment & (alignment - 1)));
593             *poffset = (*poffset + alignment - 1) & ~(alignment - 1);
594             break;
595         }
596     }
597 
598     /****************************************
599      * Place a member (mem) into an aggregate (agg), which can be a struct, union or class
600      * Returns:
601      *      offset to place field at
602      *
603      * nextoffset:    next location in aggregate
604      * memsize:       size of member
605      * memalignsize:  natural alignment of member
606      * alignment:     alignment in effect for this member
607      * paggsize:      size of aggregate (updated)
608      * paggalignsize: alignment of aggregate (updated)
609      * isunion:       the aggregate is a union
610      */
611     extern (D) static uint placeField(uint* nextoffset, uint memsize, uint memalignsize,
612         structalign_t alignment, uint* paggsize, uint* paggalignsize, bool isunion)
613     {
614         uint ofs = *nextoffset;
615 
616         const uint actualAlignment =
617             alignment == STRUCTALIGN_DEFAULT ? memalignsize : alignment;
618 
619         // Ensure no overflow
620         bool overflow;
621         const sz = addu(memsize, actualAlignment, overflow);
622         addu(ofs, sz, overflow);
623         if (overflow) assert(0);
624 
625         alignmember(alignment, memalignsize, &ofs);
626         uint memoffset = ofs;
627         ofs += memsize;
628         if (ofs > *paggsize)
629             *paggsize = ofs;
630         if (!isunion)
631             *nextoffset = ofs;
632 
633         if (*paggalignsize < actualAlignment)
634             *paggalignsize = actualAlignment;
635 
636         return memoffset;
637     }
638 
639     override final Type getType()
640     {
641         return type;
642     }
643 
644     // is aggregate deprecated?
645     override final bool isDeprecated() const
646     {
647         return !!(this.storage_class & STC.deprecated_);
648     }
649 
650     /// Flag this aggregate as deprecated
651     final void setDeprecated()
652     {
653         this.storage_class |= STC.deprecated_;
654     }
655 
656     /****************************************
657      * Returns true if there's an extra member which is the 'this'
658      * pointer to the enclosing context (enclosing aggregate or function)
659      */
660     final bool isNested() const
661     {
662         return enclosing !is null;
663     }
664 
665     /* Append vthis field (this.tupleof[$-1]) to make this aggregate type nested.
666      */
667     extern (D) final void makeNested()
668     {
669         if (enclosing) // if already nested
670             return;
671         if (sizeok == Sizeok.done)
672             return;
673         if (isUnionDeclaration() || isInterfaceDeclaration())
674             return;
675         if (storage_class & STC.static_)
676             return;
677 
678         // If nested struct, add in hidden 'this' pointer to outer scope
679         auto s = toParentLocal();
680         if (!s)
681             s = toParent2();
682         if (!s)
683             return;
684         Type t = null;
685         if (auto fd = s.isFuncDeclaration())
686         {
687             enclosing = fd;
688 
689             /* https://issues.dlang.org/show_bug.cgi?id=14422
690              * If a nested class parent is a function, its
691              * context pointer (== `outer`) should be void* always.
692              */
693             t = Type.tvoidptr;
694         }
695         else if (auto ad = s.isAggregateDeclaration())
696         {
697             if (isClassDeclaration() && ad.isClassDeclaration())
698             {
699                 enclosing = ad;
700             }
701             else if (isStructDeclaration())
702             {
703                 if (auto ti = ad.parent.isTemplateInstance())
704                 {
705                     enclosing = ti.enclosing;
706                 }
707             }
708             t = ad.handleType();
709         }
710         if (enclosing)
711         {
712             //printf("makeNested %s, enclosing = %s\n", toChars(), enclosing.toChars());
713             assert(t);
714             if (t.ty == Tstruct)
715                 t = Type.tvoidptr; // t should not be a ref type
716 
717             assert(!vthis);
718             vthis = new ThisDeclaration(loc, t);
719             //vthis.storage_class |= STC.ref_;
720 
721             // Emulate vthis.addMember()
722             members.push(vthis);
723 
724             // Emulate vthis.dsymbolSemantic()
725             vthis.storage_class |= STC.field;
726             vthis.parent = this;
727             vthis.visibility = Visibility(Visibility.Kind.public_);
728             vthis.alignment = t.alignment();
729             vthis.semanticRun = PASS.semanticdone;
730 
731             if (sizeok == Sizeok.fwd)
732                 fields.push(vthis);
733 
734             makeNested2();
735         }
736     }
737 
738     /* Append vthis2 field (this.tupleof[$-1]) to add a second context pointer.
739      */
740     extern (D) final void makeNested2()
741     {
742         if (vthis2)
743             return;
744         if (!vthis)
745             makeNested();   // can't add second before first
746         if (!vthis)
747             return;
748         if (sizeok == Sizeok.done)
749             return;
750         if (isUnionDeclaration() || isInterfaceDeclaration())
751             return;
752         if (storage_class & STC.static_)
753             return;
754 
755         auto s0 = toParentLocal();
756         auto s = toParent2();
757         if (!s || !s0 || s == s0)
758             return;
759         auto cd = s.isClassDeclaration();
760         Type t = cd ? cd.type : Type.tvoidptr;
761 
762         vthis2 = new ThisDeclaration(loc, t);
763         //vthis2.storage_class |= STC.ref_;
764 
765         // Emulate vthis2.addMember()
766         members.push(vthis2);
767 
768         // Emulate vthis2.dsymbolSemantic()
769         vthis2.storage_class |= STC.field;
770         vthis2.parent = this;
771         vthis2.visibility = Visibility(Visibility.Kind.public_);
772         vthis2.alignment = t.alignment();
773         vthis2.semanticRun = PASS.semanticdone;
774 
775         if (sizeok == Sizeok.fwd)
776             fields.push(vthis2);
777     }
778 
779     override final bool isExport() const
780     {
781         return visibility.kind == Visibility.Kind.export_;
782     }
783 
784     /*******************************************
785      * Look for constructor declaration.
786      */
787     final Dsymbol searchCtor()
788     {
789         auto s = search(Loc.initial, Id.ctor);
790         if (s)
791         {
792             if (!(s.isCtorDeclaration() ||
793                   s.isTemplateDeclaration() ||
794                   s.isOverloadSet()))
795             {
796                 s.error("is not a constructor; identifiers starting with `__` are reserved for the implementation");
797                 errors = true;
798                 s = null;
799             }
800         }
801         if (s && s.toParent() != this)
802             s = null; // search() looks through ancestor classes
803         if (s)
804         {
805             // Finish all constructors semantics to determine this.noDefaultCtor.
806             struct SearchCtor
807             {
808                 extern (C++) static int fp(Dsymbol s, void* ctxt)
809                 {
810                     auto f = s.isCtorDeclaration();
811                     if (f && f.semanticRun == PASS.init)
812                         f.dsymbolSemantic(null);
813                     return 0;
814                 }
815             }
816 
817             for (size_t i = 0; i < members.dim; i++)
818             {
819                 auto sm = (*members)[i];
820                 sm.apply(&SearchCtor.fp, null);
821             }
822         }
823         return s;
824     }
825 
826     override final Visibility visible() pure nothrow @nogc @safe
827     {
828         return visibility;
829     }
830 
831     // 'this' type
832     final Type handleType()
833     {
834         return type;
835     }
836 
837     // Back end
838     Symbol* stag;   /// tag symbol for debug data
839     Symbol* sinit;  /// initializer symbol
840 
841     override final inout(AggregateDeclaration) isAggregateDeclaration() inout
842     {
843         return this;
844     }
845 
846     override void accept(Visitor v)
847     {
848         v.visit(this);
849     }
850 }