aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2007-10-23 23:45:37 -0400
committerJason Merrill <jason@gcc.gnu.org>2007-10-23 23:45:37 -0400
commit6f4fd5362d14e6ca794b629befd60b7b3aa56a42 (patch)
treefbca0e01a3c67e9b7a3d7a0dea6fb8da66a10c03 /gcc
parentd72702e2cbf5f92f41b442c0fec1e42e65730dc4 (diff)
downloadgcc-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/ChangeLog18
-rw-r--r--gcc/cp/call.c100
-rw-r--r--gcc/cp/cp-tree.h5
-rw-r--r--gcc/testsuite/g++.dg/init/copy7.C19
-rw-r--r--gcc/testsuite/g++.dg/overload/reftemp1.C13
-rw-r--r--gcc/testsuite/g++.dg/overload/reftemp2.C23
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;
+}