diff options
| author | Eric Fiselier <eric@efcs.ca> | 2015-12-23 08:20:26 +0000 |
|---|---|---|
| committer | Eric Fiselier <eric@efcs.ca> | 2015-12-23 08:20:26 +0000 |
| commit | 7a608aa232c18cefebde9eb5035ccdcc17f58c9d (patch) | |
| tree | e84e6f1dbf60ec7f5f0de26bc7835bc82d0f7899 /libcxx | |
| parent | 7b46b4e7984ebe45e56fe4a54633c0a2cff260fe (diff) | |
| download | bcm5719-llvm-7a608aa232c18cefebde9eb5035ccdcc17f58c9d.tar.gz bcm5719-llvm-7a608aa232c18cefebde9eb5035ccdcc17f58c9d.zip | |
[libcxx] Fix LWG Issue #2367 - Fixing std::tuple and std::pair's default constructors.
Summary: This patch implements the solution for LWG Issue #2367. See http://cplusplus.github.io/LWG/lwg-active.html#2367
Reviewers: mclow.lists, EricWF
Subscribers: cfe-commits
Differential Revision: http://reviews.llvm.org/D13750
llvm-svn: 256325
Diffstat (limited to 'libcxx')
| -rw-r--r-- | libcxx/include/__config | 11 | ||||
| -rw-r--r-- | libcxx/include/utility | 6 | ||||
| -rw-r--r-- | libcxx/test/std/utilities/utility/pairs/pairs.pair/default-sfinae.pass.cpp | 164 | ||||
| -rw-r--r-- | libcxx/test/std/utilities/utility/pairs/pairs.pair/default.pass.cpp | 17 |
4 files changed, 189 insertions, 9 deletions
diff --git a/libcxx/include/__config b/libcxx/include/__config index fa0c40e92af..f141f4f1b7f 100644 --- a/libcxx/include/__config +++ b/libcxx/include/__config @@ -305,6 +305,10 @@ typedef __char32_t char32_t; #define _LIBCPP_UNUSED __attribute__((__unused__)) +#if !(__has_feature(cxx_default_function_template_args)) +#define _LIBCPP_HAS_NO_DEFAULT_FUNCTION_TEMPLATE_ARGS +#endif + #if !(__has_feature(cxx_defaulted_functions)) #define _LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS #endif // !(__has_feature(cxx_defaulted_functions)) @@ -474,6 +478,7 @@ namespace std { #define _LIBCPP_HAS_NO_ADVANCED_SFINAE #define _LIBCPP_HAS_NO_DECLTYPE +#define _LIBCPP_HAS_NO_DEFAULT_FUNCTION_TEMPLATE_ARGS #define _LIBCPP_HAS_NO_DEFAULTED_FUNCTIONS #define _LIBCPP_HAS_NO_DELETED_FUNCTIONS #define _LIBCPP_HAS_NO_NULLPTR @@ -487,13 +492,12 @@ namespace std { #else // __GXX_EXPERIMENTAL_CXX0X__ #if _GNUC_VER < 403 +#define _LIBCPP_HAS_NO_DEFAULT_FUNCTION_TEMPLATE_ARGS #define _LIBCPP_HAS_NO_RVALUE_REFERENCES -#endif - -#if _GNUC_VER < 403 #define _LIBCPP_HAS_NO_STATIC_ASSERT #endif + #if _GNUC_VER < 404 #define _LIBCPP_HAS_NO_DECLTYPE #define _LIBCPP_HAS_NO_DELETED_FUNCTIONS @@ -565,6 +569,7 @@ namespace std { #define _LIBCPP_NORETURN __attribute__((noreturn)) #define _LIBCPP_UNUSED +#define _LIBCPP_HAS_NO_DEFAULT_FUNCTION_TEMPLATE_ARGS #define _LIBCPP_HAS_NO_TEMPLATE_ALIASES #define _LIBCPP_HAS_NO_ADVANCED_SFINAE #define _LIBCPP_HAS_NO_GENERALIZED_INITIALIZERS diff --git a/libcxx/include/utility b/libcxx/include/utility index 4d0191c491f..c9f5785b3d4 100644 --- a/libcxx/include/utility +++ b/libcxx/include/utility @@ -288,6 +288,12 @@ struct _LIBCPP_TYPE_VIS_ONLY pair // pair(const pair&) = default; // pair(pair&&) = default; +#ifndef _LIBCPP_HAS_NO_DEFAULT_FUNCTION_TEMPLATE_ARGS + template <bool _Dummy = true, class = typename enable_if< + __dependent_type<is_default_constructible<_T1>, _Dummy>::value && + __dependent_type<is_default_constructible<_T2>, _Dummy>::value + >::type> +#endif _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR pair() : first(), second() {} _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11 diff --git a/libcxx/test/std/utilities/utility/pairs/pairs.pair/default-sfinae.pass.cpp b/libcxx/test/std/utilities/utility/pairs/pairs.pair/default-sfinae.pass.cpp new file mode 100644 index 00000000000..8f9fc669251 --- /dev/null +++ b/libcxx/test/std/utilities/utility/pairs/pairs.pair/default-sfinae.pass.cpp @@ -0,0 +1,164 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// <utility> + +// template <class T1, class T2> struct pair + +// Test the SFINAE required by LWG Issue #2367. +// is_default_constructible<pair> + +// UNSUPPORTED: c++98, c++03 + +#include <utility> +#include <type_traits> +#include <cassert> + +#include "test_macros.h" + +#if TEST_STD_VER > 11 +#define CONSTEXPR_CXX14 constexpr +#define STATIC_ASSERT_CXX14(Pred) static_assert(Pred, "") +#else +#define CONSTEXPR_CXX14 +#define STATIC_ASSERT_CXX14(Pred) assert(Pred) +#endif + +struct DeletedDefault { + // A class with a deleted default constructor. Used to test the SFINAE + // on std::pairs default constructor. + constexpr explicit DeletedDefault(int x) : value(x) {} + constexpr DeletedDefault() = delete; + int value; +}; + +template <class Tp, bool> +struct DependantType: public Tp {}; + +template <class T, bool Val> +using DependantIsDefault = DependantType<std::is_default_constructible<T>, Val>; + +template <class T> +struct DefaultSFINAES { + template <bool Dummy = false, class = typename std::enable_if< + DependantIsDefault<T, Dummy>::value + >::type + > + constexpr DefaultSFINAES() : value() {} + constexpr explicit DefaultSFINAES(T const& x) : value(x) {} + T value; +}; + +struct NoDefault { + constexpr NoDefault(int v) : value(v) {} + int value; +}; + +template <class Tp> +void test_not_is_default_constructible() +{ + { + typedef std::pair<int, Tp> P; + static_assert(!std::is_default_constructible<P>::value, ""); + static_assert(std::is_constructible<P, int, Tp>::value, ""); + } + { + typedef std::pair<Tp, int> P; + static_assert(!std::is_default_constructible<P>::value, ""); + static_assert(std::is_constructible<P, Tp, int>::value, ""); + } + { + typedef std::pair<Tp, Tp> P; + static_assert(!std::is_default_constructible<P>::value, ""); + static_assert(std::is_constructible<P, Tp, Tp>::value, ""); + } +} + +template <class Tp> +void test_is_default_constructible() +{ + { + typedef std::pair<int, Tp> P; + static_assert(std::is_default_constructible<P>::value, ""); + } + { + typedef std::pair<Tp, int> P; + static_assert(std::is_default_constructible<P>::value, ""); + } + { + typedef std::pair<Tp, Tp> P; + static_assert(std::is_default_constructible<P>::value, ""); + } +} + +template <class T> +struct IllFormedDefaultImp { + constexpr explicit IllFormedDefaultImp(int v) : value(v) {} + constexpr IllFormedDefaultImp() : value(T::DoesNotExistAndShouldNotCompile) {} + int value; +}; + +typedef IllFormedDefaultImp<int> IllFormedDefault; + // A class which provides a constexpr default constructor with a valid + // signature but an ill-formed body. The A compile error will be emitted if + // the default constructor is instantiated. + + +// Check that the SFINAE on the default constructor is not evaluated when +// it isn't needed. If the default constructor of 'IllFormedDefault' is evaluated +// in C++11, even with is_default_constructible, then this test should fail to +// compile. In C++14 and greater evaluate each test is evaluated as a constant +// expression. +// See LWG issue #2367 +void test_illformed_default() +{ + { + typedef std::pair<IllFormedDefault, int> P; + static_assert((std::is_constructible<P, IllFormedDefault, int>::value), ""); + CONSTEXPR_CXX14 P p(IllFormedDefault(42), -5); + STATIC_ASSERT_CXX14(p.first.value == 42 && p.second == -5); + } + { + typedef std::pair<int, IllFormedDefault> P; + static_assert((std::is_constructible<P, int, IllFormedDefault>::value), ""); + CONSTEXPR_CXX14 IllFormedDefault dd(-5); + CONSTEXPR_CXX14 P p(42, dd); + STATIC_ASSERT_CXX14(p.first == 42 && p.second.value == -5); + } + { + typedef std::pair<IllFormedDefault, IllFormedDefault> P; + static_assert((std::is_constructible<P, IllFormedDefault, IllFormedDefault>::value), ""); + CONSTEXPR_CXX14 P p(IllFormedDefault(42), IllFormedDefault(-5)); + STATIC_ASSERT_CXX14(p.first.value == 42 && p.second.value == -5); + } +} + + +int main() +{ + { + // Check that pair<T, U> can still be used even if + // is_default_constructible<T> or is_default_constructible<U> cause + // a compilation error. + test_illformed_default(); + } + { + // pair::pair() is only disable in C++11 and beyond. + test_not_is_default_constructible<NoDefault>(); + test_not_is_default_constructible<DeletedDefault>(); + test_not_is_default_constructible<DefaultSFINAES<int&>>(); + test_not_is_default_constructible<DefaultSFINAES<int&&>>(); + test_not_is_default_constructible<int&>(); + test_not_is_default_constructible<int&&>(); + } + { + test_is_default_constructible<int>(); + test_is_default_constructible<DefaultSFINAES<int>>(); + } +} diff --git a/libcxx/test/std/utilities/utility/pairs/pairs.pair/default.pass.cpp b/libcxx/test/std/utilities/utility/pairs/pairs.pair/default.pass.cpp index bb6661f7966..d83328b8f2d 100644 --- a/libcxx/test/std/utilities/utility/pairs/pairs.pair/default.pass.cpp +++ b/libcxx/test/std/utilities/utility/pairs/pairs.pair/default.pass.cpp @@ -13,9 +13,15 @@ // constexpr pair(); +// NOTE: The SFINAE on the default constructor is tested in +// default-sfinae.pass.cpp + #include <utility> +#include <type_traits> #include <cassert> +#include "test_macros.h" + int main() { { @@ -24,13 +30,12 @@ int main() assert(p.first == 0.0f); assert(p.second == nullptr); } - -#if _LIBCPP_STD_VER > 11 +#if TEST_STD_VER >= 11 { - typedef std::pair<float, short*> P; - constexpr P p; - static_assert(p.first == 0.0f, ""); - static_assert(p.second == nullptr, ""); + typedef std::pair<float, short*> P; + constexpr P p; + static_assert(p.first == 0.0f, ""); + static_assert(p.second == nullptr, ""); } #endif } |

