public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] attribs: Implement -Wno-attributes=vendor::attr [PR101940]
@ 2021-09-20 17:06 Marek Polacek
  2021-09-20 17:38 ` Jakub Jelinek
  0 siblings, 1 reply; 28+ messages in thread
From: Marek Polacek @ 2021-09-20 17:06 UTC (permalink / raw)
  To: GCC Patches

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::
clang

The last one is a special option to ignore clang-only attributes; in
this patch it is accepted but currently has no effect.

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.

Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?

	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                                 | 122 +++++++++++++++++-
 gcc/attribs.h                                 |   5 +-
 gcc/c-family/c-pragma.c                       |  22 +++-
 gcc/c/c-decl.c                                |   2 +
 gcc/common.opt                                |   9 +-
 gcc/cp/decl2.c                                |   2 +
 gcc/doc/extend.texi                           |  19 +++
 gcc/doc/invoke.texi                           |  18 +++
 gcc/opts.c                                    |  14 ++
 gcc/plugin.h                                  |   4 +-
 gcc/testsuite/c-c++-common/Wno-attributes-1.c |  40 ++++++
 gcc/testsuite/c-c++-common/Wno-attributes-2.c |  41 ++++++
 12 files changed, 289 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..c85f3aedc4d 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,94 @@ 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::
+   and as a special case:
+     clang
+   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)
+    {
+      if (strcmp (opt, "clang") == 0)
+	{
+	  // TODO
+	  continue;
+	}
+      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%>");
+	  continue;
+	}
+      /* Cut off the vendor part.  */
+      *q = '\0';
+      const 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.  */
+      const size_t l = strlen (attr);
+      if (l > 4 && attr[0] == '_' && attr[1] == '_'
+	  && attr[l - 1] == '_' && attr[l - 2] == '_')
+	{
+	  attr[l - 2] = '\0';
+	  attr += 2;
+	}
+      /* 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';
+      /* 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,
+		   false, false, nullptr, nullptr };
+      table[1] = { nullptr, 0, 0, false, false, false, false, nullptr, nullptr };
+      register_scoped_attributes (table, vendor, ignored_ns);
+    }
+}
+
+/* Free data we might have allocated when adding extra attributes.  */
+
+void
+free_attr_data ()
+{
+  for (auto x : ignored_attributes_table)
+    delete[] x;
+}
+
 /* Initialize attribute tables, and make some sanity checks if checking is
    enabled.  */
 
@@ -252,6 +349,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 +556,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 +669,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..3f7b8380d93 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,28 @@ 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));
+      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/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 ();
+
   if (!in_lto_p)
     free_attr_access_data ();
 
diff --git a/gcc/common.opt b/gcc/common.opt
index b921f5e3b25..0da1d714819 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -80,7 +80,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
@@ -88,6 +88,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.
@@ -546,6 +549,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/cp/decl2.c b/gcc/cp/decl2.c
index a79a70ba9c2..58388c51dab 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -5305,6 +5305,8 @@ c_parse_final_cleanups (void)
   cp_tree_c_finish_parsing ();
   clear_consteval_vfns (consteval_vtables);
 
+  free_attr_data ();
+
   /* The entire file is now complete.  If requested, dump everything
      to a file.  */
   dump_tu ();
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 9501a60f20e..48eaf16d209 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -23745,6 +23745,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 4acb94181d2..7c7241cdb88 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -8621,6 +8621,24 @@ 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
+
 @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 1d2d22d7a3f..45db0de3f2e 100644
--- a/gcc/opts.c
+++ b/gcc/opts.c
@@ -2546,6 +2546,20 @@ common_handle_option (struct gcc_options *opts,
       /* Currently handled in a prescan.  */
       break;
 
+    case OPT_Wattributes_:
+      if (lang_mask == CL_DRIVER)
+	break;
+
+      if (value)
+	{
+	  warning_at (loc, 0, "arguments ignored for %<-Wattributes=%>; use "
+		      "%<-Wno-attributes=%> instead");
+	  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..e28f1fbab17
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/Wno-attributes-1.c
@@ -0,0 +1,40 @@
+/* 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=clang" } */
+/* { 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__" } */
+
+[[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" } */
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..1b08e972aed
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/Wno-attributes-2.c
@@ -0,0 +1,41 @@
+/* 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 "clang"
+#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__"
+
+[[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" } */

base-commit: 1949d7540a0322993bcae2f8893e2dbd29209040
-- 
2.31.1


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH] attribs: Implement -Wno-attributes=vendor::attr [PR101940]
  2021-09-20 17:06 [PATCH] attribs: Implement -Wno-attributes=vendor::attr [PR101940] Marek Polacek
@ 2021-09-20 17:38 ` Jakub Jelinek
  2021-09-20 18:37   ` Marek Polacek
  0 siblings, 1 reply; 28+ messages in thread
From: Jakub Jelinek @ 2021-09-20 17:38 UTC (permalink / raw)
  To: Marek Polacek; +Cc: GCC Patches

On Mon, Sep 20, 2021 at 01:06:58PM -0400, Marek Polacek via Gcc-patches wrote:

Not a review, just a few nits:

I think it would be useful to clarify that -Wno-attributes=list doesn't
actually imply -Wno-attributes

> --- a/gcc/common.opt
> +++ b/gcc/common.opt
> @@ -88,6 +88,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.
> @@ -546,6 +549,10 @@ Wattributes
>  Common Var(warn_attributes) Init(1) Warning
>  Warn about inappropriate attribute usage.
>  
> +Wattributes=
> +Common Joined
> +Do not warn about specified attributes.
> +

So, wouldn't be this better specified as
Wno-attributes=
Common Joined RejectNegative
(not sure if RejectNegative is actually needed for an option
starting with Wno- )?

> +/* { 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=clang" } */
> +/* { dg-additional-options "-Wno-attributes=c2::,c2::attr" } */
> +/* { dg-additional-options "-Wno-attributes=c3::attr,c3::" } */
> +/* { dg-additional-options "-Wno-attributes=x::," } */

Should the above be accepted (I mean trailing , ?)  What does that mean?

> +/* { dg-additional-options "-Wno-attributes=yoyodyne::attr_new" } */
> +/* { dg-additional-options "-Wno-attributes=c4::__attr__" } */

When writing __attr__, does that imply we won't warn about both
c4::attr and c4::__attr__ (and __c4__::attr and __c4__::__attr__) like
it would when writing -Wno-attributes=c4::attr ?

	Jakub


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH] attribs: Implement -Wno-attributes=vendor::attr [PR101940]
  2021-09-20 17:38 ` Jakub Jelinek
@ 2021-09-20 18:37   ` Marek Polacek
  2021-09-20 19:03     ` [PATCH v2] " Marek Polacek
  2021-09-20 19:08     ` [PATCH] " Jakub Jelinek
  0 siblings, 2 replies; 28+ messages in thread
From: Marek Polacek @ 2021-09-20 18:37 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: GCC Patches

On Mon, Sep 20, 2021 at 07:38:59PM +0200, Jakub Jelinek wrote:
> On Mon, Sep 20, 2021 at 01:06:58PM -0400, Marek Polacek via Gcc-patches wrote:
> 
> Not a review, just a few nits:
> 
> I think it would be useful to clarify that -Wno-attributes=list doesn't
> actually imply -Wno-attributes

Agreed, fixed with:

+Note that @option{-Wno-attributes=} does not imply @option{-Wno-attributes}.
 
> > --- a/gcc/common.opt
> > +++ b/gcc/common.opt
> > @@ -88,6 +88,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.
> > @@ -546,6 +549,10 @@ Wattributes
> >  Common Var(warn_attributes) Init(1) Warning
> >  Warn about inappropriate attribute usage.
> >  
> > +Wattributes=
> > +Common Joined
> > +Do not warn about specified attributes.
> > +
> 
> So, wouldn't be this better specified as
> Wno-attributes=
> Common Joined RejectNegative
> (not sure if RejectNegative is actually needed for an option
> starting with Wno- )?

Looks like RejectNegative is not needed.  I could do that, but I think
it regresses the diagnostic:

error: unrecognized command-line option '-Wattributes=attr::'
vs
error: arguments ignored for ‘-Wattributes=’; use ‘-Wno-attributes=’ instead

I prefer the latter.  (I've changed the warning into error.)
 
> > +/* { 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=clang" } */
> > +/* { dg-additional-options "-Wno-attributes=c2::,c2::attr" } */
> > +/* { dg-additional-options "-Wno-attributes=c3::attr,c3::" } */
> > +/* { dg-additional-options "-Wno-attributes=x::," } */
> 
> Should the above be accepted (I mean trailing , ?)  What does that mean?
 
I'm thinking it should: the arguments to -Wno-attributes= could be
generated by a tool so accepting the trailing , might help, like in
enums etc.

> > +/* { dg-additional-options "-Wno-attributes=yoyodyne::attr_new" } */
> > +/* { dg-additional-options "-Wno-attributes=c4::__attr__" } */
> 
> When writing __attr__, does that imply we won't warn about both
> c4::attr and c4::__attr__ (and __c4__::attr and __c4__::__attr__) like
> it would when writing -Wno-attributes=c4::attr ?

"__attr__" and "attr" ought to be interchangeable.  __c4__:: and c4:: currently
are not, but I guess they should.  I'll post a v2 with that fixed.

Thanks!
--
Marek Polacek • Red Hat, Inc. • 300 A St, Boston, MA


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v2] attribs: Implement -Wno-attributes=vendor::attr [PR101940]
  2021-09-20 18:37   ` Marek Polacek
@ 2021-09-20 19:03     ` Marek Polacek
  2021-09-20 19:08     ` [PATCH] " Jakub Jelinek
  1 sibling, 0 replies; 28+ messages in thread
From: Marek Polacek @ 2021-09-20 19:03 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: GCC Patches

On Mon, Sep 20, 2021 at 02:37:03PM -0400, Marek Polacek wrote:
> > > +/* { dg-additional-options "-Wno-attributes=yoyodyne::attr_new" } */
> > > +/* { dg-additional-options "-Wno-attributes=c4::__attr__" } */
> > 
> > When writing __attr__, does that imply we won't warn about both
> > c4::attr and c4::__attr__ (and __c4__::attr and __c4__::__attr__) like
> > it would when writing -Wno-attributes=c4::attr ?
> 
> "__attr__" and "attr" ought to be interchangeable.  __c4__:: and c4:: currently
> are not, but I guess they should.  I'll post a v2 with that fixed.

Here's v2 with the documentation enhancement, warning -> error, and
which handles __vendor__:: the same as vendor::.

Regtest/bootstrap running.

-- >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::
clang

The last one is a special option to ignore clang-only attributes; in
this patch it is accepted but currently has no effect.

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                                 | 126 +++++++++++++++++-
 gcc/attribs.h                                 |   5 +-
 gcc/c-family/c-pragma.c                       |  22 ++-
 gcc/c/c-decl.c                                |   2 +
 gcc/common.opt                                |   9 +-
 gcc/cp/decl2.c                                |   2 +
 gcc/doc/extend.texi                           |  19 +++
 gcc/doc/invoke.texi                           |  20 +++
 gcc/opts.c                                    |  14 ++
 gcc/plugin.h                                  |   4 +-
 gcc/testsuite/c-c++-common/Wno-attributes-1.c |  56 ++++++++
 gcc/testsuite/c-c++-common/Wno-attributes-2.c |  57 ++++++++
 12 files changed, 327 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..869006e3526 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,98 @@ 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::
+   and as a special case:
+     clang
+   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)
+    {
+      if (strcmp (opt, "clang") == 0)
+	{
+	  // TODO
+	  continue;
+	}
+      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%>");
+	  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';
+      /* 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,
+		   false, false, nullptr, nullptr };
+      table[1] = { nullptr, 0, 0, false, false, false, false, nullptr, nullptr };
+      register_scoped_attributes (table, vendor, ignored_ns);
+    }
+}
+
+/* Free data we might have allocated when adding extra attributes.  */
+
+void
+free_attr_data ()
+{
+  for (auto x : ignored_attributes_table)
+    delete[] x;
+}
+
 /* 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..3f7b8380d93 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,28 @@ 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));
+      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/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 ();
+
   if (!in_lto_p)
     free_attr_access_data ();
 
diff --git a/gcc/common.opt b/gcc/common.opt
index b921f5e3b25..0da1d714819 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -80,7 +80,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
@@ -88,6 +88,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.
@@ -546,6 +549,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/cp/decl2.c b/gcc/cp/decl2.c
index a79a70ba9c2..58388c51dab 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -5305,6 +5305,8 @@ c_parse_final_cleanups (void)
   cp_tree_c_finish_parsing ();
   clear_consteval_vfns (consteval_vtables);
 
+  free_attr_data ();
+
   /* The entire file is now complete.  If requested, dump everything
      to a file.  */
   dump_tu ();
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 9501a60f20e..48eaf16d209 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -23745,6 +23745,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 4acb94181d2..2b0ec511984 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -8621,6 +8621,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 1d2d22d7a3f..2e5d42cea72 100644
--- a/gcc/opts.c
+++ b/gcc/opts.c
@@ -2546,6 +2546,20 @@ 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;
+	}
+
+      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..4ecee1bd9e4
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/Wno-attributes-1.c
@@ -0,0 +1,56 @@
+/* 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=clang" } */
+/* { 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..b635befcc37
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/Wno-attributes-2.c
@@ -0,0 +1,57 @@
+/* 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 "clang"
+#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" } */

base-commit: 1949d7540a0322993bcae2f8893e2dbd29209040
-- 
2.31.1


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH] attribs: Implement -Wno-attributes=vendor::attr [PR101940]
  2021-09-20 18:37   ` Marek Polacek
  2021-09-20 19:03     ` [PATCH v2] " Marek Polacek
@ 2021-09-20 19:08     ` Jakub Jelinek
  2021-09-20 22:59       ` [PATCH v3] " Marek Polacek
  1 sibling, 1 reply; 28+ messages in thread
From: Jakub Jelinek @ 2021-09-20 19:08 UTC (permalink / raw)
  To: Marek Polacek; +Cc: GCC Patches

