Add C++ attribute abi_tag and -Wabi-tag option.
[gcc.git] / gcc / attribs.c
index 7f43b2af693a32ad3e4969d9a5a624099e637001..0425de9f5b127f65c2bed05f1deb3c55d983c924 100644 (file)
@@ -1,12 +1,13 @@
 /* Functions dealing with attribute handling, used by most front ends.
    Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
-   2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+   2002, 2003, 2004, 2005, 2007, 2008, 2009, 2010
+   Free Software Foundation, Inc.
 
 This file is part of GCC.
 
 GCC is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 2, or (at your option) any later
+Software Foundation; either version 3, or (at your option) any later
 version.
 
 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
@@ -15,9 +16,8 @@ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 for more details.
 
 You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING.  If not, write to the Free
-Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
-02110-1301, USA.  */
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
 
 #include "config.h"
 #include "system.h"
@@ -25,37 +25,172 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
 #include "tm.h"
 #include "tree.h"
 #include "flags.h"
-#include "toplev.h"
-#include "output.h"
-#include "rtl.h"
+#include "diagnostic-core.h"
 #include "ggc.h"
 #include "tm_p.h"
 #include "cpplib.h"
 #include "target.h"
 #include "langhooks.h"
-
-static void init_attributes (void);
+#include "hashtab.h"
+#include "plugin.h"
 
 /* Table of the tables of attributes (common, language, format, machine)
    searched.  */
 static const struct attribute_spec *attribute_tables[4];
 
+/* Substring representation.  */
+
+struct substring
+{
+  const char *str;
+  int length;
+};
+
+DEF_VEC_O (attribute_spec);
+DEF_VEC_ALLOC_O (attribute_spec, heap);
+
+/* Scoped attribute name representation.  */
+
+struct scoped_attributes
+{
+  const char *ns;
+  VEC (attribute_spec, heap) *attributes;
+  htab_t attribute_hash;
+};
+
+DEF_VEC_O (scoped_attributes);
+DEF_VEC_ALLOC_O (scoped_attributes, heap);
+
+/* The table of scope attributes.  */
+static VEC(scoped_attributes, heap) *attributes_table;
+
+static scoped_attributes* find_attribute_namespace (const char*);
+static void register_scoped_attribute (const struct attribute_spec *,
+                                      scoped_attributes *);
+
 static bool attributes_initialized = false;
 
 /* Default empty table of attributes.  */
+
 static const struct attribute_spec empty_attribute_table[] =
 {
-  { NULL, 0, 0, false, false, false, NULL }
+  { NULL, 0, 0, false, false, false, NULL, false }
 };
 
+/* Return base name of the attribute.  Ie '__attr__' is turned into 'attr'.
+   To avoid need for copying, we simply return length of the string.  */
+
+static void
+extract_attribute_substring (struct substring *str)
+{
+  if (str->length > 4 && str->str[0] == '_' && str->str[1] == '_'
+      && str->str[str->length - 1] == '_' && str->str[str->length - 2] == '_')
+    {
+      str->length -= 4;
+      str->str += 2;
+    }
+}
+
+/* Simple hash function to avoid need to scan whole string.  */
+
+static inline hashval_t
+substring_hash (const char *str, int l)
+{
+  return str[0] + str[l - 1] * 256 + l * 65536;
+}
+
+/* Used for attribute_hash.  */
+
+static hashval_t
+hash_attr (const void *p)
+{
+  const struct attribute_spec *const spec = (const struct attribute_spec *) p;
+  const int l = strlen (spec->name);
+
+  return substring_hash (spec->name, l);
+}
+
+/* Used for attribute_hash.  */
+
+static int
+eq_attr (const void *p, const void *q)
+{
+  const struct attribute_spec *const spec = (const struct attribute_spec *) p;
+  const struct substring *const str = (const struct substring *) q;
+
+  return (!strncmp (spec->name, str->str, str->length) && !spec->name[str->length]);
+}
+
+/* Insert an array of attributes ATTRIBUTES into a namespace.  This
+   array must be NULL terminated.  NS is the name of attribute
+   namespace.  The function returns the namespace into which the
+   attributes have been registered.  */
+
+scoped_attributes*
+register_scoped_attributes (const struct attribute_spec * attributes,
+                           const char* ns)
+{
+  scoped_attributes *result = NULL;
+
+  /* See if we already have attributes in the namespace NS.  */
+  result = find_attribute_namespace (ns);
+
+  if (result == NULL)
+    {
+      /* We don't have any namespace NS yet.  Create one.  */
+      scoped_attributes sa;
+
+      if (attributes_table == NULL)
+       attributes_table = VEC_alloc (scoped_attributes, heap, 64);
+
+      memset (&sa, 0, sizeof (sa));
+      sa.ns = ns;
+      sa.attributes = VEC_alloc (attribute_spec, heap, 64);
+      result = VEC_safe_push (scoped_attributes, heap, attributes_table, sa);
+      result->attribute_hash = htab_create (200, hash_attr, eq_attr, NULL);
+    }
+
+  /* Really add the attributes to their namespace now.  */
+  for (unsigned i = 0; attributes[i].name != NULL; ++i)
+    {
+      VEC_safe_push (attribute_spec, heap,
+                    result->attributes, attributes[i]);
+      register_scoped_attribute (&attributes[i], result);
+    }
+
+  gcc_assert (result != NULL);
+
+  return result;
+}
+
+/* Return the namespace which name is NS, NULL if none exist.  */
+
+static scoped_attributes*
+find_attribute_namespace (const char* ns)
+{
+  unsigned ix;
+  scoped_attributes *iter;
+
+  FOR_EACH_VEC_ELT (scoped_attributes, attributes_table, ix, iter)
+    if (ns == iter->ns
+       || (iter->ns != NULL
+           && ns != NULL
+           && !strcmp (iter->ns, ns)))
+      return iter;
+  return NULL;
+}
+
 /* Initialize attribute tables, and make some sanity checks
    if --enable-checking.  */
 
-static void
+void
 init_attributes (void)
 {
   size_t i;
 
+  if (attributes_initialized)
+    return;
+
   attribute_tables[0] = lang_hooks.common_attribute_table;
   attribute_tables[1] = lang_hooks.attribute_table;
   attribute_tables[2] = lang_hooks.format_attribute_table;
@@ -77,21 +212,21 @@ init_attributes (void)
          /* The name must not begin and end with __.  */
          const char *name = attribute_tables[i][j].name;
          int len = strlen (name);
-         
+
          gcc_assert (!(name[0] == '_' && name[1] == '_'
                        && name[len - 1] == '_' && name[len - 2] == '_'));
-         
+
          /* The minimum and maximum lengths must be consistent.  */
          gcc_assert (attribute_tables[i][j].min_length >= 0);
-         
+
          gcc_assert (attribute_tables[i][j].max_length == -1
                      || (attribute_tables[i][j].max_length
                          >= attribute_tables[i][j].min_length));
-         
+
          /* An attribute cannot require both a DECL and a TYPE.  */
          gcc_assert (!attribute_tables[i][j].decl_required
                      || !attribute_tables[i][j].type_required);
-         
+
          /* If an attribute requires a function type, in particular
             it requires a type.  */
          gcc_assert (!attribute_tables[i][j].function_type_required
@@ -108,7 +243,8 @@ init_attributes (void)
          gcc_assert (strcmp (attribute_tables[i][j].name,
                              attribute_tables[i][k].name));
     }
-  /* Check that no name occurs in more than one table.  */
+  /* Check that no name occurs in more than one table.  Names that
+     begin with '*' are exempt, and may be overridden.  */
   for (i = 0; i < ARRAY_SIZE (attribute_tables); i++)
     {
       size_t j, k, l;
@@ -116,13 +252,96 @@ init_attributes (void)
       for (j = i + 1; j < ARRAY_SIZE (attribute_tables); j++)
        for (k = 0; attribute_tables[i][k].name != NULL; k++)
          for (l = 0; attribute_tables[j][l].name != NULL; l++)
-           gcc_assert (strcmp (attribute_tables[i][k].name,
-                               attribute_tables[j][l].name));
+           gcc_assert (attribute_tables[i][k].name[0] == '*'
+                       || strcmp (attribute_tables[i][k].name,
+                                  attribute_tables[j][l].name));
     }
 #endif
 
+  for (i = 0; i < ARRAY_SIZE (attribute_tables); ++i)
+    /* Put all the GNU attributes into the "gnu" namespace.  */
+    register_scoped_attributes (attribute_tables[i], "gnu");
+
+  invoke_plugin_callbacks (PLUGIN_ATTRIBUTES, NULL);
   attributes_initialized = true;
 }
+
+/* Insert a single ATTR into the attribute table.  */
+
+void
+register_attribute (const struct attribute_spec *attr)
+{
+  register_scoped_attribute (attr, find_attribute_namespace ("gnu"));
+}
+
+/* Insert a single attribute ATTR into a namespace of attributes.  */
+
+static void
+register_scoped_attribute (const struct attribute_spec *attr,
+                          scoped_attributes *name_space)
+{
+  struct substring str;
+  void **slot;
+
+  gcc_assert (attr != NULL && name_space != NULL);
+
+  gcc_assert (name_space->attribute_hash != NULL);
+
+  str.str = attr->name;
+  str.length = strlen (str.str);
+
+  /* Attribute names in the table must be in the form 'text' and not
+     in the form '__text__'.  */
+  gcc_assert (str.length > 0 && str.str[0] != '_');
+
+  slot = htab_find_slot_with_hash (name_space->attribute_hash, &str,
+                                  substring_hash (str.str, str.length),
+                                  INSERT);
+  gcc_assert (!*slot || attr->name[0] == '*');
+  *slot = (void *) CONST_CAST (struct attribute_spec *, attr);
+}
+
+/* Return the spec for the scoped attribute with namespace NS and
+   name NAME.   */
+
+const struct attribute_spec *
+lookup_scoped_attribute_spec (const_tree ns, const_tree name)
+{
+  struct substring attr;
+  scoped_attributes *attrs;
+
+  const char *ns_str = (ns != NULL_TREE) ? IDENTIFIER_POINTER (ns): NULL;
+
+  attrs = find_attribute_namespace (ns_str);
+
+  if (attrs == NULL)
+    return NULL;
+
+  attr.str = IDENTIFIER_POINTER (name);
+  attr.length = IDENTIFIER_LENGTH (name);
+  extract_attribute_substring (&attr);
+  return (const struct attribute_spec *)
+    htab_find_with_hash (attrs->attribute_hash, &attr,
+                        substring_hash (attr.str, attr.length));
+}
+
+/* Return the spec for the attribute named NAME.  If NAME is a TREE_LIST,
+   it also specifies the attribute namespace.  */
+
+const struct attribute_spec *
+lookup_attribute_spec (const_tree name)
+{
+  tree ns;
+  if (TREE_CODE (name) == TREE_LIST)
+    {
+      ns = TREE_PURPOSE (name);
+      name = TREE_VALUE (name);
+    }
+  else
+    ns = get_identifier ("gnu");
+  return lookup_scoped_attribute_spec (ns, name);
+}
+
 \f
 /* Process the attributes listed in ATTRIBUTES and install them in *NODE,
    which is either a DECL (including a TYPE_DECL) or a TYPE.  If a DECL,
@@ -139,49 +358,110 @@ decl_attributes (tree *node, tree attributes, int flags)
   tree a;
   tree returned_attrs = NULL_TREE;
 
+  if (TREE_TYPE (*node) == error_mark_node || attributes == error_mark_node)
+    return NULL_TREE;
+
   if (!attributes_initialized)
     init_attributes ();
 
+  /* If this is a function and the user used #pragma GCC optimize, add the
+     options to the attribute((optimize(...))) list.  */
+  if (TREE_CODE (*node) == FUNCTION_DECL && current_optimize_pragma)
+    {
+      tree cur_attr = lookup_attribute ("optimize", attributes);
+      tree opts = copy_list (current_optimize_pragma);
+
+      if (! cur_attr)
+       attributes
+         = tree_cons (get_identifier ("optimize"), opts, attributes);
+      else
+       TREE_VALUE (cur_attr) = chainon (opts, TREE_VALUE (cur_attr));
+    }
+
+  if (TREE_CODE (*node) == FUNCTION_DECL
+      && optimization_current_node != optimization_default_node
+      && !DECL_FUNCTION_SPECIFIC_OPTIMIZATION (*node))
+    DECL_FUNCTION_SPECIFIC_OPTIMIZATION (*node) = optimization_current_node;
+
+  /* If this is a function and the user used #pragma GCC target, add the
+     options to the attribute((target(...))) list.  */
+  if (TREE_CODE (*node) == FUNCTION_DECL
+      && current_target_pragma
+      && targetm.target_option.valid_attribute_p (*node, NULL_TREE,
+                                                 current_target_pragma, 0))
+    {
+      tree cur_attr = lookup_attribute ("target", attributes);
+      tree opts = copy_list (current_target_pragma);
+
+      if (! cur_attr)
+       attributes = tree_cons (get_identifier ("target"), opts, attributes);
+      else
+       TREE_VALUE (cur_attr) = chainon (opts, TREE_VALUE (cur_attr));
+    }
+
+  /* A "naked" function attribute implies "noinline" and "noclone" for
+     those targets that support it.  */
+  if (TREE_CODE (*node) == FUNCTION_DECL
+      && attributes
+      && lookup_attribute_spec (get_identifier ("naked"))
+      && lookup_attribute ("naked", attributes) != NULL)
+    {
+      if (lookup_attribute ("noinline", attributes) == NULL)
+       attributes = tree_cons (get_identifier ("noinline"), NULL, attributes);
+
+      if (lookup_attribute ("noclone", attributes) == NULL)
+       attributes = tree_cons (get_identifier ("noclone"),  NULL, attributes);
+    }
+
   targetm.insert_attributes (*node, &attributes);
 
   for (a = attributes; a; a = TREE_CHAIN (a))
     {
-      tree name = TREE_PURPOSE (a);
+      tree ns = get_attribute_namespace (a);
+      tree name = get_attribute_name (a);
       tree args = TREE_VALUE (a);
       tree *anode = node;
-      const struct attribute_spec *spec = NULL;
+      const struct attribute_spec *spec =
+       lookup_scoped_attribute_spec (ns, name);
       bool no_add_attrs = 0;
+      int fn_ptr_quals = 0;
       tree fn_ptr_tmp = NULL_TREE;
-      size_t i;
 
-      for (i = 0; i < ARRAY_SIZE (attribute_tables); i++)
+      if (spec == NULL)
        {
-         int j;
-
-         for (j = 0; attribute_tables[i][j].name != NULL; j++)
+         if (!(flags & (int) ATTR_FLAG_BUILT_IN))
            {
-             if (is_attribute_p (attribute_tables[i][j].name, name))
-               {
-                 spec = &attribute_tables[i][j];
-                 break;
-               }
+             if (ns == NULL_TREE || !cxx11_attribute_p (a))
+               warning (OPT_Wattributes, "%qE attribute directive ignored",
+                        name);
+             else
+               warning (OPT_Wattributes,
+                        "%<%E::%E%> scoped attribute directive ignored",
+                        ns, name);
            }
-         if (spec != NULL)
-           break;
-       }
-
-      if (spec == NULL)
-       {
-         warning (OPT_Wattributes, "%qs attribute directive ignored",
-                  IDENTIFIER_POINTER (name));
          continue;
        }
       else if (list_length (args) < spec->min_length
               || (spec->max_length >= 0
                   && list_length (args) > spec->max_length))
        {
-         error ("wrong number of arguments specified for %qs attribute",
-                IDENTIFIER_POINTER (name));
+         error ("wrong number of arguments specified for %qE attribute",
+                name);
+         continue;
+       }
+      gcc_assert (is_attribute_p (spec->name, name));
+
+      if (TYPE_P (*node)
+         && cxx11_attribute_p (a)
+         && !(flags & ATTR_FLAG_TYPE_IN_PLACE))
+       {
+         /* This is a c++11 attribute that appertains to a
+            type-specifier, outside of the definition of, a class
+            type.  Ignore it.  */
+         warning (OPT_Wattributes, "attribute ignored");
+         inform (input_location,
+                 "an attribute that appertains to a type-specifier "
+                 "is ignored");
          continue;
        }
 
@@ -197,8 +477,8 @@ decl_attributes (tree *node, tree attributes, int flags)
            }
          else
            {
-             warning (OPT_Wattributes, "%qs attribute does not apply to types",
-                      IDENTIFIER_POINTER (name));
+             warning (OPT_Wattributes, "%qE attribute does not apply to types",
+                      name);
              continue;
            }
        }
