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 for c++/35773


This turns out to have been a wrong-code bug before that we just hadn't noticed yet: before 4.3, for the call to f we do

operator auto_ptr&
auto_ptr(auto_ptr&)
operator auto_ptr_ref
auto_ptr(auto_ptr_ref)

Which is invalid. My previous patch caused us to (correctly) refuse to call the operator auto_ptr_ref in order to satisfy the auto_ptr_ref constructor. But we shouldn't be calling a constructor twice in the first place. This turns out to have been caused by us first doing a build_temp as part of the user-defined conversion, and then again for an rvalue conversion added because the initial conversion op returns a reference.

Fixed by always representing the second step of class copy-initialization with an rvalue conversion, rather than when we expand a user-defined conversion.

Tested x86_64-pc-linux-gnu, applied to trunk and 4.3.

2008-04-17  Jason Merrill  <jason@redhat.com>

	PR c++/35773
	* cp/call.c (build_user_type_conversion_1): Represent second step of 
	copy-init with an rvalue conversion.
	(convert_like_real) [ck_user]: Don't implicitly add it here.
	* g++.dg/overload/autoptr1.C: New.

Index: cp/call.c
===================================================================
*** cp/call.c	(revision 134397)
--- cp/call.c	(working copy)
*************** build_user_type_conversion_1 (tree totyp
*** 2634,2640 ****
  				       flags);
  
        if (cand)
! 	cand->second_conv = build_identity_conv (totype, NULL_TREE);
      }
  
    if (conv_fns)
--- 2634,2655 ----
  				       flags);
  
        if (cand)
! 	{
! 	  cand->second_conv = build_identity_conv (totype, NULL_TREE);
! 
! 	  /* If totype isn't a reference, and LOOKUP_NO_TEMP_BIND isn't
! 	     set, then this is copy-initialization.  In that case, "The
! 	     result of the call is then used to direct-initialize the
! 	     object that is the destination of the copy-initialization."
! 	     [dcl.init]
! 
! 	     We represent this in the conversion sequence with an
! 	     rvalue conversion, which means a constructor call.  */
! 	  if (TREE_CODE (totype) != REFERENCE_TYPE
! 	      && !(convflags & LOOKUP_NO_TEMP_BIND))
! 	    cand->second_conv
! 	      = build_conv (ck_rvalue, totype, cand->second_conv);
! 	}
      }
  
    if (conv_fns)
*************** build_user_type_conversion_1 (tree totyp
*** 2686,2691 ****
--- 2701,2720 ----
  				       0,
  				       /*c_cast_p=*/false, convflags);
  
+ 	      /* If LOOKUP_NO_TEMP_BIND isn't set, then this is
+ 		 copy-initialization.  In that case, "The result of the
+ 		 call is then used to direct-initialize the object that is
+ 		 the destination of the copy-initialization."  [dcl.init]
+ 
+ 		 We represent this in the conversion sequence with an
+ 		 rvalue conversion, which means a constructor call.  But
+ 		 don't add a second rvalue conversion if there's already
+ 		 one there.  Which there really shouldn't be, but it's
+ 		 harmless since we'd add it here anyway. */
+ 	      if (ics && MAYBE_CLASS_TYPE_P (totype) && ics->kind != ck_rvalue
+ 		  && !(convflags & LOOKUP_NO_TEMP_BIND))
+ 		ics = build_conv (ck_rvalue, totype, ics);
+ 
  	      cand->second_conv = ics;
  
  	      if (!ics)
*************** convert_like_real (conversion *convs, tr
*** 4425,4462 ****
  	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 (MAYBE_CLASS_TYPE_P (totype)
- 	    && (inner >= 0 || !lvalue_p (expr)))
- 	  {
- 	    expr = (build_temp
- 		    (expr, 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,
- 		     &diagnostic_fn));
- 
- 	    if (diagnostic_fn && (complain & tf_error))
- 	      {
- 		if (fn)
- 		  diagnostic_fn
- 		    ("  initializing argument %P of %qD from result of %qD",
- 		     argnum, fn, convfn);
- 		else
- 		 diagnostic_fn
- 		   ("  initializing temporary from result of %qD",  convfn);
- 	      }
- 	    expr = build_cplus_new (totype, expr);
- 	  }
  	return expr;
        }
      case ck_identity:
--- 4454,4459 ----
*************** convert_like_real (conversion *convs, tr
*** 4518,4524 ****
        flags = LOOKUP_NORMAL|LOOKUP_ONLYCONVERTING;
        if (convs->user_conv_p)
  	/* This conversion is being done in the context of a user-defined
! 	   conversion, so don't allow any more.  */
  	flags |= LOOKUP_NO_CONVERSION;
        expr = build_temp (expr, totype, flags, &diagnostic_fn);
        if (diagnostic_fn && fn)
--- 4515,4522 ----
        flags = LOOKUP_NORMAL|LOOKUP_ONLYCONVERTING;
        if (convs->user_conv_p)
  	/* This conversion is being done in the context of a user-defined
! 	   conversion (i.e. the second step of copy-initialization), so
! 	   don't allow any more.  */
  	flags |= LOOKUP_NO_CONVERSION;
        expr = build_temp (expr, totype, flags, &diagnostic_fn);
        if (diagnostic_fn && fn)
Index: testsuite/g++.dg/overload/autoptr1.C
===================================================================
*** testsuite/g++.dg/overload/autoptr1.C	(revision 0)
--- testsuite/g++.dg/overload/autoptr1.C	(revision 0)
***************
*** 0 ****
--- 1,29 ----
+ // PR c++/35773
+ 
+ template< typename T >
+ class auto_ptr
+ {
+   struct auto_ptr_ref { };
+ public:
+   auto_ptr(auto_ptr&);
+   auto_ptr(auto_ptr_ref);
+ 
+   operator auto_ptr_ref();
+ };
+ 
+ template< typename T >
+ class reference_wrapper
+ {
+ public:
+   reference_wrapper(T& t);
+   operator T& () const;
+ };
+ 
+ struct X { };
+ 
+ void f(auto_ptr< X >);
+ 
+ void g(reference_wrapper< auto_ptr< X > > r)
+ {
+   f(r);
+ }

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