On Mon, Sep 20, 2021 at 02:37:03PM -0400, Marek Polacek wrote:
> > So, wouldn't be this better specified as
> > Wno-attributes=
> > Common Joined RejectNegative
> > (not sure if RejectNegative is actually needed for an option
> > starting with Wno- )?
> 
> Looks like RejectNegative is not needed.  I could do that, but I think
> it regresses the diagnostic:
> 
> error: unrecognized command-line option '-Wattributes=attr::'
> vs
> error: arguments ignored for ‘-Wattributes=’; use ‘-Wno-attributes=’ instead
> 
> I prefer the latter.  (I've changed the warning into error.)

Ok.

> > > +/* { 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=clang" } */
> > > +/* { dg-additional-options "-Wno-attributes=c2::,c2::attr" } */
> > > +/* { dg-additional-options "-Wno-attributes=c3::attr,c3::" } */
> > > +/* { dg-additional-options "-Wno-attributes=x::," } */
> > 
> > Should the above be accepted (I mean trailing , ?)  What does that mean?
>  
> I'm thinking it should: the arguments to -Wno-attributes= could be
> generated by a tool so accepting the trailing , might help, like in
> enums etc.

I don't think we allow that for any other options that accept a list of
something (except maybe -W{p,c,a,l}, those just pass the args through).
Generating a list that has comma separation only in between items and not
at the end is trivial.

	Jakub


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v3] attribs: Implement -Wno-attributes=vendor::attr [PR101940]
  2021-09-20 19:08     ` [PATCH] " Jakub Jelinek
@ 2021-09-20 22:59       ` Marek Polacek
  2021-09-23 18:25         ` Jason Merrill
  0 siblings, 1 reply; 28+ messages in thread
From: Marek Polacek @ 2021-09-20 22:59 UTC (permalink / raw)
  To: Jakub Jelinek; +Cc: GCC Patches

On Mon, Sep 20, 2021 at 09:08:09PM +0200, Jakub Jelinek wrote:
> On Mon, Sep 20, 2021 at 02:37:03PM -0400, Marek Polacek wrote:
> > > So, wouldn't be this better specified as
> > > Wno-attributes=
> > > Common Joined RejectNegative
> > > (not sure if RejectNegative is actually needed for an option
> > > starting with Wno- )?
> > 
> > Looks like RejectNegative is not needed.  I could do that, but I think
> > it regresses the diagnostic:
> > 
> > error: unrecognized command-line option '-Wattributes=attr::'
> > vs
> > error: arguments ignored for ‘-Wattributes=’; use ‘-Wno-attributes=’ instead
> > 
> > I prefer the latter.  (I've changed the warning into error.)
> 
> Ok.
> 
> > > > +/* { 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=clang" } */
> > > > +/* { dg-additional-options "-Wno-attributes=c2::,c2::attr" } */
> > > > +/* { dg-additional-options "-Wno-attributes=c3::attr,c3::" } */
> > > > +/* { dg-additional-options "-Wno-attributes=x::," } */
> > > 
> > > Should the above be accepted (I mean trailing , ?)  What does that mean?
> >  
> > I'm thinking it should: the arguments to -Wno-attributes= could be
> > generated by a tool so accepting the trailing , might help, like in
> > enums etc.
> 
> I don't think we allow that for any other options that accept a list of
> something (except maybe -W{p,c,a,l}, those just pass the args through).
> Generating a list that has comma separation only in between items and not
> at the end is trivial.

Hmm, ok, here's a version with that checking added.  Sadly it needs
to be handled before handle_ignored_attributes_option because of
strtok.

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::
clang

The last one is a special option to ignore clang-only attributes; in
this patch it is accepted but currently has no effect.

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                                 | 126 +++++++++++++++++-
 gcc/attribs.h                                 |   5 +-
 gcc/c-family/c-pragma.c                       |  37 ++++-
 gcc/c/c-decl.c                                |   2 +
 gcc/common.opt                                |   9 +-
 gcc/cp/decl2.c                                |   2 +
 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 |  56 ++++++++
 gcc/testsuite/c-c++-common/Wno-attributes-2.c |  57 ++++++++
 12 files changed, 348 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..869006e3526 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,98 @@ 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::
+   and as a special case:
+     clang
+   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)
+    {
+      if (strcmp (opt, "clang") == 0)
+	{
+	  // TODO
+	  continue;
+	}
+      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%>");
+	  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';
+      /* 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,
+		   false, false, nullptr, nullptr };
+      table[1] = { nullptr, 0, 0, false, false, false, false, nullptr, nullptr };
+      register_scoped_attributes (table, vendor, ignored_ns);
+    }
+}
+
+/* Free data we might have allocated when adding extra attributes.  */
+
+void
+free_attr_data ()
+{
+  for (auto x : ignored_attributes_table)
+    delete[] x;
+}
+
 /* 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.  */
+      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 ();
+
   if (!in_lto_p)
     free_attr_access_data ();
 
diff --git a/gcc/common.opt b/gcc/common.opt
index b921f5e3b25..0da1d714819 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -80,7 +80,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
@@ -88,6 +88,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.
@@ -546,6 +549,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/cp/decl2.c b/gcc/cp/decl2.c
index a79a70ba9c2..58388c51dab 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -5305,6 +5305,8 @@ c_parse_final_cleanups (void)
   cp_tree_c_finish_parsing ();
   clear_consteval_vfns (consteval_vtables);
 
+  free_attr_data ();
+
   /* The entire file is now complete.  If requested, dump everything
      to a file.  */
   dump_tu ();
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 9501a60f20e..48eaf16d209 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -23745,6 +23745,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 4acb94181d2..2b0ec511984 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -8621,6 +8621,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 1d2d22d7a3f..ba664a515a2 100644
--- a/gcc/opts.c
+++ b/gcc/opts.c
@@ -2546,6 +2546,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..c174eef5fba
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/Wno-attributes-1.c
@@ -0,0 +1,56 @@
+/* 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=clang" } */
+/* { 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..8e9f55ea2da
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/Wno-attributes-2.c
@@ -0,0 +1,57 @@
+/* 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 "clang"
+#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" } */

base-commit: b333c3acb8d436b256ba8922c6426c93860bb616
-- 
2.31.1


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v3] attribs: Implement -Wno-attributes=vendor::attr [PR101940]
  2021-09-20 22:59       ` [PATCH v3] " Marek Polacek
@ 2021-09-23 18:25         ` Jason Merrill
  2021-09-28 20:20           ` [PATCH v4] " Marek Polacek
  0 siblings, 1 reply; 28+ messages in thread
From: Jason Merrill @ 2021-09-23 18:25 UTC (permalink / raw)
  To: Marek Polacek, Jakub Jelinek; +Cc: GCC Patches

On 9/20/21 18:59, Marek Polacek via Gcc-patches wrote:
> On Mon, Sep 20, 2021 at 09:08:09PM +0200, Jakub Jelinek wrote:
>> On Mon, Sep 20, 2021 at 02:37:03PM -0400, Marek Polacek wrote:
>>>> So, wouldn't be this better specified as
>>>> Wno-attributes=
>>>> Common Joined RejectNegative
>>>> (not sure if RejectNegative is actually needed for an option
>>>> starting with Wno- )?
>>>
>>> Looks like RejectNegative is not needed.  I could do that, but I think
>>> it regresses the diagnostic:
>>>
>>> error: unrecognized command-line option '-Wattributes=attr::'
>>> vs
>>> error: arguments ignored for ‘-Wattributes=’; use ‘-Wno-attributes=’ instead
>>>
>>> I prefer the latter.  (I've changed the warning into error.)
>>
>> Ok.
>>
>>>>> +/* { 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=clang" } */
>>>>> +/* { dg-additional-options "-Wno-attributes=c2::,c2::attr" } */
>>>>> +/* { dg-additional-options "-Wno-attributes=c3::attr,c3::" } */
>>>>> +/* { dg-additional-options "-Wno-attributes=x::," } */
>>>>
>>>> Should the above be accepted (I mean trailing , ?)  What does that mean?
>>>   
>>> I'm thinking it should: the arguments to -Wno-attributes= could be
>>> generated by a tool so accepting the trailing , might help, like in
>>> enums etc.
>>
>> I don't think we allow that for any other options that accept a list of
>> something (except maybe -W{p,c,a,l}, those just pass the args through).
>> Generating a list that has comma separation only in between items and not
>> at the end is trivial.
> 
> Hmm, ok, here's a version with that checking added.  Sadly it needs
> to be handled before handle_ignored_attributes_option because of
> strtok.
> 
> 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::
> clang
> 
> The last one is a special option to ignore clang-only attributes; in
> this patch it is accepted but currently has no effect.
> 
> 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                                 | 126 +++++++++++++++++-
>   gcc/attribs.h                                 |   5 +-
>   gcc/c-family/c-pragma.c                       |  37 ++++-
>   gcc/c/c-decl.c                                |   2 +
>   gcc/common.opt                                |   9 +-
>   gcc/cp/decl2.c                                |   2 +
>   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 |  56 ++++++++
>   gcc/testsuite/c-c++-common/Wno-attributes-2.c |  57 ++++++++
>   12 files changed, 348 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..869006e3526 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,98 @@ 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::
> +   and as a special case:
> +     clang
> +   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)
> +    {
> +      if (strcmp (opt, "clang") == 0)
> +	{
> +	  // TODO
> +	  continue;
> +	}

If this doesn't work yet, let's not accept it at all for now.

> +      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.

> +	  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.

> +		   false, false, nullptr, nullptr };
> +      table[1] = { nullptr, 0, 0, false, false, false, false, nullptr, nullptr };
> +      register_scoped_attributes (table, vendor, ignored_ns);
> +    }
> +}
> +
> +/* 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.

>   /* 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?

> +      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?

>     if (!in_lto_p)
>       free_attr_access_data ();
>   
> diff --git a/gcc/common.opt b/gcc/common.opt
> index b921f5e3b25..0da1d714819 100644
> --- a/gcc/common.opt
> +++ b/gcc/common.opt
> @@ -80,7 +80,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
> @@ -88,6 +88,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.
> @@ -546,6 +549,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/cp/decl2.c b/gcc/cp/decl2.c
> index a79a70ba9c2..58388c51dab 100644
> --- a/gcc/cp/decl2.c
> +++ b/gcc/cp/decl2.c
> @@ -5305,6 +5305,8 @@ c_parse_final_cleanups (void)
>     cp_tree_c_finish_parsing ();
>     clear_consteval_vfns (consteval_vtables);
>   
> +  free_attr_data ();
> +
>     /* The entire file is now complete.  If requested, dump everything
>        to a file.  */
>     dump_tu ();
> diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
> index 9501a60f20e..48eaf16d209 100644
> --- a/gcc/doc/extend.texi
> +++ b/gcc/doc/extend.texi
> @@ -23745,6 +23745,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 4acb94181d2..2b0ec511984 100644
> --- a/gcc/doc/invoke.texi
> +++ b/gcc/doc/invoke.texi
> @@ -8621,6 +8621,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 1d2d22d7a3f..ba664a515a2 100644
> --- a/gcc/opts.c
> +++ b/gcc/opts.c
> @@ -2546,6 +2546,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..c174eef5fba
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/Wno-attributes-1.c
> @@ -0,0 +1,56 @@
> +/* 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=clang" } */
> +/* { 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..8e9f55ea2da
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/Wno-attributes-2.c
> @@ -0,0 +1,57 @@
> +/* 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 "clang"
> +#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" } */
> 
> base-commit: b333c3acb8d436b256ba8922c6426c93860bb616
> 


^ permalink raw reply	[flat|nested] 28+ messages in thread

* [PATCH v4] attribs: Implement -Wno-attributes=vendor::attr [PR101940]
  2021-09-23 18:25         ` Jason Merrill
@ 2021-09-28 20:20           ` Marek Polacek
  2021-10-11 15:17             ` Marek Polacek
  2021-11-05 18:48             ` Jason Merrill
  0 siblings, 2 replies; 28+ messages in thread
From: Marek Polacek @ 2021-09-28 20:20 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Jakub Jelinek, GCC Patches

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


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v4] attribs: Implement -Wno-attributes=vendor::attr [PR101940]
  2021-09-28 20:20           ` [PATCH v4] " Marek Polacek
@ 2021-10-11 15:17             ` Marek Polacek
  2021-10-29 16:47               ` Marek Polacek
  2021-11-05 18:48             ` Jason Merrill
  1 sibling, 1 reply; 28+ messages in thread
From: Marek Polacek @ 2021-10-11 15:17 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Jakub Jelinek, GCC Patches

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


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v4] attribs: Implement -Wno-attributes=vendor::attr [PR101940]
  2021-10-11 15:17             ` Marek Polacek
@ 2021-10-29 16:47               ` Marek Polacek
  0 siblings, 0 replies; 28+ messages in thread
From: Marek Polacek @ 2021-10-29 16:47 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Jakub Jelinek, GCC Patches, Joseph Myers

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


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v4] attribs: Implement -Wno-attributes=vendor::attr [PR101940]
  2021-09-28 20:20           ` [PATCH v4] " Marek Polacek
  2021-10-11 15:17             ` Marek Polacek
@ 2021-11-05 18:48             ` Jason Merrill
  2021-11-06  0:21               ` [PATCH v5] " Marek Polacek
  1 sibling, 1 reply; 28+ messages in thread
From: Jason Merrill @ 2021-11-05 18:48 UTC (permalink / raw)
  To: Marek Polacek; +Cc: Jakub Jelinek, GCC Patches

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


^ permalink raw reply	[flat|nested] 28+ messages in thread

