[clang] [Clang][NFC] Refactor operator delete argument handling (PR #160554)
Andy Kaylor via cfe-commits
cfe-commits at lists.llvm.org
Wed Oct 1 14:01:56 PDT 2025
https://github.com/andykaylor updated https://github.com/llvm/llvm-project/pull/160554
>From ade6f590cac752c996b3c765c84a86a9867185c6 Mon Sep 17 00:00:00 2001
From: Andy Kaylor <akaylor at nvidia.com>
Date: Tue, 23 Sep 2025 17:09:29 -0700
Subject: [PATCH 1/3] [Clang][NFC] Refactor operator delete argument handling
This change moves the getUsualDeleteParams function into the FunctionDecl
class so that it can be shared between LLVM IR and CIR codegen. It also
renames the function and associated structure to better reflect its use.
---
clang/include/clang/AST/Decl.h | 3 ++
clang/include/clang/AST/ExprCXX.h | 8 +++++
clang/lib/AST/Decl.cpp | 47 +++++++++++++++++++++++++
clang/lib/CodeGen/CGExprCXX.cpp | 58 ++-----------------------------
4 files changed, 61 insertions(+), 55 deletions(-)
diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h
index d85d04d2a4d53..6894877ab5adf 100644
--- a/clang/include/clang/AST/Decl.h
+++ b/clang/include/clang/AST/Decl.h
@@ -80,6 +80,7 @@ class TypeAliasTemplateDecl;
class UnresolvedSetImpl;
class VarTemplateDecl;
enum class ImplicitParamKind;
+struct DeleteParamInfo;
// Holds a constraint expression along with a pack expansion index, if
// expanded.
@@ -2646,6 +2647,8 @@ class FunctionDecl : public DeclaratorDecl,
bool isTypeAwareOperatorNewOrDelete() const;
void setIsTypeAwareOperatorNewOrDelete(bool IsTypeAwareOperator = true);
+ DeleteParamInfo getDeleteParamInfo() const;
+
/// Compute the language linkage.
LanguageLinkage getLanguageLinkage() const;
diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h
index 5f16bac94d5e6..fec726ac96a63 100644
--- a/clang/include/clang/AST/ExprCXX.h
+++ b/clang/include/clang/AST/ExprCXX.h
@@ -2342,6 +2342,14 @@ struct ImplicitDeallocationParameters {
SizedDeallocationMode PassSize;
};
+/// The parameters to pass to a usual operator delete.
+struct DeleteParamInfo {
+ TypeAwareAllocationMode TypeAwareDelete = TypeAwareAllocationMode::No;
+ bool DestroyingDelete = false;
+ bool Size = false;
+ AlignedAllocationMode Alignment = AlignedAllocationMode::No;
+};
+
/// Represents a new-expression for memory allocation and constructor
/// calls, e.g: "new CXXNewExpr(foo)".
class CXXNewExpr final
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index cd8e495e82c80..f7b80eb244191 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -3552,6 +3552,53 @@ void FunctionDecl::setIsTypeAwareOperatorNewOrDelete(bool IsTypeAware) {
getASTContext().setIsTypeAwareOperatorNewOrDelete(this, IsTypeAware);
}
+DeleteParamInfo FunctionDecl::getDeleteParamInfo() const {
+ DeleteParamInfo Params;
+
+ // This function should only be called for operator delete declarations.
+ assert(getDeclName().isAnyOperatorDelete());
+ if (!getDeclName().isAnyOperatorDelete())
+ return Params;
+
+ const FunctionProtoType *FPT = getType()->castAs<FunctionProtoType>();
+ auto AI = FPT->param_type_begin(), AE = FPT->param_type_end();
+
+ if (isTypeAwareOperatorNewOrDelete()) {
+ Params.TypeAwareDelete = TypeAwareAllocationMode::Yes;
+ assert(AI != AE);
+ ++AI;
+ }
+
+ // The first argument after the type-identity parameter (if any) is
+ // always a void* (or C* for a destroying operator delete for class
+ // type C).
+ ++AI;
+
+ // The next parameter may be a std::destroying_delete_t.
+ if (isDestroyingOperatorDelete()) {
+ assert(!isTypeAwareAllocation(Params.TypeAwareDelete));
+ Params.DestroyingDelete = true;
+ assert(AI != AE);
+ ++AI;
+ }
+
+ // Figure out what other parameters we should be implicitly passing.
+ if (AI != AE && (*AI)->isIntegerType()) {
+ Params.Size = true;
+ ++AI;
+ } else
+ assert(!isTypeAwareAllocation(Params.TypeAwareDelete));
+
+ if (AI != AE && (*AI)->isAlignValT()) {
+ Params.Alignment = AlignedAllocationMode::Yes;
+ ++AI;
+ } else
+ assert(!isTypeAwareAllocation(Params.TypeAwareDelete));
+
+ assert(AI == AE && "unexpected usual deallocation function parameter");
+ return Params;
+}
+
LanguageLinkage FunctionDecl::getLanguageLinkage() const {
return getDeclLanguageLinkage(*this);
}
diff --git a/clang/lib/CodeGen/CGExprCXX.cpp b/clang/lib/CodeGen/CGExprCXX.cpp
index a092b718412be..349319a571442 100644
--- a/clang/lib/CodeGen/CGExprCXX.cpp
+++ b/clang/lib/CodeGen/CGExprCXX.cpp
@@ -1376,58 +1376,6 @@ RValue CodeGenFunction::EmitBuiltinNewDeleteCall(const FunctionProtoType *Type,
llvm_unreachable("predeclared global operator new/delete is missing");
}
-namespace {
-/// The parameters to pass to a usual operator delete.
-struct UsualDeleteParams {
- TypeAwareAllocationMode TypeAwareDelete = TypeAwareAllocationMode::No;
- bool DestroyingDelete = false;
- bool Size = false;
- AlignedAllocationMode Alignment = AlignedAllocationMode::No;
-};
-}
-
-static UsualDeleteParams getUsualDeleteParams(const FunctionDecl *FD) {
- UsualDeleteParams Params;
-
- const FunctionProtoType *FPT = FD->getType()->castAs<FunctionProtoType>();
- auto AI = FPT->param_type_begin(), AE = FPT->param_type_end();
-
- if (FD->isTypeAwareOperatorNewOrDelete()) {
- Params.TypeAwareDelete = TypeAwareAllocationMode::Yes;
- assert(AI != AE);
- ++AI;
- }
-
- // The first argument after the type-identity parameter (if any) is
- // always a void* (or C* for a destroying operator delete for class
- // type C).
- ++AI;
-
- // The next parameter may be a std::destroying_delete_t.
- if (FD->isDestroyingOperatorDelete()) {
- assert(!isTypeAwareAllocation(Params.TypeAwareDelete));
- Params.DestroyingDelete = true;
- assert(AI != AE);
- ++AI;
- }
-
- // Figure out what other parameters we should be implicitly passing.
- if (AI != AE && (*AI)->isIntegerType()) {
- Params.Size = true;
- ++AI;
- } else
- assert(!isTypeAwareAllocation(Params.TypeAwareDelete));
-
- if (AI != AE && (*AI)->isAlignValT()) {
- Params.Alignment = AlignedAllocationMode::Yes;
- ++AI;
- } else
- assert(!isTypeAwareAllocation(Params.TypeAwareDelete));
-
- assert(AI == AE && "unexpected usual deallocation function parameter");
- return Params;
-}
-
namespace {
/// A cleanup to call the given 'operator delete' function upon abnormal
/// exit from a new expression. Templated on a traits type that deals with
@@ -1494,7 +1442,7 @@ namespace {
DeleteArgs.add(Traits::get(CGF, Ptr), FPT->getParamType(FirstNonTypeArg));
// Figure out what other parameters we should be implicitly passing.
- UsualDeleteParams Params;
+ DeleteParamInfo Params;
if (NumPlacementArgs) {
// A placement deallocation function is implicitly passed an alignment
// if the placement allocation function was, but is never passed a size.
@@ -1505,7 +1453,7 @@ namespace {
} else {
// For a non-placement new-expression, 'operator delete' can take a
// size and/or an alignment if it has the right parameters.
- Params = getUsualDeleteParams(OperatorDelete);
+ Params = OperatorDelete->getDeleteParamInfo();
}
assert(!Params.DestroyingDelete &&
@@ -1838,7 +1786,7 @@ void CodeGenFunction::EmitDeleteCall(const FunctionDecl *DeleteFD,
const auto *DeleteFTy = DeleteFD->getType()->castAs<FunctionProtoType>();
CallArgList DeleteArgs;
- auto Params = getUsualDeleteParams(DeleteFD);
+ auto Params = DeleteFD->getDeleteParamInfo();
auto ParamTypeIt = DeleteFTy->param_type_begin();
std::optional<llvm::AllocaInst *> TagAlloca;
>From 3c185db087d0d16a13fb0f49eb3fd14b744ac7df Mon Sep 17 00:00:00 2001
From: Andy Kaylor <akaylor at nvidia.com>
Date: Wed, 24 Sep 2025 15:55:57 -0700
Subject: [PATCH 2/3] Restore original struct and function name
---
clang/include/clang/AST/Decl.h | 4 ++--
clang/include/clang/AST/ExprCXX.h | 2 +-
clang/lib/AST/Decl.cpp | 4 ++--
clang/lib/CodeGen/CGExprCXX.cpp | 6 +++---
4 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h
index 6894877ab5adf..406d79ebd6641 100644
--- a/clang/include/clang/AST/Decl.h
+++ b/clang/include/clang/AST/Decl.h
@@ -80,7 +80,7 @@ class TypeAliasTemplateDecl;
class UnresolvedSetImpl;
class VarTemplateDecl;
enum class ImplicitParamKind;
-struct DeleteParamInfo;
+struct UsualDeleteParams;
// Holds a constraint expression along with a pack expansion index, if
// expanded.
@@ -2647,7 +2647,7 @@ class FunctionDecl : public DeclaratorDecl,
bool isTypeAwareOperatorNewOrDelete() const;
void setIsTypeAwareOperatorNewOrDelete(bool IsTypeAwareOperator = true);
- DeleteParamInfo getDeleteParamInfo() const;
+ UsualDeleteParams getUsualDeleteParams() const;
/// Compute the language linkage.
LanguageLinkage getLanguageLinkage() const;
diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h
index fec726ac96a63..d78c7b6363b5d 100644
--- a/clang/include/clang/AST/ExprCXX.h
+++ b/clang/include/clang/AST/ExprCXX.h
@@ -2343,7 +2343,7 @@ struct ImplicitDeallocationParameters {
};
/// The parameters to pass to a usual operator delete.
-struct DeleteParamInfo {
+struct UsualDeleteParams {
TypeAwareAllocationMode TypeAwareDelete = TypeAwareAllocationMode::No;
bool DestroyingDelete = false;
bool Size = false;
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index f7b80eb244191..c7341552be365 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -3552,8 +3552,8 @@ void FunctionDecl::setIsTypeAwareOperatorNewOrDelete(bool IsTypeAware) {
getASTContext().setIsTypeAwareOperatorNewOrDelete(this, IsTypeAware);
}
-DeleteParamInfo FunctionDecl::getDeleteParamInfo() const {
- DeleteParamInfo Params;
+UsualDeleteParams FunctionDecl::getUsualDeleteParams() const {
+ UsualDeleteParams Params;
// This function should only be called for operator delete declarations.
assert(getDeclName().isAnyOperatorDelete());
diff --git a/clang/lib/CodeGen/CGExprCXX.cpp b/clang/lib/CodeGen/CGExprCXX.cpp
index 349319a571442..c52526c89f171 100644
--- a/clang/lib/CodeGen/CGExprCXX.cpp
+++ b/clang/lib/CodeGen/CGExprCXX.cpp
@@ -1442,7 +1442,7 @@ namespace {
DeleteArgs.add(Traits::get(CGF, Ptr), FPT->getParamType(FirstNonTypeArg));
// Figure out what other parameters we should be implicitly passing.
- DeleteParamInfo Params;
+ UsualDeleteParams Params;
if (NumPlacementArgs) {
// A placement deallocation function is implicitly passed an alignment
// if the placement allocation function was, but is never passed a size.
@@ -1453,7 +1453,7 @@ namespace {
} else {
// For a non-placement new-expression, 'operator delete' can take a
// size and/or an alignment if it has the right parameters.
- Params = OperatorDelete->getDeleteParamInfo();
+ Params = OperatorDelete->getUsualDeleteParams();
}
assert(!Params.DestroyingDelete &&
@@ -1786,7 +1786,7 @@ void CodeGenFunction::EmitDeleteCall(const FunctionDecl *DeleteFD,
const auto *DeleteFTy = DeleteFD->getType()->castAs<FunctionProtoType>();
CallArgList DeleteArgs;
- auto Params = DeleteFD->getDeleteParamInfo();
+ auto Params = DeleteFD->getUsualDeleteParams();
auto ParamTypeIt = DeleteFTy->param_type_begin();
std::optional<llvm::AllocaInst *> TagAlloca;
>From 8dfdcb1b05720748de7e0f7b750e2e2c3cb2b31f Mon Sep 17 00:00:00 2001
From: Andy Kaylor <akaylor at nvidia.com>
Date: Wed, 1 Oct 2025 13:09:09 -0700
Subject: [PATCH 3/3] Update CIR's emitDeleteCall
---
clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp | 64 ++-----------------------
1 file changed, 5 insertions(+), 59 deletions(-)
diff --git a/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp b/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp
index 83208bf226882..7989ad2e30f17 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp
@@ -210,60 +210,6 @@ RValue CIRGenFunction::emitCXXMemberOrOperatorCall(
return emitCall(fnInfo, callee, returnValue, args, nullptr, loc);
}
-namespace {
-/// The parameters to pass to a usual operator delete.
-struct UsualDeleteParams {
- TypeAwareAllocationMode typeAwareDelete = TypeAwareAllocationMode::No;
- bool destroyingDelete = false;
- bool size = false;
- AlignedAllocationMode alignment = AlignedAllocationMode::No;
-};
-} // namespace
-
-// FIXME(cir): this should be shared with LLVM codegen
-static UsualDeleteParams getUsualDeleteParams(const FunctionDecl *fd) {
- UsualDeleteParams params;
-
- const FunctionProtoType *fpt = fd->getType()->castAs<FunctionProtoType>();
- auto ai = fpt->param_type_begin(), ae = fpt->param_type_end();
-
- if (fd->isTypeAwareOperatorNewOrDelete()) {
- params.typeAwareDelete = TypeAwareAllocationMode::Yes;
- assert(ai != ae);
- ++ai;
- }
-
- // The first argument after the type-identity parameter (if any) is
- // always a void* (or C* for a destroying operator delete for class
- // type C).
- ++ai;
-
- // The next parameter may be a std::destroying_delete_t.
- if (fd->isDestroyingOperatorDelete()) {
- params.destroyingDelete = true;
- assert(ai != ae);
- ++ai;
- }
-
- // Figure out what other parameters we should be implicitly passing.
- if (ai != ae && (*ai)->isIntegerType()) {
- params.size = true;
- ++ai;
- } else {
- assert(!isTypeAwareAllocation(params.typeAwareDelete));
- }
-
- if (ai != ae && (*ai)->isAlignValT()) {
- params.alignment = AlignedAllocationMode::Yes;
- ++ai;
- } else {
- assert(!isTypeAwareAllocation(params.typeAwareDelete));
- }
-
- assert(ai == ae && "unexpected usual deallocation function parameter");
- return params;
-}
-
static mlir::Value emitCXXNewAllocSize(CIRGenFunction &cgf, const CXXNewExpr *e,
unsigned minElements,
mlir::Value &numElements,
@@ -616,11 +562,11 @@ void CIRGenFunction::emitDeleteCall(const FunctionDecl *deleteFD,
const auto *deleteFTy = deleteFD->getType()->castAs<FunctionProtoType>();
CallArgList deleteArgs;
- UsualDeleteParams params = getUsualDeleteParams(deleteFD);
+ UsualDeleteParams params = deleteFD->getUsualDeleteParams();
auto paramTypeIt = deleteFTy->param_type_begin();
// Pass std::type_identity tag if present
- if (isTypeAwareAllocation(params.typeAwareDelete))
+ if (isTypeAwareAllocation(params.TypeAwareDelete))
cgm.errorNYI(deleteFD->getSourceRange(),
"emitDeleteCall: type aware delete");
@@ -631,12 +577,12 @@ void CIRGenFunction::emitDeleteCall(const FunctionDecl *deleteFD,
deleteArgs.add(RValue::get(deletePtr), argTy);
// Pass the std::destroying_delete tag if present.
- if (params.destroyingDelete)
+ if (params.DestroyingDelete)
cgm.errorNYI(deleteFD->getSourceRange(),
"emitDeleteCall: destroying delete");
// Pass the size if the delete function has a size_t parameter.
- if (params.size) {
+ if (params.Size) {
QualType sizeType = *paramTypeIt++;
CharUnits deleteTypeSize = getContext().getTypeSizeInChars(deleteTy);
assert(mlir::isa<cir::IntType>(convertType(sizeType)) &&
@@ -648,7 +594,7 @@ void CIRGenFunction::emitDeleteCall(const FunctionDecl *deleteFD,
}
// Pass the alignment if the delete function has an align_val_t parameter.
- if (isAlignedAllocation(params.alignment))
+ if (isAlignedAllocation(params.Alignment))
cgm.errorNYI(deleteFD->getSourceRange(),
"emitDeleteCall: aligned allocation");
More information about the cfe-commits
mailing list