Thanks, Eric. On Wed, Jan 24, 2018 at 3:11 PM, Eric Fiselier <e...@efcs.ca> wrote:
> Sorry for the breakage. Fixed in r323389. > > On Wed, Jan 24, 2018 at 4:08 PM, Eric Fiselier <e...@efcs.ca> wrote: > >> Looking. >> >> On Wed, Jan 24, 2018 at 3:52 PM, Richard Trieu <rtr...@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@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@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@tuple:* 0+ {{binding reference member >>>> '__value_' to a temporary value}} >>>> - // expected-error@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@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@-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@lists.llvm.org >>>> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits >>>> >>> >>> >> >
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits