Teach Wreturn-type, Wunreachable-code, and alpha.deadcode.UnreachableCode to treat __assume(0) like __builtin_unreachable.

Fixes PR29134.
https://reviews.llvm.org/D43221

llvm-svn: 325052
This commit is contained in:
Nico Weber 2018-02-13 21:31:47 +00:00
parent fdb3b036cc
commit 758fbacea5
8 changed files with 57 additions and 6 deletions

View 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() &&

View 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> {

View 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;

View 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())

View 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;
}

View 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

View 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 {\

View 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
}