aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlan Matsuoka <alanm@redhat.com>2001-10-02 21:57:06 +0000
committerAlan Matsuoka <alanm@redhat.com>2001-10-02 21:57:06 +0000
commita0695a8e1510398f13e2ad1074b432209faf1884 (patch)
treecfaf7fdc68c0f7654aebe79f6e2af41d65484d76
parent32cfe6314cf9f51b681a7edd0c2857b78072f823 (diff)
2001-09-02 Alan Matsuoka <alanm@redhat.com>pchmerge-branch
* Changes for RedHat Precompiled headers merge from the PCH project by Geoffrey Keating <geoffk@redhat.com>, Jason Merrill <jason@redhat.com>, Catherine Moore <clm@redhat.com> et. al. Note that this is a merge in progress and things may not work. This is a source dump that has debug code, warts and all. git-svn-id: https://gcc.gnu.org/svn/gcc/branches/pchmerge-branch@45976 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/Makefile.in22
-rw-r--r--gcc/alias.c43
-rw-r--r--gcc/attribs.c10
-rw-r--r--gcc/c-common.c484
-rw-r--r--gcc/c-common.h38
-rw-r--r--gcc/c-decl.c80
-rw-r--r--gcc/c-format.c450
-rw-r--r--gcc/c-lang.c105
-rw-r--r--gcc/c-lex.c62
-rw-r--r--gcc/c-parse.in35
-rw-r--r--gcc/c-pragma.c2
-rw-r--r--gcc/c-pragma.h2
-rw-r--r--gcc/c-typeck.c4
-rw-r--r--gcc/cp/Make-lang.in4
-rw-r--r--gcc/cp/call.c8
-rw-r--r--gcc/cp/class.c3
-rw-r--r--gcc/cp/cp-tree.h24
-rw-r--r--gcc/cp/decl.c156
-rw-r--r--gcc/cp/decl2.c50
-rw-r--r--gcc/cp/g++spec.c16
-rw-r--r--gcc/cp/init.c3
-rw-r--r--gcc/cp/lang-specs.h22
-rw-r--r--gcc/cp/lex.c225
-rw-r--r--gcc/cp/linkage.c341
-rw-r--r--gcc/cp/parse.y10
-rw-r--r--gcc/cp/pch.c56
-rw-r--r--gcc/cp/pt.c9
-rw-r--r--gcc/cp/repo.c6
-rw-r--r--gcc/cp/spew.c21
-rw-r--r--gcc/cp/tree.c2
-rw-r--r--gcc/cp/typeck.c4
-rw-r--r--gcc/cppfiles.c122
-rw-r--r--gcc/cpphash.h27
-rw-r--r--gcc/cppinit.c83
-rw-r--r--gcc/cpplib.h57
-rw-r--r--gcc/cppmacro.c186
-rw-r--r--gcc/cppmain.c6
-rw-r--r--gcc/cpppch.c598
-rw-r--r--gcc/cselib.c2
-rw-r--r--gcc/dbxout.c61
-rw-r--r--gcc/dwarf2out.c8
-rw-r--r--gcc/emit-rtl.c51
-rw-r--r--gcc/except.c6
-rw-r--r--gcc/expr.c158
-rw-r--r--gcc/expr.h10
-rw-r--r--gcc/f/com.c20
-rw-r--r--gcc/f/ste.c12
-rw-r--r--gcc/f/version.c2
-rw-r--r--gcc/f/where.c2
-rw-r--r--gcc/flags.h4
-rw-r--r--gcc/flow.c7
-rw-r--r--gcc/fold-const.c4
-rw-r--r--gcc/function.c111
-rw-r--r--gcc/function.h40
-rw-r--r--gcc/gcc.c20
-rw-r--r--gcc/gcse.c2
-rw-r--r--gcc/ggc-common.c189
-rw-r--r--gcc/ggc-page.c34
-rw-r--r--gcc/ggc-simple.c23
-rw-r--r--gcc/ggc.h34
-rw-r--r--gcc/gtype.c1922
-rw-r--r--gcc/gtype.h307
-rw-r--r--gcc/hash.h4
-rw-r--r--gcc/java/class.c4
-rw-r--r--gcc/java/constants.c2
-rw-r--r--gcc/java/decl.c8
-rw-r--r--gcc/java/expr.c12
-rw-r--r--gcc/java/jcf-parse.c4
-rw-r--r--gcc/java/jcf-write.c6
-rw-r--r--gcc/java/lang.c4
-rw-r--r--gcc/java/mangle.c6
-rw-r--r--gcc/java/parse.y52
-rw-r--r--gcc/lists.c2
-rw-r--r--gcc/mkdeps.c67
-rw-r--r--gcc/mkdeps.h28
-rw-r--r--gcc/objc/objc-act.c24
-rw-r--r--gcc/optabs.c16
-rw-r--r--gcc/profile.c2
-rw-r--r--gcc/regclass.c2
-rw-r--r--gcc/sched-deps.c7
-rw-r--r--gcc/stor-layout.c9
-rw-r--r--gcc/stringpool.c3
-rw-r--r--gcc/toplev.c35
-rw-r--r--gcc/toplev.h1
-rw-r--r--gcc/tradcpp.c2
-rw-r--r--gcc/tree.c22
-rw-r--r--gcc/tree.h13
-rw-r--r--gcc/unwind-sjlj.c6
-rw-r--r--gcc/varasm.c10
-rw-r--r--gcc/version.c2
90 files changed, 5834 insertions, 924 deletions
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index ff2c58fab3e..51147aad1b1 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -558,6 +558,7 @@ MACHMODE_H = machmode.h machmode.def
RTL_BASE_H = rtl.h rtl.def $(MACHMODE_H)
RTL_H = $(RTL_BASE_H) genrtl.h
PARAMS_H = params.h params.def
+GTYPE_H = gtype.h
TREE_H = tree.h real.h tree.def $(MACHMODE_H) tree-check.h version.h builtins.def
BASIC_BLOCK_H = basic-block.h bitmap.h sbitmap.h varray.h
DEMANGLE_H = $(srcdir)/../include/demangle.h
@@ -568,7 +569,7 @@ REGS_H = regs.h varray.h $(MACHMODE_H)
INTEGRATE_H = integrate.h varray.h
LOOP_H = loop.h varray.h bitmap.h
GCC_H = gcc.h version.h
-GGC_H = ggc.h varray.h
+GGC_H = ggc.h varray.h gtype.h
TIMEVAR_H = timevar.h timevar.def
INSN_ATTR_H = insn-attr.h $(srcdir)/insn-addr.h $(srcdir)/varray.h
C_COMMON_H = c-common.h $(SPLAY_TREE_H)
@@ -734,7 +735,7 @@ C_OBJS = c-parse.o c-lang.o $(C_AND_OBJC_OBJS)
OBJS = \
alias.o bb-reorder.o bitmap.o builtins.o caller-save.o calls.o \
- combine.o conflict.o convert.o cse.o cselib.o dbxout.o debug.o \
+ combine.o conflict.o convert.o cse.o cselib.o dbxout.o debug.o gtype.o \
dependence.o df.o diagnostic.o doloop.o dominance.o dwarf2asm.o \
dwarf2out.o dwarfout.o emit-rtl.o except.o explow.o expmed.o expr.o \
final.o flow.o fold-const.o function.o gcse.o genrtl.o ggc-common.o \
@@ -1183,6 +1184,8 @@ c-aux-info.o : c-aux-info.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) $(C_TREE_H) \
c-convert.o : c-convert.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) flags.h toplev.h
c-pragma.o: c-pragma.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(TREE_H) function.h \
c-pragma.h toplev.h output.h $(GGC_H) $(TM_P_H)
+c-pch.o : c-pch.c $(CONFIG_H) system.h intl.h $(TREE_H) $(RTL_H) flags.h \
+ function.h $(EXPR_H) $(C_TREE_H) toplev.h defaults.h $(GGC_H)
mbchar.o: mbchar.c $(CONFIG_H) $(SYSTEM_H) mbchar.h
graph.o: graph.c $(CONFIG_H) $(SYSTEM_H) toplev.h flags.h output.h $(RTL_H) \
function.h hard-reg-set.h $(BASIC_BLOCK_H) graph.h
@@ -1249,7 +1252,7 @@ s-under: $(GCC_PASSES)
c-common.o : c-common.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) $(OBSTACK_H) \
$(C_COMMON_H) flags.h toplev.h output.h c-pragma.h $(RTL_H) $(GGC_H) \
- $(EXPR_H) $(TM_P_H) builtin-types.def $(TARGET_H)
+ $(EXPR_H) $(TM_P_H) builtin-types.def builtin-attrs.def $(TARGET_H)
# A file used by all variants of C and some other languages.
@@ -1316,8 +1319,11 @@ dumpvers: dumpvers.c
version.o: version.c version.h
+gtype.o: gtype.c $(CONFIG_H) system.h intl.h $(TREE_H) $(RTL_H) \
+ function.h $(EXPR_H) toplev.h hash.h defaults.h $(GGC_H) $(HASHTAB_H) $(GTYPE_H)
+
ggc-common.o: ggc-common.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(TREE_H) \
- flags.h $(GGC_H) varray.h hash.h $(HASHTAB_H) $(TM_P_H)
+ flags.h $(GGC_H) hash.h varray.h $(HASHTAB_H) $(TM_P_H)
ggc-simple.o: ggc-simple.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(TREE_H) flags.h \
$(GGC_H) varray.h $(TIMEVAR_H) $(TM_P_H)
@@ -1389,7 +1395,7 @@ varasm.o : varasm.c $(CONFIG_H) $(SYSTEM_H) $(TREE_H) $(RTL_H) flags.h \
$(HASHTAB_H) $(TARGET_H)
function.o : function.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(TREE_H) flags.h \
function.h $(EXPR_H) libfuncs.h $(REGS_H) hard-reg-set.h \
- insn-config.h $(RECOG_H) output.h toplev.h except.h hash.h $(GGC_H) $(TM_P_H)
+ insn-config.h $(RECOG_H) output.h toplev.h except.h $(GGC_H) $(TM_P_H)
stmt.o : stmt.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(TREE_H) flags.h function.h \
insn-config.h hard-reg-set.h $(EXPR_H) libfuncs.h except.h \
$(LOOP_H) $(RECOG_H) toplev.h output.h varray.h $(GGC_H) $(TM_P_H)
@@ -1989,7 +1995,7 @@ PREPROCESSOR_DEFINES = \
-DTOOL_INCLUDE_DIR=\"$(gcc_tooldir)/include\"
LIBCPP_OBJS = cpplib.o cpplex.o cppmacro.o cppexp.o cppfiles.o \
- cpphash.o cpperror.o cppinit.o cppdefault.o \
+ cpphash.o cpperror.o cppinit.o cppdefault.o cpppch.o \
hashtable.o line-map.o mkdeps.o prefix.o version.o mbchar.o
LIBCPP_DEPS = $(CPPLIB_H) cpphash.h line-map.h hashtable.h intl.h \
@@ -2010,6 +2016,7 @@ cppmain.o: cppmain.c $(CONFIG_H) $(CPPLIB_H) intl.h $(SYSTEM_H)
cpperror.o: cpperror.c $(CONFIG_H) $(LIBCPP_DEPS)
cppexp.o: cppexp.c $(CONFIG_H) $(LIBCPP_DEPS)
+cpppch.o: cpppch.c $(CONFIG_H) $(LIBCPP_DEPS)
cpplex.o: cpplex.c $(CONFIG_H) $(LIBCPP_DEPS) mbchar.h
cppmacro.o: cppmacro.c $(CONFIG_H) $(LIBCPP_DEPS)
cpplib.o: cpplib.c $(CONFIG_H) $(LIBCPP_DEPS)
@@ -2168,7 +2175,7 @@ fixinc.sh: $(FIXINCSRCDIR)/mkfixinc.sh $(FIXINCSRCDIR)/fixincl.c \
$(FIXINCSRCDIR)/server.c $(FIXINCSRCDIR)/gnu-regex.h \
$(FIXINCSRCDIR)/server.h $(FIXINCSRCDIR)/inclhack.def specs.ready
(MAKE="$(MAKE)"; srcdir=`cd $(srcdir)/fixinc && pwd` ; \
- CC="$(CC)"; CFLAGS="$(CFLAGS)"; LDFLAGS="$(LDFLAGS)"; \
+ CC="$(HOST_CC)"; CFLAGS="$(HOST_CFLAGS)"; LDFLAGS="$(HOST_LDFLAGS)"; \
WARN_CFLAGS="$(WARN_CFLAGS)"; \
export MAKE srcdir CC CFLAGS LDFLAGS WARN_CFLAGS; cd ./fixinc && \
$(SHELL) $${srcdir}/mkfixinc.sh $(build_canonical) $(target))
@@ -2958,6 +2965,7 @@ VOL_FILES=`echo $(BACKEND) $(OBJS) $(C_OBJS) $(LIBCPP_OBJS) *.c *.h gen*`
# WARN_CFLAGS setting can't be to the expansion of GCC_WARN_CFLAGS in
# the context of the stage_x rule.
STAGE2_FLAGS_TO_PASS = \
+ HOST_CC="$(HOST_CC)" \
CFLAGS="$(BOOT_CFLAGS)" \
LDFLAGS="$(BOOT_LDFLAGS)" \
WARN_CFLAGS="\$$(GCC_WARN_CFLAGS)" \
diff --git a/gcc/alias.c b/gcc/alias.c
index bf7c5e33e4f..db103b25507 100644
--- a/gcc/alias.c
+++ b/gcc/alias.c
@@ -470,16 +470,32 @@ get_alias_set (t)
return 0;
/* We can be passed either an expression or a type. This and the
- language-specific routine may make mutually-recursive calls to
- each other to figure out what to do. At each juncture, we see if
- this is a tree that the language may need to handle specially.
- First handle things that aren't types and start by removing nops
- since we care only about the actual object. */
+ language-specific routine may make mutually-recursive calls to each other
+ to figure out what to do. At each juncture, we see if this is a tree
+ that the language may need to handle specially. First handle things that
+ aren't types and start by removing nops since we care only about the
+ actual object. Also replace PLACEHOLDER_EXPRs and pick up the outermost
+ object that we could have a pointer to. */
if (! TYPE_P (t))
{
- while (TREE_CODE (t) == NOP_EXPR || TREE_CODE (t) == CONVERT_EXPR
- || TREE_CODE (t) == NON_LVALUE_EXPR)
- t = TREE_OPERAND (t, 0);
+ /* Remove any NOPs and see what any PLACEHOLD_EXPRs will expand to. */
+ while (((TREE_CODE (t) == NOP_EXPR || TREE_CODE (t) == CONVERT_EXPR)
+ && (TYPE_MODE (TREE_TYPE (t))
+ == TYPE_MODE (TREE_TYPE (TREE_OPERAND (t, 0)))))
+ || TREE_CODE (t) == NON_LVALUE_EXPR
+ || TREE_CODE (t) == PLACEHOLDER_EXPR
+ || (handled_component_p (t) && ! can_address_p (t)))
+ {
+ /* Give the language a chance to do something with this tree
+ before we go inside it. */
+ if ((set = lang_get_alias_set (t)) != -1)
+ return set;
+
+ if (TREE_CODE (t) == PLACEHOLDER_EXPR)
+ t = find_placeholder (t, 0);
+ else
+ t = TREE_OPERAND (t, 0);
+ }
/* Now give the language a chance to do something but record what we
gave it this time. */
@@ -493,9 +509,9 @@ get_alias_set (t)
while (handled_component_p (t) && ! can_address_p (t))
t = TREE_OPERAND (t, 0);
+ /* Check for accesses through restrict-qualified pointers. */
if (TREE_CODE (t) == INDIRECT_REF)
{
- /* Check for accesses through restrict-qualified pointers. */
tree decl = find_base_decl (TREE_OPERAND (t, 0));
if (decl && DECL_POINTER_ALIAS_SET_KNOWN_P (decl))
@@ -587,6 +603,11 @@ record_alias_subset (superset, subset)
alias_set_entry superset_entry;
alias_set_entry subset_entry;
+ /* It is possible in complex type situations for both sets to be the same,
+ in which case we can ignore this operation. */
+ if (superset == subset)
+ return;
+
if (superset == 0)
abort ();
@@ -2143,7 +2164,9 @@ init_alias_analysis ()
registers. */
reg_base_value_size = maxreg * 2;
reg_base_value = (rtx *) xcalloc (reg_base_value_size, sizeof (rtx));
- ggc_add_rtx_root (reg_base_value, reg_base_value_size);
+ ggc_add_rtx_root (reg_base_value, reg_base_value_size, "reg_base_value");
+
+
new_reg_base_value = (rtx *) xmalloc (reg_base_value_size * sizeof (rtx));
reg_seen = (char *) xmalloc (reg_base_value_size);
diff --git a/gcc/attribs.c b/gcc/attribs.c
index 1413dc267f9..29982dec529 100644
--- a/gcc/attribs.c
+++ b/gcc/attribs.c
@@ -241,7 +241,11 @@ init_attributes ()
information, in the form of a bitwise OR of flags in enum attribute_flags
from tree.h. Depending on these flags, some attributes may be
returned to be applied at a later stage (for example, to apply
- a decl attribute to the declaration rather than to its type). */
+ a decl attribute to the declaration rather than to its type). If
+ ATTR_FLAG_BUILT_IN is not set and *NODE is a DECL, then also consider
+ whether there might be some default attributes to apply to this DECL;
+ if so, decl_attributes will be called recusrively with those attributes
+ and ATTR_FLAG_BUILT_IN set. */
tree
decl_attributes (node, attributes, flags)
@@ -256,6 +260,10 @@ decl_attributes (node, attributes, flags)
(*targetm.insert_attributes) (*node, &attributes);
+ if (DECL_P (*node) && TREE_CODE (*node) == FUNCTION_DECL
+ && !(flags & (int) ATTR_FLAG_BUILT_IN))
+ insert_default_attributes (*node);
+
for (a = attributes; a; a = TREE_CHAIN (a))
{
tree name = TREE_PURPOSE (a);
diff --git a/gcc/c-common.c b/gcc/c-common.c
index 190c338d5f9..a3038e080d6 100644
--- a/gcc/c-common.c
+++ b/gcc/c-common.c
@@ -2074,6 +2074,89 @@ truthvalue_conversion (expr)
return build_binary_op (NE_EXPR, expr, integer_zero_node, 1);
}
+/* Read the rest of a #-directive from input stream FINPUT.
+ In normal use, the directive name and the white space after it
+ have already been read, so they won't be included in the result.
+ We allow for the fact that the directive line may contain
+ a newline embedded within a character or string literal which forms
+ a part of the directive.
+
+ The value is a string in a reusable buffer. It remains valid
+ only until the next time this function is called.
+
+ The terminating character ('\n' or EOF) is left in FINPUT for the
+ caller to re-read. */
+
+char *
+get_directive_line (finput)
+ register FILE *finput;
+{
+ static char *directive_buffer = NULL;
+ static unsigned buffer_length = 0;
+ register char *p;
+ register char *buffer_limit;
+ register int looking_for = 0;
+ register int char_escaped = 0;
+
+ if (buffer_length == 0)
+ {
+ directive_buffer = (char *)xmalloc (128);
+ buffer_length = 128;
+ }
+
+ buffer_limit = &directive_buffer[buffer_length];
+
+ for (p = directive_buffer; ; )
+ {
+ int c;
+
+ /* Make buffer bigger if it is full. */
+ if (p >= buffer_limit)
+ {
+ register unsigned bytes_used = (p - directive_buffer);
+
+ buffer_length *= 2;
+ directive_buffer
+ = (char *)xrealloc (directive_buffer, buffer_length);
+ p = &directive_buffer[bytes_used];
+ buffer_limit = &directive_buffer[buffer_length];
+ }
+
+ c = getc (finput);
+
+ /* Discard initial whitespace. */
+ if ((c == ' ' || c == '\t') && p == directive_buffer)
+ continue;
+
+ /* Detect the end of the directive. */
+ if (looking_for == 0
+ && (c == '\n' || c == EOF))
+ {
+ ungetc (c, finput);
+ c = '\0';
+ }
+
+ *p++ = c;
+
+ if (c == 0)
+ return directive_buffer;
+
+ /* Handle string and character constant syntax. */
+ if (looking_for)
+ {
+ if (looking_for == c && !char_escaped)
+ looking_for = 0; /* Found terminator... stop looking. */
+ }
+ else
+ if (c == '\'' || c == '"')
+ looking_for = c; /* Don't stop buffering until we see another
+ one of these (or an EOF). */
+
+ /* Handle backslash. */
+ char_escaped = (c == '\\' && ! char_escaped);
+ }
+}
+
static tree builtin_function_2 PARAMS ((const char *, const char *, tree, tree,
int, enum built_in_class, int, int,
int));
@@ -2324,6 +2407,19 @@ c_alignof_expr (expr)
return fold (build1 (NOP_EXPR, c_size_type_node, t));
}
+/* Give the specifications for the format attributes, used by C and all
+ descendents. */
+
+static const struct attribute_spec c_format_attribute_table[] =
+{
+ /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
+ { "format", 3, 3, false, true, true,
+ handle_format_attribute },
+ { "format_arg", 1, 1, false, true, true,
+ handle_format_arg_attribute },
+ { NULL, 0, 0, false, false, false, NULL }
+};
+
/* Build tree nodes and builtin functions common to both C and C++ language
frontends. */
@@ -2369,6 +2465,10 @@ c_common_nodes_and_builtins ()
tree va_list_ref_type_node;
tree va_list_arg_type_node;
+ /* We must initialize this before any builtin functions (which might have
+ attributes) are declared. (c_common_lang_init is too late.) */
+ format_attribute_table = c_format_attribute_table;
+
/* Define `int' and `char' first so that dbx will output them first. */
record_builtin_type (RID_INT, NULL, integer_type_node);
record_builtin_type (RID_CHAR, "char", char_type_node);
@@ -3535,14 +3635,22 @@ is_valid_printf_arglist (arglist)
/* Save this value so we can restore it later. */
const int SAVE_pedantic = pedantic;
int diagnostic_occurred = 0;
+ tree attrs;
/* Set this to a known value so the user setting won't affect code
generation. */
pedantic = 1;
/* Check to make sure there are no format specifier errors. */
- check_function_format (&diagnostic_occurred,
- maybe_get_identifier("printf"),
- NULL_TREE, arglist);
+ attrs = tree_cons (get_identifier ("format"),
+ tree_cons (NULL_TREE,
+ get_identifier ("printf"),
+ tree_cons (NULL_TREE,
+ integer_one_node,
+ tree_cons (NULL_TREE,
+ build_int_2 (2, 0),
+ NULL_TREE))),
+ NULL_TREE);
+ check_function_format (&diagnostic_occurred, attrs, arglist);
/* Restore the value of `pedantic'. */
pedantic = SAVE_pedantic;
@@ -3774,24 +3882,34 @@ boolean_increment (code, arg)
return val;
}
-/* Give the specifications for the format attributes, used by C and all
- descendents. */
+/* Handle C and C++ default attributes. */
-static const struct attribute_spec c_format_attribute_table[] =
+enum built_in_attribute
{
- { "format", 3, 3, true, false, false,
- handle_format_attribute },
- { "format_arg", 1, 1, true, false, false,
- handle_format_arg_attribute },
- { NULL, 0, 0, false, false, false, NULL }
+#define DEF_ATTR_NULL_TREE(ENUM) ENUM,
+#define DEF_ATTR_INT(ENUM, VALUE) ENUM,
+#define DEF_ATTR_IDENT(ENUM, STRING) ENUM,
+#define DEF_ATTR_TREE_LIST(ENUM, PURPOSE, VALUE, CHAIN) ENUM,
+#define DEF_FN_ATTR(NAME, ATTRS, PREDICATE) /* No entry needed in enum. */
+#include "builtin-attrs.def"
+#undef DEF_ATTR_NULL_TREE
+#undef DEF_ATTR_INT
+#undef DEF_ATTR_IDENT
+#undef DEF_ATTR_TREE_LIST
+#undef DEF_FN_ATTR
+ ATTR_LAST
};
+static tree built_in_attributes[(int) ATTR_LAST];
+
+static bool c_attrs_initialized = false;
+
+static void c_init_attributes PARAMS ((void));
+
/* Do the parts of lang_init common to C and C++. */
void
c_common_lang_init ()
{
- format_attribute_table = c_format_attribute_table;
-
/* If still "unspecified", make it match -fbounded-pointers. */
if (flag_bounds_check < 0)
flag_bounds_check = flag_bounded_pointers;
@@ -3809,3 +3927,343 @@ c_common_lang_init ()
if (warn_missing_format_attribute && !warn_format)
warning ("-Wmissing-format-attribute ignored without -Wformat");
}
+
+/* Whether we've hit a definition that prevents us from including
+ a precompiled header. */
+int allow_pch;
+
+/* Nonzero means automatically generate a precompiled header for the first
+ header file encountered. */
+int flag_auto_pch;
+
+static const unsigned char pch_ident[4] = "gpch";
+static unsigned char pch_stamp[CHECKSUM_SIZE];
+static unsigned long asm_size;
+
+/* The filename to which we should write a precompiled header, or
+ NULL if no header will be written in this compile. */
+const char *pch_file;
+
+static FILE *pch_outfile;
+
+extern char *asm_file_name;
+static off_t asm_file_startpos;
+static void (*old_late_init_hook) PARAMS((void));
+static void save_asm_offset PARAMS((void));
+static void print_checksum PARAMS ((const unsigned char *, const char *));
+
+static void
+save_asm_offset ()
+{
+ memset (pch_stamp, 0, CHECKSUM_SIZE);
+ sum_type_addresses_list (pch_stamp, &known_pointers);
+ sum_type_addresses_list (pch_stamp, &data_to_save);
+ if (version_flag)
+ print_checksum (pch_stamp, "PCH file");
+
+ pch_outfile = fopen (pch_file, "wb");
+ if (pch_outfile == NULL)
+ {
+ if (flag_auto_pch)
+ {
+ /* We probably got something in /usr/include; fail silently. */
+ if (0)
+ warning ("can't precompile %s", pch_file);
+ exit (0);
+ }
+ fatal_error (pch_file);
+ }
+
+ /* We need to be able to re-read the output. */
+ /* The driver always provides a valid -o option. */
+ if (asm_file_name == NULL
+ || strcmp (asm_file_name, "-") == 0)
+ fatal_error ("`%s' is not a valid output file", asm_file_name);
+
+ if (freopen (asm_file_name, "a+", asm_out_file) != asm_out_file)
+ fatal_error (asm_file_name);
+
+ asm_file_startpos = ftello (asm_out_file);
+
+ if (fwrite (pch_ident, sizeof (pch_ident), 1, pch_outfile) != 1
+ || fwrite (pch_stamp, CHECKSUM_SIZE, 1, pch_outfile) != 1)
+ fatal_io_error ("writing precompiled header");
+ cpp_save_state (parse_in, pch_outfile);
+}
+
+/* We're in -fauto-pch mode, and we've seen an #include for a header with
+ filename HEADER_NAME. Start generating a PCH for it if possible. */
+
+void
+pch_begin_header (header_name)
+ char *header_name;
+{
+ char *name;
+
+ if (! lang_toplevel_p ())
+ exit (0);
+ if (first_global_object_name)
+ exit (0);
+
+ name = xmalloc (strlen (header_name) + 5);
+ sprintf (name, "%s.pch", header_name);
+
+ pch_file = name;
+
+ save_asm_offset ();
+}
+
+static void
+pch_init_hook ()
+{
+ if (old_late_init_hook)
+ old_late_init_hook ();
+
+ if (pch_file)
+ save_asm_offset ();
+ else
+ allow_pch = 1;
+}
+
+static void
+print_checksum (c, s)
+ const unsigned char *c;
+ const char *s;
+{
+ int i;
+ fprintf (stderr, "%s checksum: ", s);
+ for (i = 0; i < CHECKSUM_SIZE; i++)
+ fprintf (stderr, "%02x", c[i]);
+ fputc ('\n', stderr);
+}
+
+void
+pch_init ()
+{
+ add_untyped_address (&data_to_save, &asm_size, sizeof (asm_size), "asm_size");
+
+ old_late_init_hook = late_init_hook;
+ late_init_hook = pch_init_hook;
+}
+
+void
+c_write_pch ()
+{
+ off_t asm_file_end;
+ char *buf;
+ off_t written;
+
+ if (! global_bindings_p ())
+ abort ();
+
+ /* FIXME: there are a whole bunch of error conditions
+ that should be checked, like making actual definitions
+ of functions and whatnot. */
+ if (first_global_object_name)
+ fatal_error ("can't precompile a header with global definitions");
+
+ fflush (asm_out_file);
+ asm_file_end = ftello (asm_out_file);
+ asm_size = asm_file_end - asm_file_startpos;
+
+ if (cpp_write_pch (parse_in, pch_outfile) != 0)
+ return;
+
+ write_makedeps (parse_in, pch_outfile);
+
+ if (write_type_addresses_list (pch_outfile, &known_pointers, &data_to_save)
+ != 0)
+ fatal_error (pch_file);
+
+ buf = xmalloc (16384);
+
+ if (fseeko (asm_out_file, asm_file_startpos, SEEK_SET) != 0)
+ fatal_error (pch_file);
+
+ for (written = asm_file_startpos; written < asm_file_end; )
+ {
+ off_t size = asm_file_end - written;
+ if (size > 16384)
+ size = 16384;
+ if (fread (buf, size, 1, asm_out_file) != 1
+ || fwrite (buf, size, 1, pch_outfile) != 1)
+ fatal_error (pch_file);
+ written += size;
+ }
+ free (buf);
+
+ fclose (pch_outfile);
+
+ /* We've done what we came for; don't bother finishing the assembly
+ output. */
+ exit (0);
+}
+
+int
+lang_valid_pch (pfile, name, fd)
+ cpp_reader *pfile;
+ const char *name;
+ int fd;
+{
+ int sizeread;
+ int result;
+ unsigned char ident[sizeof (pch_ident) + CHECKSUM_SIZE];
+
+ if (! allow_pch)
+ return 2;
+
+ if (! global_bindings_p ())
+ return 2;
+
+ /* FIXME: Should check here that the user hasn't
+ defined anything that would make a PCH not work. */
+
+ /* Perform a quick test of whether this is a valid
+ precompiled header for C. */
+
+ sizeread = read (fd, ident, sizeof (ident));
+ if (sizeread == -1)
+ {
+ fatal_error (name);
+ return 2;
+ }
+ else if (sizeread != sizeof (ident))
+ return 2;
+
+ if (memcmp (ident, pch_ident, sizeof (pch_ident)) != 0)
+ return 2;
+
+ memset (pch_stamp, 0, CHECKSUM_SIZE);
+ sum_type_addresses_list (pch_stamp, &known_pointers);
+ sum_type_addresses_list (pch_stamp, &data_to_save);
+ if (version_flag)
+ print_checksum (pch_stamp, "PCH file");
+
+ if (memcmp (ident + sizeof (pch_ident), pch_stamp, CHECKSUM_SIZE) != 0)
+ {
+ if (0)
+ {
+ if (flag_auto_pch)
+ cpp_warning (pfile, "regenerating PCH %s", name);
+ else
+ cpp_warning (pfile,
+ "PCH %s not for this compiler with these flags",
+ name);
+ }
+ return 2;
+ }
+
+ /* Check the preprocessor macros are the same as when the PCH was
+ generated. */
+
+ result = cpp_valid_state (pfile, fd);
+ if (result == -1)
+ return 2;
+ else
+ return result == 0;
+
+ if (!c_attrs_initialized)
+ c_init_attributes ();
+}
+
+static void
+c_init_attributes ()
+{
+ /* Fill in the built_in_attributes array. */
+#define DEF_ATTR_NULL_TREE(ENUM) \
+ built_in_attributes[(int) ENUM] = NULL_TREE;
+#define DEF_ATTR_INT(ENUM, VALUE) \
+ built_in_attributes[(int) ENUM] = build_int_2 (VALUE, VALUE < 0 ? -1 : 0);
+#define DEF_ATTR_IDENT(ENUM, STRING) \
+ built_in_attributes[(int) ENUM] = get_identifier (STRING);
+#define DEF_ATTR_TREE_LIST(ENUM, PURPOSE, VALUE, CHAIN) \
+ built_in_attributes[(int) ENUM] \
+ = tree_cons (built_in_attributes[(int) PURPOSE], \
+ built_in_attributes[(int) VALUE], \
+ built_in_attributes[(int) CHAIN]);
+#define DEF_FN_ATTR(NAME, ATTRS, PREDICATE) /* No initialization needed. */
+#include "builtin-attrs.def"
+#undef DEF_ATTR_NULL_TREE
+#undef DEF_ATTR_INT
+#undef DEF_ATTR_IDENT
+#undef DEF_ATTR_TREE_LIST
+#undef DEF_FN_ATTR
+ ggc_add_tree_root (built_in_attributes, (int) ATTR_LAST, "built_in_attributes");
+ c_attrs_initialized = true;
+}
+
+/* Depending on the name of DECL, apply default attributes to it. */
+
+void
+c_common_insert_default_attributes (decl)
+ tree decl;
+{
+ tree name = DECL_NAME (decl);
+
+ if (!c_attrs_initialized)
+ c_init_attributes ();
+
+#define DEF_ATTR_NULL_TREE(ENUM) /* Nothing needed after initialization. */
+#define DEF_ATTR_INT(ENUM, VALUE)
+#define DEF_ATTR_IDENT(ENUM, STRING)
+#define DEF_ATTR_TREE_LIST(ENUM, PURPOSE, VALUE, CHAIN)
+#define DEF_FN_ATTR(NAME, ATTRS, PREDICATE) \
+ if ((PREDICATE) && name == built_in_attributes[(int) NAME]) \
+ decl_attributes (&decl, built_in_attributes[(int) ATTRS], \
+ ATTR_FLAG_BUILT_IN);
+#include "builtin-attrs.def"
+#undef DEF_ATTR_NULL_TREE
+#undef DEF_ATTR_INT
+#undef DEF_ATTR_IDENT
+#undef DEF_ATTR_TREE_LIST
+#undef DEF_FN_ATTR
+}
+
+void
+lang_read_pch (pfile, fd, self)
+ cpp_reader *pfile;
+ int fd;
+ const char *self;
+{
+ FILE *f;
+ char *buf;
+ unsigned long written;
+
+ if (flag_auto_pch)
+ exit (0);
+
+ f = fdopen (fd, "rb");
+ if (f == NULL)
+ cpp_error_from_errno (pfile, "calling fdopen");
+
+ allow_pch = 0;
+
+ if (cpp_read_state (pfile, f) != 0)
+ return;
+
+ read_makedeps (pfile, f, self);
+
+ if (read_type_addresses_list (f, &known_pointers, &data_to_save)
+ != 0)
+ {
+ cpp_error_from_errno (pfile, "reading precompiled header");
+ /* At this point, there's really very little more the compiler can do. */
+ fatal_error ("can't continue");
+ }
+
+ buf = xmalloc (16384);
+ for (written = 0; written < asm_size; )
+ {
+ off_t size = asm_size - written;
+ if (size > 16384)
+ size = 16384;
+ if (fread (buf, size, 1, f) != 1
+ || fwrite (buf, size, 1, asm_out_file) != 1)
+ cpp_error_from_errno (pfile, "reading");
+ written += size;
+ }
+ free (buf);
+
+ fclose (f);
+}
+
diff --git a/gcc/c-common.h b/gcc/c-common.h
index 3681ed222f0..88be8fa85e2 100644
--- a/gcc/c-common.h
+++ b/gcc/c-common.h
@@ -321,6 +321,12 @@ extern int (*lang_missing_noreturn_ok_p) PARAMS ((tree));
typedef tree (*walk_tree_fn) PARAMS ((tree *,
int *,
void *));
+/* Functions for precompiled headers. */
+extern void pch_init PARAMS (( void));
+extern void lang_write_pch PARAMS ((void));
+extern int lang_valid_pch PARAMS ((cpp_reader *, const char *, int));
+extern void lang_read_pch PARAMS ((cpp_reader *, int, const char *));
+
extern stmt_tree current_stmt_tree PARAMS ((void));
extern tree *current_scope_stmt_stack PARAMS ((void));
@@ -458,6 +464,25 @@ extern int warn_conversion;
extern int warn_long_long;
+
+/* The filename to which we should write a precompiled header, or
+ NULL if no header will be written in this compile. */
+
+extern const char *pch_file;
+
+/* Whether we've hit a definition that prevents us from including
+ a precompiled header. */
+
+extern int allow_pch;
+
+/* Nonzero means automatically generate a precompiled header for the first
+ header file encountered. */
+
+extern int flag_auto_pch;
+
+
+
+
/* C types are partitioned into three subsets: object, function, and
incomplete types. */
#define C_TYPE_OBJECT_P(type) \
@@ -503,13 +528,13 @@ extern const char *fname_as_string PARAMS ((int));
extern tree fname_decl PARAMS ((unsigned, tree));
extern const char *fname_string PARAMS ((unsigned));
-extern void init_function_format_info PARAMS ((void));
-extern void check_function_format PARAMS ((int *, tree, tree, tree));
+extern void check_function_format PARAMS ((int *, tree, tree));
extern void set_Wformat PARAMS ((int));
extern tree handle_format_attribute PARAMS ((tree *, tree, tree,
int, bool *));
extern tree handle_format_arg_attribute PARAMS ((tree *, tree, tree,
int, bool *));
+extern void c_common_insert_default_attributes PARAMS ((tree));
extern void c_apply_type_quals_to_decl PARAMS ((int, tree));
extern tree c_sizeof PARAMS ((tree));
extern tree c_alignof PARAMS ((tree));
@@ -532,9 +557,10 @@ extern tree convert_and_check PARAMS ((tree, tree));
extern void overflow_warning PARAMS ((tree));
extern void unsigned_conversion_warning PARAMS ((tree, tree));
+
/* Read the rest of the current #-directive line. */
-extern char *get_directive_line PARAMS ((void));
-#define GET_DIRECTIVE_LINE() get_directive_line ()
+extern char *get_directive_line PARAMS ((FILE *));
+#define GET_DIRECTIVE_LINE() get_directive_line (finput)
/* Subroutine of build_binary_op, used for comparison operations.
See if the operands have both been converted from subword integer types
@@ -874,9 +900,13 @@ struct c_fileinfo
int time; /* Time spent in the file. */
short interface_only; /* Flags - used only by C++ */
short interface_unknown;
+ void *lang_data;
};
struct c_fileinfo *get_fileinfo PARAMS ((const char *));
extern void dump_time_statistics PARAMS ((void));
+extern void c_write_pch PARAMS ((void));
+extern int lang_toplevel_p PARAMS ((void));
+extern void pch_begin_header PARAMS ((char *));
#endif /* ! GCC_C_COMMON_H */
diff --git a/gcc/c-decl.c b/gcc/c-decl.c
index 4652267c667..ed44486223a 100644
--- a/gcc/c-decl.c
+++ b/gcc/c-decl.c
@@ -40,6 +40,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
#include "toplev.h"
#include "ggc.h"
#include "tm_p.h"
+#include "cpphash.h"
#include "cpplib.h"
#include "target.h"
#include "debug.h"
@@ -54,6 +55,8 @@ enum decl_context
TYPENAME}; /* Typename (inside cast or sizeof) */
+/* Do GC. */
+
/* Nonzero if we have seen an invalid cross reference
to a struct, union, or enum, but not yet printed the message. */
@@ -428,6 +431,16 @@ int warn_float_equal = 0;
int warn_multichar = 1;
+/* The filename to which we should write a precompiled header, or
+ NULL if no header will be written in this compile. */
+
+const char *pch_file;
+
+/* Whether we've hit a definition that prevents us from including
+ a precompiled header. */
+
+extern int allow_pch;
+
/* The variant of the C language being processed. */
c_language_kind c_language = clk_c;
@@ -546,6 +559,16 @@ c_decode_option (argc, argv)
else
error ("unknown C standard `%s'", argstart);
}
+ else if (!strncmp (p, "--output-pch=", 13))
+ {
+ pch_file = xstrdup (p + 13);
+ CPP_OPTION (parse_in, gen_deps) = 1;
+ }
+ else if (!strncmp (p, "-fauto-pch", 13))
+ {
+ flag_auto_pch = 1;
+ CPP_OPTION (parse_in, gen_deps) = 1;
+ }
else if (!strcmp (p, "-fdollars-in-identifiers"))
dollars_in_ident = 1;
else if (!strcmp (p, "-fno-dollars-in-identifiers"))
@@ -1498,6 +1521,8 @@ duplicate_decls (newdecl, olddecl, different_binding_level)
tree trytype
= build_function_type (newreturntype,
TYPE_ARG_TYPES (oldtype));
+ trytype = build_type_attribute_variant (trytype,
+ TYPE_ATTRIBUTES (oldtype));
types_match = comptypes (newtype, trytype);
if (types_match)
@@ -1519,6 +1544,8 @@ duplicate_decls (newdecl, olddecl, different_binding_level)
tree_cons (NULL_TREE,
TREE_VALUE (TYPE_ARG_TYPES (newtype)),
TREE_CHAIN (TYPE_ARG_TYPES (oldtype))));
+ trytype = build_type_attribute_variant (trytype,
+ TYPE_ATTRIBUTES (oldtype));
types_match = comptypes (newtype, trytype);
if (types_match)
@@ -2505,7 +2532,7 @@ tree
implicitly_declare (functionid)
tree functionid;
{
- register tree decl;
+ tree decl;
int traditional_warning = 0;
/* Only one "implicit declaration" warning per identifier. */
int implicit_warning;
@@ -2555,6 +2582,9 @@ implicitly_declare (functionid)
gen_aux_info_record (decl, 0, 1, 0);
+ /* Possibly apply some default attributes to this implicit declaration. */
+ decl_attributes (&decl, NULL_TREE, 0);
+
return decl;
}
@@ -2955,6 +2985,13 @@ mark_binding_level (arg)
}
}
+static const struct field_definition_s c_lang_function_field_defs[] = {
+ /* No interesting pointers. */
+ NO_MORE_FIELDS
+};
+
+
+
/* Create the predefined scalar types of C,
and some nodes representing standard constants (0, 1, (void *) 0).
Initialize the global binding level.
@@ -3056,24 +3093,26 @@ init_decl_processing ()
make_fname_decl = c_make_fname_decl;
start_fname_decls ();
- /* Prepare to check format strings against argument lists. */
- init_function_format_info ();
-
incomplete_decl_finalize_hook = finish_incomplete_decl;
/* Record our roots. */
- ggc_add_tree_root (c_global_trees, CTI_MAX);
- ggc_add_root (&c_stmt_tree, 1, sizeof c_stmt_tree, mark_stmt_tree);
- ggc_add_tree_root (&c_scope_stmt_stack, 1);
- ggc_add_tree_root (&named_labels, 1);
- ggc_add_tree_root (&shadowed_labels, 1);
+ ggc_add_tree_root (c_global_trees, CTI_MAX, "c_global_trees");
+ add_tree_addresses (&data_to_save, c_global_trees, CTI_MAX, "c_global_trees");
+ ggc_add_root (&c_stmt_tree, 1, sizeof c_stmt_tree, mark_stmt_tree, "c_stmt_tree");
+ ggc_add_tree_root (&c_scope_stmt_stack, 1, "c_scope_stmt_stack");
+ ggc_add_tree_root (&named_labels, 1, "named_labels");
+ ggc_add_tree_root (&shadowed_labels, 1, "shadowed_labels");
ggc_add_root (&current_binding_level, 1, sizeof current_binding_level,
- mark_binding_level);
+ mark_binding_level, "current_binding_level");
+ add_tree_addresses (&data_to_save, &global_binding_level->names, 1, "global_binding_level->names");
+ add_tree_addresses (&data_to_save, &global_binding_level->tags, 1, "global_binding_level->tags");
ggc_add_root (&label_level_chain, 1, sizeof label_level_chain,
- mark_binding_level);
- ggc_add_tree_root (&static_ctors, 1);
- ggc_add_tree_root (&static_dtors, 1);
+ mark_binding_level, "label_level_chain");
+ ggc_add_tree_root (&static_ctors, 1, "static_ctors");
+ add_tree_addresses (&data_to_save, &static_ctors, 1, "static_ctors");
+ ggc_add_tree_root (&static_dtors, 1, "static_dtors");
+ add_tree_addresses (&data_to_save, &static_dtors, 1, "static_dtors");
}
/* Create the VAR_DECL for __FUNCTION__ etc. ID is the name to give the
@@ -3152,8 +3191,23 @@ builtin_function (name, type, function_code, class, library_name)
if (name[0] != '_' || name[1] != '_')
C_DECL_ANTICIPATED (decl) = 1;
+ /* Possibly apply some default attributes to this built-in function. */
+ decl_attributes (&decl, NULL_TREE, 0);
+
return decl;
}
+
+/* Apply default attributes to a function, if a system function with default
+ attributes. */
+
+void
+insert_default_attributes (decl)
+ tree decl;
+{
+ if (!TREE_PUBLIC (decl))
+ return;
+ c_common_insert_default_attributes (decl);
+}
/* Called when a declaration is seen that contains no names to declare.
If its type is a reference to a structure, union or enum inherited
diff --git a/gcc/c-format.c b/gcc/c-format.c
index e25c29e2a06..ea6ef57fa6d 100644
--- a/gcc/c-format.c
+++ b/gcc/c-format.c
@@ -77,10 +77,16 @@ enum format_type { printf_format_type, scanf_format_type,
strftime_format_type, strfmon_format_type,
format_type_error };
+typedef struct function_format_info
+{
+ enum format_type format_type; /* type of format (printf, scanf, etc.) */
+ unsigned HOST_WIDE_INT format_num; /* number of format argument */
+ unsigned HOST_WIDE_INT first_arg_num; /* number of first arg (zero for varargs) */
+} function_format_info;
+
+static bool decode_format_attr PARAMS ((tree,
+ function_format_info *, int));
static enum format_type decode_format_type PARAMS ((const char *));
-static void record_function_format PARAMS ((tree, tree, enum format_type,
- int, int));
-static void record_international_format PARAMS ((tree, tree, int));
/* Handle a "format" attribute; arguments as in
struct attribute_spec.handler. */
@@ -89,75 +95,16 @@ handle_format_attribute (node, name, args, flags, no_add_attrs)
tree *node;
tree name ATTRIBUTE_UNUSED;
tree args;
- int flags ATTRIBUTE_UNUSED;
+ int flags;
bool *no_add_attrs;
{
- tree decl = *node;
- tree type = TREE_TYPE (decl);
- tree format_type_id = TREE_VALUE (args);
- tree format_num_expr = TREE_VALUE (TREE_CHAIN (args));
- tree first_arg_num_expr
- = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args)));
- unsigned HOST_WIDE_INT format_num, first_arg_num;
- enum format_type format_type;
+ tree type = *node;
+ function_format_info info;
tree argument;
- unsigned int arg_num;
+ unsigned HOST_WIDE_INT arg_num;
- if (TREE_CODE (decl) != FUNCTION_DECL)
+ if (!decode_format_attr (args, &info, 0))
{
- error_with_decl (decl,
- "argument format specified for non-function `%s'");
- *no_add_attrs = true;
- return NULL_TREE;
- }
-
- if (TREE_CODE (format_type_id) != IDENTIFIER_NODE)
- {
- error ("unrecognized format specifier");
- *no_add_attrs = true;
- return NULL_TREE;
- }
- else
- {
- const char *p = IDENTIFIER_POINTER (format_type_id);
-
- format_type = decode_format_type (p);
-
- if (format_type == format_type_error)
- {
- warning ("`%s' is an unrecognized format function type", p);
- *no_add_attrs = true;
- return NULL_TREE;
- }
- }
-
- /* Strip any conversions from the string index and first arg number
- and verify they are constants. */
- while (TREE_CODE (format_num_expr) == NOP_EXPR
- || TREE_CODE (format_num_expr) == CONVERT_EXPR
- || TREE_CODE (format_num_expr) == NON_LVALUE_EXPR)
- format_num_expr = TREE_OPERAND (format_num_expr, 0);
-
- while (TREE_CODE (first_arg_num_expr) == NOP_EXPR
- || TREE_CODE (first_arg_num_expr) == CONVERT_EXPR
- || TREE_CODE (first_arg_num_expr) == NON_LVALUE_EXPR)
- first_arg_num_expr = TREE_OPERAND (first_arg_num_expr, 0);
-
- if (TREE_CODE (format_num_expr) != INTEGER_CST
- || TREE_INT_CST_HIGH (format_num_expr) != 0
- || TREE_CODE (first_arg_num_expr) != INTEGER_CST
- || TREE_INT_CST_HIGH (first_arg_num_expr) != 0)
- {
- error ("format string has invalid operand number");
- *no_add_attrs = true;
- return NULL_TREE;
- }
-
- format_num = TREE_INT_CST_LOW (format_num_expr);
- first_arg_num = TREE_INT_CST_LOW (first_arg_num_expr);
- if (first_arg_num != 0 && first_arg_num <= format_num)
- {
- error ("format string arg follows the args to be formatted");
*no_add_attrs = true;
return NULL_TREE;
}
@@ -168,7 +115,7 @@ handle_format_attribute (node, name, args, flags, no_add_attrs)
argument = TYPE_ARG_TYPES (type);
if (argument)
{
- for (arg_num = 1; argument != 0 && arg_num != format_num;
+ for (arg_num = 1; argument != 0 && arg_num != info.format_num;
++arg_num, argument = TREE_CHAIN (argument))
;
@@ -177,65 +124,56 @@ handle_format_attribute (node, name, args, flags, no_add_attrs)
|| (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_VALUE (argument)))
!= char_type_node))
{
- error ("format string arg not a string type");
+ if (!(flags & (int) ATTR_FLAG_BUILT_IN))
+ error ("format string arg not a string type");
*no_add_attrs = true;
return NULL_TREE;
}
- else if (first_arg_num != 0)
+ else if (info.first_arg_num != 0)
{
/* Verify that first_arg_num points to the last arg,
the ... */
while (argument)
arg_num++, argument = TREE_CHAIN (argument);
- if (arg_num != first_arg_num)
+ if (arg_num != info.first_arg_num)
{
- error ("args to be formatted is not '...'");
+ if (!(flags & (int) ATTR_FLAG_BUILT_IN))
+ error ("args to be formatted is not '...'");
*no_add_attrs = true;
return NULL_TREE;
}
}
}
- if (format_type == strftime_format_type && first_arg_num != 0)
+ if (info.format_type == strftime_format_type && info.first_arg_num != 0)
{
error ("strftime formats cannot format arguments");
*no_add_attrs = true;
return NULL_TREE;
}
- record_function_format (DECL_NAME (decl), DECL_ASSEMBLER_NAME (decl),
- format_type, format_num, first_arg_num);
return NULL_TREE;
}
-/* Handle a "format" attribute; arguments as in
+/* Handle a "format_arg" attribute; arguments as in
struct attribute_spec.handler. */
tree
handle_format_arg_attribute (node, name, args, flags, no_add_attrs)
tree *node;
tree name ATTRIBUTE_UNUSED;
tree args;
- int flags ATTRIBUTE_UNUSED;
+ int flags;
bool *no_add_attrs;
{
- tree decl = *node;
- tree type = TREE_TYPE (decl);
+ tree type = *node;
tree format_num_expr = TREE_VALUE (args);
unsigned HOST_WIDE_INT format_num;
- unsigned int arg_num;
+ unsigned HOST_WIDE_INT arg_num;
tree argument;
- if (TREE_CODE (decl) != FUNCTION_DECL)
- {
- error_with_decl (decl,
- "argument format specified for non-function `%s'");
- *no_add_attrs = true;
- return NULL_TREE;
- }
-
/* Strip any conversions from the first arg number and verify it
is a constant. */
while (TREE_CODE (format_num_expr) == NOP_EXPR
@@ -268,203 +206,102 @@ handle_format_arg_attribute (node, name, args, flags, no_add_attrs)
|| (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_VALUE (argument)))
!= char_type_node))
{
- error ("format string arg not a string type");
+ if (!(flags & (int) ATTR_FLAG_BUILT_IN))
+ error ("format string arg not a string type");
*no_add_attrs = true;
return NULL_TREE;
}
}
- if (TREE_CODE (TREE_TYPE (TREE_TYPE (decl))) != POINTER_TYPE
- || (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (TREE_TYPE (decl))))
+ if (TREE_CODE (TREE_TYPE (type)) != POINTER_TYPE
+ || (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (type)))
!= char_type_node))
{
- error ("function does not return string type");
+ if (!(flags & (int) ATTR_FLAG_BUILT_IN))
+ error ("function does not return string type");
*no_add_attrs = true;
return NULL_TREE;
}
- record_international_format (DECL_NAME (decl), DECL_ASSEMBLER_NAME (decl),
- format_num);
return NULL_TREE;
}
-typedef struct function_format_info
-{
- struct function_format_info *next; /* next structure on the list */
- tree name; /* identifier such as "printf" */
- tree assembler_name; /* optional mangled identifier (for C++) */
- enum format_type format_type; /* type of format (printf, scanf, etc.) */
- int format_num; /* number of format argument */
- int first_arg_num; /* number of first arg (zero for varargs) */
-} function_format_info;
-static function_format_info *function_format_list = NULL;
+/* Decode the arguments to a "format" attribute into a function_format_info
+ structure. It is already known that the list is of the right length.
+ If VALIDATED_P is true, then these attributes have already been validated
+ and this function will abort if they are erroneous; if false, it
+ will give an error message. Returns true if the attributes are
+ successfully decoded, false otherwise. */
-typedef struct international_format_info
-{
- struct international_format_info *next; /* next structure on the list */
- tree name; /* identifier such as "gettext" */
- tree assembler_name; /* optional mangled identifier (for C++) */
- int format_num; /* number of format argument */
-} international_format_info;
-
-static international_format_info *international_format_list = NULL;
-
-/* Initialize the table of functions to perform format checking on.
- The ISO C functions are always checked (whether <stdio.h> is
- included or not), since it is common to call printf without
- including <stdio.h>. There shouldn't be a problem with this,
- since ISO C reserves these function names whether you include the
- header file or not. In any case, the checking is harmless. With
- -ffreestanding, these default attributes are disabled, and must be
- specified manually if desired.
-
- Also initialize the name of function that modify the format string for
- internationalization purposes. */
-
-void
-init_function_format_info ()
+static bool
+decode_format_attr (args, info, validated_p)
+ tree args;
+ function_format_info *info;
+ int validated_p;
{
- /* __builtin functions should be checked unconditionally, even with
- -ffreestanding. */
- record_function_format (get_identifier ("__builtin_printf"), NULL_TREE,
- printf_format_type, 1, 2);
- record_function_format (get_identifier ("__builtin_fprintf"), NULL_TREE,
- printf_format_type, 2, 3);
-
- if (flag_hosted)
- {
- /* Functions from ISO/IEC 9899:1990. */
- record_function_format (get_identifier ("printf"), NULL_TREE,
- printf_format_type, 1, 2);
- record_function_format (get_identifier ("fprintf"), NULL_TREE,
- printf_format_type, 2, 3);
- record_function_format (get_identifier ("sprintf"), NULL_TREE,
- printf_format_type, 2, 3);
- record_function_format (get_identifier ("scanf"), NULL_TREE,
- scanf_format_type, 1, 2);
- record_function_format (get_identifier ("fscanf"), NULL_TREE,
- scanf_format_type, 2, 3);
- record_function_format (get_identifier ("sscanf"), NULL_TREE,
- scanf_format_type, 2, 3);
- record_function_format (get_identifier ("vprintf"), NULL_TREE,
- printf_format_type, 1, 0);
- record_function_format (get_identifier ("vfprintf"), NULL_TREE,
- printf_format_type, 2, 0);
- record_function_format (get_identifier ("vsprintf"), NULL_TREE,
- printf_format_type, 2, 0);
- record_function_format (get_identifier ("strftime"), NULL_TREE,
- strftime_format_type, 3, 0);
- }
+ tree format_type_id = TREE_VALUE (args);
+ tree format_num_expr = TREE_VALUE (TREE_CHAIN (args));
+ tree first_arg_num_expr
+ = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (args)));
- if (flag_hosted && (flag_isoc99 || flag_noniso_default_format_attributes))
+ if (TREE_CODE (format_type_id) != IDENTIFIER_NODE)
{
- /* ISO C99 adds the snprintf and vscanf family functions. */
- record_function_format (get_identifier ("snprintf"), NULL_TREE,
- printf_format_type, 3, 4);
- record_function_format (get_identifier ("vsnprintf"), NULL_TREE,
- printf_format_type, 3, 0);
- record_function_format (get_identifier ("vscanf"), NULL_TREE,
- scanf_format_type, 1, 0);
- record_function_format (get_identifier ("vfscanf"), NULL_TREE,
- scanf_format_type, 2, 0);
- record_function_format (get_identifier ("vsscanf"), NULL_TREE,
- scanf_format_type, 2, 0);
+ if (validated_p)
+ abort ();
+ error ("unrecognized format specifier");
+ return false;
}
-
- if (flag_hosted && flag_noniso_default_format_attributes)
+ else
{
- /* Uniforum/GNU gettext functions, not in ISO C. */
- record_international_format (get_identifier ("gettext"), NULL_TREE, 1);
- record_international_format (get_identifier ("dgettext"), NULL_TREE, 2);
- record_international_format (get_identifier ("dcgettext"), NULL_TREE, 2);
- /* X/Open strfmon function. */
- record_function_format (get_identifier ("strfmon"), NULL_TREE,
- strfmon_format_type, 3, 4);
- }
-}
-
-/* Record information for argument format checking. FUNCTION_IDENT is
- the identifier node for the name of the function to check (its decl
- need not exist yet).
- FORMAT_TYPE specifies the type of format checking. FORMAT_NUM is the number
- of the argument which is the format control string (starting from 1).
- FIRST_ARG_NUM is the number of the first actual argument to check
- against the format string, or zero if no checking is not be done
- (e.g. for varargs such as vfprintf). */
-
-static void
-record_function_format (name, assembler_name, format_type,
- format_num, first_arg_num)
- tree name;
- tree assembler_name;
- enum format_type format_type;
- int format_num;
- int first_arg_num;
-{
- function_format_info *info;
-
- /* Re-use existing structure if it's there. */
+ const char *p = IDENTIFIER_POINTER (format_type_id);
- for (info = function_format_list; info; info = info->next)
- {
- if (info->name == name && info->assembler_name == assembler_name)
- break;
- }
- if (! info)
- {
- info = (function_format_info *) xmalloc (sizeof (function_format_info));
- info->next = function_format_list;
- function_format_list = info;
+ info->format_type = decode_format_type (p);
- info->name = name;
- info->assembler_name = assembler_name;
+ if (info->format_type == format_type_error)
+ {
+ if (validated_p)
+ abort ();
+ warning ("`%s' is an unrecognized format function type", p);
+ return false;
+ }
}
- info->format_type = format_type;
- info->format_num = format_num;
- info->first_arg_num = first_arg_num;
-}
-
-/* Record information for the names of function that modify the format
- argument to format functions. FUNCTION_IDENT is the identifier node for
- the name of the function (its decl need not exist yet) and FORMAT_NUM is
- the number of the argument which is the format control string (starting
- from 1). */
-
-static void
-record_international_format (name, assembler_name, format_num)
- tree name;
- tree assembler_name;
- int format_num;
-{
- international_format_info *info;
+ /* Strip any conversions from the string index and first arg number
+ and verify they are constants. */
+ while (TREE_CODE (format_num_expr) == NOP_EXPR
+ || TREE_CODE (format_num_expr) == CONVERT_EXPR
+ || TREE_CODE (format_num_expr) == NON_LVALUE_EXPR)
+ format_num_expr = TREE_OPERAND (format_num_expr, 0);
- /* Re-use existing structure if it's there. */
+ while (TREE_CODE (first_arg_num_expr) == NOP_EXPR
+ || TREE_CODE (first_arg_num_expr) == CONVERT_EXPR
+ || TREE_CODE (first_arg_num_expr) == NON_LVALUE_EXPR)
+ first_arg_num_expr = TREE_OPERAND (first_arg_num_expr, 0);
- for (info = international_format_list; info; info = info->next)
+ if (TREE_CODE (format_num_expr) != INTEGER_CST
+ || TREE_INT_CST_HIGH (format_num_expr) != 0
+ || TREE_CODE (first_arg_num_expr) != INTEGER_CST
+ || TREE_INT_CST_HIGH (first_arg_num_expr) != 0)
{
- if (info->name == name && info->assembler_name == assembler_name)
- break;
+ if (validated_p)
+ abort ();
+ error ("format string has invalid operand number");
+ return false;
}
- if (! info)
+ info->format_num = TREE_INT_CST_LOW (format_num_expr);
+ info->first_arg_num = TREE_INT_CST_LOW (first_arg_num_expr);
+ if (info->first_arg_num != 0 && info->first_arg_num <= info->format_num)
{
- info
- = (international_format_info *)
- xmalloc (sizeof (international_format_info));
- info->next = international_format_list;
- international_format_list = info;
-
- info->name = name;
- info->assembler_name = assembler_name;
+ if (validated_p)
+ abort ();
+ error ("format string arg follows the args to be formatted");
+ return false;
}
- info->format_num = format_num;
+ return true;
}
-
-
-
/* Check a call to a format function against a parameter list. */
@@ -497,7 +334,7 @@ enum format_std_version
/* The C standard version C++ is treated as equivalent to
or inheriting from, for the purpose of format features supported. */
-#define CPLUSPLUS_STD_VER STD_C89
+#define CPLUSPLUS_STD_VER STD_C94
/* The C standard version we are checking formats against when pedantic. */
#define C_STD_VER ((int)(c_language == clk_cplusplus \
? CPLUSPLUS_STD_VER \
@@ -1058,10 +895,11 @@ typedef struct
static void check_format_info PARAMS ((int *, function_format_info *, tree));
static void check_format_info_recurse PARAMS ((int *, format_check_results *,
function_format_info *, tree,
- tree, int));
+ tree, unsigned HOST_WIDE_INT));
static void check_format_info_main PARAMS ((int *, format_check_results *,
function_format_info *,
- const char *, int, tree, int));
+ const char *, int, tree,
+ unsigned HOST_WIDE_INT));
static void status_warning PARAMS ((int *, const char *, ...))
ATTRIBUTE_PRINTF_2;
@@ -1102,43 +940,42 @@ decode_format_type (s)
/* Check the argument list of a call to printf, scanf, etc.
- NAME is the function identifier.
- ASSEMBLER_NAME is the function's assembler identifier.
- (Either NAME or ASSEMBLER_NAME, but not both, may be NULL_TREE.)
+ ATTRS are the attributes on the function type.
PARAMS is the list of argument values. Also, if -Wmissing-format-attribute,
warn for calls to vprintf or vscanf in functions with no such format
attribute themselves. */
void
-check_function_format (status, name, assembler_name, params)
+check_function_format (status, attrs, params)
int *status;
- tree name;
- tree assembler_name;
+ tree attrs;
tree params;
{
- function_format_info *info;
+ tree a;
- /* See if this function is a format function. */
- for (info = function_format_list; info; info = info->next)
+ /* See if this function has any format attributes. */
+ for (a = attrs; a; a = TREE_CHAIN (a))
{
- if (info->assembler_name
- ? (info->assembler_name == assembler_name)
- : (info->name == name))
+ if (is_attribute_p ("format", TREE_PURPOSE (a)))
{
/* Yup; check it. */
- check_format_info (status, info, params);
- if (warn_missing_format_attribute && info->first_arg_num == 0
- && (format_types[info->format_type].flags
+ function_format_info info;
+ decode_format_attr (TREE_VALUE (a), &info, 1);
+ check_format_info (status, &info, params);
+ if (warn_missing_format_attribute && info.first_arg_num == 0
+ && (format_types[info.format_type].flags
& (int) FMT_FLAG_ARG_CONVERT))
{
- function_format_info *info2;
- for (info2 = function_format_list; info2; info2 = info2->next)
- if ((info2->assembler_name
- ? (info2->assembler_name == DECL_ASSEMBLER_NAME (current_function_decl))
- : (info2->name == DECL_NAME (current_function_decl)))
- && info2->format_type == info->format_type)
+ tree c;
+ for (c = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
+ c;
+ c = TREE_CHAIN (c))
+ if (is_attribute_p ("format", TREE_PURPOSE (c))
+ && (decode_format_type (IDENTIFIER_POINTER
+ (TREE_VALUE (TREE_VALUE (c))))
+ == info.format_type))
break;
- if (info2 == NULL)
+ if (c == NULL_TREE)
{
/* Check if the current function has a parameter to which
the format attribute could be attached; if not, it
@@ -1156,10 +993,9 @@ check_function_format (status, name, assembler_name, params)
}
if (args != 0)
warning ("function might be possible candidate for `%s' format attribute",
- format_types[info->format_type].name);
+ format_types[info.format_type].name);
}
}
- break;
}
}
}
@@ -1417,7 +1253,7 @@ check_format_info (status, info, params)
function_format_info *info;
tree params;
{
- int arg_num;
+ unsigned HOST_WIDE_INT arg_num;
tree format_tree;
format_check_results res;
/* Skip to format argument. If the argument isn't available, there's
@@ -1512,7 +1348,7 @@ check_format_info_recurse (status, res, info, format_tree, params, arg_num)
function_format_info *info;
tree format_tree;
tree params;
- int arg_num;
+ unsigned HOST_WIDE_INT arg_num;
{
int format_length;
HOST_WIDE_INT offset;
@@ -1529,40 +1365,58 @@ check_format_info_recurse (status, res, info, format_tree, params, arg_num)
return;
}
- if (TREE_CODE (format_tree) == CALL_EXPR
- && TREE_CODE (TREE_OPERAND (format_tree, 0)) == ADDR_EXPR
- && (TREE_CODE (TREE_OPERAND (TREE_OPERAND (format_tree, 0), 0))
- == FUNCTION_DECL))
+ if (TREE_CODE (format_tree) == CALL_EXPR)
{
- tree function = TREE_OPERAND (TREE_OPERAND (format_tree, 0), 0);
+ tree type = TREE_TYPE (TREE_TYPE (TREE_OPERAND (format_tree, 0)));
+ tree attrs;
+ bool found_format_arg = false;
/* See if this is a call to a known internationalization function
- that modifies the format arg. */
- international_format_info *iinfo;
+ that modifies the format arg. Such a function may have multiple
+ format_arg attributes (for example, ngettext). */
- for (iinfo = international_format_list; iinfo; iinfo = iinfo->next)
- if (iinfo->assembler_name
- ? (iinfo->assembler_name == DECL_ASSEMBLER_NAME (function))
- : (iinfo->name == DECL_NAME (function)))
+ for (attrs = TYPE_ATTRIBUTES (type);
+ attrs;
+ attrs = TREE_CHAIN (attrs))
+ if (is_attribute_p ("format_arg", TREE_PURPOSE (attrs)))
{
tree inner_args;
+ tree format_num_expr;
+ int format_num;
int i;
+ /* Extract the argument number, which was previously checked
+ to be valid. */
+ format_num_expr = TREE_VALUE (TREE_VALUE (attrs));
+ while (TREE_CODE (format_num_expr) == NOP_EXPR
+ || TREE_CODE (format_num_expr) == CONVERT_EXPR
+ || TREE_CODE (format_num_expr) == NON_LVALUE_EXPR)
+ format_num_expr = TREE_OPERAND (format_num_expr, 0);
+
+ if (TREE_CODE (format_num_expr) != INTEGER_CST
+ || TREE_INT_CST_HIGH (format_num_expr) != 0)
+ abort ();
+
+ format_num = TREE_INT_CST_LOW (format_num_expr);
+
for (inner_args = TREE_OPERAND (format_tree, 1), i = 1;
inner_args != 0;
inner_args = TREE_CHAIN (inner_args), i++)
- if (i == iinfo->format_num)
+ if (i == format_num)
{
- /* FIXME: with Marc Espie's __attribute__((nonnull))
- patch in GCC, we will have chained attributes,
- and be able to handle functions like ngettext
- with multiple format_arg attributes properly. */
check_format_info_recurse (status, res, info,
TREE_VALUE (inner_args), params,
arg_num);
- return;
+ found_format_arg = true;
+ break;
}
}
+
+ /* If we found a format_arg attribute and did a recursive check,
+ we are done with checking this format string. Otherwise, we
+ continue and this will count as a non-literal format string. */
+ if (found_format_arg)
+ return;
}
if (TREE_CODE (format_tree) == COND_EXPR)
@@ -1736,7 +1590,7 @@ check_format_info_main (status, res, info, format_chars, format_length,
const char *format_chars;
int format_length;
tree params;
- int arg_num;
+ unsigned HOST_WIDE_INT arg_num;
{
const char *orig_format_chars = format_chars;
tree first_fillin_param = params;
diff --git a/gcc/c-lang.c b/gcc/c-lang.c
index 36d73d29c5e..e642ade6a8b 100644
--- a/gcc/c-lang.c
+++ b/gcc/c-lang.c
@@ -37,10 +37,18 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
#include "cpplib.h"
static int c_tree_printer PARAMS ((output_buffer *));
+static size_t lang_type_size_fetcher PARAMS ((const void *v,
+ type_definition_p td));
+static int lang_type_more_fields PARAMS ((struct field_definition_s *fp,
+ const void *v,
+ unsigned n, code_type c,
+ type_definition_p td));
+
static int c_missing_noreturn_ok_p PARAMS ((tree));
static void c_init PARAMS ((void));
static void c_init_options PARAMS ((void));
static void c_post_options PARAMS ((void));
+static void c_tree_prewrite_hook PARAMS ((const void *));
/* Each front end provides its own. */
struct lang_hooks lang_hooks = {c_init,
@@ -68,6 +76,79 @@ c_init_options ()
flag_bounds_check = -1;
}
+static const struct field_definition_s c_tree_field_defs[] = {
+ { 'd', 0xFF, offsetof (union tree_node, decl.lang_specific),
+ lang_decl_type_def },
+ { 't', 0xFF, offsetof (union tree_node, type.lang_specific),
+ lang_type_type_def },
+ { IDENTIFIER_NODE << 8, 0xFF00,
+ offsetof (struct lang_identifier, global_value), tree_type_def },
+ { IDENTIFIER_NODE << 8, 0xFF00,
+ offsetof (struct lang_identifier, local_value), tree_type_def },
+ { IDENTIFIER_NODE << 8, 0xFF00,
+ offsetof (struct lang_identifier, label_value), tree_type_def },
+ { IDENTIFIER_NODE << 8, 0xFF00,
+ offsetof (struct lang_identifier, implicit_decl), tree_type_def },
+ { IDENTIFIER_NODE << 8, 0xFF00,
+ offsetof (struct lang_identifier, error_locus), tree_type_def },
+ { IDENTIFIER_NODE << 8, 0xFF00,
+ offsetof (struct lang_identifier, limbo_value), tree_type_def },
+ NO_MORE_FIELDS
+};
+
+static const struct field_definition_s c_lang_decl_field_defs[] = {
+ { 0, 0, offsetof (struct lang_decl, base.saved_tree), tree_type_def },
+ NO_MORE_FIELDS
+};
+
+static size_t
+lang_type_size_fetcher (v, td)
+ const void *v;
+ type_definition_p td ATTRIBUTE_UNUSED;
+{
+ struct lang_type *t = (struct lang_type *)v;
+ return sizeof (*t) - sizeof (tree) + t->len * sizeof (tree);
+}
+
+static int
+lang_type_more_fields (fp, v, n, c, td)
+ struct field_definition_s *fp;
+ const void *v;
+ unsigned n;
+ code_type c ATTRIBUTE_UNUSED;
+ type_definition_p td ATTRIBUTE_UNUSED;
+{
+ struct lang_type *t = (struct lang_type *)v;
+ if (n < (unsigned)t->len)
+ {
+ fp->offset = offsetof (struct lang_type, elts) + n * sizeof (tree);
+ fp->type = tree_type_def;
+ return 1;
+ }
+ return 0;
+}
+
+/* A function to be called for each tree node before they are written out
+ by the precompiled headers mechanism. Currently we use this to note
+ that the fields are not sorted, as PCH fails to preserve address order
+ for identifiers. */
+
+static void
+c_tree_prewrite_hook (t_v)
+ const void *t_v;
+{
+ tree t = (tree)t_v;
+ if (TYPE_P (t))
+ TYPE_LANG_SPECIFIC (t) = 0;
+}
+
+
+static const struct field_definition_s c_lang_function_field_defs[] = {
+
+ NO_MORE_FIELDS
+};
+
+
static void
c_init ()
{
@@ -92,7 +173,16 @@ c_init ()
lang_expand_decl_stmt = &c_expand_decl_stmt;
lang_missing_noreturn_ok_p = &c_missing_noreturn_ok_p;
+ add_tree_fields (c_tree_field_defs);
+ tree_type_def->prewrite_hook = c_tree_prewrite_hook;
+ lang_decl_type_def->size = sizeof (struct lang_decl);
+ lang_decl_type_def->field_definitions = c_lang_decl_field_defs;
+ lang_type_type_def->size = sizeof (struct lang_type) - sizeof (tree);
+ lang_type_type_def->size_fetcher = lang_type_size_fetcher;
+ lang_type_type_def->more_fields = lang_type_more_fields;
+
c_parse_init ();
+ pch_init ();
}
const char *
@@ -101,6 +191,12 @@ lang_identify ()
return "c";
}
+int
+lang_toplevel_p ()
+{
+ return global_bindings_p ();
+}
+
void
print_lang_statistics ()
{
@@ -225,6 +321,8 @@ finish_cdtor (body)
void
finish_file ()
{
+ if (pch_file)
+ lang_write_pch ();
#ifndef ASM_OUTPUT_CONSTRUCTOR
if (static_ctors)
{
@@ -308,3 +406,10 @@ c_missing_noreturn_ok_p (decl)
ok for the `main' function in hosted implementations. */
return flag_hosted && MAIN_NAME_P (DECL_ASSEMBLER_NAME (decl));
}
+void
+lang_write_pch ()
+{
+ c_write_pch ();
+}
+
+
diff --git a/gcc/c-lex.c b/gcc/c-lex.c
index 8e6582f06db..f2bf82d5779 100644
--- a/gcc/c-lex.c
+++ b/gcc/c-lex.c
@@ -31,7 +31,9 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
#include "c-tree.h"
#include "flags.h"
#include "timevar.h"
+#if 0
#include "cpplib.h"
+#endif
#include "c-pragma.h"
#include "toplev.h"
#include "intl.h"
@@ -54,6 +56,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
#define GET_ENVIRONMENT(ENV_VALUE,ENV_NAME) ((ENV_VALUE) = getenv (ENV_NAME))
#endif
+FILE *finput;
+
/* The input filename as understood by CPP, where "" represents stdin. */
static const char *cpp_filename;
@@ -67,6 +71,49 @@ static unsigned int src_lineno;
static int header_time, body_time;
static splay_tree file_info_tree;
+struct putback_buffer
+{
+ unsigned char *buffer;
+ int buffer_size;
+ int index;
+};
+
+static struct putback_buffer putback = {NULL, 0, -1};
+
+static inline int getch PARAMS ((void));
+
+static inline int
+getch ()
+{
+ if (putback.index != -1)
+ {
+ int ch = putback.buffer[putback.index];
+ --putback.index;
+ return ch;
+ }
+ return getc (finput);
+}
+
+static inline void put_back PARAMS ((int));
+
+static inline void
+put_back (ch)
+ int ch;
+{
+ if (ch != EOF)
+ {
+ if (putback.index == putback.buffer_size - 1)
+ {
+ putback.buffer_size += 16;
+ putback.buffer = xrealloc (putback.buffer, putback.buffer_size);
+ }
+ putback.buffer[++putback.index] = ch;
+ }
+}
+
+int linemode;
+
+
/* Cause the `yydebug' variable to be defined. */
#define YYDEBUG 1
@@ -79,6 +126,11 @@ extern FILE *asm_out_file;
/* Number of bytes in a wide character. */
#define WCHAR_BYTES (WCHAR_TYPE_SIZE / BITS_PER_UNIT)
+void (*lang_include_hook) PARAMS ((cpp_reader *,
+ const unsigned char *,
+ const unsigned char *,
+ unsigned int, int));
+
int indent_level; /* Number of { minus number of }. */
int pending_lang_change; /* If we need to switch languages - C++ only */
int c_header_level; /* depth in C headers - C++ only */
@@ -133,6 +185,8 @@ init_c_lex (filename)
cb->ident = cb_ident;
cb->file_change = cb_file_change;
cb->def_pragma = cb_def_pragma;
+ cb->valid_pch = lang_valid_pch;
+ cb->read_pch = lang_read_pch;
/* Set the debug callbacks if we can use them. */
if (debug_info_level == DINFO_LEVEL_VERBOSE
@@ -142,6 +196,8 @@ init_c_lex (filename)
cb->undef = cb_undef;
}
+ if (! cpp_start_read (parse_in, filename))
+ return 1; /* cpplib has emitted an error. */
if (filename == 0 || !strcmp (filename, "-"))
filename = "stdin", cpp_filename = "";
@@ -160,8 +216,10 @@ init_c_lex (filename)
int
yyparse()
{
+#if 0
if (! cpp_start_read (parse_in, cpp_filename))
return 1; /* cpplib has emitted an error. */
+#endif
return yyparse_1();
}
@@ -177,10 +235,14 @@ get_fileinfo (name)
if (n)
return (struct c_fileinfo *) n->value;
+#if 1
+ fi = (struct c_fileinfo *) xcalloc (1, sizeof (struct c_fileinfo));
+#else
fi = (struct c_fileinfo *) xmalloc (sizeof (struct c_fileinfo));
fi->time = 0;
fi->interface_only = 0;
fi->interface_unknown = 1;
+#endif
splay_tree_insert (file_info_tree, (splay_tree_key) name,
(splay_tree_value) fi);
return fi;
diff --git a/gcc/c-parse.in b/gcc/c-parse.in
index 85c2815409d..a0a62b54e62 100644
--- a/gcc/c-parse.in
+++ b/gcc/c-parse.in
@@ -41,6 +41,7 @@ end ifc
#include "tree.h"
#include "input.h"
#include "cpplib.h"
+#include "cpphash.h"
#include "intl.h"
#include "timevar.h"
#include "c-lex.h"
@@ -320,16 +321,16 @@ static void init_reswords PARAMS ((void));
void
c_parse_init ()
{
- ggc_add_tree_root (&declspec_stack, 1);
- ggc_add_tree_root (&current_declspecs, 1);
- ggc_add_tree_root (&prefix_attributes, 1);
- ggc_add_tree_root (&all_prefix_attributes, 1);
+ ggc_add_tree_root (&declspec_stack, 1, "declspec_stack");
+ ggc_add_tree_root (&current_declspecs, 1, "current_declspecs");
+ ggc_add_tree_root (&prefix_attributes, 1, "prefix_attributes");
+ ggc_add_tree_root (&all_prefix_attributes, 1, "all_prefix_attributes");
ifobjc
- ggc_add_tree_root (&objc_interface_context, 1);
- ggc_add_tree_root (&objc_implementation_context, 1);
- ggc_add_tree_root (&objc_method_context, 1);
- ggc_add_tree_root (&objc_ivar_chain, 1);
- ggc_add_tree_root (&objc_ivar_context, 1);
+ ggc_add_tree_root (&objc_interface_context, 1, "objc_interface_context");
+ ggc_add_tree_root (&objc_implementation_context, 1, "objc_implementation_context");
+ ggc_add_tree_root (&objc_method_context, 1, "objc_method_context");
+ ggc_add_tree_root (&objc_ivar_chain, 1, "objc_ivar_chain");
+ ggc_add_tree_root (&objc_ivar_context, 1, "objc_ivar_context");
end ifobjc
}
@@ -360,7 +361,18 @@ end ifc
extdefs:
{$<ttype>$ = NULL_TREE; } extdef
- | extdefs {$<ttype>$ = NULL_TREE; ggc_collect(); } extdef
+ | extdefs
+ {
+ $<ttype>$ = NULL_TREE;
+ ggc_collect();
+ if (allow_pch)
+ {
+ parse_in->cb.valid_pch = NULL;
+ allow_pch = 0;
+ }
+ }
+ extdef
+
;
extdef:
@@ -3741,7 +3753,8 @@ _yylex ()
case CPP_SEMICOLON: OBJC_NEED_RAW_IDENTIFIER (0); return ';';
case CPP_EOF:
- return 0;
+ return 0;
+
case CPP_NAME:
return yylexname ();
diff --git a/gcc/c-pragma.c b/gcc/c-pragma.c
index 0d1caaff486..90f8baebe3c 100644
--- a/gcc/c-pragma.c
+++ b/gcc/c-pragma.c
@@ -317,6 +317,6 @@ init_pragma ()
#ifdef HANDLE_PRAGMA_PACK_PUSH_POP
ggc_add_root (&alignment_stack, 1, sizeof(alignment_stack),
- mark_align_stack);
+ mark_align_stack, "alignment_stack");
#endif
}
diff --git a/gcc/c-pragma.h b/gcc/c-pragma.h
index 6f0d6ea15a0..02baac68f2d 100644
--- a/gcc/c-pragma.h
+++ b/gcc/c-pragma.h
@@ -42,6 +42,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
#endif /* HANDLE_PRAGMA_PACK_PUSH_POP */
extern void init_pragma PARAMS ((void));
+extern void dispatch_pragma PARAMS ((void));
+
/* Duplicate prototypes for the register_pragma stuff and the typedef for
cpp_reader, to avoid dragging cpplib.h in almost everywhere... */
diff --git a/gcc/c-typeck.c b/gcc/c-typeck.c
index c407f16d640..09ebf4d4b9f 100644
--- a/gcc/c-typeck.c
+++ b/gcc/c-typeck.c
@@ -1510,8 +1510,8 @@ build_function_call (function, params)
/* Check for errors in format strings. */
- if (warn_format && (name || assembler_name))
- check_function_format (NULL, name, assembler_name, coerced_params);
+ if (warn_format)
+ check_function_format (NULL, TYPE_ATTRIBUTES (fntype), coerced_params);
/* Recognize certain built-in functions so we can make tree-codes
other than CALL_EXPR. We do this when it enables fold-const.c
diff --git a/gcc/cp/Make-lang.in b/gcc/cp/Make-lang.in
index 4fe7e8752b4..3f2845d0a2f 100644
--- a/gcc/cp/Make-lang.in
+++ b/gcc/cp/Make-lang.in
@@ -101,7 +101,7 @@ CXX_OBJS = cp/call.o cp/decl.o cp/expr.o cp/pt.o cp/typeck2.o \
cp/class.o cp/decl2.o cp/error.o cp/lex.o cp/parse.o cp/ptree.o cp/rtti.o \
cp/spew.o cp/typeck.o cp/cvt.o cp/except.o cp/friend.o cp/init.o cp/method.o \
cp/search.o cp/semantics.o cp/tree.o cp/xref.o cp/repo.o cp/dump.o \
- cp/optimize.o cp/mangle.o
+ cp/optimize.o cp/mangle.o cp/linkage.o
# Use loose warnings for this front end.
cp-warn =
@@ -242,7 +242,7 @@ cp/lex.o: cp/lex.c $(CXX_TREE_H) cp/parse.h flags.h cp/lex.h c-pragma.h \
toplev.h output.h mbchar.h $(GGC_H) input.h diagnostic.h cp/operators.def \
$(TM_P_H)
cp/decl.o: cp/decl.c $(CXX_TREE_H) flags.h cp/lex.h cp/decl.h stack.h \
- output.h $(EXPR_H) except.h toplev.h hash.h $(GGC_H) $(RTL_H) \
+ output.h $(EXPR_H) except.h hash.h toplev.h $(GGC_H) $(RTL_H) \
cp/operators.def $(TM_P_H)
cp/decl2.o: cp/decl2.c $(CXX_TREE_H) flags.h cp/lex.h cp/decl.h $(EXPR_H) \
output.h except.h toplev.h $(GGC_H) $(RTL_H)
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 42731487892..bbf340811e5 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -4204,9 +4204,9 @@ build_over_call (cand, args, flags)
converted_args = nreverse (converted_args);
- if (warn_format && (DECL_NAME (fn) || DECL_ASSEMBLER_NAME (fn)))
- check_function_format (NULL, DECL_NAME (fn), DECL_ASSEMBLER_NAME (fn),
- converted_args);
+ if (warn_format)
+ check_function_format (NULL, TYPE_ATTRIBUTES (TREE_TYPE (fn)),
+ converted_args);
/* Avoid actually calling copy constructors and copy assignment operators,
if possible. */
@@ -4381,7 +4381,7 @@ build_java_interface_fn_ref (fn, instance)
= builtin_function ("_Jv_LookupInterfaceMethodIdx",
build_function_type (ptr_type_node, t),
0, NOT_BUILT_IN, NULL);
- ggc_add_tree_root (&java_iface_lookup_fn, 1);
+ ggc_add_tree_root (&java_iface_lookup_fn, 1 , "java_iface");
}
/* Look up the pointer to the runtime java.lang.Class object for `instance'.
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index ac71fc5baa5..565891e3055 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -5501,7 +5501,8 @@ init_class_processing ()
= (class_stack_node_t) xmalloc (current_class_stack_size
* sizeof (struct class_stack_node));
VARRAY_TREE_INIT (local_classes, 8, "local_classes");
- ggc_add_tree_varray_root (&local_classes, 1);
+ ggc_add_tree_varray_root (&local_classes, 1, "local_classes");
+ add_varray_tree_addresses (&data_to_save, &local_classes, 1, "local_classes");
access_default_node = build_int_2 (0, 0);
access_public_node = build_int_2 (ak_public, 0);
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index de58ee4b890..583d3abc94f 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -152,6 +152,11 @@ Boston, MA 02111-1307, USA. */
the virtual function this one overrides, and whose TREE_CHAIN is
the old DECL_VINDEX. */
+#define cp_binding_level_type_def lang1_type_def
+#define cp_lang_id2_type_def lang2_type_def
+#define cpf_tree_node_type_def lang3_type_def
+#define cp_fileinfo_type_def lang4_type_def
+
/* Language-specific tree checkers. */
#if defined ENABLE_TREE_CHECKING && (GCC_VERSION >= 2007)
@@ -1012,6 +1017,7 @@ extern int flag_signed_bitfields;
for exporting definitions that others might need. */
extern int interface_only, interface_unknown;
+
/* Nonzero means we should attempt to elide constructors when possible. */
extern int flag_elide_constructors;
@@ -1361,6 +1367,11 @@ struct lang_type
#define CLASSTYPE_DESTRUCTORS(NODE) \
(TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (NODE), CLASSTYPE_DESTRUCTOR_SLOT))
+/* Whether or not the methods for the class have been sorted yet. */
+#define METHOD_VEC_SORTED_P(NODE) (TREE_LANG_FLAG_0 (NODE))
+#define CLASSTYPE_METHOD_VEC_SORTED_P(NODE) \
+ (TREE_LANG_FLAG_0 (CLASSTYPE_METHOD_VEC (NODE)))
+
/* Mark bits for depth-first and breath-first searches. */
/* Get the value of the Nth mark bit. */
@@ -3525,6 +3536,10 @@ extern tree build_vtbl_ref PARAMS ((tree, tree));
extern tree build_vfn_ref PARAMS ((tree, tree));
extern tree get_vtable_decl PARAMS ((tree, int));
extern void add_method PARAMS ((tree, tree, int));
+#if 0
+extern void sort_methods PARAMS ((tree));
+extern void sort_fields PARAMS ((tree));
+#endif
extern int currently_open_class PARAMS ((tree));
extern tree currently_open_derived_class PARAMS ((tree));
extern void duplicate_tag_error PARAMS ((tree));
@@ -3805,6 +3820,7 @@ extern int cp_line_of PARAMS ((tree));
extern const char *language_to_string PARAMS ((enum languages, int));
extern void print_instantiation_context PARAMS ((void));
+
/* in except.c */
extern void init_exception_processing PARAMS ((void));
extern tree expand_start_catch_block PARAMS ((tree));
@@ -3887,6 +3903,13 @@ extern void clear_inline_text_obstack PARAMS ((void));
extern void yyhook PARAMS ((int));
extern int cp_type_qual_from_rid PARAMS ((tree));
+/* in linkage.c */
+extern void do_pragma_interface PARAMS ((tree));
+extern void do_pragma_implementation PARAMS ((tree));
+extern void maybe_add_interface_item PARAMS ((tree));
+extern void process_interface_items PARAMS ((void));
+extern void init_linkage PARAMS ((void));
+
/* in method.c */
extern void init_method PARAMS ((void));
extern void set_mangled_name_for_decl PARAMS ((tree));
@@ -4142,6 +4165,7 @@ extern void do_pending_defargs PARAMS ((void));
extern void done_pending_defargs PARAMS ((void));
extern void unprocessed_defarg_fn PARAMS ((tree));
extern void replace_defarg PARAMS ((tree, tree));
+extern void end_input PARAMS ((void));
/* in tree.c */
extern void init_tree PARAMS ((void));
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index dc4eb8116e9..3e12b4fb678 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -47,6 +47,8 @@ Boston, MA 02111-1307, USA. */
extern const struct attribute_spec *lang_attribute_table;
+
+
#ifndef BOOL_TYPE_SIZE
/* `bool' has size and alignment `1', on all platforms. */
#define BOOL_TYPE_SIZE CHAR_TYPE_SIZE
@@ -5533,7 +5535,7 @@ build_typename_type (context, name, fullname, base_type)
static struct hash_table *h = &ht;
hash_table_init (&ht, &hash_newfunc, &typename_hash, &typename_compare);
- ggc_add_tree_hash_table_root (&h, 1);
+ ggc_add_tree_hash_table_root (&h, 1, "h");
}
/* Build the TYPENAME_TYPE. */
@@ -6276,6 +6278,23 @@ initialize_predefined_identifiers ()
Initialize the global binding level.
Make definitions for built-in primitive functions. */
+static const struct field_definition_s cp_binding_level_field_defs[] = {
+ { 0, 0, offsetof (struct binding_level, level_chain),
+ cp_binding_level_type_def },
+ { 0, 0, offsetof (struct binding_level, names), tree_type_def },
+ { 0, 0, offsetof (struct binding_level, tags), tree_type_def },
+ { 0, 0, offsetof (struct binding_level, usings), tree_type_def },
+ { 0, 0, offsetof (struct binding_level, using_directives), tree_type_def },
+ { 0, 0, offsetof (struct binding_level, class_shadowed), tree_type_def },
+ { 0, 0, offsetof (struct binding_level, type_shadowed), tree_type_def },
+ { 0, 0, offsetof (struct binding_level, shadowed_labels), tree_type_def },
+ { 0, 0, offsetof (struct binding_level, blocks), tree_type_def },
+ { 0, 0, offsetof (struct binding_level, this_class), tree_type_def },
+ { 0, 0, offsetof (struct binding_level, incomplete), tree_type_def },
+ { 0, 0, offsetof (struct binding_level, dead_vars_from_for), tree_type_def },
+ NO_MORE_FIELDS
+};
+
void
init_decl_processing ()
{
@@ -6285,6 +6304,12 @@ init_decl_processing ()
/* Create all the identifiers we need. */
initialize_predefined_identifiers ();
+ /* Set up cp_binding_level_type_def. */
+ cp_binding_level_type_def->size = sizeof (struct binding_level);
+ cp_binding_level_type_def->field_definitions = cp_binding_level_field_defs;
+ cp_binding_level_type_def->ggc_p = -1;
+
+
/* Fill in back-end hooks. */
init_lang_status = &push_cp_function_context;
free_lang_status = &pop_cp_function_context;
@@ -6350,6 +6375,8 @@ init_decl_processing ()
std_node = current_namespace;
pop_namespace ();
+ lang_attribute_table = cp_attribute_table;
+
c_common_nodes_and_builtins ();
java_byte_type_node = record_builtin_java_type ("__java_byte", 8);
@@ -6487,47 +6514,67 @@ init_decl_processing ()
make_fname_decl = cp_make_fname_decl;
start_fname_decls ();
- /* Prepare to check format strings against argument lists. */
- init_function_format_info ();
-
/* Show we use EH for cleanups. */
using_eh_for_cleanups ();
- lang_attribute_table = cp_attribute_table;
-
/* Maintain consistency. Perhaps we should just complain if they
say -fwritable-strings? */
if (flag_writable_strings)
flag_const_strings = 0;
/* Add GC roots for all of our global variables. */
- ggc_add_tree_root (c_global_trees, sizeof c_global_trees / sizeof(tree));
- ggc_add_tree_root (cp_global_trees, sizeof cp_global_trees / sizeof(tree));
- ggc_add_tree_root (&integer_three_node, 1);
- ggc_add_tree_root (&integer_two_node, 1);
- ggc_add_tree_root (&signed_size_zero_node, 1);
- ggc_add_tree_root (&size_one_node, 1);
- ggc_add_tree_root (&size_zero_node, 1);
- ggc_add_root (&global_binding_level, 1, sizeof global_binding_level,
- mark_binding_level);
- ggc_add_root (&scope_chain, 1, sizeof scope_chain, &mark_saved_scope);
- ggc_add_tree_root (&static_ctors, 1);
- ggc_add_tree_root (&static_dtors, 1);
- ggc_add_tree_root (&lastiddecl, 1);
-
- ggc_add_tree_root (&last_function_parms, 1);
- ggc_add_tree_root (&error_mark_list, 1);
-
- ggc_add_tree_root (&global_namespace, 1);
- ggc_add_tree_root (&global_type_node, 1);
- ggc_add_tree_root (&anonymous_namespace_name, 1);
-
- ggc_add_tree_root (&got_object, 1);
- ggc_add_tree_root (&got_scope, 1);
-
- ggc_add_tree_root (&current_lang_name, 1);
- ggc_add_tree_root (&static_aggregates, 1);
- ggc_add_tree_root (&free_bindings, 1);
+ ggc_add_tree_root (c_global_trees, CTI_MAX ,"c_global_trees");
+ add_tree_addresses (&data_to_save, c_global_trees , CTI_MAX , "c_global_trees");
+ ggc_add_tree_root (cp_global_trees, CPTI_MAX , "cp_global_trees");
+ add_tree_addresses (&data_to_save, cp_global_trees, CPTI_MAX , "cp_global_trees");
+ add_tree_addresses (&data_to_save, ridpointers, RID_MAX, "ridpointers");
+ ggc_add_tree_root (&integer_three_node, 1, "integer_three_node");
+ add_tree_addresses (&data_to_save, &integer_three_node, 1, "integer_three_node");
+ ggc_add_tree_root (&integer_two_node, 1, "integer_two_node");
+ add_tree_addresses (&data_to_save, &integer_two_node, 1, "integer_two_node");
+ ggc_add_tree_root (&signed_size_zero_node, 1, "signed_size_zero_node");
+ add_tree_addresses (&data_to_save, &signed_size_zero_node, 1, "signed_size_zero_node");
+ ggc_add_tree_root (&size_one_node, 1, "size_one_node");
+ add_tree_addresses (&data_to_save, &size_one_node, 1, "size_one_node");
+ ggc_add_tree_root (&size_zero_node, 1, "size_zero_node");
+ add_tree_addresses (&data_to_save, &size_zero_node, 1, "size_zero_node");
+ ggc_add_typed_root (&global_binding_level, cp_binding_level_type_def, 1, "global_binding_level");
+ add_typed_addresses (&data_to_save, (void **)&global_binding_level,
+ cp_binding_level_type_def, 1, "global_binding_level");
+ add_typed_addresses (&data_to_save, (void **)&current_binding_level,
+ cp_binding_level_type_def, 1, "current_binding_level");
+ ggc_add_root (&scope_chain, 1, sizeof scope_chain, &mark_saved_scope, "scope_chain");
+ ggc_add_tree_root (&static_ctors, 1, "static_ctors");
+ add_tree_addresses (&data_to_save, &static_ctors, 1, "static_ctors");
+ ggc_add_tree_root (&static_dtors, 1, "static_dtors");
+ add_tree_addresses (&data_to_save, &static_dtors, 1, "static_dtors");
+ ggc_add_tree_root (&lastiddecl, 1, "lastiddecl");
+
+ ggc_add_tree_root (&last_function_parms, 1 , "last_function_parms" );
+ ggc_add_tree_root (&error_mark_list, 1 , "error_mark_list" );
+ add_tree_addresses (&data_to_save, &error_mark_list, 1 , "error_mark_list" );
+
+ ggc_add_tree_root (&global_namespace, 1 , "global_namespace" );
+ add_tree_addresses (&data_to_save, &global_namespace, 1 , "global_namespace" );
+ add_tree_addresses (&data_to_save, &current_namespace, 1 , "current_namespace" );
+ ggc_add_tree_root (&global_type_node, 1 , "global_type_node" );
+ add_tree_addresses (&data_to_save, &global_type_node, 1 , "global_type_node" );
+ ggc_add_tree_root (&anonymous_namespace_name, 1 , "anonymous_namespace_name" );
+ add_tree_addresses (&data_to_save, &anonymous_namespace_name, 1 , "anonymous_namespace_name" );
+
+ ggc_add_tree_root (&got_object, 1 , "got_object" );
+
+ ggc_add_tree_root (&got_scope, 1 , "got_scope" );
+
+ ggc_add_tree_root (&current_lang_name, 1 , "current_lang_name" );
+ add_tree_addresses (&data_to_save, &current_lang_name, 1 , "current_lang_name" );
+ ggc_add_tree_root (&static_aggregates, 1 , "static_aggregates" );
+ add_tree_addresses (&data_to_save, &static_aggregates, 1 , "static_aggregates" );
+
+ add_untyped_address (&data_to_save, &anon_cnt, sizeof (anon_cnt) , "anon_cnt" );
+
+ ggc_add_tree_root (&free_bindings, 1 , "free_bindings" );
+ add_tree_addresses (&data_to_save, &free_bindings, 1 , "free_bindings" );
}
/* Generate an initializer for a function naming variable from
@@ -6643,6 +6690,9 @@ builtin_function (name, type, code, class, libname)
if (name[0] != '_' || name[1] != '_')
DECL_ANTICIPATED (decl) = 1;
+ /* Possibly apply some default attributes to this built-in function. */
+ decl_attributes (&decl, NULL_TREE, 0);
+
return decl;
}
@@ -6765,6 +6815,20 @@ push_throw_library_fn (name, type)
TREE_NOTHROW (fn) = 0;
return fn;
}
+
+/* Apply default attributes to a function, if a system function with default
+ attributes. */
+
+void
+insert_default_attributes (decl)
+ tree decl;
+{
+ if (!DECL_EXTERN_C_FUNCTION_P (decl))
+ return;
+ if (!TREE_PUBLIC (decl))
+ return;
+ c_common_insert_default_attributes (decl);
+}
/* When we call finish_struct for an anonymous union, we create
default copy constructors and such. But, an anonymous union
@@ -11019,13 +11083,13 @@ grokdeclarator (declarator, declspecs, decl_context, initialized, attrlist)
}
else if (quals)
{
- if (ctype == NULL_TREE)
- {
- if (TREE_CODE (type) != METHOD_TYPE)
+ if (ctype == NULL_TREE)
+ {
+ if (TREE_CODE (type) != METHOD_TYPE)
cp_error_at ("invalid type qualifier for non-member function type", decl);
else
- ctype = TYPE_METHOD_BASETYPE (type);
- }
+ ctype = TYPE_METHOD_BASETYPE (type);
+ }
if (ctype != NULL_TREE)
grok_method_quals (ctype, decl, quals);
}
@@ -13451,7 +13515,7 @@ start_function (declspecs, declarator, attrs, flags)
if (!DECL_PENDING_INLINE_P (decl1)
&& DECL_SAVED_FUNCTION_DATA (decl1))
{
- free (DECL_SAVED_FUNCTION_DATA (decl1));
+ free(DECL_SAVED_FUNCTION_DATA (decl1));
DECL_SAVED_FUNCTION_DATA (decl1) = NULL;
}
@@ -13527,14 +13591,14 @@ start_function (declspecs, declarator, attrs, flags)
DECL_INTERFACE_KNOWN (decl1) = 1;
}
else if (interface_unknown && interface_only
- && (! DECL_TEMPLATE_INSTANTIATION (decl1)
- || flag_alt_external_templates))
+ && (! DECL_TEMPLATE_INSTANTIATION (decl1)
+ || flag_alt_external_templates))
{
/* If MULTIPLE_SYMBOL_SPACES is defined and we saw a #pragma
- interface, we will have interface_only set but not
- interface_known. In that case, we don't want to use the normal
- heuristics because someone will supply a #pragma implementation
- elsewhere, and deducing it here would produce a conflict. */
+ interface, we will have interface_only set but not
+ interface_known. In that case, we don't want to use the normal
+ heuristics because someone will supply a #pragma implementation
+ elsewhere, and deducing it here would produce a conflict. */
comdat_linkage (decl1);
DECL_EXTERNAL (decl1) = 0;
DECL_INTERFACE_KNOWN (decl1) = 1;
@@ -13551,7 +13615,7 @@ start_function (declspecs, declarator, attrs, flags)
&& ! DECL_INTERFACE_KNOWN (decl1)
/* Don't try to defer nested functions for now. */
&& ! decl_function_context (decl1))
- DECL_DEFER_OUTPUT (decl1) = 1;
+ DECL_DEFER_OUTPUT (decl1) = 1;
else
DECL_INTERFACE_KNOWN (decl1) = 1;
}
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index 372b8ee8139..9f9af519f1c 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -42,6 +42,7 @@ Boston, MA 02111-1307, USA. */
#include "toplev.h"
#include "ggc.h"
#include "timevar.h"
+#include "cpphash.h"
#include "cpplib.h"
#include "target.h"
extern cpp_reader *parse_in;
@@ -429,6 +430,7 @@ lang_f_options[] =
{"short-double", &flag_short_double, 1},
{"short-wchar", &flag_short_wchar, 1},
{"asm", &flag_no_asm, 0},
+ {"auto-pch", &flag_auto_pch, 1},
{"builtin", &flag_no_builtin, 0},
/* C++-only options. */
@@ -562,6 +564,11 @@ cxx_decode_option (argc, argv)
flag_external_templates = 1;
cp_deprecated ("-fexternal-templates");
}
+ else if (!strcmp (p, "auto-pch"))
+ {
+ flag_auto_pch = 1;
+ CPP_OPTION (parse_in, gen_deps) = 1;
+ }
else if ((option_value
= skip_leading_substring (p, "template-depth-")))
max_tinst_depth
@@ -572,6 +579,12 @@ cxx_decode_option (argc, argv)
warning ("-fname-mangling-version is no longer supported");
return 1;
}
+ else if ((option_value
+ = skip_leading_substring (p, "output-pch=")))
+ {
+ pch_file = option_value;
+ CPP_OPTION (parse_in, gen_deps) = 1;
+ }
else if (dump_switch_p (p))
;
else
@@ -590,14 +603,14 @@ cxx_decode_option (argc, argv)
but breaks the VAX pcc. */
found = 1;
}
- if (p[0] == 'n' && p[1] == 'o' && p[2] == '-'
- && ! strcmp (p+3, lang_f_options[j].string))
+ else if (p[0] == 'n' && p[1] == 'o' && p[2] == '-'
+ && ! strcmp (p+3, lang_f_options[j].string))
{
*lang_f_options[j].variable = ! lang_f_options[j].on_value;
found = 1;
}
}
-
+
return found;
}
}
@@ -2181,7 +2194,7 @@ mark_vtable_entries (decl)
we know all the thunks we'll need when we emit a virtual
function, so we emit the thunks there instead. */
if (DECL_THUNK_P (fn))
- use_thunk (fn, /*emit_p=*/0);
+ use_thunk (fn, /*emit_p=*/0);
mark_used (fn);
}
}
@@ -2328,7 +2341,8 @@ import_export_vtable (decl, type, final)
functions in our class, or if we come from a template. */
int found = (CLASSTYPE_TEMPLATE_INSTANTIATION (type)
- || key_method (type));
+ || key_method (type));
+
if (final || ! found)
{
@@ -3358,6 +3372,9 @@ finish_file ()
int reconsider;
size_t i;
+ if (pch_file)
+ lang_write_pch ();
+
at_eof = 1;
/* Bad parse errors. Just forget about it. */
@@ -3389,6 +3406,8 @@ finish_file ()
timevar_push (TV_VARCONST);
+ process_interface_items ();
+
emit_support_tinfos ();
do
@@ -4852,6 +4871,7 @@ validate_nonmember_using_decl (decl, scope, name)
*scope = TREE_OPERAND (decl, 0);
*name = TREE_OPERAND (decl, 1);
+
if (!processing_template_decl)
{
/* [namespace.udecl]
@@ -5253,10 +5273,18 @@ handle_class_head (aggr, scope, id)
void
init_decl2 ()
{
- ggc_add_tree_varray_root (&deferred_fns, 1);
- ggc_add_tree_varray_root (&pending_statics, 1);
- ggc_add_tree_varray_root (&ssdf_decls, 1);
- ggc_add_tree_root (&ssdf_decl, 1);
- ggc_add_tree_root (&priority_decl, 1);
- ggc_add_tree_root (&initialize_p_decl, 1);
+ ggc_add_tree_varray_root (&deferred_fns, 1 , "deferred_fns" );
+ add_varray_tree_addresses (&data_to_save, &deferred_fns, 1 , "deferred_fns" );
+ ggc_add_tree_varray_root (&pending_statics, 1 , "pending_statics" );
+ add_varray_tree_addresses (&data_to_save, &pending_statics, 1 , "pending_statics" );
+ ggc_add_tree_varray_root (&ssdf_decls, 1 , "ssdf_decls" );
+ add_varray_tree_addresses (&data_to_save, &ssdf_decls, 1 , "ssdf_decls" );
+ ggc_add_tree_root (&ssdf_decl, 1 , "ssdf_decl" );
+ add_tree_addresses (&data_to_save, &ssdf_decl, 1 , "ssdf_decl" );
+ ggc_add_tree_root (&priority_decl, 1 , "priority_decl" );
+ add_tree_addresses (&data_to_save, &priority_decl, 1 , "priority_decl" );
+ ggc_add_tree_root (&initialize_p_decl, 1 , "initialize_p_decl" );
+ add_tree_addresses (&data_to_save, &initialize_p_decl, 1 , "initialize_p_decl" );
+
+
}
diff --git a/gcc/cp/g++spec.c b/gcc/cp/g++spec.c
index fbbe5990d0c..13ca2c6a44c 100644
--- a/gcc/cp/g++spec.c
+++ b/gcc/cp/g++spec.c
@@ -185,12 +185,22 @@ lang_specific_driver (in_argc, in_argv, in_added_libraries)
But not if a specified -x option is currently active. */
len = strlen (argv[i]);
if (len > 2
- && (argv[i][len - 1] == 'c' || argv[i][len - 1] == 'i')
+ && (argv[i][len - 1] == 'c'
+ || argv[i][len - 1] == 'i'
+ || argv[i][len - 1] == 'h')
&& argv[i][len - 2] == '.')
{
args[i] |= LANGSPEC;
added += 2;
- }
+
+ /* Compiling a header doesn't involve linking. */
+ if (library && argv[i][len - 1] == 'h')
+ {
+ library = 0;
+ added -= 2;
+
+ }
+ }
}
}
@@ -246,6 +256,8 @@ lang_specific_driver (in_argc, in_argv, in_added_libraries)
int len = strlen (argv[i]);
if (argv[i][len - 1] == 'i')
arglist[j++] = "-xc++-cpp-output";
+ else if (argv[i][len - 1] == 'h')
+ arglist[j++] = "-xc++-header";
else
arglist[j++] = "-xc++";
arglist[j++] = argv[i];
diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index 487543e6386..c0828dce033 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -73,7 +73,8 @@ void init_init_processing ()
finish_builtin_type (BI_header_type, "__new_cookie", fields,
0, double_type_node);
- ggc_add_tree_root (&BI_header_type, 1);
+ ggc_add_tree_root (&BI_header_type, 1, "BI_header_type");
+ add_tree_addresses (&data_to_save, &BI_header_type, 1, "BI_header_type");
}
/* We are about to generate some complex initialization code.
diff --git a/gcc/cp/lang-specs.h b/gcc/cp/lang-specs.h
index 67a3ecbe3e8..d54731203a9 100644
--- a/gcc/cp/lang-specs.h
+++ b/gcc/cp/lang-specs.h
@@ -32,6 +32,20 @@ Boston, MA 02111-1307, USA. */
{".cpp", "@c++", 0},
{".c++", "@c++", 0},
{".C", "@c++", 0},
+ {"@c++-header",
+ "%{E|M|MM:%(cpp0) -lang-c++ %{ansi:-trigraphs -$ -D__STRICT_ANSI__}\
+ %{!no-gcc:-D__GNUG__=%v1}\
+ %{fnew-abi:-D__GXX_ABI_VERSION=100}\
+ %{fembedded-cxx:-D__EMBEDDED_CXX__} \
+ %(cpp_options)} "
+ "%{!E:cc1plus -lang-c++ %{ansi:-trigraphs -$ -D__STRICT_ANSI__}\
+ %{!no-gcc:-D__GNUG__=%v1}\
+ %{fnew-abi:-D__GXX_ABI_VERSION=100}\
+ %{ansi:-trigraphs -$ -D__STRICT_ANSI__}\
+ %{fembedded-cxx:-D__EMBEDDED_CXX__} \
+ %(cpp_options) %(cc1_options)\
+ -o %g.s %{!o*:-foutput-pch=%i.pch} %W{^o*:-foutput-pch=%*}%V} "
+ },
{"@c++",
/* cc1plus has an integrated ISO C preprocessor. We should invoke
the external preprocessor if -save-temps is given. */
@@ -48,6 +62,14 @@ Boston, MA 02111-1307, USA. */
-D__GXX_ABI_VERSION=100\
%{ansi:-D__STRICT_ANSI__ -trigraphs -$}\
%(cpp_options) %b.ii \n}\
+ %{fauto-pch:%{!fsyntax-only:%{!save-temps: %{<fauto-pch} \
+ cc1plus -lang-c++\
+ %{!no-gcc:-D__GNUG__=%v1}\
+ %{fnew-abi:-D__GXX_ABI_VERSION=100}\
+ %{ansi:-trigraphs -$ -D__STRICT_ANSI__}\
+ %{fembedded-cxx:-D__EMBEDDED_CXX__} \
+ %(cpp_options) %(cc1_options) %{+e*} \
+ -fauto-pch %{!S:-o %g.s}\n}}}\
cc1plus %{save-temps:-fpreprocessed %b.ii}\
%{!save-temps:%(cpp_options)\
%{!no-gcc:-D__GNUG__=%v1} \
diff --git a/gcc/cp/lex.c b/gcc/cp/lex.c
index 6d8fcb36ad7..2f039d58271 100644
--- a/gcc/cp/lex.c
+++ b/gcc/cp/lex.c
@@ -52,6 +52,17 @@ Boston, MA 02111-1307, USA. */
extern void yyprint PARAMS ((FILE *, int, YYSTYPE));
static int interface_strcmp PARAMS ((const char *));
+static void cp_tree_prewrite_hook PARAMS ((const void *));
+static code_type cp_tree_code_fetcher PARAMS ((const void *));
+static size_t cp_lang_decl_size_fetcher PARAMS ((const void *,
+ type_definition_p));
+static int cp_lang_decl_more_fields PARAMS ((struct field_definition_s *fp,
+ const void *t_v,
+ unsigned n,
+ code_type c,
+ type_definition_p td));
+
+
static int *init_cpp_parse PARAMS ((void));
static void init_reswords PARAMS ((void));
static void init_cp_pragma PARAMS ((void));
@@ -85,6 +96,12 @@ static void init_operators PARAMS ((void));
#include "cpplib.h"
+
+/* Pending language change.
+ Positive is push count, negative is pop count. */
+int pending_lang_change = 0;
+
+
extern int yychar; /* the lookahead symbol */
extern YYSTYPE yylval; /* the semantic value of the */
/* lookahead symbol */
@@ -103,6 +120,7 @@ tree lastiddecl;
/* Array for holding counts of the numbers of tokens seen. */
extern int *token_count;
+
/* Functions and data structures for #pragma interface.
`#pragma implementation' means that the main file being compiled
@@ -275,13 +293,195 @@ cxx_init_options ()
diagnostic_prefixing_rule (global_dc) = DIAGNOSTICS_SHOW_PREFIX_ONCE;
}
+static code_type
+cp_tree_code_fetcher (t_v)
+ const void *t_v;
+{
+ tree t = (tree)t_v;
+ enum tree_code code = TREE_CODE (t);
+
+ code_type r = code << 8 | TREE_CODE_CLASS (code);
+
+ if (code == POINTER_TYPE)
+#if 0
+ && TREE_CODE (TREE_TYPE (t)) == METHOD_TYPE)
+#endif
+ r |= 0x20000;
+ if (code == CPLUS_BINDING
+ && BINDING_HAS_LEVEL_P (t))
+ r |= 0x10000;
+ return r;
+}
+
+/* A function to be called for each tree node before they are written out by
+ the precompiled headers mechanism. Currently we use this to note that
+ the fields and methods are not sorted, as PCH fails to preserve address
+ order for identifiers. */
+
+static void
+cp_tree_prewrite_hook (t_v)
+ const void *t_v;
+{
+ tree t = (tree)t_v;
+ if (TREE_CODE (t) == TYPE_DECL && DECL_LANG_SPECIFIC (t))
+ DECL_SORTED_FIELDS (t) = NULL_TREE;
+ else if (CLASS_TYPE_P (t) && CLASSTYPE_METHOD_VEC (t))
+ CLASSTYPE_METHOD_VEC_SORTED_P (t) = 0;
+}
+
+static const struct field_definition_s cp_tree_field_defs[] = {
+ { 't', 0x200FF, offsetof (union tree_node, type.lang_specific),
+ lang_type_type_def },
+ /* In the case of pointer-to-member function types, the
+ TYPE_LANG_SPECIFIC is really just a tree. */
+ { 't' | 0x20000, 0x200FF, offsetof (union tree_node, type.lang_specific),
+ tree_type_def },
+ { IDENTIFIER_NODE << 8, 0xFF00,
+ offsetof (struct lang_identifier, namespace_bindings), tree_type_def },
+ { IDENTIFIER_NODE << 8, 0xFF00,
+ offsetof (struct lang_identifier, bindings), tree_type_def },
+ { IDENTIFIER_NODE << 8, 0xFF00,
+ offsetof (struct lang_identifier, class_value), tree_type_def },
+ { IDENTIFIER_NODE << 8, 0xFF00,
+ offsetof (struct lang_identifier, class_template_info), tree_type_def },
+ { IDENTIFIER_NODE << 8, 0xFF00,
+ offsetof (struct lang_identifier, x), cp_lang_id2_type_def },
+ { CPLUS_BINDING << 8 | 0x10000, 0x1FF00,
+ offsetof (struct tree_binding, scope.level), cp_binding_level_type_def },
+ { CPLUS_BINDING << 8 | 0x00000, 0x1FF00,
+ offsetof (struct tree_binding, scope.scope), tree_type_def },
+ { CPLUS_BINDING << 8, 0xFF00,
+ offsetof (struct tree_binding, value), tree_type_def },
+ { OVERLOAD << 8, 0xFF00,
+ offsetof (struct tree_overload, function), tree_type_def },
+ { TEMPLATE_PARM_INDEX << 8, 0xFF00,
+ offsetof (template_parm_index, decl), tree_type_def },
+
+ NO_MORE_FIELDS
+};
+
+static size_t
+cp_lang_decl_size_fetcher (v, td)
+ const void *v;
+ type_definition_p td ATTRIBUTE_UNUSED;
+{
+ tree t = (tree)v;
+ if (CAN_HAVE_FULL_LANG_DECL_P (t))
+ return sizeof (struct lang_decl);
+ else
+ return sizeof (struct lang_decl_flags);
+}
+
+static int
+cp_lang_decl_more_fields (fp, t_v, n, c, td)
+ struct field_definition_s *fp;
+ const void *t_v;
+ unsigned n;
+ code_type c ATTRIBUTE_UNUSED;
+ type_definition_p td ATTRIBUTE_UNUSED;
+{
+ tree t = (tree)t_v;
+ fp->type = tree_type_def;
+ switch (n)
+ {
+ case 0:
+ fp->offset = offsetof (struct lang_decl, decl_flags.base.saved_tree);
+ return 1;
+ case 1:
+ if (TREE_CODE (t) == NAMESPACE_DECL)
+ fp->type = cp_binding_level_type_def;
+ fp->offset = offsetof (struct lang_decl, decl_flags.u);
+ return 1;
+ case 2:
+ if (! DECL_THUNK_P (t)
+ && (DECL_GLOBAL_CTOR_P (t) || DECL_GLOBAL_DTOR_P (t)))
+ fp->type = NULL;
+ fp->offset = offsetof (struct lang_decl, decl_flags.u2);
+ return 1;
+ case 3:
+ if (! CAN_HAVE_FULL_LANG_DECL_P (t))
+ return 0;
+
+ fp->offset = offsetof (struct lang_decl, befriending_classes);
+ return 1;
+ case 4:
+ fp->offset = offsetof (struct lang_decl, context);
+ return 1;
+ case 5:
+ fp->offset = offsetof (struct lang_decl, cloned_function);
+ return 1;
+ case 6:
+ if (TREE_CODE (t) == FUNCTION_DECL
+ && ! DECL_PENDING_INLINE_P (t))
+ fp->type = lang_function_type_def;
+ else if (TREE_CODE (t) != TYPE_DECL)
+ fp->type = NULL;
+ fp->offset = offsetof (struct lang_decl, u);
+ return 1;
+ case 7:
+ if (DECL_OVERLOADED_OPERATOR_P (t))
+ fp->type = NULL;
+ fp->offset = offsetof (struct lang_decl, u2.operator_code);
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+static const struct subobject_definition_s cp_tree_subobjects[] = {
+ {
+ 'd',
+ 0xFF,
+ offsetof (union tree_node, decl.lang_specific),
+ cp_lang_decl_size_fetcher,
+ cp_lang_decl_more_fields
+ },
+ NO_MORE_SUBOBJECTS
+};
+
+static const struct field_definition_s cp_lang_id2_field_defs[] = {
+ { 0, 0, offsetof (struct lang_id2, label_value), tree_type_def },
+ { 0, 0, offsetof (struct lang_id2, implicit_decl), tree_type_def },
+ { 0, 0, offsetof (struct lang_id2, error_locus), tree_type_def },
+ NO_MORE_FIELDS
+};
+
+static const struct field_definition_s cp_lang_type_field_defs[] = {
+ { 0, 0, offsetof (struct lang_type, primary_base), tree_type_def },
+ { 0, 0, offsetof (struct lang_type, vfields), tree_type_def },
+ { 0, 0, offsetof (struct lang_type, vbases), tree_type_def },
+ { 0, 0, offsetof (struct lang_type, tags), tree_type_def },
+ { 0, 0, offsetof (struct lang_type, size), tree_type_def },
+ { 0, 0, offsetof (struct lang_type, size_unit), tree_type_def },
+ { 0, 0, offsetof (struct lang_type, pure_virtuals), tree_type_def },
+ { 0, 0, offsetof (struct lang_type, friend_classes), tree_type_def },
+ { 0, 0, offsetof (struct lang_type, rtti), tree_type_def },
+ { 0, 0, offsetof (struct lang_type, methods), tree_type_def },
+ { 0, 0, offsetof (struct lang_type, template_info), tree_type_def },
+ { 0, 0, offsetof (struct lang_type, befriending_classes), tree_type_def },
+ NO_MORE_FIELDS
+};
+
+
+
static void
cxx_init ()
{
c_common_lang_init ();
+ add_tree_fields (cp_tree_field_defs);
+ tree_type_def->code_fetcher = cp_tree_code_fetcher;
+ tree_type_def->subobject_definitions = cp_tree_subobjects;
+ tree_type_def->prewrite_hook = cp_tree_prewrite_hook;
+ lang_type_type_def->size = sizeof (struct lang_type);
+ lang_type_type_def->field_definitions = cp_lang_type_field_defs;
+ lang_function_type_def->size = sizeof (struct cp_language_function);
+ cp_lang_id2_type_def->size = sizeof (struct lang_id2);
+ cp_lang_id2_type_def->field_definitions = cp_lang_id2_field_defs;
+
if (flag_gnu_xref) GNU_xref_begin (input_filename);
init_repo (input_filename);
+ pch_init();
}
static void
@@ -296,6 +496,27 @@ lang_identify ()
return "cplusplus";
}
+void
+lang_write_pch ()
+{
+ invalidate_class_lookup_cache ();
+ c_write_pch ();
+}
+
+/* Returns nonzero if we are not nested inside any incomplete scopes.
+ Used by the PCH machinery. */
+
+int
+lang_toplevel_p ()
+{
+ if (! global_bindings_p ())
+ return 0;
+ if (current_lang_depth () != 0)
+ return 0;
+ return 1;
+}
+
+
static int *
init_cpp_parse ()
{
@@ -710,6 +931,7 @@ init_parse (filename)
init_tree ();
init_cplus_expand ();
init_cp_semantics ();
+ init_linkage ();
add_c_tree_codes ();
@@ -940,6 +1162,7 @@ set_yydebug (value)
/* Helper function to load global variables with interface
information. */
+
void
extract_interface_info ()
{
@@ -965,7 +1188,7 @@ extract_interface_info ()
/* Return nonzero if S is not considered part of an
INTERFACE/IMPLEMENTATION pair. Otherwise, return 0. */
-static int
+int
interface_strcmp (s)
const char *s;
{
diff --git a/gcc/cp/linkage.c b/gcc/cp/linkage.c
new file mode 100644
index 00000000000..21960dd81b3
--- /dev/null
+++ b/gcc/cp/linkage.c
@@ -0,0 +1,341 @@
+/* Code for handling linkage of vtables, inlines et al in GNU C++.
+ Copyright (C) 2001 Free Software Foundation, Inc.
+ Hacked by Jason Merrill (jason@redhat.com)
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#include "config.h"
+#include "system.h"
+#include "tree.h"
+#include "cp-tree.h"
+#include "ggc.h"
+#include "flags.h"
+#include "toplev.h"
+
+#include "splay-tree.h"
+#include "varray.h"
+
+/* Functions and data structures for #pragma interface.
+
+ `#pragma implementation' means that the main file being compiled
+ is considered to implement (provide) the classes that appear in
+ its main body. I.e., if this is file "foo.cc", and class `bar'
+ is defined in "foo.cc", then we say that "foo.cc implements bar".
+
+ All main input files "implement" themselves automagically.
+
+ `#pragma interface' means that unless this file (of the form "foo.h"
+ is presently being included by file "foo.cc", the FIXME FIXME
+ CLASSTYPE_INTERFACE_ONLY bit gets set. The effect is that none
+ of the vtables nor any of the inline functions defined in foo.h
+ will ever be output.
+
+ There are cases when we want to link files such as "defs.h" and
+ "main.cc". In this case, we give "defs.h" a `#pragma interface',
+ and "main.cc" has `#pragma implementation "defs.h"'. */
+
+struct cp_fileinfo
+{
+ varray_type items;
+ int implemented;
+};
+static splay_tree cp_fileinfo_tree;
+
+/* The list of entities with vague linkage in the current file, if we've
+ seen #pragma interface. */
+
+varray_type *interface_itemsptr;
+
+static varray_type impl_files;
+
+static int interface_strcmp PARAMS ((const char *, const char *));
+
+/* Helper function to load global variables with interface
+ information. */
+
+#if 0
+void
+extract_interface_info ()
+{
+ struct c_fileinfo *finfo = 0;
+ struct cp_fileinfo *ifile = 0;
+
+ if (flag_alt_external_templates)
+ {
+ tree til = tinst_for_decl ();
+
+ if (til)
+ finfo = get_fileinfo (TINST_FILE (til));
+ }
+ if (!finfo)
+ finfo = get_fileinfo (input_filename);
+
+ ifile = (struct cp_fileinfo *) (finfo->lang_data);
+
+ interface_unknown = 1;
+ if (ifile)
+ {
+ interface_itemsptr = &(ifile->items);
+ interface_only = 1;
+ }
+ else
+ {
+ interface_itemsptr = NULL;
+ interface_only = 0;
+ }
+
+ /* This happens to be a convenient place to put this. */
+ if (flag_gnu_xref) GNU_xref_file (input_filename);
+}
+#endif
+
+/* Return zero if S and T work as an INTERFACE/IMPLEMENTATION pair.
+ Basically, this is a strcmp ignoring the file extension, so that foo.C and
+ foo.h will match.
+
+ Otherwise, return as strcmp. */
+
+static int
+interface_strcmp (s1, t1)
+ const char *s1;
+ const char *t1;
+{
+ while (*s1 == *t1 && *s1 != 0)
+ s1++, t1++;
+
+ /* A match. */
+ if (*s1 == *t1)
+ return 0;
+
+ /* Don't get faked out by xxx.yyy.cc vs xxx.zzz.cc. */
+ if (strchr (s1, '.') || strchr (t1, '.'))
+ return *s1 - *t1;
+
+ if (*s1 == '\0' || s1[-1] != '.' || t1[-1] != '.')
+ return *s1 - *t1;
+
+ /* A match. */
+ return 0;
+}
+
+static struct cp_fileinfo *
+maybe_get_cp_fileinfo (name)
+ const char *name;
+{
+ splay_tree_node n;
+
+ n = splay_tree_lookup (cp_fileinfo_tree, (splay_tree_key) name);
+ if (n)
+ return (struct cp_fileinfo *) n->value;
+ return NULL;
+}
+
+static struct cp_fileinfo *
+insert_cp_fileinfo (name)
+ const char *name;
+{
+ struct cp_fileinfo *fi
+ = (struct cp_fileinfo *) xcalloc (1, sizeof (struct cp_fileinfo));
+ VARRAY_TREE_INIT (fi->items, 5, "interface items");
+ splay_tree_insert (cp_fileinfo_tree, (splay_tree_key) name,
+ (splay_tree_value) fi);
+ return fi;
+}
+
+void
+do_pragma_interface (fname)
+ tree fname;
+{
+ struct c_fileinfo *finfo;
+ struct cp_fileinfo *cp_finfo;
+ const char *main_filename;
+
+ if (fname == 0)
+ main_filename = file_name_nondirectory (input_filename);
+ else
+ main_filename = TREE_STRING_POINTER (fname);
+
+ finfo = get_fileinfo (input_filename);
+
+ cp_finfo = maybe_get_cp_fileinfo (ggc_strdup (main_filename));
+ if (cp_finfo)
+ warning ("duplicate #pragma interface for %s", main_filename);
+ else
+ cp_finfo = insert_cp_fileinfo (main_filename);
+
+ finfo->lang_data = cp_finfo;
+
+ extract_interface_info ();
+}
+
+/* Note that we have seen a #pragma implementation for the key MAIN_FILENAME.
+ We used to only allow this at toplevel, but that restriction was buggy
+ in older compilers and it seems reasonable to allow it in the headers
+ themselves, too. */
+
+void
+do_pragma_implementation (fname)
+ tree fname;
+{
+ const char *main_filename;
+
+ if (fname == 0)
+ main_filename = file_name_nondirectory (main_input_filename);
+ else
+ main_filename = TREE_STRING_POINTER (fname);
+
+ VARRAY_PUSH_CHAR_PTR (impl_files, ggc_strdup (main_filename));
+}
+
+void
+maybe_add_interface_item (item)
+ tree item;
+{
+ if (interface_itemsptr)
+ VARRAY_PUSH_TREE (*interface_itemsptr, item);
+}
+
+static int
+foreach_process_interface (node, data)
+ splay_tree_node node;
+ void *data ATTRIBUTE_UNUSED;
+{
+ struct cp_fileinfo *cp_finfo = (struct cp_fileinfo *) node->value;
+ varray_type items = cp_finfo->items;
+ int impl = cp_finfo->implemented;
+ unsigned i;
+
+ for (i = 0; i < VARRAY_ACTIVE_SIZE (items); ++i)
+ {
+ tree item = VARRAY_TREE (items, i);
+ if (TYPE_P (item))
+ {
+ SET_CLASSTYPE_INTERFACE_KNOWN (item);
+ CLASSTYPE_INTERFACE_ONLY (item) = !impl;
+#if 0
+ CLASSTYPE_VTABLE_NEEDS_WRITING (item) = impl;
+#endif
+ TYPE_DECL_SUPPRESS_DEBUG (TYPE_NAME (item)) = !impl;
+ if (impl && !uses_template_parms (item))
+ {
+ CLASSTYPE_DEBUG_REQUESTED (item) = 1;
+ rest_of_type_compilation (item, 1);
+ }
+ if (flag_external_templates && !flag_alt_external_templates
+ && uses_template_parms (item))
+ {
+ tree s
+ = DECL_TEMPLATE_INSTANTIATIONS (CLASSTYPE_TI_TEMPLATE (item));
+ for (; s; s = TREE_CHAIN (s))
+ {
+ tree t = TREE_VALUE (s);
+ SET_CLASSTYPE_INTERFACE_KNOWN (t);
+ CLASSTYPE_INTERFACE_ONLY (t) = !impl;
+#if 0
+ CLASSTYPE_VTABLE_NEEDS_WRITING (t) = impl;
+#endif
+ TYPE_DECL_SUPPRESS_DEBUG (TYPE_NAME (t)) = !impl;
+ if (impl && !uses_template_parms (t))
+ {
+ CLASSTYPE_DEBUG_REQUESTED (t) = 1;
+ rest_of_type_compilation (t, 1);
+ }
+ }
+ }
+ }
+ else
+ {
+ DECL_INTERFACE_KNOWN (item) = 1;
+ if (DECL_LANG_SPECIFIC (item))
+ DECL_NOT_REALLY_EXTERN (item) = impl;
+ else
+ DECL_EXTERNAL (item) = !impl;
+ if (flag_external_templates && !flag_alt_external_templates
+ && uses_template_parms (item))
+ {
+ tree s = DECL_TEMPLATE_SPECIALIZATIONS (DECL_TI_TEMPLATE (item));
+ for (; s; s = TREE_CHAIN (s))
+ {
+ tree d = TREE_VALUE (s);
+ DECL_INTERFACE_KNOWN (d) = 1;
+ DECL_NOT_REALLY_EXTERN (d) = impl;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+void
+process_interface_items ()
+{
+ unsigned int i;
+ for (i = 0; i < VARRAY_ACTIVE_SIZE (impl_files); ++i)
+ {
+ char *file = VARRAY_CHAR_PTR (impl_files, i);
+ struct cp_fileinfo *cp_finfo = maybe_get_cp_fileinfo (file);
+ if (! cp_finfo)
+ warning ("\
+#pragma implementation for %s does not match any #pragma interface",
+ file);
+ else
+ {
+ if (cp_finfo->implemented)
+ warning ("duplicate #pragma implementation for %s", file);
+ cp_finfo->implemented = 1;
+ }
+ }
+ splay_tree_foreach (cp_fileinfo_tree, foreach_process_interface, NULL);
+}
+
+/* Type layout information for cp_fileinfo_tree for the gtype machinery. */
+
+static const struct field_definition_s cpf_tree_node_field_defs[] = {
+ { 0, 0, offsetof (struct splay_tree_node_s, key), string_type_def },
+ { 0, 0, offsetof (struct splay_tree_node_s, value), cp_fileinfo_type_def },
+ { 0, 0, offsetof (struct splay_tree_node_s, left), cpf_tree_node_type_def },
+ { 0, 0, offsetof (struct splay_tree_node_s, right), cpf_tree_node_type_def },
+ NO_MORE_FIELDS
+};
+static const struct field_definition_s cp_fileinfo_field_defs[] = {
+ { 0, 0, offsetof (struct cp_fileinfo, items), varray_tree_type_def },
+ NO_MORE_FIELDS
+};
+
+void
+init_linkage ()
+{
+ cpf_tree_node_type_def->size = sizeof (struct splay_tree_node_s);
+ cpf_tree_node_type_def->field_definitions = cpf_tree_node_field_defs;
+ cpf_tree_node_type_def->ggc_p = -1;
+ cp_fileinfo_type_def->size = sizeof (struct cp_fileinfo);
+ cp_fileinfo_type_def->field_definitions = cp_fileinfo_field_defs;
+ cp_fileinfo_type_def->ggc_p = -1;
+
+ cp_fileinfo_tree = splay_tree_new ((splay_tree_compare_fn)interface_strcmp,
+ 0,
+ (splay_tree_delete_value_fn)free);
+
+ ggc_add_typed_root (&cp_fileinfo_tree->root, cpf_tree_node_type_def, 1, "cp_fileinfo_tree->root");
+ add_typed_addresses (&data_to_save, (void **)&cp_fileinfo_tree->root,
+ cpf_tree_node_type_def, 1, "cp_fileinfo_tree->root");
+
+ /* Not saved in PCH. */
+ VARRAY_CHAR_PTR_INIT (impl_files, 1, "impl_files");
+ ggc_add_string_varray_root (&impl_files, 1, "impl_files");
+}
diff --git a/gcc/cp/parse.y b/gcc/cp/parse.y
index 9801c3817fa..2735fc9870e 100644
--- a/gcc/cp/parse.y
+++ b/gcc/cp/parse.y
@@ -209,10 +209,10 @@ parse_method (declarator, specs_attrs, lookups)
void
cp_parse_init ()
{
- ggc_add_tree_root (&current_declspecs, 1);
- ggc_add_tree_root (&prefix_attributes, 1);
- ggc_add_tree_root (&current_enum_type, 1);
- ggc_add_tree_root (&saved_scopes, 1);
+ ggc_add_tree_root (&current_declspecs, 1, "current_declspecs");
+ ggc_add_tree_root (&prefix_attributes, 1, "prefix_attributes");
+ ggc_add_tree_root (&current_enum_type, 1, "current_enum_type");
+ ggc_add_tree_root (&saved_scopes, 1, "saved_scopes");
}
/* Rename the "yyparse" function so that we can override it elsewhere. */
@@ -736,6 +736,8 @@ datadef:
}
| error ';'
| error '}'
+ | error END_OF_SAVED_INPUT
+ { end_input (); }
| ';'
| bad_decl
;
diff --git a/gcc/cp/pch.c b/gcc/cp/pch.c
new file mode 100644
index 00000000000..15f2f192326
--- /dev/null
+++ b/gcc/cp/pch.c
@@ -0,0 +1,56 @@
+/* Precompiled header implementation for C++
+ Copyright (C) 2000 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#include "config.h"
+#include "system.h"
+#include "intl.h"
+#include "tree.h"
+#include "rtl.h"
+#include "flags.h"
+#include "function.h"
+#include "expr.h"
+#include "toplev.h"
+#include "cpplib.h"
+#include "defaults.h"
+#include "ggc.h"
+#include "tm_p.h"
+
+void
+lang_write_pch (name)
+ const char *name;
+{
+}
+
+int
+lang_valid_pch (pfile, name, fd)
+ cpp_reader *pfile ATTRIBUTE_UNUSED;
+ const char *name;
+ int fd;
+{
+ return 2;
+}
+
+void
+lang_read_pch (pfile, fd)
+ cpp_reader *pfile;
+ int fd;
+{
+ abort ();
+}
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 292513fb43e..9b3fbdac629 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -172,9 +172,12 @@ static int invalid_nontype_parm_type_p PARAMS ((tree, int));
void
init_pt ()
{
- ggc_add_tree_root (&pending_templates, 1);
- ggc_add_tree_root (&saved_trees, 1);
- ggc_add_tree_root (&current_tinst_level, 1);
+ ggc_add_tree_root (&pending_templates, 1 , "pending_templates" );
+ add_tree_addresses (&data_to_save, &pending_templates, 1 , "pending_templates" );
+ add_tree_addresses (&data_to_save, &last_pending_template, 1 , "last_pending_template" );
+ ggc_add_tree_root (&saved_trees, 1 , "saved_trees" );
+ add_tree_addresses (&data_to_save, &saved_trees, 1 , "saved_trees" );
+ ggc_add_tree_root (&current_tinst_level, 1 , "current_tinst_level" );
}
/* Do any processing required when DECL (a member template declaration
diff --git a/gcc/cp/repo.c b/gcc/cp/repo.c
index 796add92952..d03581be013 100644
--- a/gcc/cp/repo.c
+++ b/gcc/cp/repo.c
@@ -320,8 +320,10 @@ init_repo (filename)
if (! flag_use_repository)
return;
- ggc_add_tree_root (&pending_repo, 1);
- ggc_add_tree_root (&original_repo, 1);
+ ggc_add_tree_root (&pending_repo, 1, "pending_repo" );
+ add_tree_addresses (&data_to_save, &pending_repo, 1, "pending_repo" );
+ ggc_add_tree_root (&original_repo, 1, "original_repo" );
+ add_tree_addresses (&data_to_save, &original_repo, 1, "original_repo" );
gcc_obstack_init (&temporary_obstack);
open_repo_file (filename);
diff --git a/gcc/cp/spew.c b/gcc/cp/spew.c
index 64cf48dd160..b44b185881f 100644
--- a/gcc/cp/spew.c
+++ b/gcc/cp/spew.c
@@ -113,7 +113,6 @@ static SPEW_INLINE void consume_token PARAMS ((void));
static SPEW_INLINE int read_process_identifier PARAMS ((YYSTYPE *));
static SPEW_INLINE void feed_input PARAMS ((struct unparsed_text *));
-static SPEW_INLINE void end_input PARAMS ((void));
static SPEW_INLINE void snarf_block PARAMS ((const char *, int));
static tree snarf_defarg PARAMS ((void));
static int frob_id PARAMS ((int, int, tree *));
@@ -183,15 +182,19 @@ init_spew ()
inline_text_firstobj = (char *) obstack_alloc (&inline_text_obstack, 0);
gcc_obstack_init (&token_obstack);
gcc_obstack_init (&feed_obstack);
- ggc_add_tree_root (&defarg_fns, 1);
- ggc_add_tree_root (&defarg_parm, 1);
- ggc_add_tree_root (&defarg_depfns, 1);
- ggc_add_tree_root (&defarg_fnsdone, 1);
+ ggc_add_tree_root (&defarg_fns, 1 , "defarg_fns" );
+ add_tree_addresses (&data_to_save, &defarg_fns, 1 , "defarg_fns" );
+ ggc_add_tree_root (&defarg_parm, 1 , "defarg_parm" );
+ add_tree_addresses (&data_to_save, &defarg_parm, 1 , "defarg_parm" );
+ ggc_add_tree_root (&defarg_depfns, 1 , "defarg_depfns" );
+ add_tree_addresses (&data_to_save, &defarg_depfns, 1 , "defarg_depfns" );
+ ggc_add_tree_root (&defarg_fnsdone, 1 , "defarg_fnsdone" );
+ add_tree_addresses (&data_to_save, &defarg_fnsdone, 1 , "defarg_fnsdone" );
ggc_add_root (&pending_inlines, 1, sizeof (struct unparsed_text *),
- mark_pending_inlines);
+ mark_pending_inlines , "pending_inlines" );
ggc_add_root (&processing_these_inlines, 1, sizeof (struct unparsed_text *),
- mark_pending_inlines);
+ mark_pending_inlines , "processing_these_inlines" );
}
void
@@ -358,7 +361,7 @@ read_token (t)
return t->yychar;
}
-static SPEW_INLINE void
+static void
feed_input (input)
struct unparsed_text *input;
{
@@ -397,7 +400,7 @@ feed_input (input)
feed = f;
}
-static SPEW_INLINE void
+void
end_input ()
{
struct feed *f = feed;
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index 32783adc728..8a2537412a5 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -2356,7 +2356,7 @@ init_tree ()
list_hash_table = htab_create (31, list_hash, list_hash_eq, NULL);
ggc_add_root (&list_hash_table, 1,
sizeof (list_hash_table),
- mark_tree_hashtable);
+ mark_tree_hashtable, "list_hash_table");
}
/* The SAVE_EXPR pointed to by TP is being copied. If ST contains
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 54dc0ed3df5..c57bb08ab3e 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -3035,8 +3035,8 @@ build_function_call_real (function, params, require_complete, flags)
/* Check for errors in format strings. */
- if (warn_format && (name || assembler_name))
- check_function_format (NULL, name, assembler_name, coerced_params);
+ if (warn_format)
+ check_function_format (NULL, TYPE_ATTRIBUTES (fntype), coerced_params);
/* Recognize certain built-in functions so we can make tree-codes
other than CALL_EXPR. We do this when it enables fold-const.c
diff --git a/gcc/cppfiles.c b/gcc/cppfiles.c
index 5b8f9076b39..9469caaa60f 100644
--- a/gcc/cppfiles.c
+++ b/gcc/cppfiles.c
@@ -60,6 +60,7 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
struct include_file
{
const char *name; /* actual path name of file */
+ const char *nominal_fname; /* name of the original source file */
const cpp_hashnode *cmacro; /* macro, if any, preventing reinclusion. */
const struct search_path *foundhere;
/* location in search path where file was
@@ -71,6 +72,14 @@ struct include_file
unsigned short include_count; /* number of times file has been read */
unsigned short refcnt; /* number of stacked buffers using this file */
unsigned char mapped; /* file buffer is mmapped */
+ unsigned char pch; /* 0: file not known to be a PCH.
+ 1: file is a PCH
+ (on return from find_include_file).
+ 2: file is not and never will be a valid
+ precompiled header.
+ 3: file is always a valid precompiled
+ header. */
+
};
/* The cmacro works like this: If it's NULL, the file is to be
@@ -81,6 +90,7 @@ struct include_file
#define DO_NOT_REREAD(inc) \
((inc)->cmacro && ((inc)->cmacro == NEVER_REREAD \
|| (inc)->cmacro->type == NT_MACRO))
+#define INCLUDE_PCH_P(i) (((i)->pch & 1) != 0)
#define NO_INCLUDE_PATH ((struct include_file *) -1)
static struct file_name_map *read_name_map
@@ -94,6 +104,8 @@ static struct include_file *
find_include_file PARAMS ((cpp_reader *, const cpp_token *,
enum include_type));
static struct include_file *open_file PARAMS ((cpp_reader *, const char *));
+static struct include_file *open_file_pch PARAMS ((cpp_reader *,
+ const char *));
static int read_include_file PARAMS ((cpp_reader *, struct include_file *));
static bool stack_include_file PARAMS ((cpp_reader *, struct include_file *));
static void purge_cache PARAMS ((struct include_file *));
@@ -176,6 +188,7 @@ find_or_create_entry (pfile, fname)
{
file = xcnew (struct include_file);
file->name = name;
+ file->nominal_fname = file->name;
file->err_no = errno;
node = splay_tree_insert (pfile->all_include_files,
(splay_tree_key) file->name,
@@ -244,7 +257,7 @@ open_file (pfile, filename)
if (filename[0] == '\0')
file->fd = 0;
else
- file->fd = open (file->name, O_RDONLY | O_NOCTTY | O_BINARY, 0666);
+ file->fd = open (filename, O_RDONLY | O_NOCTTY | O_BINARY, 0666);
if (file->fd != -1 && fstat (file->fd, &file->st) == 0)
{
@@ -275,16 +288,53 @@ open_file (pfile, filename)
return 0;
}
+
+/* Like open_file, but also look for a precompiled header if (a) one exists
+ and (b) it is valid. */
+static struct include_file *
+open_file_pch (pfile, filename)
+ cpp_reader *pfile;
+ const char *filename;
+{
+ if (filename[0] != '\0'
+ && pfile->cb.valid_pch != NULL)
+ {
+ size_t namelen = strlen (filename);
+ char *pchname = alloca (namelen + 5);
+ struct include_file * file;
+
+ memcpy (pchname, filename, namelen);
+ memcpy (pchname + namelen, ".pch", 5);
+ file = open_file (pfile, pchname);
+ if (file != NULL)
+ {
+ file->nominal_fname = xstrdup (filename);
+ if ((file->pch & 2) == 0)
+ file->pch = pfile->cb.valid_pch (pfile, pchname, file->fd);
+ if (INCLUDE_PCH_P (file))
+ return file;
+ close (file->fd);
+ file->fd = -1;
+ }
+ }
+ return open_file (pfile, filename);
+}
/* Place the file referenced by INC into a new buffer on the buffer
stack, unless there are errors, or the file is not re-included
because of e.g. multiple-include guards. Returns true if a buffer
is stacked. */
+
+/* Place the file referenced by INC into a new buffer on PFILE's
+ stack. If there are errors, or the file should not be re-included,
+ a null (zero-length) buffer is pushed. */
+
static bool
stack_include_file (pfile, inc)
cpp_reader *pfile;
struct include_file *inc;
{
+ size_t len = 0;
cpp_buffer *fp;
int sysp;
const char *filename;
@@ -302,25 +352,63 @@ stack_include_file (pfile, inc)
/* Not in cache? */
if (! inc->buffer)
{
- /* If an error occurs, do not try to read this file again. */
- if (read_include_file (pfile, inc))
+
+ /* PCH files get dealt with immediately.
+ We stack a zero-sized buffer below.
+ The reason for this is that reading a PCH directly into memory
+ will approximately double the memory consumption of the compiler. */
+ if (INCLUDE_PCH_P (inc))
+ {
+ pfile->cb.read_pch (pfile, inc->fd, inc->nominal_fname);
+ close (inc->fd);
+ inc->fd = -1;
+
+#if 0
+ fp = cpp_push_buffer (pfile, (unsigned char *)"", 0, 0, inc->nominal_fname);
+#else
+ fp = cpp_push_buffer (pfile, (unsigned char *)"", 0, 0, 0);
+#endif
+ fp->rlimit = fp->buf;
+ }
+ else
+ {
+ /* If an error occurs, do not try to read this file again. */
+ if (read_include_file (pfile, inc))
+ _cpp_never_reread (inc);
+ close (inc->fd);
+ inc->fd = -1;
+ }
+ }
+
+
+ if (pfile->buffer)
+ {
+ /* We don't want MI guard advice for the main file. */
+ inc->include_count++;
+
+ /* Handle -H option. */
+ if (CPP_OPTION (pfile, print_include_names))
{
- _cpp_never_reread (inc);
- return false;
+ for (fp = pfile->buffer; fp; fp = fp->prev)
+ putc ('.', stderr);
+ fprintf (stderr, " %s\n", inc->name);
}
- close (inc->fd);
- inc->fd = -1;
}
+ if (! INCLUDE_PCH_P (inc))
+ {
+ len = inc->st.st_size;
+ /* Push a buffer. */
+ /* Push a buffer. */
+ fp = cpp_push_buffer (pfile, inc->buffer, inc->st.st_size,
+ /* from_stage3 */ CPP_OPTION (pfile, preprocessed), 0);
+ fp->inc = inc;
+ fp->inc->refcnt++;
+ }
if (pfile->buffer)
/* We don't want MI guard advice for the main file. */
inc->include_count++;
- /* Push a buffer. */
- fp = cpp_push_buffer (pfile, inc->buffer, inc->st.st_size,
- /* from_stage3 */ CPP_OPTION (pfile, preprocessed), 0);
- fp->inc = inc;
- fp->inc->refcnt++;
/* Initialise controlling macro state. */
pfile->mi_valid = true;
@@ -517,7 +605,7 @@ find_include_file (pfile, header, type)
char *name, *n;
if (IS_ABSOLUTE_PATHNAME (fname))
- return open_file (pfile, fname);
+ return open_file_pch (pfile, fname);
/* For #include_next, skip in the search path past the dir in which
the current file was found, but if it was found via an absolute
@@ -547,7 +635,7 @@ find_include_file (pfile, header, type)
else
n = name;
- file = open_file (pfile, n);
+ file = open_file_pch (pfile, n);
if (file)
{
file->foundhere = path;
@@ -558,6 +646,7 @@ find_include_file (pfile, header, type)
return 0;
}
+
/* Not everyone who wants to set system-header-ness on a buffer can
see the details of a buffer. This is an exported interface because
fix-header needs it. */
@@ -653,6 +742,8 @@ handle_missing_header (pfile, fname, angle_brackets)
cpp_error_from_errno (pfile, fname);
}
+#define PRINT_THIS_DEP(p, b) (CPP_PRINT_DEPS(p) > (b||p->system_include_depth))
+
/* Handles #include-family directives, and the command line -imacros
and -include. Returns true if a buffer was stacked. */
bool
@@ -664,6 +755,7 @@ _cpp_execute_include (pfile, header, type)
bool stacked = false;
struct include_file *inc = find_include_file (pfile, header, type);
+
if (inc == 0)
handle_missing_header (pfile, (const char *) header->val.str.text,
header->type == CPP_HEADER_NAME);
@@ -709,7 +801,7 @@ _cpp_read_file (pfile, fname)
cpp_reader *pfile;
const char *fname;
{
- struct include_file *f = open_file (pfile, fname);
+ struct include_file *f = open_file_pch (pfile, fname);
bool stacked = false;
if (f == NULL)
diff --git a/gcc/cpphash.h b/gcc/cpphash.h
index 43ac8336be0..5340b43c98e 100644
--- a/gcc/cpphash.h
+++ b/gcc/cpphash.h
@@ -42,7 +42,7 @@ struct directive; /* Deliberately incomplete. */
efficiency, and partly to limit runaway recursion. */
#define CPP_STACK_MAX 200
-/* A generic memory buffer. */
+/* A generic memory buffer, and operations on it. */
typedef struct _cpp_buff _cpp_buff;
struct _cpp_buff
@@ -59,6 +59,7 @@ extern _cpp_buff *_cpp_append_extend_buff PARAMS ((cpp_reader *, _cpp_buff *,
extern void _cpp_free_buff PARAMS ((_cpp_buff *));
extern unsigned char *_cpp_aligned_alloc PARAMS ((cpp_reader *, size_t));
extern unsigned char *_cpp_unaligned_alloc PARAMS ((cpp_reader *, size_t));
+
#define BUFF_ROOM(BUFF) (size_t) ((BUFF)->limit - (BUFF)->cur)
#define BUFF_FRONT(BUFF) ((BUFF)->cur)
#define BUFF_LIMIT(BUFF) ((BUFF)->limit)
@@ -114,8 +115,8 @@ struct cpp_context
When the context is popped, the buffer is released. */
_cpp_buff *buff;
- /* For a macro context, these are the macro and its arguments. */
- cpp_macro *macro;
+ /* For a macro context, the macro node, otherwise NULL. */
+ cpp_hashnode *macro;
/* True if utoken element is token, else ptoken. */
bool direct_p;
@@ -162,7 +163,6 @@ struct spec_nodes
cpp_hashnode *n_defined; /* defined operator */
cpp_hashnode *n_true; /* C++ keyword true */
cpp_hashnode *n_false; /* C++ keyword false */
- cpp_hashnode *n__Pragma; /* _Pragma operator */
cpp_hashnode *n__STRICT_ANSI__; /* STDC_0_IN_SYSTEM_HEADERS */
cpp_hashnode *n__CHAR_UNSIGNED__; /* plain char is unsigned */
cpp_hashnode *n__VA_ARGS__; /* C99 vararg macros */
@@ -178,7 +178,7 @@ struct cpp_buffer
struct cpp_buffer *prev;
- const unsigned char *buf; /* Entire buffer. */
+ const unsigned char *buf; /* Entire character buffer. */
/* Pointer into the include table; non-NULL if this is a file
buffer. Used for include_next and to record control macros. */
@@ -296,7 +296,7 @@ struct cpp_reader
cpp_token eof;
/* Opaque handle to the dependencies of mkdeps.c. Used by -M etc. */
- struct deps *deps;
+ struct make_deps *deps;
/* Obstack holding all macro hash nodes. This never shrinks.
See cpphash.c */
@@ -327,6 +327,21 @@ struct cpp_reader
we don't get it twice for -v -version. */
unsigned char print_version;
+
+ /* Nonzero means we have printed (while error reporting) a list of
+ containing files that matches the current status. */
+ unsigned char input_stack_listing_current;
+
+
+ /* True after cpp_start_read completes. Used to inhibit some
+ warnings while parsing the command line. */
+ unsigned char done_initializing;
+
+
+ /* A saved list of the defined macros, for dependency checking
+ of precompiled headers. */
+ struct cpp_savedstate *savedstate;
+
/* Whether cpplib owns the hashtable. */
unsigned char our_hashtable;
};
diff --git a/gcc/cppinit.c b/gcc/cppinit.c
index 45d9b6aebd5..b252e2c32f2 100644
--- a/gcc/cppinit.c
+++ b/gcc/cppinit.c
@@ -110,6 +110,7 @@ static bool push_include PARAMS ((cpp_reader *,
static void free_chain PARAMS ((struct pending_option *));
static void set_lang PARAMS ((cpp_reader *, enum c_lang));
static void init_dependency_output PARAMS ((cpp_reader *));
+static void initialize_dependency_output PARAMS ((cpp_reader *));
static void init_standard_includes PARAMS ((cpp_reader *));
static void new_pending_directive PARAMS ((struct cpp_pending *,
const char *,
@@ -547,7 +548,6 @@ cpp_create_reader (table, lang)
s->n_defined = cpp_lookup (pfile, DSC("defined"));
s->n_true = cpp_lookup (pfile, DSC("true"));
s->n_false = cpp_lookup (pfile, DSC("false"));
- s->n__Pragma = cpp_lookup (pfile, DSC("_Pragma"));
s->n__STRICT_ANSI__ = cpp_lookup (pfile, DSC("__STRICT_ANSI__"));
s->n__CHAR_UNSIGNED__ = cpp_lookup (pfile, DSC("__CHAR_UNSIGNED__"));
s->n__VA_ARGS__ = cpp_lookup (pfile, DSC("__VA_ARGS__"));
@@ -658,6 +658,7 @@ static const struct builtin builtin_array[] =
B("__BASE_FILE__", BT_BASE_FILE),
B("__LINE__", BT_SPECLINE),
B("__INCLUDE_LEVEL__", BT_INCLUDE_LEVEL),
+ B("_Pragma", BT_PRAGMA),
X("__VERSION__", VERS),
X("__USER_LABEL_PREFIX__", ULP),
@@ -792,6 +793,73 @@ init_builtins (pfile)
#undef CPLUS
#undef builtin_array_end
+/* Another subroutine of cpp_start_read. This one sets up to do
+ dependency-file output. */
+static void
+initialize_dependency_output (pfile)
+ cpp_reader *pfile;
+{
+ char *spec, *s, *output_file;
+
+ /* Either of two environment variables can specify output of deps.
+ Its value is either "OUTPUT_FILE" or "OUTPUT_FILE DEPS_TARGET",
+ where OUTPUT_FILE is the file to write deps info to
+ and DEPS_TARGET is the target to mention in the deps. */
+
+ if (CPP_OPTION (pfile, print_deps) == 0)
+ {
+ spec = getenv ("DEPENDENCIES_OUTPUT");
+ if (spec)
+ CPP_OPTION (pfile, print_deps) = 1;
+ else
+ {
+ spec = getenv ("SUNPRO_DEPENDENCIES");
+ if (spec)
+ CPP_OPTION (pfile, print_deps) = 2;
+ }
+
+ /* Find the space before the DEPS_TARGET, if there is one. */
+ if (spec)
+ {
+ s = strchr (spec, ' ');
+ if (s)
+ {
+ CPP_OPTION (pfile, deps_target) = s + 1;
+ output_file = (char *) xmalloc (s - spec + 1);
+ memcpy (output_file, spec, s - spec);
+ output_file[s - spec] = 0;
+ }
+ else
+ {
+ CPP_OPTION (pfile, deps_target) = 0;
+ output_file = spec;
+ }
+
+ CPP_OPTION (pfile, deps_file) = output_file;
+ CPP_OPTION (pfile, print_deps_append) = 1;
+ }
+ }
+
+
+ /* Always generate makefile dependencies when writing a .pch file. */
+ if (CPP_OPTION (pfile, print_deps) == 0 &&
+ CPP_OPTION (pfile, gen_deps) == 0)
+ return;
+
+ pfile->deps = deps_init ();
+
+ /* Print the expected object file name as the target of this Make-rule. */
+ if (CPP_OPTION (pfile, deps_target))
+ deps_add_target (pfile->deps, CPP_OPTION (pfile, deps_target), 0);
+ else if (*CPP_OPTION (pfile, in_fname) == 0)
+ deps_add_target (pfile->deps, "-", 0);
+ else
+ deps_calc_target (pfile->deps, CPP_OPTION (pfile, in_fname));
+
+ if (CPP_OPTION (pfile, in_fname))
+ deps_add_dep (pfile->deps, CPP_OPTION (pfile, in_fname));
+}
+
/* And another subroutine. This one sets up the standard include path. */
static void
init_standard_includes (pfile)
@@ -953,6 +1021,8 @@ cpp_start_read (pfile, fname)
if (!_cpp_read_file (pfile, fname))
return 0;
+ initialize_dependency_output (pfile);
+
/* Set this after cpp_post_options so the client can change the
option if it wishes, and after stacking the main file so we don't
trace the main file. */
@@ -1168,6 +1238,7 @@ new_pending_directive (pend, text, handler)
DEF_OPT("lang-c89", 0, OPT_lang_c89) \
DEF_OPT("lang-objc", 0, OPT_lang_objc) \
DEF_OPT("lang-objc++", 0, OPT_lang_objcplusplus) \
+ DEF_OPT("nopch-deps", 0, OPT_nopch_deps) \
DEF_OPT("nostdinc", 0, OPT_nostdinc) \
DEF_OPT("nostdinc++", 0, OPT_nostdincplusplus) \
DEF_OPT("o", no_fil, OPT_o) \
@@ -1553,7 +1624,9 @@ cpp_handle_option (pfile, argc, argv)
CPP_OPTION (pfile, print_deps) = 1;
CPP_OPTION (pfile, deps_file) = arg;
break;
-
+ case OPT_nopch_deps:
+ CPP_OPTION (pfile, print_deps_nopch) = 1;
+ break;
case OPT_A:
if (arg[0] == '-')
{
@@ -1826,6 +1899,12 @@ init_dependency_output (pfile)
CPP_OPTION (pfile, deps_file) = output_file;
CPP_OPTION (pfile, print_deps_append) = 1;
}
+ /* Always generate makefile dependencies when writing a .pch file. */
+ if (CPP_OPTION (pfile, print_deps) == 0 &&
+ CPP_OPTION (pfile, gen_deps) == 0)
+ return;
+
+
/* If dependencies go to standard output, or -MG is used, we should
suppress output, including -dM, -dI etc. */
diff --git a/gcc/cpplib.h b/gcc/cpplib.h
index 4404a40e5ef..d9eb256cb9e 100644
--- a/gcc/cpplib.h
+++ b/gcc/cpplib.h
@@ -168,7 +168,7 @@ struct cpp_string
#define BOL (1 << 6) /* Token at beginning of line. */
/* A preprocessing token. This has been carefully packed and should
- occupy 12 bytes on 32-bit hosts and 16 bytes on 64-bit hosts. */
+ occupy 16 bytes on 32-bit hosts and 24 bytes on 64-bit hosts. */
struct cpp_token
{
unsigned int line; /* Logical line of first char of token. */
@@ -217,6 +217,10 @@ struct cpp_options
being written to stdout. */
const char *deps_file;
+ /* Target-name to write with the dependency information. */
+ char *deps_target;
+
+
/* Search paths for include files. */
struct search_path *quote_include; /* "" */
struct search_path *bracket_include; /* <> */
@@ -275,6 +279,15 @@ struct cpp_options
/* If true, fopen (deps_file, "a") else fopen (deps_file, "w"). */
unsigned char print_deps_append;
+ /* Nonzero if we are generating Makefile dependencies
+ for precompiled headers. */
+ unsigned char gen_deps;
+
+ /* Nonzero if the Makefile dependency list should not include
+ precompiled headers. */
+ unsigned char print_deps_nopch;
+
+
/* Nonzero means print names of header files (-H). */
unsigned char print_include_names;
@@ -353,27 +366,32 @@ struct cpp_options
/* Print column number in error messages. */
unsigned char show_column;
- /* Treat C++ alternate operator names special. */
+ /* Nonzero means handle C++ alternate operator names. */
unsigned char operator_names;
/* True if --help, --version or --target-help appeared in the
options. Stand-alone CPP should then bail out after option
parsing; drivers might want to continue printing help. */
unsigned char help_only;
+
+
+
};
/* Call backs. */
struct cpp_callbacks
{
+ int (*valid_pch) PARAMS ((cpp_reader *, const char *, int));
+ void (*read_pch) PARAMS ((cpp_reader *, int, const char *));
/* Called when a new line of preprocessed output is started. */
void (*line_change) PARAMS ((cpp_reader *, const cpp_token *, int));
void (*file_change) PARAMS ((cpp_reader *, const struct line_map *));
- void (*include) PARAMS ((cpp_reader *, unsigned int,
- const unsigned char *, const cpp_token *));
- void (*define) PARAMS ((cpp_reader *, unsigned int, cpp_hashnode *));
- void (*undef) PARAMS ((cpp_reader *, unsigned int, cpp_hashnode *));
- void (*ident) PARAMS ((cpp_reader *, unsigned int, const cpp_string *));
- void (*def_pragma) PARAMS ((cpp_reader *, unsigned int));
+ void (*include) PARAMS ((cpp_reader *, unsigned int,
+ const unsigned char *, const cpp_token *));
+ void (*define) PARAMS ((cpp_reader *, unsigned int, cpp_hashnode *));
+ void (*undef) PARAMS ((cpp_reader *, unsigned int, cpp_hashnode *));
+ void (*ident) PARAMS ((cpp_reader *, unsigned int, const cpp_string *));
+ void (*def_pragma) PARAMS ((cpp_reader *, unsigned int));
};
#define CPP_FATAL_LIMIT 1000
@@ -383,6 +401,10 @@ struct cpp_callbacks
/* Name under which this program was invoked. */
extern const char *progname;
+/* Where does this buffer come from? A source file, a builtin macro,
+ a command-line option, or a _Pragma operator. */
+enum cpp_buffer_type {BUF_FILE, BUF_BUILTIN, BUF_CL_OPTION, BUF_PRAGMA, BUF_PCH};
+
/* The structure of a node in the hash table. The hash table has
entries for all identifiers: either macros defined by #define
commands (type NT_MACRO), assertions created with #assert
@@ -400,6 +422,7 @@ extern const char *progname;
#define NODE_BUILTIN (1 << 2) /* Builtin macro. */
#define NODE_DIAGNOSTIC (1 << 3) /* Possible diagnostic when lexed. */
#define NODE_WARN (1 << 4) /* Warn if redefined or undefined. */
+#define NODE_DISABLED (1 << 5) /* A disabled macro. */
/* Different flavors of hash node. */
enum node_type
@@ -409,7 +432,8 @@ enum node_type
NT_ASSERTION /* Predicate for #assert. */
};
-/* Different flavors of builtin macro. */
+/* Different flavors of builtin macro. _Pragma is an operator, but we
+ handle it with the builtin code for efficiency reasons. */
enum builtin_type
{
BT_SPECLINE = 0, /* `__LINE__' */
@@ -418,7 +442,8 @@ enum builtin_type
BT_BASE_FILE, /* `__BASE_FILE__' */
BT_INCLUDE_LEVEL, /* `__INCLUDE_LEVEL__' */
BT_TIME, /* `__TIME__' */
- BT_STDC /* `__STDC__' */
+ BT_STDC, /* `__STDC__' */
+ BT_PRAGMA /* `_Pragma' operator */
};
#define CPP_HASHNODE(HNODE) ((cpp_hashnode *) (HNODE))
@@ -445,6 +470,7 @@ struct cpp_hashnode
enum cpp_ttype operator; /* Code for a named operator. */
enum builtin_type builtin; /* Code for a builtin macro. */
} value;
+ union tree_node *fe_value; /* front end value */
};
/* Call this first to get a handle to pass to other functions. If you
@@ -568,14 +594,21 @@ extern void cpp_forall_identifiers PARAMS ((cpp_reader *,
/* In cppmacro.c */
extern void cpp_scan_nooutput PARAMS ((cpp_reader *));
-extern void cpp_start_lookahead PARAMS ((cpp_reader *));
-extern void cpp_stop_lookahead PARAMS ((cpp_reader *, int));
extern int cpp_sys_macro_p PARAMS ((cpp_reader *));
/* In cppfiles.c */
extern int cpp_included PARAMS ((cpp_reader *, const char *));
extern void cpp_make_system_header PARAMS ((cpp_reader *, int, int));
+/* In cpppch.c */
+extern int cpp_save_state PARAMS ((cpp_reader *, FILE *));
+extern int cpp_write_pch PARAMS ((cpp_reader *, FILE *));
+extern int cpp_valid_state PARAMS ((cpp_reader *, int));
+extern int cpp_read_state PARAMS ((cpp_reader *, FILE *));
+
+extern int write_makedeps PARAMS ((cpp_reader *, FILE *));
+extern int read_makedeps PARAMS ((cpp_reader *, FILE *, const char *));
+
#ifdef __cplusplus
}
#endif
diff --git a/gcc/cppmacro.c b/gcc/cppmacro.c
index 845d90b99eb..2ca29eef9f8 100644
--- a/gcc/cppmacro.c
+++ b/gcc/cppmacro.c
@@ -38,7 +38,6 @@ struct cpp_macro
unsigned short paramc; /* Number of parameters. */
unsigned int fun_like : 1; /* If a function-like macro. */
unsigned int variadic : 1; /* If a variadic macro. */
- unsigned int disabled : 1; /* If macro is disabled. */
unsigned int syshdr : 1; /* If macro defined in system header. */
};
@@ -55,11 +54,11 @@ struct macro_arg
/* Macro expansion. */
static int enter_macro_context PARAMS ((cpp_reader *, cpp_hashnode *));
-static const cpp_token *builtin_macro PARAMS ((cpp_reader *, cpp_hashnode *));
+static int builtin_macro PARAMS ((cpp_reader *, cpp_hashnode *));
static void push_token_context
- PARAMS ((cpp_reader *, cpp_macro *, const cpp_token *, unsigned int));
+ PARAMS ((cpp_reader *, cpp_hashnode *, const cpp_token *, unsigned int));
static void push_ptoken_context
- PARAMS ((cpp_reader *, cpp_macro *, _cpp_buff *,
+ PARAMS ((cpp_reader *, cpp_hashnode *, _cpp_buff *,
const cpp_token **, unsigned int));
static _cpp_buff *collect_args PARAMS ((cpp_reader *, const cpp_hashnode *));
static cpp_context *next_context PARAMS ((cpp_reader *));
@@ -76,8 +75,8 @@ static const cpp_token *stringify_arg PARAMS ((cpp_reader *, macro_arg *));
static void paste_all_tokens PARAMS ((cpp_reader *, const cpp_token *));
static bool paste_tokens PARAMS ((cpp_reader *, const cpp_token **,
const cpp_token *));
-static int funlike_invocation_p PARAMS ((cpp_reader *, const cpp_hashnode *));
-static void replace_args PARAMS ((cpp_reader *, cpp_macro *, macro_arg *));
+static int funlike_invocation_p PARAMS ((cpp_reader *, cpp_hashnode *));
+static void replace_args PARAMS ((cpp_reader *, cpp_hashnode *, macro_arg *));
/* #define directive parsing and handling. */
@@ -132,17 +131,22 @@ static const char * const monthnames[] =
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};
-/* Handle builtin macros like __FILE__. */
-static const cpp_token *
+/* Handle builtin macros like __FILE__, and push the resulting token
+ on the context stack. Also handles _Pragma, for which no new token
+ is created. Returns 1 on success, 0 to return the token to the
+ caller. */
+static int
builtin_macro (pfile, node)
cpp_reader *pfile;
cpp_hashnode *node;
{
+ const cpp_token *result;
+
switch (node->value.builtin)
{
default:
cpp_ice (pfile, "invalid builtin macro \"%s\"", NODE_NAME (node));
- return new_number_token (pfile, 1);
+ return 0;
case BT_FILE:
case BT_BASE_FILE:
@@ -161,28 +165,33 @@ builtin_macro (pfile, node)
buf = _cpp_unaligned_alloc (pfile, len * 4 + 1);
len = quote_string (buf, (const unsigned char *) name, len) - buf;
- return new_string_token (pfile, buf, len);
+ result = new_string_token (pfile, buf, len);
}
-
+ break;
+
case BT_INCLUDE_LEVEL:
/* The line map depth counts the primary source as level 1, but
historically __INCLUDE_DEPTH__ has called the primary source
level 0. */
- return new_number_token (pfile, pfile->line_maps.depth - 1);
+ result = new_number_token (pfile, pfile->line_maps.depth - 1);
+ break;
case BT_SPECLINE:
/* If __LINE__ is embedded in a macro, it must expand to the
line of the macro's invocation, not its definition.
Otherwise things like assert() will not work properly. */
- return new_number_token (pfile, SOURCE_LINE (pfile->map,
- pfile->cur_token[-1].line));
+ result = new_number_token (pfile,
+ SOURCE_LINE (pfile->map,
+ pfile->cur_token[-1].line));
+ break;
case BT_STDC:
{
int stdc = (!CPP_IN_SYSTEM_HEADER (pfile)
|| pfile->spec_nodes.n__STRICT_ANSI__->type != NT_VOID);
- return new_number_token (pfile, stdc);
+ result = new_number_token (pfile, stdc);
}
+ break;
case BT_DATE:
case BT_TIME:
@@ -212,8 +221,24 @@ builtin_macro (pfile, node)
tb->tm_hour, tb->tm_min, tb->tm_sec);
}
- return node->value.builtin == BT_DATE ? &pfile->date: &pfile->time;
+ if (node->value.builtin == BT_DATE)
+ result = &pfile->date;
+ else
+ result = &pfile->time;
+ break;
+
+ case BT_PRAGMA:
+ /* Don't interpret _Pragma within directives. The standard is
+ not clear on this, but to me this makes most sense. */
+ if (pfile->state.in_directive)
+ return 0;
+
+ _cpp_do__Pragma (pfile);
+ return 1;
}
+
+ push_token_context (pfile, NULL, result, 1);
+ return 1;
}
/* Adds backslashes before all backslashes and double quotes appearing
@@ -594,7 +619,7 @@ collect_args (pfile, node)
static int
funlike_invocation_p (pfile, node)
cpp_reader *pfile;
- const cpp_hashnode *node;
+ cpp_hashnode *node;
{
const cpp_token *maybe_paren;
_cpp_buff *buff = NULL;
@@ -626,7 +651,7 @@ funlike_invocation_p (pfile, node)
if (buff)
{
if (node->value.macro->paramc > 0)
- replace_args (pfile, node->value.macro, (macro_arg *) buff->base);
+ replace_args (pfile, node, (macro_arg *) buff->base);
_cpp_release_buff (pfile, buff);
}
@@ -642,9 +667,11 @@ enter_macro_context (pfile, node)
cpp_reader *pfile;
cpp_hashnode *node;
{
- if (node->flags & NODE_BUILTIN)
- push_token_context (pfile, NULL, builtin_macro (pfile, node), 1);
- else
+ /* Macros invalidate controlling macros. */
+ pfile->mi_valid = false;
+
+ /* Handle macros and the _Pragma operator. */
+ if (! (node->flags & NODE_BUILTIN))
{
cpp_macro *macro = node->value.macro;
@@ -652,22 +679,24 @@ enter_macro_context (pfile, node)
return 0;
/* Disable the macro within its expansion. */
- macro->disabled = 1;
+ node->flags |= NODE_DISABLED;
if (macro->paramc == 0)
- push_token_context (pfile, macro, macro->expansion, macro->count);
+ push_token_context (pfile, node, macro->expansion, macro->count);
+
+ return 1;
}
-
- return 1;
+
+ return builtin_macro (pfile, node);
}
/* Take the expansion of a function-like MACRO, replacing parameters
with the actual arguments. Each argument is macro-expanded before
replacement, unless operated upon by the # or ## operators. */
static void
-replace_args (pfile, macro, args)
+replace_args (pfile, node, args)
cpp_reader *pfile;
- cpp_macro *macro;
+ cpp_hashnode *node;
macro_arg *args;
{
unsigned int i, total;
@@ -675,11 +704,13 @@ replace_args (pfile, macro, args)
const cpp_token **dest, **first;
macro_arg *arg;
_cpp_buff *buff;
+ cpp_macro *macro;
/* First, fully macro-expand arguments, calculating the number of
tokens in the final expansion as we go. The ordering of the if
statements below is subtle; we must handle stringification before
pasting. */
+ macro = node->value.macro;
total = macro->count;
limit = macro->expansion + macro->count;
@@ -797,7 +828,7 @@ replace_args (pfile, macro, args)
if (args[i].expanded)
free (args[i].expanded);
- push_ptoken_context (pfile, macro, buff, first, dest - first);
+ push_ptoken_context (pfile, node, buff, first, dest - first);
}
/* Return a special padding token, with padding inherited from SOURCE. */
@@ -837,7 +868,7 @@ next_context (pfile)
static void
push_ptoken_context (pfile, macro, buff, first, count)
cpp_reader *pfile;
- cpp_macro *macro;
+ cpp_hashnode *macro;
_cpp_buff *buff;
const cpp_token **first;
unsigned int count;
@@ -855,7 +886,7 @@ push_ptoken_context (pfile, macro, buff, first, count)
static void
push_token_context (pfile, macro, first, count)
cpp_reader *pfile;
- cpp_macro *macro;
+ cpp_hashnode *macro;
const cpp_token *first;
unsigned int count;
{
@@ -914,7 +945,7 @@ _cpp_pop_context (pfile)
/* Re-enable a macro when leaving its expansion. */
if (context->macro)
- context->macro->disabled = 0;
+ context->macro->flags &= ~NODE_DISABLED;
if (context->buff)
_cpp_release_buff (pfile, context->buff);
@@ -975,39 +1006,30 @@ cpp_get_token (pfile)
node = result->val.node;
- /* Handle macros and the _Pragma operator. */
- if (node->type == NT_MACRO && !(result->flags & NO_EXPAND))
+ if (node->type != NT_MACRO || (result->flags & NO_EXPAND))
+ break;
+
+ if (!(node->flags & NODE_DISABLED))
{
- /* Macros invalidate controlling macros. */
- pfile->mi_valid = false;
-
- if (!(node->flags & NODE_BUILTIN) && node->value.macro->disabled)
- {
- /* Flag this token as always unexpandable. */
- cpp_token *t = _cpp_temp_token (pfile);
- t->type = result->type;
- t->flags = result->flags | NO_EXPAND;
- t->val.str = result->val.str;
- result = t;
- }
- else if (!pfile->state.prevent_expansion
- && enter_macro_context (pfile, node))
+ if (!pfile->state.prevent_expansion
+ && enter_macro_context (pfile, node))
{
if (pfile->state.in_directive)
continue;
return padding_token (pfile, result);
}
}
+ else
+ {
+ /* Flag this token as always unexpandable. */
+ cpp_token *t = _cpp_temp_token (pfile);
+ t->type = result->type;
+ t->flags = result->flags | NO_EXPAND;
+ t->val.str = result->val.str;
+ result = t;
+ }
- /* Don't interpret _Pragma within directives. The standard is
- not clear on this, but to me this makes most sense. */
- if (node != pfile->spec_nodes.n__Pragma
- || pfile->state.in_directive)
- break;
-
- /* Handle it, and loop back for another token. MI is cleared
- since this token came from either the lexer or a macro. */
- _cpp_do__Pragma (pfile);
+ break;
}
return result;
@@ -1020,9 +1042,9 @@ int
cpp_sys_macro_p (pfile)
cpp_reader *pfile;
{
- cpp_macro *macro = pfile->context->macro;
+ cpp_hashnode *node = pfile->context->macro;
- return macro && macro->syshdr;
+ return node && node->value.macro && node->value.macro->syshdr;
}
/* Read each token in, until EOF. Directives are transparently
@@ -1034,6 +1056,45 @@ cpp_scan_nooutput (pfile)
while (cpp_get_token (pfile)->type != CPP_EOF)
;
}
+#if 0
+
+/* Lookahead handling. */
+
+static void
+save_lookahead_token (pfile, token)
+ cpp_reader *pfile;
+ const cpp_token *token;
+{
+ cpp_lookahead *la = pfile->la_write;
+ cpp_token_with_pos *twp;
+
+ if (la->count == la->cap)
+ {
+ la->cap += la->cap + 8;
+ la->tokens = (cpp_token_with_pos *)
+ xrealloc (la->tokens, la->cap * sizeof (cpp_token_with_pos));
+ }
+
+ twp = &la->tokens[la->count++];
+ twp->token = *token;
+ twp->pos = *cpp_get_line (pfile);
+}
+
+static void
+take_lookahead_token (pfile, token)
+ cpp_reader *pfile;
+ cpp_token *token;
+{
+ cpp_lookahead *la = pfile->la_read;
+ cpp_token_with_pos *twp = &la->tokens[la->cur];
+
+ *token = twp->token;
+ pfile->lexer_pos = twp->pos;
+
+ if (++la->cur == la->count)
+ _cpp_release_lookahead (pfile);
+}
+#endif
/* Step back one (or more) tokens. Can only step mack more than 1 if
they are from the lexer, and not from macro expansion. */
@@ -1118,7 +1179,7 @@ _cpp_free_definition (h)
/* Macros and assertions no longer have anything to free. */
h->type = NT_VOID;
/* Clear builtin flag in case of redefinition. */
- h->flags &= ~NODE_BUILTIN;
+ h->flags &= ~(NODE_BUILTIN | NODE_DISABLED);
}
/* Save parameter NODE to the parameter list of macro MACRO. Returns
@@ -1360,9 +1421,10 @@ _cpp_create_definition (pfile, node)
BUFF_FRONT (pfile->a_buff) = (U_CHAR *) &macro->expansion[macro->count];
/* Implement the macro-defined-to-itself optimisation. */
- macro->disabled = (macro->count == 1 && !macro->fun_like
- && macro->expansion[0].type == CPP_NAME
- && macro->expansion[0].val.node == node);
+ if (macro->count == 1 && !macro->fun_like
+ && macro->expansion[0].type == CPP_NAME
+ && macro->expansion[0].val.node == node)
+ node->flags |= NODE_DISABLED;
/* To suppress some diagnostics. */
macro->syshdr = pfile->map->sysp != 0;
diff --git a/gcc/cppmain.c b/gcc/cppmain.c
index a1b8b67f54c..6d41af73f24 100644
--- a/gcc/cppmain.c
+++ b/gcc/cppmain.c
@@ -215,8 +215,8 @@ setup_callbacks ()
}
}
-/* Writes out the preprocessed file. Alternates between two tokens,
- so that we can avoid accidental token pasting. */
+/* Writes out the preprocessed file, handling spacing and paste
+ avoidance issues. */
static void
scan_translation_unit (pfile)
cpp_reader *pfile;
@@ -334,7 +334,7 @@ print_line (map, line, special_flags)
}
/* Called when a line of output is started. TOKEN is the first token
- of the line, and maybe be CPP_EOF. */
+ of the line, and may be CPP_EOF. */
static void
cb_line_change (pfile, token, parsing_args)
diff --git a/gcc/cpppch.c b/gcc/cpppch.c
new file mode 100644
index 00000000000..6465b4274a5
--- /dev/null
+++ b/gcc/cpppch.c
@@ -0,0 +1,598 @@
+/* Part of CPP library. (Precompiled header reading/writing.)
+ Copyright (C) 2000, 2001 Free Software Foundation, Inc.
+
+This program is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
+
+#include "config.h"
+#include "system.h"
+#include "cpplib.h"
+#include "cpphash.h"
+#include "intl.h"
+#include "hashtab.h"
+#include "mkdeps.h"
+
+static int write_macdef PARAMS ((cpp_reader *, cpp_hashnode *, void *));
+static int save_idents PARAMS ((cpp_reader *, cpp_hashnode *, void *));
+static hashval_t hashmem PARAMS ((const void *, size_t));
+static hashval_t cpp_string_hash PARAMS ((const void *));
+static int cpp_string_eq PARAMS ((const void *, const void *));
+static int count_defs PARAMS ((cpp_reader *, cpp_hashnode *, void *));
+static int write_defs PARAMS ((cpp_reader *, cpp_hashnode *, void *));
+
+/* This structure represents a macro definition on disk. */
+struct macrodef_struct
+{
+ unsigned short name_length;
+ unsigned short flags;
+ unsigned int definition_length;
+};
+
+static int num_to_write = 0;
+
+/* Function to write out the makefile dependency information to the
+ precompiled header. This will cause the original dependencies to be
+ preserved. */
+
+int
+write_makedeps (pfile, file_p)
+ cpp_reader *pfile;
+ FILE *file_p;
+{
+ FILE *f = (FILE *) file_p;
+ int i;
+ struct make_deps *pch_makedeps = pfile->deps;
+
+ /* The cppreader structure contains makefile dependences. Write out this
+ structure. */
+
+ /* The number of dependences. */
+ if (fwrite (&pch_makedeps->ndeps, sizeof (pch_makedeps->ndeps), 1, f) != 1)
+ {
+ cpp_error_from_errno (pfile, "while writing makefile deps: ndeps");
+ return -1;
+ }
+ /* The len of each dependence followed by the string. */
+ for (i = 0; i < pch_makedeps->ndeps; i++)
+ {
+ num_to_write = strlen (pch_makedeps->depv[i]);
+ if (fwrite (&num_to_write, sizeof (int), 1, f) != 1)
+ {
+ cpp_error_from_errno (pfile, "while writing makefile deps: dep string size");
+ return -1;
+ }
+ if (fwrite (pch_makedeps->depv[i], num_to_write, 1, f) != 1)
+ {
+ cpp_error_from_errno (pfile, "while writing makefile deps: dep string");
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/* Function to read in the makefile dependency information from
+ the precompiled header. */
+int
+read_makedeps (pfile, fd, self)
+ cpp_reader *pfile;
+ FILE *fd;
+ const char *self;
+{
+
+ int i, temp, num_to_read;
+ char *temp_str = (char *) xmalloc (5192);
+
+ if (pfile->deps == 0)
+ {
+ pfile->deps = deps_init ();
+ }
+
+ /* Number of dependences. */
+ if (fread (&temp, 1, sizeof (int), fd) != sizeof (int))
+ {
+ cpp_error_from_errno (pfile, "while reading makefile deps: num deps");
+ return -1;
+ }
+
+ /* The len of each dependence string, followed by the string. */
+ for (i = 0; i < temp; i++)
+ {
+ /* Read in # bytes in string. */
+ if (fread (&num_to_read, 1, sizeof (int), fd) != sizeof (int))
+ {
+ cpp_error_from_errno (pfile, "while reading makefile deps: target string size");
+ return -1;
+ }
+ if (fread (temp_str, 1, num_to_read, fd) != num_to_read)
+ {
+ cpp_error_from_errno (pfile, "while reading makefile deps: target string");
+ return -1;
+ }
+ temp_str[num_to_read+1] = '\0';
+ /* Generate makefile dependencies from .pch if -nopch-deps. */
+ if (CPP_OPTION (pfile, print_deps_nopch) && strcmp (temp_str, self))
+ deps_add_dep (pfile->deps, temp_str);
+ }
+
+ return 0;
+}
+/* This is how we write out a macro definition.
+ Suitable for being called by cpp_forall_identifiers. */
+
+static int
+write_macdef (pfile, hn, file_p)
+ cpp_reader *pfile;
+ cpp_hashnode *hn;
+ void *file_p;
+{
+ FILE *f = (FILE *) file_p;
+ switch (hn->type)
+ {
+ case NT_VOID:
+ if (! (hn->flags & NODE_POISONED))
+ return 1;
+
+ case NT_MACRO:
+ if ((hn->flags & NODE_BUILTIN))
+ return 1;
+
+ {
+ struct macrodef_struct s;
+ const unsigned char *defn;
+
+ s.name_length = hn->ident.len;
+ s.flags = hn->flags & NODE_POISONED;
+ if (hn->fe_value != NULL)
+ abort ();
+
+ if (hn->type == NT_MACRO)
+ defn = cpp_macro_definition (pfile, hn);
+ else
+ defn = U"";
+
+ s.definition_length = ustrlen (defn);
+
+ if (fwrite (&s, sizeof (s), 1, f) != 1
+ || fwrite (hn->ident.str, 1, s.name_length, f) != s.name_length
+ || fwrite (defn, 1, s.definition_length, f) != s.definition_length)
+ {
+ cpp_error_from_errno (pfile, "while writing precompiled header");
+ return 0;
+ }
+ }
+ return 1;
+
+ case NT_ASSERTION:
+ /* Not currently implemented. */
+ return 1;
+
+ default:
+ abort ();
+ }
+}
+
+/* This structure records the names of the defined macros.
+ It's also used as a callback structure for size_initial_idents
+ and save_idents. */
+
+struct cpp_savedstate
+{
+ /* A hash table of the defined identifiers. */
+ htab_t definedhash;
+ /* The size of the definitions of those identifiers (the size of
+ 'definedstrs'). */
+ size_t hashsize;
+ /* Space for the next definition. Definitions are null-terminated
+ strings. */
+ U_CHAR *definedstrs;
+};
+
+/* Save this identifier into the state: put it in the hash table,
+ put the definition in 'definedstrs'. */
+
+static int
+save_idents (pfile, hn, ss_p)
+ cpp_reader *pfile ATTRIBUTE_UNUSED;
+ cpp_hashnode *hn;
+ void *ss_p;
+{
+ struct cpp_savedstate *const ss = (struct cpp_savedstate *)ss_p;
+
+ if (hn->type != NT_VOID)
+ {
+ struct cpp_string news;
+ void **slot;
+
+ news.len = hn->ident.len;
+ news.text= hn->ident.str;
+ slot = htab_find_slot (ss->definedhash, &news, INSERT);
+ if (*slot == NULL)
+ {
+ struct cpp_string *sp;
+ unsigned char *text;
+
+ sp = xmalloc (sizeof (struct cpp_string));
+ *slot = sp;
+
+ sp->len = hn->ident.len;
+ sp->text = text = xmalloc (hn->ident.len);
+ memcpy (text, hn->ident.str, hn->ident.len);
+ }
+ }
+
+ return 1;
+}
+
+/* Hash some memory in a generic way. */
+
+static hashval_t
+hashmem (p_p, sz)
+ const void *p_p;
+ size_t sz;
+{
+ const unsigned char *p = (const unsigned char *)p_p;
+ size_t i;
+ hashval_t h;
+
+ h = 0;
+ for (i = 0; i < sz; i++)
+ h = h * 67 - (*p++ - 113);
+ return h;
+}
+
+/* Hash a cpp string for the hashtable machinery. */
+
+static hashval_t
+cpp_string_hash (a_p)
+ const void *a_p;
+{
+ const struct cpp_string *a = (const struct cpp_string *) a_p;
+ return hashmem (a->text, a->len);
+}
+
+/* Compare two cpp strings for the hashtable machinery. */
+
+static int
+cpp_string_eq (a_p, b_p)
+ const void *a_p;
+ const void *b_p;
+{
+ const struct cpp_string *a = (const struct cpp_string *) a_p;
+ const struct cpp_string *b = (const struct cpp_string *) b_p;
+ return (a->len == b->len
+ && memcmp (a->text, b->text, a->len) == 0);
+}
+
+/* Save the current definitions of the cpp_reader for dependency
+ checking purposes. When writing a precompiled header, this should
+ be called at the same point in the compilation as cpp_valid_state
+ would be called when reading the precompiled header back in. */
+
+int
+cpp_save_state (r, f)
+ cpp_reader *r;
+ FILE *f;
+{
+ /* Save the list of non-void identifiers for the dependency checking. */
+ r->savedstate = xmalloc (sizeof (struct cpp_savedstate));
+ r->savedstate->definedhash = htab_create (100, cpp_string_hash,
+ cpp_string_eq, NULL);
+ cpp_forall_identifiers (r, save_idents, r->savedstate);
+
+ /* Write out the list of defined identifiers. */
+ cpp_forall_identifiers (r, write_macdef, f);
+
+ return 0;
+}
+
+/* Calculate the 'hashsize' field of the saved state. */
+
+static int
+count_defs (pfile, hn, ss_p)
+ cpp_reader *pfile ATTRIBUTE_UNUSED;
+ cpp_hashnode *hn;
+ void *ss_p;
+{
+ struct cpp_savedstate *const ss = (struct cpp_savedstate *)ss_p;
+
+ switch (hn->type)
+ {
+ case NT_MACRO:
+ if (hn->flags & NODE_BUILTIN)
+ return 1;
+
+ /* else fall through. */
+
+ case NT_VOID:
+ {
+ struct cpp_string news;
+ void **slot;
+
+ news.len = hn->ident.len;
+ news.text = hn->ident.str;
+ slot = htab_find (ss->definedhash, &news);
+ if (slot == NULL)
+ ss->hashsize += hn->ident.len + 1;
+ }
+ return 1;
+
+ case NT_ASSERTION:
+ /* Not currently implemented. */
+ return 1;
+
+ default:
+ abort ();
+ }
+}
+
+/* Write the identifiers into 'definedstrs' of the state. */
+
+static int
+write_defs (pfile, hn, ss_p)
+ cpp_reader *pfile ATTRIBUTE_UNUSED;
+ cpp_hashnode *hn;
+ void *ss_p;
+{
+ struct cpp_savedstate *const ss = (struct cpp_savedstate *)ss_p;
+
+ switch (hn->type)
+ {
+ case NT_MACRO:
+ if (hn->flags & NODE_BUILTIN) {
+ return 1;
+}
+
+ /* else fall through. */
+
+ case NT_VOID:
+ {
+ struct cpp_string news;
+ void **slot;
+
+ news.len = hn->ident.len;
+ news.text = hn->ident.str;
+ slot = htab_find (ss->definedhash, &news);
+ if (slot == NULL)
+ {
+ memcpy (ss->definedstrs, hn->ident.str, hn->ident.len);
+ ss->definedstrs[hn->ident.len] = 0;
+ ss->definedstrs += hn->ident.len + 1;
+ }
+ }
+ return 1;
+
+ case NT_ASSERTION:
+ /* Not currently implemented. */
+ return 1;
+
+ default:
+ abort ();
+ }
+}
+
+/* Write out the definitions of the preprocessor, in a form suitable for
+ cpp_read_state. */
+
+int
+cpp_write_pch (r, f)
+ cpp_reader *r;
+ FILE *f;
+{
+ struct macrodef_struct z = { 0, 0, 0 };
+ struct cpp_savedstate *const ss = r->savedstate;
+ U_CHAR *definedstrs;
+
+ ss->hashsize = 0;
+
+ /* Write out the list of identifiers which have been seen and
+ weren't defined to anything previously. */
+ cpp_forall_identifiers (r, count_defs, ss);
+ definedstrs = ss->definedstrs = xmalloc (ss->hashsize);
+ cpp_forall_identifiers (r, write_defs, ss);
+ z.definition_length = ss->hashsize;
+ if (fwrite (&z, sizeof (z), 1, f) != 1
+ || fwrite (definedstrs, ss->hashsize, 1, f) != 1)
+ {
+ cpp_error_from_errno (r, "while writing precompiled header");
+ return -1;
+ }
+ free (definedstrs);
+
+ /* Write out the list of defined identifiers. */
+ cpp_forall_identifiers (r, write_macdef, f);
+ if (fwrite (&z, sizeof (z), 1, f) != 1)
+ {
+ cpp_error_from_errno (r, "while writing precompiled header");
+ return -1;
+ }
+
+ /* Free the saved state. */
+ free (ss);
+ r->savedstate = NULL;
+
+ return 0;
+}
+
+/* Determine whether 'fd' is a precompiled header which is consistent
+ with the preprocessor's current definitions. It will be consistent
+ when:
+
+ - anything that was defined just before the PCH was generated
+ is defined the same way now; and
+ - anything that was not defined then, but is defined now, was not
+ used by the PCH.
+*/
+
+int
+cpp_valid_state (r, fd)
+ cpp_reader *r;
+ int fd;
+{
+ struct macrodef_struct m;
+ size_t namebufsz = 256;
+ U_CHAR *namebuf = xmalloc (namebufsz);
+ U_CHAR *undeftab = NULL;
+ unsigned int i;
+
+ /* Read in the list of identifiers that must be defined
+ Check that they are defined in the same way. */
+ for (;;)
+ {
+ cpp_hashnode *h;
+ const U_CHAR *newdefn;
+ size_t totlen;
+
+ if (read (fd, &m, sizeof (m)) != sizeof (m))
+ goto error;
+
+ if (m.name_length == 0)
+ break;
+
+ totlen = m.name_length + m.definition_length;
+ if (totlen > namebufsz)
+ {
+ free (namebuf);
+ namebufsz = totlen + 256;
+ namebuf = xmalloc (namebufsz);
+ }
+
+ if (read (fd, namebuf, totlen) != totlen)
+ goto error;
+
+ h = cpp_lookup (r, namebuf, m.name_length);
+ if (m.flags & NODE_POISONED
+ || h->type != NT_MACRO
+ || h->flags & NODE_POISONED)
+ goto fail;
+
+ newdefn = cpp_macro_definition (r, h);
+
+ if (m.definition_length != ustrlen (newdefn)
+ || memcmp (namebuf + m.name_length, newdefn,
+ m.definition_length) != 0)
+ goto fail;
+ }
+ free (namebuf);
+ namebuf = NULL;
+
+ /* Read in the list of identifiers that must not be defined.
+ Check that they really aren't. */
+ undeftab = xmalloc (m.definition_length);
+ if (read (fd, undeftab, m.definition_length) != m.definition_length)
+ goto error;
+ for (i = 0; i < m.definition_length; )
+ {
+ int l = ustrlen (undeftab + i);
+ cpp_hashnode *h;
+ h = cpp_lookup (r, undeftab + i, l);
+ if (h->type != NT_VOID
+ || h->flags & NODE_POISONED)
+ goto fail;
+ i += l + 1;
+ }
+ free (undeftab);
+
+ /* We win! */
+ return 0;
+
+ error:
+ cpp_error_from_errno (r, "while reading precompiled header");
+ return -1;
+
+ fail:
+ if (namebuf != NULL)
+ free (namebuf);
+ if (undeftab != NULL)
+ free (undeftab);
+ return 1;
+}
+
+/* Given a precompiled header that was previously determined to be valid,
+ apply all its definitions (and undefinitions) to the current state. */
+
+int
+cpp_read_state (r, f)
+ cpp_reader *r;
+ FILE *f;
+{
+ struct macrodef_struct m;
+ size_t namelen = 80;
+ size_t defnlen = 256;
+ U_CHAR *defn = xmalloc (defnlen);
+ U_CHAR *name = xmalloc (namelen);
+ struct lexer_state old_state = r->state;
+
+ r->state.in_directive = 0;
+ r->state.prevent_expansion = 1;
+ r->state.angled_headers = 0;
+
+
+ /* Read in the identifiers that must be defined. */
+ for (;;)
+ {
+ cpp_hashnode *h;
+
+ if (fread (&m, sizeof (m), 1, f) != 1)
+ goto error;
+
+ if (m.name_length == 0)
+ break;
+
+ if (namelen < m.name_length)
+ {
+ free (name);
+ namelen = m.name_length + 80;
+ name = xmalloc (namelen);
+ }
+ if (defnlen < m.definition_length)
+ {
+ free (defn);
+ defnlen = m.definition_length + 256;
+ defn = xmalloc (m.definition_length);
+ }
+
+ if (fread (name, 1, m.name_length, f) != m.name_length
+ || fread (defn, 1, m.definition_length, f) != m.definition_length)
+ goto error;
+
+ h = cpp_lookup (r, name, m.name_length);
+
+ if (m.flags & NODE_POISONED)
+ h->flags |= NODE_POISONED | NODE_DIAGNOSTIC;
+ else
+ {
+ if (cpp_push_buffer (r, defn, m.definition_length, 0, "") != NULL)
+ {
+ r->buffer->from_stage3 = 1;
+ if (!_cpp_create_definition (r, h))
+ abort ();
+ _cpp_pop_buffer (r);
+ }
+ else
+ abort ();
+ }
+ }
+
+ r->state = old_state;
+ free (defn);
+ free (name);
+ defn = NULL;
+ name = NULL;
+ return 0;
+
+ error:
+ cpp_error_from_errno (r, "while reading precompiled header");
+ return -1;
+}
diff --git a/gcc/cselib.c b/gcc/cselib.c
index 6498d869b16..651baced906 100644
--- a/gcc/cselib.c
+++ b/gcc/cselib.c
@@ -1357,7 +1357,7 @@ cselib_init ()
cselib_startobj = obstack_alloc (&cselib_obstack, 0);
callmem = gen_rtx_MEM (BLKmode, const0_rtx);
- ggc_add_rtx_root (&callmem, 1);
+ ggc_add_rtx_root (&callmem, 1, "callmem");
}
cselib_nregs = max_reg_num ();
diff --git a/gcc/dbxout.c b/gcc/dbxout.c
index bfb6b0e8d51..69c7be13704 100644
--- a/gcc/dbxout.c
+++ b/gcc/dbxout.c
@@ -136,6 +136,22 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
/* Typical USG systems don't have stab.h, and they also have
no use for DBX-format debugging info. */
+#define MINIMAL_DEBUG 1
+
+#ifdef NO_DOLLAR_IN_LABEL
+#ifdef NO_DOT_IN_LABEL
+#undef MINIMAL_DEBUG
+#define MINIMAL_DEBUG 0
+#endif
+#endif
+
+/* This is used by ASM_OUTPUT_SOURCE_LINE in dbxelf.h and dbxcoff.h. */
+static int sym_lineno;
+
+/* Used by dbxout_function_end. */
+static int scope_labelno;
+
+
#if defined (DBX_DEBUGGING_INFO) || defined (XCOFF_DEBUGGING_INFO)
/* Nonzero if we have actually used any of the GDB extensions
@@ -219,6 +235,10 @@ struct typeinfo *typevec;
static int typevec_len;
+/* How large is *typevec, anyway? */
+static size_t dbx_typevec_size_fetcher PARAMS ((const void *,
+ type_definition_p));
+
/* In dbx output, each type gets a unique number.
This is the number for the next type output.
The number, once assigned, is in the TYPE_SYMTAB_ADDRESS field. */
@@ -238,6 +258,11 @@ struct dbx_file
int next_type_number;
};
+static const struct field_definition_s dbx_file_field_defs[] = {
+ { 0, 0, offsetof (struct dbx_file, next), dbx_file_type_def },
+ NO_MORE_FIELDS
+};
+
/* This is the top of the stack. */
static struct dbx_file *current_file;
@@ -380,7 +405,6 @@ struct gcc_debug_hooks xcoff_debug_hooks =
static void
dbxout_function_end ()
{
- static int scope_labelno = 0;
char lscope_label_name[100];
/* Convert Ltext into the appropriate format for local labels in case
the system doesn't insert underscores in front of user generated
@@ -398,6 +422,14 @@ dbxout_function_end ()
fprintf (asmfile, "\n");
}
+static size_t
+dbx_typevec_size_fetcher (v, td)
+ const void *v ATTRIBUTE_UNUSED;
+ type_definition_p td ATTRIBUTE_UNUSED;
+{
+ return typevec_len * sizeof (typevec[0]);
+}
+
/* At the beginning of compilation, start writing the symbol table.
Initialize `typevec' and output the standard data types of C. */
@@ -466,12 +498,34 @@ dbxout_init (input_file_name)
next_type_number = 1;
+ add_untyped_address (&data_to_save, &sym_lineno, sizeof (sym_lineno),"sym_lineno");
+ add_untyped_address (&data_to_save, &scope_labelno, sizeof (scope_labelno), "scope_labelno");
+ add_untyped_address (&data_to_save, &have_used_extensions,
+ sizeof (have_used_extensions), "have_used_extensions");
+ add_untyped_address (&data_to_save, &source_label_number,
+ sizeof (source_label_number), "source_label_number");
+#if 0
+ add_typed_addresses (&data_to_save, (void **)&lastfile,
+ string_type_def, 1);
+#endif
+ add_untyped_address (&data_to_save, &typevec_len,
+ sizeof (typevec_len),"typevec_len");
+ dbx_typevec_type_def->size_fetcher = dbx_typevec_size_fetcher;
+ add_typed_addresses (&data_to_save, (void **)&typevec,
+ dbx_typevec_type_def, 1,"typevec");
+ add_untyped_address (&data_to_save, &next_type_number,
+ sizeof (next_type_number),"next_type_number");
+
#ifdef DBX_USE_BINCL
current_file = (struct dbx_file *) xmalloc (sizeof *current_file);
current_file->next = NULL;
current_file->file_number = 0;
current_file->next_type_number = 1;
next_file_number = 1;
+ add_typed_addresses (&data_to_save, (void **)&current_file,
+ dbx_file_type_def, 1, "current_file");
+ add_untyped_address (&data_to_save, &next_file_number,
+ sizeof (next_file_number), "next_file_number");
#endif
/* Make sure that types `int' and `char' have numbers 1 and 2.
@@ -1025,7 +1079,10 @@ dbxout_range_type (type)
If FULL is nonzero, and the type has been described only with
a forward-reference, output the definition now.
If FULL is zero in this case, just refer to the forward-reference
- using the number previously allocated. */
+ using the number previously allocated.
+
+ If SHOW_ARG_TYPES is nonzero, we output a description of the argument
+ types for a METHOD_TYPE. */
static void
dbxout_type (type, full)
diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index 062b9257433..6b457a71471 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -3708,7 +3708,7 @@ static rtx
save_rtx (orig)
register rtx orig;
{
- VARRAY_PUSH_RTX (used_rtx_varray, orig);
+ VARRAY_PUSH_RTX (used_rtx_varray, orig);
return orig;
}
@@ -11598,7 +11598,7 @@ dwarf2out_init (main_input_filename)
/* Allocate the initial hunk of the decl_scope_table. */
VARRAY_TREE_INIT (decl_scope_table, 256, "decl_scope_table");
- ggc_add_tree_varray_root (&decl_scope_table, 1);
+ ggc_add_tree_varray_root (&decl_scope_table, 1, "decl_scope_table");
/* Allocate the initial hunk of the abbrev_die_table. */
abbrev_die_table
@@ -11624,10 +11624,10 @@ dwarf2out_init (main_input_filename)
comp_unit_die = gen_compile_unit_die (main_input_filename);
VARRAY_TREE_INIT (incomplete_types, 64, "incomplete_types");
- ggc_add_tree_varray_root (&incomplete_types, 1);
+ ggc_add_tree_varray_root (&incomplete_types, 1, "incomplete_types");
VARRAY_RTX_INIT (used_rtx_varray, 32, "used_rtx_varray");
- ggc_add_rtx_varray_root (&used_rtx_varray, 1);
+ ggc_add_rtx_varray_root (&used_rtx_varray, 1, "used_rtx_varray");
ASM_GENERATE_INTERNAL_LABEL (text_end_label, TEXT_END_LABEL, 0);
ASM_GENERATE_INTERNAL_LABEL (abbrev_section_label,
diff --git a/gcc/emit-rtl.c b/gcc/emit-rtl.c
index eeb5128fec9..967002e0d0b 100644
--- a/gcc/emit-rtl.c
+++ b/gcc/emit-rtl.c
@@ -586,6 +586,10 @@ gen_rtvec VPARAMS ((int n, ...))
VA_OPEN (p, n);
VA_FIXEDARG (p, int, n);
+#ifndef ANSI_PROTOTYPES
+ n = va_arg (p, int);
+#endif
+
if (n == 0)
return NULL_RTVEC; /* Don't allocate an empty rtvec... */
@@ -1716,13 +1720,11 @@ set_mem_alias_set (mem, set)
HOST_WIDE_INT set;
{
/* It would be nice to enable this check, but we can't quite yet. */
-#if 0
#ifdef ENABLE_CHECKING
/* If the new and old alias sets don't conflict, something is wrong. */
if (!alias_sets_conflict_p (set, MEM_ALIAS_SET (mem)))
abort ();
#endif
-#endif
MEM_ATTRS (mem) = get_mem_attrs (set, MEM_DECL (mem), MEM_OFFSET (mem),
MEM_SIZE (mem), MEM_ALIGN (mem));
@@ -4443,11 +4445,16 @@ init_emit_once (line_numbers)
/* Initialize the CONST_INT and memory attribute hash tables. */
const_int_htab = htab_create (37, const_int_htab_hash,
const_int_htab_eq, NULL);
- ggc_add_deletable_htab (const_int_htab, 0, 0);
+#if 0
+ ggc_add_root (&const_int_htab, 1, sizeof (const_int_htab),
+ rtx_htab_mark, "const_int_htab");
+#else
+ ggc_add_deletable_htab (const_int_htab, 0, 0, "const_int_htab");
mem_attrs_htab = htab_create (37, mem_attrs_htab_hash,
mem_attrs_htab_eq, NULL);
- ggc_add_deletable_htab (mem_attrs_htab, 0, mem_attrs_mark);
+ ggc_add_deletable_htab (mem_attrs_htab, 0, mem_attrs_mark, "mem_attrs_htab");
+#endif
no_line_numbers = ! line_numbers;
@@ -4503,7 +4510,9 @@ init_emit_once (line_numbers)
virtual_cfa_rtx = gen_raw_REG (Pmode, VIRTUAL_CFA_REGNUM);
/* These rtx must be roots if GC is enabled. */
- ggc_add_rtx_root (global_rtl, GR_MAX);
+ ggc_add_rtx_root (global_rtl, GR_MAX, "global_rtl");
+
+ add_rtx_addresses (&known_pointers, global_rtl, GR_MAX, "global_rtl");
#ifdef INIT_EXPANDERS
/* This is to initialize {init|mark|free}_machine_status before the first
@@ -4520,7 +4529,10 @@ init_emit_once (line_numbers)
for (i = - MAX_SAVED_CONST_INT; i <= MAX_SAVED_CONST_INT; i++)
const_int_rtx[i + MAX_SAVED_CONST_INT] =
gen_rtx_raw_CONST_INT (VOIDmode, i);
- ggc_add_rtx_root (const_int_rtx, 2 * MAX_SAVED_CONST_INT + 1);
+ ggc_add_rtx_root (const_int_rtx, 2 * MAX_SAVED_CONST_INT + 1, "const_int_rtx");
+ add_rtx_addresses (&known_pointers, const_int_rtx,
+ 2 * MAX_SAVED_CONST_INT + 1, "const_int_rtx");
+
if (STORE_FLAG_VALUE >= - MAX_SAVED_CONST_INT
&& STORE_FLAG_VALUE <= MAX_SAVED_CONST_INT)
@@ -4582,8 +4594,12 @@ init_emit_once (line_numbers)
/* For bounded pointers, `&const_tiny_rtx[0][0]' is not the same as
`(rtx *) const_tiny_rtx'. The former has bounds that only cover
`const_tiny_rtx[0]', whereas the latter has bounds that cover all. */
- ggc_add_rtx_root ((rtx *) const_tiny_rtx, sizeof const_tiny_rtx / sizeof (rtx));
- ggc_add_rtx_root (&const_true_rtx, 1);
+ ggc_add_rtx_root ((rtx *) const_tiny_rtx, sizeof const_tiny_rtx / sizeof (rtx), "const_tiny_rtx");
+ add_rtx_addresses (&known_pointers, (rtx *) const_tiny_rtx,
+ sizeof const_tiny_rtx / sizeof (rtx), "const_tiny_rtx");
+ ggc_add_rtx_root (&const_true_rtx, 1, "const_true_rtx");
+ add_rtx_addresses (&known_pointers, &const_true_rtx, 1, "const_true_rtx");
+
#ifdef RETURN_ADDRESS_POINTER_REGNUM
return_address_pointer_rtx
@@ -4632,12 +4648,19 @@ init_emit_once (line_numbers)
if (PIC_OFFSET_TABLE_REGNUM != INVALID_REGNUM)
pic_offset_table_rtx = gen_rtx_REG (Pmode, PIC_OFFSET_TABLE_REGNUM);
- ggc_add_rtx_root (&pic_offset_table_rtx, 1);
- ggc_add_rtx_root (&struct_value_rtx, 1);
- ggc_add_rtx_root (&struct_value_incoming_rtx, 1);
- ggc_add_rtx_root (&static_chain_rtx, 1);
- ggc_add_rtx_root (&static_chain_incoming_rtx, 1);
- ggc_add_rtx_root (&return_address_pointer_rtx, 1);
+ ggc_add_rtx_root (&pic_offset_table_rtx, 1, "pic_offset_table_rtx");
+ ggc_add_rtx_root (&struct_value_rtx, 1, "struct_value_rtx");
+ ggc_add_rtx_root (&struct_value_incoming_rtx, 1, "struct_value_incoming_rtx");
+ ggc_add_rtx_root (&static_chain_rtx, 1, "static_chain_rtx");
+ ggc_add_rtx_root (&static_chain_incoming_rtx, 1, "static_chain_incoming_rtx");
+ ggc_add_rtx_root (&return_address_pointer_rtx, 1, "return_address_pointer_rtx");
+ add_rtx_addresses (&known_pointers, &pic_offset_table_rtx, 1, "pic_offset_table_rtx");
+ add_rtx_addresses (&known_pointers, &struct_value_rtx, 1, "struct_value");
+ add_rtx_addresses (&known_pointers, &struct_value_incoming_rtx, 1, "struct_value_incoming");
+ add_rtx_addresses (&known_pointers, &static_chain_rtx, 1, "static_chain_rtx");
+ add_rtx_addresses (&known_pointers, &static_chain_incoming_rtx, 1, "static_chain_incoming_rtx");
+ add_rtx_addresses (&known_pointers, &return_address_pointer_rtx, 1, "return_address_pointer");
+
}
/* Query and clear/ restore no_line_numbers. This is used by the
diff --git a/gcc/except.c b/gcc/except.c
index 6b345feb8d0..8b1a57db176 100644
--- a/gcc/except.c
+++ b/gcc/except.c
@@ -367,13 +367,13 @@ doing_eh (do_warn)
void
init_eh ()
{
- ggc_add_rtx_root (&exception_handler_labels, 1);
+ ggc_add_rtx_root (&exception_handler_labels, 1, "exception_handler_labels");
if (! flag_exceptions)
return;
type_to_runtime_map = htab_create (31, t2r_hash, t2r_eq, NULL);
- ggc_add_root (&type_to_runtime_map, 1, sizeof (htab_t), t2r_mark);
+ ggc_add_root (&type_to_runtime_map, 1, sizeof (htab_t), t2r_mark, "type_to_runtime_map");
/* Create the SjLj_Function_Context structure. This should match
the definition in unwind-sjlj.c. */
@@ -382,7 +382,7 @@ init_eh ()
tree f_jbuf, f_per, f_lsda, f_prev, f_cs, f_data, tmp;
sjlj_fc_type_node = make_lang_type (RECORD_TYPE);
- ggc_add_tree_root (&sjlj_fc_type_node, 1);
+ ggc_add_tree_root (&sjlj_fc_type_node, 1, "sjlj_fc_type_node");
f_prev = build_decl (FIELD_DECL, get_identifier ("__prev"),
build_pointer_type (sjlj_fc_type_node));
diff --git a/gcc/expr.c b/gcc/expr.c
index 7d23c7ac824..87a272faf3f 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -1774,7 +1774,7 @@ emit_block_move (x, y, size, align)
fntype = build_pointer_type (void_type_node);
fntype = build_function_type (fntype, NULL_TREE);
fn = build_decl (FUNCTION_DECL, fn, fntype);
- ggc_add_tree_root (&fn, 1);
+ ggc_add_tree_root (&fn, 1, "fn");
DECL_EXTERNAL (fn) = 1;
TREE_PUBLIC (fn) = 1;
DECL_ARTIFICIAL (fn) = 1;
@@ -2671,7 +2671,7 @@ clear_storage (object, size, align)
fntype = build_pointer_type (void_type_node);
fntype = build_function_type (fntype, NULL_TREE);
fn = build_decl (FUNCTION_DECL, fn, fntype);
- ggc_add_tree_root (&fn, 1);
+ ggc_add_tree_root (&fn, 1, "fn");
DECL_EXTERNAL (fn) = 1;
TREE_PUBLIC (fn) = 1;
DECL_ARTIFICIAL (fn) = 1;
@@ -5955,6 +5955,69 @@ check_max_integer_computation_mode (exp)
}
#endif
+/* Return an object on the placeholder list that matches EXP, a
+ PLACEHOLDER_EXPR. An object "matches" if it is of the type of the
+ PLACEHOLDER_EXPR or a pointer type to it. For further information,
+ see tree.def. If no such object is found, abort. If PLIST is nonzero,
+ it is a location into which a pointer into the placeholder list at
+ which the object is found is placed. */
+
+tree
+find_placeholder (exp, plist)
+ tree exp;
+ tree *plist;
+{
+ tree type = TREE_TYPE (exp);
+ tree placeholder_expr;
+
+ for (placeholder_expr = placeholder_list; placeholder_expr != 0;
+ placeholder_expr = TREE_CHAIN (placeholder_expr))
+ {
+ tree need_type = TYPE_MAIN_VARIANT (type);
+ tree elt;
+
+ /* Find the outermost reference that is of the type we want. If none,
+ see if any object has a type that is a pointer to the type we
+ want. */
+ for (elt = TREE_PURPOSE (placeholder_expr); elt != 0;
+ elt = ((TREE_CODE (elt) == COMPOUND_EXPR
+ || TREE_CODE (elt) == COND_EXPR)
+ ? TREE_OPERAND (elt, 1)
+ : (TREE_CODE_CLASS (TREE_CODE (elt)) == 'r'
+ || TREE_CODE_CLASS (TREE_CODE (elt)) == '1'
+ || TREE_CODE_CLASS (TREE_CODE (elt)) == '2'
+ || TREE_CODE_CLASS (TREE_CODE (elt)) == 'e')
+ ? TREE_OPERAND (elt, 0) : 0))
+ if (TYPE_MAIN_VARIANT (TREE_TYPE (elt)) == need_type)
+ {
+ if (plist)
+ *plist = placeholder_expr;
+ return elt;
+ }
+
+ for (elt = TREE_PURPOSE (placeholder_expr); elt != 0;
+ elt
+ = ((TREE_CODE (elt) == COMPOUND_EXPR
+ || TREE_CODE (elt) == COND_EXPR)
+ ? TREE_OPERAND (elt, 1)
+ : (TREE_CODE_CLASS (TREE_CODE (elt)) == 'r'
+ || TREE_CODE_CLASS (TREE_CODE (elt)) == '1'
+ || TREE_CODE_CLASS (TREE_CODE (elt)) == '2'
+ || TREE_CODE_CLASS (TREE_CODE (elt)) == 'e')
+ ? TREE_OPERAND (elt, 0) : 0))
+ if (POINTER_TYPE_P (TREE_TYPE (elt))
+ && (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (elt)))
+ == need_type))
+ {
+ if (plist)
+ *plist = placeholder_expr;
+ return build1 (INDIRECT_REF, need_type, elt);
+ }
+ }
+
+ abort ();
+}
+
/* expand_expr: generate code for computing expression EXP.
An rtx for the computed value is returned. The value is never null.
In the case of a void EXP, const0_rtx is returned.
@@ -6482,66 +6545,14 @@ expand_expr (exp, target, tmode, modifier)
case PLACEHOLDER_EXPR:
{
+ tree old_list = placeholder_list;
tree placeholder_expr;
- /* If there is an object on the head of the placeholder list,
- see if some object in it of type TYPE or a pointer to it. For
- further information, see tree.def. */
- for (placeholder_expr = placeholder_list;
- placeholder_expr != 0;
- placeholder_expr = TREE_CHAIN (placeholder_expr))
- {
- tree need_type = TYPE_MAIN_VARIANT (type);
- tree object = 0;
- tree old_list = placeholder_list;
- tree elt;
-
- /* Find the outermost reference that is of the type we want.
- If none, see if any object has a type that is a pointer to
- the type we want. */
- for (elt = TREE_PURPOSE (placeholder_expr);
- elt != 0 && object == 0;
- elt
- = ((TREE_CODE (elt) == COMPOUND_EXPR
- || TREE_CODE (elt) == COND_EXPR)
- ? TREE_OPERAND (elt, 1)
- : (TREE_CODE_CLASS (TREE_CODE (elt)) == 'r'
- || TREE_CODE_CLASS (TREE_CODE (elt)) == '1'
- || TREE_CODE_CLASS (TREE_CODE (elt)) == '2'
- || TREE_CODE_CLASS (TREE_CODE (elt)) == 'e')
- ? TREE_OPERAND (elt, 0) : 0))
- if (TYPE_MAIN_VARIANT (TREE_TYPE (elt)) == need_type)
- object = elt;
-
- for (elt = TREE_PURPOSE (placeholder_expr);
- elt != 0 && object == 0;
- elt
- = ((TREE_CODE (elt) == COMPOUND_EXPR
- || TREE_CODE (elt) == COND_EXPR)
- ? TREE_OPERAND (elt, 1)
- : (TREE_CODE_CLASS (TREE_CODE (elt)) == 'r'
- || TREE_CODE_CLASS (TREE_CODE (elt)) == '1'
- || TREE_CODE_CLASS (TREE_CODE (elt)) == '2'
- || TREE_CODE_CLASS (TREE_CODE (elt)) == 'e')
- ? TREE_OPERAND (elt, 0) : 0))
- if (POINTER_TYPE_P (TREE_TYPE (elt))
- && (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (elt)))
- == need_type))
- object = build1 (INDIRECT_REF, need_type, elt);
-
- if (object != 0)
- {
- /* Expand this object skipping the list entries before
- it was found in case it is also a PLACEHOLDER_EXPR.
- In that case, we want to translate it using subsequent
- entries. */
- placeholder_list = TREE_CHAIN (placeholder_expr);
- temp = expand_expr (object, original_target, tmode,
- ro_modifier);
- placeholder_list = old_list;
- return temp;
- }
- }
+ exp = find_placeholder (exp, &placeholder_expr);
+ placeholder_list = TREE_CHAIN (placeholder_expr);
+ temp = expand_expr (exp, original_target, tmode, ro_modifier);
+ placeholder_list = old_list;
+ return temp;
}
/* We can't find the object or there was a missing WITH_RECORD_EXPR. */
@@ -6923,6 +6934,7 @@ expand_expr (exp, target, tmode, modifier)
tree tem = get_inner_reference (exp, &bitsize, &bitpos, &offset,
&mode1, &unsignedp, &volatilep,
&alignment);
+ rtx orig_op0;
/* If we got back the original object, something is wrong. Perhaps
we are evaluating an expression too early. In any event, don't
@@ -6934,15 +6946,16 @@ expand_expr (exp, target, tmode, modifier)
computation, since it will need a temporary and TARGET is known
to have to do. This occurs in unchecked conversion in Ada. */
- op0 = expand_expr (tem,
- (TREE_CODE (TREE_TYPE (tem)) == UNION_TYPE
- && (TREE_CODE (TYPE_SIZE (TREE_TYPE (tem)))
- != INTEGER_CST)
- ? target : NULL_RTX),
- VOIDmode,
- (modifier == EXPAND_INITIALIZER
- || modifier == EXPAND_CONST_ADDRESS)
- ? modifier : EXPAND_NORMAL);
+ orig_op0 = op0
+ = expand_expr (tem,
+ (TREE_CODE (TREE_TYPE (tem)) == UNION_TYPE
+ && (TREE_CODE (TYPE_SIZE (TREE_TYPE (tem)))
+ != INTEGER_CST)
+ ? target : NULL_RTX),
+ VOIDmode,
+ (modifier == EXPAND_INITIALIZER
+ || modifier == EXPAND_CONST_ADDRESS)
+ ? modifier : EXPAND_NORMAL);
/* If this is a constant, put it into a register if it is a
legitimate constant and OFFSET is 0 and memory if it isn't. */
@@ -7031,7 +7044,9 @@ expand_expr (exp, target, tmode, modifier)
/* Don't forget about volatility even if this is a bitfield. */
if (GET_CODE (op0) == MEM && volatilep && ! MEM_VOLATILE_P (op0))
{
- op0 = copy_rtx (op0);
+ if (op0 == orig_op0)
+ op0 = copy_rtx (op0);
+
MEM_VOLATILE_P (op0) = 1;
}
@@ -7173,6 +7188,9 @@ expand_expr (exp, target, tmode, modifier)
else
op0 = adjust_address (op0, mode1, bitpos / BITS_PER_UNIT);
+ if (op0 == orig_op0)
+ op0 = copy_rtx (op0);
+
set_mem_attributes (op0, exp, 0);
if (GET_CODE (XEXP (op0, 0)) == REG)
mark_reg_pointer (XEXP (op0, 0), alignment);
diff --git a/gcc/expr.h b/gcc/expr.h
index 9addf7f7326..62e90b0d211 100644
--- a/gcc/expr.h
+++ b/gcc/expr.h
@@ -498,13 +498,19 @@ extern rtx store_expr PARAMS ((tree, rtx, int));
Useful after calling expand_expr with 1 as sum_ok. */
extern rtx force_operand PARAMS ((rtx, rtx));
-#ifdef TREE_CODE
+/* Return an object on the placeholder list that matches EXP, a
+ PLACEHOLDER_EXPR. An object "matches" if it is of the type of the
+ PLACEHOLDER_EXPR or a pointer type to it. For further information,
+ see tree.def. If no such object is found, abort. If PLIST is nonzero,
+ it is a location into which a pointer into the placeholder list at
+ which the object is found is placed. */
+extern tree find_placeholder PARAMS ((tree, tree *));
+
/* Generate code for computing expression EXP.
An rtx for the computed value is returned. The value is never null.
In the case of a void EXP, const0_rtx is returned. */
extern rtx expand_expr PARAMS ((tree, rtx, enum machine_mode,
enum expand_modifier));
-#endif
/* At the start of a function, record that we have no previously-pushed
arguments waiting to be popped. */
diff --git a/gcc/f/com.c b/gcc/f/com.c
index 8d9ad8c217a..f5372ffb355 100644
--- a/gcc/f/com.c
+++ b/gcc/f/com.c
@@ -9366,7 +9366,7 @@ ffecom_type_namelist_ ()
TYPE_FIELDS (type) = namefield;
layout_type (type);
- ggc_add_tree_root (&type, 1);
+ ggc_add_tree_root (&type, 1, "type");
}
return type;
@@ -9399,7 +9399,7 @@ ffecom_type_vardesc_ ()
TYPE_FIELDS (type) = namefield;
layout_type (type);
- ggc_add_tree_root (&type, 1);
+ ggc_add_tree_root (&type, 1, "type");
}
return type;
@@ -14544,19 +14544,19 @@ init_decl_processing ()
/* Record our roots. */
for (i = 0; i < ARRAY_SIZE (tree_roots); i++)
- ggc_add_tree_root (tree_roots[i], 1);
+ ggc_add_tree_root (tree_roots[i], 1, "tree_roots[i]");
ggc_add_tree_root (&ffecom_tree_type[0][0],
- FFEINFO_basictype*FFEINFO_kindtype);
+ FFEINFO_basictype*FFEINFO_kindtype, "ffecom_tree_type[0][0]");
ggc_add_tree_root (&ffecom_tree_fun_type[0][0],
- FFEINFO_basictype*FFEINFO_kindtype);
+ FFEINFO_basictype*FFEINFO_kindtype, "ffecom_tree_fun_type[0][0]");
ggc_add_tree_root (&ffecom_tree_ptr_to_fun_type[0][0],
- FFEINFO_basictype*FFEINFO_kindtype);
- ggc_add_tree_root (ffecom_gfrt_, FFECOM_gfrt);
+ FFEINFO_basictype*FFEINFO_kindtype, "ffecom_tree_ptr_to_fun_type[0][0]");
+ ggc_add_tree_root (ffecom_gfrt_, FFECOM_gfrt, "ffecom_gfrt_");
ggc_add_root (&current_binding_level, 1, sizeof current_binding_level,
- mark_binding_level);
+ mark_binding_level, "current_binding_level");
ggc_add_root (&free_binding_level, 1, sizeof current_binding_level,
- mark_binding_level);
- ggc_add_root (&tracker_head, 1, sizeof tracker_head, mark_tracker_head);
+ mark_binding_level, "free_binding_level");
+ ggc_add_root (&tracker_head, 1, sizeof tracker_head, mark_tracker_head, "tracker_head");
ffe_init_0 ();
}
diff --git a/gcc/f/ste.c b/gcc/f/ste.c
index 5b4c68eb2d1..3e6075a620c 100644
--- a/gcc/f/ste.c
+++ b/gcc/f/ste.c
@@ -1223,7 +1223,7 @@ ffeste_io_ialist_ (bool have_err,
TYPE_FIELDS (ref) = errfield;
layout_type (ref);
- ggc_add_tree_root (&f2c_alist_struct, 1);
+ ggc_add_tree_root (&f2c_alist_struct, 1, "f2c_alist_struct");
f2c_alist_struct = ref;
}
@@ -1357,7 +1357,7 @@ ffeste_io_cilist_ (bool have_err,
TYPE_FIELDS (ref) = errfield;
layout_type (ref);
- ggc_add_tree_root (&f2c_cilist_struct, 1);
+ ggc_add_tree_root (&f2c_cilist_struct, 1, "f2c_cilist_struct");
f2c_cilist_struct = ref;
}
@@ -1575,7 +1575,7 @@ ffeste_io_cllist_ (bool have_err,
TYPE_FIELDS (ref) = errfield;
layout_type (ref);
- ggc_add_tree_root (&f2c_close_struct, 1);
+ ggc_add_tree_root (&f2c_close_struct, 1, "f2c_close_struct");
f2c_close_struct = ref;
}
@@ -1699,7 +1699,7 @@ ffeste_io_icilist_ (bool have_err,
TYPE_FIELDS (ref) = errfield;
layout_type (ref);
- ggc_add_tree_root (&f2c_icilist_struct, 1);
+ ggc_add_tree_root (&f2c_icilist_struct, 1, "f2c_icilist_struct");
f2c_icilist_struct = ref;
}
@@ -1997,7 +1997,7 @@ ffeste_io_inlist_ (bool have_err,
TYPE_FIELDS (ref) = errfield;
layout_type (ref);
- ggc_add_tree_root (&f2c_inquire_struct, 1);
+ ggc_add_tree_root (&f2c_inquire_struct, 1, "f2c_inquire_struct");
f2c_inquire_struct = ref;
}
@@ -2203,7 +2203,7 @@ ffeste_io_olist_ (bool have_err,
TYPE_FIELDS (ref) = errfield;
layout_type (ref);
- ggc_add_tree_root (&f2c_open_struct, 1);
+ ggc_add_tree_root (&f2c_open_struct, 1 ,"f2c_open_struct" );
f2c_open_struct = ref;
}
diff --git a/gcc/f/version.c b/gcc/f/version.c
index 9c7f6249b00..405e1a41bdc 100644
--- a/gcc/f/version.c
+++ b/gcc/f/version.c
@@ -1 +1 @@
-const char *const ffe_version_string = "0.5.27 20011001 (experimental)";
+const char *const ffe_version_string = "0.5.27 20011002 (experimental)";
diff --git a/gcc/f/where.c b/gcc/f/where.c
index 9f853545c67..805435eb221 100644
--- a/gcc/f/where.c
+++ b/gcc/f/where.c
@@ -175,7 +175,7 @@ ffewhere_file_new (const char *name, size_t length)
if (ffewhere_head == NULL)
{
ggc_add_root (&ffewhere_head, 1, sizeof ffewhere_head,
- mark_ffewhere_head);
+ mark_ffewhere_head, "&ffewhere_head");
filepos = NUM_FFEWHERE_HEAD_FILES;
}
else
diff --git a/gcc/flags.h b/gcc/flags.h
index bd29cea1cde..11e115706bc 100644
--- a/gcc/flags.h
+++ b/gcc/flags.h
@@ -66,6 +66,10 @@ extern int optimize_size;
extern int quiet_flag;
+/* Print compiler version information. -v. */
+
+extern int version_flag;
+
/* Print times taken by the various passes. -ftime-report. */
extern int time_report;
diff --git a/gcc/flow.c b/gcc/flow.c
index 311f8d8b726..a0ea335faee 100644
--- a/gcc/flow.c
+++ b/gcc/flow.c
@@ -296,7 +296,7 @@ static void mark_regs_live_at_end PARAMS ((regset));
static int set_phi_alternative_reg PARAMS ((rtx, int, int, void *));
static void calculate_global_regs_live PARAMS ((sbitmap, sbitmap, int));
static void propagate_block_delete_insn PARAMS ((basic_block, rtx));
-static rtx propagate_block_delete_libcall PARAMS ((basic_block, rtx, rtx));
+static rtx propagate_block_delete_libcall PARAMS ((rtx, rtx));
static int insn_dead_p PARAMS ((struct propagate_block_info *,
rtx, int, rtx));
static int libcall_dead_p PARAMS ((struct propagate_block_info *,
@@ -1376,8 +1376,7 @@ propagate_block_delete_insn (bb, insn)
before the libcall. */
static rtx
-propagate_block_delete_libcall (bb, insn, note)
- basic_block bb;
+propagate_block_delete_libcall ( insn, note)
rtx insn, note;
{
rtx first = XEXP (note, 0);
@@ -1442,7 +1441,7 @@ propagate_one_insn (pbi, insn)
pbi->cc0_live = 0;
if (libcall_is_dead)
- prev = propagate_block_delete_libcall (pbi->bb, insn, note);
+ prev = propagate_block_delete_libcall ( insn, note);
else
propagate_block_delete_insn (pbi->bb, insn);
diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index 484d9c63970..007d25df9f2 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -1935,9 +1935,9 @@ size_int_type_wide (number, type)
if (size_htab == 0)
{
size_htab = htab_create (1024, size_htab_hash, size_htab_eq, NULL);
- ggc_add_deletable_htab (size_htab, NULL, NULL);
+ ggc_add_deletable_htab (size_htab, NULL, NULL, "size_htab");
new_const = make_node (INTEGER_CST);
- ggc_add_tree_root (&new_const, 1);
+ ggc_add_tree_root (&new_const, 1, "new_const");
}
/* Adjust NEW_CONST to be the constant we want. If it's already in the
diff --git a/gcc/function.c b/gcc/function.c
index fed2b3b68c7..b41e1320497 100644
--- a/gcc/function.c
+++ b/gcc/function.c
@@ -145,6 +145,9 @@ tree inline_function_decl;
/* The currently compiled function. */
struct function *cfun = 0;
+/* Global list of all compiled functions. */
+struct function *all_functions = 0;
+
/* These arrays record the INSN_UIDs of the prologue and epilogue insns. */
static varray_type prologue;
static varray_type epilogue;
@@ -302,13 +305,13 @@ static bool insns_for_mem_comp PARAMS ((hash_table_key, hash_table_key));
static int insns_for_mem_walk PARAMS ((rtx *, void *));
static void compute_insns_for_mem PARAMS ((rtx, rtx, struct hash_table *));
static void mark_function_status PARAMS ((struct function *));
-static void maybe_mark_struct_function PARAMS ((void *));
+static void mark_function_chain PARAMS ((void *));
static void prepare_function_start PARAMS ((void));
static void do_clobber_return_reg PARAMS ((rtx, void *));
static void do_use_return_reg PARAMS ((rtx, void *));
/* Pointer to chain of `struct function' for containing functions. */
-static struct function *outer_function_chain;
+struct function *outer_function_chain;
/* Given a function decl for a containing function,
return the `struct function' for it. */
@@ -319,7 +322,7 @@ find_function_data (decl)
{
struct function *p;
- for (p = outer_function_chain; p; p = p->outer)
+ for (p = outer_function_chain; p; p = p->next)
if (p->decl == decl)
return p;
@@ -336,24 +339,21 @@ void
push_function_context_to (context)
tree context;
{
- struct function *p;
+ struct function *p, *context_data;
if (context)
{
- if (context == current_function_decl)
- cfun->contains_functions = 1;
- else
- {
- struct function *containing = find_function_data (context);
- containing->contains_functions = 1;
- }
+ context_data = (context == current_function_decl
+ ? cfun
+ : find_function_data (context));
+ context_data->contains_functions = 1;
}
if (cfun == 0)
init_dummy_function_start ();
p = cfun;
- p->outer = outer_function_chain;
+ p->next = outer_function_chain;
outer_function_chain = p;
p->fixup_var_refs_queue = 0;
@@ -380,7 +380,7 @@ pop_function_context_from (context)
struct var_refs_queue *queue;
cfun = p;
- outer_function_chain = p->outer;
+ outer_function_chain = p->next;
current_function_decl = p->decl;
reg_renumber = 0;
@@ -1330,13 +1330,10 @@ put_var_into_stack (decl)
/* Get the mode it's actually stored in. */
promoted_mode = GET_MODE (reg);
- /* If this variable comes from an outer function, find that
- function's saved context. Don't use find_function_data here,
- because it might not be in any active function.
- FIXME: Is that really supposed to happen?
- It does in ObjC at least. */
+ /* If this variable comes from an outer function,
+ find that function's saved context. */
if (context != current_function_decl && context != inline_function_decl)
- for (function = outer_function_chain; function; function = function->outer)
+ for (function = outer_function_chain; function; function = function->next)
if (function->decl == context)
break;
@@ -5510,7 +5507,12 @@ fix_lexical_addr (addr, var)
if (context == current_function_decl || context == inline_function_decl)
return addr;
- fp = find_function_data (context);
+ for (fp = outer_function_chain; fp; fp = fp->next)
+ if (fp->decl == context)
+ break;
+
+ if (fp == 0)
+ abort ();
if (GET_CODE (addr) == ADDRESSOF && GET_CODE (XEXP (addr, 0)) == MEM)
addr = XEXP (XEXP (addr, 0), 0);
@@ -5594,7 +5596,7 @@ trampoline_address (function)
return
adjust_trampoline_addr (XEXP (RTL_EXPR_RTL (TREE_VALUE (link)), 0));
- for (fp = outer_function_chain; fp; fp = fp->outer)
+ for (fp = outer_function_chain; fp; fp = fp->next)
for (link = fp->x_trampoline_list; link; link = TREE_CHAIN (link))
if (TREE_PURPOSE (link) == function)
{
@@ -5610,7 +5612,9 @@ trampoline_address (function)
fn_context = decl_function_context (function);
if (fn_context != current_function_decl
&& fn_context != inline_function_decl)
- fp = find_function_data (fn_context);
+ for (fp = outer_function_chain; fp; fp = fp->next)
+ if (fp->decl == fn_context)
+ break;
/* Allocate run-time space for this trampoline
(usually in the defining function's stack frame). */
@@ -6208,6 +6212,10 @@ init_function_start (subr, filename, line)
{
prepare_function_start ();
+ /* Remember this function for later. */
+ cfun->next_global = all_functions;
+ all_functions = cfun;
+
current_function_name = (*decl_printable_name) (subr, 2);
cfun->decl = subr;
@@ -7628,21 +7636,6 @@ mark_function_status (p)
mark_hard_reg_initial_vals (p);
}
-/* Mark the struct function pointed to by *ARG for GC, if it is not
- NULL. This is used to mark the current function and the outer
- function chain. */
-
-static void
-maybe_mark_struct_function (arg)
- void *arg;
-{
- struct function *f = *(struct function **) arg;
-
- if (f == 0)
- return;
-
- ggc_mark_struct_function (f);
-}
/* Mark a struct function * for GC. This is called from ggc-common.c. */
@@ -7669,8 +7662,40 @@ ggc_mark_struct_function (f)
ggc_mark_rtvec ((rtvec) f->original_arg_vector);
if (f->original_decl_initial)
ggc_mark_tree (f->original_decl_initial);
- if (f->outer)
- ggc_mark_struct_function (f->outer);
+}
+
+/* Mark the struct function pointed to by *ARG for GC, if it is not
+ NULL. This is used to mark the current function and the outer
+ function chain. */
+
+static void
+mark_function_chain (arg)
+ void *arg;
+{
+ struct function *f = *(struct function **) arg;
+
+ for (; f; f = f->next_global)
+ {
+ ggc_mark (f);
+ ggc_mark_tree (f->decl);
+
+ mark_function_status (f);
+ mark_eh_status (f->eh);
+ mark_stmt_status (f->stmt);
+ mark_expr_status (f->expr);
+ mark_emit_status (f->emit);
+ mark_varasm_status (f->varasm);
+
+ if (mark_machine_status)
+ (*mark_machine_status) (f);
+ if (mark_lang_status)
+ (*mark_lang_status) (f);
+
+ if (f->original_arg_vector)
+ ggc_mark_rtvec ((rtvec) f->original_arg_vector);
+ if (f->original_decl_initial)
+ ggc_mark_tree (f->original_decl_initial);
+ }
}
/* Called once, at initialization, to initialize function.c. */
@@ -7678,9 +7703,11 @@ ggc_mark_struct_function (f)
void
init_function_once ()
{
- ggc_add_root (&cfun, 1, sizeof cfun, maybe_mark_struct_function);
- ggc_add_root (&outer_function_chain, 1, sizeof outer_function_chain,
- maybe_mark_struct_function);
+ ggc_add_root (&all_functions, 1, sizeof all_functions,
+ mark_function_chain, "all_functions");
+ add_untyped_address (&data_to_save, &next_block_index,
+ sizeof (next_block_index), "next_block_index");
+
VARRAY_INT_INIT (prologue, 0, "prologue");
VARRAY_INT_INIT (epilogue, 0, "epilogue");
diff --git a/gcc/function.h b/gcc/function.h
index 8eeda3a2902..71eb887e93a 100644
--- a/gcc/function.h
+++ b/gcc/function.h
@@ -2,22 +2,22 @@
Copyright (C) 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
1999, 2000 Free Software Foundation, Inc.
-This file is part of GCC.
+This file is part of GNU CC.
-GCC is free software; you can redistribute it and/or modify it under
-the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 2, or (at your option) any later
-version.
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
-GCC is distributed in the hope that it will be useful, but WITHOUT ANY
-WARRANTY; without even the implied warranty of MERCHANTABILITY or
-FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
-for more details.
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING. If not, write to the Free
-Software Foundation, 59 Temple Place - Suite 330, Boston, MA
-02111-1307, USA. */
+along with GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
#if !defined(NULL_TREE) && !defined(tree)
@@ -178,6 +178,9 @@ struct expr_status
struct function
{
+ struct function *next_global;
+ struct function *next;
+
struct eh_status *eh;
struct stmt_status *stmt;
struct expr_status *expr;
@@ -192,9 +195,6 @@ struct function
/* Points to the FUNCTION_DECL of this function. */
tree decl;
- /* Function containing this function, if any. */
- struct function *outer;
-
/* Number of bytes of args popped by function being compiled on its return.
Zero if no bytes are to be popped.
May affect compilation of return insn or of function epilogue. */
@@ -477,14 +477,17 @@ struct function
/* Nonzero if the current function needs an lsda for exception handling. */
unsigned int uses_eh_lsda : 1;
-
/* Nonzero if code to initialize arg_pointer_save_area has been emited. */
- unsigned int arg_pointer_save_area_init : 1;
+ unsigned int arg_pointer_save_area_init : 1;
+
};
/* The function currently being compiled. */
extern struct function *cfun;
+/* A list of all functions we have compiled so far. */
+extern struct function *all_functions;
+
/* Nonzero if we've already converted virtual regs to hard regs. */
extern int virtuals_instantiated;
@@ -553,6 +556,9 @@ extern tree inline_function_decl;
return the `struct function' for it. */
struct function *find_function_data PARAMS ((tree));
+/* Pointer to chain of `struct function' for containing functions. */
+extern struct function *outer_function_chain;
+
/* Set NOTE_BLOCK for each block note in the current function. */
extern void identify_blocks PARAMS ((void));
diff --git a/gcc/gcc.c b/gcc/gcc.c
index ad692eb5b32..7f73a45983e 100644
--- a/gcc/gcc.c
+++ b/gcc/gcc.c
@@ -654,6 +654,7 @@ static const char *cpp_options =
%{fshow-column} %{fno-show-column}\
%{fleading-underscore} %{fno-leading-underscore}\
%{fno-operator-names} %{ftabstop=*} %{remap}\
+ %{nopch-dep}\
%{g3:-dD} %{W*} %{w} %{pedantic*} %{H} %{d*} %C %{D*&U*&A*} %{i*} %Z %i\
%{E:%{!M*:%W{o*}}}";
@@ -663,6 +664,7 @@ static const char *cc1_options =
%1 %{!Q:-quiet} -dumpbase %B %{d*} %{m*} %{a*}\
%{g*} %{O*} %{W*} %{w} %{pedantic*} %{std*} %{ansi}\
%{traditional} %{v:-version} %{pg:-p} %{p} %{f*}\
+ %{nopch-deps}\
%{Qn:-fno-ident} %{--help:--help}\
%{--target-help:--target-help}\
%{!fsyntax-only:%{S:%W{o*}%{!o*:-o %b.s}}}\
@@ -804,6 +806,9 @@ static struct compiler default_compilers[] =
tradcpp0 -lang-c %{ansi:-std=c89} %(cpp_options) %{!pipe:%g.i} |\n\
cc1 -fpreprocessed %{!pipe:%g.i} %(cc1_options)}\
%{!traditional:%{!ftraditional:%{!traditional-cpp:\
+ %{fauto-pch:%{!fsyntax-only: %{<fauto-pch} \
+ cc1 -lang-c %{ansi:-std=c89} %(cpp_options) %(cc1_options) \
+ -fauto-pch %{!S:-o %g.s}\n}}\
cc1 -lang-c %{ansi:-std=c89} %(cpp_options) %(cc1_options)}}}}\
%{!fsyntax-only:%(invoke_as)}}}}", 0},
{"-",
@@ -811,8 +816,10 @@ static struct compiler default_compilers[] =
%(trad_capable_cpp) -lang-c %{ansi:-std=c89} %(cpp_options)", 0},
{".h", "@c-header", 0},
{"@c-header",
- "%{!E:%eCompilation of header file requested} \
- %(trad_capable_cpp) -lang-c %{ansi:-std=c89} %(cpp_options)", 0},
+ "%{E|M|MM:%(trad_capable_cpp) -lang-c %{ansi:-std=c89} %(cpp_options)} "
+ "%{!E:cc1 -lang-c %{ansi:-std=c89} %(cpp_options) %(cc1_options)\
+ -o %g.s %{!o*:--output-pch=%i.pch} %W{^o*:--output-pch=%*}%V} "
+ },
{".i", "@cpp-output", 0},
{"@cpp-output",
"%{!M:%{!MM:%{!E:cc1 -fpreprocessed %i %(cc1_options) %{!fsyntax-only:%(invoke_as)}}}}", 0},
@@ -4466,6 +4473,10 @@ do_spec_1 (spec, inswitch, soft_matched_part)
this_is_library_file = 1;
break;
+ case 'V':
+ outfiles[input_file_number] = NULL;
+ break;
+
case 'w':
this_is_output_file = 1;
break;
@@ -4822,7 +4833,9 @@ do_spec_1 (spec, inswitch, soft_matched_part)
if (soft_matched_part)
{
do_spec_1 (soft_matched_part, 1, NULL);
+#if 0
do_spec_1 (" ", 0, NULL);
+#endif
}
else
/* Catch the case where a spec string contains something like
@@ -5167,7 +5180,7 @@ next_member:
{
do_spec_1 (string, 0, &switches[i].part1[hard_match_len]);
/* Pass any arguments this switch has. */
- give_switch (i, 1, 1);
+ give_switch (i, 1, include_blanks);
suffix_subst = NULL;
}
@@ -5542,6 +5555,7 @@ main (argc, argv)
size_t i;
int value;
int linker_was_run = 0;
+ int num_linker_inputs = 0;
char *explicit_link_files;
char *specs_file;
const char *p;
diff --git a/gcc/gcse.c b/gcc/gcse.c
index 9a468542ddd..d9894279d54 100644
--- a/gcc/gcse.c
+++ b/gcc/gcse.c
@@ -1353,7 +1353,7 @@ want_to_gcse_p (x)
FIRST_PSEUDO_REGISTER * 2),
const0_rtx));
NEXT_INSN (test_insn) = PREV_INSN (test_insn) = 0;
- ggc_add_rtx_root (&test_insn, 1);
+ ggc_add_rtx_root (&test_insn, 1, "test_insn");
}
/* Now make an insn like the one we would make when GCSE'ing and see if
diff --git a/gcc/ggc-common.c b/gcc/ggc-common.c
index 53057c8a75b..1b3b7a65a96 100644
--- a/gcc/ggc-common.c
+++ b/gcc/ggc-common.c
@@ -43,15 +43,25 @@ void (*lang_mark_false_label_stack) PARAMS ((struct label_node *));
/* Trees that have been marked, but whose children still need marking. */
varray_type ggc_pending_trees;
+#if 0
static void ggc_mark_rtx_ptr PARAMS ((void *));
static void ggc_mark_tree_ptr PARAMS ((void *));
static void ggc_mark_rtx_varray_ptr PARAMS ((void *));
static void ggc_mark_tree_varray_ptr PARAMS ((void *));
static void ggc_mark_tree_hash_table_ptr PARAMS ((void *));
+#endif
static int ggc_htab_delete PARAMS ((void **, void *));
static void ggc_mark_trees PARAMS ((void));
static bool ggc_mark_tree_hash_table_entry PARAMS ((struct hash_entry *,
- hash_table_key));
+ hash_table_key));
+static int ggc_mark_subobject_pointer PARAMS ((void *object,
+ type_definition_p td,
+ void **v,
+ subobject_definition_p sd,
+ void *ctx));
+static int ggc_mark_typed_pointer PARAMS ((void **, type_definition_p, void *));
+
+
/* Maintain global roots that are preserved during GC. */
@@ -64,10 +74,13 @@ struct ggc_root
int nelt;
int size;
void (*cb) PARAMS ((void *));
+ const char *name;
};
static struct ggc_root *roots;
+static typed_addresses_list ggc_roots;
+
/* Add BASE as a new garbage collection root. It is an array of
length NELT with each element SIZE bytes long. CB is a
function that will be called with a pointer to each element
@@ -75,73 +88,112 @@ static struct ggc_root *roots;
routine to mark gc-able memory for that element. */
void
-ggc_add_root (base, nelt, size, cb)
+ggc_add_root (base, nelt, size, cb, name)
void *base;
int nelt, size;
void (*cb) PARAMS ((void *));
+ const char *name;
{
struct ggc_root *x = (struct ggc_root *) xmalloc (sizeof (*x));
+#if 0
+fprintf(stderr,"Adding root ggc_add_root (%s)\n",name);
+#endif
x->next = roots;
x->base = base;
x->nelt = nelt;
x->size = size;
x->cb = cb;
+ x->name = name;
roots = x;
}
+/* Register an object of type TD pointed-to by NELT pointers starting
+ at BASE as a GC root. */
+void
+ggc_add_typed_root (base, td, nelt, name)
+ void *base;
+ type_definition_p td;
+ int nelt;
+ const char *name;
+{
+#if 0
+fprintf(stderr,"Adding typed_root ggc_add_typed_root (%s)\n",name);
+#endif
+ add_typed_addresses (&ggc_roots, base, td, nelt, name);
+}
+
/* Register an array of rtx as a GC root. */
void
-ggc_add_rtx_root (base, nelt)
+ggc_add_rtx_root (base, nelt, name)
rtx *base;
int nelt;
+ const char *name;
{
- ggc_add_root (base, nelt, sizeof (rtx), ggc_mark_rtx_ptr);
+ add_rtx_addresses (&ggc_roots, base, nelt, name);
}
/* Register an array of trees as a GC root. */
void
-ggc_add_tree_root (base, nelt)
+ggc_add_tree_root (base, nelt, name)
tree *base;
int nelt;
+ const char *name;
{
- ggc_add_root (base, nelt, sizeof (tree), ggc_mark_tree_ptr);
+ add_tree_addresses (&ggc_roots, base, nelt, name);
}
/* Register a varray of rtxs as a GC root. */
void
-ggc_add_rtx_varray_root (base, nelt)
+ggc_add_rtx_varray_root (base, nelt, name)
varray_type *base;
int nelt;
+ const char *name;
{
- ggc_add_root (base, nelt, sizeof (varray_type),
- ggc_mark_rtx_varray_ptr);
+ add_typed_addresses (&ggc_roots, (void **)base, varray_rtx_type_def, nelt, name);
}
/* Register a varray of trees as a GC root. */
void
-ggc_add_tree_varray_root (base, nelt)
+ggc_add_tree_varray_root (base, nelt, name)
+ varray_type *base;
+ int nelt;
+ const char *name;
+{
+ add_typed_addresses (&ggc_roots, (void **)base, varray_tree_type_def, nelt, name);
+}
+
+/* Register a varray of strings as a GC root. */
+
+void
+ggc_add_string_varray_root (base, nelt, name)
varray_type *base;
int nelt;
+ const char *name;
{
- ggc_add_root (base, nelt, sizeof (varray_type),
- ggc_mark_tree_varray_ptr);
+ add_typed_addresses (&ggc_roots, (void **)base, varray_string_type_def,
+ nelt, name);
}
/* Register a hash table of trees as a GC root. */
void
-ggc_add_tree_hash_table_root (base, nelt)
+ggc_add_tree_hash_table_root (base, nelt, name)
struct hash_table **base;
int nelt;
+ const char *name;
{
+#if 1
+ add_typed_addresses (&ggc_roots, (void **)base, hash_tree_type_def, nelt, name);
+#else
ggc_add_root (base, nelt, sizeof (struct hash_table *),
- ggc_mark_tree_hash_table_ptr);
+ ggc_mark_tree_hash_table_ptr, name);
+#endif
}
/* Remove the previously registered GC root at BASE. */
@@ -150,22 +202,7 @@ void
ggc_del_root (base)
void *base;
{
- struct ggc_root *x, **p;
-
- p = &roots, x = roots;
- while (x)
- {
- if (x->base == base)
- {
- *p = x->next;
- free (x);
- return;
- }
- p = &x->next;
- x = x->next;
- }
-
- abort();
+ remove_list_address (&ggc_roots, base);
}
/* Add a hash table to be scanned when all roots have been processed. We
@@ -177,6 +214,7 @@ struct d_htab_root
htab_t htab;
ggc_htab_marked_p marked_p;
ggc_htab_mark mark;
+ const char *name;
};
static struct d_htab_root *d_htab_roots;
@@ -202,10 +240,11 @@ static struct d_htab_root *d_htab_roots;
marked, we need to mark the DECL. */
void
-ggc_add_deletable_htab (x, marked_p, mark)
+ggc_add_deletable_htab (x, marked_p, mark, name)
PTR x;
ggc_htab_marked_p marked_p;
ggc_htab_mark mark;
+ const char *name;
{
struct d_htab_root *r
= (struct d_htab_root *) xmalloc (sizeof (struct d_htab_root));
@@ -214,6 +253,7 @@ ggc_add_deletable_htab (x, marked_p, mark)
r->htab = (htab_t) x;
r->marked_p = marked_p ? marked_p : ggc_marked_p;
r->mark = mark;
+ r->name = name;
d_htab_roots = r;
}
@@ -242,8 +282,14 @@ ggc_mark_roots ()
struct ggc_root *x;
struct d_htab_root *y;
+ apply_list_pointers_recursively (&ggc_roots, ggc_mark_typed_pointer,
+ ggc_mark_subobject_pointer, NULL);
+
VARRAY_TREE_INIT (ggc_pending_trees, 4096, "ggc_pending_trees");
+#if 0
+fprintf(stderr,"gcc_mark_roots root ===== \n");
+#endif
for (x = roots; x != NULL; x = x->next)
{
char *elt = x->base;
@@ -251,6 +297,9 @@ ggc_mark_roots ()
void (*cb) PARAMS ((void *)) = x->cb;
int i;
+#if 0
+fprintf(stderr,"Looking at gcc_mark_roots root = %s\n",x->name);
+#endif
for (i = 0; i < n; ++i, elt += s)
(*cb)(elt);
}
@@ -264,8 +313,12 @@ ggc_mark_roots ()
to reinitialize that varray. */
VARRAY_TREE_INIT (ggc_pending_trees, 1024, "ggc_pending_trees");
- for (y = d_htab_roots; y != NULL; y = y->next)
+ for (y = d_htab_roots; y != NULL; y = y->next) {
+#if 0
+ fprintf(stderr,"Looking at (%s)\n", y->name);
+#endif
htab_traverse (y->htab, ggc_htab_delete, (PTR) y);
+ }
ggc_mark_trees ();
VARRAY_FREE (ggc_pending_trees);
}
@@ -286,7 +339,7 @@ ggc_mark_rtx_children (r)
enum rtx_code code = GET_CODE (r);
/* This gets set to a child rtx to eliminate tail recursion. */
next_rtx = NULL;
-
+
/* Collect statistics, if appropriate. */
if (ggc_stats)
{
@@ -463,8 +516,10 @@ ggc_mark_trees ()
ggc_mark_tree (DECL_VINDEX (t));
if (DECL_ASSEMBLER_NAME_SET_P (t))
ggc_mark_tree (DECL_ASSEMBLER_NAME (t));
+#if 1
if (TREE_CODE (t) == FUNCTION_DECL && DECL_SAVED_INSNS (t))
ggc_mark_struct_function (DECL_SAVED_INSNS (t));
+#endif
lang_mark_tree (t);
break;
@@ -565,46 +620,49 @@ ggc_mark_tree_hash_table (ht)
hash_traverse (ht, ggc_mark_tree_hash_table_entry, /*info=*/0);
}
-/* Type-correct function to pass to ggc_add_root. It just forwards
- *ELT (which is an rtx) to ggc_mark_rtx. */
+/* Mark this pointer. */
-static void
-ggc_mark_rtx_ptr (elt)
- void *elt;
-{
- ggc_mark_rtx (*(rtx *) elt);
-}
-
-/* Type-correct function to pass to ggc_add_root. It just forwards
- *ELT (which is a tree) to ggc_mark_tree. */
-
-static void
-ggc_mark_tree_ptr (elt)
- void *elt;
+static int
+ggc_mark_typed_pointer (v, td, ctx)
+ void **v;
+ type_definition_p td;
+ void *ctx ATTRIBUTE_UNUSED;
{
- ggc_mark_tree (*(tree *) elt);
-}
+ if (*v == NULL)
+ return 0;
-/* Type-correct function to pass to ggc_add_root. It just forwards
- ELT (which is really a varray_type *) to ggc_mark_rtx_varray. */
-
-static void
-ggc_mark_rtx_varray_ptr (elt)
- void *elt;
-{
- ggc_mark_rtx_varray (*(varray_type *) elt);
+ if (td->ggc_p > 0)
+ {
+ if (td == string_type_def)
+ {
+ ggc_mark_if_gcable (*v);
+ return 0;
+ }
+ else
+ {
+ if (! ggc_marked_p (*v) )
+ return ggc_test_and_set_mark (*v);
+ else
+ return 0;
+ }
+ }
+ else
+ /* Do still mark any gcable items contained in this structure. */
+ return (td->ggc_p < 0);
}
-/* Type-correct function to pass to ggc_add_root. It just forwards
- ELT (which is really a varray_type *) to ggc_mark_tree_varray. */
-
-static void
-ggc_mark_tree_varray_ptr (elt)
- void *elt;
+static int
+ggc_mark_subobject_pointer (object, td, v, sd, ctx)
+ void *object ATTRIBUTE_UNUSED;
+ type_definition_p td;
+ void **v;
+ subobject_definition_p sd ATTRIBUTE_UNUSED;
+ void *ctx ATTRIBUTE_UNUSED;
{
- ggc_mark_tree_varray (*(varray_type *) elt);
+ return ggc_test_and_set_mark (*v);
}
+#if 0
/* Type-correct function to pass to ggc_add_root. It just forwards
ELT (which is really a struct hash_table **) to
ggc_mark_tree_hash_table. */
@@ -616,6 +674,7 @@ ggc_mark_tree_hash_table_ptr (elt)
ggc_mark_tree_hash_table (*(struct hash_table **) elt);
}
+#endif
/* Allocate a block of memory, then clear it. */
void *
ggc_alloc_cleared (size)
diff --git a/gcc/ggc-page.c b/gcc/ggc-page.c
index 8f2d32ea0bb..be654e9fada 100644
--- a/gcc/ggc-page.c
+++ b/gcc/ggc-page.c
@@ -29,6 +29,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
#include "ggc.h"
#include "timevar.h"
+#define inline
+
/* Prefer MAP_ANON(YMOUS) to /dev/zero, since we don't need to keep a
file open. Prefer either to valloc. */
#ifdef HAVE_MMAP_ANON
@@ -97,6 +99,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
when a significant amount of memory has been allocated since the
last collection. */
#undef GGC_ALWAYS_COLLECT
+#define GGC_ALWAYS_COLLECT
#ifdef ENABLE_GC_CHECKING
#define GGC_POISON
@@ -356,7 +359,7 @@ static struct globals
in_use bitmask for page_group. */
#define GGC_QUIRE_SIZE 16
-static int ggc_allocated_p PARAMS ((const void *));
+int ggc_allocated_p PARAMS ((const void *));
static page_entry *lookup_page_table_entry PARAMS ((const void *));
static void set_page_table_entry PARAMS ((void *, page_entry *));
#ifdef USING_MMAP
@@ -382,7 +385,7 @@ void debug_print_page_list PARAMS ((int));
/* Returns non-zero if P was allocated in GC'able memory. */
-static inline int
+int
ggc_allocated_p (p)
const void *p;
{
@@ -415,6 +418,11 @@ ggc_allocated_p (p)
/* Traverse the page table and find the entry for a page.
Die (probably) if the object wasn't allocated via GC. */
+void haltit()
+{
+}
+
+/*#if !defined (__GNUC__) || HOST_BITS_PER_PTR > 32 */
static inline page_entry *
lookup_page_table_entry(p)
const void *p;
@@ -436,8 +444,14 @@ lookup_page_table_entry(p)
L1 = LOOKUP_L1 (p);
L2 = LOOKUP_L2 (p);
+ if (!ggc_allocated_p(p)) haltit();
return base[L1][L2];
}
+/*
+#else
+#define lookup_page_table_entry(p) ((&G.lookup[0])[LOOKUP_L1 (p)][LOOKUP_L2 (p)])
+#endif
+*/
/* Set the page table entry for a page. */
@@ -852,6 +866,7 @@ static unsigned char size_lookup[257] =
/* Allocate a chunk of memory of SIZE bytes. If ZERO is non-zero, the
memory is zeroed; otherwise, its contents are undefined. */
+void *ggc_break = 0x401517c0;
void *
ggc_alloc (size)
size_t size;
@@ -957,6 +972,7 @@ ggc_alloc (size)
fprintf (G.debug_file,
"Allocating object, requested size=%ld, actual=%ld at %p on %p\n",
(long) size, (long) OBJECT_SIZE (order), result, (PTR) entry);
+if (result == ggc_break ) haltit();
return result;
}
@@ -1512,3 +1528,17 @@ ggc_print_statistics ()
SCALE (G.allocated), LABEL(G.allocated),
SCALE (total_overhead), LABEL (total_overhead));
}
+
+/* Mark P, but check first that it was allocated by the collector. */
+
+void
+ggc_mark_if_gcable (p)
+ const void *p;
+{
+ if (p && ggc_allocated_p (p))
+{
+fprintf(stderr,"marking %p\n", p);
+ ggc_set_mark (p);
+}
+}
+
diff --git a/gcc/ggc-simple.c b/gcc/ggc-simple.c
index 81d2c36fc6d..8f7a248decf 100644
--- a/gcc/ggc-simple.c
+++ b/gcc/ggc-simple.c
@@ -228,6 +228,29 @@ ggc_set_mark (p)
return 0;
}
+/* Mark a node, but check first to see that it's really gc-able memory. */
+
+void
+ggc_mark_if_gcable (p)
+ const void *p;
+{
+ struct ggc_mem *x;
+
+ if (p == NULL)
+ return;
+
+ x = (struct ggc_mem *) ((const char *)p - offsetof (struct ggc_mem, u));
+ if (! tree_lookup (x))
+ return;
+
+ if (x->mark)
+ return;
+
+ x->mark = 1;
+ G.allocated += x->size;
+ G.objects += 1;
+}
+
/* Return 1 if P has been marked, zero otherwise. */
int
diff --git a/gcc/ggc.h b/gcc/ggc.h
index fe3290bc59a..5582035a734 100644
--- a/gcc/ggc.h
+++ b/gcc/ggc.h
@@ -19,6 +19,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA. */
#include "varray.h"
+#include "gtype.h"
/* Symbols are marked with `ggc' for `gcc gc' so as not to interfere with
an external gc library that might be linked in. */
@@ -47,18 +48,16 @@ extern const char digit_vector[]; /* "0" .. "9" */
extern varray_type ggc_pending_trees;
/* Manipulate global roots that are needed between calls to gc. */
-extern void ggc_add_root PARAMS ((void *base, int nelt,
- int size, void (*)(void *)));
-extern void ggc_add_rtx_root PARAMS ((struct rtx_def **, int nelt));
-extern void ggc_add_tree_root PARAMS ((union tree_node **,
- int nelt));
-extern void ggc_add_rtx_varray_root PARAMS ((struct varray_head_tag **,
- int nelt));
-extern void ggc_add_tree_varray_root PARAMS ((struct varray_head_tag **,
- int nelt));
-extern void ggc_add_tree_hash_table_root PARAMS ((struct hash_table **,
- int nelt));
-extern void ggc_del_root PARAMS ((void *base));
+void ggc_add_typed_root PARAMS ((void *base, type_definition_p td, int nelt , const char * ));
+void ggc_add_string_varray_root PARAMS ((struct varray_head_tag **, int nelt , const char * ));
+void ggc_add_root PARAMS ((void *base, int nelt, int size, void (*)(void *) , const char * ));
+void ggc_add_rtx_root PARAMS ((struct rtx_def **, int nelt , const char * ));
+void ggc_add_tree_root PARAMS ((union tree_node **, int nelt , const char * ));
+void ggc_add_rtx_varray_root PARAMS ((struct varray_head_tag **, int nelt , const char * ));
+void ggc_add_tree_varray_root PARAMS ((struct varray_head_tag **, int nelt , const char * ));
+void ggc_add_tree_hash_table_root PARAMS ((struct hash_table **, int nelt , const char * ));
+void ggc_del_root PARAMS ((void *base));
+int ggc_allocated_p PARAMS ((const void *));
/* Types used for mark test and marking functions, if specified, in call
below. */
@@ -69,14 +68,15 @@ typedef void (*ggc_htab_mark) PARAMS ((const void *));
delete any entry in the table that has not been marked. The argument is
really htab_t. */
extern void ggc_add_deletable_htab PARAMS ((PTR, ggc_htab_marked_p,
- ggc_htab_mark));
+ ggc_htab_mark, const char *));
/* Mark nodes from the gc_add_root callback. These functions follow
pointers to mark other objects too. */
-extern void ggc_mark_rtx_varray PARAMS ((struct varray_head_tag *));
-extern void ggc_mark_tree_varray PARAMS ((struct varray_head_tag *));
-extern void ggc_mark_tree_hash_table PARAMS ((struct hash_table *));
-extern void ggc_mark_roots PARAMS ((void));
+extern void ggc_mark_if_gcable PARAMS ((const void *));
+extern void ggc_mark_rtx_varray PARAMS ((struct varray_head_tag *));
+extern void ggc_mark_tree_varray PARAMS ((struct varray_head_tag *));
+extern void ggc_mark_tree_hash_table PARAMS ((struct hash_table *));
+extern void ggc_mark_roots PARAMS ((void));
extern void ggc_mark_rtx_children PARAMS ((struct rtx_def *));
extern void ggc_mark_rtvec_children PARAMS ((struct rtvec_def *));
diff --git a/gcc/gtype.c b/gcc/gtype.c
new file mode 100644
index 00000000000..f5018a271f9
--- /dev/null
+++ b/gcc/gtype.c
@@ -0,0 +1,1922 @@
+/* Generic data handling for GNU CC.
+ Copyright (C) 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+#include "config.h"
+#include "system.h"
+#include "intl.h"
+#include "tree.h"
+#include "rtl.h"
+#include "function.h"
+#include "expr.h"
+#include "c-tree.h"
+#include "toplev.h"
+#include "hashtab.h"
+#include "md5.h"
+#include "defaults.h"
+#include "hash.h"
+#include "ggc.h"
+#include "tm_p.h"
+
+/* Definitions of all the types we know. */
+typedef struct pch_writer_context
+{
+ htab_t pointer_h;
+ unsigned n_constant[num_type_defs];
+ unsigned n[num_type_defs];
+ const void **ptrs[num_type_defs];
+ unsigned max_size[num_type_defs];
+ FILE *f;
+ int *listd; /* Record what objects the listed variables point to. */
+ size_t listd_ndx;
+ size_t string_size;
+ char *string_table;
+} *wctx_t;
+
+struct pointer_ent
+{
+ const void *v;
+ unsigned ndx;
+ type_definition_p td;
+};
+
+static size_t constant_size_fetcher
+PARAMS ((const void *, type_definition_p));
+
+static code_type tree_code_fetcher PARAMS ((const void *));
+static size_t tree_size_fetcher PARAMS ((const void *, type_definition_p ));
+static int tree_more_fields PARAMS ((struct field_definition_s * ,
+ const void *,
+ unsigned , code_type ,
+ type_definition_p ));
+
+static size_t rtx_size_fetcher PARAMS ((const void *, type_definition_p ));
+static int rtx_more_fields PARAMS ((struct field_definition_s * ,
+ const void *,
+ unsigned, code_type ,
+ type_definition_p ));
+
+static size_t rtvec_size_fetcher PARAMS ((const void *,
+ type_definition_p ));
+static int rtvec_more_fields PARAMS ((struct field_definition_s * ,
+ const void *,
+ unsigned , code_type ,
+ type_definition_p ));
+
+static size_t string_size_fetcher PARAMS ((const void *,
+ type_definition_p ));
+
+static size_t regno_reg_rtx_size_fetcher PARAMS ((const void *,
+ type_definition_p ));
+static int regno_reg_rtx_more_fields PARAMS ((struct field_definition_s * ,
+ const void *,
+ unsigned , code_type ,
+ type_definition_p ));
+static size_t regno_pointer_flag_size_fetcher PARAMS (( const void *, type_definition_p ));
+
+static size_t varray_size_fetcher PARAMS ((const void *,
+ type_definition_p ));
+static int varray_more_fields PARAMS ((struct field_definition_s * ,
+ const void *,
+ unsigned , code_type ,
+ type_definition_p ));
+
+static int typed_addresses_list_more_fields PARAMS ((struct field_definition_s * ,
+ const void *, unsigned , code_type , type_definition_p ));
+static void setup_strtab PARAMS ((wctx_t));
+static void record_listed_nodes PARAMS ((void **v_p, type_definition_p,
+ void *));
+static size_t htab_size_fetcher PARAMS (( const void *, type_definition_p ));
+static int htab_more_fields PARAMS (( struct field_definition_s *, const void *,
+ unsigned ,
+ code_type,
+ type_definition_p));
+
+extern void add_hash_tree_addresses PARAMS ((typed_addresses_list_p list,
+ struct htab *p , size_t, const char *));
+
+/* Size fetcher for structures with constant size; just returns SIZE from
+ the type definition. */
+
+static size_t
+constant_size_fetcher (v, td)
+ const void *v ATTRIBUTE_UNUSED;
+ type_definition_p td;
+{
+ return td->size;
+}
+
+static code_type
+tree_code_fetcher (t_v)
+ const void *t_v;
+{
+ tree t = (tree) t_v;
+ return TREE_CODE (t) << 8 | TREE_CODE_CLASS (TREE_CODE (t));
+}
+
+static size_t
+tree_size_fetcher (v, td)
+ const void *v;
+ type_definition_p td ATTRIBUTE_UNUSED;
+{
+ return tree_size ((tree) v);
+}
+
+static int
+tree_more_fields (fp, t_v, n, c, td)
+ struct field_definition_s *fp;
+ const void *t_v;
+ unsigned n;
+ code_type c;
+ type_definition_p td ATTRIBUTE_UNUSED;
+{
+ const tree t = (tree) t_v;
+ enum tree_code tc = (c >> 8) & 0xFF;
+
+ if (tc == TREE_VEC && (long) n < TREE_VEC_LENGTH (t))
+ {
+ fp->offset = (offsetof (union tree_node, vec.a)
+ + n * sizeof (TREE_VEC_ELT (t, 0)));
+ fp->type = tree_type_def;
+ return 1;
+ }
+ else if (((c & 0xFF) == 'r' || (c & 0xFF) == '<'
+ || (c & 0xFF) == '1' || (c & 0xFF) == '2'
+ || (c & 0xFF) == 'e' || (c & 0xFF) == 's')
+ && (long) n < TREE_CODE_LENGTH (tc))
+ {
+ fp->offset = (offsetof (union tree_node, exp.operands)
+ + n * sizeof (TREE_OPERAND (t, 0)));
+ fp->type =
+ ((long) n >= first_rtl_op (tc) ? rtx_type_def : tree_type_def);
+ return 1;
+ }
+
+ return 0;
+}
+
+static struct field_definition_s tree_field_defs[] = {
+ {0, 0, offsetof (union tree_node, common.chain), tree_type_def},
+ {0, 0, offsetof (union tree_node, common.type), tree_type_def},
+ {'d', 0xFF, offsetof (union tree_node, decl.filename), string_type_def},
+ {'d', 0xFF, offsetof (union tree_node, decl.size), tree_type_def},
+ {'d', 0xFF, offsetof (union tree_node, decl.size_unit), tree_type_def},
+ {'d', 0xFF, offsetof (union tree_node, decl.name), tree_type_def},
+ {'d', 0xFF, offsetof (union tree_node, decl.context), tree_type_def},
+ {'d', 0xFF, offsetof (union tree_node, decl.arguments), tree_type_def},
+ {'d', 0xFF, offsetof (union tree_node, decl.result), tree_type_def},
+ {'d', 0xFF, offsetof (union tree_node, decl.initial), tree_type_def},
+ {'d', 0xFF, offsetof (union tree_node, decl.abstract_origin),
+ tree_type_def},
+ {'d', 0xFF, offsetof (union tree_node, decl.assembler_name),
+ tree_type_def},
+ {'d', 0xFF, offsetof (union tree_node, decl.section_name), tree_type_def},
+#if 0
+ {'d', 0xFF, offsetof (union tree_node, decl.machine_attributes), tree_type_def},
+#endif
+ {'d', 0xFF, offsetof (union tree_node, decl.rtl), rtx_type_def},
+ {'d', 0xFF, offsetof (union tree_node, decl.live_range_rtl), rtx_type_def},
+ {'d', 0xFF, offsetof (union tree_node, decl.vindex), tree_type_def},
+ {FUNCTION_DECL << 8, 0xFF00,
+ offsetof (union tree_node, decl.u2.f), function_type_def},
+ {PARM_DECL << 8, 0xFF00,
+ offsetof (union tree_node, decl.u2.r), rtx_type_def},
+ {FIELD_DECL << 8, 0xFF00,
+ offsetof (union tree_node, decl.u2.t), tree_type_def},
+ {'t', 0xFF, offsetof (union tree_node, type.values), tree_type_def},
+ {'t', 0xFF, offsetof (union tree_node, type.size), tree_type_def},
+ {'t', 0xFF, offsetof (union tree_node, type.size_unit), tree_type_def},
+ {'t', 0xFF, offsetof (union tree_node, type.attributes), tree_type_def},
+ {'t', 0xFF, offsetof (union tree_node, type.pointer_to), tree_type_def},
+ {'t', 0xFF, offsetof (union tree_node, type.reference_to), tree_type_def},
+ {'t', 0xFF, offsetof (union tree_node, type.name), tree_type_def},
+ {'t', 0xFF, offsetof (union tree_node, type.minval), tree_type_def},
+ {'t', 0xFF, offsetof (union tree_node, type.maxval), tree_type_def},
+ {'t', 0xFF, offsetof (union tree_node, type.next_variant), tree_type_def},
+ {'t', 0xFF, offsetof (union tree_node, type.main_variant), tree_type_def},
+ {'t', 0xFF, offsetof (union tree_node, type.binfo), tree_type_def},
+ {'t', 0xFF, offsetof (union tree_node, type.context), tree_type_def},
+ {'b', 0xFF, offsetof (union tree_node, block.vars), tree_type_def},
+ {'b', 0xFF, offsetof (union tree_node, block.subblocks), tree_type_def},
+ {'b', 0xFF, offsetof (union tree_node, block.supercontext), tree_type_def},
+ {'b', 0xFF, offsetof (union tree_node, block.abstract_origin),
+ tree_type_def},
+ {'b', 0xFF, offsetof (union tree_node, block.fragment_origin), tree_type_def},
+ {'b', 0xFF, offsetof (union tree_node, block.fragment_chain), tree_type_def},
+
+ {'c', 0xFF, offsetof (union tree_node, real_cst.rtl), rtx_type_def},
+ {COMPLEX_CST << 8, 0xFF00,
+ offsetof (union tree_node, complex.real), tree_type_def},
+ {COMPLEX_CST << 8, 0xFF00,
+ offsetof (union tree_node, complex.imag), tree_type_def},
+ {STRING_CST << 8, 0xFF00,
+ offsetof (union tree_node, string.pointer), string_type_def},
+ {IDENTIFIER_NODE << 8, 0xFF00,
+ offsetof (union tree_node, identifier.id.str), string_type_def},
+ {TREE_LIST << 8, 0xFF00,
+ offsetof (union tree_node, list.purpose), tree_type_def},
+ {TREE_LIST << 8, 0xFF00,
+ offsetof (union tree_node, list.value), tree_type_def},
+ /* TREE_VEC_ELT is dealt with by MORE_FIELDS. */
+ /* expressions are dealt with by MORE_FIELDS. */
+
+ /* The remaining unused entries are available to hold such things as
+ decl.lang_specific, type.lang_specific, and any extra fields
+ introduced by a 'struct lang_identifier'. Normally, you'd simply
+ say
+
+ { 'd', 0xFF, offsetof (union tree_node, decl.lang_specific),
+ lang_decl_type_def },
+ { 't', 0xFF, offsetof (union tree_node, type.lang_specific),
+ lang_type_type_def },
+
+ for the first two, but some frontends put bizzare things in these fields.
+ */
+ NO_MORE_FIELDS, NO_MORE_FIELDS, NO_MORE_FIELDS, NO_MORE_FIELDS,
+ NO_MORE_FIELDS, NO_MORE_FIELDS, NO_MORE_FIELDS, NO_MORE_FIELDS,
+ NO_MORE_FIELDS, NO_MORE_FIELDS, NO_MORE_FIELDS, NO_MORE_FIELDS,
+ NO_MORE_FIELDS
+};
+
+
+/* This is how languages handle adding their favourite stuff
+at the end of a tree... */
+
+void
+add_tree_fields (fields)
+ const struct field_definition_s *fields;
+{
+ unsigned i;
+ enum
+ {
+ num_tree_fields = sizeof (tree_field_defs) / sizeof (tree_field_defs[0])
+ };
+
+ i = 0;
+ while (tree_field_defs[i].type != NULL)
+ i++;
+ for (; i < num_tree_fields; i++)
+ if (fields->type != NULL)
+ tree_field_defs[i] = *fields++;
+ else
+ return;
+ abort (); /* Need to add more NO_MORE_FIELDS to tree_field_defs. */
+}
+
+static size_t
+rtx_size_fetcher (r_v, td)
+ const void *r_v;
+ type_definition_p td ATTRIBUTE_UNUSED;
+{
+ return (sizeof (struct rtx_def) +
+ (GET_RTX_LENGTH (GET_CODE ((rtx) r_v)) - 1) * sizeof (rtunion));
+}
+
+static int
+rtx_more_fields (fp, r_v, n, c, td)
+ struct field_definition_s *fp;
+ const void *r_v;
+ unsigned n;
+ code_type c ATTRIBUTE_UNUSED;
+ type_definition_p td ATTRIBUTE_UNUSED;
+{
+ const rtx r = (rtx) r_v;
+ char fc = GET_RTX_FORMAT (GET_CODE (r))[n];
+
+ fp->offset = (offsetof (struct rtx_def, fld) + n * sizeof (rtunion));
+ switch (fc)
+ {
+ case '\0':
+ return 0;
+
+ case 'e':
+ case 'u':
+ fp->type = rtx_type_def;
+ break;
+ case 'V':
+ case 'E':
+ fp->type = rtvec_type_def;
+ break;
+ case 'S':
+ case 's':
+ case 'T':
+ fp->type = string_type_def;
+ break;
+ case 't':
+ fp->type = tree_type_def;
+ break;
+ case '0':
+ switch (GET_CODE (r))
+ {
+ case JUMP_INSN:
+ case LABEL_REF:
+ case CONST_DOUBLE:
+ fp->type = rtx_type_def;
+ break;
+ case CODE_LABEL:
+ if (n == 3)
+ fp->type = NULL;
+ else
+ fp->type = rtx_type_def;
+ break;
+ case MEM:
+ case REG:
+ case SCRATCH:
+ case ADDR_DIFF_VEC:
+ fp->type = NULL;
+ break;
+
+ case NOTE:
+ switch (NOTE_LINE_NUMBER (r))
+ {
+ case NOTE_INSN_RANGE_BEG:
+ case NOTE_INSN_RANGE_END:
+ case NOTE_INSN_LIVE:
+ case NOTE_INSN_EXPECTED_VALUE:
+ fp->type = rtx_type_def;
+ break;
+ case NOTE_INSN_BLOCK_BEG:
+ case NOTE_INSN_BLOCK_END:
+ fp->type = tree_type_def;
+ break;
+ case NOTE_INSN_DELETED_LABEL:
+ fp->type = string_type_def;
+ break;
+ default:
+ if (NOTE_LINE_NUMBER (r) >= 0)
+ fp->type = string_type_def;
+ else
+ fp->type = NULL;
+ break;
+ }
+ break;
+ default:
+ abort ();
+ }
+ break;
+ default:
+ fp->type = NULL;
+ break;
+ }
+ return 1;
+}
+
+static size_t
+rtvec_size_fetcher (v_v, td)
+ const void *v_v;
+ type_definition_p td ATTRIBUTE_UNUSED;
+{
+ return (sizeof (struct rtvec_def) +
+ (GET_NUM_ELEM ((rtvec) v_v) - 1) * sizeof (rtx));
+}
+
+static int
+rtvec_more_fields (fp, v_v, n, c, td)
+ struct field_definition_s *fp;
+ const void *v_v;
+ unsigned n;
+ code_type c ATTRIBUTE_UNUSED;
+ type_definition_p td ATTRIBUTE_UNUSED;
+{
+ if ((long) n < GET_NUM_ELEM ((rtvec) v_v))
+ {
+ fp->offset = (offsetof (struct rtvec_def, elem) + n * sizeof (rtx));
+ fp->type = rtx_type_def;
+ return 1;
+ }
+ return 0;
+}
+
+static size_t
+string_size_fetcher (v_v, td)
+ const void *v_v;
+ type_definition_p td ATTRIBUTE_UNUSED;
+{
+ return strlen ((char *) v_v) + 1;
+}
+
+
+static const struct field_definition_s function_field_defs[] = {
+#if 1
+ {0, 0, offsetof (struct function, next_global), function_type_def},
+ {0, 0, offsetof (struct function, next), function_type_def},
+#endif
+ /* struct eh_status *eh;
+ struct stmt_status *stmt;
+ struct expr_status *expr; */
+ {0, 0, offsetof (struct function, emit), emit_status_type_def},
+ /* struct varasm_status *varasm; */
+ {0, 0, offsetof (struct function, name), string_type_def},
+ {0, 0, offsetof (struct function, decl), tree_type_def},
+#if 0
+ {0, 0, offsetof (struct function, outer), function_type_def},
+#endif
+ {0, 0, offsetof (struct function, arg_offset_rtx), rtx_type_def},
+ /* CUMULATIVE_ARGS args_info; */
+ {0, 0, offsetof (struct function, return_rtx), rtx_type_def},
+ {0, 0, offsetof (struct function, cannot_inline), string_type_def},
+ {0, 0, offsetof (struct function, x_nonlocal_labels), tree_type_def},
+ {0, 0, offsetof (struct function, x_nonlocal_goto_handler_slots),
+ rtx_type_def},
+ {0, 0, offsetof (struct function, x_nonlocal_goto_handler_labels),
+ rtx_type_def},
+ {0, 0, offsetof (struct function, x_nonlocal_goto_stack_level),
+ rtx_type_def},
+ {0, 0, offsetof (struct function, x_cleanup_label), rtx_type_def},
+ {0, 0, offsetof (struct function, x_return_label), rtx_type_def},
+ {0, 0, offsetof (struct function, x_save_expr_regs), rtx_type_def},
+ {0, 0, offsetof (struct function, x_stack_slot_list), rtx_type_def},
+ {0, 0, offsetof (struct function, x_rtl_expr_chain), tree_type_def},
+ {0, 0, offsetof (struct function, x_tail_recursion_label), rtx_type_def},
+ {0, 0, offsetof (struct function, x_arg_pointer_save_area), rtx_type_def},
+ {0, 0, offsetof (struct function, x_clobber_return_insn), rtx_type_def},
+ {0, 0, offsetof (struct function, x_context_display), tree_type_def},
+ {0, 0, offsetof (struct function, x_trampoline_list), tree_type_def},
+ {0, 0, offsetof (struct function, x_parm_birth_insn), rtx_type_def},
+ {0, 0, offsetof (struct function, x_last_parm_insn), rtx_type_def},
+ /* rtx *x_parm_reg_stack_loc; */
+ /* struct temp_slot *x_temp_slots; */
+ /* struct var_refs_queue *fixup_var_refs_queue; */
+ {0, 0, offsetof (struct function, original_arg_vector), rtvec_type_def},
+ {0, 0, offsetof (struct function, original_decl_initial), tree_type_def},
+ {0, 0, offsetof (struct function, inl_last_parm_insn), rtx_type_def},
+ /* struct machine_function *machine */
+ {0, 0, offsetof (struct function, language), lang_function_type_def},
+ {0, 0, offsetof (struct function, epilogue_delay_list), rtx_type_def},
+ NO_MORE_FIELDS
+};
+
+static size_t
+regno_pointer_flag_size_fetcher (v, td)
+ const void *v;
+ type_definition_p td ATTRIBUTE_UNUSED;
+{
+ return ((struct emit_status *)v)->regno_pointer_align_length;
+}
+
+static size_t
+regno_reg_rtx_size_fetcher (v, td)
+ const void *v;
+ type_definition_p td ATTRIBUTE_UNUSED;
+{
+ return ((struct emit_status *) v)->regno_pointer_align_length * sizeof (rtx);
+}
+
+static int
+regno_reg_rtx_more_fields (fp, v, n, c, td)
+ struct field_definition_s *fp;
+ const void *v;
+ unsigned n;
+ code_type c ATTRIBUTE_UNUSED;
+ type_definition_p td ATTRIBUTE_UNUSED;
+{
+ struct emit_status *e = (struct emit_status *) v;
+
+ if (n < (unsigned) e->regno_pointer_align_length)
+ {
+ fp->offset = n * sizeof (rtx);
+ fp->type = rtx_type_def;
+ return 1;
+ }
+ return 0;
+}
+
+static const struct field_definition_s emit_status_field_defs[] = {
+ {0, 0, offsetof (struct emit_status, x_first_insn), rtx_type_def},
+ {0, 0, offsetof (struct emit_status, x_last_insn), rtx_type_def},
+ /* tree sequence_rtl_expr; -- only valid while generating a sequence. */
+ /* struct sequence_stack *sequence_stack; -- should be NULL. */
+ /* char *x_last_filename; -- only used to emit NOTEs. */
+ NO_MORE_FIELDS
+};
+
+static const struct subobject_definition_s emit_status_subobject_defs[] = {
+ { 0, 0, offsetof (struct emit_status, regno_pointer_align),
+ regno_pointer_flag_size_fetcher, NULL },
+ { 0, 0, offsetof (struct emit_status, x_regno_reg_rtx),
+ regno_reg_rtx_size_fetcher, regno_reg_rtx_more_fields },
+ NO_MORE_SUBOBJECTS
+};
+
+#define VARRAY_HEAD_SIZE \
+ (sizeof (struct varray_head_tag) - sizeof (varray_data))
+
+static size_t
+varray_size_fetcher (v, td)
+ const void *v;
+ type_definition_p td ATTRIBUTE_UNUSED;
+{
+ varray_type va = (varray_type) v;
+
+ return va->num_elements * va->element_size + VARRAY_HEAD_SIZE;
+}
+
+static int
+varray_more_fields (fp, v, n, c, td)
+ struct field_definition_s *fp;
+ const void *v;
+ unsigned n;
+ code_type c ATTRIBUTE_UNUSED;
+ type_definition_p td;
+{
+ varray_type va = (varray_type) v;
+
+ if (n < VARRAY_SIZE (va))
+ {
+ int i = type_to_type_index (td) + (tree_type_ndx - varray_tree_type_ndx);
+
+ fp->offset =
+ (offsetof (struct varray_head_tag, data) + n * va->element_size);
+ fp->type = type_index_to_type (i);
+ return 1;
+ }
+ return 0;
+}
+
+#define HTAB_HEAD_SIZE \
+ (sizeof ( htab_t))
+
+static size_t
+htab_size_fetcher (v, td)
+ const void *v;
+ type_definition_p td ATTRIBUTE_UNUSED;
+{
+ struct htab *va = (struct htab *) v;
+
+ return va->size + HTAB_HEAD_SIZE;
+}
+
+static int
+htab_more_fields (fp, v, n, c, td)
+ struct field_definition_s *fp;
+ const void *v;
+ unsigned n;
+ code_type c ATTRIBUTE_UNUSED;
+ type_definition_p td;
+{
+ struct htab *va = (struct htab *) v;
+
+#if 0
+ if (n < VARRAY_SIZE (va))
+ {
+ int i = type_to_type_index (td) + (tree_type_ndx - htab_tree_type_ndx);
+
+ fp->offset =
+ (offsetof (struct htab_head_tag, data) + n * va->element_size);
+ fp->type = type_index_to_type (i);
+ return 1;
+ }
+#endif
+ return 0;
+}
+
+static int
+typed_addresses_list_more_fields (fp, v, n, c, td)
+ struct field_definition_s *fp;
+ const void *v;
+ unsigned n;
+ code_type c ATTRIBUTE_UNUSED;
+ type_definition_p td ATTRIBUTE_UNUSED;
+{
+ typed_addresses_list_p l = (typed_addresses_list_p) v;
+
+ if (n < TYPED_ADDRESSES_LIST_CHUNK_SIZE)
+ {
+ fp->offset = (offsetof (typed_addresses_list, ta)
+ + n * sizeof (struct typed_addresses_s)
+ + offsetof (struct typed_addresses_s, p));
+ fp->type = l->ta[n].td;
+ return 1;
+ }
+ else if (n == TYPED_ADDRESSES_LIST_CHUNK_SIZE)
+ {
+ fp->offset = offsetof (typed_addresses_list, next);
+ fp->type = typed_addresses_list_type_def;
+ return 1;
+ }
+ return 0;
+}
+
+/* A description of the pointer fields in a type. */
+
+struct type_definition_s basic_type_defs[num_type_defs] = {
+ { /* tree */
+ tree_code_fetcher,
+ tree_size_fetcher,
+ NULL,
+ sizeof (struct tree_common),
+ tree_field_defs,
+ tree_more_fields,
+ NULL,
+ 1},
+ { /* rtx */
+ NULL,
+ rtx_size_fetcher,
+ NULL,
+ sizeof (struct rtx_def) - sizeof (rtunion),
+ NULL,
+ rtx_more_fields,
+ NULL,
+ 1}
+ ,
+ { /* rtvec */
+ NULL,
+ rtvec_size_fetcher,
+ NULL,
+ sizeof (struct rtvec_def) - sizeof (rtx),
+ NULL,
+ rtvec_more_fields,
+ NULL,
+ 1}
+ ,
+ { /* string */
+ NULL, string_size_fetcher, NULL, 0, NULL, NULL, NULL, 1}
+ ,
+ /* struct lang_type, initialized by the language-specific frontends. */
+ {NULL, constant_size_fetcher, NULL, 0, NULL, NULL, NULL, 1}
+ ,
+ /* struct lang_decl, initialized by the language-specific frontends. */
+ {NULL, constant_size_fetcher, NULL, 0, NULL, NULL, NULL, 1}
+ ,
+ { /* struct function */
+ NULL,
+ constant_size_fetcher,
+ NULL,
+ sizeof (struct function),
+ function_field_defs,
+ NULL,
+ NULL,
+ 0},
+ /* struct lang_function, initialized by the language-specific frontends. */
+ {NULL, constant_size_fetcher, NULL, 0, NULL, NULL, NULL, 1},
+ { /* struct emit_status */
+ NULL,
+ constant_size_fetcher,
+ NULL,
+ sizeof (struct emit_status),
+ emit_status_field_defs,
+ NULL,
+ emit_status_subobject_defs,
+ 0},
+ /* The variable `typevec' in dbxout.c, initialized there. */
+ {NULL, constant_size_fetcher, NULL, 0, NULL, NULL, NULL, 0},
+ /* struct dbx_file in dbxout.c, initialized there. */
+ {NULL, constant_size_fetcher, NULL, 0, NULL, NULL, NULL, 0},
+ /* The various varray types, arranged in the same order as
+ tree/rtx/rtvec/string above. They are distinguished by their
+ addresses. */
+ {NULL, htab_size_fetcher, NULL, HTAB_HEAD_SIZE, NULL,
+ htab_more_fields, NULL, -1},
+ {NULL, varray_size_fetcher, NULL, VARRAY_HEAD_SIZE, NULL,
+ varray_more_fields, NULL, -1},
+ {NULL, varray_size_fetcher, NULL, VARRAY_HEAD_SIZE, NULL,
+ varray_more_fields, NULL, -1},
+ {NULL, varray_size_fetcher, NULL, VARRAY_HEAD_SIZE, NULL,
+ varray_more_fields, NULL, -1},
+ {NULL, varray_size_fetcher, NULL, VARRAY_HEAD_SIZE, NULL,
+ varray_more_fields, NULL, -1},
+ { /* typed_addresses_list */
+ NULL,
+ constant_size_fetcher,
+ NULL,
+ sizeof (typed_addresses_list),
+ NULL,
+ typed_addresses_list_more_fields,
+ NULL,
+ 0}
+ ,
+ /* Language-specific types, initialized in the frontend. */
+ {NULL, constant_size_fetcher, NULL, 0, NULL, NULL, NULL, -1}
+ ,
+ {NULL, constant_size_fetcher, NULL, 0, NULL, NULL, NULL, 0}
+ ,
+ {NULL, constant_size_fetcher, NULL, 0, NULL, NULL, NULL, 0}
+ ,
+ {NULL, constant_size_fetcher, NULL, 0, NULL, NULL, NULL, 0}
+ ,
+ {NULL, constant_size_fetcher, NULL, 0, NULL, NULL, NULL, 0}
+ ,
+};
+
+void
+apply_pointer (p, td, pfn, param)
+ void *p;
+ type_definition_p td;
+ pointerfn_fnp pfn;
+ void *param;
+{
+ code_type c = 0;
+
+ if (td->code_fetcher)
+ c = td->code_fetcher (p);
+
+ if (td->field_definitions != NULL)
+ {
+ int i;
+
+ for (i = 0; td->field_definitions[i].type != NULL; i++)
+ if ((c & td->field_definitions[i].mask)
+ == td->field_definitions[i].cond)
+ pfn ((void **) ((char *) p + td->field_definitions[i].offset),
+ td->field_definitions[i].type, param);
+ }
+ if (td->more_fields)
+ {
+ unsigned i = 0;
+ struct field_definition_s fp;
+
+ fp.cond = fp.mask = 0;
+ while (td->more_fields (&fp, p, i++, c, td))
+ if (fp.type != NULL)
+ pfn ((void **) ((char *) p + fp.offset), fp.type, param);
+ }
+ if (td->subobject_definitions)
+ {
+ subobject_definition_p sd;
+
+ for (sd = td->subobject_definitions; sd->size_fetcher != NULL; sd++)
+ if (sd->fields && ((c & sd->mask) == sd->cond))
+ {
+ unsigned j = 0;
+ struct field_definition_s fp;
+ char *sdf = (char *) *(void **) ((char *) p + sd->offset);
+
+ if (sdf)
+ while (sd->fields (&fp, p, j++, c, td))
+ if (fp.type != NULL)
+ pfn ((void **) (sdf + fp.offset), fp.type, param);
+ }
+ }
+}
+
+
+/* Apply FN with context CTX to every pointer reachable from V, and
+apply SF to every subobject. V has type TD. SF may be NULL in which
+case it is treated as returning 1 if and only if the pointer to the subobject
+is not NULL. */
+
+void
+apply_pointer_recursively (p_p, td_p, pfn, sfn, param)
+ void *p_p;
+ type_definition_p td_p;
+ r_pointerfn_fnp pfn;
+ s_pointerfn_fnp sfn;
+ void *param;
+{
+ enum { worklist_size = 384 };
+ typed_address worklist[worklist_size];
+ unsigned worklist_next;
+
+ worklist[0].p = p_p;
+ worklist[0].td = td_p;
+ worklist_next = 1;
+
+ do
+ {
+ code_type c = 0;
+ type_definition_p td;
+ void *p;
+
+ worklist_next--;
+ p = worklist[worklist_next].p;
+ td = worklist[worklist_next].td;
+
+ if (td->code_fetcher)
+ c = td->code_fetcher (p);
+
+ if (td->field_definitions != NULL)
+ {
+ int i;
+
+ for (i = 0; td->field_definitions[i].type != NULL; i++)
+ if ((c & td->field_definitions[i].mask)
+ == td->field_definitions[i].cond)
+ {
+ void **np = (void **) ((char *) p
+ + td->field_definitions[i].offset);
+ type_definition_p ntd = td->field_definitions[i].type;
+
+ if (pfn (np, ntd, param))
+ {
+ if (worklist_next < worklist_size)
+ {
+ worklist[worklist_next].p = *np;
+ worklist[worklist_next].td = ntd;
+ worklist_next++;
+ }
+ else
+ apply_pointer_recursively (*np, ntd, pfn, sfn, param);
+ }
+ }
+ }
+ if (td->more_fields)
+ {
+ unsigned i = 0;
+ struct field_definition_s fp;
+
+ fp.cond = fp.mask = 0;
+ while (td->more_fields (&fp, p, i++, c, td))
+ if (fp.type != NULL)
+ if (pfn ((void **) ((char *) p + fp.offset), fp.type, param))
+ {
+ void *np = *(void **) ((char *) p + fp.offset);
+
+ if (worklist_next < worklist_size)
+ {
+ worklist[worklist_next].p = np;
+ worklist[worklist_next].td = fp.type;
+ worklist_next++;
+ }
+ else
+ apply_pointer_recursively (np, fp.type, pfn, sfn, param);
+ }
+ }
+ if (td->subobject_definitions)
+ {
+ subobject_definition_p sd;
+
+ for (sd = td->subobject_definitions; sd->size_fetcher != NULL; sd++)
+ if (sd->fields && ((c & sd->mask) == sd->cond))
+ {
+ unsigned j = 0;
+ struct field_definition_s fp;
+
+ char *sdf = (char *) *(void **) ((char *) p + sd->offset);
+
+ if ((!sfn && sdf)
+ || (sfn
+ && sfn (p, td, (void **) ((char *) p + sd->offset),
+ sd, param)))
+ while (sd->fields (&fp, p, j++, c, td))
+ if (fp.type != NULL)
+ if (pfn ((void **) (sdf + fp.offset), fp.type, param))
+ {
+ void *np = *(void **) (sdf + fp.offset);
+
+ if (worklist_next < worklist_size)
+ {
+ worklist[worklist_next].p = np;
+ worklist[worklist_next].td = fp.type;
+ worklist_next++;
+ }
+ else {
+if (fp.offset == 36900 ) haltit();
+ apply_pointer_recursively (np, fp.type, pfn, sfn,
+ param);
+ }
+ }
+ }
+ }
+ }
+ while (worklist_next > 0);
+}
+
+/* Add a block of typed addresses to a list. */
+
+
+void
+add_typed_addresses (list, p, td, count, name)
+ typed_addresses_list_p list;
+ void **p;
+ type_definition_p td;
+ size_t count;
+ const char *name;
+{
+ int i;
+
+#ifdef GT_DEBUG
+ fprintf(stderr,"add_typed_addresses (%s)\n",name);
+#endif
+ while (list->next)
+ list = list->next;
+ if (list->ta[TYPED_ADDRESSES_LIST_CHUNK_SIZE - 1].p)
+ list = list->next = xcalloc (1, sizeof (*list->next));
+ for (i = 0; i < TYPED_ADDRESSES_LIST_CHUNK_SIZE; i++)
+ if (!list->ta[i].p)
+ {
+ list->ta[i].p = p;
+ list->ta[i].td = td;
+ list->ta[i].count = count;
+ list->ta[i].name = name;
+ return;
+ }
+ abort ();
+}
+
+/* Add addresses of various types to a list. */
+
+void
+add_tree_addresses (list, p, count, name)
+ typed_addresses_list_p list;
+ tree *p;
+ size_t count;
+ const char *name;
+{
+#ifdef GT_DEBUG
+ fprintf(stderr,"add_tree_addresses (%s)\n",name);
+#endif
+ add_typed_addresses (list, (void **) p, tree_type_def, count, name);
+}
+
+void
+add_rtx_addresses (list, p, count, name)
+ typed_addresses_list_p list;
+ rtx *p;
+ size_t count;
+ const char *name;
+{
+#ifdef GT_DEBUG
+ fprintf(stderr,"add_rtx_addresses (%s)\n",name);
+#endif
+ add_typed_addresses (list, (void **) p, rtx_type_def, count, name);
+}
+
+void
+add_hash_tree_addresses (list, p, count, name)
+ typed_addresses_list_p list;
+ struct htab *p;
+ size_t count;
+ const char *name;
+{
+#ifdef GT_DEBUG
+ fprintf(stderr,"add_hash_tree_addresses (%s)\n",name);
+#endif
+ add_typed_addresses (list, (void **) p, hash_tree_type_def, count, name);
+}
+
+void
+add_varray_tree_addresses (list, p, count, name)
+ typed_addresses_list_p list;
+ varray_type *p;
+ size_t count;
+ const char *name;
+{
+#ifdef GT_DEBUG
+ fprintf(stderr,"add_varray_tree_addresses (%s)\n",name);
+#endif
+ add_typed_addresses (list, (void **) p, varray_tree_type_def, count, name);
+}
+
+
+/* Do something to each pointer in a list. */
+
+void
+apply_list_pointers (list, fn, ctx)
+ typed_addresses_list_p list;
+ pointerfn_fnp fn;
+ void *ctx;
+{
+ int i;
+ size_t j;
+
+ for (; list; list = list->next)
+ for (i = 0; i < TYPED_ADDRESSES_LIST_CHUNK_SIZE; i++)
+ if (list->ta[i].p && list->ta[i].td)
+ for (j = list->ta[i].count; j > 0; j--)
+ fn (list->ta[i].p + (j - 1), list->ta[i].td, ctx);
+}
+
+/* Do something to each pointer referenced by a list. */
+
+void
+apply_list_pointers_recursively (list, fn, sfn, ctx)
+ typed_addresses_list_p list;
+ r_pointerfn_fnp fn;
+ s_pointerfn_fnp sfn;
+ void *ctx;
+{
+ int i;
+ size_t j;
+
+ for (; list; list = list->next)
+ for (i = 0; i < TYPED_ADDRESSES_LIST_CHUNK_SIZE; i++) {
+#ifdef GT_DEBUG
+ fprintf(stderr,"APLPR(%s)\n",list->ta[i].name);
+#endif
+ if (list->ta[i].p && list->ta[i].td)
+ for (j = list->ta[i].count; j > 0; j--)
+ if (fn (list->ta[i].p + (j - 1), list->ta[i].td, ctx))
+ apply_pointer_recursively (list->ta[i].p[j - 1], list->ta[i].td,
+ fn, sfn, ctx);
+ }
+}
+
+
+/* Add a block of untyped memory to a list. */
+
+void
+add_untyped_address (list, p, size, name)
+ typed_addresses_list_p list;
+ void *p;
+ size_t size;
+ const char *name;
+{
+ int i;
+
+#ifdef GT_DEBUG
+ fprintf(stderr,"add_untyped_address (%s)\n",name);
+#endif
+ while (list->next)
+ list = list->next;
+ if (list->ta[TYPED_ADDRESSES_LIST_CHUNK_SIZE - 1].p)
+ list = list->next = xcalloc (1, sizeof (*list->next));
+ for (i = 0; i < TYPED_ADDRESSES_LIST_CHUNK_SIZE; i++)
+ if (!list->ta[i].p)
+ {
+ list->ta[i].p = (void **) p;
+ list->ta[i].td = NULL;
+ list->ta[i].count = size;
+ list->ta[i].name = name;
+ return;
+ }
+ abort ();
+}
+
+
+/* Do something to each untyped memory block in a list. */
+
+void
+apply_list_untyped (list, fn, ctx)
+ typed_addresses_list_p list;
+ untypedfn_fnp fn;
+ void *ctx;
+{
+ int i;
+
+ for (; list; list = list->next)
+ for (i = 0; i < TYPED_ADDRESSES_LIST_CHUNK_SIZE; i++)
+ if (list->ta[i].p && !list->ta[i].td)
+ fn ((void *) list->ta[i].p, list->ta[i].count, ctx);
+}
+
+/* Remove an address (typed or untyped) from a list. */
+
+void
+remove_list_address (list, p)
+ typed_addresses_list_p list;
+ void *p;
+{
+ int i;
+ for (; list; list = list->next)
+ for (i = 0; i < TYPED_ADDRESSES_LIST_CHUNK_SIZE; i++)
+ if (list->ta[i].p == p)
+ {
+ typed_addresses_list_p tail = list;
+ int taili;
+
+ while (tail->next)
+ tail = tail->next;
+ for (taili = 0; taili < TYPED_ADDRESSES_LIST_CHUNK_SIZE; taili++)
+ if (!tail->ta[taili].p)
+ break;
+
+ list->ta[i] = tail->ta[i];
+ tail->ta[i].p = NULL;
+ return;
+ }
+ abort ();
+}
+
+/* Count items in a list. */
+
+void
+count_list_pointers (list, typed_p, untyped_p)
+ typed_addresses_list_p list;
+ size_t *typed_p;
+ size_t *untyped_p;
+{
+ size_t typed, untyped;
+ int i;
+
+ typed = untyped = 0;
+ for (; list; list = list->next)
+ for (i = 0; i < TYPED_ADDRESSES_LIST_CHUNK_SIZE; i++)
+ if (list->ta[i].p)
+ {
+ if (list->ta[i].td)
+ typed += list->ta[i].count;
+ else
+ untyped++;
+ }
+
+ if (typed_p)
+ *typed_p = typed;
+ if (untyped_p)
+ *untyped_p = untyped;
+}
+
+
+/* Update a checksum of the addresses in LIST. If LIST refers to the
+same list of pointers, the checksum shouldn't vary even between
+different runs of the program. Initially, set CHKSUM to contain
+all zeros. */
+
+void
+sum_type_addresses_list (cksum, list)
+ unsigned char cksum[CHECKSUM_SIZE];
+ typed_addresses_list_p list;
+{
+ struct md5_ctx ctx;
+ unsigned char result[16];
+ typed_addresses_list_p l;
+ int i;
+
+ md5_init_ctx (&ctx);
+ md5_process_bytes (cksum, CHECKSUM_SIZE, &ctx);
+
+ for (l = list; l; l = l->next)
+ for (i = 0; i < TYPED_ADDRESSES_LIST_CHUNK_SIZE; i++)
+ if (l->ta[i].p && !l->ta[i].td)
+ {
+ md5_process_bytes (&l->ta[i].count, sizeof (l->ta[i].count), &ctx);
+ md5_process_bytes (l->ta[i].p, l->ta[i].count, &ctx);
+ }
+
+ for (l = list; l; l = l->next)
+ for (i = 0; i < TYPED_ADDRESSES_LIST_CHUNK_SIZE; i++)
+ if (l->ta[i].p && l->ta[i].td)
+ {
+ int ndx;
+ type_definition_p td = l->ta[i].td;
+ size_t j;
+
+ md5_process_bytes (&l->ta[i].count, sizeof (l->ta[i].count), &ctx);
+ ndx = type_to_type_index (td);
+ md5_process_bytes (&ndx, sizeof (ndx), &ctx);
+ if (td->field_definitions == NULL && td->more_fields == NULL)
+ for (j = 0; j < l->ta[i].count; j++)
+ if (l->ta[i].p[j] && 0)
+ {
+ size_t sz;
+ sz = td->size_fetcher (l->ta[i].p[j], td);
+ md5_process_bytes (&sz, sizeof (sz), &ctx);
+ md5_process_bytes (l->ta[i].p[j], sz, &ctx);
+ }
+ }
+
+ md5_finish_ctx (&ctx, result);
+ memcpy (cksum, result, CHECKSUM_SIZE);
+}
+
+struct pch_header
+{
+ unsigned n[num_type_defs];
+ unsigned max_size;
+ unsigned string_size;
+};
+
+typedef struct pch_reader_context
+{
+ struct pch_header h;
+ unsigned n_constant[num_type_defs];
+ void **r[num_type_defs];
+ int *rv;
+ size_t rvndx;
+ FILE *f;
+ int error;
+}
+ *rctx_t;
+
+static void add_reader_pointer_directly PARAMS ((void **v,
+ type_definition_p td,
+ void *c_v));
+static void correct_pointer PARAMS ((void **v,
+ type_definition_p td, void *c_v));
+static void restore_variable PARAMS ((void **v,
+ type_definition_p td, void *c_v));
+static void read_untyped PARAMS ((void *v, size_t sz, void *ctx));
+
+static void
+add_reader_pointer_directly (v, td, c_v)
+ void **v;
+ type_definition_p td;
+ void *c_v;
+{
+ rctx_t c = (rctx_t) c_v;
+ enum type_index_e i = type_to_type_index (td);
+
+ c->r[i][c->n_constant[i]++] = *v;
+}
+
+static void
+correct_pointer (x, td, c_v)
+ void **x;
+ type_definition_p td;
+ void *c_v;
+{
+ rctx_t c = (rctx_t) c_v;
+ enum type_index_e i = type_to_type_index (td);
+
+#ifdef GT_DEBUG
+fprintf(stderr,"correct_pointer ( x = %p )\n",*x);
+#endif
+ *x = c->r[i][(unsigned) (*x)];
+}
+
+static void
+restore_variable (x, td, c_v)
+ void **x;
+ type_definition_p td;
+ void *c_v;
+{
+ rctx_t c = (rctx_t) c_v;
+ enum type_index_e i = type_to_type_index (td);
+ int xi = c->rv[c->rvndx++];
+
+#ifdef ENABLE_CHECKING
+ if ((td->ggc_p <= 0) && (*x != NULL) && (*x != c->r[i][xi]))
+ warning ("PCH: leaking data structure at %x", *x);
+#endif
+
+ *x = c->r[i][xi];
+}
+
+static void
+read_untyped (v, sz, c_v)
+ void *v;
+ size_t sz;
+ void *c_v;
+{
+ rctx_t c = c_v;
+ if (!c->error)
+ if (fread (v, sz, 1, c->f) != 1)
+ c->error = 1;
+}
+
+
+/* Restore a list. KNOWN and LIST must point to the same list of pointers
+as was originally written. */
+
+int
+read_type_addresses_list (f, known, list)
+ FILE *f;
+ typed_addresses_list_p known;
+ typed_addresses_list_p list;
+{
+ struct pch_reader_context c;
+ char *buf;
+ enum type_index_e i;
+ unsigned j;
+ size_t listsize;
+ void *null = 0;
+
+ memset((void *)&c, 0, sizeof(struct pch_reader_context));
+ /* Read the header from the file. */
+ c.f = f;
+ if (fread (&c.h, sizeof (c.h), 1, c.f) != 1)
+ return -1;
+
+ /* Allocate the main static arrays, initialise the context. */
+ for (i = 0; i < num_type_defs; i++)
+ {
+ c.n_constant[i] = 0;
+ c.r[i] = xcalloc (c.h.n[i], sizeof (void *));
+
+ /* Add NULL pointers for each kind of object. */
+
+ add_reader_pointer_directly (&null, type_index_to_type (i), &c);
+ }
+
+ /* Add the known pointers. */
+ apply_list_pointers (known, add_reader_pointer_directly, &c);
+
+ c.error = 0;
+
+ /* Read in the untyped data. */
+ apply_list_untyped (list, read_untyped, &c);
+
+ if (c.error)
+ return -1;
+
+ buf = xmalloc (c.h.max_size);
+
+ /* Read in the string table. */
+ if (c.h.n[string_type_ndx] > 0)
+ {
+ char *string_table;
+ char *p;
+
+ string_table = xmalloc (c.h.string_size);
+ if (fread (string_table, c.h.string_size, 1, c.f) != 1)
+ return -1;
+
+ p = string_table;
+ i = string_type_ndx;
+ for (j = 1; j < c.h.n[i]; ++j)
+ {
+ int len = strlen (p);
+ c.r[i][j] = (void *)ggc_alloc_string (p, len);
+#ifdef GT_DEBUG
+fprintf(stderr,"Reading (%s)\n",p);
+#endif
+ p += len + 1;
+ }
+
+ if (p != (string_table + c.h.string_size))
+ abort ();
+ free (string_table);
+ }
+
+ /* Read in all the data... */
+ for (i = 0; i < num_type_defs; i++)
+ if (i != string_type_ndx)
+ for (j = c.n_constant[i]; j < c.h.n[i]; j++)
+ {
+ type_definition_p td = type_index_to_type (i);
+ size_t sz, readsize;
+
+ /* Read in enough to be able to determine the type's size. */
+ readsize = td->size;
+ if (readsize != 0 && fread (buf, readsize, 1, c.f) != 1)
+ return -1;
+
+ /* There's a really annoying special case here for
+ TREE_VEC trees. We need more information to be able
+ to determine their size. */
+ if (i == tree_type_ndx && TREE_CODE ((tree) buf) == TREE_VEC)
+ {
+ if (fread (buf + readsize, sizeof (struct tree_vec) - readsize,
+ 1, c.f) != 1)
+ return -1;
+ readsize = sizeof (struct tree_vec);
+ }
+
+ sz = td->size_fetcher (buf, td);
+ if (sz != readsize)
+ if (fread (buf + readsize, sz - readsize, 1, c.f) != 1)
+ return -1;
+
+ /* Handle reading any subobjects. */
+ if (td->subobject_definitions)
+ {
+ subobject_definition_p sd;
+ code_type code = 0;
+
+ if (td->code_fetcher)
+ code = td->code_fetcher (buf);
+ for (sd = td->subobject_definitions;
+ sd->size_fetcher != NULL; sd++)
+ if ((code & sd->mask) == sd->cond)
+ {
+ size_t sz;
+ char *sob;
+
+ if (fgetc (c.f) == 0)
+ {
+ *(char **) (buf + sd->offset) = 0;
+ continue;
+ }
+
+ sz = sd->size_fetcher (buf, td);
+ if (td->ggc_p > 0)
+ sob = ggc_alloc (sz);
+ else
+ sob = xmalloc (sz);
+ if (fread (sob, sz, 1, c.f) != 1)
+ return -1;
+ *(char **) (buf + sd->offset) = sob;
+ }
+ }
+
+ /* IDENTIFIER_NODEs must be canonicalized. Ask
+ get_identifier what the canonical IDENTIFIER_NODE
+ should be. */
+ if (i == tree_type_ndx && TREE_CODE ((tree) buf) == IDENTIFIER_NODE)
+ {
+ tree oldt = (tree) buf;
+ tree t;
+#if 1
+ correct_pointer ((void **)IDENTIFIER_POINTER (oldt),
+ string_type_def, &c);
+#else
+ correct_pointer ((void **) IDENTIFIER_POINTER (oldt),
+ identifier_type_def, &c);
+#endif
+ t = get_identifier (IDENTIFIER_POINTER (oldt));
+
+ TREE_CHAIN (oldt) = TREE_CHAIN (t);
+ c.r[i][j] = t;
+ }
+ else
+ if (td->ggc_p > 0)
+ c.r[i][j] = ggc_alloc (sz);
+ else
+ c.r[i][j] = xmalloc (sz);
+ memcpy (c.r[i][j], buf, sz);
+ }
+ free (buf);
+
+ /* Fix up all the pointers in the just-read structures. */
+ for (i = 0; i < num_type_defs; i++)
+ if (i != string_type_ndx)
+ for (j = c.n_constant[i]; j < c.h.n[i]; j++)
+ {
+ if (i == tree_type_ndx
+ && TREE_CODE ((tree) c.r[i][j]) == IDENTIFIER_NODE)
+ {
+ tree old_chain;
+ const char *old_identifier_pointer;
+
+ /* For IDENTIFIER_NODEs, the IDENTIFIER_POINTER and the
+ TREE_CHAIN are pointers at this point, so save and
+ restore them around the correction. */
+ old_chain = TREE_CHAIN ((tree) c.r[i][j]);
+ old_identifier_pointer = IDENTIFIER_POINTER ((tree) c.r[i][j]);
+ TREE_CHAIN ((tree) c.r[i][j]) = (tree) 0;
+ IDENTIFIER_POINTER ((tree) c.r[i][j]) = (char *) 0; /* FIXME */
+
+ apply_pointer (c.r[i][j], type_index_to_type (i),
+ correct_pointer, &c);
+
+ TREE_CHAIN ((tree) c.r[i][j]) = old_chain;
+ IDENTIFIER_POINTER ((tree) c.r[i][j]) = old_identifier_pointer;/* FIXME */
+ }
+ else
+ apply_pointer (c.r[i][j], type_index_to_type (i), correct_pointer,
+ &c);
+ }
+
+ /* Store the values read into the list. */
+ count_list_pointers (list, &listsize, NULL);
+ c.rv = xmalloc (listsize * sizeof (int));
+ if (fread (c.rv, sizeof (int), listsize, c.f) != listsize)
+ return -1;
+ c.rvndx = 0;
+ apply_list_pointers (list, restore_variable, &c);
+ free (c.rv);
+ for (i = 0; i < num_type_defs; i++)
+ free (c.r[i]);
+
+ return 0;
+}
+
+
+static int pointer_ent_eq PARAMS ((const void *, const void *));
+static hashval_t pointer_ent_hash PARAMS ((const void *));
+static unsigned add_one_pointer PARAMS ((void *v, type_definition_p td,
+ wctx_t ctx));
+static int add_writer_pointer_wrapper PARAMS ((void **v, type_definition_p td,
+ void *ctx));
+static void record_writer_pointer PARAMS ((void **v, type_definition_p td,
+ void *ctx));
+static void add_writer_pointer_directly PARAMS ((void **v,
+ type_definition_p td,
+ void *ctx));
+static int prewrite_pointer PARAMS ((void **, void *));
+static void pickle_pointer PARAMS ((void **v, type_definition_p td,
+ void *ctx));
+static int write_kind PARAMS ((enum type_index_e, wctx_t));
+static void write_untyped PARAMS ((void *v, size_t sz, void *ctx));
+
+static int
+pointer_ent_eq (a_p, b_p)
+ const void *a_p;
+ const void *b_p;
+{
+ const struct pointer_ent *a = (const struct pointer_ent *) a_p;
+ const struct pointer_ent *b = (const struct pointer_ent *) b_p;
+
+ return a->v == b->v && a->td == b->td;
+}
+
+static hashval_t
+pointer_ent_hash (a_p)
+ const void *a_p;
+{
+ const struct pointer_ent *a = (const struct pointer_ent *) a_p;
+
+ return (hashval_t) a->v;
+}
+
+/* Add the object pointer V, of type TD, to the hash table in C, recording
+ its index for later use. */
+
+static unsigned
+add_one_pointer (v, td, c)
+ void *v;
+ type_definition_p td;
+ wctx_t c;
+{
+ struct pointer_ent e;
+ int i = type_to_type_index (td);
+ void **slot;
+
+ e.v = v;
+ e.td = td;
+ e.ndx = c->n[i];
+ slot = htab_find_slot (c->pointer_h, &e, INSERT);
+ if (*slot == NULL)
+ {
+ *slot = ggc_alloc (sizeof (e));
+ memcpy (*slot, &e, sizeof (e));
+ if (td == string_type_def)
+ c->string_size += (v == NULL ? 1 : td->size_fetcher (v, td));
+ c->n[i]++;
+ return e.ndx;
+ }
+ else
+ return ((struct pointer_ent *) *slot)->ndx;
+}
+
+static int
+add_writer_pointer_wrapper (v_p, td, c_v)
+ void **v_p;
+ type_definition_p td;
+ void *c_v;
+{
+ wctx_t c = (void *) c_v;
+ int i = type_to_type_index (td);
+ unsigned old_n = c->n[i];
+ unsigned ndx;
+
+ ndx = add_one_pointer (*v_p, td, c);
+ return ndx == old_n;
+}
+
+static void
+record_writer_pointer (v_p, td, c_v)
+ void **v_p;
+ type_definition_p td;
+ void *c_v;
+{
+ wctx_t c = c_v;
+ int i = type_to_type_index (td);
+ unsigned old_n = c->n[i];
+ unsigned ndx;
+
+ ndx = add_one_pointer (*v_p, td, c);
+ if (ndx == old_n)
+ apply_pointer_recursively (*v_p, td, add_writer_pointer_wrapper, NULL,
+ c_v);
+}
+
+/* Record the indices of the objects pointed to by a variable in the
+ data_to_save list. This must happen after the indices in the hash table
+ are final; i.e. after any sorting done in setup_strtab. */
+
+static void
+record_listed_nodes (v_p, td, c_v)
+ void **v_p;
+ type_definition_p td;
+ void *c_v;
+{
+ wctx_t c = c_v;
+ struct pointer_ent e;
+ struct pointer_ent *p;
+
+ e.v = *v_p;
+ e.td = td;
+ e.ndx = 0; /* ndx should never be used by the lookup. */
+
+ p = (struct pointer_ent *) htab_find (c->pointer_h, &e);
+ if (p == NULL)
+ abort ();
+
+ c->listd[c->listd_ndx++] = p->ndx;
+}
+
+static void
+add_writer_pointer_directly (x_p, td, c_v)
+ void **x_p;
+ type_definition_p td;
+ void *c_v;
+{
+ wctx_t c = (wctx_t) c_v;
+ int i = type_to_type_index (td);
+
+ if (c->n[i] != c->n_constant[i])
+ abort ();
+ add_one_pointer (*x_p, td, c);
+ c->n_constant[i]++;
+ c->n[i] = c->n_constant[i];
+}
+
+static int
+prewrite_pointer (slot, c_v)
+ void **slot;
+ void *c_v;
+{
+ wctx_t c = c_v;
+ const struct pointer_ent *e = (const struct pointer_ent *) *slot;
+ int i = type_to_type_index (e->td);
+ size_t sz = e->v == NULL ? 0 : e->td->size_fetcher (e->v, e->td);
+
+ c->ptrs[i][e->ndx] = e->v;
+
+ if (c->max_size[i] < sz)
+ c->max_size[i] = sz;
+
+ if (e->v && e->td->prewrite_hook)
+ e->td->prewrite_hook (e->v);
+
+ return 1;
+}
+
+/*
+ * Serialize pointer
+ */
+static void
+pickle_pointer (x, td, c_v)
+ void **x;
+ type_definition_p td;
+ void *c_v;
+{
+ wctx_t c = c_v;
+ struct pointer_ent e;
+ struct pointer_ent *p;
+
+ e.v = *x;
+ e.td = td;
+ e.ndx = 0; /* ndx should never be used by the lookup. */
+ p = (struct pointer_ent *) htab_find (c->pointer_h, &e);
+ if (p == NULL)
+ abort ();
+ *x = (void *) p->ndx;
+}
+
+/*
+ * Write out actual data
+ */
+static int
+write_kind (i, c)
+ enum type_index_e i;
+ wctx_t c;
+{
+ type_definition_p td = type_index_to_type (i);
+ unsigned j;
+ const unsigned maxj = c->n[i];
+ char *d = xmalloc (c->max_size[i]);
+
+ for (j = c->n_constant[i]; j < maxj; j++)
+ {
+ const void *x = c->ptrs[i][j];
+ size_t sz = td->size_fetcher (x, td);
+ code_type code = 0;
+
+ memcpy (d, x, sz);
+
+ if (td->code_fetcher)
+ code = td->code_fetcher (d);
+
+ /* Copy any subobjects. */
+ if (td->subobject_definitions)
+ {
+ subobject_definition_p sd;
+
+ for (sd = td->subobject_definitions; sd->size_fetcher != NULL; sd++)
+ if ((code & sd->mask) == sd->cond)
+ {
+ char **loc = (char **) (d + sd->offset);
+
+ if (*loc)
+ {
+ size_t sz = sd->size_fetcher (d, td);
+ char *sob = xmalloc (sz);
+ memcpy (sob, *loc, sz);
+ *loc = sob;
+ }
+ }
+ }
+
+ /* Serialize pointer d */
+ apply_pointer (d, td, pickle_pointer, c);
+
+ if (fwrite (d, sz, 1, c->f) != 1)
+ return -1;
+
+ /* Write any subobjects. */
+ if (td->subobject_definitions)
+ {
+ subobject_definition_p sd;
+
+ for (sd = td->subobject_definitions; sd->size_fetcher != NULL; sd++)
+ if ((code & sd->mask) == sd->cond)
+ {
+ size_t sz = sd->size_fetcher (d, td);
+ char *sob = *(char **) (d + sd->offset);
+ int r;
+
+ if (sob)
+ {
+ r = putc (1, c->f);
+ if (r >= 0)
+ r = fwrite (sob, sz, 1, c->f);
+ free (sob);
+ if (r != 1)
+ return -1;
+ }
+ else
+ {
+ r = putc (0, c->f);
+ if (r < 0)
+ return -1;
+ }
+ }
+ }
+ }
+
+ free (d);
+ return 0;
+}
+
+/*
+ * Write out untyped data
+ */
+static void
+write_untyped (v, sz, c_v)
+ void *v;
+ size_t sz;
+ void *c_v;
+{
+ wctx_t c = c_v;
+ fwrite (v, sz, 1, c->f);
+}
+
+#if 0
+/* FIXME Don't bother sorting the strings until we update to Zack's string
+ table code; otherwise we have no way of guaranteeing increasing
+ addresses when we read the strings back in. */
+
+/* qsort comparison function for sorting pointers by address. */
+
+static int
+pointer_compare (a_p, b_p)
+ const void *a_p;
+ const void *b_p;
+{
+ const void *a = *(const void **) a_p;
+ const void *b = *(const void **) b_p;
+
+ if (a == b)
+ return 0;
+ else if (a < b)
+ return -1;
+ else
+ return 1;
+}
+#endif
+
+/* We have accumulated the strings in c->ptrs like any other object.
+ But we want to treat them specially, in two ways:
+ - We want to read and write them as one large block rather than individual
+ objects, since the only way to determine their length at read time is
+ to search for the null.
+ - We want them to be emitted in ascending address order, so that we can
+ preserve that order for sorted lists in the C and C++ frontends.
+
+ This processing must happen before pickling. */
+
+static void
+setup_strtab (c)
+ wctx_t c;
+{
+ unsigned int i;
+ size_t string_idx;
+ struct pointer_ent e;
+ struct pointer_ent *p;
+ int ndx = string_type_ndx;
+ type_definition_p td = string_type_def;
+
+#if 0
+ /* Sort the strings by address (not alphabetically). */
+ qsort (c->ptrs[ndx] + c->n_constant[ndx],
+ c->n[ndx] - c->n_constant[ndx], sizeof (void *), pointer_compare);
+#endif
+
+ /* Set up the string table. */
+ c->string_table = xcalloc (c->string_size, 1);
+ e.td = string_type_def;
+ e.ndx = 0; /* ndx should never be used by the lookup. */
+
+ /* The NULL pointer will always be at index 0; skip it so we don't need
+ to handle it in the loop. */
+ string_idx = 1;
+ if (c->n_constant[ndx] != 1)
+ abort ();
+ for (i = c->n_constant[ndx]; i < c->n[ndx]; ++i)
+ {
+ const void *ob = c->ptrs[ndx][i];
+ size_t sz = td->size_fetcher (ob, td);
+
+ e.v = ob;
+ p = (struct pointer_ent *) htab_find (c->pointer_h, &e);
+ if (p == NULL)
+ abort ();
+
+ p->ndx = i;
+ memcpy (c->string_table + string_idx, ob, sz);
+ string_idx += sz;
+ }
+}
+
+
+/* Write out a list.
+KNOWN is a list of pointers that need not be written. */
+
+int
+write_type_addresses_list (f, known, list)
+ FILE *f;
+ typed_addresses_list_p known;
+ typed_addresses_list_p list;
+{
+ struct pch_writer_context c;
+ struct pch_header h;
+ int i;
+ size_t listsize;
+ void *null = NULL;
+
+ memset((void *)&c, 0, sizeof(struct pch_writer_context));
+ c.pointer_h = htab_create (2040, pointer_ent_hash, pointer_ent_eq, NULL);
+ c.string_size = 0;
+ for (i = 0; i < num_type_defs; i++)
+ {
+ c.n_constant[i] = 0;
+ c.n[i] = 0;
+ /* Add NULL pointers for each kind of object. */
+ add_writer_pointer_directly (&null, type_index_to_type (i), &c);
+ }
+
+ /* Add the well-known pointers. */
+ apply_list_pointers (known, add_writer_pointer_directly, &c);
+
+ /* Add the data to write; set up the list. */
+ apply_list_pointers (list, record_writer_pointer, &c);
+
+ /* Set up the ptrs[] array. */
+ for (i = 0; i < num_type_defs; i++)
+ {
+ c.ptrs[i] = xcalloc (c.n[i], sizeof (void *));
+ c.max_size[i] = 0;
+ }
+ c.f = f;
+ htab_traverse (c.pointer_h, prewrite_pointer, &c);
+
+ /* Set up the string table. */
+ setup_strtab (&c);
+
+ /* Set up the header. */
+ for (i = 0; i < num_type_defs; i++)
+ h.n[i] = c.n[i];
+
+ /* Don't bother with the initial null. */
+ h.string_size = c.string_size - 1;
+
+ /* Compute the maximum size. */
+ h.max_size = 0;
+ for (i = 0; i < num_type_defs; i++)
+ if (c.max_size[i] > h.max_size)
+ h.max_size = c.max_size[i];
+
+ /* Write out the header. */
+ if (fwrite (&h, sizeof (h), 1, f) != 1)
+ return -1;
+
+ /* Write out the untyped data. */
+ apply_list_untyped (list, write_untyped, &c);
+
+ /* Write out the strings. */
+ if (h.string_size > 0)
+ if (fwrite (c.string_table + 1, h.string_size, 1, f) != 1)
+ return -1;
+
+ /* Write out the actual data. */
+ for (i = 0; i < num_type_defs; i++)
+ if (i != string_type_ndx)
+ write_kind (i, &c);
+
+ for (i = 0; i < num_type_defs; i++)
+ free (c.ptrs[i]);
+
+ /* Record what objects the listed variables point to. */
+ count_list_pointers (list, &listsize, NULL);
+ c.listd = xmalloc (listsize * sizeof (int));
+ c.listd_ndx = 0;
+ apply_list_pointers (list, record_listed_nodes, &c);
+
+ /* Write out LIST. */
+ if (fwrite (c.listd, sizeof (int), listsize, c.f) != listsize)
+ return -1;
+ free (c.listd);
+
+ return 0;
+}
+
+/* Various global variables used by the precompiled header machinery. */
+typed_addresses_list data_to_save;
+typed_addresses_list known_pointers;
diff --git a/gcc/gtype.h b/gcc/gtype.h
new file mode 100644
index 00000000000..f82486dd527
--- /dev/null
+++ b/gcc/gtype.h
@@ -0,0 +1,307 @@
+/* Generic data handling for GNU CC.
+ Copyright (C) 2000, 2001 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING. If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
+
+
+/* Various structures that might not be declared at this point. */
+struct rtx_def;
+union tree_node;
+struct varray_head_tag;
+
+/* A description of the pointer fields in a type. */
+typedef struct type_definition_s const *type_definition_p;
+
+/* These are all the types we know.
+ (This list needs to be known at compile time so we can
+ easily write initializers for FIELD_DEFINITIONS).
+ All types we will want to put in a PCH need to be in this list, so
+ we can index into various arrays of dimension num_type_defs. */
+enum type_index_e
+{
+ tree_type_ndx,
+ rtx_type_ndx,
+ rtvec_type_ndx,
+ string_type_ndx,
+ lang_type_type_ndx,
+ lang_decl_type_ndx,
+ function_type_ndx,
+ lang_function_type_ndx,
+ emit_status_type_ndx,
+ dbx_typevec_type_ndx,
+ dbx_file_type_ndx,
+ hash_tree_type_ndx,
+ varray_tree_type_ndx,
+ varray_rtx_type_ndx,
+ varray_rtvec_type_ndx,
+ varray_string_type_ndx,
+ typed_addresses_list_type_ndx,
+
+ lang1_type_ndx,
+ lang2_type_ndx,
+ lang3_type_ndx,
+ lang4_type_ndx,
+ lang5_type_ndx,
+
+ num_type_defs,
+ no_type_ndx
+};
+#define type_index_to_type(ti) ((ti) + basic_type_defs)
+#define type_to_type_index(td) ((enum type_index_e)((td) - basic_type_defs))
+#define tree_type_def type_index_to_type (tree_type_ndx)
+#define rtx_type_def type_index_to_type (rtx_type_ndx)
+#define rtvec_type_def type_index_to_type (rtvec_type_ndx)
+#define string_type_def type_index_to_type (string_type_ndx)
+#define lang_type_type_def type_index_to_type (lang_type_type_ndx)
+#define lang_decl_type_def type_index_to_type (lang_decl_type_ndx)
+#define function_type_def type_index_to_type (function_type_ndx)
+#define lang_function_type_def type_index_to_type (lang_function_type_ndx)
+#define emit_status_type_def type_index_to_type (emit_status_type_ndx)
+#define dbx_typevec_type_def type_index_to_type (dbx_typevec_type_ndx)
+#define dbx_file_type_def type_index_to_type (dbx_file_type_ndx)
+#define hash_tree_type_def type_index_to_type (hash_tree_type_ndx)
+#define varray_tree_type_def type_index_to_type (varray_tree_type_ndx)
+#define varray_rtx_type_def type_index_to_type (varray_rtx_type_ndx)
+#define varray_rtvec_type_def type_index_to_type (varray_rtvec_type_ndx)
+#define varray_string_type_def type_index_to_type (varray_string_type_ndx)
+#define typed_addresses_list_type_def \
+ type_index_to_type (typed_addresses_list_type_ndx)
+#define lang1_type_def type_index_to_type (lang1_type_ndx)
+#define lang2_type_def type_index_to_type (lang2_type_ndx)
+#define lang3_type_def type_index_to_type (lang3_type_ndx)
+#define lang4_type_def type_index_to_type (lang4_type_ndx)
+#define lang5_type_def type_index_to_type (lang5_type_ndx)
+
+/* This is not `const', because we allow TREE_TYPE_DEF to be modified
+ by frontends. */
+struct type_definition_s;
+extern struct type_definition_s basic_type_defs[num_type_defs];
+
+typedef unsigned code_type;
+
+/* Functions to fetch codes and sizes. */
+typedef code_type (*code_fetcher_fnp) PARAMS ((const void *));
+typedef size_t (*size_fetcher_fnp) PARAMS ((const void *, type_definition_p));
+typedef void (*prewrite_hook_fnp) PARAMS ((const void *));
+
+/* A description of one pointer field in a type. */
+typedef struct field_definition_s
+{
+ /* This description applies if (CODE & MASK) == COND, where
+ CODE is returned by the type's CODE_FETCHER. */
+ code_type cond, mask;
+ /* The field is OFFSET bytes from the start of the object. */
+ size_t offset;
+ /* The field points to an object of type TYPE. */
+ type_definition_p type;
+} const *field_definition_p;
+
+/* In a list of fields, a field with TYPE == NULL marks the end of the
+ list. */
+#define NO_MORE_FIELDS { 0, 0, 0, 0 }
+
+/* This routine is called with values of N starting with 0.
+ If there is a Nth extra field in object V of type TD, it should
+ set FP to describe that field, and return 1;
+ otherwise, it returns 0.
+
+ It may change *FP even if it does return 0. The COND and MASK
+ fields should not be changed ever. If TYPE is set to NULL,
+ this value of N is skipped.
+*/
+typedef int (*more_fields_fnp) PARAMS ((struct field_definition_s * fp,
+ const void *v, unsigned n, code_type c, type_definition_p td));
+
+/* A description of a subobject. A subobject is an object whose
+ size depends on the object that points to it (the `parent object'). */
+
+typedef struct subobject_definition_s
+{
+ /* This description applies if (CODE & MASK) == COND, where
+ CODE is returned by the type's CODE_FETCHER. */
+ code_type cond, mask;
+
+ /* A pointer to the subobject is OFFSET bytes from the start of the
+ parent object. */
+ size_t offset;
+
+ /* SIZE_FETCHER is called with the parent object and returns the size
+ of the subobject. */
+ size_fetcher_fnp size_fetcher;
+
+ /* The fields in the subobject are returned by FIELDS. */
+ more_fields_fnp fields;
+} const *subobject_definition_p;
+
+/* In a list of subobjects, a subobject with SIZE_FETCHER == NULL marks
+ the end of the list. */
+#define NO_MORE_SUBOBJECTS { 0, 0, 0, 0, 0 }
+
+/* A description of the pointer fields in a type. */
+struct type_definition_s
+{
+ /* Returns the object's CODE, used to determine what fields and subobjects
+ apply to this particular object. */
+ code_fetcher_fnp code_fetcher;
+
+ /* Returns the object's size. */
+ size_fetcher_fnp size_fetcher;
+
+ /* Does any pre-write tweaking of the object. */
+ prewrite_hook_fnp prewrite_hook;
+
+ /* Minimum size of the type.
+ Generally, SIZE_FETCHER should be able to compute the size given
+ only SIZE bytes of the object. */
+ size_t size;
+
+ /* A list of fields in the type. */
+ field_definition_p field_definitions;
+
+ /* A routine to return additional fields. */
+ more_fields_fnp more_fields;
+
+ /* A list of subobjects in the type. */
+ subobject_definition_p subobject_definitions;
+
+ /* >0 if objects of this type are garbage collected;
+ <0 if not, but objects of this type contain gc'd objects;
+ 0 otherwise.
+ There must never be a cycle from a ggc_p<0 object back to itself. */
+
+ int ggc_p;
+};
+
+/* This is how languages handle adding their favourite stuff
+at the end of a tree... */
+extern void add_tree_fields PARAMS ((const struct field_definition_s * fields));
+
+/* Do some operation on V with context CTX. *V has type TD. */
+typedef void (*pointerfn_fnp) PARAMS ((void **v, type_definition_p td, void *ctx));
+
+/* Apply FN with context CTX to every pointer in V. V has type TD. */
+extern void apply_pointer PARAMS ((void *v, type_definition_p td, pointerfn_fnp fn, void *ctx));
+
+/* Do some operation on V with context CTX. *V has type TD.
+Return nonzero if this routine is to be called again on each
+pointer contained in *V. */
+typedef int (*r_pointerfn_fnp) PARAMS ((void **v, type_definition_p td, void *ctx));
+
+/* Do some operation on a subobject V of OBJECT with context CTX.
+OBJECT has type TD, and V is the subobject described by SD. Return
+nonzero if this routine is to be called again on each pointer
+contained in *V. */
+typedef int (*s_pointerfn_fnp) PARAMS ((void *object, type_definition_p td,
+ void **v, subobject_definition_p sd, void *ctx));
+
+/* Apply FN with context CTX to every pointer reachable from V, and
+apply SF to every subobject. V has type TD. SF may be NULL in which
+case it is treated as returning 1 if and only if the pointer to the subobject
+is not NULL. */
+extern void apply_pointer_recursively PARAMS ((void *v, type_definition_p td,
+ r_pointerfn_fnp fn, s_pointerfn_fnp sf, void *ctx));
+
+/* A pointer and its type. */
+typedef struct typed_address_s
+{
+ void *p;
+ type_definition_p td;
+ const char *name;
+} typed_address;
+
+/* The address of an array of pointers and the type pointed to. */
+struct typed_addresses_s
+{
+ void **p;
+ /* If TD is NULL, it means that P is really only a 'void *' and
+ it points to a block of memory of size COUNT that doesn't contain
+ any pointers. */
+ type_definition_p td;
+ size_t count;
+ const char *name;
+};
+
+/* A list of typed addreses. */
+enum { TYPED_ADDRESSES_LIST_CHUNK_SIZE = 22 };
+
+typedef struct typed_addresses_list_s
+{
+ struct typed_addresses_s ta[TYPED_ADDRESSES_LIST_CHUNK_SIZE];
+ struct typed_addresses_list_s *next;
+} typed_addresses_list, *typed_addresses_list_p;
+
+
+/* Add a block of typed addresses to a list. */
+
+extern void add_typed_addresses PARAMS ((typed_addresses_list_p list,
+ void **p, type_definition_p td, size_t count, const char *));
+
+/* Add addresses of various types to a list. */
+extern void add_tree_addresses PARAMS ((typed_addresses_list_p list, union tree_node ** p, size_t count, const char *));
+extern void add_rtx_addresses PARAMS ((typed_addresses_list_p list, struct rtx_def ** p, size_t count, const char *));
+extern void add_varray_tree_addresses PARAMS ((typed_addresses_list_p list,
+ struct varray_head_tag ** p, size_t count, const char *));
+
+/* Remove an address (typed or untyped) from a list. */
+extern void remove_list_address PARAMS ((typed_addresses_list_p list, void *p));
+
+/* Do something to each pointer in a list. */
+extern void apply_list_pointers PARAMS ((typed_addresses_list_p list, pointerfn_fnp fn, void *ctx));
+
+/* Do something to each pointer referenced by a list. */
+extern void apply_list_pointers_recursively PARAMS ((typed_addresses_list_p
+ list, r_pointerfn_fnp fn, s_pointerfn_fnp sf, void *ctx));
+
+/* Do some operation on V with context CTX. *V is of size SZ. */
+typedef void (*untypedfn_fnp) PARAMS ((void *v, size_t sz, void *ctx));
+
+/* Add a block of untyped memory to a list. */
+extern void add_untyped_address PARAMS ((typed_addresses_list_p list, void *p, size_t size, const char *));
+
+/* Do something to each untyped memory block in a list. */
+extern void apply_list_untyped PARAMS ((typed_addresses_list_p list, untypedfn_fnp fn, void *ctx));
+
+/* Count items in a list. */
+extern void count_list_pointers PARAMS ((typed_addresses_list_p list, size_t * typed, size_t * untyped));
+
+enum { CHECKSUM_SIZE = 8 };
+
+/* Update a checksum of the addresses in LIST. If LIST refers to the
+same list of pointers, the checksum shouldn't vary even between
+different runs of the program. Initially, set CHKSUM to contain
+all zeros. */
+
+extern void sum_type_addresses_list PARAMS ((unsigned char chksum[CHECKSUM_SIZE], typed_addresses_list_p list));
+
+/* Write out a list.
+KNOWN is a list of pointers that need not be written. */
+extern int write_type_addresses_list PARAMS ((FILE * f, typed_addresses_list_p known, typed_addresses_list_p list));
+
+/* Restore a list. KNOWN and LIST must point to the same list of pointers
+as was originally written. */
+extern int read_type_addresses_list PARAMS ((FILE * f,
+ typed_addresses_list_p known, typed_addresses_list_p list));
+
+/* Various global variables used by the precompiled header machinery.
+known_pointers are nodes that will always be initialized to the same value,
+so we don't need to save them in the PCH, but we need to know about them
+so that stuff we do save can refer to them.
+data_to_save are just that. */
+
+extern typed_addresses_list data_to_save;
+extern typed_addresses_list known_pointers;
diff --git a/gcc/hash.h b/gcc/hash.h
index bd75f94c6f9..ee2f7def708 100644
--- a/gcc/hash.h
+++ b/gcc/hash.h
@@ -19,6 +19,9 @@ along with this program; if not, write to the Free Software
Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
+#ifndef GCC_HASH_H
+#define GCC_HASH_H
+
#ifndef IN_GCC
#include <ansidecl.h>
#endif /* ! IN_GCC */
@@ -127,3 +130,4 @@ extern bool string_compare PARAMS ((hash_table_key k1,
extern hash_table_key string_copy PARAMS ((struct obstack* memory,
hash_table_key k));
+#endif
diff --git a/gcc/java/class.c b/gcc/java/class.c
index 260db757d71..30ca3c637ad 100644
--- a/gcc/java/class.c
+++ b/gcc/java/class.c
@@ -2158,9 +2158,9 @@ init_class_processing ()
registerClass_libfunc = gen_rtx (SYMBOL_REF, Pmode, "_Jv_RegisterClass");
registerResource_libfunc =
gen_rtx (SYMBOL_REF, Pmode, "_Jv_RegisterResource");
- ggc_add_tree_root (class_roots, sizeof (class_roots) / sizeof (tree));
+ ggc_add_tree_root (class_roots, sizeof (class_roots) / sizeof (tree), "class_roots");
fields_ident = get_identifier ("fields");
info_ident = get_identifier ("info");
- ggc_add_rtx_root (&registerClass_libfunc, 1);
+ ggc_add_rtx_root (&registerClass_libfunc, 1, "registerClass_libfunc");
gcc_obstack_init (&temporary_obstack);
}
diff --git a/gcc/java/constants.c b/gcc/java/constants.c
index c51cec9a7a4..edad37186b5 100644
--- a/gcc/java/constants.c
+++ b/gcc/java/constants.c
@@ -337,7 +337,7 @@ get_tag_node (tag)
/* Register the TAG_NODES with the garbage collector. */
if (!initialized_p)
{
- ggc_add_tree_root (tag_nodes, 13);
+ ggc_add_tree_root (tag_nodes, 13, "tag_nodes");
initialized_p = 1;
}
diff --git a/gcc/java/decl.c b/gcc/java/decl.c
index 86b56104314..ac5c27d2d94 100644
--- a/gcc/java/decl.c
+++ b/gcc/java/decl.c
@@ -882,11 +882,11 @@ init_decl_processing ()
/* Register nodes with the garbage collector. */
ggc_add_tree_root (java_global_trees,
- sizeof (java_global_trees) / sizeof (tree));
+ sizeof (java_global_trees) / sizeof (tree), "java_global_trees");
ggc_add_tree_root (predef_filenames,
- sizeof (predef_filenames) / sizeof (tree));
- ggc_add_tree_root (&decl_map, 1);
- ggc_add_tree_root (&pending_local_decls, 1);
+ sizeof (predef_filenames) / sizeof (tree), "predef_filenames");
+ ggc_add_tree_root (&decl_map, 1, "decl_map");
+ ggc_add_tree_root (&pending_local_decls, 1, "pending_local_decls");
}
diff --git a/gcc/java/expr.c b/gcc/java/expr.c
index 5481289e444..9be6248fc4b 100644
--- a/gcc/java/expr.c
+++ b/gcc/java/expr.c
@@ -144,11 +144,11 @@ init_expr_processing()
operand_type[23] = operand_type[56] = float_type_node;
operand_type[24] = operand_type[57] = double_type_node;
operand_type[25] = operand_type[58] = ptr_type_node;
- ggc_add_tree_root (operand_type, 59);
- ggc_add_tree_root (&methods_ident, 1);
- ggc_add_tree_root (&ncode_ident, 1);
- ggc_add_tree_root (&quick_stack, 1);
- ggc_add_tree_root (&tree_list_free_list, 1);
+ ggc_add_tree_root (operand_type, 59, "operand_type");
+ ggc_add_tree_root (&methods_ident, 1, "methods_ident");
+ ggc_add_tree_root (&ncode_ident, 1, "ncode_ident");
+ ggc_add_tree_root (&quick_stack, 1, "quick_stack");
+ ggc_add_tree_root (&tree_list_free_list, 1, "tree_list_free_list");
}
tree
@@ -1879,7 +1879,7 @@ build_invokeinterface (dtable, method)
if (class_ident == NULL_TREE)
{
class_ident = get_identifier ("class");
- ggc_add_tree_root (&class_ident, 1);
+ ggc_add_tree_root (&class_ident, 1, "class_ident");
}
dtable = build_java_indirect_ref (dtable_type, dtable, flag_check_references);
diff --git a/gcc/java/jcf-parse.c b/gcc/java/jcf-parse.c
index 75e0a23c582..c44547cbf99 100644
--- a/gcc/java/jcf-parse.c
+++ b/gcc/java/jcf-parse.c
@@ -1308,9 +1308,9 @@ void
init_jcf_parse ()
{
/* Register roots with the garbage collector. */
- ggc_add_tree_root (parse_roots, sizeof (parse_roots) / sizeof(tree));
+ ggc_add_tree_root (parse_roots, sizeof (parse_roots) / sizeof(tree), "parse_roots");
- ggc_add_root (&current_jcf, 1, sizeof (JCF), (void (*)(void *))ggc_mark_jcf);
+ ggc_add_root (&current_jcf, 1, sizeof (JCF), (void (*)(void *))ggc_mark_jcf, "current_jcf");
init_src_parse ();
}
diff --git a/gcc/java/jcf-write.c b/gcc/java/jcf-write.c
index 3256625442a..2093d4d6a2b 100644
--- a/gcc/java/jcf-write.c
+++ b/gcc/java/jcf-write.c
@@ -3115,7 +3115,7 @@ generate_classfile (clas, state)
if (SourceFile_node == NULL_TREE)
{
SourceFile_node = get_identifier ("SourceFile");
- ggc_add_tree_root (&SourceFile_node, 1);
+ ggc_add_tree_root (&SourceFile_node, 1, "SourceFile_node");
}
i = find_utf8_constant (&state->cpool, SourceFile_node);
@@ -3146,7 +3146,7 @@ append_synthetic_attribute (state)
if (Synthetic_node == NULL_TREE)
{
Synthetic_node = get_identifier ("Synthetic");
- ggc_add_tree_root (&Synthetic_node, 1);
+ ggc_add_tree_root (&Synthetic_node, 1, "Synthetic_node");
}
i = find_utf8_constant (&state->cpool, Synthetic_node);
PUT2 (i); /* Attribute string index */
@@ -3192,7 +3192,7 @@ append_innerclasses_attribute (state, class)
if (InnerClasses_node == NULL_TREE)
{
InnerClasses_node = get_identifier ("InnerClasses");
- ggc_add_tree_root (&InnerClasses_node, 1);
+ ggc_add_tree_root (&InnerClasses_node, 1, "InnerClasses_node");
}
i = find_utf8_constant (&state->cpool, InnerClasses_node);
PUT2 (i);
diff --git a/gcc/java/lang.c b/gcc/java/lang.c
index 482d89b1cd4..bcb8e1e558d 100644
--- a/gcc/java/lang.c
+++ b/gcc/java/lang.c
@@ -636,8 +636,8 @@ lang_print_error (context, file)
the garbage collector. */
if (!initialized_p)
{
- ggc_add_tree_root (&last_error_function_context, 1);
- ggc_add_tree_root (&last_error_function, 1);
+ ggc_add_tree_root (&last_error_function_context, 1, "last_error_function_contex");
+ ggc_add_tree_root (&last_error_function, 1, "last_error_function");
initialized_p = 1;
}
diff --git a/gcc/java/mangle.c b/gcc/java/mangle.c
index 027eb5d5bab..72fd978a352 100644
--- a/gcc/java/mangle.c
+++ b/gcc/java/mangle.c
@@ -455,7 +455,7 @@ mangle_array_type (p_type)
if (!atms)
{
atms = get_identifier ("6JArray");
- ggc_add_tree_root (&atms, 1);
+ ggc_add_tree_root (&atms, 1, "atms");
}
/* Maybe we have what we're looking in the compression table. */
@@ -609,7 +609,7 @@ compression_table_add (type)
ggc_del_root (&compression_table);
compression_table = new;
- ggc_add_tree_root (&compression_table, 1);
+ ggc_add_tree_root (&compression_table, 1, "compression_table");
}
TREE_VEC_ELT (compression_table, compression_next++) = type;
}
@@ -631,7 +631,7 @@ init_mangling (obstack)
obstack_grow (mangle_obstack, "_Z", 2);
/* Register the compression table with the GC */
- ggc_add_tree_root (&compression_table, 1);
+ ggc_add_tree_root (&compression_table, 1, "compression_table");
}
/* Mangling finalization routine. The mangled name is returned as a
diff --git a/gcc/java/parse.y b/gcc/java/parse.y
index 154fef3f699..8e43060143c 100644
--- a/gcc/java/parse.y
+++ b/gcc/java/parse.y
@@ -610,25 +610,25 @@ goal:
{
/* Register static variables with the garbage
collector. */
- ggc_add_tree_root (&label_id, 1);
- ggc_add_tree_root (&wfl_string_buffer, 1);
- ggc_add_tree_root (&wfl_append, 1);
- ggc_add_tree_root (&wfl_to_string, 1);
- ggc_add_tree_root (&java_lang_id, 1);
- ggc_add_tree_root (&inst_id, 1);
- ggc_add_tree_root (&java_lang_cloneable, 1);
- ggc_add_tree_root (&java_io_serializable, 1);
- ggc_add_tree_root (&current_static_block, 1);
- ggc_add_tree_root (&wpv_id, 1);
- ggc_add_tree_root (&package_list, 1);
- ggc_add_tree_root (&current_this, 1);
- ggc_add_tree_root (&currently_caught_type_list, 1);
+ ggc_add_tree_root (&label_id, 1, "label_id");
+ ggc_add_tree_root (&wfl_string_buffer, 1, "wfl_string_buffer");
+ ggc_add_tree_root (&wfl_append, 1, "wfl_append");
+ ggc_add_tree_root (&wfl_to_string, 1 , "wfl_to_string" );
+ ggc_add_tree_root (&java_lang_id, 1 , "java_lang_id" );
+ ggc_add_tree_root (&inst_id, 1 , "inst_id" );
+ ggc_add_tree_root (&java_lang_cloneable, 1 , "java_lang_cloneable" );
+ ggc_add_tree_root (&java_io_serializable, 1 , "java_io_serializable" );
+ ggc_add_tree_root (&current_static_block, 1 , "current_static_block" );
+ ggc_add_tree_root (&wpv_id, 1 , "wpv_id" );
+ ggc_add_tree_root (&package_list, 1 , "package_list" );
+ ggc_add_tree_root (&current_this, 1 , "current_this" );
+ ggc_add_tree_root (&currently_caught_type_list, 1 , "currently_caught_type_list" );
ggc_add_root (&ctxp, 1,
sizeof (struct parser_ctxt *),
- mark_parser_ctxt);
+ mark_parser_ctxt , "ctxp" );
ggc_add_root (&ctxp_for_generation, 1,
sizeof (struct parser_ctxt *),
- mark_parser_ctxt);
+ mark_parser_ctxt , "ctxp_for_generation" );
}
compilation_unit
{}
@@ -4834,7 +4834,7 @@ verify_constructor_circularity (meth, current)
do so now. */
if (!initialized_p)
{
- ggc_add_tree_root (&list, 1);
+ ggc_add_tree_root (&list, 1, "list");
initialized_p = 1;
}
@@ -6624,7 +6624,7 @@ lookup_cl (decl)
if (cl == NULL_TREE)
{
cl = build_expr_wfl (NULL_TREE, NULL, 0, 0);
- ggc_add_tree_root (&cl, 1);
+ ggc_add_tree_root (&cl, 1, "cl");
}
EXPR_WFL_FILENAME_NODE (cl) = get_identifier (DECL_SOURCE_FILE (decl));
@@ -7494,7 +7494,7 @@ java_reorder_fields ()
/* Register STOP_REORDERING with the garbage collector. */
if (!initialized_p)
{
- ggc_add_tree_root (&stop_reordering, 1);
+ ggc_add_tree_root (&stop_reordering, 1, "stop_reorderimg");
initialized_p = 1;
}
@@ -8592,8 +8592,8 @@ build_current_thisn (type)
/* Register SAVED_THISN and SAVED_TYPE with the garbage collector. */
if (!initialized_p)
{
- ggc_add_tree_root (&saved_thisn, 1);
- ggc_add_tree_root (&saved_type, 1);
+ ggc_add_tree_root (&saved_thisn, 1, "saved_thisn");
+ ggc_add_tree_root (&saved_type, 1, "saved_type");
initialized_p = 1;
}
@@ -8668,8 +8668,8 @@ build_dot_class_method (class)
{
get_message_wfl = build_wfl_node (get_identifier ("getMessage"));
type_parm_wfl = build_wfl_node (get_identifier ("type$"));
- ggc_add_tree_root (&get_message_wfl, 1);
- ggc_add_tree_root (&type_parm_wfl, 1);
+ ggc_add_tree_root (&get_message_wfl, 1, "get_message_wfl");
+ ggc_add_tree_root (&type_parm_wfl, 1, "type_parm_wfl");
}
/* Build the arguments */
@@ -10022,7 +10022,7 @@ class_in_current_package (class)
/* Register CACHE with the garbage collector. */
if (!initialized_p)
{
- ggc_add_tree_root (&cache, 1);
+ ggc_add_tree_root (&cache, 1, "cache");
initialized_p = 1;
}
@@ -11083,8 +11083,8 @@ argument_types_convertible (m1, m2_or_arglist)
collector. */
if (!initialized_p)
{
- ggc_add_tree_root (&m2_arg_value, 1);
- ggc_add_tree_root (&m2_arg_cache, 1);
+ ggc_add_tree_root (&m2_arg_value, 1, "m2_arg_value");
+ ggc_add_tree_root (&m2_arg_cache, 1, "m2_arg_cache");
initialized_p = 1;
}
@@ -16248,7 +16248,7 @@ void
init_src_parse ()
{
/* Register roots with the garbage collector. */
- ggc_add_tree_root (src_parse_roots, sizeof (src_parse_roots) / sizeof(tree));
+ ggc_add_tree_root (src_parse_roots, sizeof (src_parse_roots) / sizeof(tree), "src_parse_roots");
}
diff --git a/gcc/lists.c b/gcc/lists.c
index 2a58ea2e163..4f61264430c 100644
--- a/gcc/lists.c
+++ b/gcc/lists.c
@@ -121,7 +121,7 @@ zap_lists (dummy)
void
init_EXPR_INSN_LIST_cache ()
{
- ggc_add_root (&unused_expr_list, 1, 1, zap_lists);
+ ggc_add_root (&unused_expr_list, 1, 1, zap_lists , "unused_expr_list");
}
/* This function will free up an entire list of EXPR_LIST nodes. */
diff --git a/gcc/mkdeps.c b/gcc/mkdeps.c
index 2c300631271..becaf9d5762 100644
--- a/gcc/mkdeps.c
+++ b/gcc/mkdeps.c
@@ -24,9 +24,10 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "system.h"
#include "mkdeps.h"
+#if 0
/* Keep this structure local to this file, so clients don't find it
easy to start making assumptions. */
-struct deps
+struct make_deps
{
const char **targetv;
unsigned int ntargets; /* number of slots actually occupied */
@@ -36,8 +37,10 @@ struct deps
unsigned int ndeps;
unsigned int deps_size;
};
+#endif
static const char *munge PARAMS ((const char *));
+static const char *base_name PARAMS ((const char *));
/* Given a filename, quote characters in that filename which are
significant to Make. Note that it's not possible to quote all such
@@ -106,12 +109,38 @@ munge (filename)
return buffer;
}
+/* Given a pathname, calculate the non-directory part. This always
+ knows how to handle Unix-style pathnames, and understands VMS and
+ DOS paths on those systems. */
+
+/* Find the base name of a (partial) pathname FNAME.
+ Returns a pointer into the string passed in.
+ Accepts Unix (/-separated) paths on all systems,
+ DOS and VMS paths on those systems. */
+
+static const char *
+base_name (fname)
+ const char *fname;
+{
+ const char *s = fname;
+ const char *p;
+#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
+ if (ISALPHA (s[0]) && s[1] == ':') s += 2;
+ if ((p = strrchr (s, '\\'))) s = p + 1;
+#elif defined VMS
+ if ((p = strrchr (s, ':'))) s = p + 1; /* Skip device. */
+ if ((p = strrchr (s, ']'))) s = p + 1; /* Skip directory. */
+ if ((p = strrchr (s, '>'))) s = p + 1; /* Skip alternate (int'n'l) dir. */
+#endif
+ if ((p = strrchr (s, '/'))) s = p + 1;
+ return s;
+}
/* Public routines. */
-struct deps *
+struct make_deps *
deps_init ()
{
- struct deps *d = (struct deps *) xmalloc (sizeof (struct deps));
+ struct make_deps *d = (struct make_deps *) xmalloc (sizeof (struct make_deps));
/* Allocate space for the vectors only if we need it. */
@@ -128,7 +157,7 @@ deps_init ()
void
deps_free (d)
- struct deps *d;
+ struct make_deps *d;
{
unsigned int i;
@@ -153,7 +182,7 @@ deps_free (d)
string. QUOTE is true if the string should be quoted. */
void
deps_add_target (d, t, quote)
- struct deps *d;
+ struct make_deps *d;
const char *t;
int quote;
{
@@ -177,7 +206,7 @@ deps_add_target (d, t, quote)
is quoted for MAKE. */
void
deps_add_default_target (d, tgt)
- struct deps *d;
+ struct make_deps *d;
const char *tgt;
{
/* Only if we have no targets. */
@@ -207,8 +236,28 @@ deps_add_default_target (d, tgt)
}
void
+deps_calc_target (d, t)
+ struct make_deps *d;
+ const char *t;
+{
+ char *o, *suffix;
+
+ t = base_name (t);
+ o = (char *) alloca (strlen (t) + 8);
+
+ strcpy (o, t);
+ suffix = strrchr (o, '.');
+ if (suffix)
+ strcpy (suffix, TARGET_OBJECT_SUFFIX);
+ else
+ strcat (o, TARGET_OBJECT_SUFFIX);
+
+ deps_add_target (d, o, 0);
+}
+
+void
deps_add_dep (d, t)
- struct deps *d;
+ struct make_deps *d;
const char *t;
{
t = munge (t); /* Also makes permanent copy. */
@@ -224,7 +273,7 @@ deps_add_dep (d, t)
void
deps_write (d, fp, colmax)
- const struct deps *d;
+ const struct make_deps *d;
FILE *fp;
unsigned int colmax;
{
@@ -276,7 +325,7 @@ deps_write (d, fp, colmax)
void
deps_phony_targets (d, fp)
- const struct deps *d;
+ const struct make_deps *d;
FILE *fp;
{
unsigned int i;
diff --git a/gcc/mkdeps.h b/gcc/mkdeps.h
index fa79b86591b..a556403ffab 100644
--- a/gcc/mkdeps.h
+++ b/gcc/mkdeps.h
@@ -26,37 +26,49 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
/* This is the data structure used by all the functions in mkdeps.c.
It's quite straightforward, but should be treated as opaque. */
-struct deps;
+/* Keep this structure local to this file, so clients don't find it
+ easy to start making assumptions. */
+struct make_deps
+{
+ const char **targetv;
+ unsigned int ntargets; /* number of slots actually occupied */
+ unsigned int targets_size; /* amt of allocated space - in words */
+
+ const char **depv;
+ unsigned int ndeps;
+ unsigned int deps_size;
+};
/* Create a deps buffer. */
-extern struct deps *deps_init PARAMS ((void));
+extern struct make_deps *deps_init PARAMS ((void));
/* Destroy a deps buffer. */
-extern void deps_free PARAMS ((struct deps *));
+extern void deps_free PARAMS ((struct make_deps *));
/* Add a target (appears on left side of the colon) to the deps list. Takes
a boolean indicating whether to quote the target for MAKE. */
-extern void deps_add_target PARAMS ((struct deps *, const char *, int));
+extern void deps_add_target PARAMS ((struct make_deps *, const char *, int));
/* Sets the default target if none has been given already. An empty
string as the default target in interpreted as stdin. */
-extern void deps_add_default_target PARAMS ((struct deps *, const char *));
+extern void deps_add_default_target PARAMS ((struct make_deps *, const char *));
/* Add a dependency (appears on the right side of the colon) to the
deps list. Dependencies will be printed in the order that they
were entered with this function. By convention, the first
dependency entered should be the primary source file. */
-extern void deps_add_dep PARAMS ((struct deps *, const char *));
+extern void deps_add_dep PARAMS ((struct make_deps *, const char *));
/* Write out a deps buffer to a specified file. The third argument
is the number of columns to word-wrap at (0 means don't wrap). */
-extern void deps_write PARAMS ((const struct deps *, FILE *,
+extern void deps_write PARAMS ((const struct make_deps *, FILE *,
unsigned int));
/* For each dependency *except the first*, emit a dummy rule for that
file, causing it to depend on nothing. This is used to work around
the intermediate-file deletion misfeature in Make, in some
automatic dependency schemes. */
-extern void deps_phony_targets PARAMS ((const struct deps *, FILE *));
+extern void deps_phony_targets PARAMS ((const struct make_deps *, FILE *));
+extern void deps_calc_target PARAMS ((struct make_deps *, const char *));
#endif /* ! GCC_MKDEPS_H */
diff --git a/gcc/objc/objc-act.c b/gcc/objc/objc-act.c
index 1a2cd91dd27..3491f51b93a 100644
--- a/gcc/objc/objc-act.c
+++ b/gcc/objc/objc-act.c
@@ -3020,7 +3020,7 @@ generate_method_descriptors (protocol) /* generate_dispatch_tables */
if (!objc_method_prototype_template)
{
objc_method_prototype_template = build_method_prototype_template ();
- ggc_add_tree_root (&objc_method_prototype_template, 1);
+ ggc_add_tree_root (&objc_method_prototype_template, 1, "objc_method_prototype_template");
}
cast = build_tree_list (build_tree_list (NULL_TREE, xref_tag (RECORD_TYPE,
@@ -6208,7 +6208,7 @@ start_class (code, class_name, super_name, protocol_list)
tree chain;
if (!implemented_classes)
- ggc_add_tree_root (&implemented_classes, 1);
+ ggc_add_tree_root (&implemented_classes, 1, "implemented_classes");
for (chain = implemented_classes; chain; chain = TREE_CHAIN (chain))
if (TREE_VALUE (chain) == class_name)
{
@@ -7151,7 +7151,7 @@ comp_method_with_proto (method, proto)
if (!function_type)
{
function_type = make_node (FUNCTION_TYPE);
- ggc_add_tree_root (&function_type, 1);
+ ggc_add_tree_root (&function_type, 1, "function_type");
}
/* Install argument types - normally set by build_function_type. */
@@ -7176,7 +7176,7 @@ comp_proto_with_proto (proto0, proto1)
{
function_type[0] = make_node (FUNCTION_TYPE);
function_type[1] = make_node (FUNCTION_TYPE);
- ggc_add_tree_root (function_type, 2);
+ ggc_add_tree_root (function_type, 2, "function_type");
}
/* Install argument types; normally set by build_function_type. */
@@ -8593,11 +8593,11 @@ ggc_mark_hash_table (arg)
static void
objc_act_parse_init ()
{
- ggc_add_tree_root (&objc_ellipsis_node, 1);
- ggc_add_tree_root (objc_global_trees, OCTI_MAX);
- ggc_add_root (&imp_list, 1, sizeof imp_list, ggc_mark_imp_list);
- ggc_add_root (&nst_method_hash_list, 1, sizeof nst_method_hash_list, ggc_mark_hash_table);
- ggc_add_root (&cls_method_hash_list, 1, sizeof cls_method_hash_list, ggc_mark_hash_table);
+ ggc_add_tree_root (&objc_ellipsis_node, 1, "objc_ellipsis_node");
+ ggc_add_tree_root (objc_global_trees, OCTI_MAX, "objc_global_trees");
+ ggc_add_root (&imp_list, 1, sizeof imp_list, ggc_mark_imp_list, "imp_list");
+ ggc_add_root (&nst_method_hash_list, 1, sizeof nst_method_hash_list, ggc_mark_hash_table, "nst_method_hash_list");
+ ggc_add_root (&cls_method_hash_list, 1, sizeof cls_method_hash_list, ggc_mark_hash_table, "cls_method_hash_list");
}
/* Look up ID as an instance variable. */
@@ -8620,3 +8620,9 @@ lookup_objc_ivar (id)
else
return 0;
}
+
+int
+lang_toplevel_p ()
+{
+ return global_bindings_p ();
+}
diff --git a/gcc/optabs.c b/gcc/optabs.c
index 035beac0493..bb436e7e527 100644
--- a/gcc/optabs.c
+++ b/gcc/optabs.c
@@ -2957,9 +2957,13 @@ emit_libcall_block (insns, target, result, equiv)
first = NEXT_INSN (prev);
/* Encapsulate the block so it gets manipulated as a unit. */
- REG_NOTES (first) = gen_rtx_INSN_LIST (REG_LIBCALL, last,
- REG_NOTES (first));
- REG_NOTES (last) = gen_rtx_INSN_LIST (REG_RETVAL, first, REG_NOTES (last));
+ if (!flag_non_call_exceptions || !may_trap_p (equiv))
+ {
+ REG_NOTES (first) = gen_rtx_INSN_LIST (REG_LIBCALL, last,
+ REG_NOTES (first));
+ REG_NOTES (last) = gen_rtx_INSN_LIST (REG_RETVAL, first,
+ REG_NOTES (last));
+ }
}
/* Generate code to store zero in X. */
@@ -5071,8 +5075,8 @@ init_optabs ()
#endif
/* Add these GC roots. */
- ggc_add_root (optab_table, OTI_MAX, sizeof(optab), mark_optab);
- ggc_add_rtx_root (libfunc_table, LTI_MAX);
+ ggc_add_root (optab_table, OTI_MAX, sizeof(optab), mark_optab, "optab_table");
+ ggc_add_rtx_root (libfunc_table, LTI_MAX, "libfunc_table");
}
#ifdef HAVE_conditional_trap
@@ -5088,7 +5092,7 @@ init_traps ()
if (HAVE_conditional_trap)
{
trap_rtx = gen_rtx_fmt_ee (EQ, VOIDmode, NULL_RTX, NULL_RTX);
- ggc_add_rtx_root (&trap_rtx, 1);
+ ggc_add_rtx_root (&trap_rtx, 1, "trap_rtx");
}
}
#endif
diff --git a/gcc/profile.c b/gcc/profile.c
index 44cd15d063e..7c3155aa7f4 100644
--- a/gcc/profile.c
+++ b/gcc/profile.c
@@ -1052,7 +1052,7 @@ init_edge_profiler ()
char buf[20];
ASM_GENERATE_INTERNAL_LABEL (buf, "LPBX", 2);
profiler_label = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf));
- ggc_add_rtx_root (&profiler_label, 1);
+ ggc_add_rtx_root (&profiler_label, 1, "profiler_label");
}
/* Output instructions as RTL to increment the edge execution count. */
diff --git a/gcc/regclass.c b/gcc/regclass.c
index 963fbfed9cb..cfeb9623fdb 100644
--- a/gcc/regclass.c
+++ b/gcc/regclass.c
@@ -614,7 +614,7 @@ init_regs ()
for (i = 0; i < MAX_MACHINE_MODE; i++)
top_of_stack[i] = gen_rtx_MEM (i, stack_pointer_rtx);
- ggc_add_rtx_root (top_of_stack, MAX_MACHINE_MODE);
+ ggc_add_rtx_root (top_of_stack, MAX_MACHINE_MODE, "top_of_stack");
}
#endif
}
diff --git a/gcc/sched-deps.c b/gcc/sched-deps.c
index 0142221c5e6..abb02c439ab 100644
--- a/gcc/sched-deps.c
+++ b/gcc/sched-deps.c
@@ -222,7 +222,12 @@ add_dependence (insn, elem, dep_type)
cond2 = get_condition (elem);
if (cond1 && cond2
&& conditions_mutex_p (cond1, cond2)
- && !modified_in_p (cond1, elem))
+ /* Make sure first instruction doesn't affect condition of second
+ instruction if switched. */
+ && !modified_in_p (cond1, elem)
+ /* Make sure second instruction doesn't affect condition of first
+ instruction if switched. */
+ && !modified_in_p (cond2, insn))
return;
}
diff --git a/gcc/stor-layout.c b/gcc/stor-layout.c
index 3ff8726b1a3..f17151943f3 100644
--- a/gcc/stor-layout.c
+++ b/gcc/stor-layout.c
@@ -1714,8 +1714,15 @@ set_sizetype (type)
TYPE_REFERENCE_TO (sizetype_tab[i]) = 0;
}
+#if 0
ggc_add_tree_root ((tree *) &sizetype_tab,
sizeof sizetype_tab / sizeof (tree));
+#else
+ ggc_add_tree_root (sizetype_tab,
+ sizeof sizetype_tab / sizeof (tree), "sizetype_tab");
+ add_tree_addresses (&data_to_save, sizetype_tab,
+ sizeof sizetype_tab / sizeof (tree), "sizetype_tab");
+#endif
/* Go down each of the types we already made and set the proper type
for the sizes in them. */
@@ -1882,5 +1889,5 @@ get_mode_alignment (mode)
void
init_stor_layout_once ()
{
- ggc_add_tree_root (&pending_sizes, 1);
+ ggc_add_tree_root (&pending_sizes, 1, "pending_sizes");
}
diff --git a/gcc/stringpool.c b/gcc/stringpool.c
index c28156caaee..d99395fa523 100644
--- a/gcc/stringpool.c
+++ b/gcc/stringpool.c
@@ -59,7 +59,8 @@ init_stringpool ()
ident_hash = ht_create (14);
ident_hash->alloc_node = alloc_node;
gcc_obstack_init (&string_stack);
- ggc_add_root (&ident_hash, 1, sizeof ident_hash, mark_ident_hash);
+ ggc_add_root (&ident_hash, 1, sizeof ident_hash, mark_ident_hash, "ident_hash");
+ add_untyped_address (&data_to_save, &ident_hash, sizeof (ident_hash), "ident_hash");
}
/* Allocate a hash node. */
diff --git a/gcc/toplev.c b/gcc/toplev.c
index dc3bf74945c..0979dbf14b3 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -189,6 +189,10 @@ const char *progname;
/* Copy of arguments to toplev_main. */
int save_argc;
char **save_argv;
+
+/* A hook for last-second initialisations. */
+void (*late_init_hook) PARAMS((void));
+
/* Name of current original source file (what was input to cpp).
This comes from each #-command in the actual input. */
@@ -341,9 +345,13 @@ static void close_dump_file PARAMS ((enum dump_file_index,
int rtl_dump_and_exit;
int flag_print_asm_name;
-static int version_flag;
static char *filename;
enum graph_dump_types graph_dump_format;
+
+/* Print compiler version information. -v. */
+
+int version_flag;
+
/* Name for output file of assembly code, specified with -o. */
@@ -1763,6 +1771,21 @@ strip_off_ending (name, len)
}
}
+/* Given a file name X, return the nondirectory portion. */
+
+char *
+file_name_nondirectory (x)
+ const char *x;
+{
+ char *tmp = (char *) strrchr (x, '/');
+ if (DIR_SEPARATOR != '/' && ! tmp)
+ tmp = (char *) strrchr (x, DIR_SEPARATOR);
+ if (tmp)
+ return (char *) (tmp + 1);
+ else
+ return (char *) x;
+}
+
/* Output a quoted string. */
void
@@ -2320,6 +2343,10 @@ compile_file (name)
init_final (main_input_filename);
init_branch_prob (dump_base_name);
+ /* Last call, time to go... */
+ if (late_init_hook)
+ late_init_hook ();
+
timevar_push (TV_PARSE);
/* Call the parser, which parses the entire file
@@ -4673,9 +4700,9 @@ toplev_main (argc, argv)
/* Initialize the garbage-collector. */
init_ggc ();
init_stringpool ();
- ggc_add_rtx_root (&stack_limit_rtx, 1);
- ggc_add_tree_root (&current_function_decl, 1);
- ggc_add_tree_root (&current_function_func_begin_label, 1);
+ ggc_add_rtx_root (&stack_limit_rtx, 1, "stack_limit_rtx");
+ ggc_add_tree_root (&current_function_decl, 1, "current_function_decl");
+ ggc_add_tree_root (&current_function_func_begin_label, 1, "current_function_func_begin_label");
/* Initialize the diagnostics reporting machinery. */
diagnostic_initialize (global_dc);
diff --git a/gcc/toplev.h b/gcc/toplev.h
index 860d49bd9d7..e2ac47b7812 100644
--- a/gcc/toplev.h
+++ b/gcc/toplev.h
@@ -113,6 +113,7 @@ extern int wrapup_global_declarations PARAMS ((union tree_node **, int));
extern void check_global_declarations PARAMS ((union tree_node **, int));
extern const char *progname;
+extern void (*late_init_hook) PARAMS((void));
extern const char *dump_base_name;
/* Language-specific hooks. Can be NULL unless otherwise specified. */
diff --git a/gcc/tradcpp.c b/gcc/tradcpp.c
index 3ceeceffb95..4495e86a722 100644
--- a/gcc/tradcpp.c
+++ b/gcc/tradcpp.c
@@ -42,7 +42,7 @@ size_t max_include_len;
int put_out_comments = 0;
/* mkdeps.h opaque structure that encapsulates dependency information. */
-struct deps *deps;
+struct make_deps *deps;
/* Nonzero means print the names of included files rather than
the preprocessed output. 1 means just the #include "...",
diff --git a/gcc/tree.c b/gcc/tree.c
index 62b07600497..6afcee37d22 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -226,9 +226,12 @@ init_obstacks ()
type_hash_table = htab_create (TYPE_HASH_INITIAL_SIZE, type_hash_hash,
type_hash_eq, 0);
ggc_add_deletable_htab (type_hash_table, type_hash_marked_p,
- type_hash_mark);
- ggc_add_tree_root (global_trees, TI_MAX);
- ggc_add_tree_root (integer_types, itk_none);
+ type_hash_mark, "type_hash_table");
+ ggc_add_tree_root (global_trees, TI_MAX, "global_trees");
+ ggc_add_tree_root (integer_types, itk_none, "integer_types");
+ add_tree_addresses (&data_to_save, global_trees, TI_MAX, "global_trees");
+ add_tree_addresses (&data_to_save, integer_types, itk_none, "integer_types");
+
/* Set lang_set_decl_set_assembler_name to a default value. */
lang_set_decl_assembler_name = set_decl_assembler_name;
@@ -393,7 +396,7 @@ make_node (code)
tree_node_sizes[(int) kind] += length;
#endif
- t = ggc_alloc_tree (length);
+ t = ggc_alloc_tree (length);
memset ((PTR) t, 0, length);
@@ -490,7 +493,7 @@ copy_node (node)
register size_t length;
length = tree_size (node);
- t = ggc_alloc_tree (length);
+ t = ggc_alloc_tree (length);
memcpy (t, node, length);
TREE_CHAIN (t) = 0;
@@ -716,7 +719,7 @@ build_string (len, str)
register tree s = make_node (STRING_CST);
TREE_STRING_LENGTH (s) = len;
- TREE_STRING_POINTER (s) = ggc_alloc_string (str, len);
+ TREE_STRING_POINTER (s) = ggc_alloc_string (str, len);
return s;
}
@@ -756,7 +759,7 @@ make_tree_vec (len)
tree_node_sizes[(int)vec_kind] += length;
#endif
- t = ggc_alloc_tree (length);
+ t = ggc_alloc_tree (length);
memset ((PTR) t, 0, length);
TREE_SET_CODE (t, TREE_VEC);
@@ -1281,7 +1284,8 @@ tree_cons (purpose, value, chain)
{
register tree node;
- node = ggc_alloc_tree (sizeof (struct tree_list));
+ node = ggc_alloc_tree (sizeof (struct tree_list));
+
memset (node, 0, sizeof (struct tree_common));
@@ -2454,7 +2458,7 @@ build1 (code, type, node)
length = sizeof (struct tree_exp);
- t = ggc_alloc_tree (length);
+ t = ggc_alloc_tree (length);
memset ((PTR) t, 0, sizeof (struct tree_common));
diff --git a/gcc/tree.h b/gcc/tree.h
index d4306a88eda..efa0b83c684 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -2140,7 +2140,11 @@ enum attribute_flags
ATTR_FLAG_ARRAY_NEXT = 4,
/* The type passed in is a structure, union or enumeration type being
created, and should be modified in place. */
- ATTR_FLAG_TYPE_IN_PLACE = 8
+ ATTR_FLAG_TYPE_IN_PLACE = 8,
+ /* The attributes are being applied by default to a library function whose
+ name indicates known behavior, and should be silently ignored if they
+ are not in fact compatible with the function type. */
+ ATTR_FLAG_BUILT_IN = 16
};
/* Default versions of target-overridable functions. */
@@ -2920,6 +2924,13 @@ extern int setjmp_call_p PARAMS ((tree));
a decl attribute to the declaration rather than to its type). */
extern tree decl_attributes PARAMS ((tree *, tree, int));
+/* The following function must be provided by front ends
+ using attribs.c. */
+
+/* Possibly apply default attributes to a function (represented by
+ a FUNCTION_DECL). */
+extern void insert_default_attributes PARAMS ((tree));
+
/* Table of machine-independent attributes for checking formats, if used. */
extern const struct attribute_spec *format_attribute_table;
diff --git a/gcc/unwind-sjlj.c b/gcc/unwind-sjlj.c
index 46f30ae1d8f..ff39ca4385f 100644
--- a/gcc/unwind-sjlj.c
+++ b/gcc/unwind-sjlj.c
@@ -202,20 +202,20 @@ _Unwind_GetLanguageSpecificData (struct _Unwind_Context *context)
}
_Unwind_Ptr
-_Unwind_GetRegionStart (struct _Unwind_Context *context)
+_Unwind_GetRegionStart (struct _Unwind_Context *context __attribute__((unused)) )
{
return 0;
}
#ifndef __ia64__
_Unwind_Ptr
-_Unwind_GetDataRelBase (struct _Unwind_Context *context)
+_Unwind_GetDataRelBase (struct _Unwind_Context *context __attribute__((unused)) )
{
return 0;
}
_Unwind_Ptr
-_Unwind_GetTextRelBase (struct _Unwind_Context *context)
+_Unwind_GetTextRelBase (struct _Unwind_Context *context __attribute__((unused)) )
{
return 0;
}
diff --git a/gcc/varasm.c b/gcc/varasm.c
index b2ce9a6de8f..60c06aca001 100644
--- a/gcc/varasm.c
+++ b/gcc/varasm.c
@@ -5126,9 +5126,15 @@ init_varasm_once ()
in_named_entry_eq, NULL);
ggc_add_root (const_hash_table, MAX_HASH_TABLE, sizeof const_hash_table[0],
- mark_const_hash_entry);
+ mark_const_hash_entry, "const_hash_table");
ggc_add_root (&const_str_htab, 1, sizeof const_str_htab,
- mark_const_str_htab);
+ mark_const_str_htab, "const_str_htab");
+ add_untyped_address (&data_to_save, &const_labelno, sizeof (const_labelno), "const_labelno");
+ add_untyped_address (&data_to_save, &var_labelno, sizeof (var_labelno), "var_labelno");
+ add_untyped_address (&data_to_save, &in_section, sizeof (in_section), "in_section");
+ add_typed_addresses (&data_to_save, (void **)&in_named_name,
+ string_type_def, 1, "in_named_name");
+
}
/* Select a set of attributes for section NAME based on the properties
diff --git a/gcc/version.c b/gcc/version.c
index 183734acd01..8f04789f127 100644
--- a/gcc/version.c
+++ b/gcc/version.c
@@ -1,4 +1,4 @@
#include "ansidecl.h"
#include "version.h"
-const char *const version_string = "3.1 20011001 (experimental)";
+const char *const version_string = "3.1 20011002 (experimental)";