Commit 55a3debe by Douglas Gregor Committed by Doug Gregor

cp-tree.def (STATIC_ASSERT): New.

2006-11-21      Douglas Gregor <doug.gregor@gmail.com>

        * 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
parent 218f0015
2006-11-21 Douglas Gregor <doug.gregor@gmail.com>
* 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 <jakub@redhat.com> 2006-11-21 Jakub Jelinek <jakub@redhat.com>
PR c++/29570 PR c++/29570
......
...@@ -123,6 +123,7 @@ cp_tree_size (enum tree_code code) ...@@ -123,6 +123,7 @@ cp_tree_size (enum tree_code code)
case TEMPLATE_PARM_INDEX: return sizeof (template_parm_index); case TEMPLATE_PARM_INDEX: return sizeof (template_parm_index);
case DEFAULT_ARG: return sizeof (struct tree_default_arg); case DEFAULT_ARG: return sizeof (struct tree_default_arg);
case OVERLOAD: return sizeof (struct tree_overload); case OVERLOAD: return sizeof (struct tree_overload);
case STATIC_ASSERT: return sizeof (struct tree_static_assert);
default: default:
gcc_unreachable (); gcc_unreachable ();
} }
......
...@@ -342,6 +342,14 @@ DEFTREECODE (STMT_EXPR, "stmt_expr", tcc_expression, 1) ...@@ -342,6 +342,14 @@ DEFTREECODE (STMT_EXPR, "stmt_expr", tcc_expression, 1)
is applied. */ is applied. */
DEFTREECODE (UNARY_PLUS_EXPR, "unary_plus_expr", tcc_unary, 1) 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: Local variables:
mode:c mode:c
......
...@@ -446,6 +446,29 @@ struct tree_default_arg GTY (()) ...@@ -446,6 +446,29 @@ struct tree_default_arg GTY (())
VEC(tree,gc) *instantiations; 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 { enum cp_tree_node_structure_enum {
TS_CP_GENERIC, TS_CP_GENERIC,
TS_CP_IDENTIFIER, TS_CP_IDENTIFIER,
...@@ -457,6 +480,7 @@ enum cp_tree_node_structure_enum { ...@@ -457,6 +480,7 @@ enum cp_tree_node_structure_enum {
TS_CP_BASELINK, TS_CP_BASELINK,
TS_CP_WRAPPER, TS_CP_WRAPPER,
TS_CP_DEFAULT_ARG, TS_CP_DEFAULT_ARG,
TS_CP_STATIC_ASSERT,
LAST_TS_CP_ENUM LAST_TS_CP_ENUM
}; };
...@@ -473,6 +497,8 @@ union lang_tree_node GTY((desc ("cp_tree_node_structure (&%h)"), ...@@ -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_baselink GTY ((tag ("TS_CP_BASELINK"))) baselink;
struct tree_default_arg GTY ((tag ("TS_CP_DEFAULT_ARG"))) default_arg; struct tree_default_arg GTY ((tag ("TS_CP_DEFAULT_ARG"))) default_arg;
struct lang_identifier GTY ((tag ("TS_CP_IDENTIFIER"))) identifier; 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); ...@@ -4326,6 +4352,8 @@ extern tree cxx_omp_clause_assign_op (tree, tree, tree);
extern tree cxx_omp_clause_dtor (tree, tree); extern tree cxx_omp_clause_dtor (tree, tree);
extern bool cxx_omp_privatize_by_reference (tree); extern bool cxx_omp_privatize_by_reference (tree);
extern tree baselink_for_fns (tree); extern tree baselink_for_fns (tree);
extern void finish_static_assert (tree, tree, location_t,
bool);
/* in tree.c */ /* in tree.c */
extern void lang_check_failed (const char *, int, extern void lang_check_failed (const char *, int,
......
...@@ -1711,6 +1711,10 @@ pp_cxx_statement (cxx_pretty_printer *pp, tree t) ...@@ -1711,6 +1711,10 @@ pp_cxx_statement (cxx_pretty_printer *pp, tree t)
pp_newline_and_indent (pp, -2); pp_newline_and_indent (pp, -2);
break; break;
case STATIC_ASSERT:
pp_cxx_declaration (pp, t);
break;
default: default:
pp_c_statement (pp_c_base (pp), t); pp_c_statement (pp_c_base (pp), t);
break; break;
...@@ -1906,11 +1910,21 @@ pp_cxx_explicit_instantiation (cxx_pretty_printer *pp, tree t) ...@@ -1906,11 +1910,21 @@ pp_cxx_explicit_instantiation (cxx_pretty_printer *pp, tree t)
asm-definition asm-definition
namespace-alias-definition namespace-alias-definition
using-declaration using-declaration
using-directive */ using-directive
static_assert-declaration */
void void
pp_cxx_declaration (cxx_pretty_printer *pp, tree t) 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); pp_cxx_simple_declaration (pp, t);
else if (DECL_USE_TEMPLATE (t)) else if (DECL_USE_TEMPLATE (t))
switch (DECL_USE_TEMPLATE (t)) switch (DECL_USE_TEMPLATE (t))
......
...@@ -886,6 +886,10 @@ dump_decl (tree t, int flags) ...@@ -886,6 +886,10 @@ dump_decl (tree t, int flags)
dump_decl (DECL_NAME (t), flags); dump_decl (DECL_NAME (t), flags);
break; break;
case STATIC_ASSERT:
pp_cxx_declaration (cxx_pp, t);
break;
case BASELINK: case BASELINK:
dump_decl (BASELINK_FUNCTIONS (t), flags); dump_decl (BASELINK_FUNCTIONS (t), flags);
break; break;
......
...@@ -176,6 +176,7 @@ struct resword ...@@ -176,6 +176,7 @@ struct resword
#define D_EXT 0x01 /* GCC extension */ #define D_EXT 0x01 /* GCC extension */
#define D_ASM 0x02 /* in C99, but has a switch to turn it off */ #define D_ASM 0x02 /* in C99, but has a switch to turn it off */
#define D_OBJC 0x04 /* Objective C++ only */ #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); CONSTRAINT(ridbits_fit, RID_LAST_MODIFIER < sizeof(unsigned long) * CHAR_BIT);
...@@ -259,6 +260,7 @@ static const struct resword reswords[] = ...@@ -259,6 +260,7 @@ static const struct resword reswords[] =
{ "signed", RID_SIGNED, 0 }, { "signed", RID_SIGNED, 0 },
{ "sizeof", RID_SIZEOF, 0 }, { "sizeof", RID_SIZEOF, 0 },
{ "static", RID_STATIC, 0 }, { "static", RID_STATIC, 0 },
{ "static_assert", RID_STATIC_ASSERT, D_CPP0X },
{ "static_cast", RID_STATCAST, 0 }, { "static_cast", RID_STATCAST, 0 },
{ "struct", RID_STRUCT, 0 }, { "struct", RID_STRUCT, 0 },
{ "switch", RID_SWITCH, 0 }, { "switch", RID_SWITCH, 0 },
...@@ -314,7 +316,8 @@ init_reswords (void) ...@@ -314,7 +316,8 @@ init_reswords (void)
tree id; tree id;
int mask = ((flag_no_asm ? D_ASM : 0) int mask = ((flag_no_asm ? D_ASM : 0)
| D_OBJC | 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); ridpointers = GGC_CNEWVEC (tree, (int) RID_MAX);
for (i = 0; i < ARRAY_SIZE (reswords); i++) for (i = 0; i < ARRAY_SIZE (reswords); i++)
......
...@@ -1589,6 +1589,8 @@ static void cp_parser_asm_definition ...@@ -1589,6 +1589,8 @@ static void cp_parser_asm_definition
(cp_parser *); (cp_parser *);
static void cp_parser_linkage_specification static void cp_parser_linkage_specification
(cp_parser *); (cp_parser *);
static void cp_parser_static_assert
(cp_parser *, bool);
/* Declarators [gram.dcl.decl] */ /* Declarators [gram.dcl.decl] */
...@@ -7211,6 +7213,11 @@ cp_parser_declaration (cp_parser* parser) ...@@ -7211,6 +7213,11 @@ cp_parser_declaration (cp_parser* parser)
__extension__ block-declaration __extension__ block-declaration
label-declaration label-declaration
C++0x Extension:
block-declaration:
static_assert-declaration
If STATEMENT_P is TRUE, then this block-declaration is occurring as If STATEMENT_P is TRUE, then this block-declaration is occurring as
part of a declaration-statement. */ part of a declaration-statement. */
...@@ -7272,6 +7279,9 @@ cp_parser_block_declaration (cp_parser *parser, ...@@ -7272,6 +7279,9 @@ cp_parser_block_declaration (cp_parser *parser,
cp_parser_commit_to_tentative_parse (parser); cp_parser_commit_to_tentative_parse (parser);
cp_parser_label_declaration (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. */ /* Anything else must be a simple-declaration. */
else else
cp_parser_simple_declaration (parser, !statement_p); cp_parser_simple_declaration (parser, !statement_p);
...@@ -7825,6 +7835,68 @@ cp_parser_linkage_specification (cp_parser* parser) ...@@ -7825,6 +7835,68 @@ cp_parser_linkage_specification (cp_parser* parser)
pop_lang_context (); 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] */ /* Special member functions [gram.special] */
/* Parse a conversion-function-id. /* Parse a conversion-function-id.
...@@ -13624,7 +13696,12 @@ cp_parser_member_specification_opt (cp_parser* parser) ...@@ -13624,7 +13696,12 @@ cp_parser_member_specification_opt (cp_parser* parser)
member-declarator: member-declarator:
declarator attributes [opt] pure-specifier [opt] declarator attributes [opt] pure-specifier [opt]
declarator attributes [opt] constant-initializer [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 static void
cp_parser_member_declaration (cp_parser* parser) cp_parser_member_declaration (cp_parser* parser)
...@@ -13687,6 +13764,13 @@ cp_parser_member_declaration (cp_parser* parser) ...@@ -13687,6 +13764,13 @@ cp_parser_member_declaration (cp_parser* parser)
return; 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)) if (cp_parser_using_declaration (parser, /*access_declaration=*/true))
return; return;
......
...@@ -5886,8 +5886,18 @@ instantiate_class_template (tree type) ...@@ -5886,8 +5886,18 @@ instantiate_class_template (tree type)
else else
{ {
/* Build new TYPE_FIELDS. */ /* Build new TYPE_FIELDS. */
if (TREE_CODE (t) == STATIC_ASSERT)
if (TREE_CODE (t) != CONST_DECL) {
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; tree r;
...@@ -8716,6 +8726,20 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl, ...@@ -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); tsubst (TREE_TYPE (t), args, complain, NULL_TREE);
break; 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: case OMP_PARALLEL:
tmp = tsubst_omp_clauses (OMP_PARALLEL_CLAUSES (t), tmp = tsubst_omp_clauses (OMP_PARALLEL_CLAUSES (t),
args, complain, in_decl); args, complain, in_decl);
......
...@@ -3914,5 +3914,57 @@ void ...@@ -3914,5 +3914,57 @@ void
init_cp_semantics (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" #include "gt-cp-semantics.h"
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment