OSDN Git Service

PR c++/15815
[pf3gnuchains/gcc-fork.git] / gcc / tree.c
index bc6d3ae..410acdf 100644 (file)
@@ -48,6 +48,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "tree-iterator.h"
 #include "basic-block.h"
 #include "tree-flow.h"
+#include "opts.h"
 
 /* obstack.[ch] explicitly declined to prototype this.  */
 extern int _obstack_allocated_p (struct obstack *h, void *obj);
@@ -71,6 +72,7 @@ static const char * const tree_node_kind_names[] = {
   "perm_tree_lists",
   "temp_tree_lists",
   "vecs",
+  "binfos",
   "phi_nodes",
   "ssa names",
   "random kinds",
@@ -93,6 +95,9 @@ struct type_hash GTY(())
   tree type;
 };
 
+/* Additional language-dependent binfo slots.  */
+unsigned binfo_lang_slots;
+
 /* Initial size of the hash table (rounded to next prime).  */
 #define TYPE_HASH_INITIAL_SIZE 1000
 
@@ -267,6 +272,8 @@ make_node_stat (enum tree_code code MEM_STAT_DECL)
        kind = id_kind;
       else if (code == TREE_VEC)
        kind = vec_kind;
+      else if (code == TREE_BINFO)
+       kind = binfo_kind;
       else if (code == PHI_NODE)
        kind = phi_kind;
       else if (code == SSA_NAME)
@@ -303,7 +310,10 @@ make_node_stat (enum tree_code code MEM_STAT_DECL)
       DECL_USER_ALIGN (t) = 0;
       DECL_IN_SYSTEM_HEADER (t) = in_system_header;
       DECL_SOURCE_LOCATION (t) = input_location;
-      DECL_UID (t) = next_decl_uid++;
+      if (code == TRANSLATION_UNIT_DECL)
+       DECL_UID (t) = cur_in_fname;
+      else
+       DECL_UID (t) = next_decl_uid++;
 
       /* We have not yet computed the alias set for this declaration.  */
       DECL_POINTER_ALIAS_SET (t) = -1;
@@ -376,7 +386,7 @@ copy_node_stat (tree node MEM_STAT_DECL)
   TREE_VISITED (t) = 0;
   t->common.ann = 0;
 
-  if (TREE_CODE_CLASS (code) == 'd')
+  if (TREE_CODE_CLASS (code) == 'd' && code != TRANSLATION_UNIT_DECL)
     DECL_UID (t) = next_decl_uid++;
   else if (TREE_CODE_CLASS (code) == 't')
     {
@@ -573,6 +583,39 @@ build_complex (tree type, tree real, tree imag)
   return t;
 }
 
+/* Build a BINFO with LEN language slots.  */
+
+tree
+make_tree_binfo_stat (unsigned lang_slots MEM_STAT_DECL)
+{
+  tree t;
+  static unsigned length;
+  
+  if (!length)
+    {
+      length = (offsetof (struct tree_binfo, lang_slots)
+               + (sizeof (((struct tree_binfo *)0)->lang_slots[0])
+                  * lang_slots));
+      binfo_lang_slots = lang_slots;
+    }
+  else if (binfo_lang_slots != lang_slots)
+    abort ();
+  
+#ifdef GATHER_STATISTICS
+  tree_node_counts[(int) binfo_kind]++;
+  tree_node_sizes[(int) binfo_kind] += length;
+#endif
+
+  t = ggc_alloc_zone_stat (length, tree_zone PASS_MEM_STAT);
+
+  memset (t, 0, length);
+
+  TREE_SET_CODE (t, TREE_BINFO);
+
+  return t;
+}
+
+
 /* Build a newly constructed TREE_VEC node of length LEN.  */
 
 tree
@@ -1493,6 +1536,7 @@ tree_node_structure (tree t)
     case PLACEHOLDER_EXPR:     return TS_COMMON;
     case STATEMENT_LIST:       return TS_STATEMENT_LIST;
     case BLOCK:                        return TS_BLOCK;
+    case TREE_BINFO:           return TS_BINFO;
     case VALUE_HANDLE:         return TS_VALUE_HANDLE;
 
     default:
@@ -2308,16 +2352,20 @@ do { tree _node = (NODE); \
     }
              
   /* Now see what's inside.  If it's an INDIRECT_REF, copy our properties from
-     it.  If it's a decl, it's definitely invariant and it's constant if the
-     decl is static.  (Taking the address of a volatile variable is not
-     volatile.)  If it's a constant, the address is both invariant and
-     constant.  Otherwise it's neither.  */
+     it.  If it's a decl, it's invariant and constant if the decl is static.
+     It's also invariant if it's a decl in the current function.  (Taking the
+     address of a volatile variable is not volatile.)  If it's a constant,
+     the address is both invariant and constant.  Otherwise it's neither.  */
   if (TREE_CODE (node) == INDIRECT_REF)
     UPDATE_TITCSE (node);
   else if (DECL_P (node))
     {
-      if (!staticp (node))
+      if (staticp (node))
+       ;
+      else if (decl_function_context (node) == current_function_decl)
        tc = false;
+      else
+       ti = tc = false;
     }
   else if (TREE_CODE_CLASS (TREE_CODE (node)) == 'c')
     ;
@@ -3198,7 +3246,7 @@ type_hash_eq (const void *va, const void *vb)
               || tree_int_cst_equal (TYPE_MAX_VALUE (a->type),
                                      TYPE_MAX_VALUE (b->type)))
              && (TYPE_MIN_VALUE (a->type) == TYPE_MIN_VALUE (b->type)
-                 && tree_int_cst_equal (TYPE_MIN_VALUE (a->type),
+                 || tree_int_cst_equal (TYPE_MIN_VALUE (a->type),
                                         TYPE_MIN_VALUE (b->type))));
 
     case OFFSET_TYPE:
@@ -4641,21 +4689,50 @@ int_fits_type_p (tree c, tree type)
     }
 }
 
+/* Subprogram of following function.  Called by walk_tree.
+
+   Return *TP if it is an automatic variable or parameter of the
+   function passed in as DATA.  */
+
+static tree
+find_var_from_fn (tree *tp, int *walk_subtrees, void *data)
+{
+  tree fn = (tree) data;
+
+  if (TYPE_P (*tp))
+    *walk_subtrees = 0;
+
+  else if (DECL_P (*tp) && lang_hooks.tree_inlining.auto_var_in_fn_p (*tp, fn))
+    return *tp;
+
+  return NULL_TREE;
+}
+
 /* Returns true if T is, contains, or refers to a type with variable
-   size.  This concept is more general than that of C99 'variably
-   modified types': in C99, a struct type is never variably modified
-   because a VLA may not appear as a structure member.  However, in
-   GNU C code like:
+   size.  If FN is nonzero, only return true if a modifier of the type
+   or position of FN is a variable or parameter inside FN.
+
+   This concept is more general than that of C99 'variably modified types':
+   in C99, a struct type is never variably modified because a VLA may not
+   appear as a structure member.  However, in GNU C code like:
 
      struct S { int i[f()]; };
 
    is valid, and other languages may define similar constructs.  */
 
 bool
