Patchwork C++ PATCH to improve pretty-printing of function calls

login
register
mail settings
Submitter Jason Merrill
Date July 4, 2011, 9:35 p.m.
Message ID <4E123210.8090807@redhat.com>
Download mbox | patch
Permalink /patch/103170/
State New
Headers show

Comments

Jason Merrill - July 4, 2011, 9:35 p.m.
Before this patch, GCC described the candidate as

template<int N> decltype (((TypeC*)this)->TypeC::b.template<int U> 
typename TypeA<U>::type TypeB::fn [with int U = U, int N = 10, typename 
TypeA<U>::type = TypeA<U>::type]()) TypeC::fn()

after the patch, it's

template<int N> decltype (((TypeC*)this)->TypeC::b.fn<N>()) TypeC::fn()

it doesn't make any sense to have the template header or return type in 
the middle of an expression, nor to have the [with ...] template bindings.

Tested x86_64-pc-linux-gnu, applying to trunk.
Gabriel Dos Reis - July 4, 2011, 9:41 p.m.
Jason Merrill <jason@redhat.com> writes:

| Before this patch, GCC described the candidate as
| 
| template<int N> decltype (((TypeC*)this)->TypeC::b.template<int U>
| typename TypeA<U>::type TypeB::fn [with int U = U, int N = 10,
| typename TypeA<U>::type = TypeA<U>::type]()) TypeC::fn()

ouch!

| after the patch, it's
| 
| template<int N> decltype (((TypeC*)this)->TypeC::b.fn<N>()) TypeC::fn()
| 
| it doesn't make any sense to have the template header or return type
| in the middle of an expression, nor to have the [with ...] template
| bindings.

agreed.  Thanks!

-- Gaby

Patch

commit 70816c82793a089f530a0df105c129aa9f6dfa65
Author: Jason Merrill <jason@redhat.com>
Date:   Sun Jul 3 17:25:40 2011 -0400

    	* error.c (dump_template_bindings): Don't print typenames
    	for a partial instantiation.
    	(dump_function_decl): If we aren't printing function arguments,
    	print template arguments as <args> rather than [with ...].
    	(dump_expr): Don't print return type or template header.
    	[BASELINK]: Use BASELINK_FUNCTIONS rather than get_first_fn.
    	* pt.c (dependent_template_arg_p): Handle null arg.

diff --git a/gcc/cp/error.c b/gcc/cp/error.c
index 664b918..b16fce6 100644
--- a/gcc/cp/error.c
+++ b/gcc/cp/error.c
@@ -307,9 +307,12 @@  dump_template_bindings (tree parms, tree args, VEC(tree,gc)* typenames)
       parms = TREE_CHAIN (parms);
     }
 
+  /* Don't bother with typenames for a partial instantiation.  */
+  if (VEC_empty (tree, typenames) || uses_template_parms (args))
+    return;
+
   FOR_EACH_VEC_ELT (tree, typenames, i, t)
     {
-      bool dependent = uses_template_parms (args);
       if (need_comma)
 	pp_separate_with_comma (cxx_pp);
       dump_type (t, TFF_PLAIN_IDENTIFIER);
@@ -317,11 +320,7 @@  dump_template_bindings (tree parms, tree args, VEC(tree,gc)* typenames)
       pp_equal (cxx_pp);
       pp_cxx_whitespace (cxx_pp);
       push_deferring_access_checks (dk_no_check);
-      if (dependent)
-	++processing_template_decl;
       t = tsubst (t, args, tf_none, NULL_TREE);
-      if (dependent)
-	--processing_template_decl;
       pop_deferring_access_checks ();
       /* Strip typedefs.  We can't just use TFF_CHASE_TYPEDEF because
 	 pp_simple_type_specifier doesn't know about it.  */
@@ -1379,17 +1378,37 @@  dump_function_decl (tree t, int flags)
 
       if (show_return)
 	dump_type_suffix (TREE_TYPE (fntype), flags);
-    }
 
