aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/cp/ChangeLog26
-rw-r--r--gcc/cp/cp-objcp-common.c1
-rw-r--r--gcc/cp/cp-tree.def8
-rw-r--r--gcc/cp/cp-tree.h28
-rw-r--r--gcc/cp/cxx-pretty-print.c18
-rw-r--r--gcc/cp/error.c4
-rw-r--r--gcc/cp/lex.c5
-rw-r--r--gcc/cp/parser.c86
-rw-r--r--gcc/cp/pt.c28
-rw-r--r--gcc/cp/semantics.c52
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 <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
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"