[C++ PATCH, committed] Fix PR9030 (main trunk version)

Kriang Lerdsuwanakij lerdsuwa@users.sourceforge.net
Wed Jan 8 14:54:00 GMT 2003


Hi

This is the version of PR9030 bug fix that I have committed to the 
main trunk.  The approved version doesn't apply cleanly due to
some surrounding code changes after new parser merge.  Here are the
changes I made in this version:

- Use push_nested_class instead of pushclass.
- The push_access_scope call in regenerate_decl_from_template 
  use the wrong context.  The correct context should be the already
  tsubst'ed one.
- The ARG argument of push_access_scope is no longer used and removed.

Tested on i686-pc-linux-gnu with no regressions.

--Kriang


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

	PR c++/9030
	* decl.c (make_typename_type): Check access only when tf_error.
	(make_unbound_class_template): Likewise.
	* pt.c (saved_access_scope): New variable.
	(push_access_scope_real): New function.
	(push_access_scope): Likewise.
	(pop_access_scope): Likewise.
	(tsubst_default_argument): Use them.
	(instantiate_template): Likewise.
	(regenerate_decl_from_template): Likewise.
	(instantiate_decl): Likewise.
	(get_mostly_instantiated_function_type): Likewise.

2002-01-07  Kriang Lerdsuwanakij  <lerdsuwa@users.sourceforge.net>

	PR c++/9030
	* g++.dg/template/friend12.C: New test.
	* g++.dg/template/friend13.C: Likewise.
	* g++.old-deja/g++.eh/spec6.C: Add missing error message.
	* g++.old-deja/g++.other/defarg1.C: Change expected error message.

diff -cprN gcc-main-save/gcc/cp/decl.c gcc-main-new/gcc/cp/decl.c
*** gcc-main-save/gcc/cp/decl.c	Tue Jan  7 21:21:51 2003
--- gcc-main-new/gcc/cp/decl.c	Tue Jan  7 21:18:56 2003
*************** make_typename_type (context, name, compl
*** 5671,5680 ****
  	      return error_mark_node;
  	    }
  
! 	  if (complain & tf_parsing)
! 	    type_access_control (context, tmpl);
! 	  else
! 	    enforce_access (context, tmpl);
  
  	  return lookup_template_class (tmpl,
  					TREE_OPERAND (fullname, 1),
--- 5671,5683 ----
  	      return error_mark_node;
  	    }
  
! 	  if (complain & tf_error)
! 	    {
! 	      if (complain & tf_parsing)
! 		type_access_control (context, tmpl);
! 	      else
! 		enforce_access (context, tmpl);
! 	    }
  
  	  return lookup_template_class (tmpl,
  					TREE_OPERAND (fullname, 1),
*************** make_typename_type (context, name, compl
*** 5703,5712 ****
  		  return error_mark_node;
  		}
  
! 	      if (complain & tf_parsing)
! 		type_access_control (context, t);
! 	      else
! 		enforce_access (context, t);
  
  	      if (DECL_ARTIFICIAL (t) || !(complain & tf_keep_type_decl))
  		t = TREE_TYPE (t);
--- 5706,5718 ----
  		  return error_mark_node;
  		}
  
! 	      if (complain & tf_error)
! 		{
! 	      	  if (complain & tf_parsing)
! 		    type_access_control (context, t);
! 		  else
! 		    enforce_access (context, t);
! 		}
  
  	      if (DECL_ARTIFICIAL (t) || !(complain & tf_keep_type_decl))
  		t = TREE_TYPE (t);
*************** make_unbound_class_template (context, na
*** 5774,5783 ****
  	  return error_mark_node;
  	}
        
!       if (complain & tf_parsing)
! 	type_access_control (context, tmpl);
!       else
! 	enforce_access (context, tmpl);
  
        return tmpl;
      }
--- 5780,5792 ----
  	  return error_mark_node;
  	}
        
!       if (complain & tf_error)
! 	{
! 	  if (complain & tf_parsing)
! 	    type_access_control (context, tmpl);
! 	  else
! 	    enforce_access (context, tmpl);
! 	}
  
        return tmpl;
      }
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  7 21:22:15 2003
--- gcc-main-new/gcc/cp/pt.c	Wed Jan  8 20:48:17 2003
*************** static size_t inline_parm_levels_used;
*** 67,72 ****
--- 67,74 ----
  
  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.  */
