[PATCH] D60570: [Sema] Add more tests for the behavior of argument-dependent name lookup

Bruno Ricci via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Sun Apr 14 06:03:49 PDT 2019


riccibruno marked 11 inline comments as done.
riccibruno added a comment.

In D60570#1465478 <https://reviews.llvm.org/D60570#1465478>, @Quuxplusone wrote:

> As you're making tests for ADL corner cases, you might also consider testing the interactions between ADL and defaulted function parameters, e.g. https://godbolt.org/z/vHnyFl
>  It looks like everyone (except MSVC) already gets that stuff right (or at least portable-between-the-big-three). I bet the behavior naturally falls out of some other rules; you might say "there's no way that could possibly break, so we don't need to test it," and I'd accept that.


I think that as you say this falls out of the other rules.



================
Comment at: test/CXX/basic/basic.lookup/basic.lookup.argdep/p2-associated-namespaces-classes.cpp:77
+
+  // associated class: itself, lambda
+  namespace X5 {
----------------
Quuxplusone wrote:
> Do you also have a test somewhere to verify that the parameter and return types of a lambda's `operator()` do not contribute to the associated types of the lambda type itself? That is,
> ```
> // https://godbolt.org/z/g_oMOA
> 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);
> }
> ```
> Clang does handle this correctly; I'm just asking for it to be tested, if it's not already. (I might have overlooked an existing test.)
I am not sure, but I see no harm in adding it here.


================
Comment at: test/CXX/basic/basic.lookup/basic.lookup.argdep/p2-associated-namespaces-classes.cpp:144
+
+  // template template argument
+  namespace X3 {
----------------
Quuxplusone wrote:
> I think for completeness there should be a "negative test" for non-type template arguments:
> ```
>   namespace X4 {
>     template <auto NT> struct C {};
>     namespace N {
>       struct Z {
>           enum E { E0 };
>           void X4_f(C<E::E0>);
>       };
>       enum E { E0 };
>       void X4_g(C<E::E0>);
>     }
>   }
>   void test4() {
>     X4::C<X4::N::E::E0> c1;
>     X4::C<X4::N::Z::E::E0> c2;
>     X4_f(c1); // expected-error{{undeclared identifier 'X4_f'}}
>     X4_g(c2); // expected-error{{undeclared identifier 'X4_g'}}
>   }
> ```
> In C++2a, user-defined NTTPs will become possible, so we'll want another test for something like
> ```
>   // https://godbolt.org/z/MfWG8C
>   namespace X4 {
>     template<auto NT> struct C {};
>     namespace N {
>       struct Z {
>         int i;
>         constexpr Z(int i): i(i) {}
>         auto operator<=>(const Z&) const = default;
>       };
>       void X4_f(C<Z(0)>);
>     }
>   }
>   void test4() {
>     X4::C<X4::N::Z(0)> c1;
>     X4_f(c1); // expected-error{{undeclared identifier 'X4_f'}}
>   }
> ```
Isn't that already covered by the test in `adl_class_template_specialization_type::X1` ? I agree that a test for class type NTTP will be needed in C++2a, but for now this feature is not yet implemented.


================
Comment at: test/CXX/basic/basic.lookup/basic.lookup.argdep/p2-associated-namespaces-classes.cpp:304
+    static_assert(f(g3) == 4, "");        // FIXME: Also well-formed from the union rule.
+                                          // expected-error at -1 {{use of undeclared}}
+  }
----------------
Quuxplusone wrote:
> riccibruno wrote:
> > Quuxplusone wrote:
> > > I see how `g3` matches the example in CWG997
> > > http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#997
> > > However, I don't see how CWG997's resolution actually affected this example in the slightest. The wording inserted for CWG997 was, "Additionally, if the aforementioned set of overloaded functions is named with a template-id, its associated classes and namespaces are those of its type template-arguments and its template template-arguments." That makes e.g.
> > > 
> > >     f(g3<N::S>)
> > > 
> > > consider `N::f`, because `N::S` is a "type template-argument" of the template-id `g3<N::S>` which names the set of overloaded functions.  But it doesn't do anything at all to `f(g3)` because `g3` is not a template-id and doesn't have any template-arguments.
> > > 
> > > This piece of ADL is implemented only by GCC (not EDG, Clang, or MSVC), and personally I would very much like to keep it that way. We know there's no real-world code that expects or relies on CWG997 — because such code would never work in practice except on GCC. Let's keep it that way!  As soon as you implement a crazy arcane rule, such that code _could_ portably rely on it, code _will start_ relying on it... and then we'll never be able to simplify the language.
> > > Case in point: the piece of ADL described in this blog post --
> > > https://quuxplusone.github.io/blog/2019/04/09/adl-insanity-round-2/
> > > As soon as the above-described arcane ADL rule was implemented in GCC and Clang, Boost.Hana started relying on it; and now the rule is "locked in" to the paper standard because there's real-world code relying on it.
> > > Personally I'd like to _keep_ real-world code from relying on CWG997, until someone figures out what CWG was thinking when they added it.
> > I think that the relevant part of CWG 997 is the removal of the restriction on non-dependent parameter types. Sure, `g3` is not a `template-id`, but it refers to an overload set which contains the second `g3`, and one of the parameter of this second `g3` is `N::Q<T>`.
> > 
> > I don't think this is a surprising rule. It matches the general intuition that for function types ADL is done based on the function parameter types and return type. Not having this rule introduces a difference between function templates and functions in overload sets. Consider https://godbolt.org/z/UXHqm2 :
> > ```
> > namespace N {
> >     struct S1 {};
> >     template <typename> struct S2 {};
> > 
> >     void f(void (*g)());
> > }
> > 
> > void g1();          // #1
> > void g1(N::S1);     // #2
> > 
> > void g2();                                  // #3
> > template <typename T> void g2(N::S2<T>);    // #4
> > 
> > void test() {
> >     f(g1); // ok, g1 is #1
> >     f(g2); // should be ok, g2 is #3
> > }
> > ```
> > I think that the relevant part of CWG 997 is the removal of the restriction on non-dependent parameter types.
> 
> Ah, I had missed the removal of the word `(non-dependent)` in my reading of CWG997. So just that one-word removal is what fixed their example, and is what you're testing with `g3`.
> 
> I still object to `g2` — I would like that `FIXME` to say `PLEASEDONTFIXME` or something. :)
I don't understand your objection to the template-id rule of CWG 997 (which is what `f(g2<N::S>)` tests). It seems to me that the following should be well-formed (https://godbolt.org/z/J5uhQ-) :


