Details | Last modification | View Log | RSS feed
| Rev | Author | Line No. | Line |
|---|---|---|---|
| 14 | pmbaty | 1 | //===- ComparisonCategories.h - Three Way Comparison Data -------*- C++ -*-===// |
| 2 | // |
||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
||
| 4 | // See https://llvm.org/LICENSE.txt for license information. |
||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
||
| 6 | // |
||
| 7 | //===----------------------------------------------------------------------===// |
||
| 8 | // |
||
| 9 | // This file defines the Comparison Category enum and data types, which |
||
| 10 | // store the types and expressions needed to support operator<=> |
||
| 11 | // |
||
| 12 | //===----------------------------------------------------------------------===// |
||
| 13 | |||
| 14 | #ifndef LLVM_CLANG_AST_COMPARISONCATEGORIES_H |
||
| 15 | #define LLVM_CLANG_AST_COMPARISONCATEGORIES_H |
||
| 16 | |||
| 17 | #include "clang/Basic/LLVM.h" |
||
| 18 | #include "llvm/ADT/APSInt.h" |
||
| 19 | #include "llvm/ADT/DenseMap.h" |
||
| 20 | #include <array> |
||
| 21 | #include <cassert> |
||
| 22 | #include <optional> |
||
| 23 | #include <vector> |
||
| 24 | |||
| 25 | namespace llvm { |
||
| 26 | class StringRef; |
||
| 27 | class APSInt; |
||
| 28 | } |
||
| 29 | |||
| 30 | namespace clang { |
||
| 31 | |||
| 32 | class ASTContext; |
||
| 33 | class VarDecl; |
||
| 34 | class CXXRecordDecl; |
||
| 35 | class Sema; |
||
| 36 | class QualType; |
||
| 37 | class NamespaceDecl; |
||
| 38 | |||
| 39 | /// An enumeration representing the different comparison categories |
||
| 40 | /// types. |
||
| 41 | /// |
||
| 42 | /// C++2a [cmp.categories.pre] The types weak_equality, strong_equality, |
||
| 43 | /// partial_ordering, weak_ordering, and strong_ordering are collectively |
||
| 44 | /// termed the comparison category types. |
||
| 45 | enum class ComparisonCategoryType : unsigned char { |
||
| 46 | PartialOrdering, |
||
| 47 | WeakOrdering, |
||
| 48 | StrongOrdering, |
||
| 49 | First = PartialOrdering, |
||
| 50 | Last = StrongOrdering |
||
| 51 | }; |
||
| 52 | |||
| 53 | /// Determine the common comparison type, as defined in C++2a |
||
| 54 | /// [class.spaceship]p4. |
||
| 55 | inline ComparisonCategoryType commonComparisonType(ComparisonCategoryType A, |
||
| 56 | ComparisonCategoryType B) { |
||
| 57 | return A < B ? A : B; |
||
| 58 | } |
||
| 59 | |||
| 60 | /// Get the comparison category that should be used when comparing values of |
||
| 61 | /// type \c T. |
||
| 62 | std::optional<ComparisonCategoryType> |
||
| 63 | getComparisonCategoryForBuiltinCmp(QualType T); |
||
| 64 | |||
| 65 | /// An enumeration representing the possible results of a three-way |
||
| 66 | /// comparison. These values map onto instances of comparison category types |
||
| 67 | /// defined in the standard library. e.g. 'std::strong_ordering::less'. |
||
| 68 | enum class ComparisonCategoryResult : unsigned char { |
||
| 69 | Equal, |
||
| 70 | Equivalent, |
||
| 71 | Less, |
||
| 72 | Greater, |
||
| 73 | Unordered, |
||
| 74 | Last = Unordered |
||
| 75 | }; |
||
| 76 | |||
| 77 | class ComparisonCategoryInfo { |
||
| 78 | friend class ComparisonCategories; |
||
| 79 | friend class Sema; |
||
| 80 | |||
| 81 | public: |
||
| 82 | ComparisonCategoryInfo(const ASTContext &Ctx, CXXRecordDecl *RD, |
||
| 83 | ComparisonCategoryType Kind) |
||
| 84 | : Ctx(Ctx), Record(RD), Kind(Kind) {} |
||
| 85 | |||
| 86 | struct ValueInfo { |
||
| 87 | ComparisonCategoryResult Kind; |
||
| 88 | VarDecl *VD; |
||
| 89 | |||
| 90 | ValueInfo(ComparisonCategoryResult Kind, VarDecl *VD) |
||
| 91 | : Kind(Kind), VD(VD) {} |
||
| 92 | |||
| 93 | /// True iff we've successfully evaluated the variable as a constant |
||
| 94 | /// expression and extracted its integer value. |
||
| 95 | bool hasValidIntValue() const; |
||
| 96 | |||
| 97 | /// Get the constant integer value used by this variable to represent |
||
| 98 | /// the comparison category result type. |
||
| 99 | llvm::APSInt getIntValue() const; |
||
| 100 | }; |
||
| 101 | private: |
||
| 102 | const ASTContext &Ctx; |
||
| 103 | |||
| 104 | /// A map containing the comparison category result decls from the |
||
| 105 | /// standard library. The key is a value of ComparisonCategoryResult. |
||
| 106 | mutable llvm::SmallVector< |
||
| 107 | ValueInfo, static_cast<unsigned>(ComparisonCategoryResult::Last) + 1> |
||
| 108 | Objects; |
||
| 109 | |||
| 110 | /// Lookup the ValueInfo struct for the specified ValueKind. If the |
||
| 111 | /// VarDecl for the value cannot be found, nullptr is returned. |
||
| 112 | /// |
||
| 113 | /// If the ValueInfo does not have a valid integer value the variable |
||
| 114 | /// is evaluated as a constant expression to determine that value. |
||
| 115 | ValueInfo *lookupValueInfo(ComparisonCategoryResult ValueKind) const; |
||
| 116 | |||
| 117 | public: |
||
| 118 | /// The declaration for the comparison category type from the |
||
| 119 | /// standard library. |
||
| 120 | const CXXRecordDecl *Record = nullptr; |
||
| 121 | |||
| 122 | /// The Kind of the comparison category type |
||
| 123 | ComparisonCategoryType Kind; |
||
| 124 | |||
| 125 | public: |
||
| 126 | QualType getType() const; |
||
| 127 | |||
| 128 | const ValueInfo *getValueInfo(ComparisonCategoryResult ValueKind) const { |
||
| 129 | ValueInfo *Info = lookupValueInfo(ValueKind); |
||
| 130 | assert(Info && |
||
| 131 | "comparison category does not contain the specified result kind"); |
||
| 132 | assert(Info->hasValidIntValue() && |
||
| 133 | "couldn't determine the integer constant for this value"); |
||
| 134 | return Info; |
||
| 135 | } |
||
| 136 | |||
| 137 | /// True iff the comparison is "strong". i.e. it checks equality and |
||
| 138 | /// not equivalence. |
||
| 139 | bool isStrong() const { |
||
| 140 | using CCK = ComparisonCategoryType; |
||
| 141 | return Kind == CCK::StrongOrdering; |
||
| 142 | } |
||
| 143 | |||
| 144 | /// True iff the comparison is not totally ordered. |
||
| 145 | bool isPartial() const { |
||
| 146 | using CCK = ComparisonCategoryType; |
||
| 147 | return Kind == CCK::PartialOrdering; |
||
| 148 | } |
||
| 149 | |||
| 150 | /// Converts the specified result kind into the correct result kind |
||
| 151 | /// for this category. Specifically it lowers strong equality results to |
||
| 152 | /// weak equivalence if needed. |
||
| 153 | ComparisonCategoryResult makeWeakResult(ComparisonCategoryResult Res) const { |
||
| 154 | using CCR = ComparisonCategoryResult; |
||
| 155 | if (!isStrong() && Res == CCR::Equal) |
||
| 156 | return CCR::Equivalent; |
||
| 157 | return Res; |
||
| 158 | } |
||
| 159 | |||
| 160 | const ValueInfo *getEqualOrEquiv() const { |
||
| 161 | return getValueInfo(makeWeakResult(ComparisonCategoryResult::Equal)); |
||
| 162 | } |
||
| 163 | const ValueInfo *getLess() const { |
||
| 164 | return getValueInfo(ComparisonCategoryResult::Less); |
||
| 165 | } |
||
| 166 | const ValueInfo *getGreater() const { |
||
| 167 | return getValueInfo(ComparisonCategoryResult::Greater); |
||
| 168 | } |
||
| 169 | const ValueInfo *getUnordered() const { |
||
| 170 | assert(isPartial()); |
||
| 171 | return getValueInfo(ComparisonCategoryResult::Unordered); |
||
| 172 | } |
||
| 173 | }; |
||
| 174 | |||
| 175 | class ComparisonCategories { |
||
| 176 | public: |
||
| 177 | static StringRef getCategoryString(ComparisonCategoryType Kind); |
||
| 178 | static StringRef getResultString(ComparisonCategoryResult Kind); |
||
| 179 | |||
| 180 | /// Return the list of results which are valid for the specified |
||
| 181 | /// comparison category type. |
||
| 182 | static std::vector<ComparisonCategoryResult> |
||
| 183 | getPossibleResultsForType(ComparisonCategoryType Type); |
||
| 184 | |||
| 185 | /// Return the comparison category information for the category |
||
| 186 | /// specified by 'Kind'. |
||
| 187 | const ComparisonCategoryInfo &getInfo(ComparisonCategoryType Kind) const { |
||
| 188 | const ComparisonCategoryInfo *Result = lookupInfo(Kind); |
||
| 189 | assert(Result != nullptr && |
||
| 190 | "information for specified comparison category has not been built"); |
||
| 191 | return *Result; |
||
| 192 | } |
||
| 193 | |||
| 194 | /// Return the comparison category information as specified by |
||
| 195 | /// `getCategoryForType(Ty)`. If the information is not already cached, |
||
| 196 | /// the declaration is looked up and a cache entry is created. |
||
| 197 | /// NOTE: Lookup is expected to succeed. Use lookupInfo if failure is |
||
| 198 | /// possible. |
||
| 199 | const ComparisonCategoryInfo &getInfoForType(QualType Ty) const; |
||
| 200 | |||
| 201 | public: |
||
| 202 | /// Return the cached comparison category information for the |
||
| 203 | /// specified 'Kind'. If no cache entry is present the comparison category |
||
| 204 | /// type is looked up. If lookup fails nullptr is returned. Otherwise, a |
||
| 205 | /// new cache entry is created and returned |
||
| 206 | const ComparisonCategoryInfo *lookupInfo(ComparisonCategoryType Kind) const; |
||
| 207 | |||
| 208 | ComparisonCategoryInfo *lookupInfo(ComparisonCategoryType Kind) { |
||
| 209 | const auto &This = *this; |
||
| 210 | return const_cast<ComparisonCategoryInfo *>(This.lookupInfo(Kind)); |
||
| 211 | } |
||
| 212 | |||
| 213 | const ComparisonCategoryInfo *lookupInfoForType(QualType Ty) const; |
||
| 214 | |||
| 215 | private: |
||
| 216 | friend class ASTContext; |
||
| 217 | |||
| 218 | explicit ComparisonCategories(const ASTContext &Ctx) : Ctx(Ctx) {} |
||
| 219 | |||
| 220 | const ASTContext &Ctx; |
||
| 221 | |||
| 222 | /// A map from the ComparisonCategoryType (represented as 'char') to the |
||
| 223 | /// cached information for the specified category. |
||
| 224 | mutable llvm::DenseMap<char, ComparisonCategoryInfo> Data; |
||
| 225 | mutable NamespaceDecl *StdNS = nullptr; |
||
| 226 | }; |
||
| 227 | |||
| 228 | } // namespace clang |
||
| 229 | |||
| 230 | #endif |