[clang] af68120 - [clang][Interp] Fix initializing a union from an InitLIstExpr
Timm Bäder via cfe-commits
cfe-commits at lists.llvm.org
Thu May 23 00:18:11 PDT 2024
Author: Timm Bäder
Date: 2024-05-23T09:17:56+02:00
New Revision: af6812085cc7a7251a3095acbc96343ce660f135
URL: https://github.com/llvm/llvm-project/commit/af6812085cc7a7251a3095acbc96343ce660f135
DIFF: https://github.com/llvm/llvm-project/commit/af6812085cc7a7251a3095acbc96343ce660f135.diff
LOG: [clang][Interp] Fix initializing a union from an InitLIstExpr
We can't just count the field to initialize but need to consult the
InitListExpr to give us the right field.
Added:
Modified:
clang/lib/AST/Interp/ByteCodeExprGen.cpp
clang/lib/AST/Interp/Interp.h
clang/test/AST/Interp/unions.cpp
Removed:
################################################################################
diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
index 50c85bf7d35f5..e64d3a94b5091 100644
--- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -1050,38 +1050,71 @@ bool ByteCodeExprGen<Emitter>::visitInitList(ArrayRef<const Expr *> Inits,
if (T->isRecordType()) {
const Record *R = getRecord(E->getType());
- if (Inits.size() == 1 && E->getType() == Inits[0]->getType()) {
+ if (Inits.size() == 1 && E->getType() == Inits[0]->getType())
return this->visitInitializer(Inits[0]);
+
+ auto initPrimitiveField = [=](const Record::Field *FieldToInit,
+ const Expr *Init, PrimType T) -> bool {
+ if (!this->visit(Init))
+ return false;
+
+ if (FieldToInit->isBitField()) {
+ if (!this->emitInitBitField(T, FieldToInit, E))
+ return false;
+ } else {
+ if (!this->emitInitField(T, FieldToInit->Offset, E))
+ return false;
+ }
+ return this->emitPopPtr(E);
+ };
+
+ auto initCompositeField = [=](const Record::Field *FieldToInit,
+ const Expr *Init) -> bool {
+ // Non-primitive case. Get a pointer to the field-to-initialize
+ // on the stack and recurse into visitInitializer().
+ if (!this->emitGetPtrField(FieldToInit->Offset, Init))
+ return false;
+ if (!this->visitInitializer(Init))
+ return false;
+ return this->emitPopPtr(E);
+ };
+
+ 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;
+ } else {
+ if (!initCompositeField(FieldToInit, Init))
+ return false;
+ }
+ return this->emitFinishInit(E);
}
+ assert(!R->isUnion());
unsigned InitIndex = 0;
for (const Expr *Init : Inits) {
// Skip unnamed bitfields.
while (InitIndex < R->getNumFields() &&
R->getField(InitIndex)->Decl->isUnnamedBitField())
++InitIndex;
-
- // Potentially skip ahead. This is especially relevant in unions.
- if (const auto *D = dyn_cast<CXXDefaultInitExpr>(Init))
- InitIndex = D->getField()->getFieldIndex();
-
if (!this->emitDupPtr(E))
return false;
if (std::optional<PrimType> T = classify(Init)) {
const Record::Field *FieldToInit = R->getField(InitIndex);
- if (!this->visit(Init))
- return false;
-
- if (FieldToInit->isBitField()) {
- if (!this->emitInitBitField(*T, FieldToInit, E))
- return false;
- } else {
- if (!this->emitInitField(*T, FieldToInit->Offset, E))
- return false;
- }
-
- if (!this->emitPopPtr(E))
+ if (!initPrimitiveField(FieldToInit, Init, *T))
return false;
++InitIndex;
} else {
@@ -1099,21 +1132,13 @@ bool ByteCodeExprGen<Emitter>::visitInitList(ArrayRef<const Expr *> Inits,
// into the Record's fields.
} else {
const Record::Field *FieldToInit = R->getField(InitIndex);
- // Non-primitive case. Get a pointer to the field-to-initialize
- // on the stack and recurse into visitInitializer().
- if (!this->emitGetPtrField(FieldToInit->Offset, Init))
- return false;
-
- if (!this->visitInitializer(Init))
- return false;
-
- if (!this->emitPopPtr(E))
+ if (!initCompositeField(FieldToInit, Init))
return false;
++InitIndex;
}
}
}
- return true;
+ return this->emitFinishInit(E);
}
if (T->isArrayType()) {
@@ -1137,7 +1162,7 @@ bool ByteCodeExprGen<Emitter>::visitInitList(ArrayRef<const Expr *> Inits,
}
}
- return true;
+ return this->emitFinishInit(E);
}
if (const auto *ComplexTy = E->getType()->getAs<ComplexType>()) {
diff --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h
index 7ef963c810c82..8430a7de24dff 100644
--- a/clang/lib/AST/Interp/Interp.h
+++ b/clang/lib/AST/Interp/Interp.h
@@ -1337,14 +1337,15 @@ inline bool FinishInitPop(InterpState &S, CodePtr OpPC) {
const Pointer &Ptr = S.Stk.pop<Pointer>();
if (Ptr.canBeInitialized())
Ptr.initialize();
+ Ptr.activate();
return true;
}
inline bool FinishInit(InterpState &S, CodePtr OpPC) {
const Pointer &Ptr = S.Stk.peek<Pointer>();
-
if (Ptr.canBeInitialized())
Ptr.initialize();
+ Ptr.activate();
return true;
}
diff --git a/clang/test/AST/Interp/unions.cpp b/clang/test/AST/Interp/unions.cpp
index 46ba514b47b98..bc5604c2b2d04 100644
--- a/clang/test/AST/Interp/unions.cpp
+++ b/clang/test/AST/Interp/unions.cpp
@@ -18,3 +18,15 @@ constexpr U1 u1{};
static_assert(u1.f == 3.0, "");
static_assert(u1.i == 1, ""); // both-error {{not an integral constant expression}} \
// both-note {{read of member 'i' of union with active member 'f'}}
+
+
+
+union A {
+ int a;
+ double d;
+};
+constexpr A aa = {1, 2.0}; // both-error {{excess elements in union initializer}}
+constexpr A ab = {.d = 1.0};
+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'}}
More information about the cfe-commits
mailing list