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