d: Merge upstream dmd ff57fec515, druntime ff57fec515, phobos 17bafda79.
[official-gcc.git] / gcc / d / dmd / aggregate.d
blob307bb0171c47d157f89659b892a6289e96465565
1 /**
2 * Defines a `Dsymbol` representing an aggregate, which is a `struct`, `union` or `class`.
4 * Specification: $(LINK2 https://dlang.org/spec/struct.html, Structs, Unions),
5 * $(LINK2 https://dlang.org/spec/class.html, Class).
7 * Copyright: Copyright (C) 1999-2023 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
15 module dmd.aggregate;
17 import core.stdc.stdio;
18 import core.checkedint;
20 import dmd.aliasthis;
21 import dmd.arraytypes;
22 import dmd.astenums;
23 import dmd.attrib;
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.hdrgen;
35 import dmd.id;
36 import dmd.identifier;
37 import dmd.location;
38 import dmd.mtype;
39 import dmd.tokens;
40 import dmd.typesem : defaultInit;
41 import dmd.visitor;
43 /**
44 * The ClassKind enum is used in AggregateDeclaration AST nodes to
45 * specify the linkage type of the struct/class/interface or if it
46 * is an anonymous class. If the class is anonymous it is also
47 * considered to be a D class.
49 enum ClassKind : ubyte
51 /// the aggregate is a d(efault) class
53 /// the aggregate is a C++ struct/class/interface
54 cpp,
55 /// the aggregate is an Objective-C class/interface
56 objc,
57 /// the aggregate is a C struct
61 /**
62 * Give a nice string for a class kind for error messages
63 * Params:
64 * c = class kind
65 * Returns:
66 * 0-terminated string for `c`
68 const(char)* toChars(ClassKind c) @safe
70 final switch (c)
72 case ClassKind.d:
73 return "D";
74 case ClassKind.cpp:
75 return "C++";
76 case ClassKind.objc:
77 return "Objective-C";
78 case ClassKind.c:
79 return "C";
83 /**
84 * If an aggregate has a pargma(mangle, ...) this holds the information
85 * to mangle.
87 struct MangleOverride
89 Dsymbol agg; // The symbol to copy template parameters from (if any)
90 Identifier id; // the name to override the aggregate's with, defaults to agg.ident
93 /***********************************************************
94 * Abstract aggregate as a common ancestor for Class- and StructDeclaration.
96 extern (C++) abstract class AggregateDeclaration : ScopeDsymbol
98 Type type; ///
99 StorageClass storage_class; ///
100 uint structsize; /// size of struct
101 uint alignsize; /// size of struct for alignment purposes
102 VarDeclarations fields; /// VarDeclaration fields
103 Dsymbol deferred; /// any deferred semantic2() or semantic3() symbol
105 /// specifies whether this is a D, C++, Objective-C or anonymous struct/class/interface
106 ClassKind classKind;
107 /// Specify whether to mangle the aggregate as a `class` or a `struct`
108 /// This information is used by the MSVC mangler
109 /// Only valid for class and struct. TODO: Merge with ClassKind ?
110 CPPMANGLE cppmangle;
112 /// overridden symbol with pragma(mangle, "...") if not null
113 MangleOverride* pMangleOverride;
116 * !=null if is nested
117 * pointing to the dsymbol that directly enclosing it.
118 * 1. The function that enclosing it (nested struct and class)
119 * 2. The class that enclosing it (nested class only)
120 * 3. If enclosing aggregate is template, its enclosing dsymbol.
122 * See AggregateDeclaraton::makeNested for the details.
124 Dsymbol enclosing;
126 VarDeclaration vthis; /// 'this' parameter if this aggregate is nested
127 VarDeclaration vthis2; /// 'this' parameter if this aggregate is a template and is nested
129 // Special member functions
130 FuncDeclarations invs; /// Array of invariants
131 FuncDeclaration inv; /// Merged invariant calling all members of invs
133 /// CtorDeclaration or TemplateDeclaration
134 Dsymbol ctor;
136 /// default constructor - should have no arguments, because
137 /// it would be stored in TypeInfo_Class.defaultConstructor
138 CtorDeclaration defaultCtor;
140 AliasThis aliasthis; /// forward unresolved lookups to aliasthis
142 DtorDeclarations userDtors; /// user-defined destructors (`~this()`) - mixins can yield multiple ones
143 DtorDeclaration aggrDtor; /// aggregate destructor calling userDtors and fieldDtor (and base class aggregate dtor for C++ classes)
144 DtorDeclaration dtor; /// the aggregate destructor exposed as `__xdtor` alias
145 /// (same as aggrDtor, except for C++ classes with virtual dtor on Windows)
146 DtorDeclaration tidtor; /// aggregate destructor used in TypeInfo (must have extern(D) ABI)
147 DtorDeclaration fieldDtor; /// function destructing (non-inherited) fields
149 Expression getRTInfo; /// pointer to GC info generated by object.RTInfo(this)
152 Visibility visibility;
153 bool noDefaultCtor; /// no default construction
154 bool disableNew; /// disallow allocations using `new`
155 Sizeok sizeok = Sizeok.none; /// set when structsize contains valid data
157 final extern (D) this(const ref Loc loc, Identifier id)
159 super(loc, id);
160 visibility = Visibility(Visibility.Kind.public_);
163 /***************************************
164 * Create a new scope from sc.
165 * semantic, semantic2 and semantic3 will use this for aggregate members.
167 Scope* newScope(Scope* sc)
169 auto sc2 = sc.push(this);
170 sc2.stc &= STC.flowThruAggregate;
171 sc2.parent = this;
172 sc2.inunion = isUnionDeclaration();
173 sc2.visibility = Visibility(Visibility.Kind.public_);
174 sc2.explicitVisibility = 0;
175 sc2.aligndecl = null;
176 sc2.userAttribDecl = null;
177 sc2.namespace = null;
178 return sc2;
181 override final void setScope(Scope* sc)
183 // Might need a scope to resolve forward references. The check for
184 // semanticRun prevents unnecessary setting of _scope during deferred
185 // setScope phases for aggregates which already finished semantic().
186 // See https://issues.dlang.org/show_bug.cgi?id=16607
187 if (semanticRun < PASS.semanticdone)
188 ScopeDsymbol.setScope(sc);
191 /***************************************
192 * Returns:
193 * The total number of fields minus the number of hidden fields.
195 extern (D) final size_t nonHiddenFields()
197 return fields.length - isNested() - (vthis2 !is null);
200 /***************************************
201 * Collect all instance fields, then determine instance size.
202 * Returns:
203 * false if failed to determine the size.
205 extern (D) final bool determineSize(const ref Loc loc)
207 //printf("AggregateDeclaration::determineSize() %s, sizeok = %d\n", toChars(), sizeok);
209 // The previous instance size finalizing had:
210 if (type.ty == Terror || errors)
211 return false; // failed already
212 if (sizeok == Sizeok.done)
213 return true; // succeeded
215 if (!members)
217 .error(loc, "%s `%s` unknown size", kind, toPrettyChars);
218 return false;
221 if (_scope)
222 dsymbolSemantic(this, null);
224 // Determine the instance size of base class first.
225 if (auto cd = isClassDeclaration())
227 cd = cd.baseClass;
228 if (cd && !cd.determineSize(loc))
229 goto Lfail;
232 // Determine instance fields when sizeok == Sizeok.none
233 if (!this.determineFields())
234 goto Lfail;
235 if (sizeok != Sizeok.done)
236 finalizeSize();
238 // this aggregate type has:
239 if (type.ty == Terror)
240 return false; // marked as invalid during the finalizing.
241 if (sizeok == Sizeok.done)
242 return true; // succeeded to calculate instance size.
244 Lfail:
245 // There's unresolvable forward reference.
246 if (type != Type.terror)
247 error(loc, "%s `%s` no size because of forward reference", kind, toPrettyChars);
248 // Don't cache errors from speculative semantic, might be resolvable later.
249 // https://issues.dlang.org/show_bug.cgi?id=16574
250 if (!global.gag)
252 type = Type.terror;
253 errors = true;
255 return false;
258 abstract void finalizeSize();
260 override final uinteger_t size(const ref Loc loc)
262 //printf("+AggregateDeclaration::size() %s, scope = %p, sizeok = %d\n", toChars(), _scope, sizeok);
263 bool ok = determineSize(loc);
264 //printf("-AggregateDeclaration::size() %s, scope = %p, sizeok = %d\n", toChars(), _scope, sizeok);
265 return ok ? structsize : SIZE_INVALID;
268 /***************************************
269 * Calculate field[i].overlapped and overlapUnsafe, and check that all of explicit
270 * field initializers have unique memory space on instance.
271 * Returns:
272 * true if any errors happen.
274 extern (D) final bool checkOverlappedFields()
276 //printf("AggregateDeclaration::checkOverlappedFields() %s\n", toChars());
277 assert(sizeok == Sizeok.done);
278 size_t nfields = fields.length;
279 if (isNested())
281 auto cd = isClassDeclaration();
282 if (!cd || !cd.baseClass || !cd.baseClass.isNested())
283 nfields--;
284 if (vthis2 && !(cd && cd.baseClass && cd.baseClass.vthis2))
285 nfields--;
287 bool errors = false;
289 // Fill in missing any elements with default initializers
290 foreach (i; 0 .. nfields)
292 auto vd = fields[i];
293 if (vd.errors)
295 errors = true;
296 continue;
299 const vdIsVoidInit = vd._init && vd._init.isVoidInitializer();
301 // Find overlapped fields with the hole [vd.offset .. vd.offset.size()].
302 foreach (j; 0 .. nfields)
304 if (i == j)
305 continue;
306 auto v2 = fields[j];
307 if (v2.errors)
309 errors = true;
310 continue;
312 if (!vd.isOverlappedWith(v2))
313 continue;
315 // vd and v2 are overlapping.
316 vd.overlapped = true;
317 v2.overlapped = true;
319 if (!MODimplicitConv(vd.type.mod, v2.type.mod))
320 v2.overlapUnsafe = true;
321 if (!MODimplicitConv(v2.type.mod, vd.type.mod))
322 vd.overlapUnsafe = true;
324 if (i > j)
325 continue;
327 if (!v2._init)
328 continue;
330 if (v2._init.isVoidInitializer())
331 continue;
333 if (vd._init && !vdIsVoidInit && v2._init)
335 .error(loc, "overlapping default initialization for field `%s` and `%s`", v2.toChars(), vd.toChars());
336 errors = true;
338 else if (v2._init && i < j)
340 .error(v2.loc, "union field `%s` with default initialization `%s` must be before field `%s`",
341 v2.toChars(), dmd.hdrgen.toChars(v2._init), vd.toChars());
342 errors = true;
346 return errors;
349 /***************************************
350 * Fill out remainder of elements[] with default initializers for fields[].
351 * Params:
352 * loc = location
353 * elements = explicit arguments which given to construct object.
354 * ctorinit = true if the elements will be used for default initialization.
355 * Returns:
356 * false if any errors occur.
357 * Otherwise, returns true and the missing arguments will be pushed in elements[].
359 final bool fill(const ref Loc loc, ref Expressions elements, bool ctorinit)
361 //printf("AggregateDeclaration::fill() %s\n", toChars());
362 assert(sizeok == Sizeok.done);
363 const nfields = nonHiddenFields();
364 bool errors = false;
366 size_t dim = elements.length;
367 elements.setDim(nfields);
368 foreach (size_t i; dim .. nfields)
369 elements[i] = null;
371 // Fill in missing any elements with default initializers
372 foreach (i; 0 .. nfields)
374 if (elements[i])
375 continue;
377 auto vd = fields[i];
378 auto vx = vd;
379 if (vd._init && vd._init.isVoidInitializer())
380 vx = null;
382 // Find overlapped fields with the hole [vd.offset .. vd.offset.size()].
383 size_t fieldi = i;
384 foreach (j; 0 .. nfields)
386 if (i == j)
387 continue;
388 auto v2 = fields[j];
389 if (!vd.isOverlappedWith(v2))
390 continue;
392 if (elements[j])
394 vx = null;
395 break;
397 if (v2._init && v2._init.isVoidInitializer())
398 continue;
400 version (all)
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
406 if (!vx)
408 vx = v2;
409 fieldi = j;
411 else if (v2._init)
413 .error(loc, "overlapping initialization for field `%s` and `%s`", v2.toChars(), vd.toChars());
414 errors = true;
417 else
419 // fixes https://issues.dlang.org/show_bug.cgi?id=1432 by enabling this path always
421 /* Prefer explicitly initialized field
422 * union U { int a; int b = 2; }
423 * U u; // OK (u.b == 2)
425 if (!vx || !vx._init && v2._init)
427 vx = v2;
428 fieldi = j;
430 else if (vx != vd && !vx.isOverlappedWith(v2))
432 // Both vx and v2 fills vd, but vx and v2 does not overlap
434 else if (vx._init && v2._init)
436 .error(loc, "overlapping default initialization for field `%s` and `%s`",
437 v2.toChars(), vd.toChars());
438 errors = true;
440 else
441 assert(vx._init || !vx._init && !v2._init);
444 if (vx)
446 Expression e;
447 if (vx.type.size() == 0)
449 e = null;
451 else if (vx._init)
453 assert(!vx._init.isVoidInitializer());
454 if (vx.inuse) // https://issues.dlang.org/show_bug.cgi?id=18057
456 .error(loc, "%s `%s` recursive initialization of field", vx.kind(), vx.toPrettyChars());
457 errors = true;
459 else
460 e = vx.getConstInitializer(false);
462 else
464 if ((vx.storage_class & STC.nodefaultctor) && !ctorinit)
466 .error(loc, "field `%s.%s` must be initialized because it has no default constructor",
467 type.toChars(), vx.toChars());
468 errors = true;
470 /* https://issues.dlang.org/show_bug.cgi?id=12509
471 * Get the element of static array type.
473 Type telem = vx.type;
474 if (telem.ty == Tsarray)
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.
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);
487 if (telem.needsNested() && ctorinit)
488 e = telem.defaultInit(loc);
489 else
490 e = telem.defaultInitLiteral(loc);
492 elements[fieldi] = e;
495 foreach (e; elements)
497 if (e && e.op == EXP.error)
498 return false;
501 return !errors;
504 override final Type getType()
506 /* Apply storage classes to forward references. (Issue 22254)
507 * Note: Avoid interfaces for now. Implementing qualifiers on interface
508 * definitions exposed some issues in their TypeInfo generation in DMD.
509 * Related PR: https://github.com/dlang/dmd/pull/13312
511 if (semanticRun == PASS.initial && !isInterfaceDeclaration())
513 auto stc = storage_class;
514 if (_scope)
515 stc |= _scope.stc;
516 type = type.addSTC(stc);
518 return type;
521 // is aggregate deprecated?
522 override final bool isDeprecated() const
524 return !!(this.storage_class & STC.deprecated_);
527 /// Flag this aggregate as deprecated
528 extern (D) final void setDeprecated()
530 this.storage_class |= STC.deprecated_;
533 /****************************************
534 * Returns true if there's an extra member which is the 'this'
535 * pointer to the enclosing context (enclosing aggregate or function)
537 final bool isNested() const
539 return enclosing !is null;
542 /* Append vthis field (this.tupleof[$-1]) to make this aggregate type nested.
544 extern (D) final void makeNested()
546 if (enclosing) // if already nested
547 return;
548 if (sizeok == Sizeok.done)
549 return;
550 if (isUnionDeclaration() || isInterfaceDeclaration())
551 return;
552 if (storage_class & STC.static_)
553 return;
555 // If nested struct, add in hidden 'this' pointer to outer scope
556 auto s = toParentLocal();
557 if (!s)
558 s = toParent2();
559 if (!s)
560 return;
561 Type t = null;
562 if (auto fd = s.isFuncDeclaration())
564 enclosing = fd;
566 /* https://issues.dlang.org/show_bug.cgi?id=14422
567 * If a nested class parent is a function, its
568 * context pointer (== `outer`) should be void* always.
570 t = Type.tvoidptr;
572 else if (auto ad = s.isAggregateDeclaration())
574 if (isClassDeclaration() && ad.isClassDeclaration())
576 enclosing = ad;
578 else if (isStructDeclaration())
580 if (auto ti = ad.parent.isTemplateInstance())
582 enclosing = ti.enclosing;
585 t = ad.handleType();
587 if (enclosing)
589 //printf("makeNested %s, enclosing = %s\n", toChars(), enclosing.toChars());
590 assert(t);
591 if (t.ty == Tstruct)
592 t = Type.tvoidptr; // t should not be a ref type
594 assert(!vthis);
595 vthis = new ThisDeclaration(loc, t);
596 //vthis.storage_class |= STC.ref_;
598 // Emulate vthis.addMember()
599 members.push(vthis);
601 // Emulate vthis.dsymbolSemantic()
602 vthis.storage_class |= STC.field;
603 vthis.parent = this;
604 vthis.visibility = Visibility(Visibility.Kind.public_);
605 vthis.alignment = t.alignment();
606 vthis.semanticRun = PASS.semanticdone;
608 if (sizeok == Sizeok.fwd)
609 fields.push(vthis);
611 makeNested2();
615 /* Append vthis2 field (this.tupleof[$-1]) to add a second context pointer.
617 extern (D) final void makeNested2()
619 if (vthis2)
620 return;
621 if (!vthis)
622 makeNested(); // can't add second before first
623 if (!vthis)
624 return;
625 if (sizeok == Sizeok.done)
626 return;
627 if (isUnionDeclaration() || isInterfaceDeclaration())
628 return;
629 if (storage_class & STC.static_)
630 return;
632 auto s0 = toParentLocal();
633 auto s = toParent2();
634 if (!s || !s0 || s == s0)
635 return;
636 auto cd = s.isClassDeclaration();
637 Type t = cd ? cd.type : Type.tvoidptr;
639 vthis2 = new ThisDeclaration(loc, t);
640 //vthis2.storage_class |= STC.ref_;
642 // Emulate vthis2.addMember()
643 members.push(vthis2);
645 // Emulate vthis2.dsymbolSemantic()
646 vthis2.storage_class |= STC.field;
647 vthis2.parent = this;
648 vthis2.visibility = Visibility(Visibility.Kind.public_);
649 vthis2.alignment = t.alignment();
650 vthis2.semanticRun = PASS.semanticdone;
652 if (sizeok == Sizeok.fwd)
653 fields.push(vthis2);
656 override final bool isExport() const
658 return visibility.kind == Visibility.Kind.export_;
661 /*******************************************
662 * Look for constructor declaration.
664 extern (D) final Dsymbol searchCtor()
666 auto s = this.search(Loc.initial, Id.ctor);
667 if (s)
669 if (!(s.isCtorDeclaration() ||
670 s.isTemplateDeclaration() ||
671 s.isOverloadSet()))
673 .error(s.loc, "%s `%s` is not a constructor; identifiers starting with `__` are reserved for the implementation", s.kind(), s.toPrettyChars());
674 errors = true;
675 s = null;
678 if (s && s.toParent() != this)
679 s = null; // search() looks through ancestor classes
680 if (s)
682 // Finish all constructors semantics to determine this.noDefaultCtor.
683 static int searchCtor(Dsymbol s, void*)
685 auto f = s.isCtorDeclaration();
686 if (f && f.semanticRun == PASS.initial)
687 f.dsymbolSemantic(null);
688 return 0;
691 for (size_t i = 0; i < members.length; i++)
693 auto sm = (*members)[i];
694 sm.apply(&searchCtor, null);
697 return s;
700 override final Visibility visible() pure nothrow @nogc @safe
702 return visibility;
705 // 'this' type
706 final Type handleType()
708 return type;
711 // Does this class have an invariant function?
712 final bool hasInvariant()
714 return invs.length != 0;
717 // Back end
718 void* sinit; /// initializer symbol
720 override final inout(AggregateDeclaration) isAggregateDeclaration() inout
722 return this;
725 override void accept(Visitor v)
727 v.visit(this);
731 /*********************************
732 * Iterate this dsymbol or members of this scoped dsymbol, then
733 * call `fp` with the found symbol and `params`.
734 * Params:
735 * symbol = the dsymbol or parent of members to call fp on
736 * fp = function pointer to process the iterated symbol.
737 * If it returns nonzero, the iteration will be aborted.
738 * ctx = context parameter passed to fp.
739 * Returns:
740 * nonzero if the iteration is aborted by the return value of fp,
741 * or 0 if it's completed.
743 int apply(Dsymbol symbol, int function(Dsymbol, void*) fp, void* ctx)
745 if (auto nd = symbol.isNspace())
747 return nd.members.foreachDsymbol( (s) { return s && s.apply(fp, ctx); } );
749 if (auto ad = symbol.isAttribDeclaration())
751 return ad.include(ad._scope).foreachDsymbol( (s) { return s && s.apply(fp, ctx); } );
753 if (auto tm = symbol.isTemplateMixin())
755 if (tm._scope) // if fwd reference
756 dsymbolSemantic(tm, null); // try to resolve it
758 return tm.members.foreachDsymbol( (s) { return s && s.apply(fp, ctx); } );
761 return fp(symbol, ctx);
764 /****************************
765 * Do byte or word alignment as necessary.
766 * Align sizes of 0, as we may not know array sizes yet.
767 * Params:
768 * alignment = struct alignment that is in effect
769 * memalignsize = natural alignment of field
770 * offset = offset to be aligned
771 * Returns:
772 * aligned offset
774 public uint alignmember(structalign_t alignment, uint memalignsize, uint offset) pure nothrow @safe
776 //debug printf("alignment = %u %d, size = %u, offset = %u\n", alignment.get(), alignment.isPack(), memalignsize, offset);
777 uint alignvalue;
779 if (alignment.isDefault())
781 // Alignment in Target::fieldalignsize must match what the
782 // corresponding C compiler's default alignment behavior is.
783 alignvalue = memalignsize;
785 else if (alignment.isPack()) // #pragma pack semantics
787 alignvalue = alignment.get();
788 if (memalignsize < alignvalue)
789 alignvalue = memalignsize; // align to min(memalignsize, alignment)
791 else if (alignment.get() > 1)
793 // Align on alignment boundary, which must be a positive power of 2
794 alignvalue = alignment.get();
796 else
797 return offset;
799 assert(alignvalue && !(alignvalue & (alignvalue - 1))); // non-zero and power of 2
800 return (offset + alignvalue - 1) & ~(alignvalue - 1);
803 /****************************************
804 * Place a field (mem) into an aggregate (agg), which can be a struct, union or class
805 * Params:
806 * nextoffset = location just past the end of the previous field in the aggregate.
807 * Updated to be just past the end of this field to be placed, i.e. the future nextoffset
808 * memsize = size of field
809 * memalignsize = natural alignment of field
810 * alignment = alignment in effect for this field
811 * aggsize = size of aggregate (updated)
812 * aggalignsize = alignment of aggregate (updated)
813 * isunion = the aggregate is a union
814 * Returns:
815 * aligned offset to place field at
818 public uint placeField(ref uint nextoffset, uint memsize, uint memalignsize,
819 structalign_t alignment, ref uint aggsize, ref uint aggalignsize, bool isunion) @safe pure nothrow
821 static if (0)
823 printf("placeField() nextoffset: %u\n", nextoffset);
824 printf(": memsize: %u\n", memsize);
825 printf(": memalignsize: %u\n", memalignsize);
826 printf(": alignment: %u\n", alignment.get());
827 printf(": aggsize: %u\n", aggsize);
828 printf(": aggalignsize: %u\n", aggalignsize);
829 printf(": isunion: %d\n", isunion);
832 uint ofs = nextoffset;
834 const uint actualAlignment =
835 alignment.isDefault() || alignment.isPack() && memalignsize < alignment.get()
836 ? memalignsize : alignment.get();
838 // Ensure no overflow for (memsize + actualAlignment + ofs)
839 bool overflow;
840 const sz = addu(memsize, actualAlignment, overflow);
841 addu(ofs, sz, overflow);
842 if (overflow) assert(0);
844 // Skip no-op for noreturn without custom aligment
845 if (memalignsize != 0 || !alignment.isDefault())
846 ofs = alignmember(alignment, memalignsize, ofs);
848 uint memoffset = ofs;
849 ofs += memsize;
850 if (ofs > aggsize)
851 aggsize = ofs;
852 if (!isunion)
854 nextoffset = ofs;
855 //printf(" revised nextoffset: %u\n", ofs);
858 if (aggalignsize < actualAlignment)
859 aggalignsize = actualAlignment;
861 return memoffset;