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