1 | // RUN: %clang_cc1 -fsyntax-only -fcxx-exceptions -verify -std=c++11 -Wall -Wno-unused-local-typedefs %s |
2 | |
3 | template<bool b> struct ExceptionIf { static int f(); }; |
4 | template<> struct ExceptionIf<false> { typedef int f; }; |
5 | |
6 | // The exception specification of a defaulted default constructor depends on |
7 | // the contents of in-class member initializers. However, the in-class member |
8 | // initializers can depend on the exception specification of the constructor, |
9 | // since the class is considered complete within them. We reject any such cases. |
10 | namespace InClassInitializers { |
11 | // Noexcept::Noexcept() is implicitly declared as noexcept(false), because it |
12 | // directly invokes ThrowSomething(). However... |
13 | // |
14 | // If noexcept(Noexcept()) is false, then Noexcept() is a constant expression, |
15 | // so noexcept(Noexcept()) is true. But if noexcept(Noexcept()) is true, then |
16 | // Noexcept::Noexcept is not declared constexpr, therefore noexcept(Noexcept()) |
17 | // is false. |
18 | bool ThrowSomething() noexcept(false); |
19 | struct ConstExpr { // expected-error {{default member initializer for 'b' needed}} |
20 | bool b = // expected-note {{declared here}} |
21 | noexcept(ConstExpr()) && ThrowSomething(); // expected-note {{in evaluation of exception spec}} |
22 | }; |
23 | |
24 | // Much more obviously broken: we can't parse the initializer without already |
25 | // knowing whether it produces a noexcept expression. |
26 | struct TemplateArg { // expected-error {{default member initializer for 'n' needed}} |
27 | int n = // expected-note {{declared here}} |
28 | ExceptionIf<noexcept(TemplateArg())>::f(); // expected-note {{in evaluation of exception spec}} |
29 | }; |
30 | |
31 | // And within a nested class. |
32 | struct Nested { |
33 | struct Inner { // expected-error {{default member initializer for 'n' needed}} |
34 | int n = // expected-note {{declared here}} |
35 | ExceptionIf<noexcept(Nested())>::f(); // expected-note {{in evaluation of exception spec}} |
36 | } inner; // expected-note {{in evaluation of exception spec}} |
37 | }; |
38 | |
39 | struct Nested2 { |
40 | struct Inner; |
41 | int n = Inner().n; // expected-note {{in evaluation of exception spec}} |
42 | struct Inner { // expected-error {{initializer for 'n' needed}} |
43 | int n = ExceptionIf<noexcept(Nested2())>::f(); // expected-note {{declared here}} |
44 | } inner; |
45 | }; |
46 | } |
47 | |
48 | namespace ExceptionSpecification { |
49 | struct Nested { |
50 | struct T { |
51 | T() noexcept(!noexcept(Nested())); // expected-note {{in evaluation of exception spec}} |
52 | } t; // expected-error{{exception specification is not available until end of class definition}} |
53 | }; |
54 | } |
55 | |
56 | namespace DefaultArgument { |
57 | struct Default { |
58 | struct T { |
59 | T(int = ExceptionIf<noexcept(Default())::f()); // expected-error {{call to implicitly-deleted default constructor}} |
60 | } t; // expected-note {{has no default constructor}} |
61 | }; |
62 | } |
63 | |
64 | namespace ImplicitDtorExceptionSpec { |
65 | struct A { |
66 | virtual ~A(); |
67 | |
68 | struct Inner { |
69 | ~Inner() throw(); |
70 | }; |
71 | Inner inner; |
72 | }; |
73 | |
74 | struct B { |
75 | virtual ~B() {} // expected-note {{here}} |
76 | }; |
77 | |
78 | struct C : B { |
79 | virtual ~C() {} |
80 | A a; |
81 | }; |
82 | |
83 | struct D : B { |
84 | ~D(); // expected-error {{more lax than base}} |
85 | struct E { |
86 | ~E(); |
87 | struct F { |
88 | ~F() throw(A); |
89 | } f; |
90 | } e; |
91 | }; |
92 | } |
93 | |
94 | struct nothrow_t {} nothrow; |
95 | void *operator new(decltype(sizeof(0)), nothrow_t) noexcept; |
96 | |
97 | namespace PotentiallyConstructed { |
98 | template<bool NE> struct A { |
99 | A() noexcept(NE); |
100 | A(const A&) noexcept(NE); |
101 | A(A&&) noexcept(NE); |
102 | A &operator=(const A&) noexcept(NE); |
103 | A &operator=(A&&) noexcept(NE); |
104 | ~A() noexcept(NE); |
105 | }; |
106 | |
107 | template<bool NE> struct B : virtual A<NE> {}; |
108 | |
109 | template<bool NE> struct C : virtual A<NE> { |
110 | virtual void f() = 0; // expected-note 2{{unimplemented}} |
111 | }; |
112 | |
113 | template<bool NE> struct D final : C<NE> { |
114 | void f(); |
115 | }; |
116 | |
117 | template<typename T, bool A, bool B, bool C, bool D, bool E, bool F> void check() { |
118 | T *p = nullptr; |
119 | T &a = *p; |
120 | static_assert(noexcept(a = a) == D, ""); |
121 | static_assert(noexcept(a = static_cast<T&&>(a)) == E, ""); |
122 | static_assert(noexcept(delete &a) == F, ""); |
123 | |
124 | // These are last because the first failure here causes instantiation to bail out. |
125 | static_assert(noexcept(new (nothrow) T()) == A, ""); // expected-error 2{{abstract}} |
126 | static_assert(noexcept(new (nothrow) T(a)) == B, ""); |
127 | static_assert(noexcept(new (nothrow) T(static_cast<T&&>(a))) == C, ""); |
128 | } |
129 | |
130 | template void check<A<false>, 0, 0, 0, 0, 0, 0>(); |
131 | template void check<A<true >, 1, 1, 1, 1, 1, 1>(); |
132 | template void check<B<false>, 0, 0, 0, 0, 0, 0>(); |
133 | template void check<B<true >, 1, 1, 1, 1, 1, 1>(); |
134 | template void check<C<false>, 1, 1, 1, 0, 0, 0>(); // expected-note {{instantiation}} |
135 | template void check<C<true >, 1, 1, 1, 1, 1, 1>(); // expected-note {{instantiation}} |
136 | template void check<D<false>, 0, 0, 0, 0, 0, 0>(); |
137 | template void check<D<true >, 1, 1, 1, 1, 1, 1>(); |
138 | |
139 | // ... the above trick doesn't work for this case... |
140 | struct Cfalse : virtual A<false> { |
141 | virtual void f() = 0; |
142 | |
143 | Cfalse() noexcept; |
144 | Cfalse(const Cfalse&) noexcept; |
145 | Cfalse(Cfalse&&) noexcept; |
146 | }; |
147 | Cfalse::Cfalse() noexcept = default; |
148 | Cfalse::Cfalse(const Cfalse&) noexcept = default; |
149 | Cfalse::Cfalse(Cfalse&&) noexcept = default; |
150 | } |
151 | |