Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
ee09667
do not assume zero-init of structs, calculate lazily if necessary
rainers Jan 6, 2018
f79c4c2
fix issue 10442: predict type info references in glue layer
rainers Jan 6, 2018
fc5c098
TypeInfo generation always needs semantic3 to evaluate RTInfo
rainers Jan 6, 2018
9819a55
white space fixes
rainers Jan 7, 2018
68847e6
do not write type info for broken definitions
rainers Jan 7, 2018
393427c
cannot skip RTInfo generation for deprecated structs, they might stil…
rainers Jan 7, 2018
9c55f54
fix rebase
rainers Jan 14, 2018
41878b4
add test case for issue 10442
rainers Jan 29, 2018
5e7e84b
use enum for zeroInit
rainers Jan 30, 2018
c3280e8
make some symbols private, add ddoc comments
rainers Jan 31, 2018
7f14169
fix rebase
rainers Sep 9, 2020
56aefa3
no error if RTInfo not defined
rainers Sep 14, 2020
2216410
RTInfo generation must not be omitted for deprecated aggregates
rainers Sep 14, 2020
3fff582
fix semantic not run on TypeInfo when added to module that has alread…
rainers Sep 17, 2020
391ca7c
cannot avoid running semantic on struct declaration if template RTInf…
rainers Sep 17, 2020
353957d
adapt test to new RTInfo, skip semanticTypeInfo with -betterC, ensure…
rainers Sep 18, 2020
2f87481
don't generate TypeInfo data for forward declared struct
rainers Sep 18, 2020
cd76c8d
remove unnecessary call to verifyTypeInfo
rainers Sep 18, 2020
1a42547
static foreach: no need to convert static array, can be used directly…
rainers Sep 18, 2020
0340cf1
use semanticTypeInfo instead of direct call to genTypeInfo
rainers Sep 19, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/dmd/aggregate.d
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol
DtorDeclaration tidtor; /// aggregate destructor used in TypeInfo (must have extern(D) ABI)
FuncDeclaration fieldDtor; /// aggregate destructor for just the fields

Scope* rtInfoScope; /// save scope of declaration for RTInfo calculation
Expression getRTInfo; /// pointer to GC info generated by object.RTInfo(this)

Prot protection; /// visibility
Expand Down
12 changes: 11 additions & 1 deletion src/dmd/aggregate.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,13 @@ enum Abstract
};

FuncDeclaration *search_toString(StructDeclaration *sd);
enum ZeroInit
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

enum class can now be used

{
ZEROINITunknown = -1, // not computed yet
ZEROINITno = 0, // struct is not all zeroes
ZEROINITyes = 1 // struct is all zeroes
};


