This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[C++ PATCH] Stage 2: Implement access check for template instantiation(2/n) (Take 2)


Hello

This is a revised version of my patch:
 http://gcc.gnu.org/ml/gcc-patches/2005-05/msg01320.html
The only change compare to the previous version is the addition
of ACCESS_CHAIN macro and use it instead of TREE_CHAIN
as suggested in a couple followup to the original patch.
Part 1 and 3 of this work are not affected by the change and don't
need to be updated.

OK for the mainline?

--Kriang

2005-05-18  Kriang Lerdsuwanakij  <lerdsuwa@users.sourceforge.net>

	Defer access check until template instantiation 2/n
	* cp-tree.def (ACCESS): New tree code.
	* cp-tree.h (ACCESS_CHAIN): New macro.
	(find_access_checks_append_location, build_access): Add
	declarations.
	* parser.c (cp_parser_template_id, 
	cp_parser_pre_parsed_nested_name_specifier): Adjust.
	* semantics.c (find_access_checks_append_location, build_access):
	New functions.
	(pop_to_parent_deferring_access_checks,
	perform_or_defer_access_check): Use them.
	(perform_deferred_access_checks): Adjust.



diff -cprN gcc-main-save/gcc/cp/cp-tree.def gcc-main-new/gcc/cp/cp-tree.def
*** gcc-main-save/gcc/cp/cp-tree.def	2005-05-18 11:53:06.763229672 +0700
--- gcc-main-new/gcc/cp/cp-tree.def	2005-05-18 11:56:46.632804416 +0700
*************** DEFTREECODE (ALIAS_DECL, "alias_decl", t
*** 105,110 ****
--- 105,121 ----
     overloaded.  */
  DEFTREECODE (BASELINK, "baselink", tcc_exceptional, 0)
  
+ /* A tree node to store information used for deferred access checking.
+    There are two possibilities for the operands of this tree node.
+    Case 1: Operand 0 is the BINFO of scope through which access
+ 	   checking is performed.  Operand 1 is the DECL.
+    Case 2: Operand 0 is NULL_TREE.  Operand 1 is the TYPENAME_TYPE,
+ 	   UNBOUND_CLASS_TEMPLATE, or SCOPE_REF.
+    Its ACCESS_CHAIN points to the next ACCESS node to be checked, and
+    its EXPR_LOCATION is the source location where this ACCESS first
+    appear.  */
+ DEFTREECODE (ACCESS, "access", tcc_expression, 2)
+ 
  /* Template definition.  The following fields have the specified uses,
     although there are other macros in cp-tree.h that should be used for
     accessing this data.
diff -cprN gcc-main-save/gcc/cp/cp-tree.h gcc-main-new/gcc/cp/cp-tree.h
*** gcc-main-save/gcc/cp/cp-tree.h	2005-05-18 11:53:06.766229216 +0700
--- gcc-main-new/gcc/cp/cp-tree.h	2005-05-18 11:56:44.187176208 +0700
*************** struct tree_baselink GTY(())
*** 339,344 ****
--- 339,348 ----
    tree access_binfo;
  };
  
+ /* The next ACCESS node in the chain.  */
+ #define ACCESS_CHAIN(NODE) \
+   (TREE_CHAIN (ACCESS_CHECK (NODE)))
+ 
  /* The different kinds of ids that we encounter.  */
  
  typedef enum cp_id_kind
*************** extern void stop_deferring_access_checks
*** 4061,4066 ****
--- 4065,4073 ----
  extern void pop_deferring_access_checks		(void);
  extern tree get_deferred_access_checks		(void);
  extern void pop_to_parent_deferring_access_checks	(void);
+ extern tree *find_access_checks_append_location (tree *, tree, tree,
+ 						 location_t);
+ extern tree build_access (tree, tree, tree, location_t);
  extern void perform_deferred_access_checks	(void);
  extern void perform_or_defer_access_check	(tree, tree);
  extern void init_cp_semantics                   (void);
diff -cprN gcc-main-save/gcc/cp/parser.c gcc-main-new/gcc/cp/parser.c
*** gcc-main-save/gcc/cp/parser.c	2005-05-18 11:53:06.774228000 +0700
--- gcc-main-new/gcc/cp/parser.c	2005-05-18 11:59:56.382958008 +0700
*************** cp_parser_template_id (cp_parser *parser
*** 8435,8443 ****
        /* 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));
        /* Return the stored value.  */
        return TREE_VALUE (value);
      }
--- 8435,8443 ----
        /* 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 = ACCESS_CHAIN (check))
! 	perform_or_defer_access_check (TREE_OPERAND (check, 0),
! 				       TREE_OPERAND (check, 1));
        /* Return the stored value.  */
        return TREE_VALUE (value);
      }
