Commit fb45968e authored by Justin Lebar's avatar Justin Lebar
Browse files

Use C++14-style return type deduction in LLVM.

Summary:
Simplifies the C++11-style "-> decltype(...)" return-type deduction.

Note that you have to be careful about whether the function return type
is `auto` or `decltype(auto)`.  The difference is that bare `auto`
strips const and reference, just like lambda return type deduction.  In
some cases that's what we want (or more likely, we know that the return
type is a value type), but whenever we're wrapping a templated function
which might return a reference, we need to be sure that the return type
is decltype(auto).

No functional change.

Subscribers: dexonsmith, llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D74383
parent dd11c8fb
Loading
Loading
Loading
Loading
+34 −63
Original line number Diff line number Diff line
@@ -146,16 +146,14 @@ namespace adl_detail {
using std::begin;

template <typename ContainerTy>
auto adl_begin(ContainerTy &&container)
    -> decltype(begin(std::forward<ContainerTy>(container))) {
decltype(auto) adl_begin(ContainerTy &&container) {
  return begin(std::forward<ContainerTy>(container));
}

using std::end;

template <typename ContainerTy>
auto adl_end(ContainerTy &&container)
    -> decltype(end(std::forward<ContainerTy>(container))) {
decltype(auto) adl_end(ContainerTy &&container) {
  return end(std::forward<ContainerTy>(container));
}

@@ -170,14 +168,12 @@ void adl_swap(T &&lhs, T &&rhs) noexcept(noexcept(swap(std::declval<T>(),
} // end namespace adl_detail

template <typename ContainerTy>
auto adl_begin(ContainerTy &&container)
    -> decltype(adl_detail::adl_begin(std::forward<ContainerTy>(container))) {
decltype(auto) adl_begin(ContainerTy &&container) {
  return adl_detail::adl_begin(std::forward<ContainerTy>(container));
}

template <typename ContainerTy>
auto adl_end(ContainerTy &&container)
    -> decltype(adl_detail::adl_end(std::forward<ContainerTy>(container))) {
decltype(auto) adl_end(ContainerTy &&container) {
  return adl_detail::adl_end(std::forward<ContainerTy>(container));
}

@@ -195,9 +191,7 @@ constexpr bool empty(const T &RangeOrContainer) {

/// Return a range covering \p RangeOrContainer with the first N elements
/// excluded.
template <typename T>
auto drop_begin(T &&RangeOrContainer, size_t N) ->
    iterator_range<decltype(adl_begin(RangeOrContainer))> {
template <typename T> auto drop_begin(T &&RangeOrContainer, size_t N) {
  return make_range(std::next(adl_begin(RangeOrContainer), N),
                    adl_end(RangeOrContainer));
}
@@ -233,9 +227,7 @@ inline mapped_iterator<ItTy, FuncTy> map_iterator(ItTy I, FuncTy F) {
}

template <class ContainerTy, class FuncTy>
auto map_range(ContainerTy &&C, FuncTy F)
    -> decltype(make_range(map_iterator(C.begin(), F),
                           map_iterator(C.end(), F))) {
auto map_range(ContainerTy &&C, FuncTy F) {
  return make_range(map_iterator(C.begin(), F), map_iterator(C.end(), F));
}

@@ -262,9 +254,9 @@ struct has_rbegin : has_rbegin_impl<typename std::remove_reference<Ty>::type> {
// Returns an iterator_range over the given container which iterates in reverse.
// Note that the container must have rbegin()/rend() methods for this to work.
template <typename ContainerTy>
auto reverse(ContainerTy &&C,
             typename std::enable_if<has_rbegin<ContainerTy>::value>::type * =
                 nullptr) -> decltype(make_range(C.rbegin(), C.rend())) {
auto reverse(
    ContainerTy &&C,
    typename std::enable_if<has_rbegin<ContainerTy>::value>::type * = nullptr) {
  return make_range(C.rbegin(), C.rend());
}

@@ -278,11 +270,9 @@ std::reverse_iterator<IteratorTy> make_reverse_iterator(IteratorTy It) {
// Note that the container must have begin()/end() methods which return
// bidirectional iterators for this to work.
template <typename ContainerTy>
auto reverse(
    ContainerTy &&C,
    typename std::enable_if<!has_rbegin<ContainerTy>::value>::type * = nullptr)
    -> decltype(make_range(llvm::make_reverse_iterator(std::end(C)),
                           llvm::make_reverse_iterator(std::begin(C)))) {
auto reverse(ContainerTy &&C,
             typename std::enable_if<!has_rbegin<ContainerTy>::value>::type * =
                 nullptr) {
  return make_range(llvm::make_reverse_iterator(std::end(C)),
                    llvm::make_reverse_iterator(std::begin(C)));
}
@@ -680,9 +670,8 @@ static Iter next_or_end(const Iter &I, const Iter &End) {
}

template <typename Iter>
static auto deref_or_none(const Iter &I, const Iter &End)
    -> llvm::Optional<typename std::remove_const<
        typename std::remove_reference<decltype(*I)>::type>::type> {
static auto deref_or_none(const Iter &I, const Iter &End) -> llvm::Optional<
    std::remove_const_t<std::remove_reference_t<decltype(*I)>>> {
  if (I == End)
    return None;
  return *I;
@@ -983,8 +972,7 @@ struct on_first {
  FuncTy func;

  template <typename T>
  auto operator()(const T &lhs, const T &rhs) const
      -> decltype(func(lhs.first, rhs.first)) {
  decltype(auto) operator()(const T &lhs, const T &rhs) const {
    return func(lhs.first, rhs.first);
  }
};
@@ -1164,8 +1152,7 @@ auto size(R &&Range, typename std::enable_if<
                         std::is_same<typename std::iterator_traits<decltype(
                                          Range.begin())>::iterator_category,
                                      std::random_access_iterator_tag>::value,
                         void>::type * = nullptr)
    -> decltype(std::distance(Range.begin(), Range.end())) {
                         void>::type * = nullptr) {
  return std::distance(Range.begin(), Range.end());
}

@@ -1199,27 +1186,26 @@ bool none_of(R &&Range, UnaryPredicate P) {

/// Provide wrappers to std::find which take ranges instead of having to pass
/// begin/end explicitly.
template <typename R, typename T>
auto find(R &&Range, const T &Val) -> decltype(adl_begin(Range)) {
template <typename R, typename T> auto find(R &&Range, const T &Val) {
  return std::find(adl_begin(Range), adl_end(Range), Val);
}

/// Provide wrappers to std::find_if which take ranges instead of having to pass
/// begin/end explicitly.
template <typename R, typename UnaryPredicate>
auto find_if(R &&Range, UnaryPredicate P) -> decltype(adl_begin(Range)) {
auto find_if(R &&Range, UnaryPredicate P) {
  return std::find_if(adl_begin(Range), adl_end(Range), P);
}

template <typename R, typename UnaryPredicate>
auto find_if_not(R &&Range, UnaryPredicate P) -> decltype(adl_begin(Range)) {
auto find_if_not(R &&Range, UnaryPredicate P) {
  return std::find_if_not(adl_begin(Range), adl_end(Range), P);
}

/// Provide wrappers to std::remove_if which take ranges instead of having to
/// pass begin/end explicitly.
template <typename R, typename UnaryPredicate>
auto remove_if(R &&Range, UnaryPredicate P) -> decltype(adl_begin(Range)) {
auto remove_if(R &&Range, UnaryPredicate P) {
  return std::remove_if(adl_begin(Range), adl_end(Range), P);
}

@@ -1244,17 +1230,14 @@ bool is_contained(R &&Range, const E &Element) {

/// Wrapper function around std::count to count the number of times an element
/// \p Element occurs in the given range \p Range.
template <typename R, typename E>
auto count(R &&Range, const E &Element) ->
    typename std::iterator_traits<decltype(adl_begin(Range))>::difference_type {
template <typename R, typename E> auto count(R &&Range, const E &Element) {
  return std::count(adl_begin(Range), adl_end(Range), Element);
}

/// Wrapper function around std::count_if to count the number of times an
/// element satisfying a given predicate occurs in a range.
template <typename R, typename UnaryPredicate>
auto count_if(R &&Range, UnaryPredicate P) ->
    typename std::iterator_traits<decltype(adl_begin(Range))>::difference_type {
auto count_if(R &&Range, UnaryPredicate P) {
  return std::count_if(adl_begin(Range), adl_end(Range), P);
}

@@ -1268,36 +1251,32 @@ OutputIt transform(R &&Range, OutputIt d_first, UnaryPredicate P) {
/// Provide wrappers to std::partition which take ranges instead of having to
/// pass begin/end explicitly.
template <typename R, typename UnaryPredicate>
auto partition(R &&Range, UnaryPredicate P) -> decltype(adl_begin(Range)) {
auto partition(R &&Range, UnaryPredicate P) {
  return std::partition(adl_begin(Range), adl_end(Range), P);
}

/// Provide wrappers to std::lower_bound which take ranges instead of having to
/// pass begin/end explicitly.
template <typename R, typename T>
auto lower_bound(R &&Range, T &&Value) -> decltype(adl_begin(Range)) {
template <typename R, typename T> auto lower_bound(R &&Range, T &&Value) {
  return std::lower_bound(adl_begin(Range), adl_end(Range),
                          std::forward<T>(Value));
}

template <typename R, typename T, typename Compare>
auto lower_bound(R &&Range, T &&Value, Compare C)
    -> decltype(adl_begin(Range)) {
auto lower_bound(R &&Range, T &&Value, Compare C) {
  return std::lower_bound(adl_begin(Range), adl_end(Range),
                          std::forward<T>(Value), C);
}

/// Provide wrappers to std::upper_bound which take ranges instead of having to
/// pass begin/end explicitly.
template <typename R, typename T>
auto upper_bound(R &&Range, T &&Value) -> decltype(adl_begin(Range)) {
template <typename R, typename T> auto upper_bound(R &&Range, T &&Value) {
  return std::upper_bound(adl_begin(Range), adl_end(Range),
                          std::forward<T>(Value));
}

template <typename R, typename T, typename Compare>
auto upper_bound(R &&Range, T &&Value, Compare C)
    -> decltype(adl_begin(Range)) {
auto upper_bound(R &&Range, T &&Value, Compare C) {
  return std::upper_bound(adl_begin(Range), adl_end(Range),
                          std::forward<T>(Value), C);
}
@@ -1316,7 +1295,7 @@ void stable_sort(R &&Range, Compare C) {
/// Requires that C is always true below some limit, and always false above it.
template <typename R, typename Predicate,
          typename Val = decltype(*adl_begin(std::declval<R>()))>
auto partition_point(R &&Range, Predicate P) -> decltype(adl_begin(Range)) {
auto partition_point(R &&Range, Predicate P) {
  return std::partition_point(adl_begin(Range), adl_end(Range), P);
}

@@ -1393,8 +1372,7 @@ template <typename T> struct deref {
  // Could be further improved to cope with non-derivable functors and
  // non-binary functors (should be a variadic template member function
  // operator()).
  template <typename A, typename B>
  auto operator()(A &lhs, B &rhs) const -> decltype(func(*lhs, *rhs)) {
  template <typename A, typename B> auto operator()(A &lhs, B &rhs) const {
    assert(lhs);
    assert(rhs);
    return func(*lhs, *rhs);
@@ -1515,8 +1493,7 @@ template <typename R> detail::enumerator<R> enumerate(R &&TheRange) {
namespace detail {

template <typename F, typename Tuple, std::size_t... I>
auto apply_tuple_impl(F &&f, Tuple &&t, std::index_sequence<I...>)
    -> decltype(std::forward<F>(f)(std::get<I>(std::forward<Tuple>(t))...)) {
decltype(auto) apply_tuple_impl(F &&f, Tuple &&t, std::index_sequence<I...>) {
  return std::forward<F>(f)(std::get<I>(std::forward<Tuple>(t))...);
}

@@ -1526,10 +1503,7 @@ auto apply_tuple_impl(F &&f, Tuple &&t, std::index_sequence<I...>)
/// tuple variadically to f as if by calling f(a1, a2, ..., an) and
/// return the result.
template <typename F, typename Tuple>
auto apply_tuple(F &&f, Tuple &&t) -> decltype(detail::apply_tuple_impl(
    std::forward<F>(f), std::forward<Tuple>(t),
    std::make_index_sequence<
        std::tuple_size<typename std::decay<Tuple>::type>::value>{})) {
decltype(auto) apply_tuple(F &&f, Tuple &&t) {
  using Indices = std::make_index_sequence<
      std::tuple_size<typename std::decay<Tuple>::type>::value>;

@@ -1573,15 +1547,12 @@ bool hasNItemsOrMore(

/// Returns a raw pointer that represents the same address as the argument.
///
/// The late bound return should be removed once we move to C++14 to better
/// align with the C++20 declaration. Also, this implementation can be removed
/// once we move to C++20 where it's defined as std::to_addres()
/// This implementation can be removed once we move to C++20 where it's defined
/// as std::to_addres().
///
/// The std::pointer_traits<>::to_address(p) variations of these overloads has
/// not been implemented.
template <class Ptr> auto to_address(const Ptr &P) -> decltype(P.operator->()) {
  return P.operator->();
}
template <class Ptr> auto to_address(const Ptr &P) { return P.operator->(); }
template <class T> constexpr T *to_address(T *P) { return P; }

} // end namespace llvm
+2 −4
Original line number Diff line number Diff line
@@ -96,12 +96,10 @@ public:
  }

  /// Forward dereference to the underlying iterator.
  auto operator*() -> decltype(*std::declval<Underlying>()) { return *I; }
  decltype(auto) operator*() { return *I; }

  /// Forward const dereference to the underlying iterator.
  auto operator*() const -> decltype(*std::declval<const Underlying>()) {
    return *I;
  }
  decltype(auto) operator*() const { return *I; }

  /// Forward structure dereference to the underlying iterator (if the
  /// underlying iterator supports it).
+2 −4
Original line number Diff line number Diff line
@@ -17,13 +17,11 @@
#include "llvm/Support/Casting.h"

#define FORWARD_SYMBOL_METHOD(MethodName)                                      \
  auto MethodName() const->decltype(RawSymbol->MethodName()) {                 \
    return RawSymbol->MethodName();                                            \
  }
  decltype(auto) MethodName() const { return RawSymbol->MethodName(); }

#define FORWARD_CONCRETE_SYMBOL_ID_METHOD_WITH_NAME(ConcreteType, PrivateName, \
                                                    PublicName)                \
  auto PublicName##Id() const->decltype(RawSymbol->PrivateName##Id()) {        \
  decltype(auto) PublicName##Id() const {                                      \
    return RawSymbol->PrivateName##Id();                                       \
  }                                                                            \
  std::unique_ptr<ConcreteType> PublicName() const {                           \
+1 −1
Original line number Diff line number Diff line
@@ -1079,7 +1079,7 @@ public:
  std::shared_ptr<SymbolStringPool> getSymbolStringPool() const { return SSP; }

  /// Run the given lambda with the session mutex locked.
  template <typename Func> auto runSessionLocked(Func &&F) -> decltype(F()) {
  template <typename Func> decltype(auto) runSessionLocked(Func &&F) {
    std::lock_guard<std::recursive_mutex> Lock(SessionMutex);
    return F();
  }
+2 −5
Original line number Diff line number Diff line
@@ -130,8 +130,7 @@ public:

  /// Locks the associated ThreadSafeContext and calls the given function
  /// on the contained Module.
  template <typename Func>
  auto withModuleDo(Func &&F) -> decltype(F(std::declval<Module &>())) {
  template <typename Func> decltype(auto) withModuleDo(Func &&F) {
    assert(M && "Can not call on null module");
    auto Lock = TSCtx.getLock();
    return F(*M);
@@ -139,9 +138,7 @@ public:

  /// Locks the associated ThreadSafeContext and calls the given function
  /// on the contained Module.
  template <typename Func>
  auto withModuleDo(Func &&F) const
      -> decltype(F(std::declval<const Module &>())) {
  template <typename Func> decltype(auto) withModuleDo(Func &&F) const {
    auto Lock = TSCtx.getLock();
    return F(*M);
  }
Loading