c-decl.c (shadow_tag_warned): Check for _Noreturn.
authorJoseph Myers <joseph@codesourcery.com>
Thu, 18 Aug 2011 21:35:42 +0000 (22:35 +0100)
committerJoseph Myers <jsm28@gcc.gnu.org>
Thu, 18 Aug 2011 21:35:42 +0000 (22:35 +0100)
* c-decl.c (shadow_tag_warned): Check for _Noreturn.
(quals_from_declspecs): Assert _Noreturn not present.
(grokdeclarator): Handle _Noreturn.
(build_null_declspecs): Initialize noreturn_p.
(declspecs_add_scspec): Handle RID_NORETURN.
* c-parser.c (c_token_starts_declspecs, c_parser_declspecs)
(c_parser_attributes): Handle RID_NORETURN.
* c-tree.h (struct c_declspecs): Add noreturn_p.
* ginclude/stdnoreturn.h: New.
* Makefile.in (USER_H): Add stdnoreturn.h.

c-family:
* c-common.c (c_common_reswords): Add _Noreturn.
(keyword_is_function_specifier): Handle RID_NORETURN.
* c-common.h (RID_NORETURN): New.

testsuite:
* gcc.dg/c1x-noreturn-1.c, gcc.dg/c1x-noreturn-2.c,
gcc.dg/c1x-noreturn-3.c, gcc.dg/c1x-noreturn-4.c,
gcc.dg/c1x-noreturn-5.c: New tests.

From-SVN: r177881

15 files changed:
gcc/ChangeLog
gcc/Makefile.in
gcc/c-decl.c
gcc/c-family/ChangeLog
gcc/c-family/c-common.c
gcc/c-family/c-common.h
gcc/c-parser.c
gcc/c-tree.h
gcc/ginclude/stdnoreturn.h [new file with mode: 0644]
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/c1x-noreturn-1.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/c1x-noreturn-2.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/c1x-noreturn-3.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/c1x-noreturn-4.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/c1x-noreturn-5.c [new file with mode: 0644]

index 5ade55a15648cf7c461e2b7c6f3f63a25087fcac..14723eb314aeb629b5bfbe7bebab50c05017f13f 100644 (file)
@@ -1,3 +1,16 @@
+2011-08-18  Joseph Myers  <joseph@codesourcery.com>
+
+       * c-decl.c (shadow_tag_warned): Check for _Noreturn.
+       (quals_from_declspecs): Assert _Noreturn not present.
+       (grokdeclarator): Handle _Noreturn.
+       (build_null_declspecs): Initialize noreturn_p.
+       (declspecs_add_scspec): Handle RID_NORETURN.
+       * c-parser.c (c_token_starts_declspecs, c_parser_declspecs)
+       (c_parser_attributes): Handle RID_NORETURN.
+       * c-tree.h (struct c_declspecs): Add noreturn_p.
+       * ginclude/stdnoreturn.h: New.
+       * Makefile.in (USER_H): Add stdnoreturn.h.
+
 2011-08-18  Kirill Yukhin  <kirill.yukhin@intel.com>
 
        * common/config/i386/i386-common.c (OPTION_MASK_ISA_AVX2_SET): New.
index 762b72bdae9bc50baee005359764b1ae74a796c4..8c501dd2e53be6919a140d3533f002f41e43e60d 100644 (file)
@@ -373,6 +373,7 @@ USER_H = $(srcdir)/ginclude/float.h \
         $(srcdir)/ginclude/stddef.h \
         $(srcdir)/ginclude/varargs.h \
         $(srcdir)/ginclude/stdfix.h \
+        $(srcdir)/ginclude/stdnoreturn.h \
         $(EXTRA_HEADERS)
 
 USER_H_INC_NEXT_PRE = @user_headers_inc_next_pre@
index 927beb0a33de1c3f51a5bb6ac198fcdb1d988897..d824e12b5bbc51a30b1ca380cd1bc130e87bfaa7 100644 (file)
@@ -3714,6 +3714,12 @@ shadow_tag_warned (const struct c_declspecs *declspecs, int warned)
       warned = 1;
     }
 
