diff options
author | Howard Hinnant <hhinnant@apple.com> | 2013-04-02 21:25:06 +0000 |
---|---|---|
committer | Howard Hinnant <hhinnant@apple.com> | 2013-04-02 21:25:06 +0000 |
commit | 575e4e3650323d8c48a1827eda1fe797be27789a (patch) | |
tree | c14fc9686281cf11630956c88c0173eb0c9ba59d /libcxx | |
parent | eeed39a58372135639c0b5918efb13ca552daec5 (diff) | |
download | bcm5719-llvm-575e4e3650323d8c48a1827eda1fe797be27789a.tar.gz bcm5719-llvm-575e4e3650323d8c48a1827eda1fe797be27789a.zip |
Richard Smith: It was pointed out to me off-list that libc++'s non-compiler-builtin
implementation of std::is_polymorphic does this:
template <class _Tp> struct __is_polymorphic1 : public _Tp {};
... and that g++ rejects this if _Tp has an inaccessible virtual destructor
(because __is_polymorphic1<_Tp> would have a deleted virtual destructor
overriding _Tp's non-deleted destructor). Clang was failing to reject this;
I've fixed that in r178563, but that causes libc++'s corresponding test
case to fail with both clang and gcc when using the fallback
implementation. The fallback code also incorrectly rejects final types.
The attached patch fixes the fallback implementation of is_polymorphic; we
now use dynamic_cast's detection of polymorphic class types rather than
trying to determine if adding a virtual function makes the type larger:
enable_if<sizeof((_Tp*)dynamic_cast<const volatile
void*>(declval<_Tp*>())) != 0, ...>
Two things of note here:
* the (_Tp*) cast is necessary to work around bugs in Clang and g++ where
we otherwise don't instantiate the dynamic_cast (filed as PR15656)
* the 'const volatile' is here to treat is_polymorphic<cv T> as true for a
polymorphic class type T -- my reading of the standard suggests this is
incorrect, but it matches our builtin __is_polymorphic and gcc
llvm-svn: 178576
Diffstat (limited to 'libcxx')
-rw-r--r-- | libcxx/include/type_traits | 14 | ||||
-rw-r--r-- | libcxx/test/utilities/meta/meta.unary/meta.unary.prop/is_polymorphic.pass.cpp | 6 |
2 files changed, 11 insertions, 9 deletions
diff --git a/libcxx/include/type_traits b/libcxx/include/type_traits index f60f71b54e4..7178978f5cc 100644 --- a/libcxx/include/type_traits +++ b/libcxx/include/type_traits @@ -802,17 +802,13 @@ struct _LIBCPP_TYPE_VIS is_polymorphic #else -template <class _Tp> struct __is_polymorphic1 : public _Tp {}; -template <class _Tp> struct __is_polymorphic2 : public _Tp {virtual ~__is_polymorphic2() throw();}; - -template <class _Tp, bool = is_class<_Tp>::value> -struct __libcpp_polymorphic - : public integral_constant<bool, sizeof(__is_polymorphic1<_Tp>) == sizeof(__is_polymorphic2<_Tp>)> {}; - -template <class _Tp> struct __libcpp_polymorphic<_Tp, false> : public false_type {}; +template<typename _Tp> char &__is_polymorphic_impl( + typename enable_if<sizeof((_Tp*)dynamic_cast<const volatile void*>(declval<_Tp*>())) != 0, + int>::type); +template<typename _Tp> __two &__is_polymorphic_impl(...); template <class _Tp> struct _LIBCPP_TYPE_VIS is_polymorphic - : public __libcpp_polymorphic<_Tp> {}; + : public integral_constant<bool, sizeof(__is_polymorphic_impl<_Tp>(0)) == 1> {}; #endif // __has_feature(is_polymorphic) diff --git a/libcxx/test/utilities/meta/meta.unary/meta.unary.prop/is_polymorphic.pass.cpp b/libcxx/test/utilities/meta/meta.unary/meta.unary.prop/is_polymorphic.pass.cpp index 1f4798fbb47..62a59210074 100644 --- a/libcxx/test/utilities/meta/meta.unary/meta.unary.prop/is_polymorphic.pass.cpp +++ b/libcxx/test/utilities/meta/meta.unary/meta.unary.prop/is_polymorphic.pass.cpp @@ -52,6 +52,9 @@ class Abstract virtual ~Abstract() = 0; }; +class Final final { +}; + int main() { test_is_not_polymorphic<void>(); @@ -65,6 +68,9 @@ int main() test_is_not_polymorphic<Union>(); test_is_not_polymorphic<Empty>(); test_is_not_polymorphic<bit_zero>(); + test_is_not_polymorphic<Final>(); + test_is_not_polymorphic<NotEmpty&>(); + test_is_not_polymorphic<Abstract&>(); test_is_polymorphic<NotEmpty>(); test_is_polymorphic<Abstract>(); |