[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