[clang] [clang][Interp] Handle union copy/move ctors (PR #102762)

Timm Baeder via cfe-commits cfe-commits at lists.llvm.org
Sat Aug 10 10:12:02 PDT 2024


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

They don't have a body and we need to implement them ourselves. Use the Memcpy op to do that.

>From 7c0b32dd559dd5a42ae72d8546c179565be6afc0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbaeder at redhat.com>
Date: Sat, 10 Aug 2024 18:47:59 +0200
Subject: [PATCH] [clang][Interp] Handle union copy/move ctors

They don't have a body and we need to implement them ourselves.
Use the Memcpy op to do that.
---
 clang/lib/AST/Interp/Compiler.cpp      | 16 ++++++++++++++++
 clang/lib/AST/Interp/InterpBuiltin.cpp | 26 +++++++++++++++++++++-----
 clang/test/AST/Interp/unions.cpp       | 11 +++++++++++
 3 files changed, 48 insertions(+), 5 deletions(-)

diff --git a/clang/lib/AST/Interp/Compiler.cpp b/clang/lib/AST/Interp/Compiler.cpp
index 5bed71392740eb..ad1a2f96b95903 100644
--- a/clang/lib/AST/Interp/Compiler.cpp
+++ b/clang/lib/AST/Interp/Compiler.cpp
@@ -4775,6 +4775,22 @@ bool Compiler<Emitter>::visitFunc(const FunctionDecl *F) {
     if (!R)
       return false;
 
+    if (R->isUnion() && Ctor->isCopyOrMoveConstructor()) {
+      // union copy and move ctors are special.
+      assert(cast<CompoundStmt>(Ctor->getBody())->body_empty());
+      if (!this->emitThis(Ctor))
+        return false;
+
+      auto PVD = Ctor->getParamDecl(0);
+      ParamOffset PO = this->Params[PVD]; // Must exist.
+
+      if (!this->emitGetParam(PT_Ptr, PO.Offset, Ctor))
+        return false;
+
+      return this->emitMemcpy(Ctor) && this->emitPopPtr(Ctor) &&
+             this->emitRetVoid(Ctor);
+    }
+
     InitLinkScope<Emitter> InitScope(this, InitLink::This());
     for (const auto *Init : Ctor->inits()) {
       // Scope needed for the initializers.
diff --git a/clang/lib/AST/Interp/InterpBuiltin.cpp b/clang/lib/AST/Interp/InterpBuiltin.cpp
index d7538c76e91d92..1841a2a4714d89 100644
--- a/clang/lib/AST/Interp/InterpBuiltin.cpp
+++ b/clang/lib/AST/Interp/InterpBuiltin.cpp
@@ -1658,18 +1658,34 @@ bool DoMemcpy(InterpState &S, CodePtr OpPC, const Pointer &Src, Pointer &Dest) {
   }
 
   if (DestDesc->isRecord()) {
-    assert(SrcDesc->isRecord());
-    assert(SrcDesc->ElemRecord == DestDesc->ElemRecord);
-    const Record *R = DestDesc->ElemRecord;
-    for (const Record::Field &F : R->fields()) {
+    auto copyField = [&](const Record::Field &F, bool Activate) -> bool {
       Pointer DestField = Dest.atField(F.Offset);
       if (std::optional<PrimType> FT = S.Ctx.classify(F.Decl->getType())) {
         TYPE_SWITCH(*FT, {
           DestField.deref<T>() = Src.atField(F.Offset).deref<T>();
           DestField.initialize();
+          if (Activate)
+            DestField.activate();
         });
+        return true;
+      }
+      return Invalid(S, OpPC);
+    };
+
+    assert(SrcDesc->isRecord());
+    assert(SrcDesc->ElemRecord == DestDesc->ElemRecord);
+    const Record *R = DestDesc->ElemRecord;
+    for (const Record::Field &F : R->fields()) {
+      if (R->isUnion()) {
+        // For unions, only copy the active field.
+        const Pointer &SrcField = Src.atField(F.Offset);
+        if (SrcField.isActive()) {
+          if (!copyField(F, /*Activate=*/true))
+            return false;
+        }
       } else {
-        return Invalid(S, OpPC);
+        if (!copyField(F, /*Activate=*/false))
+          return false;
       }
     }
     return true;
diff --git a/clang/test/AST/Interp/unions.cpp b/clang/test/AST/Interp/unions.cpp
index 4607df6c1d6444..4c60c2c0810d4c 100644
--- a/clang/test/AST/Interp/unions.cpp
+++ b/clang/test/AST/Interp/unions.cpp
@@ -346,5 +346,16 @@ namespace IndirectField {
   static_assert(s2.f == 7, "");
 }
 
+namespace CopyCtor {
+  union U {
+    int a;
+    int b;
+  };
 
+  constexpr U x = {42};
+  constexpr U y = x;
+  static_assert(y.a == 42, "");
+  static_assert(y.b == 42, ""); // both-error {{constant expression}} \
+                                // both-note {{'b' of union with active member 'a'}}
+}
 #endif



More information about the cfe-commits mailing list