aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp/parser.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/cp/parser.c')
-rw-r--r--gcc/cp/parser.c204
1 files changed, 122 insertions, 82 deletions
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 33f1d79..8af9f46 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -1311,7 +1311,7 @@ static tree cp_parser_class_or_namespace_name
static tree cp_parser_postfix_expression
(cp_parser *, bool);
static tree cp_parser_parenthesized_expression_list
- (cp_parser *, bool);
+ (cp_parser *, bool, bool *);
static void cp_parser_pseudo_destructor_name
(cp_parser *, tree *, tree *);
static tree cp_parser_unary_expression
@@ -1356,8 +1356,6 @@ static tree cp_parser_logical_and_expression
(cp_parser *);
static tree cp_parser_logical_or_expression
(cp_parser *);
-static tree cp_parser_conditional_expression
- (cp_parser *);
static tree cp_parser_question_colon_clause
(cp_parser *, tree);
static tree cp_parser_assignment_expression
@@ -1479,11 +1477,11 @@ static tree cp_parser_function_definition
static void cp_parser_function_body
(cp_parser *);
static tree cp_parser_initializer
- (cp_parser *, bool *);
+ (cp_parser *, bool *, bool *);
static tree cp_parser_initializer_clause
- (cp_parser *);
+ (cp_parser *, bool *);
static tree cp_parser_initializer_list
- (cp_parser *);
+ (cp_parser *, bool *);
static bool cp_parser_ctor_initializer_opt_and_function_body
(cp_parser *);
@@ -3375,9 +3373,10 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p)
keep going. */
if (!cp_parser_error_occurred (parser))
{
+ bool non_constant_p;
/* Parse the initializer-list. */
initializer_list
- = cp_parser_initializer_list (parser);
+ = cp_parser_initializer_list (parser, &non_constant_p);
/* Allow a trailing `,'. */
if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA))
cp_lexer_consume_token (parser->lexer);
@@ -3472,7 +3471,8 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p)
case CPP_OPEN_PAREN:
/* postfix-expression ( expression-list [opt] ) */
{
- tree args = cp_parser_parenthesized_expression_list (parser, false);
+ tree args = (cp_parser_parenthesized_expression_list
+ (parser, false, /*non_constant_p=*/NULL));
if (args == error_mark_node)
{
@@ -3735,14 +3735,22 @@ cp_parser_postfix_expression (cp_parser *parser, bool address_p)
error_mark_node is returned if the ( and or ) are
missing. NULL_TREE is returned on no expressions. The parentheses
are eaten. IS_ATTRIBUTE_LIST is true if this is really an attribute
- list being parsed. */
+ list being parsed. If NON_CONSTANT_P is non-NULL, *NON_CONSTANT_P
+ indicates whether or not all of the expressions in the list were
+ constant. */
static tree
-cp_parser_parenthesized_expression_list (cp_parser* parser, bool is_attribute_list)
+cp_parser_parenthesized_expression_list (cp_parser* parser,
+ bool is_attribute_list,
+ bool *non_constant_p)
{
tree expression_list = NULL_TREE;
tree identifier = NULL_TREE;
-
+
+ /* Assume all the expressions will be constant. */
+ if (non_constant_p)
+ *non_constant_p = false;
+
if (!cp_parser_require (parser, CPP_OPEN_PAREN, "`('"))
return error_mark_node;
@@ -3767,7 +3775,17 @@ cp_parser_parenthesized_expression_list (cp_parser* parser, bool is_attribute_li
else
{
/* Parse the next assignment-expression. */
- expr = cp_parser_assignment_expression (parser);
+ if (non_constant_p)
+ {
+ bool expr_non_constant_p;
+ expr = (cp_parser_constant_expression
+ (parser, /*allow_non_constant_p=*/true,
+ &expr_non_constant_p));
+ if (expr_non_constant_p)
+ *non_constant_p = true;
+ }
+ else
+ expr = cp_parser_assignment_expression (parser);
/* Add it to the list. We add error_mark_node
expressions to the list, so that we can still tell if
@@ -4177,7 +4195,8 @@ cp_parser_new_placement (cp_parser* parser)
tree expression_list;
/* Parse the expression-list. */
- expression_list = cp_parser_parenthesized_expression_list (parser, false);
+ expression_list = (cp_parser_parenthesized_expression_list
+ (parser, false, /*non_constant_p=*/NULL));
return expression_list;
}
@@ -4341,7 +4360,8 @@ cp_parser_new_initializer (cp_parser* parser)
{
tree expression_list;
- expression_list = cp_parser_parenthesized_expression_list (parser, false);
+ expression_list = (cp_parser_parenthesized_expression_list
+ (parser, false, /*non_constant_p=*/NULL));
if (!expression_list)
expression_list = void_zero_node;
@@ -4755,43 +4775,12 @@ cp_parser_logical_or_expression (cp_parser* parser)
cp_parser_logical_and_expression);
}
-/* Parse a conditional-expression.
-
- conditional-expression:
- logical-or-expression
- logical-or-expression ? expression : assignment-expression
-
- GNU Extensions:
-
- conditional-expression:
- logical-or-expression ? : assignment-expression
-
- Returns a representation of the expression. */
-
-static tree
-cp_parser_conditional_expression (cp_parser* parser)
-{
- tree logical_or_expr;
-
- /* Parse the logical-or-expression. */
- logical_or_expr = cp_parser_logical_or_expression (parser);
- /* If the next token is a `?', then we have a real conditional
- expression. */
- if (cp_lexer_next_token_is (parser->lexer, CPP_QUERY))
- return cp_parser_question_colon_clause (parser, logical_or_expr);
- /* Otherwise, the value is simply the logical-or-expression. */
- else
- return logical_or_expr;
-}
-
/* Parse the `? expression : assignment-expression' part of a
conditional-expression. The LOGICAL_OR_EXPR is the
logical-or-expression that started the conditional-expression.
Returns a representation of the entire conditional-expression.
- This routine exists only so that it can be shared between
- cp_parser_conditional_expression and
- cp_parser_assignment_expression.
+ This routine is used by cp_parser_assignment_expression.
? expression : assignment-expression
@@ -5071,8 +5060,16 @@ cp_parser_constant_expression (cp_parser* parser,
parser->constant_expression_p = true;
parser->allow_non_constant_expression_p = allow_non_constant_p;
parser->non_constant_expression_p = false;
- /* Parse the conditional-expression. */
- expression = cp_parser_conditional_expression (parser);
+ /* Although the grammar says "conditional-expression", we parse an
+ "assignment-expression", which also permits "throw-expression"
+ and the use of assignment operators. In the case that
+ ALLOW_NON_CONSTANT_P is false, we get better errors than we would
+ otherwise. In the case that ALLOW_NON_CONSTANT_P is true, it is
+ actually essential that we look for an assignment-expression.
+ For example, cp_parser_initializer_clauses uses this function to
+ determine whether a particular assignment-expression is in fact
+ constant. */
+ expression = cp_parser_assignment_expression (parser);
/* Restore the old settings. */
parser->constant_expression_p = saved_constant_expression_p;
parser->allow_non_constant_expression_p
@@ -6081,6 +6078,15 @@ cp_parser_simple_declaration (cp_parser* parser,
/* We no longer need to defer access checks. */
stop_deferring_access_checks ();
+ /* In a block scope, a valid declaration must always have a
+ decl-specifier-seq. By not trying to parse declarators, we can
+ resolve the declaration/expression ambiguity more quickly. */
+ if (!function_definition_allowed_p && !decl_specifiers)
+ {
+ cp_parser_error (parser, "expected declaration");
+ goto done;
+ }
+
/* If the next two tokens are both identifiers, the code is
erroneous. The usual cause of this situation is code like:
@@ -6093,7 +6099,7 @@ cp_parser_simple_declaration (cp_parser* parser,
looking at a declaration. */
cp_parser_commit_to_tentative_parse (parser);
/* Give up. */
- return;
+ goto done;
}
/* Keep going until we hit the `;' at the end of the simple
@@ -6116,10 +6122,7 @@ cp_parser_simple_declaration (cp_parser* parser,
statement is treated as a declaration-statement until proven
otherwise.) */
if (cp_parser_error_occurred (parser))
- {
- pop_deferring_access_checks ();
- return;
- }
+ goto done;
/* Handle function definitions specially. */
if (function_definition_p)
{
@@ -6152,8 +6155,7 @@ cp_parser_simple_declaration (cp_parser* parser,
cp_parser_error (parser, "expected `,' or `;'");
/* Skip tokens until we reach the end of the statement. */
cp_parser_skip_to_end_of_statement (parser);
- pop_deferring_access_checks ();
- return;
+ goto done;
}
/* After the first time around, a function-definition is not
allowed -- even if it was OK at first. For example:
@@ -6175,14 +6177,15 @@ cp_parser_simple_declaration (cp_parser* parser,
perform_deferred_access_checks ();
}
- pop_deferring_access_checks ();
-
/* Consume the `;'. */
cp_parser_require (parser, CPP_SEMICOLON, "`;'");
/* Mark all the classes that appeared in the decl-specifier-seq as
having received a `;'. */
note_list_got_semicolon (decl_specifiers);
+
+ done:
+ pop_deferring_access_checks ();
}
/* Parse a decl-specifier-seq.
@@ -6774,7 +6777,9 @@ cp_parser_mem_initializer (cp_parser* parser)
if (member && !DECL_P (member))
in_base_initializer = 1;
- expression_list = cp_parser_parenthesized_expression_list (parser, false);
+ expression_list
+ = cp_parser_parenthesized_expression_list (parser, false,
+ /*non_constant_p=*/NULL);
if (!expression_list)
expression_list = void_type_node;
@@ -9156,6 +9161,7 @@ cp_parser_init_declarator (cp_parser* parser,
tree scope;
bool is_initialized;
bool is_parenthesized_init;
+ bool is_non_constant_init;
int ctor_dtor_or_conv_p;
bool friend_p;
@@ -9325,11 +9331,14 @@ cp_parser_init_declarator (cp_parser* parser,
/* Parse the initializer. */
if (is_initialized)
- initializer = cp_parser_initializer (parser, &is_parenthesized_init);
+ initializer = cp_parser_initializer (parser,
+ &is_parenthesized_init,
+ &is_non_constant_init);
else
{
initializer = NULL_TREE;
is_parenthesized_init = false;
+ is_non_constant_init = true;
}
/* The old parser allows attributes to appear after a parenthesized
@@ -9371,6 +9380,12 @@ cp_parser_init_declarator (cp_parser* parser,
((is_parenthesized_init || !is_initialized)
? 0 : LOOKUP_ONLYCONVERTING));
+ /* Remember whether or not variables were initialized by
+ constant-expressions. */
+ if (decl && TREE_CODE (decl) == VAR_DECL
+ && is_initialized && !is_non_constant_init)
+ DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl) = true;
+
return decl;
}
@@ -10729,10 +10744,13 @@ cp_parser_ctor_initializer_opt_and_function_body (cp_parser *parser)
*IS_PARENTHESIZED_INIT is set to TRUE if the `( expression-list )'
production is used, and zero otherwise. *IS_PARENTHESIZED_INIT is
- set to FALSE if there is no initializer present. */
+ set to FALSE if there is no initializer present. If there is an
+ initializer, and it is not a constant-expression, *NON_CONSTANT_P
+ is set to true; otherwise it is set to false. */
static tree
-cp_parser_initializer (cp_parser* parser, bool* is_parenthesized_init)
+cp_parser_initializer (cp_parser* parser, bool* is_parenthesized_init,
+ bool* non_constant_p)
{
cp_token *token;
tree init;
@@ -10743,16 +10761,19 @@ cp_parser_initializer (cp_parser* parser, bool* is_parenthesized_init)
/* Let our caller know whether or not this initializer was
parenthesized. */
*is_parenthesized_init = (token->type == CPP_OPEN_PAREN);
+ /* Assume that the initializer is constant. */
+ *non_constant_p = false;
if (token->type == CPP_EQ)
{
/* Consume the `='. */
cp_lexer_consume_token (parser->lexer);
/* Parse the initializer-clause. */
- init = cp_parser_initializer_clause (parser);
+ init = cp_parser_initializer_clause (parser, non_constant_p);
}
else if (token->type == CPP_OPEN_PAREN)
- init = cp_parser_parenthesized_expression_list (parser, false);
+ init = cp_parser_parenthesized_expression_list (parser, false,
+ non_constant_p);
else
{
/* Anything else is an error. */
@@ -10779,17 +10800,21 @@ cp_parser_initializer (cp_parser* parser, bool* is_parenthesized_init)
the elements of the initializer-list (or NULL_TREE, if the last
production is used). The TREE_TYPE for the CONSTRUCTOR will be
NULL_TREE. There is no way to detect whether or not the optional
- trailing `,' was provided. */
+ trailing `,' was provided. NON_CONSTANT_P is as for
+ cp_parser_initializer. */
static tree
-cp_parser_initializer_clause (cp_parser* parser)
+cp_parser_initializer_clause (cp_parser* parser, bool* non_constant_p)
{
tree initializer;
/* If it is not a `{', then we are looking at an
assignment-expression. */
if (cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_BRACE))
- initializer = cp_parser_assignment_expression (parser);
+ initializer
+ = cp_parser_constant_expression (parser,
+ /*allow_non_constant_p=*/true,
+ non_constant_p);
else
{
/* Consume the `{' token. */
@@ -10805,12 +10830,11 @@ cp_parser_initializer_clause (cp_parser* parser)
{
/* Parse the initializer list. */
CONSTRUCTOR_ELTS (initializer)
- = cp_parser_initializer_list (parser);
+ = cp_parser_initializer_list (parser, non_constant_p);
/* A trailing `,' token is allowed. */
if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA))
cp_lexer_consume_token (parser->lexer);
}
-
/* Now, there should be a trailing `}'. */
cp_parser_require (parser, CPP_CLOSE_BRACE, "`}'");
}
@@ -10832,20 +10856,25 @@ cp_parser_initializer_clause (cp_parser* parser)
Returns a TREE_LIST. The TREE_VALUE of each node is an expression
for the initializer. If the TREE_PURPOSE is non-NULL, it is the
- IDENTIFIER_NODE naming the field to initialize. */
+ IDENTIFIER_NODE naming the field to initialize. NON_CONSTANT_P is
+ as for cp_parser_initializer. */
static tree
-cp_parser_initializer_list (cp_parser* parser)
+cp_parser_initializer_list (cp_parser* parser, bool* non_constant_p)
{
tree initializers = NULL_TREE;
+ /* Assume all of the expressions are constant. */
+ *non_constant_p = false;
+
/* Parse the rest of the list. */
while (true)
{
cp_token *token;
tree identifier;
tree initializer;
-
+ bool clause_non_constant_p;
+
/* If the next token is an identifier and the following one is a
colon, we are looking at the GNU designated-initializer
syntax. */
@@ -10862,8 +10891,11 @@ cp_parser_initializer_list (cp_parser* parser)
identifier = NULL_TREE;
/* Parse the initializer. */
- initializer = cp_parser_initializer_clause (parser);
-
+ initializer = cp_parser_initializer_clause (parser,
+ &clause_non_constant_p);
+ /* If any clause is non-constant, so is the entire initializer. */
+ if (clause_non_constant_p)
+ *non_constant_p = true;
/* Add it to the list. */
initializers = tree_cons (identifier, initializer, initializers);
@@ -11821,12 +11853,18 @@ cp_parser_member_declaration (cp_parser* parser)
(cp_lexer_peek_token (parser->lexer)))
decl = error_mark_node;
else
- /* Create the declaration. */
- decl = grokfield (declarator,
- decl_specifiers,
- initializer,
- asm_specification,
- attributes);
+ {
+ /* Create the declaration. */
+ decl = grokfield (declarator,
+ decl_specifiers,
+ initializer,
+ asm_specification,
+ attributes);
+ /* Any initialization must have been from a
+ constant-expression. */
+ if (decl && TREE_CODE (decl) == VAR_DECL && initializer)
+ DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl) = 1;
+ }
}
/* Reset PREFIX_ATTRIBUTES. */
@@ -12616,8 +12654,8 @@ cp_parser_attribute_list (cp_parser* parser)
{
tree arguments;
- arguments = cp_parser_parenthesized_expression_list (parser, true);
-
+ arguments = (cp_parser_parenthesized_expression_list
+ (parser, true, /*non_constant_p=*/NULL));
/* Save the identifier and arguments away. */
TREE_VALUE (attribute) = arguments;
}
@@ -13583,7 +13621,9 @@ cp_parser_functional_cast (cp_parser* parser, tree type)
{
tree expression_list;
- expression_list = cp_parser_parenthesized_expression_list (parser, false);
+ expression_list
+ = cp_parser_parenthesized_expression_list (parser, false,
+ /*non_constant_p=*/NULL);
return build_functional_cast (type, expression_list);
}