xref: /llvm-project/clang/test/SemaCXX/cxx1z-noexcept-function-type.cpp (revision 77c5cea78eac3f20d0ba79f5892235e5aac82603)
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 
redecl1()8 template<typename T> void redecl1() noexcept(noexcept(T())) {} // expected-note {{previous}}
9 template<typename T> void redecl1() noexcept(noexcept(T())); // ok, same type
redecl1()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);
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 {{cannot initialize a variable of 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 
get_fn()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;
mapDependentDefaultCtorExceptionSpec::map55     map() noexcept(T<a>::value) {}
56   };
57 
58   template<class B> struct multimap {
59     typedef B b;
multimapDependentDefaultCtorExceptionSpec::multimap60     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   template <class> struct NoexceptWithThis {
69     int ca;
fooDependentDefaultCtorExceptionSpec::NoexceptWithThis70     template <class T> auto foo(T) noexcept(ca) { return true; }
71     // expected-error@-1 {{noexcept specifier argument is not a constant expression}}
72     // expected-note@-2 {{in instantiation of exception specification}}
73     // expected-note@-3 {{implicit use of 'this' pointer is only allowed within the evaluation of a call to a 'constexpr' member function}}
74   };
75   struct InstantiateFromAnotherClass {
76     template <class B, class T = decltype(static_cast<bool (B::*)(int)>(&B::foo))> // expected-note {{in instantiation of function template specialization}}
InstantiateFromAnotherClassDependentDefaultCtorExceptionSpec::InstantiateFromAnotherClass77     InstantiateFromAnotherClass(B *) {} // expected-note {{in instantiation of default argument}}
78   };
79   NoexceptWithThis<int> f{};
80   // Don't crash here.
81   InstantiateFromAnotherClass b{&f}; // expected-note {{while substituting deduced template arguments into function template}}
82 }
83 
84 #endif
85 
86 namespace CompatWarning {
87   struct X;
88 
89   // These cases don't change.
90   void f0(void p() throw(int));
91   auto f0() -> void (*)() noexcept(false);
92 
93   // These cases take an ABI break in C++17 because their parameter / return types change.
94   void f1(void p() noexcept);
95   void f2(void (*p)() noexcept(true));
96   void f3(void (&p)() throw());
97   void f4(void (X::*p)() throw());
98   auto f5() -> void (*)() throw();
99   auto f6() -> void (&)() throw();
100   auto f7() -> void (X::*)() throw();
101 #if __cplusplus <= 201402L && !defined(NO_COMPAT_MANGLING)
102   // expected-warning@-8 {{mangled name of 'f1' will change in C++17 due to non-throwing exception specification in function signature}}
103   // expected-warning@-8 {{mangled name of 'f2' will change in C++17 due to non-throwing exception specification in function signature}}
104   // expected-warning@-8 {{mangled name of 'f3' will change in C++17 due to non-throwing exception specification in function signature}}
105   // expected-warning@-8 {{mangled name of 'f4' will change in C++17 due to non-throwing exception specification in function signature}}
106   // expected-warning@-8 {{mangled name of 'f5' will change in C++17 due to non-throwing exception specification in function signature}}
107   // expected-warning@-8 {{mangled name of 'f6' will change in C++17 due to non-throwing exception specification in function signature}}
108   // expected-warning@-8 {{mangled name of 'f7' will change in C++17 due to non-throwing exception specification in function signature}}
109 #endif
110 
111   // An instantiation-dependent exception specification needs to be mangled in
112   // all language modes, since it participates in SFINAE.
113   template<typename T> void g(void() throw(T)); // expected-note {{substitution failure}}
114   template<typename T> void g(...) = delete; // expected-note {{deleted}}
test_g()115   void test_g() { g<void>(nullptr); } // expected-error {{deleted}}
116 
117   // An instantiation-dependent exception specification needs to be mangled in
118   // all language modes, since it participates in SFINAE.
119   template<typename T> void h(void() noexcept(T())); // expected-note {{substitution failure}}
120   template<typename T> void h(...) = delete; // expected-note {{deleted}}
test_h()121   void test_h() { h<void>(nullptr); } // expected-error {{deleted}}
122 }
123 
124 namespace ImplicitExceptionSpec {
125   struct S {
126     ~S();
127     void f(const S &s = S());
128   };
~S()129   S::~S() {}
130 }
131 
132 namespace Builtins {
133   // Pick two functions that ought to have the same noexceptness.
134   extern "C" int strcmp(const char *, const char *);
135   extern "C" int strncmp(const char *, const char *, decltype(sizeof(0))) noexcept;
136 
137   // Check we recognized both as builtins.
138   typedef int arr[strcmp("bar", "foo") + 4 * strncmp("foo", "bar", 4)]; // expected-warning {{variable length array folded to constant array as an extension}} \
139                                                                            expected-warning {{variable length arrays in C++ are a Clang extension}} \
140                                                                            expected-note {{non-constexpr function 'strcmp' cannot be used in a constant expression}}
141   typedef int arr[3];
142 }
143 
144 namespace ExplicitInstantiation {
f()145   template<typename T> void f() noexcept {}
fExplicitInstantiation::X146   template<typename T> struct X { void f() noexcept {} };
147   template void f<int>();
148   template void X<int>::f();
149 }
150 
151 namespace ConversionFunction {
152   struct A { template<typename T> operator T() noexcept; };
153   int a = A().operator int();
154 }
155 
156 using size_t = decltype(sizeof(0));
157 
158 namespace OperatorDelete {
159   struct W {};
160   struct X {};
161   struct Y {};
162   struct Z {};
163   template<bool N, bool D> struct T {};
164 }
165 void *operator new(size_t, OperatorDelete::W) noexcept(false);
166 void operator delete(void*, OperatorDelete::W) noexcept(false) = delete; // expected-note {{here}}
167 void *operator new(size_t, OperatorDelete::X) noexcept(false);
168 void operator delete(void*, OperatorDelete::X) noexcept(true) = delete; // expected-note {{here}}
169 void *operator new(size_t, OperatorDelete::Y) noexcept(true);
170 void operator delete(void*, OperatorDelete::Y) noexcept(false) = delete; // expected-note {{here}}
171 void *operator new(size_t, OperatorDelete::Z) noexcept(true);
172 void operator delete(void*, OperatorDelete::Z) noexcept(true) = delete; // expected-note {{here}}
173 template<bool N, bool D> void *operator new(size_t, OperatorDelete::T<N, D>) noexcept(N);
174 template<bool N, bool D> void operator delete(void*, OperatorDelete::T<N, D>) noexcept(D) = delete; // expected-note 4{{here}}
175 namespace OperatorDelete {
176   struct A { A(); };
177   A *w = new (W{}) A; // expected-error {{deleted function}}
178   A *x = new (X{}) A; // expected-error {{deleted function}}
179   A *y = new (Y{}) A; // expected-error {{deleted function}}
180   A *z = new (Z{}) A; // expected-error {{deleted function}}
181 
182   A *t00 = new (T<false, false>{}) A; // expected-error {{deleted function}}
183   A *t01 = new (T<false, true>{}) A; // expected-error {{deleted function}}
184   A *t10 = new (T<true, false>{}) A; // expected-error {{deleted function}}
185   A *t11 = new (T<true, true>{}) A; // expected-error {{deleted function}}
186 }
187