зеркало из https://github.com/microsoft/clang.git
Add noreturn support for blocks.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@77377 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
fa9f8b4cf9
Коммит
5692586ae5
|
@ -110,6 +110,10 @@ def warn_maybe_falloff_nonvoid_function : Warning<
|
|||
def warn_falloff_nonvoid_function : Warning<
|
||||
"control reaches end of non-void function">,
|
||||
InGroup<ReturnType>;
|
||||
def err_maybe_falloff_nonvoid_block : Error<
|
||||
"control may reach end of non-void block">;
|
||||
def err_falloff_nonvoid_block : Error<
|
||||
"control reaches end of non-void block">;
|
||||
|
||||
/// Built-in functions.
|
||||
def ext_implicit_lib_function_decl : ExtWarn<
|
||||
|
|
|
@ -802,8 +802,9 @@ public:
|
|||
SourceLocation MemberLoc,
|
||||
IdentifierInfo &Member);
|
||||
|
||||
/// Helpers for dealing with functions.
|
||||
/// Helpers for dealing with blocks and functions.
|
||||
void CheckFallThroughForFunctionDef(Decl *D, Stmt *Body);
|
||||
void CheckFallThroughForBlock(QualType BlockTy, Stmt *Body);
|
||||
bool CheckParmsForFunctionDef(FunctionDecl *FD);
|
||||
void CheckCXXDefaultArguments(FunctionDecl *FD);
|
||||
void CheckExtraCXXDefaultArguments(Declarator &D);
|
||||
|
|
|
@ -1124,8 +1124,8 @@ Sema::ControlFlowKind Sema::CheckFallThrough(Stmt *Root) {
|
|||
|
||||
/// CheckFallThroughForFunctionDef - Check that we don't fall off the end of a
|
||||
/// function that should return a value. Check that we don't fall off the end
|
||||
/// of a noreturn function. We assume that functions not marked noreturn will
|
||||
/// return.
|
||||
/// of a noreturn function. We assume that functions and blocks not marked
|
||||
/// noreturn will return.
|
||||
void Sema::CheckFallThroughForFunctionDef(Decl *D, Stmt *Body) {
|
||||
// FIXME: Would be nice if we had a better way to control cascading errors,
|
||||
// but for now, avoid them. The problem is that when Parse sees:
|
||||
|
@ -1175,6 +1175,51 @@ void Sema::CheckFallThroughForFunctionDef(Decl *D, Stmt *Body) {
|
|||
}
|
||||
}
|
||||
|
||||
/// CheckFallThroughForBlock - Check that we don't fall off the end of a block
|
||||
/// that should return a value. Check that we don't fall off the end of a
|
||||
/// noreturn block. We assume that functions and blocks not marked noreturn
|
||||
/// will return.
|
||||
void Sema::CheckFallThroughForBlock(QualType BlockTy, Stmt *Body) {
|
||||
// FIXME: Would be nice if we had a better way to control cascading errors,
|
||||
// but for now, avoid them. The problem is that when Parse sees:
|
||||
// int foo() { return a; }
|
||||
// The return is eaten and the Sema code sees just:
|
||||
// int foo() { }
|
||||
// which this code would then warn about.
|
||||
if (getDiagnostics().hasErrorOccurred())
|
||||
return;
|
||||
bool ReturnsVoid = false;
|
||||
bool HasNoReturn = false;
|
||||
if (const FunctionType *FT = BlockTy->getPointeeType()->getAsFunctionType()) {
|
||||
if (FT->getResultType()->isVoidType())
|
||||
ReturnsVoid = true;
|
||||
if (FT->getNoReturnAttr())
|
||||
HasNoReturn = true;
|
||||
}
|
||||
|
||||
if (ReturnsVoid && !HasNoReturn)
|
||||
return;
|
||||
// FIXME: Funtion try block
|
||||
if (CompoundStmt *Compound = dyn_cast<CompoundStmt>(Body)) {
|
||||
switch (CheckFallThrough(Body)) {
|
||||
case MaybeFallThrough:
|
||||
if (HasNoReturn)
|
||||
Diag(Compound->getRBracLoc(), diag::err_noreturn_block_has_return_expr);
|
||||
else if (!ReturnsVoid)
|
||||
Diag(Compound->getRBracLoc(), diag::err_maybe_falloff_nonvoid_block);
|
||||
break;
|
||||
case AlwaysFallThrough:
|
||||
if (HasNoReturn)
|
||||
Diag(Compound->getRBracLoc(), diag::err_noreturn_block_has_return_expr);
|
||||
else if (!ReturnsVoid)
|
||||
Diag(Compound->getRBracLoc(), diag::err_falloff_nonvoid_block);
|
||||
break;
|
||||
case NeverFallThrough:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// CheckParmsForFunctionDef - Check that the parameters of the given
|
||||
/// function are appropriate for the definition of a function. This
|
||||
/// takes care of any checks that cannot be performed on the
|
||||
|
|
|
@ -5490,12 +5490,15 @@ Sema::OwningExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
|
|||
for (unsigned i = 0, e = BSI->Params.size(); i != e; ++i)
|
||||
ArgTypes.push_back(BSI->Params[i]->getType());
|
||||
|
||||
bool NoReturn = BSI->TheDecl->getAttr<NoReturnAttr>();
|
||||
QualType BlockTy;
|
||||
if (!BSI->hasPrototype)
|
||||
BlockTy = Context.getFunctionType(RetTy, 0, 0, false, 0);
|
||||
BlockTy = Context.getFunctionType(RetTy, 0, 0, false, 0, false, false, 0, 0,
|
||||
NoReturn);
|
||||
else
|
||||
BlockTy = Context.getFunctionType(RetTy, ArgTypes.data(), ArgTypes.size(),
|
||||
BSI->isVariadic, 0);
|
||||
BSI->isVariadic, 0, false, false, 0, 0,
|
||||
NoReturn);
|
||||
|
||||
// FIXME: Check that return/parameter types are complete/non-abstract
|
||||
DiagnoseUnusedParameters(BSI->Params.begin(), BSI->Params.end());
|
||||
|
@ -5507,6 +5510,7 @@ Sema::OwningExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
|
|||
CurFunctionNeedsScopeChecking = BSI->SavedFunctionNeedsScopeChecking;
|
||||
|
||||
BSI->TheDecl->setBody(body.takeAs<CompoundStmt>());
|
||||
CheckFallThroughForBlock(BlockTy, BSI->TheDecl->getBody());
|
||||
return Owned(new (Context) BlockExpr(BSI->TheDecl, BlockTy,
|
||||
BSI->hasBlockDeclRefExprs));
|
||||
}
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
// RUN: clang-cc -fsyntax-only %s -verify -fblocks
|
||||
|
||||
int j;
|
||||
void foo() {
|
||||
^ (void) { if (j) return 1; }(); // expected-error {{control may reach end of non-void block}}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
// RUN: clang-cc -fsyntax-only %s -verify -fblocks
|
||||
|
||||
void foo() {
|
||||
^ (void) __attribute__((noreturn)) { }(); // expected-error {{block declared 'noreturn' should not return}}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
// RUN: clang-cc -fsyntax-only %s -verify -fblocks
|
||||
|
||||
void foo() {
|
||||
^ int (void) { }(); // expected-error {{control reaches end of non-void block}}
|
||||
}
|
Загрузка…
Ссылка в новой задаче