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

Reply via email to