#include "timevar.h"
#include "except.h"
#include "debug.h"
+#include "intl.h"
/* Tree code classes. */
static GTY(()) int next_decl_uid;
/* Unique id for next type created. */
static GTY(()) int next_type_uid = 1;
+/* Unique id for next debug decl created. Use negative numbers,
+ to catch erroneous uses. */
+static GTY(()) int next_debug_decl_uid;
/* Since we cannot rehash a type after it is in the table, we have to
keep the hash code. */
return TS_LABEL_DECL;
case RESULT_DECL:
return TS_RESULT_DECL;
+ case DEBUG_EXPR_DECL:
+ return TS_DECL_WRTL;
case CONST_DECL:
return TS_CONST_DECL;
case TYPE_DECL:
return sizeof (struct tree_type_decl);
case FUNCTION_DECL:
return sizeof (struct tree_function_decl);
+ case DEBUG_EXPR_DECL:
+ return sizeof (struct tree_decl_with_rtl);
default:
return sizeof (struct tree_decl_non_common);
}
DECL_ALIGN (t) = 1;
}
DECL_SOURCE_LOCATION (t) = input_location;
- DECL_UID (t) = next_decl_uid++;
+ if (TREE_CODE (t) == DEBUG_EXPR_DECL)
+ DECL_UID (t) = --next_debug_decl_uid;
+ else
+ DECL_UID (t) = next_decl_uid++;
if (TREE_CODE (t) == LABEL_DECL)
LABEL_DECL_UID (t) = -1;
if (TREE_CODE_CLASS (code) == tcc_declaration)
{
- DECL_UID (t) = next_decl_uid++;
+ if (code == DEBUG_EXPR_DECL)
+ DECL_UID (t) = --next_debug_decl_uid;
+ else
+ DECL_UID (t) = next_decl_uid++;
if ((TREE_CODE (node) == PARM_DECL || TREE_CODE (node) == VAR_DECL)
&& DECL_HAS_VALUE_EXPR_P (node))
{
return NULL_TREE;
}
+/* Returns element number IDX (zero-origin) of chain CHAIN, or
+ NULL_TREE. */
+
+tree
+chain_index (int idx, tree chain)
+{
+ for (; chain && idx > 0; --idx)
+ chain = TREE_CHAIN (chain);
+ return chain;
+}
+
/* Return nonzero if ELEM is part of the chain CHAIN. */
int
return chain;
}
-/* Return the node in a chain of nodes whose value is x, NULL if not found. */
-
-tree
-tree_find_value (tree chain, tree x)
-{
- tree list;
- for (list = chain; list; list = TREE_CHAIN (list))
- if (TREE_VALUE (list) == x)
- return list;
- return NULL;
-}
-
/* Reverse the order of elements in the chain T,
and return the new head of the chain (old last element). */
expand_location (source_location loc)
{
expanded_location xloc;
- if (loc == 0)
+ if (loc <= BUILTINS_LOCATION)
{
- xloc.file = NULL;
+ xloc.file = loc == UNKNOWN_LOCATION ? NULL : _("<built-in>");
xloc.line = 0;
xloc.column = 0;
xloc.sysp = 0;
Record such modified types already made so we don't make duplicates. */
-static tree
+tree
build_type_attribute_qual_variant (tree ttype, tree attribute, int quals)
{
if (! attribute_list_equal (TYPE_ATTRIBUTES (ttype), attribute))
TYPE_QUALS (ttype));
}
+
+/* Reset all the fields in a binfo node BINFO. We only keep
+ BINFO_VIRTUALS, which is used by gimple_fold_obj_type_ref. */
+
+static void
+free_lang_data_in_binfo (tree binfo)
+{
+ unsigned i;
+ tree t;
+
+ gcc_assert (TREE_CODE (binfo) == TREE_BINFO);
+
+ BINFO_OFFSET (binfo) = NULL_TREE;
+ BINFO_VTABLE (binfo) = NULL_TREE;
+ BINFO_VPTR_FIELD (binfo) = NULL_TREE;
+ BINFO_BASE_ACCESSES (binfo) = NULL;
+ BINFO_INHERITANCE_CHAIN (binfo) = NULL_TREE;
+ BINFO_SUBVTT_INDEX (binfo) = NULL_TREE;
+ BINFO_VPTR_FIELD (binfo) = NULL_TREE;
+
+ for (i = 0; VEC_iterate (tree, BINFO_BASE_BINFOS (binfo), i, t); i++)
+ free_lang_data_in_binfo (t);
+}
+
+
/* Reset all language specific information still present in TYPE. */
static void
/* Remove members that are not actually FIELD_DECLs from the field
list of an aggregate. These occur in C++. */
- if (TREE_CODE (type) == RECORD_TYPE
- || TREE_CODE (type) == UNION_TYPE
- || TREE_CODE (type) == QUAL_UNION_TYPE)
+ if (RECORD_OR_UNION_TYPE_P (type))
{
tree prev, member;
TYPE_METHODS (type) = NULL_TREE;
if (TYPE_BINFO (type))
- {
- tree binfo = TYPE_BINFO (type);
-
- if (BINFO_VIRTUALS (binfo))
- {
- /* If the virtual function table for BINFO contains
- entries, these may be useful for folding OBJ_TYPE_REF
- expressions (see gimple_fold_obj_type_ref). In that
- case, we only clear the unused fields in the BINFO
- structure. */
- BINFO_OFFSET (binfo) = NULL_TREE;
- BINFO_VTABLE (binfo) = NULL_TREE;
- BINFO_VPTR_FIELD (binfo) = NULL_TREE;
- BINFO_BASE_ACCESSES (binfo) = NULL;
- BINFO_INHERITANCE_CHAIN (binfo) = NULL_TREE;
- BINFO_SUBVTT_INDEX (binfo) = NULL_TREE;
- BINFO_VPTR_FIELD (binfo) = NULL_TREE;
- }
- else
- {
- /* Otherwise, get rid of the whole binfo data. */
- TYPE_BINFO (type) = NULL_TREE;
- }
- }
+ free_lang_data_in_binfo (TYPE_BINFO (type));
}
else
{
TYPE_CONTEXT (type) = NULL_TREE;
TYPE_STUB_DECL (type) = NULL_TREE;
-
- /* Remove type variants other than the main variant. This is both
- wasteful and it may introduce infinite loops when the types are
- read from disk and merged (since the variant will be the same
- type as the main variant, traversing type variants will get into
- an infinite loop). */
- if (TYPE_MAIN_VARIANT (type))
- TYPE_NEXT_VARIANT (TYPE_MAIN_VARIANT (type)) = NULL_TREE;
-
- TYPE_NEXT_VARIANT (type) = NULL_TREE;
}
&& !DECL_EXTERNAL (decl))
return false;
- /* Do not set assembler name on builtins. Allow RTL expansion to
- decide whether to expand inline or via a regular call. */
- if (TREE_CODE (decl) == FUNCTION_DECL
- && DECL_BUILT_IN (decl)
- && DECL_BUILT_IN_CLASS (decl) != BUILT_IN_FRONTEND)
- return false;
+ if (TREE_CODE (decl) == FUNCTION_DECL)
+ {
+ /* Do not set assembler name on builtins. Allow RTL expansion to
+ decide whether to expand inline or via a regular call. */
+ if (DECL_BUILT_IN (decl)
+ && DECL_BUILT_IN_CLASS (decl) != BUILT_IN_FRONTEND)
+ return false;
- /* For FUNCTION_DECLs, only used functions and functions
- represented in the callgraph need an assembler name. */
- if (TREE_CODE (decl) == FUNCTION_DECL
- && cgraph_node_for_decl (decl) == NULL
- && !TREE_USED (decl))
- return false;
+ /* Functions represented in the callgraph need an assembler name. */
+ if (cgraph_node_for_decl (decl) != NULL)
+ return true;
+
+ /* Unused and not public functions don't need an assembler name. */
+ if (!TREE_USED (decl) && !TREE_PUBLIC (decl))
+ return false;
+ }
return true;
}
if (DECL_NAME (decl))
TREE_TYPE (DECL_NAME (decl)) = NULL_TREE;
- if (TREE_CODE (decl) == CONST_DECL)
- DECL_CONTEXT (decl) = NULL_TREE;
-
/* Ignore any intervening types, because we are going to clear their
TYPE_CONTEXT fields. */
if (TREE_CODE (decl) != FIELD_DECL)
&& DECL_FIELD_OFFSET (decl)
&& TREE_CODE (DECL_FIELD_OFFSET (decl)) != INTEGER_CST)
DECL_FIELD_OFFSET (decl) = NULL_TREE;
+
+ /* DECL_FCONTEXT is only used for debug info generation. */
+ if (TREE_CODE (decl) == FIELD_DECL)
+ DECL_FCONTEXT (decl) = NULL_TREE;
}
else if (TREE_CODE (decl) == FUNCTION_DECL)
{
&& !TREE_STATIC (expr) && !DECL_EXTERNAL (expr))
SET_DECL_DEBUG_EXPR (decl, NULL_TREE);
- if (DECL_EXTERNAL (decl))
+ if (DECL_EXTERNAL (decl)
+ && (!TREE_STATIC (decl) || !TREE_READONLY (decl)))
DECL_INITIAL (decl) = NULL_TREE;
}
else if (TREE_CODE (decl) == TYPE_DECL)
struct free_lang_data_d
{
+ /* Worklist to avoid excessive recursion. */
+ VEC(tree,heap) *worklist;
+
/* Set of traversed objects. Used to avoid duplicate visits. */
struct pointer_set_t *pset;
gcc_unreachable ();
}
+/* Push tree node T into FLD->WORKLIST. */
+
+static inline void
+fld_worklist_push (tree t, struct free_lang_data_d *fld)
+{
+ if (t && !is_lang_specific (t) && !pointer_set_contains (fld->pset, t))
+ VEC_safe_push (tree, heap, fld->worklist, (t));
+}
+
/* Operand callback helper for free_lang_data_in_node. *TP is the
subtree operand being considered. */
static tree
-find_decls_types_r (tree *tp, int *ws ATTRIBUTE_UNUSED, void *data)
+find_decls_types_r (tree *tp, int *ws, void *data)
{
tree t = *tp;
struct free_lang_data_d *fld = (struct free_lang_data_d *) data;
+ if (TREE_CODE (t) == TREE_LIST)
+ return NULL_TREE;
+
+ /* Language specific nodes will be removed, so there is no need
+ to gather anything under them. */
+ if (is_lang_specific (t))
+ {
+ *ws = 0;
+ return NULL_TREE;
+ }
+
if (DECL_P (t))
{
/* Note that walk_tree does not traverse every possible field in
decls, so we have to do our own traversals here. */
add_tree_to_fld_list (t, fld);
- walk_tree (&DECL_NAME (t), find_decls_types_r, fld, fld->pset);
- walk_tree (&DECL_CONTEXT (t), find_decls_types_r, fld, fld->pset);
- walk_tree (&DECL_SIZE (t), find_decls_types_r, fld, fld->pset);
- walk_tree (&DECL_SIZE_UNIT (t), find_decls_types_r, fld, fld->pset);
- walk_tree (&DECL_INITIAL (t), find_decls_types_r, fld, fld->pset);
- walk_tree (&DECL_ATTRIBUTES (t), find_decls_types_r, fld, fld->pset);
- walk_tree (&DECL_ABSTRACT_ORIGIN (t), find_decls_types_r, fld, fld->pset);
+ fld_worklist_push (DECL_NAME (t), fld);
+ fld_worklist_push (DECL_CONTEXT (t), fld);
+ fld_worklist_push (DECL_SIZE (t), fld);
+ fld_worklist_push (DECL_SIZE_UNIT (t), fld);
+
+ /* We are going to remove everything under DECL_INITIAL for
+ TYPE_DECLs. No point walking them. */
+ if (TREE_CODE (t) != TYPE_DECL)
+ fld_worklist_push (DECL_INITIAL (t), fld);
+
+ fld_worklist_push (DECL_ATTRIBUTES (t), fld);
+ fld_worklist_push (DECL_ABSTRACT_ORIGIN (t), fld);
if (TREE_CODE (t) == FUNCTION_DECL)
{
- walk_tree (&DECL_ARGUMENTS (t), find_decls_types_r, fld, fld->pset);
- walk_tree (&DECL_RESULT (t), find_decls_types_r, fld, fld->pset);
+ fld_worklist_push (DECL_ARGUMENTS (t), fld);
+ fld_worklist_push (DECL_RESULT (t), fld);
}
else if (TREE_CODE (t) == TYPE_DECL)
{
- walk_tree (&DECL_ARGUMENT_FLD (t), find_decls_types_r, fld,
- fld->pset);
- walk_tree (&DECL_VINDEX (t), find_decls_types_r, fld, fld->pset);
+ fld_worklist_push (DECL_ARGUMENT_FLD (t), fld);
+ fld_worklist_push (DECL_VINDEX (t), fld);
}
else if (TREE_CODE (t) == FIELD_DECL)
{
- walk_tree (&DECL_FIELD_OFFSET (t), find_decls_types_r, fld,
- fld->pset);
- walk_tree (&DECL_BIT_FIELD_TYPE (t), find_decls_types_r, fld,
- fld->pset);
- walk_tree (&DECL_QUALIFIER (t), find_decls_types_r, fld, fld->pset);
- walk_tree (&DECL_FIELD_BIT_OFFSET (t), find_decls_types_r, fld,
- fld->pset);
- walk_tree (&DECL_FCONTEXT (t), find_decls_types_r, fld, fld->pset);
+ fld_worklist_push (DECL_FIELD_OFFSET (t), fld);
+ fld_worklist_push (DECL_BIT_FIELD_TYPE (t), fld);
+ fld_worklist_push (DECL_QUALIFIER (t), fld);
+ fld_worklist_push (DECL_FIELD_BIT_OFFSET (t), fld);
+ fld_worklist_push (DECL_FCONTEXT (t), fld);
}
else if (TREE_CODE (t) == VAR_DECL)
{
- walk_tree (&DECL_SECTION_NAME (t), find_decls_types_r, fld,
- fld->pset);
- walk_tree (&DECL_COMDAT_GROUP (t), find_decls_types_r, fld,
- fld->pset);
+ fld_worklist_push (DECL_SECTION_NAME (t), fld);
+ fld_worklist_push (DECL_COMDAT_GROUP (t), fld);
}
+
+ if (TREE_CODE (t) != FIELD_DECL)
+ fld_worklist_push (TREE_CHAIN (t), fld);
+ *ws = 0;
}
else if (TYPE_P (t))
{
types, so we have to do our own traversals here. */
add_tree_to_fld_list (t, fld);
- walk_tree (&TYPE_CACHED_VALUES (t), find_decls_types_r, fld, fld->pset);
- walk_tree (&TYPE_SIZE (t), find_decls_types_r, fld, fld->pset);
- walk_tree (&TYPE_SIZE_UNIT (t), find_decls_types_r, fld, fld->pset);
- walk_tree (&TYPE_ATTRIBUTES (t), find_decls_types_r, fld, fld->pset);
- walk_tree (&TYPE_POINTER_TO (t), find_decls_types_r, fld, fld->pset);
- walk_tree (&TYPE_REFERENCE_TO (t), find_decls_types_r, fld, fld->pset);
- walk_tree (&TYPE_NAME (t), find_decls_types_r, fld, fld->pset);
- walk_tree (&TYPE_MINVAL (t), find_decls_types_r, fld, fld->pset);
- walk_tree (&TYPE_MAXVAL (t), find_decls_types_r, fld, fld->pset);
- walk_tree (&TYPE_NEXT_VARIANT (t), find_decls_types_r, fld, fld->pset);
- walk_tree (&TYPE_MAIN_VARIANT (t), find_decls_types_r, fld, fld->pset);
- walk_tree (&TYPE_CONTEXT (t), find_decls_types_r, fld, fld->pset);
- walk_tree (&TYPE_CANONICAL (t), find_decls_types_r, fld, fld->pset);
- }
-
- if (TREE_TYPE (t))
- walk_tree (&TREE_TYPE (t), find_decls_types_r, fld, fld->pset);
+ if (!RECORD_OR_UNION_TYPE_P (t))
+ fld_worklist_push (TYPE_CACHED_VALUES (t), fld);
+ fld_worklist_push (TYPE_SIZE (t), fld);
+ fld_worklist_push (TYPE_SIZE_UNIT (t), fld);
+ fld_worklist_push (TYPE_ATTRIBUTES (t), fld);
+ fld_worklist_push (TYPE_POINTER_TO (t), fld);
+ fld_worklist_push (TYPE_REFERENCE_TO (t), fld);
+ fld_worklist_push (TYPE_NAME (t), fld);
+ fld_worklist_push (TYPE_MINVAL (t), fld);
+ if (!RECORD_OR_UNION_TYPE_P (t))
+ fld_worklist_push (TYPE_MAXVAL (t), fld);
+ fld_worklist_push (TYPE_MAIN_VARIANT (t), fld);
+ fld_worklist_push (TYPE_NEXT_VARIANT (t), fld);
+ fld_worklist_push (TYPE_CONTEXT (t), fld);
+ fld_worklist_push (TYPE_CANONICAL (t), fld);
+
+ if (RECORD_OR_UNION_TYPE_P (t) && TYPE_BINFO (t))
+ {
+ unsigned i;
+ tree tem;
+ for (i = 0; VEC_iterate (tree, BINFO_BASE_BINFOS (TYPE_BINFO (t)),
+ i, tem); ++i)
+ fld_worklist_push (TREE_TYPE (tem), fld);
+ tem = BINFO_VIRTUALS (TYPE_BINFO (t));
+ while (tem)
+ {
+ fld_worklist_push (TREE_VALUE (tem), fld);
+ tem = TREE_CHAIN (tem);
+ }
+ }
+ if (RECORD_OR_UNION_TYPE_P (t))
+ {
+ tree tem;
+ /* Push all TYPE_FIELDS - there can be interleaving interesting
+ and non-interesting things. */
+ tem = TYPE_FIELDS (t);
+ while (tem)
+ {
+ if (TREE_CODE (tem) == FIELD_DECL)
+ fld_worklist_push (tem, fld);
+ tem = TREE_CHAIN (tem);
+ }
+ }
- /* Do not recurse into TREE_CHAIN to avoid blowing up the stack. */
- for (tp = &TREE_CHAIN (t); *tp; tp = &TREE_CHAIN (*tp))
- {
- tree saved_chain = TREE_CHAIN (*tp);
- TREE_CHAIN (*tp) = NULL_TREE;
- walk_tree (tp, find_decls_types_r, fld, fld->pset);
- TREE_CHAIN (*tp) = saved_chain;
+ fld_worklist_push (TREE_CHAIN (t), fld);
+ *ws = 0;
}
+ fld_worklist_push (TREE_TYPE (t), fld);
+
return NULL_TREE;
}
+/* Find decls and types in T. */
+
+static void
+find_decls_types (tree t, struct free_lang_data_d *fld)
+{
+ while (1)
+ {
+ if (!pointer_set_contains (fld->pset, t))
+ walk_tree (&t, find_decls_types_r, fld, fld->pset);
+ if (VEC_empty (tree, fld->worklist))
+ break;
+ t = VEC_pop (tree, fld->worklist);
+ }
+}
+
/* Translate all the types in LIST with the corresponding runtime
types. */
static void
find_decls_types_in_eh_region (eh_region r, struct free_lang_data_d *fld)
{
- if (r == NULL)
- return;
-
- /* The types referenced in R must first be changed to the EH types
- used at runtime. This removes references to FE types in the
- region. */
- if (r->type == ERT_CATCH)
+ switch (r->type)
{
- tree list = r->u.eh_catch.type_list;
- r->u.eh_catch.type_list = get_eh_types_for_runtime (list);
- walk_tree (&r->u.eh_catch.type_list, find_decls_types_r, fld, fld->pset);
- }
- else if (r->type == ERT_ALLOWED_EXCEPTIONS)
- {
- tree list = r->u.allowed.type_list;
- r->u.allowed.type_list = get_eh_types_for_runtime (list);
+ case ERT_CLEANUP:
+ break;
+
+ case ERT_TRY:
+ {
+ eh_catch c;
+
+ /* The types referenced in each catch must first be changed to the
+ EH types used at runtime. This removes references to FE types
+ in the region. */
+ for (c = r->u.eh_try.first_catch; c ; c = c->next_catch)
+ {
+ c->type_list = get_eh_types_for_runtime (c->type_list);
+ walk_tree (&c->type_list, find_decls_types_r, fld, fld->pset);
+ }
+ }
+ break;
+
+ case ERT_ALLOWED_EXCEPTIONS:
+ r->u.allowed.type_list
+ = get_eh_types_for_runtime (r->u.allowed.type_list);
walk_tree (&r->u.allowed.type_list, find_decls_types_r, fld, fld->pset);
+ break;
+
+ case ERT_MUST_NOT_THROW:
+ walk_tree (&r->u.must_not_throw.failure_decl,
+ find_decls_types_r, fld, fld->pset);
+ break;
}
}
struct function *fn;
tree t;
- walk_tree (&n->decl, find_decls_types_r, fld, fld->pset);
+ find_decls_types (n->decl, fld);
if (!gimple_has_body_p (n->decl))
return;
/* Traverse locals. */
for (t = fn->local_decls; t; t = TREE_CHAIN (t))
- {
- tree *tp = &TREE_VALUE (t);
- tree saved_chain = TREE_CHAIN (*tp);
- TREE_CHAIN (*tp) = NULL_TREE;
- walk_tree (tp, find_decls_types_r, fld, fld->pset);
- TREE_CHAIN (*tp) = saved_chain;
- }
+ find_decls_types (TREE_VALUE (t), fld);
/* Traverse EH regions in FN. */
- if (fn->eh->region_array)
- {
- unsigned i;
- eh_region r;
-
- for (i = 0; VEC_iterate (eh_region, fn->eh->region_array, i, r); i++)
- find_decls_types_in_eh_region (r, fld);
- }
+ {
+ eh_region r;
+ FOR_ALL_EH_REGION_FN (r, fn)
+ find_decls_types_in_eh_region (r, fld);
+ }
/* Traverse every statement in FN. */
FOR_EACH_BB_FN (bb, fn)
for (i = 0; i < gimple_phi_num_args (phi); i++)
{
tree *arg_p = gimple_phi_arg_def_ptr (phi, i);
- walk_tree (arg_p, find_decls_types_r, fld, fld->pset);
+ find_decls_types (*arg_p, fld);
}
}
for (i = 0; i < gimple_num_ops (stmt); i++)
{
- tree *arg_p = gimple_op_ptr (stmt, i);
- walk_tree (arg_p, find_decls_types_r, fld, fld->pset);
+ tree arg = gimple_op (stmt, i);
+ find_decls_types (arg, fld);
}
}
}
static void
find_decls_types_in_var (struct varpool_node *v, struct free_lang_data_d *fld)
{
- walk_tree (&v->decl, find_decls_types_r, fld, fld->pset);
+ find_decls_types (v->decl, fld);
}
/* Initialize sets and arrays to store referenced decls and types. */
fld.pset = pointer_set_create ();
+ fld.worklist = NULL;
fld.decls = VEC_alloc (tree, heap, 100);
fld.types = VEC_alloc (tree, heap, 100);
find_decls_types_in_node (n, &fld);
for (i = 0; VEC_iterate (alias_pair, alias_pairs, i, p); i++)
- walk_tree (&p->decl, find_decls_types_r, &fld, fld.pset);
+ find_decls_types (p->decl, &fld);
/* Find decls and types in every varpool symbol. */
for (v = varpool_nodes_queue; v; v = v->next_needed)
free_lang_data_in_type (t);
pointer_set_destroy (fld.pset);
+ VEC_free (tree, heap, fld.worklist);
VEC_free (tree, heap, fld.decls);
VEC_free (tree, heap, fld.types);
}
boolean_true_node = TYPE_MAX_VALUE (boolean_type_node);
}
+ /* Unify char_type_node with its properly signed variant. */
+ if (TYPE_UNSIGNED (char_type_node))
+ unsigned_char_type_node = char_type_node;
+ else
+ signed_char_type_node = char_type_node;
+
/* Reset some langhooks. */
lang_hooks.callgraph.analyze_expr = NULL;
lang_hooks.types_compatible_p = NULL;
diagnostic_finalizer (global_dc) = default_diagnostic_finalizer;
diagnostic_format_decoder (global_dc) = default_tree_printer;
+ /* FIXME. We remove sufficient language data that the debug
+ info writer gets completely confused. Disable debug information
+ for now. */
+ debug_info_level = DINFO_LEVEL_NONE;
+ write_symbols = NO_DEBUG;
+ debug_hooks = &do_nothing_debug_hooks;
+
return 0;
}
gate_free_lang_data (void)
{
/* FIXME. Remove after save_debug_info is working. */
- return !flag_gtoggle && debug_info_level <= DINFO_LEVEL_TERSE;
+ return (flag_generate_lto
+ || (!in_lto_p
+ && !flag_gtoggle && debug_info_level <= DINFO_LEVEL_TERSE));
}
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
- 0 /* todo_flags_finish */
+ TODO_ggc_collect /* todo_flags_finish */
}
};
t = make_node (ARRAY_TYPE);
TREE_TYPE (t) = elt_type;
TYPE_DOMAIN (t) = index_type;
-
- if (index_type == 0)
- {
- tree save = t;
- hashcode = iterative_hash_object (TYPE_HASH (elt_type), hashcode);
- t = type_hash_canon (hashcode, t);
- if (save == t)
- layout_type (t);
-
- if (TYPE_CANONICAL (t) == t)
- {
- if (TYPE_STRUCTURAL_EQUALITY_P (elt_type))
- SET_TYPE_STRUCTURAL_EQUALITY (t);
- else if (TYPE_CANONICAL (elt_type) != elt_type)
- TYPE_CANONICAL (t)
- = build_array_type (TYPE_CANONICAL (elt_type), index_type);
- }
+ layout_type (t);
- return t;
- }
+ /* If the element type is incomplete at this point we get marked for
+ structural equality. Do not record these types in the canonical
+ type hashtable. */
+ if (TYPE_STRUCTURAL_EQUALITY_P (t))
+ return t;
hashcode = iterative_hash_object (TYPE_HASH (elt_type), hashcode);
- hashcode = iterative_hash_object (TYPE_HASH (index_type), hashcode);
+ if (index_type)
+ hashcode = iterative_hash_object (TYPE_HASH (index_type), hashcode);
t = type_hash_canon (hashcode, t);
- if (!COMPLETE_TYPE_P (t))
- layout_type (t);
-
if (TYPE_CANONICAL (t) == t)
{
if (TYPE_STRUCTURAL_EQUALITY_P (elt_type)
- || TYPE_STRUCTURAL_EQUALITY_P (index_type))
+ || (index_type && TYPE_STRUCTURAL_EQUALITY_P (index_type)))
SET_TYPE_STRUCTURAL_EQUALITY (t);
else if (TYPE_CANONICAL (elt_type) != elt_type
- || TYPE_CANONICAL (index_type) != index_type)
+ || (index_type && TYPE_CANONICAL (index_type) != index_type))
TYPE_CANONICAL (t)
= build_array_type (TYPE_CANONICAL (elt_type),
- TYPE_CANONICAL (index_type));
+ index_type ? TYPE_CANONICAL (index_type) : NULL);
}
return t;
void
build_common_builtin_nodes (void)
{
- tree tmp, ftype;
+ tree tmp, tmp2, ftype;
if (built_in_decls[BUILT_IN_MEMCPY] == NULL
|| built_in_decls[BUILT_IN_MEMMOVE] == NULL)
local_define_builtin ("__builtin_profile_func_exit", ftype,
BUILT_IN_PROFILE_FUNC_EXIT, "profile_func_exit", 0);
+ /* If there's a possibility that we might use the ARM EABI, build the
+ alternate __cxa_end_cleanup node used to resume from C++ and Java. */
+ if (targetm.arm_eabi_unwinder)
+ {
+ ftype = build_function_type (void_type_node, void_list_node);
+ local_define_builtin ("__builtin_cxa_end_cleanup", ftype,
+ BUILT_IN_CXA_END_CLEANUP,
+ "__cxa_end_cleanup", ECF_NORETURN);
+ }
+
+ tmp = tree_cons (NULL_TREE, ptr_type_node, void_list_node);
+ ftype = build_function_type (void_type_node, tmp);
+ local_define_builtin ("__builtin_unwind_resume", ftype,
+ BUILT_IN_UNWIND_RESUME,
+ (USING_SJLJ_EXCEPTIONS
+ ? "_Unwind_SjLj_Resume" : "_Unwind_Resume"),
+ ECF_NORETURN);
+
+ /* The exception object and filter values from the runtime. The argument
+ must be zero before exception lowering, i.e. from the front end. After
+ exception lowering, it will be the region number for the exception
+ landing pad. These functions are PURE instead of CONST to prevent
+ them from being hoisted past the exception edge that will initialize
+ its value in the landing pad. */
+ tmp = tree_cons (NULL_TREE, integer_type_node, void_list_node);
+ ftype = build_function_type (ptr_type_node, tmp);
+ local_define_builtin ("__builtin_eh_pointer", ftype, BUILT_IN_EH_POINTER,
+ "__builtin_eh_pointer", ECF_PURE | ECF_NOTHROW);
+
+ tmp2 = lang_hooks.types.type_for_mode (targetm.eh_return_filter_mode (), 0);
+ ftype = build_function_type (tmp2, tmp);
+ local_define_builtin ("__builtin_eh_filter", ftype, BUILT_IN_EH_FILTER,
+ "__builtin_eh_filter", ECF_PURE | ECF_NOTHROW);
+
+ tmp = tree_cons (NULL_TREE, integer_type_node, void_list_node);
+ tmp = tree_cons (NULL_TREE, integer_type_node, tmp);
+ ftype = build_function_type (void_type_node, tmp);
+ local_define_builtin ("__builtin_eh_copy_values", ftype,
+ BUILT_IN_EH_COPY_VALUES,
+ "__builtin_eh_copy_values", ECF_NOTHROW);
+
/* Complex multiplication and division. These are handled as builtins
rather than optabs because emit_library_call_value doesn't support
complex. Further, we can do slightly better with folding these
}
-/* Build RESX_EXPR with given REGION_NUMBER. */
-tree
-build_resx (int region_number)
-{
- tree t;
- t = build1 (RESX_EXPR, void_type_node,
- build_int_cst (NULL_TREE, region_number));
- return t;
-}
-
/* Given an initializer INIT, return TRUE if INIT is zero or some
aggregate of zeros. Otherwise return FALSE. */
bool
return result;
/* If this is a record type, also walk the fields. */
- if (TREE_CODE (*type_p) == RECORD_TYPE
- || TREE_CODE (*type_p) == UNION_TYPE
- || TREE_CODE (*type_p) == QUAL_UNION_TYPE)
+ if (RECORD_OR_UNION_TYPE_P (*type_p))
{
tree field;
return exp;
}
+static GTY(()) tree gcc_eh_personality_decl;
+
+/* Return the GCC personality function decl. */
+
+tree
+lhd_gcc_personality (void)
+{
+ if (!gcc_eh_personality_decl)
+ gcc_eh_personality_decl
+ = build_personality_function (USING_SJLJ_EXCEPTIONS
+ ? "__gcc_personality_sj0"
+ : "__gcc_personality_v0");
+
+ return gcc_eh_personality_decl;
+}
#include "gt-tree.h"