public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc/devel/gccgo] c++: Explicit constructor called in copy-initialization [PR90320]
@ 2020-07-12 17:34 Ian Lance Taylor
  0 siblings, 0 replies; only message in thread
From: Ian Lance Taylor @ 2020-07-12 17:34 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:feb801f62239528bca2cfb6c3abd70d434b69c0a

commit feb801f62239528bca2cfb6c3abd70d434b69c0a
Author: Marek Polacek <polacek@redhat.com>
Date:   Wed Apr 22 20:12:47 2020 -0400

    c++: Explicit constructor called in copy-initialization [PR90320]
    
    This test is rejected with a bogus "use of deleted function" error
    starting with r225705 whereby convert_like_real/ck_base no longer
    sets LOOKUP_ONLYCONVERTING for user_conv_p conversions.  This does
    not seem to be always correct.  To recap, when we have something like
    T t = x where T is a class type and the type of x is not T or derived
    from T, we perform copy-initialization, something like:
      1. choose a user-defined conversion to convert x to T, the result is
         a prvalue,
      2. use this prvalue to direct-initialize t.
    
    In the second step, explicit constructors should be considered, since
    we're direct-initializing.  This is what r225705 fixed.
    
    In this PR we are dealing with the first step, I think, where explicit
    constructors should be skipped.  [over.match.copy] says "The converting
    constructors of T are candidate functions" which clearly eliminates
    explicit constructors.  But we also have to copy-initialize the argument
    we are passing to such a converting constructor, and here we should
    disregard explicit constructors too.
    
    In this testcase we have
    
      V v = m;
    
    and we choose V::V(M) to convert m to V.  But we wrongly choose
    the explicit M::M<M&>(M&) to copy-initialize the argument; it's
    a better match for a non-const lvalue than the implicit M::M(const M&)
    but because it's explicit, we shouldn't use it.
    
    When convert_like is processing the ck_user conversion -- the convfn is
    V::V(M) -- it can see that cand->flags contains LOOKUP_ONLYCONVERTING,
    but then when we're in build_over_call for this convfn, we have no way
    to pass the flag to convert_like for the argument 'm', because convert_like
    doesn't take flags.  Fixed by creating a new conversion flag, copy_init_p,
    set in ck_base/ck_rvalue to signal that explicit constructors should be
    skipped.
    
    LOOKUP_COPY_PARM looks relevant, but again, it's a LOOKUP_* flag, so
    can't pass it to convert_like.  DR 899 also seemed related, but that
    deals with direct-init contexts only.
    
            PR c++/90320
            * call.c (struct conversion): Add copy_init_p.
            (standard_conversion): Set copy_init_p in ck_base and ck_rvalue
            if FLAGS demands LOOKUP_ONLYCONVERTING.
            (convert_like_real) <case ck_base>: If copy_init_p is set, or
            LOOKUP_ONLYCONVERTING into FLAGS.
    
            * g++.dg/cpp0x/explicit13.C: New test.
            * g++.dg/cpp0x/explicit14.C: New test.

Diff:
---
 gcc/cp/ChangeLog                        |  9 +++++++++
 gcc/cp/call.c                           | 26 +++++++++++++++++++++-----
 gcc/testsuite/ChangeLog                 |  6 ++++++
 gcc/testsuite/g++.dg/cpp0x/explicit13.C | 14 ++++++++++++++
 gcc/testsuite/g++.dg/cpp0x/explicit14.C | 16 ++++++++++++++++
 5 files changed, 66 insertions(+), 5 deletions(-)

diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 32408f7056b..4e0ea91883d 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,12 @@
+2020-04-22  Marek Polacek  <polacek@redhat.com>
+
+	PR c++/90320
+	* call.c (struct conversion): Add copy_init_p.
+	(standard_conversion): Set copy_init_p in ck_base and ck_rvalue
+	if FLAGS demands LOOKUP_ONLYCONVERTING.
+	(convert_like_real) <case ck_base>: If copy_init_p is set, or
+	LOOKUP_ONLYCONVERTING into FLAGS.
+
 2020-04-26  Iain Sandoe  <iain@sandoe.co.uk>
 
 	PR c++/94752
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index c58231601c9..8345997ccf9 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -92,7 +92,7 @@ struct conversion {
      language standards, e.g. disregarding pointer qualifiers or
      converting integers to pointers.  */
   BOOL_BITFIELD bad_p : 1;
-  /* If KIND is ck_ref_bind ck_base_conv, true to indicate that a
+  /* If KIND is ck_ref_bind or ck_base, true to indicate that a
      temporary should be created to hold the result of the
      conversion.  If KIND is ck_ambig or ck_user, true means force
      copy-initialization.  */
@@ -111,6 +111,10 @@ struct conversion {
   /* Whether check_narrowing should only check TREE_CONSTANTs; used
      in build_converted_constant_expr.  */
   BOOL_BITFIELD check_narrowing_const_only: 1;
+  /* True if this conversion is taking place in a copy-initialization context
+     and we should only consider converting constructors.  Only set in
+     ck_base and ck_rvalue.  */
+  BOOL_BITFIELD copy_init_p : 1;
   /* The type of the expression resulting from the conversion.  */
   tree type;
   union {
@@ -1252,6 +1256,10 @@ standard_conversion (tree to, tree from, tree expr, bool c_cast_p,
       if (flags & LOOKUP_PREFER_RVALUE)
 	/* Tell convert_like_real to set LOOKUP_PREFER_RVALUE.  */
 	conv->rvaluedness_matches_p = true;
+      /* If we're performing copy-initialization, remember to skip
+	 explicit constructors.  */
+      if (flags & LOOKUP_ONLYCONVERTING)
+	conv->copy_init_p = true;
     }
 
    /* Allow conversion between `__complex__' data types.  */
@@ -1528,6 +1536,10 @@ standard_conversion (tree to, tree from, tree expr, bool c_cast_p,
       if (flags & LOOKUP_PREFER_RVALUE)
 	/* Tell convert_like_real to set LOOKUP_PREFER_RVALUE.  */
 	conv->rvaluedness_matches_p = true;
+      /* If we're performing copy-initialization, remember to skip
+	 explicit constructors.  */
+      if (flags & LOOKUP_ONLYCONVERTING)
+	conv->copy_init_p = true;
     }
   else
     return NULL;
@@ -7653,12 +7665,16 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
 	 type is the same class as, or a derived class of, the class of the
 	 destination [is treated as direct-initialization].  [dcl.init] */
       flags = LOOKUP_NORMAL;
+      /* This conversion is being done in the context of a user-defined
+	 conversion (i.e. the second step of copy-initialization), so
+	 don't allow any more.  */
       if (convs->user_conv_p)
-	/* This conversion is being done in the context of a user-defined
-	   conversion (i.e. the second step of copy-initialization), so
-	   don't allow any more.  */
 	flags |= LOOKUP_NO_CONVERSION;
-      else
+      /* We might be performing a conversion of the argument
+	 to the user-defined conversion, i.e., not a conversion of the
+	 result of the user-defined conversion.  In which case we skip
+	 explicit constructors.  */
+      if (convs->copy_init_p)
 	flags |= LOOKUP_ONLYCONVERTING;
       if (convs->rvaluedness_matches_p)
 	/* standard_conversion got LOOKUP_PREFER_RVALUE.  */
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index d6529ea7d1f..1e3325853e1 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,9 @@
+2020-04-22  Marek Polacek  <polacek@redhat.com>
+
+	PR c++/90320
+	* g++.dg/cpp0x/explicit13.C: New test.
+	* g++.dg/cpp0x/explicit14.C: New test.
+
 2020-04-27  Iain Buclaw  <ibuclaw@gdcproject.org>
 
 	PR d/89418
diff --git a/gcc/testsuite/g++.dg/cpp0x/explicit13.C b/gcc/testsuite/g++.dg/cpp0x/explicit13.C
new file mode 100644
index 00000000000..cbd9a73d8fc
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/explicit13.C
@@ -0,0 +1,14 @@
+// PR c++/90320
+// { dg-do compile { target c++11 } }
+
+struct M {
+  M() = default;
+  template <typename T> explicit M(T&&) = delete;
+};
+
+struct V {
+  V(M m);
+};
+
+M m;
+V v = m;
diff --git a/gcc/testsuite/g++.dg/cpp0x/explicit14.C b/gcc/testsuite/g++.dg/cpp0x/explicit14.C
new file mode 100644
index 00000000000..8a8adfe1677
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/explicit14.C
@@ -0,0 +1,16 @@
+// PR c++/90320
+// { dg-do compile { target c++11 } }
+
+struct B { };
+
+struct M : B {
+  M() = default;
+  template <typename T> explicit M(T&&) = delete;
+};
+
+struct V {
+  V(B);
+};
+
+M m;
+V v = m;


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2020-07-12 17:34 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-07-12 17:34 [gcc/devel/gccgo] c++: Explicit constructor called in copy-initialization [PR90320] Ian Lance Taylor

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).