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 (4/n)


Hi

This is part 4 of the work to defer access check inside
template.  In this part checks throughout template are
handled properly except those appear in the template parameter
list.  (Names in template parameter list require saving them
during parsing and processing them once we know the
class/function template the name is for.  This will be
in part 5 of the series.)

The implementation idea follows closely to the proposal I
submitted for Stage 2 projects.  List of access are stored
in list and they are checked later when the template containing
the access is instantiated.  Two cases need to be handled,
instantiation of class template and function template.
It turned out that instantiation of static data member
require instantiating enclosing class template in order to
do name lookup for the static data member, and hence the
variable 'current_var_decl' suggested in the proposal is not
required and therefore not introduced into the frontend.

Here are the design:

- The list to store access can be reached via
 CLASSTYPE_DEFERRED_ACCESS_CHECKS for class template and
 DECL_DEFERRED_ACCESS_CHECKS for function template.  They
 refer to the new field 'deferred_access_checks' in the
 lang_specific part of RECORD_TYPE/FUNCTION_DECL node.

- The functions to decide whether to do access checking
 immediately or store it until instantiation are in
 'pop_to_parent_deferring_access_checks' and
 'enforce_access_or_defer_until_instantiation' in semantics.c
 The latter is called by various check functions in semantics.c

- The function to do access checking during instantiation is
 'perform_instantiation_deferred_access_checks' in pt.c

- Qualified id inside template must be saved to the list
 explicitly via the call 'perform_or_defer_access_check'.
 This includes both dependent and non-dependent name.
 To save the id, 'perform_or_defer_access_check'
 must be called with a *_TYPE node as the first argument
 and an IDENTIFIER_NODE as the second (as opposed to
 a BINFO_TREE and a *_DECL, respectively).

- 'make_typename_type' and 'make_unbound_class_template'
 now accepts a new flag 'tf_defer'.  When the flag is
 given the qualified id are saved.  The flag is passed when
 they are called by the parser, not during template
 substitution.

- One reason for the above is that the qualified id such
 as TYPENAME_TYPE may be partially instantiated.  And
 during tsubst, current_class_type/current_function_decl
 may not be correctly setup (for example, during partial
 ordering or template argument deduction)

- Another reason is that during tsubst of a typedef name,
 its type may turn out to be a TYPENAME_TYPE such as in
 PR 18681.

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

--Kriang

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

	Defer access check until template instantiation 4/n
	PR c++/16617
	PR c++/18681
	* cp-tree.def (ACCESS): Update comment.
	* cp-tree.h (lang_type_class, lang_decl): Add
	deferred_access_checks member.
	(CLASSTYPE_DEFERRED_ACCESS_CHECKS, DECL_DEFERRED_ACCESS_CHECKS):
	(tsubst_flags_t): Add tf_defer.
	(perform_instantiation_deferred_access_checks): Add declaration.
	* decl.c (make_typename_type, make_unbound_class_template):
	Call perform_or_defer_access_check only when tf_defer flag is set.
	* parser.c (cp_parser_make_typename_type,
	cp_parser_postfix_expression, cp_parser_elaborated_type_specifier,
	cp_parser_class_name): Pass tf_defer to	make_typename_type.
	(cp_parser_lookup_name): Pass tf_defer to make_typename_type, 
	make_unbound_class_template.  Pass the scope and name of SCOPE_REF
	to perform_or_defer_access_check.
	(cp_parser_class_specifier): Set current_function_decl when
	processing default argument.
	(cp_parser_template_declaration_after_export): Don't disable
	access checking.
	* pt.c (perform_instantiation_deferred_access_checks): New
	function.
	(instantiate_class_template, instantiate_decl): Use it.
	(tsubst_qualified_id): Don't check access here.
	* semantics.c (pop_to_parent_deferring_access_checks): Save access
	used in template.
	(enforce_access_or_defer_until_instantiation): New function.
	(perform_deferred_access_checks): Use it.
	(perform_or_defer_access_check): Likewise.  Ignore dependent names
	that are not explicitly passed as type and identifier.

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

	Defer access check until template instantiation 4/n
	PR c++/16617
	PR c++/18681
	g++.dg/template/access17.C: New test.
	g++.dg/template/access18.C: Likewise.
	g++.dg/template/access19.C: Likewise.
	g++.dg/template/access20.C: Likewise.
	g++.dg/template/access21.C: Likewise.
	g++.dg/template/access22.C: Likewise.
	g++.dg/template/access23.C: Likewise.


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 14:35:13.000000000 +0700
--- gcc-main-new/gcc/cp/cp-tree.def	2005-05-19 19:07:09.000000000 +0700
*************** DEFTREECODE (BASELINK, "baselink", tcc_e
*** 108,116 ****
  /* 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.  */
--- 108,118 ----
  /* 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.  Both operands
! 	   must be non-dependent.  It is used for expressions.
!    Case 2: Operand 0 is a TYPE node.  Operand 1 is the IDENTIFIER_NODE.
! 	   Operand 0 may be dependent.  It is used for qualified id
! 	   regardless whether it is dependent or not.
     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.  */
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 14:35:13.000000000 +0700
--- gcc-main-new/gcc/cp/cp-tree.h	2005-05-18 21:15:24.000000000 +0700
*************** struct lang_type_class GTY(())
*** 1073,1078 ****
--- 1073,1079 ----
    tree decl_list;
    tree template_info;
    tree befriending_classes;
+   tree deferred_access_checks;
    /* In a RECORD_TYPE, information specific to Objective-C++, such
       as a list of adopted protocols or a pointer to a corresponding
       @interface.  See objc/objc-act.h for details.  */
*************** struct lang_type GTY(())
*** 1351,1356 ****
--- 1352,1363 ----
  #define CLASSTYPE_BEFRIENDING_CLASSES(NODE) \
    (LANG_TYPE_CLASS_CHECK (NODE)->befriending_classes)
  
+ /* For class templates, this is a chain of ACCESS tree node
+    containing names that require access checking when the class
+    is instantiated.  */
+ #define CLASSTYPE_DEFERRED_ACCESS_CHECKS(NODE) \
+   (LANG_TYPE_CLASS_CHECK (NODE)->deferred_access_checks)
+ 
  /* Say whether this node was declared as a "class" or a "struct".  */
  #define CLASSTYPE_DECLARED_CLASS(NODE) \
    (LANG_TYPE_CLASS_CHECK (NODE)->declared_class)
*************** struct lang_decl GTY(())
*** 1578,1583 ****
--- 1585,1593 ----
    	   friendly classes. For a thunk function decl, it is the
    	   thunked to function decl.  */
  	tree befriending_classes;
+ 	/* For FUNCTION_DECL that are templates, this is
+ 	   DECL_DEFERRED_ACCESS_CHECKS.  */
+ 	tree deferred_access_checks;
  
  	/* For a non-virtual FUNCTION_DECL, this is
  	   DECL_FRIEND_CONTEXT.  For a virtual FUNCTION_DECL for which
*************** struct lang_decl GTY(())
*** 1835,1840 ****
--- 1845,1857 ----
  #define DECL_BEFRIENDING_CLASSES(NODE) \
    (DECL_LANG_SPECIFIC (NODE)->u.f.befriending_classes)
  
+ /* For a FUNCTION_DECL that is a template, this is a chain of
+    ACCESS tree node containing names that require access checking
+    when the function is instantiated.  */
+ #define DECL_DEFERRED_ACCESS_CHECKS(NODE) \
+   (DECL_LANG_SPECIFIC (FUNCTION_DECL_CHECK (NODE)) \
+    ->u.f.deferred_access_checks)
+ 
  /* Nonzero for FUNCTION_DECL means that this decl is a static
     member function.  */
  #define DECL_STATIC_FUNCTION_P(NODE) \
*************** typedef enum tsubst_flags_t {
*** 3054,3063 ****
  				   instantiate_type use) */
    tf_user = 1 << 5,		/* found template must be a user template
  				   (lookup_template_class use) */
!   tf_conv = 1 << 6              /* We are determining what kind of
  				   conversion might be permissible,
  				   not actually performing the
  				   conversion.  */
  } tsubst_flags_t;
  
  /* The kind of checking we can do looking in a class hierarchy.  */
