public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [wwwdocs] porting_to: Two-stage overload resolution for implicit move removed
@ 2022-10-12 19:38 Marek Polacek
  2022-10-12 20:50 ` Jonathan Wakely
  0 siblings, 1 reply; 5+ messages in thread
From: Marek Polacek @ 2022-10-12 19:38 UTC (permalink / raw)
  To: GCC Patches; +Cc: Jason Merrill, Jonathan Wakely

As I promised in
<https://gcc.gnu.org/pipermail/gcc-patches/2022-October/603189.html>,
I'd like to update our GCC 13 porting_to.html with the following note.

Does this look OK to commit?  Thanks,

diff --git a/htdocs/gcc-13/porting_to.html b/htdocs/gcc-13/porting_to.html
index 84a00f21..243ed29d 100644
--- a/htdocs/gcc-13/porting_to.html
+++ b/htdocs/gcc-13/porting_to.html
@@ -42,5 +42,57 @@ be included explicitly when compiled with GCC 13:
 </li>
 </ul>
 
+<h3 id="two-stage-or">Two-stage overload resolution for implicit move removed</h3>
+<p>
+GCC 13 removed the two-stage overload resolution when performing
+implicit move, whereby the compiler does two separate overload resolutions:
+one treating the operand as an rvalue, and then (if that resolution fails)
+another one treating the operand as an lvalue.  In the standard this was
+introduced in C++11 and implemented in gcc in
+<a href="https://gcc.gnu.org/git/?p=gcc.git;a=commitdiff;h=4ce8c5dea53d80736b9c0ba6faa7430ed65ed365">
+r251035</a>.  In
+<a href="https://gcc.gnu.org/git/?p=gcc.git;a=commitdiff;h=1722e2013f05f1f1f99379dbaa0c0df356da731f">
+r11-2412</a>, the fallback overload resolution was disabled in C++20 (but
+not in C++17).  Then C++23 <a href="https://wg21.link/p2266">P2266</a>
+removed the fallback overload resolution, and changed the implicit move
+rules once again.
+</p>
+<p>
+The two overload resolutions approach was complicated and quirky, so users
+should transition to the newer model.  This change means that code that
+previously didn't compile in C++17 will now compile, for example:</p>
+
+<pre><code>
+   struct S1 { S1(S1 &&); };
+   struct S2 : S1 {};
+
+   S1
+   f (S2 s)
+   {
+     return s; // OK, derived-to-base, use S1::S1(S1&&)
+   }
+</code></pre>
+
+<p>
+And conversely, code that used to work in C++17 may not compile anymore:
+</p>
+
+<pre><code>
+   struct W {
+     W();
+   };
+
+   struct F {
+     F(W&);
+     F(W&&) = delete;
+   };
+
+   F fn ()
+   {
+     W w;
+     return w; // use w as rvalue -> use of deleted function F::F(W&&)
+   }
+</code></pre>
+
 </body>
 </html>


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [wwwdocs] porting_to: Two-stage overload resolution for implicit move removed
  2022-10-12 19:38 [wwwdocs] porting_to: Two-stage overload resolution for implicit move removed Marek Polacek
@ 2022-10-12 20:50 ` Jonathan Wakely
  2022-10-12 22:24   ` Marek Polacek
  0 siblings, 1 reply; 5+ messages in thread
From: Jonathan Wakely @ 2022-10-12 20:50 UTC (permalink / raw)
  To: Marek Polacek; +Cc: GCC Patches, Jason Merrill

On Wed, 12 Oct 2022 at 20:39, Marek Polacek <polacek@redhat.com> wrote:
>
> As I promised in
> <https://gcc.gnu.org/pipermail/gcc-patches/2022-October/603189.html>,
> I'd like to update our GCC 13 porting_to.html with the following note.
>
> Does this look OK to commit?  Thanks,
>
> diff --git a/htdocs/gcc-13/porting_to.html b/htdocs/gcc-13/porting_to.html
> index 84a00f21..243ed29d 100644
> --- a/htdocs/gcc-13/porting_to.html
> +++ b/htdocs/gcc-13/porting_to.html
> @@ -42,5 +42,57 @@ be included explicitly when compiled with GCC 13:
>  </li>
>  </ul>
>
> +<h3 id="two-stage-or">Two-stage overload resolution for implicit move removed</h3>
> +<p>
> +GCC 13 removed the two-stage overload resolution when performing
> +implicit move, whereby the compiler does two separate overload resolutions:
> +one treating the operand as an rvalue, and then (if that resolution fails)
> +another one treating the operand as an lvalue.  In the standard this was
> +introduced in C++11 and implemented in gcc in
> +<a href="https://gcc.gnu.org/git/?p=gcc.git;a=commitdiff;h=4ce8c5dea53d80736b9c0ba6faa7430ed65ed365">
> +r251035</a>.  In
> +<a href="https://gcc.gnu.org/git/?p=gcc.git;a=commitdiff;h=1722e2013f05f1f1f99379dbaa0c0df356da731f">
> +r11-2412</a>, the fallback overload resolution was disabled in C++20 (but
> +not in C++17).  Then C++23 <a href="https://wg21.link/p2266">P2266</a>
> +removed the fallback overload resolution, and changed the implicit move
> +rules once again.
> +</p>
> +<p>
> +The two overload resolutions approach was complicated and quirky, so users
> +should transition to the newer model.  This change means that code that
> +previously didn't compile in C++17 will now compile, for example:</p>
> +
> +<pre><code>
> +   struct S1 { S1(S1 &&); };
> +   struct S2 : S1 {};
> +
> +   S1
> +   f (S2 s)
> +   {
> +     return s; // OK, derived-to-base, use S1::S1(S1&&)
> +   }
> +</code></pre>
> +
> +<p>
> +And conversely, code that used to work in C++17 may not compile anymore:
> +</p>
> +
> +<pre><code>
> +   struct W {
> +     W();
> +   };
> +
> +   struct F {
> +     F(W&);
> +     F(W&&) = delete;
> +   };
> +
> +   F fn ()
> +   {
> +     W w;
> +     return w; // use w as rvalue -> use of deleted function F::F(W&&)

Deleted move constructors are an abomination, and should never occur
in real code. I'm not sure using one even in an example like this
should be encouraged. The example added by P2266 to Annex D is more
realistic (and actually broke a libstdc++ test):

X& foo(X&& x) { return x; }



> +   }
> +</code></pre>
> +
>  </body>
>  </html>
>


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [wwwdocs] porting_to: Two-stage overload resolution for implicit move removed
  2022-10-12 20:50 ` Jonathan Wakely
