[PATCH] D121047: Add missing template keywords

Christoph GrĂ¼ninger via Phabricator via llvm-commits llvm-commits at lists.llvm.org
Mon Mar 21 15:15:48 PDT 2022


gruenich added a comment.

  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


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D121047/new/

https://reviews.llvm.org/D121047



More information about the llvm-commits mailing list