https://gcc.gnu.org/bugzilla/show_bug.cgi?id=65681
Bug ID: 65681 Summary: [c++-concepts] spurious ambiguous template instantiation error; regression from r211824 Product: gcc Version: unknown Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: tom at honermann dot net The following test case demonstrates what I believe to be a spurious error in resolving constrained class template partial specializations. This appears to be a regression introduced at some point. The error occurs using a gcc r221861 based build. I have an old gcc build (r211824) that compiles it successfully. The test case is rather long. It may be possible to reduce it a little bit more, but it seems to be a little fragile as is. For example, changing concept C to specify a type requirement rather than a member function call requirement suffices to avoid the error. Additionally, swapping the requirements of CA1 with CB1 and the type alias targets of MA1 and MB1 (while retaining the existing dependent type names) suffices to avoid the error. The test case defines two parallel concept hierarchies, CA[1-3] and CB[1-3], with accompanying models MA[1-3] and MB[1-3]. Class template S defines the problematic constrained partial specializations. The specializations are intended to select alternate behavior when the type for T1 is less refined than the type for T2, in a covariant sense. $ cat t.cpp template<typename T> concept bool C() { return requires (T t) { { t.mf() } }; } struct MC { void mf(); }; static_assert(C<MC>(), ""); template<typename T> concept bool CA1() { return C<typename T::ca1_type>(); } template<typename T> concept bool CA2() { return CA1<T>() && requires () { typename T::ca2_type; }; } template<typename T> concept bool CA3() { return CA2<T>() && requires () { typename T::ca3_type; }; } template<typename T> concept bool CB1() { return requires () { typename T::cb1_type; }; } template<typename T> concept bool CB2() { return CB1<T>() && requires () { typename T::cb2_type; }; } template<typename T> concept bool CB3() { return CB2<T>() && requires () { typename T::cb3_type; }; } struct MA1 { using ca1_type = MC; }; struct MA2 : MA1 { using ca2_type = int; }; struct MA3 : MA2 { using ca3_type = int; }; static_assert(CA1<MA1>(), ""); static_assert(CA2<MA2>(), ""); static_assert(CA3<MA3>(), ""); struct MB1 { using cb1_type = int; }; struct MB2 : MB1 { using cb2_type = int; }; struct MB3 : MB2 { using cb3_type = int; }; static_assert(CB1<MB1>(), ""); static_assert(CB2<MB2>(), ""); static_assert(CB3<MB3>(), ""); template<typename T1, typename T2> struct S; template<CA1 T1, CB1 T2> struct S<T1, T2> { // Specialization #1 static constexpr int value = 1; }; template<CA1 T1, CB2 T2> requires ! CA2<T1>() struct S<T1, T2> { // Specialization #2 static constexpr int value = 2; }; template<CA2 T1, CB3 T2> requires ! CA3<T1>() struct S<T1, T2> { // Specialization #3 static constexpr int value = 3; }; S<MA1,MB1> s11; S<MA1,MB2> s12; S<MA1,MB3> s13; S<MA2,MB1> s21; S<MA2,MB2> s22; S<MA2,MB3> s23; S<MA3,MB1> s31; S<MA3,MB2> s32; S<MA3,MB3> s33; static_assert(S<MA1,MB1>::value == 1, ""); static_assert(S<MA1,MB2>::value == 2, ""); static_assert(S<MA1,MB3>::value == 2, ""); static_assert(S<MA2,MB1>::value == 1, ""); static_assert(S<MA2,MB2>::value == 1, ""); static_assert(S<MA2,MB3>::value == 3, ""); static_assert(S<MA3,MB1>::value == 1, ""); static_assert(S<MA3,MB2>::value == 1, ""); static_assert(S<MA3,MB3>::value == 1, ""); $ svn info # From my local svn gcc repo. Path: . URL: svn://gcc.gnu.org/svn/gcc/branches/c++-concepts Repository Root: svn://gcc.gnu.org/svn/gcc Repository UUID: 138bc75d-0d04-0410-961f-82ee72b054a4 Revision: 221861 Node Kind: directory Schedule: normal Last Changed Author: asutton Last Changed Rev: 221857 Last Changed Date: 2015-04-03 12:47:32 -0400 (Fri, 03 Apr 2015) # Using the gcc build above, an error is produced. $ g++ -Wfatal-errors -c -std=c++1z t.cpp t.cpp:101:12: error: ambiguous template instantiation for ‘struct S<MA2, MB3>’ S<MA2,MB3> s23; ^ compilation terminated due to -Wfatal-errors. # Using an old gcc r211824 based build, compilation is successful (note # that this old build required -std=c++1y to enable support for concepts. $ g++ -c -std=c++1y t.cpp $ echo $? 0