OSDN Git Service

* config/xtensa/xtensa.c (xtensa_va_arg): Fix to handle arguments
[pf3gnuchains/gcc-fork.git] / gcc / attribs.c
index 73d9d39..74786a5 100644 (file)
@@ -1,6 +1,6 @@
 /* Functions dealing with attribute handling, used by most front ends.
-   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
-   Free Software Foundation, Inc.
+   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
+   2002 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -32,6 +32,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "obstack.h"
 #include "cpplib.h"
 #include "target.h"
+#include "langhooks.h"
 
 static void init_attributes            PARAMS ((void));
 
@@ -51,6 +52,8 @@ static tree handle_noreturn_attribute PARAMS ((tree *, tree, tree, int,
                                                 bool *));
 static tree handle_noinline_attribute  PARAMS ((tree *, tree, tree, int,
                                                 bool *));
+static tree handle_always_inline_attribute PARAMS ((tree *, tree, tree, int,
+                                                   bool *));
 static tree handle_used_attribute      PARAMS ((tree *, tree, tree, int,
                                                 bool *));
 static tree handle_unused_attribute    PARAMS ((tree *, tree, tree, int,
@@ -73,6 +76,8 @@ static tree handle_weak_attribute     PARAMS ((tree *, tree, tree, int,
                                                 bool *));
 static tree handle_alias_attribute     PARAMS ((tree *, tree, tree, int,
                                                 bool *));
+static tree handle_visibility_attribute        PARAMS ((tree *, tree, tree, int,
+                                                bool *));
 static tree handle_no_instrument_function_attribute PARAMS ((tree *, tree,
                                                             tree, int,
                                                             bool *));
@@ -82,6 +87,8 @@ static tree handle_no_limit_stack_attribute PARAMS ((tree *, tree, tree, int,
                                                     bool *));
 static tree handle_pure_attribute      PARAMS ((tree *, tree, tree, int,
                                                 bool *));
+static tree handle_deprecated_attribute        PARAMS ((tree *, tree, tree, int,
+                                                bool *));
 static tree handle_vector_size_attribute PARAMS ((tree *, tree, tree, int,
                                                  bool *));
 static tree vector_size_helper PARAMS ((tree, tree));
@@ -107,6 +114,8 @@ static const struct attribute_spec c_common_attribute_table[] =
                              handle_noreturn_attribute },
   { "noinline",               0, 0, true,  false, false,
                              handle_noinline_attribute },
+  { "always_inline",          0, 0, true,  false, false,
+                             handle_always_inline_attribute },
   { "used",                   0, 0, true,  false, false,
                              handle_used_attribute },
   { "unused",                 0, 0, false, false, false,
@@ -138,8 +147,12 @@ static const struct attribute_spec c_common_attribute_table[] =
                              handle_no_limit_stack_attribute },
   { "pure",                   0, 0, true,  false, false,
                              handle_pure_attribute },
+  { "deprecated",             0, 0, false, false, false,
+                             handle_deprecated_attribute },
   { "vector_size",           1, 1, false, true, false,
                              handle_vector_size_attribute },
+  { "visibility",            1, 1, true,  false, false,
+                             handle_visibility_attribute },
   { NULL,                     0, 0, false, false, false, NULL }
 };
 
@@ -165,7 +178,7 @@ static void
 init_attributes ()
 {
 #ifdef ENABLE_CHECKING
-  int i;
+  size_t i;
 #endif
 
   attribute_tables[0]
@@ -176,9 +189,7 @@ init_attributes ()
 
 #ifdef ENABLE_CHECKING
   /* Make some sanity checks on the attribute tables.  */
-  for (i = 0;
-       i < (int) (sizeof (attribute_tables) / sizeof (attribute_tables[0]));
-       i++)
+  for (i = 0; i < ARRAY_SIZE (attribute_tables); i++)
     {
       int j;
 
@@ -210,9 +221,7 @@ init_attributes ()
     }
 
   /* Check that each name occurs just once in each table.  */
-  for (i = 0;
-       i < (int) (sizeof (attribute_tables) / sizeof (attribute_tables[0]));
-       i++)
+  for (i = 0; i < ARRAY_SIZE (attribute_tables); i++)
     {
       int j, k;
       for (j = 0; attribute_tables[i][j].name != NULL; j++)
@@ -222,16 +231,11 @@ init_attributes ()
            abort ();
     }
   /* Check that no name occurs in more than one table.  */
-  for (i = 0;
-       i < (int) (sizeof (attribute_tables) / sizeof (attribute_tables[0]));
-       i++)
+  for (i = 0; i < ARRAY_SIZE (attribute_tables); i++)
     {
-      int j, k, l;
+      size_t j, k, l;
 
-      for (j = i + 1;
-          j < ((int) (sizeof (attribute_tables)
-                      / sizeof (attribute_tables[0])));
-          j++)
+      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++)
            if (!strcmp (attribute_tables[i][k].name,
@@ -271,7 +275,7 @@ decl_attributes (node, attributes, flags)
 
   if (DECL_P (*node) && TREE_CODE (*node) == FUNCTION_DECL
       && !(flags & (int) ATTR_FLAG_BUILT_IN))
-    insert_default_attributes (*node);
+    (*lang_hooks.insert_default_attributes) (*node);
 
   for (a = attributes; a; a = TREE_CHAIN (a))
     {
@@ -280,12 +284,9 @@ decl_attributes (node, attributes, flags)
       tree *anode = node;
       const struct attribute_spec *spec = NULL;
       bool no_add_attrs = 0;
-      int i;
+      size_t i;
 
-      for (i = 0;
-          i < ((int) (sizeof (attribute_tables)
-                      / sizeof (attribute_tables[0])));
-          i++)
+      for (i = 0; i < ARRAY_SIZE (attribute_tables); i++)
        {
          int j;
 
@@ -334,8 +335,15 @@ decl_attributes (node, attributes, flags)
            }
        }
 
+      /* If we require a type, but were passed a decl, set up to make a
+        new type and update the one in the decl.  ATTR_FLAG_TYPE_IN_PLACE
+        would have applied if we'd been passed a type, but we cannot modify
+        the decl's type in place here.  */
       if (spec->type_required && DECL_P (*anode))
-       anode = &TREE_TYPE (*anode);
+       {
+         anode = &TREE_TYPE (*anode);
+         flags &= ~(int) ATTR_FLAG_TYPE_IN_PLACE;
+       }
 
       if (spec->function_type_required && TREE_CODE (*anode) != FUNCTION_TYPE
          && TREE_CODE (*anode) != METHOD_TYPE)
@@ -371,7 +379,9 @@ decl_attributes (node, attributes, flags)
 
       /* Layout the decl in case anything changed.  */
       if (spec->type_required && DECL_P (*node)
-         && TREE_CODE (*node) == VAR_DECL)
+         && (TREE_CODE (*node) == VAR_DECL
+             || TREE_CODE (*node) == PARM_DECL
+             || TREE_CODE (*node) == RESULT_DECL))
        {
          /* Force a recalculation of mode and size.  */
          DECL_MODE (*node) = VOIDmode;
@@ -552,6 +562,31 @@ handle_noinline_attribute (node, name, args, flags, no_add_attrs)
   return NULL_TREE;
 }
 
+/* Handle a "always_inline" attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+static tree
+handle_always_inline_attribute (node, name, args, flags, no_add_attrs)
+     tree *node;
+     tree name;
+     tree args ATTRIBUTE_UNUSED;
+     int flags ATTRIBUTE_UNUSED;
+     bool *no_add_attrs;
+{
+  if (TREE_CODE (*node) == FUNCTION_DECL)
+    {
+      /* Do nothing else, just set the attribute.  We'll get at
+        it later with lookup_attribute.  */
+    }
+  else
+    {
+      warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+      *no_add_attrs = true;
+    }
+
+  return NULL_TREE;
+}
+
 /* Handle a "used" attribute; arguments as in
    struct attribute_spec.handler.  */
 
@@ -800,8 +835,8 @@ handle_mode_attribute (node, name, args, flags, no_add_attrs)
 
       if (mode == VOIDmode)
        error ("unknown machine mode `%s'", p);
-      else if (0 == (typefm = type_for_mode (mode,
-                                            TREE_UNSIGNED (type))))
+      else if (0 == (typefm = (*lang_hooks.types.type_for_mode)
+                    (mode, TREE_UNSIGNED (type))))
        error ("no data type for mode `%s'", p);
       else
        *node = typefm;
