[clang] [CIR] Inline trivial copy/move assignment at call sites (PR #198918)
via cfe-commits
cfe-commits at lists.llvm.org
Tue Jun 16 08:52:13 PDT 2026
================
@@ -901,6 +901,33 @@ void CIRGenFunction::emitImplicitAssignmentOperatorBody(FunctionArgList &args) {
assert(!cir::MissingFeatures::incrementProfileCounter());
assert(!cir::MissingFeatures::runCleanupsScope());
+ // For a memcpy-equivalent special member (a union, or a trivially-copyable
+ // record) the synthesized body either copies nothing -- a union body is just
+ // `return *this` -- or relies on a memcpy the AST does not spell out as
+ // field assignments. Mirror classic CodeGen's AssignmentMemcpyizer: copy
+ // the whole object once, then fall through to emit the trailing
+ // `return *this`. Emitting the copy but skipping the return would leave the
+ // result reference uninitialized.
+ if (assignOp->isMemcpyEquivalentSpecialMember(getContext())) {
+ CanQualType recordTy =
+ getContext().getCanonicalTagType(assignOp->getParent());
+ LValue dest = makeNaturalAlignAddrLValue(loadCXXThis(), recordTy);
+ // The source is the trailing reference parameter; load it to get the
+ // referent's address before copying (mirrors the copy-constructor path).
+ mlir::Value srcPtr = builder.createLoad(getLoc(assignOp->getLocation()),
+ getAddrOfLocalVar(args.back()));
+ LValue src = makeNaturalAlignAddrLValue(srcPtr, recordTy);
+ emitAggregateAssign(dest, src, recordTy);
+
+ for (Stmt *s : rootCS->body())
+ if (isa<ReturnStmt>(s))
+ if (emitStmt(s, /*useCurrentScope=*/true).failed())
+ cgm.errorNYI(s->getSourceRange(),
+ std::string("emitImplicitAssignmentOperatorBody: ") +
+ s->getStmtClassName());
----------------
adams381 wrote:
This does belong in the AST. The union body is empty only because Sema skips union fields at that FIXME, so no front end gets a copy expression to lower. Classic gets away with it by eliding the memcpy-equivalent call at the call site and emitting the memcpy there; the `operator=` body it would generate is also just `return *this`. This PR stopped eliding the call (per earlier review), which is exactly what exposed the empty body.
So instead of reconstructing the copy in CIRGen, I'll implement the FIXME: have Sema form an AST representation for the implied memcpy in union copy and move assignment, so the synthesized body contains it. That fixes classic CodeGen and CIR together and lets this PR drop the whole-object-copy special case.
Since it changes shared AST and will shift classic codegen output (and some existing tests), I'd land it as a separate precursor PR and rebase this one on top. Does that scope sound right before I start?
https://github.com/llvm/llvm-project/pull/198918
More information about the cfe-commits
mailing list