* [PATCH v5] attribs: Implement -Wno-attributes=vendor::attr [PR101940]
  2021-11-05 18:48             ` Jason Merrill
@ 2021-11-06  0:21               ` Marek Polacek
  2021-11-06  1:32                 ` Bernhard Reutner-Fischer
  0 siblings, 1 reply; 28+ messages in thread
From: Marek Polacek @ 2021-11-06  0:21 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Jakub Jelinek, GCC Patches

On Fri, Nov 05, 2021 at 02:48:31PM -0400, Jason Merrill wrote:
> 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.

Thanks, so like this?  I'm including an incremental diff so that it's
clear what changed:

diff --git a/gcc/attribs.c b/gcc/attribs.c
index d5fba7f4bbb..addfe6f6c80 100644
--- a/gcc/attribs.c
+++ b/gcc/attribs.c
@@ -237,7 +237,7 @@ check_attribute_tables (void)
    the end of parsing of all TUs. */
 static vec<attribute_spec *> ignored_attributes_table;
 
-/* Parse arguments ARGS of -Wno-attributes=.
+/* Parse arguments V of -Wno-attributes=.
    Currently we accept:
      vendor::attr
      vendor::
@@ -252,12 +252,15 @@ handle_ignored_attributes_option (vec<char *> *v)
 
   for (auto opt : v)
     {
+      /* We're going to be modifying the string.  */
+      opt = xstrdup (opt);
       char *q = strstr (opt, "::");
       /* We don't accept '::attr'.  */
       if (q == nullptr || q == opt)
 	{
 	  error ("wrong argument to ignored attributes");
 	  inform (input_location, "valid format is %<ns::attr%> or %<ns::%>");
+	  free (opt);
 	  continue;
 	}
       /* Cut off the vendor part.  */
@@ -274,6 +277,7 @@ handle_ignored_attributes_option (vec<char *> *v)
       if (!valid_p (vendor) || !valid_p (attr))
 	{
 	  error ("wrong argument to ignored attributes");
+	  free (opt);
 	  continue;
 	}
       /* Turn "__attr__" into "attr" so that we have a canonical form of
diff --git a/gcc/c-family/c-pragma.c b/gcc/c-family/c-pragma.c
index 6beba5503f0..a299ceff6a2 100644
--- a/gcc/c-family/c-pragma.c
+++ b/gcc/c-family/c-pragma.c
@@ -817,7 +817,7 @@ handle_pragma_diagnostic(cpp_reader *ARG_UNUSED(dummy))
       for (char *p = strtok (args, ","); p; p = strtok (NULL, ","))
 	v.safe_push (p);
       handle_ignored_attributes_option (&v);
-      /* ??? We can't free (args); here.  */
+      free (args);
       return;
     }
   else


and here's the complete patch:

Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?

-- >8 --
It is desirable for -Wattributes to warn about e.g.

[[deprecate]] void g(); // typo, should warn

However, -Wattributes also warns about vendor-specific attributes
(that's because lookup_scoped_attribute_spec -> find_attribute_namespace
finds nothing), which, with -Werror, causes grief.  We don't want the
-Wattributes warning for

[[company::attr]] void f();

GCC warns because it doesn't know the "company" namespace; it only knows
the "gnu" and "omp" namespaces.  We could entirely disable warning about
attributes in unknown scopes but then the compiler would also miss typos
like

  [[company::attrx]] void f();

or

  [[gmu::warn_used_result]] int write();

so that is not a viable solution.  A workaround is to use a #pragma:

  #pragma GCC diagnostic push
  #pragma GCC diagnostic ignored "-Wattributes"
  [[company::attr]] void f() {}
  #pragma GCC diagnostic pop

but that's a mouthful and awkward to use and could also hide typos.  In
fact, any macro-based solution doesn't seem like a way forward.

This patch implements -Wno-attributes=, which takes these arguments:

company::attr
company::

This option should go well with using @file: the user could have a file
containing
-Wno-attributes=vendor::attr1,vendor::attr2
and then invoke gcc with '@attrs' or similar.

I've also added a new pragma which has the same effect:

The pragma along with the new option should help with various static
analysis tools.

	PR c++/101940

gcc/ChangeLog:

	* attribs.c (struct scoped_attributes): Add a bool member.
	(lookup_scoped_attribute_spec): Forward declare.
	(register_scoped_attributes): New bool parameter, defaulted to
	false.  Use it.
	(handle_ignored_attributes_option): New function.
	(free_attr_data): New function.
	(init_attributes): Call handle_ignored_attributes_option.
	(attr_namespace_ignored_p): New function.
	(decl_attributes): Check attr_namespace_ignored_p before
	warning.
	* attribs.h (free_attr_data): Declare.
	(register_scoped_attributes): Adjust declaration.
	(handle_ignored_attributes_option): Declare.
	* common.opt (Wattributes=): New option with a variable.
	* doc/extend.texi: Document #pragma GCC diagnostic ignored_attributes.
	* doc/invoke.texi: Document -Wno-attributes=.
	* opts.c (common_handle_option) <case OPT_Wattributes_>: Handle.
	* plugin.h (register_scoped_attributes): Adjust declaration.
	* toplev.c (compile_file): Call free_attr_data.

gcc/c-family/ChangeLog:

	* c-pragma.c (handle_pragma_diagnostic): Handle #pragma GCC diagnostic
	ignored_attributes.

gcc/testsuite/ChangeLog:

	* c-c++-common/Wno-attributes-1.c: New test.
	* c-c++-common/Wno-attributes-2.c: New test.
---
 gcc/attribs.c                                 | 124 +++++++++++++++++-
 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, 342 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..addfe6f6c80 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,96 @@ check_attribute_tables (void)
 				 attribute_tables[j][l].name));
 }
 
+/* Used to stash pointers to allocated memory so that we can free them at
+   the end of parsing of all TUs. */
+static vec<attribute_spec *> ignored_attributes_table;
+
+/* Parse arguments V of -Wno-attributes=.
+   Currently we accept:
+     vendor::attr
+     vendor::
+   This functions also registers the parsed attributes so that we don't
+   warn that we don't recognize them.  */
+
+void
+handle_ignored_attributes_option (vec<char *> *v)
+{
+  if (v == nullptr)
+    return;
+
+  for (auto opt : v)
+    {
+      /* We're going to be modifying the string.  */
+      opt = xstrdup (opt);
+      char *q = strstr (opt, "::");
+      /* We don't accept '::attr'.  */
+      if (q == nullptr || q == opt)
+	{
+	  error ("wrong argument to ignored attributes");
+	  inform (input_location, "valid format is %<ns::attr%> or %<ns::%>");
+	  free (opt);
+	  continue;
+	}
+      /* 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");
+	  free (opt);
+	  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 +351,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 +558,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 +671,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..a299ceff6a2 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);
+      free (args);
+      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 1a5b9bfcca9..de9b848eda5 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 eee4c6737bb..6e6c580e329 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -23767,6 +23767,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 9fb74d34920..3b3b0a87fb3 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -8707,6 +8707,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 caed6255500..175b4635bb4 100644
--- a/gcc/opts.c
+++ b/gcc/opts.c
@@ -2611,6 +2611,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 e91f083f8ff..99276bde87d 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -457,6 +457,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: bcf3728abe8488882922005166d3065fc5fdfea1
-- 
2.33.1


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v5] attribs: Implement -Wno-attributes=vendor::attr [PR101940]
  2021-11-06  0:21               ` [PATCH v5] " Marek Polacek
@ 2021-11-06  1:32                 ` Bernhard Reutner-Fischer
  2021-11-06 18:28                   ` Marek Polacek
  0 siblings, 1 reply; 28+ messages in thread
From: Bernhard Reutner-Fischer @ 2021-11-06  1:32 UTC (permalink / raw)
  To: Marek Polacek, Marek Polacek via Gcc-patches, Jason Merrill
  Cc: Jakub Jelinek, GCC Patches

On 6 November 2021 01:21:43 CET, Marek Polacek via Gcc-patches <gcc-patches@gcc.gnu.org> wrote:

>
>Thanks, so like this?  I'm including an incremental diff so that it's
>clear what changed:
>
>diff --git a/gcc/attribs.c b/gcc/attribs.c
>index d5fba7f4bbb..addfe6f6c80 100644
>--- a/gcc/attribs.c
>+++ b/gcc/attribs.c
>@@ -237,7 +237,7 @@ check_attribute_tables (void)
>    the end of parsing of all TUs. */
> static vec<attribute_spec *> ignored_attributes_table;
> 
>-/* Parse arguments ARGS of -Wno-attributes=.
>+/* Parse arguments V of -Wno-attributes=.
>    Currently we accept:
>      vendor::attr
>      vendor::
>@@ -252,12 +252,15 @@ handle_ignored_attributes_option (vec<char *> *v)
> 
>   for (auto opt : v)
>     {
>+      /* We're going to be modifying the string.  */
>+      opt = xstrdup (opt);
>       char *q = strstr (opt, "::");
>       /* We don't accept '::attr'.  */
>       if (q == nullptr || q == opt)
> 	{
> 	  error ("wrong argument to ignored attributes");
> 	  inform (input_location, "valid format is %<ns::attr%> or %<ns::%>");
>+	  free (opt);
> 	  continue;
> 	}

Only xstrdup here, after the strstr check?
Should maybe strdup the rest here, not full opt..
thanks,
>       /* Cut off the vendor part.  */
>@@ -274,6 +277,7 @@ handle_ignored_attributes_option (vec<char *> *v)
>       if (!valid_p (vendor) || !valid_p (attr))
> 	{
> 	  error ("wrong argument to ignored attributes");
>+	  free (opt);
> 	  continue;
> 	}
>       /* Turn "__attr__" into "attr" so that we have a canonical form of


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v5] attribs: Implement -Wno-attributes=vendor::attr [PR101940]
  2021-11-06  1:32                 ` Bernhard Reutner-Fischer
@ 2021-11-06 18:28                   ` Marek Polacek
  2021-11-06 19:29                     ` Jason Merrill
  0 siblings, 1 reply; 28+ messages in thread
From: Marek Polacek @ 2021-11-06 18:28 UTC (permalink / raw)
  To: Bernhard Reutner-Fischer
  Cc: Marek Polacek via Gcc-patches, Jason Merrill, Jakub Jelinek

On Sat, Nov 06, 2021 at 02:32:26AM +0100, Bernhard Reutner-Fischer wrote:
> On 6 November 2021 01:21:43 CET, Marek Polacek via Gcc-patches <gcc-patches@gcc.gnu.org> wrote:
> 
> >
> >Thanks, so like this?  I'm including an incremental diff so that it's
> >clear what changed:
> >
> >diff --git a/gcc/attribs.c b/gcc/attribs.c
> >index d5fba7f4bbb..addfe6f6c80 100644
> >--- a/gcc/attribs.c
> >+++ b/gcc/attribs.c
> >@@ -237,7 +237,7 @@ check_attribute_tables (void)
> >    the end of parsing of all TUs. */
> > static vec<attribute_spec *> ignored_attributes_table;
> > 
> >-/* Parse arguments ARGS of -Wno-attributes=.
> >+/* Parse arguments V of -Wno-attributes=.
> >    Currently we accept:
> >      vendor::attr
> >      vendor::
> >@@ -252,12 +252,15 @@ handle_ignored_attributes_option (vec<char *> *v)
> > 
> >   for (auto opt : v)
> >     {
> >+      /* We're going to be modifying the string.  */
> >+      opt = xstrdup (opt);
> >       char *q = strstr (opt, "::");
> >       /* We don't accept '::attr'.  */
> >       if (q == nullptr || q == opt)
> > 	{
> > 	  error ("wrong argument to ignored attributes");
> > 	  inform (input_location, "valid format is %<ns::attr%> or %<ns::%>");
> >+	  free (opt);
> > 	  continue;
> > 	}
> 
> Only xstrdup here, after the strstr check?
> Should maybe strdup the rest here, not full opt..

No, I want q to point into the copy of the string, since I'm about
to modify it.  And I'd prefer a single call to xstrdup rather than
two.

Marek


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v5] attribs: Implement -Wno-attributes=vendor::attr [PR101940]
  2021-11-06 18:28                   ` Marek Polacek
@ 2021-11-06 19:29                     ` Jason Merrill
  2021-11-06 20:29                       ` Bernhard Reutner-Fischer
  2021-11-09  1:41                       ` [PATCH v6] " Marek Polacek
  0 siblings, 2 replies; 28+ messages in thread
From: Jason Merrill @ 2021-11-06 19:29 UTC (permalink / raw)
  To: Marek Polacek, Bernhard Reutner-Fischer
  Cc: Marek Polacek via Gcc-patches, Jakub Jelinek

On 11/6/21 14:28, Marek Polacek wrote:
> On Sat, Nov 06, 2021 at 02:32:26AM +0100, Bernhard Reutner-Fischer wrote:
>> On 6 November 2021 01:21:43 CET, Marek Polacek via Gcc-patches <gcc-patches@gcc.gnu.org> wrote:
>>
>>>
>>> Thanks, so like this?  I'm including an incremental diff so that it's
>>> clear what changed:
>>>
>>> diff --git a/gcc/attribs.c b/gcc/attribs.c
>>> index d5fba7f4bbb..addfe6f6c80 100644
>>> --- a/gcc/attribs.c
>>> +++ b/gcc/attribs.c
>>> @@ -237,7 +237,7 @@ check_attribute_tables (void)
>>>     the end of parsing of all TUs. */
>>> static vec<attribute_spec *> ignored_attributes_table;
>>>
>>> -/* Parse arguments ARGS of -Wno-attributes=.
>>> +/* Parse arguments V of -Wno-attributes=.
>>>     Currently we accept:
>>>       vendor::attr
>>>       vendor::
>>> @@ -252,12 +252,15 @@ handle_ignored_attributes_option (vec<char *> *v)
>>>
>>>    for (auto opt : v)
>>>      {
>>> +      /* We're going to be modifying the string.  */
>>> +      opt = xstrdup (opt);
>>>        char *q = strstr (opt, "::");
>>>        /* We don't accept '::attr'.  */
>>>        if (q == nullptr || q == opt)
>>> 	{
>>> 	  error ("wrong argument to ignored attributes");
>>> 	  inform (input_location, "valid format is %<ns::attr%> or %<ns::%>");
>>> +	  free (opt);
>>> 	  continue;
>>> 	}
>>
>> Only xstrdup here, after the strstr check?
>> Should maybe strdup the rest here, not full opt..
> 
> No, I want q to point into the copy of the string, since I'm about
> to modify it.  And I'd prefer a single call to xstrdup rather than
> two.

It occurs to me that instead of calling xstrdup at all, since you're 
already passing the strings to get_identifier you could use 
get_identifier_with_length instead, and then refer to IDENTIFIER_POINTER 
of the result.

