Skip to content

Commit

Permalink
move determineSize/finalizeSize to dsymbolsem.d
Browse files Browse the repository at this point in the history
  • Loading branch information
thewilsonator committed Oct 6, 2024
1 parent 2024098 commit f66c6c2
Show file tree
Hide file tree
Showing 8 changed files with 377 additions and 379 deletions.
143 changes: 1 addition & 142 deletions compiler/src/dmd/aggregate.d
Original file line number Diff line number Diff line change
Expand Up @@ -187,155 +187,14 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol
return fields.length - isNested() - (vthis2 !is null);
}

/***************************************
* Collect all instance fields, then determine instance size.
* Returns:
* false if failed to determine the size.
*/
extern (D) final bool determineSize(const ref Loc loc)
{
//printf("AggregateDeclaration::determineSize() %s, sizeok = %d\n", toChars(), sizeok);

// The previous instance size finalizing had:
if (type.ty == Terror || errors)
return false; // failed already
if (sizeok == Sizeok.done)
return true; // succeeded

if (!members)
{
.error(loc, "%s `%s` unknown size", kind, toPrettyChars);
return false;
}

if (_scope)
dsymbolSemantic(this, null);

// Determine the instance size of base class first.
if (auto cd = isClassDeclaration())
{
cd = cd.baseClass;
if (cd && !cd.determineSize(loc))
goto Lfail;
}

// Determine instance fields when sizeok == Sizeok.none
if (!this.determineFields())
goto Lfail;
if (sizeok != Sizeok.done)
finalizeSize();

// this aggregate type has:
if (type.ty == Terror)
return false; // marked as invalid during the finalizing.
if (sizeok == Sizeok.done)
return true; // succeeded to calculate instance size.

Lfail:
// There's unresolvable forward reference.
if (type != Type.terror)
error(loc, "%s `%s` no size because of forward reference", kind, toPrettyChars);
// Don't cache errors from speculative semantic, might be resolvable later.
// https://issues.dlang.org/show_bug.cgi?id=16574
if (!global.gag)
{
type = Type.terror;
errors = true;
}
return false;
}

abstract void finalizeSize();

override final uinteger_t size(const ref Loc loc)
{
//printf("+AggregateDeclaration::size() %s, scope = %p, sizeok = %d\n", toChars(), _scope, sizeok);
bool ok = determineSize(loc);
bool ok = determineSize(this, loc);
//printf("-AggregateDeclaration::size() %s, scope = %p, sizeok = %d\n", toChars(), _scope, sizeok);
return ok ? structsize : SIZE_INVALID;
}

/***************************************
* Calculate field[i].overlapped and overlapUnsafe, and check that all of explicit
* field initializers have unique memory space on instance.
* Returns:
* true if any errors happen.
*/
extern (D) final bool checkOverlappedFields()
{
//printf("AggregateDeclaration::checkOverlappedFields() %s\n", toChars());
assert(sizeok == Sizeok.done);
size_t nfields = fields.length;
if (isNested())
{
auto cd = isClassDeclaration();
if (!cd || !cd.baseClass || !cd.baseClass.isNested())
nfields--;
if (vthis2 && !(cd && cd.baseClass && cd.baseClass.vthis2))
nfields--;
}
bool errors = false;

// Fill in missing any elements with default initializers
foreach (i; 0 .. nfields)
{
auto vd = fields[i];
if (vd.errors)
{
errors = true;
continue;
}

const vdIsVoidInit = vd._init && vd._init.isVoidInitializer();

// Find overlapped fields with the hole [vd.offset .. vd.offset.size()].
foreach (j; 0 .. nfields)
{
if (i == j)
continue;
auto v2 = fields[j];
if (v2.errors)
{
errors = true;
continue;
}
if (!vd.isOverlappedWith(v2))
continue;

// vd and v2 are overlapping.
vd.overlapped = true;
v2.overlapped = true;

if (!MODimplicitConv(vd.type.mod, v2.type.mod))
v2.overlapUnsafe = true;
if (!MODimplicitConv(v2.type.mod, vd.type.mod))
vd.overlapUnsafe = true;

if (i > j)
continue;

if (!v2._init)
continue;

if (v2._init.isVoidInitializer())
continue;

if (vd._init && !vdIsVoidInit && v2._init)
{
.error(loc, "overlapping default initialization for field `%s` and `%s`", v2.toChars(), vd.toChars());
errors = true;
}
else if (v2._init && i < j)
{
.error(v2.loc, "union field `%s` with default initialization `%s` must be before field `%s`",
v2.toChars(), dmd.hdrgen.toChars(v2._init), vd.toChars());
errors = true;
}
}
}
return errors;
}

