]> granicus.if.org Git - clang/commitdiff
[c++20] P0515R3: Parsing support and basic AST construction for operator <=>.
authorRichard Smith <richard-llvm@metafoo.co.uk>
Thu, 14 Dec 2017 15:16:18 +0000 (15:16 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Thu, 14 Dec 2017 15:16:18 +0000 (15:16 +0000)
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'.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@320707 91177308-0d34-0410-b5e6-96231b3b80d8

33 files changed:
include/clang/AST/Expr.h
include/clang/AST/OperationKinds.def
include/clang/AST/RecursiveASTVisitor.h
include/clang/AST/StmtVisitor.h
include/clang/Analysis/Analyses/ThreadSafetyTIL.h
include/clang/Basic/DiagnosticSemaKinds.td
include/clang/Basic/OperatorPrecedence.h
lib/AST/Expr.cpp
lib/AST/ExprConstant.cpp
lib/Analysis/ThreadSafetyCommon.cpp
lib/Analysis/ThreadSafetyTIL.cpp
lib/Basic/OperatorPrecedence.cpp
lib/CodeGen/CGExprScalar.cpp
lib/CodeGen/CGStmtOpenMP.cpp
lib/Format/ContinuationIndenter.cpp
lib/Format/Format.cpp
lib/Format/TokenAnnotator.cpp
lib/Parse/ParseExpr.cpp
lib/Sema/SemaChecking.cpp
lib/Sema/SemaExpr.cpp
lib/Sema/SemaOpenMP.cpp
lib/Sema/SemaStmt.cpp
lib/StaticAnalyzer/Checkers/IdenticalExprChecker.cpp
lib/StaticAnalyzer/Core/BugReporterVisitors.cpp
lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
lib/StaticAnalyzer/Core/RangedConstraintManager.cpp
lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
test/CodeGenCXX/cxx2a-three-way-comparison.cpp
test/Parser/cxx2a-spaceship.cpp [new file with mode: 0644]
test/SemaCXX/compare-cxx2a.cpp [new file with mode: 0644]
test/SemaCXX/constant-expression-cxx2a.cpp [new file with mode: 0644]
test/SemaTemplate/cxx1z-fold-expressions.cpp
unittests/Format/FormatTest.cpp

index b4c49eaf526c16297bf9080b96f522023c5031bb..f2770940372fd12b6e7ed09a3f4ad7161d433337 100644 (file)
@@ -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) {
index 2d48a7df47b7a8d934258dd50ddc42aee6b60973..2aec98a6dc78c2ec575f70a4d0e4637d05550e5b 100644 (file)
@@ -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, "++")
index 7fb5221b7d6067ac2fdfefedd11d5d28ffa7e68f..ba76ea0a0df55769a519626a94d46bffd690d053 100644 (file)
@@ -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()                                                             \
index 5efd47f9afb2ca2bbc06c02e6443507b52cfdef6..98fa113274069a00786d9ad6db82c6b9386665c2 100644 (file)
@@ -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)
 
index 17351622fbdf56a356038a39f19e269a3a2e6dd3..0a58d2a80250ade3284c47861ef3714d4f8a6be2 100644 (file)
@@ -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)
 };
index 22cd7c7545d07496f57118fc68babc6398867f1c..29236eab5446c7c56ed639b428dd86f4380e409b 100644 (file)
@@ -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">;
index 640749fdd10d5fd23729c970ade0521ac3351cea..94978f81e543acd1aa69b70d5d85444fad556e9a 100644 (file)
@@ -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    // .*, ->*
   };
 }
 
index 6cda82b2b0cb0871b5ec5a1dba49b8bbc0288e36..55061aa462e5ca8cb6a21b33c866ac72b7340777 100644 (file)
@@ -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;
@@ -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,
index e899b7ca164946ceedc202bd367aff1b344c9d8b..9c9eeb79b40a48d9d50efb0eb6366ed053964235 100644 (file)
@@ -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.
index 875f28c6e94a1f95aac2164b6275f9611aba2dde..c1421b09c9893f3878bc69b0ce7bc995a57effba 100644 (file)
@@ -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);
index 83aa90435e2a5ae9b5306e03d36a6b5d0bb2baa6..cd7cdc69ab73abb6c02c48ae2bfde6bbf43a00bc 100644 (file)
@@ -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 "||";
   }
