ADL causing implicit template class instantiation failure

I'm taking a look at a possible clang issue with the following code:

I'm taking a look at a possible clang issue with the following code:
___________________________
struct incomplete;

template<class T>
struct A { T d; };

template <class T>
struct B { };

template<typename T> void func(T &t);

int main() {
    B<A&lt;incomplete>> a, b;
    a = b;
}
___________________________

this code causes clang to emit an error "incomplete type T d;". I searched
in the cpp standard and found nothing related to ADL causing an implicit
instantiation in this case.

Here it is:

[basic.lookup.argdep]/2:

"[...] if T is a class template specialization, its associated [...]
classes also include: the [...] classes associated with the types of the
template arguments provided for template type parameters [...]"

[basic.lookup.argdep]/4:

"When considering an associated namespace, the lookup is the same as the
lookup performed when the associated namespace is used as a qualifier
(3.4.3.2) except that:
[...] 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 (11.3)"

[temp.inst]/1:

"Unless a class template specialization has been explicitly instantiated
(14.7.2) or explicitly specialized (14.7.3), the class template
specialization is implicitly instantiated [...] when the completeness of
the class type affects the semantics of the program."

The completeness of the class type can affect whether friends are declared
in an associated class, which therefore affects the semantics of the
program. Therefore ADL triggers the implicit instantiation of all
associated classes, and A<incomplete> is an associated class of
B<A<incomplete>>.

So I started researching clang's source and I

believe this is what is happening:

- ADL process starts

This seems like the interesting part. Why are we performing ADL? There can
be no non-member operator= functions (other than the builtin ones, which
are not found by ADL). [over.match.oper]/3.2 says:

"The set of non-member candidates is the result of the unqualified lookup
of operator@ in the context of the expression according to the usual rules
for name lookup in unqualified function calls (3.4.2) except that all
member functions are ignored."

The implication is that we don't perform this lookup (and thus do not
perform ADL) if there is no non-member form in Table 11, but that's not
explicitly stated. In any case, we're /permitted/ to skip this due to
[temp.inst]p7: "If the overload resolution process can determine the
correct function to call without instantiating a class template definition,
it is unspecified whether that instantiation actually takes place."

Anyway, fixed in r218330 by skipping ADL in this case. I'm also taking this
to the C++ committee to see if we can get the rules clarified here.

(GCC gets this wrong for operator[] and operator-> too; Clang already did
the right thing there.)

- A<incomplete> is tried to be instantiated to have a better ADL set (and

Thanks Richard! Now it makes sense. I completely agree that the standard
might be rendered clearer on this point.