[clang] f35aac6 - [clang][Interp] Fix zero-initializing unions
Timm Bäder via cfe-commits
cfe-commits at lists.llvm.org
Fri May 24 06:15:49 PDT 2024
Author: Timm Bäder
Date: 2024-05-24T15:15:40+02:00
New Revision: f35aac699167ef1046e2f177d2ba899c6975374e
URL: https://github.com/llvm/llvm-project/commit/f35aac699167ef1046e2f177d2ba899c6975374e
DIFF: https://github.com/llvm/llvm-project/commit/f35aac699167ef1046e2f177d2ba899c6975374e.diff
LOG: [clang][Interp] Fix zero-initializing unions
Only with primitive fields for now.
Added:
Modified:
clang/lib/AST/Interp/ByteCodeExprGen.cpp
clang/test/AST/Interp/unions.cpp
Removed:
################################################################################
diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
index b885cbe2c4b0e..f73eaeebf9fe8 100644
--- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -1053,9 +1053,6 @@ bool ByteCodeExprGen<Emitter>::visitInitList(ArrayRef<const Expr *> Inits,
if (Inits.size() == 1 && E->getType() == Inits[0]->getType())
return this->visitInitializer(Inits[0]);
- if (Inits.size() == 0)
- return this->emitFinishInit(E);
-
auto initPrimitiveField = [=](const Record::Field *FieldToInit,
const Expr *Init, PrimType T) -> bool {
if (!this->visit(Init))
@@ -1083,24 +1080,38 @@ bool ByteCodeExprGen<Emitter>::visitInitList(ArrayRef<const Expr *> Inits,
};
if (R->isUnion()) {
- assert(Inits.size() == 1);
- const Expr *Init = Inits[0];
- const FieldDecl *FToInit = nullptr;
- if (const auto *ILE = dyn_cast<InitListExpr>(E))
- FToInit = ILE->getInitializedFieldInUnion();
- else
- FToInit = cast<CXXParenListInitExpr>(E)->getInitializedFieldInUnion();
-
- if (!this->emitDupPtr(E))
- return false;
-
- const Record::Field *FieldToInit = R->getField(FToInit);
- if (std::optional<PrimType> T = classify(Init)) {
- if (!initPrimitiveField(FieldToInit, Init, *T))
- return false;
+ if (Inits.size() == 0) {
+ // Zero-initialize the first union field.
+ if (R->getNumFields() == 0)
+ return this->emitFinishInit(E);
+ const Record::Field *FieldToInit = R->getField(0u);
+ QualType FieldType = FieldToInit->Desc->getType();
+ if (std::optional<PrimType> T = classify(FieldType)) {
+ if (!this->visitZeroInitializer(*T, FieldType, E))
+ return false;
+ if (!this->emitInitField(*T, FieldToInit->Offset, E))
+ return false;
+ }
+ // FIXME: Non-primitive case?
} else {
- if (!initCompositeField(FieldToInit, Init))
+ const Expr *Init = Inits[0];
+ const FieldDecl *FToInit = nullptr;
+ if (const auto *ILE = dyn_cast<InitListExpr>(E))
+ FToInit = ILE->getInitializedFieldInUnion();
+ else
+ FToInit = cast<CXXParenListInitExpr>(E)->getInitializedFieldInUnion();
+
+ if (!this->emitDupPtr(E))
return false;
+
+ const Record::Field *FieldToInit = R->getField(FToInit);
+ if (std::optional<PrimType> T = classify(Init)) {
+ if (!initPrimitiveField(FieldToInit, Init, *T))
+ return false;
+ } else {
+ if (!initCompositeField(FieldToInit, Init))
+ return false;
+ }
}
return this->emitFinishInit(E);
}
diff --git a/clang/test/AST/Interp/unions.cpp b/clang/test/AST/Interp/unions.cpp
index b0b1b19617408..293a1981a52f0 100644
--- a/clang/test/AST/Interp/unions.cpp
+++ b/clang/test/AST/Interp/unions.cpp
@@ -31,6 +31,12 @@ static_assert(ab.d == 1.0, "");
static_assert(ab.a == 1, ""); // both-error {{not an integral constant expression}} \
// both-note {{read of member 'a' of union with active member 'd'}}
+
+namespace Empty {
+ union E {};
+ constexpr E e{};
+}
+
namespace SimpleStore {
union A {
int a;
@@ -49,3 +55,13 @@ namespace SimpleStore {
}
static_assert(empty() == 10, "");
}
+
+namespace ZeroInit {
+ struct S { int m; };
+ union Z {
+ float f;
+ };
+
+ constexpr Z z{};
+ static_assert(z.f == 0.0, "");
+}
More information about the cfe-commits
mailing list