This is the mail archive of the
gcc-bugs@gcc.gnu.org
mailing list for the GCC project.
[Bug c++/69288] New: [concepts] Subsumption failure with constrained member functions of class template
- From: "Casey at Carter dot net" <gcc-bugzilla at gcc dot gnu dot org>
- To: gcc-bugs at gcc dot gnu dot org
- Date: Thu, 14 Jan 2016 22:50:39 +0000
- Subject: [Bug c++/69288] New: [concepts] Subsumption failure with constrained member functions of class template
- Auto-submitted: auto-generated
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.