[Bug c++/99599] [11 Regression] Concepts requirement falsely reporting cyclic dependency, breaks tag_invoke pattern

2021-04-05 Thread the_gamester28 at msn dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99599

--- Comment #4 from the_gamester28 at msn dot com ---
(In reply to Jason Merrill from comment #2)
> (In reply to the_gamester28 from comment #0)
> > It seems that the template requirements of invoke_tag(bar_tag, int) are
> > considered while evaluating line marked "here". Requirements of irrelevant
> > overloads should not be considered, as it can potentially lead to falsely
> > reporting a cyclic dependency.
> 
> This is as specified by http://wg21.link/cwg2369
> 
> I think it would be reasonable to allow a compiler to accept the testcase
> under a generalization of 13.9.1/9: "If the function selected by overload
> resolution (12.4) can be determined without instantiating a class template
> definition, it is unspecified whether that instantiation actually takes
> place."
> 
> But that does not require a compiler to accept it.
> 
> It might make sense to check non-dependent conversions that don't require
> template instantiation, then constraints, then non-dependent conversions
> that do require template instantiation.  But that's a matter for the
> committee; G++ is conforming to the current working paper.

Perhaps I was too quick to assert what I expected the implementation details to
be.

The fooable concept should be satisfied for any (T it) for which
invoke_tag(foo_tag{}, it) is unambiguously applicable. The fact that the
invoke_tag(bar_tag, T) overload exists should not preclude that. It is not up
to me how the compiler comes to that end, but that is the desired outcome.

It is still possible to ban recursive constraints, keep the new GCC 11
implementation, and still have this particular code compile with a small
alteration in behaviour:

The compiler does not immediately bail out as soon as it sees recursion in an
overload candidate, but marks that particular candidate as invalid.

If there are no applicable overloads (because they are all recursive, or they
are invalid for some other reason), then the compiler can reject the code and
list all of the reasons why all of the candidates are invalid.

In this case, it would mark invoke_tag(bar_tag, int) as not-applicable due to
the constraint recursion, and carry on checking the rest of the overloads for
applicability, until it is sure that there is one and only one applicable
overload: invoke_tag(foo_tag, int).

[Bug c++/99599] New: Concepts requirement falsely reporting recursion, breaks tag_invoke pattern

2021-03-15 Thread the_gamester28 at msn dot com via Gcc-bugs
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99599

Bug ID: 99599
   Summary: Concepts requirement falsely reporting recursion,
breaks tag_invoke pattern
   Product: gcc
   Version: 11.0
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: c++
  Assignee: unassigned at gcc dot gnu.org
  Reporter: the_gamester28 at msn dot com
  Target Milestone: ---

The following code compiles fine on GCC 10, Clang, MSVC, but fails in GCC
11/trunk:

### begin

struct foo_tag{};
struct bar_tag{};

template 
concept fooable = requires(T it) {
invoke_tag(foo_tag{}, it); // <-- here
};

template
auto invoke_tag(foo_tag, T in) {
return in;
}

template
auto invoke_tag(bar_tag, T it) {
return it;
}

int main() {
// Neither line below compiles in GCC 11, independently of the other
return invoke_tag(foo_tag{}, 2);
return invoke_tag(bar_tag{}, 2);
}

### end

Produces the following compiler error:

### begin

: In substitution of 'template  requires  fooable auto
invoke_tag(bar_tag, T) [with T = int]':
:6:15:   required by substitution of 'template  requires 
fooable auto invoke_tag(bar_tag, T) [with T = int]'
:21:35:   required from here
:5:9:   required for the satisfaction of 'fooable' [with T = int]
:5:19:   in requirements with 'T it' [with T = int]
:5:19: error: satisfaction of atomic constraint 'requires(T it)
{invoke_tag({}, it);} [with T = T]' depends on itself
5 | concept fooable = requires(T it) {
  |   ^~~~
6 | invoke_tag(foo_tag{}, it);
  | ~~
7 | };
  | ~  

### end

It seems that the template requirements of invoke_tag(bar_tag, int) are
considered while evaluating line marked "here". Requirements of irrelevant
overloads should not be considered, as it can potentially lead to falsely
reporting a cyclic dependency.

This bug effectively prevents using the modern tag_invoke pattern, which is
increasingly used as a customisation point in many modern libraries.