1 //===- ComparisonCategories.h - Three Way Comparison Data -------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This file defines the Comparison Category enum and data types, which
11 // store the types and expressions needed to support operator<=>
13 //===----------------------------------------------------------------------===//
15 #ifndef LLVM_CLANG_AST_COMPARISONCATEGORIES_H
16 #define LLVM_CLANG_AST_COMPARISONCATEGORIES_H
18 #include "clang/Basic/LLVM.h"
19 #include "llvm/ADT/APSInt.h"
20 #include "llvm/ADT/DenseMap.h"
38 /// An enumeration representing the different comparison categories
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 {
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 {
68 class ComparisonCategoryInfo {
69 friend class ComparisonCategories;
73 ComparisonCategoryInfo(const ASTContext &Ctx, CXXRecordDecl *RD,
74 ComparisonCategoryType Kind)
75 : Ctx(Ctx), Record(RD), Kind(Kind) {}
78 ComparisonCategoryResult Kind;
81 ValueInfo(ComparisonCategoryResult Kind, VarDecl *VD)
82 : Kind(Kind), VD(VD) {}
84 /// True iff we've successfully evaluated the variable as a constant
85 /// expression and extracted its integer value.
86 bool hasValidIntValue() const;
88 /// Get the constant integer value used by this variable to represent
89 /// the comparison category result type.
90 llvm::APSInt getIntValue() const;
93 const ASTContext &Ctx;
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>
101 /// Lookup the ValueInfo struct for the specified ValueKind. If the
102 /// VarDecl for the value cannot be found, nullptr is returned.
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;
109 /// The declaration for the comparison category type from the
110 /// standard library.
111 // FIXME: Make this const
112 CXXRecordDecl *Record = nullptr;
114 /// The Kind of the comparison category type
115 ComparisonCategoryType Kind;
118 QualType getType() const;
120 const ValueInfo *getValueInfo(ComparisonCategoryResult ValueKind) const {
121 ValueInfo *Info = lookupValueInfo(ValueKind);
123 "comparison category does not contain the specified result kind");
124 assert(Info->hasValidIntValue() &&
125 "couldn't determine the integer constant for this value");
129 /// True iff the comparison category is an equality comparison.
130 bool isEquality() const { return !isOrdered(); }
132 /// True iff the comparison category is a relational comparison.
133 bool isOrdered() const {
134 using CCK = ComparisonCategoryType;
135 return Kind == CCK::PartialOrdering || Kind == CCK::WeakOrdering ||
136 Kind == CCK::StrongOrdering;
139 /// True iff the comparison is "strong". i.e. it checks equality and
141 bool isStrong() const {
142 using CCK = ComparisonCategoryType;
143 return Kind == CCK::StrongEquality || Kind == CCK::StrongOrdering;
146 /// True iff the comparison is not totally ordered.
147 bool isPartial() const {
148 using CCK = ComparisonCategoryType;
149 return Kind == CCK::PartialOrdering;
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.
155 ComparisonCategoryResult makeWeakResult(ComparisonCategoryResult Res) const {
156 using CCR = ComparisonCategoryResult;
158 if (Res == CCR::Equal)
159 return CCR::Equivalent;
160 if (Res == CCR::Nonequal)
161 return CCR::Nonequivalent;
166 const ValueInfo *getEqualOrEquiv() const {
167 return getValueInfo(makeWeakResult(ComparisonCategoryResult::Equal));
169 const ValueInfo *getNonequalOrNonequiv() const {
170 assert(isEquality());
171 return getValueInfo(makeWeakResult(ComparisonCategoryResult::Nonequal));
173 const ValueInfo *getLess() const {
175 return getValueInfo(ComparisonCategoryResult::Less);
177 const ValueInfo *getGreater() const {
179 return getValueInfo(ComparisonCategoryResult::Greater);
181 const ValueInfo *getUnordered() const {
183 return getValueInfo(ComparisonCategoryResult::Unordered);
187 class ComparisonCategories {
189 static StringRef getCategoryString(ComparisonCategoryType Kind);
190 static StringRef getResultString(ComparisonCategoryResult Kind);
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);
197 /// Return the comparison category information for the category
198 /// specified by '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");
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
211 const ComparisonCategoryInfo &getInfoForType(QualType Ty) const;
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;
220 ComparisonCategoryInfo *lookupInfo(ComparisonCategoryType Kind) {
221 const auto &This = *this;
222 return const_cast<ComparisonCategoryInfo *>(This.lookupInfo(Kind));
226 const ComparisonCategoryInfo *lookupInfoForType(QualType Ty) const;
229 friend class ASTContext;
231 explicit ComparisonCategories(const ASTContext &Ctx) : Ctx(Ctx) {}
233 const ASTContext &Ctx;
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;