[v4] attribs: Implement -Wno-attributes=vendor::attr [PR101940]
Commit Message
On Thu, Sep 23, 2021 at 02:25:16PM -0400, Jason Merrill wrote:
> On 9/20/21 18:59, Marek Polacek via Gcc-patches wrote:
> > +void
> > +handle_ignored_attributes_option (vec<char *> *v)
> > +{
> > + if (v == nullptr)
> > + return;
> > +
> > + for (auto opt : v)
> > + {
> > + if (strcmp (opt, "clang") == 0)
> > + {
> > + // TODO
> > + continue;
> > + }
>
> If this doesn't work yet, let's not accept it at all for now.
Ok.
> > + 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%>, %<ns::%>, "
> > + "or %<clang%>");
>
> ...or even mention it. Users can ignore clang:: instead, it doesn't matter
> to us if clang attributes are misspelled.
Removed.
> > + continue;
> > + }
> > + /* Cut off the vendor part. */
> > + *q = '\0';
> > + char *vendor = opt;
> > + char *attr = q + 2;
> > + /* Verify that they look valid. */
> > + auto valid_p = [](const char *s) {
> > + for (; *s != '\0'; ++s)
> > + if (!ISALNUM (*s) && *s != '_')
> > + return false;
> > + return true;
> > + };
> > + if (!valid_p (vendor) || !valid_p (attr))
> > + {
> > + 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) {
> > + const size_t l = strlen (s);
> > + if (l > 4 && s[0] == '_' && s[1] == '_'
> > + && s[l - 1] == '_' && s[l - 2] == '_')
> > + {
> > + s[l - 2] = '\0';
> > + s += 2;
> > + }
> > + };
> > + strip (attr);
> > + strip (vendor);
> > + /* 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 (get_identifier (vendor),
> > + get_identifier (attr)))
> > + continue;
> > + /* In the "vendor::" case, we should ignore *any* attribute coming
> > + from this attribute namespace. */
> > + const bool ignored_ns = attr[0] == '\0';
>
> Maybe set attr to nullptr instead of declaring ignored_ns?
>
> > + /* Create a table with extra attributes which we will register.
> > + We can't free it here, so squirrel away the pointers. */
> > + attribute_spec *table = new attribute_spec[2];
> > + ignored_attributes_table.safe_push (table);
> > + table[0] = { ignored_ns ? nullptr : attr, 0, 0, false, false,
>
> ...so this can just use attr.
I also need ignored_ns...
> > + false, false, nullptr, nullptr };
> > + table[1] = { nullptr, 0, 0, false, false, false, false, nullptr, nullptr };
> > + register_scoped_attributes (table, vendor, ignored_ns);
...here, but I tweaked this a bit to get rid of the bool.
> > + }
> > +}
> > +
> > +/* Free data we might have allocated when adding extra attributes. */
> > +
> > +void
> > +free_attr_data ()
> > +{
> > + for (auto x : ignored_attributes_table)
> > + delete[] x;
> > +}
>
> You probably also want to zero out ignored_attributes_table at this point.
Done.
> > /* Initialize attribute tables, and make some sanity checks if checking is
> > enabled. */
> > @@ -252,6 +353,9 @@ init_attributes (void)
> > /* Put all the GNU attributes into the "gnu" namespace. */
> > register_scoped_attributes (attribute_tables[i], "gnu");
> > + vec<char *> *ignored = (vec<char *> *) flag_ignored_attributes;
> > + handle_ignored_attributes_option (ignored);
> > +
> > invoke_plugin_callbacks (PLUGIN_ATTRIBUTES, NULL);
> > attributes_initialized = true;
> > }
> > @@ -456,6 +560,19 @@ diag_attr_exclusions (tree last_decl, tree node, tree attrname,
> > return found;
> > }
> > +/* Return true iff we should not complain about unknown attributes
> > + coming from the attribute namespace NS. This is the case for
> > + the -Wno-attributes=ns:: command-line option. */
> > +
> > +static bool
> > +attr_namespace_ignored_p (tree ns)
> > +{
> > + if (ns == NULL_TREE)
> > + return false;
> > + scoped_attributes *r = find_attribute_namespace (IDENTIFIER_POINTER (ns));
> > + return r && r->ignored_p;
> > +}
> > +
> > /* Process the attributes listed in ATTRIBUTES and install them in *NODE,
> > which is either a DECL (including a TYPE_DECL) or a TYPE. If a DECL,
> > it should be modified in place; if a TYPE, a copy should be created
> > @@ -556,7 +673,8 @@ decl_attributes (tree *node, tree attributes, int flags,
> > if (spec == NULL)
> > {
> > - if (!(flags & (int) ATTR_FLAG_BUILT_IN))
> > + if (!(flags & (int) ATTR_FLAG_BUILT_IN)
> > + && !attr_namespace_ignored_p (ns))
> > {
> > if (ns == NULL_TREE || !cxx11_attr_p)
> > warning (OPT_Wattributes, "%qE attribute directive ignored",
> > diff --git a/gcc/attribs.h b/gcc/attribs.h
> > index 138c509bce1..96a527f67a9 100644
> > --- a/gcc/attribs.h
> > +++ b/gcc/attribs.h
> > @@ -21,6 +21,7 @@ along with GCC; see the file COPYING3. If not see
> > #define GCC_ATTRIBS_H
> > extern const struct attribute_spec *lookup_attribute_spec (const_tree);
> > +extern void free_attr_data ();
> > extern void init_attributes (void);
> > /* Process the attributes listed in ATTRIBUTES and install them in *NODE,
> > @@ -40,12 +41,14 @@ extern void apply_tm_attr (tree, tree);
> > extern tree make_attribute (const char *, const char *, tree);
> > extern struct scoped_attributes* register_scoped_attributes (const struct attribute_spec *,
> > - const char *);
> > + const char *,
> > + bool = false);
> > extern char *sorted_attr_string (tree);
> > extern bool common_function_versions (tree, tree);
> > extern tree make_dispatcher_decl (const tree);
> > extern bool is_function_default_version (const tree);
> > +extern void handle_ignored_attributes_option (vec<char *> *);
> > /* Return a type like TTYPE except that its TYPE_ATTRIBUTES
> > is ATTRIBUTE.
> > diff --git a/gcc/c-family/c-pragma.c b/gcc/c-family/c-pragma.c
> > index a9be8df0384..6beba5503f0 100644
> > --- a/gcc/c-family/c-pragma.c
> > +++ b/gcc/c-family/c-pragma.c
> > @@ -764,7 +764,7 @@ handle_pragma_diagnostic(cpp_reader *ARG_UNUSED(dummy))
> > if (token != CPP_NAME)
> > {
> > warning_at (loc, OPT_Wpragmas,
> > - "missing [error|warning|ignored|push|pop]"
> > + "missing [error|warning|ignored|push|pop|ignored_attributes]"
> > " after %<#pragma GCC diagnostic%>");
> > return;
> > }
> > @@ -787,10 +787,43 @@ handle_pragma_diagnostic(cpp_reader *ARG_UNUSED(dummy))
> > diagnostic_pop_diagnostics (global_dc, input_location);
> > return;
> > }
> > + else if (strcmp (kind_string, "ignored_attributes") == 0)
> > + {
> > + token = pragma_lex (&x, &loc);
> > + if (token != CPP_STRING)
> > + {
> > + warning_at (loc, OPT_Wpragmas,
> > + "missing attribute name after %<#pragma GCC diagnostic "
> > + "ignored_attributes%>");
> > + return;
> > + }
> > + char *args = xstrdup (TREE_STRING_POINTER (x));
> > + const size_t l = strlen (args);
> > + if (l == 0)
> > + {
> > + warning_at (loc, OPT_Wpragmas, "missing argument to %<#pragma GCC "
> > + "diagnostic ignored_attributes%>");
> > + free (args);
> > + return;
> > + }
> > + else if (args[l - 1] == ',')
> > + {
> > + warning_at (loc, OPT_Wpragmas, "trailing %<,%> in arguments for "
> > + "%<#pragma GCC diagnostic ignored_attributes%>");
> > + free (args);
> > + return;
> > + }
> > + auto_vec<char *> v;
> > + for (char *p = strtok (args, ","); p; p = strtok (NULL, ","))
> > + v.safe_push (p);
> > + handle_ignored_attributes_option (&v);
> > + /* ??? We can't free (args); here. */
>
> Perhaps we want to copy strings in handle_ignored_attributes_option rather
> than here?
Well, the other use doesn't need copying, so I left it be.
> > + return;
> > + }
> > else
> > {
> > warning_at (loc, OPT_Wpragmas,
> > - "expected [error|warning|ignored|push|pop]"
> > + "expected [error|warning|ignored|push|pop|ignored_attributes]"
> > " after %<#pragma GCC diagnostic%>");
> > return;
> > }
> > diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c
> > index 771efa3eadf..345c8f9d620 100644
> > --- a/gcc/c/c-decl.c
> > +++ b/gcc/c/c-decl.c
> > @@ -12295,6 +12295,8 @@ c_parse_final_cleanups (void)
> > c_write_global_declarations_1 (BLOCK_VARS (DECL_INITIAL (t)));
> > c_write_global_declarations_1 (BLOCK_VARS (ext_block));
> > + free_attr_data ();
>
> Since handle_ignored_attributes_option is in language-independent code,
> shouldn't this call be as well?
Good point, I've moved it into compile_file. I don't where else it could
have gone.
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.
gcc/c-family/ChangeLog:
* c-pragma.c (handle_pragma_diagnostic): Handle #pragma GCC diagnostic
ignored_attributes.
gcc/c/ChangeLog:
* c-decl.c (c_parse_final_cleanups): Call free_attr_data.
gcc/cp/ChangeLog:
* decl2.c (c_parse_final_cleanups): Call free_attr_data.
gcc/testsuite/ChangeLog:
* c-c++-common/Wno-attributes-1.c: New test.
* c-c++-common/Wno-attributes-2.c: New test.
---
gcc/attribs.c | 120 +++++++++++++++++-
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, 338 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
base-commit: a11052d98db2f2a61841f0c5ee84de4ca1b3e296
Comments
Ping.
On Tue, Sep 28, 2021 at 04:20:46PM -0400, Marek Polacek wrote:
> On Thu, Sep 23, 2021 at 02:25:16PM -0400, Jason Merrill wrote:
> > On 9/20/21 18:59, Marek Polacek via Gcc-patches wrote:
> > > +void
> > > +handle_ignored_attributes_option (vec<char *> *v)
> > > +{
> > > + if (v == nullptr)
> > > + return;
> > > +
> > > + for (auto opt : v)
> > > + {
> > > + if (strcmp (opt, "clang") == 0)
> > > + {
> > > + // TODO
> > > + continue;
> > > + }
> >
> > If this doesn't work yet, let's not accept it at all for now.
>
> Ok.
>
> > > + 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%>, %<ns::%>, "
> > > + "or %<clang%>");
> >
> > ...or even mention it. Users can ignore clang:: instead, it doesn't matter
> > to us if clang attributes are misspelled.
>
> Removed.
>
> > > + continue;
> > > + }
> > > + /* Cut off the vendor part. */
> > > + *q = '\0';
> > > + char *vendor = opt;
> > > + char *attr = q + 2;
> > > + /* Verify that they look valid. */
> > > + auto valid_p = [](const char *s) {
> > > + for (; *s != '\0'; ++s)
> > > + if (!ISALNUM (*s) && *s != '_')
> > > + return false;
> > > + return true;
> > > + };
> > > + if (!valid_p (vendor) || !valid_p (attr))
> > > + {
> > > + 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) {
> > > + const size_t l = strlen (s);
> > > + if (l > 4 && s[0] == '_' && s[1] == '_'
> > > + && s[l - 1] == '_' && s[l - 2] == '_')
> > > + {
> > > + s[l - 2] = '\0';
> > > + s += 2;
> > > + }
> > > + };
> > > + strip (attr);
> > > + strip (vendor);
> > > + /* 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 (get_identifier (vendor),
> > > + get_identifier (attr)))
> > > + continue;
> > > + /* In the "vendor::" case, we should ignore *any* attribute coming
> > > + from this attribute namespace. */
> > > + const bool ignored_ns = attr[0] == '\0';
> >
> > Maybe set attr to nullptr instead of declaring ignored_ns?
> >
> > > + /* Create a table with extra attributes which we will register.
> > > + We can't free it here, so squirrel away the pointers. */
> > > + attribute_spec *table = new attribute_spec[2];
> > > + ignored_attributes_table.safe_push (table);
> > > + table[0] = { ignored_ns ? nullptr : attr, 0, 0, false, false,
> >
> > ...so this can just use attr.
>
> I also need ignored_ns...
>
> > > + false, false, nullptr, nullptr };
> > > + table[1] = { nullptr, 0, 0, false, false, false, false, nullptr, nullptr };
> > > + register_scoped_attributes (table, vendor, ignored_ns);
>
> ...here, but I tweaked this a bit to get rid of the bool.
>
> > > + }
> > > +}
> > > +
> > > +/* Free data we might have allocated when adding extra attributes. */
> > > +
> > > +void
> > > +free_attr_data ()
> > > +{
> > > + for (auto x : ignored_attributes_table)
> > > + delete[] x;
> > > +}
> >
> > You probably also want to zero out ignored_attributes_table at this point.
>
> Done.
>
> > > /* Initialize attribute tables, and make some sanity checks if checking is
> > > enabled. */
> > > @@ -252,6 +353,9 @@ init_attributes (void)
> > > /* Put all the GNU attributes into the "gnu" namespace. */
> > > register_scoped_attributes (attribute_tables[i], "gnu");
> > > + vec<char *> *ignored = (vec<char *> *) flag_ignored_attributes;
> > > + handle_ignored_attributes_option (ignored);
> > > +
> > > invoke_plugin_callbacks (PLUGIN_ATTRIBUTES, NULL);
> > > attributes_initialized = true;
> > > }
> > > @@ -456,6 +560,19 @@ diag_attr_exclusions (tree last_decl, tree node, tree attrname,
> > > return found;
> > > }
> > > +/* Return true iff we should not complain about unknown attributes
> > > + coming from the attribute namespace NS. This is the case for
> > > + the -Wno-attributes=ns:: command-line option. */
> > > +
> > > +static bool
> > > +attr_namespace_ignored_p (tree ns)
> > > +{
> > > + if (ns == NULL_TREE)
> > > + return false;
> > > + scoped_attributes *r = find_attribute_namespace (IDENTIFIER_POINTER (ns));
> > > + return r && r->ignored_p;
> > > +}
> > > +
> > > /* Process the attributes listed in ATTRIBUTES and install them in *NODE,
> > > which is either a DECL (including a TYPE_DECL) or a TYPE. If a DECL,
> > > it should be modified in place; if a TYPE, a copy should be created
> > > @@ -556,7 +673,8 @@ decl_attributes (tree *node, tree attributes, int flags,
> > > if (spec == NULL)
> > > {
> > > - if (!(flags & (int) ATTR_FLAG_BUILT_IN))
> > > + if (!(flags & (int) ATTR_FLAG_BUILT_IN)
> > > + && !attr_namespace_ignored_p (ns))
> > > {
> > > if (ns == NULL_TREE || !cxx11_attr_p)
> > > warning (OPT_Wattributes, "%qE attribute directive ignored",
> > > diff --git a/gcc/attribs.h b/gcc/attribs.h
> > > index 138c509bce1..96a527f67a9 100644
> > > --- a/gcc/attribs.h
> > > +++ b/gcc/attribs.h
> > > @@ -21,6 +21,7 @@ along with GCC; see the file COPYING3. If not see
> > > #define GCC_ATTRIBS_H
> > > extern const struct attribute_spec *lookup_attribute_spec (const_tree);
> > > +extern void free_attr_data ();
> > > extern void init_attributes (void);
> > > /* Process the attributes listed in ATTRIBUTES and install them in *NODE,
> > > @@ -40,12 +41,14 @@ extern void apply_tm_attr (tree, tree);
> > > extern tree make_attribute (const char *, const char *, tree);
> > > extern struct scoped_attributes* register_scoped_attributes (const struct attribute_spec *,
> > > - const char *);
> > > + const char *,
> > > + bool = false);
> > > extern char *sorted_attr_string (tree);
> > > extern bool common_function_versions (tree, tree);
> > > extern tree make_dispatcher_decl (const tree);
> > > extern bool is_function_default_version (const tree);
> > > +extern void handle_ignored_attributes_option (vec<char *> *);
> > > /* Return a type like TTYPE except that its TYPE_ATTRIBUTES
> > > is ATTRIBUTE.
> > > diff --git a/gcc/c-family/c-pragma.c b/gcc/c-family/c-pragma.c
> > > index a9be8df0384..6beba5503f0 100644
> > > --- a/gcc/c-family/c-pragma.c
> > > +++ b/gcc/c-family/c-pragma.c
> > > @@ -764,7 +764,7 @@ handle_pragma_diagnostic(cpp_reader *ARG_UNUSED(dummy))
> > > if (token != CPP_NAME)
> > > {
> > > warning_at (loc, OPT_Wpragmas,
> > > - "missing [error|warning|ignored|push|pop]"
> > > + "missing [error|warning|ignored|push|pop|ignored_attributes]"
> > > " after %<#pragma GCC diagnostic%>");
> > > return;
> > > }
> > > @@ -787,10 +787,43 @@ handle_pragma_diagnostic(cpp_reader *ARG_UNUSED(dummy))
> > > diagnostic_pop_diagnostics (global_dc, input_location);
> > > return;
> > > }
> > > + else if (strcmp (kind_string, "ignored_attributes") == 0)
> > > + {
> > > + token = pragma_lex (&x, &loc);
> > > + if (token != CPP_STRING)
> > > + {
> > > + warning_at (loc, OPT_Wpragmas,
> > > + "missing attribute name after %<#pragma GCC diagnostic "
> > > + "ignored_attributes%>");
> > > + return;
> > > + }
> > > + char *args = xstrdup (TREE_STRING_POINTER (x));
> > > + const size_t l = strlen (args);
> > > + if (l == 0)
> > > + {
> > > + warning_at (loc, OPT_Wpragmas, "missing argument to %<#pragma GCC "
> > > + "diagnostic ignored_attributes%>");
> > > + free (args);
> > > + return;
> > > + }
> > > + else if (args[l - 1] == ',')
> > > + {
> > > + warning_at (loc, OPT_Wpragmas, "trailing %<,%> in arguments for "
> > > + "%<#pragma GCC diagnostic ignored_attributes%>");
> > > + free (args);
> > > + return;
> > > + }
> > > + auto_vec<char *> v;
> > > + for (char *p = strtok (args, ","); p; p = strtok (NULL, ","))
> > > + v.safe_push (p);
> > > + handle_ignored_attributes_option (&v);
> > > + /* ??? We can't free (args); here. */
> >
> > Perhaps we want to copy strings in handle_ignored_attributes_option rather
> > than here?
>
> Well, the other use doesn't need copying, so I left it be.
>
> > > + return;
> > > + }
> > > else
> > > {
> > > warning_at (loc, OPT_Wpragmas,
> > > - "expected [error|warning|ignored|push|pop]"
> > > + "expected [error|warning|ignored|push|pop|ignored_attributes]"
> > > " after %<#pragma GCC diagnostic%>");
> > > return;
> > > }
> > > diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c
> > > index 771efa3eadf..345c8f9d620 100644
> > > --- a/gcc/c/c-decl.c
> > > +++ b/gcc/c/c-decl.c
> > > @@ -12295,6 +12295,8 @@ c_parse_final_cleanups (void)
> > > c_write_global_declarations_1 (BLOCK_VARS (DECL_INITIAL (t)));
> > > c_write_global_declarations_1 (BLOCK_VARS (ext_block));
> > > + free_attr_data ();
> >
> > Since handle_ignored_attributes_option is in language-independent code,
> > shouldn't this call be as well?
>
> Good point, I've moved it into compile_file. I don't where else it could
> have gone.
>
> 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.
>
> gcc/c-family/ChangeLog:
>
> * c-pragma.c (handle_pragma_diagnostic): Handle #pragma GCC diagnostic
> ignored_attributes.
>
> gcc/c/ChangeLog:
>
> * c-decl.c (c_parse_final_cleanups): Call free_attr_data.
>
> gcc/cp/ChangeLog:
>
> * decl2.c (c_parse_final_cleanups): Call free_attr_data.
>
> gcc/testsuite/ChangeLog:
>
> * c-c++-common/Wno-attributes-1.c: New test.
> * c-c++-common/Wno-attributes-2.c: New test.
> ---
> gcc/attribs.c | 120 +++++++++++++++++-
> 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, 338 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..d5fba7f4bbb 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,92 @@ 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 ARGS 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 *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::%>");
> + continue;
> + }
> + /* Cut off the vendor part. */
> + *q = '\0';
> + char *vendor = opt;
> + char *attr = q + 2;
> + /* Verify that they look valid. */
> + auto valid_p = [](const char *s) {
> + for (; *s != '\0'; ++s)
> + if (!ISALNUM (*s) && *s != '_')
> + return false;
> + return true;
> + };
> + if (!valid_p (vendor) || !valid_p (attr))
> + {
> + 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) {
> + const size_t l = strlen (s);
> + if (l > 4 && s[0] == '_' && s[1] == '_'
> + && s[l - 1] == '_' && s[l - 2] == '_')
> + {
> + s[l - 2] = '\0';
> + s += 2;
> + }
> + };
> + strip (attr);
> + strip (vendor);
> + /* 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 (get_identifier (vendor),
> + get_identifier (attr)))
> + continue;
> + /* In the "vendor::" case, we should ignore *any* attribute coming
> + from this attribute namespace. */
> + if (attr[0] == '\0')
> + attr = nullptr;
> + /* Create a table with extra attributes which we will register.
> + We can't free it here, so squirrel away the pointers. */
> + attribute_spec *table = new attribute_spec[2];
> + ignored_attributes_table.safe_push (table);
> + table[0] = { attr, 0, 0, false, false, false, false, nullptr, nullptr };
> + table[1] = { nullptr, 0, 0, false, false, false, false, nullptr,
> + nullptr };
> + register_scoped_attributes (table, vendor, !attr);
> + }
> +}
> +
> +/* Free data we might have allocated when adding extra attributes. */
> +
> +void
> +free_attr_data ()
> +{
> + for (auto x : ignored_attributes_table)
> + delete[] x;
> + ignored_attributes_table.release ();
> +}
> +
> /* Initialize attribute tables, and make some sanity checks if checking is
> enabled. */
>
> @@ -252,6 +347,9 @@ init_attributes (void)
> /* Put all the GNU attributes into the "gnu" namespace. */
> register_scoped_attributes (attribute_tables[i], "gnu");
>
> + vec<char *> *ignored = (vec<char *> *) flag_ignored_attributes;
> + handle_ignored_attributes_option (ignored);
> +
> invoke_plugin_callbacks (PLUGIN_ATTRIBUTES, NULL);
> attributes_initialized = true;
> }
> @@ -456,6 +554,19 @@ diag_attr_exclusions (tree last_decl, tree node, tree attrname,
> return found;
> }
>
> +/* Return true iff we should not complain about unknown attributes
> + coming from the attribute namespace NS. This is the case for
> + the -Wno-attributes=ns:: command-line option. */
> +
> +static bool
> +attr_namespace_ignored_p (tree ns)
> +{
> + if (ns == NULL_TREE)
> + return false;
> + scoped_attributes *r = find_attribute_namespace (IDENTIFIER_POINTER (ns));
> + return r && r->ignored_p;
> +}
> +
> /* Process the attributes listed in ATTRIBUTES and install them in *NODE,
> which is either a DECL (including a TYPE_DECL) or a TYPE. If a DECL,
> it should be modified in place; if a TYPE, a copy should be created
> @@ -556,7 +667,8 @@ decl_attributes (tree *node, tree attributes, int flags,
>
> if (spec == NULL)
> {
> - if (!(flags & (int) ATTR_FLAG_BUILT_IN))
> + if (!(flags & (int) ATTR_FLAG_BUILT_IN)
> + && !attr_namespace_ignored_p (ns))
> {
> if (ns == NULL_TREE || !cxx11_attr_p)
> warning (OPT_Wattributes, "%qE attribute directive ignored",
> diff --git a/gcc/attribs.h b/gcc/attribs.h
> index 138c509bce1..96a527f67a9 100644
> --- a/gcc/attribs.h
> +++ b/gcc/attribs.h
> @@ -21,6 +21,7 @@ along with GCC; see the file COPYING3. If not see
> #define GCC_ATTRIBS_H
>
> extern const struct attribute_spec *lookup_attribute_spec (const_tree);
> +extern void free_attr_data ();
> extern void init_attributes (void);
>
> /* Process the attributes listed in ATTRIBUTES and install them in *NODE,
> @@ -40,12 +41,14 @@ extern void apply_tm_attr (tree, tree);
> extern tree make_attribute (const char *, const char *, tree);
>
> extern struct scoped_attributes* register_scoped_attributes (const struct attribute_spec *,
> - const char *);
> + const char *,
> + bool = false);
>
> extern char *sorted_attr_string (tree);
> extern bool common_function_versions (tree, tree);
> extern tree make_dispatcher_decl (const tree);
> extern bool is_function_default_version (const tree);
> +extern void handle_ignored_attributes_option (vec<char *> *);
>
> /* Return a type like TTYPE except that its TYPE_ATTRIBUTES
> is ATTRIBUTE.
> diff --git a/gcc/c-family/c-pragma.c b/gcc/c-family/c-pragma.c
> index a9be8df0384..6beba5503f0 100644
> --- a/gcc/c-family/c-pragma.c
> +++ b/gcc/c-family/c-pragma.c
> @@ -764,7 +764,7 @@ handle_pragma_diagnostic(cpp_reader *ARG_UNUSED(dummy))
> if (token != CPP_NAME)
> {
> warning_at (loc, OPT_Wpragmas,
> - "missing [error|warning|ignored|push|pop]"
> + "missing [error|warning|ignored|push|pop|ignored_attributes]"
> " after %<#pragma GCC diagnostic%>");
> return;
> }
> @@ -787,10 +787,43 @@ handle_pragma_diagnostic(cpp_reader *ARG_UNUSED(dummy))
> diagnostic_pop_diagnostics (global_dc, input_location);
> return;
> }
> + else if (strcmp (kind_string, "ignored_attributes") == 0)
> + {
> + token = pragma_lex (&x, &loc);
> + if (token != CPP_STRING)
> + {
> + warning_at (loc, OPT_Wpragmas,
> + "missing attribute name after %<#pragma GCC diagnostic "
> + "ignored_attributes%>");
> + return;
> + }
> + char *args = xstrdup (TREE_STRING_POINTER (x));
> + const size_t l = strlen (args);
> + if (l == 0)
> + {
> + warning_at (loc, OPT_Wpragmas, "missing argument to %<#pragma GCC "
> + "diagnostic ignored_attributes%>");
> + free (args);
> + return;
> + }
> + else if (args[l - 1] == ',')
> + {
> + warning_at (loc, OPT_Wpragmas, "trailing %<,%> in arguments for "
> + "%<#pragma GCC diagnostic ignored_attributes%>");
> + free (args);
> + return;
> + }
> + auto_vec<char *> v;
> + for (char *p = strtok (args, ","); p; p = strtok (NULL, ","))
> + v.safe_push (p);
> + handle_ignored_attributes_option (&v);
> + /* ??? We can't free (args); here. */
> + return;
> + }
> else
> {
> warning_at (loc, OPT_Wpragmas,
> - "expected [error|warning|ignored|push|pop]"
> + "expected [error|warning|ignored|push|pop|ignored_attributes]"
> " after %<#pragma GCC diagnostic%>");
> return;
> }
> diff --git a/gcc/common.opt b/gcc/common.opt
> index a9644cae4f0..c429e43c6c1 100644
> --- a/gcc/common.opt
> +++ b/gcc/common.opt
> @@ -83,7 +83,7 @@ int flag_gen_aux_info = 0
> Variable
> int flag_shlib
>
> -; These two are really VEC(char_p,heap) *.
> +; These three are really VEC(char_p,heap) *.
>
> Variable
> void *flag_instrument_functions_exclude_functions
> @@ -91,6 +91,9 @@ void *flag_instrument_functions_exclude_functions
> Variable
> void *flag_instrument_functions_exclude_files
>
> +Variable
> +void *flag_ignored_attributes
> +
> ; Generic structs (e.g. templates not explicitly specialized)
> ; may not have a compilation unit associated with them, and so
> ; may need to be treated differently from ordinary structs.
> @@ -549,6 +552,10 @@ Wattributes
> Common Var(warn_attributes) Init(1) Warning
> Warn about inappropriate attribute usage.
>
> +Wattributes=
> +Common Joined
> +Do not warn about specified attributes.
> +
> Wattribute-alias
> Common Alias(Wattribute_alias=, 1, 0) Warning
> Warn about type safety and similar errors and mismatches in declarations with alias attributes.
> diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
> index b4c5376223a..28fd0cc6dd5 100644
> --- a/gcc/doc/extend.texi
> +++ b/gcc/doc/extend.texi
> @@ -23761,6 +23761,25 @@ restored.
> foo(d); /* depends on command-line options */
> @end smallexample
>
> +@item #pragma GCC diagnostic ignored_attributes
> +
> +Similarly to @option{-Wno-attributes=}, this pragma allows users to suppress
> +warnings about unknown scoped attributes (in C++11 and C2X). For example,
> +@code{#pragma GCC diagnostic ignored_attributes "vendor::attr"} disables
> +warning about the following declaration:
> +
> +@smallexample
> +[[vendor::attr]] void f();
> +@end smallexample
> +
> +whereas @code{#pragma GCC diagnostic ignored_attributes "vendor::"} prevents
> +warning about both of these declarations:
> +
> +@smallexample
> +[[vendor::safe]] void f();
> +[[vendor::unsafe]] void f2();
> +@end smallexample
> +
> @end table
>
> GCC also offers a simple mechanism for printing messages during
> diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
> index 5b016166972..fe2cb768c61 100644
> --- a/gcc/doc/invoke.texi
> +++ b/gcc/doc/invoke.texi
> @@ -8623,6 +8623,26 @@ unrecognized attributes, function attributes applied to variables,
> etc. This does not stop errors for incorrect use of supported
> attributes.
>
> +Additionally, using @option{-Wno-attributes=}, it is possible to suppress
> +warnings about unknown scoped attributes (in C++11 and C2X). For example,
> +@option{-Wno-attributes=vendor::attr} disables warning about the following
> +declaration:
> +
> +@smallexample
> +[[vendor::attr]] void f();
> +@end smallexample
> +
> +It is also possible to disable warning about all attributes in a namespace
> +using @option{-Wno-attributes=vendor::} which prevents warning about both
> +of these declarations:
> +
> +@smallexample
> +[[vendor::safe]] void f();
> +[[vendor::unsafe]] void f2();
> +@end smallexample
> +
> +Note that @option{-Wno-attributes=} does not imply @option{-Wno-attributes}.
> +
> @item -Wno-builtin-declaration-mismatch
> @opindex Wno-builtin-declaration-mismatch
> @opindex Wbuiltin-declaration-mismatch
> diff --git a/gcc/opts.c b/gcc/opts.c
> index 6503980cd33..e3b66ad0d43 100644
> --- a/gcc/opts.c
> +++ b/gcc/opts.c
> @@ -2558,6 +2558,26 @@ common_handle_option (struct gcc_options *opts,
> /* Currently handled in a prescan. */
> break;
>
> + case OPT_Wattributes_:
> + if (lang_mask == CL_DRIVER)
> + break;
> +
> + if (value)
> + {
> + error_at (loc, "arguments ignored for %<-Wattributes=%>; use "
> + "%<-Wno-attributes=%> instead");
> + break;
> + }
> + else if (arg[strlen (arg) - 1] == ',')
> + {
> + error_at (loc, "trailing %<,%> in arguments for "
> + "%<-Wno-attributes=%>");
> + break;
> + }
> +
> + add_comma_separated_to_vector (&opts->x_flag_ignored_attributes, arg);
> + break;
> +
> case OPT_Werror:
> dc->warning_as_error_requested = value;
> break;
> diff --git a/gcc/plugin.h b/gcc/plugin.h
> index 1640e253ca5..5556763d1bf 100644
> --- a/gcc/plugin.h
> +++ b/gcc/plugin.h
> @@ -197,7 +197,9 @@ invoke_plugin_callbacks (int event ATTRIBUTE_UNUSED,
> /* In attribs.c. */
>
> extern void register_attribute (const struct attribute_spec *attr);
> +/* The default argument for the third parameter is given in attribs.h. */
> extern struct scoped_attributes* register_scoped_attributes (const struct attribute_spec *,
> - const char *);
> + const char *,
> + bool);
>
> #endif /* PLUGIN_H */
> diff --git a/gcc/testsuite/c-c++-common/Wno-attributes-1.c b/gcc/testsuite/c-c++-common/Wno-attributes-1.c
> new file mode 100644
> index 00000000000..aac1a69fd85
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/Wno-attributes-1.c
> @@ -0,0 +1,55 @@
> +/* PR c++/101940 */
> +/* { dg-do compile } */
> +/* { dg-additional-options "-std=c++11" { target c++ } } */
> +/* { dg-additional-options "-Wno-attributes=company::,yoyodyne::attr" } */
> +/* { dg-additional-options "-Wno-attributes=c1::attr,c1::attr,c1::__attr__" } */
> +/* { dg-additional-options "-Wno-attributes=c2::,c2::attr" } */
> +/* { dg-additional-options "-Wno-attributes=c3::attr,c3::" } */
> +/* { dg-additional-options "-Wno-attributes=x::" } */
> +/* { dg-additional-options "-Wno-attributes=yoyodyne::attr_new" } */
> +/* { dg-additional-options "-Wno-attributes=c4::__attr__" } */
> +/* { dg-additional-options "-Wno-attributes=c5::attr" } */
> +/* { dg-additional-options "-Wno-attributes=__c6__::attr" } */
> +
> +[[company::attr]] void f1();
> +[[company::attr2]] void f2();
> +
> +[[yoyodyne::attr]] void f3();
> +[[yoyodyne::__attr__]] void f3__();
> +[[yoyodyne::attrx]] void f4(); /* { dg-warning "ignored" } */
> +[[yoyodyne::__attrx__]] void f4__(); /* { dg-warning "ignored" } */
> +
> +[[c1::attr]] void f5();
> +
> +[[c2::attr]] void f6();
> +[[c2::attrx]] void f7();
> +[[c2::__attr__]] void f6__();
> +[[c2::__attrx__]] void f7__();
> +
> +[[c3::attr]] void f8();
> +[[c3::attrx]] void f9();
> +
> +[[x::x]] void f10();
> +
> +[[yoyodyne::attr_new]] void f11();
> +[[yoyodyne::__attr_new__]] void f11__();
> +[[yoyodyne::attr_mew]] void f12(); /* { dg-warning "ignored" } */
> +[[yoyodyne::__attr_mew__]] void f12__(); /* { dg-warning "ignored" } */
> +
> +[[c4::attr]] void f13();
> +[[c4::__attr__]] void f13__();
> +[[c4::attrx]] void f14(); /* { dg-warning "ignored" } */
> +
> +[[c5::attr]] void f15();
> +[[c5::__attr__]] void f15__();
> +[[__c5__::attr]] void __f15();
> +[[__c5__::__attr__]] void __f15__();
> +[[c5::attrx]] void f15x(); /* { dg-warning "ignored" } */
> +[[__c5__::attrx]] void f15x(); /* { dg-warning "ignored" } */
> +
> +[[c6::attr]] void f16();
> +[[c6::__attr__]] void f16__();
> +[[__c6__::attr]] void __f16();
> +[[__c6__::__attr__]] void __f16__();
> +[[c6::attrx]] void f16x(); /* { dg-warning "ignored" } */
> +[[__c6__::attrx]] void f16x(); /* { dg-warning "ignored" } */
> diff --git a/gcc/testsuite/c-c++-common/Wno-attributes-2.c b/gcc/testsuite/c-c++-common/Wno-attributes-2.c
> new file mode 100644
> index 00000000000..4307c74b048
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/Wno-attributes-2.c
> @@ -0,0 +1,56 @@
> +/* PR c++/101940 */
> +/* { dg-do compile } */
> +/* { dg-additional-options "-std=c++11" { target c++ } } */
> +
> +#pragma GCC diagnostic ignored_attributes "company::,yoyodyne::attr"
> +#pragma GCC diagnostic ignored_attributes "c1::attr,c1::attr,c1::__attr__"
> +#pragma GCC diagnostic ignored_attributes "c2::,c2::attr"
> +#pragma GCC diagnostic ignored_attributes "c3::attr,c3::"
> +#pragma GCC diagnostic ignored_attributes "x::"
> +#pragma GCC diagnostic ignored_attributes "yoyodyne::attr_new"
> +#pragma GCC diagnostic ignored_attributes "c4::__attr__"
> +#pragma GCC diagnostic ignored_attributes "c5::attr"
> +#pragma GCC diagnostic ignored_attributes "__c6__::attr"
> +
> +[[company::attr]] void f1();
> +[[company::attr2]] void f2();
> +
> +[[yoyodyne::attr]] void f3();
> +[[yoyodyne::__attr__]] void f3__();
> +[[yoyodyne::attrx]] void f4(); /* { dg-warning "ignored" } */
> +[[yoyodyne::__attrx__]] void f4__(); /* { dg-warning "ignored" } */
> +
> +[[c1::attr]] void f5();
> +
> +[[c2::attr]] void f6();
> +[[c2::attrx]] void f7();
> +[[c2::__attr__]] void f6__();
> +[[c2::__attrx__]] void f7__();
> +
> +[[c3::attr]] void f8();
> +[[c3::attrx]] void f9();
> +
> +[[x::x]] void f10();
> +
> +[[yoyodyne::attr_new]] void f11();
> +[[yoyodyne::__attr_new__]] void f11__();
> +[[yoyodyne::attr_mew]] void f12(); /* { dg-warning "ignored" } */
> +[[yoyodyne::__attr_mew__]] void f12__(); /* { dg-warning "ignored" } */
> +
> +[[c4::attr]] void f13();
> +[[c4::__attr__]] void f13__();
> +[[c4::attrx]] void f14(); /* { dg-warning "ignored" } */
> +
> +[[c5::attr]] void f15();
> +[[c5::__attr__]] void f15__();
> +[[__c5__::attr]] void __f15();
> +[[__c5__::__attr__]] void __f15__();
> +[[c5::attrx]] void f15x(); /* { dg-warning "ignored" } */
> +[[__c5__::attrx]] void f15x(); /* { dg-warning "ignored" } */
> +
> +[[c6::attr]] void f16();
> +[[c6::__attr__]] void f16__();
> +[[__c6__::attr]] void __f16();
> +[[__c6__::__attr__]] void __f16__();
> +[[c6::attrx]] void f16x(); /* { dg-warning "ignored" } */
> +[[__c6__::attrx]] void f16x(); /* { dg-warning "ignored" } */
> diff --git a/gcc/toplev.c b/gcc/toplev.c
> index e1688aae724..f5ccaf8f799 100644
> --- a/gcc/toplev.c
> +++ b/gcc/toplev.c
> @@ -463,6 +463,8 @@ compile_file (void)
> if (flag_dump_locations)
> dump_location_info (stderr);
>
> + free_attr_data ();
> +
> /* Compilation is now finished except for writing
> what's left of the symbol table output. */
>
>
> base-commit: a11052d98db2f2a61841f0c5ee84de4ca1b3e296
> --
> 2.31.1
>
Marek
Ping.
On Mon, Oct 11, 2021 at 11:17:11AM -0400, Marek Polacek wrote:
> Ping.
>
> On Tue, Sep 28, 2021 at 04:20:46PM -0400, Marek Polacek wrote:
> > On Thu, Sep 23, 2021 at 02:25:16PM -0400, Jason Merrill wrote:
> > > On 9/20/21 18:59, Marek Polacek via Gcc-patches wrote:
> > > > +void
> > > > +handle_ignored_attributes_option (vec<char *> *v)
> > > > +{
> > > > + if (v == nullptr)
> > > > + return;
> > > > +
> > > > + for (auto opt : v)
> > > > + {
> > > > + if (strcmp (opt, "clang") == 0)
> > > > + {
> > > > + // TODO
> > > > + continue;
> > > > + }
> > >
> > > If this doesn't work yet, let's not accept it at all for now.
> >
> > Ok.
> >
> > > > + 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%>, %<ns::%>, "
> > > > + "or %<clang%>");
> > >
> > > ...or even mention it. Users can ignore clang:: instead, it doesn't matter
> > > to us if clang attributes are misspelled.
> >
> > Removed.
> >
> > > > + continue;
> > > > + }
> > > > + /* Cut off the vendor part. */
> > > > + *q = '\0';
> > > > + char *vendor = opt;
> > > > + char *attr = q + 2;
> > > > + /* Verify that they look valid. */
> > > > + auto valid_p = [](const char *s) {
> > > > + for (; *s != '\0'; ++s)
> > > > + if (!ISALNUM (*s) && *s != '_')
> > > > + return false;
> > > > + return true;
> > > > + };
> > > > + if (!valid_p (vendor) || !valid_p (attr))
> > > > + {
> > > > + 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) {
> > > > + const size_t l = strlen (s);
> > > > + if (l > 4 && s[0] == '_' && s[1] == '_'
> > > > + && s[l - 1] == '_' && s[l - 2] == '_')
> > > > + {
> > > > + s[l - 2] = '\0';
> > > > + s += 2;
> > > > + }
> > > > + };
> > > > + strip (attr);
> > > > + strip (vendor);
> > > > + /* 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 (get_identifier (vendor),
> > > > + get_identifier (attr)))
> > > > + continue;
> > > > + /* In the "vendor::" case, we should ignore *any* attribute coming
> > > > + from this attribute namespace. */
> > > > + const bool ignored_ns = attr[0] == '\0';
> > >
> > > Maybe set attr to nullptr instead of declaring ignored_ns?
> > >
> > > > + /* Create a table with extra attributes which we will register.
> > > > + We can't free it here, so squirrel away the pointers. */
> > > > + attribute_spec *table = new attribute_spec[2];
> > > > + ignored_attributes_table.safe_push (table);
> > > > + table[0] = { ignored_ns ? nullptr : attr, 0, 0, false, false,
> > >
> > > ...so this can just use attr.
> >
> > I also need ignored_ns...
> >
> > > > + false, false, nullptr, nullptr };
> > > > + table[1] = { nullptr, 0, 0, false, false, false, false, nullptr, nullptr };
> > > > + register_scoped_attributes (table, vendor, ignored_ns);
> >
> > ...here, but I tweaked this a bit to get rid of the bool.
> >
> > > > + }
> > > > +}
> > > > +
> > > > +/* Free data we might have allocated when adding extra attributes. */
> > > > +
> > > > +void
> > > > +free_attr_data ()
> > > > +{
> > > > + for (auto x : ignored_attributes_table)
> > > > + delete[] x;
> > > > +}
> > >
> > > You probably also want to zero out ignored_attributes_table at this point.
> >
> > Done.
> >
> > > > /* Initialize attribute tables, and make some sanity checks if checking is
> > > > enabled. */
> > > > @@ -252,6 +353,9 @@ init_attributes (void)
> > > > /* Put all the GNU attributes into the "gnu" namespace. */
> > > > register_scoped_attributes (attribute_tables[i], "gnu");
> > > > + vec<char *> *ignored = (vec<char *> *) flag_ignored_attributes;
> > > > + handle_ignored_attributes_option (ignored);
> > > > +
> > > > invoke_plugin_callbacks (PLUGIN_ATTRIBUTES, NULL);
> > > > attributes_initialized = true;
> > > > }
> > > > @@ -456,6 +560,19 @@ diag_attr_exclusions (tree last_decl, tree node, tree attrname,
> > > > return found;
> > > > }
> > > > +/* Return true iff we should not complain about unknown attributes
> > > > + coming from the attribute namespace NS. This is the case for
> > > > + the -Wno-attributes=ns:: command-line option. */
> > > > +
> > > > +static bool
> > > > +attr_namespace_ignored_p (tree ns)
> > > > +{
> > > > + if (ns == NULL_TREE)
> > > > + return false;
> > > > + scoped_attributes *r = find_attribute_namespace (IDENTIFIER_POINTER (ns));
> > > > + return r && r->ignored_p;
> > > > +}
> > > > +
> > > > /* Process the attributes listed in ATTRIBUTES and install them in *NODE,
> > > > which is either a DECL (including a TYPE_DECL) or a TYPE. If a DECL,
> > > > it should be modified in place; if a TYPE, a copy should be created
> > > > @@ -556,7 +673,8 @@ decl_attributes (tree *node, tree attributes, int flags,
> > > > if (spec == NULL)
> > > > {
> > > > - if (!(flags & (int) ATTR_FLAG_BUILT_IN))
> > > > + if (!(flags & (int) ATTR_FLAG_BUILT_IN)
> > > > + && !attr_namespace_ignored_p (ns))
> > > > {
> > > > if (ns == NULL_TREE || !cxx11_attr_p)
> > > > warning (OPT_Wattributes, "%qE attribute directive ignored",
> > > > diff --git a/gcc/attribs.h b/gcc/attribs.h
> > > > index 138c509bce1..96a527f67a9 100644
> > > > --- a/gcc/attribs.h
> > > > +++ b/gcc/attribs.h
> > > > @@ -21,6 +21,7 @@ along with GCC; see the file COPYING3. If not see
> > > > #define GCC_ATTRIBS_H
> > > > extern const struct attribute_spec *lookup_attribute_spec (const_tree);
> > > > +extern void free_attr_data ();
> > > > extern void init_attributes (void);
> > > > /* Process the attributes listed in ATTRIBUTES and install them in *NODE,
> > > > @@ -40,12 +41,14 @@ extern void apply_tm_attr (tree, tree);
> > > > extern tree make_attribute (const char *, const char *, tree);
> > > > extern struct scoped_attributes* register_scoped_attributes (const struct attribute_spec *,
> > > > - const char *);
> > > > + const char *,
> > > > + bool = false);
> > > > extern char *sorted_attr_string (tree);
> > > > extern bool common_function_versions (tree, tree);
> > > > extern tree make_dispatcher_decl (const tree);
> > > > extern bool is_function_default_version (const tree);
> > > > +extern void handle_ignored_attributes_option (vec<char *> *);
> > > > /* Return a type like TTYPE except that its TYPE_ATTRIBUTES
> > > > is ATTRIBUTE.
> > > > diff --git a/gcc/c-family/c-pragma.c b/gcc/c-family/c-pragma.c
> > > > index a9be8df0384..6beba5503f0 100644
> > > > --- a/gcc/c-family/c-pragma.c
> > > > +++ b/gcc/c-family/c-pragma.c
> > > > @@ -764,7 +764,7 @@ handle_pragma_diagnostic(cpp_reader *ARG_UNUSED(dummy))
> > > > if (token != CPP_NAME)
> > > > {
> > > > warning_at (loc, OPT_Wpragmas,
> > > > - "missing [error|warning|ignored|push|pop]"
> > > > + "missing [error|warning|ignored|push|pop|ignored_attributes]"
> > > > " after %<#pragma GCC diagnostic%>");
> > > > return;
> > > > }
> > > > @@ -787,10 +787,43 @@ handle_pragma_diagnostic(cpp_reader *ARG_UNUSED(dummy))
> > > > diagnostic_pop_diagnostics (global_dc, input_location);
> > > > return;
> > > > }
> > > > + else if (strcmp (kind_string, "ignored_attributes") == 0)
> > > > + {
> > > > + token = pragma_lex (&x, &loc);
> > > > + if (token != CPP_STRING)
> > > > + {
> > > > + warning_at (loc, OPT_Wpragmas,
> > > > + "missing attribute name after %<#pragma GCC diagnostic "
> > > > + "ignored_attributes%>");
> > > > + return;
> > > > + }
> > > > + char *args = xstrdup (TREE_STRING_POINTER (x));
> > > > + const size_t l = strlen (args);
> > > > + if (l == 0)
> > > > + {
> > > > + warning_at (loc, OPT_Wpragmas, "missing argument to %<#pragma GCC "
> > > > + "diagnostic ignored_attributes%>");
> > > > + free (args);
> > > > + return;
> > > > + }
> > > > + else if (args[l - 1] == ',')
> > > > + {
> > > > + warning_at (loc, OPT_Wpragmas, "trailing %<,%> in arguments for "
> > > > + "%<#pragma GCC diagnostic ignored_attributes%>");
> > > > + free (args);
> > > > + return;
> > > > + }
> > > > + auto_vec<char *> v;
> > > > + for (char *p = strtok (args, ","); p; p = strtok (NULL, ","))
> > > > + v.safe_push (p);
> > > > + handle_ignored_attributes_option (&v);
> > > > + /* ??? We can't free (args); here. */
> > >
> > > Perhaps we want to copy strings in handle_ignored_attributes_option rather
> > > than here?
> >
> > Well, the other use doesn't need copying, so I left it be.
> >
> > > > + return;
> > > > + }
> > > > else
> > > > {
> > > > warning_at (loc, OPT_Wpragmas,
> > > > - "expected [error|warning|ignored|push|pop]"
> > > > + "expected [error|warning|ignored|push|pop|ignored_attributes]"
> > > > " after %<#pragma GCC diagnostic%>");
> > > > return;
> > > > }
> > > > diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c
> > > > index 771efa3eadf..345c8f9d620 100644
> > > > --- a/gcc/c/c-decl.c
> > > > +++ b/gcc/c/c-decl.c
> > > > @@ -12295,6 +12295,8 @@ c_parse_final_cleanups (void)
> > > > c_write_global_declarations_1 (BLOCK_VARS (DECL_INITIAL (t)));
> > > > c_write_global_declarations_1 (BLOCK_VARS (ext_block));
> > > > + free_attr_data ();
> > >
> > > Since handle_ignored_attributes_option is in language-independent code,
> > > shouldn't this call be as well?
> >
> > Good point, I've moved it into compile_file. I don't where else it could
> > have gone.
> >
> > 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.
> >
> > gcc/c-family/ChangeLog:
> >
> > * c-pragma.c (handle_pragma_diagnostic): Handle #pragma GCC diagnostic
> > ignored_attributes.
> >
> > gcc/c/ChangeLog:
> >
> > * c-decl.c (c_parse_final_cleanups): Call free_attr_data.
> >
> > gcc/cp/ChangeLog:
> >
> > * decl2.c (c_parse_final_cleanups): Call free_attr_data.
> >
> > gcc/testsuite/ChangeLog:
> >
> > * c-c++-common/Wno-attributes-1.c: New test.
> > * c-c++-common/Wno-attributes-2.c: New test.
> > ---
> > gcc/attribs.c | 120 +++++++++++++++++-
> > 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, 338 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..d5fba7f4bbb 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,92 @@ 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 ARGS 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 *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::%>");
> > + continue;
> > + }
> > + /* Cut off the vendor part. */
> > + *q = '\0';
> > + char *vendor = opt;
> > + char *attr = q + 2;
> > + /* Verify that they look valid. */
> > + auto valid_p = [](const char *s) {
> > + for (; *s != '\0'; ++s)
> > + if (!ISALNUM (*s) && *s != '_')
> > + return false;
> > + return true;
> > + };
> > + if (!valid_p (vendor) || !valid_p (attr))
> > + {
> > + 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) {
> > + const size_t l = strlen (s);
> > + if (l > 4 && s[0] == '_' && s[1] == '_'
> > + && s[l - 1] == '_' && s[l - 2] == '_')
> > + {
> > + s[l - 2] = '\0';
> > + s += 2;
> > + }
> > + };
> > + strip (attr);
> > + strip (vendor);
> > + /* 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 (get_identifier (vendor),
> > + get_identifier (attr)))
> > + continue;
> > + /* In the "vendor::" case, we should ignore *any* attribute coming
> > + from this attribute namespace. */
> > + if (attr[0] == '\0')
> > + attr = nullptr;
> > + /* Create a table with extra attributes which we will register.
> > + We can't free it here, so squirrel away the pointers. */
> > + attribute_spec *table = new attribute_spec[2];
> > + ignored_attributes_table.safe_push (table);
> > + table[0] = { attr, 0, 0, false, false, false, false, nullptr, nullptr };
> > + table[1] = { nullptr, 0, 0, false, false, false, false, nullptr,
> > + nullptr };
> > + register_scoped_attributes (table, vendor, !attr);
> > + }
> > +}
> > +
> > +/* Free data we might have allocated when adding extra attributes. */
> > +
> > +void
> > +free_attr_data ()
> > +{
> > + for (auto x : ignored_attributes_table)
> > + delete[] x;
> > + ignored_attributes_table.release ();
> > +}
> > +
> > /* Initialize attribute tables, and make some sanity checks if checking is
> > enabled. */
> >
> > @@ -252,6 +347,9 @@ init_attributes (void)
> > /* Put all the GNU attributes into the "gnu" namespace. */
> > register_scoped_attributes (attribute_tables[i], "gnu");
> >
> > + vec<char *> *ignored = (vec<char *> *) flag_ignored_attributes;
> > + handle_ignored_attributes_option (ignored);
> > +
> > invoke_plugin_callbacks (PLUGIN_ATTRIBUTES, NULL);
> > attributes_initialized = true;
> > }
> > @@ -456,6 +554,19 @@ diag_attr_exclusions (tree last_decl, tree node, tree attrname,
> > return found;
> > }
> >
> > +/* Return true iff we should not complain about unknown attributes
> > + coming from the attribute namespace NS. This is the case for
> > + the -Wno-attributes=ns:: command-line option. */
> > +
> > +static bool
> > +attr_namespace_ignored_p (tree ns)
> > +{
> > + if (ns == NULL_TREE)
> > + return false;
> > + scoped_attributes *r = find_attribute_namespace (IDENTIFIER_POINTER (ns));
> > + return r && r->ignored_p;
> > +}
> > +
> > /* Process the attributes listed in ATTRIBUTES and install them in *NODE,
> > which is either a DECL (including a TYPE_DECL) or a TYPE. If a DECL,
> > it should be modified in place; if a TYPE, a copy should be created
> > @@ -556,7 +667,8 @@ decl_attributes (tree *node, tree attributes, int flags,
> >
> > if (spec == NULL)
> > {
> > - if (!(flags & (int) ATTR_FLAG_BUILT_IN))
> > + if (!(flags & (int) ATTR_FLAG_BUILT_IN)
> > + && !attr_namespace_ignored_p (ns))
> > {
> > if (ns == NULL_TREE || !cxx11_attr_p)
> > warning (OPT_Wattributes, "%qE attribute directive ignored",
> > diff --git a/gcc/attribs.h b/gcc/attribs.h
> > index 138c509bce1..96a527f67a9 100644
> > --- a/gcc/attribs.h
> > +++ b/gcc/attribs.h
> > @@ -21,6 +21,7 @@ along with GCC; see the file COPYING3. If not see
> > #define GCC_ATTRIBS_H
> >
> > extern const struct attribute_spec *lookup_attribute_spec (const_tree);
> > +extern void free_attr_data ();
> > extern void init_attributes (void);
> >
> > /* Process the attributes listed in ATTRIBUTES and install them in *NODE,
> > @@ -40,12 +41,14 @@ extern void apply_tm_attr (tree, tree);
> > extern tree make_attribute (const char *, const char *, tree);
> >
> > extern struct scoped_attributes* register_scoped_attributes (const struct attribute_spec *,
> > - const char *);
> > + const char *,
> > + bool = false);
> >
> > extern char *sorted_attr_string (tree);
> > extern bool common_function_versions (tree, tree);
> > extern tree make_dispatcher_decl (const tree);
> > extern bool is_function_default_version (const tree);
> > +extern void handle_ignored_attributes_option (vec<char *> *);
> >
> > /* Return a type like TTYPE except that its TYPE_ATTRIBUTES
> > is ATTRIBUTE.
> > diff --git a/gcc/c-family/c-pragma.c b/gcc/c-family/c-pragma.c
> > index a9be8df0384..6beba5503f0 100644
> > --- a/gcc/c-family/c-pragma.c
> > +++ b/gcc/c-family/c-pragma.c
> > @@ -764,7 +764,7 @@ handle_pragma_diagnostic(cpp_reader *ARG_UNUSED(dummy))
> > if (token != CPP_NAME)
> > {
> > warning_at (loc, OPT_Wpragmas,
> > - "missing [error|warning|ignored|push|pop]"
> > + "missing [error|warning|ignored|push|pop|ignored_attributes]"
> > " after %<#pragma GCC diagnostic%>");
> > return;
> > }
> > @@ -787,10 +787,43 @@ handle_pragma_diagnostic(cpp_reader *ARG_UNUSED(dummy))
> > diagnostic_pop_diagnostics (global_dc, input_location);
> > return;
> > }
> > + else if (strcmp (kind_string, "ignored_attributes") == 0)
> > + {
> > + token = pragma_lex (&x, &loc);
> > + if (token != CPP_STRING)
> > + {
> > + warning_at (loc, OPT_Wpragmas,
> > + "missing attribute name after %<#pragma GCC diagnostic "
> > + "ignored_attributes%>");
> > + return;
> > + }
> > + char *args = xstrdup (TREE_STRING_POINTER (x));
> > + const size_t l = strlen (args);
> > + if (l == 0)
> > + {
> > + warning_at (loc, OPT_Wpragmas, "missing argument to %<#pragma GCC "
> > + "diagnostic ignored_attributes%>");
> > + free (args);
> > + return;
> > + }
> > + else if (args[l - 1] == ',')
> > + {
> > + warning_at (loc, OPT_Wpragmas, "trailing %<,%> in arguments for "
> > + "%<#pragma GCC diagnostic ignored_attributes%>");
> > + free (args);
> > + return;
> > + }
> > + auto_vec<char *> v;
> > + for (char *p = strtok (args, ","); p; p = strtok (NULL, ","))
> > + v.safe_push (p);
> > + handle_ignored_attributes_option (&v);
> > + /* ??? We can't free (args); here. */
> > + return;
> > + }
> > else
> > {
> > warning_at (loc, OPT_Wpragmas,
> > - "expected [error|warning|ignored|push|pop]"
> > + "expected [error|warning|ignored|push|pop|ignored_attributes]"
> > " after %<#pragma GCC diagnostic%>");
> > return;
> > }
> > diff --git a/gcc/common.opt b/gcc/common.opt
> > index a9644cae4f0..c429e43c6c1 100644
> > --- a/gcc/common.opt
> > +++ b/gcc/common.opt
> > @@ -83,7 +83,7 @@ int flag_gen_aux_info = 0
> > Variable
> > int flag_shlib
> >
> > -; These two are really VEC(char_p,heap) *.
> > +; These three are really VEC(char_p,heap) *.
> >
> > Variable
> > void *flag_instrument_functions_exclude_functions
> > @@ -91,6 +91,9 @@ void *flag_instrument_functions_exclude_functions
> > Variable
> > void *flag_instrument_functions_exclude_files
> >
> > +Variable
> > +void *flag_ignored_attributes
> > +
> > ; Generic structs (e.g. templates not explicitly specialized)
> > ; may not have a compilation unit associated with them, and so
> > ; may need to be treated differently from ordinary structs.
> > @@ -549,6 +552,10 @@ Wattributes
> > Common Var(warn_attributes) Init(1) Warning
> > Warn about inappropriate attribute usage.
> >
> > +Wattributes=
> > +Common Joined
> > +Do not warn about specified attributes.
> > +
> > Wattribute-alias
> > Common Alias(Wattribute_alias=, 1, 0) Warning
> > Warn about type safety and similar errors and mismatches in declarations with alias attributes.
> > diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
> > index b4c5376223a..28fd0cc6dd5 100644
> > --- a/gcc/doc/extend.texi
> > +++ b/gcc/doc/extend.texi
> > @@ -23761,6 +23761,25 @@ restored.
> > foo(d); /* depends on command-line options */
> > @end smallexample
> >
> > +@item #pragma GCC diagnostic ignored_attributes
> > +
> > +Similarly to @option{-Wno-attributes=}, this pragma allows users to suppress
> > +warnings about unknown scoped attributes (in C++11 and C2X). For example,
> > +@code{#pragma GCC diagnostic ignored_attributes "vendor::attr"} disables
> > +warning about the following declaration:
> > +
> > +@smallexample
> > +[[vendor::attr]] void f();
> > +@end smallexample
> > +
> > +whereas @code{#pragma GCC diagnostic ignored_attributes "vendor::"} prevents
> > +warning about both of these declarations:
> > +
> > +@smallexample
> > +[[vendor::safe]] void f();
> > +[[vendor::unsafe]] void f2();
> > +@end smallexample
> > +
> > @end table
> >
> > GCC also offers a simple mechanism for printing messages during
> > diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
> > index 5b016166972..fe2cb768c61 100644
> > --- a/gcc/doc/invoke.texi
> > +++ b/gcc/doc/invoke.texi
> > @@ -8623,6 +8623,26 @@ unrecognized attributes, function attributes applied to variables,
> > etc. This does not stop errors for incorrect use of supported
> > attributes.
> >
> > +Additionally, using @option{-Wno-attributes=}, it is possible to suppress
> > +warnings about unknown scoped attributes (in C++11 and C2X). For example,
> > +@option{-Wno-attributes=vendor::attr} disables warning about the following
> > +declaration:
> > +
> > +@smallexample
> > +[[vendor::attr]] void f();
> > +@end smallexample
> > +
> > +It is also possible to disable warning about all attributes in a namespace
> > +using @option{-Wno-attributes=vendor::} which prevents warning about both
> > +of these declarations:
> > +
> > +@smallexample
> > +[[vendor::safe]] void f();
> > +[[vendor::unsafe]] void f2();
> > +@end smallexample
> > +
> > +Note that @option{-Wno-attributes=} does not imply @option{-Wno-attributes}.
> > +
> > @item -Wno-builtin-declaration-mismatch
> > @opindex Wno-builtin-declaration-mismatch
> > @opindex Wbuiltin-declaration-mismatch
> > diff --git a/gcc/opts.c b/gcc/opts.c
> > index 6503980cd33..e3b66ad0d43 100644
> > --- a/gcc/opts.c
> > +++ b/gcc/opts.c
> > @@ -2558,6 +2558,26 @@ common_handle_option (struct gcc_options *opts,
> > /* Currently handled in a prescan. */
> > break;
> >
> > + case OPT_Wattributes_:
> > + if (lang_mask == CL_DRIVER)
> > + break;
> > +
> > + if (value)
> > + {
> > + error_at (loc, "arguments ignored for %<-Wattributes=%>; use "
> > + "%<-Wno-attributes=%> instead");
> > + break;
> > + }
> > + else if (arg[strlen (arg) - 1] == ',')
> > + {
> > + error_at (loc, "trailing %<,%> in arguments for "
> > + "%<-Wno-attributes=%>");
> > + break;
> > + }
> > +
> > + add_comma_separated_to_vector (&opts->x_flag_ignored_attributes, arg);
> > + break;
> > +
> > case OPT_Werror:
> > dc->warning_as_error_requested = value;
> > break;
> > diff --git a/gcc/plugin.h b/gcc/plugin.h
> > index 1640e253ca5..5556763d1bf 100644
> > --- a/gcc/plugin.h
> > +++ b/gcc/plugin.h
> > @@ -197,7 +197,9 @@ invoke_plugin_callbacks (int event ATTRIBUTE_UNUSED,
> > /* In attribs.c. */
> >
> > extern void register_attribute (const struct attribute_spec *attr);
> > +/* The default argument for the third parameter is given in attribs.h. */
> > extern struct scoped_attributes* register_scoped_attributes (const struct attribute_spec *,
> > - const char *);
> > + const char *,
> > + bool);
> >
> > #endif /* PLUGIN_H */
> > diff --git a/gcc/testsuite/c-c++-common/Wno-attributes-1.c b/gcc/testsuite/c-c++-common/Wno-attributes-1.c
> > new file mode 100644
> > index 00000000000..aac1a69fd85
> > --- /dev/null
> > +++ b/gcc/testsuite/c-c++-common/Wno-attributes-1.c
> > @@ -0,0 +1,55 @@
> > +/* PR c++/101940 */
> > +/* { dg-do compile } */
> > +/* { dg-additional-options "-std=c++11" { target c++ } } */
> > +/* { dg-additional-options "-Wno-attributes=company::,yoyodyne::attr" } */
> > +/* { dg-additional-options "-Wno-attributes=c1::attr,c1::attr,c1::__attr__" } */
> > +/* { dg-additional-options "-Wno-attributes=c2::,c2::attr" } */
> > +/* { dg-additional-options "-Wno-attributes=c3::attr,c3::" } */
> > +/* { dg-additional-options "-Wno-attributes=x::" } */
> > +/* { dg-additional-options "-Wno-attributes=yoyodyne::attr_new" } */
> > +/* { dg-additional-options "-Wno-attributes=c4::__attr__" } */
> > +/* { dg-additional-options "-Wno-attributes=c5::attr" } */
> > +/* { dg-additional-options "-Wno-attributes=__c6__::attr" } */
> > +
> > +[[company::attr]] void f1();
> > +[[company::attr2]] void f2();
> > +
> > +[[yoyodyne::attr]] void f3();
> > +[[yoyodyne::__attr__]] void f3__();
> > +[[yoyodyne::attrx]] void f4(); /* { dg-warning "ignored" } */
> > +[[yoyodyne::__attrx__]] void f4__(); /* { dg-warning "ignored" } */
> > +
> > +[[c1::attr]] void f5();
> > +
> > +[[c2::attr]] void f6();
> > +[[c2::attrx]] void f7();
> > +[[c2::__attr__]] void f6__();
> > +[[c2::__attrx__]] void f7__();
> > +
> > +[[c3::attr]] void f8();
> > +[[c3::attrx]] void f9();
> > +
> > +[[x::x]] void f10();
> > +
> > +[[yoyodyne::attr_new]] void f11();
> > +[[yoyodyne::__attr_new__]] void f11__();
> > +[[yoyodyne::attr_mew]] void f12(); /* { dg-warning "ignored" } */
> > +[[yoyodyne::__attr_mew__]] void f12__(); /* { dg-warning "ignored" } */
> > +
> > +[[c4::attr]] void f13();
> > +[[c4::__attr__]] void f13__();
> > +[[c4::attrx]] void f14(); /* { dg-warning "ignored" } */
> > +
> > +[[c5::attr]] void f15();
> > +[[c5::__attr__]] void f15__();
> > +[[__c5__::attr]] void __f15();
> > +[[__c5__::__attr__]] void __f15__();
> > +[[c5::attrx]] void f15x(); /* { dg-warning "ignored" } */
> > +[[__c5__::attrx]] void f15x(); /* { dg-warning "ignored" } */
> > +
> > +[[c6::attr]] void f16();
> > +[[c6::__attr__]] void f16__();
> > +[[__c6__::attr]] void __f16();
> > +[[__c6__::__attr__]] void __f16__();
> > +[[c6::attrx]] void f16x(); /* { dg-warning "ignored" } */
> > +[[__c6__::attrx]] void f16x(); /* { dg-warning "ignored" } */
> > diff --git a/gcc/testsuite/c-c++-common/Wno-attributes-2.c b/gcc/testsuite/c-c++-common/Wno-attributes-2.c
> > new file mode 100644
> > index 00000000000..4307c74b048
> > --- /dev/null
> > +++ b/gcc/testsuite/c-c++-common/Wno-attributes-2.c
> > @@ -0,0 +1,56 @@
> > +/* PR c++/101940 */
> > +/* { dg-do compile } */
> > +/* { dg-additional-options "-std=c++11" { target c++ } } */
> > +
> > +#pragma GCC diagnostic ignored_attributes "company::,yoyodyne::attr"
> > +#pragma GCC diagnostic ignored_attributes "c1::attr,c1::attr,c1::__attr__"
> > +#pragma GCC diagnostic ignored_attributes "c2::,c2::attr"
> > +#pragma GCC diagnostic ignored_attributes "c3::attr,c3::"
> > +#pragma GCC diagnostic ignored_attributes "x::"
> > +#pragma GCC diagnostic ignored_attributes "yoyodyne::attr_new"
> > +#pragma GCC diagnostic ignored_attributes "c4::__attr__"
> > +#pragma GCC diagnostic ignored_attributes "c5::attr"
> > +#pragma GCC diagnostic ignored_attributes "__c6__::attr"
> > +
> > +[[company::attr]] void f1();
> > +[[company::attr2]] void f2();
> > +
> > +[[yoyodyne::attr]] void f3();
> > +[[yoyodyne::__attr__]] void f3__();
> > +[[yoyodyne::attrx]] void f4(); /* { dg-warning "ignored" } */
> > +[[yoyodyne::__attrx__]] void f4__(); /* { dg-warning "ignored" } */
> > +
> > +[[c1::attr]] void f5();
> > +
> > +[[c2::attr]] void f6();
> > +[[c2::attrx]] void f7();
> > +[[c2::__attr__]] void f6__();
> > +[[c2::__attrx__]] void f7__();
> > +
> > +[[c3::attr]] void f8();
> > +[[c3::attrx]] void f9();
> > +
> > +[[x::x]] void f10();
> > +
> > +[[yoyodyne::attr_new]] void f11();
> > +[[yoyodyne::__attr_new__]] void f11__();
> > +[[yoyodyne::attr_mew]] void f12(); /* { dg-warning "ignored" } */
> > +[[yoyodyne::__attr_mew__]] void f12__(); /* { dg-warning "ignored" } */
> > +
> > +[[c4::attr]] void f13();
> > +[[c4::__attr__]] void f13__();
> > +[[c4::attrx]] void f14(); /* { dg-warning "ignored" } */
> > +
> > +[[c5::attr]] void f15();
> > +[[c5::__attr__]] void f15__();
> > +[[__c5__::attr]] void __f15();
> > +[[__c5__::__attr__]] void __f15__();
> > +[[c5::attrx]] void f15x(); /* { dg-warning "ignored" } */
> > +[[__c5__::attrx]] void f15x(); /* { dg-warning "ignored" } */
> > +
> > +[[c6::attr]] void f16();
> > +[[c6::__attr__]] void f16__();
> > +[[__c6__::attr]] void __f16();
> > +[[__c6__::__attr__]] void __f16__();
> > +[[c6::attrx]] void f16x(); /* { dg-warning "ignored" } */
> > +[[__c6__::attrx]] void f16x(); /* { dg-warning "ignored" } */
> > diff --git a/gcc/toplev.c b/gcc/toplev.c
> > index e1688aae724..f5ccaf8f799 100644
> > --- a/gcc/toplev.c
> > +++ b/gcc/toplev.c
> > @@ -463,6 +463,8 @@ compile_file (void)
> > if (flag_dump_locations)
> > dump_location_info (stderr);
> >
> > + free_attr_data ();
> > +
> > /* Compilation is now finished except for writing
> > what's left of the symbol table output. */
> >
> >
> > base-commit: a11052d98db2f2a61841f0c5ee84de4ca1b3e296
> > --
> > 2.31.1
> >
>
> Marek
Marek
On 9/28/21 16:20, Marek Polacek wrote:
> On Thu, Sep 23, 2021 at 02:25:16PM -0400, Jason Merrill wrote:
>> On 9/20/21 18:59, Marek Polacek via Gcc-patches wrote:
>>> + handle_ignored_attributes_option (&v);
>>> + /* ??? We can't free (args); here. */
>>
>> Perhaps we want to copy strings in handle_ignored_attributes_option rather
>> than here?
>
> Well, the other use doesn't need copying, so I left it be.
But the other use is modifying the strings passed on the command line,
which also seems questionable. I think it would be better for
handle_ignored_attributes_option to copy the relevant pieces out.
The patch looks good outside of this issue.
Jason
@@ -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,92 @@ 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 ARGS 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 *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::%>");
+ continue;
+ }
+ /* Cut off the vendor part. */
+ *q = '\0';
+ char *vendor = opt;
+ char *attr = q + 2;
+ /* Verify that they look valid. */
+ auto valid_p = [](const char *s) {
+ for (; *s != '\0'; ++s)
+ if (!ISALNUM (*s) && *s != '_')
+ return false;
+ return true;
+ };
+ if (!valid_p (vendor) || !valid_p (attr))
+ {
+ 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) {
+ const size_t l = strlen (s);
+ if (l > 4 && s[0] == '_' && s[1] == '_'
+ && s[l - 1] == '_' && s[l - 2] == '_')
+ {
+ s[l - 2] = '\0';
+ s += 2;
+ }
+ };
+ strip (attr);
+ strip (vendor);
+ /* 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 (get_identifier (vendor),
+ get_identifier (attr)))
+ continue;
+ /* In the "vendor::" case, we should ignore *any* attribute coming
+ from this attribute namespace. */
+ if (attr[0] == '\0')
+ attr = nullptr;
+ /* Create a table with extra attributes which we will register.
+ We can't free it here, so squirrel away the pointers. */
+ attribute_spec *table = new attribute_spec[2];
+ ignored_attributes_table.safe_push (table);
+ table[0] = { attr, 0, 0, false, false, false, false, nullptr, nullptr };
+ table[1] = { nullptr, 0, 0, false, false, false, false, nullptr,
+ nullptr };
+ register_scoped_attributes (table, vendor, !attr);
+ }
+}
+
+/* Free data we might have allocated when adding extra attributes. */
+
+void
+free_attr_data ()
+{
+ for (auto x : ignored_attributes_table)
+ delete[] x;
+ ignored_attributes_table.release ();
+}
+
/* Initialize attribute tables, and make some sanity checks if checking is
enabled. */
@@ -252,6 +347,9 @@ init_attributes (void)
/* Put all the GNU attributes into the "gnu" namespace. */
register_scoped_attributes (attribute_tables[i], "gnu");
+ vec<char *> *ignored = (vec<char *> *) flag_ignored_attributes;
+ handle_ignored_attributes_option (ignored);
+
invoke_plugin_callbacks (PLUGIN_ATTRIBUTES, NULL);
attributes_initialized = true;
}
@@ -456,6 +554,19 @@ diag_attr_exclusions (tree last_decl, tree node, tree attrname,
return found;
}
+/* Return true iff we should not complain about unknown attributes
+ coming from the attribute namespace NS. This is the case for
+ the -Wno-attributes=ns:: command-line option. */
+
+static bool
+attr_namespace_ignored_p (tree ns)
+{
+ if (ns == NULL_TREE)
+ return false;
+ scoped_attributes *r = find_attribute_namespace (IDENTIFIER_POINTER (ns));
+ return r && r->ignored_p;
+}
+
/* Process the attributes listed in ATTRIBUTES and install them in *NODE,
which is either a DECL (including a TYPE_DECL) or a TYPE. If a DECL,
it should be modified in place; if a TYPE, a copy should be created
@@ -556,7 +667,8 @@ decl_attributes (tree *node, tree attributes, int flags,
if (spec == NULL)
{
- if (!(flags & (int) ATTR_FLAG_BUILT_IN))
+ if (!(flags & (int) ATTR_FLAG_BUILT_IN)
+ && !attr_namespace_ignored_p (ns))
{
if (ns == NULL_TREE || !cxx11_attr_p)
warning (OPT_Wattributes, "%qE attribute directive ignored",
@@ -21,6 +21,7 @@ along with GCC; see the file COPYING3. If not see
#define GCC_ATTRIBS_H
extern const struct attribute_spec *lookup_attribute_spec (const_tree);
+extern void free_attr_data ();
extern void init_attributes (void);
/* Process the attributes listed in ATTRIBUTES and install them in *NODE,
@@ -40,12 +41,14 @@ extern void apply_tm_attr (tree, tree);
extern tree make_attribute (const char *, const char *, tree);
extern struct scoped_attributes* register_scoped_attributes (const struct attribute_spec *,
- const char *);
+ const char *,
+ bool = false);
extern char *sorted_attr_string (tree);
extern bool common_function_versions (tree, tree);
extern tree make_dispatcher_decl (const tree);
extern bool is_function_default_version (const tree);
+extern void handle_ignored_attributes_option (vec<char *> *);
/* Return a type like TTYPE except that its TYPE_ATTRIBUTES
is ATTRIBUTE.
@@ -764,7 +764,7 @@ handle_pragma_diagnostic(cpp_reader *ARG_UNUSED(dummy))
if (token != CPP_NAME)
{
warning_at (loc, OPT_Wpragmas,
- "missing [error|warning|ignored|push|pop]"
+ "missing [error|warning|ignored|push|pop|ignored_attributes]"
" after %<#pragma GCC diagnostic%>");
return;
}
@@ -787,10 +787,43 @@ handle_pragma_diagnostic(cpp_reader *ARG_UNUSED(dummy))
diagnostic_pop_diagnostics (global_dc, input_location);
return;
}
+ else if (strcmp (kind_string, "ignored_attributes") == 0)
+ {
+ token = pragma_lex (&x, &loc);
+ if (token != CPP_STRING)
+ {
+ warning_at (loc, OPT_Wpragmas,
+ "missing attribute name after %<#pragma GCC diagnostic "
+ "ignored_attributes%>");
+ return;
+ }
+ char *args = xstrdup (TREE_STRING_POINTER (x));
+ const size_t l = strlen (args);
+ if (l == 0)
+ {
+ warning_at (loc, OPT_Wpragmas, "missing argument to %<#pragma GCC "
+ "diagnostic ignored_attributes%>");
+ free (args);
+ return;
+ }
+ else if (args[l - 1] == ',')
+ {
+ warning_at (loc, OPT_Wpragmas, "trailing %<,%> in arguments for "
+ "%<#pragma GCC diagnostic ignored_attributes%>");
+ free (args);
+ return;
+ }
+ auto_vec<char *> v;
+ for (char *p = strtok (args, ","); p; p = strtok (NULL, ","))
+ v.safe_push (p);
+ handle_ignored_attributes_option (&v);
+ /* ??? We can't free (args); here. */
+ return;
+ }
else
{
warning_at (loc, OPT_Wpragmas,
- "expected [error|warning|ignored|push|pop]"
+ "expected [error|warning|ignored|push|pop|ignored_attributes]"
" after %<#pragma GCC diagnostic%>");
return;
}
@@ -83,7 +83,7 @@ int flag_gen_aux_info = 0
Variable
int flag_shlib
-; These two are really VEC(char_p,heap) *.
+; These three are really VEC(char_p,heap) *.
Variable
void *flag_instrument_functions_exclude_functions
@@ -91,6 +91,9 @@ void *flag_instrument_functions_exclude_functions
Variable
void *flag_instrument_functions_exclude_files
+Variable
+void *flag_ignored_attributes
+
; Generic structs (e.g. templates not explicitly specialized)
; may not have a compilation unit associated with them, and so
; may need to be treated differently from ordinary structs.
@@ -549,6 +552,10 @@ Wattributes
Common Var(warn_attributes) Init(1) Warning
Warn about inappropriate attribute usage.
+Wattributes=
+Common Joined
+Do not warn about specified attributes.
+
Wattribute-alias
Common Alias(Wattribute_alias=, 1, 0) Warning
Warn about type safety and similar errors and mismatches in declarations with alias attributes.
@@ -23761,6 +23761,25 @@ restored.
foo(d); /* depends on command-line options */
@end smallexample
+@item #pragma GCC diagnostic ignored_attributes
+
+Similarly to @option{-Wno-attributes=}, this pragma allows users to suppress
+warnings about unknown scoped attributes (in C++11 and C2X). For example,
+@code{#pragma GCC diagnostic ignored_attributes "vendor::attr"} disables
+warning about the following declaration:
+
+@smallexample
+[[vendor::attr]] void f();
+@end smallexample
+
+whereas @code{#pragma GCC diagnostic ignored_attributes "vendor::"} prevents
+warning about both of these declarations:
+
+@smallexample
+[[vendor::safe]] void f();
+[[vendor::unsafe]] void f2();
+@end smallexample
+
@end table
GCC also offers a simple mechanism for printing messages during
@@ -8623,6 +8623,26 @@ unrecognized attributes, function attributes applied to variables,
etc. This does not stop errors for incorrect use of supported
attributes.
+Additionally, using @option{-Wno-attributes=}, it is possible to suppress
+warnings about unknown scoped attributes (in C++11 and C2X). For example,
+@option{-Wno-attributes=vendor::attr} disables warning about the following
+declaration:
+
+@smallexample
+[[vendor::attr]] void f();
+@end smallexample
+
+It is also possible to disable warning about all attributes in a namespace
+using @option{-Wno-attributes=vendor::} which prevents warning about both
+of these declarations:
+
+@smallexample
+[[vendor::safe]] void f();
+[[vendor::unsafe]] void f2();
+@end smallexample
+
+Note that @option{-Wno-attributes=} does not imply @option{-Wno-attributes}.
+
@item -Wno-builtin-declaration-mismatch
@opindex Wno-builtin-declaration-mismatch
@opindex Wbuiltin-declaration-mismatch
@@ -2558,6 +2558,26 @@ common_handle_option (struct gcc_options *opts,
/* Currently handled in a prescan. */
break;
+ case OPT_Wattributes_:
+ if (lang_mask == CL_DRIVER)
+ break;
+
+ if (value)
+ {
+ error_at (loc, "arguments ignored for %<-Wattributes=%>; use "
+ "%<-Wno-attributes=%> instead");
+ break;
+ }
+ else if (arg[strlen (arg) - 1] == ',')
+ {
+ error_at (loc, "trailing %<,%> in arguments for "
+ "%<-Wno-attributes=%>");
+ break;
+ }
+
+ add_comma_separated_to_vector (&opts->x_flag_ignored_attributes, arg);
+ break;
+
case OPT_Werror:
dc->warning_as_error_requested = value;
break;
@@ -197,7 +197,9 @@ invoke_plugin_callbacks (int event ATTRIBUTE_UNUSED,
/* In attribs.c. */
extern void register_attribute (const struct attribute_spec *attr);
+/* The default argument for the third parameter is given in attribs.h. */
extern struct scoped_attributes* register_scoped_attributes (const struct attribute_spec *,
- const char *);
+ const char *,
+ bool);
#endif /* PLUGIN_H */
new file mode 100644
@@ -0,0 +1,55 @@
+/* PR c++/101940 */
+/* { dg-do compile } */
+/* { dg-additional-options "-std=c++11" { target c++ } } */
+/* { dg-additional-options "-Wno-attributes=company::,yoyodyne::attr" } */
+/* { dg-additional-options "-Wno-attributes=c1::attr,c1::attr,c1::__attr__" } */
+/* { dg-additional-options "-Wno-attributes=c2::,c2::attr" } */
+/* { dg-additional-options "-Wno-attributes=c3::attr,c3::" } */
+/* { dg-additional-options "-Wno-attributes=x::" } */
+/* { dg-additional-options "-Wno-attributes=yoyodyne::attr_new" } */
+/* { dg-additional-options "-Wno-attributes=c4::__attr__" } */
+/* { dg-additional-options "-Wno-attributes=c5::attr" } */
+/* { dg-additional-options "-Wno-attributes=__c6__::attr" } */
+
+[[company::attr]] void f1();
+[[company::attr2]] void f2();
+
+[[yoyodyne::attr]] void f3();
+[[yoyodyne::__attr__]] void f3__();
+[[yoyodyne::attrx]] void f4(); /* { dg-warning "ignored" } */
+[[yoyodyne::__attrx__]] void f4__(); /* { dg-warning "ignored" } */
+
+[[c1::attr]] void f5();
+
+[[c2::attr]] void f6();
+[[c2::attrx]] void f7();
+[[c2::__attr__]] void f6__();
+[[c2::__attrx__]] void f7__();
+
+[[c3::attr]] void f8();
+[[c3::attrx]] void f9();
+
+[[x::x]] void f10();
+
+[[yoyodyne::attr_new]] void f11();
+[[yoyodyne::__attr_new__]] void f11__();
+[[yoyodyne::attr_mew]] void f12(); /* { dg-warning "ignored" } */
+[[yoyodyne::__attr_mew__]] void f12__(); /* { dg-warning "ignored" } */
+
+[[c4::attr]] void f13();
+[[c4::__attr__]] void f13__();
+[[c4::attrx]] void f14(); /* { dg-warning "ignored" } */
+
+[[c5::attr]] void f15();
+[[c5::__attr__]] void f15__();
+[[__c5__::attr]] void __f15();
+[[__c5__::__attr__]] void __f15__();
+[[c5::attrx]] void f15x(); /* { dg-warning "ignored" } */
+[[__c5__::attrx]] void f15x(); /* { dg-warning "ignored" } */
+
+[[c6::attr]] void f16();
+[[c6::__attr__]] void f16__();
+[[__c6__::attr]] void __f16();
+[[__c6__::__attr__]] void __f16__();
+[[c6::attrx]] void f16x(); /* { dg-warning "ignored" } */
+[[__c6__::attrx]] void f16x(); /* { dg-warning "ignored" } */
new file mode 100644
@@ -0,0 +1,56 @@
+/* PR c++/101940 */
+/* { dg-do compile } */
+/* { dg-additional-options "-std=c++11" { target c++ } } */
+
+#pragma GCC diagnostic ignored_attributes "company::,yoyodyne::attr"
+#pragma GCC diagnostic ignored_attributes "c1::attr,c1::attr,c1::__attr__"
+#pragma GCC diagnostic ignored_attributes "c2::,c2::attr"
+#pragma GCC diagnostic ignored_attributes "c3::attr,c3::"
+#pragma GCC diagnostic ignored_attributes "x::"
+#pragma GCC diagnostic ignored_attributes "yoyodyne::attr_new"
+#pragma GCC diagnostic ignored_attributes "c4::__attr__"
+#pragma GCC diagnostic ignored_attributes "c5::attr"
+#pragma GCC diagnostic ignored_attributes "__c6__::attr"
+
+[[company::attr]] void f1();
+[[company::attr2]] void f2();
+
+[[yoyodyne::attr]] void f3();
+[[yoyodyne::__attr__]] void f3__();
+[[yoyodyne::attrx]] void f4(); /* { dg-warning "ignored" } */
+[[yoyodyne::__attrx__]] void f4__(); /* { dg-warning "ignored" } */
+
+[[c1::attr]] void f5();
+
+[[c2::attr]] void f6();
+[[c2::attrx]] void f7();
+[[c2::__attr__]] void f6__();
+[[c2::__attrx__]] void f7__();
+
+[[c3::attr]] void f8();
+[[c3::attrx]] void f9();
+
+[[x::x]] void f10();
+
+[[yoyodyne::attr_new]] void f11();
+[[yoyodyne::__attr_new__]] void f11__();
+[[yoyodyne::attr_mew]] void f12(); /* { dg-warning "ignored" } */
+[[yoyodyne::__attr_mew__]] void f12__(); /* { dg-warning "ignored" } */
+
+[[c4::attr]] void f13();
+[[c4::__attr__]] void f13__();
+[[c4::attrx]] void f14(); /* { dg-warning "ignored" } */
+
+[[c5::attr]] void f15();
+[[c5::__attr__]] void f15__();
+[[__c5__::attr]] void __f15();
+[[__c5__::__attr__]] void __f15__();
+[[c5::attrx]] void f15x(); /* { dg-warning "ignored" } */
+[[__c5__::attrx]] void f15x(); /* { dg-warning "ignored" } */
+
+[[c6::attr]] void f16();
+[[c6::__attr__]] void f16__();
+[[__c6__::attr]] void __f16();
+[[__c6__::__attr__]] void __f16__();
+[[c6::attrx]] void f16x(); /* { dg-warning "ignored" } */
+[[__c6__::attrx]] void f16x(); /* { dg-warning "ignored" } */
@@ -463,6 +463,8 @@ compile_file (void)
if (flag_dump_locations)
dump_location_info (stderr);
+ free_attr_data ();
+
/* Compilation is now finished except for writing
what's left of the symbol table output. */