PATCH for member function/template confusion

Mark Mitchell mark@markmitchell.com
Fri Oct 16 11:57:00 GMT 1998


We were (incorrectly) flagging:

  struct B
  {
    void f() {}

    template <class U>
    void f() {}
  };

as erroneous.  But, we (incorrectly) accepting:

  template <class T, class U>
  struct D2
  {
    void f(T);
    void f(U);
  };

  template struct D2<int, int>; 

This patch fixes both of these problems.  It also avoids mangling the
names of template functions since there's no reason to do so, and
since any code that depends on template function mangled names being
good for anything is broken anyhow.

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

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

	* class.c (add_method): Fix documentation to reflect previous
	changes.  Check for duplicate method declarations here.
	* decl.c (decls_match): Handle FUNCTION_DECL vs TEMPLATE_DECL
	correctly; such things never match.
	(grokfndecl): Don't look for duplicate methods here.
	* decl2.c (check_classfn): Don't assume names are mangled.
	Don't add bogus member function declarations to a class before the
	class type is complete.
	(grokfield): Reformat error message.
	* method.c (set_mangled_name_for_decl): Don't mangle names while
	procesing_template_decl.
	
Index: g++.pt/memtemp78.C
===================================================================
RCS file: memtemp78.C
diff -N memtemp78.C
*** /dev/null	Mon Dec 31 20:00:00 1979
--- memtemp78.C	Fri Oct 16 11:49:58 1998
***************
*** 0 ****
--- 1,56 ----
+ // Build don't link:
+ 
+ struct A 
+ {
+   void f() {}
+ 
+   template <class U>
+   void f() {}
+ };
+ 
+ 
+ template <class T>
+ struct B
+ {
+   void f() {}
+ 
+   template <class U>
+   void f() {}
+ };
+ 
+ template struct B<int>;
+ 
+ struct C 
+ {
+   template <class U>
+   void f() {}
+ 
+   template <class U>
+   void f() {}  // ERROR - redeclaration
+ };
+ 
+ 
+ template <class T, class U>
+ struct D
+ {
+   void f(T);
+   void f(U);
+ };
+ 
+ template struct D<int, double>;
+ 
+ template <class T, class U>
+ struct D2
+ {
+   void f(T);
+   void f(U); // ERROR - redeclaration 
+ };
+ 
+ template struct D2<int, int>; 
+ 
+ struct E
+ {
+   void f(); 
+   void f(); // ERROR - redeclaration
+ };
+ 
Index: g++.benjamin/warn02.C
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/testsuite/g++.old-deja/g++.benjamin/warn02.C,v
retrieving revision 1.1
diff -c -p -r1.1 warn02.C
*** warn02.C	1998/04/21 19:45:53	1.1
--- warn02.C	1998/10/16 18:49:53
*************** class C
*** 31,46 ****
  class D
  {
  public:
!   int foo2() {return b;}  // WARNING - 
!   int foo2() {return b;}  // WARNING - 
    int b;
  };
  
  class E
  {
  public:
!   int foo2(); // WARNING - 
!   int foo2(); // WARNING - 
    int b;
  };
  
--- 31,46 ----
  class D
  {
  public:
!   int foo2() {return b;}  
!   int foo2() {return b;}  // ERROR - 
    int b;
  };
  
  class E
  {
  public:
!   int foo2(); 
!   int foo2(); // ERROR - 
    int b;
  };
  
Index: class.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/class.c,v
retrieving revision 1.93
diff -c -p -r1.93 class.c
*** class.c	1998/10/16 03:37:34	1.93
--- class.c	1998/10/16 18:38:22
*************** free_method_vec (vec)
*** 1109,1120 ****
    free_method_vecs = vec;
  }
  
! /* Add method METHOD to class TYPE.  This is used when a method
!    has been defined which did not initially appear in the class definition,
!    and helps cut down on spurious error messages.
  
!    FIELDS is the entry in the METHOD_VEC vector entry of the class type where
!    the method should be added.  */
  
  void
  add_method (type, fields, method)