@@ -210,7 +490,11 @@ decl_attributes (tree *node, tree attributes, int flags)
       if (spec->type_required && DECL_P (*anode))
        {
          anode = &TREE_TYPE (*anode);
-         flags &= ~(int) ATTR_FLAG_TYPE_IN_PLACE;
+         /* Allow ATTR_FLAG_TYPE_IN_PLACE for the type's naming decl.  */
+         if (!(TREE_CODE (*anode) == TYPE_DECL
+               && *anode == TYPE_NAME (TYPE_MAIN_VARIANT
+                                       (TREE_TYPE (*anode)))))
+           flags &= ~(int) ATTR_FLAG_TYPE_IN_PLACE;
        }
 
       if (spec->function_type_required && TREE_CODE (*anode) != FUNCTION_TYPE
@@ -227,9 +511,10 @@ decl_attributes (tree *node, tree attributes, int flags)
                 pull out the target type now, frob it as appropriate, and
                 rebuild the pointer type later.
 
-                This would all be simpler if attributes were part of the
-                declarator, grumble grumble.  */
+                This would all be simpler if attributes were part of the
+                declarator, grumble grumble.  */
              fn_ptr_tmp = TREE_TYPE (*anode);
+             fn_ptr_quals = TYPE_QUALS (*anode);
              anode = &fn_ptr_tmp;
              flags &= ~(int) ATTR_FLAG_TYPE_IN_PLACE;
            }
