From 7fb6339ab050b3629fbaf572a3d6968c3737d8f4 Mon Sep 17 00:00:00 2001 From: Aiden Grossman Date: Mon, 3 Nov 2025 22:45:04 +0000 Subject: [PATCH] [Clang] Mark this pointer in destructors dead_on_return This helps to clean up any dead stores that come up at the end of the destructor. The motivating example was a refactoring in libc++'s basic_string implementation in 8dae17be2991cd7f0d7fd9aa5aecd064520a14f6 that added a zeroing store into the destructor, causing a large performance regression on an internal workload. --- clang/lib/CodeGen/CGCall.cpp | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index 465f3f4e670c2..ea4b9a328da63 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -2765,7 +2765,8 @@ void CodeGenModule::ConstructAttributeList(StringRef Name, } // Apply `nonnull`, `dereferenceable(N)` and `align N` to the `this` argument, - // unless this is a thunk function. + // unless this is a thunk function. Add dead_on_return to the `this` argument + // in base class destructors. // FIXME: fix this properly, https://reviews.llvm.org/D100388 if (FI.isInstanceMethod() && !IRFunctionArgs.hasInallocaArg() && !FI.arg_begin()->type->isVoidPointerType() && !IsThunk) { @@ -2798,6 +2799,18 @@ void CodeGenModule::ConstructAttributeList(StringRef Name, .getAsAlign(); Attrs.addAlignmentAttr(Alignment); + if (isa_and_nonnull( + CalleeInfo.getCalleeDecl().getDecl())) { + auto *ClassDecl = dyn_cast( + CalleeInfo.getCalleeDecl().getDecl()->getDeclContext()); + assert( + ClassDecl && + "Expected CXXDestructorDecl to have a CXXRecordDecl as its parent."); + if (ClassDecl->getNumBases() == 0 && ClassDecl->getNumVBases() == 0) { + Attrs.addAttribute(llvm::Attribute::DeadOnReturn); + } + } + ArgAttrs[IRArgs.first] = llvm::AttributeSet::get(getLLVMContext(), Attrs); }