]> granicus.if.org Git - clang/commitdiff
[-Wunreachable-code] Look through member accesses for 'static const bool' configurati...
authorTed Kremenek <kremenek@apple.com>
Thu, 20 Mar 2014 06:44:35 +0000 (06:44 +0000)
committerTed Kremenek <kremenek@apple.com>
Thu, 20 Mar 2014 06:44:35 +0000 (06:44 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@204315 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Analysis/ReachableCode.cpp
test/SemaCXX/warn-unreachable.cpp

index ffe576cd0524c72e525030f2aa0325efedd118ca..0a9e82bb0ada1b6d64a08d57615350a6646347b3 100644 (file)
@@ -122,6 +122,8 @@ static bool isExpandedFromConfigurationMacro(const Stmt *S,
   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
@@ -144,34 +146,15 @@ static bool isConfigurationValue(const Stmt *S,
         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: {
@@ -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.
 static bool shouldTreatSuccessorsAsReachable(const CFGBlock *B,
                                              Preprocessor &PP) {
index 9db75926d23e38049cdff66680b1c994dadf1903..7f74732a630eee8013cf2f3a12a4cd2277e3829c 100644 (file)
@@ -236,22 +236,41 @@ Frobozz test_return_object_control_flow(int flag) {
 
 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
+}