On 7/23/21 4:58 AM, Matthias Kretz wrote:
Hi Jason,

I found a few regressions from the last patch in the meantime. Version 4 of
the patch is attached.

Questions:

1. I simplified the condition for calling dump_template_parms in
dump_function_name. !DECL_FRIEND_PSEUDO_TEMPLATE_INSTANTIATION (t) is
equivalent to DECL_USE_TEMPLATE (t) in this context; implying that
dump_template_parms is unconditionally called with `primary = false`. Or am I
missing something?

2. Given a DECL_TI_ARGS tree, can I query whether an argument was deduced or
explicitly specified? I'm asking because I still consider diagnostics of
function templates unfortunate. `template <class T> void f()` is fine, as is
`void f(T) [with T = float]`, but `void f() [with T = float]` could be better.
I.e. if the template parameter appears somewhere in the function parameter
list, dump_template_parms would only produce noise. If, however, the template
parameter was given explicitly, it would be nice if it could show up
accordingly in diagnostics.

3. When parsing tentatively and the parse is rejected, input_location is not
reset, correct? In the attached patch I therefore made
cp_parser_namespace_alias_definition reset input_location on a failed
tentative parse. But it feels wrong. Shouldn't input_location be restored on
cp_parser_parse_definitely?

--

This attribute overrides the diagnostics output string for the entity it
appertains to. The motivation is to improve QoI for library TS
implementations, where diagnostics have a very bad signal-to-noise ratio
due to the long namespaces involved.

With the attribute, it is possible to solve PR89370 and make
std::__cxx11::basic_string<_CharT, _Traits, _Alloc> appear as
std::string in diagnostic output without extra hacks to recognize the
type in the C++ frontend.

Signed-off-by: Matthias Kretz <m.kr...@gsi.de>

gcc/ChangeLog:

         PR c++/89370
         * doc/extend.texi: Document the diagnose_as attribute.
         * doc/invoke.texi: Document -fno-diagnostics-use-aliases.

gcc/c-family/ChangeLog:

         PR c++/89370
         * c.opt (fdiagnostics-use-aliases): New diagnostics flag.

gcc/cp/ChangeLog:

         PR c++/89370
         * cp-tree.h: Add is_alias_template_p declaration.
         * decl2.c (is_alias_template_p): New function. Determines
         whether a given TYPE_DECL is actually an alias template that is
         still missing its template_info.

I still think you want to share code with get_underlying_template. For the case where the alias doesn't have DECL_TEMPLATE_INFO yet, you can compare to current_template_args (). Or you could do some initial processing that doesn't care about templates in the handler, and then do more in cp_parser_alias_declaration after the call to grokfield/start_decl.

If you still think you need this function, let's call it is_renaming_alias_template or renaming_alias_template_p; using both is_ and _p is redundant. I don't have a strong preference which.

         (is_late_template_attribute): Decls with diagnose_as attribute
         are early attributes only if they are alias templates.

Is there a reason not to apply it early to other templates as well?

         * error.c (dump_scope): When printing the name of a namespace,
         look for the diagnose_as attribute. If found, print the
         associated string instead of calling dump_decl.

Did you decide not to handle this in dump_decl, so we use the diagnose_as when referring to the namespace in non-scope contexts as well?

         (dump_decl_name_or_diagnose_as): New function to replace
         dump_decl (pp, DECL_NAME(t), flags) and inspect the tree for the
         diagnose_as attribute before printing the DECL_NAME.

