/* C++ Parser.
- Copyright (C) 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+ Copyright (C) 2000, 2001, 2002, 2003, 2004,
+ 2005 Free Software Foundation, Inc.
Written by Mark Mitchell <mark@codesourcery.com>.
This file is part of GCC.
size_t space;
cp_token *buffer;
+ /* It's possible that lexing the first token will load a PCH file,
+ which is a GC collection point. So we have to grab the first
+ token before allocating any memory. Pragmas must not be deferred
+ as -fpch-preprocess can generate a pragma to load the PCH file in
+ the preprocessed output used by -save-temps. */
+ cp_lexer_get_preprocessor_token (NULL, &first_token);
+
/* Tell cpplib we want CPP_PRAGMA tokens. */
cpp_get_options (parse_in)->defer_pragmas = true;
/* Tell c_lex not to merge string constants. */
c_lex_return_raw_strings = true;
- /* It's possible that lexing the first token will load a PCH file,
- which is a GC collection point. So we have to grab the first
- token before allocating any memory. */
- cp_lexer_get_preprocessor_token (NULL, &first_token);
c_common_no_more_pch ();
/* Allocate the memory. */
static void
cp_lexer_start_debugging (cp_lexer* lexer)
{
- ++lexer->debugging_p;
+ lexer->debugging_p = true;
}
/* Stop emitting debugging information. */
static void
cp_lexer_stop_debugging (cp_lexer* lexer)
{
- --lexer->debugging_p;
+ lexer->debugging_p = false;
}
#endif /* ENABLE_CHECKING */
Other parts of the front end that need to create entities (like
VAR_DECLs or FUNCTION_DECLs) should do that directly. */
-static cp_declarator *make_id_declarator
- (tree);
static cp_declarator *make_call_declarator
(cp_declarator *, cp_parameter_declarator *, cp_cv_quals, tree);
static cp_declarator *make_array_declarator
return declarator;
}
-/* Make a declarator for a generalized identifier. */
+/* Make a declarator for a generalized identifier. If non-NULL, the
+ identifier is QUALIFYING_SCOPE::UNQUALIFIED_NAME; otherwise, it is
+ just UNQUALIFIED_NAME. */
-cp_declarator *
-make_id_declarator (tree id)
+static cp_declarator *
+make_id_declarator (tree qualifying_scope, tree unqualified_name)
{
cp_declarator *declarator;
+ /* It is valid to write:
+
+ class C { void f(); };
+ typedef C D;
+ void D::f();
+
+ The standard is not clear about whether `typedef const C D' is
+ legal; as of 2002-09-15 the committee is considering that
+ question. EDG 3.0 allows that syntax. Therefore, we do as
+ well. */
+ if (qualifying_scope && TYPE_P (qualifying_scope))
+ qualifying_scope = TYPE_MAIN_VARIANT (qualifying_scope);
+
declarator = make_declarator (cdk_id);
- declarator->u.id.name = id;
+ declarator->u.id.qualifying_scope = qualifying_scope;
+ declarator->u.id.unqualified_name = unqualified_name;
declarator->u.id.sfk = sfk_none;
return declarator;
/* Expressions [gram.expr] */
static tree cp_parser_primary_expression
- (cp_parser *, cp_id_kind *, tree *);
+ (cp_parser *, bool, cp_id_kind *, tree *);
static tree cp_parser_id_expression
(cp_parser *, bool, bool, bool *, bool);
static tree cp_parser_unqualified_id
static tree cp_parser_class_or_namespace_name
(cp_parser *, bool, bool, bool, bool, bool);
static tree cp_parser_postfix_expression
- (cp_parser *, bool);
+ (cp_parser *, bool, bool);
static tree cp_parser_postfix_open_square_expression
(cp_parser *, tree, bool);
static tree cp_parser_postfix_dot_deref_expression
(cp_parser *, enum cpp_ttype, tree, bool, cp_id_kind *);
static tree cp_parser_parenthesized_expression_list
- (cp_parser *, bool, bool *);
+ (cp_parser *, bool, bool, bool *);
static void cp_parser_pseudo_destructor_name
(cp_parser *, tree *, tree *);
static tree cp_parser_unary_expression
- (cp_parser *, bool);
+ (cp_parser *, bool, bool);
static enum tree_code cp_parser_unary_operator
(cp_token *);
static tree cp_parser_new_expression
static tree cp_parser_delete_expression
(cp_parser *);
static tree cp_parser_cast_expression
- (cp_parser *, bool);
+ (cp_parser *, bool, bool);
static tree cp_parser_binary_expression
- (cp_parser *);
+ (cp_parser *, bool);
static tree cp_parser_question_colon_clause
(cp_parser *, tree);
static tree cp_parser_assignment_expression
- (cp_parser *);
+ (cp_parser *, bool);
static enum tree_code cp_parser_assignment_operator_opt
(cp_parser *);
static tree cp_parser_expression
- (cp_parser *);
+ (cp_parser *, bool);
static tree cp_parser_constant_expression
(cp_parser *, bool, bool *);
static tree cp_parser_builtin_offsetof
(cp_parser *);
static inline bool cp_parser_parsing_tentatively
(cp_parser *);
-static bool cp_parser_committed_to_tentative_parse
+static bool cp_parser_uncommitted_to_tentative_parse_p
(cp_parser *);
static void cp_parser_error
(cp_parser *, const char *);
/* This diagnostic makes more sense if it is tagged to the line
of the token we just peeked at. */
cp_lexer_set_source_position_from_token (token);
+ if (token->type == CPP_PRAGMA)
+ {
+ error ("%<#pragma%> is not allowed here");
+ cp_lexer_purge_token (parser->lexer);
+ return;
+ }
c_parse_error (message,
/* Because c_parser_error does not understand
CPP_KEYWORD, keywords are treated like
static bool
cp_parser_simulate_error (cp_parser* parser)
{
- if (cp_parser_parsing_tentatively (parser)
- && !cp_parser_committed_to_tentative_parse (parser))
+ if (cp_parser_uncommitted_to_tentative_parse_p (parser))
{
parser->context->status = CP_PARSER_STATUS_KIND_ERROR;
return true;
else
error ("invalid template-id");
/* Remember the location of the invalid "<". */
- if (cp_parser_parsing_tentatively (parser)
- && !cp_parser_committed_to_tentative_parse (parser))
+ if (cp_parser_uncommitted_to_tentative_parse_p (parser))
start = cp_lexer_token_position (parser->lexer, true);
/* Consume the "<". */
cp_lexer_consume_token (parser->lexer);
/* If parsing an integral constant-expression, issue an error message
about the fact that THING appeared and return true. Otherwise,
- return false, marking the current expression as non-constant. */
+ return false. In either case, set
+ PARSER->NON_INTEGRAL_CONSTANT_EXPRESSION_P. */
static bool
cp_parser_non_integral_constant_expression (cp_parser *parser,
const char *thing)
{
+ parser->non_integral_constant_expression_p = true;
if (parser->integral_constant_expression_p)
{
if (!parser->allow_non_integral_constant_expression_p)
error ("%s cannot appear in a constant-expression", thing);
return true;
}
- parser->non_integral_constant_expression_p = true;
}
return false;
}
-/* Emit a diagnostic for an invalid type name. Consider also if it is
- qualified or not and the result of a lookup, to provide a better
- message. */
+/* Emit a diagnostic for an invalid type name. SCOPE is the
+ qualifying scope (or NULL, if none) for ID. This function commits
+ to the current active tentative parse, if any. (Otherwise, the
+ problematic construct might be encountered again later, resulting
+ in duplicate error messages.) */
static void
cp_parser_diagnose_invalid_type_name (cp_parser *parser, tree scope, tree id)
else
gcc_unreachable ();
}
+ cp_parser_commit_to_tentative_parse (parser);
}
/* Check for a common situation where a type-name should be present,
unsigned brace_depth = 0;
int result;
- if (recovering && !or_comma && cp_parser_parsing_tentatively (parser)
- && !cp_parser_committed_to_tentative_parse (parser))
+ if (recovering && !or_comma
+ && cp_parser_uncommitted_to_tentative_parse_p (parser))
return 0;
while (true)
literal:
__null
+ CAST_P is true if this primary expression is the target of a cast.
+
Returns a representation of the expression.
*IDK indicates what kind of id-expression (if any) was present.
static tree
cp_parser_primary_expression (cp_parser *parser,
+ bool cast_p,
cp_id_kind *idk,
tree *qualifying_class)
{
case CPP_WCHAR:
case CPP_NUMBER:
token = cp_lexer_consume_token (parser->lexer);
+ /* Floating-point literals are only allowed in an integral
+ constant expression if they are cast to an integral or
+ enumeration type. */
+ if (TREE_CODE (token->value) == REAL_CST
+ && parser->integral_constant_expression_p
+ && pedantic)
+ {
+ /* CAST_P will be set even in invalid code like "int(2.7 +
+ ...)". Therefore, we have to check that the next token
+ is sure to end the cast. */
+ if (cast_p)
+ {
+ cp_token *next_token;
+
+ next_token = cp_lexer_peek_token (parser->lexer);
+ if (/* The comma at the end of an
+ enumerator-definition. */
+ next_token->type != CPP_COMMA
+ /* The curly brace at the end of an enum-specifier. */
+ && next_token->type != CPP_CLOSE_BRACE
+ /* The end of a statement. */
+ && next_token->type != CPP_SEMICOLON
+ /* The end of the cast-expression. */
+ && next_token->type != CPP_CLOSE_PAREN
+ /* The end of an array bound. */
+ && next_token->type != CPP_CLOSE_SQUARE)
+ cast_p = false;
+ }
+
+ /* If we are within a cast, then the constraint that the
+ cast is to an integral or enumeration type will be
+ checked at that point. If we are not within a cast, then
+ this code is invalid. */
+ if (!cast_p)
+ cp_parser_non_integral_constant_expression
+ (parser, "floating-point literal");
+ }
return token->value;
case CPP_STRING:
else
{
/* Parse the parenthesized expression. */
- expr = cp_parser_expression (parser);
+ expr = cp_parser_expression (parser, cast_p);
/* Let the front end know that this expression was
enclosed in parentheses. This matters in case, for
example, the expression is of the form `A::B', since
/* Look for the opening `('. */
cp_parser_require (parser, CPP_OPEN_PAREN, "`('");
/* Now, parse the assignment-expression. */
- expression = cp_parser_assignment_expression (parser);
+ expression = cp_parser_assignment_expression (parser,
+ /*cast_p=*/false);
/* Look for the `,'. */
cp_parser_require (parser, CPP_COMMA, "`,'");
/* Parse the type-id. */
tree qualifying_scope;
tree object_scope;
tree scope;
+ bool done;
/* Consume the `~' token. */
cp_lexer_consume_token (parser->lexer);
/* If there was an explicit qualification (S::~T), first look
in the scope given by the qualification (i.e., S). */
+ done = false;
+ type_decl = NULL_TREE;
if (scope)
{
cp_parser_parse_tentatively (parser);
/*class_head_p=*/false,
declarator_p);
if (cp_parser_parse_definitely (parser))
- return build_nt (BIT_NOT_EXPR, TREE_TYPE (type_decl));
+ done = true;
}
/* In "N::S::~S", look in "N" as well. */
- if (scope && qualifying_scope)
+ if (!done && scope && qualifying_scope)
{
cp_parser_parse_tentatively (parser);
parser->scope = qualifying_scope;
/*class_head_p=*/false,
declarator_p);
if (cp_parser_parse_definitely (parser))
- return build_nt (BIT_NOT_EXPR, TREE_TYPE (type_decl));
+ done = true;
}
/* In "p->S::~T", look in the scope given by "*p" as well. */
- else if (object_scope)
+ else if (!done && object_scope)
{
cp_parser_parse_tentatively (parser);
parser->scope = object_scope;
/*class_head_p=*/false,
declarator_p);
if (cp_parser_parse_definitely (parser))
- return build_nt (BIT_NOT_EXPR, TREE_TYPE (type_decl));
+ done = true;
}
/* Look in the surrounding context. */
- parser->scope = NULL_TREE;
- parser->object_scope = NULL_TREE;
- parser->qualifying_scope = NULL_TREE;
- type_decl
- = cp_parser_class_name (parser,
- /*typename_keyword_p=*/false,
- /*template_keyword_p=*/false,
- none_type,
- /*check_dependency=*/false,
- /*class_head_p=*/false,
- declarator_p);
+ if (!done)
+ {
+ parser->scope = NULL_TREE;
+ parser->object_scope = NULL_TREE;
+ parser->qualifying_scope = NULL_TREE;
+ type_decl
+ = cp_parser_class_name (parser,
+ /*typename_keyword_p=*/false,
+ /*template_keyword_p=*/false,
+ none_type,
+ /*check_dependency=*/false,
+ /*class_head_p=*/false,
+ declarator_p);
+ }
/* If an error occurred, assume that the name of the
destructor is the same as the name of the qualifying
class. That allows us to keep parsing after running
identifier in the declarator for a destructor declaration. */
if (declarator_p
&& !DECL_IMPLICIT_TYPEDEF_P (type_decl)
- && !DECL_SELF_REFERENCE_P (type_decl))
+ && !DECL_SELF_REFERENCE_P (type_decl)
+ && !cp_parser_uncommitted_to_tentative_parse_p (parser))
error ("typedef-name %qD used as destructor declarator",
type_decl);
}
/* Remember where the nested-name-specifier starts. */
- if (cp_parser_parsing_tentatively (parser)
- && !cp_parser_committed_to_tentative_parse (parser))
+ if (cp_parser_uncommitted_to_tentative_parse_p (parser))
start = cp_lexer_token_position (parser->lexer, false);
push_deferring_access_checks (dk_deferred);
but they are essentially the same concept.)
If ADDRESS_P is true, the postfix expression is the operand of the
- `&' operator.
+ `&' operator. CAST_P is true if this expression is the target of a
+ cast.
Returns a representation of the expression. */
static tree
-cp_parser_postfix_expression (cp_parser *parser, bool address_p)
+cp_parser_postfix_expression (cp_parser *parser, bool address_p, bool cast_p)
{
cp_token *token;
enum rid keyword;
/* And the expression which is being cast. */
cp_parser_require (parser, CPP_OPEN_PAREN, "`('");
- expression = cp_parser_expression (parser);
+ expression = cp_parser_expression (parser, /*cast_p=*/true);
cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
/* Only type conversions to integral or enumeration types
tree expression;
/* Look for an expression. */
- expression = cp_parser_expression (parser);
+ expression = cp_parser_expression (parser, /*cast_p=*/false);
/* Compute its typeid. */
postfix_expression = build_typeid (expression);
/* Look for the `)' token. */
/* It must be a primary-expression. */
postfix_expression = cp_parser_primary_expression (parser,
+ cast_p,
&idk,
&qualifying_class);
}
{
bool koenig_p;
tree args = (cp_parser_parenthesized_expression_list
- (parser, false, /*non_constant_p=*/NULL));
+ (parser, false,
+ /*cast_p=*/false,
+ /*non_constant_p=*/NULL));
if (args == error_mark_node)
{
/* Function calls are not permitted in
constant-expressions. */
- if (cp_parser_non_integral_constant_expression (parser,
- "a function call"))
+ if (! builtin_valid_in_constant_expr_p (postfix_expression)
+ && cp_parser_non_integral_constant_expression (parser,
+ "a function call"))
{
postfix_expression = error_mark_node;
break;
if (for_offsetof)
index = cp_parser_constant_expression (parser, false, NULL);
else
- index = cp_parser_expression (parser);
+ index = cp_parser_expression (parser, /*cast_p=*/false);
/* Look for the closing `]'. */
cp_parser_require (parser, CPP_CLOSE_SQUARE, "`]'");
identifier
identifier, expression-list
+ CAST_P is true if this expression is the target of a cast.
+
Returns a TREE_LIST. The TREE_VALUE of each node is a
representation of an assignment-expression. Note that a TREE_LIST
is returned even if there is only a single expression in the list.
static tree
cp_parser_parenthesized_expression_list (cp_parser* parser,
bool is_attribute_list,
+ bool cast_p,
bool *non_constant_p)
{
tree expression_list = NULL_TREE;
*non_constant_p = true;
}
else
- expr = cp_parser_assignment_expression (parser);
+ expr = cp_parser_assignment_expression (parser, cast_p);
if (fold_expr_p)
expr = fold_non_dependent_expr (expr);
&& identifier
ADDRESS_P is true iff the unary-expression is appearing as the
- operand of the `&' operator.
+ operand of the `&' operator. CAST_P is true if this expression is
+ the target of a cast.
Returns a representation of the expression. */
static tree
-cp_parser_unary_expression (cp_parser *parser, bool address_p)
+cp_parser_unary_expression (cp_parser *parser, bool address_p, bool cast_p)
{
cp_token *token;
enum tree_code unary_operator;
token = cp_lexer_consume_token (parser->lexer);
/* Parse the cast-expression. */
cast_expression
- = cp_parser_cast_expression (parser, unary_operator == ADDR_EXPR);
+ = cp_parser_cast_expression (parser,
+ unary_operator == ADDR_EXPR,
+ /*cast_p=*/false);
/* Now, build an appropriate representation. */
switch (unary_operator)
{
return expression;
}
- return cp_parser_postfix_expression (parser, address_p);
+ return cp_parser_postfix_expression (parser, address_p, cast_p);
}
/* Returns ERROR_MARK if TOKEN is not a unary-operator. If TOKEN is a
/* Parse the expression-list. */
expression_list = (cp_parser_parenthesized_expression_list
- (parser, false, /*non_constant_p=*/NULL));
+ (parser, false, /*cast_p=*/false,
+ /*non_constant_p=*/NULL));
return expression_list;
}
*nelts = declarator->u.array.bounds;
if (*nelts == error_mark_node)
*nelts = integer_one_node;
- else if (!processing_template_decl)
- {
- if (!build_expr_type_conversion (WANT_INT | WANT_ENUM, *nelts,
- false))
- pedwarn ("size in array new must have integral type");
- *nelts = save_expr (cp_convert (sizetype, *nelts));
- if (*nelts == integer_zero_node)
- warning ("zero size array reserves no space");
- }
+
if (outer_declarator)
outer_declarator->declarator = declarator->declarator;
else
/* The first expression is not required to be constant. */
if (!declarator)
{
- expression = cp_parser_expression (parser);
+ expression = cp_parser_expression (parser, /*cast_p=*/false);
/* The standard requires that the expression have integral
type. DR 74 adds enumeration types. We believe that the
real intent is that these expressions be handled like the
tree expression_list;
expression_list = (cp_parser_parenthesized_expression_list
- (parser, false, /*non_constant_p=*/NULL));
+ (parser, false, /*cast_p=*/false,
+ /*non_constant_p=*/NULL));
if (!expression_list)
expression_list = void_zero_node;
unary-expression
( type-id ) cast-expression
+ ADDRESS_P is true iff the unary-expression is appearing as the
+ operand of the `&' operator. CAST_P is true if this expression is
+ the target of a cast.
+
Returns a representation of the expression. */
static tree
-cp_parser_cast_expression (cp_parser *parser, bool address_p)
+cp_parser_cast_expression (cp_parser *parser, bool address_p, bool cast_p)
{
/* If it's a `(', then we might be looking at a cast. */
if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN))
ctor of T, but looks like a cast to function returning T
without a dependent expression. */
if (!cp_parser_error_occurred (parser))
- expr = cp_parser_simple_cast_expression (parser);
+ expr = cp_parser_cast_expression (parser,
+ /*address_p=*/false,
+ /*cast_p=*/true);
if (cp_parser_parse_definitely (parser))
{
/* If we get here, then it's not a cast, so it must be a
unary-expression. */
- return cp_parser_unary_expression (parser, address_p);
+ return cp_parser_unary_expression (parser, address_p, cast_p);
}
/* Parse a binary expression of the general form:
simple-cast-expression
binary-expression <token> binary-expression
+ CAST_P is true if this expression is the target of a cast.
+
The binops_by_token map is used to get the tree codes for each <token> type.
binary-expressions are associated according to a precedence table. */
: binops_by_token[token->type].prec)
static tree
-cp_parser_binary_expression (cp_parser* parser)
+cp_parser_binary_expression (cp_parser* parser, bool cast_p)
{
cp_parser_expression_stack stack;
cp_parser_expression_stack_entry *sp = &stack[0];
bool overloaded_p;
/* Parse the first expression. */
- lhs = cp_parser_simple_cast_expression (parser);
+ lhs = cp_parser_cast_expression (parser, /*address_p=*/false, cast_p);
for (;;)
{
expr = NULL_TREE;
else
/* Parse the expression. */
- expr = cp_parser_expression (parser);
+ expr = cp_parser_expression (parser, /*cast_p=*/false);
/* The next token should be a `:'. */
cp_parser_require (parser, CPP_COLON, "`:'");
/* Parse the assignment-expression. */
- assignment_expr = cp_parser_assignment_expression (parser);
+ assignment_expr = cp_parser_assignment_expression (parser, /*cast_p=*/false);
/* Build the conditional-expression. */
return build_x_conditional_expr (logical_or_expr,
logical-or-expression assignment-operator assignment_expression
throw-expression
+ CAST_P is true if this expression is the target of a cast.
+
Returns a representation for the expression. */
static tree
-cp_parser_assignment_expression (cp_parser* parser)
+cp_parser_assignment_expression (cp_parser* parser, bool cast_p)
{
tree expr;
else
{
/* Parse the binary expressions (logical-or-expression). */
- expr = cp_parser_binary_expression (parser);
+ expr = cp_parser_binary_expression (parser, cast_p);
/* If the next token is a `?' then we're actually looking at a
conditional-expression. */
if (cp_lexer_next_token_is (parser->lexer, CPP_QUERY))
tree rhs;
/* Parse the right-hand side of the assignment. */
- rhs = cp_parser_assignment_expression (parser);
+ rhs = cp_parser_assignment_expression (parser, cast_p);
/* An assignment may not appear in a
constant-expression. */
if (cp_parser_non_integral_constant_expression (parser,
assignment-expression
expression , assignment-expression
+ CAST_P is true if this expression is the target of a cast.
+
Returns a representation of the expression. */
static tree
-cp_parser_expression (cp_parser* parser)
+cp_parser_expression (cp_parser* parser, bool cast_p)
{
tree expression = NULL_TREE;
/* Parse the next assignment-expression. */
assignment_expression
- = cp_parser_assignment_expression (parser);
+ = cp_parser_assignment_expression (parser, cast_p);
/* If this is the first assignment-expression, we can just
save it away. */
if (!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);
+ expression = cp_parser_assignment_expression (parser, /*cast_p=*/false);
/* Restore the old settings. */
- parser->integral_constant_expression_p = saved_integral_constant_expression_p;
+ parser->integral_constant_expression_p
+ = saved_integral_constant_expression_p;
parser->allow_non_integral_constant_expression_p
= saved_allow_non_integral_constant_expression_p;
if (allow_non_constant_p)
*non_constant_p = parser->non_integral_constant_expression_p;
- parser->non_integral_constant_expression_p = saved_non_integral_constant_expression_p;
+ else if (parser->non_integral_constant_expression_p)
+ expression = error_mark_node;
+ parser->non_integral_constant_expression_p
+ = saved_non_integral_constant_expression_p;
return expression;
}
/* If the next token is a ';', then there is no expression
statement. */
if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON))
- statement = cp_parser_expression (parser);
+ statement = cp_parser_expression (parser, /*cast_p=*/false);
/* Consume the final `;'. */
cp_parser_consume_semicolon_at_end_of_statement (parser);
if (in_statement_expr
&& cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_BRACE))
- {
- /* This is the final expression statement of a statement
- expression. */
- statement = finish_stmt_expr_expr (statement, in_statement_expr);
- }
+ /* This is the final expression statement of a statement
+ expression. */
+ statement = finish_stmt_expr_expr (statement, in_statement_expr);
else if (statement)
statement = finish_expr_stmt (statement);
else
for sure. */
if (cp_parser_parse_definitely (parser))
{
- bool pop_p;
+ tree pushed_scope;
/* Create the declaration. */
decl = start_decl (declarator, &type_specifiers,
/*initialized_p=*/true,
attributes, /*prefix_attributes=*/NULL_TREE,
- &pop_p);
+ &pushed_scope);
/* Parse the assignment-expression. */
- initializer = cp_parser_assignment_expression (parser);
+ initializer = cp_parser_assignment_expression (parser,
+ /*cast_p=*/false);
/* Process the initializer. */
cp_finish_decl (decl,
asm_specification,
LOOKUP_ONLYCONVERTING);
- if (pop_p)
- pop_scope (DECL_CONTEXT (decl));
+ if (pushed_scope)
+ pop_scope (pushed_scope);
return convert_from_reference (decl);
}
cp_parser_abort_tentative_parse (parser);
/* Otherwise, we are looking at an expression. */
- return cp_parser_expression (parser);
+ return cp_parser_expression (parser, /*cast_p=*/false);
}
/* Parse an iteration-statement.
/* Look for the `('. */
cp_parser_require (parser, CPP_OPEN_PAREN, "`('");
/* Parse the expression. */
- expression = cp_parser_expression (parser);
+ expression = cp_parser_expression (parser, /*cast_p=*/false);
/* We're done with the do-statement. */
finish_do_stmt (expression, statement);
/* Look for the `)'. */
/* If there's an expression, process it. */
if (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_PAREN))
- expression = cp_parser_expression (parser);
+ expression = cp_parser_expression (parser, /*cast_p=*/false);
finish_for_expr (expression, statement);
/* Look for the `)'. */
cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
/* If the next token is a `;', then there is no
expression. */
if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON))
- expr = cp_parser_expression (parser);
+ expr = cp_parser_expression (parser, /*cast_p=*/false);
else
expr = NULL_TREE;
/* Build the return-statement. */
/* Consume the '*' token. */
cp_lexer_consume_token (parser->lexer);
/* Parse the dependent expression. */
- finish_goto_stmt (cp_parser_expression (parser));
+ finish_goto_stmt (cp_parser_expression (parser, /*cast_p=*/false));
}
else
finish_goto_stmt (cp_parser_identifier (parser));
/* If we have already issued an error message we don't need
to issue another one. */
if (decl != error_mark_node
- || (cp_parser_parsing_tentatively (parser)
- && !cp_parser_committed_to_tentative_parse (parser)))
+ || cp_parser_uncommitted_to_tentative_parse_p (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);
tree saved_scope;
tree saved_qualifying_scope;
tree saved_object_scope;
- bool pop_p = false;
+ tree pushed_scope = NULL_TREE;
/* Look for the `operator' token. */
if (!cp_parser_require_keyword (parser, RID_OPERATOR, "`operator'"))
In order to see that `I' is a type-name in the definition, we
must be in the scope of `S'. */
if (saved_scope)
- pop_p = push_scope (saved_scope);
+ pushed_scope = push_scope (saved_scope);
/* Parse the conversion-type-id. */
type = cp_parser_conversion_type_id (parser);
/* Leave the scope of the class, if any. */
- if (pop_p)
- pop_scope (saved_scope);
+ if (pushed_scope)
+ pop_scope (pushed_scope);
/* Restore the saved scope. */
parser->scope = saved_scope;
parser->qualifying_scope = saved_qualifying_scope;
expression_list
= cp_parser_parenthesized_expression_list (parser, false,
+ /*cast_p=*/false,
/*non_constant_p=*/NULL);
if (!expression_list)
expression_list = void_type_node;
/* Parse the template-parameter. */
parameter = cp_parser_template_parameter (parser, &is_non_type);
/* Add it to the list. */
- parameter_list = process_template_parm (parameter_list,
- parameter,
- is_non_type);
+ if (parameter != error_mark_node)
+ parameter_list = process_template_parm (parameter_list,
+ parameter,
+ is_non_type);
/* Peek at the next token. */
token = cp_lexer_peek_token (parser->lexer);
/* If it's not a `,', we're done. */
type-parameter
parameter-declaration
- Returns a TREE_LIST. The TREE_VALUE represents the parameter. The
- TREE_PURPOSE is the default value, if any. *IS_NON_TYPE is set to
- true iff this parameter is a non-type parameter. */
+ If all goes well, returns a TREE_LIST. The TREE_VALUE represents
+ the parameter. The TREE_PURPOSE is the default value, if any.
+ Returns ERROR_MARK_NODE on failure. *IS_NON_TYPE is set to true
+ iff this parameter is a non-type parameter. */
static tree
cp_parser_template_parameter (cp_parser* parser, bool *is_non_type)
{
cp_token *token;
cp_parameter_declarator *parameter_declarator;
+ tree parm;
/* Assume it is a type parameter or a template parameter. */
*is_non_type = false;
parameter_declarator
= cp_parser_parameter_declaration (parser, /*template_parm_p=*/true,
/*parenthesized_p=*/NULL);
- return (build_tree_list
- (parameter_declarator->default_argument,
- grokdeclarator (parameter_declarator->declarator,
- ¶meter_declarator->decl_specifiers,
- PARM, /*initialized=*/0,
- /*attrlist=*/NULL)));
+ parm = grokdeclarator (parameter_declarator->declarator,
+ ¶meter_declarator->decl_specifiers,
+ PARM, /*initialized=*/0,
+ /*attrlist=*/NULL);
+ if (parm == error_mark_node)
+ return error_mark_node;
+ return build_tree_list (parameter_declarator->default_argument, parm);
}
/* Parse a type-parameter.
}
/* Remember where the template-id starts. */
- if (cp_parser_parsing_tentatively (parser)
- && !cp_parser_committed_to_tentative_parse (parser))
+ if (cp_parser_uncommitted_to_tentative_parse_p (parser))
start_of_id = cp_lexer_token_position (parser->lexer, false);
push_deferring_access_checks (dk_deferred);
/* Purge all subsequent tokens. */
cp_lexer_purge_tokens_after (parser->lexer, start_of_id);
+
+ /* ??? Can we actually assume that, if template_id ==
+ error_mark_node, we will have issued a diagnostic to the
+ user, as opposed to simply marking the tentative parse as
+ failed? */
+ if (cp_parser_error_occurred (parser) && template_id != error_mark_node)
+ error ("parse error in template argument list");
}
pop_deferring_access_checks ();
error ("non-template %qD used as template", identifier);
inform ("use %<%T::template %D%> to indicate that it is a template",
parser->scope, identifier);
- /* If parsing tentatively, find the location of the "<"
- token. */
- if (cp_parser_parsing_tentatively (parser)
- && !cp_parser_committed_to_tentative_parse (parser))
- {
- cp_parser_simulate_error (parser);
- start = cp_lexer_token_position (parser->lexer, true);
- }
+ /* If parsing tentatively, find the location of the "<" token. */
+ if (cp_parser_simulate_error (parser))
+ start = cp_lexer_token_position (parser->lexer, true);
/* Parse the template arguments so that we can issue error
messages about them. */
cp_lexer_consume_token (parser->lexer);
{
cp_parser_parse_tentatively (parser);
argument = cp_parser_primary_expression (parser,
+ /*cast_p=*/false,
&idk,
&qualifying_class);
if (TREE_CODE (argument) != TEMPLATE_PARM_INDEX
if (cp_parser_parse_definitely (parser))
return argument;
}
+
/* If the next token is "&", the argument must be the address of an
object or function with external linkage. */
address_p = cp_lexer_next_token_is (parser->lexer, CPP_AND);
{
cp_parser_parse_tentatively (parser);
argument = cp_parser_primary_expression (parser,
+ /*cast_p=*/false,
&idk,
&qualifying_class);
if (cp_parser_error_occurred (parser)
cp_parser_abort_tentative_parse (parser);
else
{
+ if (TREE_CODE (argument) == INDIRECT_REF)
+ {
+ gcc_assert (REFERENCE_REF_P (argument));
+ argument = TREE_OPERAND (argument, 0);
+ }
+
if (qualifying_class)
argument = finish_qualified_id_expr (qualifying_class,
argument,
|| TREE_CODE (argument) == SCOPE_REF))
/* A pointer-to-member. */
;
+ else if (TREE_CODE (argument) == TEMPLATE_PARM_INDEX)
+ ;
else
cp_parser_simulate_error (parser);
cp_parser_error (parser, "invalid non-type template argument");
return error_mark_node;
}
+
/* If the argument wasn't successfully parsed as a type-id followed
by '>>', the argument can only be a constant expression now.
Otherwise, we try parsing the constant-expression tentatively,
}
/* For a `typename', we needn't call xref_tag. */
- if (tag_type == typename_type)
+ if (tag_type == typename_type
+ && TREE_CODE (parser->scope) != NAMESPACE_DECL)
return cp_parser_make_typename_type (parser, parser->scope,
identifier);
/* Look up a qualified name in the usual way. */
{
tree decl;
- /* In an elaborated-type-specifier, names are assumed to name
- types, so we set IS_TYPE to TRUE when calling
- cp_parser_lookup_name. */
decl = cp_parser_lookup_name (parser, identifier,
tag_type,
/*is_template=*/false,
if (TREE_CODE (decl) != TYPE_DECL)
{
- error ("expected type-name");
+ cp_parser_diagnose_invalid_type_name (parser,
+ parser->scope,
+ identifier);
return error_mark_node;
}
if (at_class_scope_p ())
{
/* Create the USING_DECL. */
- decl = do_class_using_decl (build_nt (SCOPE_REF,
- parser->scope,
- identifier));
+ decl = do_class_using_decl (parser->scope, identifier);
/* Add it to the list of members in this class. */
finish_member_declaration (decl);
}
bool is_non_constant_init;
int ctor_dtor_or_conv_p;
bool friend_p;
- bool pop_p = false;
+ tree pushed_scope = NULL;
/* Gather the attributes that were provided with the
decl-specifiers. */
}
decl = start_decl (declarator, decl_specifiers,
is_initialized, attributes, prefix_attributes,
- &pop_p);
+ &pushed_scope);
}
else if (scope)
/* Enter the SCOPE. That way unqualified names appearing in the
initializer will be looked up in SCOPE. */
- pop_p = push_scope (scope);
+ pushed_scope = push_scope (scope);
/* Perform deferred access control checks, now that we know in which
SCOPE the declared entity resides. */
declaration. */
if (member_p)
{
- if (pop_p)
+ if (pushed_scope)
{
- pop_scope (scope);
- pop_p = false;
+ pop_scope (pushed_scope);
+ pushed_scope = false;
}
decl = grokfield (declarator, decl_specifiers,
initializer, /*asmspec=*/NULL_TREE,
`explicit' constructor cannot be used. */
((is_parenthesized_init || !is_initialized)
? 0 : LOOKUP_ONLYCONVERTING));
- if (pop_p)
- pop_scope (DECL_CONTEXT (decl));
}
+ if (!friend_p && pushed_scope)
+ pop_scope (pushed_scope);
/* Remember whether or not variables were initialized by
constant-expressions. */
bool saved_default_arg_ok_p = parser->default_arg_ok_p;
bool saved_in_declarator_p = parser->in_declarator_p;
bool first = true;
- bool pop_p = false;
+ tree pushed_scope = NULL_TREE;
while (true)
{
&non_constant_p);
if (!non_constant_p)
bounds = fold_non_dependent_expr (bounds);
+ /* Normally, the array bound must be an integral constant
+ expression. However, as an extension, we allow VLAs
+ in function scopes. */
else if (!at_function_scope_p ())
{
error ("array bound is not an integer constant");
}
else if (first && dcl_kind != CP_PARSER_DECLARATOR_ABSTRACT)
{
- tree id;
+ tree qualifying_scope;
+ tree unqualified_name;
/* Parse a declarator-id */
if (dcl_kind == CP_PARSER_DECLARATOR_EITHER)
cp_parser_parse_tentatively (parser);
- id = cp_parser_declarator_id (parser);
+ unqualified_name = cp_parser_declarator_id (parser);
+ qualifying_scope = parser->scope;
if (dcl_kind == CP_PARSER_DECLARATOR_EITHER)
{
if (!cp_parser_parse_definitely (parser))
- id = error_mark_node;
- else if (TREE_CODE (id) != IDENTIFIER_NODE)
+ unqualified_name = error_mark_node;
+ else if (qualifying_scope
+ || (TREE_CODE (unqualified_name)
+ != IDENTIFIER_NODE))
{
cp_parser_error (parser, "expected unqualified-id");
- id = error_mark_node;
+ unqualified_name = error_mark_node;
}
}
- if (id == error_mark_node)
+ if (unqualified_name == error_mark_node)
{
declarator = cp_error_declarator;
break;
}
- if (TREE_CODE (id) == SCOPE_REF && at_namespace_scope_p ())
+ if (qualifying_scope && at_namespace_scope_p ()
+ && TREE_CODE (qualifying_scope) == TYPENAME_TYPE)
{
- tree scope = TREE_OPERAND (id, 0);
-
/* In the declaration of a member of a template class
outside of the class itself, the SCOPE will sometimes
be a TYPENAME_TYPE. For example, given:
`S<T>::R' not a type. However, if `S' is
specialized, then this `i' will not be used, so there
is no harm in resolving the types here. */
- if (TREE_CODE (scope) == TYPENAME_TYPE)
- {
- tree type;
-
- /* Resolve the TYPENAME_TYPE. */
- type = resolve_typename_type (scope,
- /*only_current_p=*/false);
- /* If that failed, the declarator is invalid. */
- if (type == error_mark_node)
- error ("%<%T::%D%> is not a type",
- TYPE_CONTEXT (scope),
- TYPE_IDENTIFIER (scope));
- /* Build a new DECLARATOR. */
- id = build_nt (SCOPE_REF, type, TREE_OPERAND (id, 1));
- }
+ tree type;
+
+ /* Resolve the TYPENAME_TYPE. */
+ type = resolve_typename_type (qualifying_scope,
+ /*only_current_p=*/false);
+ /* If that failed, the declarator is invalid. */
+ if (type == error_mark_node)
+ error ("%<%T::%D%> is not a type",
+ TYPE_CONTEXT (qualifying_scope),
+ TYPE_IDENTIFIER (qualifying_scope));
+ qualifying_scope = type;
}
- declarator = make_id_declarator (id);
- if (id)
+ declarator = make_id_declarator (qualifying_scope,
+ unqualified_name);
+ if (unqualified_name)
{
tree class_type;
- tree unqualified_name;
- if (TREE_CODE (id) == SCOPE_REF
- && CLASS_TYPE_P (TREE_OPERAND (id, 0)))
- {
- class_type = TREE_OPERAND (id, 0);
- unqualified_name = TREE_OPERAND (id, 1);
- }
+ if (qualifying_scope
+ && CLASS_TYPE_P (qualifying_scope))
+ class_type = qualifying_scope;
else
- {
- class_type = current_class_type;
- unqualified_name = id;
- }
+ class_type = current_class_type;
if (class_type)
{
declarator->u.id.sfk = sfk_destructor;
else if (IDENTIFIER_TYPENAME_P (unqualified_name))
declarator->u.id.sfk = sfk_conversion;
- else if (constructor_name_p (unqualified_name,
- class_type)
- || (TREE_CODE (unqualified_name) == TYPE_DECL
- && same_type_p (TREE_TYPE (unqualified_name),
- class_type)))
+ else if (/* There's no way to declare a constructor
+ for an anonymous type, even if the type
+ got a name for linkage purposes. */
+ !TYPE_WAS_ANONYMOUS (class_type)
+ && (constructor_name_p (unqualified_name,
+ class_type)
+ || (TREE_CODE (unqualified_name) == TYPE_DECL
+ && (same_type_p
+ (TREE_TYPE (unqualified_name),
+ class_type)))))
declarator->u.id.sfk = sfk_constructor;
if (ctor_dtor_or_conv_p && declarator->u.id.sfk != sfk_none)
*ctor_dtor_or_conv_p = -1;
- if (TREE_CODE (id) == SCOPE_REF
+ if (qualifying_scope
&& TREE_CODE (unqualified_name) == TYPE_DECL
&& CLASSTYPE_USE_TEMPLATE (TREE_TYPE (unqualified_name)))
{
if (scope)
/* Any names that appear after the declarator-id for a
member are looked up in the containing scope. */
- pop_p = push_scope (scope);
+ pushed_scope = push_scope (scope);
parser->in_declarator_p = true;
if ((ctor_dtor_or_conv_p && *ctor_dtor_or_conv_p)
|| (declarator && declarator->kind == cdk_id))
cp_parser_error (parser, "expected declarator");
/* If we entered a scope, we must exit it now. */
- if (pop_p)
- pop_scope (scope);
+ if (pushed_scope)
+ pop_scope (pushed_scope);
parser->default_arg_ok_p = saved_default_arg_ok_p;
parser->in_declarator_p = saved_in_declarator_p;
static tree
cp_parser_declarator_id (cp_parser* parser)
{
- tree id_expression;
-
/* The expression must be an id-expression. Assume that qualified
names are the names of types so that:
int S<T>::R<T>::i = 3;
will work, too. */
- id_expression = cp_parser_id_expression (parser,
- /*template_keyword_p=*/false,
- /*check_dependency_p=*/false,
- /*template_p=*/NULL,
- /*declarator_p=*/true);
- /* If the name was qualified, create a SCOPE_REF to represent
- that. */
- if (parser->scope)
- {
- id_expression = build_nt (SCOPE_REF, parser->scope, id_expression);
- parser->scope = NULL_TREE;
- }
-
- return id_expression;
+ return cp_parser_id_expression (parser,
+ /*template_keyword_p=*/false,
+ /*check_dependency_p=*/false,
+ /*template_p=*/NULL,
+ /*declarator_p=*/true);
}
/* Parse a type-id.
list. */
if (!parser->in_template_argument_list_p
&& !parser->in_type_id_in_expr_p
- && cp_parser_parsing_tentatively (parser)
- && !cp_parser_committed_to_tentative_parse (parser)
+ && cp_parser_uncommitted_to_tentative_parse_p (parser)
/* However, a parameter-declaration of the form
"foat(f)" (which is a valid declaration of a
parameter "f") can also be interpreted as an
else
{
cp_parser_error (parser, "expected %<,%> or %<...%>");
- if (!cp_parser_parsing_tentatively (parser)
- || cp_parser_committed_to_tentative_parse (parser))
+ if (!cp_parser_uncommitted_to_tentative_parse_p (parser))
cp_parser_skip_to_closing_parenthesis (parser,
/*recovering=*/true,
/*or_comma=*/false,
function-type (taking a "char" as a parameter) or a cast
of some object of type "char" to "int". */
&& !parser->in_type_id_in_expr_p
- && cp_parser_parsing_tentatively (parser)
- && !cp_parser_committed_to_tentative_parse (parser)
+ && cp_parser_uncommitted_to_tentative_parse_p (parser)
&& cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_PAREN))
cp_parser_commit_to_tentative_parse (parser);
/* Parse the declarator. */
= parser->local_variables_forbidden_p;
parser->local_variables_forbidden_p = true;
/* Parse the assignment-expression. */
- default_argument = cp_parser_assignment_expression (parser);
+ default_argument
+ = cp_parser_assignment_expression (parser, /*cast_p=*/false);
/* Restore saved state. */
parser->greater_than_is_operator_p
= saved_greater_than_is_operator_p;
}
else if (token->type == CPP_OPEN_PAREN)
init = cp_parser_parenthesized_expression_list (parser, false,
+ /*cast_p=*/false,
non_constant_p);
else
{
{
tree initializer;
+ /* Assume the expression is constant. */
+ *non_constant_p = false;
+
/* 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))
{
tree queue_entry;
tree fn;
- tree class_type;
- bool pop_p;
+ tree class_type = NULL_TREE;
+ tree pushed_scope = NULL_TREE;
/* In a first pass, parse default arguments to the functions.
Then, in a second pass, parse the bodies of the functions.
};
*/
- class_type = NULL_TREE;
- pop_p = false;
for (TREE_PURPOSE (parser->unparsed_functions_queues)
= nreverse (TREE_PURPOSE (parser->unparsed_functions_queues));
(queue_entry = TREE_PURPOSE (parser->unparsed_functions_queues));
take care of them now. */
if (class_type != TREE_PURPOSE (queue_entry))
{
- if (pop_p)
- pop_scope (class_type);
+ if (pushed_scope)
+ pop_scope (pushed_scope);
class_type = TREE_PURPOSE (queue_entry);
- pop_p = push_scope (class_type);
+ pushed_scope = push_scope (class_type);
}
/* Make sure that any template parameters are in scope. */
maybe_begin_member_template_processing (fn);
/* Remove any template parameters from the symbol table. */
maybe_end_member_template_processing ();
}
- if (pop_p)
- pop_scope (class_type);
+ if (pushed_scope)
+ pop_scope (pushed_scope);
/* Now parse the body of the functions. */
for (TREE_VALUE (parser->unparsed_functions_queues)
= nreverse (TREE_VALUE (parser->unparsed_functions_queues));
bool qualified_p = false;
bool invalid_nested_name_p = false;
bool invalid_explicit_specialization_p = false;
- bool pop_p = false;
+ tree pushed_scope = NULL_TREE;
unsigned num_templates;
tree bases;
else if (nested_name_specifier)
{
tree scope;
+
+ /* Reject typedef-names in class heads. */
+ if (!DECL_IMPLICIT_TYPEDEF_P (type))
+ {
+ error ("invalid class name in declaration of %qD", type);
+ type = NULL_TREE;
+ goto done;
+ }
+
/* Figure out in what scope the declaration is being placed. */
scope = current_scope ();
/* If that scope does not contain the scope in which the
{
type = TREE_TYPE (id);
maybe_process_partial_specialization (type);
+ if (nested_name_specifier)
+ pushed_scope = push_scope (nested_name_specifier);
}
- else if (!nested_name_specifier)
- {
- /* If the class was unnamed, create a dummy name. */
- if (!id)
- id = make_anon_name ();
- type = xref_tag (class_key, id, /*tag_scope=*/ts_current,
- parser->num_template_parameter_lists);
- }
- else
+ else if (nested_name_specifier)
{
tree class_type;
- bool pop_p = false;
/* Given:
maybe_process_partial_specialization (TREE_TYPE (type));
class_type = current_class_type;
/* Enter the scope indicated by the nested-name-specifier. */
- if (nested_name_specifier)
- pop_p = push_scope (nested_name_specifier);
+ pushed_scope = push_scope (nested_name_specifier);
/* Get the canonical version of this type. */
type = TYPE_MAIN_DECL (TREE_TYPE (type));
if (PROCESSING_REAL_TEMPLATE_DECL_P ()
}
type = TREE_TYPE (type);
- if (nested_name_specifier)
- {
- *nested_name_specifier_p = true;
- if (pop_p)
- pop_scope (nested_name_specifier);
- }
+ *nested_name_specifier_p = true;
+ }
+ else /* The name is not a nested name. */
+ {
+ /* If the class was unnamed, create a dummy name. */
+ if (!id)
+ id = make_anon_name ();
+ type = xref_tag (class_key, id, /*tag_scope=*/ts_current,
+ parser->num_template_parameter_lists);
}
+
/* Indicate whether this class was declared as a `class' or as a
`struct'. */
if (TREE_CODE (type) == RECORD_TYPE)
CLASSTYPE_DECLARED_CLASS (type) = (class_key == class_type);
cp_parser_check_class_key (class_key, type);
- /* Enter the scope containing the class; the names of base classes
- should be looked up in that context. For example, given:
+ /* If this type was already complete, and we see another definition,
+ that's an error. */
+ if (type != error_mark_node && COMPLETE_TYPE_P (type))
+ {
+ error ("redefinition of %q#T", type);
+ cp_error_at ("previous definition of %q#T", type);
+ type = error_mark_node;
+ }
+
+ /* We will have entered the scope containing the class; the names of
+ base classes should be looked up in that context. For example:
struct A { struct B {}; struct C; };
struct A::C : B {};
is valid. */
- if (nested_name_specifier)
- pop_p = push_scope (nested_name_specifier);
-
bases = NULL_TREE;
/* Get the list of base-classes, if there is one. */
/* Process the base classes. */
xref_basetypes (type, bases);
+ done:
/* Leave the scope given by the nested-name-specifier. We will
enter the class scope itself while processing the members. */
- if (pop_p)
- pop_scope (nested_name_specifier);
+ if (pushed_scope)
+ pop_scope (pushed_scope);
- done:
if (invalid_explicit_specialization_p)
{
end_specialization ();
/* Create the bitfield declaration. */
decl = grokbitfield (identifier
- ? make_id_declarator (identifier)
+ ? make_id_declarator (NULL_TREE,
+ identifier)
: NULL,
&decl_specifiers,
width);
initializer = NULL_TREE;
/* See if we are probably looking at a function
- definition. We are certainly not looking at at a
+ definition. We are certainly not looking at a
member-declarator. Calling `grokfield' has
side-effects, so we must not do it unless we are sure
that we are looking at a member-declarator. */
if (!cp_parser_require (parser, CPP_EQ, "`='"))
return error_mark_node;
/* Look for the `0' token. */
- token = cp_parser_require (parser, CPP_NUMBER, "`0'");
- /* Unfortunately, this will accept `0L' and `0x00' as well. We need
- to get information from the lexer about how the number was
- spelled in order to fix this problem. */
- if (!token || !integer_zerop (token->value))
- return error_mark_node;
+ token = cp_lexer_consume_token (parser->lexer);
+ if (token->type != CPP_NUMBER || !integer_zerop (token->value))
+ {
+ cp_parser_error (parser,
+ "invalid pure specifier (only `= 0' is allowed)");
+ cp_parser_skip_to_end_of_statement (parser);
+ return error_mark_node;
+ }
+ /* FIXME: Unfortunately, this will accept `0L' and `0x00' as well.
+ We need to get information from the lexer about how the number
+ was spelled in order to fix this problem. */
return integer_zero_node;
}
|| token->type == CPP_COLON)
expression = NULL_TREE;
else
- expression = cp_parser_assignment_expression (parser);
+ expression = cp_parser_assignment_expression (parser,
+ /*cast_p=*/false);
return build_throw (expression);
}
/* Look for the `('. */
cp_parser_require (parser, CPP_OPEN_PAREN, "`('");
/* Parse the expression. */
- expression = cp_parser_expression (parser);
+ expression = cp_parser_expression (parser, /*cast_p=*/false);
/* Look for the `)'. */
cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
identifier ( identifier , expression-list )
identifier ( expression-list )
- Returns a TREE_LIST. Each node corresponds to an attribute. THe
- TREE_PURPOSE of each node is the identifier indicating which
- attribute is in use. The TREE_VALUE represents the arguments, if
- any. */
+ Returns a TREE_LIST, or NULL_TREE on error. Each node corresponds
+ to an attribute. The TREE_PURPOSE of each node is the identifier
+ indicating which attribute is in use. The TREE_VALUE represents
+ the arguments, if any. */
static tree
cp_parser_attribute_list (cp_parser* parser)
/* Look for the identifier. We also allow keywords here; for
example `__attribute__ ((const))' is legal. */
token = cp_lexer_peek_token (parser->lexer);
- if (token->type != CPP_NAME
- && token->type != CPP_KEYWORD)
- return error_mark_node;
- /* Consume the token. */
- token = cp_lexer_consume_token (parser->lexer);
+ if (token->type == CPP_NAME
+ || token->type == CPP_KEYWORD)
+ {
+ /* Consume the token. */
+ token = cp_lexer_consume_token (parser->lexer);
- /* Save away the identifier that indicates which attribute this is. */
- identifier = token->value;
- attribute = build_tree_list (identifier, NULL_TREE);
+ /* Save away the identifier that indicates which attribute
+ this is. */
+ identifier = token->value;
+ attribute = build_tree_list (identifier, NULL_TREE);
- /* Peek at the next token. */
- token = cp_lexer_peek_token (parser->lexer);
- /* If it's an `(', then parse the attribute arguments. */
- if (token->type == CPP_OPEN_PAREN)
- {
- tree arguments;
+ /* Peek at the next token. */
+ token = cp_lexer_peek_token (parser->lexer);
+ /* If it's an `(', then parse the attribute arguments. */
+ if (token->type == CPP_OPEN_PAREN)
+ {
+ tree arguments;
- arguments = (cp_parser_parenthesized_expression_list
- (parser, true, /*non_constant_p=*/NULL));
- /* Save the identifier and arguments away. */
- TREE_VALUE (attribute) = arguments;
- }
+ arguments = (cp_parser_parenthesized_expression_list
+ (parser, true, /*cast_p=*/false,
+ /*non_constant_p=*/NULL));
+ /* Save the identifier and arguments away. */
+ TREE_VALUE (attribute) = arguments;
+ }
- /* Add this attribute to the list. */
- TREE_CHAIN (attribute) = attribute_list;
- attribute_list = attribute;
+ /* Add this attribute to the list. */
+ TREE_CHAIN (attribute) = attribute_list;
+ attribute_list = attribute;
- /* Now, look for more attributes. */
- token = cp_lexer_peek_token (parser->lexer);
- /* If the next token isn't a `,', we're done. */
+ token = cp_lexer_peek_token (parser->lexer);
+ }
+ /* Now, look for more attributes. If the next token isn't a
+ `,', we're done. */
if (token->type != CPP_COMMA)
break;
/* If that's not a class type, there is no destructor. */
if (!type || !CLASS_TYPE_P (type))
return error_mark_node;
+ if (CLASSTYPE_LAZY_DESTRUCTOR (type))
+ lazily_declare_fn (sfk_destructor, type);
if (!CLASSTYPE_DESTRUCTORS (type))
return error_mark_node;
/* If it was a class type, return the destructor. */
is dependent. */
type = make_typename_type (parser->scope, name, tag_type,
/*complain=*/1);
- if (tag_type == enum_type)
- TYPENAME_IS_ENUM_P (type) = 1;
- else if (tag_type != typename_type)
- TYPENAME_IS_CLASS_P (type) = 1;
decl = TYPE_NAME (type);
}
else if (is_template)
}
else
{
- bool pop_p = false;
+ tree pushed_scope = NULL_TREE;
/* If PARSER->SCOPE is a dependent type, then it must be a
class type, and we must not be checking dependencies;
that PARSER->SCOPE is not considered a dependent base by
lookup_member, we must enter the scope here. */
if (dependent_p)
- pop_p = push_scope (parser->scope);
+ pushed_scope = push_scope (parser->scope);
/* If the PARSER->SCOPE is a a template specialization, it
may be instantiated during name lookup. In that case,
errors may be issued. Even if we rollback the current
decl = lookup_qualified_name (parser->scope, name,
tag_type != none_type,
/*complain=*/true);
- if (pop_p)
- pop_scope (parser->scope);
+ if (pushed_scope)
+ pop_scope (pushed_scope);
}
parser->qualifying_scope = parser->scope;
parser->object_scope = NULL_TREE;
switch (declarator->kind)
{
case cdk_id:
- if (TREE_CODE (declarator->u.id.name) == SCOPE_REF)
+ if (declarator->u.id.qualifying_scope)
{
tree scope;
tree member;
- scope = TREE_OPERAND (declarator->u.id.name, 0);
- member = TREE_OPERAND (declarator->u.id.name, 1);
+ scope = declarator->u.id.qualifying_scope;
+ member = declarator->u.id.unqualified_name;
while (scope && CLASS_TYPE_P (scope))
{
scope = TYPE_CONTEXT (scope);
}
}
-
- /* If the DECLARATOR has the form `X<y>' then it uses one
- additional level of template parameters. */
- if (TREE_CODE (declarator->u.id.name) == TEMPLATE_ID_EXPR)
+ else if (TREE_CODE (declarator->u.id.unqualified_name)
+ == TEMPLATE_ID_EXPR)
+ /* If the DECLARATOR has the form `X<y>' then it uses one
+ additional level of template parameters. */
++num_templates;
return cp_parser_check_template_parameters (parser,
&& !cp_parser_storage_class_specifier_opt (parser))
{
tree type;
- bool pop_p = false;
+ tree pushed_scope = NULL_TREE;
unsigned saved_num_template_parameter_lists;
/* Names appearing in the type-specifier should be looked up
return false;
}
}
- pop_p = push_scope (type);
+ pushed_scope = push_scope (type);
}
/* Inside the constructor parameter list, surrounding
= saved_num_template_parameter_lists;
/* Leave the scope of the class. */
- if (pop_p)
- pop_scope (type);
+ if (pushed_scope)
+ pop_scope (pushed_scope);
constructor_p = !cp_parser_error_occurred (parser);
}
static tree
cp_parser_simple_cast_expression (cp_parser *parser)
{
- return cp_parser_cast_expression (parser, /*address_p=*/false);
+ return cp_parser_cast_expression (parser, /*address_p=*/false,
+ /*cast_p=*/false);
}
/* Parse a functional cast to TYPE. Returns an expression
expression_list
= cp_parser_parenthesized_expression_list (parser, false,
+ /*cast_p=*/true,
/*non_constant_p=*/NULL);
cast = build_functional_cast (type, expression_list);
tokens = DECL_PENDING_INLINE_INFO (member_function);
DECL_PENDING_INLINE_INFO (member_function) = NULL;
DECL_PENDING_INLINE_P (member_function) = 0;
- /* If this was an inline function in a local class, enter the scope
- of the containing function. */
- function_scope = decl_function_context (member_function);
+
+ /* If this is a local class, enter the scope of the containing
+ function. */
+ function_scope = current_function_decl;
if (function_scope)
push_function_context_to (function_scope);
cp_parser_push_lexer_for_tokens (parser, tokens);
/* Parse the assignment-expression. */
- TREE_PURPOSE (parm) = cp_parser_assignment_expression (parser);
+ TREE_PURPOSE (parm) = cp_parser_assignment_expression (parser,
+ /*cast_p=*/false);
/* If the token stream has not been completely used up, then
there was extra junk after the end of the default
tree expr = NULL_TREE;
const char *saved_message;
bool saved_integral_constant_expression_p;
+ bool saved_non_integral_constant_expression_p;
/* Initialize FORMAT the first time we get here. */
if (!format)
/* The restrictions on constant-expressions do not apply inside
sizeof expressions. */
- saved_integral_constant_expression_p = parser->integral_constant_expression_p;
+ saved_integral_constant_expression_p
+ = parser->integral_constant_expression_p;
+ saved_non_integral_constant_expression_p
+ = parser->non_integral_constant_expression_p;
parser->integral_constant_expression_p = false;
/* Do not actually evaluate the expression. */
/* If the type-id production did not work out, then we must be
looking at the unary-expression production. */
if (!expr)
- expr = cp_parser_unary_expression (parser, /*address_p=*/false);
+ expr = cp_parser_unary_expression (parser, /*address_p=*/false,
+ /*cast_p=*/false);
/* Go back to evaluating expressions. */
--skip_evaluation;
free ((char *) parser->type_definition_forbidden_message);
/* And restore the old one. */
parser->type_definition_forbidden_message = saved_message;
- parser->integral_constant_expression_p = saved_integral_constant_expression_p;
+ parser->integral_constant_expression_p
+ = saved_integral_constant_expression_p;
+ parser->non_integral_constant_expression_p
+ = saved_non_integral_constant_expression_p;
return expr;
}
return !error_occurred;
}
-/* Returns true if we are parsing tentatively -- but have decided that
- we will stick with this tentative parse, even if errors occur. */
+/* Returns true if we are parsing tentatively and are not committed to
+ this tentative parse. */
static bool
-cp_parser_committed_to_tentative_parse (cp_parser* parser)
+cp_parser_uncommitted_to_tentative_parse_p (cp_parser* parser)
{
return (cp_parser_parsing_tentatively (parser)
- && parser->context->status == CP_PARSER_STATUS_KIND_COMMITTED);
+ && parser->context->status != CP_PARSER_STATUS_KIND_COMMITTED);
}
/* Returns nonzero iff an error has occurred during the most recent