From 7f792f96c9e636c2c9848651b7e9f8eb9498fb81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A1lint=20Cserni?= Date: Wed, 29 Mar 2017 22:58:49 +0200 Subject: [PATCH 1/6] Make is_virtual_base_of work on final classes --- .../boost/type_traits/is_virtual_base_of.hpp | 88 ++++++------------- 1 file changed, 26 insertions(+), 62 deletions(-) diff --git a/include/boost/type_traits/is_virtual_base_of.hpp b/include/boost/type_traits/is_virtual_base_of.hpp index 84cb355..1321f22 100644 --- a/include/boost/type_traits/is_virtual_base_of.hpp +++ b/include/boost/type_traits/is_virtual_base_of.hpp @@ -1,4 +1,5 @@ // (C) Copyright Daniel Frey and Robert Ramey 2009. +// (C) Copyright Balint Cserni 2017 // Use, modification and distribution are subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt). @@ -9,7 +10,6 @@ #define BOOST_TT_IS_VIRTUAL_BASE_OF_HPP_INCLUDED #include -#include namespace boost { namespace detail { @@ -22,70 +22,34 @@ namespace detail { #pragma GCC system_header #endif -template +template struct is_virtual_base_of_impl { - BOOST_STATIC_CONSTANT(bool, value = false); -}; + template + struct can_cast + { + typedef char YES; + typedef struct { char x[2]; } NO; -template -struct is_virtual_base_of_impl -{ - union max_align - { - unsigned u; - unsigned long ul; - void* v; - double d; - long double ld; -#ifndef BOOST_NO_LONG_LONG - long long ll; -#endif - }; -#ifdef __BORLANDC__ - struct boost_type_traits_internal_struct_X : public virtual Derived, public virtual Base - { - boost_type_traits_internal_struct_X(); - boost_type_traits_internal_struct_X(const boost_type_traits_internal_struct_X&); - boost_type_traits_internal_struct_X& operator=(const boost_type_traits_internal_struct_X&); - ~boost_type_traits_internal_struct_X()throw(); - max_align data[4]; - }; - struct boost_type_traits_internal_struct_Y : public virtual Derived - { - boost_type_traits_internal_struct_Y(); - boost_type_traits_internal_struct_Y(const boost_type_traits_internal_struct_Y&); - boost_type_traits_internal_struct_Y& operator=(const boost_type_traits_internal_struct_Y&); - ~boost_type_traits_internal_struct_Y()throw(); - max_align data[4]; - }; -#else - struct boost_type_traits_internal_struct_X : public Derived, virtual Base - { - boost_type_traits_internal_struct_X(); - boost_type_traits_internal_struct_X(const boost_type_traits_internal_struct_X&); - boost_type_traits_internal_struct_X& operator=(const boost_type_traits_internal_struct_X&); - ~boost_type_traits_internal_struct_X()throw(); - max_align data[16]; - }; - struct boost_type_traits_internal_struct_Y : public Derived - { - boost_type_traits_internal_struct_Y(); - boost_type_traits_internal_struct_Y(const boost_type_traits_internal_struct_Y&); - boost_type_traits_internal_struct_Y& operator=(const boost_type_traits_internal_struct_Y&); - ~boost_type_traits_internal_struct_Y()throw(); - max_align data[16]; - }; -#endif - BOOST_STATIC_CONSTANT(bool, value = (sizeof(boost_type_traits_internal_struct_X)==sizeof(boost_type_traits_internal_struct_Y))); -}; + // C-style casts have the power to ignore inheritance visibility while still act as a static_cast. + // They can also fall back to the behaviour of reinterpret_cast, which allows is_virtual_base_of to work on non-class types too. + // Note that because we are casting pointers there can be no user-defined operators to interfere. + template static YES test(int*); + static NO test(...); -template -struct is_virtual_base_of_impl2 -{ - typedef boost::integral_constant::value && ! boost::is_same::value)> tag_type; - typedef is_virtual_base_of_impl imp; - BOOST_STATIC_CONSTANT(bool, value = imp::value); + BOOST_STATIC_CONSTANT(bool, value = (sizeof(test(nullptr)) == sizeof(YES))); + }; + + // Implementation based on the standard's rules of explicit type conversions. + // A pointer to an object of *derived* class type may be explicitly converted to a pointer to an *unambiguous* *base* class type. + // A pointer to an object of an *unambiguous* *non-virtual* *base* class type may be explicitly converted to a pointer of a *derived* class type. + // Therefore Derived has a virtual base Base if and only if + // (1) a Derived* can be converted to Base* (so the base class is unambiguous, which comes necessarily from virtual inheritance) + // (2) a Base* cannot be converted to Derived* (so the base class is either ambiguous or virtual) + // With both conditions true, Base must be a virtual base of Derived. + // The "is_base_of" is only needed so the compiler can (but is not required to) error out if the types are incomplete. + // This is in league with the the expected behaviour. + BOOST_STATIC_CONSTANT(bool, value = (boost::is_base_of::value && can_cast::value && !can_cast::value)); }; #ifdef BOOST_MSVC @@ -94,7 +58,7 @@ struct is_virtual_base_of_impl2 } // namespace detail -template struct is_virtual_base_of : public integral_constant::value)>{}; +template struct is_virtual_base_of : public integral_constant::value)>{}; template struct is_virtual_base_of : public false_type{}; template struct is_virtual_base_of : public false_type{}; From 63dea93d99a5157cfde519a6e845ff340942c43d Mon Sep 17 00:00:00 2001 From: jzmaddock Date: Wed, 9 May 2018 19:14:50 +0100 Subject: [PATCH 2/6] is_virtual_base_of.hpp: Reinstate old version for old broken compilers. --- .../boost/type_traits/is_virtual_base_of.hpp | 81 +++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/include/boost/type_traits/is_virtual_base_of.hpp b/include/boost/type_traits/is_virtual_base_of.hpp index 1321f22..d2efebb 100644 --- a/include/boost/type_traits/is_virtual_base_of.hpp +++ b/include/boost/type_traits/is_virtual_base_of.hpp @@ -10,6 +10,7 @@ #define BOOST_TT_IS_VIRTUAL_BASE_OF_HPP_INCLUDED #include +#include namespace boost { namespace detail { @@ -22,6 +23,8 @@ namespace detail { #pragma GCC system_header #endif +#if !defined(BOOST_NO_SFINAE_EXPR) && !defined(BOOST_NO_CXX11_FUNCTION_TEMPLATE_DEFAULT_ARGS) && !defined(BOOST_NO_CXX11_NULLPTR) + template struct is_virtual_base_of_impl { @@ -60,6 +63,84 @@ struct is_virtual_base_of_impl template struct is_virtual_base_of : public integral_constant::value)>{}; +#else + + template + struct is_virtual_base_of_impl + { + BOOST_STATIC_CONSTANT(bool, value = false); + }; + + template + struct is_virtual_base_of_impl + { + union max_align + { + unsigned u; + unsigned long ul; + void* v; + double d; + long double ld; +#ifndef BOOST_NO_LONG_LONG + long long ll; +#endif + }; +#ifdef __BORLANDC__ + struct boost_type_traits_internal_struct_X : public virtual Derived, public virtual Base + { + boost_type_traits_internal_struct_X(); + boost_type_traits_internal_struct_X(const boost_type_traits_internal_struct_X&); + boost_type_traits_internal_struct_X& operator=(const boost_type_traits_internal_struct_X&); + ~boost_type_traits_internal_struct_X()throw(); + max_align data[4]; + }; + struct boost_type_traits_internal_struct_Y : public virtual Derived + { + boost_type_traits_internal_struct_Y(); + boost_type_traits_internal_struct_Y(const boost_type_traits_internal_struct_Y&); + boost_type_traits_internal_struct_Y& operator=(const boost_type_traits_internal_struct_Y&); + ~boost_type_traits_internal_struct_Y()throw(); + max_align data[4]; + }; +#else + struct boost_type_traits_internal_struct_X : public Derived, virtual Base + { + boost_type_traits_internal_struct_X(); + boost_type_traits_internal_struct_X(const boost_type_traits_internal_struct_X&); + boost_type_traits_internal_struct_X& operator=(const boost_type_traits_internal_struct_X&); + ~boost_type_traits_internal_struct_X()throw(); + max_align data[16]; + }; + struct boost_type_traits_internal_struct_Y : public Derived + { + boost_type_traits_internal_struct_Y(); + boost_type_traits_internal_struct_Y(const boost_type_traits_internal_struct_Y&); + boost_type_traits_internal_struct_Y& operator=(const boost_type_traits_internal_struct_Y&); + ~boost_type_traits_internal_struct_Y()throw(); + max_align data[16]; + }; +#endif + BOOST_STATIC_CONSTANT(bool, value = (sizeof(boost_type_traits_internal_struct_X) == sizeof(boost_type_traits_internal_struct_Y))); + }; + + template + struct is_virtual_base_of_impl2 + { + typedef boost::integral_constant::value && !boost::is_same::value)> tag_type; + typedef is_virtual_base_of_impl imp; + BOOST_STATIC_CONSTANT(bool, value = imp::value); + }; + +#ifdef BOOST_MSVC +#pragma warning( pop ) +#endif + +} // namespace detail + +template struct is_virtual_base_of : public integral_constant::value)> {}; + +#endif + template struct is_virtual_base_of : public false_type{}; template struct is_virtual_base_of : public false_type{}; template struct is_virtual_base_of : public false_type{}; From 770c095dcc87d3cafaf358be38c2614412d6b3fd Mon Sep 17 00:00:00 2001 From: jzmaddock Date: Wed, 9 May 2018 19:31:45 +0100 Subject: [PATCH 3/6] is_virtual_base_of_test.cpp: add more tests for tricky cases and bug reports. --- test/is_virtual_base_of_test.cpp | 56 +++++++++++++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/test/is_virtual_base_of_test.cpp b/test/is_virtual_base_of_test.cpp index bda0e59..16707a0 100644 --- a/test/is_virtual_base_of_test.cpp +++ b/test/is_virtual_base_of_test.cpp @@ -45,6 +45,51 @@ struct bug11309_A { int a; }; struct bug11309_B : public virtual bug11309_A {}; struct bug11309_C : public bug11309_A { virtual ~bug11309_C() {} }; +struct bug11323_A { virtual void foo() {} }; +struct bug11323_B : public virtual bug11323_A { virtual void foo() {} }; +struct bug11323_C : public bug11323_B {}; + +#ifndef BOOST_NO_CXX11_FINAL + +struct bug11323_2A { virtual void foo() = 0; }; +struct bug11323_2B : public virtual bug11323_2A { void foo() override {} }; +struct bug11323_2C : public bug11323_2B {}; + + +class final_non_virtual_derived final : public non_virtual_base +{ +public: + final_non_virtual_derived(); + virtual int Y(); + virtual int X(); +}; + +class final_virtual_derived final : public virtual non_virtual_base +{ +public: + final_virtual_derived(); + virtual int Y(); + virtual int X(); +}; + +#endif + +class protected_virtual_derived : protected virtual non_virtual_base +{ +public: + protected_virtual_derived(); + virtual int Y(); + virtual int X(); +}; + +class private_virtual_derived : private virtual non_virtual_base +{ +public: + private_virtual_derived(); + virtual int Y(); + virtual int X(); +}; + TT_TEST_BEGIN(is_virtual_base_of) BOOST_CHECK_INTEGRAL_CONSTANT((::tt::is_virtual_base_of::value), false); @@ -87,7 +132,16 @@ BOOST_CHECK_INTEGRAL_CONSTANT((::tt::is_virtual_base_of::value), false); BOOST_CHECK_INTEGRAL_CONSTANT((::tt::is_virtual_base_of::value), true); - +#if !defined(BOOST_NO_SFINAE_EXPR) && !defined(BOOST_NO_CXX11_FUNCTION_TEMPLATE_DEFAULT_ARGS) && !defined(BOOST_NO_CXX11_NULLPTR) +BOOST_CHECK_INTEGRAL_CONSTANT((::tt::is_virtual_base_of::value), false); +#ifndef BOOST_NO_CXX11_FINAL +BOOST_CHECK_INTEGRAL_CONSTANT((::tt::is_virtual_base_of::value), false); +BOOST_CHECK_INTEGRAL_CONSTANT((::tt::is_virtual_base_of::value), false); +BOOST_CHECK_INTEGRAL_CONSTANT((::tt::is_virtual_base_of::value), true); +#endif +BOOST_CHECK_INTEGRAL_CONSTANT((::tt::is_virtual_base_of::value), true); +BOOST_CHECK_INTEGRAL_CONSTANT((::tt::is_virtual_base_of::value), true); +#endif TT_TEST_END From 02270ed668030f7df865c75278e6219a034a55e4 Mon Sep 17 00:00:00 2001 From: jzmaddock Date: Thu, 10 May 2018 10:31:24 +0100 Subject: [PATCH 4/6] is_virtual_base_of: tentative fixes for clang and older gcc versions. [CI SKIP] --- .../boost/type_traits/is_virtual_base_of.hpp | 31 +++++++++++++++++-- test/is_virtual_base_of_test.cpp | 8 ----- 2 files changed, 29 insertions(+), 10 deletions(-) diff --git a/include/boost/type_traits/is_virtual_base_of.hpp b/include/boost/type_traits/is_virtual_base_of.hpp index d2efebb..cf890b9 100644 --- a/include/boost/type_traits/is_virtual_base_of.hpp +++ b/include/boost/type_traits/is_virtual_base_of.hpp @@ -11,9 +11,10 @@ #include #include +#include namespace boost { -namespace detail { + namespace detail { #ifdef BOOST_MSVC @@ -23,7 +24,31 @@ namespace detail { #pragma GCC system_header #endif -#if !defined(BOOST_NO_SFINAE_EXPR) && !defined(BOOST_NO_CXX11_FUNCTION_TEMPLATE_DEFAULT_ARGS) && !defined(BOOST_NO_CXX11_NULLPTR) +#if !defined(BOOST_NO_SFINAE_EXPR) && !defined(BOOST_NO_CXX11_FUNCTION_TEMPLATE_DEFAULT_ARGS) && !defined(BOOST_NO_CXX11_NULLPTR) && !BOOST_WORKAROUND(BOOST_GCC, <= 40800) + +#ifdef __clang__ + + template + constexpr bool is_virtual_base_impl(...) { return true; } + + template(std::declval()))>* = + nullptr> + constexpr bool is_virtual_base_impl(int) { return false; } + + } // namespace detail + + template + struct is_virtual_base_of : public + boost::integral_constant< + bool, + boost::is_base_of::value && + detail::is_virtual_base_impl(0) && + !detail::is_virtual_base_impl(0) + > {}; + + +#else template struct is_virtual_base_of_impl @@ -63,6 +88,8 @@ struct is_virtual_base_of_impl template struct is_virtual_base_of : public integral_constant::value)>{}; +#endif // __clang__ + #else template diff --git a/test/is_virtual_base_of_test.cpp b/test/is_virtual_base_of_test.cpp index 16707a0..aa6435c 100644 --- a/test/is_virtual_base_of_test.cpp +++ b/test/is_virtual_base_of_test.cpp @@ -145,11 +145,3 @@ BOOST_CHECK_INTEGRAL_CONSTANT((::tt::is_virtual_base_of Date: Thu, 10 May 2018 11:34:02 +0100 Subject: [PATCH 5/6] is_virtual_base_of: more workarounds for clang and older gcc versions --- include/boost/type_traits/is_virtual_base_of.hpp | 5 +++-- test/is_virtual_base_of_test.cpp | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/include/boost/type_traits/is_virtual_base_of.hpp b/include/boost/type_traits/is_virtual_base_of.hpp index cf890b9..f9e1331 100644 --- a/include/boost/type_traits/is_virtual_base_of.hpp +++ b/include/boost/type_traits/is_virtual_base_of.hpp @@ -12,6 +12,7 @@ #include #include #include +#include namespace boost { namespace detail { @@ -24,7 +25,7 @@ namespace boost { #pragma GCC system_header #endif -#if !defined(BOOST_NO_SFINAE_EXPR) && !defined(BOOST_NO_CXX11_FUNCTION_TEMPLATE_DEFAULT_ARGS) && !defined(BOOST_NO_CXX11_NULLPTR) && !BOOST_WORKAROUND(BOOST_GCC, <= 40800) +#if !defined(BOOST_NO_SFINAE_EXPR) && !defined(BOOST_NO_CXX11_FUNCTION_TEMPLATE_DEFAULT_ARGS) && !defined(BOOST_NO_CXX11_NULLPTR) && !BOOST_WORKAROUND(BOOST_GCC, < 40800) #ifdef __clang__ @@ -32,7 +33,7 @@ namespace boost { constexpr bool is_virtual_base_impl(...) { return true; } template(std::declval()))>* = + boost::void_t()))>* = nullptr> constexpr bool is_virtual_base_impl(int) { return false; } diff --git a/test/is_virtual_base_of_test.cpp b/test/is_virtual_base_of_test.cpp index aa6435c..4b77b45 100644 --- a/test/is_virtual_base_of_test.cpp +++ b/test/is_virtual_base_of_test.cpp @@ -132,7 +132,7 @@ BOOST_CHECK_INTEGRAL_CONSTANT((::tt::is_virtual_base_of::value), false); BOOST_CHECK_INTEGRAL_CONSTANT((::tt::is_virtual_base_of::value), true); -#if !defined(BOOST_NO_SFINAE_EXPR) && !defined(BOOST_NO_CXX11_FUNCTION_TEMPLATE_DEFAULT_ARGS) && !defined(BOOST_NO_CXX11_NULLPTR) +#if !defined(BOOST_NO_SFINAE_EXPR) && !defined(BOOST_NO_CXX11_FUNCTION_TEMPLATE_DEFAULT_ARGS) && !defined(BOOST_NO_CXX11_NULLPTR) && !BOOST_WORKAROUND(BOOST_GCC, < 40800) BOOST_CHECK_INTEGRAL_CONSTANT((::tt::is_virtual_base_of::value), false); #ifndef BOOST_NO_CXX11_FINAL BOOST_CHECK_INTEGRAL_CONSTANT((::tt::is_virtual_base_of::value), false); From 7bba2acbcc4c250d77714f728a5f28255adb269c Mon Sep 17 00:00:00 2001 From: jzmaddock Date: Fri, 11 May 2018 17:19:44 +0100 Subject: [PATCH 6/6] is_virtual_base_of.hpp: simplify and use clang version for all compilers. --- .../boost/type_traits/is_virtual_base_of.hpp | 56 ++++--------------- 1 file changed, 12 insertions(+), 44 deletions(-) diff --git a/include/boost/type_traits/is_virtual_base_of.hpp b/include/boost/type_traits/is_virtual_base_of.hpp index f9e1331..c3d7684 100644 --- a/include/boost/type_traits/is_virtual_base_of.hpp +++ b/include/boost/type_traits/is_virtual_base_of.hpp @@ -27,11 +27,22 @@ namespace boost { #if !defined(BOOST_NO_SFINAE_EXPR) && !defined(BOOST_NO_CXX11_FUNCTION_TEMPLATE_DEFAULT_ARGS) && !defined(BOOST_NO_CXX11_NULLPTR) && !BOOST_WORKAROUND(BOOST_GCC, < 40800) -#ifdef __clang__ + // Implementation based on the standard's rules of explicit type conversions. + // A pointer to an object of *derived* class type may be explicitly converted to a pointer to an *unambiguous* *base* class type. + // A pointer to an object of an *unambiguous* *non-virtual* *base* class type may be explicitly converted to a pointer of a *derived* class type. + // Therefore Derived has a virtual base Base if and only if + // (1) a Derived* can be converted to Base* (so the base class is unambiguous, which comes necessarily from virtual inheritance) + // (2) a Base* cannot be converted to Derived* (so the base class is either ambiguous or virtual) + // With both conditions true, Base must be a virtual base of Derived. + // The "is_base_of" is only needed so the compiler can (but is not required to) error out if the types are incomplete. + // This is in league with the the expected behaviour. template constexpr bool is_virtual_base_impl(...) { return true; } + // C-style casts have the power to ignore inheritance visibility while still act as a static_cast. + // They can also fall back to the behaviour of reinterpret_cast, which allows is_virtual_base_of to work on non-class types too. + // Note that because we are casting pointers there can be no user-defined operators to interfere. template()))>* = nullptr> @@ -48,49 +59,6 @@ namespace boost { !detail::is_virtual_base_impl(0) > {}; - -#else - -template -struct is_virtual_base_of_impl -{ - template - struct can_cast - { - typedef char YES; - typedef struct { char x[2]; } NO; - - // C-style casts have the power to ignore inheritance visibility while still act as a static_cast. - // They can also fall back to the behaviour of reinterpret_cast, which allows is_virtual_base_of to work on non-class types too. - // Note that because we are casting pointers there can be no user-defined operators to interfere. - template static YES test(int*); - static NO test(...); - - BOOST_STATIC_CONSTANT(bool, value = (sizeof(test(nullptr)) == sizeof(YES))); - }; - - // Implementation based on the standard's rules of explicit type conversions. - // A pointer to an object of *derived* class type may be explicitly converted to a pointer to an *unambiguous* *base* class type. - // A pointer to an object of an *unambiguous* *non-virtual* *base* class type may be explicitly converted to a pointer of a *derived* class type. - // Therefore Derived has a virtual base Base if and only if - // (1) a Derived* can be converted to Base* (so the base class is unambiguous, which comes necessarily from virtual inheritance) - // (2) a Base* cannot be converted to Derived* (so the base class is either ambiguous or virtual) - // With both conditions true, Base must be a virtual base of Derived. - // The "is_base_of" is only needed so the compiler can (but is not required to) error out if the types are incomplete. - // This is in league with the the expected behaviour. - BOOST_STATIC_CONSTANT(bool, value = (boost::is_base_of::value && can_cast::value && !can_cast::value)); -}; - -#ifdef BOOST_MSVC -#pragma warning( pop ) -#endif - -} // namespace detail - -template struct is_virtual_base_of : public integral_constant::value)>{}; - -#endif // __clang__ - #else template