[PATCH v6] attribs: Implement -Wno-attributes=vendor::attr [PR101940]

Marek Polacek polacek@redhat.com
Tue Nov 9 15:51:53 GMT 2021


On Tue, Nov 09, 2021 at 12:12:10AM -0500, Jason Merrill wrote:
> On 11/8/21 20:41, Marek Polacek wrote:
> > On Sat, Nov 06, 2021 at 03:29:57PM -0400, Jason Merrill wrote:
> > > On 11/6/21 14:28, Marek Polacek wrote:
> > > > On Sat, Nov 06, 2021 at 02:32:26AM +0100, Bernhard Reutner-Fischer wrote:
> > > > > On 6 November 2021 01:21:43 CET, Marek Polacek via Gcc-patches <gcc-patches@gcc.gnu.org> wrote:
> > > > > 
> > > > > > 
> > > > > > Thanks, so like this?  I'm including an incremental diff so that it's
> > > > > > clear what changed:
> > > > > > 
> > > > > > diff --git a/gcc/attribs.c b/gcc/attribs.c
> > > > > > index d5fba7f4bbb..addfe6f6c80 100644
> > > > > > --- a/gcc/attribs.c
> > > > > > +++ b/gcc/attribs.c
> > > > > > @@ -237,7 +237,7 @@ check_attribute_tables (void)
> > > > > >      the end of parsing of all TUs. */
> > > > > > static vec<attribute_spec *> ignored_attributes_table;
> > > > > > 
> > > > > > -/* Parse arguments ARGS of -Wno-attributes=.
> > > > > > +/* Parse arguments V of -Wno-attributes=.
> > > > > >      Currently we accept:
> > > > > >        vendor::attr
> > > > > >        vendor::
> > > > > > @@ -252,12 +252,15 @@ handle_ignored_attributes_option (vec<char *> *v)
> > > > > > 
> > > > > >     for (auto opt : v)
> > > > > >       {
> > > > > > +      /* We're going to be modifying the string.  */
> > > > > > +      opt = xstrdup (opt);
> > > > > >         char *q = strstr (opt, "::");
> > > > > >         /* We don't accept '::attr'.  */
> > > > > >         if (q == nullptr || q == opt)
> > > > > > 	{
> > > > > > 	  error ("wrong argument to ignored attributes");
> > > > > > 	  inform (input_location, "valid format is %<ns::attr%> or %<ns::%>");
> > > > > > +	  free (opt);
> > > > > > 	  continue;
> > > > > > 	}
> > > > > 
> > > > > Only xstrdup here, after the strstr check?
> > > > > Should maybe strdup the rest here, not full opt..
> > > > 
> > > > No, I want q to point into the copy of the string, since I'm about
> > > > to modify it.  And I'd prefer a single call to xstrdup rather than
> > > > two.
> > > 
> > > It occurs to me that instead of calling xstrdup at all, since you're already
> > > passing the strings to get_identifier you could use
> > > get_identifier_with_length instead, and then refer to IDENTIFIER_POINTER of
> > > the result.
> > 
> > Ah, clever.  I didn't think it would work because I didn't expect that
> > get_identifier_with_length works when it gets a string that isn't
> > nul-terminated but it does.  So how about the following?
> > 
> > Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?
> > 
> > -- >8 --
> > It is desirable for -Wattributes to warn about e.g.
> > 
> > [[deprecate]] void g(); // typo, should warn
> > 
> > However, -Wattributes also warns about vendor-specific attributes
> > (that's because lookup_scoped_attribute_spec -> find_attribute_namespace
> > finds nothing), which, with -Werror, causes grief.  We don't want the
> > -Wattributes warning for
> > 
> > [[company::attr]] void f();
> > 
> > GCC warns because it doesn't know the "company" namespace; it only knows
> > the "gnu" and "omp" namespaces.  We could entirely disable warning about
> > attributes in unknown scopes but then the compiler would also miss typos
> > like
> > 
> >    [[company::attrx]] void f();
> > 
> > or
> > 
> >    [[gmu::warn_used_result]] int write();
> > 
> > so that is not a viable solution.  A workaround is to use a #pragma:
> > 
> >    #pragma GCC diagnostic push
> >    #pragma GCC diagnostic ignored "-Wattributes"
> >    [[company::attr]] void f() {}
> >    #pragma GCC diagnostic pop
> > 
> > but that's a mouthful and awkward to use and could also hide typos.  In
> > fact, any macro-based solution doesn't seem like a way forward.
> > 
> > This patch implements -Wno-attributes=, which takes these arguments:
> > 
> > company::attr
> > company::
> > 
> > This option should go well with using @file: the user could have a file
> > containing
> > -Wno-attributes=vendor::attr1,vendor::attr2
> > and then invoke gcc with '@attrs' or similar.
> > 
> > I've also added a new pragma which has the same effect:
> > 
> > The pragma along with the new option should help with various static
> > analysis tools.
> > 
> > 	PR c++/101940
> > 
> > gcc/ChangeLog:
> > 
> > 	* attribs.c (struct scoped_attributes): Add a bool member.
> > 	(lookup_scoped_attribute_spec): Forward declare.
> > 	(register_scoped_attributes): New bool parameter, defaulted to
> > 	false.  Use it.
> > 	(handle_ignored_attributes_option): New function.
> > 	(free_attr_data): New function.
> > 	(init_attributes): Call handle_ignored_attributes_option.
> > 	(attr_namespace_ignored_p): New function.
> > 	(decl_attributes): Check attr_namespace_ignored_p before
> > 	warning.
> > 	* attribs.h (free_attr_data): Declare.
> > 	(register_scoped_attributes): Adjust declaration.
> > 	(handle_ignored_attributes_option): Declare.
> > 	* common.opt (Wattributes=): New option with a variable.
> > 	* doc/extend.texi: Document #pragma GCC diagnostic ignored_attributes.
> > 	* doc/invoke.texi: Document -Wno-attributes=.
> > 	* opts.c (common_handle_option) <case OPT_Wattributes_>: Handle.
> > 	* plugin.h (register_scoped_attributes): Adjust declaration.
> > 	* toplev.c (compile_file): Call free_attr_data.
> > 
> > gcc/c-family/ChangeLog:
> > 
> > 	* c-pragma.c (handle_pragma_diagnostic): Handle #pragma GCC diagnostic
> > 	ignored_attributes.
> > 
> > gcc/testsuite/ChangeLog:
> > 
> > 	* c-c++-common/Wno-attributes-1.c: New test.
> > 	* c-c++-common/Wno-attributes-2.c: New test.
> > ---
> >   gcc/attribs.c                                 | 123 +++++++++++++++++-
> >   gcc/attribs.h                                 |   5 +-
> >   gcc/c-family/c-pragma.c                       |  37 +++++-
> >   gcc/common.opt                                |   9 +-
> >   gcc/doc/extend.texi                           |  19 +++
> >   gcc/doc/invoke.texi                           |  20 +++
> >   gcc/opts.c                                    |  20 +++
> >   gcc/plugin.h                                  |   4 +-
> >   gcc/testsuite/c-c++-common/Wno-attributes-1.c |  55 ++++++++
> >   gcc/testsuite/c-c++-common/Wno-attributes-2.c |  56 ++++++++
> >   gcc/toplev.c                                  |   2 +
> >   11 files changed, 341 insertions(+), 9 deletions(-)
> >   create mode 100644 gcc/testsuite/c-c++-common/Wno-attributes-1.c
> >   create mode 100644 gcc/testsuite/c-c++-common/Wno-attributes-2.c
> > 
> > diff --git a/gcc/attribs.c b/gcc/attribs.c
> > index 83fafc98b7d..23d92ca9474 100644
> > --- a/gcc/attribs.c
> > +++ b/gcc/attribs.c
> > @@ -87,6 +87,8 @@ struct scoped_attributes
> >     const char *ns;
> >     vec<attribute_spec> attributes;
> >     hash_table<attribute_hasher> *attribute_hash;
> > +  /* True if we should not warn about unknown attributes in this NS.  */
> > +  bool ignored_p;
> >   };
> >   /* The table of scope attributes.  */
> > @@ -95,6 +97,8 @@ static vec<scoped_attributes> attributes_table;
> >   static scoped_attributes* find_attribute_namespace (const char*);
> >   static void register_scoped_attribute (const struct attribute_spec *,
> >   				       scoped_attributes *);
> > +static const struct attribute_spec *lookup_scoped_attribute_spec (const_tree,
> > +								  const_tree);
> >   static bool attributes_initialized = false;
> > @@ -121,12 +125,14 @@ extract_attribute_substring (struct substring *str)
> >   /* Insert an array of attributes ATTRIBUTES into a namespace.  This
> >      array must be NULL terminated.  NS is the name of attribute
> > -   namespace.  The function returns the namespace into which the
> > -   attributes have been registered.  */
> > +   namespace.  IGNORED_P is true iff all unknown attributes in this
> > +   namespace should be ignored for the purposes of -Wattributes.  The
> > +   function returns the namespace into which the attributes have been
> > +   registered.  */
> >   scoped_attributes *
> >   register_scoped_attributes (const struct attribute_spec *attributes,
> > -			    const char *ns)
> > +			    const char *ns, bool ignored_p /*=false*/)
> >   {
> >     scoped_attributes *result = NULL;
> > @@ -144,9 +150,12 @@ register_scoped_attributes (const struct attribute_spec *attributes,
> >         memset (&sa, 0, sizeof (sa));
> >         sa.ns = ns;
> >         sa.attributes.create (64);
> > +      sa.ignored_p = ignored_p;
> >         result = attributes_table.safe_push (sa);
> >         result->attribute_hash = new hash_table<attribute_hasher> (200);
> >       }
> > +  else
> > +    result->ignored_p |= ignored_p;
> >     /* Really add the attributes to their namespace now.  */
> >     for (unsigned i = 0; attributes[i].name != NULL; ++i)
> > @@ -224,6 +233,95 @@ check_attribute_tables (void)
> >   				 attribute_tables[j][l].name));
> >   }
> > +/* Used to stash pointers to allocated memory so that we can free them at
> > +   the end of parsing of all TUs. */
> > +static vec<attribute_spec *> ignored_attributes_table;
> > +
> > +/* Parse arguments V of -Wno-attributes=.
> > +   Currently we accept:
> > +     vendor::attr
> > +     vendor::
> > +   This functions also registers the parsed attributes so that we don't
> > +   warn that we don't recognize them.  */
> > +
> > +void
> > +handle_ignored_attributes_option (vec<char *> *v)
> > +{
> > +  if (v == nullptr)
> > +    return;
> > +
> > +  for (auto opt : v)
> > +    {
> > +      char *cln = strstr (opt, "::");
> > +      /* We don't accept '::attr'.  */
> > +      if (cln == nullptr || cln == opt)
> > +	{
> > +	  error ("wrong argument to ignored attributes");
> > +	  inform (input_location, "valid format is %<ns::attr%> or %<ns::%>");
> > +	  continue;
> > +	}
> > +      char *vendor_start = opt;
> > +      ptrdiff_t vendor_len = cln - opt;
> > +      char *attr_start = cln + 2;
> > +      /* This could really use rawmemchr :(.  */
> > +      ptrdiff_t attr_len = strchr (attr_start, '\0') - attr_start;
> > +      /* Verify that they look valid.  */
> > +      auto valid_p = [](const char *const s, ptrdiff_t len) {
> > +	for (int i = 0; i < len; ++i)
> > +	  if (!ISALNUM (*s) && *s != '_')
> > +	    return false;
> > +	return true;
> > +      };
> > +      if (!valid_p (vendor_start, vendor_len)
> > +	  || !valid_p (attr_start, attr_len))
> > +	{
> > +	  error ("wrong argument to ignored attributes");
> > +	  continue;
> > +	}
> > +      /* Turn "__attr__" into "attr" so that we have a canonical form of
> > +	 attribute names.  Likewise for vendor.  */
> > +      auto strip = [](char *&s, ptrdiff_t &l) {
> > +	if (l > 4 && s[0] == '_' && s[1] == '_'
> > +	    && s[l - 1] == '_' && s[l - 2] == '_')
> > +	  {
> > +	    s += 2;
> > +	    l -= 4;
> > +	  }
> > +      };
> > +      strip (attr_start, attr_len);
> > +      strip (vendor_start, vendor_len);
> > +      /* We perform all this hijinks so that we don't have to copy OPT.  */
> > +      tree vendor_id = get_identifier_with_length (vendor_start, vendor_len);
> > +      tree attr_id = get_identifier_with_length (attr_start, attr_len);
> > +      /* If we've already seen this vendor::attr, ignore it.  Attempting to
> > +	 register it twice would lead to a crash.  */
> > +      if (lookup_scoped_attribute_spec (vendor_id, attr_id))
> > +	continue;
> 
> Hmm, this looks like it isn't handling the case of previously ignoring
> vendor::; it seems we'll look for vendor::<empty string> instead, not find
> it, and register again.

Yes, for -Wno-attributes=vendor::,vendor:: we call register_scoped_attributes
twice, but I think that's OK: register_scoped_attributes will see that 
find_attribute_namespace finds the namespace and returns without creating a new  
one.

I think the current code handles -Wno-attributes=vendor::a,vendor:: well so
I'm not sure if I should change it.

Thanks,
Marek



More information about the Gcc-patches mailing list