--- 3071,3084 ----
  				   instantiate_type use) */
    tf_user = 1 << 5,		/* found template must be a user template
  				   (lookup_template_class use) */
!   tf_conv = 1 << 6,             /* We are determining what kind of
  				   conversion might be permissible,
  				   not actually performing the
  				   conversion.  */
+   tf_defer = 1 << 7		/* Mark this tree node so that access
+ 				   is performed during instantiation.
+ 				   (make_typename_type and
+ 				   make_unbound_class_template use)  */
  } tsubst_flags_t;
  
  /* The kind of checking we can do looking in a class hierarchy.  */
*************** extern tree build_non_dependent_args    
*** 4001,4006 ****
--- 4022,4028 ----
  extern bool reregister_specialization           (tree, tree, tree);
  extern tree fold_non_dependent_expr             (tree);
  extern tree fold_decl_constant_value            (tree);
+ extern void perform_instantiation_deferred_access_checks	(tree, tree);
  
  /* in repo.c */
  extern void init_repo (void);
diff -cprN gcc-main-save/gcc/cp/decl.c gcc-main-new/gcc/cp/decl.c
*** gcc-main-save/gcc/cp/decl.c	2005-05-08 16:24:12.000000000 +0700
--- gcc-main-new/gcc/cp/decl.c	2005-05-19 19:21:48.000000000 +0700
*************** build_typename_type (tree context, tree 
*** 2522,2532 ****
  
  /* Resolve `typename CONTEXT::NAME'.  TAG_TYPE indicates the tag
     provided to name the type.  Returns an appropriate type, unless an
!    error occurs, in which case error_mark_node is returned.  If we
!    locate a non-artificial TYPE_DECL and TF_KEEP_TYPE_DECL is set, we
!    return that, rather than the _TYPE it corresponds to, in other
!    cases we look through the type decl.  If TF_ERROR is set, complain
!    about errors, otherwise be quiet.  */
  
  tree
  make_typename_type (tree context, tree name, enum tag_types tag_type,
--- 2522,2538 ----
  
  /* Resolve `typename CONTEXT::NAME'.  TAG_TYPE indicates the tag
     provided to name the type.  Returns an appropriate type, unless an
!    error occurs, in which case error_mark_node is returned.
! 
!    If we locate a non-artificial TYPE_DECL and TF_KEEP_TYPE_DECL is 
!    set, we return that, rather than the _TYPE it corresponds to, in 
!    other cases we look through the type decl.  If TF_ERROR is set, 
!    complain about errors, otherwise be quiet.
! 
!    If TF_DEFER is set, queue this node for access check later.
!    This is intended for calls from parser, i.e., actually appear in
!    the source code, not from template substitution.  It avoids
!    queuing type coming from typedef.  */
  
  tree
  make_typename_type (tree context, tree name, enum tag_types tag_type,
*************** make_typename_type (tree context, tree n
*** 2586,2593 ****
  	      return error_mark_node;
  	    }
  
! 	  if (complain & tf_error)
! 	    perform_or_defer_access_check (TYPE_BINFO (context), tmpl);
  
  	  return lookup_template_class (tmpl,
  					TREE_OPERAND (fullname, 1),
--- 2592,2600 ----
  	      return error_mark_node;
  	    }
  
! 	  /* Defer this access check till instantiation.  */
! 	  if (complain & tf_defer)
! 	    perform_or_defer_access_check (context, name);
  
  	  return lookup_template_class (tmpl,
  					TREE_OPERAND (fullname, 1),
*************** make_typename_type (tree context, tree n
*** 2616,2623 ****
  		  return error_mark_node;
  		}
  
! 	      if (complain & tf_error)
! 		perform_or_defer_access_check (TYPE_BINFO (context), t);
  
  	      if (DECL_ARTIFICIAL (t) || !(complain & tf_keep_type_decl))
  		t = TREE_TYPE (t);
--- 2623,2631 ----
  		  return error_mark_node;
  		}
  
! 	      /* Defer this access check till instantiation.  */
! 	      if (complain & tf_defer)
! 	        perform_or_defer_access_check (context, name);
  
  	      if (DECL_ARTIFICIAL (t) || !(complain & tf_keep_type_decl))
  		t = TREE_TYPE (t);
*************** make_typename_type (tree context, tree n
*** 2636,2641 ****
--- 2644,2653 ----
        return error_mark_node;
      }
  
+   /* Defer this access check till instantiation.  */
+   if (complain & tf_defer)
+     perform_or_defer_access_check (context, name);
+ 
    return build_typename_type (context, name, fullname, tag_type);
  }
  
*************** make_typename_type (tree context, tree n
*** 2646,2652 ****
     If PARM_LIST is non-NULL, also make sure that the template parameter
     list of TEMPLATE_DECL matches.
  
!    If COMPLAIN zero, don't complain about any errors that occur.  */
  
  tree
  make_unbound_class_template (tree context, tree name, tree parm_list,
--- 2658,2666 ----
     If PARM_LIST is non-NULL, also make sure that the template parameter
     list of TEMPLATE_DECL matches.
  
!    If the TF_ERROR flag is not set in COMPLAIN, don't complain about any
!    errors that occur.  The meaning of TF_DEFER flag is the same as
!    make_typename_type.  */
  
  tree
  make_unbound_class_template (tree context, tree name, tree parm_list,
*************** make_unbound_class_template (tree contex
*** 2687,2698 ****
  	  return error_mark_node;
  	}
  
!       if (complain & tf_error)
! 	perform_or_defer_access_check (TYPE_BINFO (context), tmpl);
  
        return tmpl;
      }
  
    /* Build the UNBOUND_CLASS_TEMPLATE.  */
    t = make_aggr_type (UNBOUND_CLASS_TEMPLATE);
    TYPE_CONTEXT (t) = FROB_CONTEXT (context);
--- 2701,2717 ----
  	  return error_mark_node;
  	}
  
!       /* Defer this access check till instantiation.  */
!       if (complain & tf_defer)
!         perform_or_defer_access_check (context, name);
  
        return tmpl;
      }
  
+   /* Defer this access check till instantiation.  */
+   if (complain & tf_defer)
+     perform_or_defer_access_check (context, name);
+ 
    /* Build the UNBOUND_CLASS_TEMPLATE.  */
    t = make_aggr_type (UNBOUND_CLASS_TEMPLATE);
    TYPE_CONTEXT (t) = FROB_CONTEXT (context);
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 14:35:13.000000000 +0700
--- gcc-main-new/gcc/cp/parser.c	2005-05-19 19:29:57.000000000 +0700
*************** cp_parser_make_typename_type (cp_parser 
*** 2340,2351 ****
    if (TREE_CODE (id) == IDENTIFIER_NODE)
      {
        result = make_typename_type (scope, id, typename_type,
! 				   /*complain=*/0);
        if (result == error_mark_node)
  	cp_parser_diagnose_invalid_type_name (parser, scope, id);
        return result;
      }
!   return make_typename_type (scope, id, typename_type, tf_error);
  }
  
  
--- 2340,2351 ----
    if (TREE_CODE (id) == IDENTIFIER_NODE)
      {
        result = make_typename_type (scope, id, typename_type,
! 				   /*complain=*/tf_defer);
        if (result == error_mark_node)
  	cp_parser_diagnose_invalid_type_name (parser, scope, id);
        return result;
      }
!   return make_typename_type (scope, id, typename_type, tf_error | tf_defer);
  }
  
  
*************** cp_parser_postfix_expression (cp_parser 
*** 3917,3923 ****
  	else
  	  type = make_typename_type (parser->scope, id,
  				     typename_type,
! 				     /*complain=*/1);
  
  	postfix_expression = cp_parser_functional_cast (parser, type);
        }
--- 3917,3923 ----
  	else
  	  type = make_typename_type (parser->scope, id,
  				     typename_type,
! 				     /*complain=*/tf_error | tf_defer);
  
  	postfix_expression = cp_parser_functional_cast (parser, type);
        }
