/* 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 *, tree, bool, bool, int, bool *);
static cp_declarator *cp_parser_declarator
(cp_parser *, cp_parser_declarator_kind, int *, bool *, bool);
static cp_declarator *cp_parser_direct_declarator
(cp_parser *, bool);
static void cp_parser_template_declaration_after_export
(cp_parser *, bool);
+static void cp_parser_perform_template_parameter_access_checks
+ (tree);
static tree cp_parser_single_declaration
- (cp_parser *, bool, bool *);
+ (cp_parser *, tree, 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
/* Parse the init-declarator. */
decl = cp_parser_init_declarator (parser, &decl_specifiers,
+ /*checks=*/NULL_TREE,
function_definition_allowed_p,
/*member_p=*/false,
declares_class_or_enum,
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. */
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. */
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;
else
/* Parse the dependent declaration. */
cp_parser_single_declaration (parser,
+ /*checks=*/NULL_TREE,
/*member_p=*/false,
/*friend_p=*/NULL);
/* We're done with the specialization. */
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,
+ tree checks,
bool function_definition_allowed_p,
bool member_p,
int declares_class_or_enum,
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 ();
saved_local_variables_forbidden_p
= parser->local_variables_forbidden_p;
parser->local_variables_forbidden_p = true;
+ /* The default argument expression may cause implicitly
+ defined member functions to be synthesized, which will
+ result in garbage collection. We must treat this
+ situation as if we were within the body of function so as
+ 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
= saved_greater_than_is_operator_p;
parser->local_variables_forbidden_p
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:
/* 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;
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 ();
+ 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;
}
cp_parser_template_declaration_after_export (cp_parser* parser, bool member_p)
{
tree decl = NULL_TREE;
+ tree checks;
tree parameter_list;
bool friend_p = false;
bool need_lang_pop;
}
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, "`>'");
/* We just processed one more parameter list. */
/* 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 (tree 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,
+ tree 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,
|| 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->multiple_storage_classes_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;
}
/* Update the DECL_SPECS to reflect the TYPE_SPEC. If USER_DEFINED_P
pop_scope (pushed_scope);
}
}
+ else
+ cp_parser_abort_tentative_parse (parser);
/* If parsing as an initialized declaration failed, try again as
a simple expression. */
if (decl == NULL)
- {
- cp_parser_abort_tentative_parse (parser);
- init = cp_parser_expression (parser, false);
- }
+ init = cp_parser_expression (parser, false);
}
cp_parser_require (parser, CPP_SEMICOLON, "`;'");
pre_body = pop_stmt_list (pre_body);
}
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: