public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH][RFC] Canonize names of attributes.
@ 2017-06-13 12:32 Martin Liška
  2017-06-13 13:20 ` Richard Biener
  2017-06-14 17:24 ` Jason Merrill
  0 siblings, 2 replies; 37+ messages in thread
From: Martin Liška @ 2017-06-13 12:32 UTC (permalink / raw)
  To: gcc-patches; +Cc: Richard Biener

[-- Attachment #1: Type: text/plain, Size: 2335 bytes --]

Hello.

After some discussions with Richi, I would like to propose patch that will
come up with a canonical name of attribute names. That means __attribute__((__abi_tag__))
will be given 'abi_tag' as IDENTIFIER_NAME of the attribute. The change can improve
attribute name lookup and we can delete all the ugly code that compares strlen(i1)
== strlen(i2) + 4, etc.

Patch can bootstrap on ppc64le-redhat-linux and survives regression tests (w/ default
languages). I'm currently testing objc, obj-c++ and go.

Ready to be installed?
Martin


gcc/cp/ChangeLog:

2017-06-09  Martin Liska  <mliska@suse.cz>

	* parser.c (cp_parser_gnu_attribute_list): Canonize attribute
	names.
	(cp_parser_std_attribute): Likewise.

gcc/go/ChangeLog:

2017-06-09  Martin Liska  <mliska@suse.cz>

	* go-gcc.cc (Gcc_backend::function): Use no_split_stack
	instead of __no_split_stack__.

gcc/c/ChangeLog:

2017-06-09  Martin Liska  <mliska@suse.cz>

	* c-parser.c (c_parser_attributes): Canonize attribute names.

gcc/c-family/ChangeLog:

2017-06-09  Martin Liska  <mliska@suse.cz>

	* c-format.c (cmp_attribs): Simplify comparison of attributes.
	* c-lex.c (c_common_has_attribute): Canonize attribute names.

gcc/ChangeLog:

2017-06-09  Martin Liska  <mliska@suse.cz>

	* tree.c (cmp_attrib_identifiers): Simplify comparison of attributes.
	(private_is_attribute_p): Likewise.
	(private_lookup_attribute): Likewise.
	(private_lookup_attribute_by_prefix): Likewise.
	(remove_attribute): Likewise.
	(canonize_attr_name): New function.
	* tree.h: Declared here.

gcc/testsuite/ChangeLog:

2017-06-09  Martin Liska  <mliska@suse.cz>

	* g++.dg/cpp0x/pr65558.C: Change expected warning.
	* gcc.dg/parm-impl-decl-1.c: Likewise.
	* gcc.dg/parm-impl-decl-3.c: Likewise.
---
 gcc/c-family/c-format.c                 |  13 ++--
 gcc/c-family/c-lex.c                    |   1 +
 gcc/c/c-parser.c                        |   9 +++
 gcc/cp/parser.c                         |  11 +++-
 gcc/go/go-gcc.cc                        |   2 +-
 gcc/testsuite/g++.dg/cpp0x/pr65558.C    |   2 +-
 gcc/testsuite/gcc.dg/parm-impl-decl-1.c |   2 +-
 gcc/testsuite/gcc.dg/parm-impl-decl-3.c |   2 +-
 gcc/tree.c                              | 108 +++++++++++---------------------
 gcc/tree.h                              |   4 ++
 10 files changed, 69 insertions(+), 85 deletions(-)



[-- Attachment #2: 0001-Canonize-names-of-attributes.patch --]
[-- Type: text/x-patch, Size: 12371 bytes --]

diff --git a/gcc/c-family/c-format.c b/gcc/c-family/c-format.c
index 732339b9b5e..30f60d42cca 100644
--- a/gcc/c-family/c-format.c
+++ b/gcc/c-family/c-format.c
@@ -3982,15 +3982,10 @@ cmp_attribs (const char *tattr_name, const char *attr_name)
 {
   int alen = strlen (attr_name);
   int slen = (tattr_name ? strlen (tattr_name) : 0);
-  if (alen > 4 && attr_name[0] == '_' && attr_name[1] == '_'
-      && attr_name[alen - 1] == '_' && attr_name[alen - 2] == '_')
-    {
-      attr_name += 2;
-      alen -= 4;
-    }
-  if (alen != slen || strncmp (tattr_name, attr_name, alen) != 0)
-    return false;
-  return true;
+  gcc_checking_assert (alen == 0 || attr_name[0] != '_');
+  gcc_checking_assert (slen == 0 || tattr_name[0] != '_');
+
+  return (alen == slen && strncmp (tattr_name, attr_name, alen) == 0);
 }
 
 /* Handle a "format" attribute; arguments as in
diff --git a/gcc/c-family/c-lex.c b/gcc/c-family/c-lex.c
index e1c8bdff986..6d0e9279ed6 100644
--- a/gcc/c-family/c-lex.c
+++ b/gcc/c-family/c-lex.c
@@ -316,6 +316,7 @@ c_common_has_attribute (cpp_reader *pfile)
     {
       attr_name = get_identifier ((const char *)
 				  cpp_token_as_text (pfile, token));
+      attr_name = canonize_attr_name (attr_name);
       if (c_dialect_cxx ())
 	{
 	  int idx = 0;
diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
index 6f954f21fa2..400b65380e2 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -4168,9 +4168,11 @@ c_parser_attributes (c_parser *parser)
 	  attr_name = c_parser_attribute_any_word (parser);
 	  if (attr_name == NULL)
 	    break;
+	  attr_name = canonize_attr_name (attr_name);
 	  if (is_cilkplus_vector_p (attr_name))
 	    {
 	      c_token *v_token = c_parser_peek_token (parser);
+	      v_token->value = canonize_attr_name (v_token->value);
 	      c_parser_cilk_simd_fn_vector_attrs (parser, *v_token);
 	      /* If the next token isn't a comma, we're done.  */
 	      if (!c_parser_next_token_is (parser, CPP_COMMA))
@@ -4234,6 +4236,13 @@ c_parser_attributes (c_parser *parser)
 		  release_tree_vector (expr_list);
 		}
 	    }
+
+	  if (attr_args
+	      && TREE_VALUE (attr_args)
+	      && TREE_CODE (TREE_VALUE (attr_args)) == IDENTIFIER_NODE)
+	    TREE_VALUE (attr_args)
+	      = canonize_attr_name (TREE_VALUE (attr_args));
+
 	  attr = build_tree_list (attr_name, attr_args);
 	  if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
 	    c_parser_consume_token (parser);
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index d02ad360d16..ea6b9a61390 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -24612,7 +24612,8 @@ cp_parser_gnu_attribute_list (cp_parser* parser)
 	       parsed identifier.  */
 	    ? ridpointers[(int) token->keyword]
 	    : id_token->u.value;
-	  
+
+	  identifier = canonize_attr_name (identifier);
 	  attribute = build_tree_list (identifier, NULL_TREE);
 
 	  /* Peek at the next token.  */
@@ -24638,6 +24639,11 @@ cp_parser_gnu_attribute_list (cp_parser* parser)
 	      else
 		{
 		  arguments = build_tree_list_vec (vec);
+		  tree tv;
+		  if (arguments != NULL_TREE
+		      && ((tv = TREE_VALUE (arguments)) != NULL_TREE)
+		      && TREE_CODE (tv) == IDENTIFIER_NODE)
+		      TREE_VALUE (arguments) = canonize_attr_name (tv);
 		  release_tree_vector (vec);
 		}
 	      /* Save the arguments away.  */
@@ -24758,6 +24764,8 @@ cp_parser_std_attribute (cp_parser *parser, tree attr_ns)
 		    "expected an identifier for the attribute name");
 	  return error_mark_node;
 	}
+
+      attr_id = canonize_attr_name (attr_id);
       attribute = build_tree_list (build_tree_list (attr_ns, attr_id),
 				   NULL_TREE);
       token = cp_lexer_peek_token (parser->lexer);
@@ -24767,6 +24775,7 @@ cp_parser_std_attribute (cp_parser *parser, tree attr_ns)
 				 NULL_TREE);
   else
     {
+      attr_id = canonize_attr_name (attr_id);
       attribute = build_tree_list (build_tree_list (NULL_TREE, attr_id),
 				   NULL_TREE);
       /* C++11 noreturn attribute is equivalent to GNU's.  */
diff --git a/gcc/go/go-gcc.cc b/gcc/go/go-gcc.cc
index a7977fe03c1..04912f0ed01 100644
--- a/gcc/go/go-gcc.cc
+++ b/gcc/go/go-gcc.cc
@@ -3046,7 +3046,7 @@ Gcc_backend::function(Btype* fntype, const std::string& name,
     DECL_UNINLINABLE(decl) = 1;
   if (disable_split_stack)
     {
-      tree attr = get_identifier("__no_split_stack__");
+      tree attr = get_identifier ("no_split_stack");
       DECL_ATTRIBUTES(decl) = tree_cons(attr, NULL_TREE, NULL_TREE);
     }
   if (in_unique_section)
diff --git a/gcc/testsuite/g++.dg/cpp0x/pr65558.C b/gcc/testsuite/g++.dg/cpp0x/pr65558.C
index d294c95a657..12946b35eda 100644
--- a/gcc/testsuite/g++.dg/cpp0x/pr65558.C
+++ b/gcc/testsuite/g++.dg/cpp0x/pr65558.C
@@ -2,6 +2,6 @@
 // { dg-do compile { target c++11 } }
 
 inline namespace
-__attribute__((__abi_tag__)) // { dg-warning "ignoring .__abi_tag__. attribute on anonymous namespace" }
+__attribute__((__abi_tag__)) // { dg-warning "ignoring .abi_tag. attribute on anonymous namespace" }
 {
 }
diff --git a/gcc/testsuite/gcc.dg/parm-impl-decl-1.c b/gcc/testsuite/gcc.dg/parm-impl-decl-1.c
index 5c7ddb0a259..c1219273c75 100644
--- a/gcc/testsuite/gcc.dg/parm-impl-decl-1.c
+++ b/gcc/testsuite/gcc.dg/parm-impl-decl-1.c
@@ -7,7 +7,7 @@
 /* Implicit function declaration in attribute in definition (testcase
    from bug).  */
 int
-foo (int __attribute__ ((__mode__ (vector_size(8)))) i) /* { dg-warning "'__mode__' attribute ignored" } */
+foo (int __attribute__ ((__mode__ (vector_size(8)))) i) /* { dg-warning "'mode' attribute ignored" } */
 {
   return (long long) i;
 }
diff --git a/gcc/testsuite/gcc.dg/parm-impl-decl-3.c b/gcc/testsuite/gcc.dg/parm-impl-decl-3.c
index 904295258d7..20197b52402 100644
--- a/gcc/testsuite/gcc.dg/parm-impl-decl-3.c
+++ b/gcc/testsuite/gcc.dg/parm-impl-decl-3.c
@@ -4,7 +4,7 @@
 /* { dg-options "-g -std=gnu89" } */
 
 int
-foo (int __attribute__ ((__mode__ (vector_size(8)))) i) /* { dg-warning "'__mode__' attribute ignored" } */
+foo (int __attribute__ ((__mode__ (vector_size(8)))) i) /* { dg-warning "'mode' attribute ignored" } */
 {
   return (long long) i;
 }
diff --git a/gcc/tree.c b/gcc/tree.c
index 260280317bc..542fe0fa9bc 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -4943,34 +4943,16 @@ cmp_attrib_identifiers (const_tree attr1, const_tree attr2)
   if (attr1 == attr2)
     return true;
 
-  /* If they are not equal, they may still be one in the form
-     'text' while the other one is in the form '__text__'.  TODO:
-     If we were storing attributes in normalized 'text' form, then
-     this could all go away and we could take full advantage of
-     the fact that we're comparing identifiers. :-)  */
   const size_t attr1_len = IDENTIFIER_LENGTH (attr1);
   const size_t attr2_len = IDENTIFIER_LENGTH (attr2);
 
-  if (attr2_len == attr1_len + 4)
-    {
-      const char *p = IDENTIFIER_POINTER (attr2);
-      const char *q = IDENTIFIER_POINTER (attr1);
-      if (p[0] == '_' && p[1] == '_'
-	  && p[attr2_len - 2] == '_' && p[attr2_len - 1] == '_'
-	  && strncmp (q, p + 2, attr1_len) == 0)
-	return true;;
-    }
-  else if (attr2_len + 4 == attr1_len)
-    {
-      const char *p = IDENTIFIER_POINTER (attr2);
-      const char *q = IDENTIFIER_POINTER (attr1);
-      if (q[0] == '_' && q[1] == '_'
-	  && q[attr1_len - 2] == '_' && q[attr1_len - 1] == '_'
-	  && strncmp (q + 2, p, attr2_len) == 0)
-	return true;
-    }
+  if (attr1_len != attr2_len)
+    return false;
+  gcc_checking_assert (IDENTIFIER_POINTER (attr1)[0] != '_');
+  gcc_checking_assert (IDENTIFIER_POINTER (attr2)[0] != '_');
 
-  return false;
+  return strncmp (IDENTIFIER_POINTER (attr1), IDENTIFIER_POINTER (attr2),
+		  attr1_len) == 0;
 }
 
 /* Compare two attributes for their value identity.  Return true if the
@@ -6047,24 +6029,9 @@ bool
 private_is_attribute_p (const char *attr_name, size_t attr_len, const_tree ident)
 {
   size_t ident_len = IDENTIFIER_LENGTH (ident);
+  gcc_checking_assert (ident_len == 0 || IDENTIFIER_POINTER (ident)[0] != '_');
 
-  if (ident_len == attr_len)
-    {
-      if (id_equal (ident, attr_name))
-	return true;
-    }
-  else if (ident_len == attr_len + 4)
-    {
-      /* There is the possibility that ATTR is 'text' and IDENT is
-	 '__text__'.  */
-      const char *p = IDENTIFIER_POINTER (ident);      
-      if (p[0] == '_' && p[1] == '_'
-	  && p[ident_len - 2] == '_' && p[ident_len - 1] == '_'
-	  && strncmp (attr_name, p + 2, attr_len) == 0)
-	return true;
-    }
-
-  return false;
+  return ident_len == attr_len && id_equal (ident, attr_name);
 }
 
 /* The backbone of lookup_attribute().  ATTR_LEN is the string length
@@ -6074,25 +6041,13 @@ private_lookup_attribute (const char *attr_name, size_t attr_len, tree list)
 {
   while (list)
     {
-      size_t ident_len = IDENTIFIER_LENGTH (get_attribute_name (list));
-
-      if (ident_len == attr_len)
-	{
-	  if (!strcmp (attr_name,
-		       IDENTIFIER_POINTER (get_attribute_name (list))))
+      tree attr = get_attribute_name (list);
+      size_t ident_len = IDENTIFIER_LENGTH (attr);
+      gcc_checking_assert (ident_len == 0
+			   || IDENTIFIER_POINTER (attr)[0] != '_');
+      if (ident_len == attr_len
+	  && strcmp (attr_name, IDENTIFIER_POINTER (attr)) == 0)
 	    break;
-	}
-      /* TODO: If we made sure that attributes were stored in the
-	 canonical form without '__...__' (ie, as in 'text' as opposed
-	 to '__text__') then we could avoid the following case.  */
-      else if (ident_len == attr_len + 4)
-	{
-	  const char *p = IDENTIFIER_POINTER (get_attribute_name (list));
-	  if (p[0] == '_' && p[1] == '_'
-	      && p[ident_len - 2] == '_' && p[ident_len - 1] == '_'
-	      && strncmp (attr_name, p + 2, attr_len) == 0)
-	    break;
-	}
       list = TREE_CHAIN (list);
     }
 
@@ -6119,17 +6074,11 @@ private_lookup_attribute_by_prefix (const char *attr_name, size_t attr_len,
 	}
 
       const char *p = IDENTIFIER_POINTER (get_attribute_name (list));
+      gcc_checking_assert (attr_len == 0 || p[0] != '_');
 
       if (strncmp (attr_name, p, attr_len) == 0)
 	break;
 
-      /* TODO: If we made sure that attributes were stored in the
-	 canonical form without '__...__' (ie, as in 'text' as opposed
-	 to '__text__') then we could avoid the following case.  */
-      if (p[0] == '_' && p[1] == '_' &&
-	  strncmp (attr_name, p + 2, attr_len) == 0)
-	break;
-
       list = TREE_CHAIN (list);
     }
 
@@ -6175,16 +6124,16 @@ tree
 remove_attribute (const char *attr_name, tree list)
 {
   tree *p;
-  size_t attr_len = strlen (attr_name);
-
   gcc_checking_assert (attr_name[0] != '_');
 
   for (p = &list; *p; )
     {
       tree l = *p;
-      /* TODO: If we were storing attributes in normalized form, here
-	 we could use a simple strcmp().  */
-      if (private_is_attribute_p (attr_name, attr_len, get_attribute_name (l)))
+
+      tree attr = get_attribute_name (l);
+      gcc_checking_assert (IDENTIFIER_LENGTH (attr) == 0
+			   || IDENTIFIER_POINTER (attr)[0] != '_');
+      if (strcmp (attr_name, IDENTIFIER_POINTER (attr)) == 0)
 	*p = TREE_CHAIN (l);
       else
 	p = &TREE_CHAIN (l);
@@ -14544,6 +14493,23 @@ get_nonnull_args (const_tree fntype)
   return argmap;
 }
 
+tree
+canonize_attr_name (tree attr_name)
+{
+  const size_t l = IDENTIFIER_LENGTH (attr_name);
+  const char *s = IDENTIFIER_POINTER (attr_name);
+
+  if (l > 4 && s[0] == '_')
+    {
+      gcc_assert (s[1] == '_');
+      gcc_assert (s[l - 2] == '_');
+      gcc_assert (s[l - 1] == '_');
+      return get_identifier_with_length (s + 2, l - 4);
+    }
+
+  return attr_name;
+}
+
 #if CHECKING_P
 
 namespace selftest {
diff --git a/gcc/tree.h b/gcc/tree.h
index bfe83f7c0a2..e58d362a216 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -4186,6 +4186,10 @@ extern tree private_lookup_attribute (const char *, size_t, tree);
    of lookup_attribute_by_prefix() and you should never call it directly.  */
 extern tree private_lookup_attribute_by_prefix (const char *, size_t, tree);
 
+/* For a given IDENTIFIER_NODE, strip leading and trailing '_' characters
+   so that we have a canonized shape or attribute names.  */
+extern tree canonize_attr_name (tree attr_name);
+
 /* Given an attribute name ATTR_NAME and a list of attributes LIST,
    return a pointer to the attribute's list element if the attribute
    is part of the list, or NULL_TREE if not found.  If the attribute


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

* Re: [PATCH][RFC] Canonize names of attributes.
  2017-06-13 12:32 [PATCH][RFC] Canonize names of attributes Martin Liška
@ 2017-06-13 13:20 ` Richard Biener
  2017-06-14  7:48   ` Martin Liška
  2017-06-14 17:24 ` Jason Merrill
  1 sibling, 1 reply; 37+ messages in thread
From: Richard Biener @ 2017-06-13 13:20 UTC (permalink / raw)
  To: Martin Liška; +Cc: GCC Patches

On Tue, Jun 13, 2017 at 2:32 PM, Martin Liška <mliska@suse.cz> wrote:
> Hello.
>
> After some discussions with Richi, I would like to propose patch that will
> come up with a canonical name of attribute names. That means __attribute__((__abi_tag__))
> will be given 'abi_tag' as IDENTIFIER_NAME of the attribute. The change can improve
> attribute name lookup and we can delete all the ugly code that compares strlen(i1)
> == strlen(i2) + 4, etc.
>
> Patch can bootstrap on ppc64le-redhat-linux and survives regression tests (w/ default
> languages). I'm currently testing objc, obj-c++ and go.
>
> Ready to be installed?


+tree
+canonize_attr_name (tree attr_name)
+{

needs a comment.

+  if (l > 4 && s[0] == '_')
+    {
+      gcc_assert (s[1] == '_');
+      gcc_assert (s[l - 2] == '_');
+      gcc_assert (s[l - 1] == '_');
+      return get_identifier_with_length (s + 2, l - 4);
+    }

a single gcc_checking_assert please.  I think this belongs in attribs.[ch].

Seeing

diff --git a/gcc/c-family/c-lex.c b/gcc/c-family/c-lex.c
index e1c8bdff986..6d0e9279ed6 100644
--- a/gcc/c-family/c-lex.c
+++ b/gcc/c-family/c-lex.c
@@ -316,6 +316,7 @@ c_common_has_attribute (cpp_reader *pfile)
     {
       attr_name = get_identifier ((const char *)
                                  cpp_token_as_text (pfile, token));
+      attr_name = canonize_attr_name (attr_name);

I wondered if we can save allocating the non-canonical identifier.  Like
with

tree
canonize_attr_name (const char *attr_name, size_t len)

as we can pass it IDENTIFIER_POINTER/LENGTH or the token.  OTOH
all other cases do have IDENTIFIERs already...

@ -24638,6 +24639,11 @@ cp_parser_gnu_attribute_list (cp_parser* parser)
              else
                {
                  arguments = build_tree_list_vec (vec);
+                 tree tv;
+                 if (arguments != NULL_TREE
+                     && ((tv = TREE_VALUE (arguments)) != NULL_TREE)
+                     && TREE_CODE (tv) == IDENTIFIER_NODE)
+                     TREE_VALUE (arguments) = canonize_attr_name (tv);
                  release_tree_vector (vec);
                }

are you sure this is needed?  This seems to be solely arguments to
attributes.

The rest of the changes look good but please wait for input from FE maintainers.

Thanks,
Richard.

> Martin
>
>
> gcc/cp/ChangeLog:
>
> 2017-06-09  Martin Liska  <mliska@suse.cz>
>
>         * parser.c (cp_parser_gnu_attribute_list): Canonize attribute
>         names.
>         (cp_parser_std_attribute): Likewise.
>
> gcc/go/ChangeLog:
>
> 2017-06-09  Martin Liska  <mliska@suse.cz>
>
>         * go-gcc.cc (Gcc_backend::function): Use no_split_stack
>         instead of __no_split_stack__.
>
> gcc/c/ChangeLog:
>
> 2017-06-09  Martin Liska  <mliska@suse.cz>
>
>         * c-parser.c (c_parser_attributes): Canonize attribute names.
>
> gcc/c-family/ChangeLog:
>
> 2017-06-09  Martin Liska  <mliska@suse.cz>
>
>         * c-format.c (cmp_attribs): Simplify comparison of attributes.
>         * c-lex.c (c_common_has_attribute): Canonize attribute names.
>
> gcc/ChangeLog:
>
> 2017-06-09  Martin Liska  <mliska@suse.cz>
>
>         * tree.c (cmp_attrib_identifiers): Simplify comparison of attributes.
>         (private_is_attribute_p): Likewise.
>         (private_lookup_attribute): Likewise.
>         (private_lookup_attribute_by_prefix): Likewise.
>         (remove_attribute): Likewise.
>         (canonize_attr_name): New function.
>         * tree.h: Declared here.
>
> gcc/testsuite/ChangeLog:
>
> 2017-06-09  Martin Liska  <mliska@suse.cz>
>
>         * g++.dg/cpp0x/pr65558.C: Change expected warning.
>         * gcc.dg/parm-impl-decl-1.c: Likewise.
>         * gcc.dg/parm-impl-decl-3.c: Likewise.
> ---
>  gcc/c-family/c-format.c                 |  13 ++--
>  gcc/c-family/c-lex.c                    |   1 +
>  gcc/c/c-parser.c                        |   9 +++
>  gcc/cp/parser.c                         |  11 +++-
>  gcc/go/go-gcc.cc                        |   2 +-
>  gcc/testsuite/g++.dg/cpp0x/pr65558.C    |   2 +-
>  gcc/testsuite/gcc.dg/parm-impl-decl-1.c |   2 +-
>  gcc/testsuite/gcc.dg/parm-impl-decl-3.c |   2 +-
>  gcc/tree.c                              | 108 +++++++++++---------------------
>  gcc/tree.h                              |   4 ++
>  10 files changed, 69 insertions(+), 85 deletions(-)
>
>

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

* Re: [PATCH][RFC] Canonize names of attributes.
  2017-06-13 13:20 ` Richard Biener
@ 2017-06-14  7:48   ` Martin Liška
  2017-06-14  9:07     ` Richard Biener
  0 siblings, 1 reply; 37+ messages in thread
From: Martin Liška @ 2017-06-14  7:48 UTC (permalink / raw)
  To: Richard Biener; +Cc: GCC Patches, Jason Merrill, Marek Polacek, iant

[-- Attachment #1: Type: text/plain, Size: 6069 bytes --]

On 06/13/2017 03:20 PM, Richard Biener wrote:
> On Tue, Jun 13, 2017 at 2:32 PM, Martin Liška <mliska@suse.cz> wrote:
>> Hello.
>>
>> After some discussions with Richi, I would like to propose patch that will
>> come up with a canonical name of attribute names. That means __attribute__((__abi_tag__))
>> will be given 'abi_tag' as IDENTIFIER_NAME of the attribute. The change can improve
>> attribute name lookup and we can delete all the ugly code that compares strlen(i1)
>> == strlen(i2) + 4, etc.
>>
>> Patch can bootstrap on ppc64le-redhat-linux and survives regression tests (w/ default
>> languages). I'm currently testing objc, obj-c++ and go.
>>
>> Ready to be installed?
> 
> 
> +tree
> +canonize_attr_name (tree attr_name)
> +{
> 
> needs a comment.

Did that in header file.

> 
> +  if (l > 4 && s[0] == '_')
> +    {
> +      gcc_assert (s[1] == '_');
> +      gcc_assert (s[l - 2] == '_');
> +      gcc_assert (s[l - 1] == '_');
> +      return get_identifier_with_length (s + 2, l - 4);
> +    }
> 
> a single gcc_checking_assert please.  I think this belongs in attribs.[ch].

Ok, I'll put it there and make it static inline.

> 
> Seeing
> 
> diff --git a/gcc/c-family/c-lex.c b/gcc/c-family/c-lex.c
> index e1c8bdff986..6d0e9279ed6 100644
> --- a/gcc/c-family/c-lex.c
> +++ b/gcc/c-family/c-lex.c
> @@ -316,6 +316,7 @@ c_common_has_attribute (cpp_reader *pfile)
>      {
>        attr_name = get_identifier ((const char *)
>                                   cpp_token_as_text (pfile, token));
> +      attr_name = canonize_attr_name (attr_name);
> 
> I wondered if we can save allocating the non-canonical identifier.  Like
> with
> 
> tree
> canonize_attr_name (const char *attr_name, size_t len)
> 
> as we can pass it IDENTIFIER_POINTER/LENGTH or the token.  OTOH
> all other cases do have IDENTIFIERs already...

Well, back trace where identifiers are allocated is:

#0  make_node_stat (code=code@entry=IDENTIFIER_NODE) at ../../gcc/tree.c:1011
#1  0x0000000000da073e in alloc_node (table=<optimized out>) at ../../gcc/stringpool.c:75
#2  0x000000000163b49a in ht_lookup_with_hash (table=0x22f57b0, 
    str=str@entry=0x2383615 "__abi_tag__ (\"cxx11\")))\n#endif\n\n\n#if __cplusplus\n\n// Macro for constexpr, to support in mixed 03/0x mode.\n#ifndef _GLIBCXX_CONSTEXPR\n# if __cplusplus >= 201103L\n#  define _GLIBCXX_CONSTEXPR constexpr\n"..., len=len@entry=11, 
    hash=hash@entry=144997377, insert=insert@entry=HT_ALLOC) at ../../libcpp/symtab.c:155
#3  0x000000000162d8ee in lex_identifier (pfile=pfile@entry=0x22f2fe0, 
    base=0x2383615 "__abi_tag__ (\"cxx11\")))\n#endif\n\n\n#if __cplusplus\n\n// Macro for constexpr, to support in mixed 03/0x mode.\n#ifndef _GLIBCXX_CONSTEXPR\n# if __cplusplus >= 201103L\n#  define _GLIBCXX_CONSTEXPR constexpr\n"..., 
    starts_ucn=starts_ucn@entry=false, nst=nst@entry=0x7fffffffcd54, spelling=spelling@entry=0x2348d98) at ../../libcpp/lex.c:1459
#4  0x00000000016304f0 in _cpp_lex_direct (pfile=pfile@entry=0x22f2fe0) at ../../libcpp/lex.c:2788

It's probably not possible to make a decision from this context about
how an identifier will be used?

> 
> @ -24638,6 +24639,11 @@ cp_parser_gnu_attribute_list (cp_parser* parser)
>               else
>                 {
>                   arguments = build_tree_list_vec (vec);
> +                 tree tv;
> +                 if (arguments != NULL_TREE
> +                     && ((tv = TREE_VALUE (arguments)) != NULL_TREE)
> +                     && TREE_CODE (tv) == IDENTIFIER_NODE)
> +                     TREE_VALUE (arguments) = canonize_attr_name (tv);
>                   release_tree_vector (vec);
>                 }
> 
> are you sure this is needed?  This seems to be solely arguments to
> attributes.

It's need for cases like:
 __intN_t (8, __QI__);

> 
> The rest of the changes look good but please wait for input from FE maintainers.

Good, I'm attaching v2 and CCing FE maintainers.

Martin

> 
> Thanks,
> Richard.
> 
>> Martin
>>
>>
>> gcc/cp/ChangeLog:
>>
>> 2017-06-09  Martin Liska  <mliska@suse.cz>
>>
>>         * parser.c (cp_parser_gnu_attribute_list): Canonize attribute
>>         names.
>>         (cp_parser_std_attribute): Likewise.
>>
>> gcc/go/ChangeLog:
>>
>> 2017-06-09  Martin Liska  <mliska@suse.cz>
>>
>>         * go-gcc.cc (Gcc_backend::function): Use no_split_stack
>>         instead of __no_split_stack__.
>>
>> gcc/c/ChangeLog:
>>
>> 2017-06-09  Martin Liska  <mliska@suse.cz>
>>
>>         * c-parser.c (c_parser_attributes): Canonize attribute names.
>>
>> gcc/c-family/ChangeLog:
>>
>> 2017-06-09  Martin Liska  <mliska@suse.cz>
>>
>>         * c-format.c (cmp_attribs): Simplify comparison of attributes.
>>         * c-lex.c (c_common_has_attribute): Canonize attribute names.
>>
>> gcc/ChangeLog:
>>
>> 2017-06-09  Martin Liska  <mliska@suse.cz>
>>
>>         * tree.c (cmp_attrib_identifiers): Simplify comparison of attributes.
>>         (private_is_attribute_p): Likewise.
>>         (private_lookup_attribute): Likewise.
>>         (private_lookup_attribute_by_prefix): Likewise.
>>         (remove_attribute): Likewise.
>>         (canonize_attr_name): New function.
>>         * tree.h: Declared here.
>>
>> gcc/testsuite/ChangeLog:
>>
>> 2017-06-09  Martin Liska  <mliska@suse.cz>
>>
>>         * g++.dg/cpp0x/pr65558.C: Change expected warning.
>>         * gcc.dg/parm-impl-decl-1.c: Likewise.
>>         * gcc.dg/parm-impl-decl-3.c: Likewise.
>> ---
>>  gcc/c-family/c-format.c                 |  13 ++--
>>  gcc/c-family/c-lex.c                    |   1 +
>>  gcc/c/c-parser.c                        |   9 +++
>>  gcc/cp/parser.c                         |  11 +++-
>>  gcc/go/go-gcc.cc                        |   2 +-
>>  gcc/testsuite/g++.dg/cpp0x/pr65558.C    |   2 +-
>>  gcc/testsuite/gcc.dg/parm-impl-decl-1.c |   2 +-
>>  gcc/testsuite/gcc.dg/parm-impl-decl-3.c |   2 +-
>>  gcc/tree.c                              | 108 +++++++++++---------------------
>>  gcc/tree.h                              |   4 ++
>>  10 files changed, 69 insertions(+), 85 deletions(-)
>>
>>


[-- Attachment #2: 0001-Canonize-names-of-attributes-v2.patch --]
[-- Type: text/x-patch, Size: 14837 bytes --]

From ab39c1ba7011ceaea8c71f65b7188c0249b3c409 Mon Sep 17 00:00:00 2001
From: marxin <mliska@suse.cz>
Date: Thu, 8 Jun 2017 10:23:25 +0200
Subject: [PATCH] Canonize names of attributes.

gcc/cp/ChangeLog:

2017-06-09  Martin Liska  <mliska@suse.cz>

	* parser.c (cp_parser_gnu_attribute_list): Canonize attribute
	names.
	(cp_parser_std_attribute): Likewise.
	* tree.c: Include stringpool.h header file.

gcc/go/ChangeLog:

2017-06-09  Martin Liska  <mliska@suse.cz>

	* go-gcc.cc (Gcc_backend::function): Use no_split_stack
	instead of __no_split_stack__.

gcc/c/ChangeLog:

2017-06-09  Martin Liska  <mliska@suse.cz>

	* c-parser.c (c_parser_attributes): Canonize attribute names.

gcc/c-family/ChangeLog:

2017-06-09  Martin Liska  <mliska@suse.cz>

	* c-format.c (cmp_attribs): Simplify comparison of attributes.
	* c-lex.c (c_common_has_attribute): Canonize attribute names.
	* c-pretty-print.c: Include stringpool.h header file.

gcc/ChangeLog:

2017-06-09  Martin Liska  <mliska@suse.cz>

	* attribs.h (canonize_attr_name): New function.
	* tree.c (cmp_attrib_identifiers): Simplify comparison of attributes.
	(private_is_attribute_p): Likewise.
	(private_lookup_attribute): Likewise.
	(private_lookup_attribute_by_prefix): Likewise.
	(remove_attribute): Likewise.

gcc/testsuite/ChangeLog:

2017-06-09  Martin Liska  <mliska@suse.cz>

	* g++.dg/cpp0x/pr65558.C: Change expected warning.
	* gcc.dg/parm-impl-decl-1.c: Likewise.
	* gcc.dg/parm-impl-decl-3.c: Likewise.
---
 gcc/attribs.h                           | 19 +++++++
 gcc/c-family/c-format.c                 | 13 ++---
 gcc/c-family/c-lex.c                    |  1 +
 gcc/c-family/c-pretty-print.c           |  1 +
 gcc/c/c-parser.c                        |  9 ++++
 gcc/cp/parser.c                         | 11 +++-
 gcc/cp/tree.c                           |  1 +
 gcc/go/go-gcc.cc                        |  2 +-
 gcc/testsuite/g++.dg/cpp0x/pr65558.C    |  2 +-
 gcc/testsuite/gcc.dg/parm-impl-decl-1.c |  2 +-
 gcc/testsuite/gcc.dg/parm-impl-decl-3.c |  2 +-
 gcc/tree.c                              | 91 ++++++++-------------------------
 12 files changed, 69 insertions(+), 85 deletions(-)

diff --git a/gcc/attribs.h b/gcc/attribs.h
index 7f13332700e..010a4e5165d 100644
--- a/gcc/attribs.h
+++ b/gcc/attribs.h
@@ -47,4 +47,23 @@ extern char *make_unique_name (tree, const char *, bool);
 extern tree make_dispatcher_decl (const tree);
 extern bool is_function_default_version (const tree);
 
+/* For a given IDENTIFIER_NODE, strip leading and trailing '_' characters
+   so that we have a canonized shape or attribute names.  */
+
+static inline tree
+canonize_attr_name (tree attr_name)
+{
+  const size_t l = IDENTIFIER_LENGTH (attr_name);
+  const char *s = IDENTIFIER_POINTER (attr_name);
+
+  if (l > 4 && s[0] == '_')
+    {
+      gcc_checking_assert (s[l - 2] == '_');
+      return get_identifier_with_length (s + 2, l - 4);
+    }
+
+  return attr_name;
+}
+
+
 #endif // GCC_ATTRIBS_H
diff --git a/gcc/c-family/c-format.c b/gcc/c-family/c-format.c
index 732339b9b5e..30f60d42cca 100644
--- a/gcc/c-family/c-format.c
+++ b/gcc/c-family/c-format.c
@@ -3982,15 +3982,10 @@ cmp_attribs (const char *tattr_name, const char *attr_name)
 {
   int alen = strlen (attr_name);
   int slen = (tattr_name ? strlen (tattr_name) : 0);
-  if (alen > 4 && attr_name[0] == '_' && attr_name[1] == '_'
-      && attr_name[alen - 1] == '_' && attr_name[alen - 2] == '_')
-    {
-      attr_name += 2;
-      alen -= 4;
-    }
-  if (alen != slen || strncmp (tattr_name, attr_name, alen) != 0)
-    return false;
-  return true;
+  gcc_checking_assert (alen == 0 || attr_name[0] != '_');
+  gcc_checking_assert (slen == 0 || tattr_name[0] != '_');
+
+  return (alen == slen && strncmp (tattr_name, attr_name, alen) == 0);
 }
 
 /* Handle a "format" attribute; arguments as in
diff --git a/gcc/c-family/c-lex.c b/gcc/c-family/c-lex.c
index e1c8bdff986..6d0e9279ed6 100644
--- a/gcc/c-family/c-lex.c
+++ b/gcc/c-family/c-lex.c
@@ -316,6 +316,7 @@ c_common_has_attribute (cpp_reader *pfile)
     {
       attr_name = get_identifier ((const char *)
 				  cpp_token_as_text (pfile, token));
+      attr_name = canonize_attr_name (attr_name);
       if (c_dialect_cxx ())
 	{
 	  int idx = 0;
diff --git a/gcc/c-family/c-pretty-print.c b/gcc/c-family/c-pretty-print.c
index fdb7b41f592..b8b8f665ef3 100644
--- a/gcc/c-family/c-pretty-print.c
+++ b/gcc/c-family/c-pretty-print.c
@@ -24,6 +24,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "c-pretty-print.h"
 #include "diagnostic.h"
 #include "stor-layout.h"
+#include "stringpool.h"
 #include "attribs.h"
 #include "intl.h"
 #include "tree-pretty-print.h"
diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
index 6f954f21fa2..400b65380e2 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -4168,9 +4168,11 @@ c_parser_attributes (c_parser *parser)
 	  attr_name = c_parser_attribute_any_word (parser);
 	  if (attr_name == NULL)
 	    break;
+	  attr_name = canonize_attr_name (attr_name);
 	  if (is_cilkplus_vector_p (attr_name))
 	    {
 	      c_token *v_token = c_parser_peek_token (parser);
+	      v_token->value = canonize_attr_name (v_token->value);
 	      c_parser_cilk_simd_fn_vector_attrs (parser, *v_token);
 	      /* If the next token isn't a comma, we're done.  */
 	      if (!c_parser_next_token_is (parser, CPP_COMMA))
@@ -4234,6 +4236,13 @@ c_parser_attributes (c_parser *parser)
 		  release_tree_vector (expr_list);
 		}
 	    }
+
+	  if (attr_args
+	      && TREE_VALUE (attr_args)
+	      && TREE_CODE (TREE_VALUE (attr_args)) == IDENTIFIER_NODE)
+	    TREE_VALUE (attr_args)
+	      = canonize_attr_name (TREE_VALUE (attr_args));
+
 	  attr = build_tree_list (attr_name, attr_args);
 	  if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
 	    c_parser_consume_token (parser);
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index d02ad360d16..b968ed6572e 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -24612,7 +24612,8 @@ cp_parser_gnu_attribute_list (cp_parser* parser)
 	       parsed identifier.  */
 	    ? ridpointers[(int) token->keyword]
 	    : id_token->u.value;
-	  
+
+	  identifier = canonize_attr_name (identifier);
 	  attribute = build_tree_list (identifier, NULL_TREE);
 
 	  /* Peek at the next token.  */
@@ -24638,6 +24639,11 @@ cp_parser_gnu_attribute_list (cp_parser* parser)
 	      else
 		{
 		  arguments = build_tree_list_vec (vec);
+		  tree tv;
+		  if (arguments != NULL_TREE
+		      && ((tv = TREE_VALUE (arguments)) != NULL_TREE)
+		      && TREE_CODE (tv) == IDENTIFIER_NODE)
+		    TREE_VALUE (arguments) = canonize_attr_name (tv);
 		  release_tree_vector (vec);
 		}
 	      /* Save the arguments away.  */
@@ -24758,6 +24764,8 @@ cp_parser_std_attribute (cp_parser *parser, tree attr_ns)
 		    "expected an identifier for the attribute name");
 	  return error_mark_node;
 	}
+
+      attr_id = canonize_attr_name (attr_id);
       attribute = build_tree_list (build_tree_list (attr_ns, attr_id),
 				   NULL_TREE);
       token = cp_lexer_peek_token (parser->lexer);
@@ -24767,6 +24775,7 @@ cp_parser_std_attribute (cp_parser *parser, tree attr_ns)
 				 NULL_TREE);
   else
     {
+      attr_id = canonize_attr_name (attr_id);
       attribute = build_tree_list (build_tree_list (NULL_TREE, attr_id),
 				   NULL_TREE);
       /* C++11 noreturn attribute is equivalent to GNU's.  */
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index bb17278c611..513ecf6e71b 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -32,6 +32,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "debug.h"
 #include "convert.h"
 #include "gimplify.h"
+#include "stringpool.h"
 #include "attribs.h"
 #include "flags.h"
 
diff --git a/gcc/go/go-gcc.cc b/gcc/go/go-gcc.cc
index a7977fe03c1..04912f0ed01 100644
--- a/gcc/go/go-gcc.cc
+++ b/gcc/go/go-gcc.cc
@@ -3046,7 +3046,7 @@ Gcc_backend::function(Btype* fntype, const std::string& name,
     DECL_UNINLINABLE(decl) = 1;
   if (disable_split_stack)
     {
-      tree attr = get_identifier("__no_split_stack__");
+      tree attr = get_identifier ("no_split_stack");
       DECL_ATTRIBUTES(decl) = tree_cons(attr, NULL_TREE, NULL_TREE);
     }
   if (in_unique_section)
diff --git a/gcc/testsuite/g++.dg/cpp0x/pr65558.C b/gcc/testsuite/g++.dg/cpp0x/pr65558.C
index d294c95a657..12946b35eda 100644
--- a/gcc/testsuite/g++.dg/cpp0x/pr65558.C
+++ b/gcc/testsuite/g++.dg/cpp0x/pr65558.C
@@ -2,6 +2,6 @@
 // { dg-do compile { target c++11 } }
 
 inline namespace
-__attribute__((__abi_tag__)) // { dg-warning "ignoring .__abi_tag__. attribute on anonymous namespace" }
+__attribute__((__abi_tag__)) // { dg-warning "ignoring .abi_tag. attribute on anonymous namespace" }
 {
 }
diff --git a/gcc/testsuite/gcc.dg/parm-impl-decl-1.c b/gcc/testsuite/gcc.dg/parm-impl-decl-1.c
index 5c7ddb0a259..c1219273c75 100644
--- a/gcc/testsuite/gcc.dg/parm-impl-decl-1.c
+++ b/gcc/testsuite/gcc.dg/parm-impl-decl-1.c
@@ -7,7 +7,7 @@
 /* Implicit function declaration in attribute in definition (testcase
    from bug).  */
 int
-foo (int __attribute__ ((__mode__ (vector_size(8)))) i) /* { dg-warning "'__mode__' attribute ignored" } */
+foo (int __attribute__ ((__mode__ (vector_size(8)))) i) /* { dg-warning "'mode' attribute ignored" } */
 {
   return (long long) i;
 }
diff --git a/gcc/testsuite/gcc.dg/parm-impl-decl-3.c b/gcc/testsuite/gcc.dg/parm-impl-decl-3.c
index 904295258d7..20197b52402 100644
--- a/gcc/testsuite/gcc.dg/parm-impl-decl-3.c
+++ b/gcc/testsuite/gcc.dg/parm-impl-decl-3.c
@@ -4,7 +4,7 @@
 /* { dg-options "-g -std=gnu89" } */
 
 int
-foo (int __attribute__ ((__mode__ (vector_size(8)))) i) /* { dg-warning "'__mode__' attribute ignored" } */
+foo (int __attribute__ ((__mode__ (vector_size(8)))) i) /* { dg-warning "'mode' attribute ignored" } */
 {
   return (long long) i;
 }
diff --git a/gcc/tree.c b/gcc/tree.c
index 260280317bc..cfacae8a506 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -4943,34 +4943,16 @@ cmp_attrib_identifiers (const_tree attr1, const_tree attr2)
   if (attr1 == attr2)
     return true;
 
-  /* If they are not equal, they may still be one in the form
-     'text' while the other one is in the form '__text__'.  TODO:
-     If we were storing attributes in normalized 'text' form, then
-     this could all go away and we could take full advantage of
-     the fact that we're comparing identifiers. :-)  */
   const size_t attr1_len = IDENTIFIER_LENGTH (attr1);
   const size_t attr2_len = IDENTIFIER_LENGTH (attr2);
 
-  if (attr2_len == attr1_len + 4)
-    {
-      const char *p = IDENTIFIER_POINTER (attr2);
-      const char *q = IDENTIFIER_POINTER (attr1);
-      if (p[0] == '_' && p[1] == '_'
-	  && p[attr2_len - 2] == '_' && p[attr2_len - 1] == '_'
-	  && strncmp (q, p + 2, attr1_len) == 0)
-	return true;;
-    }
-  else if (attr2_len + 4 == attr1_len)
-    {
-      const char *p = IDENTIFIER_POINTER (attr2);
-      const char *q = IDENTIFIER_POINTER (attr1);
-      if (q[0] == '_' && q[1] == '_'
-	  && q[attr1_len - 2] == '_' && q[attr1_len - 1] == '_'
-	  && strncmp (q + 2, p, attr2_len) == 0)
-	return true;
-    }
+  if (attr1_len != attr2_len)
+    return false;
+  gcc_checking_assert (IDENTIFIER_POINTER (attr1)[0] != '_');
+  gcc_checking_assert (IDENTIFIER_POINTER (attr2)[0] != '_');
 
-  return false;
+  return strncmp (IDENTIFIER_POINTER (attr1), IDENTIFIER_POINTER (attr2),
+		  attr1_len) == 0;
 }
 
 /* Compare two attributes for their value identity.  Return true if the
@@ -6047,24 +6029,9 @@ bool
 private_is_attribute_p (const char *attr_name, size_t attr_len, const_tree ident)
 {
   size_t ident_len = IDENTIFIER_LENGTH (ident);
+  gcc_checking_assert (ident_len == 0 || IDENTIFIER_POINTER (ident)[0] != '_');
 
-  if (ident_len == attr_len)
-    {
-      if (id_equal (ident, attr_name))
-	return true;
-    }
-  else if (ident_len == attr_len + 4)
-    {
-      /* There is the possibility that ATTR is 'text' and IDENT is
-	 '__text__'.  */
-      const char *p = IDENTIFIER_POINTER (ident);      
-      if (p[0] == '_' && p[1] == '_'
-	  && p[ident_len - 2] == '_' && p[ident_len - 1] == '_'
-	  && strncmp (attr_name, p + 2, attr_len) == 0)
-	return true;
-    }
-
-  return false;
+  return ident_len == attr_len && id_equal (ident, attr_name);
 }
 
 /* The backbone of lookup_attribute().  ATTR_LEN is the string length
@@ -6074,25 +6041,13 @@ private_lookup_attribute (const char *attr_name, size_t attr_len, tree list)
 {
   while (list)
     {
-      size_t ident_len = IDENTIFIER_LENGTH (get_attribute_name (list));
-
-      if (ident_len == attr_len)
-	{
-	  if (!strcmp (attr_name,
-		       IDENTIFIER_POINTER (get_attribute_name (list))))
+      tree attr = get_attribute_name (list);
+      size_t ident_len = IDENTIFIER_LENGTH (attr);
+      gcc_checking_assert (ident_len == 0
+			   || IDENTIFIER_POINTER (attr)[0] != '_');
+      if (ident_len == attr_len
+	  && strcmp (attr_name, IDENTIFIER_POINTER (attr)) == 0)
 	    break;
-	}
-      /* TODO: If we made sure that attributes were stored in the
-	 canonical form without '__...__' (ie, as in 'text' as opposed
-	 to '__text__') then we could avoid the following case.  */
-      else if (ident_len == attr_len + 4)
-	{
-	  const char *p = IDENTIFIER_POINTER (get_attribute_name (list));
-	  if (p[0] == '_' && p[1] == '_'
-	      && p[ident_len - 2] == '_' && p[ident_len - 1] == '_'
-	      && strncmp (attr_name, p + 2, attr_len) == 0)
-	    break;
-	}
       list = TREE_CHAIN (list);
     }
 
@@ -6119,17 +6074,11 @@ private_lookup_attribute_by_prefix (const char *attr_name, size_t attr_len,
 	}
 
       const char *p = IDENTIFIER_POINTER (get_attribute_name (list));
+      gcc_checking_assert (attr_len == 0 || p[0] != '_');
 
       if (strncmp (attr_name, p, attr_len) == 0)
 	break;
 
-      /* TODO: If we made sure that attributes were stored in the
-	 canonical form without '__...__' (ie, as in 'text' as opposed
-	 to '__text__') then we could avoid the following case.  */
-      if (p[0] == '_' && p[1] == '_' &&
-	  strncmp (attr_name, p + 2, attr_len) == 0)
-	break;
-
       list = TREE_CHAIN (list);
     }
 
@@ -6175,16 +6124,16 @@ tree
 remove_attribute (const char *attr_name, tree list)
 {
   tree *p;
-  size_t attr_len = strlen (attr_name);
-
   gcc_checking_assert (attr_name[0] != '_');
 
   for (p = &list; *p; )
     {
       tree l = *p;
-      /* TODO: If we were storing attributes in normalized form, here
-	 we could use a simple strcmp().  */
-      if (private_is_attribute_p (attr_name, attr_len, get_attribute_name (l)))
+
+      tree attr = get_attribute_name (l);
+      gcc_checking_assert (IDENTIFIER_LENGTH (attr) == 0
+			   || IDENTIFIER_POINTER (attr)[0] != '_');
+      if (strcmp (attr_name, IDENTIFIER_POINTER (attr)) == 0)
 	*p = TREE_CHAIN (l);
       else
 	p = &TREE_CHAIN (l);
-- 
2.13.1


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

* Re: [PATCH][RFC] Canonize names of attributes.
  2017-06-14  7:48   ` Martin Liška
@ 2017-06-14  9:07     ` Richard Biener
  2017-06-14 11:03       ` Martin Liška
  2017-06-14 16:40       ` Joseph Myers
  0 siblings, 2 replies; 37+ messages in thread
From: Richard Biener @ 2017-06-14  9:07 UTC (permalink / raw)
  To: Martin Liška; +Cc: GCC Patches, Jason Merrill, Marek Polacek, iant

On Wed, Jun 14, 2017 at 9:48 AM, Martin Liška <mliska@suse.cz> wrote:
> On 06/13/2017 03:20 PM, Richard Biener wrote:
>> On Tue, Jun 13, 2017 at 2:32 PM, Martin Liška <mliska@suse.cz> wrote:
>>> Hello.
>>>
>>> After some discussions with Richi, I would like to propose patch that will
>>> come up with a canonical name of attribute names. That means __attribute__((__abi_tag__))
>>> will be given 'abi_tag' as IDENTIFIER_NAME of the attribute. The change can improve
>>> attribute name lookup and we can delete all the ugly code that compares strlen(i1)
>>> == strlen(i2) + 4, etc.
>>>
>>> Patch can bootstrap on ppc64le-redhat-linux and survives regression tests (w/ default
>>> languages). I'm currently testing objc, obj-c++ and go.
>>>
>>> Ready to be installed?
>>
>>
>> +tree
>> +canonize_attr_name (tree attr_name)
>> +{
>>
>> needs a comment.
>
> Did that in header file.

Coding convention requires it at the implementation.

>>
>> +  if (l > 4 && s[0] == '_')
>> +    {
>> +      gcc_assert (s[1] == '_');
>> +      gcc_assert (s[l - 2] == '_');
>> +      gcc_assert (s[l - 1] == '_');
>> +      return get_identifier_with_length (s + 2, l - 4);
>> +    }
>>
>> a single gcc_checking_assert please.  I think this belongs in attribs.[ch].
>
> Ok, I'll put it there and make it static inline.
>
>>
>> Seeing
>>
>> diff --git a/gcc/c-family/c-lex.c b/gcc/c-family/c-lex.c
>> index e1c8bdff986..6d0e9279ed6 100644
>> --- a/gcc/c-family/c-lex.c
>> +++ b/gcc/c-family/c-lex.c
>> @@ -316,6 +316,7 @@ c_common_has_attribute (cpp_reader *pfile)
>>      {
>>        attr_name = get_identifier ((const char *)
>>                                   cpp_token_as_text (pfile, token));
>> +      attr_name = canonize_attr_name (attr_name);
>>
>> I wondered if we can save allocating the non-canonical identifier.  Like
>> with
>>
>> tree
>> canonize_attr_name (const char *attr_name, size_t len)
>>
>> as we can pass it IDENTIFIER_POINTER/LENGTH or the token.  OTOH
>> all other cases do have IDENTIFIERs already...
>
> Well, back trace where identifiers are allocated is:
>
> #0  make_node_stat (code=code@entry=IDENTIFIER_NODE) at ../../gcc/tree.c:1011
> #1  0x0000000000da073e in alloc_node (table=<optimized out>) at ../../gcc/stringpool.c:75
> #2  0x000000000163b49a in ht_lookup_with_hash (table=0x22f57b0,
>     str=str@entry=0x2383615 "__abi_tag__ (\"cxx11\")))\n#endif\n\n\n#if __cplusplus\n\n// Macro for constexpr, to support in mixed 03/0x mode.\n#ifndef _GLIBCXX_CONSTEXPR\n# if __cplusplus >= 201103L\n#  define _GLIBCXX_CONSTEXPR constexpr\n"..., len=len@entry=11,
>     hash=hash@entry=144997377, insert=insert@entry=HT_ALLOC) at ../../libcpp/symtab.c:155
> #3  0x000000000162d8ee in lex_identifier (pfile=pfile@entry=0x22f2fe0,
>     base=0x2383615 "__abi_tag__ (\"cxx11\")))\n#endif\n\n\n#if __cplusplus\n\n// Macro for constexpr, to support in mixed 03/0x mode.\n#ifndef _GLIBCXX_CONSTEXPR\n# if __cplusplus >= 201103L\n#  define _GLIBCXX_CONSTEXPR constexpr\n"...,
>     starts_ucn=starts_ucn@entry=false, nst=nst@entry=0x7fffffffcd54, spelling=spelling@entry=0x2348d98) at ../../libcpp/lex.c:1459
> #4  0x00000000016304f0 in _cpp_lex_direct (pfile=pfile@entry=0x22f2fe0) at ../../libcpp/lex.c:2788
>
> It's probably not possible to make a decision from this context about
> how an identifier will be used?

No.

>>
>> @ -24638,6 +24639,11 @@ cp_parser_gnu_attribute_list (cp_parser* parser)
>>               else
>>                 {
>>                   arguments = build_tree_list_vec (vec);
>> +                 tree tv;
>> +                 if (arguments != NULL_TREE
>> +                     && ((tv = TREE_VALUE (arguments)) != NULL_TREE)
>> +                     && TREE_CODE (tv) == IDENTIFIER_NODE)
>> +                     TREE_VALUE (arguments) = canonize_attr_name (tv);
>>                   release_tree_vector (vec);
>>                 }
>>
>> are you sure this is needed?  This seems to be solely arguments to
>> attributes.
>
> It's need for cases like:
>  __intN_t (8, __QI__);

But __QI__ is not processed in lookup_attribute, is it?  So canonizing that
looks unrelated?  I didn't see similar handling in the C FE btw (but
maybe I missed it).

>>
>> The rest of the changes look good but please wait for input from FE maintainers.
>
> Good, I'm attaching v2 and CCing FE maintainers.
>
> Martin
>
>>
>> Thanks,
>> Richard.
>>
>>> Martin
>>>
>>>
>>> gcc/cp/ChangeLog:
>>>
>>> 2017-06-09  Martin Liska  <mliska@suse.cz>
>>>
>>>         * parser.c (cp_parser_gnu_attribute_list): Canonize attribute
>>>         names.
>>>         (cp_parser_std_attribute): Likewise.
>>>
>>> gcc/go/ChangeLog:
>>>
>>> 2017-06-09  Martin Liska  <mliska@suse.cz>
>>>
>>>         * go-gcc.cc (Gcc_backend::function): Use no_split_stack
>>>         instead of __no_split_stack__.
>>>
>>> gcc/c/ChangeLog:
>>>
>>> 2017-06-09  Martin Liska  <mliska@suse.cz>
>>>
>>>         * c-parser.c (c_parser_attributes): Canonize attribute names.
>>>
>>> gcc/c-family/ChangeLog:
>>>
>>> 2017-06-09  Martin Liska  <mliska@suse.cz>
>>>
>>>         * c-format.c (cmp_attribs): Simplify comparison of attributes.
>>>         * c-lex.c (c_common_has_attribute): Canonize attribute names.
>>>
>>> gcc/ChangeLog:
>>>
>>> 2017-06-09  Martin Liska  <mliska@suse.cz>
>>>
>>>         * tree.c (cmp_attrib_identifiers): Simplify comparison of attributes.
>>>         (private_is_attribute_p): Likewise.
>>>         (private_lookup_attribute): Likewise.
>>>         (private_lookup_attribute_by_prefix): Likewise.
>>>         (remove_attribute): Likewise.
>>>         (canonize_attr_name): New function.
>>>         * tree.h: Declared here.
>>>
>>> gcc/testsuite/ChangeLog:
>>>
>>> 2017-06-09  Martin Liska  <mliska@suse.cz>
>>>
>>>         * g++.dg/cpp0x/pr65558.C: Change expected warning.
>>>         * gcc.dg/parm-impl-decl-1.c: Likewise.
>>>         * gcc.dg/parm-impl-decl-3.c: Likewise.
>>> ---
>>>  gcc/c-family/c-format.c                 |  13 ++--
>>>  gcc/c-family/c-lex.c                    |   1 +
>>>  gcc/c/c-parser.c                        |   9 +++
>>>  gcc/cp/parser.c                         |  11 +++-
>>>  gcc/go/go-gcc.cc                        |   2 +-
>>>  gcc/testsuite/g++.dg/cpp0x/pr65558.C    |   2 +-
>>>  gcc/testsuite/gcc.dg/parm-impl-decl-1.c |   2 +-
>>>  gcc/testsuite/gcc.dg/parm-impl-decl-3.c |   2 +-
>>>  gcc/tree.c                              | 108 +++++++++++---------------------
>>>  gcc/tree.h                              |   4 ++
>>>  10 files changed, 69 insertions(+), 85 deletions(-)
>>>
>>>
>

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

* Re: [PATCH][RFC] Canonize names of attributes.
  2017-06-14  9:07     ` Richard Biener
@ 2017-06-14 11:03       ` Martin Liška
  2017-06-14 11:19         ` Richard Biener
  2017-06-14 16:40       ` Joseph Myers
  1 sibling, 1 reply; 37+ messages in thread
From: Martin Liška @ 2017-06-14 11:03 UTC (permalink / raw)
  To: Richard Biener; +Cc: GCC Patches, Jason Merrill, Marek Polacek, iant

On 06/14/2017 11:07 AM, Richard Biener wrote:
> On Wed, Jun 14, 2017 at 9:48 AM, Martin Liška <mliska@suse.cz> wrote:
>> On 06/13/2017 03:20 PM, Richard Biener wrote:
>>> On Tue, Jun 13, 2017 at 2:32 PM, Martin Liška <mliska@suse.cz> wrote:
>>>> Hello.
>>>>
>>>> After some discussions with Richi, I would like to propose patch that will
>>>> come up with a canonical name of attribute names. That means __attribute__((__abi_tag__))
>>>> will be given 'abi_tag' as IDENTIFIER_NAME of the attribute. The change can improve
>>>> attribute name lookup and we can delete all the ugly code that compares strlen(i1)
>>>> == strlen(i2) + 4, etc.
>>>>
>>>> Patch can bootstrap on ppc64le-redhat-linux and survives regression tests (w/ default
>>>> languages). I'm currently testing objc, obj-c++ and go.
>>>>
>>>> Ready to be installed?
>>>
>>>
>>> +tree
>>> +canonize_attr_name (tree attr_name)
>>> +{
>>>
>>> needs a comment.
>>
>> Did that in header file.
> 
> Coding convention requires it at the implementation.
> 
>>>
>>> +  if (l > 4 && s[0] == '_')
>>> +    {
>>> +      gcc_assert (s[1] == '_');
>>> +      gcc_assert (s[l - 2] == '_');
>>> +      gcc_assert (s[l - 1] == '_');
>>> +      return get_identifier_with_length (s + 2, l - 4);
>>> +    }
>>>
>>> a single gcc_checking_assert please.  I think this belongs in attribs.[ch].
>>
>> Ok, I'll put it there and make it static inline.
>>
>>>
>>> Seeing
>>>
>>> diff --git a/gcc/c-family/c-lex.c b/gcc/c-family/c-lex.c
>>> index e1c8bdff986..6d0e9279ed6 100644
>>> --- a/gcc/c-family/c-lex.c
>>> +++ b/gcc/c-family/c-lex.c
>>> @@ -316,6 +316,7 @@ c_common_has_attribute (cpp_reader *pfile)
>>>      {
>>>        attr_name = get_identifier ((const char *)
>>>                                   cpp_token_as_text (pfile, token));
>>> +      attr_name = canonize_attr_name (attr_name);
>>>
>>> I wondered if we can save allocating the non-canonical identifier.  Like
>>> with
>>>
>>> tree
>>> canonize_attr_name (const char *attr_name, size_t len)
>>>
>>> as we can pass it IDENTIFIER_POINTER/LENGTH or the token.  OTOH
>>> all other cases do have IDENTIFIERs already...
>>
>> Well, back trace where identifiers are allocated is:
>>
>> #0  make_node_stat (code=code@entry=IDENTIFIER_NODE) at ../../gcc/tree.c:1011
>> #1  0x0000000000da073e in alloc_node (table=<optimized out>) at ../../gcc/stringpool.c:75
>> #2  0x000000000163b49a in ht_lookup_with_hash (table=0x22f57b0,
>>     str=str@entry=0x2383615 "__abi_tag__ (\"cxx11\")))\n#endif\n\n\n#if __cplusplus\n\n// Macro for constexpr, to support in mixed 03/0x mode.\n#ifndef _GLIBCXX_CONSTEXPR\n# if __cplusplus >= 201103L\n#  define _GLIBCXX_CONSTEXPR constexpr\n"..., len=len@entry=11,
>>     hash=hash@entry=144997377, insert=insert@entry=HT_ALLOC) at ../../libcpp/symtab.c:155
>> #3  0x000000000162d8ee in lex_identifier (pfile=pfile@entry=0x22f2fe0,
>>     base=0x2383615 "__abi_tag__ (\"cxx11\")))\n#endif\n\n\n#if __cplusplus\n\n// Macro for constexpr, to support in mixed 03/0x mode.\n#ifndef _GLIBCXX_CONSTEXPR\n# if __cplusplus >= 201103L\n#  define _GLIBCXX_CONSTEXPR constexpr\n"...,
>>     starts_ucn=starts_ucn@entry=false, nst=nst@entry=0x7fffffffcd54, spelling=spelling@entry=0x2348d98) at ../../libcpp/lex.c:1459
>> #4  0x00000000016304f0 in _cpp_lex_direct (pfile=pfile@entry=0x22f2fe0) at ../../libcpp/lex.c:2788
>>
>> It's probably not possible to make a decision from this context about
>> how an identifier will be used?
> 
> No.
> 
>>>
>>> @ -24638,6 +24639,11 @@ cp_parser_gnu_attribute_list (cp_parser* parser)
>>>               else
>>>                 {
>>>                   arguments = build_tree_list_vec (vec);
>>> +                 tree tv;
>>> +                 if (arguments != NULL_TREE
>>> +                     && ((tv = TREE_VALUE (arguments)) != NULL_TREE)
>>> +                     && TREE_CODE (tv) == IDENTIFIER_NODE)
>>> +                     TREE_VALUE (arguments) = canonize_attr_name (tv);
>>>                   release_tree_vector (vec);
>>>                 }
>>>
>>> are you sure this is needed?  This seems to be solely arguments to
>>> attributes.
>>
>> It's need for cases like:
>>  __intN_t (8, __QI__);
> 
> But __QI__ is not processed in lookup_attribute, is it?  So canonizing that
> looks unrelated?  I didn't see similar handling in the C FE btw (but
> maybe I missed it).

It's for instance compared in cmp_attribs in:

/usr/include/stdio.h:391:62: internal compiler error: in cmp_attribs, at c-family/c-format.c:3985
      __THROWNL __attribute__ ((__format__ (__printf__, 3, 4)));
                                                              ^
nf0xa86d86 cmp_attribs
	../../gcc/c-family/c-format.c:3985
0xa86dfe convert_format_name_to_system_name
	../../gcc/c-family/c-format.c:3967
0xa8835c convert_format_name_to_system_name
	../../gcc/c-family/c-format.c:339
0xa8835c decode_format_attr
	../../gcc/c-family/c-format.c:300
0xa8b880 handle_format_attribute(tree_node**, tree_node*, tree_node*, int, bool*)
	../../gcc/c-family/c-format.c:4019
0xa49fb7 decl_attributes(tree_node**, tree_node*, int)
	../../gcc/attribs.c:548
0x866dd3 cplus_decl_attributes(tree_node**, tree_node*, int)
	../../gcc/cp/decl2.c:1431
0x7786a1 grokfndecl
	../../gcc/cp/decl.c:8836
0x85127d grokdeclarator(cp_declarator const*, cp_decl_specifier_seq*, decl_context, int, tree_node**)
	../../gcc/cp/decl.c:12215
0x8542a6 start_decl(cp_declarator const*, cp_decl_specifier_seq*, int, tree_node*, tree_node*, tree_node**)
	../../gcc/cp/decl.c:4922
0x910de7 cp_parser_init_declarator
	../../gcc/cp/parser.c:19268
0x905145 cp_parser_simple_declaration
	../../gcc/cp/parser.c:12804
0x904cae cp_parser_block_declaration
	../../gcc/cp/parser.c:12629
0x904a30 cp_parser_declaration
	../../gcc/cp/parser.c:12527
0x904589 cp_parser_declaration_seq_opt
	../../gcc/cp/parser.c:12403
0x9066a5 cp_parser_linkage_specification
	../../gcc/cp/parser.c:13557
0x9047ad cp_parser_declaration
	../../gcc/cp/parser.c:12464
0x904589 cp_parser_declaration_seq_opt
	../../gcc/cp/parser.c:12403
0x8f31b7 cp_parser_translation_unit
	../../gcc/cp/parser.c:4364
0x94402a c_parse_file()
	../../gcc/cp/parser.c:38486

Martin

> 
>>>
>>> The rest of the changes look good but please wait for input from FE maintainers.
>>
>> Good, I'm attaching v2 and CCing FE maintainers.
>>
>> Martin
>>
>>>
>>> Thanks,
>>> Richard.
>>>
>>>> Martin
>>>>
>>>>
>>>> gcc/cp/ChangeLog:
>>>>
>>>> 2017-06-09  Martin Liska  <mliska@suse.cz>
>>>>
>>>>         * parser.c (cp_parser_gnu_attribute_list): Canonize attribute
>>>>         names.
>>>>         (cp_parser_std_attribute): Likewise.
>>>>
>>>> gcc/go/ChangeLog:
>>>>
>>>> 2017-06-09  Martin Liska  <mliska@suse.cz>
>>>>
>>>>         * go-gcc.cc (Gcc_backend::function): Use no_split_stack
>>>>         instead of __no_split_stack__.
>>>>
>>>> gcc/c/ChangeLog:
>>>>
>>>> 2017-06-09  Martin Liska  <mliska@suse.cz>
>>>>
>>>>         * c-parser.c (c_parser_attributes): Canonize attribute names.
>>>>
>>>> gcc/c-family/ChangeLog:
>>>>
>>>> 2017-06-09  Martin Liska  <mliska@suse.cz>
>>>>
>>>>         * c-format.c (cmp_attribs): Simplify comparison of attributes.
>>>>         * c-lex.c (c_common_has_attribute): Canonize attribute names.
>>>>
>>>> gcc/ChangeLog:
>>>>
>>>> 2017-06-09  Martin Liska  <mliska@suse.cz>
>>>>
>>>>         * tree.c (cmp_attrib_identifiers): Simplify comparison of attributes.
>>>>         (private_is_attribute_p): Likewise.
>>>>         (private_lookup_attribute): Likewise.
>>>>         (private_lookup_attribute_by_prefix): Likewise.
>>>>         (remove_attribute): Likewise.
>>>>         (canonize_attr_name): New function.
>>>>         * tree.h: Declared here.
>>>>
>>>> gcc/testsuite/ChangeLog:
>>>>
>>>> 2017-06-09  Martin Liska  <mliska@suse.cz>
>>>>
>>>>         * g++.dg/cpp0x/pr65558.C: Change expected warning.
>>>>         * gcc.dg/parm-impl-decl-1.c: Likewise.
>>>>         * gcc.dg/parm-impl-decl-3.c: Likewise.
>>>> ---
>>>>  gcc/c-family/c-format.c                 |  13 ++--
>>>>  gcc/c-family/c-lex.c                    |   1 +
>>>>  gcc/c/c-parser.c                        |   9 +++
>>>>  gcc/cp/parser.c                         |  11 +++-
>>>>  gcc/go/go-gcc.cc                        |   2 +-
>>>>  gcc/testsuite/g++.dg/cpp0x/pr65558.C    |   2 +-
>>>>  gcc/testsuite/gcc.dg/parm-impl-decl-1.c |   2 +-
>>>>  gcc/testsuite/gcc.dg/parm-impl-decl-3.c |   2 +-
>>>>  gcc/tree.c                              | 108 +++++++++++---------------------
>>>>  gcc/tree.h                              |   4 ++
>>>>  10 files changed, 69 insertions(+), 85 deletions(-)
>>>>
>>>>
>>

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

* Re: [PATCH][RFC] Canonize names of attributes.
  2017-06-14 11:03       ` Martin Liška
@ 2017-06-14 11:19         ` Richard Biener
  0 siblings, 0 replies; 37+ messages in thread
From: Richard Biener @ 2017-06-14 11:19 UTC (permalink / raw)
  To: Martin Liška; +Cc: GCC Patches, Jason Merrill, Marek Polacek, iant

On Wed, Jun 14, 2017 at 1:03 PM, Martin Liška <mliska@suse.cz> wrote:
> On 06/14/2017 11:07 AM, Richard Biener wrote:
>> On Wed, Jun 14, 2017 at 9:48 AM, Martin Liška <mliska@suse.cz> wrote:
>>> On 06/13/2017 03:20 PM, Richard Biener wrote:
>>>> On Tue, Jun 13, 2017 at 2:32 PM, Martin Liška <mliska@suse.cz> wrote:
>>>>> Hello.
>>>>>
>>>>> After some discussions with Richi, I would like to propose patch that will
>>>>> come up with a canonical name of attribute names. That means __attribute__((__abi_tag__))
>>>>> will be given 'abi_tag' as IDENTIFIER_NAME of the attribute. The change can improve
>>>>> attribute name lookup and we can delete all the ugly code that compares strlen(i1)
>>>>> == strlen(i2) + 4, etc.
>>>>>
>>>>> Patch can bootstrap on ppc64le-redhat-linux and survives regression tests (w/ default
>>>>> languages). I'm currently testing objc, obj-c++ and go.
>>>>>
>>>>> Ready to be installed?
>>>>
>>>>
>>>> +tree
>>>> +canonize_attr_name (tree attr_name)
>>>> +{
>>>>
>>>> needs a comment.
>>>
>>> Did that in header file.
>>
>> Coding convention requires it at the implementation.
>>
>>>>
>>>> +  if (l > 4 && s[0] == '_')
>>>> +    {
>>>> +      gcc_assert (s[1] == '_');
>>>> +      gcc_assert (s[l - 2] == '_');
>>>> +      gcc_assert (s[l - 1] == '_');
>>>> +      return get_identifier_with_length (s + 2, l - 4);
>>>> +    }
>>>>
>>>> a single gcc_checking_assert please.  I think this belongs in attribs.[ch].
>>>
>>> Ok, I'll put it there and make it static inline.
>>>
>>>>
>>>> Seeing
>>>>
>>>> diff --git a/gcc/c-family/c-lex.c b/gcc/c-family/c-lex.c
>>>> index e1c8bdff986..6d0e9279ed6 100644
>>>> --- a/gcc/c-family/c-lex.c
>>>> +++ b/gcc/c-family/c-lex.c
>>>> @@ -316,6 +316,7 @@ c_common_has_attribute (cpp_reader *pfile)
>>>>      {
>>>>        attr_name = get_identifier ((const char *)
>>>>                                   cpp_token_as_text (pfile, token));
>>>> +      attr_name = canonize_attr_name (attr_name);
>>>>
>>>> I wondered if we can save allocating the non-canonical identifier.  Like
>>>> with
>>>>
>>>> tree
>>>> canonize_attr_name (const char *attr_name, size_t len)
>>>>
>>>> as we can pass it IDENTIFIER_POINTER/LENGTH or the token.  OTOH
>>>> all other cases do have IDENTIFIERs already...
>>>
>>> Well, back trace where identifiers are allocated is:
>>>
>>> #0  make_node_stat (code=code@entry=IDENTIFIER_NODE) at ../../gcc/tree.c:1011
>>> #1  0x0000000000da073e in alloc_node (table=<optimized out>) at ../../gcc/stringpool.c:75
>>> #2  0x000000000163b49a in ht_lookup_with_hash (table=0x22f57b0,
>>>     str=str@entry=0x2383615 "__abi_tag__ (\"cxx11\")))\n#endif\n\n\n#if __cplusplus\n\n// Macro for constexpr, to support in mixed 03/0x mode.\n#ifndef _GLIBCXX_CONSTEXPR\n# if __cplusplus >= 201103L\n#  define _GLIBCXX_CONSTEXPR constexpr\n"..., len=len@entry=11,
>>>     hash=hash@entry=144997377, insert=insert@entry=HT_ALLOC) at ../../libcpp/symtab.c:155
>>> #3  0x000000000162d8ee in lex_identifier (pfile=pfile@entry=0x22f2fe0,
>>>     base=0x2383615 "__abi_tag__ (\"cxx11\")))\n#endif\n\n\n#if __cplusplus\n\n// Macro for constexpr, to support in mixed 03/0x mode.\n#ifndef _GLIBCXX_CONSTEXPR\n# if __cplusplus >= 201103L\n#  define _GLIBCXX_CONSTEXPR constexpr\n"...,
>>>     starts_ucn=starts_ucn@entry=false, nst=nst@entry=0x7fffffffcd54, spelling=spelling@entry=0x2348d98) at ../../libcpp/lex.c:1459
>>> #4  0x00000000016304f0 in _cpp_lex_direct (pfile=pfile@entry=0x22f2fe0) at ../../libcpp/lex.c:2788
>>>
>>> It's probably not possible to make a decision from this context about
>>> how an identifier will be used?
>>
>> No.
>>
>>>>
>>>> @ -24638,6 +24639,11 @@ cp_parser_gnu_attribute_list (cp_parser* parser)
>>>>               else
>>>>                 {
>>>>                   arguments = build_tree_list_vec (vec);
>>>> +                 tree tv;
>>>> +                 if (arguments != NULL_TREE
>>>> +                     && ((tv = TREE_VALUE (arguments)) != NULL_TREE)
>>>> +                     && TREE_CODE (tv) == IDENTIFIER_NODE)
>>>> +                     TREE_VALUE (arguments) = canonize_attr_name (tv);
>>>>                   release_tree_vector (vec);
>>>>                 }
>>>>
>>>> are you sure this is needed?  This seems to be solely arguments to
>>>> attributes.
>>>
>>> It's need for cases like:
>>>  __intN_t (8, __QI__);
>>
>> But __QI__ is not processed in lookup_attribute, is it?  So canonizing that
>> looks unrelated?  I didn't see similar handling in the C FE btw (but
>> maybe I missed it).
>
> It's for instance compared in cmp_attribs in:

Ah, of course.

Richard.

> /usr/include/stdio.h:391:62: internal compiler error: in cmp_attribs, at c-family/c-format.c:3985
>       __THROWNL __attribute__ ((__format__ (__printf__, 3, 4)));
>                                                               ^
> nf0xa86d86 cmp_attribs
>         ../../gcc/c-family/c-format.c:3985
> 0xa86dfe convert_format_name_to_system_name
>         ../../gcc/c-family/c-format.c:3967
> 0xa8835c convert_format_name_to_system_name
>         ../../gcc/c-family/c-format.c:339
> 0xa8835c decode_format_attr
>         ../../gcc/c-family/c-format.c:300
> 0xa8b880 handle_format_attribute(tree_node**, tree_node*, tree_node*, int, bool*)
>         ../../gcc/c-family/c-format.c:4019
> 0xa49fb7 decl_attributes(tree_node**, tree_node*, int)
>         ../../gcc/attribs.c:548
> 0x866dd3 cplus_decl_attributes(tree_node**, tree_node*, int)
>         ../../gcc/cp/decl2.c:1431
> 0x7786a1 grokfndecl
>         ../../gcc/cp/decl.c:8836
> 0x85127d grokdeclarator(cp_declarator const*, cp_decl_specifier_seq*, decl_context, int, tree_node**)
>         ../../gcc/cp/decl.c:12215
> 0x8542a6 start_decl(cp_declarator const*, cp_decl_specifier_seq*, int, tree_node*, tree_node*, tree_node**)
>         ../../gcc/cp/decl.c:4922
> 0x910de7 cp_parser_init_declarator
>         ../../gcc/cp/parser.c:19268
> 0x905145 cp_parser_simple_declaration
>         ../../gcc/cp/parser.c:12804
> 0x904cae cp_parser_block_declaration
>         ../../gcc/cp/parser.c:12629
> 0x904a30 cp_parser_declaration
>         ../../gcc/cp/parser.c:12527
> 0x904589 cp_parser_declaration_seq_opt
>         ../../gcc/cp/parser.c:12403
> 0x9066a5 cp_parser_linkage_specification
>         ../../gcc/cp/parser.c:13557
> 0x9047ad cp_parser_declaration
>         ../../gcc/cp/parser.c:12464
> 0x904589 cp_parser_declaration_seq_opt
>         ../../gcc/cp/parser.c:12403
> 0x8f31b7 cp_parser_translation_unit
>         ../../gcc/cp/parser.c:4364
> 0x94402a c_parse_file()
>         ../../gcc/cp/parser.c:38486
>
> Martin
>
>>
>>>>
>>>> The rest of the changes look good but please wait for input from FE maintainers.
>>>
>>> Good, I'm attaching v2 and CCing FE maintainers.
>>>
>>> Martin
>>>
>>>>
>>>> Thanks,
>>>> Richard.
>>>>
>>>>> Martin
>>>>>
>>>>>
>>>>> gcc/cp/ChangeLog:
>>>>>
>>>>> 2017-06-09  Martin Liska  <mliska@suse.cz>
>>>>>
>>>>>         * parser.c (cp_parser_gnu_attribute_list): Canonize attribute
>>>>>         names.
>>>>>         (cp_parser_std_attribute): Likewise.
>>>>>
>>>>> gcc/go/ChangeLog:
>>>>>
>>>>> 2017-06-09  Martin Liska  <mliska@suse.cz>
>>>>>
>>>>>         * go-gcc.cc (Gcc_backend::function): Use no_split_stack
>>>>>         instead of __no_split_stack__.
>>>>>
>>>>> gcc/c/ChangeLog:
>>>>>
>>>>> 2017-06-09  Martin Liska  <mliska@suse.cz>
>>>>>
>>>>>         * c-parser.c (c_parser_attributes): Canonize attribute names.
>>>>>
>>>>> gcc/c-family/ChangeLog:
>>>>>
>>>>> 2017-06-09  Martin Liska  <mliska@suse.cz>
>>>>>
>>>>>         * c-format.c (cmp_attribs): Simplify comparison of attributes.
>>>>>         * c-lex.c (c_common_has_attribute): Canonize attribute names.
>>>>>
>>>>> gcc/ChangeLog:
>>>>>
>>>>> 2017-06-09  Martin Liska  <mliska@suse.cz>
>>>>>
>>>>>         * tree.c (cmp_attrib_identifiers): Simplify comparison of attributes.
>>>>>         (private_is_attribute_p): Likewise.
>>>>>         (private_lookup_attribute): Likewise.
>>>>>         (private_lookup_attribute_by_prefix): Likewise.
>>>>>         (remove_attribute): Likewise.
>>>>>         (canonize_attr_name): New function.
>>>>>         * tree.h: Declared here.
>>>>>
>>>>> gcc/testsuite/ChangeLog:
>>>>>
>>>>> 2017-06-09  Martin Liska  <mliska@suse.cz>
>>>>>
>>>>>         * g++.dg/cpp0x/pr65558.C: Change expected warning.
>>>>>         * gcc.dg/parm-impl-decl-1.c: Likewise.
>>>>>         * gcc.dg/parm-impl-decl-3.c: Likewise.
>>>>> ---
>>>>>  gcc/c-family/c-format.c                 |  13 ++--
>>>>>  gcc/c-family/c-lex.c                    |   1 +
>>>>>  gcc/c/c-parser.c                        |   9 +++
>>>>>  gcc/cp/parser.c                         |  11 +++-
>>>>>  gcc/go/go-gcc.cc                        |   2 +-
>>>>>  gcc/testsuite/g++.dg/cpp0x/pr65558.C    |   2 +-
>>>>>  gcc/testsuite/gcc.dg/parm-impl-decl-1.c |   2 +-
>>>>>  gcc/testsuite/gcc.dg/parm-impl-decl-3.c |   2 +-
>>>>>  gcc/tree.c                              | 108 +++++++++++---------------------
>>>>>  gcc/tree.h                              |   4 ++
>>>>>  10 files changed, 69 insertions(+), 85 deletions(-)
>>>>>
>>>>>
>>>
>

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

* Re: [PATCH][RFC] Canonize names of attributes.
  2017-06-14  9:07     ` Richard Biener
  2017-06-14 11:03       ` Martin Liška
@ 2017-06-14 16:40       ` Joseph Myers
  2017-06-28 14:45         ` Martin Liška
  1 sibling, 1 reply; 37+ messages in thread
From: Joseph Myers @ 2017-06-14 16:40 UTC (permalink / raw)
  To: Richard Biener
  Cc: Martin Liška, GCC Patches, Jason Merrill, Marek Polacek, iant

On Wed, 14 Jun 2017, Richard Biener wrote:

> >> are you sure this is needed?  This seems to be solely arguments to
> >> attributes.
> >
> > It's need for cases like:
> >  __intN_t (8, __QI__);
> 
> But __QI__ is not processed in lookup_attribute, is it?  So canonizing that
> looks unrelated?  I didn't see similar handling in the C FE btw (but
> maybe I missed it).

It's not clear to me that there is automatically a rule that where 
identifiers are arguments to attributes, they must follow this rule about 
foo and __foo__ being equivalent.

Specifically: c-attribs.c:attribute_takes_identifier_p says that the 
cleanup attribute takes an identifier (a function name).  But it's 
certainly the case that the exact function named there must be used; foo 
and __foo__ as cleanup attribute arguments are not equivalent.  (You could 
argue cleanup should take an expression, with an error then being given if 
that doesn't evaluate to a function designator.)

-- 
Joseph S. Myers
joseph@codesourcery.com

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

* Re: [PATCH][RFC] Canonize names of attributes.
  2017-06-13 12:32 [PATCH][RFC] Canonize names of attributes Martin Liška
  2017-06-13 13:20 ` Richard Biener
@ 2017-06-14 17:24 ` Jason Merrill
  2017-06-16  0:07   ` Martin Sebor
  2017-06-28 14:46   ` Martin Liška
  1 sibling, 2 replies; 37+ messages in thread
From: Jason Merrill @ 2017-06-14 17:24 UTC (permalink / raw)
  To: Martin Liška; +Cc: gcc-patches List, Richard Biener

On Tue, Jun 13, 2017 at 8:32 AM, Martin Liška <mliska@suse.cz> wrote:
>         (canonize_attr_name): New function.

I think this should be "canonicalize"; "canonize" means something else.

Jason

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

* Re: [PATCH][RFC] Canonize names of attributes.
  2017-06-14 17:24 ` Jason Merrill
@ 2017-06-16  0:07   ` Martin Sebor
  2017-06-28 14:46   ` Martin Liška
  1 sibling, 0 replies; 37+ messages in thread
From: Martin Sebor @ 2017-06-16  0:07 UTC (permalink / raw)
  To: Jason Merrill, Martin Liška; +Cc: gcc-patches List, Richard Biener

On 06/14/2017 11:24 AM, Jason Merrill wrote:
> On Tue, Jun 13, 2017 at 8:32 AM, Martin Liška <mliska@suse.cz> wrote:
>>         (canonize_attr_name): New function.
>
> I think this should be "canonicalize"; "canonize" means something else.

Right.  I was about to make the same observation but then grepped
GCC sources for the word and found a whole bunch of existing names
(besides canonize itself there's also canonize_uhwi and
df_canonize_collection_rec), so I bit my tongue.

Martin

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

* Re: [PATCH][RFC] Canonize names of attributes.
  2017-06-14 16:40       ` Joseph Myers
@ 2017-06-28 14:45         ` Martin Liška
  0 siblings, 0 replies; 37+ messages in thread
From: Martin Liška @ 2017-06-28 14:45 UTC (permalink / raw)
  To: Joseph Myers, Richard Biener
  Cc: GCC Patches, Jason Merrill, Marek Polacek, iant

On 06/14/2017 06:40 PM, Joseph Myers wrote:
> On Wed, 14 Jun 2017, Richard Biener wrote:
> 
>>>> are you sure this is needed?  This seems to be solely arguments to
>>>> attributes.
>>>
>>> It's need for cases like:
>>>  __intN_t (8, __QI__);
>>
>> But __QI__ is not processed in lookup_attribute, is it?  So canonizing that
>> looks unrelated?  I didn't see similar handling in the C FE btw (but
>> maybe I missed it).
> 
> It's not clear to me that there is automatically a rule that where 
> identifiers are arguments to attributes, they must follow this rule about 
> foo and __foo__ being equivalent.
> 
> Specifically: c-attribs.c:attribute_takes_identifier_p says that the 
> cleanup attribute takes an identifier (a function name).  But it's 
> certainly the case that the exact function named there must be used; foo 
> and __foo__ as cleanup attribute arguments are not equivalent.  (You could 
> argue cleanup should take an expression, with an error then being given if 
> that doesn't evaluate to a function designator.)
> 

Hello.

This is obvious reason where original name must be preserved. Looks following patch
works and does not break test-suite:

diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 8f638785e0e..08b4db5e5bd 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -24765,7 +24765,8 @@ cp_parser_gnu_attribute_list (cp_parser* parser)
 		  tree tv;
 		  if (arguments != NULL_TREE
 		      && ((tv = TREE_VALUE (arguments)) != NULL_TREE)
-		      && TREE_CODE (tv) == IDENTIFIER_NODE)
+		      && TREE_CODE (tv) == IDENTIFIER_NODE
+		      && !id_equal (TREE_PURPOSE (attribute), "cleanup"))
 		    TREE_VALUE (arguments) = canonize_attr_name (tv);
 		  release_tree_vector (vec);
 		}
-- 

Well, the question is whether we want to in general canonicalize attribute names?
Special situations like "cleanup" can be handled.

Martin


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

* Re: [PATCH][RFC] Canonize names of attributes.
  2017-06-14 17:24 ` Jason Merrill
  2017-06-16  0:07   ` Martin Sebor
@ 2017-06-28 14:46   ` Martin Liška
  2017-06-28 16:06     ` Joseph Myers
  1 sibling, 1 reply; 37+ messages in thread
From: Martin Liška @ 2017-06-28 14:46 UTC (permalink / raw)
  To: Jason Merrill; +Cc: gcc-patches List, Richard Biener

On 06/14/2017 07:24 PM, Jason Merrill wrote:
> On Tue, Jun 13, 2017 at 8:32 AM, Martin Liška <mliska@suse.cz> wrote:
>>         (canonize_attr_name): New function.
> 
> I think this should be "canonicalize"; "canonize" means something else.
> 
> Jason
> 

Yes, I hope it's a cosmetic problem. In general, do you welcome the change
to canonicalize attribute names?

Martin

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

* Re: [PATCH][RFC] Canonize names of attributes.
  2017-06-28 14:46   ` Martin Liška
@ 2017-06-28 16:06     ` Joseph Myers
  2017-06-28 19:01       ` Jason Merrill
  0 siblings, 1 reply; 37+ messages in thread
From: Joseph Myers @ 2017-06-28 16:06 UTC (permalink / raw)
  To: Martin Liška; +Cc: Jason Merrill, gcc-patches List, Richard Biener

[-- Attachment #1: Type: text/plain, Size: 590 bytes --]

On Wed, 28 Jun 2017, Martin Liška wrote:

> On 06/14/2017 07:24 PM, Jason Merrill wrote:
> > On Tue, Jun 13, 2017 at 8:32 AM, Martin Liška <mliska@suse.cz> wrote:
> >>         (canonize_attr_name): New function.
> > 
> > I think this should be "canonicalize"; "canonize" means something else.
> > 
> > Jason
> > 
> 
> Yes, I hope it's a cosmetic problem. In general, do you welcome the change
> to canonicalize attribute names?

I think *names* (as opposed to arguments) should be canonicalized, but 
arguments need separate consideration.

-- 
Joseph S. Myers
joseph@codesourcery.com

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

* Re: [PATCH][RFC] Canonize names of attributes.
  2017-06-28 16:06     ` Joseph Myers
@ 2017-06-28 19:01       ` Jason Merrill
  2017-06-30  9:23         ` [PATCH v2][RFC] " Martin Liška
  0 siblings, 1 reply; 37+ messages in thread
From: Jason Merrill @ 2017-06-28 19:01 UTC (permalink / raw)
  To: Joseph Myers; +Cc: Martin Liška, gcc-patches List, Richard Biener

On Wed, Jun 28, 2017 at 12:05 PM, Joseph Myers <joseph@codesourcery.com> wrote:
> On Wed, 28 Jun 2017, Martin Liška wrote:
>
>> On 06/14/2017 07:24 PM, Jason Merrill wrote:
>> > On Tue, Jun 13, 2017 at 8:32 AM, Martin Liška <mliska@suse.cz> wrote:
>> >>         (canonize_attr_name): New function.
>> >
>> > I think this should be "canonicalize"; "canonize" means something else.
>> >
>> > Jason
>> >
>>
>> Yes, I hope it's a cosmetic problem. In general, do you welcome the change
>> to canonicalize attribute names?
>
> I think *names* (as opposed to arguments) should be canonicalized, but
> arguments need separate consideration.

I agree.

Jason

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

* [PATCH v2][RFC] Canonize names of attributes.
  2017-06-28 19:01       ` Jason Merrill
@ 2017-06-30  9:23         ` Martin Liška
  2017-06-30 19:35           ` Jason Merrill
  0 siblings, 1 reply; 37+ messages in thread
From: Martin Liška @ 2017-06-30  9:23 UTC (permalink / raw)
  To: Jason Merrill, Joseph Myers; +Cc: gcc-patches List, Richard Biener

[-- Attachment #1: Type: text/plain, Size: 914 bytes --]

On 06/28/2017 09:01 PM, Jason Merrill wrote:
> On Wed, Jun 28, 2017 at 12:05 PM, Joseph Myers <joseph@codesourcery.com> wrote:
>> On Wed, 28 Jun 2017, Martin Liška wrote:
>>
>>> On 06/14/2017 07:24 PM, Jason Merrill wrote:
>>>> On Tue, Jun 13, 2017 at 8:32 AM, Martin Liška <mliska@suse.cz> wrote:
>>>>>         (canonize_attr_name): New function.
>>>>
>>>> I think this should be "canonicalize"; "canonize" means something else.
>>>>
>>>> Jason
>>>>
>>>
>>> Yes, I hope it's a cosmetic problem. In general, do you welcome the change
>>> to canonicalize attribute names?
>>
>> I think *names* (as opposed to arguments) should be canonicalized, but
>> arguments need separate consideration.
> 
> I agree.
> 
> Jason
> 

Good.

This is v2 of the patch, where just names of attributes are canonicalized.
Patch can bootstrap on ppc64le-redhat-linux and survives regression tests.

Ready to be installed?
Martin


[-- Attachment #2: 0001-Canonicalize-names-of-attributes-v2.patch --]
[-- Type: text/x-patch, Size: 18381 bytes --]

From 4c604148da4d837b06b166512ae71ddf83e5cf3b Mon Sep 17 00:00:00 2001
From: marxin <mliska@suse.cz>
Date: Thu, 8 Jun 2017 10:23:25 +0200
Subject: [PATCH] Canonicalize names of attributes.

gcc/c-family/ChangeLog:

2017-06-29  Martin Liska  <mliska@suse.cz>

	* c-format.c (convert_format_name_to_system_name): Add argument
	to function call.
	(cmp_attribs): Remove the function.
	* c-lex.c (c_common_has_attribute): Use canonicalize_attr_name.
	* c-pretty-print.c: Include stringpool.h.

gcc/cp/ChangeLog:

2017-06-29  Martin Liska  <mliska@suse.cz>

	* parser.c (cp_parser_gnu_attribute_list): Use
	canonicalize_attr_name.
	(cp_parser_std_attribute): Likewise.
	* tree.c: Include stringpool.h.

gcc/go/ChangeLog:

2017-06-29  Martin Liska  <mliska@suse.cz>

	* go-gcc.cc (Gcc_backend::function): Look up for no_split_stack
	and not __no_split_stack__.

gcc/c/ChangeLog:

2017-06-29  Martin Liska  <mliska@suse.cz>

	* c-parser.c (c_parser_attributes): Use canonicalize_attr_name.

gcc/testsuite/ChangeLog:

2017-06-29  Martin Liska  <mliska@suse.cz>

	* g++.dg/cpp0x/pr65558.C: Update scanned pattern.
	* gcc.dg/parm-impl-decl-1.c: Likewise.
	* gcc.dg/parm-impl-decl-3.c: Likewise.

gcc/ChangeLog:

2017-06-29  Martin Liska  <mliska@suse.cz>

	* attribs.h (canonicalize_attr_name): New function.
	* tree.c (cmp_attrib_identifiers): Use cmp_attribs.
	(attribute_value_equal): Add argument to a call of function.
	(private_is_attribute_p): Add checking and use id_equal.
	(private_lookup_attribute): Consider attributes do not begin
	with '_' character.
	(private_lookup_attribute_by_prefix): Likewise.
	(remove_attribute): Use string comparison.
	* tree.h (cmp_attribs): New functions.
---
 gcc/attribs.h                           |  19 ++++++
 gcc/c-family/c-format.c                 |  27 ++-------
 gcc/c-family/c-lex.c                    |   1 +
 gcc/c-family/c-pretty-print.c           |   1 +
 gcc/c/c-parser.c                        |   3 +
 gcc/cp/parser.c                         |   6 +-
 gcc/cp/tree.c                           |   1 +
 gcc/go/go-gcc.cc                        |   2 +-
 gcc/testsuite/g++.dg/cpp0x/pr65558.C    |   2 +-
 gcc/testsuite/gcc.dg/parm-impl-decl-1.c |   2 +-
 gcc/testsuite/gcc.dg/parm-impl-decl-3.c |   2 +-
 gcc/tree.c                              | 103 +++++++-------------------------
 gcc/tree.h                              |  42 +++++++++++++
 13 files changed, 103 insertions(+), 108 deletions(-)

diff --git a/gcc/attribs.h b/gcc/attribs.h
index 7f13332700e..b3b68b2e57e 100644
--- a/gcc/attribs.h
+++ b/gcc/attribs.h
@@ -47,4 +47,23 @@ extern char *make_unique_name (tree, const char *, bool);
 extern tree make_dispatcher_decl (const tree);
 extern bool is_function_default_version (const tree);
 
+/* 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);
+  const char *s = IDENTIFIER_POINTER (attr_name);
+
+  if (l > 4 && s[0] == '_')
+    {
+      gcc_checking_assert (s[l - 2] == '_');
+      return get_identifier_with_length (s + 2, l - 4);
+    }
+
+  return attr_name;
+}
+
+
 #endif // GCC_ATTRIBS_H
diff --git a/gcc/c-family/c-format.c b/gcc/c-family/c-format.c
index 732339b9b5e..3aad17522df 100644
--- a/gcc/c-family/c-format.c
+++ b/gcc/c-family/c-format.c
@@ -67,7 +67,6 @@ static bool check_format_string (tree argument,
 static bool get_constant (tree expr, unsigned HOST_WIDE_INT *value,
 			  int validated_p);
 static const char *convert_format_name_to_system_name (const char *attr_name);
-static bool cmp_attribs (const char *tattr_name, const char *attr_name);
 
 static int first_target_format_type;
 static const char *format_name (int format_num);
@@ -3951,10 +3950,10 @@ convert_format_name_to_system_name (const char *attr_name)
       for (i = 0; i < TARGET_OVERRIDES_FORMAT_ATTRIBUTES_COUNT; ++i)
         {
           if (cmp_attribs (TARGET_OVERRIDES_FORMAT_ATTRIBUTES[i].named_attr_src,
-			   attr_name))
+			   attr_name, false))
             return attr_name;
           if (cmp_attribs (TARGET_OVERRIDES_FORMAT_ATTRIBUTES[i].named_attr_dst,
-			   attr_name))
+			   attr_name, false))
             return TARGET_OVERRIDES_FORMAT_ATTRIBUTES[i].named_attr_src;
         }
     }
@@ -3965,34 +3964,16 @@ convert_format_name_to_system_name (const char *attr_name)
        ++i)
     {
       if (cmp_attribs (gnu_target_overrides_format_attributes[i].named_attr_src,
-		       attr_name))
+		       attr_name, false))
         return attr_name;
       if (cmp_attribs (gnu_target_overrides_format_attributes[i].named_attr_dst,
-		       attr_name))
+		       attr_name, false))
         return gnu_target_overrides_format_attributes[i].named_attr_src;
     }
 
   return attr_name;
 }
 
-/* Return true if TATTR_NAME and ATTR_NAME are the same format attribute,
-   counting "name" and "__name__" as the same, false otherwise.  */
-static bool
-cmp_attribs (const char *tattr_name, const char *attr_name)
-{
-  int alen = strlen (attr_name);
-  int slen = (tattr_name ? strlen (tattr_name) : 0);
-  if (alen > 4 && attr_name[0] == '_' && attr_name[1] == '_'
-      && attr_name[alen - 1] == '_' && attr_name[alen - 2] == '_')
-    {
-      attr_name += 2;
-      alen -= 4;
-    }
-  if (alen != slen || strncmp (tattr_name, attr_name, alen) != 0)
-    return false;
-  return true;
-}
-
 /* Handle a "format" attribute; arguments as in
    struct attribute_spec.handler.  */
 tree
diff --git a/gcc/c-family/c-lex.c b/gcc/c-family/c-lex.c
index e1c8bdff986..3765a800a57 100644
--- a/gcc/c-family/c-lex.c
+++ b/gcc/c-family/c-lex.c
@@ -316,6 +316,7 @@ c_common_has_attribute (cpp_reader *pfile)
     {
       attr_name = get_identifier ((const char *)
 				  cpp_token_as_text (pfile, token));
+      attr_name = canonicalize_attr_name (attr_name);
       if (c_dialect_cxx ())
 	{
 	  int idx = 0;
diff --git a/gcc/c-family/c-pretty-print.c b/gcc/c-family/c-pretty-print.c
index fdb7b41f592..b8b8f665ef3 100644
--- a/gcc/c-family/c-pretty-print.c
+++ b/gcc/c-family/c-pretty-print.c
@@ -24,6 +24,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "c-pretty-print.h"
 #include "diagnostic.h"
 #include "stor-layout.h"
+#include "stringpool.h"
 #include "attribs.h"
 #include "intl.h"
 #include "tree-pretty-print.h"
diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
index f8fbc926172..e358b19a585 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -4170,9 +4170,11 @@ c_parser_attributes (c_parser *parser)
 	  attr_name = c_parser_attribute_any_word (parser);
 	  if (attr_name == NULL)
 	    break;
+	  attr_name = canonicalize_attr_name (attr_name);
 	  if (is_cilkplus_vector_p (attr_name))
 	    {
 	      c_token *v_token = c_parser_peek_token (parser);
+	      v_token->value = canonicalize_attr_name (v_token->value);
 	      c_parser_cilk_simd_fn_vector_attrs (parser, *v_token);
 	      /* If the next token isn't a comma, we're done.  */
 	      if (!c_parser_next_token_is (parser, CPP_COMMA))
@@ -4236,6 +4238,7 @@ c_parser_attributes (c_parser *parser)
 		  release_tree_vector (expr_list);
 		}
 	    }
+
 	  attr = build_tree_list (attr_name, attr_args);
 	  if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
 	    c_parser_consume_token (parser);
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index bd99c051340..4f1be517d41 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -24764,7 +24764,8 @@ cp_parser_gnu_attribute_list (cp_parser* parser)
 	       parsed identifier.  */
 	    ? ridpointers[(int) token->keyword]
 	    : id_token->u.value;
-	  
+
+	  identifier = canonicalize_attr_name (identifier);
 	  attribute = build_tree_list (identifier, NULL_TREE);
 
 	  /* Peek at the next token.  */
@@ -24910,6 +24911,8 @@ cp_parser_std_attribute (cp_parser *parser, tree attr_ns)
 		    "expected an identifier for the attribute name");
 	  return error_mark_node;
 	}
+
+      attr_id = canonicalize_attr_name (attr_id);
       attribute = build_tree_list (build_tree_list (attr_ns, attr_id),
 				   NULL_TREE);
       token = cp_lexer_peek_token (parser->lexer);
@@ -24919,6 +24922,7 @@ cp_parser_std_attribute (cp_parser *parser, tree attr_ns)
 				 NULL_TREE);
   else
     {
+      attr_id = canonicalize_attr_name (attr_id);
       attribute = build_tree_list (build_tree_list (NULL_TREE, attr_id),
 				   NULL_TREE);
       /* C++11 noreturn attribute is equivalent to GNU's.  */
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index 4535af64dc6..d8dddfd2324 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -32,6 +32,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "debug.h"
 #include "convert.h"
 #include "gimplify.h"
+#include "stringpool.h"
 #include "attribs.h"
 #include "flags.h"
 
diff --git a/gcc/go/go-gcc.cc b/gcc/go/go-gcc.cc
index a7977fe03c1..04912f0ed01 100644
--- a/gcc/go/go-gcc.cc
+++ b/gcc/go/go-gcc.cc
@@ -3046,7 +3046,7 @@ Gcc_backend::function(Btype* fntype, const std::string& name,
     DECL_UNINLINABLE(decl) = 1;
   if (disable_split_stack)
     {
-      tree attr = get_identifier("__no_split_stack__");
+      tree attr = get_identifier ("no_split_stack");
       DECL_ATTRIBUTES(decl) = tree_cons(attr, NULL_TREE, NULL_TREE);
     }
   if (in_unique_section)
diff --git a/gcc/testsuite/g++.dg/cpp0x/pr65558.C b/gcc/testsuite/g++.dg/cpp0x/pr65558.C
index d294c95a657..12946b35eda 100644
--- a/gcc/testsuite/g++.dg/cpp0x/pr65558.C
+++ b/gcc/testsuite/g++.dg/cpp0x/pr65558.C
@@ -2,6 +2,6 @@
 // { dg-do compile { target c++11 } }
 
 inline namespace
-__attribute__((__abi_tag__)) // { dg-warning "ignoring .__abi_tag__. attribute on anonymous namespace" }
+__attribute__((__abi_tag__)) // { dg-warning "ignoring .abi_tag. attribute on anonymous namespace" }
 {
 }
diff --git a/gcc/testsuite/gcc.dg/parm-impl-decl-1.c b/gcc/testsuite/gcc.dg/parm-impl-decl-1.c
index 5c7ddb0a259..c1219273c75 100644
--- a/gcc/testsuite/gcc.dg/parm-impl-decl-1.c
+++ b/gcc/testsuite/gcc.dg/parm-impl-decl-1.c
@@ -7,7 +7,7 @@
 /* Implicit function declaration in attribute in definition (testcase
    from bug).  */
 int
-foo (int __attribute__ ((__mode__ (vector_size(8)))) i) /* { dg-warning "'__mode__' attribute ignored" } */
+foo (int __attribute__ ((__mode__ (vector_size(8)))) i) /* { dg-warning "'mode' attribute ignored" } */
 {
   return (long long) i;
 }
diff --git a/gcc/testsuite/gcc.dg/parm-impl-decl-3.c b/gcc/testsuite/gcc.dg/parm-impl-decl-3.c
index 904295258d7..20197b52402 100644
--- a/gcc/testsuite/gcc.dg/parm-impl-decl-3.c
+++ b/gcc/testsuite/gcc.dg/parm-impl-decl-3.c
@@ -4,7 +4,7 @@
 /* { dg-options "-g -std=gnu89" } */
 
 int
-foo (int __attribute__ ((__mode__ (vector_size(8)))) i) /* { dg-warning "'__mode__' attribute ignored" } */
+foo (int __attribute__ ((__mode__ (vector_size(8)))) i) /* { dg-warning "'mode' attribute ignored" } */
 {
   return (long long) i;
 }
diff --git a/gcc/tree.c b/gcc/tree.c
index ca28afad0f2..662752459bb 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -4928,12 +4928,13 @@ simple_cst_list_equal (const_tree l1, const_tree l2)
   return l1 == l2;
 }
 
-/* Compare two identifier nodes representing attributes.  Either one may
-   be in wrapped __ATTR__ form.  Return true if they are the same, false
-   otherwise.  */
+/* Compare two identifier nodes representing attributes.
+   Return true if they are the same, false otherwise.  If STRICT is not set,
+   __ATTR__ and ATTR names are considered as equal.  */
 
 static bool
-cmp_attrib_identifiers (const_tree attr1, const_tree attr2)
+cmp_attrib_identifiers (const_tree attr1, const_tree attr2,
+			bool strict = true)
 {
   /* Make sure we're dealing with IDENTIFIER_NODEs.  */
   gcc_checking_assert (TREE_CODE (attr1) == IDENTIFIER_NODE
@@ -4943,34 +4944,9 @@ cmp_attrib_identifiers (const_tree attr1, const_tree attr2)
   if (attr1 == attr2)
     return true;
 
-  /* If they are not equal, they may still be one in the form
-     'text' while the other one is in the form '__text__'.  TODO:
-     If we were storing attributes in normalized 'text' form, then
-     this could all go away and we could take full advantage of
-     the fact that we're comparing identifiers. :-)  */
-  const size_t attr1_len = IDENTIFIER_LENGTH (attr1);
-  const size_t attr2_len = IDENTIFIER_LENGTH (attr2);
-
-  if (attr2_len == attr1_len + 4)
-    {
-      const char *p = IDENTIFIER_POINTER (attr2);
-      const char *q = IDENTIFIER_POINTER (attr1);
-      if (p[0] == '_' && p[1] == '_'
-	  && p[attr2_len - 2] == '_' && p[attr2_len - 1] == '_'
-	  && strncmp (q, p + 2, attr1_len) == 0)
-	return true;;
-    }
-  else if (attr2_len + 4 == attr1_len)
-    {
-      const char *p = IDENTIFIER_POINTER (attr2);
-      const char *q = IDENTIFIER_POINTER (attr1);
-      if (q[0] == '_' && q[1] == '_'
-	  && q[attr1_len - 2] == '_' && q[attr1_len - 1] == '_'
-	  && strncmp (q + 2, p, attr2_len) == 0)
-	return true;
-    }
-
-  return false;
+  return cmp_attribs (IDENTIFIER_POINTER (attr1), IDENTIFIER_LENGTH (attr1),
+		      IDENTIFIER_POINTER (attr2), IDENTIFIER_LENGTH (attr2),
+		      strict);
 }
 
 /* Compare two attributes for their value identity.  Return true if the
@@ -4994,7 +4970,7 @@ attribute_value_equal (const_tree attr1, const_tree attr2)
 	  attr2 = TREE_VALUE (attr2);
 	  /* Compare the archetypes (printf/scanf/strftime/...).  */
 	  if (!cmp_attrib_identifiers (TREE_VALUE (attr1),
-				       TREE_VALUE (attr2)))
+				       TREE_VALUE (attr2), false))
 	    return false;
 	  /* Archetypes are the same.  Compare the rest.  */
 	  return (simple_cst_list_equal (TREE_CHAIN (attr1),
@@ -6049,24 +6025,9 @@ bool
 private_is_attribute_p (const char *attr_name, size_t attr_len, const_tree ident)
 {
   size_t ident_len = IDENTIFIER_LENGTH (ident);
+  gcc_checking_assert (ident_len == 0 || IDENTIFIER_POINTER (ident)[0] != '_');
 
-  if (ident_len == attr_len)
-    {
-      if (id_equal (ident, attr_name))
-	return true;
-    }
-  else if (ident_len == attr_len + 4)
-    {
-      /* There is the possibility that ATTR is 'text' and IDENT is
-	 '__text__'.  */
-      const char *p = IDENTIFIER_POINTER (ident);      
-      if (p[0] == '_' && p[1] == '_'
-	  && p[ident_len - 2] == '_' && p[ident_len - 1] == '_'
-	  && strncmp (attr_name, p + 2, attr_len) == 0)
-	return true;
-    }
-
-  return false;
+  return ident_len == attr_len && id_equal (ident, attr_name);
 }
 
 /* The backbone of lookup_attribute().  ATTR_LEN is the string length
@@ -6076,25 +6037,13 @@ private_lookup_attribute (const char *attr_name, size_t attr_len, tree list)
 {
   while (list)
     {
-      size_t ident_len = IDENTIFIER_LENGTH (get_attribute_name (list));
-
-      if (ident_len == attr_len)
-	{
-	  if (!strcmp (attr_name,
-		       IDENTIFIER_POINTER (get_attribute_name (list))))
-	    break;
-	}
-      /* TODO: If we made sure that attributes were stored in the
-	 canonical form without '__...__' (ie, as in 'text' as opposed
-	 to '__text__') then we could avoid the following case.  */
-      else if (ident_len == attr_len + 4)
-	{
-	  const char *p = IDENTIFIER_POINTER (get_attribute_name (list));
-	  if (p[0] == '_' && p[1] == '_'
-	      && p[ident_len - 2] == '_' && p[ident_len - 1] == '_'
-	      && strncmp (attr_name, p + 2, attr_len) == 0)
+      tree attr = get_attribute_name (list);
+      size_t ident_len = IDENTIFIER_LENGTH (attr);
+      gcc_checking_assert (ident_len == 0
+			   || IDENTIFIER_POINTER (attr)[0] != '_');
+      if (ident_len == attr_len
+	  && strcmp (attr_name, IDENTIFIER_POINTER (attr)) == 0)
 	    break;
-	}
       list = TREE_CHAIN (list);
     }
 
@@ -6121,17 +6070,11 @@ private_lookup_attribute_by_prefix (const char *attr_name, size_t attr_len,
 	}
 
       const char *p = IDENTIFIER_POINTER (get_attribute_name (list));
+      gcc_checking_assert (attr_len == 0 || p[0] != '_');
 
       if (strncmp (attr_name, p, attr_len) == 0)
 	break;
 
-      /* TODO: If we made sure that attributes were stored in the
-	 canonical form without '__...__' (ie, as in 'text' as opposed
-	 to '__text__') then we could avoid the following case.  */
-      if (p[0] == '_' && p[1] == '_' &&
-	  strncmp (attr_name, p + 2, attr_len) == 0)
-	break;
-
       list = TREE_CHAIN (list);
     }
 
@@ -6177,16 +6120,16 @@ tree
 remove_attribute (const char *attr_name, tree list)
 {
   tree *p;
-  size_t attr_len = strlen (attr_name);
-
   gcc_checking_assert (attr_name[0] != '_');
 
   for (p = &list; *p; )
     {
       tree l = *p;
-      /* TODO: If we were storing attributes in normalized form, here
-	 we could use a simple strcmp().  */
-      if (private_is_attribute_p (attr_name, attr_len, get_attribute_name (l)))
+
+      tree attr = get_attribute_name (l);
+      gcc_checking_assert (IDENTIFIER_LENGTH (attr) == 0
+			   || IDENTIFIER_POINTER (attr)[0] != '_');
+      if (strcmp (attr_name, IDENTIFIER_POINTER (attr)) == 0)
 	*p = TREE_CHAIN (l);
       else
 	p = &TREE_CHAIN (l);
diff --git a/gcc/tree.h b/gcc/tree.h
index 91cf253dee5..d16ab3a7d59 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -5493,6 +5493,48 @@ type_with_alias_set_p (const_tree t)
   return false;
 }
 
+/* Compare attribute identifiers ATTR1 and ATTR2 with length ATTR1_LEN and
+   ATTR2_LEN.  If strict is false, consider __ATTR__ and ATTR as same
+   attribute names.  */
+
+static inline bool
+cmp_attribs (const char *attr1, size_t attr1_len,
+	     const char *attr2, size_t attr2_len,
+	     bool strict = true)
+{
+  if (!strict)
+    {
+      if (attr1_len > 4 && attr1[0] == '_')
+	{
+	  attr1 += 2;
+	  attr1_len -= 4;
+	}
+
+      if (attr2_len > 4 && attr2[0] == '_')
+	{
+	  attr2 += 2;
+	  attr2_len -= 4;
+	}
+    }
+  else
+    {
+      gcc_checking_assert (attr1_len == 0 || attr1[0] != '_');
+      gcc_checking_assert (attr2_len == 0 || attr2[0] != '_');
+    }
+
+  return attr1_len == attr2_len && strncmp (attr1, attr2, attr1_len) == 0;
+}
+
+
+/* Compare attribute identifiers ATTR1 and ATTR2.
+   If strict is false, consider __ATTR__ and ATTR as same attribute names.  */
+
+static inline bool
+cmp_attribs (const char *attr1, const char *attr2, bool strict = true)
+{
+  return cmp_attribs (attr1, strlen (attr1), attr2, strlen (attr2), strict);
+}
+
 extern location_t set_block (location_t loc, tree block);
 
 extern void gt_ggc_mx (tree &);
-- 
2.13.1


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

* Re: [PATCH v2][RFC] Canonize names of attributes.
  2017-06-30  9:23         ` [PATCH v2][RFC] " Martin Liška
@ 2017-06-30 19:35           ` Jason Merrill
  2017-07-03  9:52             ` Martin Liška
  0 siblings, 1 reply; 37+ messages in thread
From: Jason Merrill @ 2017-06-30 19:35 UTC (permalink / raw)
  To: Martin Liška; +Cc: Joseph Myers, gcc-patches List, Richard Biener

On Fri, Jun 30, 2017 at 5:23 AM, Martin Liška <mliska@suse.cz> wrote:
> This is v2 of the patch, where just names of attributes are canonicalized.
> Patch can bootstrap on ppc64le-redhat-linux and survives regression tests.

What is the purpose of the new "strict" parameter to cmp_attribs* ?  I
don't see any discussion of it.

Jason

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

* Re: [PATCH v2][RFC] Canonize names of attributes.
  2017-06-30 19:35           ` Jason Merrill
@ 2017-07-03  9:52             ` Martin Liška
  2017-07-03 21:00               ` Jason Merrill
  0 siblings, 1 reply; 37+ messages in thread
From: Martin Liška @ 2017-07-03  9:52 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Joseph Myers, gcc-patches List, Richard Biener

On 06/30/2017 09:34 PM, Jason Merrill wrote:
> On Fri, Jun 30, 2017 at 5:23 AM, Martin Liška <mliska@suse.cz> wrote:
>> This is v2 of the patch, where just names of attributes are canonicalized.
>> Patch can bootstrap on ppc64le-redhat-linux and survives regression tests.
> 
> What is the purpose of the new "strict" parameter to cmp_attribs* ?  I
> don't see any discussion of it.

It's needed for arguments of attribute names, like:

/usr/include/stdio.h:391:62: internal compiler error: in cmp_attribs, at tree.h:5523
      __THROWNL __attribute__ ((__format__ (__printf__, 3, 4)));

there we need strict to be set to false:

x8a64e7 cmp_attribs
	../../gcc/tree.h:5523
0x8a64e7 cmp_attribs
	../../gcc/tree.h:5536
0x8a64e7 convert_format_name_to_system_name
	../../gcc/c-family/c-format.c:3966
0x8a6e5c convert_format_name_to_system_name
	../../gcc/c-family/c-format.c:338
0x8a6e5c decode_format_attr
	../../gcc/c-family/c-format.c:299
0x8aa380 handle_format_attribute(tree_node**, tree_node*, tree_node*, int, bool*)
	../../gcc/c-family/c-format.c:4005
0x869d07 decl_attributes(tree_node**, tree_node*, int)
	../../gcc/attribs.c:548
0x6c0ee3 cplus_decl_attributes(tree_node**, tree_node*, int)
	../../gcc/cp/decl2.c:1407
...

I think it's useful to have name comparison in a single function.

Martin

> 
> Jason
> 

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

* Re: [PATCH v2][RFC] Canonize names of attributes.
  2017-07-03  9:52             ` Martin Liška
@ 2017-07-03 21:00               ` Jason Merrill
  2017-07-11 13:38                 ` Martin Liška
  0 siblings, 1 reply; 37+ messages in thread
From: Jason Merrill @ 2017-07-03 21:00 UTC (permalink / raw)
  To: Martin Liška; +Cc: Joseph Myers, gcc-patches List, Richard Biener

On Mon, Jul 3, 2017 at 5:52 AM, Martin Liška <mliska@suse.cz> wrote:
> On 06/30/2017 09:34 PM, Jason Merrill wrote:
>> On Fri, Jun 30, 2017 at 5:23 AM, Martin Liška <mliska@suse.cz> wrote:
>>> This is v2 of the patch, where just names of attributes are canonicalized.
>>> Patch can bootstrap on ppc64le-redhat-linux and survives regression tests.
>>
>> What is the purpose of the new "strict" parameter to cmp_attribs* ?  I
>> don't see any discussion of it.
>
> It's needed for arguments of attribute names, like:
>
> /usr/include/stdio.h:391:62: internal compiler error: in cmp_attribs, at tree.h:5523
>       __THROWNL __attribute__ ((__format__ (__printf__, 3, 4)));
>

Mm.  Although we don't want to automatically canonicalize all
identifier arguments to attributes in the parser, we could still do it
for specific attributes, e.g. in handle_format_attribute or
handle_mode_attribute.

Jason

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

* Re: [PATCH v2][RFC] Canonize names of attributes.
  2017-07-03 21:00               ` Jason Merrill
@ 2017-07-11 13:38                 ` Martin Liška
  2017-07-11 15:52                   ` Jason Merrill
  0 siblings, 1 reply; 37+ messages in thread
From: Martin Liška @ 2017-07-11 13:38 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Joseph Myers, gcc-patches List, Richard Biener

On 07/03/2017 11:00 PM, Jason Merrill wrote:
> On Mon, Jul 3, 2017 at 5:52 AM, Martin Liška <mliska@suse.cz> wrote:
>> On 06/30/2017 09:34 PM, Jason Merrill wrote:
>>> On Fri, Jun 30, 2017 at 5:23 AM, Martin Liška <mliska@suse.cz> wrote:
>>>> This is v2 of the patch, where just names of attributes are canonicalized.
>>>> Patch can bootstrap on ppc64le-redhat-linux and survives regression tests.
>>>
>>> What is the purpose of the new "strict" parameter to cmp_attribs* ?  I
>>> don't see any discussion of it.
>>
>> It's needed for arguments of attribute names, like:
>>
>> /usr/include/stdio.h:391:62: internal compiler error: in cmp_attribs, at tree.h:5523
>>        __THROWNL __attribute__ ((__format__ (__printf__, 3, 4)));
>>
> 
> Mm.  Although we don't want to automatically canonicalize all
> identifier arguments to attributes in the parser, we could still do it
> for specific attributes, e.g. in handle_format_attribute or
> handle_mode_attribute.

Yep, that was done in my previous version of the patch (https://gcc.gnu.org/ml/gcc-patches/2017-06/msg00996.html).
Where only attribute that was preserved unchanged was 'cleanup':

diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 8f638785e0e..08b4db5e5bd 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -24765,7 +24765,8 @@ cp_parser_gnu_attribute_list (cp_parser* parser)
  		  tree tv;
  		  if (arguments != NULL_TREE
  		      && ((tv = TREE_VALUE (arguments)) != NULL_TREE)
-		      && TREE_CODE (tv) == IDENTIFIER_NODE)
+		      && TREE_CODE (tv) == IDENTIFIER_NODE
+		      && !id_equal (TREE_PURPOSE (attribute), "cleanup"))
  		    TREE_VALUE (arguments) = canonize_attr_name (tv);
  		  release_tree_vector (vec);
  		}

Does it work for you to do it so?

Martin

> 
> Jason
> 

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

* Re: [PATCH v2][RFC] Canonize names of attributes.
  2017-07-11 13:38                 ` Martin Liška
@ 2017-07-11 15:52                   ` Jason Merrill
  2017-07-13 13:48                     ` Martin Liška
  0 siblings, 1 reply; 37+ messages in thread
From: Jason Merrill @ 2017-07-11 15:52 UTC (permalink / raw)
  To: Martin Liška; +Cc: Joseph Myers, gcc-patches List, Richard Biener

On Tue, Jul 11, 2017 at 9:37 AM, Martin Liška <mliska@suse.cz> wrote:
> On 07/03/2017 11:00 PM, Jason Merrill wrote:
>> On Mon, Jul 3, 2017 at 5:52 AM, Martin Liška <mliska@suse.cz> wrote:
>>> On 06/30/2017 09:34 PM, Jason Merrill wrote:
>>>>
>>>> On Fri, Jun 30, 2017 at 5:23 AM, Martin Liška <mliska@suse.cz> wrote:
>>>>>
>>>>> This is v2 of the patch, where just names of attributes are
>>>>> canonicalized.
>>>>> Patch can bootstrap on ppc64le-redhat-linux and survives regression
>>>>> tests.
>>>>
>>>>
>>>> What is the purpose of the new "strict" parameter to cmp_attribs* ?  I
>>>> don't see any discussion of it.
>>>
>>>
>>> It's needed for arguments of attribute names, like:
>>>
>>> /usr/include/stdio.h:391:62: internal compiler error: in cmp_attribs, at
>>> tree.h:5523
>>>        __THROWNL __attribute__ ((__format__ (__printf__, 3, 4)));
>>>
>>
>> Mm.  Although we don't want to automatically canonicalize all
>> identifier arguments to attributes in the parser, we could still do it
>> for specific attributes, e.g. in handle_format_attribute or
>> handle_mode_attribute.
>
> Yep, that was done in my previous version of the patch
> (https://gcc.gnu.org/ml/gcc-patches/2017-06/msg00996.html).
> Where only attribute that was preserved unchanged was 'cleanup':
>
> diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
> index 8f638785e0e..08b4db5e5bd 100644
> --- a/gcc/cp/parser.c
> +++ b/gcc/cp/parser.c
> @@ -24765,7 +24765,8 @@ cp_parser_gnu_attribute_list (cp_parser* parser)
>                   tree tv;
>                   if (arguments != NULL_TREE
>                       && ((tv = TREE_VALUE (arguments)) != NULL_TREE)
> -                     && TREE_CODE (tv) == IDENTIFIER_NODE)
> +                     && TREE_CODE (tv) == IDENTIFIER_NODE
> +                     && !id_equal (TREE_PURPOSE (attribute), "cleanup"))
>                     TREE_VALUE (arguments) = canonize_attr_name (tv);
>                   release_tree_vector (vec);
>                 }
>
> Does it work for you to do it so?

This is canonicalizing arguments by default; I want the default to be
not canonicalizing arguments.  I think we only want to canonicalize
arguments for format and mode, and we can do that in their handle_*
functions.

Jason

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

* Re: [PATCH v2][RFC] Canonize names of attributes.
  2017-07-11 15:52                   ` Jason Merrill
@ 2017-07-13 13:48                     ` Martin Liška
  2017-07-13 13:51                       ` [RFC][PATCH] Do refactoring of attribute functions and move them to attribs.[hc] Martin Liška
                                         ` (3 more replies)
  0 siblings, 4 replies; 37+ messages in thread
From: Martin Liška @ 2017-07-13 13:48 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Joseph Myers, gcc-patches List, Richard Biener

[-- Attachment #1: Type: text/plain, Size: 2619 bytes --]

On 07/11/2017 05:52 PM, Jason Merrill wrote:
> On Tue, Jul 11, 2017 at 9:37 AM, Martin Liška <mliska@suse.cz> wrote:
>> On 07/03/2017 11:00 PM, Jason Merrill wrote:
>>> On Mon, Jul 3, 2017 at 5:52 AM, Martin Liška <mliska@suse.cz> wrote:
>>>> On 06/30/2017 09:34 PM, Jason Merrill wrote:
>>>>>
>>>>> On Fri, Jun 30, 2017 at 5:23 AM, Martin Liška <mliska@suse.cz> wrote:
>>>>>>
>>>>>> This is v2 of the patch, where just names of attributes are
>>>>>> canonicalized.
>>>>>> Patch can bootstrap on ppc64le-redhat-linux and survives regression
>>>>>> tests.
>>>>>
>>>>>
>>>>> What is the purpose of the new "strict" parameter to cmp_attribs* ?  I
>>>>> don't see any discussion of it.
>>>>
>>>>
>>>> It's needed for arguments of attribute names, like:
>>>>
>>>> /usr/include/stdio.h:391:62: internal compiler error: in cmp_attribs, at
>>>> tree.h:5523
>>>>        __THROWNL __attribute__ ((__format__ (__printf__, 3, 4)));
>>>>
>>>
>>> Mm.  Although we don't want to automatically canonicalize all
>>> identifier arguments to attributes in the parser, we could still do it
>>> for specific attributes, e.g. in handle_format_attribute or
>>> handle_mode_attribute.
>>
>> Yep, that was done in my previous version of the patch
>> (https://gcc.gnu.org/ml/gcc-patches/2017-06/msg00996.html).
>> Where only attribute that was preserved unchanged was 'cleanup':
>>
>> diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
>> index 8f638785e0e..08b4db5e5bd 100644
>> --- a/gcc/cp/parser.c
>> +++ b/gcc/cp/parser.c
>> @@ -24765,7 +24765,8 @@ cp_parser_gnu_attribute_list (cp_parser* parser)
>>                   tree tv;
>>                   if (arguments != NULL_TREE
>>                       && ((tv = TREE_VALUE (arguments)) != NULL_TREE)
>> -                     && TREE_CODE (tv) == IDENTIFIER_NODE)
>> +                     && TREE_CODE (tv) == IDENTIFIER_NODE
>> +                     && !id_equal (TREE_PURPOSE (attribute), "cleanup"))
>>                     TREE_VALUE (arguments) = canonize_attr_name (tv);
>>                   release_tree_vector (vec);
>>                 }
>>
>> Does it work for you to do it so?
> 
> This is canonicalizing arguments by default; I want the default to be
> not canonicalizing arguments.  I think we only want to canonicalize
> arguments for format and mode, and we can do that in their handle_*
> functions.

Yep, done that in v3. I decided to move couple of functions to attribs.h and
verified that it will not cause binary size increase of cc1 and cc1plus.

Patch can bootstrap on ppc64le-redhat-linux and survives regression tests.

Ready to be installed?
Martin

> 
> Jason
> 


[-- Attachment #2: 0001-Canonicalize-names-of-attributes-v3.patch --]
[-- Type: text/x-patch, Size: 19653 bytes --]

From bd7bf58da6f0688fa10d3dfc72328f9313d7439c Mon Sep 17 00:00:00 2001
From: marxin <mliska@suse.cz>
Date: Thu, 8 Jun 2017 10:23:25 +0200
Subject: [PATCH 1/2] Canonicalize names of attributes.

gcc/ChangeLog:

2017-07-12  Martin Liska  <mliska@suse.cz>

	* attribs.h (canonicalize_attr_name): New function.
	(cmp_attribs): Move from c-format.c and adjusted.
	(is_attribute_p): Moved from tree.h.
	* tree-inline.c: Add new includes.
	* tree.c (cmp_attrib_identifiers): Use cmp_attribs.
	(private_is_attribute_p): Remove.
	(private_lookup_attribute): Likewise.
	(private_lookup_attribute_by_prefix): Simplify.
	(remove_attribute): Use is_attribute_p.
	* tree.h: Remove removed declarations.

gcc/c-family/ChangeLog:

2017-07-12  Martin Liska  <mliska@suse.cz>

	* array-notation-common.c: Add new includes.
	* c-format.c( handle_format_attribute): Canonicalize a format
	function name.
	* c-lex.c (c_common_has_attribute): Canonicalize name of an
	attribute.
	* c-pretty-print.c: Add new include.

gcc/cp/ChangeLog:

2017-07-12  Martin Liska  <mliska@suse.cz>

	* parser.c (cp_parser_gnu_attribute_list): Canonicalize name of an
	attribute.
	(cp_parser_std_attribute): Likewise.
	* tree.c: Add new include.

gcc/c/ChangeLog:

2017-07-12  Martin Liska  <mliska@suse.cz>

	* c-parser.c (c_parser_attributes): Canonicalize name of an
	attribute.
gcc/go/ChangeLog:

2017-06-29  Martin Liska  <mliska@suse.cz>

	* go-gcc.cc (Gcc_backend::function): Look up for no_split_stack
	and not __no_split_stack__.

gcc/testsuite/ChangeLog:

2017-06-29  Martin Liska  <mliska@suse.cz>

	* g++.dg/cpp0x/pr65558.C: Update scanned pattern.
	* gcc.dg/parm-impl-decl-1.c: Likewise.
	* gcc.dg/parm-impl-decl-3.c: Likewise.
---
 gcc/attribs.h                           |  49 +++++++++++++++
 gcc/c-family/array-notation-common.c    |   2 +
 gcc/c-family/c-format.c                 |  24 ++------
 gcc/c-family/c-lex.c                    |   1 +
 gcc/c-family/c-pretty-print.c           |   1 +
 gcc/c/c-parser.c                        |   3 +
 gcc/cp/parser.c                         |   6 +-
 gcc/cp/tree.c                           |   1 +
 gcc/go/go-gcc.cc                        |   2 +-
 gcc/testsuite/g++.dg/cpp0x/pr65558.C    |   2 +-
 gcc/testsuite/gcc.dg/parm-impl-decl-1.c |   2 +-
 gcc/testsuite/gcc.dg/parm-impl-decl-3.c |   2 +-
 gcc/tree-inline.c                       |   3 +-
 gcc/tree.c                              | 104 +++++---------------------------
 gcc/tree.h                              |  23 +------
 15 files changed, 88 insertions(+), 137 deletions(-)

diff --git a/gcc/attribs.h b/gcc/attribs.h
index 7f13332700e..a6b1ac1ff35 100644
--- a/gcc/attribs.h
+++ b/gcc/attribs.h
@@ -47,4 +47,53 @@ extern char *make_unique_name (tree, const char *, bool);
 extern tree make_dispatcher_decl (const tree);
 extern bool is_function_default_version (const tree);
 
+/* 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);
+  const char *s = IDENTIFIER_POINTER (attr_name);
+
+  if (l > 4 && s[0] == '_')
+    {
+      gcc_checking_assert (s[l - 2] == '_');
+      return get_identifier_with_length (s + 2, l - 4);
+    }
+
+  return attr_name;
+}
+
+/* Compare attribute identifiers ATTR1 and ATTR2 with length ATTR1_LEN and
+   ATTR2_LEN.  */
+
+static inline bool
+cmp_attribs (const char *attr1, size_t attr1_len,
+	     const char *attr2, size_t attr2_len)
+{
+  gcc_checking_assert (attr1_len == 0 || attr1[0] != '_');
+  gcc_checking_assert (attr2_len == 0 || attr2[0] != '_');
+
+  return attr1_len == attr2_len && strncmp (attr1, attr2, attr1_len) == 0;
+}
+
+/* Compare attribute identifiers ATTR1 and ATTR2.  */
+
+static inline bool
+cmp_attribs (const char *attr1, const char *attr2)
+{
+  return cmp_attribs (attr1, strlen (attr1), attr2, strlen (attr2));
+}
+
+/* Given an identifier node IDENT and a string ATTR_NAME, return true
+   if the identifier node is a valid attribute name for the string.  */
+
+static inline bool
+is_attribute_p (const char *attr_name, const_tree ident)
+{
+  return cmp_attribs (attr_name, strlen (attr_name),
+		      IDENTIFIER_POINTER (ident), IDENTIFIER_LENGTH (ident));
+}
+
 #endif // GCC_ATTRIBS_H
diff --git a/gcc/c-family/array-notation-common.c b/gcc/c-family/array-notation-common.c
index 3b95332adad..a4809948e20 100644
--- a/gcc/c-family/array-notation-common.c
+++ b/gcc/c-family/array-notation-common.c
@@ -27,6 +27,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "options.h"
 #include "c-family/c-common.h"
 #include "tree-iterator.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* Returns true if the function call in FNDECL is  __sec_implicit_index.  */
 
diff --git a/gcc/c-family/c-format.c b/gcc/c-family/c-format.c
index 732339b9b5e..f6e65384b3f 100644
--- a/gcc/c-family/c-format.c
+++ b/gcc/c-family/c-format.c
@@ -33,6 +33,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "substring-locations.h"
 #include "selftest.h"
 #include "builtins.h"
+#include "attribs.h"
 
 /* Handle attributes associated with format checking.  */
 
@@ -67,7 +68,6 @@ static bool check_format_string (tree argument,
 static bool get_constant (tree expr, unsigned HOST_WIDE_INT *value,
 			  int validated_p);
 static const char *convert_format_name_to_system_name (const char *attr_name);
-static bool cmp_attribs (const char *tattr_name, const char *attr_name);
 
 static int first_target_format_type;
 static const char *format_name (int format_num);
@@ -3975,24 +3975,6 @@ convert_format_name_to_system_name (const char *attr_name)
   return attr_name;
 }
 
-/* Return true if TATTR_NAME and ATTR_NAME are the same format attribute,
-   counting "name" and "__name__" as the same, false otherwise.  */
-static bool
-cmp_attribs (const char *tattr_name, const char *attr_name)
-{
-  int alen = strlen (attr_name);
-  int slen = (tattr_name ? strlen (tattr_name) : 0);
-  if (alen > 4 && attr_name[0] == '_' && attr_name[1] == '_'
-      && attr_name[alen - 1] == '_' && attr_name[alen - 2] == '_')
-    {
-      attr_name += 2;
-      alen -= 4;
-    }
-  if (alen != slen || strncmp (tattr_name, attr_name, alen) != 0)
-    return false;
-  return true;
-}
-
 /* Handle a "format" attribute; arguments as in
    struct attribute_spec.handler.  */
 tree
@@ -4021,6 +4003,10 @@ handle_format_attribute (tree *node, tree ARG_UNUSED (name), tree args,
     }
 #endif
 
+  /* Canonicalize name of format function.  */
+  if (TREE_CODE (TREE_VALUE (args)) == IDENTIFIER_NODE)
+    TREE_VALUE (args) = canonicalize_attr_name (TREE_VALUE (args));
+
   if (!decode_format_attr (args, &info, 0))
     {
       *no_add_attrs = true;
diff --git a/gcc/c-family/c-lex.c b/gcc/c-family/c-lex.c
index e1c8bdff986..3765a800a57 100644
--- a/gcc/c-family/c-lex.c
+++ b/gcc/c-family/c-lex.c
@@ -316,6 +316,7 @@ c_common_has_attribute (cpp_reader *pfile)
     {
       attr_name = get_identifier ((const char *)
 				  cpp_token_as_text (pfile, token));
+      attr_name = canonicalize_attr_name (attr_name);
       if (c_dialect_cxx ())
 	{
 	  int idx = 0;
diff --git a/gcc/c-family/c-pretty-print.c b/gcc/c-family/c-pretty-print.c
index fdb7b41f592..b8b8f665ef3 100644
--- a/gcc/c-family/c-pretty-print.c
+++ b/gcc/c-family/c-pretty-print.c
@@ -24,6 +24,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "c-pretty-print.h"
 #include "diagnostic.h"
 #include "stor-layout.h"
+#include "stringpool.h"
 #include "attribs.h"
 #include "intl.h"
 #include "tree-pretty-print.h"
diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
index f8fbc926172..e358b19a585 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -4170,9 +4170,11 @@ c_parser_attributes (c_parser *parser)
 	  attr_name = c_parser_attribute_any_word (parser);
 	  if (attr_name == NULL)
 	    break;
+	  attr_name = canonicalize_attr_name (attr_name);
 	  if (is_cilkplus_vector_p (attr_name))
 	    {
 	      c_token *v_token = c_parser_peek_token (parser);
+	      v_token->value = canonicalize_attr_name (v_token->value);
 	      c_parser_cilk_simd_fn_vector_attrs (parser, *v_token);
 	      /* If the next token isn't a comma, we're done.  */
 	      if (!c_parser_next_token_is (parser, CPP_COMMA))
@@ -4236,6 +4238,7 @@ c_parser_attributes (c_parser *parser)
 		  release_tree_vector (expr_list);
 		}
 	    }
+
 	  attr = build_tree_list (attr_name, attr_args);
 	  if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
 	    c_parser_consume_token (parser);
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index c81b1a1f5c1..7e5900122f2 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -24777,7 +24777,8 @@ cp_parser_gnu_attribute_list (cp_parser* parser)
 	       parsed identifier.  */
 	    ? ridpointers[(int) token->keyword]
 	    : id_token->u.value;
-	  
+
+	  identifier = canonicalize_attr_name (identifier);
 	  attribute = build_tree_list (identifier, NULL_TREE);
 
 	  /* Peek at the next token.  */
@@ -24923,6 +24924,8 @@ cp_parser_std_attribute (cp_parser *parser, tree attr_ns)
 		    "expected an identifier for the attribute name");
 	  return error_mark_node;
 	}
+
+      attr_id = canonicalize_attr_name (attr_id);
       attribute = build_tree_list (build_tree_list (attr_ns, attr_id),
 				   NULL_TREE);
       token = cp_lexer_peek_token (parser->lexer);
@@ -24932,6 +24935,7 @@ cp_parser_std_attribute (cp_parser *parser, tree attr_ns)
 				 NULL_TREE);
   else
     {
+      attr_id = canonicalize_attr_name (attr_id);
       attribute = build_tree_list (build_tree_list (NULL_TREE, attr_id),
 				   NULL_TREE);
       /* C++11 noreturn attribute is equivalent to GNU's.  */
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index c037b2c7440..900d2e13b18 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -32,6 +32,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "debug.h"
 #include "convert.h"
 #include "gimplify.h"
+#include "stringpool.h"
 #include "attribs.h"
 #include "flags.h"
 
diff --git a/gcc/go/go-gcc.cc b/gcc/go/go-gcc.cc
index a7977fe03c1..04912f0ed01 100644
--- a/gcc/go/go-gcc.cc
+++ b/gcc/go/go-gcc.cc
@@ -3046,7 +3046,7 @@ Gcc_backend::function(Btype* fntype, const std::string& name,
     DECL_UNINLINABLE(decl) = 1;
   if (disable_split_stack)
     {
-      tree attr = get_identifier("__no_split_stack__");
+      tree attr = get_identifier ("no_split_stack");
       DECL_ATTRIBUTES(decl) = tree_cons(attr, NULL_TREE, NULL_TREE);
     }
   if (in_unique_section)
diff --git a/gcc/testsuite/g++.dg/cpp0x/pr65558.C b/gcc/testsuite/g++.dg/cpp0x/pr65558.C
index d294c95a657..12946b35eda 100644
--- a/gcc/testsuite/g++.dg/cpp0x/pr65558.C
+++ b/gcc/testsuite/g++.dg/cpp0x/pr65558.C
@@ -2,6 +2,6 @@
 // { dg-do compile { target c++11 } }
 
 inline namespace
-__attribute__((__abi_tag__)) // { dg-warning "ignoring .__abi_tag__. attribute on anonymous namespace" }
+__attribute__((__abi_tag__)) // { dg-warning "ignoring .abi_tag. attribute on anonymous namespace" }
 {
 }
diff --git a/gcc/testsuite/gcc.dg/parm-impl-decl-1.c b/gcc/testsuite/gcc.dg/parm-impl-decl-1.c
index 5c7ddb0a259..c1219273c75 100644
--- a/gcc/testsuite/gcc.dg/parm-impl-decl-1.c
+++ b/gcc/testsuite/gcc.dg/parm-impl-decl-1.c
@@ -7,7 +7,7 @@
 /* Implicit function declaration in attribute in definition (testcase
    from bug).  */
 int
-foo (int __attribute__ ((__mode__ (vector_size(8)))) i) /* { dg-warning "'__mode__' attribute ignored" } */
+foo (int __attribute__ ((__mode__ (vector_size(8)))) i) /* { dg-warning "'mode' attribute ignored" } */
 {
   return (long long) i;
 }
diff --git a/gcc/testsuite/gcc.dg/parm-impl-decl-3.c b/gcc/testsuite/gcc.dg/parm-impl-decl-3.c
index 904295258d7..20197b52402 100644
--- a/gcc/testsuite/gcc.dg/parm-impl-decl-3.c
+++ b/gcc/testsuite/gcc.dg/parm-impl-decl-3.c
@@ -4,7 +4,7 @@
 /* { dg-options "-g -std=gnu89" } */
 
 int
-foo (int __attribute__ ((__mode__ (vector_size(8)))) i) /* { dg-warning "'__mode__' attribute ignored" } */
+foo (int __attribute__ ((__mode__ (vector_size(8)))) i) /* { dg-warning "'mode' attribute ignored" } */
 {
   return (long long) i;
 }
diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c
index d4e4ef17247..affde64d2fd 100644
--- a/gcc/tree-inline.c
+++ b/gcc/tree-inline.c
@@ -57,7 +57,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "cfgloop.h"
 #include "builtins.h"
 #include "tree-chkp.h"
-
+#include "stringpool.h"
+#include "attribs.h"
 
 /* I'm not real happy about this, but we need to handle gimple and
    non-gimple trees.  */
diff --git a/gcc/tree.c b/gcc/tree.c
index ca28afad0f2..13335a007b7 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -4928,9 +4928,8 @@ simple_cst_list_equal (const_tree l1, const_tree l2)
   return l1 == l2;
 }
 
-/* Compare two identifier nodes representing attributes.  Either one may
-   be in wrapped __ATTR__ form.  Return true if they are the same, false
-   otherwise.  */
+/* Compare two identifier nodes representing attributes.
+   Return true if they are the same, false otherwise.  */
 
 static bool
 cmp_attrib_identifiers (const_tree attr1, const_tree attr2)
@@ -4943,34 +4942,8 @@ cmp_attrib_identifiers (const_tree attr1, const_tree attr2)
   if (attr1 == attr2)
     return true;
 
-  /* If they are not equal, they may still be one in the form
-     'text' while the other one is in the form '__text__'.  TODO:
-     If we were storing attributes in normalized 'text' form, then
-     this could all go away and we could take full advantage of
-     the fact that we're comparing identifiers. :-)  */
-  const size_t attr1_len = IDENTIFIER_LENGTH (attr1);
-  const size_t attr2_len = IDENTIFIER_LENGTH (attr2);
-
-  if (attr2_len == attr1_len + 4)
-    {
-      const char *p = IDENTIFIER_POINTER (attr2);
-      const char *q = IDENTIFIER_POINTER (attr1);
-      if (p[0] == '_' && p[1] == '_'
-	  && p[attr2_len - 2] == '_' && p[attr2_len - 1] == '_'
-	  && strncmp (q, p + 2, attr1_len) == 0)
-	return true;;
-    }
-  else if (attr2_len + 4 == attr1_len)
-    {
-      const char *p = IDENTIFIER_POINTER (attr2);
-      const char *q = IDENTIFIER_POINTER (attr1);
-      if (q[0] == '_' && q[1] == '_'
-	  && q[attr1_len - 2] == '_' && q[attr1_len - 1] == '_'
-	  && strncmp (q + 2, p, attr2_len) == 0)
-	return true;
-    }
-
-  return false;
+  return cmp_attribs (IDENTIFIER_POINTER (attr1), IDENTIFIER_LENGTH (attr1),
+		      IDENTIFIER_POINTER (attr2), IDENTIFIER_LENGTH (attr2));
 }
 
 /* Compare two attributes for their value identity.  Return true if the
@@ -6043,32 +6016,6 @@ make_pass_ipa_free_lang_data (gcc::context *ctxt)
   return new pass_ipa_free_lang_data (ctxt);
 }
 
-/* The backbone of is_attribute_p().  ATTR_LEN is the string length of
-   ATTR_NAME.  Also used internally by remove_attribute().  */
-bool
-private_is_attribute_p (const char *attr_name, size_t attr_len, const_tree ident)
-{
-  size_t ident_len = IDENTIFIER_LENGTH (ident);
-
-  if (ident_len == attr_len)
-    {
-      if (id_equal (ident, attr_name))
-	return true;
-    }
-  else if (ident_len == attr_len + 4)
-    {
-      /* There is the possibility that ATTR is 'text' and IDENT is
-	 '__text__'.  */
-      const char *p = IDENTIFIER_POINTER (ident);      
-      if (p[0] == '_' && p[1] == '_'
-	  && p[ident_len - 2] == '_' && p[ident_len - 1] == '_'
-	  && strncmp (attr_name, p + 2, attr_len) == 0)
-	return true;
-    }
-
-  return false;
-}
-
 /* The backbone of lookup_attribute().  ATTR_LEN is the string length
    of ATTR_NAME, and LIST is not NULL_TREE.  */
 tree
@@ -6076,25 +6023,11 @@ private_lookup_attribute (const char *attr_name, size_t attr_len, tree list)
 {
   while (list)
     {
-      size_t ident_len = IDENTIFIER_LENGTH (get_attribute_name (list));
-
-      if (ident_len == attr_len)
-	{
-	  if (!strcmp (attr_name,
-		       IDENTIFIER_POINTER (get_attribute_name (list))))
-	    break;
-	}
-      /* TODO: If we made sure that attributes were stored in the
-	 canonical form without '__...__' (ie, as in 'text' as opposed
-	 to '__text__') then we could avoid the following case.  */
-      else if (ident_len == attr_len + 4)
-	{
-	  const char *p = IDENTIFIER_POINTER (get_attribute_name (list));
-	  if (p[0] == '_' && p[1] == '_'
-	      && p[ident_len - 2] == '_' && p[ident_len - 1] == '_'
-	      && strncmp (attr_name, p + 2, attr_len) == 0)
-	    break;
-	}
+      tree attr = get_attribute_name (list);
+      size_t ident_len = IDENTIFIER_LENGTH (attr);
+      if (cmp_attribs (attr_name, attr_len, IDENTIFIER_POINTER (attr),
+		       ident_len))
+	break;
       list = TREE_CHAIN (list);
     }
 
@@ -6103,8 +6036,7 @@ private_lookup_attribute (const char *attr_name, size_t attr_len, tree list)
 
 /* Given an attribute name ATTR_NAME and a list of attributes LIST,
    return a pointer to the attribute's list first element if the attribute
-   starts with ATTR_NAME. ATTR_NAME must be in the form 'text' (not
-   '__text__').  */
+   starts with ATTR_NAME.  */
 
 tree
 private_lookup_attribute_by_prefix (const char *attr_name, size_t attr_len,
@@ -6121,17 +6053,11 @@ private_lookup_attribute_by_prefix (const char *attr_name, size_t attr_len,
 	}
 
       const char *p = IDENTIFIER_POINTER (get_attribute_name (list));
+      gcc_checking_assert (attr_len == 0 || p[0] != '_');
 
       if (strncmp (attr_name, p, attr_len) == 0)
 	break;
 
-      /* TODO: If we made sure that attributes were stored in the
-	 canonical form without '__...__' (ie, as in 'text' as opposed
-	 to '__text__') then we could avoid the following case.  */
-      if (p[0] == '_' && p[1] == '_' &&
-	  strncmp (attr_name, p + 2, attr_len) == 0)
-	break;
-
       list = TREE_CHAIN (list);
     }
 
@@ -6177,16 +6103,14 @@ tree
 remove_attribute (const char *attr_name, tree list)
 {
   tree *p;
-  size_t attr_len = strlen (attr_name);
-
   gcc_checking_assert (attr_name[0] != '_');
 
   for (p = &list; *p; )
     {
       tree l = *p;
-      /* TODO: If we were storing attributes in normalized form, here
-	 we could use a simple strcmp().  */
-      if (private_is_attribute_p (attr_name, attr_len, get_attribute_name (l)))
+
+      tree attr = get_attribute_name (l);
+      if (is_attribute_p (attr_name, attr))
 	*p = TREE_CHAIN (l);
       else
 	p = &TREE_CHAIN (l);
diff --git a/gcc/tree.h b/gcc/tree.h
index 91cf253dee5..fab566b6684 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -4231,29 +4231,8 @@ lookup_attribute_by_prefix (const char *attr_name, tree list)
 					       list);
 }
 
-
-/* This function is a private implementation detail of
-   is_attribute_p() and you should never call it directly.  */
-extern bool private_is_attribute_p (const char *, size_t, const_tree);
-
-/* Given an identifier node IDENT and a string ATTR_NAME, return true
-   if the identifier node is a valid attribute name for the string.
-   ATTR_NAME must be in the form 'text' (not '__text__').  IDENT could
-   be the identifier for 'text' or for '__text__'.  */
-
-static inline bool
-is_attribute_p (const char *attr_name, const_tree ident)
-{
-  gcc_checking_assert (attr_name[0] != '_');
-  /* Do the strlen() before calling the out-of-line implementation.
-     In most cases attr_name is a string constant, and the compiler
-     will optimize the strlen() away.  */
-  return private_is_attribute_p (attr_name, strlen (attr_name), ident);
-}
-
 /* Remove any instances of attribute ATTR_NAME in LIST and return the
-   modified list.  ATTR_NAME must be in the form 'text' (not
-   '__text__').  */
+   modified list.  */
 
 extern tree remove_attribute (const char *, tree);
 
-- 
2.13.2


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

* [RFC][PATCH] Do refactoring of attribute functions and move them to attribs.[hc].
  2017-07-13 13:48                     ` Martin Liška
@ 2017-07-13 13:51                       ` Martin Liška
  2017-07-14  7:23                         ` Jeff Law
  2017-09-12  7:55                         ` Jakub Jelinek
  2017-07-27 12:57                       ` [PATCH v2][RFC] Canonize names of attributes Martin Liška
                                         ` (2 subsequent siblings)
  3 siblings, 2 replies; 37+ messages in thread
From: Martin Liška @ 2017-07-13 13:51 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Joseph Myers, gcc-patches List, Richard Biener

[-- Attachment #1: Type: text/plain, Size: 195 bytes --]

Hi.

It's request for comment where I mechanically moved attribute-related function to attribs.[hc].

Patch can bootstrap on ppc64le-redhat-linux and survives regression tests.

Thoughts?
Martin

[-- Attachment #2: 0001-Do-refactoring-of-attribute-functions-and-move-them-.patch --]
[-- Type: text/x-patch, Size: 83084 bytes --]

From f4322151ebcd8cf71fd677317ef0a74374b0db5e Mon Sep 17 00:00:00 2001
From: marxin <mliska@suse.cz>
Date: Wed, 12 Jul 2017 13:39:54 +0200
Subject: [PATCH] Do refactoring of attribute functions and move them to
 attribs.[hc].

---
 gcc/asan.c                |   2 +
 gcc/attribs.c             | 633 ++++++++++++++++++++++++++++++++++++++++++
 gcc/attribs.h             | 113 ++++++++
 gcc/bb-reorder.c          |   2 +
 gcc/builtins.c            |   2 +
 gcc/c-family/c-ada-spec.c |   2 +
 gcc/c-family/c-ubsan.c    |   4 +-
 gcc/c-family/c-warn.c     |   2 +
 gcc/c/c-convert.c         |   2 +
 gcc/c/c-typeck.c          |   2 +
 gcc/calls.c               |   2 +
 gcc/cfgexpand.c           |   2 +
 gcc/cgraph.c              |   2 +
 gcc/cgraphunit.c          |   2 +
 gcc/convert.c             |   2 +
 gcc/cp/call.c             |   2 +
 gcc/cp/cp-gimplify.c      |   2 +
 gcc/cp/cp-ubsan.c         |   2 +
 gcc/cp/cvt.c              |   2 +
 gcc/cp/init.c             |   2 +
 gcc/cp/search.c           |   2 +
 gcc/cp/semantics.c        |   2 +
 gcc/cp/typeck.c           |   2 +
 gcc/dwarf2out.c           |   2 +
 gcc/final.c               |   2 +
 gcc/fold-const.c          |   2 +
 gcc/fortran/trans-types.c |   1 +
 gcc/function.c            |   2 +
 gcc/gimple-expr.c         |   2 +
 gcc/gimple-fold.c         |   2 +
 gcc/gimple-pretty-print.c |   2 +
 gcc/gimple.c              |   2 +
 gcc/gimplify.c            |   2 +
 gcc/hsa-common.c          |   2 +
 gcc/hsa-gen.c             |   2 +
 gcc/internal-fn.c         |   2 +
 gcc/ipa-chkp.c            |   2 +
 gcc/ipa-cp.c              |   2 +
 gcc/ipa-devirt.c          |   2 +
 gcc/ipa-fnsummary.c       |   2 +
 gcc/ipa-inline.c          |   2 +
 gcc/ipa-visibility.c      |   2 +
 gcc/ipa.c                 |   3 +-
 gcc/lto-cgraph.c          |   2 +
 gcc/lto/lto-lang.c        |   2 +
 gcc/lto/lto-symtab.c      |   2 +
 gcc/omp-expand.c          |   3 +-
 gcc/omp-general.c         |   3 +-
 gcc/omp-low.c             |   2 +
 gcc/omp-offload.c         |   2 +
 gcc/omp-simd-clone.c      |   3 +-
 gcc/opts-global.c         |   2 +
 gcc/passes.c              |   2 +
 gcc/predict.c             |   2 +
 gcc/sancov.c              |   2 +
 gcc/sanopt.c              |   2 +
 gcc/symtab.c              |   2 +
 gcc/toplev.c              |   2 +
 gcc/trans-mem.c           |   3 +-
 gcc/tree-chkp.c           |   2 +
 gcc/tree-eh.c             |   2 +
 gcc/tree-into-ssa.c       |   2 +
 gcc/tree-object-size.c    |   2 +
 gcc/tree-parloops.c       |   2 +
 gcc/tree-profile.c        |   2 +
 gcc/tree-ssa-ccp.c        |   2 +
 gcc/tree-ssa-live.c       |   2 +
 gcc/tree-ssa-loop.c       |   2 +
 gcc/tree-ssa-sccvn.c      |   2 +
 gcc/tree-ssa.c            |   2 +
 gcc/tree-streamer-in.c    |   2 +
 gcc/tree-vectorizer.c     |   2 +
 gcc/tree-vrp.c            |   2 +
 gcc/tree.c                | 685 +---------------------------------------------
 gcc/tree.h                |  86 ------
 gcc/tsan.c                |   2 +
 gcc/ubsan.c               |   2 +
 gcc/varasm.c              |   2 +
 gcc/varpool.c             |   2 +
 79 files changed, 898 insertions(+), 775 deletions(-)

diff --git a/gcc/asan.c b/gcc/asan.c
index 89c2731e8cd..23686358a08 100644
--- a/gcc/asan.c
+++ b/gcc/asan.c
@@ -47,6 +47,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "varasm.h"
 #include "stor-layout.h"
 #include "tree-iterator.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 #include "dojump.h"
 #include "explow.h"
diff --git a/gcc/attribs.c b/gcc/attribs.c
index 5eb19e82795..a1e52653edd 100644
--- a/gcc/attribs.c
+++ b/gcc/attribs.c
@@ -925,3 +925,636 @@ is_function_default_version (const tree decl)
   return (TREE_CODE (attr) == STRING_CST
 	  && strcmp (TREE_STRING_POINTER (attr), "default") == 0);
 }
+
+/* Return a declaration like DDECL except that its DECL_ATTRIBUTES
+   is ATTRIBUTE.  */
+
+tree
+build_decl_attribute_variant (tree ddecl, tree attribute)
+{
+  DECL_ATTRIBUTES (ddecl) = attribute;
+  return ddecl;
+}
+
+/* Return a type like TTYPE except that its TYPE_ATTRIBUTE
+   is ATTRIBUTE and its qualifiers are QUALS.
+
+   Record such modified types already made so we don't make duplicates.  */
+
+tree
+build_type_attribute_qual_variant (tree ttype, tree attribute, int quals)
+{
+  if (! attribute_list_equal (TYPE_ATTRIBUTES (ttype), attribute))
+    {
+      tree ntype;
+
+      /* Building a distinct copy of a tagged type is inappropriate; it
+	 causes breakage in code that expects there to be a one-to-one
+	 relationship between a struct and its fields.
+	 build_duplicate_type is another solution (as used in
+	 handle_transparent_union_attribute), but that doesn't play well
+	 with the stronger C++ type identity model.  */
+      if (TREE_CODE (ttype) == RECORD_TYPE
+	  || TREE_CODE (ttype) == UNION_TYPE
+	  || TREE_CODE (ttype) == QUAL_UNION_TYPE
+	  || TREE_CODE (ttype) == ENUMERAL_TYPE)
+	{
+	  warning (OPT_Wattributes,
+		   "ignoring attributes applied to %qT after definition",
+		   TYPE_MAIN_VARIANT (ttype));
+	  return build_qualified_type (ttype, quals);
+	}
+
+      ttype = build_qualified_type (ttype, TYPE_UNQUALIFIED);
+      ntype = build_distinct_type_copy (ttype);
+
+      TYPE_ATTRIBUTES (ntype) = attribute;
+
+      hashval_t hash = type_hash_canon_hash (ntype);
+      ntype = type_hash_canon (hash, ntype);
+
+      /* If the target-dependent attributes make NTYPE different from
+	 its canonical type, we will need to use structural equality
+	 checks for this type. */
+      if (TYPE_STRUCTURAL_EQUALITY_P (ttype)
+          || !comp_type_attributes (ntype, ttype))
+	SET_TYPE_STRUCTURAL_EQUALITY (ntype);
+      else if (TYPE_CANONICAL (ntype) == ntype)
+	TYPE_CANONICAL (ntype) = TYPE_CANONICAL (ttype);
+
+      ttype = build_qualified_type (ntype, quals);
+    }
+  else if (TYPE_QUALS (ttype) != quals)
+    ttype = build_qualified_type (ttype, quals);
+
+  return ttype;
+}
+
+/* Compare two identifier nodes representing attributes.
+   Return true if they are the same, false otherwise.  */
+
+static bool
+cmp_attrib_identifiers (const_tree attr1, const_tree attr2)
+{
+  /* Make sure we're dealing with IDENTIFIER_NODEs.  */
+  gcc_checking_assert (TREE_CODE (attr1) == IDENTIFIER_NODE
+		       && TREE_CODE (attr2) == IDENTIFIER_NODE);
+
+  /* Identifiers can be compared directly for equality.  */
+  if (attr1 == attr2)
+    return true;
+
+  return cmp_attribs (IDENTIFIER_POINTER (attr1), IDENTIFIER_LENGTH (attr1),
+		      IDENTIFIER_POINTER (attr2), IDENTIFIER_LENGTH (attr2));
+}
+
+/* Compare two constructor-element-type constants.  Return 1 if the lists
+   are known to be equal; otherwise return 0.  */
+
+static bool
+simple_cst_list_equal (const_tree l1, const_tree l2)
+{
+  while (l1 != NULL_TREE && l2 != NULL_TREE)
+    {
+      if (simple_cst_equal (TREE_VALUE (l1), TREE_VALUE (l2)) != 1)
+	return false;
+
+      l1 = TREE_CHAIN (l1);
+      l2 = TREE_CHAIN (l2);
+    }
+
+  return l1 == l2;
+}
+
+/* Check if "omp declare simd" attribute arguments, CLAUSES1 and CLAUSES2, are
+   the same.  */
+
+static bool
+omp_declare_simd_clauses_equal (tree clauses1, tree clauses2)
+{
+  tree cl1, cl2;
+  for (cl1 = clauses1, cl2 = clauses2;
+       cl1 && cl2;
+       cl1 = OMP_CLAUSE_CHAIN (cl1), cl2 = OMP_CLAUSE_CHAIN (cl2))
+    {
+      if (OMP_CLAUSE_CODE (cl1) != OMP_CLAUSE_CODE (cl2))
+	return false;
+      if (OMP_CLAUSE_CODE (cl1) != OMP_CLAUSE_SIMDLEN)
+	{
+	  if (simple_cst_equal (OMP_CLAUSE_DECL (cl1),
+				OMP_CLAUSE_DECL (cl2)) != 1)
+	    return false;
+	}
+      switch (OMP_CLAUSE_CODE (cl1))
+	{
+	case OMP_CLAUSE_ALIGNED:
+	  if (simple_cst_equal (OMP_CLAUSE_ALIGNED_ALIGNMENT (cl1),
+				OMP_CLAUSE_ALIGNED_ALIGNMENT (cl2)) != 1)
+	    return false;
+	  break;
+	case OMP_CLAUSE_LINEAR:
+	  if (simple_cst_equal (OMP_CLAUSE_LINEAR_STEP (cl1),
+				OMP_CLAUSE_LINEAR_STEP (cl2)) != 1)
+	    return false;
+	  break;
+	case OMP_CLAUSE_SIMDLEN:
+	  if (simple_cst_equal (OMP_CLAUSE_SIMDLEN_EXPR (cl1),
+				OMP_CLAUSE_SIMDLEN_EXPR (cl2)) != 1)
+	    return false;
+	default:
+	  break;
+	}
+    }
+  return true;
+}
+
+
+/* Compare two attributes for their value identity.  Return true if the
+   attribute values are known to be equal; otherwise return false.  */
+
+bool
+attribute_value_equal (const_tree attr1, const_tree attr2)
+{
+  if (TREE_VALUE (attr1) == TREE_VALUE (attr2))
+    return true;
+
+  if (TREE_VALUE (attr1) != NULL_TREE
+      && TREE_CODE (TREE_VALUE (attr1)) == TREE_LIST
+      && TREE_VALUE (attr2) != NULL_TREE
+      && TREE_CODE (TREE_VALUE (attr2)) == TREE_LIST)
+    {
+      /* Handle attribute format.  */
+      if (is_attribute_p ("format", get_attribute_name (attr1)))
+	{
+	  attr1 = TREE_VALUE (attr1);
+	  attr2 = TREE_VALUE (attr2);
+	  /* Compare the archetypes (printf/scanf/strftime/...).  */
+	  if (!cmp_attrib_identifiers (TREE_VALUE (attr1), TREE_VALUE (attr2)))
+	    return false;
+	  /* Archetypes are the same.  Compare the rest.  */
+	  return (simple_cst_list_equal (TREE_CHAIN (attr1),
+					 TREE_CHAIN (attr2)) == 1);
+	}
+      return (simple_cst_list_equal (TREE_VALUE (attr1),
+				     TREE_VALUE (attr2)) == 1);
+    }
+
+  if ((flag_openmp || flag_openmp_simd)
+      && TREE_VALUE (attr1) && TREE_VALUE (attr2)
+      && TREE_CODE (TREE_VALUE (attr1)) == OMP_CLAUSE
+      && TREE_CODE (TREE_VALUE (attr2)) == OMP_CLAUSE)
+    return omp_declare_simd_clauses_equal (TREE_VALUE (attr1),
+					   TREE_VALUE (attr2));
+
+  return (simple_cst_equal (TREE_VALUE (attr1), TREE_VALUE (attr2)) == 1);
+}
+
+/* Return 0 if the attributes for two types are incompatible, 1 if they
+   are compatible, and 2 if they are nearly compatible (which causes a
+   warning to be generated).  */
+int
+comp_type_attributes (const_tree type1, const_tree type2)
+{
+  const_tree a1 = TYPE_ATTRIBUTES (type1);
+  const_tree a2 = TYPE_ATTRIBUTES (type2);
+  const_tree a;
+
+  if (a1 == a2)
+    return 1;
+  for (a = a1; a != NULL_TREE; a = TREE_CHAIN (a))
+    {
+      const struct attribute_spec *as;
+      const_tree attr;
+
+      as = lookup_attribute_spec (get_attribute_name (a));
+      if (!as || as->affects_type_identity == false)
+        continue;
+
+      attr = lookup_attribute (as->name, CONST_CAST_TREE (a2));
+      if (!attr || !attribute_value_equal (a, attr))
+        break;
+    }
+  if (!a)
+    {
+      for (a = a2; a != NULL_TREE; a = TREE_CHAIN (a))
+	{
+	  const struct attribute_spec *as;
+
+	  as = lookup_attribute_spec (get_attribute_name (a));
+	  if (!as || as->affects_type_identity == false)
+	    continue;
+
+	  if (!lookup_attribute (as->name, CONST_CAST_TREE (a1)))
+	    break;
+	  /* We don't need to compare trees again, as we did this
+	     already in first loop.  */
+	}
+      /* All types - affecting identity - are equal, so
+         there is no need to call target hook for comparison.  */
+      if (!a)
+        return 1;
+    }
+  if (lookup_attribute ("transaction_safe", CONST_CAST_TREE (a)))
+    return 0;
+  /* As some type combinations - like default calling-convention - might
+     be compatible, we have to call the target hook to get the final result.  */
+  return targetm.comp_type_attributes (type1, type2);
+}
+
+/* Return a type like TTYPE except that its TYPE_ATTRIBUTE
+   is ATTRIBUTE.
+
+   Record such modified types already made so we don't make duplicates.  */
+
+tree
+build_type_attribute_variant (tree ttype, tree attribute)
+{
+  return build_type_attribute_qual_variant (ttype, attribute,
+					    TYPE_QUALS (ttype));
+}
+\f
+/* A variant of lookup_attribute() that can be used with an identifier
+   as the first argument, and where the identifier can be either
+   'text' or '__text__'.
+
+   Given an attribute ATTR_IDENTIFIER, and a list of attributes LIST,
+   return a pointer to the attribute's list element if the attribute
+   is part of the list, or NULL_TREE if not found.  If the attribute
+   appears more than once, this only returns the first occurrence; the
+   TREE_CHAIN of the return value should be passed back in if further
+   occurrences are wanted.  ATTR_IDENTIFIER must be an identifier but
+   can be in the form 'text' or '__text__'.  */
+static tree
+lookup_ident_attribute (tree attr_identifier, tree list)
+{
+  gcc_checking_assert (TREE_CODE (attr_identifier) == IDENTIFIER_NODE);
+
+  while (list)
+    {
+      gcc_checking_assert (TREE_CODE (get_attribute_name (list))
+			   == IDENTIFIER_NODE);
+
+      if (cmp_attrib_identifiers (attr_identifier,
+				  get_attribute_name (list)))
+	/* Found it.  */
+	break;
+      list = TREE_CHAIN (list);
+    }
+
+  return list;
+}
+
+/* Remove any instances of attribute ATTR_NAME in LIST and return the
+   modified list.  */
+
+tree
+remove_attribute (const char *attr_name, tree list)
+{
+  tree *p;
+  gcc_checking_assert (attr_name[0] != '_');
+
+  for (p = &list; *p; )
+    {
+      tree l = *p;
+
+      tree attr = get_attribute_name (l);
+      if (is_attribute_p (attr_name, attr))
+	*p = TREE_CHAIN (l);
+      else
+	p = &TREE_CHAIN (l);
+    }
+
+  return list;
+}
+
+/* Return an attribute list that is the union of a1 and a2.  */
+
+tree
+merge_attributes (tree a1, tree a2)
+{
+  tree attributes;
+
+  /* Either one unset?  Take the set one.  */
+
+  if ((attributes = a1) == 0)
+    attributes = a2;
+
+  /* One that completely contains the other?  Take it.  */
+
+  else if (a2 != 0 && ! attribute_list_contained (a1, a2))
+    {
+      if (attribute_list_contained (a2, a1))
+	attributes = a2;
+      else
+	{
+	  /* Pick the longest list, and hang on the other list.  */
+
+	  if (list_length (a1) < list_length (a2))
+	    attributes = a2, a2 = a1;
+
+	  for (; a2 != 0; a2 = TREE_CHAIN (a2))
+	    {
+	      tree a;
+	      for (a = lookup_ident_attribute (get_attribute_name (a2),
+					       attributes);
+		   a != NULL_TREE && !attribute_value_equal (a, a2);
+		   a = lookup_ident_attribute (get_attribute_name (a2),
+					       TREE_CHAIN (a)))
+		;
+	      if (a == NULL_TREE)
+		{
+		  a1 = copy_node (a2);
+		  TREE_CHAIN (a1) = attributes;
+		  attributes = a1;
+		}
+	    }
+	}
+    }
+  return attributes;
+}
+
+/* Given types T1 and T2, merge their attributes and return
+  the result.  */
+
+tree
+merge_type_attributes (tree t1, tree t2)
+{
+  return merge_attributes (TYPE_ATTRIBUTES (t1),
+			   TYPE_ATTRIBUTES (t2));
+}
+
+/* Given decls OLDDECL and NEWDECL, merge their attributes and return
+   the result.  */
+
+tree
+merge_decl_attributes (tree olddecl, tree newdecl)
+{
+  return merge_attributes (DECL_ATTRIBUTES (olddecl),
+			   DECL_ATTRIBUTES (newdecl));
+}
+
+#if TARGET_DLLIMPORT_DECL_ATTRIBUTES
+
+/* Specialization of merge_decl_attributes for various Windows targets.
+
+   This handles the following situation:
+
+     __declspec (dllimport) int foo;
+     int foo;
+
+   The second instance of `foo' nullifies the dllimport.  */
+
+tree
+merge_dllimport_decl_attributes (tree old, tree new_tree)
+{
+  tree a;
+  int delete_dllimport_p = 1;
+
+  /* What we need to do here is remove from `old' dllimport if it doesn't
+     appear in `new'.  dllimport behaves like extern: if a declaration is
+     marked dllimport and a definition appears later, then the object
+     is not dllimport'd.  We also remove a `new' dllimport if the old list
+     contains dllexport:  dllexport always overrides dllimport, regardless
+     of the order of declaration.  */
+  if (!VAR_OR_FUNCTION_DECL_P (new_tree))
+    delete_dllimport_p = 0;
+  else if (DECL_DLLIMPORT_P (new_tree)
+     	   && lookup_attribute ("dllexport", DECL_ATTRIBUTES (old)))
+    {
+      DECL_DLLIMPORT_P (new_tree) = 0;
+      warning (OPT_Wattributes, "%q+D already declared with dllexport attribute: "
+	      "dllimport ignored", new_tree);
+    }
+  else if (DECL_DLLIMPORT_P (old) && !DECL_DLLIMPORT_P (new_tree))
+    {
+      /* Warn about overriding a symbol that has already been used, e.g.:
+           extern int __attribute__ ((dllimport)) foo;
+	   int* bar () {return &foo;}
+	   int foo;
+      */
+      if (TREE_USED (old))
+	{
+	  warning (0, "%q+D redeclared without dllimport attribute "
+		   "after being referenced with dll linkage", new_tree);
+	  /* If we have used a variable's address with dllimport linkage,
+	      keep the old DECL_DLLIMPORT_P flag: the ADDR_EXPR using the
+	      decl may already have had TREE_CONSTANT computed.
+	      We still remove the attribute so that assembler code refers
+	      to '&foo rather than '_imp__foo'.  */
+	  if (VAR_P (old) && TREE_ADDRESSABLE (old))
+	    DECL_DLLIMPORT_P (new_tree) = 1;
+	}
+
+      /* Let an inline definition silently override the external reference,
+	 but otherwise warn about attribute inconsistency.  */
+      else if (VAR_P (new_tree) || !DECL_DECLARED_INLINE_P (new_tree))
+	warning (OPT_Wattributes, "%q+D redeclared without dllimport attribute: "
+		  "previous dllimport ignored", new_tree);
+    }
+  else
+    delete_dllimport_p = 0;
+
+  a = merge_attributes (DECL_ATTRIBUTES (old), DECL_ATTRIBUTES (new_tree));
+
+  if (delete_dllimport_p)
+    a = remove_attribute ("dllimport", a);
+
+  return a;
+}
+
+/* Handle a "dllimport" or "dllexport" attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+tree
+handle_dll_attribute (tree * pnode, tree name, tree args, int flags,
+		      bool *no_add_attrs)
+{
+  tree node = *pnode;
+  bool is_dllimport;
+
+  /* These attributes may apply to structure and union types being created,
+     but otherwise should pass to the declaration involved.  */
+  if (!DECL_P (node))
+    {
+      if (flags & ((int) ATTR_FLAG_DECL_NEXT | (int) ATTR_FLAG_FUNCTION_NEXT
+		   | (int) ATTR_FLAG_ARRAY_NEXT))
+	{
+	  *no_add_attrs = true;
+	  return tree_cons (name, args, NULL_TREE);
+	}
+      if (TREE_CODE (node) == RECORD_TYPE
+	  || TREE_CODE (node) == UNION_TYPE)
+	{
+	  node = TYPE_NAME (node);
+	  if (!node)
+	    return NULL_TREE;
+	}
+      else
+	{
+	  warning (OPT_Wattributes, "%qE attribute ignored",
+		   name);
+	  *no_add_attrs = true;
+	  return NULL_TREE;
+	}
+    }
+
+  if (!VAR_OR_FUNCTION_DECL_P (node) && TREE_CODE (node) != TYPE_DECL)
+    {
+      *no_add_attrs = true;
+      warning (OPT_Wattributes, "%qE attribute ignored",
+	       name);
+      return NULL_TREE;
+    }
+
+  if (TREE_CODE (node) == TYPE_DECL
+      && TREE_CODE (TREE_TYPE (node)) != RECORD_TYPE
+      && TREE_CODE (TREE_TYPE (node)) != UNION_TYPE)
+    {
+      *no_add_attrs = true;
+      warning (OPT_Wattributes, "%qE attribute ignored",
+	       name);
+      return NULL_TREE;
+    }
+
+  is_dllimport = is_attribute_p ("dllimport", name);
+
+  /* Report error on dllimport ambiguities seen now before they cause
+     any damage.  */
+  if (is_dllimport)
+    {
+      /* Honor any target-specific overrides. */
+      if (!targetm.valid_dllimport_attribute_p (node))
+	*no_add_attrs = true;
+
+     else if (TREE_CODE (node) == FUNCTION_DECL
+	        && DECL_DECLARED_INLINE_P (node))
+	{
+	  warning (OPT_Wattributes, "inline function %q+D declared as "
+		  " dllimport: attribute ignored", node);
+	  *no_add_attrs = true;
+	}
+      /* Like MS, treat definition of dllimported variables and
+	 non-inlined functions on declaration as syntax errors. */
+     else if (TREE_CODE (node) == FUNCTION_DECL && DECL_INITIAL (node))
+	{
+	  error ("function %q+D definition is marked dllimport", node);
+	  *no_add_attrs = true;
+	}
+
+     else if (VAR_P (node))
+	{
+	  if (DECL_INITIAL (node))
+	    {
+	      error ("variable %q+D definition is marked dllimport",
+		     node);
+	      *no_add_attrs = true;
+	    }
+
+	  /* `extern' needn't be specified with dllimport.
+	     Specify `extern' now and hope for the best.  Sigh.  */
+	  DECL_EXTERNAL (node) = 1;
+	  /* Also, implicitly give dllimport'd variables declared within
+	     a function global scope, unless declared static.  */
+	  if (current_function_decl != NULL_TREE && !TREE_STATIC (node))
+	    TREE_PUBLIC (node) = 1;
+	}
+
+      if (*no_add_attrs == false)
+        DECL_DLLIMPORT_P (node) = 1;
+    }
+  else if (TREE_CODE (node) == FUNCTION_DECL
+	   && DECL_DECLARED_INLINE_P (node)
+	   && flag_keep_inline_dllexport)
+    /* An exported function, even if inline, must be emitted.  */
+    DECL_EXTERNAL (node) = 0;
+
+  /*  Report error if symbol is not accessible at global scope.  */
+  if (!TREE_PUBLIC (node) && VAR_OR_FUNCTION_DECL_P (node))
+    {
+      error ("external linkage required for symbol %q+D because of "
+	     "%qE attribute", node, name);
+      *no_add_attrs = true;
+    }
+
+  /* A dllexport'd entity must have default visibility so that other
+     program units (shared libraries or the main executable) can see
+     it.  A dllimport'd entity must have default visibility so that
+     the linker knows that undefined references within this program
+     unit can be resolved by the dynamic linker.  */
+  if (!*no_add_attrs)
+    {
+      if (DECL_VISIBILITY_SPECIFIED (node)
+	  && DECL_VISIBILITY (node) != VISIBILITY_DEFAULT)
+	error ("%qE implies default visibility, but %qD has already "
+	       "been declared with a different visibility",
+	       name, node);
+      DECL_VISIBILITY (node) = VISIBILITY_DEFAULT;
+      DECL_VISIBILITY_SPECIFIED (node) = 1;
+    }
+
+  return NULL_TREE;
+}
+
+#endif /* TARGET_DLLIMPORT_DECL_ATTRIBUTES  */
+
+/* Given two lists of attributes, return true if list l2 is
+   equivalent to l1.  */
+
+int
+attribute_list_equal (const_tree l1, const_tree l2)
+{
+  if (l1 == l2)
+    return 1;
+
+  return attribute_list_contained (l1, l2)
+	 && attribute_list_contained (l2, l1);
+}
+
+/* Given two lists of attributes, return true if list L2 is
+   completely contained within L1.  */
+/* ??? This would be faster if attribute names were stored in a canonicalized
+   form.  Otherwise, if L1 uses `foo' and L2 uses `__foo__', the long method
+   must be used to show these elements are equivalent (which they are).  */
+/* ??? It's not clear that attributes with arguments will always be handled
+   correctly.  */
+
+int
+attribute_list_contained (const_tree l1, const_tree l2)
+{
+  const_tree t1, t2;
+
+  /* First check the obvious, maybe the lists are identical.  */
+  if (l1 == l2)
+    return 1;
+
+  /* Maybe the lists are similar.  */
+  for (t1 = l1, t2 = l2;
+       t1 != 0 && t2 != 0
+        && get_attribute_name (t1) == get_attribute_name (t2)
+        && TREE_VALUE (t1) == TREE_VALUE (t2);
+       t1 = TREE_CHAIN (t1), t2 = TREE_CHAIN (t2))
+    ;
+
+  /* Maybe the lists are equal.  */
+  if (t1 == 0 && t2 == 0)
+    return 1;
+
+  for (; t2 != 0; t2 = TREE_CHAIN (t2))
+    {
+      const_tree attr;
+      /* This CONST_CAST is okay because lookup_attribute does not
+	 modify its argument and the return value is assigned to a
+	 const_tree.  */
+      for (attr = lookup_ident_attribute (get_attribute_name (t2),
+					  CONST_CAST_TREE (l1));
+	   attr != NULL_TREE && !attribute_value_equal (t2, attr);
+	   attr = lookup_ident_attribute (get_attribute_name (t2),
+					  TREE_CHAIN (attr)))
+	;
+
+      if (attr == NULL_TREE)
+	return 0;
+    }
+
+  return 1;
+}
diff --git a/gcc/attribs.h b/gcc/attribs.h
index a6b1ac1ff35..4cb9beaa483 100644
--- a/gcc/attribs.h
+++ b/gcc/attribs.h
@@ -47,6 +47,46 @@ extern char *make_unique_name (tree, const char *, bool);
 extern tree make_dispatcher_decl (const tree);
 extern bool is_function_default_version (const tree);
 
+/* Return a type like TTYPE except that its TYPE_ATTRIBUTES
+   is ATTRIBUTE.
+
+   Such modified types already made are recorded so that duplicates
+   are not made.  */
+
+extern tree build_type_attribute_variant (tree, tree);
+extern tree build_decl_attribute_variant (tree, tree);
+extern tree build_type_attribute_qual_variant (tree, tree, int);
+
+extern bool attribute_value_equal (const_tree, const_tree);
+
+/* Return 0 if the attributes for two types are incompatible, 1 if they
+   are compatible, and 2 if they are nearly compatible (which causes a
+   warning to be generated).  */
+extern int comp_type_attributes (const_tree, const_tree);
+
+/* Default versions of target-overridable functions.  */
+extern tree merge_decl_attributes (tree, tree);
+extern tree merge_type_attributes (tree, tree);
+
+/* Remove any instances of attribute ATTR_NAME in LIST and return the
+   modified list.  */
+
+extern tree remove_attribute (const char *, tree);
+
+/* Given two attributes lists, return a list of their union.  */
+
+extern tree merge_attributes (tree, tree);
+
+/* Given two Windows decl attributes lists, possibly including
+   dllimport, return a list of their union .  */
+extern tree merge_dllimport_decl_attributes (tree, tree);
+
+/* Handle a "dllimport" or "dllexport" attribute.  */
+extern tree handle_dll_attribute (tree *, tree, tree, int, bool *);
+
+extern int attribute_list_equal (const_tree, const_tree);
+extern int attribute_list_contained (const_tree, const_tree);
+
 /* For a given IDENTIFIER_NODE, strip leading and trailing '_' characters
    so that we have a canonical form of attribute names.  */
 
@@ -96,4 +136,77 @@ is_attribute_p (const char *attr_name, const_tree ident)
 		      IDENTIFIER_POINTER (ident), IDENTIFIER_LENGTH (ident));
 }
 
+/* Given an attribute name ATTR_NAME and a list of attributes LIST,
+   return a pointer to the attribute's list element if the attribute
+   is part of the list, or NULL_TREE if not found.  If the attribute
+   appears more than once, this only returns the first occurrence; the
+   TREE_CHAIN of the return value should be passed back in if further
+   occurrences are wanted.  ATTR_NAME must be in the form 'text' (not
+   '__text__').  */
+
+static inline tree
+lookup_attribute (const char *attr_name, tree list)
+{
+  gcc_checking_assert (attr_name[0] != '_');  
+  /* In most cases, list is NULL_TREE.  */
+  if (list == NULL_TREE)
+    return NULL_TREE;
+  else
+    {
+      size_t attr_len = strlen (attr_name);
+      /* Do the strlen() before calling the out-of-line implementation.
+	 In most cases attr_name is a string constant, and the compiler
+	 will optimize the strlen() away.  */
+      while (list)
+	{
+	  tree attr = get_attribute_name (list);
+	  size_t ident_len = IDENTIFIER_LENGTH (attr);
+	  if (cmp_attribs (attr_name, attr_len, IDENTIFIER_POINTER (attr),
+			   ident_len))
+	    break;
+	  list = TREE_CHAIN (list);
+	}
+
+      return list;
+    }
+}
+
+/* Given an attribute name ATTR_NAME and a list of attributes LIST,
+   return a pointer to the attribute's list first element if the attribute
+   starts with ATTR_NAME. ATTR_NAME must be in the form 'text' (not
+   '__text__').  */
+
+static inline tree
+lookup_attribute_by_prefix (const char *attr_name, tree list)
+{
+  gcc_checking_assert (attr_name[0] != '_');
+  /* In most cases, list is NULL_TREE.  */
+  if (list == NULL_TREE)
+    return NULL_TREE;
+  else
+    {
+      size_t attr_len = strlen (attr_name);
+      while (list)
+	{
+	  size_t ident_len = IDENTIFIER_LENGTH (get_attribute_name (list));
+
+	  if (attr_len > ident_len)
+	    {
+	      list = TREE_CHAIN (list);
+	      continue;
+	    }
+
+	  const char *p = IDENTIFIER_POINTER (get_attribute_name (list));
+	  gcc_checking_assert (attr_len == 0 || p[0] != '_');
+
+	  if (strncmp (attr_name, p, attr_len) == 0)
+	    break;
+
+	  list = TREE_CHAIN (list);
+	}
+
+      return list;
+    }
+}
+
 #endif // GCC_ATTRIBS_H
diff --git a/gcc/bb-reorder.c b/gcc/bb-reorder.c
index a421f6b3c71..ff67d8d846d 100644
--- a/gcc/bb-reorder.c
+++ b/gcc/bb-reorder.c
@@ -115,6 +115,8 @@
 #include "bb-reorder.h"
 #include "except.h"
 #include "fibonacci_heap.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* The number of rounds.  In most cases there will only be 4 rounds, but
    when partitioning hot and cold basic blocks into separate sections of
diff --git a/gcc/builtins.c b/gcc/builtins.c
index 2deef725620..3ef10cf8a1e 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -60,6 +60,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "langhooks.h"
 #include "value-prof.h"
 #include "builtins.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 #include "cilk.h"
 #include "tree-chkp.h"
diff --git a/gcc/c-family/c-ada-spec.c b/gcc/c-family/c-ada-spec.c
index 6cf298a126a..8ee0c9a088c 100644
--- a/gcc/c-family/c-ada-spec.c
+++ b/gcc/c-family/c-ada-spec.c
@@ -28,6 +28,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "fold-const.h"
 #include "c-pragma.h"
 #include "cpp-id-data.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* Local functions, macros and variables.  */
 static int dump_generic_ada_node (pretty_printer *, tree, tree, int, int,
diff --git a/gcc/c-family/c-ubsan.c b/gcc/c-family/c-ubsan.c
index a072d19eda6..1295cfadcd0 100644
--- a/gcc/c-family/c-ubsan.c
+++ b/gcc/c-family/c-ubsan.c
@@ -25,10 +25,12 @@ along with GCC; see the file COPYING3.  If not see
 #include "c-family/c-common.h"
 #include "ubsan.h"
 #include "c-family/c-ubsan.h"
-#include "asan.h"
 #include "stor-layout.h"
 #include "builtins.h"
 #include "gimplify.h"
+#include "stringpool.h"
+#include "attribs.h"
+#include "asan.h"
 
 /* Instrument division by zero and INT_MIN / -1.  If not instrumenting,
    return NULL_TREE.  */
diff --git a/gcc/c-family/c-warn.c b/gcc/c-family/c-warn.c
index b9378c2dbe2..21e64811630 100644
--- a/gcc/c-family/c-warn.c
+++ b/gcc/c-family/c-warn.c
@@ -28,6 +28,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "tm_p.h"
 #include "diagnostic.h"
 #include "intl.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 #include "gcc-rich-location.h"
 #include "gimplify.h"
diff --git a/gcc/c/c-convert.c b/gcc/c/c-convert.c
index 33c9143e354..d6aeb9f3634 100644
--- a/gcc/c/c-convert.c
+++ b/gcc/c/c-convert.c
@@ -31,6 +31,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "convert.h"
 #include "langhooks.h"
 #include "ubsan.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 
 /* Change of width--truncation and extension of integers or reals--
diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
index 4d067e96dd3..ba542d0cceb 100644
--- a/gcc/c/c-typeck.c
+++ b/gcc/c/c-typeck.c
@@ -50,6 +50,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "gomp-constants.h"
 #include "spellcheck-tree.h"
 #include "gcc-rich-location.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 
 /* Possible cases of implicit bad conversions.  Used to select
diff --git a/gcc/calls.c b/gcc/calls.c
index 8a23b50fc66..83a1274a4f5 100644
--- a/gcc/calls.c
+++ b/gcc/calls.c
@@ -52,6 +52,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-ssanames.h"
 #include "rtl-chkp.h"
 #include "intl.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* Like PREFERRED_STACK_BOUNDARY but in units of bytes, not bits.  */
 #define STACK_BYTES (PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT)
diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c
index c427a89bab0..49ab3537ba7 100644
--- a/gcc/cfgexpand.c
+++ b/gcc/cfgexpand.c
@@ -68,6 +68,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-outof-ssa.h"
 #include "cfgloop.h"
 #include "insn-attr.h" /* For INSN_SCHEDULING.  */
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 #include "tree-ssa-address.h"
 #include "output.h"
diff --git a/gcc/cgraph.c b/gcc/cgraph.c
index 6711aeb828e..23f040a9433 100644
--- a/gcc/cgraph.c
+++ b/gcc/cgraph.c
@@ -61,6 +61,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-chkp.h"
 #include "context.h"
 #include "gimplify.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* FIXME: Only for PROP_loops, but cgraph shouldn't have to know about this.  */
 #include "tree-pass.h"
diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c
index 6072c567bc3..e8cc765095d 100644
--- a/gcc/cgraphunit.c
+++ b/gcc/cgraphunit.c
@@ -204,6 +204,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "dbgcnt.h"
 #include "tree-chkp.h"
 #include "lto-section-names.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* Queue of cgraph nodes scheduled to be added into cgraph.  This is a
    secondary queue used during optimization to accommodate passes that
diff --git a/gcc/convert.c b/gcc/convert.c
index 429f988cbde..110995fdfbe 100644
--- a/gcc/convert.c
+++ b/gcc/convert.c
@@ -33,6 +33,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "langhooks.h"
 #include "builtins.h"
 #include "ubsan.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 
 #define maybe_fold_build1_loc(FOLD_P, LOC, CODE, TYPE, EXPR) \
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index fac6b6c16ac..48d00afe175 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -39,6 +39,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "langhooks.h"
 #include "c-family/c-objc.h"
 #include "internal-fn.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* The various kinds of conversion.  */
 
diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c
index f010f6c63be..786894ec231 100644
--- a/gcc/cp/cp-gimplify.c
+++ b/gcc/cp/cp-gimplify.c
@@ -33,6 +33,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "c-family/c-ubsan.h"
 #include "cilk.h"
 #include "cp-cilkplus.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 
 /* Forward declarations.  */
diff --git a/gcc/cp/cp-ubsan.c b/gcc/cp/cp-ubsan.c
index f00f870bd3e..a1ee62618a2 100644
--- a/gcc/cp/cp-ubsan.c
+++ b/gcc/cp/cp-ubsan.c
@@ -23,6 +23,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "coretypes.h"
 #include "cp-tree.h"
 #include "ubsan.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 
 /* Test if we should instrument vptr access.  */
diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c
index 631ff49673f..fd758d3c2dc 100644
--- a/gcc/cp/cvt.c
+++ b/gcc/cp/cvt.c
@@ -33,6 +33,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "flags.h"
 #include "intl.h"
 #include "convert.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 static tree convert_to_pointer_force (tree, tree, tsubst_flags_t);
 static tree build_type_conversion (tree, tree);
diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index 14335388a50..0b73fae4146 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -30,6 +30,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "gimplify.h"
 #include "c-family/c-ubsan.h"
 #include "intl.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 
 static bool begin_init_stmts (tree *, tree *);
diff --git a/gcc/cp/search.c b/gcc/cp/search.c
index cd06e529fb9..5c8aeba0d99 100644
--- a/gcc/cp/search.c
+++ b/gcc/cp/search.c
@@ -28,6 +28,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "intl.h"
 #include "toplev.h"
 #include "spellcheck-tree.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 static int is_subobject_of_p (tree, tree);
 static tree dfs_lookup_base (tree, void *);
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index f6177b32a32..3018f1b1c1e 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -40,6 +40,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-iterator.h"
 #include "omp-general.h"
 #include "convert.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "gomp-constants.h"
 
 /* There routines provide a modular interface to perform many parsing
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 1c15f29eb3d..4aad31b283a 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -37,6 +37,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "c-family/c-ubsan.h"
 #include "params.h"
 #include "gcc-rich-location.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 
 static tree cp_build_addr_expr_strict (tree, tsubst_flags_t);
diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index 5a57b93a73a..dce2ca67666 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -92,6 +92,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-dfa.h"
 #include "gdb/gdb-index.h"
 #include "rtl-iter.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 static void dwarf2out_source_line (unsigned int, unsigned int, const char *,
 				   int, bool);
diff --git a/gcc/final.c b/gcc/final.c
index 356c923c4cd..b4c84a3b327 100644
--- a/gcc/final.c
+++ b/gcc/final.c
@@ -76,6 +76,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-ssa.h"
 #include "cfgloop.h"
 #include "params.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 #include "rtl-iter.h"
 #include "print-rtl.h"
diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index 1bcbbb58154..1ccab70e31a 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -79,6 +79,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-vrp.h"
 #include "tree-ssanames.h"
 #include "selftest.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* Nonzero if we are folding constants inside an initializer; zero
    otherwise.  */
diff --git a/gcc/fortran/trans-types.c b/gcc/fortran/trans-types.c
index 8617cd51a7c..76ee97b81c0 100644
--- a/gcc/fortran/trans-types.c
+++ b/gcc/fortran/trans-types.c
@@ -36,6 +36,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "trans-types.h"
 #include "trans-const.h"
 #include "dwarf2out.h"	/* For struct array_descr_info.  */
+#include "attribs.h"
 \f
 
 #if (GFC_MAX_DIMENSIONS < 10)
diff --git a/gcc/function.c b/gcc/function.c
index f625489205b..bd2cf882982 100644
--- a/gcc/function.c
+++ b/gcc/function.c
@@ -77,6 +77,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "rtl-chkp.h"
 #include "tree-dfa.h"
 #include "tree-ssa.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* So we can assign to cfun in this file.  */
 #undef cfun
diff --git a/gcc/gimple-expr.c b/gcc/gimple-expr.c
index 9d8034c3192..001b4bafb0e 100644
--- a/gcc/gimple-expr.c
+++ b/gcc/gimple-expr.c
@@ -35,6 +35,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "hash-set.h"
 #include "rtl.h"
 #include "tree-pass.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* ----- Type related -----  */
 
diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c
index d94dc9cd563..7b2052ef39e 100644
--- a/gcc/gimple-fold.c
+++ b/gcc/gimple-fold.c
@@ -56,6 +56,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "ipa-chkp.h"
 #include "tree-cfg.h"
 #include "fold-const-call.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 
 /* Return true when DECL can be referenced from current unit.
diff --git a/gcc/gimple-pretty-print.c b/gcc/gimple-pretty-print.c
index 4012b3b9e2d..da7666d8284 100644
--- a/gcc/gimple-pretty-print.c
+++ b/gcc/gimple-pretty-print.c
@@ -38,6 +38,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "value-prof.h"
 #include "trans-mem.h"
 #include "cfganal.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 
 #define INDENT(SPACE)							\
diff --git a/gcc/gimple.c b/gcc/gimple.c
index 488f8c82b82..3ab21848dca 100644
--- a/gcc/gimple.c
+++ b/gcc/gimple.c
@@ -41,6 +41,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "builtins.h"
 #include "selftest.h"
 #include "gimple-pretty-print.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 
 
diff --git a/gcc/gimplify.c b/gcc/gimplify.c
index 641a8210dad..3562bea4a8b 100644
--- a/gcc/gimplify.c
+++ b/gcc/gimplify.c
@@ -60,6 +60,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "gimple-walk.h"
 #include "langhooks-def.h"	/* FIXME: for lhd_set_decl_assembler_name */
 #include "builtins.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 #include "dbgcnt.h"
 
diff --git a/gcc/hsa-common.c b/gcc/hsa-common.c
index 95636ebc9a8..c8c12afb04c 100644
--- a/gcc/hsa-common.c
+++ b/gcc/hsa-common.c
@@ -40,6 +40,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "internal-fn.h"
 #include "ctype.h"
 #include "builtins.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* Structure containing intermediate HSA representation of the generated
    function.  */
diff --git a/gcc/hsa-gen.c b/gcc/hsa-gen.c
index 6ec8c348eb4..bd227626e83 100644
--- a/gcc/hsa-gen.c
+++ b/gcc/hsa-gen.c
@@ -60,6 +60,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "internal-fn.h"
 #include "builtins.h"
 #include "stor-layout.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* Print a warning message and set that we have seen an error.  */
 
diff --git a/gcc/internal-fn.c b/gcc/internal-fn.c
index 1dc75412484..59ee053115a 100644
--- a/gcc/internal-fn.c
+++ b/gcc/internal-fn.c
@@ -39,6 +39,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "stor-layout.h"
 #include "dojump.h"
 #include "expr.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 #include "ubsan.h"
 #include "recog.h"
diff --git a/gcc/ipa-chkp.c b/gcc/ipa-chkp.c
index 753673c8f66..704ef6e4550 100644
--- a/gcc/ipa-chkp.c
+++ b/gcc/ipa-chkp.c
@@ -34,6 +34,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-chkp.h"
 #include "tree-inline.h"
 #include "ipa-chkp.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /*  Pointer Bounds Checker has two IPA passes to support code instrumentation.
 
diff --git a/gcc/ipa-cp.c b/gcc/ipa-cp.c
index 3b9eab41672..6b3d8d7364c 100644
--- a/gcc/ipa-cp.c
+++ b/gcc/ipa-cp.c
@@ -122,6 +122,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "ipa-fnsummary.h"
 #include "ipa-utils.h"
 #include "tree-ssa-ccp.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 template <typename valtype> class ipcp_value;
 
diff --git a/gcc/ipa-devirt.c b/gcc/ipa-devirt.c
index f0bc2501c27..7f46c5dc698 100644
--- a/gcc/ipa-devirt.c
+++ b/gcc/ipa-devirt.c
@@ -129,6 +129,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "dbgcnt.h"
 #include "gimple-pretty-print.h"
 #include "intl.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* Hash based set of pairs of types.  */
 struct type_pair
diff --git a/gcc/ipa-fnsummary.c b/gcc/ipa-fnsummary.c
index 52a8c9b0e81..ff485210762 100644
--- a/gcc/ipa-fnsummary.c
+++ b/gcc/ipa-fnsummary.c
@@ -82,6 +82,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "cilk.h"
 #include "cfgexpand.h"
 #include "gimplify.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* Summaries.  */
 function_summary <ipa_fn_summary *> *ipa_fn_summaries;
diff --git a/gcc/ipa-inline.c b/gcc/ipa-inline.c
index 608db8f8857..dd46cb61362 100644
--- a/gcc/ipa-inline.c
+++ b/gcc/ipa-inline.c
@@ -117,6 +117,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "auto-profile.h"
 #include "builtins.h"
 #include "fibonacci_heap.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 
 typedef fibonacci_heap <sreal, cgraph_edge> edge_heap_t;
diff --git a/gcc/ipa-visibility.c b/gcc/ipa-visibility.c
index cfd90c62211..fadff7ad15e 100644
--- a/gcc/ipa-visibility.c
+++ b/gcc/ipa-visibility.c
@@ -83,6 +83,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "cgraph.h"
 #include "calls.h"
 #include "varasm.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* Return true when NODE can not be local. Worker for cgraph_local_node_p.  */
 
diff --git a/gcc/ipa.c b/gcc/ipa.c
index 00cd3084f66..16df4cacedd 100644
--- a/gcc/ipa.c
+++ b/gcc/ipa.c
@@ -37,7 +37,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "ipa-fnsummary.h"
 #include "dbgcnt.h"
 #include "debug.h"
-
+#include "stringpool.h"
+#include "attribs.h"
 
 /* Return true when NODE has ADDR reference.  */
 
diff --git a/gcc/lto-cgraph.c b/gcc/lto-cgraph.c
index e2680277bb5..15f0eaadf20 100644
--- a/gcc/lto-cgraph.c
+++ b/gcc/lto-cgraph.c
@@ -38,6 +38,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "ipa-utils.h"
 #include "omp-offload.h"
 #include "ipa-chkp.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* True when asm nodes has been output.  */
 bool asm_nodes_output = false;
diff --git a/gcc/lto/lto-lang.c b/gcc/lto/lto-lang.c
index 58935172b2c..ae670142cc5 100644
--- a/gcc/lto/lto-lang.c
+++ b/gcc/lto/lto-lang.c
@@ -35,6 +35,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "lto-tree.h"
 #include "lto.h"
 #include "cilk.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 static tree handle_noreturn_attribute (tree *, tree, tree, int, bool *);
 static tree handle_leaf_attribute (tree *, tree, tree, int, bool *);
diff --git a/gcc/lto/lto-symtab.c b/gcc/lto/lto-symtab.c
index 019677eaf95..70190d0fda2 100644
--- a/gcc/lto/lto-symtab.c
+++ b/gcc/lto/lto-symtab.c
@@ -32,6 +32,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "builtins.h"
 #include "alias.h"
 #include "lto-symtab.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* Replace the cgraph node NODE with PREVAILING_NODE in the cgraph, merging
    all edges and removing the old node.  */
diff --git a/gcc/omp-expand.c b/gcc/omp-expand.c
index 929c53078d5..c0caed6011f 100644
--- a/gcc/omp-expand.c
+++ b/gcc/omp-expand.c
@@ -58,7 +58,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "gimple-pretty-print.h"
 #include "hsa-common.h"
 #include "debug.h"
-
+#include "stringpool.h"
+#include "attribs.h"
 
 /* OMP region information.  Every parallel and workshare
    directive is enclosed between two markers, the OMP_* directive
diff --git a/gcc/omp-general.c b/gcc/omp-general.c
index 9a5ed88e2d6..237f20608ff 100644
--- a/gcc/omp-general.c
+++ b/gcc/omp-general.c
@@ -33,7 +33,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "fold-const.h"
 #include "langhooks.h"
 #include "omp-general.h"
-
+#include "stringpool.h"
+#include "attribs.h"
 
 tree
 omp_find_clause (tree clauses, enum omp_clause_code kind)
diff --git a/gcc/omp-low.c b/gcc/omp-low.c
index bf3fc53b07a..38f2ebe523a 100644
--- a/gcc/omp-low.c
+++ b/gcc/omp-low.c
@@ -58,6 +58,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "gomp-constants.h"
 #include "gimple-pretty-print.h"
 #include "hsa-common.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* Lowering of OMP parallel and workshare constructs proceeds in two
    phases.  The first phase scans the function looking for OMP statements
diff --git a/gcc/omp-offload.c b/gcc/omp-offload.c
index 54a4e90f70c..2d4fd411680 100644
--- a/gcc/omp-offload.c
+++ b/gcc/omp-offload.c
@@ -49,6 +49,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "gomp-constants.h"
 #include "gimple-pretty-print.h"
 #include "intl.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* Describe the OpenACC looping structure of a function.  The entire
    function is held in a 'NULL' loop.  */
diff --git a/gcc/omp-simd-clone.c b/gcc/omp-simd-clone.c
index a1a563e8094..ad56a61b9da 100644
--- a/gcc/omp-simd-clone.c
+++ b/gcc/omp-simd-clone.c
@@ -48,7 +48,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "ipa-prop.h"
 #include "tree-eh.h"
 #include "varasm.h"
-
+#include "stringpool.h"
+#include "attribs.h"
 
 /* Allocate a fresh `simd_clone' and return it.  NARGS is the number
    of arguments to reserve space for.  */
diff --git a/gcc/opts-global.c b/gcc/opts-global.c
index 50bad77c347..fc55512e554 100644
--- a/gcc/opts-global.c
+++ b/gcc/opts-global.c
@@ -35,6 +35,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "plugin.h"
 #include "toplev.h"
 #include "context.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 
 typedef const char *const_char_p; /* For DEF_VEC_P.  */
diff --git a/gcc/passes.c b/gcc/passes.c
index 374f6f77897..56d8fd3268b 100644
--- a/gcc/passes.c
+++ b/gcc/passes.c
@@ -61,6 +61,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-cfgcleanup.h"
 #include "insn-addr.h" /* for INSN_ADDRESSES_ALLOC.  */
 #include "diagnostic-core.h" /* for fnotice */
+#include "stringpool.h"
+#include "attribs.h"
 
 using namespace gcc;
 
diff --git a/gcc/predict.c b/gcc/predict.c
index 2a7dbfa4d9b..d1eaf4ca265 100644
--- a/gcc/predict.c
+++ b/gcc/predict.c
@@ -59,6 +59,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "gimple-pretty-print.h"
 #include "selftest.h"
 #include "cfgrtl.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* Enum with reasons why a predictor is ignored.  */
 
diff --git a/gcc/sancov.c b/gcc/sancov.c
index 1651989ea24..b19de8bbbc5 100644
--- a/gcc/sancov.c
+++ b/gcc/sancov.c
@@ -32,6 +32,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-cfg.h"
 #include "tree-pass.h"
 #include "tree-iterator.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 
 namespace {
diff --git a/gcc/sanopt.c b/gcc/sanopt.c
index b7740741d43..1f9c82feaa9 100644
--- a/gcc/sanopt.c
+++ b/gcc/sanopt.c
@@ -30,6 +30,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "gimple-pretty-print.h"
 #include "fold-const.h"
 #include "gimple-iterator.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 #include "ubsan.h"
 #include "params.h"
diff --git a/gcc/symtab.c b/gcc/symtab.c
index 0145910023f..7e5eb7d6416 100644
--- a/gcc/symtab.c
+++ b/gcc/symtab.c
@@ -35,6 +35,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "output.h"
 #include "ipa-utils.h"
 #include "calls.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 static const char *ipa_ref_use_name[] = {"read","write","addr","alias","chkp"};
 
diff --git a/gcc/toplev.c b/gcc/toplev.c
index e6c69a4ba93..1ff7fd9b6fa 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -63,6 +63,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "hosthooks.h"
 #include "opts.h"
 #include "opts-diagnostic.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 #include "tsan.h"
 #include "plugin.h"
diff --git a/gcc/trans-mem.c b/gcc/trans-mem.c
index eb03560be26..40b53681186 100644
--- a/gcc/trans-mem.c
+++ b/gcc/trans-mem.c
@@ -50,7 +50,8 @@
 #include "langhooks.h"
 #include "cfgloop.h"
 #include "tree-ssa-address.h"
-
+#include "stringpool.h"
+#include "attribs.h"
 
 #define A_RUNINSTRUMENTEDCODE	0x0001
 #define A_RUNUNINSTRUMENTEDCODE	0x0002
diff --git a/gcc/tree-chkp.c b/gcc/tree-chkp.c
index e241f50f308..12af458fb90 100644
--- a/gcc/tree-chkp.c
+++ b/gcc/tree-chkp.c
@@ -52,6 +52,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-dfa.h"
 #include "ipa-chkp.h"
 #include "params.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /*  Pointer Bounds Checker instruments code with memory checks to find
     out-of-bounds memory accesses.  Checks are performed by computing
diff --git a/gcc/tree-eh.c b/gcc/tree-eh.c
index 79d02adbade..ba05dba6ae4 100644
--- a/gcc/tree-eh.c
+++ b/gcc/tree-eh.c
@@ -43,6 +43,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "langhooks.h"
 #include "cfgloop.h"
 #include "gimple-low.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 
 /* In some instances a tree and a gimple need to be stored in a same table,
diff --git a/gcc/tree-into-ssa.c b/gcc/tree-into-ssa.c
index d4056373f31..28f72e4ce32 100644
--- a/gcc/tree-into-ssa.c
+++ b/gcc/tree-into-ssa.c
@@ -38,6 +38,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-ssa.h"
 #include "domwalk.h"
 #include "statistics.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 
 #define PERCENT(x,y) ((float)(x) * 100.0 / (float)(y))
diff --git a/gcc/tree-object-size.c b/gcc/tree-object-size.c
index 723a5283da6..a56b78a4510 100644
--- a/gcc/tree-object-size.c
+++ b/gcc/tree-object-size.c
@@ -32,6 +32,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "gimple-fold.h"
 #include "gimple-iterator.h"
 #include "tree-cfg.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 struct object_size_info
 {
diff --git a/gcc/tree-parloops.c b/gcc/tree-parloops.c
index cf9bc36936c..e8f8ae07992 100644
--- a/gcc/tree-parloops.c
+++ b/gcc/tree-parloops.c
@@ -58,6 +58,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-eh.h"
 #include "gomp-constants.h"
 #include "tree-dfa.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* This pass tries to distribute iterations of loops into several threads.
    The implementation is straightforward -- for each loop we test whether its
diff --git a/gcc/tree-profile.c b/gcc/tree-profile.c
index b1ee7f2b3f5..4b73255018c 100644
--- a/gcc/tree-profile.c
+++ b/gcc/tree-profile.c
@@ -50,6 +50,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "profile.h"
 #include "tree-cfgcleanup.h"
 #include "params.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 static GTY(()) tree gcov_type_node;
 static GTY(()) tree tree_interval_profiler_fn;
diff --git a/gcc/tree-ssa-ccp.c b/gcc/tree-ssa-ccp.c
index f18f2e0c2a4..3940d538ca7 100644
--- a/gcc/tree-ssa-ccp.c
+++ b/gcc/tree-ssa-ccp.c
@@ -145,6 +145,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-ssa-ccp.h"
 #include "tree-dfa.h"
 #include "diagnostic-core.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* Possible lattice values.  */
 typedef enum
diff --git a/gcc/tree-ssa-live.c b/gcc/tree-ssa-live.c
index c77075e4ac6..8738fe21a6e 100644
--- a/gcc/tree-ssa-live.c
+++ b/gcc/tree-ssa-live.c
@@ -38,6 +38,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-ssa.h"
 #include "ipa-utils.h"
 #include "cfgloop.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 static void verify_live_on_entry (tree_live_info_p);
 
diff --git a/gcc/tree-ssa-loop.c b/gcc/tree-ssa-loop.c
index 19a0f30c525..1e8491757a6 100644
--- a/gcc/tree-ssa-loop.c
+++ b/gcc/tree-ssa-loop.c
@@ -38,6 +38,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-vectorizer.h"
 #include "omp-general.h"
 #include "diagnostic-core.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 
 /* A pass making sure loops are fixed up.  */
diff --git a/gcc/tree-ssa-sccvn.c b/gcc/tree-ssa-sccvn.c
index 324cd73f513..e4786fb9aaa 100644
--- a/gcc/tree-ssa-sccvn.c
+++ b/gcc/tree-ssa-sccvn.c
@@ -60,6 +60,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "domwalk.h"
 #include "gimple-iterator.h"
 #include "gimple-match.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* This algorithm is based on the SCC algorithm presented by Keith
    Cooper and L. Taylor Simpson in "SCC-Based Value numbering"
diff --git a/gcc/tree-ssa.c b/gcc/tree-ssa.c
index fa8f81e9a1a..fc6022eb47a 100644
--- a/gcc/tree-ssa.c
+++ b/gcc/tree-ssa.c
@@ -41,6 +41,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "cfgexpand.h"
 #include "tree-cfg.h"
 #include "tree-dfa.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 
 /* Pointer map of variable mappings, keyed by edge.  */
diff --git a/gcc/tree-streamer-in.c b/gcc/tree-streamer-in.c
index 7f7ea7f90ab..cabdb71fd12 100644
--- a/gcc/tree-streamer-in.c
+++ b/gcc/tree-streamer-in.c
@@ -32,6 +32,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "builtins.h"
 #include "ipa-chkp.h"
 #include "gomp-constants.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 
 
diff --git a/gcc/tree-vectorizer.c b/gcc/tree-vectorizer.c
index 33a1f580474..9fe40b928d4 100644
--- a/gcc/tree-vectorizer.c
+++ b/gcc/tree-vectorizer.c
@@ -76,6 +76,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-ssa-propagate.h"
 #include "dbgcnt.h"
 #include "tree-scalar-evolution.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 
 /* Loop or bb location.  */
diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c
index 28205f19751..ebc4701d377 100644
--- a/gcc/tree-vrp.c
+++ b/gcc/tree-vrp.c
@@ -62,6 +62,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "alloc-pool.h"
 #include "domwalk.h"
 #include "tree-cfgcleanup.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 #define VR_INITIALIZER { VR_UNDEFINED, NULL_TREE, NULL_TREE, NULL }
 
diff --git a/gcc/tree.c b/gcc/tree.c
index 13335a007b7..de902f77319 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -62,6 +62,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "print-tree.h"
 #include "ipa-utils.h"
 #include "selftest.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* Tree code classes.  */
 
@@ -4804,254 +4806,6 @@ protected_set_expr_location (tree t, location_t loc)
     SET_EXPR_LOCATION (t, loc);
 }
 \f
-/* Return a declaration like DDECL except that its DECL_ATTRIBUTES
-   is ATTRIBUTE.  */
-
-tree
-build_decl_attribute_variant (tree ddecl, tree attribute)
-{
-  DECL_ATTRIBUTES (ddecl) = attribute;
-  return ddecl;
-}
-
-/* Return a type like TTYPE except that its TYPE_ATTRIBUTE
-   is ATTRIBUTE and its qualifiers are QUALS.
-
-   Record such modified types already made so we don't make duplicates.  */
-
-tree
-build_type_attribute_qual_variant (tree ttype, tree attribute, int quals)
-{
-  if (! attribute_list_equal (TYPE_ATTRIBUTES (ttype), attribute))
-    {
-      tree ntype;
-
-      /* Building a distinct copy of a tagged type is inappropriate; it
-	 causes breakage in code that expects there to be a one-to-one
-	 relationship between a struct and its fields.
-	 build_duplicate_type is another solution (as used in
-	 handle_transparent_union_attribute), but that doesn't play well
-	 with the stronger C++ type identity model.  */
-      if (TREE_CODE (ttype) == RECORD_TYPE
-	  || TREE_CODE (ttype) == UNION_TYPE
-	  || TREE_CODE (ttype) == QUAL_UNION_TYPE
-	  || TREE_CODE (ttype) == ENUMERAL_TYPE)
-	{
-	  warning (OPT_Wattributes,
-		   "ignoring attributes applied to %qT after definition",
-		   TYPE_MAIN_VARIANT (ttype));
-	  return build_qualified_type (ttype, quals);
-	}
-
-      ttype = build_qualified_type (ttype, TYPE_UNQUALIFIED);
-      ntype = build_distinct_type_copy (ttype);
-
-      TYPE_ATTRIBUTES (ntype) = attribute;
-
-      hashval_t hash = type_hash_canon_hash (ntype);
-      ntype = type_hash_canon (hash, ntype);
-
-      /* If the target-dependent attributes make NTYPE different from
-	 its canonical type, we will need to use structural equality
-	 checks for this type. */
-      if (TYPE_STRUCTURAL_EQUALITY_P (ttype)
-          || !comp_type_attributes (ntype, ttype))
-	SET_TYPE_STRUCTURAL_EQUALITY (ntype);
-      else if (TYPE_CANONICAL (ntype) == ntype)
-	TYPE_CANONICAL (ntype) = TYPE_CANONICAL (ttype);
-
-      ttype = build_qualified_type (ntype, quals);
-    }
-  else if (TYPE_QUALS (ttype) != quals)
-    ttype = build_qualified_type (ttype, quals);
-
-  return ttype;
-}
-
-/* Check if "omp declare simd" attribute arguments, CLAUSES1 and CLAUSES2, are
-   the same.  */
-
-static bool
-omp_declare_simd_clauses_equal (tree clauses1, tree clauses2)
-{
-  tree cl1, cl2;
-  for (cl1 = clauses1, cl2 = clauses2;
-       cl1 && cl2;
-       cl1 = OMP_CLAUSE_CHAIN (cl1), cl2 = OMP_CLAUSE_CHAIN (cl2))
-    {
-      if (OMP_CLAUSE_CODE (cl1) != OMP_CLAUSE_CODE (cl2))
-	return false;
-      if (OMP_CLAUSE_CODE (cl1) != OMP_CLAUSE_SIMDLEN)
-	{
-	  if (simple_cst_equal (OMP_CLAUSE_DECL (cl1),
-				OMP_CLAUSE_DECL (cl2)) != 1)
-	    return false;
-	}
-      switch (OMP_CLAUSE_CODE (cl1))
-	{
-	case OMP_CLAUSE_ALIGNED:
-	  if (simple_cst_equal (OMP_CLAUSE_ALIGNED_ALIGNMENT (cl1),
-				OMP_CLAUSE_ALIGNED_ALIGNMENT (cl2)) != 1)
-	    return false;
-	  break;
-	case OMP_CLAUSE_LINEAR:
-	  if (simple_cst_equal (OMP_CLAUSE_LINEAR_STEP (cl1),
-				OMP_CLAUSE_LINEAR_STEP (cl2)) != 1)
-	    return false;
-	  break;
-	case OMP_CLAUSE_SIMDLEN:
-	  if (simple_cst_equal (OMP_CLAUSE_SIMDLEN_EXPR (cl1),
-				OMP_CLAUSE_SIMDLEN_EXPR (cl2)) != 1)
-	    return false;
-	default:
-	  break;
-	}
-    }
-  return true;
-}
-
-/* Compare two constructor-element-type constants.  Return 1 if the lists
-   are known to be equal; otherwise return 0.  */
-
-static bool
-simple_cst_list_equal (const_tree l1, const_tree l2)
-{
-  while (l1 != NULL_TREE && l2 != NULL_TREE)
-    {
-      if (simple_cst_equal (TREE_VALUE (l1), TREE_VALUE (l2)) != 1)
-	return false;
-
-      l1 = TREE_CHAIN (l1);
-      l2 = TREE_CHAIN (l2);
-    }
-
-  return l1 == l2;
-}
-
-/* Compare two identifier nodes representing attributes.
-   Return true if they are the same, false otherwise.  */
-
-static bool
-cmp_attrib_identifiers (const_tree attr1, const_tree attr2)
-{
-  /* Make sure we're dealing with IDENTIFIER_NODEs.  */
-  gcc_checking_assert (TREE_CODE (attr1) == IDENTIFIER_NODE
-		       && TREE_CODE (attr2) == IDENTIFIER_NODE);
-
-  /* Identifiers can be compared directly for equality.  */
-  if (attr1 == attr2)
-    return true;
-
-  return cmp_attribs (IDENTIFIER_POINTER (attr1), IDENTIFIER_LENGTH (attr1),
-		      IDENTIFIER_POINTER (attr2), IDENTIFIER_LENGTH (attr2));
-}
-
-/* Compare two attributes for their value identity.  Return true if the
-   attribute values are known to be equal; otherwise return false.  */
-
-bool
-attribute_value_equal (const_tree attr1, const_tree attr2)
-{
-  if (TREE_VALUE (attr1) == TREE_VALUE (attr2))
-    return true;
-
-  if (TREE_VALUE (attr1) != NULL_TREE
-      && TREE_CODE (TREE_VALUE (attr1)) == TREE_LIST
-      && TREE_VALUE (attr2) != NULL_TREE
-      && TREE_CODE (TREE_VALUE (attr2)) == TREE_LIST)
-    {
-      /* Handle attribute format.  */
-      if (is_attribute_p ("format", get_attribute_name (attr1)))
-	{
-	  attr1 = TREE_VALUE (attr1);
-	  attr2 = TREE_VALUE (attr2);
-	  /* Compare the archetypes (printf/scanf/strftime/...).  */
-	  if (!cmp_attrib_identifiers (TREE_VALUE (attr1),
-				       TREE_VALUE (attr2)))
-	    return false;
-	  /* Archetypes are the same.  Compare the rest.  */
-	  return (simple_cst_list_equal (TREE_CHAIN (attr1),
-					 TREE_CHAIN (attr2)) == 1);
-	}
-      return (simple_cst_list_equal (TREE_VALUE (attr1),
-				     TREE_VALUE (attr2)) == 1);
-    }
-
-  if ((flag_openmp || flag_openmp_simd)
-      && TREE_VALUE (attr1) && TREE_VALUE (attr2)
-      && TREE_CODE (TREE_VALUE (attr1)) == OMP_CLAUSE
-      && TREE_CODE (TREE_VALUE (attr2)) == OMP_CLAUSE)
-    return omp_declare_simd_clauses_equal (TREE_VALUE (attr1),
-					   TREE_VALUE (attr2));
-
-  return (simple_cst_equal (TREE_VALUE (attr1), TREE_VALUE (attr2)) == 1);
-}
-
-/* Return 0 if the attributes for two types are incompatible, 1 if they
-   are compatible, and 2 if they are nearly compatible (which causes a
-   warning to be generated).  */
-int
-comp_type_attributes (const_tree type1, const_tree type2)
-{
-  const_tree a1 = TYPE_ATTRIBUTES (type1);
-  const_tree a2 = TYPE_ATTRIBUTES (type2);
-  const_tree a;
-
-  if (a1 == a2)
-    return 1;
-  for (a = a1; a != NULL_TREE; a = TREE_CHAIN (a))
-    {
-      const struct attribute_spec *as;
-      const_tree attr;
-
-      as = lookup_attribute_spec (get_attribute_name (a));
-      if (!as || as->affects_type_identity == false)
-        continue;
-
-      attr = lookup_attribute (as->name, CONST_CAST_TREE (a2));
-      if (!attr || !attribute_value_equal (a, attr))
-        break;
-    }
-  if (!a)
-    {
-      for (a = a2; a != NULL_TREE; a = TREE_CHAIN (a))
-	{
-	  const struct attribute_spec *as;
-
-	  as = lookup_attribute_spec (get_attribute_name (a));
-	  if (!as || as->affects_type_identity == false)
-	    continue;
-
-	  if (!lookup_attribute (as->name, CONST_CAST_TREE (a1)))
-	    break;
-	  /* We don't need to compare trees again, as we did this
-	     already in first loop.  */
-	}
-      /* All types - affecting identity - are equal, so
-         there is no need to call target hook for comparison.  */
-      if (!a)
-        return 1;
-    }
-  if (lookup_attribute ("transaction_safe", CONST_CAST_TREE (a)))
-    return 0;
-  /* As some type combinations - like default calling-convention - might
-     be compatible, we have to call the target hook to get the final result.  */
-  return targetm.comp_type_attributes (type1, type2);
-}
-
-/* Return a type like TTYPE except that its TYPE_ATTRIBUTE
-   is ATTRIBUTE.
-
-   Record such modified types already made so we don't make duplicates.  */
-
-tree
-build_type_attribute_variant (tree ttype, tree attribute)
-{
-  return build_type_attribute_qual_variant (ttype, attribute,
-					    TYPE_QUALS (ttype));
-}
-
-
 /* Reset the expression *EXPR_P, a size or position.
 
    ??? We could reset all non-constant sizes or positions.  But it's cheap
@@ -6015,379 +5769,6 @@ make_pass_ipa_free_lang_data (gcc::context *ctxt)
 {
   return new pass_ipa_free_lang_data (ctxt);
 }
-
-/* The backbone of lookup_attribute().  ATTR_LEN is the string length
-   of ATTR_NAME, and LIST is not NULL_TREE.  */
-tree
-private_lookup_attribute (const char *attr_name, size_t attr_len, tree list)
-{
-  while (list)
-    {
-      tree attr = get_attribute_name (list);
-      size_t ident_len = IDENTIFIER_LENGTH (attr);
-      if (cmp_attribs (attr_name, attr_len, IDENTIFIER_POINTER (attr),
-		       ident_len))
-	break;
-      list = TREE_CHAIN (list);
-    }
-
-  return list;
-}
-
-/* Given an attribute name ATTR_NAME and a list of attributes LIST,
-   return a pointer to the attribute's list first element if the attribute
-   starts with ATTR_NAME.  */
-
-tree
-private_lookup_attribute_by_prefix (const char *attr_name, size_t attr_len,
-				    tree list)
-{
-  while (list)
-    {
-      size_t ident_len = IDENTIFIER_LENGTH (get_attribute_name (list));
-
-      if (attr_len > ident_len)
-	{
-	  list = TREE_CHAIN (list);
-	  continue;
-	}
-
-      const char *p = IDENTIFIER_POINTER (get_attribute_name (list));
-      gcc_checking_assert (attr_len == 0 || p[0] != '_');
-
-      if (strncmp (attr_name, p, attr_len) == 0)
-	break;
-
-      list = TREE_CHAIN (list);
-    }
-
-  return list;
-}
-
-
-/* A variant of lookup_attribute() that can be used with an identifier
-   as the first argument, and where the identifier can be either
-   'text' or '__text__'.
-
-   Given an attribute ATTR_IDENTIFIER, and a list of attributes LIST,
-   return a pointer to the attribute's list element if the attribute
-   is part of the list, or NULL_TREE if not found.  If the attribute
-   appears more than once, this only returns the first occurrence; the
-   TREE_CHAIN of the return value should be passed back in if further
-   occurrences are wanted.  ATTR_IDENTIFIER must be an identifier but
-   can be in the form 'text' or '__text__'.  */
-static tree
-lookup_ident_attribute (tree attr_identifier, tree list)
-{
-  gcc_checking_assert (TREE_CODE (attr_identifier) == IDENTIFIER_NODE);
-
-  while (list)
-    {
-      gcc_checking_assert (TREE_CODE (get_attribute_name (list))
-			   == IDENTIFIER_NODE);
-
-      if (cmp_attrib_identifiers (attr_identifier,
-				  get_attribute_name (list)))
-	/* Found it.  */
-	break;
-      list = TREE_CHAIN (list);
-    }
-
-  return list;
-}
-
-/* Remove any instances of attribute ATTR_NAME in LIST and return the
-   modified list.  */
-
-tree
-remove_attribute (const char *attr_name, tree list)
-{
-  tree *p;
-  gcc_checking_assert (attr_name[0] != '_');
-
-  for (p = &list; *p; )
-    {
-      tree l = *p;
-
-      tree attr = get_attribute_name (l);
-      if (is_attribute_p (attr_name, attr))
-	*p = TREE_CHAIN (l);
-      else
-	p = &TREE_CHAIN (l);
-    }
-
-  return list;
-}
-
-/* Return an attribute list that is the union of a1 and a2.  */
-
-tree
-merge_attributes (tree a1, tree a2)
-{
-  tree attributes;
-
-  /* Either one unset?  Take the set one.  */
-
-  if ((attributes = a1) == 0)
-    attributes = a2;
-
-  /* One that completely contains the other?  Take it.  */
-
-  else if (a2 != 0 && ! attribute_list_contained (a1, a2))
-    {
-      if (attribute_list_contained (a2, a1))
-	attributes = a2;
-      else
-	{
-	  /* Pick the longest list, and hang on the other list.  */
-
-	  if (list_length (a1) < list_length (a2))
-	    attributes = a2, a2 = a1;
-
-	  for (; a2 != 0; a2 = TREE_CHAIN (a2))
-	    {
-	      tree a;
-	      for (a = lookup_ident_attribute (get_attribute_name (a2),
-					       attributes);
-		   a != NULL_TREE && !attribute_value_equal (a, a2);
-		   a = lookup_ident_attribute (get_attribute_name (a2),
-					       TREE_CHAIN (a)))
-		;
-	      if (a == NULL_TREE)
-		{
-		  a1 = copy_node (a2);
-		  TREE_CHAIN (a1) = attributes;
-		  attributes = a1;
-		}
-	    }
-	}
-    }
-  return attributes;
-}
-
-/* Given types T1 and T2, merge their attributes and return
-  the result.  */
-
-tree
-merge_type_attributes (tree t1, tree t2)
-{
-  return merge_attributes (TYPE_ATTRIBUTES (t1),
-			   TYPE_ATTRIBUTES (t2));
-}
-
-/* Given decls OLDDECL and NEWDECL, merge their attributes and return
-   the result.  */
-
-tree
-merge_decl_attributes (tree olddecl, tree newdecl)
-{
-  return merge_attributes (DECL_ATTRIBUTES (olddecl),
-			   DECL_ATTRIBUTES (newdecl));
-}
-
-#if TARGET_DLLIMPORT_DECL_ATTRIBUTES
-
-/* Specialization of merge_decl_attributes for various Windows targets.
-
-   This handles the following situation:
-
-     __declspec (dllimport) int foo;
-     int foo;
-
-   The second instance of `foo' nullifies the dllimport.  */
-
-tree
-merge_dllimport_decl_attributes (tree old, tree new_tree)
-{
-  tree a;
-  int delete_dllimport_p = 1;
-
-  /* What we need to do here is remove from `old' dllimport if it doesn't
-     appear in `new'.  dllimport behaves like extern: if a declaration is
-     marked dllimport and a definition appears later, then the object
-     is not dllimport'd.  We also remove a `new' dllimport if the old list
-     contains dllexport:  dllexport always overrides dllimport, regardless
-     of the order of declaration.  */
-  if (!VAR_OR_FUNCTION_DECL_P (new_tree))
-    delete_dllimport_p = 0;
-  else if (DECL_DLLIMPORT_P (new_tree)
-     	   && lookup_attribute ("dllexport", DECL_ATTRIBUTES (old)))
-    {
-      DECL_DLLIMPORT_P (new_tree) = 0;
-      warning (OPT_Wattributes, "%q+D already declared with dllexport attribute: "
-	      "dllimport ignored", new_tree);
-    }
-  else if (DECL_DLLIMPORT_P (old) && !DECL_DLLIMPORT_P (new_tree))
-    {
-      /* Warn about overriding a symbol that has already been used, e.g.:
-           extern int __attribute__ ((dllimport)) foo;
-	   int* bar () {return &foo;}
-	   int foo;
-      */
-      if (TREE_USED (old))
-	{
-	  warning (0, "%q+D redeclared without dllimport attribute "
-		   "after being referenced with dll linkage", new_tree);
-	  /* If we have used a variable's address with dllimport linkage,
-	      keep the old DECL_DLLIMPORT_P flag: the ADDR_EXPR using the
-	      decl may already have had TREE_CONSTANT computed.
-	      We still remove the attribute so that assembler code refers
-	      to '&foo rather than '_imp__foo'.  */
-	  if (VAR_P (old) && TREE_ADDRESSABLE (old))
-	    DECL_DLLIMPORT_P (new_tree) = 1;
-	}
-
-      /* Let an inline definition silently override the external reference,
-	 but otherwise warn about attribute inconsistency.  */
-      else if (VAR_P (new_tree) || !DECL_DECLARED_INLINE_P (new_tree))
-	warning (OPT_Wattributes, "%q+D redeclared without dllimport attribute: "
-		  "previous dllimport ignored", new_tree);
-    }
-  else
-    delete_dllimport_p = 0;
-
-  a = merge_attributes (DECL_ATTRIBUTES (old), DECL_ATTRIBUTES (new_tree));
-
-  if (delete_dllimport_p)
-    a = remove_attribute ("dllimport", a);
-
-  return a;
-}
-
-/* Handle a "dllimport" or "dllexport" attribute; arguments as in
-   struct attribute_spec.handler.  */
-
-tree
-handle_dll_attribute (tree * pnode, tree name, tree args, int flags,
-		      bool *no_add_attrs)
-{
-  tree node = *pnode;
-  bool is_dllimport;
-
-  /* These attributes may apply to structure and union types being created,
-     but otherwise should pass to the declaration involved.  */
-  if (!DECL_P (node))
-    {
-      if (flags & ((int) ATTR_FLAG_DECL_NEXT | (int) ATTR_FLAG_FUNCTION_NEXT
-		   | (int) ATTR_FLAG_ARRAY_NEXT))
-	{
-	  *no_add_attrs = true;
-	  return tree_cons (name, args, NULL_TREE);
-	}
-      if (TREE_CODE (node) == RECORD_TYPE
-	  || TREE_CODE (node) == UNION_TYPE)
-	{
-	  node = TYPE_NAME (node);
-	  if (!node)
-	    return NULL_TREE;
-	}
-      else
-	{
-	  warning (OPT_Wattributes, "%qE attribute ignored",
-		   name);
-	  *no_add_attrs = true;
-	  return NULL_TREE;
-	}
-    }
-
-  if (!VAR_OR_FUNCTION_DECL_P (node) && TREE_CODE (node) != TYPE_DECL)
-    {
-      *no_add_attrs = true;
-      warning (OPT_Wattributes, "%qE attribute ignored",
-	       name);
-      return NULL_TREE;
-    }
-
-  if (TREE_CODE (node) == TYPE_DECL
-      && TREE_CODE (TREE_TYPE (node)) != RECORD_TYPE
-      && TREE_CODE (TREE_TYPE (node)) != UNION_TYPE)
-    {
-      *no_add_attrs = true;
-      warning (OPT_Wattributes, "%qE attribute ignored",
-	       name);
-      return NULL_TREE;
-    }
-
-  is_dllimport = is_attribute_p ("dllimport", name);
-
-  /* Report error on dllimport ambiguities seen now before they cause
-     any damage.  */
-  if (is_dllimport)
-    {
-      /* Honor any target-specific overrides. */
-      if (!targetm.valid_dllimport_attribute_p (node))
-	*no_add_attrs = true;
-
-     else if (TREE_CODE (node) == FUNCTION_DECL
-	        && DECL_DECLARED_INLINE_P (node))
-	{
-	  warning (OPT_Wattributes, "inline function %q+D declared as "
-		  " dllimport: attribute ignored", node);
-	  *no_add_attrs = true;
-	}
-      /* Like MS, treat definition of dllimported variables and
-	 non-inlined functions on declaration as syntax errors. */
-     else if (TREE_CODE (node) == FUNCTION_DECL && DECL_INITIAL (node))
-	{
-	  error ("function %q+D definition is marked dllimport", node);
-	  *no_add_attrs = true;
-	}
-
-     else if (VAR_P (node))
-	{
-	  if (DECL_INITIAL (node))
-	    {
-	      error ("variable %q+D definition is marked dllimport",
-		     node);
-	      *no_add_attrs = true;
-	    }
-
-	  /* `extern' needn't be specified with dllimport.
-	     Specify `extern' now and hope for the best.  Sigh.  */
-	  DECL_EXTERNAL (node) = 1;
-	  /* Also, implicitly give dllimport'd variables declared within
-	     a function global scope, unless declared static.  */
-	  if (current_function_decl != NULL_TREE && !TREE_STATIC (node))
-	    TREE_PUBLIC (node) = 1;
-	}
-
-      if (*no_add_attrs == false)
-        DECL_DLLIMPORT_P (node) = 1;
-    }
-  else if (TREE_CODE (node) == FUNCTION_DECL
-	   && DECL_DECLARED_INLINE_P (node)
-	   && flag_keep_inline_dllexport)
-    /* An exported function, even if inline, must be emitted.  */
-    DECL_EXTERNAL (node) = 0;
-
-  /*  Report error if symbol is not accessible at global scope.  */
-  if (!TREE_PUBLIC (node) && VAR_OR_FUNCTION_DECL_P (node))
-    {
-      error ("external linkage required for symbol %q+D because of "
-	     "%qE attribute", node, name);
-      *no_add_attrs = true;
-    }
-
-  /* A dllexport'd entity must have default visibility so that other
-     program units (shared libraries or the main executable) can see
-     it.  A dllimport'd entity must have default visibility so that
-     the linker knows that undefined references within this program
-     unit can be resolved by the dynamic linker.  */
-  if (!*no_add_attrs)
-    {
-      if (DECL_VISIBILITY_SPECIFIED (node)
-	  && DECL_VISIBILITY (node) != VISIBILITY_DEFAULT)
-	error ("%qE implies default visibility, but %qD has already "
-	       "been declared with a different visibility",
-	       name, node);
-      DECL_VISIBILITY (node) = VISIBILITY_DEFAULT;
-      DECL_VISIBILITY_SPECIFIED (node) = 1;
-    }
-
-  return NULL_TREE;
-}
-
-#endif /* TARGET_DLLIMPORT_DECL_ATTRIBUTES  */
 \f
 /* Set the type qualifiers for TYPE to TYPE_QUALS, which is a bitmask
    of the various TYPE_QUAL values.  */
@@ -7153,68 +6534,6 @@ print_type_hash_statistics (void)
 	   type_hash_table->collisions ());
 }
 
-/* Given two lists of attributes, return true if list l2 is
-   equivalent to l1.  */
-
-int
-attribute_list_equal (const_tree l1, const_tree l2)
-{
-  if (l1 == l2)
-    return 1;
-
-  return attribute_list_contained (l1, l2)
-	 && attribute_list_contained (l2, l1);
-}
-
-/* Given two lists of attributes, return true if list L2 is
-   completely contained within L1.  */
-/* ??? This would be faster if attribute names were stored in a canonicalized
-   form.  Otherwise, if L1 uses `foo' and L2 uses `__foo__', the long method
-   must be used to show these elements are equivalent (which they are).  */
-/* ??? It's not clear that attributes with arguments will always be handled
-   correctly.  */
-
-int
-attribute_list_contained (const_tree l1, const_tree l2)
-{
-  const_tree t1, t2;
-
-  /* First check the obvious, maybe the lists are identical.  */
-  if (l1 == l2)
-    return 1;
-
-  /* Maybe the lists are similar.  */
-  for (t1 = l1, t2 = l2;
-       t1 != 0 && t2 != 0
-        && get_attribute_name (t1) == get_attribute_name (t2)
-        && TREE_VALUE (t1) == TREE_VALUE (t2);
-       t1 = TREE_CHAIN (t1), t2 = TREE_CHAIN (t2))
-    ;
-
-  /* Maybe the lists are equal.  */
-  if (t1 == 0 && t2 == 0)
-    return 1;
-
-  for (; t2 != 0; t2 = TREE_CHAIN (t2))
-    {
-      const_tree attr;
-      /* This CONST_CAST is okay because lookup_attribute does not
-	 modify its argument and the return value is assigned to a
-	 const_tree.  */
-      for (attr = lookup_ident_attribute (get_attribute_name (t2),
-					  CONST_CAST_TREE (l1));
-	   attr != NULL_TREE && !attribute_value_equal (t2, attr);
-	   attr = lookup_ident_attribute (get_attribute_name (t2),
-					  TREE_CHAIN (attr)))
-	;
-
-      if (attr == NULL_TREE)
-	return 0;
-    }
-
-  return 1;
-}
-
 /* Given two lists of types
    (chains of TREE_LIST nodes with types in the TREE_VALUE slots)
    return 1 if the lists contain the same types in the same order.
diff --git a/gcc/tree.h b/gcc/tree.h
index fab566b6684..17b11a1f707 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -4124,8 +4124,6 @@ extern tree purpose_member (const_tree, tree);
 extern bool vec_member (const_tree, vec<tree, va_gc> *);
 extern tree chain_index (int, tree);
 
-extern int attribute_list_equal (const_tree, const_tree);
-extern int attribute_list_contained (const_tree, const_tree);
 extern int tree_int_cst_equal (const_tree, const_tree);
 
 extern bool tree_fits_shwi_p (const_tree)
@@ -4163,90 +4161,6 @@ extern bool valid_constant_size_p (const_tree);
 
 extern tree make_tree (tree, rtx);
 
-/* Return a type like TTYPE except that its TYPE_ATTRIBUTES
-   is ATTRIBUTE.
-
-   Such modified types already made are recorded so that duplicates
-   are not made.  */
-
-extern tree build_type_attribute_variant (tree, tree);
-extern tree build_decl_attribute_variant (tree, tree);
-extern tree build_type_attribute_qual_variant (tree, tree, int);
-
-extern bool attribute_value_equal (const_tree, const_tree);
-
-/* Return 0 if the attributes for two types are incompatible, 1 if they
-   are compatible, and 2 if they are nearly compatible (which causes a
-   warning to be generated).  */
-extern int comp_type_attributes (const_tree, const_tree);
-
-/* Default versions of target-overridable functions.  */
-extern tree merge_decl_attributes (tree, tree);
-extern tree merge_type_attributes (tree, tree);
-
-/* This function is a private implementation detail of lookup_attribute()
-   and you should never call it directly.  */
-extern tree private_lookup_attribute (const char *, size_t, tree);
-
-/* This function is a private implementation detail
-   of lookup_attribute_by_prefix() and you should never call it directly.  */
-extern tree private_lookup_attribute_by_prefix (const char *, size_t, tree);
-
-/* Given an attribute name ATTR_NAME and a list of attributes LIST,
-   return a pointer to the attribute's list element if the attribute
-   is part of the list, or NULL_TREE if not found.  If the attribute
-   appears more than once, this only returns the first occurrence; the
-   TREE_CHAIN of the return value should be passed back in if further
-   occurrences are wanted.  ATTR_NAME must be in the form 'text' (not
-   '__text__').  */
-
-static inline tree
-lookup_attribute (const char *attr_name, tree list)
-{
-  gcc_checking_assert (attr_name[0] != '_');  
-  /* In most cases, list is NULL_TREE.  */
-  if (list == NULL_TREE)
-    return NULL_TREE;
-  else
-    /* Do the strlen() before calling the out-of-line implementation.
-       In most cases attr_name is a string constant, and the compiler
-       will optimize the strlen() away.  */
-    return private_lookup_attribute (attr_name, strlen (attr_name), list);
-}
-
-/* Given an attribute name ATTR_NAME and a list of attributes LIST,
-   return a pointer to the attribute's list first element if the attribute
-   starts with ATTR_NAME. ATTR_NAME must be in the form 'text' (not
-   '__text__').  */
-
-static inline tree
-lookup_attribute_by_prefix (const char *attr_name, tree list)
-{
-  gcc_checking_assert (attr_name[0] != '_');
-  /* In most cases, list is NULL_TREE.  */
-  if (list == NULL_TREE)
-    return NULL_TREE;
-  else
-    return private_lookup_attribute_by_prefix (attr_name, strlen (attr_name),
-					       list);
-}
-
-/* Remove any instances of attribute ATTR_NAME in LIST and return the
-   modified list.  */
-
-extern tree remove_attribute (const char *, tree);
-
-/* Given two attributes lists, return a list of their union.  */
-
-extern tree merge_attributes (tree, tree);
-
-/* Given two Windows decl attributes lists, possibly including
-   dllimport, return a list of their union .  */
-extern tree merge_dllimport_decl_attributes (tree, tree);
-
-/* Handle a "dllimport" or "dllexport" attribute.  */
-extern tree handle_dll_attribute (tree *, tree, tree, int, bool *);
-
 /* Returns true iff CAND and BASE have equivalent language-specific
    qualifiers.  */
 
diff --git a/gcc/tsan.c b/gcc/tsan.c
index 2f98b936c03..51b5821deb3 100644
--- a/gcc/tsan.c
+++ b/gcc/tsan.c
@@ -40,6 +40,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-ssa-loop-ivopts.h"
 #include "tree-eh.h"
 #include "tsan.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 #include "builtins.h"
 #include "target.h"
diff --git a/gcc/ubsan.c b/gcc/ubsan.c
index 8ea352a69d4..b66e84c6edf 100644
--- a/gcc/ubsan.c
+++ b/gcc/ubsan.c
@@ -39,6 +39,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "cfgloop.h"
 #include "ubsan.h"
 #include "expr.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 #include "gimplify-me.h"
 #include "dfp.h"
diff --git a/gcc/varasm.c b/gcc/varasm.c
index fbaebc1b5c0..a6cffb4fa66 100644
--- a/gcc/varasm.c
+++ b/gcc/varasm.c
@@ -51,6 +51,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "langhooks.h"
 #include "debug.h"
 #include "common/common-target.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 #include "rtl-iter.h"
 
diff --git a/gcc/varpool.c b/gcc/varpool.c
index ab59c80406b..b005f529cc0 100644
--- a/gcc/varpool.c
+++ b/gcc/varpool.c
@@ -33,6 +33,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "output.h"
 #include "omp-offload.h"
 #include "context.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 const char * const tls_model_names[]={"none", "emulated",
 				      "global-dynamic", "local-dynamic",
-- 
2.13.2


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

* Re: [RFC][PATCH] Do refactoring of attribute functions and move them to attribs.[hc].
  2017-07-13 13:51                       ` [RFC][PATCH] Do refactoring of attribute functions and move them to attribs.[hc] Martin Liška
@ 2017-07-14  7:23                         ` Jeff Law
  2017-07-14  7:40                           ` Martin Liška
  2017-08-04 13:53                           ` Martin Liška
  2017-09-12  7:55                         ` Jakub Jelinek
  1 sibling, 2 replies; 37+ messages in thread
From: Jeff Law @ 2017-07-14  7:23 UTC (permalink / raw)
  To: Martin Liška, Jason Merrill
  Cc: Joseph Myers, gcc-patches List, Richard Biener

On 07/13/2017 07:51 AM, Martin Liška wrote:
> Hi.
> 
> It's request for comment where I mechanically moved attribute-related function to attribs.[hc].
> 
> Patch can bootstrap on ppc64le-redhat-linux and survives regression tests.
> 
> Thoughts?
Seems reasonable.  We don't like to move things around without a good
reason and I assume you've got something in mind?

jeff

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

* Re: [RFC][PATCH] Do refactoring of attribute functions and move them to attribs.[hc].
  2017-07-14  7:23                         ` Jeff Law
@ 2017-07-14  7:40                           ` Martin Liška
  2017-08-04 13:53                           ` Martin Liška
  1 sibling, 0 replies; 37+ messages in thread
From: Martin Liška @ 2017-07-14  7:40 UTC (permalink / raw)
  To: Jeff Law, Jason Merrill; +Cc: Joseph Myers, gcc-patches List, Richard Biener

On 07/14/2017 09:23 AM, Jeff Law wrote:
> On 07/13/2017 07:51 AM, Martin Liška wrote:
>> Hi.
>>
>> It's request for comment where I mechanically moved attribute-related function to attribs.[hc].
>>
>> Patch can bootstrap on ppc64le-redhat-linux and survives regression tests.
>>
>> Thoughts?
> Seems reasonable.  We don't like to move things around without a good
> reason and I assume you've got something in mind?

Well, I basically identified that attribute-related functions are spread in between
attribs.[ch] and tree.c[ch]. And as the later ones are quite big, the code movement
logical to me.

I'm going to prepare changelog entry for that.

Martin

> 
> jeff
> 

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

* Re: [PATCH v2][RFC] Canonize names of attributes.
  2017-07-13 13:48                     ` Martin Liška
  2017-07-13 13:51                       ` [RFC][PATCH] Do refactoring of attribute functions and move them to attribs.[hc] Martin Liška
@ 2017-07-27 12:57                       ` Martin Liška
  2017-08-02 11:25                       ` Joseph Myers
  2017-08-02 19:42                       ` [PATCH v2][RFC] Canonize names of attributes Jason Merrill
  3 siblings, 0 replies; 37+ messages in thread
From: Martin Liška @ 2017-07-27 12:57 UTC (permalink / raw)
  To: Jason Merrill; +Cc: Joseph Myers, gcc-patches List, Richard Biener

PING^1

On 07/13/2017 03:48 PM, Martin Liška wrote:
> On 07/11/2017 05:52 PM, Jason Merrill wrote:
>> On Tue, Jul 11, 2017 at 9:37 AM, Martin Liška <mliska@suse.cz> wrote:
>>> On 07/03/2017 11:00 PM, Jason Merrill wrote:
>>>> On Mon, Jul 3, 2017 at 5:52 AM, Martin Liška <mliska@suse.cz> wrote:
>>>>> On 06/30/2017 09:34 PM, Jason Merrill wrote:
>>>>>>
>>>>>> On Fri, Jun 30, 2017 at 5:23 AM, Martin Liška <mliska@suse.cz> wrote:
>>>>>>>
>>>>>>> This is v2 of the patch, where just names of attributes are
>>>>>>> canonicalized.
>>>>>>> Patch can bootstrap on ppc64le-redhat-linux and survives regression
>>>>>>> tests.
>>>>>>
>>>>>>
>>>>>> What is the purpose of the new "strict" parameter to cmp_attribs* ?  I
>>>>>> don't see any discussion of it.
>>>>>
>>>>>
>>>>> It's needed for arguments of attribute names, like:
>>>>>
>>>>> /usr/include/stdio.h:391:62: internal compiler error: in cmp_attribs, at
>>>>> tree.h:5523
>>>>>        __THROWNL __attribute__ ((__format__ (__printf__, 3, 4)));
>>>>>
>>>>
>>>> Mm.  Although we don't want to automatically canonicalize all
>>>> identifier arguments to attributes in the parser, we could still do it
>>>> for specific attributes, e.g. in handle_format_attribute or
>>>> handle_mode_attribute.
>>>
>>> Yep, that was done in my previous version of the patch
>>> (https://gcc.gnu.org/ml/gcc-patches/2017-06/msg00996.html).
>>> Where only attribute that was preserved unchanged was 'cleanup':
>>>
>>> diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
>>> index 8f638785e0e..08b4db5e5bd 100644
>>> --- a/gcc/cp/parser.c
>>> +++ b/gcc/cp/parser.c
>>> @@ -24765,7 +24765,8 @@ cp_parser_gnu_attribute_list (cp_parser* parser)
>>>                   tree tv;
>>>                   if (arguments != NULL_TREE
>>>                       && ((tv = TREE_VALUE (arguments)) != NULL_TREE)
>>> -                     && TREE_CODE (tv) == IDENTIFIER_NODE)
>>> +                     && TREE_CODE (tv) == IDENTIFIER_NODE
>>> +                     && !id_equal (TREE_PURPOSE (attribute), "cleanup"))
>>>                     TREE_VALUE (arguments) = canonize_attr_name (tv);
>>>                   release_tree_vector (vec);
>>>                 }
>>>
>>> Does it work for you to do it so?
>>
>> This is canonicalizing arguments by default; I want the default to be
>> not canonicalizing arguments.  I think we only want to canonicalize
>> arguments for format and mode, and we can do that in their handle_*
>> functions.
> 
> Yep, done that in v3. I decided to move couple of functions to attribs.h and
> verified that it will not cause binary size increase of cc1 and cc1plus.
> 
> Patch can bootstrap on ppc64le-redhat-linux and survives regression tests.
> 
> Ready to be installed?
> Martin
> 
>>
>> Jason
>>
> 

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

* Re: [PATCH v2][RFC] Canonize names of attributes.
  2017-07-13 13:48                     ` Martin Liška
  2017-07-13 13:51                       ` [RFC][PATCH] Do refactoring of attribute functions and move them to attribs.[hc] Martin Liška
  2017-07-27 12:57                       ` [PATCH v2][RFC] Canonize names of attributes Martin Liška
@ 2017-08-02 11:25                       ` Joseph Myers
  2017-08-04 13:43                         ` Martin Liška
  2017-08-02 19:42                       ` [PATCH v2][RFC] Canonize names of attributes Jason Merrill
  3 siblings, 1 reply; 37+ messages in thread
From: Joseph Myers @ 2017-08-02 11:25 UTC (permalink / raw)
  To: Martin Liška; +Cc: Jason Merrill, gcc-patches List, Richard Biener

[-- Attachment #1: Type: text/plain, Size: 1922 bytes --]

On Thu, 13 Jul 2017, Martin Liška wrote:

> +/* 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);
> +  const char *s = IDENTIFIER_POINTER (attr_name);
> +
> +  if (l > 4 && s[0] == '_')
> +    {
> +      gcc_checking_assert (s[l - 2] == '_');
> +      return get_identifier_with_length (s + 2, l - 4);
> +    }
> +
> +  return attr_name;

For this to (a) be correct, (b) not trigger the assertion, there must be a 
precondition that attr_name either starts and ends with __, or does not 
start with _, or has length 4 or less.  I don't see anything in the 
callers to ensure this precondition holds, so that, for example, 
__attribute__ ((_foobar)) does not trigger the assertion, and 
__attribute__ ((_xformat__)) is not wrongly interpreted as a format 
attribute (and similarly for attribute arguments when those are 
canonicalized).

> +/* Compare attribute identifiers ATTR1 and ATTR2 with length ATTR1_LEN and
> +   ATTR2_LEN.  */
> +
> +static inline bool
> +cmp_attribs (const char *attr1, size_t attr1_len,
> +	     const char *attr2, size_t attr2_len)
> +{
> +  gcc_checking_assert (attr1_len == 0 || attr1[0] != '_');
> +  gcc_checking_assert (attr2_len == 0 || attr2[0] != '_');

Of course, once you only canonicalize attributes that both start and end 
with __, you have the possibility of a canonicalized attribute name that 
still starts with _, so can't assert on it here (unless this is only ever 
called with an attribute that is already known to be valid).  (And of 
course there are cases such as __attribute__((__)) that starts and ends 
with __ but is too short to canonicalize, etc., which arise even with the 
above canonicalize_attr_name.)

-- 
Joseph S. Myers
joseph@codesourcery.com

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

* Re: [PATCH v2][RFC] Canonize names of attributes.
  2017-07-13 13:48                     ` Martin Liška
                                         ` (2 preceding siblings ...)
  2017-08-02 11:25                       ` Joseph Myers
@ 2017-08-02 19:42                       ` Jason Merrill
  3 siblings, 0 replies; 37+ messages in thread
From: Jason Merrill @ 2017-08-02 19:42 UTC (permalink / raw)
  To: Martin Liška; +Cc: Joseph Myers, gcc-patches List, Richard Biener

OK.

On Thu, Jul 13, 2017 at 9:48 AM, Martin Liška <mliska@suse.cz> wrote:
> On 07/11/2017 05:52 PM, Jason Merrill wrote:
>> On Tue, Jul 11, 2017 at 9:37 AM, Martin Liška <mliska@suse.cz> wrote:
>>> On 07/03/2017 11:00 PM, Jason Merrill wrote:
>>>> On Mon, Jul 3, 2017 at 5:52 AM, Martin Liška <mliska@suse.cz> wrote:
>>>>> On 06/30/2017 09:34 PM, Jason Merrill wrote:
>>>>>>
>>>>>> On Fri, Jun 30, 2017 at 5:23 AM, Martin Liška <mliska@suse.cz> wrote:
>>>>>>>
>>>>>>> This is v2 of the patch, where just names of attributes are
>>>>>>> canonicalized.
>>>>>>> Patch can bootstrap on ppc64le-redhat-linux and survives regression
>>>>>>> tests.
>>>>>>
>>>>>>
>>>>>> What is the purpose of the new "strict" parameter to cmp_attribs* ?  I
>>>>>> don't see any discussion of it.
>>>>>
>>>>>
>>>>> It's needed for arguments of attribute names, like:
>>>>>
>>>>> /usr/include/stdio.h:391:62: internal compiler error: in cmp_attribs, at
>>>>> tree.h:5523
>>>>>        __THROWNL __attribute__ ((__format__ (__printf__, 3, 4)));
>>>>>
>>>>
>>>> Mm.  Although we don't want to automatically canonicalize all
>>>> identifier arguments to attributes in the parser, we could still do it
>>>> for specific attributes, e.g. in handle_format_attribute or
>>>> handle_mode_attribute.
>>>
>>> Yep, that was done in my previous version of the patch
>>> (https://gcc.gnu.org/ml/gcc-patches/2017-06/msg00996.html).
>>> Where only attribute that was preserved unchanged was 'cleanup':
>>>
>>> diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
>>> index 8f638785e0e..08b4db5e5bd 100644
>>> --- a/gcc/cp/parser.c
>>> +++ b/gcc/cp/parser.c
>>> @@ -24765,7 +24765,8 @@ cp_parser_gnu_attribute_list (cp_parser* parser)
>>>                   tree tv;
>>>                   if (arguments != NULL_TREE
>>>                       && ((tv = TREE_VALUE (arguments)) != NULL_TREE)
>>> -                     && TREE_CODE (tv) == IDENTIFIER_NODE)
>>> +                     && TREE_CODE (tv) == IDENTIFIER_NODE
>>> +                     && !id_equal (TREE_PURPOSE (attribute), "cleanup"))
>>>                     TREE_VALUE (arguments) = canonize_attr_name (tv);
>>>                   release_tree_vector (vec);
>>>                 }
>>>
>>> Does it work for you to do it so?
>>
>> This is canonicalizing arguments by default; I want the default to be
>> not canonicalizing arguments.  I think we only want to canonicalize
>> arguments for format and mode, and we can do that in their handle_*
>> functions.
>
> Yep, done that in v3. I decided to move couple of functions to attribs.h and
> verified that it will not cause binary size increase of cc1 and cc1plus.
>
> Patch can bootstrap on ppc64le-redhat-linux and survives regression tests.
>
> Ready to be installed?
> Martin
>
>>
>> Jason
>>
>

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

* Re: [PATCH v2][RFC] Canonize names of attributes.
  2017-08-02 11:25                       ` Joseph Myers
@ 2017-08-04 13:43                         ` Martin Liška
  2017-08-04 16:54                           ` Jason Merrill
  0 siblings, 1 reply; 37+ messages in thread
From: Martin Liška @ 2017-08-04 13:43 UTC (permalink / raw)
  To: Joseph Myers; +Cc: Jason Merrill, gcc-patches List, Richard Biener

[-- Attachment #1: Type: text/plain, Size: 2265 bytes --]

On 08/02/2017 01:25 PM, Joseph Myers wrote:
> On Thu, 13 Jul 2017, Martin Liška wrote:
> 
>> +/* 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);
>> +  const char *s = IDENTIFIER_POINTER (attr_name);
>> +
>> +  if (l > 4 && s[0] == '_')
>> +    {
>> +      gcc_checking_assert (s[l - 2] == '_');
>> +      return get_identifier_with_length (s + 2, l - 4);
>> +    }
>> +
>> +  return attr_name;
> 
> For this to (a) be correct, (b) not trigger the assertion, there must be a 
> precondition that attr_name either starts and ends with __, or does not 
> start with _, or has length 4 or less.  I don't see anything in the 
> callers to ensure this precondition holds, so that, for example, 
> __attribute__ ((_foobar)) does not trigger the assertion, and 
> __attribute__ ((_xformat__)) is not wrongly interpreted as a format 
> attribute (and similarly for attribute arguments when those are 
> canonicalized).

Thanks for the review. I've updated to to canonicalize just __.+__.
I added test-case for that: gcc/testsuite/gcc.dg/Wattributes-5.c.

> 
>> +/* Compare attribute identifiers ATTR1 and ATTR2 with length ATTR1_LEN and
>> +   ATTR2_LEN.  */
>> +
>> +static inline bool
>> +cmp_attribs (const char *attr1, size_t attr1_len,
>> +	     const char *attr2, size_t attr2_len)
>> +{
>> +  gcc_checking_assert (attr1_len == 0 || attr1[0] != '_');
>> +  gcc_checking_assert (attr2_len == 0 || attr2[0] != '_');

And I removed these asserts.

Patch can bootstrap on ppc64le-redhat-linux and survives regression tests.

Ready to be installed?
Martin

> 
> Of course, once you only canonicalize attributes that both start and end 
> with __, you have the possibility of a canonicalized attribute name that 
> still starts with _, so can't assert on it here (unless this is only ever 
> called with an attribute that is already known to be valid).  (And of 
> course there are cases such as __attribute__((__)) that starts and ends 
> with __ but is too short to canonicalize, etc., which arise even with the 
> above canonicalize_attr_name.)
> 


[-- Attachment #2: 0001-Canonicalize-names-of-attributes.patch --]
[-- Type: text/x-patch, Size: 20855 bytes --]

From 06c710c9eb74212d78dd82c5fcb36a86a368a086 Mon Sep 17 00:00:00 2001
From: marxin <mliska@suse.cz>
Date: Thu, 8 Jun 2017 10:23:25 +0200
Subject: [PATCH 1/2] Canonicalize names of attributes.

gcc/ChangeLog:

2017-07-12  Martin Liska  <mliska@suse.cz>

	* attribs.h (canonicalize_attr_name): New function.
	(cmp_attribs): Move from c-format.c and adjusted.
	(is_attribute_p): Moved from tree.h.
	* tree-inline.c: Add new includes.
	* tree.c (cmp_attrib_identifiers): Use cmp_attribs.
	(private_is_attribute_p): Remove.
	(private_lookup_attribute): Likewise.
	(private_lookup_attribute_by_prefix): Simplify.
	(remove_attribute): Use is_attribute_p.
	* tree.h: Remove removed declarations.

gcc/c-family/ChangeLog:

2017-07-12  Martin Liska  <mliska@suse.cz>

	* array-notation-common.c: Add new includes.
	* c-format.c( handle_format_attribute): Canonicalize a format
	function name.
	* c-lex.c (c_common_has_attribute): Canonicalize name of an
	attribute.
	* c-pretty-print.c: Add new include.

gcc/cp/ChangeLog:

2017-07-12  Martin Liska  <mliska@suse.cz>

	* parser.c (cp_parser_gnu_attribute_list): Canonicalize name of an
	attribute.
	(cp_parser_std_attribute): Likewise.
	* tree.c: Add new include.

gcc/c/ChangeLog:

2017-07-12  Martin Liska  <mliska@suse.cz>

	* c-parser.c (c_parser_attributes): Canonicalize name of an
	attribute.
gcc/go/ChangeLog:

2017-06-29  Martin Liska  <mliska@suse.cz>

	* go-gcc.cc (Gcc_backend::function): Look up for no_split_stack
	and not __no_split_stack__.

gcc/testsuite/ChangeLog:

2017-06-29  Martin Liska  <mliska@suse.cz>

	* g++.dg/cpp0x/pr65558.C: Update scanned pattern.
	* gcc.dg/parm-impl-decl-1.c: Likewise.
	* gcc.dg/parm-impl-decl-3.c: Likewise.
	* gcc.dg/Wattributes-5.c: New test.
---
 gcc/attribs.h                           |  43 +++++++++++++
 gcc/c-family/array-notation-common.c    |   2 +
 gcc/c-family/c-format.c                 |  24 ++------
 gcc/c-family/c-lex.c                    |   1 +
 gcc/c-family/c-pretty-print.c           |   1 +
 gcc/c/c-parser.c                        |   3 +
 gcc/cp/parser.c                         |   6 +-
 gcc/cp/tree.c                           |   1 +
 gcc/go/go-gcc.cc                        |   2 +-
 gcc/testsuite/g++.dg/cpp0x/pr65558.C    |   2 +-
 gcc/testsuite/gcc.dg/Wattributes-5.c    |  13 ++++
 gcc/testsuite/gcc.dg/parm-impl-decl-1.c |   2 +-
 gcc/testsuite/gcc.dg/parm-impl-decl-3.c |   2 +-
 gcc/tree-inline.c                       |   3 +-
 gcc/tree.c                              | 104 +++++---------------------------
 gcc/tree.h                              |  23 +------
 16 files changed, 95 insertions(+), 137 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/Wattributes-5.c

diff --git a/gcc/attribs.h b/gcc/attribs.h
index 7f13332700e..d4a790bb753 100644
--- a/gcc/attribs.h
+++ b/gcc/attribs.h
@@ -47,4 +47,47 @@ extern char *make_unique_name (tree, const char *, bool);
 extern tree make_dispatcher_decl (const tree);
 extern bool is_function_default_version (const tree);
 
+/* 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);
+  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);
+
+  return attr_name;
+}
+
+/* Compare attribute identifiers ATTR1 and ATTR2 with length ATTR1_LEN and
+   ATTR2_LEN.  */
+
+static inline bool
+cmp_attribs (const char *attr1, size_t attr1_len,
+	     const char *attr2, size_t attr2_len)
+{
+  return attr1_len == attr2_len && strncmp (attr1, attr2, attr1_len) == 0;
+}
+
+/* Compare attribute identifiers ATTR1 and ATTR2.  */
+
+static inline bool
+cmp_attribs (const char *attr1, const char *attr2)
+{
+  return cmp_attribs (attr1, strlen (attr1), attr2, strlen (attr2));
+}
+
+/* Given an identifier node IDENT and a string ATTR_NAME, return true
+   if the identifier node is a valid attribute name for the string.  */
+
+static inline bool
+is_attribute_p (const char *attr_name, const_tree ident)
+{
+  return cmp_attribs (attr_name, strlen (attr_name),
+		      IDENTIFIER_POINTER (ident), IDENTIFIER_LENGTH (ident));
+}
+
 #endif // GCC_ATTRIBS_H
diff --git a/gcc/c-family/array-notation-common.c b/gcc/c-family/array-notation-common.c
index 3b95332adad..a4809948e20 100644
--- a/gcc/c-family/array-notation-common.c
+++ b/gcc/c-family/array-notation-common.c
@@ -27,6 +27,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "options.h"
 #include "c-family/c-common.h"
 #include "tree-iterator.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* Returns true if the function call in FNDECL is  __sec_implicit_index.  */
 
diff --git a/gcc/c-family/c-format.c b/gcc/c-family/c-format.c
index 0a5cc03fd4e..5e5b494383f 100644
--- a/gcc/c-family/c-format.c
+++ b/gcc/c-family/c-format.c
@@ -33,6 +33,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "substring-locations.h"
 #include "selftest.h"
 #include "builtins.h"
+#include "attribs.h"
 
 /* Handle attributes associated with format checking.  */
 
@@ -67,7 +68,6 @@ static bool check_format_string (tree argument,
 static bool get_constant (tree expr, unsigned HOST_WIDE_INT *value,
 			  int validated_p);
 static const char *convert_format_name_to_system_name (const char *attr_name);
-static bool cmp_attribs (const char *tattr_name, const char *attr_name);
 
 static int first_target_format_type;
 static const char *format_name (int format_num);
@@ -3976,24 +3976,6 @@ convert_format_name_to_system_name (const char *attr_name)
   return attr_name;
 }
 
-/* Return true if TATTR_NAME and ATTR_NAME are the same format attribute,
-   counting "name" and "__name__" as the same, false otherwise.  */
-static bool
-cmp_attribs (const char *tattr_name, const char *attr_name)
-{
-  int alen = strlen (attr_name);
-  int slen = (tattr_name ? strlen (tattr_name) : 0);
-  if (alen > 4 && attr_name[0] == '_' && attr_name[1] == '_'
-      && attr_name[alen - 1] == '_' && attr_name[alen - 2] == '_')
-    {
-      attr_name += 2;
-      alen -= 4;
-    }
-  if (alen != slen || strncmp (tattr_name, attr_name, alen) != 0)
-    return false;
-  return true;
-}
-
 /* Handle a "format" attribute; arguments as in
    struct attribute_spec.handler.  */
 tree
@@ -4022,6 +4004,10 @@ handle_format_attribute (tree *node, tree ARG_UNUSED (name), tree args,
     }
 #endif
 
+  /* Canonicalize name of format function.  */
+  if (TREE_CODE (TREE_VALUE (args)) == IDENTIFIER_NODE)
+    TREE_VALUE (args) = canonicalize_attr_name (TREE_VALUE (args));
+
   if (!decode_format_attr (args, &info, 0))
     {
       *no_add_attrs = true;
diff --git a/gcc/c-family/c-lex.c b/gcc/c-family/c-lex.c
index e1c8bdff986..3765a800a57 100644
--- a/gcc/c-family/c-lex.c
+++ b/gcc/c-family/c-lex.c
@@ -316,6 +316,7 @@ c_common_has_attribute (cpp_reader *pfile)
     {
       attr_name = get_identifier ((const char *)
 				  cpp_token_as_text (pfile, token));
+      attr_name = canonicalize_attr_name (attr_name);
       if (c_dialect_cxx ())
 	{
 	  int idx = 0;
diff --git a/gcc/c-family/c-pretty-print.c b/gcc/c-family/c-pretty-print.c
index fdb7b41f592..b8b8f665ef3 100644
--- a/gcc/c-family/c-pretty-print.c
+++ b/gcc/c-family/c-pretty-print.c
@@ -24,6 +24,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "c-pretty-print.h"
 #include "diagnostic.h"
 #include "stor-layout.h"
+#include "stringpool.h"
 #include "attribs.h"
 #include "intl.h"
 #include "tree-pretty-print.h"
diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
index 16cd3579972..2bc7a613ef7 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -4170,9 +4170,11 @@ c_parser_attributes (c_parser *parser)
 	  attr_name = c_parser_attribute_any_word (parser);
 	  if (attr_name == NULL)
 	    break;
+	  attr_name = canonicalize_attr_name (attr_name);
 	  if (is_cilkplus_vector_p (attr_name))
 	    {
 	      c_token *v_token = c_parser_peek_token (parser);
+	      v_token->value = canonicalize_attr_name (v_token->value);
 	      c_parser_cilk_simd_fn_vector_attrs (parser, *v_token);
 	      /* If the next token isn't a comma, we're done.  */
 	      if (!c_parser_next_token_is (parser, CPP_COMMA))
@@ -4236,6 +4238,7 @@ c_parser_attributes (c_parser *parser)
 		  release_tree_vector (expr_list);
 		}
 	    }
+
 	  attr = build_tree_list (attr_name, attr_args);
 	  if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
 	    c_parser_consume_token (parser);
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 88d0b2b250d..23bd2784ea4 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -24782,7 +24782,8 @@ cp_parser_gnu_attribute_list (cp_parser* parser)
 	       parsed identifier.  */
 	    ? ridpointers[(int) token->keyword]
 	    : id_token->u.value;
-	  
+
+	  identifier = canonicalize_attr_name (identifier);
 	  attribute = build_tree_list (identifier, NULL_TREE);
 
 	  /* Peek at the next token.  */
@@ -24928,6 +24929,8 @@ cp_parser_std_attribute (cp_parser *parser, tree attr_ns)
 		    "expected an identifier for the attribute name");
 	  return error_mark_node;
 	}
+
+      attr_id = canonicalize_attr_name (attr_id);
       attribute = build_tree_list (build_tree_list (attr_ns, attr_id),
 				   NULL_TREE);
       token = cp_lexer_peek_token (parser->lexer);
@@ -24937,6 +24940,7 @@ cp_parser_std_attribute (cp_parser *parser, tree attr_ns)
 				 NULL_TREE);
   else
     {
+      attr_id = canonicalize_attr_name (attr_id);
       attribute = build_tree_list (build_tree_list (NULL_TREE, attr_id),
 				   NULL_TREE);
       /* C++11 noreturn attribute is equivalent to GNU's.  */
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index 2122450c653..8f18665da41 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -32,6 +32,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "debug.h"
 #include "convert.h"
 #include "gimplify.h"
+#include "stringpool.h"
 #include "attribs.h"
 #include "flags.h"
 
diff --git a/gcc/go/go-gcc.cc b/gcc/go/go-gcc.cc
index a7977fe03c1..04912f0ed01 100644
--- a/gcc/go/go-gcc.cc
+++ b/gcc/go/go-gcc.cc
@@ -3046,7 +3046,7 @@ Gcc_backend::function(Btype* fntype, const std::string& name,
     DECL_UNINLINABLE(decl) = 1;
   if (disable_split_stack)
     {
-      tree attr = get_identifier("__no_split_stack__");
+      tree attr = get_identifier ("no_split_stack");
       DECL_ATTRIBUTES(decl) = tree_cons(attr, NULL_TREE, NULL_TREE);
     }
   if (in_unique_section)
diff --git a/gcc/testsuite/g++.dg/cpp0x/pr65558.C b/gcc/testsuite/g++.dg/cpp0x/pr65558.C
index d294c95a657..12946b35eda 100644
--- a/gcc/testsuite/g++.dg/cpp0x/pr65558.C
+++ b/gcc/testsuite/g++.dg/cpp0x/pr65558.C
@@ -2,6 +2,6 @@
 // { dg-do compile { target c++11 } }
 
 inline namespace
-__attribute__((__abi_tag__)) // { dg-warning "ignoring .__abi_tag__. attribute on anonymous namespace" }
+__attribute__((__abi_tag__)) // { dg-warning "ignoring .abi_tag. attribute on anonymous namespace" }
 {
 }
diff --git a/gcc/testsuite/gcc.dg/Wattributes-5.c b/gcc/testsuite/gcc.dg/Wattributes-5.c
new file mode 100644
index 00000000000..34483391e6d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wattributes-5.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options -Wattributes } */
+
+void __attribute__((_foobar)) foo() { }		/* { dg-warning "attribute directive ignored" } */
+void __attribute__((_xformat__)) foo2() { }	/* { dg-warning "attribute directive ignored" } */
+void __attribute__((xformat__)) foo3() { }	/* { dg-warning "attribute directive ignored" } */
+void __attribute__((__xformat)) foo4() { }	/* { dg-warning "attribute directive ignored" } */
+void __attribute__((_)) foo5() { }	/* { dg-warning "attribute directive ignored" } */
+void __attribute__((_)) foo6() { }	/* { dg-warning "attribute directive ignored" } */
+void __attribute__((__)) foo7() { }	/* { dg-warning "attribute directive ignored" } */
+void __attribute__((___)) foo8() { }	/* { dg-warning "attribute directive ignored" } */
+void __attribute__((____)) foo9() { }	/* { dg-warning "attribute directive ignored" } */
+void __attribute__((_____)) foo10() { }	/* { dg-warning "attribute directive ignored" } */
diff --git a/gcc/testsuite/gcc.dg/parm-impl-decl-1.c b/gcc/testsuite/gcc.dg/parm-impl-decl-1.c
index 5c7ddb0a259..c1219273c75 100644
--- a/gcc/testsuite/gcc.dg/parm-impl-decl-1.c
+++ b/gcc/testsuite/gcc.dg/parm-impl-decl-1.c
@@ -7,7 +7,7 @@
 /* Implicit function declaration in attribute in definition (testcase
    from bug).  */
 int
-foo (int __attribute__ ((__mode__ (vector_size(8)))) i) /* { dg-warning "'__mode__' attribute ignored" } */
+foo (int __attribute__ ((__mode__ (vector_size(8)))) i) /* { dg-warning "'mode' attribute ignored" } */
 {
   return (long long) i;
 }
diff --git a/gcc/testsuite/gcc.dg/parm-impl-decl-3.c b/gcc/testsuite/gcc.dg/parm-impl-decl-3.c
index 904295258d7..20197b52402 100644
--- a/gcc/testsuite/gcc.dg/parm-impl-decl-3.c
+++ b/gcc/testsuite/gcc.dg/parm-impl-decl-3.c
@@ -4,7 +4,7 @@
 /* { dg-options "-g -std=gnu89" } */
 
 int
-foo (int __attribute__ ((__mode__ (vector_size(8)))) i) /* { dg-warning "'__mode__' attribute ignored" } */
+foo (int __attribute__ ((__mode__ (vector_size(8)))) i) /* { dg-warning "'mode' attribute ignored" } */
 {
   return (long long) i;
 }
diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c
index d4e4ef17247..affde64d2fd 100644
--- a/gcc/tree-inline.c
+++ b/gcc/tree-inline.c
@@ -57,7 +57,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "cfgloop.h"
 #include "builtins.h"
 #include "tree-chkp.h"
-
+#include "stringpool.h"
+#include "attribs.h"
 
 /* I'm not real happy about this, but we need to handle gimple and
    non-gimple trees.  */
diff --git a/gcc/tree.c b/gcc/tree.c
index 0c5acd6c8a6..2b65cb1d125 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -4946,9 +4946,8 @@ simple_cst_list_equal (const_tree l1, const_tree l2)
   return l1 == l2;
 }
 
-/* Compare two identifier nodes representing attributes.  Either one may
-   be in wrapped __ATTR__ form.  Return true if they are the same, false
-   otherwise.  */
+/* Compare two identifier nodes representing attributes.
+   Return true if they are the same, false otherwise.  */
 
 static bool
 cmp_attrib_identifiers (const_tree attr1, const_tree attr2)
@@ -4961,34 +4960,8 @@ cmp_attrib_identifiers (const_tree attr1, const_tree attr2)
   if (attr1 == attr2)
     return true;
 
-  /* If they are not equal, they may still be one in the form
-     'text' while the other one is in the form '__text__'.  TODO:
-     If we were storing attributes in normalized 'text' form, then
-     this could all go away and we could take full advantage of
-     the fact that we're comparing identifiers. :-)  */
-  const size_t attr1_len = IDENTIFIER_LENGTH (attr1);
-  const size_t attr2_len = IDENTIFIER_LENGTH (attr2);
-
-  if (attr2_len == attr1_len + 4)
-    {
-      const char *p = IDENTIFIER_POINTER (attr2);
-      const char *q = IDENTIFIER_POINTER (attr1);
-      if (p[0] == '_' && p[1] == '_'
-	  && p[attr2_len - 2] == '_' && p[attr2_len - 1] == '_'
-	  && strncmp (q, p + 2, attr1_len) == 0)
-	return true;;
-    }
-  else if (attr2_len + 4 == attr1_len)
-    {
-      const char *p = IDENTIFIER_POINTER (attr2);
-      const char *q = IDENTIFIER_POINTER (attr1);
-      if (q[0] == '_' && q[1] == '_'
-	  && q[attr1_len - 2] == '_' && q[attr1_len - 1] == '_'
-	  && strncmp (q + 2, p, attr2_len) == 0)
-	return true;
-    }
-
-  return false;
+  return cmp_attribs (IDENTIFIER_POINTER (attr1), IDENTIFIER_LENGTH (attr1),
+		      IDENTIFIER_POINTER (attr2), IDENTIFIER_LENGTH (attr2));
 }
 
 /* Compare two attributes for their value identity.  Return true if the
@@ -6051,32 +6024,6 @@ make_pass_ipa_free_lang_data (gcc::context *ctxt)
   return new pass_ipa_free_lang_data (ctxt);
 }
 
-/* The backbone of is_attribute_p().  ATTR_LEN is the string length of
-   ATTR_NAME.  Also used internally by remove_attribute().  */
-bool
-private_is_attribute_p (const char *attr_name, size_t attr_len, const_tree ident)
-{
-  size_t ident_len = IDENTIFIER_LENGTH (ident);
-
-  if (ident_len == attr_len)
-    {
-      if (id_equal (ident, attr_name))
-	return true;
-    }
-  else if (ident_len == attr_len + 4)
-    {
-      /* There is the possibility that ATTR is 'text' and IDENT is
-	 '__text__'.  */
-      const char *p = IDENTIFIER_POINTER (ident);      
-      if (p[0] == '_' && p[1] == '_'
-	  && p[ident_len - 2] == '_' && p[ident_len - 1] == '_'
-	  && strncmp (attr_name, p + 2, attr_len) == 0)
-	return true;
-    }
-
-  return false;
-}
-
 /* The backbone of lookup_attribute().  ATTR_LEN is the string length
    of ATTR_NAME, and LIST is not NULL_TREE.  */
 tree
@@ -6084,25 +6031,11 @@ private_lookup_attribute (const char *attr_name, size_t attr_len, tree list)
 {
   while (list)
     {
-      size_t ident_len = IDENTIFIER_LENGTH (get_attribute_name (list));
-
-      if (ident_len == attr_len)
-	{
-	  if (!strcmp (attr_name,
-		       IDENTIFIER_POINTER (get_attribute_name (list))))
-	    break;
-	}
-      /* TODO: If we made sure that attributes were stored in the
-	 canonical form without '__...__' (ie, as in 'text' as opposed
-	 to '__text__') then we could avoid the following case.  */
-      else if (ident_len == attr_len + 4)
-	{
-	  const char *p = IDENTIFIER_POINTER (get_attribute_name (list));
-	  if (p[0] == '_' && p[1] == '_'
-	      && p[ident_len - 2] == '_' && p[ident_len - 1] == '_'
-	      && strncmp (attr_name, p + 2, attr_len) == 0)
-	    break;
-	}
+      tree attr = get_attribute_name (list);
+      size_t ident_len = IDENTIFIER_LENGTH (attr);
+      if (cmp_attribs (attr_name, attr_len, IDENTIFIER_POINTER (attr),
+		       ident_len))
+	break;
       list = TREE_CHAIN (list);
     }
 
@@ -6111,8 +6044,7 @@ private_lookup_attribute (const char *attr_name, size_t attr_len, tree list)
 
 /* Given an attribute name ATTR_NAME and a list of attributes LIST,
    return a pointer to the attribute's list first element if the attribute
-   starts with ATTR_NAME. ATTR_NAME must be in the form 'text' (not
-   '__text__').  */
+   starts with ATTR_NAME.  */
 
 tree
 private_lookup_attribute_by_prefix (const char *attr_name, size_t attr_len,
@@ -6129,17 +6061,11 @@ private_lookup_attribute_by_prefix (const char *attr_name, size_t attr_len,
 	}
 
       const char *p = IDENTIFIER_POINTER (get_attribute_name (list));
+      gcc_checking_assert (attr_len == 0 || p[0] != '_');
 
       if (strncmp (attr_name, p, attr_len) == 0)
 	break;
 
-      /* TODO: If we made sure that attributes were stored in the
-	 canonical form without '__...__' (ie, as in 'text' as opposed
-	 to '__text__') then we could avoid the following case.  */
-      if (p[0] == '_' && p[1] == '_' &&
-	  strncmp (attr_name, p + 2, attr_len) == 0)
-	break;
-
       list = TREE_CHAIN (list);
     }
 
@@ -6185,16 +6111,14 @@ tree
 remove_attribute (const char *attr_name, tree list)
 {
   tree *p;
-  size_t attr_len = strlen (attr_name);
-
   gcc_checking_assert (attr_name[0] != '_');
 
   for (p = &list; *p; )
     {
       tree l = *p;
-      /* TODO: If we were storing attributes in normalized form, here
-	 we could use a simple strcmp().  */
-      if (private_is_attribute_p (attr_name, attr_len, get_attribute_name (l)))
+
+      tree attr = get_attribute_name (l);
+      if (is_attribute_p (attr_name, attr))
 	*p = TREE_CHAIN (l);
       else
 	p = &TREE_CHAIN (l);
diff --git a/gcc/tree.h b/gcc/tree.h
index d955b58d82a..1e89809804c 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -4195,29 +4195,8 @@ lookup_attribute_by_prefix (const char *attr_name, tree list)
 					       list);
 }
 
-
-/* This function is a private implementation detail of
-   is_attribute_p() and you should never call it directly.  */
-extern bool private_is_attribute_p (const char *, size_t, const_tree);
-
-/* Given an identifier node IDENT and a string ATTR_NAME, return true
-   if the identifier node is a valid attribute name for the string.
-   ATTR_NAME must be in the form 'text' (not '__text__').  IDENT could
-   be the identifier for 'text' or for '__text__'.  */
-
-static inline bool
-is_attribute_p (const char *attr_name, const_tree ident)
-{
-  gcc_checking_assert (attr_name[0] != '_');
-  /* Do the strlen() before calling the out-of-line implementation.
-     In most cases attr_name is a string constant, and the compiler
-     will optimize the strlen() away.  */
-  return private_is_attribute_p (attr_name, strlen (attr_name), ident);
-}
-
 /* Remove any instances of attribute ATTR_NAME in LIST and return the
-   modified list.  ATTR_NAME must be in the form 'text' (not
-   '__text__').  */
+   modified list.  */
 
 extern tree remove_attribute (const char *, tree);
 
-- 
2.13.3


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

* Re: [RFC][PATCH] Do refactoring of attribute functions and move them to attribs.[hc].
  2017-07-14  7:23                         ` Jeff Law
  2017-07-14  7:40                           ` Martin Liška
@ 2017-08-04 13:53                           ` Martin Liška
  2017-08-08  4:37                             ` Martin Liška
  1 sibling, 1 reply; 37+ messages in thread
From: Martin Liška @ 2017-08-04 13:53 UTC (permalink / raw)
  To: Jeff Law, Jason Merrill; +Cc: Joseph Myers, gcc-patches List, Richard Biener

[-- Attachment #1: Type: text/plain, Size: 565 bytes --]

On 07/14/2017 09:23 AM, Jeff Law wrote:
> On 07/13/2017 07:51 AM, Martin Liška wrote:
>> Hi.
>>
>> It's request for comment where I mechanically moved attribute-related function to attribs.[hc].
>>
>> Patch can bootstrap on ppc64le-redhat-linux and survives regression tests.
>>
>> Thoughts?
> Seems reasonable.  We don't like to move things around without a good
> reason and I assume you've got something in mind?
> 
> jeff
> 

Thanks. There's updated version (w/ ChangeLog)
of the patch that I'll install right after the first patch will be included.

Martin

[-- Attachment #2: 0002-Do-refactoring-of-attribute-functions-and-move-them-.patch --]
[-- Type: text/x-patch, Size: 89810 bytes --]

From 140b161f5dab7bba318a233259fbd002abbd0002 Mon Sep 17 00:00:00 2001
From: marxin <mliska@suse.cz>
Date: Wed, 12 Jul 2017 13:39:54 +0200
Subject: [PATCH 2/2] Do refactoring of attribute functions and move them to
 attribs.[hc].

gcc/ada/ChangeLog:

2017-08-04  Martin Liska  <mliska@suse.cz>

	* gcc-interface/trans.c: Include header files.

gcc/objc/ChangeLog:

2017-08-04  Martin Liska  <mliska@suse.cz>

	* objc-gnu-runtime-abi-01.c: Include header files.
	* objc-next-runtime-abi-01.c: Likewise.
	* objc-next-runtime-abi-02.c: Likewise.

gcc/ChangeLog:

2017-08-04  Martin Liska  <mliska@suse.cz>

	* asan.c: Include header files.
	* attribs.c (build_decl_attribute_variant): New function moved
	from tree.[ch].
	(build_type_attribute_qual_variant): Likewise.
	(cmp_attrib_identifiers): Likewise.
	(simple_cst_list_equal): Likewise.
	(omp_declare_simd_clauses_equal): Likewise.
	(attribute_value_equal): Likewise.
	(comp_type_attributes): Likewise.
	(build_type_attribute_variant): Likewise.
	(lookup_ident_attribute): Likewise.
	(remove_attribute): Likewise.
	(merge_attributes): Likewise.
	(merge_type_attributes): Likewise.
	(merge_decl_attributes): Likewise.
	(merge_dllimport_decl_attributes): Likewise.
	(handle_dll_attribute): Likewise.
	(attribute_list_equal): Likewise.
	(attribute_list_contained): Likewise.
	* attribs.h (lookup_attribute): New function moved from tree.[ch].
	(lookup_attribute_by_prefix): Likewise.
	* bb-reorder.c: Include header files.
	* builtins.c: Likewise.
	* calls.c: Likewise.
	* cfgexpand.c: Likewise.
	* cgraph.c: Likewise.
	* cgraphunit.c: Likewise.
	* convert.c: Likewise.
	* dwarf2out.c: Likewise.
	* final.c: Likewise.
	* fold-const.c: Likewise.
	* function.c: Likewise.
	* gimple-expr.c: Likewise.
	* gimple-fold.c: Likewise.
	* gimple-pretty-print.c: Likewise.
	* gimple.c: Likewise.
	* gimplify.c: Likewise.
	* hsa-common.c: Likewise.
	* hsa-gen.c: Likewise.
	* internal-fn.c: Likewise.
	* ipa-chkp.c: Likewise.
	* ipa-cp.c: Likewise.
	* ipa-devirt.c: Likewise.
	* ipa-fnsummary.c: Likewise.
	* ipa-inline.c: Likewise.
	* ipa-visibility.c: Likewise.
	* ipa.c: Likewise.
	* lto-cgraph.c: Likewise.
	* omp-expand.c: Likewise.
	* omp-general.c: Likewise.
	* omp-low.c: Likewise.
	* omp-offload.c: Likewise.
	* omp-simd-clone.c: Likewise.
	* opts-global.c: Likewise.
	* passes.c: Likewise.
	* predict.c: Likewise.
	* sancov.c: Likewise.
	* sanopt.c: Likewise.
	* symtab.c: Likewise.
	* toplev.c: Likewise.
	* trans-mem.c: Likewise.
	* tree-chkp.c: Likewise.
	* tree-eh.c: Likewise.
	* tree-into-ssa.c: Likewise.
	* tree-object-size.c: Likewise.
	* tree-parloops.c: Likewise.
	* tree-profile.c: Likewise.
	* tree-ssa-ccp.c: Likewise.
	* tree-ssa-live.c: Likewise.
	* tree-ssa-loop.c: Likewise.
	* tree-ssa-sccvn.c: Likewise.
	* tree-ssa-structalias.c: Likewise.
	* tree-ssa.c: Likewise.
	* tree-streamer-in.c: Likewise.
	* tree-vectorizer.c: Likewise.
	* tree-vrp.c: Likewise.
	* tsan.c: Likewise.
	* ubsan.c: Likewise.
	* varasm.c: Likewise.
	* varpool.c: Likewise.
	* tree.c: Remove functions moved to attribs.[ch].
	* tree.h: Likewise.

gcc/cp/ChangeLog:

2017-08-04  Martin Liska  <mliska@suse.cz>

	* call.c: Include header files.
	* cp-gimplify.c: Likewise.
	* cp-ubsan.c: Likewise.
	* cvt.c: Likewise.
	* init.c: Likewise.
	* search.c: Likewise.
	* semantics.c: Likewise.
	* typeck.c: Likewise.

gcc/lto/ChangeLog:

2017-08-04  Martin Liska  <mliska@suse.cz>

	* lto-lang.c: Include header files.
	* lto-symtab.c: Likewise.

gcc/c/ChangeLog:

2017-08-04  Martin Liska  <mliska@suse.cz>

	* c-convert.c: Include header files.
	* c-typeck.c: Likewise.

gcc/c-family/ChangeLog:

2017-08-04  Martin Liska  <mliska@suse.cz>

	* c-ada-spec.c: Include header files.
	* c-ubsan.c: Likewise.
	* c-warn.c: Likewise.

gcc/fortran/ChangeLog:

2017-08-04  Martin Liska  <mliska@suse.cz>

	* trans-types.c: Include header files.
---
 gcc/ada/gcc-interface/trans.c       |   2 +
 gcc/asan.c                          |   2 +
 gcc/attribs.c                       | 633 +++++++++++++++++++++++++++++++++
 gcc/attribs.h                       | 113 ++++++
 gcc/bb-reorder.c                    |   2 +
 gcc/builtins.c                      |   2 +
 gcc/c-family/c-ada-spec.c           |   2 +
 gcc/c-family/c-ubsan.c              |   4 +-
 gcc/c-family/c-warn.c               |   2 +
 gcc/c/c-convert.c                   |   2 +
 gcc/c/c-typeck.c                    |   2 +
 gcc/calls.c                         |   2 +
 gcc/cfgexpand.c                     |   2 +
 gcc/cgraph.c                        |   2 +
 gcc/cgraphunit.c                    |   2 +
 gcc/convert.c                       |   2 +
 gcc/cp/call.c                       |   2 +
 gcc/cp/cp-gimplify.c                |   2 +
 gcc/cp/cp-ubsan.c                   |   2 +
 gcc/cp/cvt.c                        |   2 +
 gcc/cp/init.c                       |   2 +
 gcc/cp/search.c                     |   2 +
 gcc/cp/semantics.c                  |   2 +
 gcc/cp/typeck.c                     |   2 +
 gcc/dwarf2out.c                     |   2 +
 gcc/final.c                         |   2 +
 gcc/fold-const.c                    |   2 +
 gcc/fortran/trans-types.c           |   1 +
 gcc/function.c                      |   2 +
 gcc/gimple-expr.c                   |   2 +
 gcc/gimple-fold.c                   |   2 +
 gcc/gimple-pretty-print.c           |   2 +
 gcc/gimple.c                        |   2 +
 gcc/gimplify.c                      |   2 +
 gcc/hsa-common.c                    |   2 +
 gcc/hsa-gen.c                       |   2 +
 gcc/internal-fn.c                   |   2 +
 gcc/ipa-chkp.c                      |   2 +
 gcc/ipa-cp.c                        |   2 +
 gcc/ipa-devirt.c                    |   2 +
 gcc/ipa-fnsummary.c                 |   2 +
 gcc/ipa-inline.c                    |   2 +
 gcc/ipa-visibility.c                |   2 +
 gcc/ipa.c                           |   3 +-
 gcc/lto-cgraph.c                    |   2 +
 gcc/lto/lto-lang.c                  |   2 +
 gcc/lto/lto-symtab.c                |   2 +
 gcc/objc/objc-gnu-runtime-abi-01.c  |   2 +
 gcc/objc/objc-next-runtime-abi-01.c |   2 +
 gcc/objc/objc-next-runtime-abi-02.c |   2 +
 gcc/omp-expand.c                    |   3 +-
 gcc/omp-general.c                   |   3 +-
 gcc/omp-low.c                       |   2 +
 gcc/omp-offload.c                   |   2 +
 gcc/omp-simd-clone.c                |   3 +-
 gcc/opts-global.c                   |   2 +
 gcc/passes.c                        |   2 +
 gcc/predict.c                       |   2 +
 gcc/sancov.c                        |   2 +
 gcc/sanopt.c                        |   2 +
 gcc/symtab.c                        |   2 +
 gcc/toplev.c                        |   2 +
 gcc/trans-mem.c                     |   3 +-
 gcc/tree-chkp.c                     |   2 +
 gcc/tree-eh.c                       |   2 +
 gcc/tree-into-ssa.c                 |   2 +
 gcc/tree-object-size.c              |   2 +
 gcc/tree-parloops.c                 |   2 +
 gcc/tree-profile.c                  |   2 +
 gcc/tree-ssa-ccp.c                  |   2 +
 gcc/tree-ssa-live.c                 |   2 +
 gcc/tree-ssa-loop.c                 |   2 +
 gcc/tree-ssa-sccvn.c                |   2 +
 gcc/tree-ssa-structalias.c          |   3 +-
 gcc/tree-ssa.c                      |   2 +
 gcc/tree-streamer-in.c              |   2 +
 gcc/tree-vectorizer.c               |   2 +
 gcc/tree-vrp.c                      |   2 +
 gcc/tree.c                          | 685 +-----------------------------------
 gcc/tree.h                          |  86 -----
 gcc/tsan.c                          |   2 +
 gcc/ubsan.c                         |   2 +
 gcc/varasm.c                        |   2 +
 gcc/varpool.c                       |   2 +
 84 files changed, 908 insertions(+), 776 deletions(-)

diff --git a/gcc/ada/gcc-interface/trans.c b/gcc/ada/gcc-interface/trans.c
index 7844bd7c5a8..67044b7b574 100644
--- a/gcc/ada/gcc-interface/trans.c
+++ b/gcc/ada/gcc-interface/trans.c
@@ -46,6 +46,8 @@
 #include "gimplify.h"
 #include "opts.h"
 #include "common/common-target.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 #include "ada.h"
 #include "adadecode.h"
diff --git a/gcc/asan.c b/gcc/asan.c
index 5f9275f6425..f83ca65ffdb 100644
--- a/gcc/asan.c
+++ b/gcc/asan.c
@@ -47,6 +47,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "varasm.h"
 #include "stor-layout.h"
 #include "tree-iterator.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 #include "dojump.h"
 #include "explow.h"
diff --git a/gcc/attribs.c b/gcc/attribs.c
index 05fa8ef8692..faa0649e190 100644
--- a/gcc/attribs.c
+++ b/gcc/attribs.c
@@ -942,3 +942,636 @@ is_function_default_version (const tree decl)
   return (TREE_CODE (attr) == STRING_CST
 	  && strcmp (TREE_STRING_POINTER (attr), "default") == 0);
 }
+
+/* Return a declaration like DDECL except that its DECL_ATTRIBUTES
+   is ATTRIBUTE.  */
+
+tree
+build_decl_attribute_variant (tree ddecl, tree attribute)
+{
+  DECL_ATTRIBUTES (ddecl) = attribute;
+  return ddecl;
+}
+
+/* Return a type like TTYPE except that its TYPE_ATTRIBUTE
+   is ATTRIBUTE and its qualifiers are QUALS.
+
+   Record such modified types already made so we don't make duplicates.  */
+
+tree
+build_type_attribute_qual_variant (tree ttype, tree attribute, int quals)
+{
+  if (! attribute_list_equal (TYPE_ATTRIBUTES (ttype), attribute))
+    {
+      tree ntype;
+
+      /* Building a distinct copy of a tagged type is inappropriate; it
+	 causes breakage in code that expects there to be a one-to-one
+	 relationship between a struct and its fields.
+	 build_duplicate_type is another solution (as used in
+	 handle_transparent_union_attribute), but that doesn't play well
+	 with the stronger C++ type identity model.  */
+      if (TREE_CODE (ttype) == RECORD_TYPE
+	  || TREE_CODE (ttype) == UNION_TYPE
+	  || TREE_CODE (ttype) == QUAL_UNION_TYPE
+	  || TREE_CODE (ttype) == ENUMERAL_TYPE)
+	{
+	  warning (OPT_Wattributes,
+		   "ignoring attributes applied to %qT after definition",
+		   TYPE_MAIN_VARIANT (ttype));
+	  return build_qualified_type (ttype, quals);
+	}
+
+      ttype = build_qualified_type (ttype, TYPE_UNQUALIFIED);
+      ntype = build_distinct_type_copy (ttype);
+
+      TYPE_ATTRIBUTES (ntype) = attribute;
+
+      hashval_t hash = type_hash_canon_hash (ntype);
+      ntype = type_hash_canon (hash, ntype);
+
+      /* If the target-dependent attributes make NTYPE different from
+	 its canonical type, we will need to use structural equality
+	 checks for this type.  */
+      if (TYPE_STRUCTURAL_EQUALITY_P (ttype)
+	  || !comp_type_attributes (ntype, ttype))
+	SET_TYPE_STRUCTURAL_EQUALITY (ntype);
+      else if (TYPE_CANONICAL (ntype) == ntype)
+	TYPE_CANONICAL (ntype) = TYPE_CANONICAL (ttype);
+
+      ttype = build_qualified_type (ntype, quals);
+    }
+  else if (TYPE_QUALS (ttype) != quals)
+    ttype = build_qualified_type (ttype, quals);
+
+  return ttype;
+}
+
+/* Compare two identifier nodes representing attributes.
+   Return true if they are the same, false otherwise.  */
+
+static bool
+cmp_attrib_identifiers (const_tree attr1, const_tree attr2)
+{
+  /* Make sure we're dealing with IDENTIFIER_NODEs.  */
+  gcc_checking_assert (TREE_CODE (attr1) == IDENTIFIER_NODE
+		       && TREE_CODE (attr2) == IDENTIFIER_NODE);
+
+  /* Identifiers can be compared directly for equality.  */
+  if (attr1 == attr2)
+    return true;
+
+  return cmp_attribs (IDENTIFIER_POINTER (attr1), IDENTIFIER_LENGTH (attr1),
+		      IDENTIFIER_POINTER (attr2), IDENTIFIER_LENGTH (attr2));
+}
+
+/* Compare two constructor-element-type constants.  Return 1 if the lists
+   are known to be equal; otherwise return 0.  */
+
+static bool
+simple_cst_list_equal (const_tree l1, const_tree l2)
+{
+  while (l1 != NULL_TREE && l2 != NULL_TREE)
+    {
+      if (simple_cst_equal (TREE_VALUE (l1), TREE_VALUE (l2)) != 1)
+	return false;
+
+      l1 = TREE_CHAIN (l1);
+      l2 = TREE_CHAIN (l2);
+    }
+
+  return l1 == l2;
+}
+
+/* Check if "omp declare simd" attribute arguments, CLAUSES1 and CLAUSES2, are
+   the same.  */
+
+static bool
+omp_declare_simd_clauses_equal (tree clauses1, tree clauses2)
+{
+  tree cl1, cl2;
+  for (cl1 = clauses1, cl2 = clauses2;
+       cl1 && cl2;
+       cl1 = OMP_CLAUSE_CHAIN (cl1), cl2 = OMP_CLAUSE_CHAIN (cl2))
+    {
+      if (OMP_CLAUSE_CODE (cl1) != OMP_CLAUSE_CODE (cl2))
+	return false;
+      if (OMP_CLAUSE_CODE (cl1) != OMP_CLAUSE_SIMDLEN)
+	{
+	  if (simple_cst_equal (OMP_CLAUSE_DECL (cl1),
+				OMP_CLAUSE_DECL (cl2)) != 1)
+	    return false;
+	}
+      switch (OMP_CLAUSE_CODE (cl1))
+	{
+	case OMP_CLAUSE_ALIGNED:
+	  if (simple_cst_equal (OMP_CLAUSE_ALIGNED_ALIGNMENT (cl1),
+				OMP_CLAUSE_ALIGNED_ALIGNMENT (cl2)) != 1)
+	    return false;
+	  break;
+	case OMP_CLAUSE_LINEAR:
+	  if (simple_cst_equal (OMP_CLAUSE_LINEAR_STEP (cl1),
+				OMP_CLAUSE_LINEAR_STEP (cl2)) != 1)
+	    return false;
+	  break;
+	case OMP_CLAUSE_SIMDLEN:
+	  if (simple_cst_equal (OMP_CLAUSE_SIMDLEN_EXPR (cl1),
+				OMP_CLAUSE_SIMDLEN_EXPR (cl2)) != 1)
+	    return false;
+	default:
+	  break;
+	}
+    }
+  return true;
+}
+
+
+/* Compare two attributes for their value identity.  Return true if the
+   attribute values are known to be equal; otherwise return false.  */
+
+bool
+attribute_value_equal (const_tree attr1, const_tree attr2)
+{
+  if (TREE_VALUE (attr1) == TREE_VALUE (attr2))
+    return true;
+
+  if (TREE_VALUE (attr1) != NULL_TREE
+      && TREE_CODE (TREE_VALUE (attr1)) == TREE_LIST
+      && TREE_VALUE (attr2) != NULL_TREE
+      && TREE_CODE (TREE_VALUE (attr2)) == TREE_LIST)
+    {
+      /* Handle attribute format.  */
+      if (is_attribute_p ("format", get_attribute_name (attr1)))
+	{
+	  attr1 = TREE_VALUE (attr1);
+	  attr2 = TREE_VALUE (attr2);
+	  /* Compare the archetypes (printf/scanf/strftime/...).  */
+	  if (!cmp_attrib_identifiers (TREE_VALUE (attr1), TREE_VALUE (attr2)))
+	    return false;
+	  /* Archetypes are the same.  Compare the rest.  */
+	  return (simple_cst_list_equal (TREE_CHAIN (attr1),
+					 TREE_CHAIN (attr2)) == 1);
+	}
+      return (simple_cst_list_equal (TREE_VALUE (attr1),
+				     TREE_VALUE (attr2)) == 1);
+    }
+
+  if ((flag_openmp || flag_openmp_simd)
+      && TREE_VALUE (attr1) && TREE_VALUE (attr2)
+      && TREE_CODE (TREE_VALUE (attr1)) == OMP_CLAUSE
+      && TREE_CODE (TREE_VALUE (attr2)) == OMP_CLAUSE)
+    return omp_declare_simd_clauses_equal (TREE_VALUE (attr1),
+					   TREE_VALUE (attr2));
+
+  return (simple_cst_equal (TREE_VALUE (attr1), TREE_VALUE (attr2)) == 1);
+}
+
+/* Return 0 if the attributes for two types are incompatible, 1 if they
+   are compatible, and 2 if they are nearly compatible (which causes a
+   warning to be generated).  */
+int
+comp_type_attributes (const_tree type1, const_tree type2)
+{
+  const_tree a1 = TYPE_ATTRIBUTES (type1);
+  const_tree a2 = TYPE_ATTRIBUTES (type2);
+  const_tree a;
+
+  if (a1 == a2)
+    return 1;
+  for (a = a1; a != NULL_TREE; a = TREE_CHAIN (a))
+    {
+      const struct attribute_spec *as;
+      const_tree attr;
+
+      as = lookup_attribute_spec (get_attribute_name (a));
+      if (!as || as->affects_type_identity == false)
+	continue;
+
+      attr = lookup_attribute (as->name, CONST_CAST_TREE (a2));
+      if (!attr || !attribute_value_equal (a, attr))
+	break;
+    }
+  if (!a)
+    {
+      for (a = a2; a != NULL_TREE; a = TREE_CHAIN (a))
+	{
+	  const struct attribute_spec *as;
+
+	  as = lookup_attribute_spec (get_attribute_name (a));
+	  if (!as || as->affects_type_identity == false)
+	    continue;
+
+	  if (!lookup_attribute (as->name, CONST_CAST_TREE (a1)))
+	    break;
+	  /* We don't need to compare trees again, as we did this
+	     already in first loop.  */
+	}
+      /* All types - affecting identity - are equal, so
+	 there is no need to call target hook for comparison.  */
+      if (!a)
+	return 1;
+    }
+  if (lookup_attribute ("transaction_safe", CONST_CAST_TREE (a)))
+    return 0;
+  /* As some type combinations - like default calling-convention - might
+     be compatible, we have to call the target hook to get the final result.  */
+  return targetm.comp_type_attributes (type1, type2);
+}
+
+/* Return a type like TTYPE except that its TYPE_ATTRIBUTE
+   is ATTRIBUTE.
+
+   Record such modified types already made so we don't make duplicates.  */
+
+tree
+build_type_attribute_variant (tree ttype, tree attribute)
+{
+  return build_type_attribute_qual_variant (ttype, attribute,
+					    TYPE_QUALS (ttype));
+}
+\f
+/* A variant of lookup_attribute() that can be used with an identifier
+   as the first argument, and where the identifier can be either
+   'text' or '__text__'.
+
+   Given an attribute ATTR_IDENTIFIER, and a list of attributes LIST,
+   return a pointer to the attribute's list element if the attribute
+   is part of the list, or NULL_TREE if not found.  If the attribute
+   appears more than once, this only returns the first occurrence; the
+   TREE_CHAIN of the return value should be passed back in if further
+   occurrences are wanted.  ATTR_IDENTIFIER must be an identifier but
+   can be in the form 'text' or '__text__'.  */
+static tree
+lookup_ident_attribute (tree attr_identifier, tree list)
+{
+  gcc_checking_assert (TREE_CODE (attr_identifier) == IDENTIFIER_NODE);
+
+  while (list)
+    {
+      gcc_checking_assert (TREE_CODE (get_attribute_name (list))
+			   == IDENTIFIER_NODE);
+
+      if (cmp_attrib_identifiers (attr_identifier,
+				  get_attribute_name (list)))
+	/* Found it.  */
+	break;
+      list = TREE_CHAIN (list);
+    }
+
+  return list;
+}
+
+/* Remove any instances of attribute ATTR_NAME in LIST and return the
+   modified list.  */
+
+tree
+remove_attribute (const char *attr_name, tree list)
+{
+  tree *p;
+  gcc_checking_assert (attr_name[0] != '_');
+
+  for (p = &list; *p;)
+    {
+      tree l = *p;
+
+      tree attr = get_attribute_name (l);
+      if (is_attribute_p (attr_name, attr))
+	*p = TREE_CHAIN (l);
+      else
+	p = &TREE_CHAIN (l);
+    }
+
+  return list;
+}
+
+/* Return an attribute list that is the union of a1 and a2.  */
+
+tree
+merge_attributes (tree a1, tree a2)
+{
+  tree attributes;
+
+  /* Either one unset?  Take the set one.  */
+
+  if ((attributes = a1) == 0)
+    attributes = a2;
+
+  /* One that completely contains the other?  Take it.  */
+
+  else if (a2 != 0 && ! attribute_list_contained (a1, a2))
+    {
+      if (attribute_list_contained (a2, a1))
+	attributes = a2;
+      else
+	{
+	  /* Pick the longest list, and hang on the other list.  */
+
+	  if (list_length (a1) < list_length (a2))
+	    attributes = a2, a2 = a1;
+
+	  for (; a2 != 0; a2 = TREE_CHAIN (a2))
+	    {
+	      tree a;
+	      for (a = lookup_ident_attribute (get_attribute_name (a2),
+					       attributes);
+		   a != NULL_TREE && !attribute_value_equal (a, a2);
+		   a = lookup_ident_attribute (get_attribute_name (a2),
+					       TREE_CHAIN (a)))
+		;
+	      if (a == NULL_TREE)
+		{
+		  a1 = copy_node (a2);
+		  TREE_CHAIN (a1) = attributes;
+		  attributes = a1;
+		}
+	    }
+	}
+    }
+  return attributes;
+}
+
+/* Given types T1 and T2, merge their attributes and return
+  the result.  */
+
+tree
+merge_type_attributes (tree t1, tree t2)
+{
+  return merge_attributes (TYPE_ATTRIBUTES (t1),
+			   TYPE_ATTRIBUTES (t2));
+}
+
+/* Given decls OLDDECL and NEWDECL, merge their attributes and return
+   the result.  */
+
+tree
+merge_decl_attributes (tree olddecl, tree newdecl)
+{
+  return merge_attributes (DECL_ATTRIBUTES (olddecl),
+			   DECL_ATTRIBUTES (newdecl));
+}
+
+#if TARGET_DLLIMPORT_DECL_ATTRIBUTES
+
+/* Specialization of merge_decl_attributes for various Windows targets.
+
+   This handles the following situation:
+
+     __declspec (dllimport) int foo;
+     int foo;
+
+   The second instance of `foo' nullifies the dllimport.  */
+
+tree
+merge_dllimport_decl_attributes (tree old, tree new_tree)
+{
+  tree a;
+  int delete_dllimport_p = 1;
+
+  /* What we need to do here is remove from `old' dllimport if it doesn't
+     appear in `new'.  dllimport behaves like extern: if a declaration is
+     marked dllimport and a definition appears later, then the object
+     is not dllimport'd.  We also remove a `new' dllimport if the old list
+     contains dllexport:  dllexport always overrides dllimport, regardless
+     of the order of declaration.  */
+  if (!VAR_OR_FUNCTION_DECL_P (new_tree))
+    delete_dllimport_p = 0;
+  else if (DECL_DLLIMPORT_P (new_tree)
+     	   && lookup_attribute ("dllexport", DECL_ATTRIBUTES (old)))
+    {
+      DECL_DLLIMPORT_P (new_tree) = 0;
+      warning (OPT_Wattributes, "%q+D already declared with dllexport "
+	       "attribute: dllimport ignored", new_tree);
+    }
+  else if (DECL_DLLIMPORT_P (old) && !DECL_DLLIMPORT_P (new_tree))
+    {
+      /* Warn about overriding a symbol that has already been used, e.g.:
+	   extern int __attribute__ ((dllimport)) foo;
+	   int* bar () {return &foo;}
+	   int foo;
+      */
+      if (TREE_USED (old))
+	{
+	  warning (0, "%q+D redeclared without dllimport attribute "
+		   "after being referenced with dll linkage", new_tree);
+	  /* If we have used a variable's address with dllimport linkage,
+	      keep the old DECL_DLLIMPORT_P flag: the ADDR_EXPR using the
+	      decl may already have had TREE_CONSTANT computed.
+	      We still remove the attribute so that assembler code refers
+	      to '&foo rather than '_imp__foo'.  */
+	  if (VAR_P (old) && TREE_ADDRESSABLE (old))
+	    DECL_DLLIMPORT_P (new_tree) = 1;
+	}
+
+      /* Let an inline definition silently override the external reference,
+	 but otherwise warn about attribute inconsistency.  */
+      else if (VAR_P (new_tree) || !DECL_DECLARED_INLINE_P (new_tree))
+	warning (OPT_Wattributes, "%q+D redeclared without dllimport "
+		 "attribute: previous dllimport ignored", new_tree);
+    }
+  else
+    delete_dllimport_p = 0;
+
+  a = merge_attributes (DECL_ATTRIBUTES (old), DECL_ATTRIBUTES (new_tree));
+
+  if (delete_dllimport_p)
+    a = remove_attribute ("dllimport", a);
+
+  return a;
+}
+
+/* Handle a "dllimport" or "dllexport" attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+tree
+handle_dll_attribute (tree * pnode, tree name, tree args, int flags,
+		      bool *no_add_attrs)
+{
+  tree node = *pnode;
+  bool is_dllimport;
+
+  /* These attributes may apply to structure and union types being created,
+     but otherwise should pass to the declaration involved.  */
+  if (!DECL_P (node))
+    {
+      if (flags & ((int) ATTR_FLAG_DECL_NEXT | (int) ATTR_FLAG_FUNCTION_NEXT
+		   | (int) ATTR_FLAG_ARRAY_NEXT))
+	{
+	  *no_add_attrs = true;
+	  return tree_cons (name, args, NULL_TREE);
+	}
+      if (TREE_CODE (node) == RECORD_TYPE
+	  || TREE_CODE (node) == UNION_TYPE)
+	{
+	  node = TYPE_NAME (node);
+	  if (!node)
+	    return NULL_TREE;
+	}
+      else
+	{
+	  warning (OPT_Wattributes, "%qE attribute ignored",
+		   name);
+	  *no_add_attrs = true;
+	  return NULL_TREE;
+	}
+    }
+
+  if (!VAR_OR_FUNCTION_DECL_P (node) && TREE_CODE (node) != TYPE_DECL)
+    {
+      *no_add_attrs = true;
+      warning (OPT_Wattributes, "%qE attribute ignored",
+	       name);
+      return NULL_TREE;
+    }
+
+  if (TREE_CODE (node) == TYPE_DECL
+      && TREE_CODE (TREE_TYPE (node)) != RECORD_TYPE
+      && TREE_CODE (TREE_TYPE (node)) != UNION_TYPE)
+    {
+      *no_add_attrs = true;
+      warning (OPT_Wattributes, "%qE attribute ignored",
+	       name);
+      return NULL_TREE;
+    }
+
+  is_dllimport = is_attribute_p ("dllimport", name);
+
+  /* Report error on dllimport ambiguities seen now before they cause
+     any damage.  */
+  if (is_dllimport)
+    {
+      /* Honor any target-specific overrides.  */
+      if (!targetm.valid_dllimport_attribute_p (node))
+	*no_add_attrs = true;
+
+     else if (TREE_CODE (node) == FUNCTION_DECL
+	      && DECL_DECLARED_INLINE_P (node))
+	{
+	  warning (OPT_Wattributes, "inline function %q+D declared as "
+		  " dllimport: attribute ignored", node);
+	  *no_add_attrs = true;
+	}
+      /* Like MS, treat definition of dllimported variables and
+	 non-inlined functions on declaration as syntax errors.  */
+     else if (TREE_CODE (node) == FUNCTION_DECL && DECL_INITIAL (node))
+	{
+	  error ("function %q+D definition is marked dllimport", node);
+	  *no_add_attrs = true;
+	}
+
+     else if (VAR_P (node))
+	{
+	  if (DECL_INITIAL (node))
+	    {
+	      error ("variable %q+D definition is marked dllimport",
+		     node);
+	      *no_add_attrs = true;
+	    }
+
+	  /* `extern' needn't be specified with dllimport.
+	     Specify `extern' now and hope for the best.  Sigh.  */
+	  DECL_EXTERNAL (node) = 1;
+	  /* Also, implicitly give dllimport'd variables declared within
+	     a function global scope, unless declared static.  */
+	  if (current_function_decl != NULL_TREE && !TREE_STATIC (node))
+	    TREE_PUBLIC (node) = 1;
+	}
+
+      if (*no_add_attrs == false)
+	DECL_DLLIMPORT_P (node) = 1;
+    }
+  else if (TREE_CODE (node) == FUNCTION_DECL
+	   && DECL_DECLARED_INLINE_P (node)
+	   && flag_keep_inline_dllexport)
+    /* An exported function, even if inline, must be emitted.  */
+    DECL_EXTERNAL (node) = 0;
+
+  /*  Report error if symbol is not accessible at global scope.  */
+  if (!TREE_PUBLIC (node) && VAR_OR_FUNCTION_DECL_P (node))
+    {
+      error ("external linkage required for symbol %q+D because of "
+	     "%qE attribute", node, name);
+      *no_add_attrs = true;
+    }
+
+  /* A dllexport'd entity must have default visibility so that other
+     program units (shared libraries or the main executable) can see
+     it.  A dllimport'd entity must have default visibility so that
+     the linker knows that undefined references within this program
+     unit can be resolved by the dynamic linker.  */
+  if (!*no_add_attrs)
+    {
+      if (DECL_VISIBILITY_SPECIFIED (node)
+	  && DECL_VISIBILITY (node) != VISIBILITY_DEFAULT)
+	error ("%qE implies default visibility, but %qD has already "
+	       "been declared with a different visibility",
+	       name, node);
+      DECL_VISIBILITY (node) = VISIBILITY_DEFAULT;
+      DECL_VISIBILITY_SPECIFIED (node) = 1;
+    }
+
+  return NULL_TREE;
+}
+
+#endif /* TARGET_DLLIMPORT_DECL_ATTRIBUTES  */
+
+/* Given two lists of attributes, return true if list l2 is
+   equivalent to l1.  */
+
+int
+attribute_list_equal (const_tree l1, const_tree l2)
+{
+  if (l1 == l2)
+    return 1;
+
+  return attribute_list_contained (l1, l2)
+	 && attribute_list_contained (l2, l1);
+}
+
+/* Given two lists of attributes, return true if list L2 is
+   completely contained within L1.  */
+/* ??? This would be faster if attribute names were stored in a canonicalized
+   form.  Otherwise, if L1 uses `foo' and L2 uses `__foo__', the long method
+   must be used to show these elements are equivalent (which they are).  */
+/* ??? It's not clear that attributes with arguments will always be handled
+   correctly.  */
+
+int
+attribute_list_contained (const_tree l1, const_tree l2)
+{
+  const_tree t1, t2;
+
+  /* First check the obvious, maybe the lists are identical.  */
+  if (l1 == l2)
+    return 1;
+
+  /* Maybe the lists are similar.  */
+  for (t1 = l1, t2 = l2;
+       t1 != 0 && t2 != 0
+       && get_attribute_name (t1) == get_attribute_name (t2)
+       && TREE_VALUE (t1) == TREE_VALUE (t2);
+       t1 = TREE_CHAIN (t1), t2 = TREE_CHAIN (t2))
+    ;
+
+  /* Maybe the lists are equal.  */
+  if (t1 == 0 && t2 == 0)
+    return 1;
+
+  for (; t2 != 0; t2 = TREE_CHAIN (t2))
+    {
+      const_tree attr;
+      /* This CONST_CAST is okay because lookup_attribute does not
+	 modify its argument and the return value is assigned to a
+	 const_tree.  */
+      for (attr = lookup_ident_attribute (get_attribute_name (t2),
+					  CONST_CAST_TREE (l1));
+	   attr != NULL_TREE && !attribute_value_equal (t2, attr);
+	   attr = lookup_ident_attribute (get_attribute_name (t2),
+					  TREE_CHAIN (attr)))
+	;
+
+      if (attr == NULL_TREE)
+	return 0;
+    }
+
+  return 1;
+}
diff --git a/gcc/attribs.h b/gcc/attribs.h
index d4a790bb753..06e6993e958 100644
--- a/gcc/attribs.h
+++ b/gcc/attribs.h
@@ -47,6 +47,46 @@ extern char *make_unique_name (tree, const char *, bool);
 extern tree make_dispatcher_decl (const tree);
 extern bool is_function_default_version (const tree);
 
+/* Return a type like TTYPE except that its TYPE_ATTRIBUTES
+   is ATTRIBUTE.
+
+   Such modified types already made are recorded so that duplicates
+   are not made.  */
+
+extern tree build_type_attribute_variant (tree, tree);
+extern tree build_decl_attribute_variant (tree, tree);
+extern tree build_type_attribute_qual_variant (tree, tree, int);
+
+extern bool attribute_value_equal (const_tree, const_tree);
+
+/* Return 0 if the attributes for two types are incompatible, 1 if they
+   are compatible, and 2 if they are nearly compatible (which causes a
+   warning to be generated).  */
+extern int comp_type_attributes (const_tree, const_tree);
+
+/* Default versions of target-overridable functions.  */
+extern tree merge_decl_attributes (tree, tree);
+extern tree merge_type_attributes (tree, tree);
+
+/* Remove any instances of attribute ATTR_NAME in LIST and return the
+   modified list.  */
+
+extern tree remove_attribute (const char *, tree);
+
+/* Given two attributes lists, return a list of their union.  */
+
+extern tree merge_attributes (tree, tree);
+
+/* Given two Windows decl attributes lists, possibly including
+   dllimport, return a list of their union .  */
+extern tree merge_dllimport_decl_attributes (tree, tree);
+
+/* Handle a "dllimport" or "dllexport" attribute.  */
+extern tree handle_dll_attribute (tree *, tree, tree, int, bool *);
+
+extern int attribute_list_equal (const_tree, const_tree);
+extern int attribute_list_contained (const_tree, const_tree);
+
 /* For a given IDENTIFIER_NODE, strip leading and trailing '_' characters
    so that we have a canonical form of attribute names.  */
 
@@ -90,4 +130,77 @@ is_attribute_p (const char *attr_name, const_tree ident)
 		      IDENTIFIER_POINTER (ident), IDENTIFIER_LENGTH (ident));
 }
 
+/* Given an attribute name ATTR_NAME and a list of attributes LIST,
+   return a pointer to the attribute's list element if the attribute
+   is part of the list, or NULL_TREE if not found.  If the attribute
+   appears more than once, this only returns the first occurrence; the
+   TREE_CHAIN of the return value should be passed back in if further
+   occurrences are wanted.  ATTR_NAME must be in the form 'text' (not
+   '__text__').  */
+
+static inline tree
+lookup_attribute (const char *attr_name, tree list)
+{
+  gcc_checking_assert (attr_name[0] != '_');
+  /* In most cases, list is NULL_TREE.  */
+  if (list == NULL_TREE)
+    return NULL_TREE;
+  else
+    {
+      size_t attr_len = strlen (attr_name);
+      /* Do the strlen() before calling the out-of-line implementation.
+	 In most cases attr_name is a string constant, and the compiler
+	 will optimize the strlen() away.  */
+      while (list)
+	{
+	  tree attr = get_attribute_name (list);
+	  size_t ident_len = IDENTIFIER_LENGTH (attr);
+	  if (cmp_attribs (attr_name, attr_len, IDENTIFIER_POINTER (attr),
+			   ident_len))
+	    break;
+	  list = TREE_CHAIN (list);
+	}
+
+      return list;
+    }
+}
+
+/* Given an attribute name ATTR_NAME and a list of attributes LIST,
+   return a pointer to the attribute's list first element if the attribute
+   starts with ATTR_NAME.  ATTR_NAME must be in the form 'text' (not
+   '__text__').  */
+
+static inline tree
+lookup_attribute_by_prefix (const char *attr_name, tree list)
+{
+  gcc_checking_assert (attr_name[0] != '_');
+  /* In most cases, list is NULL_TREE.  */
+  if (list == NULL_TREE)
+    return NULL_TREE;
+  else
+    {
+      size_t attr_len = strlen (attr_name);
+      while (list)
+	{
+	  size_t ident_len = IDENTIFIER_LENGTH (get_attribute_name (list));
+
+	  if (attr_len > ident_len)
+	    {
+	      list = TREE_CHAIN (list);
+	      continue;
+	    }
+
+	  const char *p = IDENTIFIER_POINTER (get_attribute_name (list));
+	  gcc_checking_assert (attr_len == 0 || p[0] != '_');
+
+	  if (strncmp (attr_name, p, attr_len) == 0)
+	    break;
+
+	  list = TREE_CHAIN (list);
+	}
+
+      return list;
+    }
+}
+
 #endif // GCC_ATTRIBS_H
diff --git a/gcc/bb-reorder.c b/gcc/bb-reorder.c
index dc50546ab63..df9d4d3e0f3 100644
--- a/gcc/bb-reorder.c
+++ b/gcc/bb-reorder.c
@@ -115,6 +115,8 @@
 #include "bb-reorder.h"
 #include "except.h"
 #include "fibonacci_heap.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* The number of rounds.  In most cases there will only be 4 rounds, but
    when partitioning hot and cold basic blocks into separate sections of
diff --git a/gcc/builtins.c b/gcc/builtins.c
index 016f68d2cb6..fa0f89c8f33 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -60,6 +60,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "langhooks.h"
 #include "value-prof.h"
 #include "builtins.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 #include "cilk.h"
 #include "tree-chkp.h"
diff --git a/gcc/c-family/c-ada-spec.c b/gcc/c-family/c-ada-spec.c
index 761e518d965..7b86f3c309c 100644
--- a/gcc/c-family/c-ada-spec.c
+++ b/gcc/c-family/c-ada-spec.c
@@ -28,6 +28,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "fold-const.h"
 #include "c-pragma.h"
 #include "cpp-id-data.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* Local functions, macros and variables.  */
 static int dump_generic_ada_node (pretty_printer *, tree, tree, int, int,
diff --git a/gcc/c-family/c-ubsan.c b/gcc/c-family/c-ubsan.c
index 541b53009c2..b1386db9c25 100644
--- a/gcc/c-family/c-ubsan.c
+++ b/gcc/c-family/c-ubsan.c
@@ -25,10 +25,12 @@ along with GCC; see the file COPYING3.  If not see
 #include "c-family/c-common.h"
 #include "ubsan.h"
 #include "c-family/c-ubsan.h"
-#include "asan.h"
 #include "stor-layout.h"
 #include "builtins.h"
 #include "gimplify.h"
+#include "stringpool.h"
+#include "attribs.h"
+#include "asan.h"
 
 /* Instrument division by zero and INT_MIN / -1.  If not instrumenting,
    return NULL_TREE.  */
diff --git a/gcc/c-family/c-warn.c b/gcc/c-family/c-warn.c
index 505070e5586..1bda6231fef 100644
--- a/gcc/c-family/c-warn.c
+++ b/gcc/c-family/c-warn.c
@@ -28,6 +28,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "tm_p.h"
 #include "diagnostic.h"
 #include "intl.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 #include "gcc-rich-location.h"
 #include "gimplify.h"
diff --git a/gcc/c/c-convert.c b/gcc/c/c-convert.c
index bc649178f4c..8752132d175 100644
--- a/gcc/c/c-convert.c
+++ b/gcc/c/c-convert.c
@@ -31,6 +31,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "convert.h"
 #include "langhooks.h"
 #include "ubsan.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 
 /* Change of width--truncation and extension of integers or reals--
diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
index 71d01350186..321c953e7f1 100644
--- a/gcc/c/c-typeck.c
+++ b/gcc/c/c-typeck.c
@@ -50,6 +50,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "gomp-constants.h"
 #include "spellcheck-tree.h"
 #include "gcc-rich-location.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 
 /* Possible cases of implicit bad conversions.  Used to select
diff --git a/gcc/calls.c b/gcc/calls.c
index 8a23b50fc66..83a1274a4f5 100644
--- a/gcc/calls.c
+++ b/gcc/calls.c
@@ -52,6 +52,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-ssanames.h"
 #include "rtl-chkp.h"
 #include "intl.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* Like PREFERRED_STACK_BOUNDARY but in units of bytes, not bits.  */
 #define STACK_BYTES (PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT)
diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c
index c9d8118ed45..7f0130d0365 100644
--- a/gcc/cfgexpand.c
+++ b/gcc/cfgexpand.c
@@ -68,6 +68,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-outof-ssa.h"
 #include "cfgloop.h"
 #include "insn-attr.h" /* For INSN_SCHEDULING.  */
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 #include "tree-ssa-address.h"
 #include "output.h"
diff --git a/gcc/cgraph.c b/gcc/cgraph.c
index d7c9ba61795..c6ab7e38ff6 100644
--- a/gcc/cgraph.c
+++ b/gcc/cgraph.c
@@ -61,6 +61,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-chkp.h"
 #include "context.h"
 #include "gimplify.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* FIXME: Only for PROP_loops, but cgraph shouldn't have to know about this.  */
 #include "tree-pass.h"
diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c
index 6072c567bc3..e8cc765095d 100644
--- a/gcc/cgraphunit.c
+++ b/gcc/cgraphunit.c
@@ -204,6 +204,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "dbgcnt.h"
 #include "tree-chkp.h"
 #include "lto-section-names.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* Queue of cgraph nodes scheduled to be added into cgraph.  This is a
    secondary queue used during optimization to accommodate passes that
diff --git a/gcc/convert.c b/gcc/convert.c
index 58d8054a724..b1a53afb811 100644
--- a/gcc/convert.c
+++ b/gcc/convert.c
@@ -33,6 +33,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "langhooks.h"
 #include "builtins.h"
 #include "ubsan.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 
 #define maybe_fold_build1_loc(FOLD_P, LOC, CODE, TYPE, EXPR) \
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index e74d48daa8b..a55a2e468aa 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -39,6 +39,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "langhooks.h"
 #include "c-family/c-objc.h"
 #include "internal-fn.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* The various kinds of conversion.  */
 
diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c
index a9563b1a8cd..528e38816d3 100644
--- a/gcc/cp/cp-gimplify.c
+++ b/gcc/cp/cp-gimplify.c
@@ -33,6 +33,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "c-family/c-ubsan.h"
 #include "cilk.h"
 #include "cp-cilkplus.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 
 /* Forward declarations.  */
diff --git a/gcc/cp/cp-ubsan.c b/gcc/cp/cp-ubsan.c
index 3be607c0a42..cd2b60ad488 100644
--- a/gcc/cp/cp-ubsan.c
+++ b/gcc/cp/cp-ubsan.c
@@ -23,6 +23,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "coretypes.h"
 #include "cp-tree.h"
 #include "ubsan.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 
 /* Test if we should instrument vptr access.  */
diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c
index 631ff49673f..fd758d3c2dc 100644
--- a/gcc/cp/cvt.c
+++ b/gcc/cp/cvt.c
@@ -33,6 +33,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "flags.h"
 #include "intl.h"
 #include "convert.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 static tree convert_to_pointer_force (tree, tree, tsubst_flags_t);
 static tree build_type_conversion (tree, tree);
diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index 3fe8f18b2a9..81804112fd0 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -30,6 +30,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "gimplify.h"
 #include "c-family/c-ubsan.h"
 #include "intl.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 
 static bool begin_init_stmts (tree *, tree *);
diff --git a/gcc/cp/search.c b/gcc/cp/search.c
index 469a88b4c6f..ced82da6117 100644
--- a/gcc/cp/search.c
+++ b/gcc/cp/search.c
@@ -28,6 +28,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "intl.h"
 #include "toplev.h"
 #include "spellcheck-tree.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 static int is_subobject_of_p (tree, tree);
 static tree dfs_lookup_base (tree, void *);
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index f56d00fd8f3..5401e78fbc6 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -40,6 +40,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-iterator.h"
 #include "omp-general.h"
 #include "convert.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "gomp-constants.h"
 #include "predict.h"
 
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 3dc64045e1a..bd49b7f572d 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -37,6 +37,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "c-family/c-ubsan.h"
 #include "params.h"
 #include "gcc-rich-location.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 
 static tree cp_build_addr_expr_strict (tree, tsubst_flags_t);
diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index 4a3b3c1d0f4..8e422279a61 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -92,6 +92,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-dfa.h"
 #include "gdb/gdb-index.h"
 #include "rtl-iter.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 static void dwarf2out_source_line (unsigned int, unsigned int, const char *,
 				   int, bool);
diff --git a/gcc/final.c b/gcc/final.c
index 2a24f4fe102..ad999f77fdd 100644
--- a/gcc/final.c
+++ b/gcc/final.c
@@ -76,6 +76,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-ssa.h"
 #include "cfgloop.h"
 #include "params.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 #include "rtl-iter.h"
 #include "print-rtl.h"
diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index eeeff1ed166..16cbba74b13 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -79,6 +79,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-vrp.h"
 #include "tree-ssanames.h"
 #include "selftest.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* Nonzero if we are folding constants inside an initializer; zero
    otherwise.  */
diff --git a/gcc/fortran/trans-types.c b/gcc/fortran/trans-types.c
index 8617cd51a7c..76ee97b81c0 100644
--- a/gcc/fortran/trans-types.c
+++ b/gcc/fortran/trans-types.c
@@ -36,6 +36,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "trans-types.h"
 #include "trans-const.h"
 #include "dwarf2out.h"	/* For struct array_descr_info.  */
+#include "attribs.h"
 \f
 
 #if (GFC_MAX_DIMENSIONS < 10)
diff --git a/gcc/function.c b/gcc/function.c
index 62e72eb2a9f..e02774a1216 100644
--- a/gcc/function.c
+++ b/gcc/function.c
@@ -77,6 +77,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "rtl-chkp.h"
 #include "tree-dfa.h"
 #include "tree-ssa.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* So we can assign to cfun in this file.  */
 #undef cfun
diff --git a/gcc/gimple-expr.c b/gcc/gimple-expr.c
index 13e55ef55fe..c1771fcf1d0 100644
--- a/gcc/gimple-expr.c
+++ b/gcc/gimple-expr.c
@@ -35,6 +35,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "hash-set.h"
 #include "rtl.h"
 #include "tree-pass.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* ----- Type related -----  */
 
diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c
index d82d0606cbe..251446c5b82 100644
--- a/gcc/gimple-fold.c
+++ b/gcc/gimple-fold.c
@@ -56,6 +56,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "ipa-chkp.h"
 #include "tree-cfg.h"
 #include "fold-const-call.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 
 /* Return true when DECL can be referenced from current unit.
diff --git a/gcc/gimple-pretty-print.c b/gcc/gimple-pretty-print.c
index 8b69b72e9e2..5727d14777a 100644
--- a/gcc/gimple-pretty-print.c
+++ b/gcc/gimple-pretty-print.c
@@ -38,6 +38,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "value-prof.h"
 #include "trans-mem.h"
 #include "cfganal.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 
 #define INDENT(SPACE)							\
diff --git a/gcc/gimple.c b/gcc/gimple.c
index 3a32b530cce..c4e6f8176b9 100644
--- a/gcc/gimple.c
+++ b/gcc/gimple.c
@@ -41,6 +41,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "builtins.h"
 #include "selftest.h"
 #include "gimple-pretty-print.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 
 
diff --git a/gcc/gimplify.c b/gcc/gimplify.c
index 76a08c67061..7ae446a979c 100644
--- a/gcc/gimplify.c
+++ b/gcc/gimplify.c
@@ -60,6 +60,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "gimple-walk.h"
 #include "langhooks-def.h"	/* FIXME: for lhd_set_decl_assembler_name */
 #include "builtins.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 #include "dbgcnt.h"
 
diff --git a/gcc/hsa-common.c b/gcc/hsa-common.c
index 95636ebc9a8..c8c12afb04c 100644
--- a/gcc/hsa-common.c
+++ b/gcc/hsa-common.c
@@ -40,6 +40,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "internal-fn.h"
 #include "ctype.h"
 #include "builtins.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* Structure containing intermediate HSA representation of the generated
    function.  */
diff --git a/gcc/hsa-gen.c b/gcc/hsa-gen.c
index 6ec8c348eb4..bd227626e83 100644
--- a/gcc/hsa-gen.c
+++ b/gcc/hsa-gen.c
@@ -60,6 +60,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "internal-fn.h"
 #include "builtins.h"
 #include "stor-layout.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* Print a warning message and set that we have seen an error.  */
 
diff --git a/gcc/internal-fn.c b/gcc/internal-fn.c
index e24ed169515..2b72367a1d3 100644
--- a/gcc/internal-fn.c
+++ b/gcc/internal-fn.c
@@ -39,6 +39,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "stor-layout.h"
 #include "dojump.h"
 #include "expr.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 #include "ubsan.h"
 #include "recog.h"
diff --git a/gcc/ipa-chkp.c b/gcc/ipa-chkp.c
index 753673c8f66..704ef6e4550 100644
--- a/gcc/ipa-chkp.c
+++ b/gcc/ipa-chkp.c
@@ -34,6 +34,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-chkp.h"
 #include "tree-inline.h"
 #include "ipa-chkp.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /*  Pointer Bounds Checker has two IPA passes to support code instrumentation.
 
diff --git a/gcc/ipa-cp.c b/gcc/ipa-cp.c
index 3b9eab41672..6b3d8d7364c 100644
--- a/gcc/ipa-cp.c
+++ b/gcc/ipa-cp.c
@@ -122,6 +122,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "ipa-fnsummary.h"
 #include "ipa-utils.h"
 #include "tree-ssa-ccp.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 template <typename valtype> class ipcp_value;
 
diff --git a/gcc/ipa-devirt.c b/gcc/ipa-devirt.c
index 9781acd0766..f0aecfbc455 100644
--- a/gcc/ipa-devirt.c
+++ b/gcc/ipa-devirt.c
@@ -129,6 +129,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "dbgcnt.h"
 #include "gimple-pretty-print.h"
 #include "intl.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* Hash based set of pairs of types.  */
 struct type_pair
diff --git a/gcc/ipa-fnsummary.c b/gcc/ipa-fnsummary.c
index 27e8d73f9df..076ccd40bd7 100644
--- a/gcc/ipa-fnsummary.c
+++ b/gcc/ipa-fnsummary.c
@@ -82,6 +82,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "cilk.h"
 #include "cfgexpand.h"
 #include "gimplify.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* Summaries.  */
 function_summary <ipa_fn_summary *> *ipa_fn_summaries;
diff --git a/gcc/ipa-inline.c b/gcc/ipa-inline.c
index 608db8f8857..dd46cb61362 100644
--- a/gcc/ipa-inline.c
+++ b/gcc/ipa-inline.c
@@ -117,6 +117,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "auto-profile.h"
 #include "builtins.h"
 #include "fibonacci_heap.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 
 typedef fibonacci_heap <sreal, cgraph_edge> edge_heap_t;
diff --git a/gcc/ipa-visibility.c b/gcc/ipa-visibility.c
index 3033f20e3f1..998024893a5 100644
--- a/gcc/ipa-visibility.c
+++ b/gcc/ipa-visibility.c
@@ -84,6 +84,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "calls.h"
 #include "varasm.h"
 #include "ipa-utils.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* Return true when NODE can not be local. Worker for cgraph_local_node_p.  */
 
diff --git a/gcc/ipa.c b/gcc/ipa.c
index 00cd3084f66..16df4cacedd 100644
--- a/gcc/ipa.c
+++ b/gcc/ipa.c
@@ -37,7 +37,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "ipa-fnsummary.h"
 #include "dbgcnt.h"
 #include "debug.h"
-
+#include "stringpool.h"
+#include "attribs.h"
 
 /* Return true when NODE has ADDR reference.  */
 
diff --git a/gcc/lto-cgraph.c b/gcc/lto-cgraph.c
index e2680277bb5..15f0eaadf20 100644
--- a/gcc/lto-cgraph.c
+++ b/gcc/lto-cgraph.c
@@ -38,6 +38,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "ipa-utils.h"
 #include "omp-offload.h"
 #include "ipa-chkp.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* True when asm nodes has been output.  */
 bool asm_nodes_output = false;
diff --git a/gcc/lto/lto-lang.c b/gcc/lto/lto-lang.c
index 6e9a138fa3b..375cdd1a90b 100644
--- a/gcc/lto/lto-lang.c
+++ b/gcc/lto/lto-lang.c
@@ -35,6 +35,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "lto-tree.h"
 #include "lto.h"
 #include "cilk.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 static tree handle_noreturn_attribute (tree *, tree, tree, int, bool *);
 static tree handle_leaf_attribute (tree *, tree, tree, int, bool *);
diff --git a/gcc/lto/lto-symtab.c b/gcc/lto/lto-symtab.c
index 019677eaf95..70190d0fda2 100644
--- a/gcc/lto/lto-symtab.c
+++ b/gcc/lto/lto-symtab.c
@@ -32,6 +32,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "builtins.h"
 #include "alias.h"
 #include "lto-symtab.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* Replace the cgraph node NODE with PREVAILING_NODE in the cgraph, merging
    all edges and removing the old node.  */
diff --git a/gcc/objc/objc-gnu-runtime-abi-01.c b/gcc/objc/objc-gnu-runtime-abi-01.c
index d1686e659bd..b53d1820db3 100644
--- a/gcc/objc/objc-gnu-runtime-abi-01.c
+++ b/gcc/objc/objc-gnu-runtime-abi-01.c
@@ -22,7 +22,9 @@ along with GCC; see the file COPYING3.  If not see
 #include "system.h"
 #include "coretypes.h"
 #include "options.h"
+#include "tree.h"
 #include "stringpool.h"
+#include "attribs.h"
 
 #ifdef OBJCPLUS
 #include "cp/cp-tree.h"
diff --git a/gcc/objc/objc-next-runtime-abi-01.c b/gcc/objc/objc-next-runtime-abi-01.c
index 7aff7883f21..686d9285482 100644
--- a/gcc/objc/objc-next-runtime-abi-01.c
+++ b/gcc/objc/objc-next-runtime-abi-01.c
@@ -26,7 +26,9 @@ along with GCC; see the file COPYING3.  If not see
 #include "config.h"
 #include "system.h"
 #include "coretypes.h"
+#include "tree.h"
 #include "stringpool.h"
+#include "attribs.h"
 
 #ifdef OBJCPLUS
 #include "cp/cp-tree.h"
diff --git a/gcc/objc/objc-next-runtime-abi-02.c b/gcc/objc/objc-next-runtime-abi-02.c
index 97314860e01..a2245a4c339 100644
--- a/gcc/objc/objc-next-runtime-abi-02.c
+++ b/gcc/objc/objc-next-runtime-abi-02.c
@@ -28,7 +28,9 @@ along with GCC; see the file COPYING3.  If not see
 #include "config.h"
 #include "system.h"
 #include "coretypes.h"
+#include "tree.h"
 #include "stringpool.h"
+#include "attribs.h"
 
 #ifdef OBJCPLUS
 #include "cp/cp-tree.h"
diff --git a/gcc/omp-expand.c b/gcc/omp-expand.c
index 970e04f71f8..775d8bf2faf 100644
--- a/gcc/omp-expand.c
+++ b/gcc/omp-expand.c
@@ -58,7 +58,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "gimple-pretty-print.h"
 #include "hsa-common.h"
 #include "debug.h"
-
+#include "stringpool.h"
+#include "attribs.h"
 
 /* OMP region information.  Every parallel and workshare
    directive is enclosed between two markers, the OMP_* directive
diff --git a/gcc/omp-general.c b/gcc/omp-general.c
index ed94668559b..af955bce783 100644
--- a/gcc/omp-general.c
+++ b/gcc/omp-general.c
@@ -33,7 +33,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "fold-const.h"
 #include "langhooks.h"
 #include "omp-general.h"
-
+#include "stringpool.h"
+#include "attribs.h"
 
 tree
 omp_find_clause (tree clauses, enum omp_clause_code kind)
diff --git a/gcc/omp-low.c b/gcc/omp-low.c
index bf3fc53b07a..38f2ebe523a 100644
--- a/gcc/omp-low.c
+++ b/gcc/omp-low.c
@@ -58,6 +58,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "gomp-constants.h"
 #include "gimple-pretty-print.h"
 #include "hsa-common.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* Lowering of OMP parallel and workshare constructs proceeds in two
    phases.  The first phase scans the function looking for OMP statements
diff --git a/gcc/omp-offload.c b/gcc/omp-offload.c
index 54a4e90f70c..2d4fd411680 100644
--- a/gcc/omp-offload.c
+++ b/gcc/omp-offload.c
@@ -49,6 +49,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "gomp-constants.h"
 #include "gimple-pretty-print.h"
 #include "intl.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* Describe the OpenACC looping structure of a function.  The entire
    function is held in a 'NULL' loop.  */
diff --git a/gcc/omp-simd-clone.c b/gcc/omp-simd-clone.c
index a1a563e8094..ad56a61b9da 100644
--- a/gcc/omp-simd-clone.c
+++ b/gcc/omp-simd-clone.c
@@ -48,7 +48,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "ipa-prop.h"
 #include "tree-eh.h"
 #include "varasm.h"
-
+#include "stringpool.h"
+#include "attribs.h"
 
 /* Allocate a fresh `simd_clone' and return it.  NARGS is the number
    of arguments to reserve space for.  */
diff --git a/gcc/opts-global.c b/gcc/opts-global.c
index 50bad77c347..fc55512e554 100644
--- a/gcc/opts-global.c
+++ b/gcc/opts-global.c
@@ -35,6 +35,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "plugin.h"
 #include "toplev.h"
 #include "context.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 
 typedef const char *const_char_p; /* For DEF_VEC_P.  */
diff --git a/gcc/passes.c b/gcc/passes.c
index f5791ac806a..2c9add84c1d 100644
--- a/gcc/passes.c
+++ b/gcc/passes.c
@@ -61,6 +61,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-cfgcleanup.h"
 #include "insn-addr.h" /* for INSN_ADDRESSES_ALLOC.  */
 #include "diagnostic-core.h" /* for fnotice */
+#include "stringpool.h"
+#include "attribs.h"
 
 using namespace gcc;
 
diff --git a/gcc/predict.c b/gcc/predict.c
index 609c099d7b5..80c2c1966d8 100644
--- a/gcc/predict.c
+++ b/gcc/predict.c
@@ -59,6 +59,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "gimple-pretty-print.h"
 #include "selftest.h"
 #include "cfgrtl.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* Enum with reasons why a predictor is ignored.  */
 
diff --git a/gcc/sancov.c b/gcc/sancov.c
index 1651989ea24..b19de8bbbc5 100644
--- a/gcc/sancov.c
+++ b/gcc/sancov.c
@@ -32,6 +32,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-cfg.h"
 #include "tree-pass.h"
 #include "tree-iterator.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 
 namespace {
diff --git a/gcc/sanopt.c b/gcc/sanopt.c
index f6dd14da00d..d17c7db3321 100644
--- a/gcc/sanopt.c
+++ b/gcc/sanopt.c
@@ -30,6 +30,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "gimple-pretty-print.h"
 #include "fold-const.h"
 #include "gimple-iterator.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 #include "ubsan.h"
 #include "params.h"
diff --git a/gcc/symtab.c b/gcc/symtab.c
index 0145910023f..7e5eb7d6416 100644
--- a/gcc/symtab.c
+++ b/gcc/symtab.c
@@ -35,6 +35,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "output.h"
 #include "ipa-utils.h"
 #include "calls.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 static const char *ipa_ref_use_name[] = {"read","write","addr","alias","chkp"};
 
diff --git a/gcc/toplev.c b/gcc/toplev.c
index b28f1847c83..ba7c13371fd 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -63,6 +63,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "hosthooks.h"
 #include "opts.h"
 #include "opts-diagnostic.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 #include "tsan.h"
 #include "plugin.h"
diff --git a/gcc/trans-mem.c b/gcc/trans-mem.c
index eb03560be26..40b53681186 100644
--- a/gcc/trans-mem.c
+++ b/gcc/trans-mem.c
@@ -50,7 +50,8 @@
 #include "langhooks.h"
 #include "cfgloop.h"
 #include "tree-ssa-address.h"
-
+#include "stringpool.h"
+#include "attribs.h"
 
 #define A_RUNINSTRUMENTEDCODE	0x0001
 #define A_RUNUNINSTRUMENTEDCODE	0x0002
diff --git a/gcc/tree-chkp.c b/gcc/tree-chkp.c
index e241f50f308..12af458fb90 100644
--- a/gcc/tree-chkp.c
+++ b/gcc/tree-chkp.c
@@ -52,6 +52,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-dfa.h"
 #include "ipa-chkp.h"
 #include "params.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /*  Pointer Bounds Checker instruments code with memory checks to find
     out-of-bounds memory accesses.  Checks are performed by computing
diff --git a/gcc/tree-eh.c b/gcc/tree-eh.c
index c68d71a5e54..938197992ce 100644
--- a/gcc/tree-eh.c
+++ b/gcc/tree-eh.c
@@ -43,6 +43,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "langhooks.h"
 #include "cfgloop.h"
 #include "gimple-low.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 
 /* In some instances a tree and a gimple need to be stored in a same table,
diff --git a/gcc/tree-into-ssa.c b/gcc/tree-into-ssa.c
index d4056373f31..28f72e4ce32 100644
--- a/gcc/tree-into-ssa.c
+++ b/gcc/tree-into-ssa.c
@@ -38,6 +38,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-ssa.h"
 #include "domwalk.h"
 #include "statistics.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 
 #define PERCENT(x,y) ((float)(x) * 100.0 / (float)(y))
diff --git a/gcc/tree-object-size.c b/gcc/tree-object-size.c
index 723a5283da6..a56b78a4510 100644
--- a/gcc/tree-object-size.c
+++ b/gcc/tree-object-size.c
@@ -32,6 +32,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "gimple-fold.h"
 #include "gimple-iterator.h"
 #include "tree-cfg.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 struct object_size_info
 {
diff --git a/gcc/tree-parloops.c b/gcc/tree-parloops.c
index 538932e50bf..69f49558bb4 100644
--- a/gcc/tree-parloops.c
+++ b/gcc/tree-parloops.c
@@ -58,6 +58,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-eh.h"
 #include "gomp-constants.h"
 #include "tree-dfa.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* This pass tries to distribute iterations of loops into several threads.
    The implementation is straightforward -- for each loop we test whether its
diff --git a/gcc/tree-profile.c b/gcc/tree-profile.c
index b1ee7f2b3f5..4b73255018c 100644
--- a/gcc/tree-profile.c
+++ b/gcc/tree-profile.c
@@ -50,6 +50,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "profile.h"
 #include "tree-cfgcleanup.h"
 #include "params.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 static GTY(()) tree gcov_type_node;
 static GTY(()) tree tree_interval_profiler_fn;
diff --git a/gcc/tree-ssa-ccp.c b/gcc/tree-ssa-ccp.c
index f18f2e0c2a4..3940d538ca7 100644
--- a/gcc/tree-ssa-ccp.c
+++ b/gcc/tree-ssa-ccp.c
@@ -145,6 +145,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-ssa-ccp.h"
 #include "tree-dfa.h"
 #include "diagnostic-core.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* Possible lattice values.  */
 typedef enum
diff --git a/gcc/tree-ssa-live.c b/gcc/tree-ssa-live.c
index c77075e4ac6..8738fe21a6e 100644
--- a/gcc/tree-ssa-live.c
+++ b/gcc/tree-ssa-live.c
@@ -38,6 +38,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-ssa.h"
 #include "ipa-utils.h"
 #include "cfgloop.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 static void verify_live_on_entry (tree_live_info_p);
 
diff --git a/gcc/tree-ssa-loop.c b/gcc/tree-ssa-loop.c
index 19a0f30c525..1e8491757a6 100644
--- a/gcc/tree-ssa-loop.c
+++ b/gcc/tree-ssa-loop.c
@@ -38,6 +38,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-vectorizer.h"
 #include "omp-general.h"
 #include "diagnostic-core.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 
 /* A pass making sure loops are fixed up.  */
diff --git a/gcc/tree-ssa-sccvn.c b/gcc/tree-ssa-sccvn.c
index ca43f01b1f5..d62a49d2d1e 100644
--- a/gcc/tree-ssa-sccvn.c
+++ b/gcc/tree-ssa-sccvn.c
@@ -60,6 +60,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "domwalk.h"
 #include "gimple-iterator.h"
 #include "gimple-match.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* This algorithm is based on the SCC algorithm presented by Keith
    Cooper and L. Taylor Simpson in "SCC-Based Value numbering"
diff --git a/gcc/tree-ssa-structalias.c b/gcc/tree-ssa-structalias.c
index e743e35033e..c120ce40303 100644
--- a/gcc/tree-ssa-structalias.c
+++ b/gcc/tree-ssa-structalias.c
@@ -40,7 +40,8 @@
 #include "params.h"
 #include "gimple-walk.h"
 #include "varasm.h"
-
+#include "stringpool.h"
+#include "attribs.h"
 
 /* The idea behind this analyzer is to generate set constraints from the
    program, then solve the resulting constraints in order to generate the
diff --git a/gcc/tree-ssa.c b/gcc/tree-ssa.c
index a67012c043f..8b6da9645ce 100644
--- a/gcc/tree-ssa.c
+++ b/gcc/tree-ssa.c
@@ -41,6 +41,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "cfgexpand.h"
 #include "tree-cfg.h"
 #include "tree-dfa.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 
 /* Pointer map of variable mappings, keyed by edge.  */
diff --git a/gcc/tree-streamer-in.c b/gcc/tree-streamer-in.c
index d7b6d224ab5..50aad371062 100644
--- a/gcc/tree-streamer-in.c
+++ b/gcc/tree-streamer-in.c
@@ -32,6 +32,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "builtins.h"
 #include "ipa-chkp.h"
 #include "gomp-constants.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 
 
diff --git a/gcc/tree-vectorizer.c b/gcc/tree-vectorizer.c
index 33a1f580474..9fe40b928d4 100644
--- a/gcc/tree-vectorizer.c
+++ b/gcc/tree-vectorizer.c
@@ -76,6 +76,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-ssa-propagate.h"
 #include "dbgcnt.h"
 #include "tree-scalar-evolution.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 
 /* Loop or bb location.  */
diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c
index 79a29bf0efb..657a8d186c8 100644
--- a/gcc/tree-vrp.c
+++ b/gcc/tree-vrp.c
@@ -62,6 +62,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "alloc-pool.h"
 #include "domwalk.h"
 #include "tree-cfgcleanup.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 #define VR_INITIALIZER { VR_UNDEFINED, NULL_TREE, NULL_TREE, NULL }
 
diff --git a/gcc/tree.c b/gcc/tree.c
index 2b65cb1d125..c493edd561d 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -62,6 +62,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "print-tree.h"
 #include "ipa-utils.h"
 #include "selftest.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* Tree code classes.  */
 
@@ -4822,254 +4824,6 @@ protected_set_expr_location (tree t, location_t loc)
     SET_EXPR_LOCATION (t, loc);
 }
 \f
-/* Return a declaration like DDECL except that its DECL_ATTRIBUTES
-   is ATTRIBUTE.  */
-
-tree
-build_decl_attribute_variant (tree ddecl, tree attribute)
-{
-  DECL_ATTRIBUTES (ddecl) = attribute;
-  return ddecl;
-}
-
-/* Return a type like TTYPE except that its TYPE_ATTRIBUTE
-   is ATTRIBUTE and its qualifiers are QUALS.
-
-   Record such modified types already made so we don't make duplicates.  */
-
-tree
-build_type_attribute_qual_variant (tree ttype, tree attribute, int quals)
-{
-  if (! attribute_list_equal (TYPE_ATTRIBUTES (ttype), attribute))
-    {
-      tree ntype;
-
-      /* Building a distinct copy of a tagged type is inappropriate; it
-	 causes breakage in code that expects there to be a one-to-one
-	 relationship between a struct and its fields.
-	 build_duplicate_type is another solution (as used in
-	 handle_transparent_union_attribute), but that doesn't play well
-	 with the stronger C++ type identity model.  */
-      if (TREE_CODE (ttype) == RECORD_TYPE
-	  || TREE_CODE (ttype) == UNION_TYPE
-	  || TREE_CODE (ttype) == QUAL_UNION_TYPE
-	  || TREE_CODE (ttype) == ENUMERAL_TYPE)
-	{
-	  warning (OPT_Wattributes,
-		   "ignoring attributes applied to %qT after definition",
-		   TYPE_MAIN_VARIANT (ttype));
-	  return build_qualified_type (ttype, quals);
-	}
-
-      ttype = build_qualified_type (ttype, TYPE_UNQUALIFIED);
-      ntype = build_distinct_type_copy (ttype);
-
-      TYPE_ATTRIBUTES (ntype) = attribute;
-
-      hashval_t hash = type_hash_canon_hash (ntype);
-      ntype = type_hash_canon (hash, ntype);
-
-      /* If the target-dependent attributes make NTYPE different from
-	 its canonical type, we will need to use structural equality
-	 checks for this type. */
-      if (TYPE_STRUCTURAL_EQUALITY_P (ttype)
-          || !comp_type_attributes (ntype, ttype))
-	SET_TYPE_STRUCTURAL_EQUALITY (ntype);
-      else if (TYPE_CANONICAL (ntype) == ntype)
-	TYPE_CANONICAL (ntype) = TYPE_CANONICAL (ttype);
-
-      ttype = build_qualified_type (ntype, quals);
-    }
-  else if (TYPE_QUALS (ttype) != quals)
-    ttype = build_qualified_type (ttype, quals);
-
-  return ttype;
-}
-
-/* Check if "omp declare simd" attribute arguments, CLAUSES1 and CLAUSES2, are
-   the same.  */
-
-static bool
-omp_declare_simd_clauses_equal (tree clauses1, tree clauses2)
-{
-  tree cl1, cl2;
-  for (cl1 = clauses1, cl2 = clauses2;
-       cl1 && cl2;
-       cl1 = OMP_CLAUSE_CHAIN (cl1), cl2 = OMP_CLAUSE_CHAIN (cl2))
-    {
-      if (OMP_CLAUSE_CODE (cl1) != OMP_CLAUSE_CODE (cl2))
-	return false;
-      if (OMP_CLAUSE_CODE (cl1) != OMP_CLAUSE_SIMDLEN)
-	{
-	  if (simple_cst_equal (OMP_CLAUSE_DECL (cl1),
-				OMP_CLAUSE_DECL (cl2)) != 1)
-	    return false;
-	}
-      switch (OMP_CLAUSE_CODE (cl1))
-	{
-	case OMP_CLAUSE_ALIGNED:
-	  if (simple_cst_equal (OMP_CLAUSE_ALIGNED_ALIGNMENT (cl1),
-				OMP_CLAUSE_ALIGNED_ALIGNMENT (cl2)) != 1)
-	    return false;
-	  break;
-	case OMP_CLAUSE_LINEAR:
-	  if (simple_cst_equal (OMP_CLAUSE_LINEAR_STEP (cl1),
-				OMP_CLAUSE_LINEAR_STEP (cl2)) != 1)
-	    return false;
-	  break;
-	case OMP_CLAUSE_SIMDLEN:
-	  if (simple_cst_equal (OMP_CLAUSE_SIMDLEN_EXPR (cl1),
-				OMP_CLAUSE_SIMDLEN_EXPR (cl2)) != 1)
-	    return false;
-	default:
-	  break;
-	}
-    }
-  return true;
-}
-
-/* Compare two constructor-element-type constants.  Return 1 if the lists
-   are known to be equal; otherwise return 0.  */
-
-static bool
-simple_cst_list_equal (const_tree l1, const_tree l2)
-{
-  while (l1 != NULL_TREE && l2 != NULL_TREE)
-    {
-      if (simple_cst_equal (TREE_VALUE (l1), TREE_VALUE (l2)) != 1)
-	return false;
-
-      l1 = TREE_CHAIN (l1);
-      l2 = TREE_CHAIN (l2);
-    }
-
-  return l1 == l2;
-}
-
-/* Compare two identifier nodes representing attributes.
-   Return true if they are the same, false otherwise.  */
-
-static bool
-cmp_attrib_identifiers (const_tree attr1, const_tree attr2)
-{
-  /* Make sure we're dealing with IDENTIFIER_NODEs.  */
-  gcc_checking_assert (TREE_CODE (attr1) == IDENTIFIER_NODE
-		       && TREE_CODE (attr2) == IDENTIFIER_NODE);
-
-  /* Identifiers can be compared directly for equality.  */
-  if (attr1 == attr2)
-    return true;
-
-  return cmp_attribs (IDENTIFIER_POINTER (attr1), IDENTIFIER_LENGTH (attr1),
-		      IDENTIFIER_POINTER (attr2), IDENTIFIER_LENGTH (attr2));
-}
-
-/* Compare two attributes for their value identity.  Return true if the
-   attribute values are known to be equal; otherwise return false.  */
-
-bool
-attribute_value_equal (const_tree attr1, const_tree attr2)
-{
-  if (TREE_VALUE (attr1) == TREE_VALUE (attr2))
-    return true;
-
-  if (TREE_VALUE (attr1) != NULL_TREE
-      && TREE_CODE (TREE_VALUE (attr1)) == TREE_LIST
-      && TREE_VALUE (attr2) != NULL_TREE
-      && TREE_CODE (TREE_VALUE (attr2)) == TREE_LIST)
-    {
-      /* Handle attribute format.  */
-      if (is_attribute_p ("format", get_attribute_name (attr1)))
-	{
-	  attr1 = TREE_VALUE (attr1);
-	  attr2 = TREE_VALUE (attr2);
-	  /* Compare the archetypes (printf/scanf/strftime/...).  */
-	  if (!cmp_attrib_identifiers (TREE_VALUE (attr1),
-				       TREE_VALUE (attr2)))
-	    return false;
-	  /* Archetypes are the same.  Compare the rest.  */
-	  return (simple_cst_list_equal (TREE_CHAIN (attr1),
-					 TREE_CHAIN (attr2)) == 1);
-	}
-      return (simple_cst_list_equal (TREE_VALUE (attr1),
-				     TREE_VALUE (attr2)) == 1);
-    }
-
-  if ((flag_openmp || flag_openmp_simd)
-      && TREE_VALUE (attr1) && TREE_VALUE (attr2)
-      && TREE_CODE (TREE_VALUE (attr1)) == OMP_CLAUSE
-      && TREE_CODE (TREE_VALUE (attr2)) == OMP_CLAUSE)
-    return omp_declare_simd_clauses_equal (TREE_VALUE (attr1),
-					   TREE_VALUE (attr2));
-
-  return (simple_cst_equal (TREE_VALUE (attr1), TREE_VALUE (attr2)) == 1);
-}
-
-/* Return 0 if the attributes for two types are incompatible, 1 if they
-   are compatible, and 2 if they are nearly compatible (which causes a
-   warning to be generated).  */
-int
-comp_type_attributes (const_tree type1, const_tree type2)
-{
-  const_tree a1 = TYPE_ATTRIBUTES (type1);
-  const_tree a2 = TYPE_ATTRIBUTES (type2);
-  const_tree a;
-
-  if (a1 == a2)
-    return 1;
-  for (a = a1; a != NULL_TREE; a = TREE_CHAIN (a))
-    {
-      const struct attribute_spec *as;
-      const_tree attr;
-
-      as = lookup_attribute_spec (get_attribute_name (a));
-      if (!as || as->affects_type_identity == false)
-        continue;
-
-      attr = lookup_attribute (as->name, CONST_CAST_TREE (a2));
-      if (!attr || !attribute_value_equal (a, attr))
-        break;
-    }
-  if (!a)
-    {
-      for (a = a2; a != NULL_TREE; a = TREE_CHAIN (a))
-	{
-	  const struct attribute_spec *as;
-
-	  as = lookup_attribute_spec (get_attribute_name (a));
-	  if (!as || as->affects_type_identity == false)
-	    continue;
-
-	  if (!lookup_attribute (as->name, CONST_CAST_TREE (a1)))
-	    break;
-	  /* We don't need to compare trees again, as we did this
-	     already in first loop.  */
-	}
-      /* All types - affecting identity - are equal, so
-         there is no need to call target hook for comparison.  */
-      if (!a)
-        return 1;
-    }
-  if (lookup_attribute ("transaction_safe", CONST_CAST_TREE (a)))
-    return 0;
-  /* As some type combinations - like default calling-convention - might
-     be compatible, we have to call the target hook to get the final result.  */
-  return targetm.comp_type_attributes (type1, type2);
-}
-
-/* Return a type like TTYPE except that its TYPE_ATTRIBUTE
-   is ATTRIBUTE.
-
-   Record such modified types already made so we don't make duplicates.  */
-
-tree
-build_type_attribute_variant (tree ttype, tree attribute)
-{
-  return build_type_attribute_qual_variant (ttype, attribute,
-					    TYPE_QUALS (ttype));
-}
-
-
 /* Reset the expression *EXPR_P, a size or position.
 
    ??? We could reset all non-constant sizes or positions.  But it's cheap
@@ -6023,379 +5777,6 @@ make_pass_ipa_free_lang_data (gcc::context *ctxt)
 {
   return new pass_ipa_free_lang_data (ctxt);
 }
-
-/* The backbone of lookup_attribute().  ATTR_LEN is the string length
-   of ATTR_NAME, and LIST is not NULL_TREE.  */
-tree
-private_lookup_attribute (const char *attr_name, size_t attr_len, tree list)
-{
-  while (list)
-    {
-      tree attr = get_attribute_name (list);
-      size_t ident_len = IDENTIFIER_LENGTH (attr);
-      if (cmp_attribs (attr_name, attr_len, IDENTIFIER_POINTER (attr),
-		       ident_len))
-	break;
-      list = TREE_CHAIN (list);
-    }
-
-  return list;
-}
-
-/* Given an attribute name ATTR_NAME and a list of attributes LIST,
-   return a pointer to the attribute's list first element if the attribute
-   starts with ATTR_NAME.  */
-
-tree
-private_lookup_attribute_by_prefix (const char *attr_name, size_t attr_len,
-				    tree list)
-{
-  while (list)
-    {
-      size_t ident_len = IDENTIFIER_LENGTH (get_attribute_name (list));
-
-      if (attr_len > ident_len)
-	{
-	  list = TREE_CHAIN (list);
-	  continue;
-	}
-
-      const char *p = IDENTIFIER_POINTER (get_attribute_name (list));
-      gcc_checking_assert (attr_len == 0 || p[0] != '_');
-
-      if (strncmp (attr_name, p, attr_len) == 0)
-	break;
-
-      list = TREE_CHAIN (list);
-    }
-
-  return list;
-}
-
-
-/* A variant of lookup_attribute() that can be used with an identifier
-   as the first argument, and where the identifier can be either
-   'text' or '__text__'.
-
-   Given an attribute ATTR_IDENTIFIER, and a list of attributes LIST,
-   return a pointer to the attribute's list element if the attribute
-   is part of the list, or NULL_TREE if not found.  If the attribute
-   appears more than once, this only returns the first occurrence; the
-   TREE_CHAIN of the return value should be passed back in if further
-   occurrences are wanted.  ATTR_IDENTIFIER must be an identifier but
-   can be in the form 'text' or '__text__'.  */
-static tree
-lookup_ident_attribute (tree attr_identifier, tree list)
-{
-  gcc_checking_assert (TREE_CODE (attr_identifier) == IDENTIFIER_NODE);
-
-  while (list)
-    {
-      gcc_checking_assert (TREE_CODE (get_attribute_name (list))
-			   == IDENTIFIER_NODE);
-
-      if (cmp_attrib_identifiers (attr_identifier,
-				  get_attribute_name (list)))
-	/* Found it.  */
-	break;
-      list = TREE_CHAIN (list);
-    }
-
-  return list;
-}
-
-/* Remove any instances of attribute ATTR_NAME in LIST and return the
-   modified list.  */
-
-tree
-remove_attribute (const char *attr_name, tree list)
-{
-  tree *p;
-  gcc_checking_assert (attr_name[0] != '_');
-
-  for (p = &list; *p; )
-    {
-      tree l = *p;
-
-      tree attr = get_attribute_name (l);
-      if (is_attribute_p (attr_name, attr))
-	*p = TREE_CHAIN (l);
-      else
-	p = &TREE_CHAIN (l);
-    }
-
-  return list;
-}
-
-/* Return an attribute list that is the union of a1 and a2.  */
-
-tree
-merge_attributes (tree a1, tree a2)
-{
-  tree attributes;
-
-  /* Either one unset?  Take the set one.  */
-
-  if ((attributes = a1) == 0)
-    attributes = a2;
-
-  /* One that completely contains the other?  Take it.  */
-
-  else if (a2 != 0 && ! attribute_list_contained (a1, a2))
-    {
-      if (attribute_list_contained (a2, a1))
-	attributes = a2;
-      else
-	{
-	  /* Pick the longest list, and hang on the other list.  */
-
-	  if (list_length (a1) < list_length (a2))
-	    attributes = a2, a2 = a1;
-
-	  for (; a2 != 0; a2 = TREE_CHAIN (a2))
-	    {
-	      tree a;
-	      for (a = lookup_ident_attribute (get_attribute_name (a2),
-					       attributes);
-		   a != NULL_TREE && !attribute_value_equal (a, a2);
-		   a = lookup_ident_attribute (get_attribute_name (a2),
-					       TREE_CHAIN (a)))
-		;
-	      if (a == NULL_TREE)
-		{
-		  a1 = copy_node (a2);
-		  TREE_CHAIN (a1) = attributes;
-		  attributes = a1;
-		}
-	    }
-	}
-    }
-  return attributes;
-}
-
-/* Given types T1 and T2, merge their attributes and return
-  the result.  */
-
-tree
-merge_type_attributes (tree t1, tree t2)
-{
-  return merge_attributes (TYPE_ATTRIBUTES (t1),
-			   TYPE_ATTRIBUTES (t2));
-}
-
-/* Given decls OLDDECL and NEWDECL, merge their attributes and return
-   the result.  */
-
-tree
-merge_decl_attributes (tree olddecl, tree newdecl)
-{
-  return merge_attributes (DECL_ATTRIBUTES (olddecl),
-			   DECL_ATTRIBUTES (newdecl));
-}
-
-#if TARGET_DLLIMPORT_DECL_ATTRIBUTES
-
-/* Specialization of merge_decl_attributes for various Windows targets.
-
-   This handles the following situation:
-
-     __declspec (dllimport) int foo;
-     int foo;
-
-   The second instance of `foo' nullifies the dllimport.  */
-
-tree
-merge_dllimport_decl_attributes (tree old, tree new_tree)
-{
-  tree a;
-  int delete_dllimport_p = 1;
-
-  /* What we need to do here is remove from `old' dllimport if it doesn't
-     appear in `new'.  dllimport behaves like extern: if a declaration is
-     marked dllimport and a definition appears later, then the object
-     is not dllimport'd.  We also remove a `new' dllimport if the old list
-     contains dllexport:  dllexport always overrides dllimport, regardless
-     of the order of declaration.  */
-  if (!VAR_OR_FUNCTION_DECL_P (new_tree))
-    delete_dllimport_p = 0;
-  else if (DECL_DLLIMPORT_P (new_tree)
-     	   && lookup_attribute ("dllexport", DECL_ATTRIBUTES (old)))
-    {
-      DECL_DLLIMPORT_P (new_tree) = 0;
-      warning (OPT_Wattributes, "%q+D already declared with dllexport attribute: "
-	      "dllimport ignored", new_tree);
-    }
-  else if (DECL_DLLIMPORT_P (old) && !DECL_DLLIMPORT_P (new_tree))
-    {
-      /* Warn about overriding a symbol that has already been used, e.g.:
-           extern int __attribute__ ((dllimport)) foo;
-	   int* bar () {return &foo;}
-	   int foo;
-      */
-      if (TREE_USED (old))
-	{
-	  warning (0, "%q+D redeclared without dllimport attribute "
-		   "after being referenced with dll linkage", new_tree);
-	  /* If we have used a variable's address with dllimport linkage,
-	      keep the old DECL_DLLIMPORT_P flag: the ADDR_EXPR using the
-	      decl may already have had TREE_CONSTANT computed.
-	      We still remove the attribute so that assembler code refers
-	      to '&foo rather than '_imp__foo'.  */
-	  if (VAR_P (old) && TREE_ADDRESSABLE (old))
-	    DECL_DLLIMPORT_P (new_tree) = 1;
-	}
-
-      /* Let an inline definition silently override the external reference,
-	 but otherwise warn about attribute inconsistency.  */
-      else if (VAR_P (new_tree) || !DECL_DECLARED_INLINE_P (new_tree))
-	warning (OPT_Wattributes, "%q+D redeclared without dllimport attribute: "
-		  "previous dllimport ignored", new_tree);
-    }
-  else
-    delete_dllimport_p = 0;
-
-  a = merge_attributes (DECL_ATTRIBUTES (old), DECL_ATTRIBUTES (new_tree));
-
-  if (delete_dllimport_p)
-    a = remove_attribute ("dllimport", a);
-
-  return a;
-}
-
-/* Handle a "dllimport" or "dllexport" attribute; arguments as in
-   struct attribute_spec.handler.  */
-
-tree
-handle_dll_attribute (tree * pnode, tree name, tree args, int flags,
-		      bool *no_add_attrs)
-{
-  tree node = *pnode;
-  bool is_dllimport;
-
-  /* These attributes may apply to structure and union types being created,
-     but otherwise should pass to the declaration involved.  */
-  if (!DECL_P (node))
-    {
-      if (flags & ((int) ATTR_FLAG_DECL_NEXT | (int) ATTR_FLAG_FUNCTION_NEXT
-		   | (int) ATTR_FLAG_ARRAY_NEXT))
-	{
-	  *no_add_attrs = true;
-	  return tree_cons (name, args, NULL_TREE);
-	}
-      if (TREE_CODE (node) == RECORD_TYPE
-	  || TREE_CODE (node) == UNION_TYPE)
-	{
-	  node = TYPE_NAME (node);
-	  if (!node)
-	    return NULL_TREE;
-	}
-      else
-	{
-	  warning (OPT_Wattributes, "%qE attribute ignored",
-		   name);
-	  *no_add_attrs = true;
-	  return NULL_TREE;
-	}
-    }
-
-  if (!VAR_OR_FUNCTION_DECL_P (node) && TREE_CODE (node) != TYPE_DECL)
-    {
-      *no_add_attrs = true;
-      warning (OPT_Wattributes, "%qE attribute ignored",
-	       name);
-      return NULL_TREE;
-    }
-
-  if (TREE_CODE (node) == TYPE_DECL
-      && TREE_CODE (TREE_TYPE (node)) != RECORD_TYPE
-      && TREE_CODE (TREE_TYPE (node)) != UNION_TYPE)
-    {
-      *no_add_attrs = true;
-      warning (OPT_Wattributes, "%qE attribute ignored",
-	       name);
-      return NULL_TREE;
-    }
-
-  is_dllimport = is_attribute_p ("dllimport", name);
-
-  /* Report error on dllimport ambiguities seen now before they cause
-     any damage.  */
-  if (is_dllimport)
-    {
-      /* Honor any target-specific overrides. */
-      if (!targetm.valid_dllimport_attribute_p (node))
-	*no_add_attrs = true;
-
-     else if (TREE_CODE (node) == FUNCTION_DECL
-	        && DECL_DECLARED_INLINE_P (node))
-	{
-	  warning (OPT_Wattributes, "inline function %q+D declared as "
-		  " dllimport: attribute ignored", node);
-	  *no_add_attrs = true;
-	}
-      /* Like MS, treat definition of dllimported variables and
-	 non-inlined functions on declaration as syntax errors. */
-     else if (TREE_CODE (node) == FUNCTION_DECL && DECL_INITIAL (node))
-	{
-	  error ("function %q+D definition is marked dllimport", node);
-	  *no_add_attrs = true;
-	}
-
-     else if (VAR_P (node))
-	{
-	  if (DECL_INITIAL (node))
-	    {
-	      error ("variable %q+D definition is marked dllimport",
-		     node);
-	      *no_add_attrs = true;
-	    }
-
-	  /* `extern' needn't be specified with dllimport.
-	     Specify `extern' now and hope for the best.  Sigh.  */
-	  DECL_EXTERNAL (node) = 1;
-	  /* Also, implicitly give dllimport'd variables declared within
-	     a function global scope, unless declared static.  */
-	  if (current_function_decl != NULL_TREE && !TREE_STATIC (node))
-	    TREE_PUBLIC (node) = 1;
-	}
-
-      if (*no_add_attrs == false)
-        DECL_DLLIMPORT_P (node) = 1;
-    }
-  else if (TREE_CODE (node) == FUNCTION_DECL
-	   && DECL_DECLARED_INLINE_P (node)
-	   && flag_keep_inline_dllexport)
-    /* An exported function, even if inline, must be emitted.  */
-    DECL_EXTERNAL (node) = 0;
-
-  /*  Report error if symbol is not accessible at global scope.  */
-  if (!TREE_PUBLIC (node) && VAR_OR_FUNCTION_DECL_P (node))
-    {
-      error ("external linkage required for symbol %q+D because of "
-	     "%qE attribute", node, name);
-      *no_add_attrs = true;
-    }
-
-  /* A dllexport'd entity must have default visibility so that other
-     program units (shared libraries or the main executable) can see
-     it.  A dllimport'd entity must have default visibility so that
-     the linker knows that undefined references within this program
-     unit can be resolved by the dynamic linker.  */
-  if (!*no_add_attrs)
-    {
-      if (DECL_VISIBILITY_SPECIFIED (node)
-	  && DECL_VISIBILITY (node) != VISIBILITY_DEFAULT)
-	error ("%qE implies default visibility, but %qD has already "
-	       "been declared with a different visibility",
-	       name, node);
-      DECL_VISIBILITY (node) = VISIBILITY_DEFAULT;
-      DECL_VISIBILITY_SPECIFIED (node) = 1;
-    }
-
-  return NULL_TREE;
-}
-
-#endif /* TARGET_DLLIMPORT_DECL_ATTRIBUTES  */
 \f
 /* Set the type qualifiers for TYPE to TYPE_QUALS, which is a bitmask
    of the various TYPE_QUAL values.  */
@@ -7155,68 +6536,6 @@ print_type_hash_statistics (void)
 	   type_hash_table->collisions ());
 }
 
-/* Given two lists of attributes, return true if list l2 is
-   equivalent to l1.  */
-
-int
-attribute_list_equal (const_tree l1, const_tree l2)
-{
-  if (l1 == l2)
-    return 1;
-
-  return attribute_list_contained (l1, l2)
-	 && attribute_list_contained (l2, l1);
-}
-
-/* Given two lists of attributes, return true if list L2 is
-   completely contained within L1.  */
-/* ??? This would be faster if attribute names were stored in a canonicalized
-   form.  Otherwise, if L1 uses `foo' and L2 uses `__foo__', the long method
-   must be used to show these elements are equivalent (which they are).  */
-/* ??? It's not clear that attributes with arguments will always be handled
-   correctly.  */
-
-int
-attribute_list_contained (const_tree l1, const_tree l2)
-{
-  const_tree t1, t2;
-
-  /* First check the obvious, maybe the lists are identical.  */
-  if (l1 == l2)
-    return 1;
-
-  /* Maybe the lists are similar.  */
-  for (t1 = l1, t2 = l2;
-       t1 != 0 && t2 != 0
-        && get_attribute_name (t1) == get_attribute_name (t2)
-        && TREE_VALUE (t1) == TREE_VALUE (t2);
-       t1 = TREE_CHAIN (t1), t2 = TREE_CHAIN (t2))
-    ;
-
-  /* Maybe the lists are equal.  */
-  if (t1 == 0 && t2 == 0)
-    return 1;
-
-  for (; t2 != 0; t2 = TREE_CHAIN (t2))
-    {
-      const_tree attr;
-      /* This CONST_CAST is okay because lookup_attribute does not
-	 modify its argument and the return value is assigned to a
-	 const_tree.  */
-      for (attr = lookup_ident_attribute (get_attribute_name (t2),
-					  CONST_CAST_TREE (l1));
-	   attr != NULL_TREE && !attribute_value_equal (t2, attr);
-	   attr = lookup_ident_attribute (get_attribute_name (t2),
-					  TREE_CHAIN (attr)))
-	;
-
-      if (attr == NULL_TREE)
-	return 0;
-    }
-
-  return 1;
-}
-
 /* Given two lists of types
    (chains of TREE_LIST nodes with types in the TREE_VALUE slots)
    return 1 if the lists contain the same types in the same order.
diff --git a/gcc/tree.h b/gcc/tree.h
index 1e89809804c..46debc12a84 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -4088,8 +4088,6 @@ extern tree purpose_member (const_tree, tree);
 extern bool vec_member (const_tree, vec<tree, va_gc> *);
 extern tree chain_index (int, tree);
 
-extern int attribute_list_equal (const_tree, const_tree);
-extern int attribute_list_contained (const_tree, const_tree);
 extern int tree_int_cst_equal (const_tree, const_tree);
 
 extern bool tree_fits_shwi_p (const_tree)
@@ -4127,90 +4125,6 @@ extern bool valid_constant_size_p (const_tree);
 
 extern tree make_tree (tree, rtx);
 
-/* Return a type like TTYPE except that its TYPE_ATTRIBUTES
-   is ATTRIBUTE.
-
-   Such modified types already made are recorded so that duplicates
-   are not made.  */
-
-extern tree build_type_attribute_variant (tree, tree);
-extern tree build_decl_attribute_variant (tree, tree);
-extern tree build_type_attribute_qual_variant (tree, tree, int);
-
-extern bool attribute_value_equal (const_tree, const_tree);
-
-/* Return 0 if the attributes for two types are incompatible, 1 if they
-   are compatible, and 2 if they are nearly compatible (which causes a
-   warning to be generated).  */
-extern int comp_type_attributes (const_tree, const_tree);
-
-/* Default versions of target-overridable functions.  */
-extern tree merge_decl_attributes (tree, tree);
-extern tree merge_type_attributes (tree, tree);
-
-/* This function is a private implementation detail of lookup_attribute()
-   and you should never call it directly.  */
-extern tree private_lookup_attribute (const char *, size_t, tree);
-
-/* This function is a private implementation detail
-   of lookup_attribute_by_prefix() and you should never call it directly.  */
-extern tree private_lookup_attribute_by_prefix (const char *, size_t, tree);
-
-/* Given an attribute name ATTR_NAME and a list of attributes LIST,
-   return a pointer to the attribute's list element if the attribute
-   is part of the list, or NULL_TREE if not found.  If the attribute
-   appears more than once, this only returns the first occurrence; the
-   TREE_CHAIN of the return value should be passed back in if further
-   occurrences are wanted.  ATTR_NAME must be in the form 'text' (not
-   '__text__').  */
-
-static inline tree
-lookup_attribute (const char *attr_name, tree list)
-{
-  gcc_checking_assert (attr_name[0] != '_');  
-  /* In most cases, list is NULL_TREE.  */
-  if (list == NULL_TREE)
-    return NULL_TREE;
-  else
-    /* Do the strlen() before calling the out-of-line implementation.
-       In most cases attr_name is a string constant, and the compiler
-       will optimize the strlen() away.  */
-    return private_lookup_attribute (attr_name, strlen (attr_name), list);
-}
-
-/* Given an attribute name ATTR_NAME and a list of attributes LIST,
-   return a pointer to the attribute's list first element if the attribute
-   starts with ATTR_NAME. ATTR_NAME must be in the form 'text' (not
-   '__text__').  */
-
-static inline tree
-lookup_attribute_by_prefix (const char *attr_name, tree list)
-{
-  gcc_checking_assert (attr_name[0] != '_');
-  /* In most cases, list is NULL_TREE.  */
-  if (list == NULL_TREE)
-    return NULL_TREE;
-  else
-    return private_lookup_attribute_by_prefix (attr_name, strlen (attr_name),
-					       list);
-}
-
-/* Remove any instances of attribute ATTR_NAME in LIST and return the
-   modified list.  */
-
-extern tree remove_attribute (const char *, tree);
-
-/* Given two attributes lists, return a list of their union.  */
-
-extern tree merge_attributes (tree, tree);
-
-/* Given two Windows decl attributes lists, possibly including
-   dllimport, return a list of their union .  */
-extern tree merge_dllimport_decl_attributes (tree, tree);
-
-/* Handle a "dllimport" or "dllexport" attribute.  */
-extern tree handle_dll_attribute (tree *, tree, tree, int, bool *);
-
 /* Returns true iff CAND and BASE have equivalent language-specific
    qualifiers.  */
 
diff --git a/gcc/tsan.c b/gcc/tsan.c
index 2f98b936c03..51b5821deb3 100644
--- a/gcc/tsan.c
+++ b/gcc/tsan.c
@@ -40,6 +40,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-ssa-loop-ivopts.h"
 #include "tree-eh.h"
 #include "tsan.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 #include "builtins.h"
 #include "target.h"
diff --git a/gcc/ubsan.c b/gcc/ubsan.c
index 2580a58b6eb..49e38fa6c09 100644
--- a/gcc/ubsan.c
+++ b/gcc/ubsan.c
@@ -39,6 +39,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "cfgloop.h"
 #include "ubsan.h"
 #include "expr.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 #include "gimplify-me.h"
 #include "dfp.h"
diff --git a/gcc/varasm.c b/gcc/varasm.c
index 6eccbe4b3f7..e0834a1ff3b 100644
--- a/gcc/varasm.c
+++ b/gcc/varasm.c
@@ -51,6 +51,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "langhooks.h"
 #include "debug.h"
 #include "common/common-target.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 #include "rtl-iter.h"
 
diff --git a/gcc/varpool.c b/gcc/varpool.c
index ab59c80406b..b005f529cc0 100644
--- a/gcc/varpool.c
+++ b/gcc/varpool.c
@@ -33,6 +33,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "output.h"
 #include "omp-offload.h"
 #include "context.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 const char * const tls_model_names[]={"none", "emulated",
 				      "global-dynamic", "local-dynamic",
-- 
2.13.3


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

* Re: [PATCH v2][RFC] Canonize names of attributes.
  2017-08-04 13:43                         ` Martin Liška
@ 2017-08-04 16:54                           ` Jason Merrill
  2017-08-07 16:44                             ` [PATCH][OBVIOUS] Fix missing include of header file in mips.c Martin Liška
  0 siblings, 1 reply; 37+ messages in thread
From: Jason Merrill @ 2017-08-04 16:54 UTC (permalink / raw)
  To: Martin Liška; +Cc: Joseph Myers, gcc-patches List, Richard Biener

On Fri, Aug 4, 2017 at 9:42 AM, Martin Liška <mliska@suse.cz> wrote:
> On 08/02/2017 01:25 PM, Joseph Myers wrote:
>> On Thu, 13 Jul 2017, Martin Liška wrote:
>>
>>> +/* 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);
>>> +  const char *s = IDENTIFIER_POINTER (attr_name);
>>> +
>>> +  if (l > 4 && s[0] == '_')
>>> +    {
>>> +      gcc_checking_assert (s[l - 2] == '_');
>>> +      return get_identifier_with_length (s + 2, l - 4);
>>> +    }
>>> +
>>> +  return attr_name;
>>
>> For this to (a) be correct, (b) not trigger the assertion, there must be a
>> precondition that attr_name either starts and ends with __, or does not
>> start with _, or has length 4 or less.  I don't see anything in the
>> callers to ensure this precondition holds, so that, for example,
>> __attribute__ ((_foobar)) does not trigger the assertion, and
>> __attribute__ ((_xformat__)) is not wrongly interpreted as a format
>> attribute (and similarly for attribute arguments when those are
>> canonicalized).
>
> Thanks for the review. I've updated to to canonicalize just __.+__.
> I added test-case for that: gcc/testsuite/gcc.dg/Wattributes-5.c.
>
>>
>>> +/* Compare attribute identifiers ATTR1 and ATTR2 with length ATTR1_LEN and
>>> +   ATTR2_LEN.  */
>>> +
>>> +static inline bool
>>> +cmp_attribs (const char *attr1, size_t attr1_len,
>>> +         const char *attr2, size_t attr2_len)
>>> +{
>>> +  gcc_checking_assert (attr1_len == 0 || attr1[0] != '_');
>>> +  gcc_checking_assert (attr2_len == 0 || attr2[0] != '_');
>
> And I removed these asserts.
>
> Patch can bootstrap on ppc64le-redhat-linux and survives regression tests.
>
> Ready to be installed?

OK.

Jason

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

* [PATCH][OBVIOUS] Fix missing include of header file in mips.c.
  2017-08-04 16:54                           ` Jason Merrill
@ 2017-08-07 16:44                             ` Martin Liška
  2017-08-07 17:10                               ` [PATCH][OBVIOUS] Add missing header file attribs.h to couple of targets Martin Liška
  0 siblings, 1 reply; 37+ messages in thread
From: Martin Liška @ 2017-08-07 16:44 UTC (permalink / raw)
  To: Jason Merrill
  Cc: Joseph Myers, gcc-patches List, Richard Biener, graham.stott

[-- Attachment #1: Type: text/plain, Size: 71 bytes --]

Hi.

This is small fallout of the patch. Installed as obvious.

Martin

[-- Attachment #2: 0001-Fix-missing-include-of-header-file-in-mips.c.patch --]
[-- Type: text/x-patch, Size: 755 bytes --]

From ee45f39052dcd2efe468f3e6efc6608b77ab6054 Mon Sep 17 00:00:00 2001
From: marxin <mliska@suse.cz>
Date: Mon, 7 Aug 2017 18:42:38 +0200
Subject: [PATCH] Fix missing include of header file in mips.c.

gcc/ChangeLog:

2017-08-07  Martin Liska  <mliska@suse.cz>

	* config/mips/mips.c: Include attribs.h.
---
 gcc/config/mips/mips.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c
index 6bfd86a07af..d2737a6ee80 100644
--- a/gcc/config/mips/mips.c
+++ b/gcc/config/mips/mips.c
@@ -34,6 +34,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "df.h"
 #include "tm_p.h"
 #include "stringpool.h"
+#include "attribs.h"
 #include "optabs.h"
 #include "regs.h"
 #include "emit-rtl.h"
-- 
2.13.3


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

* [PATCH][OBVIOUS] Add missing header file attribs.h to couple of targets.
  2017-08-07 16:44                             ` [PATCH][OBVIOUS] Fix missing include of header file in mips.c Martin Liška
@ 2017-08-07 17:10                               ` Martin Liška
  0 siblings, 0 replies; 37+ messages in thread
From: Martin Liška @ 2017-08-07 17:10 UTC (permalink / raw)
  To: Jason Merrill
  Cc: Joseph Myers, gcc-patches List, Richard Biener, graham.stott

[-- Attachment #1: Type: text/plain, Size: 63 bytes --]

I've been building cross compilers and this is part 2.

Martin

[-- Attachment #2: 0001-Add-missing-header-file-attribs.h-to-couple-of-targe.patch --]
[-- Type: text/x-patch, Size: 1983 bytes --]

From 924e6a075cfef0418a67eba5415fc96b841ea019 Mon Sep 17 00:00:00 2001
From: marxin <mliska@suse.cz>
Date: Mon, 7 Aug 2017 19:08:38 +0200
Subject: [PATCH] Add missing header file attribs.h to couple of targets.

gcc/ChangeLog:

2017-08-07  Martin Liska  <mliska@suse.cz>

	* config/m32c/m32c.c: Add include of stringpool.h and attribs.h.
	* config/rl78/rl78.c: Add include of attribs.h.
	* config/sh/sh.c: Likewise.
	* config/v850/v850.c: Likewise.
---
 gcc/config/m32c/m32c.c | 2 ++
 gcc/config/rl78/rl78.c | 1 +
 gcc/config/sh/sh.c     | 1 +
 gcc/config/v850/v850.c | 1 +
 4 files changed, 5 insertions(+)

diff --git a/gcc/config/m32c/m32c.c b/gcc/config/m32c/m32c.c
index b23f5aaf21a..95e97abf533 100644
--- a/gcc/config/m32c/m32c.c
+++ b/gcc/config/m32c/m32c.c
@@ -25,6 +25,8 @@
 #include "target.h"
 #include "rtl.h"
 #include "tree.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "df.h"
 #include "memmodel.h"
 #include "tm_p.h"
diff --git a/gcc/config/rl78/rl78.c b/gcc/config/rl78/rl78.c
index 460775cb995..f93116230d5 100644
--- a/gcc/config/rl78/rl78.c
+++ b/gcc/config/rl78/rl78.c
@@ -29,6 +29,7 @@
 #include "memmodel.h"
 #include "tm_p.h"
 #include "stringpool.h"
+#include "attribs.h"
 #include "optabs.h"
 #include "emit-rtl.h"
 #include "recog.h"
diff --git a/gcc/config/sh/sh.c b/gcc/config/sh/sh.c
index 6f01dcb700c..c31776ffef8 100644
--- a/gcc/config/sh/sh.c
+++ b/gcc/config/sh/sh.c
@@ -35,6 +35,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "memmodel.h"
 #include "tm_p.h"
 #include "stringpool.h"
+#include "attribs.h"
 #include "optabs.h"
 #include "emit-rtl.h"
 #include "recog.h"
diff --git a/gcc/config/v850/v850.c b/gcc/config/v850/v850.c
index eeb24aa972c..dd73c96435f 100644
--- a/gcc/config/v850/v850.c
+++ b/gcc/config/v850/v850.c
@@ -29,6 +29,7 @@
 #include "memmodel.h"
 #include "tm_p.h"
 #include "stringpool.h"
+#include "attribs.h"
 #include "insn-config.h"
 #include "regs.h"
 #include "emit-rtl.h"
-- 
2.13.3


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

* Re: [RFC][PATCH] Do refactoring of attribute functions and move them to attribs.[hc].
  2017-08-04 13:53                           ` Martin Liška
@ 2017-08-08  4:37                             ` Martin Liška
  2017-08-08  9:14                               ` Tom de Vries
  0 siblings, 1 reply; 37+ messages in thread
From: Martin Liška @ 2017-08-08  4:37 UTC (permalink / raw)
  To: Jeff Law, Jason Merrill; +Cc: Joseph Myers, gcc-patches List, Richard Biener

[-- Attachment #1: Type: text/plain, Size: 150 bytes --]

Hello.

I'm sending final version that I'm going to install. Compared to the previous version I tested
all targets in contrib/config-list.mk.

Martin

[-- Attachment #2: 0001-Do-refactoring-of-attribute-functions-and-move-them-.patch --]
[-- Type: text/x-patch, Size: 110373 bytes --]

From 860a6af96c27be95ead1163e7512fdca4cc6a67a Mon Sep 17 00:00:00 2001
From: marxin <mliska@suse.cz>
Date: Wed, 12 Jul 2017 13:39:54 +0200
Subject: [PATCH] Do refactoring of attribute functions and move them to
 attribs.[hc].

gcc/ada/ChangeLog:

2017-08-04  Martin Liska  <mliska@suse.cz>

	* gcc-interface/trans.c: Include header files.

gcc/objc/ChangeLog:

2017-08-04  Martin Liska  <mliska@suse.cz>

	* objc-gnu-runtime-abi-01.c: Include header files.
	* objc-next-runtime-abi-01.c: Likewise.
	* objc-next-runtime-abi-02.c: Likewise.

gcc/ChangeLog:

2017-08-04  Martin Liska  <mliska@suse.cz>

	* asan.c: Include header files.
	* attribs.c (build_decl_attribute_variant): New function moved
	from tree.[ch].
	(build_type_attribute_qual_variant): Likewise.
	(cmp_attrib_identifiers): Likewise.
	(simple_cst_list_equal): Likewise.
	(omp_declare_simd_clauses_equal): Likewise.
	(attribute_value_equal): Likewise.
	(comp_type_attributes): Likewise.
	(build_type_attribute_variant): Likewise.
	(lookup_ident_attribute): Likewise.
	(remove_attribute): Likewise.
	(merge_attributes): Likewise.
	(merge_type_attributes): Likewise.
	(merge_decl_attributes): Likewise.
	(merge_dllimport_decl_attributes): Likewise.
	(handle_dll_attribute): Likewise.
	(attribute_list_equal): Likewise.
	(attribute_list_contained): Likewise.
	* attribs.h (lookup_attribute): New function moved from tree.[ch].
	(lookup_attribute_by_prefix): Likewise.
	* bb-reorder.c: Include header files.
	* builtins.c: Likewise.
	* calls.c: Likewise.
	* cfgexpand.c: Likewise.
	* cgraph.c: Likewise.
	* cgraphunit.c: Likewise.
	* convert.c: Likewise.
	* dwarf2out.c: Likewise.
	* final.c: Likewise.
	* fold-const.c: Likewise.
	* function.c: Likewise.
	* gimple-expr.c: Likewise.
	* gimple-fold.c: Likewise.
	* gimple-pretty-print.c: Likewise.
	* gimple.c: Likewise.
	* gimplify.c: Likewise.
	* hsa-common.c: Likewise.
	* hsa-gen.c: Likewise.
	* internal-fn.c: Likewise.
	* ipa-chkp.c: Likewise.
	* ipa-cp.c: Likewise.
	* ipa-devirt.c: Likewise.
	* ipa-fnsummary.c: Likewise.
	* ipa-inline.c: Likewise.
	* ipa-visibility.c: Likewise.
	* ipa.c: Likewise.
	* lto-cgraph.c: Likewise.
	* omp-expand.c: Likewise.
	* omp-general.c: Likewise.
	* omp-low.c: Likewise.
	* omp-offload.c: Likewise.
	* omp-simd-clone.c: Likewise.
	* opts-global.c: Likewise.
	* passes.c: Likewise.
	* predict.c: Likewise.
	* sancov.c: Likewise.
	* sanopt.c: Likewise.
	* symtab.c: Likewise.
	* toplev.c: Likewise.
	* trans-mem.c: Likewise.
	* tree-chkp.c: Likewise.
	* tree-eh.c: Likewise.
	* tree-into-ssa.c: Likewise.
	* tree-object-size.c: Likewise.
	* tree-parloops.c: Likewise.
	* tree-profile.c: Likewise.
	* tree-ssa-ccp.c: Likewise.
	* tree-ssa-live.c: Likewise.
	* tree-ssa-loop.c: Likewise.
	* tree-ssa-sccvn.c: Likewise.
	* tree-ssa-structalias.c: Likewise.
	* tree-ssa.c: Likewise.
	* tree-streamer-in.c: Likewise.
	* tree-vectorizer.c: Likewise.
	* tree-vrp.c: Likewise.
	* tsan.c: Likewise.
	* ubsan.c: Likewise.
	* varasm.c: Likewise.
	* varpool.c: Likewise.
	* tree.c: Remove functions moved to attribs.[ch].
	* tree.h: Likewise.
	* config/aarch64/aarch64.c: Add attrs.h header file.
	* config/alpha/alpha.c: Likewise.
	* config/arc/arc.c: Likewise.
	* config/arm/arm.c: Likewise.
	* config/avr/avr.c: Likewise.
	* config/bfin/bfin.c: Likewise.
	* config/c6x/c6x.c: Likewise.
	* config/cr16/cr16.c: Likewise.
	* config/cris/cris.c: Likewise.
	* config/darwin.c: Likewise.
	* config/epiphany/epiphany.c: Likewise.
	* config/fr30/fr30.c: Likewise.
	* config/frv/frv.c: Likewise.
	* config/ft32/ft32.c: Likewise.
	* config/h8300/h8300.c: Likewise.
	* config/i386/winnt.c: Likewise.
	* config/ia64/ia64.c: Likewise.
	* config/iq2000/iq2000.c: Likewise.
	* config/lm32/lm32.c: Likewise.
	* config/m32c/m32c.c: Likewise.
	* config/m32r/m32r.c: Likewise.
	* config/m68k/m68k.c: Likewise.
	* config/mcore/mcore.c: Likewise.
	* config/microblaze/microblaze.c: Likewise.
	* config/mips/mips.c: Likewise.
	* config/mmix/mmix.c: Likewise.
	* config/mn10300/mn10300.c: Likewise.
	* config/moxie/moxie.c: Likewise.
	* config/msp430/msp430.c: Likewise.
	* config/nds32/nds32-isr.c: Likewise.
	* config/nds32/nds32.c: Likewise.
	* config/nios2/nios2.c: Likewise.
	* config/nvptx/nvptx.c: Likewise.
	* config/pa/pa.c: Likewise.
	* config/pdp11/pdp11.c: Likewise.
	* config/powerpcspe/powerpcspe.c: Likewise.
	* config/riscv/riscv.c: Likewise.
	* config/rl78/rl78.c: Likewise.
	* config/rx/rx.c: Likewise.
	* config/s390/s390.c: Likewise.
	* config/sh/sh.c: Likewise.
	* config/sol2.c: Likewise.
	* config/sparc/sparc.c: Likewise.
	* config/spu/spu.c: Likewise.
	* config/stormy16/stormy16.c: Likewise.
	* config/tilegx/tilegx.c: Likewise.
	* config/tilepro/tilepro.c: Likewise.
	* config/v850/v850.c: Likewise.
	* config/vax/vax.c: Likewise.
	* config/visium/visium.c: Likewise.
	* config/xtensa/xtensa.c: Likewise.

gcc/cp/ChangeLog:

2017-08-04  Martin Liska  <mliska@suse.cz>

	* call.c: Include header files.
	* cp-gimplify.c: Likewise.
	* cp-ubsan.c: Likewise.
	* cvt.c: Likewise.
	* init.c: Likewise.
	* search.c: Likewise.
	* semantics.c: Likewise.
	* typeck.c: Likewise.

gcc/lto/ChangeLog:

2017-08-04  Martin Liska  <mliska@suse.cz>

	* lto-lang.c: Include header files.
	* lto-symtab.c: Likewise.

gcc/c/ChangeLog:

2017-08-04  Martin Liska  <mliska@suse.cz>

	* c-convert.c: Include header files.
	* c-typeck.c: Likewise.

gcc/c-family/ChangeLog:

2017-08-04  Martin Liska  <mliska@suse.cz>

	* c-ada-spec.c: Include header files.
	* c-ubsan.c: Likewise.
	* c-warn.c: Likewise.

gcc/fortran/ChangeLog:

2017-08-04  Martin Liska  <mliska@suse.cz>

	* trans-types.c: Include header files.
---
 gcc/ada/gcc-interface/trans.c       |   2 +
 gcc/asan.c                          |   2 +
 gcc/attribs.c                       | 633 +++++++++++++++++++++++++++++++++
 gcc/attribs.h                       | 113 ++++++
 gcc/bb-reorder.c                    |   2 +
 gcc/builtins.c                      |   2 +
 gcc/c-family/c-ada-spec.c           |   2 +
 gcc/c-family/c-ubsan.c              |   4 +-
 gcc/c-family/c-warn.c               |   2 +
 gcc/c/c-convert.c                   |   2 +
 gcc/c/c-typeck.c                    |   2 +
 gcc/calls.c                         |   2 +
 gcc/cfgexpand.c                     |   2 +
 gcc/cgraph.c                        |   2 +
 gcc/cgraphunit.c                    |   2 +
 gcc/config/aarch64/aarch64.c        |   1 +
 gcc/config/alpha/alpha.c            |   2 +
 gcc/config/arc/arc.c                |   1 +
 gcc/config/arm/arm.c                |   1 +
 gcc/config/avr/avr.c                |   2 +
 gcc/config/bfin/bfin.c              |   2 +
 gcc/config/c6x/c6x.c                |   1 +
 gcc/config/cr16/cr16.c              |   2 +
 gcc/config/cris/cris.c              |   2 +
 gcc/config/darwin.c                 |   1 +
 gcc/config/epiphany/epiphany.c      |   1 +
 gcc/config/fr30/fr30.c              |   2 +
 gcc/config/frv/frv.c                |   1 +
 gcc/config/ft32/ft32.c              |   2 +
 gcc/config/h8300/h8300.c            |   1 +
 gcc/config/i386/winnt.c             |   1 +
 gcc/config/ia64/ia64.c              |   1 +
 gcc/config/iq2000/iq2000.c          |   2 +
 gcc/config/lm32/lm32.c              |   2 +
 gcc/config/m32r/m32r.c              |   1 +
 gcc/config/m68k/m68k.c              |   2 +
 gcc/config/mcore/mcore.c            |   1 +
 gcc/config/microblaze/microblaze.c  |   2 +
 gcc/config/mmix/mmix.c              |   2 +
 gcc/config/mn10300/mn10300.c        |   2 +
 gcc/config/moxie/moxie.c            |   2 +
 gcc/config/msp430/msp430.c          |   2 +
 gcc/config/nds32/nds32-isr.c        |   2 +
 gcc/config/nds32/nds32.c            |   2 +
 gcc/config/nios2/nios2.c            |   2 +
 gcc/config/nvptx/nvptx.c            |   1 +
 gcc/config/pa/pa.c                  |   1 +
 gcc/config/pdp11/pdp11.c            |   2 +
 gcc/config/powerpcspe/powerpcspe.c  |   1 +
 gcc/config/riscv/riscv.c            |   2 +
 gcc/config/rx/rx.c                  |   2 +
 gcc/config/s390/s390.c              |   1 +
 gcc/config/sol2.c                   |   1 +
 gcc/config/sparc/sparc.c            |   1 +
 gcc/config/spu/spu.c                |   1 +
 gcc/config/stormy16/stormy16.c      |   2 +
 gcc/config/tilegx/tilegx.c          |   1 +
 gcc/config/tilepro/tilepro.c        |   1 +
 gcc/config/vax/vax.c                |   2 +
 gcc/config/visium/visium.c          |   1 +
 gcc/config/xtensa/xtensa.c          |   1 +
 gcc/convert.c                       |   2 +
 gcc/cp/call.c                       |   2 +
 gcc/cp/cp-gimplify.c                |   2 +
 gcc/cp/cp-ubsan.c                   |   2 +
 gcc/cp/cvt.c                        |   2 +
 gcc/cp/init.c                       |   2 +
 gcc/cp/search.c                     |   2 +
 gcc/cp/semantics.c                  |   2 +
 gcc/cp/typeck.c                     |   2 +
 gcc/dwarf2out.c                     |   2 +
 gcc/final.c                         |   2 +
 gcc/fold-const.c                    |   2 +
 gcc/fortran/trans-types.c           |   1 +
 gcc/function.c                      |   2 +
 gcc/gimple-expr.c                   |   2 +
 gcc/gimple-fold.c                   |   2 +
 gcc/gimple-pretty-print.c           |   2 +
 gcc/gimple.c                        |   2 +
 gcc/gimplify.c                      |   2 +
 gcc/hsa-common.c                    |   2 +
 gcc/hsa-gen.c                       |   2 +
 gcc/internal-fn.c                   |   2 +
 gcc/ipa-chkp.c                      |   2 +
 gcc/ipa-cp.c                        |   2 +
 gcc/ipa-devirt.c                    |   2 +
 gcc/ipa-fnsummary.c                 |   2 +
 gcc/ipa-inline.c                    |   2 +
 gcc/ipa-visibility.c                |   2 +
 gcc/ipa.c                           |   3 +-
 gcc/lto-cgraph.c                    |   2 +
 gcc/lto/lto-lang.c                  |   2 +
 gcc/lto/lto-symtab.c                |   2 +
 gcc/objc/objc-gnu-runtime-abi-01.c  |   2 +
 gcc/objc/objc-next-runtime-abi-01.c |   2 +
 gcc/objc/objc-next-runtime-abi-02.c |   2 +
 gcc/omp-expand.c                    |   3 +-
 gcc/omp-general.c                   |   3 +-
 gcc/omp-low.c                       |   2 +
 gcc/omp-offload.c                   |   2 +
 gcc/omp-simd-clone.c                |   3 +-
 gcc/opts-global.c                   |   2 +
 gcc/passes.c                        |   2 +
 gcc/predict.c                       |   2 +
 gcc/sancov.c                        |   2 +
 gcc/sanopt.c                        |   2 +
 gcc/symtab.c                        |   2 +
 gcc/toplev.c                        |   2 +
 gcc/trans-mem.c                     |   3 +-
 gcc/tree-chkp.c                     |   2 +
 gcc/tree-eh.c                       |   2 +
 gcc/tree-into-ssa.c                 |   2 +
 gcc/tree-object-size.c              |   2 +
 gcc/tree-parloops.c                 |   2 +
 gcc/tree-profile.c                  |   2 +
 gcc/tree-ssa-ccp.c                  |   2 +
 gcc/tree-ssa-live.c                 |   2 +
 gcc/tree-ssa-loop.c                 |   2 +
 gcc/tree-ssa-sccvn.c                |   2 +
 gcc/tree-ssa-structalias.c          |   3 +-
 gcc/tree-ssa.c                      |   2 +
 gcc/tree-streamer-in.c              |   2 +
 gcc/tree-vectorizer.c               |   2 +
 gcc/tree-vrp.c                      |   2 +
 gcc/tree.c                          | 685 +-----------------------------------
 gcc/tree.h                          |  86 -----
 gcc/tsan.c                          |   2 +
 gcc/ubsan.c                         |   2 +
 gcc/varasm.c                        |   2 +
 gcc/varpool.c                       |   2 +
 130 files changed, 977 insertions(+), 776 deletions(-)

diff --git a/gcc/ada/gcc-interface/trans.c b/gcc/ada/gcc-interface/trans.c
index 7844bd7c5a8..67044b7b574 100644
--- a/gcc/ada/gcc-interface/trans.c
+++ b/gcc/ada/gcc-interface/trans.c
@@ -46,6 +46,8 @@
 #include "gimplify.h"
 #include "opts.h"
 #include "common/common-target.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 #include "ada.h"
 #include "adadecode.h"
diff --git a/gcc/asan.c b/gcc/asan.c
index 5f9275f6425..f83ca65ffdb 100644
--- a/gcc/asan.c
+++ b/gcc/asan.c
@@ -47,6 +47,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "varasm.h"
 #include "stor-layout.h"
 #include "tree-iterator.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 #include "dojump.h"
 #include "explow.h"
diff --git a/gcc/attribs.c b/gcc/attribs.c
index 05fa8ef8692..faa0649e190 100644
--- a/gcc/attribs.c
+++ b/gcc/attribs.c
@@ -942,3 +942,636 @@ is_function_default_version (const tree decl)
   return (TREE_CODE (attr) == STRING_CST
 	  && strcmp (TREE_STRING_POINTER (attr), "default") == 0);
 }
+
+/* Return a declaration like DDECL except that its DECL_ATTRIBUTES
+   is ATTRIBUTE.  */
+
+tree
+build_decl_attribute_variant (tree ddecl, tree attribute)
+{
+  DECL_ATTRIBUTES (ddecl) = attribute;
+  return ddecl;
+}
+
+/* Return a type like TTYPE except that its TYPE_ATTRIBUTE
+   is ATTRIBUTE and its qualifiers are QUALS.
+
+   Record such modified types already made so we don't make duplicates.  */
+
+tree
+build_type_attribute_qual_variant (tree ttype, tree attribute, int quals)
+{
+  if (! attribute_list_equal (TYPE_ATTRIBUTES (ttype), attribute))
+    {
+      tree ntype;
+
+      /* Building a distinct copy of a tagged type is inappropriate; it
+	 causes breakage in code that expects there to be a one-to-one
+	 relationship between a struct and its fields.
+	 build_duplicate_type is another solution (as used in
+	 handle_transparent_union_attribute), but that doesn't play well
+	 with the stronger C++ type identity model.  */
+      if (TREE_CODE (ttype) == RECORD_TYPE
+	  || TREE_CODE (ttype) == UNION_TYPE
+	  || TREE_CODE (ttype) == QUAL_UNION_TYPE
+	  || TREE_CODE (ttype) == ENUMERAL_TYPE)
+	{
+	  warning (OPT_Wattributes,
+		   "ignoring attributes applied to %qT after definition",
+		   TYPE_MAIN_VARIANT (ttype));
+	  return build_qualified_type (ttype, quals);
+	}
+
+      ttype = build_qualified_type (ttype, TYPE_UNQUALIFIED);
+      ntype = build_distinct_type_copy (ttype);
+
+      TYPE_ATTRIBUTES (ntype) = attribute;
+
+      hashval_t hash = type_hash_canon_hash (ntype);
+      ntype = type_hash_canon (hash, ntype);
+
+      /* If the target-dependent attributes make NTYPE different from
+	 its canonical type, we will need to use structural equality
+	 checks for this type.  */
+      if (TYPE_STRUCTURAL_EQUALITY_P (ttype)
+	  || !comp_type_attributes (ntype, ttype))
+	SET_TYPE_STRUCTURAL_EQUALITY (ntype);
+      else if (TYPE_CANONICAL (ntype) == ntype)
+	TYPE_CANONICAL (ntype) = TYPE_CANONICAL (ttype);
+
+      ttype = build_qualified_type (ntype, quals);
+    }
+  else if (TYPE_QUALS (ttype) != quals)
+    ttype = build_qualified_type (ttype, quals);
+
+  return ttype;
+}
+
+/* Compare two identifier nodes representing attributes.
+   Return true if they are the same, false otherwise.  */
+
+static bool
+cmp_attrib_identifiers (const_tree attr1, const_tree attr2)
+{
+  /* Make sure we're dealing with IDENTIFIER_NODEs.  */
+  gcc_checking_assert (TREE_CODE (attr1) == IDENTIFIER_NODE
+		       && TREE_CODE (attr2) == IDENTIFIER_NODE);
+
+  /* Identifiers can be compared directly for equality.  */
+  if (attr1 == attr2)
+    return true;
+
+  return cmp_attribs (IDENTIFIER_POINTER (attr1), IDENTIFIER_LENGTH (attr1),
+		      IDENTIFIER_POINTER (attr2), IDENTIFIER_LENGTH (attr2));
+}
+
+/* Compare two constructor-element-type constants.  Return 1 if the lists
+   are known to be equal; otherwise return 0.  */
+
+static bool
+simple_cst_list_equal (const_tree l1, const_tree l2)
+{
+  while (l1 != NULL_TREE && l2 != NULL_TREE)
+    {
+      if (simple_cst_equal (TREE_VALUE (l1), TREE_VALUE (l2)) != 1)
+	return false;
+
+      l1 = TREE_CHAIN (l1);
+      l2 = TREE_CHAIN (l2);
+    }
+
+  return l1 == l2;
+}
+
+/* Check if "omp declare simd" attribute arguments, CLAUSES1 and CLAUSES2, are
+   the same.  */
+
+static bool
+omp_declare_simd_clauses_equal (tree clauses1, tree clauses2)
+{
+  tree cl1, cl2;
+  for (cl1 = clauses1, cl2 = clauses2;
+       cl1 && cl2;
+       cl1 = OMP_CLAUSE_CHAIN (cl1), cl2 = OMP_CLAUSE_CHAIN (cl2))
+    {
+      if (OMP_CLAUSE_CODE (cl1) != OMP_CLAUSE_CODE (cl2))
+	return false;
+      if (OMP_CLAUSE_CODE (cl1) != OMP_CLAUSE_SIMDLEN)
+	{
+	  if (simple_cst_equal (OMP_CLAUSE_DECL (cl1),
+				OMP_CLAUSE_DECL (cl2)) != 1)
+	    return false;
+	}
+      switch (OMP_CLAUSE_CODE (cl1))
+	{
+	case OMP_CLAUSE_ALIGNED:
+	  if (simple_cst_equal (OMP_CLAUSE_ALIGNED_ALIGNMENT (cl1),
+				OMP_CLAUSE_ALIGNED_ALIGNMENT (cl2)) != 1)
+	    return false;
+	  break;
+	case OMP_CLAUSE_LINEAR:
+	  if (simple_cst_equal (OMP_CLAUSE_LINEAR_STEP (cl1),
+				OMP_CLAUSE_LINEAR_STEP (cl2)) != 1)
+	    return false;
+	  break;
+	case OMP_CLAUSE_SIMDLEN:
+	  if (simple_cst_equal (OMP_CLAUSE_SIMDLEN_EXPR (cl1),
+				OMP_CLAUSE_SIMDLEN_EXPR (cl2)) != 1)
+	    return false;
+	default:
+	  break;
+	}
+    }
+  return true;
+}
+
+
+/* Compare two attributes for their value identity.  Return true if the
+   attribute values are known to be equal; otherwise return false.  */
+
+bool
+attribute_value_equal (const_tree attr1, const_tree attr2)
+{
+  if (TREE_VALUE (attr1) == TREE_VALUE (attr2))
+    return true;
+
+  if (TREE_VALUE (attr1) != NULL_TREE
+      && TREE_CODE (TREE_VALUE (attr1)) == TREE_LIST
+      && TREE_VALUE (attr2) != NULL_TREE
+      && TREE_CODE (TREE_VALUE (attr2)) == TREE_LIST)
+    {
+      /* Handle attribute format.  */
+      if (is_attribute_p ("format", get_attribute_name (attr1)))
+	{
+	  attr1 = TREE_VALUE (attr1);
+	  attr2 = TREE_VALUE (attr2);
+	  /* Compare the archetypes (printf/scanf/strftime/...).  */
+	  if (!cmp_attrib_identifiers (TREE_VALUE (attr1), TREE_VALUE (attr2)))
+	    return false;
+	  /* Archetypes are the same.  Compare the rest.  */
+	  return (simple_cst_list_equal (TREE_CHAIN (attr1),
+					 TREE_CHAIN (attr2)) == 1);
+	}
+      return (simple_cst_list_equal (TREE_VALUE (attr1),
+				     TREE_VALUE (attr2)) == 1);
+    }
+
+  if ((flag_openmp || flag_openmp_simd)
+      && TREE_VALUE (attr1) && TREE_VALUE (attr2)
+      && TREE_CODE (TREE_VALUE (attr1)) == OMP_CLAUSE
+      && TREE_CODE (TREE_VALUE (attr2)) == OMP_CLAUSE)
+    return omp_declare_simd_clauses_equal (TREE_VALUE (attr1),
+					   TREE_VALUE (attr2));
+
+  return (simple_cst_equal (TREE_VALUE (attr1), TREE_VALUE (attr2)) == 1);
+}
+
+/* Return 0 if the attributes for two types are incompatible, 1 if they
+   are compatible, and 2 if they are nearly compatible (which causes a
+   warning to be generated).  */
+int
+comp_type_attributes (const_tree type1, const_tree type2)
+{
+  const_tree a1 = TYPE_ATTRIBUTES (type1);
+  const_tree a2 = TYPE_ATTRIBUTES (type2);
+  const_tree a;
+
+  if (a1 == a2)
+    return 1;
+  for (a = a1; a != NULL_TREE; a = TREE_CHAIN (a))
+    {
+      const struct attribute_spec *as;
+      const_tree attr;
+
+      as = lookup_attribute_spec (get_attribute_name (a));
+      if (!as || as->affects_type_identity == false)
+	continue;
+
+      attr = lookup_attribute (as->name, CONST_CAST_TREE (a2));
+      if (!attr || !attribute_value_equal (a, attr))
+	break;
+    }
+  if (!a)
+    {
+      for (a = a2; a != NULL_TREE; a = TREE_CHAIN (a))
+	{
+	  const struct attribute_spec *as;
+
+	  as = lookup_attribute_spec (get_attribute_name (a));
+	  if (!as || as->affects_type_identity == false)
+	    continue;
+
+	  if (!lookup_attribute (as->name, CONST_CAST_TREE (a1)))
+	    break;
+	  /* We don't need to compare trees again, as we did this
+	     already in first loop.  */
+	}
+      /* All types - affecting identity - are equal, so
+	 there is no need to call target hook for comparison.  */
+      if (!a)
+	return 1;
+    }
+  if (lookup_attribute ("transaction_safe", CONST_CAST_TREE (a)))
+    return 0;
+  /* As some type combinations - like default calling-convention - might
+     be compatible, we have to call the target hook to get the final result.  */
+  return targetm.comp_type_attributes (type1, type2);
+}
+
+/* Return a type like TTYPE except that its TYPE_ATTRIBUTE
+   is ATTRIBUTE.
+
+   Record such modified types already made so we don't make duplicates.  */
+
+tree
+build_type_attribute_variant (tree ttype, tree attribute)
+{
+  return build_type_attribute_qual_variant (ttype, attribute,
+					    TYPE_QUALS (ttype));
+}
+\f
+/* A variant of lookup_attribute() that can be used with an identifier
+   as the first argument, and where the identifier can be either
+   'text' or '__text__'.
+
+   Given an attribute ATTR_IDENTIFIER, and a list of attributes LIST,
+   return a pointer to the attribute's list element if the attribute
+   is part of the list, or NULL_TREE if not found.  If the attribute
+   appears more than once, this only returns the first occurrence; the
+   TREE_CHAIN of the return value should be passed back in if further
+   occurrences are wanted.  ATTR_IDENTIFIER must be an identifier but
+   can be in the form 'text' or '__text__'.  */
+static tree
+lookup_ident_attribute (tree attr_identifier, tree list)
+{
+  gcc_checking_assert (TREE_CODE (attr_identifier) == IDENTIFIER_NODE);
+
+  while (list)
+    {
+      gcc_checking_assert (TREE_CODE (get_attribute_name (list))
+			   == IDENTIFIER_NODE);
+
+      if (cmp_attrib_identifiers (attr_identifier,
+				  get_attribute_name (list)))
+	/* Found it.  */
+	break;
+      list = TREE_CHAIN (list);
+    }
+
+  return list;
+}
+
+/* Remove any instances of attribute ATTR_NAME in LIST and return the
+   modified list.  */
+
+tree
+remove_attribute (const char *attr_name, tree list)
+{
+  tree *p;
+  gcc_checking_assert (attr_name[0] != '_');
+
+  for (p = &list; *p;)
+    {
+      tree l = *p;
+
+      tree attr = get_attribute_name (l);
+      if (is_attribute_p (attr_name, attr))
+	*p = TREE_CHAIN (l);
+      else
+	p = &TREE_CHAIN (l);
+    }
+
+  return list;
+}
+
+/* Return an attribute list that is the union of a1 and a2.  */
+
+tree
+merge_attributes (tree a1, tree a2)
+{
+  tree attributes;
+
+  /* Either one unset?  Take the set one.  */
+
+  if ((attributes = a1) == 0)
+    attributes = a2;
+
+  /* One that completely contains the other?  Take it.  */
+
+  else if (a2 != 0 && ! attribute_list_contained (a1, a2))
+    {
+      if (attribute_list_contained (a2, a1))
+	attributes = a2;
+      else
+	{
+	  /* Pick the longest list, and hang on the other list.  */
+
+	  if (list_length (a1) < list_length (a2))
+	    attributes = a2, a2 = a1;
+
+	  for (; a2 != 0; a2 = TREE_CHAIN (a2))
+	    {
+	      tree a;
+	      for (a = lookup_ident_attribute (get_attribute_name (a2),
+					       attributes);
+		   a != NULL_TREE && !attribute_value_equal (a, a2);
+		   a = lookup_ident_attribute (get_attribute_name (a2),
+					       TREE_CHAIN (a)))
+		;
+	      if (a == NULL_TREE)
+		{
+		  a1 = copy_node (a2);
+		  TREE_CHAIN (a1) = attributes;
+		  attributes = a1;
+		}
+	    }
+	}
+    }
+  return attributes;
+}
+
+/* Given types T1 and T2, merge their attributes and return
+  the result.  */
+
+tree
+merge_type_attributes (tree t1, tree t2)
+{
+  return merge_attributes (TYPE_ATTRIBUTES (t1),
+			   TYPE_ATTRIBUTES (t2));
+}
+
+/* Given decls OLDDECL and NEWDECL, merge their attributes and return
+   the result.  */
+
+tree
+merge_decl_attributes (tree olddecl, tree newdecl)
+{
+  return merge_attributes (DECL_ATTRIBUTES (olddecl),
+			   DECL_ATTRIBUTES (newdecl));
+}
+
+#if TARGET_DLLIMPORT_DECL_ATTRIBUTES
+
+/* Specialization of merge_decl_attributes for various Windows targets.
+
+   This handles the following situation:
+
+     __declspec (dllimport) int foo;
+     int foo;
+
+   The second instance of `foo' nullifies the dllimport.  */
+
+tree
+merge_dllimport_decl_attributes (tree old, tree new_tree)
+{
+  tree a;
+  int delete_dllimport_p = 1;
+
+  /* What we need to do here is remove from `old' dllimport if it doesn't
+     appear in `new'.  dllimport behaves like extern: if a declaration is
+     marked dllimport and a definition appears later, then the object
+     is not dllimport'd.  We also remove a `new' dllimport if the old list
+     contains dllexport:  dllexport always overrides dllimport, regardless
+     of the order of declaration.  */
+  if (!VAR_OR_FUNCTION_DECL_P (new_tree))
+    delete_dllimport_p = 0;
+  else if (DECL_DLLIMPORT_P (new_tree)
+     	   && lookup_attribute ("dllexport", DECL_ATTRIBUTES (old)))
+    {
+      DECL_DLLIMPORT_P (new_tree) = 0;
+      warning (OPT_Wattributes, "%q+D already declared with dllexport "
+	       "attribute: dllimport ignored", new_tree);
+    }
+  else if (DECL_DLLIMPORT_P (old) && !DECL_DLLIMPORT_P (new_tree))
+    {
+      /* Warn about overriding a symbol that has already been used, e.g.:
+	   extern int __attribute__ ((dllimport)) foo;
+	   int* bar () {return &foo;}
+	   int foo;
+      */
+      if (TREE_USED (old))
+	{
+	  warning (0, "%q+D redeclared without dllimport attribute "
+		   "after being referenced with dll linkage", new_tree);
+	  /* If we have used a variable's address with dllimport linkage,
+	      keep the old DECL_DLLIMPORT_P flag: the ADDR_EXPR using the
+	      decl may already have had TREE_CONSTANT computed.
+	      We still remove the attribute so that assembler code refers
+	      to '&foo rather than '_imp__foo'.  */
+	  if (VAR_P (old) && TREE_ADDRESSABLE (old))
+	    DECL_DLLIMPORT_P (new_tree) = 1;
+	}
+
+      /* Let an inline definition silently override the external reference,
+	 but otherwise warn about attribute inconsistency.  */
+      else if (VAR_P (new_tree) || !DECL_DECLARED_INLINE_P (new_tree))
+	warning (OPT_Wattributes, "%q+D redeclared without dllimport "
+		 "attribute: previous dllimport ignored", new_tree);
+    }
+  else
+    delete_dllimport_p = 0;
+
+  a = merge_attributes (DECL_ATTRIBUTES (old), DECL_ATTRIBUTES (new_tree));
+
+  if (delete_dllimport_p)
+    a = remove_attribute ("dllimport", a);
+
+  return a;
+}
+
+/* Handle a "dllimport" or "dllexport" attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+tree
+handle_dll_attribute (tree * pnode, tree name, tree args, int flags,
+		      bool *no_add_attrs)
+{
+  tree node = *pnode;
+  bool is_dllimport;
+
+  /* These attributes may apply to structure and union types being created,
+     but otherwise should pass to the declaration involved.  */
+  if (!DECL_P (node))
+    {
+      if (flags & ((int) ATTR_FLAG_DECL_NEXT | (int) ATTR_FLAG_FUNCTION_NEXT
+		   | (int) ATTR_FLAG_ARRAY_NEXT))
+	{
+	  *no_add_attrs = true;
+	  return tree_cons (name, args, NULL_TREE);
+	}
+      if (TREE_CODE (node) == RECORD_TYPE
+	  || TREE_CODE (node) == UNION_TYPE)
+	{
+	  node = TYPE_NAME (node);
+	  if (!node)
+	    return NULL_TREE;
+	}
+      else
+	{
+	  warning (OPT_Wattributes, "%qE attribute ignored",
+		   name);
+	  *no_add_attrs = true;
+	  return NULL_TREE;
+	}
+    }
+
+  if (!VAR_OR_FUNCTION_DECL_P (node) && TREE_CODE (node) != TYPE_DECL)
+    {
+      *no_add_attrs = true;
+      warning (OPT_Wattributes, "%qE attribute ignored",
+	       name);
+      return NULL_TREE;
+    }
+
+  if (TREE_CODE (node) == TYPE_DECL
+      && TREE_CODE (TREE_TYPE (node)) != RECORD_TYPE
+      && TREE_CODE (TREE_TYPE (node)) != UNION_TYPE)
+    {
+      *no_add_attrs = true;
+      warning (OPT_Wattributes, "%qE attribute ignored",
+	       name);
+      return NULL_TREE;
+    }
+
+  is_dllimport = is_attribute_p ("dllimport", name);
+
+  /* Report error on dllimport ambiguities seen now before they cause
+     any damage.  */
+  if (is_dllimport)
+    {
+      /* Honor any target-specific overrides.  */
+      if (!targetm.valid_dllimport_attribute_p (node))
+	*no_add_attrs = true;
+
+     else if (TREE_CODE (node) == FUNCTION_DECL
+	      && DECL_DECLARED_INLINE_P (node))
+	{
+	  warning (OPT_Wattributes, "inline function %q+D declared as "
+		  " dllimport: attribute ignored", node);
+	  *no_add_attrs = true;
+	}
+      /* Like MS, treat definition of dllimported variables and
+	 non-inlined functions on declaration as syntax errors.  */
+     else if (TREE_CODE (node) == FUNCTION_DECL && DECL_INITIAL (node))
+	{
+	  error ("function %q+D definition is marked dllimport", node);
+	  *no_add_attrs = true;
+	}
+
+     else if (VAR_P (node))
+	{
+	  if (DECL_INITIAL (node))
+	    {
+	      error ("variable %q+D definition is marked dllimport",
+		     node);
+	      *no_add_attrs = true;
+	    }
+
+	  /* `extern' needn't be specified with dllimport.
+	     Specify `extern' now and hope for the best.  Sigh.  */
+	  DECL_EXTERNAL (node) = 1;
+	  /* Also, implicitly give dllimport'd variables declared within
+	     a function global scope, unless declared static.  */
+	  if (current_function_decl != NULL_TREE && !TREE_STATIC (node))
+	    TREE_PUBLIC (node) = 1;
+	}
+
+      if (*no_add_attrs == false)
+	DECL_DLLIMPORT_P (node) = 1;
+    }
+  else if (TREE_CODE (node) == FUNCTION_DECL
+	   && DECL_DECLARED_INLINE_P (node)
+	   && flag_keep_inline_dllexport)
+    /* An exported function, even if inline, must be emitted.  */
+    DECL_EXTERNAL (node) = 0;
+
+  /*  Report error if symbol is not accessible at global scope.  */
+  if (!TREE_PUBLIC (node) && VAR_OR_FUNCTION_DECL_P (node))
+    {
+      error ("external linkage required for symbol %q+D because of "
+	     "%qE attribute", node, name);
+      *no_add_attrs = true;
+    }
+
+  /* A dllexport'd entity must have default visibility so that other
+     program units (shared libraries or the main executable) can see
+     it.  A dllimport'd entity must have default visibility so that
+     the linker knows that undefined references within this program
+     unit can be resolved by the dynamic linker.  */
+  if (!*no_add_attrs)
+    {
+      if (DECL_VISIBILITY_SPECIFIED (node)
+	  && DECL_VISIBILITY (node) != VISIBILITY_DEFAULT)
+	error ("%qE implies default visibility, but %qD has already "
+	       "been declared with a different visibility",
+	       name, node);
+      DECL_VISIBILITY (node) = VISIBILITY_DEFAULT;
+      DECL_VISIBILITY_SPECIFIED (node) = 1;
+    }
+
+  return NULL_TREE;
+}
+
+#endif /* TARGET_DLLIMPORT_DECL_ATTRIBUTES  */
+
+/* Given two lists of attributes, return true if list l2 is
+   equivalent to l1.  */
+
+int
+attribute_list_equal (const_tree l1, const_tree l2)
+{
+  if (l1 == l2)
+    return 1;
+
+  return attribute_list_contained (l1, l2)
+	 && attribute_list_contained (l2, l1);
+}
+
+/* Given two lists of attributes, return true if list L2 is
+   completely contained within L1.  */
+/* ??? This would be faster if attribute names were stored in a canonicalized
+   form.  Otherwise, if L1 uses `foo' and L2 uses `__foo__', the long method
+   must be used to show these elements are equivalent (which they are).  */
+/* ??? It's not clear that attributes with arguments will always be handled
+   correctly.  */
+
+int
+attribute_list_contained (const_tree l1, const_tree l2)
+{
+  const_tree t1, t2;
+
+  /* First check the obvious, maybe the lists are identical.  */
+  if (l1 == l2)
+    return 1;
+
+  /* Maybe the lists are similar.  */
+  for (t1 = l1, t2 = l2;
+       t1 != 0 && t2 != 0
+       && get_attribute_name (t1) == get_attribute_name (t2)
+       && TREE_VALUE (t1) == TREE_VALUE (t2);
+       t1 = TREE_CHAIN (t1), t2 = TREE_CHAIN (t2))
+    ;
+
+  /* Maybe the lists are equal.  */
+  if (t1 == 0 && t2 == 0)
+    return 1;
+
+  for (; t2 != 0; t2 = TREE_CHAIN (t2))
+    {
+      const_tree attr;
+      /* This CONST_CAST is okay because lookup_attribute does not
+	 modify its argument and the return value is assigned to a
+	 const_tree.  */
+      for (attr = lookup_ident_attribute (get_attribute_name (t2),
+					  CONST_CAST_TREE (l1));
+	   attr != NULL_TREE && !attribute_value_equal (t2, attr);
+	   attr = lookup_ident_attribute (get_attribute_name (t2),
+					  TREE_CHAIN (attr)))
+	;
+
+      if (attr == NULL_TREE)
+	return 0;
+    }
+
+  return 1;
+}
diff --git a/gcc/attribs.h b/gcc/attribs.h
index d4a790bb753..06e6993e958 100644
--- a/gcc/attribs.h
+++ b/gcc/attribs.h
@@ -47,6 +47,46 @@ extern char *make_unique_name (tree, const char *, bool);
 extern tree make_dispatcher_decl (const tree);
 extern bool is_function_default_version (const tree);
 
+/* Return a type like TTYPE except that its TYPE_ATTRIBUTES
+   is ATTRIBUTE.
+
+   Such modified types already made are recorded so that duplicates
+   are not made.  */
+
+extern tree build_type_attribute_variant (tree, tree);
+extern tree build_decl_attribute_variant (tree, tree);
+extern tree build_type_attribute_qual_variant (tree, tree, int);
+
+extern bool attribute_value_equal (const_tree, const_tree);
+
+/* Return 0 if the attributes for two types are incompatible, 1 if they
+   are compatible, and 2 if they are nearly compatible (which causes a
+   warning to be generated).  */
+extern int comp_type_attributes (const_tree, const_tree);
+
+/* Default versions of target-overridable functions.  */
+extern tree merge_decl_attributes (tree, tree);
+extern tree merge_type_attributes (tree, tree);
+
+/* Remove any instances of attribute ATTR_NAME in LIST and return the
+   modified list.  */
+
+extern tree remove_attribute (const char *, tree);
+
+/* Given two attributes lists, return a list of their union.  */
+
+extern tree merge_attributes (tree, tree);
+
+/* Given two Windows decl attributes lists, possibly including
+   dllimport, return a list of their union .  */
+extern tree merge_dllimport_decl_attributes (tree, tree);
+
+/* Handle a "dllimport" or "dllexport" attribute.  */
+extern tree handle_dll_attribute (tree *, tree, tree, int, bool *);
+
+extern int attribute_list_equal (const_tree, const_tree);
+extern int attribute_list_contained (const_tree, const_tree);
+
 /* For a given IDENTIFIER_NODE, strip leading and trailing '_' characters
    so that we have a canonical form of attribute names.  */
 
@@ -90,4 +130,77 @@ is_attribute_p (const char *attr_name, const_tree ident)
 		      IDENTIFIER_POINTER (ident), IDENTIFIER_LENGTH (ident));
 }
 
+/* Given an attribute name ATTR_NAME and a list of attributes LIST,
+   return a pointer to the attribute's list element if the attribute
+   is part of the list, or NULL_TREE if not found.  If the attribute
+   appears more than once, this only returns the first occurrence; the
+   TREE_CHAIN of the return value should be passed back in if further
+   occurrences are wanted.  ATTR_NAME must be in the form 'text' (not
+   '__text__').  */
+
+static inline tree
+lookup_attribute (const char *attr_name, tree list)
+{
+  gcc_checking_assert (attr_name[0] != '_');
+  /* In most cases, list is NULL_TREE.  */
+  if (list == NULL_TREE)
+    return NULL_TREE;
+  else
+    {
+      size_t attr_len = strlen (attr_name);
+      /* Do the strlen() before calling the out-of-line implementation.
+	 In most cases attr_name is a string constant, and the compiler
+	 will optimize the strlen() away.  */
+      while (list)
+	{
+	  tree attr = get_attribute_name (list);
+	  size_t ident_len = IDENTIFIER_LENGTH (attr);
+	  if (cmp_attribs (attr_name, attr_len, IDENTIFIER_POINTER (attr),
+			   ident_len))
+	    break;
+	  list = TREE_CHAIN (list);
+	}
+
+      return list;
+    }
+}
+
+/* Given an attribute name ATTR_NAME and a list of attributes LIST,
+   return a pointer to the attribute's list first element if the attribute
+   starts with ATTR_NAME.  ATTR_NAME must be in the form 'text' (not
+   '__text__').  */
+
+static inline tree
+lookup_attribute_by_prefix (const char *attr_name, tree list)
+{
+  gcc_checking_assert (attr_name[0] != '_');
+  /* In most cases, list is NULL_TREE.  */
+  if (list == NULL_TREE)
+    return NULL_TREE;
+  else
+    {
+      size_t attr_len = strlen (attr_name);
+      while (list)
+	{
+	  size_t ident_len = IDENTIFIER_LENGTH (get_attribute_name (list));
+
+	  if (attr_len > ident_len)
+	    {
+	      list = TREE_CHAIN (list);
+	      continue;
+	    }
+
+	  const char *p = IDENTIFIER_POINTER (get_attribute_name (list));
+	  gcc_checking_assert (attr_len == 0 || p[0] != '_');
+
+	  if (strncmp (attr_name, p, attr_len) == 0)
+	    break;
+
+	  list = TREE_CHAIN (list);
+	}
+
+      return list;
+    }
+}
+
 #endif // GCC_ATTRIBS_H
diff --git a/gcc/bb-reorder.c b/gcc/bb-reorder.c
index 3dbae819b1b..4dad298fe59 100644
--- a/gcc/bb-reorder.c
+++ b/gcc/bb-reorder.c
@@ -115,6 +115,8 @@
 #include "bb-reorder.h"
 #include "except.h"
 #include "fibonacci_heap.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* The number of rounds.  In most cases there will only be 4 rounds, but
    when partitioning hot and cold basic blocks into separate sections of
diff --git a/gcc/builtins.c b/gcc/builtins.c
index 016f68d2cb6..fa0f89c8f33 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -60,6 +60,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "langhooks.h"
 #include "value-prof.h"
 #include "builtins.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 #include "cilk.h"
 #include "tree-chkp.h"
diff --git a/gcc/c-family/c-ada-spec.c b/gcc/c-family/c-ada-spec.c
index 6c050fb673b..0cd3d55b55b 100644
--- a/gcc/c-family/c-ada-spec.c
+++ b/gcc/c-family/c-ada-spec.c
@@ -28,6 +28,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "fold-const.h"
 #include "c-pragma.h"
 #include "cpp-id-data.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* Local functions, macros and variables.  */
 static int dump_generic_ada_node (pretty_printer *, tree, tree, int, int,
diff --git a/gcc/c-family/c-ubsan.c b/gcc/c-family/c-ubsan.c
index 541b53009c2..b1386db9c25 100644
--- a/gcc/c-family/c-ubsan.c
+++ b/gcc/c-family/c-ubsan.c
@@ -25,10 +25,12 @@ along with GCC; see the file COPYING3.  If not see
 #include "c-family/c-common.h"
 #include "ubsan.h"
 #include "c-family/c-ubsan.h"
-#include "asan.h"
 #include "stor-layout.h"
 #include "builtins.h"
 #include "gimplify.h"
+#include "stringpool.h"
+#include "attribs.h"
+#include "asan.h"
 
 /* Instrument division by zero and INT_MIN / -1.  If not instrumenting,
    return NULL_TREE.  */
diff --git a/gcc/c-family/c-warn.c b/gcc/c-family/c-warn.c
index e970ab2a00d..9c3073444cf 100644
--- a/gcc/c-family/c-warn.c
+++ b/gcc/c-family/c-warn.c
@@ -28,6 +28,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "tm_p.h"
 #include "diagnostic.h"
 #include "intl.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 #include "gcc-rich-location.h"
 #include "gimplify.h"
diff --git a/gcc/c/c-convert.c b/gcc/c/c-convert.c
index bc649178f4c..8752132d175 100644
--- a/gcc/c/c-convert.c
+++ b/gcc/c/c-convert.c
@@ -31,6 +31,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "convert.h"
 #include "langhooks.h"
 #include "ubsan.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 
 /* Change of width--truncation and extension of integers or reals--
diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
index 71d01350186..321c953e7f1 100644
--- a/gcc/c/c-typeck.c
+++ b/gcc/c/c-typeck.c
@@ -50,6 +50,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "gomp-constants.h"
 #include "spellcheck-tree.h"
 #include "gcc-rich-location.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 
 /* Possible cases of implicit bad conversions.  Used to select
diff --git a/gcc/calls.c b/gcc/calls.c
index 6405f482e91..7599928c7cb 100644
--- a/gcc/calls.c
+++ b/gcc/calls.c
@@ -52,6 +52,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-ssanames.h"
 #include "rtl-chkp.h"
 #include "intl.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* Like PREFERRED_STACK_BOUNDARY but in units of bytes, not bits.  */
 #define STACK_BYTES (PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT)
diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c
index c9d8118ed45..7f0130d0365 100644
--- a/gcc/cfgexpand.c
+++ b/gcc/cfgexpand.c
@@ -68,6 +68,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-outof-ssa.h"
 #include "cfgloop.h"
 #include "insn-attr.h" /* For INSN_SCHEDULING.  */
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 #include "tree-ssa-address.h"
 #include "output.h"
diff --git a/gcc/cgraph.c b/gcc/cgraph.c
index d7c9ba61795..c6ab7e38ff6 100644
--- a/gcc/cgraph.c
+++ b/gcc/cgraph.c
@@ -61,6 +61,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-chkp.h"
 #include "context.h"
 #include "gimplify.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* FIXME: Only for PROP_loops, but cgraph shouldn't have to know about this.  */
 #include "tree-pass.h"
diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c
index 6072c567bc3..e8cc765095d 100644
--- a/gcc/cgraphunit.c
+++ b/gcc/cgraphunit.c
@@ -204,6 +204,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "dbgcnt.h"
 #include "tree-chkp.h"
 #include "lto-section-names.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* Queue of cgraph nodes scheduled to be added into cgraph.  This is a
    secondary queue used during optimization to accommodate passes that
diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c
index 79a396ec674..28c4e0e6476 100644
--- a/gcc/config/aarch64/aarch64.c
+++ b/gcc/config/aarch64/aarch64.c
@@ -33,6 +33,7 @@
 #include "df.h"
 #include "tm_p.h"
 #include "stringpool.h"
+#include "attribs.h"
 #include "optabs.h"
 #include "regs.h"
 #include "emit-rtl.h"
diff --git a/gcc/config/alpha/alpha.c b/gcc/config/alpha/alpha.c
index 341ec20d340..e13c5f9fc57 100644
--- a/gcc/config/alpha/alpha.c
+++ b/gcc/config/alpha/alpha.c
@@ -26,6 +26,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "target.h"
 #include "rtl.h"
 #include "tree.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "memmodel.h"
 #include "gimple.h"
 #include "df.h"
diff --git a/gcc/config/arc/arc.c b/gcc/config/arc/arc.c
index be5f1bd2003..057f8756fba 100644
--- a/gcc/config/arc/arc.c
+++ b/gcc/config/arc/arc.c
@@ -40,6 +40,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "df.h"
 #include "tm_p.h"
 #include "stringpool.h"
+#include "attribs.h"
 #include "optabs.h"
 #include "regs.h"
 #include "emit-rtl.h"
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index 25677d19e20..fa3e2fa6c76 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -32,6 +32,7 @@
 #include "df.h"
 #include "tm_p.h"
 #include "stringpool.h"
+#include "attribs.h"
 #include "optabs.h"
 #include "regs.h"
 #include "emit-rtl.h"
diff --git a/gcc/config/avr/avr.c b/gcc/config/avr/avr.c
index 1f333ccc1b2..e453bfb6814 100644
--- a/gcc/config/avr/avr.c
+++ b/gcc/config/avr/avr.c
@@ -26,6 +26,8 @@
 #include "target.h"
 #include "rtl.h"
 #include "tree.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "cgraph.h"
 #include "c-family/c-common.h"
 #include "cfghooks.h"
diff --git a/gcc/config/bfin/bfin.c b/gcc/config/bfin/bfin.c
index 9fe90fc37b4..f04fe874777 100644
--- a/gcc/config/bfin/bfin.c
+++ b/gcc/config/bfin/bfin.c
@@ -25,6 +25,8 @@
 #include "target.h"
 #include "rtl.h"
 #include "tree.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "cfghooks.h"
 #include "df.h"
 #include "memmodel.h"
diff --git a/gcc/config/c6x/c6x.c b/gcc/config/c6x/c6x.c
index 4529fd44aae..a7083c12898 100644
--- a/gcc/config/c6x/c6x.c
+++ b/gcc/config/c6x/c6x.c
@@ -32,6 +32,7 @@
 #include "memmodel.h"
 #include "tm_p.h"
 #include "stringpool.h"
+#include "attribs.h"
 #include "optabs.h"
 #include "regs.h"
 #include "emit-rtl.h"
diff --git a/gcc/config/cr16/cr16.c b/gcc/config/cr16/cr16.c
index 93edd232af2..ab6ef7adf1d 100644
--- a/gcc/config/cr16/cr16.c
+++ b/gcc/config/cr16/cr16.c
@@ -25,6 +25,8 @@
 #include "target.h"
 #include "rtl.h"
 #include "tree.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "df.h"
 #include "memmodel.h"
 #include "tm_p.h"
diff --git a/gcc/config/cris/cris.c b/gcc/config/cris/cris.c
index 8c134a6bc8b..b57881ac04e 100644
--- a/gcc/config/cris/cris.c
+++ b/gcc/config/cris/cris.c
@@ -25,6 +25,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "target.h"
 #include "rtl.h"
 #include "tree.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "cfghooks.h"
 #include "df.h"
 #include "memmodel.h"
diff --git a/gcc/config/darwin.c b/gcc/config/darwin.c
index 9a8cf31d400..949db25c650 100644
--- a/gcc/config/darwin.c
+++ b/gcc/config/darwin.c
@@ -31,6 +31,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "memmodel.h"
 #include "tm_p.h"
 #include "stringpool.h"
+#include "attribs.h"
 #include "insn-config.h"
 #include "emit-rtl.h"
 #include "cgraph.h"
diff --git a/gcc/config/epiphany/epiphany.c b/gcc/config/epiphany/epiphany.c
index b9ec0f40d12..4e27557d3ce 100644
--- a/gcc/config/epiphany/epiphany.c
+++ b/gcc/config/epiphany/epiphany.c
@@ -29,6 +29,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "memmodel.h"
 #include "tm_p.h"
 #include "stringpool.h"
+#include "attribs.h"
 #include "optabs.h"
 #include "emit-rtl.h"
 #include "recog.h"
diff --git a/gcc/config/fr30/fr30.c b/gcc/config/fr30/fr30.c
index 42bec9f733c..d83b2f31daa 100644
--- a/gcc/config/fr30/fr30.c
+++ b/gcc/config/fr30/fr30.c
@@ -27,6 +27,8 @@
 #include "target.h"
 #include "rtl.h"
 #include "tree.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "df.h"
 #include "memmodel.h"
 #include "emit-rtl.h"
diff --git a/gcc/config/frv/frv.c b/gcc/config/frv/frv.c
index c571d63f2c6..1cdbaa81c8d 100644
--- a/gcc/config/frv/frv.c
+++ b/gcc/config/frv/frv.c
@@ -28,6 +28,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "memmodel.h"
 #include "tm_p.h"
 #include "stringpool.h"
+#include "attribs.h"
 #include "optabs.h"
 #include "regs.h"
 #include "emit-rtl.h"
diff --git a/gcc/config/ft32/ft32.c b/gcc/config/ft32/ft32.c
index db0365e92c1..78c5edc8f09 100644
--- a/gcc/config/ft32/ft32.c
+++ b/gcc/config/ft32/ft32.c
@@ -25,6 +25,8 @@
 #include "target.h"
 #include "rtl.h"
 #include "tree.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "df.h"
 #include "memmodel.h"
 #include "tm_p.h"
diff --git a/gcc/config/h8300/h8300.c b/gcc/config/h8300/h8300.c
index acdededeccc..0e0bb57768d 100644
--- a/gcc/config/h8300/h8300.c
+++ b/gcc/config/h8300/h8300.c
@@ -30,6 +30,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "memmodel.h"
 #include "tm_p.h"
 #include "stringpool.h"
+#include "attribs.h"
 #include "optabs.h"
 #include "regs.h"
 #include "emit-rtl.h"
diff --git a/gcc/config/i386/winnt.c b/gcc/config/i386/winnt.c
index 8272c7fddc1..405f74a7597 100644
--- a/gcc/config/i386/winnt.c
+++ b/gcc/config/i386/winnt.c
@@ -30,6 +30,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "memmodel.h"
 #include "tm_p.h"
 #include "stringpool.h"
+#include "attribs.h"
 #include "emit-rtl.h"
 #include "cgraph.h"
 #include "lto-streamer.h"
diff --git a/gcc/config/ia64/ia64.c b/gcc/config/ia64/ia64.c
index c8e4c74bbdb..79c323f67ee 100644
--- a/gcc/config/ia64/ia64.c
+++ b/gcc/config/ia64/ia64.c
@@ -31,6 +31,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "df.h"
 #include "tm_p.h"
 #include "stringpool.h"
+#include "attribs.h"
 #include "optabs.h"
 #include "regs.h"
 #include "emit-rtl.h"
diff --git a/gcc/config/iq2000/iq2000.c b/gcc/config/iq2000/iq2000.c
index 99abd76c5a6..5a92164ef05 100644
--- a/gcc/config/iq2000/iq2000.c
+++ b/gcc/config/iq2000/iq2000.c
@@ -24,6 +24,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "target.h"
 #include "rtl.h"
 #include "tree.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "df.h"
 #include "memmodel.h"
 #include "tm_p.h"
diff --git a/gcc/config/lm32/lm32.c b/gcc/config/lm32/lm32.c
index 2231412e566..214cc0ac5fd 100644
--- a/gcc/config/lm32/lm32.c
+++ b/gcc/config/lm32/lm32.c
@@ -26,6 +26,8 @@
 #include "target.h"
 #include "rtl.h"
 #include "tree.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "df.h"
 #include "memmodel.h"
 #include "tm_p.h"
diff --git a/gcc/config/m32r/m32r.c b/gcc/config/m32r/m32r.c
index 4efb4b9c287..d7893d7550a 100644
--- a/gcc/config/m32r/m32r.c
+++ b/gcc/config/m32r/m32r.c
@@ -28,6 +28,7 @@
 #include "memmodel.h"
 #include "tm_p.h"
 #include "stringpool.h"
+#include "attribs.h"
 #include "insn-config.h"
 #include "emit-rtl.h"
 #include "recog.h"
diff --git a/gcc/config/m68k/m68k.c b/gcc/config/m68k/m68k.c
index c14ce86d810..89726655122 100644
--- a/gcc/config/m68k/m68k.c
+++ b/gcc/config/m68k/m68k.c
@@ -23,6 +23,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "backend.h"
 #include "cfghooks.h"
 #include "tree.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "rtl.h"
 #include "df.h"
 #include "alias.h"
diff --git a/gcc/config/mcore/mcore.c b/gcc/config/mcore/mcore.c
index c4b7c4cf94f..e67376fb6aa 100644
--- a/gcc/config/mcore/mcore.c
+++ b/gcc/config/mcore/mcore.c
@@ -28,6 +28,7 @@
 #include "memmodel.h"
 #include "tm_p.h"
 #include "stringpool.h"
+#include "attribs.h"
 #include "emit-rtl.h"
 #include "diagnostic-core.h"
 #include "stor-layout.h"
diff --git a/gcc/config/microblaze/microblaze.c b/gcc/config/microblaze/microblaze.c
index 15ceac0b346..2cdd24056a5 100644
--- a/gcc/config/microblaze/microblaze.c
+++ b/gcc/config/microblaze/microblaze.c
@@ -26,6 +26,8 @@
 #include "target.h"
 #include "rtl.h"
 #include "tree.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "df.h"
 #include "memmodel.h"
 #include "tm_p.h"
diff --git a/gcc/config/mmix/mmix.c b/gcc/config/mmix/mmix.c
index 9849c19e076..6ca2fd9441c 100644
--- a/gcc/config/mmix/mmix.c
+++ b/gcc/config/mmix/mmix.c
@@ -25,6 +25,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "target.h"
 #include "rtl.h"
 #include "tree.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "df.h"
 #include "memmodel.h"
 #include "tm_p.h"
diff --git a/gcc/config/mn10300/mn10300.c b/gcc/config/mn10300/mn10300.c
index 301207fa66a..f46caac7e94 100644
--- a/gcc/config/mn10300/mn10300.c
+++ b/gcc/config/mn10300/mn10300.c
@@ -25,6 +25,8 @@
 #include "target.h"
 #include "rtl.h"
 #include "tree.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "cfghooks.h"
 #include "cfgloop.h"
 #include "df.h"
diff --git a/gcc/config/moxie/moxie.c b/gcc/config/moxie/moxie.c
index 70d6d7e2eaf..19cd83f5193 100644
--- a/gcc/config/moxie/moxie.c
+++ b/gcc/config/moxie/moxie.c
@@ -25,6 +25,8 @@
 #include "target.h"
 #include "rtl.h"
 #include "tree.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "df.h"
 #include "regs.h"
 #include "memmodel.h"
diff --git a/gcc/config/msp430/msp430.c b/gcc/config/msp430/msp430.c
index 6acab1e70cb..1ab79a722ed 100644
--- a/gcc/config/msp430/msp430.c
+++ b/gcc/config/msp430/msp430.c
@@ -25,6 +25,8 @@
 #include "target.h"
 #include "rtl.h"
 #include "tree.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "gimple-expr.h"
 #include "df.h"
 #include "memmodel.h"
diff --git a/gcc/config/nds32/nds32-isr.c b/gcc/config/nds32/nds32-isr.c
index 29e94d004c6..7d7b9e27ca6 100644
--- a/gcc/config/nds32/nds32-isr.c
+++ b/gcc/config/nds32/nds32-isr.c
@@ -27,6 +27,8 @@
 #include "target.h"
 #include "rtl.h"
 #include "tree.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "diagnostic-core.h"
 #include "output.h"
 
diff --git a/gcc/config/nds32/nds32.c b/gcc/config/nds32/nds32.c
index 705d223e496..14310de8672 100644
--- a/gcc/config/nds32/nds32.c
+++ b/gcc/config/nds32/nds32.c
@@ -27,6 +27,8 @@
 #include "target.h"
 #include "rtl.h"
 #include "tree.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "df.h"
 #include "memmodel.h"
 #include "tm_p.h"
diff --git a/gcc/config/nios2/nios2.c b/gcc/config/nios2/nios2.c
index 2fc9a080402..884b1dc367e 100644
--- a/gcc/config/nios2/nios2.c
+++ b/gcc/config/nios2/nios2.c
@@ -27,6 +27,8 @@
 #include "target.h"
 #include "rtl.h"
 #include "tree.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "df.h"
 #include "memmodel.h"
 #include "tm_p.h"
diff --git a/gcc/config/nvptx/nvptx.c b/gcc/config/nvptx/nvptx.c
index dddb9522dfa..ffd50d781f0 100644
--- a/gcc/config/nvptx/nvptx.c
+++ b/gcc/config/nvptx/nvptx.c
@@ -62,6 +62,7 @@
 #include "internal-fn.h"
 #include "gimple-iterator.h"
 #include "stringpool.h"
+#include "attribs.h"
 #include "tree-vrp.h"
 #include "tree-ssa-operands.h"
 #include "tree-ssanames.h"
diff --git a/gcc/config/pa/pa.c b/gcc/config/pa/pa.c
index 2a78018650c..52f76cfd5f1 100644
--- a/gcc/config/pa/pa.c
+++ b/gcc/config/pa/pa.c
@@ -29,6 +29,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "df.h"
 #include "tm_p.h"
 #include "stringpool.h"
+#include "attribs.h"
 #include "optabs.h"
 #include "regs.h"
 #include "emit-rtl.h"
diff --git a/gcc/config/pdp11/pdp11.c b/gcc/config/pdp11/pdp11.c
index c2ce6e8abe5..fbbb34390f4 100644
--- a/gcc/config/pdp11/pdp11.c
+++ b/gcc/config/pdp11/pdp11.c
@@ -25,6 +25,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "target.h"
 #include "rtl.h"
 #include "tree.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "df.h"
 #include "memmodel.h"
 #include "tm_p.h"
diff --git a/gcc/config/powerpcspe/powerpcspe.c b/gcc/config/powerpcspe/powerpcspe.c
index b94afd5ca2e..f2840894fc1 100644
--- a/gcc/config/powerpcspe/powerpcspe.c
+++ b/gcc/config/powerpcspe/powerpcspe.c
@@ -31,6 +31,7 @@
 #include "df.h"
 #include "tm_p.h"
 #include "stringpool.h"
+#include "attribs.h"
 #include "expmed.h"
 #include "optabs.h"
 #include "regs.h"
diff --git a/gcc/config/riscv/riscv.c b/gcc/config/riscv/riscv.c
index 57b2edbcb43..cbf2f79bc4d 100644
--- a/gcc/config/riscv/riscv.c
+++ b/gcc/config/riscv/riscv.c
@@ -31,6 +31,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "output.h"
 #include "alias.h"
 #include "tree.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "varasm.h"
 #include "stor-layout.h"
 #include "calls.h"
diff --git a/gcc/config/rx/rx.c b/gcc/config/rx/rx.c
index 9d512b8959b..daae27b404a 100644
--- a/gcc/config/rx/rx.c
+++ b/gcc/config/rx/rx.c
@@ -29,6 +29,8 @@
 #include "target.h"
 #include "rtl.h"
 #include "tree.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "cfghooks.h"
 #include "df.h"
 #include "memmodel.h"
diff --git a/gcc/config/s390/s390.c b/gcc/config/s390/s390.c
index 9f422c88a99..deced953d75 100644
--- a/gcc/config/s390/s390.c
+++ b/gcc/config/s390/s390.c
@@ -35,6 +35,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "memmodel.h"
 #include "tm_p.h"
 #include "stringpool.h"
+#include "attribs.h"
 #include "expmed.h"
 #include "optabs.h"
 #include "regs.h"
diff --git a/gcc/config/sol2.c b/gcc/config/sol2.c
index cdabf24e24b..b8ef3409942 100644
--- a/gcc/config/sol2.c
+++ b/gcc/config/sol2.c
@@ -27,6 +27,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "memmodel.h"
 #include "tm_p.h"
 #include "stringpool.h"
+#include "attribs.h"
 #include "diagnostic-core.h"
 #include "varasm.h"
 #include "output.h"
diff --git a/gcc/config/sparc/sparc.c b/gcc/config/sparc/sparc.c
index 59761aac310..d494ecf2410 100644
--- a/gcc/config/sparc/sparc.c
+++ b/gcc/config/sparc/sparc.c
@@ -32,6 +32,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "df.h"
 #include "tm_p.h"
 #include "stringpool.h"
+#include "attribs.h"
 #include "expmed.h"
 #include "optabs.h"
 #include "regs.h"
diff --git a/gcc/config/spu/spu.c b/gcc/config/spu/spu.c
index ec20bd60e67..b6d03d7afd4 100644
--- a/gcc/config/spu/spu.c
+++ b/gcc/config/spu/spu.c
@@ -28,6 +28,7 @@
 #include "memmodel.h"
 #include "tm_p.h"
 #include "stringpool.h"
+#include "attribs.h"
 #include "expmed.h"
 #include "optabs.h"
 #include "regs.h"
diff --git a/gcc/config/stormy16/stormy16.c b/gcc/config/stormy16/stormy16.c
index aee7742de89..1a362524e8d 100644
--- a/gcc/config/stormy16/stormy16.c
+++ b/gcc/config/stormy16/stormy16.c
@@ -25,6 +25,8 @@
 #include "target.h"
 #include "rtl.h"
 #include "tree.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "gimple.h"
 #include "df.h"
 #include "memmodel.h"
diff --git a/gcc/config/tilegx/tilegx.c b/gcc/config/tilegx/tilegx.c
index dafb49daf1f..81559acfce0 100644
--- a/gcc/config/tilegx/tilegx.c
+++ b/gcc/config/tilegx/tilegx.c
@@ -30,6 +30,7 @@
 #include "df.h"
 #include "tm_p.h"
 #include "stringpool.h"
+#include "attribs.h"
 #include "expmed.h"
 #include "optabs.h"
 #include "regs.h"
diff --git a/gcc/config/tilepro/tilepro.c b/gcc/config/tilepro/tilepro.c
index 80475b959ee..f03f0670ce9 100644
--- a/gcc/config/tilepro/tilepro.c
+++ b/gcc/config/tilepro/tilepro.c
@@ -30,6 +30,7 @@
 #include "memmodel.h"
 #include "tm_p.h"
 #include "stringpool.h"
+#include "attribs.h"
 #include "expmed.h"
 #include "optabs.h"
 #include "regs.h"
diff --git a/gcc/config/vax/vax.c b/gcc/config/vax/vax.c
index 864eaeb8531..fad4849bc5a 100644
--- a/gcc/config/vax/vax.c
+++ b/gcc/config/vax/vax.c
@@ -24,6 +24,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "target.h"
 #include "rtl.h"
 #include "tree.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "df.h"
 #include "memmodel.h"
 #include "tm_p.h"
diff --git a/gcc/config/visium/visium.c b/gcc/config/visium/visium.c
index e5d843e8d4c..2c5b6734ae0 100644
--- a/gcc/config/visium/visium.c
+++ b/gcc/config/visium/visium.c
@@ -30,6 +30,7 @@
 #include "memmodel.h"
 #include "tm_p.h"
 #include "stringpool.h"
+#include "attribs.h"
 #include "expmed.h"
 #include "optabs.h"
 #include "regs.h"
diff --git a/gcc/config/xtensa/xtensa.c b/gcc/config/xtensa/xtensa.c
index cf9a3a79388..7c36e68b251 100644
--- a/gcc/config/xtensa/xtensa.c
+++ b/gcc/config/xtensa/xtensa.c
@@ -31,6 +31,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "memmodel.h"
 #include "tm_p.h"
 #include "stringpool.h"
+#include "attribs.h"
 #include "optabs.h"
 #include "regs.h"
 #include "emit-rtl.h"
diff --git a/gcc/convert.c b/gcc/convert.c
index 58d8054a724..b1a53afb811 100644
--- a/gcc/convert.c
+++ b/gcc/convert.c
@@ -33,6 +33,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "langhooks.h"
 #include "builtins.h"
 #include "ubsan.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 
 #define maybe_fold_build1_loc(FOLD_P, LOC, CODE, TYPE, EXPR) \
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index f633fa5ad91..fdd373116e0 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -39,6 +39,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "langhooks.h"
 #include "c-family/c-objc.h"
 #include "internal-fn.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* The various kinds of conversion.  */
 
diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c
index a9563b1a8cd..528e38816d3 100644
--- a/gcc/cp/cp-gimplify.c
+++ b/gcc/cp/cp-gimplify.c
@@ -33,6 +33,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "c-family/c-ubsan.h"
 #include "cilk.h"
 #include "cp-cilkplus.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 
 /* Forward declarations.  */
diff --git a/gcc/cp/cp-ubsan.c b/gcc/cp/cp-ubsan.c
index 3be607c0a42..cd2b60ad488 100644
--- a/gcc/cp/cp-ubsan.c
+++ b/gcc/cp/cp-ubsan.c
@@ -23,6 +23,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "coretypes.h"
 #include "cp-tree.h"
 #include "ubsan.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 
 /* Test if we should instrument vptr access.  */
diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c
index 631ff49673f..fd758d3c2dc 100644
--- a/gcc/cp/cvt.c
+++ b/gcc/cp/cvt.c
@@ -33,6 +33,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "flags.h"
 #include "intl.h"
 #include "convert.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 static tree convert_to_pointer_force (tree, tree, tsubst_flags_t);
 static tree build_type_conversion (tree, tree);
diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index 3fe8f18b2a9..81804112fd0 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -30,6 +30,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "gimplify.h"
 #include "c-family/c-ubsan.h"
 #include "intl.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 
 static bool begin_init_stmts (tree *, tree *);
diff --git a/gcc/cp/search.c b/gcc/cp/search.c
index 469a88b4c6f..ced82da6117 100644
--- a/gcc/cp/search.c
+++ b/gcc/cp/search.c
@@ -28,6 +28,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "intl.h"
 #include "toplev.h"
 #include "spellcheck-tree.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 static int is_subobject_of_p (tree, tree);
 static tree dfs_lookup_base (tree, void *);
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index f56d00fd8f3..5401e78fbc6 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -40,6 +40,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-iterator.h"
 #include "omp-general.h"
 #include "convert.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "gomp-constants.h"
 #include "predict.h"
 
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index a58de1d6206..074dae2dfee 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -37,6 +37,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "c-family/c-ubsan.h"
 #include "params.h"
 #include "gcc-rich-location.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 
 static tree cp_build_addr_expr_strict (tree, tsubst_flags_t);
diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index 4a3b3c1d0f4..8e422279a61 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -92,6 +92,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-dfa.h"
 #include "gdb/gdb-index.h"
 #include "rtl-iter.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 static void dwarf2out_source_line (unsigned int, unsigned int, const char *,
 				   int, bool);
diff --git a/gcc/final.c b/gcc/final.c
index 2a24f4fe102..ad999f77fdd 100644
--- a/gcc/final.c
+++ b/gcc/final.c
@@ -76,6 +76,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-ssa.h"
 #include "cfgloop.h"
 #include "params.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 #include "rtl-iter.h"
 #include "print-rtl.h"
diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index 8eaea6cce3a..5a118ca50a1 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -79,6 +79,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-vrp.h"
 #include "tree-ssanames.h"
 #include "selftest.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* Nonzero if we are folding constants inside an initializer; zero
    otherwise.  */
diff --git a/gcc/fortran/trans-types.c b/gcc/fortran/trans-types.c
index 8617cd51a7c..76ee97b81c0 100644
--- a/gcc/fortran/trans-types.c
+++ b/gcc/fortran/trans-types.c
@@ -36,6 +36,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "trans-types.h"
 #include "trans-const.h"
 #include "dwarf2out.h"	/* For struct array_descr_info.  */
+#include "attribs.h"
 \f
 
 #if (GFC_MAX_DIMENSIONS < 10)
diff --git a/gcc/function.c b/gcc/function.c
index 86f14847cfa..20c287bc8e0 100644
--- a/gcc/function.c
+++ b/gcc/function.c
@@ -77,6 +77,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "rtl-chkp.h"
 #include "tree-dfa.h"
 #include "tree-ssa.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* So we can assign to cfun in this file.  */
 #undef cfun
diff --git a/gcc/gimple-expr.c b/gcc/gimple-expr.c
index 13e55ef55fe..c1771fcf1d0 100644
--- a/gcc/gimple-expr.c
+++ b/gcc/gimple-expr.c
@@ -35,6 +35,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "hash-set.h"
 #include "rtl.h"
 #include "tree-pass.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* ----- Type related -----  */
 
diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c
index d82d0606cbe..251446c5b82 100644
--- a/gcc/gimple-fold.c
+++ b/gcc/gimple-fold.c
@@ -56,6 +56,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "ipa-chkp.h"
 #include "tree-cfg.h"
 #include "fold-const-call.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 
 /* Return true when DECL can be referenced from current unit.
diff --git a/gcc/gimple-pretty-print.c b/gcc/gimple-pretty-print.c
index 8b69b72e9e2..5727d14777a 100644
--- a/gcc/gimple-pretty-print.c
+++ b/gcc/gimple-pretty-print.c
@@ -38,6 +38,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "value-prof.h"
 #include "trans-mem.h"
 #include "cfganal.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 
 #define INDENT(SPACE)							\
diff --git a/gcc/gimple.c b/gcc/gimple.c
index 3a32b530cce..c4e6f8176b9 100644
--- a/gcc/gimple.c
+++ b/gcc/gimple.c
@@ -41,6 +41,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "builtins.h"
 #include "selftest.h"
 #include "gimple-pretty-print.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 
 
diff --git a/gcc/gimplify.c b/gcc/gimplify.c
index ed2ec646da2..86623e09f5d 100644
--- a/gcc/gimplify.c
+++ b/gcc/gimplify.c
@@ -60,6 +60,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "gimple-walk.h"
 #include "langhooks-def.h"	/* FIXME: for lhd_set_decl_assembler_name */
 #include "builtins.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 #include "dbgcnt.h"
 
diff --git a/gcc/hsa-common.c b/gcc/hsa-common.c
index 95636ebc9a8..c8c12afb04c 100644
--- a/gcc/hsa-common.c
+++ b/gcc/hsa-common.c
@@ -40,6 +40,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "internal-fn.h"
 #include "ctype.h"
 #include "builtins.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* Structure containing intermediate HSA representation of the generated
    function.  */
diff --git a/gcc/hsa-gen.c b/gcc/hsa-gen.c
index 6ec8c348eb4..bd227626e83 100644
--- a/gcc/hsa-gen.c
+++ b/gcc/hsa-gen.c
@@ -60,6 +60,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "internal-fn.h"
 #include "builtins.h"
 #include "stor-layout.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* Print a warning message and set that we have seen an error.  */
 
diff --git a/gcc/internal-fn.c b/gcc/internal-fn.c
index e24ed169515..2b72367a1d3 100644
--- a/gcc/internal-fn.c
+++ b/gcc/internal-fn.c
@@ -39,6 +39,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "stor-layout.h"
 #include "dojump.h"
 #include "expr.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 #include "ubsan.h"
 #include "recog.h"
diff --git a/gcc/ipa-chkp.c b/gcc/ipa-chkp.c
index 753673c8f66..704ef6e4550 100644
--- a/gcc/ipa-chkp.c
+++ b/gcc/ipa-chkp.c
@@ -34,6 +34,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-chkp.h"
 #include "tree-inline.h"
 #include "ipa-chkp.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /*  Pointer Bounds Checker has two IPA passes to support code instrumentation.
 
diff --git a/gcc/ipa-cp.c b/gcc/ipa-cp.c
index 3b9eab41672..6b3d8d7364c 100644
--- a/gcc/ipa-cp.c
+++ b/gcc/ipa-cp.c
@@ -122,6 +122,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "ipa-fnsummary.h"
 #include "ipa-utils.h"
 #include "tree-ssa-ccp.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 template <typename valtype> class ipcp_value;
 
diff --git a/gcc/ipa-devirt.c b/gcc/ipa-devirt.c
index 9781acd0766..f0aecfbc455 100644
--- a/gcc/ipa-devirt.c
+++ b/gcc/ipa-devirt.c
@@ -129,6 +129,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "dbgcnt.h"
 #include "gimple-pretty-print.h"
 #include "intl.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* Hash based set of pairs of types.  */
 struct type_pair
diff --git a/gcc/ipa-fnsummary.c b/gcc/ipa-fnsummary.c
index 27e8d73f9df..076ccd40bd7 100644
--- a/gcc/ipa-fnsummary.c
+++ b/gcc/ipa-fnsummary.c
@@ -82,6 +82,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "cilk.h"
 #include "cfgexpand.h"
 #include "gimplify.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* Summaries.  */
 function_summary <ipa_fn_summary *> *ipa_fn_summaries;
diff --git a/gcc/ipa-inline.c b/gcc/ipa-inline.c
index 608db8f8857..dd46cb61362 100644
--- a/gcc/ipa-inline.c
+++ b/gcc/ipa-inline.c
@@ -117,6 +117,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "auto-profile.h"
 #include "builtins.h"
 #include "fibonacci_heap.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 
 typedef fibonacci_heap <sreal, cgraph_edge> edge_heap_t;
diff --git a/gcc/ipa-visibility.c b/gcc/ipa-visibility.c
index 3033f20e3f1..998024893a5 100644
--- a/gcc/ipa-visibility.c
+++ b/gcc/ipa-visibility.c
@@ -84,6 +84,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "calls.h"
 #include "varasm.h"
 #include "ipa-utils.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* Return true when NODE can not be local. Worker for cgraph_local_node_p.  */
 
diff --git a/gcc/ipa.c b/gcc/ipa.c
index 00cd3084f66..16df4cacedd 100644
--- a/gcc/ipa.c
+++ b/gcc/ipa.c
@@ -37,7 +37,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "ipa-fnsummary.h"
 #include "dbgcnt.h"
 #include "debug.h"
-
+#include "stringpool.h"
+#include "attribs.h"
 
 /* Return true when NODE has ADDR reference.  */
 
diff --git a/gcc/lto-cgraph.c b/gcc/lto-cgraph.c
index e2680277bb5..15f0eaadf20 100644
--- a/gcc/lto-cgraph.c
+++ b/gcc/lto-cgraph.c
@@ -38,6 +38,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "ipa-utils.h"
 #include "omp-offload.h"
 #include "ipa-chkp.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* True when asm nodes has been output.  */
 bool asm_nodes_output = false;
diff --git a/gcc/lto/lto-lang.c b/gcc/lto/lto-lang.c
index 6e9a138fa3b..375cdd1a90b 100644
--- a/gcc/lto/lto-lang.c
+++ b/gcc/lto/lto-lang.c
@@ -35,6 +35,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "lto-tree.h"
 #include "lto.h"
 #include "cilk.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 static tree handle_noreturn_attribute (tree *, tree, tree, int, bool *);
 static tree handle_leaf_attribute (tree *, tree, tree, int, bool *);
diff --git a/gcc/lto/lto-symtab.c b/gcc/lto/lto-symtab.c
index 019677eaf95..70190d0fda2 100644
--- a/gcc/lto/lto-symtab.c
+++ b/gcc/lto/lto-symtab.c
@@ -32,6 +32,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "builtins.h"
 #include "alias.h"
 #include "lto-symtab.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* Replace the cgraph node NODE with PREVAILING_NODE in the cgraph, merging
    all edges and removing the old node.  */
diff --git a/gcc/objc/objc-gnu-runtime-abi-01.c b/gcc/objc/objc-gnu-runtime-abi-01.c
index d1686e659bd..b53d1820db3 100644
--- a/gcc/objc/objc-gnu-runtime-abi-01.c
+++ b/gcc/objc/objc-gnu-runtime-abi-01.c
@@ -22,7 +22,9 @@ along with GCC; see the file COPYING3.  If not see
 #include "system.h"
 #include "coretypes.h"
 #include "options.h"
+#include "tree.h"
 #include "stringpool.h"
+#include "attribs.h"
 
 #ifdef OBJCPLUS
 #include "cp/cp-tree.h"
diff --git a/gcc/objc/objc-next-runtime-abi-01.c b/gcc/objc/objc-next-runtime-abi-01.c
index 7aff7883f21..686d9285482 100644
--- a/gcc/objc/objc-next-runtime-abi-01.c
+++ b/gcc/objc/objc-next-runtime-abi-01.c
@@ -26,7 +26,9 @@ along with GCC; see the file COPYING3.  If not see
 #include "config.h"
 #include "system.h"
 #include "coretypes.h"
+#include "tree.h"
 #include "stringpool.h"
+#include "attribs.h"
 
 #ifdef OBJCPLUS
 #include "cp/cp-tree.h"
diff --git a/gcc/objc/objc-next-runtime-abi-02.c b/gcc/objc/objc-next-runtime-abi-02.c
index 97314860e01..a2245a4c339 100644
--- a/gcc/objc/objc-next-runtime-abi-02.c
+++ b/gcc/objc/objc-next-runtime-abi-02.c
@@ -28,7 +28,9 @@ along with GCC; see the file COPYING3.  If not see
 #include "config.h"
 #include "system.h"
 #include "coretypes.h"
+#include "tree.h"
 #include "stringpool.h"
+#include "attribs.h"
 
 #ifdef OBJCPLUS
 #include "cp/cp-tree.h"
diff --git a/gcc/omp-expand.c b/gcc/omp-expand.c
index 0f635070a21..ac83ba168d2 100644
--- a/gcc/omp-expand.c
+++ b/gcc/omp-expand.c
@@ -58,7 +58,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "gimple-pretty-print.h"
 #include "hsa-common.h"
 #include "debug.h"
-
+#include "stringpool.h"
+#include "attribs.h"
 
 /* OMP region information.  Every parallel and workshare
    directive is enclosed between two markers, the OMP_* directive
diff --git a/gcc/omp-general.c b/gcc/omp-general.c
index ed94668559b..af955bce783 100644
--- a/gcc/omp-general.c
+++ b/gcc/omp-general.c
@@ -33,7 +33,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "fold-const.h"
 #include "langhooks.h"
 #include "omp-general.h"
-
+#include "stringpool.h"
+#include "attribs.h"
 
 tree
 omp_find_clause (tree clauses, enum omp_clause_code kind)
diff --git a/gcc/omp-low.c b/gcc/omp-low.c
index 2e0973e06d1..3df60561d5b 100644
--- a/gcc/omp-low.c
+++ b/gcc/omp-low.c
@@ -58,6 +58,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "gomp-constants.h"
 #include "gimple-pretty-print.h"
 #include "hsa-common.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* Lowering of OMP parallel and workshare constructs proceeds in two
    phases.  The first phase scans the function looking for OMP statements
diff --git a/gcc/omp-offload.c b/gcc/omp-offload.c
index 54a4e90f70c..2d4fd411680 100644
--- a/gcc/omp-offload.c
+++ b/gcc/omp-offload.c
@@ -49,6 +49,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "gomp-constants.h"
 #include "gimple-pretty-print.h"
 #include "intl.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* Describe the OpenACC looping structure of a function.  The entire
    function is held in a 'NULL' loop.  */
diff --git a/gcc/omp-simd-clone.c b/gcc/omp-simd-clone.c
index fbb122cd1e0..0a3a386f33d 100644
--- a/gcc/omp-simd-clone.c
+++ b/gcc/omp-simd-clone.c
@@ -48,7 +48,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "ipa-prop.h"
 #include "tree-eh.h"
 #include "varasm.h"
-
+#include "stringpool.h"
+#include "attribs.h"
 
 /* Allocate a fresh `simd_clone' and return it.  NARGS is the number
    of arguments to reserve space for.  */
diff --git a/gcc/opts-global.c b/gcc/opts-global.c
index 50bad77c347..fc55512e554 100644
--- a/gcc/opts-global.c
+++ b/gcc/opts-global.c
@@ -35,6 +35,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "plugin.h"
 #include "toplev.h"
 #include "context.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 
 typedef const char *const_char_p; /* For DEF_VEC_P.  */
diff --git a/gcc/passes.c b/gcc/passes.c
index f5791ac806a..2c9add84c1d 100644
--- a/gcc/passes.c
+++ b/gcc/passes.c
@@ -61,6 +61,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-cfgcleanup.h"
 #include "insn-addr.h" /* for INSN_ADDRESSES_ALLOC.  */
 #include "diagnostic-core.h" /* for fnotice */
+#include "stringpool.h"
+#include "attribs.h"
 
 using namespace gcc;
 
diff --git a/gcc/predict.c b/gcc/predict.c
index 609c099d7b5..80c2c1966d8 100644
--- a/gcc/predict.c
+++ b/gcc/predict.c
@@ -59,6 +59,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "gimple-pretty-print.h"
 #include "selftest.h"
 #include "cfgrtl.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* Enum with reasons why a predictor is ignored.  */
 
diff --git a/gcc/sancov.c b/gcc/sancov.c
index 1651989ea24..b19de8bbbc5 100644
--- a/gcc/sancov.c
+++ b/gcc/sancov.c
@@ -32,6 +32,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-cfg.h"
 #include "tree-pass.h"
 #include "tree-iterator.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 
 namespace {
diff --git a/gcc/sanopt.c b/gcc/sanopt.c
index f6dd14da00d..d17c7db3321 100644
--- a/gcc/sanopt.c
+++ b/gcc/sanopt.c
@@ -30,6 +30,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "gimple-pretty-print.h"
 #include "fold-const.h"
 #include "gimple-iterator.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 #include "ubsan.h"
 #include "params.h"
diff --git a/gcc/symtab.c b/gcc/symtab.c
index 0145910023f..7e5eb7d6416 100644
--- a/gcc/symtab.c
+++ b/gcc/symtab.c
@@ -35,6 +35,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "output.h"
 #include "ipa-utils.h"
 #include "calls.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 static const char *ipa_ref_use_name[] = {"read","write","addr","alias","chkp"};
 
diff --git a/gcc/toplev.c b/gcc/toplev.c
index 48a79e28d99..d23714c4773 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -63,6 +63,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "hosthooks.h"
 #include "opts.h"
 #include "opts-diagnostic.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 #include "tsan.h"
 #include "plugin.h"
diff --git a/gcc/trans-mem.c b/gcc/trans-mem.c
index eb03560be26..40b53681186 100644
--- a/gcc/trans-mem.c
+++ b/gcc/trans-mem.c
@@ -50,7 +50,8 @@
 #include "langhooks.h"
 #include "cfgloop.h"
 #include "tree-ssa-address.h"
-
+#include "stringpool.h"
+#include "attribs.h"
 
 #define A_RUNINSTRUMENTEDCODE	0x0001
 #define A_RUNUNINSTRUMENTEDCODE	0x0002
diff --git a/gcc/tree-chkp.c b/gcc/tree-chkp.c
index e241f50f308..12af458fb90 100644
--- a/gcc/tree-chkp.c
+++ b/gcc/tree-chkp.c
@@ -52,6 +52,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-dfa.h"
 #include "ipa-chkp.h"
 #include "params.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /*  Pointer Bounds Checker instruments code with memory checks to find
     out-of-bounds memory accesses.  Checks are performed by computing
diff --git a/gcc/tree-eh.c b/gcc/tree-eh.c
index c68d71a5e54..938197992ce 100644
--- a/gcc/tree-eh.c
+++ b/gcc/tree-eh.c
@@ -43,6 +43,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "langhooks.h"
 #include "cfgloop.h"
 #include "gimple-low.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 
 /* In some instances a tree and a gimple need to be stored in a same table,
diff --git a/gcc/tree-into-ssa.c b/gcc/tree-into-ssa.c
index d4056373f31..28f72e4ce32 100644
--- a/gcc/tree-into-ssa.c
+++ b/gcc/tree-into-ssa.c
@@ -38,6 +38,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-ssa.h"
 #include "domwalk.h"
 #include "statistics.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 
 #define PERCENT(x,y) ((float)(x) * 100.0 / (float)(y))
diff --git a/gcc/tree-object-size.c b/gcc/tree-object-size.c
index 723a5283da6..a56b78a4510 100644
--- a/gcc/tree-object-size.c
+++ b/gcc/tree-object-size.c
@@ -32,6 +32,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "gimple-fold.h"
 #include "gimple-iterator.h"
 #include "tree-cfg.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 struct object_size_info
 {
diff --git a/gcc/tree-parloops.c b/gcc/tree-parloops.c
index 59e261d2aaa..cfc143f3c02 100644
--- a/gcc/tree-parloops.c
+++ b/gcc/tree-parloops.c
@@ -58,6 +58,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-eh.h"
 #include "gomp-constants.h"
 #include "tree-dfa.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* This pass tries to distribute iterations of loops into several threads.
    The implementation is straightforward -- for each loop we test whether its
diff --git a/gcc/tree-profile.c b/gcc/tree-profile.c
index b1ee7f2b3f5..4b73255018c 100644
--- a/gcc/tree-profile.c
+++ b/gcc/tree-profile.c
@@ -50,6 +50,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "profile.h"
 #include "tree-cfgcleanup.h"
 #include "params.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 static GTY(()) tree gcov_type_node;
 static GTY(()) tree tree_interval_profiler_fn;
diff --git a/gcc/tree-ssa-ccp.c b/gcc/tree-ssa-ccp.c
index f18f2e0c2a4..3940d538ca7 100644
--- a/gcc/tree-ssa-ccp.c
+++ b/gcc/tree-ssa-ccp.c
@@ -145,6 +145,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-ssa-ccp.h"
 #include "tree-dfa.h"
 #include "diagnostic-core.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* Possible lattice values.  */
 typedef enum
diff --git a/gcc/tree-ssa-live.c b/gcc/tree-ssa-live.c
index c77075e4ac6..8738fe21a6e 100644
--- a/gcc/tree-ssa-live.c
+++ b/gcc/tree-ssa-live.c
@@ -38,6 +38,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-ssa.h"
 #include "ipa-utils.h"
 #include "cfgloop.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 static void verify_live_on_entry (tree_live_info_p);
 
diff --git a/gcc/tree-ssa-loop.c b/gcc/tree-ssa-loop.c
index 19a0f30c525..1e8491757a6 100644
--- a/gcc/tree-ssa-loop.c
+++ b/gcc/tree-ssa-loop.c
@@ -38,6 +38,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-vectorizer.h"
 #include "omp-general.h"
 #include "diagnostic-core.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 
 /* A pass making sure loops are fixed up.  */
diff --git a/gcc/tree-ssa-sccvn.c b/gcc/tree-ssa-sccvn.c
index ca43f01b1f5..d62a49d2d1e 100644
--- a/gcc/tree-ssa-sccvn.c
+++ b/gcc/tree-ssa-sccvn.c
@@ -60,6 +60,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "domwalk.h"
 #include "gimple-iterator.h"
 #include "gimple-match.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* This algorithm is based on the SCC algorithm presented by Keith
    Cooper and L. Taylor Simpson in "SCC-Based Value numbering"
diff --git a/gcc/tree-ssa-structalias.c b/gcc/tree-ssa-structalias.c
index e743e35033e..c120ce40303 100644
--- a/gcc/tree-ssa-structalias.c
+++ b/gcc/tree-ssa-structalias.c
@@ -40,7 +40,8 @@
 #include "params.h"
 #include "gimple-walk.h"
 #include "varasm.h"
-
+#include "stringpool.h"
+#include "attribs.h"
 
 /* The idea behind this analyzer is to generate set constraints from the
    program, then solve the resulting constraints in order to generate the
diff --git a/gcc/tree-ssa.c b/gcc/tree-ssa.c
index a67012c043f..8b6da9645ce 100644
--- a/gcc/tree-ssa.c
+++ b/gcc/tree-ssa.c
@@ -41,6 +41,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "cfgexpand.h"
 #include "tree-cfg.h"
 #include "tree-dfa.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 
 /* Pointer map of variable mappings, keyed by edge.  */
diff --git a/gcc/tree-streamer-in.c b/gcc/tree-streamer-in.c
index eb41e7556d0..600470080aa 100644
--- a/gcc/tree-streamer-in.c
+++ b/gcc/tree-streamer-in.c
@@ -32,6 +32,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "builtins.h"
 #include "ipa-chkp.h"
 #include "gomp-constants.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 #include "opts.h"
 
diff --git a/gcc/tree-vectorizer.c b/gcc/tree-vectorizer.c
index 129129f6b68..feddfa2287c 100644
--- a/gcc/tree-vectorizer.c
+++ b/gcc/tree-vectorizer.c
@@ -76,6 +76,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-ssa-propagate.h"
 #include "dbgcnt.h"
 #include "tree-scalar-evolution.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 
 /* Loop or bb location.  */
diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c
index 79a29bf0efb..657a8d186c8 100644
--- a/gcc/tree-vrp.c
+++ b/gcc/tree-vrp.c
@@ -62,6 +62,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "alloc-pool.h"
 #include "domwalk.h"
 #include "tree-cfgcleanup.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 #define VR_INITIALIZER { VR_UNDEFINED, NULL_TREE, NULL_TREE, NULL }
 
diff --git a/gcc/tree.c b/gcc/tree.c
index 2b65cb1d125..c493edd561d 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -62,6 +62,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "print-tree.h"
 #include "ipa-utils.h"
 #include "selftest.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 /* Tree code classes.  */
 
@@ -4822,254 +4824,6 @@ protected_set_expr_location (tree t, location_t loc)
     SET_EXPR_LOCATION (t, loc);
 }
 \f
-/* Return a declaration like DDECL except that its DECL_ATTRIBUTES
-   is ATTRIBUTE.  */
-
-tree
-build_decl_attribute_variant (tree ddecl, tree attribute)
-{
-  DECL_ATTRIBUTES (ddecl) = attribute;
-  return ddecl;
-}
-
-/* Return a type like TTYPE except that its TYPE_ATTRIBUTE
-   is ATTRIBUTE and its qualifiers are QUALS.
-
-   Record such modified types already made so we don't make duplicates.  */
-
-tree
-build_type_attribute_qual_variant (tree ttype, tree attribute, int quals)
-{
-  if (! attribute_list_equal (TYPE_ATTRIBUTES (ttype), attribute))
-    {
-      tree ntype;
-
-      /* Building a distinct copy of a tagged type is inappropriate; it
-	 causes breakage in code that expects there to be a one-to-one
-	 relationship between a struct and its fields.
-	 build_duplicate_type is another solution (as used in
-	 handle_transparent_union_attribute), but that doesn't play well
-	 with the stronger C++ type identity model.  */
-      if (TREE_CODE (ttype) == RECORD_TYPE
-	  || TREE_CODE (ttype) == UNION_TYPE
-	  || TREE_CODE (ttype) == QUAL_UNION_TYPE
-	  || TREE_CODE (ttype) == ENUMERAL_TYPE)
-	{
-	  warning (OPT_Wattributes,
-		   "ignoring attributes applied to %qT after definition",
-		   TYPE_MAIN_VARIANT (ttype));
-	  return build_qualified_type (ttype, quals);
-	}
-
-      ttype = build_qualified_type (ttype, TYPE_UNQUALIFIED);
-      ntype = build_distinct_type_copy (ttype);
-
-      TYPE_ATTRIBUTES (ntype) = attribute;
-
-      hashval_t hash = type_hash_canon_hash (ntype);
-      ntype = type_hash_canon (hash, ntype);
-
-      /* If the target-dependent attributes make NTYPE different from
-	 its canonical type, we will need to use structural equality
-	 checks for this type. */
-      if (TYPE_STRUCTURAL_EQUALITY_P (ttype)
-          || !comp_type_attributes (ntype, ttype))
-	SET_TYPE_STRUCTURAL_EQUALITY (ntype);
-      else if (TYPE_CANONICAL (ntype) == ntype)
-	TYPE_CANONICAL (ntype) = TYPE_CANONICAL (ttype);
-
-      ttype = build_qualified_type (ntype, quals);
-    }
-  else if (TYPE_QUALS (ttype) != quals)
-    ttype = build_qualified_type (ttype, quals);
-
-  return ttype;
-}
-
-/* Check if "omp declare simd" attribute arguments, CLAUSES1 and CLAUSES2, are
-   the same.  */
-
-static bool
-omp_declare_simd_clauses_equal (tree clauses1, tree clauses2)
-{
-  tree cl1, cl2;
-  for (cl1 = clauses1, cl2 = clauses2;
-       cl1 && cl2;
-       cl1 = OMP_CLAUSE_CHAIN (cl1), cl2 = OMP_CLAUSE_CHAIN (cl2))
-    {
-      if (OMP_CLAUSE_CODE (cl1) != OMP_CLAUSE_CODE (cl2))
-	return false;
-      if (OMP_CLAUSE_CODE (cl1) != OMP_CLAUSE_SIMDLEN)
-	{
-	  if (simple_cst_equal (OMP_CLAUSE_DECL (cl1),
-				OMP_CLAUSE_DECL (cl2)) != 1)
-	    return false;
-	}
-      switch (OMP_CLAUSE_CODE (cl1))
-	{
-	case OMP_CLAUSE_ALIGNED:
-	  if (simple_cst_equal (OMP_CLAUSE_ALIGNED_ALIGNMENT (cl1),
-				OMP_CLAUSE_ALIGNED_ALIGNMENT (cl2)) != 1)
-	    return false;
-	  break;
-	case OMP_CLAUSE_LINEAR:
-	  if (simple_cst_equal (OMP_CLAUSE_LINEAR_STEP (cl1),
-				OMP_CLAUSE_LINEAR_STEP (cl2)) != 1)
-	    return false;
-	  break;
-	case OMP_CLAUSE_SIMDLEN:
-	  if (simple_cst_equal (OMP_CLAUSE_SIMDLEN_EXPR (cl1),
-				OMP_CLAUSE_SIMDLEN_EXPR (cl2)) != 1)
-	    return false;
-	default:
-	  break;
-	}
-    }
-  return true;
-}
-
-/* Compare two constructor-element-type constants.  Return 1 if the lists
-   are known to be equal; otherwise return 0.  */
-
-static bool
-simple_cst_list_equal (const_tree l1, const_tree l2)
-{
-  while (l1 != NULL_TREE && l2 != NULL_TREE)
-    {
-      if (simple_cst_equal (TREE_VALUE (l1), TREE_VALUE (l2)) != 1)
-	return false;
-
-      l1 = TREE_CHAIN (l1);
-      l2 = TREE_CHAIN (l2);
-    }
-
-  return l1 == l2;
-}
-
-/* Compare two identifier nodes representing attributes.
-   Return true if they are the same, false otherwise.  */
-
-static bool
-cmp_attrib_identifiers (const_tree attr1, const_tree attr2)
-{
-  /* Make sure we're dealing with IDENTIFIER_NODEs.  */
-  gcc_checking_assert (TREE_CODE (attr1) == IDENTIFIER_NODE
-		       && TREE_CODE (attr2) == IDENTIFIER_NODE);
-
-  /* Identifiers can be compared directly for equality.  */
-  if (attr1 == attr2)
-    return true;
-
-  return cmp_attribs (IDENTIFIER_POINTER (attr1), IDENTIFIER_LENGTH (attr1),
-		      IDENTIFIER_POINTER (attr2), IDENTIFIER_LENGTH (attr2));
-}
-
-/* Compare two attributes for their value identity.  Return true if the
-   attribute values are known to be equal; otherwise return false.  */
-
-bool
-attribute_value_equal (const_tree attr1, const_tree attr2)
-{
-  if (TREE_VALUE (attr1) == TREE_VALUE (attr2))
-    return true;
-
-  if (TREE_VALUE (attr1) != NULL_TREE
-      && TREE_CODE (TREE_VALUE (attr1)) == TREE_LIST
-      && TREE_VALUE (attr2) != NULL_TREE
-      && TREE_CODE (TREE_VALUE (attr2)) == TREE_LIST)
-    {
-      /* Handle attribute format.  */
-      if (is_attribute_p ("format", get_attribute_name (attr1)))
-	{
-	  attr1 = TREE_VALUE (attr1);
-	  attr2 = TREE_VALUE (attr2);
-	  /* Compare the archetypes (printf/scanf/strftime/...).  */
-	  if (!cmp_attrib_identifiers (TREE_VALUE (attr1),
-				       TREE_VALUE (attr2)))
-	    return false;
-	  /* Archetypes are the same.  Compare the rest.  */
-	  return (simple_cst_list_equal (TREE_CHAIN (attr1),
-					 TREE_CHAIN (attr2)) == 1);
-	}
-      return (simple_cst_list_equal (TREE_VALUE (attr1),
-				     TREE_VALUE (attr2)) == 1);
-    }
-
-  if ((flag_openmp || flag_openmp_simd)
-      && TREE_VALUE (attr1) && TREE_VALUE (attr2)
-      && TREE_CODE (TREE_VALUE (attr1)) == OMP_CLAUSE
-      && TREE_CODE (TREE_VALUE (attr2)) == OMP_CLAUSE)
-    return omp_declare_simd_clauses_equal (TREE_VALUE (attr1),
-					   TREE_VALUE (attr2));
-
-  return (simple_cst_equal (TREE_VALUE (attr1), TREE_VALUE (attr2)) == 1);
-}
-
-/* Return 0 if the attributes for two types are incompatible, 1 if they
-   are compatible, and 2 if they are nearly compatible (which causes a
-   warning to be generated).  */
-int
-comp_type_attributes (const_tree type1, const_tree type2)
-{
-  const_tree a1 = TYPE_ATTRIBUTES (type1);
-  const_tree a2 = TYPE_ATTRIBUTES (type2);
-  const_tree a;
-
-  if (a1 == a2)
-    return 1;
-  for (a = a1; a != NULL_TREE; a = TREE_CHAIN (a))
-    {
-      const struct attribute_spec *as;
-      const_tree attr;
-
-      as = lookup_attribute_spec (get_attribute_name (a));
-      if (!as || as->affects_type_identity == false)
-        continue;
-
-      attr = lookup_attribute (as->name, CONST_CAST_TREE (a2));
-      if (!attr || !attribute_value_equal (a, attr))
-        break;
-    }
-  if (!a)
-    {
-      for (a = a2; a != NULL_TREE; a = TREE_CHAIN (a))
-	{
-	  const struct attribute_spec *as;
-
-	  as = lookup_attribute_spec (get_attribute_name (a));
-	  if (!as || as->affects_type_identity == false)
-	    continue;
-
-	  if (!lookup_attribute (as->name, CONST_CAST_TREE (a1)))
-	    break;
-	  /* We don't need to compare trees again, as we did this
-	     already in first loop.  */
-	}
-      /* All types - affecting identity - are equal, so
-         there is no need to call target hook for comparison.  */
-      if (!a)
-        return 1;
-    }
-  if (lookup_attribute ("transaction_safe", CONST_CAST_TREE (a)))
-    return 0;
-  /* As some type combinations - like default calling-convention - might
-     be compatible, we have to call the target hook to get the final result.  */
-  return targetm.comp_type_attributes (type1, type2);
-}
-
-/* Return a type like TTYPE except that its TYPE_ATTRIBUTE
-   is ATTRIBUTE.
-
-   Record such modified types already made so we don't make duplicates.  */
-
-tree
-build_type_attribute_variant (tree ttype, tree attribute)
-{
-  return build_type_attribute_qual_variant (ttype, attribute,
-					    TYPE_QUALS (ttype));
-}
-
-
 /* Reset the expression *EXPR_P, a size or position.
 
    ??? We could reset all non-constant sizes or positions.  But it's cheap
@@ -6023,379 +5777,6 @@ make_pass_ipa_free_lang_data (gcc::context *ctxt)
 {
   return new pass_ipa_free_lang_data (ctxt);
 }
-
-/* The backbone of lookup_attribute().  ATTR_LEN is the string length
-   of ATTR_NAME, and LIST is not NULL_TREE.  */
-tree
-private_lookup_attribute (const char *attr_name, size_t attr_len, tree list)
-{
-  while (list)
-    {
-      tree attr = get_attribute_name (list);
-      size_t ident_len = IDENTIFIER_LENGTH (attr);
-      if (cmp_attribs (attr_name, attr_len, IDENTIFIER_POINTER (attr),
-		       ident_len))
-	break;
-      list = TREE_CHAIN (list);
-    }
-
-  return list;
-}
-
-/* Given an attribute name ATTR_NAME and a list of attributes LIST,
-   return a pointer to the attribute's list first element if the attribute
-   starts with ATTR_NAME.  */
-
-tree
-private_lookup_attribute_by_prefix (const char *attr_name, size_t attr_len,
-				    tree list)
-{
-  while (list)
-    {
-      size_t ident_len = IDENTIFIER_LENGTH (get_attribute_name (list));
-
-      if (attr_len > ident_len)
-	{
-	  list = TREE_CHAIN (list);
-	  continue;
-	}
-
-      const char *p = IDENTIFIER_POINTER (get_attribute_name (list));
-      gcc_checking_assert (attr_len == 0 || p[0] != '_');
-
-      if (strncmp (attr_name, p, attr_len) == 0)
-	break;
-
-      list = TREE_CHAIN (list);
-    }
-
-  return list;
-}
-
-
-/* A variant of lookup_attribute() that can be used with an identifier
-   as the first argument, and where the identifier can be either
-   'text' or '__text__'.
-
-   Given an attribute ATTR_IDENTIFIER, and a list of attributes LIST,
-   return a pointer to the attribute's list element if the attribute
-   is part of the list, or NULL_TREE if not found.  If the attribute
-   appears more than once, this only returns the first occurrence; the
-   TREE_CHAIN of the return value should be passed back in if further
-   occurrences are wanted.  ATTR_IDENTIFIER must be an identifier but
-   can be in the form 'text' or '__text__'.  */
-static tree
-lookup_ident_attribute (tree attr_identifier, tree list)
-{
-  gcc_checking_assert (TREE_CODE (attr_identifier) == IDENTIFIER_NODE);
-
-  while (list)
-    {
-      gcc_checking_assert (TREE_CODE (get_attribute_name (list))
-			   == IDENTIFIER_NODE);
-
-      if (cmp_attrib_identifiers (attr_identifier,
-				  get_attribute_name (list)))
-	/* Found it.  */
-	break;
-      list = TREE_CHAIN (list);
-    }
-
-  return list;
-}
-
-/* Remove any instances of attribute ATTR_NAME in LIST and return the
-   modified list.  */
-
-tree
-remove_attribute (const char *attr_name, tree list)
-{
-  tree *p;
-  gcc_checking_assert (attr_name[0] != '_');
-
-  for (p = &list; *p; )
-    {
-      tree l = *p;
-
-      tree attr = get_attribute_name (l);
-      if (is_attribute_p (attr_name, attr))
-	*p = TREE_CHAIN (l);
-      else
-	p = &TREE_CHAIN (l);
-    }
-
-  return list;
-}
-
-/* Return an attribute list that is the union of a1 and a2.  */
-
-tree
-merge_attributes (tree a1, tree a2)
-{
-  tree attributes;
-
-  /* Either one unset?  Take the set one.  */
-
-  if ((attributes = a1) == 0)
-    attributes = a2;
-
-  /* One that completely contains the other?  Take it.  */
-
-  else if (a2 != 0 && ! attribute_list_contained (a1, a2))
-    {
-      if (attribute_list_contained (a2, a1))
-	attributes = a2;
-      else
-	{
-	  /* Pick the longest list, and hang on the other list.  */
-
-	  if (list_length (a1) < list_length (a2))
-	    attributes = a2, a2 = a1;
-
-	  for (; a2 != 0; a2 = TREE_CHAIN (a2))
-	    {
-	      tree a;
-	      for (a = lookup_ident_attribute (get_attribute_name (a2),
-					       attributes);
-		   a != NULL_TREE && !attribute_value_equal (a, a2);
-		   a = lookup_ident_attribute (get_attribute_name (a2),
-					       TREE_CHAIN (a)))
-		;
-	      if (a == NULL_TREE)
-		{
-		  a1 = copy_node (a2);
-		  TREE_CHAIN (a1) = attributes;
-		  attributes = a1;
-		}
-	    }
-	}
-    }
-  return attributes;
-}
-
-/* Given types T1 and T2, merge their attributes and return
-  the result.  */
-
-tree
-merge_type_attributes (tree t1, tree t2)
-{
-  return merge_attributes (TYPE_ATTRIBUTES (t1),
-			   TYPE_ATTRIBUTES (t2));
-}
-
-/* Given decls OLDDECL and NEWDECL, merge their attributes and return
-   the result.  */
-
-tree
-merge_decl_attributes (tree olddecl, tree newdecl)
-{
-  return merge_attributes (DECL_ATTRIBUTES (olddecl),
-			   DECL_ATTRIBUTES (newdecl));
-}
-
-#if TARGET_DLLIMPORT_DECL_ATTRIBUTES
-
-/* Specialization of merge_decl_attributes for various Windows targets.
-
-   This handles the following situation:
-
-     __declspec (dllimport) int foo;
-     int foo;
-
-   The second instance of `foo' nullifies the dllimport.  */
-
-tree
-merge_dllimport_decl_attributes (tree old, tree new_tree)
-{
-  tree a;
-  int delete_dllimport_p = 1;
-
-  /* What we need to do here is remove from `old' dllimport if it doesn't
-     appear in `new'.  dllimport behaves like extern: if a declaration is
-     marked dllimport and a definition appears later, then the object
-     is not dllimport'd.  We also remove a `new' dllimport if the old list
-     contains dllexport:  dllexport always overrides dllimport, regardless
-     of the order of declaration.  */
-  if (!VAR_OR_FUNCTION_DECL_P (new_tree))
-    delete_dllimport_p = 0;
-  else if (DECL_DLLIMPORT_P (new_tree)
-     	   && lookup_attribute ("dllexport", DECL_ATTRIBUTES (old)))
-    {
-      DECL_DLLIMPORT_P (new_tree) = 0;
-      warning (OPT_Wattributes, "%q+D already declared with dllexport attribute: "
-	      "dllimport ignored", new_tree);
-    }
-  else if (DECL_DLLIMPORT_P (old) && !DECL_DLLIMPORT_P (new_tree))
-    {
-      /* Warn about overriding a symbol that has already been used, e.g.:
-           extern int __attribute__ ((dllimport)) foo;
-	   int* bar () {return &foo;}
-	   int foo;
-      */
-      if (TREE_USED (old))
-	{
-	  warning (0, "%q+D redeclared without dllimport attribute "
-		   "after being referenced with dll linkage", new_tree);
-	  /* If we have used a variable's address with dllimport linkage,
-	      keep the old DECL_DLLIMPORT_P flag: the ADDR_EXPR using the
-	      decl may already have had TREE_CONSTANT computed.
-	      We still remove the attribute so that assembler code refers
-	      to '&foo rather than '_imp__foo'.  */
-	  if (VAR_P (old) && TREE_ADDRESSABLE (old))
-	    DECL_DLLIMPORT_P (new_tree) = 1;
-	}
-
-      /* Let an inline definition silently override the external reference,
-	 but otherwise warn about attribute inconsistency.  */
-      else if (VAR_P (new_tree) || !DECL_DECLARED_INLINE_P (new_tree))
-	warning (OPT_Wattributes, "%q+D redeclared without dllimport attribute: "
-		  "previous dllimport ignored", new_tree);
-    }
-  else
-    delete_dllimport_p = 0;
-
-  a = merge_attributes (DECL_ATTRIBUTES (old), DECL_ATTRIBUTES (new_tree));
-
-  if (delete_dllimport_p)
-    a = remove_attribute ("dllimport", a);
-
-  return a;
-}
-
-/* Handle a "dllimport" or "dllexport" attribute; arguments as in
-   struct attribute_spec.handler.  */
-
-tree
-handle_dll_attribute (tree * pnode, tree name, tree args, int flags,
-		      bool *no_add_attrs)
-{
-  tree node = *pnode;
-  bool is_dllimport;
-
-  /* These attributes may apply to structure and union types being created,
-     but otherwise should pass to the declaration involved.  */
-  if (!DECL_P (node))
-    {
-      if (flags & ((int) ATTR_FLAG_DECL_NEXT | (int) ATTR_FLAG_FUNCTION_NEXT
-		   | (int) ATTR_FLAG_ARRAY_NEXT))
-	{
-	  *no_add_attrs = true;
-	  return tree_cons (name, args, NULL_TREE);
-	}
-      if (TREE_CODE (node) == RECORD_TYPE
-	  || TREE_CODE (node) == UNION_TYPE)
-	{
-	  node = TYPE_NAME (node);
-	  if (!node)
-	    return NULL_TREE;
-	}
-      else
-	{
-	  warning (OPT_Wattributes, "%qE attribute ignored",
-		   name);
-	  *no_add_attrs = true;
-	  return NULL_TREE;
-	}
-    }
-
-  if (!VAR_OR_FUNCTION_DECL_P (node) && TREE_CODE (node) != TYPE_DECL)
-    {
-      *no_add_attrs = true;
-      warning (OPT_Wattributes, "%qE attribute ignored",
-	       name);
-      return NULL_TREE;
-    }
-
-  if (TREE_CODE (node) == TYPE_DECL
-      && TREE_CODE (TREE_TYPE (node)) != RECORD_TYPE
-      && TREE_CODE (TREE_TYPE (node)) != UNION_TYPE)
-    {
-      *no_add_attrs = true;
-      warning (OPT_Wattributes, "%qE attribute ignored",
-	       name);
-      return NULL_TREE;
-    }
-
-  is_dllimport = is_attribute_p ("dllimport", name);
-
-  /* Report error on dllimport ambiguities seen now before they cause
-     any damage.  */
-  if (is_dllimport)
-    {
-      /* Honor any target-specific overrides. */
-      if (!targetm.valid_dllimport_attribute_p (node))
-	*no_add_attrs = true;
-
-     else if (TREE_CODE (node) == FUNCTION_DECL
-	        && DECL_DECLARED_INLINE_P (node))
-	{
-	  warning (OPT_Wattributes, "inline function %q+D declared as "
-		  " dllimport: attribute ignored", node);
-	  *no_add_attrs = true;
-	}
-      /* Like MS, treat definition of dllimported variables and
-	 non-inlined functions on declaration as syntax errors. */
-     else if (TREE_CODE (node) == FUNCTION_DECL && DECL_INITIAL (node))
-	{
-	  error ("function %q+D definition is marked dllimport", node);
-	  *no_add_attrs = true;
-	}
-
-     else if (VAR_P (node))
-	{
-	  if (DECL_INITIAL (node))
-	    {
-	      error ("variable %q+D definition is marked dllimport",
-		     node);
-	      *no_add_attrs = true;
-	    }
-
-	  /* `extern' needn't be specified with dllimport.
-	     Specify `extern' now and hope for the best.  Sigh.  */
-	  DECL_EXTERNAL (node) = 1;
-	  /* Also, implicitly give dllimport'd variables declared within
-	     a function global scope, unless declared static.  */
-	  if (current_function_decl != NULL_TREE && !TREE_STATIC (node))
-	    TREE_PUBLIC (node) = 1;
-	}
-
-      if (*no_add_attrs == false)
-        DECL_DLLIMPORT_P (node) = 1;
-    }
-  else if (TREE_CODE (node) == FUNCTION_DECL
-	   && DECL_DECLARED_INLINE_P (node)
-	   && flag_keep_inline_dllexport)
-    /* An exported function, even if inline, must be emitted.  */
-    DECL_EXTERNAL (node) = 0;
-
-  /*  Report error if symbol is not accessible at global scope.  */
-  if (!TREE_PUBLIC (node) && VAR_OR_FUNCTION_DECL_P (node))
-    {
-      error ("external linkage required for symbol %q+D because of "
-	     "%qE attribute", node, name);
-      *no_add_attrs = true;
-    }
-
-  /* A dllexport'd entity must have default visibility so that other
-     program units (shared libraries or the main executable) can see
-     it.  A dllimport'd entity must have default visibility so that
-     the linker knows that undefined references within this program
-     unit can be resolved by the dynamic linker.  */
-  if (!*no_add_attrs)
-    {
-      if (DECL_VISIBILITY_SPECIFIED (node)
-	  && DECL_VISIBILITY (node) != VISIBILITY_DEFAULT)
-	error ("%qE implies default visibility, but %qD has already "
-	       "been declared with a different visibility",
-	       name, node);
-      DECL_VISIBILITY (node) = VISIBILITY_DEFAULT;
-      DECL_VISIBILITY_SPECIFIED (node) = 1;
-    }
-
-  return NULL_TREE;
-}
-
-#endif /* TARGET_DLLIMPORT_DECL_ATTRIBUTES  */
 \f
 /* Set the type qualifiers for TYPE to TYPE_QUALS, which is a bitmask
    of the various TYPE_QUAL values.  */
@@ -7155,68 +6536,6 @@ print_type_hash_statistics (void)
 	   type_hash_table->collisions ());
 }
 
-/* Given two lists of attributes, return true if list l2 is
-   equivalent to l1.  */
-
-int
-attribute_list_equal (const_tree l1, const_tree l2)
-{
-  if (l1 == l2)
-    return 1;
-
-  return attribute_list_contained (l1, l2)
-	 && attribute_list_contained (l2, l1);
-}
-
-/* Given two lists of attributes, return true if list L2 is
-   completely contained within L1.  */
-/* ??? This would be faster if attribute names were stored in a canonicalized
-   form.  Otherwise, if L1 uses `foo' and L2 uses `__foo__', the long method
-   must be used to show these elements are equivalent (which they are).  */
-/* ??? It's not clear that attributes with arguments will always be handled
-   correctly.  */
-
-int
-attribute_list_contained (const_tree l1, const_tree l2)
-{
-  const_tree t1, t2;
-
-  /* First check the obvious, maybe the lists are identical.  */
-  if (l1 == l2)
-    return 1;
-
-  /* Maybe the lists are similar.  */
-  for (t1 = l1, t2 = l2;
-       t1 != 0 && t2 != 0
-        && get_attribute_name (t1) == get_attribute_name (t2)
-        && TREE_VALUE (t1) == TREE_VALUE (t2);
-       t1 = TREE_CHAIN (t1), t2 = TREE_CHAIN (t2))
-    ;
-
-  /* Maybe the lists are equal.  */
-  if (t1 == 0 && t2 == 0)
-    return 1;
-
-  for (; t2 != 0; t2 = TREE_CHAIN (t2))
-    {
-      const_tree attr;
-      /* This CONST_CAST is okay because lookup_attribute does not
-	 modify its argument and the return value is assigned to a
-	 const_tree.  */
-      for (attr = lookup_ident_attribute (get_attribute_name (t2),
-					  CONST_CAST_TREE (l1));
-	   attr != NULL_TREE && !attribute_value_equal (t2, attr);
-	   attr = lookup_ident_attribute (get_attribute_name (t2),
-					  TREE_CHAIN (attr)))
-	;
-
-      if (attr == NULL_TREE)
-	return 0;
-    }
-
-  return 1;
-}
-
 /* Given two lists of types
    (chains of TREE_LIST nodes with types in the TREE_VALUE slots)
    return 1 if the lists contain the same types in the same order.
diff --git a/gcc/tree.h b/gcc/tree.h
index 1e89809804c..46debc12a84 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -4088,8 +4088,6 @@ extern tree purpose_member (const_tree, tree);
 extern bool vec_member (const_tree, vec<tree, va_gc> *);
 extern tree chain_index (int, tree);
 
-extern int attribute_list_equal (const_tree, const_tree);
-extern int attribute_list_contained (const_tree, const_tree);
 extern int tree_int_cst_equal (const_tree, const_tree);
 
 extern bool tree_fits_shwi_p (const_tree)
@@ -4127,90 +4125,6 @@ extern bool valid_constant_size_p (const_tree);
 
 extern tree make_tree (tree, rtx);
 
-/* Return a type like TTYPE except that its TYPE_ATTRIBUTES
-   is ATTRIBUTE.
-
-   Such modified types already made are recorded so that duplicates
-   are not made.  */
-
-extern tree build_type_attribute_variant (tree, tree);
-extern tree build_decl_attribute_variant (tree, tree);
-extern tree build_type_attribute_qual_variant (tree, tree, int);
-
-extern bool attribute_value_equal (const_tree, const_tree);
-
-/* Return 0 if the attributes for two types are incompatible, 1 if they
-   are compatible, and 2 if they are nearly compatible (which causes a
-   warning to be generated).  */
-extern int comp_type_attributes (const_tree, const_tree);
-
-/* Default versions of target-overridable functions.  */
-extern tree merge_decl_attributes (tree, tree);
-extern tree merge_type_attributes (tree, tree);
-
-/* This function is a private implementation detail of lookup_attribute()
-   and you should never call it directly.  */
-extern tree private_lookup_attribute (const char *, size_t, tree);
-
-/* This function is a private implementation detail
-   of lookup_attribute_by_prefix() and you should never call it directly.  */
-extern tree private_lookup_attribute_by_prefix (const char *, size_t, tree);
-
-/* Given an attribute name ATTR_NAME and a list of attributes LIST,
-   return a pointer to the attribute's list element if the attribute
-   is part of the list, or NULL_TREE if not found.  If the attribute
-   appears more than once, this only returns the first occurrence; the
-   TREE_CHAIN of the return value should be passed back in if further
-   occurrences are wanted.  ATTR_NAME must be in the form 'text' (not
-   '__text__').  */
-
-static inline tree
-lookup_attribute (const char *attr_name, tree list)
-{
-  gcc_checking_assert (attr_name[0] != '_');  
-  /* In most cases, list is NULL_TREE.  */
-  if (list == NULL_TREE)
-    return NULL_TREE;
-  else
-    /* Do the strlen() before calling the out-of-line implementation.
-       In most cases attr_name is a string constant, and the compiler
-       will optimize the strlen() away.  */
-    return private_lookup_attribute (attr_name, strlen (attr_name), list);
-}
-
-/* Given an attribute name ATTR_NAME and a list of attributes LIST,
-   return a pointer to the attribute's list first element if the attribute
-   starts with ATTR_NAME. ATTR_NAME must be in the form 'text' (not
-   '__text__').  */
-
-static inline tree
-lookup_attribute_by_prefix (const char *attr_name, tree list)
-{
-  gcc_checking_assert (attr_name[0] != '_');
-  /* In most cases, list is NULL_TREE.  */
-  if (list == NULL_TREE)
-    return NULL_TREE;
-  else
-    return private_lookup_attribute_by_prefix (attr_name, strlen (attr_name),
-					       list);
-}
-
-/* Remove any instances of attribute ATTR_NAME in LIST and return the
-   modified list.  */
-
-extern tree remove_attribute (const char *, tree);
-
-/* Given two attributes lists, return a list of their union.  */
-
-extern tree merge_attributes (tree, tree);
-
-/* Given two Windows decl attributes lists, possibly including
-   dllimport, return a list of their union .  */
-extern tree merge_dllimport_decl_attributes (tree, tree);
-
-/* Handle a "dllimport" or "dllexport" attribute.  */
-extern tree handle_dll_attribute (tree *, tree, tree, int, bool *);
-
 /* Returns true iff CAND and BASE have equivalent language-specific
    qualifiers.  */
 
diff --git a/gcc/tsan.c b/gcc/tsan.c
index 2f98b936c03..51b5821deb3 100644
--- a/gcc/tsan.c
+++ b/gcc/tsan.c
@@ -40,6 +40,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "tree-ssa-loop-ivopts.h"
 #include "tree-eh.h"
 #include "tsan.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 #include "builtins.h"
 #include "target.h"
diff --git a/gcc/ubsan.c b/gcc/ubsan.c
index 2580a58b6eb..49e38fa6c09 100644
--- a/gcc/ubsan.c
+++ b/gcc/ubsan.c
@@ -39,6 +39,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "cfgloop.h"
 #include "ubsan.h"
 #include "expr.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 #include "gimplify-me.h"
 #include "dfp.h"
diff --git a/gcc/varasm.c b/gcc/varasm.c
index 6eccbe4b3f7..e0834a1ff3b 100644
--- a/gcc/varasm.c
+++ b/gcc/varasm.c
@@ -51,6 +51,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "langhooks.h"
 #include "debug.h"
 #include "common/common-target.h"
+#include "stringpool.h"
+#include "attribs.h"
 #include "asan.h"
 #include "rtl-iter.h"
 
diff --git a/gcc/varpool.c b/gcc/varpool.c
index ab59c80406b..b005f529cc0 100644
--- a/gcc/varpool.c
+++ b/gcc/varpool.c
@@ -33,6 +33,8 @@ along with GCC; see the file COPYING3.  If not see
 #include "output.h"
 #include "omp-offload.h"
 #include "context.h"
+#include "stringpool.h"
+#include "attribs.h"
 
 const char * const tls_model_names[]={"none", "emulated",
 				      "global-dynamic", "local-dynamic",
-- 
2.13.3


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

* Re: [RFC][PATCH] Do refactoring of attribute functions and move them to attribs.[hc].
  2017-08-08  4:37                             ` Martin Liška
@ 2017-08-08  9:14                               ` Tom de Vries
  0 siblings, 0 replies; 37+ messages in thread
From: Tom de Vries @ 2017-08-08  9:14 UTC (permalink / raw)
  To: Martin Liška; +Cc: Thomas Schwinge, gcc-patches List

On 08/08/2017 06:36 AM, Martin Liška wrote:
> Hello.
> 
> I'm sending final version that I'm going to install. Compared to the previous version I tested
> all targets in contrib/config-list.mk.
> 

I ran into a build breaker for an nvptx offloading compiler (where the 
ACCEL_COMPILER-guarded code is enabled).

Retrying with patch below.

Thanks,
- Tom

diff --git a/gcc/lto/lto.c b/gcc/lto/lto.c
index a3b4d13..31d1488 100644
--- a/gcc/lto/lto.c
+++ b/gcc/lto/lto.c
@@ -53,6 +53,7 @@ along with GCC; see the file COPYING3.  If not see
  #include "lto-symtab.h"
  #include "stringpool.h"
  #include "fold-const.h"
+#include "attribs.h"


  /* Number of parallel tasks to run, -1 if we want to use GNU Make 
jobserver.  */

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

* Re: [RFC][PATCH] Do refactoring of attribute functions and move them to attribs.[hc].
  2017-07-13 13:51                       ` [RFC][PATCH] Do refactoring of attribute functions and move them to attribs.[hc] Martin Liška
  2017-07-14  7:23                         ` Jeff Law
@ 2017-09-12  7:55                         ` Jakub Jelinek
  2017-09-12 11:31                           ` Martin Liška
  1 sibling, 1 reply; 37+ messages in thread
From: Jakub Jelinek @ 2017-09-12  7:55 UTC (permalink / raw)
  To: Martin Liška
  Cc: Jason Merrill, Joseph Myers, gcc-patches List, Richard Biener

On Thu, Jul 13, 2017 at 03:51:31PM +0200, Martin Liška wrote:
> It's request for comment where I mechanically moved attribute-related function to attribs.[hc].
> 
> Patch can bootstrap on ppc64le-redhat-linux and survives regression tests.
> 
> Thoughts?

I've only noticed this now, what is the reason for undoing the size
optimization we had, i.e. inline lookup_attribute that handles the most
common case inline only and inline computes the strlen (an important
optimization, because we almost always call it with a string literal
and strlen of that is a constant) and doing the rest out of line?

> -/* Given an attribute name ATTR_NAME and a list of attributes LIST,
> -   return a pointer to the attribute's list element if the attribute
> -   is part of the list, or NULL_TREE if not found.  If the attribute
> -   appears more than once, this only returns the first occurrence; the
> -   TREE_CHAIN of the return value should be passed back in if further
> -   occurrences are wanted.  ATTR_NAME must be in the form 'text' (not
> -   '__text__').  */
> -
> -static inline tree
> -lookup_attribute (const char *attr_name, tree list)
> -{
> -  gcc_checking_assert (attr_name[0] != '_');  
> -  /* In most cases, list is NULL_TREE.  */
> -  if (list == NULL_TREE)
> -    return NULL_TREE;
> -  else
> -    /* Do the strlen() before calling the out-of-line implementation.
> -       In most cases attr_name is a string constant, and the compiler
> -       will optimize the strlen() away.  */
> -    return private_lookup_attribute (attr_name, strlen (attr_name), list);
> -}

The current code instead inlines the whole lookup_attribute which is larger.
Have you looked at the code size effects of that change?

	Jakub

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

* Re: [RFC][PATCH] Do refactoring of attribute functions and move them to attribs.[hc].
  2017-09-12  7:55                         ` Jakub Jelinek
@ 2017-09-12 11:31                           ` Martin Liška
  2017-09-12 11:40                             ` Jakub Jelinek
  0 siblings, 1 reply; 37+ messages in thread
From: Martin Liška @ 2017-09-12 11:31 UTC (permalink / raw)
  To: Jakub Jelinek
  Cc: Jason Merrill, Joseph Myers, gcc-patches List, Richard Biener

[-- Attachment #1: Type: text/plain, Size: 4235 bytes --]

On 09/12/2017 09:54 AM, Jakub Jelinek wrote:
> On Thu, Jul 13, 2017 at 03:51:31PM +0200, Martin Liška wrote:
>> It's request for comment where I mechanically moved attribute-related function to attribs.[hc].
>>
>> Patch can bootstrap on ppc64le-redhat-linux and survives regression tests.
>>
>> Thoughts?
> 
> I've only noticed this now, what is the reason for undoing the size
> optimization we had, i.e. inline lookup_attribute that handles the most
> common case inline only and inline computes the strlen (an important
> optimization, because we almost always call it with a string literal
> and strlen of that is a constant) and doing the rest out of line?
> 
>> -/* Given an attribute name ATTR_NAME and a list of attributes LIST,
>> -   return a pointer to the attribute's list element if the attribute
>> -   is part of the list, or NULL_TREE if not found.  If the attribute
>> -   appears more than once, this only returns the first occurrence; the
>> -   TREE_CHAIN of the return value should be passed back in if further
>> -   occurrences are wanted.  ATTR_NAME must be in the form 'text' (not
>> -   '__text__').  */
>> -
>> -static inline tree
>> -lookup_attribute (const char *attr_name, tree list)
>> -{
>> -  gcc_checking_assert (attr_name[0] != '_');  
>> -  /* In most cases, list is NULL_TREE.  */
>> -  if (list == NULL_TREE)
>> -    return NULL_TREE;
>> -  else
>> -    /* Do the strlen() before calling the out-of-line implementation.
>> -       In most cases attr_name is a string constant, and the compiler
>> -       will optimize the strlen() away.  */
>> -    return private_lookup_attribute (attr_name, strlen (attr_name), list);
>> -}
> 
> The current code instead inlines the whole lookup_attribute which is larger.
> Have you looked at the code size effects of that change?
> 
> 	Jakub
> 

Hi.

Sorry for removal of the optimization. You're right it really adds some size (~30K of .text):

$ bloaty gcc/cc1plus -- /tmp/cc1plus 
     VM SIZE                      FILE SIZE
 ++++++++++++++ GROWING        ++++++++++++++
  [ = ]       0 .debug_loc      +277Ki  +0.4%
  [ = ]       0 .debug_info    +86.9Ki  +0.1%
  [ = ]       0 .debug_ranges  +59.9Ki  +0.5%
  +0.2% +32.1Ki .text          +32.1Ki  +0.2%
  [ = ]       0 .debug_line    +9.36Ki  +0.1%
  +0.0% +2.06Ki .rodata        +2.06Ki  +0.0%
  [ = ]       0 .symtab        +1.73Ki  +0.1%
  +0.1% +1.72Ki .eh_frame      +1.72Ki  +0.1%
  +0.0%    +272 .dynstr           +272  +0.0%
  [ = ]       0 .debug_abbrev     +140  +0.0%
  +0.0%     +72 .dynsym            +72  +0.0%
  +0.0%     +64 .eh_frame_hdr      +64  +0.0%
  [ = ]       0 .debug_aranges     +48  +0.0%
  +0.0%     +12 .gnu.hash          +12  +0.0%
  +0.0%     +12 .hash              +12  +0.0%
  +0.0%      +6 .gnu.version        +6  +0.0%

 -------------- SHRINKING      --------------
 -10.2%      -6 [Unmapped]        -317 -20.8%
  [ = ]       0 .strtab            -66  -0.0%
  [ = ]       0 .debug_str         -52  -0.0%

  +0.1% +36.3Ki TOTAL           +471Ki  +0.2%

$ bloaty gcc/cc1 -- /tmp/cc1
     VM SIZE                      FILE SIZE
 ++++++++++++++ GROWING        ++++++++++++++
  [ = ]       0 .debug_loc      +232Ki  +0.4%
  [ = ]       0 .debug_info    +74.1Ki  +0.1%
  [ = ]       0 .debug_ranges  +48.9Ki  +0.4%
  +0.2% +26.9Ki .text          +26.9Ki  +0.2%
  [ = ]       0 .debug_line    +8.22Ki  +0.1%
  +0.1% +1.79Ki .eh_frame      +1.79Ki  +0.1%
  +0.0% +1.75Ki .rodata        +1.75Ki  +0.0%
  [ = ]       0 .symtab        +1.50Ki  +0.1%
  +0.0%    +272 .dynstr           +272  +0.0%
  [ = ]       0 .debug_abbrev      +72  +0.0%
  +0.0%     +72 .dynsym            +72  +0.0%
  +0.0%     +64 .eh_frame_hdr      +64  +0.0%
  [ = ]       0 .debug_aranges     +48  +0.0%
  +0.0%     +12 .gnu.hash          +12  +0.0%
  +0.0%     +12 .hash              +12  +0.0%
  +0.0%      +6 .gnu.version        +6  +0.0%

 -------------- SHRINKING      --------------
  [ = ]       0 .debug_str         -52  -0.0%
  [ = ]       0 .strtab            -26  -0.0%

 -+-+-+-+-+-+-+ MIXED          +-+-+-+-+-+-+-
   +19%     +10 [Unmapped]     -2.87Ki -75.1%

  +0.1% +30.9Ki TOTAL           +392Ki  +0.2%

Thus I'm suggesting to the how it was. Is the patch OK after testing?

Martin

[-- Attachment #2: 0001-Reduce-lookup_attribute-memory-footprint.patch --]
[-- Type: text/x-patch, Size: 2453 bytes --]

From a40c06fc06afcb7bb886d7a3106e6da631a48430 Mon Sep 17 00:00:00 2001
From: marxin <mliska@suse.cz>
Date: Tue, 12 Sep 2017 13:30:39 +0200
Subject: [PATCH] Reduce lookup_attribute memory footprint.

gcc/ChangeLog:

2017-09-12  Martin Liska  <mliska@suse.cz>

	* attribs.c (private_lookup_attribute): New function.
	* attribs.h (private_lookup_attribute): Declared here.
	(lookup_attribute): Called from this place.
---
 gcc/attribs.c | 17 +++++++++++++++++
 gcc/attribs.h | 17 ++++++-----------
 2 files changed, 23 insertions(+), 11 deletions(-)

diff --git a/gcc/attribs.c b/gcc/attribs.c
index b8f58a74596..9064434e5f2 100644
--- a/gcc/attribs.c
+++ b/gcc/attribs.c
@@ -1584,3 +1584,20 @@ attribute_list_contained (const_tree l1, const_tree l2)
 
   return 1;
 }
+
+
+tree
+private_lookup_attribute (const char *attr_name, size_t attr_len, tree list)
+{
+  while (list)
+    {
+      tree attr = get_attribute_name (list);
+      size_t ident_len = IDENTIFIER_LENGTH (attr);
+      if (cmp_attribs (attr_name, attr_len, IDENTIFIER_POINTER (attr),
+		       ident_len))
+	break;
+      list = TREE_CHAIN (list);
+    }
+
+  return list;
+}
diff --git a/gcc/attribs.h b/gcc/attribs.h
index 06e6993e958..0285b93cbc3 100644
--- a/gcc/attribs.h
+++ b/gcc/attribs.h
@@ -87,6 +87,11 @@ extern tree handle_dll_attribute (tree *, tree, tree, int, bool *);
 extern int attribute_list_equal (const_tree, const_tree);
 extern int attribute_list_contained (const_tree, const_tree);
 
+/* The backbone of lookup_attribute().  ATTR_LEN is the string length
+   of ATTR_NAME, and LIST is not NULL_TREE.  */
+extern tree private_lookup_attribute (const char *attr_name, size_t attr_len,
+				      tree list);
+
 /* For a given IDENTIFIER_NODE, strip leading and trailing '_' characters
    so that we have a canonical form of attribute names.  */
 
@@ -151,17 +156,7 @@ lookup_attribute (const char *attr_name, tree list)
       /* Do the strlen() before calling the out-of-line implementation.
 	 In most cases attr_name is a string constant, and the compiler
 	 will optimize the strlen() away.  */
-      while (list)
-	{
-	  tree attr = get_attribute_name (list);
-	  size_t ident_len = IDENTIFIER_LENGTH (attr);
-	  if (cmp_attribs (attr_name, attr_len, IDENTIFIER_POINTER (attr),
-			   ident_len))
-	    break;
-	  list = TREE_CHAIN (list);
-	}
-
-      return list;
+      return private_lookup_attribute (attr_name, attr_len, list);
     }
 }
 
-- 
2.14.1


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

* Re: [RFC][PATCH] Do refactoring of attribute functions and move them to attribs.[hc].
  2017-09-12 11:31                           ` Martin Liška
@ 2017-09-12 11:40                             ` Jakub Jelinek
  2017-09-12 14:25                               ` Martin Liška
  0 siblings, 1 reply; 37+ messages in thread
From: Jakub Jelinek @ 2017-09-12 11:40 UTC (permalink / raw)
  To: Martin Liška
  Cc: Jason Merrill, Joseph Myers, gcc-patches List, Richard Biener

On Tue, Sep 12, 2017 at 01:31:47PM +0200, Martin Liška wrote:
> >From a40c06fc06afcb7bb886d7a3106e6da631a48430 Mon Sep 17 00:00:00 2001
> From: marxin <mliska@suse.cz>
> Date: Tue, 12 Sep 2017 13:30:39 +0200
> Subject: [PATCH] Reduce lookup_attribute memory footprint.
> 
> gcc/ChangeLog:
> 
> 2017-09-12  Martin Liska  <mliska@suse.cz>
> 
> 	* attribs.c (private_lookup_attribute): New function.
> 	* attribs.h (private_lookup_attribute): Declared here.
> 	(lookup_attribute): Called from this place.
> ---
>  gcc/attribs.c | 17 +++++++++++++++++
>  gcc/attribs.h | 17 ++++++-----------
>  2 files changed, 23 insertions(+), 11 deletions(-)
> 
> diff --git a/gcc/attribs.c b/gcc/attribs.c
> index b8f58a74596..9064434e5f2 100644
> --- a/gcc/attribs.c
> +++ b/gcc/attribs.c
> @@ -1584,3 +1584,20 @@ attribute_list_contained (const_tree l1, const_tree l2)
>  
>    return 1;
>  }
> +
> +

Can you please add a function comment (and in addition to arguments explain
there why lookup_attribute is split into the two parts)?

> +tree
> +private_lookup_attribute (const char *attr_name, size_t attr_len, tree list)
> +{
> +  while (list)
> +    {

> @@ -151,17 +156,7 @@ lookup_attribute (const char *attr_name, tree list)
>        /* Do the strlen() before calling the out-of-line implementation.
>  	 In most cases attr_name is a string constant, and the compiler
>  	 will optimize the strlen() away.  */

Part of the comment is of course here and that comment didn't make any sense
when everything was inlined.

> -      while (list)
> -	{
> -	  tree attr = get_attribute_name (list);
> -	  size_t ident_len = IDENTIFIER_LENGTH (attr);
> -	  if (cmp_attribs (attr_name, attr_len, IDENTIFIER_POINTER (attr),
> -			   ident_len))
> -	    break;
> -	  list = TREE_CHAIN (list);
> -	}
> -
> -      return list;
> +      return private_lookup_attribute (attr_name, attr_len, list);
>      }
>  }

LGTM with the comment added.  In theory fnsplit could handle that too,
but 1) it would emit out of line stuff in every TU separately 2) the
compiler doesn't know that NULL DECL_ATTRIBUTES is so common (it could
with profiledbootstrap).  And of course LTO can decide to inline it
from attribs.c back anyway if there are reasons why it would be beneficial
somewhere (but I doubt it is beneficial at least in most spots).

	Jakub

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

* Re: [RFC][PATCH] Do refactoring of attribute functions and move them to attribs.[hc].
  2017-09-12 11:40                             ` Jakub Jelinek
@ 2017-09-12 14:25                               ` Martin Liška
  0 siblings, 0 replies; 37+ messages in thread
From: Martin Liška @ 2017-09-12 14:25 UTC (permalink / raw)
  To: Jakub Jelinek
  Cc: Jason Merrill, Joseph Myers, gcc-patches List, Richard Biener

On 09/12/2017 01:39 PM, Jakub Jelinek wrote:
> On Tue, Sep 12, 2017 at 01:31:47PM +0200, Martin Liška wrote:
>> >From a40c06fc06afcb7bb886d7a3106e6da631a48430 Mon Sep 17 00:00:00 2001
>> From: marxin <mliska@suse.cz>
>> Date: Tue, 12 Sep 2017 13:30:39 +0200
>> Subject: [PATCH] Reduce lookup_attribute memory footprint.
>>
>> gcc/ChangeLog:
>>
>> 2017-09-12  Martin Liska  <mliska@suse.cz>
>>
>> 	* attribs.c (private_lookup_attribute): New function.
>> 	* attribs.h (private_lookup_attribute): Declared here.
>> 	(lookup_attribute): Called from this place.
>> ---
>>  gcc/attribs.c | 17 +++++++++++++++++
>>  gcc/attribs.h | 17 ++++++-----------
>>  2 files changed, 23 insertions(+), 11 deletions(-)
>>
>> diff --git a/gcc/attribs.c b/gcc/attribs.c
>> index b8f58a74596..9064434e5f2 100644
>> --- a/gcc/attribs.c
>> +++ b/gcc/attribs.c
>> @@ -1584,3 +1584,20 @@ attribute_list_contained (const_tree l1, const_tree l2)
>>  
>>    return 1;
>>  }
>> +
>> +
> 
> Can you please add a function comment (and in addition to arguments explain
> there why lookup_attribute is split into the two parts)?

Yes.

> 
>> +tree
>> +private_lookup_attribute (const char *attr_name, size_t attr_len, tree list)
>> +{
>> +  while (list)
>> +    {
> 
>> @@ -151,17 +156,7 @@ lookup_attribute (const char *attr_name, tree list)
>>        /* Do the strlen() before calling the out-of-line implementation.
>>  	 In most cases attr_name is a string constant, and the compiler
>>  	 will optimize the strlen() away.  */
> 
> Part of the comment is of course here and that comment didn't make any sense
> when everything was inlined.

You're completely right.

> 
>> -      while (list)
>> -	{
>> -	  tree attr = get_attribute_name (list);
>> -	  size_t ident_len = IDENTIFIER_LENGTH (attr);
>> -	  if (cmp_attribs (attr_name, attr_len, IDENTIFIER_POINTER (attr),
>> -			   ident_len))
>> -	    break;
>> -	  list = TREE_CHAIN (list);
>> -	}
>> -
>> -      return list;
>> +      return private_lookup_attribute (attr_name, attr_len, list);
>>      }
>>  }
> 
> LGTM with the comment added.  In theory fnsplit could handle that too,
> but 1) it would emit out of line stuff in every TU separately 2) the
> compiler doesn't know that NULL DECL_ATTRIBUTES is so common (it could
> with profiledbootstrap).  And of course LTO can decide to inline it
> from attribs.c back anyway if there are reasons why it would be beneficial
> somewhere (but I doubt it is beneficial at least in most spots).

Doing it as it was is the right way ;)
Installed as r252022.

Martin

> 
> 	Jakub
> 

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

end of thread, other threads:[~2017-09-12 14:25 UTC | newest]

Thread overview: 37+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-06-13 12:32 [PATCH][RFC] Canonize names of attributes Martin Liška
2017-06-13 13:20 ` Richard Biener
2017-06-14  7:48   ` Martin Liška
2017-06-14  9:07     ` Richard Biener
2017-06-14 11:03       ` Martin Liška
2017-06-14 11:19         ` Richard Biener
2017-06-14 16:40       ` Joseph Myers
2017-06-28 14:45         ` Martin Liška
2017-06-14 17:24 ` Jason Merrill
2017-06-16  0:07   ` Martin Sebor
2017-06-28 14:46   ` Martin Liška
2017-06-28 16:06     ` Joseph Myers
2017-06-28 19:01       ` Jason Merrill
2017-06-30  9:23         ` [PATCH v2][RFC] " Martin Liška
2017-06-30 19:35           ` Jason Merrill
2017-07-03  9:52             ` Martin Liška
2017-07-03 21:00               ` Jason Merrill
2017-07-11 13:38                 ` Martin Liška
2017-07-11 15:52                   ` Jason Merrill
2017-07-13 13:48                     ` Martin Liška
2017-07-13 13:51                       ` [RFC][PATCH] Do refactoring of attribute functions and move them to attribs.[hc] Martin Liška
2017-07-14  7:23                         ` Jeff Law
2017-07-14  7:40                           ` Martin Liška
2017-08-04 13:53                           ` Martin Liška
2017-08-08  4:37                             ` Martin Liška
2017-08-08  9:14                               ` Tom de Vries
2017-09-12  7:55                         ` Jakub Jelinek
2017-09-12 11:31                           ` Martin Liška
2017-09-12 11:40                             ` Jakub Jelinek
2017-09-12 14:25                               ` Martin Liška
2017-07-27 12:57                       ` [PATCH v2][RFC] Canonize names of attributes Martin Liška
2017-08-02 11:25                       ` Joseph Myers
2017-08-04 13:43                         ` Martin Liška
2017-08-04 16:54                           ` Jason Merrill
2017-08-07 16:44                             ` [PATCH][OBVIOUS] Fix missing include of header file in mips.c Martin Liška
2017-08-07 17:10                               ` [PATCH][OBVIOUS] Add missing header file attribs.h to couple of targets Martin Liška
2017-08-02 19:42                       ` [PATCH v2][RFC] Canonize names of attributes Jason Merrill

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