/* 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
+ 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
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.
else
{
t = (tree) obstack_alloc (obstack, length);
- bzero ((PTR) t, length);
+ memset ((PTR) t, 0, length);
}
#ifdef GATHER_STATISTICS
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. */
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
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 t;
register int length;
register int i;
+ int fro;
VA_START (p, 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. */
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)
{
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
{
{
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;
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]++;
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;
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;
}
{
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;
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
&& 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 && (__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