On 11/19/21 04:53, Matthias Kretz wrote:
On Thursday, 18 November 2021 20:24:36 CET Jason Merrill wrote:
On 11/17/21 17:51, Matthias Kretz wrote:
Right, I had already added a `gcc_assert (!TMPL_ARGS_HAVE_MULTIPLE_LEVELS
(args))` to my new set_non_default_template_args_count function and found
cp/ constraint.cc:2896 (get_mapped_args), which calls
SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT on the outer TREE_VEC. Was this
supposed to apply to all inner TREE_VECs? Or is deleting the line the
correct fix?

That should apply to the inner TREE_VECs (and probably use list.length)

Like this?

Yes.

@@ -2890,10 +2890,11 @@ get_mapped_args (tree map)
        tree level = make_tree_vec (list.length ());
        for (unsigned j = 0; j < list.length(); ++j)
          TREE_VEC_ELT (level, j) = list[j];
+      /* None of the args at any level are defaulted.  */
+      SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (level, list.length());
        SET_TMPL_ARGS_LEVEL (args, i + 1, level);
        list.release ();
      }
-  SET_NON_DEFAULT_TEMPLATE_ARGS_COUNT (args, 0);

    return args;
  }

__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?

No, instantiations don't have template args/parms in __FUNCTION__.

Hmm, that inconsistency seems like a bug, though I'm not sure whether it
should have the template args or not; I lean toward not.  The standard
says that the value of __func__ is implementation-defined, the GCC
manual says it's "the unadorned name of the function".

So you think f1<int> in testsuite/g++.old-deja/g++.ext/pretty3.C needs to test
for

   if (strcmp (function, "f1"))
     bad = true;
   if (strcmp (pretty, "void f1(T) [with T = int]"))
     bad = true;

I think so.

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.

What about

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

With -fpretty-templates shouldn't it print as 'void f<T>() [with T =
float]' and 'void f<int>()'? Yes, it's probably too subtle for most users
to notice the difference. But I find it's more consistent this way.

I disagree; the function signature is the same whether a particular
function is an explicit specialization or an instantiation.

Yes, the call signature is the same. But what it calls is different. There's
no obvious answer for my stated goal "print template parms wherever they
would appear in the source code as well", since it depends on whether the user
is interested in recognizing the exact function body that was called.

My motivation for printing a function template specialization differently is:

1. It's a different function definition that's being called. The user (caller)
might be surprised to realize this is the case as he forgot about the
specialization and was expecting his change to the general template to make a
difference.

2. There's no T in

template <> void f<int>() {
   // no T here, but of course I can define one:
   using T = int;
}

so presenting the function that was called as 'void f<T>() [with T = int]' is
not exactly correct. In this case it wasn't even the case that T was deduced
to be 'int', which we could argue to be useful information that might get
lost.

On the other hand, this tells us what template this specialization is specializing, which could be unclear if there are multiple overloaded function templates.

There's always -fno-pretty-templates if you want the form without template args.

Incidentally, the contents of __PRETTY_FUNCTION__ probably shouldn't vary with that flag...

For

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

the whole story is "'void f(int)' was called for 'template <class T> void f(T)
[with T = int]'". What the user wants to see depends on what is more important
to fix the bug: that T was deduced to be int, or that the specialization of f
was called instead of the general template. I'd still go with 'void f(int)',
though I'd be happier if I had some indication that a template was involved.

The current form tells you about the template, and the line number points you at the declaration.

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.

I was thinking about all the std::allocator defaults in the standard
library. I don't want to see them. E.g. vector<int>::clear() on const
object:

error: passing 'const std::vector<int>' as 'this' argument discards
qualifiers [...]/stl_vector.h:1498:7: note:   in call to 'void
std::vector<_Tp, _Alloc>::clear() [with _Tp = int; _Alloc =
std::allocator<int>]'

With my patch the last line becomes
[...]/stl_vector.h:1498:7: note:   in call to 'void
std::vector<_Tp>::clear() [with _Tp = int]'


Another case I didn't consider before:

template <class T, class U = int> struct A {

    [[deprecated]] void f(U);

};

A<float> a; a.f(1);

With my patch it prints 'void A<T>::f(U) [with T = float]', with your
suggestion 'void A<T, U>::f(U) [with T = float]'. Both are missing
important information in the substitution list, IMHO. Would 'void A<T, U
= int>::f(U) [with T = float]' be an improvement? Or should
find_typenames (in cp/error.c) find defaulted template parms and add them
to its list? IIUC find_typenames would find all template parms and
couldn't know whether they're defaulted.

That sounds good: omit defaulted parms only if they don't appear in the
signature (other than as another default template argument).

Let me check whether I have the right idea:

I could extend find_typenames (which walks the complete) tree to look for
TEMPLATE_TYPE_PARM (and the 3 others I don't recall right now). But since that
walks the *complete* tree, it'll simply find all parms with no indication
whether they appear in the signature. Ideas:

Hmm, since it walks DECL_TEMPLATE_RESULT, I wouldn't expect it to find template parms that aren't in the function signature.

1. Count occurrences: with 2 occurrences, one of them must be a use in the
signature.

2. Walk only over TYPE_ARG_TYPES (TREE_TYPE (DECL_TEMPLATE_RESULT (fn))) to
collect TEMPLATE_TYPE_PARMs.

Jason

Reply via email to