Jason


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v5] attribs: Implement -Wno-attributes=vendor::attr [PR101940]
  2021-11-06 19:29                     ` Jason Merrill
@ 2021-11-06 20:29                       ` Bernhard Reutner-Fischer
  2021-11-09  1:41                       ` [PATCH v6] " Marek Polacek
  1 sibling, 0 replies; 28+ messages in thread
From: Bernhard Reutner-Fischer @ 2021-11-06 20:29 UTC (permalink / raw)
  To: Jason Merrill
  Cc: rep.dot.nop, Marek Polacek, Marek Polacek via Gcc-patches, Jakub Jelinek

On Sat, 6 Nov 2021 15:29:57 -0400
Jason Merrill <jason@redhat.com> wrote:

> On 11/6/21 14:28, Marek Polacek wrote:
> > On Sat, Nov 06, 2021 at 02:32:26AM +0100, Bernhard Reutner-Fischer wrote:  

> > No, I want q to point into the copy of the string, since I'm about
> > to modify it.  And I'd prefer a single call to xstrdup rather than
> > two.  
> 
> It occurs to me that instead of calling xstrdup at all, since you're 
> already passing the strings to get_identifier you could use 
> get_identifier_with_length instead, and then refer to IDENTIFIER_POINTER 
> of the result.

Right, i should have looked at the full diff.
I can see the point in stripping __attr__ to attr but also stripping
the vendors sounds a bit odd, doesn't it.

IMHO it would have been way easier to just calculate the desired start
and end and get_identifier_with_length for the vendor and attr as Jason
said.

Guess these local lambdas are a thing nowadays :)

Sorry for the noise..

^ permalink raw reply	[flat|nested] 28+ messages in thread

* [PATCH v6] attribs: Implement -Wno-attributes=vendor::attr [PR101940]
  2021-11-06 19:29                     ` Jason Merrill
  2021-11-06 20:29                       ` Bernhard Reutner-Fischer
@ 2021-11-09  1:41                       ` Marek Polacek
  2021-11-09  5:12                         ` Jason Merrill
  1 sibling, 1 reply; 28+ messages in thread
From: Marek Polacek @ 2021-11-09  1:41 UTC (permalink / raw)
  To: Jason Merrill
  Cc: Bernhard Reutner-Fischer, Marek Polacek via Gcc-patches, Jakub Jelinek

On Sat, Nov 06, 2021 at 03:29:57PM -0400, Jason Merrill wrote:
> On 11/6/21 14:28, Marek Polacek wrote:
> > On Sat, Nov 06, 2021 at 02:32:26AM +0100, Bernhard Reutner-Fischer wrote:
> > > On 6 November 2021 01:21:43 CET, Marek Polacek via Gcc-patches <gcc-patches@gcc.gnu.org> wrote:
> > > 
> > > > 
> > > > Thanks, so like this?  I'm including an incremental diff so that it's
> > > > clear what changed:
> > > > 
> > > > diff --git a/gcc/attribs.c b/gcc/attribs.c
> > > > index d5fba7f4bbb..addfe6f6c80 100644
> > > > --- a/gcc/attribs.c
> > > > +++ b/gcc/attribs.c
> > > > @@ -237,7 +237,7 @@ check_attribute_tables (void)
> > > >     the end of parsing of all TUs. */
> > > > static vec<attribute_spec *> ignored_attributes_table;
> > > > 
> > > > -/* Parse arguments ARGS of -Wno-attributes=.
> > > > +/* Parse arguments V of -Wno-attributes=.
> > > >     Currently we accept:
> > > >       vendor::attr
> > > >       vendor::
> > > > @@ -252,12 +252,15 @@ handle_ignored_attributes_option (vec<char *> *v)
> > > > 
> > > >    for (auto opt : v)
> > > >      {
> > > > +      /* We're going to be modifying the string.  */
> > > > +      opt = xstrdup (opt);
> > > >        char *q = strstr (opt, "::");
> > > >        /* We don't accept '::attr'.  */
> > > >        if (q == nullptr || q == opt)
> > > > 	{
> > > > 	  error ("wrong argument to ignored attributes");
> > > > 	  inform (input_location, "valid format is %<ns::attr%> or %<ns::%>");
> > > > +	  free (opt);
> > > > 	  continue;
> > > > 	}
> > > 
> > > Only xstrdup here, after the strstr check?
> > > Should maybe strdup the rest here, not full opt..
> > 
> > No, I want q to point into the copy of the string, since I'm about
> > to modify it.  And I'd prefer a single call to xstrdup rather than
> > two.
> 
> It occurs to me that instead of calling xstrdup at all, since you're already
> passing the strings to get_identifier you could use
> get_identifier_with_length instead, and then refer to IDENTIFIER_POINTER of
> the result.

Ah, clever.  I didn't think it would work because I didn't expect that
get_identifier_with_length works when it gets a string that isn't
nul-terminated but it does.  So how about the following?

Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?

-- >8 --
It is desirable for -Wattributes to warn about e.g.

[[deprecate]] void g(); // typo, should warn

However, -Wattributes also warns about vendor-specific attributes
(that's because lookup_scoped_attribute_spec -> find_attribute_namespace
finds nothing), which, with -Werror, causes grief.  We don't want the
-Wattributes warning for

[[company::attr]] void f();

GCC warns because it doesn't know the "company" namespace; it only knows
the "gnu" and "omp" namespaces.  We could entirely disable warning about
attributes in unknown scopes but then the compiler would also miss typos
like

  [[company::attrx]] void f();

or

  [[gmu::warn_used_result]] int write();

so that is not a viable solution.  A workaround is to use a #pragma:

  #pragma GCC diagnostic push
  #pragma GCC diagnostic ignored "-Wattributes"
  [[company::attr]] void f() {}
  #pragma GCC diagnostic pop

but that's a mouthful and awkward to use and could also hide typos.  In
fact, any macro-based solution doesn't seem like a way forward.

This patch implements -Wno-attributes=, which takes these arguments:

company::attr
company::

This option should go well with using @file: the user could have a file
containing
-Wno-attributes=vendor::attr1,vendor::attr2
and then invoke gcc with '@attrs' or similar.

I've also added a new pragma which has the same effect:

The pragma along with the new option should help with various static
analysis tools.

	PR c++/101940

gcc/ChangeLog:

	* attribs.c (struct scoped_attributes): Add a bool member.
	(lookup_scoped_attribute_spec): Forward declare.
	(register_scoped_attributes): New bool parameter, defaulted to
	false.  Use it.
	(handle_ignored_attributes_option): New function.
	(free_attr_data): New function.
	(init_attributes): Call handle_ignored_attributes_option.
	(attr_namespace_ignored_p): New function.
	(decl_attributes): Check attr_namespace_ignored_p before
	warning.
	* attribs.h (free_attr_data): Declare.
	(register_scoped_attributes): Adjust declaration.
	(handle_ignored_attributes_option): Declare.
	* common.opt (Wattributes=): New option with a variable.
	* doc/extend.texi: Document #pragma GCC diagnostic ignored_attributes.
	* doc/invoke.texi: Document -Wno-attributes=.
	* opts.c (common_handle_option) <case OPT_Wattributes_>: Handle.
	* plugin.h (register_scoped_attributes): Adjust declaration.
	* toplev.c (compile_file): Call free_attr_data.

gcc/c-family/ChangeLog:

	* c-pragma.c (handle_pragma_diagnostic): Handle #pragma GCC diagnostic
	ignored_attributes.

gcc/testsuite/ChangeLog:

	* c-c++-common/Wno-attributes-1.c: New test.
	* c-c++-common/Wno-attributes-2.c: New test.
---
 gcc/attribs.c                                 | 123 +++++++++++++++++-
 gcc/attribs.h                                 |   5 +-
 gcc/c-family/c-pragma.c                       |  37 +++++-
 gcc/common.opt                                |   9 +-
 gcc/doc/extend.texi                           |  19 +++
 gcc/doc/invoke.texi                           |  20 +++
 gcc/opts.c                                    |  20 +++
 gcc/plugin.h                                  |   4 +-
 gcc/testsuite/c-c++-common/Wno-attributes-1.c |  55 ++++++++
 gcc/testsuite/c-c++-common/Wno-attributes-2.c |  56 ++++++++
 gcc/toplev.c                                  |   2 +
 11 files changed, 341 insertions(+), 9 deletions(-)
 create mode 100644 gcc/testsuite/c-c++-common/Wno-attributes-1.c
 create mode 100644 gcc/testsuite/c-c++-common/Wno-attributes-2.c

diff --git a/gcc/attribs.c b/gcc/attribs.c
index 83fafc98b7d..23d92ca9474 100644
--- a/gcc/attribs.c
+++ b/gcc/attribs.c
@@ -87,6 +87,8 @@ struct scoped_attributes
   const char *ns;
   vec<attribute_spec> attributes;
   hash_table<attribute_hasher> *attribute_hash;
+  /* True if we should not warn about unknown attributes in this NS.  */
+  bool ignored_p;
 };
 
 /* The table of scope attributes.  */
@@ -95,6 +97,8 @@ static vec<scoped_attributes> attributes_table;
 static scoped_attributes* find_attribute_namespace (const char*);
 static void register_scoped_attribute (const struct attribute_spec *,
 				       scoped_attributes *);
+static const struct attribute_spec *lookup_scoped_attribute_spec (const_tree,
+								  const_tree);
 
 static bool attributes_initialized = false;
 
@@ -121,12 +125,14 @@ extract_attribute_substring (struct substring *str)
 
 /* Insert an array of attributes ATTRIBUTES into a namespace.  This
    array must be NULL terminated.  NS is the name of attribute
-   namespace.  The function returns the namespace into which the
-   attributes have been registered.  */
+   namespace.  IGNORED_P is true iff all unknown attributes in this
+   namespace should be ignored for the purposes of -Wattributes.  The
+   function returns the namespace into which the attributes have been
+   registered.  */
 
 scoped_attributes *
 register_scoped_attributes (const struct attribute_spec *attributes,
-			    const char *ns)
+			    const char *ns, bool ignored_p /*=false*/)
 {
   scoped_attributes *result = NULL;
 
@@ -144,9 +150,12 @@ register_scoped_attributes (const struct attribute_spec *attributes,
       memset (&sa, 0, sizeof (sa));
       sa.ns = ns;
       sa.attributes.create (64);
+      sa.ignored_p = ignored_p;
       result = attributes_table.safe_push (sa);
       result->attribute_hash = new hash_table<attribute_hasher> (200);
     }
+  else
+    result->ignored_p |= ignored_p;
 
   /* Really add the attributes to their namespace now.  */
   for (unsigned i = 0; attributes[i].name != NULL; ++i)
@@ -224,6 +233,95 @@ check_attribute_tables (void)
 				 attribute_tables[j][l].name));
 }
 
+/* Used to stash pointers to allocated memory so that we can free them at
+   the end of parsing of all TUs. */
+static vec<attribute_spec *> ignored_attributes_table;
+
+/* Parse arguments V of -Wno-attributes=.
+   Currently we accept:
+     vendor::attr
+     vendor::
+   This functions also registers the parsed attributes so that we don't
+   warn that we don't recognize them.  */
+
+void
+handle_ignored_attributes_option (vec<char *> *v)
+{
+  if (v == nullptr)
+    return;
+
+  for (auto opt : v)
+    {
+      char *cln = strstr (opt, "::");
+      /* We don't accept '::attr'.  */
+      if (cln == nullptr || cln == opt)
+	{
+	  error ("wrong argument to ignored attributes");
+	  inform (input_location, "valid format is %<ns::attr%> or %<ns::%>");
+	  continue;
+	}
+      char *vendor_start = opt;
+      ptrdiff_t vendor_len = cln - opt;
+      char *attr_start = cln + 2;
+      /* This could really use rawmemchr :(.  */
+      ptrdiff_t attr_len = strchr (attr_start, '\0') - attr_start;
+      /* Verify that they look valid.  */
+      auto valid_p = [](const char *const s, ptrdiff_t len) {
+	for (int i = 0; i < len; ++i)
+	  if (!ISALNUM (*s) && *s != '_')
+	    return false;
+	return true;
+      };
+      if (!valid_p (vendor_start, vendor_len)
+	  || !valid_p (attr_start, attr_len))
+	{
+	  error ("wrong argument to ignored attributes");
+	  continue;
+	}
+      /* Turn "__attr__" into "attr" so that we have a canonical form of
+	 attribute names.  Likewise for vendor.  */
+      auto strip = [](char *&s, ptrdiff_t &l) {
+	if (l > 4 && s[0] == '_' && s[1] == '_'
+	    && s[l - 1] == '_' && s[l - 2] == '_')
+	  {
+	    s += 2;
+	    l -= 4;
+	  }
+      };
+      strip (attr_start, attr_len);
+      strip (vendor_start, vendor_len);
+      /* We perform all this hijinks so that we don't have to copy OPT.  */
+      tree vendor_id = get_identifier_with_length (vendor_start, vendor_len);
+      tree attr_id = get_identifier_with_length (attr_start, attr_len);
+      /* If we've already seen this vendor::attr, ignore it.  Attempting to
+	 register it twice would lead to a crash.  */
+      if (lookup_scoped_attribute_spec (vendor_id, attr_id))
+	continue;
+      /* In the "vendor::" case, we should ignore *any* attribute coming
+	 from this attribute namespace.  */
+      const char *vendor = IDENTIFIER_POINTER (vendor_id);
+      const char *attr = attr_len == 0 ? nullptr : IDENTIFIER_POINTER (attr_id);
+      /* 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 +350,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 +557,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 +670,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..a299ceff6a2 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);
+      free (args);
+      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 1a5b9bfcca9..de9b848eda5 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 eee4c6737bb..6e6c580e329 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -23767,6 +23767,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 f206cff1221..339b8d7597b 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -8707,6 +8707,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 caed6255500..175b4635bb4 100644
--- a/gcc/opts.c
+++ b/gcc/opts.c
@@ -2611,6 +2611,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 e91f083f8ff..99276bde87d 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -457,6 +457,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: 206c08ce28a3c70afa4ecf9274611295d6369218
-- 
2.33.1


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v6] attribs: Implement -Wno-attributes=vendor::attr [PR101940]
  2021-11-09  1:41                       ` [PATCH v6] " Marek Polacek
@ 2021-11-09  5:12                         ` Jason Merrill
  2021-11-09  7:09                           ` Bernhard Reutner-Fischer
  2021-11-09 15:51                           ` [PATCH v6] " Marek Polacek
  0 siblings, 2 replies; 28+ messages in thread
From: Jason Merrill @ 2021-11-09  5:12 UTC (permalink / raw)
  To: Marek Polacek
  Cc: Bernhard Reutner-Fischer, Marek Polacek via Gcc-patches, Jakub Jelinek

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

Hmm, this looks like it isn't handling the case of previously ignoring 
vendor::; it seems we'll look for vendor::<empty string> instead, not 
find it, and register again.

> +      /* In the "vendor::" case, we should ignore *any* attribute coming
> +	 from this attribute namespace.  */
> +      const char *vendor = IDENTIFIER_POINTER (vendor_id);
> +      const char *attr = attr_len == 0 ? nullptr : IDENTIFIER_POINTER (attr_id);
> +      /* 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 +350,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 +557,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 +670,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..a299ceff6a2 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);
> +      free (args);
> +      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 1a5b9bfcca9..de9b848eda5 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 eee4c6737bb..6e6c580e329 100644
> --- a/gcc/doc/extend.texi
> +++ b/gcc/doc/extend.texi
> @@ -23767,6 +23767,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 f206cff1221..339b8d7597b 100644
> --- a/gcc/doc/invoke.texi
> +++ b/gcc/doc/invoke.texi
> @@ -8707,6 +8707,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 caed6255500..175b4635bb4 100644
> --- a/gcc/opts.c
> +++ b/gcc/opts.c
> @@ -2611,6 +2611,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 e91f083f8ff..99276bde87d 100644
> --- a/gcc/toplev.c
> +++ b/gcc/toplev.c
> @@ -457,6 +457,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: 206c08ce28a3c70afa4ecf9274611295d6369218
> 


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v6] attribs: Implement -Wno-attributes=vendor::attr [PR101940]
  2021-11-09  5:12                         ` Jason Merrill
