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

Eric Fiselier via cfe-commits cfe-commits at lists.llvm.org
Wed Jan 24 15:11:51 PST 2018


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/bd731ab4/attachment-0001.html>


More information about the cfe-commits mailing list