+  if (declspecs->noreturn_p)
+    {
+      error ("%<_Noreturn%> in empty declaration");
+      warned = 1;
+    }
+
   if (current_scope == file_scope && declspecs->storage_class == csc_auto)
     {
       error ("%<auto%> in file-scope empty declaration");
@@ -3780,6 +3786,7 @@ quals_from_declspecs (const struct c_declspecs *specs)
              && !specs->unsigned_p
              && !specs->complex_p
              && !specs->inline_p
+             && !specs->noreturn_p
              && !specs->thread_p);
   return quals;
 }
@@ -5734,6 +5741,8 @@ grokdeclarator (const struct c_declarator *declarator,
        C_TYPEDEF_EXPLICITLY_SIGNED (decl) = 1;
       if (declspecs->inline_p)
        pedwarn (loc, 0,"typedef %q+D declared %<inline%>", decl);
+      if (declspecs->noreturn_p)
+       pedwarn (loc, 0,"typedef %q+D declared %<_Noreturn%>", decl);
 
       if (warn_cxx_compat && declarator->u.id != NULL_TREE)
        {
@@ -5765,7 +5774,7 @@ grokdeclarator (const struct c_declarator *declarator,
       /* Note that the grammar rejects storage classes in typenames
         and fields.  */
       gcc_assert (storage_class == csc_none && !threadp
-                 && !declspecs->inline_p);
+                 && !declspecs->inline_p && !declspecs->noreturn_p);
       if (pedantic && TREE_CODE (type) == FUNCTION_TYPE
          && type_quals)
        pedwarn (loc, OPT_pedantic,
@@ -5862,13 +5871,15 @@ grokdeclarator (const struct c_declarator *declarator,
        DECL_ARG_TYPE (decl) = promoted_type;
        if (declspecs->inline_p)
          pedwarn (loc, 0, "parameter %q+D declared %<inline%>", decl);
+       if (declspecs->noreturn_p)
+         pedwarn (loc, 0, "parameter %q+D declared %<_Noreturn%>", decl);
       }
     else if (decl_context == FIELD)
       {
        /* Note that the grammar rejects storage classes in typenames
           and fields.  */
        gcc_assert (storage_class == csc_none && !threadp
-                   && !declspecs->inline_p);
+                   && !declspecs->inline_p && !declspecs->noreturn_p);
 
        /* Structure field.  It may not be a function.  */
 
@@ -5960,15 +5971,23 @@ grokdeclarator (const struct c_declarator *declarator,
        if (declspecs->default_int_p)
          C_FUNCTION_IMPLICIT_INT (decl) = 1;
 
-       /* Record presence of `inline', if it is reasonable.  */
+       /* Record presence of `inline' and `_Noreturn', if it is
+          reasonable.  */
        if (flag_hosted && MAIN_NAME_P (declarator->u.id))
          {
            if (declspecs->inline_p)
              pedwarn (loc, 0, "cannot inline function %<main%>");
+           if (declspecs->noreturn_p)
+             pedwarn (loc, 0, "%<main%> declared %<_Noreturn%>");
+         }
+       else
+         {
+           if (declspecs->inline_p)
+             /* Record that the function is declared `inline'.  */
+             DECL_DECLARED_INLINE_P (decl) = 1;
+           if (declspecs->noreturn_p)
+             TREE_THIS_VOLATILE (decl) = 1;
          }
-       else if (declspecs->inline_p)
-         /* Record that the function is declared `inline'.  */
-         DECL_DECLARED_INLINE_P (decl) = 1;
       }
     else
       {
@@ -6004,6 +6023,8 @@ grokdeclarator (const struct c_declarator *declarator,
 
        if (declspecs->inline_p)
          pedwarn (loc, 0, "variable %q+D declared %<inline%>", decl);
+       if (declspecs->noreturn_p)
+         pedwarn (loc, 0, "variable %q+D declared %<_Noreturn%>", decl);
 
        /* At file scope, an initialized extern declaration may follow
           a static declaration.  In that case, DECL_EXTERNAL will be
@@ -8646,6 +8667,7 @@ build_null_declspecs (void)
   ret->unsigned_p = false;
   ret->complex_p = false;
   ret->inline_p = false;
+  ret->noreturn_p = false;
   ret->thread_p = false;
   ret->const_p = false;
   ret->volatile_p = false;
@@ -9367,6 +9389,11 @@ declspecs_add_scspec (struct c_declspecs *specs, tree scspec)
       dupe = false;
       specs->inline_p = true;
       break;
+    case RID_NORETURN:
+      /* Duplicate _Noreturn is permitted.  */
+      dupe = false;
+      specs->noreturn_p = true;
+      break;
     case RID_THREAD:
       dupe = specs->thread_p;
       if (specs->storage_class == csc_auto)
index 5f56369f3c34b049c067f1cad9f610df67d4a032..9a8d953eec8e08051d9f85f476632d394e4344f9 100644 (file)
@@ -1,3 +1,9 @@
+2011-08-18  Joseph Myers  <joseph@codesourcery.com>
+
+       * c-common.c (c_common_reswords): Add _Noreturn.
+       (keyword_is_function_specifier): Handle RID_NORETURN.
+       * c-common.h (RID_NORETURN): New.
+
 2011-08-10  Artjoms Sinkarovs <artyom.shinakroff@gmail.com>
 
        * c-common.c (unsafe_conversion_p): New function. Check if it is
index 1ef7e3c42e20f5bdefb4931a4b03f02fb59c7252..d4dceab30dad92835d4b12754f28588f0f4cac2b 100644 (file)
@@ -414,6 +414,7 @@ const struct c_common_resword c_common_reswords[] =
   { "_Accum",           RID_ACCUM,     D_CONLY | D_EXT },
   { "_Sat",             RID_SAT,       D_CONLY | D_EXT },
   { "_Static_assert",   RID_STATIC_ASSERT, D_CONLY },
+  { "_Noreturn",        RID_NORETURN,  D_CONLY },
   { "__FUNCTION__",    RID_FUNCTION_NAME, 0 },
   { "__PRETTY_FUNCTION__", RID_PRETTY_FUNCTION_NAME, 0 },
   { "__alignof",       RID_ALIGNOF,    0 },
@@ -9793,6 +9794,7 @@ keyword_is_function_specifier (enum rid keyword)
   switch (keyword)
     {
     case RID_INLINE:
+    case RID_NORETURN:
     case RID_VIRTUAL:
     case RID_EXPLICIT:
       return true;
index 6905737c28e4069fced1fd0ecede9d4d1fb088be..a771c33033a1740c0ce1c4ac805f7036b2a6156a 100644 (file)
@@ -58,7 +58,7 @@ never after.
 /* Reserved identifiers.  This is the union of all the keywords for C,
    C++, and Objective-C.  All the type modifiers have to be in one
    block at the beginning, because they are used as mask bits.  There
-   are 27 type modifiers; if we add many more we will have to redesign
+   are 28 type modifiers; if we add many more we will have to redesign
    the mask mechanism.  */
 
 enum rid
@@ -69,6 +69,7 @@ enum rid
   RID_UNSIGNED, RID_LONG,    RID_CONST, RID_EXTERN,
   RID_REGISTER, RID_TYPEDEF, RID_SHORT, RID_INLINE,
   RID_VOLATILE, RID_SIGNED,  RID_AUTO,  RID_RESTRICT,
+  RID_NORETURN,
 
   /* C extensions */
   RID_COMPLEX, RID_THREAD, RID_SAT,
index 0d2a1b7dfca075640c70c711e11e07804e3abcf6..d0f8fba50eae136c1c098bd78416033c7d6bf106 100644 (file)
@@ -621,6 +621,7 @@ c_token_starts_declspecs (c_token *token)
        case RID_REGISTER:
        case RID_TYPEDEF:
        case RID_INLINE:
+       case RID_NORETURN:
        case RID_AUTO:
        case RID_THREAD:
        case RID_UNSIGNED:
@@ -2080,12 +2081,13 @@ c_parser_declspecs (c_parser *parser, struct c_declspecs *specs,
        case RID_REGISTER:
        case RID_TYPEDEF:
        case RID_INLINE:
+       case RID_NORETURN:
        case RID_AUTO:
        case RID_THREAD:
          if (!scspec_ok)
            goto out;
          attrs_ok = true;
-         /* TODO: Distinguish between function specifiers (inline)
+         /* TODO: Distinguish between function specifiers (inline, noreturn)
             and storage class specifiers, either here or in
             declspecs_add_scspec.  */
          declspecs_add_scspec (specs, c_parser_peek_token (parser)->value);
@@ -3428,6 +3430,7 @@ c_parser_attributes (c_parser *parser)
                case RID_TYPEDEF:
                case RID_SHORT:
                case RID_INLINE:
+               case RID_NORETURN:
                case RID_VOLATILE:
                case RID_SIGNED:
                case RID_AUTO:
index 95a0ba2e1f407d141b97630de9ad7e5a67b4297b..cda5d06863a06e91ccee74697f0901db4d795f41 100644 (file)
@@ -266,6 +266,8 @@ struct c_declspecs {
   BOOL_BITFIELD complex_p : 1;
   /* Whether "inline" was specified.  */
   BOOL_BITFIELD inline_p : 1;
+  /* Whether "_Noreturn" was speciied.  */
+  BOOL_BITFIELD noreturn_p : 1;
   /* Whether "__thread" was specified.  */
   BOOL_BITFIELD thread_p : 1;
   /* Whether "const" was specified.  */
diff --git a/gcc/ginclude/stdnoreturn.h b/gcc/ginclude/stdnoreturn.h
new file mode 100644 (file)
index 0000000..c92537c
--- /dev/null
@@ -0,0 +1,31 @@
+/* Copyright (C) 2011 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 3, or (at your option)
+any later version.
+
+GCC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+Under Section 7 of GPL version 3, you are granted additional
+permissions described in the GCC Runtime Library Exception, version
+3.1, as published by the Free Software Foundation.
+
+You should have received a copy of the GNU General Public License and
+a copy of the GCC Runtime Library Exception along with this program;
+see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+<http://www.gnu.org/licenses/>.  */
+
+/* ISO C1X: 7.23 _Noreturn <stdnoreturn.h>.  */
+
+#ifndef _STDNORETURN_H
+#define _STDNORETURN_H
+
+#define noreturn _Noreturn
+
+#endif /* stdnoreturn.h */
index d8f7f1140ef3f94ff9da6e56c6b18dcffb589856..47379668f8143e5db2a010abd5f11caa1fc976ef 100644 (file)
@@ -1,3 +1,9 @@
+2011-08-18  Joseph Myers  <joseph@codesourcery.com>
+
+       * gcc.dg/c1x-noreturn-1.c, gcc.dg/c1x-noreturn-2.c,
+       gcc.dg/c1x-noreturn-3.c, gcc.dg/c1x-noreturn-4.c,
+       gcc.dg/c1x-noreturn-5.c: New tests.
+
 2011-08-18  Joseph Myers  <joseph@codesourcery.com>
 
        * gcc.dg/c1x-uni-string-1.c, gcc.dg/c1x-uni-string-2.c: New tests.
diff --git a/gcc/testsuite/gcc.dg/c1x-noreturn-1.c b/gcc/testsuite/gcc.dg/c1x-noreturn-1.c
new file mode 100644 (file)
index 0000000..d9c141d
--- /dev/null
@@ -0,0 +1,59 @@
+/* Test C1X _Noreturn.  Test valid code.  */
+/* { dg-do compile } */
+/* { dg-options "-std=c1x -pedantic-errors" } */
+
+_Noreturn void exit (int);
+
+_Noreturn int f1 (void);
+
+_Noreturn void f2 (void);
+
+static void _Noreturn f3 (void) { exit (0); }
+
+/* Returning from a noreturn function is undefined at runtime, not a
+   constraint violation, but recommended practice is to diagnose if
+   such a return appears possible.  */
+
+_Noreturn int
+f4 (void)
+{
+  return 1; /* { dg-warning "has a 'return' statement" } */
+  /* { dg-warning "does return" "second warning" { target *-*-* } 20 } */
+}
+
+_Noreturn void
+f5 (void)
+{
+  return; /* { dg-warning "has a 'return' statement" } */
+  /* { dg-warning "does return" "second warning" { target *-*-* } 27 } */
+}
+
+_Noreturn void
+f6 (void)
+{
+} /* { dg-warning "does return" } */
+
+_Noreturn void
+f7 (int a)
+{
+  if (a)
+    exit (0);
+} /* { dg-warning "does return" } */
+
+/* Declarations need not all have _Noreturn.  */
+
+void f2 (void);
+
+void f8 (void);
+_Noreturn void f8 (void);
+
+/* Duplicate _Noreturn is OK.  */
+_Noreturn _Noreturn void _Noreturn f9 (void);
+
+/* _Noreturn does not affect type compatibility.  */
+
+void (*fp) (void) = f5;
+
+/* noreturn is an ordinary identifier.  */
+
+int noreturn;
diff --git a/gcc/testsuite/gcc.dg/c1x-noreturn-2.c b/gcc/testsuite/gcc.dg/c1x-noreturn-2.c
new file mode 100644 (file)
index 0000000..81972f1
--- /dev/null
@@ -0,0 +1,77 @@
+/* Test C1X _Noreturn.  Test valid code using stdnoreturn.h.  */
+/* { dg-do run } */
+/* { dg-options "-std=c1x -pedantic-errors" } */
+
+#include <stdnoreturn.h>
+
+extern int strcmp (const char *, const char *);
+
+noreturn void exit (int);
+noreturn void abort (void);
+
+noreturn int f1 (void);
+
+noreturn void f2 (void);
+
+static void noreturn f3 (void) { exit (0); }
+
+/* Returning from a noreturn function is undefined at runtime, not a
+   constraint violation, but recommended practice is to diagnose if
+   such a return appears possible.  */
+
+noreturn int
+f4 (void)
+{
+  return 1; /* { dg-warning "has a 'return' statement" } */
+  /* { dg-warning "does return" "second warning" { target *-*-* } 25 } */
+}
+
+noreturn void
+f5 (void)
+{
+  return; /* { dg-warning "has a 'return' statement" } */
+  /* { dg-warning "does return" "second warning" { target *-*-* } 32 } */
+}
+
+noreturn void
+f6 (void)
+{
+} /* { dg-warning "does return" } */
+
+noreturn void
+f7 (int a)
+{
+  if (a)
+    exit (0);
+} /* { dg-warning "does return" } */
+
+/* Declarations need not all have noreturn.  */
+
+void f2 (void);
+
+void f8 (void);
+noreturn void f8 (void);
+
+/* Duplicate noreturn is OK.  */
+noreturn noreturn void noreturn f9 (void);
+
+/* noreturn does not affect type compatibility.  */
+
+void (*fp) (void) = f5;
+
+#ifndef noreturn
+#error "noreturn not defined"
+#endif
+
+#define str(x) #x
+#define xstr(x) str(x)
+
+const char *s = xstr(noreturn);
+
+int
+main (void)
+{
+  if (strcmp (s, "_Noreturn") != 0)
+    abort ();
+  exit (0);
+}
diff --git a/gcc/testsuite/gcc.dg/c1x-noreturn-3.c b/gcc/testsuite/gcc.dg/c1x-noreturn-3.c
new file mode 100644 (file)
index 0000000..b12c23e
--- /dev/null
@@ -0,0 +1,11 @@
+/* Test C1X _Noreturn.  Test _Noreturn on main, hosted.  */
+/* { dg-do compile } */
+/* { dg-options "-std=c1x -pedantic-errors -fhosted" } */
+
+_Noreturn void exit (int);
+
+_Noreturn int
+main (void) /* { dg-error "'main' declared '_Noreturn'" } */
+{
+  exit (0);
+}
diff --git a/gcc/testsuite/gcc.dg/c1x-noreturn-4.c b/gcc/testsuite/gcc.dg/c1x-noreturn-4.c
new file mode 100644 (file)
index 0000000..72dceaf
--- /dev/null
@@ -0,0 +1,11 @@
+/* Test C1X _Noreturn.  Test _Noreturn on main, freestanding.  */
+/* { dg-do compile } */
+/* { dg-options "-std=c1x -pedantic-errors -ffreestanding" } */
+
+_Noreturn void exit (int);
+
+_Noreturn int
+main (void)
+{
+  exit (0);
+}
diff --git a/gcc/testsuite/gcc.dg/c1x-noreturn-5.c b/gcc/testsuite/gcc.dg/c1x-noreturn-5.c
new file mode 100644 (file)
index 0000000..73f2216
--- /dev/null
@@ -0,0 +1,17 @@
+/* Test C1X _Noreturn.  Test invalid uses.  */
+/* { dg-do compile } */
+/* { dg-options "-std=c1x -pedantic-errors" } */
+
+_Noreturn struct s; /* { dg-error "empty declaration" } */
+
+typedef _Noreturn void f (void); /* { dg-error "typedef" } */
+
+void g (_Noreturn void fp (void)); /* { dg-error "parameter" } */
+
+_Noreturn void (*p) (void); /* { dg-error "variable" } */
+
+struct t { int a; _Noreturn void (*f) (void); }; /* { dg-error "expected" } */
+
+int *_Noreturn *q; /* { dg-error "expected" } */
+
+int i = sizeof (_Noreturn int (*) (void)); /* { dg-error "expected" } */