tree.c (decl_function_context): Handle virtual functions.
[gcc.git] / gcc / tree.c
index d5e19c8b992579bdf981f52ff002723ee6abe3c2..78ea4cf976a7a9d3d5cedafca27adf9ab6a98a46 100644 (file)
@@ -37,6 +37,7 @@ Boston, MA 02111-1307, USA.  */
 #include "system.h"
 #include "flags.h"
 #include "tree.h"
+#include "tm_p.h"
 #include "function.h"
 #include "obstack.h"
 #include "toplev.h"
@@ -47,6 +48,8 @@ Boston, MA 02111-1307, USA.  */
 /* obstack.[ch] explicitly declined to prototype this. */
 extern int _obstack_allocated_p PROTO ((struct obstack *h, PTR obj));
 
+static void unsave_expr_now_r PROTO ((tree));
+
 /* Tree nodes of permanent duration are allocated in this obstack.
    They are the identifier nodes, and everything outside of
    the bodies and parameters of function definitions.  */
@@ -274,9 +277,20 @@ static void build_real_from_int_cst_1 PROTO((PTR));
 static void mark_type_hash PROTO ((void *));
 static void fix_sizetype PROTO ((tree));
 
-/* If non-null, a language specific helper for unsave_expr_now. */
-
+/* If non-null, these are language-specific helper functions for
+   unsave_expr_now.  If present, LANG_UNSAVE is called before its
+   argument (an UNSAVE_EXPR) is to be unsaved, and all other
+   processing in unsave_expr_now is aborted.  LANG_UNSAVE_EXPR_NOW is
+   called from unsave_expr_1 for language-specific tree codes.  */
+void (*lang_unsave) PROTO((tree *));
 void (*lang_unsave_expr_now) PROTO((tree));
+
+/* The string used as a placeholder instead of a source file name for
+   built-in tree nodes.  The variable, which is dynamically allocated,
+   should be used; the macro is only used to initialize it.  */
+
+static char *built_in_filename;
+#define BUILT_IN_FILENAME ("<built-in>")
 \f
 tree global_trees[TI_MAX];
 \f
@@ -866,7 +880,9 @@ resume_momentary (yes)
 void
 init_tree_codes ()
 {
-  
+  built_in_filename = 
+    ggc_alloc_string (BUILT_IN_FILENAME, sizeof (BUILT_IN_FILENAME));
+  ggc_add_string_root (&built_in_filename, 1);
 }
 
 /* Return a newly allocated node of code CODE.
@@ -1018,7 +1034,7 @@ make_node (code)
   else
     {
       t = (tree) obstack_alloc (obstack, length);
-      bzero ((PTR) t, length);
+      memset ((PTR) t, 0, length);
     }
 
 #ifdef GATHER_STATISTICS
@@ -1043,7 +1059,8 @@ make_node (code)
       DECL_IN_SYSTEM_HEADER (t)
        = in_system_header && (obstack == &permanent_obstack);
       DECL_SOURCE_LINE (t) = lineno;
-      DECL_SOURCE_FILE (t) = (input_filename) ? input_filename : "<built-in>";
+      DECL_SOURCE_FILE (t) = 
+       (input_filename) ? input_filename : built_in_filename;
       DECL_UID (t) = next_decl_uid++;
       /* Note that we have not yet computed the alias set for this
         declaration.  */
@@ -1067,10 +1084,46 @@ make_node (code)
     case 'c':
       TREE_CONSTANT (t) = 1;
       break;
+
+    case 'e':
+      switch (code)
+       {
+       case INIT_EXPR:
+       case MODIFY_EXPR:
+       case VA_ARG_EXPR:
+       case RTL_EXPR:
+       case PREDECREMENT_EXPR:
+       case PREINCREMENT_EXPR:
+       case POSTDECREMENT_EXPR:
+       case POSTINCREMENT_EXPR:
+         /* All of these have side-effects, no matter what their
+            operands are.  */
+         TREE_SIDE_EFFECTS (t) = 1;
+         break;
+         
+       default:
+         break;
+       }
+      break;
     }
 
   return t;
 }
