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 |