[libcxx] r256325 - [libcxx] Fix LWG Issue #2367 - Fixing std::tuple and std::pair's default constructors.

Eric Fiselier via cfe-commits cfe-commits at lists.llvm.org
Wed Dec 23 00:20:27 PST 2015


Author: ericwf
Date: Wed Dec 23 02:20:26 2015
New Revision: 256325

URL: http://llvm.org/viewvc/llvm-project?rev=256325&view=rev
Log:
[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

Added:
    libcxx/trunk/test/std/utilities/utility/pairs/pairs.pair/default-sfinae.pass.cpp
Modified:
    libcxx/trunk/include/__config
    libcxx/trunk/include/utility
    libcxx/trunk/test/std/utilities/utility/pairs/pairs.pair/default.pass.cpp

Modified: libcxx/trunk/include/__config
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/__config?rev=256325&r1=256324&r2=256325&view=diff
==============================================================================
--- libcxx/trunk/include/__config (original)
+++ libcxx/trunk/include/__config Wed Dec 23 02:20:26 2015
@@ -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

Modified: libcxx/trunk/include/utility
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/utility?rev=256325&r1=256324&r2=256325&view=diff
==============================================================================
--- libcxx/trunk/include/utility (original)
+++ libcxx/trunk/include/utility Wed Dec 23 02:20:26 2015
@@ -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

Added: libcxx/trunk/test/std/utilities/utility/pairs/pairs.pair/default-sfinae.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/utilities/utility/pairs/pairs.pair/default-sfinae.pass.cpp?rev=256325&view=auto
==============================================================================
--- libcxx/trunk/test/std/utilities/utility/pairs/pairs.pair/default-sfinae.pass.cpp (added)
+++ libcxx/trunk/test/std/utilities/utility/pairs/pairs.pair/default-sfinae.pass.cpp Wed Dec 23 02:20:26 2015
@@ -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>>();
+    }
+}

Modified: libcxx/trunk/test/std/utilities/utility/pairs/pairs.pair/default.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/utilities/utility/pairs/pairs.pair/default.pass.cpp?rev=256325&r1=256324&r2=256325&view=diff
==============================================================================
--- libcxx/trunk/test/std/utilities/utility/pairs/pairs.pair/default.pass.cpp (original)
+++ libcxx/trunk/test/std/utilities/utility/pairs/pairs.pair/default.pass.cpp Wed Dec 23 02:20:26 2015
@@ -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
 }




More information about the cfe-commits mailing list