aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Stump <mrs@apple.com>2009-10-27 01:59:05 +0000
committerMike Stump <mrs@apple.com>2009-10-27 01:59:05 +0000
commit1d7e767dc8700724b7534a8640596c6a13baf3a7 (patch)
tree6216c7e365d23022edce9da7c96c5dccb0ce22d5
parent848b9b6227e8319efabc9d65aa6ca58c24b85f8b (diff)
Refine noreturn handling. Fixes -Wmissing-noreturn so that it doesn't
complain that functions that have a return statement should be declared noreturn. Fixed PR5286. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@85195 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--lib/Sema/Sema.h2
-rw-r--r--lib/Sema/SemaDecl.cpp19
-rw-r--r--test/SemaObjC/return.m18
3 files changed, 32 insertions, 7 deletions
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index fa10dead6e..f108878676 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -988,7 +988,7 @@ public:
void CheckCXXDefaultArguments(FunctionDecl *FD);
void CheckExtraCXXDefaultArguments(Declarator &D);
enum ControlFlowKind { NeverFallThrough = 0, MaybeFallThrough = 1,
- AlwaysFallThrough = 2 };
+ AlwaysFallThrough = 2, NeverFallThroughOrReturn = 3 };
ControlFlowKind CheckFallThrough(Stmt *);
Scope *getNonFieldDeclScope(Scope *S);
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index 8277a6ad5b..886b8869c8 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -1044,6 +1044,7 @@ void Sema::MergeVarDecl(VarDecl *New, Decl *OldD) {
/// Statement that should return a value.
///
/// \returns AlwaysFallThrough iff we always fall off the end of the statement,
+/// MaybeFallThroughOrReturn iff we might or might not fall off the end and
/// MaybeFallThrough iff we might or might not fall off the end and
/// NeverFallThrough iff we never fall off the end of the statement. We assume
/// that functions not marked noreturn will return.
@@ -1054,7 +1055,8 @@ Sema::ControlFlowKind Sema::CheckFallThrough(Stmt *Root) {
// FIXME: They should never return 0, fix that, delete this code.
if (cfg == 0)
- return NeverFallThrough;
+ // FIXME: This should be NeverFallThrough
+ return NeverFallThroughOrReturn;
// The CFG leaves in dead things, and we don't want to dead code paths to
// confuse us, so we mark all live things first.
std::queue<CFGBlock*> workq;
@@ -1127,8 +1129,11 @@ Sema::ControlFlowKind Sema::CheckFallThrough(Stmt *Root) {
if (NoReturnEdge == false)
HasPlainEdge = true;
}
- if (!HasPlainEdge)
- return NeverFallThrough;
+ if (!HasPlainEdge) {
+ if (HasLiveReturn)
+ return NeverFallThrough;
+ return NeverFallThroughOrReturn;
+ }
if (HasFakeEdge || HasLiveReturn)
return MaybeFallThrough;
// This says AlwaysFallThrough for calls to functions that are not marked
@@ -1192,10 +1197,12 @@ void Sema::CheckFallThroughForFunctionDef(Decl *D, Stmt *Body) {
else if (!ReturnsVoid)
Diag(Compound->getRBracLoc(), diag::warn_falloff_nonvoid_function);
break;
- case NeverFallThrough:
+ case NeverFallThroughOrReturn:
if (ReturnsVoid && !HasNoReturn)
Diag(Compound->getLBracLoc(), diag::warn_suggest_noreturn_function);
break;
+ case NeverFallThrough:
+ break;
}
}
}
@@ -1243,10 +1250,12 @@ void Sema::CheckFallThroughForBlock(QualType BlockTy, Stmt *Body) {
else if (!ReturnsVoid)
Diag(Compound->getRBracLoc(), diag::err_falloff_nonvoid_block);
break;
- case NeverFallThrough:
+ case NeverFallThroughOrReturn:
if (ReturnsVoid)
Diag(Compound->getLBracLoc(), diag::warn_suggest_noreturn_block);
break;
+ case NeverFallThrough:
+ break;
}
}
}
diff --git a/test/SemaObjC/return.m b/test/SemaObjC/return.m
index 9acf470799..ff64994794 100644
--- a/test/SemaObjC/return.m
+++ b/test/SemaObjC/return.m
@@ -1,6 +1,22 @@
-// RUN: clang-cc %s -fsyntax-only -verify
+// RUN: clang-cc %s -fsyntax-only -verify -Wmissing-noreturn
int test1() {
id a;
@throw a;
}
+
+// PR5286
+void test2(int a) {
+ while (1) {
+ if (a)
+ return;
+ }
+}
+
+// PR5286
+void test3(int a) { // expected-warning {{function could be attribute 'noreturn'}}
+ while (1) {
+ if (a)
+ @throw (id)0;
+ }
+}