diff options
author | Sebastian Redl <sebastian.redl@getdesigned.at> | 2009-10-26 15:24:15 +0000 |
---|---|---|
committer | Sebastian Redl <sebastian.redl@getdesigned.at> | 2009-10-26 15:24:15 +0000 |
commit | 9e1d29bb369530c15230e4c92aa67239c283ece2 (patch) | |
tree | aabef2c8556c5b94ed52219e33cc1686bb28b92b | |
parent | 8d737cc78cb28f39179d6c7ca00eb5d3cf563129 (diff) |
Implement a warning for mixing bitwise logical with comparison ops. Fixes PR5297.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@85117 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.td | 4 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 50 | ||||
-rw-r--r-- | test/Sema/parentheses.c | 19 |
3 files changed, 73 insertions, 0 deletions
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index c553998146..033c90c538 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -1385,6 +1385,10 @@ def warn_shift_negative : Warning< def warn_shift_gt_typewidth : Warning< "shift count >= width of type">; +def warn_precedence_bitwise_rel : Warning< + "%0 has lower precedence than %1; %1 will be evaluated first">, + InGroup<Parentheses>; + def err_sizeof_nonfragile_interface : Error< "invalid application of '%select{alignof|sizeof}1' to interface %0 in " "non-fragile ABI">; diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 78647e392f..84a430ab52 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -5412,6 +5412,53 @@ Action::OwningExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, OpLoc)); } +static inline bool IsBitwise(int Opc) { + return Opc >= BinaryOperator::And && Opc <= BinaryOperator::Or; +} +static inline bool IsEqOrRel(int Opc) { + return Opc >= BinaryOperator::LT && Opc <= BinaryOperator::NE; +} + +static void DiagnoseBitwisePrecedence(Sema &Self, BinaryOperator::Opcode Opc, + SourceLocation OpLoc,Expr *lhs,Expr *rhs){ + typedef BinaryOperator::Opcode Opcode; + int lhsopc = -1, rhsopc = -1; + if (BinaryOperator *BO = dyn_cast<BinaryOperator>(lhs)) + lhsopc = BO->getOpcode(); + if (BinaryOperator *BO = dyn_cast<BinaryOperator>(rhs)) + rhsopc = BO->getOpcode(); + + // Subs are not binary operators. + if (lhsopc == -1 && rhsopc == -1) + return; + + // Bitwise operations are sometimes used as eager logical ops. + // Don't diagnose this. + if ((IsEqOrRel(lhsopc) || IsBitwise(lhsopc)) && + (IsEqOrRel(rhsopc) || IsBitwise(rhsopc))) + return; + + if (IsEqOrRel(lhsopc)) + Self.Diag(OpLoc, diag::warn_precedence_bitwise_rel) + << SourceRange(lhs->getLocStart(), OpLoc) + << BinaryOperator::getOpcodeStr(Opc) + << BinaryOperator::getOpcodeStr(static_cast<Opcode>(lhsopc)); + else if (IsEqOrRel(rhsopc)) + Self.Diag(OpLoc, diag::warn_precedence_bitwise_rel) + << SourceRange(OpLoc, rhs->getLocEnd()) + << BinaryOperator::getOpcodeStr(Opc) + << BinaryOperator::getOpcodeStr(static_cast<Opcode>(rhsopc)); +} + +/// DiagnoseBinOpPrecedence - Emit warnings for expressions with tricky +/// precedence. This currently diagnoses only "arg1 'bitwise' arg2 'eq' arg3". +/// But it could also warn about arg1 && arg2 || arg3, as GCC 4.3+ does. +static void DiagnoseBinOpPrecedence(Sema &Self, BinaryOperator::Opcode Opc, + SourceLocation OpLoc, Expr *lhs, Expr *rhs){ + if (IsBitwise(Opc)) + DiagnoseBitwisePrecedence(Self, Opc, OpLoc, lhs, rhs); +} + // Binary Operators. 'Tok' is the token for the operator. Action::OwningExprResult Sema::ActOnBinOp(Scope *S, SourceLocation TokLoc, tok::TokenKind Kind, @@ -5422,6 +5469,9 @@ Action::OwningExprResult Sema::ActOnBinOp(Scope *S, SourceLocation TokLoc, assert((lhs != 0) && "ActOnBinOp(): missing left expression"); assert((rhs != 0) && "ActOnBinOp(): missing right expression"); + // Emit warnings for tricky precedence issues, e.g. "bitfield & 0x4 == 0" + DiagnoseBinOpPrecedence(*this, Opc, TokLoc, lhs, rhs); + if (getLangOptions().CPlusPlus && (lhs->getType()->isOverloadableType() || rhs->getType()->isOverloadableType())) { diff --git a/test/Sema/parentheses.c b/test/Sema/parentheses.c new file mode 100644 index 0000000000..360aade837 --- /dev/null +++ b/test/Sema/parentheses.c @@ -0,0 +1,19 @@ +// RUN: clang-cc -Wparentheses -fsyntax-only -verify %s + +// Test the various warnings under -Wparentheses +void if_assign(void) { + int i; + if (i = 4) {} // expected-warning {{assignment as a condition}} + if ((i = 4)) {} +} + +void bitwise_rel(unsigned i) { + (void)(i & 0x2 == 0); // expected-warning {{& has lower precedence than ==}} + (void)(0 == i & 0x2); // expected-warning {{& has lower precedence than ==}} + (void)(i & 0xff < 30); // expected-warning {{& has lower precedence than <}} + (void)((i & 0x2) == 0); + (void)(i & (0x2 == 0)); + // Eager logical op + (void)(i == 1 | i == 2 | i == 3); + (void)(i != 1 & i != 2 & i != 3); +} |