This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
C++ PATCH for c++/35773
- From: Jason Merrill <jason at redhat dot com>
- To: gcc-patches List <gcc-patches at gcc dot gnu dot org>
- Date: Thu, 17 Apr 2008 10:00:44 -0400
- Subject: 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);
+ }