[llvm-bugs] [Bug 27753] New: SFINAE issue on Clang 3.7

via llvm-bugs llvm-bugs at lists.llvm.org
Mon May 16 01:09:03 PDT 2016


https://llvm.org/bugs/show_bug.cgi?id=27753

            Bug ID: 27753
           Summary: SFINAE issue on Clang 3.7
           Product: clang
           Version: 3.7
          Hardware: PC
                OS: All
            Status: NEW
          Severity: normal
          Priority: P
         Component: C++11
          Assignee: unassignedclangbugs at nondot.org
          Reporter: wenzel.jakob at epfl.ch
                CC: dgregor at apple.com, llvm-bugs at lists.llvm.org
    Classification: Unclassified

I think I've stumbled upon an issue related to the C++11 SFINAE implementation
in Clang.

The following type_traits-style code tries to test whether a given type (or a
STL map involving a key and value type) are comparable using operator==.

When instantiating it with a non-comparable type, Clang issues a type checker
error despite there being a fallback definition where the relevant types can be
substituted without errors.

The observed and expected output are listed below. It works without issues in
GCC 5.0. This was compiled using the latest XCode build.


#include <iostream>
#include <vector>
#include <map>

/* Non-comparable dummy class */
struct A {
    bool operator==(const A&) = delete;
};

/* SFINAE helper class to check for the presence of 'key_type' and 'value_type'
*/
template <typename T>  struct container_traits {
    template <typename T2> static std::true_type test_key(typename T2::key_type
*);
    template <typename T2> static std::false_type test_key(...);
    template <typename T2> static std::true_type test_value(typename
T2::value_type *);
    template <typename T2> static std::false_type test_value(...);
    static constexpr const bool has_key = std::is_same<std::true_type,
decltype(test_key<T>(nullptr))>::value;
    static constexpr const bool has_value = std::is_same<std::true_type,
decltype(test_value<T>(nullptr))>::value;

    /* True if 'key_type' and 'value_type' typedefs exist */
    static constexpr const bool is_map = has_key && has_value;
};

/* Default: is_comparable -> std::false_type */
template <typename T, typename SFINAE = void>
struct is_comparable : std::false_type { };

/* For non-map data structures, check whether operator== can be instantiated */
template <typename T>
struct is_comparable< T, typename std::enable_if<!container_traits<T>::is_map
&&
                                                 decltype((void)
(std::declval<const T &>() == std::declval<const T &>()),
                                                 bool())(true)>::type>
    : std::true_type { };

/* For a map data structure, recursively check the key and value types */
template <typename T>
struct is_comparable<T, typename
std::enable_if<container_traits<T>::is_map>::type> {
    static constexpr const bool value =
        is_comparable<typename T::key_type>::value &&
        is_comparable<typename T::value_type>::value;
};


int main(int argc, char *argv[]) {
    std::cout << "is_comparable(int) = "     << is_comparable<int>::value <<
std::endl;
    std::cout << "is_comparable(map int) = " << is_comparable<std::map<int,
int>>::value << std::endl;
    std::cout << "is_comparable(A) = "       << is_comparable<A>::value <<
std::endl;
    std::cout << "is_comparable(map A) = "   << is_comparable<std::map<A,
A>>::value << std::endl;

    /* Expected output (GCC-5.0)

       is_comparable(int) = 1
       is_comparable(map int) = 1
       is_comparable(A) = 0
       is_comparable(map A) = 0
    */

    /* Actual output

       $ clang++ -v
       Apple LLVM version 7.3.0 (clang-703.0.31)
       Target: x86_64-apple-darwin15.4.0
       Thread model: posix
       InstalledDir:
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin

       $ clang++ -std=c++14 -Wall test.cpp -o test

       In file included from test.cpp:1:
       In file included from
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/iostream:38:
       In file included from
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/ios:216:
       In file included from
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/__locale:15:
       In file included from
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/string:439:
       In file included from
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/algorithm:627:
      
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/utility:410:22:
error: invalid operands to binary expression ('const A' and 'const A')
           return __x.first == __y.first && __x.second == __y.second;
                  ~~~~~~~~~ ^  ~~~~~~~~~
       test.cpp:38:93: note: in instantiation of function template
specialization 'std::__1::operator==<const A, A>' requested here
                                                        decltype((void)
(std::declval<const T &>() == std::declval<const T &>()),
                                                                               
                   ^
       test.cpp:33:9: note: during template argument deduction for class
template partial specialization 'is_comparable<type-parameter-0-0, typename
enable_if<container_traits<T>::no_match && decltype((void)(std::declval<const T
&>() == std::declval<const T
             &>()) , bool())(true), void>::type>' [with T =
std::__1::pair<const A, A>]
               is_comparable<typename T::value_type>::value;
               ^
       test.cpp:48:47: note: in instantiation of template class
'is_comparable<std::__1::map<A, A, std::__1::less<A>,
std::__1::allocator<std::__1::pair<const A, A> > >, void>' requested here
           std::cout << "is_comparable(map A) = " << is_comparable<std::map<A,
A>>::value << std::endl;
                                                     ^
       test.cpp:6:7: note: candidate function not viable: 'this' argument has
type 'const A', but method is not marked const
               bool operator==(const A&) = delete;
                    ^
      
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/utility:408:1:
note: candidate template ignored: could not match 'pair<type-parameter-0-0,
type-parameter-0-1>' against 'const A'
       operator==(const pair<_T1,_T2>& __x, const pair<_T1,_T2>& __y)
       ^
       1 error generated.
    */

    return 0;
}

-- 
You are receiving this mail because:
You are on the CC list for the bug.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-bugs/attachments/20160516/c6622861/attachment.html>


More information about the llvm-bugs mailing list