re PR c++/9554 (Out of class declaration of member class template specialisation rejected)

PR c++/9554
	* parser.c (cp_parser_class_name): Remove check_access parameter.
	All caller adjusted.  Update declaration.
	(cp_parser_lookup_name): Likewise.
	* semantics.c (push_deferring_access_checks): Change parameter type
	to enum deferring_kind.  All caller adjusted.
	(resume_deferring_access_checks): Adjust to use new enum.
	(stop_deferring_access_checks): Likewise.
	(perform_or_defer_access_check): Likewise.
	* cp-tree.h (deferring_kind): New enum.
	(deferred_access): Adjust field type.
	(push_deferring_access_checks): Update declaration.

	* g++.dg/parse/access1.C: New test.

From-SVN: r66659
This commit is contained in:
Kriang Lerdsuwanakij 2003-05-10 11:06:26 +00:00 committed by Kriang Lerdsuwanakij
parent 9ca5e6948d
commit 8d241e0b57
6 changed files with 132 additions and 50 deletions

View File

@ -1,3 +1,18 @@
2003-05-10 Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net>
PR c++/9554
* parser.c (cp_parser_class_name): Remove check_access parameter.
All caller adjusted. Update declaration.
(cp_parser_lookup_name): Likewise.
* semantics.c (push_deferring_access_checks): Change parameter type
to enum deferring_kind. All caller adjusted.
(resume_deferring_access_checks): Adjust to use new enum.
(stop_deferring_access_checks): Likewise.
(perform_or_defer_access_check): Likewise.
* cp-tree.h (deferring_kind): New enum.
(deferred_access): Adjust field type.
(push_deferring_access_checks): Update declaration.
2003-05-09 Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net>
PR c++/10555, c++/10576

View File

@ -3030,6 +3030,13 @@ typedef enum base_access {
ba_quiet = 4 /* Do not issue error messages (bit mask). */
} base_access;
/* The various kinds of access check during parsing. */
typedef enum deferring_kind {
dk_no_deferred = 0, /* Check access immediately */
dk_deferred = 1, /* Deferred check */
dk_no_check = 2 /* No access check */
} deferring_kind;
/* The kind of base we can find, looking in a class hierarchy.
Values <0 indicate we failed. */
typedef enum base_kind {
@ -3088,8 +3095,8 @@ typedef struct deferred_access GTY(())
name being looked up; the TREE_VALUE is the DECL to which the
name was resolved. */
tree deferred_access_checks;
/* TRUE iff we are deferring access checks. */
bool deferring_access_checks_p;
/* The current mode of access checks. */
enum deferring_kind deferring_access_checks_kind;
/* The next deferred access data in stack or linked-list. */
struct deferred_access *next;
} deferred_access;
@ -4044,7 +4051,7 @@ extern tree copied_binfo (tree, tree);
extern tree original_binfo (tree, tree);
/* in semantics.c */
extern void push_deferring_access_checks (bool defer_p);
extern void push_deferring_access_checks (deferring_kind);
extern void resume_deferring_access_checks (void);
extern void stop_deferring_access_checks (void);
extern void pop_deferring_access_checks (void);

View File

