[c++-concepts] constrained friends

2014-08-21 Thread Andrew Sutton
Added tests for constrained friends.  No code, we already to the right thing.

2014-08-15  Andrew Sutton  

Add tests for constrained friends.
* gcc/testsuite/g++.dg/concepts/friend1.C: New.
* gcc/testsuite/g++.dg/concepts/friend2.C: New.

Andrew
Index: gcc/testsuite/g++.dg/concepts/friend2.C
===
--- gcc/testsuite/g++.dg/concepts/friend2.C	(revision 0)
+++ gcc/testsuite/g++.dg/concepts/friend2.C	(revision 0)
@@ -0,0 +1,20 @@
+// { dg-options "-std=c++1z" }
+
+template
+  concept bool Eq() { return requires(T t) { t == t; }; }
+
+template struct Foo { };
+
+template
+  struct S { // { dg-error "constraint failure" }
+template friend class Bar;
+
+friend class Foo;
+  };
+
+struct X { };
+
+int main() {
+  S si; // OK
+  S sx;
+}
Index: gcc/testsuite/g++.dg/concepts/friend1.C
===
--- gcc/testsuite/g++.dg/concepts/friend1.C	(revision 0)
+++ gcc/testsuite/g++.dg/concepts/friend1.C	(revision 0)
@@ -0,0 +1,33 @@
+// { dg-options "-std=c++1z" }
+
+template
+  concept bool Eq() { return requires(T t) { t == t; }; }
+
+struct Nt {
+  template friend void f(T) { }
+} nt;
+
+template struct S;
+
+template
+  void proc(S*);
+
+template
+  struct S {
+friend bool operator==(S, S) requires Eq() { return true; }
+
+friend void proc<>(S*); // { dg-error "does not match any template declaration" }
+  };
+
+struct X { } x;
+
+int main() {
+  f(0); // OK
+  f(x); // { dg-error "cannot call" }
+
+  S si;
+  si == si; // OK
+
+  S sx; 
+  sx == sx; // { dg-error "no match" }
+}


Re: [c++-concepts] constrained friends redux

2013-10-04 Thread Paolo Carlini

Hi Andrew,

On 10/04/2013 07:36 PM, Andrew Sutton wrote:

+  if (!check_template_constraints (tmpl, args))
+{
+  location_t loc = DECL_SOURCE_LOCATION (function);
+  error ("%qD is not a viable candidate", function);
+  diagnose_constraints (input_location, tmpl, args);
+  return error_mark_node;
+}

Nit: loc seems unused.

Thanks,
Paolo.


Re: [c++-concepts] constrained friends redux

2013-10-04 Thread Jason Merrill

OK.

Jason


Re: [c++-concepts] constrained friends redux

2013-10-04 Thread Andrew Sutton
>>> >Perhaps you mean that it must match a fully-instantiated function, so
>>> > any
>>> >constraints on the templates were considered during
>>> >determine_specialization.
>
>
>> This seems like a simple comment fix, but there's a longer explanation
>> of what I want (see below). Would this be more appropriate?
>>
>>// Do not allow constrained friend template specializations.
>>
>> The intent is stronger than to say it must match something.
>
>
> By "must" I meant that whatever it matches could only be a
> fully-instantiated function.


I see what you mean. I was caught up in the wrong part of the
sentence.. But yes, that's right.

> But I guess the main reason for disallowing constraints here is the same as
> for explicit specializations and non-template functions; non-dependent
> constraints don't really make any sense.

That's the intent.

Okay to commit?

Andrew


friends-3.patch
Description: Binary data


Re: [c++-concepts] constrained friends redux

2013-10-04 Thread Jason Merrill

On 10/04/2013 09:20 AM, Andrew Sutton wrote:

>Perhaps you mean that it must match a fully-instantiated function, so any
>constraints on the templates were considered during
>determine_specialization.



This seems like a simple comment fix, but there's a longer explanation
of what I want (see below). Would this be more appropriate?

   // Do not allow constrained friend template specializations.

The intent is stronger than to say it must match something.


By "must" I meant that whatever it matches could only be a 
fully-instantiated function.


But I guess the main reason for disallowing constraints here is the same 
as for explicit specializations and non-template functions; 
non-dependent constraints don't really make any sense.


Jason



Re: [c++-concepts] constrained friends redux

2013-10-04 Thread Andrew Sutton
>> +  // Do not permit the declaration of constrained friend
>> +  // function declarations. They cannot be instantiated since
>> +  // the resulting declaration would never match the definition,
>> +  // which must be a non-template and cannot be constrained.
>
>
> You're in the template-id code here, so "must be a non-template" is
> confusing:
>
> template  void f();
>
> struct A {
>   friend void f(); // matches a template
> };
>
> Perhaps you mean that it must match a fully-instantiated function, so any
> constraints on the templates were considered during
> determine_specialization.

This seems like a simple comment fix, but there's a longer explanation
of what I want (see below). Would this be more appropriate?

  // Do not allow constrained friend template specializations.

The intent is stronger than to say it must match something. I don't
want to allow any declarations of the form

template
struct X {
  friend void f<>(T x) requires C; // Error.
};

This should never even get to determine_specialization since the
original declaration is never actually pushed.

