[-Wunreachable-code] Look through member accesses for 'static const bool' configuration values.

llvm-svn: 204315
This commit is contained in:
Ted Kremenek 2014-03-20 06:44:35 +00:00
parent 798e548955
commit f5ae0bc671
2 changed files with 64 additions and 41 deletions

View File

@ -122,6 +122,8 @@ static bool isExpandedFromConfigurationMacro(const Stmt *S,
return false; return false;
} }
static bool isConfigurationValue(const ValueDecl *D, Preprocessor &PP);
/// Returns true if the statement represents a configuration value. /// Returns true if the statement represents a configuration value.
/// ///
/// A configuration value is something usually determined at compile-time /// A configuration value is something usually determined at compile-time
@ -144,34 +146,15 @@ static bool isConfigurationValue(const Stmt *S,
dyn_cast_or_null<FunctionDecl>(cast<CallExpr>(S)->getCalleeDecl()); dyn_cast_or_null<FunctionDecl>(cast<CallExpr>(S)->getCalleeDecl());
return Callee ? Callee->isConstexpr() : false; return Callee ? Callee->isConstexpr() : false;
} }
case Stmt::DeclRefExprClass: { case Stmt::DeclRefExprClass:
const DeclRefExpr *DR = cast<DeclRefExpr>(S); return isConfigurationValue(cast<DeclRefExpr>(S)->getDecl(), PP);
const ValueDecl *D = DR->getDecl();
if (const EnumConstantDecl *ED = dyn_cast<EnumConstantDecl>(D))
return isConfigurationValue(ED->getInitExpr(), PP);
if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
// As a heuristic, treat globals as configuration values. Note
// that we only will get here if Sema evaluated this
// condition to a constant expression, which means the global
// had to be declared in a way to be a truly constant value.
// We could generalize this to local variables, but it isn't
// clear if those truly represent configuration values that
// gate unreachable code.
if (!VD->hasLocalStorage())
return true;
// As a heuristic, locals that have been marked 'const' explicitly
// can be treated as configuration values as well.
return VD->getType().isLocalConstQualified();
}
return false;
}
case Stmt::IntegerLiteralClass: case Stmt::IntegerLiteralClass:
return IncludeIntegers ? isExpandedFromConfigurationMacro(S, PP) return IncludeIntegers ? isExpandedFromConfigurationMacro(S, PP)
: false; : false;
case Stmt::MemberExprClass:
return isConfigurationValue(cast<MemberExpr>(S)->getMemberDecl(), PP);
case Stmt::ObjCBoolLiteralExprClass: case Stmt::ObjCBoolLiteralExprClass:
return isExpandedFromConfigurationMacro(S, PP, /* IgnoreYES_NO */ true); return isExpandedFromConfigurationMacro(S, PP, /* IgnoreYES_NO */ true);
case Stmt::UnaryExprOrTypeTraitExprClass: case Stmt::UnaryExprOrTypeTraitExprClass:
return true; return true;
case Stmt::BinaryOperatorClass: { case Stmt::BinaryOperatorClass: {
@ -193,6 +176,27 @@ static bool isConfigurationValue(const Stmt *S,
} }
} }
static bool isConfigurationValue(const ValueDecl *D, Preprocessor &PP) {
if (const EnumConstantDecl *ED = dyn_cast<EnumConstantDecl>(D))
return isConfigurationValue(ED->getInitExpr(), PP);
if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
// As a heuristic, treat globals as configuration values. Note
// that we only will get here if Sema evaluated this
// condition to a constant expression, which means the global
// had to be declared in a way to be a truly constant value.
// We could generalize this to local variables, but it isn't
// clear if those truly represent configuration values that
// gate unreachable code.
if (!VD->hasLocalStorage())
return true;
// As a heuristic, locals that have been marked 'const' explicitly
// can be treated as configuration values as well.
return VD->getType().isLocalConstQualified();
}
return false;
}
/// Returns true if we should always explore all successors of a block. /// Returns true if we should always explore all successors of a block.
static bool shouldTreatSuccessorsAsReachable(const CFGBlock *B, static bool shouldTreatSuccessorsAsReachable(const CFGBlock *B,
Preprocessor &PP) { Preprocessor &PP) {

View File

@ -255,3 +255,22 @@ void somethingToCall();
return 1; return 1;
} }
class Frodo {
public:
static const bool aHobbit = true;
};
void test_static_class_var() {
if (Frodo::aHobbit)
somethingToCall();
else
somethingToCall(); // no-warning
}
void test_static_class_var(Frodo &F) {
if (F.aHobbit)
somethingToCall();
else
somethingToCall(); // no-warning
}