OSDN Git Service

2003-06-10 Andrew Haley <aph@redhat.com>
[pf3gnuchains/gcc-fork.git] / gcc / tree.c
index 7deaa65..ad4f51c 100644 (file)
@@ -1,6 +1,6 @@
 /* Language-independent node constructors for parse phase of GNU compiler.
    Copyright (C) 1987, 1988, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+   1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -308,7 +308,7 @@ make_node (code)
        DECL_ALIGN (t) = 1;
       DECL_USER_ALIGN (t) = 0;
       DECL_IN_SYSTEM_HEADER (t) = in_system_header;
-      DECL_SOURCE_LINE (t) = lineno;
+      DECL_SOURCE_LINE (t) = input_line;
       DECL_SOURCE_FILE (t) =
        (input_filename) ? input_filename : "<built-in>";
       DECL_UID (t) = next_decl_uid++;
@@ -1031,26 +1031,27 @@ tree
 chainon (op1, op2)
      tree op1, op2;
 {
+  tree t1;
 
-  if (op1)
-    {
-      tree t1;
-#ifdef ENABLE_TREE_CHECKING
-      tree t2;
-#endif
+  if (!op1)
+    return op2;
+  if (!op2)
+    return op1;
+
+  for (t1 = op1; TREE_CHAIN (t1); t1 = TREE_CHAIN (t1))
+    continue;
+  TREE_CHAIN (t1) = op2;
 
-      for (t1 = op1; TREE_CHAIN (t1); t1 = TREE_CHAIN (t1))
-       ;
-      TREE_CHAIN (t1) = op2;
 #ifdef ENABLE_TREE_CHECKING
-      for (t2 = op2; t2; t2 = TREE_CHAIN (t2))
-       if (t2 == t1)
-         abort ();  /* Circularity created.  */
+  {
+    tree t2;
+    for (t2 = op2; t2; t2 = TREE_CHAIN (t2))
+      if (t2 == t1)
+       abort ();  /* Circularity created.  */
+  }
 #endif
-      return op1;
-    }
-  else
-    return op2;
+
+  return op1;
 }
 
 /* Return the last node in a chain of nodes (chained through TREE_CHAIN).  */
@@ -1122,6 +1123,44 @@ tree_cons (purpose, value, chain)
   return node;
 }
 
+/* Return the first expression in a sequence of COMPOUND_EXPRs.  */
+
+tree
+expr_first (tree expr)
+{
+  if (expr == NULL_TREE)
+    return expr;
+  while (TREE_CODE (expr) == COMPOUND_EXPR)
+    expr = TREE_OPERAND (expr, 0);
+  return expr;
+}
+
+/* Return the last expression in a sequence of COMPOUND_EXPRs.  */
+
+tree
+expr_last (tree expr)
+{
+  if (expr == NULL_TREE)
+    return expr;
+  while (TREE_CODE (expr) == COMPOUND_EXPR)
+    expr = TREE_OPERAND (expr, 1);
+  return expr;
+}
+
+/* Return the number of subexpressions in a sequence of COMPOUND_EXPRs.  */
+
+int
+expr_length (tree expr)
+{
+  int len = 0;
+  
+  if (expr == NULL_TREE)
+    return 0;
+  for (; TREE_CODE (expr) == COMPOUND_EXPR; expr = TREE_OPERAND (expr, 1))
+    len += expr_length (TREE_OPERAND (expr, 0));
+  ++len;
+  return len;
+}
 \f
 /* Return the size nominally occupied by an object of type TYPE
    when it resides in memory.  The value is measured in units of bytes,
@@ -1185,7 +1224,6 @@ tree
 bit_position (field)
      tree field;
 {
-
   return bit_from_pos (DECL_FIELD_OFFSET (field),
                       DECL_FIELD_BIT_OFFSET (field));
 }
@@ -1378,15 +1416,9 @@ tree
 save_expr (expr)
      tree expr;
 {
-  tree t = expr;
+  tree t = fold (expr);
   tree inner;
 
-  /* Don't fold a COMPONENT_EXPR: if the operand was a CONSTRUCTOR (the
-     only time it will fold), it can cause problems with PLACEHOLDER_EXPRs
-     in Ada.  Moreover, it isn't at all clear why we fold here at all.  */
-  if (TREE_CODE (t) != COMPONENT_REF)
-    t = fold (t);
-
   /* If the tree evaluates to a constant, then we don't want to hide that
      fact (i.e. this allows further folding, and direct checks for constants).
      However, a read-only object that has side effects cannot be bypassed.
@@ -1733,7 +1765,7 @@ unsafe_for_reeval (expr)
 /* Return 1 if EXP contains a PLACEHOLDER_EXPR; i.e., if it represents a size
    or offset that depends on a field within a record.  */
 
