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]

C++ PATCH: clean up copy-initialization


I decided to fix the auto_ptr test in v3, which led to an overhaul of the
copy-initialization code.  Amusingly, the old conversion code (ocp_convert)
was doing the right thing for copy-initialization, but the new conversion
code was not.  The comments should be pretty clear as to what's going on.

For the moment, I've handled giving error context in these conversions like
we do in convert_for_initialization, but I think that something like a
maybe_print_overload_context in error.c would be cleaner.  Thoughts?

Tested repeatedly on i686-pc-linux-gnu.

2000-12-08  Jason Merrill  <jason@redhat.com>

	Clean up copy-initialization in overloading code.
	* call.c (build_user_type_conversion_1): Die if we are asked to
	convert to the same or a base type.
	(implicit_conversion): Avoid doing so.  Lose reference binding code.
	(convert_like_real): Treat BASE_CONV and RVALUE_CONV as implicit
	direct-initialization.  Also do direct-init part of copy-init.
	(build_user_type_conversion): Don't provide context to convert_like.
	* cvt.c (ocp_convert): build_user_type_conversion will now provide
	the constructor call for copy-init.

*** call.c.~1~	Fri Dec  8 21:17:29 2000
--- call.c	Fri Dec  8 21:17:34 2000
*************** implicit_conversion (to, from, expr, fla
*** 1237,1265 ****
    if (conv)
      ;
    else if (expr != NULL_TREE
! 	   && (IS_AGGR_TYPE (non_reference (from))
! 	       || IS_AGGR_TYPE (non_reference (to)))
  	   && (flags & LOOKUP_NO_CONVERSION) == 0)
      {
        cand = build_user_type_conversion_1
  	(to, expr, LOOKUP_ONLYCONVERTING);
        if (cand)
  	conv = cand->second_conv;
!       if ((! conv || ICS_BAD_FLAG (conv))
! 	  && TREE_CODE (to) == REFERENCE_TYPE
! 	  && (flags & LOOKUP_NO_TEMP_BIND) == 0)
! 	{
! 	  cand = build_user_type_conversion_1
! 	    (TYPE_MAIN_VARIANT (TREE_TYPE (to)), expr, LOOKUP_ONLYCONVERTING);
! 	  if (cand)
! 	    {
! 	      if (!CP_TYPE_CONST_NON_VOLATILE_P (TREE_TYPE (to)))
! 		ICS_BAD_FLAG (cand->second_conv) = 1;
! 	      if (!conv || (ICS_BAD_FLAG (conv)
! 			    > ICS_BAD_FLAG (cand->second_conv)))
! 		conv = build_conv (REF_BIND, to, cand->second_conv);
! 	    }
! 	}
      }
  
    return conv;
--- 1237,1254 ----
    if (conv)
      ;
    else if (expr != NULL_TREE
! 	   && (IS_AGGR_TYPE (from)
! 	       || IS_AGGR_TYPE (to))
  	   && (flags & LOOKUP_NO_CONVERSION) == 0)
      {
        cand = build_user_type_conversion_1
  	(to, expr, LOOKUP_ONLYCONVERTING);
        if (cand)
  	conv = cand->second_conv;
! 
!       /* We used to try to bind a reference to a temporary here, but that
! 	 is now handled by the recursive call to this function at the end
! 	 of reference_binding.  */
      }
  
    return conv;
*************** build_user_type_conversion_1 (totype, ex
*** 2325,2330 ****
--- 2314,2326 ----
    tree args = NULL_TREE;
    tree templates = NULL_TREE;
  
+   /* We represent conversion within a hierarchy using RVALUE_CONV and
+      BASE_CONV, as specified by [over.best.ics]; these become plain
+      constructor calls, as specified in [dcl.init].  */
+   if (IS_AGGR_TYPE (fromtype) && IS_AGGR_TYPE (totype)
+       && DERIVED_FROM_P (totype, fromtype))
+     abort ();
+ 
    if (IS_AGGR_TYPE (totype))
      ctors = lookup_fnfields (TYPE_BINFO (totype),
  			     (flag_new_abi 
*************** build_user_type_conversion_1 (totype, ex
*** 2332,2339 ****
  			      : ctor_identifier),
  			     0);
  
!   if (IS_AGGR_TYPE (fromtype)
!       && (! IS_AGGR_TYPE (totype) || ! DERIVED_FROM_P (totype, fromtype)))
      convs = lookup_conversions (fromtype);
  
    candidates = 0;
--- 2328,2334 ----
  			      : ctor_identifier),
  			     0);
  
!   if (IS_AGGR_TYPE (fromtype))
      convs = lookup_conversions (fromtype);
  
    candidates = 0;
*************** build_user_type_conversion (totype, expr
*** 2509,2517 ****
      {
        if (TREE_CODE (cand->second_conv) == AMBIG_CONV)
  	return error_mark_node;
!       return convert_from_reference
!               (convert_like_with_context
!                 (cand->second_conv, expr, cand->fn, 0));
      }
    return NULL_TREE;
  }
--- 2504,2510 ----
      {
        if (TREE_CODE (cand->second_conv) == AMBIG_CONV)
  	return error_mark_node;
!       return convert_from_reference (convert_like (cand->second_conv, expr));
      }
    return NULL_TREE;
  }
