aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2011-09-12 14:04:55 -0400
committerJason Merrill <jason@gcc.gnu.org>2011-09-12 14:04:55 -0400
commit940023f4baf01438669c2316bc0e25eb73c9cf19 (patch)
treea0b9e337e48a0e15f1a6f11de52f6930317c52a2
parent62a405ddf395d4804d18954fc6b09d90da345d39 (diff)
downloadgcc-940023f4baf01438669c2316bc0e25eb73c9cf19.zip
gcc-940023f4baf01438669c2316bc0e25eb73c9cf19.tar.gz
gcc-940023f4baf01438669c2316bc0e25eb73c9cf19.tar.bz2
call.c (merge_conversion_sequences): Set bad_p and user_conv_p on all of the second conversion sequence.
* call.c (merge_conversion_sequences): Set bad_p and user_conv_p on all of the second conversion sequence. (build_user_type_conversion_1): Set bad_p on the ck_user conv. (convert_like_real): Handle bad ck_ref_bind with user_conv_p in the first section. Fix loop logic. (initialize_reference): Call convert_like for diagnostics when we have a (bad) conversion. From-SVN: r178790
-rw-r--r--gcc/cp/ChangeLog8
-rw-r--r--gcc/cp/call.c44
-rw-r--r--gcc/testsuite/ChangeLog4
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/explicit7.C17
4 files changed, 56 insertions, 17 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 772ba51..83bd780 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,5 +1,13 @@
2011-09-12 Jason Merrill <jason@redhat.com>
+ * call.c (merge_conversion_sequences): Set bad_p and user_conv_p
+ on all of the second conversion sequence.
+ (build_user_type_conversion_1): Set bad_p on the ck_user conv.
+ (convert_like_real): Handle bad ck_ref_bind with user_conv_p in the
+ first section. Fix loop logic.
+ (initialize_reference): Call convert_like for diagnostics when
+ we have a (bad) conversion.
+
* call.c (convert_class_to_reference)
(convert_class_to_reference_1): Remove.
(reference_binding): Use build_user_type_conversion_1 instead.
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index d58ed13..a97e8c7 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -3242,21 +3242,23 @@ static conversion *
merge_conversion_sequences (conversion *user_seq, conversion *std_seq)
{
conversion **t;
+ bool bad = user_seq->bad_p;
gcc_assert (user_seq->kind == ck_user);
/* Find the end of the second conversion sequence. */
- t = &(std_seq);
- while ((*t)->kind != ck_identity)
- t = &((*t)->u.next);
+ for (t = &std_seq; (*t)->kind != ck_identity; t = &((*t)->u.next))
+ {
+ /* The entire sequence is a user-conversion sequence. */
+ (*t)->user_conv_p = true;
+ if (bad)
+ (*t)->bad_p = true;
+ }
/* Replace the identity conversion with the user conversion
sequence. */
*t = user_seq;
- /* The entire sequence is a user-conversion sequence. */
- std_seq->user_conv_p = true;
-
return std_seq;
}
@@ -3533,6 +3535,8 @@ build_user_type_conversion_1 (tree totype, tree expr, int flags)
? totype : non_reference (TREE_TYPE (TREE_TYPE (cand->fn)))),
build_identity_conv (TREE_TYPE (expr), expr));
conv->cand = cand;
+ if (cand->viable == -1)
+ conv->bad_p = true;
/* Remember that this was a list-initialization. */
if (flags & LOOKUP_NO_NARROWING)
@@ -3542,9 +3546,6 @@ build_user_type_conversion_1 (tree totype, tree expr, int flags)
cand->second_conv = merge_conversion_sequences (conv,
cand->second_conv);
- if (cand->viable == -1)
- cand->second_conv->bad_p = true;
-
return cand;
}
@@ -5529,7 +5530,8 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
&& convs->kind != ck_user
&& convs->kind != ck_list
&& convs->kind != ck_ambig
- && convs->kind != ck_ref_bind
+ && (convs->kind != ck_ref_bind
+ || convs->user_conv_p)
&& convs->kind != ck_rvalue
&& convs->kind != ck_base)
{
@@ -5542,7 +5544,7 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
&& BRACE_ENCLOSED_INITIALIZER_P (CONSTRUCTOR_ELT (expr, 0)->value))
permerror (input_location, "too many braces around initializer for %qT", totype);
- for (; t; t = convs->u.next)
+ for (; t; t = t->u.next)
{
if (t->kind == ck_user && t->cand->reason)
{
@@ -5553,7 +5555,11 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
/*issue_conversion_warnings=*/false,
/*c_cast_p=*/false,
complain);
- return cp_convert (totype, expr);
+ if (convs->kind == ck_ref_bind)
+ return convert_to_reference (totype, expr, CONV_IMPLICIT,
+ LOOKUP_NORMAL, NULL_TREE);
+ else
+ return cp_convert (totype, expr);
}
else if (t->kind == ck_user || !t->bad_p)
{
@@ -5788,9 +5794,11 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
{
tree ref_type = totype;
- if (convs->bad_p && TYPE_REF_IS_RVALUE (ref_type)
- && real_lvalue_p (expr))
+ if (convs->bad_p && !convs->u.next->bad_p)
{
+ gcc_assert (TYPE_REF_IS_RVALUE (ref_type)
+ && real_lvalue_p (expr));
+
error ("cannot bind %qT lvalue to %qT",
TREE_TYPE (expr), totype);
if (fn)
@@ -8581,9 +8589,11 @@ initialize_reference (tree type, tree expr, tree decl, tree *cleanup,
{
if (complain & tf_error)
{
- if (!CP_TYPE_CONST_P (TREE_TYPE (type))
- && !TYPE_REF_IS_RVALUE (type)
- && !real_lvalue_p (expr))
+ if (conv)
+ convert_like (conv, expr, complain);
+ else if (!CP_TYPE_CONST_P (TREE_TYPE (type))
+ && !TYPE_REF_IS_RVALUE (type)
+ && !real_lvalue_p (expr))
error ("invalid initialization of non-const reference of "
"type %qT from an rvalue of type %qT",
type, TREE_TYPE (expr));
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 4fa122c..65bd354 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,7 @@
+2011-09-12 Jason Merrill <jason@redhat.com>
+
+ * g++.dg/cpp0x/explicit7.C: New.
+
2011-09-12 Jakub Jelinek <jakub@redhat.com>
PR rtl-optimization/50212
diff --git a/gcc/testsuite/g++.dg/cpp0x/explicit7.C b/gcc/testsuite/g++.dg/cpp0x/explicit7.C
new file mode 100644
index 0000000..7a0b73e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/explicit7.C
@@ -0,0 +1,17 @@
+// [over.match.conv]: For direct-initialization, those explicit conversion
+// functions that are not hidden within S and yield type T or a type that
+// can be converted to type T with a qualification conversion (4.4) are
+// also candidate functions.
+
+// { dg-options -std=c++0x }
+
+struct A { };
+struct B: A { };
+struct C {
+ explicit operator B*(); // { dg-message "explicit" }
+ explicit operator B&(); // { dg-message "explicit" }
+};
+
+C c;
+A* ap (c); // { dg-error "" }
+A& ar (c); // { dg-error "" }