Skip to content

Commit f35aac6

Browse files
committed
[clang][Interp] Fix zero-initializing unions
Only with primitive fields for now.
1 parent 214e6b4 commit f35aac6

File tree

2 files changed

+46
-19
lines changed

2 files changed

+46
-19
lines changed

clang/lib/AST/Interp/ByteCodeExprGen.cpp

Lines changed: 30 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1053,9 +1053,6 @@ bool ByteCodeExprGen<Emitter>::visitInitList(ArrayRef<const Expr *> Inits,
10531053
if (Inits.size() == 1 && E->getType() == Inits[0]->getType())
10541054
return this->visitInitializer(Inits[0]);
10551055

1056-
if (Inits.size() == 0)
1057-
return this->emitFinishInit(E);
1058-
10591056
auto initPrimitiveField = [=](const Record::Field *FieldToInit,
10601057
const Expr *Init, PrimType T) -> bool {
10611058
if (!this->visit(Init))
@@ -1083,24 +1080,38 @@ bool ByteCodeExprGen<Emitter>::visitInitList(ArrayRef<const Expr *> Inits,
10831080
};
10841081

10851082
if (R->isUnion()) {
1086-
assert(Inits.size() == 1);
1087-
const Expr *Init = Inits[0];
1088-
const FieldDecl *FToInit = nullptr;
1089-
if (const auto *ILE = dyn_cast<InitListExpr>(E))
1090-
FToInit = ILE->getInitializedFieldInUnion();
1091-
else
1092-
FToInit = cast<CXXParenListInitExpr>(E)->getInitializedFieldInUnion();
1093-
1094-
if (!this->emitDupPtr(E))
1095-
return false;
1096-
1097-
const Record::Field *FieldToInit = R->getField(FToInit);
1098-
if (std::optional<PrimType> T = classify(Init)) {
1099-
if (!initPrimitiveField(FieldToInit, Init, *T))
1100-
return false;
1083+
if (Inits.size() == 0) {
1084+
// Zero-initialize the first union field.
1085+
if (R->getNumFields() == 0)
1086+
return this->emitFinishInit(E);
1087+
const Record::Field *FieldToInit = R->getField(0u);
1088+
QualType FieldType = FieldToInit->Desc->getType();
1089+
if (std::optional<PrimType> T = classify(FieldType)) {
1090+
if (!this->visitZeroInitializer(*T, FieldType, E))
1091+
return false;
1092+
if (!this->emitInitField(*T, FieldToInit->Offset, E))
1093+
return false;
1094+
}
1095+
// FIXME: Non-primitive case?
11011096
} else {
1102-
if (!initCompositeField(FieldToInit, Init))
1097+
const Expr *Init = Inits[0];
1098+
const FieldDecl *FToInit = nullptr;
1099+
if (const auto *ILE = dyn_cast<InitListExpr>(E))
1100+
FToInit = ILE->getInitializedFieldInUnion();
1101+
else
1102+
FToInit = cast<CXXParenListInitExpr>(E)->getInitializedFieldInUnion();
1103+
1104+
if (!this->emitDupPtr(E))
11031105
return false;
1106+
1107+
const Record::Field *FieldToInit = R->getField(FToInit);
1108+
if (std::optional<PrimType> T = classify(Init)) {
1109+
if (!initPrimitiveField(FieldToInit, Init, *T))
1110+
return false;
1111+
} else {
1112+
if (!initCompositeField(FieldToInit, Init))
1113+
return false;
1114+
}
11041115
}
11051116
return this->emitFinishInit(E);
11061117
}

clang/test/AST/Interp/unions.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,12 @@ static_assert(ab.d == 1.0, "");
3131
static_assert(ab.a == 1, ""); // both-error {{not an integral constant expression}} \
3232
// both-note {{read of member 'a' of union with active member 'd'}}
3333

34+
35+
namespace Empty {
36+
union E {};
37+
constexpr E e{};
38+
}
39+
3440
namespace SimpleStore {
3541
union A {
3642
int a;
@@ -49,3 +55,13 @@ namespace SimpleStore {
4955
}
5056
static_assert(empty() == 10, "");
5157
}
58+
59+
namespace ZeroInit {
60+
struct S { int m; };
61+
union Z {
62+
float f;
63+
};
64+
65+
constexpr Z z{};
66+
static_assert(z.f == 0.0, "");
67+
}

0 commit comments

Comments
 (0)