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 {
foofoo24 	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>
foofoo38 	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 {
foofoo53 	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>
foofoo67 	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 {
foofoo90 	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>
foofoo106 	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 {
foofoo123 	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>
foofoo138 	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>
foofoo164 	constexpr foo(T, ...) {}
165       };
166       struct boo : foo {
167 	using foo::foo;
168       };
169       struct bar : boo {
170 	template <typename ...T>
barbar171 	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>
foofoo179 	constexpr foo(T, ...) {}
180       };
181       struct boo : foo {
182 	using foo::foo;
183       };
184       struct bar : boo {
185 	template <typename ...T>
barbar186 	/* 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>
foofoo196 	constexpr foo(T, ...) {}
197       };
198       struct boo : foo {
199 	using foo::foo;
200       };
201       struct bor : boo {
202 	template <typename ...T>
borbor203 	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>
foofoo214 	constexpr foo(T, ...) {}
215       };
216       struct boo : foo {
217 	using foo::foo;
218       };
219       struct bor : boo {
220 	template <typename ...T>
borbor221 	/* 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 }
230