Index: include/clang/Basic/DiagnosticGroups.td =================================================================== --- include/clang/Basic/DiagnosticGroups.td +++ include/clang/Basic/DiagnosticGroups.td @@ -764,7 +764,7 @@ def TypeSafety : DiagGroup<"type-safety">; def IncompatibleExceptionSpec : DiagGroup<"incompatible-exception-spec">; - +def IntInBoolContext : DiagGroup<"int-in-bool-context">; def IntToVoidPointerCast : DiagGroup<"int-to-void-pointer-cast">; def IntToPointerCast : DiagGroup<"int-to-pointer-cast", [IntToVoidPointerCast]>; @@ -795,6 +795,7 @@ ForLoopAnalysis, Format, Implicit, + IntInBoolContext, InfiniteRecursion, MismatchedTags, MissingBraces, Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -5605,6 +5605,24 @@ def note_precedence_conditional_first : Note< "place parentheses around the '?:' expression to evaluate it first">; +def warn_mul_in_bool_context : Warning< + "'*' in boolean context">, + InGroup; +def warn_left_shift_in_bool_context : Warning< + "'<<' in boolean context; did you mean '<'?">, + InGroup; +def warn_enum_constant_in_bool_context : Warning< + "enum constant in boolean context">, + InGroup; + +def warn_integer_constants_in_conditional : Warning< + "'?:' with integer constants in boolean context">, + InGroup; +def warn_integer_constants_in_conditional_always_true : Warning< + "'?:' with integer constants in boolean context, the expression will always " + "evaluate to 'true'">, + InGroup; + def warn_logical_instead_of_bitwise : Warning< "use of logical '%0' with constant operand">, InGroup>; Index: lib/Sema/SemaChecking.cpp =================================================================== --- lib/Sema/SemaChecking.cpp +++ lib/Sema/SemaChecking.cpp @@ -11096,6 +11096,42 @@ return true; } +static void DiagnoseIntInBoolContext(Sema &S, const Expr *E) { + E = E->IgnoreParenImpCasts(); + SourceLocation ExprLoc = E->getExprLoc(); + + if (const auto *BO = dyn_cast(E)) { + BinaryOperator::Opcode Opc = BO->getOpcode(); + if (Opc == BO_Mul) + S.Diag(ExprLoc, diag::warn_mul_in_bool_context); + if (Opc == BO_Shl) + S.Diag(ExprLoc, diag::warn_left_shift_in_bool_context); + } + + const auto *DRE = dyn_cast(E); + if (DRE && S.getLangOpts().CPlusPlus) { + const auto *ECD = dyn_cast(DRE->getDecl()); + if (ECD && ECD->getInitVal() != 0 && ECD->getInitVal() != 1) + S.Diag(ExprLoc, diag::warn_enum_constant_in_bool_context); + } + + if (const auto *CO = dyn_cast(E)) { + const auto *LHS = dyn_cast(CO->getTrueExpr()); + const auto *RHS = dyn_cast(CO->getFalseExpr()); + if (LHS && RHS) { + if ((LHS->getValue() == 0 || LHS->getValue() == 1) && + (RHS->getValue() == 0 || RHS->getValue() == 1)) + // Do not diagnose common idioms + return; + if (LHS->getValue() != 0 && LHS->getValue() != 0) + S.Diag(ExprLoc, + diag::warn_integer_constants_in_conditional_always_true); + else + S.Diag(ExprLoc, diag::warn_integer_constants_in_conditional); + } + } +} + static void CheckImplicitConversion(Sema &S, Expr *E, QualType T, SourceLocation CC, bool *ICContext = nullptr) { @@ -11319,6 +11355,9 @@ S.DiscardMisalignedMemberAddress(Target, E); + if (Target->isBooleanType()) + DiagnoseIntInBoolContext(S, E); + if (!Source->isIntegerType() || !Target->isIntegerType()) return; @@ -11517,6 +11556,8 @@ if (isa(E)) { ConditionalOperator *CO = cast(E); CheckConditionalOperator(S, CO, CC, T); + if (T->isBooleanType()) + DiagnoseIntInBoolContext(S, E); return; } Index: test/Analysis/misc-ps.c =================================================================== --- test/Analysis/misc-ps.c +++ test/Analysis/misc-ps.c @@ -96,7 +96,7 @@ extern int nR10376675; void barR10376675(int *x) { int *pm; - if (nR10376675 * 2) { + if (nR10376675 * 2) { // expected-warning {{'*' in boolean context}} int *pk = bazR10376675(); pm = pk; //expected-warning {{never read}} } Index: test/Sema/integer-overflow.c =================================================================== --- test/Sema/integer-overflow.c +++ test/Sema/integer-overflow.c @@ -34,13 +34,13 @@ uint64_t not_overflow2 = (1ULL * ((uint64_t)(4608) * (1024 * 1024)) + 2ULL); // expected-warning@+1 2{{overflow in expression; result is 536870912 with type 'int'}} - overflow = 4608 * 1024 * 1024 ? 4608 * 1024 * 1024 : 0; + overflow = 4608 * 1024 * 1024 ? 4608 * 1024 * 1024 : 0; // expected-warning {{'*' in boolean context}} // expected-warning@+1 {{overflow in expression; result is 536870912 with type 'int'}} overflow = 0 ? 0 : 4608 * 1024 * 1024; // expected-warning@+1 {{overflow in expression; result is 536870912 with type 'int'}} - if (4608 * 1024 * 1024) + if (4608 * 1024 * 1024) // expected-warning {{'*' in boolean context}} return 0; // expected-warning@+1 {{overflow in expression; result is 536870912 with type 'int'}} @@ -83,7 +83,7 @@ } // expected-warning@+1 {{overflow in expression; result is 536870912 with type 'int'}} - while (4608 * 1024 * 1024); + while (4608 * 1024 * 1024); // expected-warning {{'*' in boolean context}} // expected-warning@+1 {{overflow in expression; result is 536870912 with type 'int'}} while ((uint64_t)(4608 * 1024 * 1024)); @@ -101,7 +101,7 @@ while ((uint64_t)((uint64_t)(4608 * 1024 * 1024) * (uint64_t)(4608 * 1024 * 1024))); // expected-warning@+1 {{overflow in expression; result is 536870912 with type 'int'}} - do { } while (4608 * 1024 * 1024); + do { } while (4608 * 1024 * 1024); // expected-warning {{'*' in boolean context}} // expected-warning@+1 {{overflow in expression; result is 536870912 with type 'int'}} do { } while ((uint64_t)(4608 * 1024 * 1024)); Index: test/Sema/parentheses.c =================================================================== --- test/Sema/parentheses.c +++ test/Sema/parentheses.c @@ -119,6 +119,7 @@ // CHECK: fix-it:"{{.*}}":{[[@LINE-5]]:14-[[@LINE-5]]:14}:"(" // CHECK: fix-it:"{{.*}}":{[[@LINE-6]]:23-[[@LINE-6]]:23}:")" + // expected-warning@+1 {{'*' in boolean context}} (void)(x * (x == y) ? 1 : 2); // expected-warning {{operator '?:' has lower precedence than '*'}} \ // expected-note {{place parentheses around the '*' expression to silence this warning}} \ // expected-note {{place parentheses around the '?:' expression to evaluate it first}} Index: test/Sema/parentheses.cpp =================================================================== --- test/Sema/parentheses.cpp +++ test/Sema/parentheses.cpp @@ -20,6 +20,7 @@ // CHECK: fix-it:"{{.*}}":{[[@LINE-5]]:14-[[@LINE-5]]:14}:"(" // CHECK: fix-it:"{{.*}}":{[[@LINE-6]]:23-[[@LINE-6]]:23}:")" + // expected-warning@+1 {{'*' in boolean context}} (void)(x * (x == y) ? 1 : 2); // expected-warning {{operator '?:' has lower precedence than '*'}} \ // expected-note {{place parentheses around the '*' expression to silence this warning}} \ // expected-note {{place parentheses around the '?:' expression to evaluate it first}} Index: test/Sema/warn-unreachable.c =================================================================== --- test/Sema/warn-unreachable.c +++ test/Sema/warn-unreachable.c @@ -141,7 +141,9 @@ void test_mul_and_zero(int x) { if (x & 0) calledFun(); // expected-warning {{will never be executed}} if (0 & x) calledFun(); // expected-warning {{will never be executed}} + // expected-warning@+1 {{'*' in boolean context}} if (x * 0) calledFun(); // expected-warning {{will never be executed}} + // expected-warning@+1 {{'*' in boolean context}} if (0 * x) calledFun(); // expected-warning {{will never be executed}} } Index: test/SemaCXX/constexpr-printing.cpp =================================================================== --- test/SemaCXX/constexpr-printing.cpp +++ test/SemaCXX/constexpr-printing.cpp @@ -99,6 +99,7 @@ a:b:return; } +// expected-warning@+1 {{'*' in boolean context}} constexpr bool test_bool_printing(bool b) { return 1 / !(2*b | !(2*b)); } // expected-note 2{{division by zero}} constexpr bool test_bool_0 = test_bool_printing(false); // expected-error {{constant expr}} expected-note {{in call to 'test_bool_printing(false)'}} constexpr bool test_bool_1 = test_bool_printing(true); // expected-error {{constant expr}} expected-note {{in call to 'test_bool_printing(true)'}} Index: test/SemaCXX/integer-overflow.cpp =================================================================== --- test/SemaCXX/integer-overflow.cpp +++ test/SemaCXX/integer-overflow.cpp @@ -41,13 +41,13 @@ uint64_t not_overflow2 = (1ULL * ((uint64_t)(4608) * (1024 * 1024)) + 2ULL); // expected-warning@+1 2{{overflow in expression; result is 536870912 with type 'int'}} - overflow = 4608 * 1024 * 1024 ? 4608 * 1024 * 1024 : 0; + overflow = 4608 * 1024 * 1024 ? 4608 * 1024 * 1024 : 0; // expected-warning {{'*' in boolean context}} // expected-warning@+1 {{overflow in expression; result is 536870912 with type 'int'}} overflow = 0 ? 0 : 4608 * 1024 * 1024; // expected-warning@+1 {{overflow in expression; result is 536870912 with type 'int'}} - if (4608 * 1024 * 1024) + if (4608 * 1024 * 1024) // expected-warning {{'*' in boolean context}} return 0; // expected-warning@+1 {{overflow in expression; result is 536870912 with type 'int'}} @@ -100,7 +100,7 @@ #endif // expected-warning@+1 {{overflow in expression; result is 536870912 with type 'int'}} - while (4608 * 1024 * 1024); + while (4608 * 1024 * 1024); // expected-warning {{'*' in boolean context}} // expected-warning@+1 {{overflow in expression; result is 536870912 with type 'int'}} while ((uint64_t)(4608 * 1024 * 1024)); @@ -121,7 +121,7 @@ while ((uint64_t)((uint64_t)(4608 * 1024 * 1024) * (uint64_t)(4608 * 1024 * 1024))); // expected-warning@+1 {{overflow in expression; result is 536870912 with type 'int'}} - do { } while (4608 * 1024 * 1024); + do { } while (4608 * 1024 * 1024); // expected-warning {{'*' in boolean context}} // expected-warning@+1 {{overflow in expression; result is 536870912 with type 'int'}} do { } while ((uint64_t)(4608 * 1024 * 1024)); Index: test/SemaCXX/nested-name-spec.cpp =================================================================== --- test/SemaCXX/nested-name-spec.cpp +++ test/SemaCXX/nested-name-spec.cpp @@ -402,9 +402,9 @@ T1 var_1a; T1 var_1b; // expected-error{{unexpected ':' in nested name specifier; did you mean '::'?}} template int F() {} -int (*X1)() = (B1::B2 ? F<1> : F<2>); +int (*X1)() = (B1::B2 ? F<1> : F<2>); // expected-warning {{enum constant in boolean context}} int (*X2)() = (B1:B2 ? F<1> : F<2>); // expected-error{{unexpected ':' in nested name specifier; did you mean '::'?}} - +// expected-warning@-1 {{enum constant in boolean context}} // Bit fields + templates struct S7a { T1::C1 m1 : T1::N1; Index: test/SemaCXX/warn-unreachable.cpp =================================================================== --- test/SemaCXX/warn-unreachable.cpp +++ test/SemaCXX/warn-unreachable.cpp @@ -186,13 +186,13 @@ int test_enum_sizeof_arithmetic() { - if (BrownCow) + if (BrownCow) // expected-warning {{enum constant in boolean context}} return 1; return 2; } int test_enum_arithmetic() { - if (CowBrown) + if (CowBrown) // expected-warning {{enum constant in boolean context}} return 1; return 2; // expected-warning {{never be executed}} }