@ 2021-11-09  7:09                           ` Bernhard Reutner-Fischer
  2021-11-09 15:55                             ` Marek Polacek
  2021-11-09 15:51                           ` [PATCH v6] " Marek Polacek
  1 sibling, 1 reply; 28+ messages in thread
From: Bernhard Reutner-Fischer @ 2021-11-09  7:09 UTC (permalink / raw)
  To: Jason Merrill
  Cc: rep.dot.nop, Marek Polacek, Marek Polacek via Gcc-patches, Jakub Jelinek

On Tue, 9 Nov 2021 00:12:10 -0500
Jason Merrill <jason@redhat.com> wrote:

> On 11/8/21 20:41, Marek Polacek wrote:
> > On Sat, Nov 06, 2021 at 03:29:57PM -0400, Jason Merrill wrote:  

> > +  for (auto opt : v)
> > +    {
> > +      char *cln = strstr (opt, "::");
> > +      /* We don't accept '::attr'.  */
> > +      if (cln == nullptr || cln == opt)
> > +	{
> > +	  error ("wrong argument to ignored attributes");
> > +	  inform (input_location, "valid format is %<ns::attr%> or %<ns::%>");
> > +	  continue;
> > +	}
> > +      char *vendor_start = opt;
> > +      ptrdiff_t vendor_len = cln - opt;
> > +      char *attr_start = cln + 2;
> > +      /* This could really use rawmemchr :(.  */
> > +      ptrdiff_t attr_len = strchr (attr_start, '\0') - attr_start;
> > +      /* Verify that they look valid.  */
> > +      auto valid_p = [](const char *const s, ptrdiff_t len) {
> > +	for (int i = 0; i < len; ++i)
> > +	  if (!ISALNUM (*s) && *s != '_')
> > +	    return false;
> > +	return true;
> > +      };
> > +      if (!valid_p (vendor_start, vendor_len)
> > +	  || !valid_p (attr_start, attr_len))
> > +	{
> > +	  error ("wrong argument to ignored attributes");
> > +	  continue;
> > +	}
> > +      /* Turn "__attr__" into "attr" so that we have a canonical form of
> > +	 attribute names.  Likewise for vendor.  */
> > +      auto strip = [](char *&s, ptrdiff_t &l) {
> > +	if (l > 4 && s[0] == '_' && s[1] == '_'
> > +	    && s[l - 1] == '_' && s[l - 2] == '_')
> > +	  {
> > +	    s += 2;
> > +	    l -= 4;
> > +	  }
> > +      };
> > +      strip (attr_start, attr_len);
> > +      strip (vendor_start, vendor_len);
> > +      /* We perform all this hijinks so that we don't have to copy OPT.  */
> > +      tree vendor_id = get_identifier_with_length (vendor_start, vendor_len);
> > +      tree attr_id = get_identifier_with_length (attr_start, attr_len);
> > +      /* If we've already seen this vendor::attr, ignore it.  Attempting to
> > +	 register it twice would lead to a crash.  */
> > +      if (lookup_scoped_attribute_spec (vendor_id, attr_id))
> > +	continue;  
> 
> Hmm, this looks like it isn't handling the case of previously ignoring 
> vendor::; it seems we'll look for vendor::<empty string> instead, not 
> find it, and register again.

I don't know if there are __attrib with 2 leading underscores but no
trailing that we accept and should normalize?

And it is surprising that we do not have a simple normalize_attr_name().
There must be existing spots where we would normalize attribute names?
extract_attribute_substring does about the same but with a struct substring(?).
Maybe that's just to avoid a normal string hash.

thanks,

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v6] attribs: Implement -Wno-attributes=vendor::attr [PR101940]
  2021-11-09  5:12                         ` Jason Merrill
  2021-11-09  7:09                           ` Bernhard Reutner-Fischer
@ 2021-11-09 15:51                           ` Marek Polacek
  1 sibling, 0 replies; 28+ messages in thread
From: Marek Polacek @ 2021-11-09 15:51 UTC (permalink / raw)
  To: Jason Merrill
  Cc: Bernhard Reutner-Fischer, Marek Polacek via Gcc-patches, Jakub Jelinek

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

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

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

Thanks,
Marek


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v6] attribs: Implement -Wno-attributes=vendor::attr [PR101940]
  2021-11-09  7:09                           ` Bernhard Reutner-Fischer
@ 2021-11-09 15:55                             ` Marek Polacek
  2021-11-09 17:27                               ` Jason Merrill
  0 siblings, 1 reply; 28+ messages in thread
From: Marek Polacek @ 2021-11-09 15:55 UTC (permalink / raw)
  To: Bernhard Reutner-Fischer
  Cc: Jason Merrill, Marek Polacek via Gcc-patches, Jakub Jelinek

On Tue, Nov 09, 2021 at 08:09:10AM +0100, Bernhard Reutner-Fischer wrote:
> On Tue, 9 Nov 2021 00:12:10 -0500
> Jason Merrill <jason@redhat.com> wrote:
> 
> > On 11/8/21 20:41, Marek Polacek wrote:
> > > On Sat, Nov 06, 2021 at 03:29:57PM -0400, Jason Merrill wrote:  
> 
> > > +  for (auto opt : v)
> > > +    {
> > > +      char *cln = strstr (opt, "::");
> > > +      /* We don't accept '::attr'.  */
> > > +      if (cln == nullptr || cln == opt)
> > > +	{
> > > +	  error ("wrong argument to ignored attributes");
> > > +	  inform (input_location, "valid format is %<ns::attr%> or %<ns::%>");
> > > +	  continue;
> > > +	}
> > > +      char *vendor_start = opt;
> > > +      ptrdiff_t vendor_len = cln - opt;
> > > +      char *attr_start = cln + 2;
> > > +      /* This could really use rawmemchr :(.  */
> > > +      ptrdiff_t attr_len = strchr (attr_start, '\0') - attr_start;
> > > +      /* Verify that they look valid.  */
> > > +      auto valid_p = [](const char *const s, ptrdiff_t len) {
> > > +	for (int i = 0; i < len; ++i)
> > > +	  if (!ISALNUM (*s) && *s != '_')
> > > +	    return false;
> > > +	return true;
> > > +      };
> > > +      if (!valid_p (vendor_start, vendor_len)
> > > +	  || !valid_p (attr_start, attr_len))
> > > +	{
> > > +	  error ("wrong argument to ignored attributes");
> > > +	  continue;
> > > +	}
> > > +      /* Turn "__attr__" into "attr" so that we have a canonical form of
> > > +	 attribute names.  Likewise for vendor.  */
> > > +      auto strip = [](char *&s, ptrdiff_t &l) {
> > > +	if (l > 4 && s[0] == '_' && s[1] == '_'
> > > +	    && s[l - 1] == '_' && s[l - 2] == '_')
> > > +	  {
> > > +	    s += 2;
> > > +	    l -= 4;
> > > +	  }
> > > +      };
> > > +      strip (attr_start, attr_len);
> > > +      strip (vendor_start, vendor_len);
> > > +      /* We perform all this hijinks so that we don't have to copy OPT.  */
> > > +      tree vendor_id = get_identifier_with_length (vendor_start, vendor_len);
> > > +      tree attr_id = get_identifier_with_length (attr_start, attr_len);
> > > +      /* If we've already seen this vendor::attr, ignore it.  Attempting to
> > > +	 register it twice would lead to a crash.  */
> > > +      if (lookup_scoped_attribute_spec (vendor_id, attr_id))
> > > +	continue;  
> > 
> > Hmm, this looks like it isn't handling the case of previously ignoring 
> > vendor::; it seems we'll look for vendor::<empty string> instead, not 
> > find it, and register again.
> 
> I don't know if there are __attrib with 2 leading underscores but no
> trailing that we accept and should normalize?
> 
> And it is surprising that we do not have a simple normalize_attr_name().
> There must be existing spots where we would normalize attribute names?
> extract_attribute_substring does about the same but with a struct substring(?).
> Maybe that's just to avoid a normal string hash.

We have canonicalize_attr_name which I based my code on.

Marek


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v6] attribs: Implement -Wno-attributes=vendor::attr [PR101940]
  2021-11-09 15:55                             ` Marek Polacek
@ 2021-11-09 17:27                               ` Jason Merrill
  2021-11-09 19:17                                 ` [PATCH v7] " Marek Polacek
  0 siblings, 1 reply; 28+ messages in thread
From: Jason Merrill @ 2021-11-09 17:27 UTC (permalink / raw)
  To: Marek Polacek, Bernhard Reutner-Fischer
  Cc: Marek Polacek via Gcc-patches, Jakub Jelinek

On 11/9/21 10:55, Marek Polacek wrote:
> On Tue, Nov 09, 2021 at 08:09:10AM +0100, Bernhard Reutner-Fischer wrote:
>> On Tue, 9 Nov 2021 00:12:10 -0500
>> Jason Merrill <jason@redhat.com> wrote:
>>
>>> On 11/8/21 20:41, Marek Polacek wrote:
>>>> On Sat, Nov 06, 2021 at 03:29:57PM -0400, Jason Merrill wrote:
>>
>>>> +  for (auto opt : v)
>>>> +    {
>>>> +      char *cln = strstr (opt, "::");
>>>> +      /* We don't accept '::attr'.  */
>>>> +      if (cln == nullptr || cln == opt)
>>>> +	{
>>>> +	  error ("wrong argument to ignored attributes");
>>>> +	  inform (input_location, "valid format is %<ns::attr%> or %<ns::%>");
>>>> +	  continue;
>>>> +	}
>>>> +      char *vendor_start = opt;
>>>> +      ptrdiff_t vendor_len = cln - opt;
>>>> +      char *attr_start = cln + 2;
>>>> +      /* This could really use rawmemchr :(.  */
>>>> +      ptrdiff_t attr_len = strchr (attr_start, '\0') - attr_start;
>>>> +      /* Verify that they look valid.  */
>>>> +      auto valid_p = [](const char *const s, ptrdiff_t len) {
>>>> +	for (int i = 0; i < len; ++i)
>>>> +	  if (!ISALNUM (*s) && *s != '_')
>>>> +	    return false;
>>>> +	return true;
>>>> +      };
>>>> +      if (!valid_p (vendor_start, vendor_len)
>>>> +	  || !valid_p (attr_start, attr_len))
>>>> +	{
>>>> +	  error ("wrong argument to ignored attributes");
>>>> +	  continue;
>>>> +	}
>>>> +      /* Turn "__attr__" into "attr" so that we have a canonical form of
>>>> +	 attribute names.  Likewise for vendor.  */
>>>> +      auto strip = [](char *&s, ptrdiff_t &l) {
>>>> +	if (l > 4 && s[0] == '_' && s[1] == '_'
>>>> +	    && s[l - 1] == '_' && s[l - 2] == '_')
>>>> +	  {
>>>> +	    s += 2;
>>>> +	    l -= 4;
>>>> +	  }
>>>> +      };
>>>> +      strip (attr_start, attr_len);
>>>> +      strip (vendor_start, vendor_len);
>>>> +      /* We perform all this hijinks so that we don't have to copy OPT.  */
>>>> +      tree vendor_id = get_identifier_with_length (vendor_start, vendor_len);
>>>> +      tree attr_id = get_identifier_with_length (attr_start, attr_len);
>>>> +      /* If we've already seen this vendor::attr, ignore it.  Attempting to
>>>> +	 register it twice would lead to a crash.  */
>>>> +      if (lookup_scoped_attribute_spec (vendor_id, attr_id))
>>>> +	continue;
>>>
>>> Hmm, this looks like it isn't handling the case of previously ignoring
>>> vendor::; it seems we'll look for vendor::<empty string> instead, not
>>> find it, and register again.

> Yes, for -Wno-attributes=vendor::,vendor:: we call register_scoped_attributes
> twice, but I think that's OK: register_scoped_attributes will see that 
> find_attribute_namespace finds the namespace and returns without creating a new  
> one.
> 
> I think the current code handles -Wno-attributes=vendor::a,vendor:: well so
> I'm not sure if I should change it.

Makes sense.  But we should be able to avoid calling 
lookup_scoped_attribute_spec, and even get_identifier_with_length 
(attr...), if attr_len is 0.

>> I don't know if there are __attrib with 2 leading underscores but no
>> trailing that we accept and should normalize?
>>
>> And it is surprising that we do not have a simple normalize_attr_name().
>> There must be existing spots where we would normalize attribute names?
>> extract_attribute_substring does about the same but with a struct substring(?).
>> Maybe that's just to avoid a normal string hash.
> 
> We have canonicalize_attr_name which I based my code on.

We could factor out of that function an overload equivalent to your 
strip lambda?

Jason


^ permalink raw reply	[flat|nested] 28+ messages in thread

* [PATCH v7] attribs: Implement -Wno-attributes=vendor::attr [PR101940]
  2021-11-09 17:27                               ` Jason Merrill
@ 2021-11-09 19:17                                 ` Marek Polacek
  2021-11-09 19:47                                   ` Bernhard Reutner-Fischer
  2021-11-09 21:30                                   ` [PATCH v8] " Marek Polacek
  0 siblings, 2 replies; 28+ messages in thread
From: Marek Polacek @ 2021-11-09 19:17 UTC (permalink / raw)
  To: Jason Merrill
  Cc: Bernhard Reutner-Fischer, Marek Polacek via Gcc-patches, Jakub Jelinek

On Tue, Nov 09, 2021 at 12:27:28PM -0500, Jason Merrill wrote:
> On 11/9/21 10:55, Marek Polacek wrote:
> > On Tue, Nov 09, 2021 at 08:09:10AM +0100, Bernhard Reutner-Fischer wrote:
> > > On Tue, 9 Nov 2021 00:12:10 -0500
> > > Jason Merrill <jason@redhat.com> wrote:
> > > 
> > > > On 11/8/21 20:41, Marek Polacek wrote:
> > > > > On Sat, Nov 06, 2021 at 03:29:57PM -0400, Jason Merrill wrote:
> > > 
> > > > > +  for (auto opt : v)
> > > > > +    {
> > > > > +      char *cln = strstr (opt, "::");
> > > > > +      /* We don't accept '::attr'.  */
> > > > > +      if (cln == nullptr || cln == opt)
> > > > > +	{
> > > > > +	  error ("wrong argument to ignored attributes");
> > > > > +	  inform (input_location, "valid format is %<ns::attr%> or %<ns::%>");
> > > > > +	  continue;
> > > > > +	}
> > > > > +      char *vendor_start = opt;
> > > > > +      ptrdiff_t vendor_len = cln - opt;
> > > > > +      char *attr_start = cln + 2;
> > > > > +      /* This could really use rawmemchr :(.  */
> > > > > +      ptrdiff_t attr_len = strchr (attr_start, '\0') - attr_start;
> > > > > +      /* Verify that they look valid.  */
> > > > > +      auto valid_p = [](const char *const s, ptrdiff_t len) {
> > > > > +	for (int i = 0; i < len; ++i)
> > > > > +	  if (!ISALNUM (*s) && *s != '_')
> > > > > +	    return false;
> > > > > +	return true;
> > > > > +      };
> > > > > +      if (!valid_p (vendor_start, vendor_len)
> > > > > +	  || !valid_p (attr_start, attr_len))
> > > > > +	{
> > > > > +	  error ("wrong argument to ignored attributes");
> > > > > +	  continue;
> > > > > +	}
> > > > > +      /* Turn "__attr__" into "attr" so that we have a canonical form of
> > > > > +	 attribute names.  Likewise for vendor.  */
> > > > > +      auto strip = [](char *&s, ptrdiff_t &l) {
> > > > > +	if (l > 4 && s[0] == '_' && s[1] == '_'
> > > > > +	    && s[l - 1] == '_' && s[l - 2] == '_')
> > > > > +	  {
> > > > > +	    s += 2;
> > > > > +	    l -= 4;
> > > > > +	  }
> > > > > +      };
> > > > > +      strip (attr_start, attr_len);
> > > > > +      strip (vendor_start, vendor_len);
> > > > > +      /* We perform all this hijinks so that we don't have to copy OPT.  */
> > > > > +      tree vendor_id = get_identifier_with_length (vendor_start, vendor_len);
> > > > > +      tree attr_id = get_identifier_with_length (attr_start, attr_len);
> > > > > +      /* If we've already seen this vendor::attr, ignore it.  Attempting to
> > > > > +	 register it twice would lead to a crash.  */
> > > > > +      if (lookup_scoped_attribute_spec (vendor_id, attr_id))
> > > > > +	continue;
> > > > 
> > > > Hmm, this looks like it isn't handling the case of previously ignoring
> > > > vendor::; it seems we'll look for vendor::<empty string> instead, not
> > > > find it, and register again.
> 
> > Yes, for -Wno-attributes=vendor::,vendor:: we call register_scoped_attributes
> > twice, but I think that's OK: register_scoped_attributes will see that
> > find_attribute_namespace finds the namespace and returns without
> > creating a new  one.
> > 
> > I think the current code handles -Wno-attributes=vendor::a,vendor:: well so
> > I'm not sure if I should change it.
> 
> Makes sense.  But we should be able to avoid calling
> lookup_scoped_attribute_spec, and even get_identifier_with_length (attr...),
> if attr_len is 0.
 
Duh, of course.  Also no need to canonicalize an empty string.

> > > I don't know if there are __attrib with 2 leading underscores but no
> > > trailing that we accept and should normalize?
> > > 
> > > And it is surprising that we do not have a simple normalize_attr_name().
> > > There must be existing spots where we would normalize attribute names?
> > > extract_attribute_substring does about the same but with a struct substring(?).
> > > Maybe that's just to avoid a normal string hash.
> > 
> > We have canonicalize_attr_name which I based my code on.
> 
> We could factor out of that function an overload equivalent to your strip
> lambda?

OK.  Since it's taking a reference and I wanted it to work both with a size_t
and ptrdiff_t, I made it a template.  Is is too much?

Thanks,

Bootstrap/regtest running on ppc64le-linux-gnu.

-- >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.
	(canonicalize_attr_name): New function template.
	(canonicalize_attr_name): Use it.
	* common.opt (Wattributes=): New option with a variable.
	* doc/extend.texi: Document #pragma GCC diagnostic ignored_attributes.
	* doc/invoke.texi: Document -Wno-attributes=.
	* opts.c (common_handle_option) <case OPT_Wattributes_>: Handle.
	* plugin.h (register_scoped_attributes): Adjust declaration.
	* toplev.c (compile_file): Call free_attr_data.

gcc/c-family/ChangeLog:

	* c-pragma.c (handle_pragma_diagnostic): Handle #pragma GCC diagnostic
	ignored_attributes.

gcc/testsuite/ChangeLog:

	* c-c++-common/Wno-attributes-1.c: New test.
	* c-c++-common/Wno-attributes-2.c: New test.
---
 gcc/attribs.c                                 | 118 +++++++++++++++++-
 gcc/attribs.h                                 |  28 ++++-
 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, 356 insertions(+), 12 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..7779ef98cc6 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,90 @@ check_attribute_tables (void)
 				 attribute_tables[j][l].name));
 }
 
