[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