diff options
author | Mike Stump <mrs@apple.com> | 2009-07-24 02:49:01 +0000 |
---|---|---|
committer | Mike Stump <mrs@apple.com> | 2009-07-24 02:49:01 +0000 |
commit | 5f28a1edf6decac64ca12e51ca4a929d26fc21f2 (patch) | |
tree | a416de11de6af65f91b31a064638ecc647567735 | |
parent | 728d7cd2e25a0a1e5ff272163fc7ed17980f029a (diff) |
Implement new warning for functions declared 'noreturn' when they fall off the end.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@76932 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.td | 3 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 54 | ||||
-rw-r--r-- | test/CodeGen/attributes.c | 4 | ||||
-rw-r--r-- | test/Sema/attr-noreturn.c | 2 |
4 files changed, 45 insertions, 18 deletions
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index ead116d8da..881e9d90a1 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -1917,6 +1917,9 @@ def ext_return_has_void_expr : Extension< def warn_noreturn_function_has_return_expr : Warning< "function %0 declared 'noreturn' should not return">, DefaultError, InGroup<DiagGroup<"invalid-noreturn">>; +def warn_falloff_noreturn_function : Warning< + "function declared 'noreturn' should not return">, DefaultError, + InGroup<DiagGroup<"invalid-noreturn">>; def err_noreturn_block_has_return_expr : Error< "block declared 'noreturn' should not return">; def err_block_on_nonlocal : Error< diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 2ecefde538..617943fd9f 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -1015,6 +1015,13 @@ void Sema::MergeVarDecl(VarDecl *New, Decl *OldD) { New->setPreviousDeclaration(Old); } +/// CheckFallThrough - Check that we don't fall off the end of a +/// Statement that should return a value. +/// +/// \returns AlwaysFallThrough iff we always fall off the end of the statement, +/// 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. Sema::ControlFlowKind Sema::CheckFallThrough(Stmt *Root) { llvm::OwningPtr<CFG> cfg (CFG::buildCFG(Root, &Context)); @@ -1101,12 +1108,9 @@ Sema::ControlFlowKind Sema::CheckFallThrough(Stmt *Root) { } /// CheckFallThroughForFunctionDef - Check that we don't fall off the end of a -/// function that should return a value. -/// -/// \returns AlwaysFallThrough iff we always fall off the end of the statement, -/// 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. +/// 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. 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: @@ -1116,17 +1120,39 @@ void Sema::CheckFallThroughForFunctionDef(Decl *D, Stmt *Body) { // which this code would then warn about. if (getDiagnostics().hasErrorOccurred()) return; - if (Diags.getDiagnosticLevel(diag::warn_maybe_falloff_nonvoid_function) - == Diagnostic::Ignored) + bool ReturnsVoid = false; + bool HasNoReturn = false; + if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + if (FD->getResultType()->isVoidType()) + ReturnsVoid = true; + if (FD->hasAttr<NoReturnAttr>()) + HasNoReturn = true; + } else if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { + if (MD->getResultType()->isVoidType()) + ReturnsVoid = true; + if (MD->hasAttr<NoReturnAttr>()) + HasNoReturn = true; + } + + if ((Diags.getDiagnosticLevel(diag::warn_maybe_falloff_nonvoid_function) + == Diagnostic::Ignored || ReturnsVoid) + && (Diags.getDiagnosticLevel(diag::warn_noreturn_function_has_return_expr) + == Diagnostic::Ignored || !HasNoReturn)) return; // FIXME: Funtion try block if (CompoundStmt *Compound = dyn_cast<CompoundStmt>(Body)) { switch (CheckFallThrough(Body)) { case MaybeFallThrough: - Diag(Compound->getRBracLoc(), diag::warn_maybe_falloff_nonvoid_function); + if (HasNoReturn) + Diag(Compound->getRBracLoc(), diag::warn_falloff_noreturn_function); + else if (!ReturnsVoid) + Diag(Compound->getRBracLoc(),diag::warn_maybe_falloff_nonvoid_function); break; case AlwaysFallThrough: - Diag(Compound->getRBracLoc(), diag::warn_falloff_nonvoid_function); + if (HasNoReturn) + Diag(Compound->getRBracLoc(), diag::warn_falloff_noreturn_function); + else if (!ReturnsVoid) + Diag(Compound->getRBracLoc(), diag::warn_falloff_nonvoid_function); break; case NeverFallThrough: break; @@ -3369,9 +3395,8 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg, Stmt *Body = BodyArg.takeAs<Stmt>(); if (FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(dcl)) { FD->setBody(Body); - if (!FD->getResultType()->isVoidType() - // C and C++ allow for main to automagically return 0. - && !FD->isMain()) + if (!FD->isMain()) + // C and C++ allow for main to automagically return 0. CheckFallThroughForFunctionDef(FD, Body); if (!FD->isInvalidDecl()) @@ -3387,8 +3412,7 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg, } else if (ObjCMethodDecl *MD = dyn_cast_or_null<ObjCMethodDecl>(dcl)) { assert(MD == getCurMethodDecl() && "Method parsing confused"); MD->setBody(Body); - if (!MD->getResultType()->isVoidType()) - CheckFallThroughForFunctionDef(MD, Body); + CheckFallThroughForFunctionDef(MD, Body); MD->setEndLoc(Body->getLocEnd()); if (!MD->isInvalidDecl()) diff --git a/test/CodeGen/attributes.c b/test/CodeGen/attributes.c index 8f157f3d31..00252b1135 100644 --- a/test/CodeGen/attributes.c +++ b/test/CodeGen/attributes.c @@ -17,7 +17,7 @@ // RUN: grep '@t16 = extern_weak global i32' %t && void t1() __attribute__((noreturn)); -void t1() {} +void t1() { while (1) {} } void t2() __attribute__((nothrow)); void t2() {} @@ -33,7 +33,7 @@ int t5 __attribute__((weak)) = 2; int t6 __attribute__((visibility("protected"))); void t7() __attribute__((noreturn, nothrow)); -void t7() {} +void t7() { while (1) {} } void __t8() {} void t9() __attribute__((weak, alias("__t8"))); diff --git a/test/Sema/attr-noreturn.c b/test/Sema/attr-noreturn.c index d1417f093f..2970a4827e 100644 --- a/test/Sema/attr-noreturn.c +++ b/test/Sema/attr-noreturn.c @@ -4,7 +4,7 @@ static void (*fp0)(void) __attribute__((noreturn)); static void __attribute__((noreturn)) f0(void) { fatal(); -} +} // expected-error {{function declared 'noreturn' should not return}} // On K&R int f1() __attribute__((noreturn)); |