This is an archive of the discontinued LLVM Phabricator instance.

Add missing template keywords
ClosedPublic

Authored by gruenich on Mar 5 2022, 8:24 AM.

Details

Summary

GCC 14 warns about these.

Diff Detail

Event Timeline

gruenich created this revision.Mar 5 2022, 8:24 AM
Herald added a project: Restricted Project. · View Herald TranscriptMar 5 2022, 8:24 AM
Herald added a subscriber: dexonsmith. · View Herald Transcript
gruenich requested review of this revision.Mar 5 2022, 8:24 AM
Herald added a project: Restricted Project. · View Herald TranscriptMar 5 2022, 8:24 AM
gruenich updated this revision to Diff 413235.Mar 5 2022, 11:19 AM

Provide patch with a full context, please

By full context, you mean the whole file with the diff included? Or something else?

//===- llvm/ADT/PointerSumType.h --------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_ADT_POINTERSUMTYPE_H
#define LLVM_ADT_POINTERSUMTYPE_H

#include "llvm/ADT/bit.h"
#include "llvm/ADT/DenseMapInfo.h"
#include "llvm/Support/PointerLikeTypeTraits.h"
#include <cassert>
#include <cstdint>
#include <type_traits>

namespace llvm {

/// A compile time pair of an integer tag and the pointer-like type which it
/// indexes within a sum type. Also allows the user to specify a particular
/// traits class for pointer types with custom behavior such as over-aligned
/// allocation.
template <uintptr_t N, typename PointerArgT,
          typename TraitsArgT = PointerLikeTypeTraits<PointerArgT>>
struct PointerSumTypeMember {
  enum { Tag = N };
  using PointerT = PointerArgT;
  using TraitsT = TraitsArgT;
};

namespace detail {

template <typename TagT, typename... MemberTs> struct PointerSumTypeHelper;

} // end namespace detail

/// A sum type over pointer-like types.
///
/// This is a normal tagged union across pointer-like types that uses the low
/// bits of the pointers to store the tag.
///
/// Each member of the sum type is specified by passing a \c
/// PointerSumTypeMember specialization in the variadic member argument list.
/// This allows the user to control the particular tag value associated with
/// a particular type, use the same type for multiple different tags, and
/// customize the pointer-like traits used for a particular member. Note that
/// these *must* be specializations of \c PointerSumTypeMember, no other type
/// will suffice, even if it provides a compatible interface.
///
/// This type implements all of the comparison operators and even hash table
/// support by comparing the underlying storage of the pointer values. It
/// doesn't support delegating to particular members for comparisons.
///
/// It also default constructs to a zero tag with a null pointer, whatever that
/// would be. This means that the zero value for the tag type is significant
/// and may be desirable to set to a state that is particularly desirable to
/// default construct.
///
/// Having a supported zero-valued tag also enables getting the address of a
/// pointer stored with that tag provided it is stored in its natural bit
/// representation. This works because in the case of a zero-valued tag, the
/// pointer's value is directly stored into this object and we can expose the
/// address of that internal storage. This is especially useful when building an
/// `ArrayRef` of a single pointer stored in a sum type.
///
/// There is no support for constructing or accessing with a dynamic tag as
/// that would fundamentally violate the type safety provided by the sum type.
template <typename TagT, typename... MemberTs> class PointerSumType {
  using HelperT = detail::PointerSumTypeHelper<TagT, MemberTs...>;

  // We keep both the raw value and the min tag value's pointer in a union. When
  // the minimum tag value is zero, this allows code below to cleanly expose the
  // address of the zero-tag pointer instead of just the zero-tag pointer
  // itself. This is especially useful when building `ArrayRef`s out of a single
  // pointer. However, we have to carefully access the union due to the active
  // member potentially changing. When we *store* a new value, we directly
  // access the union to allow us to store using the obvious types. However,
  // when we *read* a value, we copy the underlying storage out to avoid relying
  // on one member or the other being active.
  union StorageT {
    // Ensure we get a null default constructed value. We don't use a member
    // initializer because some compilers seem to not implement those correctly
    // for a union.
    StorageT() : Value(0) {}

    uintptr_t Value;

    typename HelperT::template Lookup<HelperT::MinTag>::PointerT MinTagPointer;
  };

  StorageT Storage;

public:
  constexpr PointerSumType() = default;

  /// A typed setter to a given tagged member of the sum type.
  template <TagT N>
  void set(typename HelperT::template Lookup<N>::PointerT Pointer) {
    void *V = HelperT::template Lookup<N>::TraitsT::getAsVoidPointer(Pointer);
    assert((reinterpret_cast<uintptr_t>(V) & HelperT::TagMask) == 0 &&
           "Pointer is insufficiently aligned to store the discriminant!");
    Storage.Value = reinterpret_cast<uintptr_t>(V) | N;
  }

  /// A typed constructor for a specific tagged member of the sum type.
  template <TagT N>
  static PointerSumType
  create(typename HelperT::template Lookup<N>::PointerT Pointer) {
    PointerSumType Result;
    Result.set<N>(Pointer);
    return Result;
  }

  /// Clear the value to null with the min tag type.
  void clear() { set<HelperT::MinTag>(nullptr); }

  TagT getTag() const {
    return static_cast<TagT>(getOpaqueValue() & HelperT::TagMask);
  }

  template <TagT N> bool is() const { return N == getTag(); }

  template <TagT N> typename HelperT::template Lookup<N>::PointerT get() const {
    void *P = is<N>() ? getVoidPtr() : nullptr;
    return HelperT::template Lookup<N>::TraitsT::getFromVoidPointer(P);
  }

  template <TagT N>
  typename HelperT::template Lookup<N>::PointerT cast() const {
    assert(is<N>() && "This instance has a different active member.");
    return HelperT::template Lookup<N>::TraitsT::getFromVoidPointer(
        getVoidPtr());
  }

  /// If the tag is zero and the pointer's value isn't changed when being
  /// stored, get the address of the stored value type-punned to the zero-tag's
  /// pointer type.
  typename HelperT::template Lookup<HelperT::MinTag>::PointerT const *
  getAddrOfZeroTagPointer() const {
    return const_cast<PointerSumType *>(this)->getAddrOfZeroTagPointer();
  }

  /// If the tag is zero and the pointer's value isn't changed when being
  /// stored, get the address of the stored value type-punned to the zero-tag's
  /// pointer type.
  typename HelperT::template Lookup<HelperT::MinTag>::PointerT *
  getAddrOfZeroTagPointer() {
    static_assert(HelperT::MinTag == 0, "Non-zero minimum tag value!");
    assert(is<HelperT::MinTag>() && "The active tag is not zero!");
    // Store the initial value of the pointer when read out of our storage.
    auto InitialPtr = get<HelperT::MinTag>();
    // Now update the active member of the union to be the actual pointer-typed
    // member so that accessing it indirectly through the returned address is
    // valid.
    Storage.MinTagPointer = InitialPtr;
    // Finally, validate that this was a no-op as expected by reading it back
    // out using the same underlying-storage read as above.
    assert(InitialPtr == get<HelperT::MinTag>() &&
           "Switching to typed storage changed the pointer returned!");
    // Now we can correctly return an address to typed storage.
    return &Storage.MinTagPointer;
  }

  explicit operator bool() const {
    return getOpaqueValue() & HelperT::PointerMask;
  }
  bool operator==(const PointerSumType &R) const {
    return getOpaqueValue() == R.getOpaqueValue();
  }
  bool operator!=(const PointerSumType &R) const {
    return getOpaqueValue() != R.getOpaqueValue();
  }
  bool operator<(const PointerSumType &R) const {
    return getOpaqueValue() < R.getOpaqueValue();
  }
  bool operator>(const PointerSumType &R) const {
    return getOpaqueValue() > R.getOpaqueValue();
  }
  bool operator<=(const PointerSumType &R) const {
    return getOpaqueValue() <= R.getOpaqueValue();
  }
  bool operator>=(const PointerSumType &R) const {
    return getOpaqueValue() >= R.getOpaqueValue();
  }

  uintptr_t getOpaqueValue() const {
    // Read the underlying storage of the union, regardless of the active
    // member.
    return bit_cast<uintptr_t>(Storage);
  }

protected:
  void *getVoidPtr() const {
    return reinterpret_cast<void *>(getOpaqueValue() & HelperT::PointerMask);
  }
};

namespace detail {

/// A helper template for implementing \c PointerSumType. It provides fast
/// compile-time lookup of the member from a particular tag value, along with
/// useful constants and compile time checking infrastructure..
template <typename TagT, typename... MemberTs>
struct PointerSumTypeHelper : MemberTs... {
  // First we use a trick to allow quickly looking up information about
  // a particular member of the sum type. This works because we arranged to
  // have this type derive from all of the member type templates. We can select
  // the matching member for a tag using type deduction during overload
  // resolution.
  template <TagT N, typename PointerT, typename TraitsT>
  static PointerSumTypeMember<N, PointerT, TraitsT>
  LookupOverload(PointerSumTypeMember<N, PointerT, TraitsT> *);
  template <TagT N> static void LookupOverload(...);
  template <TagT N> struct Lookup {
    // Compute a particular member type by resolving the lookup helper overload.
    using MemberT = decltype(
        LookupOverload<N>(static_cast<PointerSumTypeHelper *>(nullptr)));

    /// The Nth member's pointer type.
    using PointerT = typename MemberT::PointerT;

    /// The Nth member's traits type.
    using TraitsT = typename MemberT::TraitsT;
  };

