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)


Hi

This is part two of access checking of template which is a
continuation of
 http://gcc.gnu.org/ml/gcc-patches/2005-05/msg00640.html

In this patch a new tree node called ACCESS is introduced. Currently we are using TREE_LIST to store list of access to
check later but when we want to check during template instantiation,
the source location where access appear is needed. So various
uses of TREE_LIST for access checking is replaced by ACCESS
which is an expression node with 2 operands and also contains
location information.


The first operand of ACCESS corresponds to TREE_PURPOSE,
and the second operand of ACCESS corresponds to TREE_VALUE
of TREE_LIST respectively.  Several ACCESS nodes can be
linked in a linked list via TREE_CHAIN.  Some comments
in the patch about this tree node mentions a usage (when
operand 0 is NULL_TREE) to be added in future work.

Two functions are also added by this patch, build_access and
find_access_checks_append_location.  They are declared
in cp-tree.h since they will be used in a few more places
in later patches.  The function find_access_checks_append_location
assures that the check is added as a chain in the order of
appearance in the source code.  So that diagnostics will
be issued in the correct order.

Tested on i686-pc-linux-gnu. OK for the mainline?

--Kriang

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

	Defer access check until template instantiation 2/n
	* cp-tree.def (ACCESS): New tree code.
	* cp-tree.h (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-08 16:24:12.000000000 +0700
--- gcc-main-new/gcc/cp/cp-tree.def	2005-05-08 22:04:34.000000000 +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 TREE_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-08 16:24:12.000000000 +0700
--- gcc-main-new/gcc/cp/cp-tree.h	2005-05-13 22:19:26.208979400 +0700
*************** extern void stop_deferring_access_checks
*** 4061,4066 ****
--- 4061,4069 ----
  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-08 16:24:13.000000000 +0700
--- gcc-main-new/gcc/cp/parser.c	2005-05-08 22:07:58.000000000 +0700
*************** cp_parser_template_id (cp_parser *parser
*** 8436,8443 ****
        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);
      }
--- 8436,8443 ----
        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_OPERAND (check, 0),
! 				       TREE_OPERAND (check, 1));
        /* Return the stored value.  */
        return TREE_VALUE (value);
      }
*************** cp_parser_pre_parsed_nested_name_specifi
*** 15894,15900 ****
    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);
--- 15894,15901 ----
    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_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-08 16:24:13.000000000 +0700
--- gcc-main-new/gcc/cp/semantics.c	2005-05-13 22:25:04.818502928 +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 = &TREE_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
*** 237,265 ****
  	{
  	  /* 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:;
  	    }
  	}
      }
--- 255,282 ----
  	{
  	  /* Check access.  */
  	  for (; checks; checks = TREE_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 = TREE_CHAIN (checks);
  
! 	      tail = find_access_checks_append_location
! 		       (list,
! 			TREE_OPERAND (checks, 0),
! 			TREE_OPERAND (checks, 1),
! 			EXPR_LOCATION (checks));
! 	      if (tail)
! 		*tail = checks;
! 	      TREE_CHAIN (checks) = NULL_TREE;
  	    }
  	}
      }
*************** perform_deferred_access_checks (void)
*** 290,297 ****
         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
--- 307,325 ----
         deferred_check;
         deferred_check = TREE_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);
!   TREE_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]