From 55a3debe44095349b898ca6e297b0ecb9f9d16b6 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Tue, 21 Nov 2006 20:23:03 +0000 Subject: cp-tree.def (STATIC_ASSERT): New. 2006-11-21 Douglas Gregor * cp-tree.def (STATIC_ASSERT): New. * cp-objcp-common.c (cp_tree_size): Handle STATIC_ASSERT. * error.c (dump_decl): Handle STATIC_ASSERT. * cp-tree.h (STATIC_ASSERT_CONDITION): New. (STATIC_ASSERT_MESSAGE): New. (STATIC_ASSERT_SOURCE_LOCATION): New. (struct tree_static_assert): New. (enum cp_tree_node_structure_enum): Add TS_CP_STATIC_ASSERT. (union lang_tree_node): Add static_assertion. (finish_static_assert): Declare. * cxx-pretty-print.c (pp_cxx_statement): Handle STATIC_ASSERT. (pp_cxx_declaration): Handle STATIC_ASSERT. * pt.c (instantiate_class_template): Handle STATIC_ASSERT members. (tsubst_expr): Handle STATIC_ASSERT statements. * semantics.c (finish_static_assert): New. * lex.c (D_CPP0X): New. (reswords): Add static_assert keyword. (init_reswords): If not flag_cpp0x, mask out C++0x keywords. * parser.c (cp_parser_block_declaration): Parse static assertions. (cp_parser_static_assert): New. (cp_parser_member_declaration): Parse static assertions. From-SVN: r119066 --- gcc/cp/ChangeLog | 26 ++++++++++++++ gcc/cp/cp-objcp-common.c | 1 + gcc/cp/cp-tree.def | 8 +++++ gcc/cp/cp-tree.h | 28 +++++++++++++++ gcc/cp/cxx-pretty-print.c | 18 ++++++++-- gcc/cp/error.c | 4 +++ gcc/cp/lex.c | 5 ++- gcc/cp/parser.c | 86 ++++++++++++++++++++++++++++++++++++++++++++++- gcc/cp/pt.c | 28 +++++++++++++-- gcc/cp/semantics.c | 52 ++++++++++++++++++++++++++++ 10 files changed, 250 insertions(+), 6 deletions(-) diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 0cd3ccc..af4a3fc 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,29 @@ +2006-11-21 Douglas Gregor + + * cp-tree.def (STATIC_ASSERT): New. + * cp-objcp-common.c (cp_tree_size): Handle STATIC_ASSERT. + * error.c (dump_decl): Handle STATIC_ASSERT. + * cp-tree.h (STATIC_ASSERT_CONDITION): New. + (STATIC_ASSERT_MESSAGE): New. + (STATIC_ASSERT_SOURCE_LOCATION): New. + (struct tree_static_assert): New. + (enum cp_tree_node_structure_enum): Add TS_CP_STATIC_ASSERT. + (union lang_tree_node): Add static_assertion. + (finish_static_assert): Declare. + * cxx-pretty-print.c (pp_cxx_statement): Handle STATIC_ASSERT. + (pp_cxx_declaration): Handle STATIC_ASSERT. + * pt.c (instantiate_class_template): Handle + STATIC_ASSERT members. + (tsubst_expr): Handle STATIC_ASSERT statements. + * semantics.c (finish_static_assert): New. + * lex.c (D_CPP0X): New. + (reswords): Add static_assert keyword. + (init_reswords): If not flag_cpp0x, mask out C++0x keywords. + * parser.c (cp_parser_block_declaration): Parse static + assertions. + (cp_parser_static_assert): New. + (cp_parser_member_declaration): Parse static assertions. + 2006-11-21 Jakub Jelinek PR c++/29570 diff --git a/gcc/cp/cp-objcp-common.c b/gcc/cp/cp-objcp-common.c index f40be96..a3e19db 100644 --- a/gcc/cp/cp-objcp-common.c +++ b/gcc/cp/cp-objcp-common.c @@ -123,6 +123,7 @@ cp_tree_size (enum tree_code code) case TEMPLATE_PARM_INDEX: return sizeof (template_parm_index); case DEFAULT_ARG: return sizeof (struct tree_default_arg); case OVERLOAD: return sizeof (struct tree_overload); + case STATIC_ASSERT: return sizeof (struct tree_static_assert); default: gcc_unreachable (); } diff --git a/gcc/cp/cp-tree.def b/gcc/cp/cp-tree.def index 55ef21e..090f91f 100644 --- a/gcc/cp/cp-tree.def +++ b/gcc/cp/cp-tree.def @@ -342,6 +342,14 @@ DEFTREECODE (STMT_EXPR, "stmt_expr", tcc_expression, 1) is applied. */ DEFTREECODE (UNARY_PLUS_EXPR, "unary_plus_expr", tcc_unary, 1) +/** C++0x extensions. */ + +/* A static assertion. This is a C++0x extension. + STATIC_ASSERT_CONDITION contains the condition that is being + checked. STATIC_ASSERT_MESSAGE contains the message (a string + literal) to be displayed if the condition fails to hold. */ +DEFTREECODE (STATIC_ASSERT, "static_assert", tcc_exceptional, 0) + /* Local variables: mode:c diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 43e6e29..0270eb3 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -446,6 +446,29 @@ struct tree_default_arg GTY (()) VEC(tree,gc) *instantiations; }; +/* The condition associated with the static assertion. This must be + an integral constant expression. */ +#define STATIC_ASSERT_CONDITION(NODE) \ + (((struct tree_static_assert *)STATIC_ASSERT_CHECK (NODE))->condition) + +/* The message associated with the static assertion. This must be a + string constant, which will be emitted as an error message when the + static assert condition is false. */ +#define STATIC_ASSERT_MESSAGE(NODE) \ + (((struct tree_static_assert *)STATIC_ASSERT_CHECK (NODE))->message) + +/* Source location information for a static assertion. */ +#define STATIC_ASSERT_SOURCE_LOCATION(NODE) \ + (((struct tree_static_assert *)STATIC_ASSERT_CHECK (NODE))->location) + +struct tree_static_assert GTY (()) +{ + struct tree_common common; + tree condition; + tree message; + location_t location; +}; + enum cp_tree_node_structure_enum { TS_CP_GENERIC, TS_CP_IDENTIFIER, @@ -457,6 +480,7 @@ enum cp_tree_node_structure_enum { TS_CP_BASELINK, TS_CP_WRAPPER, TS_CP_DEFAULT_ARG, + TS_CP_STATIC_ASSERT, LAST_TS_CP_ENUM }; @@ -473,6 +497,8 @@ union lang_tree_node GTY((desc ("cp_tree_node_structure (&%h)"), struct tree_baselink GTY ((tag ("TS_CP_BASELINK"))) baselink; struct tree_default_arg GTY ((tag ("TS_CP_DEFAULT_ARG"))) default_arg; struct lang_identifier GTY ((tag ("TS_CP_IDENTIFIER"))) identifier; + struct tree_static_assert GTY ((tag ("TS_CP_STATIC_ASSERT"))) + static_assertion; }; @@ -4326,6 +4352,8 @@ extern tree cxx_omp_clause_assign_op (tree, tree, tree); extern tree cxx_omp_clause_dtor (tree, tree); extern bool cxx_omp_privatize_by_reference (tree); extern tree baselink_for_fns (tree); +extern void finish_static_assert (tree, tree, location_t, + bool); /* in tree.c */ extern void lang_check_failed (const char *, int, diff --git a/gcc/cp/cxx-pretty-print.c b/gcc/cp/cxx-pretty-print.c index 5ceca61..4f2bf86 100644 --- a/gcc/cp/cxx-pretty-print.c +++ b/gcc/cp/cxx-pretty-print.c @@ -1711,6 +1711,10 @@ pp_cxx_statement (cxx_pretty_printer *pp, tree t) pp_newline_and_indent (pp, -2); break; + case STATIC_ASSERT: + pp_cxx_declaration (pp, t); + break; + default: pp_c_statement (pp_c_base (pp), t); break; @@ -1906,11 +1910,21 @@ pp_cxx_explicit_instantiation (cxx_pretty_printer *pp, tree t) asm-definition namespace-alias-definition using-declaration - using-directive */ + using-directive + static_assert-declaration */ void pp_cxx_declaration (cxx_pretty_printer *pp, tree t) { - if (!DECL_LANG_SPECIFIC (t)) + if (TREE_CODE (t) == STATIC_ASSERT) + { + pp_cxx_identifier (pp, "static_assert"); + pp_cxx_left_paren (pp); + pp_cxx_expression (pp, STATIC_ASSERT_CONDITION (t)); + pp_cxx_separate_with (pp, ','); + pp_cxx_expression (pp, STATIC_ASSERT_MESSAGE (t)); + pp_cxx_right_paren (pp); + } + else if (!DECL_LANG_SPECIFIC (t)) pp_cxx_simple_declaration (pp, t); else if (DECL_USE_TEMPLATE (t)) switch (DECL_USE_TEMPLATE (t)) diff --git a/gcc/cp/error.c b/gcc/cp/error.c index f873558..c4f4d46 100644 --- a/gcc/cp/error.c +++ b/gcc/cp/error.c @@ -886,6 +886,10 @@ dump_decl (tree t, int flags) dump_decl (DECL_NAME (t), flags); break; + case STATIC_ASSERT: + pp_cxx_declaration (cxx_pp, t); + break; + case BASELINK: dump_decl (BASELINK_FUNCTIONS (t), flags); break; diff --git a/gcc/cp/lex.c b/gcc/cp/lex.c index d14a1ba..27a17c3 100644 --- a/gcc/cp/lex.c +++ b/gcc/cp/lex.c @@ -176,6 +176,7 @@ struct resword #define D_EXT 0x01 /* GCC extension */ #define D_ASM 0x02 /* in C99, but has a switch to turn it off */ #define D_OBJC 0x04 /* Objective C++ only */ +#define D_CPP0X 0x08 /* C++0x only */ CONSTRAINT(ridbits_fit, RID_LAST_MODIFIER < sizeof(unsigned long) * CHAR_BIT); @@ -259,6 +260,7 @@ static const struct resword reswords[] = { "signed", RID_SIGNED, 0 }, { "sizeof", RID_SIZEOF, 0 }, { "static", RID_STATIC, 0 }, + { "static_assert", RID_STATIC_ASSERT, D_CPP0X }, { "static_cast", RID_STATCAST, 0 }, { "struct", RID_STRUCT, 0 }, { "switch", RID_SWITCH, 0 }, @@ -314,7 +316,8 @@ init_reswords (void) tree id; int mask = ((flag_no_asm ? D_ASM : 0) | D_OBJC - | (flag_no_gnu_keywords ? D_EXT : 0)); + | (flag_no_gnu_keywords ? D_EXT : 0) + | (flag_cpp0x ? 0 : D_CPP0X)); ridpointers = GGC_CNEWVEC (tree, (int) RID_MAX); for (i = 0; i < ARRAY_SIZE (reswords); i++) diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 8e79eab..c5dfea6 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -1589,6 +1589,8 @@ static void cp_parser_asm_definition (cp_parser *); static void cp_parser_linkage_specification (cp_parser *); +static void cp_parser_static_assert + (cp_parser *, bool); /* Declarators [gram.dcl.decl] */ @@ -7211,6 +7213,11 @@ cp_parser_declaration (cp_parser* parser) __extension__ block-declaration label-declaration + C++0x Extension: + + block-declaration: + static_assert-declaration + If STATEMENT_P is TRUE, then this block-declaration is occurring as part of a declaration-statement. */ @@ -7272,6 +7279,9 @@ cp_parser_block_declaration (cp_parser *parser, cp_parser_commit_to_tentative_parse (parser); cp_parser_label_declaration (parser); } + /* If the next token is `static_assert' we have a static assertion. */ + else if (token1->keyword == RID_STATIC_ASSERT) + cp_parser_static_assert (parser, /*member_p=*/false); /* Anything else must be a simple-declaration. */ else cp_parser_simple_declaration (parser, !statement_p); @@ -7825,6 +7835,68 @@ cp_parser_linkage_specification (cp_parser* parser) pop_lang_context (); } +/* Parse a static_assert-declaration. + + static_assert-declaration: + static_assert ( constant-expression , string-literal ) ; + + If MEMBER_P, this static_assert is a class member. */ + +static void +cp_parser_static_assert(cp_parser *parser, bool member_p) +{ + tree condition; + tree message; + cp_token *token; + location_t saved_loc; + + /* Peek at the `static_assert' token so we can keep track of exactly + where the static assertion started. */ + token = cp_lexer_peek_token (parser->lexer); + saved_loc = token->location; + + /* Look for the `static_assert' keyword. */ + if (!cp_parser_require_keyword (parser, RID_STATIC_ASSERT, + "`static_assert'")) + return; + + /* We know we are in a static assertion; commit to any tentative + parse. */ + if (cp_parser_parsing_tentatively (parser)) + cp_parser_commit_to_tentative_parse (parser); + + /* Parse the `(' starting the static assertion condition. */ + cp_parser_require (parser, CPP_OPEN_PAREN, "`('"); + + /* Parse the constant-expression. */ + condition = + cp_parser_constant_expression (parser, + /*allow_non_constant_p=*/false, + /*non_constant_p=*/NULL); + + /* Parse the separating `,'. */ + cp_parser_require (parser, CPP_COMMA, "`,'"); + + /* Parse the string-literal message. */ + message = cp_parser_string_literal (parser, + /*translate=*/false, + /*wide_ok=*/true); + + /* A `)' completes the static assertion. */ + if (!cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'")) + cp_parser_skip_to_closing_parenthesis (parser, + /*recovering=*/true, + /*or_comma=*/false, + /*consume_paren=*/true); + + /* A semicolon terminates the declaration. */ + cp_parser_require (parser, CPP_SEMICOLON, "`;'"); + + /* Complete the static assertion, which may mean either processing + the static assert now or saving it for template instantiation. */ + finish_static_assert (condition, message, saved_loc, member_p); +} + /* Special member functions [gram.special] */ /* Parse a conversion-function-id. @@ -13624,7 +13696,12 @@ cp_parser_member_specification_opt (cp_parser* parser) member-declarator: declarator attributes [opt] pure-specifier [opt] declarator attributes [opt] constant-initializer [opt] - identifier [opt] attributes [opt] : constant-expression */ + identifier [opt] attributes [opt] : constant-expression + + C++0x Extensions: + + member-declaration: + static_assert-declaration */ static void cp_parser_member_declaration (cp_parser* parser) @@ -13687,6 +13764,13 @@ cp_parser_member_declaration (cp_parser* parser) return; } + /* If the next token is `static_assert' we have a static assertion. */ + if (cp_lexer_next_token_is_keyword (parser->lexer, RID_STATIC_ASSERT)) + { + cp_parser_static_assert (parser, /*member_p=*/true); + return; + } + if (cp_parser_using_declaration (parser, /*access_declaration=*/true)) return; diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 16e3e18..bcaae6b 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -5886,8 +5886,18 @@ instantiate_class_template (tree type) else { /* Build new TYPE_FIELDS. */ - - if (TREE_CODE (t) != CONST_DECL) + if (TREE_CODE (t) == STATIC_ASSERT) + { + tree condition = + tsubst_expr (STATIC_ASSERT_CONDITION (t), args, + tf_warning_or_error, NULL_TREE, + /*integral_constant_expression_p=*/true); + finish_static_assert (condition, + STATIC_ASSERT_MESSAGE (t), + STATIC_ASSERT_SOURCE_LOCATION (t), + /*member_p=*/true); + } + else if (TREE_CODE (t) != CONST_DECL) { tree r; @@ -8716,6 +8726,20 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, tsubst (TREE_TYPE (t), args, complain, NULL_TREE); break; + case STATIC_ASSERT: + { + tree condition = + tsubst_expr (STATIC_ASSERT_CONDITION (t), + args, + complain, in_decl, + /*integral_constant_expression_p=*/true); + finish_static_assert (condition, + STATIC_ASSERT_MESSAGE (t), + STATIC_ASSERT_SOURCE_LOCATION (t), + /*member_p=*/false); + } + break; + case OMP_PARALLEL: tmp = tsubst_omp_clauses (OMP_PARALLEL_CLAUSES (t), args, complain, in_decl); diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index e3dc3ab..9192aff 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -3914,5 +3914,57 @@ void init_cp_semantics (void) { } + +/* Build a STATIC_ASSERT for a static assertion with the condition + CONDITION and the message text MESSAGE. LOCATION is the location + of the static assertion in the source code. When MEMBER_P, this + static assertion is a member of a class. */ +void +finish_static_assert (tree condition, tree message, location_t location, + bool member_p) +{ + if (type_dependent_expression_p (condition) + || value_dependent_expression_p (condition)) + { + /* We're in a template; build a STATIC_ASSERT and put it in + the right place. */ + tree assertion; + + assertion = make_node (STATIC_ASSERT); + STATIC_ASSERT_CONDITION (assertion) = condition; + STATIC_ASSERT_MESSAGE (assertion) = message; + STATIC_ASSERT_SOURCE_LOCATION (assertion) = location; + + if (member_p) + maybe_add_class_template_decl_list (current_class_type, + assertion, + /*friend_p=*/0); + else + add_stmt (assertion); + + return; + } + + /* Fold the expression and convert it to a boolean value. */ + condition = fold_non_dependent_expr (condition); + condition = cp_convert (boolean_type_node, condition); + + if (TREE_CODE (condition) == INTEGER_CST && !integer_zerop (condition)) + /* Do nothing; the condition is satisfied. */ + ; + else + { + location_t saved_loc = input_location; + + input_location = location; + if (TREE_CODE (condition) == INTEGER_CST + && integer_zerop (condition)) + /* Report the error. */ + error ("static assertion failed: %E", message); + else if (condition && condition != error_mark_node) + error ("non-constant condition for static assertion"); + input_location = saved_loc; + } +} #include "gt-cp-semantics.h" -- cgit v1.1