  // Next we need to compute the number of bits available for the discriminant
  // by taking the min of the bits available for each member. Much of this
  // would be amazingly easier with good constexpr support.
  template <uintptr_t V, uintptr_t... Vs>
  struct Min : std::integral_constant<
                   uintptr_t, (V < Min<Vs...>::value ? V : Min<Vs...>::value)> {
  };
  template <uintptr_t V>
  struct Min<V> : std::integral_constant<uintptr_t, V> {};
  enum { NumTagBits = Min<MemberTs::TraitsT::NumLowBitsAvailable...>::value };

  // Also compute the smallest discriminant and various masks for convenience.
  constexpr static TagT MinTag =
      static_cast<TagT>(Min<MemberTs::Tag...>::value);
  enum : uint64_t {
    PointerMask = static_cast<uint64_t>(-1) << NumTagBits,
    TagMask = ~PointerMask
  };

  // Finally we need a recursive template to do static checks of each
  // member.
  template <typename MemberT, typename... InnerMemberTs>
  struct Checker : Checker<InnerMemberTs...> {
    static_assert(MemberT::Tag < (1 << NumTagBits),
                  "This discriminant value requires too many bits!");
  };
  template <typename MemberT> struct Checker<MemberT> : std::true_type {
    static_assert(MemberT::Tag < (1 << NumTagBits),
                  "This discriminant value requires too many bits!");
  };
  static_assert(Checker<MemberTs...>::value,
                "Each member must pass the checker.");
};

} // end namespace detail

// Teach DenseMap how to use PointerSumTypes as keys.
template <typename TagT, typename... MemberTs>
struct DenseMapInfo<PointerSumType<TagT, MemberTs...>> {
  using SumType = PointerSumType<TagT, MemberTs...>;
  using HelperT = detail::PointerSumTypeHelper<TagT, MemberTs...>;
  enum { SomeTag = HelperT::MinTag };
  using SomePointerT =
      typename HelperT::template Lookup<HelperT::MinTag>::PointerT;
  using SomePointerInfo = DenseMapInfo<SomePointerT>;