-int
+bool
 contains_placeholder_p (exp)
      tree exp;
 {
@@ -1758,13 +1790,12 @@ contains_placeholder_p (exp)
         position computations since they will be converted into a
         WITH_RECORD_EXPR involving the reference, which will assume
         here will be valid.  */
-      return contains_placeholder_p (TREE_OPERAND (exp, 0));
+      return CONTAINS_PLACEHOLDER_P (TREE_OPERAND (exp, 0));
 
     case 'x':
       if (code == TREE_LIST)
-       return (contains_placeholder_p (TREE_VALUE (exp))
-               || (TREE_CHAIN (exp) != 0
-                   && contains_placeholder_p (TREE_CHAIN (exp))));
+       return (CONTAINS_PLACEHOLDER_P (TREE_VALUE (exp))
+               || CONTAINS_PLACEHOLDER_P (TREE_CHAIN (exp)));
       break;
 
     case '1':
@@ -1774,16 +1805,16 @@ contains_placeholder_p (exp)
        {
        case COMPOUND_EXPR:
          /* Ignoring the first operand isn't quite right, but works best.  */
-         return contains_placeholder_p (TREE_OPERAND (exp, 1));
+         return CONTAINS_PLACEHOLDER_P (TREE_OPERAND (exp, 1));
 
        case RTL_EXPR:
        case CONSTRUCTOR:
          return 0;
 
        case COND_EXPR:
-         return (contains_placeholder_p (TREE_OPERAND (exp, 0))
-                 || contains_placeholder_p (TREE_OPERAND (exp, 1))
-                 || contains_placeholder_p (TREE_OPERAND (exp, 2)));
+         return (CONTAINS_PLACEHOLDER_P (TREE_OPERAND (exp, 0))
+                 || CONTAINS_PLACEHOLDER_P (TREE_OPERAND (exp, 1))
+                 || CONTAINS_PLACEHOLDER_P (TREE_OPERAND (exp, 2)));
 
        case SAVE_EXPR:
          /* If we already know this doesn't have a placeholder, don't
@@ -1792,15 +1823,14 @@ contains_placeholder_p (exp)
            return 0;
 
          SAVE_EXPR_NOPLACEHOLDER (exp) = 1;
-         result = contains_placeholder_p (TREE_OPERAND (exp, 0));
+         result = CONTAINS_PLACEHOLDER_P (TREE_OPERAND (exp, 0));
          if (result)
            SAVE_EXPR_NOPLACEHOLDER (exp) = 0;
 
          return result;
 
        case CALL_EXPR:
-         return (TREE_OPERAND (exp, 1) != 0
-                 && contains_placeholder_p (TREE_OPERAND (exp, 1)));
+         return CONTAINS_PLACEHOLDER_P (TREE_OPERAND (exp, 1));
 
        default:
          break;
@@ -1809,10 +1839,10 @@ contains_placeholder_p (exp)
       switch (TREE_CODE_LENGTH (code))
        {
        case 1:
-         return contains_placeholder_p (TREE_OPERAND (exp, 0));
+         return CONTAINS_PLACEHOLDER_P (TREE_OPERAND (exp, 0));
        case 2:
-         return (contains_placeholder_p (TREE_OPERAND (exp, 0))
-                 || contains_placeholder_p (TREE_OPERAND (exp, 1)));
+         return (CONTAINS_PLACEHOLDER_P (TREE_OPERAND (exp, 0))
+                 || CONTAINS_PLACEHOLDER_P (TREE_OPERAND (exp, 1)));
        default:
          return 0;
        }
@@ -1823,6 +1853,109 @@ contains_placeholder_p (exp)
   return 0;
 }
 
+/* Return 1 if any part of the computation of TYPE involves a PLACEHOLDER_EXPR.
+   This includes size, bounds, qualifiers (for QUAL_UNION_TYPE) and field
+   positions.  */
+
+bool
+type_contains_placeholder_p (type)
+     tree type;
+{
+  /* If the size contains a placeholder or the parent type (component type in
+     the case of arrays) type involves a placeholder, this type does.  */
+  if (CONTAINS_PLACEHOLDER_P (TYPE_SIZE (type))
+      || CONTAINS_PLACEHOLDER_P (TYPE_SIZE_UNIT (type))
+      || (TREE_TYPE (type) != 0
+         && type_contains_placeholder_p (TREE_TYPE (type))))
+    return 1;
+
+  /* Now do type-specific checks.  Note that the last part of the check above
+     greatly limits what we have to do below.  */
+  switch (TREE_CODE (type))
+    {
+    case VOID_TYPE:
+    case COMPLEX_TYPE:
+    case VECTOR_TYPE:
+    case ENUMERAL_TYPE:
+    case BOOLEAN_TYPE:
+    case CHAR_TYPE:
+    case POINTER_TYPE:
+    case OFFSET_TYPE:
+    case REFERENCE_TYPE:
+    case METHOD_TYPE:
+    case FILE_TYPE:
+    case FUNCTION_TYPE:
+      return 0;
+
+    case INTEGER_TYPE:
+    case REAL_TYPE:
+      /* Here we just check the bounds.  */
+      return (CONTAINS_PLACEHOLDER_P (TYPE_MIN_VALUE (type))
+             || CONTAINS_PLACEHOLDER_P (TYPE_MAX_VALUE (type)));
+
+    case ARRAY_TYPE:
+    case SET_TYPE:
+      /* We're already checked the component type (TREE_TYPE), so just check
+        the index type.  */
+      return type_contains_placeholder_p (TYPE_DOMAIN (type));
+
+    case RECORD_TYPE:
+    case UNION_TYPE:
+    case QUAL_UNION_TYPE:
+      {
+       static tree seen_types = 0;
+       tree field;
+       bool ret = 0;
+
+       /* We have to be careful here that we don't end up in infinite
+          recursions due to a field of a type being a pointer to that type
+          or to a mutually-recursive type.  So we store a list of record
+          types that we've seen and see if this type is in them.  To save
+          memory, we don't use a list for just one type.  Here we check
+          whether we've seen this type before and store it if not.  */
+       if (seen_types == 0)
+         seen_types = type;
+       else if (TREE_CODE (seen_types) != TREE_LIST)
+         {
+           if (seen_types == type)
+             return 0;
+
+           seen_types = tree_cons (NULL_TREE, type,
+                                   build_tree_list (NULL_TREE, seen_types));
+         }
+       else
+         {
+           if (value_member (type, seen_types) != 0)
+             return 0;
+
+           seen_types = tree_cons (NULL_TREE, type, seen_types);
+         }
+
+       for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
+         if (TREE_CODE (field) == FIELD_DECL
+             && (CONTAINS_PLACEHOLDER_P (DECL_FIELD_OFFSET (field))
+                 || (TREE_CODE (type) == QUAL_UNION_TYPE
+                     && CONTAINS_PLACEHOLDER_P (DECL_QUALIFIER (field)))
+                 || type_contains_placeholder_p (TREE_TYPE (field))))
+           {
+             ret = true;
+             break;
+           }
+
+       /* Now remove us from seen_types and return the result.  */
+       if (seen_types == type)
+         seen_types = 0;
+       else
+         seen_types = TREE_CHAIN (seen_types);
+
+       return ret;
+      }
+
+    default:
+      abort ();
+    }
+}
+
 /* Return 1 if EXP contains any expressions that produce cleanups for an
    outer scope to deal with.  Used by fold.  */
 
@@ -1948,9 +2081,9 @@ substitute_in_expr (exp, f, r)
 
          op0 = TREE_OPERAND (exp, 0);
          op1 = TREE_OPERAND (exp, 1);
-         if (contains_placeholder_p (op0))
+         if (CONTAINS_PLACEHOLDER_P (op0))
            op0 = substitute_in_expr (op0, f, r);
-         if (contains_placeholder_p (op1))
+         if (CONTAINS_PLACEHOLDER_P (op1))
            op1 = substitute_in_expr (op1, f, r);
 
          if (op0 == TREE_OPERAND (exp, 0) && op1 == TREE_OPERAND (exp, 1))
@@ -1982,11 +2115,11 @@ substitute_in_expr (exp, f, r)
          op1 = TREE_OPERAND (exp, 1);
          op2 = TREE_OPERAND (exp, 2);
 
-         if (contains_placeholder_p (op0))
+         if (CONTAINS_PLACEHOLDER_P (op0))
            op0 = substitute_in_expr (op0, f, r);
-         if (contains_placeholder_p (op1))
+         if (CONTAINS_PLACEHOLDER_P (op1))
            op1 = substitute_in_expr (op1, f, r);
-         if (contains_placeholder_p (op2))
+         if (CONTAINS_PLACEHOLDER_P (op2))
            op2 = substitute_in_expr (op2, f, r);
 
          if (op0 == TREE_OPERAND (exp, 0) && op1 == TREE_OPERAND (exp, 1)
@@ -2246,17 +2379,16 @@ stabilize_reference_1 (e)
    Constants, decls, types and misc nodes cannot be.  */
 
 tree
-build VPARAMS ((enum tree_code code, tree tt, ...))
+build (enum tree_code code, tree tt, ...)
 {
   tree t;
   int length;
   int i;
   int fro;
   int constant;
+  va_list p;
 
-  VA_OPEN (p, tt);
-  VA_FIXEDARG (p, enum tree_code, code);
-  VA_FIXEDARG (p, tree, tt);
+  va_start (p, tt);
 
   t = make_node (code);
   length = TREE_CODE_LENGTH (code);
@@ -2333,7 +2465,7 @@ build VPARAMS ((enum tree_code code, tree tt, ...))
            }
        }
     }
-  VA_CLOSE (p);
+  va_end (p);
 
   TREE_CONSTANT (t) = constant;
   return t;
@@ -2434,14 +2566,14 @@ build1 (code, type, node)
    or even garbage if their values do not matter.  */
 
 tree
-build_nt VPARAMS ((enum tree_code code, ...))
+build_nt (enum tree_code code, ...)
 {
   tree t;
   int length;
   int i;
+  va_list p;
 
-  VA_OPEN (p, code);
-  VA_FIXEDARG (p, enum tree_code, code);
+  va_start (p, code);
 
   t = make_node (code);
   length = TREE_CODE_LENGTH (code);
@@ -2449,7 +2581,7 @@ build_nt VPARAMS ((enum tree_code code, ...))
   for (i = 0; i < length; i++)
     TREE_OPERAND (t, i) = va_arg (p, tree);
 
-  VA_CLOSE (p);
+  va_end (p);
   return t;
 }
 \f
@@ -3490,6 +3622,98 @@ compare_tree_int (t, u)
   else
     return 1;
 }
