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