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