[pushed] c++: fix tourney logic

Message ID 20231020202953.2247779-1-jason@redhat.com
State Accepted
Headers
Series [pushed] c++: fix tourney logic |

Checks

Context Check Description
snail/gcc-patch-check success Github commit url

Commit Message

Jason Merrill Oct. 20, 2023, 8:29 p.m. UTC
  Tested x86_64-pc-linux-gnu, applying to trunk.  Patrick, sorry I didn't apply
this sooner.

-- 8< --

In r13-3766 I changed the logic at the end of tourney to avoid redundant
comparisons, but the change also meant skipping any less-good matches
between the champ_compared_to_predecessor candidate and champ itself.

This should not be a correctness issue, since we believe that joust is a
partial order.  But it can lead to missed warnings, as in this testcase.

gcc/cp/ChangeLog:

	* call.cc (tourney): Only skip champ_compared_to_predecessor.

gcc/testsuite/ChangeLog:

	* g++.dg/warn/Wsign-promo1.C: New test.
---
 gcc/cp/call.cc                           |  5 +++--
 gcc/testsuite/g++.dg/warn/Wsign-promo1.C | 15 +++++++++++++++
 2 files changed, 18 insertions(+), 2 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/warn/Wsign-promo1.C


base-commit: 084addf8a700fab9222d4127ab8524920d0ca481
  

Comments

Patrick Palka Oct. 27, 2023, 8:22 p.m. UTC | #1
On Fri, 20 Oct 2023, Jason Merrill wrote:

> Tested x86_64-pc-linux-gnu, applying to trunk.  Patrick, sorry I didn't apply
> this sooner.
> 
> -- 8< --
> 
> In r13-3766 I changed the logic at the end of tourney to avoid redundant
> comparisons, but the change also meant skipping any less-good matches
> between the champ_compared_to_predecessor candidate and champ itself.
> 
> This should not be a correctness issue, since we believe that joust is a
> partial order.  But it can lead to missed warnings, as in this testcase.

I suppose this rules out optimizing tourney via transitivity when in
a non-SFINAE context since it'd cause missed warnings such as these.
But maybe we'd still want to optimize the second pass via transitivity
in a SFINAE context?

