Ping #2

On Tue, 2025-12-02 at 12:11 -0500, David Malcolm wrote:
> I'd like to ping these two C++ frontend patches for review:
> 
> 
> * [PATCH 1/2] c++: use nesting and counts in print_candidates
>   *
> https://gcc.gnu.org/pipermail/gcc-patches/2025-November/700801.html
> * [PATCH 2/2] c++: UX improvements for close matches in
> print_candidates
>   *
> https://gcc.gnu.org/pipermail/gcc-patches/2025-November/700802.html
> 
> Thanks
> Dave
> 
> On Sat, 2025-11-15 at 18:14 -0500, David Malcolm wrote:
> > In r15-6116-gd3dd24acd74605 I updated print_z_candidates to print a
> > count of the number of candidates, and to show the number of each
> > candidate in the list if there is more than one.
> > 
> > The following patch updates print_candidates to work in a similar
> > way, showing counts, numbering, and using nesting.
> > 
> > Consider this test case for which we print 2 candidates:
> > 
> > class foo
> > {
> > public:
> >   void test (int i, int j, void *ptr, int k);
> >   void test (int i, int j, int k);
> > };
> > 
> > // Wrong "const"-ness of a param, for one of the overloads (param
> > 3).
> > void foo::test (int i, int j, const void *ptr, int k)
> > {
> > }
> > 
> > The output before the patch is:
> > 
> > test.cc:9:6: error: no declaration matches ‘void foo::test(int,
> > int,
> > const void*, int)’
> >     9 | void foo::test (int i, int j, const void *ptr, int k)
> >       |      ^~~
> > test.cc:5:8: note: candidates are: ‘void foo::test(int, int, int)’
> >     5 |   void test (int i, int j, int k);
> >       |        ^~~~
> > test.cc:4:8: note:                 ‘void foo::test(int, int, void*,
> > int)’
> >     4 |   void test (int i, int j, void *ptr, int k);
> >       |        ^~~~
> > test.cc:1:7: note: ‘class foo’ defined here
> >     1 | class foo
> >       |       ^~~
> > 
> > With the patch, the output looks like:
> > 
> > test.cc:9:6: error: no declaration matches ‘void foo::test(int,
> > int,
> > const void*, int)’
> >     9 | void foo::test (int i, int j, const void *ptr, int k)
> >       |      ^~~
> >   • there are 2 candidates
> >     • candidate 1: ‘void foo::test(int, int, int)’
> >       test.cc:5:8:
> >           5 |   void test (int i, int j, int k);
> >             |        ^~~~
> >     • candidate 2: ‘void foo::test(int, int, void*, int)’
> >       test.cc:4:8:
> >           4 |   void test (int i, int j, void *ptr, int k);
> >             |        ^~~~
> > test.cc:1:7: note: ‘class foo’ defined here
> >     1 | class foo
> >       |       ^~~
> > 
> > which I believe is much more readable.
> > 
> > I dabbled with removing the "there is 1 candidate" line for the
> > case
> > of
> > a single candidate, but I think I prefer it to be present.
> > 
> > Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu.
> > 
> > OK for trunk?
> > Dave
> > 
> > gcc/cp/ChangeLog:
> >     * call.cc (print_z_candidates): Move inform_n call into a
> > new
> >     inform_num_candidates function.
> >     * cp-tree.h (inform_num_candidates): New decl.
> >     * pt.cc  (print_candidates_1): Drop, converting the
> > looping
> > part
> >     into...
> >     (flatten_candidates): ...this new function.
> >     (print_candidates): Use flatten_candidates to build an
> > auto_vec
> >     of candidates, and use this to print them here, rather
> > than
> > in
> >     print_candidates_1.  Eliminate the dynamic allocation of
> > spaces
> >     for a prefix in favor of printing "candidate %i" when
> > there
> > is
> >     more than one candidate.  Use inform_num_candidates to
> > show
> > a
> >     heading, and add nesting levels for it and for the
> > candidate
> >     notes.
> > 
> > gcc/testsuite/ChangeLog:
> >     * g++.dg/cpp0x/inline-ns2.C: Make dg-message directives
> > non-
> > empty.
> >     * g++.dg/cpp23/explicit-obj-lambda11.C: Prune the extra
> > note.
> >     * g++.dg/diagnostic/bad-fndef-1.C: New test.
> >     * g++.dg/lookup/decl1.C: Give the dg-message directives
> > different
> >     messages.
> >     * g++.dg/lookup/using17.C: Update expected output.
> >     * g++.dg/parse/non-dependent2.C: Likewise.
> >     * g++.old-deja/g++.other/lineno2.C: Give the dg-message
> > directives
> >     different messages.
> >     * g++.old-deja/g++.pt/t37.C: Likewise.
> > ---
> >  gcc/cp/call.cc                                |  5 +-
> >  gcc/cp/cp-tree.h                              |  1 +
> >  gcc/cp/pt.cc                                  | 67 +++++++++++----
> > --
> > --
> >  gcc/testsuite/g++.dg/cpp0x/inline-ns2.C       | 18 ++---
> >  .../g++.dg/cpp23/explicit-obj-lambda11.C      |  1 +
> >  gcc/testsuite/g++.dg/diagnostic/bad-fndef-1.C | 15 +++++
> >  gcc/testsuite/g++.dg/lookup/decl1.C           |  8 +--
> >  gcc/testsuite/g++.dg/lookup/using17.C         |  4 +-
> >  gcc/testsuite/g++.dg/parse/non-dependent2.C   |  2 +-
> >  .../g++.old-deja/g++.other/lineno2.C          |  8 +--
> >  gcc/testsuite/g++.old-deja/g++.pt/t37.C       | 10 +--
> >  11 files changed, 82 insertions(+), 57 deletions(-)
> >  create mode 100644 gcc/testsuite/g++.dg/diagnostic/bad-fndef-1.C
> > 
> > diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
> > index f80d597b33944..fc4e6da1f9a20 100644
> > --- a/gcc/cp/call.cc
> > +++ b/gcc/cp/call.cc
> > @@ -4261,9 +4261,8 @@ print_z_candidates (location_t loc, struct
> > z_candidate *candidates,
> >        ++num_candidates;
> >      }
> >  
> > -  inform_n (loc,
> > -       num_candidates, "there is %i candidate", "there are %i
> > candidates",
> > -       num_candidates);
> > +  inform_num_candidates (loc, num_candidates);
> > +
> >    auto_diagnostic_nesting_level sentinel2;
> >  
> >    int candidate_idx = 0;
> > diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
> > index 5e8d1c9644c5b..d0d057c927017 100644
> > --- a/gcc/cp/cp-tree.h
> > +++ b/gcc/cp/cp-tree.h
> > @@ -7890,6 +7890,7 @@ extern tree
> > maybe_process_partial_specialization (tree);
> >  extern tree most_specialized_instantiation (tree);
> >  extern tree most_specialized_partial_spec       (tree,
> > tsubst_flags_t, bool = false);
> >  extern tree most_constrained_function              (tree);
> > +extern void inform_num_candidates          (location_t, int);
> >  extern void print_candidates                       (tree);
> >  extern void instantiate_pending_templates  (int);
> >  extern tree tsubst_default_argument                (tree, int, tree,
> > tree,
> > diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> > index bbbf49363e8f0..59e9585aac94d 100644
> > --- a/gcc/cp/pt.cc
> > +++ b/gcc/cp/pt.cc
> > @@ -2033,39 +2033,30 @@ explicit_class_specialization_p (tree type)
> >    return !uses_template_parms (CLASSTYPE_TI_ARGS (type));
> >  }
> >  
> > -/* Print the list of functions at FNS, going through all the
> > overloads
> > -   for each element of the list.  Alternatively, FNS cannot be a
> > -   TREE_LIST, in which case it will be printed together with all
> > the
> > -   overloads.
> > -
> > -   MORE and *STR should respectively be FALSE and NULL when the
> > function
> > -   is called from the outside.  They are used internally on
> > recursive
> > -   calls.  print_candidates manages the two parameters and leaves
> > NULL
> > -   in *STR when it ends.  */
> > +/* Populate OUT the list of functions at FNS, going through all
> > the
> > +   overloads for each element of the list.  Alternatively, FNS can
> > be a
> > +   TREE_LIST, in which case it will be added together with all the
> > +   overloads.  */
> >  
> >  static void
> > -print_candidates_1 (tree fns, char **str, bool more = false)
> > +flatten_candidates (tree fns, auto_vec<tree> &out)
> >  {
> >    if (TREE_CODE (fns) == TREE_LIST)
> >      for (; fns; fns = TREE_CHAIN (fns))
> > -      print_candidates_1 (TREE_VALUE (fns), str, more ||
> > TREE_CHAIN
> > (fns));
> > +      flatten_candidates (TREE_VALUE (fns), out);
> >    else
> > -    for (lkp_iterator iter (fns); iter;)
> > -      {
> > -   tree cand = *iter;
> > -   ++iter;
> > +    for (lkp_iterator iter (fns); iter; ++iter)
> > +      out.safe_push (*iter);
> > +}
> >  
> > -   const char *pfx = *str;
> > -   if (!pfx)
> > -     {
> > -       if (more || iter)
> > -         pfx = _("candidates are:");
> > -       else
> > -         pfx = _("candidate is:");
> > -       *str = get_spaces (pfx);
> > -     }
> > -   inform (DECL_SOURCE_LOCATION (cand), "%s %#qD", pfx,
> > cand);
> > -      }
> > +/* Print a note announcing a list of candidates.  */
> > +
> > +void
> > +inform_num_candidates (location_t loc, int num_candidates)
> > +{
> > +  inform_n (loc,
> > +       num_candidates, "there is %i candidate", "there are %i
> > candidates",
> > +       num_candidates);
> >  }
> >  
> >  /* Print the list of candidate FNS in an error message.  FNS can
> > also
> > @@ -2074,9 +2065,27 @@ print_candidates_1 (tree fns, char **str,
> > bool
> > more = false)
> >  void
> >  print_candidates (tree fns)
> >  {
> > -  char *str = NULL;
> > -  print_candidates_1 (fns, &str);
> > -  free (str);
> > +  auto_vec<tree> candidates;
> > +  flatten_candidates (fns, candidates);
> > +
> > +  auto_diagnostic_nesting_level sentinel;
> > +
> > +  inform_num_candidates (UNKNOWN_LOCATION, candidates.length ());
> > +
> > +  auto_diagnostic_nesting_level sentinel2;
> > +
> > +  if (candidates.length () == 1)
> > +    {
> > +      tree cand = candidates[0];
> > +      inform (DECL_SOURCE_LOCATION (cand), "candidate is: %#qD",
> > cand);
> > +    }
> > +  else
> > +    {
> > +      int idx = 0;
> > +      for (auto cand : candidates)
> > +   inform (DECL_SOURCE_LOCATION (cand), "candidate %i: %#qD",
> > +           ++idx, cand);
> > +    }
> >  }
> >  
> >  /* Get a (possibly) constrained template declaration for the
> > diff --git a/gcc/testsuite/g++.dg/cpp0x/inline-ns2.C
> > b/gcc/testsuite/g++.dg/cpp0x/inline-ns2.C
> > index 6ad9d65a6fbbb..1dc8efeb329ff 100644
> > --- a/gcc/testsuite/g++.dg/cpp0x/inline-ns2.C
> > +++ b/gcc/testsuite/g++.dg/cpp0x/inline-ns2.C
> > @@ -2,17 +2,17 @@
> >  
> >  namespace Q {
> >    inline namespace V1 {
> > -    extern int i;          // { dg-message "" }
> > -    extern int j;          // { dg-message "" }
> > -    void f();                      // { dg-message "" }
> > -    void g();                      // { dg-message "" }
> > +    extern int i;          // { dg-message "candidate" }
> > +    extern int j;          // { dg-message "candidate" }
> > +    void f();                      // { dg-message "candidate" }
> > +    void g();                      // { dg-message "candidate" }
> >    }
> >    inline namespace V2 {
> > -    extern int j;          // { dg-message "" }
> > -    void g();                      // { dg-message "" }
> > +    extern int j;          // { dg-message "candidate" }
> > +    void g();                      // { dg-message "candidate" }
> >    }
> > -  extern int i;                    // { dg-message "" }
> > -  void f();                        // { dg-message "" }
> > +  extern int i;                    // { dg-message
> > "candidate"
> > }
> > +  void f();                        // { dg-message "candidate" }
> >    void h();
> >  }
> >  namespace R {
> > @@ -22,4 +22,4 @@ int Q::i = 1;                     // { dg-error
> > "ambiguous" }
> >  int Q::j = 1;                      // { dg-error "ambiguous" }
> >  void Q::f() { }                    // { dg-error "ambiguous"
> > }
> >  void Q::g() { }                    // { dg-error "ambiguous"
> > }
> > -void R::h() { }                    // { dg-error "" }
> > +void R::h() { }                    // { dg-error "should have
> > been declared inside 'R'" }
> > diff --git a/gcc/testsuite/g++.dg/cpp23/explicit-obj-lambda11.C
> > b/gcc/testsuite/g++.dg/cpp23/explicit-obj-lambda11.C
> > index 7957ad3e19430..1fc67d624714a 100644
> > --- a/gcc/testsuite/g++.dg/cpp23/explicit-obj-lambda11.C
> > +++ b/gcc/testsuite/g++.dg/cpp23/explicit-obj-lambda11.C
> > @@ -45,3 +45,4 @@ void test2()
> >  // { dg-error "a lambda with captures may not have an explicit
> > object parameter of an unrelated type" {depends on PR112874} {
> > xfail
> > *-*-* } t2_f }
> >  // { dg-note "candidate is" "" { target *-*-* } t2_f }
> >  
> > +// { dg-prune-output "cc1plus: note: there is 1 candidate" }
> > diff --git a/gcc/testsuite/g++.dg/diagnostic/bad-fndef-1.C
> > b/gcc/testsuite/g++.dg/diagnostic/bad-fndef-1.C
> > new file mode 100644
> > index 0000000000000..1156072b11f16
> > --- /dev/null
> > +++ b/gcc/testsuite/g++.dg/diagnostic/bad-fndef-1.C
> > @@ -0,0 +1,15 @@
> > +class foo // { dg-message "'class foo' defined here" }
> > +{
> > +public:
> > +  void test (int i, int j, void *ptr, int k); // { dg-line
> > close_decl }
> > +  void test (int i, int j, int k);            // { dg-line
> > other_decl }
> > +};
> > +
> > +// Wrong "const"-ness of a param, for one of the overloads (param
> > 3).
> > +void foo::test (int i, int j, const void *ptr, int k) // { dg-line
> > defn }
> > +{
> > +}
> > +
> > +// { dg-error "6: no declaration matches" "error" { target *-*-* }
> > defn }
> > +// { dg-message "8: candidate 1: " "candidate 1" { target *-*-* }
> > other_decl }
> > +// { dg-message "8: candidate 2: " "candidate 2" { target *-*-* }
> > close_decl }
> > diff --git a/gcc/testsuite/g++.dg/lookup/decl1.C
> > b/gcc/testsuite/g++.dg/lookup/decl1.C
> > index 205ffcff1d73d..38319ba923de0 100644
> > --- a/gcc/testsuite/g++.dg/lookup/decl1.C
> > +++ b/gcc/testsuite/g++.dg/lookup/decl1.C
> > @@ -20,10 +20,10 @@ C2<X>::operator C1<Y>()
> >  }
> >  
> >  struct A { // { dg-message "defined here" }
> > -  operator int ();                 // { dg-message "operator"
> > }
> > -  operator float ();                       // { dg-message "operator"
> > }
> > -  operator float () const;         // { dg-message "operator"
> > }
> > -  template <typename T> operator T * (); // { dg-message
> > "operator"
> > }
> > +  operator int ();                 // { dg-message "operator
> > int" }
> > +  operator float ();                       // { dg-message "operator
> > float" }
> > +  operator float () const;         // { dg-message "operator
> > float" }
> > +  template <typename T> operator T * (); // { dg-message "operator
> > T" }
> >  };
> >  
> >  A::operator short () { // { dg-error "no declaration matches" }
> > diff --git a/gcc/testsuite/g++.dg/lookup/using17.C
> > b/gcc/testsuite/g++.dg/lookup/using17.C
> > index 55875fe9af978..1e69dbe36376d 100644
> > --- a/gcc/testsuite/g++.dg/lookup/using17.C
> > +++ b/gcc/testsuite/g++.dg/lookup/using17.C
> > @@ -3,11 +3,11 @@
> >  // { dg-do compile }
> >  
> >  namespace M {
> > -  struct S {}; // { dg-message "candidates are: .struct M::S."
> > "candidate 1" }
> > +  struct S {}; // { dg-message "candidates 1: 'struct M::S'"}
> >  }
> >  
> >  int S;
> > -struct S {}; // { dg-message ".struct S." "candidate 2" }
> > +struct S {}; // { dg-message "candidate 2: 'struct S'" }
> >  
> >  using namespace M;
> >  
> > diff --git a/gcc/testsuite/g++.dg/parse/non-dependent2.C
> > b/gcc/testsuite/g++.dg/parse/non-dependent2.C
> > index c22497044e90c..eb83390206c52 100644
> > --- a/gcc/testsuite/g++.dg/parse/non-dependent2.C
> > +++ b/gcc/testsuite/g++.dg/parse/non-dependent2.C
> > @@ -15,7 +15,7 @@ struct Foo {
> >  struct Baz 
> >  {
> >    int j;
> > -  int k; // { dg-message "candidates" }
> > +  int k; // { dg-message "candidate" }
> >    
> >  };
> >  
> > diff --git a/gcc/testsuite/g++.old-deja/g++.other/lineno2.C
> > b/gcc/testsuite/g++.old-deja/g++.other/lineno2.C
> > index d6aca8b9cfd08..6434f9ac45ce4 100644
> > --- a/gcc/testsuite/g++.old-deja/g++.other/lineno2.C
> > +++ b/gcc/testsuite/g++.old-deja/g++.other/lineno2.C
> > @@ -2,14 +2,14 @@
> >  // Submitted by Nathan Sidwell <[email protected]>
> >  // Bug: g++ wasn't listing candidates for a failed conversion.
> >  
> > -void f(int, double);               // { dg-message "" } candidate
> > -void f(double, int);               // { dg-message "" } candidate
> > -void f(int);                       // { dg-message "" } candidate
> > +void f(int, double);               // { dg-message "candidate" }
> > +void f(double, int);               // { dg-message "candidate" }
> > +void f(int);                       // { dg-message "candidate" }
> >  
> >  int
> >  main ()
> >  {
> >    void (*ptr)(int, int);
> >    
> > -  ptr = &f;                        // { dg-error "" } no match
> > +  ptr = &f;                        // { dg-error "no matches" }
> >  }
> > diff --git a/gcc/testsuite/g++.old-deja/g++.pt/t37.C
> > b/gcc/testsuite/g++.old-deja/g++.pt/t37.C
> > index dbf1f4403b31c..ffef5e58a4385 100644
> > --- a/gcc/testsuite/g++.old-deja/g++.pt/t37.C
> > +++ b/gcc/testsuite/g++.old-deja/g++.pt/t37.C
> > @@ -1,14 +1,14 @@
> >  // { dg-do compile  }
> >  
> > -class A { // { dg-message "A::A" } synthesized copy ctor
> > -  // { dg-message "defined here" "note" { target *-*-* } .-1 }
> > +class A { // { dg-message "A::A\\\(const A&\\\)" } synthesized
> > copy
> > ctor
> > +  // { dg-message "'class A' defined here" "note" { target *-*-* }
> > .-1 }
> >  public:
> > -  A(int);                  // { dg-message "A::A" }
> > -  A(float);                        // { dg-message "A::A" }
> > +  A(int);                  // { dg-message "A::A\\\(int\\\)"
> > }
> > +  A(float);                        // { dg-message
> > "A::A\\\(float\\\)"
> > }
> >    ~A();
> >  };
> >  
> > -A::A() {           // { dg-error "" } 
> > +A::A() {           // { dg-error "no declaration matches" } 
> >  }
> >    
> >  A::A(int) {
> 

Reply via email to