]> granicus.if.org Git - clang/commitdiff
Improve diagnostics if _Noreturn is placed after a function declarator. (This sometim...
authorRichard Smith <richard-llvm@metafoo.co.uk>
Mon, 10 Nov 2014 21:10:32 +0000 (21:10 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Mon, 10 Nov 2014 21:10:32 +0000 (21:10 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@221630 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/DiagnosticParseKinds.td
lib/Parse/ParseDecl.cpp
test/FixIt/fixit-errors.c
test/Parser/c11-noreturn.c

index 90d30d779f06d928f8ab1012ea591f974f62b3a4..eb03f5a3aa266a710843cd4f13e43360c5d8e4f3 100644 (file)
@@ -121,6 +121,8 @@ def ext_c11_alignment : Extension<
 
 def ext_c11_noreturn : Extension<
   "_Noreturn functions are a C11-specific feature">, InGroup<C11>;
+def err_c11_noreturn_misplaced : Error<
+  "'_Noreturn' keyword must precede function declarator">;
 
 def ext_gnu_indirect_goto : Extension<
   "use of GNU indirect-goto extension">, InGroup<GNULabelsAsValue>;
index b2fa88db2b65122de5a228a8415e362032b66340..66b98c2c4da906e0ff6c4b6d3620e5f05161a674 100644 (file)
@@ -1601,9 +1601,30 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
   // appropriate function scope after the function Decl has been constructed.
   // These will be parsed in ParseFunctionDefinition or ParseLexedAttrList.
   LateParsedAttrList LateParsedAttrs(true);
-  if (D.isFunctionDeclarator())
+  if (D.isFunctionDeclarator()) {
     MaybeParseGNUAttributes(D, &LateParsedAttrs);
 
+    // The _Noreturn keyword can't appear here, unlike the GNU noreturn
+    // attribute. If we find the keyword here, tell the user to put it
+    // at the start instead.
+    if (Tok.is(tok::kw__Noreturn)) {
+      SourceLocation Loc = ConsumeToken();
+      const char *PrevSpec;
+      unsigned DiagID;
+
+      // We can offer a fixit if it's valid to mark this function as _Noreturn
+      // and we don't have any other declarators in this declaration.
+      bool Fixit = !DS.setFunctionSpecNoreturn(Loc, PrevSpec, DiagID);
+      MaybeParseGNUAttributes(D, &LateParsedAttrs);
+      Fixit &= Tok.is(tok::semi) || Tok.is(tok::l_brace) || Tok.is(tok::kw_try);
+
+      Diag(Loc, diag::err_c11_noreturn_misplaced)
+          << (Fixit ? FixItHint::CreateRemoval(Loc) : FixItHint())
+          << (Fixit ? FixItHint::CreateInsertion(D.getLocStart(), "_Noreturn ")
+                    : FixItHint());
+    }
+  }
+
   // Check to see if we have a function *definition* which must have a body.
   if (D.isFunctionDeclarator() &&
       // Look at the next token to make sure that this isn't a function
index c425fc8a2d954ff3c8821274e2866b9b5c76bcbf..d727adb6fdfbe4908f58bc0b730d88d40386fb0d 100644 (file)
@@ -1,7 +1,7 @@
 // RUN: %clang_cc1 -fsyntax-only -pedantic -verify %s
 // RUN: cp %s %t
 // RUN: not %clang_cc1 -pedantic -fixit -x c %t
-// RUN: %clang_cc1 -pedantic -Werror -x c %t
+// RUN: %clang_cc1 -pedantic -Werror -Wno-invalid-noreturn -x c %t
 
 /* This is a test of the various code modification hints that are
    provided as part of warning or extension diagnostics. All of the
@@ -21,3 +21,11 @@ struct Point *get_origin();
 void test_point() {
   (void)get_origin->x; // expected-error {{base of member reference is a function; perhaps you meant to call it with no arguments?}}
 }
+
+void noreturn_1() _Noreturn; // expected-error {{must precede function declarator}}
+void noreturn_1() {
+  return; // expected-warning {{should not return}}
+}
+void noreturn_2() _Noreturn { // expected-error {{must precede function declarator}}
+  return; // expected-warning {{should not return}}
+}
index 6c01b5533acfcfccf29f579c0699561f273070a2..9b932abeaff2feb7f9b6c0ecd1eba67cffb46f09 100644 (file)
@@ -4,7 +4,7 @@
 _Noreturn int f();
 int _Noreturn f(); // expected-note {{previous}}
 int f _Noreturn(); // expected-error {{expected ';'}} expected-error 2{{}}
-int f() _Noreturn; // expected-error {{expected ';'}} expected-warning {{does not declare anything}} expected-error {{'_Noreturn' can only appear on functions}}
+int f() _Noreturn; // expected-error {{'_Noreturn' keyword must precede function declarator}}
 
 _Noreturn char c1; // expected-error {{'_Noreturn' can only appear on functions}}
 char _Noreturn c2; // expected-error {{'_Noreturn' can only appear on functions}}