#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"
#include "target.h"
#include "debug.h"
#include "c-common.h"
#include "../../libcpp/internal.h"
#include "tree-iterator.h"
typedef struct cp_token GTY (())
{
ENUM_BITFIELD (cpp_ttype) type : 8;
ENUM_BITFIELD (rid) keyword : 8;
unsigned char flags;
BOOL_BITFIELD in_system_header : 1;
BOOL_BITFIELD implicit_extern_c : 1;
tree value;
location_t location;
} cp_token;
typedef struct cp_token *cp_token_position;
DEF_VEC_MALLOC_P (cp_token_position);
static const cp_token eof_token =
{
CPP_EOF, RID_MAX, 0, 0, 0, NULL_TREE,
#if USE_MAPPED_LOCATION
0
#else
{0, 0}
#endif
};
typedef struct cp_lexer GTY (())
{
cp_token * GTY ((length ("%h.buffer_length"))) buffer;
size_t buffer_length;
cp_token_position GTY ((skip)) last_token;
cp_token_position GTY ((skip)) next_token;
VEC (cp_token_position) *GTY ((skip)) saved_tokens;
bool debugging_p;
struct cp_lexer *next;
} cp_lexer;
typedef struct cp_token_cache GTY(())
{
cp_token * GTY((skip)) first;
cp_token * GTY ((skip)) last;
} cp_token_cache;
static void objc_finish_foreach_stmt (tree);
static cp_lexer *cp_lexer_new_main
(void);
static cp_lexer *cp_lexer_new_from_tokens
(cp_token_cache *tokens);
static void cp_lexer_destroy
(cp_lexer *);
static int cp_lexer_saving_tokens
(const cp_lexer *);
static cp_token_position cp_lexer_token_position
(cp_lexer *, bool);
static cp_token *cp_lexer_token_at
(cp_lexer *, cp_token_position);
static void cp_lexer_get_preprocessor_token
(cp_lexer *, cp_token *);
static inline 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_position);
static void cp_lexer_handle_pragma
(cp_lexer *);
static void cp_lexer_save_tokens
(cp_lexer *);
static void cp_lexer_commit_tokens
(cp_lexer *);
static void cp_lexer_rollback_tokens
(cp_lexer *);
#ifdef ENABLE_CHECKING
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;
#else
#define cp_lexer_debug_stream stdout
#define cp_lexer_print_token(str, tok) (void) 0
#define cp_lexer_debugging_p(lexer) 0
#endif
static cp_token_cache *cp_token_cache_new
(cp_token *, cp_token *);
#define CP_LEXER_BUFFER_SIZE 10000
#define CP_SAVED_TOKEN_STACK 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_PURGED ((enum cpp_ttype) (CPP_NESTED_NAME_SPECIFIER + 1))
#define N_CP_TTYPES ((int) (CPP_PURGED + 1))
#ifdef ENABLE_CHECKING
static FILE *cp_lexer_debug_stream;
#endif
static cp_lexer *
cp_lexer_new_main (void)
{
cp_token first_token;
cp_lexer *lexer;
cp_token *pos;
size_t alloc;
size_t space;
cp_token *buffer;
cpp_get_options (parse_in)->defer_file_change_debug_hooks = true;
cp_lexer_get_preprocessor_token (NULL, &first_token);
while (first_token.type == CPP_BINCL
|| first_token.type == CPP_EINCL)
{
if (first_token.type == CPP_BINCL)
(*debug_hooks->start_source_file) (TREE_INT_CST_LOW (first_token.value),
first_token.location.file);
else
(*debug_hooks->end_source_file) (TREE_INT_CST_LOW (first_token.value));
cp_lexer_get_preprocessor_token (NULL, &first_token);
}
cpp_get_options (parse_in)->defer_pragmas = true;
c_lex_return_raw_strings = true;
c_common_no_more_pch ();
lexer = GGC_CNEW (cp_lexer);
#ifdef ENABLE_CHECKING
lexer->debugging_p = false;
#endif
lexer->saved_tokens = VEC_alloc (cp_token_position, CP_SAVED_TOKEN_STACK);
alloc = CP_LEXER_BUFFER_SIZE;
buffer = ggc_alloc (alloc * sizeof (cp_token));
space = alloc;
pos = buffer;
*pos = first_token;
while (pos->type != CPP_EOF)
{
pos++;
if (!--space)
{
space = alloc;
alloc *= 2;
buffer = ggc_realloc (buffer, alloc * sizeof (cp_token));
pos = buffer + space;
}
cp_lexer_get_preprocessor_token (lexer, pos);
}
lexer->buffer = buffer;
lexer->buffer_length = alloc - space;
lexer->last_token = pos;
lexer->next_token = lexer->buffer_length ? buffer : (cp_token *)&eof_token;
c_lex_return_raw_strings = false;
gcc_assert (lexer->next_token->type != CPP_PURGED);
return lexer;
}
static cp_lexer *
cp_lexer_new_from_tokens (cp_token_cache *cache)
{
cp_token *first = cache->first;
cp_token *last = cache->last;
cp_lexer *lexer = GGC_CNEW (cp_lexer);
lexer->buffer = NULL;
lexer->buffer_length = 0;
lexer->next_token = first == last ? (cp_token *)&eof_token : first;
lexer->last_token = last;
lexer->saved_tokens = VEC_alloc (cp_token_position, CP_SAVED_TOKEN_STACK);
#ifdef ENABLE_CHECKING
lexer->debugging_p = false;
#endif
gcc_assert (lexer->next_token->type != CPP_PURGED);
return lexer;
}
static void
cp_lexer_destroy (cp_lexer *lexer)
{
if (lexer->buffer)
ggc_free (lexer->buffer);
VEC_free (cp_token_position, lexer->saved_tokens);
ggc_free (lexer);
}
#ifdef ENABLE_CHECKING
static inline bool
cp_lexer_debugging_p (cp_lexer *lexer)
{
return lexer->debugging_p;
}
#endif
static inline cp_token_position
cp_lexer_token_position (cp_lexer *lexer, bool previous_p)
{
gcc_assert (!previous_p || lexer->next_token != &eof_token);
return lexer->next_token - previous_p;
}
static inline cp_token *
cp_lexer_token_at (cp_lexer *lexer ATTRIBUTE_UNUSED, cp_token_position pos)
{
return pos;
}
static inline int
cp_lexer_saving_tokens (const cp_lexer* lexer)
{
return VEC_length (cp_token_position, lexer->saved_tokens) != 0;
}
static void
cp_lexer_get_preprocessor_token (cp_lexer *lexer ATTRIBUTE_UNUSED ,
cp_token *token)
{
static int is_extern_c = 0;
token->type = c_lex_with_flags (&token->value, &token->flags);
token->location = input_location;
token->in_system_header = in_system_header;
is_extern_c += pending_lang_change;
pending_lang_change = 0;
token->implicit_extern_c = is_extern_c > 0;
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 if (token->type == CPP_AT_NAME)
{
token->type = CPP_KEYWORD;
switch (C_RID_CODE (token->value))
{
case RID_CLASS: token->keyword = RID_AT_CLASS; break;
case RID_AT_PACKAGE: token->keyword = RID_AT_PACKAGE; break;
case RID_PRIVATE: token->keyword = RID_AT_PRIVATE; break;
case RID_PROTECTED: token->keyword = RID_AT_PROTECTED; break;
case RID_PUBLIC: token->keyword = RID_AT_PUBLIC; break;
case RID_THROW: token->keyword = RID_AT_THROW; break;
case RID_TRY: token->keyword = RID_AT_TRY; break;
case RID_CATCH: token->keyword = RID_AT_CATCH; break;
default: token->keyword = C_RID_CODE (token->value);
}
}
else
token->keyword = RID_MAX;
}
static inline void
cp_lexer_set_source_position_from_token (cp_token *token)
{
if (token->type != CPP_EOF)
{
input_location = token->location;
in_system_header = token->in_system_header;
}
}
static inline void
cp_lexer_consume_bincl_eincl_token (cp_lexer *lexer)
{
while (lexer->next_token->type == CPP_BINCL
|| lexer->next_token->type == CPP_EINCL)
{
if (lexer->next_token->type == CPP_BINCL)
(*debug_hooks->start_source_file) (TREE_INT_CST_LOW (lexer->next_token->value),
lexer->next_token->location.file);
else if (lexer->next_token->type == CPP_EINCL)
(*debug_hooks->end_source_file) (TREE_INT_CST_LOW (lexer->next_token->value));
cp_lexer_purge_token (lexer);
}
}
static inline cp_token *
cp_lexer_peek_token (cp_lexer *lexer)
{
if (flag_ms_asms)
while (lexer->next_token->type == CPP_NUMBER
&& lexer->next_token->value == error_mark_node)
{
error ("invalid suffix on integer constant");
cp_lexer_consume_token (lexer);
}
cp_lexer_consume_bincl_eincl_token (lexer);
if (cp_lexer_debugging_p (lexer))
{
fputs ("cp_lexer: peeking at token: ", cp_lexer_debug_stream);
cp_lexer_print_token (cp_lexer_debug_stream, lexer->next_token);
putc ('\n', cp_lexer_debug_stream);
}
return lexer->next_token;
}
static inline bool
cp_lexer_next_token_is (cp_lexer* lexer, enum cpp_ttype type)
{
return cp_lexer_peek_token (lexer)->type == type;
}
static inline bool
cp_lexer_next_token_is_not (cp_lexer* lexer, enum cpp_ttype type)
{
return !cp_lexer_next_token_is (lexer, type);
}
static inline 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;
gcc_assert (n > 0 && lexer->next_token != &eof_token);
if (cp_lexer_debugging_p (lexer))
fprintf (cp_lexer_debug_stream,
"cp_lexer: peeking ahead %ld at token: ", (long)n);
--n;
token = lexer->next_token;
while (n != 0)
{
++token;
if (token == lexer->last_token)
{
token = (cp_token *)&eof_token;
break;
}
if (token->type != CPP_PURGED
&& token->type != CPP_BINCL
&& token->type != CPP_EINCL)
--n;
}
if (cp_lexer_debugging_p (lexer))
{
cp_lexer_print_token (cp_lexer_debug_stream, token);
putc ('\n', cp_lexer_debug_stream);
}
return token;
}
static cp_token *
cp_lexer_consume_token (cp_lexer* lexer)
{
cp_token *token = lexer->next_token;
gcc_assert (token != &eof_token);
do
{
lexer->next_token++;
cp_lexer_consume_bincl_eincl_token (lexer);
if (lexer->next_token == lexer->last_token)
{
lexer->next_token = (cp_token *)&eof_token;
break;
}
}
while (lexer->next_token->type == CPP_PURGED);
cp_lexer_set_source_position_from_token (token);
if (cp_lexer_debugging_p (lexer))
{
fputs ("cp_lexer: consuming token: ", cp_lexer_debug_stream);
cp_lexer_print_token (cp_lexer_debug_stream, token);
putc ('\n', cp_lexer_debug_stream);
}
return token;
}
static void
cp_lexer_purge_token (cp_lexer *lexer)
{
cp_token *tok = lexer->next_token;
gcc_assert (tok != &eof_token);
tok->type = CPP_PURGED;
tok->location = UNKNOWN_LOCATION;
tok->value = NULL_TREE;
tok->keyword = RID_MAX;
do
{
tok++;
if (tok == lexer->last_token)
{
tok = (cp_token *)&eof_token;
break;
}
}
while (tok->type == CPP_PURGED);
lexer->next_token = tok;
}
static void
cp_lexer_purge_tokens_after (cp_lexer *lexer, cp_token *tok)
{
cp_token *peek = lexer->next_token;
if (peek == &eof_token)
peek = lexer->last_token;
gcc_assert (tok < peek);
for ( tok += 1; tok != peek; tok += 1)
{
tok->type = CPP_PURGED;
tok->location = UNKNOWN_LOCATION;
tok->value = NULL_TREE;
tok->keyword = RID_MAX;
}
}
static void
cp_lexer_handle_pragma (cp_lexer *lexer)
{
cpp_string s;
cp_token *token = cp_lexer_consume_token (lexer);
gcc_assert (token->type == CPP_PRAGMA);
gcc_assert (token->value);
s.len = TREE_STRING_LENGTH (token->value);
s.text = (const unsigned char *) TREE_STRING_POINTER (token->value);
cpp_handle_deferred_pragma (parse_in, &s);
token->value = NULL;
}
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");
VEC_safe_push (cp_token_position, lexer->saved_tokens, 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");
VEC_pop (cp_token_position, lexer->saved_tokens);
}
static void
cp_lexer_rollback_tokens (cp_lexer* lexer)
{
if (cp_lexer_debugging_p (lexer))
fprintf (cp_lexer_debug_stream, "cp_lexer: restoring tokens\n");
lexer->next_token = VEC_pop (cp_token_position, lexer->saved_tokens);
}
#ifdef ENABLE_CHECKING
static void
cp_lexer_print_token (FILE * stream, cp_token *token)
{
static const char *const token_names[] = {
#define OP(e, s) #e,
#define TK(e, s) #e,
TTYPE_TABLE
#undef OP
#undef TK
"KEYWORD",
"TEMPLATE_ID",
"NESTED_NAME_SPECIFIER",
"PURGED"
};
gcc_assert (token->type < ARRAY_SIZE(token_names));
fputs (token_names[token->type], stream);
switch (token->type)
{
case CPP_KEYWORD:
if (TREE_CODE (token->value) != IDENTIFIER_NODE)
break;
case CPP_NAME:
fputs (IDENTIFIER_POINTER (token->value), stream);
break;
case CPP_STRING:
case CPP_WSTRING:
case CPP_PRAGMA:
fprintf (stream, " \"%s\"", TREE_STRING_POINTER (token->value));
break;
default:
break;
}
}
static void
cp_lexer_start_debugging (cp_lexer* lexer)
{
lexer->debugging_p = true;
}
static void
cp_lexer_stop_debugging (cp_lexer* lexer)
{
lexer->debugging_p = false;
}
#endif
static cp_token_cache *
cp_token_cache_new (cp_token *first, cp_token *last)
{
cp_token_cache *cache = GGC_NEW (cp_token_cache);
cache->first = first;
cache->last = last;
return cache;
}
static void clear_decl_specs
(cp_decl_specifier_seq *);
static void
clear_decl_specs (cp_decl_specifier_seq *decl_specs)
{
memset (decl_specs, 0, sizeof (cp_decl_specifier_seq));
}
static cp_declarator *make_call_declarator
(cp_declarator *, cp_parameter_declarator *, cp_cv_quals, tree);
static cp_declarator *make_array_declarator
(cp_declarator *, tree);
static cp_declarator *make_pointer_declarator
(cp_cv_quals, cp_declarator *);
static cp_declarator *make_reference_declarator
(cp_cv_quals, cp_declarator *);
static cp_parameter_declarator *make_parameter_declarator
(cp_decl_specifier_seq *, cp_declarator *, tree);
static cp_declarator *make_ptrmem_declarator
(cp_cv_quals, tree, cp_declarator *);
cp_declarator *cp_error_declarator;
static struct obstack declarator_obstack;
static inline void *
alloc_declarator (size_t bytes)
{
return obstack_alloc (&declarator_obstack, bytes);
}
static cp_declarator *
make_declarator (cp_declarator_kind kind)
{
cp_declarator *declarator;
declarator = (cp_declarator *) alloc_declarator (sizeof (cp_declarator));
declarator->kind = kind;
declarator->attributes = NULL_TREE;
declarator->declarator = NULL;
return declarator;
}
static cp_declarator *
make_id_declarator (tree qualifying_scope, tree unqualified_name,
special_function_kind sfk)
{
cp_declarator *declarator;
if (qualifying_scope && TYPE_P (qualifying_scope))
qualifying_scope = TYPE_MAIN_VARIANT (qualifying_scope);
gcc_assert (TREE_CODE (unqualified_name) == IDENTIFIER_NODE
|| TREE_CODE (unqualified_name) == BIT_NOT_EXPR
|| TREE_CODE (unqualified_name) == TEMPLATE_ID_EXPR);
declarator = make_declarator (cdk_id);
declarator->u.id.qualifying_scope = qualifying_scope;
declarator->u.id.unqualified_name = unqualified_name;
declarator->u.id.sfk = sfk;
return declarator;
}
cp_declarator *
make_pointer_declarator (cp_cv_quals cv_qualifiers, cp_declarator *target)
{
cp_declarator *declarator;
declarator = make_declarator (cdk_pointer);
declarator->declarator = target;
declarator->u.pointer.qualifiers = cv_qualifiers;
declarator->u.pointer.class_type = NULL_TREE;
return declarator;
}
cp_declarator *
make_reference_declarator (cp_cv_quals cv_qualifiers, cp_declarator *target)
{
cp_declarator *declarator;
declarator = make_declarator (cdk_reference);
declarator->declarator = target;
declarator->u.pointer.qualifiers = cv_qualifiers;
declarator->u.pointer.class_type = NULL_TREE;
return declarator;
}
cp_declarator *
make_ptrmem_declarator (cp_cv_quals cv_qualifiers, tree class_type,
cp_declarator *pointee)
{
cp_declarator *declarator;
declarator = make_declarator (cdk_ptrmem);
declarator->declarator = pointee;
declarator->u.pointer.qualifiers = cv_qualifiers;
declarator->u.pointer.class_type = class_type;
return declarator;
}
cp_declarator *
make_call_declarator (cp_declarator *target,
cp_parameter_declarator *parms,
cp_cv_quals cv_qualifiers,
tree exception_specification)
{
cp_declarator *declarator;
declarator = make_declarator (cdk_function);
declarator->declarator = target;
declarator->u.function.parameters = parms;
declarator->u.function.qualifiers = cv_qualifiers;
declarator->u.function.exception_specification = exception_specification;
return declarator;
}
cp_declarator *
make_array_declarator (cp_declarator *element, tree bounds)
{
cp_declarator *declarator;
declarator = make_declarator (cdk_array);
declarator->declarator = element;
declarator->u.array.bounds = bounds;
return declarator;
}
cp_parameter_declarator *no_parameters;
cp_parameter_declarator *
make_parameter_declarator (cp_decl_specifier_seq *decl_specifiers,
cp_declarator *declarator,
tree default_argument)
{
cp_parameter_declarator *parameter;
parameter = ((cp_parameter_declarator *)
alloc_declarator (sizeof (cp_parameter_declarator)));
parameter->next = NULL;
if (decl_specifiers)
parameter->decl_specifiers = *decl_specifiers;
else
clear_decl_specs (¶meter->decl_specifiers);
parameter->declarator = declarator;
parameter->default_argument = default_argument;
parameter->ellipsis_p = false;
return parameter;
}
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;
enum cp_parser_prec
{
PREC_NOT_OPERATOR,
PREC_LOGICAL_OR_EXPRESSION,
PREC_LOGICAL_AND_EXPRESSION,
PREC_INCLUSIVE_OR_EXPRESSION,
PREC_EXCLUSIVE_OR_EXPRESSION,
PREC_AND_EXPRESSION,
PREC_EQUALITY_EXPRESSION,
PREC_RELATIONAL_EXPRESSION,
PREC_SHIFT_EXPRESSION,
PREC_ADDITIVE_EXPRESSION,
PREC_MULTIPLICATIVE_EXPRESSION,
PREC_PM_EXPRESSION,
NUM_PREC_VALUES = PREC_PM_EXPRESSION
};
typedef struct cp_parser_binary_operations_map_node
{
enum cpp_ttype token_type;
enum tree_code tree_type;
enum cp_parser_prec prec;
} cp_parser_binary_operations_map_node;
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_expression_stack_entry
{
tree lhs;
enum tree_code tree_type;
int prec;
} cp_parser_expression_stack_entry;
typedef struct cp_parser_expression_stack_entry
cp_parser_expression_stack[NUM_PREC_VALUES];
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 const cp_parser_binary_operations_map_node binops[] = {
{ CPP_DEREF_STAR, MEMBER_REF, PREC_PM_EXPRESSION },
{ CPP_DOT_STAR, DOTSTAR_EXPR, PREC_PM_EXPRESSION },
{ CPP_MULT, MULT_EXPR, PREC_MULTIPLICATIVE_EXPRESSION },
{ CPP_DIV, TRUNC_DIV_EXPR, PREC_MULTIPLICATIVE_EXPRESSION },
{ CPP_MOD, TRUNC_MOD_EXPR, PREC_MULTIPLICATIVE_EXPRESSION },
{ CPP_PLUS, PLUS_EXPR, PREC_ADDITIVE_EXPRESSION },
{ CPP_MINUS, MINUS_EXPR, PREC_ADDITIVE_EXPRESSION },
{ CPP_LSHIFT, LSHIFT_EXPR, PREC_SHIFT_EXPRESSION },
{ CPP_RSHIFT, RSHIFT_EXPR, PREC_SHIFT_EXPRESSION },
{ CPP_LESS, LT_EXPR, PREC_RELATIONAL_EXPRESSION },
{ CPP_GREATER, GT_EXPR, PREC_RELATIONAL_EXPRESSION },
{ CPP_LESS_EQ, LE_EXPR, PREC_RELATIONAL_EXPRESSION },
{ CPP_GREATER_EQ, GE_EXPR, PREC_RELATIONAL_EXPRESSION },
{ CPP_MIN, MIN_EXPR, PREC_RELATIONAL_EXPRESSION },
{ CPP_MAX, MAX_EXPR, PREC_RELATIONAL_EXPRESSION },
{ CPP_EQ_EQ, EQ_EXPR, PREC_EQUALITY_EXPRESSION },
{ CPP_NOT_EQ, NE_EXPR, PREC_EQUALITY_EXPRESSION },
{ CPP_AND, BIT_AND_EXPR, PREC_AND_EXPRESSION },
{ CPP_XOR, BIT_XOR_EXPR, PREC_EXCLUSIVE_OR_EXPRESSION },
{ CPP_OR, BIT_IOR_EXPR, PREC_INCLUSIVE_OR_EXPRESSION },
{ CPP_AND_AND, TRUTH_ANDIF_EXPR, PREC_LOGICAL_AND_EXPRESSION },
{ CPP_OR_OR, TRUTH_ORIF_EXPR, PREC_LOGICAL_OR_EXPRESSION }
};
static cp_parser_binary_operations_map_node binops_by_token[N_CP_TTYPES];
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_CNEW (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 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;
bool implicit_extern_c;
bool translate_strings_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 tree cp_parser_string_literal
(cp_parser *, bool, bool);
static bool cp_parser_translation_unit
(cp_parser *);
static tree cp_parser_primary_expression
(cp_parser *, bool, cp_id_kind *, tree *);
static tree cp_parser_id_expression
(cp_parser *, bool, bool, bool *, bool);
static tree cp_parser_unqualified_id
(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, bool);
static tree cp_parser_postfix_open_square_expression
(cp_parser *, tree, bool);
static tree cp_parser_postfix_dot_deref_expression
(cp_parser *, enum cpp_ttype, tree, bool, cp_id_kind *);
static tree cp_parser_parenthesized_expression_list
(cp_parser *, bool, bool, bool *);
static void cp_parser_pseudo_destructor_name
(cp_parser *, tree *, tree *);
static tree cp_parser_unary_expression
(cp_parser *, bool, 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 *, tree *);
static cp_declarator *cp_parser_new_declarator_opt
(cp_parser *);
static cp_declarator *cp_parser_direct_new_declarator
(cp_parser *);
static tree cp_parser_new_initializer
(cp_parser *);
static tree cp_parser_delete_expression
(cp_parser *);
static tree cp_parser_cast_expression
(cp_parser *, bool, bool);
static tree cp_parser_binary_expression
(cp_parser *, bool);
static tree cp_parser_question_colon_clause
(cp_parser *, tree);
static tree cp_parser_assignment_expression
(cp_parser *, bool);
static enum tree_code cp_parser_assignment_operator_opt
(cp_parser *);
static tree cp_parser_expression
(cp_parser *, bool);
static tree cp_parser_constant_expression
(cp_parser *, bool, bool *);
static tree cp_parser_builtin_offsetof
(cp_parser *);
static void objc_foreach_stmt
(cp_parser *, tree);
static void objc_cp_parser_at_property
(cp_parser *);
static void objc_cp_parse_property_decl
(cp_parser *);
static void objc_cp_parser_property_impl (cp_parser *parser,
enum rid keyword);
static bool objc_attr_follwed_by_at_keyword
(cp_parser *);
static void cp_parser_statement
(cp_parser *, tree);
static tree cp_parser_labeled_statement
(cp_parser *, tree);
static tree cp_parser_expression_statement
(cp_parser *, tree);
static tree cp_parser_compound_statement
(cp_parser *, tree, bool);
static void cp_parser_statement_seq_opt
(cp_parser *, tree);
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 void cp_parser_decl_specifier_seq
(cp_parser *, cp_parser_flags, cp_decl_specifier_seq *, int *);
static tree cp_parser_storage_class_specifier_opt
(cp_parser *);
static tree cp_parser_function_specifier_opt
(cp_parser *, cp_decl_specifier_seq *);
static tree cp_parser_type_specifier
(cp_parser *, cp_parser_flags, cp_decl_specifier_seq *, bool,
int *, bool *);
static tree cp_parser_simple_type_specifier
(cp_parser *, cp_decl_specifier_seq *, cp_parser_flags);
static tree cp_parser_type_name
(cp_parser *);
static tree cp_parser_elaborated_type_specifier
(cp_parser *, 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 *, bool);
static void cp_parser_linkage_specification
(cp_parser *);
static tree cp_parser_init_declarator
(cp_parser *, cp_decl_specifier_seq *, bool, bool, int, bool *);
static cp_declarator *cp_parser_declarator
(cp_parser *, cp_parser_declarator_kind, int *, bool *, bool);
static cp_declarator *cp_parser_direct_declarator
(cp_parser *, cp_parser_declarator_kind, int *, bool);
static enum tree_code cp_parser_ptr_operator
(cp_parser *, tree *, cp_cv_quals *);
static cp_cv_quals cp_parser_cv_qualifier_seq_opt
(cp_parser *);
static tree cp_parser_declarator_id
(cp_parser *);
static tree cp_parser_type_id
(cp_parser *);
static void cp_parser_type_specifier_seq
(cp_parser *, bool, cp_decl_specifier_seq *);
static cp_parameter_declarator *cp_parser_parameter_declaration_clause
(cp_parser *);
static cp_parameter_declarator *cp_parser_parameter_declaration_list
(cp_parser *, bool *);
static cp_parameter_declarator *cp_parser_parameter_declaration
(cp_parser *, bool, bool *);
static void cp_parser_function_body
(cp_parser *);
static tree cp_parser_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, enum tag_types, 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 cp_declarator *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 *, bool *);
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_objc_message_receiver
(cp_parser *);
static tree cp_parser_objc_message_args
(cp_parser *);
static tree cp_parser_objc_message_expression
(cp_parser *);
static tree cp_parser_objc_encode_expression
(cp_parser *);
static tree cp_parser_objc_defs_expression
(cp_parser *);
static tree cp_parser_objc_protocol_expression
(cp_parser *);
static tree cp_parser_objc_selector_expression
(cp_parser *);
static tree cp_parser_objc_expression
(cp_parser *);
static void cp_parser_objc_visibility_spec
(cp_parser *);
static void cp_parser_objc_method_type
(cp_parser *);
static tree cp_parser_objc_protocol_qualifiers
(cp_parser *);
static tree cp_parser_objc_typename
(cp_parser *);
static bool cp_parser_objc_selector_p
(enum cpp_ttype);
static tree cp_parser_objc_selector
(cp_parser *);
static void cp_parser_objc_maybe_attributes
(cp_parser *, tree *);
static tree cp_parser_objc_method_keyword_params
(cp_parser *, tree *);
static tree cp_parser_objc_method_tail_params_opt
(cp_parser *, tree *);
static void cp_parser_objc_interstitial_code
(cp_parser *);
static tree cp_parser_objc_method_signature
(cp_parser *, tree *);
static void cp_parser_objc_method_prototype_list
(cp_parser *);
static void cp_parser_objc_method_definition_list
(cp_parser *);
static void cp_parser_objc_class_ivars
(cp_parser *);
static tree cp_parser_objc_identifier_list
(cp_parser *);
static void cp_parser_objc_alias_declaration
(cp_parser *);
static void cp_parser_objc_class_declaration
(cp_parser *);
static void cp_parser_objc_protocol_declaration
(cp_parser *);
static tree cp_parser_objc_protocol_refs_opt
(cp_parser *);
static void cp_parser_objc_superclass_or_category
(cp_parser *, tree *, tree *, bool *);
static void cp_parser_objc_class_interface
(cp_parser *);
static void cp_parser_objc_class_implementation
(cp_parser *);
static void cp_parser_objc_end_implementation
(cp_parser *);
static void cp_parser_objc_declaration
(cp_parser *);
static tree cp_parser_objc_try_catch_finally_statement
(cp_parser *);
static tree cp_parser_objc_synchronized_statement
(cp_parser *);
static tree cp_parser_objc_throw_statement
(cp_parser *);
static tree cp_parser_objc_statement
(cp_parser *);
static tree cp_parser_lookup_name
(cp_parser *, tree, enum tag_types, 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 *, cp_declarator *);
static bool cp_parser_check_template_parameters
(cp_parser *, unsigned);
static tree cp_parser_simple_cast_expression
(cp_parser *);
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 *, cp_decl_specifier_seq *, tree, const cp_declarator *);
static tree cp_parser_function_definition_after_declarator
(cp_parser *, bool);
static void cp_parser_template_declaration_after_export
(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 *, cp_decl_specifier_seq *, cp_declarator *, tree);
static tree cp_parser_enclosed_template_argument_list
(cp_parser *);
static void cp_parser_save_default_args
(cp_parser *, 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 void cp_parser_set_storage_class
(cp_decl_specifier_seq *, cp_storage_class);
static void cp_parser_set_decl_spec_type
(cp_decl_specifier_seq *, tree, bool);
static bool cp_parser_friend_p
(const cp_decl_specifier_seq *);
static cp_token *cp_parser_require
(cp_parser *, enum cpp_ttype, const char *);
static cp_token *cp_parser_require_keyword
(cp_parser *, enum rid, const char *);
static bool cp_parser_token_starts_function_definition_p
(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 *, 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_uncommitted_to_tentative_parse_p
(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
(cp_declarator *, tree);
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 tree cp_parser_iasm_compound_statement
(cp_parser *);
static void cp_parser_iasm_declaration_seq_opt
(cp_parser *);
static void cp_parser_iasm_line_seq_opt
(cp_parser *);
static void cp_parser_iasm_line
(cp_parser *);
static void cp_parser_iasm_statement_seq_opt
(cp_parser *);
static void cp_parser_iasm_statement
(cp_parser *);
static tree cp_parser_iasm_operands
(cp_parser *);
static tree cp_parser_iasm_operand
(cp_parser *);
static tree cp_parser_iasm_postfix_expression
(cp_parser *, bool);
static tree cp_parser_iasm_identifier_or_number
(cp_parser* parser);
static tree iasm_build_identifier_string
(cp_parser* parser, const char* str);
static tree cp_parser_iasm_relative_branch
(cp_parser *parser);
static tree cp_parser_iasm_top_statement
(cp_parser *parser);
static void cp_parser_iasm_maybe_skip_comments
(cp_parser *parser);
#ifndef IASM_SEE_OPCODE
#define IASM_SEE_OPCODE(YYCHAR, T) YYCHAR
#endif
#define TYPESPEC 1
#define IDENTIFIER 2
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 inline void
cp_parser_warn_min_max (void)
{
if (warn_deprecated && !in_system_header)
warning ("minimum/maximum operators are deprecated");
}
static void
cp_parser_error (cp_parser* parser, const char* message)
{
if (!cp_parser_simulate_error (parser))
{
cp_token *token = cp_lexer_peek_token (parser->lexer);
cp_lexer_set_source_position_from_token (token);
if (token->type == CPP_PRAGMA)
{
error ("%<#pragma%> is not allowed here");
cp_lexer_purge_token (parser->lexer);
return;
}
c_parse_error (message,
(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 if (parser->object_scope
&& !CLASS_TYPE_P (parser->object_scope))
error ("request for member %qD in non-class type %qT",
name, parser->object_scope);
else if (parser->object_scope)
error ("%<%T::%D%> has not been declared",
parser->object_scope, name);
else
error ("%qD 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 ("%qD %s", name, desired);
}
static bool
cp_parser_simulate_error (cp_parser* parser)
{
if (cp_parser_uncommitted_to_tentative_parse_p (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 (cp_declarator *declarator,
tree type)
{
while (declarator
&& (declarator->kind == cdk_pointer
|| declarator->kind == cdk_reference
|| declarator->kind == cdk_ptrmem))
declarator = declarator->declarator;
if (declarator
&& declarator->kind == cdk_function)
{
error ("new types may not be defined in a return type");
inform ("(perhaps a semicolon is missing after the definition of %qT)",
type);
}
}
static void
cp_parser_check_for_invalid_template_id (cp_parser* parser,
tree type)
{
cp_token_position start = 0;
if (cp_lexer_next_token_is (parser->lexer, CPP_LESS))
{
if (TYPE_P (type))
error ("%qT is not a template", type);
else if (TREE_CODE (type) == IDENTIFIER_NODE)
error ("%qE is not a template", type);
else
error ("invalid template-id");
if (cp_parser_uncommitted_to_tentative_parse_p (parser))
start = cp_lexer_token_position (parser->lexer, true);
cp_lexer_consume_token (parser->lexer);
cp_parser_enclosed_template_argument_list (parser);
if (start)
cp_lexer_purge_tokens_after (parser->lexer, start);
}
}
static bool
cp_parser_non_integral_constant_expression (cp_parser *parser,
const char *thing)
{
parser->non_integral_constant_expression_p = true;
if (parser->integral_constant_expression_p)
{
if (!parser->allow_non_integral_constant_expression_p)
{
error ("%s cannot appear in a constant-expression", thing);
return true;
}
}
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 %qE without an argument list",
decl);
else if (!parser->scope)
{
error ("%qE does not name a type", id);
if (processing_template_decl && current_class_type
&& TYPE_BINFO (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 ("%qE in namespace %qE does not name a type",
id, parser->scope);
else if (TYPE_P (parser->scope))
error ("%qE in class %qT does not name a type", id, parser->scope);
else
gcc_unreachable ();
}
cp_parser_commit_to_tentative_parse (parser);
}
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)
|| TREE_CODE (id) != IDENTIFIER_NODE)
return false;
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;
int result;
if (recovering && !or_comma
&& cp_parser_uncommitted_to_tentative_parse_p (parser))
return 0;
while (true)
{
cp_token *token;
if (cp_lexer_next_token_is (parser->lexer, CPP_EOF))
{
result = 0;
break;
}
token = cp_lexer_peek_token (parser->lexer);
if (token->type == CPP_SEMICOLON && !brace_depth)
{
result = 0;
break;
}
if (token->type == CPP_OPEN_BRACE)
++brace_depth;
if (token->type == CPP_CLOSE_BRACE)
{
if (!brace_depth--)
{
result = 0;
break;
}
}
if (recovering && or_comma && token->type == CPP_COMMA
&& !brace_depth && !paren_depth)
{
result = -1;
break;
}
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);
{
result = 1;
break;
}
}
}
cp_lexer_consume_token (parser->lexer);
}
return result;
}
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
objc_cp_parse_property_decl (cp_parser *parser)
{
int declares_class_or_enum;
cp_decl_specifier_seq declspecs;
cp_parser_decl_specifier_seq (parser,
CP_PARSER_FLAGS_NONE,
&declspecs,
&declares_class_or_enum);
while (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON))
{
tree property;
cp_token *token;
cp_declarator *declarator
= cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED,
NULL, NULL, false);
property = grokdeclarator (declarator, &declspecs, NORMAL,0, NULL);
if (property == error_mark_node || property == NULL_TREE)
return;
if (declspecs.attributes)
cplus_decl_attributes (&property, declspecs.attributes, 0);
token = cp_lexer_peek_token (parser->lexer);
if (token->keyword == RID_ATTRIBUTE)
{
declspecs.attributes = cp_parser_attributes_opt (parser);
cplus_decl_attributes (&property, declspecs.attributes, 0);
token = cp_lexer_peek_token (parser->lexer);
}
objc_add_property_variable (copy_node (property));
if (token->type == CPP_COMMA)
{
cp_lexer_consume_token (parser->lexer);
continue;
}
else if (token->type == CPP_EOF)
return;
}
cp_lexer_consume_token (parser->lexer);
}
static void
objc_cp_parser_property_impl (cp_parser *parser, enum rid keyword)
{
cp_lexer_consume_token (parser->lexer);
if (keyword == RID_AT_DYNAMIC)
{
tree identifier_list = cp_parser_objc_identifier_list (parser);
objc_declare_property_impl (2, identifier_list);
}
else
{
cp_token *sep = cp_lexer_peek_token (parser->lexer);
tree list = NULL_TREE;
do
{
tree property;
tree identifier_list;
if (sep->type == CPP_COMMA)
cp_lexer_consume_token (parser->lexer);
property = cp_parser_identifier (parser);
sep = cp_lexer_peek_token (parser->lexer);
if (sep->type == CPP_EQ)
{
cp_lexer_consume_token (parser->lexer);
identifier_list = build_tree_list (cp_parser_identifier (parser), property);
}
else
identifier_list = build_tree_list (NULL_TREE, property);
list = chainon (list, identifier_list);
sep = cp_lexer_peek_token (parser->lexer);
}
while (sep->type == CPP_COMMA);
objc_declare_property_impl (1, list);
}
cp_parser_consume_semicolon_at_end_of_statement (parser);
}
static void
objc_cp_parser_at_property (cp_parser *parser)
{
cp_token *token;
objc_set_property_attr (0, NULL_TREE);
cp_lexer_consume_token (parser->lexer);
token = cp_lexer_peek_token (parser->lexer);
if (token->type == CPP_OPEN_PAREN)
{
cp_lexer_consume_token (parser->lexer);
while (token->type != CPP_CLOSE_PAREN && token->type != CPP_EOF)
{
tree node;
node = cp_parser_identifier (parser);
if (node == ridpointers [(int) RID_READONLY])
{
objc_set_property_attr (1, NULL_TREE);
}
else if (node == ridpointers [(int) RID_GETTER]
|| node == ridpointers [(int) RID_SETTER])
{
token = cp_lexer_consume_token (parser->lexer);
if (token->type == CPP_EQ)
{
tree attr_ident = cp_parser_objc_selector (parser);
int num;
if (node == ridpointers [(int) RID_GETTER])
num = 2;
else
{
num = 3;
if (cp_lexer_next_token_is (parser->lexer, CPP_COLON))
cp_lexer_consume_token (parser->lexer);
}
objc_set_property_attr (num, attr_ident);
}
else
{
error ("getter/setter attribute must be followed by '='");
break;
}
}
else if (node == ridpointers [(int) RID_IVAR])
{
tree ivar_ident = NULL_TREE;
if (cp_lexer_next_token_is (parser->lexer, CPP_EQ))
{
cp_lexer_consume_token (parser->lexer);
ivar_ident = cp_parser_identifier (parser);
}
objc_set_property_attr (4, ivar_ident);
}
else if (node == ridpointers [(int) RID_BYCOPY])
{
objc_set_property_attr (5, NULL_TREE);
}
else if (node == ridpointers [(int) RID_BYREF])
{
objc_set_property_attr (6, NULL_TREE);
}
else if (node == ridpointers [(int) RID_DYNAMIC])
{
objc_set_property_attr (7, NULL_TREE);
}
else if (node == ridpointers [(int) RID_WEAK])
{
objc_set_property_attr (8, NULL_TREE);
}
else if (node == ridpointers [(int) RID_READWRITE])
{
objc_set_property_attr (9, NULL_TREE);
}
else if (node == ridpointers [(int) RID_ASSIGN])
{
objc_set_property_attr (10, NULL_TREE);
}
else if (node == ridpointers [(int) RID_RETAIN])
{
objc_set_property_attr (11, NULL_TREE);
}
else if (node == ridpointers [(int) RID_COPY])
{
objc_set_property_attr (12, NULL_TREE);
}
else if (node == ridpointers [(int) RID_NONATOMIC])
{
objc_set_property_attr (13, NULL_TREE);
}
else
{
error ("unknown property attribute");
break;
}
if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA))
cp_lexer_consume_token (parser->lexer);
token = cp_lexer_peek_token (parser->lexer);
}
if (token->type != CPP_CLOSE_PAREN)
{
error ("syntax error in @property's attribute declaration");
}
cp_lexer_consume_token (parser->lexer);
}
objc_cp_parse_property_decl (parser);
}
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, typename_type,
0);
if (result == error_mark_node)
cp_parser_diagnose_invalid_type_name (parser, scope, id);
return result;
}
return make_typename_type (scope, id, typename_type, tf_error);
}
static cp_parser *
cp_parser_new (void)
{
cp_parser *parser;
cp_lexer *lexer;
unsigned i;
lexer = cp_lexer_new_main ();
for (i = 0; i < sizeof (binops) / sizeof (binops[0]); i++)
binops_by_token[binops[i].token_type] = binops[i];
parser = GGC_CNEW (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->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->implicit_extern_c = false;
parser->translate_strings_p = true;
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 void
cp_parser_push_lexer_for_tokens (cp_parser *parser, cp_token_cache *cache)
{
cp_lexer *lexer = cp_lexer_new_from_tokens (cache);
lexer->next = parser->lexer;
parser->lexer = lexer;
cp_lexer_set_source_position_from_token (lexer->next_token);
}
static void
cp_parser_pop_lexer (cp_parser *parser)
{
cp_lexer *lexer = parser->lexer;
parser->lexer = lexer->next;
cp_lexer_destroy (lexer);
cp_lexer_set_source_position_from_token (parser->lexer->next_token);
}
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 tree
cp_parser_string_literal (cp_parser *parser, bool translate, bool wide_ok)
{
tree value;
bool wide = false;
bool pascal_p = false;
size_t count;
struct obstack str_ob;
cpp_string str, istr, *strs;
cp_token *tok;
tok = cp_lexer_peek_token (parser->lexer);
if (!cp_parser_is_string_literal (tok))
{
cp_parser_error (parser, "expected string-literal");
return error_mark_node;
}
if (!cp_parser_is_string_literal
(cp_lexer_peek_nth_token (parser->lexer, 2)))
{
cp_lexer_consume_token (parser->lexer);
str.text = (const unsigned char *)TREE_STRING_POINTER (tok->value);
str.len = TREE_STRING_LENGTH (tok->value);
count = 1;
if (tok->type == CPP_WSTRING)
wide = true;
if (CPP_OPTION (parse_in, pascal_strings))
{
if (wide && str.text[0] == 'L' && str.text[2] == '\\' && str.text[3] == 'p')
pascal_p = true;
else if (str.text[1] == '\\' && str.text[2] == 'p')
pascal_p = true;
}
strs = &str;
}
else
{
gcc_obstack_init (&str_ob);
count = 0;
do
{
cp_lexer_consume_token (parser->lexer);
count++;
str.text = (unsigned char *)TREE_STRING_POINTER (tok->value);
str.len = TREE_STRING_LENGTH (tok->value);
if (tok->type == CPP_WSTRING)
wide = true;
if (CPP_OPTION (parse_in, pascal_strings) && count == 1)
{
if (wide && str.text[0] == 'L' && str.text[2] == '\\' && str.text[3] == 'p')
pascal_p = true;
else if (str.text[1] == '\\' && str.text[2] == 'p')
pascal_p = true;
}
obstack_grow (&str_ob, &str, sizeof (cpp_string));
tok = cp_lexer_peek_token (parser->lexer);
}
while (cp_parser_is_string_literal (tok));
strs = (cpp_string *) obstack_finish (&str_ob);
}
if (wide && !wide_ok)
{
cp_parser_error (parser, "a wide string is invalid in this context");
wide = false;
}
if ((translate ? cpp_interpret_string : cpp_interpret_string_notranslate)
(parse_in, strs, count, &istr, wide, pascal_p))
{
value = build_string (istr.len, (char *)istr.text);
free ((void *)istr.text);
TREE_TYPE (value) = wide ? wchar_array_type_node
: pascal_p ? pascal_string_type_node
: char_array_type_node;
value = fix_string_type (value);
}
else
value = error_mark_node;
if (count > 1)
obstack_free (&str_ob, 0);
return value;
}
static bool
cp_parser_translation_unit (cp_parser* parser)
{
static void *declarator_obstack_base;
bool success;
if (!cp_error_declarator)
{
gcc_obstack_init (&declarator_obstack);
cp_error_declarator = make_declarator (cdk_error);
no_parameters = make_parameter_declarator (NULL, NULL, NULL_TREE);
declarator_obstack_base = obstack_next_free (&declarator_obstack);
}
while (true)
{
cp_parser_declaration_seq_opt (parser);
if (cp_lexer_next_token_is (parser->lexer, CPP_EOF))
{
cp_lexer_destroy (parser->lexer);
parser->lexer = NULL;
if (parser->implicit_extern_c)
{
pop_lang_context ();
parser->implicit_extern_c = false;
}
finish_translation_unit ();
success = true;
break;
}
else
{
cp_parser_error (parser, "expected declaration");
success = false;
break;
}
}
gcc_assert (obstack_next_free (&declarator_obstack)
== declarator_obstack_base);
return success;
}
static tree
cp_parser_primary_expression (cp_parser *parser,
bool cast_p,
cp_id_kind *idk,
tree *qualifying_class)
{
cp_token *token;
int atsignhack = 0;
*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_NUMBER:
token = cp_lexer_consume_token (parser->lexer);
if (TREE_CODE (token->value) == REAL_CST
&& parser->integral_constant_expression_p
&& pedantic)
{
if (cast_p)
{
cp_token *next_token;
next_token = cp_lexer_peek_token (parser->lexer);
if (
next_token->type != CPP_COMMA
&& next_token->type != CPP_CLOSE_BRACE
&& next_token->type != CPP_SEMICOLON
&& next_token->type != CPP_CLOSE_PAREN
&& next_token->type != CPP_CLOSE_SQUARE)
cast_p = false;
}
if (!cast_p)
cp_parser_non_integral_constant_expression
(parser, "floating-point literal");
}
return token->value;
case CPP_STRING:
case CPP_WSTRING:
return cp_parser_string_literal (parser,
parser->translate_strings_p,
true);
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, expr, false);
expr = finish_stmt_expr (expr, false);
}
else
{
expr = cp_parser_expression (parser, cast_p);
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,
false);
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:
return cp_parser_builtin_offsetof (parser);
case RID_AT_ENCODE:
case RID_AT_PROTOCOL:
case RID_AT_SELECTOR:
return cp_parser_objc_expression (parser);
default:
cp_parser_error (parser, "expected primary-expression");
return error_mark_node;
}
case CPP_ATSIGN:
cp_lexer_consume_token (parser->lexer);
atsignhack = 1;
token = cp_lexer_peek_token (parser->lexer);
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 (atsignhack && id_expression != error_mark_node)
id_expression = prepend_char_identifier (id_expression, '@');
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
{
bool ambiguous_p;
decl = cp_parser_lookup_name (parser, id_expression,
none_type,
false,
false,
true,
&ambiguous_p);
if (ambiguous_p)
return error_mark_node;
decl = objc_lookup_ivar (decl, 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 %qD 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:
if (inside_iasm_block)
{
if (token->type == CPP_OPEN_SQUARE)
{
tree expr;
cp_lexer_consume_token (parser->lexer);
expr = cp_parser_iasm_operand (parser);
cp_parser_require (parser, CPP_CLOSE_SQUARE, "`]'");
return iasm_build_bracket (expr, NULL_TREE);
}
}
if (c_dialect_objc ()
&& (token->type == CPP_OPEN_SQUARE || token->type == CPP_OBJC_STRING))
return cp_parser_objc_expression (parser);
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,
declarator_p)
!= 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;
bool done;
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);
}
done = false;
type_decl = NULL_TREE;
if (scope)
{
cp_parser_parse_tentatively (parser);
type_decl = cp_parser_class_name (parser,
false,
false,
none_type,
false,
false,
declarator_p);
if (cp_parser_parse_definitely (parser))
done = true;
}
if (!done && 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,
none_type,
false,
false,
declarator_p);
if (cp_parser_parse_definitely (parser))
done = true;
}
else if (!done && 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,
none_type,
false,
false,
declarator_p);
if (cp_parser_parse_definitely (parser))
done = true;
}
if (!done)
{
parser->scope = NULL_TREE;
parser->object_scope = NULL_TREE;
parser->qualifying_scope = NULL_TREE;
type_decl
= cp_parser_class_name (parser,
false,
false,
none_type,
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)
&& !cp_parser_uncommitted_to_tentative_parse_p (parser))
error ("typedef-name %qD used as destructor declarator",
type_decl);
return build_nt (BIT_NOT_EXPR, TREE_TYPE (type_decl));
}
case CPP_NUMBER:
{
if (flag_iasm_blocks && inside_iasm_block
&& TREE_CODE (token->value) == INTEGER_CST)
{
char buf[60];
sprintf (buf, HOST_WIDE_INT_PRINT_UNSIGNED, tree_low_cst (token->value, 0));
cp_lexer_consume_token (parser->lexer);
return get_identifier (buf);
}
goto bad;
}
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:
bad:
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;
cp_token_position start = 0;
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_uncommitted_to_tentative_parse_p (parser))
start = cp_lexer_token_position (parser->lexer, false);
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;
if (is_declaration
&& !typename_keyword_p
&& parser->scope
&& TREE_CODE (parser->scope) == TYPENAME_TYPE)
parser->scope = resolve_typename_type (parser->scope,
false);
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 ("%qD 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)
{
cp_token *token = cp_lexer_token_at (parser->lexer, 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, start);
}
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 ? class_type : none_type,
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, bool cast_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, true);
cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
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;
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:
gcc_unreachable ();
}
}
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, false);
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;
tree scope;
cp_lexer_consume_token (parser->lexer);
cp_parser_global_scope_opt (parser,
false);
scope = 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 (scope == error_mark_node)
return error_mark_node;
else if (TREE_CODE (id) == TYPE_DECL
&& !dependent_type_p (parser->scope))
type = TREE_TYPE (id);
else
type = make_typename_type (parser->scope, id,
typename_type,
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,
NULL,
CP_PARSER_FLAGS_NONE);
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 && TREE_CODE (type) != VECTOR_TYPE)
pedwarn ("ISO C++ forbids compound-literals");
postfix_expression
= finish_compound_literal (type, initializer_list);
break;
}
}
postfix_expression = cp_parser_primary_expression (parser,
cast_p,
&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:
postfix_expression
= cp_parser_postfix_open_square_expression (parser,
postfix_expression,
false);
idk = CP_ID_KIND_NONE;
break;
case CPP_OPEN_PAREN:
{
bool koenig_p;
bool is_builtin_constant_p;
bool saved_integral_constant_expression_p = false;
bool saved_non_integral_constant_expression_p = false;
tree args;
is_builtin_constant_p
= DECL_IS_BUILTIN_CONSTANT_P (postfix_expression);
if (is_builtin_constant_p)
{
saved_integral_constant_expression_p
= parser->integral_constant_expression_p;
saved_non_integral_constant_expression_p
= parser->non_integral_constant_expression_p;
parser->integral_constant_expression_p = false;
}
args = (cp_parser_parenthesized_expression_list
(parser, false,
false,
NULL));
if (is_builtin_constant_p)
{
parser->integral_constant_expression_p
= saved_integral_constant_expression_p;
parser->non_integral_constant_expression_p
= saved_non_integral_constant_expression_p;
}
if (args == error_mark_node)
{
postfix_expression = error_mark_node;
break;
}
if (! builtin_valid_in_constant_expr_p (postfix_expression)
&& cp_parser_non_integral_constant_expression (parser,
"a function call"))
{
postfix_expression = error_mark_node;
break;
}
koenig_p = false;
if (idk == CP_ID_KIND_UNQUALIFIED)
{
if (TREE_CODE (postfix_expression) == IDENTIFIER_NODE)
{
if (args)
{
koenig_p = true;
postfix_expression
= perform_koenig_lookup (postfix_expression, args);
}
else
postfix_expression
= unqualified_fn_lookup_error (postfix_expression);
}
else if (args && is_overloaded_fn (postfix_expression))
{
tree fn = get_first_fn (postfix_expression);
if (TREE_CODE (fn) == TEMPLATE_ID_EXPR)
fn = OVL_CURRENT (TREE_OPERAND (fn, 0));
if (!DECL_FUNCTION_MEMBER_P (fn))
{
koenig_p = true;
postfix_expression
= perform_koenig_lookup (postfix_expression, args);
}
}
}
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:
cp_lexer_consume_token (parser->lexer);
postfix_expression
= cp_parser_postfix_dot_deref_expression (parser, token->type,
postfix_expression,
false, &idk);
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;
}
}
gcc_unreachable ();
return error_mark_node;
}
static tree
cp_parser_postfix_open_square_expression (cp_parser *parser,
tree postfix_expression,
bool for_offsetof)
{
tree index;
cp_lexer_consume_token (parser->lexer);
if (for_offsetof)
index = cp_parser_constant_expression (parser, false, NULL);
else
index = cp_parser_expression (parser, false);
cp_parser_require (parser, CPP_CLOSE_SQUARE, "`]'");
postfix_expression = grok_array_decl (postfix_expression, index);
if (!for_offsetof
&& (cp_parser_non_integral_constant_expression
(parser, "an array reference")))
postfix_expression = error_mark_node;
return postfix_expression;
}
static tree
cp_parser_postfix_dot_deref_expression (cp_parser *parser,
enum cpp_ttype token_type,
tree postfix_expression,
bool for_offsetof, cp_id_kind *idk)
{
tree name;
bool dependent_p;
bool template_p;
bool pseudo_destructor_p;
tree scope = NULL_TREE;
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;
}
pseudo_destructor_p = false;
if (scope && SCALAR_TYPE_P (scope))
{
tree s;
tree type;
cp_parser_parse_tentatively (parser);
s = NULL_TREE;
cp_parser_pseudo_destructor_name (parser, &s, &type);
if (cp_parser_parse_definitely (parser))
{
pseudo_destructor_p = true;
postfix_expression
= finish_pseudo_destructor_expr (postfix_expression,
s, TREE_TYPE (type));
}
}
if (!pseudo_destructor_p)
{
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 (TREE_CODE (name) == TYPE_DECL)
{
error ("invalid use of %qD", name);
postfix_expression = error_mark_node;
}
else
{
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);
}
}
parser->context->object_type = NULL_TREE;
if (!for_offsetof
&& (cp_parser_non_integral_constant_expression
(parser, token_type == CPP_DEREF ? "'->'" : "`.'")))
postfix_expression = error_mark_node;
return postfix_expression;
}
static tree
cp_parser_parenthesized_expression_list (cp_parser* parser,
bool is_attribute_list,
bool cast_p,
bool *non_constant_p)
{
tree expression_list = NULL_TREE;
bool fold_expr_p = is_attribute_list;
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, cast_p);
if (fold_expr_p)
expr = fold_non_dependent_expr (expr);
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;
*type = error_mark_node;
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)
return;
if (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");
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, bool cast_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_SIZEOF:
if (inside_iasm_block)
break;
case RID_ALIGNOF:
{
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 (inside_iasm_block && unary_operator == INDIRECT_REF)
{
cp_token *token = cp_lexer_peek_nth_token (parser->lexer, 2);
if (token->type == CPP_PLUS || token->type == CPP_MINUS)
unary_operator = ERROR_MARK;
}
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,
false);
switch (unary_operator)
{
case INDIRECT_REF:
non_constant_p = "`*'";
expression = build_x_indirect_ref (cast_expression, "unary *");
break;
case ADDR_EXPR:
non_constant_p = "`&'";
case BIT_NOT_EXPR:
if (inside_iasm_block
&& unary_operator == ADDR_EXPR
&& TREE_CODE (cast_expression) == LABEL_DECL)
{
expression = finish_label_address_expr (DECL_NAME (cast_expression));
break;
}
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:
if (inside_iasm_block && TREE_TYPE (cast_expression) == 0)
{
expression = build1 (unary_operator, NULL_TREE, cast_expression);
break;
}
expression = finish_unary_op_expr (unary_operator, cast_expression);
break;
default:
gcc_unreachable ();
}
if (non_constant_p
&& cp_parser_non_integral_constant_expression (parser,
non_constant_p))
expression = error_mark_node;
return expression;
}
if (inside_iasm_block)
return cp_parser_iasm_postfix_expression (parser, address_p);
return cp_parser_postfix_expression (parser, address_p, cast_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;
case CPP_NAME:
if (iasm_state >= iasm_decls
&& flag_ms_asms
&& strcasecmp (IDENTIFIER_POINTER (token->value), "offset") == 0)
return ADDR_EXPR;
default:
return ERROR_MARK;
}
}
static tree
cp_parser_new_expression (cp_parser* parser)
{
bool global_scope_p;
tree placement;
tree type;
tree initializer;
tree nelts;
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);
}
nelts = NULL_TREE;
}
else
type = cp_parser_new_type_id (parser, &nelts);
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, nelts, 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, false,
NULL));
return expression_list;
}
static tree
cp_parser_new_type_id (cp_parser* parser, tree *nelts)
{
cp_decl_specifier_seq type_specifier_seq;
cp_declarator *new_declarator;
cp_declarator *declarator;
cp_declarator *outer_declarator;
const char *saved_message;
tree type;
saved_message = parser->type_definition_forbidden_message;
parser->type_definition_forbidden_message
= "types may not be defined in a new-type-id";
cp_parser_type_specifier_seq (parser, false,
&type_specifier_seq);
parser->type_definition_forbidden_message = saved_message;
new_declarator = cp_parser_new_declarator_opt (parser);
*nelts = NULL_TREE;
declarator = new_declarator;
outer_declarator = NULL;
while (declarator && (declarator->kind == cdk_pointer
|| declarator->kind == cdk_ptrmem))
{
outer_declarator = declarator;
declarator = declarator->declarator;
}
while (declarator
&& declarator->kind == cdk_array
&& declarator->declarator
&& declarator->declarator->kind == cdk_array)
{
outer_declarator = declarator;
declarator = declarator->declarator;
}
if (declarator && declarator->kind == cdk_array)
{
*nelts = declarator->u.array.bounds;
if (*nelts == error_mark_node)
*nelts = integer_one_node;
if (outer_declarator)
outer_declarator->declarator = declarator->declarator;
else
new_declarator = NULL;
}
type = groktypename (&type_specifier_seq, new_declarator);
if (TREE_CODE (type) == ARRAY_TYPE && *nelts == NULL_TREE)
{
*nelts = array_type_nelts_top (type);
type = TREE_TYPE (type);
}
return type;
}
static cp_declarator *
cp_parser_new_declarator_opt (cp_parser* parser)
{
enum tree_code code;
tree type;
cp_cv_quals cv_quals;
cp_parser_parse_tentatively (parser);
code = cp_parser_ptr_operator (parser, &type, &cv_quals);
if (cp_parser_parse_definitely (parser))
{
cp_declarator *declarator;
declarator = cp_parser_new_declarator_opt (parser);
if (type)
declarator = make_ptrmem_declarator (cv_quals, type, declarator);
else if (code == INDIRECT_REF)
declarator = make_pointer_declarator (cv_quals, declarator);
else
declarator = make_reference_declarator (cv_quals, declarator);
return declarator;
}
if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_SQUARE))
return cp_parser_direct_new_declarator (parser);
return NULL;
}
static cp_declarator *
cp_parser_direct_new_declarator (cp_parser* parser)
{
cp_declarator *declarator = NULL;
while (true)
{
tree expression;
cp_parser_require (parser, CPP_OPEN_SQUARE, "`['");
if (!declarator)
{
expression = cp_parser_expression (parser, false);
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 = make_array_declarator (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, 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, bool cast_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_cast_expression (parser,
false,
true);
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 (c_dialect_objc() && flag_objc_gc)
? objc_build_weak_reference_tree (expr) : expr;
}
}
if (c_dialect_objc() && flag_objc_gc)
return objc_build_weak_reference_tree (
cp_parser_unary_expression (parser, address_p, cast_p));
else
return cp_parser_unary_expression (parser, address_p, cast_p);
}
#define TOKEN_PRECEDENCE(token) \
((token->type == CPP_GREATER && !parser->greater_than_is_operator_p) \
? PREC_NOT_OPERATOR \
: binops_by_token[token->type].prec)
static tree
cp_parser_binary_expression (cp_parser* parser, bool cast_p)
{
cp_parser_expression_stack stack;
cp_parser_expression_stack_entry *sp = &stack[0];
tree lhs, rhs;
cp_token *token;
enum tree_code tree_type;
enum cp_parser_prec prec = PREC_NOT_OPERATOR, new_prec, lookahead_prec;
bool overloaded_p;
lhs = cp_parser_cast_expression (parser, false, cast_p);
for (;;)
{
token = cp_lexer_peek_token (parser->lexer);
if (token->type == CPP_MIN || token->type == CPP_MAX)
cp_parser_warn_min_max ();
new_prec = TOKEN_PRECEDENCE (token);
if (flag_iasm_blocks && inside_iasm_block)
{
if ((token->flags & BOL) != 0)
new_prec = PREC_NOT_OPERATOR;
}
if (new_prec <= prec)
{
if (sp == stack)
break;
else
goto pop;
}
get_rhs:
tree_type = binops_by_token[token->type].tree_type;
cp_lexer_consume_token (parser->lexer);
rhs = cp_parser_simple_cast_expression (parser);
token = cp_lexer_peek_token (parser->lexer);
lookahead_prec = TOKEN_PRECEDENCE (token);
if (flag_iasm_blocks && inside_iasm_block)
{
if ((token->flags & BOL) != 0)
lookahead_prec = PREC_NOT_OPERATOR;
}
if (lookahead_prec > new_prec)
{
sp->prec = prec;
sp->tree_type = tree_type;
sp->lhs = lhs;
sp++;
lhs = rhs;
prec = new_prec;
new_prec = lookahead_prec;
goto get_rhs;
pop:
--sp;
prec = sp->prec;
tree_type = sp->tree_type;
rhs = lhs;
lhs = sp->lhs;
}
if (inside_iasm_block && TREE_CODE (rhs) == COMPOUND_EXPR)
{
gcc_assert (TREE_CODE (TREE_OPERAND (rhs, 1)) == IDENTIFIER_NODE);
lhs = build_x_binary_op (tree_type, lhs, TREE_OPERAND (rhs, 0), &overloaded_p);
lhs = iasm_build_register_offset (lhs, TREE_OPERAND (rhs, 1));
return lhs;
}
if (inside_iasm_block)
{
if (TREE_CODE (rhs) == IDENTIFIER_NODE
|| TREE_CODE (lhs) == IDENTIFIER_NODE
|| TREE_TYPE (rhs) == NULL_TREE
|| TREE_TYPE (lhs) == NULL_TREE)
{
lhs = build2 (tree_type, NULL_TREE, lhs, rhs);
continue;
}
}
overloaded_p = false;
lhs = build_x_binary_op (tree_type, lhs, rhs, &overloaded_p);
if (overloaded_p
&& (cp_parser_non_integral_constant_expression
(parser, "calls to overloaded operators")))
return error_mark_node;
}
return lhs;
}
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, false);
cp_parser_require (parser, CPP_COLON, "`:'");
assignment_expr = cp_parser_assignment_expression (parser, false);
return build_x_conditional_expr (logical_or_expr,
expr,
assignment_expr);
}
static tree
cp_parser_assignment_expression (cp_parser* parser, bool cast_p)
{
tree expr;
if (cp_lexer_next_token_is_keyword (parser->lexer, RID_THROW))
expr = cp_parser_throw_expression (parser);
else
{
expr = cp_parser_binary_expression (parser, cast_p);
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, cast_p);
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;
cp_parser_warn_min_max ();
break;
case CPP_MAX_EQ:
op = MAX_EXPR;
cp_parser_warn_min_max ();
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, bool cast_p)
{
tree expression = NULL_TREE;
while (true)
{
tree assignment_expression;
assignment_expression
= cp_parser_assignment_expression (parser, cast_p);
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, false);
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;
else if (parser->non_integral_constant_expression_p)
expression = error_mark_node;
parser->non_integral_constant_expression_p
= saved_non_integral_constant_expression_p;
return expression;
}
static tree
cp_parser_builtin_offsetof (cp_parser *parser)
{
int save_ice_p, save_non_ice_p;
tree type, expr;
cp_id_kind dummy;
save_ice_p = parser->integral_constant_expression_p;
save_non_ice_p = parser->non_integral_constant_expression_p;
cp_lexer_consume_token (parser->lexer);
cp_parser_require (parser, CPP_OPEN_PAREN, "`('");
type = cp_parser_type_id (parser);
cp_parser_require (parser, CPP_COMMA, "`,'");
expr = build_static_cast (build_pointer_type (type), null_pointer_node);
expr = cp_parser_postfix_dot_deref_expression (parser, CPP_DEREF, expr,
true, &dummy);
while (true)
{
cp_token *token = cp_lexer_peek_token (parser->lexer);
switch (token->type)
{
case CPP_OPEN_SQUARE:
expr = cp_parser_postfix_open_square_expression (parser, expr, true);
break;
case CPP_DOT:
cp_lexer_consume_token (parser->lexer);
expr = cp_parser_postfix_dot_deref_expression (parser, CPP_DOT, expr,
true, &dummy);
break;
case CPP_CLOSE_PAREN:
cp_lexer_consume_token (parser->lexer);
goto success;
default:
cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
cp_parser_skip_to_closing_parenthesis (parser, true, false, true);
expr = error_mark_node;
goto failure;
}
}
success:
if (processing_template_decl)
expr = build1 (OFFSETOF_EXPR, size_type_node, expr);
else
expr = fold_offsetof (expr);
failure:
parser->integral_constant_expression_p = save_ice_p;
parser->non_integral_constant_expression_p = save_non_ice_p;
return expr;
}
static void
cp_parser_statement (cp_parser* parser, tree in_statement_expr)
{
tree statement;
cp_token *token;
location_t statement_location;
statement = NULL_TREE;
token = cp_lexer_peek_token (parser->lexer);
statement_location = 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);
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_AT_TRY:
case RID_AT_CATCH:
case RID_AT_FINALLY:
case RID_AT_SYNCHRONIZED:
case RID_AT_THROW:
statement = cp_parser_objc_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);
}
else if (token->type == CPP_OPEN_BRACE)
statement = cp_parser_compound_statement (parser, NULL, false);
else if (token->type == CPP_PRAGMA)
{
cp_lexer_handle_pragma (parser->lexer);
return;
}
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);
}
if (statement && STATEMENT_CODE_P (TREE_CODE (statement)))
SET_EXPR_LOCATION (statement, statement_location);
}
static tree
cp_parser_labeled_statement (cp_parser* parser, tree in_statement_expr)
{
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 %qE 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);
return statement;
}
static tree
cp_parser_expression_statement (cp_parser* parser, tree in_statement_expr)
{
tree statement = NULL_TREE;
if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON))
statement = cp_parser_expression (parser, false);
cp_parser_consume_semicolon_at_end_of_statement (parser);
if (in_statement_expr
&& cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_BRACE))
statement = finish_stmt_expr_expr (statement, in_statement_expr);
else if (statement)
statement = finish_expr_stmt (statement);
else
finish_stmt ();
return statement;
}
static tree
cp_parser_compound_statement (cp_parser *parser, tree in_statement_expr,
bool in_try)
{
tree compound_stmt;
cp_parser_require (parser, CPP_OPEN_BRACE, "`{'");
compound_stmt = begin_compound_stmt (in_try ? BCS_TRY_BLOCK : 0);
if (iasm_state >= iasm_decls)
{
cp_token *token = cp_lexer_peek_token (parser->lexer);
iasm_in_decl = 1;
if (token->value && IASM_SEE_OPCODE (TYPESPEC, token->value) == IDENTIFIER)
{
token->keyword = RID_MAX;
token->type = CPP_NAME;
}
cp_parser_iasm_declaration_seq_opt (parser);
iasm_in_decl = 0;
iasm_state = iasm_asm;
inside_iasm_block = true;
iasm_kill_regs = true;
iasm_clear_labels ();
cp_parser_iasm_line_seq_opt (parser);
iasm_state = iasm_none;
iasm_end_block ();
}
else
cp_parser_statement_seq_opt (parser, in_statement_expr);
finish_compound_stmt (compound_stmt);
cp_parser_require (parser, CPP_CLOSE_BRACE, "`}'");
return compound_stmt;
}
static bool
cp_lexer_iasm_bol (cp_lexer* lexer)
{
cp_token *token = lexer->next_token;
return (token->flags & BOL) != 0;
}
static void
cp_parser_statement_seq_opt (cp_parser* parser, tree in_statement_expr)
{
while (true)
{
cp_token *token = cp_lexer_peek_token (parser->lexer);
if (token->type == CPP_CLOSE_BRACE || token->type == CPP_EOF
|| (token->type == CPP_KEYWORD
&& (token->keyword == RID_ELSE
|| token->keyword == RID_AT_END)))
break;
cp_parser_statement (parser, in_statement_expr);
if (flag_iasm_blocks
&& iasm_state >= iasm_decls
&& (cp_lexer_iasm_bol (parser->lexer)
|| cp_lexer_next_token_is (parser->lexer, CPP_NAME)))
break;
}
}
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)
{
finish_if_stmt_cond (condition, statement);
cp_parser_implicitly_scoped_statement (parser);
finish_then_clause (statement);
if (cp_lexer_next_token_is_keyword (parser->lexer,
RID_ELSE))
{
cp_lexer_consume_token (parser->lexer);
begin_else_clause (statement);
cp_parser_implicitly_scoped_statement (parser);
finish_else_clause (statement);
}
finish_if_stmt (statement);
}
else
{
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;
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)
{
cp_decl_specifier_seq 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";
cp_parser_type_specifier_seq (parser, true,
&type_specifiers);
parser->type_definition_forbidden_message = saved_message;
if (!cp_parser_error_occurred (parser))
{
tree decl;
tree asm_specification;
tree attributes;
cp_declarator *declarator;
tree initializer = NULL_TREE;
declarator = cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED,
NULL,
NULL,
false);
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))
{
tree pushed_scope;
decl = start_decl (declarator, &type_specifiers,
true,
attributes, NULL_TREE,
&pushed_scope);
initializer = cp_parser_assignment_expression (parser,
false);
cp_finish_decl (decl,
initializer,
asm_specification,
LOOKUP_ONLYCONVERTING);
if (pushed_scope)
pop_scope (pushed_scope);
return convert_from_reference (decl);
}
}
else
cp_parser_abort_tentative_parse (parser);
return cp_parser_expression (parser, false);
}
static bool
cp_parser_parse_foreach_stmt (cp_parser *parser)
{
int decl_spec_declares_class_or_enum;
bool is_cv_qualifier;
tree type_spec;
cp_decl_specifier_seq decl_specs;
tree node;
cp_token *token;
bool is_legit_foreach = false;
cp_declarator *declarator;
token = cp_lexer_peek_token (parser->lexer);
if (cp_parser_token_is_class_key (token) || token->keyword == RID_ENUM)
return false;
cp_parser_parse_tentatively (parser);
clear_decl_specs (&decl_specs);
type_spec
= cp_parser_type_specifier (parser, CP_PARSER_FLAGS_OPTIONAL,
&decl_specs,
true,
&decl_spec_declares_class_or_enum,
&is_cv_qualifier);
declarator
= cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED,
NULL,
NULL,
false);
if (declarator == cp_error_declarator)
{
cp_parser_abort_tentative_parse (parser);
return false;
}
token = cp_lexer_peek_token (parser->lexer);
node = token->value;
if (node && TREE_CODE (node) == IDENTIFIER_NODE
&& node == ridpointers [(int) RID_IN])
{
enum cpp_ttype nt = cp_lexer_peek_nth_token (parser->lexer, 2)->type;
switch (nt)
{
case CPP_NAME:
case CPP_OPEN_PAREN:
case CPP_MULT:
case CPP_PLUS: case CPP_PLUS_PLUS:
case CPP_MINUS: case CPP_MINUS_MINUS:
case CPP_OPEN_SQUARE:
is_legit_foreach = true;
default:
break;
}
}
if (is_legit_foreach)
{
tree pushed_scope = NULL;
tree decl;
if (type_spec)
{
cp_parser_commit_to_tentative_parse (parser);
decl = start_decl (declarator, &decl_specs,
false ,
NULL_TREE ,
NULL_TREE ,
&pushed_scope);
if (!decl || decl == error_mark_node)
{
error ("selector is undeclared");
is_legit_foreach = false;
}
else
cp_finish_decl (decl,
NULL_TREE ,
NULL_TREE ,
0 );
}
else {
tree statement;
cp_parser_abort_tentative_parse (parser);
statement = cp_parser_expression (parser, false);
add_stmt (statement);
}
cp_lexer_consume_token (parser->lexer);
}
else
cp_parser_abort_tentative_parse (parser);
return is_legit_foreach;
}
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, false);
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, "`('");
if (c_dialect_objc ()
&& cp_parser_parse_foreach_stmt (parser))
{
objc_foreach_stmt (parser, statement);
break;
}
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, false);
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, false);
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, false));
}
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)
{
void *p;
p = obstack_alloc (&declarator_obstack, 0);
cp_parser_block_declaration (parser, true);
obstack_free (&declarator_obstack, p);
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 (0);
cp_parser_statement (parser, false);
finish_compound_stmt (statement);
}
else
statement = cp_parser_compound_statement (parser, NULL, 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))
cp_parser_statement (parser, false);
else
{
cp_parser_require (parser, CPP_OPEN_BRACE, "`{'");
cp_parser_statement_seq_opt (parser, false);
cp_parser_require (parser, CPP_CLOSE_BRACE, "`}'");
}
}
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)
{
cp_lexer_consume_token (parser->lexer);
if (pedantic && !in_system_header)
pedwarn ("extra %<;%>");
continue;
}
if (!parser->implicit_extern_c && token->implicit_extern_c)
{
push_lang_context (lang_name_c);
parser->implicit_extern_c = true;
}
else if (parser->implicit_extern_c && !token->implicit_extern_c)
{
pop_lang_context ();
parser->implicit_extern_c = false;
}
if (token->type == CPP_PRAGMA)
{
cp_lexer_handle_pragma (parser->lexer);
continue;
}
cp_parser_declaration (parser);
}
}
static bool
objc_attr_follwed_by_at_keyword (cp_parser* parser)
{
cp_token token1;
tree attributes = NULL_TREE;
cp_lexer_save_tokens (parser->lexer);
cp_parser_objc_maybe_attributes (parser, &attributes);
gcc_assert (attributes);
token1 = *cp_lexer_peek_token (parser->lexer);
cp_lexer_rollback_tokens (parser->lexer);
return OBJC_IS_AT_KEYWORD (token1.keyword);
}
static void
cp_parser_declaration (cp_parser* parser)
{
cp_token token1;
cp_token token2;
int saved_pedantic;
void *p;
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.type != CPP_EOF)
token2 = *cp_lexer_peek_nth_token (parser->lexer, 2);
p = obstack_alloc (&declarator_obstack, 0);
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 if (c_dialect_objc ()
&& (OBJC_IS_AT_KEYWORD (token1.keyword)
|| (token1.keyword == RID_ATTRIBUTE
&& objc_attr_follwed_by_at_keyword (parser))))
cp_parser_objc_declaration (parser);
else
cp_parser_block_declaration (parser, false);
obstack_free (&declarator_obstack, p);
}
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, statement_p);
}
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)
{
cp_decl_specifier_seq decl_specifiers;
int declares_class_or_enum;
bool saw_declarator;
push_deferring_access_checks (dk_deferred);
cp_parser_decl_specifier_seq (parser,
CP_PARSER_FLAGS_OPTIONAL,
&decl_specifiers,
&declares_class_or_enum);
stop_deferring_access_checks ();
if (!function_definition_allowed_p
&& !decl_specifiers.any_specifiers_p)
{
if (flag_iasm_blocks && iasm_state >= iasm_decls)
return;
cp_parser_error (parser, "expected declaration");
goto done;
}
if (!decl_specifiers.type
&& cp_parser_parse_and_diagnose_invalid_type_name (parser))
{
cp_parser_commit_to_tentative_parse (parser);
goto done;
}
if (decl_specifiers.any_specifiers_p
&& cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_PAREN))
cp_parser_commit_to_tentative_parse (parser);
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,
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
{
if (decl != error_mark_node
|| cp_parser_uncommitted_to_tentative_parse_p (parser))
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, "`;'");
if (flag_iasm_blocks)
iasm_in_decl = 0;
done:
pop_deferring_access_checks ();
}
static void
cp_parser_decl_specifier_seq (cp_parser* parser,
cp_parser_flags flags,
cp_decl_specifier_seq *decl_specs,
int* declares_class_or_enum)
{
bool constructor_possible_p = !parser->in_declarator_p;
clear_decl_specs (decl_specs);
*declares_class_or_enum = 0;
while (true)
{
bool constructor_p;
bool found_decl_spec;
cp_token *token;
token = cp_lexer_peek_token (parser->lexer);
if (token->keyword == RID_ATTRIBUTE)
{
decl_specs->attributes
= chainon (decl_specs->attributes,
cp_parser_attributes_opt (parser));
continue;
}
found_decl_spec = true;
switch (token->keyword)
{
case RID_FRIEND:
if (decl_specs->specs[(int) ds_friend]++)
error ("duplicate %<friend%>");
cp_lexer_consume_token (parser->lexer);
break;
case RID_INLINE:
case RID_VIRTUAL:
case RID_EXPLICIT:
cp_parser_function_specifier_opt (parser, decl_specs);
break;
case RID_TYPEDEF:
++decl_specs->specs[(int) ds_typedef];
cp_lexer_consume_token (parser->lexer);
constructor_possible_p = false;
cp_parser_commit_to_tentative_parse (parser);
break;
case RID_AUTO:
cp_lexer_consume_token (parser->lexer);
cp_parser_set_storage_class (decl_specs, sc_auto);
break;
case RID_REGISTER:
cp_lexer_consume_token (parser->lexer);
cp_parser_set_storage_class (decl_specs, sc_register);
break;
case RID_STATIC:
cp_lexer_consume_token (parser->lexer);
if (decl_specs->specs[(int) ds_thread])
{
error ("%<__thread%> before %<static%>");
decl_specs->specs[(int) ds_thread] = 0;
}
cp_parser_set_storage_class (decl_specs, sc_static);
break;
case RID_EXTERN:
cp_lexer_consume_token (parser->lexer);
if (decl_specs->specs[(int) ds_thread])
{
error ("%<__thread%> before %<extern%>");
decl_specs->specs[(int) ds_thread] = 0;
}
cp_parser_set_storage_class (decl_specs, sc_extern);
break;
case RID_MUTABLE:
cp_lexer_consume_token (parser->lexer);
cp_parser_set_storage_class (decl_specs, sc_mutable);
break;
case RID_THREAD:
cp_lexer_consume_token (parser->lexer);
++decl_specs->specs[(int) ds_thread];
break;
case RID_ASM:
cp_lexer_consume_token (parser->lexer);
++decl_specs->specs[(int) ds_iasm_asm];
break;
default:
found_decl_spec = false;
break;
}
constructor_p
= (!found_decl_spec
&& constructor_possible_p
&& (cp_parser_constructor_declarator_p
(parser, decl_specs->specs[(int) ds_friend] != 0)));
if (!found_decl_spec && !constructor_p)
{
int decl_spec_declares_class_or_enum;
bool is_cv_qualifier;
tree type_spec;
type_spec
= cp_parser_type_specifier (parser, flags,
decl_specs,
true,
&decl_spec_declares_class_or_enum,
&is_cv_qualifier);
*declares_class_or_enum |= decl_spec_declares_class_or_enum;
if (type_spec && !is_cv_qualifier)
flags |= CP_PARSER_FLAGS_NO_USER_DEFINED_TYPES;
if (type_spec)
{
constructor_possible_p = false;
found_decl_spec = true;
}
}
if (!found_decl_spec)
break;
decl_specs->any_specifiers_p = true;
flags |= CP_PARSER_FLAGS_OPTIONAL;
}
if (decl_specs->specs[(int) ds_friend] != 0
&& (*declares_class_or_enum & 2))
error ("class definition may not be declared a friend");
}
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:
case RID_ASM:
return cp_lexer_consume_token (parser->lexer)->value;
default:
return NULL_TREE;
}
}
static tree
cp_parser_function_specifier_opt (cp_parser* parser,
cp_decl_specifier_seq *decl_specs)
{
switch (cp_lexer_peek_token (parser->lexer)->keyword)
{
case RID_INLINE:
if (decl_specs)
++decl_specs->specs[(int) ds_inline];
break;
case RID_VIRTUAL:
if (decl_specs)
++decl_specs->specs[(int) ds_virtual];
break;
case RID_EXPLICIT:
if (decl_specs)
++decl_specs->specs[(int) ds_explicit];
break;
default:
return NULL_TREE;
}
return cp_lexer_consume_token (parser->lexer)->value;
}
static void
cp_parser_linkage_specification (cp_parser* parser)
{
tree linkage;
cp_parser_require_keyword (parser, RID_EXTERN, "`extern'");
linkage = cp_parser_string_literal (parser, false, false);
if (strlen (TREE_STRING_POINTER (linkage))
!= (size_t) (TREE_STRING_LENGTH (linkage) - 1))
{
cp_parser_error (parser, "invalid linkage-specification");
linkage = lang_name_cplusplus;
}
else
linkage = get_identifier (TREE_STRING_POINTER (linkage));
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;
tree pushed_scope = NULL_TREE;
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)
pushed_scope = push_scope (saved_scope);
type = cp_parser_conversion_type_id (parser);
if (pushed_scope)
pop_scope (pushed_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;
cp_decl_specifier_seq type_specifiers;
cp_declarator *declarator;
tree type_specified;
attributes = cp_parser_attributes_opt (parser);
cp_parser_type_specifier_seq (parser, false,
&type_specifiers);
if (type_specifiers.type == error_mark_node)
return error_mark_node;
declarator = cp_parser_conversion_declarator_opt (parser);
type_specified = grokdeclarator (declarator, &type_specifiers, TYPENAME,
0, &attributes);
if (attributes)
cplus_decl_attributes (&type_specified, attributes, 0);
return type_specified;
}
static cp_declarator *
cp_parser_conversion_declarator_opt (cp_parser* parser)
{
enum tree_code code;
tree class_type;
cp_cv_quals cv_quals;
cp_parser_parse_tentatively (parser);
code = cp_parser_ptr_operator (parser, &class_type, &cv_quals);
if (cp_parser_parse_definitely (parser))
{
cp_declarator *declarator;
declarator = cp_parser_conversion_declarator_opt (parser);
if (class_type)
declarator = make_ptrmem_declarator (cv_quals, class_type,
declarator);
else if (code == INDIRECT_REF)
declarator = make_pointer_declarator (cv_quals, declarator);
else
declarator = make_reference_declarator (cv_quals, declarator);
return declarator;
}
return NULL;
}
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,
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;
bool template_p = false;
tree id;
if (cp_lexer_next_token_is_keyword (parser->lexer, RID_TYPENAME))
{
error ("keyword %<typename%> not allowed in this context (a qualified "
"member initializer is implicitly a type)");
cp_lexer_consume_token (parser->lexer);
}
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 (nested_name_specifier_p)
template_p = cp_parser_optional_template_keyword (parser);
if (global_scope_p || nested_name_specifier_p)
return cp_parser_class_name (parser,
true,
template_p,
none_type,
true,
false,
true);
cp_parser_parse_tentatively (parser);
id = cp_parser_class_name (parser,
true,
false,
none_type,
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);
cp_parser_warn_min_max ();
break;
case CPP_MAX:
id = ansi_opname (MAX_EXPR);
cp_parser_warn_min_max ();
break;
case CPP_MIN_EQ:
id = ansi_assopname (MIN_EXPR);
cp_parser_warn_min_max ();
break;
case CPP_MAX_EQ:
id = ansi_assopname (MAX_EXPR);
cp_parser_warn_min_max ();
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;
bool is_non_type;
parameter = cp_parser_template_parameter (parser, &is_non_type);
if (parameter != error_mark_node)
parameter_list = process_template_parm (parameter_list,
parameter,
is_non_type);
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, bool *is_non_type)
{
cp_token *token;
cp_parameter_declarator *parameter_declarator;
tree parm;
*is_non_type = false;
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);
}
*is_non_type = true;
parameter_declarator
= cp_parser_parameter_declaration (parser, true,
NULL);
parm = grokdeclarator (parameter_declarator->declarator,
¶meter_declarator->decl_specifiers,
PARM, 0,
NULL);
if (parm == error_mark_node)
return error_mark_node;
return build_tree_list (parameter_declarator->default_argument, parm);
}
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);
if (identifier == error_mark_node)
identifier = NULL_TREE;
}
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,
none_type,
is_template,
false,
true,
NULL);
default_argument
= check_template_template_default_arg (default_argument);
}
else
default_argument = NULL_TREE;
parameter = build_tree_list (default_argument, parameter);
}
break;
default:
gcc_unreachable ();
break;
}
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;
cp_token_position start_of_id = 0;
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_uncommitted_to_tentative_parse_p (parser))
start_of_id = cp_lexer_token_position (parser->lexer, false);
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_token (parser->lexer);
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
{
gcc_assert ((DECL_FUNCTION_TEMPLATE_P (template)
|| TREE_CODE (template) == OVERLOAD
|| BASELINK_P (template)));
template_id = lookup_template_function (template, arguments);
}
access_check = get_deferred_access_checks ();
if (start_of_id)
{
cp_token *token = cp_lexer_token_at (parser->lexer, 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, start_of_id);
if (cp_parser_error_occurred (parser) && template_id != error_mark_node)
error ("parse error in template argument list");
}
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)
&& check_dependency_p
&& dependent_type_p (parser->scope)
&& !constructor_name_p (identifier, parser->scope))
{
cp_token_position start = 0;
error ("non-template %qD used as template", identifier);
inform ("use %<%T::template %D%> to indicate that it is a template",
parser->scope, identifier);
if (cp_parser_simulate_error (parser))
start = cp_lexer_token_position (parser->lexer, true);
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)
cp_lexer_purge_tokens_after (parser->lexer, start);
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,
none_type,
false,
false,
check_dependency_p,
NULL);
decl = maybe_get_template_decl_from_type_decl (decl);
if (TREE_CODE (decl) == TEMPLATE_DECL)
;
else
{
tree fn = NULL_TREE;
fns = BASELINK_P (decl) ? BASELINK_FUNCTIONS (decl) : decl;
if (TREE_CODE (fns) == OVERLOAD)
for (fn = fns; fn; fn = OVL_NEXT (fn))
if (TREE_CODE (OVL_CURRENT (fn)) == TEMPLATE_DECL)
break;
if (!fn)
{
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,
none_type,
template_p,
false,
true,
NULL);
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,
false,
&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,
false,
&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 (TREE_CODE (argument) == INDIRECT_REF)
{
gcc_assert (REFERENCE_REF_P (argument));
argument = TREE_OPERAND (argument, 0);
}
if (qualifying_class)
argument = finish_qualified_id_expr (qualifying_class,
argument,
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 if (TREE_CODE (argument) == TEMPLATE_PARM_INDEX)
;
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;
cp_decl_specifier_seq decl_specifiers;
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,
NULL);
}
cp_parser_require_keyword (parser, RID_TEMPLATE, "`template'");
begin_explicit_instantiation ();
push_deferring_access_checks (dk_no_check);
cp_parser_decl_specifier_seq (parser,
CP_PARSER_FLAGS_OPTIONAL,
&decl_specifiers,
&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
{
cp_declarator *declarator;
tree decl;
declarator
= cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED,
NULL,
NULL,
false);
if (declares_class_or_enum & 2)
cp_parser_check_for_definition_in_return_type (declarator,
decl_specifiers.type);
if (declarator != cp_error_declarator)
{
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,
cp_decl_specifier_seq *decl_specs,
bool is_declaration,
int* declares_class_or_enum,
bool* is_cv_qualifier)
{
tree type_spec = NULL_TREE;
cp_token *token;
enum rid keyword;
cp_decl_spec ds = ds_last;
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_ENUM:
if (cp_lexer_peek_nth_token (parser->lexer, 2)->type == CPP_OPEN_BRACE
|| (cp_lexer_peek_nth_token (parser->lexer, 2)->type == CPP_NAME
&& cp_lexer_peek_nth_token (parser->lexer, 3)->type
== CPP_OPEN_BRACE))
{
if (parser->num_template_parameter_lists)
{
error ("template declaration of %qs", "enum");
cp_parser_skip_to_end_of_block_or_statement (parser);
type_spec = error_mark_node;
}
else
type_spec = cp_parser_enum_specifier (parser);
if (declares_class_or_enum)
*declares_class_or_enum = 2;
if (decl_specs)
cp_parser_set_decl_spec_type (decl_specs,
type_spec,
true);
return type_spec;
}
else
goto elaborated_type_specifier;
case RID_CLASS:
case RID_STRUCT:
case RID_UNION:
cp_parser_parse_tentatively (parser);
type_spec = cp_parser_class_specifier (parser);
if (cp_parser_parse_definitely (parser))
{
if (declares_class_or_enum)
*declares_class_or_enum = 2;
if (decl_specs)
cp_parser_set_decl_spec_type (decl_specs,
type_spec,
true);
return type_spec;
}
elaborated_type_specifier:
if (declares_class_or_enum)
*declares_class_or_enum = 1;
case RID_TYPENAME:
type_spec
= (cp_parser_elaborated_type_specifier
(parser,
decl_specs && decl_specs->specs[(int) ds_friend],
is_declaration));
if (decl_specs)
cp_parser_set_decl_spec_type (decl_specs,
type_spec,
true);
return type_spec;
case RID_CONST:
ds = ds_const;
if (is_cv_qualifier)
*is_cv_qualifier = true;
break;
case RID_VOLATILE:
ds = ds_volatile;
if (is_cv_qualifier)
*is_cv_qualifier = true;
break;
case RID_RESTRICT:
ds = ds_restrict;
if (is_cv_qualifier)
*is_cv_qualifier = true;
break;
case RID_COMPLEX:
ds = ds_complex;
break;
default:
break;
}
if (ds != ds_last)
{
if (decl_specs)
{
++decl_specs->specs[(int)ds];
decl_specs->any_specifiers_p = true;
}
return cp_lexer_consume_token (parser->lexer)->value;
}
type_spec = cp_parser_simple_type_specifier (parser,
decl_specs,
flags);
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_decl_specifier_seq *decl_specs,
cp_parser_flags flags)
{
tree type = NULL_TREE;
cp_token *token;
token = cp_lexer_peek_token (parser->lexer);
switch (token->keyword)
{
case RID_CHAR:
if (decl_specs)
decl_specs->explicit_char_p = true;
type = char_type_node;
break;
case RID_WCHAR:
type = wchar_type_node;
break;
case RID_BOOL:
type = boolean_type_node;
break;
case RID_SHORT:
if (decl_specs)
++decl_specs->specs[(int) ds_short];
type = short_integer_type_node;
break;
case RID_INT:
if (decl_specs)
decl_specs->explicit_int_p = true;
type = integer_type_node;
break;
case RID_LONG:
if (decl_specs)
++decl_specs->specs[(int) ds_long];
type = long_integer_type_node;
break;
case RID_SIGNED:
if (decl_specs)
++decl_specs->specs[(int) ds_signed];
type = integer_type_node;
break;
case RID_UNSIGNED:
if (decl_specs)
++decl_specs->specs[(int) ds_unsigned];
type = unsigned_type_node;
break;
case RID_FLOAT:
type = float_type_node;
break;
case RID_DOUBLE:
type = double_type_node;
break;
case RID_VOID:
type = void_type_node;
break;
case RID_TYPEOF:
cp_lexer_consume_token (parser->lexer);
type = cp_parser_sizeof_operand (parser, RID_TYPEOF);
if (!TYPE_P (type))
type = finish_typeof (type);
if (decl_specs)
cp_parser_set_decl_spec_type (decl_specs, type,
true);
return type;
default:
break;
}
if (type)
{
tree id;
if (decl_specs
&& (token->keyword != RID_SIGNED
&& token->keyword != RID_UNSIGNED
&& token->keyword != RID_SHORT
&& token->keyword != RID_LONG))
cp_parser_set_decl_spec_type (decl_specs,
type,
false);
if (decl_specs)
decl_specs->any_specifiers_p = true;
id = cp_lexer_consume_token (parser->lexer)->value;
cp_parser_check_for_invalid_template_id (parser, type);
return TYPE_NAME (type);
}
if (!(flags & CP_PARSER_FLAGS_NO_USER_DEFINED_TYPES))
{
bool qualified_p;
bool global_p;
if (flags & CP_PARSER_FLAGS_OPTIONAL)
cp_parser_parse_tentatively (parser);
global_p
= (cp_parser_global_scope_opt (parser,
false)
!= NULL_TREE);
qualified_p
= (cp_parser_nested_name_specifier_opt (parser,
false,
true,
false,
false)
!= NULL_TREE);
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 (type
&& !global_p
&& !qualified_p
&& TREE_CODE (type) == TYPE_DECL
&& TREE_CODE (DECL_NAME (type)) == IDENTIFIER_NODE)
maybe_note_name_used_in_class (DECL_NAME (type), type);
if ((flags & CP_PARSER_FLAGS_OPTIONAL)
&& !cp_parser_parse_definitely (parser))
type = NULL_TREE;
if (type && decl_specs)
cp_parser_set_decl_spec_type (decl_specs, type,
true);
}
if (!type && !(flags & CP_PARSER_FLAGS_OPTIONAL))
{
cp_parser_error (parser, "expected type-name");
return error_mark_node;
}
if (type && type != error_mark_node)
{
if (c_dialect_objc () && !parser->scope
&& (objc_is_id (type) || objc_is_class_name (type)))
{
tree protos = cp_parser_objc_protocol_refs_opt (parser);
tree qual_type = objc_get_protocol_qualified_type (type, protos);
if (decl_specs)
decl_specs->type = qual_type;
return qual_type;
}
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,
none_type,
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
&& (objc_is_id (identifier) || objc_is_class_name (identifier)))
{
tree protos = cp_parser_objc_protocol_refs_opt (parser);
tree type = objc_get_protocol_qualified_type (identifier, protos);
if (type)
type_decl = TYPE_NAME (type);
}
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,
typename_type,
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
&& TREE_CODE (parser->scope) != NAMESPACE_DECL)
return cp_parser_make_typename_type (parser, parser->scope,
identifier);
if (parser->scope)
{
tree decl;
decl = cp_parser_lookup_name (parser, identifier,
tag_type,
false,
false,
true,
NULL);
decl = (cp_parser_maybe_treat_template_as_class
(decl, is_friend
&& parser->num_template_parameter_lists));
if (TREE_CODE (decl) != TYPE_DECL)
{
cp_parser_diagnose_invalid_type_name (parser,
parser->scope,
identifier);
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
{
tag_scope ts;
if (is_friend)
ts = ts_within_enclosing_non_class;
else if (is_declaration
&& cp_lexer_next_token_is (parser->lexer,
CPP_SEMICOLON))
ts = ts_current;
else
ts = ts_global;
if (attributes)
warning ("type attributes are honored only at type definition");
type = xref_tag (tag_type, identifier, ts,
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)
{
tree identifier;
tree type;
cp_lexer_consume_token (parser->lexer);
if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
identifier = cp_parser_identifier (parser);
else
identifier = make_anon_name ();
cp_parser_check_type_definition (parser);
type = start_enum (identifier);
cp_lexer_consume_token (parser->lexer);
if (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_BRACE))
cp_parser_enumerator_list (parser, type);
cp_parser_require (parser, CPP_CLOSE_BRACE, "`}'");
if (cp_parser_allow_gnu_extensions_p (parser))
{
tree trailing_attr = cp_parser_attributes_opt (parser);
cplus_decl_attributes (&type,
trailing_attr,
(int) ATTR_FLAG_TYPE_IN_PLACE);
}
finish_enum (type);
return type;
}
static void
cp_parser_enumerator_list (cp_parser* parser, tree type)
{
while (true)
{
cp_parser_enumerator_definition (parser, type);
if (cp_lexer_next_token_is_not (parser->lexer, 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)
{
tree identifier;
tree value;
identifier = cp_parser_identifier (parser);
if (identifier == error_mark_node)
return;
if (cp_lexer_next_token_is (parser->lexer, 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,
none_type,
false,
true,
true,
NULL);
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 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
{
if (at_class_scope_p ())
{
decl = do_class_using_decl (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 (!at_namespace_scope_p ())
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, bool statement_p ATTRIBUTE_UNUSED)
{
tree string;
tree outputs = NULL_TREE;
tree inputs = NULL_TREE;
tree clobbers = NULL_TREE;
tree uses = NULL_TREE;
tree asm_stmt;
bool volatile_p = false;
bool extended_p = false;
cp_token *nextup;
if (flag_iasm_blocks)
{
nextup = cp_lexer_peek_nth_token (parser->lexer, 2);
if (statement_p
&& nextup->value
&& IASM_SEE_OPCODE (TYPESPEC, nextup->value) == IDENTIFIER)
{
nextup->keyword = RID_MAX;
nextup->type = CPP_NAME;
}
if (!((nextup->type == CPP_OPEN_PAREN)
|| (nextup->keyword == RID_VOLATILE
&& cp_lexer_peek_nth_token (parser->lexer, 3)->type == CPP_OPEN_PAREN)
|| (nextup->type == CPP_OPEN_BRACE)
|| (nextup->type == CPP_ATSIGN)
|| (nextup->keyword == RID_ASM)
|| (nextup->type == CPP_DOT)
|| (nextup->type == CPP_SEMICOLON)
|| (nextup->type == CPP_NAME
&& !iasm_typename_or_reserved (nextup->value))))
{
cp_parser_simple_declaration (parser, true);
return;
}
}
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);
}
if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE))
{
if (flag_iasm_blocks)
cp_parser_iasm_compound_statement (parser);
else
error ("asm blocks not enabled, use `-fasm-blocks'");
return;
}
if (cp_lexer_next_token_is (parser->lexer, CPP_DOT)
|| cp_lexer_next_token_is (parser->lexer, CPP_ATSIGN)
|| cp_lexer_next_token_is (parser->lexer, CPP_NAME)
|| cp_lexer_next_token_is_keyword (parser->lexer, RID_ASM)
|| cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON))
{
if (flag_iasm_blocks)
cp_parser_iasm_top_statement (parser);
else
error ("asm blocks not enabled, use `-fasm-blocks'");
return;
}
if (!cp_parser_require (parser, CPP_OPEN_PAREN, "`('"))
return;
string = cp_parser_string_literal (parser, false, false);
if (string == error_mark_node)
{
cp_parser_skip_to_closing_parenthesis (parser, true, false,
true);
return;
}
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))
inputs_p = true;
if (inputs_p
|| 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_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))
{
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, uses);
if (!extended_p)
{
tree temp = asm_stmt;
if (TREE_CODE (temp) == CLEANUP_POINT_EXPR)
temp = TREE_OPERAND (temp, 0);
ASM_INPUT_P (temp) = 1;
}
}
else
assemble_asm (string);
}
static tree
cp_parser_init_declarator (cp_parser* parser,
cp_decl_specifier_seq *decl_specifiers,
bool function_definition_allowed_p,
bool member_p,
int declares_class_or_enum,
bool* function_definition_p)
{
cp_token *token;
cp_declarator *declarator;
tree prefix_attributes;
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;
tree pushed_scope = NULL;
prefix_attributes = decl_specifiers->attributes;
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,
false);
stop_deferring_access_checks ();
if (declarator == cp_error_declarator)
return error_mark_node;
if (declares_class_or_enum & 2)
cp_parser_check_for_definition_in_return_type (declarator,
decl_specifiers->type);
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->any_specifiers_p && 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 initializer");
return error_mark_node;
}
cp_parser_commit_to_tentative_parse (parser);
if (decl_specifiers->any_specifiers_p
&& decl_specifiers->type == error_mark_node)
{
cp_parser_error (parser, "invalid type in declaration");
decl_specifiers->type = 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->storage_class = sc_extern;
have_extern_spec = false;
}
decl = start_decl (declarator, decl_specifiers,
is_initialized, attributes, prefix_attributes,
&pushed_scope);
}
else if (scope)
pushed_scope = 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 (member_p)
{
if (pushed_scope)
{
pop_scope (pushed_scope);
pushed_scope = false;
}
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 && decl != error_mark_node)
{
cp_finish_decl (decl,
initializer,
asm_specification,
((is_parenthesized_init || !is_initialized)
? 0 : LOOKUP_ONLYCONVERTING));
}
if (!friend_p && pushed_scope)
pop_scope (pushed_scope);
if (decl && TREE_CODE (decl) == VAR_DECL
&& is_initialized && !is_non_constant_init)
DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl) = true;
return decl;
}
static cp_declarator *
cp_parser_declarator (cp_parser* parser,
cp_parser_declarator_kind dcl_kind,
int* ctor_dtor_or_conv_p,
bool* parenthesized_p,
bool member_p)
{
cp_token *token;
cp_declarator *declarator;
enum tree_code code;
cp_cv_quals cv_quals;
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_quals);
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,
false);
if (dcl_kind != CP_PARSER_DECLARATOR_NAMED
&& !cp_parser_parse_definitely (parser))
declarator = NULL;
if (class_type)
declarator = make_ptrmem_declarator (cv_quals,
class_type,
declarator);
else if (code == INDIRECT_REF)
declarator = make_pointer_declarator (cv_quals, declarator);
else
declarator = make_reference_declarator (cv_quals, declarator);
}
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,
member_p);
}
if (attributes && declarator != cp_error_declarator)
declarator->attributes = attributes;
return declarator;
}
static cp_declarator *
cp_parser_direct_declarator (cp_parser* parser,
cp_parser_declarator_kind dcl_kind,
int* ctor_dtor_or_conv_p,
bool member_p)
{
cp_token *token;
cp_declarator *declarator = NULL;
tree scope = NULL_TREE;
bool saved_default_arg_ok_p = parser->default_arg_ok_p;
bool saved_in_declarator_p = parser->in_declarator_p;
bool first = true;
tree pushed_scope = NULL_TREE;
while (true)
{
token = cp_lexer_peek_token (parser->lexer);
if (token->type == CPP_OPEN_PAREN)
{
if (!first || dcl_kind != CP_PARSER_DECLARATOR_NAMED)
{
cp_parameter_declarator *params;
unsigned saved_num_template_parameter_lists;
if (!member_p)
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 (member_p || cp_parser_parse_definitely (parser))
{
cp_cv_quals cv_quals;
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_quals = cp_parser_cv_qualifier_seq_opt (parser);
exception_specification
= cp_parser_exception_specification_opt (parser);
declarator = make_call_declarator (declarator,
params,
cv_quals,
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,
member_p);
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 = cp_error_declarator;
if (declarator == cp_error_declarator)
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 if (!at_function_scope_p ())
{
error ("array bound is not an integer constant");
bounds = error_mark_node;
}
}
else
bounds = NULL_TREE;
if (!cp_parser_require (parser, CPP_CLOSE_SQUARE, "`]'"))
{
declarator = cp_error_declarator;
break;
}
declarator = make_array_declarator (declarator, bounds);
}
else if (first && dcl_kind != CP_PARSER_DECLARATOR_ABSTRACT)
{
tree qualifying_scope;
tree unqualified_name;
special_function_kind sfk;
if (dcl_kind == CP_PARSER_DECLARATOR_EITHER)
cp_parser_parse_tentatively (parser);
unqualified_name = cp_parser_declarator_id (parser);
qualifying_scope = parser->scope;
if (dcl_kind == CP_PARSER_DECLARATOR_EITHER)
{
if (!cp_parser_parse_definitely (parser))
unqualified_name = error_mark_node;
else if (qualifying_scope
|| (TREE_CODE (unqualified_name)
!= IDENTIFIER_NODE))
{
cp_parser_error (parser, "expected unqualified-id");
unqualified_name = error_mark_node;
}
}
if (unqualified_name == error_mark_node)
{
declarator = cp_error_declarator;
break;
}
if (qualifying_scope && at_namespace_scope_p ()
&& TREE_CODE (qualifying_scope) == TYPENAME_TYPE)
{
tree type;
type = resolve_typename_type (qualifying_scope,
false);
if (type == error_mark_node)
error ("%<%T::%D%> is not a type",
TYPE_CONTEXT (qualifying_scope),
TYPE_IDENTIFIER (qualifying_scope));
qualifying_scope = type;
}
sfk = sfk_none;
if (unqualified_name)
{
tree class_type;
if (qualifying_scope
&& CLASS_TYPE_P (qualifying_scope))
class_type = qualifying_scope;
else
class_type = current_class_type;
if (TREE_CODE (unqualified_name) == TYPE_DECL)
{
tree name_type = TREE_TYPE (unqualified_name);
if (class_type && same_type_p (name_type, class_type))
{
if (qualifying_scope
&& CLASSTYPE_USE_TEMPLATE (name_type))
{
error ("invalid use of constructor as a template");
inform ("use %<%T::%D%> instead of %<%T::%D%> to "
"name the constructor in a qualified name",
class_type,
DECL_NAME (TYPE_TI_TEMPLATE (class_type)),
class_type, name_type);
declarator = cp_error_declarator;
break;
}
else
unqualified_name = constructor_name (class_type);
}
else
{
cp_parser_error (parser, "invalid declarator");
declarator = cp_error_declarator;
break;
}
}
if (class_type)
{
if (TREE_CODE (unqualified_name) == BIT_NOT_EXPR)
sfk = sfk_destructor;
else if (IDENTIFIER_TYPENAME_P (unqualified_name))
sfk = sfk_conversion;
else if (
!TYPE_WAS_ANONYMOUS (class_type)
&& constructor_name_p (unqualified_name,
class_type))
{
unqualified_name = constructor_name (class_type);
sfk = sfk_constructor;
}
if (ctor_dtor_or_conv_p && sfk != sfk_none)
*ctor_dtor_or_conv_p = -1;
}
}
declarator = make_id_declarator (qualifying_scope,
unqualified_name,
sfk);
handle_declarator:;
scope = get_scope_of_declarator (declarator);
if (scope)
pushed_scope = push_scope (scope);
parser->in_declarator_p = true;
if ((ctor_dtor_or_conv_p && *ctor_dtor_or_conv_p)
|| (declarator && declarator->kind == cdk_id))
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 (pushed_scope)
pop_scope (pushed_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,
cp_cv_quals *cv_quals)
{
enum tree_code code = ERROR_MARK;
cp_token *token;
*type = NULL_TREE;
*cv_quals = TYPE_UNQUALIFIED;
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_quals = 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_quals = cp_parser_cv_qualifier_seq_opt (parser);
}
if (!cp_parser_parse_definitely (parser))
cp_parser_error (parser, "expected ptr-operator");
}
return code;
}
static cp_cv_quals
cp_parser_cv_qualifier_seq_opt (cp_parser* parser)
{
cp_cv_quals cv_quals = TYPE_UNQUALIFIED;
while (true)
{
cp_token *token;
cp_cv_quals cv_qualifier;
token = cp_lexer_peek_token (parser->lexer);
switch (token->keyword)
{
case RID_CONST:
cv_qualifier = TYPE_QUAL_CONST;
break;
case RID_VOLATILE:
cv_qualifier = TYPE_QUAL_VOLATILE;
break;
case RID_RESTRICT:
cv_qualifier = TYPE_QUAL_RESTRICT;
break;
default:
cv_qualifier = TYPE_UNQUALIFIED;
break;
}
if (!cv_qualifier)
break;
if (cv_quals & cv_qualifier)
{
error ("duplicate cv-qualifier");
cp_lexer_purge_token (parser->lexer);
}
else
{
cp_lexer_consume_token (parser->lexer);
cv_quals |= cv_qualifier;
}
}
return cv_quals;
}
static tree
cp_parser_declarator_id (cp_parser* parser)
{
tree id;
id = cp_parser_id_expression (parser,
false,
false,
NULL,
true);
if (BASELINK_P (id))
id = BASELINK_FUNCTIONS (id);
return id;
}
static tree
cp_parser_type_id (cp_parser* parser)
{
cp_decl_specifier_seq type_specifier_seq;
cp_declarator *abstract_declarator;
cp_parser_type_specifier_seq (parser, false,
&type_specifier_seq);
if (type_specifier_seq.type == error_mark_node)
return error_mark_node;
cp_parser_parse_tentatively (parser);
abstract_declarator
= cp_parser_declarator (parser, CP_PARSER_DECLARATOR_ABSTRACT, NULL,
NULL,
false);
if (!cp_parser_parse_definitely (parser))
abstract_declarator = NULL;
return groktypename (&type_specifier_seq, abstract_declarator);
}
static void
cp_parser_type_specifier_seq (cp_parser* parser,
bool is_condition,
cp_decl_specifier_seq *type_specifier_seq)
{
bool seen_type_specifier = false;
cp_parser_flags flags = CP_PARSER_FLAGS_OPTIONAL;
clear_decl_specs (type_specifier_seq);
while (true)
{
tree type_specifier;
bool is_cv_qualifier;
if (cp_lexer_next_token_is_keyword (parser->lexer, RID_ATTRIBUTE))
{
type_specifier_seq->attributes =
chainon (type_specifier_seq->attributes,
cp_parser_attributes_opt (parser));
continue;
}
type_specifier = cp_parser_type_specifier (parser,
flags,
type_specifier_seq,
false,
NULL,
&is_cv_qualifier);
if (!type_specifier)
{
if (!seen_type_specifier)
{
cp_parser_error (parser, "expected type-specifier");
type_specifier_seq->type = error_mark_node;
return;
}
break;
}
seen_type_specifier = true;
if (is_condition && !is_cv_qualifier)
flags |= CP_PARSER_FLAGS_NO_USER_DEFINED_TYPES;
}
return;
}
static cp_parameter_declarator *
cp_parser_parameter_declaration_clause (cp_parser* parser)
{
cp_parameter_declarator *parameters;
cp_token *token;
bool ellipsis_p;
bool is_error;
token = cp_lexer_peek_token (parser->lexer);
if (token->type == CPP_ELLIPSIS)
{
cp_lexer_consume_token (parser->lexer);
return NULL;
}
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;
else
#endif
return no_parameters;
}
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 no_parameters;
}
parameters = cp_parser_parameter_declaration_list (parser, &is_error);
if (is_error)
return NULL;
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;
if (parameters && ellipsis_p)
parameters->ellipsis_p = true;
return parameters;
}
static cp_parameter_declarator *
cp_parser_parameter_declaration_list (cp_parser* parser, bool *is_error)
{
cp_parameter_declarator *parameters = NULL;
cp_parameter_declarator **tail = ¶meters;
*is_error = false;
while (true)
{
cp_parameter_declarator *parameter;
bool parenthesized_p;
parameter
= cp_parser_parameter_declaration (parser,
false,
&parenthesized_p);
if (!parameter)
{
*is_error = true;
parameters = NULL;
break;
}
*tail = parameter;
tail = ¶meter->next;
if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_PAREN)
|| cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS)
|| cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON)
|| cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE))
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_uncommitted_to_tentative_parse_p (parser)
&& !parenthesized_p)
cp_parser_commit_to_tentative_parse (parser);
}
else
{
cp_parser_error (parser, "expected %<,%> or %<...%>");
if (!cp_parser_uncommitted_to_tentative_parse_p (parser))
cp_parser_skip_to_closing_parenthesis (parser,
true,
false,
false);
break;
}
}
return parameters;
}
static cp_parameter_declarator *
cp_parser_parameter_declaration (cp_parser *parser,
bool template_parm_p,
bool *parenthesized_p)
{
int declares_class_or_enum;
bool greater_than_is_operator_p;
cp_decl_specifier_seq decl_specifiers;
cp_declarator *declarator;
tree default_argument;
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";
cp_parser_decl_specifier_seq (parser,
CP_PARSER_FLAGS_NONE,
&decl_specifiers,
&declares_class_or_enum);
if (cp_parser_error_occurred (parser))
{
parser->type_definition_forbidden_message = saved_message;
return NULL;
}
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;
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_uncommitted_to_tentative_parse_p (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,
false);
parser->default_arg_ok_p = saved_default_arg_ok_p;
decl_specifiers.attributes
= chainon (decl_specifiers.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;
cp_token *first_token;
cp_token *token;
first_token = cp_lexer_peek_token (parser->lexer);
while (true)
{
bool done = false;
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);
}
default_argument = make_node (DEFAULT_ARG);
DEFARG_TOKENS (default_argument)
= cp_token_cache_new (first_token, 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, false);
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;
return make_parameter_declarator (&decl_specifiers,
declarator,
default_argument);
}
static void
cp_parser_function_body (cp_parser *parser)
{
cp_parser_compound_statement (parser, NULL, 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,
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;
*non_constant_p = false;
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,
enum tag_types tag_type,
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))
tag_type = typename_type;
decl = cp_parser_lookup_name (parser, identifier,
tag_type,
false,
false,
check_dependency_p,
NULL);
}
}
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, typename_type, 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, tag_type, tf_error));
else if (decl == error_mark_node
|| TREE_CODE (decl) != TYPE_DECL
|| TREE_TYPE (decl) == error_mark_node
|| !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;
tree old_scope = NULL_TREE;
tree scope = NULL_TREE;
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)
{
scope = CP_DECL_CONTEXT (TYPE_MAIN_DECL (type));
old_scope = push_inner_scope (scope);
}
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 (nested_name_specifier_p)
pop_inner_scope (old_scope, scope);
if (--parser->num_classes_being_defined == 0)
{
tree queue_entry;
tree fn;
tree class_type = NULL_TREE;
tree pushed_scope = NULL_TREE;
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);
if (class_type != TREE_PURPOSE (queue_entry))
{
if (pushed_scope)
pop_scope (pushed_scope);
class_type = TREE_PURPOSE (queue_entry);
pushed_scope = push_scope (class_type);
}
maybe_begin_member_template_processing (fn);
cp_parser_late_parsing_default_args (parser, fn);
maybe_end_member_template_processing ();
}
if (pushed_scope)
pop_scope (pushed_scope);
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)
{
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;
tree pushed_scope = NULL_TREE;
unsigned num_templates;
tree bases;
*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,
class_type,
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;
if (!DECL_IMPLICIT_TYPEDEF_P (type))
{
error ("invalid class name in declaration of %qD", type);
type = NULL_TREE;
goto done;
}
scope = current_scope ();
if (scope && !is_ancestor (scope, nested_name_specifier))
{
error ("declaration of %qD in %qD which does not enclose %qD",
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);
if (nested_name_specifier)
pushed_scope = push_scope (nested_name_specifier);
}
else if (nested_name_specifier)
{
tree class_type;
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;
pushed_scope = 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);
if (type == error_mark_node)
{
type = NULL_TREE;
goto done;
}
}
type = TREE_TYPE (type);
*nested_name_specifier_p = true;
}
else
{
if (!id)
id = make_anon_name ();
type = xref_tag (class_key, id, ts_current,
parser->num_template_parameter_lists);
}
if (TREE_CODE (type) == RECORD_TYPE)
CLASSTYPE_DECLARED_CLASS (type) = (class_key == class_type);
cp_parser_check_class_key (class_key, type);
if (type != error_mark_node && COMPLETE_TYPE_P (type))
{
error ("redefinition of %q#T", type);
cp_error_at ("previous definition of %q#T", type);
type = NULL_TREE;
goto done;
}
bases = NULL_TREE;
if (cp_lexer_next_token_is (parser->lexer, CPP_COLON))
bases = cp_parser_base_clause (parser);
xref_basetypes (type, bases);
done:
if (pushed_scope)
pop_scope (pushed_scope);
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:
if (token->type == CPP_PRAGMA)
{
cp_lexer_handle_pragma (parser->lexer);
break;
}
cp_parser_member_declaration (parser);
}
}
}
static void
cp_parser_member_declaration (cp_parser* parser)
{
cp_decl_specifier_seq 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;
}
if (cp_lexer_next_token_is_keyword (parser->lexer, RID_AT_DEFS))
{
tree ivar, member;
tree ivar_chains = cp_parser_objc_defs_expression (parser);
ivar = ivar_chains;
while (ivar)
{
member = ivar;
ivar = TREE_CHAIN (member);
TREE_CHAIN (member) = NULL_TREE;
finish_member_declaration (member);
}
if (flag_objc_abi == 3
|| (flag_objc2_check && flag_objc_abi == 1))
warning ("@defs will not be supported in future");
else if (flag_objc_abi == 2 && flag_objc_atdefs != 1)
error ("@defs will not be supported in future");
return;
}
cp_parser_decl_specifier_seq (parser,
CP_PARSER_FLAGS_OPTIONAL,
&decl_specifiers,
&declares_class_or_enum);
prefix_attributes = decl_specifiers.attributes;
decl_specifiers.attributes = NULL_TREE;
if (!decl_specifiers.type
&& cp_parser_parse_and_diagnose_invalid_type_name (parser))
return;
if (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON))
{
if (!decl_specifiers.any_specifiers_p)
{
cp_token *token = cp_lexer_peek_token (parser->lexer);
if (pedantic && !token->in_system_header)
pedwarn ("%Hextra %<;%>", &token->location);
}
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
&& decl_specifiers.type
&& TYPE_P (decl_specifiers.type))
type = decl_specifiers.type;
if (!type || !TYPE_P (type))
error ("friend declaration does not name a class or "
"function");
else
make_friend_class (current_class_type, type,
true);
}
else if (!type || type == error_mark_node)
;
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
? make_id_declarator (NULL_TREE,
identifier,
sfk_none)
: NULL,
&decl_specifiers,
width);
cplus_decl_attributes (&decl, attributes, 0);
}
else
{
cp_declarator *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,
true);
if (declarator == cp_error_declarator)
{
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;
}
if (declares_class_or_enum & 2)
cp_parser_check_for_definition_in_return_type
(declarator, decl_specifiers.type);
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 (declarator->kind == cdk_function)
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_lexer_consume_token (parser->lexer);
if (token->type != CPP_NUMBER || !integer_zerop (token->value))
{
cp_parser_error (parser,
"invalid pure specifier (only `= 0' is allowed)");
cp_parser_skip_to_end_of_statement (parser);
return error_mark_node;
}
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,
typename_type,
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,
typename_type,
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, NULL, true);
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, NULL, false);
finish_handler (handler);
}
static tree
cp_parser_exception_declaration (cp_parser* parser)
{
tree decl;
cp_decl_specifier_seq type_specifiers;
cp_declarator *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";
cp_parser_type_specifier_seq (parser, false,
&type_specifiers);
if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_PAREN))
declarator = NULL;
else
declarator = cp_parser_declarator (parser, CP_PARSER_DECLARATOR_EITHER,
NULL,
NULL,
false);
parser->type_definition_forbidden_message = saved_message;
if (type_specifiers.any_specifiers_p)
{
decl = grokdeclarator (declarator, &type_specifiers, CATCHPARM, 1, NULL);
if (decl == NULL_TREE)
error ("invalid catch parameter");
}
else
decl = NULL_TREE;
return decl;
}
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,
false);
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, "`('");
asm_specification = cp_parser_string_literal (parser, false, false);
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;
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;
string_literal = cp_parser_string_literal (parser, false, false);
cp_parser_require (parser, CPP_OPEN_PAREN, "`('");
expression = cp_parser_expression (parser, false);
cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
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)
{
tree string_literal;
string_literal = cp_parser_string_literal (parser, false, false);
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;
bool save_translate_strings_p = parser->translate_strings_p;
parser->translate_strings_p = 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)
{
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, false,
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);
}
parser->translate_strings_p = save_translate_strings_p;
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,
enum tag_types tag_type,
bool is_template, bool is_namespace,
bool check_dependency,
bool *ambiguous_p)
{
tree decl;
tree object_type = parser->context->object_type;
if (ambiguous_p)
*ambiguous_p = false;
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))
{
gcc_assert (TREE_CODE (BASELINK_FUNCTIONS (name))
== TEMPLATE_ID_EXPR);
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_LAZY_DESTRUCTOR (type))
lazily_declare_fn (sfk_destructor, type);
if (!CLASSTYPE_DESTRUCTORS (type))
return error_mark_node;
return CLASSTYPE_DESTRUCTORS (type);
}
gcc_assert (TREE_CODE (name) == IDENTIFIER_NODE);
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 (tag_type)
{
tree type;
type = make_typename_type (parser->scope, name, tag_type,
1);
decl = TYPE_NAME (type);
}
else if (is_template)
decl = make_unbound_class_template (parser->scope,
name, NULL_TREE,
1);
else
decl = build_nt (SCOPE_REF, parser->scope, name);
}
else
{
tree pushed_scope = NULL_TREE;
if (dependent_p)
pushed_scope = push_scope (parser->scope);
decl = lookup_qualified_name (parser->scope, name,
tag_type != none_type,
true);
if (pushed_scope)
pop_scope (pushed_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,
tag_type != none_type);
decl = lookup_name_real (name, tag_type != none_type,
0,
true, 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, tag_type != none_type,
0,
true, 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 (ambiguous_p)
*ambiguous_p = true;
if (!cp_parser_simulate_error (parser))
{
error ("reference to %qD is ambiguous", name);
print_candidates (decl);
}
return error_mark_node;
}
gcc_assert (DECL_P (decl)
|| TREE_CODE (decl) == OVERLOAD
|| TREE_CODE (decl) == SCOPE_REF
|| TREE_CODE (decl) == UNBOUND_CLASS_TEMPLATE
|| BASELINK_P (decl));
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,
none_type,
false,
false,
true,
NULL);
}
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,
cp_declarator *declarator)
{
unsigned num_templates;
num_templates = 0;
switch (declarator->kind)
{
case cdk_id:
if (declarator->u.id.qualifying_scope)
{
tree scope;
tree member;
scope = declarator->u.id.qualifying_scope;
member = declarator->u.id.unqualified_name;
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);
}
}
else if (TREE_CODE (declarator->u.id.unqualified_name)
== TEMPLATE_ID_EXPR)
++num_templates;
return cp_parser_check_template_parameters (parser,
num_templates);
case cdk_function:
case cdk_array:
case cdk_pointer:
case cdk_reference:
case cdk_ptrmem:
return (cp_parser_check_declarator_template_parameters
(parser, declarator->declarator));
case cdk_error:
return true;
default:
gcc_unreachable ();
}
return false;
}
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_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,
none_type,
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;
tree pushed_scope = NULL_TREE;
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;
}
}
pushed_scope = 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,
NULL,
true,
NULL,
NULL);
parser->num_template_parameter_lists
= saved_num_template_parameter_lists;
if (pushed_scope)
pop_scope (pushed_scope);
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,
cp_decl_specifier_seq *decl_specifiers,
tree attributes,
const cp_declarator *declarator)
{
tree fn;
bool success_p;
success_p = start_function (decl_specifiers, declarator, attributes);
reset_specialization ();
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
{
push_deferring_access_checks (dk_no_check);
decl = cp_parser_single_declaration (parser,
member_p,
&friend_p);
pop_deferring_access_checks ();
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;
cp_decl_specifier_seq decl_specifiers;
bool function_definition_p = false;
gcc_assert (innermost_scope_kind () == sk_template_parms
|| innermost_scope_kind () == sk_template_spec);
push_deferring_access_checks (dk_deferred);
cp_parser_decl_specifier_seq (parser,
CP_PARSER_FLAGS_OPTIONAL,
&decl_specifiers,
&declares_class_or_enum);
if (friend_p)
*friend_p = cp_parser_friend_p (&decl_specifiers);
if (decl_specifiers.specs[(int) ds_typedef])
{
error ("template declaration of %qs", "typedef");
decl = error_mark_node;
}
stop_deferring_access_checks ();
if (declares_class_or_enum)
{
if (cp_parser_declares_only_class_p (parser))
{
decl = shadow_tag (&decl_specifiers);
if (friend_p && *friend_p
&& !decl
&& decl_specifiers.type
&& TYPE_P (decl_specifiers.type))
decl = decl_specifiers.type;
if (decl && decl != error_mark_node)
decl = TYPE_NAME (decl);
else
decl = error_mark_node;
}
}
if (!decl
&& (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON)
|| decl_specifiers.type != error_mark_node))
decl = cp_parser_init_declarator (parser,
&decl_specifiers,
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
&& (decl == error_mark_node
|| !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,
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,
true,
NULL);
cast = build_functional_cast (type, expression_list);
if (TREE_CODE (type) == TYPE_DECL)
type = TREE_TYPE (type);
if (cast != error_mark_node && !dependent_type_p (type)
&& !INTEGRAL_OR_ENUMERATION_TYPE_P (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,
cp_decl_specifier_seq *decl_specifiers,
cp_declarator *declarator,
tree attributes)
{
cp_token *first;
cp_token *last;
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);
first = parser->lexer->next_token;
cp_parser_cache_group (parser, CPP_CLOSE_BRACE, 0);
while (cp_lexer_next_token_is_keyword (parser->lexer, RID_CATCH))
cp_parser_cache_group (parser, CPP_CLOSE_BRACE, 0);
last = parser->lexer->next_token;
DECL_PENDING_INLINE_INFO (fn) = cp_token_cache_new (first, last);
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 = cp_lexer_peek_token (parser->lexer);
error ("%H%<>>%> should be %<> >%> "
"within a nested template argument list",
&token->location);
token->type = CPP_GREATER;
}
else
{
cp_lexer_consume_token (parser->lexer);
error ("spurious %<>>%>, use %<>%> to terminate "
"a template argument list");
}
}
else if (!cp_lexer_next_token_is (parser->lexer, CPP_GREATER))
error ("missing %<>%> to terminate the template argument list");
else
cp_lexer_consume_token (parser->lexer);
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)
{
if (DECL_FUNCTION_TEMPLATE_P (member_function))
member_function = DECL_TEMPLATE_RESULT (member_function);
gcc_assert (parser->num_classes_being_defined == 0);
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 = current_function_decl;
if (function_scope)
push_function_context_to (function_scope);
cp_parser_push_lexer_for_tokens (parser, tokens);
start_preparsed_function (member_function, NULL_TREE,
SF_PRE_PARSED | SF_INCLASS_INLINE);
if (processing_template_decl)
push_deferring_access_checks (dk_no_check);
cp_parser_function_definition_after_declarator (parser,
true);
if (processing_template_decl)
pop_deferring_access_checks ();
if (function_scope)
pop_function_context_from (function_scope);
cp_parser_pop_lexer (parser);
}
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 (current_class_type, decl,
TREE_PURPOSE (parser->unparsed_functions_queues));
break;
}
return;
}
static void
cp_parser_late_parsing_default_args (cp_parser *parser, tree fn)
{
bool saved_local_variables_forbidden_p;
tree parm;
parser->unparsed_functions_queues
= tree_cons (NULL_TREE, NULL_TREE, parser->unparsed_functions_queues);
saved_local_variables_forbidden_p = parser->local_variables_forbidden_p;
parser->local_variables_forbidden_p = true;
for (parm = TYPE_ARG_TYPES (TREE_TYPE (fn));
parm;
parm = TREE_CHAIN (parm))
{
cp_token_cache *tokens;
if (!TREE_PURPOSE (parm)
|| TREE_CODE (TREE_PURPOSE (parm)) != DEFAULT_ARG)
continue;
tokens = DEFARG_TOKENS (TREE_PURPOSE (parm));
cp_parser_push_lexer_for_tokens (parser, tokens);
TREE_PURPOSE (parm) = cp_parser_assignment_expression (parser,
false);
if (!cp_lexer_next_token_is (parser->lexer, CPP_EOF))
cp_parser_error (parser, "expected %<,%>");
cp_parser_pop_lexer (parser);
}
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;
bool saved_non_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;
saved_non_integral_constant_expression_p
= parser->non_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))
{
cp_decl_specifier_seq decl_specs;
clear_decl_specs (&decl_specs);
decl_specs.type = type;
expr = grokdeclarator (NULL,
&decl_specs,
TYPENAME,
0,
NULL);
}
}
if (!expr)
expr = cp_parser_unary_expression (parser, false,
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;
parser->non_integral_constant_expression_p
= saved_non_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 void
cp_parser_set_storage_class (cp_decl_specifier_seq *decl_specs,
cp_storage_class storage_class)
{
if (decl_specs->storage_class != sc_none)
decl_specs->multiple_storage_classes_p = true;
else
decl_specs->storage_class = storage_class;
}
static void
cp_parser_set_decl_spec_type (cp_decl_specifier_seq *decl_specs,
tree type_spec,
bool user_defined_p)
{
decl_specs->any_specifiers_p = true;
if (decl_specs->specs[(int) ds_typedef]
&& !user_defined_p
&& (type_spec == boolean_type_node
|| type_spec == wchar_type_node)
&& (decl_specs->type
|| decl_specs->specs[(int) ds_long]
|| decl_specs->specs[(int) ds_short]
|| decl_specs->specs[(int) ds_unsigned]
|| decl_specs->specs[(int) ds_signed]))
{
decl_specs->redefined_builtin_type = type_spec;
if (!decl_specs->type)
{
decl_specs->type = type_spec;
decl_specs->user_defined_type_p = false;
}
}
else if (decl_specs->type)
decl_specs->multiple_types_p = true;
else
{
decl_specs->type = type_spec;
decl_specs->user_defined_type_p = user_defined_p;
decl_specs->redefined_builtin_type = NULL_TREE;
}
}
static bool
cp_parser_friend_p (const cp_decl_specifier_seq *decl_specifiers)
{
return decl_specifiers->specs[(int) ds_friend] != 0;
}
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);
}
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 ("%qs tag used in naming %q#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 ("%qD 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,
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);
if (token->type == CPP_OPEN_BRACE)
{
cp_parser_cache_group (parser, CPP_CLOSE_BRACE, depth + 1);
if (depth == 0)
return;
}
else if (token->type == CPP_OPEN_PAREN)
cp_parser_cache_group (parser, 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_uncommitted_to_tentative_parse_p (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 tree
cp_parser_iasm_compound_statement (cp_parser *parser)
{
tree compound_stmt;
iasm_state = iasm_asm;
inside_iasm_block = true;
iasm_kill_regs = true;
iasm_at_bol = 1;
iasm_clear_labels ();
if (!cp_parser_require (parser, CPP_OPEN_BRACE, "`{'"))
return error_mark_node;
compound_stmt = begin_compound_stmt (false);
cp_parser_iasm_line_seq_opt (parser);
finish_compound_stmt (compound_stmt);
cp_parser_require (parser, CPP_CLOSE_BRACE, "`}'");
iasm_at_bol = 0;
iasm_end_block ();
iasm_state = iasm_none;
return compound_stmt;
}
static tree
cp_parser_iasm_top_statement (cp_parser *parser)
{
tree compound_stmt;
iasm_state = iasm_asm;
inside_iasm_block = true;
iasm_kill_regs = true;
iasm_at_bol = 1;
iasm_clear_labels ();
compound_stmt = begin_compound_stmt (false);
if (!cp_lexer_iasm_bol (parser->lexer))
{
cp_parser_iasm_line (parser);
}
finish_compound_stmt (compound_stmt);
iasm_at_bol = 0;
iasm_end_block ();
iasm_state = iasm_none;
return compound_stmt;
}
static void
cp_parser_iasm_declaration_seq_opt (cp_parser* parser)
{
cp_token *token = cp_lexer_peek_token (parser->lexer);
if (token->type == CPP_NAME
&& !iasm_typename_or_reserved (token->value))
return;
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_simple_declaration (parser, false);
if (token->type == CPP_PRAGMA)
cp_lexer_handle_pragma (parser->lexer);
if (iasm_state >= iasm_decls
&& (cp_lexer_iasm_bol (parser->lexer)
|| cp_lexer_next_token_is (parser->lexer, CPP_NAME)))
break;
}
}
static void
cp_parser_iasm_line_seq_opt (cp_parser* parser)
{
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_iasm_line (parser);
}
}
static void
cp_parser_iasm_line (cp_parser* parser)
{
cp_parser_iasm_statement_seq_opt (parser);
}
static void
cp_parser_iasm_skip_to_eol (cp_parser *parser)
{
while (true)
{
cp_token *token;
if ((token = parser->lexer->next_token)->type == CPP_NUMBER)
;
else
token = cp_lexer_peek_token (parser->lexer);
if (token->type == CPP_EOF)
break;
if (cp_lexer_iasm_bol (parser->lexer))
break;
cp_lexer_consume_token (parser->lexer);
}
}
static void
cp_parser_iasm_maybe_skip_comments (cp_parser *parser)
{
if (flag_ms_asms
&& cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON))
{
cp_lexer_consume_token (parser->lexer);
cp_parser_iasm_skip_to_eol (parser);
}
}
static void
cp_parser_iasm_statement_seq_opt (cp_parser* parser)
{
int check;
while (true)
{
check = 0;
if (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON))
{
if (flag_ms_asms)
{
cp_parser_iasm_maybe_skip_comments (parser);
return;
}
cp_lexer_consume_token (parser->lexer);
}
else if (cp_lexer_next_token_is_keyword (parser->lexer, RID_ASM))
{
cp_lexer_consume_token (parser->lexer);
}
else
{
cp_parser_iasm_statement (parser);
check = 1;
}
if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_BRACE)
|| cp_lexer_next_token_is (parser->lexer, CPP_EOF)
|| cp_lexer_iasm_bol (parser->lexer))
return;
if (check
&& !(cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_BRACE)
|| cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON)
|| cp_lexer_next_token_is_keyword (parser->lexer, RID_ASM)
|| cp_lexer_iasm_bol (parser->lexer)))
{
cp_parser_error (parser, "expected `;' or `}' `asm' or end-of-line");
}
}
if (!cp_lexer_iasm_bol (parser->lexer))
cp_parser_iasm_maybe_skip_comments (parser);
}
static tree
iasm_build_identifier_string (cp_parser* parser, const char* str)
{
char *buf;
int len;
tree id;
if (strcmp (str, ".") == 0
&& (cp_lexer_peek_token (parser->lexer)->flags & PREV_WHITE) == 0)
{
if (cp_lexer_next_token_is_keyword (parser->lexer, RID_SHORT))
{
cp_lexer_consume_token (parser->lexer);
return get_identifier (".short");
}
if (cp_lexer_next_token_is_keyword (parser->lexer, RID_LONG))
{
cp_lexer_consume_token (parser->lexer);
return get_identifier (".long");
}
}
id = cp_parser_iasm_identifier_or_number (parser);
len = strlen (str);
buf = (char *) alloca (IDENTIFIER_LENGTH (id) + len + 1);
memcpy (buf, str, len);
memcpy (buf+len, IDENTIFIER_POINTER (id), IDENTIFIER_LENGTH (id));
buf[IDENTIFIER_LENGTH (id) + len] = 0;
return get_identifier (buf);
}
static tree
cp_parser_iasm_identifier (cp_parser* parser)
{
cp_token *token;
tree t;
const char *str = "";
token = cp_lexer_peek_token (parser->lexer);
if (token->flags & NAMED_OP)
{
const char *s = 0;
switch (token->type) {
case CPP_AND_AND: s="and"; break;
case CPP_AND_EQ: s="and_eq"; break;
case CPP_AND: s="bitand"; break;
case CPP_OR: s="bitor"; break;
case CPP_COMPL: s="compl"; break;
case CPP_NOT: s="not"; break;
case CPP_NOT_EQ: s="not_eq"; break;
case CPP_OR_OR: s="or"; break;
case CPP_OR_EQ: s="or_eq"; break;
case CPP_XOR: s="xor"; break;
case CPP_XOR_EQ: s="xor_eq"; break;
default: break;
}
gcc_assert (s != 0);
cp_lexer_consume_token (parser->lexer);
t = get_identifier (s);
}
else if (token->type == CPP_DOT)
{
cp_lexer_consume_token (parser->lexer);
t = iasm_build_identifier_string (parser, ".");
}
else if (token->value
&& IASM_SEE_OPCODE (TYPESPEC, token->value) == IDENTIFIER)
{
cp_lexer_consume_token (parser->lexer);
t = token->value;
}
else
t = cp_parser_identifier (parser);
if (t == error_mark_node)
return t;
token = cp_lexer_peek_token (parser->lexer);
switch (token->type)
{
case CPP_DOT:
str = ".";
break;
case CPP_PLUS:
str = "+";
break;
case CPP_MINUS:
str = "-";
break;
case CPP_PLUS_PLUS:
str = "++";
break;
case CPP_MINUS_MINUS:
str = "--";
break;
default:
return t;
}
if (token->flags & PREV_WHITE)
return t;
cp_lexer_consume_token (parser->lexer);
return iasm_get_identifier (t, str);
}
static tree
cp_parser_iasm_identifier_or_number (cp_parser* parser)
{
cp_token *token;
token = cp_lexer_peek_token (parser->lexer);
if (token->type == CPP_NUMBER
&& TREE_CODE (token->value) == INTEGER_CST)
{
char buf[60];
sprintf (buf, HOST_WIDE_INT_PRINT_UNSIGNED, tree_low_cst (token->value, 0));
cp_lexer_consume_token (parser->lexer);
return get_identifier (buf);
}
return cp_parser_identifier (parser);
}
static tree
cp_parser_iasm_maybe_prefix (cp_parser *parser, tree id)
{
tree prefix_list = NULL_TREE;
while (iasm_is_prefix (id))
{
if (cp_lexer_iasm_bol (parser->lexer))
break;
prefix_list = tree_cons (NULL_TREE, id, prefix_list);
id = cp_parser_iasm_identifier (parser);
}
if (prefix_list)
id = tree_cons (NULL_TREE, id, prefix_list);
return id;
}
static void
cp_parser_iasm_statement (cp_parser* parser)
{
tree aname, scspec, anothername, operands;
while (true)
{
if (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON)
|| cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_BRACE)
|| cp_lexer_next_token_is (parser->lexer, CPP_EOF))
break;
if (cp_lexer_next_token_is (parser->lexer, CPP_PRAGMA))
{
cp_lexer_handle_pragma (parser->lexer);
}
else if (cp_lexer_next_token_is (parser->lexer, CPP_ATSIGN))
{
cp_lexer_consume_token (parser->lexer);
aname = cp_parser_iasm_identifier_or_number (parser);
if (cp_lexer_next_token_is (parser->lexer, CPP_COLON))
cp_lexer_consume_token (parser->lexer);
iasm_label (aname, 1);
}
else
{
aname = cp_parser_iasm_identifier (parser);
if (cp_lexer_next_token_is (parser->lexer, CPP_COLON))
{
cp_lexer_consume_token (parser->lexer);
iasm_label (aname, 0);
}
else
{
if (strcmp (IDENTIFIER_POINTER (aname), "entry") != 0)
scspec = 0;
else
scspec = cp_parser_storage_class_specifier_opt (parser);
if (scspec)
{
anothername = cp_parser_iasm_operand (parser);
iasm_entry (aname, scspec, anothername);
}
else
{
aname = cp_parser_iasm_maybe_prefix (parser, aname);
iasm_in_operands = 1;
operands = cp_parser_iasm_operands (parser);
iasm_stmt (aname, operands, input_line);
}
if (cp_lexer_iasm_bol (parser->lexer))
return;
break;
}
}
if (cp_lexer_iasm_bol (parser->lexer))
return;
}
cp_parser_iasm_maybe_skip_comments (parser);
}
static void
cp_parser_iasm_skip_to_next_asm (cp_parser *parser)
{
cp_token *token = cp_lexer_peek_token (parser->lexer);
do
{
if (cp_lexer_iasm_bol (parser->lexer)
|| token->type == CPP_SEMICOLON
|| token->type == CPP_CLOSE_BRACE
|| token->type == CPP_EOF
|| token->keyword == RID_ASM)
return;
cp_lexer_consume_token (parser->lexer);
}
while (1);
}
tree
cp_parser_iasm_operands (cp_parser *parser)
{
tree operands = NULL_TREE, operand;
while (true)
{
if (cp_lexer_iasm_bol (parser->lexer)
|| cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON)
|| cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_BRACE)
|| cp_lexer_next_token_is (parser->lexer, CPP_EOF)
|| cp_lexer_next_token_is_keyword (parser->lexer, RID_ASM))
break;
operand = cp_parser_iasm_operand (parser);
if (operand && operand != error_mark_node)
{
operands = chainon (operands, build_tree_list (NULL_TREE, operand));
if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA))
cp_lexer_consume_token (parser->lexer);
}
else
{
cp_parser_iasm_skip_to_next_asm (parser);
return NULL_TREE;
}
}
return operands;
}
tree
cp_parser_iasm_operand (cp_parser *parser)
{
tree operand;
operand = cp_parser_binary_expression (parser, false);
return operand;
}
static tree
cp_parser_iasm_relative_branch (cp_parser *parser)
{
cp_token *token;
token = cp_lexer_peek_nth_token (parser->lexer, 2);
if (token->type == CPP_PLUS || token->type == CPP_MINUS)
{
const char *str = (token->type == CPP_PLUS) ? ".+" : ".-";
cp_lexer_consume_token (parser->lexer);
cp_lexer_consume_token (parser->lexer);
return iasm_build_identifier_string (parser, str);
}
return error_mark_node;
}
static tree
cp_parser_iasm_postfix_expression (cp_parser *parser, bool address_p)
{
bool for_offsetof = false;
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_SIZEOF:
{
tree operand;
cp_lexer_consume_token (parser->lexer);
operand = cp_parser_sizeof_operand (parser, keyword);
postfix_expression = cxx_sizeof_or_alignof_type (operand, SIZEOF_EXPR, true);
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 (token->type == CPP_DOT || token->type == CPP_MULT)
{
postfix_expression = cp_parser_iasm_relative_branch (parser);
if (postfix_expression != error_mark_node)
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,
false,
&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, false);
cp_parser_require (parser, CPP_CLOSE_SQUARE, "`]'");
if (inside_iasm_block)
{
if (TREE_CODE (postfix_expression) == BRACKET_EXPR
|| TREE_CODE (index) == IDENTIFIER_NODE
|| TREE_TYPE (index) == NULL_TREE)
{
postfix_expression = iasm_build_bracket (postfix_expression, index);
break;
}
}
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:
{
tree expr;
cp_lexer_consume_token (parser->lexer);
expr = cp_parser_binary_expression (parser, false);
if (expr == error_mark_node)
{
postfix_expression = error_mark_node;
break;
}
postfix_expression =
iasm_build_register_offset (postfix_expression, expr);
cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
idk = CP_ID_KIND_NONE;
}
break;
case CPP_DOT:
if (TREE_CODE (postfix_expression) == INTEGER_CST
|| TREE_CODE (postfix_expression) == IDENTIFIER_NODE
|| TREE_CODE (postfix_expression) == COMPOUND_EXPR
|| TREE_CODE (postfix_expression) == LABEL_DECL
|| TREE_CODE (postfix_expression) == FUNCTION_DECL)
return postfix_expression;
case CPP_DEREF:
{
tree name;
bool dependent_p;
bool template_p;
tree scope = NULL_TREE;
enum cpp_ttype token_type = token->type;
if (TREE_CODE (postfix_expression) == BRACKET_EXPR)
{
cp_token *new_token;
new_token = cp_lexer_peek_nth_token (parser->lexer, 2);
if (new_token->type == CPP_NUMBER)
{
cp_lexer_consume_token (parser->lexer);
postfix_expression = iasm_build_bracket (postfix_expression,
new_token->value);
cp_lexer_consume_token (parser->lexer);
break;
}
}
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
= iasm_cp_build_component_ref (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 (!for_offsetof
&& (cp_parser_non_integral_constant_expression
(parser, token_type == CPP_DEREF ? "'->'" : "`.'")))
postfix_expression = error_mark_node;
}
break;
case CPP_NAME:
if (strcasecmp (IDENTIFIER_POINTER (token->value), "ptr") == 0)
{
tree type = postfix_expression;
cp_lexer_consume_token (parser->lexer);
postfix_expression = cp_parser_iasm_postfix_expression (parser, address_p);
postfix_expression = iasm_ptr_conv (type, postfix_expression);
}
default:
return postfix_expression;
}
}
abort ();
return error_mark_node;
}
int
iasm_typename_or_reserved (tree value)
{
tree type_decl;
if (IASM_SEE_OPCODE (TYPESPEC, value) == IDENTIFIER)
return 0;
if (C_IS_RESERVED_WORD (value))
return 1;
type_decl = lookup_name_real (value, 0, 0, true, 0, 0);
return type_decl
&& (TREE_CODE (type_decl) == TYPE_DECL
|| TREE_CODE (type_decl) == NAMESPACE_DECL
|| TREE_CODE (type_decl) == TEMPLATE_DECL);
}
static tree
cp_parser_objc_expression (cp_parser* parser)
{
cp_token *kwd = cp_lexer_peek_token (parser->lexer);
switch (kwd->type)
{
case CPP_OPEN_SQUARE:
return cp_parser_objc_message_expression (parser);
case CPP_OBJC_STRING:
kwd = cp_lexer_consume_token (parser->lexer);
return objc_build_string_object (kwd->value);
case CPP_KEYWORD:
switch (kwd->keyword)
{
case RID_AT_ENCODE:
return cp_parser_objc_encode_expression (parser);
case RID_AT_PROTOCOL:
return cp_parser_objc_protocol_expression (parser);
case RID_AT_SELECTOR:
return cp_parser_objc_selector_expression (parser);
default:
break;
}
default:
error ("misplaced `@%D' Objective-C++ construct", kwd->value);
cp_parser_skip_to_end_of_block_or_statement (parser);
}
return error_mark_node;
}
static tree
cp_parser_objc_message_expression (cp_parser* parser)
{
tree receiver, messageargs;
cp_lexer_consume_token (parser->lexer);
receiver = cp_parser_objc_message_receiver (parser);
messageargs = cp_parser_objc_message_args (parser);
cp_parser_require (parser, CPP_CLOSE_SQUARE, "`]'");
return objc_build_message_expr (build_tree_list (receiver, messageargs));
}
static tree
cp_parser_objc_message_receiver (cp_parser* parser)
{
tree rcv;
cp_parser_parse_tentatively (parser);
rcv = cp_parser_expression (parser, false);
if (cp_parser_parse_definitely (parser))
return rcv;
rcv = cp_parser_simple_type_specifier (parser,
NULL,
CP_PARSER_FLAGS_NONE);
return objc_get_class_reference (rcv);
}
static tree
cp_parser_objc_message_args (cp_parser* parser)
{
tree sel_args = NULL_TREE, addl_args = NULL_TREE;
bool maybe_unary_selector_p = true;
cp_token *token = cp_lexer_peek_token (parser->lexer);
while (cp_parser_objc_selector_p (token->type) || token->type == CPP_COLON)
{
tree selector = NULL_TREE, arg;
if (token->type != CPP_COLON)
selector = cp_parser_objc_selector (parser);
if (maybe_unary_selector_p
&& cp_lexer_next_token_is_not (parser->lexer, CPP_COLON))
return build_tree_list (selector, NULL_TREE);
maybe_unary_selector_p = false;
cp_parser_require (parser, CPP_COLON, "`:'");
arg = cp_parser_assignment_expression (parser, false);
sel_args
= chainon (sel_args,
build_tree_list (selector, arg));
token = cp_lexer_peek_token (parser->lexer);
}
while (token->type == CPP_COMMA)
{
tree arg;
cp_lexer_consume_token (parser->lexer);
arg = cp_parser_assignment_expression (parser, false);
addl_args
= chainon (addl_args,
build_tree_list (NULL_TREE, arg));
token = cp_lexer_peek_token (parser->lexer);
}
if (sel_args == NULL_TREE && addl_args == NULL_TREE)
{
cp_parser_error (parser, "objective-c++ message argument(s) are expected");
return build_tree_list (error_mark_node, error_mark_node);
}
return build_tree_list (sel_args, addl_args);
}
static tree
cp_parser_objc_encode_expression (cp_parser* parser)
{
tree type;
cp_lexer_consume_token (parser->lexer);
cp_parser_require (parser, CPP_OPEN_PAREN, "`('");
type = complete_type (cp_parser_type_id (parser));
cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
if (!type)
{
error ("`@encode' must specify a type as an argument");
return error_mark_node;
}
if (dependent_type_p (type))
{
tree value = build_min (AT_ENCODE_EXPR, size_type_node, type);
TREE_READONLY (value) = 1;
return value;
}
return objc_build_encode_expr (type);
}
static tree
cp_parser_objc_defs_expression (cp_parser *parser)
{
tree name;
cp_lexer_consume_token (parser->lexer);
cp_parser_require (parser, CPP_OPEN_PAREN, "`('");
name = cp_parser_identifier (parser);
cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
return objc_get_class_ivars (name);
}
static tree
cp_parser_objc_protocol_expression (cp_parser* parser)
{
tree proto;
cp_lexer_consume_token (parser->lexer);
cp_parser_require (parser, CPP_OPEN_PAREN, "`('");
proto = cp_parser_identifier (parser);
cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
return objc_build_protocol_expr (proto);
}
static tree
cp_parser_objc_selector_expression (cp_parser* parser)
{
tree sel_seq = NULL_TREE;
bool maybe_unary_selector_p = true;
cp_token *token;
cp_lexer_consume_token (parser->lexer);
cp_parser_require (parser, CPP_OPEN_PAREN, "`('");
token = cp_lexer_peek_token (parser->lexer);
while (cp_parser_objc_selector_p (token->type) || token->type == CPP_COLON)
{
tree selector = NULL_TREE;
if (token->type != CPP_COLON)
selector = cp_parser_objc_selector (parser);
if (maybe_unary_selector_p
&& cp_lexer_next_token_is_not (parser->lexer, CPP_COLON))
{
sel_seq = selector;
goto finish_selector;
}
maybe_unary_selector_p = false;
cp_parser_require (parser, CPP_COLON, "`:'");
sel_seq
= chainon (sel_seq,
build_tree_list (selector, NULL_TREE));
token = cp_lexer_peek_token (parser->lexer);
}
finish_selector:
cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
return objc_build_selector_expr (sel_seq);
}
static tree
cp_parser_objc_identifier_list (cp_parser* parser)
{
tree list = build_tree_list (NULL_TREE, cp_parser_identifier (parser));
cp_token *sep = cp_lexer_peek_token (parser->lexer);
while (sep->type == CPP_COMMA)
{
cp_lexer_consume_token (parser->lexer);
list = chainon (list,
build_tree_list (NULL_TREE,
cp_parser_identifier (parser)));
sep = cp_lexer_peek_token (parser->lexer);
}
return list;
}
static void
cp_parser_objc_alias_declaration (cp_parser* parser)
{
tree alias, orig;
cp_lexer_consume_token (parser->lexer);
alias = cp_parser_identifier (parser);
orig = cp_parser_identifier (parser);
objc_declare_alias (alias, orig);
cp_parser_consume_semicolon_at_end_of_statement (parser);
}
static void
cp_parser_objc_class_declaration (cp_parser* parser)
{
cp_lexer_consume_token (parser->lexer);
objc_declare_class (cp_parser_objc_identifier_list (parser));
cp_parser_consume_semicolon_at_end_of_statement (parser);
}
static tree
cp_parser_objc_protocol_refs_opt (cp_parser* parser)
{
tree protorefs = NULL_TREE;
if(cp_lexer_next_token_is (parser->lexer, CPP_LESS))
{
cp_lexer_consume_token (parser->lexer);
protorefs = cp_parser_objc_identifier_list (parser);
cp_parser_require (parser, CPP_GREATER, "`>'");
}
return protorefs;
}
static void
cp_parser_objc_visibility_spec (cp_parser* parser)
{
cp_token *vis = cp_lexer_peek_token (parser->lexer);
switch (vis->keyword)
{
case RID_AT_PRIVATE:
objc_set_visibility (2);
break;
case RID_AT_PROTECTED:
objc_set_visibility (0);
break;
case RID_AT_PUBLIC:
objc_set_visibility (1);
break;
case RID_AT_PACKAGE:
objc_set_visibility (3);
break;
default:
return;
}
cp_lexer_consume_token (parser->lexer);
}
static void
cp_parser_objc_method_type (cp_parser* parser)
{
objc_set_method_type
(cp_lexer_consume_token (parser->lexer)->type == CPP_PLUS
? PLUS_EXPR
: MINUS_EXPR);
}
static tree
cp_parser_objc_protocol_qualifiers (cp_parser* parser)
{
tree quals = NULL_TREE, node;
cp_token *token = cp_lexer_peek_token (parser->lexer);
node = token->value;
while (node && TREE_CODE (node) == IDENTIFIER_NODE
&& (node == ridpointers [(int) RID_IN]
|| node == ridpointers [(int) RID_OUT]
|| node == ridpointers [(int) RID_INOUT]
|| node == ridpointers [(int) RID_BYCOPY]
|| node == ridpointers [(int) RID_BYREF]
|| node == ridpointers [(int) RID_ONEWAY]))
{
quals = tree_cons (NULL_TREE, node, quals);
cp_lexer_consume_token (parser->lexer);
token = cp_lexer_peek_token (parser->lexer);
node = token->value;
}
return quals;
}
static tree
cp_parser_objc_typename (cp_parser* parser)
{
tree typename = NULL_TREE;
if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN))
{
tree proto_quals, cp_type = NULL_TREE;
cp_lexer_consume_token (parser->lexer);
proto_quals = cp_parser_objc_protocol_qualifiers (parser);
if (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_PAREN))
cp_type = cp_parser_type_id (parser);
cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
typename = build_tree_list (proto_quals, cp_type);
}
return typename;
}
static bool
cp_parser_objc_selector_p (enum cpp_ttype type)
{
return (type == CPP_NAME || type == CPP_KEYWORD
|| type == CPP_AND_AND || type == CPP_AND_EQ || type == CPP_AND
|| type == CPP_OR || type == CPP_COMPL || type == CPP_NOT
|| type == CPP_NOT_EQ || type == CPP_OR_OR || type == CPP_OR_EQ
|| type == CPP_XOR || type == CPP_XOR_EQ);
}
static tree
cp_parser_objc_selector (cp_parser* parser)
{
cp_token *token = cp_lexer_consume_token (parser->lexer);
if (!cp_parser_objc_selector_p (token->type))
{
error ("invalid Objective-C++ selector name");
return error_mark_node;
}
switch (token->type)
{
case CPP_AND_AND: return get_identifier ("and");
case CPP_AND_EQ: return get_identifier ("and_eq");
case CPP_AND: return get_identifier ("bitand");
case CPP_OR: return get_identifier ("bitor");
case CPP_COMPL: return get_identifier ("compl");
case CPP_NOT: return get_identifier ("not");
case CPP_NOT_EQ: return get_identifier ("not_eq");
case CPP_OR_OR: return get_identifier ("or");
case CPP_OR_EQ: return get_identifier ("or_eq");
case CPP_XOR: return get_identifier ("xor");
case CPP_XOR_EQ: return get_identifier ("xor_eq");
default: return token->value;
}
}
static void
cp_parser_objc_maybe_attributes (cp_parser* parser, tree* attributes)
{
cp_token *token = cp_lexer_peek_token (parser->lexer);
if (*attributes != NULL_TREE)
{
error ("method attributes must be specified at the end only");
*attributes = NULL_TREE;
}
if (token->keyword == RID_ATTRIBUTE)
*attributes = cp_parser_attributes_opt (parser);
}
static tree
cp_parser_objc_method_keyword_params (cp_parser* parser, tree* attributes)
{
tree params = NULL_TREE;
bool maybe_unary_selector_p = true;
cp_token *token = cp_lexer_peek_token (parser->lexer);
while (cp_parser_objc_selector_p (token->type) || token->type == CPP_COLON)
{
tree selector = NULL_TREE, typename, identifier;
if (token->type != CPP_COLON)
selector = cp_parser_objc_selector (parser);
if (maybe_unary_selector_p
&& cp_lexer_next_token_is_not (parser->lexer, CPP_COLON))
{
cp_parser_objc_maybe_attributes (parser, attributes);
if (cp_lexer_next_token_is_not (parser->lexer, CPP_COLON))
return selector;
}
maybe_unary_selector_p = false;
cp_parser_require (parser, CPP_COLON, "`:'");
typename = cp_parser_objc_typename (parser);
identifier = cp_parser_identifier (parser);
cp_parser_objc_maybe_attributes (parser, attributes);
params
= chainon (params,
objc_build_keyword_decl (selector,
typename,
identifier));
token = cp_lexer_peek_token (parser->lexer);
}
if (params == NULL_TREE)
{
cp_parser_error (parser, "objective-c++ method declaration is expected");
return error_mark_node;
}
return params;
}
static tree
cp_parser_objc_method_tail_params_opt (cp_parser* parser, tree* attributes)
{
tree params = make_node (TREE_LIST);
cp_token *token = cp_lexer_peek_token (parser->lexer);
TREE_OVERFLOW (params) = 0;
while (token->type == CPP_COMMA)
{
cp_parameter_declarator *parmdecl;
tree parm;
cp_lexer_consume_token (parser->lexer);
token = cp_lexer_peek_token (parser->lexer);
if (token->type == CPP_ELLIPSIS)
{
cp_lexer_consume_token (parser->lexer);
TREE_OVERFLOW (params) = 1;
cp_parser_objc_maybe_attributes (parser, attributes);
break;
}
parmdecl = cp_parser_parameter_declaration (parser, false, NULL);
parm = grokdeclarator (parmdecl->declarator,
&parmdecl->decl_specifiers,
PARM, 0,
NULL);
chainon (params, build_tree_list (NULL_TREE, parm));
token = cp_lexer_peek_token (parser->lexer);
}
return params;
}
static void
cp_parser_objc_interstitial_code (cp_parser* parser)
{
cp_token *token = cp_lexer_peek_token (parser->lexer);
if (token->keyword == RID_EXTERN
&& cp_parser_is_string_literal (cp_lexer_peek_nth_token (parser->lexer, 2)))
cp_parser_linkage_specification (parser);
else if (token->type == CPP_PRAGMA)
cp_lexer_handle_pragma (parser->lexer);
else if (token->type == CPP_SEMICOLON)
cp_lexer_consume_token (parser->lexer);
else if (token->keyword == RID_AT_OPTIONAL)
{
cp_lexer_consume_token (parser->lexer);
objc_set_method_opt (1);
}
else if (token->keyword == RID_AT_REQUIRED)
{
cp_lexer_consume_token (parser->lexer);
objc_set_method_opt (0);
}
else if (token->keyword == RID_NAMESPACE)
cp_parser_namespace_definition (parser);
else if (token->type == CPP_OPEN_BRACE || token->type == CPP_CLOSE_BRACE)
{
cp_lexer_consume_token (parser->lexer);
error ("stray `%s' between Objective-C++ methods",
token->type == CPP_OPEN_BRACE ? "{" : "}");
}
else
cp_parser_block_declaration (parser, false);
}
static tree
cp_parser_objc_method_signature (cp_parser* parser, tree* attributes)
{
tree rettype, kwdparms, optparms;
cp_parser_objc_method_type (parser);
rettype = cp_parser_objc_typename (parser);
*attributes = NULL_TREE;
kwdparms = cp_parser_objc_method_keyword_params (parser, attributes);
optparms = cp_parser_objc_method_tail_params_opt (parser, attributes);
return objc_build_method_signature (rettype, kwdparms, optparms);
}
static void
cp_parser_objc_method_prototype_list (cp_parser* parser)
{
cp_token *token = cp_lexer_peek_token (parser->lexer);
while (token->keyword != RID_AT_END && token->type != CPP_EOF)
{
if (token->type == CPP_PLUS || token->type == CPP_MINUS)
{
tree attributes, sig;
sig = cp_parser_objc_method_signature (parser, &attributes);
objc_add_method_declaration (sig, attributes);
cp_parser_consume_semicolon_at_end_of_statement (parser);
}
else if (token->keyword == RID_AT_PROPERTY)
objc_cp_parser_at_property (parser);
else
cp_parser_objc_interstitial_code (parser);
token = cp_lexer_peek_token (parser->lexer);
}
cp_parser_require_keyword (parser, RID_AT_END, "`@end'");
objc_finish_interface ();
}
static void
cp_parser_objc_method_definition_list (cp_parser* parser)
{
cp_token *token = cp_lexer_peek_token (parser->lexer);
while (token->keyword != RID_AT_END && token->type != CPP_EOF)
{
tree meth;
if (token->type == CPP_PLUS || token->type == CPP_MINUS)
{
cp_token *ptk;
tree sig, attribute;
push_deferring_access_checks (dk_deferred);
sig = cp_parser_objc_method_signature (parser, &attribute);
objc_start_method_definition (sig, attribute);
if (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON))
cp_lexer_consume_token (parser->lexer);
ptk = cp_lexer_peek_token (parser->lexer);
if (!(ptk->type == CPP_PLUS || ptk->type == CPP_MINUS
|| ptk->type == CPP_EOF || ptk->keyword == RID_AT_END))
{
perform_deferred_access_checks ();
stop_deferring_access_checks ();
meth = cp_parser_function_definition_after_declarator (parser,
false);
pop_deferring_access_checks ();
objc_finish_method_definition (meth);
}
}
else if (token->keyword == RID_AT_PROPERTY)
objc_cp_parser_at_property (parser);
else if (token->keyword == RID_AT_SYNTHESIZE
|| token->keyword == RID_AT_DYNAMIC)
objc_cp_parser_property_impl (parser, token->keyword);
else
cp_parser_objc_interstitial_code (parser);
token = cp_lexer_peek_token (parser->lexer);
}
cp_parser_require_keyword (parser, RID_AT_END, "`@end'");
objc_finish_implementation ();
}
static void
cp_parser_objc_class_ivars (cp_parser* parser)
{
cp_token *token = cp_lexer_peek_token (parser->lexer);
if (token->type != CPP_OPEN_BRACE)
return;
cp_lexer_consume_token (parser->lexer);
token = cp_lexer_peek_token (parser->lexer);
while (token->type != CPP_CLOSE_BRACE
&& token->keyword != RID_AT_END && token->type != CPP_EOF)
{
cp_decl_specifier_seq declspecs;
int decl_class_or_enum_p;
tree prefix_attributes;
cp_parser_objc_visibility_spec (parser);
if (cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_BRACE))
break;
cp_parser_decl_specifier_seq (parser,
CP_PARSER_FLAGS_OPTIONAL,
&declspecs,
&decl_class_or_enum_p);
if (declspecs.storage_class == sc_static)
{
error ("storage class specified for ivar");
declspecs.storage_class = sc_none;
}
else if (declspecs.specs[(int) ds_typedef])
{
error ("typedef declaration among ivars");
cp_lexer_consume_token (parser->lexer);
}
prefix_attributes = declspecs.attributes;
declspecs.attributes = NULL_TREE;
while (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON))
{
tree width = NULL_TREE, attributes, first_attribute, decl;
cp_declarator *declarator = NULL;
int ctor_dtor_or_conv_p;
token = cp_lexer_peek_token (parser->lexer);
if (token->type == CPP_COLON)
goto eat_colon;
if (token->type == CPP_NAME
&& (cp_lexer_peek_nth_token (parser->lexer, 2)->type
== CPP_COLON))
{
declarator = make_id_declarator (NULL_TREE,
cp_parser_identifier (parser),
sfk_none);
eat_colon:
cp_lexer_consume_token (parser->lexer);
width
= cp_parser_constant_expression (parser,
false,
NULL);
}
else
{
declarator
= cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED,
&ctor_dtor_or_conv_p,
NULL,
false);
}
attributes = cp_parser_attributes_opt (parser);
first_attribute = attributes;
attributes = chainon (prefix_attributes, attributes);
if (width)
{
decl = grokbitfield (declarator, &declspecs, width);
cplus_decl_attributes (&decl, attributes, 0);
}
else
decl = grokfield (declarator, &declspecs, NULL_TREE,
NULL_TREE, attributes);
objc_add_instance_variable (decl);
while (attributes && TREE_CHAIN (attributes) != first_attribute)
attributes = TREE_CHAIN (attributes);
if (attributes)
TREE_CHAIN (attributes) = NULL_TREE;
token = cp_lexer_peek_token (parser->lexer);
if (token->type == CPP_COMMA)
{
cp_lexer_consume_token (parser->lexer);
continue;
}
break;
}
cp_parser_consume_semicolon_at_end_of_statement (parser);
token = cp_lexer_peek_token (parser->lexer);
}
cp_lexer_consume_token (parser->lexer);
if (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON))
cp_lexer_consume_token (parser->lexer);
}
static void
cp_parser_objc_protocol_declaration (cp_parser* parser)
{
tree proto, protorefs;
cp_token *tok;
cp_lexer_consume_token (parser->lexer);
if (cp_lexer_next_token_is_not (parser->lexer, CPP_NAME))
{
error ("identifier expected after `@protocol'");
goto finish;
}
tok = cp_lexer_peek_nth_token (parser->lexer, 2);
if (tok->type == CPP_COMMA || tok->type == CPP_SEMICOLON)
{
objc_declare_protocols (cp_parser_objc_identifier_list (parser));
finish:
cp_parser_consume_semicolon_at_end_of_statement (parser);
}
else
{
proto = cp_parser_identifier (parser);
protorefs = cp_parser_objc_protocol_refs_opt (parser);
objc_start_protocol (proto, protorefs);
cp_parser_objc_method_prototype_list (parser);
}
}
static void
cp_parser_objc_superclass_or_category (cp_parser *parser, tree *super,
tree *categ, bool *is_category)
{
cp_token *next = cp_lexer_peek_token (parser->lexer);
*super = *categ = NULL_TREE;
*is_category = false;
if (next->type == CPP_COLON)
{
cp_lexer_consume_token (parser->lexer);
*super = cp_parser_identifier (parser);
}
else if (next->type == CPP_OPEN_PAREN)
{
cp_lexer_consume_token (parser->lexer);
next = cp_lexer_peek_token (parser->lexer);
*categ = (next->type == CPP_CLOSE_PAREN) ? NULL_TREE : cp_parser_identifier (parser);
*is_category = true;
cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
}
}
static void
cp_parser_objc_class_interface (cp_parser* parser)
{
tree name, super, categ, protos;
bool is_categ;
tree attributes = NULL_TREE;
cp_parser_objc_maybe_attributes (parser, &attributes);
cp_lexer_consume_token (parser->lexer);
name = cp_parser_identifier (parser);
cp_parser_objc_superclass_or_category (parser, &super, &categ, &is_categ);
protos = cp_parser_objc_protocol_refs_opt (parser);
if (is_categ)
{
if (attributes)
error ("attributes may not be specified on a category");
objc_start_category_interface (name, categ, protos);
}
else
{
objc_start_class_interface (name, super, protos, attributes);
cp_parser_objc_class_ivars (parser);
objc_continue_interface ();
}
cp_parser_objc_method_prototype_list (parser);
}
static void
cp_parser_objc_class_implementation (cp_parser* parser)
{
tree name, super, categ;
bool is_categ;
cp_lexer_consume_token (parser->lexer);
if(cp_lexer_next_token_is (parser->lexer, CPP_LESS))
{
tree protorefs;
cp_lexer_consume_token (parser->lexer);
protorefs = cp_parser_objc_identifier_list (parser);
cp_parser_require (parser, CPP_GREATER, "`>'");
objc_protocol_implementation (protorefs);
return;
}
name = cp_parser_identifier (parser);
cp_parser_objc_superclass_or_category (parser, &super, &categ, &is_categ);
if (is_categ)
{
if (categ == NULL_TREE)
{
error ("cannot implement anonymous category");
return;
}
objc_start_category_implementation (name, categ);
}
else
{
objc_start_class_implementation (name, super);
cp_parser_objc_class_ivars (parser);
objc_continue_implementation ();
}
cp_parser_objc_method_definition_list (parser);
}
static void
cp_parser_objc_end_implementation (cp_parser* parser)
{
cp_lexer_consume_token (parser->lexer);
objc_finish_implementation ();
}
static void
cp_parser_objc_declaration (cp_parser* parser)
{
cp_token *kwd = cp_lexer_peek_token (parser->lexer);
switch (kwd->keyword)
{
case RID_AT_ALIAS:
cp_parser_objc_alias_declaration (parser);
break;
case RID_AT_CLASS:
cp_parser_objc_class_declaration (parser);
break;
case RID_AT_PROTOCOL:
cp_parser_objc_protocol_declaration (parser);
break;
case RID_ATTRIBUTE:
case RID_AT_INTERFACE:
cp_parser_objc_class_interface (parser);
break;
case RID_AT_IMPLEMENTATION:
cp_parser_objc_class_implementation (parser);
break;
case RID_AT_END:
cp_parser_objc_end_implementation (parser);
break;
default:
error ("misplaced `@%D' Objective-C++ construct", kwd->value);
cp_parser_skip_to_end_of_block_or_statement (parser);
}
}
static tree
cp_parser_objc_try_catch_finally_statement (cp_parser *parser) {
location_t location;
tree stmt;
cp_parser_require_keyword (parser, RID_AT_TRY, "`@try'");
location = cp_lexer_peek_token (parser->lexer)->location;
stmt = push_stmt_list ();
cp_parser_compound_statement (parser, NULL, false);
objc_begin_try_stmt (location, pop_stmt_list (stmt));
while (cp_lexer_next_token_is_keyword (parser->lexer, RID_AT_CATCH))
{
cp_parameter_declarator *parmdecl;
tree parm;
bool ellipsis_seen = false;
cp_lexer_consume_token (parser->lexer);
cp_parser_require (parser, CPP_OPEN_PAREN, "`('");
{
cp_token *token = cp_lexer_peek_token (parser->lexer);
if (token->type == CPP_ELLIPSIS)
{
parm = NULL_TREE;
cp_lexer_consume_token (parser->lexer);
ellipsis_seen = true;
}
}
if (!ellipsis_seen)
{
parmdecl = cp_parser_parameter_declaration (parser, false, NULL);
parm = grokdeclarator (parmdecl->declarator,
&parmdecl->decl_specifiers,
PARM, 0,
NULL);
}
cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
objc_begin_catch_clause (parm);
cp_parser_compound_statement (parser, NULL, false);
objc_finish_catch_clause ();
}
if (cp_lexer_next_token_is_keyword (parser->lexer, RID_AT_FINALLY))
{
cp_lexer_consume_token (parser->lexer);
location = cp_lexer_peek_token (parser->lexer)->location;
stmt = push_stmt_list ();
cp_parser_compound_statement (parser, NULL, false);
objc_build_finally_clause (location, pop_stmt_list (stmt));
}
return objc_finish_try_stmt ();
}
static tree
cp_parser_objc_synchronized_statement (cp_parser *parser) {
location_t location;
tree lock, stmt;
cp_parser_require_keyword (parser, RID_AT_SYNCHRONIZED, "`@synchronized'");
location = cp_lexer_peek_token (parser->lexer)->location;
cp_parser_require (parser, CPP_OPEN_PAREN, "`('");
lock = cp_parser_expression (parser, false);
cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
stmt = push_stmt_list ();
cp_parser_compound_statement (parser, NULL, false);
return objc_build_synchronized (location, lock, pop_stmt_list (stmt));
}
static tree
cp_parser_objc_throw_statement (cp_parser *parser) {
tree expr = NULL_TREE;
cp_parser_require_keyword (parser, RID_AT_THROW, "`@throw'");
if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON))
expr = cp_parser_assignment_expression (parser, false);
cp_parser_consume_semicolon_at_end_of_statement (parser);
return objc_build_throw_stmt (expr);
}
static tree
cp_parser_objc_statement (cp_parser * parser) {
cp_token *kwd = cp_lexer_peek_token (parser->lexer);
switch (kwd->keyword)
{
case RID_AT_TRY:
return cp_parser_objc_try_catch_finally_statement (parser);
case RID_AT_SYNCHRONIZED:
return cp_parser_objc_synchronized_statement (parser);
case RID_AT_THROW:
return cp_parser_objc_throw_statement (parser);
default:
error ("misplaced `@%D' Objective-C++ construct", kwd->value);
cp_parser_skip_to_end_of_block_or_statement (parser);
}
return error_mark_node;
}
static void
objc_finish_foreach_stmt (tree for_stmt)
{
if (flag_new_for_scope > 0)
{
tree scope = TREE_CHAIN (for_stmt);
TREE_CHAIN (for_stmt) = NULL;
add_stmt (do_poplevel (scope));
}
finish_stmt ();
}
static void
objc_foreach_stmt (cp_parser* parser, tree statement)
{
bool in_iteration_statement_p;
tree enumerationMutation_call_exp;
tree countByEnumeratingWithState;
tree receiver;
tree exp, bind;
tree enumState_decl, items_decl;
tree limit_decl, limit_decl_assign_expr;
tree outer_if_stmt, inner_if_stmt, if_condition, startMutations_decl;
tree outer_do_stmt, inner_do_stmt, do_condition;
tree counter_decl;
tree_stmt_iterator i = tsi_start (TREE_CHAIN (statement));
tree t = tsi_stmt (i);
tree elem_decl = TREE_CODE (t) == DECL_EXPR ? DECL_EXPR_DECL (t) : t;
receiver = cp_parser_condition (parser);
cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
if (elem_decl == error_mark_node)
return;
if (!lvalue_p (elem_decl))
{
error ("selector element must be an lvalue");
return;
}
if (!objc_type_valid_for_messaging (TREE_TYPE (elem_decl)))
{
error ("selector element does not have a valid object type");
return;
}
if (!objc_type_valid_for_messaging (TREE_TYPE (receiver)))
{
error ("expression does not have a valid object type");
return;
}
enumerationMutation_call_exp = objc_build_foreach_components (receiver, &enumState_decl,
&items_decl, &limit_decl,
&startMutations_decl, &counter_decl,
&countByEnumeratingWithState);
exp = build_stmt (DECL_EXPR, enumState_decl);
bind = build (BIND_EXPR, void_type_node, enumState_decl, exp, NULL);
TREE_SIDE_EFFECTS (bind) = 1;
add_stmt (bind);
bind = build (BIND_EXPR, void_type_node, items_decl, NULL, NULL);
TREE_SIDE_EFFECTS (bind) = 1;
add_stmt (bind);
limit_decl_assign_expr = build (MODIFY_EXPR, TREE_TYPE (limit_decl), limit_decl,
countByEnumeratingWithState);
bind = build (BIND_EXPR, void_type_node, limit_decl, NULL, NULL);
TREE_SIDE_EFFECTS (bind) = 1;
add_stmt (bind);
outer_if_stmt = begin_if_stmt ();
if_condition = build_binary_op (NE_EXPR, limit_decl_assign_expr,
fold_convert (TREE_TYPE (limit_decl), integer_zero_node),
1);
finish_if_stmt_cond (if_condition, outer_if_stmt);
exp = objc_build_component_ref (enumState_decl, get_identifier("mutationsPtr"));
exp = build_indirect_ref (exp, "unary *");
exp = build (MODIFY_EXPR, void_type_node, startMutations_decl, exp);
bind = build (BIND_EXPR, void_type_node, startMutations_decl, exp, NULL);
TREE_SIDE_EFFECTS (bind) = 1;
add_stmt (bind);
outer_do_stmt = begin_do_stmt ();
exp = build (MODIFY_EXPR, void_type_node, counter_decl,
fold_convert (TREE_TYPE (counter_decl), integer_zero_node));
bind = build (BIND_EXPR, void_type_node, counter_decl, exp, NULL);
TREE_SIDE_EFFECTS (bind) = 1;
add_stmt (bind);
inner_do_stmt = begin_do_stmt ();
inner_if_stmt = begin_if_stmt ();
exp = objc_build_component_ref (enumState_decl, get_identifier("mutationsPtr"));
exp = build_indirect_ref (exp, "unary *");
if_condition = build_binary_op (NE_EXPR, startMutations_decl, exp, 1);
finish_if_stmt_cond (if_condition, inner_if_stmt);
add_stmt (enumerationMutation_call_exp);
finish_then_clause (inner_if_stmt);
finish_if_stmt (inner_if_stmt);
exp = objc_build_component_ref (enumState_decl, get_identifier("itemsPtr"));
exp = build_array_ref (exp, counter_decl);
add_stmt (build (MODIFY_EXPR, void_type_node, elem_decl, exp));
TREE_USED (elem_decl) = 1;
exp = build2 (PLUS_EXPR, TREE_TYPE (counter_decl), counter_decl,
build_int_cst (NULL_TREE, 1));
add_stmt (build (MODIFY_EXPR, void_type_node, counter_decl, exp));
in_iteration_statement_p = parser->in_iteration_statement_p;
parser->in_iteration_statement_p = true;
cp_parser_already_scoped_statement (parser);
parser->in_iteration_statement_p = in_iteration_statement_p;
finish_do_body (inner_do_stmt);
do_condition = build_binary_op (LT_EXPR, counter_decl, limit_decl, 1);
finish_do_stmt (do_condition, inner_do_stmt);
DO_FOREACH (inner_do_stmt) = integer_zero_node;
DO_FOREACH (outer_do_stmt) = elem_decl;
finish_do_body (outer_do_stmt);
exp = unshare_expr (limit_decl_assign_expr);
do_condition = build_binary_op (NE_EXPR, exp,
fold_convert (TREE_TYPE (limit_decl), integer_zero_node),
1);
finish_do_stmt (do_condition, outer_do_stmt);
finish_then_clause (outer_if_stmt);
begin_else_clause (outer_if_stmt);
add_stmt (build (MODIFY_EXPR, void_type_node, elem_decl,
fold_convert (TREE_TYPE (elem_decl), integer_zero_node)));
finish_else_clause (outer_if_stmt);
finish_if_stmt (outer_if_stmt);
objc_finish_foreach_stmt (statement);
}
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"