> 
> gcc/cp/ChangeLog:
> 
> 	* call.cc (tourney): Only skip champ_compared_to_predecessor.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* g++.dg/warn/Wsign-promo1.C: New test.
> ---
>  gcc/cp/call.cc                           |  5 +++--
>  gcc/testsuite/g++.dg/warn/Wsign-promo1.C | 15 +++++++++++++++
>  2 files changed, 18 insertions(+), 2 deletions(-)
>  create mode 100644 gcc/testsuite/g++.dg/warn/Wsign-promo1.C
> 
> diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
> index 657eca93d23..a49fde949d5 100644
> --- a/gcc/cp/call.cc
> +++ b/gcc/cp/call.cc
> @@ -13227,10 +13227,11 @@ tourney (struct z_candidate *candidates, tsubst_flags_t complain)
>       been compared to.  */
>  
>    for (challenger = candidates;
> -       challenger != champ
> -	 && challenger != champ_compared_to_predecessor;
> +       challenger != champ;
>         challenger = challenger->next)
>      {
> +      if (challenger == champ_compared_to_predecessor)
> +	continue;
>        fate = joust (champ, challenger, 0, complain);
>        if (fate != 1)
>  	return NULL;
> diff --git a/gcc/testsuite/g++.dg/warn/Wsign-promo1.C b/gcc/testsuite/g++.dg/warn/Wsign-promo1.C
> new file mode 100644
> index 00000000000..51b76eee735
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/warn/Wsign-promo1.C
> @@ -0,0 +1,15 @@
> +// Check that we get joust warnings from comparing the final champ to a
> +// candidate between it and the previous champ.
> +
> +// { dg-additional-options -Wsign-promo }
> +
> +struct A { A(int); };
> +
> +enum E { e };
> +
> +int f(int, A);
> +int f(unsigned, A);
> +int f(int, int);
> +
> +int i = f(e, 42);		// { dg-warning "passing 'E'" }
> +// { dg-warning "in call to 'int f" "" { target *-*-* } .-1 }
> 
> base-commit: 084addf8a700fab9222d4127ab8524920d0ca481
> -- 
> 2.39.3
> 
>
  
Patrick Palka Oct. 27, 2023, 8:33 p.m. UTC | #2
On Fri, 27 Oct 2023, Patrick Palka wrote:

> On Fri, 20 Oct 2023, Jason Merrill wrote:
> 
> > Tested x86_64-pc-linux-gnu, applying to trunk.  Patrick, sorry I didn't apply
> > this sooner.
> > 
> > -- 8< --
> > 
> > In r13-3766 I changed the logic at the end of tourney to avoid redundant
> > comparisons, but the change also meant skipping any less-good matches
> > between the champ_compared_to_predecessor candidate and champ itself.
> > 
> > This should not be a correctness issue, since we believe that joust is a
> > partial order.  But it can lead to missed warnings, as in this testcase.
> 
> I suppose this rules out optimizing tourney via transitivity when in
> a non-SFINAE context since it'd cause missed warnings such as these.
> But maybe we'd still want to optimize the second pass via transitivity
> in a SFINAE context?

Eh, maybe it's not worth it either way..  According to some quick
experiments, making the second pass in tourney assume transitivity by
going up to the most recent tie even in non-SFINAE contexts reduces the
total number of non-trivial calls to tourney by about 5%.  Doing the
same in only SFINAE contexts reduces the number of calls by less than 1%.

> 
> > 
> > gcc/cp/ChangeLog:
> > 
> > 	* call.cc (tourney): Only skip champ_compared_to_predecessor.
> > 
> > gcc/testsuite/ChangeLog:
> > 
> > 	* g++.dg/warn/Wsign-promo1.C: New test.
> > ---
> >  gcc/cp/call.cc                           |  5 +++--
> >  gcc/testsuite/g++.dg/warn/Wsign-promo1.C | 15 +++++++++++++++
> >  2 files changed, 18 insertions(+), 2 deletions(-)
> >  create mode 100644 gcc/testsuite/g++.dg/warn/Wsign-promo1.C
> > 
> > diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
> > index 657eca93d23..a49fde949d5 100644
> > --- a/gcc/cp/call.cc
> > +++ b/gcc/cp/call.cc
> > @@ -13227,10 +13227,11 @@ tourney (struct z_candidate *candidates, tsubst_flags_t complain)
> >       been compared to.  */
> >  
> >    for (challenger = candidates;
> > -       challenger != champ
> > -	 && challenger != champ_compared_to_predecessor;
> > +       challenger != champ;
> >         challenger = challenger->next)
> >      {
> > +      if (challenger == champ_compared_to_predecessor)
> > +	continue;
> >        fate = joust (champ, challenger, 0, complain);
> >        if (fate != 1)
> >  	return NULL;
> > diff --git a/gcc/testsuite/g++.dg/warn/Wsign-promo1.C b/gcc/testsuite/g++.dg/warn/Wsign-promo1.C
> > new file mode 100644
> > index 00000000000..51b76eee735
> > --- /dev/null
> > +++ b/gcc/testsuite/g++.dg/warn/Wsign-promo1.C
> > @@ -0,0 +1,15 @@
> > +// Check that we get joust warnings from comparing the final champ to a
> > +// candidate between it and the previous champ.
> > +
> > +// { dg-additional-options -Wsign-promo }
> > +
> > +struct A { A(int); };
> > +
> > +enum E { e };
> > +
> > +int f(int, A);
> > +int f(unsigned, A);
> > +int f(int, int);
> > +
> > +int i = f(e, 42);		// { dg-warning "passing 'E'" }
> > +// { dg-warning "in call to 'int f" "" { target *-*-* } .-1 }
> > 
> > base-commit: 084addf8a700fab9222d4127ab8524920d0ca481
> > -- 
> > 2.39.3
> > 
> > 
>
  
Patrick Palka Oct. 27, 2023, 8:34 p.m. UTC | #3
On Fri, 27 Oct 2023, Patrick Palka wrote:

> On Fri, 27 Oct 2023, Patrick Palka wrote:
> 
> > On Fri, 20 Oct 2023, Jason Merrill wrote:
> > 
> > > Tested x86_64-pc-linux-gnu, applying to trunk.  Patrick, sorry I didn't apply
> > > this sooner.
> > > 
> > > -- 8< --
> > > 
> > > In r13-3766 I changed the logic at the end of tourney to avoid redundant
> > > comparisons, but the change also meant skipping any less-good matches
> > > between the champ_compared_to_predecessor candidate and champ itself.
> > > 
> > > This should not be a correctness issue, since we believe that joust is a
> > > partial order.  But it can lead to missed warnings, as in this testcase.
> > 
> > I suppose this rules out optimizing tourney via transitivity when in
> > a non-SFINAE context since it'd cause missed warnings such as these.
> > But maybe we'd still want to optimize the second pass via transitivity
> > in a SFINAE context?
> 
> Eh, maybe it's not worth it either way..  According to some quick
> experiments, making the second pass in tourney assume transitivity by
> going up to the most recent tie even in non-SFINAE contexts reduces the
> total number of non-trivial calls to tourney by about 5%.  Doing the

total number of non-trivial calls to joust, rather

> same in only SFINAE contexts reduces the number of calls by less than 1%.
> 
> > 
> > > 
> > > gcc/cp/ChangeLog:
> > > 
> > > 	* call.cc (tourney): Only skip champ_compared_to_predecessor.
> > > 
> > > gcc/testsuite/ChangeLog:
> > > 
> > > 	* g++.dg/warn/Wsign-promo1.C: New test.
> > > ---
> > >  gcc/cp/call.cc                           |  5 +++--
> > >  gcc/testsuite/g++.dg/warn/Wsign-promo1.C | 15 +++++++++++++++
> > >  2 files changed, 18 insertions(+), 2 deletions(-)
> > >  create mode 100644 gcc/testsuite/g++.dg/warn/Wsign-promo1.C
> > > 
> > > diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
> > > index 657eca93d23..a49fde949d5 100644
> > > --- a/gcc/cp/call.cc
> > > +++ b/gcc/cp/call.cc
> > > @@ -13227,10 +13227,11 @@ tourney (struct z_candidate *candidates, tsubst_flags_t complain)
> > >       been compared to.  */
> > >  
> > >    for (challenger = candidates;
> > > -       challenger != champ
> > > -	 && challenger != champ_compared_to_predecessor;
> > > +       challenger != champ;
> > >         challenger = challenger->next)
> > >      {
> > > +      if (challenger == champ_compared_to_predecessor)
> > > +	continue;
> > >        fate = joust (champ, challenger, 0, complain);
> > >        if (fate != 1)
> > >  	return NULL;
> > > diff --git a/gcc/testsuite/g++.dg/warn/Wsign-promo1.C b/gcc/testsuite/g++.dg/warn/Wsign-promo1.C
> > > new file mode 100644
> > > index 00000000000..51b76eee735
> > > --- /dev/null
> > > +++ b/gcc/testsuite/g++.dg/warn/Wsign-promo1.C
> > > @@ -0,0 +1,15 @@
> > > +// Check that we get joust warnings from comparing the final champ to a
> > > +// candidate between it and the previous champ.
> > > +
> > > +// { dg-additional-options -Wsign-promo }
> > > +
> > > +struct A { A(int); };
> > > +
> > > +enum E { e };
> > > +
> > > +int f(int, A);
> > > +int f(unsigned, A);
> > > +int f(int, int);
> > > +
> > > +int i = f(e, 42);		// { dg-warning "passing 'E'" }
> > > +// { dg-warning "in call to 'int f" "" { target *-*-* } .-1 }
> > > 
> > > base-commit: 084addf8a700fab9222d4127ab8524920d0ca481
> > > -- 
> > > 2.39.3
> > > 
> > > 
> > 
>
  

Patch

diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
index 657eca93d23..a49fde949d5 100644
--- a/gcc/cp/call.cc
+++ b/gcc/cp/call.cc
@@ -13227,10 +13227,11 @@  tourney (struct z_candidate *candidates, tsubst_flags_t complain)
      been compared to.  */
 
   for (challenger = candidates;
-       challenger != champ
-	 && challenger != champ_compared_to_predecessor;
+       challenger != champ;
        challenger = challenger->next)
     {
+      if (challenger == champ_compared_to_predecessor)
+	continue;
       fate = joust (champ, challenger, 0, complain);
       if (fate != 1)
 	return NULL;
diff --git a/gcc/testsuite/g++.dg/warn/Wsign-promo1.C b/gcc/testsuite/g++.dg/warn/Wsign-promo1.C
new file mode 100644
index 00000000000..51b76eee735
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Wsign-promo1.C
@@ -0,0 +1,15 @@ 
+// Check that we get joust warnings from comparing the final champ to a
+// candidate between it and the previous champ.
+
+// { dg-additional-options -Wsign-promo }
+
+struct A { A(int); };
+
+enum E { e };
+
+int f(int, A);
+int f(unsigned, A);
+int f(int, int);
+
+int i = f(e, 42);		// { dg-warning "passing 'E'" }
+// { dg-warning "in call to 'int f" "" { target *-*-* } .-1 }