| 1 | // RUN: %clang_cc1 -std=c++14 -verify -fexceptions -fcxx-exceptions %s |
| 2 | // RUN: %clang_cc1 -std=c++17 -verify -fexceptions -fcxx-exceptions %s -Wno-dynamic-exception-spec |
| 3 | // RUN: %clang_cc1 -std=c++14 -verify -fexceptions -fcxx-exceptions -Wno-c++1z-compat-mangling -DNO_COMPAT_MANGLING %s |
| 4 | // RUN: %clang_cc1 -std=c++14 -verify -fexceptions -fcxx-exceptions -Wno-noexcept-type -DNO_COMPAT_MANGLING %s |
| 5 | |
| 6 | #if __cplusplus > 201402L |
| 7 | |
| 8 | template<typename T> void redecl1() noexcept(noexcept(T())) {} // expected-note {{previous}} |
| 9 | template<typename T> void redecl1() noexcept(noexcept(T())); // ok, same type |
| 10 | template<typename T> void redecl1() noexcept(noexcept(T())) {} // expected-error {{redefinition}} |
| 11 | |
| 12 | template<bool A, bool B> void redecl2() noexcept(A); // expected-note {{previous}} |
| 13 | template<bool A, bool B> void redecl2() noexcept(B); // expected-error {{does not match previous}} |
| 14 | |
| 15 | // These have the same canonical type, but are still different. |
| 16 | template<typename A, typename B> void redecl3() throw(A); // expected-note {{previous}} |
| 17 | template<typename A, typename B> void redecl3() throw(B); // expected-error {{does not match previous}} |
| 18 | |
| 19 | typedef int I; |
| 20 | template<bool B> void redecl4(I) noexcept(B); |
| 21 | template<bool B> void redecl4(I) noexcept(B); // expected-note {{could not match 'void (I) noexcept(false)' (aka 'void (int) noexcept(false)') against 'void (int) noexcept'}} |
| 22 | |
| 23 | void (*init_with_exact_type_a)(int) noexcept = redecl4<true>; |
| 24 | void (*init_with_mismatched_type_a)(int) = redecl4<true>; |
| 25 | auto deduce_auto_from_noexcept_function_ptr_a = redecl4<true>; |
| 26 | using DeducedType_a = decltype(deduce_auto_from_noexcept_function_ptr_a); |
| 27 | using DeducedType_a = void (*)(int) noexcept; |
| 28 | |
| 29 | void (*init_with_exact_type_b)(int) = redecl4<false>; |
| 30 | void (*init_with_mismatched_type_b)(int) noexcept = redecl4<false>; // expected-error {{does not match required type}} |
| 31 | auto deduce_auto_from_noexcept_function_ptr_b = redecl4<false>; |
| 32 | using DeducedType_b = decltype(deduce_auto_from_noexcept_function_ptr_b); |
| 33 | using DeducedType_b = void (*)(int); |
| 34 | |
| 35 | static_assert(noexcept(init_with_exact_type_a(0))); |
| 36 | static_assert(noexcept((+init_with_exact_type_a)(0))); |
| 37 | static_assert(!noexcept(init_with_exact_type_b(0))); |
| 38 | static_assert(!noexcept((+init_with_exact_type_b)(0))); |
| 39 | |
| 40 | // Don't look through casts, use the direct type of the expression. |
| 41 | // FIXME: static_cast here would be reasonable, but is not currently permitted. |
| 42 | static_assert(noexcept(static_cast<decltype(init_with_exact_type_a)>(init_with_exact_type_b)(0))); // expected-error {{is not allowed}} |
| 43 | static_assert(noexcept(reinterpret_cast<decltype(init_with_exact_type_a)>(init_with_exact_type_b)(0))); |
| 44 | static_assert(!noexcept(static_cast<decltype(init_with_exact_type_b)>(init_with_exact_type_a)(0))); |
| 45 | |
| 46 | template<bool B> auto get_fn() noexcept -> void (*)() noexcept(B) {} |
| 47 | static_assert(noexcept(get_fn<true>()())); |
| 48 | static_assert(!noexcept(get_fn<false>()())); |
| 49 | |
| 50 | namespace DependentDefaultCtorExceptionSpec { |
| 51 | template<typename> struct T { static const bool value = true; }; |
| 52 | |
| 53 | template<class A> struct map { |
| 54 | typedef A a; |
| 55 | map() noexcept(T<a>::value) {} |
| 56 | }; |
| 57 | |
| 58 | template<class B> struct multimap { |
| 59 | typedef B b; |
| 60 | multimap() noexcept(T<b>::value) {} |
| 61 | }; |
| 62 | |
| 63 | // Don't crash here. |
| 64 | struct A { multimap<int> Map; } a; |
| 65 | |
| 66 | static_assert(noexcept(A())); |
| 67 | } |
| 68 | |
| 69 | #endif |
| 70 | |
| 71 | namespace CompatWarning { |
| 72 | struct X; |
| 73 | |
| 74 | // These cases don't change. |
| 75 | void f0(void p() throw(int)); |
| 76 | auto f0() -> void (*)() noexcept(false); |
| 77 | |
| 78 | // These cases take an ABI break in C++17 because their parameter / return types change. |
| 79 | void f1(void p() noexcept); |
| 80 | void f2(void (*p)() noexcept(true)); |
| 81 | void f3(void (&p)() throw()); |
| 82 | void f4(void (X::*p)() throw()); |
| 83 | auto f5() -> void (*)() throw(); |
| 84 | auto f6() -> void (&)() throw(); |
| 85 | auto f7() -> void (X::*)() throw(); |
| 86 | #if __cplusplus <= 201402L && !defined(NO_COMPAT_MANGLING) |
| 87 | // expected-warning@-8 {{mangled name of 'f1' will change in C++17 due to non-throwing exception specification in function signature}} |
| 88 | // expected-warning@-8 {{mangled name of 'f2' will change in C++17 due to non-throwing exception specification in function signature}} |
| 89 | // expected-warning@-8 {{mangled name of 'f3' will change in C++17 due to non-throwing exception specification in function signature}} |
| 90 | // expected-warning@-8 {{mangled name of 'f4' will change in C++17 due to non-throwing exception specification in function signature}} |
| 91 | // expected-warning@-8 {{mangled name of 'f5' will change in C++17 due to non-throwing exception specification in function signature}} |
| 92 | // expected-warning@-8 {{mangled name of 'f6' will change in C++17 due to non-throwing exception specification in function signature}} |
| 93 | // expected-warning@-8 {{mangled name of 'f7' will change in C++17 due to non-throwing exception specification in function signature}} |
| 94 | #endif |
| 95 | |
| 96 | // An instantiation-dependent exception specification needs to be mangled in |
| 97 | // all language modes, since it participates in SFINAE. |
| 98 | template<typename T> void g(void() throw(T)); // expected-note {{substitution failure}} |
| 99 | template<typename T> void g(...) = delete; // expected-note {{deleted}} |
| 100 | void test_g() { g<void>(nullptr); } // expected-error {{deleted}} |
| 101 | |
| 102 | // An instantiation-dependent exception specification needs to be mangled in |
| 103 | // all language modes, since it participates in SFINAE. |
| 104 | template<typename T> void h(void() noexcept(T())); // expected-note {{substitution failure}} |
| 105 | template<typename T> void h(...) = delete; // expected-note {{deleted}} |
| 106 | void test_h() { h<void>(nullptr); } // expected-error {{deleted}} |
| 107 | } |
| 108 | |
| 109 | namespace ImplicitExceptionSpec { |
| 110 | struct S { |
| 111 | ~S(); |
| 112 | void f(const S &s = S()); |
| 113 | }; |
| 114 | S::~S() {} |
| 115 | } |
| 116 | |
| 117 | namespace Builtins { |
| 118 | // Pick two functions that ought to have the same noexceptness. |
| 119 | extern "C" int strcmp(const char *, const char *); |
| 120 | extern "C" int strncmp(const char *, const char *, decltype(sizeof(0))) noexcept; |
| 121 | |
| 122 | // Check we recognized both as builtins. |
| 123 | typedef int arr[strcmp("bar", "foo") + 4 * strncmp("foo", "bar", 4)]; |
| 124 | typedef int arr[3]; |
| 125 | } |
| 126 | |
| 127 | namespace ExplicitInstantiation { |
| 128 | template<typename T> void f() noexcept {} |
| 129 | template<typename T> struct X { void f() noexcept {} }; |
| 130 | template void f<int>(); |
| 131 | template void X<int>::f(); |
| 132 | } |
| 133 | |
| 134 | namespace ConversionFunction { |
| 135 | struct A { template<typename T> operator T() noexcept; }; |
| 136 | int a = A().operator int(); |
| 137 | } |
| 138 | |
| 139 | using size_t = decltype(sizeof(0)); |
| 140 | |
| 141 | namespace OperatorDelete { |
| 142 | struct W {}; |
| 143 | struct X {}; |
| 144 | struct Y {}; |
| 145 | struct Z {}; |
| 146 | template<bool N, bool D> struct T {}; |
| 147 | } |
| 148 | void *operator new(size_t, OperatorDelete::W) noexcept(false); |
| 149 | void operator delete(void*, OperatorDelete::W) noexcept(false) = delete; // expected-note {{here}} |
| 150 | void *operator new(size_t, OperatorDelete::X) noexcept(false); |
| 151 | void operator delete(void*, OperatorDelete::X) noexcept(true) = delete; // expected-note {{here}} |
| 152 | void *operator new(size_t, OperatorDelete::Y) noexcept(true); |
| 153 | void operator delete(void*, OperatorDelete::Y) noexcept(false) = delete; // expected-note {{here}} |
| 154 | void *operator new(size_t, OperatorDelete::Z) noexcept(true); |
| 155 | void operator delete(void*, OperatorDelete::Z) noexcept(true) = delete; // expected-note {{here}} |
| 156 | template<bool N, bool D> void *operator new(size_t, OperatorDelete::T<N, D>) noexcept(N); |
| 157 | template<bool N, bool D> void operator delete(void*, OperatorDelete::T<N, D>) noexcept(D) = delete; // expected-note 4{{here}} |
| 158 | namespace OperatorDelete { |
| 159 | struct A { A(); }; |
| 160 | A *w = new (W{}) A; // expected-error {{deleted function}} |
| 161 | A *x = new (X{}) A; // expected-error {{deleted function}} |
| 162 | A *y = new (Y{}) A; // expected-error {{deleted function}} |
| 163 | A *z = new (Z{}) A; // expected-error {{deleted function}} |
| 164 | |
| 165 | A *t00 = new (T<false, false>{}) A; // expected-error {{deleted function}} |
| 166 | A *t01 = new (T<false, true>{}) A; // expected-error {{deleted function}} |
| 167 | A *t10 = new (T<true, false>{}) A; // expected-error {{deleted function}} |
| 168 | A *t11 = new (T<true, true>{}) A; // expected-error {{deleted function}} |
| 169 | } |
| 170 | |