OSDN Git Service

PR c++/9554
authorlerdsuwa <lerdsuwa@138bc75d-0d04-0410-961f-82ee72b054a4>
Sat, 10 May 2003 11:06:26 +0000 (11:06 +0000)
committerlerdsuwa <lerdsuwa@138bc75d-0d04-0410-961f-82ee72b054a4>
Sat, 10 May 2003 11:06:26 +0000 (11:06 +0000)
* 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.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@66659 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/cp/ChangeLog
gcc/cp/cp-tree.h
gcc/cp/parser.c
gcc/cp/semantics.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/parse/access1.C [new file with mode: 0644]

index 65cc247..2087066 100644 (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
index 2da12e2..89d068a 100644 (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);
index 0181f25..607749b 100644 (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;
   
index 8344038..dfe40ee 100644 (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;
index dd0c8c8..e30b580 100644 (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
diff --git a/gcc/testsuite/g++.dg/parse/access1.C b/gcc/testsuite/g++.dg/parse/access1.C
new file mode 100644 (file)
index 0000000..f8994e3
--- /dev/null
@@ -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>;