]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c++: Output less irrelevant info for function template decl [PR100716]
authorMatthias Kretz <kretz@kde.org>
Thu, 27 May 2021 15:25:37 +0000 (17:25 +0200)
committerJason Merrill <jason@redhat.com>
Thu, 27 May 2021 21:00:38 +0000 (17:00 -0400)
Ensure dump_template_decl for function templates never prints template
parameters after the function name (it did with -fno-pretty-templates)
and skip output of irrelevant & confusing "[with T = T]" in
dump_substitution.

gcc/cp/ChangeLog:

PR c++/100716
* error.c (dump_template_bindings): Include code to print
"[with" and ']', conditional on whether anything is printed at
all. This is tied to whether a semicolon is needed to separate
multiple template parameters. If the template argument repeats
the template parameter (T = T), then skip the parameter.
(dump_substitution): Moved code to print "[with" and ']' to
dump_template_bindings.
(dump_function_decl): Partial revert of PR50828, which masked
TFF_TEMPLATE_NAME for all of dump_function_decl. Now
TFF_TEMPLATE_NAME is masked for the scope of the function and
only carries through to dump_function_name.
(dump_function_name): Avoid calling dump_template_parms if
TFF_TEMPLATE_NAME is set.

gcc/testsuite/ChangeLog:

PR c++/100716
* g++.dg/diagnostic/pr100716.C: New test.
* g++.dg/diagnostic/pr100716-1.C: Same test with
-fno-pretty-templates.

gcc/cp/error.c
gcc/testsuite/g++.dg/diagnostic/pr100716-1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/diagnostic/pr100716.C [new file with mode: 0644]

