]> granicus.if.org Git - clang/commitdiff
Teach Wreturn-type, Wunreachable-code, and alpha.deadcode.UnreachableCode to treat...
authorNico Weber <nicolasweber@gmx.de>
Tue, 13 Feb 2018 21:31:47 +0000 (21:31 +0000)
committerNico Weber <nicolasweber@gmx.de>
Tue, 13 Feb 2018 21:31:47 +0000 (21:31 +0000)
Fixes PR29134.
https://reviews.llvm.org/D43221

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@325052 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/Expr.h
lib/AST/Expr.cpp
lib/Analysis/CFG.cpp
lib/Analysis/ReachableCode.cpp
lib/StaticAnalyzer/Checkers/UnreachableCodeChecker.cpp
test/Analysis/unreachable-code-path.c
test/Sema/return.c
test/Sema/warn-unreachable.c

index 9d7a29e909f9b9d788744ed45f047d059ca43f48..247850c62cd5c93ac0d4d21d5a36d2e0b1b6bd18 100644 (file)
@@ -2357,6 +2357,10 @@ public:
   SourceLocation getLocStart() const LLVM_READONLY;
   SourceLocation getLocEnd() const LLVM_READONLY;
 
+  /// Return true if this is a call to __assume() or __builtin_assume() with
+  /// a non-value-dependent constant parameter evaluating as false.
+  bool isBuiltinAssumeFalse(const ASTContext &Ctx) const;
+
   bool isCallToStdMove() const {
     const FunctionDecl* FD = getDirectCallee();
     return getNumArgs() == 1 && FD && FD->isInStdNamespace() &&
index 7ddab9356b54a5d6675c307dd1c15ac04279571f..66f61708c5ab6274030bdb09d873ee64630ae7b6 100644 (file)
@@ -2917,6 +2917,18 @@ bool Expr::isConstantInitializer(ASTContext &Ctx, bool IsForRef,
   return false;
 }
 
+bool CallExpr::isBuiltinAssumeFalse(const ASTContext &Ctx) const {
+  const FunctionDecl* FD = getDirectCallee();
+  if (!FD || (FD->getBuiltinID() != Builtin::BI__assume &&
+              FD->getBuiltinID() != Builtin::BI__builtin_assume))
+    return false;
+  
+  const Expr* Arg = getArg(0);
+  bool ArgVal;
+  return !Arg->isValueDependent() &&
+         Arg->EvaluateAsBooleanCondition(ArgVal, Ctx) && !ArgVal;
+}
+
 namespace {
   /// \brief Look for any side effects within a Stmt.
   class SideEffectFinder : public ConstEvaluatedExprVisitor<SideEffectFinder> {
index cec5a652b94aeb3f885529bad98376b23104c863..9fe9ad11bf38a75e772e855194bd89a30d2fbec7 100644 (file)
@@ -2134,7 +2134,7 @@ CFGBlock *CFGBuilder::VisitCallExpr(CallExpr *C, AddStmtChoice asc) {
   bool OmitArguments = false;
 
   if (FunctionDecl *FD = C->getDirectCallee()) {
-    if (FD->isNoReturn())
+    if (FD->isNoReturn() || C->isBuiltinAssumeFalse(*Context))
       NoReturn = true;
     if (FD->hasAttr<NoThrowAttr>())
       AddEHEdge = false;
index 7e72795a47f6964b982d180b935d5586133df0c2..f644d503dc4908f76ac092c940bc59ab6510e0c4 100644 (file)
@@ -66,6 +66,21 @@ static bool isBuiltinUnreachable(const Stmt *S) {
   return false;
 }
 
+static bool isBuiltinAssumeFalse(const CFGBlock *B, const Stmt *S,
+                                 ASTContext &C) {
+  if (B->empty())  {
+    // Happens if S is B's terminator and B contains nothing else
+    // (e.g. a CFGBlock containing only a goto).
+    return false;
+  }
+  if (Optional<CFGStmt> CS = B->back().getAs<CFGStmt>()) {
+    if (const auto *CE = dyn_cast<CallExpr>(CS->getStmt())) {
+      return CE->getCallee()->IgnoreCasts() == S && CE->isBuiltinAssumeFalse(C);
+    }
+  }
+  return false;
+}
+
 static bool isDeadReturn(const CFGBlock *B, const Stmt *S) {
   // Look to see if the current control flow ends with a 'return', and see if
   // 'S' is a substatement. The 'return' may not be the last element in the
@@ -372,6 +387,7 @@ namespace {
     llvm::BitVector &Reachable;
     SmallVector<const CFGBlock *, 10> WorkList;
     Preprocessor &PP;
+    ASTContext &C;
 
     typedef SmallVector<std::pair<const CFGBlock *, const Stmt *>, 12>
     DeferredLocsTy;
@@ -379,10 +395,10 @@ namespace {
     DeferredLocsTy DeferredLocs;
 
   public:
-    DeadCodeScan(llvm::BitVector &reachable, Preprocessor &PP)
+    DeadCodeScan(llvm::BitVector &reachable, Preprocessor &PP, ASTContext &C)
     : Visited(reachable.size()),
       Reachable(reachable),
-      PP(PP) {}
+      PP(PP), C(C) {}
 
     void enqueue(const CFGBlock *block);
     unsigned scanBackwards(const CFGBlock *Start,
@@ -600,7 +616,8 @@ void DeadCodeScan::reportDeadCode(const CFGBlock *B,
 
   if (isa<BreakStmt>(S)) {
     UK = reachable_code::UK_Break;
-  } else if (isTrivialDoWhile(B, S) || isBuiltinUnreachable(S)) {
+  } else if (isTrivialDoWhile(B, S) || isBuiltinUnreachable(S) ||
+             isBuiltinAssumeFalse(B, S, C)) {
     return;
   }
   else if (isDeadReturn(B, S)) {
@@ -693,7 +710,7 @@ void FindUnreachableCode(AnalysisDeclContext &AC, Preprocessor &PP,
     if (reachable[block->getBlockID()])
       continue;
     
-    DeadCodeScan DS(reachable, PP);
+    DeadCodeScan DS(reachable, PP, AC.getASTContext());
     numReachable += DS.scanBackwards(block, CB);
     
     if (numReachable == cfg->getNumBlockIDs())
index 6f21e868b17424fa3079b4082b45fb5fa0a64f33..dbd12cc9b65afe9dab844d481d7a82a97c0f7b42 100644 (file)
@@ -132,7 +132,8 @@ void UnreachableCodeChecker::checkEndAnalysis(ExplodedGraph &G,
            ci != ce; ++ci) {
         if (Optional<CFGStmt> S = (*ci).getAs<CFGStmt>())
           if (const CallExpr *CE = dyn_cast<CallExpr>(S->getStmt())) {
-            if (CE->getBuiltinCallee() == Builtin::BI__builtin_unreachable) {
+            if (CE->getBuiltinCallee() == Builtin::BI__builtin_unreachable ||
+                CE->isBuiltinAssumeFalse(Eng.getContext())) {
               foundUnreachable = true;
               break;
             }
index effa4d9bfa6f4e72e42cb8d85749746c910f7a2f..95cc4eab50db432602373086877f5249cac36202 100644 (file)
@@ -63,6 +63,7 @@ void test6(const char *c) {
   if (c) return;
   if (!c) return;
   __builtin_unreachable(); // no-warning
+  __builtin_assume(0); // no-warning
 }
 
 // Compile-time constant false positives
index 2a58a6ef9e4702638e0701666acb2ae23d6a862b..debf5ab55f5b5b0530f173df730ee7bdbb0d1717 100644 (file)
@@ -283,6 +283,18 @@ lbl:
     goto lbl;
 }
 
+int test36a(int b) {
+  if (b)
+    return 43;
+  __builtin_unreachable();
+}
+
+int test36b(int b) {
+  if (b)
+    return 43;
+  __builtin_assume(0);
+}
+
 // PR19074.
 void abort(void) __attribute__((noreturn));
 #define av_assert0(cond) do {\
index 440aa0a5a174ca1ce586c0f21ed5dbebdfb54290..aec3b070213c72de262800d6ad9ba69c39d79c11 100644 (file)
@@ -468,6 +468,7 @@ int pr13910_foo(int x) {
   else
     return x;
   __builtin_unreachable(); // expected no warning
+  __builtin_assume(0); // expected no warning
 }
 
 int pr13910_bar(int x) {
@@ -485,16 +486,19 @@ int pr13910_bar2(int x) {
     return x;
   pr13910_foo(x);          // expected-warning {{code will never be executed}}
   __builtin_unreachable(); // expected no warning
+  __builtin_assume(0);     // expected no warning
   pr13910_foo(x);          // expected-warning {{code will never be executed}}
 }
 
 void pr13910_noreturn() {
   raze();
   __builtin_unreachable(); // expected no warning
+  __builtin_assume(0); // expected no warning
 }
 
 void pr13910_assert() {
   myassert(0 && "unreachable");
   return;
   __builtin_unreachable(); // expected no warning
+  __builtin_assume(0); // expected no warning
 }