Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dependent name lookup in function template: clang rejects, gcc accepts

Consider the following fragment:

struct X { };

namespace foo {
    template <class T>
    void bar() { T{} < T{}; }

    void operator<(const X&, const X&) {}
}

int main() {
    foo::bar<X>();
}

clang rejects this code, gcc accepts it. Is this a gcc bug or is this a clang bug?

like image 396
Barry Avatar asked Mar 05 '16 19:03

Barry


2 Answers

I believe this is a gcc bug, filed as 70099. From [temp.dep.res]:

In resolving dependent names, names from the following sources are considered:
(1.1) — Declarations that are visible at the point of definition of the template.
(1.2) — Declarations from namespaces associated with the types of the function arguments both from the instantiation context (14.6.4.1) and from the definition context.

foo::operator<() isn't visible at the point of definition of the template, and isn't in an associated namespace from the function arguments (X's associated namespace is just the global namespace ::). So I think gcc is wrong to find foo::operator< and clang is correct to reject the code.

like image 98
Barry Avatar answered Oct 21 '22 11:10

Barry


GCC is wrong Clang is correct. The fact that GCC swallows invalid code as the one that you showed is also mentioned in CLANG's compatibility page here.

Unqualified names are looked up in the following ways.

  1. The compiler conducts unqualified lookup in the scope where the name was written. For a template, this means the lookup is done at the point where the template is defined, not where it's instantiated. Since operator< hasn't been declared yet at this point, unqualified lookup won't find it.
  2. If the name is called like a function, then the compiler also does argument-dependent lookup (ADL). (Sometimes unqualified lookup can suppress ADL; see [basic.lookup.argdep] paragraph 3 for more information.) In ADL, the compiler looks at the types of all the arguments to the call. When it finds a class type, it looks up the name in that class's namespace; the result is all the declarations it finds in those namespaces, plus the declarations from unqualified lookup. However, the compiler doesn't do ADL until it knows all the argument types.
like image 7
101010 Avatar answered Oct 21 '22 12:10

101010