+
+/* A front-end can reset this to an appropriate function if types need
+   special handling.  */
+
+tree (*make_lang_type_fn) PROTO((enum tree_code)) = make_node;
+
+/* Return a new type (with the indicated CODE), doing whatever
+   language-specific processing is required.  */
+
+tree 
+make_lang_type (code)
+     enum tree_code code;
+{
+  return (*make_lang_type_fn) (code);
+}
 \f
 /* Return a new node with the same contents as NODE except that its
    TREE_CHAIN is zero and it has a fresh uid.  Unlike make_node, this
@@ -1138,9 +1191,7 @@ copy_node (node)
     t = (tree) obstack_alloc (current_obstack, length);
   memcpy (t, node, length);
 
-  /* EXPR_WITH_FILE_LOCATION must keep filename info stored in TREE_CHAIN */
-  if (TREE_CODE (node) != EXPR_WITH_FILE_LOCATION)
-    TREE_CHAIN (t) = 0;
+  TREE_CHAIN (t) = 0;
   TREE_ASM_WRITTEN (t) = 0;
 
   if (TREE_CODE_CLASS (code) == 'd')
@@ -2189,10 +2240,7 @@ int_size_in_bytes (type)
 }
 \f
 /* Return, as a tree node, the number of elements for TYPE (which is an
-   ARRAY_TYPE) minus one. This counts only elements of the top array.
-
-   Don't let any SAVE_EXPRs escape; if we are called as part of a cleanup
-   action, they would get unsaved.  */
+   ARRAY_TYPE) minus one. This counts only elements of the top array.  */
 
 tree
 array_type_nelts (type)
@@ -2209,26 +2257,6 @@ array_type_nelts (type)
   min = TYPE_MIN_VALUE (index_type);
   max = TYPE_MAX_VALUE (index_type);
 
-  if (! TREE_CONSTANT (min))
-    {
-      STRIP_NOPS (min);
-      if (TREE_CODE (min) == SAVE_EXPR && SAVE_EXPR_RTL (min))
-       min = build (RTL_EXPR, TREE_TYPE (TYPE_MIN_VALUE (index_type)), 0,
-                    SAVE_EXPR_RTL (min));
-      else
-       min = TYPE_MIN_VALUE (index_type);
-    }
-
-  if (! TREE_CONSTANT (max))
-    {
-      STRIP_NOPS (max);
-      if (TREE_CODE (max) == SAVE_EXPR && SAVE_EXPR_RTL (max))
-       max = build (RTL_EXPR, TREE_TYPE (TYPE_MAX_VALUE (index_type)), 0,
-                    SAVE_EXPR_RTL (max));
-      else
-       max = TYPE_MAX_VALUE (index_type);
-    }
-
   return (integer_zerop (min)
          ? max
          : fold (build (MINUS_EXPR, TREE_TYPE (max), max, min)));
@@ -2395,30 +2423,18 @@ first_rtl_op (code)
     }
 }
 
-/* Modify a tree in place so that all the evaluate only once things
-   are cleared out.  Return the EXPR given.  
-
-   LANG_UNSAVE_EXPR_NOW, if set, is a pointer to a function to handle
-   language specific nodes.
-*/
+/* Perform any modifications to EXPR required when it is unsaved.  Does
+   not recurse into EXPR's subtrees.  */
 
-tree
-unsave_expr_now (expr)
+void
+unsave_expr_1 (expr)
      tree expr;
 {
-  enum tree_code code;
-  register int i;
-  int first_rtl;
-
-  if (expr == NULL_TREE)
-    return expr;
-
-  code = TREE_CODE (expr);
-  first_rtl = first_rtl_op (code);
-  switch (code)
+  switch (TREE_CODE (expr))
     {
     case SAVE_EXPR:
-      SAVE_EXPR_RTL (expr) = 0;
+      if (!SAVE_EXPR_PERSISTENT_P (expr))
+       SAVE_EXPR_RTL (expr) = 0;
       break;
 
     case TARGET_EXPR:
@@ -2428,22 +2444,12 @@ unsave_expr_now (expr)
       
     case RTL_EXPR:
       /* I don't yet know how to emit a sequence multiple times.  */
-      if (RTL_EXPR_SEQUENCE (expr) != 0)
+      if (RTL_EXPR_SEQUENCE (expr))
        abort ();
       break;
 
     case CALL_EXPR:
       CALL_EXPR_RTL (expr) = 0;
-      if (TREE_OPERAND (expr, 1)
-         && TREE_CODE (TREE_OPERAND (expr, 1)) == TREE_LIST)
-       {
-         tree exp = TREE_OPERAND (expr, 1);
-         while (exp)
-           {
-             unsave_expr_now (TREE_VALUE (exp));
-             exp = TREE_CHAIN (exp);
-           }
-       }
       break;
 
     default:
@@ -2451,7 +2457,35 @@ unsave_expr_now (expr)
        (*lang_unsave_expr_now) (expr);
       break;
     }
+}
+
+/* Helper function for unsave_expr_now.  */
+
+static void
+unsave_expr_now_r (expr)
+     tree expr;
+{
+  enum tree_code code;
+
+  /* There's nothing to do for NULL_TREE.  */
+  if (!expr)
+    return;
 
+  unsave_expr_1 (expr);
+
+  code = TREE_CODE (expr);
+  if (code == CALL_EXPR 
+      && TREE_OPERAND (expr, 1)
+      && TREE_CODE (TREE_OPERAND (expr, 1)) == TREE_LIST)
+    {
+      tree exp = TREE_OPERAND (expr, 1);
+      while (exp)
+       {
+         unsave_expr_now_r (TREE_VALUE (exp));
+         exp = TREE_CHAIN (exp);
+       }
+    }
   switch (TREE_CODE_CLASS (code))
     {
     case 'c':  /* a constant */
@@ -2459,7 +2493,7 @@ unsave_expr_now (expr)
     case 'x':  /* something random, like an identifier or an ERROR_MARK.  */
     case 'd':  /* A decl node */
     case 'b':  /* A block node */
-      return expr;
+      break;
 
     case 'e':  /* an expression */
     case 'r':  /* a reference */
@@ -2467,14 +2501,33 @@ unsave_expr_now (expr)
     case '<':  /* a comparison expression */
     case '2':  /* a binary arithmetic expression */
     case '1':  /* a unary arithmetic expression */
-      for (i = first_rtl - 1; i >= 0; i--)
-       unsave_expr_now (TREE_OPERAND (expr, i));
-      return expr;
+      {
+       int i;
+       
+       for (i = first_rtl_op (code) - 1; i >= 0; i--)
+         unsave_expr_now_r (TREE_OPERAND (expr, i));
+      }
+      break;
 
     default:
       abort ();
     }
 }
+
+/* Modify a tree in place so that all the evaluate only once things
+   are cleared out.  Return the EXPR given.  */
+
+tree
+unsave_expr_now (expr)
+     tree expr;
+{
+  if (lang_unsave)
+    (*lang_unsave) (&expr);
+  else
+    unsave_expr_now_r (expr);
+
+  return expr;
+}
 \f
 /* 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.  */
@@ -2979,6 +3032,7 @@ build VPROTO((enum tree_code code, tree tt, ...))
   register tree t;
   register int length;
   register int i;
+  int fro;
 
   VA_START (p, tt);
 
@@ -2991,6 +3045,12 @@ build VPROTO((enum tree_code code, tree tt, ...))
   length = tree_code_length[(int) code];
   TREE_TYPE (t) = tt;
 
