[clang] [clang][Interp] Handle union copy/move ctors (PR #102762)
via cfe-commits
cfe-commits at lists.llvm.org
Sat Aug 10 10:12:28 PDT 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: Timm Baeder (tbaederr)
<details>
<summary>Changes</summary>
They don't have a body and we need to implement them ourselves. Use the Memcpy op to do that.
---
Full diff: https://github.com/llvm/llvm-project/pull/102762.diff
3 Files Affected:
- (modified) clang/lib/AST/Interp/Compiler.cpp (+16)
- (modified) clang/lib/AST/Interp/InterpBuiltin.cpp (+21-5)
- (modified) clang/test/AST/Interp/unions.cpp (+11)
``````````diff
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
``````````
</details>
https://github.com/llvm/llvm-project/pull/102762
More information about the cfe-commits
mailing list