[libcxx] r276078 - Add tests for reference binding assertions in std::tuple.

Eric Fiselier via cfe-commits cfe-commits at lists.llvm.org
Tue Jul 19 19:57:41 PDT 2016


Author: ericwf
Date: Tue Jul 19 21:57:39 2016
New Revision: 276078

URL: http://llvm.org/viewvc/llvm-project?rev=276078&view=rev
Log:
Add tests for reference binding assertions in std::tuple.

Libc++ provides static assertions to detect reference binding issues inside
tuple. This patch adds tests for those diagnostics.

It should be noted that these static assertions technically violate the
standard since it allows these illegal bindings to occur.

Also see https://llvm.org/bugs/show_bug.cgi?id=20855

Added:
    libcxx/trunk/test/libcxx/utilities/tuple/tuple.tuple/
    libcxx/trunk/test/libcxx/utilities/tuple/tuple.tuple/diagnose_reference_binding.fail.cpp
    libcxx/trunk/test/libcxx/utilities/tuple/tuple.tuple/diagnose_reference_binding.pass.cpp
Modified:
    libcxx/trunk/include/tuple

Modified: libcxx/trunk/include/tuple
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/tuple?rev=276078&r1=276077&r2=276078&view=diff
==============================================================================
--- libcxx/trunk/include/tuple (original)
+++ libcxx/trunk/include/tuple Tue Jul 19 21:57:39 2016
@@ -192,6 +192,20 @@ class __tuple_leaf
 {
     _Hp value;
 
+    template <class _Tp>
+    static constexpr bool __can_bind_reference() {
+        using _RawTp = typename remove_reference<_Tp>::type;
+        using _RawHp = typename remove_reference<_Hp>::type;
+        using _CheckLValueArg = integral_constant<bool,
+            is_lvalue_reference<_Tp>::value
+        ||  is_same<_RawTp, reference_wrapper<_RawHp>>::value
+        ||  is_same<_RawTp, reference_wrapper<typename remove_const<_RawHp>::type>>::value
+        >;
+        return  !is_reference<_Hp>::value
+            || (is_lvalue_reference<_Hp>::value && _CheckLValueArg::value)
+            || (is_rvalue_reference<_Hp>::value && !is_lvalue_reference<_Tp>::value);
+    }
+
     __tuple_leaf& operator=(const __tuple_leaf&);
 public:
     _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR __tuple_leaf()
@@ -231,59 +245,29 @@ public:
         _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
         explicit __tuple_leaf(_Tp&& __t) _NOEXCEPT_((is_nothrow_constructible<_Hp, _Tp>::value))
             : value(_VSTD::forward<_Tp>(__t))
-        {static_assert(!is_reference<_Hp>::value ||
-                       (is_lvalue_reference<_Hp>::value &&
-                        (is_lvalue_reference<_Tp>::value ||
-                         is_same<typename remove_reference<_Tp>::type,
-                                 reference_wrapper<
-                                    typename remove_reference<_Hp>::type
-                                 >
-                                >::value)) ||
-                        (is_rvalue_reference<_Hp>::value &&
-                         !is_lvalue_reference<_Tp>::value),
+        {static_assert(__can_bind_reference<_Tp>(),
        "Attempted to construct a reference element in a tuple with an rvalue");}
 
     template <class _Tp, class _Alloc>
         _LIBCPP_INLINE_VISIBILITY
         explicit __tuple_leaf(integral_constant<int, 0>, const _Alloc&, _Tp&& __t)
             : value(_VSTD::forward<_Tp>(__t))
-        {static_assert(!is_lvalue_reference<_Hp>::value ||
-                       (is_lvalue_reference<_Hp>::value &&
-                        (is_lvalue_reference<_Tp>::value ||
-                         is_same<typename remove_reference<_Tp>::type,
-                                 reference_wrapper<
-                                    typename remove_reference<_Hp>::type
-                                 >
-                                >::value)),
+        {static_assert(__can_bind_reference<_Tp>(),
        "Attempted to construct a reference element in a tuple with an rvalue");}
 
     template <class _Tp, class _Alloc>
         _LIBCPP_INLINE_VISIBILITY
         explicit __tuple_leaf(integral_constant<int, 1>, const _Alloc& __a, _Tp&& __t)
             : value(allocator_arg_t(), __a, _VSTD::forward<_Tp>(__t))
-        {static_assert(!is_lvalue_reference<_Hp>::value ||
-                       (is_lvalue_reference<_Hp>::value &&
-                        (is_lvalue_reference<_Tp>::value ||
-                         is_same<typename remove_reference<_Tp>::type,
-                                 reference_wrapper<
-                                    typename remove_reference<_Hp>::type
-                                 >
-                                >::value)),
-       "Attempted to construct a reference element in a tuple with an rvalue");}
+        {static_assert(!is_reference<_Hp>::value,
+            "Attempted to uses-allocator construct a reference element in a tuple");}
 
     template <class _Tp, class _Alloc>
         _LIBCPP_INLINE_VISIBILITY
         explicit __tuple_leaf(integral_constant<int, 2>, const _Alloc& __a, _Tp&& __t)
             : value(_VSTD::forward<_Tp>(__t), __a)
-        {static_assert(!is_lvalue_reference<_Hp>::value ||
-                       (is_lvalue_reference<_Hp>::value &&
-                        (is_lvalue_reference<_Tp>::value ||
-                         is_same<typename remove_reference<_Tp>::type,
-                                 reference_wrapper<
-                                    typename remove_reference<_Hp>::type
-                                 >
-                                >::value)),
-       "Attempted to construct a reference element in a tuple with an rvalue");}
+        {static_assert(!is_reference<_Hp>::value,
+           "Attempted to uses-allocator construct a reference element in a tuple");}
 
     __tuple_leaf(const __tuple_leaf& __t) = default;
     __tuple_leaf(__tuple_leaf&& __t) = default;

Added: libcxx/trunk/test/libcxx/utilities/tuple/tuple.tuple/diagnose_reference_binding.fail.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/libcxx/utilities/tuple/tuple.tuple/diagnose_reference_binding.fail.cpp?rev=276078&view=auto
==============================================================================
--- libcxx/trunk/test/libcxx/utilities/tuple/tuple.tuple/diagnose_reference_binding.fail.cpp (added)
+++ libcxx/trunk/test/libcxx/utilities/tuple/tuple.tuple/diagnose_reference_binding.fail.cpp Tue Jul 19 21:57:39 2016
@@ -0,0 +1,33 @@
+//===----------------------------------------------------------------------===//
+//
+//                     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.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <tuple>
+
+// Test the diagnostics libc++ generates for invalid reference binding.
+// Libc++ attempts to diagnose the following cases:
+//  * Constructing an lvalue reference from an rvalue.
+//  * Constructing an rvalue reference from an lvalue.
+
+#include <tuple>
+#include <string>
+
+int main() {
+    std::allocator<void> alloc;
+
+    // expected-error at tuple:* 4 {{static_assert failed "Attempted to construct a reference element in a tuple with an rvalue"}}
+
+    // bind lvalue to rvalue
+    std::tuple<int const&> t(42); // expected-note {{requested here}}
+    std::tuple<int const&> t1(std::allocator_arg, alloc, 42); // expected-note {{requested here}}
+    // bind rvalue to constructed non-rvalue
+    std::tuple<std::string &&> t2("hello"); // expected-note {{requested here}}
+    std::tuple<std::string &&> t3(std::allocator_arg, alloc, "hello"); // expected-note {{requested here}}
+}

Added: libcxx/trunk/test/libcxx/utilities/tuple/tuple.tuple/diagnose_reference_binding.pass.cpp
URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/libcxx/utilities/tuple/tuple.tuple/diagnose_reference_binding.pass.cpp?rev=276078&view=auto
==============================================================================
--- libcxx/trunk/test/libcxx/utilities/tuple/tuple.tuple/diagnose_reference_binding.pass.cpp (added)
+++ libcxx/trunk/test/libcxx/utilities/tuple/tuple.tuple/diagnose_reference_binding.pass.cpp Tue Jul 19 21:57:39 2016
@@ -0,0 +1,71 @@
+//===----------------------------------------------------------------------===//
+//
+//                     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.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <tuple>
+
+// Test the diagnostics libc++ generates for invalid reference binding.
+// Libc++ attempts to diagnose the following cases:
+//  * Constructing an lvalue reference from an rvalue.
+//  * Constructing an rvalue reference from an lvalue.
+
+#include <tuple>
+#include <string>
+#include <functional>
+#include <cassert>
+
+static_assert(std::is_constructible<int&, std::reference_wrapper<int>>::value, "");
+static_assert(std::is_constructible<int const&, std::reference_wrapper<int>>::value, "");
+
+
+int main() {
+    std::allocator<void> alloc;
+    int x = 42;
+    {
+        std::tuple<int&> t(std::ref(x));
+        assert(&std::get<0>(t) == &x);
+        std::tuple<int&> t1(std::allocator_arg, alloc, std::ref(x));
+        assert(&std::get<0>(t1) == &x);
+    }
+    {
+        auto r = std::ref(x);
+        auto const& cr = r;
+        std::tuple<int&> t(r);
+        assert(&std::get<0>(t) == &x);
+        std::tuple<int&> t1(cr);
+        assert(&std::get<0>(t1) == &x);
+        std::tuple<int&> t2(std::allocator_arg, alloc, r);
+        assert(&std::get<0>(t2) == &x);
+        std::tuple<int&> t3(std::allocator_arg, alloc, cr);
+        assert(&std::get<0>(t3) == &x);
+    }
+    {
+        std::tuple<int const&> t(std::ref(x));
+        assert(&std::get<0>(t) == &x);
+        std::tuple<int const&> t2(std::cref(x));
+        assert(&std::get<0>(t2) == &x);
+        std::tuple<int const&> t3(std::allocator_arg, alloc, std::ref(x));
+        assert(&std::get<0>(t3) == &x);
+        std::tuple<int const&> t4(std::allocator_arg, alloc, std::cref(x));
+        assert(&std::get<0>(t4) == &x);
+    }
+    {
+        auto r = std::ref(x);
+        auto cr = std::cref(x);
+        std::tuple<int const&> t(r);
+        assert(&std::get<0>(t) == &x);
+        std::tuple<int const&> t2(cr);
+        assert(&std::get<0>(t2) == &x);
+        std::tuple<int const&> t3(std::allocator_arg, alloc, r);
+        assert(&std::get<0>(t3) == &x);
+        std::tuple<int const&> t4(std::allocator_arg, alloc, cr);
+        assert(&std::get<0>(t4) == &x);
+    }
+}
\ No newline at end of file




More information about the cfe-commits mailing list