index ae78b10c7b2e5ab2d6414d28c2c70221f39642bf..4a89b3488291480784d23b6fe53018b8cb18eb95 100644 (file)
@@ -371,7 +371,35 @@ static void
 dump_template_bindings (cxx_pretty_printer *pp, tree parms, tree args,
                         vec<tree, va_gc> *typenames)
 {
-  bool need_semicolon = false;
+  /* Print "[with" and ']', conditional on whether anything is printed at all.
+     This is tied to whether a semicolon is needed to separate multiple template
+     parameters.  */
+  struct prepost_semicolon
+  {
+    cxx_pretty_printer *pp;
+    bool need_semicolon;
+
+    void operator() ()
+    {
+      if (need_semicolon)
+       pp_separate_with_semicolon (pp);
+      else
+       {
+         pp_cxx_whitespace (pp);
+         pp_cxx_left_bracket (pp);
+         pp->translate_string ("with");
+         pp_cxx_whitespace (pp);
+         need_semicolon = true;
+       }
+    }
+
+    ~prepost_semicolon ()
+    {
+      if (need_semicolon)
+       pp_cxx_right_bracket (pp);
+    }
+  } semicolon_or_introducer = {pp, false};
+
   int i;
   tree t;
 
@@ -395,10 +423,20 @@ dump_template_bindings (cxx_pretty_printer *pp, tree parms, tree args,
          if (lvl_args && NUM_TMPL_ARGS (lvl_args) > arg_idx)
            arg = TREE_VEC_ELT (lvl_args, arg_idx);
 
-         if (need_semicolon)
-           pp_separate_with_semicolon (pp);
-         dump_template_parameter (pp, TREE_VEC_ELT (p, i),
-                                   TFF_PLAIN_IDENTIFIER);
+         tree parm_i = TREE_VEC_ELT (p, i);
+         /* If the template argument repeats the template parameter (T = T),
+            skip the parameter.*/
+         if (arg && TREE_CODE (arg) == TEMPLATE_TYPE_PARM
+               && TREE_CODE (parm_i) == TREE_LIST
+               && TREE_CODE (TREE_VALUE (parm_i)) == TYPE_DECL
+               && TREE_CODE (TREE_TYPE (TREE_VALUE (parm_i)))
+                    == TEMPLATE_TYPE_PARM
+               && DECL_NAME (TREE_VALUE (parm_i))
+                    == DECL_NAME (TREE_CHAIN (arg)))
+           continue;
+
+         semicolon_or_introducer ();
+         dump_template_parameter (pp, parm_i, TFF_PLAIN_IDENTIFIER);
          pp_cxx_whitespace (pp);
          pp_equal (pp);
          pp_cxx_whitespace (pp);
@@ -414,7 +452,6 @@ dump_template_bindings (cxx_pretty_printer *pp, tree parms, tree args,
            pp_string (pp, M_("<missing>"));
 
          ++arg_idx;
-         need_semicolon = true;
        }
 
       parms = TREE_CHAIN (parms);
@@ -436,8 +473,7 @@ dump_template_bindings (cxx_pretty_printer *pp, tree parms, tree args,
 
   FOR_EACH_VEC_SAFE_ELT (typenames, i, t)
     {
-      if (need_semicolon)
-       pp_separate_with_semicolon (pp);
+      semicolon_or_introducer ();
       dump_type (pp, t, TFF_PLAIN_IDENTIFIER);
       pp_cxx_whitespace (pp);
       pp_equal (pp);
@@ -1599,12 +1635,7 @@ dump_substitution (cxx_pretty_printer *pp,
       && !(flags & TFF_NO_TEMPLATE_BINDINGS))
     {
       vec<tree, va_gc> *typenames = t ? find_typenames (t) : NULL;
-      pp_cxx_whitespace (pp);
-      pp_cxx_left_bracket (pp);
-      pp->translate_string ("with");
-      pp_cxx_whitespace (pp);
       dump_template_bindings (pp, template_parms, template_args, typenames);
-      pp_cxx_right_bracket (pp);
     }
 }
 
@@ -1645,7 +1676,8 @@ dump_function_decl (cxx_pretty_printer *pp, tree t, int flags)
   bool constexpr_p;
   tree ret = NULL_TREE;
 
-  flags &= ~(TFF_UNQUALIFIED_NAME | TFF_TEMPLATE_NAME);
+  int dump_function_name_flags = flags & ~TFF_UNQUALIFIED_NAME;
+  flags = dump_function_name_flags & ~TFF_TEMPLATE_NAME;
   if (TREE_CODE (t) == TEMPLATE_DECL)
     t = DECL_TEMPLATE_RESULT (t);
 
@@ -1723,7 +1755,7 @@ dump_function_decl (cxx_pretty_printer *pp, tree t, int flags)
   else
     dump_scope (pp, CP_DECL_CONTEXT (t), flags);
 
-  dump_function_name (pp, t, flags);
+  dump_function_name (pp, t, dump_function_name_flags);
 
   if (!(flags & TFF_NO_FUNCTION_ARGUMENTS))
     {
@@ -1937,6 +1969,7 @@ dump_function_name (cxx_pretty_printer *pp, tree t, int flags)
   dump_module_suffix (pp, t);
 
   if (DECL_TEMPLATE_INFO (t)
+      && !(flags & TFF_TEMPLATE_NAME)
       && !DECL_FRIEND_PSEUDO_TEMPLATE_INSTANTIATION (t)
       && (TREE_CODE (DECL_TI_TEMPLATE (t)) != TEMPLATE_DECL
          || PRIMARY_TEMPLATE_P (DECL_TI_TEMPLATE (t))))
diff --git a/gcc/testsuite/g++.dg/diagnostic/pr100716-1.C b/gcc/testsuite/g++.dg/diagnostic/pr100716-1.C
new file mode 100644 (file)
index 0000000..93490da
--- /dev/null
@@ -0,0 +1,54 @@
+// { dg-options "-fno-pretty-templates" }
+
+template<typename T>
+  struct A
+  {
+    template<typename U>
+      void f() {} // { dg-line Af }
+
+    template<typename U>
+      void g(U) {} // { dg-line Ag }
+  };
+
+template<typename T>
+  struct B
+  {
+    template<typename U>
+      void f(U) {} // { dg-line Bf }
+
+    template<typename U>
+      void g(U, T) {} // { dg-line Bg }
+  };
+
+struct C
+{
+  template<typename U>
+    void f(U) {} // { dg-line Cf }
+
+  template<typename U>
+    void g() {} // { dg-line Cg }
+};
+
+int main()
+{
+  A<int>().f(0); // { dg-error "no matching function for call to 'A<int>::f\\(int\\)'" }
+  // { dg-message "candidate: 'template<class U> void A<int>::f\\(\\)'" "" { target *-*-* } Af }
+
+  A<int>().g(); // { dg-error "no matching function for call to 'A<int>::g\\(\\)'" }
+  // { dg-message "candidate: 'template<class U> void A<int>::g\\(U\\)'" "" { target *-*-* } Ag }
+
+  B<int>().f(); // { dg-error "no matching function for call to 'B<int>::f\\(\\)'" }
+  // { dg-message "candidate: 'template<class U> void B<int>::f\\(U\\)'" "" { target *-*-* } Bf }
+
+  B<int>().g(); // { dg-error "no matching function for call to 'B<int>::g\\(\\)'" }
+  // { dg-message "candidate: 'template<class U> void B<int>::g\\(U, int\\)'" "" { target *-*-* } Bg }
+
+  B<float>().g(0); // { dg-error "no matching function for call to 'B<float>::g\\(int\\)'" }
+  // { dg-message "candidate: 'template<class U> void B<float>::g\\(U, float\\)'" "" { target *-*-* } Bg }
+
+  C().f(); // { dg-error "no matching function for call to 'C::f\\(\\)'" }
+  // { dg-message "candidate: 'template<class U> void C::f\\(U\\)'" "" { target *-*-* } Cf }
+
+  C().g(0); // { dg-error "no matching function for call to 'C::g\\(int\\)'" }
+  // { dg-message "candidate: 'template<class U> void C::g\\(\\)'" "" { target *-*-* } Cg }
+}
diff --git a/gcc/testsuite/g++.dg/diagnostic/pr100716.C b/gcc/testsuite/g++.dg/diagnostic/pr100716.C
new file mode 100644 (file)
index 0000000..4a1f0a4
--- /dev/null
@@ -0,0 +1,54 @@
+// { dg-options "-fpretty-templates" }
+
+template<typename T>
+  struct A
+  {
+    template<typename U>
+      void f() {} // { dg-line Af }
+
+    template<typename U>
+      void g(U) {} // { dg-line Ag }
+  };
+
+template<typename T>
+  struct B
+  {
+    template<typename U>
+      void f(U) {} // { dg-line Bf }
+
+    template<typename U>
+      void g(U, T) {} // { dg-line Bg }
+  };
+
+struct C
+{
+  template<typename U>
+    void f(U) {} // { dg-line Cf }
+
+  template<typename U>
+    void g() {} // { dg-line Cg }
+};
+
+int main()
+{
+  A<int>().f(0); // { dg-error "no matching function for call to 'A<int>::f\\(int\\)'" }
+  // { dg-message "candidate: 'template<class U> void A<T>::f\\(\\) \\\[with T = int\\\]'" "" { target *-*-* } Af }
+
+  A<int>().g(); // { dg-error "no matching function for call to 'A<int>::g\\(\\)'" }
+  // { dg-message "candidate: 'template<class U> void A<T>::g\\(U\\) \\\[with T = int\\\]'" "" { target *-*-* } Ag }
+
+  B<int>().f(); // { dg-error "no matching function for call to 'B<int>::f\\(\\)'" }
+  // { dg-message "candidate: 'template<class U> void B<T>::f\\(U\\) \\\[with T = int\\\]'" "" { target *-*-* } Bf }
+
+  B<int>().g(); // { dg-error "no matching function for call to 'B<int>::g\\(\\)'" }
+  // { dg-message "candidate: 'template<class U> void B<T>::g\\(U, T\\) \\\[with T = int\\\]'" "" { target *-*-* } Bg }
+
+  B<float>().g(0); // { dg-error "no matching function for call to 'B<float>::g\\(int\\)'" }
+  // { dg-message "candidate: 'template<class U> void B<T>::g\\(U, T\\) \\\[with T = float\\\]'" "" { target *-*-* } Bg }
+
+  C().f(); // { dg-error "no matching function for call to 'C::f\\(\\)'" }
+  // { dg-message "candidate: 'template<class U> void C::f\\(U\\)'" "" { target *-*-* } Cf }
+
+  C().g(0); // { dg-error "no matching function for call to 'C::g\\(int\\)'" }
+  // { dg-message "candidate: 'template<class U> void C::g\\(\\)'" "" { target *-*-* } Cg }
+}