https://github.com/tbaederr created 
https://github.com/llvm/llvm-project/pull/147338

When activating the new pointer, we need to de-activate pointers of all parent 
unions, not just the topmost one.

>From 2e4627dbde65aecbde9080c0edff5805d2c60890 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbae...@redhat.com>
Date: Mon, 7 Jul 2025 18:06:04 +0200
Subject: [PATCH] [clang][bytecode] Fix activating nested unions

When activating the new pointer, we need to de-activate pointers of
all parent unions, not just the topmost one.
---
 clang/lib/AST/ByteCode/Pointer.cpp | 36 ++++++++++--------------
 clang/test/AST/ByteCode/cxx23.cpp  | 45 ++++++++++++++++++++++++++++++
 2 files changed, 59 insertions(+), 22 deletions(-)

diff --git a/clang/lib/AST/ByteCode/Pointer.cpp 
b/clang/lib/AST/ByteCode/Pointer.cpp
index e915316272178..3ddae950926a0 100644
--- a/clang/lib/AST/ByteCode/Pointer.cpp
+++ b/clang/lib/AST/ByteCode/Pointer.cpp
@@ -525,33 +525,25 @@ void Pointer::activate() const {
   Pointer UnionPtr = getBase();
   while (!UnionPtr.isRoot() && UnionPtr.inUnion())
     UnionPtr = UnionPtr.getBase();
-
   assert(UnionPtr.getFieldDesc()->isUnion());
-  const Record *UnionRecord = UnionPtr.getRecord();
-
-  // The direct child pointer of the union that's on the path from
-  // this pointer to the union.
-  Pointer ChildPtr = *this;
-  assert(ChildPtr != UnionPtr);
-  while (true) {
-    if (ChildPtr.getBase() == UnionPtr)
-      break;
-    ChildPtr = ChildPtr.getBase();
-  }
-  assert(ChildPtr.getBase() == UnionPtr);
-
-  for (const Record::Field &F : UnionRecord->fields()) {
-    Pointer FieldPtr = UnionPtr.atField(F.Offset);
-    if (FieldPtr == ChildPtr) {
-      // No need to deactivate, will be activated in the next loop.
-    } else {
-      deactivate(FieldPtr);
-    }
-  }
 
   Pointer B = *this;
   while (B != UnionPtr) {
     activate(B);
+
+    // When walking up the pointer chain, deactivate
+    // all union child pointers that aren't on our path.
+    if (!B.isRoot()) {
+      Pointer BasePtr = B.getBase();
+      if (const Record *BR = BasePtr.getRecord(); BR && BR->isUnion()) {
+        for (const Record::Field &F : BR->fields()) {
+          Pointer FieldPtr = BasePtr.atField(F.Offset);
+          if (FieldPtr != B)
+            deactivate(FieldPtr);
+        }
+      }
+    }
+
     B = B.getBase();
   }
 }
diff --git a/clang/test/AST/ByteCode/cxx23.cpp 
b/clang/test/AST/ByteCode/cxx23.cpp
index 417d35dbca946..2856b872d44ab 100644
--- a/clang/test/AST/ByteCode/cxx23.cpp
+++ b/clang/test/AST/ByteCode/cxx23.cpp
@@ -4,6 +4,16 @@
 // RUN: %clang_cc1 -std=c++20 -fsyntax-only -fcxx-exceptions 
-verify=expected20,all,all20 %s -fexperimental-new-constant-interpreter
 // RUN: %clang_cc1 -std=c++23 -fsyntax-only -fcxx-exceptions 
-verify=expected23,all,all23 %s -fexperimental-new-constant-interpreter
 
+
+#define assert_active(F)   if (!__builtin_is_within_lifetime(&F)) (1/0);
+#define assert_inactive(F) if ( __builtin_is_within_lifetime(&F)) (1/0);
+
+inline constexpr void* operator new(__SIZE_TYPE__, void* p) noexcept { return 
p; }
+namespace std {
+template<typename T, typename... Args>
+constexpr T* construct_at(T* p, Args&&... args) { return ::new((void*)p) 
T(static_cast<Args&&>(args)...); }
+}
+
 constexpr int f(int n) {  // all20-error {{constexpr function never produces a 
constant expression}}
   static const int m = n; // all-note {{control flows through the definition 
of a static variable}} \
                           // all20-note {{control flows through the definition 
of a static variable}} \
@@ -328,3 +338,38 @@ namespace VoidCast {
   constexpr int *f = (int*)(void*)b; // all-error {{must be initialized by a 
constant expression}} \
                                      // all-note {{cast from 'void *' is not 
allowed in a constant expression}}
 }
+
+#if __cplusplus >= 202302L
+namespace NestedUnions {
+  consteval bool test_nested() {
+    union {
+      union { int i; char c; } u;
+      long l;
+    };
+    std::construct_at(&l);
+    assert_active(l);
+    assert_inactive(u);
+
+    std::construct_at(&u);
+    assert_active(u);
+    assert_inactive(l);
+    assert_active(u.i);
+    assert_inactive(u.c);
+
+    std::construct_at(&u.i);
+    assert_active(u);
+    assert_inactive(u.c);
+
+
+    std::construct_at(&u.c);
+    assert_active(u);
+    assert_inactive(u.i);
+    assert_active(u.c);
+    assert_inactive(l);
+    return true;
+  }
+  static_assert(test_nested());
+
+
+}
+#endif

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to