*************** static htab_t local_specializations;
*** 88,93 ****
--- 90,98 ----
  #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,
  						   unification_kind_t, int));
  static int try_one_overload PARAMS ((tree, tree, tree, tree, tree,
*************** static int invalid_nontype_parm_type_p P
*** 168,173 ****
--- 173,252 ----
  static int eq_local_specializations (const void *, const void *);
  static tree template_for_substitution (tree);
  
+ /* 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;
+ 	}
+ 
+       saved_access_scope = tree_cons
+ 	(NULL_TREE, current_function_decl, saved_access_scope);
+       current_function_decl = t;
+     }
+ 
+   if (!context)
+     context = DECL_CONTEXT (t);
+   if (context && TYPE_P (context))
+     push_nested_class (context, 2);
+ }
+ 
+ /* Like push_access_scope_real, but always uses DECL_CONTEXT.  */
+ 
+ void
+ 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 (DECL_CLASS_SCOPE_P (t))
+     pop_nested_class ();
+ 
+   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);
+     }
+ }
+ 
  /* Do any processing required when DECL (a member template
     declaration) is finished.  Returns the TEMPLATE_DECL corresponding
     to DECL, unless it is a specialization, in which case the DECL
*************** tsubst_default_argument (fn, type, arg)
*** 5733,5746 ****
       ??? current_class_type affects a lot more than name lookup.  This is
       very fragile.  Fortunately, it will go away when we do 2-phase name
       binding properly.  */
!   if (DECL_CLASS_SCOPE_P (fn))
!     pushclass (DECL_CONTEXT (fn), 2);
  
    arg = tsubst_expr (arg, DECL_TI_ARGS (fn),
  		     tf_error | tf_warning, NULL_TREE);
    
!   if (DECL_CLASS_SCOPE_P (fn))
!     popclass ();
  
    /* Make sure the default argument is reasonable.  */
    arg = check_default_argument (type, arg);
--- 5812,5825 ----
       ??? current_class_type affects a lot more than name lookup.  This is
       very fragile.  Fortunately, it will go away when we do 2-phase name
       binding properly.  */
! 
!   /* FN is already the desired FUNCTION_DECL.  */
!   push_access_scope (fn);
  
    arg = tsubst_expr (arg, DECL_TI_ARGS (fn),
  		     tf_error | tf_warning, NULL_TREE);
    
!   pop_access_scope (fn);
  
    /* Make sure the default argument is reasonable.  */
    arg = check_default_argument (type, arg);
*************** instantiate_template (tmpl, targ_ptr)
*** 7873,7889 ****
      }
  
    /* Make sure that we can see identifiers, and compute access
!      correctly.  */
!   if (DECL_CLASS_SCOPE_P (gen_tmpl))
!     pushclass (tsubst (DECL_CONTEXT (gen_tmpl), targ_ptr, tf_error,
! 		       gen_tmpl), 1);
  
    /* substitute template parameters */
    fndecl = tsubst (DECL_TEMPLATE_RESULT (gen_tmpl),
  		   targ_ptr, tf_error, gen_tmpl);
  
!   if (DECL_CLASS_SCOPE_P (gen_tmpl))
!     popclass ();
  
    /* The DECL_TI_TEMPLATE should always be the immediate parent
       template, not the most general template.  */
