blob: 4ccc256d636298891852377ba8a61c3acc08e89a [file] [log] [blame]
// RUN: %clang_cc1 -triple arm64-apple-macosx -fsyntax-only -verify %s -std=c++26 -Wno-ext-cxx-type-aware-allocators -fexceptions -fcxx-exceptions -fsized-deallocation -faligned-allocation -Wno-non-c-typedef-for-linkage -DDEFAULT_DELETE=1
// RUN: %clang_cc1 -triple arm64-apple-macosx -fsyntax-only -verify %s -std=c++26 -Wno-ext-cxx-type-aware-allocators -fexceptions -fcxx-exceptions -fno-sized-deallocation -faligned-allocation -Wno-non-c-typedef-for-linkage -DDEFAULT_DELETE=0
// RUN: %clang_cc1 -triple arm64-apple-macosx -fsyntax-only -verify %s -std=c++26 -Wno-ext-cxx-type-aware-allocators -fexceptions -fcxx-exceptions -fsized-deallocation -fno-aligned-allocation -Wno-non-c-typedef-for-linkage -DDEFAULT_DELETE=1
// RUN: %clang_cc1 -triple arm64-apple-macosx -fsyntax-only -verify %s -std=c++26 -Wno-ext-cxx-type-aware-allocators -fexceptions -fcxx-exceptions -fno-sized-deallocation -fno-aligned-allocation -Wno-non-c-typedef-for-linkage -DDEFAULT_DELETE=0
namespace std {
template <class T> struct type_identity {};
enum class align_val_t : __SIZE_TYPE__ {};
}
static_assert(__has_extension(cxx_type_aware_allocators), "Verifying the type aware extension flag is set");
using size_t = __SIZE_TYPE__;
void *operator new(size_t); // #default_operator_new
#if DEFAULT_DELETE==0
void operator delete(void*) noexcept; // #default_operator_delete
#elif DEFAULT_DELETE==1
void operator delete(void*, size_t) noexcept; // #default_operator_delete
#elif DEFAULT_DELETE==2
void operator delete(void*, std::align_val_t) noexcept; // #default_operator_delete
#elif DEFAULT_DELETE==3
void operator delete(void*, size_t, std::align_val_t) noexcept; // #default_operator_delete
#endif
struct Invalid1 {
// expected-error@-1 {{declaration of type aware 'operator new' in 'Invalid1' must have matching type aware 'operator delete'}}
void *operator new(std::type_identity<Invalid1>, size_t, std::align_val_t);
// expected-note@-1 {{unmatched type aware 'operator new' declared here}}
};
struct Invalid2 {
// expected-error@-1 {{declaration of type aware 'operator new' in 'Invalid2' must have matching type aware 'operator delete'}}
template <class T> void *operator new(std::type_identity<T>, size_t, std::align_val_t); // #Invalid2_new
// expected-note@-1 {{unmatched type aware 'operator new' declared here}}
};
struct Invalid3 {
// expected-error@-1 {{declaration of type aware 'operator delete' in 'Invalid3' must have matching type aware 'operator new'}}
void operator delete(std::type_identity<Invalid3>, void*, size_t, std::align_val_t);
// expected-note@-1 {{unmatched type aware 'operator delete' declared here}}
};
struct Invalid4 {
// expected-error@-1 {{declaration of type aware 'operator delete' in 'Invalid4' must have matching type aware 'operator new'}}
template <class T> void operator delete(std::type_identity<T>, void*, size_t, std::align_val_t); // #Invalid4_delete
// expected-note@-1 {{unmatched type aware 'operator delete' declared here}}
};
struct Invalid5 {
// expected-error@-1 {{declaration of type aware 'operator new[]' in 'Invalid5' must have matching type aware 'operator delete[]'}}
void *operator new[](std::type_identity<Invalid5>, size_t, std::align_val_t);
// expected-note@-1 {{unmatched type aware 'operator new[]' declared here}}
};
struct Invalid6 {
// expected-error@-1 {{declaration of type aware 'operator new[]' in 'Invalid6' must have matching type aware 'operator delete[]'}}
template <class T> void *operator new[](std::type_identity<T>, size_t, std::align_val_t);
// expected-note@-1 {{unmatched type aware 'operator new[]' declared here}}
};
struct Invalid7 {
// expected-error@-1 {{declaration of type aware 'operator delete[]' in 'Invalid7' must have matching type aware 'operator new[]'}}
void operator delete[](std::type_identity<Invalid7>, void*, size_t, std::align_val_t);
// expected-note@-1 {{unmatched type aware 'operator delete[]' declared here}}
};
struct Invalid8 {
// expected-error@-1 {{declaration of type aware 'operator delete[]' in 'Invalid8' must have matching type aware 'operator new[]'}}
template <class T> void operator delete[](std::type_identity<T>, void*, size_t, std::align_val_t);
// expected-note@-1 {{unmatched type aware 'operator delete[]' declared here}}
};
// Invalid9 and Invalid10 will ensure we report the correct owner for the
// resolved, but unmatched, new and delete
struct Invalid9: Invalid2 {};
struct Invalid10: Invalid4 {};
// Invalid11 inherits a "matching" new and delete pair (so no inheritance ambiguity)
// but the resolved operators are from different scopes
struct Invalid11 : Invalid2, Invalid4 {};
struct Invalid12 : Invalid2, Invalid4 {
using Invalid2::operator new;
using Invalid4::operator delete;
};
struct TestClass1 {
void *operator new(std::type_identity<TestClass1>, size_t, std::align_val_t); // #TestClass1_new
void operator delete(std::type_identity<int>, void *, size_t, std::align_val_t); // #TestClass1_delete
};
struct TestClass2 {
void *operator new(std::type_identity<int>, size_t, std::align_val_t); // #TestClass2_new
void operator delete(std::type_identity<TestClass2>, void *, size_t, std::align_val_t); // #TestClass2_delete
};
void basic_tests() {
TestClass1 * tc1 = new TestClass1;
delete tc1;
// expected-error@-1 {{no suitable member 'operator delete' in 'TestClass1'}}
// expected-note@#TestClass1_delete {{member 'operator delete' declared here}}
TestClass2 * tc2 = new TestClass2;
// expected-error@-1 {{no matching function for call to 'operator new'}}
delete tc2;
Invalid9 * i9 = new Invalid9;
// expected-error@-1 {{type aware 'operator new' requires a matching type aware 'operator delete' to be declared in the same scope}}
// expected-note@#Invalid2_new {{type aware 'operator new' declared here in 'Invalid2'}}
delete i9;
Invalid10 * i10 = new Invalid10;
// expected-error@-1 {{type aware 'operator delete' requires a matching type aware 'operator new' to be declared in the same scope}}
// expected-note@#Invalid4_delete {{type aware 'operator delete' declared here in 'Invalid4'}}
// expected-note@#default_operator_new {{non-type aware 'operator new' declared here in the global namespace}}
delete i10;
Invalid11 * i11 = new Invalid11;
// expected-error@-1 {{type aware 'operator new' requires a matching type aware 'operator delete' to be declared in the same scope}}
// expected-note@#Invalid2_new {{type aware 'operator new' declared here in 'Invalid2'}}
// expected-note@#Invalid4_delete {{type aware 'operator delete' declared here in 'Invalid4'}}
delete i11;
Invalid12 * i12 = new Invalid12;
// expected-error@-1 {{type aware 'operator new' requires a matching type aware 'operator delete' to be declared in the same scope}}
// expected-note@#Invalid2_new {{type aware 'operator new' declared here in 'Invalid2'}}
// expected-note@#Invalid4_delete {{type aware 'operator delete' declared here in 'Invalid4'}}
delete i12;
}
struct Baseclass1 {
void *operator new(std::type_identity<Baseclass1>, size_t, std::align_val_t);
void operator delete(std::type_identity<Baseclass1>, void *, size_t, std::align_val_t); // #Baseclass1_delete
};
struct Subclass1 : Baseclass1 {
Subclass1();
};
struct Baseclass2 {
template <class T> void *operator new(std::type_identity<T>, size_t, std::align_val_t);
void operator delete(std::type_identity<Baseclass2>, void *, size_t, std::align_val_t); // #Baseclass2_delete
};
struct Subclass2 : Baseclass2 {
Subclass2();
};
struct Baseclass3 {
template <class T> void *operator new(std::type_identity<T>, size_t, std::align_val_t);
template <class T> void operator delete(std::type_identity<T>, void *, size_t, std::align_val_t);
};
struct Subclass3_1 : Baseclass3 {
Subclass3_1();
void *operator new(std::type_identity<int>, size_t, std::align_val_t);
template <class T> void operator delete(std::type_identity<T>, void *, size_t, std::align_val_t);
};
struct Subclass3_2 : Baseclass3 {
Subclass3_2();
template <class T> void *operator new(std::type_identity<T>, size_t, std::align_val_t);
void operator delete(std::type_identity<int>, void *, size_t, std::align_val_t); // #Subclass3_2_delete
};
void test_subclasses() {
Subclass1 * sc1 = new Subclass1;
// expected-error@-1 {{no matching function for call to 'operator new'}}
delete sc1;
// expected-error@-1 {{no suitable member 'operator delete' in 'Subclass1'}}
// expected-note@#Baseclass1_delete {{member 'operator delete' declared here}}
Subclass2 * sc2 = new Subclass2;
delete sc2;
// expected-error@-1 {{no suitable member 'operator delete' in 'Subclass2'}}
// expected-note@#Baseclass2_delete {{member 'operator delete' declared here}}
Subclass3_1 * sc3_1 = new Subclass3_1;
// expected-error@-1 {{no matching function for call to 'operator new'}}
delete sc3_1;
Subclass3_2 * sc3_2 = new Subclass3_2;
delete sc3_2;
// expected-error@-1 {{no suitable member 'operator delete' in 'Subclass3_2'}}
// expected-note@#Subclass3_2_delete {{member 'operator delete' declared here}}
}
template <class A, class B> constexpr bool same_type_v = false;
template <class A> constexpr bool same_type_v<A, A> = true;
template <class T> struct InvalidConstrainedOperator {
template <class U> void *operator new(std::type_identity<U>, size_t, std::align_val_t);
template <class U> requires (same_type_v<T, int>) void operator delete(std::type_identity<U>, void *, size_t, std::align_val_t); // #InvalidConstrainedOperator_delete
};
struct Context;
template <class T> struct InvalidConstrainedCleanup {
template <class U> void *operator new(std::type_identity<U>, size_t, std::align_val_t, Context&); // #InvalidConstrainedCleanup_placement_new
template <class U> requires (same_type_v<T, int>) void operator delete(std::type_identity<U>, void *, size_t, std::align_val_t, Context&); // #InvalidConstrainedCleanup_delete
template <class U> void operator delete(std::type_identity<U>, void *, size_t, std::align_val_t);
};
void test_incompatible_constrained_operators(Context &Ctx) {
InvalidConstrainedOperator<int> *ico1 = new InvalidConstrainedOperator<int>;
delete ico1;
InvalidConstrainedOperator<float> *ico2 = new InvalidConstrainedOperator<float>;
delete ico2;
// expected-error@-1 {{no suitable member 'operator delete' in 'InvalidConstrainedOperator<float>'}}
// expected-note@#InvalidConstrainedOperator_delete {{member 'operator delete' declared here}}
InvalidConstrainedCleanup<int> *icc1 = new (Ctx) InvalidConstrainedCleanup<int>;
delete icc1;
InvalidConstrainedCleanup<float> *icc2 = new (Ctx) InvalidConstrainedCleanup<float>;
// expected-error@-1 {{type aware 'operator new' requires a matching type aware placement 'operator delete' to be declared in the same scope}}
// expected-note@#InvalidConstrainedCleanup_placement_new {{type aware 'operator new' declared here in 'InvalidConstrainedCleanup<float>'}}
delete icc2;
}
typedef struct {
// expected-error@-1 {{declaration of type aware 'operator new' in '(unnamed struct}}
// expected-note@#AnonymousClass1_new {{unmatched type aware 'operator new' declared here}}
template <class T> void *operator new(std::type_identity<T>, size_t, std::align_val_t); // #AnonymousClass1_new
} AnonymousClass1;
typedef struct {
// expected-error@-1 {{declaration of type aware 'operator delete' in '(unnamed struct}}
template <class T> void operator delete(std::type_identity<T>, void*, size_t, std::align_val_t); // #AnonymousClass2_delete
} AnonymousClass2;
typedef struct {
template <class T> void *operator new(std::type_identity<T>, size_t, std::align_val_t);
template <class T> void operator delete(std::type_identity<T>, void*, size_t, std::align_val_t);
} AnonymousClass3;
using AnonymousClass4 = struct {};
using AnonymousClass5 = struct {};
using AnonymousClass6 = struct {};
using AnonymousClass7 = struct {
// expected-error@-1 {{declaration of type aware 'operator new' in}}
// expected-note@#AnonymousClass7_new {{unmatched type aware 'operator new' declared here}}
template <class T> void *operator new(std::type_identity<T>, size_t, std::align_val_t, Context&); // #AnonymousClass7_new
};
void *operator new(std::type_identity<AnonymousClass4>, size_t, std::align_val_t); // #AnonymousClass4_new
void operator delete(std::type_identity<AnonymousClass5>, void*, size_t, std::align_val_t); // #AnonymousClass5_delete
void *operator new(std::type_identity<AnonymousClass6>, size_t, std::align_val_t, Context&); // #AnonymousClass6_placement_new
void operator delete(std::type_identity<AnonymousClass6>, void*, size_t, std::align_val_t);
void test_anonymous_types(Context &Ctx) {
AnonymousClass1 *ac1 = new AnonymousClass1;
// expected-error@-1 {{type aware 'operator new' requires a matching type aware 'operator delete' to be declared in the same scope}}
// expected-note@#AnonymousClass1_new {{type aware 'operator new' declared here in 'AnonymousClass1'}}
delete ac1;
AnonymousClass2 *ac2 = new AnonymousClass2;
// expected-error@-1 {{type aware 'operator delete' requires a matching type aware 'operator new' to be declared in the same scope}}
// expected-note@#AnonymousClass2_delete {{unmatched type aware 'operator delete' declared here}}
// expected-note@#AnonymousClass2_delete {{type aware 'operator delete' declared here in 'AnonymousClass2'}}
// expected-note@#default_operator_new {{non-type aware 'operator new' declared here in the global namespace}}
delete ac2;
AnonymousClass3 *ac3 = new AnonymousClass3;
delete ac3;
AnonymousClass4 *ac4 = new AnonymousClass4;
// expected-error@-1 {{type aware 'operator new' requires a matching type aware 'operator delete' to be declared in the same scope}}
// expected-note@#AnonymousClass4_new {{type aware 'operator new' declared here in the global namespace}}
delete ac4;
AnonymousClass5 *ac5 = new AnonymousClass5;
// expected-error@-1 {{type aware 'operator delete' requires a matching type aware 'operator new' to be declared in the same scope}}
// expected-note@#AnonymousClass5_delete {{type aware 'operator delete' declared here}}
// expected-note@#default_operator_new {{non-type aware 'operator new' declared here in the global namespace}}
delete ac5;
AnonymousClass6 *ac6 = new (Ctx) AnonymousClass6;
// expected-error@-1 {{type aware 'operator new' requires a matching type aware placement 'operator delete' to be declared in the same scope}}
// expected-note@#AnonymousClass6_placement_new {{type aware 'operator new' declared here in the global namespace}}
// expected-note@#default_operator_delete {{non-type aware 'operator delete' declared here in the global namespace}}
delete ac6;
}