aboutsummaryrefslogtreecommitdiff
path: root/clang
diff options
context:
space:
mode:
authorTimm Baeder <tbaeder@redhat.com>2025-07-23 05:28:37 +0200
committerGitHub <noreply@github.com>2025-07-23 05:28:37 +0200
commit01b47eb86c991f88d3117f494ebd1826fd3ab41e (patch)
tree707102933bbe62bf4184616d03c1f6b90ceb4876 /clang
parenteb0c863c447bf2ad4d35cfde39925a655c060fa5 (diff)
downloadllvm-01b47eb86c991f88d3117f494ebd1826fd3ab41e.zip
llvm-01b47eb86c991f88d3117f494ebd1826fd3ab41e.tar.gz
llvm-01b47eb86c991f88d3117f494ebd1826fd3ab41e.tar.bz2
[clang][bytecode] Only implicitly start lifetime of trivially-default-constructible union members (#149835)
See https://github.com/llvm/llvm-project/commit/faee39baa87e43f4b746dd77e479268391163658
Diffstat (limited to 'clang')
-rw-r--r--clang/lib/AST/ByteCode/Compiler.cpp9
-rw-r--r--clang/test/AST/ByteCode/unions.cpp55
2 files changed, 63 insertions, 1 deletions
diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp
index 07efd6f8..e760055 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -25,11 +25,18 @@ using APSInt = llvm::APSInt;
namespace clang {
namespace interp {
+static bool hasTrivialDefaultCtorParent(const FieldDecl *FD) {
+ assert(FD);
+ assert(FD->getParent()->isUnion());
+ const auto *CXXRD = dyn_cast<CXXRecordDecl>(FD->getParent());
+ return !CXXRD || CXXRD->hasTrivialDefaultConstructor();
+}
+
static bool refersToUnion(const Expr *E) {
for (;;) {
if (const auto *ME = dyn_cast<MemberExpr>(E)) {
if (const auto *FD = dyn_cast<FieldDecl>(ME->getMemberDecl());
- FD && FD->getParent()->isUnion())
+ FD && FD->getParent()->isUnion() && hasTrivialDefaultCtorParent(FD))
return true;
E = ME->getBase();
continue;
diff --git a/clang/test/AST/ByteCode/unions.cpp b/clang/test/AST/ByteCode/unions.cpp
index 7cfd0d6..ae71776 100644
--- a/clang/test/AST/ByteCode/unions.cpp
+++ b/clang/test/AST/ByteCode/unions.cpp
@@ -861,6 +861,61 @@ namespace CopyCtorMutable {
// both-note {{in call}}
}
+
+namespace NonTrivialCtor {
+ struct A { int x = 1; constexpr int f() { return 1; } };
+ struct B : A { int y = 1; constexpr int g() { return 2; } };
+ struct C {
+ int x;
+ constexpr virtual int f() = 0;
+ };
+ struct D : C {
+ int y;
+ constexpr virtual int f() override { return 3; }
+ };
+
+ union U {
+ int n;
+ B b;
+ D d;
+ };
+
+ consteval int test(int which) {
+ if (which == 0) {}
+
+ U u{.n = 5};
+ assert_active(u);
+ assert_active(u.n);
+ assert_inactive(u.b);
+
+ switch (which) {
+ case 0:
+ u.b.x = 10; // both-note {{assignment to member 'b' of union with active member 'n'}}
+ return u.b.f();
+ case 1:
+ u.b.y = 10; // both-note {{assignment to member 'b' of union with active member 'n'}}
+ return u.b.g();
+ case 2:
+ u.d.x = 10; // both-note {{assignment to member 'd' of union with active member 'n'}}
+ return u.d.f();
+ case 3:
+ u.d.y = 10; // both-note {{assignment to member 'd' of union with active member 'n'}}
+ return u.d.f();
+ }
+
+ return 1;
+ }
+ static_assert(test(0)); // both-error {{not an integral constant expression}} \
+ // both-note {{in call}}
+ static_assert(test(1)); // both-error {{not an integral constant expression}} \
+ // both-note {{in call}}
+ static_assert(test(2)); // both-error {{not an integral constant expression}} \
+ // both-note {{in call}}
+ static_assert(test(3)); // both-error {{not an integral constant expression}} \
+ // both-note {{in call}}
+
+}
+
#endif
namespace AddressComparison {