*************** cp_parser_pre_parsed_nested_name_specifi
*** 15893,15900 ****
    /* 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));
    /* Set the scope from the stored value.  */
    parser->scope = TREE_VALUE (value);
    parser->qualifying_scope = TREE_TYPE (value);
--- 15893,15901 ----
    /* 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 = ACCESS_CHAIN (check))
!     perform_or_defer_access_check (TREE_OPERAND (check, 0), 
! 				   TREE_OPERAND (check, 1));
    /* Set the scope from the stored value.  */
    parser->scope = TREE_VALUE (value);
    parser->qualifying_scope = TREE_TYPE (value);
diff -cprN gcc-main-save/gcc/cp/semantics.c gcc-main-new/gcc/cp/semantics.c
*** gcc-main-save/gcc/cp/semantics.c	2005-05-18 11:53:06.775227848 +0700
--- gcc-main-new/gcc/cp/semantics.c	2005-05-18 11:58:19.903625096 +0700
*************** static tree finalize_nrv_r (tree *, int 
*** 100,106 ****
  
     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
--- 100,106 ----
  
     2. When a declaration such as a type, or a variable, is encountered,
        the function `perform_or_defer_access_check' is called.  It
!       maintains the list of deferred checks in a chain of ACCESS tree node.
  
     3. The global `current_class_type' or `current_function_decl' is then
        setup by the parser.  `enforce_access' relies on these information
*************** static tree finalize_nrv_r (tree *, int 
*** 108,114 ****
  
     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'
--- 108,114 ----
  
     4. Upon exiting the context mentioned in step 1,
        `perform_deferred_access_checks' is called to check all declaration
!       stored in the ACCESS 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'
*************** static tree finalize_nrv_r (tree *, int 
*** 116,125 ****
  
  typedef struct deferred_access GTY(())
  {
!   /* A TREE_LIST 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:
  
         class A { 
           class B {};
--- 116,125 ----
  
  typedef struct deferred_access GTY(())
  {
!   /* A chain of ACCESS tree nodes 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:
  
         class A { 
           class B {};
*************** typedef struct deferred_access GTY(())
*** 128,138 ****
  
         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;
    
    /* The current mode of access checks.  */
--- 128,134 ----
  
         A::B* A::f() { return 0; }
  
!      is valid, even though `A::B' is not generally accessible.  */
    tree deferred_access_checks;
    
    /* The current mode of access checks.  */
*************** pop_deferring_access_checks (void)
*** 199,207 ****
      VEC_pop (deferred_access, deferred_access_stack);
  }
  
! /* Returns a TREE_LIST representing the deferred checks.  
!    The TREE_PURPOSE of each node is the type through which the 
!    access occurred; the TREE_VALUE is the declaration named.
     */
  
  tree
--- 195,203 ----
      VEC_pop (deferred_access, deferred_access_stack);
  }
  
! /* Returns a chain of ACCESS tree node representing the deferred 
!    checks.  The operand 0 of each node is the type through which the 
!    access occurred; the operand 1 is the declaration named.
     */
  
  tree
*************** get_deferred_access_checks (void)
*** 214,219 ****
--- 210,237 ----
  	    ->deferred_access_checks);
  }
  
+ /* Search the chain of ACCESS tree node for BINFO and DECL.
+    If found, returns NULL.  Otherwise return the location of the
+    end of the chain where the chain can be extended.  With this
+    method of node insertion, the ACCESS nodes in the chain is sorted
+    in the order of appearance in the source code to aid diagnostics.  */
+ 
+ tree *
+ find_access_checks_append_location (tree *list, tree binfo, tree decl,
+ 				    location_t location)
+ {
+   tree *probe;
+   for (probe = list; *probe; probe = &ACCESS_CHAIN (*probe))
+     {
+       location_t probe_location = EXPR_LOCATION (*probe);
+       if (TREE_OPERAND (*probe, 0) == binfo
+ 	  && TREE_OPERAND (*probe, 1) == decl
+ 	  && !memcmp (&location, &probe_location, sizeof (location_t)))
+ 	return NULL;
+     }
+   return probe;
+ }
+ 
  /* Take current deferred checks and combine with the
     previous states if we also defer checks previously.
     Otherwise perform checks now.  */
*************** pop_to_parent_deferring_access_checks (v
*** 236,265 ****
        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));
  	}
        else
  	{
  	  /* Merge with parent.  */
  	  tree next;
! 	  tree original = ptr->deferred_access_checks;
  	  
  	  for (; checks; checks = next)
  	    {
! 	      tree probe;
! 	      
! 	      next = TREE_CHAIN (checks);
  
! 	      for (probe = original; probe; probe = TREE_CHAIN (probe))
! 		if (TREE_VALUE (probe) == TREE_VALUE (checks)
! 		    && TREE_PURPOSE (probe) == TREE_PURPOSE (checks))
! 		  goto found;
! 	      /* Insert into parent's checks.  */
! 	      TREE_CHAIN (checks) = ptr->deferred_access_checks;
! 	      ptr->deferred_access_checks = checks;
! 	    found:;
  	    }
  	}
      }
--- 254,282 ----
        if (ptr->deferring_access_checks_kind == dk_no_deferred)
  	{
  	  /* Check access.  */
! 	  for (; checks; checks = ACCESS_CHAIN (checks)) 
! 	    enforce_access (TREE_OPERAND (checks, 0), 
! 			    TREE_OPERAND (checks, 1));
  	}
        else
  	{
  	  /* Merge with parent.  */
  	  tree next;
! 	  tree *list = &ptr->deferred_access_checks;
  	  
  	  for (; checks; checks = next)
  	    {
! 	      tree *tail;
! 	      next = ACCESS_CHAIN (checks);
  
! 	      tail = find_access_checks_append_location
! 		       (list,
! 			TREE_OPERAND (checks, 0),
! 			TREE_OPERAND (checks, 1),
! 			EXPR_LOCATION (checks));
! 	      if (tail)
! 		*tail = checks;
! 	      ACCESS_CHAIN (checks) = NULL_TREE;
  	    }
  	}
      }
*************** perform_deferred_access_checks (void)
*** 288,297 ****
  
    for (deferred_check = get_deferred_access_checks ();
         deferred_check;
!        deferred_check = TREE_CHAIN (deferred_check))
      /* Check access.  */
!     enforce_access (TREE_PURPOSE (deferred_check), 
! 		    TREE_VALUE (deferred_check));
  }
  
  /* Defer checking the accessibility of DECL, when looked up in
--- 305,325 ----
  
    for (deferred_check = get_deferred_access_checks ();
         deferred_check;
!        deferred_check = ACCESS_CHAIN (deferred_check))
      /* Check access.  */
!     enforce_access (TREE_OPERAND (deferred_check, 0), 
! 		    TREE_OPERAND (deferred_check, 1));
! }
! 
! /* Build ACCESS tree node to store deferred access information.  */
! 
! tree
! build_access (tree binfo, tree decl, tree chain, location_t location)
! {
!   tree t = build_nt (ACCESS, binfo, decl);
!   ACCESS_CHAIN (t) = chain;
!   SET_EXPR_LOCATION (t, location);
!   return t;
  }
  
  /* Defer checking the accessibility of DECL, when looked up in
*************** perform_deferred_access_checks (void)
*** 300,306 ****
  void
  perform_or_defer_access_check (tree binfo, tree decl)
  {
-   tree check;
    deferred_access *ptr;
  
    /* Exit if we are in a context that no access checking is performed.
--- 328,333 ----
*************** perform_or_defer_access_check (tree binf
*** 318,333 ****
        enforce_access (binfo, decl);
        return;
      }
!   
!   /* 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;
!   /* If not, record the check.  */
!   ptr->deferred_access_checks
!     = tree_cons (binfo, decl, ptr->deferred_access_checks);
  }
  
  /* Returns nonzero if the current statement is a full expression,
--- 345,361 ----
        enforce_access (binfo, decl);
        return;
      }
!   else
!     {
!       tree *tail;
!       /* See if we are already going to perform this check.  */
!       tail = find_access_checks_append_location
! 	       (&(ptr->deferred_access_checks), binfo, decl,
! 		input_location);
!       /* If not, record the check.  */
!       if (tail)
! 	*tail = build_access (binfo, decl, NULL_TREE, input_location);
!     }
  }
  
  /* Returns nonzero if the current statement is a full expression,

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]