/***************************************
* Fill out remainder of elements[] with default initializers for fields[].
* Params:
Expand Down
3 changes: 0 additions & 3 deletions compiler/src/dmd/aggregate.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,6 @@ class AggregateDeclaration : public ScopeDsymbol
Sizeok sizeok; // set when structsize contains valid data

virtual Scope *newScope(Scope *sc);
virtual void finalizeSize() = 0;
uinteger_t size(const Loc &loc) override final;
bool fill(const Loc &loc, Expressions &elements, bool ctorinit);
Type *getType() override final;
Expand Down Expand Up @@ -171,7 +170,6 @@ class StructDeclaration : public AggregateDeclaration
static StructDeclaration *create(const Loc &loc, Identifier *id, bool inObject);
StructDeclaration *syntaxCopy(Dsymbol *s) override;
const char *kind() const override;
void finalizeSize() override final;
bool isPOD();
bool zeroInit() const; // !=0 if initialize with 0 fill
bool zeroInit(bool v);
Expand Down Expand Up @@ -288,7 +286,6 @@ class ClassDeclaration : public AggregateDeclaration
virtual bool isBaseOf(ClassDeclaration *cd, int *poffset);

bool isBaseInfoComplete();
void finalizeSize() override;
bool hasMonitor();
bool isFuncHidden(FuncDeclaration *fd);
bool isCOMclass() const;
Expand Down
110 changes: 0 additions & 110 deletions compiler/src/dmd/dclass.d
Original file line number Diff line number Diff line change
Expand Up @@ -496,116 +496,6 @@ extern (C++) class ClassDeclaration : AggregateDeclaration
return null;
}

final override void finalizeSize()
{
assert(sizeok != Sizeok.done);

// Set the offsets of the fields and determine the size of the class
if (baseClass)
{
assert(baseClass.sizeok == Sizeok.done);

alignsize = baseClass.alignsize;
if (classKind == ClassKind.cpp)
structsize = target.cpp.derivedClassOffset(baseClass);
else
structsize = baseClass.structsize;
}
else if (classKind == ClassKind.objc)
structsize = 0; // no hidden member for an Objective-C class
else if (isInterfaceDeclaration())
{
if (interfaces.length == 0)
{
alignsize = target.ptrsize;
structsize = target.ptrsize; // allow room for __vptr
}
}
else
{
alignsize = target.ptrsize;
structsize = target.ptrsize; // allow room for __vptr
if (hasMonitor())
structsize += target.ptrsize; // allow room for __monitor
}

//printf("finalizeSize() %s, sizeok = %d\n", toChars(), sizeok);
size_t bi = 0; // index into vtblInterfaces[]

/****
* Runs through the inheritance graph to set the BaseClass.offset fields.
* Recursive in order to account for the size of the interface classes, if they are
* more than just interfaces.
* Params:
* cd = interface to look at
* baseOffset = offset of where cd will be placed
* Returns:
* subset of instantiated size used by cd for interfaces
*/
uint membersPlace(ClassDeclaration cd, uint baseOffset)
{
//printf(" membersPlace(%s, %d)\n", cd.toChars(), baseOffset);
uint offset = baseOffset;

foreach (BaseClass* b; cd.interfaces)
{
if (b.sym.sizeok != Sizeok.done)
b.sym.finalizeSize();
assert(b.sym.sizeok == Sizeok.done);

if (!b.sym.alignsize)
b.sym.alignsize = target.ptrsize;
offset = alignmember(structalign_t(cast(ushort)b.sym.alignsize), b.sym.alignsize, offset);
assert(bi < vtblInterfaces.length);

BaseClass* bv = (*vtblInterfaces)[bi];
if (b.sym.interfaces.length == 0)
{
//printf("\tvtblInterfaces[%d] b=%p b.sym = %s, offset = %d\n", bi, bv, bv.sym.toChars(), offset);
bv.offset = offset;
++bi;
// All the base interfaces down the left side share the same offset
for (BaseClass* b2 = bv; b2.baseInterfaces.length; )
{
b2 = &b2.baseInterfaces[0];
b2.offset = offset;
//printf("\tvtblInterfaces[%d] b=%p sym = %s, offset = %d\n", bi, b2, b2.sym.toChars(), b2.offset);
}
}
membersPlace(b.sym, offset);
//printf(" %s size = %d\n", b.sym.toChars(), b.sym.structsize);
offset += b.sym.structsize;
if (alignsize < b.sym.alignsize)
alignsize = b.sym.alignsize;
}
return offset - baseOffset;
}

structsize += membersPlace(this, structsize);

if (isInterfaceDeclaration())
{
sizeok = Sizeok.done;
return;
}

// FIXME: Currently setFieldOffset functions need to increase fields
// to calculate each variable offsets. It can be improved later.
fields.setDim(0);

FieldState fieldState;
fieldState.offset = structsize;
foreach (s; *members)
{
s.setFieldOffset(this, &fieldState, false);
}

sizeok = Sizeok.done;

// Calculate fields[i].overlapped
checkOverlappedFields();
}

/**************
* Returns: true if there's a __monitor field
*/
Expand Down
Loading

0 comments on commit f66c6c2

Please sign in to comment.