1 //===- ComparisonCategories.h - Three Way Comparison Data -------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 // This file defines the Comparison Category enum and data types, which
10 // store the types and expressions needed to support operator<=>
12 //===----------------------------------------------------------------------===//
14 #ifndef LLVM_CLANG_AST_COMPARISONCATEGORIES_H
15 #define LLVM_CLANG_AST_COMPARISONCATEGORIES_H
17 #include "clang/Basic/LLVM.h"
18 #include "llvm/ADT/APSInt.h"
19 #include "llvm/ADT/DenseMap.h"
37 /// An enumeration representing the different comparison categories
40 /// C++2a [cmp.categories.pre] The types weak_equality, strong_equality,
41 /// partial_ordering, weak_ordering, and strong_ordering are collectively
42 /// termed the comparison category types.
43 enum class ComparisonCategoryType : unsigned char {
53 /// An enumeration representing the possible results of a three-way
54 /// comparison. These values map onto instances of comparison category types
55 /// defined in the standard library. e.g. 'std::strong_ordering::less'.
56 enum class ComparisonCategoryResult : unsigned char {
67 class ComparisonCategoryInfo {
68 friend class ComparisonCategories;
72 ComparisonCategoryInfo(const ASTContext &Ctx, CXXRecordDecl *RD,
73 ComparisonCategoryType Kind)
74 : Ctx(Ctx), Record(RD), Kind(Kind) {}
77 ComparisonCategoryResult Kind;
80 ValueInfo(ComparisonCategoryResult Kind, VarDecl *VD)
81 : Kind(Kind), VD(VD) {}
83 /// True iff we've successfully evaluated the variable as a constant
84 /// expression and extracted its integer value.
85 bool hasValidIntValue() const;
87 /// Get the constant integer value used by this variable to represent
88 /// the comparison category result type.
89 llvm::APSInt getIntValue() const;
92 const ASTContext &Ctx;
94 /// A map containing the comparison category result decls from the
95 /// standard library. The key is a value of ComparisonCategoryResult.
96 mutable llvm::SmallVector<
97 ValueInfo, static_cast<unsigned>(ComparisonCategoryResult::Last) + 1>
100 /// Lookup the ValueInfo struct for the specified ValueKind. If the
101 /// VarDecl for the value cannot be found, nullptr is returned.
103 /// If the ValueInfo does not have a valid integer value the variable
104 /// is evaluated as a constant expression to determine that value.
105 ValueInfo *lookupValueInfo(ComparisonCategoryResult ValueKind) const;
108 /// The declaration for the comparison category type from the
109 /// standard library.
110 // FIXME: Make this const
111 CXXRecordDecl *Record = nullptr;
113 /// The Kind of the comparison category type
114 ComparisonCategoryType Kind;
117 QualType getType() const;
119 const ValueInfo *getValueInfo(ComparisonCategoryResult ValueKind) const {
120 ValueInfo *Info = lookupValueInfo(ValueKind);
122 "comparison category does not contain the specified result kind");
123 assert(Info->hasValidIntValue() &&
124 "couldn't determine the integer constant for this value");
128 /// True iff the comparison category is an equality comparison.
129 bool isEquality() const { return !isOrdered(); }
131 /// True iff the comparison category is a relational comparison.
132 bool isOrdered() const {
133 using CCK = ComparisonCategoryType;
134 return Kind == CCK::PartialOrdering || Kind == CCK::WeakOrdering ||
135 Kind == CCK::StrongOrdering;
138 /// True iff the comparison is "strong". i.e. it checks equality and
140 bool isStrong() const {
141 using CCK = ComparisonCategoryType;
142 return Kind == CCK::StrongEquality || Kind == CCK::StrongOrdering;
145 /// True iff the comparison is not totally ordered.
146 bool isPartial() const {
147 using CCK = ComparisonCategoryType;
148 return Kind == CCK::PartialOrdering;
151 /// Converts the specified result kind into the the correct result kind
152 /// for this category. Specifically it lowers strong equality results to
153 /// weak equivalence if needed.
154 ComparisonCategoryResult makeWeakResult(ComparisonCategoryResult Res) const {
155 using CCR = ComparisonCategoryResult;
157 if (Res == CCR::Equal)
158 return CCR::Equivalent;
159 if (Res == CCR::Nonequal)
160 return CCR::Nonequivalent;
165 const ValueInfo *getEqualOrEquiv() const {
166 return getValueInfo(makeWeakResult(ComparisonCategoryResult::Equal));
168 const ValueInfo *getNonequalOrNonequiv() const {
169 assert(isEquality());
170 return getValueInfo(makeWeakResult(ComparisonCategoryResult::Nonequal));
172 const ValueInfo *getLess() const {
174 return getValueInfo(ComparisonCategoryResult::Less);
176 const ValueInfo *getGreater() const {
178 return getValueInfo(ComparisonCategoryResult::Greater);
180 const ValueInfo *getUnordered() const {
182 return getValueInfo(ComparisonCategoryResult::Unordered);
186 class ComparisonCategories {
188 static StringRef getCategoryString(ComparisonCategoryType Kind);
189 static StringRef getResultString(ComparisonCategoryResult Kind);
191 /// Return the list of results which are valid for the specified
192 /// comparison category type.
193 static std::vector<ComparisonCategoryResult>
194 getPossibleResultsForType(ComparisonCategoryType Type);
196 /// Return the comparison category information for the category
197 /// specified by 'Kind'.
198 const ComparisonCategoryInfo &getInfo(ComparisonCategoryType Kind) const {
199 const ComparisonCategoryInfo *Result = lookupInfo(Kind);
200 assert(Result != nullptr &&
201 "information for specified comparison category has not been built");
205 /// Return the comparison category information as specified by
206 /// `getCategoryForType(Ty)`. If the information is not already cached,
207 /// the declaration is looked up and a cache entry is created.
208 /// NOTE: Lookup is expected to succeed. Use lookupInfo if failure is
210 const ComparisonCategoryInfo &getInfoForType(QualType Ty) const;
213 /// Return the cached comparison category information for the
214 /// specified 'Kind'. If no cache entry is present the comparison category
215 /// type is looked up. If lookup fails nullptr is returned. Otherwise, a
216 /// new cache entry is created and returned
217 const ComparisonCategoryInfo *lookupInfo(ComparisonCategoryType Kind) const;
219 ComparisonCategoryInfo *lookupInfo(ComparisonCategoryType Kind) {
220 const auto &This = *this;
221 return const_cast<ComparisonCategoryInfo *>(This.lookupInfo(Kind));
225 const ComparisonCategoryInfo *lookupInfoForType(QualType Ty) const;
228 friend class ASTContext;
230 explicit ComparisonCategories(const ASTContext &Ctx) : Ctx(Ctx) {}
232 const ASTContext &Ctx;
234 /// A map from the ComparisonCategoryType (represented as 'char') to the
235 /// cached information for the specified category.
236 mutable llvm::DenseMap<char, ComparisonCategoryInfo> Data;
237 mutable NamespaceDecl *StdNS = nullptr;