[-Wunreachable-code] Tweak heuristic for configuration values to include arithmetic operations involving sizeof(), but not raw integers.

This case was motivated by a false positive with the
llvm::AlignOf<> specialization in LLVM.

llvm-svn: 203363
This commit is contained in:
Ted Kremenek 2014-03-08 23:20:11 +00:00
parent b97112e4bd
commit c980afc578
2 changed files with 35 additions and 6 deletions

View File

@ -189,7 +189,8 @@ static bool isExpandedFromConfigurationMacro(const Stmt *S) {
/// "sometimes unreachable" code. Such code is usually not interesting /// "sometimes unreachable" code. Such code is usually not interesting
/// to report as unreachable, and may mask truly unreachable code within /// to report as unreachable, and may mask truly unreachable code within
/// those blocks. /// those blocks.
static bool isConfigurationValue(const Stmt *S) { static bool isConfigurationValue(const Stmt *S,
bool IncludeIntegers = true) {
if (!S) if (!S)
return false; return false;
@ -201,7 +202,7 @@ static bool isConfigurationValue(const Stmt *S) {
const DeclRefExpr *DR = cast<DeclRefExpr>(S); const DeclRefExpr *DR = cast<DeclRefExpr>(S);
const ValueDecl *D = DR->getDecl(); const ValueDecl *D = DR->getDecl();
if (const EnumConstantDecl *ED = dyn_cast<EnumConstantDecl>(D)) if (const EnumConstantDecl *ED = dyn_cast<EnumConstantDecl>(D))
return ED ? isConfigurationValue(ED->getInitExpr()) : false; return isConfigurationValue(ED->getInitExpr());
if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
// As a heuristic, treat globals as configuration values. Note // As a heuristic, treat globals as configuration values. Note
// that we only will get here if Sema evaluated this // that we only will get here if Sema evaluated this
@ -215,14 +216,18 @@ static bool isConfigurationValue(const Stmt *S) {
return false; return false;
} }
case Stmt::IntegerLiteralClass: case Stmt::IntegerLiteralClass:
return isExpandedFromConfigurationMacro(S); return IncludeIntegers ? isExpandedFromConfigurationMacro(S)
: false;
case Stmt::UnaryExprOrTypeTraitExprClass: case Stmt::UnaryExprOrTypeTraitExprClass:
return true; return true;
case Stmt::BinaryOperatorClass: { case Stmt::BinaryOperatorClass: {
const BinaryOperator *B = cast<BinaryOperator>(S); const BinaryOperator *B = cast<BinaryOperator>(S);
return (B->isLogicalOp() || B->isComparisonOp()) && // Only include raw integers (not enums) as configuration
(isConfigurationValue(B->getLHS()) || // values if they are used in a logical or comparison operator
isConfigurationValue(B->getRHS())); // (not arithmetic).
IncludeIntegers &= (B->isLogicalOp() || B->isComparisonOp());
return isConfigurationValue(B->getLHS(), IncludeIntegers) ||
isConfigurationValue(B->getRHS(), IncludeIntegers);
} }
case Stmt::UnaryOperatorClass: { case Stmt::UnaryOperatorClass: {
const UnaryOperator *UO = cast<UnaryOperator>(S); const UnaryOperator *UO = cast<UnaryOperator>(S);

View File

@ -175,3 +175,27 @@ void raze(const A& x);
void test_with_unreachable_tmp_dtors(int x) { void test_with_unreachable_tmp_dtors(int x) {
raze(x ? A() : A()); // no-warning raze(x ? A() : A()); // no-warning
} }
// Test sizeof - sizeof in enum declaration.
enum { BrownCow = sizeof(long) - sizeof(char) };
enum { CowBrown = 8 - 1 };
int test_enum_sizeof_arithmetic() {
if (BrownCow)
return 1;
return 2;
}
int test_enum_arithmetic() {
if (CowBrown)
return 1;
return 2; // expected-warning {{never be executed}}
}
int test_arithmetic() {
if (8 -1)
return 1;
return 2; // expected-warning {{never be executed}}
}