public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
From: Martin Sebor <msebor@gmail.com>
To: Matthias Kretz <m.kretz@gsi.de>, gcc-patches@gcc.gnu.org
Cc: libstdc++@gcc.gnu.org
Subject: Re: [PATCH] Add gnu::diagnose_as attribute
Date: Fri, 14 May 2021 10:05:03 -0600	[thread overview]
Message-ID: <ed879577-5cf0-9b5a-27a4-6f734bd85bc1@gmail.com> (raw)
In-Reply-To: <91863212.B8guWdUDZo@excalibur>

On 5/4/21 5:13 AM, Matthias Kretz wrote:
> From: Matthias Kretz<kretz@kde.org>
> 
> 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.

There are other mechanisms to change symbol names such as macros,
typedefs or alias or using declarations, and at the object level,
ELF aliases, and even the C++ ABI with its substitutions for types
like std::string and with the abi_tag attribute.

They all have a potential to cause some confusion when a symbol with
one name is referred to by another.  For the syntactic mechanisms
compilers usually deal with the problem by mentioning both the macro
or alias name and its expansion or target in the diagnostics they
issue.  The renaming prescribed by the C++ is reflected in the mangled
symbols that demanglers know how to decode and restore the their
originals.  For ELF aliases no such solution exists but they are
used only rarely by well-tested system code and so the different
names don't typically come up in compiler (or even linker)
diagnostics.  When they do, the names often share some common
prefix or suffix so the confusion is minimal.

I like the idea of printing names in diagnostics that are familiar
to users while leaving out implementation details that's in most
cases irrelevant to them.

