Regression in Boost.Variant with gcc6.3 in C++03 mode
Hi,
This is the simplest possible repro I could get:
#include
On 27 Jun 2017, at 20:09, dariomt--- via Boost-users
wrote: #include
class A {}; class B : private A {}; typedef boost::variant variant_t; int main() { B b; variant_t v (b); }
In `boost/type_traits/is_convertible.hpp`:
```
123 struct any_conversion
124 {
125 template <typename T> any_conversion(const volatile T&);
126 template <typename T> any_conversion(const T&);
127 template <typename T> any_conversion(volatile T&);
128 template <typename T> any_conversion(T&);
129 };
130
131 template <typename T> struct checker
132 {
133 static boost::type_traits::no_type _m_check(any_conversion ...);
134 static boost::type_traits::yes_type _m_check(T, int);
135 };
```
And according to [https://stackoverflow.com/questions/30004771/why-is-a-malformed-function-use...], the standard conversion sequence takes precedence of the user-defined conversion (`any_conversion`), hence `checker<A>::_m_check(B(), 0)` results in a hard error.
So I suspect this is a bug in 'type_traits' library, but I'm not sure. Hopefully somebody else can confirm. (I'm sorry but I don't know to whom should I CC this post.)
An easy workaround would be specializing `boost::is_convertible` for your classes:
```
namespace boost {
template <> struct is_convertible : boost::false_type {};
template <> struct is_convertible
2017-06-27 17:46 GMT+02:00 d25fe0be@outlook.com
So I suspect this is a bug in 'type_traits' library, but I'm not sure. Hopefully somebody else can confirm. (I'm sorry but I don't know to whom should I CC this post.)
I don't know why clang accepts your code though. Perhaps `boost::is_convertible` is conditionally compiled to some different implementations in Clang.
Thanks for the analysis. My guess is that clang uses a different implementation of is_convertible. Also, I guess this works in C++14 because std::is_convertible is used instead? Regards
On 28 Jun 2017, at 00:53, dariomt@gmail.com wrote:
2017-06-27 17:46 GMT+02:00 d25fe0be@outlook.com
: So I suspect this is a bug in 'type_traits' library, but I'm not sure. Hopefully somebody else can confirm. (I'm sorry but I don't know to whom should I CC this post.) I don't know why clang accepts your code though. Perhaps `boost::is_convertible` is conditionally compiled to some different implementations in Clang.
Thanks for the analysis. My guess is that clang uses a different implementation of is_convertible. Also, I guess this works in C++14 because std::is_convertible is used instead?
Yes, after a deeper dig, `boost/type_traits/intrinsics.hpp` shows that `type_traits` uses Clang's intrinsics to do the job:
```
157 #if defined(BOOST_CLANG) && defined(__has_feature) && !defined(__CUDACC__)
[...]
213 # if __has_feature(is_convertible_to)
214 # define BOOST_IS_CONVERTIBLE(T,U) __is_convertible_to(T,U)
215 # endif
```
After commenting out macro `BOOST_IS_CONVERTIBLE`, clang errors out the original code as well.
And I believe this finding gives us an easier workaround: Just defining our own `BOOST_IS_CONVERTIBLE` before including `boost/variant.hpp`, and the compilation error should disappear.
```
#include
On 28 Jun 2017, at 01:27, d25fe0be@outlook.com wrote:
And I believe this finding gives us an easier workaround: Just defining our own `BOOST_IS_CONVERTIBLE` before including `boost/variant.hpp`, and the compilation error should disappear.
``` #include
#define BOOST_IS_CONVERTIBLE(T,U) std::is_convertible ::value #include
[...] ```
Oh sorry I forgot you're using C++03. Maybe you could write your own `is_convertible` in C++03 and redirect boost's to there.
On 28 Jun 2017, at 01:30, d25fe0be--- via Boost-users
wrote: On 28 Jun 2017, at 01:27, d25fe0be@outlook.com wrote:
And I believe this finding gives us an easier workaround: Just defining our own `BOOST_IS_CONVERTIBLE` before including `boost/variant.hpp`, and the compilation error should disappear.
``` #include
#define BOOST_IS_CONVERTIBLE(T,U) std::is_convertible ::value #include
[...] ``` Oh sorry I forgot you're using C++03.
Maybe you could write your own `is_convertible` in C++03 and redirect boost's to there.
Sorry I missed John's reply.. I believe John is right, without C++11 a fully conforming is_convertible seems not to be implementable (I didn't find a way to remove `_m_check` taking the inaccessible base as a parameter from the overload set.), hence 'your own `is_convertible`' seems not to be feasible either. Thank you John for pointing this out, and sorry for the noise.
2017-06-27 20:05 GMT+02:00 d25fe0be@outlook.com
Sorry I missed John's reply..
I believe John is right, without C++11 a fully conforming is_convertible seems not to be implementable (I didn't find a way to remove `_m_check` taking the inaccessible base as a parameter from the overload set.), hence 'your own `is_convertible`' seems not to be feasible either.
Thank you John for pointing this out, and sorry for the noise.
Thanks for the follow up. So the only workaround with 1.64 is to get rid of the private inheritance, right? Anyway, my test case used to work in older versions of Boost. I'm not sure about what changed between 1.61 and 1.62, if it's a change in type_traits or a change in variant. Would it be possible to recover the lost functionality in 1.65?
On 28 Jun 2017, at 16:52, dariomt@gmail.com wrote:
2017-06-27 20:05 GMT+02:00 d25fe0be@outlook.com
: Sorry I missed John's reply.. I believe John is right, without C++11 a fully conforming is_convertible seems not to be implementable (I didn't find a way to remove `_m_check` taking the inaccessible base as a parameter from the overload set.), hence 'your own `is_convertible`' seems not to be feasible either.
Thank you John for pointing this out, and sorry for the noise.
Thanks for the follow up.
So the only workaround with 1.64 is to get rid of the private inheritance, right?
I'm afraid yes.
Anyway, my test case used to work in older versions of Boost. I'm not sure about what changed between 1.61 and 1.62, if it's a change in type_traits or a change in variant. Would it be possible to recover the lost functionality in 1.65?
I think the change was introduced by commit [https://github.com/boostorg/variant/commit/b3650685f941a0c35cadfd878a185f274...], which tried to solve ticket #11602 [https://svn.boost.org/trac10/ticket/11602].
I don't know how can both #11602 and the issue here be solved at the same time. CC'ing Antony.
Perhaps we can test for convertibility only if C++11 is available, and leave #11602 unsolved in C++03 (as there're still corner cases not solved as of now, see below)?
---
As `boost::is_constructible` triggers a hard error when testing a class and its privately parent, the following code fails the compilation as well (both before (because of #11602) and after (because of the hard error triggered by `boost::is_convertible`) commit b3650685f941a0c35cadfd878a185f274e132788):
```
#include
So I suspect this is a bug in 'type_traits' library, but I'm not sure. Hopefully somebody else can confirm. (I'm sorry but I don't know to whom should I CC this post.)
The short answer, is that a fully conforming is_convertible requires C++11 language features, so your test code is fine in C++11 or 14 mode but in 03 mode uses legacy code which is known not to work in every circumstance. clang works because the clang front end provides an intrinsic for is_convertible which gcc does not (last I checked). Of course that doesn't help you much, sorry, John. --- This email has been checked for viruses by AVG. http://www.avg.com
participants (3)
-
d25fe0be@outlook.com
-
dariomt@gmail.com
-
John Maddock