#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "dyn-string.h"
#include "varray.h"
#include "cpplib.h"
#include "tree.h"
#include "cp-tree.h"
#include "c-pragma.h"
#include "decl.h"
#include "flags.h"
#include "diagnostic.h"
#include "toplev.h"
#include "output.h"
typedef struct cp_token GTY (())
{
ENUM_BITFIELD (cpp_ttype) type : 8;
ENUM_BITFIELD (rid) keyword : 8;
unsigned char flags;
tree value;
location_t location;
} cp_token;
#define CP_TOKEN_BLOCK_NUM_TOKENS ((512 - 3*sizeof (char*))/sizeof (cp_token))
typedef struct cp_token_block GTY (())
{
cp_token tokens[CP_TOKEN_BLOCK_NUM_TOKENS];
size_t num_tokens;
struct cp_token_block *next;
struct cp_token_block *prev;
} cp_token_block;
typedef struct cp_token_cache GTY (())
{
cp_token_block *first;
cp_token_block *last;
} cp_token_cache;
static cp_token_cache *cp_token_cache_new
(void);
static void cp_token_cache_push_token
(cp_token_cache *, cp_token *);
static cp_token_cache *
cp_token_cache_new (void)
{
return ggc_alloc_cleared (sizeof (cp_token_cache));
}
static void
cp_token_cache_push_token (cp_token_cache *cache,
cp_token *token)
{
cp_token_block *b = cache->last;
if (!b || b->num_tokens == CP_TOKEN_BLOCK_NUM_TOKENS)
{
b = ggc_alloc_cleared (sizeof (cp_token_block));
b->prev = cache->last;
if (cache->last)
{
cache->last->next = b;
cache->last = b;
}
else
cache->first = cache->last = b;
}
b->tokens[b->num_tokens++] = *token;
}
typedef struct cp_lexer GTY (())
{
cp_token * GTY ((length ("(%h.buffer_end - %h.buffer)"))) buffer;
cp_token * GTY ((skip)) buffer_end;
cp_token * GTY ((skip)) first_token;
cp_token * GTY ((skip)) next_token;
cp_token * GTY ((skip)) last_token;
varray_type saved_tokens;
varray_type string_tokens;
bool main_lexer_p;
bool debugging_p;
struct cp_lexer *next;
} cp_lexer;
static cp_lexer *cp_lexer_new_main
(void);
static cp_lexer *cp_lexer_new_from_tokens
(struct cp_token_cache *);
static int cp_lexer_saving_tokens
(const cp_lexer *);
static cp_token *cp_lexer_next_token
(cp_lexer *, cp_token *);
static cp_token *cp_lexer_prev_token
(cp_lexer *, cp_token *);
static ptrdiff_t cp_lexer_token_difference
(cp_lexer *, cp_token *, cp_token *);
static cp_token *cp_lexer_read_token
(cp_lexer *);
static void cp_lexer_maybe_grow_buffer
(cp_lexer *);
static void cp_lexer_get_preprocessor_token
(cp_lexer *, cp_token *);
static cp_token *cp_lexer_peek_token
(cp_lexer *);
static cp_token *cp_lexer_peek_nth_token
(cp_lexer *, size_t);
static inline bool cp_lexer_next_token_is
(cp_lexer *, enum cpp_ttype);
static bool cp_lexer_next_token_is_not
(cp_lexer *, enum cpp_ttype);
static bool cp_lexer_next_token_is_keyword
(cp_lexer *, enum rid);
static cp_token *cp_lexer_consume_token
(cp_lexer *);
static void cp_lexer_purge_token
(cp_lexer *);
static void cp_lexer_purge_tokens_after
(cp_lexer *, cp_token *);
static void cp_lexer_save_tokens
(cp_lexer *);
static void cp_lexer_commit_tokens
(cp_lexer *);
static void cp_lexer_rollback_tokens
(cp_lexer *);
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
(cp_lexer *);
static void cp_lexer_start_debugging
(cp_lexer *) ATTRIBUTE_UNUSED;
static void cp_lexer_stop_debugging
(cp_lexer *) ATTRIBUTE_UNUSED;
#define CP_TOKEN_BUFFER_SIZE 5
#define CP_SAVED_TOKENS_SIZE 5
#define CPP_KEYWORD ((enum cpp_ttype) (N_TTYPES + 1))
#define CPP_TEMPLATE_ID ((enum cpp_ttype) (CPP_KEYWORD + 1))
#define CPP_NESTED_NAME_SPECIFIER ((enum cpp_ttype) (CPP_TEMPLATE_ID + 1))
#define CPP_NONE (CPP_NESTED_NAME_SPECIFIER + 1)
static FILE *cp_lexer_debug_stream;
static cp_lexer *
cp_lexer_new_main (void)
{
cp_lexer *lexer;
cp_token first_token;
cp_lexer_get_preprocessor_token (NULL, &first_token);
c_common_no_more_pch ();
lexer = ggc_alloc_cleared (sizeof (cp_lexer));
lexer->buffer = ggc_calloc (CP_TOKEN_BUFFER_SIZE, sizeof (cp_token));
lexer->buffer_end = lexer->buffer + CP_TOKEN_BUFFER_SIZE;
lexer->last_token = lexer->buffer + 1;
lexer->first_token = lexer->buffer;
lexer->next_token = lexer->buffer;
memcpy (lexer->buffer, &first_token, sizeof (cp_token));
lexer->main_lexer_p = true;
VARRAY_INT_INIT (lexer->saved_tokens, CP_SAVED_TOKENS_SIZE, "saved_tokens");
VARRAY_TREE_INIT (lexer->string_tokens, 32, "strings");
lexer->debugging_p = false;
return lexer;
}
static cp_lexer *
cp_lexer_new_from_tokens (cp_token_cache *tokens)
{
cp_lexer *lexer;
cp_token *token;
cp_token_block *block;
ptrdiff_t num_tokens;
lexer = ggc_alloc_cleared (sizeof (cp_lexer));
num_tokens = 0;
for (block = tokens->first; block != NULL; block = block->next)
num_tokens += block->num_tokens;
lexer->buffer = ggc_alloc (num_tokens * sizeof (cp_token));
lexer->buffer_end = lexer->buffer + num_tokens;
token = lexer->buffer;
for (block = tokens->first; block != NULL; block = block->next)
{
memcpy (token, block->tokens, block->num_tokens * sizeof (cp_token));
token += block->num_tokens;
}
lexer->first_token = lexer->buffer;
lexer->next_token = lexer->buffer;
lexer->last_token = lexer->first_token;
lexer->main_lexer_p = false;
VARRAY_INT_INIT (lexer->saved_tokens, CP_SAVED_TOKENS_SIZE, "saved_tokens");
VARRAY_TREE_INIT (lexer->string_tokens, 32, "strings");
lexer->debugging_p = false;
return lexer;
}
static inline bool
cp_lexer_debugging_p (cp_lexer *lexer)
{
return lexer->debugging_p;
}
static inline void
cp_lexer_set_source_position_from_token (cp_lexer *lexer ATTRIBUTE_UNUSED ,
const cp_token *token)
{
if (token->type != CPP_EOF)
input_location = token->location;
}
static inline cp_token *
cp_lexer_next_token (cp_lexer* lexer, cp_token* token)
{
token++;
if (token == lexer->buffer_end)
token = lexer->buffer;
return token;
}
static inline cp_token *
cp_lexer_prev_token (cp_lexer* lexer, cp_token* token)
{
if (token == lexer->buffer)
token = lexer->buffer_end;
return token - 1;
}
static int
cp_lexer_saving_tokens (const cp_lexer* lexer)
{
return VARRAY_ACTIVE_SIZE (lexer->saved_tokens) != 0;
}
static cp_token *
cp_lexer_advance_token (cp_lexer *lexer, cp_token *token, ptrdiff_t n)
{
token += n;
if (token >= lexer->buffer_end)
token = lexer->buffer + (token - lexer->buffer_end);
return token;
}
static ptrdiff_t
cp_lexer_token_difference (cp_lexer* lexer, cp_token* start, cp_token* finish)
{
if (finish >= start)
return finish - start;
else
return ((lexer->buffer_end - lexer->buffer)
- (start - finish));
}
static cp_token *
cp_lexer_read_token (cp_lexer* lexer)
{
cp_token *token;
cp_lexer_maybe_grow_buffer (lexer);
if (!lexer->first_token)
lexer->first_token = lexer->last_token;
if (!lexer->next_token)
lexer->next_token = lexer->last_token;
token = lexer->last_token;
cp_lexer_get_preprocessor_token (lexer, token);
lexer->last_token = cp_lexer_next_token (lexer, token);
if ((token->type == CPP_STRING || token->type == CPP_WSTRING)
&& flag_const_strings)
{
tree type;
type = TREE_TYPE (token->value);
type = build_cplus_array_type (TREE_TYPE (type), TYPE_DOMAIN (type));
TREE_TYPE (token->value) = type;
}
return token;
}
static void
cp_lexer_maybe_grow_buffer (cp_lexer* lexer)
{
if (lexer->last_token == lexer->first_token)
{
cp_token *new_buffer;
cp_token *old_buffer;
cp_token *new_first_token;
ptrdiff_t buffer_length;
size_t num_tokens_to_copy;
old_buffer = lexer->buffer;
buffer_length = lexer->buffer_end - lexer->buffer;
new_buffer = ggc_realloc (lexer->buffer,
2 * buffer_length * sizeof (cp_token));
num_tokens_to_copy = (lexer->first_token - old_buffer);
memcpy (new_buffer + buffer_length,
new_buffer,
num_tokens_to_copy * sizeof (cp_token));
memset (new_buffer + buffer_length + num_tokens_to_copy, 0,
(buffer_length - num_tokens_to_copy) * sizeof (cp_token));
new_first_token
= new_buffer + (lexer->first_token - old_buffer);
if (lexer->next_token != NULL)
{
ptrdiff_t next_token_delta;
if (lexer->next_token > lexer->first_token)
next_token_delta = lexer->next_token - lexer->first_token;
else
next_token_delta =
buffer_length - (lexer->first_token - lexer->next_token);
lexer->next_token = new_first_token + next_token_delta;
}
lexer->last_token = new_first_token + buffer_length;
lexer->buffer = new_buffer;
lexer->buffer_end = new_buffer + buffer_length * 2;
lexer->first_token = new_first_token;
}
}
static void
cp_lexer_get_preprocessor_token (cp_lexer *lexer ATTRIBUTE_UNUSED ,
cp_token *token)
{
bool done;
if (lexer != NULL && !lexer->main_lexer_p)
{
token->type = CPP_EOF;
token->location.line = 0;
token->location.file = NULL;
token->value = NULL_TREE;
token->keyword = RID_MAX;
return;
}
done = false;
while (!done)
{
token->type = c_lex_with_flags (&token->value, &token->flags);
switch (token->type)
{
case CPP_ATSIGN:
case CPP_HASH:
case CPP_PASTE:
error ("invalid token");
break;
default:
done = true;
break;
}
}
token->location = input_location;
if (token->type == CPP_NAME
&& C_IS_RESERVED_WORD (token->value))
{
token->type = CPP_KEYWORD;
token->keyword = C_RID_CODE (token->value);
token->value = ridpointers[token->keyword];
}
else
token->keyword = RID_MAX;
}
static cp_token *
cp_lexer_peek_token (cp_lexer* lexer)
{
cp_token *token;
if (!lexer->next_token)
cp_lexer_read_token (lexer);
if (cp_lexer_debugging_p (lexer))
{
fprintf (cp_lexer_debug_stream, "cp_lexer: peeking at token: ");
cp_lexer_print_token (cp_lexer_debug_stream, lexer->next_token);
fprintf (cp_lexer_debug_stream, "\n");
}
token = lexer->next_token;
cp_lexer_set_source_position_from_token (lexer, token);
return token;
}
static bool
cp_lexer_next_token_is (cp_lexer* lexer, enum cpp_ttype type)
{
cp_token *token;
token = cp_lexer_peek_token (lexer);
return token->type == type;
}
static bool
cp_lexer_next_token_is_not (cp_lexer* lexer, enum cpp_ttype type)
{
return !cp_lexer_next_token_is (lexer, type);
}
static bool
cp_lexer_next_token_is_keyword (cp_lexer* lexer, enum rid keyword)
{
cp_token *token;
token = cp_lexer_peek_token (lexer);
return token->keyword == keyword;
}
static cp_token *
cp_lexer_peek_nth_token (cp_lexer* lexer, size_t n)
{
cp_token *token;
my_friendly_assert (n > 0, 20000224);
token = lexer->next_token;
if (!token)
{
cp_lexer_read_token (lexer);
token = lexer->next_token;
}
while (--n > 0)
{
token = cp_lexer_next_token (lexer, token);
if (token == lexer->last_token)
token = cp_lexer_read_token (lexer);
}
return token;
}
static cp_token *
cp_lexer_consume_token (cp_lexer* lexer)
{
cp_token *token;
if (!lexer->next_token)
cp_lexer_read_token (lexer);
token = lexer->next_token;
lexer->next_token = cp_lexer_next_token (lexer,
lexer->next_token);
if (lexer->next_token == lexer->last_token)
lexer->next_token = NULL;
if (!cp_lexer_saving_tokens (lexer))
{
if (!lexer->next_token)
lexer->first_token = NULL;
else
lexer->first_token = lexer->next_token;
}
if (cp_lexer_debugging_p (lexer))
{
fprintf (cp_lexer_debug_stream, "cp_lexer: consuming token: ");
cp_lexer_print_token (cp_lexer_debug_stream, token);
fprintf (cp_lexer_debug_stream, "\n");
}
return token;
}
static void
cp_lexer_purge_token (cp_lexer *lexer)
{
cp_token *token;
cp_token *next_token;
token = lexer->next_token;
while (true)
{
next_token = cp_lexer_next_token (lexer, token);
if (next_token == lexer->last_token)
break;
*token = *next_token;
token = next_token;
}
lexer->last_token = token;
if (lexer->next_token == token)
lexer->next_token = NULL;
}
static void
cp_lexer_purge_tokens_after (cp_lexer *lexer, cp_token *token)
{
cp_token *peek;
cp_token *t1;
cp_token *t2;
if (lexer->next_token)
{
t1 = cp_lexer_next_token (lexer, token);
t2 = peek = cp_lexer_peek_token (lexer);
while (t2 != lexer->last_token)
{
*t1 = *t2;
t1 = cp_lexer_next_token (lexer, t1);
t2 = cp_lexer_next_token (lexer, t2);
}
lexer->next_token = cp_lexer_next_token (lexer, token);
lexer->last_token = t1;
}
else
{
lexer->last_token = cp_lexer_next_token (lexer, token);
}
}
static void
cp_lexer_save_tokens (cp_lexer* lexer)
{
if (cp_lexer_debugging_p (lexer))
fprintf (cp_lexer_debug_stream, "cp_lexer: saving tokens\n");
if (!lexer->next_token)
cp_lexer_read_token (lexer);
VARRAY_PUSH_INT (lexer->saved_tokens,
cp_lexer_token_difference (lexer,
lexer->first_token,
lexer->next_token));
}
static void
cp_lexer_commit_tokens (cp_lexer* lexer)
{
if (cp_lexer_debugging_p (lexer))
fprintf (cp_lexer_debug_stream, "cp_lexer: committing tokens\n");
VARRAY_POP (lexer->saved_tokens);
}
static void
cp_lexer_rollback_tokens (cp_lexer* lexer)
{
size_t delta;
if (cp_lexer_debugging_p (lexer))
fprintf (cp_lexer_debug_stream, "cp_lexer: restoring tokens\n");
delta = VARRAY_TOP_INT(lexer->saved_tokens);
lexer->next_token = cp_lexer_advance_token (lexer,
lexer->first_token,
delta);
if (!lexer->next_token && lexer->first_token)
lexer->next_token = lexer->first_token;
VARRAY_POP (lexer->saved_tokens);
}
static void
cp_lexer_print_token (FILE * stream, cp_token* token)
{
const char *token_type = NULL;
switch (token->type)
{
case CPP_EQ:
token_type = "EQ";
break;
case CPP_COMMA:
token_type = "COMMA";
break;
case CPP_OPEN_PAREN:
token_type = "OPEN_PAREN";
break;
case CPP_CLOSE_PAREN:
token_type = "CLOSE_PAREN";
break;
case CPP_OPEN_BRACE:
token_type = "OPEN_BRACE";
break;
case CPP_CLOSE_BRACE:
token_type = "CLOSE_BRACE";
break;
case CPP_SEMICOLON:
token_type = "SEMICOLON";
break;
case CPP_NAME:
token_type = "NAME";
break;
case CPP_EOF:
token_type = "EOF";
break;
case CPP_KEYWORD:
token_type = "keyword";
break;
default:
break;
}
if (token_type)
fprintf (stream, "%s", token_type);
else
fprintf (stream, "%d", token->type);
if (token->type == CPP_NAME
|| (token->type == CPP_KEYWORD
&& TREE_CODE (token->value) == IDENTIFIER_NODE))
fprintf (stream, " %s", IDENTIFIER_POINTER (token->value));
}
static void
cp_lexer_start_debugging (cp_lexer* lexer)
{
++lexer->debugging_p;
}
static void
cp_lexer_stop_debugging (cp_lexer* lexer)
{
--lexer->debugging_p;
}
typedef enum cp_parser_flags
{
CP_PARSER_FLAGS_NONE = 0x0,
CP_PARSER_FLAGS_OPTIONAL = 0x1,
CP_PARSER_FLAGS_NO_USER_DEFINED_TYPES = 0x2
} cp_parser_flags;
typedef enum cp_parser_declarator_kind
{
CP_PARSER_DECLARATOR_ABSTRACT,
CP_PARSER_DECLARATOR_NAMED,
CP_PARSER_DECLARATOR_EITHER
} cp_parser_declarator_kind;
typedef struct cp_parser_token_tree_map_node
{
ENUM_BITFIELD (cpp_ttype) token_type : 8;
ENUM_BITFIELD (tree_code) tree_type : 8;
} cp_parser_token_tree_map_node;
typedef cp_parser_token_tree_map_node cp_parser_token_tree_map[];
typedef enum cp_parser_status_kind
{
CP_PARSER_STATUS_KIND_NO_ERROR,
CP_PARSER_STATUS_KIND_ERROR,
CP_PARSER_STATUS_KIND_COMMITTED
} cp_parser_status_kind;
typedef struct cp_parser_context GTY (())
{
enum cp_parser_status_kind status;
tree object_type;
struct cp_parser_context *next;
} cp_parser_context;
static cp_parser_context *cp_parser_context_new
(cp_parser_context *);
static GTY((deletable)) cp_parser_context* cp_parser_context_free_list;
static cp_parser_context *
cp_parser_context_new (cp_parser_context* next)
{
cp_parser_context *context;
if (cp_parser_context_free_list != NULL)
{
context = cp_parser_context_free_list;
cp_parser_context_free_list = context->next;
memset (context, 0, sizeof (*context));
}
else
context = ggc_alloc_cleared (sizeof (cp_parser_context));
context->status = CP_PARSER_STATUS_KIND_NO_ERROR;
if (next)
{
context->object_type = next->object_type;
context->next = next;
}
return context;
}
typedef struct cp_parser GTY(())
{
cp_lexer *lexer;
tree scope;
tree object_scope;
tree qualifying_scope;
cp_parser_context *context;
bool allow_gnu_extensions_p;
bool greater_than_is_operator_p;
bool default_arg_ok_p;
bool integral_constant_expression_p;
bool allow_non_integral_constant_expression_p;
bool non_integral_constant_expression_p;
bool in_offsetof_p;
bool local_variables_forbidden_p;
bool in_unbraced_linkage_specification_p;
bool in_declarator_p;
bool in_template_argument_list_p;
bool in_iteration_statement_p;
bool in_switch_statement_p;
bool in_type_id_in_expr_p;
const char *type_definition_forbidden_message;
tree unparsed_functions_queues;
unsigned num_classes_being_defined;
unsigned num_template_parameter_lists;
} cp_parser;
typedef tree (*cp_parser_expression_fn) (cp_parser *);
static cp_parser *cp_parser_new
(void);
static tree cp_parser_identifier
(cp_parser *);
static bool cp_parser_translation_unit
(cp_parser *);
static tree cp_parser_primary_expression
(cp_parser *, cp_id_kind *, tree *);
static tree cp_parser_id_expression
(cp_parser *, bool, bool, bool *, bool);
static tree cp_parser_unqualified_id
(cp_parser *, bool, bool, bool);
static tree cp_parser_nested_name_specifier_opt
(cp_parser *, bool, bool, bool, bool);
static tree cp_parser_nested_name_specifier
(cp_parser *, bool, bool, bool, bool);
static tree cp_parser_class_or_namespace_name
(cp_parser *, bool, bool, bool, bool, bool);
static tree cp_parser_postfix_expression
(cp_parser *, bool);
static tree cp_parser_parenthesized_expression_list
(cp_parser *, bool, bool *);
static void cp_parser_pseudo_destructor_name
(cp_parser *, tree *, tree *);
static tree cp_parser_unary_expression
(cp_parser *, bool);
static enum tree_code cp_parser_unary_operator
(cp_token *);
static tree cp_parser_new_expression
(cp_parser *);
static tree cp_parser_new_placement
(cp_parser *);
static tree cp_parser_new_type_id
(cp_parser *);
static tree cp_parser_new_declarator_opt
(cp_parser *);
static tree 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
(cp_parser *, bool);
static tree cp_parser_pm_expression
(cp_parser *);
static tree cp_parser_multiplicative_expression
(cp_parser *);
static tree cp_parser_additive_expression
(cp_parser *);
static tree cp_parser_shift_expression
(cp_parser *);
static tree cp_parser_relational_expression
(cp_parser *);
static tree cp_parser_equality_expression
(cp_parser *);
static tree cp_parser_and_expression
(cp_parser *);
static tree cp_parser_exclusive_or_expression
(cp_parser *);
static tree cp_parser_inclusive_or_expression
(cp_parser *);
static tree cp_parser_logical_and_expression
(cp_parser *);
static tree cp_parser_logical_or_expression
(cp_parser *);
static tree cp_parser_question_colon_clause
(cp_parser *, tree);
static tree cp_parser_assignment_expression
(cp_parser *);
static enum tree_code cp_parser_assignment_operator_opt
(cp_parser *);
static tree cp_parser_expression
(cp_parser *);
static tree cp_parser_constant_expression
(cp_parser *, bool, bool *);
static void cp_parser_statement
(cp_parser *, bool);
static tree cp_parser_labeled_statement
(cp_parser *, bool);
static tree cp_parser_expression_statement
(cp_parser *, bool);
static tree cp_parser_compound_statement
(cp_parser *, bool);
static void cp_parser_statement_seq_opt
(cp_parser *, bool);
static tree cp_parser_selection_statement
(cp_parser *);
static tree cp_parser_condition
(cp_parser *);
static tree cp_parser_iteration_statement
(cp_parser *);
static void cp_parser_for_init_statement
(cp_parser *);
static tree cp_parser_jump_statement
(cp_parser *);
static void cp_parser_declaration_statement
(cp_parser *);
static tree cp_parser_implicitly_scoped_statement
(cp_parser *);
static void cp_parser_already_scoped_statement
(cp_parser *);
static void cp_parser_declaration_seq_opt
(cp_parser *);
static void cp_parser_declaration
(cp_parser *);
static void cp_parser_block_declaration
(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 tree cp_parser_storage_class_specifier_opt
(cp_parser *);
static tree cp_parser_function_specifier_opt
(cp_parser *);
static tree cp_parser_type_specifier
(cp_parser *, cp_parser_flags, bool, bool, int *, bool *);
static tree cp_parser_simple_type_specifier
(cp_parser *, cp_parser_flags, bool);
static tree cp_parser_type_name
(cp_parser *);
static tree cp_parser_elaborated_type_specifier
(cp_parser *, bool, bool);
static tree cp_parser_enum_specifier
(cp_parser *);
static void cp_parser_enumerator_list
(cp_parser *, tree);
static void cp_parser_enumerator_definition
(cp_parser *, tree);
static tree cp_parser_namespace_name
(cp_parser *);
static void cp_parser_namespace_definition
(cp_parser *);
static void cp_parser_namespace_body
(cp_parser *);
static tree cp_parser_qualified_namespace_specifier
(cp_parser *);
static void cp_parser_namespace_alias_definition
(cp_parser *);
static void cp_parser_using_declaration
(cp_parser *);
static void cp_parser_using_directive
(cp_parser *);
static void cp_parser_asm_definition
(cp_parser *);
static void cp_parser_linkage_specification
(cp_parser *);
static tree cp_parser_init_declarator
(cp_parser *, tree, tree, bool, bool, int, bool *);
static tree cp_parser_declarator
(cp_parser *, cp_parser_declarator_kind, int *, bool *);
static tree 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 *);
static tree cp_parser_declarator_id
(cp_parser *);
static tree cp_parser_type_id
(cp_parser *);
static tree cp_parser_type_specifier_seq
(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
(cp_parser *, bool, bool *);
static void cp_parser_function_body
(cp_parser *);
static tree cp_parser_initializer
(cp_parser *, bool *, bool *);
static tree cp_parser_initializer_clause
(cp_parser *, bool *);
static tree cp_parser_initializer_list
(cp_parser *, bool *);
static bool cp_parser_ctor_initializer_opt_and_function_body
(cp_parser *);
static tree cp_parser_class_name
(cp_parser *, bool, bool, bool, bool, bool, bool);
static tree cp_parser_class_specifier
(cp_parser *);
static tree cp_parser_class_head
(cp_parser *, bool *, tree *);
static enum tag_types cp_parser_class_key
(cp_parser *);
static void cp_parser_member_specification_opt
(cp_parser *);
static void cp_parser_member_declaration
(cp_parser *);
static tree cp_parser_pure_specifier
(cp_parser *);
static tree cp_parser_constant_initializer
(cp_parser *);
static tree cp_parser_base_clause
(cp_parser *);
static tree cp_parser_base_specifier
(cp_parser *);
static tree cp_parser_conversion_function_id
(cp_parser *);
static tree cp_parser_conversion_type_id
(cp_parser *);
static tree cp_parser_conversion_declarator_opt
(cp_parser *);
static bool cp_parser_ctor_initializer_opt
(cp_parser *);
static void cp_parser_mem_initializer_list
(cp_parser *);
static tree cp_parser_mem_initializer
(cp_parser *);
static tree cp_parser_mem_initializer_id
(cp_parser *);
static tree cp_parser_operator_function_id
(cp_parser *);
static tree cp_parser_operator
(cp_parser *);
static void cp_parser_template_declaration
(cp_parser *, bool);
static tree cp_parser_template_parameter_list
(cp_parser *);
static tree cp_parser_template_parameter
(cp_parser *);
static tree cp_parser_type_parameter
(cp_parser *);
static tree cp_parser_template_id
(cp_parser *, bool, bool, bool);
static tree cp_parser_template_name
(cp_parser *, bool, bool, bool, bool *);
static tree cp_parser_template_argument_list
(cp_parser *);
static tree cp_parser_template_argument
(cp_parser *);
static void cp_parser_explicit_instantiation
(cp_parser *);
static void cp_parser_explicit_specialization
(cp_parser *);
static tree cp_parser_try_block
(cp_parser *);
static bool cp_parser_function_try_block
(cp_parser *);
static void cp_parser_handler_seq
(cp_parser *);
static void cp_parser_handler
(cp_parser *);
static tree cp_parser_exception_declaration
(cp_parser *);
static tree cp_parser_throw_expression
(cp_parser *);
static tree cp_parser_exception_specification_opt
(cp_parser *);
static tree cp_parser_type_id_list
(cp_parser *);
static tree cp_parser_asm_specification_opt
(cp_parser *);
static tree cp_parser_asm_operand_list
(cp_parser *);
static tree cp_parser_asm_clobber_list
(cp_parser *);
static tree cp_parser_attributes_opt
(cp_parser *);
static tree cp_parser_attribute_list
(cp_parser *);
static bool cp_parser_extension_opt
(cp_parser *, int *);
static void cp_parser_label_declaration
(cp_parser *);
static tree cp_parser_lookup_name
(cp_parser *, tree, bool, bool, bool, bool);
static tree cp_parser_lookup_name_simple
(cp_parser *, tree);
static tree cp_parser_maybe_treat_template_as_class
(tree, bool);
static bool cp_parser_check_declarator_template_parameters
(cp_parser *, tree);
static bool cp_parser_check_template_parameters
(cp_parser *, unsigned);
static tree cp_parser_simple_cast_expression
(cp_parser *);
static tree cp_parser_binary_expression
(cp_parser *, const cp_parser_token_tree_map, cp_parser_expression_fn);
static tree cp_parser_global_scope_opt
(cp_parser *, bool);
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);
static tree cp_parser_function_definition_after_declarator
(cp_parser *, bool);
static void cp_parser_template_declaration_after_export
(cp_parser *, bool);
static tree cp_parser_single_declaration
(cp_parser *, bool, bool *);
static tree cp_parser_functional_cast
(cp_parser *, tree);
static tree cp_parser_save_member_function_body
(cp_parser *, tree, tree, tree);
static tree cp_parser_enclosed_template_argument_list
(cp_parser *);
static void cp_parser_save_default_args
(cp_parser *, tree);
static void cp_parser_late_parsing_for_member
(cp_parser *, tree);
static void cp_parser_late_parsing_default_args
(cp_parser *, tree);
static tree cp_parser_sizeof_operand
(cp_parser *, enum rid);
static bool cp_parser_declares_only_class_p
(cp_parser *);
static bool cp_parser_friend_p
(tree);
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
(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
(enum tag_types, tree type);
static void cp_parser_check_access_in_redeclaration
(tree type);
static bool cp_parser_optional_template_keyword
(cp_parser *);
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
(cp_parser *);
static void cp_parser_commit_to_tentative_parse
(cp_parser *);
static void cp_parser_abort_tentative_parse
(cp_parser *);
static bool cp_parser_parse_definitely
(cp_parser *);
static inline bool cp_parser_parsing_tentatively
(cp_parser *);
static bool cp_parser_committed_to_tentative_parse
(cp_parser *);
static void cp_parser_error
(cp_parser *, const char *);
static void cp_parser_name_lookup_error
(cp_parser *, tree, tree, const char *);
static bool cp_parser_simulate_error
(cp_parser *);
static void cp_parser_check_type_definition
(cp_parser *);
static void cp_parser_check_for_definition_in_return_type
(tree, int);
static void cp_parser_check_for_invalid_template_id
(cp_parser *, tree);
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);
static void cp_parser_skip_to_end_of_statement
(cp_parser *);
static void cp_parser_consume_semicolon_at_end_of_statement
(cp_parser *);
static void cp_parser_skip_to_end_of_block_or_statement
(cp_parser *);
static void cp_parser_skip_to_closing_brace
(cp_parser *);
static void cp_parser_skip_until_found
(cp_parser *, enum cpp_ttype, const char *);
static bool cp_parser_error_occurred
(cp_parser *);
static bool cp_parser_allow_gnu_extensions_p
(cp_parser *);
static bool cp_parser_is_string_literal
(cp_token *);
static bool cp_parser_is_keyword
(cp_token *, enum rid);
static tree cp_parser_make_typename_type
(cp_parser *, tree, tree);
static inline bool
cp_parser_parsing_tentatively (cp_parser* parser)
{
return parser->context->next != NULL;
}
static bool
cp_parser_is_string_literal (cp_token* token)
{
return (token->type == CPP_STRING || token->type == CPP_WSTRING);
}
static bool
cp_parser_is_keyword (cp_token* token, enum rid keyword)
{
return token->keyword == keyword;
}
static void
cp_parser_error (cp_parser* parser, const char* message)
{
if (!cp_parser_simulate_error (parser))
{
cp_token *token;
token = cp_lexer_peek_token (parser->lexer);
c_parse_error (message,
(token->type == CPP_KEYWORD ? CPP_NAME : token->type),
token->value);
}
}
static void
cp_parser_name_lookup_error (cp_parser* parser,
tree name,
tree decl,
const char* desired)
{
if (decl == error_mark_node)
{
if (parser->scope && parser->scope != global_namespace)
error ("`%D::%D' has not been declared",
parser->scope, name);
else if (parser->scope == global_namespace)
error ("`::%D' has not been declared", name);
else
error ("`%D' has not been declared", name);
}
else if (parser->scope && parser->scope != global_namespace)
error ("`%D::%D' %s", parser->scope, name, desired);
else if (parser->scope == global_namespace)
error ("`::%D' %s", name, desired);
else
error ("`%D' %s", name, desired);
}
static bool
cp_parser_simulate_error (cp_parser* parser)
{
if (cp_parser_parsing_tentatively (parser)
&& !cp_parser_committed_to_tentative_parse (parser))
{
parser->context->status = CP_PARSER_STATUS_KIND_ERROR;
return true;
}
return false;
}
static void
cp_parser_check_type_definition (cp_parser* parser)
{
if (parser->type_definition_forbidden_message)
error ("%s", parser->type_definition_forbidden_message);
}
static void
cp_parser_check_for_definition_in_return_type (tree declarator,
int declares_class_or_enum)
{
while (declarator
&& (TREE_CODE (declarator) == INDIRECT_REF
|| TREE_CODE (declarator) == ADDR_EXPR))
declarator = TREE_OPERAND (declarator, 0);
if (declarator
&& TREE_CODE (declarator) == CALL_EXPR
&& declares_class_or_enum & 2)
error ("new types may not be defined in a return type");
}
static void
cp_parser_check_for_invalid_template_id (cp_parser* parser,
tree type)
{
ptrdiff_t start;
cp_token *token;
if (cp_lexer_next_token_is (parser->lexer, CPP_LESS))
{
if (TYPE_P (type))
error ("`%T' is not a template", type);
else if (TREE_CODE (type) == IDENTIFIER_NODE)
error ("`%E' is not a template", type);
else
error ("invalid template-id");
if (cp_parser_parsing_tentatively (parser)
&& !cp_parser_committed_to_tentative_parse (parser))
{
token = cp_lexer_peek_token (parser->lexer);
token = cp_lexer_prev_token (parser->lexer, token);
start = cp_lexer_token_difference (parser->lexer,
parser->lexer->first_token,
token);
}
else
start = -1;
cp_lexer_consume_token (parser->lexer);
cp_parser_enclosed_template_argument_list (parser);
if (start >= 0)
{
token = cp_lexer_advance_token (parser->lexer,
parser->lexer->first_token,
start);
cp_lexer_purge_tokens_after (parser->lexer, token);
}
}
}
static bool
cp_parser_non_integral_constant_expression (cp_parser *parser,
const char *thing)
{
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;
}
static void
cp_parser_diagnose_invalid_type_name (cp_parser *parser, tree scope, tree id)
{
tree decl, old_scope;
old_scope = parser->scope;
parser->scope = scope;
decl = cp_parser_lookup_name_simple (parser, id);
parser->scope = old_scope;
if (TREE_CODE (decl) == TEMPLATE_DECL)
error ("invalid use of template-name `%E' without an argument list",
decl);
else if (!parser->scope)
{
error ("`%E' does not name a type", id);
if (processing_template_decl && current_class_type)
{
tree b;
for (b = TREE_CHAIN (TYPE_BINFO (current_class_type));
b;
b = TREE_CHAIN (b))
{
tree base_type = BINFO_TYPE (b);
if (CLASS_TYPE_P (base_type)
&& dependent_type_p (base_type))
{
tree field;
base_type = CLASSTYPE_PRIMARY_TEMPLATE_TYPE (base_type);
for (field = TYPE_FIELDS (base_type);
field;
field = TREE_CHAIN (field))
if (TREE_CODE (field) == TYPE_DECL
&& DECL_NAME (field) == id)
{
inform ("(perhaps `typename %T::%E' was intended)",
BINFO_TYPE (b), id);
break;
}
if (field)
break;
}
}
}
}
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();
}
}
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,
false,
true,
NULL,
true);
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;
my_friendly_assert (TREE_CODE (id) == IDENTIFIER_NODE, 20030203);
cp_parser_diagnose_invalid_type_name (parser, parser->scope, id);
cp_parser_skip_to_end_of_block_or_statement (parser);
return true;
}
static int
cp_parser_skip_to_closing_parenthesis (cp_parser *parser,
bool recovering,
bool or_comma,
bool consume_paren)
{
unsigned paren_depth = 0;
unsigned brace_depth = 0;
if (recovering && !or_comma && cp_parser_parsing_tentatively (parser)
&& !cp_parser_committed_to_tentative_parse (parser))
return 0;
while (true)
{
cp_token *token;
if (cp_lexer_next_token_is (parser->lexer, CPP_EOF))
return 0;
token = cp_lexer_peek_token (parser->lexer);
if (token->type == CPP_SEMICOLON && !brace_depth)
return 0;
if (token->type == CPP_OPEN_BRACE)
++brace_depth;
if (token->type == CPP_CLOSE_BRACE)
{
if (!brace_depth--)
return 0;
}
if (recovering && or_comma && token->type == CPP_COMMA
&& !brace_depth && !paren_depth)
return -1;
if (!brace_depth)
{
if (token->type == CPP_OPEN_PAREN)
++paren_depth;
else if (token->type == CPP_CLOSE_PAREN && !paren_depth--)
{
if (consume_paren)
cp_lexer_consume_token (parser->lexer);
return 1;
}
}
cp_lexer_consume_token (parser->lexer);
}
}
static void
cp_parser_skip_to_end_of_statement (cp_parser* parser)
{
unsigned nesting_depth = 0;
while (true)
{
cp_token *token;
token = cp_lexer_peek_token (parser->lexer);
if (token->type == CPP_EOF)
break;
if (token->type == CPP_SEMICOLON && !nesting_depth)
break;
if (token->type == CPP_CLOSE_BRACE)
{
if (nesting_depth == 0)
break;
if (--nesting_depth == 0)
{
cp_lexer_consume_token (parser->lexer);
break;
}
}
else if (token->type == CPP_OPEN_BRACE)
++nesting_depth;
cp_lexer_consume_token (parser->lexer);
}
}
static void
cp_parser_consume_semicolon_at_end_of_statement (cp_parser *parser)
{
if (!cp_parser_require (parser, CPP_SEMICOLON, "`;'"))
{
cp_parser_skip_to_end_of_statement (parser);
if (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON))
cp_lexer_consume_token (parser->lexer);
}
}
static void
cp_parser_skip_to_end_of_block_or_statement (cp_parser* parser)
{
unsigned nesting_depth = 0;
while (true)
{
cp_token *token;
token = cp_lexer_peek_token (parser->lexer);
if (token->type == CPP_EOF)
break;
if (token->type == CPP_SEMICOLON && !nesting_depth)
{
cp_lexer_consume_token (parser->lexer);
break;
}
token = cp_lexer_consume_token (parser->lexer);
if (token->type == CPP_CLOSE_BRACE
&& (nesting_depth == 0 || --nesting_depth == 0))
break;
if (token->type == CPP_OPEN_BRACE)
++nesting_depth;
}
}
static void
cp_parser_skip_to_closing_brace (cp_parser *parser)
{
unsigned nesting_depth = 0;
while (true)
{
cp_token *token;
token = cp_lexer_peek_token (parser->lexer);
if (token->type == CPP_EOF)
break;
if (token->type == CPP_CLOSE_BRACE && nesting_depth-- == 0)
break;
else if (token->type == CPP_OPEN_BRACE)
++nesting_depth;
cp_lexer_consume_token (parser->lexer);
}
}
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, 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);
}
static cp_parser *
cp_parser_new (void)
{
cp_parser *parser;
cp_lexer *lexer;
lexer = cp_lexer_new_main ();
parser = ggc_alloc_cleared (sizeof (cp_parser));
parser->lexer = lexer;
parser->context = cp_parser_context_new (NULL);
parser->allow_gnu_extensions_p = 1;
parser->greater_than_is_operator_p = true;
parser->default_arg_ok_p = true;
parser->integral_constant_expression_p = false;
parser->allow_non_integral_constant_expression_p = false;
parser->non_integral_constant_expression_p = false;
parser->in_offsetof_p = false;
parser->local_variables_forbidden_p = false;
parser->in_unbraced_linkage_specification_p = false;
parser->in_declarator_p = false;
parser->in_template_argument_list_p = false;
parser->in_iteration_statement_p = false;
parser->in_switch_statement_p = false;
parser->in_type_id_in_expr_p = false;
parser->unparsed_functions_queues = build_tree_list (NULL_TREE, NULL_TREE);
parser->num_classes_being_defined = 0;
parser->num_template_parameter_lists = 0;
return parser;
}
static tree
cp_parser_identifier (cp_parser* parser)
{
cp_token *token;
token = cp_parser_require (parser, CPP_NAME, "identifier");
return token ? token->value : error_mark_node;
}
static bool
cp_parser_translation_unit (cp_parser* parser)
{
while (true)
{
cp_parser_declaration_seq_opt (parser);
if (cp_lexer_next_token_is (parser->lexer, CPP_EOF))
break;
cp_parser_error (parser, "expected declaration");
return false;
}
cp_parser_require (parser, CPP_EOF, "end-of-file");
finish_translation_unit ();
return true;
}
static tree
cp_parser_primary_expression (cp_parser *parser,
cp_id_kind *idk,
tree *qualifying_class)
{
cp_token *token;
*idk = CP_ID_KIND_NONE;
*qualifying_class = NULL_TREE;
token = cp_lexer_peek_token (parser->lexer);
switch (token->type)
{
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_OPEN_PAREN:
{
tree expr;
bool saved_greater_than_is_operator_p;
cp_lexer_consume_token (parser->lexer);
saved_greater_than_is_operator_p
= parser->greater_than_is_operator_p;
parser->greater_than_is_operator_p = true;
if (cp_parser_allow_gnu_extensions_p (parser)
&& cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE))
{
if (pedantic)
pedwarn ("ISO C++ forbids braced-groups within expressions");
if (!at_function_scope_p ())
error ("statement-expressions are allowed only inside functions");
expr = begin_stmt_expr ();
cp_parser_compound_statement (parser, true);
expr = finish_stmt_expr (expr, false);
}
else
{
expr = cp_parser_expression (parser);
finish_parenthesized_expr (expr);
}
parser->greater_than_is_operator_p
= saved_greater_than_is_operator_p;
if (!cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'"))
cp_parser_skip_to_end_of_statement (parser);
return expr;
}
case CPP_KEYWORD:
switch (token->keyword)
{
case RID_TRUE:
cp_lexer_consume_token (parser->lexer);
return boolean_true_node;
case RID_FALSE:
cp_lexer_consume_token (parser->lexer);
return boolean_false_node;
case RID_NULL:
cp_lexer_consume_token (parser->lexer);
return null_node;
case RID_THIS:
cp_lexer_consume_token (parser->lexer);
if (parser->local_variables_forbidden_p)
{
error ("`this' may not be used in this context");
return error_mark_node;
}
if (cp_parser_non_integral_constant_expression (parser,
"`this'"))
return error_mark_node;
return finish_this_expr ();
case RID_OPERATOR:
goto id_expression;
case RID_FUNCTION_NAME:
case RID_PRETTY_FUNCTION_NAME:
case RID_C99_FUNCTION_NAME:
token = cp_lexer_consume_token (parser->lexer);
return finish_fname (token->value);
case RID_VA_ARG:
{
tree expression;
tree type;
cp_lexer_consume_token (parser->lexer);
cp_parser_require (parser, CPP_OPEN_PAREN, "`('");
expression = cp_parser_assignment_expression (parser);
cp_parser_require (parser, CPP_COMMA, "`,'");
type = cp_parser_type_id (parser);
cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
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;
cp_lexer_consume_token (parser->lexer);
cp_parser_require (parser, CPP_OPEN_PAREN, "`('");
saved_in_offsetof_p = parser->in_offsetof_p;
parser->in_offsetof_p = true;
expression
= cp_parser_constant_expression (parser,
false,
NULL);
parser->in_offsetof_p = saved_in_offsetof_p;
cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
return expression;
}
default:
cp_parser_error (parser, "expected primary-expression");
return error_mark_node;
}
case CPP_NAME:
case CPP_SCOPE:
case CPP_TEMPLATE_ID:
case CPP_NESTED_NAME_SPECIFIER:
{
tree id_expression;
tree decl;
const char *error_msg;
id_expression:
id_expression
= cp_parser_id_expression (parser,
false,
true,
NULL,
false);
if (id_expression == error_mark_node)
return error_mark_node;
else if (TREE_CODE (id_expression) == TEMPLATE_ID_EXPR
|| TREE_CODE (id_expression) == TYPE_DECL)
decl = id_expression;
else
{
decl = cp_parser_lookup_name_simple (parser, id_expression);
if (TREE_CODE (decl) == SCOPE_REF)
{
if (TYPE_P (TREE_OPERAND (decl, 0)))
*qualifying_class = TREE_OPERAND (decl, 0);
return decl;
}
if (parser->local_variables_forbidden_p
&& local_variable_p (decl))
{
decl = check_for_out_of_scope_variable (decl);
if (local_variable_p (decl))
{
error ("local variable `%D' may not appear in this context",
decl);
return error_mark_node;
}
}
}
decl = finish_id_expression (id_expression, decl, parser->scope,
idk, qualifying_class,
parser->integral_constant_expression_p,
parser->allow_non_integral_constant_expression_p,
&parser->non_integral_constant_expression_p,
&error_msg);
if (error_msg)
cp_parser_error (parser, error_msg);
return decl;
}
default:
cp_parser_error (parser, "expected primary-expression");
return error_mark_node;
}
}
static tree
cp_parser_id_expression (cp_parser *parser,
bool template_keyword_p,
bool check_dependency_p,
bool *template_p,
bool declarator_p)
{
bool global_scope_p;
bool nested_name_specifier_p;
if (template_p)
*template_p = false;
global_scope_p
= (cp_parser_global_scope_opt (parser, false)
!= NULL_TREE);
nested_name_specifier_p
= (cp_parser_nested_name_specifier_opt (parser,
false,
check_dependency_p,
false,
false)
!= NULL_TREE);
if (nested_name_specifier_p)
{
tree saved_scope;
tree saved_object_scope;
tree saved_qualifying_scope;
tree unqualified_id;
bool is_template;
if (!template_p)
template_p = &is_template;
*template_p = cp_parser_optional_template_keyword (parser);
saved_scope = parser->scope;
saved_object_scope = parser->object_scope;
saved_qualifying_scope = parser->qualifying_scope;
unqualified_id = cp_parser_unqualified_id (parser, *template_p,
check_dependency_p,
declarator_p);
parser->scope = saved_scope;
parser->object_scope = saved_object_scope;
parser->qualifying_scope = saved_qualifying_scope;
return unqualified_id;
}
else if (global_scope_p)
{
cp_token *token;
tree id;
token = cp_lexer_peek_token (parser->lexer);
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);
id = cp_parser_template_id (parser,
false,
true,
declarator_p);
if (cp_parser_parse_definitely (parser))
return id;
token = cp_lexer_peek_token (parser->lexer);
switch (token->type)
{
case CPP_NAME:
return cp_parser_identifier (parser);
case CPP_KEYWORD:
if (token->keyword == RID_OPERATOR)
return cp_parser_operator_function_id (parser);
default:
cp_parser_error (parser, "expected id-expression");
return error_mark_node;
}
}
else
return cp_parser_unqualified_id (parser, template_keyword_p,
true,
declarator_p);
}
static tree
cp_parser_unqualified_id (cp_parser* parser,
bool template_keyword_p,
bool check_dependency_p,
bool declarator_p)
{
cp_token *token;
token = cp_lexer_peek_token (parser->lexer);
switch (token->type)
{
case CPP_NAME:
{
tree id;
cp_parser_parse_tentatively (parser);
id = cp_parser_template_id (parser, template_keyword_p,
check_dependency_p,
declarator_p);
if (cp_parser_parse_definitely (parser))
return id;
return cp_parser_identifier (parser);
}
case CPP_TEMPLATE_ID:
return cp_parser_template_id (parser, template_keyword_p,
check_dependency_p,
declarator_p);
case CPP_COMPL:
{
tree type_decl;
tree qualifying_scope;
tree object_scope;
tree scope;
cp_lexer_consume_token (parser->lexer);
scope = parser->scope;
object_scope = parser->object_scope;
qualifying_scope = parser->qualifying_scope;
if (scope && TYPE_P (scope)
&& cp_lexer_next_token_is (parser->lexer, CPP_NAME)
&& (cp_lexer_peek_nth_token (parser->lexer, 2)->type
== CPP_OPEN_PAREN)
&& (cp_lexer_peek_token (parser->lexer)->value
== TYPE_IDENTIFIER (scope)))
{
cp_lexer_consume_token (parser->lexer);
return build_nt (BIT_NOT_EXPR, scope);
}
if (scope)
{
cp_parser_parse_tentatively (parser);
type_decl = cp_parser_class_name (parser,
false,
false,
false,
false,
false,
declarator_p);
if (cp_parser_parse_definitely (parser))
return build_nt (BIT_NOT_EXPR, TREE_TYPE (type_decl));
}
if (scope && qualifying_scope)
{
cp_parser_parse_tentatively (parser);
parser->scope = qualifying_scope;
parser->object_scope = NULL_TREE;
parser->qualifying_scope = NULL_TREE;
type_decl
= cp_parser_class_name (parser,
false,
false,
false,
false,
false,
declarator_p);
if (cp_parser_parse_definitely (parser))
return build_nt (BIT_NOT_EXPR, TREE_TYPE (type_decl));
}
else if (object_scope)
{
cp_parser_parse_tentatively (parser);
parser->scope = object_scope;
parser->object_scope = NULL_TREE;
parser->qualifying_scope = NULL_TREE;
type_decl
= cp_parser_class_name (parser,
false,
false,
false,
false,
false,
declarator_p);
if (cp_parser_parse_definitely (parser))
return build_nt (BIT_NOT_EXPR, TREE_TYPE (type_decl));
}
parser->scope = NULL_TREE;
parser->object_scope = NULL_TREE;
parser->qualifying_scope = NULL_TREE;
type_decl
= cp_parser_class_name (parser,
false,
false,
false,
false,
false,
declarator_p);
if (type_decl == error_mark_node && scope && TYPE_P (scope))
return build_nt (BIT_NOT_EXPR, scope);
else if (type_decl == error_mark_node)
return error_mark_node;
if (declarator_p
&& !DECL_IMPLICIT_TYPEDEF_P (type_decl)
&& !DECL_SELF_REFERENCE_P (type_decl))
error ("typedef-name `%D' used as destructor declarator",
type_decl);
return build_nt (BIT_NOT_EXPR, TREE_TYPE (type_decl));
}
case CPP_KEYWORD:
if (token->keyword == RID_OPERATOR)
{
tree id;
cp_parser_parse_tentatively (parser);
id = cp_parser_template_id (parser, template_keyword_p,
true,
declarator_p);
if (cp_parser_parse_definitely (parser))
return id;
cp_parser_parse_tentatively (parser);
id = cp_parser_operator_function_id (parser);
if (!cp_parser_parse_definitely (parser))
id = cp_parser_conversion_function_id (parser);
return id;
}
default:
cp_parser_error (parser, "expected unqualified-id");
return error_mark_node;
}
}
static tree
cp_parser_nested_name_specifier_opt (cp_parser *parser,
bool typename_keyword_p,
bool check_dependency_p,
bool type_p,
bool is_declaration)
{
bool success = false;
tree access_check = NULL_TREE;
ptrdiff_t start;
cp_token* token;
if (check_dependency_p
&& cp_lexer_next_token_is (parser->lexer, CPP_NESTED_NAME_SPECIFIER))
{
cp_parser_pre_parsed_nested_name_specifier (parser);
return parser->scope;
}
if (cp_parser_parsing_tentatively (parser)
&& !cp_parser_committed_to_tentative_parse (parser))
{
token = cp_lexer_peek_token (parser->lexer);
start = cp_lexer_token_difference (parser->lexer,
parser->lexer->first_token,
token);
}
else
start = -1;
push_deferring_access_checks (dk_deferred);
while (true)
{
tree new_scope;
tree old_scope;
tree saved_qualifying_scope;
bool template_keyword_p;
token = cp_lexer_peek_token (parser->lexer);
if (token->type == CPP_NESTED_NAME_SPECIFIER)
{
cp_parser_pre_parsed_nested_name_specifier (parser);
success = true;
continue;
}
if (success && token->keyword == RID_TEMPLATE)
;
else if (token->type == CPP_TEMPLATE_ID)
;
else
{
if (token->type != CPP_NAME)
break;
token = cp_lexer_peek_nth_token (parser->lexer, 2);
if (token->type != CPP_SCOPE
&& !cp_parser_nth_token_starts_template_argument_list_p
(parser, 2))
break;
}
cp_parser_parse_tentatively (parser);
if (success)
template_keyword_p = cp_parser_optional_template_keyword (parser);
else
template_keyword_p = false;
old_scope = parser->scope;
saved_qualifying_scope = parser->qualifying_scope;
new_scope
= cp_parser_class_or_namespace_name (parser,
typename_keyword_p,
template_keyword_p,
check_dependency_p,
type_p,
is_declaration);
cp_parser_require (parser, CPP_SCOPE, "`::'");
if (!cp_parser_parse_definitely (parser))
{
bool error_p = false;
parser->scope = old_scope;
parser->qualifying_scope = saved_qualifying_scope;
while (cp_lexer_next_token_is (parser->lexer, CPP_NAME)
&& (cp_lexer_peek_nth_token (parser->lexer, 2)->type
== CPP_SCOPE)
&& (cp_lexer_peek_nth_token (parser->lexer, 3)->type
!= CPP_COMPL))
{
token = cp_lexer_consume_token (parser->lexer);
if (!error_p)
{
tree decl;
decl = cp_parser_lookup_name_simple (parser, token->value);
if (TREE_CODE (decl) == TEMPLATE_DECL)
error ("`%D' used without template parameters",
decl);
else
cp_parser_name_lookup_error
(parser, token->value, decl,
"is not a class or namespace");
parser->scope = NULL_TREE;
error_p = true;
success = true;
}
cp_lexer_consume_token (parser->lexer);
}
break;
}
success = true;
parser->scope = (TREE_CODE (new_scope) == TYPE_DECL
? TREE_TYPE (new_scope)
: new_scope);
if (TYPE_P (parser->scope)
&& !COMPLETE_TYPE_P (parser->scope)
&& !dependent_type_p (parser->scope))
complete_type (parser->scope);
}
access_check = get_deferred_access_checks ();
if (success && start >= 0)
{
token = cp_lexer_advance_token (parser->lexer,
parser->lexer->first_token,
start);
token->type = CPP_NESTED_NAME_SPECIFIER;
token->value = build_tree_list (access_check, parser->scope);
TREE_TYPE (token->value) = parser->qualifying_scope;
token->keyword = RID_MAX;
cp_lexer_purge_tokens_after (parser->lexer, token);
}
pop_deferring_access_checks ();
return success ? parser->scope : NULL_TREE;
}
static tree
cp_parser_nested_name_specifier (cp_parser *parser,
bool typename_keyword_p,
bool check_dependency_p,
bool type_p,
bool is_declaration)
{
tree scope;
scope = cp_parser_nested_name_specifier_opt (parser,
typename_keyword_p,
check_dependency_p,
type_p,
is_declaration);
if (!scope)
{
cp_parser_error (parser, "expected nested-name-specifier");
parser->scope = NULL_TREE;
return error_mark_node;
}
return scope;
}
static tree
cp_parser_class_or_namespace_name (cp_parser *parser,
bool typename_keyword_p,
bool template_keyword_p,
bool check_dependency_p,
bool type_p,
bool is_declaration)
{
tree saved_scope;
tree saved_qualifying_scope;
tree saved_object_scope;
tree scope;
bool only_class_p;
saved_scope = parser->scope;
saved_qualifying_scope = parser->qualifying_scope;
saved_object_scope = parser->object_scope;
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,
typename_keyword_p,
template_keyword_p,
type_p,
check_dependency_p,
false,
is_declaration);
if (!only_class_p && !cp_parser_parse_definitely (parser))
{
parser->scope = saved_scope;
parser->qualifying_scope = saved_qualifying_scope;
parser->object_scope = saved_object_scope;
if (cp_lexer_next_token_is_not (parser->lexer, CPP_NAME)
|| cp_lexer_peek_nth_token (parser->lexer, 2)->type != CPP_SCOPE)
return error_mark_node;
scope = cp_parser_namespace_name (parser);
}
return scope;
}
static tree
cp_parser_postfix_expression (cp_parser *parser, bool address_p)
{
cp_token *token;
enum rid keyword;
cp_id_kind idk = CP_ID_KIND_NONE;
tree postfix_expression = NULL_TREE;
tree qualifying_class = NULL_TREE;
token = cp_lexer_peek_token (parser->lexer);
keyword = token->keyword;
switch (keyword)
{
case RID_DYNCAST:
case RID_STATCAST:
case RID_REINTCAST:
case RID_CONSTCAST:
{
tree type;
tree expression;
const char *saved_message;
cp_lexer_consume_token (parser->lexer);
saved_message = parser->type_definition_forbidden_message;
parser->type_definition_forbidden_message
= "types may not be defined in casts";
cp_parser_require (parser, CPP_LESS, "`<'");
type = cp_parser_type_id (parser);
cp_parser_require (parser, CPP_GREATER, "`>'");
parser->type_definition_forbidden_message = saved_message;
cp_parser_require (parser, CPP_OPEN_PAREN, "`('");
expression = cp_parser_expression (parser);
cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
if (parser->integral_constant_expression_p
&& !dependent_type_p (type)
&& !INTEGRAL_OR_ENUMERATION_TYPE_P (type)
&& !(parser->in_offsetof_p && POINTER_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;
switch (keyword)
{
case RID_DYNCAST:
postfix_expression
= build_dynamic_cast (type, expression);
break;
case RID_STATCAST:
postfix_expression
= build_static_cast (type, expression);
break;
case RID_REINTCAST:
postfix_expression
= build_reinterpret_cast (type, expression);
break;
case RID_CONSTCAST:
postfix_expression
= build_const_cast (type, expression);
break;
default:
abort ();
}
}
break;
case RID_TYPEID:
{
tree type;
const char *saved_message;
bool saved_in_type_id_in_expr_p;
cp_lexer_consume_token (parser->lexer);
cp_parser_require (parser, CPP_OPEN_PAREN, "`('");
saved_message = parser->type_definition_forbidden_message;
parser->type_definition_forbidden_message
= "types may not be defined in a `typeid\' expression";
cp_parser_parse_tentatively (parser);
saved_in_type_id_in_expr_p = parser->in_type_id_in_expr_p;
parser->in_type_id_in_expr_p = true;
type = cp_parser_type_id (parser);
parser->in_type_id_in_expr_p = saved_in_type_id_in_expr_p;
cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
if (cp_parser_parse_definitely (parser))
postfix_expression = get_typeid (type);
else
{
tree expression;
expression = cp_parser_expression (parser);
postfix_expression = build_typeid (expression);
cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
}
if (cp_parser_non_integral_constant_expression(parser,
"`typeid' operator"))
return error_mark_node;
parser->type_definition_forbidden_message = saved_message;
}
break;
case RID_TYPENAME:
{
bool template_p = false;
tree id;
tree type;
cp_lexer_consume_token (parser->lexer);
cp_parser_global_scope_opt (parser,
false);
cp_parser_nested_name_specifier (parser,
true,
true,
true,
true);
template_p = cp_parser_optional_template_keyword (parser);
cp_parser_parse_tentatively (parser);
id = cp_parser_template_id (parser, template_p,
true,
true);
if (!cp_parser_parse_definitely (parser))
id = cp_parser_identifier (parser);
if (TREE_CODE (id) == TYPE_DECL
&& !dependent_type_p (parser->scope))
type = TREE_TYPE (id);
else
type = make_typename_type (parser->scope, id,
1);
postfix_expression = cp_parser_functional_cast (parser, type);
}
break;
default:
{
tree type;
cp_parser_parse_tentatively (parser);
type = cp_parser_simple_type_specifier (parser,
CP_PARSER_FLAGS_NONE,
false);
if (!cp_parser_error_occurred (parser))
postfix_expression
= cp_parser_functional_cast (parser, type);
if (cp_parser_parse_definitely (parser))
break;
if (cp_parser_allow_gnu_extensions_p (parser)
&& cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN))
{
tree initializer_list = NULL_TREE;
bool saved_in_type_id_in_expr_p;
cp_parser_parse_tentatively (parser);
cp_lexer_consume_token (parser->lexer);
saved_in_type_id_in_expr_p = parser->in_type_id_in_expr_p;
parser->in_type_id_in_expr_p = true;
type = cp_parser_type_id (parser);
parser->in_type_id_in_expr_p = saved_in_type_id_in_expr_p;
cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
cp_parser_require (parser, CPP_OPEN_BRACE, "`{'");
if (!cp_parser_error_occurred (parser))
{
bool non_constant_p;
initializer_list
= cp_parser_initializer_list (parser, &non_constant_p);
if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA))
cp_lexer_consume_token (parser->lexer);
cp_parser_require (parser, CPP_CLOSE_BRACE, "`}'");
}
if (cp_parser_parse_definitely (parser))
{
if (pedantic)
pedwarn ("ISO C++ forbids compound-literals");
postfix_expression
= finish_compound_literal (type, initializer_list);
break;
}
}
postfix_expression = cp_parser_primary_expression (parser,
&idk,
&qualifying_class);
}
break;
}
if (qualifying_class)
{
bool done;
token = cp_lexer_peek_token (parser->lexer);
done = (token->type != CPP_OPEN_SQUARE
&& token->type != CPP_OPEN_PAREN
&& token->type != CPP_DOT
&& token->type != CPP_DEREF
&& token->type != CPP_PLUS_PLUS
&& token->type != CPP_MINUS_MINUS);
postfix_expression = finish_qualified_id_expr (qualifying_class,
postfix_expression,
done,
address_p);
if (done)
return postfix_expression;
}
while (true)
{
if (idk == CP_ID_KIND_UNQUALIFIED
&& TREE_CODE (postfix_expression) == IDENTIFIER_NODE
&& cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_PAREN))
postfix_expression
= unqualified_name_lookup_error (postfix_expression);
token = cp_lexer_peek_token (parser->lexer);
switch (token->type)
{
case CPP_OPEN_SQUARE:
{
tree index;
cp_lexer_consume_token (parser->lexer);
index = cp_parser_expression (parser);
cp_parser_require (parser, CPP_CLOSE_SQUARE, "`]'");
postfix_expression
= grok_array_decl (postfix_expression, index);
idk = CP_ID_KIND_NONE;
if (cp_parser_non_integral_constant_expression
(parser, "an array reference"))
postfix_expression = error_mark_node;
}
break;
case CPP_OPEN_PAREN:
{
bool koenig_p;
tree args = (cp_parser_parenthesized_expression_list
(parser, false, NULL));
if (args == error_mark_node)
{
postfix_expression = error_mark_node;
break;
}
if (cp_parser_non_integral_constant_expression (parser,
"a function call"))
{
postfix_expression = error_mark_node;
break;
}
koenig_p = false;
if (idk == CP_ID_KIND_UNQUALIFIED)
{
if (args
&& (is_overloaded_fn (postfix_expression)
|| TREE_CODE (postfix_expression) == IDENTIFIER_NODE))
{
koenig_p = true;
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);
tree fn = TREE_OPERAND (postfix_expression, 1);
if (processing_template_decl
&& (type_dependent_expression_p (instance)
|| (!BASELINK_P (fn)
&& TREE_CODE (fn) != FIELD_DECL)
|| type_dependent_expression_p (fn)
|| any_type_dependent_arguments_p (args)))
{
postfix_expression
= build_min_nt (CALL_EXPR, postfix_expression,
args, NULL_TREE);
break;
}
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,
false,
false);
}
else if (TREE_CODE (postfix_expression) == OFFSET_REF
|| TREE_CODE (postfix_expression) == MEMBER_REF
|| TREE_CODE (postfix_expression) == DOTSTAR_EXPR)
postfix_expression = (build_offset_ref_call_from_tree
(postfix_expression, args));
else if (idk == CP_ID_KIND_QUALIFIED)
postfix_expression
= finish_call_expr (postfix_expression, args,
true,
koenig_p);
else
postfix_expression
= finish_call_expr (postfix_expression, args,
false,
koenig_p);
idk = CP_ID_KIND_NONE;
}
break;
case CPP_DOT:
case CPP_DEREF:
{
tree name;
bool dependent_p;
bool template_p;
tree scope = NULL_TREE;
enum cpp_ttype token_type = token->type;
if (token->type == CPP_DEREF)
postfix_expression = build_x_arrow (postfix_expression);
dependent_p = type_dependent_expression_p (postfix_expression);
parser->scope = NULL_TREE;
parser->qualifying_scope = NULL_TREE;
parser->object_scope = NULL_TREE;
idk = CP_ID_KIND_NONE;
if (!dependent_p
&& TREE_TYPE (postfix_expression) != NULL_TREE)
{
scope = TREE_TYPE (postfix_expression);
scope = non_reference (scope);
scope = complete_type_or_else (scope, NULL_TREE);
parser->context->object_type = scope;
if (!scope)
scope = error_mark_node;
if (scope == error_mark_node)
postfix_expression = error_mark_node;
}
cp_lexer_consume_token (parser->lexer);
if (!scope || !SCALAR_TYPE_P (scope))
{
template_p = cp_parser_optional_template_keyword (parser);
name = cp_parser_id_expression (parser,
template_p,
true,
NULL,
false);
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);
}
else
{
tree s = NULL_TREE;
tree type;
cp_parser_pseudo_destructor_name (parser, &s, &type);
postfix_expression
= finish_pseudo_destructor_expr (postfix_expression,
s, TREE_TYPE (type));
}
parser->context->object_type = NULL_TREE;
if (
!parser->in_offsetof_p
&& (cp_parser_non_integral_constant_expression
(parser,
token_type == CPP_DEREF ? "'->'" : "`.'")))
postfix_expression = error_mark_node;
}
break;
case CPP_PLUS_PLUS:
cp_lexer_consume_token (parser->lexer);
postfix_expression
= finish_increment_expr (postfix_expression,
POSTINCREMENT_EXPR);
if (cp_parser_non_integral_constant_expression (parser,
"an increment"))
postfix_expression = error_mark_node;
idk = CP_ID_KIND_NONE;
break;
case CPP_MINUS_MINUS:
cp_lexer_consume_token (parser->lexer);
postfix_expression
= finish_increment_expr (postfix_expression,
POSTDECREMENT_EXPR);
if (cp_parser_non_integral_constant_expression (parser,
"a decrement"))
postfix_expression = error_mark_node;
idk = CP_ID_KIND_NONE;
break;
default:
return postfix_expression;
}
}
abort ();
return error_mark_node;
}
static tree
cp_parser_parenthesized_expression_list (cp_parser* parser,
bool is_attribute_list,
bool *non_constant_p)
{
tree expression_list = NULL_TREE;
tree identifier = NULL_TREE;
if (non_constant_p)
*non_constant_p = false;
if (!cp_parser_require (parser, CPP_OPEN_PAREN, "`('"))
return error_mark_node;
if (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_PAREN))
while (true)
{
tree expr;
if (is_attribute_list
&& cp_lexer_peek_token (parser->lexer)->type == CPP_NAME)
{
cp_token *token;
token = cp_lexer_consume_token (parser->lexer);
identifier = token->value;
}
else
{
if (non_constant_p)
{
bool expr_non_constant_p;
expr = (cp_parser_constant_expression
(parser, true,
&expr_non_constant_p));
if (expr_non_constant_p)
*non_constant_p = true;
}
else
expr = cp_parser_assignment_expression (parser);
expression_list = tree_cons (NULL_TREE, expr, expression_list);
if (expr == error_mark_node)
goto skip_comma;
}
is_attribute_list = false;
get_comma:;
if (cp_lexer_next_token_is_not (parser->lexer, CPP_COMMA))
break;
cp_lexer_consume_token (parser->lexer);
}
if (!cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'"))
{
int ending;
skip_comma:;
ending = cp_parser_skip_to_closing_parenthesis (parser,
true,
true,
true);
if (ending < 0)
goto get_comma;
if (!ending)
return error_mark_node;
}
expression_list = nreverse (expression_list);
if (identifier)
expression_list = tree_cons (NULL_TREE, identifier, expression_list);
return expression_list;
}
static void
cp_parser_pseudo_destructor_name (cp_parser* parser,
tree* scope,
tree* type)
{
bool nested_name_specifier_p;
cp_parser_global_scope_opt (parser, true);
nested_name_specifier_p
= (cp_parser_nested_name_specifier_opt (parser,
false,
true,
false,
true)
!= NULL_TREE);
if (nested_name_specifier_p
&& cp_lexer_next_token_is_keyword (parser->lexer, RID_TEMPLATE))
{
cp_lexer_consume_token (parser->lexer);
cp_parser_template_id (parser,
true,
false,
true);
cp_parser_require (parser, CPP_SCOPE, "`::'");
}
else if (cp_lexer_next_token_is_not (parser->lexer, CPP_COMPL))
{
*scope = TREE_TYPE (cp_parser_type_name (parser));
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;
}
cp_parser_require (parser, CPP_SCOPE, "`::'");
}
else
*scope = NULL_TREE;
cp_parser_require (parser, CPP_COMPL, "`~'");
*type = cp_parser_type_name (parser);
}
static tree
cp_parser_unary_expression (cp_parser *parser, bool address_p)
{
cp_token *token;
enum tree_code unary_operator;
token = cp_lexer_peek_token (parser->lexer);
if (token->type == CPP_KEYWORD)
{
enum rid keyword = token->keyword;
switch (keyword)
{
case RID_ALIGNOF:
case RID_SIZEOF:
{
tree operand;
enum tree_code op;
op = keyword == RID_ALIGNOF ? ALIGNOF_EXPR : SIZEOF_EXPR;
cp_lexer_consume_token (parser->lexer);
operand = cp_parser_sizeof_operand (parser, keyword);
if (TYPE_P (operand))
return cxx_sizeof_or_alignof_type (operand, op, true);
else
return cxx_sizeof_or_alignof_expr (operand, op);
}
case RID_NEW:
return cp_parser_new_expression (parser);
case RID_DELETE:
return cp_parser_delete_expression (parser);
case RID_EXTENSION:
{
int saved_pedantic;
tree expr;
cp_parser_extension_opt (parser, &saved_pedantic);
expr = cp_parser_simple_cast_expression (parser);
pedantic = saved_pedantic;
return expr;
}
case RID_REALPART:
case RID_IMAGPART:
{
tree expression;
cp_lexer_consume_token (parser->lexer);
expression = cp_parser_simple_cast_expression (parser);
return build_x_unary_op ((keyword == RID_REALPART
? REALPART_EXPR : IMAGPART_EXPR),
expression);
}
break;
default:
break;
}
}
if (cp_lexer_next_token_is (parser->lexer, CPP_SCOPE))
{
enum rid keyword;
keyword = cp_lexer_peek_nth_token (parser->lexer, 2)->keyword;
if (keyword == RID_NEW)
return cp_parser_new_expression (parser);
else if (keyword == RID_DELETE)
return cp_parser_delete_expression (parser);
}
unary_operator = cp_parser_unary_operator (token);
if (unary_operator == ERROR_MARK)
{
if (token->type == CPP_PLUS_PLUS)
unary_operator = PREINCREMENT_EXPR;
else if (token->type == CPP_MINUS_MINUS)
unary_operator = PREDECREMENT_EXPR;
else if (cp_parser_allow_gnu_extensions_p (parser)
&& token->type == CPP_AND_AND)
{
tree identifier;
cp_lexer_consume_token (parser->lexer);
identifier = cp_parser_identifier (parser);
return finish_label_address_expr (identifier);
}
}
if (unary_operator != ERROR_MARK)
{
tree cast_expression;
tree expression = error_mark_node;
const char *non_constant_p = NULL;
token = cp_lexer_consume_token (parser->lexer);
cast_expression
= cp_parser_cast_expression (parser, unary_operator == ADDR_EXPR);
switch (unary_operator)
{
case INDIRECT_REF:
non_constant_p = "`*'";
expression = build_x_indirect_ref (cast_expression, "unary *");
break;
case ADDR_EXPR:
if (!parser->in_offsetof_p)
non_constant_p = "`&'";
case BIT_NOT_EXPR:
expression = build_x_unary_op (unary_operator, cast_expression);
break;
case PREINCREMENT_EXPR:
case PREDECREMENT_EXPR:
non_constant_p = (unary_operator == PREINCREMENT_EXPR
? "`++'" : "`--'");
case CONVERT_EXPR:
case NEGATE_EXPR:
case TRUTH_NOT_EXPR:
expression = finish_unary_op_expr (unary_operator, cast_expression);
break;
default:
abort ();
}
if (non_constant_p
&& cp_parser_non_integral_constant_expression (parser,
non_constant_p))
expression = error_mark_node;
return expression;
}
return cp_parser_postfix_expression (parser, address_p);
}
static enum tree_code
cp_parser_unary_operator (cp_token* token)
{
switch (token->type)
{
case CPP_MULT:
return INDIRECT_REF;
case CPP_AND:
return ADDR_EXPR;
case CPP_PLUS:
return CONVERT_EXPR;
case CPP_MINUS:
return NEGATE_EXPR;
case CPP_NOT:
return TRUTH_NOT_EXPR;
case CPP_COMPL:
return BIT_NOT_EXPR;
default:
return ERROR_MARK;
}
}
static tree
cp_parser_new_expression (cp_parser* parser)
{
bool global_scope_p;
tree placement;
tree type;
tree initializer;
global_scope_p
= (cp_parser_global_scope_opt (parser,
false)
!= NULL_TREE);
cp_parser_require_keyword (parser, RID_NEW, "`new'");
cp_parser_parse_tentatively (parser);
placement = cp_parser_new_placement (parser);
if (!cp_parser_parse_definitely (parser))
placement = NULL_TREE;
if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN))
{
cp_lexer_consume_token (parser->lexer);
type = cp_parser_type_id (parser);
cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
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);
}
}
else
type = cp_parser_new_type_id (parser);
if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN))
initializer = cp_parser_new_initializer (parser);
else
initializer = NULL_TREE;
if (cp_parser_non_integral_constant_expression (parser, "`new'"))
return error_mark_node;
return build_new (placement, type, initializer, global_scope_p);
}
static tree
cp_parser_new_placement (cp_parser* parser)
{
tree expression_list;
expression_list = (cp_parser_parenthesized_expression_list
(parser, false, NULL));
return expression_list;
}
static tree
cp_parser_new_type_id (cp_parser* parser)
{
tree type_specifier_seq;
tree declarator;
const char *saved_message;
saved_message = parser->type_definition_forbidden_message;
parser->type_definition_forbidden_message
= "types may not be defined in a new-type-id";
type_specifier_seq = cp_parser_type_specifier_seq (parser);
parser->type_definition_forbidden_message = saved_message;
declarator = cp_parser_new_declarator_opt (parser);
return build_tree_list (type_specifier_seq, declarator);
}
static tree
cp_parser_new_declarator_opt (cp_parser* parser)
{
enum tree_code code;
tree type;
tree cv_qualifier_seq;
cp_parser_parse_tentatively (parser);
code = cp_parser_ptr_operator (parser, &type, &cv_qualifier_seq);
if (cp_parser_parse_definitely (parser))
{
tree declarator;
declarator = cp_parser_new_declarator_opt (parser);
if (code == INDIRECT_REF)
declarator = make_pointer_declarator (cv_qualifier_seq,
declarator);
else
declarator = make_reference_declarator (cv_qualifier_seq,
declarator);
if (type)
declarator = build_nt (SCOPE_REF, type, declarator);
return declarator;
}
if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_SQUARE))
return cp_parser_direct_new_declarator (parser);
return NULL_TREE;
}
static tree
cp_parser_direct_new_declarator (cp_parser* parser)
{
tree declarator = NULL_TREE;
while (true)
{
tree expression;
cp_parser_require (parser, CPP_OPEN_SQUARE, "`['");
if (!declarator)
{
expression = cp_parser_expression (parser);
if (!processing_template_decl)
{
expression
= build_expr_type_conversion (WANT_INT | WANT_ENUM,
expression,
true);
if (!expression)
{
error ("expression in new-declarator must have integral or enumeration type");
expression = error_mark_node;
}
}
}
else
expression
= cp_parser_constant_expression (parser,
false,
NULL);
cp_parser_require (parser, CPP_CLOSE_SQUARE, "`]'");
declarator = build_nt (ARRAY_REF, declarator, expression);
if (cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_SQUARE))
break;
}
return declarator;
}
static tree
cp_parser_new_initializer (cp_parser* parser)
{
tree expression_list;
expression_list = (cp_parser_parenthesized_expression_list
(parser, false, NULL));
if (!expression_list)
expression_list = void_zero_node;
return expression_list;
}
static tree
cp_parser_delete_expression (cp_parser* parser)
{
bool global_scope_p;
bool array_p;
tree expression;
global_scope_p
= (cp_parser_global_scope_opt (parser,
false)
!= NULL_TREE);
cp_parser_require_keyword (parser, RID_DELETE, "`delete'");
if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_SQUARE))
{
cp_lexer_consume_token (parser->lexer);
cp_parser_require (parser, CPP_CLOSE_SQUARE, "`]'");
array_p = true;
}
else
array_p = false;
expression = cp_parser_simple_cast_expression (parser);
if (cp_parser_non_integral_constant_expression (parser, "`delete'"))
return error_mark_node;
return delete_sanity (expression, NULL_TREE, array_p, global_scope_p);
}
static tree
cp_parser_cast_expression (cp_parser *parser, bool address_p)
{
if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN))
{
tree type = NULL_TREE;
tree expr = NULL_TREE;
bool compound_literal_p;
const char *saved_message;
cp_parser_parse_tentatively (parser);
saved_message = parser->type_definition_forbidden_message;
parser->type_definition_forbidden_message
= "types may not be defined in casts";
cp_lexer_consume_token (parser->lexer);
cp_lexer_save_tokens (parser->lexer);
compound_literal_p
= (cp_parser_skip_to_closing_parenthesis (parser, false, false,
true)
&& cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE));
cp_lexer_rollback_tokens (parser->lexer);
if (compound_literal_p)
cp_parser_simulate_error (parser);
else
{
bool saved_in_type_id_in_expr_p = parser->in_type_id_in_expr_p;
parser->in_type_id_in_expr_p = true;
type = cp_parser_type_id (parser);
cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
parser->in_type_id_in_expr_p = saved_in_type_id_in_expr_p;
}
parser->type_definition_forbidden_message = saved_message;
if (!cp_parser_error_occurred (parser))
expr = cp_parser_simple_cast_expression (parser);
if (cp_parser_parse_definitely (parser))
{
if (warn_old_style_cast
&& !in_system_header
&& !VOID_TYPE_P (type)
&& current_lang_name != lang_name_c)
warning ("use of old-style cast");
if (parser->integral_constant_expression_p
&& !dependent_type_p (type)
&& !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;
expr = build_c_cast (type, expr);
return expr;
}
}
return cp_parser_unary_expression (parser, address_p);
}
static tree
cp_parser_pm_expression (cp_parser* parser)
{
static const cp_parser_token_tree_map map = {
{ CPP_DEREF_STAR, MEMBER_REF },
{ CPP_DOT_STAR, DOTSTAR_EXPR },
{ CPP_EOF, ERROR_MARK }
};
return cp_parser_binary_expression (parser, map,
cp_parser_simple_cast_expression);
}
static tree
cp_parser_multiplicative_expression (cp_parser* parser)
{
static const cp_parser_token_tree_map map = {
{ CPP_MULT, MULT_EXPR },
{ CPP_DIV, TRUNC_DIV_EXPR },
{ CPP_MOD, TRUNC_MOD_EXPR },
{ CPP_EOF, ERROR_MARK }
};
return cp_parser_binary_expression (parser,
map,
cp_parser_pm_expression);
}
static tree
cp_parser_additive_expression (cp_parser* parser)
{
static const cp_parser_token_tree_map map = {
{ CPP_PLUS, PLUS_EXPR },
{ CPP_MINUS, MINUS_EXPR },
{ CPP_EOF, ERROR_MARK }
};
return cp_parser_binary_expression (parser,
map,
cp_parser_multiplicative_expression);
}
static tree
cp_parser_shift_expression (cp_parser* parser)
{
static const cp_parser_token_tree_map map = {
{ CPP_LSHIFT, LSHIFT_EXPR },
{ CPP_RSHIFT, RSHIFT_EXPR },
{ CPP_EOF, ERROR_MARK }
};
return cp_parser_binary_expression (parser,
map,
cp_parser_additive_expression);
}
static tree
cp_parser_relational_expression (cp_parser* parser)
{
static const cp_parser_token_tree_map map = {
{ CPP_LESS, LT_EXPR },
{ CPP_GREATER, GT_EXPR },
{ CPP_LESS_EQ, LE_EXPR },
{ CPP_GREATER_EQ, GE_EXPR },
{ CPP_MIN, MIN_EXPR },
{ CPP_MAX, MAX_EXPR },
{ CPP_EOF, ERROR_MARK }
};
return cp_parser_binary_expression (parser,
map,
cp_parser_shift_expression);
}
static tree
cp_parser_equality_expression (cp_parser* parser)
{
static const cp_parser_token_tree_map map = {
{ CPP_EQ_EQ, EQ_EXPR },
{ CPP_NOT_EQ, NE_EXPR },
{ CPP_EOF, ERROR_MARK }
};
return cp_parser_binary_expression (parser,
map,
cp_parser_relational_expression);
}
static tree
cp_parser_and_expression (cp_parser* parser)
{
static const cp_parser_token_tree_map map = {
{ CPP_AND, BIT_AND_EXPR },
{ CPP_EOF, ERROR_MARK }
};
return cp_parser_binary_expression (parser,
map,
cp_parser_equality_expression);
}
static tree
cp_parser_exclusive_or_expression (cp_parser* parser)
{
static const cp_parser_token_tree_map map = {
{ CPP_XOR, BIT_XOR_EXPR },
{ CPP_EOF, ERROR_MARK }
};
return cp_parser_binary_expression (parser,
map,
cp_parser_and_expression);
}
static tree
cp_parser_inclusive_or_expression (cp_parser* parser)
{
static const cp_parser_token_tree_map map = {
{ CPP_OR, BIT_IOR_EXPR },
{ CPP_EOF, ERROR_MARK }
};
return cp_parser_binary_expression (parser,
map,
cp_parser_exclusive_or_expression);
}
static tree
cp_parser_logical_and_expression (cp_parser* parser)
{
static const cp_parser_token_tree_map map = {
{ CPP_AND_AND, TRUTH_ANDIF_EXPR },
{ CPP_EOF, ERROR_MARK }
};
return cp_parser_binary_expression (parser,
map,
cp_parser_inclusive_or_expression);
}
static tree
cp_parser_logical_or_expression (cp_parser* parser)
{
static const cp_parser_token_tree_map map = {
{ CPP_OR_OR, TRUTH_ORIF_EXPR },
{ CPP_EOF, ERROR_MARK }
};
return cp_parser_binary_expression (parser,
map,
cp_parser_logical_and_expression);
}
static tree
cp_parser_question_colon_clause (cp_parser* parser, tree logical_or_expr)
{
tree expr;
tree assignment_expr;
cp_lexer_consume_token (parser->lexer);
if (cp_parser_allow_gnu_extensions_p (parser)
&& cp_lexer_next_token_is (parser->lexer, CPP_COLON))
expr = NULL_TREE;
else
expr = cp_parser_expression (parser);
cp_parser_require (parser, CPP_COLON, "`:'");
assignment_expr = cp_parser_assignment_expression (parser);
return build_x_conditional_expr (logical_or_expr,
expr,
assignment_expr);
}
static tree
cp_parser_assignment_expression (cp_parser* parser)
{
tree expr;
if (cp_lexer_next_token_is_keyword (parser->lexer, RID_THROW))
expr = cp_parser_throw_expression (parser);
else
{
expr = cp_parser_logical_or_expression (parser);
if (cp_lexer_next_token_is (parser->lexer, CPP_QUERY))
return cp_parser_question_colon_clause (parser, expr);
else
{
enum tree_code assignment_operator;
assignment_operator
= cp_parser_assignment_operator_opt (parser);
if (assignment_operator != ERROR_MARK)
{
tree rhs;
rhs = cp_parser_assignment_expression (parser);
if (cp_parser_non_integral_constant_expression (parser,
"an assignment"))
return error_mark_node;
expr = build_x_modify_expr (expr,
assignment_operator,
rhs);
}
}
}
return expr;
}
static enum tree_code
cp_parser_assignment_operator_opt (cp_parser* parser)
{
enum tree_code op;
cp_token *token;
token = cp_lexer_peek_token (parser->lexer);
switch (token->type)
{
case CPP_EQ:
op = NOP_EXPR;
break;
case CPP_MULT_EQ:
op = MULT_EXPR;
break;
case CPP_DIV_EQ:
op = TRUNC_DIV_EXPR;
break;
case CPP_MOD_EQ:
op = TRUNC_MOD_EXPR;
break;
case CPP_PLUS_EQ:
op = PLUS_EXPR;
break;
case CPP_MINUS_EQ:
op = MINUS_EXPR;
break;
case CPP_RSHIFT_EQ:
op = RSHIFT_EXPR;
break;
case CPP_LSHIFT_EQ:
op = LSHIFT_EXPR;
break;
case CPP_AND_EQ:
op = BIT_AND_EXPR;
break;
case CPP_XOR_EQ:
op = BIT_XOR_EXPR;
break;
case CPP_OR_EQ:
op = BIT_IOR_EXPR;
break;
case CPP_MIN_EQ:
op = MIN_EXPR;
break;
case CPP_MAX_EQ:
op = MAX_EXPR;
break;
default:
op = ERROR_MARK;
}
if (op != ERROR_MARK)
cp_lexer_consume_token (parser->lexer);
return op;
}
static tree
cp_parser_expression (cp_parser* parser)
{
tree expression = NULL_TREE;
while (true)
{
tree assignment_expression;
assignment_expression
= cp_parser_assignment_expression (parser);
if (!expression)
expression = assignment_expression;
else
expression = build_x_compound_expr (expression,
assignment_expression);
if (cp_lexer_next_token_is_not (parser->lexer, CPP_COMMA))
break;
cp_lexer_consume_token (parser->lexer);
if (cp_parser_non_integral_constant_expression (parser,
"a comma operator"))
expression = error_mark_node;
}
return expression;
}
static tree
cp_parser_constant_expression (cp_parser* parser,
bool allow_non_constant_p,
bool *non_constant_p)
{
bool saved_integral_constant_expression_p;
bool saved_allow_non_integral_constant_expression_p;
bool saved_non_integral_constant_expression_p;
tree expression;
saved_integral_constant_expression_p = parser->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;
parser->integral_constant_expression_p = true;
parser->allow_non_integral_constant_expression_p = allow_non_constant_p;
parser->non_integral_constant_expression_p = false;
expression = cp_parser_assignment_expression (parser);
parser->integral_constant_expression_p = saved_integral_constant_expression_p;
parser->allow_non_integral_constant_expression_p
= saved_allow_non_integral_constant_expression_p;
if (allow_non_constant_p)
*non_constant_p = parser->non_integral_constant_expression_p;
parser->non_integral_constant_expression_p = saved_non_integral_constant_expression_p;
return expression;
}
static void
cp_parser_statement (cp_parser* parser, bool in_statement_expr_p)
{
tree statement;
cp_token *token;
location_t statement_locus;
statement = NULL_TREE;
token = cp_lexer_peek_token (parser->lexer);
statement_locus = token->location;
if (token->type == CPP_KEYWORD)
{
enum rid keyword = token->keyword;
switch (keyword)
{
case RID_CASE:
case RID_DEFAULT:
statement = cp_parser_labeled_statement (parser,
in_statement_expr_p);
break;
case RID_IF:
case RID_SWITCH:
statement = cp_parser_selection_statement (parser);
break;
case RID_WHILE:
case RID_DO:
case RID_FOR:
statement = cp_parser_iteration_statement (parser);
break;
case RID_BREAK:
case RID_CONTINUE:
case RID_RETURN:
case RID_GOTO:
statement = cp_parser_jump_statement (parser);
break;
case RID_TRY:
statement = cp_parser_try_block (parser);
break;
default:
break;
}
}
else if (token->type == CPP_NAME)
{
token = cp_lexer_peek_nth_token (parser->lexer, 2);
if (token->type == CPP_COLON)
statement = cp_parser_labeled_statement (parser, in_statement_expr_p);
}
else if (token->type == CPP_OPEN_BRACE)
statement = cp_parser_compound_statement (parser, false);
if (!statement)
{
if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON))
{
cp_parser_parse_tentatively (parser);
cp_parser_declaration_statement (parser);
if (cp_parser_parse_definitely (parser))
return;
}
statement = cp_parser_expression_statement (parser, in_statement_expr_p);
}
if (statement && STATEMENT_CODE_P (TREE_CODE (statement)))
{
SET_EXPR_LOCUS (statement, NULL);
annotate_with_locus (statement, statement_locus);
}
}
static tree
cp_parser_labeled_statement (cp_parser* parser, bool in_statement_expr_p)
{
cp_token *token;
tree statement = error_mark_node;
token = cp_lexer_peek_token (parser->lexer);
if (token->type != CPP_NAME
&& token->type != CPP_KEYWORD)
{
cp_parser_error (parser, "expected labeled-statement");
return error_mark_node;
}
switch (token->keyword)
{
case RID_CASE:
{
tree expr, expr_hi;
cp_token *ellipsis;
cp_lexer_consume_token (parser->lexer);
expr = cp_parser_constant_expression (parser,
false,
NULL);
ellipsis = cp_lexer_peek_token (parser->lexer);
if (ellipsis->type == CPP_ELLIPSIS)
{
cp_lexer_consume_token (parser->lexer);
expr_hi =
cp_parser_constant_expression (parser,
false,
NULL);
}
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, expr_hi);
}
break;
case RID_DEFAULT:
cp_lexer_consume_token (parser->lexer);
if (!parser->in_switch_statement_p)
error ("case label not within a switch statement");
else
statement = finish_case_label (NULL_TREE, NULL_TREE);
break;
default:
statement = finish_label_stmt (cp_parser_identifier (parser));
break;
}
cp_parser_require (parser, CPP_COLON, "`:'");
cp_parser_statement (parser, in_statement_expr_p);
return statement;
}
static tree
cp_parser_expression_statement (cp_parser* parser, bool in_statement_expr_p)
{
tree statement = NULL_TREE;
if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON))
statement = cp_parser_expression (parser);
cp_parser_consume_semicolon_at_end_of_statement (parser);
if (in_statement_expr_p
&& cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_BRACE))
{
statement = finish_stmt_expr_expr (statement);
}
else if (statement)
statement = finish_expr_stmt (statement);
else
finish_stmt ();
return statement;
}
static tree
cp_parser_compound_statement (cp_parser *parser, bool in_statement_expr_p)
{
tree compound_stmt;
if (!cp_parser_require (parser, CPP_OPEN_BRACE, "`{'"))
return error_mark_node;
compound_stmt = begin_compound_stmt (false);
cp_parser_statement_seq_opt (parser, in_statement_expr_p);
finish_compound_stmt (compound_stmt);
cp_parser_require (parser, CPP_CLOSE_BRACE, "`}'");
return compound_stmt;
}
static void
cp_parser_statement_seq_opt (cp_parser* parser, bool in_statement_expr_p)
{
while (true)
{
if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_BRACE)
|| cp_lexer_next_token_is (parser->lexer, CPP_EOF))
break;
cp_parser_statement (parser, in_statement_expr_p);
}
}
static tree
cp_parser_selection_statement (cp_parser* parser)
{
cp_token *token;
enum rid keyword;
token = cp_parser_require (parser, CPP_KEYWORD, "selection-statement");
keyword = token->keyword;
switch (keyword)
{
case RID_IF:
case RID_SWITCH:
{
tree statement;
tree condition;
if (!cp_parser_require (parser, CPP_OPEN_PAREN, "`('"))
{
cp_parser_skip_to_end_of_statement (parser);
return error_mark_node;
}
if (keyword == RID_IF)
statement = begin_if_stmt ();
else
statement = begin_switch_stmt ();
condition = cp_parser_condition (parser);
if (!cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'"))
cp_parser_skip_to_closing_parenthesis (parser, true, false,
true);
if (keyword == RID_IF)
{
tree then_stmt;
finish_if_stmt_cond (condition, statement);
then_stmt = cp_parser_implicitly_scoped_statement (parser);
finish_then_clause (statement);
if (cp_lexer_next_token_is_keyword (parser->lexer,
RID_ELSE))
{
tree else_stmt;
cp_lexer_consume_token (parser->lexer);
else_stmt
= cp_parser_implicitly_scoped_statement (parser);
finish_else_clause (statement);
}
finish_if_stmt ();
}
else
{
tree body;
bool in_switch_statement_p;
finish_switch_cond (condition, statement);
in_switch_statement_p = parser->in_switch_statement_p;
parser->in_switch_statement_p = true;
body = cp_parser_implicitly_scoped_statement (parser);
parser->in_switch_statement_p = in_switch_statement_p;
finish_switch_stmt (statement);
}
return statement;
}
break;
default:
cp_parser_error (parser, "expected selection-statement");
return error_mark_node;
}
}
static tree
cp_parser_condition (cp_parser* parser)
{
tree type_specifiers;
const char *saved_message;
cp_parser_parse_tentatively (parser);
saved_message = parser->type_definition_forbidden_message;
parser->type_definition_forbidden_message
= "types may not be defined in conditions";
type_specifiers = cp_parser_type_specifier_seq (parser);
parser->type_definition_forbidden_message = saved_message;
if (!cp_parser_error_occurred (parser))
{
tree decl;
tree asm_specification;
tree attributes;
tree declarator;
tree initializer = NULL_TREE;
declarator = cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED,
NULL,
NULL);
attributes = cp_parser_attributes_opt (parser);
asm_specification = cp_parser_asm_specification_opt (parser);
cp_parser_require (parser, CPP_EQ, "`='");
if (cp_parser_parse_definitely (parser))
{
decl = start_decl (declarator, type_specifiers,
true,
attributes, NULL_TREE);
initializer = cp_parser_assignment_expression (parser);
cp_finish_decl (decl,
initializer,
asm_specification,
LOOKUP_ONLYCONVERTING);
return convert_from_reference (decl);
}
}
else
cp_parser_abort_tentative_parse (parser);
return cp_parser_expression (parser);
}
static tree
cp_parser_iteration_statement (cp_parser* parser)
{
cp_token *token;
enum rid keyword;
tree statement;
bool in_iteration_statement_p;
token = cp_parser_require (parser, CPP_KEYWORD, "iteration-statement");
if (!token)
return error_mark_node;
in_iteration_statement_p = parser->in_iteration_statement_p;
keyword = token->keyword;
switch (keyword)
{
case RID_WHILE:
{
tree condition;
statement = begin_while_stmt ();
cp_parser_require (parser, CPP_OPEN_PAREN, "`('");
condition = cp_parser_condition (parser);
finish_while_stmt_cond (condition, statement);
cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
parser->in_iteration_statement_p = true;
cp_parser_already_scoped_statement (parser);
parser->in_iteration_statement_p = in_iteration_statement_p;
finish_while_stmt (statement);
}
break;
case RID_DO:
{
tree expression;
statement = begin_do_stmt ();
parser->in_iteration_statement_p = true;
cp_parser_implicitly_scoped_statement (parser);
parser->in_iteration_statement_p = in_iteration_statement_p;
finish_do_body (statement);
cp_parser_require_keyword (parser, RID_WHILE, "`while'");
cp_parser_require (parser, CPP_OPEN_PAREN, "`('");
expression = cp_parser_expression (parser);
finish_do_stmt (expression, statement);
cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
cp_parser_require (parser, CPP_SEMICOLON, "`;'");
}
break;
case RID_FOR:
{
tree condition = NULL_TREE;
tree expression = NULL_TREE;
statement = begin_for_stmt ();
cp_parser_require (parser, CPP_OPEN_PAREN, "`('");
cp_parser_for_init_statement (parser);
finish_for_init_stmt (statement);
if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON))
condition = cp_parser_condition (parser);
finish_for_cond (condition, statement);
cp_parser_require (parser, CPP_SEMICOLON, "`;'");
if (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_PAREN))
expression = cp_parser_expression (parser);
finish_for_expr (expression, statement);
cp_parser_require (parser, CPP_CLOSE_PAREN, "`;'");
parser->in_iteration_statement_p = true;
cp_parser_already_scoped_statement (parser);
parser->in_iteration_statement_p = in_iteration_statement_p;
finish_for_stmt (statement);
}
break;
default:
cp_parser_error (parser, "expected iteration-statement");
statement = error_mark_node;
break;
}
return statement;
}
static void
cp_parser_for_init_statement (cp_parser* parser)
{
if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON))
{
cp_parser_parse_tentatively (parser);
cp_parser_simple_declaration (parser,
false);
if (cp_parser_parse_definitely (parser))
return;
}
cp_parser_expression_statement (parser, false);
}
static tree
cp_parser_jump_statement (cp_parser* parser)
{
tree statement = error_mark_node;
cp_token *token;
enum rid keyword;
token = cp_parser_require (parser, CPP_KEYWORD, "jump-statement");
if (!token)
return error_mark_node;
keyword = token->keyword;
switch (keyword)
{
case RID_BREAK:
if (!parser->in_switch_statement_p
&& !parser->in_iteration_statement_p)
{
error ("break statement not within loop or switch");
statement = error_mark_node;
}
else
statement = finish_break_stmt ();
cp_parser_require (parser, CPP_SEMICOLON, "`;'");
break;
case RID_CONTINUE:
if (!parser->in_iteration_statement_p)
{
error ("continue statement not within a loop");
statement = error_mark_node;
}
else
statement = finish_continue_stmt ();
cp_parser_require (parser, CPP_SEMICOLON, "`;'");
break;
case RID_RETURN:
{
tree expr;
if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON))
expr = cp_parser_expression (parser);
else
expr = NULL_TREE;
statement = finish_return_stmt (expr);
cp_parser_require (parser, CPP_SEMICOLON, "`;'");
}
break;
case RID_GOTO:
if (cp_lexer_next_token_is (parser->lexer, CPP_MULT))
{
if (pedantic)
pedwarn ("ISO C++ forbids computed gotos");
cp_lexer_consume_token (parser->lexer);
finish_goto_stmt (cp_parser_expression (parser));
}
else
finish_goto_stmt (cp_parser_identifier (parser));
cp_parser_require (parser, CPP_SEMICOLON, "`;'");
break;
default:
cp_parser_error (parser, "expected jump-statement");
break;
}
return statement;
}
static void
cp_parser_declaration_statement (cp_parser* parser)
{
cp_parser_block_declaration (parser, true);
finish_stmt ();
}
static tree
cp_parser_implicitly_scoped_statement (cp_parser* parser)
{
tree statement;
if (cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_BRACE))
{
statement = begin_compound_stmt (false);
cp_parser_statement (parser, false);
finish_compound_stmt (statement);
}
else
statement = cp_parser_compound_statement (parser, false);
return statement;
}
static void
cp_parser_already_scoped_statement (cp_parser* parser)
{
if (cp_lexer_next_token_is_not(parser->lexer, CPP_OPEN_BRACE))
{
tree statement;
statement = begin_compound_stmt (true);
cp_parser_statement (parser, false);
finish_compound_stmt (statement);
}
else
cp_parser_statement (parser, false);
}
static void
cp_parser_declaration_seq_opt (cp_parser* parser)
{
while (true)
{
cp_token *token;
token = cp_lexer_peek_token (parser->lexer);
if (token->type == CPP_CLOSE_BRACE
|| token->type == CPP_EOF)
break;
if (token->type == CPP_SEMICOLON)
{
if (pedantic && !in_system_header)
pedwarn ("extra `;'");
cp_lexer_consume_token (parser->lexer);
continue;
}
while (pending_lang_change > 0)
{
push_lang_context (lang_name_c);
--pending_lang_change;
}
while (pending_lang_change < 0)
{
pop_lang_context ();
++pending_lang_change;
}
cp_parser_declaration (parser);
}
}
static void
cp_parser_declaration (cp_parser* parser)
{
cp_token token1;
cp_token token2;
int saved_pedantic;
c_lex_string_translate = true;
if (cp_parser_extension_opt (parser, &saved_pedantic))
{
cp_parser_declaration (parser);
pedantic = saved_pedantic;
return;
}
token1 = *cp_lexer_peek_token (parser->lexer);
if (token1.keyword == RID_EXTERN)
c_lex_string_translate = false;
if (token1.type != CPP_EOF)
token2 = *cp_lexer_peek_nth_token (parser->lexer, 2);
c_lex_string_translate = true;
if (token1.keyword == RID_EXTERN
&& cp_parser_is_string_literal (&token2))
cp_parser_linkage_specification (parser);
else if (token1.keyword == RID_TEMPLATE)
{
if (token2.type == CPP_LESS
&& cp_lexer_peek_nth_token (parser->lexer, 3)->type == CPP_GREATER)
cp_parser_explicit_specialization (parser);
else if (token2.type == CPP_LESS)
cp_parser_template_declaration (parser, false);
else
cp_parser_explicit_instantiation (parser);
}
else if (token1.keyword == RID_EXPORT)
cp_parser_template_declaration (parser, false);
else if (cp_parser_allow_gnu_extensions_p (parser)
&& (token1.keyword == RID_EXTERN
|| token1.keyword == RID_STATIC
|| token1.keyword == RID_INLINE)
&& token2.keyword == RID_TEMPLATE)
cp_parser_explicit_instantiation (parser);
else if (token1.keyword == RID_NAMESPACE
&& (
(token2.type == CPP_NAME
&& (cp_lexer_peek_nth_token (parser->lexer, 3)->type
== CPP_OPEN_BRACE))
|| token2.type == CPP_OPEN_BRACE))
cp_parser_namespace_definition (parser);
else
cp_parser_block_declaration (parser, false);
}
static void
cp_parser_block_declaration (cp_parser *parser,
bool statement_p)
{
cp_token *token1;
int saved_pedantic;
if (cp_parser_extension_opt (parser, &saved_pedantic))
{
cp_parser_block_declaration (parser, statement_p);
pedantic = saved_pedantic;
return;
}
token1 = cp_lexer_peek_token (parser->lexer);
if (token1->keyword == RID_ASM)
{
if (statement_p)
cp_parser_commit_to_tentative_parse (parser);
cp_parser_asm_definition (parser);
}
else if (token1->keyword == RID_NAMESPACE)
cp_parser_namespace_alias_definition (parser);
else if (token1->keyword == RID_USING)
{
cp_token *token2;
if (statement_p)
cp_parser_commit_to_tentative_parse (parser);
token2 = cp_lexer_peek_nth_token (parser->lexer, 2);
if (token2->keyword == RID_NAMESPACE)
cp_parser_using_directive (parser);
else
cp_parser_using_declaration (parser);
}
else if (token1->keyword == RID_LABEL)
{
if (statement_p)
cp_parser_commit_to_tentative_parse (parser);
cp_parser_label_declaration (parser);
}
else
cp_parser_simple_declaration (parser, !statement_p);
}
static void
cp_parser_simple_declaration (cp_parser* parser,
bool function_definition_allowed_p)
{
tree decl_specifiers;
tree attributes;
int declares_class_or_enum;
bool saw_declarator;
push_deferring_access_checks (dk_deferred);
decl_specifiers
= cp_parser_decl_specifier_seq (parser,
CP_PARSER_FLAGS_OPTIONAL,
&attributes,
&declares_class_or_enum);
stop_deferring_access_checks ();
if (!function_definition_allowed_p && !decl_specifiers)
{
cp_parser_error (parser, "expected declaration");
goto done;
}
if (cp_parser_parse_and_diagnose_invalid_type_name (parser))
{
cp_parser_commit_to_tentative_parse (parser);
goto done;
}
saw_declarator = false;
while (cp_lexer_next_token_is_not (parser->lexer,
CPP_SEMICOLON))
{
cp_token *token;
bool function_definition_p;
tree decl;
saw_declarator = true;
decl = cp_parser_init_declarator (parser, decl_specifiers, attributes,
function_definition_allowed_p,
false,
declares_class_or_enum,
&function_definition_p);
if (cp_parser_error_occurred (parser))
goto done;
if (function_definition_p)
{
if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA))
error ("mixing declarations and function-definitions is forbidden");
else
{
pop_deferring_access_checks ();
return;
}
}
token = cp_lexer_peek_token (parser->lexer);
if (token->type == CPP_COMMA)
cp_lexer_consume_token (parser->lexer);
else if (token->type == CPP_SEMICOLON)
break;
else
{
cp_parser_error (parser, "expected `,' or `;'");
cp_parser_skip_to_end_of_statement (parser);
if (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON))
cp_lexer_consume_token (parser->lexer);
goto done;
}
function_definition_allowed_p = false;
}
if (!saw_declarator)
{
if (cp_parser_declares_only_class_p (parser))
shadow_tag (decl_specifiers);
perform_deferred_access_checks ();
}
cp_parser_require (parser, CPP_SEMICOLON, "`;'");
done:
pop_deferring_access_checks ();
}
static tree
cp_parser_decl_specifier_seq (cp_parser* parser,
cp_parser_flags flags,
tree* attributes,
int* declares_class_or_enum)
{
tree decl_specs = NULL_TREE;
bool friend_p = false;
bool constructor_possible_p = !parser->in_declarator_p;
*declares_class_or_enum = 0;
*attributes = NULL_TREE;
while (true)
{
tree decl_spec = NULL_TREE;
bool constructor_p;
cp_token *token;
token = cp_lexer_peek_token (parser->lexer);
if (token->keyword == RID_ATTRIBUTE)
{
decl_spec = cp_parser_attributes_opt (parser);
*attributes = chainon (*attributes, decl_spec);
continue;
}
switch (token->keyword)
{
case RID_FRIEND:
if (friend_p)
error ("duplicate `friend'");
else
friend_p = true;
decl_spec = token->value;
cp_lexer_consume_token (parser->lexer);
break;
case RID_INLINE:
case RID_VIRTUAL:
case RID_EXPLICIT:
decl_spec = cp_parser_function_specifier_opt (parser);
break;
case RID_TYPEDEF:
decl_spec = token->value;
cp_lexer_consume_token (parser->lexer);
constructor_possible_p = false;
cp_parser_commit_to_tentative_parse (parser);
break;
case RID_AUTO:
case RID_REGISTER:
case RID_STATIC:
case RID_EXTERN:
case RID_MUTABLE:
case RID_THREAD:
decl_spec = cp_parser_storage_class_specifier_opt (parser);
break;
default:
break;
}
constructor_p = (!decl_spec
&& constructor_possible_p
&& cp_parser_constructor_declarator_p (parser,
friend_p));
if (!decl_spec && !constructor_p)
{
int decl_spec_declares_class_or_enum;
bool is_cv_qualifier;
decl_spec
= cp_parser_type_specifier (parser, flags,
friend_p,
true,
&decl_spec_declares_class_or_enum,
&is_cv_qualifier);
*declares_class_or_enum |= decl_spec_declares_class_or_enum;
if (decl_spec && !is_cv_qualifier)
flags |= CP_PARSER_FLAGS_NO_USER_DEFINED_TYPES;
if (decl_spec)
constructor_possible_p = false;
}
if (!decl_spec)
{
if (!(flags & CP_PARSER_FLAGS_OPTIONAL))
{
cp_parser_error (parser, "expected decl specifier");
return error_mark_node;
}
break;
}
if (decl_specs == NULL || TREE_VALUE (decl_specs) != error_mark_node)
decl_specs = tree_cons (NULL_TREE, decl_spec, decl_specs);
flags |= CP_PARSER_FLAGS_OPTIONAL;
}
if (friend_p && (*declares_class_or_enum & 2))
error ("class definition may not be declared a friend");
return nreverse (decl_specs);
}
static tree
cp_parser_storage_class_specifier_opt (cp_parser* parser)
{
switch (cp_lexer_peek_token (parser->lexer)->keyword)
{
case RID_AUTO:
case RID_REGISTER:
case RID_STATIC:
case RID_EXTERN:
case RID_MUTABLE:
case RID_THREAD:
return cp_lexer_consume_token (parser->lexer)->value;
default:
return NULL_TREE;
}
}
static tree
cp_parser_function_specifier_opt (cp_parser* parser)
{
switch (cp_lexer_peek_token (parser->lexer)->keyword)
{
case RID_INLINE:
case RID_VIRTUAL:
case RID_EXPLICIT:
return cp_lexer_consume_token (parser->lexer)->value;
default:
return NULL_TREE;
}
}
static void
cp_parser_linkage_specification (cp_parser* parser)
{
cp_token *token;
tree linkage;
cp_parser_require_keyword (parser, RID_EXTERN, "`extern'");
token = cp_lexer_peek_token (parser->lexer);
if (!cp_parser_is_string_literal (token))
{
cp_parser_error (parser, "expected language-name");
return;
}
cp_lexer_consume_token (parser->lexer);
if (token->type == CPP_WSTRING
|| (strlen (TREE_STRING_POINTER (token->value))
!= (size_t) (TREE_STRING_LENGTH (token->value) - 1)))
{
cp_parser_error (parser, "invalid linkage-specification");
linkage = get_identifier ("c++");
}
else
linkage = get_identifier (TREE_STRING_POINTER (token->value));
push_lang_context (linkage);
if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE))
{
cp_lexer_consume_token (parser->lexer);
cp_parser_declaration_seq_opt (parser);
cp_parser_require (parser, CPP_CLOSE_BRACE, "`}'");
}
else
{
bool 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
= saved_in_unbraced_linkage_specification_p;
}
pop_lang_context ();
}
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;
if (!cp_parser_require_keyword (parser, RID_OPERATOR, "`operator'"))
return error_mark_node;
saved_scope = parser->scope;
saved_qualifying_scope = parser->qualifying_scope;
saved_object_scope = parser->object_scope;
if (saved_scope)
pop_p = push_scope (saved_scope);
type = cp_parser_conversion_type_id (parser);
if (pop_p)
pop_scope (saved_scope);
parser->scope = saved_scope;
parser->qualifying_scope = saved_qualifying_scope;
parser->object_scope = saved_object_scope;
if (type == error_mark_node)
return error_mark_node;
return mangle_conv_op_name_for_type (type);
}
static tree
cp_parser_conversion_type_id (cp_parser* parser)
{
tree attributes;
tree type_specifiers;
tree declarator;
attributes = cp_parser_attributes_opt (parser);
type_specifiers = cp_parser_type_specifier_seq (parser);
if (type_specifiers == error_mark_node)
return error_mark_node;
declarator = cp_parser_conversion_declarator_opt (parser);
return grokdeclarator (declarator, type_specifiers, TYPENAME,
0, &attributes);
}
static tree
cp_parser_conversion_declarator_opt (cp_parser* parser)
{
enum tree_code code;
tree class_type;
tree cv_qualifier_seq;
cp_parser_parse_tentatively (parser);
code = cp_parser_ptr_operator (parser, &class_type,
&cv_qualifier_seq);
if (cp_parser_parse_definitely (parser))
{
tree declarator;
declarator = cp_parser_conversion_declarator_opt (parser);
if (code == INDIRECT_REF)
declarator = make_pointer_declarator (cv_qualifier_seq,
declarator);
else
declarator = make_reference_declarator (cv_qualifier_seq,
declarator);
if (class_type)
declarator = build_nt (SCOPE_REF, class_type, declarator);
return declarator;
}
return NULL_TREE;
}
static bool
cp_parser_ctor_initializer_opt (cp_parser* parser)
{
if (cp_lexer_next_token_is_not (parser->lexer, CPP_COLON))
{
if (DECL_CONSTRUCTOR_P (current_function_decl))
finish_mem_initializers (NULL_TREE);
return false;
}
cp_lexer_consume_token (parser->lexer);
cp_parser_mem_initializer_list (parser);
return true;
}
static void
cp_parser_mem_initializer_list (cp_parser* parser)
{
tree mem_initializer_list = NULL_TREE;
if (!DECL_CONSTRUCTOR_P (current_function_decl))
error ("only constructors take base initializers");
while (true)
{
tree mem_initializer;
mem_initializer = cp_parser_mem_initializer (parser);
if (mem_initializer)
{
TREE_CHAIN (mem_initializer) = mem_initializer_list;
mem_initializer_list = mem_initializer;
}
if (cp_lexer_next_token_is_not (parser->lexer, CPP_COMMA))
break;
cp_lexer_consume_token (parser->lexer);
}
if (DECL_CONSTRUCTOR_P (current_function_decl))
finish_mem_initializers (mem_initializer_list);
}
static tree
cp_parser_mem_initializer (cp_parser* parser)
{
tree mem_initializer_id;
tree expression_list;
tree member;
if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN))
{
pedwarn ("anachronistic old-style base class initializer");
mem_initializer_id = NULL_TREE;
}
else
mem_initializer_id = cp_parser_mem_initializer_id (parser);
member = expand_member_init (mem_initializer_id);
if (member && !DECL_P (member))
in_base_initializer = 1;
expression_list
= cp_parser_parenthesized_expression_list (parser, false,
NULL);
if (!expression_list)
expression_list = void_type_node;
in_base_initializer = 0;
return member ? build_tree_list (member, expression_list) : NULL_TREE;
}
static tree
cp_parser_mem_initializer_id (cp_parser* parser)
{
bool global_scope_p;
bool nested_name_specifier_p;
tree id;
global_scope_p
= (cp_parser_global_scope_opt (parser,
false)
!= NULL_TREE);
nested_name_specifier_p
= (cp_parser_nested_name_specifier_opt (parser,
true,
true,
true,
true)
!= NULL_TREE);
if (global_scope_p || nested_name_specifier_p)
return cp_parser_class_name (parser,
true,
false,
false,
true,
false,
true);
cp_parser_parse_tentatively (parser);
id = cp_parser_class_name (parser,
true,
false,
false,
true,
false,
true);
if (cp_parser_parse_definitely (parser))
return id;
return cp_parser_identifier (parser);
}
static tree
cp_parser_operator_function_id (cp_parser* parser)
{
if (!cp_parser_require_keyword (parser, RID_OPERATOR, "`operator'"))
return error_mark_node;
return cp_parser_operator (parser);
}
static tree
cp_parser_operator (cp_parser* parser)
{
tree id = NULL_TREE;
cp_token *token;
token = cp_lexer_peek_token (parser->lexer);
switch (token->type)
{
case CPP_KEYWORD:
{
enum tree_code op;
if (token->keyword == RID_NEW)
op = NEW_EXPR;
else if (token->keyword == RID_DELETE)
op = DELETE_EXPR;
else
break;
cp_lexer_consume_token (parser->lexer);
token = cp_lexer_peek_token (parser->lexer);
if (token->type == CPP_OPEN_SQUARE)
{
cp_lexer_consume_token (parser->lexer);
cp_parser_require (parser, CPP_CLOSE_SQUARE, "`]'");
id = ansi_opname (op == NEW_EXPR
? VEC_NEW_EXPR : VEC_DELETE_EXPR);
}
else
id = ansi_opname (op);
return id;
}
case CPP_PLUS:
id = ansi_opname (PLUS_EXPR);
break;
case CPP_MINUS:
id = ansi_opname (MINUS_EXPR);
break;
case CPP_MULT:
id = ansi_opname (MULT_EXPR);
break;
case CPP_DIV:
id = ansi_opname (TRUNC_DIV_EXPR);
break;
case CPP_MOD:
id = ansi_opname (TRUNC_MOD_EXPR);
break;
case CPP_XOR:
id = ansi_opname (BIT_XOR_EXPR);
break;
case CPP_AND:
id = ansi_opname (BIT_AND_EXPR);
break;
case CPP_OR:
id = ansi_opname (BIT_IOR_EXPR);
break;
case CPP_COMPL:
id = ansi_opname (BIT_NOT_EXPR);
break;
case CPP_NOT:
id = ansi_opname (TRUTH_NOT_EXPR);
break;
case CPP_EQ:
id = ansi_assopname (NOP_EXPR);
break;
case CPP_LESS:
id = ansi_opname (LT_EXPR);
break;
case CPP_GREATER:
id = ansi_opname (GT_EXPR);
break;
case CPP_PLUS_EQ:
id = ansi_assopname (PLUS_EXPR);
break;
case CPP_MINUS_EQ:
id = ansi_assopname (MINUS_EXPR);
break;
case CPP_MULT_EQ:
id = ansi_assopname (MULT_EXPR);
break;
case CPP_DIV_EQ:
id = ansi_assopname (TRUNC_DIV_EXPR);
break;
case CPP_MOD_EQ:
id = ansi_assopname (TRUNC_MOD_EXPR);
break;
case CPP_XOR_EQ:
id = ansi_assopname (BIT_XOR_EXPR);
break;
case CPP_AND_EQ:
id = ansi_assopname (BIT_AND_EXPR);
break;
case CPP_OR_EQ:
id = ansi_assopname (BIT_IOR_EXPR);
break;
case CPP_LSHIFT:
id = ansi_opname (LSHIFT_EXPR);
break;
case CPP_RSHIFT:
id = ansi_opname (RSHIFT_EXPR);
break;
case CPP_LSHIFT_EQ:
id = ansi_assopname (LSHIFT_EXPR);
break;
case CPP_RSHIFT_EQ:
id = ansi_assopname (RSHIFT_EXPR);
break;
case CPP_EQ_EQ:
id = ansi_opname (EQ_EXPR);
break;
case CPP_NOT_EQ:
id = ansi_opname (NE_EXPR);
break;
case CPP_LESS_EQ:
id = ansi_opname (LE_EXPR);
break;
case CPP_GREATER_EQ:
id = ansi_opname (GE_EXPR);
break;
case CPP_AND_AND:
id = ansi_opname (TRUTH_ANDIF_EXPR);
break;
case CPP_OR_OR:
id = ansi_opname (TRUTH_ORIF_EXPR);
break;
case CPP_PLUS_PLUS:
id = ansi_opname (POSTINCREMENT_EXPR);
break;
case CPP_MINUS_MINUS:
id = ansi_opname (PREDECREMENT_EXPR);
break;
case CPP_COMMA:
id = ansi_opname (COMPOUND_EXPR);
break;
case CPP_DEREF_STAR:
id = ansi_opname (MEMBER_REF);
break;
case CPP_DEREF:
id = ansi_opname (COMPONENT_REF);
break;
case CPP_OPEN_PAREN:
cp_lexer_consume_token (parser->lexer);
cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
return ansi_opname (CALL_EXPR);
case CPP_OPEN_SQUARE:
cp_lexer_consume_token (parser->lexer);
cp_parser_require (parser, CPP_CLOSE_SQUARE, "`]'");
return ansi_opname (ARRAY_REF);
case CPP_MIN:
id = ansi_opname (MIN_EXPR);
break;
case CPP_MAX:
id = ansi_opname (MAX_EXPR);
break;
case CPP_MIN_EQ:
id = ansi_assopname (MIN_EXPR);
break;
case CPP_MAX_EQ:
id = ansi_assopname (MAX_EXPR);
break;
default:
break;
}
if (id)
cp_lexer_consume_token (parser->lexer);
else
{
cp_parser_error (parser, "expected operator");
id = error_mark_node;
}
return id;
}
static void
cp_parser_template_declaration (cp_parser* parser, bool member_p)
{
if (cp_lexer_next_token_is_keyword (parser->lexer, RID_EXPORT))
{
cp_lexer_consume_token (parser->lexer);
warning ("keyword `export' not implemented, and will be ignored");
}
cp_parser_template_declaration_after_export (parser, member_p);
}
static tree
cp_parser_template_parameter_list (cp_parser* parser)
{
tree parameter_list = NULL_TREE;
while (true)
{
tree parameter;
cp_token *token;
parameter = cp_parser_template_parameter (parser);
parameter_list = process_template_parm (parameter_list,
parameter);
token = cp_lexer_peek_token (parser->lexer);
if (token->type != CPP_COMMA)
break;
cp_lexer_consume_token (parser->lexer);
}
return parameter_list;
}
static tree
cp_parser_template_parameter (cp_parser* parser)
{
cp_token *token;
token = cp_lexer_peek_token (parser->lexer);
if (token->keyword == RID_TEMPLATE)
return cp_parser_type_parameter (parser);
if (token->keyword == RID_TYPENAME || token->keyword == RID_CLASS)
{
token = cp_lexer_peek_nth_token (parser->lexer, 2);
if (token->type == CPP_NAME)
token = cp_lexer_peek_nth_token (parser->lexer, 3);
if (token->type == CPP_COMMA
|| token->type == CPP_EQ
|| token->type == CPP_GREATER)
return cp_parser_type_parameter (parser);
}
return
cp_parser_parameter_declaration (parser, true,
NULL);
}
static tree
cp_parser_type_parameter (cp_parser* parser)
{
cp_token *token;
tree parameter;
token = cp_parser_require (parser, CPP_KEYWORD,
"`class', `typename', or `template'");
if (!token)
return error_mark_node;
switch (token->keyword)
{
case RID_CLASS:
case RID_TYPENAME:
{
tree identifier;
tree default_argument;
if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
identifier = cp_parser_identifier (parser);
else
identifier = NULL_TREE;
parameter = finish_template_type_parm (class_type_node, identifier);
if (cp_lexer_next_token_is (parser->lexer, CPP_EQ))
{
cp_lexer_consume_token (parser->lexer);
default_argument = cp_parser_type_id (parser);
}
else
default_argument = NULL_TREE;
parameter = build_tree_list (default_argument, parameter);
}
break;
case RID_TEMPLATE:
{
tree parameter_list;
tree identifier;
tree default_argument;
cp_parser_require (parser, CPP_LESS, "`<'");
begin_template_parm_list ();
parameter_list
= cp_parser_template_parameter_list (parser);
parameter_list = end_template_parm_list (parameter_list);
cp_parser_require (parser, CPP_GREATER, "`>'");
cp_parser_require_keyword (parser, RID_CLASS, "`class'");
if (cp_lexer_next_token_is_not (parser->lexer, CPP_EQ)
&& cp_lexer_next_token_is_not (parser->lexer, CPP_GREATER)
&& cp_lexer_next_token_is_not (parser->lexer, CPP_COMMA))
identifier = cp_parser_identifier (parser);
else
identifier = NULL_TREE;
parameter = finish_template_template_parm (class_type_node,
identifier);
if (cp_lexer_next_token_is (parser->lexer, CPP_EQ))
{
bool is_template;
cp_lexer_consume_token (parser->lexer);
default_argument
= cp_parser_id_expression (parser,
false,
true,
&is_template,
false);
if (TREE_CODE (default_argument) == TYPE_DECL)
;
else
default_argument
= cp_parser_lookup_name (parser, default_argument,
false,
is_template,
false,
true);
default_argument
= check_template_template_default_arg (default_argument);
}
else
default_argument = NULL_TREE;
parameter = build_tree_list (default_argument, parameter);
}
break;
default:
cp_parser_error (parser,
"expected `class', `typename', or `template'");
parameter = error_mark_node;
}
return parameter;
}
static tree
cp_parser_template_id (cp_parser *parser,
bool template_keyword_p,
bool check_dependency_p,
bool is_declaration)
{
tree template;
tree arguments;
tree template_id;
ptrdiff_t start_of_id;
tree access_check = NULL_TREE;
cp_token *next_token, *next_token_2;
bool is_identifier;
next_token = cp_lexer_peek_token (parser->lexer);
if (next_token->type == CPP_TEMPLATE_ID)
{
tree value;
tree check;
value = cp_lexer_consume_token (parser->lexer)->value;
for (check = TREE_PURPOSE (value); check; check = TREE_CHAIN (check))
perform_or_defer_access_check (TREE_PURPOSE (check),
TREE_VALUE (check));
return TREE_VALUE (value);
}
if ((next_token->type != CPP_NAME && next_token->keyword != RID_OPERATOR)
|| (next_token->type == CPP_NAME
&& !cp_parser_nth_token_starts_template_argument_list_p
(parser, 2)))
{
cp_parser_error (parser, "expected template-id");
return error_mark_node;
}
if (cp_parser_parsing_tentatively (parser)
&& !cp_parser_committed_to_tentative_parse (parser))
{
next_token = cp_lexer_peek_token (parser->lexer);
start_of_id = cp_lexer_token_difference (parser->lexer,
parser->lexer->first_token,
next_token);
}
else
start_of_id = -1;
push_deferring_access_checks (dk_deferred);
is_identifier = false;
template = cp_parser_template_name (parser, template_keyword_p,
check_dependency_p,
is_declaration,
&is_identifier);
if (template == error_mark_node || is_identifier)
{
pop_deferring_access_checks ();
return template;
}
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))
{
cp_parser_parse_tentatively (parser);
next_token_2->type = CPP_SCOPE;
cp_lexer_consume_token (parser->lexer);
arguments = cp_parser_enclosed_template_argument_list (parser);
if (!cp_parser_parse_definitely (parser))
{
next_token_2->type = CPP_COLON;
cp_parser_error (parser, "expected `<'");
pop_deferring_access_checks ();
return error_mark_node;
}
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
{
if (!cp_parser_require (parser, CPP_LESS, "`<'"))
{
pop_deferring_access_checks ();
return error_mark_node;
}
arguments = cp_parser_enclosed_template_argument_list (parser);
}
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,
CPP_SCOPE));
else
{
my_friendly_assert ((DECL_FUNCTION_TEMPLATE_P (template)
|| TREE_CODE (template) == OVERLOAD
|| BASELINK_P (template)),
20010716);
template_id = lookup_template_function (template, arguments);
}
access_check = get_deferred_access_checks ();
if (start_of_id >= 0)
{
cp_token *token;
token = cp_lexer_advance_token (parser->lexer,
parser->lexer->first_token,
start_of_id);
token->type = CPP_TEMPLATE_ID;
token->value = build_tree_list (access_check, template_id);
token->keyword = RID_MAX;
cp_lexer_purge_tokens_after (parser->lexer, token);
}
pop_deferring_access_checks ();
return template_id;
}
static tree
cp_parser_template_name (cp_parser* parser,
bool template_keyword_p,
bool check_dependency_p,
bool is_declaration,
bool *is_identifier)
{
tree identifier;
tree decl;
tree fns;
if (cp_lexer_next_token_is_keyword (parser->lexer, RID_OPERATOR))
{
cp_parser_parse_tentatively (parser);
identifier = cp_parser_operator_function_id (parser);
if (!cp_parser_parse_definitely (parser))
{
cp_parser_error (parser, "expected template-name");
return error_mark_node;
}
}
else
identifier = cp_parser_identifier (parser);
if (identifier == error_mark_node)
return error_mark_node;
if (processing_template_decl
&& cp_parser_nth_token_starts_template_argument_list_p (parser, 1))
{
if (is_declaration
&& !template_keyword_p
&& parser->scope && TYPE_P (parser->scope)
&& dependent_type_p (parser->scope))
{
ptrdiff_t start;
cp_token* token;
error ("non-template `%D' used as template", identifier);
error ("(use `%T::template %D' to indicate that it is a template)",
parser->scope, identifier);
if (cp_parser_parsing_tentatively (parser)
&& !cp_parser_committed_to_tentative_parse (parser))
{
cp_parser_simulate_error (parser);
token = cp_lexer_peek_token (parser->lexer);
token = cp_lexer_prev_token (parser->lexer, token);
start = cp_lexer_token_difference (parser->lexer,
parser->lexer->first_token,
token);
}
else
start = -1;
cp_lexer_consume_token (parser->lexer);
cp_parser_enclosed_template_argument_list (parser);
cp_parser_skip_to_closing_parenthesis (parser,
true,
true,
false);
if (start >= 0)
{
token = cp_lexer_advance_token (parser->lexer,
parser->lexer->first_token,
start);
cp_lexer_purge_tokens_after (parser->lexer, token);
}
if (is_identifier)
*is_identifier = true;
return identifier;
}
if (template_keyword_p
&& (!parser->scope
|| (TYPE_P (parser->scope)
&& dependent_type_p (parser->scope))))
return identifier;
}
decl = cp_parser_lookup_name (parser, identifier,
false,
false,
false,
check_dependency_p);
decl = maybe_get_template_decl_from_type_decl (decl);
if (TREE_CODE (decl) == TEMPLATE_DECL)
;
else
{
fns = BASELINK_P (decl) ? BASELINK_FUNCTIONS (decl) : decl;
if (TREE_CODE (fns) == OVERLOAD)
{
tree fn;
for (fn = fns; fn; fn = OVL_NEXT (fn))
if (TREE_CODE (OVL_CURRENT (fn)) == TEMPLATE_DECL)
break;
}
else
{
cp_parser_error (parser, "expected template-name");
return error_mark_node;
}
}
if (DECL_FUNCTION_TEMPLATE_P (decl) || !DECL_P (decl))
{
tree scope = CP_DECL_CONTEXT (get_first_fn (decl));
if (TYPE_P (scope) && dependent_type_p (scope))
return identifier;
}
return decl;
}
static tree
cp_parser_template_argument_list (cp_parser* parser)
{
tree fixed_args[10];
unsigned n_args = 0;
unsigned alloced = 10;
tree *arg_ary = fixed_args;
tree vec;
bool saved_in_template_argument_list_p;
saved_in_template_argument_list_p = parser->in_template_argument_list_p;
parser->in_template_argument_list_p = true;
do
{
tree argument;
if (n_args)
cp_lexer_consume_token (parser->lexer);
argument = cp_parser_template_argument (parser);
if (n_args == alloced)
{
alloced *= 2;
if (arg_ary == fixed_args)
{
arg_ary = xmalloc (sizeof (tree) * alloced);
memcpy (arg_ary, fixed_args, sizeof (tree) * n_args);
}
else
arg_ary = xrealloc (arg_ary, sizeof (tree) * alloced);
}
arg_ary[n_args++] = argument;
}
while (cp_lexer_next_token_is (parser->lexer, CPP_COMMA));
vec = make_tree_vec (n_args);
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;
return vec;
}
static tree
cp_parser_template_argument (cp_parser* parser)
{
tree argument;
bool template_p;
bool address_p;
bool maybe_type_id = false;
cp_token *token;
cp_id_kind idk;
tree qualifying_class;
cp_parser_parse_tentatively (parser);
argument = cp_parser_type_id (parser);
if (!cp_parser_error_occurred (parser)
&& cp_lexer_next_token_is (parser->lexer, CPP_RSHIFT))
{
maybe_type_id = true;
cp_parser_abort_tentative_parse (parser);
}
else
{
if (!cp_parser_next_token_ends_template_argument_p (parser))
cp_parser_error (parser, "expected template-argument");
if (cp_parser_parse_definitely (parser))
return argument;
}
cp_parser_parse_tentatively (parser);
argument = cp_parser_id_expression (parser,
false,
true,
&template_p,
false);
if (!cp_parser_next_token_ends_template_argument_p (parser))
cp_parser_error (parser, "expected template-argument");
if (!cp_parser_error_occurred (parser))
{
if (TREE_CODE (argument) != TYPE_DECL)
argument = cp_parser_lookup_name (parser, argument,
false,
template_p,
false,
true);
if (TREE_CODE (argument) != TEMPLATE_DECL
&& TREE_CODE (argument) != UNBOUND_CLASS_TEMPLATE)
cp_parser_error (parser, "expected template-name");
}
if (cp_parser_parse_definitely (parser))
return argument;
if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
{
cp_parser_parse_tentatively (parser);
argument = cp_parser_primary_expression (parser,
&idk,
&qualifying_class);
if (TREE_CODE (argument) != TEMPLATE_PARM_INDEX
|| !cp_parser_next_token_ends_template_argument_p (parser))
cp_parser_simulate_error (parser);
if (cp_parser_parse_definitely (parser))
return argument;
}
address_p = cp_lexer_next_token_is (parser->lexer, CPP_AND);
if (address_p)
cp_lexer_consume_token (parser->lexer);
token = cp_lexer_peek_token (parser->lexer);
if (token->type == CPP_NAME
|| token->keyword == RID_OPERATOR
|| token->type == CPP_SCOPE
|| token->type == CPP_TEMPLATE_ID
|| token->type == CPP_NESTED_NAME_SPECIFIER)
{
cp_parser_parse_tentatively (parser);
argument = cp_parser_primary_expression (parser,
&idk,
&qualifying_class);
if (cp_parser_error_occurred (parser)
|| !cp_parser_next_token_ends_template_argument_p (parser))
cp_parser_abort_tentative_parse (parser);
else
{
if (qualifying_class)
argument = finish_qualified_id_expr (qualifying_class,
argument,
true,
address_p);
if (TREE_CODE (argument) == VAR_DECL)
{
if (!DECL_EXTERNAL_LINKAGE_P (argument))
cp_parser_simulate_error (parser);
}
else if (is_overloaded_fn (argument))
;
else if (address_p
&& (TREE_CODE (argument) == OFFSET_REF
|| TREE_CODE (argument) == SCOPE_REF))
;
else
cp_parser_simulate_error (parser);
if (cp_parser_parse_definitely (parser))
{
if (address_p)
argument = build_x_unary_op (ADDR_EXPR, argument);
return argument;
}
}
}
if (address_p)
{
cp_parser_error (parser, "invalid non-type template argument");
return error_mark_node;
}
if (maybe_type_id)
cp_parser_parse_tentatively (parser);
argument = cp_parser_constant_expression (parser,
false,
NULL);
argument = fold_non_dependent_expr (argument);
if (!maybe_type_id)
return argument;
if (!cp_parser_next_token_ends_template_argument_p (parser))
cp_parser_error (parser, "expected template-argument");
if (cp_parser_parse_definitely (parser))
return argument;
return cp_parser_type_id (parser);
}
static void
cp_parser_explicit_instantiation (cp_parser* parser)
{
int declares_class_or_enum;
tree decl_specifiers;
tree attributes;
tree extension_specifier = NULL_TREE;
if (cp_parser_allow_gnu_extensions_p (parser))
{
extension_specifier
= cp_parser_storage_class_specifier_opt (parser);
if (!extension_specifier)
extension_specifier = cp_parser_function_specifier_opt (parser);
}
cp_parser_require_keyword (parser, RID_TEMPLATE, "`template'");
begin_explicit_instantiation ();
push_deferring_access_checks (dk_no_check);
decl_specifiers
= cp_parser_decl_specifier_seq (parser,
CP_PARSER_FLAGS_OPTIONAL,
&attributes,
&declares_class_or_enum);
if (declares_class_or_enum && cp_parser_declares_only_class_p (parser))
{
tree type;
type = check_tag_decl (decl_specifiers);
pop_deferring_access_checks ();
if (type)
do_type_instantiation (type, extension_specifier, 1);
}
else
{
tree declarator;
tree decl;
declarator
= cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED,
NULL,
NULL);
cp_parser_check_for_definition_in_return_type (declarator,
declares_class_or_enum);
if (declarator != error_mark_node)
{
decl = grokdeclarator (declarator, decl_specifiers,
NORMAL, 0, NULL);
pop_deferring_access_checks ();
do_decl_instantiation (decl, extension_specifier);
}
else
{
pop_deferring_access_checks ();
cp_parser_skip_to_end_of_statement (parser);
}
}
end_explicit_instantiation ();
cp_parser_consume_semicolon_at_end_of_statement (parser);
}
static void
cp_parser_explicit_specialization (cp_parser* parser)
{
cp_parser_require_keyword (parser, RID_TEMPLATE, "`template'");
cp_parser_require (parser, CPP_LESS, "`<'");
cp_parser_require (parser, CPP_GREATER, "`>'");
++parser->num_template_parameter_lists;
begin_specialization ();
if (cp_lexer_next_token_is_keyword (parser->lexer, RID_TEMPLATE))
{
if (cp_lexer_peek_nth_token (parser->lexer, 2)->type == CPP_LESS
&& cp_lexer_peek_nth_token (parser->lexer, 3)->type != CPP_GREATER)
cp_parser_template_declaration_after_export (parser,
false);
else
cp_parser_explicit_specialization (parser);
}
else
cp_parser_single_declaration (parser,
false,
NULL);
end_specialization ();
--parser->num_template_parameter_lists;
}
static tree
cp_parser_type_specifier (cp_parser* parser,
cp_parser_flags flags,
bool is_friend,
bool is_declaration,
int* declares_class_or_enum,
bool* is_cv_qualifier)
{
tree type_spec = NULL_TREE;
cp_token *token;
enum rid keyword;
if (declares_class_or_enum)
*declares_class_or_enum = 0;
if (is_cv_qualifier)
*is_cv_qualifier = false;
token = cp_lexer_peek_token (parser->lexer);
keyword = token->keyword;
switch (keyword)
{
case RID_CLASS:
case RID_STRUCT:
case RID_UNION:
case RID_ENUM:
cp_parser_parse_tentatively (parser);
if (keyword == RID_ENUM)
type_spec = cp_parser_enum_specifier (parser);
else
type_spec = cp_parser_class_specifier (parser);
if (cp_parser_parse_definitely (parser))
{
if (declares_class_or_enum)
*declares_class_or_enum = 2;
return type_spec;
}
case RID_TYPENAME:
type_spec = cp_parser_elaborated_type_specifier (parser,
is_friend,
is_declaration);
if (declares_class_or_enum && keyword != RID_TYPENAME)
*declares_class_or_enum = 1;
return type_spec;
case RID_CONST:
case RID_VOLATILE:
case RID_RESTRICT:
type_spec = cp_parser_cv_qualifier_opt (parser);
my_friendly_assert (type_spec != NULL, 20000328);
if (is_cv_qualifier)
*is_cv_qualifier = true;
return type_spec;
case RID_COMPLEX:
return cp_lexer_consume_token (parser->lexer)->value;
default:
break;
}
type_spec = cp_parser_simple_type_specifier (parser, flags,
true);
if (!type_spec && !(flags & CP_PARSER_FLAGS_OPTIONAL))
{
cp_parser_error (parser, "expected type specifier");
return error_mark_node;
}
return type_spec;
}
static tree
cp_parser_simple_type_specifier (cp_parser* parser, cp_parser_flags flags,
bool identifier_p)
{
tree type = NULL_TREE;
cp_token *token;
token = cp_lexer_peek_token (parser->lexer);
switch (token->keyword)
{
case RID_CHAR:
type = char_type_node;
break;
case RID_WCHAR:
type = wchar_type_node;
break;
case RID_BOOL:
type = boolean_type_node;
break;
case RID_SHORT:
type = short_integer_type_node;
break;
case RID_INT:
type = integer_type_node;
break;
case RID_LONG:
type = long_integer_type_node;
break;
case RID_SIGNED:
type = integer_type_node;
break;
case RID_UNSIGNED:
type = unsigned_type_node;
break;
case RID_FLOAT:
type = float_type_node;
break;
case RID_DOUBLE:
type = double_type_node;
break;
case RID_VOID:
type = void_type_node;
break;
case RID_TYPEOF:
{
tree operand;
cp_lexer_consume_token (parser->lexer);
operand = cp_parser_sizeof_operand (parser, RID_TYPEOF);
if (!TYPE_P (operand))
operand = finish_typeof (operand);
return operand;
}
default:
break;
}
if (type)
{
tree id;
id = cp_lexer_consume_token (parser->lexer)->value;
cp_parser_check_for_invalid_template_id (parser, type);
return identifier_p ? id : TYPE_NAME (type);
}
if (!(flags & CP_PARSER_FLAGS_NO_USER_DEFINED_TYPES))
{
if (flags & CP_PARSER_FLAGS_OPTIONAL)
cp_parser_parse_tentatively (parser);
cp_parser_global_scope_opt (parser,
false);
cp_parser_nested_name_specifier_opt (parser,
false,
true,
false,
false);
if (parser->scope
&& cp_parser_optional_template_keyword (parser))
{
type = cp_parser_template_id (parser,
true,
true,
false);
if (TREE_CODE (type) != TYPE_DECL)
{
cp_parser_error (parser, "expected template-id for type");
type = NULL_TREE;
}
}
else
type = cp_parser_type_name (parser);
if ((flags & CP_PARSER_FLAGS_OPTIONAL)
&& !cp_parser_parse_definitely (parser))
type = NULL_TREE;
}
if (!type && !(flags & CP_PARSER_FLAGS_OPTIONAL))
{
cp_parser_error (parser, "expected type-name");
return error_mark_node;
}
if (type && type != error_mark_node)
cp_parser_check_for_invalid_template_id (parser, TREE_TYPE (type));
return type;
}
static tree
cp_parser_type_name (cp_parser* parser)
{
tree type_decl;
tree identifier;
cp_parser_parse_tentatively (parser);
type_decl = cp_parser_class_name (parser,
false,
false,
false,
true,
false,
false);
if (!cp_parser_parse_definitely (parser))
{
identifier = cp_parser_identifier (parser);
if (identifier == error_mark_node)
return error_mark_node;
type_decl = cp_parser_lookup_name_simple (parser, identifier);
if (TREE_CODE (type_decl) != TYPE_DECL)
{
if (!cp_parser_simulate_error (parser))
cp_parser_name_lookup_error (parser, identifier, type_decl,
"is not a type");
type_decl = error_mark_node;
}
else if (type_decl != error_mark_node
&& !parser->scope)
maybe_note_name_used_in_class (identifier, type_decl);
}
return type_decl;
}
static tree
cp_parser_elaborated_type_specifier (cp_parser* parser,
bool is_friend,
bool is_declaration)
{
enum tag_types tag_type;
tree identifier;
tree type = NULL_TREE;
tree attributes = NULL_TREE;
if (cp_lexer_next_token_is_keyword (parser->lexer, RID_ENUM))
{
cp_lexer_consume_token (parser->lexer);
tag_type = enum_type;
attributes = cp_parser_attributes_opt (parser);
}
else if (cp_lexer_next_token_is_keyword (parser->lexer,
RID_TYPENAME))
{
cp_lexer_consume_token (parser->lexer);
tag_type = typename_type;
if (!processing_template_decl)
pedwarn ("using `typename' outside of template");
}
else
{
tag_type = cp_parser_class_key (parser);
if (tag_type == none_type)
return error_mark_node;
attributes = cp_parser_attributes_opt (parser);
}
cp_parser_global_scope_opt (parser,
false);
if (tag_type == typename_type)
{
if (cp_parser_nested_name_specifier (parser,
true,
true,
true,
is_declaration)
== error_mark_node)
return error_mark_node;
}
else
cp_parser_nested_name_specifier_opt (parser,
true,
true,
true,
is_declaration);
if (tag_type != enum_type)
{
bool template_p = false;
tree decl;
template_p = cp_parser_optional_template_keyword (parser);
if (!template_p)
cp_parser_parse_tentatively (parser);
decl = cp_parser_template_id (parser, template_p,
true,
is_declaration);
if (!template_p && !cp_parser_parse_definitely (parser))
;
else if (TREE_CODE (decl) == TEMPLATE_ID_EXPR
&& tag_type == typename_type)
type = make_typename_type (parser->scope, decl,
1);
else
type = TREE_TYPE (decl);
}
if (!type)
{
identifier = cp_parser_identifier (parser);
if (identifier == error_mark_node)
{
parser->scope = NULL_TREE;
return error_mark_node;
}
if (tag_type == typename_type)
return cp_parser_make_typename_type (parser, parser->scope,
identifier);
if (parser->scope)
{
tree decl;
decl = cp_parser_lookup_name (parser, identifier,
true,
false,
false,
true);
decl = (cp_parser_maybe_treat_template_as_class
(decl, is_friend
&& parser->num_template_parameter_lists));
if (TREE_CODE (decl) != TYPE_DECL)
{
error ("expected type-name");
return error_mark_node;
}
if (TREE_CODE (TREE_TYPE (decl)) != TYPENAME_TYPE)
check_elaborated_type_specifier
(tag_type, decl,
(parser->num_template_parameter_lists
|| DECL_SELF_REFERENCE_P (decl)));
type = TREE_TYPE (decl);
}
else
{
if (attributes)
warning ("type attributes are honored only at type definition");
type = xref_tag (tag_type, identifier,
(is_friend
|| !is_declaration
|| cp_lexer_next_token_is_not (parser->lexer,
CPP_SEMICOLON)),
parser->num_template_parameter_lists);
}
}
if (tag_type != enum_type)
cp_parser_check_class_key (tag_type, type);
cp_parser_check_for_invalid_template_id (parser, type);
return type;
}
static tree
cp_parser_enum_specifier (cp_parser* parser)
{
cp_token *token;
tree identifier = NULL_TREE;
tree type;
if (!cp_parser_require_keyword (parser, RID_ENUM, "`enum'"))
return error_mark_node;
token = cp_lexer_peek_token (parser->lexer);
if (token->type == CPP_NAME)
identifier = cp_parser_identifier (parser);
if (!cp_parser_require (parser, CPP_OPEN_BRACE, "`{'"))
return error_mark_node;
cp_parser_commit_to_tentative_parse (parser);
cp_parser_check_type_definition (parser);
type = start_enum (identifier ? identifier : make_anon_name ());
token = cp_lexer_peek_token (parser->lexer);
if (token->type != CPP_CLOSE_BRACE)
cp_parser_enumerator_list (parser, type);
cp_parser_require (parser, CPP_CLOSE_BRACE, "`}'");
finish_enum (type);
return type;
}
static void
cp_parser_enumerator_list (cp_parser* parser, tree type)
{
while (true)
{
cp_token *token;
cp_parser_enumerator_definition (parser, type);
token = cp_lexer_peek_token (parser->lexer);
if (token->type != CPP_COMMA)
break;
cp_lexer_consume_token (parser->lexer);
if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_BRACE))
{
if (pedantic && !in_system_header)
pedwarn ("comma at end of enumerator list");
break;
}
}
}
static void
cp_parser_enumerator_definition (cp_parser* parser, tree type)
{
cp_token *token;
tree identifier;
tree value;
identifier = cp_parser_identifier (parser);
if (identifier == error_mark_node)
return;
token = cp_lexer_peek_token (parser->lexer);
if (token->type == CPP_EQ)
{
cp_lexer_consume_token (parser->lexer);
value = cp_parser_constant_expression (parser,
false,
NULL);
}
else
value = NULL_TREE;
build_enumerator (identifier, value, type);
}
static tree
cp_parser_namespace_name (cp_parser* parser)
{
tree identifier;
tree namespace_decl;
identifier = cp_parser_identifier (parser);
if (identifier == error_mark_node)
return error_mark_node;
namespace_decl = cp_parser_lookup_name (parser, identifier,
false,
false,
true,
true);
if (namespace_decl == error_mark_node
|| TREE_CODE (namespace_decl) != NAMESPACE_DECL)
{
cp_parser_error (parser, "expected namespace-name");
namespace_decl = error_mark_node;
}
return namespace_decl;
}
static void
cp_parser_namespace_definition (cp_parser* parser)
{
tree identifier;
cp_parser_require_keyword (parser, RID_NAMESPACE, "`namespace'");
if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
identifier = cp_parser_identifier (parser);
else
identifier = NULL_TREE;
cp_parser_require (parser, CPP_OPEN_BRACE, "`{'");
push_namespace (identifier);
cp_parser_namespace_body (parser);
pop_namespace ();
cp_parser_require (parser, CPP_CLOSE_BRACE, "`}'");
}
static void
cp_parser_namespace_body (cp_parser* parser)
{
cp_parser_declaration_seq_opt (parser);
}
static void
cp_parser_namespace_alias_definition (cp_parser* parser)
{
tree identifier;
tree namespace_specifier;
cp_parser_require_keyword (parser, RID_NAMESPACE, "`namespace'");
identifier = cp_parser_identifier (parser);
if (identifier == error_mark_node)
return;
cp_parser_require (parser, CPP_EQ, "`='");
namespace_specifier
= cp_parser_qualified_namespace_specifier (parser);
cp_parser_require (parser, CPP_SEMICOLON, "`;'");
do_namespace_alias (identifier, namespace_specifier);
}
static tree
cp_parser_qualified_namespace_specifier (cp_parser* parser)
{
cp_parser_global_scope_opt (parser,
false);
cp_parser_nested_name_specifier_opt (parser,
false,
true,
false,
true);
return cp_parser_namespace_name (parser);
}
static void
cp_parser_using_declaration (cp_parser* parser)
{
cp_token *token;
bool typename_p = false;
bool global_scope_p;
tree decl;
tree identifier;
tree scope;
tree qscope;
cp_parser_require_keyword (parser, RID_USING, "`using'");
token = cp_lexer_peek_token (parser->lexer);
if (token->keyword == RID_TYPENAME)
{
typename_p = true;
cp_lexer_consume_token (parser->lexer);
}
global_scope_p
= (cp_parser_global_scope_opt (parser,
false)
!= NULL_TREE);
if (typename_p || !global_scope_p)
qscope = cp_parser_nested_name_specifier (parser, typename_p,
true,
false,
true);
else
qscope = cp_parser_nested_name_specifier_opt (parser,
false,
true,
false,
true);
if (!qscope)
qscope = global_namespace;
identifier = cp_parser_unqualified_id (parser,
false,
true,
true);
if (identifier == error_mark_node)
;
else if (TREE_CODE (identifier) != IDENTIFIER_NODE
&& TREE_CODE (identifier) != BIT_NOT_EXPR)
error ("a template-id may not appear in a using-declaration");
else
{
scope = current_scope ();
if (scope && TYPE_P (scope))
{
decl = do_class_using_decl (build_nt (SCOPE_REF,
parser->scope,
identifier));
finish_member_declaration (decl);
}
else
{
decl = cp_parser_lookup_name_simple (parser, identifier);
if (decl == error_mark_node)
cp_parser_name_lookup_error (parser, identifier, decl, NULL);
else if (scope)
do_local_using_decl (decl, qscope, identifier);
else
do_toplevel_using_decl (decl, qscope, identifier);
}
}
cp_parser_require (parser, CPP_SEMICOLON, "`;'");
}
static void
cp_parser_using_directive (cp_parser* parser)
{
tree namespace_decl;
tree attribs;
cp_parser_require_keyword (parser, RID_USING, "`using'");
cp_parser_require_keyword (parser, RID_NAMESPACE, "`namespace'");
cp_parser_global_scope_opt (parser, false);
cp_parser_nested_name_specifier_opt (parser,
false,
true,
false,
true);
namespace_decl = cp_parser_namespace_name (parser);
attribs = cp_parser_attributes_opt (parser);
parse_using_directive (namespace_decl, attribs);
cp_parser_require (parser, CPP_SEMICOLON, "`;'");
}
static void
cp_parser_asm_definition (cp_parser* parser)
{
cp_token *token;
tree string;
tree outputs = NULL_TREE;
tree inputs = NULL_TREE;
tree clobbers = NULL_TREE;
tree asm_stmt;
bool volatile_p = false;
bool extended_p = false;
cp_parser_require_keyword (parser, RID_ASM, "`asm'");
if (cp_parser_allow_gnu_extensions_p (parser)
&& cp_lexer_next_token_is_keyword (parser->lexer, RID_VOLATILE))
{
volatile_p = true;
cp_lexer_consume_token (parser->lexer);
}
cp_parser_require (parser, CPP_OPEN_PAREN, "`('");
c_lex_string_translate = false;
token = cp_parser_require (parser, CPP_STRING, "asm body");
if (!token)
goto finish;
string = token->value;
if (cp_parser_allow_gnu_extensions_p (parser)
&& at_function_scope_p ()
&& (cp_lexer_next_token_is (parser->lexer, CPP_COLON)
|| cp_lexer_next_token_is (parser->lexer, CPP_SCOPE)))
{
bool inputs_p = false;
bool clobbers_p = false;
extended_p = true;
if (cp_lexer_next_token_is (parser->lexer, CPP_COLON))
{
cp_lexer_consume_token (parser->lexer);
if (cp_lexer_next_token_is_not (parser->lexer,
CPP_COLON)
&& cp_lexer_next_token_is_not (parser->lexer,
CPP_SCOPE)
&& cp_lexer_next_token_is_not (parser->lexer,
CPP_CLOSE_PAREN))
outputs = cp_parser_asm_operand_list (parser);
}
else if (cp_lexer_next_token_is (parser->lexer, CPP_SCOPE))
{
cp_lexer_consume_token (parser->lexer);
inputs_p = true;
}
if (inputs_p
|| cp_lexer_next_token_is (parser->lexer, CPP_COLON))
{
if (!inputs_p)
cp_lexer_consume_token (parser->lexer);
if (cp_lexer_next_token_is_not (parser->lexer,
CPP_COLON)
&& cp_lexer_next_token_is_not (parser->lexer,
CPP_SCOPE)
&& cp_lexer_next_token_is_not (parser->lexer,
CPP_CLOSE_PAREN))
inputs = cp_parser_asm_operand_list (parser);
}
else if (cp_lexer_next_token_is (parser->lexer, CPP_SCOPE))
clobbers_p = true;
if (clobbers_p
|| cp_lexer_next_token_is (parser->lexer, CPP_COLON))
{
if (!clobbers_p)
cp_lexer_consume_token (parser->lexer);
if (cp_lexer_next_token_is_not (parser->lexer,
CPP_CLOSE_PAREN))
clobbers = cp_parser_asm_clobber_list (parser);
}
}
if (!cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'"))
cp_parser_skip_to_closing_parenthesis (parser, true, false,
true);
cp_parser_require (parser, CPP_SEMICOLON, "`;'");
if (at_function_scope_p ())
{
asm_stmt = finish_asm_stmt (volatile_p, string, outputs,
inputs, clobbers);
if (!extended_p)
ASM_INPUT_P (asm_stmt) = 1;
}
else
assemble_asm (string);
finish:
c_lex_string_translate = true;
}
static tree
cp_parser_init_declarator (cp_parser* parser,
tree decl_specifiers,
tree prefix_attributes,
bool function_definition_allowed_p,
bool member_p,
int declares_class_or_enum,
bool* function_definition_p)
{
cp_token *token;
tree declarator;
tree attributes;
tree asm_specification;
tree initializer;
tree decl = NULL_TREE;
tree scope;
bool is_initialized;
bool is_parenthesized_init;
bool is_non_constant_init;
int ctor_dtor_or_conv_p;
bool friend_p;
bool pop_p = false;
if (function_definition_p)
*function_definition_p = false;
resume_deferring_access_checks ();
declarator
= cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED,
&ctor_dtor_or_conv_p,
NULL);
stop_deferring_access_checks ();
if (declarator == error_mark_node)
return error_mark_node;
cp_parser_check_for_definition_in_return_type (declarator,
declares_class_or_enum);
scope = get_scope_of_declarator (declarator);
if (cp_parser_allow_gnu_extensions_p (parser))
{
asm_specification = cp_parser_asm_specification_opt (parser);
attributes = cp_parser_attributes_opt (parser);
}
else
{
asm_specification = NULL_TREE;
attributes = NULL_TREE;
}
token = cp_lexer_peek_token (parser->lexer);
if (cp_parser_token_starts_function_definition_p (token))
{
if (!function_definition_allowed_p)
{
cp_parser_error (parser,
"a function-definition is not allowed here");
return error_mark_node;
}
else
{
if (asm_specification)
error ("an asm-specification is not allowed on a function-definition");
if (attributes)
error ("attributes are not allowed on a function-definition");
*function_definition_p = true;
if (member_p)
decl = cp_parser_save_member_function_body (parser,
decl_specifiers,
declarator,
prefix_attributes);
else
decl
= (cp_parser_function_definition_from_specifiers_and_declarator
(parser, decl_specifiers, prefix_attributes, declarator));
return decl;
}
}
if (!decl_specifiers && ctor_dtor_or_conv_p <= 0)
{
cp_parser_error (parser,
"expected constructor, destructor, or type conversion");
return error_mark_node;
}
is_initialized = (token->type == CPP_EQ
|| token->type == CPP_OPEN_PAREN);
if (!is_initialized
&& token->type != CPP_COMMA
&& token->type != CPP_SEMICOLON)
{
cp_parser_error (parser, "expected init-declarator");
return error_mark_node;
}
cp_parser_commit_to_tentative_parse (parser);
if (decl_specifiers != NULL
&& TREE_VALUE (decl_specifiers) == error_mark_node)
{
cp_parser_error (parser, "invalid type in declaration");
TREE_VALUE (decl_specifiers) = integer_type_node;
}
friend_p = cp_parser_friend_p (decl_specifiers);
if (!cp_parser_check_declarator_template_parameters (parser, declarator))
return error_mark_node;
if (!member_p)
{
if (parser->in_unbraced_linkage_specification_p)
{
decl_specifiers = tree_cons (error_mark_node,
get_identifier ("extern"),
decl_specifiers);
have_extern_spec = false;
}
decl = start_decl (declarator, decl_specifiers,
is_initialized, attributes, prefix_attributes);
}
if (scope)
pop_p = push_scope (scope);
if (!member_p && decl)
{
tree saved_current_function_decl = NULL_TREE;
if (TREE_CODE (decl) == FUNCTION_DECL)
{
saved_current_function_decl = current_function_decl;
current_function_decl = decl;
}
perform_deferred_access_checks ();
if (TREE_CODE (decl) == FUNCTION_DECL)
current_function_decl = saved_current_function_decl;
}
if (is_initialized)
initializer = cp_parser_initializer (parser,
&is_parenthesized_init,
&is_non_constant_init);
else
{
initializer = NULL_TREE;
is_parenthesized_init = false;
is_non_constant_init = true;
}
if (cp_parser_allow_gnu_extensions_p (parser) && is_parenthesized_init)
if (cp_parser_attributes_opt (parser))
warning ("attributes after parenthesized initializer ignored");
if (pop_p)
pop_scope (scope);
if (member_p)
{
decl = grokfield (declarator, decl_specifiers,
initializer, NULL_TREE,
NULL_TREE);
if (decl && TREE_CODE (decl) == FUNCTION_DECL)
cp_parser_save_default_args (parser, decl);
}
if (!friend_p && decl)
cp_finish_decl (decl,
initializer,
asm_specification,
((is_parenthesized_init || !is_initialized)
? 0 : LOOKUP_ONLYCONVERTING));
if (decl && TREE_CODE (decl) == VAR_DECL
&& is_initialized && !is_non_constant_init)
DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl) = true;
return decl;
}
static tree
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;
enum tree_code code;
tree cv_qualifier_seq;
tree class_type;
tree attributes = NULL_TREE;
if (ctor_dtor_or_conv_p)
*ctor_dtor_or_conv_p = 0;
if (cp_parser_allow_gnu_extensions_p (parser))
attributes = cp_parser_attributes_opt (parser);
token = cp_lexer_peek_token (parser->lexer);
cp_parser_parse_tentatively (parser);
code = cp_parser_ptr_operator (parser,
&class_type,
&cv_qualifier_seq);
if (cp_parser_parse_definitely (parser))
{
if (parenthesized_p)
*parenthesized_p = true;
if (dcl_kind != CP_PARSER_DECLARATOR_NAMED)
cp_parser_parse_tentatively (parser);
declarator = cp_parser_declarator (parser, dcl_kind,
NULL,
NULL);
if (dcl_kind != CP_PARSER_DECLARATOR_NAMED
&& !cp_parser_parse_definitely (parser))
declarator = NULL_TREE;
if (code == INDIRECT_REF)
declarator = make_pointer_declarator (cv_qualifier_seq,
declarator);
else
declarator = make_reference_declarator (cv_qualifier_seq,
declarator);
if (class_type)
declarator = build_nt (SCOPE_REF, class_type, declarator);
}
else
{
if (parenthesized_p)
*parenthesized_p = cp_lexer_next_token_is (parser->lexer,
CPP_OPEN_PAREN);
declarator = cp_parser_direct_declarator (parser, dcl_kind,
ctor_dtor_or_conv_p);
}
if (attributes && declarator != error_mark_node)
declarator = tree_cons (attributes, declarator, NULL_TREE);
return declarator;
}
static tree
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;
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)
{
token = cp_lexer_peek_token (parser->lexer);
if (token->type == CPP_OPEN_PAREN)
{
if (!first || dcl_kind != CP_PARSER_DECLARATOR_NAMED)
{
tree params;
unsigned saved_num_template_parameter_lists;
cp_parser_parse_tentatively (parser);
cp_lexer_consume_token (parser->lexer);
if (first)
{
parser->default_arg_ok_p = false;
parser->in_declarator_p = true;
}
saved_num_template_parameter_lists
= parser->num_template_parameter_lists;
parser->num_template_parameter_lists = 0;
params = cp_parser_parameter_declaration_clause (parser);
parser->num_template_parameter_lists
= saved_num_template_parameter_lists;
if (cp_parser_parse_definitely (parser))
{
tree cv_qualifiers;
tree exception_specification;
if (ctor_dtor_or_conv_p)
*ctor_dtor_or_conv_p = *ctor_dtor_or_conv_p < 0;
first = false;
cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
cv_qualifiers = cp_parser_cv_qualifier_seq_opt (parser);
exception_specification
= cp_parser_exception_specification_opt (parser);
declarator = make_call_declarator (declarator,
params,
cv_qualifiers,
exception_specification);
parser->default_arg_ok_p = false;
continue;
}
}
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;
cp_lexer_consume_token (parser->lexer);
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,
NULL);
parser->in_type_id_in_expr_p = saved_in_type_id_in_expr_p;
first = false;
if (!cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'"))
declarator = error_mark_node;
if (declarator == error_mark_node)
break;
goto handle_declarator;
}
else
break;
}
else if ((!first || dcl_kind != CP_PARSER_DECLARATOR_NAMED)
&& token->type == CPP_OPEN_SQUARE)
{
tree bounds;
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;
cp_lexer_consume_token (parser->lexer);
token = cp_lexer_peek_token (parser->lexer);
if (token->type != CPP_CLOSE_SQUARE)
{
bool non_constant_p;
bounds
= cp_parser_constant_expression (parser,
true,
&non_constant_p);
if (!non_constant_p)
bounds = fold_non_dependent_expr (bounds);
}
else
bounds = NULL_TREE;
if (!cp_parser_require (parser, CPP_CLOSE_SQUARE, "`]'"))
{
declarator = error_mark_node;
break;
}
declarator = build_nt (ARRAY_REF, declarator, bounds);
}
else if (first && dcl_kind != CP_PARSER_DECLARATOR_ABSTRACT)
{
if (dcl_kind == CP_PARSER_DECLARATOR_EITHER)
cp_parser_parse_tentatively (parser);
declarator = 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)
{
cp_parser_error (parser, "expected unqualified-id");
declarator = error_mark_node;
}
}
if (declarator == error_mark_node)
break;
if (TREE_CODE (declarator) == SCOPE_REF
&& !current_scope ())
{
tree scope = TREE_OPERAND (declarator, 0);
if (TREE_CODE (scope) == TYPENAME_TYPE)
{
tree type;
type = resolve_typename_type (scope,
false);
if (type != error_mark_node)
scope = type;
declarator = build_nt (SCOPE_REF,
scope,
TREE_OPERAND (declarator, 1));
}
}
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 ())))
{
tree unqualified_name;
tree class_type;
if (TREE_CODE (declarator) == SCOPE_REF)
{
class_type = TREE_OPERAND (declarator, 0);
unqualified_name = TREE_OPERAND (declarator, 1);
}
else
{
class_type = current_class_type;
unqualified_name = declarator;
}
if (TREE_CODE (unqualified_name) == BIT_NOT_EXPR
|| IDENTIFIER_TYPENAME_P (unqualified_name)
|| constructor_name_p (unqualified_name, class_type)
|| (TREE_CODE (unqualified_name) == TYPE_DECL
&& same_type_p (TREE_TYPE (unqualified_name),
class_type)))
*ctor_dtor_or_conv_p = -1;
}
handle_declarator:;
scope = get_scope_of_declarator (declarator);
if (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)))
parser->default_arg_ok_p = saved_default_arg_ok_p;
else
parser->default_arg_ok_p = false;
first = false;
}
else
break;
}
if (!declarator)
cp_parser_error (parser, "expected declarator");
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;
}
static enum tree_code
cp_parser_ptr_operator (cp_parser* parser,
tree* type,
tree* cv_qualifier_seq)
{
enum tree_code code = ERROR_MARK;
cp_token *token;
*type = NULL_TREE;
*cv_qualifier_seq = NULL_TREE;
token = cp_lexer_peek_token (parser->lexer);
if (token->type == CPP_MULT || token->type == CPP_AND)
{
code = (token->type == CPP_AND ? ADDR_EXPR : INDIRECT_REF);
cp_lexer_consume_token (parser->lexer);
if (code == INDIRECT_REF
|| cp_parser_allow_gnu_extensions_p (parser))
*cv_qualifier_seq = cp_parser_cv_qualifier_seq_opt (parser);
}
else
{
cp_parser_parse_tentatively (parser);
cp_parser_global_scope_opt (parser,
false);
cp_parser_nested_name_specifier (parser,
false,
true,
false,
false);
if (!cp_parser_error_occurred (parser)
&& cp_parser_require (parser, CPP_MULT, "`*'"))
{
*type = parser->scope;
parser->scope = NULL_TREE;
parser->qualifying_scope = NULL_TREE;
parser->object_scope = NULL_TREE;
code = INDIRECT_REF;
*cv_qualifier_seq = cp_parser_cv_qualifier_seq_opt (parser);
}
if (!cp_parser_parse_definitely (parser))
cp_parser_error (parser, "expected ptr-operator");
}
return code;
}
static tree
cp_parser_cv_qualifier_seq_opt (cp_parser* parser)
{
tree cv_qualifiers = NULL_TREE;
while (true)
{
tree cv_qualifier;
cv_qualifier = cp_parser_cv_qualifier_opt (parser);
if (!cv_qualifier)
break;
cv_qualifiers
= tree_cons (NULL_TREE, cv_qualifier, cv_qualifiers);
}
return nreverse (cv_qualifiers);
}
static tree
cp_parser_cv_qualifier_opt (cp_parser* parser)
{
cp_token *token;
tree cv_qualifier = NULL_TREE;
token = cp_lexer_peek_token (parser->lexer);
switch (token->keyword)
{
case RID_CONST:
case RID_VOLATILE:
case RID_RESTRICT:
cv_qualifier = token->value;
cp_lexer_consume_token (parser->lexer);
break;
default:
break;
}
return cv_qualifier;
}
static tree
cp_parser_declarator_id (cp_parser* parser)
{
tree id_expression;
id_expression = cp_parser_id_expression (parser,
false,
false,
NULL,
true);
if (parser->scope)
{
id_expression = build_nt (SCOPE_REF, parser->scope, id_expression);
parser->scope = NULL_TREE;
}
return id_expression;
}
static tree
cp_parser_type_id (cp_parser* parser)
{
tree type_specifier_seq;
tree abstract_declarator;
type_specifier_seq
= cp_parser_type_specifier_seq (parser);
if (type_specifier_seq == error_mark_node)
return error_mark_node;
cp_parser_parse_tentatively (parser);
abstract_declarator
= cp_parser_declarator (parser, CP_PARSER_DECLARATOR_ABSTRACT, NULL,
NULL);
if (!cp_parser_parse_definitely (parser))
abstract_declarator = NULL_TREE;
return groktypename (build_tree_list (type_specifier_seq,
abstract_declarator));
}
static tree
cp_parser_type_specifier_seq (cp_parser* parser)
{
bool seen_type_specifier = false;
tree type_specifier_seq = NULL_TREE;
while (true)
{
tree type_specifier;
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);
continue;
}
if (seen_type_specifier)
cp_parser_parse_tentatively (parser);
type_specifier = cp_parser_type_specifier (parser,
CP_PARSER_FLAGS_NONE,
false,
false,
NULL,
NULL);
if (!seen_type_specifier && type_specifier == error_mark_node)
return error_mark_node;
else if (seen_type_specifier && !cp_parser_parse_definitely (parser))
break;
type_specifier_seq
= tree_cons (NULL_TREE, type_specifier, type_specifier_seq);
seen_type_specifier = true;
}
return nreverse (type_specifier_seq);
}
static tree
cp_parser_parameter_declaration_clause (cp_parser* parser)
{
tree parameters;
cp_token *token;
bool ellipsis_p;
token = cp_lexer_peek_token (parser->lexer);
if (token->type == CPP_ELLIPSIS)
{
cp_lexer_consume_token (parser->lexer);
return NULL_TREE;
}
else if (token->type == CPP_CLOSE_PAREN)
{
#ifndef NO_IMPLICIT_EXTERN_C
if (in_system_header && current_class_type == NULL
&& current_lang_name == lang_name_c)
return NULL_TREE;
else
#endif
return void_list_node;
}
else if (token->keyword == RID_VOID
&& (cp_lexer_peek_nth_token (parser->lexer, 2)->type
== CPP_CLOSE_PAREN))
{
cp_lexer_consume_token (parser->lexer);
return void_list_node;
}
parameters = cp_parser_parameter_declaration_list (parser);
if (parameters == error_mark_node)
return error_mark_node;
token = cp_lexer_peek_token (parser->lexer);
if (token->type == CPP_COMMA)
{
cp_lexer_consume_token (parser->lexer);
ellipsis_p
= (cp_parser_require (parser, CPP_ELLIPSIS, "`...'") != NULL);
}
else if (token->type == CPP_ELLIPSIS)
{
cp_lexer_consume_token (parser->lexer);
ellipsis_p = true;
}
else
ellipsis_p = false;
return finish_parmlist (parameters, ellipsis_p);
}
static tree
cp_parser_parameter_declaration_list (cp_parser* parser)
{
tree parameters = NULL_TREE;
while (true)
{
tree parameter;
bool parenthesized_p;
parameter
= cp_parser_parameter_declaration (parser,
false,
&parenthesized_p);
if (parameter == error_mark_node)
{
parameters = error_mark_node;
break;
}
TREE_CHAIN (parameter) = parameters;
parameters = parameter;
if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_PAREN)
|| cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS))
break;
else if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA))
{
cp_token *token;
token = cp_lexer_peek_nth_token (parser->lexer, 2);
if (token->type == CPP_ELLIPSIS)
break;
cp_lexer_consume_token (parser->lexer);
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)
&& !parenthesized_p)
cp_parser_commit_to_tentative_parse (parser);
}
else
{
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,
true,
false,
false);
break;
}
}
return nreverse (parameters);
}
static tree
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;
tree default_argument;
tree parameter;
cp_token *token;
const char *saved_message;
greater_than_is_operator_p = !template_parm_p;
saved_message = parser->type_definition_forbidden_message;
parser->type_definition_forbidden_message
= "types may not be defined in parameter types";
decl_specifiers
= cp_parser_decl_specifier_seq (parser,
CP_PARSER_FLAGS_NONE,
&attributes,
&declares_class_or_enum);
if (cp_parser_error_occurred (parser))
{
parser->type_definition_forbidden_message = saved_message;
return error_mark_node;
}
token = cp_lexer_peek_token (parser->lexer);
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;
if (parenthesized_p)
*parenthesized_p = false;
}
else
{
bool saved_default_arg_ok_p = parser->default_arg_ok_p;
parser->default_arg_ok_p = false;
if (!parser->in_template_argument_list_p
&& !parser->in_type_id_in_expr_p
&& cp_parser_parsing_tentatively (parser)
&& !cp_parser_committed_to_tentative_parse (parser)
&& cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_PAREN))
cp_parser_commit_to_tentative_parse (parser);
declarator = cp_parser_declarator (parser,
CP_PARSER_DECLARATOR_EITHER,
NULL,
parenthesized_p);
parser->default_arg_ok_p = saved_default_arg_ok_p;
attributes = chainon (attributes, cp_parser_attributes_opt (parser));
}
parser->type_definition_forbidden_message = saved_message;
if (cp_lexer_next_token_is (parser->lexer, CPP_EQ))
{
bool saved_greater_than_is_operator_p;
cp_lexer_consume_token (parser->lexer);
if (!template_parm_p && at_class_scope_p ()
&& TYPE_BEING_DEFINED (current_class_type))
{
unsigned depth = 0;
default_argument = make_node (DEFAULT_ARG);
DEFARG_TOKENS (default_argument) = cp_token_cache_new ();
while (true)
{
bool done = false;
cp_token *token;
token = cp_lexer_peek_token (parser->lexer);
switch (token->type)
{
case CPP_COMMA:
case CPP_CLOSE_PAREN:
case CPP_ELLIPSIS:
case CPP_SEMICOLON:
case CPP_CLOSE_BRACE:
case CPP_CLOSE_SQUARE:
if (depth == 0)
done = true;
else if (token->type == CPP_CLOSE_PAREN
|| token->type == CPP_CLOSE_BRACE
|| token->type == CPP_CLOSE_SQUARE)
--depth;
break;
case CPP_OPEN_PAREN:
case CPP_OPEN_SQUARE:
case CPP_OPEN_BRACE:
++depth;
break;
case CPP_GREATER:
if (!depth && !greater_than_is_operator_p)
done = true;
break;
case CPP_EOF:
error ("file ends in default argument");
done = true;
break;
case CPP_NAME:
case CPP_SCOPE:
break;
default:
break;
}
if (done)
break;
token = cp_lexer_consume_token (parser->lexer);
cp_token_cache_push_token (DEFARG_TOKENS (default_argument),
token);
}
}
else
{
bool saved_local_variables_forbidden_p;
saved_greater_than_is_operator_p
= parser->greater_than_is_operator_p;
parser->greater_than_is_operator_p = greater_than_is_operator_p;
saved_local_variables_forbidden_p
= parser->local_variables_forbidden_p;
parser->local_variables_forbidden_p = true;
default_argument = cp_parser_assignment_expression (parser);
parser->greater_than_is_operator_p
= saved_greater_than_is_operator_p;
parser->local_variables_forbidden_p
= saved_local_variables_forbidden_p;
}
if (!parser->default_arg_ok_p)
{
if (!flag_pedantic_errors)
warning ("deprecated use of default argument for parameter of non-function");
else
{
error ("default arguments are only permitted for function parameters");
default_argument = NULL_TREE;
}
}
}
else
default_argument = NULL_TREE;
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;
}
static void
cp_parser_function_body (cp_parser *parser)
{
cp_parser_compound_statement (parser, false);
}
static bool
cp_parser_ctor_initializer_opt_and_function_body (cp_parser *parser)
{
tree body;
bool ctor_initializer_p;
body = begin_function_body ();
ctor_initializer_p = cp_parser_ctor_initializer_opt (parser);
cp_parser_function_body (parser);
finish_function_body (body);
return ctor_initializer_p;
}
static tree
cp_parser_initializer (cp_parser* parser, bool* is_parenthesized_init,
bool* non_constant_p)
{
cp_token *token;
tree init;
token = cp_lexer_peek_token (parser->lexer);
*is_parenthesized_init = (token->type == CPP_OPEN_PAREN);
*non_constant_p = false;
if (token->type == CPP_EQ)
{
cp_lexer_consume_token (parser->lexer);
init = cp_parser_initializer_clause (parser, non_constant_p);
}
else if (token->type == CPP_OPEN_PAREN)
init = cp_parser_parenthesized_expression_list (parser, false,
non_constant_p);
else
{
cp_parser_error (parser, "expected initializer");
init = error_mark_node;
}
return init;
}
static tree
cp_parser_initializer_clause (cp_parser* parser, bool* non_constant_p)
{
tree initializer;
if (cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_BRACE))
{
initializer
= cp_parser_constant_expression (parser,
true,
non_constant_p);
if (!*non_constant_p)
initializer = fold_non_dependent_expr (initializer);
}
else
{
cp_lexer_consume_token (parser->lexer);
initializer = make_node (CONSTRUCTOR);
if (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_BRACE))
{
CONSTRUCTOR_ELTS (initializer)
= cp_parser_initializer_list (parser, non_constant_p);
if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA))
cp_lexer_consume_token (parser->lexer);
}
cp_parser_require (parser, CPP_CLOSE_BRACE, "`}'");
}
return initializer;
}
static tree
cp_parser_initializer_list (cp_parser* parser, bool* non_constant_p)
{
tree initializers = NULL_TREE;
*non_constant_p = false;
while (true)
{
cp_token *token;
tree identifier;
tree initializer;
bool clause_non_constant_p;
if (cp_parser_allow_gnu_extensions_p (parser)
&& cp_lexer_next_token_is (parser->lexer, CPP_NAME)
&& cp_lexer_peek_nth_token (parser->lexer, 2)->type == CPP_COLON)
{
identifier = cp_lexer_consume_token (parser->lexer)->value;
cp_lexer_consume_token (parser->lexer);
}
else
identifier = NULL_TREE;
initializer = cp_parser_initializer_clause (parser,
&clause_non_constant_p);
if (clause_non_constant_p)
*non_constant_p = true;
initializers = tree_cons (identifier, initializer, initializers);
if (cp_lexer_next_token_is_not (parser->lexer, CPP_COMMA))
break;
token = cp_lexer_peek_nth_token (parser->lexer, 2);
if (token->type == CPP_CLOSE_BRACE)
break;
cp_lexer_consume_token (parser->lexer);
}
return nreverse (initializers);
}
static tree
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,
bool is_declaration)
{
tree decl;
tree scope;
bool typename_p;
cp_token *token;
token = cp_lexer_peek_token (parser->lexer);
if (token->type != CPP_NAME && token->type != CPP_TEMPLATE_ID)
{
cp_parser_error (parser, "expected class-name");
return error_mark_node;
}
scope = parser->scope;
if (scope == error_mark_node)
return error_mark_node;
typename_p = (typename_keyword_p && scope && TYPE_P (scope)
&& dependent_type_p (scope));
if (token->type == CPP_NAME
&& !cp_parser_nth_token_starts_template_argument_list_p (parser, 2))
{
tree identifier;
identifier = cp_parser_identifier (parser);
if (identifier == error_mark_node)
decl = error_mark_node;
else if (typename_p)
decl = identifier;
else
{
if (cp_lexer_next_token_is (parser->lexer, CPP_SCOPE))
type_p = true;
decl = cp_parser_lookup_name (parser, identifier,
type_p,
false,
false,
check_dependency_p);
}
}
else
{
decl = cp_parser_template_id (parser, template_keyword_p,
check_dependency_p,
is_declaration);
if (decl == error_mark_node)
return error_mark_node;
}
decl = cp_parser_maybe_treat_template_as_class (decl, class_head_p);
if (typename_p && decl != error_mark_node)
{
decl = make_typename_type (scope, decl, 1);
if (decl != error_mark_node)
decl = TYPE_NAME (decl);
}
if (TREE_CODE (decl) == TEMPLATE_ID_EXPR
&& TREE_CODE (TREE_OPERAND (decl, 0)) == IDENTIFIER_NODE
&& cp_lexer_next_token_is (parser->lexer, CPP_SCOPE))
decl = TYPE_NAME (make_typename_type (scope, decl, tf_error));
else if (decl == error_mark_node
|| TREE_CODE (decl) != TYPE_DECL
|| !IS_AGGR_TYPE (TREE_TYPE (decl)))
{
cp_parser_error (parser, "expected class-name");
return error_mark_node;
}
return decl;
}
static tree
cp_parser_class_specifier (cp_parser* parser)
{
cp_token *token;
tree type;
tree attributes = NULL_TREE;
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);
type = cp_parser_class_head (parser,
&nested_name_specifier_p,
&attributes);
if (!type)
{
cp_parser_skip_to_end_of_block_or_statement (parser);
pop_deferring_access_checks ();
return error_mark_node;
}
if (!cp_parser_require (parser, CPP_OPEN_BRACE, "`{'"))
{
pop_deferring_access_checks ();
return error_mark_node;
}
cp_parser_check_type_definition (parser);
++parser->num_classes_being_defined;
saved_num_template_parameter_lists
= parser->num_template_parameter_lists;
parser->num_template_parameter_lists = 0;
if (nested_name_specifier_p)
pop_p = push_scope (CP_DECL_CONTEXT (TYPE_MAIN_DECL (type)));
type = begin_class_definition (type);
if (type == error_mark_node)
cp_parser_skip_to_closing_brace (parser);
else
cp_parser_member_specification_opt (parser);
cp_parser_require (parser, CPP_CLOSE_BRACE, "`}'");
token = cp_lexer_peek_token (parser->lexer);
has_trailing_semicolon = (token->type == CPP_SEMICOLON);
if (cp_parser_allow_gnu_extensions_p (parser))
{
tree sub_attr = cp_parser_attributes_opt (parser);
attributes = chainon (attributes, sub_attr);
}
if (type != error_mark_node)
type = finish_struct (type, attributes);
if (pop_p)
pop_scope (CP_DECL_CONTEXT (TYPE_MAIN_DECL (type)));
if (--parser->num_classes_being_defined == 0)
{
tree queue_entry;
tree fn;
for (TREE_PURPOSE (parser->unparsed_functions_queues)
= nreverse (TREE_PURPOSE (parser->unparsed_functions_queues));
(queue_entry = TREE_PURPOSE (parser->unparsed_functions_queues));
TREE_PURPOSE (parser->unparsed_functions_queues)
= TREE_CHAIN (TREE_PURPOSE (parser->unparsed_functions_queues)))
{
fn = TREE_VALUE (queue_entry);
maybe_begin_member_template_processing (fn);
cp_parser_late_parsing_default_args (parser, fn);
maybe_end_member_template_processing ();
}
for (TREE_VALUE (parser->unparsed_functions_queues)
= nreverse (TREE_VALUE (parser->unparsed_functions_queues));
(queue_entry = TREE_VALUE (parser->unparsed_functions_queues));
TREE_VALUE (parser->unparsed_functions_queues)
= TREE_CHAIN (TREE_VALUE (parser->unparsed_functions_queues)))
{
fn = TREE_VALUE (queue_entry);
function_depth++;
cp_parser_late_parsing_for_member (parser, fn);
function_depth--;
}
}
pop_deferring_access_checks ();
parser->num_template_parameter_lists
= saved_num_template_parameter_lists;
return type;
}
static tree
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;
tree type = NULL_TREE;
tree attributes;
bool template_id_p = false;
bool qualified_p = false;
bool invalid_nested_name_p = false;
bool invalid_explicit_specialization_p = false;
bool pop_p = false;
unsigned num_templates;
*nested_name_specifier_p = false;
num_templates = 0;
class_key = cp_parser_class_key (parser);
if (class_key == none_type)
return error_mark_node;
attributes = cp_parser_attributes_opt (parser);
if (cp_parser_global_scope_opt (parser, false))
qualified_p = true;
push_deferring_access_checks (dk_no_check);
nested_name_specifier
= cp_parser_nested_name_specifier_opt (parser,
false,
false,
false,
false);
if (nested_name_specifier)
{
cp_parser_parse_tentatively (parser);
type = cp_parser_class_name (parser,
false,
false,
true,
false,
true,
false);
if (!cp_parser_parse_definitely (parser))
{
invalid_nested_name_p = true;
id = cp_parser_identifier (parser);
if (id == error_mark_node)
id = NULL_TREE;
}
if (type == error_mark_node)
nested_name_specifier = NULL_TREE;
else
{
tree scope;
for (scope = TREE_TYPE (type);
scope && TREE_CODE (scope) != NAMESPACE_DECL;
scope = (TYPE_P (scope)
? TYPE_CONTEXT (scope)
: DECL_CONTEXT (scope)))
if (TYPE_P (scope)
&& CLASS_TYPE_P (scope)
&& CLASSTYPE_TEMPLATE_INFO (scope)
&& PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (scope))
&& !CLASSTYPE_TEMPLATE_SPECIALIZATION (scope))
++num_templates;
}
}
else
{
cp_parser_parse_tentatively (parser);
id = cp_parser_template_id (parser,
false,
true,
true);
if (!cp_parser_parse_definitely (parser))
{
if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
id = cp_parser_identifier (parser);
else
id = NULL_TREE;
}
else
{
template_id_p = true;
++num_templates;
}
}
pop_deferring_access_checks ();
if (id)
cp_parser_check_for_invalid_template_id (parser, id);
if (!cp_parser_next_token_starts_class_definition_p (parser))
{
cp_parser_error (parser, "expected `{' or `:'");
return error_mark_node;
}
cp_parser_commit_to_tentative_parse (parser);
if (qualified_p)
cp_parser_error (parser,
"global qualification of class name is invalid");
else if (invalid_nested_name_p)
cp_parser_error (parser,
"qualified name does not name a class");
else if (nested_name_specifier)
{
tree scope;
scope = current_scope ();
if (!scope)
scope = current_namespace;
if (scope && !is_ancestor (scope, nested_name_specifier))
{
error ("declaration of `%D' in `%D' which does not "
"enclose `%D'", type, scope, nested_name_specifier);
type = NULL_TREE;
goto done;
}
if (scope == nested_name_specifier)
{
pedwarn ("extra qualification ignored");
nested_name_specifier = NULL_TREE;
num_templates = 0;
}
}
if (at_namespace_scope_p ()
&& parser->num_template_parameter_lists == 0
&& template_id_p)
{
error ("an explicit specialization must be preceded by 'template <>'");
invalid_explicit_specialization_p = true;
++parser->num_template_parameter_lists;
begin_specialization ();
}
if (!cp_parser_check_template_parameters (parser, num_templates))
{
type = NULL_TREE;
goto done;
}
if (template_id_p)
{
type = TREE_TYPE (id);
maybe_process_partial_specialization (type);
}
else if (!nested_name_specifier)
{
if (!id)
id = make_anon_name ();
type = xref_tag (class_key, id, false,
parser->num_template_parameter_lists);
}
else
{
tree class_type;
bool pop_p = false;
if (TREE_CODE (TREE_TYPE (type)) == TYPENAME_TYPE)
{
class_type = resolve_typename_type (TREE_TYPE (type),
false);
if (class_type != error_mark_node)
type = TYPE_NAME (class_type);
else
{
cp_parser_error (parser, "could not resolve typename type");
type = error_mark_node;
}
}
maybe_process_partial_specialization (TREE_TYPE (type));
class_type = current_class_type;
if (nested_name_specifier)
pop_p = push_scope (nested_name_specifier);
type = TYPE_MAIN_DECL (TREE_TYPE (type));
if (PROCESSING_REAL_TEMPLATE_DECL_P ()
&& !CLASSTYPE_TEMPLATE_SPECIALIZATION (TREE_TYPE (type)))
type = push_template_decl (type);
type = TREE_TYPE (type);
if (nested_name_specifier)
{
*nested_name_specifier_p = true;
if (pop_p)
pop_scope (nested_name_specifier);
}
}
if (TREE_CODE (type) == RECORD_TYPE)
CLASSTYPE_DECLARED_CLASS (type) = (class_key == class_type);
cp_parser_check_class_key (class_key, type);
if (nested_name_specifier)
pop_p = push_scope (nested_name_specifier);
token = cp_lexer_peek_token (parser->lexer);
if (token->type == CPP_COLON)
{
tree bases;
bases = cp_parser_base_clause (parser);
xref_basetypes (type, bases);
}
if (pop_p)
pop_scope (nested_name_specifier);
done:
if (invalid_explicit_specialization_p)
{
end_specialization ();
--parser->num_template_parameter_lists;
}
*attributes_p = attributes;
return type;
}
static enum tag_types
cp_parser_class_key (cp_parser* parser)
{
cp_token *token;
enum tag_types tag_type;
token = cp_parser_require (parser, CPP_KEYWORD, "class-key");
if (!token)
return none_type;
tag_type = cp_parser_token_is_class_key (token);
if (!tag_type)
cp_parser_error (parser, "expected class-key");
return tag_type;
}
static void
cp_parser_member_specification_opt (cp_parser* parser)
{
while (true)
{
cp_token *token;
enum rid keyword;
token = cp_lexer_peek_token (parser->lexer);
if (token->type == CPP_CLOSE_BRACE || token->type == CPP_EOF)
break;
keyword = token->keyword;
switch (keyword)
{
case RID_PUBLIC:
case RID_PROTECTED:
case RID_PRIVATE:
cp_lexer_consume_token (parser->lexer);
current_access_specifier = token->value;
cp_parser_require (parser, CPP_COLON, "`:'");
break;
default:
cp_parser_member_declaration (parser);
}
}
}
static void
cp_parser_member_declaration (cp_parser* parser)
{
tree decl_specifiers;
tree prefix_attributes;
tree decl;
int declares_class_or_enum;
bool friend_p;
cp_token *token;
int saved_pedantic;
if (cp_parser_extension_opt (parser, &saved_pedantic))
{
cp_parser_member_declaration (parser);
pedantic = saved_pedantic;
return;
}
if (cp_lexer_next_token_is_keyword (parser->lexer, RID_TEMPLATE))
{
cp_parser_template_declaration (parser, true);
return;
}
if (cp_lexer_next_token_is_keyword (parser->lexer, RID_USING))
{
cp_parser_using_declaration (parser);
return;
}
decl_specifiers
= cp_parser_decl_specifier_seq (parser,
CP_PARSER_FLAGS_OPTIONAL,
&prefix_attributes,
&declares_class_or_enum);
if (cp_parser_parse_and_diagnose_invalid_type_name (parser))
return;
if (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON))
{
if (!decl_specifiers)
{
if (pedantic)
pedwarn ("extra semicolon");
}
else
{
tree type;
friend_p = cp_parser_friend_p (decl_specifiers);
type = check_tag_decl (decl_specifiers);
if (friend_p)
{
if (!declares_class_or_enum)
error ("a class-key must be used when declaring a friend");
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 || !TYPE_P (type))
error ("friend declaration does not name a class or "
"function");
else
make_friend_class (current_class_type, type,
true);
}
else if (!type)
;
else if (ANON_AGGR_TYPE_P (type))
{
fixup_anonymous_aggr (type);
decl = build_decl (FIELD_DECL, NULL_TREE, type);
finish_member_declaration (decl);
}
else
cp_parser_check_access_in_redeclaration (TYPE_NAME (type));
}
}
else
{
friend_p = cp_parser_friend_p (decl_specifiers);
while (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON))
{
tree attributes = NULL_TREE;
tree first_attribute;
token = cp_lexer_peek_token (parser->lexer);
if (token->type == CPP_COLON
|| (token->type == CPP_NAME
&& cp_lexer_peek_nth_token (parser->lexer, 2)->type
== CPP_COLON))
{
tree identifier;
tree width;
if (cp_lexer_peek_token (parser->lexer)->type != CPP_COLON)
identifier = cp_parser_identifier (parser);
else
identifier = NULL_TREE;
cp_lexer_consume_token (parser->lexer);
width
= cp_parser_constant_expression (parser,
false,
NULL);
attributes = cp_parser_attributes_opt (parser);
first_attribute = attributes;
attributes = chainon (prefix_attributes, attributes);
decl = grokbitfield (identifier,
decl_specifiers,
width);
cplus_decl_attributes (&decl, attributes, 0);
}
else
{
tree declarator;
tree initializer;
tree asm_specification;
int ctor_dtor_or_conv_p;
declarator
= cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED,
&ctor_dtor_or_conv_p,
NULL);
if (declarator == error_mark_node)
{
cp_parser_skip_to_end_of_statement (parser);
if (cp_lexer_next_token_is (parser->lexer,
CPP_SEMICOLON))
cp_lexer_consume_token (parser->lexer);
return;
}
cp_parser_check_for_definition_in_return_type
(declarator, declares_class_or_enum);
asm_specification = cp_parser_asm_specification_opt (parser);
attributes = cp_parser_attributes_opt (parser);
first_attribute = attributes;
attributes = chainon (prefix_attributes, attributes);
if (cp_lexer_next_token_is (parser->lexer, CPP_EQ))
{
if (TREE_CODE (declarator) == CALL_EXPR)
initializer = cp_parser_pure_specifier (parser);
else
initializer = cp_parser_constant_initializer (parser);
}
else
initializer = NULL_TREE;
if (cp_parser_token_starts_function_definition_p
(cp_lexer_peek_token (parser->lexer)))
{
if (initializer)
error ("pure-specifier on function-definition");
decl = cp_parser_save_member_function_body (parser,
decl_specifiers,
declarator,
attributes);
if (!friend_p)
finish_member_declaration (decl);
token = cp_lexer_peek_token (parser->lexer);
if (token->type == CPP_SEMICOLON)
cp_lexer_consume_token (parser->lexer);
return;
}
else
{
decl = grokfield (declarator, decl_specifiers,
initializer, asm_specification,
attributes);
if (decl && TREE_CODE (decl) == VAR_DECL && initializer)
DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl) = 1;
}
}
while (attributes && TREE_CHAIN (attributes) != first_attribute)
attributes = TREE_CHAIN (attributes);
if (attributes)
TREE_CHAIN (attributes) = NULL_TREE;
parser->scope = NULL_TREE;
parser->qualifying_scope = NULL_TREE;
parser->object_scope = NULL_TREE;
if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA))
cp_lexer_consume_token (parser->lexer);
else if (cp_lexer_next_token_is_not (parser->lexer,
CPP_SEMICOLON))
{
cp_parser_error (parser, "expected `;'");
cp_parser_skip_to_end_of_statement (parser);
break;
}
if (decl)
{
if (!friend_p)
finish_member_declaration (decl);
if (TREE_CODE (decl) == FUNCTION_DECL)
cp_parser_save_default_args (parser, decl);
}
}
}
cp_parser_require (parser, CPP_SEMICOLON, "`;'");
}
static tree
cp_parser_pure_specifier (cp_parser* parser)
{
cp_token *token;
if (!cp_parser_require (parser, CPP_EQ, "`='"))
return error_mark_node;
token = cp_parser_require (parser, CPP_NUMBER, "`0'");
if (!token || !integer_zerop (token->value))
return error_mark_node;
return integer_zero_node;
}
static tree
cp_parser_constant_initializer (cp_parser* parser)
{
if (!cp_parser_require (parser, CPP_EQ, "`='"))
return error_mark_node;
if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE))
{
cp_parser_error (parser,
"a brace-enclosed initializer is not allowed here");
cp_lexer_consume_token (parser->lexer);
cp_parser_skip_to_closing_brace (parser);
cp_parser_require (parser, CPP_CLOSE_BRACE, "`}'");
return error_mark_node;
}
return cp_parser_constant_expression (parser,
false,
NULL);
}
static tree
cp_parser_base_clause (cp_parser* parser)
{
tree bases = NULL_TREE;
cp_parser_require (parser, CPP_COLON, "`:'");
while (true)
{
cp_token *token;
tree base;
base = cp_parser_base_specifier (parser);
if (base != error_mark_node)
{
TREE_CHAIN (base) = bases;
bases = base;
}
token = cp_lexer_peek_token (parser->lexer);
if (token->type != CPP_COMMA)
break;
cp_lexer_consume_token (parser->lexer);
}
parser->scope = NULL_TREE;
parser->qualifying_scope = NULL_TREE;
parser->object_scope = NULL_TREE;
return nreverse (bases);
}
static tree
cp_parser_base_specifier (cp_parser* parser)
{
cp_token *token;
bool done = false;
bool virtual_p = false;
bool duplicate_virtual_error_issued_p = false;
bool duplicate_access_error_issued_p = false;
bool class_scope_p, template_p;
tree access = access_default_node;
tree type;
while (!done)
{
token = cp_lexer_peek_token (parser->lexer);
switch (token->keyword)
{
case RID_VIRTUAL:
if (virtual_p && !duplicate_virtual_error_issued_p)
{
cp_parser_error (parser,
"`virtual' specified more than once in base-specified");
duplicate_virtual_error_issued_p = true;
}
virtual_p = true;
cp_lexer_consume_token (parser->lexer);
break;
case RID_PUBLIC:
case RID_PROTECTED:
case RID_PRIVATE:
if (access != access_default_node
&& !duplicate_access_error_issued_p)
{
cp_parser_error (parser,
"more than one access specifier in base-specified");
duplicate_access_error_issued_p = true;
}
access = ridpointers[(int) token->keyword];
cp_lexer_consume_token (parser->lexer);
break;
default:
done = true;
break;
}
}
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);
}
cp_parser_global_scope_opt (parser, false);
cp_parser_nested_name_specifier_opt (parser,
true,
true,
true,
true);
class_scope_p = (parser->scope && TYPE_P (parser->scope));
template_p = class_scope_p && cp_parser_optional_template_keyword (parser);
type = cp_parser_class_name (parser,
class_scope_p,
template_p,
true,
true,
false,
true);
if (type == error_mark_node)
return error_mark_node;
return finish_base_specifier (TREE_TYPE (type), access, virtual_p);
}
static tree
cp_parser_exception_specification_opt (cp_parser* parser)
{
cp_token *token;
tree type_id_list;
token = cp_lexer_peek_token (parser->lexer);
if (!cp_parser_is_keyword (token, RID_THROW))
return NULL_TREE;
cp_lexer_consume_token (parser->lexer);
cp_parser_require (parser, CPP_OPEN_PAREN, "`('");
token = cp_lexer_peek_token (parser->lexer);
if (token->type != CPP_CLOSE_PAREN)
{
const char *saved_message;
saved_message = parser->type_definition_forbidden_message;
parser->type_definition_forbidden_message
= "types may not be defined in an exception-specification";
type_id_list = cp_parser_type_id_list (parser);
parser->type_definition_forbidden_message = saved_message;
}
else
type_id_list = empty_except_spec;
cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
return type_id_list;
}
static tree
cp_parser_type_id_list (cp_parser* parser)
{
tree types = NULL_TREE;
while (true)
{
cp_token *token;
tree type;
type = cp_parser_type_id (parser);
types = add_exception_specifier (types, type, 1);
token = cp_lexer_peek_token (parser->lexer);
if (token->type != CPP_COMMA)
break;
cp_lexer_consume_token (parser->lexer);
}
return nreverse (types);
}
static tree
cp_parser_try_block (cp_parser* parser)
{
tree try_block;
cp_parser_require_keyword (parser, RID_TRY, "`try'");
try_block = begin_try_block ();
cp_parser_compound_statement (parser, false);
finish_try_block (try_block);
cp_parser_handler_seq (parser);
finish_handler_sequence (try_block);
return try_block;
}
static bool
cp_parser_function_try_block (cp_parser* parser)
{
tree try_block;
bool ctor_initializer_p;
if (!cp_parser_require_keyword (parser, RID_TRY, "`try'"))
return false;
try_block = begin_function_try_block ();
ctor_initializer_p
= cp_parser_ctor_initializer_opt_and_function_body (parser);
finish_function_try_block (try_block);
cp_parser_handler_seq (parser);
finish_function_handler_sequence (try_block);
return ctor_initializer_p;
}
static void
cp_parser_handler_seq (cp_parser* parser)
{
while (true)
{
cp_token *token;
cp_parser_handler (parser);
token = cp_lexer_peek_token (parser->lexer);
if (!cp_parser_is_keyword (token, RID_CATCH))
break;
}
}
static void
cp_parser_handler (cp_parser* parser)
{
tree handler;
tree declaration;
cp_parser_require_keyword (parser, RID_CATCH, "`catch'");
handler = begin_handler ();
cp_parser_require (parser, CPP_OPEN_PAREN, "`('");
declaration = cp_parser_exception_declaration (parser);
finish_handler_parms (declaration, handler);
cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
cp_parser_compound_statement (parser, false);
finish_handler (handler);
}
static tree
cp_parser_exception_declaration (cp_parser* parser)
{
tree type_specifiers;
tree declarator;
const char *saved_message;
if (cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS))
{
cp_lexer_consume_token (parser->lexer);
return NULL_TREE;
}
saved_message = parser->type_definition_forbidden_message;
parser->type_definition_forbidden_message
= "types may not be defined in exception-declarations";
type_specifiers = cp_parser_type_specifier_seq (parser);
if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_PAREN))
declarator = NULL_TREE;
else
declarator = cp_parser_declarator (parser, CP_PARSER_DECLARATOR_EITHER,
NULL,
NULL);
parser->type_definition_forbidden_message = saved_message;
return start_handler_parms (type_specifiers, declarator);
}
static tree
cp_parser_throw_expression (cp_parser* parser)
{
tree expression;
cp_token* token;
cp_parser_require_keyword (parser, RID_THROW, "`throw'");
token = cp_lexer_peek_token (parser->lexer);
if (token->type == CPP_COMMA
|| token->type == CPP_SEMICOLON
|| token->type == CPP_CLOSE_PAREN
|| token->type == CPP_CLOSE_SQUARE
|| token->type == CPP_CLOSE_BRACE
|| token->type == CPP_COLON)
expression = NULL_TREE;
else
expression = cp_parser_assignment_expression (parser);
return build_throw (expression);
}
static tree
cp_parser_asm_specification_opt (cp_parser* parser)
{
cp_token *token;
tree asm_specification;
token = cp_lexer_peek_token (parser->lexer);
if (!cp_parser_is_keyword (token, RID_ASM))
return NULL_TREE;
cp_lexer_consume_token (parser->lexer);
cp_parser_require (parser, CPP_OPEN_PAREN, "`('");
token = cp_parser_require (parser, CPP_STRING, "string-literal");
if (token)
asm_specification = token->value;
else
asm_specification = NULL_TREE;
cp_parser_require (parser, CPP_CLOSE_PAREN, "`('");
return asm_specification;
}
static tree
cp_parser_asm_operand_list (cp_parser* parser)
{
tree asm_operands = NULL_TREE;
while (true)
{
tree string_literal;
tree expression;
tree name;
cp_token *token;
c_lex_string_translate = false;
if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_SQUARE))
{
cp_lexer_consume_token (parser->lexer);
name = cp_parser_identifier (parser);
if (name != error_mark_node)
name = build_string (IDENTIFIER_LENGTH (name),
IDENTIFIER_POINTER (name));
cp_parser_require (parser, CPP_CLOSE_SQUARE, "`]'");
}
else
name = NULL_TREE;
token = cp_parser_require (parser, CPP_STRING, "string-literal");
string_literal = token ? token->value : error_mark_node;
c_lex_string_translate = true;
cp_parser_require (parser, CPP_OPEN_PAREN, "`('");
expression = cp_parser_expression (parser);
cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
c_lex_string_translate = false;
asm_operands = tree_cons (build_tree_list (name, string_literal),
expression,
asm_operands);
if (cp_lexer_next_token_is_not (parser->lexer, CPP_COMMA))
break;
cp_lexer_consume_token (parser->lexer);
}
return nreverse (asm_operands);
}
static tree
cp_parser_asm_clobber_list (cp_parser* parser)
{
tree clobbers = NULL_TREE;
while (true)
{
cp_token *token;
tree string_literal;
token = cp_parser_require (parser, CPP_STRING, "string-literal");
string_literal = token ? token->value : error_mark_node;
clobbers = tree_cons (NULL_TREE, string_literal, clobbers);
if (cp_lexer_next_token_is_not (parser->lexer, CPP_COMMA))
break;
cp_lexer_consume_token (parser->lexer);
}
return clobbers;
}
static tree
cp_parser_attributes_opt (cp_parser* parser)
{
tree attributes = NULL_TREE;
while (true)
{
cp_token *token;
tree attribute_list;
token = cp_lexer_peek_token (parser->lexer);
if (token->keyword != RID_ATTRIBUTE)
break;
cp_lexer_consume_token (parser->lexer);
cp_parser_require (parser, CPP_OPEN_PAREN, "`('");
cp_parser_require (parser, CPP_OPEN_PAREN, "`('");
token = cp_lexer_peek_token (parser->lexer);
if (token->type != CPP_CLOSE_PAREN)
attribute_list = cp_parser_attribute_list (parser);
else
attribute_list = NULL;
cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
attributes = chainon (attributes, attribute_list);
}
return attributes;
}
static tree
cp_parser_attribute_list (cp_parser* parser)
{
tree attribute_list = NULL_TREE;
c_lex_string_translate = false;
while (true)
{
cp_token *token;
tree identifier;
tree attribute;
token = cp_lexer_peek_token (parser->lexer);
if (token->type != CPP_NAME
&& token->type != CPP_KEYWORD)
return error_mark_node;
token = cp_lexer_consume_token (parser->lexer);
identifier = token->value;
attribute = build_tree_list (identifier, NULL_TREE);
token = cp_lexer_peek_token (parser->lexer);
if (token->type == CPP_OPEN_PAREN)
{
tree arguments;
arguments = (cp_parser_parenthesized_expression_list
(parser, true, NULL));
TREE_VALUE (attribute) = arguments;
}
TREE_CHAIN (attribute) = attribute_list;
attribute_list = attribute;
token = cp_lexer_peek_token (parser->lexer);
if (token->type != CPP_COMMA)
break;
cp_lexer_consume_token (parser->lexer);
}
c_lex_string_translate = true;
return nreverse (attribute_list);
}
static bool
cp_parser_extension_opt (cp_parser* parser, int* saved_pedantic)
{
*saved_pedantic = pedantic;
if (cp_lexer_next_token_is_keyword (parser->lexer, RID_EXTENSION))
{
cp_lexer_consume_token (parser->lexer);
pedantic = 0;
return true;
}
return false;
}
static void
cp_parser_label_declaration (cp_parser* parser)
{
cp_parser_require_keyword (parser, RID_LABEL, "`__label__'");
while (true)
{
tree identifier;
identifier = cp_parser_identifier (parser);
finish_label_decl (identifier);
if (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON))
break;
cp_parser_require (parser, CPP_COMMA, "`,'");
}
cp_parser_require (parser, CPP_SEMICOLON, "`;'");
}
static tree
cp_parser_lookup_name (cp_parser *parser, tree name,
bool is_type, bool is_template, bool is_namespace,
bool check_dependency)
{
tree decl;
tree object_type = parser->context->object_type;
parser->context->object_type = NULL_TREE;
if (name == error_mark_node)
return error_mark_node;
if (TREE_CODE (name) == TEMPLATE_ID_EXPR)
return name;
if (BASELINK_P (name))
{
my_friendly_assert ((TREE_CODE (BASELINK_FUNCTIONS (name))
== TEMPLATE_ID_EXPR),
20020909);
return name;
}
if (TREE_CODE (name) == BIT_NOT_EXPR)
{
tree type;
if (parser->scope)
type = parser->scope;
else if (object_type)
type = object_type;
else
type = current_class_type;
if (!type || !CLASS_TYPE_P (type))
return error_mark_node;
if (!CLASSTYPE_DESTRUCTORS (type))
return error_mark_node;
return CLASSTYPE_DESTRUCTORS (type);
}
my_friendly_assert (TREE_CODE (name) == IDENTIFIER_NODE,
20000619);
if (parser->scope)
{
bool dependent_p;
if (parser->scope == error_mark_node)
return error_mark_node;
dependent_p = (TYPE_P (parser->scope)
&& !(parser->in_declarator_p
&& currently_open_class (parser->scope))
&& dependent_type_p (parser->scope));
if ((check_dependency || !CLASS_TYPE_P (parser->scope))
&& dependent_p)
{
if (is_type)
decl = TYPE_NAME (make_typename_type (parser->scope,
name,
1));
else if (is_template)
decl = make_unbound_class_template (parser->scope,
name,
1);
else
decl = build_nt (SCOPE_REF, parser->scope, name);
}
else
{
bool pop_p = false;
if (dependent_p)
pop_p = push_scope (parser->scope);
decl = lookup_qualified_name (parser->scope, name, is_type,
true);
if (pop_p)
pop_scope (parser->scope);
}
parser->qualifying_scope = parser->scope;
parser->object_scope = NULL_TREE;
}
else if (object_type)
{
tree object_decl = NULL_TREE;
if (CLASS_TYPE_P (object_type))
object_decl = lookup_member (object_type,
name,
0, is_type);
decl = lookup_name_real (name, is_type, 0,
is_namespace,
0);
parser->object_scope = object_type;
parser->qualifying_scope = NULL_TREE;
if (object_decl)
decl = object_decl;
}
else
{
decl = lookup_name_real (name, is_type, 0,
is_namespace,
0);
parser->qualifying_scope = NULL_TREE;
parser->object_scope = NULL_TREE;
}
if (!decl
|| decl == error_mark_node
|| (TREE_CODE (decl) == FUNCTION_DECL
&& DECL_ANTICIPATED (decl)))
return error_mark_node;
if (TREE_CODE (decl) == TREE_LIST)
{
if (!cp_parser_simulate_error (parser))
{
error ("reference to `%D' is ambiguous", name);
print_candidates (decl);
}
return error_mark_node;
}
my_friendly_assert (DECL_P (decl)
|| TREE_CODE (decl) == OVERLOAD
|| TREE_CODE (decl) == SCOPE_REF
|| TREE_CODE (decl) == UNBOUND_CLASS_TEMPLATE
|| BASELINK_P (decl),
20000619);
if (DECL_P (decl))
check_accessibility_of_qualified_id (decl, object_type, parser->scope);
return decl;
}
static tree
cp_parser_lookup_name_simple (cp_parser* parser, tree name)
{
return cp_parser_lookup_name (parser, name,
false,
false,
false,
true);
}
static tree
cp_parser_maybe_treat_template_as_class (tree decl, bool tag_name_p)
{
if (DECL_CLASS_TEMPLATE_P (decl) && tag_name_p)
return DECL_TEMPLATE_RESULT (decl);
return decl;
}
static bool
cp_parser_check_declarator_template_parameters (cp_parser* parser,
tree declarator)
{
unsigned num_templates;
num_templates = 0;
switch (TREE_CODE (declarator))
{
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 (TREE_CODE (member) == INDIRECT_REF)
return (cp_parser_check_declarator_template_parameters
(parser, member));
while (scope && CLASS_TYPE_P (scope))
{
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 (TREE_CODE (declarator) == TEMPLATE_ID_EXPR)
++num_templates;
return cp_parser_check_template_parameters (parser,
num_templates);
}
}
static bool
cp_parser_check_template_parameters (cp_parser* parser,
unsigned num_templates)
{
if (parser->num_template_parameter_lists < num_templates)
{
error ("too few template-parameter-lists");
return false;
}
if (parser->num_template_parameter_lists == num_templates)
return true;
if (parser->num_template_parameter_lists == num_templates + 1)
return true;
error ("too many template-parameter-lists");
return false;
}
static tree
cp_parser_binary_expression (cp_parser* parser,
const cp_parser_token_tree_map token_tree_map,
cp_parser_expression_fn fn)
{
tree lhs;
lhs = (*fn) (parser);
while (true)
{
cp_token *token;
const cp_parser_token_tree_map_node *map_node;
tree rhs;
token = cp_lexer_peek_token (parser->lexer);
if (token->type == CPP_GREATER
&& !parser->greater_than_is_operator_p)
break;
for (map_node = token_tree_map;
map_node->token_type != CPP_EOF;
++map_node)
if (map_node->token_type == token->type)
{
bool overloaded_p = false;
cp_lexer_consume_token (parser->lexer);
rhs = (*fn) (parser);
lhs = build_x_binary_op (map_node->tree_type, lhs, rhs,
&overloaded_p);
if (overloaded_p
&& (cp_parser_non_integral_constant_expression
(parser, "calls to overloaded operators")))
lhs = error_mark_node;
break;
}
if (map_node->token_type == CPP_EOF)
break;
}
return lhs;
}
static tree
cp_parser_global_scope_opt (cp_parser* parser, bool current_scope_valid_p)
{
cp_token *token;
token = cp_lexer_peek_token (parser->lexer);
if (token->type == CPP_SCOPE)
{
cp_lexer_consume_token (parser->lexer);
parser->scope = global_namespace;
parser->qualifying_scope = global_namespace;
parser->object_scope = NULL_TREE;
return parser->scope;
}
else if (!current_scope_valid_p)
{
parser->scope = NULL_TREE;
parser->qualifying_scope = NULL_TREE;
parser->object_scope = NULL_TREE;
}
return NULL_TREE;
}
static bool
cp_parser_constructor_declarator_p (cp_parser *parser, bool friend_p)
{
bool constructor_p;
tree type_decl = NULL_TREE;
bool nested_name_p;
cp_token *next_token;
if (at_function_scope_p ())
return false;
next_token = cp_lexer_peek_token (parser->lexer);
if (next_token->type != CPP_NAME
&& next_token->type != CPP_SCOPE
&& next_token->type != CPP_NESTED_NAME_SPECIFIER
&& next_token->type != CPP_TEMPLATE_ID)
return false;
cp_parser_parse_tentatively (parser);
constructor_p = true;
cp_parser_global_scope_opt (parser,
false);
nested_name_p
= (cp_parser_nested_name_specifier_opt (parser,
false,
false,
false,
false)
!= NULL_TREE);
if (!nested_name_p &&
(!at_class_scope_p () || !TYPE_BEING_DEFINED (current_class_type)
|| friend_p))
constructor_p = false;
if (constructor_p)
{
type_decl = cp_parser_class_name (parser,
false,
false,
false,
false,
false,
false);
constructor_p = !cp_parser_error_occurred (parser);
}
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)
&& !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;
if (current_class_type)
type = NULL_TREE;
else
{
type = TREE_TYPE (type_decl);
if (TREE_CODE (type) == TYPENAME_TYPE)
{
type = resolve_typename_type (type,
false);
if (type == error_mark_node)
{
cp_parser_abort_tentative_parse (parser);
return false;
}
}
pop_p = push_scope (type);
}
saved_num_template_parameter_lists
= parser->num_template_parameter_lists;
parser->num_template_parameter_lists = 0;
cp_parser_type_specifier (parser,
CP_PARSER_FLAGS_NONE,
false,
true,
NULL,
NULL);
parser->num_template_parameter_lists
= saved_num_template_parameter_lists;
if (pop_p)
pop_scope (type);
constructor_p = !cp_parser_error_occurred (parser);
}
}
else
constructor_p = false;
cp_parser_abort_tentative_parse (parser);
return constructor_p;
}
static tree
cp_parser_function_definition_from_specifiers_and_declarator
(cp_parser* parser,
tree decl_specifiers,
tree attributes,
tree declarator)
{
tree fn;
bool success_p;
success_p = begin_function_definition (decl_specifiers,
attributes,
declarator);
perform_deferred_access_checks ();
if (!success_p)
{
error ("invalid function declaration");
cp_parser_skip_to_end_of_block_or_statement (parser);
fn = error_mark_node;
}
else
fn = cp_parser_function_definition_after_declarator (parser,
false);
return fn;
}
static tree
cp_parser_function_definition_after_declarator (cp_parser* parser,
bool inline_p)
{
tree fn;
bool ctor_initializer_p = false;
bool saved_in_unbraced_linkage_specification_p;
unsigned saved_num_template_parameter_lists;
if (cp_lexer_next_token_is_keyword (parser->lexer, RID_RETURN))
{
cp_lexer_consume_token (parser->lexer);
cp_parser_identifier (parser);
error ("named return values are no longer supported");
while (cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_BRACE)
&& cp_lexer_next_token_is_not (parser->lexer, CPP_EOF))
cp_lexer_consume_token (parser->lexer);
}
saved_in_unbraced_linkage_specification_p
= parser->in_unbraced_linkage_specification_p;
parser->in_unbraced_linkage_specification_p = false;
saved_num_template_parameter_lists
= parser->num_template_parameter_lists;
parser->num_template_parameter_lists = 0;
if (cp_lexer_next_token_is_keyword (parser->lexer, RID_TRY))
ctor_initializer_p = cp_parser_function_try_block (parser);
else
ctor_initializer_p
= cp_parser_ctor_initializer_opt_and_function_body (parser);
fn = finish_function ((ctor_initializer_p ? 1 : 0) |
(inline_p ? 2 : 0));
expand_or_defer_fn (fn);
parser->in_unbraced_linkage_specification_p
= saved_in_unbraced_linkage_specification_p;
parser->num_template_parameter_lists
= saved_num_template_parameter_lists;
return fn;
}
static void
cp_parser_template_declaration_after_export (cp_parser* parser, bool member_p)
{
tree decl = NULL_TREE;
tree parameter_list;
bool friend_p = false;
if (!cp_parser_require_keyword (parser, RID_TEMPLATE, "`template'"))
return;
if (!cp_parser_require (parser, CPP_LESS, "`<'"))
return;
if (cp_lexer_next_token_is (parser->lexer, CPP_GREATER))
{
cp_parser_error (parser, "invalid explicit specialization");
begin_specialization ();
parameter_list = NULL_TREE;
}
else
{
begin_template_parm_list ();
parameter_list = cp_parser_template_parameter_list (parser);
parameter_list = end_template_parm_list (parameter_list);
}
cp_parser_skip_until_found (parser, CPP_GREATER, "`>'");
++parser->num_template_parameter_lists;
if (cp_lexer_next_token_is_keyword (parser->lexer,
RID_TEMPLATE))
cp_parser_template_declaration_after_export (parser, member_p);
else
{
decl = cp_parser_single_declaration (parser,
member_p,
&friend_p);
if (member_p && !friend_p && decl)
{
if (TREE_CODE (decl) == TYPE_DECL)
cp_parser_check_access_in_redeclaration (decl);
decl = finish_member_template_decl (decl);
}
else if (friend_p && decl && TREE_CODE (decl) == TYPE_DECL)
make_friend_class (current_class_type, TREE_TYPE (decl),
true);
}
--parser->num_template_parameter_lists;
finish_template_decl (parameter_list);
if (member_p && !friend_p && decl && !DECL_CLASS_TEMPLATE_P (decl))
finish_member_declaration (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_VALUE (parser->unparsed_functions_queues));
}
static tree
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;
bool function_definition_p = false;
push_deferring_access_checks (dk_deferred);
decl_specifiers
= cp_parser_decl_specifier_seq (parser,
CP_PARSER_FLAGS_OPTIONAL,
&attributes,
&declares_class_or_enum);
if (friend_p)
*friend_p = cp_parser_friend_p (decl_specifiers);
stop_deferring_access_checks ();
if (declares_class_or_enum)
{
if (cp_parser_declares_only_class_p (parser))
{
decl = shadow_tag (decl_specifiers);
if (decl)
decl = TYPE_NAME (decl);
else
decl = error_mark_node;
}
}
else
decl = NULL_TREE;
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,
true,
member_p,
declares_class_or_enum,
&function_definition_p);
pop_deferring_access_checks ();
parser->scope = NULL_TREE;
parser->qualifying_scope = NULL_TREE;
parser->object_scope = NULL_TREE;
if (!function_definition_p
&& !cp_parser_require (parser, CPP_SEMICOLON, "`;'"))
cp_parser_skip_to_end_of_block_or_statement (parser);
return decl;
}
static tree
cp_parser_simple_cast_expression (cp_parser *parser)
{
return cp_parser_cast_expression (parser, false);
}
static tree
cp_parser_functional_cast (cp_parser* parser, tree type)
{
tree expression_list;
tree cast;
expression_list
= cp_parser_parenthesized_expression_list (parser, false,
NULL);
cast = build_functional_cast (type, expression_list);
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;
}
static tree
cp_parser_save_member_function_body (cp_parser* parser,
tree decl_specifiers,
tree declarator,
tree attributes)
{
cp_token_cache *cache;
tree fn;
fn = start_method (decl_specifiers, declarator, attributes);
if (fn == error_mark_node)
{
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;
}
cp_parser_save_default_args (parser, fn);
cache = cp_token_cache_new ();
cp_parser_cache_group (parser, cache, CPP_CLOSE_BRACE, 0);
while (cp_lexer_next_token_is_keyword (parser->lexer, RID_CATCH))
cp_parser_cache_group (parser, cache, CPP_CLOSE_BRACE, 0);
DECL_PENDING_INLINE_INFO (fn) = cache;
DECL_PENDING_INLINE_P (fn) = 1;
DECL_INITIALIZED_IN_CLASS_P (fn) = 1;
finish_method (fn);
TREE_VALUE (parser->unparsed_functions_queues)
= tree_cons (NULL_TREE, fn,
TREE_VALUE (parser->unparsed_functions_queues));
return fn;
}
static tree
cp_parser_enclosed_template_argument_list (cp_parser* parser)
{
tree arguments;
tree saved_scope;
tree saved_qualifying_scope;
tree saved_object_scope;
bool 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;
saved_scope = parser->scope;
saved_qualifying_scope = parser->qualifying_scope;
saved_object_scope = parser->object_scope;
if (cp_lexer_next_token_is (parser->lexer, CPP_GREATER))
arguments = NULL_TREE;
else
arguments = cp_parser_template_argument_list (parser);
if (cp_lexer_next_token_is (parser->lexer, CPP_RSHIFT))
{
if (!saved_greater_than_is_operator_p)
{
cp_token* token;
error ("`>>' should be `> >' within a nested template argument list");
token = cp_lexer_peek_token (parser->lexer);
token->type = CPP_GREATER;
}
else
{
error ("spurious `>>', use `>' to terminate a template argument list");
cp_lexer_consume_token (parser->lexer);
}
}
else if (!cp_parser_require (parser, CPP_GREATER, "`>'"))
error ("missing `>' to terminate the template argument list");
parser->greater_than_is_operator_p
= saved_greater_than_is_operator_p;
parser->scope = saved_scope;
parser->qualifying_scope = saved_qualifying_scope;
parser->object_scope = saved_object_scope;
return arguments;
}
static void
cp_parser_late_parsing_for_member (cp_parser* parser, tree member_function)
{
cp_lexer *saved_lexer;
if (DECL_FUNCTION_TEMPLATE_P (member_function))
member_function = DECL_TEMPLATE_RESULT (member_function);
my_friendly_assert (parser->num_classes_being_defined == 0, 20010816);
parser->unparsed_functions_queues
= tree_cons (NULL_TREE, NULL_TREE, parser->unparsed_functions_queues);
maybe_begin_member_template_processing (member_function);
if (DECL_PENDING_INLINE_P (member_function))
{
tree function_scope;
cp_token_cache *tokens;
tokens = DECL_PENDING_INLINE_INFO (member_function);
DECL_PENDING_INLINE_INFO (member_function) = NULL;
DECL_PENDING_INLINE_P (member_function) = 0;
function_scope = decl_function_context (member_function);
if (function_scope)
push_function_context_to (function_scope);
saved_lexer = parser->lexer;
parser->lexer = cp_lexer_new_from_tokens (tokens);
parser->lexer->next = saved_lexer;
cp_lexer_peek_token (parser->lexer);
start_function (NULL_TREE, member_function, NULL_TREE,
SF_PRE_PARSED | SF_INCLASS_INLINE);
cp_parser_function_definition_after_declarator (parser,
true);
if (function_scope)
pop_function_context_from (function_scope);
parser->lexer = saved_lexer;
}
maybe_end_member_template_processing ();
parser->unparsed_functions_queues
= TREE_CHAIN (parser->unparsed_functions_queues);
}
static void
cp_parser_save_default_args (cp_parser* parser, tree decl)
{
tree probe;
for (probe = TYPE_ARG_TYPES (TREE_TYPE (decl));
probe;
probe = TREE_CHAIN (probe))
if (TREE_PURPOSE (probe))
{
TREE_PURPOSE (parser->unparsed_functions_queues)
= tree_cons (NULL_TREE, decl,
TREE_PURPOSE (parser->unparsed_functions_queues));
break;
}
return;
}
static void
cp_parser_late_parsing_default_args (cp_parser *parser, tree fn)
{
cp_lexer *saved_lexer;
cp_token_cache *tokens;
bool saved_local_variables_forbidden_p;
tree parameters;
parser->unparsed_functions_queues
= tree_cons (NULL_TREE, NULL_TREE, parser->unparsed_functions_queues);
for (parameters = TYPE_ARG_TYPES (TREE_TYPE (fn));
parameters;
parameters = TREE_CHAIN (parameters))
{
if (!TREE_PURPOSE (parameters)
|| TREE_CODE (TREE_PURPOSE (parameters)) != DEFAULT_ARG)
continue;
saved_lexer = parser->lexer;
tokens = DEFARG_TOKENS (TREE_PURPOSE (parameters));
parser->lexer = cp_lexer_new_from_tokens (tokens);
cp_lexer_peek_token (parser->lexer);
saved_local_variables_forbidden_p = parser->local_variables_forbidden_p;
parser->local_variables_forbidden_p = true;
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 (!cp_lexer_next_token_is (parser->lexer, CPP_EOF))
cp_parser_error (parser, "expected `,'");
parser->lexer = saved_lexer;
parser->local_variables_forbidden_p = saved_local_variables_forbidden_p;
}
parser->unparsed_functions_queues
= TREE_CHAIN (parser->unparsed_functions_queues);
}
static tree
cp_parser_sizeof_operand (cp_parser* parser, enum rid keyword)
{
static const char *format;
tree expr = NULL_TREE;
const char *saved_message;
bool saved_integral_constant_expression_p;
if (!format)
format = "types may not be defined in `%s' expressions";
saved_message = parser->type_definition_forbidden_message;
parser->type_definition_forbidden_message
= xmalloc (strlen (format)
+ strlen (IDENTIFIER_POINTER (ridpointers[keyword]))
+ 1 );
sprintf ((char *) parser->type_definition_forbidden_message,
format, IDENTIFIER_POINTER (ridpointers[keyword]));
saved_integral_constant_expression_p = parser->integral_constant_expression_p;
parser->integral_constant_expression_p = false;
++skip_evaluation;
if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN))
{
tree type;
bool saved_in_type_id_in_expr_p;
cp_parser_parse_tentatively (parser);
cp_lexer_consume_token (parser->lexer);
saved_in_type_id_in_expr_p = parser->in_type_id_in_expr_p;
parser->in_type_id_in_expr_p = true;
type = cp_parser_type_id (parser);
parser->in_type_id_in_expr_p = saved_in_type_id_in_expr_p;
cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
if (cp_parser_parse_definitely (parser))
{
type = build_tree_list (NULL_TREE,
type);
expr = grokdeclarator (NULL_TREE,
type,
TYPENAME,
0,
NULL);
}
}
if (!expr)
expr = cp_parser_unary_expression (parser, false);
--skip_evaluation;
free ((char *) parser->type_definition_forbidden_message);
parser->type_definition_forbidden_message = saved_message;
parser->integral_constant_expression_p = saved_integral_constant_expression_p;
return expr;
}
static bool
cp_parser_declares_only_class_p (cp_parser *parser)
{
return (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON)
|| cp_lexer_next_token_is (parser->lexer, CPP_COMMA));
}
static bool
cp_parser_friend_p (tree decl_specifiers)
{
while (decl_specifiers)
{
if (TREE_CODE (TREE_VALUE (decl_specifiers)) == IDENTIFIER_NODE
&& C_RID_CODE (TREE_VALUE (decl_specifiers)) == RID_FRIEND)
return true;
decl_specifiers = TREE_CHAIN (decl_specifiers);
}
return false;
}
static cp_token *
cp_parser_require (cp_parser* parser,
enum cpp_ttype type,
const char* token_desc)
{
if (cp_lexer_next_token_is (parser->lexer, type))
return cp_lexer_consume_token (parser->lexer);
else
{
if (!cp_parser_simulate_error (parser))
{
char *message = concat ("expected ", token_desc, NULL);
cp_parser_error (parser, message);
free (message);
}
return NULL;
}
}
static void
cp_parser_skip_until_found (cp_parser* parser,
enum cpp_ttype type,
const char* token_desc)
{
cp_token *token;
unsigned nesting_depth = 0;
if (cp_parser_require (parser, type, token_desc))
return;
while (true)
{
token = cp_lexer_peek_token (parser->lexer);
if (token->type == type && !nesting_depth)
{
cp_lexer_consume_token (parser->lexer);
return;
}
if (token->type == CPP_EOF)
return;
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
|| token->type == CPP_CLOSE_PAREN
|| token->type == CPP_CLOSE_SQUARE)
{
if (nesting_depth-- == 0)
return;
}
cp_lexer_consume_token (parser->lexer);
}
}
static cp_token *
cp_parser_require_keyword (cp_parser* parser,
enum rid keyword,
const char* token_desc)
{
cp_token *token = cp_parser_require (parser, CPP_KEYWORD, token_desc);
if (token && token->keyword != keyword)
{
dyn_string_t error_msg;
error_msg = dyn_string_new (0);
dyn_string_append_cstr (error_msg, "expected ");
dyn_string_append_cstr (error_msg, token_desc);
cp_parser_error (parser, error_msg->s);
dyn_string_delete (error_msg);
return NULL;
}
return token;
}
static bool
cp_parser_token_starts_function_definition_p (cp_token* token)
{
return (
token->type == CPP_OPEN_BRACE
|| token->type == CPP_COLON
|| token->keyword == RID_TRY
|| token->keyword == RID_RETURN);
}
static bool
cp_parser_next_token_starts_class_definition_p (cp_parser *parser)
{
cp_token *token;
token = cp_lexer_peek_token (parser->lexer);
return (token->type == CPP_OPEN_BRACE || token->type == CPP_COLON);
}
static bool
cp_parser_next_token_ends_template_argument_p (cp_parser *parser)
{
cp_token *token;
token = cp_lexer_peek_token (parser->lexer);
return (token->type == CPP_COMMA || token->type == CPP_GREATER
|| token->type == CPP_RSHIFT);
}
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;
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;
}
static enum tag_types
cp_parser_token_is_class_key (cp_token* token)
{
switch (token->keyword)
{
case RID_CLASS:
return class_type;
case RID_STRUCT:
return record_type;
case RID_UNION:
return union_type;
default:
return none_type;
}
}
static void
cp_parser_check_class_key (enum tag_types class_key, tree 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",
type);
}
static void cp_parser_check_access_in_redeclaration (tree decl)
{
if (!CLASS_TYPE_P (TREE_TYPE (decl)))
return;
if ((TREE_PRIVATE (decl)
!= (current_access_specifier == access_private_node))
|| (TREE_PROTECTED (decl)
!= (current_access_specifier == access_protected_node)))
error ("%D redeclared with different access", decl);
}
static bool
cp_parser_optional_template_keyword (cp_parser *parser)
{
if (cp_lexer_next_token_is_keyword (parser->lexer, RID_TEMPLATE))
{
if (!processing_template_decl)
{
error ("`template' (as a disambiguator) is only allowed "
"within templates");
cp_lexer_purge_token (parser->lexer);
return false;
}
else
{
cp_lexer_consume_token (parser->lexer);
return true;
}
}
return false;
}
static void
cp_parser_pre_parsed_nested_name_specifier (cp_parser *parser)
{
tree value;
tree check;
value = cp_lexer_consume_token (parser->lexer)->value;
for (check = TREE_PURPOSE (value); check; check = TREE_CHAIN (check))
perform_or_defer_access_check (TREE_PURPOSE (check), TREE_VALUE (check));
parser->scope = TREE_VALUE (value);
parser->qualifying_scope = TREE_TYPE (value);
parser->object_scope = NULL_TREE;
}
static void
cp_parser_cache_group (cp_parser *parser,
cp_token_cache *cache,
enum cpp_ttype end,
unsigned depth)
{
while (true)
{
cp_token *token;
if ((end == CPP_CLOSE_PAREN || depth == 0)
&& cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON))
return;
if (cp_lexer_next_token_is (parser->lexer, CPP_EOF))
return;
token = cp_lexer_consume_token (parser->lexer);
cp_token_cache_push_token (cache, token);
if (token->type == CPP_OPEN_BRACE)
{
cp_parser_cache_group (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);
else if (token->type == end)
return;
}
}
static void
cp_parser_parse_tentatively (cp_parser* parser)
{
parser->context = cp_parser_context_new (parser->context);
cp_lexer_save_tokens (parser->lexer);
push_deferring_access_checks (dk_deferred);
}
static void
cp_parser_commit_to_tentative_parse (cp_parser* parser)
{
cp_parser_context *context;
cp_lexer *lexer;
lexer = parser->lexer;
for (context = parser->context; context->next; context = context->next)
{
if (context->status == CP_PARSER_STATUS_KIND_COMMITTED)
break;
context->status = CP_PARSER_STATUS_KIND_COMMITTED;
while (!cp_lexer_saving_tokens (lexer))
lexer = lexer->next;
cp_lexer_commit_tokens (lexer);
}
}
static void
cp_parser_abort_tentative_parse (cp_parser* parser)
{
cp_parser_simulate_error (parser);
cp_parser_parse_definitely (parser);
}
static bool
cp_parser_parse_definitely (cp_parser* parser)
{
bool error_occurred;
cp_parser_context *context;
error_occurred = cp_parser_error_occurred (parser);
context = parser->context;
parser->context = context->next;
if (!error_occurred)
{
if (context->status != CP_PARSER_STATUS_KIND_COMMITTED)
cp_lexer_commit_tokens (parser->lexer);
pop_to_parent_deferring_access_checks ();
}
else
{
cp_lexer_rollback_tokens (parser->lexer);
pop_deferring_access_checks ();
}
context->next = cp_parser_context_free_list;
cp_parser_context_free_list = context;
return !error_occurred;
}
static bool
cp_parser_committed_to_tentative_parse (cp_parser* parser)
{
return (cp_parser_parsing_tentatively (parser)
&& parser->context->status == CP_PARSER_STATUS_KIND_COMMITTED);
}
static bool
cp_parser_error_occurred (cp_parser* parser)
{
return (cp_parser_parsing_tentatively (parser)
&& parser->context->status == CP_PARSER_STATUS_KIND_ERROR);
}
static bool
cp_parser_allow_gnu_extensions_p (cp_parser* parser)
{
return parser->allow_gnu_extensions_p;
}
static GTY (()) cp_parser *the_parser;
void
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
? dk_no_deferred : dk_no_check);
error_occurred = cp_parser_translation_unit (the_parser);
the_parser = NULL;
}
int yydebug;
#include "gt-cp-parser.h"