diff --git a/compiler/src/dmd/aggregate.d b/compiler/src/dmd/aggregate.d index 78cb87f2fe7d..8970c351fc07 100644 --- a/compiler/src/dmd/aggregate.d +++ b/compiler/src/dmd/aggregate.d @@ -99,7 +99,7 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol StorageClass storage_class; /// uint structsize; /// size of struct uint alignsize; /// size of struct for alignment purposes - VarDeclarations fields; /// VarDeclaration fields + VarDeclarations fields; /// VarDeclaration fields including flattened AnonDeclaration members Dsymbol deferred; /// any deferred semantic2() or semantic3() symbol /// specifies whether this is a D, C++, Objective-C or anonymous struct/class/interface diff --git a/compiler/src/dmd/dstruct.d b/compiler/src/dmd/dstruct.d index 64f19d932ebf..0ed194a17ef6 100644 --- a/compiler/src/dmd/dstruct.d +++ b/compiler/src/dmd/dstruct.d @@ -350,8 +350,18 @@ extern (C++) class StructDeclaration : AggregateDeclaration // 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()) @@ -360,10 +370,6 @@ extern (C++) class StructDeclaration : AggregateDeclaration */ 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)) diff --git a/compiler/test/compilable/isZeroInit.d b/compiler/test/compilable/isZeroInit.d index a64420febc0f..342dc07bf0f2 100644 --- a/compiler/test/compilable/isZeroInit.d +++ b/compiler/test/compilable/isZeroInit.d @@ -78,3 +78,45 @@ static if (is(Vector!(int[4]))) static assert(__traits(isZeroInit, Holder!(Vector!(int[4]), 0))); static assert(!__traits(isZeroInit, Holder!(Vector!(int[4]), 1))); } + +// https://issues.dlang.org/show_bug.cgi?id=24776 +struct S6 { + union { + int i1; + float f1; + } +} +static assert(__traits(isZeroInit, S6)); + +struct S7 +{ + union { + float f2; + int i2; + } +} +static assert(!__traits(isZeroInit, S7)); + +// https://issues.dlang.org/show_bug.cgi?id=23841 +union U +{ + float x = 0; + float y; +} +static assert(__traits(isZeroInit, U)); + +union U2 +{ + float x; + int y; +} +static assert(!__traits(isZeroInit, U2)); + +struct S8 { + int[0] dummy; // same offset as anon union, but doesn't overlap; should be ignored anyway for zero-init check + union { + float f; // is the first member of the anon union and must be checked + int i; + } +} +static assert(!__traits(isZeroInit, S8));