--- 1109,1118 ----
    free_method_vecs = vec;
  }
  
! /* Add method METHOD to class TYPE.
  
!    If non-NULL, FIELDS is the entry in the METHOD_VEC vector entry of
!    the class type where the method should be added.  */
  
  void
  add_method (type, fields, method)
*************** add_method (type, fields, method)
*** 1184,1189 ****
--- 1182,1233 ----
  	      len = 2 * len;
  	      method_vec = CLASSTYPE_METHOD_VEC (type) = new_vec;
  	    }
+ 	  else if (template_class_depth (type))
+ 	    /* TYPE is a template class.  Don't issue any errors now;
+ 	       wait until instantiation time to complain.  */
+ 	      ;
+ 	  else
+ 	    {
+ 	      tree fns;
+ 
+ 	      /* Check to see if we've already got this method.  */
+ 	      for (fns = TREE_VEC_ELT (method_vec, i);
+ 		   fns;
+ 		   fns = OVL_NEXT (fns))
+ 		{
+ 		  tree fn = OVL_CURRENT (fns);
+ 		 
+ 		  if (TREE_CODE (fn) != TREE_CODE (method))
+ 		    continue;
+ 
+ 		  if (TREE_CODE (method) != TEMPLATE_DECL)
+ 		    {
+ 		      /* Since this is an ordinary function in a
+ 			 non-template class, it's mangled name can be
+ 			 used as a unique identifier.  This technique
+ 			 is only an optimization; we would get the
+ 			 same results if we just used decls_match
+ 			 here.  */
+ 		      if (DECL_ASSEMBLER_NAME (fn) 
+ 			  != DECL_ASSEMBLER_NAME (method))
+ 			continue;
+ 		    }
+ 		  else if (!decls_match (fn, method))
+ 		    continue;
+ 
+ 		  /* There has already been a declaration of this
+ 		     method or member template.  */
+ 		  cp_error_at ("`%D' has already been declared in `%T'", 
+ 			       method, type);
+ 
+ 		  /* We don't call duplicate_decls here to merege the
+ 		     declarations because that will confuse things if
+ 		     the methods have inline definitions In
+ 		     particular, we will crash while processing the
+ 		     definitions.  */
+ 		  return;
+ 		}
+ 	    }
  
  	  if (IDENTIFIER_TYPENAME_P (DECL_NAME (method)))
  	    {
*************** add_method (type, fields, method)
*** 1225,1230 ****
--- 1269,1277 ----
  		  TREE_VEC_ELT (method_vec, i) = NULL_TREE;
  		}
  	    }
+ 
+ 	  /* Create RTL for the METHOD.  */
+ 	  make_decl_rtl (method, NULL_PTR, 1);
  
  	  /* Actually insert the new method.  */
  	  TREE_VEC_ELT (method_vec, i) 