-  /* If T is a template instantiation, dump the parameter binding.  */
-  if (template_parms != NULL_TREE && template_args != NULL_TREE)
+      /* If T is a template instantiation, dump the parameter binding.  */
+      if (template_parms != NULL_TREE && template_args != NULL_TREE)
+	{
+	  pp_cxx_whitespace (cxx_pp);
+	  pp_cxx_left_bracket (cxx_pp);
+	  pp_cxx_ws_string (cxx_pp, M_("with"));
+	  pp_cxx_whitespace (cxx_pp);
+	  dump_template_bindings (template_parms, template_args, typenames);
+	  pp_cxx_right_bracket (cxx_pp);
+	}
+    }
+  else if (template_args)
     {
-      pp_cxx_whitespace (cxx_pp);
-      pp_cxx_left_bracket (cxx_pp);
-      pp_cxx_ws_string (cxx_pp, M_("with"));
-      pp_cxx_whitespace (cxx_pp);
-      dump_template_bindings (template_parms, template_args, typenames);
-      pp_cxx_right_bracket (cxx_pp);
+      bool need_comma = false;
+      int i;
+      pp_cxx_begin_template_argument_list (cxx_pp);
+      template_args = INNERMOST_TEMPLATE_ARGS (template_args);
+      for (i = 0; i < TREE_VEC_LENGTH (template_args); ++i)
+	{
+	  tree arg = TREE_VEC_ELT (template_args, i);
+	  if (need_comma)
+	    pp_separate_with_comma (cxx_pp);
+	  if (ARGUMENT_PACK_P (arg))
+	    pp_cxx_left_brace (cxx_pp);
+	  dump_template_argument (arg, TFF_PLAIN_IDENTIFIER);
+	  if (ARGUMENT_PACK_P (arg))
+	    pp_cxx_right_brace (cxx_pp);
+	  need_comma = true;
+	}
+      pp_cxx_end_template_argument_list (cxx_pp);
     }
 }
 
@@ -1724,7 +1743,9 @@  dump_expr (tree t, int flags)
     case OVERLOAD:
     case TYPE_DECL:
     case IDENTIFIER_NODE:
-      dump_decl (t, (flags & ~TFF_DECL_SPECIFIERS) | TFF_NO_FUNCTION_ARGUMENTS);
+      dump_decl (t, ((flags & ~(TFF_DECL_SPECIFIERS|TFF_RETURN_TYPE
+				|TFF_TEMPLATE_HEADER))
+		     | TFF_NO_FUNCTION_ARGUMENTS));
       break;
 
     case INTEGER_CST:
@@ -2289,7 +2310,7 @@  dump_expr (tree t, int flags)
       break;
 
     case BASELINK:
-      dump_expr (get_first_fn (t), flags & ~TFF_EXPR_IN_PARENS);
+      dump_expr (BASELINK_FUNCTIONS (t), flags & ~TFF_EXPR_IN_PARENS);
       break;
 
     case EMPTY_CLASS_EXPR:
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 7236e7e..e7be08b 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -18848,7 +18848,7 @@  dependent_template_arg_p (tree arg)
      is dependent. This is consistent with what
      any_dependent_template_arguments_p [that calls this function]
      does.  */
-  if (arg == error_mark_node)
+  if (!arg || arg == error_mark_node)
     return true;
 
   if (TREE_CODE (arg) == ARGUMENT_PACK_SELECT)
diff --git a/gcc/testsuite/g++.dg/cpp0x/diag1.C b/gcc/testsuite/g++.dg/cpp0x/diag1.C
new file mode 100644
index 0000000..b3f30bc
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/diag1.C
@@ -0,0 +1,32 @@ 
+// { dg-options -std=c++0x }
+
+template <int U>
+struct TypeA
+{
+  typedef int type;
+};
+
+template <int N>
+struct TypeB
+{
+  template <int U> typename TypeA<U>::type fn();
+};
+
+struct TypeC
+{
+  TypeB<10> b;
+  // This was being printed as:
+  // template<int N>
+  //   decltype (((TypeC*)this)->
+  //             TypeC::b.
+  //             template<int U> typename TypeA<U>::type TypeB::fn [with int U = U, int N = 10, typename TypeA<U>::type = TypeA<U>::type]())
+  //   TypeC::fn()
+  // we don't want to see the template header, return type, or parameter bindings
+  // for TypeB::fn.
+  template <int N> auto fn() -> decltype(b.fn<N>()); // { dg-bogus "typename|with" }
+};
+
+int main()
+{
+  TypeC().fn<4>(1);		// { dg-error "no match" }
+}