]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
call.c (merge_conversion_sequences): Set bad_p and user_conv_p on all of the second...
authorJason Merrill <jason@redhat.com>
Mon, 12 Sep 2011 18:04:55 +0000 (14:04 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Mon, 12 Sep 2011 18:04:55 +0000 (14:04 -0400)
* 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

gcc/cp/ChangeLog
gcc/cp/call.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/cpp0x/explicit7.C [new file with mode: 0644]

index 772ba51b52a5cc6e4d1cd115330fce4a375b4892..83bd7801cdcf3284d1bf70daddf6f6116c7af723 100644 (file)
@@ -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.
index d58ed135169c915ef348af052862b66349115b7e..a97e8c79417d7302ff47b05b01907c7e4f9f2108 100644 (file)
@@ -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));
index 4fa122cf0e8c5ad3096623a0420c62856a79e0f5..65bd35467997f5f3220107a13e14b00fe87ad5c3 100644 (file)
@@ -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 (file)
index 0000000..7a0b73e
--- /dev/null
@@ -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 "" }