@@ -1008,7 +1043,6 @@ handle_alias_attribute (node, name, args, flags, no_add_attrs)
        DECL_INITIAL (decl) = error_mark_node;
       else
        DECL_EXTERNAL (decl) = 0;
-      assemble_alias (decl, id);
     }
   else
     {
@@ -1019,6 +1053,48 @@ handle_alias_attribute (node, name, args, flags, no_add_attrs)
   return NULL_TREE;
 }
 
+/* Handle an "visibility" attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+static tree
+handle_visibility_attribute (node, name, args, flags, no_add_attrs)
+     tree *node;
+     tree name;
+     tree args;
+     int flags ATTRIBUTE_UNUSED;
+     bool *no_add_attrs;
+{
+  tree decl = *node;
+
+  if (decl_function_context (decl) != 0 || ! TREE_PUBLIC (decl))
+    {
+      warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
+      *no_add_attrs = true;
+    }
+  else
+    {
+      tree id;
+
+      id = TREE_VALUE (args);
+      if (TREE_CODE (id) != STRING_CST)
+       {
+         error ("visibility arg not a string");
+         *no_add_attrs = true;
+         return NULL_TREE;
+       }
+      if (strcmp (TREE_STRING_POINTER (id), "hidden")
+         && strcmp (TREE_STRING_POINTER (id), "protected")
+         && strcmp (TREE_STRING_POINTER (id), "internal"))
+       {
+         error ("visibility arg must be one of \"hidden\", \"protected\" or \"internal\"");
+         *no_add_attrs = true;
+         return NULL_TREE;
+       }
+    }
+
+  return NULL_TREE;
+}
+
 /* Handle a "no_instrument_function" attribute; arguments as in
    struct attribute_spec.handler.  */
 
@@ -1131,6 +1207,67 @@ handle_pure_attribute (node, name, args, flags, no_add_attrs)
   return NULL_TREE;
 }
 
+/* Handle a "deprecated" attribute; arguments as in
+   struct attribute_spec.handler.  */
+   
+static tree
+handle_deprecated_attribute (node, name, args, flags, no_add_attrs)
+     tree *node;
+     tree name;
+     tree args ATTRIBUTE_UNUSED;
+     int flags;
+     bool *no_add_attrs;
+{
+  tree type = NULL_TREE;
+  int warn = 0;
+  const char *what = NULL;
+  
+  if (DECL_P (*node))
+    {
+      tree decl = *node;
+      type = TREE_TYPE (decl);
+      
+      if (TREE_CODE (decl) == TYPE_DECL
+         || TREE_CODE (decl) == PARM_DECL
+         || TREE_CODE (decl) == VAR_DECL
+         || TREE_CODE (decl) == FUNCTION_DECL
+         || TREE_CODE (decl) == FIELD_DECL)
+       TREE_DEPRECATED (decl) = 1;
+      else
+       warn = 1;
+    }
+  else if (TYPE_P (*node))
+    {
+      if (!(flags & (int) ATTR_FLAG_TYPE_IN_PLACE))
+       *node = build_type_copy (*node);
+      TREE_DEPRECATED (*node) = 1;
+      type = *node;
+    }
+  else
+    warn = 1;
+  
+  if (warn)
+    {
+      *no_add_attrs = true;
+      if (type && TYPE_NAME (type))
+       {
+         if (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE)
+           what = IDENTIFIER_POINTER (TYPE_NAME (*node));
+         else if (TREE_CODE (TYPE_NAME (type)) == TYPE_DECL
+                  && DECL_NAME (TYPE_NAME (type)))
+           what = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type)));
+       }
+      if (what)
+       warning ("`%s' attribute ignored for `%s'",
+                 IDENTIFIER_POINTER (name), what);
+      else
+       warning ("`%s' attribute ignored", 
+                     IDENTIFIER_POINTER (name));
+    }
+
+  return NULL_TREE;
+}
+
 /* Handle a "vector_size" attribute; arguments as in
    struct attribute_spec.handler.  */
 
@@ -1142,20 +1279,20 @@ handle_vector_size_attribute (node, name, args, flags, no_add_attrs)
      int flags ATTRIBUTE_UNUSED;
      bool *no_add_attrs;
 {
-  unsigned int vecsize, nunits;
+  unsigned HOST_WIDE_INT vecsize, nunits;
   enum machine_mode mode, orig_mode, new_mode;
   tree type = *node, new_type;
 
   *no_add_attrs = true;
 
-  if (TREE_CODE (TREE_VALUE (args)) != INTEGER_CST)
+  if (! host_integerp (TREE_VALUE (args), 1))
     {
       warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
       return NULL_TREE;
     }
 
   /* Get the vector size (in bytes).  */
-  vecsize = TREE_INT_CST_LOW (TREE_VALUE (args));
+  vecsize = tree_low_cst (TREE_VALUE (args), 1);
 
   /* We need to provide for vector pointers, vector arrays, and
      functions returning vectors.  For example:
@@ -1173,9 +1310,10 @@ handle_vector_size_attribute (node, name, args, flags, no_add_attrs)
   /* Get the mode of the type being modified.  */
   orig_mode = TYPE_MODE (type);
 
-  if (TREE_CODE (type) == RECORD_TYPE ||
-      (GET_MODE_CLASS (orig_mode) != MODE_FLOAT
-       && GET_MODE_CLASS (orig_mode) != MODE_INT))
+  if (TREE_CODE (type) == RECORD_TYPE
+      || (GET_MODE_CLASS (orig_mode) != MODE_FLOAT
+         && GET_MODE_CLASS (orig_mode) != MODE_INT)
+      || ! host_integerp (TYPE_SIZE_UNIT (type), 1))
     {
       error ("invalid vector type for attribute `%s'",
             IDENTIFIER_POINTER (name));
@@ -1183,7 +1321,7 @@ handle_vector_size_attribute (node, name, args, flags, no_add_attrs)
     }
 
   /* Calculate how many units fit in the vector.  */
-  nunits = vecsize / TREE_INT_CST_LOW (TYPE_SIZE_UNIT (type));
+  nunits = vecsize / tree_low_cst (TYPE_SIZE_UNIT (type), 1);
 
   /* Find a suitably sized vector.  */
   new_mode = VOIDmode;
@@ -1192,7 +1330,8 @@ handle_vector_size_attribute (node, name, args, flags, no_add_attrs)
                                        : MODE_VECTOR_FLOAT);
        mode != VOIDmode;
        mode = GET_MODE_WIDER_MODE (mode))
-    if (vecsize == GET_MODE_SIZE (mode)        && nunits == GET_MODE_NUNITS (mode))
+    if (vecsize == GET_MODE_SIZE (mode)
+       && nunits == (unsigned HOST_WIDE_INT) GET_MODE_NUNITS (mode))
       {
        new_mode = mode;
        break;
@@ -1202,12 +1341,34 @@ handle_vector_size_attribute (node, name, args, flags, no_add_attrs)
     error ("no vector mode with the size and type specified could be found");
   else
     {
-      new_type = type_for_mode (new_mode, TREE_UNSIGNED (type));
+      tree index, array, rt;
+
+      new_type = (*lang_hooks.types.type_for_mode) (new_mode,
+                                                   TREE_UNSIGNED (type));
+
       if (!new_type)
-       error ("no vector mode with the size and type specified could be found");
-      else
-       /* Build back pointers if needed.  */
-       *node = vector_size_helper (*node, new_type);
+       {
+         error ("no vector mode with the size and type specified could be found");
+         return NULL_TREE;
+       }
+
+      new_type = build_type_copy (new_type);
+
+      /* Set the debug information here, because this is the only
+        place where we know the underlying type for a vector made
+        with vector_size.  For debugging purposes we pretend a vector
+        is an array within a structure.  */
+      index = build_int_2 (TYPE_VECTOR_SUBPARTS (new_type) - 1, 0);
+      array = build_array_type (type, build_index_type (index));
+      rt = make_node (RECORD_TYPE);
+
+      TYPE_FIELDS (rt) = build_decl (FIELD_DECL, get_identifier ("f"), array);
+      DECL_CONTEXT (TYPE_FIELDS (rt)) = rt;
+      layout_type (rt);
+      TYPE_DEBUG_REPRESENTATION_TYPE (new_type) = rt;
+
+      /* Build back pointers if needed.  */
+      *node = vector_size_helper (*node, new_type);
     }
     
   return NULL_TREE;
@@ -1357,3 +1518,4 @@ strip_attrs (specs_attrs)
 
   return specs;
 }
+