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