[libcxx] r323380 - [libc++] Fix PR20855 -- libc++ incorrectly diagnoses illegal reference binding in std::tuple.

Richard Trieu via cfe-commits cfe-commits at lists.llvm.org
Wed Jan 24 16:17:49 PST 2018


Thanks, Eric.

On Wed, Jan 24, 2018 at 3:11 PM, Eric Fiselier <eric at efcs.ca> wrote:

> Sorry for the breakage. Fixed in r323389.
>
> On Wed, Jan 24, 2018 at 4:08 PM, Eric Fiselier <eric at efcs.ca> wrote:
>
>> Looking.
>>
>> On Wed, Jan 24, 2018 at 3:52 PM, Richard Trieu <rtrieu at google.com> wrote:
>>
>>> Hi Eric,
>>>
>>> I am getting a build failure after this revision:
>>>
>>> llvm/projects/libcxx/include/tuple:175:27: error: no return statement
>>> in constexpr function
>>>     static constexpr bool __can_bind_reference() {
>>>                           ^
>>> 1 error generated.
>>>
>>> It looks like if the #if in __can_bind_reference is false, the function
>>> will be empty.  Can you take a look?
>>>
>>> Richard
>>>
>>> On Wed, Jan 24, 2018 at 2:14 PM, Eric Fiselier via cfe-commits <
>>> cfe-commits at lists.llvm.org> wrote:
>>>
>>>> Author: ericwf
>>>> Date: Wed Jan 24 14:14:01 2018
>>>> New Revision: 323380
>>>>
>>>> URL: http://llvm.org/viewvc/llvm-project?rev=323380&view=rev
>>>> Log:
>>>> [libc++] Fix PR20855 -- libc++ incorrectly diagnoses illegal reference
>>>> binding in std::tuple.
>>>>
>>>> Summary:
>>>> See https://bugs.llvm.org/show_bug.cgi?id=20855
>>>>
>>>> Libc++ goes out of it's way to diagnose `std::tuple` constructions
>>>> which are UB due to lifetime bugs caused by reference creation. For example:
>>>>
>>>> ```
>>>> // The 'const std::string&' is created *inside* the tuple constructor,
>>>> and its lifetime is over before the end of the constructor call.
>>>> std::tuple<int, const std::string&> t(std::make_tuple(42, "abc"));
>>>> ```
>>>>
>>>> However, we are over-aggressive and we incorrectly diagnose cases such
>>>> as:
>>>>
>>>> ```
>>>> void foo(std::tuple<int const&, int const&> const&);
>>>> foo(std::make_tuple(42, 42));
>>>> ```
>>>>
>>>> This patch fixes the incorrectly diagnosed cases, as well as converting
>>>> the diagnostic to use the newly added Clang trait
>>>> `__reference_binds_to_temporary`. The new trait allows us to diagnose
>>>> cases we previously couldn't such as:
>>>>
>>>> ```
>>>> std::tuple<int, const std::string&> t(42, "abc");
>>>> ```
>>>>
>>>> Reviewers: rsmith, mclow.lists
>>>>
>>>> Reviewed By: rsmith
>>>>
>>>> Subscribers: cfe-commits
>>>>
>>>> Differential Revision: https://reviews.llvm.org/D41977
>>>>
>>>> Added:
>>>>     libcxx/trunk/test/libcxx/utilities/tuple/tuple.tuple/tuple.c
>>>> nstr/PR20855_tuple_ref_binding_diagnostics.fail.cpp
>>>>     libcxx/trunk/test/std/utilities/tuple/tuple.tuple/tuple.cnst
>>>> r/PR20855_tuple_ref_binding_diagnostics.pass.cpp
>>>> Removed:
>>>>     libcxx/trunk/test/libcxx/utilities/tuple/tuple.tuple/diagnos
>>>> e_reference_binding.fail.cpp
>>>>     libcxx/trunk/test/libcxx/utilities/tuple/tuple.tuple/diagnos
>>>> e_reference_binding.pass.cpp
>>>> Modified:
>>>>     libcxx/trunk/include/tuple
>>>>
>>>> Modified: libcxx/trunk/include/tuple
>>>> URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/tup
>>>> le?rev=323380&r1=323379&r2=323380&view=diff
>>>> ============================================================
>>>> ==================
>>>> --- libcxx/trunk/include/tuple (original)
>>>> +++ libcxx/trunk/include/tuple Wed Jan 24 14:14:01 2018
>>>> @@ -173,16 +173,9 @@ class __tuple_leaf
>>>>
>>>>      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);
>>>> +#if __has_keyword(__reference_binds_to_temporary)
>>>> +      return !__reference_binds_to_temporary(_Hp, _Tp);
>>>> +#endif
>>>>      }
>>>>
>>>>      __tuple_leaf& operator=(const __tuple_leaf&);
>>>> @@ -224,15 +217,15 @@ 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(__can_bind_reference<_Tp>(),
>>>> -       "Attempted to construct a reference element in a tuple with an
>>>> rvalue");}
>>>> +        {static_assert(__can_bind_reference<_Tp&&>(),
>>>> +       "Attempted construction of reference element binds to a
>>>> temporary whose lifetime has ended");}
>>>>
>>>>      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(__can_bind_reference<_Tp>(),
>>>> -       "Attempted to construct a reference element in a tuple with an
>>>> rvalue");}
>>>> +        {static_assert(__can_bind_reference<_Tp&&>(),
>>>> +       "Attempted construction of reference element binds to a
>>>> temporary whose lifetime has ended");}
>>>>
>>>>      template <class _Tp, class _Alloc>
>>>>          _LIBCPP_INLINE_VISIBILITY
>>>>
>>>> Removed: libcxx/trunk/test/libcxx/utilities/tuple/tuple.tuple/diagnos
>>>> e_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=323379&view=auto
>>>> ============================================================
>>>> ==================
>>>> --- libcxx/trunk/test/libcxx/utilities/tuple/tuple.tuple/diagnose_reference_binding.fail.cpp
>>>> (original)
>>>> +++ libcxx/trunk/test/libcxx/utilities/tuple/tuple.tuple/diagnose_reference_binding.fail.cpp
>>>> (removed)
>>>> @@ -1,40 +0,0 @@
>>>> -//===------------------------------------------------------
>>>> ----------------===//
>>>> -//
>>>> -//                     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-re 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}}
>>>> -
>>>> -    // FIXME: The below warnings may get emitted as an error, a
>>>> warning, or not emitted at all
>>>> -    // depending on the flags used to compile this test.
>>>> -  {
>>>> -    // expected-warning at tuple:* 0+ {{binding reference member
>>>> '__value_' to a temporary value}}
>>>> -    // expected-error at tuple:* 0+ {{binding reference member
>>>> '__value_' to a temporary value}}
>>>> -  }
>>>> -}
>>>>
>>>> Removed: libcxx/trunk/test/libcxx/utilities/tuple/tuple.tuple/diagnos
>>>> e_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=323379&view=auto
>>>> ============================================================
>>>> ==================
>>>> --- libcxx/trunk/test/libcxx/utilities/tuple/tuple.tuple/diagnose_reference_binding.pass.cpp
>>>> (original)
>>>> +++ libcxx/trunk/test/libcxx/utilities/tuple/tuple.tuple/diagnose_reference_binding.pass.cpp
>>>> (removed)
>>>> @@ -1,71 +0,0 @@
>>>> -//===------------------------------------------------------
>>>> ----------------===//
>>>> -//
>>>> -//                     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);
>>>> -    }
>>>> -}
>>>>
>>>> Added: libcxx/trunk/test/libcxx/utilities/tuple/tuple.tuple/tuple.c
>>>> nstr/PR20855_tuple_ref_binding_diagnostics.fail.cpp
>>>> URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/libcxx
>>>> /utilities/tuple/tuple.tuple/tuple.cnstr/PR20855_tuple_ref_b
>>>> inding_diagnostics.fail.cpp?rev=323380&view=auto
>>>> ============================================================
>>>> ==================
>>>> --- libcxx/trunk/test/libcxx/utilities/tuple/tuple.tuple/tuple.c
>>>> nstr/PR20855_tuple_ref_binding_diagnostics.fail.cpp (added)
>>>> +++ libcxx/trunk/test/libcxx/utilities/tuple/tuple.tuple/tuple.c
>>>> nstr/PR20855_tuple_ref_binding_diagnostics.fail.cpp Wed Jan 24
>>>> 14:14:01 2018
>>>> @@ -0,0 +1,80 @@
>>>> +// -*- C++ -*-
>>>> +//===------------------------------------------------------
>>>> ----------------===//
>>>> +//
>>>> +//                     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>
>>>> +
>>>> +// See llvm.org/PR20855
>>>> +
>>>> +#ifdef __clang__
>>>> +#pragma clang diagnostic ignored "-Wdangling-field"
>>>> +#endif
>>>> +
>>>> +#include <tuple>
>>>> +#include <string>
>>>> +#include "test_macros.h"
>>>> +
>>>> +template <class Tp>
>>>> +struct ConvertsTo {
>>>> +  using RawTp = typename std::remove_cv< typename
>>>> std::remove_reference<Tp>::type>::type;
>>>> +
>>>> +  operator Tp() const {
>>>> +    return static_cast<Tp>(value);
>>>> +  }
>>>> +
>>>> +  mutable RawTp value;
>>>> +};
>>>> +
>>>> +struct Base {};
>>>> +struct Derived : Base {};
>>>> +
>>>> +template <class T> struct CannotDeduce {
>>>> + using type = T;
>>>> +};
>>>> +
>>>> +template <class ...Args>
>>>> +void F(typename CannotDeduce<std::tuple<Args...>>::type const&) {}
>>>> +
>>>> +
>>>> +int main() {
>>>> +#if TEST_HAS_BUILTIN_IDENTIFIER(__reference_binds_to_temporary)
>>>> +  // expected-error at tuple:* 8 {{"Attempted construction of reference
>>>> element binds to a temporary whose lifetime has ended"}}
>>>> +  {
>>>> +    F<int, const std::string&>(std::make_tuple(1, "abc")); //
>>>> expected-note 1 {{requested here}}
>>>> +  }
>>>> +  {
>>>> +    std::tuple<int, const std::string&> t(1, "a"); // expected-note 1
>>>> {{requested here}}
>>>> +  }
>>>> +  {
>>>> +    F<int, const std::string&>(std::tuple<int, const std::string&>(1,
>>>> "abc")); // expected-note 1 {{requested here}}
>>>> +  }
>>>> +  {
>>>> +    ConvertsTo<int&> ct;
>>>> +    std::tuple<const long&, int> t(ct, 42); // expected-note
>>>> {{requested here}}
>>>> +  }
>>>> +  {
>>>> +    ConvertsTo<int> ct;
>>>> +    std::tuple<int const&, void*> t(ct, nullptr); // expected-note
>>>> {{requested here}}
>>>> +  }
>>>> +  {
>>>> +    ConvertsTo<Derived> ct;
>>>> +    std::tuple<Base const&, int> t(ct, 42); // expected-note
>>>> {{requested here}}
>>>> +  }
>>>> +  {
>>>> +    std::allocator<void> alloc;
>>>> +    std::tuple<std::string &&> t2("hello"); // expected-note
>>>> {{requested here}}
>>>> +    std::tuple<std::string &&> t3(std::allocator_arg, alloc, "hello");
>>>> // expected-note {{requested here}}
>>>> +  }
>>>> +#else
>>>> +#error force failure
>>>> +// expected-error at -1 {{force failure}}
>>>> +#endif
>>>> +}
>>>>
>>>> Added: libcxx/trunk/test/std/utilities/tuple/tuple.tuple/tuple.cnst
>>>> r/PR20855_tuple_ref_binding_diagnostics.pass.cpp
>>>> URL: http://llvm.org/viewvc/llvm-project/libcxx/trunk/test/std/ut
>>>> ilities/tuple/tuple.tuple/tuple.cnstr/PR20855_tuple_ref_bind
>>>> ing_diagnostics.pass.cpp?rev=323380&view=auto
>>>> ============================================================
>>>> ==================
>>>> --- libcxx/trunk/test/std/utilities/tuple/tuple.tuple/tuple.cnst
>>>> r/PR20855_tuple_ref_binding_diagnostics.pass.cpp (added)
>>>> +++ libcxx/trunk/test/std/utilities/tuple/tuple.tuple/tuple.cnst
>>>> r/PR20855_tuple_ref_binding_diagnostics.pass.cpp Wed Jan 24 14:14:01
>>>> 2018
>>>> @@ -0,0 +1,136 @@
>>>> +// -*- C++ -*-
>>>> +//===------------------------------------------------------
>>>> ----------------===//
>>>> +//
>>>> +//                     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>
>>>> +
>>>> +// See llvm.org/PR20855
>>>> +
>>>> +#include <tuple>
>>>> +#include <string>
>>>> +#include "test_macros.h"
>>>> +
>>>> +#if TEST_HAS_BUILTIN_IDENTIFIER(__reference_binds_to_temporary)
>>>> +# define ASSERT_REFERENCE_BINDS_TEMPORARY(...)
>>>> static_assert(__reference_binds_to_temporary(__VA_ARGS__), "")
>>>> +# define ASSERT_NOT_REFERENCE_BINDS_TEMPORARY(...)
>>>> static_assert(!__reference_binds_to_temporary(__VA_ARGS__), "")
>>>> +#else
>>>> +# define ASSERT_REFERENCE_BINDS_TEMPORARY(...) static_assert(true, "")
>>>> +# define ASSERT_NOT_REFERENCE_BINDS_TEMPORARY(...)
>>>> static_assert(true, "")
>>>> +#endif
>>>> +
>>>> +template <class Tp>
>>>> +struct ConvertsTo {
>>>> +  using RawTp = typename std::remove_cv< typename
>>>> std::remove_reference<Tp>::type>::type;
>>>> +
>>>> +  operator Tp() const {
>>>> +    return static_cast<Tp>(value);
>>>> +  }
>>>> +
>>>> +  mutable RawTp value;
>>>> +};
>>>> +
>>>> +struct Base {};
>>>> +struct Derived : Base {};
>>>> +
>>>> +
>>>> +static_assert(std::is_same<decltype("abc"),
>>>> decltype(("abc"))>::value, "");
>>>> +ASSERT_REFERENCE_BINDS_TEMPORARY(std::string const&, decltype("abc"));
>>>> +ASSERT_REFERENCE_BINDS_TEMPORARY(std::string const&,
>>>> decltype(("abc")));
>>>> +ASSERT_REFERENCE_BINDS_TEMPORARY(std::string const&, const char*&&);
>>>> +
>>>> +ASSERT_NOT_REFERENCE_BINDS_TEMPORARY(int&, const ConvertsTo<int&>&);
>>>> +ASSERT_NOT_REFERENCE_BINDS_TEMPORARY(const int&, ConvertsTo<int&>&);
>>>> +ASSERT_NOT_REFERENCE_BINDS_TEMPORARY(Base&, Derived&);
>>>> +
>>>> +
>>>> +static_assert(std::is_constructible<int&,
>>>> std::reference_wrapper<int>>::value, "");
>>>> +static_assert(std::is_constructible<int const&,
>>>> std::reference_wrapper<int>>::value, "");
>>>> +
>>>> +template <class T> struct CannotDeduce {
>>>> + using type = T;
>>>> +};
>>>> +
>>>> +template <class ...Args>
>>>> +void F(typename CannotDeduce<std::tuple<Args...>>::type const&) {}
>>>> +
>>>> +void compile_tests() {
>>>> +  {
>>>> +    F<int, int const&>(std::make_tuple(42, 42));
>>>> +  }
>>>> +  {
>>>> +    F<int, int const&>(std::make_tuple<const int&, const int&>(42,
>>>> 42));
>>>> +    std::tuple<int, int const&> t(std::make_tuple<const int&, const
>>>> int&>(42, 42));
>>>> +  }
>>>> +  {
>>>> +    auto fn = &F<int, std::string const&>;
>>>> +    fn(std::tuple<int, std::string const&>(42, std::string("a")));
>>>> +    fn(std::make_tuple(42, std::string("a")));
>>>> +  }
>>>> +  {
>>>> +    Derived d;
>>>> +    std::tuple<Base&, Base const&> t(d, d);
>>>> +  }
>>>> +  {
>>>> +    ConvertsTo<int&> ct;
>>>> +    std::tuple<int, int&> t(42, ct);
>>>> +  }
>>>> +}
>>>> +
>>>> +void allocator_tests() {
>>>> +    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);
>>>> +    }
>>>> +}
>>>> +
>>>> +
>>>> +int main() {
>>>> +  compile_tests();
>>>> +  allocator_tests();
>>>> +}
>>>>
>>>>
>>>> _______________________________________________
>>>> cfe-commits mailing list
>>>> cfe-commits at lists.llvm.org
>>>> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
>>>>
>>>
>>>
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20180124/22daf857/attachment-0001.html>


More information about the cfe-commits mailing list