index 384d23c38af5c53d947f007dd4460b494ade996b..3743b6ad5fefc6f1c7d265f9d194e45fe477c2dc 100644 (file)
@@ -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;
index 32e0f8853048a00a24a9a200721c46872f6b288e..c46215067a68c47244cc6194a4b3b9954bbf89f7 100644 (file)
@@ -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:
index a24aaa046ab6da57de8d6611835186b7af51dbb5..f04d28ed0d4a932ac69641693e13545c82c04e73 100644 (file)
@@ -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:
index e022a3a8c77107fcb8cf74eb98cc5d9574b72fd1..a3d38b244c5c17b987b149683e57a1cfa6c2cd5e 100644 (file)
@@ -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 =
@@ -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) &&
index 38e8163d3feb3af94838a52fa69d582830535098..217c6729ee39712082a5d123c683f684d15e860c 100644 (file)
@@ -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;
index c394fa03b2661d6b288d949dd564da9172e182cf..298c72b002f8b61cbe4f5d826aa29f07e00783b9 100644 (file)
@@ -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;
index 233e0accce97f1965c9f668db333343f1d67f167..bc587628c954d8ee1cbb89888bc873ebe20043b2 100644 (file)
@@ -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(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 {
index 9ed21daad603aa9b45957ee3fa6d3e02e50e2596..94070bb9c9aa1f81a12d2d460793b3e9ddd5f302 100644 (file)
@@ -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();
@@ -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:
@@ -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;
   }
 };
index 8c6d11b495700a7abf48dddb5dd50eca8c5a9059..929806ac6bfaf4a1f979a218e85f6e5ba218141f 100644 (file)
@@ -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;
@@ -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;
index b9323388579dabca3f74841afac40ebb328a2097..b34bb3388d7177290eb25df99e39474913764ba5 100644 (file)
@@ -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:
index 45b73f0a2bf510902e28e9016817339a9ef0cf63..ff0f4d99585127410693329f31803a292c96a650 100644 (file)
@@ -127,34 +127,47 @@ void Sema::ActOnForEachDeclStmt(DeclGroupPtrTy dg) {
 /// 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(Sema &S, const Expr *E) {
     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, "=");
   }
index 0c3bff5b63b8f7f7de77866408eac2eeaa3cdac8..cf57b8dca06386ce276ac8e9fb9966f7532f43ae 100644 (file)
@@ -255,7 +255,10 @@ void FindIdenticalExprVisitor::checkComparisonOp(const BinaryOperator *B) {
     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";
index f651596006b3aab3d7626ea30e5abf84d57be77c..7304d789431eee26274f7b56455ee2c351ba01ee 100644 (file)
@@ -1541,7 +1541,7 @@ ConditionBRVisitor::VisitTrueTest(const Expr *Cond, const BinaryOperator *BExpr,
   // 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?
index 6a4c4d115857054efabe1d950cd046620cb10153..5a4031c0b4a5f5e555f5d9c5881e4ce9ad34dc75 100644 (file)
@@ -396,7 +396,9 @@ bool RangeConstraintManager::canReasonAbout(SVal X) const {
     }
 
     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()));
index 1304116f4974b4cfba70d4772dea3ce22cbabd2f..55ff15806efe60e6701c58b1850599c1a303e37f 100644 (file)
@@ -33,7 +33,7 @@ ProgramStateRef RangedConstraintManager::assumeSym(ProgramStateRef State,
     // 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);
 
index a5b5744c3fbe28d1db7beafc6ee7be2f524a3304..94d29d5a6ba32df0c011fda44f6e40e44c3b35d1 100644 (file)
@@ -679,7 +679,7 @@ SVal SimpleSValBuilder::evalBinOpLL(ProgramStateRef state,
     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();
index 08ab41b1eaa0ddbf068ce5ac60e10091dc1ff312..fd72d4a39cb37330d96f734a0bc94f663c6a5708 100644 (file)
@@ -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
diff --git a/test/Parser/cxx2a-spaceship.cpp b/test/Parser/cxx2a-spaceship.cpp
new file mode 100644 (file)
index 0000000..24cece3
--- /dev/null
@@ -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{{}}
+}
diff --git a/test/SemaCXX/compare-cxx2a.cpp b/test/SemaCXX/compare-cxx2a.cpp
new file mode 100644 (file)
index 0000000..61d3502
--- /dev/null
@@ -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));
+}
diff --git a/test/SemaCXX/constant-expression-cxx2a.cpp b/test/SemaCXX/constant-expression-cxx2a.cpp
new file mode 100644 (file)
index 0000000..935cbef
--- /dev/null
@@ -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 <=>
+}
index aefee92f648a6e79df53ffa7c9c39aae29f79dd4..383f51df21dc7d22dbc1fb48d67a4353828c9a11 100644 (file)
@@ -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> constexpr decltype(auto) apply(T &t, Ts ...
   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}}
index 6f4bd6d69d0d5f87bcef32e5699915b16fa3531c..2cae9dd0c547b8d71b875281f23839220143a514 100644 (file)
@@ -3072,6 +3072,10 @@ TEST_F(FormatTest, LineBreakingInBinaryExpressions) {
       "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, LineBreakingInBinaryExpressions) {
                "        aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ==\n"
                "    5) {\n"
                "}");
+  verifyFormat("if (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +\n"
+               "        aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa <=>\n"
+               "    5) {\n"
+               "}");
 
   FormatStyle OnePerLine = getLLVMStyle();
   OnePerLine.BinPackParameters = false;