1 /**
2  * Compiler implementation of the
3  * $(LINK2 http://www.dlang.org, D programming language).
4  *
5  * Copyright:   Copyright (c) 1999-2016 by Digital Mars, All Rights Reserved
6  * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
7  * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
8  * Source:      $(DMDSRC _aggregate.d)
9  */
10 
11 module ddmd.aggregate;
12 
13 import core.stdc.stdio;
14 import ddmd.arraytypes;
15 import ddmd.gluelayer;
16 import ddmd.declaration;
17 import ddmd.dscope;
18 import ddmd.dstruct;
19 import ddmd.dsymbol;
20 import ddmd.dtemplate;
21 import ddmd.errors;
22 import ddmd.expression;
23 import ddmd.func;
24 import ddmd.globals;
25 import ddmd.id;
26 import ddmd.identifier;
27 import ddmd.mtype;
28 import ddmd.tokens;
29 import ddmd.visitor;
30 
31 enum Sizeok : int
32 {
33     SIZEOKnone,             // size of aggregate is not yet able to compute
34     SIZEOKfwd,              // size of aggregate is ready to compute
35     SIZEOKdone,             // size of aggregate is set correctly
36 }
37 
38 alias SIZEOKnone = Sizeok.SIZEOKnone;
39 alias SIZEOKdone = Sizeok.SIZEOKdone;
40 alias SIZEOKfwd = Sizeok.SIZEOKfwd;
41 
42 enum Baseok : int
43 {
44     BASEOKnone,             // base classes not computed yet
45     BASEOKin,               // in process of resolving base classes
46     BASEOKdone,             // all base classes are resolved
47     BASEOKsemanticdone,     // all base classes semantic done
48 }
49 
50 alias BASEOKnone = Baseok.BASEOKnone;
51 alias BASEOKin = Baseok.BASEOKin;
52 alias BASEOKdone = Baseok.BASEOKdone;
53 alias BASEOKsemanticdone = Baseok.BASEOKsemanticdone;
54 
55 /***********************************************************
56  */
57 extern (C++) abstract class AggregateDeclaration : ScopeDsymbol
58 {
59     Type type;
60     StorageClass storage_class;
61     Prot protection;
62     uint structsize;        // size of struct
63     uint alignsize;         // size of struct for alignment purposes
64     VarDeclarations fields; // VarDeclaration fields
65     Sizeok sizeok;          // set when structsize contains valid data
66     Dsymbol deferred;       // any deferred semantic2() or semantic3() symbol
67     bool isdeprecated;      // true if deprecated
68 
69     /* !=null if is nested
70      * pointing to the dsymbol that directly enclosing it.
71      * 1. The function that enclosing it (nested struct and class)
72      * 2. The class that enclosing it (nested class only)
73      * 3. If enclosing aggregate is template, its enclosing dsymbol.
74      * See AggregateDeclaraton::makeNested for the details.
75      */
76     Dsymbol enclosing;
77 
78     VarDeclaration vthis;   // 'this' parameter if this aggregate is nested
79 
80     // Special member functions
81     FuncDeclarations invs;          // Array of invariants
82     FuncDeclaration inv;            // invariant
83     NewDeclaration aggNew;          // allocator
84     DeleteDeclaration aggDelete;    // deallocator
85 
86     // CtorDeclaration or TemplateDeclaration
87     Dsymbol ctor;
88 
89     // default constructor - should have no arguments, because
90     // it would be stored in TypeInfo_Class.defaultConstructor
91     CtorDeclaration defaultCtor;
92 
93     Dsymbol aliasthis;      // forward unresolved lookups to aliasthis
94     bool noDefaultCtor;     // no default construction
95 
96     FuncDeclarations dtors; // Array of destructors
97     FuncDeclaration dtor;   // aggregate destructor
98 
99     Expression getRTInfo;   // pointer to GC info generated by object.RTInfo(this)
100 
101     final extern (D) this(Loc loc, Identifier id)
102     {
103         super(id);
104         this.loc = loc;
105         protection = Prot(PROTpublic);
106         sizeok = SIZEOKnone; // size not determined yet
107     }
108 
109     /***************************************
110      * Create a new scope from sc.
111      * semantic, semantic2 and semantic3 will use this for aggregate members.
112      */
113     Scope* newScope(Scope* sc)
114     {
115         auto sc2 = sc.push(this);
116         sc2.stc &= STCsafe | STCtrusted | STCsystem;
117         sc2.parent = this;
118         if (isUnionDeclaration())
119             sc2.inunion = 1;
120         sc2.protection = Prot(PROTpublic);
121         sc2.explicitProtection = 0;
122         sc2.aligndecl = null;
123         sc2.userAttribDecl = null;
124         return sc2;
125     }
126 
127     override final void semantic2(Scope* sc)
128     {
129         //printf("AggregateDeclaration::semantic2(%s) type = %s, errors = %d\n", toChars(), type.toChars(), errors);
130         if (!members)
131             return;
132 
133         if (_scope)
134         {
135             error("has forward references");
136             return;
137         }
138 
139         auto sc2 = newScope(sc);
140 
141         determineSize(loc);
142 
143         for (size_t i = 0; i < members.dim; i++)
144         {
145             Dsymbol s = (*members)[i];
146             //printf("\t[%d] %s\n", i, s.toChars());
147             s.semantic2(sc2);
148         }
149 
150         sc2.pop();
151     }
152 
153     override final void semantic3(Scope* sc)
154     {
155         //printf("AggregateDeclaration::semantic3(%s) type = %s, errors = %d\n", toChars(), type.toChars(), errors);
156         if (!members)
157             return;
158 
159         StructDeclaration sd = isStructDeclaration();
160         if (!sc) // from runDeferredSemantic3 for TypeInfo generation
161         {
162             assert(sd);
163             sd.semanticTypeInfoMembers();
164             return;
165         }
166 
167         auto sc2 = newScope(sc);
168 
169         for (size_t i = 0; i < members.dim; i++)
170         {
171             Dsymbol s = (*members)[i];
172             s.semantic3(sc2);
173         }
174 
175         sc2.pop();
176 
177         // don't do it for unused deprecated types
178         // or error types
179         if (!getRTInfo && Type.rtinfo && (!isDeprecated() || global.params.useDeprecated) && (type && type.ty != Terror))
180         {
181             // Evaluate: RTinfo!type
182             auto tiargs = new Objects();
183             tiargs.push(type);
184             auto ti = new TemplateInstance(loc, Type.rtinfo, tiargs);
185 
186             Scope* sc3 = ti.tempdecl._scope.startCTFE();
187             sc3.tinst = sc.tinst;
188             sc3.minst = sc.minst;
189             if (isDeprecated())
190                 sc3.stc |= STCdeprecated;
191 
192             ti.semantic(sc3);
193             ti.semantic2(sc3);
194             ti.semantic3(sc3);
195             auto e = DsymbolExp.resolve(Loc(), sc3, ti.toAlias(), false);
196 
197             sc3.endCTFE();
198 
199             e = e.ctfeInterpret();
200             getRTInfo = e;
201         }
202         if (sd)
203             sd.semanticTypeInfoMembers();
204     }
205 
206     /***************************************
207      * Find all instance fields, then push them into `fields`.
208      *
209      * Runs semantic() for all instance field variables, but also
210      * the field types can reamin yet not resolved forward references,
211      * except direct recursive definitions.
212      * After the process sizeok is set to SIZEOKfwd.
213      *
214      * Returns:
215      *      false if any errors occur.
216      */
217     final bool determineFields()
218     {
219         if (sizeok != SIZEOKnone)
220             return true;
221 
222         //printf("determineFields() %s, fields.dim = %d\n", toChars(), fields.dim);
223 
224         extern (C++) static int func(Dsymbol s, void* param)
225         {
226             auto v = s.isVarDeclaration();
227             if (!v)
228                 return 0;
229             if (v.storage_class & STCmanifest)
230                 return 0;
231 
232             if (v._scope)
233                 v.semantic(null);
234             if (v.aliassym)
235                 return 0;   // If this variable was really a tuple, skip it.
236 
237             if (v.storage_class & (STCstatic | STCextern | STCtls | STCgshared | STCmanifest | STCctfe | STCtemplateparameter))
238                 return 0;
239             if (!v.isField() || v.semanticRun < PASSsemanticdone)
240                 return 1;   // unresolvable forward reference
241 
242             auto ad = cast(AggregateDeclaration)param;
243             ad.fields.push(v);
244 
245             if (v.storage_class & STCref)
246                 return 0;
247             auto tv = v.type.baseElemOf();
248             if (tv.ty != Tstruct)
249                 return 0;
250             if (ad == (cast(TypeStruct)tv).sym)
251             {
252                 const(char)* psz = (v.type.toBasetype().ty == Tsarray) ? "static array of " : "";
253                 ad.error("cannot have field %s with %ssame struct type", v.toChars(), psz);
254                 ad.type = Type.terror;
255                 ad.errors = true;
256                 return 1;
257             }
258             return 0;
259         }
260 
261         fields.setDim(0);
262 
263         for (size_t i = 0; i < members.dim; i++)
264         {
265             auto s = (*members)[i];
266             if (s.apply(&func, cast(void*)this))
267                 return false;
268         }
269 
270         if (sizeok != SIZEOKdone)
271             sizeok = SIZEOKfwd;
272 
273         return true;
274     }
275 
276     /***************************************
277      * Collect all instance fields, then determine instance size.
278      * Returns:
279      *      false if failed to determine the size.
280      */
281     final bool determineSize(Loc loc)
282     {
283         //printf("AggregateDeclaration::determineSize() %s, sizeok = %d\n", toChars(), sizeok);
284 
285         // The previous instance size finalizing had:
286         if (type.ty == Terror)
287             return false;   // failed already
288         if (sizeok == SIZEOKdone)
289             return true;    // succeeded
290 
291         if (!members)
292         {
293             error(loc, "unknown size");
294             return false;
295         }
296 
297         if (_scope)
298             semantic(null);
299 
300         // Determine the instance size of base class first.
301         if (auto cd = isClassDeclaration())
302         {
303             cd = cd.baseClass;
304             if (cd && !cd.determineSize(loc))
305                 goto Lfail;
306         }
307 
308         // Determine instance fields when sizeok == SIZEOKnone
309         if (!determineFields())
310             goto Lfail;
311         if (sizeok != SIZEOKdone)
312             finalizeSize();
313 
314         // this aggregate type has:
315         if (type.ty == Terror)
316             return false;   // marked as invalid during the finalizing.
317         if (sizeok == SIZEOKdone)
318             return true;    // succeeded to calculate instance size.
319 
320     Lfail:
321         // There's unresolvable forward reference.
322         if (type != Type.terror)
323             error(loc, "no size because of forward reference");
324         type = Type.terror;
325         errors = true;
326         return false;
327     }
328 
329     abstract void finalizeSize();
330 
331     override final d_uns64 size(Loc loc)
332     {
333         //printf("+AggregateDeclaration::size() %s, scope = %p, sizeok = %d\n", toChars(), _scope, sizeok);
334         bool ok = determineSize(loc);
335         //printf("-AggregateDeclaration::size() %s, scope = %p, sizeok = %d\n", toChars(), _scope, sizeok);
336         return ok ? structsize : SIZE_INVALID;
337     }
338 
339     /***************************************
340      * Calculate field[i].overlapped and overlapUnsafe, and check that all of explicit
341      * field initializers have unique memory space on instance.
342      * Returns:
343      *      true if any errors happen.
344      */
345     final bool checkOverlappedFields()
346     {
347         //printf("AggregateDeclaration::checkOverlappedFields() %s\n", toChars());
348         assert(sizeok == SIZEOKdone);
349         size_t nfields = fields.dim;
350         if (isNested())
351         {
352             auto cd = isClassDeclaration();
353             if (!cd || !cd.baseClass || !cd.baseClass.isNested())
354                 nfields--;
355         }
356         bool errors = false;
357 
358         // Fill in missing any elements with default initializers
359         foreach (i; 0 .. nfields)
360         {
361             auto vd = fields[i];
362             if (vd.errors)
363                 continue;
364 
365             auto vx = vd;
366             if (vd._init && vd._init.isVoidInitializer())
367                 vx = null;
368 
369             // Find overlapped fields with the hole [vd->offset .. vd->offset->size()].
370             foreach (j; 0 .. nfields)
371             {
372                 if (i == j)
373                     continue;
374                 auto v2 = fields[j];
375                 if (!vd.isOverlappedWith(v2))
376                     continue;
377 
378                 // vd and v2 are overlapping.
379                 vd.overlapped = true;
380                 v2.overlapped = true;
381 
382                 if (!MODimplicitConv(vd.type.mod, v2.type.mod))
383                     v2.overlapUnsafe = true;
384                 if (!MODimplicitConv(v2.type.mod, vd.type.mod))
385                     vd.overlapUnsafe = true;
386 
387                 if (!vx)
388                     continue;
389                 if (v2._init && v2._init.isVoidInitializer())
390                     continue;
391 
392                 if (vx._init && v2._init)
393                 {
394                     .error(loc, "overlapping default initialization for field %s and %s", v2.toChars(), vd.toChars());
395                     errors = true;
396                 }
397             }
398         }
399         return errors;
400     }
401 
402     /***************************************
403      * Fill out remainder of elements[] with default initializers for fields[].
404      * Params:
405      *      loc         = location
406      *      elements    = explicit arguments which given to construct object.
407      *      ctorinit    = true if the elements will be used for default initialization.
408      * Returns:
409      *      false if any errors occur.
410      *      Otherwise, returns true and the missing arguments will be pushed in elements[].
411      */
412     final bool fill(Loc loc, Expressions* elements, bool ctorinit)
413     {
414         //printf("AggregateDeclaration::fill() %s\n", toChars());
415         assert(sizeok == SIZEOKdone);
416         assert(elements);
417         size_t nfields = fields.dim - isNested();
418         bool errors = false;
419 
420         size_t dim = elements.dim;
421         elements.setDim(nfields);
422         foreach (size_t i; dim .. nfields)
423             (*elements)[i] = null;
424 
425         // Fill in missing any elements with default initializers
426         foreach (i; 0 .. nfields)
427         {
428             if ((*elements)[i])
429                 continue;
430 
431             auto vd = fields[i];
432             auto vx = vd;
433             if (vd._init && vd._init.isVoidInitializer())
434                 vx = null;
435 
436             // Find overlapped fields with the hole [vd->offset .. vd->offset->size()].
437             size_t fieldi = i;
438             foreach (j; 0 .. nfields)
439             {
440                 if (i == j)
441                     continue;
442                 auto v2 = fields[j];
443                 if (!vd.isOverlappedWith(v2))
444                     continue;
445 
446                 if ((*elements)[j])
447                 {
448                     vx = null;
449                     break;
450                 }
451                 if (v2._init && v2._init.isVoidInitializer())
452                     continue;
453 
454                 version (all)
455                 {
456                     /* Prefer first found non-void-initialized field
457                      * union U { int a; int b = 2; }
458                      * U u;    // Error: overlapping initialization for field a and b
459                      */
460                     if (!vx)
461                     {
462                         vx = v2;
463                         fieldi = j;
464                     }
465                     else if (v2._init)
466                     {
467                         .error(loc, "overlapping initialization for field %s and %s", v2.toChars(), vd.toChars());
468                         errors = true;
469                     }
470                 }
471                 else
472                 {
473                     // Will fix Bugzilla 1432 by enabling this path always
474 
475                     /* Prefer explicitly initialized field
476                      * union U { int a; int b = 2; }
477                      * U u;    // OK (u.b == 2)
478                      */
479                     if (!vx || !vx._init && v2._init)
480                     {
481                         vx = v2;
482                         fieldi = j;
483                     }
484                     else if (vx != vd && !vx.isOverlappedWith(v2))
485                     {
486                         // Both vx and v2 fills vd, but vx and v2 does not overlap
487                     }
488                     else if (vx._init && v2._init)
489                     {
490                         .error(loc, "overlapping default initialization for field %s and %s",
491                             v2.toChars(), vd.toChars());
492                         errors = true;
493                     }
494                     else
495                         assert(vx._init || !vx._init && !v2._init);
496                 }
497             }
498             if (vx)
499             {
500                 Expression e;
501                 if (vx.type.size() == 0)
502                 {
503                     e = null;
504                 }
505                 else if (vx._init)
506                 {
507                     assert(!vx._init.isVoidInitializer());
508                     e = vx.getConstInitializer(false);
509                 }
510                 else
511                 {
512                     if ((vx.storage_class & STCnodefaultctor) && !ctorinit)
513                     {
514                         .error(loc, "field %s.%s must be initialized because it has no default constructor",
515                             type.toChars(), vx.toChars());
516                         errors = true;
517                     }
518                     /* Bugzilla 12509: Get the element of static array type.
519                      */
520                     Type telem = vx.type;
521                     if (telem.ty == Tsarray)
522                     {
523                         /* We cannot use Type::baseElemOf() here.
524                          * If the bottom of the Tsarray is an enum type, baseElemOf()
525                          * will return the base of the enum, and its default initializer
526                          * would be different from the enum's.
527                          */
528                         while (telem.toBasetype().ty == Tsarray)
529                             telem = (cast(TypeSArray)telem.toBasetype()).next;
530                         if (telem.ty == Tvoid)
531                             telem = Type.tuns8.addMod(telem.mod);
532                     }
533                     if (telem.needsNested() && ctorinit)
534                         e = telem.defaultInit(loc);
535                     else
536                         e = telem.defaultInitLiteral(loc);
537                 }
538                 (*elements)[fieldi] = e;
539             }
540         }
541         foreach (e; *elements)
542         {
543             if (e && e.op == TOKerror)
544                 return false;
545         }
546 
547         return !errors;
548     }
549 
550     /****************************
551      * Do byte or word alignment as necessary.
552      * Align sizes of 0, as we may not know array sizes yet.
553      *
554      * alignment: struct alignment that is in effect
555      * size: alignment requirement of field
556      */
557     static void alignmember(structalign_t alignment, uint size, uint* poffset)
558     {
559         //printf("alignment = %d, size = %d, offset = %d\n",alignment,size,offset);
560         switch (alignment)
561         {
562         case cast(structalign_t)1:
563             // No alignment
564             break;
565 
566         case cast(structalign_t)STRUCTALIGN_DEFAULT:
567             // Alignment in Target::fieldalignsize must match what the
568             // corresponding C compiler's default alignment behavior is.
569             assert(size > 0 && !(size & (size - 1)));
570             *poffset = (*poffset + size - 1) & ~(size - 1);
571             break;
572 
573         default:
574             // Align on alignment boundary, which must be a positive power of 2
575             assert(alignment > 0 && !(alignment & (alignment - 1)));
576             *poffset = (*poffset + alignment - 1) & ~(alignment - 1);
577             break;
578         }
579     }
580 
581     /****************************************
582      * Place a member (mem) into an aggregate (agg), which can be a struct, union or class
583      * Returns:
584      *      offset to place field at
585      *
586      * nextoffset:    next location in aggregate
587      * memsize:       size of member
588      * memalignsize:  size of member for alignment purposes
589      * alignment:     alignment in effect for this member
590      * paggsize:      size of aggregate (updated)
591      * paggalignsize: size of aggregate for alignment purposes (updated)
592      * isunion:       the aggregate is a union
593      */
594     static uint placeField(uint* nextoffset, uint memsize, uint memalignsize,
595         structalign_t alignment, uint* paggsize, uint* paggalignsize, bool isunion)
596     {
597         uint ofs = *nextoffset;
598         alignmember(alignment, memalignsize, &ofs);
599         uint memoffset = ofs;
600         ofs += memsize;
601         if (ofs > *paggsize)
602             *paggsize = ofs;
603         if (!isunion)
604             *nextoffset = ofs;
605 
606         if (alignment == STRUCTALIGN_DEFAULT)
607         {
608             if (global.params.is64bit && memalignsize == 16)
609             {
610             }
611             else if (8 < memalignsize)
612                 memalignsize = 8;
613         }
614         else
615         {
616             if (memalignsize < alignment)
617                 memalignsize = alignment;
618         }
619 
620         if (*paggalignsize < memalignsize)
621             *paggalignsize = memalignsize;
622 
623         return memoffset;
624     }
625 
626     override final Type getType()
627     {
628         return type;
629     }
630 
631     // is aggregate deprecated?
632     override final bool isDeprecated()
633     {
634         return isdeprecated;
635     }
636 
637     /****************************************
638      * Returns true if there's an extra member which is the 'this'
639      * pointer to the enclosing context (enclosing aggregate or function)
640      */
641     final bool isNested()
642     {
643         return enclosing !is null;
644     }
645 
646     /* Append vthis field (this.tupleof[$-1]) to make this aggregate type nested.
647      */
648     final void makeNested()
649     {
650         if (enclosing) // if already nested
651             return;
652         if (sizeok == SIZEOKdone)
653             return;
654         if (isUnionDeclaration() || isInterfaceDeclaration())
655             return;
656         if (storage_class & STCstatic)
657             return;
658 
659         // If nested struct, add in hidden 'this' pointer to outer scope
660         auto s = toParent2();
661         if (!s)
662             return;
663         Type t = null;
664         if (auto fd = s.isFuncDeclaration())
665         {
666             enclosing = fd;
667 
668             /* Bugzilla 14422: If a nested class parent is a function, its
669              * context pointer (== `outer`) should be void* always.
670              */
671             t = Type.tvoidptr;
672         }
673         else if (auto ad = s.isAggregateDeclaration())
674         {
675             if (isClassDeclaration() && ad.isClassDeclaration())
676             {
677                 enclosing = ad;
678             }
679             else if (isStructDeclaration())
680             {
681                 if (auto ti = ad.parent.isTemplateInstance())
682                 {
683                     enclosing = ti.enclosing;
684                 }
685             }
686             t = ad.handleType();
687         }
688         if (enclosing)
689         {
690             //printf("makeNested %s, enclosing = %s\n", toChars(), enclosing.toChars());
691             assert(t);
692             if (t.ty == Tstruct)
693                 t = Type.tvoidptr; // t should not be a ref type
694 
695             assert(!vthis);
696             vthis = new ThisDeclaration(loc, t);
697             //vthis->storage_class |= STCref;
698 
699             // Emulate vthis.addMember()
700             members.push(vthis);
701 
702             // Emulate vthis.semantic()
703             vthis.storage_class |= STCfield;
704             vthis.parent = this;
705             vthis.protection = Prot(PROTpublic);
706             vthis.alignment = t.alignment();
707             vthis.semanticRun = PASSsemanticdone;
708 
709             if (sizeok == SIZEOKfwd)
710                 fields.push(vthis);
711         }
712     }
713 
714     override final bool isExport()
715     {
716         return protection.kind == PROTexport;
717     }
718 
719     /*******************************************
720      * Look for constructor declaration.
721      */
722     final Dsymbol searchCtor()
723     {
724         auto s = search(Loc(), Id.ctor);
725         if (s)
726         {
727             if (!(s.isCtorDeclaration() ||
728                   s.isTemplateDeclaration() ||
729                   s.isOverloadSet()))
730             {
731                 s.error("is not a constructor; identifiers starting with __ are reserved for the implementation");
732                 errors = true;
733                 s = null;
734             }
735         }
736         if (s && s.toParent() != this)
737             s = null; // search() looks through ancestor classes
738         if (s)
739         {
740             // Finish all constructors semantics to determine this->noDefaultCtor.
741             struct SearchCtor
742             {
743                 extern (C++) static int fp(Dsymbol s, void* ctxt)
744                 {
745                     auto f = s.isCtorDeclaration();
746                     if (f && f.semanticRun == PASSinit)
747                         f.semantic(null);
748                     return 0;
749                 }
750             }
751 
752             for (size_t i = 0; i < members.dim; i++)
753             {
754                 auto sm = (*members)[i];
755                 sm.apply(&SearchCtor.fp, null);
756             }
757         }
758         return s;
759     }
760 
761     override final Prot prot()
762     {
763         return protection;
764     }
765 
766     // 'this' type
767     final Type handleType()
768     {
769         return type;
770     }
771 
772     // Back end
773     Symbol* stag; // tag symbol for debug data
774     Symbol* sinit;
775 
776     override final inout(AggregateDeclaration) isAggregateDeclaration() inout
777     {
778         return this;
779     }
780 
781     override void accept(Visitor v)
782     {
783         v.visit(this);
784     }
785 }