[PATCH] D13643: [Sema] Warn on ternary comparison

Matěj Grabovský via cfe-commits cfe-commits at lists.llvm.org
Sun Oct 11 23:16:43 PDT 2015


mgrabovsky created this revision.
mgrabovsky added a subscriber: cfe-commits.

This change adds a Sema diagnostic for comparisons like `a < b < c`,
which usually do not behave as intended by the author.

Fixes bug 20082.

http://reviews.llvm.org/D13643

Files:
  include/clang/Basic/DiagnosticSemaKinds.td
  lib/Sema/SemaChecking.cpp
  test/Sema/bool-compare.c

Index: test/Sema/bool-compare.c
===================================================================
--- test/Sema/bool-compare.c
+++ test/Sema/bool-compare.c
@@ -85,7 +85,9 @@
   if ((a<y) != -1) {}// expected-warning {{comparison of constant -1 with boolean expression is always true}}
 
   if ((a<y) == z) {} // no warning
-  if (a>y<z)      {} // no warning
+  if (a>y<z)      {} // expected-warning {{ternary comparisons do not work as expected}} \
+                     // expected-note {{to achieve the expected behavior, turn this expression into a conjunction of two comparisons}} \
+                     // expected-note {{place parentheses around either of the comparisons to silence this warning}}
   if ((a<y) > z)  {} // no warning
   if((a<y)>(z<y)) {} // no warning
   if((a<y)==(z<y)){} // no warning
@@ -144,10 +146,12 @@
   if (z !=(a<y))  {} // no warning
   if (-1 !=(a<y)) {} // expected-warning {{comparison of constant -1 with boolean expression is always true}}
 
-  if (z ==(a<y))  {}    // no warning
-  if (z<a>y)      {}        // no warning
-  if (z > (a<y))  {}    // no warning
-  if((z<y)>(a<y)) {}   // no warning
+  if (z ==(a<y))  {}  // no warning
+  if (z<a>y)      {}  // expected-warning {{ternary comparisons do not work as expected}} \
+                      // expected-note {{to achieve the expected behavior, turn this expression into a conjunction of two comparisons}} \
+                      // expected-note {{place parentheses around either of the comparisons to silence this warning}}
+  if (z > (a<y))  {}  // no warning
+  if((z<y)>(a<y)) {}  // no warning
   if((z<y)==(a<y)){}  // no warning
   if((z<y)!=(a<y)){}  // no warning
   if((y==z)<(z==x)){}  // no warning
Index: lib/Sema/SemaChecking.cpp
===================================================================
--- lib/Sema/SemaChecking.cpp
+++ lib/Sema/SemaChecking.cpp
@@ -6693,6 +6693,22 @@
         << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange());
 }
 
+/// Diagnose attempts at ternary comparison, e.g., 1 < x < 2
+static void DiagnoseTernaryComparison(Sema &S, BinaryOperator *E) {
+  BinaryOperator *LHS = dyn_cast<BinaryOperator>(E->getLHS());
+  if (!LHS || !LHS->isComparisonOp())
+    return;
+
+  SourceLocation Loc = E->getSourceRange().getBegin();
+
+  S.DiagRuntimeBehavior(Loc, E,
+    S.PDiag(diag::warn_ternary_comparison) << E->getSourceRange());
+  S.DiagRuntimeBehavior(Loc, E,
+    S.PDiag(diag::note_ternary_comparison_to_conjunction));
+  S.DiagRuntimeBehavior(Loc, E,
+    S.PDiag(diag::note_ternary_comparison_silence));
+}
+
 /// Analyze the operands of the given comparison.  Implements the
 /// fallback case from AnalyzeComparison.
 static void AnalyzeImpConvsInComparison(Sema &S, BinaryOperator *E) {
@@ -6720,7 +6736,9 @@
   Expr *RHS = E->getRHS()->IgnoreParenImpCasts();
   
   bool IsComparisonConstant = false;
-  
+
+  DiagnoseTernaryComparison(S, E);
+
   // Check whether an integer constant comparison results in a value
   // of 'true' or 'false'.
   if (T->isIntegralType(S.Context)) {
Index: include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- include/clang/Basic/DiagnosticSemaKinds.td
+++ include/clang/Basic/DiagnosticSemaKinds.td
@@ -5862,6 +5862,14 @@
 def note_condition_assign_silence : Note<
   "place parentheses around the assignment to silence this warning">;
 
+def warn_ternary_comparison : Warning<"ternary comparisons do not work "
+  "as expected">,
+  InGroup<Parentheses>;
+def note_ternary_comparison_to_conjunction : Note<"to achieve the expected behavior, "
+  "turn this expression into a conjunction of two comparisons">;
+def note_ternary_comparison_silence : Note<"place parentheses around either "
+  "of the comparisons to silence this warning">;
+
 def warn_equality_with_extra_parens : Warning<"equality comparison with "
   "extraneous parentheses">, InGroup<ParenthesesOnEquality>;
 def note_equality_comparison_to_assign : Note<


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D13643.37078.patch
Type: text/x-patch
Size: 3998 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20151012/94a7c4a0/attachment-0001.bin>


More information about the cfe-commits mailing list