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?= <tbae...@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 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits