diff options
author | Jason Merrill <jason@redhat.com> | 2007-10-23 23:45:37 -0400 |
---|---|---|
committer | Jason Merrill <jason@gcc.gnu.org> | 2007-10-23 23:45:37 -0400 |
commit | 6f4fd5362d14e6ca794b629befd60b7b3aa56a42 (patch) | |
tree | fbca0e01a3c67e9b7a3d7a0dea6fb8da66a10c03 /gcc | |
parent | d72702e2cbf5f92f41b442c0fec1e42e65730dc4 (diff) | |
download | gcc-6f4fd5362d14e6ca794b629befd60b7b3aa56a42.zip gcc-6f4fd5362d14e6ca794b629befd60b7b3aa56a42.tar.gz gcc-6f4fd5362d14e6ca794b629befd60b7b3aa56a42.tar.bz2 |
PR c++/25950 (DR 391)
PR c++/25950 (DR 391)
* call.c (struct conversion): Remove check_copy_constructor_p.
(reference_binding): Always bind a reference directly to a
compatible class rvalue. Pass down LOOKUP_NO_TEMP_BIND during
temporary creation.
(check_constructor_callable): Remove.
(convert_like_real): Don't call it.
(initialize_reference): Don't call check_constructor_callable.
(standard_conversion): Check LOOKUP_NO_CONVERSION instead of
LOOKUP_CONSTRUCTOR_CALLABLE. Don't require a temporary for base
conversions if LOOKUP_NO_TEMP_BIND.
(implicit_conversion): Pass through LOOKUP_NO_TEMP_BIND.
(build_user_type_conversion_1): Pass through LOOKUP_NO_TEMP_BIND for
second conversion.
* cp-tree.h (LOOKUP_CONSTRUCTOR_CALLABLE): Remove.
From-SVN: r129596
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/cp/ChangeLog | 18 | ||||
-rw-r--r-- | gcc/cp/call.c | 100 | ||||
-rw-r--r-- | gcc/cp/cp-tree.h | 5 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/init/copy7.C | 19 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/overload/reftemp1.C | 13 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/overload/reftemp2.C | 23 |
6 files changed, 90 insertions, 88 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 29e5cb5..d75316e 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,21 @@ +2007-10-23 Jason Merrill <jason@redhat.com> + + PR c++/25950 (DR 391) + * call.c (struct conversion): Remove check_copy_constructor_p. + (reference_binding): Always bind a reference directly to a + compatible class rvalue. Pass down LOOKUP_NO_TEMP_BIND during + temporary creation. + (check_constructor_callable): Remove. + (convert_like_real): Don't call it. + (initialize_reference): Don't call check_constructor_callable. + (standard_conversion): Check LOOKUP_NO_CONVERSION instead of + LOOKUP_CONSTRUCTOR_CALLABLE. Don't require a temporary for base + conversions if LOOKUP_NO_TEMP_BIND. + (implicit_conversion): Pass through LOOKUP_NO_TEMP_BIND. + (build_user_type_conversion_1): Pass through LOOKUP_NO_TEMP_BIND for + second conversion. + * cp-tree.h (LOOKUP_CONSTRUCTOR_CALLABLE): Remove. + 2007-10-22 Jakub Jelinek <jakub@redhat.com> PR c++/33372 diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 6ca0a95..121092d 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -89,10 +89,6 @@ struct conversion { temporary should be created to hold the result of the conversion. */ BOOL_BITFIELD need_temporary_p : 1; - /* If KIND is ck_identity or ck_base_conv, true to indicate that the - copy constructor must be accessible, even though it is not being - used. */ - BOOL_BITFIELD check_copy_constructor_p : 1; /* If KIND is ck_ptr or ck_pmem, true to indicate that a conversion from a pointer-to-derived to pointer-to-base is being performed. */ BOOL_BITFIELD base_p : 1; @@ -201,7 +197,6 @@ static conversion *merge_conversion_sequences (conversion *, conversion *); static bool magic_varargs_p (tree); typedef void (*diagnostic_fn_t) (const char *, ...) ATTRIBUTE_GCC_CXXDIAG(1,2); static tree build_temp (tree, tree, int, diagnostic_fn_t *); -static void check_constructor_callable (tree, tree); /* Returns nonzero iff the destructor name specified in NAME matches BASETYPE. NAME can take many forms... */ @@ -866,7 +861,13 @@ standard_conversion (tree to, tree from, tree expr, bool c_cast_p, else if (fcode == VECTOR_TYPE && tcode == VECTOR_TYPE && vector_types_convertible_p (from, to, false)) return build_conv (ck_std, to, conv); - else if (!(flags & LOOKUP_CONSTRUCTOR_CALLABLE) + /* A derived-to-base conversion sequence is a user-defined conversion + because it involves a constructor call, even though it has the rank of + a standard conversion, so we don't consider it if we aren't allowing + user-defined conversions. But if we're binding directly to a + reference, it's only a pointer conversion. */ + else if ((!(flags & LOOKUP_NO_CONVERSION) + || (flags & LOOKUP_NO_TEMP_BIND)) && IS_AGGR_TYPE (to) && IS_AGGR_TYPE (from) && is_properly_derived_from (from, to)) { @@ -876,8 +877,8 @@ standard_conversion (tree to, tree from, tree expr, bool c_cast_p, /* The derived-to-base conversion indicates the initialization of a parameter with base type from an object of a derived type. A temporary object is created to hold the result of - the conversion. */ - conv->need_temporary_p = true; + the conversion unless we're binding directly to a reference. */ + conv->need_temporary_p = !(flags & LOOKUP_NO_TEMP_BIND); } else return NULL; @@ -1153,14 +1154,12 @@ reference_binding (tree rto, tree rfrom, tree expr, bool c_cast_p, int flags) compatible_p = reference_compatible_p (to, from); /* Directly bind reference when target expression's type is compatible with - the reference and expression is an lvalue. In C++0x, the wording in - [8.5.3/5 dcl.init.ref] is changed to also allow direct bindings for const - and rvalue references to rvalues of compatible class type, as part of - DR391. */ + the reference and expression is an lvalue. In DR391, the wording in + [8.5.3/5 dcl.init.ref] is changed to also require direct bindings for + const and rvalue references to rvalues of compatible class type. */ if (compatible_p && (lvalue_p - || ((cxx_dialect != cxx98) - && (CP_TYPE_CONST_NON_VOLATILE_P(to) || TYPE_REF_IS_RVALUE (rto)) + || ((CP_TYPE_CONST_NON_VOLATILE_P(to) || TYPE_REF_IS_RVALUE (rto)) && CLASS_TYPE_P (from)))) { /* [dcl.init.ref] @@ -1171,7 +1170,14 @@ reference_binding (tree rto, tree rfrom, tree expr, bool c_cast_p, int flags) is reference-compatible with "cv2 T2," the reference is bound directly to the initializer expression - lvalue. */ + lvalue. + + [...] + If the initializer expression is an rvalue, with T2 a class type, + and "cv1 T1" is reference-compatible with "cv2 T2", the reference + is bound to the object represented by the rvalue or to a sub-object + within that object. */ + conv = build_identity_conv (from, expr); conv = direct_reference_binding (rto, conv); @@ -1251,32 +1257,6 @@ reference_binding (tree rto, tree rfrom, tree expr, bool c_cast_p, int flags) /* [dcl.init.ref] - If the initializer expression is an rvalue, with T2 a class type, - and "cv1 T1" is reference-compatible with "cv2 T2", the reference - is bound in one of the following ways: - - -- The reference is bound to the object represented by the rvalue - or to a sub-object within that object. - - -- ... - - We use the first alternative. The implicit conversion sequence - is supposed to be same as we would obtain by generating a - temporary. Fortunately, if the types are reference compatible, - then this is either an identity conversion or the derived-to-base - conversion, just as for direct binding. */ - if (CLASS_TYPE_P (from) && compatible_p) - { - conv = build_identity_conv (from, expr); - conv = direct_reference_binding (rto, conv); - conv->rvaluedness_matches_p = TYPE_REF_IS_RVALUE (rto); - if (!(flags & LOOKUP_CONSTRUCTOR_CALLABLE)) - conv->u.next->check_copy_constructor_p = true; - return conv; - } - - /* [dcl.init.ref] - Otherwise, a temporary of type "cv1 T1" is created and initialized from the initializer expression using the rules for a non-reference copy initialization. If T1 is reference-related to @@ -1285,6 +1265,11 @@ reference_binding (tree rto, tree rfrom, tree expr, bool c_cast_p, int flags) if (related_p && !at_least_as_qualified_p (to, from)) return NULL; + /* We're generating a temporary now, but don't bind any more in the + conversion (specifically, don't slice the temporary returned by a + conversion operator). */ + flags |= LOOKUP_NO_TEMP_BIND; + conv = implicit_conversion (to, from, expr, c_cast_p, flags); if (!conv) @@ -1329,9 +1314,10 @@ implicit_conversion (tree to, tree from, tree expr, bool c_cast_p, && (flags & LOOKUP_NO_CONVERSION) == 0) { struct z_candidate *cand; + int convflags = ((flags & LOOKUP_NO_TEMP_BIND) + |LOOKUP_ONLYCONVERTING); - cand = build_user_type_conversion_1 - (to, expr, LOOKUP_ONLYCONVERTING); + cand = build_user_type_conversion_1 (to, expr, convflags); if (cand) conv = cand->second_conv; @@ -2590,6 +2576,7 @@ build_user_type_conversion_1 (tree totype, tree expr, int flags) conversion *conv = NULL; tree args = NULL_TREE; bool any_viable_p; + int convflags; /* We represent conversion within a hierarchy using RVALUE_CONV and BASE_CONV, as specified by [over.best.ics]; these become plain @@ -2620,6 +2607,11 @@ build_user_type_conversion_1 (tree totype, tree expr, int flags) candidates = 0; flags |= LOOKUP_NO_CONVERSION; + /* It's OK to bind a temporary for converting constructor arguments, but + not in converting the return value of a conversion operator. */ + convflags = ((flags & LOOKUP_NO_TEMP_BIND) | LOOKUP_NO_CONVERSION); + flags &= ~LOOKUP_NO_TEMP_BIND; + if (ctors) { tree t; @@ -2664,7 +2656,6 @@ build_user_type_conversion_1 (tree totype, tree expr, int flags) { tree fns; tree conversion_path = TREE_PURPOSE (conv_fns); - int convflags = LOOKUP_NO_CONVERSION; /* 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 @@ -4270,21 +4261,6 @@ enforce_access (tree basetype_path, tree decl, tree diag_decl) return true; } -/* Check that a callable constructor to initialize a temporary of - TYPE from an EXPR exists. */ - -static void -check_constructor_callable (tree type, tree expr) -{ - build_special_member_call (NULL_TREE, - complete_ctor_identifier, - build_tree_list (NULL_TREE, expr), - type, - LOOKUP_NORMAL | LOOKUP_ONLYCONVERTING - | LOOKUP_NO_CONVERSION - | LOOKUP_CONSTRUCTOR_CALLABLE); -} - /* Initialize a temporary of type TYPE with EXPR. The FLAGS are a bitwise or of LOOKUP_* values. If any errors are warnings are generated, set *DIAGNOSTIC_FN to "error" or "warning", @@ -4442,8 +4418,6 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum, leave it as an lvalue. */ if (inner >= 0) expr = decl_constant_value (expr); - if (convs->check_copy_constructor_p) - check_constructor_callable (totype, expr); return expr; case ck_ambig: /* Call build_user_type_conversion again for the error. */ @@ -4473,8 +4447,6 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum, { /* We are going to bind a reference directly to a base-class subobject of EXPR. */ - if (convs->check_copy_constructor_p) - check_constructor_callable (TREE_TYPE (expr), expr); /* Build an expression for `*((base*) &expr)'. */ expr = build_unary_op (ADDR_EXPR, expr, 0); expr = convert_to_base (expr, build_pointer_type (totype), @@ -6796,8 +6768,6 @@ initialize_reference (tree type, tree expr, tree decl, tree *cleanup) remember that the conversion was required. */ if (conv->kind == ck_base) { - if (conv->check_copy_constructor_p) - check_constructor_callable (TREE_TYPE (expr), expr); base_conv_type = conv->type; conv = conv->u.next; } diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index bd9292a..c0f3bf0 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -3699,13 +3699,10 @@ enum overload_flags { NO_SPECIAL = 0, DTOR_FLAG, OP_FLAG, TYPENAME_FLAG }; #define LOOKUP_PREFER_NAMESPACES (1 << 9) /* Accept types or namespaces. */ #define LOOKUP_PREFER_BOTH (LOOKUP_PREFER_TYPES | LOOKUP_PREFER_NAMESPACES) -/* We are checking that a constructor can be called -- but we do not - actually plan to call it. */ -#define LOOKUP_CONSTRUCTOR_CALLABLE (1 << 10) /* Return friend declarations and un-declared builtin functions. (Normally, these entities are registered in the symbol table, but not found by lookup.) */ -#define LOOKUP_HIDDEN (LOOKUP_CONSTRUCTOR_CALLABLE << 1) +#define LOOKUP_HIDDEN (LOOKUP_PREFER_NAMESPACES << 1) /* Prefer that the lvalue be treated as an rvalue. */ #define LOOKUP_PREFER_RVALUE (LOOKUP_HIDDEN << 1) diff --git a/gcc/testsuite/g++.dg/init/copy7.C b/gcc/testsuite/g++.dg/init/copy7.C deleted file mode 100644 index 8c23c54..0000000 --- a/gcc/testsuite/g++.dg/init/copy7.C +++ /dev/null @@ -1,19 +0,0 @@ -// { dg-options "-std=c++98" } -// PR c++/12226 - -class foo { -private: - foo(const foo &); // { dg-error "" } -public: - foo(); -}; -const foo &bar = foo(); // { dg-error "" } - -class derived : public foo { -private: - derived(const derived&); // { dg-error "" } -public: - derived(); -}; - -const foo& baz = derived(); // { dg-error "" } diff --git a/gcc/testsuite/g++.dg/overload/reftemp1.C b/gcc/testsuite/g++.dg/overload/reftemp1.C new file mode 100644 index 0000000..89f9418 --- /dev/null +++ b/gcc/testsuite/g++.dg/overload/reftemp1.C @@ -0,0 +1,13 @@ +// PR c++/25950 + +struct X { + X(); + explicit X(const X&); +}; + +void g(const X&); + +int main() +{ + g(X()); +} diff --git a/gcc/testsuite/g++.dg/overload/reftemp2.C b/gcc/testsuite/g++.dg/overload/reftemp2.C new file mode 100644 index 0000000..365d5b1 --- /dev/null +++ b/gcc/testsuite/g++.dg/overload/reftemp2.C @@ -0,0 +1,23 @@ +// DR 391 says that we always bind a reference to the base subobject; it is +// incorrect to call the A copy constructor to initialize the parameter of +// f. + +int fail; + +struct A { + A() { } + A(const A&) { fail = 1; } +}; +struct B : public A { }; +struct X { + operator B() { return B(); } +}; +X x; + +void f (const A&) { } + +int main() +{ + f(x); + return fail; +} |