Author: rsmith Date: Thu Dec 14 07:16:18 2017 New Revision: 320707 URL: http://llvm.org/viewvc/llvm-project?rev=320707&view=rev Log: [c++20] P0515R3: Parsing support and basic AST construction for operator <=>.
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'. Added: cfe/trunk/test/Parser/cxx2a-spaceship.cpp cfe/trunk/test/SemaCXX/compare-cxx2a.cpp cfe/trunk/test/SemaCXX/constant-expression-cxx2a.cpp Modified: cfe/trunk/include/clang/AST/Expr.h cfe/trunk/include/clang/AST/OperationKinds.def cfe/trunk/include/clang/AST/RecursiveASTVisitor.h cfe/trunk/include/clang/AST/StmtVisitor.h cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyTIL.h cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td cfe/trunk/include/clang/Basic/OperatorPrecedence.h cfe/trunk/lib/AST/Expr.cpp cfe/trunk/lib/AST/ExprConstant.cpp cfe/trunk/lib/Analysis/ThreadSafetyCommon.cpp cfe/trunk/lib/Analysis/ThreadSafetyTIL.cpp cfe/trunk/lib/Basic/OperatorPrecedence.cpp cfe/trunk/lib/CodeGen/CGExprScalar.cpp cfe/trunk/lib/CodeGen/CGStmtOpenMP.cpp cfe/trunk/lib/Format/ContinuationIndenter.cpp cfe/trunk/lib/Format/Format.cpp cfe/trunk/lib/Format/TokenAnnotator.cpp cfe/trunk/lib/Parse/ParseExpr.cpp cfe/trunk/lib/Sema/SemaChecking.cpp cfe/trunk/lib/Sema/SemaExpr.cpp cfe/trunk/lib/Sema/SemaOpenMP.cpp cfe/trunk/lib/Sema/SemaStmt.cpp cfe/trunk/lib/StaticAnalyzer/Checkers/IdenticalExprChecker.cpp cfe/trunk/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp cfe/trunk/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp cfe/trunk/lib/StaticAnalyzer/Core/RangedConstraintManager.cpp cfe/trunk/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp cfe/trunk/test/CodeGenCXX/cxx2a-three-way-comparison.cpp cfe/trunk/test/SemaTemplate/cxx1z-fold-expressions.cpp cfe/trunk/unittests/Format/FormatTest.cpp Modified: cfe/trunk/include/clang/AST/Expr.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Expr.h?rev=320707&r1=320706&r2=320707&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/Expr.h (original) +++ cfe/trunk/include/clang/AST/Expr.h Thu Dec 14 07:16:18 2017 @@ -3072,7 +3072,7 @@ public: 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) { Modified: cfe/trunk/include/clang/AST/OperationKinds.def URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/OperationKinds.def?rev=320707&r1=320706&r2=320707&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/OperationKinds.def (original) +++ cfe/trunk/include/clang/AST/OperationKinds.def Thu Dec 14 07:16:18 2017 @@ -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, ".*") @@ -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, ">") @@ -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, "++") Modified: cfe/trunk/include/clang/AST/RecursiveASTVisitor.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/RecursiveASTVisitor.h?rev=320707&r1=320706&r2=320707&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/RecursiveASTVisitor.h (original) +++ cfe/trunk/include/clang/AST/RecursiveASTVisitor.h Thu Dec 14 07:16:18 2017 @@ -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() \ Modified: cfe/trunk/include/clang/AST/StmtVisitor.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/StmtVisitor.h?rev=320707&r1=320706&r2=320707&view=diff ============================================================================== --- cfe/trunk/include/clang/AST/StmtVisitor.h (original) +++ cfe/trunk/include/clang/AST/StmtVisitor.h Thu Dec 14 07:16:18 2017 @@ -65,6 +65,7 @@ public: 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); @@ -132,6 +133,8 @@ public: 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) Modified: cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyTIL.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyTIL.h?rev=320707&r1=320706&r2=320707&view=diff ============================================================================== --- cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyTIL.h (original) +++ cfe/trunk/include/clang/Analysis/Analyses/ThreadSafetyTIL.h Thu Dec 14 07:16:18 2017 @@ -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) }; Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=320707&r1=320706&r2=320707&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original) +++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Thu Dec 14 07:16:18 2017 @@ -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< @@ -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">; Modified: cfe/trunk/include/clang/Basic/OperatorPrecedence.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/OperatorPrecedence.h?rev=320707&r1=320706&r2=320707&view=diff ============================================================================== --- cfe/trunk/include/clang/Basic/OperatorPrecedence.h (original) +++ cfe/trunk/include/clang/Basic/OperatorPrecedence.h Thu Dec 14 07:16:18 2017 @@ -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 // .*, ->* }; } Modified: cfe/trunk/lib/AST/Expr.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Expr.cpp?rev=320707&r1=320706&r2=320707&view=diff ============================================================================== --- cfe/trunk/lib/AST/Expr.cpp (original) +++ cfe/trunk/lib/AST/Expr.cpp Thu Dec 14 07:16:18 2017 @@ -1780,6 +1780,7 @@ BinaryOperator::getOverloadedOpcode(Over 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; @@ -1811,6 +1812,7 @@ OverloadedOperatorKind BinaryOperator::g 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, Modified: cfe/trunk/lib/AST/ExprConstant.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=320707&r1=320706&r2=320707&view=diff ============================================================================== --- cfe/trunk/lib/AST/ExprConstant.cpp (original) +++ cfe/trunk/lib/AST/ExprConstant.cpp Thu Dec 14 07:16:18 2017 @@ -10471,6 +10471,7 @@ static ICEDiag CheckICE(const Expr* E, c 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. Modified: cfe/trunk/lib/Analysis/ThreadSafetyCommon.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/ThreadSafetyCommon.cpp?rev=320707&r1=320706&r2=320707&view=diff ============================================================================== --- cfe/trunk/lib/Analysis/ThreadSafetyCommon.cpp (original) +++ cfe/trunk/lib/Analysis/ThreadSafetyCommon.cpp Thu Dec 14 07:16:18 2017 @@ -505,6 +505,7 @@ til::SExpr *SExprBuilder::translateBinar 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); Modified: cfe/trunk/lib/Analysis/ThreadSafetyTIL.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/ThreadSafetyTIL.cpp?rev=320707&r1=320706&r2=320707&view=diff ============================================================================== --- cfe/trunk/lib/Analysis/ThreadSafetyTIL.cpp (original) +++ cfe/trunk/lib/Analysis/ThreadSafetyTIL.cpp Thu Dec 14 07:16:18 2017 @@ -38,6 +38,7 @@ StringRef til::getBinaryOpcodeString(TIL case BOP_Neq: return "!="; case BOP_Lt: return "<"; case BOP_Leq: return "<="; + case BOP_Cmp: return "<=>"; case BOP_LogicAnd: return "&&"; case BOP_LogicOr: return "||"; } Modified: cfe/trunk/lib/Basic/OperatorPrecedence.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/OperatorPrecedence.cpp?rev=320707&r1=320706&r2=320707&view=diff ============================================================================== --- cfe/trunk/lib/Basic/OperatorPrecedence.cpp (original) +++ cfe/trunk/lib/Basic/OperatorPrecedence.cpp Thu Dec 14 07:16:18 2017 @@ -63,6 +63,7 @@ prec::Level getBinOpPrecedence(tok::Toke 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; Modified: cfe/trunk/lib/CodeGen/CGExprScalar.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprScalar.cpp?rev=320707&r1=320706&r2=320707&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGExprScalar.cpp (original) +++ cfe/trunk/lib/CodeGen/CGExprScalar.cpp Thu Dec 14 07:16:18 2017 @@ -3922,6 +3922,7 @@ LValue CodeGenFunction::EmitCompoundAssi case BO_GE: case BO_EQ: case BO_NE: + case BO_Cmp: case BO_And: case BO_Xor: case BO_Or: Modified: cfe/trunk/lib/CodeGen/CGStmtOpenMP.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGStmtOpenMP.cpp?rev=320707&r1=320706&r2=320707&view=diff ============================================================================== --- cfe/trunk/lib/CodeGen/CGStmtOpenMP.cpp (original) +++ cfe/trunk/lib/CodeGen/CGStmtOpenMP.cpp Thu Dec 14 07:16:18 2017 @@ -3408,6 +3408,7 @@ static std::pair<bool, RValue> emitOMPAt case BO_GE: case BO_EQ: case BO_NE: + case BO_Cmp: case BO_AddAssign: case BO_SubAssign: case BO_AndAssign: Modified: cfe/trunk/lib/Format/ContinuationIndenter.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/ContinuationIndenter.cpp?rev=320707&r1=320706&r2=320707&view=diff ============================================================================== --- cfe/trunk/lib/Format/ContinuationIndenter.cpp (original) +++ cfe/trunk/lib/Format/ContinuationIndenter.cpp Thu Dec 14 07:16:18 2017 @@ -323,7 +323,8 @@ bool ContinuationIndenter::mustBreak(con // 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 = @@ -536,7 +537,8 @@ void ContinuationIndenter::addTokenOnCur (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) && Modified: cfe/trunk/lib/Format/Format.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/Format.cpp?rev=320707&r1=320706&r2=320707&view=diff ============================================================================== --- cfe/trunk/lib/Format/Format.cpp (original) +++ cfe/trunk/lib/Format/Format.cpp Thu Dec 14 07:16:18 2017 @@ -2074,6 +2074,7 @@ LangOptions getFormattingLangOpts(const 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; Modified: cfe/trunk/lib/Format/TokenAnnotator.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Format/TokenAnnotator.cpp?rev=320707&r1=320706&r2=320707&view=diff ============================================================================== --- cfe/trunk/lib/Format/TokenAnnotator.cpp (original) +++ cfe/trunk/lib/Format/TokenAnnotator.cpp Thu Dec 14 07:16:18 2017 @@ -2153,7 +2153,7 @@ unsigned TokenAnnotator::splitPenalty(co 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; Modified: cfe/trunk/lib/Parse/ParseExpr.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExpr.cpp?rev=320707&r1=320706&r2=320707&view=diff ============================================================================== --- cfe/trunk/lib/Parse/ParseExpr.cpp (original) +++ cfe/trunk/lib/Parse/ParseExpr.cpp Thu Dec 14 07:16:18 2017 @@ -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 @@ -267,7 +271,8 @@ bool Parser::diagnoseUnknownTemplateId(E } 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 { Modified: cfe/trunk/lib/Sema/SemaChecking.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaChecking.cpp?rev=320707&r1=320706&r2=320707&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaChecking.cpp (original) +++ cfe/trunk/lib/Sema/SemaChecking.cpp Thu Dec 14 07:16:18 2017 @@ -7279,8 +7279,8 @@ static bool CheckMemorySizeofForComparis 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(); @@ -8433,6 +8433,8 @@ static IntRange GetExprRange(ASTContext 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: @@ -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; @@ -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; } }; Modified: cfe/trunk/lib/Sema/SemaExpr.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=320707&r1=320706&r2=320707&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaExpr.cpp (original) +++ cfe/trunk/lib/Sema/SemaExpr.cpp Thu Dec 14 07:16:18 2017 @@ -11375,6 +11375,7 @@ BinaryOperatorKind Sema::ConvertTokenKin 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; @@ -11683,6 +11684,13 @@ ExprResult Sema::CreateBuiltinBinOp(Sour 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; Modified: cfe/trunk/lib/Sema/SemaOpenMP.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOpenMP.cpp?rev=320707&r1=320706&r2=320707&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaOpenMP.cpp (original) +++ cfe/trunk/lib/Sema/SemaOpenMP.cpp Thu Dec 14 07:16:18 2017 @@ -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: Modified: cfe/trunk/lib/Sema/SemaStmt.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaStmt.cpp?rev=320707&r1=320706&r2=320707&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaStmt.cpp (original) +++ cfe/trunk/lib/Sema/SemaStmt.cpp Thu Dec 14 07:16:18 2017 @@ -127,34 +127,47 @@ void Sema::ActOnForEachDeclStmt(DeclGrou /// warning from firing. static bool DiagnoseUnusedComparison(Sema &S, const Expr *E) { SourceLocation Loc; - bool IsNotEqual, CanAssign, IsRelational; + bool CanAssign; + enum { Equality, Inequality, Relational, ThreeWay } Kind; if (const BinaryOperator *Op = dyn_cast<BinaryOperator>(E)) { if (!Op->isComparisonOp()) return false; - IsRelational = Op->isRelationalOp(); + if (Op->getOpcode() == BO_EQ) + Kind = Equality; + else if (Op->getOpcode() == BO_NE) + Kind = Inequality; + else if (Op->getOpcode() == BO_Cmp) + Kind = ThreeWay; + else { + assert(Op->isRelationalOp()); + Kind = Relational; + } Loc = Op->getOperatorLoc(); - IsNotEqual = Op->getOpcode() == BO_NE; CanAssign = Op->getLHS()->IgnoreParenImpCasts()->isLValue(); } else if (const CXXOperatorCallExpr *Op = dyn_cast<CXXOperatorCallExpr>(E)) { switch (Op->getOperator()) { - default: - return false; case OO_EqualEqual: + Kind = Equality; + break; case OO_ExclaimEqual: - IsRelational = false; + Kind = Inequality; break; case OO_Less: case OO_Greater: case OO_GreaterEqual: case OO_LessEqual: - IsRelational = true; + Kind = Relational; break; + case OO_Spaceship: + Kind = ThreeWay; + break; + default: + return false; } Loc = Op->getOperatorLoc(); - IsNotEqual = Op->getOperator() == OO_ExclaimEqual; CanAssign = Op->getArg(0)->IgnoreParenImpCasts()->isLValue(); } else { // Not a typo-prone comparison. @@ -167,15 +180,15 @@ static bool DiagnoseUnusedComparison(Sem return false; S.Diag(Loc, diag::warn_unused_comparison) - << (unsigned)IsRelational << (unsigned)IsNotEqual << E->getSourceRange(); + << (unsigned)Kind << E->getSourceRange(); // If the LHS is a plausible entity to assign to, provide a fixit hint to // correct common typos. - if (!IsRelational && CanAssign) { - if (IsNotEqual) + if (CanAssign) { + if (Kind == Inequality) S.Diag(Loc, diag::note_inequality_comparison_to_or_assign) << FixItHint::CreateReplacement(Loc, "|="); - else + else if (Kind == Equality) S.Diag(Loc, diag::note_equality_comparison_to_assign) << FixItHint::CreateReplacement(Loc, "="); } Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/IdenticalExprChecker.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/IdenticalExprChecker.cpp?rev=320707&r1=320706&r2=320707&view=diff ============================================================================== --- cfe/trunk/lib/StaticAnalyzer/Checkers/IdenticalExprChecker.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Checkers/IdenticalExprChecker.cpp Thu Dec 14 07:16:18 2017 @@ -255,7 +255,10 @@ void FindIdenticalExprVisitor::checkComp PathDiagnosticLocation ELoc = PathDiagnosticLocation::createOperatorLoc(B, BR.getSourceManager()); StringRef Message; - if (((Op == BO_EQ) || (Op == BO_LE) || (Op == BO_GE))) + if (Op == BO_Cmp) + Message = "comparison of identical expressions always evaluates to " + "'equal'"; + else if (((Op == BO_EQ) || (Op == BO_LE) || (Op == BO_GE))) Message = "comparison of identical expressions always evaluates to true"; else Message = "comparison of identical expressions always evaluates to false"; Modified: cfe/trunk/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp?rev=320707&r1=320706&r2=320707&view=diff ============================================================================== --- cfe/trunk/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp Thu Dec 14 07:16:18 2017 @@ -1541,7 +1541,7 @@ ConditionBRVisitor::VisitTrueTest(const // For non-assignment operations, we require that we can understand // both the LHS and RHS. if (LhsString.empty() || RhsString.empty() || - !BinaryOperator::isComparisonOp(Op)) + !BinaryOperator::isComparisonOp(Op) || Op == BO_Cmp) return nullptr; // Should we invert the strings if the LHS is not a variable name? Modified: cfe/trunk/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp?rev=320707&r1=320706&r2=320707&view=diff ============================================================================== --- cfe/trunk/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp Thu Dec 14 07:16:18 2017 @@ -396,7 +396,9 @@ bool RangeConstraintManager::canReasonAb } if (const SymSymExpr *SSE = dyn_cast<SymSymExpr>(SE)) { - if (BinaryOperator::isComparisonOp(SSE->getOpcode())) { + // FIXME: Handle <=> here. + if (BinaryOperator::isEqualityOp(SSE->getOpcode()) || + BinaryOperator::isRelationalOp(SSE->getOpcode())) { // We handle Loc <> Loc comparisons, but not (yet) NonLoc <> NonLoc. if (Loc::isLocType(SSE->getLHS()->getType())) { assert(Loc::isLocType(SSE->getRHS()->getType())); Modified: cfe/trunk/lib/StaticAnalyzer/Core/RangedConstraintManager.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/RangedConstraintManager.cpp?rev=320707&r1=320706&r2=320707&view=diff ============================================================================== --- cfe/trunk/lib/StaticAnalyzer/Core/RangedConstraintManager.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Core/RangedConstraintManager.cpp Thu Dec 14 07:16:18 2017 @@ -33,7 +33,7 @@ ProgramStateRef RangedConstraintManager: // We can only simplify expressions whose RHS is an integer. BinaryOperator::Opcode op = SIE->getOpcode(); - if (BinaryOperator::isComparisonOp(op)) { + if (BinaryOperator::isComparisonOp(op) && op != BO_Cmp) { if (!Assumption) op = BinaryOperator::negateComparisonOp(op); Modified: cfe/trunk/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp?rev=320707&r1=320706&r2=320707&view=diff ============================================================================== --- cfe/trunk/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp Thu Dec 14 07:16:18 2017 @@ -679,7 +679,7 @@ SVal SimpleSValBuilder::evalBinOpLL(Prog if (SymbolRef rSym = rhs.getAsLocSymbol()) { // We can only build expressions with symbols on the left, // so we need a reversible operator. - if (!BinaryOperator::isComparisonOp(op)) + if (!BinaryOperator::isComparisonOp(op) || op == BO_Cmp) return UnknownVal(); const llvm::APSInt &lVal = lhs.castAs<loc::ConcreteInt>().getValue(); Modified: cfe/trunk/test/CodeGenCXX/cxx2a-three-way-comparison.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/cxx2a-three-way-comparison.cpp?rev=320707&r1=320706&r2=320707&view=diff ============================================================================== --- cfe/trunk/test/CodeGenCXX/cxx2a-three-way-comparison.cpp (original) +++ cfe/trunk/test/CodeGenCXX/cxx2a-three-way-comparison.cpp Thu Dec 14 07:16:18 2017 @@ -1,5 +1,6 @@ // RUN: %clang_cc1 -std=c++2a -emit-llvm %s -o - -triple %itanium_abi_triple | FileCheck %s --check-prefix=ITANIUM // RUN: not %clang_cc1 -std=c++2a -emit-llvm %s -o - -triple %ms_abi_triple 2>&1 | FileCheck %s --check-prefix=MSABI +// RUN: not %clang_cc1 -std=c++2a -emit-llvm %s -o - -triple %itanium_abi_triple -DBUILTIN 2>&1 | FileCheck %s --check-prefix=BUILTIN // MSABI: cannot mangle this three-way comparison operator yet struct A { @@ -11,3 +12,18 @@ void A::operator<=>(int) {} // ITANIUM: define {{.*}}@_Zssi1A( void operator<=>(int, A) {} + +int operator<=>(A, A); + +// ITANIUM: define {{.*}}_Z1f1A( +int f(A a) { + // ITANIUM: %[[RET:.*]] = call {{.*}}_Zss1AS_( + // ITANIUM: ret i32 %[[RET]] + return a <=> a; +} + +#ifdef BUILTIN +void builtin(int a) { + a <=> a; // BUILTIN: cannot compile this scalar expression yet +} +#endif Added: cfe/trunk/test/Parser/cxx2a-spaceship.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Parser/cxx2a-spaceship.cpp?rev=320707&view=auto ============================================================================== --- cfe/trunk/test/Parser/cxx2a-spaceship.cpp (added) +++ cfe/trunk/test/Parser/cxx2a-spaceship.cpp Thu Dec 14 07:16:18 2017 @@ -0,0 +1,18 @@ +// RUN: %clang_cc1 -std=c++2a -verify %s + +template<int> struct X {}; + +X<1> operator<<(X<0>, X<0>); +X<2> operator<=>(X<0>, X<1>); +X<2> operator<=>(X<1>, X<0>); +X<3> operator<(X<0>, X<2>); +X<3> operator<(X<2>, X<0>); + +void f(X<0> x0, X<1> x1) { + X<2> a = x0 <=> x0 << x0; + X<2> b = x0 << x0 <=> x0; // expected-warning {{overloaded operator << has higher precedence than comparison operator}} expected-note 2{{}} + X<3> c = x0 < x0 <=> x1; + X<3> d = x1 <=> x0 < x0; + X<3> e = x0 < x0 <=> x0 << x0; + X<3> f = x0 << x0 <=> x0 < x0; // expected-warning {{overloaded operator << has higher precedence than comparison operator}} expected-note 2{{}} +} Added: cfe/trunk/test/SemaCXX/compare-cxx2a.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/compare-cxx2a.cpp?rev=320707&view=auto ============================================================================== --- cfe/trunk/test/SemaCXX/compare-cxx2a.cpp (added) +++ cfe/trunk/test/SemaCXX/compare-cxx2a.cpp Thu Dec 14 07:16:18 2017 @@ -0,0 +1,166 @@ +// Force x86-64 because some of our heuristics are actually based +// on integer sizes. + +// RUN: %clang_cc1 -triple x86_64-apple-darwin -fsyntax-only -pedantic -verify -Wsign-compare -std=c++2a %s + +void test0(long a, unsigned long b) { + enum EnumA {A}; + enum EnumB {B}; + enum EnumC {C = 0x10000}; + // (a,b) + + // FIXME: <=> should never produce -Wsign-compare warnings. All the possible error + // cases involve narrowing conversions and so are ill-formed. + (void)(a <=> (unsigned long) b); // expected-warning {{comparison of integers of different signs}} + (void)(a <=> (unsigned int) b); + (void)(a <=> (unsigned short) b); + (void)(a <=> (unsigned char) b); + (void)((long) a <=> b); // expected-warning {{comparison of integers of different signs}} + (void)((int) a <=> b); // expected-warning {{comparison of integers of different signs}} + (void)((short) a <=> b); // expected-warning {{comparison of integers of different signs}} + (void)((signed char) a <=> b); // expected-warning {{comparison of integers of different signs}} + (void)((long) a <=> (unsigned long) b); // expected-warning {{comparison of integers of different signs}} + (void)((int) a <=> (unsigned int) b); // expected-warning {{comparison of integers of different signs}} + (void)((short) a <=> (unsigned short) b); + (void)((signed char) a <=> (unsigned char) b); + +#if 0 + // (A,b) + (void)(A <=> (unsigned long) b); + (void)(A <=> (unsigned int) b); + (void)(A <=> (unsigned short) b); + (void)(A <=> (unsigned char) b); + (void)((long) A <=> b); + (void)((int) A <=> b); + (void)((short) A <=> b); + (void)((signed char) A <=> b); + (void)((long) A <=> (unsigned long) b); + (void)((int) A <=> (unsigned int) b); + (void)((short) A <=> (unsigned short) b); + (void)((signed char) A <=> (unsigned char) b); + + // (a,B) + (void)(a <=> (unsigned long) B); + (void)(a <=> (unsigned int) B); + (void)(a <=> (unsigned short) B); + (void)(a <=> (unsigned char) B); + (void)((long) a <=> B); + (void)((int) a <=> B); + (void)((short) a <=> B); + (void)((signed char) a <=> B); + (void)((long) a <=> (unsigned long) B); + (void)((int) a <=> (unsigned int) B); + (void)((short) a <=> (unsigned short) B); + (void)((signed char) a <=> (unsigned char) B); + + // (C,b) + (void)(C <=> (unsigned long) b); + (void)(C <=> (unsigned int) b); + (void)(C <=> (unsigned short) b); // expected-warning {{comparison of constant 'C' (65536) with expression of type 'unsigned short' is always 'std::strong_ordering::greater'}} + (void)(C <=> (unsigned char) b); // expected-warning {{comparison of constant 'C' (65536) with expression of type 'unsigned char' is always 'std::strong_ordering::greater'}} + (void)((long) C <=> b); + (void)((int) C <=> b); + (void)((short) C <=> b); + (void)((signed char) C <=> b); + (void)((long) C <=> (unsigned long) b); + (void)((int) C <=> (unsigned int) b); + (void)((short) C <=> (unsigned short) b); + (void)((signed char) C <=> (unsigned char) b); + + // (a,C) + (void)(a <=> (unsigned long) C); + (void)(a <=> (unsigned int) C); + (void)(a <=> (unsigned short) C); + (void)(a <=> (unsigned char) C); + (void)((long) a <=> C); + (void)((int) a <=> C); + (void)((short) a <=> C); // expected-warning {{comparison of constant 'C' (65536) with expression of type 'short' is always 'std::strong_ordering::less'}} + (void)((signed char) a <=> C); // expected-warning {{comparison of constant 'C' (65536) with expression of type 'signed char' is always 'std::strong_ordering::less'}} + (void)((long) a <=> (unsigned long) C); + (void)((int) a <=> (unsigned int) C); + (void)((short) a <=> (unsigned short) C); + (void)((signed char) a <=> (unsigned char) C); +#endif + + // (0x80000,b) + (void)(0x80000 <=> (unsigned long) b); + (void)(0x80000 <=> (unsigned int) b); + (void)(0x80000 <=> (unsigned short) b); // expected-warning {{result of comparison of constant 524288 with expression of type 'unsigned short' is always 'std::strong_ordering::greater'}} + (void)(0x80000 <=> (unsigned char) b); // expected-warning {{result of comparison of constant 524288 with expression of type 'unsigned char' is always 'std::strong_ordering::greater'}} + (void)((long) 0x80000 <=> b); + (void)((int) 0x80000 <=> b); + (void)((short) 0x80000 <=> b); + (void)((signed char) 0x80000 <=> b); + (void)((long) 0x80000 <=> (unsigned long) b); + (void)((int) 0x80000 <=> (unsigned int) b); + (void)((short) 0x80000 <=> (unsigned short) b); + (void)((signed char) 0x80000 <=> (unsigned char) b); + + // (a,0x80000) + (void)(a <=> (unsigned long) 0x80000); // expected-warning {{comparison of integers of different signs}} + (void)(a <=> (unsigned int) 0x80000); + (void)(a <=> (unsigned short) 0x80000); + (void)(a <=> (unsigned char) 0x80000); + (void)((long) a <=> 0x80000); + (void)((int) a <=> 0x80000); + (void)((short) a <=> 0x80000); // expected-warning {{comparison of constant 524288 with expression of type 'short' is always 'std::strong_ordering::less'}} + (void)((signed char) a <=> 0x80000); // expected-warning {{comparison of constant 524288 with expression of type 'signed char' is always 'std::strong_ordering::less'}} + (void)((long) a <=> (unsigned long) 0x80000); // expected-warning {{comparison of integers of different signs}} + (void)((int) a <=> (unsigned int) 0x80000); // expected-warning {{comparison of integers of different signs}} + (void)((short) a <=> (unsigned short) 0x80000); + (void)((signed char) a <=> (unsigned char) 0x80000); +} + +void test5(bool b) { + (void) (b <=> -10); // expected-warning{{comparison of constant -10 with expression of type 'bool' is always 'std::strong_ordering::greater'}} + (void) (b <=> -1); // expected-warning{{comparison of constant -1 with expression of type 'bool' is always 'std::strong_ordering::greater'}} + (void) (b <=> 0); + (void) (b <=> 1); + (void) (b <=> 2); // expected-warning{{comparison of constant 2 with expression of type 'bool' is always 'std::strong_ordering::less'}} + (void) (b <=> 10); // expected-warning{{comparison of constant 10 with expression of type 'bool' is always 'std::strong_ordering::less'}} +} + +void test6(signed char sc) { + (void)(sc <=> 200); // expected-warning{{comparison of constant 200 with expression of type 'signed char' is always 'std::strong_ordering::less'}} + (void)(200 <=> sc); // expected-warning{{comparison of constant 200 with expression of type 'signed char' is always 'std::strong_ordering::greater'}} +} + +// Test many signedness combinations. +void test7(unsigned long other) { + // Common unsigned, other unsigned, constant unsigned + (void)((unsigned)other <=> (unsigned long)(0x1'ffff'ffff)); // expected-warning{{less}} + (void)((unsigned)other <=> (unsigned long)(0xffff'ffff)); + (void)((unsigned long)other <=> (unsigned)(0x1'ffff'ffff)); + (void)((unsigned long)other <=> (unsigned)(0xffff'ffff)); + + // Common unsigned, other signed, constant unsigned + (void)((int)other <=> (unsigned long)(0xffff'ffff'ffff'ffff)); // expected-warning{{different signs}} + (void)((int)other <=> (unsigned long)(0x0000'0000'ffff'ffff)); // expected-warning{{different signs}} + (void)((int)other <=> (unsigned long)(0x0000'0000'0fff'ffff)); // expected-warning{{different signs}} + (void)((int)other <=> (unsigned)(0x8000'0000)); // expected-warning{{different signs}} + + // Common unsigned, other unsigned, constant signed + (void)((unsigned long)other <=> (int)(0xffff'ffff)); // expected-warning{{different signs}} + + // Common unsigned, other signed, constant signed + // Should not be possible as the common type should also be signed. + + // Common signed, other signed, constant signed + (void)((int)other <=> (long)(0xffff'ffff)); // expected-warning{{less}} + (void)((int)other <=> (long)(0xffff'ffff'0000'0000)); // expected-warning{{greater}} + (void)((int)other <=> (long)(0x0fff'ffff)); + (void)((int)other <=> (long)(0xffff'ffff'f000'0000)); + + // Common signed, other signed, constant unsigned + (void)((int)other <=> (unsigned char)(0xffff)); + (void)((int)other <=> (unsigned char)(0xff)); + + // Common signed, other unsigned, constant signed + (void)((unsigned char)other <=> (int)(0xff)); + (void)((unsigned char)other <=> (int)(0xffff)); // expected-warning{{less}} + + // Common signed, other unsigned, constant unsigned + (void)((unsigned char)other <=> (unsigned short)(0xff)); + (void)((unsigned char)other <=> (unsigned short)(0x100)); // expected-warning{{less}} + (void)((unsigned short)other <=> (unsigned char)(0xff)); +} Added: cfe/trunk/test/SemaCXX/constant-expression-cxx2a.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/constant-expression-cxx2a.cpp?rev=320707&view=auto ============================================================================== --- cfe/trunk/test/SemaCXX/constant-expression-cxx2a.cpp (added) +++ cfe/trunk/test/SemaCXX/constant-expression-cxx2a.cpp Thu Dec 14 07:16:18 2017 @@ -0,0 +1,27 @@ +// RUN: %clang_cc1 -std=c++2a -verify %s -fcxx-exceptions -triple=x86_64-linux-gnu + +namespace ThreeWayComparison { + struct A { + int n; + constexpr friend int operator<=>(const A &a, const A &b) { + return a.n < b.n ? -1 : a.n > b.n ? 1 : 0; + } + }; + static_assert(A{1} <=> A{2} < 0); + static_assert(A{2} <=> A{1} > 0); + static_assert(A{2} <=> A{2} == 0); + + // Note: not yet supported. + static_assert(1 <=> 2 < 0); // expected-error {{invalid operands}} + static_assert(2 <=> 1 > 0); // expected-error {{invalid operands}} + static_assert(1 <=> 1 == 0); // expected-error {{invalid operands}} + constexpr int k = (1 <=> 1, 0); + // expected-error@-1 {{constexpr variable 'k' must be initialized by a constant expression}} + // expected-warning@-2 {{three-way comparison result unused}} + + constexpr void f() { // expected-error {{constant expression}} + void(1 <=> 1); // expected-note {{constant expression}} + } + + // TODO: defaulted operator <=> +} Modified: cfe/trunk/test/SemaTemplate/cxx1z-fold-expressions.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/cxx1z-fold-expressions.cpp?rev=320707&r1=320706&r2=320707&view=diff ============================================================================== --- cfe/trunk/test/SemaTemplate/cxx1z-fold-expressions.cpp (original) +++ cfe/trunk/test/SemaTemplate/cxx1z-fold-expressions.cpp Thu Dec 14 07:16:18 2017 @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -std=c++1z -verify %s +// RUN: %clang_cc1 -std=c++2a -verify %s template<typename ...T> constexpr auto sum(T ...t) { return (... + t); } template<typename ...T> constexpr auto product(T ...t) { return (t * ...); } @@ -76,3 +77,18 @@ template<typename T, typename ...Ts> con return (t.*....*ts); } static_assert(&apply(a, &A::b, &A::B::c, &A::B::C::d, &A::B::C::D::e) == &a.b.c.d.e); + +#if __cplusplus > 201703L +// The <=> operator is unique among binary operators in not being a +// fold-operator. +// FIXME: This diagnostic is not great. +template<typename ...T> constexpr auto spaceship1(T ...t) { return (t <=> ...); } // expected-error {{expected expression}} +template<typename ...T> constexpr auto spaceship2(T ...t) { return (... <=> t); } // expected-error {{expected expression}} +template<typename ...T> constexpr auto spaceship3(T ...t) { return (t <=> ... <=> 0); } // expected-error {{expected expression}} +#endif + +// The GNU binary conditional operator ?: is not recognized as a fold-operator. +// FIXME: Why not? This seems like it would be useful. +template<typename ...T> constexpr auto binary_conditional1(T ...t) { return (t ?: ...); } // expected-error {{expected expression}} +template<typename ...T> constexpr auto binary_conditional2(T ...t) { return (... ?: t); } // expected-error {{expected expression}} +template<typename ...T> constexpr auto binary_conditional3(T ...t) { return (t ?: ... ?: 0); } // expected-error {{expected expression}} Modified: cfe/trunk/unittests/Format/FormatTest.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Format/FormatTest.cpp?rev=320707&r1=320706&r2=320707&view=diff ============================================================================== --- cfe/trunk/unittests/Format/FormatTest.cpp (original) +++ cfe/trunk/unittests/Format/FormatTest.cpp Thu Dec 14 07:16:18 2017 @@ -3072,6 +3072,10 @@ TEST_F(FormatTest, LineBreakingInBinaryE "if (aaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaa(\n" " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) == 5) {\n" "}"); + verifyFormat( + "if (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(\n" + " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) <=> 5) {\n" + "}"); // Even explicit parentheses stress the precedence enough to make the // additional break unnecessary. verifyFormat("if ((aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +\n" @@ -3091,6 +3095,10 @@ TEST_F(FormatTest, LineBreakingInBinaryE " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ==\n" " 5) {\n" "}"); + verifyFormat("if (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +\n" + " aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa <=>\n" + " 5) {\n" + "}"); FormatStyle OnePerLine = getLLVMStyle(); OnePerLine.BinPackParameters = false; _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits