#include "diagnostic.h"
#include "toplev.h"
#include "output.h"
+#include "target.h"
\f
/* The lexer. */
The parser routinely peeks at the next token, and then consumes it
later. That also requires a buffer in which to store the tokens.
-
+
In order to easily permit adding tokens to the end of the buffer,
while removing them from the beginning of the buffer, we use a
circular buffer. */
/* If this token is a keyword, this value indicates which keyword.
Otherwise, this value is RID_MAX. */
ENUM_BITFIELD (rid) keyword : 8;
+ /* Token flags. */
+ unsigned char flags;
/* The value associated with this token, if any. */
tree value;
/* The location at which this token was found. */
large numbers of tokens. (For example, a token block is created
when the body of an inline member function is first encountered;
the tokens are processed later after the class definition is
- complete.)
+ complete.)
This somewhat ungainly data structure (as opposed to, say, a
variable-length array), is used due to constraints imposed by the
/* Prototypes. */
-static cp_token_cache *cp_token_cache_new
+static cp_token_cache *cp_token_cache_new
(void);
static void cp_token_cache_push_token
(cp_token_cache *, cp_token *);
/* The memory allocated for the buffer. Never NULL. */
cp_token * GTY ((length ("(%h.buffer_end - %h.buffer)"))) buffer;
/* A pointer just past the end of the memory allocated for the buffer. */
- cp_token * GTY ((skip (""))) buffer_end;
+ cp_token * GTY ((skip)) buffer_end;
/* The first valid token in the buffer, or NULL if none. */
- cp_token * GTY ((skip (""))) first_token;
+ cp_token * GTY ((skip)) first_token;
/* The next available token. If NEXT_TOKEN is NULL, then there are
no more available tokens. */
- cp_token * GTY ((skip (""))) next_token;
+ cp_token * GTY ((skip)) next_token;
/* A pointer just past the last available token. If FIRST_TOKEN is
NULL, however, there are no available tokens, and then this
location is simply the place in which the next token read will be
placed. If LAST_TOKEN == FIRST_TOKEN, then the buffer is full.
When the LAST_TOKEN == BUFFER, then the last token is at the
highest memory address in the BUFFER. */
- cp_token * GTY ((skip (""))) last_token;
+ cp_token * GTY ((skip)) last_token;
/* A stack indicating positions at which cp_lexer_save_tokens was
called. The top entry is the most recent position at which we
(cp_lexer *, cp_token *);
static cp_token *cp_lexer_prev_token
(cp_lexer *, cp_token *);
-static ptrdiff_t cp_lexer_token_difference
+static ptrdiff_t cp_lexer_token_difference
(cp_lexer *, cp_token *, cp_token *);
static cp_token *cp_lexer_read_token
(cp_lexer *);
(cp_lexer *, enum cpp_ttype);
static bool cp_lexer_next_token_is_keyword
(cp_lexer *, enum rid);
-static cp_token *cp_lexer_consume_token
+static cp_token *cp_lexer_consume_token
(cp_lexer *);
static void cp_lexer_purge_token
(cp_lexer *);
(cp_lexer *);
static void cp_lexer_rollback_tokens
(cp_lexer *);
-static inline void cp_lexer_set_source_position_from_token
+static inline void cp_lexer_set_source_position_from_token
(cp_lexer *, const cp_token *);
static void cp_lexer_print_token
(FILE *, cp_token *);
-static inline bool cp_lexer_debugging_p
+static inline bool cp_lexer_debugging_p
(cp_lexer *);
static void cp_lexer_start_debugging
(cp_lexer *) ATTRIBUTE_UNUSED;
/* Create the SAVED_TOKENS stack. */
VARRAY_INT_INIT (lexer->saved_tokens, CP_SAVED_TOKENS_SIZE, "saved_tokens");
-
+
/* Create the STRINGS array. */
VARRAY_TREE_INIT (lexer->string_tokens, 32, "strings");
num_tokens += block->num_tokens;
lexer->buffer = ggc_alloc (num_tokens * sizeof (cp_token));
lexer->buffer_end = lexer->buffer + num_tokens;
-
+
/* Install the tokens. */
token = lexer->buffer;
for (block = tokens->first; block != NULL; block = block->next)
/* Create the SAVED_TOKENS stack. */
VARRAY_INT_INIT (lexer->saved_tokens, CP_SAVED_TOKENS_SIZE, "saved_tokens");
-
+
/* Create the STRINGS array. */
VARRAY_TREE_INIT (lexer->string_tokens, 32, "strings");
if ((token->type == CPP_STRING || token->type == CPP_WSTRING)
&& flag_const_strings)
{
- tree type;
+ if (c_lex_string_translate)
+ {
+ tree value = token->value;
+ tree type;
- /* Get the current type. It will be an ARRAY_TYPE. */
- type = TREE_TYPE (token->value);
- /* Use build_cplus_array_type to rebuild the array, thereby
- getting the right type. */
- type = build_cplus_array_type (TREE_TYPE (type), TYPE_DOMAIN (type));
- /* Reset the type of the token. */
- TREE_TYPE (token->value) = type;
+ /* We might as well go ahead and release the chained
+ translated string such that we can reuse its memory. */
+ if (TREE_CHAIN (value))
+ value = TREE_CHAIN (token->value);
+
+ /* Get the current type. It will be an ARRAY_TYPE. */
+ type = TREE_TYPE (value);
+ /* Use build_cplus_array_type to rebuild the array, thereby
+ getting the right type. */
+ type = build_cplus_array_type (TREE_TYPE (type),
+ TYPE_DOMAIN (type));
+ /* Reset the type of the token. */
+ TREE_TYPE (value) = type;
+ }
}
return token;
/* Compute the current buffer size. */
buffer_length = lexer->buffer_end - lexer->buffer;
/* Allocate a buffer twice as big. */
- new_buffer = ggc_realloc (lexer->buffer,
+ new_buffer = ggc_realloc (lexer->buffer,
2 * buffer_length * sizeof (cp_token));
-
+
/* Because the buffer is circular, logically consecutive tokens
are not necessarily placed consecutively in memory.
Therefore, we must keep move the tokens that were before
num_tokens_to_copy * sizeof (cp_token));
/* Clear the rest of the buffer. We never look at this storage,
but the garbage collector may. */
- memset (new_buffer + buffer_length + num_tokens_to_copy, 0,
+ memset (new_buffer + buffer_length + num_tokens_to_copy, 0,
(buffer_length - num_tokens_to_copy) * sizeof (cp_token));
/* Now recompute all of the buffer pointers. */
- new_first_token
+ new_first_token
= new_buffer + (lexer->first_token - old_buffer);
if (lexer->next_token != NULL)
{
if (lexer->next_token > lexer->first_token)
next_token_delta = lexer->next_token - lexer->first_token;
else
- next_token_delta =
+ next_token_delta =
buffer_length - (lexer->first_token - lexer->next_token);
lexer->next_token = new_first_token + next_token_delta;
}
/* Store the next token from the preprocessor in *TOKEN. */
-static void
+static void
cp_lexer_get_preprocessor_token (cp_lexer *lexer ATTRIBUTE_UNUSED ,
cp_token *token)
{
if (lexer != NULL && !lexer->main_lexer_p)
{
token->type = CPP_EOF;
- token->location.line = 0;
- token->location.file = NULL;
+ token->location = UNKNOWN_LOCATION;
token->value = NULL_TREE;
token->keyword = RID_MAX;
while (!done)
{
/* Get a new token from the preprocessor. */
- token->type = c_lex (&token->value);
+ token->type = c_lex_with_flags (&token->value, &token->flags);
/* Issue messages about tokens we cannot process. */
switch (token->type)
{
token->location = input_location;
/* Check to see if this token is a keyword. */
- if (token->type == CPP_NAME
+ if (token->type == CPP_NAME
&& C_IS_RESERVED_WORD (token->value))
{
/* Mark this token as a keyword. */
token = lexer->next_token;
/* Increment NEXT_TOKEN. */
- lexer->next_token = cp_lexer_next_token (lexer,
+ lexer->next_token = cp_lexer_next_token (lexer,
lexer->next_token);
/* Check to see if we're all out of tokens. */
if (lexer->next_token == lexer->last_token)
cp_token *next_token;
token = lexer->next_token;
- while (true)
+ while (true)
{
next_token = cp_lexer_next_token (lexer, token);
if (next_token == lexer->last_token)
delta = VARRAY_TOP_INT(lexer->saved_tokens);
/* Make it the next token again now. */
lexer->next_token = cp_lexer_advance_token (lexer,
- lexer->first_token,
+ lexer->first_token,
delta);
/* It might be the case that there were no tokens when we started
saving tokens, but that there are some tokens now. */
else
fprintf (stream, "%d", token->type);
/* And, for an identifier, print the identifier name. */
- if (token->type == CPP_NAME
+ if (token->type == CPP_NAME
/* Some keywords have a value that is not an IDENTIFIER_NODE.
For example, `struct' is mapped to an INTEGER_CST. */
- || (token->type == CPP_KEYWORD
+ || (token->type == CPP_KEYWORD
&& TREE_CODE (token->value) == IDENTIFIER_NODE))
fprintf (stream, " %s", IDENTIFIER_POINTER (token->value));
}
{
++lexer->debugging_p;
}
-
+
/* Stop emitting debugging information. */
static void
}
\f
+/* Decl-specifiers. */
+
+static void clear_decl_specs
+ (cp_decl_specifier_seq *);
+
+/* Set *DECL_SPECS to represent an empty decl-specifier-seq. */
+
+static void
+clear_decl_specs (cp_decl_specifier_seq *decl_specs)
+{
+ memset (decl_specs, 0, sizeof (cp_decl_specifier_seq));
+}
+
+/* Declarators. */
+
+/* Nothing other than the parser should be creating declarators;
+ declarators are a semi-syntactic representation of C++ entities.
+ 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
+ (cp_declarator *, tree);
+static cp_declarator *make_pointer_declarator
+ (cp_cv_quals, cp_declarator *);
+static cp_declarator *make_reference_declarator
+ (cp_cv_quals, cp_declarator *);
+static cp_parameter_declarator *make_parameter_declarator
+ (cp_decl_specifier_seq *, cp_declarator *, tree);
+static cp_declarator *make_ptrmem_declarator
+ (cp_cv_quals, tree, cp_declarator *);
+
+cp_declarator *cp_error_declarator;
+
+/* The obstack on which declarators and related data structures are
+ allocated. */
+static struct obstack declarator_obstack;
+
+/* Alloc BYTES from the declarator memory pool. */
+
+static inline void *
+alloc_declarator (size_t bytes)
+{
+ return obstack_alloc (&declarator_obstack, bytes);
+}
+
+/* Allocate a declarator of the indicated KIND. Clear fields that are
+ common to all declarators. */
+
+static cp_declarator *
+make_declarator (cp_declarator_kind kind)
+{
+ cp_declarator *declarator;
+
+ declarator = (cp_declarator *) alloc_declarator (sizeof (cp_declarator));
+ declarator->kind = kind;
+ declarator->attributes = NULL_TREE;
+ declarator->declarator = NULL;
+
+ return declarator;
+}
+
+/* Make a declarator for a generalized identifier. */
+
+cp_declarator *
+make_id_declarator (tree id)
+{
+ cp_declarator *declarator;
+
+ declarator = make_declarator (cdk_id);
+ declarator->u.id.name = id;
+ declarator->u.id.sfk = sfk_none;
+
+ return declarator;
+}
+
+/* Make a declarator for a pointer to TARGET. CV_QUALIFIERS is a list
+ of modifiers such as const or volatile to apply to the pointer
+ type, represented as identifiers. */
+
+cp_declarator *
+make_pointer_declarator (cp_cv_quals cv_qualifiers, cp_declarator *target)
+{
+ cp_declarator *declarator;
+
+ declarator = make_declarator (cdk_pointer);
+ declarator->declarator = target;
+ declarator->u.pointer.qualifiers = cv_qualifiers;
+ declarator->u.pointer.class_type = NULL_TREE;
+
+ return declarator;
+}
+
+/* Like make_pointer_declarator -- but for references. */
+
+cp_declarator *
+make_reference_declarator (cp_cv_quals cv_qualifiers, cp_declarator *target)
+{
+ cp_declarator *declarator;
+
+ declarator = make_declarator (cdk_reference);
+ declarator->declarator = target;
+ declarator->u.pointer.qualifiers = cv_qualifiers;
+ declarator->u.pointer.class_type = NULL_TREE;
+
+ return declarator;
+}
+
+/* Like make_pointer_declarator -- but for a pointer to a non-static
+ member of CLASS_TYPE. */
+
+cp_declarator *
+make_ptrmem_declarator (cp_cv_quals cv_qualifiers, tree class_type,
+ cp_declarator *pointee)
+{
+ cp_declarator *declarator;
+
+ declarator = make_declarator (cdk_ptrmem);
+ declarator->declarator = pointee;
+ declarator->u.pointer.qualifiers = cv_qualifiers;
+ declarator->u.pointer.class_type = class_type;
+
+ return declarator;
+}
+
+/* Make a declarator for the function given by TARGET, with the
+ indicated PARMS. The CV_QUALIFIERS aply to the function, as in
+ "const"-qualified member function. The EXCEPTION_SPECIFICATION
+ indicates what exceptions can be thrown. */
+
+cp_declarator *
+make_call_declarator (cp_declarator *target,
+ cp_parameter_declarator *parms,
+ cp_cv_quals cv_qualifiers,
+ tree exception_specification)
+{
+ cp_declarator *declarator;
+
+ declarator = make_declarator (cdk_function);
+ declarator->declarator = target;
+ declarator->u.function.parameters = parms;
+ declarator->u.function.qualifiers = cv_qualifiers;
+ declarator->u.function.exception_specification = exception_specification;
+
+ return declarator;
+}
+
+/* Make a declarator for an array of BOUNDS elements, each of which is
+ defined by ELEMENT. */
+
+cp_declarator *
+make_array_declarator (cp_declarator *element, tree bounds)
+{
+ cp_declarator *declarator;
+
+ declarator = make_declarator (cdk_array);
+ declarator->declarator = element;
+ declarator->u.array.bounds = bounds;
+
+ return declarator;
+}
+
+cp_parameter_declarator *no_parameters;
+
+/* Create a parameter declarator with the indicated DECL_SPECIFIERS,
+ DECLARATOR and DEFAULT_ARGUMENT. */
+
+cp_parameter_declarator *
+make_parameter_declarator (cp_decl_specifier_seq *decl_specifiers,
+ cp_declarator *declarator,
+ tree default_argument)
+{
+ cp_parameter_declarator *parameter;
+
+ parameter = ((cp_parameter_declarator *)
+ alloc_declarator (sizeof (cp_parameter_declarator)));
+ parameter->next = NULL;
+ if (decl_specifiers)
+ parameter->decl_specifiers = *decl_specifiers;
+ else
+ clear_decl_specs (¶meter->decl_specifiers);
+ parameter->declarator = declarator;
+ parameter->default_argument = default_argument;
+ parameter->ellipsis_p = false;
+
+ return parameter;
+}
+
/* The parser. */
/* Overview
The parser invokes routines elsewhere in the compiler to perform
semantic analysis and to build up the abstract syntax tree for the
- code processed.
+ code processed.
The parser (and the template instantiation code, which is, in a
way, a close relative of parsing) are the only parts of the
Methodology
-----------
-
+
The parser is of the standard recursive-descent variety. Upcoming
tokens in the token stream are examined in order to determine which
production to use when parsing a non-terminal. Some C++ constructs
Future Improvements
-------------------
-
+
The performance of the parser could probably be improved
substantially. Some possible improvements include:
typedef enum cp_parser_declarator_kind
{
- /* We want an abstract declartor. */
+ /* We want an abstract declarator. */
CP_PARSER_DECLARATOR_ABSTRACT,
/* We want a named declarator. */
CP_PARSER_DECLARATOR_NAMED,
/* Class variables. */
-static GTY((deletable (""))) cp_parser_context* cp_parser_context_free_list;
+static GTY((deletable)) cp_parser_context* cp_parser_context_free_list;
/* Constructors and destructors. */
/* The scope in which names should be looked up. If NULL_TREE, then
we look up names in the scope that is currently open in the
source program. If non-NULL, this is either a TYPE or
- NAMESPACE_DECL for the scope in which we should look.
+ NAMESPACE_DECL for the scope in which we should look.
This value is not cleared automatically after a name is looked
up, so we must be careful to clear it before starting a new look
/* OBJECT_SCOPE and QUALIFYING_SCOPE give the scopes in which the
last lookup took place. OBJECT_SCOPE is used if an expression
like "x->y" or "x.y" was used; it gives the type of "*x" or "x",
- respectively. QUALIFYING_SCOPE is used for an expression of the
+ respectively. QUALIFYING_SCOPE is used for an expression of the
form "X::Y"; it refers to X. */
tree object_scope;
tree qualifying_scope;
that starts at this point. FALSE if only a gnu extension makes
them permissible. */
bool default_arg_ok_p;
-
+
/* TRUE if we are parsing an integral constant-expression. See
[expr.const] for a precise definition. */
bool integral_constant_expression_p;
been seen that makes the expression non-constant. */
bool non_integral_constant_expression_p;
- /* TRUE if we are parsing the argument to "__offsetof__". */
- bool in_offsetof_p;
-
/* TRUE if local variable names and `this' are forbidden in the
current context. */
bool local_variables_forbidden_p;
static cp_parser *cp_parser_new
(void);
-/* Routines to parse various constructs.
+/* Routines to parse various constructs.
Those that return `tree' will return the error_mark_node (rather
than NULL_TREE) if a parse error occurs, unless otherwise noted.
(cp_parser *, bool, bool, bool, bool, bool);
static tree cp_parser_postfix_expression
(cp_parser *, 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 *);
static void cp_parser_pseudo_destructor_name
static tree cp_parser_new_placement
(cp_parser *);
static tree cp_parser_new_type_id
+ (cp_parser *, tree *);
+static cp_declarator *cp_parser_new_declarator_opt
(cp_parser *);
-static tree cp_parser_new_declarator_opt
- (cp_parser *);
-static tree cp_parser_direct_new_declarator
+static cp_declarator *cp_parser_direct_new_declarator
(cp_parser *);
static tree cp_parser_new_initializer
(cp_parser *);
static tree cp_parser_delete_expression
(cp_parser *);
-static tree cp_parser_cast_expression
+static tree cp_parser_cast_expression
(cp_parser *, bool);
static tree cp_parser_pm_expression
(cp_parser *);
(cp_parser *);
static tree cp_parser_logical_and_expression
(cp_parser *);
-static tree cp_parser_logical_or_expression
+static tree cp_parser_logical_or_expression
(cp_parser *);
static tree cp_parser_question_colon_clause
(cp_parser *, tree);
(cp_parser *);
static tree cp_parser_constant_expression
(cp_parser *, bool, bool *);
+static tree cp_parser_builtin_offsetof
+ (cp_parser *);
/* Statements [gram.stmt.stmt] */
static void cp_parser_statement
- (cp_parser *, bool);
+ (cp_parser *, tree);
static tree cp_parser_labeled_statement
- (cp_parser *, bool);
+ (cp_parser *, tree);
static tree cp_parser_expression_statement
- (cp_parser *, bool);
+ (cp_parser *, tree);
static tree cp_parser_compound_statement
- (cp_parser *, bool);
+ (cp_parser *, tree, bool);
static void cp_parser_statement_seq_opt
- (cp_parser *, bool);
+ (cp_parser *, tree);
static tree cp_parser_selection_statement
(cp_parser *);
static tree cp_parser_condition
(cp_parser *, bool);
static void cp_parser_simple_declaration
(cp_parser *, bool);
-static tree cp_parser_decl_specifier_seq
- (cp_parser *, cp_parser_flags, tree *, int *);
+static void cp_parser_decl_specifier_seq
+ (cp_parser *, cp_parser_flags, cp_decl_specifier_seq *, int *);
static tree cp_parser_storage_class_specifier_opt
(cp_parser *);
static tree cp_parser_function_specifier_opt
- (cp_parser *);
+ (cp_parser *, cp_decl_specifier_seq *);
static tree cp_parser_type_specifier
- (cp_parser *, cp_parser_flags, bool, bool, int *, bool *);
+ (cp_parser *, cp_parser_flags, cp_decl_specifier_seq *, bool,
+ int *, bool *);
static tree cp_parser_simple_type_specifier
- (cp_parser *, cp_parser_flags, bool);
+ (cp_parser *, cp_decl_specifier_seq *, cp_parser_flags);
static tree cp_parser_type_name
(cp_parser *);
static tree cp_parser_elaborated_type_specifier
(cp_parser *);
static void cp_parser_enumerator_list
(cp_parser *, tree);
-static void cp_parser_enumerator_definition
+static void cp_parser_enumerator_definition
(cp_parser *, tree);
static tree cp_parser_namespace_name
(cp_parser *);
/* Declarators [gram.dcl.decl] */
static tree cp_parser_init_declarator
- (cp_parser *, tree, tree, bool, bool, int, bool *);
-static tree cp_parser_declarator
+ (cp_parser *, cp_decl_specifier_seq *, bool, bool, int, bool *);
+static cp_declarator *cp_parser_declarator
(cp_parser *, cp_parser_declarator_kind, int *, bool *);
-static tree cp_parser_direct_declarator
+static cp_declarator *cp_parser_direct_declarator
(cp_parser *, cp_parser_declarator_kind, int *);
static enum tree_code cp_parser_ptr_operator
- (cp_parser *, tree *, tree *);
-static tree cp_parser_cv_qualifier_seq_opt
- (cp_parser *);
-static tree cp_parser_cv_qualifier_opt
+ (cp_parser *, tree *, cp_cv_quals *);
+static cp_cv_quals cp_parser_cv_qualifier_seq_opt
(cp_parser *);
static tree cp_parser_declarator_id
(cp_parser *);
static tree cp_parser_type_id
(cp_parser *);
-static tree cp_parser_type_specifier_seq
+static void cp_parser_type_specifier_seq
+ (cp_parser *, cp_decl_specifier_seq *);
+static cp_parameter_declarator *cp_parser_parameter_declaration_clause
(cp_parser *);
-static tree cp_parser_parameter_declaration_clause
- (cp_parser *);
-static tree cp_parser_parameter_declaration_list
- (cp_parser *);
-static tree cp_parser_parameter_declaration
+static cp_parameter_declarator *cp_parser_parameter_declaration_list
+ (cp_parser *, bool *);
+static cp_parameter_declarator *cp_parser_parameter_declaration
(cp_parser *, bool, bool *);
static void cp_parser_function_body
(cp_parser *);
static tree cp_parser_class_specifier
(cp_parser *);
static tree cp_parser_class_head
- (cp_parser *, bool *);
+ (cp_parser *, bool *, tree *);
static enum tag_types cp_parser_class_key
(cp_parser *);
static void cp_parser_member_specification_opt
(cp_parser *);
static tree cp_parser_conversion_type_id
(cp_parser *);
-static tree cp_parser_conversion_declarator_opt
+static cp_declarator *cp_parser_conversion_declarator_opt
(cp_parser *);
static bool cp_parser_ctor_initializer_opt
(cp_parser *);
static tree cp_parser_template_parameter_list
(cp_parser *);
static tree cp_parser_template_parameter
- (cp_parser *);
+ (cp_parser *, bool *);
static tree cp_parser_type_parameter
(cp_parser *);
static tree cp_parser_template_id
/* Exception handling [gram.exception] */
-static tree cp_parser_try_block
+static tree cp_parser_try_block
(cp_parser *);
static bool cp_parser_function_try_block
(cp_parser *);
static tree cp_parser_maybe_treat_template_as_class
(tree, bool);
static bool cp_parser_check_declarator_template_parameters
- (cp_parser *, tree);
+ (cp_parser *, cp_declarator *);
static bool cp_parser_check_template_parameters
(cp_parser *, unsigned);
static tree cp_parser_simple_cast_expression
static bool cp_parser_constructor_declarator_p
(cp_parser *, bool);
static tree cp_parser_function_definition_from_specifiers_and_declarator
- (cp_parser *, tree, tree, tree);
+ (cp_parser *, cp_decl_specifier_seq *, tree, const cp_declarator *);
static tree cp_parser_function_definition_after_declarator
(cp_parser *, bool);
static void cp_parser_template_declaration_after_export
static tree cp_parser_functional_cast
(cp_parser *, tree);
static tree cp_parser_save_member_function_body
- (cp_parser *, tree, tree, tree);
+ (cp_parser *, cp_decl_specifier_seq *, cp_declarator *, tree);
static tree cp_parser_enclosed_template_argument_list
(cp_parser *);
static void cp_parser_save_default_args
(cp_parser *, enum rid);
static bool cp_parser_declares_only_class_p
(cp_parser *);
-static tree cp_parser_fold_non_dependent_expr
- (tree);
+static void cp_parser_set_storage_class
+ (cp_decl_specifier_seq *, cp_storage_class);
+static void cp_parser_set_decl_spec_type
+ (cp_decl_specifier_seq *, tree, bool);
static bool cp_parser_friend_p
- (tree);
+ (const cp_decl_specifier_seq *);
static cp_token *cp_parser_require
(cp_parser *, enum cpp_ttype, const char *);
static cp_token *cp_parser_require_keyword
(cp_parser *, enum rid, const char *);
-static bool cp_parser_token_starts_function_definition_p
+static bool cp_parser_token_starts_function_definition_p
(cp_token *);
static bool cp_parser_next_token_starts_class_definition_p
(cp_parser *);
static bool cp_parser_next_token_ends_template_argument_p
(cp_parser *);
+static bool cp_parser_nth_token_starts_template_argument_list_p
+ (cp_parser *, size_t);
static enum tag_types cp_parser_token_is_class_key
(cp_token *);
static void cp_parser_check_class_key
(tree type);
static bool cp_parser_optional_template_keyword
(cp_parser *);
-static void cp_parser_pre_parsed_nested_name_specifier
+static void cp_parser_pre_parsed_nested_name_specifier
(cp_parser *);
static void cp_parser_cache_group
(cp_parser *, cp_token_cache *, enum cpp_ttype, unsigned);
-static void cp_parser_parse_tentatively
+static void cp_parser_parse_tentatively
(cp_parser *);
static void cp_parser_commit_to_tentative_parse
(cp_parser *);
static void cp_parser_check_type_definition
(cp_parser *);
static void cp_parser_check_for_definition_in_return_type
- (tree, int);
+ (cp_declarator *, int);
static void cp_parser_check_for_invalid_template_id
(cp_parser *, tree);
-static tree cp_parser_non_integral_constant_expression
- (const char *);
-static bool cp_parser_diagnose_invalid_type_name
+static bool cp_parser_non_integral_constant_expression
+ (cp_parser *, const char *);
+static void cp_parser_diagnose_invalid_type_name
+ (cp_parser *, tree, tree);
+static bool cp_parser_parse_and_diagnose_invalid_type_name
(cp_parser *);
static int cp_parser_skip_to_closing_parenthesis
(cp_parser *, bool, bool, bool);
(cp_parser *);
static bool cp_parser_is_string_literal
(cp_token *);
-static bool cp_parser_is_keyword
+static bool cp_parser_is_keyword
(cp_token *, enum rid);
+static tree cp_parser_make_typename_type
+ (cp_parser *, tree, tree);
/* Returns nonzero if we are parsing tentatively. */
{
cp_token *token;
token = cp_lexer_peek_token (parser->lexer);
- c_parse_error (message,
+ c_parse_error (message,
/* Because c_parser_error does not understand
CPP_KEYWORD, keywords are treated like
identifiers. */
- (token->type == CPP_KEYWORD ? CPP_NAME : token->type),
+ (token->type == CPP_KEYWORD ? CPP_NAME : token->type),
token->value);
}
}
if (decl == error_mark_node)
{
if (parser->scope && parser->scope != global_namespace)
- error ("`%D::%D' has not been declared",
+ error ("`%D::%D' has not been declared",
parser->scope, name);
else if (parser->scope == global_namespace)
error ("`::%D' has not been declared", name);
/* If we are parsing tentatively, remember that an error has occurred
during this tentative parse. Returns true if the error was
- simulated; false if a messgae should be issued by the caller. */
+ simulated; false if a message should be issued by the caller. */
static bool
cp_parser_simulate_error (cp_parser* parser)
then an error is issued. */
static void
-cp_parser_check_for_definition_in_return_type (tree declarator,
+cp_parser_check_for_definition_in_return_type (cp_declarator *declarator,
int declares_class_or_enum)
{
/* [dcl.fct] forbids type definitions in return types.
Unfortunately, it's not easy to know whether or not we are
processing a return type until after the fact. */
while (declarator
- && (TREE_CODE (declarator) == INDIRECT_REF
- || TREE_CODE (declarator) == ADDR_EXPR))
- declarator = TREE_OPERAND (declarator, 0);
+ && (declarator->kind == cdk_pointer
+ || declarator->kind == cdk_reference
+ || declarator->kind == cdk_ptrmem))
+ declarator = declarator->declarator;
if (declarator
- && TREE_CODE (declarator) == CALL_EXPR
+ && declarator->kind == cdk_function
&& declares_class_or_enum & 2)
error ("new types may not be defined in a return type");
}
invalid attempt to form a template-id. */
static void
-cp_parser_check_for_invalid_template_id (cp_parser* parser,
+cp_parser_check_for_invalid_template_id (cp_parser* parser,
tree type)
{
ptrdiff_t start;
if (TYPE_P (type))
error ("`%T' is not a template", type);
else if (TREE_CODE (type) == IDENTIFIER_NODE)
- error ("`%s' is not a template", IDENTIFIER_POINTER (type));
+ error ("`%E' is not a template", type);
else
error ("invalid template-id");
/* Remember the location of the invalid "<". */
}
}
-/* Issue an error message about the fact that THING appeared in a
- constant-expression. Returns ERROR_MARK_NODE. */
-
-static tree
-cp_parser_non_integral_constant_expression (const char *thing)
-{
- error ("%s cannot appear in a constant-expression", thing);
- return error_mark_node;
-}
-
-/* Check for a common situation where a type-name should be present,
- but is not, and issue a sensible error message. Returns true if an
- invalid type-name was detected. */
+/* 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. */
static bool
-cp_parser_diagnose_invalid_type_name (cp_parser *parser)
+cp_parser_non_integral_constant_expression (cp_parser *parser,
+ const char *thing)
{
- /* If the next two tokens are both identifiers, the code is
- erroneous. The usual cause of this situation is code like:
+ 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;
+}
- T t;
+/* 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. */
- where "T" should name a type -- but does not. */
- if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)
- && cp_lexer_peek_nth_token (parser->lexer, 2)->type == CPP_NAME)
+static void
+cp_parser_diagnose_invalid_type_name (cp_parser *parser, tree scope, tree id)
+{
+ tree decl, old_scope;
+ /* Try to lookup the identifier. */
+ old_scope = parser->scope;
+ parser->scope = scope;
+ decl = cp_parser_lookup_name_simple (parser, id);
+ parser->scope = old_scope;
+ /* If the lookup found a template-name, it means that the user forgot
+ to specify an argument list. Emit an useful error message. */
+ if (TREE_CODE (decl) == TEMPLATE_DECL)
+ error ("invalid use of template-name `%E' without an argument list",
+ decl);
+ else if (!parser->scope)
{
- tree name;
-
- /* If parsing tentatively, we should commit; we really are
- looking at a declaration. */
- /* Consume the first identifier. */
- name = cp_lexer_consume_token (parser->lexer)->value;
/* Issue an error message. */
- error ("`%s' does not name a type", IDENTIFIER_POINTER (name));
+ error ("`%E' does not name a type", id);
/* If we're in a template class, it's possible that the user was
referring to a type from a base class. For example:
b = TREE_CHAIN (b))
{
tree base_type = BINFO_TYPE (b);
- if (CLASS_TYPE_P (base_type)
+ if (CLASS_TYPE_P (base_type)
&& dependent_type_p (base_type))
{
tree field;
field;
field = TREE_CHAIN (field))
if (TREE_CODE (field) == TYPE_DECL
- && DECL_NAME (field) == name)
+ && DECL_NAME (field) == id)
{
- error ("(perhaps `typename %T::%s' was intended)",
- BINFO_TYPE (b), IDENTIFIER_POINTER (name));
+ inform ("(perhaps `typename %T::%E' was intended)",
+ BINFO_TYPE (b), id);
break;
}
if (field)
}
}
}
- /* Skip to the end of the declaration; there's no point in
- trying to process it. */
- cp_parser_skip_to_end_of_statement (parser);
-
- return true;
}
+ /* Here we diagnose qualified-ids where the scope is actually correct,
+ but the identifier does not resolve to a valid type name. */
+ else
+ {
+ if (TREE_CODE (parser->scope) == NAMESPACE_DECL)
+ error ("`%E' in namespace `%E' does not name a type",
+ id, parser->scope);
+ else if (TYPE_P (parser->scope))
+ error ("`%E' in class `%T' does not name a type",
+ id, parser->scope);
+ else
+ abort();
+ }
+}
- return false;
+/* Check for a common situation where a type-name should be present,
+ but is not, and issue a sensible error message. Returns true if an
+ invalid type-name was detected.
+
+ The situation handled by this function are variable declarations of the
+ form `ID a', where `ID' is an id-expression and `a' is a plain identifier.
+ Usually, `ID' should name a type, but if we got here it means that it
+ does not. We try to emit the best possible error message depending on
+ how exactly the id-expression looks like.
+*/
+
+static bool
+cp_parser_parse_and_diagnose_invalid_type_name (cp_parser *parser)
+{
+ tree id;
+
+ cp_parser_parse_tentatively (parser);
+ id = cp_parser_id_expression (parser,
+ /*template_keyword_p=*/false,
+ /*check_dependency_p=*/true,
+ /*template_p=*/NULL,
+ /*declarator_p=*/true);
+ /* After the id-expression, there should be a plain identifier,
+ otherwise this is not a simple variable declaration. Also, if
+ the scope is dependent, we cannot do much. */
+ if (!cp_lexer_next_token_is (parser->lexer, CPP_NAME)
+ || (parser->scope && TYPE_P (parser->scope)
+ && dependent_type_p (parser->scope)))
+ {
+ cp_parser_abort_tentative_parse (parser);
+ return false;
+ }
+ if (!cp_parser_parse_definitely (parser))
+ return false;
+
+ /* If we got here, this cannot be a valid variable declaration, thus
+ the cp_parser_id_expression must have resolved to a plain identifier
+ node (not a TYPE_DECL or TEMPLATE_ID_EXPR). */
+ my_friendly_assert (TREE_CODE (id) == IDENTIFIER_NODE, 20030203);
+ /* Emit a diagnostic for the invalid type. */
+ cp_parser_diagnose_invalid_type_name (parser, parser->scope, id);
+ /* Skip to the end of the declaration; there's no point in
+ trying to process it. */
+ cp_parser_skip_to_end_of_block_or_statement (parser);
+ return true;
}
-/* Consume tokens up to, and including, the next non-nested closing `)'.
+/* Consume tokens up to, and including, the next non-nested closing `)'.
Returns 1 iff we found a closing `)'. RECOVERING is true, if we
are doing error recovery. Returns -1 if OR_COMMA is true and we
found an unnested comma. */
static int
cp_parser_skip_to_closing_parenthesis (cp_parser *parser,
- bool recovering,
+ bool recovering,
bool or_comma,
bool consume_paren)
{
unsigned paren_depth = 0;
unsigned brace_depth = 0;
+ int saved_c_lex_string_translate = c_lex_string_translate;
+ int result;
if (recovering && !or_comma && cp_parser_parsing_tentatively (parser)
&& !cp_parser_committed_to_tentative_parse (parser))
return 0;
-
+
+ if (! recovering)
+ /* If we're looking ahead, keep both translated and untranslated
+ strings. */
+ c_lex_string_translate = -1;
+
while (true)
{
cp_token *token;
-
+
/* If we've run out of tokens, then there is no closing `)'. */
if (cp_lexer_next_token_is (parser->lexer, CPP_EOF))
- return 0;
+ {
+ result = 0;
+ break;
+ }
token = cp_lexer_peek_token (parser->lexer);
-
+
/* This matches the processing in skip_to_end_of_statement. */
if (token->type == CPP_SEMICOLON && !brace_depth)
- return 0;
+ {
+ result = 0;
+ break;
+ }
if (token->type == CPP_OPEN_BRACE)
++brace_depth;
if (token->type == CPP_CLOSE_BRACE)
{
if (!brace_depth--)
- return 0;
+ {
+ result = 0;
+ break;
+ }
}
if (recovering && or_comma && token->type == CPP_COMMA
&& !brace_depth && !paren_depth)
- return -1;
-
+ {
+ result = -1;
+ break;
+ }
+
if (!brace_depth)
{
/* If it is an `(', we have entered another level of nesting. */
{
if (consume_paren)
cp_lexer_consume_token (parser->lexer);
- return 1;
+ {
+ result = 1;
+ break;
+ }
}
}
-
+
/* Consume the token. */
cp_lexer_consume_token (parser->lexer);
}
+
+ c_lex_string_translate = saved_c_lex_string_translate;
+ return result;
}
/* Consume tokens until we reach the end of the current statement.
/* If this is a non-nested `}', stop before consuming it.
That way, when confronted with something like:
- { 3 + }
+ { 3 + }
we stop before consuming the closing `}', even though we
have not yet reached a `;'. */
token = cp_lexer_consume_token (parser->lexer);
/* If the next token is a non-nested `}', then we have reached
the end of the current block. */
- if (token->type == CPP_CLOSE_BRACE
+ if (token->type == CPP_CLOSE_BRACE
&& (nesting_depth == 0 || --nesting_depth == 0))
break;
/* If it the next token is a `{', then we are entering a new
}
}
+/* This is a simple wrapper around make_typename_type. When the id is
+ an unresolved identifier node, we can provide a superior diagnostic
+ using cp_parser_diagnose_invalid_type_name. */
+
+static tree
+cp_parser_make_typename_type (cp_parser *parser, tree scope, tree id)
+{
+ tree result;
+ if (TREE_CODE (id) == IDENTIFIER_NODE)
+ {
+ result = make_typename_type (scope, id, /*complain=*/0);
+ if (result == error_mark_node)
+ cp_parser_diagnose_invalid_type_name (parser, scope, id);
+ return result;
+ }
+ return make_typename_type (scope, id, tf_error);
+}
+
+
/* Create a new C++ parser. */
static cp_parser *
parser->greater_than_is_operator_p = true;
parser->default_arg_ok_p = true;
-
+
/* We are not parsing a constant-expression. */
parser->integral_constant_expression_p = false;
parser->allow_non_integral_constant_expression_p = false;
parser->non_integral_constant_expression_p = false;
- /* We are not parsing offsetof. */
- parser->in_offsetof_p = false;
-
/* Local variable names are not forbidden. */
parser->local_variables_forbidden_p = false;
/* Parse an identifier. Returns an IDENTIFIER_NODE representing the
identifier. */
-static tree
+static tree
cp_parser_identifier (cp_parser* parser)
{
cp_token *token;
/* Parse a translation-unit.
translation-unit:
- declaration-seq [opt]
+ declaration-seq [opt]
Returns TRUE if all went well. */
static bool
cp_parser_translation_unit (cp_parser* parser)
{
+ /* The address of the first non-permanent object on the declarator
+ obstack. */
+ static void *declarator_obstack_base;
+
+ bool success;
+
+ /* Create the declarator obstack, if necessary. */
+ if (!cp_error_declarator)
+ {
+ gcc_obstack_init (&declarator_obstack);
+ /* Create the error declarator. */
+ cp_error_declarator = make_declarator (cdk_error);
+ /* Create the empty parameter list. */
+ no_parameters = make_parameter_declarator (NULL, NULL, NULL_TREE);
+ /* Remember where the base of the declarator obstack lies. */
+ declarator_obstack_base = obstack_next_free (&declarator_obstack);
+ }
+
while (true)
{
cp_parser_declaration_seq_opt (parser);
/* If there are no tokens left then all went well. */
if (cp_lexer_next_token_is (parser->lexer, CPP_EOF))
- break;
-
- /* Otherwise, issue an error message. */
- cp_parser_error (parser, "expected declaration");
- return false;
+ {
+ /* Consume the EOF token. */
+ cp_parser_require (parser, CPP_EOF, "end-of-file");
+
+ /* Finish up. */
+ finish_translation_unit ();
+
+ success = true;
+ break;
+ }
+ else
+ {
+ cp_parser_error (parser, "expected declaration");
+ success = false;
+ break;
+ }
}
- /* Consume the EOF token. */
- cp_parser_require (parser, CPP_EOF, "end-of-file");
-
- /* Finish up. */
- finish_translation_unit ();
+ /* Make sure the declarator obstack was fully cleaned up. */
+ my_friendly_assert (obstack_next_free (&declarator_obstack) ==
+ declarator_obstack_base,
+ 20040621);
/* All went well. */
- return true;
+ return success;
}
/* Expressions [gram.expr] */
literal:
__null
- Returns a representation of the expression.
+ Returns a representation of the expression.
- *IDK indicates what kind of id-expression (if any) was present.
+ *IDK indicates what kind of id-expression (if any) was present.
*QUALIFYING_CLASS is set to a non-NULL value if the id-expression can be
used as the operand of a pointer-to-member. In that case,
class in the pointer-to-member. */
static tree
-cp_parser_primary_expression (cp_parser *parser,
+cp_parser_primary_expression (cp_parser *parser,
cp_id_kind *idk,
tree *qualifying_class)
{
boolean-literal */
case CPP_CHAR:
case CPP_WCHAR:
- case CPP_STRING:
- case CPP_WSTRING:
case CPP_NUMBER:
token = cp_lexer_consume_token (parser->lexer);
return token->value;
+ case CPP_STRING:
+ case CPP_WSTRING:
+ token = cp_lexer_consume_token (parser->lexer);
+ if (TREE_CHAIN (token->value))
+ return TREE_CHAIN (token->value);
+ else
+ return token->value;
+
case CPP_OPEN_PAREN:
{
tree expr;
cp_lexer_consume_token (parser->lexer);
/* Within a parenthesized expression, a `>' token is always
the greater-than operator. */
- saved_greater_than_is_operator_p
+ saved_greater_than_is_operator_p
= parser->greater_than_is_operator_p;
parser->greater_than_is_operator_p = true;
/* If we see `( { ' then we are looking at the beginning of
{
/* Statement-expressions are not allowed by the standard. */
if (pedantic)
- pedwarn ("ISO C++ forbids braced-groups within expressions");
-
+ pedwarn ("ISO C++ forbids braced-groups within expressions");
+
/* And they're not allowed outside of a function-body; you
cannot, for example, write:
-
+
int i = ({ int j = 3; j + 1; });
-
+
at class or namespace scope. */
if (!at_function_scope_p ())
error ("statement-expressions are allowed only inside functions");
/* Start the statement-expression. */
expr = begin_stmt_expr ();
/* Parse the compound-statement. */
- cp_parser_compound_statement (parser, true);
+ cp_parser_compound_statement (parser, expr, false);
/* Finish up. */
expr = finish_stmt_expr (expr, false);
}
}
/* The `>' token might be the end of a template-id or
template-parameter-list now. */
- parser->greater_than_is_operator_p
+ parser->greater_than_is_operator_p
= saved_greater_than_is_operator_p;
/* Consume the `)'. */
if (!cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'"))
case RID_FALSE:
cp_lexer_consume_token (parser->lexer);
return boolean_false_node;
-
+
/* The `__null' literal. */
case RID_NULL:
cp_lexer_consume_token (parser->lexer);
return error_mark_node;
}
/* Pointers cannot appear in constant-expressions. */
- if (parser->integral_constant_expression_p)
- {
- if (!parser->allow_non_integral_constant_expression_p)
- return cp_parser_non_integral_constant_expression ("`this'");
- parser->non_integral_constant_expression_p = true;
- }
+ if (cp_parser_non_integral_constant_expression (parser,
+ "`this'"))
+ return error_mark_node;
return finish_this_expr ();
/* The `operator' keyword can be the beginning of an
__func__ are the names of variables -- but they are
treated specially. Therefore, they are handled here,
rather than relying on the generic id-expression logic
- below. Grammatically, these names are id-expressions.
+ below. Grammatically, these names are id-expressions.
Consume the token. */
token = cp_lexer_consume_token (parser->lexer);
cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
/* Using `va_arg' in a constant-expression is not
allowed. */
- if (parser->integral_constant_expression_p)
- {
- if (!parser->allow_non_integral_constant_expression_p)
- return cp_parser_non_integral_constant_expression ("`va_arg'");
- parser->non_integral_constant_expression_p = true;
- }
+ if (cp_parser_non_integral_constant_expression (parser,
+ "`va_arg'"))
+ return error_mark_node;
return build_x_va_arg (expression, type);
}
case RID_OFFSETOF:
- {
- tree expression;
- bool saved_in_offsetof_p;
-
- /* Consume the "__offsetof__" token. */
- cp_lexer_consume_token (parser->lexer);
- /* Consume the opening `('. */
- cp_parser_require (parser, CPP_OPEN_PAREN, "`('");
- /* Parse the parenthesized (almost) constant-expression. */
- saved_in_offsetof_p = parser->in_offsetof_p;
- parser->in_offsetof_p = true;
- expression
- = cp_parser_constant_expression (parser,
- /*allow_non_constant_p=*/false,
- /*non_constant_p=*/NULL);
- parser->in_offsetof_p = saved_in_offsetof_p;
- /* Consume the closing ')'. */
- cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
-
- return expression;
- }
+ return cp_parser_builtin_offsetof (parser);
default:
cp_parser_error (parser, "expected primary-expression");
id_expression:
/* Parse the id-expression. */
- id_expression
- = cp_parser_id_expression (parser,
+ id_expression
+ = cp_parser_id_expression (parser,
/*template_keyword_p=*/false,
/*check_dependency_p=*/true,
/*template_p=*/NULL,
|| TREE_CODE (id_expression) == TYPE_DECL)
decl = id_expression;
/* Look up the name. */
- else
+ else
{
decl = cp_parser_lookup_name_simple (parser, id_expression);
/* If name lookup gives us a SCOPE_REF, then the
extern void f(int j = i);
}
- Here, name look up will originally find the out
+ Here, name look up will originally find the out
of scope `i'. We need to issue a warning message,
but then use the global `i'. */
decl = check_for_out_of_scope_variable (decl);
}
}
}
-
- decl = finish_id_expression (id_expression, decl, parser->scope,
+
+ decl = finish_id_expression (id_expression, decl, parser->scope,
idk, qualifying_class,
parser->integral_constant_expression_p,
parser->allow_non_integral_constant_expression_p,
`template' keyword.
If CHECK_DEPENDENCY_P is false, then names are looked up inside
- uninstantiated templates.
+ uninstantiated templates.
If *TEMPLATE_P is non-NULL, it is set to true iff the
`template' keyword is used to explicitly indicate that the entity
- named is a template.
+ named is a template.
If DECLARATOR_P is true, the id-expression is appearing as part of
a declarator, rather than as part of an expression. */
*template_p = false;
/* Look for the optional `::' operator. */
- global_scope_p
- = (cp_parser_global_scope_opt (parser, /*current_scope_valid_p=*/false)
+ global_scope_p
+ = (cp_parser_global_scope_opt (parser, /*current_scope_valid_p=*/false)
!= NULL_TREE);
/* Look for the optional nested-name-specifier. */
- nested_name_specifier_p
+ nested_name_specifier_p
= (cp_parser_nested_name_specifier_opt (parser,
/*typename_keyword_p=*/false,
check_dependency_p,
/* If it's an identifier, and the next token is not a "<", then
we can avoid the template-id case. This is an optimization
for this common case. */
- if (token->type == CPP_NAME
- && cp_lexer_peek_nth_token (parser->lexer, 2)->type != CPP_LESS)
+ if (token->type == CPP_NAME
+ && !cp_parser_nth_token_starts_template_argument_list_p
+ (parser, 2))
return cp_parser_identifier (parser);
cp_parser_parse_tentatively (parser);
/* Try a template-id. */
- id = cp_parser_template_id (parser,
+ id = cp_parser_template_id (parser,
/*template_keyword_p=*/false,
/*check_dependency_p=*/true,
declarator_p);
if (token->keyword == RID_OPERATOR)
return cp_parser_operator_function_id (parser);
/* Fall through. */
-
+
default:
cp_parser_error (parser, "expected id-expression");
return error_mark_node;
rather than as part of an expression. */
static tree
-cp_parser_unqualified_id (cp_parser* parser,
+cp_parser_unqualified_id (cp_parser* parser,
bool template_keyword_p,
bool check_dependency_p,
bool declarator_p)
/* Peek at the next token. */
token = cp_lexer_peek_token (parser->lexer);
-
+
switch (token->type)
{
case CPP_NAME:
template <typename T> void f(T t) {
t.T::~T();
- }
+ }
Here, it is not possible to look up `T' in the scope of `T'
itself. We must look in both the current scope, and the
- scope of the containing complete expression.
+ scope of the containing complete expression.
Yet another issue is:
/* If the name is of the form "X::~X" it's OK. */
if (scope && TYPE_P (scope)
&& cp_lexer_next_token_is (parser->lexer, CPP_NAME)
- && (cp_lexer_peek_nth_token (parser->lexer, 2)->type
+ && (cp_lexer_peek_nth_token (parser->lexer, 2)->type
== CPP_OPEN_PAREN)
- && (cp_lexer_peek_token (parser->lexer)->value
+ && (cp_lexer_peek_token (parser->lexer)->value
== TYPE_IDENTIFIER (scope)))
{
cp_lexer_consume_token (parser->lexer);
if (scope)
{
cp_parser_parse_tentatively (parser);
- type_decl = cp_parser_class_name (parser,
+ type_decl = cp_parser_class_name (parser,
/*typename_keyword_p=*/false,
/*template_keyword_p=*/false,
/*type_p=*/false,
parser->scope = qualifying_scope;
parser->object_scope = NULL_TREE;
parser->qualifying_scope = NULL_TREE;
- type_decl
- = cp_parser_class_name (parser,
+ type_decl
+ = cp_parser_class_name (parser,
/*typename_keyword_p=*/false,
/*template_keyword_p=*/false,
/*type_p=*/false,
parser->scope = object_scope;
parser->object_scope = NULL_TREE;
parser->qualifying_scope = NULL_TREE;
- type_decl
- = cp_parser_class_name (parser,
+ type_decl
+ = cp_parser_class_name (parser,
/*typename_keyword_p=*/false,
/*template_keyword_p=*/false,
/*type_p=*/false,
parser->scope = NULL_TREE;
parser->object_scope = NULL_TREE;
parser->qualifying_scope = NULL_TREE;
- type_decl
- = cp_parser_class_name (parser,
+ type_decl
+ = cp_parser_class_name (parser,
/*typename_keyword_p=*/false,
/*template_keyword_p=*/false,
/*type_p=*/false,
A typedef-name that names a class shall not be used as the
identifier in the declarator for a destructor declaration. */
- if (declarator_p
+ if (declarator_p
&& !DECL_IMPLICIT_TYPEDEF_P (type_decl)
&& !DECL_SELF_REFERENCE_P (type_decl))
error ("typedef-name `%D' used as destructor declarator",
Sets PARSER->SCOPE to the class (TYPE) or namespace
(NAMESPACE_DECL) specified by the nested-name-specifier, or leaves
it unchanged if there is no nested-name-specifier. Returns the new
- scope iff there is a nested-name-specifier, or NULL_TREE otherwise.
+ scope iff there is a nested-name-specifier, or NULL_TREE otherwise.
If IS_DECLARATION is TRUE, the nested-name-specifier is known to be
part of a declaration and/or decl-specifier. */
static tree
-cp_parser_nested_name_specifier_opt (cp_parser *parser,
- bool typename_keyword_p,
+cp_parser_nested_name_specifier_opt (cp_parser *parser,
+ bool typename_keyword_p,
bool check_dependency_p,
bool type_p,
bool is_declaration)
/* If the next token corresponds to a nested name specifier, there
is no need to reparse it. However, if CHECK_DEPENDENCY_P is
- false, it may have been true before, in which case something
+ false, it may have been true before, in which case something
like `A<X>::B<Y>::C' may have resulted in a nested-name-specifier
of `A<X>::', where it should now be `A<X>::B<Y>::'. So, when
CHECK_DEPENDENCY_P is false, we have to fall through into the
template-id), nor a `::', then we are not looking at a
nested-name-specifier. */
token = cp_lexer_peek_nth_token (parser->lexer, 2);
- if (token->type != CPP_LESS && token->type != CPP_SCOPE)
+ if (token->type != CPP_SCOPE
+ && !cp_parser_nth_token_starts_template_argument_list_p
+ (parser, 2))
break;
}
old_scope = parser->scope;
saved_qualifying_scope = parser->qualifying_scope;
/* Parse the qualifying entity. */
- new_scope
+ new_scope
= cp_parser_class_or_namespace_name (parser,
typename_keyword_p,
template_keyword_p,
that is a `::', then any valid interpretation would have
found a class-or-namespace-name. */
while (cp_lexer_next_token_is (parser->lexer, CPP_NAME)
- && (cp_lexer_peek_nth_token (parser->lexer, 2)->type
+ && (cp_lexer_peek_nth_token (parser->lexer, 2)->type
== CPP_SCOPE)
- && (cp_lexer_peek_nth_token (parser->lexer, 3)->type
+ && (cp_lexer_peek_nth_token (parser->lexer, 3)->type
!= CPP_COMPL))
{
token = cp_lexer_consume_token (parser->lexer);
- if (!error_p)
+ if (!error_p)
{
tree decl;
error ("`%D' used without template parameters",
decl);
else
- cp_parser_name_lookup_error
- (parser, token->value, decl,
+ cp_parser_name_lookup_error
+ (parser, token->value, decl,
"is not a class or namespace");
parser->scope = NULL_TREE;
error_p = true;
success = true;
/* Make sure we look in the right scope the next time through
the loop. */
- parser->scope = (TREE_CODE (new_scope) == TYPE_DECL
+ parser->scope = (TREE_CODE (new_scope) == TYPE_DECL
? TREE_TYPE (new_scope)
: new_scope);
/* If it is a class scope, try to complete it; we are about to
{
/* Find the token that corresponds to the start of the
template-id. */
- token = cp_lexer_advance_token (parser->lexer,
+ token = cp_lexer_advance_token (parser->lexer,
parser->lexer->first_token,
start);
is present. */
static tree
-cp_parser_nested_name_specifier (cp_parser *parser,
- bool typename_keyword_p,
+cp_parser_nested_name_specifier (cp_parser *parser,
+ bool typename_keyword_p,
bool check_dependency_p,
bool type_p,
bool is_declaration)
ERROR_MARK_NODE is returned. */
static tree
-cp_parser_class_or_namespace_name (cp_parser *parser,
+cp_parser_class_or_namespace_name (cp_parser *parser,
bool typename_keyword_p,
bool template_keyword_p,
bool check_dependency_p,
only_class_p = template_keyword_p || (saved_scope && TYPE_P (saved_scope));
if (!only_class_p)
cp_parser_parse_tentatively (parser);
- scope = cp_parser_class_name (parser,
+ scope = cp_parser_class_name (parser,
typename_keyword_p,
template_keyword_p,
type_p,
postfix-expression [ expression ]
postfix-expression ( expression-list [opt] )
simple-type-specifier ( expression-list [opt] )
- typename :: [opt] nested-name-specifier identifier
+ typename :: [opt] nested-name-specifier identifier
( expression-list [opt] )
typename :: [opt] nested-name-specifier template [opt] template-id
( expression-list [opt] )
typeid ( type-id )
GNU Extension:
-
+
postfix-expression:
( type-id ) { initializer-list , [opt] }
of view of parsing. Begin by consuming the token
identifying the cast. */
cp_lexer_consume_token (parser->lexer);
-
+
/* New types cannot be defined in the cast. */
saved_message = parser->type_definition_forbidden_message;
parser->type_definition_forbidden_message
if (parser->integral_constant_expression_p
&& !dependent_type_p (type)
&& !INTEGRAL_OR_ENUMERATION_TYPE_P (type)
- /* A cast to pointer or reference type is allowed in the
- implementation of "offsetof". */
- && !(parser->in_offsetof_p && POINTER_TYPE_P (type)))
- {
- if (!parser->allow_non_integral_constant_expression_p)
- return (cp_parser_non_integral_constant_expression
- ("a cast to a type other than an integral or "
- "enumeration type"));
- parser->non_integral_constant_expression_p = true;
- }
+ && (cp_parser_non_integral_constant_expression
+ (parser,
+ "a cast to a type other than an integral or "
+ "enumeration type")))
+ return error_mark_node;
switch (keyword)
{
/* Look for the `)' token. */
cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
}
-
+ /* `typeid' may not appear in an integral constant expression. */
+ if (cp_parser_non_integral_constant_expression(parser,
+ "`typeid' operator"))
+ return error_mark_node;
/* Restore the saved message. */
parser->type_definition_forbidden_message = saved_message;
}
break;
-
+
case RID_TYPENAME:
{
bool template_p = false;
/* Consume the `typename' token. */
cp_lexer_consume_token (parser->lexer);
/* Look for the optional `::' operator. */
- cp_parser_global_scope_opt (parser,
+ cp_parser_global_scope_opt (parser,
/*current_scope_valid_p=*/false);
/* Look for the nested-name-specifier. */
cp_parser_nested_name_specifier (parser,
/* If that didn't work, try an identifier. */
if (!cp_parser_parse_definitely (parser))
id = cp_parser_identifier (parser);
+ /* If we look up a template-id in a non-dependent qualifying
+ scope, there's no need to create a dependent type. */
+ if (TREE_CODE (id) == TYPE_DECL
+ && !dependent_type_p (parser->scope))
+ type = TREE_TYPE (id);
/* Create a TYPENAME_TYPE to represent the type to which the
functional cast is being performed. */
- type = make_typename_type (parser->scope, id,
- /*complain=*/1);
+ else
+ type = make_typename_type (parser->scope, id,
+ /*complain=*/1);
postfix_expression = cp_parser_functional_cast (parser, type);
}
that doesn't work we fall back to the primary-expression. */
cp_parser_parse_tentatively (parser);
/* Look for the simple-type-specifier. */
- type = cp_parser_simple_type_specifier (parser,
- CP_PARSER_FLAGS_NONE,
- /*identifier_p=*/false);
+ type = cp_parser_simple_type_specifier (parser,
+ /*decl_specs=*/NULL,
+ CP_PARSER_FLAGS_NONE);
/* Parse the cast itself. */
if (!cp_parser_error_occurred (parser))
- postfix_expression
+ postfix_expression
= cp_parser_functional_cast (parser, type);
/* If that worked, we're done. */
if (cp_parser_parse_definitely (parser))
{
bool non_constant_p;
/* Parse the initializer-list. */
- initializer_list
+ initializer_list
= cp_parser_initializer_list (parser, &non_constant_p);
/* Allow a trailing `,'. */
if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA))
if (pedantic)
pedwarn ("ISO C++ forbids compound-literals");
/* Form the representation of the compound-literal. */
- postfix_expression
+ postfix_expression
= finish_compound_literal (type, initializer_list);
break;
}
}
/* It must be a primary-expression. */
- postfix_expression = cp_parser_primary_expression (parser,
+ postfix_expression = cp_parser_primary_expression (parser,
&idk,
&qualifying_class);
}
&& TREE_CODE (postfix_expression) == IDENTIFIER_NODE
&& cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_PAREN))
/* It is not a Koenig lookup function call. */
- postfix_expression
+ postfix_expression
= unqualified_name_lookup_error (postfix_expression);
-
+
/* Peek at the next token. */
token = cp_lexer_peek_token (parser->lexer);
switch (token->type)
{
case CPP_OPEN_SQUARE:
- /* postfix-expression [ expression ] */
- {
- tree index;
-
- /* Consume the `[' token. */
- cp_lexer_consume_token (parser->lexer);
- /* Parse the index expression. */
- index = cp_parser_expression (parser);
- /* Look for the closing `]'. */
- cp_parser_require (parser, CPP_CLOSE_SQUARE, "`]'");
-
- /* Build the ARRAY_REF. */
- postfix_expression
- = grok_array_decl (postfix_expression, index);
- idk = CP_ID_KIND_NONE;
- /* Array references are not permitted in
- constant-expressions. */
- if (parser->integral_constant_expression_p)
- {
- if (!parser->allow_non_integral_constant_expression_p)
- postfix_expression
- = cp_parser_non_integral_constant_expression ("an array reference");
- parser->non_integral_constant_expression_p = true;
- }
- }
+ postfix_expression
+ = cp_parser_postfix_open_square_expression (parser,
+ postfix_expression,
+ false);
+ idk = CP_ID_KIND_NONE;
break;
case CPP_OPEN_PAREN:
/* postfix-expression ( expression-list [opt] ) */
{
bool koenig_p;
- tree args = (cp_parser_parenthesized_expression_list
+ tree args = (cp_parser_parenthesized_expression_list
(parser, false, /*non_constant_p=*/NULL));
if (args == error_mark_node)
postfix_expression = error_mark_node;
break;
}
-
+
/* Function calls are not permitted in
constant-expressions. */
- if (parser->integral_constant_expression_p)
+ if (cp_parser_non_integral_constant_expression (parser,
+ "a function call"))
{
- if (!parser->allow_non_integral_constant_expression_p)
- {
- postfix_expression
- = cp_parser_non_integral_constant_expression ("a function call");
- break;
- }
- parser->non_integral_constant_expression_p = true;
+ postfix_expression = error_mark_node;
+ break;
}
koenig_p = false;
if (idk == CP_ID_KIND_UNQUALIFIED)
{
+ /* We do not perform argument-dependent lookup if
+ normal lookup finds a non-function, in accordance
+ with the expected resolution of DR 218. */
if (args
&& (is_overloaded_fn (postfix_expression)
- || DECL_P (postfix_expression)
|| TREE_CODE (postfix_expression) == IDENTIFIER_NODE))
{
koenig_p = true;
- postfix_expression
+ postfix_expression
= perform_koenig_lookup (postfix_expression, args);
}
else if (TREE_CODE (postfix_expression) == IDENTIFIER_NODE)
postfix_expression
= unqualified_fn_lookup_error (postfix_expression);
}
-
+
if (TREE_CODE (postfix_expression) == COMPONENT_REF)
{
tree instance = TREE_OPERAND (postfix_expression, 0);
|| any_type_dependent_arguments_p (args)))
{
postfix_expression
- = build_min_nt (CALL_EXPR, postfix_expression, args);
+ = build_min_nt (CALL_EXPR, postfix_expression,
+ args, NULL_TREE);
break;
}
-
- postfix_expression
- = (build_new_method_call
- (instance, fn, args, NULL_TREE,
- (idk == CP_ID_KIND_QUALIFIED
- ? LOOKUP_NONVIRTUAL : LOOKUP_NORMAL)));
+
+ if (BASELINK_P (fn))
+ postfix_expression
+ = (build_new_method_call
+ (instance, fn, args, NULL_TREE,
+ (idk == CP_ID_KIND_QUALIFIED
+ ? LOOKUP_NONVIRTUAL : LOOKUP_NORMAL)));
+ else
+ postfix_expression
+ = finish_call_expr (postfix_expression, args,
+ /*disallow_virtual=*/false,
+ /*koenig_p=*/false);
}
else if (TREE_CODE (postfix_expression) == OFFSET_REF
|| TREE_CODE (postfix_expression) == MEMBER_REF
koenig_p);
else
/* All other function calls. */
- postfix_expression
- = finish_call_expr (postfix_expression, args,
+ postfix_expression
+ = finish_call_expr (postfix_expression, args,
/*disallow_virtual=*/false,
koenig_p);
idk = CP_ID_KIND_NONE;
}
break;
-
+
case CPP_DOT:
case CPP_DEREF:
- /* postfix-expression . template [opt] id-expression
- postfix-expression . pseudo-destructor-name
+ /* postfix-expression . template [opt] id-expression
+ postfix-expression . pseudo-destructor-name
postfix-expression -> template [opt] id-expression
postfix-expression -> pseudo-destructor-name */
- {
- tree name;
- bool dependent_p;
- bool template_p;
- tree scope = NULL_TREE;
- enum cpp_ttype token_type = token->type;
-
- /* If this is a `->' operator, dereference the pointer. */
- if (token->type == CPP_DEREF)
- postfix_expression = build_x_arrow (postfix_expression);
- /* Check to see whether or not the expression is
- type-dependent. */
- dependent_p = type_dependent_expression_p (postfix_expression);
- /* The identifier following the `->' or `.' is not
- qualified. */
- parser->scope = NULL_TREE;
- parser->qualifying_scope = NULL_TREE;
- parser->object_scope = NULL_TREE;
- idk = CP_ID_KIND_NONE;
- /* Enter the scope corresponding to the type of the object
- given by the POSTFIX_EXPRESSION. */
- if (!dependent_p
- && TREE_TYPE (postfix_expression) != NULL_TREE)
- {
- scope = TREE_TYPE (postfix_expression);
- /* According to the standard, no expression should
- ever have reference type. Unfortunately, we do not
- currently match the standard in this respect in
- that our internal representation of an expression
- may have reference type even when the standard says
- it does not. Therefore, we have to manually obtain
- the underlying type here. */
- scope = non_reference (scope);
- /* The type of the POSTFIX_EXPRESSION must be
- complete. */
- scope = complete_type_or_else (scope, NULL_TREE);
- /* Let the name lookup machinery know that we are
- processing a class member access expression. */
- parser->context->object_type = scope;
- /* If something went wrong, we want to be able to
- discern that case, as opposed to the case where
- there was no SCOPE due to the type of expression
- being dependent. */
- if (!scope)
- scope = error_mark_node;
- }
- /* Consume the `.' or `->' operator. */
- cp_lexer_consume_token (parser->lexer);
- /* If the SCOPE is not a scalar type, we are looking at an
- ordinary class member access expression, rather than a
- pseudo-destructor-name. */
- if (!scope || !SCALAR_TYPE_P (scope))
- {
- template_p = cp_parser_optional_template_keyword (parser);
- /* Parse the id-expression. */
- name = cp_parser_id_expression (parser,
- template_p,
- /*check_dependency_p=*/true,
- /*template_p=*/NULL,
- /*declarator_p=*/false);
- /* In general, build a SCOPE_REF if the member name is
- qualified. However, if the name was not dependent
- and has already been resolved; there is no need to
- build the SCOPE_REF. For example;
-
- struct X { void f(); };
- template <typename T> void f(T* t) { t->X::f(); }
-
- Even though "t" is dependent, "X::f" is not and has
- been resolved to a BASELINK; there is no need to
- include scope information. */
-
- /* But we do need to remember that there was an explicit
- scope for virtual function calls. */
- if (parser->scope)
- idk = CP_ID_KIND_QUALIFIED;
-
- if (name != error_mark_node
- && !BASELINK_P (name)
- && parser->scope)
- {
- name = build_nt (SCOPE_REF, parser->scope, name);
- parser->scope = NULL_TREE;
- parser->qualifying_scope = NULL_TREE;
- parser->object_scope = NULL_TREE;
- }
- postfix_expression
- = finish_class_member_access_expr (postfix_expression, name);
- }
- /* Otherwise, try the pseudo-destructor-name production. */
- else
- {
- tree s = NULL_TREE;
- tree type;
-
- /* Parse the pseudo-destructor-name. */
- cp_parser_pseudo_destructor_name (parser, &s, &type);
- /* Form the call. */
- postfix_expression
- = finish_pseudo_destructor_expr (postfix_expression,
- s, TREE_TYPE (type));
- }
+ /* Consume the `.' or `->' operator. */
+ cp_lexer_consume_token (parser->lexer);
- /* We no longer need to look up names in the scope of the
- object on the left-hand side of the `.' or `->'
- operator. */
- parser->context->object_type = NULL_TREE;
- /* These operators may not appear in constant-expressions. */
- if (parser->integral_constant_expression_p
- /* The "->" operator is allowed in the implementation
- of "offsetof". The "." operator may appear in the
- name of the member. */
- && !parser->in_offsetof_p)
- {
- if (!parser->allow_non_integral_constant_expression_p)
- postfix_expression
- = (cp_parser_non_integral_constant_expression
- (token_type == CPP_DEREF ? "'->'" : "`.'"));
- parser->non_integral_constant_expression_p = true;
- }
- }
+ postfix_expression
+ = cp_parser_postfix_dot_deref_expression (parser, token->type,
+ postfix_expression,
+ false, &idk);
break;
case CPP_PLUS_PLUS:
/* Consume the `++' token. */
cp_lexer_consume_token (parser->lexer);
/* Generate a representation for the complete expression. */
- postfix_expression
- = finish_increment_expr (postfix_expression,
+ postfix_expression
+ = finish_increment_expr (postfix_expression,
POSTINCREMENT_EXPR);
/* Increments may not appear in constant-expressions. */
- if (parser->integral_constant_expression_p)
- {
- if (!parser->allow_non_integral_constant_expression_p)
- postfix_expression
- = cp_parser_non_integral_constant_expression ("an increment");
- parser->non_integral_constant_expression_p = true;
- }
+ if (cp_parser_non_integral_constant_expression (parser,
+ "an increment"))
+ postfix_expression = error_mark_node;
idk = CP_ID_KIND_NONE;
break;
/* Consume the `--' token. */
cp_lexer_consume_token (parser->lexer);
/* Generate a representation for the complete expression. */
- postfix_expression
- = finish_increment_expr (postfix_expression,
+ postfix_expression
+ = finish_increment_expr (postfix_expression,
POSTDECREMENT_EXPR);
/* Decrements may not appear in constant-expressions. */
- if (parser->integral_constant_expression_p)
- {
- if (!parser->allow_non_integral_constant_expression_p)
- postfix_expression
- = cp_parser_non_integral_constant_expression ("a decrement");
- parser->non_integral_constant_expression_p = true;
- }
+ if (cp_parser_non_integral_constant_expression (parser,
+ "a decrement"))
+ postfix_expression = error_mark_node;
idk = CP_ID_KIND_NONE;
break;
return error_mark_node;
}
+/* A subroutine of cp_parser_postfix_expression that also gets hijacked
+ by cp_parser_builtin_offsetof. We're looking for
+
+ postfix-expression [ expression ]
+
+ FOR_OFFSETOF is set if we're being called in that context, which
+ changes how we deal with integer constant expressions. */
+
+static tree
+cp_parser_postfix_open_square_expression (cp_parser *parser,
+ tree postfix_expression,
+ bool for_offsetof)
+{
+ tree index;
+
+ /* Consume the `[' token. */
+ cp_lexer_consume_token (parser->lexer);
+
+ /* Parse the index expression. */
+ /* ??? For offsetof, there is a question of what to allow here. If
+ offsetof is not being used in an integral constant expression context,
+ then we *could* get the right answer by computing the value at runtime.
+ If we are in an integral constant expression context, then we might
+ could accept any constant expression; hard to say without analysis.
+ Rather than open the barn door too wide right away, allow only integer
+ constant expresions here. */
+ if (for_offsetof)
+ index = cp_parser_constant_expression (parser, false, NULL);
+ else
+ index = cp_parser_expression (parser);
+
+ /* Look for the closing `]'. */
+ cp_parser_require (parser, CPP_CLOSE_SQUARE, "`]'");
+
+ /* Build the ARRAY_REF. */
+ postfix_expression = grok_array_decl (postfix_expression, index);
+
+ /* When not doing offsetof, array references are not permitted in
+ constant-expressions. */
+ if (!for_offsetof
+ && (cp_parser_non_integral_constant_expression
+ (parser, "an array reference")))
+ postfix_expression = error_mark_node;
+
+ return postfix_expression;
+}
+
+/* A subroutine of cp_parser_postfix_expression that also gets hijacked
+ by cp_parser_builtin_offsetof. We're looking for
+
+ postfix-expression . template [opt] id-expression
+ postfix-expression . pseudo-destructor-name
+ postfix-expression -> template [opt] id-expression
+ postfix-expression -> pseudo-destructor-name
+
+ FOR_OFFSETOF is set if we're being called in that context. That sorta
+ limits what of the above we'll actually accept, but nevermind.
+ TOKEN_TYPE is the "." or "->" token, which will already have been
+ removed from the stream. */
+
+static tree
+cp_parser_postfix_dot_deref_expression (cp_parser *parser,
+ enum cpp_ttype token_type,
+ tree postfix_expression,
+ bool for_offsetof, cp_id_kind *idk)
+{
+ tree name;
+ bool dependent_p;
+ bool template_p;
+ tree scope = NULL_TREE;
+
+ /* If this is a `->' operator, dereference the pointer. */
+ if (token_type == CPP_DEREF)
+ postfix_expression = build_x_arrow (postfix_expression);
+ /* Check to see whether or not the expression is type-dependent. */
+ dependent_p = type_dependent_expression_p (postfix_expression);
+ /* The identifier following the `->' or `.' is not qualified. */
+ parser->scope = NULL_TREE;
+ parser->qualifying_scope = NULL_TREE;
+ parser->object_scope = NULL_TREE;
+ *idk = CP_ID_KIND_NONE;
+ /* Enter the scope corresponding to the type of the object
+ given by the POSTFIX_EXPRESSION. */
+ if (!dependent_p && TREE_TYPE (postfix_expression) != NULL_TREE)
+ {
+ scope = TREE_TYPE (postfix_expression);
+ /* According to the standard, no expression should ever have
+ reference type. Unfortunately, we do not currently match
+ the standard in this respect in that our internal representation
+ of an expression may have reference type even when the standard
+ says it does not. Therefore, we have to manually obtain the
+ underlying type here. */
+ scope = non_reference (scope);
+ /* The type of the POSTFIX_EXPRESSION must be complete. */
+ scope = complete_type_or_else (scope, NULL_TREE);
+ /* Let the name lookup machinery know that we are processing a
+ class member access expression. */
+ parser->context->object_type = scope;
+ /* If something went wrong, we want to be able to discern that case,
+ as opposed to the case where there was no SCOPE due to the type
+ of expression being dependent. */
+ if (!scope)
+ scope = error_mark_node;
+ /* If the SCOPE was erroneous, make the various semantic analysis
+ functions exit quickly -- and without issuing additional error
+ messages. */
+ if (scope == error_mark_node)
+ postfix_expression = error_mark_node;
+ }
+
+ /* If the SCOPE is not a scalar type, we are looking at an
+ ordinary class member access expression, rather than a
+ pseudo-destructor-name. */
+ if (!scope || !SCALAR_TYPE_P (scope))
+ {
+ template_p = cp_parser_optional_template_keyword (parser);
+ /* Parse the id-expression. */
+ name = cp_parser_id_expression (parser, template_p,
+ /*check_dependency_p=*/true,
+ /*template_p=*/NULL,
+ /*declarator_p=*/false);
+ /* In general, build a SCOPE_REF if the member name is qualified.
+ However, if the name was not dependent and has already been
+ resolved; there is no need to build the SCOPE_REF. For example;
+
+ struct X { void f(); };
+ template <typename T> void f(T* t) { t->X::f(); }
+
+ Even though "t" is dependent, "X::f" is not and has been resolved
+ to a BASELINK; there is no need to include scope information. */
+
+ /* But we do need to remember that there was an explicit scope for
+ virtual function calls. */
+ if (parser->scope)
+ *idk = CP_ID_KIND_QUALIFIED;
+
+ if (name != error_mark_node && !BASELINK_P (name) && parser->scope)
+ {
+ name = build_nt (SCOPE_REF, parser->scope, name);
+ parser->scope = NULL_TREE;
+ parser->qualifying_scope = NULL_TREE;
+ parser->object_scope = NULL_TREE;
+ }
+ if (scope && name && BASELINK_P (name))
+ adjust_result_of_qualified_name_lookup
+ (name, BINFO_TYPE (BASELINK_BINFO (name)), scope);
+ postfix_expression
+ = finish_class_member_access_expr (postfix_expression, name);
+ }
+ /* Otherwise, try the pseudo-destructor-name production. */
+ else
+ {
+ tree s = NULL_TREE;
+ tree type;
+
+ /* Parse the pseudo-destructor-name. */
+ cp_parser_pseudo_destructor_name (parser, &s, &type);
+ /* Form the call. */
+ postfix_expression
+ = finish_pseudo_destructor_expr (postfix_expression,
+ s, TREE_TYPE (type));
+ }
+
+ /* We no longer need to look up names in the scope of the object on
+ the left-hand side of the `.' or `->' operator. */
+ parser->context->object_type = NULL_TREE;
+
+ /* Outside of offsetof, these operators may not appear in
+ constant-expressions. */
+ if (!for_offsetof
+ && (cp_parser_non_integral_constant_expression
+ (parser, token_type == CPP_DEREF ? "'->'" : "`.'")))
+ postfix_expression = error_mark_node;
+
+ return postfix_expression;
+}
+
/* Parse a parenthesized expression-list.
expression-list:
constant. */
static tree
-cp_parser_parenthesized_expression_list (cp_parser* parser,
+cp_parser_parenthesized_expression_list (cp_parser* parser,
bool is_attribute_list,
bool *non_constant_p)
{
if (!cp_parser_require (parser, CPP_OPEN_PAREN, "`('"))
return error_mark_node;
-
+
/* Consume expressions until there are no more. */
if (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_PAREN))
while (true)
{
tree expr;
-
+
/* At the beginning of attribute lists, check to see if the
next token is an identifier. */
if (is_attribute_list
&& cp_lexer_peek_token (parser->lexer)->type == CPP_NAME)
{
cp_token *token;
-
+
/* Consume the identifier. */
token = cp_lexer_consume_token (parser->lexer);
/* Save the identifier. */
if (non_constant_p)
{
bool expr_non_constant_p;
- expr = (cp_parser_constant_expression
+ expr = (cp_parser_constant_expression
(parser, /*allow_non_constant_p=*/true,
&expr_non_constant_p));
if (expr_non_constant_p)
/* After the first item, attribute lists look the same as
expression lists. */
is_attribute_list = false;
-
+
get_comma:;
/* If the next token isn't a `,', then we are done. */
if (cp_lexer_next_token_is_not (parser->lexer, CPP_COMMA))
/* Otherwise, consume the `,' and keep going. */
cp_lexer_consume_token (parser->lexer);
}
-
+
if (!cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'"))
{
int ending;
-
+
skip_comma:;
/* We try and resync to an unnested comma, as that will give the
user better diagnostics. */
- ending = cp_parser_skip_to_closing_parenthesis (parser,
- /*recovering=*/true,
+ ending = cp_parser_skip_to_closing_parenthesis (parser,
+ /*recovering=*/true,
/*or_comma=*/true,
/*consume_paren=*/true);
if (ending < 0)
expression_list = nreverse (expression_list);
if (identifier)
expression_list = tree_cons (NULL_TREE, identifier, expression_list);
-
+
return expression_list;
}
If either of the first two productions is used, sets *SCOPE to the
TYPE specified before the final `::'. Otherwise, *SCOPE is set to
NULL_TREE. *TYPE is set to the TYPE_DECL for the final type-name,
- or ERROR_MARK_NODE if no type-name is present. */
+ or ERROR_MARK_NODE if the parse fails. */
static void
-cp_parser_pseudo_destructor_name (cp_parser* parser,
- tree* scope,
+cp_parser_pseudo_destructor_name (cp_parser* parser,
+ tree* scope,
tree* type)
{
bool nested_name_specifier_p;
/* Look for the optional `::' operator. */
cp_parser_global_scope_opt (parser, /*current_scope_valid_p=*/true);
/* Look for the optional nested-name-specifier. */
- nested_name_specifier_p
+ nested_name_specifier_p
= (cp_parser_nested_name_specifier_opt (parser,
/*typename_keyword_p=*/false,
/*check_dependency_p=*/true,
/*type_p=*/false,
- /*is_declaration=*/true)
+ /*is_declaration=*/true)
!= NULL_TREE);
/* Now, if we saw a nested-name-specifier, we might be doing the
second production. */
- if (nested_name_specifier_p
+ if (nested_name_specifier_p
&& cp_lexer_next_token_is_keyword (parser->lexer, RID_TEMPLATE))
{
/* Consume the `template' keyword. */
cp_lexer_consume_token (parser->lexer);
/* Parse the template-id. */
- cp_parser_template_id (parser,
+ cp_parser_template_id (parser,
/*template_keyword_p=*/true,
/*check_dependency_p=*/false,
/*is_declaration=*/true);
{
/* Look for the type-name. */
*scope = TREE_TYPE (cp_parser_type_name (parser));
+
+ /* If we didn't get an aggregate type, or we don't have ::~,
+ then something has gone wrong. Since the only caller of this
+ function is looking for something after `.' or `->' after a
+ scalar type, most likely the program is trying to get a
+ member of a non-aggregate type. */
+ if (*scope == error_mark_node
+ || cp_lexer_next_token_is_not (parser->lexer, CPP_SCOPE)
+ || cp_lexer_peek_nth_token (parser->lexer, 2)->type != CPP_COMPL)
+ {
+ cp_parser_error (parser, "request for member of non-aggregate type");
+ *type = error_mark_node;
+ return;
+ }
+
/* Look for the `::' token. */
cp_parser_require (parser, CPP_SCOPE, "`::'");
}
{
tree operand;
enum tree_code op;
-
+
op = keyword == RID_ALIGNOF ? ALIGNOF_EXPR : SIZEOF_EXPR;
/* Consume the token. */
cp_lexer_consume_token (parser->lexer);
case RID_DELETE:
return cp_parser_delete_expression (parser);
-
+
case RID_EXTENSION:
{
/* The saved value of the PEDANTIC flag. */
/* Consume the operator token. */
token = cp_lexer_consume_token (parser->lexer);
/* Parse the cast-expression. */
- cast_expression
+ cast_expression
= cp_parser_cast_expression (parser, unary_operator == ADDR_EXPR);
/* Now, build an appropriate representation. */
switch (unary_operator)
break;
case ADDR_EXPR:
- /* The "&" operator is allowed in the implementation of
- "offsetof". */
- if (!parser->in_offsetof_p)
- non_constant_p = "`&'";
+ non_constant_p = "`&'";
/* Fall through. */
case BIT_NOT_EXPR:
expression = build_x_unary_op (unary_operator, cast_expression);
abort ();
}
- if (non_constant_p && parser->integral_constant_expression_p)
- {
- if (!parser->allow_non_integral_constant_expression_p)
- return cp_parser_non_integral_constant_expression (non_constant_p);
- parser->non_integral_constant_expression_p = true;
- }
+ if (non_constant_p
+ && cp_parser_non_integral_constant_expression (parser,
+ non_constant_p))
+ expression = error_mark_node;
return expression;
}
case CPP_NOT:
return TRUTH_NOT_EXPR;
-
+
case CPP_COMPL:
return BIT_NOT_EXPR;
tree placement;
tree type;
tree initializer;
+ tree nelts;
/* Look for the optional `::' operator. */
- global_scope_p
+ global_scope_p
= (cp_parser_global_scope_opt (parser,
/*current_scope_valid_p=*/false)
!= NULL_TREE);
type = cp_parser_type_id (parser);
/* Look for the closing `)'. */
cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
+ /* There should not be a direct-new-declarator in this production,
+ but GCC used to allowed this, so we check and emit a sensible error
+ message for this case. */
+ if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_SQUARE))
+ {
+ error ("array bound forbidden after parenthesized type-id");
+ inform ("try removing the parentheses around the type-id");
+ cp_parser_direct_new_declarator (parser);
+ }
+ nelts = integer_one_node;
}
/* Otherwise, there must be a new-type-id. */
else
- type = cp_parser_new_type_id (parser);
+ type = cp_parser_new_type_id (parser, &nelts);
/* If the next token is a `(', then we have a new-initializer. */
if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN))
else
initializer = NULL_TREE;
+ /* A new-expression may not appear in an integral constant
+ expression. */
+ if (cp_parser_non_integral_constant_expression (parser, "`new'"))
+ return error_mark_node;
+
/* Create a representation of the new-expression. */
- return build_new (placement, type, initializer, global_scope_p);
+ return build_new (placement, type, nelts, initializer, global_scope_p);
}
/* Parse a new-placement.
tree expression_list;
/* Parse the expression-list. */
- expression_list = (cp_parser_parenthesized_expression_list
+ expression_list = (cp_parser_parenthesized_expression_list
(parser, false, /*non_constant_p=*/NULL));
return expression_list;
new-type-id:
type-specifier-seq new-declarator [opt]
- Returns a TREE_LIST whose TREE_PURPOSE is the type-specifier-seq,
- and whose TREE_VALUE is the new-declarator. */
+ Returns the TYPE allocated. If the new-type-id indicates an array
+ type, *NELTS is set to the number of elements in the last array
+ bound; the TYPE will not include the last array bound. */
static tree
-cp_parser_new_type_id (cp_parser* parser)
+cp_parser_new_type_id (cp_parser* parser, tree *nelts)
{
- tree type_specifier_seq;
- tree declarator;
+ cp_decl_specifier_seq type_specifier_seq;
+ cp_declarator *new_declarator;
+ cp_declarator *declarator;
+ cp_declarator *outer_declarator;
const char *saved_message;
+ tree type;
/* The type-specifier sequence must not contain type definitions.
(It cannot contain declarations of new types either, but if they
parser->type_definition_forbidden_message
= "types may not be defined in a new-type-id";
/* Parse the type-specifier-seq. */
- type_specifier_seq = cp_parser_type_specifier_seq (parser);
+ cp_parser_type_specifier_seq (parser, &type_specifier_seq);
/* Restore the old message. */
parser->type_definition_forbidden_message = saved_message;
/* Parse the new-declarator. */
- declarator = cp_parser_new_declarator_opt (parser);
+ new_declarator = cp_parser_new_declarator_opt (parser);
- return build_tree_list (type_specifier_seq, declarator);
+ /* Determine the number of elements in the last array dimension, if
+ any. */
+ *nelts = NULL_TREE;
+ /* Skip down to the last array dimension. */
+ declarator = new_declarator;
+ outer_declarator = NULL;
+ while (declarator && (declarator->kind == cdk_pointer
+ || declarator->kind == cdk_ptrmem))
+ {
+ outer_declarator = declarator;
+ declarator = declarator->declarator;
+ }
+ while (declarator
+ && declarator->kind == cdk_array
+ && declarator->declarator
+ && declarator->declarator->kind == cdk_array)
+ {
+ outer_declarator = declarator;
+ declarator = declarator->declarator;
+ }
+
+ if (declarator && declarator->kind == cdk_array)
+ {
+ *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
+ new_declarator = NULL;
+ }
+
+ type = groktypename (&type_specifier_seq, new_declarator);
+ if (TREE_CODE (type) == ARRAY_TYPE && *nelts == NULL_TREE)
+ {
+ *nelts = array_type_nelts_top (type);
+ type = TREE_TYPE (type);
+ }
+ return type;
}
/* Parse an (optional) new-declarator.
ptr-operator new-declarator [opt]
direct-new-declarator
- Returns a representation of the declarator. See
- cp_parser_declarator for the representations used. */
+ Returns the declarator. */
-static tree
+static cp_declarator *
cp_parser_new_declarator_opt (cp_parser* parser)
{
enum tree_code code;
tree type;
- tree cv_qualifier_seq;
+ cp_cv_quals cv_quals;
/* We don't know if there's a ptr-operator next, or not. */
cp_parser_parse_tentatively (parser);
/* Look for a ptr-operator. */
- code = cp_parser_ptr_operator (parser, &type, &cv_qualifier_seq);
+ code = cp_parser_ptr_operator (parser, &type, &cv_quals);
/* If that worked, look for more new-declarators. */
if (cp_parser_parse_definitely (parser))
{
- tree declarator;
+ cp_declarator *declarator;
/* Parse another optional declarator. */
declarator = cp_parser_new_declarator_opt (parser);
/* Create the representation of the declarator. */
- if (code == INDIRECT_REF)
- declarator = make_pointer_declarator (cv_qualifier_seq,
- declarator);
+ if (type)
+ declarator = make_ptrmem_declarator (cv_quals, type, declarator);
+ else if (code == INDIRECT_REF)
+ declarator = make_pointer_declarator (cv_quals, declarator);
else
- declarator = make_reference_declarator (cv_qualifier_seq,
- declarator);
-
- /* Handle the pointer-to-member case. */
- if (type)
- declarator = build_nt (SCOPE_REF, type, declarator);
+ declarator = make_reference_declarator (cv_quals, declarator);
return declarator;
}
if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_SQUARE))
return cp_parser_direct_new_declarator (parser);
- return NULL_TREE;
+ return NULL;
}
/* Parse a direct-new-declarator.
direct-new-declarator:
[ expression ]
- direct-new-declarator [constant-expression]
+ direct-new-declarator [constant-expression]
- Returns an ARRAY_REF, following the same conventions as are
- documented for cp_parser_direct_declarator. */
+ */
-static tree
+static cp_declarator *
cp_parser_direct_new_declarator (cp_parser* parser)
{
- tree declarator = NULL_TREE;
+ cp_declarator *declarator = NULL;
while (true)
{
enumeration type. */
if (!processing_template_decl)
{
- expression
+ expression
= build_expr_type_conversion (WANT_INT | WANT_ENUM,
expression,
/*complain=*/true);
}
/* But all the other expressions must be. */
else
- expression
- = cp_parser_constant_expression (parser,
+ expression
+ = cp_parser_constant_expression (parser,
/*allow_non_constant=*/false,
NULL);
/* Look for the closing `]'. */
cp_parser_require (parser, CPP_CLOSE_SQUARE, "`]'");
/* Add this bound to the declarator. */
- declarator = build_nt (ARRAY_REF, declarator, expression);
+ declarator = make_array_declarator (declarator, expression);
/* If the next token is not a `[', then there are no more
bounds. */
{
tree expression_list;
- expression_list = (cp_parser_parenthesized_expression_list
+ expression_list = (cp_parser_parenthesized_expression_list
(parser, false, /*non_constant_p=*/NULL));
if (!expression_list)
expression_list = void_zero_node;
/* Parse the cast-expression. */
expression = cp_parser_simple_cast_expression (parser);
+ /* A delete-expression may not appear in an integral constant
+ expression. */
+ if (cp_parser_non_integral_constant_expression (parser, "`delete'"))
+ return error_mark_node;
+
return delete_sanity (expression, NULL_TREE, array_p, global_scope_p);
}
the type-id, and it happens to be a class-specifier, then we
will commit to the parse at that point, because we cannot
undo the action that is done when creating a new class. So,
- then we cannot back up and do a postfix-expression.
+ then we cannot back up and do a postfix-expression.
Therefore, we scan ahead to the closing `)', and check to see
if the token after the `)' is a `{'. If so, we are not
- looking at a cast-expression.
+ looking at a cast-expression.
Save tokens so that we can put them back. */
cp_lexer_save_tokens (parser->lexer);
/* Skip tokens until the next token is a closing parenthesis.
If we find the closing `)', and the next token is a `{', then
we are looking at a compound-literal. */
- compound_literal_p
+ compound_literal_p
= (cp_parser_skip_to_closing_parenthesis (parser, false, false,
/*consume_paren=*/true)
&& cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE));
if (cp_parser_parse_definitely (parser))
{
/* Warn about old-style casts, if so requested. */
- if (warn_old_style_cast
- && !in_system_header
- && !VOID_TYPE_P (type)
+ if (warn_old_style_cast
+ && !in_system_header
+ && !VOID_TYPE_P (type)
&& current_lang_name != lang_name_c)
warning ("use of old-style cast");
can be used in constant-expressions. */
if (parser->integral_constant_expression_p
&& !dependent_type_p (type)
- && !INTEGRAL_OR_ENUMERATION_TYPE_P (type))
- {
- if (!parser->allow_non_integral_constant_expression_p)
- return (cp_parser_non_integral_constant_expression
- ("a casts to a type other than an integral or "
- "enumeration type"));
- parser->non_integral_constant_expression_p = true;
- }
+ && !INTEGRAL_OR_ENUMERATION_TYPE_P (type)
+ && (cp_parser_non_integral_constant_expression
+ (parser,
+ "a cast to a type other than an integral or "
+ "enumeration type")))
+ return error_mark_node;
+
/* Perform the cast. */
expr = build_c_cast (type, expr);
return expr;
{ CPP_EOF, ERROR_MARK }
};
- return cp_parser_binary_expression (parser, map,
+ return cp_parser_binary_expression (parser, map,
cp_parser_simple_cast_expression);
}
/* Parse a multiplicative-expression.
- mulitplicative-expression:
+ multiplicative-expression:
pm-expression
multiplicative-expression * pm-expression
multiplicative-expression / pm-expression
This routine is used by cp_parser_assignment_expression.
? expression : assignment-expression
-
+
GNU Extensions:
-
+
? : assignment-expression */
static tree
else
/* Parse the expression. */
expr = cp_parser_expression (parser);
-
+
/* The next token should be a `:'. */
cp_parser_require (parser, CPP_COLON, "`:'");
/* Parse the assignment-expression. */
conditional-expression. */
if (cp_lexer_next_token_is (parser->lexer, CPP_QUERY))
return cp_parser_question_colon_clause (parser, expr);
- else
+ else
{
enum tree_code assignment_operator;
/* If it's an assignment-operator, we're using the second
production. */
- assignment_operator
+ assignment_operator
= cp_parser_assignment_operator_opt (parser);
if (assignment_operator != ERROR_MARK)
{
rhs = cp_parser_assignment_expression (parser);
/* An assignment may not appear in a
constant-expression. */
- if (parser->integral_constant_expression_p)
- {
- if (!parser->allow_non_integral_constant_expression_p)
- return cp_parser_non_integral_constant_expression ("an assignment");
- parser->non_integral_constant_expression_p = true;
- }
+ if (cp_parser_non_integral_constant_expression (parser,
+ "an assignment"))
+ return error_mark_node;
/* Build the assignment expression. */
- expr = build_x_modify_expr (expr,
- assignment_operator,
+ expr = build_x_modify_expr (expr,
+ assignment_operator,
rhs);
}
}
/* Parse an (optional) assignment-operator.
- assignment-operator: one of
- = *= /= %= += -= >>= <<= &= ^= |=
+ assignment-operator: one of
+ = *= /= %= += -= >>= <<= &= ^= |=
GNU Extension:
-
+
assignment-operator: one of
<?= >?=
op = MAX_EXPR;
break;
- default:
+ default:
/* Nothing else is an assignment operator. */
op = ERROR_MARK;
}
tree assignment_expression;
/* Parse the next assignment-expression. */
- assignment_expression
+ assignment_expression
= cp_parser_assignment_expression (parser);
/* If this is the first assignment-expression, we can just
save it away. */
/* Consume the `,'. */
cp_lexer_consume_token (parser->lexer);
/* A comma operator cannot appear in a constant-expression. */
- if (parser->integral_constant_expression_p)
- {
- if (!parser->allow_non_integral_constant_expression_p)
- expression
- = cp_parser_non_integral_constant_expression ("a comma operator");
- parser->non_integral_constant_expression_p = true;
- }
+ if (cp_parser_non_integral_constant_expression (parser,
+ "a comma operator"))
+ expression = error_mark_node;
}
return expression;
}
-/* Parse a constant-expression.
+/* Parse a constant-expression.
constant-expression:
- conditional-expression
+ conditional-expression
If ALLOW_NON_CONSTANT_P a non-constant expression is silently
accepted. If ALLOW_NON_CONSTANT_P is true and the expression is not
is false, NON_CONSTANT_P should be NULL. */
static tree
-cp_parser_constant_expression (cp_parser* parser,
+cp_parser_constant_expression (cp_parser* parser,
bool allow_non_constant_p,
bool *non_constant_p)
{
/* Save the old settings. */
saved_integral_constant_expression_p = parser->integral_constant_expression_p;
- saved_allow_non_integral_constant_expression_p
+ saved_allow_non_integral_constant_expression_p
= parser->allow_non_integral_constant_expression_p;
saved_non_integral_constant_expression_p = parser->non_integral_constant_expression_p;
/* We are now parsing a constant-expression. */
expression = cp_parser_assignment_expression (parser);
/* Restore the old settings. */
parser->integral_constant_expression_p = saved_integral_constant_expression_p;
- parser->allow_non_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;
return expression;
}
+/* Parse __builtin_offsetof.
+
+ offsetof-expression:
+ "__builtin_offsetof" "(" type-id "," offsetof-member-designator ")"
+
+ offsetof-member-designator:
+ id-expression
+ | offsetof-member-designator "." id-expression
+ | offsetof-member-designator "[" expression "]"
+*/
+
+static tree
+cp_parser_builtin_offsetof (cp_parser *parser)
+{
+ int save_ice_p, save_non_ice_p;
+ tree type, expr;
+ cp_id_kind dummy;
+
+ /* We're about to accept non-integral-constant things, but will
+ definitely yield an integral constant expression. Save and
+ restore these values around our local parsing. */
+ save_ice_p = parser->integral_constant_expression_p;
+ save_non_ice_p = parser->non_integral_constant_expression_p;
+
+ /* Consume the "__builtin_offsetof" token. */
+ cp_lexer_consume_token (parser->lexer);
+ /* Consume the opening `('. */
+ cp_parser_require (parser, CPP_OPEN_PAREN, "`('");
+ /* Parse the type-id. */
+ type = cp_parser_type_id (parser);
+ /* Look for the `,'. */
+ cp_parser_require (parser, CPP_COMMA, "`,'");
+
+ /* Build the (type *)null that begins the traditional offsetof macro. */
+ expr = build_static_cast (build_pointer_type (type), null_pointer_node);
+
+ /* Parse the offsetof-member-designator. We begin as if we saw "expr->". */
+ expr = cp_parser_postfix_dot_deref_expression (parser, CPP_DEREF, expr,
+ true, &dummy);
+ while (true)
+ {
+ cp_token *token = cp_lexer_peek_token (parser->lexer);
+ switch (token->type)
+ {
+ case CPP_OPEN_SQUARE:
+ /* offsetof-member-designator "[" expression "]" */
+ expr = cp_parser_postfix_open_square_expression (parser, expr, true);
+ break;
+
+ case CPP_DOT:
+ /* offsetof-member-designator "." identifier */
+ cp_lexer_consume_token (parser->lexer);
+ expr = cp_parser_postfix_dot_deref_expression (parser, CPP_DOT, expr,
+ true, &dummy);
+ break;
+
+ case CPP_CLOSE_PAREN:
+ /* Consume the ")" token. */
+ cp_lexer_consume_token (parser->lexer);
+ goto success;
+
+ default:
+ /* Error. We know the following require will fail, but
+ that gives the proper error message. */
+ cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
+ cp_parser_skip_to_closing_parenthesis (parser, true, false, true);
+ expr = error_mark_node;
+ goto failure;
+ }
+ }
+
+ success:
+ /* We've finished the parsing, now finish with the semantics. At present
+ we're just mirroring the traditional macro implementation. Better
+ would be to do the lowering of the ADDR_EXPR to flat pointer arithmetic
+ here rather than in build_x_unary_op. */
+ expr = build_reinterpret_cast (build_reference_type (char_type_node), expr);
+ expr = build_x_unary_op (ADDR_EXPR, expr);
+ expr = build_reinterpret_cast (size_type_node, expr);
+
+ failure:
+ parser->integral_constant_expression_p = save_ice_p;
+ parser->non_integral_constant_expression_p = save_non_ice_p;
+
+ return expr;
+}
+
/* Statements [gram.stmt.stmt] */
-/* Parse a statement.
+/* Parse a statement.
statement:
labeled-statement
try-block */
static void
-cp_parser_statement (cp_parser* parser, bool in_statement_expr_p)
+cp_parser_statement (cp_parser* parser, tree in_statement_expr)
{
tree statement;
cp_token *token;
- int statement_line_number;
+ location_t statement_location;
/* There is no statement yet. */
statement = NULL_TREE;
/* Peek at the next token. */
token = cp_lexer_peek_token (parser->lexer);
- /* Remember the line number of the first token in the statement. */
- statement_line_number = token->location.line;
+ /* Remember the location of the first token in the statement. */
+ statement_location = token->location;
/* If this is a keyword, then that will often determine what kind of
statement we have. */
if (token->type == CPP_KEYWORD)
case RID_CASE:
case RID_DEFAULT:
statement = cp_parser_labeled_statement (parser,
- in_statement_expr_p);
+ in_statement_expr);
break;
case RID_IF:
labeled-statement. */
token = cp_lexer_peek_nth_token (parser->lexer, 2);
if (token->type == CPP_COLON)
- statement = cp_parser_labeled_statement (parser, in_statement_expr_p);
+ statement = cp_parser_labeled_statement (parser, in_statement_expr);
}
/* Anything that starts with a `{' must be a compound-statement. */
else if (token->type == CPP_OPEN_BRACE)
- statement = cp_parser_compound_statement (parser, false);
+ statement = cp_parser_compound_statement (parser, NULL, false);
/* Everything else must be a declaration-statement or an
- expression-statement. Try for the declaration-statement
+ expression-statement. Try for the declaration-statement
first, unless we are looking at a `;', in which case we know that
we have an expression-statement. */
if (!statement)
return;
}
/* Look for an expression-statement instead. */
- statement = cp_parser_expression_statement (parser, in_statement_expr_p);
+ statement = cp_parser_expression_statement (parser, in_statement_expr);
}
/* Set the line number for the statement. */
if (statement && STATEMENT_CODE_P (TREE_CODE (statement)))
- STMT_LINENO (statement) = statement_line_number;
+ SET_EXPR_LOCATION (statement, statement_location);
}
/* Parse a labeled-statement.
labeled-statement:
identifier : statement
case constant-expression : statement
- default : statement
+ default : statement
+
+ GNU Extension:
+
+ labeled-statement:
+ case constant-expression ... constant-expression : statement
- Returns the new CASE_LABEL, for a `case' or `default' label. For
- an ordinary label, returns a LABEL_STMT. */
+ Returns the new CASE_LABEL_EXPR, for a `case' or `default' label.
+ For an ordinary label, returns a LABEL_EXPR. */
static tree
-cp_parser_labeled_statement (cp_parser* parser, bool in_statement_expr_p)
+cp_parser_labeled_statement (cp_parser* parser, tree in_statement_expr)
{
cp_token *token;
tree statement = error_mark_node;
{
case RID_CASE:
{
- tree expr;
+ tree expr, expr_hi;
+ cp_token *ellipsis;
/* Consume the `case' token. */
cp_lexer_consume_token (parser->lexer);
/* Parse the constant-expression. */
- expr = cp_parser_constant_expression (parser,
+ expr = cp_parser_constant_expression (parser,
/*allow_non_constant_p=*/false,
NULL);
+
+ ellipsis = cp_lexer_peek_token (parser->lexer);
+ if (ellipsis->type == CPP_ELLIPSIS)
+ {
+ /* Consume the `...' token. */
+ cp_lexer_consume_token (parser->lexer);
+ expr_hi =
+ cp_parser_constant_expression (parser,
+ /*allow_non_constant_p=*/false,
+ NULL);
+ /* We don't need to emit warnings here, as the common code
+ will do this for us. */
+ }
+ else
+ expr_hi = NULL_TREE;
+
if (!parser->in_switch_statement_p)
error ("case label `%E' not within a switch statement", expr);
else
- statement = finish_case_label (expr, NULL_TREE);
+ statement = finish_case_label (expr, expr_hi);
}
break;
/* Require the `:' token. */
cp_parser_require (parser, CPP_COLON, "`:'");
/* Parse the labeled statement. */
- cp_parser_statement (parser, in_statement_expr_p);
+ cp_parser_statement (parser, in_statement_expr);
/* Return the label, in the case of a `case' or `default' label. */
return statement;
expression statement. */
static tree
-cp_parser_expression_statement (cp_parser* parser, bool in_statement_expr_p)
+cp_parser_expression_statement (cp_parser* parser, tree in_statement_expr)
{
tree statement = NULL_TREE;
statement. */
if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON))
statement = cp_parser_expression (parser);
-
+
/* Consume the final `;'. */
cp_parser_consume_semicolon_at_end_of_statement (parser);
- if (in_statement_expr_p
+ 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);
+ statement = finish_stmt_expr_expr (statement, in_statement_expr);
}
else if (statement)
statement = finish_expr_stmt (statement);
else
finish_stmt ();
-
+
return statement;
}
compound-statement:
{ statement-seq [opt] }
-
- Returns a COMPOUND_STMT representing the statement. */
+
+ Returns a tree representing the statement. */
static tree
-cp_parser_compound_statement (cp_parser *parser, bool in_statement_expr_p)
+cp_parser_compound_statement (cp_parser *parser, tree in_statement_expr,
+ bool in_try)
{
tree compound_stmt;
if (!cp_parser_require (parser, CPP_OPEN_BRACE, "`{'"))
return error_mark_node;
/* Begin the compound-statement. */
- compound_stmt = begin_compound_stmt (/*has_no_scope=*/false);
+ compound_stmt = begin_compound_stmt (in_try ? BCS_TRY_BLOCK : 0);
/* Parse an (optional) statement-seq. */
- cp_parser_statement_seq_opt (parser, in_statement_expr_p);
+ cp_parser_statement_seq_opt (parser, in_statement_expr);
/* Finish the compound-statement. */
finish_compound_stmt (compound_stmt);
/* Consume the `}'. */
statement-seq [opt] statement */
static void
-cp_parser_statement_seq_opt (cp_parser* parser, bool in_statement_expr_p)
+cp_parser_statement_seq_opt (cp_parser* parser, tree in_statement_expr)
{
/* Scan statements until there aren't any more. */
while (true)
break;
/* Parse the statement. */
- cp_parser_statement (parser, in_statement_expr_p);
+ cp_parser_statement (parser, in_statement_expr);
}
}
selection-statement:
if ( condition ) statement
if ( condition ) statement else statement
- switch ( condition ) statement
+ switch ( condition ) statement
Returns the new IF_STMT or SWITCH_STMT. */
if (keyword == RID_IF)
{
- tree then_stmt;
-
/* Add the condition. */
finish_if_stmt_cond (condition, statement);
/* Parse the then-clause. */
- then_stmt = cp_parser_implicitly_scoped_statement (parser);
+ cp_parser_implicitly_scoped_statement (parser);
finish_then_clause (statement);
/* If the next token is `else', parse the else-clause. */
if (cp_lexer_next_token_is_keyword (parser->lexer,
RID_ELSE))
{
- tree else_stmt;
-
/* Consume the `else' keyword. */
cp_lexer_consume_token (parser->lexer);
+ begin_else_clause (statement);
/* Parse the else-clause. */
- else_stmt
- = cp_parser_implicitly_scoped_statement (parser);
+ cp_parser_implicitly_scoped_statement (parser);
finish_else_clause (statement);
}
/* Now we're all done with the if-statement. */
- finish_if_stmt ();
+ finish_if_stmt (statement);
}
else
{
- tree body;
bool in_switch_statement_p;
/* Add the condition. */
/* Parse the body of the switch-statement. */
in_switch_statement_p = parser->in_switch_statement_p;
parser->in_switch_statement_p = true;
- body = cp_parser_implicitly_scoped_statement (parser);
+ cp_parser_implicitly_scoped_statement (parser);
parser->in_switch_statement_p = in_switch_statement_p;
/* Now we're all done with the switch-statement. */
}
}
-/* Parse a condition.
+/* Parse a condition.
condition:
expression
- type-specifier-seq declarator = assignment-expression
+ type-specifier-seq declarator = assignment-expression
GNU Extension:
-
+
condition:
- type-specifier-seq declarator asm-specification [opt]
+ type-specifier-seq declarator asm-specification [opt]
attributes [opt] = assignment-expression
-
+
Returns the expression that should be tested. */
static tree
cp_parser_condition (cp_parser* parser)
{
- tree type_specifiers;
+ cp_decl_specifier_seq type_specifiers;
const char *saved_message;
/* Try the declaration first. */
parser->type_definition_forbidden_message
= "types may not be defined in conditions";
/* Parse the type-specifier-seq. */
- type_specifiers = cp_parser_type_specifier_seq (parser);
+ cp_parser_type_specifier_seq (parser, &type_specifiers);
/* Restore the saved message. */
parser->type_definition_forbidden_message = saved_message;
/* If all is well, we might be looking at a declaration. */
tree decl;
tree asm_specification;
tree attributes;
- tree declarator;
+ cp_declarator *declarator;
tree initializer = NULL_TREE;
-
+
/* Parse the declarator. */
declarator = cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED,
/*ctor_dtor_or_conv_p=*/NULL,
asm_specification = cp_parser_asm_specification_opt (parser);
/* If the next token is not an `=', then we might still be
looking at an expression. For example:
-
+
if (A(a).x)
-
+
looks like a decl-specifier-seq and a declarator -- but then
there is no `=', so this is an expression. */
cp_parser_require (parser, CPP_EQ, "`='");
if (cp_parser_parse_definitely (parser))
{
/* Create the declaration. */
- decl = start_decl (declarator, type_specifiers,
+ decl = start_decl (declarator, &type_specifiers,
/*initialized_p=*/true,
attributes, /*prefix_attributes=*/NULL_TREE);
/* Parse the assignment-expression. */
initializer = cp_parser_assignment_expression (parser);
-
+
/* Process the initializer. */
- cp_finish_decl (decl,
- initializer,
- asm_specification,
+ cp_finish_decl (decl,
+ initializer,
+ asm_specification,
LOOKUP_ONLYCONVERTING);
-
+
return convert_from_reference (decl);
}
}
return error_mark_node;
/* Remember whether or not we are already within an iteration
- statement. */
+ statement. */
in_iteration_statement_p = parser->in_iteration_statement_p;
/* See what kind of keyword it is. */
expression = cp_parser_expression (parser);
finish_for_expr (expression, statement);
/* Look for the `)'. */
- cp_parser_require (parser, CPP_CLOSE_PAREN, "`;'");
+ cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
/* Parse the body of the for-statement. */
parser->in_iteration_statement_p = true;
break ;
continue ;
return expression [opt] ;
- goto identifier ;
+ goto identifier ;
GNU extension:
jump-statement:
goto * expression ;
- Returns the new BREAK_STMT, CONTINUE_STMT, RETURN_STMT, or
- GOTO_STMT. */
+ Returns the new BREAK_STMT, CONTINUE_STMT, RETURN_EXPR, or GOTO_EXPR. */
static tree
cp_parser_jump_statement (cp_parser* parser)
{
tree expr;
- /* If the next token is a `;', then there is no
+ /* 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);
static void
cp_parser_declaration_statement (cp_parser* parser)
{
- /* Parse the block-declaration. */
+ void *p;
+
+ /* Get the high-water mark for the DECLARATOR_OBSTACK. */
+ p = obstack_alloc (&declarator_obstack, 0);
+
+ /* Parse the block-declaration. */
cp_parser_block_declaration (parser, /*statement_p=*/true);
+ /* Free any declarators allocated. */
+ obstack_free (&declarator_obstack, p);
+
/* Finish off the statement. */
finish_stmt ();
}
declarations appearing in the dependent statement are out of scope
after control passes that point. This function parses a statement,
but ensures that is in its own scope, even if it is not a
- compound-statement.
+ compound-statement.
Returns the new statement. */
if (cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_BRACE))
{
/* Create a compound-statement. */
- statement = begin_compound_stmt (/*has_no_scope=*/false);
+ statement = begin_compound_stmt (0);
/* Parse the dependent-statement. */
cp_parser_statement (parser, false);
/* Finish the dummy compound-statement. */
}
/* Otherwise, we simply parse the statement directly. */
else
- statement = cp_parser_compound_statement (parser, false);
+ statement = cp_parser_compound_statement (parser, NULL, false);
/* Return the statement. */
return statement;
static void
cp_parser_already_scoped_statement (cp_parser* parser)
{
- /* If the token is not a `{', then we must take special action. */
- if (cp_lexer_next_token_is_not(parser->lexer, CPP_OPEN_BRACE))
+ /* If the token is a `{', then we must take special action. */
+ if (cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_BRACE))
+ cp_parser_statement (parser, false);
+ else
{
- tree statement;
-
- /* Create a compound-statement. */
- statement = begin_compound_stmt (/*has_no_scope=*/true);
- /* Parse the dependent-statement. */
- cp_parser_statement (parser, false);
- /* Finish the dummy compound-statement. */
- finish_compound_stmt (statement);
+ /* Avoid calling cp_parser_compound_statement, so that we
+ don't create a new scope. Do everything else by hand. */
+ cp_parser_require (parser, CPP_OPEN_BRACE, "`{'");
+ cp_parser_statement_seq_opt (parser, false);
+ cp_parser_require (parser, CPP_CLOSE_BRACE, "`}'");
}
- /* Otherwise, we simply parse the statement directly. */
- else
- cp_parser_statement (parser, false);
}
/* Declarations [gram.dcl.dcl] */
|| token->type == CPP_EOF)
break;
- if (token->type == CPP_SEMICOLON)
+ if (token->type == CPP_SEMICOLON)
{
/* A declaration consisting of a single semicolon is
invalid. Allow it unless we're being pedantic. */
explicit-instantiation
explicit-specialization
linkage-specification
- namespace-definition
+ namespace-definition
GNU extension:
cp_token token1;
cp_token token2;
int saved_pedantic;
+ void *p;
+
+ /* Set this here since we can be called after
+ pushing the linkage specification. */
+ c_lex_string_translate = 1;
/* Check for the `__extension__' keyword. */
if (cp_parser_extension_opt (parser, &saved_pedantic))
/* Try to figure out what kind of declaration is present. */
token1 = *cp_lexer_peek_token (parser->lexer);
+
+ /* Don't translate the CPP_STRING in extern "C". */
+ if (token1.keyword == RID_EXTERN)
+ c_lex_string_translate = 0;
+
if (token1.type != CPP_EOF)
token2 = *cp_lexer_peek_nth_token (parser->lexer, 2);
+ c_lex_string_translate = 1;
+
+ /* Get the high-water mark for the DECLARATOR_OBSTACK. */
+ p = obstack_alloc (&declarator_obstack, 0);
+
/* If the next token is `extern' and the following token is a string
literal, then we have a linkage specification. */
if (token1.keyword == RID_EXTERN
else if (token1.keyword == RID_NAMESPACE
&& (/* A named namespace definition. */
(token2.type == CPP_NAME
- && (cp_lexer_peek_nth_token (parser->lexer, 3)->type
+ && (cp_lexer_peek_nth_token (parser->lexer, 3)->type
== CPP_OPEN_BRACE))
/* An unnamed namespace definition. */
|| token2.type == CPP_OPEN_BRACE))
else
/* Try to parse a block-declaration, or a function-definition. */
cp_parser_block_declaration (parser, /*statement_p=*/false);
+
+ /* Free any declarators allocated. */
+ obstack_free (&declarator_obstack, p);
}
-/* Parse a block-declaration.
+/* Parse a block-declaration.
block-declaration:
simple-declaration
asm-definition
namespace-alias-definition
using-declaration
- using-directive
+ using-directive
GNU Extension:
block-declaration:
- __extension__ block-declaration
+ __extension__ block-declaration
label-declaration
If STATEMENT_P is TRUE, then this block-declaration is occurring as
part of a declaration-statement. */
static void
-cp_parser_block_declaration (cp_parser *parser,
+cp_parser_block_declaration (cp_parser *parser,
bool statement_p)
{
cp_token *token1;
/* Parse a simple-declaration.
simple-declaration:
- decl-specifier-seq [opt] init-declarator-list [opt] ;
+ decl-specifier-seq [opt] init-declarator-list [opt] ;
init-declarator-list:
init-declarator
- init-declarator-list , init-declarator
+ init-declarator-list , init-declarator
If FUNCTION_DEFINITION_ALLOWED_P is TRUE, then we also recognize a
function-definition as a simple-declaration. */
static void
-cp_parser_simple_declaration (cp_parser* parser,
+cp_parser_simple_declaration (cp_parser* parser,
bool function_definition_allowed_p)
{
- tree decl_specifiers;
- tree attributes;
+ cp_decl_specifier_seq decl_specifiers;
int declares_class_or_enum;
bool saw_declarator;
/* Parse the decl-specifier-seq. We have to keep track of whether
or not the decl-specifier-seq declares a named class or
enumeration type, since that is the only case in which the
- init-declarator-list is allowed to be empty.
+ init-declarator-list is allowed to be empty.
[dcl.dcl]
omitted only when declaring a class or enumeration, that is when
the decl-specifier-seq contains either a class-specifier, an
elaborated-type-specifier, or an enum-specifier. */
- decl_specifiers
- = cp_parser_decl_specifier_seq (parser,
- CP_PARSER_FLAGS_OPTIONAL,
- &attributes,
- &declares_class_or_enum);
+ cp_parser_decl_specifier_seq (parser,
+ CP_PARSER_FLAGS_OPTIONAL,
+ &decl_specifiers,
+ &declares_class_or_enum);
/* 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)
+ if (!function_definition_allowed_p
+ && !decl_specifiers.any_specifiers_p)
{
cp_parser_error (parser, "expected declaration");
goto done;
T t;
where "T" should name a type -- but does not. */
- if (cp_parser_diagnose_invalid_type_name (parser))
+ if (cp_parser_parse_and_diagnose_invalid_type_name (parser))
{
/* If parsing tentatively, we should commit; we really are
looking at a declaration. */
/* Keep going until we hit the `;' at the end of the simple
declaration. */
saw_declarator = false;
- while (cp_lexer_next_token_is_not (parser->lexer,
+ while (cp_lexer_next_token_is_not (parser->lexer,
CPP_SEMICOLON))
{
cp_token *token;
saw_declarator = true;
/* Parse the init-declarator. */
- decl = cp_parser_init_declarator (parser, decl_specifiers, attributes,
+ decl = cp_parser_init_declarator (parser, &decl_specifiers,
function_definition_allowed_p,
/*member_p=*/false,
declares_class_or_enum,
cp_parser_error (parser, "expected `,' or `;'");
/* Skip tokens until we reach the end of the statement. */
cp_parser_skip_to_end_of_statement (parser);
+ /* If the next token is now a `;', consume it. */
+ if (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON))
+ cp_lexer_consume_token (parser->lexer);
goto done;
}
/* After the first time around, a function-definition is not
if (!saw_declarator)
{
if (cp_parser_declares_only_class_p (parser))
- shadow_tag (decl_specifiers);
+ shadow_tag (&decl_specifiers);
/* Perform any deferred access checks. */
perform_deferred_access_checks ();
}
type-specifier
function-specifier
friend
- typedef
+ typedef
GNU Extension:
- decl-specifier-seq:
- decl-specifier-seq [opt] attributes
-
- Returns a TREE_LIST, giving the decl-specifiers in the order they
- appear in the source code. The TREE_VALUE of each node is the
- decl-specifier. For a keyword (such as `auto' or `friend'), the
- TREE_VALUE is simply the corresponding TREE_IDENTIFIER. For the
- representation of a type-specifier, see cp_parser_type_specifier.
+ decl-specifier:
+ attributes
- If there are attributes, they will be stored in *ATTRIBUTES,
- represented as described above cp_parser_attributes.
+ Set *DECL_SPECS to a representation of the decl-specifier-seq.
If FRIEND_IS_NOT_CLASS_P is non-NULL, and the `friend' specifier
appears, and the entity that will be a friend is not going to be a
class, then *FRIEND_IS_NOT_CLASS_P will be set to TRUE. Note that
even if *FRIEND_IS_NOT_CLASS_P is FALSE, the entity to which
- friendship is granted might not be a class.
+ friendship is granted might not be a class.
*DECLARES_CLASS_OR_ENUM is set to the bitwise or of the following
flags:
*/
-static tree
-cp_parser_decl_specifier_seq (cp_parser* parser,
- cp_parser_flags flags,
- tree* attributes,
+static void
+cp_parser_decl_specifier_seq (cp_parser* parser,
+ cp_parser_flags flags,
+ cp_decl_specifier_seq *decl_specs,
int* declares_class_or_enum)
{
- tree decl_specs = NULL_TREE;
- bool friend_p = false;
bool constructor_possible_p = !parser->in_declarator_p;
-
+
+ /* Clear DECL_SPECS. */
+ clear_decl_specs (decl_specs);
+
/* Assume no class or enumeration type is declared. */
*declares_class_or_enum = 0;
- /* Assume there are no attributes. */
- *attributes = NULL_TREE;
-
/* Keep reading specifiers until there are no more to read. */
while (true)
{
- tree decl_spec = NULL_TREE;
bool constructor_p;
+ bool found_decl_spec;
cp_token *token;
/* Peek at the next token. */
if (token->keyword == RID_ATTRIBUTE)
{
/* Parse the attributes. */
- decl_spec = cp_parser_attributes_opt (parser);
- /* Add them to the list. */
- *attributes = chainon (*attributes, decl_spec);
+ decl_specs->attributes
+ = chainon (decl_specs->attributes,
+ cp_parser_attributes_opt (parser));
continue;
}
+ /* Assume we will find a decl-specifier keyword. */
+ found_decl_spec = true;
/* If the next token is an appropriate keyword, we can simply
add it to the list. */
switch (token->keyword)
{
- case RID_FRIEND:
/* decl-specifier:
friend */
- if (friend_p)
+ case RID_FRIEND:
+ if (decl_specs->specs[(int) ds_friend]++)
error ("duplicate `friend'");
- else
- friend_p = true;
- /* The representation of the specifier is simply the
- appropriate TREE_IDENTIFIER node. */
- decl_spec = token->value;
/* Consume the token. */
cp_lexer_consume_token (parser->lexer);
break;
case RID_INLINE:
case RID_VIRTUAL:
case RID_EXPLICIT:
- decl_spec = cp_parser_function_specifier_opt (parser);
+ cp_parser_function_specifier_opt (parser, decl_specs);
break;
-
+
/* decl-specifier:
typedef */
case RID_TYPEDEF:
- /* The representation of the specifier is simply the
- appropriate TREE_IDENTIFIER node. */
- decl_spec = token->value;
+ ++decl_specs->specs[(int) ds_typedef];
/* Consume the token. */
cp_lexer_consume_token (parser->lexer);
/* A constructor declarator cannot appear in a typedef. */
register
static
extern
- mutable
+ mutable
GNU Extension:
thread */
case RID_AUTO:
+ /* Consume the token. */
+ cp_lexer_consume_token (parser->lexer);
+ cp_parser_set_storage_class (decl_specs, sc_auto);
+ break;
case RID_REGISTER:
+ /* Consume the token. */
+ cp_lexer_consume_token (parser->lexer);
+ cp_parser_set_storage_class (decl_specs, sc_register);
+ break;
case RID_STATIC:
+ /* Consume the token. */
+ cp_lexer_consume_token (parser->lexer);
+ if (decl_specs->specs[(int) ds_thread])
+ {
+ error ("`__thread' before `static'");
+ decl_specs->specs[(int) ds_thread] = 0;
+ }
+ cp_parser_set_storage_class (decl_specs, sc_static);
+ break;
case RID_EXTERN:
+ /* Consume the token. */
+ cp_lexer_consume_token (parser->lexer);
+ if (decl_specs->specs[(int) ds_thread])
+ {
+ error ("`__thread' before `extern'");
+ decl_specs->specs[(int) ds_thread] = 0;
+ }
+ cp_parser_set_storage_class (decl_specs, sc_extern);
+ break;
case RID_MUTABLE:
+ /* Consume the token. */
+ cp_lexer_consume_token (parser->lexer);
+ cp_parser_set_storage_class (decl_specs, sc_mutable);
+ break;
case RID_THREAD:
- decl_spec = cp_parser_storage_class_specifier_opt (parser);
+ /* Consume the token. */
+ cp_lexer_consume_token (parser->lexer);
+ ++decl_specs->specs[(int) ds_thread];
break;
-
+
default:
+ /* We did not yet find a decl-specifier yet. */
+ found_decl_spec = false;
break;
}
/* Constructors are a special case. The `S' in `S()' is not a
decl-specifier; it is the beginning of the declarator. */
- constructor_p = (!decl_spec
- && constructor_possible_p
- && cp_parser_constructor_declarator_p (parser,
- friend_p));
+ constructor_p
+ = (!found_decl_spec
+ && constructor_possible_p
+ && (cp_parser_constructor_declarator_p
+ (parser, decl_specs->specs[(int) ds_friend] != 0)));
/* If we don't have a DECL_SPEC yet, then we must be looking at
a type-specifier. */
- if (!decl_spec && !constructor_p)
+ if (!found_decl_spec && !constructor_p)
{
int decl_spec_declares_class_or_enum;
bool is_cv_qualifier;
+ tree type_spec;
- decl_spec
+ type_spec
= cp_parser_type_specifier (parser, flags,
- friend_p,
+ decl_specs,
/*is_declaration=*/true,
&decl_spec_declares_class_or_enum,
&is_cv_qualifier);
only exceptions are the following:
-- const or volatile can be combined with any other
- type-specifier.
+ type-specifier.
-- signed or unsigned can be combined with char, long,
short, or int.
user-defined types. We *do* still allow things like `int
int' to be considered a decl-specifier-seq, and issue the
error message later. */
- if (decl_spec && !is_cv_qualifier)
+ if (type_spec && !is_cv_qualifier)
flags |= CP_PARSER_FLAGS_NO_USER_DEFINED_TYPES;
/* A constructor declarator cannot follow a type-specifier. */
- if (decl_spec)
- constructor_possible_p = false;
- }
-
- /* If we still do not have a DECL_SPEC, then there are no more
- decl-specifiers. */
- if (!decl_spec)
- {
- /* Issue an error message, unless the entire construct was
- optional. */
- if (!(flags & CP_PARSER_FLAGS_OPTIONAL))
+ if (type_spec)
{
- cp_parser_error (parser, "expected decl specifier");
- return error_mark_node;
+ constructor_possible_p = false;
+ found_decl_spec = true;
}
-
- break;
}
- /* Add the DECL_SPEC to the list of specifiers. */
- if (decl_specs == NULL || TREE_VALUE (decl_specs) != error_mark_node)
- decl_specs = tree_cons (NULL_TREE, decl_spec, decl_specs);
+ /* If we still do not have a DECL_SPEC, then there are no more
+ decl-specifiers. */
+ if (!found_decl_spec)
+ break;
+ decl_specs->any_specifiers_p = true;
/* After we see one decl-specifier, further decl-specifiers are
always optional. */
flags |= CP_PARSER_FLAGS_OPTIONAL;
}
/* Don't allow a friend specifier with a class definition. */
- if (friend_p && (*declares_class_or_enum & 2))
+ if (decl_specs->specs[(int) ds_friend] != 0
+ && (*declares_class_or_enum & 2))
error ("class definition may not be declared a friend");
-
- /* We have built up the DECL_SPECS in reverse order. Return them in
- the correct order. */
- return nreverse (decl_specs);
}
-/* Parse an (optional) storage-class-specifier.
+/* Parse an (optional) storage-class-specifier.
storage-class-specifier:
auto
register
static
extern
- mutable
+ mutable
GNU Extension:
thread
Returns an IDENTIFIER_NODE corresponding to the keyword used. */
-
+
static tree
cp_parser_storage_class_specifier_opt (cp_parser* parser)
{
}
}
-/* Parse an (optional) function-specifier.
+/* Parse an (optional) function-specifier.
function-specifier:
inline
virtual
explicit
- Returns an IDENTIFIER_NODE corresponding to the keyword used. */
-
+ Returns an IDENTIFIER_NODE corresponding to the keyword used.
+ Updates DECL_SPECS, if it is non-NULL. */
+
static tree
-cp_parser_function_specifier_opt (cp_parser* parser)
+cp_parser_function_specifier_opt (cp_parser* parser,
+ cp_decl_specifier_seq *decl_specs)
{
switch (cp_lexer_peek_token (parser->lexer)->keyword)
{
case RID_INLINE:
+ if (decl_specs)
+ ++decl_specs->specs[(int) ds_inline];
+ break;
+
case RID_VIRTUAL:
+ if (decl_specs)
+ ++decl_specs->specs[(int) ds_virtual];
+ break;
+
case RID_EXPLICIT:
- /* Consume the token. */
- return cp_lexer_consume_token (parser->lexer)->value;
+ if (decl_specs)
+ ++decl_specs->specs[(int) ds_explicit];
+ break;
default:
return NULL_TREE;
}
+
+ /* Consume the token. */
+ return cp_lexer_consume_token (parser->lexer)->value;
}
/* Parse a linkage-specification.
/* Assume C++ linkage. */
linkage = get_identifier ("c++");
}
+ /* If the string is chained to another string, take the latter,
+ that's the untranslated string. */
+ else if (TREE_CHAIN (token->value))
+ linkage = get_identifier (TREE_STRING_POINTER (TREE_CHAIN (token->value)));
/* If it's a simple string constant, things are easier. */
else
linkage = get_identifier (TREE_STRING_POINTER (token->value));
{
bool saved_in_unbraced_linkage_specification_p;
- saved_in_unbraced_linkage_specification_p
+ saved_in_unbraced_linkage_specification_p
= parser->in_unbraced_linkage_specification_p;
parser->in_unbraced_linkage_specification_p = true;
have_extern_spec = true;
cp_parser_declaration (parser);
have_extern_spec = false;
- parser->in_unbraced_linkage_specification_p
+ parser->in_unbraced_linkage_specification_p
= saved_in_unbraced_linkage_specification_p;
}
/* Parse a conversion-function-id.
conversion-function-id:
- operator conversion-type-id
+ operator conversion-type-id
Returns an IDENTIFIER_NODE representing the operator. */
-static tree
+static tree
cp_parser_conversion_function_id (cp_parser* parser)
{
tree type;
tree saved_scope;
tree saved_qualifying_scope;
tree saved_object_scope;
+ bool pop_p = false;
/* Look for the `operator' token. */
if (!cp_parser_require_keyword (parser, RID_OPERATOR, "`operator'"))
entities declared within the class are available in the
conversion-type-id. For example, consider:
- struct S {
+ struct S {
typedef int I;
operator I();
};
In order to see that `I' is a type-name in the definition, we
must be in the scope of `S'. */
if (saved_scope)
- push_scope (saved_scope);
+ pop_p = 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 (saved_scope)
+ if (pop_p)
pop_scope (saved_scope);
/* Restore the saved scope. */
parser->scope = saved_scope;
cp_parser_conversion_type_id (cp_parser* parser)
{
tree attributes;
- tree type_specifiers;
- tree declarator;
+ cp_decl_specifier_seq type_specifiers;
+ cp_declarator *declarator;
/* Parse the attributes. */
attributes = cp_parser_attributes_opt (parser);
/* Parse the type-specifiers. */
- type_specifiers = cp_parser_type_specifier_seq (parser);
+ cp_parser_type_specifier_seq (parser, &type_specifiers);
/* If that didn't work, stop. */
- if (type_specifiers == error_mark_node)
+ if (type_specifiers.type == error_mark_node)
return error_mark_node;
/* Parse the conversion-declarator. */
declarator = cp_parser_conversion_declarator_opt (parser);
- return grokdeclarator (declarator, type_specifiers, TYPENAME,
+ return grokdeclarator (declarator, &type_specifiers, TYPENAME,
/*initialized=*/0, &attributes);
}
/* Parse an (optional) conversion-declarator.
conversion-declarator:
- ptr-operator conversion-declarator [opt]
+ ptr-operator conversion-declarator [opt]
- Returns a representation of the declarator. See
- cp_parser_declarator for details. */
+ */
-static tree
+static cp_declarator *
cp_parser_conversion_declarator_opt (cp_parser* parser)
{
enum tree_code code;
tree class_type;
- tree cv_qualifier_seq;
+ cp_cv_quals cv_quals;
/* We don't know if there's a ptr-operator next, or not. */
cp_parser_parse_tentatively (parser);
/* Try the ptr-operator. */
- code = cp_parser_ptr_operator (parser, &class_type,
- &cv_qualifier_seq);
+ code = cp_parser_ptr_operator (parser, &class_type, &cv_quals);
/* If it worked, look for more conversion-declarators. */
if (cp_parser_parse_definitely (parser))
{
- tree declarator;
+ cp_declarator *declarator;
- /* Parse another optional declarator. */
- declarator = cp_parser_conversion_declarator_opt (parser);
+ /* Parse another optional declarator. */
+ declarator = cp_parser_conversion_declarator_opt (parser);
- /* Create the representation of the declarator. */
- if (code == INDIRECT_REF)
- declarator = make_pointer_declarator (cv_qualifier_seq,
+ /* Create the representation of the declarator. */
+ if (class_type)
+ declarator = make_ptrmem_declarator (cv_quals, class_type,
declarator);
- else
- declarator = make_reference_declarator (cv_qualifier_seq,
- declarator);
-
- /* Handle the pointer-to-member case. */
- if (class_type)
- declarator = build_nt (SCOPE_REF, class_type, declarator);
+ else if (code == INDIRECT_REF)
+ declarator = make_pointer_declarator (cv_quals, declarator);
+ else
+ declarator = make_reference_declarator (cv_quals, declarator);
- return declarator;
+ return declarator;
}
- return NULL_TREE;
+ return NULL;
}
/* Parse an (optional) ctor-initializer.
ctor-initializer:
- : mem-initializer-list
+ : mem-initializer-list
Returns TRUE iff the ctor-initializer was actually present. */
/* Parse a mem-initializer.
mem-initializer:
- mem-initializer-id ( expression-list [opt] )
+ mem-initializer-id ( expression-list [opt] )
GNU extension:
-
+
mem-initializer:
( expression-list [opt] )
tree mem_initializer_id;
tree expression_list;
tree member;
-
+
/* Find out what is being initialized. */
if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN))
{
if (member && !DECL_P (member))
in_base_initializer = 1;
- expression_list
+ expression_list
= cp_parser_parenthesized_expression_list (parser, false,
/*non_constant_p=*/NULL);
if (!expression_list)
expression_list = void_type_node;
in_base_initializer = 0;
-
+
return member ? build_tree_list (member, expression_list) : NULL_TREE;
}
mem-initializer-id:
:: [opt] nested-name-specifier [opt] class-name
- identifier
+ identifier
Returns a TYPE indicating the class to be initializer for the first
production. Returns an IDENTIFIER_NODE indicating the data member
{
bool global_scope_p;
bool nested_name_specifier_p;
+ bool template_p = false;
tree id;
+ /* `typename' is not allowed in this context ([temp.res]). */
+ if (cp_lexer_next_token_is_keyword (parser->lexer, RID_TYPENAME))
+ {
+ error ("keyword `typename' not allowed in this context (a qualified "
+ "member initializer is implicitly a type)");
+ cp_lexer_consume_token (parser->lexer);
+ }
/* Look for the optional `::' operator. */
- global_scope_p
- = (cp_parser_global_scope_opt (parser,
- /*current_scope_valid_p=*/false)
+ global_scope_p
+ = (cp_parser_global_scope_opt (parser,
+ /*current_scope_valid_p=*/false)
!= NULL_TREE);
/* Look for the optional nested-name-specifier. The simplest way to
implement:
is to assume that we have seen the `typename' keyword at this
point. */
- nested_name_specifier_p
+ nested_name_specifier_p
= (cp_parser_nested_name_specifier_opt (parser,
/*typename_keyword_p=*/true,
/*check_dependency_p=*/true,
/*type_p=*/true,
/*is_declaration=*/true)
!= NULL_TREE);
+ if (nested_name_specifier_p)
+ template_p = cp_parser_optional_template_keyword (parser);
/* If there is a `::' operator or a nested-name-specifier, then we
are definitely looking for a class-name. */
if (global_scope_p || nested_name_specifier_p)
return cp_parser_class_name (parser,
/*typename_keyword_p=*/true,
- /*template_keyword_p=*/false,
+ /*template_keyword_p=*/template_p,
/*type_p=*/false,
/*check_dependency_p=*/true,
/*class_head_p=*/false,
/* Otherwise, we could also be looking for an ordinary identifier. */
cp_parser_parse_tentatively (parser);
/* Try a class-name. */
- id = cp_parser_class_name (parser,
+ id = cp_parser_class_name (parser,
/*typename_keyword_p=*/true,
/*template_keyword_p=*/false,
/*type_p=*/false,
/* Parse an operator-function-id.
operator-function-id:
- operator operator
+ operator operator
Returns an IDENTIFIER_NODE for the operator which is a
human-readable spelling of the identifier, e.g., `operator +'. */
-static tree
+static tree
cp_parser_operator_function_id (cp_parser* parser)
{
/* Look for the `operator' keyword. */
|| ++ -- , ->* -> () []
GNU Extensions:
-
+
operator:
<? >? <?= >?=
Returns an IDENTIFIER_NODE for the operator which is a
human-readable spelling of the identifier, e.g., `operator +'. */
-
+
static tree
cp_parser_operator (cp_parser* parser)
{
cp_lexer_consume_token (parser->lexer);
/* Look for the `]' token. */
cp_parser_require (parser, CPP_CLOSE_SQUARE, "`]'");
- id = ansi_opname (op == NEW_EXPR
+ id = ansi_opname (op == NEW_EXPR
? VEC_NEW_EXPR : VEC_DELETE_EXPR);
}
/* Otherwise, we have the non-array variant. */
case CPP_COMPL:
id = ansi_opname (BIT_NOT_EXPR);
break;
-
+
case CPP_NOT:
id = ansi_opname (TRUTH_NOT_EXPR);
break;
case CPP_OR_OR:
id = ansi_opname (TRUTH_ORIF_EXPR);
break;
-
+
case CPP_PLUS_PLUS:
id = ansi_opname (POSTINCREMENT_EXPR);
break;
/* Parse a template-declaration.
template-declaration:
- export [opt] template < template-parameter-list > declaration
+ export [opt] template < template-parameter-list > declaration
If MEMBER_P is TRUE, this template-declaration occurs within a
- class-specifier.
+ class-specifier.
The grammar rule given by the standard isn't correct. What
is really meant is:
template-declaration:
- export [opt] template-parameter-list-seq
+ export [opt] template-parameter-list-seq
decl-specifier-seq [opt] init-declarator [opt] ;
- export [opt] template-parameter-list-seq
+ export [opt] template-parameter-list-seq
function-definition
template-parameter-list-seq:
{
tree parameter;
cp_token *token;
+ bool is_non_type;
/* Parse the template-parameter. */
- parameter = cp_parser_template_parameter (parser);
+ parameter = cp_parser_template_parameter (parser, &is_non_type);
/* Add it to the list. */
parameter_list = process_template_parm (parameter_list,
- parameter);
-
+ parameter,
+ is_non_type);
/* Peek at the next token. */
token = cp_lexer_peek_token (parser->lexer);
/* If it's not a `,', we're done. */
parameter-declaration
Returns a TREE_LIST. The TREE_VALUE represents the parameter. The
- TREE_PURPOSE is the default value, if any. */
+ TREE_PURPOSE is the default value, if any. *IS_NON_TYPE is set to
+ true iff this parameter is a non-type parameter. */
static tree
-cp_parser_template_parameter (cp_parser* parser)
+cp_parser_template_parameter (cp_parser* parser, bool *is_non_type)
{
cp_token *token;
+ cp_parameter_declarator *parameter_declarator;
+ /* Assume it is a type parameter or a template parameter. */
+ *is_non_type = false;
/* Peek at the next token. */
token = cp_lexer_peek_token (parser->lexer);
/* If it is `class' or `template', we have a type-parameter. */
template <typename T, typename T::X X> ...
or:
-
+
template <class C, class D*> ...
Here, the first parameter is a type parameter, and the second is
token = cp_lexer_peek_nth_token (parser->lexer, 3);
/* Now, see if the token looks like the end of a template
parameter. */
- if (token->type == CPP_COMMA
+ if (token->type == CPP_COMMA
|| token->type == CPP_EQ
|| token->type == CPP_GREATER)
return cp_parser_type_parameter (parser);
}
- /* Otherwise, it is a non-type parameter.
+ /* Otherwise, it is a non-type parameter.
[temp.param]
template-parameter, the first non-nested `>' is taken as the end
of the template parameter-list rather than a greater-than
operator. */
- return
- cp_parser_parameter_declaration (parser, /*template_parm_p=*/true,
- /*parenthesized_p=*/NULL);
+ *is_non_type = true;
+ 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)));
}
/* Parse a type-parameter.
typename identifier [opt]
typename identifier [opt] = type-id
template < template-parameter-list > class identifier [opt]
- template < template-parameter-list > class identifier [opt]
- = id-expression
+ template < template-parameter-list > class identifier [opt]
+ = id-expression
Returns a TREE_LIST. The TREE_VALUE is itself a TREE_LIST. The
TREE_PURPOSE is the default-argument, if any. The TREE_VALUE is
tree parameter;
/* Look for a keyword to tell us what kind of parameter this is. */
- token = cp_parser_require (parser, CPP_KEYWORD,
+ token = cp_parser_require (parser, CPP_KEYWORD,
"`class', `typename', or `template'");
if (!token)
return error_mark_node;
cp_parser_require (parser, CPP_LESS, "`<'");
/* Parse the template-parameter-list. */
begin_template_parm_list ();
- parameter_list
+ parameter_list
= cp_parser_template_parameter_list (parser);
parameter_list = end_template_parm_list (parameter_list);
/* Look for the `>'. */
/* Create the template parameter. */
parameter = finish_template_template_parm (class_type_node,
identifier);
-
+
/* If the next token is an `=', then there is a
default-argument. */
if (cp_lexer_next_token_is (parser->lexer, CPP_EQ))
/* Consume the `='. */
cp_lexer_consume_token (parser->lexer);
/* Parse the id-expression. */
- default_argument
+ default_argument
= cp_parser_id_expression (parser,
/*template_keyword_p=*/false,
/*check_dependency_p=*/true,
/*template_p=*/&is_template,
/*declarator_p=*/false);
- /* Look up the name. */
- default_argument
- = cp_parser_lookup_name (parser, default_argument,
- /*is_type=*/false,
- /*is_template=*/is_template,
- /*is_namespace=*/false,
- /*check_dependency=*/true);
+ if (TREE_CODE (default_argument) == TYPE_DECL)
+ /* If the id-expression was a template-id that refers to
+ a template-class, we already have the declaration here,
+ so no further lookup is needed. */
+ ;
+ else
+ /* Look up the name. */
+ default_argument
+ = cp_parser_lookup_name (parser, default_argument,
+ /*is_type=*/false,
+ /*is_template=*/is_template,
+ /*is_namespace=*/false,
+ /*check_dependency=*/true);
/* See if the default argument is valid. */
default_argument
= check_template_template_default_arg (default_argument);
"expected `class', `typename', or `template'");
parameter = error_mark_node;
}
-
+
return parameter;
}
`template' keyword. In this case, a TEMPLATE_ID_EXPR will be
returned. Otherwise, if the template-name names a function, or set
of functions, returns a TEMPLATE_ID_EXPR. If the template-name
- names a class, returns a TYPE_DECL for the specialization.
+ names a class, returns a TYPE_DECL for the specialization.
If CHECK_DEPENDENCY_P is FALSE, names are looked up in
uninstantiated templates. */
static tree
-cp_parser_template_id (cp_parser *parser,
- bool template_keyword_p,
+cp_parser_template_id (cp_parser *parser,
+ bool template_keyword_p,
bool check_dependency_p,
bool is_declaration)
{
tree template_id;
ptrdiff_t start_of_id;
tree access_check = NULL_TREE;
- cp_token *next_token;
+ cp_token *next_token, *next_token_2;
bool is_identifier;
/* If the next token corresponds to a template-id, there is no need
finding a template-id. */
if ((next_token->type != CPP_NAME && next_token->keyword != RID_OPERATOR)
|| (next_token->type == CPP_NAME
- && cp_lexer_peek_nth_token (parser->lexer, 2)->type != CPP_LESS))
+ && !cp_parser_nth_token_starts_template_argument_list_p
+ (parser, 2)))
{
cp_parser_error (parser, "expected template-id");
return error_mark_node;
return template;
}
- /* Look for the `<' that starts the template-argument-list. */
- if (!cp_parser_require (parser, CPP_LESS, "`<'"))
+ /* If we find the sequence `[:' after a template-name, it's probably
+ a digraph-typo for `< ::'. Substitute the tokens and check if we can
+ parse correctly the argument list. */
+ next_token = cp_lexer_peek_nth_token (parser->lexer, 1);
+ next_token_2 = cp_lexer_peek_nth_token (parser->lexer, 2);
+ if (next_token->type == CPP_OPEN_SQUARE
+ && next_token->flags & DIGRAPH
+ && next_token_2->type == CPP_COLON
+ && !(next_token_2->flags & PREV_WHITE))
{
- pop_deferring_access_checks ();
- return error_mark_node;
+ cp_parser_parse_tentatively (parser);
+ /* Change `:' into `::'. */
+ next_token_2->type = CPP_SCOPE;
+ /* Consume the first token (CPP_OPEN_SQUARE - which we pretend it is
+ CPP_LESS. */
+ cp_lexer_consume_token (parser->lexer);
+ /* Parse the arguments. */
+ arguments = cp_parser_enclosed_template_argument_list (parser);
+ if (!cp_parser_parse_definitely (parser))
+ {
+ /* If we couldn't parse an argument list, then we revert our changes
+ and return simply an error. Maybe this is not a template-id
+ after all. */
+ next_token_2->type = CPP_COLON;
+ cp_parser_error (parser, "expected `<'");
+ pop_deferring_access_checks ();
+ return error_mark_node;
+ }
+ /* Otherwise, emit an error about the invalid digraph, but continue
+ parsing because we got our argument list. */
+ pedwarn ("`<::' cannot begin a template-argument list");
+ inform ("`<:' is an alternate spelling for `['. Insert whitespace "
+ "between `<' and `::'");
+ if (!flag_permissive)
+ {
+ static bool hint;
+ if (!hint)
+ {
+ inform ("(if you use `-fpermissive' G++ will accept your code)");
+ hint = true;
+ }
+ }
+ }
+ else
+ {
+ /* Look for the `<' that starts the template-argument-list. */
+ if (!cp_parser_require (parser, CPP_LESS, "`<'"))
+ {
+ pop_deferring_access_checks ();
+ return error_mark_node;
+ }
+ /* Parse the arguments. */
+ arguments = cp_parser_enclosed_template_argument_list (parser);
}
-
- /* Parse the arguments. */
- arguments = cp_parser_enclosed_template_argument_list (parser);
/* Build a representation of the specialization. */
if (TREE_CODE (template) == IDENTIFIER_NODE)
template_id = build_min_nt (TEMPLATE_ID_EXPR, template, arguments);
else if (DECL_CLASS_TEMPLATE_P (template)
|| DECL_TEMPLATE_TEMPLATE_PARM_P (template))
- template_id
- = finish_template_type (template, arguments,
- cp_lexer_next_token_is (parser->lexer,
+ template_id
+ = finish_template_type (template, arguments,
+ cp_lexer_next_token_is (parser->lexer,
CPP_SCOPE));
else
{
|| TREE_CODE (template) == OVERLOAD
|| BASELINK_P (template)),
20010716);
-
+
template_id = lookup_template_function (template, arguments);
}
-
+
/* Retrieve any deferred checks. Do not pop this access checks yet
so the memory will not be reclaimed during token replacing below. */
access_check = get_deferred_access_checks ();
/* Find the token that corresponds to the start of the
template-id. */
- token = cp_lexer_advance_token (parser->lexer,
+ token = cp_lexer_advance_token (parser->lexer,
parser->lexer->first_token,
start_of_id);
template-name:
identifier
-
+
The standard should actually say:
template-name:
identifier
operator-function-id
- conversion-function-id
A defect report has been filed about this issue.
+ A conversion-function-id cannot be a template name because they cannot
+ be part of a template-id. In fact, looking at this code:
+
+ a.operator K<int>()
+
+ the conversion-function-id is "operator K<int>", and K<int> is a type-id.
+ It is impossible to call a templated conversion-function-id with an
+ explicit argument list, since the only allowed template parameter is
+ the type to which it is converting.
+
If TEMPLATE_KEYWORD_P is true, then we have just seen the
`template' keyword, in a construction like:
names are looked up inside uninstantiated templates. */
static tree
-cp_parser_template_name (cp_parser* parser,
- bool template_keyword_p,
+cp_parser_template_name (cp_parser* parser,
+ bool template_keyword_p,
bool check_dependency_p,
bool is_declaration,
bool *is_identifier)
identifier = cp_parser_operator_function_id (parser);
/* If that didn't work, try a conversion-function-id. */
if (!cp_parser_parse_definitely (parser))
- identifier = cp_parser_conversion_function_id (parser);
+ {
+ cp_parser_error (parser, "expected template-name");
+ return error_mark_node;
+ }
}
/* Look for the identifier. */
else
identifier = cp_parser_identifier (parser);
-
+
/* If we didn't find an identifier, we don't have a template-id. */
if (identifier == error_mark_node)
return error_mark_node;
-- but we do not if there is no `<'. */
if (processing_template_decl
- && cp_lexer_next_token_is (parser->lexer, CPP_LESS))
+ && cp_parser_nth_token_starts_template_argument_list_p (parser, 1))
{
/* In a declaration, in a dependent context, we pretend that the
"template" keyword was present in order to improve error
recovery. For example, given:
-
+
template <typename T> void f(T::X<int>);
-
+
we want to treat "X<int>" as a template-id. */
- if (is_declaration
- && !template_keyword_p
+ if (is_declaration
+ && !template_keyword_p
&& parser->scope && TYPE_P (parser->scope)
- && dependent_type_p (parser->scope))
+ && dependent_type_p (parser->scope)
+ /* Do not do this for dtors (or ctors), since they never
+ need the template keyword before their name. */
+ && !constructor_name_p (identifier, parser->scope))
{
ptrdiff_t start;
cp_token* token;
/* Explain what went wrong. */
error ("non-template `%D' used as template", identifier);
- error ("(use `%T::template %D' to indicate that it is a template)",
- parser->scope, 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)
*is_identifier = true;
return identifier;
}
- if (template_keyword_p)
+
+ /* If the "template" keyword is present, then there is generally
+ no point in doing name-lookup, so we just return IDENTIFIER.
+ But, if the qualifying scope is non-dependent then we can
+ (and must) do name-lookup normally. */
+ if (template_keyword_p
+ && (!parser->scope
+ || (TYPE_P (parser->scope)
+ && dependent_type_p (parser->scope))))
return identifier;
}
/* If DECL is a template, then the name was a template-name. */
if (TREE_CODE (decl) == TEMPLATE_DECL)
;
- else
+ else
{
/* The standard does not explicitly indicate whether a name that
names a set of overloaded declarations, some of which are
if (TREE_CODE (fns) == OVERLOAD)
{
tree fn;
-
+
for (fn = fns; fn; fn = OVL_NEXT (fn))
if (TREE_CODE (OVL_CURRENT (fn)) == TEMPLATE_DECL)
break;
if (n_args)
/* Consume the comma. */
cp_lexer_consume_token (parser->lexer);
-
+
/* Parse the template-argument. */
argument = cp_parser_template_argument (parser);
if (n_args == alloced)
{
alloced *= 2;
-
+
if (arg_ary == fixed_args)
{
arg_ary = xmalloc (sizeof (tree) * alloced);
while (n_args--)
TREE_VEC_ELT (vec, n_args) = arg_ary[n_args];
-
+
if (arg_ary != fixed_args)
free (arg_ary);
parser->in_template_argument_list_p = saved_in_template_argument_list_p;
The representation is that of an assignment-expression, type-id, or
id-expression -- except that the qualified id-expression is
evaluated, so that the value returned is either a DECL or an
- OVERLOAD.
+ OVERLOAD.
Although the standard says "assignment-expression", it forbids
throw-expressions or assignments in the template argument.
tree qualifying_class;
/* There's really no way to know what we're looking at, so we just
- try each alternative in order.
+ try each alternative in order.
[temp.arg]
In a template-argument, an ambiguity between a type-id and an
expression is resolved to a type-id, regardless of the form of
- the corresponding template-parameter.
+ the corresponding template-parameter.
Therefore, we try a type-id first. */
cp_parser_parse_tentatively (parser);
argument = cp_parser_type_id (parser);
/* If there was no error parsing the type-id but the next token is a '>>',
- we probably found a typo for '> >'. But there are type-id which are
+ we probably found a typo for '> >'. But there are type-id which are
also valid expressions. For instance:
struct X { int operator >> (int); };
/* We're still not sure what the argument will be. */
cp_parser_parse_tentatively (parser);
/* Try a template. */
- argument = cp_parser_id_expression (parser,
+ argument = cp_parser_id_expression (parser,
/*template_keyword_p=*/false,
/*check_dependency_p=*/true,
&template_p,
cp_parser_error (parser, "expected template-argument");
if (!cp_parser_error_occurred (parser))
{
- /* Figure out what is being referred to. */
- argument = cp_parser_lookup_name (parser, argument,
- /*is_type=*/false,
- /*is_template=*/template_p,
- /*is_namespace=*/false,
- /*check_dependency=*/true);
+ /* Figure out what is being referred to. If the id-expression
+ was for a class template specialization, then we will have a
+ TYPE_DECL at this point. There is no need to do name lookup
+ at this point in that case. */
+ if (TREE_CODE (argument) != TYPE_DECL)
+ argument = cp_parser_lookup_name (parser, argument,
+ /*is_type=*/false,
+ /*is_template=*/template_p,
+ /*is_namespace=*/false,
+ /*check_dependency=*/true);
if (TREE_CODE (argument) != TEMPLATE_DECL
&& TREE_CODE (argument) != UNBOUND_CLASS_TEMPLATE)
cp_parser_error (parser, "expected template-name");
later. */
;
else if (address_p
- && (TREE_CODE (argument) == OFFSET_REF
+ && (TREE_CODE (argument) == OFFSET_REF
|| TREE_CODE (argument) == SCOPE_REF))
/* A pointer-to-member. */
;
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.
+ by '>>', the argument can only be a constant expression now.
Otherwise, we try parsing the constant-expression tentatively,
because the argument could really be a type-id. */
if (maybe_type_id)
cp_parser_parse_tentatively (parser);
- argument = cp_parser_constant_expression (parser,
+ argument = cp_parser_constant_expression (parser,
/*allow_non_constant_p=*/false,
/*non_constant_p=*/NULL);
- argument = cp_parser_fold_non_dependent_expr (argument);
+ argument = fold_non_dependent_expr (argument);
if (!maybe_type_id)
return argument;
if (!cp_parser_next_token_ends_template_argument_p (parser))
return argument;
/* We did our best to parse the argument as a non type-id, but that
was the only alternative that matched (albeit with a '>' after
- it). We can assume it's just a typo from the user, and a
+ it). We can assume it's just a typo from the user, and a
diagnostic will then be issued. */
return cp_parser_type_id (parser);
}
/* Parse an explicit-instantiation.
explicit-instantiation:
- template declaration
+ template declaration
Although the standard says `declaration', what it really means is:
explicit-instantiation:
- template decl-specifier-seq [opt] declarator [opt] ;
+ template decl-specifier-seq [opt] declarator [opt] ;
Things like `template int S<int>::i = 5, int S<double>::j;' are not
supposed to be allowed. A defect report has been filed about this
- issue.
+ issue.
GNU Extension:
-
+
explicit-instantiation:
- storage-class-specifier template
+ storage-class-specifier template
decl-specifier-seq [opt] declarator [opt] ;
- function-specifier template
+ function-specifier template
decl-specifier-seq [opt] declarator [opt] ; */
static void
cp_parser_explicit_instantiation (cp_parser* parser)
{
int declares_class_or_enum;
- tree decl_specifiers;
- tree attributes;
+ cp_decl_specifier_seq decl_specifiers;
tree extension_specifier = NULL_TREE;
/* Look for an (optional) storage-class-specifier or
function-specifier. */
if (cp_parser_allow_gnu_extensions_p (parser))
{
- extension_specifier
+ extension_specifier
= cp_parser_storage_class_specifier_opt (parser);
if (!extension_specifier)
- extension_specifier = cp_parser_function_specifier_opt (parser);
+ extension_specifier
+ = cp_parser_function_specifier_opt (parser,
+ /*decl_specs=*/NULL);
}
/* Look for the `template' keyword. */
control while processing explicit instantiation directives. */
push_deferring_access_checks (dk_no_check);
/* Parse a decl-specifier-seq. */
- decl_specifiers
- = cp_parser_decl_specifier_seq (parser,
- CP_PARSER_FLAGS_OPTIONAL,
- &attributes,
- &declares_class_or_enum);
+ cp_parser_decl_specifier_seq (parser,
+ CP_PARSER_FLAGS_OPTIONAL,
+ &decl_specifiers,
+ &declares_class_or_enum);
/* If there was exactly one decl-specifier, and it declared a class,
and there's no declarator, then we have an explicit type
instantiation. */
{
tree type;
- type = check_tag_decl (decl_specifiers);
+ type = check_tag_decl (&decl_specifiers);
/* Turn access control back on for names used during
template instantiation. */
pop_deferring_access_checks ();
}
else
{
- tree declarator;
+ cp_declarator *declarator;
tree decl;
/* Parse the declarator. */
- declarator
+ declarator
= cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED,
/*ctor_dtor_or_conv_p=*/NULL,
/*parenthesized_p=*/NULL);
- cp_parser_check_for_definition_in_return_type (declarator,
+ cp_parser_check_for_definition_in_return_type (declarator,
declares_class_or_enum);
- if (declarator != error_mark_node)
+ if (declarator != cp_error_declarator)
{
- decl = grokdeclarator (declarator, decl_specifiers,
+ decl = grokdeclarator (declarator, &decl_specifiers,
NORMAL, 0, NULL);
/* Turn access control back on for names used during
template instantiation. */
/* Parse an explicit-specialization.
explicit-specialization:
- template < > declaration
+ template < > declaration
Although the standard says `declaration', what it really means is:
explicit-specialization:
template <> decl-specifier [opt] init-declarator [opt] ;
- template <> function-definition
+ template <> function-definition
template <> explicit-specialization
template <> template-declaration */
}
else
/* Parse the dependent declaration. */
- cp_parser_single_declaration (parser,
+ cp_parser_single_declaration (parser,
/*member_p=*/false,
/*friend_p=*/NULL);
type-specifier:
__complex__
- Returns a representation of the type-specifier. If the
- type-specifier is a keyword (like `int' or `const', or
- `__complex__') then the corresponding IDENTIFIER_NODE is returned.
- For a class-specifier, enum-specifier, or elaborated-type-specifier
- a TREE_TYPE is returned; otherwise, a TYPE_DECL is returned.
+ Returns a representation of the type-specifier. For a
+ class-specifier, enum-specifier, or elaborated-type-specifier, a
+ TREE_TYPE is returned; otherwise, a TYPE_DECL is returned.
If IS_FRIEND is TRUE then this type-specifier is being declared a
`friend'. If IS_DECLARATION is TRUE, then this type-specifier is
is set to FALSE. */
static tree
-cp_parser_type_specifier (cp_parser* parser,
- cp_parser_flags flags,
- bool is_friend,
+cp_parser_type_specifier (cp_parser* parser,
+ cp_parser_flags flags,
+ cp_decl_specifier_seq *decl_specs,
bool is_declaration,
int* declares_class_or_enum,
bool* is_cv_qualifier)
tree type_spec = NULL_TREE;
cp_token *token;
enum rid keyword;
+ cp_decl_spec ds = ds_last;
/* Assume this type-specifier does not declare a new type. */
if (declares_class_or_enum)
{
if (declares_class_or_enum)
*declares_class_or_enum = 2;
+ if (decl_specs)
+ cp_parser_set_decl_spec_type (decl_specs,
+ type_spec,
+ /*user_defined_p=*/true);
return type_spec;
}
case RID_TYPENAME:
/* Look for an elaborated-type-specifier. */
- type_spec = cp_parser_elaborated_type_specifier (parser,
- is_friend,
- is_declaration);
+ type_spec
+ = (cp_parser_elaborated_type_specifier
+ (parser,
+ decl_specs && decl_specs->specs[(int) ds_friend],
+ is_declaration));
/* We're declaring a class or enum -- unless we're using
`typename'. */
if (declares_class_or_enum && keyword != RID_TYPENAME)
*declares_class_or_enum = 1;
+ if (decl_specs)
+ cp_parser_set_decl_spec_type (decl_specs,
+ type_spec,
+ /*user_defined_p=*/true);
return type_spec;
case RID_CONST:
+ ds = ds_const;
+ if (is_cv_qualifier)
+ *is_cv_qualifier = true;
+ break;
+
case RID_VOLATILE:
- case RID_RESTRICT:
- type_spec = cp_parser_cv_qualifier_opt (parser);
- /* Even though we call a routine that looks for an optional
- qualifier, we know that there should be one. */
- my_friendly_assert (type_spec != NULL, 20000328);
- /* This type-specifier was a cv-qualified. */
+ ds = ds_volatile;
if (is_cv_qualifier)
*is_cv_qualifier = true;
+ break;
- return type_spec;
+ case RID_RESTRICT:
+ ds = ds_restrict;
+ if (is_cv_qualifier)
+ *is_cv_qualifier = true;
+ break;
case RID_COMPLEX:
/* The `__complex__' keyword is a GNU extension. */
- return cp_lexer_consume_token (parser->lexer)->value;
+ ds = ds_complex;
+ break;
default:
break;
}
+ /* Handle simple keywords. */
+ if (ds != ds_last)
+ {
+ if (decl_specs)
+ {
+ ++decl_specs->specs[(int)ds];
+ decl_specs->any_specifiers_p = true;
+ }
+ return cp_lexer_consume_token (parser->lexer)->value;
+ }
+
/* If we do not already have a type-specifier, assume we are looking
at a simple-type-specifier. */
- type_spec = cp_parser_simple_type_specifier (parser, flags,
- /*identifier_p=*/true);
+ type_spec = cp_parser_simple_type_specifier (parser,
+ decl_specs,
+ flags);
/* If we didn't find a type-specifier, and a type-specifier was not
optional in this context, issue an error message. */
unsigned
float
double
- void
+ void
GNU Extension:
__typeof__ unary-expression
__typeof__ ( type-id )
- For the various keywords, the value returned is simply the
- TREE_IDENTIFIER representing the keyword if IDENTIFIER_P is true.
- For the first two productions, and if IDENTIFIER_P is false, the
- value returned is the indicated TYPE_DECL. */
+ Returns the indicated TYPE_DECL. If DECL_SPECS is not NULL, it is
+ appropriately updated. */
static tree
-cp_parser_simple_type_specifier (cp_parser* parser, cp_parser_flags flags,
- bool identifier_p)
+cp_parser_simple_type_specifier (cp_parser* parser,
+ cp_decl_specifier_seq *decl_specs,
+ cp_parser_flags flags)
{
tree type = NULL_TREE;
cp_token *token;
switch (token->keyword)
{
case RID_CHAR:
+ if (decl_specs)
+ decl_specs->explicit_char_p = true;
type = char_type_node;
break;
case RID_WCHAR:
type = boolean_type_node;
break;
case RID_SHORT:
+ if (decl_specs)
+ ++decl_specs->specs[(int) ds_short];
type = short_integer_type_node;
break;
case RID_INT:
+ if (decl_specs)
+ decl_specs->explicit_int_p = true;
type = integer_type_node;
break;
case RID_LONG:
+ if (decl_specs)
+ ++decl_specs->specs[(int) ds_long];
type = long_integer_type_node;
break;
case RID_SIGNED:
+ if (decl_specs)
+ ++decl_specs->specs[(int) ds_signed];
type = integer_type_node;
break;
case RID_UNSIGNED:
+ if (decl_specs)
+ ++decl_specs->specs[(int) ds_unsigned];
type = unsigned_type_node;
break;
case RID_FLOAT:
break;
case RID_TYPEOF:
- {
- tree operand;
+ /* Consume the `typeof' token. */
+ cp_lexer_consume_token (parser->lexer);
+ /* Parse the operand to `typeof'. */
+ type = cp_parser_sizeof_operand (parser, RID_TYPEOF);
+ /* If it is not already a TYPE, take its type. */
+ if (!TYPE_P (type))
+ type = finish_typeof (type);
- /* Consume the `typeof' token. */
- cp_lexer_consume_token (parser->lexer);
- /* Parse the operand to `typeof'. */
- operand = cp_parser_sizeof_operand (parser, RID_TYPEOF);
- /* If it is not already a TYPE, take its type. */
- if (!TYPE_P (operand))
- operand = finish_typeof (operand);
+ if (decl_specs)
+ cp_parser_set_decl_spec_type (decl_specs, type,
+ /*user_defined_p=*/true);
- return operand;
- }
+ return type;
default:
break;
{
tree id;
+ /* Record the type. */
+ if (decl_specs
+ && (token->keyword != RID_SIGNED
+ && token->keyword != RID_UNSIGNED
+ && token->keyword != RID_SHORT
+ && token->keyword != RID_LONG))
+ cp_parser_set_decl_spec_type (decl_specs,
+ type,
+ /*user_defined=*/false);
+ if (decl_specs)
+ decl_specs->any_specifiers_p = true;
+
/* Consume the token. */
id = cp_lexer_consume_token (parser->lexer)->value;
- return identifier_p ? id : TYPE_NAME (type);
+
+ /* There is no valid C++ program where a non-template type is
+ followed by a "<". That usually indicates that the user thought
+ that the type was a template. */
+ cp_parser_check_for_invalid_template_id (parser, type);
+
+ return TYPE_NAME (type);
}
/* The type-specifier must be a user-defined type. */
- if (!(flags & CP_PARSER_FLAGS_NO_USER_DEFINED_TYPES))
+ if (!(flags & CP_PARSER_FLAGS_NO_USER_DEFINED_TYPES))
{
+ bool qualified_p;
+
/* Don't gobble tokens or issue error messages if this is an
optional type-specifier. */
if (flags & CP_PARSER_FLAGS_OPTIONAL)
cp_parser_global_scope_opt (parser,
/*current_scope_valid_p=*/false);
/* Look for the nested-name specifier. */
- cp_parser_nested_name_specifier_opt (parser,
- /*typename_keyword_p=*/false,
- /*check_dependency_p=*/true,
- /*type_p=*/false,
- /*is_declaration=*/false);
+ qualified_p
+ = (cp_parser_nested_name_specifier_opt (parser,
+ /*typename_keyword_p=*/false,
+ /*check_dependency_p=*/true,
+ /*type_p=*/false,
+ /*is_declaration=*/false)
+ != NULL_TREE);
/* If we have seen a nested-name-specifier, and the next token
is `template', then we are using the template-id production. */
- if (parser->scope
+ if (parser->scope
&& cp_parser_optional_template_keyword (parser))
{
/* Look for the template-id. */
- type = cp_parser_template_id (parser,
+ type = cp_parser_template_id (parser,
/*template_keyword_p=*/true,
/*check_dependency_p=*/true,
/*is_declaration=*/false);
/* Otherwise, look for a type-name. */
else
type = cp_parser_type_name (parser);
+ /* Keep track of all name-lookups performed in class scopes. */
+ if (type
+ && !qualified_p
+ && TREE_CODE (type) == TYPE_DECL
+ && TREE_CODE (DECL_NAME (type)) == IDENTIFIER_NODE)
+ maybe_note_name_used_in_class (DECL_NAME (type), type);
/* If it didn't work out, we don't have a TYPE. */
- if ((flags & CP_PARSER_FLAGS_OPTIONAL)
+ if ((flags & CP_PARSER_FLAGS_OPTIONAL)
&& !cp_parser_parse_definitely (parser))
type = NULL_TREE;
+ if (type && decl_specs)
+ cp_parser_set_decl_spec_type (decl_specs, type,
+ /*user_defined=*/true);
}
/* If we didn't get a type-name, issue an error message. */
type-name:
class-name
enum-name
- typedef-name
+ typedef-name
enum-name:
identifier
typedef-name:
- identifier
+ identifier
Returns a TYPE_DECL for the the type. */
/* We can't know yet whether it is a class-name or not. */
cp_parser_parse_tentatively (parser);
/* Try a class-name. */
- type_decl = cp_parser_class_name (parser,
+ type_decl = cp_parser_class_name (parser,
/*typename_keyword_p=*/false,
/*template_keyword_p=*/false,
/*type_p=*/false,
identifier = cp_parser_identifier (parser);
if (identifier == error_mark_node)
return error_mark_node;
-
+
/* Look up the type-name. */
type_decl = cp_parser_lookup_name_simple (parser, identifier);
/* Issue an error if we did not find a type-name. */
if (TREE_CODE (type_decl) != TYPE_DECL)
{
if (!cp_parser_simulate_error (parser))
- cp_parser_name_lookup_error (parser, identifier, type_decl,
+ cp_parser_name_lookup_error (parser, identifier, type_decl,
"is not a type");
type_decl = error_mark_node;
}
&& !parser->scope)
maybe_note_name_used_in_class (identifier, type_decl);
}
-
+
return type_decl;
}
class-key :: [opt] nested-name-specifier [opt] template [opt] template-id
enum :: [opt] nested-name-specifier [opt] identifier
typename :: [opt] nested-name-specifier identifier
- typename :: [opt] nested-name-specifier template [opt]
- template-id
+ typename :: [opt] nested-name-specifier template [opt]
+ template-id
GNU extension:
elaborated-type-specifier:
class-key attributes :: [opt] nested-name-specifier [opt] identifier
- class-key attributes :: [opt] nested-name-specifier [opt]
+ class-key attributes :: [opt] nested-name-specifier [opt]
template [opt] template-id
enum attributes :: [opt] nested-name-specifier [opt] identifier
Returns the TYPE specified. */
static tree
-cp_parser_elaborated_type_specifier (cp_parser* parser,
- bool is_friend,
+cp_parser_elaborated_type_specifier (cp_parser* parser,
+ bool is_friend,
bool is_declaration)
{
enum tag_types tag_type;
}
/* Look for the `::' operator. */
- cp_parser_global_scope_opt (parser,
+ cp_parser_global_scope_opt (parser,
/*current_scope_valid_p=*/false);
/* Look for the nested-name-specifier. */
if (tag_type == typename_type)
/*typename_keyword_p=*/true,
/*check_dependency_p=*/true,
/*type_p=*/true,
- is_declaration)
+ is_declaration)
== error_mark_node)
return error_mark_node;
}
&& tag_type == typename_type)
type = make_typename_type (parser->scope, decl,
/*complain=*/1);
- else
+ else
type = TREE_TYPE (decl);
}
/* For a `typename', we needn't call xref_tag. */
if (tag_type == typename_type)
- return make_typename_type (parser->scope, identifier,
- /*complain=*/1);
+ return cp_parser_make_typename_type (parser, parser->scope,
+ identifier);
/* Look up a qualified name in the usual way. */
if (parser->scope)
{
/* 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,
+ decl = cp_parser_lookup_name (parser, identifier,
/*is_type=*/true,
/*is_template=*/false,
/*is_namespace=*/false,
processing_template_decl does not work here since it is
always 1 for the above two cases. */
- decl = (cp_parser_maybe_treat_template_as_class
+ decl = (cp_parser_maybe_treat_template_as_class
(decl, /*tag_name_p=*/is_friend
&& parser->num_template_parameter_lists));
}
if (TREE_CODE (TREE_TYPE (decl)) != TYPENAME_TYPE)
- check_elaborated_type_specifier
+ check_elaborated_type_specifier
(tag_type, decl,
(parser->num_template_parameter_lists
|| DECL_SELF_REFERENCE_P (decl)));
type = TREE_TYPE (decl);
}
- else
+ else
{
/* An elaborated-type-specifier sometimes introduces a new type and
sometimes names an existing type. Normally, the rule is that it
the `struct S' in the body of `f' is the same `struct S' as in
the global scope; the existing definition is used. However, if
- there were no global declaration, this would introduce a new
+ there were no global declaration, this would introduce a new
local class named `S'.
An exception to this rule applies to the following code:
This exception only applies if the elaborated-type-specifier
forms the complete declaration:
- [class.name]
+ [class.name]
A declaration consisting solely of `class-key identifier ;' is
either a redeclaration of the name in the current scope or a
struct S { friend struct T; };
- `T' is not a new type in the scope of `S'.
+ `T' is not a new type in the scope of `S'.
Also, `new struct S' or `sizeof (struct S)' never results in the
definition of a new type; a new type can only be declared in a
if (attributes)
warning ("type attributes are honored only at type definition");
- type = xref_tag (tag_type, identifier,
- /*attributes=*/NULL_TREE,
- (is_friend
+ type = xref_tag (tag_type, identifier,
+ (is_friend
|| !is_declaration
- || cp_lexer_next_token_is_not (parser->lexer,
+ || cp_lexer_next_token_is_not (parser->lexer,
CPP_SEMICOLON)),
parser->num_template_parameter_lists);
}
}
/* Parse an enumerator-list. The enumerators all have the indicated
- TYPE.
+ TYPE.
enumerator-list:
enumerator-definition
cp_parser_enumerator_definition (parser, type);
/* Peek at the next token. */
token = cp_lexer_peek_token (parser->lexer);
- /* If it's not a `,', then we've reached the end of the
+ /* If it's not a `,', then we've reached the end of the
list. */
if (token->type != CPP_COMMA)
break;
enumerator-definition:
enumerator
enumerator = constant-expression
-
+
enumerator:
identifier */
identifier = cp_parser_identifier (parser);
if (identifier == error_mark_node)
return;
-
+
/* Peek at the next token. */
token = cp_lexer_peek_token (parser->lexer);
/* If it's an `=', then there's an explicit value. */
/* Consume the `=' token. */
cp_lexer_consume_token (parser->lexer);
/* Parse the value. */
- value = cp_parser_constant_expression (parser,
+ value = cp_parser_constant_expression (parser,
/*allow_non_constant_p=*/false,
NULL);
}
[basic.lookup.udir]
When looking up a namespace-name in a using-directive or alias
- definition, only namespace names are considered.
+ definition, only namespace names are considered.
And:
[basic.lookup.qual]
During the lookup of a name preceding the :: scope resolution
- operator, object, function, and enumerator names are ignored.
+ operator, object, function, and enumerator names are ignored.
(Note that cp_parser_class_or_namespace_name only calls this
function if the token after the name is the scope resolution
cp_parser_error (parser, "expected namespace-name");
namespace_decl = error_mark_node;
}
-
+
return namespace_decl;
}
namespace-definition:
named-namespace-definition
- unnamed-namespace-definition
+ unnamed-namespace-definition
named-namespace-definition:
original-namespace-definition
original-namespace-definition:
namespace identifier { namespace-body }
-
+
extension-namespace-definition:
namespace original-namespace-name { namespace-body }
-
+
unnamed-namespace-definition:
namespace { namespace-body } */
/* Look for the `=' token. */
cp_parser_require (parser, CPP_EQ, "`='");
/* Look for the qualified-namespace-specifier. */
- namespace_specifier
+ namespace_specifier
= cp_parser_qualified_namespace_specifier (parser);
/* Look for the `;' token. */
cp_parser_require (parser, CPP_SEMICOLON, "`;'");
cp_parser_qualified_namespace_specifier (cp_parser* parser)
{
/* Look for the optional `::'. */
- cp_parser_global_scope_opt (parser,
+ cp_parser_global_scope_opt (parser,
/*current_scope_valid_p=*/false);
/* Look for the optional nested-name-specifier. */
tree decl;
tree identifier;
tree scope;
+ tree qscope;
/* Look for the `using' keyword. */
cp_parser_require_keyword (parser, RID_USING, "`using'");
-
+
/* Peek at the next token. */
token = cp_lexer_peek_token (parser->lexer);
/* See if it's `typename'. */
}
/* Look for the optional global scope qualification. */
- global_scope_p
+ global_scope_p
= (cp_parser_global_scope_opt (parser,
- /*current_scope_valid_p=*/false)
+ /*current_scope_valid_p=*/false)
!= NULL_TREE);
/* If we saw `typename', or didn't see `::', then there must be a
nested-name-specifier present. */
if (typename_p || !global_scope_p)
- cp_parser_nested_name_specifier (parser, typename_p,
- /*check_dependency_p=*/true,
- /*type_p=*/false,
- /*is_declaration=*/true);
+ qscope = cp_parser_nested_name_specifier (parser, typename_p,
+ /*check_dependency_p=*/true,
+ /*type_p=*/false,
+ /*is_declaration=*/true);
/* Otherwise, we could be in either of the two productions. In that
case, treat the nested-name-specifier as optional. */
else
- cp_parser_nested_name_specifier_opt (parser,
- /*typename_keyword_p=*/false,
- /*check_dependency_p=*/true,
- /*type_p=*/false,
- /*is_declaration=*/true);
+ qscope = cp_parser_nested_name_specifier_opt (parser,
+ /*typename_keyword_p=*/false,
+ /*check_dependency_p=*/true,
+ /*type_p=*/false,
+ /*is_declaration=*/true);
+ if (!qscope)
+ qscope = global_namespace;
/* Parse the unqualified-id. */
- identifier = cp_parser_unqualified_id (parser,
+ identifier = cp_parser_unqualified_id (parser,
/*template_keyword_p=*/false,
/*check_dependency_p=*/true,
/*declarator_p=*/true);
if (decl == error_mark_node)
cp_parser_name_lookup_error (parser, identifier, decl, NULL);
else if (scope)
- do_local_using_decl (decl);
+ do_local_using_decl (decl, qscope, identifier);
else
- do_toplevel_using_decl (decl);
+ do_toplevel_using_decl (decl, qscope, identifier);
}
}
cp_parser_require (parser, CPP_SEMICOLON, "`;'");
}
-/* Parse a using-directive.
-
+/* Parse a using-directive.
+
using-directive:
using namespace :: [opt] nested-name-specifier [opt]
namespace-name ; */
/* Parse an asm-definition.
asm-definition:
- asm ( string-literal ) ;
+ asm ( string-literal ) ;
GNU Extension:
asm volatile [opt] ( string-literal : asm-operand-list [opt] ) ;
asm volatile [opt] ( string-literal : asm-operand-list [opt]
: asm-operand-list [opt] ) ;
- asm volatile [opt] ( string-literal : asm-operand-list [opt]
- : asm-operand-list [opt]
+ asm volatile [opt] ( string-literal : asm-operand-list [opt]
+ : asm-operand-list [opt]
: asm-operand-list [opt] ) ; */
static void
/* Look for the opening `('. */
cp_parser_require (parser, CPP_OPEN_PAREN, "`('");
/* Look for the string. */
+ c_lex_string_translate = 0;
token = cp_parser_require (parser, CPP_STRING, "asm body");
if (!token)
- return;
+ goto finish;
string = token->value;
/* If we're allowing GNU extensions, check for the extended assembly
- syntax. Unfortunately, the `:' tokens need not be separated by
+ syntax. Unfortunately, the `:' tokens need not be separated by
a space in C, and so, for compatibility, we tolerate that here
too. Doing that means that we have to treat the `::' operator as
two `:' tokens. */
/* Consume the `:'. */
cp_lexer_consume_token (parser->lexer);
/* Parse the output-operands. */
- if (cp_lexer_next_token_is_not (parser->lexer,
+ if (cp_lexer_next_token_is_not (parser->lexer,
CPP_COLON)
&& cp_lexer_next_token_is_not (parser->lexer,
CPP_SCOPE)
/* Consume the `:'. */
cp_lexer_consume_token (parser->lexer);
/* Parse the output-operands. */
- if (cp_lexer_next_token_is_not (parser->lexer,
+ if (cp_lexer_next_token_is_not (parser->lexer,
CPP_COLON)
&& cp_lexer_next_token_is_not (parser->lexer,
CPP_SCOPE)
clobbers_p = true;
/* Look for clobbers. */
- if (clobbers_p
+ if (clobbers_p
|| cp_lexer_next_token_is (parser->lexer, CPP_COLON))
{
if (!clobbers_p)
/*consume_paren=*/true);
cp_parser_require (parser, CPP_SEMICOLON, "`;'");
- /* Create the ASM_STMT. */
+ /* Create the ASM_EXPR. */
if (at_function_scope_p ())
{
- asm_stmt =
- finish_asm_stmt (volatile_p
- ? ridpointers[(int) RID_VOLATILE] : NULL_TREE,
- string, outputs, inputs, clobbers);
- /* If the extended syntax was not used, mark the ASM_STMT. */
+ asm_stmt = finish_asm_stmt (volatile_p, string, outputs,
+ inputs, clobbers);
+ /* If the extended syntax was not used, mark the ASM_EXPR. */
if (!extended_p)
ASM_INPUT_P (asm_stmt) = 1;
}
else
assemble_asm (string);
+
+ finish:
+ c_lex_string_translate = 1;
}
/* Declarators [gram.dcl.decl] */
function-definition:
decl-specifier-seq [opt] declarator ctor-initializer [opt]
- function-body
- decl-specifier-seq [opt] declarator function-try-block
+ function-body
+ decl-specifier-seq [opt] declarator function-try-block
GNU Extension:
function-definition:
- __extension__ function-definition
+ __extension__ function-definition
The DECL_SPECIFIERS and PREFIX_ATTRIBUTES apply to this declarator.
Returns a representation of the entity declared. If MEMBER_P is TRUE,
is FALSE. */
static tree
-cp_parser_init_declarator (cp_parser* parser,
- tree decl_specifiers,
- tree prefix_attributes,
+cp_parser_init_declarator (cp_parser* parser,
+ cp_decl_specifier_seq *decl_specifiers,
bool function_definition_allowed_p,
bool member_p,
int declares_class_or_enum,
bool* function_definition_p)
{
cp_token *token;
- tree declarator;
+ cp_declarator *declarator;
+ tree prefix_attributes;
tree attributes;
tree asm_specification;
tree initializer;
bool is_non_constant_init;
int ctor_dtor_or_conv_p;
bool friend_p;
+ bool pop_p = false;
+
+ /* Gather the attributes that were provided with the
+ decl-specifiers. */
+ prefix_attributes = decl_specifiers->attributes;
/* Assume that this is not the declarator for a function
definition. */
*function_definition_p = false;
/* Defer access checks while parsing the declarator; we cannot know
- what names are accessible until we know what is being
+ what names are accessible until we know what is being
declared. */
resume_deferring_access_checks ();
/* Parse the declarator. */
- declarator
+ declarator
= cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED,
&ctor_dtor_or_conv_p,
/*parenthesized_p=*/NULL);
/* If the DECLARATOR was erroneous, there's no need to go
further. */
- if (declarator == error_mark_node)
+ if (declarator == cp_error_declarator)
return error_mark_node;
cp_parser_check_for_definition_in_return_type (declarator,
declarator,
prefix_attributes);
else
- decl
+ decl
= (cp_parser_function_definition_from_specifiers_and_declarator
(parser, decl_specifiers, prefix_attributes, declarator));
/* [dcl.dcl]
Only in function declarations for constructors, destructors, and
- type conversions can the decl-specifier-seq be omitted.
+ type conversions can the decl-specifier-seq be omitted.
We explicitly postpone this check past the point where we handle
function-definitions because we tolerate function-definitions
that are missing their return types in some modes. */
- if (!decl_specifiers && ctor_dtor_or_conv_p <= 0)
+ if (!decl_specifiers->any_specifiers_p && ctor_dtor_or_conv_p <= 0)
{
- cp_parser_error (parser,
+ cp_parser_error (parser,
"expected constructor, destructor, or type conversion");
return error_mark_node;
}
/* An `=' or an `(' indicates an initializer. */
- is_initialized = (token->type == CPP_EQ
+ is_initialized = (token->type == CPP_EQ
|| token->type == CPP_OPEN_PAREN);
/* If the init-declarator isn't initialized and isn't followed by a
`,' or `;', it's not a valid init-declarator. */
- if (!is_initialized
+ if (!is_initialized
&& token->type != CPP_COMMA
&& token->type != CPP_SEMICOLON)
{
sure this was intended to be a declarator. Then continue
declaring the variable(s), as int, to try to cut down on further
errors. */
- if (decl_specifiers != NULL
- && TREE_VALUE (decl_specifiers) == error_mark_node)
+ if (decl_specifiers->any_specifiers_p
+ && decl_specifiers->type == error_mark_node)
{
cp_parser_error (parser, "invalid type in declaration");
- TREE_VALUE (decl_specifiers) = integer_type_node;
+ decl_specifiers->type = integer_type_node;
}
/* Check to see whether or not this declaration is a friend. */
{
if (parser->in_unbraced_linkage_specification_p)
{
- decl_specifiers = tree_cons (error_mark_node,
- get_identifier ("extern"),
- decl_specifiers);
+ decl_specifiers->storage_class = sc_extern;
have_extern_spec = false;
}
decl = start_decl (declarator, decl_specifiers,
/* Enter the SCOPE. That way unqualified names appearing in the
initializer will be looked up in SCOPE. */
if (scope)
- push_scope (scope);
+ pop_p = push_scope (scope);
/* Perform deferred access control checks, now that we know in which
SCOPE the declared entity resides. */
- if (!member_p && decl)
+ if (!member_p && decl)
{
tree saved_current_function_decl = NULL_TREE;
saved_current_function_decl = current_function_decl;
current_function_decl = decl;
}
-
+
/* Perform the access control checks for the declarator and the
the decl-specifiers. */
perform_deferred_access_checks ();
/* Parse the initializer. */
if (is_initialized)
- initializer = cp_parser_initializer (parser,
+ initializer = cp_parser_initializer (parser,
&is_parenthesized_init,
&is_non_constant_init);
else
/* Leave the SCOPE, now that we have processed the initializer. It
is important to do this before calling cp_finish_decl because it
- makes decisions about whether to create DECL_STMTs or not based
+ makes decisions about whether to create DECL_EXPRs or not based
on the current scope. */
- if (scope)
+ if (pop_p)
pop_scope (scope);
/* For an in-class declaration, use `grokfield' to create the
if (decl && TREE_CODE (decl) == FUNCTION_DECL)
cp_parser_save_default_args (parser, decl);
}
-
+
/* Finish processing the declaration. But, skip friend
declarations. */
if (!friend_p && decl)
- cp_finish_decl (decl,
- initializer,
+ cp_finish_decl (decl,
+ initializer,
asm_specification,
/* If the initializer is in parentheses, then this is
a direct-initialization, which means that an
/* Remember whether or not variables were initialized by
constant-expressions. */
- if (decl && TREE_CODE (decl) == VAR_DECL
+ if (decl && TREE_CODE (decl) == VAR_DECL
&& is_initialized && !is_non_constant_init)
DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl) = true;
}
/* Parse a declarator.
-
+
declarator:
direct-declarator
- ptr-operator declarator
+ ptr-operator declarator
abstract-declarator:
ptr-operator abstract-declarator [opt]
declarator:
attributes [opt] direct-declarator
- attributes [opt] ptr-operator declarator
+ attributes [opt] ptr-operator declarator
abstract-declarator:
attributes [opt] ptr-operator abstract-declarator [opt]
attributes [opt] direct-abstract-declarator
-
- Returns a representation of the declarator. If the declarator has
- the form `* declarator', then an INDIRECT_REF is returned, whose
- only operand is the sub-declarator. Analogously, `& declarator' is
- represented as an ADDR_EXPR. For `X::* declarator', a SCOPE_REF is
- used. The first operand is the TYPE for `X'. The second operand
- is an INDIRECT_REF whose operand is the sub-declarator.
-
- Otherwise, the representation is as for a direct-declarator.
-
- (It would be better to define a structure type to represent
- declarators, rather than abusing `tree' nodes to represent
- declarators. That would be much clearer and save some memory.
- There is no reason for declarators to be garbage-collected, for
- example; they are created during parser and no longer needed after
- `grokdeclarator' has been called.)
-
- For a ptr-operator that has the optional cv-qualifier-seq,
- cv-qualifiers will be stored in the TREE_TYPE of the INDIRECT_REF
- node.
If CTOR_DTOR_OR_CONV_P is not NULL, *CTOR_DTOR_OR_CONV_P is used to
detect constructor, destructor or conversion operators. It is set
to -1 if the declarator is a name, and +1 if it is a
function. Otherwise it is set to zero. Usually you just want to
test for >0, but internally the negative value is used.
-
+
(The reason for CTOR_DTOR_OR_CONV_P is that a declaration must have
a decl-specifier-seq unless it declares a constructor, destructor,
or conversion. It might seem that we could check this condition in
semantic analysis, rather than parsing, but that makes it difficult
to handle something like `f()'. We want to notice that there are
no decl-specifiers, and therefore realize that this is an
- expression, not a declaration.)
-
+ expression, not a declaration.)
+
If PARENTHESIZED_P is non-NULL, *PARENTHESIZED_P is set to true iff
the declarator is a direct-declarator of the form "(...)". */
-static tree
-cp_parser_declarator (cp_parser* parser,
- cp_parser_declarator_kind dcl_kind,
+static cp_declarator *
+cp_parser_declarator (cp_parser* parser,
+ cp_parser_declarator_kind dcl_kind,
int* ctor_dtor_or_conv_p,
bool* parenthesized_p)
{
cp_token *token;
- tree declarator;
+ cp_declarator *declarator;
enum tree_code code;
- tree cv_qualifier_seq;
+ cp_cv_quals cv_quals;
tree class_type;
tree attributes = NULL_TREE;
if (cp_parser_allow_gnu_extensions_p (parser))
attributes = cp_parser_attributes_opt (parser);
-
+
/* Peek at the next token. */
token = cp_lexer_peek_token (parser->lexer);
-
+
/* Check for the ptr-operator production. */
cp_parser_parse_tentatively (parser);
/* Parse the ptr-operator. */
- code = cp_parser_ptr_operator (parser,
- &class_type,
- &cv_qualifier_seq);
+ code = cp_parser_ptr_operator (parser,
+ &class_type,
+ &cv_quals);
/* If that worked, then we have a ptr-operator. */
if (cp_parser_parse_definitely (parser))
{
case where the dependent declarator is absent. */
if (dcl_kind != CP_PARSER_DECLARATOR_NAMED
&& !cp_parser_parse_definitely (parser))
- declarator = NULL_TREE;
-
+ declarator = NULL;
+
/* Build the representation of the ptr-operator. */
- if (code == INDIRECT_REF)
- declarator = make_pointer_declarator (cv_qualifier_seq,
- declarator);
- else
- declarator = make_reference_declarator (cv_qualifier_seq,
- declarator);
- /* Handle the pointer-to-member case. */
if (class_type)
- declarator = build_nt (SCOPE_REF, class_type, declarator);
+ declarator = make_ptrmem_declarator (cv_quals,
+ class_type,
+ declarator);
+ else if (code == INDIRECT_REF)
+ declarator = make_pointer_declarator (cv_quals, declarator);
+ else
+ declarator = make_reference_declarator (cv_quals, declarator);
}
/* Everything else is a direct-declarator. */
else
ctor_dtor_or_conv_p);
}
- if (attributes && declarator != error_mark_node)
- declarator = tree_cons (attributes, declarator, NULL_TREE);
-
+ if (attributes && declarator != cp_error_declarator)
+ declarator->attributes = attributes;
+
return declarator;
}
direct-declarator:
declarator-id
direct-declarator ( parameter-declaration-clause )
- cv-qualifier-seq [opt]
+ cv-qualifier-seq [opt]
exception-specification [opt]
direct-declarator [ constant-expression [opt] ]
- ( declarator )
+ ( declarator )
direct-abstract-declarator:
direct-abstract-declarator [opt]
- ( parameter-declaration-clause )
+ ( parameter-declaration-clause )
cv-qualifier-seq [opt]
exception-specification [opt]
direct-abstract-declarator [opt] [ constant-expression [opt] ]
CP_PARSER_DECLARATOR_EITHER, if we can accept either - in the case
of ambiguity we prefer an abstract declarator, as per
[dcl.ambig.res]. CTOR_DTOR_OR_CONV_P is as for
- cp_parser_declarator.
+ cp_parser_declarator. */
- For the declarator-id production, the representation is as for an
- id-expression, except that a qualified name is represented as a
- SCOPE_REF. A function-declarator is represented as a CALL_EXPR;
- see the documentation of the FUNCTION_DECLARATOR_* macros for
- information about how to find the various declarator components.
- An array-declarator is represented as an ARRAY_REF. The
- direct-declarator is the first operand; the constant-expression
- indicating the size of the array is the second operand. */
-
-static tree
+static cp_declarator *
cp_parser_direct_declarator (cp_parser* parser,
cp_parser_declarator_kind dcl_kind,
int* ctor_dtor_or_conv_p)
{
cp_token *token;
- tree declarator = NULL_TREE;
+ cp_declarator *declarator = NULL;
tree scope = NULL_TREE;
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;
+
while (true)
{
/* Peek at the next token. */
template parameter `(T)' is a
parameter-declaration-clause, and not a parenthesized
named declarator.
-
+
We first try and parse a parameter-declaration-clause,
and then try a nested declarator (if FIRST is true).
int i (int (3));
The former is a function-declaration; the latter is a
- variable initialization.
+ variable initialization.
Thus again, we try a parameter-declaration-clause, and if
that fails, we back out and return. */
if (!first || dcl_kind != CP_PARSER_DECLARATOR_NAMED)
{
- tree params;
+ cp_parameter_declarator *params;
unsigned saved_num_template_parameter_lists;
-
+
cp_parser_parse_tentatively (parser);
/* Consume the `('. */
parser->default_arg_ok_p = false;
parser->in_declarator_p = true;
}
-
+
/* Inside the function parameter list, surrounding
template-parameter-lists do not apply. */
saved_num_template_parameter_lists
exception-specification. */
if (cp_parser_parse_definitely (parser))
{
- tree cv_qualifiers;
+ cp_cv_quals cv_quals;
tree exception_specification;
if (ctor_dtor_or_conv_p)
cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
/* Parse the cv-qualifier-seq. */
- cv_qualifiers = cp_parser_cv_qualifier_seq_opt (parser);
+ cv_quals = cp_parser_cv_qualifier_seq_opt (parser);
/* And the exception-specification. */
- exception_specification
+ exception_specification
= cp_parser_exception_specification_opt (parser);
/* Create the function-declarator. */
declarator = make_call_declarator (declarator,
params,
- cv_qualifiers,
+ cv_quals,
exception_specification);
/* Any subsequent parameter lists are to do with
return type, so are not those of the declared
function. */
parser->default_arg_ok_p = false;
-
+
/* Repeat the main loop. */
continue;
}
}
-
+
/* If this is the first, we can try a parenthesized
declarator. */
if (first)
{
+ bool saved_in_type_id_in_expr_p;
+
parser->default_arg_ok_p = saved_default_arg_ok_p;
parser->in_declarator_p = saved_in_declarator_p;
-
+
/* Consume the `('. */
cp_lexer_consume_token (parser->lexer);
/* Parse the nested declarator. */
- declarator
+ saved_in_type_id_in_expr_p = parser->in_type_id_in_expr_p;
+ parser->in_type_id_in_expr_p = true;
+ declarator
= cp_parser_declarator (parser, dcl_kind, ctor_dtor_or_conv_p,
/*parenthesized_p=*/NULL);
+ parser->in_type_id_in_expr_p = saved_in_type_id_in_expr_p;
first = false;
/* Expect a `)'. */
if (!cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'"))
- declarator = error_mark_node;
- if (declarator == error_mark_node)
+ declarator = cp_error_declarator;
+ if (declarator == cp_error_declarator)
break;
-
+
goto handle_declarator;
}
/* Otherwise, we must be done. */
if (ctor_dtor_or_conv_p)
*ctor_dtor_or_conv_p = 0;
-
+
first = false;
parser->default_arg_ok_p = false;
parser->in_declarator_p = true;
{
bool non_constant_p;
- bounds
+ bounds
= cp_parser_constant_expression (parser,
/*allow_non_constant=*/true,
&non_constant_p);
if (!non_constant_p)
- bounds = cp_parser_fold_non_dependent_expr (bounds);
+ bounds = fold_non_dependent_expr (bounds);
}
else
bounds = NULL_TREE;
/* Look for the closing `]'. */
if (!cp_parser_require (parser, CPP_CLOSE_SQUARE, "`]'"))
{
- declarator = error_mark_node;
+ declarator = cp_error_declarator;
break;
}
- declarator = build_nt (ARRAY_REF, declarator, bounds);
+ declarator = make_array_declarator (declarator, bounds);
}
else if (first && dcl_kind != CP_PARSER_DECLARATOR_ABSTRACT)
{
+ tree id;
+
/* Parse a declarator-id */
if (dcl_kind == CP_PARSER_DECLARATOR_EITHER)
cp_parser_parse_tentatively (parser);
- declarator = cp_parser_declarator_id (parser);
+ id = cp_parser_declarator_id (parser);
if (dcl_kind == CP_PARSER_DECLARATOR_EITHER)
{
if (!cp_parser_parse_definitely (parser))
- declarator = error_mark_node;
- else if (TREE_CODE (declarator) != IDENTIFIER_NODE)
+ id = error_mark_node;
+ else if (TREE_CODE (id) != IDENTIFIER_NODE)
{
cp_parser_error (parser, "expected unqualified-id");
- declarator = error_mark_node;
+ id = error_mark_node;
}
}
-
- if (declarator == error_mark_node)
- break;
-
- if (TREE_CODE (declarator) == SCOPE_REF
- && !current_scope ())
+
+ if (id == error_mark_node)
+ {
+ declarator = cp_error_declarator;
+ break;
+ }
+
+ if (TREE_CODE (id) == SCOPE_REF && !current_scope ())
{
- tree scope = TREE_OPERAND (declarator, 0);
+ 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:
-
+
template <typename T>
int S<T>::R::i = 3;
-
+
the SCOPE will be a TYPENAME_TYPE for `S<T>::R'. In
this context, we must resolve S<T>::R to an ordinary
type, rather than a typename type.
-
+
The reason we normally avoid resolving TYPENAME_TYPEs
is that a specialization of `S' might render
`S<T>::R' not a type. However, if `S' is
type = resolve_typename_type (scope,
/*only_current_p=*/false);
/* If that failed, the declarator is invalid. */
- if (type != error_mark_node)
- scope = type;
+ if (type == error_mark_node)
+ error ("`%T::%D' is not a type",
+ TYPE_CONTEXT (scope),
+ TYPE_IDENTIFIER (scope));
/* Build a new DECLARATOR. */
- declarator = build_nt (SCOPE_REF,
- scope,
- TREE_OPERAND (declarator, 1));
+ id = build_nt (SCOPE_REF, type, TREE_OPERAND (id, 1));
}
}
-
- /* Check to see whether the declarator-id names a constructor,
- destructor, or conversion. */
- if (declarator && ctor_dtor_or_conv_p
- && ((TREE_CODE (declarator) == SCOPE_REF
- && CLASS_TYPE_P (TREE_OPERAND (declarator, 0)))
- || (TREE_CODE (declarator) != SCOPE_REF
- && at_class_scope_p ())))
+
+ declarator = make_id_declarator (id);
+ if (id)
{
- tree unqualified_name;
tree class_type;
+ tree unqualified_name;
- /* Get the unqualified part of the name. */
- if (TREE_CODE (declarator) == SCOPE_REF)
+ if (TREE_CODE (id) == SCOPE_REF
+ && CLASS_TYPE_P (TREE_OPERAND (id, 0)))
{
- class_type = TREE_OPERAND (declarator, 0);
- unqualified_name = TREE_OPERAND (declarator, 1);
+ class_type = TREE_OPERAND (id, 0);
+ unqualified_name = TREE_OPERAND (id, 1);
}
else
{
class_type = current_class_type;
- unqualified_name = declarator;
+ unqualified_name = id;
}
- /* See if it names ctor, dtor or conv. */
- if (TREE_CODE (unqualified_name) == BIT_NOT_EXPR
- || IDENTIFIER_TYPENAME_P (unqualified_name)
- || constructor_name_p (unqualified_name, class_type))
- *ctor_dtor_or_conv_p = -1;
+ if (class_type)
+ {
+ if (TREE_CODE (unqualified_name) == BIT_NOT_EXPR)
+ 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)))
+ 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
+ && TREE_CODE (unqualified_name) == TYPE_DECL
+ && CLASSTYPE_USE_TEMPLATE (TREE_TYPE (unqualified_name)))
+ {
+ error ("invalid use of constructor as a template");
+ inform ("use `%T::%D' instead of `%T::%T' to name the "
+ "constructor in a qualified name", class_type,
+ DECL_NAME (TYPE_TI_TEMPLATE (class_type)),
+ class_type, class_type);
+ }
+ }
}
handle_declarator:;
scope = get_scope_of_declarator (declarator);
if (scope)
- /* Any names that appear after the declarator-id for a member
- are looked up in the containing scope. */
- push_scope (scope);
+ /* Any names that appear after the declarator-id for a
+ member are looked up in the containing scope. */
+ pop_p = push_scope (scope);
parser->in_declarator_p = true;
if ((ctor_dtor_or_conv_p && *ctor_dtor_or_conv_p)
- || (declarator
- && (TREE_CODE (declarator) == SCOPE_REF
- || TREE_CODE (declarator) == IDENTIFIER_NODE)))
+ || (declarator && declarator->kind == cdk_id))
/* Default args are only allowed on function
declarations. */
parser->default_arg_ok_p = saved_default_arg_ok_p;
cp_parser_error (parser, "expected declarator");
/* If we entered a scope, we must exit it now. */
- if (scope)
+ if (pop_p)
pop_scope (scope);
parser->default_arg_ok_p = saved_default_arg_ok_p;
parser->in_declarator_p = saved_in_declarator_p;
-
+
return declarator;
}
-/* Parse a ptr-operator.
+/* Parse a ptr-operator.
ptr-operator:
* cv-qualifier-seq [opt]
ptr-operator:
& cv-qualifier-seq [opt]
- Returns INDIRECT_REF if a pointer, or pointer-to-member, was
- used. Returns ADDR_EXPR if a reference was used. In the
- case of a pointer-to-member, *TYPE is filled in with the
- TYPE containing the member. *CV_QUALIFIER_SEQ is filled in
- with the cv-qualifier-seq, or NULL_TREE, if there are no
- cv-qualifiers. Returns ERROR_MARK if an error occurred. */
-
+ Returns INDIRECT_REF if a pointer, or pointer-to-member, was used.
+ Returns ADDR_EXPR if a reference was used. In the case of a
+ pointer-to-member, *TYPE is filled in with the TYPE containing the
+ member. *CV_QUALS is filled in with the cv-qualifier-seq, or
+ TYPE_UNQUALIFIED, if there are no cv-qualifiers. Returns
+ ERROR_MARK if an error occurred. */
+
static enum tree_code
-cp_parser_ptr_operator (cp_parser* parser,
- tree* type,
- tree* cv_qualifier_seq)
+cp_parser_ptr_operator (cp_parser* parser,
+ tree* type,
+ cp_cv_quals *cv_quals)
{
enum tree_code code = ERROR_MARK;
cp_token *token;
/* Assume that it's not a pointer-to-member. */
*type = NULL_TREE;
/* And that there are no cv-qualifiers. */
- *cv_qualifier_seq = NULL_TREE;
+ *cv_quals = TYPE_UNQUALIFIED;
/* Peek at the next token. */
token = cp_lexer_peek_token (parser->lexer);
`&', if we are allowing GNU extensions. (The only qualifier
that can legally appear after `&' is `restrict', but that is
enforced during semantic analysis. */
- if (code == INDIRECT_REF
+ if (code == INDIRECT_REF
|| cp_parser_allow_gnu_extensions_p (parser))
- *cv_qualifier_seq = cp_parser_cv_qualifier_seq_opt (parser);
+ *cv_quals = cp_parser_cv_qualifier_seq_opt (parser);
}
else
{
/* Indicate that the `*' operator was used. */
code = INDIRECT_REF;
/* Look for the optional cv-qualifier-seq. */
- *cv_qualifier_seq = cp_parser_cv_qualifier_seq_opt (parser);
+ *cv_quals = cp_parser_cv_qualifier_seq_opt (parser);
}
/* If that didn't work we don't have a ptr-operator. */
if (!cp_parser_parse_definitely (parser))
/* Parse an (optional) cv-qualifier-seq.
cv-qualifier-seq:
- cv-qualifier cv-qualifier-seq [opt]
+ cv-qualifier cv-qualifier-seq [opt]
- Returns a TREE_LIST. The TREE_VALUE of each node is the
- representation of a cv-qualifier. */
+ cv-qualifier:
+ const
+ volatile
-static tree
-cp_parser_cv_qualifier_seq_opt (cp_parser* parser)
-{
- tree cv_qualifiers = NULL_TREE;
-
- while (true)
- {
- tree cv_qualifier;
+ GNU Extension:
- /* Look for the next cv-qualifier. */
- cv_qualifier = cp_parser_cv_qualifier_opt (parser);
- /* If we didn't find one, we're done. */
- if (!cv_qualifier)
- break;
+ cv-qualifier:
+ __restrict__
- /* Add this cv-qualifier to the list. */
- cv_qualifiers
- = tree_cons (NULL_TREE, cv_qualifier, cv_qualifiers);
- }
+ Returns a bitmask representing the cv-qualifiers. */
- /* We built up the list in reverse order. */
- return nreverse (cv_qualifiers);
-}
+static cp_cv_quals
+cp_parser_cv_qualifier_seq_opt (cp_parser* parser)
+{
+ cp_cv_quals cv_quals = TYPE_UNQUALIFIED;
-/* Parse an (optional) cv-qualifier.
+ while (true)
+ {
+ cp_token *token;
+ cp_cv_quals cv_qualifier;
- cv-qualifier:
- const
- volatile
+ /* Peek at the next token. */
+ token = cp_lexer_peek_token (parser->lexer);
+ /* See if it's a cv-qualifier. */
+ switch (token->keyword)
+ {
+ case RID_CONST:
+ cv_qualifier = TYPE_QUAL_CONST;
+ break;
- GNU Extension:
+ case RID_VOLATILE:
+ cv_qualifier = TYPE_QUAL_VOLATILE;
+ break;
- cv-qualifier:
- __restrict__ */
+ case RID_RESTRICT:
+ cv_qualifier = TYPE_QUAL_RESTRICT;
+ break;
-static tree
-cp_parser_cv_qualifier_opt (cp_parser* parser)
-{
- cp_token *token;
- tree cv_qualifier = NULL_TREE;
+ default:
+ cv_qualifier = TYPE_UNQUALIFIED;
+ break;
+ }
- /* Peek at the next token. */
- token = cp_lexer_peek_token (parser->lexer);
- /* See if it's a cv-qualifier. */
- switch (token->keyword)
- {
- case RID_CONST:
- case RID_VOLATILE:
- case RID_RESTRICT:
- /* Save the value of the token. */
- cv_qualifier = token->value;
- /* Consume the token. */
- cp_lexer_consume_token (parser->lexer);
- break;
+ if (!cv_qualifier)
+ break;
- default:
- break;
+ if (cv_quals & cv_qualifier)
+ {
+ error ("duplicate cv-qualifier");
+ cp_lexer_purge_token (parser->lexer);
+ }
+ else
+ {
+ cp_lexer_consume_token (parser->lexer);
+ cv_quals |= cv_qualifier;
+ }
}
- return cv_qualifier;
+ return cv_quals;
}
/* Parse a declarator-id.
declarator-id:
id-expression
- :: [opt] nested-name-specifier [opt] type-name
+ :: [opt] nested-name-specifier [opt] type-name
In the `id-expression' case, the value returned is as for
cp_parser_id_expression if the id-expression was an unqualified-id.
/*check_dependency_p=*/false,
/*template_p=*/NULL,
/*declarator_p=*/true);
- /* If the name was qualified, create a SCOPE_REF to represent
+ /* If the name was qualified, create a SCOPE_REF to represent
that. */
if (parser->scope)
{
static tree
cp_parser_type_id (cp_parser* parser)
{
- tree type_specifier_seq;
- tree abstract_declarator;
+ cp_decl_specifier_seq type_specifier_seq;
+ cp_declarator *abstract_declarator;
/* Parse the type-specifier-seq. */
- type_specifier_seq
- = cp_parser_type_specifier_seq (parser);
- if (type_specifier_seq == error_mark_node)
+ cp_parser_type_specifier_seq (parser, &type_specifier_seq);
+ if (type_specifier_seq.type == error_mark_node)
return error_mark_node;
/* There might or might not be an abstract declarator. */
cp_parser_parse_tentatively (parser);
/* Look for the declarator. */
- abstract_declarator
+ abstract_declarator
= cp_parser_declarator (parser, CP_PARSER_DECLARATOR_ABSTRACT, NULL,
/*parenthesized_p=*/NULL);
/* Check to see if there really was a declarator. */
if (!cp_parser_parse_definitely (parser))
- abstract_declarator = NULL_TREE;
+ abstract_declarator = NULL;
- return groktypename (build_tree_list (type_specifier_seq,
- abstract_declarator));
+ return groktypename (&type_specifier_seq, abstract_declarator);
}
/* Parse a type-specifier-seq.
type-specifier-seq:
attributes type-specifier-seq [opt]
- Returns a TREE_LIST. Either the TREE_VALUE of each node is a
- type-specifier, or the TREE_PURPOSE is a list of attributes. */
+ Sets *TYPE_SPECIFIER_SEQ to represent the sequence. */
-static tree
-cp_parser_type_specifier_seq (cp_parser* parser)
+static void
+cp_parser_type_specifier_seq (cp_parser* parser,
+ cp_decl_specifier_seq *type_specifier_seq)
{
bool seen_type_specifier = false;
- tree type_specifier_seq = NULL_TREE;
+
+ /* Clear the TYPE_SPECIFIER_SEQ. */
+ clear_decl_specs (type_specifier_seq);
/* Parse the type-specifiers and attributes. */
while (true)
/* Check for attributes first. */
if (cp_lexer_next_token_is_keyword (parser->lexer, RID_ATTRIBUTE))
{
- type_specifier_seq = tree_cons (cp_parser_attributes_opt (parser),
- NULL_TREE,
- type_specifier_seq);
+ type_specifier_seq->attributes =
+ chainon (type_specifier_seq->attributes,
+ cp_parser_attributes_opt (parser));
continue;
}
- /* After the first type-specifier, others are optional. */
- if (seen_type_specifier)
- cp_parser_parse_tentatively (parser);
/* Look for the type-specifier. */
- type_specifier = cp_parser_type_specifier (parser,
- CP_PARSER_FLAGS_NONE,
- /*is_friend=*/false,
+ type_specifier = cp_parser_type_specifier (parser,
+ CP_PARSER_FLAGS_OPTIONAL,
+ type_specifier_seq,
/*is_declaration=*/false,
NULL,
NULL);
/* If the first type-specifier could not be found, this is not a
type-specifier-seq at all. */
- if (!seen_type_specifier && type_specifier == error_mark_node)
- return error_mark_node;
+ if (!seen_type_specifier && !type_specifier)
+ {
+ cp_parser_error (parser, "expected type-specifier");
+ type_specifier_seq->type = error_mark_node;
+ return;
+ }
/* If subsequent type-specifiers could not be found, the
type-specifier-seq is complete. */
- else if (seen_type_specifier && !cp_parser_parse_definitely (parser))
+ else if (seen_type_specifier && !type_specifier)
break;
- /* Add the new type-specifier to the list. */
- type_specifier_seq
- = tree_cons (NULL_TREE, type_specifier, type_specifier_seq);
seen_type_specifier = true;
}
- /* We built up the list in reverse order. */
- return nreverse (type_specifier_seq);
+ return;
}
/* Parse a parameter-declaration-clause.
parameter-declaration-list [opt] ... [opt]
parameter-declaration-list , ...
- Returns a representation for the parameter declarations. Each node
- is a TREE_LIST. (See cp_parser_parameter_declaration for the exact
- representation.) If the parameter-declaration-clause ends with an
- ellipsis, PARMLIST_ELLIPSIS_P will hold of the first node in the
- list. A return value of NULL_TREE indicates a
- parameter-declaration-clause consisting only of an ellipsis. */
+ Returns a representation for the parameter declarations. A return
+ value of NULL indicates a parameter-declaration-clause consisting
+ only of an ellipsis. */
-static tree
+static cp_parameter_declarator *
cp_parser_parameter_declaration_clause (cp_parser* parser)
{
- tree parameters;
+ cp_parameter_declarator *parameters;
cp_token *token;
bool ellipsis_p;
+ bool is_error;
/* Peek at the next token. */
token = cp_lexer_peek_token (parser->lexer);
{
/* Consume the `...' token. */
cp_lexer_consume_token (parser->lexer);
- return NULL_TREE;
+ return NULL;
}
else if (token->type == CPP_CLOSE_PAREN)
/* There are no parameters. */
#ifndef NO_IMPLICIT_EXTERN_C
if (in_system_header && current_class_type == NULL
&& current_lang_name == lang_name_c)
- return NULL_TREE;
+ return NULL;
else
#endif
- return void_list_node;
+ return no_parameters;
}
/* Check for `(void)', too, which is a special case. */
else if (token->keyword == RID_VOID
- && (cp_lexer_peek_nth_token (parser->lexer, 2)->type
+ && (cp_lexer_peek_nth_token (parser->lexer, 2)->type
== CPP_CLOSE_PAREN))
{
/* Consume the `void' token. */
cp_lexer_consume_token (parser->lexer);
/* There are no parameters. */
- return void_list_node;
+ return no_parameters;
}
-
+
/* Parse the parameter-declaration-list. */
- parameters = cp_parser_parameter_declaration_list (parser);
+ parameters = cp_parser_parameter_declaration_list (parser, &is_error);
/* If a parse error occurred while parsing the
parameter-declaration-list, then the entire
parameter-declaration-clause is erroneous. */
- if (parameters == error_mark_node)
- return error_mark_node;
+ if (is_error)
+ return NULL;
/* Peek at the next token. */
token = cp_lexer_peek_token (parser->lexer);
/* Consume the `,'. */
cp_lexer_consume_token (parser->lexer);
/* Expect an ellipsis. */
- ellipsis_p
+ ellipsis_p
= (cp_parser_require (parser, CPP_ELLIPSIS, "`...'") != NULL);
}
- /* It might also be `...' if the optional trailing `,' was
+ /* It might also be `...' if the optional trailing `,' was
omitted. */
else if (token->type == CPP_ELLIPSIS)
{
ellipsis_p = false;
/* Finish the parameter list. */
- return finish_parmlist (parameters, ellipsis_p);
+ if (parameters && ellipsis_p)
+ parameters->ellipsis_p = true;
+
+ return parameters;
}
/* Parse a parameter-declaration-list.
Returns a representation of the parameter-declaration-list, as for
cp_parser_parameter_declaration_clause. However, the
- `void_list_node' is never appended to the list. */
+ `void_list_node' is never appended to the list. Upon return,
+ *IS_ERROR will be true iff an error occurred. */
-static tree
-cp_parser_parameter_declaration_list (cp_parser* parser)
+static cp_parameter_declarator *
+cp_parser_parameter_declaration_list (cp_parser* parser, bool *is_error)
{
- tree parameters = NULL_TREE;
+ cp_parameter_declarator *parameters = NULL;
+ cp_parameter_declarator **tail = ¶meters;
+
+ /* Assume all will go well. */
+ *is_error = false;
/* Look for more parameters. */
while (true)
{
- tree parameter;
+ cp_parameter_declarator *parameter;
bool parenthesized_p;
/* Parse the parameter. */
- parameter
- = cp_parser_parameter_declaration (parser,
+ parameter
+ = cp_parser_parameter_declaration (parser,
/*template_parm_p=*/false,
&parenthesized_p);
/* If a parse error occurred parsing the parameter declaration,
then the entire parameter-declaration-list is erroneous. */
- if (parameter == error_mark_node)
+ if (!parameter)
{
- parameters = error_mark_node;
+ *is_error = true;
+ parameters = NULL;
break;
}
/* Add the new parameter to the list. */
- TREE_CHAIN (parameter) = parameters;
- parameters = parameter;
+ *tail = parameter;
+ tail = ¶meter->next;
/* Peek at the next token. */
if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_PAREN)
/* When parsing something like:
int i(float f, double d)
-
+
we can tell after seeing the declaration for "f" that we
are not looking at an initialization of a variable "i",
- but rather at the declaration of a function "i".
+ but rather at the declaration of a function "i".
Due to the fact that the parsing of template arguments
(as specified to a template-id) requires backtracking we
cannot use this technique when inside a template argument
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)
/* However, a parameter-declaration of the form
cp_parser_error (parser, "expected `,' or `...'");
if (!cp_parser_parsing_tentatively (parser)
|| cp_parser_committed_to_tentative_parse (parser))
- cp_parser_skip_to_closing_parenthesis (parser,
+ cp_parser_skip_to_closing_parenthesis (parser,
/*recovering=*/true,
/*or_comma=*/false,
/*consume_paren=*/false);
}
}
- /* We built up the list in reverse order; straighten it out now. */
- return nreverse (parameters);
+ return parameters;
}
/* Parse a parameter declaration.
token encountered during the parsing of the assignment-expression
is not interpreted as a greater-than operator.)
- Returns a TREE_LIST representing the parameter-declaration. The
- TREE_PURPOSE is the default argument expression, or NULL_TREE if
- there is no default argument. The TREE_VALUE is a representation
- of the decl-specifier-seq and declarator. In particular, the
- TREE_VALUE will be a TREE_LIST whose TREE_PURPOSE represents the
- decl-specifier-seq and whose TREE_VALUE represents the declarator.
- If PARENTHESIZED_P is non-NULL, *PARENTHESIZED_P is set to true iff
- the declarator is of the form "(p)". */
+ Returns a representation of the parameter, or NULL if an error
+ occurs. If PARENTHESIZED_P is non-NULL, *PARENTHESIZED_P is set to
+ true iff the declarator is of the form "(p)". */
-static tree
-cp_parser_parameter_declaration (cp_parser *parser,
+static cp_parameter_declarator *
+cp_parser_parameter_declaration (cp_parser *parser,
bool template_parm_p,
bool *parenthesized_p)
{
int declares_class_or_enum;
bool greater_than_is_operator_p;
- tree decl_specifiers;
- tree attributes;
- tree declarator;
+ cp_decl_specifier_seq decl_specifiers;
+ cp_declarator *declarator;
tree default_argument;
- tree parameter;
cp_token *token;
const char *saved_message;
/* Type definitions may not appear in parameter types. */
saved_message = parser->type_definition_forbidden_message;
- parser->type_definition_forbidden_message
+ parser->type_definition_forbidden_message
= "types may not be defined in parameter types";
/* Parse the declaration-specifiers. */
- decl_specifiers
- = cp_parser_decl_specifier_seq (parser,
- CP_PARSER_FLAGS_NONE,
- &attributes,
- &declares_class_or_enum);
+ cp_parser_decl_specifier_seq (parser,
+ CP_PARSER_FLAGS_NONE,
+ &decl_specifiers,
+ &declares_class_or_enum);
/* If an error occurred, there's no reason to attempt to parse the
rest of the declaration. */
if (cp_parser_error_occurred (parser))
{
parser->type_definition_forbidden_message = saved_message;
- return error_mark_node;
+ return NULL;
}
/* Peek at the next token. */
token = cp_lexer_peek_token (parser->lexer);
/* If the next token is a `)', `,', `=', `>', or `...', then there
is no declarator. */
- if (token->type == CPP_CLOSE_PAREN
+ if (token->type == CPP_CLOSE_PAREN
|| token->type == CPP_COMMA
|| token->type == CPP_EQ
|| token->type == CPP_ELLIPSIS
|| token->type == CPP_GREATER)
{
- declarator = NULL_TREE;
+ declarator = NULL;
if (parenthesized_p)
*parenthesized_p = false;
}
{
bool saved_default_arg_ok_p = parser->default_arg_ok_p;
parser->default_arg_ok_p = false;
-
+
/* After seeing a decl-specifier-seq, if the next token is not a
"(", there is no possibility that the code is a valid
expression. Therefore, if parsing tentatively, we commit at
if (!parser->in_template_argument_list_p
/* In an expression context, having seen:
- (int((char *)...
+ (int((char ...
we cannot be sure whether we are looking at a
- function-type (taking a "char*" as a parameter) or a cast
- of some object of type "char*" to "int". */
+ 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)
parenthesized_p);
parser->default_arg_ok_p = saved_default_arg_ok_p;
/* After the declarator, allow more attributes. */
- attributes = chainon (attributes, cp_parser_attributes_opt (parser));
+ decl_specifiers.attributes
+ = chainon (decl_specifiers.attributes,
+ cp_parser_attributes_opt (parser));
}
/* The restriction on defining new types applies only to the type
/* If we are defining a class, then the tokens that make up the
default argument must be saved and processed later. */
- if (!template_parm_p && at_class_scope_p ()
+ if (!template_parm_p && at_class_scope_p ()
&& TYPE_BEING_DEFINED (current_class_type))
{
unsigned depth = 0;
case CPP_NAME:
case CPP_SCOPE:
/* In these cases, we should look for template-ids.
- For example, if the default argument is
+ For example, if the default argument is
`X<int, double>()', we need to do name lookup to
figure out whether or not `X' is a template; if
so, the `,' does not end the default argument.
/* If we've reached the end, stop. */
if (done)
break;
-
+
/* Add the token to the token block. */
token = cp_lexer_consume_token (parser->lexer);
cp_token_cache_push_token (DEFARG_TOKENS (default_argument),
/* Make sure that PARSER->GREATER_THAN_IS_OPERATOR_P is
set correctly. */
- saved_greater_than_is_operator_p
+ saved_greater_than_is_operator_p
= parser->greater_than_is_operator_p;
parser->greater_than_is_operator_p = greater_than_is_operator_p;
/* Local variable names (and the `this' keyword) may not
appear in a default argument. */
- saved_local_variables_forbidden_p
+ saved_local_variables_forbidden_p
= parser->local_variables_forbidden_p;
parser->local_variables_forbidden_p = true;
/* Parse the assignment-expression. */
default_argument = cp_parser_assignment_expression (parser);
/* Restore saved state. */
- parser->greater_than_is_operator_p
+ parser->greater_than_is_operator_p
= saved_greater_than_is_operator_p;
- parser->local_variables_forbidden_p
- = saved_local_variables_forbidden_p;
+ parser->local_variables_forbidden_p
+ = saved_local_variables_forbidden_p;
}
if (!parser->default_arg_ok_p)
{
}
else
default_argument = NULL_TREE;
-
- /* Create the representation of the parameter. */
- if (attributes)
- decl_specifiers = tree_cons (attributes, NULL_TREE, decl_specifiers);
- parameter = build_tree_list (default_argument,
- build_tree_list (decl_specifiers,
- declarator));
- return parameter;
+ return make_parameter_declarator (&decl_specifiers,
+ declarator,
+ default_argument);
}
/* Parse a function-body.
static void
cp_parser_function_body (cp_parser *parser)
{
- cp_parser_compound_statement (parser, false);
+ cp_parser_compound_statement (parser, NULL, false);
}
/* Parse a ctor-initializer-opt followed by a function-body. Return
initializer:
= initializer-clause
- ( expression-list )
+ ( expression-list )
Returns a expression representing the initializer. If no
- initializer is present, NULL_TREE is returned.
+ initializer is present, NULL_TREE is returned.
*IS_PARENTHESIZED_INIT is set to TRUE if the `( expression-list )'
production is used, and zero otherwise. *IS_PARENTHESIZED_INIT is
return init;
}
-/* Parse an initializer-clause.
+/* Parse an initializer-clause.
initializer-clause:
assignment-expression
{ initializer-list , [opt] }
{ }
- Returns an expression representing the initializer.
+ Returns an expression representing the initializer.
If the `assignment-expression' production is used the value
- returned is simply a representation for the expression.
+ returned is simply a representation for the expression.
Otherwise, a CONSTRUCTOR is returned. The CONSTRUCTOR_ELTS will be
the elements of the initializer-list (or NULL_TREE, if the last
/* 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_constant_expression (parser,
- /*allow_non_constant_p=*/true,
- non_constant_p);
+ {
+ initializer
+ = cp_parser_constant_expression (parser,
+ /*allow_non_constant_p=*/true,
+ non_constant_p);
+ if (!*non_constant_p)
+ initializer = fold_non_dependent_expr (initializer);
+ }
else
{
/* Consume the `{' token. */
cp_lexer_consume_token (parser->lexer);
/* Create a CONSTRUCTOR to represent the braced-initializer. */
initializer = make_node (CONSTRUCTOR);
- /* Mark it with TREE_HAS_CONSTRUCTOR. This should not be
- necessary, but check_initializer depends upon it, for
- now. */
- TREE_HAS_CONSTRUCTOR (initializer) = 1;
/* If it's not a `}', then there is a non-trivial initializer. */
if (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_BRACE))
{
initializer-list , initializer-clause
GNU Extension:
-
+
initializer-list:
identifier : initializer-clause
initializer-list, identifier : initializer-clause
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)
Returns the TYPE_DECL representing the class. */
static tree
-cp_parser_class_name (cp_parser *parser,
- bool typename_keyword_p,
- bool template_keyword_p,
+cp_parser_class_name (cp_parser *parser,
+ bool typename_keyword_p,
+ bool template_keyword_p,
bool type_p,
bool check_dependency_p,
bool class_head_p,
cp_parser_error (parser, "expected class-name");
return error_mark_node;
}
-
+
/* PARSER->SCOPE can be cleared when parsing the template-arguments
to a template-id, so we save it here. */
scope = parser->scope;
if (scope == error_mark_node)
return error_mark_node;
-
+
/* Any name names a type if we're following the `typename' keyword
in a qualified name where the enclosing scope is type-dependent. */
typename_p = (typename_keyword_p && scope && TYPE_P (scope)
&& dependent_type_p (scope));
/* Handle the common case (an identifier, but not a template-id)
efficiently. */
- if (token->type == CPP_NAME
- && cp_lexer_peek_nth_token (parser->lexer, 2)->type != CPP_LESS)
+ if (token->type == CPP_NAME
+ && !cp_parser_nth_token_starts_template_argument_list_p (parser, 2))
{
tree identifier;
if (cp_lexer_next_token_is (parser->lexer, CPP_SCOPE))
type_p = true;
/* Look up the name. */
- decl = cp_parser_lookup_name (parser, identifier,
+ decl = cp_parser_lookup_name (parser, identifier,
type_p,
/*is_template=*/false,
/*is_namespace=*/false,
/* If this is a typename, create a TYPENAME_TYPE. */
if (typename_p && decl != error_mark_node)
- decl = TYPE_NAME (make_typename_type (scope, decl,
- /*complain=*/1));
+ {
+ decl = make_typename_type (scope, decl, /*complain=*/1);
+ if (decl != error_mark_node)
+ decl = TYPE_NAME (decl);
+ }
/* Check to see that it is really the name of a class. */
- if (TREE_CODE (decl) == TEMPLATE_ID_EXPR
+ if (TREE_CODE (decl) == TEMPLATE_ID_EXPR
&& TREE_CODE (TREE_OPERAND (decl, 0)) == IDENTIFIER_NODE
&& cp_lexer_next_token_is (parser->lexer, CPP_SCOPE))
/* Situations like this:
template <typename T> struct A {
- typename T::template X<int>::I i;
+ typename T::template X<int>::I i;
};
are problematic. Is `T::template X<int>' a class-name? The
int has_trailing_semicolon;
bool nested_name_specifier_p;
unsigned saved_num_template_parameter_lists;
+ bool pop_p = false;
push_deferring_access_checks (dk_no_deferred);
/* Parse the class-head. */
type = cp_parser_class_head (parser,
- &nested_name_specifier_p);
+ &nested_name_specifier_p,
+ &attributes);
/* If the class-head was a semantic disaster, skip the entire body
of the class. */
if (!type)
++parser->num_classes_being_defined;
/* Inside the class, surrounding template-parameter-lists do not
apply. */
- saved_num_template_parameter_lists
- = parser->num_template_parameter_lists;
+ saved_num_template_parameter_lists
+ = parser->num_template_parameter_lists;
parser->num_template_parameter_lists = 0;
/* Start the class. */
if (nested_name_specifier_p)
- push_scope (CP_DECL_CONTEXT (TYPE_MAIN_DECL (type)));
+ pop_p = push_scope (CP_DECL_CONTEXT (TYPE_MAIN_DECL (type)));
type = begin_class_definition (type);
+
if (type == error_mark_node)
/* If the type is erroneous, skip the entire body of the class. */
cp_parser_skip_to_closing_brace (parser);
else
/* Parse the member-specification. */
cp_parser_member_specification_opt (parser);
+
/* Look for the trailing `}'. */
cp_parser_require (parser, CPP_CLOSE_BRACE, "`}'");
/* We get better error messages by noticing a common problem: a
missing trailing `;'. */
token = cp_lexer_peek_token (parser->lexer);
has_trailing_semicolon = (token->type == CPP_SEMICOLON);
- /* Look for attributes to apply to this class. */
+ /* Look for trailing attributes to apply to this class. */
if (cp_parser_allow_gnu_extensions_p (parser))
- attributes = cp_parser_attributes_opt (parser);
- /* If we got any attributes in class_head, xref_tag will stick them in
- TREE_TYPE of the type. Grab them now. */
- if (type != error_mark_node)
{
- attributes = chainon (TYPE_ATTRIBUTES (type), attributes);
- TYPE_ATTRIBUTES (type) = NULL_TREE;
- type = finish_struct (type, attributes);
+ tree sub_attr = cp_parser_attributes_opt (parser);
+ attributes = chainon (attributes, sub_attr);
}
- if (nested_name_specifier_p)
+ if (type != error_mark_node)
+ type = finish_struct (type, attributes);
+ if (pop_p)
pop_scope (CP_DECL_CONTEXT (TYPE_MAIN_DECL (type)));
/* If this class is not itself within the scope of another class,
then we need to parse the bodies of all of the queued function
struct A::B { void f() { } };
there is no need to delay the parsing of `A::B::f'. */
- if (--parser->num_classes_being_defined == 0)
+ if (--parser->num_classes_being_defined == 0)
{
tree queue_entry;
tree fn;
+ tree class_type;
+ bool pop_p;
/* In a first pass, parse default arguments to the functions.
Then, in a second pass, parse the bodies of the functions.
This two-phased approach handles cases like:
-
- struct S {
- void f() { g(); }
+
+ struct S {
+ void f() { g(); }
void g(int i = 3);
};
*/
+ 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));
= TREE_CHAIN (TREE_PURPOSE (parser->unparsed_functions_queues)))
{
fn = TREE_VALUE (queue_entry);
- /* Make sure that any template parameters are in scope. */
- maybe_begin_member_template_processing (fn);
/* If there are default arguments that have not yet been processed,
take care of them now. */
+ if (class_type != TREE_PURPOSE (queue_entry))
+ {
+ if (pop_p)
+ pop_scope (class_type);
+ class_type = TREE_PURPOSE (queue_entry);
+ pop_p = push_scope (class_type);
+ }
+ /* Make sure that any template parameters are in scope. */
+ maybe_begin_member_template_processing (fn);
+ /* Parse the default argument expressions. */
cp_parser_late_parsing_default_args (parser, fn);
/* Remove any template parameters from the symbol table. */
maybe_end_member_template_processing ();
}
+ if (pop_p)
+ pop_scope (class_type);
/* Now parse the body of the functions. */
for (TREE_VALUE (parser->unparsed_functions_queues)
= nreverse (TREE_VALUE (parser->unparsed_functions_queues));
/* Figure out which function we need to process. */
fn = TREE_VALUE (queue_entry);
+ /* A hack to prevent garbage collection. */
+ function_depth++;
+
/* Parse the function. */
cp_parser_late_parsing_for_member (parser, fn);
+ function_depth--;
}
-
}
/* Put back any saved access checks. */
class-head:
class-key identifier [opt] base-clause [opt]
class-key nested-name-specifier identifier base-clause [opt]
- class-key nested-name-specifier [opt] template-id
- base-clause [opt]
+ class-key nested-name-specifier [opt] template-id
+ base-clause [opt]
GNU Extensions:
class-key attributes identifier [opt] base-clause [opt]
class-key attributes nested-name-specifier identifier base-clause [opt]
- class-key attributes nested-name-specifier [opt] template-id
- base-clause [opt]
+ class-key attributes nested-name-specifier [opt] template-id
+ base-clause [opt]
Returns the TYPE of the indicated class. Sets
*NESTED_NAME_SPECIFIER_P to TRUE iff one of the productions
body of the class. */
static tree
-cp_parser_class_head (cp_parser* parser,
- bool* nested_name_specifier_p)
+cp_parser_class_head (cp_parser* parser,
+ bool* nested_name_specifier_p,
+ tree *attributes_p)
{
- cp_token *token;
tree nested_name_specifier;
enum tag_types class_key;
tree id = NULL_TREE;
bool qualified_p = false;
bool invalid_nested_name_p = false;
bool invalid_explicit_specialization_p = false;
+ bool pop_p = false;
unsigned num_templates;
+ tree bases;
/* Assume no nested-name-specifier will be present. */
*nested_name_specifier_p = false;
/* If the next token is `::', that is invalid -- but sometimes
people do try to write:
- struct ::S {};
+ struct ::S {};
Handle this gracefully by accepting the extra qualifier, and then
issuing an error about it later if this really is a
/* Determine the name of the class. Begin by looking for an
optional nested-name-specifier. */
- nested_name_specifier
+ nested_name_specifier
= cp_parser_nested_name_specifier_opt (parser,
/*typename_keyword_p=*/false,
/*check_dependency_p=*/false,
/* Although the grammar says `identifier', it really means
`class-name' or `template-name'. You are only allowed to
define a class that has already been declared with this
- syntax.
+ syntax.
The proposed resolution for Core Issue 180 says that whever
you see `class T::X' you should treat `X' as a type-name.
-
+
It is OK to define an inaccessible class; for example:
-
+
class A { class B; };
class A::B {};
-
+
We do not know if we will see a class-name, or a
template-name. We look for a class-name first, in case the
class-name is a template-id; if we looked for the
nested_name_specifier = NULL_TREE;
/* Otherwise, count the number of templates used in TYPE and its
containing scopes. */
- else
+ else
{
tree scope;
- for (scope = TREE_TYPE (type);
+ for (scope = TREE_TYPE (type);
scope && TREE_CODE (scope) != NAMESPACE_DECL;
- scope = (TYPE_P (scope)
+ scope = (TYPE_P (scope)
? TYPE_CONTEXT (scope)
- : DECL_CONTEXT (scope)))
- if (TYPE_P (scope)
+ : DECL_CONTEXT (scope)))
+ if (TYPE_P (scope)
&& CLASS_TYPE_P (scope)
&& CLASSTYPE_TEMPLATE_INFO (scope)
&& PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (scope))
an identifier, or nothing at all. */
cp_parser_parse_tentatively (parser);
/* Check for a template-id. */
- id = cp_parser_template_id (parser,
+ id = cp_parser_template_id (parser,
/*template_keyword_p=*/false,
/*check_dependency_p=*/true,
/*is_declaration=*/true);
pop_deferring_access_checks ();
- cp_parser_check_for_invalid_template_id (parser, id);
+ if (id)
+ cp_parser_check_for_invalid_template_id (parser, id);
/* If it's not a `:' or a `{' then we can't really be looking at a
class-head, since a class-head only appears as part of a
}
/* An explicit-specialization must be preceded by "template <>". If
it is not, try to recover gracefully. */
- if (at_namespace_scope_p ()
+ if (at_namespace_scope_p ()
&& parser->num_template_parameter_lists == 0
&& template_id_p)
{
/* If the class was unnamed, create a dummy name. */
if (!id)
id = make_anon_name ();
- type = xref_tag (class_key, id, attributes, /*globalize=*/false,
+ type = xref_tag (class_key, id, /*globalize=*/false,
parser->num_template_parameter_lists);
}
else
{
tree class_type;
+ bool pop_p = false;
/* Given:
class_type = current_class_type;
/* Enter the scope indicated by the nested-name-specifier. */
if (nested_name_specifier)
- push_scope (nested_name_specifier);
+ pop_p = 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 ()
if (nested_name_specifier)
{
*nested_name_specifier_p = true;
- pop_scope (nested_name_specifier);
+ if (pop_p)
+ pop_scope (nested_name_specifier);
}
}
/* Indicate whether this class was declared as a `class' or as a
is valid. */
if (nested_name_specifier)
- push_scope (nested_name_specifier);
- /* Now, look for the base-clause. */
- token = cp_lexer_peek_token (parser->lexer);
- if (token->type == CPP_COLON)
- {
- tree bases;
+ pop_p = push_scope (nested_name_specifier);
+
+ bases = NULL_TREE;
+
+ /* Get the list of base-classes, if there is one. */
+ if (cp_lexer_next_token_is (parser->lexer, CPP_COLON))
+ bases = cp_parser_base_clause (parser);
+
+ /* Process the base classes. */
+ xref_basetypes (type, bases);
- /* Get the list of base-classes. */
- bases = cp_parser_base_clause (parser);
- /* Process them. */
- xref_basetypes (type, bases);
- }
/* Leave the scope given by the nested-name-specifier. We will
enter the class scope itself while processing the members. */
- if (nested_name_specifier)
+ if (pop_p)
pop_scope (nested_name_specifier);
done:
end_specialization ();
--parser->num_template_parameter_lists;
}
+ *attributes_p = attributes;
return type;
}
}
}
-/* Parse a member-declaration.
+/* Parse a member-declaration.
member-declaration:
decl-specifier-seq [opt] member-declarator-list [opt] ;
function-definition ; [opt]
:: [opt] nested-name-specifier template [opt] unqualified-id ;
using-declaration
- template-declaration
+ template-declaration
member-declarator-list:
member-declarator
member-declarator-list , member-declarator
member-declarator:
- declarator pure-specifier [opt]
+ declarator pure-specifier [opt]
declarator constant-initializer [opt]
- identifier [opt] : constant-expression
+ identifier [opt] : constant-expression
GNU Extensions:
static void
cp_parser_member_declaration (cp_parser* parser)
{
- tree decl_specifiers;
+ cp_decl_specifier_seq decl_specifiers;
tree prefix_attributes;
tree decl;
int declares_class_or_enum;
return;
}
-
+
/* Parse the decl-specifier-seq. */
- decl_specifiers
- = cp_parser_decl_specifier_seq (parser,
- CP_PARSER_FLAGS_OPTIONAL,
- &prefix_attributes,
- &declares_class_or_enum);
+ cp_parser_decl_specifier_seq (parser,
+ CP_PARSER_FLAGS_OPTIONAL,
+ &decl_specifiers,
+ &declares_class_or_enum);
+ prefix_attributes = decl_specifiers.attributes;
+ decl_specifiers.attributes = NULL_TREE;
/* Check for an invalid type-name. */
- if (cp_parser_diagnose_invalid_type_name (parser))
+ if (cp_parser_parse_and_diagnose_invalid_type_name (parser))
return;
/* If there is no declarator, then the decl-specifier-seq should
specify a type. */
Each member-declaration shall declare at least one member
name of the class. */
- if (!decl_specifiers)
+ if (!decl_specifiers.any_specifiers_p)
{
if (pedantic)
pedwarn ("extra semicolon");
}
- else
+ else
{
tree type;
-
+
/* See if this declaration is a friend. */
- friend_p = cp_parser_friend_p (decl_specifiers);
+ friend_p = cp_parser_friend_p (&decl_specifiers);
/* If there were decl-specifiers, check to see if there was
a class-declaration. */
- type = check_tag_decl (decl_specifiers);
+ type = check_tag_decl (&decl_specifiers);
/* Nested classes have already been added to the class, but
a `friend' needs to be explicitly registered. */
if (friend_p)
error ("a class-key must be used when declaring a friend");
/* In this case:
- template <typename T> struct A {
- friend struct A<T>::B;
+ template <typename T> struct A {
+ friend struct A<T>::B;
};
-
+
A<T>::B will be represented by a TYPENAME_TYPE, and
therefore not recognized by check_tag_decl. */
- if (!type)
- {
- tree specifier;
-
- for (specifier = decl_specifiers;
- specifier;
- specifier = TREE_CHAIN (specifier))
- {
- tree s = TREE_VALUE (specifier);
-
- if (TREE_CODE (s) == IDENTIFIER_NODE)
- get_global_value_if_present (s, &type);
- if (TREE_CODE (s) == TYPE_DECL)
- s = TREE_TYPE (s);
- if (TYPE_P (s))
- {
- type = s;
- break;
- }
- }
- }
+ if (!type
+ && decl_specifiers.type
+ && TYPE_P (decl_specifiers.type))
+ type = decl_specifiers.type;
if (!type || !TYPE_P (type))
error ("friend declaration does not name a class or "
"function");
}
/* If there is no TYPE, an error message will already have
been issued. */
- else if (!type)
+ else if (!type || type == error_mark_node)
;
/* An anonymous aggregate has to be handled specially; such
a declaration really declares a data member (with a
else
{
/* See if these declarations will be friends. */
- friend_p = cp_parser_friend_p (decl_specifiers);
+ friend_p = cp_parser_friend_p (&decl_specifiers);
- /* Keep going until we hit the `;' at the end of the
+ /* Keep going until we hit the `;' at the end of the
declaration. */
while (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON))
{
/* Check for a bitfield declaration. */
if (token->type == CPP_COLON
|| (token->type == CPP_NAME
- && cp_lexer_peek_nth_token (parser->lexer, 2)->type
+ && cp_lexer_peek_nth_token (parser->lexer, 2)->type
== CPP_COLON))
{
tree identifier;
/* Consume the `:' token. */
cp_lexer_consume_token (parser->lexer);
/* Get the width of the bitfield. */
- width
+ width
= cp_parser_constant_expression (parser,
/*allow_non_constant=*/false,
NULL);
attributes = chainon (prefix_attributes, attributes);
/* Create the bitfield declaration. */
- decl = grokbitfield (identifier,
- decl_specifiers,
+ decl = grokbitfield (identifier
+ ? make_id_declarator (identifier)
+ : NULL,
+ &decl_specifiers,
width);
/* Apply the attributes. */
cplus_decl_attributes (&decl, attributes, /*flags=*/0);
}
else
{
- tree declarator;
+ cp_declarator *declarator;
tree initializer;
tree asm_specification;
int ctor_dtor_or_conv_p;
/* Parse the declarator. */
- declarator
+ declarator
= cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED,
&ctor_dtor_or_conv_p,
/*parenthesized_p=*/NULL);
/* If something went wrong parsing the declarator, make sure
that we at least consume some tokens. */
- if (declarator == error_mark_node)
+ if (declarator == cp_error_declarator)
{
/* Skip to the end of the statement. */
cp_parser_skip_to_end_of_statement (parser);
return;
}
- cp_parser_check_for_definition_in_return_type
+ cp_parser_check_for_definition_in_return_type
(declarator, declares_class_or_enum);
/* Look for an asm-specification. */
/* In [class.mem]:
A pure-specifier shall be used only in the declaration of
- a virtual function.
+ a virtual function.
A member-declarator can contain a constant-initializer
only if it declares a static member of integral or
- enumeration type.
+ enumeration type.
Therefore, if the DECLARATOR is for a function, we look
for a pure-specifier; otherwise, we look for a
constant-initializer. When we call `grokfield', it will
perform more stringent semantics checks. */
- if (TREE_CODE (declarator) == CALL_EXPR)
+ if (declarator->kind == cdk_function)
initializer = cp_parser_pure_specifier (parser);
else
/* Parse the initializer. */
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_token_starts_function_definition_p
+ if (cp_parser_token_starts_function_definition_p
(cp_lexer_peek_token (parser->lexer)))
{
/* The grammar does not allow a pure-specifier to be
if (initializer)
error ("pure-specifier on function-definition");
decl = cp_parser_save_member_function_body (parser,
- decl_specifiers,
+ &decl_specifiers,
declarator,
attributes);
/* If the member was not a friend, declare it here. */
else
{
/* Create the declaration. */
- decl = grokfield (declarator, decl_specifiers,
+ decl = grokfield (declarator, &decl_specifiers,
initializer, asm_specification,
attributes);
/* Any initialization must have been from a
cp_parser_skip_to_closing_brace (parser);
/* Look for the trailing `}'. */
cp_parser_require (parser, CPP_CLOSE_BRACE, "`}'");
-
+
return error_mark_node;
}
- return cp_parser_constant_expression (parser,
+ return cp_parser_constant_expression (parser,
/*allow_non_constant=*/false,
NULL);
}
/* Parse a base-clause.
base-clause:
- : base-specifier-list
+ : base-specifier-list
base-specifier-list:
base-specifier
Returns a TREE_LIST representing the base-classes, in the order in
which they were declared. The representation of each node is as
- described by cp_parser_base_specifier.
+ described by cp_parser_base_specifier.
In the case that no bases are specified, this function will return
NULL_TREE, not ERROR_MARK_NODE. */
ACCESS_{DEFAULT,PUBLIC,PROTECTED,PRIVATE}_[VIRTUAL]_NODE to
indicate the specifiers provided. The TREE_VALUE will be a TYPE
(or the ERROR_MARK_NODE) indicating the type that was specified. */
-
+
static tree
cp_parser_base_specifier (cp_parser* parser)
{
break;
}
}
+ /* It is not uncommon to see programs mechanically, erroneously, use
+ the 'typename' keyword to denote (dependent) qualified types
+ as base classes. */
+ if (cp_lexer_next_token_is_keyword (parser->lexer, RID_TYPENAME))
+ {
+ if (!processing_template_decl)
+ error ("keyword `typename' not allowed outside of templates");
+ else
+ error ("keyword `typename' not allowed in this context "
+ "(the base class is implicitly a type)");
+ cp_lexer_consume_token (parser->lexer);
+ }
/* Look for the optional `::' operator. */
cp_parser_global_scope_opt (parser, /*current_scope_valid_p=*/false);
type name.
is to pretend that we have seen the `typename' keyword at this
- point. */
+ point. */
cp_parser_nested_name_specifier_opt (parser,
/*typename_keyword_p=*/true,
/*check_dependency_p=*/true,
we see are type names or templates, as appropriate. */
class_scope_p = (parser->scope && TYPE_P (parser->scope));
template_p = class_scope_p && cp_parser_optional_template_keyword (parser);
-
+
/* Finally, look for the class-name. */
- type = cp_parser_class_name (parser,
+ type = cp_parser_class_name (parser,
class_scope_p,
template_p,
/*type_p=*/true,
cp_parser_require_keyword (parser, RID_TRY, "`try'");
try_block = begin_try_block ();
- cp_parser_compound_statement (parser, false);
+ cp_parser_compound_statement (parser, NULL, true);
finish_try_block (try_block);
cp_parser_handler_seq (parser);
finish_handler_sequence (try_block);
/* Let the rest of the front-end know where we are. */
try_block = begin_function_try_block ();
/* Parse the function-body. */
- ctor_initializer_p
+ ctor_initializer_p
= cp_parser_ctor_initializer_opt_and_function_body (parser);
/* We're done with the `try' part. */
finish_function_try_block (try_block);
declaration = cp_parser_exception_declaration (parser);
finish_handler_parms (declaration, handler);
cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
- cp_parser_compound_statement (parser, false);
+ cp_parser_compound_statement (parser, NULL, false);
finish_handler (handler);
}
type-specifier-seq declarator
type-specifier-seq abstract-declarator
type-specifier-seq
- ...
+ ...
Returns a VAR_DECL for the declaration, or NULL_TREE if the
ellipsis variant is used. */
static tree
cp_parser_exception_declaration (cp_parser* parser)
{
- tree type_specifiers;
- tree declarator;
+ tree decl;
+ cp_decl_specifier_seq type_specifiers;
+ cp_declarator *declarator;
const char *saved_message;
/* If it's an ellipsis, it's easy to handle. */
= "types may not be defined in exception-declarations";
/* Parse the type-specifier-seq. */
- type_specifiers = cp_parser_type_specifier_seq (parser);
+ cp_parser_type_specifier_seq (parser, &type_specifiers);
/* If it's a `)', then there is no declarator. */
if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_PAREN))
- declarator = NULL_TREE;
+ declarator = NULL;
else
declarator = cp_parser_declarator (parser, CP_PARSER_DECLARATOR_EITHER,
/*ctor_dtor_or_conv_p=*/NULL,
/* Restore the saved message. */
parser->type_definition_forbidden_message = saved_message;
- return start_handler_parms (type_specifiers, declarator);
+ if (type_specifiers.any_specifiers_p)
+ {
+ decl = grokdeclarator (declarator, &type_specifiers, CATCHPARM, 1, NULL);
+ if (decl == NULL_TREE)
+ error ("invalid catch parameter");
+ }
+ else
+ decl = NULL_TREE;
+
+ return decl;
}
-/* Parse a throw-expression.
+/* Parse a throw-expression.
throw-expression:
throw assignment-expression [opt]
/* Peek at the next token. */
token = cp_lexer_peek_token (parser->lexer);
- /* If the next token isn't the `asm' keyword, then there's no
+ /* If the next token isn't the `asm' keyword, then there's no
asm-specification. */
if (!cp_parser_is_keyword (token, RID_ASM))
return NULL_TREE;
return asm_specification;
}
-/* Parse an asm-operand-list.
+/* Parse an asm-operand-list.
asm-operand-list:
asm-operand
asm-operand-list , asm-operand
-
+
asm-operand:
- string-literal ( expression )
+ string-literal ( expression )
[ string-literal ] string-literal ( expression )
Returns a TREE_LIST representing the operands. The TREE_VALUE of
tree expression;
tree name;
cp_token *token;
-
- if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_SQUARE))
+
+ if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_SQUARE))
{
/* Consume the `[' token. */
cp_lexer_consume_token (parser->lexer);
/* Read the operand name. */
name = cp_parser_identifier (parser);
- if (name != error_mark_node)
+ if (name != error_mark_node)
name = build_string (IDENTIFIER_LENGTH (name),
IDENTIFIER_POINTER (name));
/* Look for the closing `]'. */
/* Look for the string-literal. */
token = cp_parser_require (parser, CPP_STRING, "string-literal");
string_literal = token ? token->value : error_mark_node;
+ c_lex_string_translate = 1;
/* Look for the `('. */
cp_parser_require (parser, CPP_OPEN_PAREN, "`('");
/* Parse the expression. */
expression = cp_parser_expression (parser);
/* Look for the `)'. */
cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
+ c_lex_string_translate = 0;
/* Add this operand to the list. */
asm_operands = tree_cons (build_tree_list (name, string_literal),
- expression,
+ expression,
asm_operands);
- /* If the next token is not a `,', there are no more
+ /* If the next token is not a `,', there are no more
operands. */
if (cp_lexer_next_token_is_not (parser->lexer, CPP_COMMA))
break;
return nreverse (asm_operands);
}
-/* Parse an asm-clobber-list.
+/* Parse an asm-clobber-list.
asm-clobber-list:
string-literal
- asm-clobber-list , string-literal
+ asm-clobber-list , string-literal
Returns a TREE_LIST, indicating the clobbers in the order that they
appeared. The TREE_VALUE of each node is a STRING_CST. */
string_literal = token ? token->value : error_mark_node;
/* Add it to the list. */
clobbers = tree_cons (NULL_TREE, string_literal, clobbers);
- /* If the next token is not a `,', then the list is
+ /* If the next token is not a `,', then the list is
complete. */
if (cp_lexer_next_token_is_not (parser->lexer, CPP_COMMA))
break;
attributes attribute
attribute:
- __attribute__ (( attribute-list [opt] ))
+ __attribute__ (( attribute-list [opt] ))
The return value is as for cp_parser_attribute_list. */
-
+
static tree
cp_parser_attributes_opt (cp_parser* parser)
{
return attributes;
}
-/* Parse an attribute-list.
+/* Parse an attribute-list.
- attribute-list:
- attribute
+ attribute-list:
+ attribute
attribute-list , attribute
attribute:
- identifier
+ identifier
identifier ( identifier )
identifier ( identifier , expression-list )
- 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
{
tree attribute_list = NULL_TREE;
+ c_lex_string_translate = 0;
while (true)
{
cp_token *token;
/* 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
+ if (token->type != CPP_NAME
&& token->type != CPP_KEYWORD)
return error_mark_node;
/* 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);
{
tree arguments;
- arguments = (cp_parser_parenthesized_expression_list
+ arguments = (cp_parser_parenthesized_expression_list
(parser, true, /*non_constant_p=*/NULL));
/* Save the identifier and arguments away. */
TREE_VALUE (attribute) = arguments;
/* Consume the comma and keep going. */
cp_lexer_consume_token (parser->lexer);
}
+ c_lex_string_translate = 1;
/* We built up the list in reverse order. */
return nreverse (attribute_list);
types. */
static tree
-cp_parser_lookup_name (cp_parser *parser, tree name,
+cp_parser_lookup_name (cp_parser *parser, tree name,
bool is_type, bool is_template, bool is_namespace,
bool check_dependency)
{
stored in PARSER->SCOPE at this point. */
my_friendly_assert (TREE_CODE (name) == IDENTIFIER_NODE,
20000619);
-
+
/* Perform the lookup. */
if (parser->scope)
- {
+ {
bool dependent_p;
if (parser->scope == error_mark_node)
}
else
{
+ bool pop_p = false;
+
/* If PARSER->SCOPE is a dependent type, then it must be a
class type, and we must not be checking dependencies;
otherwise, we would have processed this lookup above. So
that PARSER->SCOPE is not considered a dependent base by
lookup_member, we must enter the scope here. */
if (dependent_p)
- push_scope (parser->scope);
+ pop_p = 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
tentative parse, those errors are valid. */
decl = lookup_qualified_name (parser->scope, name, is_type,
/*complain=*/true);
- if (dependent_p)
+ if (pop_p)
pop_scope (parser->scope);
}
parser->qualifying_scope = parser->scope;
name,
/*protect=*/0, is_type);
/* Look it up in the enclosing context, too. */
- decl = lookup_name_real (name, is_type, /*nonclass=*/0,
- is_namespace,
+ decl = lookup_name_real (name, is_type, /*nonclass=*/0,
+ /*block_p=*/true, is_namespace,
/*flags=*/0);
parser->object_scope = object_type;
parser->qualifying_scope = NULL_TREE;
}
else
{
- decl = lookup_name_real (name, is_type, /*nonclass=*/0,
- is_namespace,
+ decl = lookup_name_real (name, is_type, /*nonclass=*/0,
+ /*block_p=*/true, is_namespace,
/*flags=*/0);
parser->qualifying_scope = NULL_TREE;
parser->object_scope = NULL_TREE;
}
/* If the lookup failed, let our caller know. */
- if (!decl
+ if (!decl
|| decl == error_mark_node
- || (TREE_CODE (decl) == FUNCTION_DECL
+ || (TREE_CODE (decl) == FUNCTION_DECL
&& DECL_ANTICIPATED (decl)))
return error_mark_node;
return error_mark_node;
}
- my_friendly_assert (DECL_P (decl)
+ my_friendly_assert (DECL_P (decl)
|| TREE_CODE (decl) == OVERLOAD
|| TREE_CODE (decl) == SCOPE_REF
|| TREE_CODE (decl) == UNBOUND_CLASS_TEMPLATE
/* If we have resolved the name of a member declaration, check to
see if the declaration is accessible. When the name resolves to
set of overloaded functions, accessibility is checked when
- overload resolution is done.
+ overload resolution is done.
During an explicit instantiation, access is not checked at all,
as per [temp.explicit]. */
static tree
cp_parser_lookup_name_simple (cp_parser* parser, tree name)
{
- return cp_parser_lookup_name (parser, name,
+ return cp_parser_lookup_name (parser, name,
/*is_type=*/false,
/*is_template=*/false,
/*is_namespace=*/false,
/* If the TEMPLATE_DECL is being declared as part of a class-head,
the translation from TEMPLATE_DECL to TYPE_DECL occurs:
- struct A {
+ struct A {
template <typename T> struct B;
};
- template <typename T> struct A::B {};
-
+ template <typename T> struct A::B {};
+
Similarly, in a elaborated-type-specifier:
namespace N { struct X{}; }
and FALSE otherwise. */
static bool
-cp_parser_check_declarator_template_parameters (cp_parser* parser,
- tree declarator)
+cp_parser_check_declarator_template_parameters (cp_parser* parser,
+ cp_declarator *declarator)
{
unsigned num_templates;
/* We haven't seen any classes that involve template parameters yet. */
num_templates = 0;
- switch (TREE_CODE (declarator))
+ switch (declarator->kind)
{
- case CALL_EXPR:
- case ARRAY_REF:
- case INDIRECT_REF:
- case ADDR_EXPR:
- {
- tree main_declarator = TREE_OPERAND (declarator, 0);
- return
- cp_parser_check_declarator_template_parameters (parser,
- main_declarator);
- }
-
- case SCOPE_REF:
- {
- tree scope;
- tree member;
-
- scope = TREE_OPERAND (declarator, 0);
- member = TREE_OPERAND (declarator, 1);
-
- /* If this is a pointer-to-member, then we are not interested
- in the SCOPE, because it does not qualify the thing that is
- being declared. */
- if (TREE_CODE (member) == INDIRECT_REF)
- return (cp_parser_check_declarator_template_parameters
- (parser, member));
-
- while (scope && CLASS_TYPE_P (scope))
- {
- /* You're supposed to have one `template <...>'
- for every template class, but you don't need one
- for a full specialization. For example:
-
- template <class T> struct S{};
- template <> struct S<int> { void f(); };
- void S<int>::f () {}
-
- is correct; there shouldn't be a `template <>' for
- the definition of `S<int>::f'. */
- if (CLASSTYPE_TEMPLATE_INFO (scope)
- && (CLASSTYPE_TEMPLATE_INSTANTIATION (scope)
- || uses_template_parms (CLASSTYPE_TI_ARGS (scope)))
- && PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (scope)))
- ++num_templates;
+ case cdk_id:
+ if (TREE_CODE (declarator->u.id.name) == SCOPE_REF)
+ {
+ tree scope;
+ tree member;
- scope = TYPE_CONTEXT (scope);
- }
- }
+ scope = TREE_OPERAND (declarator->u.id.name, 0);
+ member = TREE_OPERAND (declarator->u.id.name, 1);
- /* Fall through. */
+ while (scope && CLASS_TYPE_P (scope))
+ {
+ /* You're supposed to have one `template <...>'
+ for every template class, but you don't need one
+ for a full specialization. For example:
+
+ template <class T> struct S{};
+ template <> struct S<int> { void f(); };
+ void S<int>::f () {}
+
+ is correct; there shouldn't be a `template <>' for
+ the definition of `S<int>::f'. */
+ if (CLASSTYPE_TEMPLATE_INFO (scope)
+ && (CLASSTYPE_TEMPLATE_INSTANTIATION (scope)
+ || uses_template_parms (CLASSTYPE_TI_ARGS (scope)))
+ && PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (scope)))
+ ++num_templates;
+
+ scope = TYPE_CONTEXT (scope);
+ }
+ }
- default:
/* If the DECLARATOR has the form `X<y>' then it uses one
additional level of template parameters. */
- if (TREE_CODE (declarator) == TEMPLATE_ID_EXPR)
+ if (TREE_CODE (declarator->u.id.name) == TEMPLATE_ID_EXPR)
++num_templates;
- return cp_parser_check_template_parameters (parser,
+ return cp_parser_check_template_parameters (parser,
num_templates);
+
+ case cdk_function:
+ case cdk_array:
+ case cdk_pointer:
+ case cdk_reference:
+ case cdk_ptrmem:
+ return (cp_parser_check_declarator_template_parameters
+ (parser, declarator->declarator));
+
+ case cdk_error:
+ return true;
+
+ default:
+ abort ();
+ return false;
}
}
{
/* If there are more template classes than parameter lists, we have
something like:
-
+
template <class T> void S<T>::R<T>::f (); */
if (parser->num_template_parameter_lists < num_templates)
{
the two sub-expressions. */
static tree
-cp_parser_binary_expression (cp_parser* parser,
- const cp_parser_token_tree_map token_tree_map,
+cp_parser_binary_expression (cp_parser* parser,
+ const cp_parser_token_tree_map token_tree_map,
cp_parser_expression_fn fn)
{
tree lhs;
break;
/* If we find one of the tokens we want, build the corresponding
tree representation. */
- for (map_node = token_tree_map;
+ for (map_node = token_tree_map;
map_node->token_type != CPP_EOF;
++map_node)
if (map_node->token_type == token->type)
{
+ /* Assume that an overloaded operator will not be used. */
+ bool overloaded_p = false;
+
/* Consume the operator token. */
cp_lexer_consume_token (parser->lexer);
/* Parse the right-hand side of the expression. */
rhs = (*fn) (parser);
/* Build the binary tree node. */
- lhs = build_x_binary_op (map_node->tree_type, lhs, rhs);
+ lhs = build_x_binary_op (map_node->tree_type, lhs, rhs,
+ &overloaded_p);
+ /* If the binary operator required the use of an
+ overloaded operator, then this expression cannot be an
+ integral constant-expression. An overloaded operator
+ can be used even if both operands are otherwise
+ permissible in an integral constant-expression if at
+ least one of the operands is of enumeration type. */
+ if (overloaded_p
+ && (cp_parser_non_integral_constant_expression
+ (parser, "calls to overloaded operators")))
+ lhs = error_mark_node;
break;
}
cp_parser_global_scope_opt (parser,
/*current_scope_valid_p=*/false);
/* Look for the nested-name-specifier. */
- nested_name_p
+ nested_name_p
= (cp_parser_nested_name_specifier_opt (parser,
/*typename_keyword_p=*/false,
/*check_dependency_p=*/false,
!= NULL_TREE);
/* Outside of a class-specifier, there must be a
nested-name-specifier. */
- if (!nested_name_p &&
+ if (!nested_name_p &&
(!at_class_scope_p () || !TYPE_BEING_DEFINED (current_class_type)
|| friend_p))
constructor_p = false;
is a constructor. (It is actually a function named `f' that
takes one parameter (of type `int') and returns a value of type
`S::S'. */
- if (constructor_p
+ if (constructor_p
&& cp_parser_require (parser, CPP_OPEN_PAREN, "`('"))
{
if (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_PAREN)
&& cp_lexer_next_token_is_not (parser->lexer, CPP_ELLIPSIS)
+ /* A parameter declaration begins with a decl-specifier,
+ which is either the "attribute" keyword, a storage class
+ specifier, or (usually) a type-specifier. */
+ && !cp_lexer_next_token_is_keyword (parser->lexer, RID_ATTRIBUTE)
&& !cp_parser_storage_class_specifier_opt (parser))
{
tree type;
+ bool pop_p = false;
unsigned saved_num_template_parameter_lists;
/* Names appearing in the type-specifier should be looked up
type = TREE_TYPE (type_decl);
if (TREE_CODE (type) == TYPENAME_TYPE)
{
- type = resolve_typename_type (type,
+ type = resolve_typename_type (type,
/*only_current_p=*/false);
if (type == error_mark_node)
{
return false;
}
}
- push_scope (type);
+ pop_p = push_scope (type);
}
/* Inside the constructor parameter list, surrounding
/* Look for the type-specifier. */
cp_parser_type_specifier (parser,
CP_PARSER_FLAGS_NONE,
- /*is_friend=*/false,
+ /*decl_specs=*/NULL,
/*is_declarator=*/true,
/*declares_class_or_enum=*/NULL,
/*is_cv_qualifier=*/NULL);
= saved_num_template_parameter_lists;
/* Leave the scope of the class. */
- if (type)
+ if (pop_p)
pop_scope (type);
constructor_p = !cp_parser_error_occurred (parser);
static tree
cp_parser_function_definition_from_specifiers_and_declarator
(cp_parser* parser,
- tree decl_specifiers,
+ cp_decl_specifier_seq *decl_specifiers,
tree attributes,
- tree declarator)
+ const cp_declarator *declarator)
{
tree fn;
bool success_p;
/* Begin the function-definition. */
- success_p = begin_function_definition (decl_specifiers,
- attributes,
- declarator);
+ success_p = start_function (decl_specifiers, declarator, attributes);
+
+ /* The things we're about to see are not directly qualified by any
+ template headers we've seen thus far. */
+ reset_specialization ();
/* If there were names looked up in the decl-specifier-seq that we
did not check, check them now. We must wait until we are in the
if (!success_p)
{
- /* If begin_function_definition didn't like the definition, skip
- the entire function. */
+ /* Skip the entire function. */
error ("invalid function declaration");
cp_parser_skip_to_end_of_block_or_statement (parser);
fn = error_mark_node;
Returns the function defined. */
-static tree
-cp_parser_function_definition_after_declarator (cp_parser* parser,
+static tree
+cp_parser_function_definition_after_declarator (cp_parser* parser,
bool inline_p)
{
tree fn;
}
/* The `extern' in `extern "C" void f () { ... }' does not apply to
anything declared inside `f'. */
- saved_in_unbraced_linkage_specification_p
+ saved_in_unbraced_linkage_specification_p
= parser->in_unbraced_linkage_specification_p;
parser->in_unbraced_linkage_specification_p = false;
/* Inside the function, surrounding template-parameter-lists do not
apply. */
- saved_num_template_parameter_lists
- = parser->num_template_parameter_lists;
+ saved_num_template_parameter_lists
+ = parser->num_template_parameter_lists;
parser->num_template_parameter_lists = 0;
/* If the next token is `try', then we are looking at a
function-try-block. */
/* A function-try-block includes the function-body, so we only do
this next part if we're not processing a function-try-block. */
else
- ctor_initializer_p
+ ctor_initializer_p
= cp_parser_ctor_initializer_opt_and_function_body (parser);
/* Finish the function. */
- fn = finish_function ((ctor_initializer_p ? 1 : 0) |
+ fn = finish_function ((ctor_initializer_p ? 1 : 0) |
(inline_p ? 2 : 0));
/* Generate code for it, if necessary. */
expand_or_defer_fn (fn);
/* Restore the saved values. */
- parser->in_unbraced_linkage_specification_p
+ parser->in_unbraced_linkage_specification_p
= saved_in_unbraced_linkage_specification_p;
- parser->num_template_parameter_lists
+ parser->num_template_parameter_lists
= saved_num_template_parameter_lists;
return fn;
/* Look for the `template' keyword. */
if (!cp_parser_require_keyword (parser, RID_TEMPLATE, "`template'"))
return;
-
+
/* And the `<'. */
if (!cp_parser_require (parser, CPP_LESS, "`<'"))
return;
-
+
/* If the next token is `>', then we have an invalid
specialization. Rather than complain about an invalid template
parameter, issue an error message here. */
++parser->num_template_parameter_lists;
/* If the next token is `template', there are more template
parameters. */
- if (cp_lexer_next_token_is_keyword (parser->lexer,
+ if (cp_lexer_next_token_is_keyword (parser->lexer,
RID_TEMPLATE))
cp_parser_template_declaration_after_export (parser, member_p);
else
{
+ /* There are no access checks when parsing a template, as we do not
+ know if a specialization will be a friend. */
+ push_deferring_access_checks (dk_no_check);
+
decl = cp_parser_single_declaration (parser,
member_p,
&friend_p);
+ pop_deferring_access_checks ();
+
/* If this is a member template declaration, let the front
end know. */
if (member_p && !friend_p && decl)
/* If DECL is a function template, we must return to parse it later.
(Even though there is no definition, there might be default
arguments that need handling.) */
- if (member_p && decl
+ if (member_p && decl
&& (TREE_CODE (decl) == FUNCTION_DECL
|| DECL_FUNCTION_TEMPLATE_P (decl)))
TREE_VALUE (parser->unparsed_functions_queues)
- = tree_cons (NULL_TREE, decl,
+ = tree_cons (NULL_TREE, decl,
TREE_VALUE (parser->unparsed_functions_queues));
}
*FRIEND_P is set to TRUE iff the declaration is a friend. */
static tree
-cp_parser_single_declaration (cp_parser* parser,
+cp_parser_single_declaration (cp_parser* parser,
bool member_p,
bool* friend_p)
{
int declares_class_or_enum;
tree decl = NULL_TREE;
- tree decl_specifiers;
- tree attributes;
+ cp_decl_specifier_seq decl_specifiers;
bool function_definition_p = false;
/* Defer access checks until we know what is being declared. */
/* Try the `decl-specifier-seq [opt] init-declarator [opt]'
alternative. */
- decl_specifiers
- = cp_parser_decl_specifier_seq (parser,
- CP_PARSER_FLAGS_OPTIONAL,
- &attributes,
- &declares_class_or_enum);
+ cp_parser_decl_specifier_seq (parser,
+ CP_PARSER_FLAGS_OPTIONAL,
+ &decl_specifiers,
+ &declares_class_or_enum);
if (friend_p)
- *friend_p = cp_parser_friend_p (decl_specifiers);
+ *friend_p = cp_parser_friend_p (&decl_specifiers);
/* Gather up the access checks that occurred the
decl-specifier-seq. */
stop_deferring_access_checks ();
{
if (cp_parser_declares_only_class_p (parser))
{
- decl = shadow_tag (decl_specifiers);
- if (decl)
+ decl = shadow_tag (&decl_specifiers);
+ if (decl && decl != error_mark_node)
decl = TYPE_NAME (decl);
else
decl = error_mark_node;
In that case, there's no need to warn about a missing declarator. */
if (!decl
&& (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON)
- || !value_member (error_mark_node, decl_specifiers)))
- decl = cp_parser_init_declarator (parser,
- decl_specifiers,
- attributes,
+ || decl_specifiers.type != error_mark_node))
+ decl = cp_parser_init_declarator (parser,
+ &decl_specifiers,
/*function_definition_allowed_p=*/true,
member_p,
declares_class_or_enum,
cp_parser_functional_cast (cp_parser* parser, tree type)
{
tree expression_list;
+ tree cast;
- expression_list
+ expression_list
= cp_parser_parenthesized_expression_list (parser, false,
/*non_constant_p=*/NULL);
- return build_functional_cast (type, expression_list);
+ cast = build_functional_cast (type, expression_list);
+ /* [expr.const]/1: In an integral constant expression "only type
+ conversions to integral or enumeration type can be used". */
+ if (cast != error_mark_node && !type_dependent_expression_p (type)
+ && !INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (type)))
+ {
+ if (cp_parser_non_integral_constant_expression
+ (parser, "a call to a constructor"))
+ return error_mark_node;
+ }
+ return cast;
}
/* Save the tokens that make up the body of a member function defined
static tree
cp_parser_save_member_function_body (cp_parser* parser,
- tree decl_specifiers,
- tree declarator,
+ cp_decl_specifier_seq *decl_specifiers,
+ cp_declarator *declarator,
tree attributes)
{
cp_token_cache *cache;
if (fn == error_mark_node)
{
/* If there's a function-body, skip it. */
- if (cp_parser_token_starts_function_definition_p
+ if (cp_parser_token_starts_function_definition_p
(cp_lexer_peek_token (parser->lexer)))
cp_parser_skip_to_end_of_block_or_statement (parser);
return error_mark_node;
/* Create a token cache. */
cache = cp_token_cache_new ();
- /* Save away the tokens that make up the body of the
+ /* Save away the tokens that make up the body of the
function. */
cp_parser_cache_group (parser, cache, CPP_CLOSE_BRACE, /*depth=*/0);
/* Handle function try blocks. */
/* Add FN to the queue of functions to be parsed later. */
TREE_VALUE (parser->unparsed_functions_queues)
- = tree_cons (NULL_TREE, fn,
+ = tree_cons (NULL_TREE, fn,
TREE_VALUE (parser->unparsed_functions_queues));
return fn;
When parsing a template-id, the first non-nested `>' is taken as
the end of the template-argument-list rather than a greater-than
operator. */
- saved_greater_than_is_operator_p
+ saved_greater_than_is_operator_p
= parser->greater_than_is_operator_p;
parser->greater_than_is_operator_p = false;
/* Parsing the argument list may modify SCOPE, so we save it
cp_lexer_consume_token (parser->lexer);
}
}
- else
- cp_parser_require (parser, CPP_GREATER, "`>'");
+ else if (!cp_parser_require (parser, CPP_GREATER, "`>'"))
+ error ("missing `>' to terminate the template argument list");
/* The `>' token might be a greater-than operator again now. */
- parser->greater_than_is_operator_p
+ parser->greater_than_is_operator_p
= saved_greater_than_is_operator_p;
/* Restore the SAVED_SCOPE. */
parser->scope = saved_scope;
function_scope = decl_function_context (member_function);
if (function_scope)
push_function_context_to (function_scope);
-
+
/* Save away the current lexer. */
saved_lexer = parser->lexer;
/* Make a new lexer to feed us the tokens saved for this function. */
parser->lexer = cp_lexer_new_from_tokens (tokens);
parser->lexer->next = saved_lexer;
-
+
/* Set the current source position to be the location of the first
token in the saved inline body. */
cp_lexer_peek_token (parser->lexer);
-
+
/* Let the front end know that we going to be defining this
function. */
- start_function (NULL_TREE, member_function, NULL_TREE,
- SF_PRE_PARSED | SF_INCLASS_INLINE);
-
+ start_preparsed_function (member_function, NULL_TREE,
+ SF_PRE_PARSED | SF_INCLASS_INLINE);
+
/* Now, parse the body of the function. */
cp_parser_function_definition_after_declarator (parser,
/*inline_p=*/true);
-
+
/* Leave the scope of the containing function. */
if (function_scope)
pop_function_context_from (function_scope);
maybe_end_member_template_processing ();
/* Restore the queue. */
- parser->unparsed_functions_queues
+ parser->unparsed_functions_queues
= TREE_CHAIN (parser->unparsed_functions_queues);
}
if (TREE_PURPOSE (probe))
{
TREE_PURPOSE (parser->unparsed_functions_queues)
- = tree_cons (NULL_TREE, decl,
+ = tree_cons (current_class_type, decl,
TREE_PURPOSE (parser->unparsed_functions_queues));
break;
}
}
/* FN is a FUNCTION_DECL which may contains a parameter with an
- unparsed DEFAULT_ARG. Parse the default args now. */
+ unparsed DEFAULT_ARG. Parse the default args now. This function
+ assumes that the current scope is the scope in which the default
+ argument should be processed. */
static void
cp_parser_late_parsing_default_args (cp_parser *parser, tree fn)
if (!TREE_PURPOSE (parameters)
|| TREE_CODE (TREE_PURPOSE (parameters)) != DEFAULT_ARG)
continue;
-
+
/* Save away the current lexer. */
saved_lexer = parser->lexer;
/* Create a new one, using the tokens we have saved. */
saved_local_variables_forbidden_p = parser->local_variables_forbidden_p;
parser->local_variables_forbidden_p = true;
/* Parse the assignment-expression. */
- if (DECL_CLASS_SCOPE_P (fn))
- push_nested_class (DECL_CONTEXT (fn));
TREE_PURPOSE (parameters) = cp_parser_assignment_expression (parser);
- if (DECL_CLASS_SCOPE_P (fn))
- pop_nested_class ();
+
+ /* If the token stream has not been completely used up, then
+ there was extra junk after the end of the default
+ argument. */
+ if (!cp_lexer_next_token_is (parser->lexer, CPP_EOF))
+ cp_parser_error (parser, "expected `,'");
/* Restore saved state. */
parser->lexer = saved_lexer;
}
/* Restore the queue. */
- parser->unparsed_functions_queues
+ parser->unparsed_functions_queues
= TREE_CHAIN (parser->unparsed_functions_queues);
}
old message. */
saved_message = parser->type_definition_forbidden_message;
/* And create the new one. */
- parser->type_definition_forbidden_message
- = xmalloc (strlen (format)
+ parser->type_definition_forbidden_message
+ = xmalloc (strlen (format)
+ strlen (IDENTIFIER_POINTER (ridpointers[keyword]))
+ 1 /* `\0' */);
sprintf ((char *) parser->type_definition_forbidden_message,
/* If all went well, then we're done. */
if (cp_parser_parse_definitely (parser))
{
- /* Build a list of decl-specifiers; right now, we have only
- a single type-specifier. */
- type = build_tree_list (NULL_TREE,
- type);
+ cp_decl_specifier_seq decl_specs;
+
+ /* Build a trivial decl-specifier-seq. */
+ clear_decl_specs (&decl_specs);
+ decl_specs.type = type;
/* Call grokdeclarator to figure out what type this is. */
- expr = grokdeclarator (NULL_TREE,
- type,
+ expr = grokdeclarator (NULL,
+ &decl_specs,
TYPENAME,
/*initialized=*/0,
/*attrlist=*/NULL);
static bool
cp_parser_declares_only_class_p (cp_parser *parser)
{
- /* If the next token is a `;' or a `,' then there is no
+ /* If the next token is a `;' or a `,' then there is no
declarator. */
return (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON)
|| cp_lexer_next_token_is (parser->lexer, CPP_COMMA));
}
-/* Simplify EXPR if it is a non-dependent expression. Returns the
- (possibly simplified) expression. */
+/* Update the DECL_SPECS to reflect the STORAGE_CLASS. */
-static tree
-cp_parser_fold_non_dependent_expr (tree expr)
-{
- /* If we're in a template, but EXPR isn't value dependent, simplify
- it. We're supposed to treat:
-
- template <typename T> void f(T[1 + 1]);
- template <typename T> void f(T[2]);
-
- as two declarations of the same function, for example. */
- if (processing_template_decl
- && !type_dependent_expression_p (expr)
- && !value_dependent_expression_p (expr))
- {
- HOST_WIDE_INT saved_processing_template_decl;
+static void
+cp_parser_set_storage_class (cp_decl_specifier_seq *decl_specs,
+ cp_storage_class storage_class)
+{
+ if (decl_specs->storage_class != sc_none)
+ decl_specs->multiple_storage_classes_p = true;
+ else
+ decl_specs->storage_class = storage_class;
+}
+
+/* Update the DECL_SPECS to reflect the TYPE_SPEC. If USER_DEFINED_P
+ is true, the type is a user-defined type; otherwise it is a
+ built-in type specified by a keyword. */
- saved_processing_template_decl = processing_template_decl;
- processing_template_decl = 0;
- expr = tsubst_copy_and_build (expr,
- /*args=*/NULL_TREE,
- tf_error,
- /*in_decl=*/NULL_TREE,
- /*function_p=*/false);
- processing_template_decl = saved_processing_template_decl;
+static void
+cp_parser_set_decl_spec_type (cp_decl_specifier_seq *decl_specs,
+ tree type_spec,
+ bool user_defined_p)
+{
+ decl_specs->any_specifiers_p = true;
+
+ /* If the user tries to redeclare a built-in type (with, for example,
+ in "typedef int wchar_t;") we remember that this is what
+ happened. In system headers, we ignore these declarations so
+ that G++ can work with system headers that are not C++-safe. */
+ if (decl_specs->specs[(int) ds_typedef]
+ && !user_defined_p
+ && (decl_specs->type
+ || decl_specs->specs[(int) ds_long]
+ || decl_specs->specs[(int) ds_short]
+ || decl_specs->specs[(int) ds_unsigned]
+ || decl_specs->specs[(int) ds_signed]))
+ {
+ decl_specs->redefined_builtin_type = type_spec;
+ if (!decl_specs->type)
+ {
+ decl_specs->type = type_spec;
+ decl_specs->user_defined_type_p = false;
+ }
+ }
+ else if (decl_specs->type)
+ decl_specs->multiple_types_p = true;
+ else
+ {
+ decl_specs->type = type_spec;
+ decl_specs->user_defined_type_p = user_defined_p;
+ decl_specs->redefined_builtin_type = NULL_TREE;
}
- return expr;
}
/* DECL_SPECIFIERS is the representation of a decl-specifier-seq.
Returns TRUE iff `friend' appears among the DECL_SPECIFIERS. */
static bool
-cp_parser_friend_p (tree decl_specifiers)
+cp_parser_friend_p (const cp_decl_specifier_seq *decl_specifiers)
{
- while (decl_specifiers)
- {
- /* See if this decl-specifier is `friend'. */
- if (TREE_CODE (TREE_VALUE (decl_specifiers)) == IDENTIFIER_NODE
- && C_RID_CODE (TREE_VALUE (decl_specifiers)) == RID_FRIEND)
- return true;
-
- /* Go on to the next decl-specifier. */
- decl_specifiers = TREE_CHAIN (decl_specifiers);
- }
-
- return false;
+ return decl_specifiers->specs[(int) ds_friend] != 0;
}
/* If the next token is of the indicated TYPE, consume it. Otherwise,
issue an error message indicating that TOKEN_DESC was expected.
-
+
Returns the token consumed, if the token had the appropriate type.
Otherwise, returns NULL. */
the next token is not as expected. */
static void
-cp_parser_skip_until_found (cp_parser* parser,
- enum cpp_ttype type,
+cp_parser_skip_until_found (cp_parser* parser,
+ enum cpp_ttype type,
const char* token_desc)
{
cp_token *token;
{
/* Peek at the next token. */
token = cp_lexer_peek_token (parser->lexer);
- /* If we've reached the token we want, consume it and
+ /* If we've reached the token we want, consume it and
stop. */
if (token->type == type && !nesting_depth)
{
/* If we've run out of tokens, stop. */
if (token->type == CPP_EOF)
return;
- if (token->type == CPP_OPEN_BRACE
+ if (token->type == CPP_OPEN_BRACE
|| token->type == CPP_OPEN_PAREN
|| token->type == CPP_OPEN_SQUARE)
++nesting_depth;
- else if (token->type == CPP_CLOSE_BRACE
+ else if (token->type == CPP_CLOSE_BRACE
|| token->type == CPP_CLOSE_PAREN
|| token->type == CPP_CLOSE_SQUARE)
{
/* If the next token is the indicated keyword, consume it. Otherwise,
issue an error message indicating that TOKEN_DESC was expected.
-
+
Returns the token consumed, if the token had the appropriate type.
Otherwise, returns NULL. */
/* Returns TRUE iff TOKEN is a token that can begin the body of a
function-definition. */
-static bool
+static bool
cp_parser_token_starts_function_definition_p (cp_token* token)
{
return (/* An ordinary function-body begins with an `{'. */
cp_token *token;
token = cp_lexer_peek_token (parser->lexer);
- return (token->type == CPP_COMMA || token->type == CPP_GREATER
+ return (token->type == CPP_COMMA || token->type == CPP_GREATER
|| token->type == CPP_RSHIFT);
}
-
+
+/* Returns TRUE iff the n-th token is a ">", or the n-th is a "[" and the
+ (n+1)-th is a ":" (which is a possible digraph typo for "< ::"). */
+
+static bool
+cp_parser_nth_token_starts_template_argument_list_p (cp_parser * parser,
+ size_t n)
+{
+ cp_token *token;
+
+ token = cp_lexer_peek_nth_token (parser->lexer, n);
+ if (token->type == CPP_LESS)
+ return true;
+ /* Check for the sequence `<::' in the original code. It would be lexed as
+ `[:', where `[' is a digraph, and there is no whitespace before
+ `:'. */
+ if (token->type == CPP_OPEN_SQUARE && token->flags & DIGRAPH)
+ {
+ cp_token *token2;
+ token2 = cp_lexer_peek_nth_token (parser->lexer, n+1);
+ if (token2->type == CPP_COLON && !(token2->flags & PREV_WHITE))
+ return true;
+ }
+ return false;
+}
+
/* Returns the kind of tag indicated by TOKEN, if it is a class-key,
or none_type otherwise. */
return record_type;
case RID_UNION:
return union_type;
-
+
default:
return none_type;
}
if ((TREE_CODE (type) == UNION_TYPE) != (class_key == union_type))
pedwarn ("`%s' tag used in naming `%#T'",
class_key == union_type ? "union"
- : class_key == record_type ? "struct" : "class",
+ : class_key == record_type ? "struct" : "class",
type);
}
-
+
/* Issue an error message if DECL is redeclared with different
access than its original declaration [class.access.spec/3].
This applies to nested classes and nested class templates.
}
/* Look for the `template' keyword, as a syntactic disambiguator.
- Return TRUE iff it is present, in which case it will be
+ Return TRUE iff it is present, in which case it will be
consumed. */
static bool
parser->object_scope = NULL_TREE;
}
-/* Add tokens to CACHE until an non-nested END token appears. */
+/* Add tokens to CACHE until a non-nested END token appears. */
static void
-cp_parser_cache_group (cp_parser *parser,
- cp_token_cache *cache,
- enum cpp_ttype end,
- unsigned depth)
+cp_parser_cache_group_1 (cp_parser *parser,
+ cp_token_cache *cache,
+ enum cpp_ttype end,
+ unsigned depth)
{
while (true)
{
if ((end == CPP_CLOSE_PAREN || depth == 0)
&& cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON))
return;
- /* Consume the next token. */
- token = cp_lexer_consume_token (parser->lexer);
/* If we've reached the end of the file, stop. */
- if (token->type == CPP_EOF)
+ if (cp_lexer_next_token_is (parser->lexer, CPP_EOF))
return;
+ /* Consume the next token. */
+ token = cp_lexer_consume_token (parser->lexer);
/* Add this token to the tokens we are saving. */
cp_token_cache_push_token (cache, token);
/* See if it starts a new group. */
if (token->type == CPP_OPEN_BRACE)
{
- cp_parser_cache_group (parser, cache, CPP_CLOSE_BRACE, depth + 1);
+ cp_parser_cache_group_1 (parser, cache, CPP_CLOSE_BRACE, depth + 1);
if (depth == 0)
return;
}
else if (token->type == CPP_OPEN_PAREN)
- cp_parser_cache_group (parser, cache, CPP_CLOSE_PAREN, depth + 1);
+ cp_parser_cache_group_1 (parser, cache, CPP_CLOSE_PAREN, depth + 1);
else if (token->type == end)
return;
}
}
+/* Convenient interface for cp_parser_cache_group_1 that makes sure we
+ preserve string tokens in both translated and untranslated
+ forms. */
+
+static void
+cp_parser_cache_group (cp_parser *parser,
+ cp_token_cache *cache,
+ enum cpp_ttype end,
+ unsigned depth)
+{
+ int saved_c_lex_string_translate;
+
+ saved_c_lex_string_translate = c_lex_string_translate;
+ c_lex_string_translate = -1;
+
+ cp_parser_cache_group_1 (parser, cache, end, depth);
+
+ c_lex_string_translate = saved_c_lex_string_translate;
+}
+
+
/* Begin parsing tentatively. We always save tokens while parsing
tentatively so that if the tentative parsing fails we can restore the
tokens. */
/* Returns nonzero iff an error has occurred during the most recent
tentative parse. */
-
+
static bool
cp_parser_error_occurred (cp_parser* parser)
{
}
\f
-
/* The parser. */
static GTY (()) cp_parser *the_parser;
c_parse_file (void)
{
bool error_occurred;
+ static bool already_called = false;
+
+ if (already_called)
+ {
+ sorry ("inter-module optimizations not implemented for C++");
+ return;
+ }
+ already_called = true;
the_parser = cp_parser_new ();
push_deferring_access_checks (flag_access_control
the_parser = NULL;
}
-/* Clean up after parsing the entire translation unit. */
-
-void
-free_parser_stacks (void)
-{
- /* Nothing to do. */
-}
-
/* This variable must be provided by every front end. */
int yydebug;