re PR c++/47080 ([C++0x] explicit conversion function return conversions not restrict...
authorJason Merrill <jason@redhat.com>
Mon, 20 Jun 2011 14:40:38 +0000 (10:40 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Mon, 20 Jun 2011 14:40:38 +0000 (10:40 -0400)
PR c++/47080
* call.c (rejection_reason_code): Add rr_explicit_conversion.
(print_z_candidate): Handle it.
(explicit_conversion_rejection): New.
(build_user_type_conversion_1): Reject an explicit conversion
function that requires more than a qualification conversion.

From-SVN: r175217

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

index 9269a759d347a8313d0de5a7708963ecde377f2a..eff4c8ee81e2bdf69aa66fbab0e9cf402e723513 100644 (file)
@@ -1,5 +1,12 @@
 2011-06-20  Jason Merrill  <jason@redhat.com>
 
+       PR c++/47080
+       * call.c (rejection_reason_code): Add rr_explicit_conversion.
+       (print_z_candidate): Handle it.
+       (explicit_conversion_rejection): New.
+       (build_user_type_conversion_1): Reject an explicit conversion
+       function that requires more than a qualification conversion.
+
        PR c++/47635
        * decl.c (grokdeclarator): Don't set ctype to an ENUMERAL_TYPE.
 
index 09d73d0c4c5a4e582099847bbc1d5bfed2a2e69d..e9d6e7ea354c6928d63aa0b1d7f5df7a104df1d0 100644 (file)
@@ -429,6 +429,7 @@ struct candidate_warning {
 enum rejection_reason_code {
   rr_none,
   rr_arity,
+  rr_explicit_conversion,
   rr_arg_conversion,
   rr_bad_arg_conversion
 };
@@ -608,6 +609,16 @@ bad_arg_conversion_rejection (tree first_arg, int n_arg, tree from, tree to)
   return r;
 }
 
+static struct rejection_reason *
+explicit_conversion_rejection (tree from, tree to)
+{
+  struct rejection_reason *r = alloc_rejection (rr_explicit_conversion);
+  r->u.conversion.n_arg = 0;
+  r->u.conversion.from_type = from;
+  r->u.conversion.to_type = to;
+  return r;
+}
+
 /* Dynamically allocate a conversion.  */
 
 static conversion *
@@ -3153,6 +3164,12 @@ print_z_candidate (const char *msgstr, struct z_candidate *candidate)
        case rr_bad_arg_conversion:
          print_conversion_rejection (loc, &r->u.bad_conversion);
          break;
+       case rr_explicit_conversion:
+         inform (loc, "  return type %qT of explicit conversion function "
+                 "cannot be converted to %qT with a qualification "
+                 "conversion", r->u.conversion.from_type,
+                 r->u.conversion.to_type);
+         break;
        case rr_none:
        default:
          /* This candidate didn't have any issues or we failed to
@@ -3429,9 +3446,10 @@ build_user_type_conversion_1 (tree totype, tree expr, int flags)
 
       for (cand = candidates; cand != old_candidates; cand = cand->next)
        {
+         tree rettype = TREE_TYPE (TREE_TYPE (cand->fn));
          conversion *ics
            = implicit_conversion (totype,
-                                  TREE_TYPE (TREE_TYPE (cand->fn)),
+                                  rettype,
                                   0,
                                   /*c_cast_p=*/false, convflags);
 
@@ -3453,14 +3471,23 @@ build_user_type_conversion_1 (tree totype, tree expr, int flags)
 
          if (!ics)
            {
-             tree rettype = TREE_TYPE (TREE_TYPE (cand->fn));
              cand->viable = 0;
              cand->reason = arg_conversion_rejection (NULL_TREE, -1,
                                                       rettype, totype);
            }
+         else if (DECL_NONCONVERTING_P (cand->fn)
+                  && ics->rank > cr_exact)
+           {
+             /* 13.3.1.5: 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.  */
+             cand->viable = -1;
+             cand->reason = explicit_conversion_rejection (rettype, totype);
+           }
          else if (cand->viable == 1 && ics->bad_p)
            {
-             tree rettype = TREE_TYPE (TREE_TYPE (cand->fn));
              cand->viable = -1;
              cand->reason
                = bad_arg_conversion_rejection (NULL_TREE, -1,
@@ -5513,7 +5540,18 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
 
       for (; t; t = convs->u.next)
        {
-         if (t->kind == ck_user || !t->bad_p)
+         if (t->kind == ck_user && t->cand->reason)
+           {
+             permerror (input_location, "invalid user-defined conversion "
+                        "from %qT to %qT", TREE_TYPE (expr), totype);
+             print_z_candidate ("candidate is:", t->cand);
+             expr = convert_like_real (t, expr, fn, argnum, 1,
+                                       /*issue_conversion_warnings=*/false,
+                                       /*c_cast_p=*/false,
+                                       complain);
+             return cp_convert (totype, expr);
+           }
+         else if (t->kind == ck_user || !t->bad_p)
            {
              expr = convert_like_real (t, expr, fn, argnum, 1,
                                        /*issue_conversion_warnings=*/false,
index 337e5f9a2f46e86e9cc5ef8442c66c7b11ea0d3c..5590283925f396bb6353f3cfa0fae4446ac6532c 100644 (file)
@@ -1,5 +1,8 @@
 2011-06-20  Jason Merrill  <jason@redhat.com>
 
+       PR c++/47080
+       * g++.dg/cpp0x/explicit6.C: New.
+
        PR c++/47635
        * g++.dg/cpp0x/enum20.C: New.
 
diff --git a/gcc/testsuite/g++.dg/cpp0x/explicit6.C b/gcc/testsuite/g++.dg/cpp0x/explicit6.C
new file mode 100644 (file)
index 0000000..0d620be
--- /dev/null
@@ -0,0 +1,11 @@
+// PR c++/47080
+// { dg-options -std=c++0x }
+
+struct A {
+  explicit operator int();     // { dg-message "qualification conversion" }
+};
+
+int main() {
+  bool b((A()));               // { dg-error "invalid user-defined" }
+  !A();                                // { dg-error "" }
+}