llvmbot wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Timm Baeder (tbaederr)

<details>
<summary>Changes</summary>

When activating a union member, none of the unions in that path can have a 
non-trivial constructor. Unfortunately, this is something we have to do when 
evaluating the bytecode, not while compiling it.

---
Full diff: https://github.com/llvm/llvm-project/pull/174745.diff


4 Files Affected:

- (modified) clang/lib/AST/ByteCode/Compiler.cpp (+2-1) 
- (modified) clang/lib/AST/ByteCode/Interp.cpp (+23-2) 
- (modified) clang/lib/AST/ByteCode/Interp.h (+5-5) 
- (modified) clang/test/AST/ByteCode/unions.cpp (+21) 


``````````diff
diff --git a/clang/lib/AST/ByteCode/Compiler.cpp 
b/clang/lib/AST/ByteCode/Compiler.cpp
index b4449def1c6f0..93e80de37ab68 100644
--- a/clang/lib/AST/ByteCode/Compiler.cpp
+++ b/clang/lib/AST/ByteCode/Compiler.cpp
@@ -5570,7 +5570,8 @@ bool Compiler<Emitter>::maybeEmitDeferredVarInit(const 
VarDecl *VD) {
 static bool hasTrivialDefaultCtorParent(const FieldDecl *FD) {
   assert(FD);
   assert(FD->getParent()->isUnion());
-  const auto *CXXRD = dyn_cast<CXXRecordDecl>(FD->getParent());
+  const CXXRecordDecl *CXXRD =
+      FD->getType()->getBaseElementTypeUnsafe()->getAsCXXRecordDecl();
   return !CXXRD || CXXRD->hasTrivialDefaultConstructor();
 }
 
diff --git a/clang/lib/AST/ByteCode/Interp.cpp 
b/clang/lib/AST/ByteCode/Interp.cpp
index 889ac1e1a9a7e..888543bb9c021 100644
--- a/clang/lib/AST/ByteCode/Interp.cpp
+++ b/clang/lib/AST/ByteCode/Interp.cpp
@@ -326,12 +326,13 @@ bool CheckBCPResult(InterpState &S, const Pointer &Ptr) {
 }
 
 bool CheckActive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
-                 AccessKinds AK) {
+                 AccessKinds AK, bool WillActivate) {
   if (Ptr.isActive())
     return true;
 
   assert(Ptr.inUnion());
 
+  // Find the outermost union.
   Pointer U = Ptr.getBase();
   Pointer C = Ptr;
   while (!U.isRoot() && !U.isActive()) {
@@ -346,6 +347,7 @@ bool CheckActive(InterpState &S, CodePtr OpPC, const 
Pointer &Ptr,
     U = U.getBase();
   }
   assert(C.isField());
+  assert(C.getBase() == U);
 
   // Consider:
   // union U {
@@ -362,6 +364,25 @@ bool CheckActive(InterpState &S, CodePtr OpPC, const 
Pointer &Ptr,
   if (!U.getFieldDesc()->isUnion())
     return true;
 
+  // When we will activate Ptr, check that none of the unions in its path have 
a
+  // non-trivial default constructor.
+  if (WillActivate) {
+    bool Fails = false;
+    Pointer It = Ptr;
+    while (!It.isRoot() && !It.isActive()) {
+      if (const Record *R = It.getRecord(); R && R->isUnion()) {
+        if (const auto *CXXRD = dyn_cast<CXXRecordDecl>(R->getDecl());
+            CXXRD && !CXXRD->hasTrivialDefaultConstructor()) {
+          Fails = true;
+          break;
+        }
+      }
+      It = It.getBase();
+    }
+    if (!Fails)
+      return true;
+  }
+
   // Get the inactive field descriptor.
   assert(!C.isActive());
   const FieldDecl *InactiveField = C.getField();
@@ -885,7 +906,7 @@ bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer 
&Ptr,
     return false;
   if (!CheckRange(S, OpPC, Ptr, AK_Assign))
     return false;
-  if (!WillBeActivated && !CheckActive(S, OpPC, Ptr, AK_Assign))
+  if (!CheckActive(S, OpPC, Ptr, AK_Assign, WillBeActivated))
     return false;
   if (!CheckGlobal(S, OpPC, Ptr))
     return false;
diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h
index 155d96fc1652b..7ccd690d22fb7 100644
--- a/clang/lib/AST/ByteCode/Interp.h
+++ b/clang/lib/AST/ByteCode/Interp.h
@@ -94,7 +94,7 @@ bool CheckDeleteSource(InterpState &S, CodePtr OpPC, const 
Expr *Source,
                        const Pointer &Ptr);
 
 bool CheckActive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
-                 AccessKinds AK);
+                 AccessKinds AK, bool WillActivate = false);
 
 /// Sets the given integral value to the pointer, which is of
 /// a std::{weak,partial,strong}_ordering type.
@@ -2017,7 +2017,7 @@ bool StoreActivate(InterpState &S, CodePtr OpPC) {
   const T &Value = S.Stk.pop<T>();
   const Pointer &Ptr = S.Stk.peek<Pointer>();
 
-  if (!CheckStore(S, OpPC, Ptr, /*WilLBeActivated=*/true))
+  if (!CheckStore(S, OpPC, Ptr, /*WillBeActivated=*/true))
     return false;
   if (Ptr.canBeInitialized()) {
     Ptr.initialize();
@@ -2032,7 +2032,7 @@ bool StoreActivatePop(InterpState &S, CodePtr OpPC) {
   const T &Value = S.Stk.pop<T>();
   const Pointer &Ptr = S.Stk.pop<Pointer>();
 
-  if (!CheckStore(S, OpPC, Ptr, /*WilLBeActivated=*/true))
+  if (!CheckStore(S, OpPC, Ptr, /*WillBeActivated=*/true))
     return false;
   if (Ptr.canBeInitialized()) {
     Ptr.initialize();
@@ -2047,7 +2047,7 @@ bool StoreBitField(InterpState &S, CodePtr OpPC) {
   const T &Value = S.Stk.pop<T>();
   const Pointer &Ptr = S.Stk.peek<Pointer>();
 
-  if (!CheckStore(S, OpPC, Ptr, /*WilLBeActivated=*/true))
+  if (!CheckStore(S, OpPC, Ptr))
     return false;
   if (Ptr.canBeInitialized())
     Ptr.initialize();
@@ -2078,7 +2078,7 @@ bool StoreBitFieldActivate(InterpState &S, CodePtr OpPC) {
   const T &Value = S.Stk.pop<T>();
   const Pointer &Ptr = S.Stk.peek<Pointer>();
 
-  if (!CheckStore(S, OpPC, Ptr, /*WilLBeActivated=*/true))
+  if (!CheckStore(S, OpPC, Ptr, /*WillBeActivated=*/true))
     return false;
   if (Ptr.canBeInitialized()) {
     Ptr.initialize();
diff --git a/clang/test/AST/ByteCode/unions.cpp 
b/clang/test/AST/ByteCode/unions.cpp
index 414070417a02a..2123a932fce10 100644
--- a/clang/test/AST/ByteCode/unions.cpp
+++ b/clang/test/AST/ByteCode/unions.cpp
@@ -986,4 +986,25 @@ namespace ActicvateInvalidPtr {
     foo.a[1] = 0; // both-note {{assignment to dereferenced one-past-the-end 
pointer}}
   }
 }
+
+namespace NonTrivialUnionCtor {
+  union A {
+    int y = 5;
+  };
+  union D {
+    constexpr D(int n) : n(n) {}
+    constexpr D() : n(3) {}
+
+    A a;
+    int n;
+  };
+
+  constexpr bool j() {
+    D d;
+    d.a.y = 3; // both-note {{assignment to member 'a' of union with active 
member 'n'}}
+    return d.a.y == 3;
+  }
+  static_assert(j()); // both-error {{not an integral constant expression}} \
+                      // both-note {{in call to}}
+}
 #endif

``````````

</details>


https://github.com/llvm/llvm-project/pull/174745
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to