[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:
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user