On 11/17/21 04:04, Matthias Kretz wrote:
On Wednesday, 17 November 2021 07:09:18 CET Jason Merrill wrote:
-  if (CHECKING_P)
-    SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (a, TREE_VEC_LENGTH (a));
+  SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (a, nondefault);

should have been

if (CHECKING_P || nondefault != TREE_VEC_LENGTH (a))
    SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (a, nondefault);

TBH, I don't understand the purpose of CHECKING_P here, or rather it makes me
nervous because AFAIU I'm only testing with CHECKING_P enabled. Why make
behavior dependent on CHECKING_P? I expected CHECKING_P to basically only add
more assertions.

The idea when NON_DEFAULT_TEMPLATE_ARGS_COUNT was added years back was to leave the TREE_CHAIN null when !CHECKING_P and treat that as equivalent to TREE_VEC_LENGTH (args). But perhaps you're right that it's not a savings worth the complexity.

(copy_template_args): Jason?

Only copy the non-default template args count on TREE_VECs that should
have it.

Why not simply set the count on all args? Is it a performance concern? The
INTEGER_CST the TREE_CHAIN has to point to exists anyway, so it's not wasting
any memory, right?

In this case the TREE_VEC we're excluding is the one wrapping multiple levels of template args; it doesn't contain args directly, so setting NON_DEFAULT_ARGS_COUNT on it doesn't make sense.

+  /* Pretty print only template instantiations. Don't pretty print
explicit
+     specializations like 'template <> void fun<int> (int)'.

This seems like a significant change of behavior unrelated to printing
default template arguments.  What's the rationale for handling
specializations differently from instantiations?

Right, this is about "The general idea of this change is to print template
parms wherever they would appear in the source code as well".

Initially, the change to print function template arguments/parameters only if
the args were explicitly specified lead to printing 'void fun (T) [with T =
...]' or 'template <> void fun (int)'. Both are not telling the full story,
even if the former is how the function would be called.

and the latter is how I expect the specialization to be declared, not with the deducible template argument made explicit.

But if the reader
should quickly recognize what code is getting called, it is helpful to see
right away that a function template specialization is called. (It might also
reveal an implementation detail of a library, so it's not 100% obvious how to
choose here.) Also, saying 'T = int' is kind of wrong. Yes, 'int' was deduced.
But there's no T in fun<int>:

template <class T> void fun (T);
template <> void fun<int> (int);

There's a T in the template, and as you said above, that's how it's called (and mangled).

__FUNCTION__ was 'fun<int>' all the time, but __PRETTY_FUNCTION__ was 'void
fun(T) [with T = int]'.

Isn't that true for instantiations, as well?

It's more consistent that __PRETTY_FUNCTION__ contains __FUNCTION__, IMHO

I suppose, but I don't see that as a strong enough motivation to mix this up.

so it would have to be at least 'void fun<int>(T) [with T
= int]'. But that's strange: How it uses T and int for the same type. So I
settled on 'void fun<int>(int)'.

I also don't understand the purpose of TFF_AS_PRIMARY.

dump_function_decl generalizes the TEMPLATE_DECL (if flag_pretty_templates is
true) and, before this change, passes the generalized TEMPLATE_DECL to
dump_type (... DECL_CONTEXT (t) ...) and dump_function_name (... t ...).
That's why the whole template is printed as primary template (i.e. with
template parms instead of template args, as is needed for
flag_pretty_templates). But this drops the count of non-default template args.

Ah, you're trying to omit defaulted parms from the <list>? I'm not sure that's necessary, leaving them out of the [with ...] list should be sufficient.

To retain the count, dump_type and dump_function_name need to be called with
the original TEMPLATE_DECL. But if I do this, pretty-templates is broken.
'template <class T> struct A { template <class U> void f(T, U); };' would
print as 'A<int>::f<float>(T, U) [with U = float, T = int]'. To get back to
'A<T>::f<U>(T, U) [with U = float, T = int]' I needed to tell
dump_template_parms that even though the template args are there, it should
print only the template parms. The most obvious way to do that was to carry it
through via flags.

Note that this creates another problem. Given

template <class T0, class T1 = int> struct Outer {
   template <class T, class U> struct A;
   template <class X> struct A<X, int> {
     void f();
   };
};

we want to print e.g. 'void Outer<T0>::A<X, int>::f() [with X = int, T0 =
int]', but certainly not 'void Outer<T0>::A<T, U>::f() [with X = int, T0 =
int]'. However, specialized_t holds A<int, int> which is printed as A<T, U>
with TFF_AS_PRIMARY. Only most_general_template of the function's
TEMPLATE_DECL can give us A<X, int> as DECL_CONTEXT.

I have a solution in the diagnose_as patch, where I had to solve a similar
problem because for the diagnose_as attribute (dump_template_scope).

+/* Print function template parameters if:
+   1. t is template, and
+   2. flags did not request "show only template-name", and
+   3. t is a specialization of a template (Why is this needed? This was
present +      since 1999 via !DECL_FRIEND_PSEUDO_TEMPLATE_INSTANTIATION:
"Don't crash if +      given a friend pseudo-instantiation". The
DECL_USE_TEMPLATE should likely +      inform the PRIMARY parameter of
dump_template_parms.), and

Good question.  It seems that the existing
!DECL_FRIEND_PSEUDO_TEMPLATE_INSTANTIATION has mostly been excluding the
most general template; removing that line changes things like

int bar(T) [with T = int]

to

int bar<T>(T) [with T = int]



+   4. either
+      - flags requests to show no function arguments, in which case
deduced +        types could be hidden, or
+      - at least one function template argument was given explicitly, or
+      - we're printing a DWARF name,

...but perhaps this can replace the above.

I'll rerun the tests with DECL_USE_TEMPLATE moved to the PRIMARY parameter of
dump_template_parms.

Though, why do we want
different behavior here when printing a DWARF name?

Sorry, I should have asked ... I also added the same issue as an open question
on the diagnose_as patch. When I ran the whole testsuite I had failures in the
DWARF tests. This change resolved them. I don't know enough about how those
strings are used and whether they may change between GCC versions. Anyway, the
DWARF strings in that test had only the function name and template argument
list (i.e. no function arguments).

If they only have arguments, isn't TFF_NO_FUNCTION_ARGUMENTS set?

If the template argument list was removed
(as was the case without the condition here), the DWARF strings lost important
information, giving several different functions the same name. That seemed
like a regression. So either the DWARF strings need to include the function
arguments, or we need this condition to keep showing the template arguments
independent of whether they were explicitly given or not.

+   5. either
+      - t is a member friend template of a template class (see
DECL_TI_TEMPLATE +        documentation), or
+      -

Missing the last item.  :)

Oh, I got distracted while trying to figure this out. :) I'll try to
understand why PRIMARY_TEMPLATE_P (DECL_TI_TEMPLATE (t)) is needed and
document it.


Reply via email to