+/* Used to stash pointers to allocated memory so that we can free them at
+   the end of parsing of all TUs. */
+static vec<attribute_spec *> ignored_attributes_table;
+
+/* Parse arguments V of -Wno-attributes=.
+   Currently we accept:
+     vendor::attr
+     vendor::
+   This functions also registers the parsed attributes so that we don't
+   warn that we don't recognize them.  */
+
+void
+handle_ignored_attributes_option (vec<char *> *v)
+{
+  if (v == nullptr)
+    return;
+
+  for (auto opt : v)
+    {
+      char *cln = strstr (opt, "::");
+      /* We don't accept '::attr'.  */
+      if (cln == nullptr || cln == opt)
+	{
+	  error ("wrong argument to ignored attributes");
+	  inform (input_location, "valid format is %<ns::attr%> or %<ns::%>");
+	  continue;
+	}
+      const char *vendor_start = opt;
+      ptrdiff_t vendor_len = cln - opt;
+      const char *attr_start = cln + 2;
+      /* This could really use rawmemchr :(.  */
+      ptrdiff_t attr_len = strchr (attr_start, '\0') - attr_start;
+      /* Verify that they look valid.  */
+      auto valid_p = [](const char *const s, ptrdiff_t len) {
+	for (int i = 0; i < len; ++i)
+	  if (!ISALNUM (*s) && *s != '_')
+	    return false;
+	return true;
+      };
+      if (!valid_p (vendor_start, vendor_len)
+	  || !valid_p (attr_start, attr_len))
+	{
+	  error ("wrong argument to ignored attributes");
+	  continue;
+	}
+      canonicalize_attr_name (vendor_start, vendor_len);
+      /* We perform all this hijinks so that we don't have to copy OPT.  */
+      tree vendor_id = get_identifier_with_length (vendor_start, vendor_len);
+      const char *attr;
+      /* In the "vendor::" case, we should ignore *any* attribute coming
+	 from this attribute namespace.  */
+      if (attr_len > 0)
+	{
+	  canonicalize_attr_name (attr_start, attr_len);
+	  tree attr_id = get_identifier_with_length (attr_start, attr_len);
+	  attr = IDENTIFIER_POINTER (attr_id);
+	  /* If we've already seen this vendor::attr, ignore it.  Attempting to
+	     register it twice would lead to a crash.  */
+	  if (lookup_scoped_attribute_spec (vendor_id, attr_id))
+	    continue;
+	}
+      else
+	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, IDENTIFIER_POINTER (vendor_id), !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 +345,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 +552,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 +665,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..ba657881940 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.
@@ -114,17 +117,34 @@ extern unsigned decls_mismatched_attributes (tree, tree, tree,
 
 extern void maybe_diag_alias_attributes (tree, tree);
 
+/* For a given string S of length L, strip leading and trailing '_' characters
+   so that we have a canonical form of attribute names.  NB: This function may
+   change S and L.  */
+
+template <typename T>
+inline bool
+canonicalize_attr_name (const char *&s, T &l)
+{
+  if (l > 4 && s[0] == '_' && s[1] == '_' && s[l - 1] == '_' && s[l - 2] == '_')
+    {
+      s += 2;
+      l -= 4;
+      return true;
+    }
+  return false;
+}
+
 /* For a given IDENTIFIER_NODE, strip leading and trailing '_' characters
    so that we have a canonical form of attribute names.  */
 
 static inline tree
 canonicalize_attr_name (tree attr_name)
 {
-  const size_t l = IDENTIFIER_LENGTH (attr_name);
+  size_t l = IDENTIFIER_LENGTH (attr_name);
   const char *s = IDENTIFIER_POINTER (attr_name);
 
-  if (l > 4 && s[0] == '_' && s[1] == '_' && s[l - 1] == '_' && s[l - 2] == '_')
-    return get_identifier_with_length (s + 2, l - 4);
+  if (canonicalize_attr_name (s, l))
+    return get_identifier_with_length (s, l);
 
   return attr_name;
 }
diff --git a/gcc/c-family/c-pragma.c b/gcc/c-family/c-pragma.c
index a9be8df0384..a299ceff6a2 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);
+      free (args);
+      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 1a5b9bfcca9..de9b848eda5 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 eee4c6737bb..6e6c580e329 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -23767,6 +23767,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 2ea23d07c4c..297ca98deae 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -8707,6 +8707,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 caed6255500..175b4635bb4 100644
--- a/gcc/opts.c
+++ b/gcc/opts.c
@@ -2611,6 +2611,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 e91f083f8ff..99276bde87d 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -457,6 +457,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: 53080c5b4ce3742d20a0aa4643203215f20aadf6
-- 
2.33.1


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v7] attribs: Implement -Wno-attributes=vendor::attr [PR101940]
  2021-11-09 19:17                                 ` [PATCH v7] " Marek Polacek
@ 2021-11-09 19:47                                   ` Bernhard Reutner-Fischer
  2021-11-09 19:57                                     ` Bernhard Reutner-Fischer
  2021-11-09 21:30                                   ` [PATCH v8] " Marek Polacek
  1 sibling, 1 reply; 28+ messages in thread
From: Bernhard Reutner-Fischer @ 2021-11-09 19:47 UTC (permalink / raw)
  To: Marek Polacek
  Cc: rep.dot.nop, Jason Merrill, Marek Polacek via Gcc-patches, Jakub Jelinek

On Tue, 9 Nov 2021 14:17:14 -0500
Marek Polacek <polacek@redhat.com> wrote:

> +      if (!valid_p (vendor_start, vendor_len)
> +	  || !valid_p (attr_start, attr_len))
> +	{
> +	  error ("wrong argument to ignored attributes");
> +	  continue;
> +	}
> +      canonicalize_attr_name (vendor_start, vendor_len);
> +      /* We perform all this hijinks so that we don't have to copy OPT.  */
> +      tree vendor_id = get_identifier_with_length (vendor_start, vendor_len);

[[____::attry]] void f17y(); /* { dg-warning "ignored" } */

so i'd maybe put the
|| !canonicalize_attr_name (vendor_start, vendor_len)
in the condition above?

thanks,

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v7] attribs: Implement -Wno-attributes=vendor::attr [PR101940]
  2021-11-09 19:47                                   ` Bernhard Reutner-Fischer
@ 2021-11-09 19:57                                     ` Bernhard Reutner-Fischer
  2021-11-09 20:23                                       ` Marek Polacek
  0 siblings, 1 reply; 28+ messages in thread
From: Bernhard Reutner-Fischer @ 2021-11-09 19:57 UTC (permalink / raw)
  To: Marek Polacek
  Cc: rep.dot.nop, Jason Merrill, Marek Polacek via Gcc-patches, Jakub Jelinek

On Tue, 9 Nov 2021 20:47:02 +0100
Bernhard Reutner-Fischer <rep.dot.nop@gmail.com> wrote:

> On Tue, 9 Nov 2021 14:17:14 -0500
> Marek Polacek <polacek@redhat.com> wrote:
> 
> > +      if (!valid_p (vendor_start, vendor_len)
> > +	  || !valid_p (attr_start, attr_len))
> > +	{
> > +	  error ("wrong argument to ignored attributes");
> > +	  continue;
> > +	}
> > +      canonicalize_attr_name (vendor_start, vendor_len);
> > +      /* We perform all this hijinks so that we don't have to copy OPT.  */
> > +      tree vendor_id = get_identifier_with_length (vendor_start, vendor_len);  
> 
> [[____::attry]] void f17y(); /* { dg-warning "ignored" } */
> 
> so i'd maybe put the
> || !canonicalize_attr_name (vendor_start, vendor_len)
> in the condition above?

Well no. Guess vendors and attribute just consisting of underscores
will not be used that often anyway. I'd have required at least one
alpha or at least alnum but whatever.
thanks,

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v7] attribs: Implement -Wno-attributes=vendor::attr [PR101940]
  2021-11-09 19:57                                     ` Bernhard Reutner-Fischer
