Implement explicit conversions ops as specified in N2437.
authorJason Merrill <jason@redhat.com>
Mon, 18 May 2009 21:48:02 +0000 (17:48 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Mon, 18 May 2009 21:48:02 +0000 (17:48 -0400)
* decl.c (grokdeclarator): Handle explicit conversion ops.
(check_initializer): Pass flags to store_init_value.
* decl2.c (maybe_emit_vtables): Likewise.
* init.c (expand_aggr_init_1): Likewise.
* call.c (convert_class_to_reference): Take flags parm,
check DECL_NONCONVERTING_P.
(build_user_type_conversion_1): Check DECL_NONCONVERTING_P.
(add_builtin_candidates): Simplify getting type of conversion.
(build_object_call): Likewise.  Check DECL_NONCONVERTING_P.
(implicit_conversion): Pass through LOOKUP_ONLYCONVERTING.
(reference_binding): Take flags parm.  Direct-initialize copy parm.
(add_function_candidate): Direct-initialize the copy parm.
(add_conv_candidate): Use LOOKUP_IMPLICIT, not LOOKUP_NORMAL.
(build_builtin_candidate): Add LOOKUP_ONLYCONVERTING.
(conditional_conversion): Likewise.
(convert_like_real): Only complain about DECL_NONCONVERTING_P
constructors.
(perform_implicit_conversion_flags): Add flags parm to
perform_implicit_conversion.  Improve diagnostics.
* cp-tree.h (LOOKUP_IMPLICIT): New macro.
(LOOKUP_COPY_PARM): New bit macro.
* cvt.c (build_expr_type_conversion): Check DECL_NONCONVERTING_P.
* typeck.c (convert_for_assignment): Take flags parm, pass it to
perform_implicit_conversion_flags.
(cp_build_modify_expr): Pass flags to convert_for_assignment.
(convert_for_initialization): Likewise.
* typeck2.c (store_init_value): Take flags parm, pass to
digest_init_flags.
(digest_init_flags): Add flags parm to digest_init.
(digest_init_r): Take flags parm, pass to convert_for_initialization.
(process_init_constructor_array): Pass it.
(process_init_constructor_record): Likewise.
(process_init_constructor_union): Likewise.

From-SVN: r147677

12 files changed:
gcc/cp/ChangeLog
gcc/cp/call.c
gcc/cp/cp-tree.h
gcc/cp/cvt.c
gcc/cp/decl.c
gcc/cp/decl2.c
gcc/cp/init.c
gcc/cp/typeck.c
gcc/cp/typeck2.c
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/cpp0x/explicit1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp0x/explicit2.C [new file with mode: 0644]

index af4b69ca718307086eac47f8b0ac6b052b8c966d..813413e767d3e79d95886c284949e27fcab7c541 100644 (file)
@@ -1,3 +1,40 @@
+2009-05-18  Jason Merrill  <jason@redhat.com>
+
+       Implement explicit conversions ops as specified in N2437.
+       * decl.c (grokdeclarator): Handle explicit conversion ops.
+       (check_initializer): Pass flags to store_init_value.
+       * decl2.c (maybe_emit_vtables): Likewise.
+       * init.c (expand_aggr_init_1): Likewise.
+       * call.c (convert_class_to_reference): Take flags parm,
+       check DECL_NONCONVERTING_P.
+       (build_user_type_conversion_1): Check DECL_NONCONVERTING_P.
+       (add_builtin_candidates): Simplify getting type of conversion.
+       (build_object_call): Likewise.  Check DECL_NONCONVERTING_P.
+       (implicit_conversion): Pass through LOOKUP_ONLYCONVERTING.
+       (reference_binding): Take flags parm.  Direct-initialize copy parm.
+       (add_function_candidate): Direct-initialize the copy parm.
+       (add_conv_candidate): Use LOOKUP_IMPLICIT, not LOOKUP_NORMAL.
+       (build_builtin_candidate): Add LOOKUP_ONLYCONVERTING.
+       (conditional_conversion): Likewise.
+       (convert_like_real): Only complain about DECL_NONCONVERTING_P
+       constructors.
+       (perform_implicit_conversion_flags): Add flags parm to
+       perform_implicit_conversion.  Improve diagnostics.
+       * cp-tree.h (LOOKUP_IMPLICIT): New macro.
+       (LOOKUP_COPY_PARM): New bit macro.
+       * cvt.c (build_expr_type_conversion): Check DECL_NONCONVERTING_P.
+       * typeck.c (convert_for_assignment): Take flags parm, pass it to
+       perform_implicit_conversion_flags.
+       (cp_build_modify_expr): Pass flags to convert_for_assignment.
+       (convert_for_initialization): Likewise.
+       * typeck2.c (store_init_value): Take flags parm, pass to
+       digest_init_flags.
+       (digest_init_flags): Add flags parm to digest_init.
+       (digest_init_r): Take flags parm, pass to convert_for_initialization.
+       (process_init_constructor_array): Pass it.
+       (process_init_constructor_record): Likewise.
+       (process_init_constructor_union): Likewise.
+
 2009-05-16  Jason Merrill  <jason@redhat.com>
 
        PR c++/40139
index 607e3edc4f5acab9c1b9dcf38def5b5047452207..b33e9036b4d7980409ad68b3042539c7255657ef 100644 (file)
@@ -190,7 +190,7 @@ static tree source_type (conversion *);
 static void add_warning (struct z_candidate *, struct z_candidate *);
 static bool reference_related_p (tree, tree);
 static bool reference_compatible_p (tree, tree);
-static conversion *convert_class_to_reference (tree, tree, tree);
+static conversion *convert_class_to_reference (tree, tree, tree, int);
 static conversion *direct_reference_binding (tree, conversion *);
 static bool promoted_arithmetic_type_p (tree);
 static conversion *conditional_conversion (tree, tree);
@@ -993,7 +993,7 @@ reference_compatible_p (tree t1, tree t2)
    converted to T as in [over.match.ref].  */
 
 static conversion *
-convert_class_to_reference (tree reference_type, tree s, tree expr)
+convert_class_to_reference (tree reference_type, tree s, tree expr, int flags)
 {
   tree conversions;
   tree arglist;
@@ -1034,7 +1034,7 @@ convert_class_to_reference (tree reference_type, tree s, tree expr)
 
   t = TREE_TYPE (reference_type);
 
-  while (conversions)
+  for (; conversions; conversions = TREE_CHAIN (conversions))
     {
       tree fns = TREE_VALUE (conversions);
 
@@ -1043,6 +1043,10 @@ convert_class_to_reference (tree reference_type, tree s, tree expr)
          tree f = OVL_CURRENT (fns);
          tree t2 = TREE_TYPE (TREE_TYPE (f));
 
+         if (DECL_NONCONVERTING_P (f)
+             && (flags & LOOKUP_ONLYCONVERTING))
+           continue;
+
          cand = NULL;
 
          /* If this is a template function, try to get an exact
@@ -1101,7 +1105,6 @@ convert_class_to_reference (tree reference_type, tree s, tree expr)
              cand->second_conv->bad_p |= cand->convs[0]->bad_p;
            }
        }
-      conversions = TREE_CHAIN (conversions);
     }
 
   candidates = splice_viable (candidates, pedantic, &any_viable_p);
@@ -1303,7 +1306,7 @@ reference_binding (tree rto, tree rfrom, tree expr, bool c_cast_p, int flags)
 
        the reference is bound to the lvalue result of the conversion
        in the second case.  */
-      conv = convert_class_to_reference (rto, from, expr);
+      conv = convert_class_to_reference (rto, from, expr, flags);
       if (conv)
        return conv;
     }
@@ -1347,6 +1350,12 @@ reference_binding (tree rto, tree rfrom, tree expr, bool c_cast_p, int flags)
      conversion operator).  */
   flags |= LOOKUP_NO_TEMP_BIND;
 
+  /* Temporaries are copy-initialized, except for this hack to allow
+     explicit conversion ops to the copy ctor.  See also
+     add_function_candidate.  */
+  if (!(flags & LOOKUP_COPY_PARM))
+    flags |= LOOKUP_ONLYCONVERTING;
+
   conv = implicit_conversion (to, from, expr, c_cast_p,
                              flags);
   if (!conv)
@@ -1394,8 +1403,7 @@ 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);
+      int convflags = (flags & (LOOKUP_NO_TEMP_BIND|LOOKUP_ONLYCONVERTING));
 
       if (CLASS_TYPE_P (to)
          && !CLASSTYPE_NON_AGGREGATE (complete_type (to))
@@ -1547,9 +1555,17 @@ add_function_candidate (struct z_candidate **candidates,
              parmtype = build_pointer_type (parmtype);
            }
 
-         if ((flags & LOOKUP_NO_COPY_CTOR_CONVERSION)
-             && ctype && i == 0 && DECL_COPY_CONSTRUCTOR_P (fn))
-           lflags |= LOOKUP_NO_CONVERSION;
+         if (ctype && i == 0 && DECL_COPY_CONSTRUCTOR_P (fn))
+           {
+             /* Hack: Direct-initialize copy parm (i.e. suppress
+                LOOKUP_ONLYCONVERTING) to make explicit conversion ops
+                work.  See also reference_binding.  */
+             lflags |= LOOKUP_COPY_PARM;
+             if (flags & LOOKUP_NO_COPY_CTOR_CONVERSION)
+               lflags |= LOOKUP_NO_CONVERSION;
+           }
+         else
+           lflags |= LOOKUP_ONLYCONVERTING;
 
          t = implicit_conversion (parmtype, argtype, arg,
                                   /*c_cast_p=*/false, lflags);
@@ -1612,7 +1628,7 @@ add_conv_candidate (struct z_candidate **candidates, tree fn, tree obj,
   parmnode = parmlist;
   argnode = arglist;
   viable = 1;
-  flags = LOOKUP_NORMAL;
+  flags = LOOKUP_IMPLICIT;
 
   /* Don't bother looking up the same type twice.  */
   if (*candidates && (*candidates)->fn == totype)
@@ -1679,6 +1695,7 @@ build_builtin_candidate (struct z_candidate **candidates, tree fnname,
 
   num_convs =  args[2] ? 3 : (args[1] ? 2 : 1);
   convs = alloc_conversions (num_convs);
+  flags |= LOOKUP_ONLYCONVERTING;
 
   for (i = 0; i < 2; ++i)
     {
@@ -2268,7 +2285,7 @@ add_builtin_candidates (struct z_candidate **candidates, enum tree_code code,
 
          for (; convs; convs = TREE_CHAIN (convs))
            {
-             type = TREE_TYPE (TREE_TYPE (OVL_CURRENT (TREE_VALUE (convs))));
+             type = TREE_TYPE (convs);
 
              if (i == 0 && ref1
                  && (TREE_CODE (type) != REFERENCE_TYPE
@@ -2785,6 +2802,10 @@ build_user_type_conversion_1 (tree totype, tree expr, int flags)
        {
          tree fn = OVL_CURRENT (fns);
 
+         if (DECL_NONCONVERTING_P (fn)
+             && (flags & LOOKUP_ONLYCONVERTING))
+           continue;
+
          /* [over.match.funcs] For conversion functions, the function
             is considered to be a member of the class of the implicit
             object argument for the purpose of defining the type of
@@ -3214,7 +3235,7 @@ build_object_call (tree obj, tree args, tsubst_flags_t complain)
   for (; convs; convs = TREE_CHAIN (convs))
     {
       tree fns = TREE_VALUE (convs);
-      tree totype = TREE_TYPE (TREE_TYPE (OVL_CURRENT (fns)));
+      tree totype = TREE_TYPE (convs);
 
       if ((TREE_CODE (totype) == POINTER_TYPE
           && TREE_CODE (TREE_TYPE (totype)) == FUNCTION_TYPE)
@@ -3226,6 +3247,10 @@ build_object_call (tree obj, tree args, tsubst_flags_t complain)
        for (; fns; fns = OVL_NEXT (fns))
          {
            tree fn = OVL_CURRENT (fns);
+
+           if (DECL_NONCONVERTING_P (fn))
+             continue;
+
            if (TREE_CODE (fn) == TEMPLATE_DECL)
              add_template_conv_candidate
                (&candidates, fn, obj, args, totype,
@@ -3348,7 +3373,7 @@ conditional_conversion (tree e1, tree e2)
                                  t1,
                                  e1,
                                  /*c_cast_p=*/false,
-                                 LOOKUP_NO_TEMP_BIND);
+                                 LOOKUP_NO_TEMP_BIND|LOOKUP_ONLYCONVERTING);
       if (conv)
        return conv;
     }
@@ -3386,7 +3411,7 @@ conditional_conversion (tree e1, tree e2)
        converted to the type that expression E2 would have if E2 were
        converted to an rvalue (or the type it has, if E2 is an rvalue).  */
     return implicit_conversion (t2, t1, e1, /*c_cast_p=*/false,
-                               LOOKUP_NORMAL);
+                               LOOKUP_IMPLICIT);
 }
 
 /* Implement [expr.cond].  ARG1, ARG2, and ARG3 are the three
@@ -4584,7 +4609,7 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
 
        /* When converting from an init list we consider explicit
           constructors, but actually trying to call one is an error.  */
-       if (DECL_NONCONVERTING_P (convfn))
+       if (DECL_NONCONVERTING_P (convfn) && DECL_CONSTRUCTOR_P (convfn))
          {
            if (complain & tf_error)
              error ("converting to %qT from initializer list would use "
@@ -7025,7 +7050,7 @@ can_convert_arg_bad (tree to, tree from, tree arg)
    doing a bad conversion, convert_like will complain.  */
 
 tree
-perform_implicit_conversion (tree type, tree expr, tsubst_flags_t complain)
+perform_implicit_conversion_flags (tree type, tree expr, tsubst_flags_t complain, int flags)
 {
   conversion *conv;
   void *p;
@@ -7038,11 +7063,21 @@ perform_implicit_conversion (tree type, tree expr, tsubst_flags_t complain)
 
   conv = implicit_conversion (type, TREE_TYPE (expr), expr,
                              /*c_cast_p=*/false,
-                             LOOKUP_NORMAL);
+                             flags);
+
   if (!conv)
     {
       if (complain & tf_error)
-       error ("could not convert %qE to %qT", expr, type);
+       {
+         /* If expr has unknown type, then it is an overloaded function.
+            Call instantiate_type to get good error messages.  */
+         if (TREE_TYPE (expr) == unknown_type_node)
+           instantiate_type (type, expr, complain);
+         else if (invalid_nonstatic_memfn_p (expr, complain))
+           /* We gave an error.  */;
+         else
+           error ("could not convert %qE to %qT", expr, type);
+       }
       expr = error_mark_node;
     }
   else if (processing_template_decl)
@@ -7062,6 +7097,12 @@ perform_implicit_conversion (tree type, tree expr, tsubst_flags_t complain)
   return expr;
 }
 
+tree
+perform_implicit_conversion (tree type, tree expr, tsubst_flags_t complain)
+{
+  return perform_implicit_conversion_flags (type, expr, complain, LOOKUP_IMPLICIT);
+}
+
 /* Convert EXPR to TYPE (as a direct-initialization) if that is
    permitted.  If the conversion is valid, the converted expression is
    returned.  Otherwise, NULL_TREE is returned, except in the case
index e6545f650f0f09917c6ac7b0ba673455b59bc2ba..3dfd482f3c93fc1a15110ded20d5f05b2ccd0e94 100644 (file)
@@ -1963,8 +1963,8 @@ struct GTY(()) lang_decl {
    is mutable.  */
 #define DECL_MUTABLE_P(NODE) (DECL_LANG_FLAG_0 (NODE))
 
-/* Nonzero for _DECL means that this constructor is a non-converting
-   constructor.  */
+/* Nonzero for _DECL means that this constructor or conversion function is
+   non-converting.  */
 #define DECL_NONCONVERTING_P(NODE) \
   (DECL_LANG_SPECIFIC (NODE)->decl_flags.nonconverting)
 
@@ -3758,8 +3758,10 @@ enum overload_flags { NO_SPECIAL = 0, DTOR_FLAG, OP_FLAG, TYPENAME_FLAG };
 /* Even if the function found by lookup is a virtual function, it
    should be called directly.  */
 #define LOOKUP_NONVIRTUAL (1 << 2)
-/* Non-converting (i.e., "explicit") constructors are not tried.  */
+/* Non-converting (i.e., "explicit") constructors are not tried.  This flag
+   indicates that we are not performing direct-initialization.  */
 #define LOOKUP_ONLYCONVERTING (1 << 3)
+#define LOOKUP_IMPLICIT (LOOKUP_NORMAL | LOOKUP_ONLYCONVERTING)
 /* If a temporary is created, it should be created so that it lives
    as long as the current variable bindings; otherwise it only lives
    until the end of the complete-expression.  It also forces
@@ -3793,6 +3795,8 @@ enum overload_flags { NO_SPECIAL = 0, DTOR_FLAG, OP_FLAG, TYPENAME_FLAG };
 /* Avoid user-defined conversions for the first parameter of a copy
    constructor.  */
 #define LOOKUP_NO_COPY_CTOR_CONVERSION (LOOKUP_NO_NARROWING << 1)
+/* This is the first parameter of a copy constructor.  */
+#define LOOKUP_COPY_PARM (LOOKUP_NO_COPY_CTOR_CONVERSION << 1)
 
 #define LOOKUP_NAMESPACES_ONLY(F)  \
   (((F) & LOOKUP_PREFER_NAMESPACES) && !((F) & LOOKUP_PREFER_TYPES))
@@ -4200,6 +4204,7 @@ extern tree initialize_reference          (tree, tree, tree, tree *);
 extern tree make_temporary_var_for_ref_to_temp (tree, tree);
 extern tree strip_top_quals                    (tree);
 extern tree perform_implicit_conversion                (tree, tree, tsubst_flags_t);
+extern tree perform_implicit_conversion_flags  (tree, tree, tsubst_flags_t, int);
 extern tree perform_direct_initialization_if_possible (tree, tree, bool,
                                                        tsubst_flags_t);
 extern tree in_charge_arg_for_name             (tree);
@@ -5001,9 +5006,10 @@ extern void readonly_error                       (tree, const char *);
 extern void complete_type_check_abstract       (tree);
 extern int abstract_virtuals_error             (tree, tree);
 
-extern tree store_init_value                   (tree, tree);
+extern tree store_init_value                   (tree, tree, int);
 extern void check_narrowing                    (tree, tree);
 extern tree digest_init                                (tree, tree);
+extern tree digest_init_flags                  (tree, tree, int);
 extern tree build_scoped_ref                   (tree, tree, tree *);
 extern tree build_x_arrow                      (tree);
 extern tree build_m_component_ref              (tree, tree);
index c86fbdfe0da0cc7da8d4ac1e1bd8995bed33893f..3fdebd7f155e10f8068a1c297dddda601618ee3a 100644 (file)
@@ -1181,6 +1181,9 @@ build_expr_type_conversion (int desires, tree expr, bool complain)
       if (winner && winner == cand)
        continue;
 
+      if (DECL_NONCONVERTING_P (cand))
+       continue;
+
       candidate = non_reference (TREE_TYPE (TREE_TYPE (cand)));
 
       switch (TREE_CODE (candidate))
index ed76dc397e49d99bda8f9bf45988c70583a41fbb..e9ff87bcec996f0a49a072721ec316a62b95238d 100644 (file)
@@ -5176,7 +5176,7 @@ check_initializer (tree decl, tree init, int flags, tree *cleanup)
        return build_aggr_init_full_exprs (decl, init, flags);
       else if (TREE_CODE (init) != TREE_VEC)
        {
-         init_code = store_init_value (decl, init);
+         init_code = store_init_value (decl, init, flags);
          if (pedantic && TREE_CODE (type) == ARRAY_TYPE
              && DECL_INITIAL (decl)
              && TREE_CODE (DECL_INITIAL (decl)) == STRING_CST
@@ -8413,6 +8413,14 @@ grokdeclarator (const cp_declarator *declarator,
                         "class definition",
                         name);
              }
+           else if (ctype && sfk == sfk_conversion)
+             {
+               if (explicitp == 1)
+                 {
+                   maybe_warn_cpp0x ("explicit conversion operators");
+                   explicitp = 2;
+                 }
+             }
 
            arg_types = grokparms (declarator->u.function.parameters,
                                   &parms);
index 1f8e848bf2ebd6692ff88734065b76554e118a99..0e050dd0cf86aa1e8b113e3a25ce45b84a20f6c0 100644 (file)
@@ -1764,7 +1764,7 @@ maybe_emit_vtables (tree ctype)
 
       if (TREE_TYPE (DECL_INITIAL (vtbl)) == 0)
        {
-         tree expr = store_init_value (vtbl, DECL_INITIAL (vtbl));
+         tree expr = store_init_value (vtbl, DECL_INITIAL (vtbl), LOOKUP_NORMAL);
 
          /* It had better be all done at compile-time.  */
          gcc_assert (!expr);
index d40a5e7e53fd344d274ce7602b36b3391b830a70..5fa5eb84b27bf010790667e2cb8937f7898c893f 100644 (file)
@@ -1387,7 +1387,7 @@ expand_aggr_init_1 (tree binfo, tree true_exp, tree exp, tree init, int flags,
       /* If store_init_value returns NULL_TREE, the INIT has been
         recorded as the DECL_INITIAL for EXP.  That means there's
         nothing more we have to do.  */
-      init = store_init_value (exp, init);
+      init = store_init_value (exp, init, flags);
       if (init)
        finish_expr_stmt (init);
       return;
index 069a057004406e2984ac3f355ec259b54ad51c19..66472ee96ebfb5f1d3528952172da98b3c0e660c 100644 (file)
@@ -48,7 +48,7 @@ along with GCC; see the file COPYING3.  If not see
 static tree pfn_from_ptrmemfunc (tree);
 static tree delta_from_ptrmemfunc (tree);
 static tree convert_for_assignment (tree, tree, const char *, tree, int,
-                                   tsubst_flags_t);
+                                   tsubst_flags_t, int);
 static tree cp_pointer_int_sum (enum tree_code, tree, tree);
 static tree rationalize_conditional_expr (enum tree_code, tree, 
                                          tsubst_flags_t);
@@ -6157,12 +6157,14 @@ cp_build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs,
     }
 
   if (modifycode == INIT_EXPR)
+    /* Calls with INIT_EXPR are all direct-initialization, so don't set
+       LOOKUP_ONLYCONVERTING.  */
     newrhs = convert_for_initialization (lhs, olhstype, newrhs, LOOKUP_NORMAL,
                                         "initialization", NULL_TREE, 0,
                                          complain);
   else
     newrhs = convert_for_assignment (olhstype, newrhs, "assignment",
-                                    NULL_TREE, 0, complain);
+                                    NULL_TREE, 0, complain, LOOKUP_IMPLICIT);
 
   if (!same_type_p (lhstype, olhstype))
     newrhs = cp_convert_and_check (lhstype, newrhs);
@@ -6568,7 +6570,7 @@ delta_from_ptrmemfunc (tree t)
 static tree
 convert_for_assignment (tree type, tree rhs,
                        const char *errtype, tree fndecl, int parmnum,
-                       tsubst_flags_t complain)
+                       tsubst_flags_t complain, int flags)
 {
   tree rhstype;
   enum tree_code coder;
@@ -6689,7 +6691,8 @@ convert_for_assignment (tree type, tree rhs,
       TREE_NO_WARNING (rhs) = 1;
     }
 
-  return perform_implicit_conversion (strip_top_quals (type), rhs, complain);
+  return perform_implicit_conversion_flags (strip_top_quals (type), rhs,
+                                           complain, flags);
 }
 
 /* Convert RHS to be of type TYPE.
@@ -6780,7 +6783,7 @@ convert_for_initialization (tree exp, tree type, tree rhs, int flags,
     return ocp_convert (type, rhs, CONV_IMPLICIT|CONV_FORCE_TEMP, flags);
 
   return convert_for_assignment (type, rhs, errtype, fndecl, parmnum,
-                                complain);
+                                complain, flags);
 }
 \f
 /* If RETVAL is the address of, or a reference to, a local variable or
index 5ed7818732f19aa0b4e83927a5e8d16e6d7ab564..5783f6781b1f82317d66469021d610887f8745e4 100644 (file)
@@ -586,7 +586,7 @@ split_nonconstant_init (tree dest, tree init)
    for static variable.  In that case, caller must emit the code.  */
 
 tree
-store_init_value (tree decl, tree init)
+store_init_value (tree decl, tree init, int flags)
 {
   tree value, type;
 
@@ -628,7 +628,7 @@ store_init_value (tree decl, tree init)
   /* End of special C++ code.  */
 
   /* Digest the specified initializer into an expression.  */
-  value = digest_init (type, init);
+  value = digest_init_flags (type, init, flags);
   /* If the initializer is not a constant, fill in DECL_INITIAL with
      the bits that are constant, and then return an expression that
      will perform the dynamic initialization.  */
@@ -717,7 +717,7 @@ check_narrowing (tree type, tree init)
    NESTED is true iff we are being called for an element of a CONSTRUCTOR.  */
 
 static tree
-digest_init_r (tree type, tree init, bool nested)
+digest_init_r (tree type, tree init, bool nested, int flags)
 {
   enum tree_code code = TREE_CODE (type);
 
@@ -796,9 +796,9 @@ digest_init_r (tree type, tree init, bool nested)
 
       if (cxx_dialect != cxx98 && nested)
        check_narrowing (type, init);
-      init = convert_for_initialization (0, type, init, LOOKUP_NORMAL,
+      init = convert_for_initialization (0, type, init, flags,
                                         "initialization", NULL_TREE, 0,
-                                         tf_warning_or_error);
+                                        tf_warning_or_error);
       exp = &init;
 
       /* Skip any conversions since we'll be outputting the underlying
@@ -842,7 +842,7 @@ digest_init_r (tree type, tree init, bool nested)
        }
 
       return convert_for_initialization (NULL_TREE, type, init,
-                                        LOOKUP_NORMAL | LOOKUP_ONLYCONVERTING,
+                                        flags,
                                         "initialization", NULL_TREE, 0,
                                          tf_warning_or_error);
     }
@@ -851,7 +851,13 @@ digest_init_r (tree type, tree init, bool nested)
 tree
 digest_init (tree type, tree init)
 {
-  return digest_init_r (type, init, false);
+  return digest_init_r (type, init, false, LOOKUP_IMPLICIT);
+}
+
+tree
+digest_init_flags (tree type, tree init, int flags)
+{
+  return digest_init_r (type, init, false, flags);
 }
 \f
 /* Set of flags used within process_init_constructor to describe the
@@ -924,7 +930,7 @@ process_init_constructor_array (tree type, tree init)
       else
        ce->index = size_int (i);
       gcc_assert (ce->value);
-      ce->value = digest_init_r (TREE_TYPE (type), ce->value, true);
+      ce->value = digest_init_r (TREE_TYPE (type), ce->value, true, LOOKUP_IMPLICIT);
 
       if (ce->value != error_mark_node)
        gcc_assert (same_type_ignoring_top_level_qualifiers_p
@@ -1031,7 +1037,7 @@ process_init_constructor_record (tree type, tree init)
            }
 
          gcc_assert (ce->value);
-         next = digest_init_r (type, ce->value, true);
+         next = digest_init_r (type, ce->value, true, LOOKUP_IMPLICIT);
          ++idx;
        }
       else if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (field)))
@@ -1046,7 +1052,7 @@ process_init_constructor_record (tree type, tree init)
          else
            next = build_constructor (init_list_type_node, NULL);
 
-         next = digest_init_r (TREE_TYPE (field), next, true);
+         next = digest_init_r (TREE_TYPE (field), next, true, LOOKUP_IMPLICIT);
 
          /* Warn when some struct elements are implicitly initialized.  */
          warning (OPT_Wmissing_field_initializers,
@@ -1156,7 +1162,7 @@ process_init_constructor_union (tree type, tree init)
     }
 
   if (ce->value && ce->value != error_mark_node)
-    ce->value = digest_init_r (TREE_TYPE (ce->index), ce->value, true);
+    ce->value = digest_init_r (TREE_TYPE (ce->index), ce->value, true, LOOKUP_IMPLICIT);
 
   return picflag_from_initializer (ce->value);
 }
index 1e1c805fa2161d31ae33a3760b75fe1ed2d5f2e1..34a7a2d0a4a19525fa0e43a0df6e64264e84a8f7 100644 (file)
@@ -1,3 +1,8 @@
+2009-05-18  Jason Merrill  <jason@redhat.com>
+
+       * g++.dg/cpp0x/explicit1.C: New.
+       * g++.dg/cpp0x/explicit2.C: New.
+
 2009-05-18  Dodji Seketeli  <dodji@redhat.com>
 
        PR debug/40109
diff --git a/gcc/testsuite/g++.dg/cpp0x/explicit1.C b/gcc/testsuite/g++.dg/cpp0x/explicit1.C
new file mode 100644 (file)
index 0000000..fe164fc
--- /dev/null
@@ -0,0 +1,58 @@
+// Test for explicit conversion ops from N2437.
+// { dg-options "-std=c++0x" }
+
+class U; class V;
+class T
+{
+public:
+  T( U const & );
+  //implicit converting ctor
+  explicit T( V const & );
+  // explicit ctor
+};
+class U
+{
+};
+class V
+{
+};
+class W
+{
+public:
+  operator T() const;
+};
+class X
+{
+public:
+  explicit operator T() const; // theoretical
+};
+int main()
+{
+  U u; V v; W w; X x;
+  // Direct initialization:
+  T t1( u );
+  T t2( v );
+  T t3( w );
+  T t4( x );
+  // Copy initialization:
+  T t5 = u;
+  T t6 = v;                    // { dg-error "" }
+  T t7 = w;
+  T t8 = x;                    // { dg-error "" }
+  // Cast notation:
+  T t9 = (T) u;
+  T t10 = (T) v;
+  T t11 = (T) w;
+  T t12 = (T) x;
+  // Static cast:
+  T t13 = static_cast<T>( u );
+  T t14 = static_cast<T>( v );
+  T t15 = static_cast<T>( w );
+  T t16 = static_cast<T>( x );
+  // Function-style cast:
+  T t17 = T( u );
+  T t18 = T( v );
+  T t19 = T( w );
+  T t20 = T( x );
+  return 0;
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/explicit2.C b/gcc/testsuite/g++.dg/cpp0x/explicit2.C
new file mode 100644 (file)
index 0000000..c2327c1
--- /dev/null
@@ -0,0 +1,29 @@
+// Test for explicit conversion ops in various conversion situations.
+// { dg-options "-std=c++0x" }
+
+typedef void (*pfn)();
+
+struct A
+{
+  explicit operator int() const;
+  explicit operator pfn() const;
+};
+
+int main()
+{
+  A a;
+  int i = a;                   // { dg-error "" }
+  const int &ir = a;           // { dg-error "" }
+  a();                         // { dg-error "" }
+  a + 1;                       // { dg-message "" } (error and note on same line)
+
+  int j (a);
+  (int)a;
+  static_cast<int>(a);
+}
+
+struct B
+{
+  int i;
+  B(const A& a): i(a) { }
+};