riccibruno updated this revision to Diff 195076. riccibruno added a comment.
Also test that typedef-names and using-declarations are not considered. Repository: rC Clang CHANGES SINCE LAST ACTION https://reviews.llvm.org/D60570/new/ https://reviews.llvm.org/D60570 Files: test/CXX/basic/basic.lookup/basic.lookup.argdep/p2-associated-namespaces-classes.cpp test/CXX/basic/basic.lookup/basic.lookup.argdep/p2-inline-namespace.cpp test/CXX/basic/basic.lookup/basic.lookup.argdep/p2.cpp test/CXX/basic/basic.lookup/basic.lookup.argdep/p3.cpp test/CXX/basic/basic.lookup/basic.lookup.argdep/p4.cpp
Index: test/CXX/basic/basic.lookup/basic.lookup.argdep/p4.cpp =================================================================== --- test/CXX/basic/basic.lookup/basic.lookup.argdep/p4.cpp +++ test/CXX/basic/basic.lookup/basic.lookup.argdep/p4.cpp @@ -67,3 +67,96 @@ foo(a, 10); // expected-error {{no matching function for call to 'foo'}} } } + + +// Check the rules described in p4: +// When considering an associated namespace, the lookup is the same as the lookup +// performed when the associated namespace is used as a qualifier (6.4.3.2) except that: + +// - Any using-directives in the associated namespace are ignored. +namespace test_using_directives { + namespace M { struct S; } + namespace N { + void f(M::S); // expected-note {{declared here}} + } + namespace M { + using namespace N; + struct S {}; + } + void test() { + M::S s; + f(s); // expected-error {{use of undeclared}} + M::f(s); // ok + } +} + +// - Any namespace-scope friend functions or friend function templates declared in +// associated classes are visible within their respective namespaces even if +// they are not visible during an ordinary lookup +// (Note: For the friend declaration to be visible, the corresponding class must be +// included in the set of associated classes. Merely including the namespace in +// the set of associated namespaces is not enough.) +namespace test_friend1 { + namespace N { + struct S; + struct T { + friend void f(S); // #1 + }; + struct S { S(); S(T); }; + } + + void test() { + N::S s; + N::T t; + f(s); // expected-error {{use of undeclared}} + f(t); // ok, #1 + } +} + +// credit: Arthur O’Dwyer +namespace test_friend2 { + struct A { + struct B { + struct C {}; + }; + friend void foo(...); // #1 + }; + + struct D { + friend void foo(...); // #2 + }; + template<class> struct E { + struct F {}; + }; + + template<class> struct G {}; + template<class> struct H {}; + template<class> struct I {}; + struct J { friend void foo(...) {} }; // #3 + + void test() { + A::B::C c; + foo(c); // #1 is not visible since A is not an associated class + // expected-error@-1 {{use of undeclared}} + E<D>::F f; + foo(f); // #2 is not visible since D is not an associated class + // expected-error@-1 {{use of undeclared}} + G<H<I<J> > > j; + foo(j); // ok, #3. + } +} + +// - All names except those of (possibly overloaded) functions and +// function templates are ignored. +namespace test_other_names { + namespace N { + struct S {}; + struct Callable { void operator()(S); }; + static struct Callable Callable; + } + + void test() { + N::S s; + Callable(s); // expected-error {{use of undeclared}} + } +} Index: test/CXX/basic/basic.lookup/basic.lookup.argdep/p3.cpp =================================================================== --- test/CXX/basic/basic.lookup/basic.lookup.argdep/p3.cpp +++ test/CXX/basic/basic.lookup/basic.lookup.argdep/p3.cpp @@ -18,3 +18,67 @@ } }; } + +// If X contains [...] then Y is empty. +// - a declaration of a class member +namespace test_adl_suppression_by_class_member { + namespace N { + struct T {}; + void f(T); // expected-note {{declared here}} + } + struct S { + void f(); + void test() { + N::T t; + f(t); // expected-error {{too many arguments}} + } + }; +} + +// - a block-scope function declaration that is not a using-declaration +namespace test_adl_suppression_by_block_scope { + namespace N { + struct S {}; + void f(S); + } + namespace M { void f(int); } // expected-note 2{{candidate}} + void test1() { + N::S s; + using M::f; + f(s); // ok + } + + void test2() { + N::S s; + extern void f(char); // expected-note {{passing argument to parameter here}} + f(s); // expected-error {{no viable conversion from 'N::S' to 'char'}} + } + + void test3() { + N::S s; + extern void f(char); // expected-note {{candidate}} + using M::f; + f(s); // expected-error {{no matching function}} + } + + void test4() { + N::S s; + using M::f; + extern void f(char); // expected-note {{candidate}} + f(s); // expected-error {{no matching function}} + } + +} + +// - a declaration that is neither a function nor a function template +namespace test_adl_suppression_by_non_function { + namespace N { + struct S {}; + void f(S); + } + void test() { + extern void (*f)(); + N::S s; + f(s); // expected-error {{too many arguments}} + } +} Index: test/CXX/basic/basic.lookup/basic.lookup.argdep/p2.cpp =================================================================== --- test/CXX/basic/basic.lookup/basic.lookup.argdep/p2.cpp +++ test/CXX/basic/basic.lookup/basic.lookup.argdep/p2.cpp @@ -132,3 +132,19 @@ test8_function(ref); } } + + + +// [...] Typedef names and using-declarations used to specify the types +// do not contribute to this set. +namespace typedef_names_and_using_declarations { + namespace N { struct S {}; void f(S); } + namespace M { typedef N::S S; void g1(S); } // expected-note {{declared here}} + namespace L { using N::S; void g2(S); } // expected-note {{declared here}} + void test() { + M::S s; + f(s); // ok + g1(s); // expected-error {{use of undeclared}} + g2(s); // expected-error {{use of undeclared}} + } +} Index: test/CXX/basic/basic.lookup/basic.lookup.argdep/p2-inline-namespace.cpp =================================================================== --- /dev/null +++ test/CXX/basic/basic.lookup/basic.lookup.argdep/p2-inline-namespace.cpp @@ -0,0 +1,56 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s + +// C++11 [basic.lookup.argdep]p2 +// +// [...] If an associated namespace is an inline namespace (10.3.1), its +// enclosing namespace is also included in the set. If an associated +// namespace directly contains inline namespaces, those inline namespaces +// are also included in the set. + +namespace test1 { + namespace L { + namespace M { + inline namespace N { + inline namespace O { + struct S {}; + void f1(S); + } + void f2(S); + } + void f3(S); + } + void f4(M::S); // expected-note {{declared here}} + } + + void test() { + L::M::S s; + f1(s); // ok + f2(s); // ok + f3(s); // ok + f4(s); // expected-error {{use of undeclared}} + } +} + +namespace test2 { + namespace L { + struct S {}; + inline namespace M { + inline namespace N { + inline namespace O { + void f1(S); + } + void f2(S); + } + void f3(S); + } + void f4(S); + } + + void test() { + L::S s; + f1(s); // ok + f2(s); // ok + f3(s); // ok + f4(s); // ok + } +} Index: test/CXX/basic/basic.lookup/basic.lookup.argdep/p2-associated-namespaces-classes.cpp =================================================================== --- /dev/null +++ test/CXX/basic/basic.lookup/basic.lookup.argdep/p2-associated-namespaces-classes.cpp @@ -0,0 +1,330 @@ +// 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); // expected-note {{'X2::f' declared here}} + } + void test2() { + f(X2::S{}); // FIXME: This is well-formed; X2 is the innermost enclosing namespace + // of the local struct S. + // expected-error@-2 {{use of undeclared identifier 'f'}} + } + + // 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); // FIXME: This is well-formed. expected-error {{use of undeclared}} + } + } + + // 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); + }; + } + + void test() { + N::E e; + f(e); // ok + N::S::F f; + g(f); // 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}} + static_assert(f(g3) == 4, ""); // FIXME: Also well-formed from the union rule. + // expected-error@-1 {{use of undeclared}} + } +}
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits