C++ PATCH for template parameter shadowing and overloading

Mark Mitchell mark@markmitchell.com
Wed Dec 16 15:52:00 GMT 1998


This patch fixes two bugs.  On code like:

  // Build don't link:
  
  template <class T>
  struct S {
    typedef T X;
  
    class C {
      typedef T X;
    };
  };
  
  template <int I>
  struct S2 {
    enum { A = I };
  
    void f() {
      int A;
    }
  };

we issued spurious errors about shadowing template parameters.  Quite
bogus ineed.  And, on:

  int i = 1;
  
  void func(void (*f)(void *))
  {
    (*f)(0);
  }
  
  class foobar {
    void callback();
    static void callback(void *);
  public:
    foobar();
  };
  
  void foobar::callback(void*)
  {
    i = 0;
  }
  
  foobar::foobar()
  {
    func(callback);
  }
   
  int main()
  {
    foobar fb;
  
    return i;
  }

we failed to take the address of `callback' before passing it to
`func', resulting in bogus code generation and/or compiler aborts.

-- 
Mark Mitchell 			mark@markmitchell.com
Mark Mitchell Consulting	http://www.markmitchell.com

1998-12-16  Mark Mitchell  <mark@markmitchell.com>

	* class.c (resolve_address_of_overloaded_function): Do conversion
	to correct type here, rather than ...
	(instantiate_type): Here.

	* cp-tree.h (DECL_TEMPLATE_PARM_P): New macro.
	(DECL_TEMPLATE_TEMPLATE_PARM_P): Use it.
	(decl_template_parm_p): Remove.
	* decl.c (pushdecl): Don't set DECL_CONTEXT for a template
	paramter. 
	* lex.c (do_identifier): Use DECL_TEMPLATE_PARM_P.
	(push_inline_template_parms_recursive): Set it.
	(decl_template_parm_p): Remove.
	(check_template_shadow): Use DECL_TEMPLATE_PARM_P.
	(process_template_parm): Set it.
	
Index: cp/class.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/class.c,v
retrieving revision 1.122
diff -c -p -r1.122 class.c
*** class.c	1998/12/14 15:35:28	1.122
--- class.c	1998/12/16 21:25:43
*************** resolve_address_of_overloaded_function (
*** 5025,5030 ****
--- 5025,5031 ----
       are the TREE_PURPOSE, not the TREE_VALUE, in this list, for easy
       interoperability with most_specialized_instantiation.  */
    tree matches = NULL_TREE;
+   tree fn;
  
    /* By the time we get here, we should be seeing only real
       pointer-to-member types, not the internal POINTER_TYPE to
*************** resolve_address_of_overloaded_function (
*** 5212,5219 ****
        return error_mark_node;
      }
  
!   /* Good, exactly one match.  */
!   return TREE_PURPOSE (matches);
  }
  
  /* This function will instantiate the type of the expression given in
--- 5213,5232 ----
        return error_mark_node;
      }
  
!   /* Good, exactly one match.  Now, convert it to the correct type.  */
!   fn = TREE_PURPOSE (matches);
! 
!   if (TYPE_PTRFN_P (target_type) || TYPE_PTRMEMFUNC_P (target_type))
!     return build_unary_op (ADDR_EXPR, fn, 0);
!   else
!     {
!       /* The target must be a REFERENCE_TYPE.  Above, build_unary_op
! 	 will mark the function as addressed, but here we must do it
! 	 explicitly.  */
!       mark_addressable (fn);
! 
!       return fn;
!     }
  }
  
  /* This function will instantiate the type of the expression given in
*************** instantiate_type (lhstype, rhs, complain
*** 5291,5323 ****
      case COMPONENT_REF:
        {
  	tree field = TREE_OPERAND (rhs, 1);
! 	if (TREE_CODE (field) == TREE_LIST)
! 	  {
! 	    tree function = instantiate_type (lhstype, field, complain);
! 	    if (function == error_mark_node)
! 	      return error_mark_node;
! 	    my_friendly_assert (TREE_CODE (function) == FUNCTION_DECL, 185);
  
! 	    if (! DECL_STATIC_FUNCTION_P (function))
  	      {
! 		tree t = TREE_TYPE (TREE_OPERAND (rhs, 0));
! 		if (TYPE_MAIN_VARIANT (t) == current_class_type)
! 		  t = constructor_name (t);
! 
! 		cp_error ("object-dependent reference to `%D' can only be used in a call",
! 			  function);
! 		cp_error ("  to form a pointer to member function, say `&%T::%D'",
! 			  t, DECL_NAME (function));
! 		return error_mark_node;
  	      }
! 
! 	    mark_used (function);
! 	    return function;
  	  }
! 
! 	/* I could not trigger this code. MvL */
! 	my_friendly_abort (980326);
! 	return rhs;
        }
  
      case OFFSET_REF:
--- 5304,5334 ----
      case COMPONENT_REF:
        {
  	tree field = TREE_OPERAND (rhs, 1);
! 	tree r;
  
! 	my_friendly_assert (TREE_CODE (field) == TREE_LIST, 0);
! 
! 	r = instantiate_type (lhstype, field, complain);
! 
! 	if (r != error_mark_node && TYPE_PTRMEMFUNC_P (lhstype))
! 	  {
! 	    tree t = TYPE_PTRMEMFUNC_OBJECT_TYPE (lhstype);
! 	    tree fn = TREE_VALUE (field);
! 	    if (TREE_CODE (fn) == OVERLOAD)
! 	      fn = OVL_FUNCTION (fn);
! 	    if (TREE_CODE (fn) == FUNCTION_DECL)
  	      {
! 		cp_error ("object-dependent reference `%E' can only be used in a call",
! 			  DECL_NAME (fn));
! 		cp_error ("  to form a pointer to member function, say `&%T::%E'",
! 			  t, DECL_NAME (fn));
  	      }
! 	    else
! 	      cp_error ("object-dependent reference can only be used in a call");
! 	    return error_mark_node;
  	  }
! 	
! 	return r;
        }
  
      case OFFSET_REF:
*************** instantiate_type (lhstype, rhs, complain
*** 5469,5495 ****
        return rhs;
        
      case ADDR_EXPR:
!       {
! 	tree fn = instantiate_type (lhstype, TREE_OPERAND (rhs, 0), complain);
! 	if (fn == error_mark_node)
! 	  return error_mark_node;
! 	mark_addressable (fn);
! 	TREE_OPERAND (rhs, 0) = fn;
! 	TREE_CONSTANT (rhs) = staticp (fn);
! 	if (TYPE_PTRMEMFUNC_P (lhstype))
! 	  {
! 	    /* We must use the POINTER_TYPE to METHOD_TYPE on RHS here
! 	       so that build_ptrmemfunc knows that RHS we have is not
! 	       already a pointer-to-member constant.  Instead, it is
! 	       just a ADDR_EXPR over a FUNCTION_DECL.  */
! 	    TREE_TYPE (rhs) = TYPE_PTRMEMFUNC_FN_TYPE (lhstype);
! 	    rhs = build_ptrmemfunc (TREE_TYPE (rhs), rhs, 0);
! 	  }
! 	else
! 	  /* Here, things our simple; we have exactly what we need.  */
! 	  TREE_TYPE (rhs) = lhstype;
!       }
!       return rhs;
  
      case ENTRY_VALUE_EXPR:
        my_friendly_abort (184);
--- 5480,5486 ----
        return rhs;
        
      case ADDR_EXPR:
!       return instantiate_type (lhstype, TREE_OPERAND (rhs, 0), complain);
  
      case ENTRY_VALUE_EXPR:
        my_friendly_abort (184);
Index: cp/cp-tree.h
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/cp-tree.h,v
retrieving revision 1.180
diff -c -p -r1.180 cp-tree.h
*** cp-tree.h	1998/12/13 14:45:49	1.180
--- cp-tree.h	1998/12/16 21:25:46
*************** Boston, MA 02111-1307, USA.  */
*** 65,70 ****
--- 65,71 ----
  
     Usage of DECL_LANG_FLAG_?:
     0: DECL_ERROR_REPORTED (in VAR_DECL).
+       DECL_TEMPLATE_PARM_P (in CONST_DECL, TYPE_DECL, or TEMPLATE_DECL)
     1: C_TYPEDEF_EXPLICITLY_SIGNED (in TYPE_DECL).
        DECL_TEMPLATE_INSTANTIATED (in a VAR_DECL or a FUNCTION_DECL)
     2: DECL_THIS_EXTERN (in VAR_DECL or FUNCTION_DECL).
*************** extern int flag_new_for_scope;
*** 1832,1842 ****
  #define DECL_TEMPLATE_SPECIALIZATIONS(NODE)     DECL_SIZE(NODE)
  #define DECL_TEMPLATE_INJECT(NODE)	DECL_INITIAL(NODE)
  
! /* Nonzero for TEMPLATE_DECL nodes that represents template template
!    parameters */
  #define DECL_TEMPLATE_TEMPLATE_PARM_P(NODE) \
!   (TREE_CODE (NODE) == TEMPLATE_DECL && TREE_TYPE (NODE) \
!    && TREE_CODE (TREE_TYPE (NODE)) == TEMPLATE_TEMPLATE_PARM)
  
  #define DECL_FUNCTION_TEMPLATE_P(NODE)  \
    (TREE_CODE (NODE) == TEMPLATE_DECL \
--- 1833,1844 ----
  #define DECL_TEMPLATE_SPECIALIZATIONS(NODE)     DECL_SIZE(NODE)
  #define DECL_TEMPLATE_INJECT(NODE)	DECL_INITIAL(NODE)
  
! /* Nonzero for a DECL which is actually a template parameter.  */
! #define DECL_TEMPLATE_PARM_P(NODE) \
!   DECL_LANG_FLAG_0 (NODE)
! 
  #define DECL_TEMPLATE_TEMPLATE_PARM_P(NODE) \
!   (TREE_CODE (NODE) == TEMPLATE_DECL && DECL_TEMPLATE_PARM_P (NODE))
  
  #define DECL_FUNCTION_TEMPLATE_P(NODE)  \
    (TREE_CODE (NODE) == TEMPLATE_DECL \
*************** extern void do_pushlevel			PROTO((void))
*** 3070,3076 ****
  extern int is_member_template                   PROTO((tree));
  extern int template_parms_equal                 PROTO((tree, tree));
  extern int comp_template_parms                  PROTO((tree, tree));
- extern int decl_template_parm_p			PROTO((tree));
  extern int template_class_depth                 PROTO((tree));
  extern int is_specialization_of                 PROTO((tree, tree));
  extern int comp_template_args                   PROTO((tree, tree));
--- 3072,3077 ----
Index: cp/decl.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/decl.c,v
retrieving revision 1.286
diff -c -p -r1.286 decl.c
*** decl.c	1998/12/15 13:59:52	1.286
--- decl.c	1998/12/16 21:25:55
*************** pushdecl (x)
*** 3514,3528 ****
    register tree name = DECL_ASSEMBLER_NAME (x);
    int need_new_binding = 1;
  
!   if (current_function_decl && x != current_function_decl
!       /* A local declaration for a function doesn't constitute nesting.  */
!       && (TREE_CODE (x) != FUNCTION_DECL || DECL_INITIAL (x))
!       /* Don't change DECL_CONTEXT of virtual methods.  */
!       && (TREE_CODE (x) != FUNCTION_DECL || !DECL_VIRTUAL_P (x))
!       && !DECL_CONTEXT (x))
!     DECL_CONTEXT (x) = current_function_decl;
!   if (!DECL_CONTEXT (x))
!     DECL_CONTEXT (x) = FROB_CONTEXT (current_namespace);
  
    /* Type are looked up using the DECL_NAME, as that is what the rest of the
       compiler wants to use.  */
--- 3514,3536 ----
    register tree name = DECL_ASSEMBLER_NAME (x);
    int need_new_binding = 1;
  
!   if (DECL_TEMPLATE_PARM_P (x))
!     /* Template parameters have no context; they are not X::T even
!        when declared within a class or namespace.  */
!     ;
!   else
!     {
!       if (current_function_decl && x != current_function_decl
! 	  /* A local declaration for a function doesn't constitute
!              nesting.  */
! 	  && (TREE_CODE (x) != FUNCTION_DECL || DECL_INITIAL (x))
! 	  /* Don't change DECL_CONTEXT of virtual methods.  */
! 	  && (TREE_CODE (x) != FUNCTION_DECL || !DECL_VIRTUAL_P (x))
! 	  && !DECL_CONTEXT (x))
! 	DECL_CONTEXT (x) = current_function_decl;
!       if (!DECL_CONTEXT (x))
! 	DECL_CONTEXT (x) = FROB_CONTEXT (current_namespace);
!     }
  
    /* Type are looked up using the DECL_NAME, as that is what the rest of the
       compiler wants to use.  */
Index: cp/lex.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/lex.c,v
retrieving revision 1.94
diff -c -p -r1.94 lex.c
*** lex.c	1998/12/13 14:45:57	1.94
--- lex.c	1998/12/16 21:25:58
*************** do_identifier (token, parsing, args)
*** 3051,3066 ****
  	    cp_error ("enum `%D' is private", id);
  	  /* protected is OK, since it's an enum of `this'.  */
  	}
!       if (!processing_template_decl
! 	  /* Really, if we're processing a template, we just want to
! 	     resolve template parameters, and not enumeration
! 	     constants.  But, they're hard to tell apart.  (Note that
! 	     a non-type template parameter may have enumeration type.)
! 	     Fortunately, there's no harm in resolving *global*
! 	     enumeration constants, since they can't depend on
! 	     template parameters.  */
! 	  || (TREE_CODE (CP_DECL_CONTEXT (id)) == NAMESPACE_DECL
! 	      && TREE_CODE (DECL_INITIAL (id)) == TEMPLATE_PARM_INDEX))
  	id = DECL_INITIAL (id);
      }
    else
--- 3051,3057 ----
  	    cp_error ("enum `%D' is private", id);
  	  /* protected is OK, since it's an enum of `this'.  */
  	}
