return false;
}
+static bool isConfigurationValue(const ValueDecl *D, Preprocessor &PP);
+
/// Returns true if the statement represents a configuration value.
///
/// A configuration value is something usually determined at compile-time
dyn_cast_or_null<FunctionDecl>(cast<CallExpr>(S)->getCalleeDecl());
return Callee ? Callee->isConstexpr() : false;
}
- case Stmt::DeclRefExprClass: {
- const DeclRefExpr *DR = cast<DeclRefExpr>(S);
- 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::DeclRefExprClass:
+ return isConfigurationValue(cast<DeclRefExpr>(S)->getDecl(), PP);
case Stmt::IntegerLiteralClass:
return IncludeIntegers ? isExpandedFromConfigurationMacro(S, PP)
: false;
+ case Stmt::MemberExprClass:
+ return isConfigurationValue(cast<MemberExpr>(S)->getMemberDecl(), PP);
case Stmt::ObjCBoolLiteralExprClass:
return isExpandedFromConfigurationMacro(S, PP, /* IgnoreYES_NO */ true);
-
case Stmt::UnaryExprOrTypeTraitExprClass:
return true;
case Stmt::BinaryOperatorClass: {
}
}
+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.
static bool shouldTreatSuccessorsAsReachable(const CFGBlock *B,
Preprocessor &PP) {
void somethingToCall();
- static constexpr bool isConstExprConfigValue() { return true; }
-
- int test_const_expr_config_value() {
- if (isConstExprConfigValue()) {
- somethingToCall();
- return 0;
- }
- somethingToCall(); // no-warning
- return 1;
- }
- int test_const_expr_config_value_2() {
- if (!isConstExprConfigValue()) {
- somethingToCall(); // no-warning
- return 0;
- }
+static constexpr bool isConstExprConfigValue() { return true; }
+
+int test_const_expr_config_value() {
+ if (isConstExprConfigValue()) {
somethingToCall();
- return 1;
+ return 0;
}
+ somethingToCall(); // no-warning
+ return 1;
+}
+int test_const_expr_config_value_2() {
+ if (!isConstExprConfigValue()) {
+ somethingToCall(); // no-warning
+ return 0;
+ }
+ somethingToCall();
+ 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
+}