struct ClassKind
{
Expand Down Expand Up @@ -113,6 +120,7 @@ class AggregateDeclaration : public ScopeDsymbol
DtorDeclaration *tidtor; // aggregate destructor used in TypeInfo (must have extern(D) ABI)
FuncDeclaration *fieldDtor; // aggregate destructor for just the fields

Scope* rtInfoScope; // save scope of declaration for RTInfo calculation
Expression *getRTInfo; // pointer to GC info generated by object.RTInfo(this)

Prot protection;
Expand Down Expand Up @@ -159,7 +167,7 @@ struct StructFlags
class StructDeclaration : public AggregateDeclaration
{
public:
bool zeroInit; // !=0 if initialize with 0 fill
ZeroInit zeroInit; // if struct is initialized to all zeroes
bool hasIdentityAssign; // true if has identity opAssign
bool hasBlitAssign; // true if opAssign is a blit
bool hasIdentityEquals; // true if has identity opEquals
Expand Down Expand Up @@ -193,6 +201,8 @@ class StructDeclaration : public AggregateDeclaration
void finalizeSize();
bool fit(const Loc &loc, Scope *sc, Expressions *elements, Type *stype);
bool isPOD();
bool isZeroInit();
ZeroInit calcZeroInit();

StructDeclaration *isStructDeclaration() { return this; }
void accept(Visitor *v) { v->visit(this); }
Expand Down
11 changes: 9 additions & 2 deletions src/dmd/astbase.d
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,13 @@ struct ASTBase
fwd, // POD not yet computed
}

enum ZeroInit : byte
{
unknown = -1, // not computed yet
no = 0, // struct is not all zeroes
yes = 1, // struct is all zeroes
};

enum TRUST : ubyte
{
default_ = 0,
Expand Down Expand Up @@ -1512,13 +1519,13 @@ struct ASTBase

extern (C++) class StructDeclaration : AggregateDeclaration
{
int zeroInit;
ZeroInit zeroInit;
StructPOD ispod;

final extern (D) this(const ref Loc loc, Identifier id, bool inObject)
{
super(loc, id);
zeroInit = 0;
zeroInit = ZeroInit.unknown;
ispod = StructPOD.fwd;
type = new TypeStruct(this);
if (inObject)
Expand Down
5 changes: 3 additions & 2 deletions src/dmd/cond.d
Original file line number Diff line number Diff line change
Expand Up @@ -447,14 +447,15 @@ extern (C++) final class StaticForeach : RootObject
}
}

if (aggrfe && aggrfe.aggr.type.toBasetype().ty == Terror)
auto ty = aggrfe ? aggrfe.aggr.type.toBasetype().ty : TMAX;
if (ty == Terror)
{
return;
}

if (!ready())
{
if (aggrfe && aggrfe.aggr.type.toBasetype().ty == Tarray)
if (ty == Tarray || ty == Tsarray)
{
lowerArrayAggregate(sc);
}
Expand Down
21 changes: 21 additions & 0 deletions src/dmd/dcast.d
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,18 @@ Expression implicitCastTo(Expression e, Scope* sc, Type t)
semanticTypeInfo(sc, ta.next);
}

override void visit(AssocArrayLiteralExp e)
{
visit(cast(Expression)e);
semanticTypeInfo(sc, result.type);
}

override void visit(NewExp e)
{
visit(cast(Expression)e);
semanticTypeInfo(sc, result.type);
}

override void visit(SliceExp e)
{
visit(cast(Expression)e);
Expand Down Expand Up @@ -1750,6 +1762,12 @@ Expression castTo(Expression e, Scope* sc, Type t)
result = e;
}

override void visit(NewExp e)
{
visit(cast(Expression)e);
semanticTypeInfo(sc, result.type);
}

override void visit(StructLiteralExp e)
{
visit(cast(Expression)e);
Expand Down Expand Up @@ -2209,6 +2227,7 @@ Expression castTo(Expression e, Scope* sc, Type t)
{
ae = cast(ArrayLiteralExp)e.copy();
ae.type = tp;
semanticTypeInfo(sc, ae.type);
}
}
else if (tb.ty == Tvector && (typeb.ty == Tarray || typeb.ty == Tsarray))
Expand Down Expand Up @@ -2242,6 +2261,7 @@ Expression castTo(Expression e, Scope* sc, Type t)
}
Expression ev = new VectorExp(e.loc, ae, tb);
ev = ev.expressionSemantic(sc);
semanticTypeInfo(sc, ev.type);
result = ev;
return;
}
Expand Down Expand Up @@ -2279,6 +2299,7 @@ Expression castTo(Expression e, Scope* sc, Type t)
(*ae.keys)[i] = ex;
}
ae.type = t;
ae.verifyTypeInfo(sc);
result = ae;
return;
}
Expand Down
96 changes: 62 additions & 34 deletions src/dmd/dstruct.d
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@
*/
extern (C++) void semanticTypeInfo(Scope* sc, Type t)
{
if (!global.params.useTypeInfo || !Type.dtypeinfo)
return; // not expected to be used with -betterC

if (sc)
{
if (sc.intypeof)
Expand Down Expand Up @@ -128,7 +131,7 @@
*/
if (!sd.members)
return; // opaque struct
if (!sd.xeq && !sd.xcmp && !sd.postblit && !sd.dtor && !sd.xhash && !search_toString(sd))
if (!Type.rtinfo && !sd.xeq && !sd.xcmp && !sd.postblit && !sd.dtor && !sd.xhash && !search_toString(sd))
return; // none of TypeInfo-specific members

// If the struct is in a non-root module, run semantic3 to get
Expand Down Expand Up @@ -166,7 +169,7 @@
/* Note structural similarity of this Type walker to that in isSpeculativeType()
*/

Type tb = t.toBasetype();
Type tb = t.toBasetype().mutableOf().unSharedOf(); // remove modifiers
switch (tb.ty)
{
case Tvector: visitVector(tb.isTypeVector()); break;
Expand Down Expand Up @@ -194,12 +197,19 @@
fwd, // POD not yet computed
}

private enum ZeroInit : byte
{
unknown = -1, // not computed yet
no = 0, // struct is not all zeroes
yes = 1, // struct is all zeroes
};

/***********************************************************
* All `struct` declarations are an instance of this.
*/
extern (C++) class StructDeclaration : AggregateDeclaration
{
bool zeroInit; // !=0 if initialize with 0 fill
ZeroInit zeroInit; // if struct is initialized to all zeroes
bool hasIdentityAssign; // true if has identity opAssign
bool hasBlitAssign; // true if opAssign is a blit
bool hasIdentityEquals; // true if has identity opEquals
Expand Down Expand Up @@ -228,7 +238,7 @@
extern (D) this(const ref Loc loc, Identifier id, bool inObject)
{
super(loc, id);
zeroInit = false; // assume false until we do semantic processing
zeroInit = ZeroInit.unknown;
ispod = StructPOD.fwd;
// For forward references
type = new TypeStruct(this);
Expand Down Expand Up @@ -386,36 +396,8 @@
return;
}

// Determine if struct is all zeros or not
zeroInit = true;
foreach (vd; fields)
{
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;

// Zero size fields are zero initialized
if (vd.type.size(vd.loc) == 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;
}
}
if (zeroInit == ZeroInit.unknown)
zeroInit = calcZeroInit();

argTypes = target.toArgTypes(type);
}
Expand Down Expand Up @@ -585,6 +567,52 @@
return (ispod == StructPOD.yes);
}

/***************************************
* Lazily determine whether a struct init value is a chunk of zeroes
*
* Returns:
* true if struct is all zeroes
*/
final bool isZeroInit()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why add this function alongside TypeStruct.isZeroInit?

{
if (zeroInit == ZeroInit.unknown)
if (semanticRun < PASS.semanticdone && _scope)
dsymbolSemantic(this, null);

Check warning on line 580 in src/dmd/dstruct.d

View check run for this annotation

Codecov / codecov/patch

src/dmd/dstruct.d#L580

Added line #L580 was not covered by tests
if (zeroInit == ZeroInit.unknown)
zeroInit = calcZeroInit();
return zeroInit == ZeroInit.yes;
}

private final ZeroInit calcZeroInit()
{
// Determine if struct is all zeros or not
foreach (vd; fields)
{
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;

// Zero size fields are zero initialized
if (vd.type.size(vd.loc) == 0)
continue;

Check warning on line 601 in src/dmd/dstruct.d

View check run for this annotation

Codecov / codecov/patch

src/dmd/dstruct.d#L601

Added line #L601 was not covered by tests

// Examine init to see if it is all 0s.
auto exp = vd.getConstInitializer();
if (!exp || !_isZeroInit(exp))
return ZeroInit.no;
}
else if (!vd.type.isZeroInit(loc))
{
return ZeroInit.no;
}
}
return ZeroInit.yes;
}

