From 461c06aa3be15f57c292c3aeb07cd5f57b39277d Mon Sep 17 00:00:00 2001 From: Mogball Date: Wed, 3 Nov 2021 17:59:02 +0000 Subject: [PATCH] [llvm][adt] make_first_range returning reference to temporary Reviewed By: rriddle Differential Revision: https://reviews.llvm.org/D112957 --- llvm/include/llvm/ADT/STLExtras.h | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/llvm/include/llvm/ADT/STLExtras.h b/llvm/include/llvm/ADT/STLExtras.h index 68bc656..daa6d25 100644 --- a/llvm/include/llvm/ADT/STLExtras.h +++ b/llvm/include/llvm/ADT/STLExtras.h @@ -1251,20 +1251,39 @@ public: } }; +namespace detail { +/// Return a reference to the first or second member of a reference. Otherwise, +/// return a copy of the member of a temporary. +/// +/// When passing a range whose iterators return values instead of references, +/// the reference must be dropped from `decltype((elt.first))`, which will +/// always be a reference, to avoid returning a reference to a temporary. +template class first_or_second_type { +public: + using type = + typename std::conditional_t::value, FirstTy, + std::remove_reference_t>; +}; +} // end namespace detail + /// Given a container of pairs, return a range over the first elements. template auto make_first_range(ContainerTy &&c) { - return llvm::map_range( - std::forward(c), - [](decltype((*std::begin(c))) elt) -> decltype((elt.first)) { - return elt.first; - }); + using EltTy = decltype((*std::begin(c))); + return llvm::map_range(std::forward(c), + [](EltTy elt) -> typename detail::first_or_second_type< + EltTy, decltype((elt.first))>::type { + return elt.first; + }); } /// Given a container of pairs, return a range over the second elements. template auto make_second_range(ContainerTy &&c) { + using EltTy = decltype((*std::begin(c))); return llvm::map_range( std::forward(c), - [](decltype((*std::begin(c))) elt) -> decltype((elt.second)) { + [](EltTy elt) -> + typename detail::first_or_second_type::type { return elt.second; }); } -- 2.7.4