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] Fix PR9453


Hi

The following patch fix the regression PR9453 about access checking
during function template instantiation.  During instantiation, we
tsubst return type and parameter type which require access checking.  
However, we only have the TEMPLATE_DECL at this stage while its 
FUNCTION_DECL has not been built yet.  I decide to use my recent
defer access work here, deferring checks until we have the FUNCTION_DECL
and its specialization information has been record.  This patch
requires one of my earlier patch:

  http://gcc.gnu.org/ml/gcc-patches/2003-01/msg01293.html

Bootstrapped and tested on i686-pc-linux-gnu.  OK for the main trunk?

--Kriang

2003-01-28  Kriang Lerdsuwanakij  <lerdsuwa@users.sourceforge.net>

	PR c++/9453
	* pt.c (saved_access_scope): Remove.
	(push_access_scope_real): Remove ARG parameter.  Use
	push_deferring_access_checks.  All caller adjusted.
	(pop_access_scope): Use pop_deferring_access_checks.
	(instantiate_template): Call pop_access_scope after specialization
	is recorded.
	(regenerated_decl_from_template): Likewise.
	
2003-01-28  Kriang Lerdsuwanakij  <lerdsuwa@users.sourceforge.net>

	PR c++/9453
	* g++.dg/template/friend15.C: New test.


diff -cprN gcc-main-save/gcc/cp/pt.c gcc-main-new/gcc/cp/pt.c
*** gcc-main-save/gcc/cp/pt.c	Tue Jan 28 22:25:47 2003
--- gcc-main-new/gcc/cp/pt.c	Tue Jan 28 22:44:33 2003
*************** static size_t inline_parm_levels_used;
*** 66,73 ****
  
  static GTY(()) tree current_tinst_level;
  
- static GTY(()) tree saved_access_scope;
- 
  /* A map from local variable declarations in the body of the template
     presently being instantiated to the corresponding instantiated
     local variables.  */
--- 66,71 ----
*************** static htab_t local_specializations;
*** 89,95 ****
  #define GTB_IGNORE_TYPE 2 /* We don't need to try to unify the current
  			     type with the desired type.  */
  
