From bbceee64bef15b92b1f9b964b8d371bd07ea794a Mon Sep 17 00:00:00 2001 From: Joseph Myers Date: Thu, 18 Aug 2011 22:35:42 +0100 Subject: [PATCH] c-decl.c (shadow_tag_warned): Check for _Noreturn. * 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 --- gcc/ChangeLog | 13 +++++ gcc/Makefile.in | 1 + gcc/c-decl.c | 39 +++++++++++--- gcc/c-family/ChangeLog | 6 +++ gcc/c-family/c-common.c | 2 + gcc/c-family/c-common.h | 3 +- gcc/c-parser.c | 5 +- gcc/c-tree.h | 2 + gcc/ginclude/stdnoreturn.h | 31 +++++++++++ gcc/testsuite/ChangeLog | 6 +++ gcc/testsuite/gcc.dg/c1x-noreturn-1.c | 59 ++++++++++++++++++++ gcc/testsuite/gcc.dg/c1x-noreturn-2.c | 77 +++++++++++++++++++++++++++ gcc/testsuite/gcc.dg/c1x-noreturn-3.c | 11 ++++ gcc/testsuite/gcc.dg/c1x-noreturn-4.c | 11 ++++ gcc/testsuite/gcc.dg/c1x-noreturn-5.c | 17 ++++++ 15 files changed, 275 insertions(+), 8 deletions(-) create mode 100644 gcc/ginclude/stdnoreturn.h create mode 100644 gcc/testsuite/gcc.dg/c1x-noreturn-1.c create mode 100644 gcc/testsuite/gcc.dg/c1x-noreturn-2.c create mode 100644 gcc/testsuite/gcc.dg/c1x-noreturn-3.c create mode 100644 gcc/testsuite/gcc.dg/c1x-noreturn-4.c create mode 100644 gcc/testsuite/gcc.dg/c1x-noreturn-5.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 5ade55a1564..14723eb314a 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,16 @@ +2011-08-18 Joseph Myers + + * 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 * common/config/i386/i386-common.c (OPTION_MASK_ISA_AVX2_SET): New. diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 762b72bdae9..8c501dd2e53 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -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@ diff --git a/gcc/c-decl.c b/gcc/c-decl.c index 927beb0a33d..d824e12b5bb 100644 --- a/gcc/c-decl.c +++ b/gcc/c-decl.c @@ -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 ("% 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 %", 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 %", 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 %"); + if (declspecs->noreturn_p) + pedwarn (loc, 0, "% 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 %", 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) diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index 5f56369f3c3..9a8d953eec8 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,9 @@ +2011-08-18 Joseph Myers + + * 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 * c-common.c (unsafe_conversion_p): New function. Check if it is diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c index 1ef7e3c42e2..d4dceab30da 100644 --- a/gcc/c-family/c-common.c +++ b/gcc/c-family/c-common.c @@ -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; diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index 6905737c28e..a771c33033a 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -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, diff --git a/gcc/c-parser.c b/gcc/c-parser.c index 0d2a1b7dfca..d0f8fba50ea 100644 --- a/gcc/c-parser.c +++ b/gcc/c-parser.c @@ -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: diff --git a/gcc/c-tree.h b/gcc/c-tree.h index 95a0ba2e1f4..cda5d06863a 100644 --- a/gcc/c-tree.h +++ b/gcc/c-tree.h @@ -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 index 00000000000..c92537ce2d7 --- /dev/null +++ b/gcc/ginclude/stdnoreturn.h @@ -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 +. */ + +/* ISO C1X: 7.23 _Noreturn . */ + +#ifndef _STDNORETURN_H +#define _STDNORETURN_H + +#define noreturn _Noreturn + +#endif /* stdnoreturn.h */ diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index d8f7f1140ef..47379668f81 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2011-08-18 Joseph Myers + + * 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 * 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 index 00000000000..d9c141d5326 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c1x-noreturn-1.c @@ -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 index 00000000000..81972f1e8be --- /dev/null +++ b/gcc/testsuite/gcc.dg/c1x-noreturn-2.c @@ -0,0 +1,77 @@ +/* Test C1X _Noreturn. Test valid code using stdnoreturn.h. */ +/* { dg-do run } */ +/* { dg-options "-std=c1x -pedantic-errors" } */ + +#include + +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 index 00000000000..b12c23efafc --- /dev/null +++ b/gcc/testsuite/gcc.dg/c1x-noreturn-3.c @@ -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 index 00000000000..72dceafba19 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c1x-noreturn-4.c @@ -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 index 00000000000..73f22165cb0 --- /dev/null +++ b/gcc/testsuite/gcc.dg/c1x-noreturn-5.c @@ -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" } */