@ 2021-11-09 20:23                                       ` Marek Polacek
  0 siblings, 0 replies; 28+ messages in thread
From: Marek Polacek @ 2021-11-09 20:23 UTC (permalink / raw)
  To: Bernhard Reutner-Fischer
  Cc: Jason Merrill, Marek Polacek via Gcc-patches, Jakub Jelinek

On Tue, Nov 09, 2021 at 08:57:48PM +0100, Bernhard Reutner-Fischer wrote:
> On Tue, 9 Nov 2021 20:47:02 +0100
> Bernhard Reutner-Fischer <rep.dot.nop@gmail.com> wrote:
> 
> > On Tue, 9 Nov 2021 14:17:14 -0500
> > Marek Polacek <polacek@redhat.com> wrote:
> > 
> > > +      if (!valid_p (vendor_start, vendor_len)
> > > +	  || !valid_p (attr_start, attr_len))
> > > +	{
> > > +	  error ("wrong argument to ignored attributes");
> > > +	  continue;
> > > +	}
> > > +      canonicalize_attr_name (vendor_start, vendor_len);
> > > +      /* We perform all this hijinks so that we don't have to copy OPT.  */
> > > +      tree vendor_id = get_identifier_with_length (vendor_start, vendor_len);  
> > 
> > [[____::attry]] void f17y(); /* { dg-warning "ignored" } */
> > 
> > so i'd maybe put the
> > || !canonicalize_attr_name (vendor_start, vendor_len)
> > in the condition above?
> 
> Well no. Guess vendors and attribute just consisting of underscores
> will not be used that often anyway. I'd have required at least one
> alpha or at least alnum but whatever.
> thanks,

I see that -Wno-attributes=vendor::____ or -Wno-attributes=____::____
crashes, so I need to send yet another version to handle this.

*sigh*

Marek


^ permalink raw reply	[flat|nested] 28+ messages in thread

* [PATCH v8] attribs: Implement -Wno-attributes=vendor::attr [PR101940]
  2021-11-09 19:17                                 ` [PATCH v7] " Marek Polacek
  2021-11-09 19:47                                   ` Bernhard Reutner-Fischer
@ 2021-11-09 21:30                                   ` Marek Polacek
  2021-11-10  5:53                                     ` Jason Merrill
  1 sibling, 1 reply; 28+ messages in thread
From: Marek Polacek @ 2021-11-09 21:30 UTC (permalink / raw)
  To: Jason Merrill
  Cc: Bernhard Reutner-Fischer, Marek Polacek via Gcc-patches, Jakub Jelinek

On Tue, Nov 09, 2021 at 02:17:14PM -0500, Marek Polacek wrote:
> On Tue, Nov 09, 2021 at 12:27:28PM -0500, Jason Merrill wrote:
> > On 11/9/21 10:55, Marek Polacek wrote:
> > > On Tue, Nov 09, 2021 at 08:09:10AM +0100, Bernhard Reutner-Fischer wrote:
> > > > On Tue, 9 Nov 2021 00:12:10 -0500
> > > > Jason Merrill <jason@redhat.com> wrote:
> > > > 
> > > > > On 11/8/21 20:41, Marek Polacek wrote:
> > > > > > On Sat, Nov 06, 2021 at 03:29:57PM -0400, Jason Merrill wrote:
> > > > 
> > > > > > +  for (auto opt : v)
> > > > > > +    {
> > > > > > +      char *cln = strstr (opt, "::");
> > > > > > +      /* We don't accept '::attr'.  */
> > > > > > +      if (cln == nullptr || cln == opt)
> > > > > > +	{
> > > > > > +	  error ("wrong argument to ignored attributes");
> > > > > > +	  inform (input_location, "valid format is %<ns::attr%> or %<ns::%>");
> > > > > > +	  continue;
> > > > > > +	}
> > > > > > +      char *vendor_start = opt;
> > > > > > +      ptrdiff_t vendor_len = cln - opt;
> > > > > > +      char *attr_start = cln + 2;
> > > > > > +      /* This could really use rawmemchr :(.  */
> > > > > > +      ptrdiff_t attr_len = strchr (attr_start, '\0') - attr_start;
> > > > > > +      /* Verify that they look valid.  */
> > > > > > +      auto valid_p = [](const char *const s, ptrdiff_t len) {
> > > > > > +	for (int i = 0; i < len; ++i)
> > > > > > +	  if (!ISALNUM (*s) && *s != '_')
> > > > > > +	    return false;
> > > > > > +	return true;
> > > > > > +      };
> > > > > > +      if (!valid_p (vendor_start, vendor_len)
> > > > > > +	  || !valid_p (attr_start, attr_len))
> > > > > > +	{
> > > > > > +	  error ("wrong argument to ignored attributes");
> > > > > > +	  continue;
> > > > > > +	}
> > > > > > +      /* Turn "__attr__" into "attr" so that we have a canonical form of
> > > > > > +	 attribute names.  Likewise for vendor.  */
> > > > > > +      auto strip = [](char *&s, ptrdiff_t &l) {
> > > > > > +	if (l > 4 && s[0] == '_' && s[1] == '_'
> > > > > > +	    && s[l - 1] == '_' && s[l - 2] == '_')
> > > > > > +	  {
> > > > > > +	    s += 2;
> > > > > > +	    l -= 4;
> > > > > > +	  }
> > > > > > +      };
> > > > > > +      strip (attr_start, attr_len);
> > > > > > +      strip (vendor_start, vendor_len);
> > > > > > +      /* We perform all this hijinks so that we don't have to copy OPT.  */
> > > > > > +      tree vendor_id = get_identifier_with_length (vendor_start, vendor_len);
> > > > > > +      tree attr_id = get_identifier_with_length (attr_start, attr_len);
> > > > > > +      /* If we've already seen this vendor::attr, ignore it.  Attempting to
> > > > > > +	 register it twice would lead to a crash.  */
> > > > > > +      if (lookup_scoped_attribute_spec (vendor_id, attr_id))
> > > > > > +	continue;
> > > > > 
> > > > > Hmm, this looks like it isn't handling the case of previously ignoring
> > > > > vendor::; it seems we'll look for vendor::<empty string> instead, not
> > > > > find it, and register again.
> > 
> > > Yes, for -Wno-attributes=vendor::,vendor:: we call register_scoped_attributes
> > > twice, but I think that's OK: register_scoped_attributes will see that
> > > find_attribute_namespace finds the namespace and returns without
> > > creating a new  one.
> > > 
> > > I think the current code handles -Wno-attributes=vendor::a,vendor:: well so
> > > I'm not sure if I should change it.
> > 
> > Makes sense.  But we should be able to avoid calling
> > lookup_scoped_attribute_spec, and even get_identifier_with_length (attr...),
> > if attr_len is 0.
>  
> Duh, of course.  Also no need to canonicalize an empty string.
> 
> > > > I don't know if there are __attrib with 2 leading underscores but no
> > > > trailing that we accept and should normalize?
> > > > 
> > > > And it is surprising that we do not have a simple normalize_attr_name().
> > > > There must be existing spots where we would normalize attribute names?
> > > > extract_attribute_substring does about the same but with a struct substring(?).
> > > > Maybe that's just to avoid a normal string hash.
> > > 
> > > We have canonicalize_attr_name which I based my code on.
> > 
> > We could factor out of that function an overload equivalent to your strip
> > lambda?
> 
> OK.  Since it's taking a reference and I wanted it to work both with a size_t
> and ptrdiff_t, I made it a template.  Is is too much?

OK, this time for real.  Here's another version, which doesn't crash on
-Wno-attributes=c::____.  I apologize for the number of takes.  :-(

Bootstrap/regtest running on ppc64le-linux-gnu.  OK if it passes?

-- >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.
	(canonicalize_attr_name): New function template.
	(canonicalize_attr_name): Use it.
	* common.opt (Wattributes=): New option with a variable.
	* doc/extend.texi: Document #pragma GCC diagnostic ignored_attributes.
	* doc/invoke.texi: Document -Wno-attributes=.
	* opts.c (common_handle_option) <case OPT_Wattributes_>: Handle.
	* plugin.h (register_scoped_attributes): Adjust declaration.
	* toplev.c (compile_file): Call free_attr_data.

gcc/c-family/ChangeLog:

	* c-pragma.c (handle_pragma_diagnostic): Handle #pragma GCC diagnostic
	ignored_attributes.

gcc/testsuite/ChangeLog:

	* c-c++-common/Wno-attributes-1.c: New test.
	* c-c++-common/Wno-attributes-2.c: New test.
	* c-c++-common/Wno-attributes-3.c: New test.
---
 gcc/attribs.c                                 | 127 +++++++++++++++++-
 gcc/attribs.h                                 |  28 +++-
 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/testsuite/c-c++-common/Wno-attributes-3.c |   9 ++
 gcc/toplev.c                                  |   2 +
 12 files changed, 374 insertions(+), 12 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
 create mode 100644 gcc/testsuite/c-c++-common/Wno-attributes-3.c

diff --git a/gcc/attribs.c b/gcc/attribs.c
index 83fafc98b7d..0284e5bf2fd 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,99 @@ check_attribute_tables (void)
 				 attribute_tables[j][l].name));
 }
 
+/* Used to stash pointers to allocated memory so that we can free them at
+   the end of parsing of all TUs. */
+static vec<attribute_spec *> ignored_attributes_table;
+
+/* Parse arguments V of -Wno-attributes=.
+   Currently we accept:
+     vendor::attr
+     vendor::
+   This functions also registers the parsed attributes so that we don't
+   warn that we don't recognize them.  */
+
+void
+handle_ignored_attributes_option (vec<char *> *v)
+{
+  if (v == nullptr)
+    return;
+
+  for (auto opt : v)
+    {
+      char *cln = strstr (opt, "::");
+      /* We don't accept '::attr'.  */
+      if (cln == nullptr || cln == opt)
+	{
+	  error ("wrong argument to ignored attributes");
+	  inform (input_location, "valid format is %<ns::attr%> or %<ns::%>");
+	  continue;
+	}
+      const char *vendor_start = opt;
+      ptrdiff_t vendor_len = cln - opt;
+      const char *attr_start = cln + 2;
+      /* This could really use rawmemchr :(.  */
+      ptrdiff_t attr_len = strchr (attr_start, '\0') - attr_start;
+      /* Verify that they look valid.  */
+      auto valid_p = [](const char *const s, ptrdiff_t len) {
+	bool ok = false;
+
+	for (int i = 0; i < len; ++i)
+	  if (ISALNUM (s[i]))
+	    ok = true;
+	  else if (s[i] != '_')
+	    return false;
+
+	return ok;
+      };
+      if (!valid_p (vendor_start, vendor_len))
+	{
+	  error ("wrong argument to ignored attributes");
+	  continue;
+	}
+      canonicalize_attr_name (vendor_start, vendor_len);
+      /* We perform all this hijinks so that we don't have to copy OPT.  */
+      tree vendor_id = get_identifier_with_length (vendor_start, vendor_len);
+      const char *attr;
+      /* In the "vendor::" case, we should ignore *any* attribute coming
+	 from this attribute namespace.  */
+      if (attr_len > 0)
+	{
+	  if (!valid_p (attr_start, attr_len))
+	    {
+	      error ("wrong argument to ignored attributes");
+	      continue;
+	    }
+	  canonicalize_attr_name (attr_start, attr_len);
+	  tree attr_id = get_identifier_with_length (attr_start, attr_len);
+	  attr = IDENTIFIER_POINTER (attr_id);
+	  /* If we've already seen this vendor::attr, ignore it.  Attempting to
+	     register it twice would lead to a crash.  */
+	  if (lookup_scoped_attribute_spec (vendor_id, attr_id))
+	    continue;
+	}
+      else
+	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, IDENTIFIER_POINTER (vendor_id), !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 +354,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 +561,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 +674,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..ba657881940 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.
@@ -114,17 +117,34 @@ extern unsigned decls_mismatched_attributes (tree, tree, tree,
 
 extern void maybe_diag_alias_attributes (tree, tree);
 
+/* For a given string S of length L, strip leading and trailing '_' characters
+   so that we have a canonical form of attribute names.  NB: This function may
+   change S and L.  */
+
+template <typename T>
+inline bool
+canonicalize_attr_name (const char *&s, T &l)
+{
+  if (l > 4 && s[0] == '_' && s[1] == '_' && s[l - 1] == '_' && s[l - 2] == '_')
+    {
+      s += 2;
+      l -= 4;
+      return true;
+    }
+  return false;
+}
+
 /* For a given IDENTIFIER_NODE, strip leading and trailing '_' characters
    so that we have a canonical form of attribute names.  */
 
 static inline tree
 canonicalize_attr_name (tree attr_name)
 {
-  const size_t l = IDENTIFIER_LENGTH (attr_name);
+  size_t l = IDENTIFIER_LENGTH (attr_name);
   const char *s = IDENTIFIER_POINTER (attr_name);
 
-  if (l > 4 && s[0] == '_' && s[1] == '_' && s[l - 1] == '_' && s[l - 2] == '_')
-    return get_identifier_with_length (s + 2, l - 4);
+  if (canonicalize_attr_name (s, l))
+    return get_identifier_with_length (s, l);
 
   return attr_name;
 }
diff --git a/gcc/c-family/c-pragma.c b/gcc/c-family/c-pragma.c
index a9be8df0384..a299ceff6a2 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);
+      free (args);
+      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 1a5b9bfcca9..de9b848eda5 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 eee4c6737bb..6e6c580e329 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -23767,6 +23767,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 2ea23d07c4c..297ca98deae 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -8707,6 +8707,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 caed6255500..175b4635bb4 100644
--- a/gcc/opts.c
+++ b/gcc/opts.c
@@ -2611,6 +2611,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/testsuite/c-c++-common/Wno-attributes-3.c b/gcc/testsuite/c-c++-common/Wno-attributes-3.c
new file mode 100644
index 00000000000..64370f2ef6f
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/Wno-attributes-3.c
@@ -0,0 +1,9 @@
+/* PR c++/101940 */
+/* { dg-do compile } */
+/* { dg-additional-options "-Wno-attributes=___::" } */
+/* { dg-additional-options "-Wno-attributes=c::____" } */
+/* { dg-additional-options "-Wno-attributes=____::____" } */
+/* { dg-additional-options "-Wno-attributes=c@::attr" } */
+/* { dg-additional-options "-Wno-attributes=c2::@tr" } */
+
+/* { dg-error "wrong argument to ignored attributes" "" { target *-*-* } 0 } */
diff --git a/gcc/toplev.c b/gcc/toplev.c
index e91f083f8ff..99276bde87d 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -457,6 +457,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: 8875a92d31329ae52b734683784c4b054839a661
-- 
2.33.1


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: [PATCH v8] attribs: Implement -Wno-attributes=vendor::attr [PR101940]
  2021-11-09 21:30                                   ` [PATCH v8] " Marek Polacek
