[wwwdocs] porting_to: Two-stage overload resolution for implicit move removed

Message ID Y0cX0wQJBbmESbG1@redhat.com
State New, archived
Headers
Series [wwwdocs] porting_to: Two-stage overload resolution for implicit move removed |

Commit Message

Marek Polacek Oct. 12, 2022, 7:38 p.m. UTC
  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,
  

Comments

Jonathan Wakely Oct. 12, 2022, 8:50 p.m. UTC | #1
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>
>
  
Marek Polacek Oct. 12, 2022, 10:24 p.m. UTC | #2
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>
  
Jonathan Wakely Oct. 12, 2022, 10:38 p.m. UTC | #3
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>
>
  
Marek Polacek Oct. 12, 2022, 10:44 p.m. UTC | #4
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>
  

Patch

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>