+  /* Below, we automatically set TREE_SIDE_EFFECTS and TREE_RAISED for
+     the result based on those same flags for the arguments.  But, if
+     the arguments aren't really even `tree' expressions, we shouldn't
+     be trying to do this.  */
+  fro = first_rtl_op (code);
+
   if (length == 2)
     {
       /* This is equivalent to the loop below, but faster.  */
@@ -2998,11 +3058,20 @@ build VPROTO((enum tree_code code, tree tt, ...))
       register tree arg1 = va_arg (p, tree);
       TREE_OPERAND (t, 0) = arg0;
       TREE_OPERAND (t, 1) = arg1;
-      if ((arg0 && TREE_SIDE_EFFECTS (arg0))
-         || (arg1 && TREE_SIDE_EFFECTS (arg1)))
-       TREE_SIDE_EFFECTS (t) = 1;
-      TREE_RAISES (t)
-       = (arg0 && TREE_RAISES (arg0)) || (arg1 && TREE_RAISES (arg1));
+      if (arg0 && fro > 0)
+       {
+         if (TREE_SIDE_EFFECTS (arg0))
+           TREE_SIDE_EFFECTS (t) = 1;
+         if (TREE_RAISES (arg0))
+           TREE_RAISES (t) = 1;
+       }
+      if (arg1 && fro > 1)
+       {
+         if (TREE_SIDE_EFFECTS (arg1))
+           TREE_SIDE_EFFECTS (t) = 1;
+         if (TREE_RAISES (arg1))
+           TREE_RAISES (t) = 1;
+       }
     }
   else if (length == 1)
     {
@@ -3012,9 +3081,12 @@ build VPROTO((enum tree_code code, tree tt, ...))
       if (TREE_CODE_CLASS (code) != 's')
        abort ();
       TREE_OPERAND (t, 0) = arg0;
-      if (arg0 && TREE_SIDE_EFFECTS (arg0))
-       TREE_SIDE_EFFECTS (t) = 1;
-      TREE_RAISES (t) = (arg0 && TREE_RAISES (arg0));
+      if (fro > 0)
+       {
+         if (arg0 && TREE_SIDE_EFFECTS (arg0))
+           TREE_SIDE_EFFECTS (t) = 1;
+         TREE_RAISES (t) = (arg0 && TREE_RAISES (arg0));
+       }
     }
   else
     {
@@ -3022,7 +3094,7 @@ build VPROTO((enum tree_code code, tree tt, ...))
        {
          register tree operand = va_arg (p, tree);
          TREE_OPERAND (t, i) = operand;
-         if (operand)
+         if (operand && fro > i)
            {
              if (TREE_SIDE_EFFECTS (operand))
                TREE_SIDE_EFFECTS (t) = 1;
@@ -3064,8 +3136,10 @@ build1 (code, type, node)
   if (ggc_p)
     t = ggc_alloc_tree (length);
   else
-    t = (tree) obstack_alloc (obstack, length);
-  bzero ((PTR) t, length);
+    {
+      t = (tree) obstack_alloc (obstack, length);
+      memset ((PTR) t, 0, length);
+    }
 
 #ifdef GATHER_STATISTICS
   tree_node_counts[(int)kind]++;
@@ -3079,7 +3153,7 @@ build1 (code, type, node)
     TREE_PERMANENT (t) = 1;
 
   TREE_OPERAND (t, 0) = node;
-  if (node)
+  if (node && first_rtl_op (code) != 0)
     {
       if (TREE_SIDE_EFFECTS (node))
        TREE_SIDE_EFFECTS (t) = 1;
@@ -3087,6 +3161,25 @@ build1 (code, type, node)
        TREE_RAISES (t) = 1;
     }
 
+  switch (code)
+    {
+    case INIT_EXPR:
+    case MODIFY_EXPR:
+    case VA_ARG_EXPR:
+    case RTL_EXPR:
+    case PREDECREMENT_EXPR:
+    case PREINCREMENT_EXPR:
+    case POSTDECREMENT_EXPR:
+    case POSTINCREMENT_EXPR:
+      /* All of these have side-effects, no matter what their
+        operands are.  */
+      TREE_SIDE_EFFECTS (t) = 1;
+      break;
+         
+    default:
+      break;
+    }
+
   return t;
 }
 
@@ -3212,7 +3305,6 @@ build_block (vars, tags, subblocks, supercontext, chain)
 {
   register tree block = make_node (BLOCK);
   BLOCK_VARS (block) = vars;
-  BLOCK_TYPE_TAGS (block) = tags;
   BLOCK_SUBBLOCKS (block) = subblocks;
   BLOCK_SUPERCONTEXT (block) = supercontext;
   BLOCK_CHAIN (block) = chain;
@@ -3273,12 +3365,9 @@ build_type_attribute_variant (ttype, attribute)
   if ( ! attribute_list_equal (TYPE_ATTRIBUTES (ttype), attribute))
     {
       register int hashcode;
-      register struct obstack *ambient_obstack = current_obstack;
       tree ntype;
 
-      if (ambient_obstack != &permanent_obstack)
-        current_obstack = TYPE_OBSTACK (ttype);
-
+      push_obstacks (TYPE_OBSTACK (ttype), TYPE_OBSTACK (ttype));
       ntype = copy_node (ttype);
 
       TYPE_POINTER_TO (ntype) = 0;
@@ -3314,12 +3403,7 @@ build_type_attribute_variant (ttype, attribute)
 
       ntype = type_hash_canon (hashcode, ntype);
       ttype = build_qualified_type (ntype, TYPE_QUALS (ttype));
-
-      /* We must restore the current obstack after the type_hash_canon call,
-        because type_hash_canon calls type_hash_add for permanent types, and
-        then type_hash_add calls oballoc expecting to get something permanent
-        back.  */
-      current_obstack = ambient_obstack;
+      pop_obstacks ();
     }
 
   return ttype;
@@ -4438,6 +4522,40 @@ build_complex_type (component_type)
   if (TYPE_SIZE (t) == 0)
     layout_type (t);
 
+  /* If we are writing Dwarf2 output we need to create a name,
+     since complex is a fundamental type.  */
+  if (write_symbols == DWARF2_DEBUG && ! TYPE_NAME (t))
+    {
+      const char *name;
+      if (component_type == char_type_node)
+       name = "complex char";
+      else if (component_type == signed_char_type_node)
+       name = "complex signed char";
+      else if (component_type == unsigned_char_type_node)
+       name = "complex unsigned char";
+      else if (component_type == short_integer_type_node)
+       name = "complex short int";
+      else if (component_type == short_unsigned_type_node)
+       name = "complex short unsigned int";
+      else if (component_type == integer_type_node)
+       name = "complex int";
+      else if (component_type == unsigned_type_node)
+       name = "complex unsigned int";
+      else if (component_type == long_integer_type_node)
+       name = "complex long int";
+      else if (component_type == long_unsigned_type_node)
+       name = "complex long unsigned int";
+      else if (component_type == long_long_integer_type_node)
+       name = "complex long long int";
+      else if (component_type == long_long_unsigned_type_node)
+       name = "complex long long unsigned int";
+      else
+       name = (char *)0;
+
+      if (name)
+       TYPE_NAME (t) = get_identifier (name);
+    }
+
   return t;
 }
 \f
@@ -4660,6 +4778,16 @@ int_fits_type_p (c, type)
                  && TREE_UNSIGNED (TREE_TYPE (c))));
 }
 
