[clang] Ensure type aware allocators handle transparent decl contexts (#138616)

We were testing the immediate DeclContext for found new and delete
operators, which is incorrect if the declarations are contained by a
transparent decl as can be induced with extern or export statements.
This commit is contained in:
Oliver Hunt
2025-05-05 22:39:17 -07:00
committed by GitHub
parent ffc5f79e2a
commit f1985d583d
2 changed files with 56 additions and 8 deletions

View File

@@ -3070,10 +3070,16 @@ bool Sema::FindAllocationFunctions(
Filter.done();
}
auto GetRedeclContext = [](Decl *D) {
return D->getDeclContext()->getRedeclContext();
};
DeclContext *OperatorNewContext = GetRedeclContext(OperatorNew);
bool FoundGlobalDelete = FoundDelete.empty();
bool IsClassScopedTypeAwareNew =
isTypeAwareAllocation(IAP.PassTypeIdentity) &&
OperatorNew->getDeclContext()->isRecord();
OperatorNewContext->isRecord();
auto DiagnoseMissingTypeAwareCleanupOperator = [&](bool IsPlacementOperator) {
assert(isTypeAwareAllocation(IAP.PassTypeIdentity));
if (Diagnose) {
@@ -3081,7 +3087,7 @@ bool Sema::FindAllocationFunctions(
<< OperatorNew->getDeclName() << IsPlacementOperator << DeleteName;
Diag(OperatorNew->getLocation(), diag::note_type_aware_operator_declared)
<< OperatorNew->isTypeAwareOperatorNewOrDelete()
<< OperatorNew->getDeclName() << OperatorNew->getDeclContext();
<< OperatorNew->getDeclName() << OperatorNewContext;
}
};
if (IsClassScopedTypeAwareNew && FoundDelete.empty()) {
@@ -3224,6 +3230,7 @@ bool Sema::FindAllocationFunctions(
// deallocation function will be called.
if (Matches.size() == 1) {
OperatorDelete = Matches[0].second;
DeclContext *OperatorDeleteContext = GetRedeclContext(OperatorDelete);
bool FoundTypeAwareOperator =
OperatorDelete->isTypeAwareOperatorNewOrDelete() ||
OperatorNew->isTypeAwareOperatorNewOrDelete();
@@ -3231,8 +3238,7 @@ bool Sema::FindAllocationFunctions(
bool MismatchedTypeAwareness =
OperatorDelete->isTypeAwareOperatorNewOrDelete() !=
OperatorNew->isTypeAwareOperatorNewOrDelete();
bool MismatchedContext =
OperatorDelete->getDeclContext() != OperatorNew->getDeclContext();
bool MismatchedContext = OperatorDeleteContext != OperatorNewContext;
if (MismatchedTypeAwareness || MismatchedContext) {
FunctionDecl *Operators[] = {OperatorDelete, OperatorNew};
bool TypeAwareOperatorIndex =
@@ -3241,16 +3247,15 @@ bool Sema::FindAllocationFunctions(
<< Operators[TypeAwareOperatorIndex]->getDeclName()
<< isPlacementNew
<< Operators[!TypeAwareOperatorIndex]->getDeclName()
<< Operators[TypeAwareOperatorIndex]->getDeclContext();
<< GetRedeclContext(Operators[TypeAwareOperatorIndex]);
Diag(OperatorNew->getLocation(),
diag::note_type_aware_operator_declared)
<< OperatorNew->isTypeAwareOperatorNewOrDelete()
<< OperatorNew->getDeclName() << OperatorNew->getDeclContext();
<< OperatorNew->getDeclName() << OperatorNewContext;
Diag(OperatorDelete->getLocation(),
diag::note_type_aware_operator_declared)
<< OperatorDelete->isTypeAwareOperatorNewOrDelete()
<< OperatorDelete->getDeclName()
<< OperatorDelete->getDeclContext();
<< OperatorDelete->getDeclName() << OperatorDeleteContext;
}
}

View File

@@ -0,0 +1,43 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++26 -fexceptions -DTRANSPARENT_DECL=0
// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++26 -fexceptions -DTRANSPARENT_DECL=1
// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++26 -fexceptions -DTRANSPARENT_DECL=2
// expected-no-diagnostics
#if TRANSPARENT_DECL==2
export module Testing;
#endif
namespace std {
template <class T> struct type_identity {};
using size_t = __SIZE_TYPE__;
enum class align_val_t : size_t {};
struct destroying_delete_t { explicit destroying_delete_t() = default; };
}
#if TRANSPARENT_DECL==0
#define BEGIN_TRANSPARENT_DECL extern "C" {
#define END_TRANSPARENT_DECL }
#elif TRANSPARENT_DECL==1
#define BEGIN_TRANSPARENT_DECL extern "C++" {
#define END_TRANSPARENT_DECL }
#elif TRANSPARENT_DECL==2
#define BEGIN_TRANSPARENT_DECL export {
#define END_TRANSPARENT_DECL }
#else
#error unexpected decl kind
#endif
BEGIN_TRANSPARENT_DECL
void *operator new(std::type_identity<int>, std::size_t, std::align_val_t);
void operator delete[](std::type_identity<int>, void*, std::size_t, std::align_val_t);
END_TRANSPARENT_DECL
void *operator new[](std::type_identity<int>, std::size_t, std::align_val_t);
void operator delete(std::type_identity<int>, void*, std::size_t, std::align_val_t);
void foo() {
int *iptr = new int;
delete iptr;
int *iarray = new int[5];
delete [] iarray;
}