We could use those constraints to match the specialization to one of
several constrained overloads, as you mentioned earlier, but I'd
rather avoid that for now. Solving that problem in general would
require that we allow constrained (explicit) specializations and
define a method of matching instantiated constraints to dependent
constraints, and that we do so as an alternative to the usual
constraint checking during template argument deduction.

Maybe it's a useful feature, but it's really hard to gauge how much
use it would actually get. We can always revisit that in the future.
Somebody else can write that paper :)

Andrew


Re: [c++-concepts] constrained friends redux

2013-10-02 Thread Jason Merrill

On 10/02/2013 09:05 AM, Andrew Sutton wrote:

+  // Do not permit the declaration of constrained friend
+  // function declarations. They cannot be instantiated since
+  // the resulting declaration would never match the definition,
+  // which must be a non-template and cannot be constrained.


You're in the template-id code here, so "must be a non-template" is 
confusing:


template  void f();

struct A {
  friend void f(); // matches a template
};

Perhaps you mean that it must match a fully-instantiated function, so 
any constraints on the templates were considered during 
determine_specialization.



+  error("constrained friend does not depend on template parameters");


Space before (.


+// Returns true if FN is a non-template member function.
+static inline bool
 is_non_template_member_fn (tree fn)
 {
   return DECL_FUNCTION_MEMBER_P (fn) &&
@@ -1829,6 +1829,21 @@ is_non_template_member_fn (tree fn)
  !DECL_MEMBER_TEMPLATE_P (DECL_TI_TEMPLATE (fn));
 }

+// Returns true if FN is a non-template friend definition.
+static inline bool
+is_non_template_friend (tree fn)


These names/comments fail to make it clear that they return true only 
for non-template members/friends *of class template specializations*. 
So my preference would be to open-code them into 
is_constrainable_non_template_fn.


Jason



[c++-concepts] constrained friends redux

2013-10-02 Thread Andrew Sutton
This patch implements constrained friends and disallows declarations
of constrained friend template specialization.

There was a previous question about whether I was doing the right
thing in determine_specialization. I'm looking at that issue
separately.

2013-10-01  Andrew Sutton  
* gcc/cp/parser.c (cp_parser_member_declaration): Check that
a constrained friend definition is valid.
* gcc/cp/decl.c (grokfndecl): Disallow constrained friend template
specializations.
* gcc/cp/constraints.cc (check_constrained_friend): New.
* gcc/cp/typeck.c (cp_build_function_call_vec): Diagnose constraints
in the presence of the failure of a single candidate.
* gcc/cp/cp-tree.h (check_constrained_friend): New.
* gcc/cp/call.c (is_non_template_member_fn): Make inline.
(is_non_template_friend), (is_constrainable_non_template_fn): New.
(add_function_candidate): Predicate check on
is_constrainable_non_template_fn.

Andrew Sutton


friends-2.patch
Description: Binary data


Re: [c++-concepts] Constrained friends

2013-09-21 Thread Jason Merrill

On 09/21/2013 08:52 AM, Andrew Sutton wrote:

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.


Hmm, it seems to me the constraints on the specialization help to select 
the template the specialization belongs to.  I'm not sure that would be 
useful, but I don't see a need to specifically prevent it.


Jason



Re: [c++-concepts] Constrained friends

2013-09-21 Thread Andrew Sutton
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  T f(T) requires Thing;
> template  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


Re: [c++-concepts] Constrained friends

2013-09-21 Thread Jason Merrill

On 09/13/2013 12:21 PM, Andrew Sutton wrote:

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?



+  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.



+  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.



+  // 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  T f(T) requires Thing;
template  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.



+// 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.


Jason



[c++-concepts] Constrained friends

2013-09-13 Thread Andrew Sutton
This patch implements semantics for constrained friend templates and
classes. The only significant changes are in determine_specializaiton
and check_constrained_friend.

Unless a friend function is defined, a constraints on friend
declarations are never actually checked. The checking happens during
overload resolution against the actual (non-friend) declarations.

The change to determine_specialization is interesting. We have cases
where a programmer has written an explicit specialization and it's
being matched to a template. 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").

With this patch, we defer constraints checks until we've selected the
best template for the specialization. And then we only check the
constraints if the declaration is a non-friend.

2013-09-13  Andrew Sutton  
* gcc/cp/cp-tree.h (check_constrained_friend): New.
* gcc/cp/pt.c (determine_specialization): Only check constraints
after determining which template the declaraiton is a specialization
of. Don't check constraints for friends during class template
instantiation.
(fn_type_unification): New parameter to determine if constraints
should be checked.
(more_specialized_class): Update for interface change.
(get_bindings): New parameter to determine if constraints should
be checked during fn_type_unification. New overload that checks
constraints by default.
* gcc/cp/parser.c (cp_parser_member_declaration): Check constrained
friends after parsing.
* gcc/cp/class.c (resolve_address_of_overloaded_function): Update
for interface change.
* gcc/cp/call.c (is_non_template_friend): New.
(add_function_candidate): Check constraints on constrained friend
templates.
(add_template_candidate_real): Update for interface change.
* gcc/cp/constraint.c (check_constrained_friend): New.


Andrew Sutton


friends.patch
Description: Binary data