diff options
| -rw-r--r-- | clang/include/clang/Basic/DiagnosticGroups.td | 2 | ||||
| -rw-r--r-- | clang/include/clang/Basic/DiagnosticSemaKinds.td | 3 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaChecking.cpp | 11 | ||||
| -rw-r--r-- | clang/test/Sema/warn-int-in-bool-context.c | 31 | ||||
| -rw-r--r-- | clang/test/SemaCXX/cxx2a-explicit-bool.cpp | 2 | 
5 files changed, 47 insertions, 2 deletions
diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td index 4e2f85d4e7c..4c7ea3d4ea2 100644 --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -499,6 +499,7 @@ def StringCompare : DiagGroup<"string-compare">;  def StringPlusInt : DiagGroup<"string-plus-int">;  def StringPlusChar : DiagGroup<"string-plus-char">;  def StrncatSize : DiagGroup<"strncat-size">; +def IntInBoolContext : DiagGroup<"int-in-bool-context">;  def TautologicalTypeLimitCompare : DiagGroup<"tautological-type-limit-compare">;  def TautologicalUnsignedZeroCompare : DiagGroup<"tautological-unsigned-zero-compare">;  def TautologicalUnsignedEnumZeroCompare : DiagGroup<"tautological-unsigned-enum-zero-compare">; @@ -821,6 +822,7 @@ def Most : DiagGroup<"most", [      Format,      Implicit,      InfiniteRecursion, +    IntInBoolContext,      MismatchedTags,      MissingBraces,      Move, diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 5f47da03338..26b328b9990 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -5720,6 +5720,9 @@ def warn_precedence_conditional : Warning<  def note_precedence_conditional_first : Note<    "place parentheses around the '?:' expression to evaluate it first">; +def warn_left_shift_in_bool_context : Warning< +  "converting the result of '<<' to a boolean; did you mean '(%0) != 0'?">, +  InGroup<IntInBoolContext>;  def warn_logical_instead_of_bitwise : Warning<    "use of logical '%0' with constant operand">,    InGroup<DiagGroup<"constant-logical-operand">>; diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 7aeace5c2a7..cbe7e9a8238 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -11256,10 +11256,16 @@ static bool isSameWidthConstantConversion(Sema &S, Expr *E, QualType T,    return true;  } -static void DiagnoseIntInBoolContext(Sema &S, const Expr *E) { +static void DiagnoseIntInBoolContext(Sema &S, Expr *E) {    E = E->IgnoreParenImpCasts();    SourceLocation ExprLoc = E->getExprLoc(); +  if (const auto *BO = dyn_cast<BinaryOperator>(E)) { +    BinaryOperator::Opcode Opc = BO->getOpcode(); +    if (Opc == BO_Shl) +      S.Diag(ExprLoc, diag::warn_left_shift_in_bool_context) << E; +  } +    if (const auto *CO = dyn_cast<ConditionalOperator>(E)) {      const auto *LHS = dyn_cast<IntegerLiteral>(CO->getTrueExpr());      if (!LHS) { @@ -11585,6 +11591,9 @@ static void CheckImplicitConversion(Sema &S, Expr *E, QualType T,    S.DiscardMisalignedMemberAddress(Target, E); +  if (Target->isBooleanType()) +    DiagnoseIntInBoolContext(S, E); +    if (!Source->isIntegerType() || !Target->isIntegerType())      return; diff --git a/clang/test/Sema/warn-int-in-bool-context.c b/clang/test/Sema/warn-int-in-bool-context.c new file mode 100644 index 00000000000..0a0d88f04e7 --- /dev/null +++ b/clang/test/Sema/warn-int-in-bool-context.c @@ -0,0 +1,31 @@ +// RUN: %clang_cc1 -x c -fsyntax-only -verify -Wint-in-bool-context %s +// RUN: %clang_cc1 -x c -fsyntax-only -verify -Wall %s +// RUN: %clang_cc1 -x c++ -fsyntax-only -verify -Wint-in-bool-context %s +// RUN: %clang_cc1 -x c++ -fsyntax-only -verify -Wall %s + +#define ONE 1 +#define TWO 2 + +#define SHIFT(l, r) l << r + +#ifdef __cplusplus +typedef bool boolean; +#else +typedef _Bool boolean; +#endif + +int test(int a) { +  boolean r; +  r = (1 << 3); // expected-warning {{converting the result of '<<' to a boolean; did you mean '(1 << 3) != 0'?}} +  r = TWO << 7; // expected-warning {{converting the result of '<<' to a boolean; did you mean '(2 << 7) != 0'?}} +  r = a << 7;   // expected-warning {{converting the result of '<<' to a boolean; did you mean '(a << 7) != 0'?}} +  r = ONE << a; // expected-warning {{converting the result of '<<' to a boolean; did you mean '(1 << a) != 0'?}} +  if (TWO << 4) // expected-warning {{converting the result of '<<' to a boolean; did you mean '(2 << 4) != 0'?}} +    return a; + +  if (a << TWO) // expected-warning {{converting the result of '<<' to a boolean; did you mean '(a << 2) != 0'?}} +    return a; + +  // Don't warn in macros. +  return SHIFT(1, a); +} diff --git a/clang/test/SemaCXX/cxx2a-explicit-bool.cpp b/clang/test/SemaCXX/cxx2a-explicit-bool.cpp index 56fa76f0a8b..bb62a25bdf1 100644 --- a/clang/test/SemaCXX/cxx2a-explicit-bool.cpp +++ b/clang/test/SemaCXX/cxx2a-explicit-bool.cpp @@ -20,7 +20,7 @@ namespace special_cases  template<int a>  struct A {  // expected-note@-1+ {{candidate constructor}} -  explicit(1 << a) +  explicit(1 << a)  // expected-warning {{converting the result of '<<' to a boolean; did you mean '(1 << -1) != 0'?}}  // expected-note@-1 {{negative shift count -1}}  // expected-error@-2 {{explicit specifier argument is not a constant expression}}    A(int);  | 

