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

>From 8b42dbd7659ce5e424fb107a0d375f449a8d44a9 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 | 42 ++++++++--------------------
 clang/test/AST/ByteCode/cxx23.cpp  | 45 ++++++++++++++++++++++++++++++
 2 files changed, 57 insertions(+), 30 deletions(-)

diff --git a/clang/lib/AST/ByteCode/Pointer.cpp 
b/clang/lib/AST/ByteCode/Pointer.cpp
index e915316272178..6769e51a8ad00 100644
--- a/clang/lib/AST/ByteCode/Pointer.cpp
+++ b/clang/lib/AST/ByteCode/Pointer.cpp
@@ -520,39 +520,21 @@ void Pointer::activate() const {
     }
   };
 
-  // Unions might be nested etc., so find the topmost Pointer that's
-  // not in a union anymore.
-  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) {
+  while (!B.isRoot() && B.inUnion()) {
     activate(B);
+
+    // When walking up the pointer chain, deactivate
+    // all union child pointers that aren't on our path.
+    Pointer Cur = B;
     B = B.getBase();
+    if (const Record *BR = B.getRecord(); BR && BR->isUnion()) {
+      for (const Record::Field &F : BR->fields()) {
+        Pointer FieldPtr = B.atField(F.Offset);
+        if (FieldPtr != Cur)
+          deactivate(FieldPtr);
+      }
+    }
   }
 }
 
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