Bug 92102 - identical requires-expression not subsumed
Summary: identical requires-expression not subsumed
Status: RESOLVED INVALID
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 10.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: rejects-valid
: 95626 (view as bug list)
Depends on:
Blocks: concepts
  Show dependency treegraph
 
Reported: 2019-10-15 09:55 UTC by Jonathan Wakely
Modified: 2020-06-10 18:52 UTC (History)
3 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2019-10-15 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Jonathan Wakely 2019-10-15 09:55:56 UTC
This fails to compile with -std=gnu++2a:


template<typename T, typename U> constexpr bool same = false;
template<typename T> constexpr bool same<T, T> = true;

template<typename T, typename U>
  concept same_same = same<T, U> && same<U, T>;

template<typename T>
  struct traits { using type = T; };

struct tag { };

template<typename T>
  struct category
  { };

template<typename T>
  requires requires { typename traits<T>::type; }
  struct category<T>
  { };

template<typename T>
  requires requires { typename traits<T>::type; }
      && same_same<typename traits<T>::type, tag>
  struct category<T>
  { using type = int; };

category<tag>::type t;


ambig.cc:27:14: error: ambiguous template instantiation for 'struct category<tag>'
   27 | category<tag>::type t;
      |              ^~
ambig.cc:18:10: note: candidates are: 'template<class T>  requires requires{typename traits<T>::type;} struct category<T> [with T = tag]'
   18 |   struct category<T>
      |          ^~~~~~~~~~~
ambig.cc:24:10: note:                 'template<class T>  requires requires{typename traits<T>::type;} && (same_same<typename traits::type, tag>) struct category<T> [with T = tag]'
   24 |   struct category<T>
      |          ^~~~~~~~~~~
ambig.cc:27:16: error: invalid use of incomplete type 'struct category<tag>'
   27 | category<tag>::type t;
      |                ^~~~
ambig.cc:13:10: note: declaration of 'struct category<tag>'
   13 |   struct category
      |          ^~~~~~~~



It compiles OK if the subsumed constraint is a concept instead of a requires-expression, even though that should be equivalent:

template<typename T, typename U> constexpr bool same = false;
template<typename T> constexpr bool same<T, T> = true;

template<typename T, typename U>
  concept same_same = same<T, U> && same<U, T>;

template<typename T>
  struct traits { using type = T; };

template<typename T>
  concept traitsy = requires { typename traits<T>::type; };

struct tag { };

template<typename T>
  struct category
  { };

template<typename T>
  requires traitsy<T>
  struct category<T>
  { };

template<typename T>
  requires traitsy<T>
      && same_same<typename traits<T>::type, tag>
  struct category<T>
  { using type = int; };

category<tag>::type t;
Comment 1 Jonathan Wakely 2019-10-15 10:55:41 UTC
Reduced:


template<typename>
  concept nope = false;

template<typename>
  concept sure_thing = true;

template<typename T>
  struct category
  { };

template<typename T> requires (!nope<T>)
  struct category<T>
  { };

template<typename T> requires (!nope<T>) && sure_thing<T>
  struct category<T>
  { using type = T; };

category<int>::type t;



ambig.cc:19:14: error: ambiguous template instantiation for 'struct category<int>'
   19 | category<int>::type t;
      |              ^~
ambig.cc:12:10: note: candidates are: 'template<class T>  requires !(nope<T>) struct category<T> [with T = int]'
   12 |   struct category<T>
      |          ^~~~~~~~~~~
ambig.cc:16:10: note:                 'template<class T>  requires !(nope<T>) && (sure_thing<T>) struct category<T> [with T = int]'
   16 |   struct category<T>
      |          ^~~~~~~~~~~
ambig.cc:19:16: error: invalid use of incomplete type 'struct category<int>'
   19 | category<int>::type t;
      |                ^~~~
ambig.cc:8:10: note: declaration of 'struct category<int>'
    8 |   struct category
      |          ^~~~~~~~


To make subsumption of (!E) work I need to add a concept for !E


template<typename T>
  concept nope_nope = !nope<T>;


and then use that:


template<typename T> requires nope_nope<T>
  struct category<T>
  { };

template<typename T> requires nope_nope<T> && sure_thing<T>
  struct category<T>
  { using type = T; };
Comment 2 Jason Merrill 2019-11-04 14:18:42 UTC
In C++20, atomic constraints are only equivalent if they come from the same lexical tokens.  So yes, you need to add a concept.
Comment 3 Jonathan Wakely 2020-06-10 18:52:42 UTC
*** Bug 95626 has been marked as a duplicate of this bug. ***