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.