[PATCH 1/2] C++ template type diff printing
David Malcolm
dmalcolm@redhat.com
Mon May 8 16:58:00 GMT 2017
On Mon, 2017-05-08 at 07:36 -0400, Nathan Sidwell wrote:
> On 05/04/2017 07:44 PM, David Malcolm wrote:
> > This patch kit implements two new options to make it easier
> > to read diagnostics involving mismatched template types:
> > -fdiagnostics-show-template-tree and
> > -fno-elide-type.
> >
> > It adds two new formatting codes: %H and %I which are
> > equivalent to %qT, but are to be used together for type
> > comparisons e.g.
> > "can't convert from %H to %I".
>
> While I can see why one might want %H and %I to imply quoting, it
> seems
> confusingly inconsistent with the other formatters, which require an
> explicit 'q'.
This an implementation detail leaking through, but I *think* it's
fixable.
The implementation has to jump through some hoops to interact with
pp_format, because the two codes interact with each other: in order to
elide commonality and colorize differences we can't start printing the
%H until we've seen the %I (vice versa should work also).
The 'q' for quoting the next format code happens in the 2nd phase of
pp_format: if 'q' is present, then a quote (and potentially
colorization) is emitted to the chunk for the item before and after the
item's main content is emitted to the chunk.
To make the interaction of %H and %I work, we have to delay the writing
to the chunk to a new phase between phases 2 and 3 (and stash a pointer
to the chunk we're going to write to).
As written, if one uses '%qH' and '%qI', then phase 2 writes the open
and close quotes to the chunks, and then the delayed handler blows that
away and overwrites the chunk content with (forcibly) quoted content
for the types.
So I think it can work if we add a "needs quoting" flag to the
postprocessing phase, if we need to handle the case where %H and %I
ever appear without 'q' (and have the delayed handling stash that flag,
and do the quoting there).
I'll look at implementing that.
> > rather than printing:
> >
> > could not convert 'std::map<int, std::vector<double> >()'
> > from 'std::map<int, std::vector<double> >' to 'std::map<int,
> > std::vector<float> >'
> >
> > with -felide-type (the default), it prints:
> >
> > could not convert 'std::map<int, std::vector<double> >()'
> > from 'map<[...],vector<double>>' to 'map<[...],vector<float>>
>
> Neat.
>
> Is '-felide-type' a good name? Wouldn't something like
> '-fdiagnostic-elide-template-args' be better?
Here I'm merely copying clang's option name.
http://clang.llvm.org/docs/UsersManual.html#cmdoption-fno-elide-type
> > With -fdiagnostics-show-template-tree a tree-like structure of the
> > template is printed, showing the differences; in this case:
>
> 'tree' sounds implementor-speaky, Perhaps
> '-fdiagnostic-expand-template-args' or something?
As Jason noted, this is a user-visible thing that's tree-like, rather
than our "tree" type.
Also, I'm (shamelessly) copying clang's name for this.
> Right, bikeshedding out of the way ...
>
> > --- a/gcc/cp/error.c
> > +++ b/gcc/cp/error.c
> > @@ -99,7 +99,47 @@ static void cp_diagnostic_starter
> > (diagnostic_context *, diagnostic_info *);
> > static void cp_print_error_function (diagnostic_context *,
> > diagnostic_info *);
> >
>
> > +
> > +/* Return true iff TYPE_A and TYPE_B are template types that are
> > + meaningful to compare. */
> > +
> > +static bool
> > +comparable_template_types_p (tree type_a, tree type_b)
> > +{
> > + if (TREE_CODE (type_a) != RECORD_TYPE)
> > + return false;
> > + if (TREE_CODE (type_b) != RECORD_TYPE)
> > + return false;
>
> CLASS_TYPE_P (type_a) etc?
I'll use this in the next version.
> > + int len_max = MAX (len_a, len_b);
> > + for (int idx = 0; idx < len_max; idx++)
> > + {
> > + tree arg_a = idx < len_a ? TREE_VEC_ELT (args_a, idx) :
> > NULL;
> > + tree arg_b = idx < len_b ? TREE_VEC_ELT (args_b, idx) :
> > NULL;
> > + if (arg_a == arg_b)
>
> Should this use same_type_p for types? If direct comparison is
> correct,
> a comment would help.
What about non-type template arguments? That said, I just tried one,
and it's handled poorly by my patch. I'll try to address for the next
version.
> > + Only non-default template arguments are printed. */
> > +
> > +static void
> > +print_template_tree_comparison (pretty_printer *pp, tree type_a,
> > tree type_b,
>
> > + for (int idx = 0; idx < len_max; idx++)
> > + {
> > + tree arg_a = idx < len_a ? TREE_VEC_ELT (args_a, idx) :
> > NULL;
> > + tree arg_b = idx < len_b ? TREE_VEC_ELT (args_b, idx) :
> > NULL;
> > + if (arg_a == arg_b)
>
> Same question. If these have to be comparable template type, when
> can
> len_a and len_b be different?
I guess I was thinking about variadic templates. I'll have another
look at how these are handled.
> > + This is called in phase 2 of pp_format, when it is accumulating
> > + a series of formatted chunks. We stash the location of the
> > chunk
> > + we're meant to have written to, so that we can write to it in
> > the
> > + m_format_postprocessor hook. */
> > +
> > +static void
> > +defer_half_of_type_diff (pretty_printer *pp, char spec, tree type,
>
> If this is called 'phase 2' why not name the function for that,
> rather
> than 'half'?
Maybe I should have used "peer" rather than "half": I'm attempting to
refer to one of the two peer types being compared - half of the
comparison.
> > + case 'H':
> > + case 'I':
> > + {
> > + defer_half_of_type_diff (pp, *spec, next_tree, buffer_ptr,
> > verbose);
>
> Why not tell defer_half_of_type_diff whether it's doing the %H bit or
> the %I bit directly, rather than have it also check for H and I?
OK.
> I've not looked more than cursorily at the non C++ bits.
>
> nathan
Thanks for the input. I'm working on an updated version.
Dave
More information about the Gcc-patches
mailing list