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 bug 4361


Hi,
this fixes bug 4361, a problem with templated conversion operators.
It also fixes several other conversion operator problems, which I came
across in the process.

We would give every conversion operator a slot in the
CLASSTYPE_METHOD_VEC based on its name. If we failed to find the conversion
op required, we'd then pull out the first TEMPLATE_DECL conversion op
found. If there were more than one template conversion op, things went
wrong.

There are two types of templated conversion operator to deal with.
a) Those whose type depends on template arguments
b) Those whose type doesn't (these are rather odd)

I've added a flag to decl_lang_flags which distinguishes a & b.
DECL_TEMPLATE_CONV_FN_P is true for template decls of conversion operators
where the converted-to type is dependent on the innermost template
arguments. It is true for
	template <typename T> operator T ();
but not for
	template <typename T> operator int ();

All conversion ops for which DECL_TEMPLATE_CONV_FN_P is true are put
on the CLASSTYPE_FIRST_CONVERSION_SLOT. The other conversion operators
are as before, afterwards.

I also discovered that mangle_conv_op_name_for_type was not generating
unique names when template parameters were involved. I've added a
global flag to mangle.c indicating that we are doing an internal mangling.
When doing that we mangle the template parm level and, for non-type
template parms, the parm's type too. (This latter part is like the
patch I posted for PR45 which shows a similar problem for non-type
template parms of different type.)

build_user_type_conversion_1 was erroneously assuming that if the
first conversion operator of an overload was a template then all the others
would be. This leads to ICS being error_mark_node, when that is not true.
So I don't attempt to optimize the second type conversion there.

Finally, build_component_ref for a conversion operator might get back a
list of templated conversion operators. The type of whose name does not
resemble the required type (because they involve template parameters).
I preserve the original required type on the type of the first OVERLOAD,
and then recreate it in build_x_function_call.

You'll see I've added a questioning comment in build_component_ref. I
don't understand why we're simply ignoring the TREE_CHAIN of fndecls.
In the previous if to see whether it is a single function, we check
whether the chain is non-null. It doesn't seem right, but that's a
different bug.

built & tested on i686-pc-linux-gnu, ok?

nathan
-- 
Dr Nathan Sidwell   ::   http://www.codesourcery.com   ::   CodeSourcery LLC
         'But that's a lie.' - 'Yes it is. What's your point?'
nathan@codesourcery.com : http://www.cs.bris.ac.uk/~nathan/ : nathan@acm.org
2001-12-30  Nathan Sidwell  <nathan@codesourcery.com>

	PR c++/4361
	* cp-tree.h (CLASSTYPE_METHOD_VEC): Document where templated
	conversion operators go.
	(struct lang_decl_flags): Add template_conv_p and unused
	bitfields.
	(DECL_TEMPLATE_CONV_FN_P): New macro.
	* call.c (build_user_type_conversion_1): Don't check second type
	conversion of overload set first.
	* class.c (add_method): Make sure templated conversion operators
	all end up on slot 2.
	* lex.c (do_identifier): A conversion operator token might be
	satisfied by a templated conversion operator.
	* mangle.c (internal_mangling_p): New global variable.
	(write_template_param): Do internal mangling, if needed.
	(mangle_conv_op_name_for_type): Request internal mangling.
	* pt.c (check_explicit_specialization): Use
	CLASSTYPE_FIRST_CONVERSION_SLOT.
	(template_parm_this_level_p): New function.
	(push_template_decl_real): Determine DECL_TEMPLATE_CONV_FN_P.
	* search.c (lookup_fn_fields_1): Template conversions will be on
	the first slot.
	* typeck.c (build_component_ref): Preserve the type of an
	conversion operator name on the overload type.
	(build_x_function_call): Retrieve the conversion operator name.

Index: cp/call.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/call.c,v
retrieving revision 1.300
diff -c -3 -p -r1.300 call.c
*** call.c	2001/12/29 17:24:59	1.300
--- call.c	2001/12/30 14:48:03
*************** build_user_type_conversion_1 (totype, ex
*** 2438,2444 ****
      {
        tree fns = TREE_VALUE (convs);
        int convflags = LOOKUP_NO_CONVERSION;
-       tree ics;
  
        /* If we are called to convert to a reference type, we are trying to
  	 find an lvalue binding, so don't even consider temporaries.  If
--- 2438,2443 ----
*************** build_user_type_conversion_1 (totype, ex
*** 2446,2502 ****
  	 look for a temporary binding.  */
        if (TREE_CODE (totype) == REFERENCE_TYPE)
  	convflags |= LOOKUP_NO_TEMP_BIND;
! 
!       if (TREE_CODE (OVL_CURRENT (fns)) != TEMPLATE_DECL)
! 	ics = implicit_conversion
! 	  (totype, TREE_TYPE (TREE_TYPE (OVL_CURRENT (fns))), 0, convflags);
!       else
! 	/* We can't compute this yet.  */
! 	ics = error_mark_node;
! 
!       if (TREE_CODE (totype) == REFERENCE_TYPE && ics && ICS_BAD_FLAG (ics))
! 	/* ignore the near match.  */;
!       else if (ics)
! 	for (; fns; fns = OVL_NEXT (fns))
! 	  {
! 	    tree fn = OVL_CURRENT (fns);
! 	    struct z_candidate *old_candidates = candidates;
! 
! 	    /* [over.match.funcs] For conversion functions, the function is
! 	       considered to be a member of the class of the implicit object
! 	       argument for the purpose of defining the type of the implicit
! 	       object parameter.
! 
! 	       So we pass fromtype as CTYPE to add_*_candidate.  */
! 
! 	    if (TREE_CODE (fn) == TEMPLATE_DECL)
! 	      {
! 		templates = tree_cons (NULL_TREE, fn, templates);
! 		candidates = 
! 		  add_template_candidate (candidates, fn, fromtype, NULL_TREE,
! 					  args, totype, flags,
! 					  DEDUCE_CONV);
! 	      } 
! 	    else 
! 	      candidates = add_function_candidate (candidates, fn, fromtype,
! 						   args, flags); 
! 
! 	    if (candidates != old_candidates)
! 	      {
! 		if (TREE_CODE (fn) == TEMPLATE_DECL)
! 		  ics = implicit_conversion
! 		    (totype, TREE_TYPE (TREE_TYPE (candidates->fn)),
! 		     0, convflags);
! 
! 		candidates->second_conv = ics;
! 		candidates->basetype_path = TYPE_BINFO (fromtype);
! 
! 		if (ics == NULL_TREE)
! 		  candidates->viable = 0;
! 		else if (candidates->viable == 1 && ICS_BAD_FLAG (ics))
! 		  candidates->viable = -1;
! 	      }
! 	  }
      }
  
    if (! any_viable (candidates))
--- 2445,2490 ----
  	 look for a temporary binding.  */
        if (TREE_CODE (totype) == REFERENCE_TYPE)
  	convflags |= LOOKUP_NO_TEMP_BIND;
!       
!       for (; fns; fns = OVL_NEXT (fns))
! 	{
! 	  tree fn = OVL_CURRENT (fns);
! 	  struct z_candidate *old_candidates = candidates;
! 	  
! 	  /* [over.match.funcs] For conversion functions, the function
! 	     is considered to be a member of the class of the implicit
! 	     object argument for the purpose of defining the type of
! 	     the implicit object parameter.
! 
! 	     So we pass fromtype as CTYPE to add_*_candidate.  */
! 
! 	  if (TREE_CODE (fn) == TEMPLATE_DECL)
! 	    {
! 	      templates = tree_cons (NULL_TREE, fn, templates);
! 	      candidates = 
! 		add_template_candidate (candidates, fn, fromtype, NULL_TREE,
! 					args, totype, flags,
! 					DEDUCE_CONV);
! 	    } 
! 	  else 
! 	    candidates = add_function_candidate (candidates, fn, fromtype,
! 						 args, flags); 
! 
! 	  if (candidates != old_candidates)
! 	    {
! 	      tree ics = implicit_conversion
! 		(totype, TREE_TYPE (TREE_TYPE (candidates->fn)),
! 		 0, convflags);
! 
! 	      candidates->second_conv = ics;
! 	      candidates->basetype_path = TYPE_BINFO (fromtype);
! 	      
! 	      if (ics == NULL_TREE)
! 		candidates->viable = 0;
! 	      else if (candidates->viable == 1 && ICS_BAD_FLAG (ics))
! 		candidates->viable = -1;
! 	    }
! 	}
      }
  
    if (! any_viable (candidates))
