summaryrefslogtreecommitdiffstats
path: root/libcxx/test
diff options
context:
space:
mode:
authorEric Fiselier <eric@efcs.ca>2016-11-02 03:57:34 +0000
committerEric Fiselier <eric@efcs.ca>2016-11-02 03:57:34 +0000
commit0b460e6bf8e0c418558401acc4832538ed8b662b (patch)
tree410814dca6b97572b4a309bdab1883b86e3ec439 /libcxx/test
parent76a3ace1f0897906f59166b341008cf386b9e1f9 (diff)
downloadbcm5719-llvm-0b460e6bf8e0c418558401acc4832538ed8b662b.tar.gz
bcm5719-llvm-0b460e6bf8e0c418558401acc4832538ed8b662b.zip
Fix __libcpp_is_constructible for source types with explicit conversion operators.
Previously __libcpp_is_constructible checked the validity of reference construction using 'eat<To>(declval<From>())' but this doesn't consider From's explicit conversion operators. This patch teaches __libcpp_is_constructible how to handle these cases. To do this we need to check the validity using 'static_cast<To>(declval<From>())'. Unfortunately static_cast allows additional base-to-derived and lvalue-to-rvalue conversions, which have to be checked for and manually rejected. While implementing these changes I discovered that Clang incorrectly rejects `static_cast<int&&>(declval<float&>())` even though `int &&X(declval<float&>())` is well formed. In order to tolerate this bug the `__eat<T>(...)` needs to be left in-place. Otherwise it could be replaced entirely with the new static_cast implementation. Thanks to Walter Brown for providing the test cases. llvm-svn: 285786
Diffstat (limited to 'libcxx/test')
-rw-r--r--libcxx/test/std/utilities/meta/meta.unary/meta.unary.prop/is_constructible.pass.cpp120
1 files changed, 118 insertions, 2 deletions
diff --git a/libcxx/test/std/utilities/meta/meta.unary/meta.unary.prop/is_constructible.pass.cpp b/libcxx/test/std/utilities/meta/meta.unary/meta.unary.prop/is_constructible.pass.cpp
index 7f5ab7214fd..eb942a52a5b 100644
--- a/libcxx/test/std/utilities/meta/meta.unary/meta.unary.prop/is_constructible.pass.cpp
+++ b/libcxx/test/std/utilities/meta/meta.unary/meta.unary.prop/is_constructible.pass.cpp
@@ -14,9 +14,17 @@
// template <class T, class... Args>
// struct is_constructible;
+#define _LIBCPP_TESTING_FALLBACK_IS_CONSTRUCTIBLE
#include <type_traits>
#include "test_macros.h"
+#if TEST_STD_VER >= 11 && defined(_LIBCPP_VERSION)
+#define LIBCPP11_STATIC_ASSERT(...) static_assert(__VA_ARGS__)
+#else
+#define LIBCPP11_STATIC_ASSERT(...) ((void)0)
+#endif
+
+
struct A
{
explicit A(int);
@@ -51,14 +59,27 @@ struct S {
#if TEST_STD_VER >= 11
explicit
#endif
- operator T () const { return T(); }
+ operator T () const;
+};
+
+template <class To>
+struct ImplicitTo {
+ operator To();
+};
+
+#if TEST_STD_VER >= 11
+template <class To>
+struct ExplicitTo {
+ explicit operator To ();
};
+#endif
template <class T>
void test_is_constructible()
{
static_assert( (std::is_constructible<T>::value), "");
+ LIBCPP11_STATIC_ASSERT((std::__libcpp_is_constructible<T>::type::value), "");
#if TEST_STD_VER > 14
static_assert( std::is_constructible_v<T>, "");
#endif
@@ -68,6 +89,7 @@ template <class T, class A0>
void test_is_constructible()
{
static_assert(( std::is_constructible<T, A0>::value), "");
+ LIBCPP11_STATIC_ASSERT((std::__libcpp_is_constructible<T, A0>::type::value), "");
#if TEST_STD_VER > 14
static_assert(( std::is_constructible_v<T, A0>), "");
#endif
@@ -77,6 +99,7 @@ template <class T, class A0, class A1>
void test_is_constructible()
{
static_assert(( std::is_constructible<T, A0, A1>::value), "");
+ LIBCPP11_STATIC_ASSERT((std::__libcpp_is_constructible<T, A0, A1>::type::value), "");
#if TEST_STD_VER > 14
static_assert(( std::is_constructible_v<T, A0, A1>), "");
#endif
@@ -86,6 +109,7 @@ template <class T>
void test_is_not_constructible()
{
static_assert((!std::is_constructible<T>::value), "");
+ LIBCPP11_STATIC_ASSERT((!std::__libcpp_is_constructible<T>::type::value), "");
#if TEST_STD_VER > 14
static_assert((!std::is_constructible_v<T>), "");
#endif
@@ -95,13 +119,28 @@ template <class T, class A0>
void test_is_not_constructible()
{
static_assert((!std::is_constructible<T, A0>::value), "");
+ LIBCPP11_STATIC_ASSERT((!std::__libcpp_is_constructible<T, A0>::type::value), "");
#if TEST_STD_VER > 14
static_assert((!std::is_constructible_v<T, A0>), "");
#endif
}
+#if TEST_STD_VER >= 11
+template <class T = int, class = decltype(static_cast<T&&>(std::declval<double&>()))>
+constexpr bool clang_disallows_valid_static_cast_test(int) { return false; };
+
+constexpr bool clang_disallows_valid_static_cast_test(long) { return true; }
+
+static constexpr bool clang_disallows_valid_static_cast_bug =
+ clang_disallows_valid_static_cast_test(0);
+#endif
+
+
int main()
{
+ typedef Base B;
+ typedef Derived D;
+
test_is_constructible<int> ();
test_is_constructible<int, const int> ();
test_is_constructible<A, int> ();
@@ -115,6 +154,14 @@ int main()
test_is_constructible<A, char> ();
#endif
test_is_not_constructible<A, void> ();
+ test_is_not_constructible<int, void()>();
+ test_is_not_constructible<int, void(&)()>();
+ test_is_not_constructible<int, void() const>();
+ test_is_not_constructible<int&, void>();
+ test_is_not_constructible<int&, void()>();
+ test_is_not_constructible<int&, void() const>();
+ test_is_not_constructible<int&, void(&)()>();
+
test_is_not_constructible<void> ();
test_is_not_constructible<const void> (); // LWG 2738
test_is_not_constructible<volatile void> ();
@@ -125,10 +172,21 @@ int main()
test_is_constructible<int, S>();
test_is_not_constructible<int&, S>();
+ test_is_constructible<void(&)(), void(&)()>();
+ test_is_constructible<void(&)(), void()>();
+#if TEST_STD_VER >= 11
+ test_is_constructible<void(&&)(), void(&&)()>();
+ test_is_constructible<void(&&)(), void()>();
+ test_is_constructible<void(&&)(), void(&)()>();
+#endif
+
#if TEST_STD_VER >= 11
test_is_constructible<int const&, int>();
test_is_constructible<int const&, int&&>();
+ test_is_constructible<int&&, double&>();
+ test_is_constructible<void(&)(), void(&&)()>();
+
test_is_not_constructible<int&, int>();
test_is_not_constructible<int&, int const&>();
test_is_not_constructible<int&, int&&>();
@@ -157,6 +215,64 @@ int main()
test_is_not_constructible<void() const, void() const>();
test_is_not_constructible<void() const, void*>();
+ test_is_constructible<int&, ImplicitTo<int&>>();
+ test_is_constructible<const int&, ImplicitTo<int&&>>();
+ test_is_constructible<int&&, ImplicitTo<int&&>>();
+ test_is_constructible<const int&, ImplicitTo<int>>();
+
+ test_is_not_constructible<B&&, B&>();
+ test_is_not_constructible<B&&, D&>();
+ test_is_constructible<B&&, ImplicitTo<D&&>>();
+ test_is_constructible<B&&, ImplicitTo<D&&>&>();
+ test_is_constructible<int&&, double&>();
+ test_is_constructible<const int&, ImplicitTo<int&>&>();
+ test_is_constructible<const int&, ImplicitTo<int&>>();
+ test_is_constructible<const int&, ExplicitTo<int&>&>();
+ test_is_constructible<const int&, ExplicitTo<int&>>();
+
+ test_is_constructible<const int&, ExplicitTo<int&>&>();
+ test_is_constructible<const int&, ExplicitTo<int&>>();
+ test_is_constructible<int&, ExplicitTo<int&>>();
+ test_is_constructible<const int&, ExplicitTo<int&&>>();
+
+ // Binding through reference-compatible type is required to perform
+ // direct-initialization as described in [over.match.ref] p. 1 b. 1:
+ test_is_constructible<int&, ExplicitTo<int&>>();
+ test_is_constructible<const int&, ExplicitTo<int&&>>();
+
+ static_assert(std::is_constructible<int&&, ExplicitTo<int&&>>::value, "");
+#ifdef __clang__
+#if defined(CLANG_TEST_VER) && CLANG_TEST_VER < 400
+ static_assert(clang_disallows_valid_static_cast_bug, "bug still exists");
+#endif
+ // FIXME Clang disallows this construction because it thinks that
+ // 'static_cast<int&&>(declval<ExplicitTo<int&&>>())' is ill-formed.
+ LIBCPP_STATIC_ASSERT(
+ clang_disallows_valid_static_cast_bug !=
+ std::__libcpp_is_constructible<int&&, ExplicitTo<int&&>>::value, "");
+#else
+ static_assert(clang_disallows_valid_static_cast_bug == false, "");
+ LIBCPP_STATIC_ASSERT(std::__libcpp_is_constructible<int&&, ExplicitTo<int&&>>::value, "");
+#endif
+
+#ifdef __clang__
+ // FIXME Clang and GCC disagree on the validity of this expression.
+ test_is_constructible<const int&, ExplicitTo<int>>();
+ static_assert(std::is_constructible<int&&, ExplicitTo<int>>::value, "");
+ LIBCPP_STATIC_ASSERT(
+ clang_disallows_valid_static_cast_bug !=
+ std::__libcpp_is_constructible<int&&, ExplicitTo<int>>::value, "");
+#else
+ test_is_not_constructible<const int&, ExplicitTo<int>>();
+ test_is_not_constructible<int&&, ExplicitTo<int>>();
+#endif
+
+ // Binding through temporary behaves like copy-initialization,
+ // see [dcl.init.ref] p. 5, very last sub-bullet:
+ test_is_not_constructible<const int&, ExplicitTo<double&&>>();
+ test_is_not_constructible<int&&, ExplicitTo<double&&>>();
+
+
// TODO: Remove this workaround once Clang <= 3.7 are no longer used regularly.
// In those compiler versions the __is_constructible builtin gives the wrong
// results for abominable function types.
@@ -171,5 +287,5 @@ int main()
test_is_not_constructible<void() &> ();
test_is_not_constructible<void() &&> ();
#endif
-#endif
+#endif // TEST_STD_VER >= 11
}
OpenPOWER on IntegriCloud