--- 7952,7968 ----
      }
  
    /* Make sure that we can see identifiers, and compute access
!      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.  */
*************** fn_type_unification (fn, explicit_targs,
*** 7955,7961 ****
    int result;
  
    my_friendly_assert (TREE_CODE (fn) == TEMPLATE_DECL, 0);
!   
    fntype = TREE_TYPE (fn);
    if (explicit_targs)
      {
--- 8034,8040 ----
    int result;
  
    my_friendly_assert (TREE_CODE (fn) == TEMPLATE_DECL, 0);
! 
    fntype = TREE_TYPE (fn);
    if (explicit_targs)
      {
*************** regenerate_decl_from_template (decl, tmp
*** 9977,9982 ****
--- 10056,10062 ----
       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
*************** regenerate_decl_from_template (decl, tmp
*** 9984,9995 ****
       register_specialization for it.  */
    my_friendly_assert (unregistered, 0);
  
-   if (DECL_CLASS_SCOPE_P (decl))
-     /* Make sure that we can see identifiers, and compute access
-        correctly, for the class members used in the declaration of
-        this static variable or function.  */
-     push_nested_class (DECL_CONTEXT (decl), 2);
- 
    /* Do the substitution to get the new declaration.  */
    new_decl = tsubst (code_pattern, args, tf_error, NULL_TREE);
  
--- 10064,10069 ----
*************** regenerate_decl_from_template (decl, tmp
*** 10010,10018 ****
        DECL_INITIAL (decl) = NULL_TREE;
      }
  
!   /* Pop the class context we pushed above.  */
!   if (DECL_CLASS_SCOPE_P (decl))
!     pop_nested_class ();
  
    /* The immediate parent of the new template is still whatever it was
       before, even though tsubst sets DECL_TI_TEMPLATE up as the most
--- 10084,10090 ----
        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
*************** instantiate_decl (d, defer_ok)
*** 10218,10226 ****
        tree type = TREE_TYPE (gen);
  
        /* Make sure that we can see identifiers, and compute access
! 	 correctly.  */
!       if (DECL_CLASS_SCOPE_P (d))
! 	pushclass (DECL_CONTEXT (d), 1);
  
        if (TREE_CODE (gen) == FUNCTION_DECL)
  	{
--- 10290,10298 ----
        tree type = TREE_TYPE (gen);
  
        /* 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);
  
        if (TREE_CODE (gen) == FUNCTION_DECL)
  	{
*************** instantiate_decl (d, defer_ok)
*** 10235,10242 ****
  	}
        tsubst (type, gen_args, tf_error | tf_warning, d);
  
!       if (DECL_CLASS_SCOPE_P (d))
! 	popclass ();
      }
    
    if (TREE_CODE (d) == VAR_DECL && DECL_INITIALIZED_IN_CLASS_P (d)
--- 10307,10313 ----
  	}
        tsubst (type, gen_args, tf_error | tf_warning, d);
  
!       pop_access_scope (d);
      }
    
    if (TREE_CODE (d) == VAR_DECL && DECL_INITIALIZED_IN_CLASS_P (d)
*************** get_mostly_instantiated_function_type (d
*** 10597,10604 ****
  	 partial substitution here.  It depends only on outer template
  	 parameters, regardless of whether the innermost level is
  	 specialized or not.  */
!       if (DECL_CLASS_SCOPE_P (decl))
! 	pushclass (DECL_CONTEXT (decl), 1);
  
        /* Now, do the (partial) substitution to figure out the
  	 appropriate function type.  */
--- 10668,10674 ----
  	 partial substitution here.  It depends only on outer template
  	 parameters, regardless of whether the innermost level is
  	 specialized or not.  */
!       push_access_scope (decl);
  
        /* Now, do the (partial) substitution to figure out the
  	 appropriate function type.  */
*************** get_mostly_instantiated_function_type (d
*** 10611,10618 ****
        TREE_VEC_LENGTH (partial_args)--;
        tparms = tsubst_template_parms (tparms, partial_args, tf_error);
  
!       if (DECL_CLASS_SCOPE_P (decl))
! 	popclass ();
      }
  
    return fn_type;
--- 10681,10687 ----
        TREE_VEC_LENGTH (partial_args)--;
        tparms = tsubst_template_parms (tparms, partial_args, tf_error);
  
!       pop_access_scope (decl);
      }
  
    return fn_type;
diff -cprN gcc-main-save/gcc/testsuite/g++.dg/template/friend12.C gcc-main-new/gcc/testsuite/g++.dg/template/friend12.C
*** gcc-main-save/gcc/testsuite/g++.dg/template/friend12.C	Thu Jan  1 07:00:00 1970
--- gcc-main-new/gcc/testsuite/g++.dg/template/friend12.C	Tue Jan  7 21:13:00 2003
***************
*** 0 ****
--- 1,24 ----
+ // { dg-do compile }
+ 
+ // Origin: Wolfgang Bangerth <bangerth@ticam.utexas.edu>
+ 
+ // PR 9030.  Perform access checking to parameter and return type of 
+ // function template correctly when the template is friend.
+ 
+ template <class T> class Outer {
+   private:
+     struct Inner {};
+ 
+     template <class T_>
+     friend typename Outer<T_>::Inner foo ();
+ };
+ 
+ template <class T>
+ typename Outer<T>::Inner
+ foo () {
+   return typename Outer<T>::Inner();
+ }
+ 
+ void f() {
+   foo<int>();
+ }
diff -cprN gcc-main-save/gcc/testsuite/g++.dg/template/friend13.C gcc-main-new/gcc/testsuite/g++.dg/template/friend13.C
*** gcc-main-save/gcc/testsuite/g++.dg/template/friend13.C	Thu Jan  1 07:00:00 1970
--- gcc-main-new/gcc/testsuite/g++.dg/template/friend13.C	Tue Jan  7 21:13:00 2003
***************
*** 0 ****
--- 1,21 ----
+ // { dg-do compile }
+ 
+ // Perform access checking to parameter and return type of 
+ // function template correctly when only specialization is friend.
+ 
+ template <class T>
+ typename T::Inner
+ foo () {
+   return typename T::Inner();
+ }
+ 
+ class Outer {
+   private:
+     struct Inner {};
+ 
+     friend Outer::Inner foo<Outer> ();
+ };
+ 
+ void f() {
+   foo<Outer>();
+ }
diff -cprN gcc-main-save/gcc/testsuite/g++.old-deja/g++.eh/spec6.C gcc-main-new/gcc/testsuite/g++.old-deja/g++.eh/spec6.C
*** gcc-main-save/gcc/testsuite/g++.old-deja/g++.eh/spec6.C	Tue Jan  7 21:24:15 2003
--- gcc-main-new/gcc/testsuite/g++.old-deja/g++.eh/spec6.C	Tue Jan  7 21:13:00 2003
*************** template<class T> void fnx(T *) throw(T)
*** 25,31 ****
  void fx()
  {
    fnx((int *)0);
!   fnx((void *)0);
  }
  
  // [except.spec] 2, exception specifiers must be the same set of types (but
--- 25,31 ----
  void fx()
  {
    fnx((int *)0);
!   fnx((void *)0);		// ERROR - instantiated from here
  }
  
  // [except.spec] 2, exception specifiers must be the same set of types (but



More information about the Gcc-patches mailing list