At the same time, my concern with adding another syntactic renaming
mechanism that's specifically intended to change symbol names in
diagnostics (and the two macros) but nowhere else is that it would
considerably raise the risk of confusion between the name in
the source and the name in the diagnostic.  (E.g., one source
file renames symbol Foo to Bar but another one doesn't; messages
from one file will refer to Foo and other to Bar with no way of
knowing they're the same.  This could be solved by printing both
the renamed symbol and what it stands for (like for typedefs or
template instantiations) but that would then increase the S/R
ratio this solution is aimed at improving.  Providing an option
to disable the renaming is great but suffers from the same problem:
to be sure what symbol is being referred to, users would have to
disable the renaming.

It doesn't seem like we can have it both ways.  But maybe indicating
in some way when a symbol mentioned in a diagnostic is the result of
renaming by the attribute, without spelling out the original name,
would be a good enough compromise.  Though that won't help with
the same problem in the expansion of macros like __FUNCTION__.

Other than that, I have a couple of questions:

Are there any implementations that provide this attribute?  (If
so does the syntax and effects match?  It would be nice to be
compatible if possible.)

Does the attribute change the typeinfo strings?  If not, did you
consider the interplay between compile-time and runtime diagnostics
involving names decorated with the attribute?  (A related concern
is the runtime output of messages involving macros like
__FUNCTION__ issued from object files compiled by different
compilers or versions of the same compiler.)

Below are a few comments on the changes below, mostly focused on
the phrasing and style of diagnostic messages.  As others already
mentioned, the patch should include tests (including them early
in the review process helps get an idea of how the whole feature
works).

> 
> On Tuesday, 27 April 2021 11:46:48 CEST Jonathan Wakely wrote:
>> I think it's a great idea and would like to use it for all the TS
>> implementations where there is some inline namespace that the user
>> doesn't care about. std::experimental::fundamentals_v1:: would be much
>> better as just std::experimental::, or something like std::[LFTS]::.
> 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.
> 
> 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
> 	* 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.
> 	(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.
> 	(dump_aggr_type): If the type has a diagnose_as attribute, print
> 	the associated string instead of printing the original type
> 	name.
> 	(dump_simple_decl): Call dump_decl_name_or_diagnose_as instead
> 	of dump_decl.
> 	(dump_decl): Ditto.
> 	(lang_decl_name): Ditto.
> 	(dump_function_decl): Ensure complete replacement of the class
> 	template diagnostics if a diagnose_as attribute is present.
> 	(dump_function_name): Replace the function diagnostic output if
> 	the diagnose_as attribute is set.
> 	* name-lookup.c (handle_namespace_attrs): Handle the diagnose_as
> 	attribute. Ensure exactly one string argument. Ensure previous
> 	diagnose_as attributes used the same name.
> 	* 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 and the TREE_TYPE is an implicit class template
> 	instantiation, call decl_attributes to add the diagnose_as
> 	attribute to the TREE_TYPE.
> ---
>   gcc/c-family/c.opt   |   4 ++
>   gcc/cp/error.c       |  85 ++++++++++++++++++++++++++++---
>   gcc/cp/name-lookup.c |  27 ++++++++++
>   gcc/cp/tree.c        | 117 +++++++++++++++++++++++++++++++++++++++++++
>   gcc/doc/extend.texi  |  37 ++++++++++++++
>   gcc/doc/invoke.texi  |   9 +++-
>   6 files changed, 270 insertions(+), 9 deletions(-)
> 
> 
> --
> ──────────────────────────────────────────────────────────────────────────
>   Dr. Matthias Kretzhttps://mattkretz.github.io
>   GSI Helmholtz Centre for Heavy Ion Researchhttps://gsi.de
>   std::experimental::simdhttps://github.com/VcDevel/std-simd
> ──────────────────────────────────────────────────────────────────────────
> 
> 
> 0001-Add-gnu-diagnose_as-attribute.patch
> 
> diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
> index 3f8b72cdc00..0cf01c6dba4 100644
> --- a/gcc/c-family/c.opt
> +++ b/gcc/c-family/c.opt
> @@ -1582,6 +1582,10 @@ fdiagnostics-show-template-tree
>   C++ ObjC++ Var(flag_diagnostics_show_template_tree) Init(0)
>   Print hierarchical comparisons when template types are mismatched.
>   
> +fdiagnostics-use-aliases
> +C++ Var(flag_diagnostics_use_aliases) Init(1)
> +Replace identifiers or scope names in diagnostics as defined by the diagnose_as attribute.
> +
>   fdirectives-only
>   C ObjC C++ ObjC++
>   Preprocess directives only.
> diff --git a/gcc/cp/error.c b/gcc/cp/error.c
> index c88d1749a0f..10b547afaa7 100644
> --- a/gcc/cp/error.c
> +++ b/gcc/cp/error.c
> @@ -35,6 +35,7 @@ along with GCC; see the file COPYING3.  If not see
>   #include "internal-fn.h"
>   #include "gcc-rich-location.h"
>   #include "cp-name-hint.h"
> +#include "attribs.h"
>   
>   #define pp_separate_with_comma(PP) pp_cxx_separate_with (PP, ',')
>   #define pp_separate_with_semicolon(PP) pp_cxx_separate_with (PP, ';')
> @@ -66,6 +67,7 @@ static void dump_alias_template_specialization (cxx_pretty_printer *, tree, int)
>   static void dump_type (cxx_pretty_printer *, tree, int);
>   static void dump_typename (cxx_pretty_printer *, tree, int);
>   static void dump_simple_decl (cxx_pretty_printer *, tree, tree, int);
> +static void dump_decl_name_or_diagnose_as (cxx_pretty_printer *, tree, int);
>   static void dump_decl (cxx_pretty_printer *, tree, int);
>   static void dump_template_decl (cxx_pretty_printer *, tree, int);
>   static void dump_function_decl (cxx_pretty_printer *, tree, int);
> @@ -231,7 +233,15 @@ dump_scope (cxx_pretty_printer *pp, tree scope, int flags)
>       {
>         if (scope != global_namespace)
>   	{
> -          dump_decl (pp, scope, f);
> +	  tree diagnose_as
> +	    = flag_diagnostics_use_aliases
> +		? lookup_attribute ("diagnose_as", DECL_ATTRIBUTES (scope))
> +		: NULL_TREE;
> +	  if (diagnose_as)
> +	    pp_cxx_ws_string (
> +	      pp, TREE_STRING_POINTER (TREE_VALUE (TREE_VALUE (diagnose_as))));
> +	  else
> +	    dump_decl (pp, scope, f);
>   	  pp_cxx_colon_colon (pp);
>   	}
>       }
> @@ -743,6 +753,7 @@ dump_aggr_type (cxx_pretty_printer *pp, tree t, int flags)
>   
>     tree decl = TYPE_NAME (t);
>   
> +  tree diagnose_as = NULL_TREE;
>     if (decl)
>       {
>         typdef = (!DECL_ARTIFICIAL (decl)
> @@ -769,8 +780,15 @@ dump_aggr_type (cxx_pretty_printer *pp, tree t, int flags)
>         if (! (flags & TFF_UNQUALIFIED_NAME))
>   	dump_scope (pp, CP_DECL_CONTEXT (decl), flags | TFF_SCOPE);
>         flags &= ~TFF_UNQUALIFIED_NAME;
> +
> +      tree diagnose_as_specialized = NULL_TREE;
>         if (tmplate)
>   	{
> +	  if (flag_diagnostics_use_aliases)
> +	    diagnose_as_specialized
> +	      = lookup_attribute ("diagnose_as",
> +				  TYPE_ATTRIBUTES (TREE_TYPE (decl)));
> +
>   	  /* Because the template names are mangled, we have to locate
>   	     the most general template, and use that name.  */
>   	  tree tpl = TYPE_TI_TEMPLATE (t);
> @@ -779,9 +797,25 @@ dump_aggr_type (cxx_pretty_printer *pp, tree t, int flags)
>   	    tpl = DECL_TI_TEMPLATE (tpl);
>   	  decl = tpl;
>   	}
> +
> +      if (flag_diagnostics_use_aliases)
> +	diagnose_as = lookup_attribute ("diagnose_as",
> +					TYPE_ATTRIBUTES (TREE_TYPE (decl)));
> +      if (diagnose_as_specialized
> +	    && (!diagnose_as || TREE_VALUE(diagnose_as_specialized)
> +				  != TREE_VALUE(diagnose_as)))
> +	 {
> +	   pp_cxx_ws_string (
> +	     pp, TREE_STRING_POINTER (
> +		   TREE_VALUE (TREE_VALUE (diagnose_as_specialized))));
> +	   return;
> +	 }
>       }
>   
> -  if (LAMBDA_TYPE_P (t))
> +  if (diagnose_as)
> +    pp_cxx_ws_string (pp, TREE_STRING_POINTER (
> +			    TREE_VALUE (TREE_VALUE (diagnose_as))));
> +  else if (LAMBDA_TYPE_P (t))
>       {
>         /* A lambda's "type" is essentially its signature.  */
>         pp_string (pp, M_("<lambda"));
> @@ -1103,7 +1137,7 @@ dump_simple_decl (cxx_pretty_printer *pp, tree t, tree type, int flags)
>   	  pp_string (pp, " capture>");
>   	}
>         else
> -	dump_decl (pp, DECL_NAME (t), flags);
> +	dump_decl_name_or_diagnose_as (pp, t, flags);
>       }
>     else if (DECL_DECOMPOSITION_P (t))
>       pp_string (pp, M_("<structured bindings>"));
> @@ -1147,6 +1181,25 @@ dump_decl_name (cxx_pretty_printer *pp, tree t, int flags)
>     pp_cxx_tree_identifier (pp, t);
>   }
>   
> +/* Print the DECL_NAME of DECL unless a different string was requested by the
> +   diagnose_as attribute. */
> +
> +static void
> +dump_decl_name_or_diagnose_as (cxx_pretty_printer *pp, tree decl, int flags)
> +{
> +  if (flag_diagnostics_use_aliases)
> +    {
> +      tree attr = lookup_attribute ("diagnose_as", DECL_ATTRIBUTES (decl));
> +      if (attr)
> +	{
> +	  pp_cxx_ws_string (
> +	    pp, TREE_STRING_POINTER (TREE_VALUE (TREE_VALUE (attr))));
> +	  return;
> +	}
> +    }
> +  dump_decl_name (pp, DECL_NAME (decl), flags);
> +}
> +
>   /* Dump a human readable string for the decl T under control of FLAGS.  */
>   
>   static void
> @@ -1192,7 +1245,7 @@ dump_decl (cxx_pretty_printer *pp, tree t, int flags)
>   	      || flags & TFF_CLASS_KEY_OR_ENUM))
>   	{
>   	  pp_cxx_ws_string (pp, "using");
> -	  dump_decl (pp, DECL_NAME (t), flags);
> +	  dump_decl_name_or_diagnose_as(pp, t, flags);
>   	  pp_cxx_whitespace (pp);
>   	  pp_cxx_ws_string (pp, "=");
>   	  pp_cxx_whitespace (pp);
> @@ -1374,7 +1427,7 @@ dump_decl (cxx_pretty_printer *pp, tree t, int flags)
>   	      TREE_CODE (DECL_INITIAL (t)) == TEMPLATE_PARM_INDEX))
>   	dump_simple_decl (pp, t, TREE_TYPE (t), flags);
>         else if (DECL_NAME (t))
> -	dump_decl (pp, DECL_NAME (t), flags);
> +	dump_decl_name_or_diagnose_as (pp, t, flags);
>         else if (DECL_INITIAL (t))
>   	dump_expr (pp, DECL_INITIAL (t), flags | TFF_EXPR_IN_PARENS);
>         else
> @@ -1393,7 +1446,7 @@ dump_decl (cxx_pretty_printer *pp, tree t, int flags)
>   	  }
>   	dump_type (pp, scope, flags);
>   	pp_cxx_colon_colon (pp);
> -	dump_decl (pp, DECL_NAME (t), flags);
> +	dump_decl_name_or_diagnose_as (pp, t, flags);
>   	if (variadic)
>   	  pp_cxx_ws_string (pp, "...");
>         }
> @@ -1657,7 +1710,13 @@ dump_function_decl (cxx_pretty_printer *pp, tree t, int flags)
>     /* Pretty print template instantiations only.  */
>     if (DECL_USE_TEMPLATE (t) && DECL_TEMPLATE_INFO (t)
>         && !(flags & TFF_NO_TEMPLATE_BINDINGS)
> -      && flag_pretty_templates)
> +      && flag_pretty_templates
> +      // skip the output of template parameters if the function is a member of a
> +      // class with diagnose_as attribute:
> +      && !(flag_diagnostics_use_aliases
> +	     && DECL_CLASS_SCOPE_P (t)
> +	     && lookup_attribute ("diagnose_as",
> +				  TYPE_ATTRIBUTES (DECL_CONTEXT (t)))))
>       {
>         tree tmpl;
>   
> @@ -1885,6 +1944,16 @@ dump_exception_spec (cxx_pretty_printer *pp, tree t, int flags)
>   static void
>   dump_function_name (cxx_pretty_printer *pp, tree t, int flags)
>   {
> +  if (flag_diagnostics_use_aliases)
> +    {
> +      tree attr = lookup_attribute ("diagnose_as", DECL_ATTRIBUTES (t));
> +      if (attr)
> +	{
> +	  pp_cxx_ws_string (
> +	    pp, TREE_STRING_POINTER (TREE_VALUE (TREE_VALUE (attr))));
> +	  return;
> +	}
> +    }
>     tree name = DECL_NAME (t);
>   
>     /* We can get here with a decl that was synthesized by language-
> @@ -3133,7 +3202,7 @@ lang_decl_name (tree decl, int v, bool translate)
>              && TREE_CODE (decl) == NAMESPACE_DECL)
>       dump_decl (cxx_pp, decl, TFF_PLAIN_IDENTIFIER | TFF_UNQUALIFIED_NAME);
>     else
> -    dump_decl (cxx_pp, DECL_NAME (decl), TFF_PLAIN_IDENTIFIER);
> +    dump_decl_name_or_diagnose_as (cxx_pp, decl, TFF_PLAIN_IDENTIFIER);
>   
>     return pp_ggc_formatted_text (cxx_pp);
>   }
> diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c
> index 4e84e2f9987..80637503310 100644
> --- a/gcc/cp/name-lookup.c
> +++ b/gcc/cp/name-lookup.c
> @@ -6082,6 +6082,33 @@ handle_namespace_attrs (tree ns, tree attributes)
>   	    DECL_ATTRIBUTES (ns) = tree_cons (name, args,
>   					      DECL_ATTRIBUTES (ns));
>   	}
> +      else if (is_attribute_p ("diagnose_as", name))
> +	{
> +	  if (!args || TREE_CHAIN(args))
> +	    {
> +	      error ("the %qE attribute requires exactly one argument", name);

Other diagnostics involving attributes do not start with an article.
Can you please drop the "the"?  (In general, I would suggest to either
reuse or follow the style of existing diagnostics issued from the same
file, and/or look at those in gcc/po/gcc.pot.  Not nearly all of then
are consistent with one another but it's best to avoid introducing
yet another style; it will make converging on a single style easier,
and reduces the effort involved in translating messages).

> +	      continue;
> +	    }
> +	  if (TREE_CODE (TREE_VALUE (args)) != STRING_CST)
> +	    {
> +	      error ("the argument to the %qE attribute must be a string "
> +		    "literal", name);

Similarly here, recommend to follow one of the existing styles (see
c-family/c-attribs.c) rather than adding another variation to the mix.

> +	      continue;
> +	    }
> +	  tree existing
> +	    = lookup_attribute ("diagnose_as", DECL_ATTRIBUTES (ns));
> +	  if (existing
> +		&& !cp_tree_equal(TREE_VALUE (args),
> +				  TREE_VALUE (TREE_VALUE (existing))))
> +	    {
> +	      error ("the namespace %qE already uses a different diagnose_as "
> +		     "attribute value", ns);

Here too, please drop the article.  Also, please quote the attribute
name (using %qs or %<diagnose_as%>).


> +	      inform (DECL_SOURCE_LOCATION (ns), "previous declaration here");
> +	      continue;
> +	    }
> +	  DECL_ATTRIBUTES (ns) = tree_cons (name, args,
> +					    DECL_ATTRIBUTES (ns));
> +	}
>         else
>   	{
>   	  warning (OPT_Wattributes, "%qD attribute directive ignored",
> diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
> index a8bfd5fc053..f7b93dc89d7 100644
> --- a/gcc/cp/tree.c
> +++ b/gcc/cp/tree.c
> @@ -46,6 +46,7 @@ static tree verify_stmt_tree_r (tree *, int *, void *);
>   
>   static tree handle_init_priority_attribute (tree *, tree, tree, int, bool *);
>   static tree handle_abi_tag_attribute (tree *, tree, tree, int, bool *);
> +static tree handle_diagnose_as_attribute (tree *, tree, tree, int, bool *);
>   
>   /* If REF is an lvalue, returns the kind of lvalue that REF is.
>      Otherwise, returns clk_none.  */
> @@ -4860,6 +4861,8 @@ const struct attribute_spec cxx_attribute_table[] =
>       handle_init_priority_attribute, NULL },
>     { "abi_tag", 1, -1, false, false, false, true,
>       handle_abi_tag_attribute, NULL },
> +  { "diagnose_as", 1, 1, false, false, false, false,
> +    handle_diagnose_as_attribute, NULL },
>     { NULL, 0, 0, false, false, false, false, NULL, NULL }
>   };
>   
> @@ -5128,6 +5131,120 @@ handle_abi_tag_attribute (tree* node, tree name, tree args,
>     return NULL_TREE;
>   }
>   
> +static bool
> +check_diagnose_as_redeclaration (const_tree decl, const_tree old,
> +				 const_tree new_)
> +{
> +  if (!old)
> +    return true;
> +  if (TREE_CODE (TREE_VALUE (old)) == TREE_LIST)
> +    old = TREE_VALUE (old);
> +  if (TREE_CODE (TREE_VALUE (new_)) == TREE_LIST)
> +    new_ = TREE_VALUE (new_);
> +  tree old_value = TREE_VALUE (old);
> +  tree new_value = TREE_VALUE (new_);
> +  if (cp_tree_equal (old_value, new_value))
> +    return true;
> +  error ("conflicting declaration of %<diagnose_as%> attribute on %qD would "
> +	 "overwrite %qE with %qE", decl, old_value, new_value);

There are a few messages GCC issues to diagnose attribute conflicts.
Conflicts between different attributes are usually diagnosed by
warnings:
msgid "ignoring attribute %qE because it conflicts with attribute %qs"
but some conflicts cause errors:
msgid "section of %q+D conflicts with previous declaration"

Either way, I would again recommend adopting one of the existing styles
for consistency rather than introducing a new one.

> +  return false;
> +}
> +
> +static tree
> +handle_diagnose_as_attribute (tree* node, tree name, tree args,
> +			      int flags, bool* no_add_attrs)
> +{
> +  tree decl = NULL_TREE;
> +  if (!args || TREE_CHAIN (args))
> +    {
> +      error ("the %qE attribute requires exactly one argument", name);
> +      goto fail;
> +    }
> +  if (TREE_CODE (TREE_VALUE (args)) != STRING_CST)
> +    {
> +      error ("the argument to the %qE attribute must be a string literal",
> +	     name);

Same comment here.  E.g.,
msgid "%qE attribute argument must be a string constant"
in the same file.

> +      goto fail;
> +    }
> +  if (TREE_CODE (*node) == TYPE_DECL)
> +    {
> +      // Apply the attribute to the type alias itself.
> +      decl = *node;
> +      tree type = TREE_TYPE (*node);
> +      if (CLASS_TYPE_P (type) && CLASSTYPE_IMPLICIT_INSTANTIATION (type))
> +	{
> +	  if (COMPLETE_OR_OPEN_TYPE_P (type))
> +	    warning (OPT_Wattributes, "%qE attribute cannot be applied to %qT "
> +				      "after its instantiation", name, type);

Ditto here:
msgid "ignoring %qE attribute applied to template instantiation %qT"


> +	  else
> +	    {
> +	      type = strip_typedefs(type, nullptr, 0);
> +	      // And apply the attribute to the specialization on the RHS.
> +	      tree attributes = tree_cons (name, args, NULL_TREE);
> +	      decl_attributes (&type, attributes,
> +			       ATTR_FLAG_TYPE_IN_PLACE, NULL_TREE);
> +	    }
> +	}
> +    }
> +  else if (TYPE_P (*node))
> +    {
> +      if (!OVERLOAD_TYPE_P (*node))
> +	{
> +	  error ("%qE attribute applied to non-class, non-enum type %qT",
> +		 name, *node);
> +	  goto fail;
> +	}
> +      else if (!(flags & (int)ATTR_FLAG_TYPE_IN_PLACE))
> +	{
> +	  error ("%qE attribute applied to %qT after its definition",
> +		 name, *node);
> +	  goto fail;
> +	}
> +      decl = TYPE_NAME (*node);
> +    }
> +  else
> +    {
> +      if (!VAR_OR_FUNCTION_DECL_P (*node))
> +	{
> +	  error ("%qE attribute applied to non-function, non-variable %qD",
> +		 name, *node);
> +	  goto fail;
> +	}
> +      else if (DECL_LANGUAGE (*node) == lang_c)
> +	{
> +	  error ("%qE attribute applied to extern \"C\" declaration %qD",

Please quote extern "C" (as "%<extern \"C\"%>).

> +		 name, *node);
> +	  goto fail;
> +	}
> +      decl = *node;
> +    }
> +
> +  // Make sure all declarations have the same diagnose_as string.
> +  if (DECL_SOURCE_LOCATION (decl) != input_location)
> +    {
> +      tree attributes = TYPE_P (*node) ? TYPE_ATTRIBUTES (*node)
> +				       : DECL_ATTRIBUTES (decl);
> +      if (!check_diagnose_as_redeclaration (
> +	     decl, lookup_attribute ("diagnose_as", attributes), args))
> +	goto fail;
> +    }
> +  else if (CLASS_TYPE_P (*node) && CLASSTYPE_IMPLICIT_INSTANTIATION (*node))
> +    {
> +      // The above branch (different source location) is taken for declarations
> +      // of type aliases that modify an implicit template specialization on the
> +      // RHS. This branch is taken when the template is instantiated via
> +      // instantiate_class_template_1, in which case the attribute either
> +      // already has the value from the general template or from a type alias.
> +      goto fail;
> +    }
> +
> +  return NULL_TREE;
> +
> + fail:
> +  *no_add_attrs = true;
> +  return NULL_TREE;
> +}
> +
>   /* Return a new PTRMEM_CST of the indicated TYPE.  The MEMBER is the
>      thing pointed to by the constant.  */
>   
> diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
> index c8caf36f293..7976e3a72d4 100644
> --- a/gcc/doc/extend.texi
> +++ b/gcc/doc/extend.texi
> @@ -2865,6 +2865,43 @@ types (@pxref{Variable Attributes}, @pxref{Type Attributes}.)
>   The message attached to the attribute is affected by the setting of
>   the @option{-fmessage-length} option.
>   
> +@item diagnose_as ("@var{string}")
> +@cindex @code{diagnose_as} function attribute
> +The @code{diagnose_as} attribute modifies how the entity the attribute
> +appertains to is diagnosed in compiler messages and __FUNCTION__ /
> +__PRETTY_FUNCTION__ macros.

Presumably also __func__.  Symbol names should be quoted in @code{}.


  If the attribute is applied to a @code{namespace},
> +the specified string replaces the complete enclosing scope. The effect of the
> +@code{diagnose_as} attribute can be disabled with the
> +@option{-fno-diagnostics-use-aliases} command line option.

If the attribute doesn't change typeinfo it might be worth mentioning
in the documentation.

Martin

> +
> +@smallexample
> +namespace Foo @{
> +  namespace Bar @{
> +    inline namespace v1 [[gnu::diagnose_as("Foobar")]] @{
> +      int f() @{
> +        // __PRETTY_FUNCTION__ == "void Foobar::f()"
> +      @}
> +    @}
> +  @}
> +@}
> +// In function 'int Foobar::f()':
> +// warning: no return statement in function returning non-void [-Wreturn-type]
> +@end smallexample
> +
> +The @code{diagnose_as} attribute can be used with namespaces, functions,
> +variables, alias declarations (but not alias templates), and user-defined types
> +(classes, unions, and enums). If the alias declaration aliases an implicit class
> +template specialization, the attribute is additionally applied to the class
> +template specialization.
> +
> +@smallexample
> +template <class T> struct basic_string @{@};
> +using string [[gnu::diagnose_as("string")]] = basic_string<char>;
> +int f(basic_string<char>) @{@}
> +// In function 'int f(string)':
> +// warning: no return statement in function returning non-void [-Wreturn-type]
> +@end smallexample
> +
>   @item error ("@var{message}")
>   @itemx warning ("@var{message}")
>   @cindex @code{error} function attribute
> diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
> index f5a9dc33819..84c19344c89 100644
> --- a/gcc/doc/invoke.texi
> +++ b/gcc/doc/invoke.texi
> @@ -311,7 +311,8 @@ Objective-C and Objective-C++ Dialects}.
>   -fdiagnostics-show-path-depths @gol
>   -fno-show-column @gol
>   -fdiagnostics-column-unit=@r{[}display@r{|}byte@r{]} @gol
> --fdiagnostics-column-origin=@var{origin}}
> +-fdiagnostics-column-origin=@var{origin} @gol
> +-fno-diagnostics-aliases}
>   
>   @item Warning Options
>   @xref{Warning Options,,Options to Request or Suppress Warnings}.
> @@ -5077,6 +5078,12 @@ first column.  The default value of 1 corresponds to traditional GCC
>   behavior and to the GNU style guide.  Some utilities may perform better with an
>   origin of 0; any non-negative value may be specified.
>   
> +@item -fno-diagnostics-use-aliases
> +@opindex fno-diagnostics-use-aliases
> +@opindex fdiagnostics-use-aliases
> +Do not replace identifiers or scope names with the aliases defined with the
> +@code{[[gnu::diagnose_as("alias")]]} attribute.
> +
>   @item -fdiagnostics-format=@var{FORMAT}
>   @opindex fdiagnostics-format
>   Select a different format for printing diagnostics.
> 


  parent reply	other threads:[~2021-05-14 16:05 UTC|newest]