-variably_modified_type_p (tree type)
+variably_modified_type_p (tree type, tree fn)
 {
   tree t;
 
+/* Test if T is either variable (if FN is zero) or an expression containing
+   a variable in FN.  */
+#define RETURN_TRUE_IF_VAR(T)                                          \
+  do { tree _t = (T);                                                  \
+    if (_t && _t != error_mark_node && TREE_CODE (_t) != INTEGER_CST   \
+        && (!fn || walk_tree (&_t, find_var_from_fn, fn, NULL)))       \
+      return true;  } while (0)
+
   if (type == error_mark_node)
     return false;
 
@@ -4664,9 +4741,8 @@ variably_modified_type_p (tree type)
      We do not yet have a representation of the C99 '[*]' syntax.
      When a representation is chosen, this function should be modified
      to test for that case as well.  */
-  t = TYPE_SIZE (type);
-  if (t && t != error_mark_node && TREE_CODE (t) != INTEGER_CST)
-    return true;
+  RETURN_TRUE_IF_VAR (TYPE_SIZE (type));
+  RETURN_TRUE_IF_VAR (TYPE_SIZE_UNIT(type));
 
   switch (TREE_CODE (type))
     {
@@ -4675,7 +4751,7 @@ variably_modified_type_p (tree type)
     case ARRAY_TYPE:
     case SET_TYPE:
     case VECTOR_TYPE:
-      if (variably_modified_type_p (TREE_TYPE (type)))
+      if (variably_modified_type_p (TREE_TYPE (type), fn))
        return true;
       break;
 
@@ -4683,13 +4759,13 @@ variably_modified_type_p (tree type)
     case METHOD_TYPE:
       /* If TYPE is a function type, it is variably modified if any of the
          parameters or the return type are variably modified.  */
-      if (variably_modified_type_p (TREE_TYPE (type)))
+      if (variably_modified_type_p (TREE_TYPE (type), fn))
          return true;
 
       for (t = TYPE_ARG_TYPES (type);
           t && t != void_list_node;
           t = TREE_CHAIN (t))
-       if (variably_modified_type_p (TREE_VALUE (t)))
+       if (variably_modified_type_p (TREE_VALUE (t), fn))
          return true;
       break;
 
@@ -4700,13 +4776,8 @@ variably_modified_type_p (tree type)
     case CHAR_TYPE:
       /* Scalar types are variably modified if their end points
         aren't constant.  */
-      t = TYPE_MIN_VALUE (type);
-      if (t && t != error_mark_node && TREE_CODE (t) != INTEGER_CST)
-       return true;
-
-      t = TYPE_MAX_VALUE (type);
-      if (t && t != error_mark_node && TREE_CODE (t) != INTEGER_CST)
-       return true;
+      RETURN_TRUE_IF_VAR (TYPE_MIN_VALUE (type));
+      RETURN_TRUE_IF_VAR (TYPE_MAX_VALUE (type));
       break;
 
     case RECORD_TYPE:
@@ -4719,14 +4790,12 @@ variably_modified_type_p (tree type)
       for (t = TYPE_FIELDS (type); t; t = TREE_CHAIN (t))
        if (TREE_CODE (t) == FIELD_DECL)
          {
-           tree t1 = DECL_FIELD_OFFSET (t);
-
-           if (t1 && t1 != error_mark_node && TREE_CODE (t1) != INTEGER_CST)
-             return true;
+           RETURN_TRUE_IF_VAR (DECL_FIELD_OFFSET (t));
+           RETURN_TRUE_IF_VAR (DECL_SIZE (t));
+           RETURN_TRUE_IF_VAR (DECL_SIZE_UNIT (t));
 
-           t1 = DECL_SIZE (t);
-           if (t1 && t1 != error_mark_node && TREE_CODE (t1) != INTEGER_CST)
-             return true;
+           if (TREE_CODE (type) == QUAL_UNION_TYPE)
+             RETURN_TRUE_IF_VAR (DECL_QUALIFIER (t));
          }
        break;
 
@@ -4736,7 +4805,9 @@ variably_modified_type_p (tree type)
 
   /* The current language may have other cases to check, but in general,
      all other types are not variably modified.  */
-  return lang_hooks.tree_inlining.var_mod_type_p (type);
+  return lang_hooks.tree_inlining.var_mod_type_p (type, fn);
+
+#undef RETURN_TRUE_IF_VAR
 }
 
 /* Given a DECL or TYPE, return the scope in which it was declared, or
@@ -5270,6 +5341,14 @@ make_or_reuse_type (unsigned size, int unsignedp)
 void
 build_common_tree_nodes (int signed_char)
 {
+  /* This function is called after command line parsing is complete,
+     but before any DECL nodes should have been created.  Therefore,
+     now is the appropriate time to adjust next_decl_uid so that the
+     range 0 .. num_in_fnames-1 is reserved for TRANSLATION_UNIT_DECLs.  */
+  if (next_decl_uid)
+    abort ();
+  next_decl_uid = num_in_fnames;
+
   error_mark_node = make_node (ERROR_MARK);
   TREE_TYPE (error_mark_node) = error_mark_node;