!       if (!processing_template_decl || DECL_TEMPLATE_PARM_P (id))
  	id = DECL_INITIAL (id);
      }
    else
Index: cp/pt.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/pt.c,v
retrieving revision 1.246
diff -c -p -r1.246 pt.c
*** pt.c	1998/12/14 15:35:35	1.246
--- pt.c	1998/12/16 21:26:08
*************** push_inline_template_parms_recursive (pa
*** 357,366 ****
  
  	case PARM_DECL:
  	  {
! 	    /* Make a CONST_DECL as is done in process_template_parm. */
  	    tree decl = build_decl (CONST_DECL, DECL_NAME (parm),
  				    TREE_TYPE (parm));
  	    DECL_INITIAL (decl) = DECL_INITIAL (parm);
  	    pushdecl (decl);
  	  }
  	  break;
--- 357,371 ----
  
  	case PARM_DECL:
  	  {
! 	    /* Make a CONST_DECL as is done in process_template_parm.
! 	       It is ugly that we recreate this here; the original
! 	       version built in process_template_parm is no longer
! 	       available.  */
  	    tree decl = build_decl (CONST_DECL, DECL_NAME (parm),
  				    TREE_TYPE (parm));
+ 	    SET_DECL_ARTIFICIAL (decl);
  	    DECL_INITIAL (decl) = DECL_INITIAL (parm);
+ 	    DECL_TEMPLATE_PARM_P (decl) = 1;
  	    pushdecl (decl);
  	  }
  	  break;
*************** int comp_template_parms (parms1, parms2)
*** 1467,1499 ****
    return 1;
  }
  
