345 lines · cpp
1// RUN: %clang_cc1 -fsyntax-only -verify -std=c++17 %s2 3// Attempt to test each rule for forming associated namespaces4// and classes as described in [basic.lookup.argdep]p2.5 6// fundamental type: no associated namespace and no associated class7namespace adl_fundamental_type {8 constexpr int g(char) { return 1; } // #19 template <typename T> constexpr int foo(T t) { return g(t); }10 constexpr int g(int) { return 2; } // #2 not found11 void test() {12 static_assert(foo(0) == 1); // ok, #113 }14}15 16// class type:17// associated classes: itself, the class of which it is a member (if any),18// direct and indirect base classes19// associated namespaces: innermost enclosing namespaces of associated classes20namespace adl_class_type {21 // associated class: itself, simple case22 namespace X1 {23 namespace N {24 struct S {};25 void f(S); // found26 }27 void g(N::S); // not found28 };29 void test1() {30 f(X1::N::S{}); // ok31 g(X1::N::S{}); // expected-error {{use of undeclared identifier}}32 }33 34 // associated class: itself, local type35 namespace X2 {36 auto foo() {37 struct S {} s;38 return s;39 }40 using S = decltype(foo());41 void f(S); // #142 }43 void test2() {44 f(X2::S{}); // This is well-formed; X2 is the innermost enclosing namespace45 // of the local struct S. Calls #1.46 }47 48 // associated class: the parent class49 namespace X3 {50 struct S {51 struct T {};52 friend void f(T);53 };54 }55 void test3() {56 f(X3::S::T{}); // ok57 }58 59 // associated class: direct and indirect base classes60 namespace X4 {61 namespace IndirectBaseNamespace {62 struct IndirectBase {};63 void f(IndirectBase); // #164 }65 namespace DirectBaseNamespace {66 struct DirectBase : IndirectBaseNamespace::IndirectBase {};67 void g(DirectBase); // #268 }69 struct S : DirectBaseNamespace::DirectBase {};70 }71 void test4() {72 f(X4::S{}); // ok, #173 g(X4::S{}); // ok, #274 }75 76 // associated class: itself, lambda77 namespace X5 {78 namespace N {79 auto get_lambda() { return [](){}; }80 void f(decltype(get_lambda()));81 }82 83 void test5() {84 auto lambda = N::get_lambda();85 f(lambda); // ok86 }87 }88 89 // The parameter types and return type of a lambda's operator() do not90 // contribute to the associated namespaces and classes of the lambda itself.91 namespace X6 {92 namespace N {93 struct A {};94 template<class T> constexpr int f(T) { return 1; }95 }96 97 constexpr int f(N::A (*)()) { return 2; }98 constexpr int f(void (*)(N::A)) { return 3; }99 100 void test() {101 constexpr auto lambda = []() -> N::A { return {}; };102 static_assert(f(lambda) == 2);103 104 constexpr auto lambda2 = [](N::A) {};105 static_assert(f(lambda2) == 3);106 }107 }108} // namespace adl_class_type109 110// class template specialization: as for class type plus111// for non-type template arguments:112// - nothing113// for type template arguments:114// - associated namespaces and classes of the type template arguments115// for template template arguments:116// - namespaces of which template template arguments are member of117// - classes of which member template used as template template arguments118// are member of119namespace adl_class_template_specialization_type {120 // non-type template argument121 namespace X1 {122 namespace BaseNamespace { struct Base {}; }123 namespace N { struct S : BaseNamespace::Base {}; }124 template <N::S *> struct C {};125 namespace N {126 template <S *p> void X1_f(C<p>); // #1127 }128 namespace BaseNamespace {129 template <N::S *p> void X1_g(C<p>); // #2130 }131 template <N::S *p> void X1_h(C<p>); // #3132 }133 void test1() {134 constexpr X1::N::S *p = nullptr;135 X1::C<p> c;136 X1_f(c); // N is not added to the set of associated namespaces137 // and #1 is not found...138 // expected-error@-2 {{use of undeclared identifier}}139 X1_g(c); // ... nor is #2 ...140 // expected-error@-1 {{use of undeclared identifier}}141 X1_h(c); // ... but the namespace X1 is added and #3 is found.142 }143 144 // type template argument145 namespace X2 {146 template <typename T> struct C {};147 namespace BaseNamespace { struct Base {}; }148 namespace N { struct S : BaseNamespace::Base {}; }149 namespace N {150 template <typename T> void X2_f(C<T>); // #1151 }152 namespace BaseNamespace {153 template <typename T> void X2_g(C<T>); // #2154 }155 template <typename T> void X2_h(C<T>); // #2156 }157 void test2() {158 X2::C<X2::N::S> c;159 X2_f(c); // N is added to the set of associated namespaces and #1 is found.160 X2_g(c); // Similarly BaseNamespace is added and #2 is found.161 X2_h(c); // As before, X2 is also added and #3 is found.162 }163 164 // template template argument165 namespace X3 {166 template <template <typename> class TT> struct C {};167 namespace N {168 template <typename T> struct Z {};169 void X3_f(C<Z>); // #1170 }171 struct M {172 template <typename T> struct Z {};173 friend void X3_g(C<Z>); // #2174 };175 }176 void test3() {177 X3::C<X3::N::Z> c1;178 X3::C<X3::M::Z> c2;179 X3_f(c1); // ok, namespace N is added, #1180 X3_g(c2); // ok, struct M is added, #2181 }182}183 184// enumeration type:185// associated namespace: innermost enclosing namespace of its declaration.186// associated class: if the enumeration is a class member, the member's class.187namespace adl_enumeration_type {188 namespace N {189 enum E : int;190 void f(E);191 struct S {192 enum F : int;193 friend void g(F);194 };195 auto foo() {196 enum G {} g;197 return g;198 }199 using G = decltype(foo());200 void h(G);201 }202 203 void test() {204 N::E e;205 f(e); // ok206 N::S::F f;207 g(f); // ok208 N::G g;209 h(g); // ok210 211 }212}213 214// pointer and reference type:215// associated namespaces and classes of the pointee type216// array type:217// associated namespaces and classes of the base type218namespace adl_point_array_reference_type {219 namespace N {220 struct S {};221 void f(S *);222 void f(S &);223 }224 225 void test() {226 N::S *p;227 f(p); // ok228 extern N::S &r;229 f(r); // ok230 N::S a[2];231 f(a); // ok232 }233}234 235// function type:236// associated namespaces and classes of the function parameter types237// and the return type.238namespace adl_function_type {239 namespace M { struct T; }240 namespace N {241 struct S {};242 void f(S (*)(M::T));243 };244 namespace M {245 struct T {};246 void g(N::S (*)(T));247 }248 249 void test() {250 extern N::S x(M::T);251 f(x); // ok252 g(x); // ok253 }254}255 256// pointer to member function:257// associated namespaces and classes of the class, parameter types258// and return type.259namespace adl_pointer_to_member_function {260 namespace M { struct C; }261 namespace L { struct T; }262 namespace N {263 struct S {};264 void f(N::S (M::C::*)(L::T));265 }266 namespace L {267 struct T {};268 void g(N::S (M::C::*)(L::T));269 }270 namespace M {271 struct C {};272 void h(N::S (M::C::*)(L::T));273 }274 275 void test() {276 N::S (M::C::*p)(L::T);277 f(p); // ok278 g(p); // ok279 h(p); // ok280 }281}282 283// pointer to member:284// associated namespaces and classes of the class and of the member type.285namespace adl_pointer_to_member {286 namespace M { struct C; }287 namespace N {288 struct S {};289 void f(N::S (M::C::*));290 }291 namespace M {292 struct C {};293 void g(N::S (M::C::*));294 }295 296 void test() {297 N::S (M::C::*p);298 f(p); // ok299 g(p); // ok300 }301}302 303// [...] if the argument is the name or address of a set of overloaded304// functions and/or function templates, its associated classes and namespaces305// are the union of those associated with each of the members of the set,306// i.e., the classes and namespaces associated with its parameter types and307// return type.308//309// Additionally, if the aforementioned set of overloaded functions is named310// with a template-id, its associated classes and namespaces also include311// those of its type template-arguments and its template template-arguments.312//313// CWG 33 for the union rule. CWG 997 for the template-id rule.314namespace adl_overload_set {315 namespace N {316 struct S {};317 constexpr int f(int (*g)()) { return g(); }318 // expected-note@-1 2{{'N::f' declared here}}319 template <typename T> struct Q;320 }321 322 constexpr int g1() { return 1; }323 constexpr int g1(N::S) { return 2; }324 325 template <typename T> constexpr int g2() { return 3; }326 327 // Inspired from CWG 997.328 constexpr int g3() { return 4; }329 template <typename T> constexpr int g3(T, N::Q<T>) { return 5; }330 331 void test() {332 static_assert(f(g1) == 1, ""); // Well-formed from the union rule above333 static_assert(f(g2<N::S>) == 3, ""); // FIXME: Well-formed from the template-id rule above.334 // expected-error@-1 {{use of undeclared}}335 336 // A objection was raised during review against implementing the337 // template-id rule. Currently only GCC implements it. Implementing338 // it would weaken the argument to remove it in the future since339 // actual real code might start to depend on it.340 341 static_assert(f(g3) == 4, ""); // FIXME: Also well-formed from the union rule.342 // expected-error@-1 {{use of undeclared}}343 }344}345