/* Language-independent node constructors for parse phase of GNU compiler.
- Copyright (C) 1987, 88, 92-97, 1998 Free Software Foundation, Inc.
+ Copyright (C) 1987, 88, 92-98, 1999 Free Software Foundation, Inc.
This file is part of GNU CC.
by all passes of the compiler. */
#include "config.h"
-#include <setjmp.h>
+#include "system.h"
#include "flags.h"
#include "tree.h"
-#include "except.h"
+#include "tm_p.h"
#include "function.h"
#include "obstack.h"
-#ifdef __STDC__
-#include <stdarg.h>
-#else
-#include <varargs.h>
-#endif
-#include <stdio.h>
-
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-
-#ifdef NEED_DECLARATION_FREE
-extern void free PROTO((void *));
-#endif
-
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
+#include "toplev.h"
+#include "ggc.h"
#define obstack_chunk_alloc xmalloc
#define obstack_chunk_free free
+/* 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
struct obstack maybepermanent_obstack;
-/* This is a list of function_maybepermanent_obstacks for top-level inline
- functions that are compiled in the middle of compiling other functions. */
-
-struct simple_obstack_stack *toplev_inline_obstacks;
-
-/* Former elements of toplev_inline_obstacks that have been recycled. */
-
-struct simple_obstack_stack *extra_inline_obstacks;
-
-/* This is a list of function_maybepermanent_obstacks for inline functions
- nested in the current function that were compiled in the middle of
- compiling other functions. */
-
-struct simple_obstack_stack *inline_obstacks;
-
/* The contents of the current function definition are allocated
in this obstack, and all are freed at the end of the function.
For top-level functions, this is temporary_obstack.
Used for printing out the tree and error messages. */
#define DEFTREECODE(SYM, NAME, TYPE, LEN) NAME,
-char *tree_code_name[MAX_TREE_CODES] = {
+const char *tree_code_name[MAX_TREE_CODES] = {
#include "tree.def"
};
#undef DEFTREECODE
int tree_node_sizes[(int)all_kinds];
int id_string_size = 0;
-char *tree_node_kind_names[] = {
+static const char * const tree_node_kind_names[] = {
"decls",
"types",
"blocks",
/* Unique id for next type created. */
static int next_type_uid = 1;
+/* The language-specific function for alias analysis. If NULL, the
+ language does not do any special alias analysis. */
+int (*lang_get_alias_set) PROTO((tree));
+
/* Here is how primitive or already-canonicalized types' hash
codes are made. */
#define TYPE_HASH(TYPE) ((unsigned long) (TYPE) & 0777777)
-extern char *mode_name[];
+/* Each hash table slot is a bucket containing a chain
+ of these structures. */
+
+struct type_hash
+{
+ struct type_hash *next; /* Next structure in the bucket. */
+ int hashcode; /* Hash code of this type. */
+ tree type; /* The type recorded here. */
+};
+
+/* Now here is the hash table. When recording a type, it is added
+ to the slot whose index is the hash code mod the table size.
+ Note that the hash table is used for several kinds of types
+ (function types, array types and array index range types, for now).
+ While all these live in the same table, they are completely independent,
+ and the hash code is computed differently for each of these. */
+
+#define TYPE_HASH_SIZE 59
+struct type_hash *type_hash_table[TYPE_HASH_SIZE];
-void gcc_obstack_init ();
+static void set_type_quals PROTO((tree, int));
+static void append_random_chars PROTO((char *));
+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, 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
/* Init the principal obstacks. */
/* Init the hash table of identifiers. */
bzero ((char *) hash_table, sizeof hash_table);
+
+ ggc_add_tree_root (hash_table, MAX_HASH_TABLE);
+ ggc_add_root (type_hash_table, TYPE_HASH_SIZE,
+ sizeof(struct type_hash *),
+ mark_type_hash);
+ ggc_add_tree_root (global_trees, TI_MAX);
}
void
#define OBSTACK_CHUNK_FREE free
#endif
_obstack_begin (obstack, OBSTACK_CHUNK_SIZE, 0,
- (void *(*) ()) OBSTACK_CHUNK_ALLOC,
- (void (*) ()) OBSTACK_CHUNK_FREE);
+ (void *(*) PROTO ((long))) OBSTACK_CHUNK_ALLOC,
+ (void (*) PROTO ((void *))) OBSTACK_CHUNK_FREE);
}
-/* Save all variables describing the current status into the structure *P.
- This is used before starting a nested function.
+/* Save all variables describing the current status into the structure
+ *P. This function is called whenever we start compiling one
+ function in the midst of compiling another. For example, when
+ compiling a nested function, or, in C++, a template instantiation
+ that is required by the function we are currently compiling.
CONTEXT is the decl_function_context for the function we're about to
compile; if it isn't current_function_decl, we have to play some games. */
void
-save_tree_status (p, context)
+save_tree_status (p)
struct function *p;
- tree context;
{
p->all_types_permanent = all_types_permanent;
p->momentary_stack = momentary_stack;
p->expression_obstack = expression_obstack;
p->saveable_obstack = saveable_obstack;
p->rtl_obstack = rtl_obstack;
- p->inline_obstacks = inline_obstacks;
-
- if (context == current_function_decl)
- /* Objects that need to be saved in this function can be in the nonsaved
- obstack of the enclosing function since they can't possibly be needed
- once it has returned. */
- function_maybepermanent_obstack = function_obstack;
- else
- {
- /* We're compiling a function which isn't nested in the current
- function. We need to create a new maybepermanent_obstack for this
- function, since it can't go onto any of the existing obstacks. */
- struct simple_obstack_stack **head;
- struct simple_obstack_stack *current;
-
- if (context == NULL_TREE)
- head = &toplev_inline_obstacks;
- else
- {
- struct function *f = find_function_data (context);
- head = &f->inline_obstacks;
- }
-
- if (context == NULL_TREE && extra_inline_obstacks)
- {
- current = extra_inline_obstacks;
- extra_inline_obstacks = current->next;
- }
- else
- {
- current = ((struct simple_obstack_stack *)
- xmalloc (sizeof (struct simple_obstack_stack)));
-
- current->obstack
- = (struct obstack *) xmalloc (sizeof (struct obstack));
- gcc_obstack_init (current->obstack);
- }
-
- function_maybepermanent_obstack = current->obstack;
-
- current->next = *head;
- *head = current;
- }
+ function_maybepermanent_obstack
+ = (struct obstack *) xmalloc (sizeof (struct obstack));
+ gcc_obstack_init (function_maybepermanent_obstack);
maybepermanent_firstobj
= (char *) obstack_finish (function_maybepermanent_obstack);
This is used after a nested function. */
void
-restore_tree_status (p, context)
+restore_tree_status (p)
struct function *p;
- tree context;
{
all_types_permanent = p->all_types_permanent;
momentary_stack = p->momentary_stack;
obstack_free (&momentary_obstack, momentary_function_firstobj);
/* Free saveable storage used by the function just compiled and not
- saved.
-
- CAUTION: This is in function_obstack of the containing function.
- So we must be sure that we never allocate from that obstack during
- the compilation of a nested function if we expect it to survive
- past the nested function's end. */
+ saved. */
obstack_free (function_maybepermanent_obstack, maybepermanent_firstobj);
-
- /* If we were compiling a toplevel function, we can free this space now. */
- if (context == NULL_TREE)
+ if (obstack_empty_p (function_maybepermanent_obstack))
{
- obstack_free (&temporary_obstack, temporary_firstobj);
- obstack_free (&momentary_obstack, momentary_function_firstobj);
+ obstack_free (function_maybepermanent_obstack, NULL);
+ free (function_maybepermanent_obstack);
}
- /* If we were compiling a toplevel function that we don't actually want
- to save anything from, return the obstack to the pool. */
- if (context == NULL_TREE
- && obstack_empty_p (function_maybepermanent_obstack))
- {
- struct simple_obstack_stack *current, **p = &toplev_inline_obstacks;
-
- if ((*p) != NULL)
- {
- while ((*p)->obstack != function_maybepermanent_obstack)
- p = &((*p)->next);
- current = *p;
- *p = current->next;
-
- current->next = extra_inline_obstacks;
- extra_inline_obstacks = current;
- }
- }
+ obstack_free (&temporary_obstack, temporary_firstobj);
+ obstack_free (&momentary_obstack, momentary_function_firstobj);
- obstack_free (function_obstack, 0);
+ obstack_free (function_obstack, NULL);
free (function_obstack);
temporary_firstobj = p->temporary_firstobj;
expression_obstack = p->expression_obstack;
saveable_obstack = p->saveable_obstack;
rtl_obstack = p->rtl_obstack;
- inline_obstacks = p->inline_obstacks;
}
\f
/* Start allocating on the temporary (per function) obstack.
expression_obstack = function_obstack;
rtl_obstack = saveable_obstack = function_maybepermanent_obstack;
momentary_stack = 0;
- inline_obstacks = 0;
}
/* Start allocating on the permanent obstack but don't
push_obstacks (current, saveable)
struct obstack *current, *saveable;
{
- struct obstack_stack *p
- = (struct obstack_stack *) obstack_alloc (&obstack_stack_obstack,
+ struct obstack_stack *p;
+
+ p = (struct obstack_stack *) obstack_alloc (&obstack_stack_obstack,
(sizeof (struct obstack_stack)));
p->current = current_obstack;
void
push_obstacks_nochange ()
{
- struct obstack_stack *p
- = (struct obstack_stack *) obstack_alloc (&obstack_stack_obstack,
+ struct obstack_stack *p;
+
+ p = (struct obstack_stack *) obstack_alloc (&obstack_stack_obstack,
(sizeof (struct obstack_stack)));
p->current = current_obstack;
void
pop_obstacks ()
{
- struct obstack_stack *p = obstack_stack;
+ struct obstack_stack *p;
+
+ p = obstack_stack;
obstack_stack = p->next;
current_obstack = p->current;
obstack_free (function_maybepermanent_obstack, maybepermanent_firstobj);
obstack_free (&temp_decl_obstack, temp_decl_firstobj);
- /* Free up the maybepermanent_obstacks for any of our nested functions
- which were compiled at a lower level. */
- while (inline_obstacks)
- {
- struct simple_obstack_stack *current = inline_obstacks;
- inline_obstacks = current->next;
- obstack_free (current->obstack, 0);
- free (current->obstack);
- free (current);
- }
-
current_obstack = &permanent_obstack;
expression_obstack = &permanent_obstack;
rtl_obstack = saveable_obstack = &permanent_obstack;
print_obstack_name (object, file, prefix)
char *object;
FILE *file;
- char *prefix;
+ const char *prefix;
{
struct obstack *obstack = NULL;
- char *obstack_name = NULL;
+ const char *obstack_name = NULL;
struct function *p;
for (p = outer_function_chain; p; p = p->next)
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.
{
register tree t;
register int type = TREE_CODE_CLASS (code);
- register int length;
+ register int length = 0;
register struct obstack *obstack = current_obstack;
- register int i;
#ifdef GATHER_STATISTICS
register tree_node_kind kind;
#endif
abort ();
}
- t = (tree) obstack_alloc (obstack, length);
+ if (ggc_p)
+ t = ggc_alloc_tree (length);
+ else
+ {
+ t = (tree) obstack_alloc (obstack, length);
+ memset ((PTR) t, 0, length);
+ }
#ifdef GATHER_STATISTICS
tree_node_counts[(int)kind]++;
tree_node_sizes[(int)kind] += length;
#endif
- /* Clear a word at a time. */
- for (i = (length / sizeof (int)) - 1; i >= 0; i--)
- ((int *) t)[i] = 0;
- /* Clear any extra bytes. */
- for (i = length / sizeof (int) * sizeof (int); i < length; i++)
- ((char *) t)[i] = 0;
-
TREE_SET_CODE (t, code);
if (obstack == &permanent_obstack)
TREE_PERMANENT (t) = 1;
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. */
+ DECL_POINTER_ALIAS_SET (t) = -1;
break;
case 't':
#ifdef SET_DEFAULT_TYPE_ATTRIBUTES
SET_DEFAULT_TYPE_ATTRIBUTES (t);
#endif
+ /* Note that we have not yet computed the alias set for this
+ type. */
+ TYPE_ALIAS_SET (t) = -1;
break;
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. */
+/* 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
+ function always performs the allocation on the CURRENT_OBSTACK;
+ it's up to the caller to pick the right obstack before calling this
+ function. */
tree
copy_node (node)
{
register tree t;
register enum tree_code code = TREE_CODE (node);
- register int length;
- register int i;
+ register int length = 0;
switch (TREE_CODE_CLASS (code))
{
length += (TREE_VEC_LENGTH (node) - 1) * sizeof (char *);
}
- t = (tree) obstack_alloc (current_obstack, length);
-
- for (i = (length / sizeof (int)) - 1; i >= 0; i--)
- ((int *) t)[i] = ((int *) node)[i];
- /* Clear any extra bytes. */
- for (i = length / sizeof (int) * sizeof (int); i < length; i++)
- ((char *) t)[i] = ((char *) node)[i];
+ if (ggc_p)
+ t = ggc_alloc_tree (length);
+ else
+ t = (tree) obstack_alloc (current_obstack, length);
+ memcpy (t, node, length);
TREE_CHAIN (t) = 0;
TREE_ASM_WRITTEN (t) = 0;
tree
get_identifier (text)
- register char *text;
+ register const char *text;
{
register int hi;
register int i;
register int len, hash_len;
/* Compute length of text in len. */
- for (len = 0; text[len]; len++);
+ len = strlen (text);
/* Decide how much of that length to hash on */
hash_len = len;
- if (warn_id_clash && len > id_clash_len)
+ if (warn_id_clash && (unsigned)len > id_clash_len)
hash_len = id_clash_len;
/* Compute hash code */
return idp; /* <-- return if found */
/* Not found; optionally warn about a similar identifier */
- if (warn_id_clash && do_identifier_warnings && len >= id_clash_len)
+ if (warn_id_clash && do_identifier_warnings && (unsigned)len >= id_clash_len)
for (idp = hash_table[hi]; idp; idp = TREE_CHAIN (idp))
if (!strncmp (IDENTIFIER_POINTER (idp), text, id_clash_len))
{
id_string_size += len;
#endif
- IDENTIFIER_POINTER (idp) = obstack_copy0 (&permanent_obstack, text, len);
+ if (ggc_p)
+ IDENTIFIER_POINTER (idp) = ggc_alloc_string (text, len);
+ else
+ IDENTIFIER_POINTER (idp) = obstack_copy0 (&permanent_obstack, text, len);
TREE_CHAIN (idp) = hash_table[hi];
hash_table[hi] = idp;
tree
maybe_get_identifier (text)
- register char *text;
+ register const char *text;
{
register int hi;
register int i;
register int len, hash_len;
/* Compute length of text in len. */
- for (len = 0; text[len]; len++);
+ len = strlen (text);
/* Decide how much of that length to hash on */
hash_len = len;
- if (warn_id_clash && len > id_clash_len)
+ if (warn_id_clash && (unsigned)len > id_clash_len)
hash_len = id_clash_len;
/* Compute hash code */
return d;
}
+struct brfic_args
+{
+ /* Input */
+ tree type, i;
+ /* Output */
+ REAL_VALUE_TYPE d;
+};
+
+static void
+build_real_from_int_cst_1 (data)
+ PTR data;
+{
+ struct brfic_args * args = (struct brfic_args *) data;
+
+#ifdef REAL_ARITHMETIC
+ args->d = real_value_from_int_cst (args->type, args->i);
+#else
+ args->d =
+ REAL_VALUE_TRUNCATE (TYPE_MODE (args->type),
+ real_value_from_int_cst (args->type, args->i));
+#endif
+}
+
/* This function can't be implemented if we can't do arithmetic
on the float representation. */
tree v;
int overflow = TREE_OVERFLOW (i);
REAL_VALUE_TYPE d;
- jmp_buf float_error;
+ struct brfic_args args;
v = make_node (REAL_CST);
TREE_TYPE (v) = type;
- if (setjmp (float_error))
+ /* Setup input for build_real_from_int_cst_1() */
+ args.type = type;
+ args.i = i;
+
+ if (do_float_handler (build_real_from_int_cst_1, (PTR) &args))
+ {
+ /* Receive output from build_real_from_int_cst_1() */
+ d = args.d;
+ }
+ else
{
+ /* We got an exception from build_real_from_int_cst_1() */
d = dconst0;
overflow = 1;
- goto got_it;
}
-
- set_float_handler (float_error);
-
-#ifdef REAL_ARITHMETIC
- d = real_value_from_int_cst (type, i);
-#else
- d = REAL_VALUE_TRUNCATE (TYPE_MODE (type),
- real_value_from_int_cst (type, i));
-#endif
-
+
/* Check for valid float value for this type on this target machine. */
- got_it:
- set_float_handler (NULL_PTR);
-
#ifdef CHECK_FLOAT_VALUE
CHECK_FLOAT_VALUE (TYPE_MODE (type), d, overflow);
#endif
tree
build_string (len, str)
int len;
- char *str;
+ const char *str;
{
/* Put the string in saveable_obstack since it will be placed in the RTL
for an "asm" statement and will also be kept around a while if
register tree s = make_node (STRING_CST);
TREE_STRING_LENGTH (s) = len;
- TREE_STRING_POINTER (s) = obstack_copy0 (saveable_obstack, str, len);
+ if (ggc_p)
+ TREE_STRING_POINTER (s) = ggc_alloc_string (str, len);
+ else
+ TREE_STRING_POINTER (s) = obstack_copy0 (saveable_obstack, str, len);
return s;
}
register tree t;
register int length = (len-1) * sizeof (tree) + sizeof (struct tree_vec);
register struct obstack *obstack = current_obstack;
- register int i;
#ifdef GATHER_STATISTICS
tree_node_counts[(int)vec_kind]++;
tree_node_sizes[(int)vec_kind] += length;
#endif
- t = (tree) obstack_alloc (obstack, length);
-
- for (i = (length / sizeof (int)) - 1; i >= 0; i--)
- ((int *) t)[i] = 0;
+ if (ggc_p)
+ t = ggc_alloc_tree (length);
+ else
+ {
+ t = (tree) obstack_alloc (obstack, length);
+ bzero ((PTR) t, length);
+ }
TREE_SET_CODE (t, TREE_VEC);
TREE_VEC_LENGTH (t) = len;
if (TREE_CODE (expr) != INTEGER_CST || TREE_CONSTANT_OVERFLOW (expr))
return 0;
- prec = (TREE_CODE (TREE_TYPE (expr)) == POINTER_TYPE
+ prec = (POINTER_TYPE_P (TREE_TYPE (expr))
? POINTER_SIZE : TYPE_PRECISION (TREE_TYPE (expr)));
high = TREE_INT_CST_HIGH (expr);
low = TREE_INT_CST_LOW (expr);
if (TREE_CODE (expr) == COMPLEX_CST)
return tree_log2 (TREE_REALPART (expr));
- prec = (TREE_CODE (TREE_TYPE (expr)) == POINTER_TYPE
+ prec = (POINTER_TYPE_P (TREE_TYPE (expr))
? POINTER_SIZE : TYPE_PRECISION (TREE_TYPE (expr)));
high = TREE_INT_CST_HIGH (expr);
if (op1)
{
register tree t1;
+#ifdef ENABLE_CHECKING
register tree t2;
+#endif
for (t1 = op1; TREE_CHAIN (t1); t1 = TREE_CHAIN (t1))
;
TREE_CHAIN (t1) = op2;
+#ifdef ENABLE_CHECKING
for (t2 = op2; t2; t2 = TREE_CHAIN (t2))
if (t2 == t1)
abort (); /* Circularity created. */
+#endif
return op1;
}
else return op2;
#if 0
register tree node = make_node (TREE_LIST);
#else
- register int i;
- register tree node = (tree) obstack_alloc (current_obstack, sizeof (struct tree_list));
+ register tree node;
+
+ if (ggc_p)
+ node = ggc_alloc_tree (sizeof (struct tree_list));
+ else
+ {
+ node = (tree) obstack_alloc (current_obstack, sizeof (struct tree_list));
+ memset (node, 0, sizeof (struct tree_common));
+ }
+
#ifdef GATHER_STATISTICS
tree_node_counts[(int)x_kind]++;
tree_node_sizes[(int)x_kind] += sizeof (struct tree_list);
#endif
- for (i = (sizeof (struct tree_common) / sizeof (int)) - 1; i >= 0; i--)
- ((int *) node)[i] = 0;
TREE_SET_CODE (node, TREE_LIST);
if (current_obstack == &permanent_obstack)
if (type == error_mark_node)
return integer_zero_node;
+
type = TYPE_MAIN_VARIANT (type);
- if (TYPE_SIZE (type) == 0)
+ t = TYPE_SIZE_UNIT (type);
+ if (t == 0)
{
incomplete_type_error (NULL_TREE, type);
return integer_zero_node;
}
- t = size_binop (CEIL_DIV_EXPR, TYPE_SIZE (type),
- size_int (BITS_PER_UNIT));
if (TREE_CODE (t) == INTEGER_CST)
force_fit_type (t, 0);
+
return t;
}
-/* Return the size of TYPE (in bytes) as an integer,
- or return -1 if the size can vary. */
+/* Return the size of TYPE (in bytes) as a wide integer
+ or return -1 if the size can vary or is larger than an integer. */
-int
+HOST_WIDE_INT
int_size_in_bytes (type)
tree type;
{
- unsigned int size;
+ tree t;
+
if (type == error_mark_node)
return 0;
+
type = TYPE_MAIN_VARIANT (type);
- if (TYPE_SIZE (type) == 0)
- return -1;
- if (TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST)
+ t = TYPE_SIZE_UNIT (type);
+ if (t == 0
+ || TREE_CODE (t) != INTEGER_CST
+ || TREE_INT_CST_HIGH (t) != 0)
return -1;
- if (TREE_INT_CST_HIGH (TYPE_SIZE (type)) != 0)
- {
- tree t = size_binop (CEIL_DIV_EXPR, TYPE_SIZE (type),
- size_int (BITS_PER_UNIT));
- return TREE_INT_CST_LOW (t);
- }
- size = TREE_INT_CST_LOW (TYPE_SIZE (type));
- return (size + BITS_PER_UNIT - 1) / BITS_PER_UNIT;
+
+ return TREE_INT_CST_LOW (t);
}
\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)
- 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)
- 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)));
case FUNCTION_DECL:
/* Nested functions aren't static, since taking their address
involves a trampoline. */
- return decl_function_context (arg) == 0 || DECL_NO_STATIC_CHAIN (arg);
+ return (decl_function_context (arg) == 0 || DECL_NO_STATIC_CHAIN (arg))
+ && ! DECL_NON_ADDR_CONST_P (arg);
+
case VAR_DECL:
- return TREE_STATIC (arg) || DECL_EXTERNAL (arg);
+ return (TREE_STATIC (arg) || DECL_EXTERNAL (arg))
+ && ! DECL_NON_ADDR_CONST_P (arg);
case CONSTRUCTOR:
return TREE_STATIC (arg);
return t;
}
-/* Modify a tree in place so that all the evaluate only once things
- are cleared out. Return the EXPR given. */
+/* Returns the index of the first non-tree operand for CODE, or the number
+ of operands if all are trees. */
-tree
-unsave_expr_now (expr)
- tree expr;
+int
+first_rtl_op (code)
+ enum tree_code code;
{
- enum tree_code code;
- register int i;
- int first_rtl;
+ switch (code)
+ {
+ case SAVE_EXPR:
+ return 2;
+ case GOTO_SUBROUTINE_EXPR:
+ case RTL_EXPR:
+ return 0;
+ case CALL_EXPR:
+ return 2;
+ case WITH_CLEANUP_EXPR:
+ /* Should be defined to be 2. */
+ return 1;
+ case METHOD_CALL_EXPR:
+ return 3;
+ default:
+ return tree_code_length [(int) code];
+ }
+}
- if (expr == NULL_TREE)
- return expr;
+/* Perform any modifications to EXPR required when it is unsaved. Does
+ not recurse into EXPR's subtrees. */
- code = TREE_CODE (expr);
- first_rtl = tree_code_length [(int) code];
- switch (code)
+void
+unsave_expr_1 (expr)
+ tree expr;
+{
+ switch (TREE_CODE (expr))
{
case SAVE_EXPR:
- SAVE_EXPR_RTL (expr) = 0;
- first_rtl = 2;
+ 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 ();
- first_rtl = 0;
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);
- }
- }
- first_rtl = 2;
- break;
-
- case WITH_CLEANUP_EXPR:
- /* Should be defined to be 2. */
- first_rtl = 1;
- break;
-
- case METHOD_CALL_EXPR:
- first_rtl = 3;
break;
default:
+ if (lang_unsave_expr_now)
+ (*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. */
default:
return 0;
}
+ return 0;
}
-\f
-/* Given a tree EXP, a FIELD_DECL F, and a replacement value R,
- return a tree with all occurrences of references to F in a
- PLACEHOLDER_EXPR replaced by R. Note that we assume here that EXP
- contains only arithmetic expressions or a CALL_EXPR with a
- PLACEHOLDER_EXPR occurring only in its arglist. */
-tree
-substitute_in_expr (exp, f, r)
+/* Return 1 if EXP contains any expressions that produce cleanups for an
+ outer scope to deal with. Used by fold. */
+
+int
+has_cleanups (exp)
tree exp;
- tree f;
- tree r;
{
- enum tree_code code = TREE_CODE (exp);
- tree op0, op1, op2;
- tree new;
- tree inner;
+ int i, nops, cmp;
- switch (TREE_CODE_CLASS (code))
+ if (! TREE_SIDE_EFFECTS (exp))
+ return 0;
+
+ switch (TREE_CODE (exp))
{
- case 'c':
- case 'd':
- return exp;
+ case TARGET_EXPR:
+ case GOTO_SUBROUTINE_EXPR:
+ case WITH_CLEANUP_EXPR:
+ return 1;
- case 'x':
- if (code == PLACEHOLDER_EXPR)
- return exp;
- else if (code == TREE_LIST)
- {
+ case CLEANUP_POINT_EXPR:
+ return 0;
+
+ case CALL_EXPR:
+ for (exp = TREE_OPERAND (exp, 1); exp; exp = TREE_CHAIN (exp))
+ {
+ cmp = has_cleanups (TREE_VALUE (exp));
+ if (cmp)
+ return cmp;
+ }
+ return 0;
+
+ default:
+ break;
+ }
+
+ /* This general rule works for most tree codes. All exceptions should be
+ handled above. If this is a language-specific tree code, we can't
+ trust what might be in the operand, so say we don't know
+ the situation. */
+ if ((int) TREE_CODE (exp) >= (int) LAST_AND_UNUSED_TREE_CODE)
+ return -1;
+
+ nops = first_rtl_op (TREE_CODE (exp));
+ for (i = 0; i < nops; i++)
+ if (TREE_OPERAND (exp, i) != 0)
+ {
+ int type = TREE_CODE_CLASS (TREE_CODE (TREE_OPERAND (exp, i)));
+ if (type == 'e' || type == '<' || type == '1' || type == '2'
+ || type == 'r' || type == 's')
+ {
+ cmp = has_cleanups (TREE_OPERAND (exp, i));
+ if (cmp)
+ return cmp;
+ }
+ }
+
+ return 0;
+}
+\f
+/* Given a tree EXP, a FIELD_DECL F, and a replacement value R,
+ return a tree with all occurrences of references to F in a
+ PLACEHOLDER_EXPR replaced by R. Note that we assume here that EXP
+ contains only arithmetic expressions or a CALL_EXPR with a
+ PLACEHOLDER_EXPR occurring only in its arglist. */
+
+tree
+substitute_in_expr (exp, f, r)
+ tree exp;
+ tree f;
+ tree r;
+{
+ enum tree_code code = TREE_CODE (exp);
+ tree op0, op1, op2;
+ tree new;
+ tree inner;
+
+ switch (TREE_CODE_CLASS (code))
+ {
+ case 'c':
+ case 'd':
+ return exp;
+
+ case 'x':
+ if (code == PLACEHOLDER_EXPR)
+ return exp;
+ else if (code == TREE_LIST)
+ {
op0 = (TREE_CHAIN (exp) == 0
? 0 : substitute_in_expr (TREE_CHAIN (exp), f, r));
op1 = substitute_in_expr (TREE_VALUE (exp), f, r);
tree
build VPROTO((enum tree_code code, tree tt, ...))
{
-#ifndef __STDC__
+#ifndef ANSI_PROTOTYPES
enum tree_code code;
tree tt;
#endif
register tree t;
register int length;
register int i;
+ int fro;
VA_START (p, tt);
-#ifndef __STDC__
+#ifndef ANSI_PROTOTYPES
code = va_arg (p, enum tree_code);
tt = va_arg (p, tree);
#endif
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;
tree node;
{
register struct obstack *obstack = expression_obstack;
- register int i, length;
+ register int length;
#ifdef GATHER_STATISTICS
register tree_node_kind kind;
#endif
length = sizeof (struct tree_exp);
- t = (tree) obstack_alloc (obstack, length);
+ if (ggc_p)
+ t = ggc_alloc_tree (length);
+ else
+ {
+ t = (tree) obstack_alloc (obstack, length);
+ memset ((PTR) t, 0, length);
+ }
#ifdef GATHER_STATISTICS
tree_node_counts[(int)kind]++;
tree_node_sizes[(int)kind] += length;
#endif
- for (i = (length / sizeof (int)) - 1; i >= 0; i--)
- ((int *) t)[i] = 0;
-
TREE_TYPE (t) = type;
TREE_SET_CODE (t, code);
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;
}
tree
build_nt VPROTO((enum tree_code code, ...))
{
-#ifndef __STDC__
+#ifndef ANSI_PROTOTYPES
enum tree_code code;
#endif
va_list p;
VA_START (p, code);
-#ifndef __STDC__
+#ifndef ANSI_PROTOTYPES
code = va_arg (p, enum tree_code);
#endif
tree
build_parse_node VPROTO((enum tree_code code, ...))
{
-#ifndef __STDC__
+#ifndef ANSI_PROTOTYPES
enum tree_code code;
#endif
register struct obstack *ambient_obstack = expression_obstack;
VA_START (p, code);
-#ifndef __STDC__
+#ifndef ANSI_PROTOTYPES
code = va_arg (p, enum tree_code);
#endif
{
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;
return block;
}
+
+/* EXPR_WITH_FILE_LOCATION are used to keep track of the exact
+ location where an expression or an identifier were encountered. It
+ is necessary for languages where the frontend parser will handle
+ recursively more than one file (Java is one of them). */
+
+tree
+build_expr_wfl (node, file, line, col)
+ tree node;
+ const char *file;
+ int line, col;
+{
+ static const char *last_file = 0;
+ static tree last_filenode = NULL_TREE;
+ register tree wfl = make_node (EXPR_WITH_FILE_LOCATION);
+
+ EXPR_WFL_NODE (wfl) = node;
+ EXPR_WFL_SET_LINECOL (wfl, line, col);
+ if (file != last_file)
+ {
+ last_file = file;
+ last_filenode = file ? get_identifier (file) : NULL_TREE;
+ }
+ EXPR_WFL_FILENAME_NODE (wfl) = last_filenode;
+ if (node)
+ {
+ TREE_SIDE_EFFECTS (wfl) = TREE_SIDE_EFFECTS (node);
+ TREE_TYPE (wfl) = TREE_TYPE (node);
+ }
+ return wfl;
+}
\f
/* Return a declaration like DDECL except that its DECL_MACHINE_ATTRIBUTE
is 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);
- current_obstack = ambient_obstack;
TYPE_POINTER_TO (ntype) = 0;
TYPE_REFERENCE_TO (ntype) = 0;
/* Create a new main variant of TYPE. */
TYPE_MAIN_VARIANT (ntype) = ntype;
TYPE_NEXT_VARIANT (ntype) = 0;
- TYPE_READONLY (ntype) = TYPE_VOLATILE (ntype) = 0;
+ set_type_quals (ntype, TYPE_UNQUALIFIED);
hashcode = TYPE_HASH (TREE_CODE (ntype))
+ TYPE_HASH (TREE_TYPE (ntype))
}
ntype = type_hash_canon (hashcode, ntype);
- ttype = build_type_variant (ntype, TYPE_READONLY (ttype),
- TYPE_VOLATILE (ttype));
+ ttype = build_qualified_type (ntype, TYPE_QUALS (ttype));
+ pop_obstacks ();
}
return ttype;
int
valid_machine_attribute (attr_name, attr_args, decl, type)
- tree attr_name, attr_args;
- tree decl;
- tree type;
+ tree attr_name;
+ tree attr_args ATTRIBUTE_UNUSED;
+ tree decl ATTRIBUTE_UNUSED;
+ tree type ATTRIBUTE_UNUSED;
{
- int valid = 0;
+ int validated = 0;
+#ifdef VALID_MACHINE_DECL_ATTRIBUTE
tree decl_attr_list = decl != 0 ? DECL_MACHINE_ATTRIBUTES (decl) : 0;
+#endif
+#ifdef VALID_MACHINE_TYPE_ATTRIBUTE
tree type_attr_list = TYPE_ATTRIBUTES (type);
+#endif
if (TREE_CODE (attr_name) != IDENTIFIER_NODE)
abort ();
decl = build_decl_attribute_variant (decl, decl_attr_list);
}
- valid = 1;
+ validated = 1;
}
#endif
#ifdef VALID_MACHINE_TYPE_ATTRIBUTE
- if (VALID_MACHINE_TYPE_ATTRIBUTE (type, type_attr_list, attr_name, attr_args))
+ if (validated)
+ /* Don't apply the attribute to both the decl and the type. */;
+ else if (VALID_MACHINE_TYPE_ATTRIBUTE (type, type_attr_list, attr_name,
+ attr_args))
{
tree attr = lookup_attribute (IDENTIFIER_POINTER (attr_name),
type_attr_list);
}
else
{
+ /* If this is part of a declaration, create a type variant,
+ otherwise, this is part of a type definition, so add it
+ to the base type. */
type_attr_list = tree_cons (attr_name, attr_args, type_attr_list);
- type = build_type_attribute_variant (type, type_attr_list);
+ if (decl != 0)
+ type = build_type_attribute_variant (type, type_attr_list);
+ else
+ TYPE_ATTRIBUTES (type) = type_attr_list;
}
if (decl != 0)
TREE_TYPE (decl) = type;
- valid = 1;
+ validated = 1;
}
/* Handle putting a type attribute on pointer-to-function-type by putting
the attribute on the function type. */
- else if (TREE_CODE (type) == POINTER_TYPE
+ else if (POINTER_TYPE_P (type)
&& TREE_CODE (TREE_TYPE (type)) == FUNCTION_TYPE
&& VALID_MACHINE_TYPE_ATTRIBUTE (TREE_TYPE (type), type_attr_list,
attr_name, attr_args))
if (decl != 0)
TREE_TYPE (decl) = build_pointer_type (inner_type);
+ else
+ {
+ /* Clear TYPE_POINTER_TO for the old inner type, since
+ `type' won't be pointing to it anymore. */
+ TYPE_POINTER_TO (TREE_TYPE (type)) = NULL_TREE;
+ TREE_TYPE (type) = inner_type;
+ }
- valid = 1;
+ validated = 1;
}
#endif
- return valid;
+ return validated;
}
/* Return non-zero if IDENT is a valid name for attribute ATTR,
int
is_attribute_p (attr, ident)
- char *attr;
+ const char *attr;
tree ident;
{
int ident_len, attr_len;
tree
lookup_attribute (attr_name, list)
- char *attr_name;
+ const char *attr_name;
tree list;
{
tree l;
/* One that completely contains the other? Take it. */
else if (a2 && ! attribute_list_contained (a1, a2))
+ {
if (attribute_list_contained (a2, a1))
attributes = a2;
else
attributes = a1;
}
}
+ }
return attributes;
}
-\f
-/* Return a type like TYPE except that its TYPE_READONLY is CONSTP
- and its TYPE_VOLATILE is VOLATILEP.
- Such variant types already made are recorded so that duplicates
- are not made.
+/* Given types T1 and T2, merge their attributes and return
+ the result. */
- A variant types should never be used as the type of an expression.
- Always copy the variant information into the TREE_READONLY
- and TREE_THIS_VOLATILE of the expression, and then give the expression
- as its type the "main variant", the variant whose TYPE_READONLY
- and TYPE_VOLATILE are zero. Use TYPE_MAIN_VARIANT to find the
- main variant. */
+tree
+merge_machine_type_attributes (t1, t2)
+ tree t1, t2;
+{
+#ifdef MERGE_MACHINE_TYPE_ATTRIBUTES
+ return MERGE_MACHINE_TYPE_ATTRIBUTES (t1, t2);
+#else
+ return merge_attributes (TYPE_ATTRIBUTES (t1),
+ TYPE_ATTRIBUTES (t2));
+#endif
+}
+
+/* Given decls OLDDECL and NEWDECL, merge their attributes and return
+ the result. */
tree
-build_type_variant (type, constp, volatilep)
+merge_machine_decl_attributes (olddecl, newdecl)
+ tree olddecl, newdecl;
+{
+#ifdef MERGE_MACHINE_DECL_ATTRIBUTES
+ return MERGE_MACHINE_DECL_ATTRIBUTES (olddecl, newdecl);
+#else
+ return merge_attributes (DECL_MACHINE_ATTRIBUTES (olddecl),
+ DECL_MACHINE_ATTRIBUTES (newdecl));
+#endif
+}
+\f
+/* Set the type qualifiers for TYPE to TYPE_QUALS, which is a bitmask
+ of the various TYPE_QUAL values. */
+
+static void
+set_type_quals (type, type_quals)
tree type;
- int constp, volatilep;
+ int type_quals;
{
- register tree t;
+ TYPE_READONLY (type) = (type_quals & TYPE_QUAL_CONST) != 0;
+ TYPE_VOLATILE (type) = (type_quals & TYPE_QUAL_VOLATILE) != 0;
+ TYPE_RESTRICT (type) = (type_quals & TYPE_QUAL_RESTRICT) != 0;
+}
- /* Treat any nonzero argument as 1. */
- constp = !!constp;
- volatilep = !!volatilep;
+/* Given a type node TYPE and a TYPE_QUALIFIER_SET, return a type for
+ the same kind of data as TYPE describes. Variants point to the
+ "main variant" (which has no qualifiers set) via TYPE_MAIN_VARIANT,
+ and it points to a chain of other variants so that duplicate
+ variants are never made. Only main variants should ever appear as
+ types of expressions. */
+tree
+build_qualified_type (type, type_quals)
+ tree type;
+ int type_quals;
+{
+ register tree t;
+
/* Search the chain of variants to see if there is already one there just
like the one we need to have. If so, use that existing one. We must
preserve the TYPE_NAME, since there is code that depends on this. */
for (t = TYPE_MAIN_VARIANT (type); t; t = TYPE_NEXT_VARIANT (t))
- if (constp == TYPE_READONLY (t) && volatilep == TYPE_VOLATILE (t)
- && TYPE_NAME (t) == TYPE_NAME (type))
+ if (TYPE_QUALS (t) == type_quals && TYPE_NAME (t) == TYPE_NAME (type))
return t;
/* We need a new one. */
-
t = build_type_copy (type);
- TYPE_READONLY (t) = constp;
- TYPE_VOLATILE (t) = volatilep;
-
+ set_type_quals (t, type_quals);
return t;
}
/* Hashing of types so that we don't make duplicates.
The entry point is `type_hash_canon'. */
-/* Each hash table slot is a bucket containing a chain
- of these structures. */
-
-struct type_hash
-{
- struct type_hash *next; /* Next structure in the bucket. */
- int hashcode; /* Hash code of this type. */
- tree type; /* The type recorded here. */
-};
-
-/* Now here is the hash table. When recording a type, it is added
- to the slot whose index is the hash code mod the table size.
- Note that the hash table is used for several kinds of types
- (function types, array types and array index range types, for now).
- While all these live in the same table, they are completely independent,
- and the hash code is computed differently for each of these. */
-
-#define TYPE_HASH_SIZE 59
-struct type_hash *type_hash_table[TYPE_HASH_SIZE];
-
/* Compute a hash code for a list of types (chain of TREE_LIST nodes
with types in the TREE_VALUE slots), by adding the hash codes
of the individual types. */
tree type;
{
register struct type_hash *h;
+
+ /* The TYPE_ALIGN field of a type is set by layout_type(), so we
+ must call that routine before comparing TYPE_ALIGNs. */
+ layout_type (type);
+
for (h = type_hash_table[hashcode % TYPE_HASH_SIZE]; h; h = h->next)
if (h->hashcode == hashcode
&& TREE_CODE (h->type) == TREE_CODE (type)
&& TREE_TYPE (h->type) == TREE_TYPE (type)
&& attribute_list_equal (TYPE_ATTRIBUTES (h->type),
TYPE_ATTRIBUTES (type))
+ && TYPE_ALIGN (h->type) == TYPE_ALIGN (type)
&& (TYPE_MAX_VALUE (h->type) == TYPE_MAX_VALUE (type)
|| tree_int_cst_equal (TYPE_MAX_VALUE (h->type),
TYPE_MAX_VALUE (type)))
{
register struct type_hash *h;
- h = (struct type_hash *) oballoc (sizeof (struct type_hash));
+ h = (struct type_hash *) permalloc (sizeof (struct type_hash));
h->hashcode = hashcode;
h->type = type;
h->next = type_hash_table[hashcode % TYPE_HASH_SIZE];
t1 = type_hash_lookup (hashcode, type);
if (t1 != 0)
{
- obstack_free (TYPE_OBSTACK (type), type);
+ if (!ggc_p)
+ obstack_free (TYPE_OBSTACK (type), type);
#ifdef GATHER_STATISTICS
tree_node_counts[(int)t_kind]--;
tree_node_sizes[(int)t_kind] -= sizeof (struct tree_type);
}
/* If this is a permanent type, record it for later reuse. */
- if (TREE_PERMANENT (type))
+ if (ggc_p || TREE_PERMANENT (type))
type_hash_add (hashcode, type);
return type;
}
+/* Mark ARG (which is really a struct type_hash **) for GC. */
+
+static void
+mark_type_hash (arg)
+ void *arg;
+{
+ struct type_hash *t = *(struct type_hash **) arg;
+
+ while (t)
+ {
+ ggc_mark_tree (t->type);
+ t = t->next;
+ }
+}
+
/* Compute a hash code for a list of attributes (chain of TREE_LIST nodes
with names in the TREE_PURPOSE slots and args in the TREE_VALUE slots),
by adding the hash codes of the individual attributes. */
code2 = TREE_CODE (t2);
if (code1 == NOP_EXPR || code1 == CONVERT_EXPR || code1 == NON_LVALUE_EXPR)
- if (code2 == NOP_EXPR || code2 == CONVERT_EXPR || code2 == NON_LVALUE_EXPR)
- return simple_cst_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0));
- else
- return simple_cst_equal (TREE_OPERAND (t1, 0), t2);
+ {
+ if (code2 == NOP_EXPR || code2 == CONVERT_EXPR
+ || code2 == NON_LVALUE_EXPR)
+ return simple_cst_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0));
+ else
+ return simple_cst_equal (TREE_OPERAND (t1, 0), t2);
+ }
else if (code2 == NOP_EXPR || code2 == CONVERT_EXPR
|| code2 == NON_LVALUE_EXPR)
return simple_cst_equal (t1, TREE_OPERAND (t2, 0));
TREE_STRING_LENGTH (t1));
case CONSTRUCTOR:
- abort ();
+ if (CONSTRUCTOR_ELTS (t1) == CONSTRUCTOR_ELTS (t2))
+ return 1;
+ else
+ abort ();
case SAVE_EXPR:
return simple_cst_equal (TREE_OPERAND (t1, 0), TREE_OPERAND (t2, 0));
TYPE_MODE (itype) = TYPE_MODE (sizetype);
TYPE_SIZE (itype) = TYPE_SIZE (sizetype);
+ TYPE_SIZE_UNIT (itype) = TYPE_SIZE_UNIT (sizetype);
TYPE_ALIGN (itype) = TYPE_ALIGN (sizetype);
if (TREE_CODE (maxval) == INTEGER_CST)
{
TYPE_PRECISION (itype) = TYPE_PRECISION (type);
TYPE_MODE (itype) = TYPE_MODE (type);
TYPE_SIZE (itype) = TYPE_SIZE (type);
+ TYPE_SIZE_UNIT (itype) = TYPE_SIZE_UNIT (type);
TYPE_ALIGN (itype) = TYPE_ALIGN (type);
if (TREE_CODE (lowval) == INTEGER_CST)
{
return t;
}
+/* Return the TYPE of the elements comprising
+ the innermost dimension of ARRAY. */
+
+tree
+get_inner_array_type (array)
+ tree array;
+{
+ tree type = TREE_TYPE (array);
+
+ while (TREE_CODE (type) == ARRAY_TYPE)
+ type = TREE_TYPE (type);
+
+ return type;
+}
+
/* Construct, lay out and return
the type of functions returning type VALUE_TYPE
given arguments of types ARG_TYPES.
tree to_type;
{
register tree t = TYPE_REFERENCE_TO (to_type);
- register struct obstack *ambient_obstack = current_obstack;
- register struct obstack *ambient_saveable_obstack = saveable_obstack;
/* First, if we already have a type for pointers to TO_TYPE, use it. */
if (t)
return t;
- /* We need a new one. If TO_TYPE is permanent, make this permanent too. */
- if (TREE_PERMANENT (to_type))
- {
- current_obstack = &permanent_obstack;
- saveable_obstack = &permanent_obstack;
- }
-
+ /* We need a new one. Put this in the same obstack as TO_TYPE. */
+ push_obstacks (TYPE_OBSTACK (to_type), TYPE_OBSTACK (to_type));
t = make_node (REFERENCE_TYPE);
+ pop_obstacks ();
+
TREE_TYPE (t) = to_type;
/* Record this type as the pointer to TO_TYPE. */
layout_type (t);
- current_obstack = ambient_obstack;
- saveable_obstack = ambient_saveable_obstack;
return t;
}
t = make_node (COMPLEX_TYPE);
TREE_TYPE (t) = TYPE_MAIN_VARIANT (component_type);
- TYPE_VOLATILE (t) = TYPE_VOLATILE (component_type);
- TYPE_READONLY (t) = TYPE_READONLY (component_type);
+ set_type_quals (t, TYPE_QUALS (component_type));
/* If we already have such a type, use the old one and free this one. */
hashcode = TYPE_HASH (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
tree for_type;
{
/* Set UNS initially if converting OP to FOR_TYPE is a zero-extension. */
- /* TYPE_PRECISION is safe in place of type_precision since
- pointer types are not allowed. */
register tree type = TREE_TYPE (op);
register unsigned final_prec
= TYPE_PRECISION (for_type != 0 ? for_type : type);
return win;
}
\f
-/* Return the precision of a type, for arithmetic purposes.
- Supports all types on which arithmetic is possible
- (including pointer types).
- It's not clear yet what will be right for complex types. */
-
-int
-type_precision (type)
- register tree type;
-{
- return ((TREE_CODE (type) == INTEGER_TYPE
- || TREE_CODE (type) == ENUMERAL_TYPE
- || TREE_CODE (type) == REAL_TYPE)
- ? TYPE_PRECISION (type) : POINTER_SIZE);
-}
-
/* Nonzero if integer constant C has a value that is permissible
for type TYPE (an INTEGER_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. */
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 (context) == RECORD_TYPE
- || TREE_CODE (context) == UNION_TYPE
- || TREE_CODE (context) == QUAL_UNION_TYPE)
- context = TYPE_CONTEXT (context);
- else if (TREE_CODE (context) == TYPE_DECL)
- 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;
}
-/* Print debugging information about the size of the
- toplev_inline_obstacks. */
+/* CALL is a CALL_EXPR. Return the declaration for the function
+ called, or NULL_TREE if the called function cannot be
+ determined. */
-void
-print_inline_obstack_statistics ()
+tree
+get_callee_fndecl (call)
+ tree call;
{
- struct simple_obstack_stack *current = toplev_inline_obstacks;
- int n_obstacks = 0;
- int n_alloc = 0;
- int n_chunks = 0;
+ tree addr;
- for (; current; current = current->next, ++n_obstacks)
- {
- struct obstack *o = current->obstack;
- struct _obstack_chunk *chunk = o->chunk;
+ /* It's invalid to call this function with anything but a
+ CALL_EXPR. */
+ if (TREE_CODE (call) != CALL_EXPR)
+ abort ();
- n_alloc += o->next_free - chunk->contents;
- chunk = chunk->prev;
- ++n_chunks;
- for (; chunk; chunk = chunk->prev, ++n_chunks)
- n_alloc += chunk->limit - &chunk->contents[0];
- }
- fprintf (stderr, "inline obstacks: %d obstacks, %d bytes, %d chunks\n",
- n_obstacks, n_alloc, n_chunks);
+ /* 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
print_obstack_statistics (str, o)
- char *str;
+ const char *str;
struct obstack *o;
{
struct _obstack_chunk *chunk = o->chunk;
print_obstack_statistics ("temporary_obstack", &temporary_obstack);
print_obstack_statistics ("momentary_obstack", &momentary_obstack);
print_obstack_statistics ("temp_decl_obstack", &temp_decl_obstack);
- print_inline_obstack_statistics ();
print_lang_statistics ();
}
\f
#define FILE_FUNCTION_PREFIX_LEN 9
#ifndef NO_DOLLAR_IN_LABEL
-#define FILE_FUNCTION_FORMAT "_GLOBAL_$D$%s"
+#define FILE_FUNCTION_FORMAT "_GLOBAL_$%s$%s"
#else /* NO_DOLLAR_IN_LABEL */
#ifndef NO_DOT_IN_LABEL
-#define FILE_FUNCTION_FORMAT "_GLOBAL_.D.%s"
+#define FILE_FUNCTION_FORMAT "_GLOBAL_.%s.%s"
#else /* NO_DOT_IN_LABEL */
-#define FILE_FUNCTION_FORMAT "_GLOBAL__D_%s"
+#define FILE_FUNCTION_FORMAT "_GLOBAL__%s_%s"
#endif /* NO_DOT_IN_LABEL */
#endif /* NO_DOLLAR_IN_LABEL */
extern char * first_global_object_name;
+extern char * weak_global_object_name;
-/* If KIND=='I', return a suitable global initializer (constructor) name.
- If KIND=='D', return a suitable global clean-up (destructor) name. */
+/* Appends 6 random characters to TEMPLATE to (hopefully) avoid name
+ clashes in cases where we can't reliably choose a unique name.
+
+ Derived from mkstemp.c in libiberty. */
+
+static void
+append_random_chars (template)
+ char *template;
+{
+ static const char letters[]
+ = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+ static unsigned HOST_WIDE_INT value;
+ unsigned HOST_WIDE_INT v;
+
+#ifdef HAVE_GETTIMEOFDAY
+ struct timeval tv;
+#endif
+
+ template += strlen (template);
+
+#ifdef HAVE_GETTIMEOFDAY
+ /* Get some more or less random data. */
+ gettimeofday (&tv, NULL);
+ value += ((unsigned HOST_WIDE_INT) tv.tv_usec << 16) ^ tv.tv_sec ^ getpid ();
+#else
+ value += getpid ();
+#endif
+
+ v = value;
+
+ /* Fill in the random bits. */
+ template[0] = letters[v % 62];
+ v /= 62;
+ template[1] = letters[v % 62];
+ v /= 62;
+ template[2] = letters[v % 62];
+ v /= 62;
+ template[3] = letters[v % 62];
+ v /= 62;
+ template[4] = letters[v % 62];
+ v /= 62;
+ template[5] = letters[v % 62];
+
+ template[6] = '\0';
+}
+
+/* Generate a name for a function unique to this translation unit.
+ TYPE is some string to identify the purpose of this function to the
+ linker or collect2. */
tree
-get_file_function_name (kind)
- int kind;
+get_file_function_name_long (type)
+ const char *type;
{
char *buf;
register char *p;
if (first_global_object_name)
p = first_global_object_name;
- else if (main_input_filename)
- p = main_input_filename;
else
- p = input_filename;
+ {
+ /* We don't have anything that we know to be unique to this translation
+ unit, so use what we do have and throw in some randomness. */
- buf = (char *) alloca (sizeof (FILE_FUNCTION_FORMAT) + strlen (p));
+ const char *name = weak_global_object_name;
+ const char *file = main_input_filename;
+
+ if (! name)
+ name = "";
+ if (! file)
+ file = input_filename;
+
+ p = (char *) alloca (7 + strlen (name) + strlen (file));
+
+ sprintf (p, "%s%s", name, file);
+ append_random_chars (p);
+ }
+
+ buf = (char *) alloca (sizeof (FILE_FUNCTION_FORMAT) + strlen (p)
+ + strlen (type));
/* Set up the name of the file-level functions we may need. */
/* Use a global object (which is already required to be unique over
the program) rather than the file name (which imposes extra
constraints). -- Raeburn@MIT.EDU, 10 Jan 1990. */
- sprintf (buf, FILE_FUNCTION_FORMAT, p);
+ sprintf (buf, FILE_FUNCTION_FORMAT, type, p);
/* Don't need to pull weird characters out of global names. */
if (p != first_global_object_name)
{
for (p = buf+11; *p; p++)
- if (! ((*p >= '0' && *p <= '9')
+ if (! ( ISDIGIT(*p)
#if 0 /* we always want labels, which are valid C++ identifiers (+ `$') */
#ifndef ASM_IDENTIFY_GCC /* this is required if `.' is invalid -- k. raeburn */
|| *p == '.'
#ifndef NO_DOT_IN_LABEL /* this for `.'; unlikely, but... */
|| *p == '.'
#endif
- || (*p >= 'A' && *p <= 'Z')
- || (*p >= 'a' && *p <= 'z')))
+ || ISUPPER(*p)
+ || ISLOWER(*p)))
*p = '_';
}
- buf[FILE_FUNCTION_PREFIX_LEN] = kind;
-
return get_identifier (buf);
}
+
+/* If KIND=='I', return a suitable global initializer (constructor) name.
+ If KIND=='D', return a suitable global clean-up (destructor) name. */
+
+tree
+get_file_function_name (kind)
+ int kind;
+{
+ char p[2];
+ p[0] = kind;
+ p[1] = 0;
+
+ return get_file_function_name_long (p);
+}
+
\f
/* Expand (the constant part of) a SET_TYPE CONSTRUCTOR node.
The result is placed in BUFFER (which has length BIT_SIZE),
}
return non_const_bits;
}
+\f
+#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
+tree_check_failed (node, code, file, line, function)
+ const tree node;
+ enum tree_code code;
+ const char *file;
+ int line;
+ const char *function;
+{
+ error ("Tree check: expected %s, have %s",
+ tree_code_name[code], tree_code_name[TREE_CODE (node)]);
+ fancy_abort (file, line, function);
+}
+
+/* Similar to above, except that we check for a class of tree
+ code, given in CL. */
+void
+tree_class_check_failed (node, cl, file, line, function)
+ const tree node;
+ char cl;
+ const char *file;
+ int line;
+ const char *function;
+{
+ error ("Tree check: expected class '%c', have '%c' (%s)",
+ cl, TREE_CODE_CLASS (TREE_CODE (node)),
+ tree_code_name[TREE_CODE (node)]);
+ fancy_abort (file, line, function);
+}
+
+#endif /* ENABLE_CHECKING */
+
+/* Return the alias set for T, which may be either a type or an
+ expression. */
+
+int
+get_alias_set (t)
+ tree t;
+{
+ if (!flag_strict_aliasing || !lang_get_alias_set)
+ /* If we're not doing any lanaguage-specific alias analysis, just
+ assume everything aliases everything else. */
+ return 0;
+ else
+ return (*lang_get_alias_set) (t);
+}
+
+/* Return a brand-new alias set. */
+
+int
+new_alias_set ()
+{
+ static int last_alias_set;
+ if (flag_strict_aliasing)
+ return ++last_alias_set;
+ else
+ return 0;
+}
+\f
+#ifndef CHAR_TYPE_SIZE
+#define CHAR_TYPE_SIZE BITS_PER_UNIT
+#endif
+
+#ifndef SHORT_TYPE_SIZE
+#define SHORT_TYPE_SIZE (BITS_PER_UNIT * MIN ((UNITS_PER_WORD + 1) / 2, 2))
+#endif
+
+#ifndef INT_TYPE_SIZE
+#define INT_TYPE_SIZE BITS_PER_WORD
+#endif
+
+#ifndef LONG_TYPE_SIZE
+#define LONG_TYPE_SIZE BITS_PER_WORD
+#endif
+
+#ifndef LONG_LONG_TYPE_SIZE
+#define LONG_LONG_TYPE_SIZE (BITS_PER_WORD * 2)
+#endif
+
+#ifndef FLOAT_TYPE_SIZE
+#define FLOAT_TYPE_SIZE BITS_PER_WORD
+#endif
+
+#ifndef DOUBLE_TYPE_SIZE
+#define DOUBLE_TYPE_SIZE (BITS_PER_WORD * 2)
+#endif
+
+#ifndef LONG_DOUBLE_TYPE_SIZE
+#define LONG_DOUBLE_TYPE_SIZE (BITS_PER_WORD * 2)
+#endif
+
+/* Create nodes for all integer types (and error_mark_node) using the sizes
+ of C datatypes. The caller should call set_sizetype soon after calling
+ this function to select one of the types as sizetype. */
+
+void
+build_common_tree_nodes (signed_char)
+ int signed_char;
+{
+ error_mark_node = make_node (ERROR_MARK);
+ TREE_TYPE (error_mark_node) = error_mark_node;
+
+ /* Define both `signed char' and `unsigned char'. */
+ signed_char_type_node = make_signed_type (CHAR_TYPE_SIZE);
+ unsigned_char_type_node = make_unsigned_type (CHAR_TYPE_SIZE);
+
+ /* Define `char', which is like either `signed char' or `unsigned char'
+ but not the same as either. */
+ char_type_node
+ = (signed_char
+ ? make_signed_type (CHAR_TYPE_SIZE)
+ : make_unsigned_type (CHAR_TYPE_SIZE));
+
+ short_integer_type_node = make_signed_type (SHORT_TYPE_SIZE);
+ short_unsigned_type_node = make_unsigned_type (SHORT_TYPE_SIZE);
+ integer_type_node = make_signed_type (INT_TYPE_SIZE);
+ /* Define an unsigned integer first. make_unsigned_type and make_signed_type
+ both call set_sizetype for the first type that we create, and we want this
+ to be large enough to hold the sizes of various types until we switch to
+ the real sizetype. */
+ unsigned_type_node = make_unsigned_type (INT_TYPE_SIZE);
+ long_integer_type_node = make_signed_type (LONG_TYPE_SIZE);
+ long_unsigned_type_node = make_unsigned_type (LONG_TYPE_SIZE);
+ long_long_integer_type_node = make_signed_type (LONG_LONG_TYPE_SIZE);
+ long_long_unsigned_type_node = make_unsigned_type (LONG_LONG_TYPE_SIZE);
+
+ intQI_type_node = make_signed_type (GET_MODE_BITSIZE (QImode));
+ intHI_type_node = make_signed_type (GET_MODE_BITSIZE (HImode));
+ intSI_type_node = make_signed_type (GET_MODE_BITSIZE (SImode));
+ intDI_type_node = make_signed_type (GET_MODE_BITSIZE (DImode));
+ intTI_type_node = make_signed_type (GET_MODE_BITSIZE (TImode));
+
+ unsigned_intQI_type_node = make_unsigned_type (GET_MODE_BITSIZE (QImode));
+ unsigned_intHI_type_node = make_unsigned_type (GET_MODE_BITSIZE (HImode));
+ unsigned_intSI_type_node = make_unsigned_type (GET_MODE_BITSIZE (SImode));
+ unsigned_intDI_type_node = make_unsigned_type (GET_MODE_BITSIZE (DImode));
+ unsigned_intTI_type_node = make_unsigned_type (GET_MODE_BITSIZE (TImode));
+}
+
+/* For type TYPE, fill in the proper type for TYPE_SIZE and
+ TYPE_SIZE_UNIT. */
+static void
+fix_sizetype (type)
+ tree type;
+{
+ TREE_TYPE (TYPE_SIZE (type)) = bitsizetype;
+ TREE_TYPE (TYPE_SIZE_UNIT (type)) = sizetype;
+}
+
+/* Call this function after calling build_common_tree_nodes and set_sizetype.
+ It will fix the previously made nodes to have proper references to
+ sizetype, and it will create several other common tree nodes. */
+void
+build_common_tree_nodes_2 (short_double)
+ int short_double;
+{
+ fix_sizetype (signed_char_type_node);
+ fix_sizetype (unsigned_char_type_node);
+ fix_sizetype (char_type_node);
+ fix_sizetype (short_integer_type_node);
+ fix_sizetype (short_unsigned_type_node);
+ fix_sizetype (integer_type_node);
+ fix_sizetype (unsigned_type_node);
+ fix_sizetype (long_unsigned_type_node);
+ fix_sizetype (long_integer_type_node);
+ fix_sizetype (long_long_integer_type_node);
+ fix_sizetype (long_long_unsigned_type_node);
+
+ fix_sizetype (intQI_type_node);
+ fix_sizetype (intHI_type_node);
+ fix_sizetype (intSI_type_node);
+ fix_sizetype (intDI_type_node);
+ fix_sizetype (intTI_type_node);
+ fix_sizetype (unsigned_intQI_type_node);
+ fix_sizetype (unsigned_intHI_type_node);
+ fix_sizetype (unsigned_intSI_type_node);
+ fix_sizetype (unsigned_intDI_type_node);
+ fix_sizetype (unsigned_intTI_type_node);
+
+ integer_zero_node = build_int_2 (0, 0);
+ TREE_TYPE (integer_zero_node) = integer_type_node;
+ integer_one_node = build_int_2 (1, 0);
+ TREE_TYPE (integer_one_node) = integer_type_node;
+
+ size_zero_node = build_int_2 (0, 0);
+ TREE_TYPE (size_zero_node) = sizetype;
+ size_one_node = build_int_2 (1, 0);
+ TREE_TYPE (size_one_node) = sizetype;
+
+ void_type_node = make_node (VOID_TYPE);
+ layout_type (void_type_node); /* Uses size_zero_node */
+ /* We are not going to have real types in C with less than byte alignment,
+ so we might as well not have any types that claim to have it. */
+ TYPE_ALIGN (void_type_node) = BITS_PER_UNIT;
+
+ null_pointer_node = build_int_2 (0, 0);
+ TREE_TYPE (null_pointer_node) = build_pointer_type (void_type_node);
+ layout_type (TREE_TYPE (null_pointer_node));
+
+ ptr_type_node = build_pointer_type (void_type_node);
+ const_ptr_type_node
+ = build_pointer_type (build_type_variant (void_type_node, 1, 0));
+
+ float_type_node = make_node (REAL_TYPE);
+ TYPE_PRECISION (float_type_node) = FLOAT_TYPE_SIZE;
+ layout_type (float_type_node);
+
+ double_type_node = make_node (REAL_TYPE);
+ if (short_double)
+ TYPE_PRECISION (double_type_node) = FLOAT_TYPE_SIZE;
+ else
+ TYPE_PRECISION (double_type_node) = DOUBLE_TYPE_SIZE;
+ layout_type (double_type_node);
+
+ long_double_type_node = make_node (REAL_TYPE);
+ TYPE_PRECISION (long_double_type_node) = LONG_DOUBLE_TYPE_SIZE;
+ layout_type (long_double_type_node);
+
+ complex_integer_type_node = make_node (COMPLEX_TYPE);
+ TREE_TYPE (complex_integer_type_node) = integer_type_node;
+ layout_type (complex_integer_type_node);
+
+ complex_float_type_node = make_node (COMPLEX_TYPE);
+ TREE_TYPE (complex_float_type_node) = float_type_node;
+ layout_type (complex_float_type_node);
+
+ complex_double_type_node = make_node (COMPLEX_TYPE);
+ TREE_TYPE (complex_double_type_node) = double_type_node;
+ layout_type (complex_double_type_node);
+
+ complex_long_double_type_node = make_node (COMPLEX_TYPE);
+ TREE_TYPE (complex_long_double_type_node) = long_double_type_node;
+ layout_type (complex_long_double_type_node);
+
+#ifdef BUILD_VA_LIST_TYPE
+ BUILD_VA_LIST_TYPE(va_list_type_node);
+#else
+ va_list_type_node = ptr_type_node;
+#endif
+}