Created attachment 32608 [details] Reproducible test program This works under gcc 4.7.2 and clang 3.4, but fails to compile under gcc 4.9 RC1. enum class seems to be the only issue; plain enums work fine. #include <boost/type_traits.hpp> #include <iostream> enum class E {}; int main() { std::cout << boost::has_complement<E>() << std::endl; } Using Boost 1.55 and g++ -std=c++11, we get: In file included from /opt/local/include/boost/config.hpp:57:0, from /opt/local/include/boost/type_traits/add_const.hpp:13, from /opt/local/include/boost/type_traits.hpp:13, from a.cpp:1: /opt/local/include/boost/type_traits/detail/has_prefix_operator.hpp: In instantiation of 'const bool boost::detail::has_complement_impl::operator_exists<E>::value': /opt/local/include/boost/type_traits/detail/has_prefix_operator.hpp:173:4: required from 'const bool boost::detail::has_complement_impl::trait_impl1<E, boost::detail::has_complement_impl::dont_care, false>::value' /opt/local/include/boost/type_traits/detail/has_prefix_operator.hpp:195:4: required from 'const bool boost::detail::has_complement_impl::trait_impl<E, boost::detail::has_complement_impl::dont_care>::value' /opt/local/include/boost/type_traits/detail/has_prefix_operator.hpp:202:1: required from 'struct boost::has_complement<E>' a.cpp:7:41: required from here /opt/local/include/boost/type_traits/detail/has_prefix_operator.hpp:152:56: error: no match for 'operator~' (operand type is 'E') BOOST_STATIC_CONSTANT(bool, value = (sizeof(check(((BOOST_TT_TRAIT_OP make<Rhs>()),make<has_operator>())))==sizeof(::boost::type_traits::yes_type))); ^ /opt/local/include/boost/type_traits/detail/has_prefix_operator.hpp: In instantiation of 'const bool boost::detail::has_complement_impl::operator_returns_void<E>::value': /opt/local/include/boost/type_traits/detail/has_prefix_operator.hpp:173:4: required from 'const bool boost::detail::has_complement_impl::trait_impl1<E, boost::detail::has_complement_impl::dont_care, false>::value' /opt/local/include/boost/type_traits/detail/has_prefix_operator.hpp:195:4: required from 'const bool boost::detail::has_complement_impl::trait_impl<E, boost::detail::has_complement_impl::dont_care>::value' /opt/local/include/boost/type_traits/detail/has_prefix_operator.hpp:202:1: required from 'struct boost::has_complement<E>' a.cpp:7:41: required from here /opt/local/include/boost/type_traits/detail/has_prefix_operator.hpp:89:102: error: no match for 'operator~' (operand type is 'E') BOOST_STATIC_CONSTANT(bool, value = (sizeof(::boost::type_traits::yes_type)==sizeof(returns_void((BOOST_TT_TRAIT_OP make<Rhs>(),returns_void_t()))))); ^ a.cpp: In function 'int main()': a.cpp:7:41: error: cannot bind 'std::ostream {aka std::basic_ostream<char>}' lvalue to 'std::basic_ostream<char>&&' { std::cout << boost::has_complement<E>() << std::endl; } ^ In file included from /opt/local/include/gcc49/c++/istream:39:0, from /opt/local/include/gcc49/c++/sstream:38, from /opt/local/include/gcc49/c++/complex:45, from /opt/local/include/boost/type_traits/is_complex.hpp:12, from /opt/local/include/boost/type_traits.hpp:49, from a.cpp:1: /opt/local/include/gcc49/c++/ostream:602:5: note: initializing argument 1 of 'std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&&, const _Tp&) [with _CharT = char; _Traits = std::char_traits<char>; _Tp = boost::has_complement<E>]' operator<<(basic_ostream<_CharT, _Traits>&& __os, const _Tp& __x) ^
Also filed this as a Boost bug at https://svn.boost.org/trac/boost/ticket/9913
Preprocessed source, please. And ideally reduced so it doesn't contain a billion lines of MPL!
reduced test case: struct A; typedef A false_; struct A { }; template <int> struct B; template <> struct B<false> : false_ { }; template <int> struct C { static const int value = 0; }; template <typename T> T &make (); struct D { template <class T> D (T); }; template <typename, typename, int> struct G; template <typename Rhs> struct H { static const int value = G<Rhs, int, 0>::value; }; template <typename Rhs> struct I : B<H<Rhs>::value> { }; enum class E; int operator~(const D &); template <typename Rhs> struct F { static const int value = sizeof ~make<Rhs>(); }; template <typename Rhs, typename Ret> struct G<Rhs, Ret, 0> { static const int value = C<F<Rhs>::value>::value; }; int main () { I<E>(); } markus@x4 tmp % g++ -std=c++11 boost.ii boost.ii: In instantiation of ‘const int F<E>::value’: boost.ii:35:20: required from ‘const int G<E, int, 0>::value’ boost.ii:22:20: required from ‘const int H<E>::value’ boost.ii:24:32: required from ‘struct I<E>’ boost.ii:37:20: required from here boost.ii:31:35: error: no match for ‘operator~’ (operand type is ‘E’) static const int value = sizeof ~make<Rhs>(); ^
Confirmed. Not sure if the code is valid.
Further reduced: struct D { template <class T> D (T); }; int operator~(const D &); template <typename T> T &make (); template <typename Rhs> struct H { static const int value = sizeof ~make<Rhs>(); }; enum class E; int main () { return H<E>::value; }
Started to be rejected with r192471 aka PR17805.
Both clang and G++ reject: static const int value = sizeof ~make<E>(); Whereas clang accepts (and G++ rejects) the same expression using a dependent type: template <typename Rhs> struct H { static const int value = sizeof ~make<Rhs>(); }; Clang constructs a temporary D and applies operator~ to that temporary
I'm about to take a few days off, but note that the patch from Alexandre which I moved forward fixed an accept invalid. Thus if you like, before leaving I can revert it in the branches and return to it for 4.10. Let me know.
Given that the patch has been there for quite some time already, I think it is important to first understand if this testcase is valid or not, before considering reversion. CCing Alex as well.
Humm, I notice only now that the issue only affects enum classes not plain enums. Thus must be easy to fix.
I don't know if it's valid, but the discrepancy noted in comment 7 is probably relevant, one way or another
The guys on stackoverflow think it's invalid: http://stackoverflow.com/questions/23108590/is-this-valid-c11
Clang is wrong, only operator taking E or reference to E can contribute. In 13.3.1.2 §3 For a unary operator @ with an operand of a type whose cv-unqualified version is T1, and for a binary operator @ with a left operand of a type whose cv-unqualified version is T1 and a right operand of a type whose cv-unqualified version is T2, three sets of candidate functions, designated member candidates, nonmember candidates and built-in candidates, are constructed as follows: Follow by : However, if no operand has a class type, only those non-member functions in the lookup set that have a first parameter of type T1 or “reference to (possibly cv-qualified) T1”, when T1 is an enumeration type, or (if there is a right operand) a second parameter of type T2 or “reference to (possibly cv-qualified) T2”, when T2 is an enumeration type, are candidate functions.
Thanks Nicolas. Closing.
Did someone file a corresponding PR for clang? It is useful for them, but also for gcc because it gives them a chance to give a different interpretation of the standard.
(In reply to Marc Glisse from comment #15) > Did someone file a corresponding PR for clang? It is useful for them, but > also for gcc because it gives them a chance to give a different > interpretation of the standard. Unfortunately filing bugs for clang is like posting to /dev/null most of the time.
(In reply to Markus Trippelsdorf from comment #16) > Unfortunately filing bugs for clang is like posting to /dev/null > most of the time. That's not my experience - if it hasn't been filed yet I'll do so.
http://llvm.org/bugs/show_bug.cgi?id=19452
(In reply to Jonathan Wakely from comment #17) > (In reply to Markus Trippelsdorf from comment #16) > > Unfortunately filing bugs for clang is like posting to /dev/null > > most of the time. > > That's not my experience - if it hasn't been filed yet I'll do so. > http://llvm.org/bugs/show_bug.cgi?id=19452 I was wrong this time: % clang++ -std=c++11 b.ii b.ii:11:35: error: invalid argument type 'E' to unary expression static const int value = sizeof ~make<Rhs>(); ^~~~~~~~~~~~ b.ii:16:22: note: in instantiation of template class 'H<E>' requested here int main () { return H<E>::value; } ^ 1 error generated.