ComparisonCategories.h 7.6 KB

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