Subject: Re: [boost] [type_traits][parameter] Inconsistent boost::is_convertible between gcc and clang
From: John Maddock (boost.regex_at_[hidden])
Date: 2012-08-12 14:06:11


> "Non-intrinsic version of `boost::is_convertible<int, int&>` returns
> true_type" is a BUG.

Yes it's a bug, but whether it's completely fixable is another matter (see
comments below).

> So, in Boost 1.47 and later versions, `boost::is_convertible<int, int&>`
> should return false_type.

Right.

> Below, I'll show the bug fix using the non-intrinsic version for gcc.
> The bug is caused by the following code (Line 132):
>
> template <typename From, typename To>
> struct is_convertible_basic_impl
> {
> static typename add_rvalue_reference<From>::type _m_from;
> static bool const value = sizeof(
> boost::detail::checker<To>::_m_check(_m_from, 0) )
> == sizeof(::boost::type_traits::yes_type);
> };
>
> Here, `_m_from` is not treated as an rvalue.
> The correct code is
>
> template <typename From, typename To>
> struct is_convertible_basic_impl
> {
> static bool const value = sizeof(
> boost::detail::checker<To>::_m_check(boost::declval<From>(),
> 0) )
> == sizeof(::boost::type_traits::yes_type);
> };

Yep. Fixed in Trunk.

> Also, `any_conversion` needs a constructor for an rvalue (Line 120):
>
> template <typename T> any_conversion(const T&);

Yep, fixed in Trunk.

> Finally, in `is_convertible_impl`, we shouldn't use `ref_type` in Line
> 299.
> Just using `From` is correct:
>
> boost::detail::is_convertible_basic_impl<From,To>::value
>
> With these changes, `boost::is_convertible<int, int&>` on gcc
> returns false_type.

It does, but it also terminally breaks C++03 compilers (not just gcc).

> One note:
> The above code cannot deal with `boost::is_convertible<Func, Func&>`,
> where `Func` is a function type in a C++03 mode.

Not only that, it also breaks for abstract types, arrays, incomplete types,
and anything else I've forgotten.

I've fixed the issue for GCC in C++11 mode by forwarding to
std::is_convertible, but it remains for now in C++03 mode.

Note that other compilers are similarly effected *even when using a compiler
intrinsic*, so for example given:

1) is_convertible<int&&, int&>
2) is_convertible<int, int&>

MSVC fails (1) even though it's using a compiler intrinsic (and no we can't
stop using it, that breaks other stuff).
Intel on Win32 fails both 1 & 2, again using it's __is_convertible
intrinsic.

It seems to me that these related issues are basically unfixable without
badly breaking something else,

Regards, John.