This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
C1X static assertions patch
- From: "Joseph S. Myers" <joseph at codesourcery dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Sun, 16 May 2010 16:56:24 +0000 (UTC)
- Subject: C1X static assertions patch
This patch adds support for C1X _Static_assert to GCC. (The C1X
static assertions changes also include a macro static_assert in
<assert.h>, but that's the responsibility of the library not of GCC.)
As with other cases where integer constant expressions are required,
this implementation will pedwarn-if-pedantic for something this is not
an integer constant expression but folds to an integer constant.
Unlike C++0x, it appears that C1X allows a static assertion as the
declaration in a "for" loop, so that is allowed by this
implementation.
Bootstrapped with no regressions on x86_64-unknown-linux-gnu. Applied
to mainline.
2010-05-16 Joseph Myers <joseph@codesourcery.com>
* c-common.c (c_common_reswords): Add _Static_assert for C.
* c-parser.c (c_token_starts_declaration,
c_parser_next_token_starts_declaration,
c_parser_static_assert_declaration_no_semi,
c_parser_static_assert_declaration): New.
(c_parser_declaration_or_fndef): Add parameter static_assert_ok.
Handle static assertions if static_assert_ok.
(c_parser_external_declaration, c_parser_declaration_or_fndef,
c_parser_compound_statement_nostart, c_parser_label,
c_parser_for_statement, c_parser_objc_methodprotolist,
c_parser_omp_for_loop): All callers of
c_parser_declaration_or_fndef changed.
(c_parser_struct_declaration): Handle static assertions.
(c_parser_compound_statement_nostart): Use
c_parser_next_token_starts_declaration and
c_token_starts_declaration to detect start of declarations.
(c_parser_label, c_parser_for_statement, c_parser_omp_for_loop):
Likewise.
testsuite:
2010-05-16 Joseph Myers <joseph@codesourcery.com>
* gcc.dg/c1x-static-assert-1.c, gcc.dg/c1x-static-assert-2.c,
gcc.dg/c1x-static-assert-3.c, gcc.dg/c1x-static-assert-4.c,
gcc.dg/c1x-static-assert-5.c, gcc.dg/c1x-static-assert-6.c,
gcc.dg/c90-static-assert-1.c, gcc.dg/c99-static-assert-1.c: New
tests.
Index: gcc/testsuite/gcc.dg/c1x-static-assert-1.c
===================================================================
--- gcc/testsuite/gcc.dg/c1x-static-assert-1.c (revision 0)
+++ gcc/testsuite/gcc.dg/c1x-static-assert-1.c (revision 0)
@@ -0,0 +1,41 @@
+/* Test C1X static assertions. Valid assertions. */
+/* { dg-do compile } */
+/* { dg-options "-std=c1x -pedantic-errors" } */
+
+_Static_assert (1, "foo");
+
+enum e { E0, E1 };
+
+_Static_assert (E1, L"bar");
+
+_Static_assert (-1, "foo" L"bar");
+
+struct s
+{
+ int a;
+ _Static_assert (3, "s");
+ int b;
+};
+
+union u
+{
+ int i;
+ _Static_assert ((int)1.0, L"");
+};
+
+void
+f (void)
+{
+ int i;
+ i = 1;
+ _Static_assert (0 + 1, "f");
+ i = 2;
+}
+
+void
+g (void)
+{
+ int i = 0;
+ for (_Static_assert (1, ""); i < 10; i++)
+ ;
+}
Index: gcc/testsuite/gcc.dg/c90-static-assert-1.c
===================================================================
--- gcc/testsuite/gcc.dg/c90-static-assert-1.c (revision 0)
+++ gcc/testsuite/gcc.dg/c90-static-assert-1.c (revision 0)
@@ -0,0 +1,5 @@
+/* Test for static assertions not in C90. */
+/* { dg-do compile } */
+/* { dg-options "-std=iso9899:1990 -pedantic-errors" } */
+
+_Static_assert (1, ""); /* { dg-error "ISO C90 does not support '_Static_assert'" } */
Index: gcc/testsuite/gcc.dg/c1x-static-assert-5.c
===================================================================
--- gcc/testsuite/gcc.dg/c1x-static-assert-5.c (revision 0)
+++ gcc/testsuite/gcc.dg/c1x-static-assert-5.c (revision 0)
@@ -0,0 +1,5 @@
+/* Test C1X static assertions. Non-constant-expression without -pedantic. */
+/* { dg-do compile } */
+/* { dg-options "-std=c1x" } */
+
+_Static_assert ((int)(1.0 + 1.0), "non-constant-expression");
Index: gcc/testsuite/gcc.dg/c1x-static-assert-2.c
===================================================================
--- gcc/testsuite/gcc.dg/c1x-static-assert-2.c (revision 0)
+++ gcc/testsuite/gcc.dg/c1x-static-assert-2.c (revision 0)
@@ -0,0 +1,41 @@
+/* Test C1X static assertions. Failed assertions. */
+/* { dg-do compile } */
+/* { dg-options "-std=c1x -pedantic-errors" } */
+
+_Static_assert (0, "assert1"); /* { dg-error "static assertion failed: \"assert1\"" } */
+
+enum e { E0, E1 };
+
+_Static_assert (E0, L"assert2"); /* { dg-error "static assertion failed: \"assert2\"" } */
+
+_Static_assert (-0, "ass" L"ert3"); /* { dg-error "static assertion failed: \"assert3\"" } */
+
+struct s
+{
+ int a;
+ _Static_assert (0, "assert4"); /* { dg-error "static assertion failed: \"assert4\"" } */
+ int b;
+};
+
+union u
+{
+ int i;
+ _Static_assert ((int)0.0, L"assert5"); /* { dg-error "static assertion failed: \"assert5\"" } */
+};
+
+void
+f (void)
+{
+ int i;
+ i = 1;
+ _Static_assert (0 + 0, "assert6"); /* { dg-error "static assertion failed: \"assert6\"" } */
+ i = 2;
+}
+
+void
+g (void)
+{
+ int i = 0;
+ for (_Static_assert (0, "assert7"); i < 10; i++) /* { dg-error "static assertion failed: \"assert7\"" } */
+ ;
+}
Index: gcc/testsuite/gcc.dg/c1x-static-assert-6.c
===================================================================
--- gcc/testsuite/gcc.dg/c1x-static-assert-6.c (revision 0)
+++ gcc/testsuite/gcc.dg/c1x-static-assert-6.c (revision 0)
@@ -0,0 +1,5 @@
+/* Test C1X static assertions. Non-constant-expression with -pedantic. */
+/* { dg-do compile } */
+/* { dg-options "-std=c1x -pedantic" } */
+
+_Static_assert ((int)(1.0 + 1.0), "non-constant-expression"); /* { dg-warning "not an integer constant expression" } */
Index: gcc/testsuite/gcc.dg/c1x-static-assert-3.c
===================================================================
--- gcc/testsuite/gcc.dg/c1x-static-assert-3.c (revision 0)
+++ gcc/testsuite/gcc.dg/c1x-static-assert-3.c (revision 0)
@@ -0,0 +1,28 @@
+/* Test C1X static assertions. Invalid assertions. */
+/* { dg-do compile } */
+/* { dg-options "-std=c1x -pedantic-errors" } */
+
+_Static_assert (__INT_MAX__ * 2, "overflow"); /* { dg-warning "integer overflow in expression" } */
+/* { dg-error "overflow in constant expression" "error" { target *-*-* } 5 } */
+
+_Static_assert ((void *)(__SIZE_TYPE__)16, "non-integer"); /* { dg-error "not an integer" } */
+
+_Static_assert (1.0, "non-integer"); /* { dg-error "not an integer" } */
+
+_Static_assert ((int)(1.0 + 1.0), "non-constant-expression"); /* { dg-error "not an integer constant expression" } */
+
+int i;
+
+_Static_assert (i, "non-constant"); /* { dg-error "not constant" } */
+
+void
+f (void)
+{
+ int j = 0;
+ for (_Static_assert (sizeof (struct s { int k; }), ""); j < 10; j++) /* { dg-error "loop initial declaration" } */
+ ;
+}
+
+_Static_assert (1, 1); /* { dg-error "expected" } */
+
+_Static_assert (1, ("")); /* { dg-error "expected" } */
Index: gcc/testsuite/gcc.dg/c99-static-assert-1.c
===================================================================
--- gcc/testsuite/gcc.dg/c99-static-assert-1.c (revision 0)
+++ gcc/testsuite/gcc.dg/c99-static-assert-1.c (revision 0)
@@ -0,0 +1,5 @@
+/* Test for static assertions not in C99. */
+/* { dg-do compile } */
+/* { dg-options "-std=iso9899:1999 -pedantic-errors" } */
+
+_Static_assert (1, ""); /* { dg-error "ISO C99 does not support '_Static_assert'" } */
Index: gcc/testsuite/gcc.dg/c1x-static-assert-4.c
===================================================================
--- gcc/testsuite/gcc.dg/c1x-static-assert-4.c (revision 0)
+++ gcc/testsuite/gcc.dg/c1x-static-assert-4.c (revision 0)
@@ -0,0 +1,13 @@
+/* Test C1X static assertions. More invalid assertions. */
+/* { dg-do compile } */
+/* { dg-options "-std=c1x -pedantic-errors" } */
+
+/* Static assertions not valid in old-style parameter declarations
+ because declarations there must have declarators. */
+
+void
+f (i)
+ int i;
+ _Static_assert (1, ""); /* { dg-error "expected" } */
+{
+}
Index: gcc/c-common.c
===================================================================
--- gcc/c-common.c (revision 159439)
+++ gcc/c-common.c (working copy)
@@ -564,6 +564,7 @@ const struct c_common_resword c_common_r
{ "_Fract", RID_FRACT, D_CONLY | D_EXT },
{ "_Accum", RID_ACCUM, D_CONLY | D_EXT },
{ "_Sat", RID_SAT, D_CONLY | D_EXT },
+ { "_Static_assert", RID_STATIC_ASSERT, D_CONLY },
{ "__FUNCTION__", RID_FUNCTION_NAME, 0 },
{ "__PRETTY_FUNCTION__", RID_PRETTY_FUNCTION_NAME, 0 },
{ "__alignof", RID_ALIGNOF, 0 },
Index: gcc/c-parser.c
===================================================================
--- gcc/c-parser.c (revision 159439)
+++ gcc/c-parser.c (working copy)
@@ -495,6 +495,19 @@ c_token_starts_declspecs (c_token *token
}
}
+
+/* Return true if TOKEN can start declaration specifiers or a static
+ assertion, false otherwise. */
+static bool
+c_token_starts_declaration (c_token *token)
+{
+ if (c_token_starts_declspecs (token)
+ || token->keyword == RID_STATIC_ASSERT)
+ return true;
+ else
+ return false;
+}
+
/* Return true if the next token from PARSER can start declaration
specifiers, false otherwise. */
static inline bool
@@ -504,6 +517,15 @@ c_parser_next_token_starts_declspecs (c_
return c_token_starts_declspecs (token);
}
+/* Return true if the next token from PARSER can start declaration
+ specifiers or a static assertion, false otherwise. */
+static inline bool
+c_parser_next_token_starts_declaration (c_parser *parser)
+{
+ c_token *token = c_parser_peek_token (parser);
+ return c_token_starts_declaration (token);
+}
+
/* Return a pointer to the next-but-one token from PARSER, reading it
in if necessary. The next token is already read in. */
@@ -884,7 +906,10 @@ typedef enum c_dtr_syn {
static void c_parser_external_declaration (c_parser *);
static void c_parser_asm_definition (c_parser *);
-static void c_parser_declaration_or_fndef (c_parser *, bool, bool, bool, bool);
+static void c_parser_declaration_or_fndef (c_parser *, bool, bool, bool,
+ bool, bool);
+static void c_parser_static_assert_declaration_no_semi (c_parser *);
+static void c_parser_static_assert_declaration (c_parser *);
static void c_parser_declspecs (c_parser *, struct c_declspecs *, bool, bool,
bool);
static struct c_typespec c_parser_enum_specifier (c_parser *);
@@ -1102,7 +1127,7 @@ c_parser_external_declaration (c_parser
/* A declaration or a function definition. We can only tell
which after parsing the declaration specifiers, if any, and
the first declarator. */
- c_parser_declaration_or_fndef (parser, true, true, false, true);
+ c_parser_declaration_or_fndef (parser, true, true, true, false, true);
break;
}
}
@@ -1111,18 +1136,21 @@ c_parser_external_declaration (c_parser
/* Parse a declaration or function definition (C90 6.5, 6.7.1, C99
6.7, 6.9.1). If FNDEF_OK is true, a function definition is
accepted; otherwise (old-style parameter declarations) only other
- declarations are accepted. If NESTED is true, we are inside a
- function or parsing old-style parameter declarations; any functions
- encountered are nested functions and declaration specifiers are
- required; otherwise we are at top level and functions are normal
- functions and declaration specifiers may be optional. If EMPTY_OK
- is true, empty declarations are OK (subject to all other
- constraints); otherwise (old-style parameter declarations) they are
- diagnosed. If START_ATTR_OK is true, the declaration specifiers
- may start with attributes; otherwise they may not.
+ declarations are accepted. If STATIC_ASSERT_OK is true, a static
+ assertion is accepted; otherwise (old-style parameter declarations)
+ it is not. If NESTED is true, we are inside a function or parsing
+ old-style parameter declarations; any functions encountered are
+ nested functions and declaration specifiers are required; otherwise
+ we are at top level and functions are normal functions and
+ declaration specifiers may be optional. If EMPTY_OK is true, empty
+ declarations are OK (subject to all other constraints); otherwise
+ (old-style parameter declarations) they are diagnosed. If
+ START_ATTR_OK is true, the declaration specifiers may start with
+ attributes; otherwise they may not.
declaration:
declaration-specifiers init-declarator-list[opt] ;
+ static_assert-declaration
function-definition:
declaration-specifiers[opt] declarator declaration-list[opt]
@@ -1166,7 +1194,8 @@ c_parser_external_declaration (c_parser
threadprivate-directive */
static void
-c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, bool empty_ok,
+c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
+ bool static_assert_ok, bool empty_ok,
bool nested, bool start_attr_ok)
{
struct c_declspecs *specs;
@@ -1175,6 +1204,12 @@ c_parser_declaration_or_fndef (c_parser
bool diagnosed_no_specs = false;
location_t here = c_parser_peek_token (parser)->location;
+ if (static_assert_ok
+ && c_parser_next_token_is_keyword (parser, RID_STATIC_ASSERT))
+ {
+ c_parser_static_assert_declaration (parser);
+ return;
+ }
specs = build_null_declspecs ();
c_parser_declspecs (parser, specs, true, true, start_attr_ok);
if (parser->error)
@@ -1333,7 +1368,8 @@ c_parser_declaration_or_fndef (c_parser
function definitions either. */
while (c_parser_next_token_is_not (parser, CPP_EOF)
&& c_parser_next_token_is_not (parser, CPP_OPEN_BRACE))
- c_parser_declaration_or_fndef (parser, false, false, true, false);
+ c_parser_declaration_or_fndef (parser, false, false, false,
+ true, false);
store_parm_decls ();
DECL_STRUCT_FUNCTION (current_function_decl)->function_start_locus
= c_parser_peek_token (parser)->location;
@@ -1376,6 +1412,97 @@ c_parser_asm_definition (c_parser *parse
c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
}
+/* Parse a static assertion (C1X N1425 6.7.10).
+
+ static_assert-declaration:
+ static_assert-declaration-no-semi ;
+*/
+
+static void
+c_parser_static_assert_declaration (c_parser *parser)
+{
+ c_parser_static_assert_declaration_no_semi (parser);
+ if (parser->error
+ || !c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>"))
+ c_parser_skip_to_end_of_block_or_statement (parser);
+}
+
+/* Parse a static assertion (C1X N1425 6.7.10), without the trailing
+ semicolon.
+
+ static_assert-declaration-no-semi:
+ _Static_assert ( constant-expression , string-literal )
+*/
+
+static void
+c_parser_static_assert_declaration_no_semi (c_parser *parser)
+{
+ location_t assert_loc, value_loc;
+ tree value;
+ tree string;
+
+ gcc_assert (c_parser_next_token_is_keyword (parser, RID_STATIC_ASSERT));
+ assert_loc = c_parser_peek_token (parser)->location;
+ if (!flag_isoc1x)
+ {
+ if (flag_isoc99)
+ pedwarn (assert_loc, OPT_pedantic,
+ "ISO C99 does not support %<_Static_assert%>");
+ else
+ pedwarn (assert_loc, OPT_pedantic,
+ "ISO C90 does not support %<_Static_assert%>");
+ }
+ c_parser_consume_token (parser);
+ if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ return;
+ value_loc = c_parser_peek_token (parser)->location;
+ value = c_parser_expr_no_commas (parser, NULL).value;
+ parser->lex_untranslated_string = true;
+ if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>"))
+ {
+ parser->lex_untranslated_string = false;
+ return;
+ }
+ switch (c_parser_peek_token (parser)->type)
+ {
+ case CPP_STRING:
+ case CPP_STRING16:
+ case CPP_STRING32:
+ case CPP_WSTRING:
+ case CPP_UTF8STRING:
+ string = c_parser_peek_token (parser)->value;
+ c_parser_consume_token (parser);
+ parser->lex_untranslated_string = false;
+ break;
+ default:
+ c_parser_error (parser, "expected string literal");
+ parser->lex_untranslated_string = false;
+ return;
+ }
+ c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+
+ if (!INTEGRAL_TYPE_P (TREE_TYPE (value)))
+ {
+ error_at (value_loc, "expression in static assertion is not an integer");
+ return;
+ }
+ if (TREE_CODE (value) != INTEGER_CST)
+ {
+ value = c_fully_fold (value, false, NULL);
+ if (TREE_CODE (value) == INTEGER_CST)
+ pedwarn (value_loc, OPT_pedantic, "expression in static assertion "
+ "is not an integer constant expression");
+ }
+ if (TREE_CODE (value) != INTEGER_CST)
+ {
+ error_at (value_loc, "expression in static assertion is not constant");
+ return;
+ }
+ constant_expression_warning (value);
+ if (integer_zerop (value))
+ error_at (assert_loc, "static assertion failed: %E", string);
+}
+
/* Parse some declaration specifiers (possibly none) (C90 6.5, C99
6.7), adding them to SPECS (which may already include some).
Storage class specifiers are accepted iff SCSPEC_OK; type
@@ -1974,6 +2101,7 @@ c_parser_struct_or_union_specifier (c_pa
struct-declaration:
specifier-qualifier-list struct-declarator-list
+ static_assert-declaration-no-semi
specifier-qualifier-list:
type-specifier specifier-qualifier-list[opt]
@@ -2018,6 +2146,11 @@ c_parser_struct_declaration (c_parser *p
restore_extension_diagnostics (ext);
return decl;
}
+ if (c_parser_next_token_is_keyword (parser, RID_STATIC_ASSERT))
+ {
+ c_parser_static_assert_declaration_no_semi (parser);
+ return NULL_TREE;
+ }
specs = build_null_declspecs ();
decl_loc = c_parser_peek_token (parser)->location;
c_parser_declspecs (parser, specs, false, true, true);
@@ -3506,11 +3639,11 @@ c_parser_compound_statement_nostart (c_p
c_parser_label (parser);
}
else if (!last_label
- && c_parser_next_token_starts_declspecs (parser))
+ && c_parser_next_token_starts_declaration (parser))
{
last_label = false;
mark_valid_location_for_stdc_pragma (false);
- c_parser_declaration_or_fndef (parser, true, true, true, true);
+ c_parser_declaration_or_fndef (parser, true, true, true, true, true);
if (last_stmt)
pedwarn_c90 (loc,
(pedantic && !flag_isoc99)
@@ -3530,14 +3663,15 @@ c_parser_compound_statement_nostart (c_p
&& (c_parser_peek_2nd_token (parser)->keyword
== RID_EXTENSION))
c_parser_consume_token (parser);
- if (c_token_starts_declspecs (c_parser_peek_2nd_token (parser)))
+ if (c_token_starts_declaration (c_parser_peek_2nd_token (parser)))
{
int ext;
ext = disable_extension_diagnostics ();
c_parser_consume_token (parser);
last_label = false;
mark_valid_location_for_stdc_pragma (false);
- c_parser_declaration_or_fndef (parser, true, true, true, true);
+ c_parser_declaration_or_fndef (parser, true, true, true, true,
+ true);
/* Following the old parser, __extension__ does not
disable this diagnostic. */
restore_extension_diagnostics (ext);
@@ -3667,7 +3801,7 @@ c_parser_label (c_parser *parser)
}
if (label)
{
- if (c_parser_next_token_starts_declspecs (parser)
+ if (c_parser_next_token_starts_declaration (parser)
&& !(c_parser_next_token_is (parser, CPP_NAME)
&& c_parser_peek_2nd_token (parser)->type == CPP_COLON))
{
@@ -3675,6 +3809,7 @@ c_parser_label (c_parser *parser)
"a label can only be part of a statement and "
"a declaration is not a statement");
c_parser_declaration_or_fndef (parser, /*fndef_ok*/ false,
+ /*static_assert_ok*/ true,
/*nested*/ true, /*empty_ok*/ false,
/*start_attr_ok*/ true);
}
@@ -4211,9 +4346,9 @@ c_parser_for_statement (c_parser *parser
c_parser_consume_token (parser);
c_finish_expr_stmt (loc, NULL_TREE);
}
- else if (c_parser_next_token_starts_declspecs (parser))
+ else if (c_parser_next_token_starts_declaration (parser))
{
- c_parser_declaration_or_fndef (parser, true, true, true, true);
+ c_parser_declaration_or_fndef (parser, true, true, true, true, true);
check_for_loop_decls (for_loc);
}
else if (c_parser_next_token_is_keyword (parser, RID_EXTENSION))
@@ -4226,12 +4361,13 @@ c_parser_for_statement (c_parser *parser
&& (c_parser_peek_2nd_token (parser)->keyword
== RID_EXTENSION))
c_parser_consume_token (parser);
- if (c_token_starts_declspecs (c_parser_peek_2nd_token (parser)))
+ if (c_token_starts_declaration (c_parser_peek_2nd_token (parser)))
{
int ext;
ext = disable_extension_diagnostics ();
c_parser_consume_token (parser);
- c_parser_declaration_or_fndef (parser, true, true, true, true);
+ c_parser_declaration_or_fndef (parser, true, true, true, true,
+ true);
restore_extension_diagnostics (ext);
check_for_loop_decls (for_loc);
}
@@ -6519,7 +6655,8 @@ c_parser_objc_methodprotolist (c_parser
default:
if (c_parser_next_token_is_keyword (parser, RID_AT_END))
return;
- c_parser_declaration_or_fndef (parser, false, true, false, true);
+ c_parser_declaration_or_fndef (parser, false, false, true,
+ false, true);
break;
}
}
@@ -8040,12 +8177,12 @@ c_parser_omp_for_loop (location_t loc,
goto pop_scopes;
/* Parse the initialization declaration or expression. */
- if (c_parser_next_token_starts_declspecs (parser))
+ if (c_parser_next_token_starts_declaration (parser))
{
if (i > 0)
for_block
= tree_cons (NULL, c_begin_compound_stmt (true), for_block);
- c_parser_declaration_or_fndef (parser, true, true, true, true);
+ c_parser_declaration_or_fndef (parser, true, true, true, true, true);
decl = check_for_loop_decls (for_loc);
if (decl == NULL)
goto error_init;
--
Joseph S. Myers
joseph@codesourcery.com