[clang] 496b224 - [clang][Interp] Handle union copy/move ctors (#102762)

via cfe-commits cfe-commits at lists.llvm.org
Sat Aug 10 10:54:10 PDT 2024


Author: Timm Baeder
Date: 2024-08-10T19:54:07+02:00
New Revision: 496b224dc2fabe7c9f72e02fb5096f2b0fdd9e9b

URL: https://github.com/llvm/llvm-project/commit/496b224dc2fabe7c9f72e02fb5096f2b0fdd9e9b
DIFF: https://github.com/llvm/llvm-project/commit/496b224dc2fabe7c9f72e02fb5096f2b0fdd9e9b.diff

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

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

Added: 
    

Modified: 
    clang/lib/AST/Interp/Compiler.cpp
    clang/lib/AST/Interp/InterpBuiltin.cpp
    clang/test/AST/Interp/unions.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/AST/Interp/Compiler.cpp b/clang/lib/AST/Interp/Compiler.cpp
index 5bed71392740e..ad1a2f96b9590 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 d7538c76e91d9..1841a2a4714d8 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 4607df6c1d644..4c60c2c0810d4 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