  static inline SumType getEmptyKey() {
-    return SumType::create<SomeTag>(SomePointerInfo::getEmptyKey());
+    return SumType::template create<SomeTag>(SomePointerInfo::getEmptyKey());
   }
 
   static inline SumType getTombstoneKey() {
-    return SumType::create<SomeTag>(SomePointerInfo::getTombstoneKey());
+    return SumType::template create<SomeTag>(
+        SomePointerInfo::getTombstoneKey());
  }

  static unsigned getHashValue(const SumType &Arg) {
    uintptr_t OpaqueValue = Arg.getOpaqueValue();
    return DenseMapInfo<uintptr_t>::getHashValue(OpaqueValue);
  }

  static bool isEqual(const SumType &LHS, const SumType &RHS) {
    return LHS == RHS;
  }
};

} // end namespace llvm

#endif // LLVM_ADT_POINTERSUMTYPE_H

git diff -U9999 usually works for me

diff --git a/llvm/include/llvm/ADT/PointerSumType.h b/llvm/include/llvm/ADT/PointerSumType.h
index a7ef774e20..57f045035a 100644
--- a/llvm/include/llvm/ADT/PointerSumType.h
+++ b/llvm/include/llvm/ADT/PointerSumType.h
@@ -1,294 +1,295 @@
 //===- llvm/ADT/PointerSumType.h --------------------------------*- C++ -*-===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 //
 //===----------------------------------------------------------------------===//
 
 #ifndef LLVM_ADT_POINTERSUMTYPE_H
 #define LLVM_ADT_POINTERSUMTYPE_H
 
 #include "llvm/ADT/bit.h"
 #include "llvm/ADT/DenseMapInfo.h"
 #include "llvm/Support/PointerLikeTypeTraits.h"
 #include <cassert>
 #include <cstdint>
 #include <type_traits>
 
 namespace llvm {
 
 /// A compile time pair of an integer tag and the pointer-like type which it
 /// indexes within a sum type. Also allows the user to specify a particular
 /// traits class for pointer types with custom behavior such as over-aligned
 /// allocation.
 template <uintptr_t N, typename PointerArgT,
           typename TraitsArgT = PointerLikeTypeTraits<PointerArgT>>
 struct PointerSumTypeMember {
   enum { Tag = N };
   using PointerT = PointerArgT;
   using TraitsT = TraitsArgT;
 };
 
 namespace detail {
 
 template <typename TagT, typename... MemberTs> struct PointerSumTypeHelper;
 
 } // end namespace detail
 
 /// A sum type over pointer-like types.
 ///
 /// This is a normal tagged union across pointer-like types that uses the low
 /// bits of the pointers to store the tag.
 ///
 /// Each member of the sum type is specified by passing a \c
 /// PointerSumTypeMember specialization in the variadic member argument list.
 /// This allows the user to control the particular tag value associated with
 /// a particular type, use the same type for multiple different tags, and
 /// customize the pointer-like traits used for a particular member. Note that
 /// these *must* be specializations of \c PointerSumTypeMember, no other type
 /// will suffice, even if it provides a compatible interface.
 ///
 /// This type implements all of the comparison operators and even hash table
 /// support by comparing the underlying storage of the pointer values. It
 /// doesn't support delegating to particular members for comparisons.
 ///
 /// It also default constructs to a zero tag with a null pointer, whatever that
 /// would be. This means that the zero value for the tag type is significant
 /// and may be desirable to set to a state that is particularly desirable to
 /// default construct.
 ///
 /// Having a supported zero-valued tag also enables getting the address of a
 /// pointer stored with that tag provided it is stored in its natural bit
 /// representation. This works because in the case of a zero-valued tag, the
 /// pointer's value is directly stored into this object and we can expose the
 /// address of that internal storage. This is especially useful when building an
 /// `ArrayRef` of a single pointer stored in a sum type.
 ///
 /// There is no support for constructing or accessing with a dynamic tag as
 /// that would fundamentally violate the type safety provided by the sum type.
 template <typename TagT, typename... MemberTs> class PointerSumType {
   using HelperT = detail::PointerSumTypeHelper<TagT, MemberTs...>;
 
   // We keep both the raw value and the min tag value's pointer in a union. When
   // the minimum tag value is zero, this allows code below to cleanly expose the
   // address of the zero-tag pointer instead of just the zero-tag pointer
   // itself. This is especially useful when building `ArrayRef`s out of a single
   // pointer. However, we have to carefully access the union due to the active
   // member potentially changing. When we *store* a new value, we directly
   // access the union to allow us to store using the obvious types. However,
   // when we *read* a value, we copy the underlying storage out to avoid relying
   // on one member or the other being active.
   union StorageT {
     // Ensure we get a null default constructed value. We don't use a member
     // initializer because some compilers seem to not implement those correctly
     // for a union.
     StorageT() : Value(0) {}
 
     uintptr_t Value;
 
     typename HelperT::template Lookup<HelperT::MinTag>::PointerT MinTagPointer;
   };
 
   StorageT Storage;
 
 public:
   constexpr PointerSumType() = default;
 
   /// A typed setter to a given tagged member of the sum type.
   template <TagT N>
   void set(typename HelperT::template Lookup<N>::PointerT Pointer) {
     void *V = HelperT::template Lookup<N>::TraitsT::getAsVoidPointer(Pointer);
     assert((reinterpret_cast<uintptr_t>(V) & HelperT::TagMask) == 0 &&
            "Pointer is insufficiently aligned to store the discriminant!");
     Storage.Value = reinterpret_cast<uintptr_t>(V) | N;
   }
 
   /// A typed constructor for a specific tagged member of the sum type.
   template <TagT N>
   static PointerSumType
   create(typename HelperT::template Lookup<N>::PointerT Pointer) {
     PointerSumType Result;
     Result.set<N>(Pointer);
     return Result;
   }
 
   /// Clear the value to null with the min tag type.
   void clear() { set<HelperT::MinTag>(nullptr); }
 
   TagT getTag() const {
     return static_cast<TagT>(getOpaqueValue() & HelperT::TagMask);
   }
 
   template <TagT N> bool is() const { return N == getTag(); }
 
   template <TagT N> typename HelperT::template Lookup<N>::PointerT get() const {
     void *P = is<N>() ? getVoidPtr() : nullptr;
     return HelperT::template Lookup<N>::TraitsT::getFromVoidPointer(P);
   }
 
   template <TagT N>
   typename HelperT::template Lookup<N>::PointerT cast() const {
     assert(is<N>() && "This instance has a different active member.");
     return HelperT::template Lookup<N>::TraitsT::getFromVoidPointer(
         getVoidPtr());
   }
 
   /// If the tag is zero and the pointer's value isn't changed when being
   /// stored, get the address of the stored value type-punned to the zero-tag's
   /// pointer type.
   typename HelperT::template Lookup<HelperT::MinTag>::PointerT const *
   getAddrOfZeroTagPointer() const {
     return const_cast<PointerSumType *>(this)->getAddrOfZeroTagPointer();
   }
 
   /// If the tag is zero and the pointer's value isn't changed when being
   /// stored, get the address of the stored value type-punned to the zero-tag's
   /// pointer type.
   typename HelperT::template Lookup<HelperT::MinTag>::PointerT *
   getAddrOfZeroTagPointer() {
     static_assert(HelperT::MinTag == 0, "Non-zero minimum tag value!");
     assert(is<HelperT::MinTag>() && "The active tag is not zero!");
     // Store the initial value of the pointer when read out of our storage.
     auto InitialPtr = get<HelperT::MinTag>();
     // Now update the active member of the union to be the actual pointer-typed
     // member so that accessing it indirectly through the returned address is
     // valid.
     Storage.MinTagPointer = InitialPtr;
     // Finally, validate that this was a no-op as expected by reading it back
     // out using the same underlying-storage read as above.
     assert(InitialPtr == get<HelperT::MinTag>() &&
            "Switching to typed storage changed the pointer returned!");
     // Now we can correctly return an address to typed storage.
     return &Storage.MinTagPointer;
   }
 
   explicit operator bool() const {
     return getOpaqueValue() & HelperT::PointerMask;
   }
   bool operator==(const PointerSumType &R) const {
     return getOpaqueValue() == R.getOpaqueValue();
   }
   bool operator!=(const PointerSumType &R) const {
     return getOpaqueValue() != R.getOpaqueValue();
   }
   bool operator<(const PointerSumType &R) const {
     return getOpaqueValue() < R.getOpaqueValue();
   }
   bool operator>(const PointerSumType &R) const {
     return getOpaqueValue() > R.getOpaqueValue();
   }
   bool operator<=(const PointerSumType &R) const {
     return getOpaqueValue() <= R.getOpaqueValue();
   }
   bool operator>=(const PointerSumType &R) const {
     return getOpaqueValue() >= R.getOpaqueValue();
   }
 
   uintptr_t getOpaqueValue() const {
     // Read the underlying storage of the union, regardless of the active
     // member.
     return bit_cast<uintptr_t>(Storage);
   }
 
 protected:
   void *getVoidPtr() const {
     return reinterpret_cast<void *>(getOpaqueValue() & HelperT::PointerMask);
   }
 };
 
 namespace detail {
 
 /// A helper template for implementing \c PointerSumType. It provides fast
 /// compile-time lookup of the member from a particular tag value, along with
 /// useful constants and compile time checking infrastructure..
 template <typename TagT, typename... MemberTs>
 struct PointerSumTypeHelper : MemberTs... {
   // First we use a trick to allow quickly looking up information about
   // a particular member of the sum type. This works because we arranged to
   // have this type derive from all of the member type templates. We can select
   // the matching member for a tag using type deduction during overload
   // resolution.
   template <TagT N, typename PointerT, typename TraitsT>
   static PointerSumTypeMember<N, PointerT, TraitsT>
   LookupOverload(PointerSumTypeMember<N, PointerT, TraitsT> *);
   template <TagT N> static void LookupOverload(...);
   template <TagT N> struct Lookup {
     // Compute a particular member type by resolving the lookup helper overload.
     using MemberT = decltype(
         LookupOverload<N>(static_cast<PointerSumTypeHelper *>(nullptr)));
 
     /// The Nth member's pointer type.
     using PointerT = typename MemberT::PointerT;
 
     /// The Nth member's traits type.
     using TraitsT = typename MemberT::TraitsT;
   };
 
   // Next we need to compute the number of bits available for the discriminant
   // by taking the min of the bits available for each member. Much of this
   // would be amazingly easier with good constexpr support.
   template <uintptr_t V, uintptr_t... Vs>
   struct Min : std::integral_constant<
                    uintptr_t, (V < Min<Vs...>::value ? V : Min<Vs...>::value)> {
   };
   template <uintptr_t V>
   struct Min<V> : std::integral_constant<uintptr_t, V> {};
   enum { NumTagBits = Min<MemberTs::TraitsT::NumLowBitsAvailable...>::value };
 
   // Also compute the smallest discriminant and various masks for convenience.
   constexpr static TagT MinTag =
       static_cast<TagT>(Min<MemberTs::Tag...>::value);
   enum : uint64_t {
     PointerMask = static_cast<uint64_t>(-1) << NumTagBits,
     TagMask = ~PointerMask
   };
 
   // Finally we need a recursive template to do static checks of each
   // member.
   template <typename MemberT, typename... InnerMemberTs>
   struct Checker : Checker<InnerMemberTs...> {
     static_assert(MemberT::Tag < (1 << NumTagBits),
                   "This discriminant value requires too many bits!");
   };
   template <typename MemberT> struct Checker<MemberT> : std::true_type {
     static_assert(MemberT::Tag < (1 << NumTagBits),
                   "This discriminant value requires too many bits!");
   };
   static_assert(Checker<MemberTs...>::value,
                 "Each member must pass the checker.");
 };
 
 } // end namespace detail
 
 // Teach DenseMap how to use PointerSumTypes as keys.
 template <typename TagT, typename... MemberTs>
 struct DenseMapInfo<PointerSumType<TagT, MemberTs...>> {
   using SumType = PointerSumType<TagT, MemberTs...>;
   using HelperT = detail::PointerSumTypeHelper<TagT, MemberTs...>;
   enum { SomeTag = HelperT::MinTag };
   using SomePointerT =
       typename HelperT::template Lookup<HelperT::MinTag>::PointerT;
   using SomePointerInfo = DenseMapInfo<SomePointerT>;
 
   static inline SumType getEmptyKey() {
-    return SumType::create<SomeTag>(SomePointerInfo::getEmptyKey());
+    return SumType::template create<SomeTag>(SomePointerInfo::getEmptyKey());
   }
 
   static inline SumType getTombstoneKey() {
-    return SumType::create<SomeTag>(SomePointerInfo::getTombstoneKey());
+    return SumType::template create<SomeTag>(
+        SomePointerInfo::getTombstoneKey());
   }
 
   static unsigned getHashValue(const SumType &Arg) {
     uintptr_t OpaqueValue = Arg.getOpaqueValue();
     return DenseMapInfo<uintptr_t>::getHashValue(OpaqueValue);
   }
 
   static bool isEqual(const SumType &LHS, const SumType &RHS) {
     return LHS == RHS;
   }
 };
 
 } // end namespace llvm
 
 #endif // LLVM_ADT_POINTERSUMTYPE_H
