OK, thanks.

On Wed, Mar 21, 2018 at 11:48 AM, Jason Merrill <ja...@redhat.com> wrote:
> 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

Reply via email to