[clang] 3b57f6b - [clang][Interp] Handle nested unions (#102743)
via cfe-commits
cfe-commits at lists.llvm.org
Sat Aug 10 05:16:51 PDT 2024
Author: Timm Baeder
Date: 2024-08-10T14:16:47+02:00
New Revision: 3b57f6b4c76d9b54b1c42591fdddf0ddc86dc964
URL: https://github.com/llvm/llvm-project/commit/3b57f6b4c76d9b54b1c42591fdddf0ddc86dc964
DIFF: https://github.com/llvm/llvm-project/commit/3b57f6b4c76d9b54b1c42591fdddf0ddc86dc964.diff
LOG: [clang][Interp] Handle nested unions (#102743)
Added:
Modified:
clang/lib/AST/Interp/Interp.cpp
clang/lib/AST/Interp/Pointer.cpp
clang/test/AST/Interp/unions.cpp
Removed:
################################################################################
diff --git a/clang/lib/AST/Interp/Interp.cpp b/clang/lib/AST/Interp/Interp.cpp
index 588680adb4616..89ac693893113 100644
--- a/clang/lib/AST/Interp/Interp.cpp
+++ b/clang/lib/AST/Interp/Interp.cpp
@@ -125,18 +125,15 @@ static bool CheckActive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
if (Ptr.isActive())
return true;
- // Get the inactive field descriptor.
- const FieldDecl *InactiveField = Ptr.getField();
- assert(InactiveField);
-
- // Walk up the pointer chain to find the closest union.
Pointer U = Ptr.getBase();
- while (!U.getFieldDesc()->isUnion())
+ Pointer C = Ptr;
+ while (!U.isRoot() && U.inUnion() && !U.isActive()) {
+ C = U;
U = U.getBase();
-
- // Find the active field of the union.
- const Record *R = U.getRecord();
- assert(R && R->isUnion() && "Not a union");
+ }
+ // Get the inactive field descriptor.
+ const FieldDecl *InactiveField = C.getField();
+ assert(InactiveField);
// Consider:
// union U {
@@ -148,10 +145,15 @@ static bool CheckActive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
//
// When activating x, we will also activate a. If we now try to read
// from y, we will get to CheckActive, because y is not active. In that
- // case we return here and let later code handle this.
- if (!llvm::is_contained(R->getDecl()->fields(), InactiveField))
+ // case, our U will be a (not a union). We return here and let later code
+ // handle this.
+ if (!U.getFieldDesc()->isUnion())
return true;
+ // Find the active field of the union.
+ const Record *R = U.getRecord();
+ assert(R && R->isUnion() && "Not a union");
+
const FieldDecl *ActiveField = nullptr;
for (unsigned I = 0, N = R->getNumFields(); I < N; ++I) {
const Pointer &Field = U.atField(R->getField(I)->Offset);
diff --git a/clang/lib/AST/Interp/Pointer.cpp b/clang/lib/AST/Interp/Pointer.cpp
index f1f7a27c1400d..466e61666c76e 100644
--- a/clang/lib/AST/Interp/Pointer.cpp
+++ b/clang/lib/AST/Interp/Pointer.cpp
@@ -413,7 +413,7 @@ void Pointer::activate() const {
}
Pointer B = getBase();
- while (!B.getFieldDesc()->isUnion()) {
+ while (!B.isRoot() && B.inUnion()) {
// FIXME: Need to de-activate other fields of parent records.
B.getInlineDesc()->IsActive = true;
assert(B.isActive());
diff --git a/clang/test/AST/Interp/unions.cpp b/clang/test/AST/Interp/unions.cpp
index b0b279831405d..a51f30cd9185b 100644
--- a/clang/test/AST/Interp/unions.cpp
+++ b/clang/test/AST/Interp/unions.cpp
@@ -198,4 +198,59 @@ namespace UnionMemberDtor {
}
static_assert(foo() == 100);
}
+
+namespace Nested {
+ union U {
+ int a;
+ int b;
+ };
+
+ union U2 {
+ U u;
+ U u2;
+ int x;
+ int y;
+ };
+
+ constexpr int foo() { // ref-error {{constexpr function never produces a constant expression}}
+ U2 u;
+ u.u.a = 10;
+ int a = u.y; // both-note {{read of member 'y' of union with active member 'u' is not allowed in a constant expression}} \
+ // ref-note {{read of member 'y' of union with active member 'u' is not allowed in a constant expression}}
+
+ return 1;
+ }
+ static_assert(foo() == 1); // both-error {{not an integral constant expression}} \
+ // both-note {{in call to}}
+
+ constexpr int foo2() {
+ U2 u;
+ u.u.a = 10;
+ return u.u.a;
+ }
+ static_assert(foo2() == 10);
+
+ constexpr int foo3() { // ref-error {{constexpr function never produces a constant expression}}
+ U2 u;
+ u.u.a = 10;
+ int a = u.u.b; // both-note {{read of member 'b' of union with active member 'a' is not allowed in a constant expression}} \
+ // ref-note {{read of member 'b' of union with active member 'a' is not allowed in a constant expression}}
+
+ return 1;
+ }
+ static_assert(foo3() == 1); // both-error {{not an integral constant expression}} \
+ // both-note {{in call to}}
+
+ constexpr int foo4() { // ref-error {{constexpr function never produces a constant expression}}
+ U2 u;
+
+ u.x = 10;
+
+ return u.u.a;// both-note {{read of member 'u' of union with active member 'x' is not allowed in a constant expression}} \
+ // ref-note {{read of member 'u' of union with active member 'x' is not allowed in a constant expression}}
+ }
+ static_assert(foo4() == 1); // both-error {{not an integral constant expression}} \
+ // both-note {{in call to}}
+
+}
#endif
More information about the cfe-commits
mailing list