145
|
1 // { dg-do compile { target c++11 } }
|
|
2 // Minimized from the testcase for PR c++/88146,
|
|
3 // then turned into multiple variants.
|
|
4
|
|
5 // We issue an error when calling an inherited ctor with at least one
|
|
6 // argument passed through a varargs ellipsis, if the call is in an
|
|
7 // evaluated context. Even in nonevaluated contexts, we will
|
|
8 // instantiate constexpr templates (unlike non-constexpr templates),
|
|
9 // which might then issue errors that in nonevlauated contexts
|
|
10 // wouldn't be issued.
|
|
11
|
|
12 // In these variants, the inherited ctor is constexpr, but it's only
|
|
13 // called in unevaluated contexts, so no error is issued. The
|
|
14 // templateness of the ctor doesn't matter, because the only call that
|
|
15 // passes args through the ellipsis is in a noexcept expr, that is not
|
|
16 // evaluated. The ctors in derived classes are created and
|
|
17 // instantiated, discarding arguments passed through the ellipsis when
|
|
18 // calling base ctors, but that's not reported: we only report a
|
|
19 // problem when *calling* ctors that behave this way.
|
|
20 namespace unevaled_call {
|
|
21 namespace no_arg_before_ellipsis {
|
|
22 namespace without_template {
|
|
23 struct foo {
|
|
24 constexpr foo(...) {}
|
|
25 };
|
|
26 struct boo : foo {
|
|
27 using foo::foo;
|
|
28 };
|
|
29 struct bar : boo {
|
|
30 using boo::boo;
|
|
31 };
|
|
32 void f() noexcept(noexcept(bar{0}));
|
|
33 }
|
|
34
|
|
35 namespace with_template {
|
|
36 struct foo {
|
|
37 template <typename... T>
|
|
38 constexpr foo(...) {}
|
|
39 };
|
|
40 struct boo : foo {
|
|
41 using foo::foo;
|
|
42 };
|
|
43 struct bar : boo {
|
|
44 using boo::boo;
|
|
45 };
|
|
46 void f() noexcept(noexcept(bar{0}));
|
|
47 }
|
|
48 }
|
|
49
|
|
50 namespace one_arg_before_ellipsis {
|
|
51 namespace without_template {
|
|
52 struct foo {
|
|
53 constexpr foo(int, ...) {}
|
|
54 };
|
|
55 struct boo : foo {
|
|
56 using foo::foo;
|
|
57 };
|
|
58 struct bar : boo {
|
|
59 using boo::boo;
|
|
60 };
|
|
61 void f() noexcept(noexcept(bar{0,1}));
|
|
62 }
|
|
63
|
|
64 namespace with_template {
|
|
65 struct foo {
|
|
66 template <typename T>
|
|
67 constexpr foo(T, ...) {}
|
|
68 };
|
|
69 struct boo : foo {
|
|
70 using foo::foo;
|
|
71 };
|
|
72 struct bar : boo {
|
|
73 using boo::boo;
|
|
74 };
|
|
75 void f() noexcept(noexcept(bar{0,1}));
|
|
76 }
|
|
77 }
|
|
78 }
|
|
79
|
|
80 // In these variants, the inherited ctor is constexpr, and it's called
|
|
81 // in unevaluated contexts in ways that would otherwise trigger the
|
|
82 // sorry message. Here we check that the message is not issued at
|
|
83 // those calls, nor at subsequent calls that use the same ctor without
|
|
84 // passing arguments through its ellipsis. We check that it is issued
|
|
85 // later, when we pass the ctor arguments through the ellipsis.
|
|
86 namespace evaled_bad_call_in_u {
|
|
87 namespace one_arg_before_ellipsis {
|
|
88 namespace without_template {
|
|
89 struct foo {
|
|
90 constexpr foo(int, ...) {}
|
|
91 };
|
|
92 struct boo : foo {
|
|
93 using foo::foo;
|
|
94 };
|
|
95 struct bar : boo {
|
|
96 using boo::boo;
|
|
97 };
|
|
98 void f() noexcept(noexcept(bar{0, 1}));
|
|
99 bar t(0);
|
|
100 bar u(0, 1); // { dg-message "sorry, unimplemented: passing arguments to ellipsis" }
|
|
101 }
|
|
102
|
|
103 namespace with_template {
|
|
104 struct foo {
|
|
105 template <typename T>
|
|
106 constexpr foo(T, ...) {}
|
|
107 };
|
|
108 struct boo : foo {
|
|
109 using foo::foo;
|
|
110 };
|
|
111 struct bar : boo {
|
|
112 using boo::boo;
|
|
113 };
|
|
114 void f() noexcept(noexcept(bar{0,1}));
|
|
115 bar t(0);
|
|
116 bar u(0,1); // { dg-message "sorry, unimplemented: passing arguments to ellipsis" }
|
|
117 }
|
|
118 }
|
|
119
|
|
120 namespace no_arg_before_ellipsis {
|
|
121 namespace without_template {
|
|
122 struct foo {
|
|
123 constexpr foo(...) {}
|
|
124 };
|
|
125 struct boo : foo {
|
|
126 using foo::foo;
|
|
127 };
|
|
128 struct bar : boo {
|
|
129 using boo::boo;
|
|
130 };
|
|
131 void f() noexcept(noexcept(bar{0}));
|
|
132 bar u(0); // { dg-message "sorry, unimplemented: passing arguments to ellipsis" }
|
|
133 }
|
|
134
|
|
135 namespace with_template {
|
|
136 struct foo {
|
|
137 template <typename... T>
|
|
138 constexpr foo(...) {}
|
|
139 };
|
|
140 struct boo : foo {
|
|
141 using foo::foo;
|
|
142 };
|
|
143 struct bar : boo {
|
|
144 using boo::boo;
|
|
145 };
|
|
146 void f() noexcept(noexcept(bar{0}));
|
|
147 bar u(0); // { dg-message "sorry, unimplemented: passing arguments to ellipsis" }
|
|
148 }
|
|
149 }
|
|
150 }
|
|
151
|
|
152 // Now, instead of instantiating a class that uses a derived ctor, we
|
|
153 // introduce another template ctor that will use the varargs ctor to
|
|
154 // initialize its base class. The idea is to verify that the error
|
|
155 // message is issued, even if the instantiation occurs in a
|
|
156 // nonevaluated context, e.g., for constexpr templates. In the
|
|
157 // inherited_derived_ctor, we check that even an inherited ctor of a
|
|
158 // constexpr ctor is instantiated and have an error message issued.
|
|
159 namespace derived_ctor {
|
|
160 namespace direct_derived_ctor {
|
|
161 namespace constexpr_noninherited_ctor {
|
|
162 struct foo {
|
|
163 template <typename T>
|
|
164 constexpr foo(T, ...) {}
|
|
165 };
|
|
166 struct boo : foo {
|
|
167 using foo::foo;
|
|
168 };
|
|
169 struct bar : boo {
|
|
170 template <typename ...T>
|
|
171 constexpr bar(T ... args) : boo(args...) {}
|
|
172 };
|
|
173 void f() noexcept(noexcept(bar{0,1}));
|
|
174 }
|
|
175
|
|
176 namespace no_constexpr_noninherited_ctor {
|
|
177 struct foo {
|
|
178 template <typename T>
|
|
179 constexpr foo(T, ...) {}
|
|
180 };
|
|
181 struct boo : foo {
|
|
182 using foo::foo;
|
|
183 };
|
|
184 struct bar : boo {
|
|
185 template <typename ...T>
|
|
186 /* constexpr */ bar(T ... args) : boo(args...) {}
|
|
187 };
|
|
188 void f() noexcept(noexcept(bar{0,1}));
|
|
189 }
|
|
190 }
|
|
191
|
|
192 namespace inherited_derived_ctor {
|
|
193 namespace constexpr_noninherited_ctor {
|
|
194 struct foo {
|
|
195 template <typename T>
|
|
196 constexpr foo(T, ...) {}
|
|
197 };
|
|
198 struct boo : foo {
|
|
199 using foo::foo;
|
|
200 };
|
|
201 struct bor : boo {
|
|
202 template <typename ...T>
|
|
203 constexpr bor(T ... args) : boo(args...) {}
|
|
204 };
|
|
205 struct bar : bor {
|
|
206 using bor::bor;
|
|
207 };
|
|
208 void f() noexcept(noexcept(bar{0,1}));
|
|
209 }
|
|
210
|
|
211 namespace no_constexpr_noninherited_ctor {
|
|
212 struct foo {
|
|
213 template <typename T>
|
|
214 constexpr foo(T, ...) {}
|
|
215 };
|
|
216 struct boo : foo {
|
|
217 using foo::foo;
|
|
218 };
|
|
219 struct bor : boo {
|
|
220 template <typename ...T>
|
|
221 /* constexpr */ bor(T ... args) : boo(args...) {}
|
|
222 };
|
|
223 struct bar : bor {
|
|
224 using bor::bor;
|
|
225 };
|
|
226 void f() noexcept(noexcept(bar{0,1}));
|
|
227 }
|
|
228 }
|
|
229 }
|