Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:36:30

0001 //===- ComparisonCategories.h - Three Way Comparison Data -------*- C++ -*-===//
0002 //
0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0004 // See https://llvm.org/LICENSE.txt for license information.
0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0006 //
0007 //===----------------------------------------------------------------------===//
0008 //
0009 //  This file defines the Comparison Category enum and data types, which
0010 //  store the types and expressions needed to support operator<=>
0011 //
0012 //===----------------------------------------------------------------------===//
0013 
0014 #ifndef LLVM_CLANG_AST_COMPARISONCATEGORIES_H
0015 #define LLVM_CLANG_AST_COMPARISONCATEGORIES_H
0016 
0017 #include "clang/Basic/LLVM.h"
0018 #include "llvm/ADT/APSInt.h"
0019 #include "llvm/ADT/DenseMap.h"
0020 #include <array>
0021 #include <cassert>
0022 #include <optional>
0023 #include <vector>
0024 
0025 namespace llvm {
0026   class StringRef;
0027   class APSInt;
0028 }
0029 
0030 namespace clang {
0031 
0032 class ASTContext;
0033 class VarDecl;
0034 class CXXRecordDecl;
0035 class Sema;
0036 class QualType;
0037 class NamespaceDecl;
0038 
0039 /// An enumeration representing the different comparison categories
0040 /// types.
0041 ///
0042 /// C++20 [cmp.categories.pre] The types partial_ordering, weak_ordering, and
0043 /// strong_ordering are collectively termed the comparison category types.
0044 enum class ComparisonCategoryType : unsigned char {
0045   PartialOrdering,
0046   WeakOrdering,
0047   StrongOrdering,
0048   First = PartialOrdering,
0049   Last = StrongOrdering
0050 };
0051 
0052 /// Determine the common comparison type, as defined in C++2a
0053 /// [class.spaceship]p4.
0054 inline ComparisonCategoryType commonComparisonType(ComparisonCategoryType A,
0055                                                    ComparisonCategoryType B) {
0056   return A < B ? A : B;
0057 }
0058 
0059 /// Get the comparison category that should be used when comparing values of
0060 /// type \c T.
0061 std::optional<ComparisonCategoryType>
0062 getComparisonCategoryForBuiltinCmp(QualType T);
0063 
0064 /// An enumeration representing the possible results of a three-way
0065 /// comparison. These values map onto instances of comparison category types
0066 /// defined in the standard library. e.g. 'std::strong_ordering::less'.
0067 enum class ComparisonCategoryResult : unsigned char {
0068   Equal,
0069   Equivalent,
0070   Less,
0071   Greater,
0072   Unordered,
0073   Last = Unordered
0074 };
0075 
0076 class ComparisonCategoryInfo {
0077   friend class ComparisonCategories;
0078   friend class Sema;
0079 
0080 public:
0081   ComparisonCategoryInfo(const ASTContext &Ctx, const CXXRecordDecl *RD,
0082                          ComparisonCategoryType Kind)
0083       : Ctx(Ctx), Record(RD), Kind(Kind) {}
0084 
0085   struct ValueInfo {
0086     ComparisonCategoryResult Kind;
0087     VarDecl *VD;
0088 
0089     ValueInfo(ComparisonCategoryResult Kind, VarDecl *VD)
0090         : Kind(Kind), VD(VD) {}
0091 
0092     /// True iff we've successfully evaluated the variable as a constant
0093     /// expression and extracted its integer value.
0094     bool hasValidIntValue() const;
0095 
0096     /// Get the constant integer value used by this variable to represent
0097     /// the comparison category result type.
0098     llvm::APSInt getIntValue() const;
0099   };
0100 private:
0101   const ASTContext &Ctx;
0102 
0103   /// A map containing the comparison category result decls from the
0104   /// standard library. The key is a value of ComparisonCategoryResult.
0105   mutable llvm::SmallVector<
0106       ValueInfo, static_cast<unsigned>(ComparisonCategoryResult::Last) + 1>
0107       Objects;
0108 
0109   /// Lookup the ValueInfo struct for the specified ValueKind. If the
0110   /// VarDecl for the value cannot be found, nullptr is returned.
0111   ///
0112   /// If the ValueInfo does not have a valid integer value the variable
0113   /// is evaluated as a constant expression to determine that value.
0114   ValueInfo *lookupValueInfo(ComparisonCategoryResult ValueKind) const;
0115 
0116 public:
0117   /// The declaration for the comparison category type from the
0118   /// standard library.
0119   const CXXRecordDecl *Record = nullptr;
0120 
0121   /// The Kind of the comparison category type
0122   ComparisonCategoryType Kind;
0123 
0124 public:
0125   QualType getType() const;
0126 
0127   const ValueInfo *getValueInfo(ComparisonCategoryResult ValueKind) const {
0128     ValueInfo *Info = lookupValueInfo(ValueKind);
0129     assert(Info &&
0130            "comparison category does not contain the specified result kind");
0131     assert(Info->hasValidIntValue() &&
0132            "couldn't determine the integer constant for this value");
0133     return Info;
0134   }
0135 
0136   /// True iff the comparison is "strong". i.e. it checks equality and
0137   /// not equivalence.
0138   bool isStrong() const {
0139     using CCK = ComparisonCategoryType;
0140     return Kind == CCK::StrongOrdering;
0141   }
0142 
0143   /// True iff the comparison is not totally ordered.
0144   bool isPartial() const {
0145     using CCK = ComparisonCategoryType;
0146     return Kind == CCK::PartialOrdering;
0147   }
0148 
0149   /// Converts the specified result kind into the correct result kind
0150   /// for this category. Specifically it lowers strong equality results to
0151   /// weak equivalence if needed.
0152   ComparisonCategoryResult makeWeakResult(ComparisonCategoryResult Res) const {
0153     using CCR = ComparisonCategoryResult;
0154     if (!isStrong() && Res == CCR::Equal)
0155       return CCR::Equivalent;
0156     return Res;
0157   }
0158 
0159   const ValueInfo *getEqualOrEquiv() const {
0160     return getValueInfo(makeWeakResult(ComparisonCategoryResult::Equal));
0161   }
0162   const ValueInfo *getLess() const {
0163     return getValueInfo(ComparisonCategoryResult::Less);
0164   }
0165   const ValueInfo *getGreater() const {
0166     return getValueInfo(ComparisonCategoryResult::Greater);
0167   }
0168   const ValueInfo *getUnordered() const {
0169     assert(isPartial());
0170     return getValueInfo(ComparisonCategoryResult::Unordered);
0171   }
0172 };
0173 
0174 class ComparisonCategories {
0175 public:
0176   static StringRef getCategoryString(ComparisonCategoryType Kind);
0177   static StringRef getResultString(ComparisonCategoryResult Kind);
0178 
0179   /// Return the list of results which are valid for the specified
0180   /// comparison category type.
0181   static std::vector<ComparisonCategoryResult>
0182   getPossibleResultsForType(ComparisonCategoryType Type);
0183 
0184   /// Return the comparison category information for the category
0185   /// specified by 'Kind'.
0186   const ComparisonCategoryInfo &getInfo(ComparisonCategoryType Kind) const {
0187     const ComparisonCategoryInfo *Result = lookupInfo(Kind);
0188     assert(Result != nullptr &&
0189            "information for specified comparison category has not been built");
0190     return *Result;
0191   }
0192 
0193   /// Return the comparison category information as specified by
0194   /// `getCategoryForType(Ty)`. If the information is not already cached,
0195   /// the declaration is looked up and a cache entry is created.
0196   /// NOTE: Lookup is expected to succeed. Use lookupInfo if failure is
0197   /// possible.
0198   const ComparisonCategoryInfo &getInfoForType(QualType Ty) const;
0199 
0200 public:
0201   /// Return the cached comparison category information for the
0202   /// specified 'Kind'. If no cache entry is present the comparison category
0203   /// type is looked up. If lookup fails nullptr is returned. Otherwise, a
0204   /// new cache entry is created and returned
0205   const ComparisonCategoryInfo *lookupInfo(ComparisonCategoryType Kind) const;
0206 
0207   ComparisonCategoryInfo *lookupInfo(ComparisonCategoryType Kind) {
0208     const auto &This = *this;
0209     return const_cast<ComparisonCategoryInfo *>(This.lookupInfo(Kind));
0210   }
0211 
0212   const ComparisonCategoryInfo *lookupInfoForType(QualType Ty) const;
0213 
0214 private:
0215   friend class ASTContext;
0216 
0217   explicit ComparisonCategories(const ASTContext &Ctx) : Ctx(Ctx) {}
0218 
0219   const ASTContext &Ctx;
0220 
0221   /// A map from the ComparisonCategoryType (represented as 'char') to the
0222   /// cached information for the specified category.
0223   mutable llvm::DenseMap<char, ComparisonCategoryInfo> Data;
0224   mutable NamespaceDecl *StdNS = nullptr;
0225 };
0226 
0227 } // namespace clang
0228 
0229 #endif