PR c++/25950 (DR 391)
authorJason Merrill <jason@redhat.com>
Wed, 24 Oct 2007 03:45:37 +0000 (23:45 -0400)
committerJason Merrill <jason@gcc.gnu.org>
Wed, 24 Oct 2007 03:45:37 +0000 (23:45 -0400)
        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

gcc/cp/ChangeLog
gcc/cp/call.c
gcc/cp/cp-tree.h
gcc/testsuite/g++.dg/init/copy7.C [deleted file]
gcc/testsuite/g++.dg/overload/reftemp1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/overload/reftemp2.C [new file with mode: 0644]

index 29e5cb598826d17e84341c922a14d787d56b9671..d75316e67de451569a80fd75c04c7108bfb4ae4c 100644 (file)
@@ -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
index 6ca0a957f425f61e50ced3947f3f8be524627cf9..121092de3325697f2a91cc8b197a7b73e51348da 100644 (file)
@@ -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);
 
@@ -1249,32 +1255,6 @@ reference_binding (tree rto, tree rfrom, tree expr, bool c_cast_p, int flags)
   if (!CP_TYPE_CONST_NON_VOLATILE_P (to) && !TYPE_REF_IS_RVALUE (rto))
     return NULL;
 
-  /* [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
@@ -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;
        }
index bd9292a5565dc49884e5377b9a249bfb2e381449..c0f3bf0ea7335e99f58905fe23a51835546961f5 100644 (file)
@@ -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 (file)
index 8c23c54..0000000
+++ /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 (file)
index 0000000..89f9418
--- /dev/null
@@ -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 (file)
index 0000000..365d5b1
--- /dev/null
@@ -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;
+}