+  if (flag_diagnostics_use_aliases)
+    {
+      tree attr = lookup_attribute ("diagnose_as", DECL_ATTRIBUTES (decl));
+      if (attr && TREE_VALUE (attr))
+       {
+         pp_cxx_ws_string (
+           pp, TREE_STRING_POINTER (TREE_VALUE (TREE_VALUE (attr))));

This pattern is used several places outside this function; can we factor it into something like

if (maybe_print_diagnose_as (special))
  /* OK */;

?

         (dump_template_scope): New function. Prints the scope of a
         template instance correctly applying diagnose_as attributes and
         adjusting the list of template parms accordingly.

+      const bool tmplate
+       = TYPE_LANG_SPECIFIC (special) && CLASSTYPE_TEMPLATE_INFO (special)
+           && (TREE_CODE (CLASSTYPE_TI_TEMPLATE (special)) != TEMPLATE_DECL
+                 || PRIMARY_TEMPLATE_P (CLASSTYPE_TI_TEMPLATE (special)));

CLASSTYPE_SPECIALIZATION_OF_PRIMARY_TEMPLATE_P?

+                          tmplate ? &TREE_CHAIN(*parms) : parms, flags);

Missing space before (

+         if (tmplate)
+           TREE_VALUE (*parms) = make_tree_vec (0);

This could use a comment.

         (dump_aggr_type): If the type has a diagnose_as attribute, print
         the associated string instead of printing the original type
         name. Print template parms only if the attribute was not applied
         to the instantiation / full specialization. Delay call to
         dump_scope until the diagnose_as attribute is found. If the
         attribute has a second argument, use it to override the context
         passed to dump_scope.

+             for (int i = 0; i < NUM_TMPL_ARGS (args); ++i)
+               {
+                 tree arg = TREE_VEC_ELT (args, i);
+                 while (INDIRECT_TYPE_P (arg))
+                   arg = TREE_TYPE (arg);
+                 if (WILDCARD_TYPE_P (arg))
+                   {
+                     tmplate = true;
+                     break;
+                   }
+               }

I think you want any_dependent_template_args_p (args)

Checking WILDCARD_TYPE_P is generally not what you want; plenty of dependent types don't show up specifically as wildcards. T*, for instance.

+  if (diagnose_as)
+    pp_cxx_ws_string (pp, TREE_STRING_POINTER (
+                           TREE_VALUE (TREE_VALUE (diagnose_as))));

( needs to go on the next line.  I'd format this as

if (diagnose_as)
  pp_cxx_ws_string (pp, (TREE_STRING_POINTER
                         (TREE_VALUE (TREE_VALUE (diagnose_as)))));

There's a lot of this formatting pattern in the patch.

         (dump_simple_decl): Call dump_decl_name_or_diagnose_as instead
         of dump_decl.
         (dump_decl): Ditto.

+         dump_decl_name_or_diagnose_as(pp, t, flags);

Missing space before (

         (lang_decl_name): Ditto.
         (dump_function_decl): Walk the functions context list to
         determine whether a call to dump_template_scope is required.
         Ensure function templates diagnosed with pretty templates set
         TFF_TEMPLATE_NAME to skip dump_template_parms.
         (dump_function_name): Replace the function's identifier with the
         diagnose_as attribute value, if set. Expand
         DECL_FRIEND_PSEUDO_TEMPLATE_INSTANTIATION to DECL_USE_TEMPLATE
         and consequently call dump_template_parms with primary = false.
         (comparable_template_types_p): Consider the types not a template
         if one carries a diagnose_as attribute.

I'd think it would be more helpful to suppress diagnose_as if the types are comparable.

         (print_template_differences): Replace the identifier with the
         diagnose_as attribute value on the most general template, if it
         is set.
         * name-lookup.c (handle_namespace_attrs): Handle the diagnose_as
         attribute on namespaces. Ensure exactly one string argument.
         Ensure previous diagnose_as attributes used the same name.
         'diagnose_as' on namespace aliases are forwarded to the original
         namespace. Support no-argument 'diagnose_as' on namespace
         aliases.
         (do_namespace_alias): Add attributes parameter and call
         handle_namespace_attrs.
         * name-lookup.h (do_namespace_alias): Add attributes tree
         parameter.
         * parser.c (cp_parser_declaration): If the next token is
         RID_NAMESPACE, tentatively parse a namespace alias definition.
         If this fails expect a namespace definition.
         (cp_parser_namespace_alias_definition): Allow optional
         attributes before and after the identifier. Fast exit, restoring
         input_location, if the expected CPP_EQ token is missing. Pass
         attributes to do_namespace_alias.

+  if (attributes
+       && !cp_parser_uncommitted_to_tentative_parse_p (parser))
+    pedwarn (input_location, OPT_Wpedantic,
+            "standard attributes on namespaces aliases must follow "
+            "the namespace alias name");

Maybe remember where we saw attributes and warn later, after we've committed to parsing as an alias. Or use cp_parser_skip_attributes_opt to avoid tentative parsing in the first place.

+  if (nullptr == cp_parser_require (parser, CPP_EQ, RT_EQ))

The usual pattern is

 if (!cp_parser_require

         * tree.c (cxx_attribute_table): Add diagnose_as attribute to the
         table.
         (check_diagnose_as_redeclaration): New function; copied and
         adjusted from check_abi_tag_redeclaration.
         (handle_diagnose_as_attribute): New function; copied and
         adjusted from handle_abi_tag_attribute. If the given *node is a
         TYPE_DECL: allow no argument to the attribute, using DECL_NAME
         instead; apply the attribute to the type on the RHS in place,
         even if the type is complete. Allow 2 arguments when called from
         handle_diagnose_as_attribute. For type aliases, append
         CP_DECL_CONTEXT as second attribute argument when the RHS type
         has a different context. Warn about alias templates without
         matching template arguments. Apply the attribute to the primary
         template type for alias templates.

All this description of semantics should be in a comment rather than the CHangeLog.

+      /* Reject alias templates without wildcards on the innermost template arg
s
+         of the RHS type. E.g. template <class> using A = B;  */
+      if (DECL_LANG_SPECIFIC (decl)
+           && DECL_TEMPLATE_INFO (decl)
+           && DECL_ALIAS_TEMPLATE_P (DECL_TI_TEMPLATE (decl))
+           && PRIMARY_TEMPLATE_P (DECL_TI_TEMPLATE (decl)))
+       return error_mark_node;

I don't think this is doing anything useful; if we had already done push_template_decl by this point, it would reject all alias templates.

+      // Add the DECL_CONTEXT of the alias to the attribute if it is different
+      // to the context of the type.

How about using the alias TYPE_DECL itself as the argument to the attribute on the type? Then we wouldn't need to copy its name into a string, either.

gcc/testsuite/ChangeLog:

         PR c++/89370
         * g++.dg/diagnostic/diagnose-as1.C: New test.
         * g++.dg/diagnostic/diagnose-as2.C: New test.
         * g++.dg/diagnostic/diagnose-as3.C: New test.
         * g++.dg/diagnostic/diagnose-as4.C: New test.
         * g++.dg/diagnostic/diagnose-as5.C: New test.
         * g++.dg/diagnostic/diagnose-as6.C: New test.
---
  gcc/c-family/c.opt                            |   4 +
  gcc/cp/cp-tree.h                              |   1 +
  gcc/cp/decl2.c                                |  45 ++++
  gcc/cp/error.c                                | 247 ++++++++++++++++--
  gcc/cp/name-lookup.c                          |  52 +++-
  gcc/cp/name-lookup.h                          |   2 +-
  gcc/cp/parser.c                               |  41 +--
  gcc/cp/tree.c                                 | 148 +++++++++++
  gcc/doc/extend.texi                           |  45 ++++
  gcc/doc/invoke.texi                           |   9 +-
  .../g++.dg/diagnostic/diagnose-as1.C          | 213 +++++++++++++++
  .../g++.dg/diagnostic/diagnose-as2.C          | 144 ++++++++++
  .../g++.dg/diagnostic/diagnose-as3.C          | 152 +++++++++++
  .../g++.dg/diagnostic/diagnose-as4.C          | 158 +++++++++++
  .../g++.dg/diagnostic/diagnose-as5.C          |  21 ++
  .../g++.dg/diagnostic/diagnose-as6.C          |  45 ++++
  16 files changed, 1291 insertions(+), 36 deletions(-)
  create mode 100644 gcc/testsuite/g++.dg/diagnostic/diagnose-as1.C
  create mode 100644 gcc/testsuite/g++.dg/diagnostic/diagnose-as2.C
  create mode 100644 gcc/testsuite/g++.dg/diagnostic/diagnose-as3.C
  create mode 100644 gcc/testsuite/g++.dg/diagnostic/diagnose-as4.C
  create mode 100644 gcc/testsuite/g++.dg/diagnostic/diagnose-as5.C
  create mode 100644 gcc/testsuite/g++.dg/diagnostic/diagnose-as6.C


Reply via email to