+
+/* Generate a hash value for an expression.  This can be used iteratively
+   by passing a previous result as the "val" argument.
+
+   This function is intended to produce the same hash for expressions which
+   would compare equal using operand_equal_p.  */
+
+hashval_t
+iterative_hash_expr (tree t, hashval_t val)
+{
+  int i;
+  enum tree_code code;
+  char class;
+
+  if (t == NULL_TREE)
+    return iterative_hash_object (t, val);
+
+  code = TREE_CODE (t);
+  class = TREE_CODE_CLASS (code);
+
+  if (class == 'd')
+    {
+      /* Decls we can just compare by pointer.  */
+      val = iterative_hash_object (t, val);
+    }
+  else if (class == 'c')
+    {
+      /* Alas, constants aren't shared, so we can't rely on pointer
+        identity.  */
+      if (code == INTEGER_CST)
+       {
+         val = iterative_hash_object (TREE_INT_CST_LOW (t), val);
+         val = iterative_hash_object (TREE_INT_CST_HIGH (t), val);
+       }
+      else if (code == REAL_CST)
+       val = iterative_hash (TREE_REAL_CST_PTR (t),
+                             sizeof (REAL_VALUE_TYPE), val);
+      else if (code == STRING_CST)
+       val = iterative_hash (TREE_STRING_POINTER (t),
+                             TREE_STRING_LENGTH (t), val);
+      else if (code == COMPLEX_CST)
+       {
+         val = iterative_hash_expr (TREE_REALPART (t), val);
+         val = iterative_hash_expr (TREE_IMAGPART (t), val);
+       }
+      else if (code == VECTOR_CST)
+       val = iterative_hash_expr (TREE_VECTOR_CST_ELTS (t), val);
+      else
+       abort ();
+    }
+  else if (IS_EXPR_CODE_CLASS (class) || class == 'r')
+    {
+      val = iterative_hash_object (code, val);
+
+      if (code == NOP_EXPR || code == CONVERT_EXPR
+         || code == NON_LVALUE_EXPR)
+       val = iterative_hash_object (TREE_TYPE (t), val);
+
+      if (code == PLUS_EXPR || code == MULT_EXPR || code == MIN_EXPR
+         || code == MAX_EXPR || code == BIT_IOR_EXPR || code == BIT_XOR_EXPR
+         || code == BIT_AND_EXPR || code == NE_EXPR || code == EQ_EXPR)
+       {
+         /* It's a commutative expression.  We want to hash it the same
+            however it appears.  We do this by first hashing both operands
+            and then rehashing based on the order of their independent
+            hashes.  */
+         hashval_t one = iterative_hash_expr (TREE_OPERAND (t, 0), 0);
+         hashval_t two = iterative_hash_expr (TREE_OPERAND (t, 1), 0);
+         hashval_t t;
+
+         if (one > two)
+           t = one, one = two, two = t;
+
+         val = iterative_hash_object (one, val);
+         val = iterative_hash_object (two, val);
+       }
+      else
+       for (i = first_rtl_op (code) - 1; i >= 0; --i)
+         val = iterative_hash_expr (TREE_OPERAND (t, i), val);
+    }
+  else if (code == TREE_LIST)
+    {
+      /* A list of expressions, for a CALL_EXPR or as the elements of a
+        VECTOR_CST.  */
+      for (; t; t = TREE_CHAIN (t))
+       val = iterative_hash_expr (TREE_VALUE (t), val);
+    }
+  else
+    abort ();
+
+  return val;
+}
 \f
 /* Constructors for pointer, array and function types.
    (RECORD_TYPE, UNION_TYPE and ENUMERAL_TYPE nodes are
@@ -3764,12 +3988,12 @@ build_function_type (value_type, arg_types)
    be terminated by NULL_TREE.  */
 
 tree
-build_function_type_list VPARAMS ((tree return_type, ...))
+build_function_type_list (tree return_type, ...)
 {
   tree t, args, last;
+  va_list p;
 
-  VA_OPEN (p, return_type);
-  VA_FIXEDARG (p, tree, return_type);
+  va_start (p, return_type);
 
   t = va_arg (p, tree);
   for (args = NULL_TREE; t != NULL_TREE; t = va_arg (p, tree))
@@ -3780,7 +4004,7 @@ build_function_type_list VPARAMS ((tree return_type, ...))
   TREE_CHAIN (last) = void_list_node;
   args = build_function_type (return_type, args);
 
-  VA_CLOSE (p);
+  va_end (p);
   return args;
 }