- 
- /* Returns 1 iff DECL is a template parameter.  */
- 
- int decl_template_parm_p (decl)
-      tree decl;
- {
-   /* For template template parms. */
-   if (TREE_CODE (decl) == TEMPLATE_DECL
-       && TREE_TYPE (decl)
-       && TREE_CODE (TREE_TYPE (decl)) == TEMPLATE_TEMPLATE_PARM)
-     return 1;
- 
-   /* For template type parms. */
-   if (TREE_CODE (decl) == TYPE_DECL
-       && TREE_TYPE (decl)
-       && TREE_CODE (TREE_TYPE (decl)) == TEMPLATE_TYPE_PARM)
-     return 1;
- 
-   /* For template non-type parms. */
-   if (TREE_CODE (decl) == CONST_DECL
-       && DECL_INITIAL (decl) 
-       && TREE_CODE (DECL_INITIAL (decl)) == TEMPLATE_PARM_INDEX)
-     return 1;
- 
-   return 0;
- }
- 
  /* Complain if DECL shadows a template parameter.
  
     [temp.local]: A template-parameter shall not be redeclared within its
--- 1472,1477 ----
*************** check_template_shadow (decl)
*** 1510,1516 ****
        /* We check for decl != olddecl to avoid bogus errors for using a
  	 name inside a class.  We check TPFI to avoid duplicate errors for
  	 inline member templates.  */
