https://gcc.gnu.org/g:7fed7e9bbc57d502e141e079a6be2706bdbd4560

commit r15-1292-g7fed7e9bbc57d502e141e079a6be2706bdbd4560
Author: Patrick Palka <ppa...@redhat.com>
Date:   Thu Jun 13 10:02:43 2024 -0400

    c++: ICE w/ ambig and non-strictly-viable cands [PR115239]
    
    Here during overload resolution we have two strictly viable ambiguous
    candidates #1 and #2, and two non-strictly viable candidates #3 and #4
    which we hold on to ever since r14-6522.  These latter candidates have
    an empty second arg conversion since the first arg conversion was deemed
    bad, and this trips up joust when called on #3 and #4 which assumes all
    arg conversions are there.
    
    We can fix this by making joust robust to empty arg conversions, but in
    this situation we shouldn't need to compare #3 and #4 at all given that
    we have a strictly viable candidate.  To that end, this patch makes
    tourney shortcut considering non-strictly viable candidates upon
    encountering ambiguity between two strictly viable candidates (taking
    advantage of the fact that the candidates list is sorted according to
    viability via splice_viable).
    
            PR c++/115239
    
    gcc/cp/ChangeLog:
    
            * call.cc (tourney): Don't consider a non-strictly viable
            candidate as the champ if there was ambiguity between two
            strictly viable candidates.
    
    gcc/testsuite/ChangeLog:
    
            * g++.dg/overload/error7.C: New test.
    
    Reviewed-by: Jason Merrill <ja...@redhat.com>

Diff:
---
 gcc/cp/call.cc                         |  3 ++-
 gcc/testsuite/g++.dg/overload/error7.C | 10 ++++++++++
 2 files changed, 12 insertions(+), 1 deletion(-)

diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
index 85536fc25ff2..7bbc1fb0c789 100644
--- a/gcc/cp/call.cc
+++ b/gcc/cp/call.cc
@@ -13490,7 +13490,8 @@ tourney (struct z_candidate *candidates, tsubst_flags_t 
complain)
        {
          previous_worse_champ = nullptr;
          champ = &(*challenger)->next;
-         if (!*champ || !(*champ)->viable)
+         if (!*champ || !(*champ)->viable
+             || (*champ)->viable < (*challenger)->viable)
            {
              champ = nullptr;
              break;
diff --git a/gcc/testsuite/g++.dg/overload/error7.C 
b/gcc/testsuite/g++.dg/overload/error7.C
new file mode 100644
index 000000000000..de50ce5f66e4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/overload/error7.C
@@ -0,0 +1,10 @@
+// PR c++/115239
+
+bool foo(char *, long);     // #1, strictly viable, ambig with #2
+bool foo(char *, unsigned); // #2, strictly viable, ambig with #1
+bool foo(char, long);       // #3, non-strictly viable
+bool foo(char, unsigned);   // #4, non-strictly viable
+
+int main() {
+  foo((char *)0, 0); // { dg-error "ambiguous" }
+}

Reply via email to