aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Stump <mrs@apple.com>2009-07-28 22:04:01 +0000
committerMike Stump <mrs@apple.com>2009-07-28 22:04:01 +0000
commit5692586ae59be8d49edd7b45dd52c1ffa920ba5e (patch)
treef4647b56230d466c63ae0385c0ea25828cbd806b
parentfa9f8b4cf962d865c4b430a25aca2fb5faa84337 (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.td4
-rw-r--r--lib/Sema/Sema.h3
-rw-r--r--lib/Sema/SemaDecl.cpp49
-rw-r--r--lib/Sema/SemaExpr.cpp8
-rw-r--r--test/Sema/block-return-1.c6
-rw-r--r--test/Sema/block-return-2.c5
-rw-r--r--test/Sema/block-return-3.c5
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}}
+}