Index: cp/class.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/class.c,v
retrieving revision 1.427
diff -c -3 -p -r1.427 class.c
*** class.c	2001/12/18 15:18:20	1.427
--- class.c	2001/12/30 14:49:25
*************** add_method (type, method, error_p)
*** 853,858 ****
--- 853,860 ----
    int len;
    int slot;
    tree method_vec;
+   int template_conv_p = (TREE_CODE (method) == TEMPLATE_DECL
+ 			 && DECL_TEMPLATE_CONV_FN_P (method));
  
    if (!CLASSTYPE_METHOD_VEC (type))
      /* Make a new method vector.  We start with 8 entries.  We must
*************** add_method (type, method, error_p)
*** 877,890 ****
      slot = CLASSTYPE_DESTRUCTOR_SLOT;
    else
      {
        /* See if we already have an entry with this name.  */
        for (slot = CLASSTYPE_FIRST_CONVERSION_SLOT; slot < len; ++slot)
! 	if (!TREE_VEC_ELT (method_vec, slot)
! 	    || (DECL_NAME (OVL_CURRENT (TREE_VEC_ELT (method_vec, 
! 						      slot))) 
! 		== DECL_NAME (method)))
! 	  break;
! 		
        if (slot == len)
  	{
  	  /* We need a bigger method vector.  */
--- 879,914 ----
      slot = CLASSTYPE_DESTRUCTOR_SLOT;
    else
      {
+       int have_template_convs_p = 0;
+       
        /* See if we already have an entry with this name.  */
        for (slot = CLASSTYPE_FIRST_CONVERSION_SLOT; slot < len; ++slot)
! 	{
! 	  tree m = TREE_VEC_ELT (method_vec, slot);
! 
! 	  if (!m)
! 	    break;
! 	  m = OVL_CURRENT (m);
! 	  
! 	  if (template_conv_p)
! 	    {
! 	      have_template_convs_p = (TREE_CODE (m) == TEMPLATE_DECL
! 				       && DECL_TEMPLATE_CONV_FN_P (m));
! 	      
! 	      /* If we need to move things up, see if there's
! 		 space. */
! 	      if (!have_template_convs_p)
! 		{
! 		  slot = len - 1;
! 		  if (TREE_VEC_ELT (method_vec, slot))
! 		    slot++;
! 		}
! 	      break;
! 	    }
! 	  if (DECL_NAME (m) == DECL_NAME (method))
! 	    break;
! 	}
!       
        if (slot == len)
  	{
  	  /* We need a bigger method vector.  */
*************** add_method (type, method, error_p)
*** 917,938 ****
  	     slide some of the vector elements up.  In theory, this
  	     makes this algorithm O(N^2) but we don't expect many
  	     conversion operators.  */
! 	  for (slot = 2; slot < len; ++slot)
! 	    {
! 	      tree fn = TREE_VEC_ELT (method_vec, slot);
    
! 	      if (!fn)
! 		/* There are no more entries in the vector, so we
! 		   can insert the new conversion operator here.  */
! 		break;
    		  
! 	      if (!DECL_CONV_FN_P (OVL_CURRENT (fn)))
! 		/* We can insert the new function right at the
! 		   SLOTth position.  */
! 		break;
! 	    }
!   
! 	  if (!TREE_VEC_ELT (method_vec, slot))
  	    /* There is nothing in the Ith slot, so we can avoid
  	       moving anything.  */
  		; 
--- 941,967 ----
  	     slide some of the vector elements up.  In theory, this
  	     makes this algorithm O(N^2) but we don't expect many
  	     conversion operators.  */
! 	  if (template_conv_p)
! 	    slot = CLASSTYPE_FIRST_CONVERSION_SLOT;
! 	  else
! 	    for (slot = CLASSTYPE_FIRST_CONVERSION_SLOT; slot < len; ++slot)
! 	      {
! 		tree fn = TREE_VEC_ELT (method_vec, slot);
    
! 		if (!fn)
! 		  /* There are no more entries in the vector, so we
! 		     can insert the new conversion operator here.  */
! 		  break;
    		  
! 		if (!DECL_CONV_FN_P (OVL_CURRENT (fn)))
! 		  /* We can insert the new function right at the
! 		     SLOTth position.  */
! 		  break;
! 	      }
! 
! 	  if (template_conv_p && have_template_convs_p)
! 	    /*OK*/;
! 	  else if (!TREE_VEC_ELT (method_vec, slot))
  	    /* There is nothing in the Ith slot, so we can avoid
  	       moving anything.  */
  		; 
*************** add_method (type, method, error_p)
*** 1033,1039 ****
    TREE_VEC_ELT (method_vec, slot) 
      = build_overload (method, TREE_VEC_ELT (method_vec, slot));
  
!       /* Add the new binding.  */ 
    if (!DECL_CONSTRUCTOR_P (method)
        && !DECL_DESTRUCTOR_P (method))
      push_class_level_binding (DECL_NAME (method),
--- 1062,1068 ----
    TREE_VEC_ELT (method_vec, slot) 
      = build_overload (method, TREE_VEC_ELT (method_vec, slot));
  
!   /* Add the new binding.  */ 
    if (!DECL_CONSTRUCTOR_P (method)
        && !DECL_DESTRUCTOR_P (method))
      push_class_level_binding (DECL_NAME (method),
Index: cp/cp-tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/cp-tree.h,v
retrieving revision 1.667
diff -c -3 -p -r1.667 cp-tree.h
*** cp-tree.h	2001/12/18 03:35:25	1.667
--- cp-tree.h	2001/12/30 14:50:24
*************** struct lang_type
*** 1337,1344 ****
     either a FUNCTION_DECL, a TEMPLATE_DECL, or an OVERLOAD.  All
     functions with the same name end up in the same slot.  The first
     two elements are for constructors, and destructors, respectively.
!    Any conversion operators are next, followed by ordinary member
!    functions.  There may be empty entries at the end of the vector.  */
  #define CLASSTYPE_METHOD_VEC(NODE) (TYPE_LANG_SPECIFIC(NODE)->methods)
  
  /* The slot in the CLASSTYPE_METHOD_VEC where constructors go.  */
--- 1337,1350 ----
     either a FUNCTION_DECL, a TEMPLATE_DECL, or an OVERLOAD.  All
     functions with the same name end up in the same slot.  The first
     two elements are for constructors, and destructors, respectively.
!    All template conversion operators to innermost template dependent
!    types are overloaded on the next slot, if they exist.  Note, the
!    names for these functions will not all be the same.  The
!    non-template conversion operators & templated conversions to
!    non-innermost template types are next, followed by ordinary member
!    functions.  There may be empty entries at the end of the vector.
!    The conversion operators are unsorted. The ordinary member
!    functions are sorted, once the class is complete.  */
  #define CLASSTYPE_METHOD_VEC(NODE) (TYPE_LANG_SPECIFIC(NODE)->methods)
  
  /* The slot in the CLASSTYPE_METHOD_VEC where constructors go.  */
*************** struct lang_decl_flags
*** 1713,1719 ****
    unsigned global_dtor_p : 1;
    unsigned assignment_operator_p : 1;
    unsigned anticipated_p : 1;
!   /* Four unused bits.  */
  
    union {
      /* In a FUNCTION_DECL, VAR_DECL, TYPE_DECL, or TEMPLATE_DECL, this
--- 1719,1727 ----
    unsigned global_dtor_p : 1;
    unsigned assignment_operator_p : 1;
    unsigned anticipated_p : 1;
!   unsigned template_conv_p : 1;
!   
!   unsigned unused : 3; /* Three unused bits.  */
  
    union {
      /* In a FUNCTION_DECL, VAR_DECL, TYPE_DECL, or TEMPLATE_DECL, this
*************** struct lang_decl
*** 1901,1906 ****
--- 1909,1920 ----
  /* Non-zero if NODE is a user-defined conversion operator.  */
  #define DECL_CONV_FN_P(NODE) \
    (IDENTIFIER_TYPENAME_P (DECL_NAME (NODE)))
+ 
+ /* Non-zero if NODE, which is a TEMPLATE_DECL, is a template
+    conversion operator to a type dependent on the innermost template
+    args.  */
+ #define DECL_TEMPLATE_CONV_FN_P(NODE) \
+   (DECL_LANG_SPECIFIC (NODE)->decl_flags.template_conv_p)
  
  /* Set the overloaded operator code for NODE to CODE.  */
  #define SET_OVERLOADED_OPERATOR_CODE(NODE, CODE) \
Index: cp/lex.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/lex.c,v
retrieving revision 1.261
diff -c -3 -p -r1.261 lex.c
*** lex.c	2001/12/18 03:35:33	1.261
--- lex.c	2001/12/30 14:51:30
*************** do_identifier (token, parsing, args)
*** 1245,1250 ****
--- 1245,1253 ----
      {
        if (current_template_parms)
  	return build_min_nt (LOOKUP_EXPR, token);
+       else if (IDENTIFIER_TYPENAME_P (token))
+ 	/* A templated conversion operator might exist.  */
+ 	return token;
        else if (IDENTIFIER_OPNAME_P (token))
  	{
  	  if (token != ansi_opname (ERROR_MARK))
Index: cp/mangle.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/mangle.c,v
retrieving revision 1.40
diff -c -3 -p -r1.40 mangle.c
*** mangle.c	2001/11/22 02:32:56	1.40
--- mangle.c	2001/12/30 14:51:54
*************** integer_type_codes[itk_none] =
*** 131,136 ****
--- 131,141 ----
    'y'   /* itk_unsigned_long_long */
  };
  
+ /* We are mangling an internal symbol. It is important to keep those
+    involving template parmeters distinct by distinguishing their level
+    and, for non-type parms, their type.  */
+ static bool internal_mangling_p;
+ 
  static int decl_is_template_id PARAMS ((tree, tree*));
  
  /* Functions for handling substitutions.  */
*************** write_pointer_to_member_type (type)
*** 2045,2058 ****
  /* Non-terminal <template-param>.  PARM is a TEMPLATE_TYPE_PARM,
     TEMPLATE_TEMPLATE_PARM, BOUND_TEMPLATE_TEMPLATE_PARM or a
     TEMPLATE_PARM_INDEX.
  
!      <template-param> ::= T </parameter/ number> _  */
  
  static void
  write_template_param (parm)
       tree parm;
  {
    int parm_index;
  
    MANGLE_TRACE_TREE ("template-parm", parm);
  
--- 2050,2072 ----
  /* Non-terminal <template-param>.  PARM is a TEMPLATE_TYPE_PARM,
     TEMPLATE_TEMPLATE_PARM, BOUND_TEMPLATE_TEMPLATE_PARM or a
     TEMPLATE_PARM_INDEX.
+ 
+      <template-param> ::= T </parameter/ number> _
+ 
+    If we are internally mangling then we distinguish level and, for
+    non-type parms, type too. The mangling appends
+    
+      </level/ number> _ </non-type type/ type> _
  
!    This is used by mangle_conv_op_name_for_type.  */
  
  static void
  write_template_param (parm)
       tree parm;
  {
    int parm_index;
+   int parm_level;
+   tree parm_type = NULL_TREE;
  
    MANGLE_TRACE_TREE ("template-parm", parm);
  
*************** write_template_param (parm)
*** 2062,2071 ****
--- 2076,2088 ----
      case TEMPLATE_TEMPLATE_PARM:
      case BOUND_TEMPLATE_TEMPLATE_PARM:
        parm_index = TEMPLATE_TYPE_IDX (parm);
+       parm_level = TEMPLATE_TYPE_LEVEL (parm);
        break;
  
      case TEMPLATE_PARM_INDEX:
        parm_index = TEMPLATE_PARM_IDX (parm);
+       parm_level = TEMPLATE_PARM_LEVEL (parm);
+       parm_type = TREE_TYPE (TEMPLATE_PARM_DECL (parm));
        break;
  
      default:
*************** write_template_param (parm)
*** 2078,2083 ****
--- 2095,2109 ----
    if (parm_index > 0)
      write_unsigned_number (parm_index - 1);
    write_char ('_');
+   if (internal_mangling_p)
+     {
+       if (parm_level > 0)
+ 	write_unsigned_number (parm_level - 1);
+       write_char ('_');
+       if (parm_type)
+ 	write_type (parm_type);
+       write_char ('_');
+     }
  }
  
  /*  <template-template-param>
*************** mangle_conv_op_name_for_type (type)
*** 2404,2418 ****
       tree type;
  {
    tree identifier;
  
!   /* Build the mangling for TYPE.  */
!   const char *mangled_type = mangle_type_string (type);
    /* Allocate a temporary buffer for the complete name.  */
!   char *op_name = concat ("operator ", mangled_type, NULL);
    /* Find or create an identifier.  */
    identifier = get_identifier (op_name);
    /* Done with the temporary buffer.  */
    free (op_name);
    /* Set bits on the identifier so we know later it's a conversion.  */
    IDENTIFIER_OPNAME_P (identifier) = 1;
    IDENTIFIER_TYPENAME_P (identifier) = 1;
--- 2430,2455 ----
       tree type;
  {
    tree identifier;
+   const char *mangled_type;
+   char *op_name;
  
!   /* Build the internal mangling for TYPE.  */
!   internal_mangling_p = true;
!   mangled_type = mangle_type_string (type);
!   internal_mangling_p = false;
!   
    /* Allocate a temporary buffer for the complete name.  */
!   op_name = concat ("operator ", mangled_type, NULL);
    /* Find or create an identifier.  */
    identifier = get_identifier (op_name);
    /* Done with the temporary buffer.  */
    free (op_name);
+ 
+   /* It had better be a unique mangling for the type.  */
+   my_friendly_assert (!IDENTIFIER_TYPENAME_P (identifier)
+ 		      || same_type_p (type, TREE_TYPE (identifier)),
+ 		      20011230);
+   
    /* Set bits on the identifier so we know later it's a conversion.  */
    IDENTIFIER_OPNAME_P (identifier) = 1;
    IDENTIFIER_TYPENAME_P (identifier) = 1;
Index: cp/pt.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/pt.c,v
retrieving revision 1.568
diff -c -3 -p -r1.568 pt.c
*** pt.c	2001/12/29 17:24:59	1.568
--- pt.c	2001/12/30 14:53:37
*************** static int unregister_specialization PAR
*** 130,135 ****
--- 130,136 ----
  static tree reduce_template_parm_level PARAMS ((tree, tree, int));
  static tree build_template_decl PARAMS ((tree, tree));
  static int mark_template_parm PARAMS ((tree, void *));
+ static int template_parm_this_level_p PARAMS ((tree, void *));
  static tree tsubst_friend_function PARAMS ((tree, tree));
  static tree tsubst_friend_class PARAMS ((tree, tree));
  static tree get_bindings_real PARAMS ((tree, tree, tree, int, int, int));
*************** check_explicit_specialization (declarato
*** 1576,1582 ****
  
  	      methods = CLASSTYPE_METHOD_VEC (ctype);
  	      if (methods)
! 		for (idx = 2; idx < TREE_VEC_LENGTH (methods); ++idx) 
  		  {
  		    tree ovl = TREE_VEC_ELT (methods, idx);
  
--- 1577,1584 ----
  
  	      methods = CLASSTYPE_METHOD_VEC (ctype);
  	      if (methods)
! 		for (idx = CLASSTYPE_FIRST_CONVERSION_SLOT;
! 		     idx < TREE_VEC_LENGTH (methods); ++idx) 
  		  {
  		    tree ovl = TREE_VEC_ELT (methods, idx);
  
*************** check_default_tmpl_args (decl, parms, is
*** 2492,2497 ****
--- 2494,2519 ----
      }
  }
  
+ /* Worker for push_template_decl_real, called via
+    for_each_template_parm.  DATA is really an int, indicating the
+    level of the parameters we are interested in.  If T is a template
+    parameter of that level, return non-zero.  */
+ 
+ static int
+ template_parm_this_level_p (t, data)
+      tree t;
+      void *data;
+ {
+   int this_level = (int)data;
+   int level;
+ 
+   if (TREE_CODE (t) == TEMPLATE_PARM_INDEX)
+     level = TEMPLATE_PARM_LEVEL (t);
+   else
+     level = TEMPLATE_TYPE_LEVEL (t);
+   return level == this_level;
+ }
+ 
  /* Creates a TEMPLATE_DECL for the indicated DECL using the template
     parameters given by current_template_args, or reuses a
     previously existing one, if appropriate.  Returns the DECL, or an
*************** push_template_decl_real (decl, is_friend
*** 2712,2718 ****
      tmpl = pushdecl_namespace_level (tmpl);
  
    if (primary)
!     DECL_PRIMARY_TEMPLATE (tmpl) = tmpl;
  
    info = tree_cons (tmpl, args, NULL_TREE);
  
--- 2734,2753 ----
      tmpl = pushdecl_namespace_level (tmpl);
  
    if (primary)
!     {
!       DECL_PRIMARY_TEMPLATE (tmpl) = tmpl;
!       if (DECL_CONV_FN_P (tmpl))
! 	{
! 	  /* It is a conversion operator. See if the type converted to
! 	     depends on innermost template operands.  */
! 	  
! 	  if (for_each_template_parm
! 	      (TREE_TYPE (TREE_TYPE (tmpl)),
! 	       template_parm_this_level_p,
! 	       (void *)TMPL_PARMS_DEPTH (DECL_TEMPLATE_PARMS (tmpl))))
! 	    DECL_TEMPLATE_CONV_FN_P (tmpl) = 1;
! 	}
!     }
  
    info = tree_cons (tmpl, args, NULL_TREE);
  
Index: cp/search.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/search.c,v
retrieving revision 1.220
diff -c -3 -p -r1.220 search.c
*** search.c	2001/12/18 03:35:37	1.220
--- search.c	2001/12/30 14:54:02
*************** int
*** 1527,1534 ****
  lookup_fnfields_1 (type, name)
       tree type, name;
  {
!   tree method_vec 
!     = CLASS_TYPE_P (type) ? CLASSTYPE_METHOD_VEC (type) : NULL_TREE;
  
    if (method_vec != 0)
      {
--- 1527,1535 ----
  lookup_fnfields_1 (type, name)
       tree type, name;
  {
!   tree method_vec = (CLASS_TYPE_P (type)
! 		     ? CLASSTYPE_METHOD_VEC (type)
! 		     : NULL_TREE);
  
    if (method_vec != 0)
      {
*************** lookup_fnfields_1 (type, name)
*** 1591,1612 ****
  	}
  
        /* If we didn't find it, it might have been a template
! 	 conversion operator.  (Note that we don't look for this case
! 	 above so that we will always find specializations first.)  */
        if (IDENTIFIER_TYPENAME_P (name)) 
  	{
! 	  for (i = CLASSTYPE_FIRST_CONVERSION_SLOT; 
! 	       i < len && methods[i]; 
! 	       ++i)
  	    {
  	      tmp = OVL_CURRENT (methods[i]);
! 	      if (! DECL_CONV_FN_P (tmp))
! 		{
! 		  /* Since all conversion operators come first, we know
! 		     there is no such operator.  */
! 		  break;
! 		}
! 	      else if (TREE_CODE (tmp) == TEMPLATE_DECL)
  		return i;
  	    }
  	}
--- 1592,1610 ----
  	}
  
        /* If we didn't find it, it might have been a template
! 	 conversion operator to a templated type.  If there are any,
! 	 such template conversion operators will all be overloaded on
! 	 the first conversion slot.  (Note that we don't look for this
! 	 case above so that we will always find specializations
! 	 first.)  */
        if (IDENTIFIER_TYPENAME_P (name)) 
  	{
! 	  i = CLASSTYPE_FIRST_CONVERSION_SLOT;
! 	  if (i < len && methods[i])
  	    {
  	      tmp = OVL_CURRENT (methods[i]);
! 	      if (TREE_CODE (tmp) == TEMPLATE_DECL
! 		  && DECL_TEMPLATE_CONV_FN_P (tmp))
  		return i;
  	    }
  	}
Index: cp/typeck.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/typeck.c,v
retrieving revision 1.379
diff -c -3 -p -r1.379 typeck.c
*** typeck.c	2001/12/29 17:10:07	1.379
--- typeck.c	2001/12/30 14:55:14
*************** build_component_ref (datum, component, b
*** 2140,2146 ****
  		 now.  Otherwise, we have to wait and see what context it is
  		 used in; a component_ref involving a non-static member
  		 function can only be used in a call (expr.ref).  */
! 
  	      if (TREE_CHAIN (fndecls) == NULL_TREE
  		  && TREE_CODE (TREE_VALUE (fndecls)) == FUNCTION_DECL)
  		{
--- 2140,2146 ----
  		 now.  Otherwise, we have to wait and see what context it is
  		 used in; a component_ref involving a non-static member
  		 function can only be used in a call (expr.ref).  */
! 	      
  	      if (TREE_CHAIN (fndecls) == NULL_TREE
  		  && TREE_CODE (TREE_VALUE (fndecls)) == FUNCTION_DECL)
  		{
*************** build_component_ref (datum, component, b
*** 2161,2169 ****
  			= ovl_cons (TREE_VALUE (fndecls), NULL_TREE);
  		    }
  		}
! 
  	      ref = build (COMPONENT_REF, unknown_type_node,
! 			   datum, TREE_VALUE (fndecls));
  	      return ref;
  	    }
  
--- 2161,2180 ----
  			= ovl_cons (TREE_VALUE (fndecls), NULL_TREE);
  		    }
  		}
! 	      /* Why are we forgetting TREE_CHAIN here? [NMS 2001/12/30] */
! 	      fndecls = TREE_VALUE (fndecls);
! 	      if (IDENTIFIER_TYPENAME_P (name))
! 		{
! 		  /* We want for a conversion op. We need to remember
! 		     the actual type we wanted, incase we got a set of
! 		     templated conversion operators back.  */
! 		  fndecls = ovl_cons (OVL_CURRENT (fndecls),
! 				      OVL_NEXT (fndecls));
! 		  TREE_TYPE (fndecls) = TREE_TYPE (name);
! 		}
! 	      
  	      ref = build (COMPONENT_REF, unknown_type_node,
! 			   datum, fndecls);
  	      return ref;
  	    }
  
*************** build_x_function_call (function, params,
*** 2698,2705 ****
      {
        /* Undo what we did in build_component_ref.  */
        decl = TREE_OPERAND (function, 0);
        function = TREE_OPERAND (function, 1);
!       function = DECL_NAME (OVL_CURRENT (function));
  
        if (template_id)
  	{
--- 2709,2723 ----
      {
        /* Undo what we did in build_component_ref.  */
        decl = TREE_OPERAND (function, 0);
+ 
        function = TREE_OPERAND (function, 1);
!       if (TREE_CODE (function) == OVERLOAD
! 	  && TREE_TYPE (function) != unknown_type_node)
! 	/* It was a conversion operator. We can't use DECL_NAME, as
! 	   that might refer to a templated function.  */
! 	function = mangle_conv_op_name_for_type (TREE_TYPE (function));
!       else
! 	function = DECL_NAME (OVL_CURRENT (function));
  
        if (template_id)
  	{
// { dg-do compile }

// Copyright (C) 2001 Free Software Foundation, Inc.
// Contributed by Nathan Sidwell 29 Dec 2001 <nathan@nathan@codesourcery.com>

// PR 4361. Template conversion operators were not overloaded.

template <class T> struct Second;

template<class T> struct First
{
  int Foo ();
  
  template <class U> operator Second<U>();
  template <class U> operator First<U>();
};

template <class T> int First<T>::Foo ()
{} // This is here to make sure we didn't smash Foo's decl in the
   // method vector

struct B { };
struct D { };

void Foo ()
{
  First<B> (First<D>::*pf)() = &First<D>::operator First<B>;
}
// { dg-do run }

// Copyright (C) 2001 Free Software Foundation, Inc.
// Contributed by Nathan Sidwell 29 Dec 2001 <nathan@nathan@codesourcery.com>

// PR 4361. Template conversion operators were not overloaded.

class C
{
public:

  operator float () {return 2;}
  
  operator int () 
  {
    return 0;
  }
  
  template<typename T>
  operator int ()
  { return 1;
  }
};

int main ()
{
  C p;
  int r;

  r = p.operator int ();
  if (r)
    return r;
  r = static_cast <int> (p);

  if (r)
    return r + 2;
  
  return 0;
}
// { dg-do run }

// Copyright (C) 2001 Free Software Foundation, Inc.
// Contributed by Nathan Sidwell 29 Dec 2001 <nathan@nathan@codesourcery.com>

// PR 4361. Template conversion operators were not overloaded.

template <typename T> struct C
{
  operator T () 
  {
    return 0;
  }
  template <typename T2> operator T2 ()
  {
    return 1;
  }
  int Foo ()
  {
    return operator T ();
  }
  template <typename T2> int Baz ()
  {
    return static_cast <int> (operator T2 ());
  }
};

int main ()
{
  int r;
  C<int> c;

  r = c.Foo ();
  if (r)
    return 1;
  r = c.Baz<int> ();
  if (r)
    return 2;
  r = c.Baz<float> ();
  if (!r)
    return 3;
  return 0;
}
// { dg-do compile }

// Copyright (C) 2001 Free Software Foundation, Inc.
// Contributed by Nathan Sidwell 29 Dec 2001 <nathan@nathan@codesourcery.com>

// PR 4361. Template conversion operators were not overloaded.

struct C
{
  template <typename T2> operator T2 ()
  {
    return 1;
  }
  int Foo ()
  {
    return operator int ();
  }
};

struct D
{
  int Foo ()
  {
    return operator int (); // { dg-error "no matching function" "" }
  }
};


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