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

            Bug ID: 69235
           Summary: [concepts] Spurious ambiguous template instantiation
                    error on oppositely constrained class template
                    specializations
           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
  Target Milestone: ---

I believe the following test case is well-formed, but gcc trunk (r232017) emits
an "ambiguous template instantiation" error for the X<S> specialization.  The
ambiguity arises from the oppositely constrained partial specializations of
template class X.  Since the partial specializations are oppositely
constrained, an ambiguity should not be possible.

The test case exhibits some fragility.  The error only occurs when the requires
expression in the C concept definition specifies a constrained-type-specifer as
the trailing-return-type of the compound-requirement at #3; substituting a
non-placeholder simple-type-specifier as is done at #2 by compiling with the
AVOID_BOOLEAN_CONCEPT macro defined enables successful compilation.

Additionally, compilation is successful (with or without AVOID_BOOLEAN_CONCEPT
defined) if the code is adjusted at #6 to pass a fundamental type (char)
instead of S as the template argument to X, and at #4 and #5 to pass T rather
than the member type T::type in the requires clause.

$ cat t.cpp
template<typename T>
concept bool
Boolean()
{
  return requires(T t)
  {
    { t } -> bool                 // #1
  };
}

template<typename T>
concept bool
C() {
  return requires (T t)
  {
#if AVOID_BOOLEAN_CONCEPT
    { t } -> bool;                // #2
#else
    { t } -> Boolean;             // #3
#endif
  };
}

template<typename T>
struct X;
template<typename T>
requires ! C<typename T::type>()  // #4
struct X<T> {
    using type = int;
};
template<typename T>
requires C<typename T::type>()    // #5
struct X<T> {
    using type = int;
};

struct S {
    using type = char;
};

void f() {
    X<S>::type x;                 // #6
}

$ svn info   # From my local svn gcc repo.
Path: .
Working Copy Root Path: /home/tom/src/gcc-trunk
URL: svn://gcc.gnu.org/svn/gcc/trunk
Relative URL: ^/trunk
Repository Root: svn://gcc.gnu.org/svn/gcc
Repository UUID: 138bc75d-0d04-0410-961f-82ee72b054a4
Revision: 232017
Node Kind: directory
Schedule: normal
Last Changed Author: nathan
Last Changed Rev: 232017
Last Changed Date: 2015-12-31 09:07:52 -0500 (Thu, 31 Dec 2015)

# Using the gcc version above, the error is produced:
$ g++ -c -std=c++1z t.cpp
t.cpp: In function ‘void f()’:
t.cpp:42:9: error: ambiguous template instantiation for ‘struct X<S>’
     X<S>::type x;
         ^~

t.cpp:28:8: note: candidates are: template<class T>  requires
predicate(!(C<typename T::type>)()) struct X<T> [with T = S]
 struct X<T> {
        ^~~~

t.cpp:33:8: note:                 template<class T>  requires
predicate((C<typename T::type>)()) struct X<T> [with T = S]
 struct X<T> {
        ^~~~

t.cpp:42:5: error: incomplete type ‘X<S>’ used in nested name specifier
     X<S>::type x;
     ^~~~

# Compiling with AVOID_BOOLEAN_CONCEPT defined avoids the spurious error:
$ g++ -c -std=c++1z t.cpp -DAVOID_BOOLEAN_CONCEPT; echo $?
0

Reply via email to