This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [c++-concepts] Constrained friends
- From: Andrew Sutton <andrew dot n dot sutton at gmail dot com>
- To: Jason Merrill <jason at redhat dot com>
- Cc: gcc-patches at gcc dot gnu dot org
- Date: Sat, 21 Sep 2013 08:52:59 -0400
- Subject: Re: [c++-concepts] Constrained friends
- Authentication-results: sourceware.org; auth=none
- References: <CANq5SytNsrWf6e5WcX_uFqmYzAr9pBMi8gw16nuarbk+HkJ3Sw at mail dot gmail dot com> <523D91EF dot 6080301 at redhat dot com>
I'm going to rewrite this patch tomorrow morning. The semantics aren't
quite right --- they should be simpler.
>> Previously, if constraints were not
>> satisfied, we would not record the template as a candidate. However,
>> this causes errors in class template instantiation if there are
>> constrained friend declarations whose constraints are not satisfied
>> ("no matching template declaration").
>
> Is that wrong? We normally give errors about friend declarations that don't
> match any template. Why don't we want this error when the friend
> declaration is looking for a constrained template?
It is wrong, but not for the reasons I gave. This only happens when
you try to constrain a friend function that declares a specialization,
which happens to be completely separate from the previously declared
template.
I'm going to disallow the ability to declare constrained friend
specializations. They don't really make sense.
>> + if (is_non_template_member_fn (fn) || is_non_template_friend (fn))
>
>
> Let's have one predicate instead of two; the condition here is a temploid
> that is not a specialization of a primary template.
Agreed.
>
>> + if (!check_template_constraints (tmpl, args) && (complain &
>> tf_error))
>> {
>> reason = template_constraint_failure (tmpl, args);
>> viable = false;
>
>
> Why add the complain check? A constraint failure should make a candidate
> non-viable even in SFINAE context.
What have I done? That's awful...
>> + // If we're not instantiating a friend function, then we need to
>> + // ensure the specialization of the best template satisfies its
>> + // constraints.
>
>
> Surely we need to check constraints in the earlier loop, so that we don't
> treat as a candidate a template that doesn't satisfy the constraints;
> otherwise if we have two templates
>
> template <class T> T f(T) requires Thing;
> template <class T> T* f(T*);
>
> and our specialization requires Thing, we would select the second (because
> it is otherwise more specialized) and then give an error about constraint
> mismatch; I would think we want to select the first.
I believe that's what the previous version did, and we'll go back to
that. This change was part of the semantics that I didn't get right.
>> + // If there is an overload with the same type and
>> + // constraints, then this is a good declaration.
>> + if (same_type_p (TREE_TYPE (fn), TREE_TYPE (f)))
>> + if (equivalent_constraints (constr, get_constraints (f)))
>> + return;
>
>
> It seems that this will only allow friend declarations that match the
> template exactly, not friend declarations that are more specialized than the
> matching template. It looks like you're trying to implement a subset of
> determine_specialization here, which I think is a mistake.
I agree. It's a mistake. This is also related to the semantics that I got wrong.
Effectively, the only changes needed for constrained friends are that:
a) you can't constrain non-dependent friends
b) you can't constraint non-template friend functions that declare a
specialization
and c) that we check non-template friends the same way as non-template
member fns
There should be no changes to any of the rules for determining specializations.
Andrew