@ 2021-11-10  5:53                                     ` Jason Merrill
  0 siblings, 0 replies; 28+ messages in thread
From: Jason Merrill @ 2021-11-10  5:53 UTC (permalink / raw)
  To: Marek Polacek
  Cc: Bernhard Reutner-Fischer, Marek Polacek via Gcc-patches, Jakub Jelinek

On 11/9/21 16:30, Marek Polacek wrote:
> On Tue, Nov 09, 2021 at 02:17:14PM -0500, Marek Polacek wrote:
>> On Tue, Nov 09, 2021 at 12:27:28PM -0500, Jason Merrill wrote:
>>> On 11/9/21 10:55, Marek Polacek wrote:
>>>> On Tue, Nov 09, 2021 at 08:09:10AM +0100, Bernhard Reutner-Fischer wrote:
>>>>> On Tue, 9 Nov 2021 00:12:10 -0500
>>>>> Jason Merrill <jason@redhat.com> wrote:
>>>>>
>>>>>> On 11/8/21 20:41, Marek Polacek wrote:
>>>>>>> On Sat, Nov 06, 2021 at 03:29:57PM -0400, Jason Merrill wrote:
>>>>>
>>>>>>> +  for (auto opt : v)
>>>>>>> +    {
>>>>>>> +      char *cln = strstr (opt, "::");
>>>>>>> +      /* We don't accept '::attr'.  */
>>>>>>> +      if (cln == nullptr || cln == opt)
>>>>>>> +	{
>>>>>>> +	  error ("wrong argument to ignored attributes");
>>>>>>> +	  inform (input_location, "valid format is %<ns::attr%> or %<ns::%>");
>>>>>>> +	  continue;
>>>>>>> +	}
>>>>>>> +      char *vendor_start = opt;
>>>>>>> +      ptrdiff_t vendor_len = cln - opt;
>>>>>>> +      char *attr_start = cln + 2;
>>>>>>> +      /* This could really use rawmemchr :(.  */
>>>>>>> +      ptrdiff_t attr_len = strchr (attr_start, '\0') - attr_start;
>>>>>>> +      /* Verify that they look valid.  */
>>>>>>> +      auto valid_p = [](const char *const s, ptrdiff_t len) {
>>>>>>> +	for (int i = 0; i < len; ++i)
>>>>>>> +	  if (!ISALNUM (*s) && *s != '_')
>>>>>>> +	    return false;
>>>>>>> +	return true;
>>>>>>> +      };
>>>>>>> +      if (!valid_p (vendor_start, vendor_len)
>>>>>>> +	  || !valid_p (attr_start, attr_len))
>>>>>>> +	{
>>>>>>> +	  error ("wrong argument to ignored attributes");
>>>>>>> +	  continue;
>>>>>>> +	}
>>>>>>> +      /* Turn "__attr__" into "attr" so that we have a canonical form of
>>>>>>> +	 attribute names.  Likewise for vendor.  */
>>>>>>> +      auto strip = [](char *&s, ptrdiff_t &l) {
>>>>>>> +	if (l > 4 && s[0] == '_' && s[1] == '_'
>>>>>>> +	    && s[l - 1] == '_' && s[l - 2] == '_')
>>>>>>> +	  {
>>>>>>> +	    s += 2;
>>>>>>> +	    l -= 4;
>>>>>>> +	  }
>>>>>>> +      };
>>>>>>> +      strip (attr_start, attr_len);
>>>>>>> +      strip (vendor_start, vendor_len);
>>>>>>> +      /* We perform all this hijinks so that we don't have to copy OPT.  */
>>>>>>> +      tree vendor_id = get_identifier_with_length (vendor_start, vendor_len);
>>>>>>> +      tree attr_id = get_identifier_with_length (attr_start, attr_len);
>>>>>>> +      /* If we've already seen this vendor::attr, ignore it.  Attempting to
>>>>>>> +	 register it twice would lead to a crash.  */
>>>>>>> +      if (lookup_scoped_attribute_spec (vendor_id, attr_id))
>>>>>>> +	continue;
>>>>>>
>>>>>> Hmm, this looks like it isn't handling the case of previously ignoring
>>>>>> vendor::; it seems we'll look for vendor::<empty string> instead, not
>>>>>> find it, and register again.
>>>
>>>> Yes, for -Wno-attributes=vendor::,vendor:: we call register_scoped_attributes
>>>> twice, but I think that's OK: register_scoped_attributes will see that
>>>> find_attribute_namespace finds the namespace and returns without
>>>> creating a new  one.
>>>>
>>>> I think the current code handles -Wno-attributes=vendor::a,vendor:: well so
>>>> I'm not sure if I should change it.
>>>
>>> Makes sense.  But we should be able to avoid calling
>>> lookup_scoped_attribute_spec, and even get_identifier_with_length (attr...),
>>> if attr_len is 0.
>>   
>> Duh, of course.  Also no need to canonicalize an empty string.
>>
>>>>> I don't know if there are __attrib with 2 leading underscores but no
>>>>> trailing that we accept and should normalize?
>>>>>
>>>>> And it is surprising that we do not have a simple normalize_attr_name().
>>>>> There must be existing spots where we would normalize attribute names?
>>>>> extract_attribute_substring does about the same but with a struct substring(?).
>>>>> Maybe that's just to avoid a normal string hash.
>>>>
>>>> We have canonicalize_attr_name which I based my code on.
>>>
>>> We could factor out of that function an overload equivalent to your strip
>>> lambda?
>>
>> OK.  Since it's taking a reference and I wanted it to work both with a size_t
>> and ptrdiff_t, I made it a template.  Is is too much?
> 
> OK, this time for real.  Here's another version, which doesn't crash on
> -Wno-attributes=c::____.  I apologize for the number of takes.  :-(
> 
> Bootstrap/regtest running on ppc64le-linux-gnu.  OK if it passes?

OK, thanks for your persistence.  :)

> -- >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.
> 	(canonicalize_attr_name): New function template.
> 	(canonicalize_attr_name): Use it.
> 	* common.opt (Wattributes=): New option with a variable.
> 	* doc/extend.texi: Document #pragma GCC diagnostic ignored_attributes.
> 	* doc/invoke.texi: Document -Wno-attributes=.
> 	* opts.c (common_handle_option) <case OPT_Wattributes_>: Handle.
> 	* plugin.h (register_scoped_attributes): Adjust declaration.
> 	* toplev.c (compile_file): Call free_attr_data.
> 
> gcc/c-family/ChangeLog:
> 
> 	* c-pragma.c (handle_pragma_diagnostic): Handle #pragma GCC diagnostic
> 	ignored_attributes.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* c-c++-common/Wno-attributes-1.c: New test.
> 	* c-c++-common/Wno-attributes-2.c: New test.
> 	* c-c++-common/Wno-attributes-3.c: New test.
> ---
>   gcc/attribs.c                                 | 127 +++++++++++++++++-
>   gcc/attribs.h                                 |  28 +++-
>   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/testsuite/c-c++-common/Wno-attributes-3.c |   9 ++
>   gcc/toplev.c                                  |   2 +
>   12 files changed, 374 insertions(+), 12 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
>   create mode 100644 gcc/testsuite/c-c++-common/Wno-attributes-3.c
> 
> diff --git a/gcc/attribs.c b/gcc/attribs.c
> index 83fafc98b7d..0284e5bf2fd 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,99 @@ check_attribute_tables (void)
>   				 attribute_tables[j][l].name));
>   }
>   
> +/* Used to stash pointers to allocated memory so that we can free them at
> +   the end of parsing of all TUs. */
> +static vec<attribute_spec *> ignored_attributes_table;
> +
> +/* Parse arguments V of -Wno-attributes=.
> +   Currently we accept:
> +     vendor::attr
> +     vendor::
> +   This functions also registers the parsed attributes so that we don't
> +   warn that we don't recognize them.  */
> +
> +void
> +handle_ignored_attributes_option (vec<char *> *v)
> +{
> +  if (v == nullptr)
> +    return;
> +
> +  for (auto opt : v)
> +    {
> +      char *cln = strstr (opt, "::");
> +      /* We don't accept '::attr'.  */
> +      if (cln == nullptr || cln == opt)
> +	{
> +	  error ("wrong argument to ignored attributes");
> +	  inform (input_location, "valid format is %<ns::attr%> or %<ns::%>");
> +	  continue;
> +	}
> +      const char *vendor_start = opt;
> +      ptrdiff_t vendor_len = cln - opt;
> +      const char *attr_start = cln + 2;
> +      /* This could really use rawmemchr :(.  */
> +      ptrdiff_t attr_len = strchr (attr_start, '\0') - attr_start;
> +      /* Verify that they look valid.  */
> +      auto valid_p = [](const char *const s, ptrdiff_t len) {
> +	bool ok = false;
> +
> +	for (int i = 0; i < len; ++i)
> +	  if (ISALNUM (s[i]))
> +	    ok = true;
> +	  else if (s[i] != '_')
> +	    return false;
> +
> +	return ok;
> +      };
> +      if (!valid_p (vendor_start, vendor_len))
> +	{
> +	  error ("wrong argument to ignored attributes");
> +	  continue;
> +	}
> +      canonicalize_attr_name (vendor_start, vendor_len);
> +      /* We perform all this hijinks so that we don't have to copy OPT.  */
> +      tree vendor_id = get_identifier_with_length (vendor_start, vendor_len);
> +      const char *attr;
> +      /* In the "vendor::" case, we should ignore *any* attribute coming
> +	 from this attribute namespace.  */
> +      if (attr_len > 0)
> +	{
> +	  if (!valid_p (attr_start, attr_len))
> +	    {
> +	      error ("wrong argument to ignored attributes");
> +	      continue;
> +	    }
> +	  canonicalize_attr_name (attr_start, attr_len);
> +	  tree attr_id = get_identifier_with_length (attr_start, attr_len);
> +	  attr = IDENTIFIER_POINTER (attr_id);
> +	  /* If we've already seen this vendor::attr, ignore it.  Attempting to
> +	     register it twice would lead to a crash.  */
> +	  if (lookup_scoped_attribute_spec (vendor_id, attr_id))
> +	    continue;
> +	}
> +      else
> +	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, IDENTIFIER_POINTER (vendor_id), !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 +354,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 +561,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 +674,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..ba657881940 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.
> @@ -114,17 +117,34 @@ extern unsigned decls_mismatched_attributes (tree, tree, tree,
>   
>   extern void maybe_diag_alias_attributes (tree, tree);
>   
> +/* For a given string S of length L, strip leading and trailing '_' characters
> +   so that we have a canonical form of attribute names.  NB: This function may
> +   change S and L.  */
> +
> +template <typename T>
> +inline bool
> +canonicalize_attr_name (const char *&s, T &l)
> +{
> +  if (l > 4 && s[0] == '_' && s[1] == '_' && s[l - 1] == '_' && s[l - 2] == '_')
> +    {
> +      s += 2;
> +      l -= 4;
> +      return true;
> +    }
> +  return false;
> +}
> +
>   /* For a given IDENTIFIER_NODE, strip leading and trailing '_' characters
>      so that we have a canonical form of attribute names.  */
>   
>   static inline tree
>   canonicalize_attr_name (tree attr_name)
>   {
> -  const size_t l = IDENTIFIER_LENGTH (attr_name);
> +  size_t l = IDENTIFIER_LENGTH (attr_name);
>     const char *s = IDENTIFIER_POINTER (attr_name);
>   
> -  if (l > 4 && s[0] == '_' && s[1] == '_' && s[l - 1] == '_' && s[l - 2] == '_')
> -    return get_identifier_with_length (s + 2, l - 4);
> +  if (canonicalize_attr_name (s, l))
> +    return get_identifier_with_length (s, l);
>   
>     return attr_name;
>   }
> diff --git a/gcc/c-family/c-pragma.c b/gcc/c-family/c-pragma.c
> index a9be8df0384..a299ceff6a2 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);
> +      free (args);
> +      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 1a5b9bfcca9..de9b848eda5 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 eee4c6737bb..6e6c580e329 100644
> --- a/gcc/doc/extend.texi
> +++ b/gcc/doc/extend.texi
> @@ -23767,6 +23767,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 2ea23d07c4c..297ca98deae 100644
> --- a/gcc/doc/invoke.texi
> +++ b/gcc/doc/invoke.texi
> @@ -8707,6 +8707,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 caed6255500..175b4635bb4 100644
> --- a/gcc/opts.c
> +++ b/gcc/opts.c
> @@ -2611,6 +2611,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/testsuite/c-c++-common/Wno-attributes-3.c b/gcc/testsuite/c-c++-common/Wno-attributes-3.c
> new file mode 100644
> index 00000000000..64370f2ef6f
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/Wno-attributes-3.c
> @@ -0,0 +1,9 @@
> +/* PR c++/101940 */
> +/* { dg-do compile } */
> +/* { dg-additional-options "-Wno-attributes=___::" } */
> +/* { dg-additional-options "-Wno-attributes=c::____" } */
> +/* { dg-additional-options "-Wno-attributes=____::____" } */
> +/* { dg-additional-options "-Wno-attributes=c@::attr" } */
> +/* { dg-additional-options "-Wno-attributes=c2::@tr" } */
> +
> +/* { dg-error "wrong argument to ignored attributes" "" { target *-*-* } 0 } */
> diff --git a/gcc/toplev.c b/gcc/toplev.c
> index e91f083f8ff..99276bde87d 100644
> --- a/gcc/toplev.c
> +++ b/gcc/toplev.c
> @@ -457,6 +457,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: 8875a92d31329ae52b734683784c4b054839a661
> 


^ permalink raw reply	[flat|nested] 28+ messages in thread

end of thread, other threads:[~2021-11-10  5:53 UTC | newest]

Thread overview: 28+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-09-20 17:06 [PATCH] attribs: Implement -Wno-attributes=vendor::attr [PR101940] Marek Polacek
2021-09-20 17:38 ` Jakub Jelinek
2021-09-20 18:37   ` Marek Polacek
2021-09-20 19:03     ` [PATCH v2] " Marek Polacek
2021-09-20 19:08     ` [PATCH] " Jakub Jelinek
2021-09-20 22:59       ` [PATCH v3] " Marek Polacek
2021-09-23 18:25         ` Jason Merrill
2021-09-28 20:20           ` [PATCH v4] " Marek Polacek
2021-10-11 15:17             ` Marek Polacek
2021-10-29 16:47               ` Marek Polacek
2021-11-05 18:48             ` Jason Merrill
2021-11-06  0:21               ` [PATCH v5] " Marek Polacek
2021-11-06  1:32                 ` Bernhard Reutner-Fischer
2021-11-06 18:28                   ` Marek Polacek
2021-11-06 19:29                     ` Jason Merrill
2021-11-06 20:29                       ` Bernhard Reutner-Fischer
2021-11-09  1:41                       ` [PATCH v6] " Marek Polacek
2021-11-09  5:12                         ` Jason Merrill
2021-11-09  7:09                           ` Bernhard Reutner-Fischer
2021-11-09 15:55                             ` Marek Polacek
2021-11-09 17:27                               ` Jason Merrill
2021-11-09 19:17                                 ` [PATCH v7] " Marek Polacek
2021-11-09 19:47                                   ` Bernhard Reutner-Fischer
2021-11-09 19:57                                     ` Bernhard Reutner-Fischer
2021-11-09 20:23                                       ` Marek Polacek
2021-11-09 21:30                                   ` [PATCH v8] " Marek Polacek
2021-11-10  5:53                                     ` Jason Merrill
2021-11-09 15:51                           ` [PATCH v6] " Marek Polacek

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).