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) {
-- 
2.26.3

Reply via email to