C1X provides a standard way of declaring non-returning functions, with
the _Noreturn keyword and a header stdnoreturn.h defining a macro
"noreturn" to expand to _Noreturn.  This patch implements this syntax
and header.  Bootstrapped with no regressions on
x86_64-unknown-linux-gnu.  Applied to mainline.

I didn't touch the USER_H definition in mips/t-sdemtk (so that target
will not install this new header).  The comment "Remove stdarg.h and
stddef.h from USER_H." suggests that maybe it should be added to that
definition, but stdfix.h is also missing from that definition.  As far
as I know MIPS is no longer using the old SDE library and it is
considered superseded by newlib, so perhaps that configuration
(mips*-sde-elf* without newlib) should actually be deprecated/removed
(and "mipssde" threads along with it).

The new keyword is C-only (C++0x has a different way of declaring
non-returning functions) and I did not try to make the header do
anything useful if included in C++ code.

2011-08-18  Joseph Myers  <jos...@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.

c-family:
2011-08-18  Joseph Myers  <jos...@codesourcery.com>

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

testsuite:
2011-08-18  Joseph Myers  <jos...@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.

Index: gcc/c-family/c-common.c
===================================================================
--- gcc/c-family/c-common.c     (revision 177868)
+++ gcc/c-family/c-common.c     (working copy)
@@ -414,6 +414,7 @@ const struct c_common_resword c_common_r
   { "_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 
   switch (keyword)
     {
     case RID_INLINE:
+    case RID_NORETURN:
     case RID_VIRTUAL:
     case RID_EXPLICIT:
       return true;
Index: gcc/c-family/c-common.h
===================================================================
--- gcc/c-family/c-common.h     (revision 177868)
+++ gcc/c-family/c-common.h     (working copy)
@@ -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: gcc/ginclude/stdnoreturn.h
===================================================================
--- gcc/ginclude/stdnoreturn.h  (revision 0)
+++ gcc/ginclude/stdnoreturn.h  (revision 0)
@@ -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: gcc/testsuite/gcc.dg/c1x-noreturn-1.c
===================================================================
--- gcc/testsuite/gcc.dg/c1x-noreturn-1.c       (revision 0)
+++ gcc/testsuite/gcc.dg/c1x-noreturn-1.c       (revision 0)
@@ -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;
Index: gcc/testsuite/gcc.dg/c1x-noreturn-5.c
===================================================================
--- gcc/testsuite/gcc.dg/c1x-noreturn-5.c       (revision 0)
+++ gcc/testsuite/gcc.dg/c1x-noreturn-5.c       (revision 0)
@@ -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" } */
Index: gcc/testsuite/gcc.dg/c1x-noreturn-2.c
===================================================================
--- gcc/testsuite/gcc.dg/c1x-noreturn-2.c       (revision 0)
+++ gcc/testsuite/gcc.dg/c1x-noreturn-2.c       (revision 0)
@@ -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);
+}
Index: gcc/testsuite/gcc.dg/c1x-noreturn-3.c
===================================================================
--- gcc/testsuite/gcc.dg/c1x-noreturn-3.c       (revision 0)
+++ gcc/testsuite/gcc.dg/c1x-noreturn-3.c       (revision 0)
@@ -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);
+}
Index: gcc/testsuite/gcc.dg/c1x-noreturn-4.c
===================================================================
--- gcc/testsuite/gcc.dg/c1x-noreturn-4.c       (revision 0)
+++ gcc/testsuite/gcc.dg/c1x-noreturn-4.c       (revision 0)
@@ -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);
+}
Index: gcc/c-tree.h
===================================================================
--- gcc/c-tree.h        (revision 177868)
+++ gcc/c-tree.h        (working copy)
@@ -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.  */
Index: gcc/c-decl.c
===================================================================
--- gcc/c-decl.c        (revision 177868)
+++ gcc/c-decl.c        (working copy)
@@ -3714,6 +3714,12 @@ shadow_tag_warned (const struct c_declsp
       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_dec
              && !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_declarato
        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_declarato
       /* 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_declarato
        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_declarato
        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_declarato
 
        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
       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: gcc/Makefile.in
===================================================================
--- gcc/Makefile.in     (revision 177868)
+++ gcc/Makefile.in     (working copy)
@@ -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: gcc/c-parser.c
===================================================================
--- gcc/c-parser.c      (revision 177868)
+++ gcc/c-parser.c      (working copy)
@@ -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, st
        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:

-- 
Joseph S. Myers
jos...@codesourcery.com

Reply via email to