+/* Given a DECL or TYPE, return the scope in which it was declared, or
+   NUL_TREE if there is no containing scope.  */
+
+tree
+get_containing_scope (t)
+     tree t;
+{
+  return (TYPE_P (t) ? TYPE_CONTEXT (t) : DECL_CONTEXT (t));
+}
+
 /* Return the innermost context enclosing DECL that is
    a FUNCTION_DECL, or zero if none.  */
 
@@ -4674,20 +4802,24 @@ decl_function_context (decl)
 
   if (TREE_CODE (decl) == SAVE_EXPR)
     context = SAVE_EXPR_CONTEXT (decl);
+  /* C++ virtual functions use DECL_CONTEXT for the class of the vtable
+     where we look up the function at runtime.  Such functions always take
+     a first argument of type 'pointer to real context'.
+
+     C++ should really be fixed to use DECL_CONTEXT for the real context,
+     and use something else for the "virtual context".  */
+  else if (TREE_CODE (decl) == FUNCTION_DECL && DECL_VINDEX (decl))
+    context = TYPE_MAIN_VARIANT
+      (TREE_TYPE (TREE_VALUE (TYPE_ARG_TYPES (TREE_TYPE (decl)))));
   else
     context = DECL_CONTEXT (decl);
 
   while (context && TREE_CODE (context) != FUNCTION_DECL)
     {
-      if (TREE_CODE_CLASS (TREE_CODE (context)) == 't')
-       context = TYPE_CONTEXT (context);
-      else if (TREE_CODE_CLASS (TREE_CODE (context)) == 'd')
-       context = DECL_CONTEXT (context);
-      else if (TREE_CODE (context) == BLOCK)
+      if (TREE_CODE (context) == BLOCK)
        context = BLOCK_SUPERCONTEXT (context);
-      else
-       /* Unhandled CONTEXT !?  */
-       abort ();
+      else 
+       context = get_containing_scope (context);
     }
 
   return context;
@@ -4721,6 +4853,35 @@ decl_type_context (decl)
   return NULL_TREE;
 }
 
+/* CALL is a CALL_EXPR.  Return the declaration for the function
+   called, or NULL_TREE if the called function cannot be 
+   determined.  */
+
+tree
+get_callee_fndecl (call)
+     tree call;
+{
+  tree addr;
+
+  /* It's invalid to call this function with anything but a
+     CALL_EXPR.  */
+  if (TREE_CODE (call) != CALL_EXPR)
+    abort ();
+
+  /* The first operand to the CALL is the address of the function
+     called.  */
+  addr = TREE_OPERAND (call, 0);
+
+  /* If the address is just `&f' for some function `f', then we know
+     that `f' is being called.  */
+  if (TREE_CODE (addr) == ADDR_EXPR
+      && TREE_CODE (TREE_OPERAND (addr, 0)) == FUNCTION_DECL)
+    return TREE_OPERAND (addr, 0);
+
+  /* We couldn't figure out what was being called.  */
+  return NULL_TREE;
+}
+
 /* Print debugging information about the obstack O, named STR.  */
 
 void
@@ -5019,7 +5180,7 @@ get_set_constructor_bytes (init, buffer, wd_size)
   return non_const_bits;
 }
 \f
-#if defined ENABLE_CHECKING && (__GNUC__ > 2 || __GNUC_MINOR__ > 6)
+#if defined ENABLE_CHECKING && (GCC_VERSION >= 2007)
 /* Complain that the tree code of NODE does not match the expected CODE.
    FILE, LINE, and FUNCTION are of the caller.  */
 void