diff options
author | Mike Stump <mrs@apple.com> | 2009-07-28 22:04:01 +0000 |
---|---|---|
committer | Mike Stump <mrs@apple.com> | 2009-07-28 22:04:01 +0000 |
commit | 5692586ae59be8d49edd7b45dd52c1ffa920ba5e (patch) | |
tree | f4647b56230d466c63ae0385c0ea25828cbd806b | |
parent | fa9f8b4cf962d865c4b430a25aca2fb5faa84337 (diff) |
Add noreturn support for blocks.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@77377 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.td | 4 | ||||
-rw-r--r-- | lib/Sema/Sema.h | 3 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 49 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 8 | ||||
-rw-r--r-- | test/Sema/block-return-1.c | 6 | ||||
-rw-r--r-- | test/Sema/block-return-2.c | 5 | ||||
-rw-r--r-- | test/Sema/block-return-3.c | 5 |
7 files changed, 75 insertions, 5 deletions
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index b654557730..65f0488072 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -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< diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index c23002f9a0..6737175fcf 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -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); diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index d3fe31e738..7c0f849fd7 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -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 diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 458655868a..1590e2218e 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -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)); } diff --git a/test/Sema/block-return-1.c b/test/Sema/block-return-1.c new file mode 100644 index 0000000000..2da87351e4 --- /dev/null +++ b/test/Sema/block-return-1.c @@ -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}} +} diff --git a/test/Sema/block-return-2.c b/test/Sema/block-return-2.c new file mode 100644 index 0000000000..d389f4e4ff --- /dev/null +++ b/test/Sema/block-return-2.c @@ -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}} +} diff --git a/test/Sema/block-return-3.c b/test/Sema/block-return-3.c new file mode 100644 index 0000000000..e7e9342e02 --- /dev/null +++ b/test/Sema/block-return-3.c @@ -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}} +} |