*************** convert_like_real (convs, expr, fn, argn
*** 3653,3658 ****
--- 3646,3656 ----
       int argnum;
       int inner;
  {
+   extern int warningcount, errorcount;
+   int savew, savee;
+ 
+   tree totype = TREE_TYPE (convs);
+ 
    if (ICS_BAD_FLAG (convs)
        && TREE_CODE (convs) != USER_CONV
        && TREE_CODE (convs) != AMBIG_CONV
*************** convert_like_real (convs, expr, fn, argn
*** 3672,3700 ****
  	    break;
  	}
        return convert_for_initialization
! 	(NULL_TREE, TREE_TYPE (convs), expr, LOOKUP_NORMAL,
  	 "conversion", fn, argnum);
      }
    
    if (!inner)
      expr = dubious_conversion_warnings
!              (TREE_TYPE (convs), expr, "argument", fn, argnum);
    switch (TREE_CODE (convs))
      {
      case USER_CONV:
        {
  	struct z_candidate *cand
  	  = WRAPPER_PTR (TREE_OPERAND (convs, 1));
! 	tree fn = cand->fn;
  	tree args;
  
! 	if (DECL_CONSTRUCTOR_P (fn))
  	  {
  	    tree t = build_int_2 (0, 0);
! 	    TREE_TYPE (t) = build_pointer_type (DECL_CONTEXT (fn));
  
  	    args = build_tree_list (NULL_TREE, expr);
! 	    if (DECL_HAS_IN_CHARGE_PARM_P (fn))
  	      args = tree_cons (NULL_TREE, integer_one_node, args);
  	    args = tree_cons (NULL_TREE, t, args);
  	  }
--- 3670,3698 ----
  	    break;
  	}
        return convert_for_initialization
! 	(NULL_TREE, totype, expr, LOOKUP_NORMAL,
  	 "conversion", fn, argnum);
      }
    
    if (!inner)
      expr = dubious_conversion_warnings
!              (totype, expr, "argument", fn, argnum);
    switch (TREE_CODE (convs))
      {
      case USER_CONV:
        {
  	struct z_candidate *cand
  	  = WRAPPER_PTR (TREE_OPERAND (convs, 1));
! 	tree convfn = cand->fn;
  	tree args;
  
! 	if (DECL_CONSTRUCTOR_P (convfn))
  	  {
  	    tree t = build_int_2 (0, 0);
! 	    TREE_TYPE (t) = build_pointer_type (DECL_CONTEXT (convfn));
  
  	    args = build_tree_list (NULL_TREE, expr);
! 	    if (DECL_HAS_IN_CHARGE_PARM_P (convfn))
  	      args = tree_cons (NULL_TREE, integer_one_node, args);
  	    args = tree_cons (NULL_TREE, t, args);
  	  }
*************** convert_like_real (convs, expr, fn, argn
*** 3704,3722 ****
  
  	/* If this is a constructor or a function returning an aggr type,
  	   we need to build up a TARGET_EXPR.  */
! 	if (DECL_CONSTRUCTOR_P (fn))
! 	  expr = build_cplus_new (TREE_TYPE (convs), expr);
  
  	return expr;
        }
      case IDENTITY_CONV:
        if (type_unknown_p (expr))
! 	expr = instantiate_type (TREE_TYPE (convs), expr, itf_complain);
        return expr;
      case AMBIG_CONV:
        /* Call build_user_type_conversion again for the error.  */
        return build_user_type_conversion
! 	(TREE_TYPE (convs), TREE_OPERAND (convs, 0), LOOKUP_NORMAL);
  
      default:
        break;
--- 3702,3762 ----
  
  	/* If this is a constructor or a function returning an aggr type,
  	   we need to build up a TARGET_EXPR.  */
! 	if (DECL_CONSTRUCTOR_P (convfn))
! 	  expr = build_cplus_new (totype, expr);
  
+ 	/* The result of the call is then used to direct-initialize the object
+ 	   that is the destination of the copy-initialization.  [dcl.init]
+ 
+ 	   Note that this step is not reflected in the conversion sequence;
+ 	   it affects the semantics when we actually perform the
+ 	   conversion, but is not considered during overload resolution.
+ 
+ 	   If the target is a class, that means call a ctor.  */
+ 	if (IS_AGGR_TYPE (totype))
+ 	  {
+ 	    savew = warningcount, savee = errorcount;
+ 	    expr = build_new_method_call
+ 	      (NULL_TREE, complete_ctor_identifier,
+ 	       build_tree_list (NULL_TREE, expr), TYPE_BINFO (totype),
+ 	       /* Core issue 84, now a DR, says that we don't allow UDCs
+ 		  for these args (which deliberately breaks copy-init of an
+ 		  auto_ptr<Base> from an auto_ptr<Derived>).  */
+ 	       LOOKUP_NORMAL|LOOKUP_ONLYCONVERTING|LOOKUP_NO_CONVERSION);
+ 
+ 	    /* Tell the user where this failing constructor call came from.  */
+ 	    if (fn)
+ 	      {
+ 		if (warningcount > savew)
+ 		  cp_warning
+ 		    ("  initializing argument %P of `%D' from result of `%D'",
+ 		     argnum, fn, convfn);
+ 		else if (errorcount > savee)
+ 		  cp_error
+ 		    ("  initializing argument %P of `%D' from result of `%D'",
+ 		     argnum, fn, convfn);
+ 	      }
+ 	    else
+ 	      {
+ 		if (warningcount > savew)
+ 		  cp_warning ("  initializing temporary from result of `%D'",
+ 			      convfn);
+ 		else if (errorcount > savee)
+ 		  cp_error ("  initializing temporary from result of `%D'",
+ 			    convfn);
+ 	      }
+ 	    expr = build_cplus_new (totype, expr);
+ 	  }
  	return expr;
        }
      case IDENTITY_CONV:
        if (type_unknown_p (expr))
! 	expr = instantiate_type (totype, expr, itf_complain);
        return expr;
      case AMBIG_CONV:
        /* Call build_user_type_conversion again for the error.  */
        return build_user_type_conversion
! 	(totype, TREE_OPERAND (convs, 0), LOOKUP_NORMAL);
  
      default:
        break;
*************** convert_like_real (convs, expr, fn, argn
*** 3736,3742 ****
    switch (TREE_CODE (convs))
      {
      case RVALUE_CONV:
!       if (! IS_AGGR_TYPE (TREE_TYPE (convs)))
  	return expr;
        /* else fall through */
      case BASE_CONV:
--- 3776,3782 ----
    switch (TREE_CODE (convs))
      {
      case RVALUE_CONV:
!       if (! IS_AGGR_TYPE (totype))
  	return expr;
        /* else fall through */
      case BASE_CONV:
*************** convert_like_real (convs, expr, fn, argn
*** 3744,3750 ****
  	{
  	  /* We are going to bind a reference directly to a base-class
  	     subobject of EXPR.  */
! 	  tree base_ptr = build_pointer_type (TREE_TYPE (convs));
  
  	  /* Build an expression for `*((base*) &expr)'.  */
  	  expr = build_unary_op (ADDR_EXPR, expr, 0);
--- 3784,3790 ----
  	{
  	  /* We are going to bind a reference directly to a base-class
  	     subobject of EXPR.  */
! 	  tree base_ptr = build_pointer_type (totype);
  
  	  /* Build an expression for `*((base*) &expr)'.  */
  	  expr = build_unary_op (ADDR_EXPR, expr, 0);
*************** convert_like_real (convs, expr, fn, argn
*** 3753,3787 ****
  	  return expr;
  	}
  
!       {
! 	tree cvt_expr = build_user_type_conversion
! 	  (TREE_TYPE (convs), expr, LOOKUP_NORMAL);
! 	if (!cvt_expr) 
! 	  {
! 	    /* This can occur if, for example, the EXPR has incomplete
! 	       type.  We can't check for that before attempting the
! 	       conversion because the type might be an incomplete
! 	       array type, which is OK if some constructor for the
! 	       destination type takes a pointer argument.  */
! 	    if (!COMPLETE_TYPE_P (TREE_TYPE (expr)))
! 	      {
! 		if (same_type_p (TREE_TYPE (expr), TREE_TYPE (convs)))
! 		  incomplete_type_error (expr, TREE_TYPE (expr));
! 		else
! 		  cp_error ("could not convert `%E' (with incomplete type `%T') to `%T'",
! 			    expr, TREE_TYPE (expr), TREE_TYPE (convs));
! 	      }
! 	    else
! 	      cp_error ("could not convert `%E' to `%T'",
! 			expr, TREE_TYPE (convs));
! 	    return error_mark_node;
! 	  }
! 	return cvt_expr;
!       }
  
      case REF_BIND:
        {
! 	tree ref_type = TREE_TYPE (convs);
  
  	/* If necessary, create a temporary.  */
  	if (NEED_TEMPORARY_P (convs))
--- 3793,3819 ----
  	  return expr;
  	}
  
!       /* Copy-initialization where the cv-unqualified version of the source
! 	 type is the same class as, or a derived class of, the class of the
! 	 destination [is treated as direct-initialization].  [dcl.init] */
!       if (fn)
! 	savew = warningcount, savee = errorcount;
!       expr = build_new_method_call (NULL_TREE, complete_ctor_identifier,
! 				    build_tree_list (NULL_TREE, expr),
! 				    TYPE_BINFO (totype),
! 				    LOOKUP_NORMAL|LOOKUP_ONLYCONVERTING);
!       if (fn)
! 	{
! 	  if (warningcount > savew)
! 	    cp_warning ("  initializing argument %P of `%D'", argnum, fn);
! 	  else if (errorcount > savee)
! 	    cp_error ("  initializing argument %P of `%D'", argnum, fn);
! 	}
!       return build_cplus_new (totype, expr);
  
      case REF_BIND:
        {
! 	tree ref_type = totype;
  
  	/* If necessary, create a temporary.  */
  	if (NEED_TEMPORARY_P (convs))
*************** convert_like_real (convs, expr, fn, argn
*** 3812,3824 ****
  
      case QUAL_CONV:
        /* Warn about deprecated conversion if appropriate.  */
!       string_conv_p (TREE_TYPE (convs), expr, 1);
        break;
        
      default:
        break;
      }
!   return ocp_convert (TREE_TYPE (convs), expr, CONV_IMPLICIT,
  		      LOOKUP_NORMAL|LOOKUP_NO_CONVERSION);
  }
  
--- 3844,3856 ----
  
      case QUAL_CONV:
        /* Warn about deprecated conversion if appropriate.  */
!       string_conv_p (totype, expr, 1);
        break;
        
      default:
        break;
      }
!   return ocp_convert (totype, expr, CONV_IMPLICIT,
  		      LOOKUP_NORMAL|LOOKUP_NO_CONVERSION);
  }
  
*** cvt.c.~1~	Fri Dec  8 21:17:29 2000
--- cvt.c	Fri Dec  8 21:17:34 2000
*************** ocp_convert (type, expr, convtype, flags
*** 841,847 ****
  	   with a user-defined conversion sequence, then we direct-initialize
  	   the target with the temp (see [dcl.init]).  */
  	ctor = build_user_type_conversion (type, ctor, flags);
!       if (ctor)
  	ctor = build_method_call (NULL_TREE, 
  				  complete_ctor_identifier,
  				  build_tree_list (NULL_TREE, ctor),
--- 841,847 ----
  	   with a user-defined conversion sequence, then we direct-initialize
  	   the target with the temp (see [dcl.init]).  */
  	ctor = build_user_type_conversion (type, ctor, flags);
!       else
  	ctor = build_method_call (NULL_TREE, 
  				  complete_ctor_identifier,
  				  build_tree_list (NULL_TREE, ctor),

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