mirror of
https://github.com/dlang/dmd.git
synced 2025-04-25 20:50:41 +03:00
Extracted AggregateDeclaration.finalizeSize into a visitor in dsymbolsem (#21139)
This commit is contained in:
parent
b5b84fb102
commit
d48bdb8f78
6 changed files with 242 additions and 240 deletions
|
@ -187,8 +187,6 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol
|
|||
return fields.length - isNested() - (vthis2 !is null);
|
||||
}
|
||||
|
||||
abstract void finalizeSize();
|
||||
|
||||
override final uinteger_t size(Loc loc)
|
||||
{
|
||||
//printf("+AggregateDeclaration::size() %s, scope = %p, sizeok = %d\n", toChars(), _scope, sizeok);
|
||||
|
|
|
@ -120,7 +120,6 @@ public:
|
|||
Sizeok sizeok; // set when structsize contains valid data
|
||||
|
||||
virtual Scope *newScope(Scope *sc);
|
||||
virtual void finalizeSize() = 0;
|
||||
uinteger_t size(Loc loc) override final;
|
||||
Type *getType() override final;
|
||||
bool isDeprecated() const override final; // is aggregate deprecated?
|
||||
|
@ -172,7 +171,6 @@ public:
|
|||
static StructDeclaration *create(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);
|
||||
|
@ -287,7 +285,6 @@ public:
|
|||
virtual bool isBaseOf(ClassDeclaration *cd, int *poffset);
|
||||
|
||||
bool isBaseInfoComplete();
|
||||
void finalizeSize() override;
|
||||
bool hasMonitor();
|
||||
bool isCOMclass() const;
|
||||
virtual bool isCOMinterface() const;
|
||||
|
|
|
@ -23,7 +23,6 @@ import dmd.gluelayer;
|
|||
import dmd.declaration;
|
||||
import dmd.dscope;
|
||||
import dmd.dsymbol;
|
||||
import dmd.dsymbolsem : setFieldOffset;
|
||||
import dmd.errors;
|
||||
import dmd.func;
|
||||
import dmd.id;
|
||||
|
@ -495,116 +494,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
|
||||
*/
|
||||
|
|
|
@ -151,127 +151,6 @@ extern (C++) class StructDeclaration : AggregateDeclaration
|
|||
return "struct";
|
||||
}
|
||||
|
||||
override final void finalizeSize()
|
||||
{
|
||||
//printf("StructDeclaration::finalizeSize() %s, sizeok = %d\n", toChars(), sizeok);
|
||||
assert(sizeok != Sizeok.done);
|
||||
|
||||
if (sizeok == Sizeok.inProcess)
|
||||
{
|
||||
return;
|
||||
}
|
||||
sizeok = Sizeok.inProcess;
|
||||
|
||||
//printf("+StructDeclaration::finalizeSize() %s, fields.length = %d, sizeok = %d\n", toChars(), fields.length, sizeok);
|
||||
|
||||
fields.setDim(0); // workaround
|
||||
|
||||
// Set the offsets of the fields and determine the size of the struct
|
||||
FieldState fieldState;
|
||||
bool isunion = isUnionDeclaration() !is null;
|
||||
for (size_t i = 0; i < members.length; i++)
|
||||
{
|
||||
Dsymbol s = (*members)[i];
|
||||
s.setFieldOffset(this, &fieldState, isunion);
|
||||
if (type.ty == Terror)
|
||||
{
|
||||
errorSupplemental(s.loc, "error on member `%s`", s.toPrettyChars);
|
||||
errors = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (structsize == 0)
|
||||
{
|
||||
hasNoFields = true;
|
||||
alignsize = 1;
|
||||
|
||||
// A fine mess of what size a zero sized struct should be
|
||||
final switch (classKind)
|
||||
{
|
||||
case ClassKind.d:
|
||||
case ClassKind.cpp:
|
||||
structsize = 1;
|
||||
break;
|
||||
|
||||
case ClassKind.c:
|
||||
case ClassKind.objc:
|
||||
if (target.c.bitFieldStyle == TargetC.BitFieldStyle.MS)
|
||||
{
|
||||
/* Undocumented MS behavior for:
|
||||
* struct S { int :0; };
|
||||
*/
|
||||
structsize = 4;
|
||||
}
|
||||
else
|
||||
structsize = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Round struct size up to next alignsize boundary.
|
||||
// This will ensure that arrays of structs will get their internals
|
||||
// aligned properly.
|
||||
if (alignment.isDefault() || alignment.isPack())
|
||||
structsize = (structsize + alignsize - 1) & ~(alignsize - 1);
|
||||
else
|
||||
structsize = (structsize + alignment.get() - 1) & ~(alignment.get() - 1);
|
||||
|
||||
sizeok = Sizeok.done;
|
||||
|
||||
//printf("-StructDeclaration::finalizeSize() %s, fields.length = %d, structsize = %d\n", toChars(), cast(int)fields.length, cast(int)structsize);
|
||||
|
||||
if (errors)
|
||||
return;
|
||||
|
||||
// Calculate fields[i].overlapped
|
||||
if (checkOverlappedFields())
|
||||
{
|
||||
errors = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// Determine if struct is all zeros or not
|
||||
zeroInit = true;
|
||||
auto lastOffset = -1;
|
||||
foreach (vd; fields)
|
||||
{
|
||||
// First skip zero sized fields
|
||||
if (vd.type.size(vd.loc) == 0)
|
||||
continue;
|
||||
|
||||
// only consider first sized member of an (anonymous) union
|
||||
if (vd.overlapped && vd.offset == lastOffset)
|
||||
continue;
|
||||
lastOffset = vd.offset;
|
||||
|
||||
if (vd._init)
|
||||
{
|
||||
if (vd._init.isVoidInitializer())
|
||||
/* Treat as 0 for the purposes of putting the initializer
|
||||
* in the BSS segment, or doing a mass set to 0
|
||||
*/
|
||||
continue;
|
||||
|
||||
// Examine init to see if it is all 0s.
|
||||
auto exp = vd.getConstInitializer();
|
||||
if (!exp || !_isZeroInit(exp))
|
||||
{
|
||||
zeroInit = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (!vd.type.isZeroInit(loc))
|
||||
{
|
||||
zeroInit = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
argTypes = target.toArgTypes(type);
|
||||
}
|
||||
|
||||
/// Compute cached type properties for `TypeStruct`
|
||||
extern(D) final void determineTypeProperties()
|
||||
{
|
||||
|
|
|
@ -8308,3 +8308,245 @@ extern(C++) bool isAbstract(ClassDeclaration cd)
|
|||
|
||||
return no();
|
||||
}
|
||||
|
||||
void finalizeSize(AggregateDeclaration ad)
|
||||
{
|
||||
scope v = new FinalizeSizeVisitor();
|
||||
ad.accept(v);
|
||||
}
|
||||
|
||||
private extern(C++) class FinalizeSizeVisitor : Visitor
|
||||
{
|
||||
alias visit = Visitor.visit;
|
||||
|
||||
override void visit(ClassDeclaration outerCd)
|
||||
{
|
||||
assert(outerCd.sizeok != Sizeok.done);
|
||||
|
||||
// Set the offsets of the fields and determine the size of the class
|
||||
if (outerCd.baseClass)
|
||||
{
|
||||
assert(outerCd.baseClass.sizeok == Sizeok.done);
|
||||
|
||||
outerCd.alignsize = outerCd.baseClass.alignsize;
|
||||
if (outerCd.classKind == ClassKind.cpp)
|
||||
outerCd.structsize = target.cpp.derivedClassOffset(outerCd.baseClass);
|
||||
else
|
||||
outerCd.structsize = outerCd.baseClass.structsize;
|
||||
}
|
||||
else if (outerCd.classKind == ClassKind.objc)
|
||||
outerCd.structsize = 0; // no hidden member for an Objective-C class
|
||||
else if (outerCd.isInterfaceDeclaration())
|
||||
{
|
||||
if (outerCd.interfaces.length == 0)
|
||||
{
|
||||
outerCd.alignsize = target.ptrsize;
|
||||
outerCd.structsize = target.ptrsize; // allow room for __vptr
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
outerCd.alignsize = target.ptrsize;
|
||||
outerCd.structsize = target.ptrsize; // allow room for __vptr
|
||||
if (outerCd.hasMonitor())
|
||||
outerCd.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 < outerCd.vtblInterfaces.length);
|
||||
|
||||
BaseClass* bv = (*(outerCd.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 (outerCd.alignsize < b.sym.alignsize)
|
||||
outerCd.alignsize = b.sym.alignsize;
|
||||
}
|
||||
return offset - baseOffset;
|
||||
}
|
||||
|
||||
outerCd.structsize += membersPlace(outerCd, outerCd.structsize);
|
||||
|
||||
if (outerCd.isInterfaceDeclaration())
|
||||
{
|
||||
outerCd.sizeok = Sizeok.done;
|
||||
return;
|
||||
}
|
||||
|
||||
// FIXME: Currently setFieldOffset functions need to increase fields
|
||||
// to calculate each variable offsets. It can be improved later.
|
||||
outerCd.fields.setDim(0);
|
||||
|
||||
FieldState fieldState;
|
||||
fieldState.offset = outerCd.structsize;
|
||||
foreach (s; *(outerCd.members))
|
||||
{
|
||||
s.setFieldOffset(outerCd, &fieldState, false);
|
||||
}
|
||||
|
||||
outerCd.sizeok = Sizeok.done;
|
||||
|
||||
// Calculate fields[i].overlapped
|
||||
outerCd.checkOverlappedFields();
|
||||
}
|
||||
|
||||
override void visit(StructDeclaration sd)
|
||||
{
|
||||
//printf("StructDeclaration::finalizeSize() %s, sizeok = %d\n", toChars(), sizeok);
|
||||
assert(sd.sizeok != Sizeok.done);
|
||||
|
||||
if (sd.sizeok == Sizeok.inProcess)
|
||||
{
|
||||
return;
|
||||
}
|
||||
sd.sizeok = Sizeok.inProcess;
|
||||
|
||||
//printf("+StructDeclaration::finalizeSize() %s, fields.length = %d, sizeok = %d\n", toChars(), fields.length, sizeok);
|
||||
|
||||
sd.fields.setDim(0); // workaround
|
||||
|
||||
// Set the offsets of the fields and determine the size of the struct
|
||||
FieldState fieldState;
|
||||
bool isunion = sd.isUnionDeclaration() !is null;
|
||||
for (size_t i = 0; i < sd.members.length; i++)
|
||||
{
|
||||
Dsymbol s = (*sd.members)[i];
|
||||
s.setFieldOffset(sd, &fieldState, isunion);
|
||||
if (sd.type.ty == Terror)
|
||||
{
|
||||
errorSupplemental(s.loc, "error on member `%s`", s.toPrettyChars);
|
||||
sd.errors = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (sd.structsize == 0)
|
||||
{
|
||||
sd.hasNoFields = true;
|
||||
sd.alignsize = 1;
|
||||
|
||||
// A fine mess of what size a zero sized struct should be
|
||||
final switch (sd.classKind)
|
||||
{
|
||||
case ClassKind.d:
|
||||
case ClassKind.cpp:
|
||||
sd.structsize = 1;
|
||||
break;
|
||||
|
||||
case ClassKind.c:
|
||||
case ClassKind.objc:
|
||||
if (target.c.bitFieldStyle == TargetC.BitFieldStyle.MS)
|
||||
{
|
||||
/* Undocumented MS behavior for:
|
||||
* struct S { int :0; };
|
||||
*/
|
||||
sd.structsize = 4;
|
||||
}
|
||||
else
|
||||
sd.structsize = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Round struct size up to next alignsize boundary.
|
||||
// This will ensure that arrays of structs will get their internals
|
||||
// aligned properly.
|
||||
if (sd.alignment.isDefault() || sd.alignment.isPack())
|
||||
sd.structsize = (sd.structsize + sd.alignsize - 1) & ~(sd.alignsize - 1);
|
||||
else
|
||||
sd.structsize = (sd.structsize + sd.alignment.get() - 1) & ~(sd.alignment.get() - 1);
|
||||
|
||||
sd.sizeok = Sizeok.done;
|
||||
|
||||
//printf("-StructDeclaration::finalizeSize() %s, fields.length = %d, structsize = %d\n", toChars(), cast(int)fields.length, cast(int)structsize);
|
||||
|
||||
if (sd.errors)
|
||||
return;
|
||||
|
||||
// Calculate fields[i].overlapped
|
||||
if (sd.checkOverlappedFields())
|
||||
{
|
||||
sd.errors = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// Determine if struct is all zeros or not
|
||||
sd.zeroInit = true;
|
||||
auto lastOffset = -1;
|
||||
foreach (vd; sd.fields)
|
||||
{
|
||||
// First skip zero sized fields
|
||||
if (vd.type.size(vd.loc) == 0)
|
||||
continue;
|
||||
|
||||
// only consider first sized member of an (anonymous) union
|
||||
if (vd.overlapped && vd.offset == lastOffset)
|
||||
continue;
|
||||
lastOffset = vd.offset;
|
||||
|
||||
if (vd._init)
|
||||
{
|
||||
if (vd._init.isVoidInitializer())
|
||||
/* Treat as 0 for the purposes of putting the initializer
|
||||
* in the BSS segment, or doing a mass set to 0
|
||||
*/
|
||||
continue;
|
||||
|
||||
// Examine init to see if it is all 0s.
|
||||
auto exp = vd.getConstInitializer();
|
||||
if (!exp || !_isZeroInit(exp))
|
||||
{
|
||||
sd.zeroInit = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (!vd.type.isZeroInit(sd.loc))
|
||||
{
|
||||
sd.zeroInit = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
sd.argTypes = target.toArgTypes(sd.type);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6354,7 +6354,6 @@ public:
|
|||
bool disableNew;
|
||||
Sizeok sizeok;
|
||||
virtual Scope* newScope(Scope* sc);
|
||||
virtual void finalizeSize() = 0;
|
||||
uinteger_t size(Loc loc) final override;
|
||||
Type* getType() final override;
|
||||
bool isDeprecated() const final override;
|
||||
|
@ -6701,7 +6700,6 @@ public:
|
|||
|
||||
virtual bool isBaseOf(ClassDeclaration* cd, int32_t* poffset);
|
||||
bool isBaseInfoComplete() const;
|
||||
void finalizeSize() final override;
|
||||
bool hasMonitor();
|
||||
bool isCOMclass() const;
|
||||
virtual bool isCOMinterface() const;
|
||||
|
@ -7435,7 +7433,6 @@ public:
|
|||
static StructDeclaration* create(Loc loc, Identifier* id, bool inObject);
|
||||
StructDeclaration* syntaxCopy(Dsymbol* s) override;
|
||||
const char* kind() const override;
|
||||
void finalizeSize() final override;
|
||||
bool isPOD();
|
||||
bool hasCopyConstruction();
|
||||
void accept(Visitor* v) override;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue