зеркало из https://github.com/microsoft/clang-1.git
Make noreturn functions alter the CFG.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@76133 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
808825cd08
Коммит
cd7bf230a7
|
@ -117,9 +117,9 @@ public:
|
|||
CFGBlock* VisitStmt(Stmt* Statement);
|
||||
CFGBlock* VisitSwitchStmt(SwitchStmt* Terminator);
|
||||
CFGBlock* VisitWhileStmt(WhileStmt* W);
|
||||
|
||||
|
||||
// FIXME: Add support for ObjC-specific control-flow structures.
|
||||
|
||||
|
||||
// NYS == Not Yet Supported
|
||||
CFGBlock* NYS() {
|
||||
badCFG = true;
|
||||
|
@ -280,7 +280,7 @@ CFGBlock* CFGBuilder::addStmt(Stmt* Terminator) {
|
|||
/// WalkAST - Used by addStmt to walk the subtree of a statement and
|
||||
/// add extra blocks for ternary operators, &&, and ||. We also
|
||||
/// process "," and DeclStmts (which may contain nested control-flow).
|
||||
CFGBlock* CFGBuilder::WalkAST(Stmt* Terminator, bool AlwaysAddStmt = false) {
|
||||
CFGBlock* CFGBuilder::WalkAST(Stmt* Terminator, bool AlwaysAddStmt = false) {
|
||||
switch (Terminator->getStmtClass()) {
|
||||
case Stmt::ConditionalOperatorClass: {
|
||||
ConditionalOperator* C = cast<ConditionalOperator>(Terminator);
|
||||
|
@ -478,6 +478,36 @@ CFGBlock* CFGBuilder::WalkAST(Stmt* Terminator, bool AlwaysAddStmt = false) {
|
|||
case Stmt::ParenExprClass:
|
||||
return WalkAST(cast<ParenExpr>(Terminator)->getSubExpr(), AlwaysAddStmt);
|
||||
|
||||
case Stmt::CallExprClass: {
|
||||
bool NoReturn = false;
|
||||
CallExpr *C = cast<CallExpr>(Terminator);
|
||||
Expr *CEE = C->getCallee()->IgnoreParenCasts();
|
||||
if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(CEE)) {
|
||||
// FIXME: We can follow objective-c methods and C++ member functions...
|
||||
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(DRE->getDecl())) {
|
||||
if (FD->hasAttr<NoReturnAttr>())
|
||||
NoReturn = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!NoReturn)
|
||||
break;
|
||||
|
||||
if (Block) {
|
||||
if (!FinishBlock(Block))
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Create new block with no successor for the remaining pieces.
|
||||
Block = createBlock(false);
|
||||
Block->appendStmt(Terminator);
|
||||
|
||||
// Wire this to the exit block directly.
|
||||
Block->addSuccessor(&cfg->getExit());
|
||||
|
||||
return WalkAST_VisitChildren(Terminator);
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
};
|
||||
|
@ -1190,7 +1220,7 @@ CFGBlock* CFGBuilder::VisitBreakStmt(BreakStmt* B) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
// Now create a new block that ends with the continue statement.
|
||||
// Now create a new block that ends with the break statement.
|
||||
Block = createBlock(false);
|
||||
Block->setTerminator(B);
|
||||
|
||||
|
|
|
@ -138,7 +138,8 @@ int f17() {
|
|||
|
||||
// <rdar://problem/6506065>
|
||||
// The values of dead stores are only "consumed" in an enclosing expression
|
||||
// what that value is actually used. In other words, don't say "Although the value stored to 'x' is used...".
|
||||
// what that value is actually used. In other words, don't say "Although the
|
||||
// value stored to 'x' is used...".
|
||||
int f18() {
|
||||
int x = 0; // no-warning
|
||||
if (1)
|
||||
|
@ -173,3 +174,14 @@ void f20(void) {
|
|||
#pragma unused(x)
|
||||
}
|
||||
|
||||
void halt() __attribute__((noreturn));
|
||||
int f21() {
|
||||
int x = 4;
|
||||
|
||||
++x; // expected-warning{{never read}}
|
||||
if (1) {
|
||||
halt();
|
||||
(void)x;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче