diff options
Diffstat (limited to 'test/CXX/basic/basic.lookup/basic.lookup.argdep/p2-associated-namespaces-classes.cpp')
-rw-r--r-- | test/CXX/basic/basic.lookup/basic.lookup.argdep/p2-associated-namespaces-classes.cpp | 344 |
1 files changed, 344 insertions, 0 deletions
diff --git a/test/CXX/basic/basic.lookup/basic.lookup.argdep/p2-associated-namespaces-classes.cpp b/test/CXX/basic/basic.lookup/basic.lookup.argdep/p2-associated-namespaces-classes.cpp new file mode 100644 index 0000000000..7562e64b17 --- /dev/null +++ b/test/CXX/basic/basic.lookup/basic.lookup.argdep/p2-associated-namespaces-classes.cpp @@ -0,0 +1,344 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -std=c++17 %s + +// Attempt to test each rule for forming associated namespaces +// and classes as described in [basic.lookup.argdep]p2. + +// fundamental type: no associated namespace and no associated class +namespace adl_fundamental_type { + constexpr int g(char) { return 1; } // #1 + template <typename T> constexpr int foo(T t) { return g(t); } + constexpr int g(int) { return 2; } // #2 not found + void test() { + static_assert(foo(0) == 1); // ok, #1 + } +} + +// class type: +// associated classes: itself, the class of which it is a member (if any), +// direct and indirect base classes +// associated namespaces: innermost enclosing namespaces of associated classes +namespace adl_class_type { + // associated class: itself, simple case + namespace X1 { + namespace N { + struct S {}; + void f(S); // found + } + void g(N::S); // not found + }; + void test1() { + f(X1::N::S{}); // ok + g(X1::N::S{}); // expected-error {{use of undeclared identifier}} + } + + // associated class: itself, local type + namespace X2 { + auto foo() { + struct S {} s; + return s; + } + using S = decltype(foo()); + void f(S); // #1 + } + void test2() { + f(X2::S{}); // This is well-formed; X2 is the innermost enclosing namespace + // of the local struct S. Calls #1. + } + + // associated class: the parent class + namespace X3 { + struct S { + struct T {}; + friend void f(T); + }; + } + void test3() { + f(X3::S::T{}); // ok + } + + // associated class: direct and indirect base classes + namespace X4 { + namespace IndirectBaseNamespace { + struct IndirectBase {}; + void f(IndirectBase); // #1 + } + namespace DirectBaseNamespace { + struct DirectBase : IndirectBaseNamespace::IndirectBase {}; + void g(DirectBase); // #2 + } + struct S : DirectBaseNamespace::DirectBase {}; + } + void test4() { + f(X4::S{}); // ok, #1 + g(X4::S{}); // ok, #2 + } + + // associated class: itself, lambda + namespace X5 { + namespace N { + auto get_lambda() { return [](){}; } + void f(decltype(get_lambda())); + } + + void test5() { + auto lambda = N::get_lambda(); + f(lambda); // ok + } + } + + // The parameter types and return type of a lambda's operator() do not + // contribute to the associated namespaces and classes of the lambda itself. + namespace X6 { + namespace N { + struct A {}; + template<class T> constexpr int f(T) { return 1; } + } + + constexpr int f(N::A (*)()) { return 2; } + constexpr int f(void (*)(N::A)) { return 3; } + + void test() { + constexpr auto lambda = []() -> N::A { return {}; }; + static_assert(f(lambda) == 2); + + constexpr auto lambda2 = [](N::A) {}; + static_assert(f(lambda2) == 3); + } + } +} // namespace adl_class_type + +// class template specialization: as for class type plus +// for non-type template arguments: +// - nothing +// for type template arguments: +// - associated namespaces and classes of the type template arguments +// for template template arguments: +// - namespaces of which template template arguments are member of +// - classes of which member template used as template template arguments +// are member of +namespace adl_class_template_specialization_type { + // non-type template argument + namespace X1 { + namespace BaseNamespace { struct Base {}; } + namespace N { struct S : BaseNamespace::Base {}; } + template <N::S *> struct C {}; + namespace N { + template <S *p> void X1_f(C<p>); // #1 + } + namespace BaseNamespace { + template <N::S *p> void X1_g(C<p>); // #2 + } + template <N::S *p> void X1_h(C<p>); // #3 + } + void test1() { + constexpr X1::N::S *p = nullptr; + X1::C<p> c; + X1_f(c); // N is not added to the set of associated namespaces + // and #1 is not found... + // expected-error@-2 {{use of undeclared identifier}} + X1_g(c); // ... nor is #2 ... + // expected-error@-1 {{use of undeclared identifier}} + X1_h(c); // ... but the namespace X1 is added and #3 is found. + } + + // type template argument + namespace X2 { + template <typename T> struct C {}; + namespace BaseNamespace { struct Base {}; } + namespace N { struct S : BaseNamespace::Base {}; } + namespace N { + template <typename T> void X2_f(C<T>); // #1 + } + namespace BaseNamespace { + template <typename T> void X2_g(C<T>); // #2 + } + template <typename T> void X2_h(C<T>); // #2 + } + void test2() { + X2::C<X2::N::S> c; + X2_f(c); // N is added to the set of associated namespaces and #1 is found. + X2_g(c); // Similarly BaseNamespace is added and #2 is found. + X2_h(c); // As before, X2 is also added and #3 is found. + } + + // template template argument + namespace X3 { + template <template <typename> class TT> struct C {}; + namespace N { + template <typename T> struct Z {}; + void X3_f(C<Z>); // #1 + } + struct M { + template <typename T> struct Z {}; + friend void X3_g(C<Z>); // #2 + }; + } + void test3() { + X3::C<X3::N::Z> c1; + X3::C<X3::M::Z> c2; + X3_f(c1); // ok, namespace N is added, #1 + X3_g(c2); // ok, struct M is added, #2 + } +} + +// enumeration type: +// associated namespace: innermost enclosing namespace of its declaration. +// associated class: if the enumeration is a class member, the member's class. +namespace adl_enumeration_type { + namespace N { + enum E : int; + void f(E); + struct S { + enum F : int; + friend void g(F); + }; + auto foo() { + enum G {} g; + return g; + } + using G = decltype(foo()); + void h(G); + } + + void test() { + N::E e; + f(e); // ok + N::S::F f; + g(f); // ok + N::G g; + h(g); // ok + + } +} + +// pointer and reference type: +// associated namespaces and classes of the pointee type +// array type: +// associated namespaces and classes of the base type +namespace adl_point_array_reference_type { + namespace N { + struct S {}; + void f(S *); + void f(S &); + } + + void test() { + N::S *p; + f(p); // ok + extern N::S &r; + f(r); // ok + N::S a[2]; + f(a); // ok + } +} + +// function type: +// associated namespaces and classes of the function parameter types +// and the return type. +namespace adl_function_type { + namespace M { struct T; } + namespace N { + struct S {}; + void f(S (*)(M::T)); + }; + namespace M { + struct T {}; + void g(N::S (*)(T)); + } + + void test() { + extern N::S x(M::T); + f(x); // ok + g(x); // ok + } +} + +// pointer to member function: +// associated namespaces and classes of the class, parameter types +// and return type. +namespace adl_pointer_to_member_function { + namespace M { struct C; } + namespace L { struct T; } + namespace N { + struct S {}; + void f(N::S (M::C::*)(L::T)); + } + namespace L { + struct T {}; + void g(N::S (M::C::*)(L::T)); + } + namespace M { + struct C {}; + void h(N::S (M::C::*)(L::T)); + } + + void test() { + N::S (M::C::*p)(L::T); + f(p); // ok + g(p); // ok + h(p); // ok + } +} + +// pointer to member: +// associated namespaces and classes of the class and of the member type. +namespace adl_pointer_to_member { + namespace M { struct C; } + namespace N { + struct S {}; + void f(N::S (M::C::*)); + } + namespace M { + struct C {}; + void g(N::S (M::C::*)); + } + + void test() { + N::S (M::C::*p); + f(p); // ok + g(p); // ok + } +} + +// [...] if the argument is the name or address of a set of overloaded +// functions and/or function templates, its associated classes and namespaces +// are the union of those associated with each of the members of the set, +// i.e., the classes and namespaces associated with its parameter types and +// return type. +// +// Additionally, if the aforementioned set of overloaded functions is named +// with a template-id, its associated classes and namespaces also include +// those of its type template-arguments and its template template-arguments. +// +// CWG 33 for the union rule. CWG 997 for the template-id rule. +namespace adl_overload_set { + namespace N { + struct S {}; + constexpr int f(int (*g)()) { return g(); } + // expected-note@-1 2{{'N::f' declared here}} + template <typename T> struct Q; + } + + constexpr int g1() { return 1; } + constexpr int g1(N::S) { return 2; } + + template <typename T> constexpr int g2() { return 3; } + + // Inspired from CWG 997. + constexpr int g3() { return 4; } + template <typename T> constexpr int g3(T, N::Q<T>) { return 5; } + + void test() { + static_assert(f(g1) == 1, ""); // Well-formed from the union rule above + static_assert(f(g2<N::S>) == 3, ""); // FIXME: Well-formed from the template-id rule above. + // expected-error@-1 {{use of undeclared}} + + // A objection was raised during review against implementing the + // template-id rule. Currently only GCC implements it. Implementing + // it would weaken the argument to remove it in the future since + // actual real code might start to depend on it. + + static_assert(f(g3) == 4, ""); // FIXME: Also well-formed from the union rule. + // expected-error@-1 {{use of undeclared}} + } +} |