Thread overview: 30+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <14205410.xuKvIAzr1H@excalibur>
     [not found] ` <20210427094648.GL3008@redhat.com>
2021-05-04 11:13   ` Matthias Kretz
2021-05-04 13:34     ` David Malcolm
2021-05-04 14:23       ` Matthias Kretz
2021-05-04 14:32         ` Matthias Kretz
2021-05-04 19:00         ` David Malcolm
2021-05-04 19:22           ` Matthias Kretz
2021-05-14 16:05     ` Martin Sebor [this message]
2021-05-26 21:33       ` Matthias Kretz
2021-05-27 17:39     ` Jason Merrill
2021-05-27 18:54       ` Matthias Kretz
2021-05-27 21:15         ` Jason Merrill
2021-05-27 22:07           ` Matthias Kretz
2021-05-28  3:05             ` Jason Merrill
2021-05-28  7:42               ` Matthias Kretz
2021-06-01 19:12                 ` Jason Merrill
2021-06-01 21:01                   ` Matthias Kretz
2021-06-11 10:01                   ` Matthias Kretz
2021-06-15 15:51                     ` Jason Merrill
2021-06-15 20:56                       ` Matthias Kretz
2021-06-16  0:48                         ` Jason Merrill
2021-06-22  7:30                           ` Matthias Kretz
2021-06-22 19:52                             ` Jason Merrill
2021-06-22 20:01                               ` Matthias Kretz
2021-06-22 20:12                                 ` Jason Merrill
2021-07-01  9:28                                   ` Matthias Kretz
2021-07-01 15:18                                     ` Jason Merrill
2021-07-05 14:18                                       ` Matthias Kretz
2021-07-07 22:34                                         ` Jason Merrill
2021-07-07  8:23                               ` Matthias Kretz
2021-07-08  1:19                                 ` Jason Merrill

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=ed879577-5cf0-9b5a-27a4-6f734bd85bc1@gmail.com \
    --to=msebor@gmail.com \
    --cc=gcc-patches@gcc.gnu.org \
    --cc=libstdc++@gcc.gnu.org \
    --cc=m.kretz@gsi.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).