/* 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. */
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
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')
}
\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)
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)));
}
}
-/* 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:
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:
(*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 */
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 */
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. */
{
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;
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;
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;
since complex is a fundamental type. */
if (write_symbols == DWARF2_DEBUG && ! TYPE_NAME (t))
{
- char *name;
+ const char *name;
if (component_type == char_type_node)
name = "complex char";
else if (component_type == signed_char_type_node)
&& 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. */
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;
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
return non_const_bits;
}
\f
-#if defined ENABLE_CHECKING && HAVE_GCC_VERSION(2,7)
+#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