Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[C++2a] Implement operator<=> CodeGen and ExprConstant
Summary: This patch tackles long hanging fruit for the builtin operator<=> expressions. It is currently needs some cleanup before landing, but I want to get some initial feedback. The main changes are: * Lookup, build, and store the required standard library types and expressions in `ASTContext`. By storing them in ASTContext we don't need to store (and duplicate) the required expressions in the BinaryOperator AST nodes. * Implement [expr.spaceship] checking, including diagnosing narrowing conversions. * Implement `ExprConstant` for builtin spaceship operators. * Implement builitin operator<=> support in `CodeGenAgg`. Initially I emitted the required comparisons using `ScalarExprEmitter::VisitBinaryOperator`, but this caused the operand expressions to be emitted once for every required cmp. * Implement [builtin.over] with modifications to support the intent of P0946R0. See the note on `BuiltinOperatorOverloadBuilder::addThreeWayArithmeticOverloads` for more information about the workaround. Reviewers: rsmith, aaron.ballman, majnemer, rnk, compnerd, rjmccall Reviewed By: rjmccall Subscribers: rjmccall, rsmith, aaron.ballman, junbuml, mgorny, cfe-commits Differential Revision: https://reviews.llvm.org/D45476 llvm-svn: 331677
- Loading branch information
Showing
24 changed files
with
3,548 additions
and
392 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,255 @@ | ||
//===- ComparisonCategories.h - Three Way Comparison Data -------*- C++ -*-===// | ||
// | ||
// The LLVM Compiler Infrastructure | ||
// | ||
// This file is distributed under the University of Illinois Open Source | ||
// License. See LICENSE.TXT for details. | ||
// | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// This file defines the Comparison Category enum and data types, which | ||
// store the types and expressions needed to support operator<=> | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#ifndef LLVM_CLANG_AST_COMPARISONCATEGORIES_H | ||
#define LLVM_CLANG_AST_COMPARISONCATEGORIES_H | ||
|
||
#include "clang/Basic/LLVM.h" | ||
#include "llvm/ADT/APSInt.h" | ||
#include "llvm/ADT/DenseMap.h" | ||
#include <array> | ||
#include <cassert> | ||
|
||
namespace llvm { | ||
class StringRef; | ||
class APSInt; | ||
} | ||
|
||
namespace clang { | ||
|
||
class ASTContext; | ||
class VarDecl; | ||
class CXXRecordDecl; | ||
class Sema; | ||
class QualType; | ||
class NamespaceDecl; | ||
|
||
/// \brief An enumeration representing the different comparison categories | ||
/// types. | ||
/// | ||
/// C++2a [cmp.categories.pre] The types weak_equality, strong_equality, | ||
/// partial_ordering, weak_ordering, and strong_ordering are collectively | ||
/// termed the comparison category types. | ||
enum class ComparisonCategoryType : unsigned char { | ||
WeakEquality, | ||
StrongEquality, | ||
PartialOrdering, | ||
WeakOrdering, | ||
StrongOrdering, | ||
First = WeakEquality, | ||
Last = StrongOrdering | ||
}; | ||
|
||
/// \brief An enumeration representing the possible results of a three-way | ||
/// comparison. These values map onto instances of comparison category types | ||
/// defined in the standard library. i.e. 'std::strong_ordering::less'. | ||
enum class ComparisonCategoryResult : unsigned char { | ||
Equal, | ||
Equivalent, | ||
Nonequivalent, | ||
Nonequal, | ||
Less, | ||
Greater, | ||
Unordered, | ||
Last = Unordered | ||
}; | ||
|
||
class ComparisonCategoryInfo { | ||
friend class ComparisonCategories; | ||
friend class Sema; | ||
|
||
public: | ||
ComparisonCategoryInfo(const ASTContext &Ctx, CXXRecordDecl *RD, | ||
ComparisonCategoryType Kind) | ||
: Ctx(Ctx), Record(RD), Kind(Kind) {} | ||
|
||
struct ValueInfo { | ||
ComparisonCategoryResult Kind; | ||
VarDecl *VD; | ||
|
||
ValueInfo(ComparisonCategoryResult Kind, VarDecl *VD) | ||
: Kind(Kind), VD(VD), HasValue(false) {} | ||
|
||
/// \brief True iff we've successfully evaluated the variable as a constant | ||
/// expression and extracted its integer value. | ||
bool hasValidIntValue() const { return HasValue; } | ||
|
||
/// \brief Get the constant integer value used by this variable to represent | ||
/// the comparison category result type. | ||
llvm::APSInt getIntValue() const { | ||
assert(hasValidIntValue()); | ||
return IntValue; | ||
} | ||
|
||
void setIntValue(llvm::APSInt Val) { | ||
IntValue = Val; | ||
HasValue = true; | ||
} | ||
|
||
private: | ||
friend class ComparisonCategoryInfo; | ||
llvm::APSInt IntValue; | ||
bool HasValue : 1; | ||
}; | ||
private: | ||
const ASTContext &Ctx; | ||
|
||
/// \brief A map containing the comparison category result decls from the | ||
/// standard library. The key is a value of ComparisonCategoryResult. | ||
mutable llvm::SmallVector< | ||
ValueInfo, static_cast<unsigned>(ComparisonCategoryResult::Last) + 1> | ||
Objects; | ||
|
||
/// \brief Lookup the ValueInfo struct for the specified ValueKind. If the | ||
/// VarDecl for the value cannot be found, nullptr is returned. | ||
/// | ||
/// If the ValueInfo does not have a valid integer value the variable | ||
/// is evaluated as a constant expression to determine that value. | ||
ValueInfo *lookupValueInfo(ComparisonCategoryResult ValueKind) const; | ||
|
||
public: | ||
/// \brief The declaration for the comparison category type from the | ||
/// standard library. | ||
// FIXME: Make this const | ||
CXXRecordDecl *Record = nullptr; | ||
|
||
/// \brief The Kind of the comparison category type | ||
ComparisonCategoryType Kind; | ||
|
||
public: | ||
QualType getType() const; | ||
|
||
const ValueInfo *getValueInfo(ComparisonCategoryResult ValueKind) const { | ||
ValueInfo *Info = lookupValueInfo(ValueKind); | ||
assert(Info && | ||
"comparison category does not contain the specified result kind"); | ||
assert(Info->hasValidIntValue() && | ||
"couldn't determine the integer constant for this value"); | ||
return Info; | ||
} | ||
|
||
/// \brief True iff the comparison category is an equality comparison. | ||
bool isEquality() const { return !isOrdered(); } | ||
|
||
/// \brief True iff the comparison category is a relational comparison. | ||
bool isOrdered() const { | ||
using CCK = ComparisonCategoryType; | ||
return Kind == CCK::PartialOrdering || Kind == CCK::WeakOrdering || | ||
Kind == CCK::StrongOrdering; | ||
} | ||
|
||
/// \brief True iff the comparison is "strong". i.e. it checks equality and | ||
/// not equivalence. | ||
bool isStrong() const { | ||
using CCK = ComparisonCategoryType; | ||
return Kind == CCK::StrongEquality || Kind == CCK::StrongOrdering; | ||
} | ||
|
||
/// \brief True iff the comparison is not totally ordered. | ||
bool isPartial() const { | ||
using CCK = ComparisonCategoryType; | ||
return Kind == CCK::PartialOrdering; | ||
} | ||
|
||
/// \brief Converts the specified result kind into the the correct result kind | ||
/// for this category. Specifically it lowers strong equality results to | ||
/// weak equivalence if needed. | ||
ComparisonCategoryResult makeWeakResult(ComparisonCategoryResult Res) const { | ||
using CCR = ComparisonCategoryResult; | ||
if (!isStrong()) { | ||
if (Res == CCR::Equal) | ||
return CCR::Equivalent; | ||
if (Res == CCR::Nonequal) | ||
return CCR::Nonequivalent; | ||
} | ||
return Res; | ||
} | ||
|
||
const ValueInfo *getEqualOrEquiv() const { | ||
return getValueInfo(makeWeakResult(ComparisonCategoryResult::Equal)); | ||
} | ||
const ValueInfo *getNonequalOrNonequiv() const { | ||
assert(isEquality()); | ||
return getValueInfo(makeWeakResult(ComparisonCategoryResult::Nonequal)); | ||
} | ||
const ValueInfo *getLess() const { | ||
assert(isOrdered()); | ||
return getValueInfo(ComparisonCategoryResult::Less); | ||
} | ||
const ValueInfo *getGreater() const { | ||
assert(isOrdered()); | ||
return getValueInfo(ComparisonCategoryResult::Greater); | ||
} | ||
const ValueInfo *getUnordered() const { | ||
assert(isPartial()); | ||
return getValueInfo(ComparisonCategoryResult::Unordered); | ||
} | ||
}; | ||
|
||
class ComparisonCategories { | ||
public: | ||
static StringRef getCategoryString(ComparisonCategoryType Kind); | ||
static StringRef getResultString(ComparisonCategoryResult Kind); | ||
|
||
/// \brief Return the list of results which are valid for the specified | ||
/// comparison category type. | ||
static std::vector<ComparisonCategoryResult> | ||
getPossibleResultsForType(ComparisonCategoryType Type); | ||
|
||
/// \brief Return the comparison category information for the category | ||
/// specified by 'Kind'. | ||
const ComparisonCategoryInfo &getInfo(ComparisonCategoryType Kind) const { | ||
const ComparisonCategoryInfo *Result = lookupInfo(Kind); | ||
assert(Result != nullptr && | ||
"information for specified comparison category has not been built"); | ||
return *Result; | ||
} | ||
|
||
/// \brief Return the comparison category information as specified by | ||
/// `getCategoryForType(Ty)`. If the information is not already cached, | ||
/// the declaration is looked up and a cache entry is created. | ||
/// NOTE: Lookup is expected to succeed. Use lookupInfo if failure is possible. | ||
const ComparisonCategoryInfo &getInfoForType(QualType Ty) const; | ||
|
||
public: | ||
/// \brief Return the cached comparison category information for the | ||
/// specified 'Kind'. If no cache entry is present the comparison category | ||
/// type is looked up. If lookup fails nullptr is returned. Otherwise, a | ||
/// new cache entry is created and returned | ||
const ComparisonCategoryInfo *lookupInfo(ComparisonCategoryType Kind) const; | ||
|
||
ComparisonCategoryInfo *lookupInfo(ComparisonCategoryType Kind) { | ||
const auto &This = *this; | ||
return const_cast<ComparisonCategoryInfo *>(This.lookupInfo(Kind)); | ||
} | ||
|
||
private: | ||
const ComparisonCategoryInfo *lookupInfoForType(QualType Ty) const; | ||
|
||
private: | ||
friend class ASTContext; | ||
|
||
explicit ComparisonCategories(const ASTContext &Ctx) : Ctx(Ctx) {} | ||
|
||
const ASTContext &Ctx; | ||
|
||
/// A map from the ComparisonCategoryType (represented as 'char') to the | ||
/// cached information for the specified category. | ||
mutable llvm::DenseMap<char, ComparisonCategoryInfo> Data; | ||
mutable NamespaceDecl *StdNS = nullptr; | ||
}; | ||
|
||
} // namespace clang | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.