This is the mail archive of the gcc-bugs@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]

[Bug c++/69288] New: [concepts] Subsumption failure with constrained member functions of class template


https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69288

            Bug ID: 69288
           Summary: [concepts] Subsumption failure with constrained member
                    functions of class template
           Product: gcc
           Version: 6.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: Casey at Carter dot net
  Target Milestone: ---

Created attachment 37346
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=37346&action=edit
Minimized test case

r232370 miscompiles this program:

template <class T, class U>
constexpr bool Same = __is_same_as(T, U);

template <class T>
concept bool C = requires(T& t) { t.f(); };

template <class T>
concept bool D = C<T> && requires(T& t) { requires Same<T, decltype(t.f())>; };
// NB: D subsumes C

struct X {};
struct Y { int f(); };
struct Z { Z f(); };

// Y satisfies C but not D
static_assert(C<Y>);
static_assert(!D<Y>);

// Z satisfies both C and D
static_assert(C<Z>);
static_assert(D<Z>);

template <class T>
struct foo {
  void g(T); // #1

  int g(T)   // #2
    requires C<T>;

  T g(T)     // #3
    requires D<T>;
};

static_assert(Same<decltype(foo<X>{}.g(X{})), void>); // calls #1
static_assert(Same<decltype(foo<Y>{}.g(Y{})), int>);  // calls #2
static_assert(Same<decltype(foo<Z>{}.g(Z{})), Z>);    // error: ambiguous

with diagnostics:

~/gcc6/bin/g++ -std=c++1z foo.cpp -c
foo.cpp:36:43: error: call of overloaded âg(Z)â is ambiguous
 static_assert(Same<decltype(foo<Z>{}.g(Z{})), Z>);    // error: ambiguous
                                           ^

foo.cpp:25:8: note: candidate: void foo<T>::g(T) [with T = Z]
   void g(T); // #1
        ^

foo.cpp:27:7: note: candidate: int foo<T>::g(T) requires predicate( C<T>) [with
T = Z]
   int g(T)   // #2
       ^

foo.cpp:30:5: note: candidate: T foo<T>::g(T) requires predicate( D<T>) [with T
= Z]
   T g(T)     // #3
     ^

foo.cpp:36:43: error: call of overloaded âg(Z)â is ambiguous
 static_assert(Same<decltype(foo<Z>{}.g(Z{})), Z>);    // error: ambiguous
                                           ^

foo.cpp:25:8: note: candidate: void foo<T>::g(T) [with T = Z]
   void g(T); // #1
        ^

foo.cpp:27:7: note: candidate: int foo<T>::g(T) requires predicate( C<T>) [with
T = Z]
   int g(T)   // #2
       ^

foo.cpp:30:5: note: candidate: T foo<T>::g(T) requires predicate( D<T>) [with T
= Z]
   T g(T)     // #3
     ^

foo.cpp:36:15: error: template argument 1 is invalid
 static_assert(Same<decltype(foo<Z>{}.g(Z{})), Z>);    // error: ambiguous
               ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

(Not a cut-and-paste error, the same diagnostic is actually issued twice.)

The concept machinery is apparently failing to determine that overload #3 is
more constrained than overload #2. This problem notably does *not* occur for
constrained member templates of a class:

struct foo {
  template <class T>
  void g(T); // #1

  template <class T>
  int g(T)   // #2
    requires C<T>;

  template <class T>
  T g(T)     // #3
    requires D<T>;
};

static_assert(Same<decltype(foo{}.g(Z{})), Z>);    // calls #3

or with non-member function templates:

template <class T>
void g(T); // #1

template <class T>
  requires C<T>
int g(T);  // #2

template <class T>
  requires D<T>
T g(T);    // #3

static_assert(Same<decltype(g(Z{})), Z>);    // calls #3

but *does* occur with member templates that are constrained by a class template
parameter:

template <class T>
struct foo {
  template <int = 42>
  void g(T); // #1

  template <int = 42>
  int g(T)   // #2
    requires C<T>;

  template <int = 42>
  T g(T)     // #3
    requires D<T>;
};

static_assert(Same<decltype(foo<Z>{}.g(Z{})), Z>);    // error: ambiguous

I speculate the error arises due to a failure to properly substitute the
non-dependent type T into the constraint expressions.

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