[PATCH] Fix PR c++/29475: Incomplete template diagnostics

Simon Martin simartin@users.sourceforge.net
Fri Dec 1 19:54:00 GMT 2006


Hello Mark.

On Tuesday 14 November 2006 05:57, you wrote:
> [...]
> > I am willing to try to change the "storage" of the deferred checks from a
> > TREE_LIST to a VEC.
>
> Thanks!
As promised, here's a patch that changes the way deferred access checks are 
stored: one uses a VEC of a new 'struct deferred_access_check' instead of a 
tree list. It is rather straight-forward except for the parser.c bits...

In some cases, the deferred access checks would be attached to a tree, and 
would be retrieved afterwards for processing; this is not possible anymore 
since we don't use a tree list anymore to store the deferred checks. To solve 
this problem, I've created a hashtable of a structure that associates a VEC 
of 'struct deferred_access_check' to a tree, and two accessors to add and 
lookup such an association.

This is my first use of both VEC and htab_t; I hope there are no mistakes.

I've regtested this patch with no new unexpected failure on i686-pc-linux-gnu. 
Is it OK?

Thanks in advance.

Best regards,
Simon
-------------- next part --------------
2006-12-01  Simon Martin  <simartin@users.sourceforge.net>

	PR c++/29475
	* cp-tree.h (struct deferred_access_check): New structure to represent a
	deferred access check. It replaces the previous representation as a tree.
	(get_deferred_access_checks): Return a vector of struct
	deferred_access_check instead of a tree list.
	(perform_access_checks): Take a vector of struct deferred_access_check
	instead of a tree list.
	* semantics.c (struct deferred_access): Store the deferred access checks
	as a vector of struct deferred_access_check instead of a tree list.
	(push_deferring_access_checks): Handle the change in struct
	deferred_access.
	(get_deferred_access_checks): Likewise.
	(pop_to_parent_deferring_access_checks): Likewise.
	(perform_or_defer_access_check): Likewise.
	(perform_access_checks): Take a vector of struct deferred_access_check
	instead of a tree list.
	* parser.c (struct deferred_access_check_hash_node): New structure to
	associate a tree with a vector of struct deferred_access_check.
	(deferred_access_check_hash, deferred_access_check_hash_node_eq): New
	functions to be able to create hash table(s) of struct
	deferred_access_check_hash_node.
	(deferred_access_checks_hash): New hashtable used to store tree / vector
	of deferred access checks associations.
	(save_deferred_access_checks): New function to save the association
	between a tree and a vector of deferred access checks in
	deferred_access_checks_hash.
	(get_saved_deferred_access_checks): New function to lookup the vector of
	deferred access checks associated with a given tree.
	(cp_parser_nested_name_specifier_opt): Associate the current deferred
	access checks with token->value by calling save_deferred_access_checks.
	(cp_parser_template_id): Use get_saved_deferred_access_checks and
	save_deferred_access_checks.
	(cp_parser_pre_parsed_nested_name_specifier): Likewise.
	(cp_parser_template_declaration_after_export): Adjusted the call to
	get_deferred_access_checks.
	(cp_parser_init_declarator): Take the access checks as a vector of struct
	deferred_access_check instead of a tree list.
	(cp_parser_single_declaration): Likewise.
	(cp_parser_perform_template_parameter_access_checks): Likewise.
	(cp_parser_simple_declaration): Adjusted the call to
	cp_parser_init_declarator.
	(cp_parser_explicit_specialization): Adjusted the call to
	cp_parser_single_declaration.
-------------- next part --------------
Index: gcc/cp/cp-tree.h
===================================================================
--- gcc/cp/cp-tree.h	(revision 119333)
+++ gcc/cp/cp-tree.h	(working copy)
@@ -4227,14 +4227,29 @@ extern tree copied_binfo			(tree, tree);
 extern tree original_binfo			(tree, tree);
 extern int shared_member_p			(tree);
 
+
+/* The representation of a deferred access check.  */
+
+typedef struct deferred_access_check GTY(())
+{
+  /* The base class in which the declaration is referenced. */
+  tree binfo;
+  /* The declaration whose access must be checked.  */
+  tree decl;
+  /* The declaration that should be used in the error message.  */
+  tree diag_decl;
+} deferred_access_check;
+DEF_VEC_O(deferred_access_check);
+DEF_VEC_ALLOC_O(deferred_access_check,gc);
+
 /* in semantics.c */
 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);
-extern tree get_deferred_access_checks		(void);
+extern VEC (deferred_access_check,gc)* get_deferred_access_checks		(void);
 extern void pop_to_parent_deferring_access_checks (void);