*************** cp_parser_elaborated_type_specifier (cp_
*** 9781,9787 ****
  	       && tag_type == typename_type)
  	type = make_typename_type (parser->scope, decl,
  				   typename_type,
! 				   /*complain=*/1);
        else
  	type = TREE_TYPE (decl);
      }
--- 9781,9787 ----
  	       && tag_type == typename_type)
  	type = make_typename_type (parser->scope, decl,
  				   typename_type,
! 				   /*complain=*/tf_error | tf_defer);
        else
  	type = TREE_TYPE (decl);
      }
*************** cp_parser_class_name (cp_parser *parser,
*** 12380,12386 ****
    /* If this is a typename, create a TYPENAME_TYPE.  */
    if (typename_p && decl != error_mark_node)
      {
!       decl = make_typename_type (scope, decl, typename_type, /*complain=*/1);
        if (decl != error_mark_node)
  	decl = TYPE_NAME (decl);
      }
--- 12380,12387 ----
    /* If this is a typename, create a TYPENAME_TYPE.  */
    if (typename_p && decl != error_mark_node)
      {
!       decl = make_typename_type (scope, decl, typename_type,
! 				 /*complain=*/tf_error | tf_defer);
        if (decl != error_mark_node)
  	decl = TYPE_NAME (decl);
      }
*************** cp_parser_class_name (cp_parser *parser,
*** 12399,12405 ****
         standard does not seem to be definitive, but there is no other
         valid interpretation of the following `::'.  Therefore, those
         names are considered class-names.  */
!     decl = TYPE_NAME (make_typename_type (scope, decl, tag_type, tf_error));
    else if (decl == error_mark_node
  	   || TREE_CODE (decl) != TYPE_DECL
  	   || TREE_TYPE (decl) == error_mark_node
--- 12400,12407 ----
         standard does not seem to be definitive, but there is no other
         valid interpretation of the following `::'.  Therefore, those
         names are considered class-names.  */
!     decl = TYPE_NAME (make_typename_type (scope, decl, tag_type, 
! 					  tf_error | tf_defer));
    else if (decl == error_mark_node
  	   || TREE_CODE (decl) != TYPE_DECL
  	   || TREE_TYPE (decl) == error_mark_node
*************** cp_parser_class_specifier (cp_parser* pa
*** 12537,12542 ****
--- 12539,12546 ----
  	   TREE_PURPOSE (parser->unparsed_functions_queues)
  	     = TREE_CHAIN (TREE_PURPOSE (parser->unparsed_functions_queues)))
  	{
+ 	  tree save_function_decl = current_function_decl;
+ 
  	  fn = TREE_VALUE (queue_entry);
  	  /* If there are default arguments that have not yet been processed,
  	     take care of them now.  */
*************** cp_parser_class_specifier (cp_parser* pa
*** 12549,12556 ****
--- 12553,12564 ----
  	    }
  	  /* Make sure that any template parameters are in scope.  */
  	  maybe_begin_member_template_processing (fn);
+ 
  	  /* Parse the default argument expressions.  */
+ 	  current_function_decl = fn;
  	  cp_parser_late_parsing_default_args (parser, fn);
+ 	  current_function_decl = save_function_decl;
+ 
  	  /* Remove any template parameters from the symbol table.  */
  	  maybe_end_member_template_processing ();
  	}
*************** cp_parser_lookup_name (cp_parser *parser
*** 14294,14299 ****
--- 14302,14308 ----
  {
    tree decl;
    tree object_type = parser->context->object_type;
+   bool check_access_p = true;
  
    /* Assume that the lookup will be unambiguous.  */
    if (ambiguous_p)
*************** cp_parser_lookup_name (cp_parser *parser
*** 14368,14373 ****
--- 14377,14384 ----
        if ((check_dependency || !CLASS_TYPE_P (parser->scope))
  	   && dependent_p)
  	{
+ 	  check_access_p = false;
+ 
  	  if (tag_type)
  	    {
  	      tree type;
*************** cp_parser_lookup_name (cp_parser *parser
*** 14376,14390 ****
  		 A::B' should be considered a type-name, even if `A'
  		 is dependent.  */
  	      type = make_typename_type (parser->scope, name, tag_type,
! 					 /*complain=*/1);
  	      decl = TYPE_NAME (type);
  	    }
  	  else if (is_template)
  	    decl = make_unbound_class_template (parser->scope,
  						name, NULL_TREE,
! 						/*complain=*/1);
  	  else
! 	    decl = build_nt (SCOPE_REF, parser->scope, name);
  	}
        else
  	{
--- 14387,14405 ----
  		 A::B' should be considered a type-name, even if `A'
  		 is dependent.  */
  	      type = make_typename_type (parser->scope, name, tag_type,
! 					 /*complain=*/tf_error | tf_defer);
  	      decl = TYPE_NAME (type);
  	    }
  	  else if (is_template)
  	    decl = make_unbound_class_template (parser->scope,
  						name, NULL_TREE,
! 						/*complain=*/tf_error
! 						| tf_defer);
  	  else
! 	    {
! 	      decl = build_nt (SCOPE_REF, parser->scope, name);
! 	      perform_or_defer_access_check (parser->scope, name);
! 	    }
  	}
        else
  	{
*************** cp_parser_lookup_name (cp_parser *parser
*** 14476,14482 ****
  
       During an explicit instantiation, access is not checked at all,
       as per [temp.explicit].  */
!   if (DECL_P (decl))
      check_accessibility_of_qualified_id (decl, object_type, parser->scope);
  
    return decl;
--- 14491,14497 ----
  
       During an explicit instantiation, access is not checked at all,
       as per [temp.explicit].  */
!   if (DECL_P (decl) && check_access_p)
      check_accessibility_of_qualified_id (decl, object_type, parser->scope);
  
    return decl;
*************** cp_parser_template_declaration_after_exp
*** 14990,14997 ****
    else
      {
        /* There are no access checks when parsing a template, as we do not
!          know if a specialization will be a friend.  */
!       push_deferring_access_checks (dk_no_check);
  
        decl = cp_parser_single_declaration (parser,
  					   member_p,
--- 15005,15013 ----
    else
      {
        /* There are no access checks when parsing a template, as we do not
!          know if a specialization will be a friend.  They are automatically
! 	 saved until the template is instantiated.  */
!       push_deferring_access_checks (dk_no_deferred);
  
        decl = cp_parser_single_declaration (parser,
  					   member_p,
diff -cprN gcc-main-save/gcc/cp/pt.c gcc-main-new/gcc/cp/pt.c
*** gcc-main-save/gcc/cp/pt.c	2005-05-18 14:35:01.000000000 +0700
--- gcc-main-new/gcc/cp/pt.c	2005-05-19 19:34:46.000000000 +0700
*************** instantiate_class_template (tree type)
*** 5860,5865 ****
--- 5860,5868 ----
  		   tsubst (TREE_VALUE (t), args, tf_none, NULL_TREE),
  		   CLASSTYPE_BEFRIENDING_CLASSES (type));
  
+   perform_instantiation_deferred_access_checks
+     (CLASSTYPE_DEFERRED_ACCESS_CHECKS (pattern), args);
+ 
    /* Set the file and line number information to whatever is given for
       the class itself.  This puts error messages involving generated
       implicit functions at a predictable point, and the same point
*************** tsubst_qualified_id (tree qualified_id, 
*** 7620,7631 ****
      }
    
    if (DECL_P (expr))
!     {
!       check_accessibility_of_qualified_id (expr, /*object_type=*/NULL_TREE,
! 					   scope);
!       /* Remember that there was a reference to this entity.  */
!       mark_used (expr);
!     }
  
    if (expr == error_mark_node || TREE_CODE (expr) == TREE_LIST)
      {
--- 7623,7630 ----
      }
    
    if (DECL_P (expr))
!     /* Remember that there was a reference to this entity.  */
!     mark_used (expr);
  
    if (expr == error_mark_node || TREE_CODE (expr) == TREE_LIST)
      {
*************** instantiate_decl (tree d, int defer_ok, 
*** 11578,11583 ****
--- 11577,11590 ----
        tsubst_expr (DECL_SAVED_TREE (code_pattern), args,
  		   tf_error | tf_warning, tmpl);
  
+       /* Make sure that we can see identifiers, and compute access
+ 	 correctly.  D is already the target FUNCTION_DECL with the
+ 	 right context.  */
+       push_access_scope (d);
+       perform_instantiation_deferred_access_checks
+ 	(DECL_DEFERRED_ACCESS_CHECKS (code_pattern), args);
+       pop_access_scope (d);
+ 
        /* We don't need the local specializations any more.  */
        htab_delete (local_specializations);
        local_specializations = saved_local_specializations;
*************** build_non_dependent_args (tree args)
*** 12597,12600 ****
--- 12604,12654 ----
    return nreverse (new_args);
  }
  
+ /* Check access of name used in template when it is instantiated.
+    CHECKS is the chain of ACCESS to check, ARGS is the template 
+    arguments for template substitution. */
+ 
+ void
+ perform_instantiation_deferred_access_checks (tree checks, tree args)
+ {
+   location_t save_input_location;
+   save_input_location = input_location;
+ 
+   for ( ; checks; checks = ACCESS_CHAIN (checks))
+     {
+       tree scope = TREE_OPERAND (checks, 0);
+ 
+       input_location = EXPR_LOCATION (checks);
+ 
+       if (TREE_CODE (scope) == TREE_BINFO)
+ 	{
+ 	  tree decl = TREE_OPERAND (checks, 1);
+ 
+ 	  gcc_assert (DECL_P (decl));
+ 
+ 	  enforce_access (scope, decl);
+ 	}
+       else
+ 	{
+ 	  tree decl = error_mark_node;
+ 	  tree name = TREE_OPERAND (checks, 1);
+ 
+ 	  gcc_assert (TYPE_P (scope)
+ 		      && TREE_CODE (name) == IDENTIFIER_NODE);
+ 
+ 	  scope = tsubst (scope, args, tf_none, NULL_TREE);
+ 	  if (CLASS_TYPE_P (scope))
+ 	    decl = lookup_field (scope, name, 0, false);
+ 
+ 	  /* These maybe ERROR_MARK_NODE upon tsubst error and
+ 	     NULL_TREE when lookup_field fails to find the member.  */
+ 	  if (scope != error_mark_node
+ 	      && decl && decl != error_mark_node)
+ 	    enforce_access (TYPE_BINFO (scope), decl);
+ 	}
+     }
+ 
+   input_location = save_input_location;
+ }
+ 
  #include "gt-cp-pt.h"
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 14:35:13.000000000 +0700
--- gcc-main-new/gcc/cp/semantics.c	2005-05-19 21:43:41.848731320 +0700
*************** static tree finalize_nrv_r (tree *, int 
*** 80,94 ****
           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:
     
--- 80,143 ----
           X f();
       };
  
!      A::X A::f();	// OK
!      A::X g();		// Error
  
     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 explicit
!    template instantiations.  Names inside templates need special
!    treatment.
! 
!    For templates, access of a particular name may depend on
!    instantiation.  For example:
! 
!      template <class T> class B;
!      template <class T> void f();
!      class C {
!        typedef int X;
!        friend class B<int>;
!        friend void f<int>();
!      };
! 
!      template <class T> class B {
!        C::X x;		// #1
!      };
! 
!      template <class T> void f() {
!        C::X x;		// #2
!      };
! 
!      int g() {
!        B<int> b1;	// OK
!        B<char> b2;	// Error
!        f<int>();	// OK
!        f<char>();	// Error
!      }
! 
!    We have to wait until instantiation time to check the access of
!    `C::X' despite it is a non-dependent name.  We solve this problem
!    by storing such names in two lists instead of calling `enforce_access':
!    CLASSTYPE_DEFERRED_ACCESS_CHECKS for class templates (RECORD_TYPE), and 
!    DECL_DEFERRED_ACCESS_CHECKS for function templates.  They will be 
!    checked during template instantiation.  We decide which list to put 
!    in based on the current scope.  If the scope is a class, such as
!    case #1 above, CLASSTYPE_DEFERRED_ACCESS_CHECKS will be used.  If 
!    the scope is a function such as case #2, DECL_DEFERRED_ACCESS_CHECKS
!    is used.
! 
!    There is a situation that the current scope is a namespace scope, i.e.,
!    when the name appears in the template header:
! 
!      template <C::X x> void h() {}
! 
!    this `C::X' is checked immediately.
! 
! 
!    Deferred Access Checking Usage
!    ------------------------------
  
     Typical use of access checking functions is described here:
     
*************** static tree finalize_nrv_r (tree *, int 
*** 107,115 ****
        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 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'
        without `perform_deferred_access_checks'.  */
--- 156,170 ----
        to check access.
  
     4. Upon exiting the context mentioned in step 1,
!       `perform_deferred_access_checks' is called.  For non-templates,
!       all declarations stored in the ACCESS chain are checked immediately.
!       For templates, the declarations may be moved to separated lists,
!       CLASSTYPE_DEFERRED_ACCESS_CHECKS for class templates, and
!       DECL_DEFERRED_ACCESS_CHECKS for function templates.  They will be
!       checked during template instantiation.
! 
!       `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'.  */
*************** DEF_VEC_ALLOC_O (deferred_access,gc);
*** 142,147 ****
--- 197,204 ----
  static GTY(()) VEC(deferred_access,gc) *deferred_access_stack;
  static GTY(()) unsigned deferred_access_no_check;
  
+ static void enforce_access_or_defer_until_instantiation (tree, tree);
+ 
  /* Save the current deferred access states and start deferred
     access checking iff DEFER_P is true.  */
  
*************** find_access_checks_append_location (tree
*** 234,240 ****
  
  /* Take current deferred checks and combine with the
     previous states if we also defer checks previously.
!    Otherwise perform checks now.  */
  
  void
  pop_to_parent_deferring_access_checks (void)
--- 291,298 ----
  
  /* Take current deferred checks and combine with the
     previous states if we also defer checks previously.
!    Otherwise perform checks now or queue it until template
!    instantiation.  */
  
  void
  pop_to_parent_deferring_access_checks (void)
*************** pop_to_parent_deferring_access_checks (v
*** 244,249 ****
--- 302,308 ----
    else
      {
        tree checks;
+       tree *list;
        deferred_access *ptr;
  
        checks = (VEC_last (deferred_access, deferred_access_stack)
*************** pop_to_parent_deferring_access_checks (v
*** 253,268 ****
        ptr = VEC_last (deferred_access, deferred_access_stack);
        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)
  	    {
--- 312,349 ----
        ptr = VEC_last (deferred_access, deferred_access_stack);
        if (ptr->deferring_access_checks_kind == dk_no_deferred)
  	{
! 	  if (!processing_template_decl)
! 	    /* Check immediately.  */
! 	    list = 0;
! 	  else
! 	    {
! 	      /* Queue in the correct list.  */
! 	      tree cs = current_scope ();
! 	      if (TYPE_P (cs))
! 		list = &CLASSTYPE_DEFERRED_ACCESS_CHECKS (cs);
! 	      else if (TREE_CODE (cs) == FUNCTION_DECL)
! 		list = &DECL_DEFERRED_ACCESS_CHECKS (cs);
! 	      else
! 		list = 0;
! 	    }
! 	}
!       else
! 	/* Merge with parent.  */
! 	list = &ptr->deferred_access_checks;
! 
!       if (!list)
! 	{
! 	  /* Check access.  The if is required to ignore names
! 	     that appear in template parameter.  */
! 	  for (; checks; checks = ACCESS_CHAIN (checks))
! 	    if (TREE_CODE (TREE_OPERAND (checks, 0)) == TREE_BINFO)
! 	      enforce_access (TREE_OPERAND (checks, 0), 
! 			      TREE_OPERAND (checks, 1));
  	}
        else
  	{
! 	  /* Merge with LIST.  */
  	  tree next;
  	  
  	  for (; checks; checks = next)
  	    {
*************** perform_deferred_access_checks (void)
*** 307,314 ****
         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.  */
--- 388,395 ----
         deferred_check;
         deferred_check = ACCESS_CHAIN (deferred_check))
      /* Check access.  */
!     enforce_access_or_defer_until_instantiation
!       (TREE_OPERAND (deferred_check, 0), TREE_OPERAND (deferred_check, 1));
  }
  
  /* Build ACCESS tree node to store deferred access information.  */
*************** perform_or_defer_access_check (tree binf
*** 335,350 ****
    if (deferred_access_no_check)
      return;
    
!   gcc_assert (TREE_CODE (binfo) == TREE_BINFO);
  
    ptr = VEC_last (deferred_access, deferred_access_stack);
    
    /* If we are not supposed to defer access checks, just check now.  */
!   if (ptr->deferring_access_checks_kind == dk_no_deferred)
!     {
!       enforce_access (binfo, decl);
!       return;
!     }
    else
      {
        tree *tail;
--- 416,443 ----
    if (deferred_access_no_check)
      return;
    
!   gcc_assert ((TREE_CODE (binfo) == TREE_BINFO && DECL_P (decl))
! 	      || (TYPE_P (binfo) && TREE_CODE (decl) == IDENTIFIER_NODE));
! 
!   /* For invalid code such as typename outside template.  */
!   if (TYPE_P (binfo) && !processing_template_decl)
!     return;
  
    ptr = VEC_last (deferred_access, deferred_access_stack);
    
+   /* Dependent names should arrive here as TYPENAME_TYPE,
+      UNBOUND_CLASS_TEMPLATE or SCOPE_REF with BINFO as NULL_TREE.
+      Otherwise it will arrive here again while processing
+      expressions in template body during instantiation.  */
+   if (TREE_CODE (binfo) == TREE_BINFO
+       && (dependent_type_p (BINFO_TYPE (binfo))
+ 	  || type_dependent_expression_p (decl) 
+ 	  || value_dependent_expression_p (decl)
+ 	  || dependent_type_p (DECL_CONTEXT (decl))))
+     ;
    /* If we are not supposed to defer access checks, just check now.  */
!   else if (ptr->deferring_access_checks_kind == dk_no_deferred)
!     enforce_access_or_defer_until_instantiation (binfo, decl);
    else
      {
        tree *tail;
*************** perform_or_defer_access_check (tree binf
*** 358,363 ****
--- 451,498 ----
      }
  }
  
+ /* Check the accessibility of DECL, when looked up in BINFO.  */
+ 
+ void
+ enforce_access_or_defer_until_instantiation (tree binfo, tree decl)
+ {
+   tree *list;
+ 
+   if (deferred_access_no_check)
+     return;
+ 
+   if (!processing_template_decl)
+     list = 0;
+   else
+     {
+       tree cs = current_scope ();
+       if (TYPE_P (cs))
+ 	list = &CLASSTYPE_DEFERRED_ACCESS_CHECKS (cs);
+       else if (TREE_CODE (cs) == FUNCTION_DECL)
+ 	list = &DECL_DEFERRED_ACCESS_CHECKS (cs);
+       else
+ 	/* Namespace scope such as names in template header.  */
+ 	list = 0;
+     }
+ 
+   if (!list)
+     {
+       if (TREE_CODE (binfo) == TREE_BINFO)
+ 	enforce_access (binfo, decl);
+       return;
+     }
+   else
+     {
+       tree *tail;
+       /* See if we are already going to perform this check.  */
+       tail = find_access_checks_append_location (list, 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,
     i.e. temporaries created during that statement should be destroyed
     at the end of the statement.  */
diff -cprN gcc-main-save/gcc/testsuite/g++.dg/template/access17.C gcc-main-new/gcc/testsuite/g++.dg/template/access17.C
*** gcc-main-save/gcc/testsuite/g++.dg/template/access17.C	1970-01-01 07:00:00.000000000 +0700
--- gcc-main-new/gcc/testsuite/g++.dg/template/access17.C	2005-05-18 21:15:24.000000000 +0700
***************
*** 0 ****
--- 1,32 ----
+ // Copyright (C) 2005 Free Software Foundation
+ // Contributed by Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net>
+ // { dg-do compile }
+ 
+ // PR c++/16617
+ 
+ // Two-phase name lookup for address of member:
+ // Protected member access inside function template
+ 
+ class B
+ {
+   protected:
+   int i;			// { dg-error "protected" }
+ };
+ 
+ template <class T> void fr ();
+ 
+ class D2 : public B
+ {
+   friend void fr<int> ();
+ };
+ 
+ template<int B::*> struct X
+ {};
+ 
+ template <class T> void fr ()
+ {
+   X<&B::i> x1;			// { dg-error "context" }
+   X<&D2::i> x2;			// { dg-error "context" }
+ }
+ 
+ template void fr<char>();	// { dg-error "instantiated" }
diff -cprN gcc-main-save/gcc/testsuite/g++.dg/template/access18.C gcc-main-new/gcc/testsuite/g++.dg/template/access18.C
*** gcc-main-save/gcc/testsuite/g++.dg/template/access18.C	1970-01-01 07:00:00.000000000 +0700
--- gcc-main-new/gcc/testsuite/g++.dg/template/access18.C	2005-05-18 21:15:24.000000000 +0700
***************
*** 0 ****
--- 1,30 ----
+ // Copyright (C) 2005 Free Software Foundation
+ // Contributed by Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net>
+ // { dg-do compile }
+ 
+ // Two-phase name lookup for address of member:
+ // Protected member access inside function template [class.protected/1]
+ 
+ class B
+ {
+   protected:
+   int i;			// { dg-error "protected" }
+ };
+ 
+ template <class T> void fr ();
+ 
+ class D2 : public B
+ {
+   friend void fr<int> ();
+ };
+ 
+ template<int B::*> struct X
+ {};
+ 
+ template <class T> void fr ()
+ {
+   X<&B::i> x1;			// { dg-error "context" }
+   X<&D2::i> x2;
+ }
+ 
+ template void fr<int>();	// { dg-error "instantiated" }
diff -cprN gcc-main-save/gcc/testsuite/g++.dg/template/access19.C gcc-main-new/gcc/testsuite/g++.dg/template/access19.C
*** gcc-main-save/gcc/testsuite/g++.dg/template/access19.C	1970-01-01 07:00:00.000000000 +0700
--- gcc-main-new/gcc/testsuite/g++.dg/template/access19.C	2005-05-18 21:15:24.000000000 +0700
***************
*** 0 ****
--- 1,45 ----
+ // { dg-do compile }
+ 
+ // Origin: Wolfgang Roehrl <wolfgang.roehrl@de.gi-de.com>
+ 
+ // PR c++/18681: Access checking of typedef containing typename
+ 
+ template <typename> class C1;
+ template <typename> class C2;
+ 
+ template <typename T_>
+ class C2<T_*>
+ {
+     typedef T_* T_PAR_TYPE;
+     friend class C1<T_*>;
+ };
+ 
+ template <typename T_>
+ class C1
+ {
+     typedef typename C2<T_>::T_PAR_TYPE T_PAR;
+     struct S1
+     {
+         T_PAR par;
+     };
+ 
+     static void fx (S1&);
+ 
+ public:
+     void f (T_PAR ptr);
+ };
+ 
+ template <typename T_>
+ void C1<T_>::f (T_PAR ptr_)
+ {
+     S1 s1;
+     fx (s1);
+ }
+ 
+ typedef int T_MEM[20];
+ 
+ void f (T_MEM* p1)
+ {
+     C1<T_MEM*> c1;
+     c1.f (p1);
+ }
diff -cprN gcc-main-save/gcc/testsuite/g++.dg/template/access20.C gcc-main-new/gcc/testsuite/g++.dg/template/access20.C
*** gcc-main-save/gcc/testsuite/g++.dg/template/access20.C	1970-01-01 07:00:00.000000000 +0700
--- gcc-main-new/gcc/testsuite/g++.dg/template/access20.C	2005-05-18 21:15:24.000000000 +0700
***************
*** 0 ****
--- 1,13 ----
+ // Copyright (C) 2005 Free Software Foundation
+ // Contributed by Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net>
+ // { dg-do compile }
+ 
+ class A { typedef int X; }; // { dg-error "private" }
+ 
+ template <class T> class C {
+   void f() {
+     int x = typename T::X(0); // { dg-error "this context" }
+   }
+ };
+ 
+ template class C<A>; // { dg-error "instantiated" }
diff -cprN gcc-main-save/gcc/testsuite/g++.dg/template/access21.C gcc-main-new/gcc/testsuite/g++.dg/template/access21.C
*** gcc-main-save/gcc/testsuite/g++.dg/template/access21.C	1970-01-01 07:00:00.000000000 +0700
--- gcc-main-new/gcc/testsuite/g++.dg/template/access21.C	2005-05-19 00:22:55.000000000 +0700
***************
*** 0 ****
--- 1,17 ----
+ // Copyright (C) 2004 Free Software Foundation
+ // Contributed by Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net>
+ // { dg-do compile }
+ 
+ // Access check of non-dependent typename
+ 
+ class A {
+   typedef int X;		// { dg-error "private" }
+ };
+ 
+ template <class T> class C {
+   static const typename A::X x = 0; // { dg-error "context" }
+ };
+ 
+ template <class T> const typename A::X C<T>::x; // { dg-error "context" }
+ 
+ template const A::X C<int>::x; // { dg-error "instantiated" }
diff -cprN gcc-main-save/gcc/testsuite/g++.dg/template/access22.C gcc-main-new/gcc/testsuite/g++.dg/template/access22.C
*** gcc-main-save/gcc/testsuite/g++.dg/template/access22.C	1970-01-01 07:00:00.000000000 +0700
--- gcc-main-new/gcc/testsuite/g++.dg/template/access22.C	2005-05-19 00:29:49.000000000 +0700
***************
*** 0 ****
--- 1,18 ----
+ // Copyright (C) 2005 Free Software Foundation
+ // Contributed by Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net>
+ // { dg-do compile }
+ 
+ // Access checking according to default argument instantiation [temp.inst]/11
+ 
+ template <class T> class C;
+ template <class T> void f(int = C<T>::i) {}
+ 
+ template <class T> class C {
+   static const int i = 0;
+   template <class U> friend void f(int);
+ };
+ 
+ void g()
+ {
+   f<char>();
+ }
diff -cprN gcc-main-save/gcc/testsuite/g++.dg/template/access23.C gcc-main-new/gcc/testsuite/g++.dg/template/access23.C
*** gcc-main-save/gcc/testsuite/g++.dg/template/access23.C	1970-01-01 07:00:00.000000000 +0700
--- gcc-main-new/gcc/testsuite/g++.dg/template/access23.C	2005-05-19 00:29:56.000000000 +0700
***************
*** 0 ****
--- 1,18 ----
+ // Copyright (C) 2005 Free Software Foundation
+ // Contributed by Kriang Lerdsuwanakij <lerdsuwa@users.sourceforge.net>
+ // { dg-do compile }
+ 
+ // Access checking according to default argument instantiation [temp.inst]/11
+ 
+ template <class T> class C;
+ template <class T> void f(int = C<T>::i) {} // { dg-error "context" }
+ 
+ template <class T> class C {
+   static const int i = 0;	// { dg-error "private" }
+   friend void g();
+ };
+ 
+ void g()
+ {
+   f<char>();			// { dg-error "instantiated" }
+ }

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