! static void push_access_scope_real PARAMS ((tree, tree, tree));
  static void push_access_scope PARAMS ((tree));
  static void pop_access_scope PARAMS ((tree));
  static int resolve_overloaded_unification PARAMS ((tree, tree, tree, tree,
--- 87,93 ----
  #define GTB_IGNORE_TYPE 2 /* We don't need to try to unify the current
  			     type with the desired type.  */
  
! static void push_access_scope_real PARAMS ((tree, tree));
  static void push_access_scope PARAMS ((tree));
  static void pop_access_scope PARAMS ((tree));
  static int resolve_overloaded_unification PARAMS ((tree, tree, tree, tree,
*************** static bool dependent_template_id_p (tre
*** 177,217 ****
  /* Make the current scope suitable for access checking when we are
     processing T.  T can be FUNCTION_DECL for instantiated function
     template, TEMPLATE_DECL for uninstantiated one, or VAR_DECL for
!    static member variable (need by instantiate_decl).  ARGS is the 
!    template argument for TEMPLATE_DECL.  If CONTEXT is not NULL_TREE, 
!    this is used instead of the context of T.  */
  
  void
! push_access_scope_real (t, args, context)
!   tree t, args, context;
  {
-   if (TREE_CODE (t) == FUNCTION_DECL || DECL_FUNCTION_TEMPLATE_P (t))
-     {
-       /* When we are processing specialization `foo<Outer>' for code like
- 
- 	   template <class U> typename U::Inner foo ();
- 	   class Outer {
- 	     struct Inner {};
- 	     friend Outer::Inner foo<Outer> ();
- 	   };
- 
- 	 `T' is a TEMPLATE_DECL, but `Outer' is only a friend of one of
- 	 its specialization.  We can get the FUNCTION_DECL with the right
- 	 information because this specialization has already been
- 	 registered by the friend declaration above.  */
- 
-       if (DECL_FUNCTION_TEMPLATE_P (t) && args)
- 	{
- 	  tree full_args = tsubst_template_arg_vector
- 	    (DECL_TI_ARGS (DECL_TEMPLATE_RESULT (t)), args, tf_none);
- 	  tree spec = NULL_TREE;
- 	  if (full_args != error_mark_node)
- 	    spec = retrieve_specialization (t, full_args);
- 	  if (spec)
- 	    t = spec;
- 	}
-     }
- 
    if (!context)
      context = DECL_CONTEXT (t);
    if (context && TYPE_P (context))
--- 175,187 ----
  /* Make the current scope suitable for access checking when we are
     processing T.  T can be FUNCTION_DECL for instantiated function
     template, TEMPLATE_DECL for uninstantiated one, or VAR_DECL for
!    static member variable (need by instantiate_decl).  If CONTEXT is
!    not NULL_TREE, this is used instead of the context of T.  */
  
  void
! push_access_scope_real (t, context)
!   tree t, context;
  {
    if (!context)
      context = DECL_CONTEXT (t);
    if (context && TYPE_P (context))
*************** push_access_scope_real (t, args, context
*** 220,230 ****
      push_to_top_level ();
      
    if (TREE_CODE (t) == FUNCTION_DECL || DECL_FUNCTION_TEMPLATE_P (t))
!     {
!       saved_access_scope = tree_cons
! 	(NULL_TREE, current_function_decl, saved_access_scope);
!       current_function_decl = t;
!     }
  }
  
  /* Like push_access_scope_real, but always uses DECL_CONTEXT.  */
--- 190,196 ----
      push_to_top_level ();
      
    if (TREE_CODE (t) == FUNCTION_DECL || DECL_FUNCTION_TEMPLATE_P (t))
!     push_deferring_access_checks (true);
  }
  
  /* Like push_access_scope_real, but always uses DECL_CONTEXT.  */
*************** void
*** 233,252 ****
  push_access_scope (t)
    tree t;
  {
!   push_access_scope_real (t, NULL_TREE, NULL_TREE);
  }
  
  /* Restore the scope set up by push_access_scope.  T is the node we
!    are processing.  */
  
  void
  pop_access_scope (t)
    tree t;
  {
!   if (TREE_CODE (t) == FUNCTION_DECL || DECL_FUNCTION_TEMPLATE_P (t))
      {
!       current_function_decl = TREE_VALUE (saved_access_scope);
!       saved_access_scope = TREE_CHAIN (saved_access_scope);
      }
  
    if (DECL_CLASS_SCOPE_P (t))
--- 199,223 ----
  push_access_scope (t)
    tree t;
  {
!   push_access_scope_real (t, NULL_TREE);
  }
  
  /* Restore the scope set up by push_access_scope.  T is the node we
!    are processing.  Unlike push_access_scope_real, T must not be a
!    TEMPLATE_DECL.  */
  
  void
  pop_access_scope (t)
    tree t;
  {
!   my_friendly_assert (!DECL_FUNCTION_TEMPLATE_P (t), 0);
!   if (TREE_CODE (t) == FUNCTION_DECL)
      {
!       tree saved = current_function_decl;
!       current_function_decl = t;
!       perform_deferred_access_checks ();
!       current_function_decl = saved;
!       pop_deferring_access_checks ();
      }
  
    if (DECL_CLASS_SCOPE_P (t))
*************** instantiate_template (tmpl, targ_ptr)
*** 8413,8431 ****
       correctly.  The desired FUNCTION_DECL for FNDECL may or may not be
       created earlier.  Let push_access_scope_real figure that out.  */
    push_access_scope_real
!     (gen_tmpl, targ_ptr, tsubst (DECL_CONTEXT (gen_tmpl), targ_ptr, 
! 				 tf_error, gen_tmpl));
  
    /* substitute template parameters */
    fndecl = tsubst (DECL_TEMPLATE_RESULT (gen_tmpl),
  		   targ_ptr, tf_error, gen_tmpl);
  
-   pop_access_scope (gen_tmpl);
- 
    /* The DECL_TI_TEMPLATE should always be the immediate parent
       template, not the most general template.  */
    DECL_TI_TEMPLATE (fndecl) = tmpl;
  
    if (flag_external_templates)
      add_pending_template (fndecl);
  
--- 8384,8402 ----
       correctly.  The desired FUNCTION_DECL for FNDECL may or may not be
       created earlier.  Let push_access_scope_real figure that out.  */
    push_access_scope_real
!     (gen_tmpl, tsubst (DECL_CONTEXT (gen_tmpl), targ_ptr, 
! 		       tf_error, gen_tmpl));
  
    /* substitute template parameters */
    fndecl = tsubst (DECL_TEMPLATE_RESULT (gen_tmpl),
  		   targ_ptr, tf_error, gen_tmpl);
  
    /* The DECL_TI_TEMPLATE should always be the immediate parent
       template, not the most general template.  */
    DECL_TI_TEMPLATE (fndecl) = tmpl;
  
+   pop_access_scope (fndecl);
+ 
    if (flag_external_templates)
      add_pending_template (fndecl);
  
*************** regenerate_decl_from_template (decl, tmp
*** 10514,10520 ****
       instantiation of a specialization, which it isn't: it's a full
       instantiation.  */
    gen_tmpl = most_general_template (tmpl);
!   push_access_scope_real (gen_tmpl, args, DECL_CONTEXT (decl));
    unregistered = unregister_specialization (decl, gen_tmpl);
  
    /* If the DECL was not unregistered then something peculiar is
--- 10485,10491 ----
       instantiation of a specialization, which it isn't: it's a full
       instantiation.  */
    gen_tmpl = most_general_template (tmpl);
!   push_access_scope_real (gen_tmpl, DECL_CONTEXT (decl));
    unregistered = unregister_specialization (decl, gen_tmpl);
  
    /* If the DECL was not unregistered then something peculiar is
*************** regenerate_decl_from_template (decl, tmp
*** 10542,10549 ****
        DECL_INITIAL (decl) = NULL_TREE;
      }
  
-   pop_access_scope (decl);
- 
    /* The immediate parent of the new template is still whatever it was
       before, even though tsubst sets DECL_TI_TEMPLATE up as the most
       general template.  We also reset the DECL_ASSEMBLER_NAME since
--- 10513,10518 ----
*************** regenerate_decl_from_template (decl, tmp
*** 10561,10566 ****
--- 10530,10537 ----
  
    /* Now, re-register the specialization.  */
    register_specialization (decl, gen_tmpl, args);
+ 
+   pop_access_scope (decl);
  }
  
  /* Return the TEMPLATE_DECL into which DECL_TI_ARGS(DECL) should be
diff -cprN gcc-main-save/gcc/testsuite/g++.dg/template/friend15.C gcc-main-new/gcc/testsuite/g++.dg/template/friend15.C
*** gcc-main-save/gcc/testsuite/g++.dg/template/friend15.C	Thu Jan  1 07:00:00 1970
--- gcc-main-new/gcc/testsuite/g++.dg/template/friend15.C	Tue Jan 28 22:50:32 2003
***************
*** 0 ****
--- 1,19 ----
+ // { dg-do compile }
+ 
+ // Origin: Wolfgang Bangerth <bangerth@ticam.utexas.edu>
+ 
+ // PR c++/9453
+ // Access checking when template friend is defined in class.
+ 
+ template <typename> class X {
+   private:
+     struct Inner;
+ 
+     template <typename R>
+     friend typename X<R>::Inner * foo () { return 0; }
+ };
+ template class X<void>;
+ 
+ struct U {
+     void bar () { foo<void> (); }
+ };


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