| 1 | // RUN: %clang_cc1 -std=c++1z -fsyntax-only -verify %s |
| 2 | // RUN: %clang_cc1 -std=c++03 -fsyntax-only -verify %s |
| 3 | // RUN: %clang_cc1 -std=c++03 -faligned-allocation -fsyntax-only -verify %s |
| 4 | // RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s |
| 5 | // RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify -fsized-deallocation %s |
| 6 | |
| 7 | #if !__has_builtin(__builtin_operator_new) || !__has_builtin(__builtin_operator_delete) |
| 8 | #error builtins should always be available |
| 9 | #endif |
| 10 | |
| 11 | #if __has_builtin(__builtin_operator_new) != 201802L || \ |
| 12 | __has_builtin(__builtin_operator_delete) != 201802L |
| 13 | #error builtin should report updated value |
| 14 | #endif |
| 15 | |
| 16 | typedef __SIZE_TYPE__ size_t; |
| 17 | namespace std { |
| 18 | struct nothrow_t {}; |
| 19 | #if __cplusplus >= 201103L |
| 20 | enum class align_val_t : size_t {}; |
| 21 | #else |
| 22 | enum align_val_t { |
| 23 | // We can't force an underlying type when targeting windows. |
| 24 | # ifndef _WIN32 |
| 25 | __zero = 0, __max = (size_t)-1 |
| 26 | # endif |
| 27 | }; |
| 28 | #endif |
| 29 | } |
| 30 | std::nothrow_t nothrow; |
| 31 | |
| 32 | void *operator new(size_t); // expected-note 1+ {{candidate function}} |
| 33 | void operator delete(void *); // expected-note 1+ {{candidate function}} |
| 34 | |
| 35 | // Declare the reserved placement operators. |
| 36 | void *operator new(size_t, void*) throw(); // expected-note 1+ {{candidate function}} |
| 37 | void operator delete(void *, void *)throw(); // expected-note 1+ {{candidate function}} |
| 38 | void *operator new[](size_t, void*) throw(); |
| 39 | void operator delete[](void*, void*) throw(); |
| 40 | |
| 41 | // Declare the replaceable global allocation operators. |
| 42 | void *operator new(size_t, const std::nothrow_t &) throw(); // expected-note 1+ {{candidate function}} |
| 43 | void *operator new[](size_t, const std::nothrow_t &) throw(); |
| 44 | void operator delete(void *, const std::nothrow_t &)throw(); // expected-note 1+ {{candidate function}} |
| 45 | void operator delete[](void *, const std::nothrow_t &) throw(); |
| 46 | |
| 47 | // aligned allocation and deallocation functions. |
| 48 | void* operator new ( size_t count, std::align_val_t al); // expected-note 1+ {{candidate function}} |
| 49 | void operator delete(void *, std::align_val_t); // expected-note 1+ {{candidate}} |
| 50 | #ifndef __cpp_aligned_new |
| 51 | // expected-note@-3 1+ {{non-usual 'operator new' declared here}} |
| 52 | // expected-note@-3 1+ {{non-usual 'operator delete' declared here}} |
| 53 | #endif |
| 54 | void *operator new[](size_t count, std::align_val_t al); |
| 55 | void operator delete[](void*, std::align_val_t); |
| 56 | |
| 57 | void operator delete(void *, size_t); // expected-note 1+ {{candidate}} |
| 58 | #ifndef __cpp_sized_deallocation |
| 59 | // expected-note@-2 1+ {{non-usual 'operator delete' declared here}} |
| 60 | #endif |
| 61 | void operator delete[](void*, size_t); |
| 62 | |
| 63 | // Declare some other placemenet operators. |
| 64 | void *operator new(size_t, void*, bool) throw(); // expected-note 1+ {{candidate function}} |
| 65 | void *operator new[](size_t, void*, bool) throw(); |
| 66 | |
| 67 | void *NP = 0; |
| 68 | |
| 69 | void test_typo_in_args() { |
| 70 | __builtin_operator_new(DNE); // expected-error {{undeclared identifier 'DNE'}} |
| 71 | __builtin_operator_new(DNE, DNE2); // expected-error {{undeclared identifier 'DNE'}} expected-error {{'DNE2'}} |
| 72 | __builtin_operator_delete(DNE); // expected-error {{'DNE'}} |
| 73 | __builtin_operator_delete(DNE, DNE2); // expected-error {{'DNE'}} expected-error {{'DNE2'}} |
| 74 | } |
| 75 | |
| 76 | void test_arg_types() { |
| 77 | __builtin_operator_new(NP); // expected-error {{no matching function for call to 'operator new'}} |
| 78 | __builtin_operator_new(NP, std::align_val_t(0)); // expected-error {{no matching function for call to 'operator new'}}} |
| 79 | } |
| 80 | void test_return_type() { |
| 81 | int w = __builtin_operator_new(42); // expected-error {{cannot initialize a variable of type 'int' with an rvalue of type 'void *'}} |
| 82 | int y = __builtin_operator_delete(NP); // expected-error {{cannot initialize a variable of type 'int' with an rvalue of type 'void'}} |
| 83 | } |
| 84 | |
| 85 | void test_aligned_new() { |
| 86 | #ifdef __cpp_aligned_new |
| 87 | void *p = __builtin_operator_new(42, std::align_val_t(2)); |
| 88 | __builtin_operator_delete(p, std::align_val_t(2)); |
| 89 | #else |
| 90 | // FIXME: We've manually declared the aligned new/delete overloads, |
| 91 | // but LangOpts::AlignedAllocation is false. Should our overloads be considered |
| 92 | // usual allocation/deallocation functions? |
| 93 | void *p = __builtin_operator_new(42, std::align_val_t(2)); // expected-error {{call to '__builtin_operator_new' selects non-usual allocation function}} |
| 94 | __builtin_operator_delete(p, std::align_val_t(2)); // expected-error {{call to '__builtin_operator_delete' selects non-usual deallocation function}} |
| 95 | #endif |
| 96 | } |
| 97 | |
| 98 | void test_sized_delete() { |
| 99 | #ifdef __cpp_sized_deallocation |
| 100 | __builtin_operator_delete(NP, 4); |
| 101 | #else |
| 102 | __builtin_operator_delete(NP, 4); // expected-error {{call to '__builtin_operator_delete' selects non-usual deallocation function}} |
| 103 | #endif |
| 104 | } |
| 105 | |
| 106 | void *operator new(size_t, bool); // expected-note 1+ {{candidate}} |
| 107 | // expected-note@-1 {{non-usual 'operator new' declared here}} |
| 108 | void operator delete(void *, bool); // expected-note 1+ {{candidate}} |
| 109 | // expected-note@-1 {{non-usual 'operator delete' declared here}} |
| 110 | |
| 111 | void test_non_usual() { |
| 112 | __builtin_operator_new(42, true); // expected-error {{call to '__builtin_operator_new' selects non-usual allocation function}} |
| 113 | __builtin_operator_delete(NP, false); // expected-error {{call to '__builtin_operator_delete' selects non-usual deallocation function}} |
| 114 | } |
| 115 | |
| 116 | template <int ID> |
| 117 | struct Tag {}; |
| 118 | struct ConvertsToTypes { |
| 119 | operator std::align_val_t() const; |
| 120 | operator Tag<0>() const; |
| 121 | }; |
| 122 | |
| 123 | void *operator new(size_t, Tag<0>); // expected-note 0+ {{candidate}} |
| 124 | void operator delete(void *, Tag<0>); // expected-note 0+ {{candidate}} |
| 125 | |
| 126 | void test_ambiguous() { |
| 127 | #ifdef __cpp_aligned_new |
| 128 | ConvertsToTypes cvt; |
| 129 | __builtin_operator_new(42, cvt); // expected-error {{call to 'operator new' is ambiguous}} |
| 130 | __builtin_operator_delete(NP, cvt); // expected-error {{call to 'operator delete' is ambiguous}} |
| 131 | #endif |
| 132 | } |
| 133 | |
| 134 | void test_no_args() { |
| 135 | __builtin_operator_new(); // expected-error {{no matching function for call to 'operator new'}} |
| 136 | __builtin_operator_delete(); // expected-error {{no matching function for call to 'operator delete'}} |
| 137 | } |
| 138 | |
| 139 | void test_no_matching_fn() { |
| 140 | Tag<1> tag; |
| 141 | __builtin_operator_new(42, tag); // expected-error {{no matching function for call to 'operator new'}} |
| 142 | __builtin_operator_delete(NP, tag); // expected-error {{no matching function for call to 'operator delete'}} |
| 143 | } |
| 144 | |
| 145 | template <class Tp, class Up, class RetT> |
| 146 | void test_dependent_call(Tp new_arg, Up delete_arg, RetT) { |
| 147 | RetT ret = __builtin_operator_new(new_arg); |
| 148 | __builtin_operator_delete(delete_arg); |
| 149 | } |
| 150 | template void test_dependent_call(int, int*, void*); |
| 151 | |
| 152 | void test_const_attribute() { |
| 153 | __builtin_operator_new(42); // expected-warning {{ignoring return value of function declared with const attribute}} |
| 154 | #ifdef __cpp_aligned_new |
| 155 | __builtin_operator_new(42, std::align_val_t(8)); // expected-warning {{ignoring return value of function declared with const attribute}} |
| 156 | #endif |
| 157 | } |
| 158 | |