From 8d241e0b5734bb89d46fc9b6884f78ad70ff453c Mon Sep 17 00:00:00 2001 From: Kriang Lerdsuwanakij Date: Sat, 10 May 2003 11:06:26 +0000 Subject: [PATCH] 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 --- gcc/cp/ChangeLog | 15 ++++++ gcc/cp/cp-tree.h | 13 ++++-- gcc/cp/parser.c | 70 +++++++++++----------------- gcc/cp/semantics.c | 66 ++++++++++++++++++++++++-- gcc/testsuite/ChangeLog | 5 ++ gcc/testsuite/g++.dg/parse/access1.C | 13 ++++++ 6 files changed, 132 insertions(+), 50 deletions(-) create mode 100644 gcc/testsuite/g++.dg/parse/access1.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 65cc24723c5..2087066e0e7 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,18 @@ +2003-05-10 Kriang Lerdsuwanakij + + 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 PR c++/10555, c++/10576 diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 2da12e2cf4c..89d068a2183 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -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); diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 0181f2570bf..607749b2345 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -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; diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 83440386e4d..dfe40ee0278 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -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; diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index dd0c8c841c8..e30b5805844 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2003-05-10 Kriang Lerdsuwanakij + + PR c++/9554 + * g++.dg/parse/access1.C: New test. + 2003-05-09 DJ Delorie * g++.dg/other/stdarg1.C: Make sure arg "3" is passed as a diff --git a/gcc/testsuite/g++.dg/parse/access1.C b/gcc/testsuite/g++.dg/parse/access1.C new file mode 100644 index 00000000000..f8994e39e3c --- /dev/null +++ b/gcc/testsuite/g++.dg/parse/access1.C @@ -0,0 +1,13 @@ +// { dg-do compile } + +// Origin: Volker Lukas + +// PR c++/9554: Access checking for template ID as class head. + +class enclose +{ + template struct enclosed; +}; + +template <> +struct enclose::enclosed; -- 2.30.2