Skip to content

Commit

Permalink
[c++20] P0515R3: Parsing support and basic AST construction for opera…
Browse files Browse the repository at this point in the history
…tor <=>.

Adding the new enumerator forced a bunch more changes into this patch than I
would have liked. The -Wtautological-compare warning was extended to properly
check the new comparison operator, clang-format needed updating because it uses
precedence levels as weights for determining where to break lines (and several
operators increased their precedence levels with this change), thread-safety
analysis needed changes to build its own IL properly for the new operator.

All "real" semantic checking for this operator has been deferred to a future
patch. For now, we use the relational comparison rules and arbitrarily give
the builtin form of the operator a return type of 'void'.

llvm-svn: 320707
  • Loading branch information
zygoloid committed Dec 14, 2017
1 parent ee27d2e commit c70f1d6
Show file tree
Hide file tree
Showing 33 changed files with 366 additions and 52 deletions.
2 changes: 1 addition & 1 deletion clang/include/clang/AST/Expr.h
Original file line number Diff line number Diff line change
Expand Up @@ -3072,7 +3072,7 @@ class BinaryOperator : public Expr {
static bool isEqualityOp(Opcode Opc) { return Opc == BO_EQ || Opc == BO_NE; }
bool isEqualityOp() const { return isEqualityOp(getOpcode()); }

static bool isComparisonOp(Opcode Opc) { return Opc >= BO_LT && Opc<=BO_NE; }
static bool isComparisonOp(Opcode Opc) { return Opc >= BO_Cmp && Opc<=BO_NE; }
bool isComparisonOp() const { return isComparisonOp(getOpcode()); }

static Opcode negateComparisonOp(Opcode Opc) {
Expand Down
8 changes: 6 additions & 2 deletions clang/include/clang/AST/OperationKinds.def
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,8 @@ CAST_OPERATION(IntToOCLSampler)

//===- Binary Operations -------------------------------------------------===//
// Operators listed in order of precedence.
// Note that additions to this should also update the StmtVisitor class.
// Note that additions to this should also update the StmtVisitor class and
// BinaryOperator::getOverloadedOperator.

// [C++ 5.5] Pointer-to-member operators.
BINARY_OPERATION(PtrMemD, ".*")
Expand All @@ -347,6 +348,8 @@ BINARY_OPERATION(Sub, "-")
// [C99 6.5.7] Bitwise shift operators.
BINARY_OPERATION(Shl, "<<")
BINARY_OPERATION(Shr, ">>")
// C++20 [expr.spaceship] Three-way comparison operator.
BINARY_OPERATION(Cmp, "<=>")
// [C99 6.5.8] Relational operators.
BINARY_OPERATION(LT, "<")
BINARY_OPERATION(GT, ">")
Expand Down Expand Up @@ -382,7 +385,8 @@ BINARY_OPERATION(Comma, ",")


//===- Unary Operations ---------------------------------------------------===//
// Note that additions to this should also update the StmtVisitor class.
// Note that additions to this should also update the StmtVisitor class and
// UnaryOperator::getOverloadedOperator.

// [C99 6.5.2.4] Postfix increment and decrement
UNARY_OPERATION(PostInc, "++")
Expand Down
4 changes: 2 additions & 2 deletions clang/include/clang/AST/RecursiveASTVisitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,8 @@
OPERATOR(PtrMemD) OPERATOR(PtrMemI) OPERATOR(Mul) OPERATOR(Div) \
OPERATOR(Rem) OPERATOR(Add) OPERATOR(Sub) OPERATOR(Shl) OPERATOR(Shr) \
OPERATOR(LT) OPERATOR(GT) OPERATOR(LE) OPERATOR(GE) OPERATOR(EQ) \
OPERATOR(NE) OPERATOR(And) OPERATOR(Xor) OPERATOR(Or) OPERATOR(LAnd) \
OPERATOR(LOr) OPERATOR(Assign) OPERATOR(Comma)
OPERATOR(NE) OPERATOR(Cmp) OPERATOR(And) OPERATOR(Xor) OPERATOR(Or) \
OPERATOR(LAnd) OPERATOR(LOr) OPERATOR(Assign) OPERATOR(Comma)

// All compound assign operators.
#define CAO_LIST() \
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/AST/StmtVisitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ class StmtVisitorBase {
case BO_GE: DISPATCH(BinGE, BinaryOperator);
case BO_EQ: DISPATCH(BinEQ, BinaryOperator);
case BO_NE: DISPATCH(BinNE, BinaryOperator);
case BO_Cmp: DISPATCH(BinCmp, BinaryOperator);

case BO_And: DISPATCH(BinAnd, BinaryOperator);
case BO_Xor: DISPATCH(BinXor, BinaryOperator);
Expand Down Expand Up @@ -132,6 +133,8 @@ class StmtVisitorBase {

BINOP_FALLBACK(LT) BINOP_FALLBACK(GT) BINOP_FALLBACK(LE)
BINOP_FALLBACK(GE) BINOP_FALLBACK(EQ) BINOP_FALLBACK(NE)
BINOP_FALLBACK(Cmp)

BINOP_FALLBACK(And) BINOP_FALLBACK(Xor) BINOP_FALLBACK(Or)
BINOP_FALLBACK(LAnd) BINOP_FALLBACK(LOr)

Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Analysis/Analyses/ThreadSafetyTIL.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ enum TIL_BinaryOpcode : unsigned char {
BOP_Neq, // !=
BOP_Lt, // <
BOP_Leq, // <=
BOP_Cmp, // <=>
BOP_LogicAnd, // && (no short-circuit)
BOP_LogicOr // || (no short-circuit)
};
Expand Down
20 changes: 10 additions & 10 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -5937,25 +5937,25 @@ def note_typecheck_assign_const : Note<
"%select{|nested }1data member %2 declared const here}0">;

def warn_unsigned_always_true_comparison : Warning<
"comparison of %select{%3|unsigned expression}0 %2 "
"%select{unsigned expression|%3}0 is always %select{false|true}4">,
"result of comparison of %select{%3|unsigned expression}0 %2 "
"%select{unsigned expression|%3}0 is always %4">,
InGroup<TautologicalUnsignedZeroCompare>;
def warn_unsigned_enum_always_true_comparison : Warning<
"comparison of %select{%3|unsigned enum expression}0 %2 "
"%select{unsigned enum expression|%3}0 is always %select{false|true}4">,
"result of comparison of %select{%3|unsigned enum expression}0 %2 "
"%select{unsigned enum expression|%3}0 is always %4">,
InGroup<TautologicalUnsignedEnumZeroCompare>;
def warn_tautological_constant_compare : Warning<
"comparison %select{%3|%1}0 %2 "
"%select{%1|%3}0 is always %select{false|true}4">,
"result of comparison %select{%3|%1}0 %2 "
"%select{%1|%3}0 is always %4">,
InGroup<TautologicalConstantCompare>;

def warn_mixed_sign_comparison : Warning<
"comparison of integers of different signs: %0 and %1">,
InGroup<SignCompare>, DefaultIgnore;
def warn_out_of_range_compare : Warning<
"comparison of %select{constant %0|true|false}1 with "
"%select{expression of type %2|boolean expression}3 is always "
"%select{false|true}4">, InGroup<TautologicalOutOfRangeCompare>;
"result of comparison of %select{constant %0|true|false}1 with "
"%select{expression of type %2|boolean expression}3 is always %4">,
InGroup<TautologicalOutOfRangeCompare>;
def warn_tautological_bool_compare : Warning<warn_out_of_range_compare.Text>,
InGroup<TautologicalConstantCompare>;
def warn_comparison_of_mixed_enum_types : Warning<
Expand Down Expand Up @@ -7289,7 +7289,7 @@ def ext_cxx17_attr : Extension<
"use of the %0 attribute is a C++17 extension">, InGroup<CXX17>;

def warn_unused_comparison : Warning<
"%select{%select{|in}1equality|relational}0 comparison result unused">,
"%select{equality|inequality|relational|three-way}0 comparison result unused">,
InGroup<UnusedComparison>;
def note_inequality_comparison_to_or_assign : Note<
"use '|=' to turn this inequality comparison into an or-assignment">;
Expand Down
9 changes: 5 additions & 4 deletions clang/include/clang/Basic/OperatorPrecedence.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,11 @@ namespace prec {
And = 8, // &
Equality = 9, // ==, !=
Relational = 10, // >=, <=, >, <
Shift = 11, // <<, >>
Additive = 12, // -, +
Multiplicative = 13, // *, /, %
PointerToMember = 14 // .*, ->*
Spaceship = 11, // <=>
Shift = 12, // <<, >>
Additive = 13, // -, +
Multiplicative = 14, // *, /, %
PointerToMember = 15 // .*, ->*
};
}

Expand Down
2 changes: 2 additions & 0 deletions clang/lib/AST/Expr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1780,6 +1780,7 @@ BinaryOperator::getOverloadedOpcode(OverloadedOperatorKind OO) {
case OO_Amp: return BO_And;
case OO_Pipe: return BO_Or;
case OO_Equal: return BO_Assign;
case OO_Spaceship: return BO_Cmp;
case OO_Less: return BO_LT;
case OO_Greater: return BO_GT;
case OO_PlusEqual: return BO_AddAssign;
Expand Down Expand Up @@ -1811,6 +1812,7 @@ OverloadedOperatorKind BinaryOperator::getOverloadedOperator(Opcode Opc) {
OO_Star, OO_Slash, OO_Percent,
OO_Plus, OO_Minus,
OO_LessLess, OO_GreaterGreater,
OO_Spaceship,
OO_Less, OO_Greater, OO_LessEqual, OO_GreaterEqual,
OO_EqualEqual, OO_ExclaimEqual,
OO_Amp,
Expand Down
1 change: 1 addition & 0 deletions clang/lib/AST/ExprConstant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10471,6 +10471,7 @@ static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) {
case BO_AndAssign:
case BO_XorAssign:
case BO_OrAssign:
case BO_Cmp: // FIXME: Re-enable once we can evaluate this.
// C99 6.6/3 allows assignments within unevaluated subexpressions of
// constant expressions, but they can never be ICEs because an ICE cannot
// contain an lvalue operand.
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Analysis/ThreadSafetyCommon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -505,6 +505,7 @@ til::SExpr *SExprBuilder::translateBinaryOperator(const BinaryOperator *BO,
case BO_GE: return translateBinOp(til::BOP_Leq, BO, Ctx, true);
case BO_EQ: return translateBinOp(til::BOP_Eq, BO, Ctx);
case BO_NE: return translateBinOp(til::BOP_Neq, BO, Ctx);
case BO_Cmp: return translateBinOp(til::BOP_Cmp, BO, Ctx);
case BO_And: return translateBinOp(til::BOP_BitAnd, BO, Ctx);
case BO_Xor: return translateBinOp(til::BOP_BitXor, BO, Ctx);
case BO_Or: return translateBinOp(til::BOP_BitOr, BO, Ctx);
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Analysis/ThreadSafetyTIL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ StringRef til::getBinaryOpcodeString(TIL_BinaryOpcode Op) {
case BOP_Neq: return "!=";
case BOP_Lt: return "<";
case BOP_Leq: return "<=";
case BOP_Cmp: return "<=>";
case BOP_LogicAnd: return "&&";
case BOP_LogicOr: return "||";
}
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Basic/OperatorPrecedence.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ prec::Level getBinOpPrecedence(tok::TokenKind Kind, bool GreaterThanIsOperator,
case tok::lessequal:
case tok::less:
case tok::greaterequal: return prec::Relational;
case tok::spaceship: return prec::Spaceship;
case tok::lessless: return prec::Shift;
case tok::plus:
case tok::minus: return prec::Additive;
Expand Down
1 change: 1 addition & 0 deletions clang/lib/CodeGen/CGExprScalar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3922,6 +3922,7 @@ LValue CodeGenFunction::EmitCompoundAssignmentLValue(
case BO_GE:
case BO_EQ:
case BO_NE:
case BO_Cmp:
case BO_And:
case BO_Xor:
case BO_Or:
Expand Down
1 change: 1 addition & 0 deletions clang/lib/CodeGen/CGStmtOpenMP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3408,6 +3408,7 @@ static std::pair<bool, RValue> emitOMPAtomicRMW(CodeGenFunction &CGF, LValue X,
case BO_GE:
case BO_EQ:
case BO_NE:
case BO_Cmp:
case BO_AddAssign:
case BO_SubAssign:
case BO_AndAssign:
Expand Down
6 changes: 4 additions & 2 deletions clang/lib/Format/ContinuationIndenter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,8 @@ bool ContinuationIndenter::mustBreak(const LineState &State) {
// We need special cases for ">>" which we have split into two ">" while
// lexing in order to make template parsing easier.
bool IsComparison = (Previous.getPrecedence() == prec::Relational ||
Previous.getPrecedence() == prec::Equality) &&
Previous.getPrecedence() == prec::Equality ||
Previous.getPrecedence() == prec::Spaceship) &&
Previous.Previous &&
Previous.Previous->isNot(TT_BinaryOperator); // For >>.
bool LHSIsBinaryExpr =
Expand Down Expand Up @@ -536,7 +537,8 @@ void ContinuationIndenter::addTokenOnCurrentLine(LineState &State, bool DryRun,
(P->is(TT_ConditionalExpr) && P->is(tok::colon))) &&
!P->isOneOf(TT_OverloadedOperator, TT_CtorInitializerComma) &&
P->getPrecedence() != prec::Assignment &&
P->getPrecedence() != prec::Relational) {
P->getPrecedence() != prec::Relational &&
P->getPrecedence() != prec::Spaceship) {
bool BreakBeforeOperator =
P->MustBreakBefore || P->is(tok::lessless) ||
(P->is(TT_BinaryOperator) &&
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Format/Format.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2074,6 +2074,7 @@ LangOptions getFormattingLangOpts(const FormatStyle &Style) {
LangOpts.CPlusPlus11 = Style.Standard == FormatStyle::LS_Cpp03 ? 0 : 1;
LangOpts.CPlusPlus14 = Style.Standard == FormatStyle::LS_Cpp03 ? 0 : 1;
LangOpts.CPlusPlus17 = Style.Standard == FormatStyle::LS_Cpp03 ? 0 : 1;
LangOpts.CPlusPlus2a = Style.Standard == FormatStyle::LS_Cpp03 ? 0 : 1;
LangOpts.LineComment = 1;
bool AlternativeOperators = Style.isCpp();
LangOpts.CXXOperatorNames = AlternativeOperators ? 1 : 0;
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Format/TokenAnnotator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2153,7 +2153,7 @@ unsigned TokenAnnotator::splitPenalty(const AnnotatedLine &Line,
if (Left.isOneOf(tok::plus, tok::comma) && Left.Previous &&
Left.Previous->isLabelString() &&
(Left.NextOperator || Left.OperatorIndex != 0))
return 45;
return 50;
if (Right.is(tok::plus) && Left.isLabelString() &&
(Right.NextOperator || Right.OperatorIndex != 0))
return 25;
Expand Down
17 changes: 11 additions & 6 deletions clang/lib/Parse/ParseExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,12 +66,16 @@ using namespace clang;
/// shift-expression '<<' additive-expression
/// shift-expression '>>' additive-expression
///
/// relational-expression: [C99 6.5.8]
/// compare-expression: [C++20 expr.spaceship]
/// shift-expression
/// relational-expression '<' shift-expression
/// relational-expression '>' shift-expression
/// relational-expression '<=' shift-expression
/// relational-expression '>=' shift-expression
/// compare-expression '<=>' shift-expression
///
/// relational-expression: [C99 6.5.8]
/// compare-expression
/// relational-expression '<' compare-expression
/// relational-expression '>' compare-expression
/// relational-expression '<=' compare-expression
/// relational-expression '>=' compare-expression
///
/// equality-expression: [C99 6.5.9]
/// relational-expression
Expand Down Expand Up @@ -267,7 +271,8 @@ bool Parser::diagnoseUnknownTemplateId(ExprResult LHS, SourceLocation Less) {
}

bool Parser::isFoldOperator(prec::Level Level) const {
return Level > prec::Unknown && Level != prec::Conditional;
return Level > prec::Unknown && Level != prec::Conditional &&
Level != prec::Spaceship;
}

bool Parser::isFoldOperator(tok::TokenKind Kind) const {
Expand Down
25 changes: 18 additions & 7 deletions clang/lib/Sema/SemaChecking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7279,8 +7279,8 @@ static bool CheckMemorySizeofForComparison(Sema &S, const Expr *E,
if (!Size)
return false;

// if E is binop and op is >, <, >=, <=, ==, &&, ||:
if (!Size->isComparisonOp() && !Size->isEqualityOp() && !Size->isLogicalOp())
// if E is binop and op is <=>, >, <, >=, <=, ==, &&, ||:
if (!Size->isComparisonOp() && !Size->isLogicalOp())
return false;

SourceRange SizeRange = Size->getSourceRange();
Expand Down Expand Up @@ -8433,6 +8433,8 @@ static IntRange GetExprRange(ASTContext &C, const Expr *E, unsigned MaxWidth) {

if (const auto *BO = dyn_cast<BinaryOperator>(E)) {
switch (BO->getOpcode()) {
case BO_Cmp:
llvm_unreachable("builtin <=> should have class type");

// Boolean-valued operations are single-bit and positive.
case BO_LAnd:
Expand Down Expand Up @@ -8747,9 +8749,18 @@ struct PromotedRange {
llvm_unreachable("impossible compare result");
}

static llvm::Optional<bool> constantValue(BinaryOperatorKind Op,
ComparisonResult R,
bool ConstantOnRHS) {
static llvm::Optional<StringRef>
constantValue(BinaryOperatorKind Op, ComparisonResult R, bool ConstantOnRHS) {
if (Op == BO_Cmp) {
ComparisonResult LTFlag = LT, GTFlag = GT;
if (ConstantOnRHS) std::swap(LTFlag, GTFlag);

if (R & EQ) return StringRef("'std::strong_ordering::equal'");
if (R & LTFlag) return StringRef("'std::strong_ordering::less'");
if (R & GTFlag) return StringRef("'std::strong_ordering::greater'");
return llvm::None;
}

ComparisonResult TrueFlag, FalseFlag;
if (Op == BO_EQ) {
TrueFlag = EQ;
Expand All @@ -8769,9 +8780,9 @@ struct PromotedRange {
std::swap(TrueFlag, FalseFlag);
}
if (R & TrueFlag)
return true;
return StringRef("true");
if (R & FalseFlag)
return false;
return StringRef("false");
return llvm::None;
}
};
Expand Down
8 changes: 8 additions & 0 deletions clang/lib/Sema/SemaExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11375,6 +11375,7 @@ BinaryOperatorKind Sema::ConvertTokenKindToBinaryOpcode(tok::TokenKind Kind) {
case tok::greater: Opc = BO_GT; break;
case tok::exclaimequal: Opc = BO_NE; break;
case tok::equalequal: Opc = BO_EQ; break;
case tok::spaceship: Opc = BO_Cmp; break;
case tok::amp: Opc = BO_And; break;
case tok::caret: Opc = BO_Xor; break;
case tok::pipe: Opc = BO_Or; break;
Expand Down Expand Up @@ -11683,6 +11684,13 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
ConvertHalfVec = true;
ResultTy = CheckCompareOperands(LHS, RHS, OpLoc, Opc, false);
break;
case BO_Cmp:
// FIXME: Implement proper semantic checking of '<=>'.
ConvertHalfVec = true;
ResultTy = CheckCompareOperands(LHS, RHS, OpLoc, Opc, true);
if (!ResultTy.isNull())
ResultTy = Context.VoidTy;
break;
case BO_And:
checkObjCPointerIntrospection(*this, LHS, RHS, OpLoc);
LLVM_FALLTHROUGH;
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Sema/SemaOpenMP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10343,6 +10343,7 @@ static bool ActOnOMPReductionKindClause(
case BO_GE:
case BO_EQ:
case BO_NE:
case BO_Cmp:
case BO_AndAssign:
case BO_XorAssign:
case BO_OrAssign:
Expand Down
Loading

0 comments on commit c70f1d6

Please sign in to comment.