r358881 - [Sema][NFC] Add more tests for the behavior of argument-dependent name lookup
Bruno Ricci via cfe-commits
cfe-commits at lists.llvm.org
Mon Apr 22 04:40:31 PDT 2019
Author: brunoricci
Date: Mon Apr 22 04:40:31 2019
New Revision: 358881
URL: http://llvm.org/viewvc/llvm-project?rev=358881&view=rev
Log:
[Sema][NFC] Add more tests for the behavior of argument-dependent name lookup
The goal here is to exercise each rule in [basic.lookup.argdep] at least once.
These new tests expose what I believe are 2 issues:
1. CWG 1691 needs to be implemented (p2: [...] Its associated namespaces are
the innermost enclosing namespaces of its associated classes [...]) The
corresponding tests are adl_class_type::X2 and adl_class_type::X5.
2. The end of paragraph 2 ([...] 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.) is not implemented. Closely related, the
restriction on non-dependent parameter types in this same paragraph needs
to be removed. The corresponding tests are in adl_overload_set (both issues
are from CWG 997).
Differential Revision: https://reviews.llvm.org/D60570
Reviewed By: riccibruno, Quuxplusone
Added:
cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.argdep/p2-associated-namespaces-classes.cpp
cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.argdep/p2-inline-namespace.cpp
Modified:
cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.argdep/p2.cpp
cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.argdep/p3.cpp
cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.argdep/p4.cpp
Added: cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.argdep/p2-associated-namespaces-classes.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.argdep/p2-associated-namespaces-classes.cpp?rev=358881&view=auto
==============================================================================
--- cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.argdep/p2-associated-namespaces-classes.cpp (added)
+++ cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.argdep/p2-associated-namespaces-classes.cpp Mon Apr 22 04:40:31 2019
@@ -0,0 +1,336 @@
+// 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 at -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 at -2 {{use of undeclared identifier}}
+ X1_g(c); // ... nor is #2 ...
+ // expected-error at -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 at -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 at -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 at -1 {{use of undeclared}}
+ }
+}
Added: cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.argdep/p2-inline-namespace.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.argdep/p2-inline-namespace.cpp?rev=358881&view=auto
==============================================================================
--- cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.argdep/p2-inline-namespace.cpp (added)
+++ cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.argdep/p2-inline-namespace.cpp Mon Apr 22 04:40:31 2019
@@ -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
+ }
+}
Modified: cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.argdep/p2.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.argdep/p2.cpp?rev=358881&r1=358880&r2=358881&view=diff
==============================================================================
--- cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.argdep/p2.cpp (original)
+++ cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.argdep/p2.cpp Mon Apr 22 04:40:31 2019
@@ -132,3 +132,19 @@ namespace test8 {
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}}
+ }
+}
Modified: cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.argdep/p3.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.argdep/p3.cpp?rev=358881&r1=358880&r2=358881&view=diff
==============================================================================
--- cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.argdep/p3.cpp (original)
+++ cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.argdep/p3.cpp Mon Apr 22 04:40:31 2019
@@ -18,3 +18,67 @@ namespace test0 {
}
};
}
+
+// 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}}
+ }
+}
Modified: cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.argdep/p4.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.argdep/p4.cpp?rev=358881&r1=358880&r2=358881&view=diff
==============================================================================
--- cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.argdep/p4.cpp (original)
+++ cfe/trunk/test/CXX/basic/basic.lookup/basic.lookup.argdep/p4.cpp Mon Apr 22 04:40:31 2019
@@ -67,3 +67,96 @@ namespace test1 {
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 at -1 {{use of undeclared}}
+ E<D>::F f;
+ foo(f); // #2 is not visible since D is not an associated class
+ // expected-error at -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}}
+ }
+}
More information about the cfe-commits
mailing list