/* The cp_lexer_* routines mediate between the lexer proper (in libcpp
and c-lex.c) and the C++ parser. */
+/* A token's value and its associated deferred access checks and
+ qualifying scope. */
+
+struct tree_check GTY(())
+{
+ /* The value associated with the token. */
+ tree value;
+ /* The checks that have been associated with value. */
+ VEC (deferred_access_check, gc)* checks;
+ /* The token's qualifying scope (used when it is a
+ CPP_NESTED_NAME_SPECIFIER). */
+ tree qualifying_scope;
+};
+
/* A C++ token. */
typedef struct cp_token GTY (())
KEYWORD is RID_MAX) iff this name was looked up and found to be
ambiguous. An error has already been reported. */
BOOL_BITFIELD ambiguous_p : 1;
+ /* The input file stack index at which this token was found. */
+ unsigned input_file_stack_index : INPUT_FILE_STACK_BITS;
/* The value associated with this token, if any. */
- tree value;
+ union cp_token_value {
+ /* Used for CPP_NESTED_NAME_SPECIFIER and CPP_TEMPLATE_ID. */
+ struct tree_check* GTY((tag ("1"))) tree_check_value;
+ /* Use for all other tokens. */
+ tree GTY((tag ("0"))) value;
+ } GTY((desc ("(%1.type == CPP_TEMPLATE_ID) || (%1.type == CPP_NESTED_NAME_SPECIFIER)"))) u;
/* The location at which this token was found. */
location_t location;
} cp_token;
static const cp_token eof_token =
{
- CPP_EOF, RID_MAX, 0, PRAGMA_NONE, 0, 0, false, NULL_TREE,
+ CPP_EOF, RID_MAX, 0, PRAGMA_NONE, 0, 0, false, 0, { NULL },
#if USE_MAPPED_LOCATION
0
#else
(cp_token *);
/* Manifest constants. */
-#define CP_LEXER_BUFFER_SIZE 10000
+#define CP_LEXER_BUFFER_SIZE ((256 * 1024) / sizeof (cp_token))
#define CP_SAVED_TOKEN_STACK 5
/* A token type for keywords, as opposed to ordinary identifiers. */
/* Get a new token from the preprocessor. */
token->type
- = c_lex_with_flags (&token->value, &token->location, &token->flags);
+ = c_lex_with_flags (&token->u.value, &token->location, &token->flags);
+ token->input_file_stack_index = input_file_stack_tick;
token->keyword = RID_MAX;
token->pragma_kind = PRAGMA_NONE;
token->in_system_header = in_system_header;
/* Check to see if this token is a keyword. */
if (token->type == CPP_NAME)
{
- if (C_IS_RESERVED_WORD (token->value))
+ if (C_IS_RESERVED_WORD (token->u.value))
{
/* Mark this token as a keyword. */
token->type = CPP_KEYWORD;
/* Record which keyword. */
- token->keyword = C_RID_CODE (token->value);
+ token->keyword = C_RID_CODE (token->u.value);
/* Update the value. Some keywords are mapped to particular
entities, rather than simply having the value of the
corresponding IDENTIFIER_NODE. For example, `__const' is
mapped to `const'. */
- token->value = ridpointers[token->keyword];
+ token->u.value = ridpointers[token->keyword];
}
else
{
+ if (warn_cxx0x_compat
+ && C_RID_CODE (token->u.value) >= RID_FIRST_CXX0X
+ && C_RID_CODE (token->u.value) <= RID_LAST_CXX0X)
+ {
+ /* Warn about the C++0x keyword (but still treat it as
+ an identifier). */
+ warning (OPT_Wc__0x_compat,
+ "identifier %<%s%> will become a keyword in C++0x",
+ IDENTIFIER_POINTER (token->u.value));
+
+ /* Clear out the C_RID_CODE so we don't warn about this
+ particular identifier-turned-keyword again. */
+ C_RID_CODE (token->u.value) = RID_MAX;
+ }
+
token->ambiguous_p = false;
token->keyword = RID_MAX;
}
else if (token->type == CPP_AT_NAME)
{
token->type = CPP_KEYWORD;
- switch (C_RID_CODE (token->value))
+ switch (C_RID_CODE (token->u.value))
{
/* Map 'class' to '@class', 'private' to '@private', etc. */
case RID_CLASS: token->keyword = RID_AT_CLASS; 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);
+ default: token->keyword = C_RID_CODE (token->u.value);
}
}
else if (token->type == CPP_PRAGMA)
{
/* We smuggled the cpp_token->u.pragma value in an INTEGER_CST. */
- token->pragma_kind = TREE_INT_CST_LOW (token->value);
- token->value = NULL;
+ token->pragma_kind = TREE_INT_CST_LOW (token->u.value);
+ token->u.value = NULL_TREE;
}
}
-/* Update the globals input_location and in_system_header from TOKEN. */
+/* Update the globals input_location and in_system_header and the
+ input file stack from TOKEN. */
static inline void
cp_lexer_set_source_position_from_token (cp_token *token)
{
{
input_location = token->location;
in_system_header = token->in_system_header;
+ restore_input_file_stack (token->input_file_stack_index);
}
}
return cp_lexer_peek_token (lexer)->keyword == keyword;
}
+/* Return true if the next token is a keyword for a decl-specifier. */
+
+static bool
+cp_lexer_next_token_is_decl_specifier_keyword (cp_lexer *lexer)
+{
+ cp_token *token;
+
+ token = cp_lexer_peek_token (lexer);
+ switch (token->keyword)
+ {
+ /* Storage classes. */
+ case RID_AUTO:
+ case RID_REGISTER:
+ case RID_STATIC:
+ case RID_EXTERN:
+ case RID_MUTABLE:
+ case RID_THREAD:
+ /* Elaborated type specifiers. */
+ case RID_ENUM:
+ case RID_CLASS:
+ case RID_STRUCT:
+ case RID_UNION:
+ case RID_TYPENAME:
+ /* Simple type specifiers. */
+ case RID_CHAR:
+ case RID_WCHAR:
+ case RID_BOOL:
+ case RID_SHORT:
+ case RID_INT:
+ case RID_LONG:
+ case RID_SIGNED:
+ case RID_UNSIGNED:
+ case RID_FLOAT:
+ case RID_DOUBLE:
+ case RID_VOID:
+ /* GNU extensions. */
+ case RID_ATTRIBUTE:
+ case RID_TYPEOF:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
/* Return a pointer to the Nth token in the token stream. If N is 1,
then this is precisely equivalent to cp_lexer_peek_token (except
that it is not inline). One would like to disallow that case, but
/* N is 1-based, not zero-based. */
gcc_assert (n > 0);
-
+
if (cp_lexer_debugging_p (lexer))
fprintf (cp_lexer_debug_stream,
"cp_lexer: peeking ahead %ld at token: ", (long)n);
gcc_assert (tok != &eof_token);
tok->type = CPP_PURGED;
tok->location = UNKNOWN_LOCATION;
- tok->value = NULL_TREE;
+ tok->u.value = NULL_TREE;
tok->keyword = RID_MAX;
do
{
tok->type = CPP_PURGED;
tok->location = UNKNOWN_LOCATION;
- tok->value = NULL_TREE;
+ tok->u.value = NULL_TREE;
tok->keyword = RID_MAX;
}
}
case CPP_KEYWORD:
/* Some keywords have a value that is not an IDENTIFIER_NODE.
For example, `struct' is mapped to an INTEGER_CST. */
- if (TREE_CODE (token->value) != IDENTIFIER_NODE)
+ if (TREE_CODE (token->u.value) != IDENTIFIER_NODE)
break;
/* else fall through */
case CPP_NAME:
- fputs (IDENTIFIER_POINTER (token->value), stream);
+ fputs (IDENTIFIER_POINTER (token->u.value), stream);
break;
case CPP_STRING:
case CPP_WSTRING:
- fprintf (stream, " \"%s\"", TREE_STRING_POINTER (token->value));
+ fprintf (stream, " \"%s\"", TREE_STRING_POINTER (token->u.value));
break;
default:
return parameter;
}
+/* Returns true iff DECLARATOR is a declaration for a function. */
+
+static bool
+function_declarator_p (const cp_declarator *declarator)
+{
+ while (declarator)
+ {
+ if (declarator->kind == cdk_function
+ && declarator->declarator->kind == cdk_id)
+ return true;
+ if (declarator->kind == cdk_id
+ || declarator->kind == cdk_error)
+ return false;
+ declarator = declarator->declarator;
+ }
+ return false;
+}
+
/* The parser. */
/* Overview
typedef struct cp_parser_expression_stack_entry
{
+ /* Left hand side of the binary operation we are currently
+ parsing. */
tree lhs;
+ /* Original tree code for left hand side, if it was a binary
+ expression itself (used for -Wparentheses). */
+ enum tree_code lhs_type;
+ /* Tree code for the binary operation we are parsing. */
enum tree_code tree_type;
+ /* Precedence of the binary operation we are parsing. */
int prec;
} cp_parser_expression_stack_entry;
{ 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 },
character set. */
bool translate_strings_p;
+ /* TRUE if we are presently parsing the body of a function, but not
+ a local class. */
+ bool in_function_body;
+
/* If non-NULL, then we are parsing a construct where new type
definitions are not permitted. The string stored here will be
issued as an error message if a type is defined. */
/* Statements [gram.stmt.stmt] */
static void cp_parser_statement
- (cp_parser *, tree, bool);
-static tree cp_parser_labeled_statement
- (cp_parser *, tree, bool);
+ (cp_parser *, tree, bool, bool *);
+static void cp_parser_label_for_labeled_statement
+ (cp_parser *);
static tree cp_parser_expression_statement
(cp_parser *, tree);
static tree cp_parser_compound_statement
static void cp_parser_statement_seq_opt
(cp_parser *, tree);
static tree cp_parser_selection_statement
- (cp_parser *);
+ (cp_parser *, bool *);
static tree cp_parser_condition
(cp_parser *);
static tree cp_parser_iteration_statement
(cp_parser *);
static tree cp_parser_implicitly_scoped_statement
- (cp_parser *);
+ (cp_parser *, bool *);
static void cp_parser_already_scoped_statement
(cp_parser *);
(cp_parser *);
static void cp_parser_namespace_alias_definition
(cp_parser *);
-static void cp_parser_using_declaration
- (cp_parser *);
+static bool cp_parser_using_declaration
+ (cp_parser *, bool);
static void cp_parser_using_directive
(cp_parser *);
static void cp_parser_asm_definition
(cp_parser *);
static void cp_parser_linkage_specification
(cp_parser *);
+static void cp_parser_static_assert
+ (cp_parser *, bool);
/* Declarators [gram.dcl.decl] */
static tree cp_parser_init_declarator
- (cp_parser *, cp_decl_specifier_seq *, bool, bool, int, bool *);
+ (cp_parser *, cp_decl_specifier_seq *, VEC (deferred_access_check,gc)*, 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
static tree cp_parser_class_specifier
(cp_parser *);
static tree cp_parser_class_head
- (cp_parser *, bool *, tree *);
+ (cp_parser *, bool *, tree *, tree *);
static enum tag_types cp_parser_class_key
(cp_parser *);
static void cp_parser_member_specification_opt
(cp_parser *, bool);
static void cp_parser_template_declaration_after_export
(cp_parser *, bool);
+static void cp_parser_perform_template_parameter_access_checks
+ (VEC (deferred_access_check,gc)*);
static tree cp_parser_single_declaration
- (cp_parser *, bool, bool *);
+ (cp_parser *, VEC (deferred_access_check,gc)*, bool, bool *);
static tree cp_parser_functional_cast
(cp_parser *, tree);
static tree cp_parser_save_member_function_body
static bool cp_parser_declares_only_class_p
(cp_parser *);
static void cp_parser_set_storage_class
- (cp_decl_specifier_seq *, cp_storage_class);
+ (cp_parser *, cp_decl_specifier_seq *, enum rid);
static void cp_parser_set_decl_spec_type
(cp_decl_specifier_seq *, tree, bool);
static bool cp_parser_friend_p
(cp_parser *, tree, tree, const char *);
static bool cp_parser_simulate_error
(cp_parser *);
-static void cp_parser_check_type_definition
+static bool cp_parser_check_type_definition
(cp_parser *);
static void cp_parser_check_for_definition_in_return_type
(cp_declarator *, tree);
(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 void cp_parser_skip_to_end_of_template_parameter_list
+ (cp_parser *);
static void cp_parser_skip_to_pragma_eol
(cp_parser*, cp_token *);
static bool cp_parser_error_occurred
return token->keyword == keyword;
}
-/* A minimum or maximum operator has been seen. As these are
- deprecated, issue a warning. */
-
-static inline void
-cp_parser_warn_min_max (void)
-{
- if (warn_deprecated && !in_system_header)
- warning (OPT_Wdeprecated, "minimum/maximum operators are deprecated");
-}
-
/* If not parsing tentatively, issue a diagnostic of the form
FILE:LINE: MESSAGE before TOKEN
where TOKEN is the next token in the input stream. MESSAGE
CPP_KEYWORD, keywords are treated like
identifiers. */
(token->type == CPP_KEYWORD ? CPP_NAME : token->type),
- token->value);
+ token->u.value);
}
}
return false;
}
+/* Check for repeated decl-specifiers. */
+
+static void
+cp_parser_check_decl_spec (cp_decl_specifier_seq *decl_specs)
+{
+ cp_decl_spec ds;
+
+ for (ds = ds_first; ds != ds_last; ++ds)
+ {
+ unsigned count = decl_specs->specs[(int)ds];
+ if (count < 2)
+ continue;
+ /* The "long" specifier is a special case because of "long long". */
+ if (ds == ds_long)
+ {
+ if (count > 2)
+ error ("%<long long long%> is too long for GCC");
+ else if (pedantic && !in_system_header && warn_long_long)
+ pedwarn ("ISO C++ does not support %<long long%>");
+ }
+ else if (count > 1)
+ {
+ static const char *const decl_spec_names[] = {
+ "signed",
+ "unsigned",
+ "short",
+ "long",
+ "const",
+ "volatile",
+ "restrict",
+ "inline",
+ "virtual",
+ "explicit",
+ "friend",
+ "typedef",
+ "__complex",
+ "__thread"
+ };
+ error ("duplicate %qs", decl_spec_names[(int)ds]);
+ }
+ }
+}
+
/* This function is called when a type is defined. If type
definitions are forbidden at this point, an error message is
issued. */
-static void
+static bool
cp_parser_check_type_definition (cp_parser* parser)
{
/* If types are forbidden here, issue a message. */
if (parser->type_definition_forbidden_message)
- /* Use `%s' to print the string in case there are any escape
- characters in the message. */
- error ("%s", parser->type_definition_forbidden_message);
+ {
+ /* Use `%s' to print the string in case there are any escape
+ characters in the message. */
+ error ("%s", parser->type_definition_forbidden_message);
+ return false;
+ }
+ return true;
}
/* This function is called when the DECLARATOR is processed. The TYPE
/* If the lookup found a template-name, it means that the user forgot
to specify an argument list. Emit a useful error message. */
if (TREE_CODE (decl) == TEMPLATE_DECL)
- error ("invalid use of template-name %qE without an argument list",
- decl);
+ error ("invalid use of template-name %qE without an argument list", decl);
+ else if (TREE_CODE (id) == BIT_NOT_EXPR)
+ error ("invalid use of destructor %qD as a type", id);
+ else if (TREE_CODE (decl) == TYPE_DECL)
+ /* Something like 'unsigned A a;' */
+ error ("invalid combination of multiple type-specifiers");
else if (!parser->scope)
{
/* Issue an error message. */
form `ID a', where `ID' is an id-expression and `a' is a plain identifier.
Usually, `ID' should name a type, but if we got here it means that it
does not. We try to emit the best possible error message depending on
- how exactly the id-expression looks like.
-*/
+ how exactly the id-expression looks like. */
static bool
cp_parser_parse_and_diagnose_invalid_type_name (cp_parser *parser)
cp_parser_abort_tentative_parse (parser);
return false;
}
- if (!cp_parser_parse_definitely (parser)
- || TREE_CODE (id) != IDENTIFIER_NODE)
+ if (!cp_parser_parse_definitely (parser) || TREE_CODE (id) == TYPE_DECL)
return false;
/* Emit a diagnostic for the invalid type. */
if (TREE_CODE (id) == IDENTIFIER_NODE)
{
result = make_typename_type (scope, id, typename_type,
- /*complain=*/tf_none);
+ /*complain=*/tf_none);
if (result == error_mark_node)
cp_parser_diagnose_invalid_type_name (parser, scope, id);
return result;
/* String literals should be translated to the execution character set. */
parser->translate_strings_p = true;
+ /* We are not parsing a function body. */
+ parser->in_function_body = false;
+
/* The unparsed function queue is empty. */
parser->unparsed_functions_queues = build_tree_list (NULL_TREE, NULL_TREE);
/* Look for the identifier. */
token = cp_parser_require (parser, CPP_NAME, "identifier");
/* Return the value. */
- return token ? token->value : error_mark_node;
+ return token ? token->u.value : error_mark_node;
}
/* Parse a sequence of adjacent string constants. Returns a
{
cp_lexer_consume_token (parser->lexer);
- str.text = (const unsigned char *)TREE_STRING_POINTER (tok->value);
- str.len = TREE_STRING_LENGTH (tok->value);
+ str.text = (const unsigned char *)TREE_STRING_POINTER (tok->u.value);
+ str.len = TREE_STRING_LENGTH (tok->u.value);
count = 1;
if (tok->type == CPP_WSTRING)
wide = true;
{
cp_lexer_consume_token (parser->lexer);
count++;
- str.text = (unsigned char *)TREE_STRING_POINTER (tok->value);
- str.len = TREE_STRING_LENGTH (tok->value);
+ str.text = (unsigned char *)TREE_STRING_POINTER (tok->u.value);
+ str.len = TREE_STRING_LENGTH (tok->u.value);
if (tok->type == CPP_WSTRING)
wide = true;
}
cp_parser_declaration_seq_opt (parser);
-
+
/* If there are no tokens left then all went well. */
if (cp_lexer_next_token_is (parser->lexer, CPP_EOF))
{
/* Get rid of the token array; we don't need it any more. */
cp_lexer_destroy (parser->lexer);
parser->lexer = NULL;
-
+
/* This file might have been a context that's implicitly extern
- "C". If so, pop the lang context. (Only relevant for PCH.) */
+ "C". If so, pop the lang context. (Only relevant for PCH.) */
if (parser->implicit_extern_c)
- {
- pop_lang_context ();
- parser->implicit_extern_c = false;
- }
-
+ {
+ pop_lang_context ();
+ parser->implicit_extern_c = false;
+ }
+
/* Finish up. */
finish_translation_unit ();
-
+
success = true;
}
else
cp_parser_error (parser, "expected declaration");
success = false;
}
-
+
/* Make sure the declarator obstack was fully cleaned up. */
gcc_assert (obstack_next_free (&declarator_obstack)
== declarator_obstack_base);
/* Floating-point literals are only allowed in an integral
constant expression if they are cast to an integral or
enumeration type. */
- if (TREE_CODE (token->value) == REAL_CST
+ if (TREE_CODE (token->u.value) == REAL_CST
&& parser->integral_constant_expression_p
&& pedantic)
{
cp_parser_non_integral_constant_expression
(parser, "floating-point literal");
}
- return token->value;
+ return token->u.value;
case CPP_STRING:
case CPP_WSTRING:
int i = ({ int j = 3; j + 1; });
at class or namespace scope. */
- if (!at_function_scope_p ())
- error ("statement-expressions are allowed only inside functions");
- /* Start the statement-expression. */
- expr = begin_stmt_expr ();
- /* Parse the compound-statement. */
- cp_parser_compound_statement (parser, expr, false);
- /* Finish up. */
- expr = finish_stmt_expr (expr, false);
+ if (!parser->in_function_body)
+ {
+ error ("statement-expressions are allowed only inside functions");
+ cp_parser_skip_to_end_of_block_or_statement (parser);
+ expr = error_mark_node;
+ }
+ else
+ {
+ /* Start the statement-expression. */
+ expr = begin_stmt_expr ();
+ /* Parse the compound-statement. */
+ cp_parser_compound_statement (parser, expr, false);
+ /* Finish up. */
+ expr = finish_stmt_expr (expr, false);
+ }
}
else
{
Consume the token. */
token = cp_lexer_consume_token (parser->lexer);
/* Look up the name. */
- return finish_fname (token->value);
+ return finish_fname (token->u.value);
case RID_VA_ARG:
{
}
}
- decl = (finish_id_expression
+ decl = (finish_id_expression
(id_expression, decl, parser->scope,
idk,
parser->integral_constant_expression_p,
/* Anything else is an error. */
default:
- /* ...unless we have an Objective-C++ message or string literal, that is. */
+ /* ...unless we have an Objective-C++ message or string literal,
+ that is. */
if (c_dialect_objc ()
- && (token->type == CPP_OPEN_SQUARE || token->type == CPP_OBJC_STRING))
+ && (token->type == CPP_OPEN_SQUARE
+ || token->type == CPP_OBJC_STRING))
return cp_parser_objc_expression (parser);
cp_parser_error (parser, "expected primary-expression");
cp_parser_unqualified_id (cp_parser* parser,
bool template_keyword_p,
bool check_dependency_p,
- bool declarator_p,
+ bool declarator_p,
bool optional_p)
{
cp_token *token;
object_scope = parser->object_scope;
qualifying_scope = parser->qualifying_scope;
+ /* Check for invalid scopes. */
+ if (scope == error_mark_node)
+ {
+ if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
+ cp_lexer_consume_token (parser->lexer);
+ return error_mark_node;
+ }
+ if (scope && TREE_CODE (scope) == NAMESPACE_DECL)
+ {
+ if (!cp_parser_uncommitted_to_tentative_parse_p (parser))
+ error ("scope %qT before %<~%> is not a class-name", scope);
+ cp_parser_simulate_error (parser);
+ if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
+ cp_lexer_consume_token (parser->lexer);
+ return error_mark_node;
+ }
+ gcc_assert (!scope || TYPE_P (scope));
+
/* If the name is of the form "X::~X" it's OK. */
- if (scope && TYPE_P (scope)
- && cp_lexer_next_token_is (parser->lexer, CPP_NAME)
+ token = cp_lexer_peek_token (parser->lexer);
+ if (scope
+ && token->type == CPP_NAME
&& (cp_lexer_peek_nth_token (parser->lexer, 2)->type
== CPP_OPEN_PAREN)
- && (cp_lexer_peek_token (parser->lexer)->value
- == TYPE_IDENTIFIER (scope)))
+ && constructor_name_p (token->u.value, scope))
{
cp_lexer_consume_token (parser->lexer);
return build_nt (BIT_NOT_EXPR, scope);
destructor is the same as the name of the qualifying
class. That allows us to keep parsing after running
into ill-formed destructor names. */
- if (type_decl == error_mark_node && scope && TYPE_P (scope))
+ if (type_decl == error_mark_node && scope)
return build_nt (BIT_NOT_EXPR, scope);
else if (type_decl == error_mark_node)
return error_mark_node;
if (!cp_parser_uncommitted_to_tentative_parse_p (parser))
error ("declaration of %<~%T%> as member of %qT",
type_decl, scope);
+ cp_parser_simulate_error (parser);
return error_mark_node;
}
cp_token_position start = 0;
cp_token *token;
- /* If the next token corresponds to a nested name specifier, there
- is no need to reparse it. However, if CHECK_DEPENDENCY_P is
- false, it may have been true before, in which case something
- like `A<X>::B<Y>::C' may have resulted in a nested-name-specifier
- of `A<X>::', where it should now be `A<X>::B<Y>::'. So, when
- CHECK_DEPENDENCY_P is false, we have to fall through into the
- main loop. */
- 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;
- }
-
/* Remember where the nested-name-specifier starts. */
if (cp_parser_uncommitted_to_tentative_parse_p (parser))
{
{
/* Grab the nested-name-specifier and continue the loop. */
cp_parser_pre_parsed_nested_name_specifier (parser);
+ /* If we originally encountered this nested-name-specifier
+ with IS_DECLARATION set to false, we will not have
+ resolved TYPENAME_TYPEs, so we must do so here. */
+ if (is_declaration
+ && TREE_CODE (parser->scope) == TYPENAME_TYPE)
+ {
+ new_scope = resolve_typename_type (parser->scope,
+ /*only_current_p=*/false);
+ if (new_scope != error_mark_node)
+ parser->scope = new_scope;
+ }
success = true;
continue;
}
class-or-namespace-name. */
parser->scope = old_scope;
parser->qualifying_scope = saved_qualifying_scope;
+ if (cp_parser_uncommitted_to_tentative_parse_p (parser))
+ break;
/* If the next token is an identifier, and the one after
that is a `::', then any valid interpretation would have
found a class-or-namespace-name. */
tree decl;
tree ambiguous_decls;
- decl = cp_parser_lookup_name (parser, token->value,
+ decl = cp_parser_lookup_name (parser, token->u.value,
none_type,
/*is_template=*/false,
/*is_namespace=*/false,
error ("%qD used without template parameters", decl);
else if (ambiguous_decls)
{
- error ("reference to %qD is ambiguous",
- token->value);
+ error ("reference to %qD is ambiguous",
+ token->u.value);
print_candidates (ambiguous_decls);
decl = error_mark_node;
}
else
cp_parser_name_lookup_error
- (parser, token->value, decl,
+ (parser, token->u.value, decl,
"is not a class or namespace");
}
parser->scope = error_mark_node;
if (success && start)
{
cp_token *token;
- tree access_checks;
token = cp_lexer_token_at (parser->lexer, start);
/* Reset the contents of the START token. */
token->type = CPP_NESTED_NAME_SPECIFIER;
/* Retrieve any deferred checks. Do not pop this access checks yet
so the memory will not be reclaimed during token replacing below. */
- access_checks = get_deferred_access_checks ();
- token->value = build_tree_list (copy_list (access_checks),
- parser->scope);
- TREE_TYPE (token->value) = parser->qualifying_scope;
+ token->u.tree_check_value = GGC_CNEW (struct tree_check);
+ token->u.tree_check_value->value = parser->scope;
+ token->u.tree_check_value->checks = get_deferred_access_checks ();
+ token->u.tree_check_value->qualifying_scope =
+ parser->qualifying_scope;
token->keyword = RID_MAX;
/* Purge all subsequent tokens. */
cp_lexer_purge_tokens_after (parser->lexer, start);
}
-
+
if (start)
pop_to_parent_deferring_access_checks ();
/* Only type conversions to integral or enumeration types
can be used in constant-expressions. */
- if (parser->integral_constant_expression_p
- && !dependent_type_p (type)
- && !INTEGRAL_OR_ENUMERATION_TYPE_P (type)
+ if (!cast_valid_in_integral_constant_expression_p (type)
&& (cp_parser_non_integral_constant_expression
(parser,
"a cast to a type other than an integral or "
/* Look for the `)' token. */
cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
}
+ /* Restore the saved message. */
+ parser->type_definition_forbidden_message = saved_message;
/* `typeid' may not appear in an integral constant expression. */
if (cp_parser_non_integral_constant_expression(parser,
"`typeid' operator"))
return error_mark_node;
- /* Restore the saved message. */
- parser->type_definition_forbidden_message = saved_message;
}
break;
}
/* It must be a primary-expression. */
- postfix_expression
- = cp_parser_primary_expression (parser, address_p, cast_p,
+ postfix_expression
+ = cp_parser_primary_expression (parser, address_p, cast_p,
/*template_arg_p=*/false,
&idk);
}
|| any_type_dependent_arguments_p (args)))
{
postfix_expression
- = build_min_nt (CALL_EXPR, postfix_expression,
- args, NULL_TREE);
+ = build_nt_call_list (postfix_expression, args);
break;
}
pseudo-destructor-name. */
bool template_p;
/* Parse the id-expression. */
- name = (cp_parser_id_expression
- (parser,
+ name = (cp_parser_id_expression
+ (parser,
cp_parser_optional_template_keyword (parser),
/*check_dependency_p=*/true,
&template_p,
}
if (scope && name && BASELINK_P (name))
adjust_result_of_qualified_name_lookup
- (name, BINFO_TYPE (BASELINK_BINFO (name)), scope);
+ (name, BINFO_TYPE (BASELINK_ACCESS_BINFO (name)), scope);
postfix_expression
= finish_class_member_access_expr (postfix_expression, name,
template_p);
/* Consume the identifier. */
token = cp_lexer_consume_token (parser->lexer);
/* Save the identifier. */
- identifier = token->value;
+ identifier = token->u.value;
}
else
{
/* Only type conversions to integral or enumeration types
can be used in constant-expressions. */
- if (parser->integral_constant_expression_p
- && !dependent_type_p (type)
- && !INTEGRAL_OR_ENUMERATION_TYPE_P (type)
+ if (!cast_valid_in_integral_constant_expression_p (type)
&& (cp_parser_non_integral_constant_expression
(parser,
"a cast to a type other than an integral or "
cp_parser_expression_stack_entry *sp = &stack[0];
tree lhs, rhs;
cp_token *token;
- enum tree_code tree_type;
+ enum tree_code tree_type, lhs_type, rhs_type;
enum cp_parser_prec prec = PREC_NOT_OPERATOR, new_prec, lookahead_prec;
bool overloaded_p;
/* Parse the first expression. */
lhs = cp_parser_cast_expression (parser, /*address_p=*/false, cast_p);
+ lhs_type = ERROR_MARK;
for (;;)
{
/* Get an operator token. */
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);
/* Extract another operand. It may be the RHS of this expression
or the LHS of a new, higher priority expression. */
rhs = cp_parser_simple_cast_expression (parser);
+ rhs_type = ERROR_MARK;
/* Get another operator token. Look up its precedence to avoid
building a useless (immediately popped) stack entry for common
sp->prec = prec;
sp->tree_type = tree_type;
sp->lhs = lhs;
+ sp->lhs_type = lhs_type;
sp++;
lhs = rhs;
+ lhs_type = rhs_type;
prec = new_prec;
new_prec = lookahead_prec;
goto get_rhs;
prec = sp->prec;
tree_type = sp->tree_type;
rhs = lhs;
+ rhs_type = lhs_type;
lhs = sp->lhs;
+ lhs_type = sp->lhs_type;
}
overloaded_p = false;
- lhs = build_x_binary_op (tree_type, lhs, rhs, &overloaded_p);
+ lhs = build_x_binary_op (tree_type, lhs, lhs_type, rhs, rhs_type,
+ &overloaded_p);
+ lhs_type = tree_type;
/* If the binary operator required the use of an overloaded operator,
then this expression cannot be an integral constant-expression.
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:
/* Nothing else is an assignment operator. */
op = ERROR_MARK;
offsetof-member-designator:
id-expression
| offsetof-member-designator "." id-expression
- | offsetof-member-designator "[" expression "]"
-*/
+ | offsetof-member-designator "[" expression "]" */
static tree
cp_parser_builtin_offsetof (cp_parser *parser)
if (processing_template_decl)
expr = build1 (OFFSETOF_EXPR, size_type_node, expr);
else
- expr = fold_offsetof (expr);
+ expr = finish_offsetof (expr);
failure:
parser->integral_constant_expression_p = save_ice_p;
declaration-statement
try-block
- IN_COMPOUND is true when the statement is nested inside a
- cp_parser_compound_statement; this matters for certain pragmas. */
+ IN_COMPOUND is true when the statement is nested inside a
+ cp_parser_compound_statement; this matters for certain pragmas.
+
+ If IF_P is not NULL, *IF_P is set to indicate whether the statement
+ is a (possibly labeled) if statement which is not enclosed in braces
+ and has an else clause. This is used to implement -Wparentheses. */
static void
cp_parser_statement (cp_parser* parser, tree in_statement_expr,
- bool in_compound)
+ bool in_compound, bool *if_p)
{
tree statement;
cp_token *token;
location_t statement_location;
restart:
+ if (if_p != NULL)
+ *if_p = false;
/* There is no statement yet. */
statement = NULL_TREE;
/* Peek at the next token. */
{
case RID_CASE:
case RID_DEFAULT:
- statement = cp_parser_labeled_statement (parser, in_statement_expr,
- in_compound);
- break;
+ /* Looks like a labeled-statement with a case label.
+ Parse the label, and then use tail recursion to parse
+ the statement. */
+ cp_parser_label_for_labeled_statement (parser);
+ goto restart;
case RID_IF:
case RID_SWITCH:
- statement = cp_parser_selection_statement (parser);
+ statement = cp_parser_selection_statement (parser, if_p);
break;
case RID_WHILE:
labeled-statement. */
token = cp_lexer_peek_nth_token (parser->lexer, 2);
if (token->type == CPP_COLON)
- statement = cp_parser_labeled_statement (parser, in_statement_expr,
- in_compound);
+ {
+ /* Looks like a labeled-statement with an ordinary label.
+ Parse the label, and then use tail recursion to parse
+ the statement. */
+ cp_parser_label_for_labeled_statement (parser);
+ goto restart;
+ }
}
/* Anything that starts with a `{' must be a compound-statement. */
else if (token->type == CPP_OPEN_BRACE)
/* Only certain OpenMP pragmas are attached to statements, and thus
are considered statements themselves. All others are not. In
the context of a compound, accept the pragma as a "statement" and
- return so that we can check for a close brace. Otherwise we
+ return so that we can check for a close brace. Otherwise we
require a real statement and must go back and read one. */
if (in_compound)
cp_parser_pragma (parser, pragma_compound);
SET_EXPR_LOCATION (statement, statement_location);
}
-/* Parse a labeled-statement.
+/* Parse the label for a labeled-statement, i.e.
- labeled-statement:
- identifier : statement
- case constant-expression : statement
- default : statement
+ identifier :
+ case constant-expression :
+ default :
GNU Extension:
+ case constant-expression ... constant-expression : statement
- labeled-statement:
- case constant-expression ... constant-expression : statement
-
- Returns the new CASE_LABEL_EXPR, for a `case' or `default' label.
- For an ordinary label, returns a LABEL_EXPR.
-
- IN_COMPOUND is as for cp_parser_statement: true when we're nested
- inside a compound. */
+ When a label is parsed without errors, the label is added to the
+ parse tree by the finish_* functions, so this function doesn't
+ have to return the label. */
-static tree
-cp_parser_labeled_statement (cp_parser* parser, tree in_statement_expr,
- bool in_compound)
+static void
+cp_parser_label_for_labeled_statement (cp_parser* parser)
{
cp_token *token;
- tree statement = error_mark_node;
/* The next token should be an identifier. */
token = cp_lexer_peek_token (parser->lexer);
&& token->type != CPP_KEYWORD)
{
cp_parser_error (parser, "expected labeled-statement");
- return error_mark_node;
+ return;
}
switch (token->keyword)
expr_hi = NULL_TREE;
if (parser->in_switch_statement_p)
- statement = finish_case_label (expr, expr_hi);
+ finish_case_label (expr, expr_hi);
else
error ("case label %qE not within a switch statement", expr);
}
cp_lexer_consume_token (parser->lexer);
if (parser->in_switch_statement_p)
- statement = finish_case_label (NULL_TREE, NULL_TREE);
+ finish_case_label (NULL_TREE, NULL_TREE);
else
error ("case label not within a switch statement");
break;
default:
/* Anything else must be an ordinary label. */
- statement = finish_label_stmt (cp_parser_identifier (parser));
+ finish_label_stmt (cp_parser_identifier (parser));
break;
}
/* Require the `:' token. */
cp_parser_require (parser, CPP_COLON, "`:'");
- /* Parse the labeled statement. */
- cp_parser_statement (parser, in_statement_expr, in_compound);
-
- /* Return the label, in the case of a `case' or `default' label. */
- return statement;
}
/* Parse an expression-statement.
break;
/* Parse the statement. */
- cp_parser_statement (parser, in_statement_expr, true);
+ cp_parser_statement (parser, in_statement_expr, true, NULL);
}
}
if ( condition ) statement else statement
switch ( condition ) statement
- Returns the new IF_STMT or SWITCH_STMT. */
+ Returns the new IF_STMT or SWITCH_STMT.
+
+ If IF_P is not NULL, *IF_P is set to indicate whether the statement
+ is a (possibly labeled) if statement which is not enclosed in
+ braces and has an else clause. This is used to implement
+ -Wparentheses. */
static tree
-cp_parser_selection_statement (cp_parser* parser)
+cp_parser_selection_statement (cp_parser* parser, bool *if_p)
{
cp_token *token;
enum rid keyword;
+ if (if_p != NULL)
+ *if_p = false;
+
/* Peek at the next token. */
token = cp_parser_require (parser, CPP_KEYWORD, "selection-statement");
if (keyword == RID_IF)
{
+ bool nested_if;
+
/* Add the condition. */
finish_if_stmt_cond (condition, statement);
/* Parse the then-clause. */
- cp_parser_implicitly_scoped_statement (parser);
+ cp_parser_implicitly_scoped_statement (parser, &nested_if);
finish_then_clause (statement);
/* If the next token is `else', parse the else-clause. */
cp_lexer_consume_token (parser->lexer);
begin_else_clause (statement);
/* Parse the else-clause. */
- cp_parser_implicitly_scoped_statement (parser);
+ cp_parser_implicitly_scoped_statement (parser, NULL);
finish_else_clause (statement);
+
+ /* If we are currently parsing a then-clause, then
+ IF_P will not be NULL. We set it to true to
+ indicate that this if statement has an else clause.
+ This may trigger the Wparentheses warning below
+ when we get back up to the parent if statement. */
+ if (if_p != NULL)
+ *if_p = true;
+ }
+ else
+ {
+ /* This if statement does not have an else clause. If
+ NESTED_IF is true, then the then-clause is an if
+ statement which does have an else clause. We warn
+ about the potential ambiguity. */
+ if (nested_if)
+ warning (OPT_Wparentheses,
+ ("%Hsuggest explicit braces "
+ "to avoid ambiguous %<else%>"),
+ EXPR_LOCUS (statement));
}
/* Now we're all done with the if-statement. */
in_statement = parser->in_statement;
parser->in_switch_statement_p = true;
parser->in_statement |= IN_SWITCH_STMT;
- cp_parser_implicitly_scoped_statement (parser);
+ cp_parser_implicitly_scoped_statement (parser, NULL);
parser->in_switch_statement_p = in_switch_statement_p;
parser->in_statement = in_statement;
attributes, /*prefix_attributes=*/NULL_TREE,
&pushed_scope);
/* Parse the assignment-expression. */
- initializer
+ initializer
= cp_parser_constant_expression (parser,
/*allow_non_constant_p=*/true,
&non_constant_p);
/* Process the initializer. */
cp_finish_decl (decl,
- initializer, !non_constant_p,
+ initializer, !non_constant_p,
asm_specification,
LOOKUP_ONLYCONVERTING);
statement = begin_do_stmt ();
/* Parse the body of the do-statement. */
parser->in_statement = IN_ITERATION_STMT;
- cp_parser_implicitly_scoped_statement (parser);
+ cp_parser_implicitly_scoped_statement (parser, NULL);
parser->in_statement = in_statement;
finish_do_body (statement);
/* Look for the `while' keyword. */
but ensures that is in its own scope, even if it is not a
compound-statement.
+ If IF_P is not NULL, *IF_P is set to indicate whether the statement
+ is a (possibly labeled) if statement which is not enclosed in
+ braces and has an else clause. This is used to implement
+ -Wparentheses.
+
Returns the new statement. */
static tree
-cp_parser_implicitly_scoped_statement (cp_parser* parser)
+cp_parser_implicitly_scoped_statement (cp_parser* parser, bool *if_p)
{
tree statement;
+ if (if_p != NULL)
+ *if_p = false;
+
/* Mark if () ; with a special NOP_EXPR. */
if (cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON))
{
/* Create a compound-statement. */
statement = begin_compound_stmt (0);
/* Parse the dependent-statement. */
- cp_parser_statement (parser, NULL_TREE, false);
+ cp_parser_statement (parser, NULL_TREE, false, if_p);
/* Finish the dummy compound-statement. */
finish_compound_stmt (statement);
}
{
/* If the token is a `{', then we must take special action. */
if (cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_BRACE))
- cp_parser_statement (parser, NULL_TREE, false);
+ cp_parser_statement (parser, NULL_TREE, false, NULL);
else
{
/* Avoid calling cp_parser_compound_statement, so that we
__extension__ block-declaration
label-declaration
+ C++0x Extension:
+
+ block-declaration:
+ static_assert-declaration
+
If STATEMENT_P is TRUE, then this block-declaration is occurring as
part of a declaration-statement. */
cp_parser_using_directive (parser);
/* Otherwise, it's a using-declaration. */
else
- cp_parser_using_declaration (parser);
+ cp_parser_using_declaration (parser,
+ /*access_declaration_p=*/false);
}
/* If the next keyword is `__label__' we have a label declaration. */
else if (token1->keyword == RID_LABEL)
cp_parser_commit_to_tentative_parse (parser);
cp_parser_label_declaration (parser);
}
+ /* If the next token is `static_assert' we have a static assertion. */
+ else if (token1->keyword == RID_STATIC_ASSERT)
+ cp_parser_static_assert (parser, /*member_p=*/false);
/* Anything else must be a simple-declaration. */
else
cp_parser_simple_declaration (parser, !statement_p);
/* Parse the init-declarator. */
decl = cp_parser_init_declarator (parser, &decl_specifiers,
+ /*checks=*/NULL,
function_definition_allowed_p,
/*member_p=*/false,
declares_class_or_enum,
int* declares_class_or_enum)
{
bool constructor_possible_p = !parser->in_declarator_p;
- cp_decl_spec ds;
/* Clear DECL_SPECS. */
clear_decl_specs (decl_specs);
/* decl-specifier:
friend */
case RID_FRIEND:
- ++decl_specs->specs[(int) ds_friend];
- /* Consume the token. */
- cp_lexer_consume_token (parser->lexer);
+ if (!at_class_scope_p ())
+ {
+ error ("%<friend%> used outside of class");
+ cp_lexer_purge_token (parser->lexer);
+ }
+ else
+ {
+ ++decl_specs->specs[(int) ds_friend];
+ /* Consume the token. */
+ cp_lexer_consume_token (parser->lexer);
+ }
break;
/* function-specifier:
/* The "typedef" keyword can only occur in a declaration; we
may as well commit at this point. */
cp_parser_commit_to_tentative_parse (parser);
+
+ if (decl_specs->storage_class != sc_none)
+ decl_specs->conflicting_specifiers_p = true;
break;
/* storage-class-specifier:
GNU Extension:
thread */
case RID_AUTO:
- /* Consume the token. */
- cp_lexer_consume_token (parser->lexer);
- cp_parser_set_storage_class (decl_specs, sc_auto);
- break;
case RID_REGISTER:
- /* Consume the token. */
- cp_lexer_consume_token (parser->lexer);
- cp_parser_set_storage_class (decl_specs, sc_register);
- break;
case RID_STATIC:
- /* Consume the token. */
- cp_lexer_consume_token (parser->lexer);
- if (decl_specs->specs[(int) ds_thread])
- {
- error ("%<__thread%> before %<static%>");
- decl_specs->specs[(int) ds_thread] = 0;
- }
- cp_parser_set_storage_class (decl_specs, sc_static);
- break;
case RID_EXTERN:
- /* Consume the token. */
- cp_lexer_consume_token (parser->lexer);
- if (decl_specs->specs[(int) ds_thread])
- {
- error ("%<__thread%> before %<extern%>");
- decl_specs->specs[(int) ds_thread] = 0;
- }
- cp_parser_set_storage_class (decl_specs, sc_extern);
- break;
case RID_MUTABLE:
/* Consume the token. */
cp_lexer_consume_token (parser->lexer);
- cp_parser_set_storage_class (decl_specs, sc_mutable);
+ cp_parser_set_storage_class (parser, decl_specs, token->keyword);
break;
case RID_THREAD:
/* Consume the token. */
flags |= CP_PARSER_FLAGS_OPTIONAL;
}
- /* Check for repeated decl-specifiers. */
- for (ds = ds_first; ds != ds_last; ++ds)
- {
- unsigned count = decl_specs->specs[(int)ds];
- if (count < 2)
- continue;
- /* The "long" specifier is a special case because of "long long". */
- if (ds == ds_long)
- {
- if (count > 2)
- error ("%<long long long%> is too long for GCC");
- else if (pedantic && !in_system_header && warn_long_long)
- pedwarn ("ISO C++ does not support %<long long%>");
- }
- else if (count > 1)
- {
- static const char *const decl_spec_names[] = {
- "signed",
- "unsigned",
- "short",
- "long",
- "const",
- "volatile",
- "restrict",
- "inline",
- "virtual",
- "explicit",
- "friend",
- "typedef",
- "__complex",
- "__thread"
- };
- error ("duplicate %qs", decl_spec_names[(int)ds]);
- }
- }
+ cp_parser_check_decl_spec (decl_specs);
/* Don't allow a friend specifier with a class definition. */
if (decl_specs->specs[(int) ds_friend] != 0
case RID_MUTABLE:
case RID_THREAD:
/* Consume the token. */
- return cp_lexer_consume_token (parser->lexer)->value;
+ return cp_lexer_consume_token (parser->lexer)->u.value;
default:
return NULL_TREE;
break;
case RID_VIRTUAL:
- if (decl_specs)
+ /* 14.5.2.3 [temp.mem]
+
+ A member function template shall not be virtual. */
+ if (PROCESSING_REAL_TEMPLATE_DECL_P ())
+ error ("templates may not be %<virtual%>");
+ else if (decl_specs)
++decl_specs->specs[(int) ds_virtual];
break;
}
/* Consume the token. */
- return cp_lexer_consume_token (parser->lexer)->value;
+ return cp_lexer_consume_token (parser->lexer)->u.value;
}
/* Parse a linkage-specification.
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 ();
}
+/* Parse a static_assert-declaration.
+
+ static_assert-declaration:
+ static_assert ( constant-expression , string-literal ) ;
+
+ If MEMBER_P, this static_assert is a class member. */
+
+static void
+cp_parser_static_assert(cp_parser *parser, bool member_p)
+{
+ tree condition;
+ tree message;
+ cp_token *token;
+ location_t saved_loc;
+
+ /* Peek at the `static_assert' token so we can keep track of exactly
+ where the static assertion started. */
+ token = cp_lexer_peek_token (parser->lexer);
+ saved_loc = token->location;
+
+ /* Look for the `static_assert' keyword. */
+ if (!cp_parser_require_keyword (parser, RID_STATIC_ASSERT,
+ "`static_assert'"))
+ return;
+
+ /* We know we are in a static assertion; commit to any tentative
+ parse. */
+ if (cp_parser_parsing_tentatively (parser))
+ cp_parser_commit_to_tentative_parse (parser);
+
+ /* Parse the `(' starting the static assertion condition. */
+ cp_parser_require (parser, CPP_OPEN_PAREN, "`('");
+
+ /* Parse the constant-expression. */
+ condition =
+ cp_parser_constant_expression (parser,
+ /*allow_non_constant_p=*/false,
+ /*non_constant_p=*/NULL);
+
+ /* Parse the separating `,'. */
+ cp_parser_require (parser, CPP_COMMA, "`,'");
+
+ /* Parse the string-literal message. */
+ message = cp_parser_string_literal (parser,
+ /*translate=*/false,
+ /*wide_ok=*/true);
+
+ /* A `)' completes the static assertion. */
+ if (!cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'"))
+ cp_parser_skip_to_closing_parenthesis (parser,
+ /*recovering=*/true,
+ /*or_comma=*/false,
+ /*consume_paren=*/true);
+
+ /* A semicolon terminates the declaration. */
+ cp_parser_require (parser, CPP_SEMICOLON, "`;'");
+
+ /* Complete the static assertion, which may mean either processing
+ the static assert now or saving it for template instantiation. */
+ finish_static_assert (condition, message, saved_loc, member_p);
+}
+
/* Special member functions [gram.special] */
/* Parse a conversion-function-id.
cp_parser_require (parser, CPP_CLOSE_SQUARE, "`]'");
return ansi_opname (ARRAY_REF);
- /* Extensions. */
- 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:
/* Anything else is an error. */
break;
parameter_list = process_template_parm (parameter_list,
parameter,
is_non_type);
+ else
+ {
+ tree err_parm = build_tree_list (parameter, parameter);
+ TREE_VALUE (err_parm) = error_mark_node;
+ parameter_list = chainon (parameter_list, err_parm);
+ }
+
/* Peek at the next token. */
token = cp_lexer_peek_token (parser->lexer);
/* If it's not a `,', we're done. */
/* Consume the `=' token. */
cp_lexer_consume_token (parser->lexer);
/* Parse the default-argument. */
+ push_deferring_access_checks (dk_no_deferred);
default_argument = cp_parser_type_id (parser);
+ pop_deferring_access_checks ();
}
else
default_argument = NULL_TREE;
/* Consume the `='. */
cp_lexer_consume_token (parser->lexer);
/* Parse the id-expression. */
+ push_deferring_access_checks (dk_no_deferred);
default_argument
= cp_parser_id_expression (parser,
/*template_keyword_p=*/false,
/* See if the default argument is valid. */
default_argument
= check_template_template_default_arg (default_argument);
+ pop_deferring_access_checks ();
}
else
default_argument = NULL_TREE;
bool check_dependency_p,
bool is_declaration)
{
+ int i;
tree template;
tree arguments;
tree template_id;
cp_token_position start_of_id = 0;
- tree access_check = NULL_TREE;
+ deferred_access_check *chk;
+ VEC (deferred_access_check,gc) *access_check;
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;
+ struct tree_check *check_value;
/* Get the stored value. */
- value = cp_lexer_consume_token (parser->lexer)->value;
+ check_value = cp_lexer_consume_token (parser->lexer)->u.tree_check_value;
/* Perform any access checks that were deferred. */
- for (check = TREE_PURPOSE (value); check; check = TREE_CHAIN (check))
- perform_or_defer_access_check (TREE_PURPOSE (check),
- TREE_VALUE (check));
+ access_check = check_value->checks;
+ if (access_check)
+ {
+ for (i = 0 ;
+ VEC_iterate (deferred_access_check, access_check, i, chk) ;
+ ++i)
+ {
+ perform_or_defer_access_check (chk->binfo,
+ chk->decl,
+ chk->diag_decl);
+ }
+ }
/* Return the stored value. */
- return TREE_VALUE (value);
+ return check_value->value;
}
/* Avoid performing name lookup if there is no possibility of
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));
+ {
+ bool entering_scope;
+ /* In "template <typename T> ... A<T>::", A<T> is the abstract A
+ template (rather than some instantiation thereof) only if
+ is not nested within some other construct. For example, in
+ "template <typename T> void f(T) { A<T>::", A<T> is just an
+ instantiation of A. */
+ entering_scope = (template_parm_scope_p ()
+ && cp_lexer_next_token_is (parser->lexer,
+ CPP_SCOPE));
+ template_id
+ = finish_template_type (template, arguments, entering_scope);
+ }
else
{
/* If it's not a class-template or a template-template, it should be
template_id = lookup_template_function (template, arguments);
}
- /* Retrieve any deferred checks. Do not pop this access checks yet
- so the memory will not be reclaimed during token replacing below. */
- access_check = get_deferred_access_checks ();
-
/* If parsing tentatively, replace the sequence of tokens that makes
up the template-id with a CPP_TEMPLATE_ID token. That way,
should we re-parse the token stream, we will not have to repeat
/* Reset the contents of the START_OF_ID token. */
token->type = CPP_TEMPLATE_ID;
- token->value = build_tree_list (access_check, template_id);
+ /* Retrieve any deferred checks. Do not pop this access checks yet
+ so the memory will not be reclaimed during token replacing below. */
+ token->u.tree_check_value = GGC_CNEW (struct tree_check);
+ token->u.tree_check_value->value = template_id;
+ token->u.tree_check_value->checks = get_deferred_access_checks ();
token->keyword = RID_MAX;
/* Purge all subsequent tokens. */
saved_in_template_argument_list_p = parser->in_template_argument_list_p;
parser->in_template_argument_list_p = true;
/* Even if the template-id appears in an integral
- constant-expression, the contents of the argument list do
- not. */
+ constant-expression, the contents of the argument list do
+ not. */
saved_ice_p = parser->integral_constant_expression_p;
parser->integral_constant_expression_p = false;
saved_non_ice_p = parser->non_integral_constant_expression_p;
argument = TREE_OPERAND (argument, 0);
}
- if (TREE_CODE (argument) == BASELINK)
- /* We don't need the information about what class was used
- to name the overloaded functions. */
- argument = BASELINK_FUNCTIONS (argument);
-
if (TREE_CODE (argument) == VAR_DECL)
{
/* A variable without external linkage might still be a
valid constant-expression, so no error is issued here
if the external-linkage check fails. */
- if (!DECL_EXTERNAL_LINKAGE_P (argument))
+ if (!address_p && !DECL_EXTERNAL_LINKAGE_P (argument))
cp_parser_simulate_error (parser);
}
else if (is_overloaded_fn (argument))
pop_deferring_access_checks ();
if (type)
do_type_instantiation (type, extension_specifier,
- /*complain=*/tf_error);
+ /*complain=*/tf_error);
}
else
{
if (declarator != cp_error_declarator)
{
decl = grokdeclarator (declarator, &decl_specifiers,
- NORMAL, 0, NULL);
+ NORMAL, 0, &decl_specifiers.attributes);
/* Turn access control back on for names used during
template instantiation. */
pop_deferring_access_checks ();
/* We have processed another parameter list. */
++parser->num_template_parameter_lists;
/* [temp]
-
+
A template ... explicit specialization ... shall not have C
- linkage. */
+ linkage. */
if (current_lang_name == lang_name_c)
{
error ("template specialization with C linkage");
else
need_lang_pop = false;
/* Let the front end know that we are beginning a specialization. */
- begin_specialization ();
+ if (!begin_specialization ())
+ {
+ end_specialization ();
+ cp_parser_skip_to_end_of_block_or_statement (parser);
+ return;
+ }
+
/* If the next keyword is `template', we need to figure out whether
or not we're looking a template-declaration. */
if (cp_lexer_next_token_is_keyword (parser->lexer, RID_TEMPLATE))
else
/* Parse the dependent declaration. */
cp_parser_single_declaration (parser,
+ /*checks=*/NULL,
/*member_p=*/false,
/*friend_p=*/NULL);
/* We're done with the specialization. */
switch (keyword)
{
case RID_ENUM:
- /* 'enum' [identifier] '{' introduces an enum-specifier;
- 'enum' <anything else> introduces an elaborated-type-specifier. */
- 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))
+ /* Look for the enum-specifier. */
+ type_spec = cp_parser_enum_specifier (parser);
+ /* If that worked, we're done. */
+ if (type_spec)
{
- 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)
++decl_specs->specs[(int)ds];
decl_specs->any_specifiers_p = true;
}
- return cp_lexer_consume_token (parser->lexer)->value;
+ return cp_lexer_consume_token (parser->lexer)->u.value;
}
/* If we do not already have a type-specifier, assume we are looking
decl_specs->any_specifiers_p = true;
/* Consume the token. */
- id = cp_lexer_consume_token (parser->lexer)->value;
+ id = cp_lexer_consume_token (parser->lexer)->u.value;
/* There is no valid C++ program where a non-template type is
followed by a "<". That usually indicates that the user thought
/*check_dependency_p=*/true,
/*type_p=*/true,
is_declaration);
- /* For everything but enumeration types, consider a template-id. */
+ /* For everything but enumeration types, consider a template-id.
+ For an enumeration type, consider only a plain identifier. */
if (tag_type != enum_type)
{
bool template_p = false;
type = TREE_TYPE (decl);
}
- /* For an enumeration type, consider only a plain identifier. */
if (!type)
{
identifier = cp_parser_identifier (parser);
}
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)));
+ {
+ bool allow_template = (parser->num_template_parameter_lists
+ || DECL_SELF_REFERENCE_P (decl));
+ type = check_elaborated_type_specifier (tag_type, decl,
+ allow_template);
+
+ if (type == error_mark_node)
+ return error_mark_node;
+ }
type = TREE_TYPE (decl);
}
else
ts = ts_global;
- /* Warn about attributes. They are ignored. */
- if (attributes)
- warning (OPT_Wattributes,
- "type attributes are honored only at type definition");
-
- template_p =
+ template_p =
(parser->num_template_parameter_lists
&& (cp_parser_next_token_starts_class_definition_p (parser)
|| cp_lexer_next_token_is (parser->lexer, CPP_SEMICOLON)));
/* An unqualified name was used to reference this type, so
there were no qualifying templates. */
- if (!cp_parser_check_template_parameters (parser,
+ if (!cp_parser_check_template_parameters (parser,
/*num_templates=*/0))
return error_mark_node;
type = xref_tag (tag_type, identifier, ts, template_p);
}
}
+
+ if (type == error_mark_node)
+ return error_mark_node;
+
+ /* Allow attributes on forward declarations of classes. */
+ if (attributes)
+ {
+ if (TREE_CODE (type) == TYPENAME_TYPE)
+ warning (OPT_Wattributes,
+ "attributes ignored on uninstantiated type");
+ else if (tag_type != enum_type && CLASSTYPE_TEMPLATE_INSTANTIATION (type)
+ && ! processing_explicit_instantiation)
+ warning (OPT_Wattributes,
+ "attributes ignored on template instantiation");
+ else if (is_declaration && cp_parser_declares_only_class_p (parser))
+ cplus_decl_attributes (&type, attributes, (int) ATTR_FLAG_TYPE_IN_PLACE);
+ else
+ warning (OPT_Wattributes,
+ "attributes ignored on elaborated-type-specifier that is not a forward declaration");
+ }
+
if (tag_type != enum_type)
cp_parser_check_class_key (tag_type, type);
enum identifier [opt] { enumerator-list [opt] }
GNU Extensions:
- enum identifier [opt] { enumerator-list [opt] } attributes
+ enum attributes[opt] identifier [opt] { enumerator-list [opt] }
+ attributes[opt]
- Returns an ENUM_TYPE representing the enumeration. */
+ Returns an ENUM_TYPE representing the enumeration, or NULL_TREE
+ if the token stream isn't an enum-specifier after all. */
static tree
cp_parser_enum_specifier (cp_parser* parser)
{
tree identifier;
tree type;
+ tree attributes;
+
+ /* Parse tentatively so that we can back up if we don't find a
+ enum-specifier. */
+ cp_parser_parse_tentatively (parser);
/* Caller guarantees that the current token is 'enum', an identifier
possibly follows, and the token after that is an opening brace.
the enumeration being defined. */
cp_lexer_consume_token (parser->lexer);
+ attributes = cp_parser_attributes_opt (parser);
+
if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
identifier = cp_parser_identifier (parser);
else
identifier = make_anon_name ();
- /* Issue an error message if type-definitions are forbidden here. */
- cp_parser_check_type_definition (parser);
+ /* Look for the `{' but don't consume it yet. */
+ if (!cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE))
+ cp_parser_simulate_error (parser);
- /* Create the new type. We do this before consuming the opening brace
- so the enum will be recorded as being on the line of its tag (or the
- 'enum' keyword, if there is no tag). */
- type = start_enum (identifier);
+ if (!cp_parser_parse_definitely (parser))
+ return NULL_TREE;
+ /* Issue an error message if type-definitions are forbidden here. */
+ if (!cp_parser_check_type_definition (parser))
+ type = error_mark_node;
+ else
+ /* Create the new type. We do this before consuming the opening
+ brace so the enum will be recorded as being on the line of its
+ tag (or the 'enum' keyword, if there is no tag). */
+ type = start_enum (identifier);
+
/* Consume the opening brace. */
cp_lexer_consume_token (parser->lexer);
+ if (type == error_mark_node)
+ {
+ cp_parser_skip_to_end_of_block_or_statement (parser);
+ return error_mark_node;
+ }
+
/* If the next token is not '}', then there are some enumerators. */
if (cp_lexer_next_token_is_not (parser->lexer, CPP_CLOSE_BRACE))
cp_parser_enumerator_list (parser, type);
return cp_parser_namespace_name (parser);
}
-/* Parse a using-declaration.
+/* Parse a using-declaration, or, if ACCESS_DECLARATION_P is true, an
+ access declaration.
using-declaration:
using typename [opt] :: [opt] nested-name-specifier unqualified-id ;
- using :: unqualified-id ; */
+ using :: unqualified-id ;
-static void
-cp_parser_using_declaration (cp_parser* parser)
+ access-declaration:
+ qualified-id ;
+
+ */
+
+static bool
+cp_parser_using_declaration (cp_parser* parser,
+ bool access_declaration_p)
{
cp_token *token;
bool typename_p = false;
tree identifier;
tree qscope;
- /* Look for the `using' keyword. */
- cp_parser_require_keyword (parser, RID_USING, "`using'");
-
- /* Peek at the next token. */
- token = cp_lexer_peek_token (parser->lexer);
- /* See if it's `typename'. */
- if (token->keyword == RID_TYPENAME)
+ if (access_declaration_p)
+ cp_parser_parse_tentatively (parser);
+ else
{
- /* Remember that we've seen it. */
- typename_p = true;
- /* Consume the `typename' token. */
- cp_lexer_consume_token (parser->lexer);
+ /* Look for the `using' keyword. */
+ cp_parser_require_keyword (parser, RID_USING, "`using'");
+
+ /* Peek at the next token. */
+ token = cp_lexer_peek_token (parser->lexer);
+ /* See if it's `typename'. */
+ if (token->keyword == RID_TYPENAME)
+ {
+ /* Remember that we've seen it. */
+ typename_p = true;
+ /* Consume the `typename' token. */
+ cp_lexer_consume_token (parser->lexer);
+ }
}
/* Look for the optional global scope qualification. */
if (!qscope)
qscope = global_namespace;
+ if (access_declaration_p && cp_parser_error_occurred (parser))
+ /* Something has already gone wrong; there's no need to parse
+ further. Since an error has occurred, the return value of
+ cp_parser_parse_definitely will be false, as required. */
+ return cp_parser_parse_definitely (parser);
+
/* Parse the unqualified-id. */
identifier = cp_parser_unqualified_id (parser,
/*template_keyword_p=*/false,
/*declarator_p=*/true,
/*optional_p=*/false);
+ if (access_declaration_p)
+ {
+ if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON))
+ cp_parser_simulate_error (parser);
+ if (!cp_parser_parse_definitely (parser))
+ return false;
+ }
+
/* The function we call to handle a using-declaration is different
depending on what scope we are in. */
if (qscope == error_mark_node || identifier == error_mark_node)
/* Look for the final `;'. */
cp_parser_require (parser, CPP_SEMICOLON, "`;'");
+
+ return true;
}
/* Parse a using-directive.
too. Doing that means that we have to treat the `::' operator as
two `:' tokens. */
if (cp_parser_allow_gnu_extensions_p (parser)
- && at_function_scope_p ()
+ && parser->in_function_body
&& (cp_lexer_next_token_is (parser->lexer, CPP_COLON)
|| cp_lexer_next_token_is (parser->lexer, CPP_SCOPE)))
{
cp_parser_require (parser, CPP_SEMICOLON, "`;'");
/* Create the ASM_EXPR. */
- if (at_function_scope_p ())
+ if (parser->in_function_body)
{
asm_stmt = finish_asm_stmt (volatile_p, string, outputs,
inputs, clobbers);
function-definition:
__extension__ function-definition
- The DECL_SPECIFIERS and PREFIX_ATTRIBUTES apply to this declarator.
- Returns a representation of the entity declared. If MEMBER_P is TRUE,
- then this declarator appears in a class scope. The new DECL created
- by this declarator is returned.
+ The DECL_SPECIFIERS apply to this declarator. Returns a
+ representation of the entity declared. If MEMBER_P is TRUE, then
+ this declarator appears in a class scope. The new DECL created by
+ this declarator is returned.
+
+ The CHECKS are access checks that should be performed once we know
+ what entity is being declared (and, therefore, what classes have
+ befriended it).
If FUNCTION_DEFINITION_ALLOWED_P then we handle the declarator and
for a function-definition here as well. If the declarator is a
static tree
cp_parser_init_declarator (cp_parser* parser,
cp_decl_specifier_seq *decl_specifiers,
+ VEC (deferred_access_check,gc)* checks,
bool function_definition_allowed_p,
bool member_p,
int declares_class_or_enum,
if (declarator == cp_error_declarator)
return error_mark_node;
+ /* Check that the number of template-parameter-lists is OK. */
+ if (!cp_parser_check_declarator_template_parameters (parser, declarator))
+ return error_mark_node;
+
if (declares_class_or_enum & 2)
cp_parser_check_for_definition_in_return_type (declarator,
decl_specifiers->type);
/* Check to see whether or not this declaration is a friend. */
friend_p = cp_parser_friend_p (decl_specifiers);
- /* Check that the number of template-parameter-lists is OK. */
- if (!cp_parser_check_declarator_template_parameters (parser, declarator))
- return error_mark_node;
-
/* Enter the newly declared entry in the symbol table. If we're
processing a declaration in a class-specifier, we wait until
after processing the initializer. */
if (!member_p)
{
if (parser->in_unbraced_linkage_specification_p)
- {
- decl_specifiers->storage_class = sc_extern;
- have_extern_spec = false;
- }
+ decl_specifiers->storage_class = sc_extern;
decl = start_decl (declarator, decl_specifiers,
is_initialized, attributes, prefix_attributes,
&pushed_scope);
current_function_decl = decl;
}
+ /* Perform access checks for template parameters. */
+ cp_parser_perform_template_parameter_access_checks (checks);
+
/* Perform the access control checks for the declarator and the
the decl-specifiers. */
perform_deferred_access_checks ();
is_non_constant_init = true;
if (is_initialized)
{
- if (declarator->kind == cdk_function
- && declarator->declarator->kind == cdk_id
- && initialization_kind == CPP_EQ)
- initializer = cp_parser_pure_specifier (parser);
+ if (function_declarator_p (declarator))
+ {
+ if (initialization_kind == CPP_EQ)
+ initializer = cp_parser_pure_specifier (parser);
+ else
+ {
+ /* If the declaration was erroneous, we don't really
+ know what the user intended, so just silently
+ consume the initializer. */
+ if (decl != error_mark_node)
+ error ("initializer provided for function");
+ cp_parser_skip_to_closing_parenthesis (parser,
+ /*recovering=*/true,
+ /*or_comma=*/false,
+ /*consume_paren=*/true);
+ }
+ }
else
initializer = cp_parser_initializer (parser,
&is_parenthesized_init,
member_p);
}
- if (attributes && declarator != cp_error_declarator)
+ if (attributes && declarator && declarator != cp_error_declarator)
declarator->attributes = attributes;
return declarator;
/* Normally, the array bound must be an integral constant
expression. However, as an extension, we allow VLAs
in function scopes. */
- else if (!at_function_scope_p ())
+ else if (!parser->in_function_body)
{
error ("array bound is not an integer constant");
bounds = error_mark_node;
abstract_ok = (dcl_kind == CP_PARSER_DECLARATOR_EITHER);
if (abstract_ok)
cp_parser_parse_tentatively (parser);
- unqualified_name
+ unqualified_name
= cp_parser_declarator_id (parser, /*optional_p=*/abstract_ok);
qualifying_scope = parser->scope;
if (abstract_ok)
*ctor_dtor_or_conv_p = -1;
}
}
- declarator = make_id_declarator (qualifying_scope,
+ declarator = make_id_declarator (qualifying_scope,
unqualified_name,
sfk);
declarator->id_loc = token->location;
if (is_condition && !is_cv_qualifier)
flags |= CP_PARSER_FLAGS_NO_USER_DEFINED_TYPES;
}
+
+ cp_parser_check_decl_spec (type_specifier_seq);
}
/* Parse a parameter-declaration-clause.
{
cp_parameter_declarator *parameters = NULL;
cp_parameter_declarator **tail = ¶meters;
+ bool saved_in_unbraced_linkage_specification_p;
/* Assume all will go well. */
*is_error = false;
+ /* The special considerations that apply to a function within an
+ unbraced linkage specifications do not apply to the parameters
+ to the function. */
+ saved_in_unbraced_linkage_specification_p
+ = parser->in_unbraced_linkage_specification_p;
+ parser->in_unbraced_linkage_specification_p = false;
/* Look for more parameters. */
while (true)
}
}
+ parser->in_unbraced_linkage_specification_p
+ = saved_in_unbraced_linkage_specification_p;
+
return parameters;
}
to avoid collecting live data on the stack. */
++function_depth;
/* Parse the assignment-expression. */
+ if (template_parm_p)
+ push_deferring_access_checks (dk_no_deferred);
default_argument
= cp_parser_assignment_expression (parser, /*cast_p=*/false);
+ if (template_parm_p)
+ pop_deferring_access_checks ();
/* Restore saved state. */
--function_depth;
parser->greater_than_is_operator_p
&& cp_lexer_next_token_is (parser->lexer, CPP_NAME)
&& cp_lexer_peek_nth_token (parser->lexer, 2)->type == CPP_COLON)
{
+ /* Warn the user that they are using an extension. */
+ if (pedantic)
+ pedwarn ("ISO C++ does not allow designated initializers");
/* Consume the identifier. */
- identifier = cp_lexer_consume_token (parser->lexer)->value;
+ identifier = cp_lexer_consume_token (parser->lexer)->u.value;
/* Consume the `:'. */
cp_lexer_consume_token (parser->lexer);
}
if (typename_p && decl != error_mark_node)
{
decl = make_typename_type (scope, decl, typename_type,
- /*complain=*/tf_error);
+ /*complain=*/tf_error);
if (decl != error_mark_node)
decl = TYPE_NAME (decl);
}
int has_trailing_semicolon;
bool nested_name_specifier_p;
unsigned saved_num_template_parameter_lists;
+ bool saved_in_function_body;
tree old_scope = NULL_TREE;
tree scope = NULL_TREE;
+ tree bases;
push_deferring_access_checks (dk_no_deferred);
/* Parse the class-head. */
type = cp_parser_class_head (parser,
&nested_name_specifier_p,
- &attributes);
+ &attributes,
+ &bases);
/* If the class-head was a semantic disaster, skip the entire body
of the class. */
if (!type)
return error_mark_node;
}
+ /* Process the base classes. If they're invalid, skip the
+ entire class body. */
+ if (!xref_basetypes (type, bases))
+ {
+ cp_parser_skip_to_closing_brace (parser);
+
+ /* Consuming the closing brace yields better error messages
+ later on. */
+ cp_lexer_consume_token (parser->lexer);
+ pop_deferring_access_checks ();
+ return error_mark_node;
+ }
+
/* Issue an error message if type-definitions are forbidden here. */
cp_parser_check_type_definition (parser);
/* Remember that we are defining one more class. */
saved_num_template_parameter_lists
= parser->num_template_parameter_lists;
parser->num_template_parameter_lists = 0;
+ /* We are not in a function body. */
+ saved_in_function_body = parser->in_function_body;
+ parser->in_function_body = false;
/* Start the class. */
if (nested_name_specifier_p)
scope = CP_DECL_CONTEXT (TYPE_MAIN_DECL (type));
old_scope = push_inner_scope (scope);
}
- type = begin_class_definition (type);
+ type = begin_class_definition (type, attributes);
if (type == error_mark_node)
/* If the type is erroneous, skip the entire body of the class. */
has_trailing_semicolon = (token->type == CPP_SEMICOLON);
/* Look for trailing attributes to apply to this class. */
if (cp_parser_allow_gnu_extensions_p (parser))
- {
- tree sub_attr = cp_parser_attributes_opt (parser);
- attributes = chainon (attributes, sub_attr);
- }
+ attributes = cp_parser_attributes_opt (parser);
if (type != error_mark_node)
type = finish_struct (type, attributes);
if (nested_name_specifier_p)
tree fn;
tree class_type = NULL_TREE;
tree pushed_scope = NULL_TREE;
-
+
/* In a first pass, parse default arguments to the functions.
Then, in a second pass, parse the bodies of the functions.
This two-phased approach handles cases like:
/* Put back any saved access checks. */
pop_deferring_access_checks ();
- /* Restore the count of active template-parameter-lists. */
+ /* Restore saved state. */
+ parser->in_function_body = saved_in_function_body;
parser->num_template_parameter_lists
= saved_num_template_parameter_lists;
class-key attributes nested-name-specifier [opt] template-id
base-clause [opt]
+ Upon return BASES is initialized to the list of base classes (or
+ NULL, if there are none) in the same form returned by
+ cp_parser_base_clause.
+
Returns the TYPE of the indicated class. Sets
*NESTED_NAME_SPECIFIER_P to TRUE iff one of the productions
involving a nested-name-specifier was used, and FALSE otherwise.
static tree
cp_parser_class_head (cp_parser* parser,
bool* nested_name_specifier_p,
- tree *attributes_p)
+ tree *attributes_p,
+ tree *bases)
{
tree nested_name_specifier;
enum tag_types class_key;
bool invalid_explicit_specialization_p = false;
tree pushed_scope = NULL_TREE;
unsigned num_templates;
- tree bases;
/* Assume no nested-name-specifier will be present. */
*nested_name_specifier_p = false;
type. */
num_templates = 0;
+ *bases = NULL_TREE;
+
/* Look for the class-key. */
class_key = cp_parser_class_key (parser);
if (class_key == none_type)
define a class that has already been declared with this
syntax.
- The proposed resolution for Core Issue 180 says that whever
+ The proposed resolution for Core Issue 180 says that wherever
you see `class T::X' you should treat `X' as a type-name.
It is OK to define an inaccessible class; for example:
if (template_id_p)
{
type = TREE_TYPE (id);
- maybe_process_partial_specialization (type);
+ type = maybe_process_partial_specialization (type);
if (nested_name_specifier)
pushed_scope = push_scope (nested_name_specifier);
}
type = NULL_TREE;
goto done;
}
+ else if (type == error_mark_node)
+ type = NULL_TREE;
/* We will have entered the scope containing the class; the names of
base classes should be looked up in that context. For example:
struct A::C : B {};
is valid. */
- bases = NULL_TREE;
/* Get the list of base-classes, if there is one. */
if (cp_lexer_next_token_is (parser->lexer, CPP_COLON))
- bases = cp_parser_base_clause (parser);
-
- /* Process the base classes. */
- xref_basetypes (type, bases);
+ *bases = cp_parser_base_clause (parser);
done:
/* Leave the scope given by the nested-name-specifier. We will
/* Consume the access-specifier. */
cp_lexer_consume_token (parser->lexer);
/* Remember which access-specifier is active. */
- current_access_specifier = token->value;
+ current_access_specifier = token->u.value;
/* Look for the `:'. */
cp_parser_require (parser, CPP_COLON, "`:'");
break;
member-declarator:
declarator attributes [opt] pure-specifier [opt]
declarator attributes [opt] constant-initializer [opt]
- identifier [opt] attributes [opt] : constant-expression */
+ identifier [opt] attributes [opt] : constant-expression
+
+ C++0x Extensions:
+
+ member-declaration:
+ static_assert-declaration */
static void
cp_parser_member_declaration (cp_parser* parser)
if (cp_lexer_next_token_is_keyword (parser->lexer, RID_USING))
{
/* Parse the using-declaration. */
- cp_parser_using_declaration (parser);
-
+ cp_parser_using_declaration (parser,
+ /*access_declaration_p=*/false);
return;
}
return;
}
+ /* If the next token is `static_assert' we have a static assertion. */
+ if (cp_lexer_next_token_is_keyword (parser->lexer, RID_STATIC_ASSERT))
+ {
+ cp_parser_static_assert (parser, /*member_p=*/true);
+ return;
+ }
+
+ if (cp_parser_using_declaration (parser, /*access_declaration=*/true))
+ return;
+
/* Parse the decl-specifier-seq. */
cp_parser_decl_specifier_seq (parser,
CP_PARSER_FLAGS_OPTIONAL,
for a pure-specifier; otherwise, we look for a
constant-initializer. When we call `grokfield', it will
perform more stringent semantics checks. */
- if (declarator->kind == cdk_function
- && declarator->declarator->kind == cdk_id)
+ if (function_declarator_p (declarator))
initializer = cp_parser_pure_specifier (parser);
else
/* Parse the initializer. */
/* Look for the `0' token. */
token = cp_lexer_consume_token (parser->lexer);
/* c_lex_with_flags marks a single digit '0' with PURE_ZERO. */
- if (token->type == CPP_NUMBER && (token->flags & PURE_ZERO))
- return integer_zero_node;
+ if (token->type != CPP_NUMBER || !(token->flags & PURE_ZERO))
+ {
+ cp_parser_error (parser,
+ "invalid pure specifier (only `= 0' is allowed)");
+ cp_parser_skip_to_end_of_statement (parser);
+ return error_mark_node;
+ }
+ if (PROCESSING_REAL_TEMPLATE_DECL_P ())
+ {
+ error ("templates may not be %<virtual%>");
+ return error_mark_node;
+ }
- 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;
}
/* Parse a constant-initializer.
static bool
cp_parser_function_try_block (cp_parser* parser)
{
+ tree compound_stmt;
tree try_block;
bool ctor_initializer_p;
/* Look for the `try' keyword. */
if (!cp_parser_require_keyword (parser, RID_TRY, "`try'"))
return false;
- /* Let the rest of the front-end know where we are. */
- try_block = begin_function_try_block ();
+ /* Let the rest of the front end know where we are. */
+ try_block = begin_function_try_block (&compound_stmt);
/* Parse the function-body. */
ctor_initializer_p
= cp_parser_ctor_initializer_opt_and_function_body (parser);
/* Parse the handlers. */
cp_parser_handler_seq (parser);
/* We're done with the handlers. */
- finish_function_handler_sequence (try_block);
+ finish_function_handler_sequence (try_block, compound_stmt);
return ctor_initializer_p;
}
static tree
cp_parser_exception_declaration (cp_parser* parser)
{
- tree decl;
cp_decl_specifier_seq type_specifiers;
cp_declarator *declarator;
const char *saved_message;
/* Restore the saved message. */
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;
+ if (!type_specifiers.any_specifiers_p)
+ return error_mark_node;
- return decl;
+ return grokdeclarator (declarator, &type_specifiers, CATCHPARM, 1, NULL);
}
/* Parse a throw-expression.
if (token->type == CPP_NAME
|| token->type == CPP_KEYWORD)
{
+ tree arguments = NULL_TREE;
+
/* Consume the token. */
token = cp_lexer_consume_token (parser->lexer);
/* Save away the identifier that indicates which attribute
this is. */
- identifier = token->value;
+ identifier = token->u.value;
attribute = build_tree_list (identifier, NULL_TREE);
/* Peek at the next token. */
/* If it's an `(', then parse the attribute arguments. */
if (token->type == CPP_OPEN_PAREN)
{
- tree arguments;
-
- arguments = (cp_parser_parenthesized_expression_list
- (parser, true, /*cast_p=*/false,
- /*non_constant_p=*/NULL));
- /* Save the identifier and arguments away. */
+ arguments = cp_parser_parenthesized_expression_list
+ (parser, true, /*cast_p=*/false,
+ /*non_constant_p=*/NULL);
+ /* Save the arguments away. */
TREE_VALUE (attribute) = arguments;
}
- /* Add this attribute to the list. */
- TREE_CHAIN (attribute) = attribute_list;
- attribute_list = attribute;
+ if (arguments != error_mark_node)
+ {
+ /* Add this attribute to the list. */
+ TREE_CHAIN (attribute) = attribute_list;
+ attribute_list = attribute;
+ }
token = cp_lexer_peek_token (parser->lexer);
}
If AMBIGUOUS_DECLS is non-NULL, *AMBIGUOUS_DECLS is set to a
TREE_LIST of candidates if name-lookup results in an ambiguity, and
- NULL_TREE otherwise. */
+ NULL_TREE otherwise. */
static tree
cp_parser_lookup_name (cp_parser *parser, tree name,
enum tag_types tag_type,
- bool is_template,
+ bool is_template,
bool is_namespace,
bool check_dependency,
tree *ambiguous_decls)
is correct; there shouldn't be a `template <>' for
the definition of `S<int>::f'. */
- if (CLASSTYPE_TEMPLATE_INFO (scope)
- && (CLASSTYPE_TEMPLATE_INSTANTIATION (scope)
- || uses_template_parms (CLASSTYPE_TI_ARGS (scope)))
- && PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (scope)))
+ if (!CLASSTYPE_TEMPLATE_INFO (scope))
+ /* If SCOPE does not have template information of any
+ kind, then it is not a template, nor is it nested
+ within a template. */
+ break;
+ if (explicit_class_specialization_p (scope))
+ break;
+ if (PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (scope)))
++num_templates;
scope = TYPE_CONTEXT (scope);
/* The common case is that this is not a constructor declarator, so
try to avoid doing lots of work if at all possible. It's not
valid declare a constructor at function scope. */
- if (at_function_scope_p ())
+ if (parser->in_function_body)
return false;
/* And only certain tokens can begin a constructor declarator. */
next_token = cp_lexer_peek_token (parser->lexer);
/* A parameter declaration begins with a decl-specifier,
which is either the "attribute" keyword, a storage class
specifier, or (usually) a type-specifier. */
- && !cp_lexer_next_token_is_keyword (parser->lexer, RID_ATTRIBUTE)
- && !cp_parser_storage_class_specifier_opt (parser))
+ && !cp_lexer_next_token_is_decl_specifier_keyword (parser->lexer))
{
tree type;
tree pushed_scope = NULL_TREE;
cp_parser_skip_to_end_of_block_or_statement (parser);
fn = error_mark_node;
}
+ else if (DECL_INITIAL (current_function_decl) != error_mark_node)
+ {
+ /* Seen already, skip it. An error message has already been output. */
+ cp_parser_skip_to_end_of_block_or_statement (parser);
+ fn = current_function_decl;
+ current_function_decl = NULL_TREE;
+ /* If this is a function from a class, pop the nested class. */
+ if (current_class_name)
+ pop_nested_class ();
+ }
else
fn = cp_parser_function_definition_after_declarator (parser,
/*inline_p=*/false);
tree fn;
bool ctor_initializer_p = false;
bool saved_in_unbraced_linkage_specification_p;
+ bool saved_in_function_body;
unsigned saved_num_template_parameter_lists;
+ saved_in_function_body = parser->in_function_body;
+ parser->in_function_body = true;
/* If the next token is `return', then the code may be trying to
make use of the "named return value" extension that G++ used to
support. */
= saved_in_unbraced_linkage_specification_p;
parser->num_template_parameter_lists
= saved_num_template_parameter_lists;
+ parser->in_function_body = saved_in_function_body;
return fn;
}
cp_parser_template_declaration_after_export (cp_parser* parser, bool member_p)
{
tree decl = NULL_TREE;
+ VEC (deferred_access_check,gc) *checks;
tree parameter_list;
bool friend_p = false;
bool need_lang_pop;
/* And the `<'. */
if (!cp_parser_require (parser, CPP_LESS, "`<'"))
return;
+ if (at_class_scope_p () && current_function_decl)
+ {
+ /* 14.5.2.2 [temp.mem]
+
+ A local class shall not have member templates. */
+ error ("invalid declaration of member template in local class");
+ cp_parser_skip_to_end_of_block_or_statement (parser);
+ return;
+ }
/* [temp]
-
+
A template ... shall not have C linkage. */
if (current_lang_name == lang_name_c)
{
}
else
need_lang_pop = false;
+
+ /* We cannot perform access checks on the template parameter
+ declarations until we know what is being declared, just as we
+ cannot check the decl-specifier list. */
+ push_deferring_access_checks (dk_deferred);
+
/* If the next token is `>', then we have an invalid
specialization. Rather than complain about an invalid template
parameter, issue an error message here. */
/* Parse the template parameters. */
parameter_list = cp_parser_template_parameter_list (parser);
+ /* Get the deferred access checks from the parameter list. These
+ will be checked once we know what is being declared, as for a
+ member template the checks must be performed in the scope of the
+ class containing the member. */
+ checks = get_deferred_access_checks ();
+
/* Look for the `>'. */
- cp_parser_skip_until_found (parser, CPP_GREATER, "`>'");
+ cp_parser_skip_to_end_of_template_parameter_list (parser);
/* We just processed one more parameter list. */
++parser->num_template_parameter_lists;
/* If the next token is `template', there are more template
/* There are no access checks when parsing a template, as we do not
know if a specialization will be a friend. */
push_deferring_access_checks (dk_no_check);
-
decl = cp_parser_single_declaration (parser,
+ checks,
member_p,
&friend_p);
-
pop_deferring_access_checks ();
/* If this is a member template declaration, let the front
/* We are done with the current parameter list. */
--parser->num_template_parameter_lists;
+ pop_deferring_access_checks ();
+
/* Finish up. */
finish_template_decl (parameter_list);
TREE_VALUE (parser->unparsed_functions_queues));
}
+/* Perform the deferred access checks from a template-parameter-list.
+ CHECKS is a TREE_LIST of access checks, as returned by
+ get_deferred_access_checks. */
+
+static void
+cp_parser_perform_template_parameter_access_checks (VEC (deferred_access_check,gc)* checks)
+{
+ ++processing_template_parmlist;
+ perform_access_checks (checks);
+ --processing_template_parmlist;
+}
+
/* Parse a `decl-specifier-seq [opt] init-declarator [opt] ;' or
`function-definition' sequence. MEMBER_P is true, this declaration
appears in a class scope.
static tree
cp_parser_single_declaration (cp_parser* parser,
+ VEC (deferred_access_check,gc)* checks,
bool member_p,
bool* friend_p)
{
decl = TYPE_NAME (decl);
else
decl = error_mark_node;
+
+ /* Perform access checks for template parameters. */
+ cp_parser_perform_template_parameter_access_checks (checks);
}
}
/* If it's not a template class, try for a template function. If
|| decl_specifiers.type != error_mark_node))
decl = cp_parser_init_declarator (parser,
&decl_specifiers,
+ checks,
/*function_definition_allowed_p=*/true,
member_p,
declares_class_or_enum,
conversions to integral or enumeration type can be used". */
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;
- }
+ if (cast != error_mark_node
+ && !cast_valid_in_integral_constant_expression_p (type)
+ && (cp_parser_non_integral_constant_expression
+ (parser, "a call to a constructor")))
+ return error_mark_node;
return cast;
}
}
}
else
- cp_parser_skip_until_found (parser, CPP_GREATER, "`>'");
+ cp_parser_skip_to_end_of_template_parameter_list (parser);
/* The `>' token might be a greater-than operator again now. */
parser->greater_than_is_operator_p
= saved_greater_than_is_operator_p;
if (!processing_template_decl)
parsed_arg = check_default_argument (TREE_VALUE (parm), parsed_arg);
-
+
TREE_PURPOSE (parm) = parsed_arg;
/* Update any instantiations we've already created. */
|| cp_lexer_next_token_is (parser->lexer, CPP_COMMA));
}
-/* Update the DECL_SPECS to reflect the STORAGE_CLASS. */
+/* Update the DECL_SPECS to reflect the storage class indicated by
+ KEYWORD. */
static void
-cp_parser_set_storage_class (cp_decl_specifier_seq *decl_specs,
- cp_storage_class storage_class)
+cp_parser_set_storage_class (cp_parser *parser,
+ cp_decl_specifier_seq *decl_specs,
+ enum rid keyword)
{
- if (decl_specs->storage_class != sc_none)
- decl_specs->multiple_storage_classes_p = true;
- else
- decl_specs->storage_class = storage_class;
+ cp_storage_class storage_class;
+
+ if (parser->in_unbraced_linkage_specification_p)
+ {
+ error ("invalid use of %qD in linkage specification",
+ ridpointers[keyword]);
+ return;
+ }
+ else if (decl_specs->storage_class != sc_none)
+ {
+ decl_specs->conflicting_specifiers_p = true;
+ return;
+ }
+
+ if ((keyword == RID_EXTERN || keyword == RID_STATIC)
+ && decl_specs->specs[(int) ds_thread])
+ {
+ error ("%<__thread%> before %qD", ridpointers[keyword]);
+ decl_specs->specs[(int) ds_thread] = 0;
+ }
+
+ switch (keyword)
+ {
+ case RID_AUTO:
+ storage_class = sc_auto;
+ break;
+ case RID_REGISTER:
+ storage_class = sc_register;
+ break;
+ case RID_STATIC:
+ storage_class = sc_static;
+ break;
+ case RID_EXTERN:
+ storage_class = sc_extern;
+ break;
+ case RID_MUTABLE:
+ storage_class = sc_mutable;
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ decl_specs->storage_class = storage_class;
+
+ /* A storage class specifier cannot be applied alongside a typedef
+ specifier. If there is a typedef specifier present then set
+ conflicting_specifiers_p which will trigger an error later
+ on in grokdeclarator. */
+ if (decl_specs->specs[(int)ds_typedef])
+ decl_specs->conflicting_specifiers_p = true;
}
/* Update the DECL_SPECS to reflect the TYPE_SPEC. If USER_DEFINED_P
}
}
-/* Like cp_parser_require, except that tokens will be skipped until
- the desired token is found. An error message is still produced if
- the next token is not as expected. */
+/* An error message is produced if the next token is not '>'.
+ All further tokens are skipped until the desired token is
+ found or '{', '}', ';' or an unbalanced ')' or ']'. */
static void
-cp_parser_skip_until_found (cp_parser* parser,
- enum cpp_ttype type,
- const char* token_desc)
+cp_parser_skip_to_end_of_template_parameter_list (cp_parser* parser)
{
- cp_token *token;
+ /* Current level of '< ... >'. */
+ unsigned level = 0;
+ /* Ignore '<' and '>' nested inside '( ... )' or '[ ... ]'. */
unsigned nesting_depth = 0;
- if (cp_parser_require (parser, type, token_desc))
+ /* Are we ready, yet? If not, issue error message. */
+ if (cp_parser_require (parser, CPP_GREATER, "%<>%>"))
return;
/* Skip tokens until the desired token is found. */
while (true)
{
/* Peek at the next token. */
- token = cp_lexer_peek_token (parser->lexer);
-
- /* If we've reached the token we want, consume it and stop. */
- if (token->type == type && !nesting_depth)
+ switch (cp_lexer_peek_token (parser->lexer)->type)
{
- cp_lexer_consume_token (parser->lexer);
- return;
- }
+ case CPP_LESS:
+ if (!nesting_depth)
+ ++level;
+ break;
- switch (token->type)
- {
- case CPP_EOF:
- case CPP_PRAGMA_EOL:
- /* If we've run out of tokens, stop. */
- return;
+ case CPP_GREATER:
+ if (!nesting_depth && level-- == 0)
+ {
+ /* We've reached the token we want, consume it and stop. */
+ cp_lexer_consume_token (parser->lexer);
+ return;
+ }
+ break;
- case CPP_OPEN_BRACE:
case CPP_OPEN_PAREN:
case CPP_OPEN_SQUARE:
++nesting_depth;
break;
- case CPP_CLOSE_BRACE:
case CPP_CLOSE_PAREN:
case CPP_CLOSE_SQUARE:
if (nesting_depth-- == 0)
return;
break;
+ case CPP_EOF:
+ case CPP_PRAGMA_EOL:
+ case CPP_SEMICOLON:
+ case CPP_OPEN_BRACE:
+ case CPP_CLOSE_BRACE:
+ /* The '>' was probably forgotten, don't look further. */
+ return;
+
default:
break;
}
static void
cp_parser_pre_parsed_nested_name_specifier (cp_parser *parser)
{
- tree value;
- tree check;
+ int i;
+ struct tree_check *check_value;
+ deferred_access_check *chk;
+ VEC (deferred_access_check,gc) *checks;
/* Get the stored value. */
- value = cp_lexer_consume_token (parser->lexer)->value;
+ check_value = cp_lexer_consume_token (parser->lexer)->u.tree_check_value;
/* Perform any access checks that were deferred. */
- for (check = TREE_PURPOSE (value); check; check = TREE_CHAIN (check))
- perform_or_defer_access_check (TREE_PURPOSE (check), TREE_VALUE (check));
+ checks = check_value->checks;
+ if (checks)
+ {
+ for (i = 0 ;
+ VEC_iterate (deferred_access_check, checks, i, chk) ;
+ ++i)
+ {
+ perform_or_defer_access_check (chk->binfo,
+ chk->decl,
+ chk->diag_decl);
+ }
+ }
/* Set the scope from the stored value. */
- parser->scope = TREE_VALUE (value);
- parser->qualifying_scope = TREE_TYPE (value);
+ parser->scope = check_value->value;
+ parser->qualifying_scope = check_value->qualifying_scope;
parser->object_scope = NULL_TREE;
}
case CPP_OBJC_STRING:
kwd = cp_lexer_consume_token (parser->lexer);
- return objc_build_string_object (kwd->value);
+ return objc_build_string_object (kwd->u.value);
case CPP_KEYWORD:
switch (kwd->keyword)
break;
}
default:
- error ("misplaced %<@%D%> Objective-C++ construct", kwd->value);
+ error ("misplaced %<@%D%> Objective-C++ construct", kwd->u.value);
cp_parser_skip_to_end_of_block_or_statement (parser);
}
token = cp_lexer_peek_token (parser->lexer);
while (cp_parser_objc_selector_p (token->type) || token->type == CPP_COLON
- || token->type == CPP_SCOPE)
+ || token->type == CPP_SCOPE)
{
tree selector = NULL_TREE;
selector = cp_parser_objc_selector (parser);
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_SCOPE))
{
/* Detect if we have a unary selector. */
if (maybe_unary_selector_p)
}
maybe_unary_selector_p = false;
token = cp_lexer_consume_token (parser->lexer);
-
+
if (token->type == CPP_SCOPE)
- {
+ {
sel_seq
= chainon (sel_seq,
build_tree_list (selector, NULL_TREE));
objc-alias-declaration:
@compatibility_alias identifier identifier ;
- This function registers the alias mapping with the Objective-C front-end.
+ This function registers the alias mapping with the Objective-C front end.
It returns nothing. */
static void
@class objc-identifier-list ;
The function registers the forward declarations with the Objective-C
- front-end. It returns nothing. */
+ front end. It returns nothing. */
static void
cp_parser_objc_class_declaration (cp_parser* parser)
tree quals = NULL_TREE, node;
cp_token *token = cp_lexer_peek_token (parser->lexer);
- node = token->value;
+ node = token->u.value;
while (node && TREE_CODE (node) == IDENTIFIER_NODE
&& (node == ridpointers [(int) RID_IN]
quals = tree_cons (NULL_TREE, node, quals);
cp_lexer_consume_token (parser->lexer);
token = cp_lexer_peek_token (parser->lexer);
- node = token->value;
+ node = token->u.value;
}
return quals;
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;
+ default: return token->u.value;
}
}
cplus_decl_attributes (&decl, attributes, /*flags=*/0);
}
else
- decl = grokfield (declarator, &declspecs,
+ decl = grokfield (declarator, &declspecs,
NULL_TREE, /*init_const_expr_p=*/false,
NULL_TREE, attributes);
cp_parser_objc_end_implementation (parser);
break;
default:
- error ("misplaced %<@%D%> Objective-C++ construct", kwd->value);
+ error ("misplaced %<@%D%> Objective-C++ construct", kwd->u.value);
cp_parser_skip_to_end_of_block_or_statement (parser);
}
}
case RID_AT_THROW:
return cp_parser_objc_throw_statement (parser);
default:
- error ("misplaced %<@%D%> Objective-C++ construct", kwd->value);
+ error ("misplaced %<@%D%> Objective-C++ construct", kwd->u.value);
cp_parser_skip_to_end_of_block_or_statement (parser);
}
\f
/* OpenMP 2.5 parsing routines. */
-/* All OpenMP clauses. OpenMP 2.5. */
-typedef enum pragma_omp_clause {
- PRAGMA_OMP_CLAUSE_NONE = 0,
-
- PRAGMA_OMP_CLAUSE_COPYIN,
- PRAGMA_OMP_CLAUSE_COPYPRIVATE,
- PRAGMA_OMP_CLAUSE_DEFAULT,
- PRAGMA_OMP_CLAUSE_FIRSTPRIVATE,
- PRAGMA_OMP_CLAUSE_IF,
- PRAGMA_OMP_CLAUSE_LASTPRIVATE,
- PRAGMA_OMP_CLAUSE_NOWAIT,
- PRAGMA_OMP_CLAUSE_NUM_THREADS,
- PRAGMA_OMP_CLAUSE_ORDERED,
- PRAGMA_OMP_CLAUSE_PRIVATE,
- PRAGMA_OMP_CLAUSE_REDUCTION,
- PRAGMA_OMP_CLAUSE_SCHEDULE,
- PRAGMA_OMP_CLAUSE_SHARED
-} pragma_omp_clause;
-
/* Returns name of the next clause.
If the clause is not recognized PRAGMA_OMP_CLAUSE_NONE is returned and
the token is not consumed. Otherwise appropriate pragma_omp_clause is
result = PRAGMA_OMP_CLAUSE_PRIVATE;
else if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
{
- tree id = cp_lexer_peek_token (parser->lexer)->value;
+ tree id = cp_lexer_peek_token (parser->lexer)->u.value;
const char *p = IDENTIFIER_POINTER (id);
switch (p[0])
case 'c':
if (!strcmp ("copyin", p))
result = PRAGMA_OMP_CLAUSE_COPYIN;
- else if (!strcmp ("copyprivate", p))
+ else if (!strcmp ("copyprivate", p))
result = PRAGMA_OMP_CLAUSE_COPYPRIVATE;
break;
case 'f':
return list;
if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
{
- tree id = cp_lexer_peek_token (parser->lexer)->value;
+ tree id = cp_lexer_peek_token (parser->lexer)->u.value;
const char *p = IDENTIFIER_POINTER (id);
switch (p[0])
cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true,
/*or_comma=*/false,
/*consume_paren=*/true);
-
+
if (kind == OMP_CLAUSE_DEFAULT_UNSPECIFIED)
return list;
schedule ( schedule-kind , expression )
schedule-kind:
- static | dynamic | guided | runtime
-*/
+ static | dynamic | guided | runtime */
static tree
cp_parser_omp_clause_schedule (cp_parser *parser, tree list)
if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
{
- tree id = cp_lexer_peek_token (parser->lexer)->value;
+ tree id = cp_lexer_peek_token (parser->lexer)->u.value;
const char *p = IDENTIFIER_POINTER (id);
switch (p[0])
OMP_CLAUSE_SCHEDULE_KIND (c) = OMP_CLAUSE_SCHEDULE_DYNAMIC;
break;
- case 'g':
+ case 'g':
if (strcmp ("guided", p) != 0)
goto invalid_kind;
OMP_CLAUSE_SCHEDULE_KIND (c) = OMP_CLAUSE_SCHEDULE_GUIDED;
tree stmt = begin_omp_structured_block ();
unsigned int save = cp_parser_begin_omp_structured_block (parser);
- cp_parser_statement (parser, NULL_TREE, false);
+ cp_parser_statement (parser, NULL_TREE, false, NULL);
cp_parser_end_omp_structured_block (parser, save);
return finish_omp_structured_block (stmt);
/* OpenMP 2.5:
- # pragma omp barrier new-line
-*/
+ # pragma omp barrier new-line */
static void
cp_parser_omp_barrier (cp_parser *parser, cp_token *pragma_tok)
/* OpenMP 2.5:
# pragma omp critical [(name)] new-line
- structured-block
-*/
+ structured-block */
static tree
cp_parser_omp_critical (cp_parser *parser, cp_token *pragma_tok)
cp_lexer_consume_token (parser->lexer);
name = cp_parser_identifier (parser);
-
+
if (name == error_mark_node
|| !cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'"))
cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true,
/* Note that the grammar doesn't call for a structured block here,
though the loop as a whole is a structured block. */
body = push_stmt_list ();
- cp_parser_statement (parser, NULL_TREE, false);
+ cp_parser_statement (parser, NULL_TREE, false, NULL);
body = pop_stmt_list (body);
return finish_omp_for (loc, decl, init, cond, incr, body, pre_body);
/* OpenMP 2.5:
#pragma omp for for-clause[optseq] new-line
- for-loop
-*/
+ for-loop */
#define OMP_FOR_CLAUSE_MASK \
( (1u << PRAGMA_OMP_CLAUSE_PRIVATE) \
/* OpenMP 2.5:
# pragma omp master new-line
- structured-block
-*/
+ structured-block */
static tree
cp_parser_omp_master (cp_parser *parser, cp_token *pragma_tok)
/* OpenMP 2.5:
# pragma omp ordered new-line
- structured-block
-*/
+ structured-block */
static tree
cp_parser_omp_ordered (cp_parser *parser, cp_token *pragma_tok)
while (1)
{
- cp_parser_statement (parser, NULL_TREE, false);
+ cp_parser_statement (parser, NULL_TREE, false, NULL);
tok = cp_lexer_peek_token (parser->lexer);
if (tok->pragma_kind == PRAGMA_OMP_SECTION)
/* OpenMP 2.5:
# pragma omp sections sections-clause[optseq] newline
- sections-scope
-*/
+ sections-scope */
#define OMP_SECTIONS_CLAUSE_MASK \
( (1u << PRAGMA_OMP_CLAUSE_PRIVATE) \
/* OpenMP 2.5:
# pragma parallel parallel-clause new-line
# pragma parallel for parallel-for-clause new-line
- # pragma parallel sections parallel-sections-clause new-line
-*/
+ # pragma parallel sections parallel-sections-clause new-line */
#define OMP_PARALLEL_CLAUSE_MASK \
( (1u << PRAGMA_OMP_CLAUSE_IF) \
}
else if (cp_lexer_next_token_is (parser->lexer, CPP_NAME))
{
- tree id = cp_lexer_peek_token (parser->lexer)->value;
+ tree id = cp_lexer_peek_token (parser->lexer)->u.value;
const char *p = IDENTIFIER_POINTER (id);
if (strcmp (p, "sections") == 0)
{
}
cp_parser_end_omp_structured_block (parser, save);
- return finish_omp_parallel (par_clause, block);
+ stmt = finish_omp_parallel (par_clause, block);
+ if (p_kind != PRAGMA_OMP_PARALLEL)
+ OMP_PARALLEL_COMBINED (stmt) = 1;
+ return stmt;
}
/* OpenMP 2.5:
# pragma omp single single-clause[optseq] new-line
- structured-block
-*/
+ structured-block */
#define OMP_SINGLE_CLAUSE_MASK \
( (1u << PRAGMA_OMP_CLAUSE_PRIVATE) \
vars = cp_parser_omp_var_list (parser, 0, NULL);
cp_parser_require_pragma_eol (parser, pragma_tok);
- if (!targetm.have_tls)
- sorry ("threadprivate variables not supported in this target");
-
finish_omp_threadprivate (vars);
}
PCH file, which is a GC collection point. So we need to handle this
first pragma without benefit of an existing lexer structure.
- Always returns one token to the caller in *FIRST_TOKEN. This is
+ Always returns one token to the caller in *FIRST_TOKEN. This is
either the true first token of the file, or the first token after
the initial pragma. */
cp_lexer_get_preprocessor_token (NULL, first_token);
if (first_token->type == CPP_STRING)
{
- name = first_token->value;
+ name = first_token->u.value;
cp_lexer_get_preprocessor_token (NULL, first_token);
if (first_token->type != CPP_PRAGMA_EOL)
while (first_token->type != CPP_PRAGMA_EOL && first_token->type != CPP_EOF)
cp_lexer_get_preprocessor_token (NULL, first_token);
- /* Read one more token to return to our caller. */
- cp_lexer_get_preprocessor_token (NULL, first_token);
-
/* Now actually load the PCH file. */
if (name)
c_common_pch_pragma (parse_in, TREE_STRING_POINTER (name));
+
+ /* Read one more token to return to our caller. We have to do this
+ after reading the PCH file in, since its pointers have to be
+ live. */
+ cp_lexer_get_preprocessor_token (NULL, first_token);
}
/* Normal parsing of a pragma token. Here we can (and must) use the
tok = cp_lexer_peek_token (the_parser->lexer);
ret = tok->type;
- *value = tok->value;
+ *value = tok->u.value;
if (ret == CPP_PRAGMA_EOL || ret == CPP_EOF)
ret = CPP_EOF;
the_parser = NULL;
}
-/* This variable must be provided by every front end. */
-
-int yydebug;
-
#include "gt-cp-parser.h"