[cfe-commits] r76932 - in /cfe/trunk: include/clang/Basic/DiagnosticSemaKinds.td lib/Sema/SemaDecl.cpp test/CodeGen/attributes.c test/Sema/attr-noreturn.c

Mike Stump mrs at apple.com
Thu Jul 23 19:49:01 PDT 2009


Author: mrs
Date: Thu Jul 23 21:49:01 2009
New Revision: 76932

URL: http://llvm.org/viewvc/llvm-project?rev=76932&view=rev
Log:
Implement new warning for functions declared 'noreturn' when they fall off the end.

Modified:
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/test/CodeGen/attributes.c
    cfe/trunk/test/Sema/attr-noreturn.c

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=76932&r1=76931&r2=76932&view=diff

==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Thu Jul 23 21:49:01 2009
@@ -1917,6 +1917,9 @@
 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<

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=76932&r1=76931&r2=76932&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Thu Jul 23 21:49:01 2009
@@ -1015,6 +1015,13 @@
   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 @@
 }
 
 /// 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 @@
   // 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 @@
   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 @@
   } 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())

Modified: cfe/trunk/test/CodeGen/attributes.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/attributes.c?rev=76932&r1=76931&r2=76932&view=diff

==============================================================================
--- cfe/trunk/test/CodeGen/attributes.c (original)
+++ cfe/trunk/test/CodeGen/attributes.c Thu Jul 23 21:49:01 2009
@@ -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 t6 __attribute__((visibility("protected")));
 
 void t7() __attribute__((noreturn, nothrow));
-void t7() {}
+void t7() { while (1) {} }
 
 void __t8() {}
 void t9() __attribute__((weak, alias("__t8")));

Modified: cfe/trunk/test/Sema/attr-noreturn.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/attr-noreturn.c?rev=76932&r1=76931&r2=76932&view=diff

==============================================================================
--- cfe/trunk/test/Sema/attr-noreturn.c (original)
+++ cfe/trunk/test/Sema/attr-noreturn.c Thu Jul 23 21:49:01 2009
@@ -4,7 +4,7 @@
 
 static void __attribute__((noreturn)) f0(void) {
   fatal();
-}
+} // expected-error {{function declared 'noreturn' should not return}}
 
 // On K&R
 int f1() __attribute__((noreturn));





More information about the cfe-commits mailing list