!       if (decl != olddecl && decl_template_parm_p (olddecl)
  	  && ! TEMPLATE_PARMS_FOR_INLINE (current_template_parms))
  	{
  	  cp_error_at ("declaration of `%#D'", decl);
--- 1488,1494 ----
        /* We check for decl != olddecl to avoid bogus errors for using a
  	 name inside a class.  We check TPFI to avoid duplicate errors for
  	 inline member templates.  */
!       if (decl != olddecl && DECL_TEMPLATE_PARM_P (olddecl)
  	  && ! TEMPLATE_PARMS_FOR_INLINE (current_template_parms))
  	{
  	  cp_error_at ("declaration of `%#D'", decl);
*************** process_template_parm (list, next)
*** 1671,1676 ****
--- 1649,1655 ----
  				     decl, TREE_TYPE (parm));
      }
    SET_DECL_ARTIFICIAL (decl);
+   DECL_TEMPLATE_PARM_P (decl) = 1;
    pushdecl (decl);
    parm = build_tree_list (defval, parm);
    return chainon (list, parm);
Index: testsuite/g++.old-deja/g++.pt/shadow1.C
===================================================================
RCS file: shadow1.C
diff -N shadow1.C
*** /dev/null	Sat Dec  5 20:30:03 1998
--- shadow1.C	Wed Dec 16 14:33:49 1998
***************
*** 0 ****
--- 1,19 ----
+ // Build don't link:
+ 
+ template <class T>
+ struct S {
+   typedef T X;
+ 
+   class C {
+     typedef T X;
+   };
+ };
+ 
+ template <int I>
+ struct S2 {
+   enum { A = I };
+ 
+   void f() {
+     int A;
+   }
+ };
Index: testsuite/g++.old-deja/g++.other/overload10.C
===================================================================
RCS file: overload10.C
diff -N overload10.C
*** /dev/null	Sat Dec  5 20:30:03 1998
--- overload10.C	Wed Dec 16 14:34:23 1998
***************
*** 0 ****
--- 1,30 ----
+ int i = 1;
+ 
+ void func(void (*f)(void *))
+ {
+   (*f)(0);
+ }
+ 
+ class foobar {
+   void callback();
+   static void callback(void *);
+ public:
+   foobar();
+ };
+ 
+ void foobar::callback(void*)
+ {
+   i = 0;
+ }
+ 
+ foobar::foobar()
+ {
+   func(callback);
+ }
+  
+ int main()
+ {
+   foobar fb;
+ 
+   return i;
+ }



More information about the Gcc-patches mailing list