Mercurial > hg > CbC > CbC_llvm
diff clang/lib/AST/ComparisonCategories.cpp @ 150:1d019706d866
LLVM10
author | anatofuz |
---|---|
date | Thu, 13 Feb 2020 15:10:13 +0900 |
parents | |
children | 0572611fdcc8 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/clang/lib/AST/ComparisonCategories.cpp Thu Feb 13 15:10:13 2020 +0900 @@ -0,0 +1,213 @@ +//===- ComparisonCategories.cpp - Three Way Comparison Data -----*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines the Comparison Category enum and data types, which +// store the types and expressions needed to support operator<=> +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/ComparisonCategories.h" +#include "clang/AST/Decl.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/Type.h" +#include "llvm/ADT/SmallVector.h" + +using namespace clang; + +Optional<ComparisonCategoryType> +clang::getComparisonCategoryForBuiltinCmp(QualType T) { + using CCT = ComparisonCategoryType; + + if (T->isIntegralOrEnumerationType()) + return CCT::StrongOrdering; + + if (T->isRealFloatingType()) + return CCT::PartialOrdering; + + // C++2a [expr.spaceship]p8: If the composite pointer type is an object + // pointer type, p <=> q is of type std::strong_ordering. + // Note: this assumes neither operand is a null pointer constant. + if (T->isObjectPointerType()) + return CCT::StrongOrdering; + + // TODO: Extend support for operator<=> to ObjC types. + return llvm::None; +} + +bool ComparisonCategoryInfo::ValueInfo::hasValidIntValue() const { + assert(VD && "must have var decl"); + if (!VD->checkInitIsICE()) + return false; + + // Before we attempt to get the value of the first field, ensure that we + // actually have one (and only one) field. + auto *Record = VD->getType()->getAsCXXRecordDecl(); + if (std::distance(Record->field_begin(), Record->field_end()) != 1 || + !Record->field_begin()->getType()->isIntegralOrEnumerationType()) + return false; + + return true; +} + +/// Attempt to determine the integer value used to represent the comparison +/// category result by evaluating the initializer for the specified VarDecl as +/// a constant expression and retreiving the value of the class's first +/// (and only) field. +/// +/// Note: The STL types are expected to have the form: +/// struct X { T value; }; +/// where T is an integral or enumeration type. +llvm::APSInt ComparisonCategoryInfo::ValueInfo::getIntValue() const { + assert(hasValidIntValue() && "must have a valid value"); + return VD->evaluateValue()->getStructField(0).getInt(); +} + +ComparisonCategoryInfo::ValueInfo *ComparisonCategoryInfo::lookupValueInfo( + ComparisonCategoryResult ValueKind) const { + // Check if we already have a cache entry for this value. + auto It = llvm::find_if( + Objects, [&](ValueInfo const &Info) { return Info.Kind == ValueKind; }); + if (It != Objects.end()) + return &(*It); + + // We don't have a cached result. Lookup the variable declaration and create + // a new entry representing it. + DeclContextLookupResult Lookup = Record->getCanonicalDecl()->lookup( + &Ctx.Idents.get(ComparisonCategories::getResultString(ValueKind))); + if (Lookup.empty() || !isa<VarDecl>(Lookup.front())) + return nullptr; + Objects.emplace_back(ValueKind, cast<VarDecl>(Lookup.front())); + return &Objects.back(); +} + +static const NamespaceDecl *lookupStdNamespace(const ASTContext &Ctx, + NamespaceDecl *&StdNS) { + if (!StdNS) { + DeclContextLookupResult Lookup = + Ctx.getTranslationUnitDecl()->lookup(&Ctx.Idents.get("std")); + if (!Lookup.empty()) + StdNS = dyn_cast<NamespaceDecl>(Lookup.front()); + } + return StdNS; +} + +static CXXRecordDecl *lookupCXXRecordDecl(const ASTContext &Ctx, + const NamespaceDecl *StdNS, + ComparisonCategoryType Kind) { + StringRef Name = ComparisonCategories::getCategoryString(Kind); + DeclContextLookupResult Lookup = StdNS->lookup(&Ctx.Idents.get(Name)); + if (!Lookup.empty()) + if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(Lookup.front())) + return RD; + return nullptr; +} + +const ComparisonCategoryInfo * +ComparisonCategories::lookupInfo(ComparisonCategoryType Kind) const { + auto It = Data.find(static_cast<char>(Kind)); + if (It != Data.end()) + return &It->second; + + if (const NamespaceDecl *NS = lookupStdNamespace(Ctx, StdNS)) + if (CXXRecordDecl *RD = lookupCXXRecordDecl(Ctx, NS, Kind)) + return &Data.try_emplace((char)Kind, Ctx, RD, Kind).first->second; + + return nullptr; +} + +const ComparisonCategoryInfo * +ComparisonCategories::lookupInfoForType(QualType Ty) const { + assert(!Ty.isNull() && "type must be non-null"); + using CCT = ComparisonCategoryType; + auto *RD = Ty->getAsCXXRecordDecl(); + if (!RD) + return nullptr; + + // Check to see if we have information for the specified type cached. + const auto *CanonRD = RD->getCanonicalDecl(); + for (auto &KV : Data) { + const ComparisonCategoryInfo &Info = KV.second; + if (CanonRD == Info.Record->getCanonicalDecl()) + return &Info; + } + + if (!RD->getEnclosingNamespaceContext()->isStdNamespace()) + return nullptr; + + // If not, check to see if the decl names a type in namespace std with a name + // matching one of the comparison category types. + for (unsigned I = static_cast<unsigned>(CCT::First), + End = static_cast<unsigned>(CCT::Last); + I <= End; ++I) { + CCT Kind = static_cast<CCT>(I); + + // We've found the comparison category type. Build a new cache entry for + // it. + if (getCategoryString(Kind) == RD->getName()) + return &Data.try_emplace((char)Kind, Ctx, RD, Kind).first->second; + } + + // We've found nothing. This isn't a comparison category type. + return nullptr; +} + +const ComparisonCategoryInfo &ComparisonCategories::getInfoForType(QualType Ty) const { + const ComparisonCategoryInfo *Info = lookupInfoForType(Ty); + assert(Info && "info for comparison category not found"); + return *Info; +} + +QualType ComparisonCategoryInfo::getType() const { + assert(Record); + return QualType(Record->getTypeForDecl(), 0); +} + +StringRef ComparisonCategories::getCategoryString(ComparisonCategoryType Kind) { + using CCKT = ComparisonCategoryType; + switch (Kind) { + case CCKT::PartialOrdering: + return "partial_ordering"; + case CCKT::WeakOrdering: + return "weak_ordering"; + case CCKT::StrongOrdering: + return "strong_ordering"; + } + llvm_unreachable("unhandled cases in switch"); +} + +StringRef ComparisonCategories::getResultString(ComparisonCategoryResult Kind) { + using CCVT = ComparisonCategoryResult; + switch (Kind) { + case CCVT::Equal: + return "equal"; + case CCVT::Equivalent: + return "equivalent"; + case CCVT::Less: + return "less"; + case CCVT::Greater: + return "greater"; + case CCVT::Unordered: + return "unordered"; + } + llvm_unreachable("unhandled case in switch"); +} + +std::vector<ComparisonCategoryResult> +ComparisonCategories::getPossibleResultsForType(ComparisonCategoryType Type) { + using CCT = ComparisonCategoryType; + using CCR = ComparisonCategoryResult; + std::vector<CCR> Values; + Values.reserve(4); + bool IsStrong = Type == CCT::StrongOrdering; + Values.push_back(IsStrong ? CCR::Equal : CCR::Equivalent); + Values.push_back(CCR::Less); + Values.push_back(CCR::Greater); + if (Type == CCT::PartialOrdering) + Values.push_back(CCR::Unordered); + return Values; +}