[Bug c++/87366] New: SFINAE trait as template parameter causes incorrect application of trait to other areas

sudgylacmoe at gmail dot com gcc-bugzilla@gcc.gnu.org
Wed Sep 19 17:31:00 GMT 2018


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

            Bug ID: 87366
           Summary: SFINAE trait as template parameter causes incorrect
                    application of trait to other areas
           Product: gcc
           Version: 8.2.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: sudgylacmoe at gmail dot com
  Target Milestone: ---

Created attachment 44727
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=44727&action=edit
Compiler output when trying to compile the complete code snippet

This code should be accepted (and both clang and msvc accept it according to
godbolt), but gcc does not, on every version that I tested (7, 8, and trunk):

namespace std {
    template <typename T, typename U> struct is_same {static constexpr bool
value = false;};
    template <typename T> struct is_same<T, T> {static constexpr bool value =
true;};
    template <bool, typename T = void> struct enable_if {};
    template <typename T> struct enable_if<true, T> {using type = T;};
    template <typename T, typename U> constexpr bool is_same_v = is_same<T,
U>::value;
    template <bool B, typename T = void> using enable_if_t = typename
enable_if<B, T>::type;
}

struct A {};
struct B {};

template <typename T> struct wrapper {};

template <typename T, typename = std::enable_if_t<std::is_same_v<T, A>>> using
ok_t = T;

template <typename T> void not_even_called(wrapper<const ok_t<T>&> a);

template <typename T> int called(wrapper<const T&> a);

void test(wrapper<const B&>& val)
{
    called(val);
}

GCC fails to compile with the following error message:

test.cpp: In function ‘void test(wrapper<const B&>&)’:
test.cpp:23:15: error: no matching function for call to ‘called(wrapper<const
B&>&)’
     called(val);
               ^
test.cpp:19:27: note: candidate: ‘template<class T> int
called(wrapper<ok_t<T>&>)’
 template <typename T> int called(wrapper<const T&> a);
                           ^~~~~~
test.cpp:19:27: note:   template argument deduction/substitution failed:
test.cpp: In substitution of ‘template<class T> int called(wrapper<ok_t<T>&>)
[with T = B]’:
test.cpp:23:15:   required from here
test.cpp:19:27: error: no type named ‘type’ in ‘struct std::enable_if<false,
void>’

As you can see, the SFINAE trait ok_t from not_even_called got applied to the
parameter in called.  Removing not_even_called makes the code compile, and
swapping the declaration of called and not_even_called makes the code compile
(and then you can even call not_even_called with a wrapper<const B&>, which
should fail).  Removing the wrapper makes it compile, and moving the enable_if
directly into the wrapper makes it compile as well.  In addition, making ok_t
work for struct B instead of struct A makes it compile.

I'm guessing what is happening is that for some reason gcc thinks that
wrapper<ok_t<T>> is the same as wrapper<T> and starts applying whatever it saw
to the first occurrence to all future occurrences of the type.

I have attached the compiler output when run with -v trying to compile the code
I posted above.


More information about the Gcc-bugs mailing list