override final inout(StructDeclaration) isStructDeclaration() inout
{
return this;
Expand Down
18 changes: 15 additions & 3 deletions src/dmd/dsymbolsem.d
Original file line number Diff line number Diff line change
Expand Up @@ -1310,7 +1310,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
dsym._init = new ExpInitializer(dsym.loc, e);
goto Ldtor;
}
if (tv.ty == Tstruct && (cast(TypeStruct)tv).sym.zeroInit)
if (tv.ty == Tstruct && (cast(TypeStruct)tv).sym.isZeroInit())
{
/* If a struct is all zeros, as a special case
* set it's initializer to the integer 0.
Expand Down Expand Up @@ -4827,6 +4827,10 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
}
}

if (!sc.nofree)
sc.setNoFree(); // may need it even after semantic() finishes
sd.rtInfoScope = sc;

if (sd.type.ty == Tstruct && (cast(TypeStruct)sd.type).sym != sd)
{
// https://issues.dlang.org/show_bug.cgi?id=19024
Expand Down Expand Up @@ -5488,7 +5492,11 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
cldec.semanticRun = PASS.semanticdone;
//printf("-ClassDeclaration.dsymbolSemantic(%s), type = %p\n", toChars(), type);

sc2.pop();
sc2 = sc2.pop();

if (!sc2.nofree)
sc2.setNoFree(); // may need it even after semantic() finishes
cldec.rtInfoScope = sc2;

/* isAbstract() is undecidable in some cases because of circular dependencies.
* Now that semantic is finished, get a definitive result, and error if it is not the same.
Expand Down Expand Up @@ -5840,7 +5848,11 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
idec.semanticRun = PASS.semanticdone;
//printf("-InterfaceDeclaration.dsymbolSemantic(%s), type = %p\n", toChars(), type);

sc2.pop();
sc2 = sc2.pop();

if (!sc2.nofree)
sc2.setNoFree(); // may need it even after semantic() finishes
idec.rtInfoScope = sc2;

if (global.errors != errors)
{
Expand Down
Loading