@ -1545,7 +1545,7 @@ static bool cp_parser_ctor_initializer_opt_and_function_body
/* 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
@ -1654,7 +1654,7 @@ static void cp_parser_label_declaration
/* 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
@ -1914,7 +1914,7 @@ cp_parser_diagnose_invalid_type_name (cp_parser *parser)
{
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;
@ -3081,7 +3081,6 @@ cp_parser_unqualified_id (cp_parser* 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))
@ -3099,7 +3098,6 @@ cp_parser_unqualified_id (cp_parser* 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))
@ -3117,7 +3115,6 @@ cp_parser_unqualified_id (cp_parser* 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))
@ -3132,7 +3129,6 @@ cp_parser_unqualified_id (cp_parser* 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
@ -3232,7 +3228,7 @@ cp_parser_nested_name_specifier_opt (cp_parser *parser,
else
start = -1;
push_deferring_access_checks (true);
push_deferring_access_checks (dk_deferred);
while (true)
{
@ -3485,7 +3481,6 @@ cp_parser_class_or_namespace_name (cp_parser *parser,
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. */
@ -6535,7 +6530,7 @@ cp_parser_simple_declaration (cp_parser* parser,
/* 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
@ -6564,7 +6559,7 @@ cp_parser_simple_declaration (cp_parser* parser,
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. */
@ -7312,7 +7307,6 @@ cp_parser_mem_initializer_id (cp_parser* parser)
/*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. */
@ -7322,7 +7316,6 @@ cp_parser_mem_initializer_id (cp_parser* parser)
/*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. */
@ -7942,7 +7935,7 @@ cp_parser_template_id (cp_parser *parser,
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,
@ -8116,7 +8109,6 @@ cp_parser_template_name (cp_parser* parser,
/* Look up the name. */
decl = cp_parser_lookup_name (parser, identifier,
/*check_access=*/true,
/*is_type=*/false,
/*is_namespace=*/false,
check_dependency_p);
@ -8343,7 +8335,7 @@ cp_parser_explicit_instantiation (cp_parser* parser)
}
/* 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);
@ -8687,7 +8679,6 @@ cp_parser_type_name (cp_parser* 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. */
@ -8846,7 +8837,6 @@ cp_parser_elaborated_type_specifier (cp_parser* parser,
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);
@ -9114,7 +9104,6 @@ cp_parser_namespace_name (cp_parser* parser)
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);
@ -10957,7 +10946,7 @@ cp_parser_function_definition (cp_parser* parser, bool* friend_p)
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
@ -11301,10 +11290,9 @@ cp_parser_initializer_list (cp_parser* parser)
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. */
@ -11313,7 +11301,6 @@ cp_parser_class_name (cp_parser *parser,
bool typename_keyword_p,
bool template_keyword_p,
bool type_p,
bool check_access_p,
bool check_dependency_p,
bool class_head_p)
{
@ -11368,7 +11355,6 @@ cp_parser_class_name (cp_parser *parser,
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);
@ -11434,7 +11420,7 @@ cp_parser_class_specifier (cp_parser* parser)
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,
@ -11635,6 +11621,8 @@ cp_parser_class_head (cp_parser* 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
@ -11659,8 +11647,6 @@ cp_parser_class_head (cp_parser* parser,
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
@ -11670,7 +11656,6 @@ cp_parser_class_head (cp_parser* parser,
/*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. */
@ -11729,6 +11714,8 @@ cp_parser_class_head (cp_parser* parser,
}
}
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
@ -12528,7 +12515,6 @@ cp_parser_base_specifier (cp_parser* parser)
class_scope_p,
template_p,
/*type_p=*/true,
/*check_access=*/true,
/*check_dependency_p=*/true,
/*class_head_p=*/false);
@ -13172,10 +13158,6 @@ cp_parser_label_declaration (cp_parser* parser)
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.
@ -13186,7 +13168,7 @@ cp_parser_label_declaration (cp_parser* parser)
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;
@ -13354,7 +13336,7 @@ cp_parser_lookup_name (cp_parser *parser, tree name, bool check_access,
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;
@ -13379,7 +13361,6 @@ static tree
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);
@ -13664,6 +13645,9 @@ cp_parser_constructor_declarator_p (cp_parser *parser, bool friend_p)
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);
@ -13699,12 +13683,14 @@ cp_parser_constructor_declarator_p (cp_parser *parser, bool friend_p)
/*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
@ -13968,7 +13954,7 @@ cp_parser_single_declaration (cp_parser* parser,
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. */
@ -14558,7 +14544,7 @@ cp_parser_parse_tentatively (cp_parser* parser)
/* 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. */
@ -14678,7 +14664,7 @@ yyparse (void)
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;

View File

@ -79,6 +79,57 @@ static tree clear_decl_rtl PARAMS ((tree *, int *, void *));
(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;
@ -86,7 +137,7 @@ 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;
@ -101,7 +152,7 @@ void push_deferring_access_checks (bool deferring_p)
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;
}
@ -110,14 +161,16 @@ void push_deferring_access_checks (bool deferring_p)
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
@ -199,11 +252,14 @@ void perform_or_defer_access_check (tree class_type, tree decl)
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;

View File

@ -1,3 +1,8 @@
2003-05-10 Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net>
PR c++/9554
* g++.dg/parse/access1.C: New test.
2003-05-09 DJ Delorie <dj@redhat.com>
* g++.dg/other/stdarg1.C: Make sure arg "3" is passed as a

View File

@ -0,0 +1,13 @@
// { dg-do compile }
// Origin: Volker Lukas <vlukas@gmx.de>
// PR c++/9554: Access checking for template ID as class head.
class enclose
{
template<typename T> struct enclosed;
};
template <>
struct enclose::enclosed<int>;