@ 2022-10-12 22:24   ` Marek Polacek
  2022-10-12 22:38     ` Jonathan Wakely
  0 siblings, 1 reply; 5+ messages in thread
From: Marek Polacek @ 2022-10-12 22:24 UTC (permalink / raw)
  To: Jonathan Wakely; +Cc: GCC Patches, Jason Merrill

On Wed, Oct 12, 2022 at 09:50:36PM +0100, Jonathan Wakely wrote:
> On Wed, 12 Oct 2022 at 20:39, Marek Polacek <polacek@redhat.com> wrote:
> >
> > As I promised in
> > <https://gcc.gnu.org/pipermail/gcc-patches/2022-October/603189.html>,
> > I'd like to update our GCC 13 porting_to.html with the following note.
> >
> > Does this look OK to commit?  Thanks,
> >
> > diff --git a/htdocs/gcc-13/porting_to.html b/htdocs/gcc-13/porting_to.html
> > index 84a00f21..243ed29d 100644
> > --- a/htdocs/gcc-13/porting_to.html
> > +++ b/htdocs/gcc-13/porting_to.html
> > @@ -42,5 +42,57 @@ be included explicitly when compiled with GCC 13:
> >  </li>
> >  </ul>
> >
> > +<h3 id="two-stage-or">Two-stage overload resolution for implicit move removed</h3>
> > +<p>
> > +GCC 13 removed the two-stage overload resolution when performing
> > +implicit move, whereby the compiler does two separate overload resolutions:
> > +one treating the operand as an rvalue, and then (if that resolution fails)
> > +another one treating the operand as an lvalue.  In the standard this was
> > +introduced in C++11 and implemented in gcc in
> > +<a href="https://gcc.gnu.org/git/?p=gcc.git;a=commitdiff;h=4ce8c5dea53d80736b9c0ba6faa7430ed65ed365">
> > +r251035</a>.  In
> > +<a href="https://gcc.gnu.org/git/?p=gcc.git;a=commitdiff;h=1722e2013f05f1f1f99379dbaa0c0df356da731f">
> > +r11-2412</a>, the fallback overload resolution was disabled in C++20 (but
> > +not in C++17).  Then C++23 <a href="https://wg21.link/p2266">P2266</a>
> > +removed the fallback overload resolution, and changed the implicit move
> > +rules once again.
> > +</p>
> > +<p>
> > +The two overload resolutions approach was complicated and quirky, so users
> > +should transition to the newer model.  This change means that code that
> > +previously didn't compile in C++17 will now compile, for example:</p>
> > +
> > +<pre><code>
> > +   struct S1 { S1(S1 &&); };
> > +   struct S2 : S1 {};
> > +
> > +   S1
> > +   f (S2 s)
> > +   {
> > +     return s; // OK, derived-to-base, use S1::S1(S1&&)
> > +   }
> > +</code></pre>
> > +
> > +<p>
> > +And conversely, code that used to work in C++17 may not compile anymore:
> > +</p>
> > +
> > +<pre><code>
> > +   struct W {
> > +     W();
> > +   };
> > +
> > +   struct F {
> > +     F(W&);
> > +     F(W&&) = delete;
> > +   };
> > +
> > +   F fn ()
> > +   {
> > +     W w;
> > +     return w; // use w as rvalue -> use of deleted function F::F(W&&)
> 
> Deleted move constructors are an abomination, and should never occur
> in real code. I'm not sure using one even in an example like this
> should be encouraged. The example added by P2266 to Annex D is more
> realistic (and actually broke a libstdc++ test):
> 
> X& foo(X&& x) { return x; }

Right, but this code still compiles in C++17, it only fails to compile
in C++23.  The previous example now doesn't compile even in C++17.  So
how about this improved patch which makes it clear that code with
deleted move constructors should never occur in practice, and adds a new
note, specifically about P2266 and the code you showed?

Thanks for taking a look,

diff --git a/htdocs/gcc-13/porting_to.html b/htdocs/gcc-13/porting_to.html
index 84a00f21..a9991e8b 100644
--- a/htdocs/gcc-13/porting_to.html
+++ b/htdocs/gcc-13/porting_to.html
@@ -42,5 +42,71 @@ be included explicitly when compiled with GCC 13:
 </li>
 </ul>
 
+<h3 id="P2266">Implicit move rules change</h3>
+<p>
+GCC 13 implements C++23 <a href="https://wg21.link/p2266">P2266</a> which
+simplified the rules for implicit move.  As a consequence, valid C++20
+code that relies on a returned <em>id-expression</em>'s being an lvalue
+may change behavior or fail to compile in C++23.  For example:</p>
+
+<pre><code>
+   decltype(auto) f(int&& x) { return (x); }  // returns int&&; previously returned int&
+   int& g(int&& x) { return x; }  // ill-formed; previously well-formed
+</code></pre>
+
+<h3 id="two-stage-or">Two-stage overload resolution for implicit move removed</h3>
+<p>GCC 13 removed the two-stage overload resolution when performing
+implicit move, whereby the compiler does two separate overload resolutions:
+one treating the operand as an rvalue, and then (if that resolution fails)
+another one treating the operand as an lvalue.  In the standard this was
+introduced in C++11 and implemented in gcc in
+<a href="https://gcc.gnu.org/git/?p=gcc.git;a=commitdiff;h=4ce8c5dea53d80736b9c0ba6faa7430ed65ed365">
+r251035</a>.  In
+<a href="https://gcc.gnu.org/git/?p=gcc.git;a=commitdiff;h=1722e2013f05f1f1f99379dbaa0c0df356da731f">
+r11-2412</a>, the fallback overload resolution was disabled in C++20 (but
+not in C++17).  Then C++23 <a href="https://wg21.link/p2266">P2266</a>
+removed the fallback overload resolution, and changed the implicit move
+rules once again.</p>
+
+<p>The two overload resolutions approach was complicated and quirky, so users
+should transition to the newer model.  This change means that code that
+previously didn't compile in C++17 will now compile, for example:</p>
+
+<pre><code>
+   struct S1 { S1(S1 &&); };
+   struct S2 : S1 {};
+
+   S1
+   f (S2 s)
+   {
+     return s; // OK, derived-to-base, use S1::S1(S1&&)
+   }
+</code></pre>
+
+<p>Conversely, code that used to work in C++17 may not compile anymore.
+For example, the following example used to compile in C++11...17 because
+we performed two separate overload resolutions: one treating the operand
+as an rvalue, and then (if that resolution failed) another one treating
+the operand as an lvalue.<br>
+<strong>NB:</strong> this example is contrived because deleted move
+constructors should not occur in real code.</p>
+
+<pre><code>
+   struct W {
+     W();
+   };
+
+   struct F {
+     F(W&);
+     F(W&&) = delete;
+   };
+
+   F fn ()
+   {
+     W w;
+     return w; // use w as rvalue -> use of deleted function F::F(W&&)
+   }
+</code></pre>
+
 </body>
 </html>


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [wwwdocs] porting_to: Two-stage overload resolution for implicit move removed
  2022-10-12 22:24   ` Marek Polacek
@ 2022-10-12 22:38     ` Jonathan Wakely
  2022-10-12 22:44       ` Marek Polacek
  0 siblings, 1 reply; 5+ messages in thread
From: Jonathan Wakely @ 2022-10-12 22:38 UTC (permalink / raw)
  To: Marek Polacek; +Cc: GCC Patches, Jason Merrill

On Wed, 12 Oct 2022 at 23:24, Marek Polacek <polacek@redhat.com> wrote:
>
> On Wed, Oct 12, 2022 at 09:50:36PM +0100, Jonathan Wakely wrote:
> > On Wed, 12 Oct 2022 at 20:39, Marek Polacek <polacek@redhat.com> wrote:
> > >
> > > As I promised in
> > > <https://gcc.gnu.org/pipermail/gcc-patches/2022-October/603189.html>,
> > > I'd like to update our GCC 13 porting_to.html with the following note.
> > >
> > > Does this look OK to commit?  Thanks,
> > >
> > > diff --git a/htdocs/gcc-13/porting_to.html b/htdocs/gcc-13/porting_to.html
> > > index 84a00f21..243ed29d 100644
> > > --- a/htdocs/gcc-13/porting_to.html
> > > +++ b/htdocs/gcc-13/porting_to.html
> > > @@ -42,5 +42,57 @@ be included explicitly when compiled with GCC 13:
> > >  </li>
> > >  </ul>
> > >
> > > +<h3 id="two-stage-or">Two-stage overload resolution for implicit move removed</h3>
> > > +<p>
> > > +GCC 13 removed the two-stage overload resolution when performing
> > > +implicit move, whereby the compiler does two separate overload resolutions:
> > > +one treating the operand as an rvalue, and then (if that resolution fails)
> > > +another one treating the operand as an lvalue.  In the standard this was
> > > +introduced in C++11 and implemented in gcc in
> > > +<a href="https://gcc.gnu.org/git/?p=gcc.git;a=commitdiff;h=4ce8c5dea53d80736b9c0ba6faa7430ed65ed365">
> > > +r251035</a>.  In
> > > +<a href="https://gcc.gnu.org/git/?p=gcc.git;a=commitdiff;h=1722e2013f05f1f1f99379dbaa0c0df356da731f">
> > > +r11-2412</a>, the fallback overload resolution was disabled in C++20 (but
> > > +not in C++17).  Then C++23 <a href="https://wg21.link/p2266">P2266</a>
> > > +removed the fallback overload resolution, and changed the implicit move
> > > +rules once again.
> > > +</p>
> > > +<p>
> > > +The two overload resolutions approach was complicated and quirky, so users
> > > +should transition to the newer model.  This change means that code that
> > > +previously didn't compile in C++17 will now compile, for example:</p>
> > > +
> > > +<pre><code>
> > > +   struct S1 { S1(S1 &&); };
> > > +   struct S2 : S1 {};
> > > +
> > > +   S1
> > > +   f (S2 s)
> > > +   {
> > > +     return s; // OK, derived-to-base, use S1::S1(S1&&)
> > > +   }
> > > +</code></pre>
> > > +
> > > +<p>
> > > +And conversely, code that used to work in C++17 may not compile anymore:
> > > +</p>
> > > +
> > > +<pre><code>
> > > +   struct W {
> > > +     W();
> > > +   };
> > > +
> > > +   struct F {
> > > +     F(W&);
> > > +     F(W&&) = delete;
> > > +   };
> > > +
> > > +   F fn ()
> > > +   {
> > > +     W w;
> > > +     return w; // use w as rvalue -> use of deleted function F::F(W&&)
> >
> > Deleted move constructors are an abomination, and should never occur
> > in real code. I'm not sure using one even in an example like this
> > should be encouraged. The example added by P2266 to Annex D is more
> > realistic (and actually broke a libstdc++ test):
> >
> > X& foo(X&& x) { return x; }
>
> Right, but this code still compiles in C++17, it only fails to compile
> in C++23.  The previous example now doesn't compile even in C++17.  So
> how about this improved patch which makes it clear that code with
> deleted move constructors should never occur in practice, and adds a new
> note, specifically about P2266 and the code you showed?

Doh, I've just realised that F(W&&) isn't a move ctor at all. For some
reason I read the example as F(F&&).

I think your original example is fine, and the note would just be
confusing (because it's not a deleted move ctor!)


>
> Thanks for taking a look,
>
> diff --git a/htdocs/gcc-13/porting_to.html b/htdocs/gcc-13/porting_to.html
> index 84a00f21..a9991e8b 100644
> --- a/htdocs/gcc-13/porting_to.html
> +++ b/htdocs/gcc-13/porting_to.html
> @@ -42,5 +42,71 @@ be included explicitly when compiled with GCC 13:
>  </li>
>  </ul>
>
> +<h3 id="P2266">Implicit move rules change</h3>
> +<p>
> +GCC 13 implements C++23 <a href="https://wg21.link/p2266">P2266</a> which
> +simplified the rules for implicit move.  As a consequence, valid C++20
> +code that relies on a returned <em>id-expression</em>'s being an lvalue
> +may change behavior or fail to compile in C++23.  For example:</p>
> +
> +<pre><code>
> +   decltype(auto) f(int&& x) { return (x); }  // returns int&&; previously returned int&
> +   int& g(int&& x) { return x; }  // ill-formed; previously well-formed
> +</code></pre>
> +
> +<h3 id="two-stage-or">Two-stage overload resolution for implicit move removed</h3>
> +<p>GCC 13 removed the two-stage overload resolution when performing
> +implicit move, whereby the compiler does two separate overload resolutions:
> +one treating the operand as an rvalue, and then (if that resolution fails)
> +another one treating the operand as an lvalue.  In the standard this was
> +introduced in C++11 and implemented in gcc in
> +<a href="https://gcc.gnu.org/git/?p=gcc.git;a=commitdiff;h=4ce8c5dea53d80736b9c0ba6faa7430ed65ed365">
> +r251035</a>.  In
> +<a href="https://gcc.gnu.org/git/?p=gcc.git;a=commitdiff;h=1722e2013f05f1f1f99379dbaa0c0df356da731f">
> +r11-2412</a>, the fallback overload resolution was disabled in C++20 (but
> +not in C++17).  Then C++23 <a href="https://wg21.link/p2266">P2266</a>
> +removed the fallback overload resolution, and changed the implicit move
> +rules once again.</p>
> +
> +<p>The two overload resolutions approach was complicated and quirky, so users
> +should transition to the newer model.  This change means that code that
> +previously didn't compile in C++17 will now compile, for example:</p>
> +
> +<pre><code>
> +   struct S1 { S1(S1 &&); };
> +   struct S2 : S1 {};
> +
> +   S1
> +   f (S2 s)
> +   {
> +     return s; // OK, derived-to-base, use S1::S1(S1&&)
> +   }
> +</code></pre>
> +
> +<p>Conversely, code that used to work in C++17 may not compile anymore.
> +For example, the following example used to compile in C++11...17 because
> +we performed two separate overload resolutions: one treating the operand
> +as an rvalue, and then (if that resolution failed) another one treating
> +the operand as an lvalue.<br>
> +<strong>NB:</strong> this example is contrived because deleted move
> +constructors should not occur in real code.</p>
> +
> +<pre><code>
> +   struct W {
> +     W();
> +   };
> +
> +   struct F {
> +     F(W&);
> +     F(W&&) = delete;
> +   };
> +
> +   F fn ()
> +   {
> +     W w;
> +     return w; // use w as rvalue -> use of deleted function F::F(W&&)
> +   }
> +</code></pre>
> +
>  </body>
>  </html>
>


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [wwwdocs] porting_to: Two-stage overload resolution for implicit move removed
  2022-10-12 22:38     ` Jonathan Wakely
@ 2022-10-12 22:44       ` Marek Polacek
  0 siblings, 0 replies; 5+ messages in thread
From: Marek Polacek @ 2022-10-12 22:44 UTC (permalink / raw)
  To: Jonathan Wakely; +Cc: GCC Patches, Jason Merrill

On Wed, Oct 12, 2022 at 11:38:01PM +0100, Jonathan Wakely wrote:
> On Wed, 12 Oct 2022 at 23:24, Marek Polacek <polacek@redhat.com> wrote:
> >
> > On Wed, Oct 12, 2022 at 09:50:36PM +0100, Jonathan Wakely wrote:
> > > On Wed, 12 Oct 2022 at 20:39, Marek Polacek <polacek@redhat.com> wrote:
> > > >
> > > > As I promised in
> > > > <https://gcc.gnu.org/pipermail/gcc-patches/2022-October/603189.html>,
> > > > I'd like to update our GCC 13 porting_to.html with the following note.
> > > >
> > > > Does this look OK to commit?  Thanks,
> > > >
> > > > diff --git a/htdocs/gcc-13/porting_to.html b/htdocs/gcc-13/porting_to.html
> > > > index 84a00f21..243ed29d 100644
> > > > --- a/htdocs/gcc-13/porting_to.html
> > > > +++ b/htdocs/gcc-13/porting_to.html
> > > > @@ -42,5 +42,57 @@ be included explicitly when compiled with GCC 13:
> > > >  </li>
> > > >  </ul>
> > > >
> > > > +<h3 id="two-stage-or">Two-stage overload resolution for implicit move removed</h3>
> > > > +<p>
> > > > +GCC 13 removed the two-stage overload resolution when performing
> > > > +implicit move, whereby the compiler does two separate overload resolutions:
> > > > +one treating the operand as an rvalue, and then (if that resolution fails)
> > > > +another one treating the operand as an lvalue.  In the standard this was
> > > > +introduced in C++11 and implemented in gcc in
> > > > +<a href="https://gcc.gnu.org/git/?p=gcc.git;a=commitdiff;h=4ce8c5dea53d80736b9c0ba6faa7430ed65ed365">
> > > > +r251035</a>.  In
> > > > +<a href="https://gcc.gnu.org/git/?p=gcc.git;a=commitdiff;h=1722e2013f05f1f1f99379dbaa0c0df356da731f">
> > > > +r11-2412</a>, the fallback overload resolution was disabled in C++20 (but
> > > > +not in C++17).  Then C++23 <a href="https://wg21.link/p2266">P2266</a>
> > > > +removed the fallback overload resolution, and changed the implicit move
> > > > +rules once again.
> > > > +</p>
> > > > +<p>
> > > > +The two overload resolutions approach was complicated and quirky, so users
> > > > +should transition to the newer model.  This change means that code that
> > > > +previously didn't compile in C++17 will now compile, for example:</p>
> > > > +
> > > > +<pre><code>
> > > > +   struct S1 { S1(S1 &&); };
> > > > +   struct S2 : S1 {};
> > > > +
> > > > +   S1
> > > > +   f (S2 s)
> > > > +   {
> > > > +     return s; // OK, derived-to-base, use S1::S1(S1&&)
> > > > +   }
> > > > +</code></pre>
> > > > +
> > > > +<p>
> > > > +And conversely, code that used to work in C++17 may not compile anymore:
> > > > +</p>
> > > > +
> > > > +<pre><code>
> > > > +   struct W {
> > > > +     W();
> > > > +   };
> > > > +
> > > > +   struct F {
> > > > +     F(W&);
> > > > +     F(W&&) = delete;
> > > > +   };
> > > > +
> > > > +   F fn ()
> > > > +   {
> > > > +     W w;
> > > > +     return w; // use w as rvalue -> use of deleted function F::F(W&&)
> > >
> > > Deleted move constructors are an abomination, and should never occur
> > > in real code. I'm not sure using one even in an example like this
> > > should be encouraged. The example added by P2266 to Annex D is more
> > > realistic (and actually broke a libstdc++ test):
> > >
> > > X& foo(X&& x) { return x; }
> >
> > Right, but this code still compiles in C++17, it only fails to compile
> > in C++23.  The previous example now doesn't compile even in C++17.  So
> > how about this improved patch which makes it clear that code with
> > deleted move constructors should never occur in practice, and adds a new
> > note, specifically about P2266 and the code you showed?
> 
> Doh, I've just realised that F(W&&) isn't a move ctor at all. For some
> reason I read the example as F(F&&).

And so did I while adding the note :[.

> I think your original example is fine, and the note would just be
> confusing (because it's not a deleted move ctor!)

I think I'll go ahead with this, then (I've removed the NB).  Thanks!

diff --git a/htdocs/gcc-13/porting_to.html b/htdocs/gcc-13/porting_to.html
index 84a00f21..ccd3f08f 100644
--- a/htdocs/gcc-13/porting_to.html
+++ b/htdocs/gcc-13/porting_to.html
@@ -42,5 +42,69 @@ be included explicitly when compiled with GCC 13:
 </li>
 </ul>
 
+<h3 id="P2266">Implicit move rules change</h3>
+<p>
+GCC 13 implements C++23 <a href="https://wg21.link/p2266">P2266</a> which
+simplified the rules for implicit move.  As a consequence, valid C++20
+code that relies on a returned <em>id-expression</em>'s being an lvalue
+may change behavior or fail to compile in C++23.  For example:</p>
+
+<pre><code>
+   decltype(auto) f(int&& x) { return (x); }  // returns int&&; previously returned int&
+   int& g(int&& x) { return x; }  // ill-formed; previously well-formed
+</code></pre>
+
+<h3 id="two-stage-or">Two-stage overload resolution for implicit move removed</h3>
+<p>GCC 13 removed the two-stage overload resolution when performing
+implicit move, whereby the compiler does two separate overload resolutions:
+one treating the operand as an rvalue, and then (if that resolution fails)
+another one treating the operand as an lvalue.  In the standard this was
+introduced in C++11 and implemented in gcc in
+<a href="https://gcc.gnu.org/git/?p=gcc.git;a=commitdiff;h=4ce8c5dea53d80736b9c0ba6faa7430ed65ed365">
+r251035</a>.  In
+<a href="https://gcc.gnu.org/git/?p=gcc.git;a=commitdiff;h=1722e2013f05f1f1f99379dbaa0c0df356da731f">
+r11-2412</a>, the fallback overload resolution was disabled in C++20 (but
+not in C++17).  Then C++23 <a href="https://wg21.link/p2266">P2266</a>
+removed the fallback overload resolution, and changed the implicit move
+rules once again.</p>
+
+<p>The two overload resolutions approach was complicated and quirky, so users
+should transition to the newer model.  This change means that code that
+previously didn't compile in C++17 will now compile, for example:</p>
+
+<pre><code>
+   struct S1 { S1(S1 &&); };
+   struct S2 : S1 {};
+
+   S1
+   f (S2 s)
+   {
+     return s; // OK, derived-to-base, use S1::S1(S1&&)
+   }
+</code></pre>
+
+<p>Conversely, code that used to work in C++17 may not compile anymore.
+For example, the following example used to compile in C++11...17 because
+we performed two separate overload resolutions: one treating the operand
+as an rvalue, and then (if that resolution failed) another one treating
+the operand as an lvalue.<br>
+
+<pre><code>
+   struct W {
+     W();
+   };
+
+   struct F {
+     F(W&);
+     F(W&&) = delete;
+   };
+
+   F fn ()
+   {
+     W w;
+     return w; // use w as rvalue -> use of deleted function F::F(W&&)
+   }
+</code></pre>
+
 </body>
 </html>


^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2022-10-12 22:44 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-10-12 19:38 [wwwdocs] porting_to: Two-stage overload resolution for implicit move removed Marek Polacek
2022-10-12 20:50 ` Jonathan Wakely
2022-10-12 22:24   ` Marek Polacek
2022-10-12 22:38     ` Jonathan Wakely
2022-10-12 22:44       ` Marek Polacek

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).