On Tue, Mar 20, 2018 at 11:27 PM, Alexandre Oliva <aol...@redhat.com> wrote: > On Mar 20, 2018, Jason Merrill <ja...@redhat.com> wrote: > >> On Tue, Mar 20, 2018 at 6:07 PM, Alexandre Oliva <aol...@redhat.com> wrote: >>> On Mar 20, 2018, Jason Merrill <ja...@redhat.com> wrote: >>>> that doesn't mean it's wrong to peek. > >>> Huh? We're referencing members of an unrelated template that AFAIK >>> needs not even be defined at that point, and even if it is, it could >>> still be specialized afterwards. How can it possibly be right to >>> short-circuit such nested names? > >>> template<typename> struct B : A {}; // would /*: A {}*/ make any diff? >>> template<typename T> struct C : B<T> // would /* : B<T>*/ make any diff? >>> { >>> B<T>::A::I::I i; // { dg-error "typename" } >>> }; > >> No, we look inside when we're trying to parse the qualified-id as the >> name of a declaration > > Yeah, but that's not the case at hand. I guess we're miscommunicating. > I understood you were saying it was ok to peek in this case. Would you > please state, for clarity, what your stance is on peeking in this case, > specifically, in the B<T>::A::I::I within the definition of C above?
It's OK when we're tentatively trying to parse it as a declarator, not when we're trying to parse it as a type-specifier. We seem to be talking past each other on this point: We already don't peek when parsing a type-specifier, we only call resolve_typename_type with false for only_current_p in the context of trying to parse a declarator. The parser tries both interpretations for B<T>::A::I::I. The type interpretation is ill-formed because of missing 'typename', so it tries again as a declarator, and therefore tries to resolve the TYPENAME_TYPE that it built while trying for a type, and trips the assert. >> in a declarator-id we can look into uninstantiated classes, otherwise >> there would be no way to define members of class templates. > >> void X<T>::N::f() { } // looks inside X<T> > > Of course, but then, we wouldn't get to a template-independent member. > A member of a template-dependent name is still template-dependent. It's > only when a qualified name maps to an external name that it might become > template-independent, and when this happens, I believe the qualified-id > is not one that can be used to define a member. Specifically: > > struct K { struct L { static double j; }; }; > template <typename T> struct M { struct N { static int i; }; }; > template <typename T> struct O { typedef M<T> P; typedef K Q; }; > template <typename T> int O<T>::P::N::i = 42; > template <typename T> double O<T>::Q::L::j = 42.0; > > if we remap O<T>::P to M<T> and O<T>::Q to K, how will we realize the > given type-ids are not appropriate? Where will the template parmlist > belong when the qualified-id is taken as equivalent to K::L::j? Agreed, these look bizarre because the template parm is used in O<T>, which is not an enclosing class of i or j. And j is clearly ill-formed because it declares a non-template as a template. But it's not clear to me that i is ill-formed; we allow struct A { static int i; }; struct B { typedef ::A A; }; int B::A::i = 0; and the i example seems analogous. I wouldn't argue against making it ill-formed, but I don't see a rule that would make it so in the current draft standard. And even resolving the scope to be non-dependent doesn't necessarily mean the declaration will be, if the template parameter list ends up being for a member template: struct K { struct L { template <typename T> static void f(T); }; }; template <typename T> struct O { typedef K Q; }; template <typename T> void O<T>::Q::L::f(T) { } >>>> I disagree; it seems to me that the assert should allow the case where >>>> the scope was originally dependent, but got resolved earlier in the >>>> function. >>> >>> Doesn't the function always take dependent scopes? I for some reason >>> thought that was the case. > >> Yes, as the comment says, a TYPENAME_TYPE should always have a >> dependent scope. In this case, the dependent scope was "typename >> B<T>::A", but just above we resolved it to just A, making it no longer >> dependent. > > Then you got me thoroughly confused: what did you mean by 'the assert > should allow' a case that's a given? asserts are often used to verify that things we think of as givens are actually true. :) I suppose we could remove the assert, but I'd probably move it up above where we start messing with 'scope'. Jason