Index: decl.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/decl.c,v
retrieving revision 1.233
diff -c -p -r1.233 decl.c
*** decl.c	1998/10/16 03:20:33	1.233
--- decl.c	1998/10/16 18:39:03
*************** decls_match (newdecl, olddecl)
*** 2511,2518 ****
  {
    int types_match;
  
!   if (TREE_CODE (newdecl) == FUNCTION_DECL
!       && TREE_CODE (olddecl) == FUNCTION_DECL)
      {
        tree f1 = TREE_TYPE (newdecl);
        tree f2 = TREE_TYPE (olddecl);
--- 2511,2522 ----
  {
    int types_match;
  
!   if (TREE_CODE (newdecl) != TREE_CODE (olddecl))
!     /* If the two DECLs are not even the same kind of thing, we're not
!        interested in their types.  */
!     return 0;
! 
!   if (TREE_CODE (newdecl) == FUNCTION_DECL)
      {
        tree f1 = TREE_TYPE (newdecl);
        tree f2 = TREE_TYPE (olddecl);
*************** decls_match (newdecl, olddecl)
*** 2568,2575 ****
        else
  	types_match = 0;
      }
!   else if (TREE_CODE (newdecl) == TEMPLATE_DECL
! 	   && TREE_CODE (olddecl) == TEMPLATE_DECL)
      {
        if (!comp_template_parms (DECL_TEMPLATE_PARMS (newdecl),
  				DECL_TEMPLATE_PARMS (olddecl)))
--- 2572,2578 ----
        else
  	types_match = 0;
      }
!   else if (TREE_CODE (newdecl) == TEMPLATE_DECL)
      {
        if (!comp_template_parms (DECL_TEMPLATE_PARMS (newdecl),
  				DECL_TEMPLATE_PARMS (olddecl)))
*************** grokfndecl (ctype, type, declarator, ori
*** 8184,8205 ****
  	}
        if (! grok_ctor_properties (ctype, decl))
  	return error_mark_node;
- 
-       if (check == 0 && ! current_function_decl)
- 	{
- 	  /* Assembler names live in the global namespace. */
- 	  tmp = IDENTIFIER_GLOBAL_VALUE (DECL_ASSEMBLER_NAME (decl));
- 	  if (tmp == NULL_TREE)
- 	    SET_IDENTIFIER_GLOBAL_VALUE (DECL_ASSEMBLER_NAME (decl), decl);
- 	  else if (TREE_CODE (tmp) != TREE_CODE (decl))
- 	    cp_error ("inconsistent declarations for `%D'", decl);
- 	  else
- 	    {
- 	      duplicate_decls (decl, tmp);
- 	      decl = tmp;
- 	    }
- 	  make_decl_rtl (decl, NULL_PTR, 1);
- 	}
      }
    else
      {
--- 8187,8192 ----
*************** grokfndecl (ctype, type, declarator, ori
*** 8248,8284 ****
        if (ctype == NULL_TREE || check)
  	return decl;
  
-       /* Now install the declaration of this function so that others may
- 	 find it (esp. its DECL_FRIENDLIST).  Don't do this for local class
- 	 methods, though.  */
-       if (! current_function_decl)
- 	{
- 	  if (!DECL_TEMPLATE_SPECIALIZATION (decl))
- 	    {
- 	      /* We don't do this for specializations since the
- 		 equivalent checks will be done later.  Also, at this
- 		 point the DECL_ASSEMBLER_NAME is not yet fully
- 		 accurate.  */
- 
- 	      /* FIXME: this should only need to look at
- 		 IDENTIFIER_GLOBAL_VALUE.  */
- 	      tmp = lookup_name (DECL_ASSEMBLER_NAME (decl), 0);
- 	      if (tmp == NULL_TREE)
- 		SET_IDENTIFIER_GLOBAL_VALUE (DECL_ASSEMBLER_NAME (decl), decl);
- 	      else if (TREE_CODE (tmp) != TREE_CODE (decl))
- 		cp_error ("inconsistent declarations for `%D'", decl);
- 	      else
- 		{
- 		  duplicate_decls (decl, tmp);
- 		  decl = tmp;
- 		}
- 	    }
- 
- 	  if (attrlist)
- 	    cplus_decl_attributes (decl, TREE_PURPOSE (attrlist),
- 				   TREE_VALUE (attrlist));
- 	  make_decl_rtl (decl, NULL_PTR, 1);
- 	}
        if (virtualp)
  	{
  	  DECL_VIRTUAL_P (decl) = 1;
--- 8235,8240 ----
Index: decl2.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/decl2.c,v
retrieving revision 1.142
diff -c -p -r1.142 decl2.c
*** decl2.c	1998/10/10 09:24:06	1.142
--- decl2.c	1998/10/16 18:39:17
*************** check_classfn (ctype, function)
*** 1383,1396 ****
  		   fndecls = OVL_NEXT (fndecls))
  		{
  		  fndecl = OVL_CURRENT (fndecls);
! 		  /* The DECL_ASSEMBLER_NAME for a TEMPLATE_DECL is
  		     not mangled, so the check below does not work
! 		     correctly in that case.  Since mangled destructor names
! 		     do not include the type of the arguments, we
! 		     can't use this short-cut for them, either.  */
! 		  if (TREE_CODE (function) != TEMPLATE_DECL
! 		      && TREE_CODE (fndecl) != TEMPLATE_DECL
! 		      && !DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (function))
  		      && (DECL_ASSEMBLER_NAME (function) 
  			  == DECL_ASSEMBLER_NAME (fndecl)))
  		    return fndecl;
--- 1383,1401 ----
  		   fndecls = OVL_NEXT (fndecls))
  		{
  		  fndecl = OVL_CURRENT (fndecls);
! 		  /* The DECL_ASSEMBLER_NAME for a TEMPLATE_DECL, or
! 		     for a for member function of a template class, is
  		     not mangled, so the check below does not work
! 		     correctly in that case.  Since mangled destructor
! 		     names do not include the type of the arguments,
! 		     we can't use this short-cut for them, either.
! 		     (It's not legal to declare arguments for a
! 		     destructor, but some people try.)  */
! 		  if (!DESTRUCTOR_NAME_P (DECL_ASSEMBLER_NAME (function))
! 		      && (DECL_ASSEMBLER_NAME (function)
! 			  != DECL_NAME (function))
! 		      && (DECL_ASSEMBLER_NAME (fndecl)
! 			  != DECL_NAME (fndecl))
  		      && (DECL_ASSEMBLER_NAME (function) 
  			  == DECL_ASSEMBLER_NAME (fndecl)))
  		    return fndecl;
*************** check_classfn (ctype, function)
*** 1467,1474 ****
      }
  
    /* If we did not find the method in the class, add it to avoid
!      spurious errors.  */
!   add_method (ctype, methods, function);
    return NULL_TREE;
  }
  
--- 1472,1482 ----
      }
  
    /* If we did not find the method in the class, add it to avoid
!      spurious errors (unless the CTYPE is not yet defined, in which
!      case we'll only confuse ourselves when the function is declared
!      properly within the class.  */
!   if (TYPE_SIZE (ctype))
!     add_method (ctype, methods, function);
    return NULL_TREE;
  }
  
*************** grokfield (declarator, declspecs, init, 
*** 1573,1580 ****
  
    if (DECL_IN_AGGR_P (value))
      {
!       cp_error ("`%D' is already defined in the class %T", value,
! 		  DECL_CONTEXT (value));
        return void_type_node;
      }
  
--- 1581,1588 ----
  
    if (DECL_IN_AGGR_P (value))
      {
!       cp_error ("`%D' is already defined in `%T'", value,
! 		DECL_CONTEXT (value));
        return void_type_node;
      }
  
Index: method.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/method.c,v
retrieving revision 1.78
diff -c -p -r1.78 method.c
*** method.c	1998/10/06 14:19:59	1.78
--- method.c	1998/10/16 18:39:22
*************** void
*** 1662,1668 ****
  set_mangled_name_for_decl (decl)
       tree decl;
  {
!   tree parm_types = TYPE_ARG_TYPES (TREE_TYPE (decl));
  
    if (DECL_STATIC_FUNCTION_P (decl))
      parm_types = 
--- 1662,1674 ----
  set_mangled_name_for_decl (decl)
       tree decl;
  {
!   tree parm_types;
! 
!   if (processing_template_decl)
!     /* There's no need to mangle the name of a template function.  */
!     return;
! 
!   parm_types = TYPE_ARG_TYPES (TREE_TYPE (decl));
  
    if (DECL_STATIC_FUNCTION_P (decl))
      parm_types = 



More information about the Gcc-patches mailing list