```
namespace N {
    template <typename T> void f(T &&);
    struct S {};
}

template <typename T> struct C {};
template <typename T> void g();

void test() {
    f(C<N::S>{}); // ok
    f(g<N::S>);   // should be ok (and is ok according to the spec)
}
```


================
Comment at: test/CXX/basic/basic.lookup/basic.lookup.argdep/p3.cpp:50
+    extern void f(char); // expected-note {{candidate}}
+    f(s); // expected-error {{no matching function for call to 'f'}}
+  }
----------------
Quuxplusone wrote:
> ...But if you put the `using M::f;` _after_ the `extern void f(char);`, then GCC believes it's okay. https://godbolt.org/z/DghSTM
> You should definitely have a test for the using-after-extern case, just to make sure it doesn't ICE or anything.
Hmm... I am not sure what gcc is thinking here. The order should not matter according to the beginning of [basic.lookup.argdep]p3. 


================
Comment at: test/CXX/basic/basic.lookup/basic.lookup.argdep/p4.cpp:96
+//    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
----------------
Quuxplusone wrote:
> Nit: 80-column lines here and above would be nice. :)
I am usually a little bit more flexible on the 80-columns rule in tests, but you are right. Fixed.


Repository:
  rC Clang

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D60570/new/

https://reviews.llvm.org/D60570





More information about the cfe-commits mailing list