@@ -244,16 +529,30 @@ decl_attributes (tree *node, tree attributes, int flags)
              && TREE_CODE (*anode) != METHOD_TYPE)
            {
              warning (OPT_Wattributes,
-                      "%qs attribute only applies to function types",
-                      IDENTIFIER_POINTER (name));
+                      "%qE attribute only applies to function types",
+                      name);
              continue;
            }
        }
 
+      if (TYPE_P (*anode)
+         && (flags & (int) ATTR_FLAG_TYPE_IN_PLACE)
+         && TYPE_SIZE (*anode) != NULL_TREE)
+       {
+         warning (OPT_Wattributes, "type attributes ignored after type is already defined");
+         continue;
+       }
+
       if (spec->handler != NULL)
-       returned_attrs = chainon ((*spec->handler) (anode, name, args,
-                                                   flags, &no_add_attrs),
-                                 returned_attrs);
+       {
+         int cxx11_flag =
+           cxx11_attribute_p (a) ? ATTR_FLAG_CXX11 : 0;
+
+         returned_attrs = chainon ((*spec->handler) (anode, name, args,
+                                                     flags|cxx11_flag,
+                                                     &no_add_attrs),
+                                   returned_attrs);
+       }
 
       /* Layout the decl in case anything changed.  */
       if (spec->type_required && DECL_P (*node)
@@ -318,6 +617,8 @@ decl_attributes (tree *node, tree attributes, int flags)
          /* Rebuild the function pointer type and put it in the
             appropriate place.  */
          fn_ptr_tmp = build_pointer_type (fn_ptr_tmp);
+         if (fn_ptr_quals)
+           fn_ptr_tmp = build_qualified_type (fn_ptr_tmp, fn_ptr_quals);
          if (DECL_P (*node))
            TREE_TYPE (*node) = fn_ptr_tmp;
          else
@@ -330,3 +631,62 @@ decl_attributes (tree *node, tree attributes, int flags)
 
   return returned_attrs;
 }
+
+/* Return TRUE iff ATTR has been parsed by the front-end as a C++-11
+   attribute.
+
+   When G++ parses a C++11 attribute, it is represented as
+   a TREE_LIST which TREE_PURPOSE is itself a TREE_LIST.  TREE_PURPOSE
+   (TREE_PURPOSE (ATTR)) is the namespace of the attribute, and the
+   TREE_VALUE (TREE_PURPOSE (ATTR)) is its non-qualified name.  Please
+   use get_attribute_namespace and get_attribute_name to retrieve the
+   namespace and name of the attribute, as these accessors work with
+   GNU attributes as well.  */
+
+bool
+cxx11_attribute_p (const_tree attr)
+{
+  if (attr == NULL_TREE
+      || TREE_CODE (attr) != TREE_LIST)
+    return false;
+
+  return (TREE_CODE (TREE_PURPOSE (attr)) == TREE_LIST);
+}
+
+/* Return the name of the attribute ATTR.  This accessor works on GNU
+   and C++11 (scoped) attributes.
+
+   Please read the comments of cxx11_attribute_p to understand the
+   format of attributes.  */
+
+tree
+get_attribute_name (const_tree attr)
+{
+  if (cxx11_attribute_p (attr))
+    return TREE_VALUE (TREE_PURPOSE (attr));
+  return TREE_PURPOSE (attr);
+}
+
+/* Return the namespace of the attribute ATTR.  This accessor works on
+   GNU and C++11 (scoped) attributes.  On GNU attributes,
+   it returns an identifier tree for the string "gnu".
+
+   Please read the comments of cxx11_attribute_p to understand the
+   format of attributes.  */
+
+tree
+get_attribute_namespace (const_tree attr)
+{
+  if (cxx11_attribute_p (attr))
+    return TREE_PURPOSE (TREE_PURPOSE (attr));
+  return get_identifier ("gnu");
+}
+
+/* Subroutine of set_method_tm_attributes.  Apply TM attribute ATTR
+   to the method FNDECL.  */
+
+void
+apply_tm_attr (tree fndecl, tree attr)
+{
+  decl_attributes (&TREE_TYPE (fndecl), tree_cons (attr, NULL, NULL), 0);
+}