/* Classes [gram.class] */
static tree cp_parser_class_name
- (cp_parser *, bool, bool, bool, bool, bool, bool);
+ (cp_parser *, bool, bool, bool, bool, bool);
static tree cp_parser_class_specifier
(cp_parser *);
static tree cp_parser_class_head
/* Utility Routines */
static tree cp_parser_lookup_name
- (cp_parser *, tree, bool, bool, bool, bool);
+ (cp_parser *, tree, bool, bool, bool);
static tree cp_parser_lookup_name_simple
(cp_parser *, tree);
static tree cp_parser_maybe_treat_template_as_class
{
tree name;
- /* If parsing tenatively, we should commit; we really are
+ /* If parsing tentatively, we should commit; we really are
looking at a declaration. */
/* Consume the first identifier. */
name = cp_lexer_consume_token (parser->lexer)->value;
/*typename_keyword_p=*/false,
/*template_keyword_p=*/false,
/*type_p=*/false,
- /*check_access_p=*/true,
/*check_dependency=*/false,
/*class_head_p=*/false);
if (cp_parser_parse_definitely (parser))
/*typename_keyword_p=*/false,
/*template_keyword_p=*/false,
/*type_p=*/false,
- /*check_access_p=*/true,
/*check_dependency=*/false,
/*class_head_p=*/false);
if (cp_parser_parse_definitely (parser))
/*typename_keyword_p=*/false,
/*template_keyword_p=*/false,
/*type_p=*/false,
- /*check_access_p=*/true,
/*check_dependency=*/false,
/*class_head_p=*/false);
if (cp_parser_parse_definitely (parser))
/*typename_keyword_p=*/false,
/*template_keyword_p=*/false,
/*type_p=*/false,
- /*check_access_p=*/true,
/*check_dependency=*/false,
/*class_head_p=*/false);
/* If an error occurred, assume that the name of the
else
start = -1;
- push_deferring_access_checks (true);
+ push_deferring_access_checks (dk_deferred);
while (true)
{
typename_keyword_p,
template_keyword_p,
type_p,
- /*check_access_p=*/true,
check_dependency_p,
/*class_head_p=*/false);
/* If that didn't work, try for a namespace-name. */
/* Defer access checks until we know what is being declared; the
checks for names appearing in the decl-specifier-seq should be
done as if we were in the scope of the thing being declared. */
- push_deferring_access_checks (true);
+ push_deferring_access_checks (dk_deferred);
/* Parse the decl-specifier-seq. We have to keep track of whether
or not the decl-specifier-seq declares a named class or
where "T" should name a type -- but does not. */
if (cp_parser_diagnose_invalid_type_name (parser))
{
- /* If parsing tenatively, we should commit; we really are
+ /* If parsing tentatively, we should commit; we really are
looking at a declaration. */
cp_parser_commit_to_tentative_parse (parser);
/* Give up. */
/*typename_keyword_p=*/true,
/*template_keyword_p=*/false,
/*type_p=*/false,
- /*check_access_p=*/true,
/*check_dependency_p=*/true,
/*class_head_p=*/false);
/* Otherwise, we could also be looking for an ordinary identifier. */
/*typename_keyword_p=*/true,
/*template_keyword_p=*/false,
/*type_p=*/false,
- /*check_access_p=*/true,
/*check_dependency_p=*/true,
/*class_head_p=*/false);
/* If we found one, we're done. */
else
start_of_id = -1;
- push_deferring_access_checks (true);
+ push_deferring_access_checks (dk_deferred);
/* Parse the template-name. */
template = cp_parser_template_name (parser, template_keyword_p,
/* Look up the name. */
decl = cp_parser_lookup_name (parser, identifier,
- /*check_access=*/true,
/*is_type=*/false,
/*is_namespace=*/false,
check_dependency_p);
}
/* We're done with the instantiation. */
end_explicit_instantiation ();
- /* Trun access control back on. */
+ /* Turn access control back on. */
scope_chain->check_access = flag_access_control;
cp_parser_consume_semicolon_at_end_of_statement (parser);
/*typename_keyword_p=*/false,
/*template_keyword_p=*/false,
/*type_p=*/false,
- /*check_access_p=*/true,
/*check_dependency_p=*/true,
/*class_head_p=*/false);
/* If it's not a class-name, keep looking. */
types, so we set IS_TYPE to TRUE when calling
cp_parser_lookup_name. */
decl = cp_parser_lookup_name (parser, identifier,
- /*check_access=*/true,
/*is_type=*/true,
/*is_namespace=*/false,
/*check_dependency=*/true);
function if the token after the name is the scope resolution
operator.) */
namespace_decl = cp_parser_lookup_name (parser, identifier,
- /*check_access=*/true,
/*is_type=*/false,
/*is_namespace=*/true,
/*check_dependency=*/true);
function is being defined. There is no need to do this for the
definition of member functions; we cannot be defining a member
from another class. */
- push_deferring_access_checks (!member_p);
+ push_deferring_access_checks (member_p ? dk_no_check: dk_deferred);
/* Parse the decl-specifier-seq. */
decl_specifiers
keyword has been used to indicate that the name that appears next
is a template. TYPE_P is true iff the next name should be treated
as class-name, even if it is declared to be some other kind of name
- as well. The accessibility of the class-name is checked iff
- CHECK_ACCESS_P is true. If CHECK_DEPENDENCY_P is FALSE, names are
- looked up in dependent scopes. If CLASS_HEAD_P is TRUE, this class
- is the class being defined in a class-head.
+ as well. If CHECK_DEPENDENCY_P is FALSE, names are looked up in
+ dependent scopes. If CLASS_HEAD_P is TRUE, this class is the class
+ being defined in a class-head.
Returns the TYPE_DECL representing the class. */
bool typename_keyword_p,
bool template_keyword_p,
bool type_p,
- bool check_access_p,
bool check_dependency_p,
bool class_head_p)
{
type_p = true;
/* Look up the name. */
decl = cp_parser_lookup_name (parser, identifier,
- check_access_p,
type_p,
/*is_namespace=*/false,
check_dependency_p);
bool nested_name_specifier_p;
unsigned saved_num_template_parameter_lists;
- push_deferring_access_checks (false);
+ push_deferring_access_checks (dk_no_deferred);
/* Parse the class-head. */
type = cp_parser_class_head (parser,
if (cp_parser_global_scope_opt (parser, /*current_scope_valid_p=*/false))
qualified_p = true;
+ push_deferring_access_checks (dk_no_check);
+
/* Determine the name of the class. Begin by looking for an
optional nested-name-specifier. */
nested_name_specifier
class A { class B; };
class A::B {};
- So, we ask cp_parser_class_name not to check accessibility.
-
We do not know if we will see a class-name, or a
template-name. We look for a class-name first, in case the
class-name is a template-id; if we looked for the
/*typename_keyword_p=*/false,
/*template_keyword_p=*/false,
/*type_p=*/true,
- /*check_access_p=*/false,
/*check_dependency_p=*/false,
/*class_head_p=*/true);
/* If that didn't work, ignore the nested-name-specifier. */
}
}
+ pop_deferring_access_checks ();
+
/* If it's not a `:' or a `{' then we can't really be looking at a
class-head, since a class-head only appears as part of a
class-specifier. We have to detect this situation before calling
class_scope_p,
template_p,
/*type_p=*/true,
- /*check_access=*/true,
/*check_dependency_p=*/true,
/*class_head_p=*/false);
If there was no entity with the indicated NAME, the ERROR_MARK_NODE
is returned.
- If CHECK_ACCESS is TRUE, then access control is performed on the
- declaration to which the name resolves, and an error message is
- issued if the declaration is inaccessible.
-
If IS_TYPE is TRUE, bindings that do not refer to types are
ignored.
types. */
static tree
-cp_parser_lookup_name (cp_parser *parser, tree name, bool check_access,
+cp_parser_lookup_name (cp_parser *parser, tree name,
bool is_type, bool is_namespace, bool check_dependency)
{
tree decl;
During an explicit instantiation, access is not checked at all,
as per [temp.explicit]. */
- if (check_access && scope_chain->check_access && DECL_P (decl))
+ if (DECL_P (decl))
{
tree qualifying_type;
cp_parser_lookup_name_simple (cp_parser* parser, tree name)
{
return cp_parser_lookup_name (parser, name,
- /*check_access=*/true,
/*is_type=*/false,
/*is_namespace=*/false,
/*check_dependency=*/true);
cp_parser_parse_tentatively (parser);
/* Assume that we are looking at a constructor declarator. */
constructor_p = true;
+
+ push_deferring_access_checks (dk_no_check);
+
/* Look for the optional `::' operator. */
cp_parser_global_scope_opt (parser,
/*current_scope_valid_p=*/false);
/*typename_keyword_p=*/false,
/*template_keyword_p=*/false,
/*type_p=*/false,
- /*check_access_p=*/false,
/*check_dependency_p=*/false,
/*class_head_p=*/false);
/* If there was no class-name, then this is not a constructor. */
constructor_p = !cp_parser_error_occurred (parser);
}
+
+ pop_deferring_access_checks ();
+
/* If we're still considering a constructor, we have to see a `(',
to begin the parameter-declaration-clause, followed by either a
`)', an `...', or a decl-specifier. We need to check for a
whether it will be a function-definition. */
cp_parser_parse_tentatively (parser);
/* Defer access checks until we know what is being declared. */
- push_deferring_access_checks (true);
+ push_deferring_access_checks (dk_deferred);
/* Try the `decl-specifier-seq [opt] init-declarator [opt]'
alternative. */
/* In order to avoid repetitive access control error messages,
access checks are queued up until we are no longer parsing
tentatively. */
- push_deferring_access_checks (true);
+ push_deferring_access_checks (dk_deferred);
}
/* Commit to the currently active tentative parse. */
bool error_occurred;
the_parser = cp_parser_new ();
- push_deferring_access_checks (false);
+ push_deferring_access_checks (dk_no_deferred);
error_occurred = cp_parser_translation_unit (the_parser);
the_parser = NULL;
(SUBSTMT) = (COND); \
} while (0)
+/* Deferred Access Checking Overview
+ ---------------------------------
+
+ Most C++ expressions and declarations require access checking
+ to be performed during parsing. However, in several cases,
+ this has to be treated differently.
+
+ For member declarations, access checking has to be deferred
+ until more information about the declaration is known. For
+ example:
+
+ class A {
+ typedef int X;
+ public:
+ X f();
+ };
+
+ A::X A::f();
+ A::X g();
+
+ When we are parsing the function return type `A::X', we don't
+ really know if this is allowed until we parse the function name.
+
+ Furthermore, some contexts require that access checking is
+ never performed at all. These include class heads, and template
+ instantiations.
+
+ Typical use of access checking functions is described here:
+
+ 1. When we enter a context that requires certain access checking
+ mode, the function `push_deferring_access_checks' is called with
+ DEFERRING argument specifying the desired mode. Access checking
+ may be performed immediately (dk_no_deferred), deferred
+ (dk_deferred), or not performed (dk_no_check).
+
+ 2. When a declaration such as a type, or a variable, is encountered,
+ the function `perform_or_defer_access_check' is called. It
+ maintains a TREE_LIST of all deferred checks.
+
+ 3. The global `current_class_type' or `current_function_decl' is then
+ setup by the parser. `enforce_access' relies on these information
+ to check access.
+
+ 4. Upon exiting the context mentioned in step 1,
+ `perform_deferred_access_checks' is called to check all declaration
+ stored in the TREE_LIST. `pop_deferring_access_checks' is then
+ called to restore the previous access checking mode.
+
+ In case of parsing error, we simply call `pop_deferring_access_checks'
+ without `perform_deferred_access_checks'. */
+
/* Data for deferred access checking. */
static GTY(()) deferred_access *deferred_access_stack;
static GTY(()) deferred_access *deferred_access_free_list;
/* Save the current deferred access states and start deferred
access checking iff DEFER_P is true. */
-void push_deferring_access_checks (bool deferring_p)
+void push_deferring_access_checks (deferring_kind deferring)
{
deferred_access *d;
d->next = deferred_access_stack;
d->deferred_access_checks = NULL_TREE;
- d->deferring_access_checks_p = deferring_p;
+ d->deferring_access_checks_kind = deferring;
deferred_access_stack = d;
}
void resume_deferring_access_checks (void)
{
- deferred_access_stack->deferring_access_checks_p = true;
+ if (deferred_access_stack->deferring_access_checks_kind == dk_no_deferred)
+ deferred_access_stack->deferring_access_checks_kind = dk_deferred;
}
/* Stop deferring access checks. */
void stop_deferring_access_checks (void)
{
- deferred_access_stack->deferring_access_checks_p = false;
+ if (deferred_access_stack->deferring_access_checks_kind == dk_deferred)
+ deferred_access_stack->deferring_access_checks_kind = dk_no_deferred;
}
/* Discard the current deferred access checks and restore the
tree check;
/* If we are not supposed to defer access checks, just check now. */
- if (!deferred_access_stack->deferring_access_checks_p)
+ if (deferred_access_stack->deferring_access_checks_kind == dk_no_deferred)
{
enforce_access (class_type, decl);
return;
}
+ /* Exit if we are in a context that no access checking is performed. */
+ else if (deferred_access_stack->deferring_access_checks_kind == dk_no_check)
+ return;
/* See if we are already going to perform this check. */
for (check = deferred_access_stack->deferred_access_checks;