diff --git a/llvm/include/llvm/ADT/PointerSumType.h b/llvm/include/llvm/ADT/PointerSumType.h
index a7ef774e20..57f045035a 100644
--- a/llvm/include/llvm/ADT/PointerSumType.h
+++ b/llvm/include/llvm/ADT/PointerSumType.h
@@ -1,294 +1,295 @@
 //===- llvm/ADT/PointerSumType.h --------------------------------*- C++ -*-===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 //
 //===----------------------------------------------------------------------===//
 
 #ifndef LLVM_ADT_POINTERSUMTYPE_H
 #define LLVM_ADT_POINTERSUMTYPE_H
 
 #include "llvm/ADT/bit.h"
 #include "llvm/ADT/DenseMapInfo.h"
 #include "llvm/Support/PointerLikeTypeTraits.h"
 #include <cassert>
 #include <cstdint>
 #include <type_traits>
 
 namespace llvm {
 
 /// A compile time pair of an integer tag and the pointer-like type which it
 /// indexes within a sum type. Also allows the user to specify a particular
 /// traits class for pointer types with custom behavior such as over-aligned
 /// allocation.
 template <uintptr_t N, typename PointerArgT,
           typename TraitsArgT = PointerLikeTypeTraits<PointerArgT>>
 struct PointerSumTypeMember {
   enum { Tag = N };
   using PointerT = PointerArgT;
   using TraitsT = TraitsArgT;
 };
 
 namespace detail {
 
 template <typename TagT, typename... MemberTs> struct PointerSumTypeHelper;
 
 } // end namespace detail
 
 /// A sum type over pointer-like types.
 ///
 /// This is a normal tagged union across pointer-like types that uses the low
 /// bits of the pointers to store the tag.
 ///
 /// Each member of the sum type is specified by passing a \c
 /// PointerSumTypeMember specialization in the variadic member argument list.
 /// This allows the user to control the particular tag value associated with
 /// a particular type, use the same type for multiple different tags, and
 /// customize the pointer-like traits used for a particular member. Note that
 /// these *must* be specializations of \c PointerSumTypeMember, no other type
 /// will suffice, even if it provides a compatible interface.
 ///
 /// This type implements all of the comparison operators and even hash table
 /// support by comparing the underlying storage of the pointer values. It
 /// doesn't support delegating to particular members for comparisons.
 ///
 /// It also default constructs to a zero tag with a null pointer, whatever that
 /// would be. This means that the zero value for the tag type is significant
 /// and may be desirable to set to a state that is particularly desirable to
 /// default construct.
 ///
 /// Having a supported zero-valued tag also enables getting the address of a
 /// pointer stored with that tag provided it is stored in its natural bit
 /// representation. This works because in the case of a zero-valued tag, the
 /// pointer's value is directly stored into this object and we can expose the
 /// address of that internal storage. This is especially useful when building an
 /// `ArrayRef` of a single pointer stored in a sum type.
 ///
 /// There is no support for constructing or accessing with a dynamic tag as
 /// that would fundamentally violate the type safety provided by the sum type.
 template <typename TagT, typename... MemberTs> class PointerSumType {
   using HelperT = detail::PointerSumTypeHelper<TagT, MemberTs...>;
 
   // We keep both the raw value and the min tag value's pointer in a union. When
   // the minimum tag value is zero, this allows code below to cleanly expose the
   // address of the zero-tag pointer instead of just the zero-tag pointer
   // itself. This is especially useful when building `ArrayRef`s out of a single
   // pointer. However, we have to carefully access the union due to the active
   // member potentially changing. When we *store* a new value, we directly
   // access the union to allow us to store using the obvious types. However,
   // when we *read* a value, we copy the underlying storage out to avoid relying
   // on one member or the other being active.
   union StorageT {
     // Ensure we get a null default constructed value. We don't use a member
     // initializer because some compilers seem to not implement those correctly
     // for a union.
     StorageT() : Value(0) {}
 
     uintptr_t Value;
 
     typename HelperT::template Lookup<HelperT::MinTag>::PointerT MinTagPointer;
   };
 
   StorageT Storage;
 
 public:
   constexpr PointerSumType() = default;
 
   /// A typed setter to a given tagged member of the sum type.
   template <TagT N>
   void set(typename HelperT::template Lookup<N>::PointerT Pointer) {
     void *V = HelperT::template Lookup<N>::TraitsT::getAsVoidPointer(Pointer);
     assert((reinterpret_cast<uintptr_t>(V) & HelperT::TagMask) == 0 &&
            "Pointer is insufficiently aligned to store the discriminant!");
     Storage.Value = reinterpret_cast<uintptr_t>(V) | N;
   }
 
   /// A typed constructor for a specific tagged member of the sum type.
   template <TagT N>
   static PointerSumType
   create(typename HelperT::template Lookup<N>::PointerT Pointer) {
     PointerSumType Result;
     Result.set<N>(Pointer);
     return Result;
   }
 
   /// Clear the value to null with the min tag type.
   void clear() { set<HelperT::MinTag>(nullptr); }
 
   TagT getTag() const {
     return static_cast<TagT>(getOpaqueValue() & HelperT::TagMask);
   }
 
   template <TagT N> bool is() const { return N == getTag(); }
 
   template <TagT N> typename HelperT::template Lookup<N>::PointerT get() const {
     void *P = is<N>() ? getVoidPtr() : nullptr;
     return HelperT::template Lookup<N>::TraitsT::getFromVoidPointer(P);
   }
 
   template <TagT N>
   typename HelperT::template Lookup<N>::PointerT cast() const {
     assert(is<N>() && "This instance has a different active member.");
     return HelperT::template Lookup<N>::TraitsT::getFromVoidPointer(
         getVoidPtr());
   }
 
   /// If the tag is zero and the pointer's value isn't changed when being
   /// stored, get the address of the stored value type-punned to the zero-tag's
   /// pointer type.
   typename HelperT::template Lookup<HelperT::MinTag>::PointerT const *
   getAddrOfZeroTagPointer() const {
     return const_cast<PointerSumType *>(this)->getAddrOfZeroTagPointer();
   }
 
   /// If the tag is zero and the pointer's value isn't changed when being
   /// stored, get the address of the stored value type-punned to the zero-tag's
   /// pointer type.
   typename HelperT::template Lookup<HelperT::MinTag>::PointerT *
   getAddrOfZeroTagPointer() {
     static_assert(HelperT::MinTag == 0, "Non-zero minimum tag value!");
     assert(is<HelperT::MinTag>() && "The active tag is not zero!");
     // Store the initial value of the pointer when read out of our storage.
     auto InitialPtr = get<HelperT::MinTag>();
     // Now update the active member of the union to be the actual pointer-typed
     // member so that accessing it indirectly through the returned address is
     // valid.
     Storage.MinTagPointer = InitialPtr;
     // Finally, validate that this was a no-op as expected by reading it back
     // out using the same underlying-storage read as above.
     assert(InitialPtr == get<HelperT::MinTag>() &&
            "Switching to typed storage changed the pointer returned!");
     // Now we can correctly return an address to typed storage.
     return &Storage.MinTagPointer;
   }
 
   explicit operator bool() const {
     return getOpaqueValue() & HelperT::PointerMask;
   }
   bool operator==(const PointerSumType &R) const {
     return getOpaqueValue() == R.getOpaqueValue();
   }
   bool operator!=(const PointerSumType &R) const {
     return getOpaqueValue() != R.getOpaqueValue();
   }
   bool operator<(const PointerSumType &R) const {
     return getOpaqueValue() < R.getOpaqueValue();
   }
   bool operator>(const PointerSumType &R) const {
     return getOpaqueValue() > R.getOpaqueValue();
   }
   bool operator<=(const PointerSumType &R) const {
     return getOpaqueValue() <= R.getOpaqueValue();
   }
   bool operator>=(const PointerSumType &R) const {
     return getOpaqueValue() >= R.getOpaqueValue();
   }
 
   uintptr_t getOpaqueValue() const {
     // Read the underlying storage of the union, regardless of the active
     // member.
     return bit_cast<uintptr_t>(Storage);
   }
 
 protected:
   void *getVoidPtr() const {
     return reinterpret_cast<void *>(getOpaqueValue() & HelperT::PointerMask);
   }
 };
 
 namespace detail {
 
 /// A helper template for implementing \c PointerSumType. It provides fast
 /// compile-time lookup of the member from a particular tag value, along with
 /// useful constants and compile time checking infrastructure..
 template <typename TagT, typename... MemberTs>
 struct PointerSumTypeHelper : MemberTs... {
   // First we use a trick to allow quickly looking up information about
   // a particular member of the sum type. This works because we arranged to
   // have this type derive from all of the member type templates. We can select
   // the matching member for a tag using type deduction during overload
   // resolution.
   template <TagT N, typename PointerT, typename TraitsT>
   static PointerSumTypeMember<N, PointerT, TraitsT>
   LookupOverload(PointerSumTypeMember<N, PointerT, TraitsT> *);
   template <TagT N> static void LookupOverload(...);
   template <TagT N> struct Lookup {
     // Compute a particular member type by resolving the lookup helper overload.
     using MemberT = decltype(
         LookupOverload<N>(static_cast<PointerSumTypeHelper *>(nullptr)));
 
     /// The Nth member's pointer type.
     using PointerT = typename MemberT::PointerT;
 
     /// The Nth member's traits type.
     using TraitsT = typename MemberT::TraitsT;
   };
 
   // Next we need to compute the number of bits available for the discriminant
   // by taking the min of the bits available for each member. Much of this
   // would be amazingly easier with good constexpr support.
   template <uintptr_t V, uintptr_t... Vs>
   struct Min : std::integral_constant<
                    uintptr_t, (V < Min<Vs...>::value ? V : Min<Vs...>::value)> {
   };
   template <uintptr_t V>
   struct Min<V> : std::integral_constant<uintptr_t, V> {};
   enum { NumTagBits = Min<MemberTs::TraitsT::NumLowBitsAvailable...>::value };
 
   // Also compute the smallest discriminant and various masks for convenience.
   constexpr static TagT MinTag =
       static_cast<TagT>(Min<MemberTs::Tag...>::value);
   enum : uint64_t {
     PointerMask = static_cast<uint64_t>(-1) << NumTagBits,
     TagMask = ~PointerMask
   };
 
   // Finally we need a recursive template to do static checks of each
   // member.
   template <typename MemberT, typename... InnerMemberTs>
   struct Checker : Checker<InnerMemberTs...> {
     static_assert(MemberT::Tag < (1 << NumTagBits),
                   "This discriminant value requires too many bits!");
   };
   template <typename MemberT> struct Checker<MemberT> : std::true_type {
     static_assert(MemberT::Tag < (1 << NumTagBits),
                   "This discriminant value requires too many bits!");
   };
   static_assert(Checker<MemberTs...>::value,
                 "Each member must pass the checker.");
 };
 
 } // end namespace detail
 
 // Teach DenseMap how to use PointerSumTypes as keys.
 template <typename TagT, typename... MemberTs>
 struct DenseMapInfo<PointerSumType<TagT, MemberTs...>> {
   using SumType = PointerSumType<TagT, MemberTs...>;
   using HelperT = detail::PointerSumTypeHelper<TagT, MemberTs...>;
   enum { SomeTag = HelperT::MinTag };
   using SomePointerT =
       typename HelperT::template Lookup<HelperT::MinTag>::PointerT;
   using SomePointerInfo = DenseMapInfo<SomePointerT>;
 
   static inline SumType getEmptyKey() {
-    return SumType::create<SomeTag>(SomePointerInfo::getEmptyKey());
+    return SumType::template create<SomeTag>(SomePointerInfo::getEmptyKey());
   }
 
   static inline SumType getTombstoneKey() {
-    return SumType::create<SomeTag>(SomePointerInfo::getTombstoneKey());
+    return SumType::template create<SomeTag>(
+        SomePointerInfo::getTombstoneKey());
   }
 
   static unsigned getHashValue(const SumType &Arg) {
     uintptr_t OpaqueValue = Arg.getOpaqueValue();
     return DenseMapInfo<uintptr_t>::getHashValue(OpaqueValue);
   }
 
   static bool isEqual(const SumType &LHS, const SumType &RHS) {
     return LHS == RHS;
   }
 };
 
 } // end namespace llvm
 
 #endif // LLVM_ADT_POINTERSUMTYPE_H

I mean upload the patch with the full context

gruenich updated this revision to Diff 417118.Mar 21 2022, 3:38 PM
ABataev accepted this revision.Mar 21 2022, 3:48 PM

This looks good, to my knowledge.

This revision is now accepted and ready to land.Mar 21 2022, 3:48 PM

What is needed to get this merged?

I can commit it.

This revision was automatically updated to reflect the committed changes.