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
This commit is contained in:
Douglas Gregor 2006-11-21 20:23:03 +00:00 committed by Doug Gregor
parent 218f00156c
commit 55a3debe44
10 changed files with 250 additions and 6 deletions

View File

@ -1,3 +1,29 @@
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>
PR c++/29570

View File

@ -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 ();
}

View File

@ -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

View File

@ -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,

View File

@ -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))

View File

@ -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;

View File

@ -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++)

View File

@ -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;

View File

@ -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);

View File

@ -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"