// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++26 -Wno-ext-cxx-type-aware-allocators -fexceptions    -fsized-deallocation    -faligned-allocation  -Wall -Wpedantic
// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++26 -Wno-ext-cxx-type-aware-allocators -fexceptions -fno-sized-deallocation    -faligned-allocation  -Wall -Wpedantic
// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++26 -Wno-ext-cxx-type-aware-allocators -fexceptions -fno-sized-deallocation -fno-aligned-allocation  -Wall -Wpedantic
// RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++26 -Wno-ext-cxx-type-aware-allocators -fexceptions    -fsized-deallocation -fno-aligned-allocation  -Wall -Wpedantic

namespace std {
  template <class T> struct type_identity {};
  enum class align_val_t : __SIZE_TYPE__ {};
  struct destroying_delete_t { explicit destroying_delete_t() = default; };
}

using size_t = __SIZE_TYPE__;

struct BasicTypeAwareArrayAllocator {
   template <typename T> void *operator new[](std::type_identity<T>, size_t, std::align_val_t) = delete; // #1
   template <typename T> void  operator delete[](std::type_identity<T>, void*, size_t, std::align_val_t) = delete; // #2
};
void *operator new[](std::type_identity<BasicTypeAwareArrayAllocator>, size_t, std::align_val_t);
void  operator delete[](std::type_identity<BasicTypeAwareArrayAllocator>, void*, size_t, std::align_val_t);

struct BasicTypeAwareNonArrayAllocator {
   template <typename T> void *operator new[](std::type_identity<T>, size_t, std::align_val_t);
   template <typename T> void  operator delete[](std::type_identity<T>, void*, size_t, std::align_val_t);
   void *operator new(size_t) = delete;
   void operator delete(void*) = delete;
};

struct WorkingTypeAwareAllocator {
   template <typename T> void *operator new[](std::type_identity<T>, size_t, std::align_val_t);
   template <typename T> void  operator delete[](std::type_identity<T>, void*, size_t, std::align_val_t);
};

void *operator new[](std::type_identity<WorkingTypeAwareAllocator>, size_t, std::align_val_t) = delete;
void  operator delete[](std::type_identity<WorkingTypeAwareAllocator>, void*, size_t, std::align_val_t) = delete;


void test() {
  BasicTypeAwareArrayAllocator *A0 = new BasicTypeAwareArrayAllocator[10];
  // expected-error@-1 {{call to deleted function 'operator new[]'}}
  // expected-note@#1 {{candidate function [with T = BasicTypeAwareArrayAllocator] has been explicitly deleted}}
  delete [] A0;
  // expected-error@-1 {{attempt to use a deleted function}}
  // expected-note@#2 {{'operator delete[]<BasicTypeAwareArrayAllocator>' has been explicitly marked deleted here}}
  
  BasicTypeAwareNonArrayAllocator *A1 = new BasicTypeAwareNonArrayAllocator[10];
  delete [] A1;

  WorkingTypeAwareAllocator *A2 = new WorkingTypeAwareAllocator[10];
  // expected-note@-1 {{allocated with 'new[]' here}}
  delete A2;
  // expected-warning@-1 {{'delete' applied to a pointer that was allocated with 'new[]'; did you mean 'delete[]'?}}

  WorkingTypeAwareAllocator *A3 = new WorkingTypeAwareAllocator;
  // expected-note@-1 {{allocated with 'new' here}}
  delete [] A3;
  // expected-warning@-1 {{'delete[]' applied to a pointer that was allocated with 'new'; did you mean 'delete'?}}

}