-extern void perform_access_checks		(tree);
+extern void perform_access_checks		(VEC (deferred_access_check,gc)*);
 extern void perform_deferred_access_checks	(void);
 extern void perform_or_defer_access_check	(tree, tree, tree);
 extern int stmts_are_full_exprs_p		(void);
Index: gcc/cp/semantics.c
===================================================================
--- gcc/cp/semantics.c	(revision 119333)
+++ gcc/cp/semantics.c	(working copy)
@@ -96,7 +96,7 @@ static tree finalize_nrv_r (tree *, int 
 
    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.
+      maintains a VECTOR 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
@@ -104,7 +104,7 @@ static tree finalize_nrv_r (tree *, int 
 
    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
+      stored in the VECTOR.   `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'
@@ -112,7 +112,7 @@ static tree finalize_nrv_r (tree *, int 
 
 typedef struct deferred_access GTY(())
 {
-  /* A TREE_LIST representing name-lookups for which we have deferred
+  /* A VECTOR representing name-lookups for which we have deferred
      checking access controls.  We cannot check the accessibility of
      names used in a decl-specifier-seq until we know what is being
      declared because code like:
@@ -124,12 +124,8 @@ typedef struct deferred_access GTY(())
 
        A::B* A::f() { return 0; }
 
-     is valid, even though `A::B' is not generally accessible.
-
-     The TREE_PURPOSE of each node is the scope used to qualify the
-     name being looked up; the TREE_VALUE is the DECL to which the
-     name was resolved.  */
-  tree deferred_access_checks;
+     is valid, even though `A::B' is not generally accessible.  */
+  VEC (deferred_access_check,gc)* GTY(()) deferred_access_checks;
 
   /* The current mode of access checks.  */
   enum deferring_kind deferring_access_checks_kind;
@@ -157,7 +153,7 @@ push_deferring_access_checks (deferring_
       deferred_access *ptr;
 
       ptr = VEC_safe_push (deferred_access, gc, deferred_access_stack, NULL);
-      ptr->deferred_access_checks = NULL_TREE;
+      ptr->deferred_access_checks = NULL;
       ptr->deferring_access_checks_kind = deferring;
     }
 }
@@ -200,7 +196,7 @@ pop_deferring_access_checks (void)
    access occurred; the TREE_VALUE is the declaration named.
    */
 
-tree
+VEC (deferred_access_check,gc)*
 get_deferred_access_checks (void)
 {
   if (deferred_access_no_check)
@@ -221,7 +217,7 @@ pop_to_parent_deferring_access_checks (v
     deferred_access_no_check--;
   else
     {
-      tree checks;
+      VEC (deferred_access_check,gc) *checks;
       deferred_access *ptr;
 
       checks = (VEC_last (deferred_access, deferred_access_stack)
@@ -232,29 +228,31 @@ pop_to_parent_deferring_access_checks (v
       if (ptr->deferring_access_checks_kind == dk_no_deferred)
 	{
 	  /* Check access.  */
-	  for (; checks; checks = TREE_CHAIN (checks))
-	    enforce_access (TREE_PURPOSE (checks),
-			    TREE_VALUE (checks), TREE_VALUE (checks));
+	  perform_access_checks (checks);
 	}
       else
 	{
 	  /* Merge with parent.  */
-	  tree next;
-	  tree original = ptr->deferred_access_checks;
-
-	  for (; checks; checks = next)
-	    {
-	      tree probe;
-
-	      next = TREE_CHAIN (checks);
+	  int i, j;
+	  deferred_access_check *chk, *probe;
 
-	      for (probe = original; probe; probe = TREE_CHAIN (probe))
-		if (TREE_VALUE (probe) == TREE_VALUE (checks)
-		    && TREE_PURPOSE (probe) == TREE_PURPOSE (checks))
-		  goto found;
+	  for (i = 0 ;
+	       VEC_iterate (deferred_access_check, checks, i, chk) ;
+	       ++i)
+	    {
+	      for (j = 0 ;
+		   VEC_iterate (deferred_access_check,
+				ptr->deferred_access_checks, j, probe) ;
+		   ++j)
+		{
+		  if (probe->binfo == chk->binfo &&
+		      probe->decl == chk->decl &&
+		      probe->diag_decl == chk->diag_decl)
+		    goto found;
+		}
 	      /* Insert into parent's checks.  */
-	      TREE_CHAIN (checks) = ptr->deferred_access_checks;
-	      ptr->deferred_access_checks = checks;
+	      VEC_safe_push (deferred_access_check, gc,
+			     ptr->deferred_access_checks, chk);
 	    found:;
 	    }
 	}
@@ -266,14 +264,16 @@ pop_to_parent_deferring_access_checks (v
    DECL node stored in the TREE_VALUE of the node.  */
 
 void
-perform_access_checks (tree checks)
+perform_access_checks (VEC (deferred_access_check,gc)* checks)
 {
-  while (checks)
-    {
-      enforce_access (TREE_PURPOSE (checks),
-		      TREE_VALUE (checks), TREE_VALUE (checks));
-      checks = TREE_CHAIN (checks);
-    }
+  int i;
+  deferred_access_check *chk;
+
+  if (!checks)
+    return;
+
+  for (i = 0 ; VEC_iterate (deferred_access_check, checks, i, chk) ; ++i)
+    enforce_access (chk->binfo, chk->decl, chk->diag_decl);
 }
 
 /* Perform the deferred access checks.
@@ -304,8 +304,11 @@ perform_deferred_access_checks (void)
 void
 perform_or_defer_access_check (tree binfo, tree decl, tree diag_decl)
 {
-  tree check;
+  int i;
   deferred_access *ptr;
+  deferred_access_check *chk;
+  deferred_access_check *new_access;
+
 
   /* Exit if we are in a context that no access checking is performed.
      */
@@ -324,14 +327,24 @@ perform_or_defer_access_check (tree binf
     }
 
   /* See if we are already going to perform this check.  */
-  for (check = ptr->deferred_access_checks;
-       check;
-       check = TREE_CHAIN (check))
-    if (TREE_VALUE (check) == decl && TREE_PURPOSE (check) == binfo)
-      return;
+  for (i = 0 ;
+       VEC_iterate (deferred_access_check,
+		    ptr->deferred_access_checks, i, chk) ;
+       ++i)
+    {
+      if (chk->decl == decl && chk->binfo == binfo &&
+	  chk->diag_decl == diag_decl)
+	{
+	  return;
+	}
+    }
   /* If not, record the check.  */
-  ptr->deferred_access_checks
-    = tree_cons (binfo, decl, ptr->deferred_access_checks);
+  new_access =
+    VEC_safe_push (deferred_access_check, gc,
+		   ptr->deferred_access_checks, 0);
+  new_access->binfo = binfo;
+  new_access->decl = decl;
+  new_access->diag_decl = diag_decl;
 }
 
 /* Returns nonzero if the current statement is a full expression,
Index: gcc/cp/parser.c
===================================================================
--- gcc/cp/parser.c	(revision 119333)
+++ gcc/cp/parser.c	(working copy)
@@ -1599,7 +1599,7 @@ static void cp_parser_static_assert
 /* Declarators [gram.dcl.decl] */
 
 static tree cp_parser_init_declarator
-  (cp_parser *, cp_decl_specifier_seq *, tree, bool, bool, int, bool *);
+  (cp_parser *, cp_decl_specifier_seq *, VEC (deferred_access_check,gc)*, 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
@@ -1799,9 +1799,9 @@ static tree cp_parser_function_definitio
 static void cp_parser_template_declaration_after_export
   (cp_parser *, bool);
 static void cp_parser_perform_template_parameter_access_checks
-  (tree);
+  (VEC (deferred_access_check,gc)*);
 static tree cp_parser_single_declaration
-  (cp_parser *, tree, bool, bool *);
+  (cp_parser *, VEC (deferred_access_check,gc)*, bool, bool *);
 static tree cp_parser_functional_cast
   (cp_parser *, tree);
 static tree cp_parser_save_member_function_body
@@ -2575,6 +2575,87 @@ cp_parser_make_typename_type (cp_parser 
 }
 
 
+/* Deferred checks management.
+   Some deferred checks are not done immediately, but rather "attached"
+   a tree for later processing. The "tree / deferred access checks"
+   associations are stored in a hash table.  */
+
+/* A node in the deferred access checks hash table.  */
+
+typedef struct deferred_access_check_hash_node GTY(())
+{
+  tree t;
+  /* The checks that have been associated with T.  */
+  VEC (deferred_access_check, gc)* GTY(()) checks;
+} deferred_access_check_hash_node;
+
+/* Computes a hash of a given node. The node's T pointer is hashed.  */
+
+static hashval_t
+deferred_access_check_hash (const void *node)
+{
+  deferred_access_check_hash_node *n =
+    (deferred_access_check_hash_node*) node;
+  return htab_hash_pointer (n->t);
+}
+
+/* Determines whether NODE1 and NODE2 are equal, i.e. whether their T
+   pointers are equal.  */
+
+static int
+deferred_access_check_node_eq (const void *node1, const void *node2)
+{
+  deferred_access_check_hash_node *n1 =
+    (deferred_access_check_hash_node*) node1;
+  deferred_access_check_hash_node *n2 =
+    (deferred_access_check_hash_node*) node2;
+  return htab_eq_pointer (n1->t, n2->t);
+}
+
+/* The deferred access checks hash table.  */
+
+static GTY((param_is (deferred_access_check_hash_node))) htab_t
+deferred_access_checks_hash;
+
+
+/* Saves that the CHECKS deferred checks must be performed for T.  */
+
+static void
+save_deferred_access_checks (tree t,
+			     VEC (deferred_access_check, gc) *checks)
+{
+  deferred_access_check_hash_node proxy, **chk;
+
+  /* Create the hash table if needed.  */
+  if (deferred_access_checks_hash == NULL)
+    deferred_access_checks_hash =
+      htab_create_ggc (31, deferred_access_check_hash,
+		       deferred_access_check_node_eq, NULL);
+
+  /* Create an entry for T.  */
+  proxy.t = t;
+  chk = (deferred_access_check_hash_node**)
+    htab_find_slot (deferred_access_checks_hash, &proxy, INSERT);
+
+  /* Setup the entry for T.  */
+  *chk = GGC_CNEW (deferred_access_check_hash_node);
+  (*chk)->t = t;
+  (*chk)->checks = checks;
+}
+
+
+/* Gets the deferred checks saved for T.  */
+
+static VEC (deferred_access_check, gc)*
+get_saved_deferred_access_checks (tree t)
+{
+  deferred_access_check_hash_node proxy, *chk;
+  proxy.t = t;
+  chk = htab_find (deferred_access_checks_hash, &proxy);
+  return chk ? chk->checks : NULL;
+}
+
+
 /* Create a new C++ parser.  */
 
 static cp_parser *
@@ -3889,16 +3970,16 @@ cp_parser_nested_name_specifier_opt (cp_
   if (success && start)
     {
       cp_token *token;
-      tree access_checks;
 
       token = cp_lexer_token_at (parser->lexer, start);
       /* Reset the contents of the START token.  */
       token->type = CPP_NESTED_NAME_SPECIFIER;
       /* Retrieve any deferred checks.  Do not pop this access checks yet
 	 so the memory will not be reclaimed during token replacing below.  */
-      access_checks = get_deferred_access_checks ();
-      token->value = build_tree_list (copy_list (access_checks),
+      token->value = build_tree_list (NULL_TREE,
 				      parser->scope);
+      save_deferred_access_checks (token->value,
+				   get_deferred_access_checks ());
       TREE_TYPE (token->value) = parser->qualifying_scope;
       token->keyword = RID_MAX;
 
@@ -7392,7 +7473,7 @@ cp_parser_simple_declaration (cp_parser*
 
       /* Parse the init-declarator.  */
       decl = cp_parser_init_declarator (parser, &decl_specifiers,
-					/*checks=*/NULL_TREE,
+					/*checks=*/NULL,
 					function_definition_allowed_p,
 					/*member_p=*/false,
 					declares_class_or_enum,
@@ -8817,11 +8898,13 @@ cp_parser_template_id (cp_parser *parser
 		       bool check_dependency_p,
 		       bool is_declaration)
 {
+  int i;
   tree template;
   tree arguments;
   tree template_id;
   cp_token_position start_of_id = 0;
-  tree access_check = NULL_TREE;
+  deferred_access_check *chk;
+  VEC (deferred_access_check,gc) *access_check;
   cp_token *next_token, *next_token_2;
   bool is_identifier;
 
@@ -8831,15 +8914,22 @@ cp_parser_template_id (cp_parser *parser
   if (next_token->type == CPP_TEMPLATE_ID)
     {
       tree value;
-      tree check;
 
       /* Get the stored value.  */
       value = cp_lexer_consume_token (parser->lexer)->value;
       /* Perform any access checks that were deferred.  */
-      for (check = TREE_PURPOSE (value); check; check = TREE_CHAIN (check))
-	perform_or_defer_access_check (TREE_PURPOSE (check),
-				       TREE_VALUE (check),
-				       TREE_VALUE (check));
+      access_check = get_saved_deferred_access_checks (value);
+      if (access_check)
+	{
+	  for (i = 0 ;
+	       VEC_iterate (deferred_access_check, access_check, i, chk) ;
+	       ++i)
+	    {
+	      perform_or_defer_access_check (chk->binfo,
+					     chk->decl,
+					     chk->diag_decl);
+	    }
+	}
       /* Return the stored value.  */
       return TREE_VALUE (value);
     }
@@ -8957,10 +9047,6 @@ cp_parser_template_id (cp_parser *parser
       template_id = lookup_template_function (template, arguments);
     }
 
-  /* Retrieve any deferred checks.  Do not pop this access checks yet
-     so the memory will not be reclaimed during token replacing below.  */
-  access_check = get_deferred_access_checks ();
-
   /* If parsing tentatively, replace the sequence of tokens that makes
      up the template-id with a CPP_TEMPLATE_ID token.  That way,
      should we re-parse the token stream, we will not have to repeat
@@ -8973,7 +9059,11 @@ cp_parser_template_id (cp_parser *parser
 
       /* Reset the contents of the START_OF_ID token.  */
       token->type = CPP_TEMPLATE_ID;
-      token->value = build_tree_list (access_check, template_id);
+      /* Retrieve any deferred checks.  Do not pop this access checks yet
+	 so the memory will not be reclaimed during token replacing below.  */
+      token->value = build_tree_list (NULL_TREE, template_id);
+      save_deferred_access_checks (token->value,
+				   get_deferred_access_checks ());
       token->keyword = RID_MAX;
 
       /* Purge all subsequent tokens.  */
@@ -9638,7 +9728,7 @@ cp_parser_explicit_specialization (cp_pa
   else
     /* Parse the dependent declaration.  */
     cp_parser_single_declaration (parser,
-				  /*checks=*/NULL_TREE,
+				  /*checks=*/NULL,
 				  /*member_p=*/false,
 				  /*friend_p=*/NULL);
   /* We're done with the specialization.  */
@@ -11086,7 +11176,7 @@ cp_parser_asm_definition (cp_parser* par
 static tree
 cp_parser_init_declarator (cp_parser* parser,
 			   cp_decl_specifier_seq *decl_specifiers,
-			   tree checks,
+			   VEC (deferred_access_check,gc)* checks,
 			   bool function_definition_allowed_p,
 			   bool member_p,
 			   int declares_class_or_enum,
@@ -15674,7 +15764,7 @@ static void
 cp_parser_template_declaration_after_export (cp_parser* parser, bool member_p)
 {
   tree decl = NULL_TREE;
-  tree checks;
+  VEC (deferred_access_check,gc) *checks;
   tree parameter_list;
   bool friend_p = false;
   bool need_lang_pop;
@@ -15788,7 +15878,7 @@ cp_parser_template_declaration_after_exp
    get_deferred_access_checks.  */
 
 static void
-cp_parser_perform_template_parameter_access_checks (tree checks)
+cp_parser_perform_template_parameter_access_checks (VEC (deferred_access_check,gc)* checks)
 {
   ++processing_template_parmlist;
   perform_access_checks (checks);
@@ -15804,7 +15894,7 @@ cp_parser_perform_template_parameter_acc
 
 static tree
 cp_parser_single_declaration (cp_parser* parser,
-			      tree checks,
+			      VEC (deferred_access_check,gc)* checks,
 			      bool member_p,
 			      bool* friend_p)
 {
@@ -16750,16 +16840,26 @@ cp_parser_optional_template_keyword (cp_
 static void
 cp_parser_pre_parsed_nested_name_specifier (cp_parser *parser)
 {
+  int i;
   tree value;
-  tree check;
+  deferred_access_check *chk;
+  VEC (deferred_access_check,gc) *checks;
 
   /* Get the stored value.  */
   value = cp_lexer_consume_token (parser->lexer)->value;
   /* Perform any access checks that were deferred.  */
-  for (check = TREE_PURPOSE (value); check; check = TREE_CHAIN (check))
-    perform_or_defer_access_check (TREE_PURPOSE (check),
-				   TREE_VALUE (check),
-				   TREE_VALUE (check));
+  checks = get_saved_deferred_access_checks (value);
+  if (checks)
+    {
+      for (i = 0 ;
+	   VEC_iterate (deferred_access_check, checks, i, chk) ;
+	   ++i)
+	{
+	  perform_or_defer_access_check (chk->binfo,
+					 chk->decl,
+					 chk->diag_decl);
+	}
+    }
   /* Set the scope from the stored value.  */
   parser->scope = TREE_VALUE (value);
   parser->qualifying_scope = TREE_TYPE (value);


More information about the Gcc-patches mailing list