This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [PR c++/84789] do not resolve typename into template-independent


On Tue, Mar 20, 2018 at 11:27 PM, Alexandre Oliva <aoliva@redhat.com> wrote:
> On Mar 20, 2018, Jason Merrill <jason@redhat.com> wrote:
>
>> On Tue, Mar 20, 2018 at 6:07 PM, Alexandre Oliva <aoliva@redhat.com> wrote:
>>> On Mar 20, 2018, Jason Merrill <jason@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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]