4

Consider a struct B derived from two structs A<1> and A<2>, each defining a typename D to itself, and there is also a global typename D. Then one writes .D:: after a B object , which D must be taken?

template<int N> struct A{ int v = N; using D = A; };
struct B : A<1>, A<2> {};
using D = A<1>;
int main() { return B{}.D::v; }

According to the standard: [basic.lookup.classref]

4 If the id-expression in a class member access is a qualified-id of the form

class-name-or-namespace-name::...

the class-name-or-namespace-name following the . or -> operator is first looked up in the class of the object expression ([class.member.lookup]) and the name, if found, is used. Otherwise it is looked up in the context of the entire postfix-expression.

So, first D must be looked inside struct B, but it is ambiguous there. And indeed, Clang reports an error about it:

error: member 'D' found in multiple base classes of different types

But GCC accepts the code, demo: https://gcc.godbolt.org/z/74qraoeac

It seems that GCC interprets the standard as if D is ambiguous in B, let us look outside of B. Which compiler is correct here?

Fedor
  • 17,146
  • 13
  • 40
  • 131
  • 2
    I personally think Clang's behaviour seems correct here. You could try filing a bug against GCC and see if they agree. – Brian Bi Sep 01 '21 at 20:08
  • Both are quite happy if one does `return B{}.::D::v;` instead. I'm leaning towards `clang++` being correct for looking for `D` in `B` in the original code (before looking in the enclosing namespace where `D` is not ambiguous). – Ted Lyngmo Sep 01 '21 at 20:37
  • I agree with BrianBi. The quoted language says to look in another context only if the name is not found. Well, the name is found, it is just ambiguous. The search should stop there. – Remy Lebeau Sep 01 '21 at 21:00
  • Thanks, I reported GCC bug: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102170 – Fedor Sep 02 '21 at 06:41

1 Answers1

2

Clang is correct according to the recent clarification of that wording, which now says

If nothing is found by qualified lookup for a member-qualified name that is the terminal name ([expr.prim.id.qual]) of a nested-name-specifier and is not dependent, it undergoes unqualified lookup.

Now there is no problematic “the name, if found” which could imply uniqueness.

Davis Herring
  • 36,443
  • 4
  • 48
  • 76