intermodule optimisation patch

Geoffrey Keating gkeating@apple.com
Mon May 19 19:44:00 GMT 2003


The attached patch allows GCC to perform optimisations between
modules.  It works by allowing GCC to compile more than one file in
one invocation of the backend, and by setting up appropriate links
between the trees so that information about one file is available
while generating code for routines from another.

It does work to build GCC's libbackend.a, although you have to switch
off loop optimisations because due to various bugs they take too much
time and memory, and when I try to use aggressive inlining I hit some
other bug involving jump tables.  If you build GCC with -O3 and this
patch, expand_expr (which loop dies on) has 220k instructions, 120k
pseudos, and over 4k loops.

Some limitations of this patch:

- No testsuite
- Works only for C at present
- Doesn't allow you to specify -D and -U and so on differently for different
  files
- Debugging sort-of works, but needs some thought

I'd like to spark some discussion of this patch.  Is it the right way
to go for intermodule optimisation, at least for the moment?  Can
anyone suggest better documentation?  Should I commit it now, or wait,
and what should I wait for?

Mike Stump suggested that instead of adding extra parameters to
comptypes() it might be better to just chase up the DECL_CONTEXT chain
looking for a TRANSLATION_UNIT_DECL.  I couldn't decide which was
better, so I posted this version because that's the one I've tested.

-- 
- Geoffrey Keating <geoffk@apple.com>

===File ~/patches/imi-4.patch===============================
2003-05-19  Geoffrey Keating  <geoffk@apple.com>

	* c-common.h (c_reset_state): New prototype.
	(c_parse_file): New prototype.
	(finish_file): Move prototype from c-tree.h.
	* c-decl.c: Include <hashtab.h>.
	(builtin_decls): New.
	(current_file_decl): New.
	(duplicate_decls): Add extra parameter. Change all callers.  Don't
	output duplicate common symbols.
	(link_hash_hash): New.
	(link_hash_eq): New.
	(poplevel): Handle popping of the top level.
	(warn_if_shadowing): Handle TRANSLATION_UNIT_DECL.
	(pushdecl): Set DECL_CONTEXT to TRANSLATION_UNIT_DECL if appropriate.
	(pushdecl_top_level): Likewise.
	(redeclaration_error_message): Handle TRANSLATION_UNIT_DECL.
	(c_init_decl_processing): Create TRANSLATION_UNIT_DECL.
	(finish_decl): Handle TRANSLATION_UNIT_DECL.
	(merge_translation_unit_decls): New.
	(c_write_global_declarations): New.
	(c_reset_state): New.
	* c-lang.c (LANG_HOOKS_WRITE_GLOBALS): New.
	* c-objc-common.c (c_cannot_inline_tree_fn): Handle
	TRANSLATION_UNIT_DECL.
	(c_objc_common_finish_file): Call merge_translation_unit_decls.
	* c-opts.c (in_fnames): Rename from in_fname.
	(c_common_decode_option): Handle multiple input filenames.
	(c_common_post_options): Likewise.
	(c_common_parse_file): Likewise; also, call c_parse_file rather than
	yyparse.
	* c-parse.in: Move cleanup code to c_parse_file.
	(free_parser_stacks): Move contents to c_parse_file.
	(c_parse_file): New.
	* c-tree.h (union lang_tree_node): Chain along TYPE_NEXT_VARIANT
	for integer types.
	(finish_file): Move prototype to c-common.h.
	(merge_translation_unit_decls): New prototype.
	(comptypes): Add extra parameter to prototype.
	(c_write_global_declarations): New prototype.
	* c-typeck.c (tagged_types_tu_compatible_p): New.
	(function_types_compatible_p): Add extra parameter, change all callers.
	(type_lists_compatible_p): Likewise.
	(comptypes): Likewise.
	(struct tagged_tu_seen): New.
	(tagged_tu_seen_base): New.
	(build_unary_op): Handle TRANSLATION_UNIT_DECL.
	(c_mark_addressable): Remove #if 0 code.
	* calls.c (special_function_p): Handle TRANSLATION_UNIT_DECL, add
	comment explaining why it shouldn't have to.
	* cppinit.c (cpp_read_next_file): New.
	(cpp_read_main_file): Use it.
	* cpplib.c (undefine_macros): New.
	(cpp_undef_all): New.
	* cpplib.h (cpp_read_next_file): Prototype.
	(cpp_undef_all): Prototype.
	* langhooks-def.h (write_global_declarations): Remove prototype.
	* toplev.h (write_global_declarations): Add prototype.
	* tree.c (decl_type_context): Use switch statement, handle
	TRANSLATION_UNIT_DECL.
	* tree.def: Update documentation for TRANSLATION_UNIT_DECL.
	(TRANSLATION_UNIT_DECL): New kind of tree.
	* tree.h: Update documentation for TRANSLATION_UNIT_DECL.
	* Makefile.in (c-decl.o): Add $(HASHTAB_H) to dependencies.
	* doc/invoke.texi: Make attempt to document new functionality.

	2003-05-19  Per Bothner <bothner@apple.com>

	* gcc.c (combine_inputs): New.
	(process_command): Set combine_inputs.
	(do_spec_1): Handle combine_inputs.
	(main): Likewise.

Index: gcc/gcc/cp/ChangeLog
2003-05-19  Geoffrey Keating  <geoffk@apple.com>

	* cp-lang.c (c_reset_state): New dummy routine.
	* cp-tree.h (finish_file): Move prototype to c-common.h.
	* parser.c (c_parse_file): Rename from yyparse; don't call finish_file.

Index: gcc/gcc/Makefile.in
===================================================================
RCS file: /cvs/gcc/gcc/gcc/Makefile.in,v
retrieving revision 1.1048
diff -u -p -u -p -r1.1048 Makefile.in
--- gcc/gcc/Makefile.in	4 May 2003 15:20:23 -0000	1.1048
+++ gcc/gcc/Makefile.in	19 May 2003 19:01:36 -0000
@@ -1261,7 +1261,7 @@ c-incpath.o: c-incpath.c c-incpath.h $(C
 c-decl.o : c-decl.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) $(RTL_H) \
     $(C_TREE_H) $(GGC_H) $(TARGET_H) flags.h function.h output.h $(EXPR_H) \
     debug.h toplev.h intl.h $(TM_P_H) tree-inline.h $(TIMEVAR_H) c-pragma.h \
-    gt-c-decl.h cgraph.h
+    gt-c-decl.h cgraph.h $(HASHTAB_H)
 c-typeck.o : c-typeck.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) $(C_TREE_H) \
     $(TARGET_H) flags.h intl.h output.h $(EXPR_H) $(RTL_H) toplev.h $(TM_P_H)
 c-lang.o : c-lang.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) $(C_TREE_H) \
Index: gcc/gcc/c-common.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-common.h,v
retrieving revision 1.178
diff -u -p -u -p -r1.178 c-common.h
--- gcc/gcc/c-common.h	20 Apr 2003 22:58:28 -0000	1.178
+++ gcc/gcc/c-common.h	19 May 2003 19:01:37 -0000
@@ -969,6 +969,14 @@ extern bool c_promoting_integer_type_p		
 extern int self_promoting_args_p		PARAMS ((tree));
 extern tree strip_array_types                   PARAMS ((tree));
 
+/* This function resets the parsers' state in preparation for parsing
+   a new file.  */
+extern void c_reset_state			PARAMS ((void));
+/* This is the basic parsing function.  */
+extern void c_parse_file			PARAMS ((void));
+/* This is misnamed, it actually performs end-of-compilation processing.  */
+extern void finish_file				PARAMS ((void));
+
 /* These macros provide convenient access to the various _STMT nodes.  */
 
 /* Nonzero if this statement should be considered a full-expression,
Index: gcc/gcc/c-decl.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-decl.c,v
retrieving revision 1.385
diff -u -p -u -p -r1.385 c-decl.c
--- gcc/gcc/c-decl.c	3 May 2003 13:28:31 -0000	1.385
+++ gcc/gcc/c-decl.c	19 May 2003 19:01:37 -0000
@@ -49,6 +49,7 @@ Software Foundation, 59 Temple Place - S
 #include "c-common.h"
 #include "c-pragma.h"
 #include "cgraph.h"
+#include "hashtab.h"
 
 /* In grokdeclarator, distinguish syntactic contexts of declarators.  */
 enum decl_context
@@ -125,6 +126,14 @@ static GTY(()) tree shadowed_labels;
    some other global meaning for that identifier.  */
 static GTY(()) tree truly_local_externals;
 
+/* A list of the builtin file-scope DECLs.  */
+
+static GTY(()) tree builtin_decls;
+
+/* A DECL for the current file-scope context.  */
+
+static GTY(()) tree current_file_decl;
+
 /* Set to 0 at beginning of a function definition, set to 1 if
    a return statement that specifies a return value is seen.  */
 
@@ -263,7 +272,7 @@ tree static_ctors, static_dtors;
 
 static struct binding_level *make_binding_level		PARAMS ((void));
 static void pop_binding_level		PARAMS ((struct binding_level **));
-static int duplicate_decls		PARAMS ((tree, tree, int));
+static int duplicate_decls		PARAMS ((tree, tree, int, int));
 static int redeclaration_error_message	PARAMS ((tree, tree));
 static void implicit_decl_warning       PARAMS ((tree));
 static void storedecls			PARAMS ((tree));
@@ -281,6 +290,8 @@ static void record_external_decl	PARAMS 
 static void warn_if_shadowing		PARAMS ((tree, tree));
 static void clone_underlying_type	PARAMS ((tree));
 static bool flexible_array_type_p	PARAMS ((tree));
+static hashval_t link_hash_hash		PARAMS ((const void *));
+static int link_hash_eq			PARAMS ((const void *, const void *));
 
 /* States indicating how grokdeclarator() should handle declspecs marked
    with __attribute__((deprecated)).  An object declared as
@@ -492,8 +503,12 @@ poplevel (keep, reverse, functionbody)
   /* We used to warn about unused variables in expand_end_bindings,
      i.e. while generating RTL.  But in function-at-a-time mode we may
      choose to never expand a function at all (e.g. auto inlining), so
-     we do this explicitly now.  */
-  warn_about_unused_variables (decls);
+     we do this explicitly now.
+     No warnings when the global scope is popped because the global
+     scope isn't popped for the last translation unit, so the warnings
+     are done in c_write_global_declaration.  */
+  if (current_binding_level != global_binding_level)
+    warn_about_unused_variables (decls);
 
   /* Clear out the name-meanings declared on this level.
      Propagate TREE_ADDRESSABLE from nested functions to their
@@ -502,7 +517,8 @@ poplevel (keep, reverse, functionbody)
     {
       if (DECL_NAME (link) != 0)
 	{
-	  if (DECL_EXTERNAL (link))
+	  if (DECL_EXTERNAL (link) 
+	      && current_binding_level != global_binding_level)
 	    /* External decls stay in the symbol-value slot but are
 	       inaccessible.  */
 	    C_DECL_INVISIBLE (link) = 1;
@@ -637,7 +653,7 @@ poplevel (keep, reverse, functionbody)
   /* Dispose of the block that we just made inside some higher level.  */
   if (functionbody)
     DECL_INITIAL (current_function_decl) = block;
-  else if (block)
+  else if (block && current_binding_level)
     current_binding_level->blocks
       = chainon (current_binding_level->blocks, block);
   /* If we did not make a block for the level just exited,
@@ -645,7 +661,7 @@ poplevel (keep, reverse, functionbody)
      (since they cannot be recorded as subblocks in that level)
      must be carried forward so they will later become subblocks
      of something else.  */
-  else if (subblocks)
+  else if (! block && subblocks)
     current_binding_level->blocks
       = chainon (current_binding_level->blocks, subblocks);
 
@@ -799,11 +815,13 @@ pushtag (name, type)
    and OLDDECL is in an outer binding level and should thus not be changed.  */
 
 static int
-duplicate_decls (newdecl, olddecl, different_binding_level)
+duplicate_decls (newdecl, olddecl, different_binding_level, different_tu)
      tree newdecl, olddecl;
      int different_binding_level;
+     int different_tu;
 {
-  int types_match = comptypes (TREE_TYPE (newdecl), TREE_TYPE (olddecl));
+  int types_match = comptypes (TREE_TYPE (newdecl), TREE_TYPE (olddecl),
+			       different_tu);
   int new_is_definition = (TREE_CODE (newdecl) == FUNCTION_DECL
 			   && DECL_INITIAL (newdecl) != 0);
   tree oldtype = TREE_TYPE (olddecl);
@@ -925,7 +943,7 @@ duplicate_decls (newdecl, olddecl, diffe
 	      trytype = build_type_attribute_variant (trytype,
 						      TYPE_ATTRIBUTES (oldtype));
 
-              types_match = comptypes (newtype, trytype);
+              types_match = comptypes (newtype, trytype, different_tu);
 	      if (types_match)
 		oldtype = trytype;
 	    }
@@ -948,7 +966,7 @@ duplicate_decls (newdecl, olddecl, diffe
 	      trytype = build_type_attribute_variant (trytype,
 						      TYPE_ATTRIBUTES (oldtype));
 
-	      types_match = comptypes (newtype, trytype);
+	      types_match = comptypes (newtype, trytype, different_tu);
 	      if (types_match)
 		oldtype = trytype;
 	    }
@@ -1047,7 +1065,7 @@ duplicate_decls (newdecl, olddecl, diffe
 		 && ! pedantic
 		 /* Return types must still match.  */
 		 && comptypes (TREE_TYPE (oldtype),
-			       TREE_TYPE (newtype))
+			       TREE_TYPE (newtype), different_tu)
 		 && TYPE_ARG_TYPES (newtype) == 0))
     {
       error_with_decl (newdecl, "conflicting types for `%s'");
@@ -1055,7 +1073,7 @@ duplicate_decls (newdecl, olddecl, diffe
 	 involving an empty arglist vs a nonempty one.  */
       if (TREE_CODE (olddecl) == FUNCTION_DECL
 	  && comptypes (TREE_TYPE (oldtype),
-			TREE_TYPE (newtype))
+			TREE_TYPE (newtype), different_tu)
 	  && ((TYPE_ARG_TYPES (oldtype) == 0
 	       && DECL_INITIAL (olddecl) == 0)
 	      ||
@@ -1183,7 +1201,8 @@ duplicate_decls (newdecl, olddecl, diffe
 		}
 	      /* Type for passing arg must be consistent
 		 with that declared for the arg.  */
-	      if (! comptypes (TREE_VALUE (parm), TREE_VALUE (type)))
+	      if (! comptypes (TREE_VALUE (parm), TREE_VALUE (type),
+			       different_tu))
 		{
 		  error_with_decl (newdecl,
 				   "prototype for `%s' follows and argument %d doesn't match",
@@ -1410,7 +1429,7 @@ duplicate_decls (newdecl, olddecl, diffe
     }
   if (DECL_EXTERNAL (newdecl))
     {
-      if (! different_binding_level)
+      if (! different_binding_level || different_tu)
 	{
 	  /* Don't mess with these flags on local externs; they remain
 	     external even if there's a declaration at file scope which
@@ -1421,7 +1440,13 @@ duplicate_decls (newdecl, olddecl, diffe
       /* An extern decl does not override previous storage class.  */
       TREE_PUBLIC (newdecl) = TREE_PUBLIC (olddecl);
       if (! DECL_EXTERNAL (newdecl))
-	DECL_CONTEXT (newdecl) = DECL_CONTEXT (olddecl);
+	{
+	  DECL_CONTEXT (newdecl) = DECL_CONTEXT (olddecl);
+	  /* If we have two non-EXTERNAL file-scope decls that are
+	     the same, only one of them should be written out.  */
+	  if (different_tu)
+	    TREE_ASM_WRITTEN (newdecl) = 1;
+	}
     }
   else
     {
@@ -1594,7 +1619,8 @@ warn_if_shadowing (x, old)
 
   if (TREE_CODE (old) == PARM_DECL)
     shadow_warning (SW_PARAM, name, old);
-  else if (DECL_CONTEXT (old) == 0)
+  else if (DECL_CONTEXT (old) == 0
+	   || TREE_CODE (DECL_CONTEXT (old)) == TRANSLATION_UNIT_DECL)
     shadow_warning (SW_GLOBAL, name, old);
   else
     shadow_warning (SW_LOCAL, name, old);
@@ -1695,12 +1721,13 @@ pushdecl (x)
   /* A local extern declaration for a function doesn't constitute nesting.
      A local auto declaration does, since it's a forward decl
      for a nested function coming later.  */
-  if ((TREE_CODE (x) == FUNCTION_DECL || TREE_CODE (x) == VAR_DECL)
-      && DECL_INITIAL (x) == 0 && DECL_EXTERNAL (x))
-    DECL_CONTEXT (x) = 0;
+  if (current_function_decl == NULL
+      || ((TREE_CODE (x) == FUNCTION_DECL || TREE_CODE (x) == VAR_DECL)
+	  && DECL_INITIAL (x) == 0 && DECL_EXTERNAL (x)))
+    DECL_CONTEXT (x) = current_file_decl;
   else
     DECL_CONTEXT (x) = current_function_decl;
-
+  
   if (name)
     {
       tree old;
@@ -1713,7 +1740,7 @@ pushdecl (x)
 		 IDENTIFIER_POINTER (name));
 
       old = lookup_name_current_level (name);
-      if (old && duplicate_decls (x, old, 0))
+      if (old && duplicate_decls (x, old, 0, false))
 	return old;
       if (DECL_EXTERNAL (x) || scope == global_binding_level)
 	{
@@ -1724,13 +1751,14 @@ pushdecl (x)
 	  tree ext = any_external_decl (name);
 	  if (ext)
 	    {
-	      if (duplicate_decls (x, ext, scope != global_binding_level))
+	      if (duplicate_decls (x, ext, scope != global_binding_level, 
+				   false))
 		x = copy_node (ext);
 	    }
 	  else
 	    record_external_decl (x);
 	}
-	  
+
       if (TREE_CODE (x) == TYPE_DECL)
 	clone_underlying_type (x);
 
@@ -1799,13 +1827,13 @@ pushdecl_top_level (x)
       if (DECL_CONTEXT (old))
 	abort ();
 
-      if (!duplicate_decls (x, old, 0))
+      if (!duplicate_decls (x, old, 0, false))
 	abort ();
 
       return old;
     }
 
-  DECL_CONTEXT (x) = 0;
+  DECL_CONTEXT (x) = current_file_decl;
   IDENTIFIER_SYMBOL_VALUE (name) = x;
   TREE_CHAIN (x) = global_binding_level->names;
   global_binding_level->names = x;
@@ -1951,7 +1979,8 @@ redeclaration_error_message (newdecl, ol
 	return 1;
       return 0;
     }
-  else if (DECL_CONTEXT (newdecl) == NULL_TREE)
+  else if (DECL_CONTEXT (newdecl) == NULL_TREE
+	   || TREE_CODE (DECL_CONTEXT (newdecl)) == TRANSLATION_UNIT_DECL)
     {
       /* Objects declared at top level:  */
       /* If at least one is a reference, it's ok.  */
@@ -2271,6 +2300,9 @@ c_init_decl_processing ()
   pushlevel (0);
   global_binding_level = current_binding_level;
 
+  /* Make the DECL for the toplevel file scope.  */
+  current_file_decl = build_decl (TRANSLATION_UNIT_DECL, NULL, NULL);
+
   build_common_tree_nodes (flag_signed_char);
 
   c_common_nodes_and_builtins ();
@@ -2301,6 +2333,8 @@ c_init_decl_processing ()
 
   make_fname_decl = c_make_fname_decl;
   start_fname_decls ();
+
+  builtin_decls = global_binding_level->names;
 }
 
 /* Create the VAR_DECL for __FUNCTION__ etc. ID is the name to give the
@@ -2900,7 +2934,8 @@ finish_decl (decl, init, asmspec_tree)
       if (flag_objc)
 	objc_check_decl (decl);
 
-      if (!DECL_CONTEXT (decl))
+      if (!DECL_CONTEXT (decl) 
+	  || TREE_CODE (DECL_CONTEXT (decl)) == TRANSLATION_UNIT_DECL)
 	{
 	  if (DECL_INITIAL (decl) == NULL_TREE
 	      || DECL_INITIAL (decl) == error_mark_node)
@@ -5975,7 +6010,8 @@ store_parm_decls ()
 		 declared for the arg.  ISO C says we take the unqualified
 		 type for parameters declared with qualified type.  */
 	      if (! comptypes (TYPE_MAIN_VARIANT (DECL_ARG_TYPE (parm)),
-			       TYPE_MAIN_VARIANT (TREE_VALUE (type))))
+			       TYPE_MAIN_VARIANT (TREE_VALUE (type)),
+			       false))
 		{
 		  if (TYPE_MAIN_VARIANT (TREE_TYPE (parm))
 		      == TYPE_MAIN_VARIANT (TREE_VALUE (type)))
@@ -6773,6 +6809,181 @@ make_pointer_declarator (type_quals_attr
   if (attrs != NULL_TREE)
     itarget = tree_cons (attrs, target, NULL_TREE);
   return build1 (INDIRECT_REF, quals, itarget);
+}
+
+/* Hash and equality functions for link_hash_table: key off
+   DECL_ASSEMBLER_NAME.  */
+
+static hashval_t
+link_hash_hash (x_p)
+     const void *x_p;
+{
+  tree x = (tree)x_p;
+  return (hashval_t) DECL_ASSEMBLER_NAME (x);
+}
+
+static int
+link_hash_eq (x1_p, x2_p)
+     const void *x1_p;
+     const void *x2_p;
+{
+  tree x1 = (tree)x1_p;
+  tree x2 = (tree)x2_p;
+  return DECL_ASSEMBLER_NAME (x1) == DECL_ASSEMBLER_NAME (x2);
+}
+
+/* Propagate information between definitions and uses between multiple
+   translation units in TU_LIST based on linkage rules.  */
+
+void
+merge_translation_unit_decls PARAMS((void))
+{
+  const tree tu_list = current_file_decl;
+  tree tu;
+  tree decl;
+  htab_t link_hash_table;
+  tree block;
+  
+  /* Create the BLOCK that poplevel would have created, but don't
+     actually call poplevel since that's expensive.  */
+  block = make_node (BLOCK);
+  BLOCK_VARS (block) = current_binding_level->names;
+  TREE_USED (block) = 1;
+  DECL_INITIAL (current_file_decl) = block;
+
+  /* If only one translation unit seen, no copying necessary.  */
+  if (TREE_CHAIN (tu_list) == NULL_TREE)
+    return;
+
+  link_hash_table = htab_create (1021, link_hash_hash, link_hash_eq, NULL);
+
+  /* Enter any actual definitions into the hash table.  */
+  for (tu = tu_list; tu; tu = TREE_CHAIN (tu))
+    for (decl = BLOCK_VARS (DECL_INITIAL (tu)); decl; decl = TREE_CHAIN (decl))
+      if (TREE_PUBLIC (decl) && ! DECL_EXTERNAL (decl))
+	{
+	  PTR *slot;
+	  slot = htab_find_slot (link_hash_table, decl, INSERT);
+
+	  /* If we've already got a definition, work out which one is
+	     the real one, put it into the hash table, and make the
+	     other one DECL_EXTERNAL.  This is important to avoid
+	     putting out two definitions of the same symbol in the
+	     assembly output.  */
+	  if (*slot != NULL)
+	    {
+	      tree old_decl = (tree) *slot;
+
+	      /* If this is weak or common or whatever, suppress it
+		 in favour of the other definition.  */
+	      if (DECL_WEAK (decl))
+		DECL_EXTERNAL (decl) = 1;
+	      else if (DECL_WEAK (old_decl) && ! DECL_WEAK (decl))
+		DECL_EXTERNAL (old_decl) = 1;
+	      else if (DECL_COMMON (decl) || DECL_ONE_ONLY (decl))
+		DECL_EXTERNAL (decl) = 1;
+	      else if (DECL_COMMON (old_decl) || DECL_ONE_ONLY (old_decl))
+		DECL_EXTERNAL (old_decl) = 1;
+	      
+	      if (DECL_EXTERNAL (decl))
+		{
+		  DECL_INITIAL (decl) = NULL_TREE;
+		  DECL_COMMON (decl) = 0;
+		  DECL_ONE_ONLY (decl) = 0;
+		  DECL_WEAK (decl) = 0;
+		}
+	      else if (DECL_EXTERNAL (old_decl))
+		{
+		  DECL_INITIAL (old_decl) = NULL_TREE;
+		  DECL_COMMON (old_decl) = 0;
+		  DECL_ONE_ONLY (old_decl) = 0;
+		  DECL_WEAK (old_decl) = 0;
+		  *slot = decl;
+		}
+	      else
+		{
+		  error_with_decl (decl, "redefinition of global `%s'");
+		  error_with_decl (old_decl, "`%s' previously defined here");
+		}
+	    }
+	  else
+	    *slot = decl;
+	}
+
+  /* Now insert the desired information from all the definitions
+     into any plain declarations.  */
+  for (tu = tu_list; tu; tu = TREE_CHAIN (tu))
+    for (decl = BLOCK_VARS (DECL_INITIAL (tu)); decl; decl = TREE_CHAIN (decl))
+      if (TREE_PUBLIC (decl) && DECL_EXTERNAL (decl))
+	{
+	  tree global_decl;
+	  global_decl = (tree) htab_find (link_hash_table, decl);
+	  
+	  if (! global_decl)
+	    continue;
+	  
+	  /* Print any appropriate error messages, and partially merge
+	     the decls.  */
+	  (void) duplicate_decls (decl, global_decl, true, true);
+	}
+
+  htab_delete (link_hash_table);
+}
+
+/* Perform final processing on file-scope data.  */
+
+void
+c_write_global_declarations()
+{
+  tree link;
+  
+  for (link = current_file_decl; link; link = TREE_CHAIN (link))
+    {
+      tree globals = BLOCK_VARS (DECL_INITIAL (link));
+      int len = list_length (globals);
+      tree *vec = (tree *) xmalloc (sizeof (tree) * len);
+      int i;
+      tree decl;
+      
+      /* Process the decls in reverse order--earliest first.
+	 Put them into VEC from back to front, then take out from front.  */
+      
+      for (i = 0, decl = globals; i < len; i++, decl = TREE_CHAIN (decl))
+	vec[len - i - 1] = decl;
+      
+      wrapup_global_declarations (vec, len);
+      
+      check_global_declarations (vec, len);
+      
+      /* Clean up.  */
+      free (vec);
+    }
+}
+
+/* Reset the parser's state in preparation for a new file.  */
+
+void
+c_reset_state ()
+{
+  tree link;
+  tree file_scope_decl;
+  
+  /* Pop the global binding level.  */
+  if (current_binding_level != global_binding_level)
+      current_binding_level = global_binding_level;
+  file_scope_decl = current_file_decl;
+  DECL_INITIAL (file_scope_decl) = poplevel (1, 0, 0);
+  truly_local_externals = NULL_TREE;
+
+  /* Start a new global binding level.  */
+  pushlevel (0);
+  global_binding_level = current_binding_level;
+  current_file_decl = build_decl (TRANSLATION_UNIT_DECL, NULL, NULL);
+  TREE_CHAIN (current_file_decl) = file_scope_decl;
+
+  /* Reintroduce the global declarations.  */
+  for (link = builtin_decls; link; link = TREE_CHAIN (link))
+    pushdecl (copy_node (link));
 }
 
 #include "gt-c-decl.h"
Index: gcc/gcc/c-lang.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-lang.c,v
retrieving revision 1.102
diff -u -p -u -p -r1.102 c-lang.c
--- gcc/gcc/c-lang.c	12 Feb 2003 21:48:57 -0000	1.102
+++ gcc/gcc/c-lang.c	19 May 2003 19:01:37 -0000
@@ -117,6 +117,9 @@ static void c_init_options PARAMS ((void
 #undef LANG_HOOKS_TYPE_PROMOTES_TO
 #define LANG_HOOKS_TYPE_PROMOTES_TO c_type_promotes_to
 
+#undef LANG_HOOKS_WRITE_GLOBALS
+#define LANG_HOOKS_WRITE_GLOBALS c_write_global_declarations
+
 /* ### When changing hooks, consider if ObjC needs changing too!! ### */
 
 /* Each front end provides its own.  */
Index: gcc/gcc/c-objc-common.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-objc-common.c,v
retrieving revision 1.24
diff -u -p -u -p -r1.24 c-objc-common.c
--- gcc/gcc/c-objc-common.c	10 Apr 2003 08:07:10 -0000	1.24
+++ gcc/gcc/c-objc-common.c	19 May 2003 19:01:37 -0000
@@ -189,7 +189,8 @@ c_cannot_inline_tree_fn (fnp)
 	goto cannot_inline;
     }
 
-  if (DECL_CONTEXT (fn))
+  if (DECL_CONTEXT (fn) 
+      && TREE_CODE (DECL_CONTEXT (fn)) != TRANSLATION_UNIT_DECL)
     {
       /* If a nested function has pending sizes, we may have already
          saved them.  */
@@ -365,6 +366,10 @@ c_objc_common_finish_file ()
 {
   if (pch_file)
     c_common_write_pch ();
+
+  /* If multiple translation units were built, copy information between
+     them based on linkage rules.  */
+  merge_translation_unit_decls ();
 
   if (flag_unit_at_a_time)
     {
Index: gcc/gcc/c-opts.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-opts.c,v
retrieving revision 1.42
diff -u -p -u -p -r1.42 c-opts.c
--- gcc/gcc/c-opts.c	3 May 2003 21:44:25 -0000	1.42
+++ gcc/gcc/c-opts.c	19 May 2003 19:01:37 -0000
@@ -50,7 +50,8 @@ static int saved_lineno;
 static cpp_options *cpp_opts;
 
 /* Input filename.  */
-static const char *in_fname;
+static const char **in_fnames;
+static unsigned num_in_fnames;
 
 /* Filename and stream for preprocessed output.  */
 static const char *out_fname;
@@ -616,20 +617,12 @@ c_common_decode_option (argc, argv)
 
   opt = argv[0];
 
-  /* Interpret "-" or a non-switch as a file name.  */
+  /* Interpret "-" or a non-switch as an input file name.  */
   if (opt[0] != '-' || opt[1] == '\0')
     {
-      if (!in_fname)
-	in_fname = opt;
-      else if (!out_fname)
-	out_fname = opt;
-      else
-	{
-	  error ("too many filenames given.  Type %s --help for usage",
-		 progname);
-	  return argc;
-	}
-
+      num_in_fnames++;
+      in_fnames = xrealloc (in_fnames, num_in_fnames * sizeof (in_fnames[0]));
+      in_fnames[num_in_fnames - 1] = opt;
       return 1;
     }
 
@@ -1493,8 +1486,13 @@ c_common_post_options (pfilename)
      const char **pfilename;
 {
   /* Canonicalize the input and output filenames.  */
-  if (in_fname == NULL || !strcmp (in_fname, "-"))
-    in_fname = "";
+  if (in_fnames == NULL)
+    {
+      in_fnames = xmalloc (sizeof (in_fnames[0]));
+      in_fnames[0] = "";
+    }
+  else if (strcmp (in_fnames[0], "-") == 0)
+    in_fnames[0] = "";
 
   if (out_fname == NULL || !strcmp (out_fname, "-"))
     out_fname = "";
@@ -1574,7 +1572,7 @@ c_common_post_options (pfilename)
   cpp_get_callbacks (parse_in)->file_change = cb_file_change;
 
   /* NOTE: we use in_fname here, not the one supplied.  */
-  *pfilename = cpp_read_main_file (parse_in, in_fname);
+  *pfilename = cpp_read_main_file (parse_in, in_fnames[0]);
 
   saved_lineno = input_line;
   input_line = 0;
@@ -1614,25 +1612,46 @@ c_common_init ()
   return true;
 }
 
-/* A thin wrapper around the real parser that initializes the 
-   integrated preprocessor after debug output has been initialized.
-   Also, make sure the start_source_file debug hook gets called for
-   the primary source file.  */
+/* Initialize the integrated preprocessor after debug output has been
+   initialized;  make sure the start_source_file debug hook gets
+   called for each primary source file; loop over each input file.  */
 void
 c_common_parse_file (set_yydebug)
      int set_yydebug ATTRIBUTE_UNUSED;
 {
+  unsigned file_index;
+  
 #if YYDEBUG != 0
   yydebug = set_yydebug;
 #else
   warning ("YYDEBUG not defined");
 #endif
 
-  (*debug_hooks->start_source_file) (input_line, input_filename);
-  finish_options();
-  pch_init();
-  yyparse ();
+  file_index = 0;
+  
+  do
+    {
+      if (file_index > 0)
+	{
+	  /* Reset the state of the parser.  */
+	  c_reset_state();
+
+	  /* Reset cpplib's macros and start a new file.  */
+	  cpp_undef_all (parse_in);
+	  cpp_read_next_file (parse_in, in_fnames[file_index]);
+	}
+
+      (*debug_hooks->start_source_file) (input_line, input_filename);
+      finish_options();
+      if (file_index == 0)
+	pch_init();
+      c_parse_file ();
+
+      file_index++;
+    } while (file_index < num_in_fnames);
+  
   free_parser_stacks ();
+  finish_file ();
 }
 
 /* Common finish hook for the C, ObjC and C++ front ends.  */
Index: gcc/gcc/c-parse.in
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-parse.in,v
retrieving revision 1.157
diff -u -p -u -p -r1.157 c-parse.in
--- gcc/gcc/c-parse.in	1 May 2003 16:13:27 -0000	1.157
+++ gcc/gcc/c-parse.in	19 May 2003 19:01:38 -0000
@@ -359,20 +359,8 @@ c_parse_init ()
 program: /* empty */
 		{ if (pedantic)
 		    pedwarn ("ISO C forbids an empty source file");
-		  finish_file ();
 		}
 	| extdefs
-		{
-		  /* In case there were missing closebraces,
-		     get us back to the global binding level.  */
-		  while (! global_bindings_p ())
-		    poplevel (0, 0, 0);
-		  /* __FUNCTION__ is defined at file scope ("").  This
-		     call may not be necessary as my tests indicate it
-		     still works without it.  */
-		  finish_fname_decls ();
-                  finish_file ();
-		}
 	;
 
 /* the reason for the strange actions in this rule
@@ -729,7 +717,7 @@ primary:
 		  e1 = TYPE_MAIN_VARIANT (groktypename ($3));
 		  e2 = TYPE_MAIN_VARIANT (groktypename ($5));
 
-		  $$ = comptypes (e1, e2)
+		  $$ = comptypes (e1, e2, false)
 		    ? build_int_2 (1, 0) : build_int_2 (0, 0);
 		}
 	| primary '[' expr ']'   %prec '.'
@@ -3904,10 +3892,27 @@ yyprint (file, yychar, yyl)
 void
 free_parser_stacks ()
 {
+}
+
+/* Parse the file.  */
+void
+c_parse_file ()
+{
+  yyparse ();
+  /* In case there were missing closebraces, get us back to the global
+     binding level.  */
+  while (! global_bindings_p ())
+    poplevel (0, 0, 0);
+  /* __FUNCTION__ is defined at file scope ("").  This
+     call may not be necessary as my tests indicate it
+     still works without it.  */
+  finish_fname_decls ();
+
   if (malloced_yyss)
     {
       free (malloced_yyss);
       free (malloced_yyvs);
+      malloced_yyss = 0;
     }
 }
 
Index: gcc/gcc/c-tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-tree.h,v
retrieving revision 1.113
diff -u -p -u -p -r1.113 c-tree.h
--- gcc/gcc/c-tree.h	11 Apr 2003 04:26:49 -0000	1.113
+++ gcc/gcc/c-tree.h	19 May 2003 19:01:38 -0000
@@ -46,7 +46,7 @@ struct lang_identifier GTY(())
 
 union lang_tree_node 
   GTY((desc ("TREE_CODE (&%h.generic) == IDENTIFIER_NODE"),
-       chain_next ("(union lang_tree_node *)TREE_CHAIN (&%h.generic)")))
+       chain_next ("TREE_CODE (&%h.generic) == INTEGER_TYPE ? (union lang_tree_node *)TYPE_NEXT_VARIANT (&%h.generic) : (union lang_tree_node *)TREE_CHAIN (&%h.generic)")))
 {
   union tree_node GTY ((tag ("0"), 
 			desc ("tree_node_structure (&%h)"))) 
@@ -157,7 +157,6 @@ extern tree lookup_interface			PARAMS ((
 extern tree is_class_name			PARAMS ((tree));
 extern tree objc_is_id				PARAMS ((tree));
 extern void objc_check_decl			PARAMS ((tree));
-extern void finish_file				PARAMS ((void));
 extern int objc_comptypes                 	PARAMS ((tree, tree, int));
 extern tree objc_message_selector		PARAMS ((void));
 extern tree lookup_objc_ivar			PARAMS ((tree));
@@ -229,6 +228,7 @@ extern tree c_begin_compound_stmt       
 extern void c_expand_deferred_function          PARAMS ((tree));
 extern void c_expand_decl_stmt                  PARAMS ((tree));
 extern tree make_pointer_declarator		PARAMS ((tree, tree));
+extern void merge_translation_unit_decls	PARAMS ((void));
 
 /* in c-objc-common.c */
 extern int c_disregard_inline_limits		PARAMS ((tree));
@@ -247,7 +247,7 @@ extern bool c_warn_unused_global_decl		P
 #define c_sizeof_nowarn(T)  c_sizeof_or_alignof_type (T, SIZEOF_EXPR, 0)
 /* in c-typeck.c */
 extern tree require_complete_type		PARAMS ((tree));
-extern int comptypes				PARAMS ((tree, tree));
+extern int comptypes				PARAMS ((tree, tree, int));
 extern tree c_size_in_bytes                     PARAMS ((tree));
 extern bool c_mark_addressable			PARAMS ((tree));
 extern void c_incomplete_type_error		PARAMS ((tree, tree));
@@ -308,6 +308,7 @@ extern int system_header_p;
 
 /* In c-decl.c */
 extern void c_finish_incomplete_decl PARAMS ((tree));
+extern void c_write_global_declarations PARAMS ((void));
 
 extern GTY(()) tree static_ctors;
 extern GTY(()) tree static_dtors;
Index: gcc/gcc/c-typeck.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-typeck.c,v
retrieving revision 1.237
diff -u -p -u -p -r1.237 c-typeck.c
--- gcc/gcc/c-typeck.c	5 May 2003 19:21:10 -0000	1.237
+++ gcc/gcc/c-typeck.c	19 May 2003 19:01:39 -0000
@@ -54,8 +54,9 @@ static int undeclared_variable_notice;
 
 static tree qualify_type		PARAMS ((tree, tree));
 static int comp_target_types		PARAMS ((tree, tree, int));
-static int function_types_compatible_p	PARAMS ((tree, tree));
-static int type_lists_compatible_p	PARAMS ((tree, tree));
+static int tagged_types_tu_compatible_p	PARAMS ((tree, tree));
+static int function_types_compatible_p	PARAMS ((tree, tree, int));
+static int type_lists_compatible_p	PARAMS ((tree, tree, int));
 static tree decl_constant_value_for_broken_optimization PARAMS ((tree));
 static tree default_function_array_conversion	PARAMS ((tree));
 static tree lookup_field		PARAMS ((tree, tree));
@@ -420,7 +421,7 @@ common_type (t1, t2)
 		tree memb;
 		for (memb = TYPE_FIELDS (TREE_VALUE (p1));
 		     memb; memb = TREE_CHAIN (memb))
-		  if (comptypes (TREE_TYPE (memb), TREE_VALUE (p2)))
+		  if (comptypes (TREE_TYPE (memb), TREE_VALUE (p2), false))
 		    {
 		      TREE_VALUE (n) = TREE_VALUE (p2);
 		      if (pedantic)
@@ -434,7 +435,7 @@ common_type (t1, t2)
 		tree memb;
 		for (memb = TYPE_FIELDS (TREE_VALUE (p2));
 		     memb; memb = TREE_CHAIN (memb))
-		  if (comptypes (TREE_TYPE (memb), TREE_VALUE (p1)))
+		  if (comptypes (TREE_TYPE (memb), TREE_VALUE (p1), false))
 		    {
 		      TREE_VALUE (n) = TREE_VALUE (p1);
 		      if (pedantic)
@@ -463,8 +464,9 @@ common_type (t1, t2)
    but a warning may be needed if you use them together.  */
 
 int
-comptypes (type1, type2)
+comptypes (type1, type2, different_tu)
      tree type1, type2;
+     int different_tu;
 {
   tree t1 = type1;
   tree t2 = type2;
@@ -524,11 +526,11 @@ comptypes (type1, type2)
     {
     case POINTER_TYPE:
       val = (TREE_TYPE (t1) == TREE_TYPE (t2)
-	      ? 1 : comptypes (TREE_TYPE (t1), TREE_TYPE (t2)));
+	      ? 1 : comptypes (TREE_TYPE (t1), TREE_TYPE (t2), different_tu));
       break;
 
     case FUNCTION_TYPE:
-      val = function_types_compatible_p (t1, t2);
+      val = function_types_compatible_p (t1, t2, different_tu);
       break;
 
     case ARRAY_TYPE:
@@ -541,7 +543,8 @@ comptypes (type1, type2)
 
 	/* Target types must match incl. qualifiers.  */
 	if (TREE_TYPE (t1) != TREE_TYPE (t2)
-	    && 0 == (val = comptypes (TREE_TYPE (t1), TREE_TYPE (t2))))
+	    && 0 == (val = comptypes (TREE_TYPE (t1), TREE_TYPE (t2),
+				      different_tu)))
 	  return 0;
 
 	/* Sizes must match unless one is missing or variable.  */
@@ -573,6 +576,11 @@ comptypes (type1, type2)
     case RECORD_TYPE:
       if (flag_objc && objc_comptypes (t1, t2, 0) == 1)
 	val = 1;
+
+    case ENUMERAL_TYPE:
+    case UNION_TYPE:
+      if (val != 1 && different_tu)
+	val = tagged_types_tu_compatible_p (t1, t2);
       break;
 
     case VECTOR_TYPE:
@@ -606,7 +614,7 @@ comp_target_types (ttl, ttr, reflexive)
     return val;
 
   val = comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (ttl)),
-		   TYPE_MAIN_VARIANT (TREE_TYPE (ttr)));
+		   TYPE_MAIN_VARIANT (TREE_TYPE (ttr)), false);
 
   if (val == 2 && pedantic)
     pedwarn ("types are not quite compatible");
@@ -615,6 +623,156 @@ comp_target_types (ttl, ttr, reflexive)
 
 /* Subroutines of `comptypes'.  */
 
+/* The C standard says that two structures in different translation
+   units are compatible with each other only if the types of their
+   fields are compatible (among other things).  So, consider two copies
+   of this structure:  */
+
+struct tagged_tu_seen {
+  const struct tagged_tu_seen * next;
+  tree t1;
+  tree t2;
+};
+
+/* Can they be compatible with each other?  We choose to break the
+   recursion by allowing those types to be compatible.  */
+
+static const struct tagged_tu_seen * tagged_tu_seen_base;
+
+/* Return 1 if two 'struct', 'union', or 'enum' types T1 and T2 are
+   compatible.  If the two types are not the same (which has been
+   checked earlier), this can only happen when multiple translation
+   units are being compiled.  See C99 6.2.7 paragraph 1 for the exact
+   rules.  */
+
+static int
+tagged_types_tu_compatible_p (t1, t2)
+     tree t1, t2;
+{
+  tree s1, s2;
+  bool needs_warning = false;
+  
+  /* We have to verify that the tags of the types are the same.  This
+     is harder than it looks because this may be a typedef, so we have
+     to go look at the original type.  It may even be a typedef of a
+     typedef... */
+  while (TYPE_NAME (t1) && TREE_CODE (TYPE_NAME (t1)) == TYPE_DECL)
+    t1 = DECL_ORIGINAL_TYPE (TYPE_NAME (t1));
+
+  while (TYPE_NAME (t2) && TREE_CODE (TYPE_NAME (t2)) == TYPE_DECL)
+    t2 = DECL_ORIGINAL_TYPE (TYPE_NAME (t2));
+
+  if (TYPE_NAME (t1) != TYPE_NAME (t2))
+    return 0;
+  
+  if (TYPE_SIZE (t1) == NULL
+      || TYPE_SIZE (t2) == NULL)
+    return 1;
+  
+  {
+    const struct tagged_tu_seen * tts_i;
+    for (tts_i = tagged_tu_seen_base; tts_i != NULL; tts_i = tts_i->next)
+      if (tts_i->t1 == t1 && tts_i->t2 == t2)
+	return 1;
+  }
+  
+  switch (TREE_CODE (t1))
+    {
+    case ENUMERAL_TYPE:
+      {
+	if (list_length (TYPE_VALUES (t1)) != list_length (TYPE_VALUES (t2)))
+	  return 0;
+	
+	for (s1 = TYPE_VALUES (t1); s1; s1 = TREE_CHAIN (s1))
+	  {
+	    s2 = purpose_member (TREE_PURPOSE (s1), TYPE_VALUES (t2));
+	    if (s2 == NULL
+		|| simple_cst_equal (TREE_VALUE (s1), TREE_VALUE (s2)) != 1)
+	      return 0;
+	  }
+	return 1;
+      }
+
+    case UNION_TYPE:
+      {
+	if (list_length (TYPE_FIELDS (t1)) != list_length (TYPE_FIELDS (t2)))
+	  return 0;
+
+	for (s1 = TYPE_FIELDS (t1); s1; s1 = TREE_CHAIN (s1))
+	  {
+	    bool ok = false;
+	    struct tagged_tu_seen tts;
+
+	    tts.next = tagged_tu_seen_base;
+	    tts.t1 = t1;
+	    tts.t2 = t2;
+	    tagged_tu_seen_base = &tts;
+	
+	    if (DECL_NAME (s1) != NULL)
+	      for (s2 = TYPE_VALUES (t2); s2; s2 = TREE_CHAIN (s2))
+		if (DECL_NAME (s1) == DECL_NAME (s2))
+		  {
+		    int result;
+		    result = comptypes (TREE_TYPE (s1), TREE_TYPE (s2), true);
+		    if (result == 0)
+		      break;
+		    if (result == 2)
+		      needs_warning = true;
+		    
+		    if (TREE_CODE (s1) == FIELD_DECL
+			&& simple_cst_equal (DECL_FIELD_BIT_OFFSET (s1),
+					     DECL_FIELD_BIT_OFFSET (s2)) != 1)
+		      break;
+
+		    ok = true;
+		    break;
+		  }
+	    tagged_tu_seen_base = tts.next;
+	    if (! ok)
+	      return 0;
+	  }
+	return needs_warning ? 2 : 1;
+      }
+
+    case RECORD_TYPE:
+      {
+	struct tagged_tu_seen tts;
+	
+	tts.next = tagged_tu_seen_base;
+	tts.t1 = t1;
+	tts.t2 = t2;
+	tagged_tu_seen_base = &tts;
+	  
+	for (s1 = TYPE_FIELDS (t1), s2 = TYPE_FIELDS (t2); 
+	     s1 && s2;
+	     s1 = TREE_CHAIN (s1), s2 = TREE_CHAIN (s2))
+	  {
+	    int result;
+	    if (TREE_CODE (s1) != TREE_CODE (s2)
+		|| DECL_NAME (s1) != DECL_NAME (s2))
+	      break;
+	    result = comptypes (TREE_TYPE (s1), TREE_TYPE (s2), true);
+	    if (result == 0)
+	      break;
+	    if (result == 2)
+	      needs_warning = true;
+	    
+	    if (TREE_CODE (s1) == FIELD_DECL
+		&& simple_cst_equal (DECL_FIELD_BIT_OFFSET (s1),
+				     DECL_FIELD_BIT_OFFSET (s2)) != 1)
+	      break;
+	  }
+	tagged_tu_seen_base = tts.next;
+	if (s1 && s2)
+	  return 0;
+	return needs_warning ? 2 : 1;
+      }
+
+    default:
+      abort ();
+    }
+}
+
 /* Return 1 if two function types F1 and F2 are compatible.
    If either type specifies no argument types,
    the other must specify a fixed number of self-promoting arg types.
@@ -623,8 +781,9 @@ comp_target_types (ttl, ttr, reflexive)
    Otherwise, the argument types must match.  */
 
 static int
-function_types_compatible_p (f1, f2)
+function_types_compatible_p (f1, f2, different_tu)
      tree f1, f2;
+     int different_tu;
 {
   tree args1, args2;
   /* 1 if no need for warning yet, 2 if warning cause has been seen.  */
@@ -645,7 +804,7 @@ function_types_compatible_p (f1, f2)
   if (TYPE_VOLATILE (ret2))
     ret2 = build_qualified_type (TYPE_MAIN_VARIANT (ret2),
 				 TYPE_QUALS (ret2) & ~TYPE_QUAL_VOLATILE);
-  val = comptypes (ret1, ret2);
+  val = comptypes (ret1, ret2, different_tu);
   if (val == 0)
     return 0;
 
@@ -663,7 +822,8 @@ function_types_compatible_p (f1, f2)
 	 compare that with the other type's arglist.
 	 If they don't match, ask for a warning (but no error).  */
       if (TYPE_ACTUAL_ARG_TYPES (f1)
-	  && 1 != type_lists_compatible_p (args2, TYPE_ACTUAL_ARG_TYPES (f1)))
+	  && 1 != type_lists_compatible_p (args2, TYPE_ACTUAL_ARG_TYPES (f1),
+					   different_tu))
 	val = 2;
       return val;
     }
@@ -672,13 +832,14 @@ function_types_compatible_p (f1, f2)
       if (!self_promoting_args_p (args1))
 	return 0;
       if (TYPE_ACTUAL_ARG_TYPES (f2)
-	  && 1 != type_lists_compatible_p (args1, TYPE_ACTUAL_ARG_TYPES (f2)))
+	  && 1 != type_lists_compatible_p (args1, TYPE_ACTUAL_ARG_TYPES (f2),
+					   different_tu))
 	val = 2;
       return val;
     }
 
   /* Both types have argument lists: compare them and propagate results.  */
-  val1 = type_lists_compatible_p (args1, args2);
+  val1 = type_lists_compatible_p (args1, args2, different_tu);
   return val1 != 1 ? val1 : val;
 }
 
@@ -687,8 +848,9 @@ function_types_compatible_p (f1, f2)
    or 2 for compatible with warning.  */
 
 static int
-type_lists_compatible_p (args1, args2)
+type_lists_compatible_p (args1, args2, different_tu)
      tree args1, args2;
+     int different_tu;
 {
   /* 1 if no need for warning yet, 2 if warning cause has been seen.  */
   int val = 1;
@@ -717,7 +879,8 @@ type_lists_compatible_p (args1, args2)
 	    return 0;
 	}
       else if (! (newval = comptypes (TYPE_MAIN_VARIANT (TREE_VALUE (args1)), 
-				      TYPE_MAIN_VARIANT (TREE_VALUE (args2)))))
+				      TYPE_MAIN_VARIANT (TREE_VALUE (args2)),
+				      different_tu)))
 	{
 	  /* Allow  wait (union {union wait *u; int *i} *)
 	     and  wait (union wait *)  to be compatible.  */
@@ -731,7 +894,8 @@ type_lists_compatible_p (args1, args2)
 	      tree memb;
 	      for (memb = TYPE_FIELDS (TREE_VALUE (args1));
 		   memb; memb = TREE_CHAIN (memb))
-		if (comptypes (TREE_TYPE (memb), TREE_VALUE (args2)))
+		if (comptypes (TREE_TYPE (memb), TREE_VALUE (args2),
+			       different_tu))
 		  break;
 	      if (memb == 0)
 		return 0;
@@ -746,7 +910,8 @@ type_lists_compatible_p (args1, args2)
 	      tree memb;
 	      for (memb = TYPE_FIELDS (TREE_VALUE (args2));
 		   memb; memb = TREE_CHAIN (memb))
-		if (comptypes (TREE_TYPE (memb), TREE_VALUE (args1)))
+		if (comptypes (TREE_TYPE (memb), TREE_VALUE (args1),
+			       different_tu))
 		  break;
 	      if (memb == 0)
 		return 0;
@@ -3101,7 +3266,8 @@ build_unary_op (code, xarg, flag)
 	   file-scope function counts as a constant.  */
 	if (staticp (arg)
 	    && ! (TREE_CODE (arg) == FUNCTION_DECL
-		  && DECL_CONTEXT (arg) != 0))
+		  && DECL_CONTEXT (arg) != 0
+		  && TREE_CODE (DECL_CONTEXT (arg)) != TRANSLATION_UNIT_DECL))
 	  TREE_CONSTANT (addr) = 1;
 	return addr;
       }
@@ -3367,10 +3533,6 @@ c_mark_addressable (exp)
 	/* drops in */
       case FUNCTION_DECL:
 	TREE_ADDRESSABLE (x) = 1;
-#if 0  /* poplevel deals with this now.  */
-	if (DECL_CONTEXT (x) == 0)
-	  TREE_ADDRESSABLE (DECL_ASSEMBLER_NAME (x)) = 1;
-#endif
 
       default:
 	return true;
@@ -3674,7 +3836,7 @@ build_c_cast (type, expr)
 
       for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
 	if (comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (field)),
-		       TYPE_MAIN_VARIANT (TREE_TYPE (value))))
+		       TYPE_MAIN_VARIANT (TREE_TYPE (value)), false))
 	  break;
 
       if (field)
@@ -4074,7 +4236,7 @@ convert_for_assignment (type, rhs, errty
      This code doesn't fully support references, it's just for the
      special case of va_start and va_copy.  */
   if (codel == REFERENCE_TYPE
-      && comptypes (TREE_TYPE (type), TREE_TYPE (rhs)) == 1)
+      && comptypes (TREE_TYPE (type), TREE_TYPE (rhs), false) == 1)
     {
       if (!lvalue_p (rhs))
 	{
@@ -4123,7 +4285,7 @@ convert_for_assignment (type, rhs, errty
 	  tree memb_type = TREE_TYPE (memb_types);
 
 	  if (comptypes (TYPE_MAIN_VARIANT (memb_type),
-			 TYPE_MAIN_VARIANT (rhstype)))
+			 TYPE_MAIN_VARIANT (rhstype), false))
 	    break;
 
 	  if (TREE_CODE (memb_type) != POINTER_TYPE)
@@ -4746,7 +4908,7 @@ digest_init (type, init, require_constan
 	  && ((inside_init && TREE_CODE (inside_init) == STRING_CST)))
 	{
 	  if (comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (inside_init)),
-			 TYPE_MAIN_VARIANT (type)))
+			 TYPE_MAIN_VARIANT (type), false))
 	    return inside_init;
 
 	  if ((TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (inside_init)))
@@ -4788,7 +4950,7 @@ digest_init (type, init, require_constan
      vector constructor is not constant (e.g. {1,2,3,foo()}) then punt
      below and handle as a constructor.  */
   if (code == VECTOR_TYPE
-      && comptypes (TREE_TYPE (inside_init), type)
+      && comptypes (TREE_TYPE (inside_init), type, false)
       && TREE_CONSTANT (inside_init))
     return build_vector (type, CONSTRUCTOR_ELTS (inside_init));
 
@@ -4797,16 +4959,16 @@ digest_init (type, init, require_constan
 
   if (inside_init && TREE_TYPE (inside_init) != 0
       && (comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (inside_init)),
-		     TYPE_MAIN_VARIANT (type))
+		     TYPE_MAIN_VARIANT (type), false)
 	  || (code == ARRAY_TYPE
-	      && comptypes (TREE_TYPE (inside_init), type))
+	      && comptypes (TREE_TYPE (inside_init), type, false))
 	  || (code == VECTOR_TYPE
-	      && comptypes (TREE_TYPE (inside_init), type))
+	      && comptypes (TREE_TYPE (inside_init), type, false))
 	  || (code == POINTER_TYPE
 	      && (TREE_CODE (TREE_TYPE (inside_init)) == ARRAY_TYPE
 		  || TREE_CODE (TREE_TYPE (inside_init)) == FUNCTION_TYPE)
 	      && comptypes (TREE_TYPE (TREE_TYPE (inside_init)),
-			    TREE_TYPE (type)))))
+			    TREE_TYPE (type), false))))
     {
       if (code == POINTER_TYPE)
 	inside_init = default_function_array_conversion (inside_init);
@@ -6250,7 +6412,7 @@ output_init_element (value, type, field,
 	       && TREE_CODE (type) == ARRAY_TYPE
 	       && TREE_CODE (TREE_TYPE (type)) == INTEGER_TYPE)
 	  && !comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (value)),
-			 TYPE_MAIN_VARIANT (type))))
+			 TYPE_MAIN_VARIANT (type), false)))
     value = default_conversion (value);
 
   if (TREE_CODE (value) == COMPOUND_LITERAL_EXPR
Index: gcc/gcc/calls.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/calls.c,v
retrieving revision 1.273
diff -u -p -u -p -r1.273 calls.c
--- gcc/gcc/calls.c	3 May 2003 14:25:20 -0000	1.273
+++ gcc/gcc/calls.c	19 May 2003 19:01:39 -0000
@@ -652,8 +652,14 @@ special_function_p (fndecl, flags)
       && IDENTIFIER_LENGTH (DECL_NAME (fndecl)) <= 17
       /* Exclude functions not at the file scope, or not `extern',
 	 since they are not the magic functions we would otherwise
-	 think they are.  */
-      && DECL_CONTEXT (fndecl) == NULL_TREE && TREE_PUBLIC (fndecl))
+	 think they are.
+         FIXME: this should be handled with attributes, not with this
+         hacky imitation of DECL_ASSEMBLER_NAME.  It's (also) wrong
+         because you can declare fork() inside a function if you
+         wish.  */
+      && (DECL_CONTEXT (fndecl) == NULL_TREE 
+	  || TREE_CODE (DECL_CONTEXT (fndecl)) == TRANSLATION_UNIT_DECL)
+      && TREE_PUBLIC (fndecl))
     {
       const char *name = IDENTIFIER_POINTER (DECL_NAME (fndecl));
       const char *tname = name;
Index: gcc/gcc/cppinit.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cppinit.c,v
retrieving revision 1.277
diff -u -p -u -p -r1.277 cppinit.c
--- gcc/gcc/cppinit.c	4 May 2003 20:03:54 -0000	1.277
+++ gcc/gcc/cppinit.c	19 May 2003 19:01:40 -0000
@@ -425,6 +425,17 @@ cpp_add_dependency_target (pfile, target
   deps_add_target (pfile->deps, target, quote);
 }
 
+/* This sets up for processing input from the file FNAME.  
+   It returns false on error.  */
+bool
+cpp_read_next_file (pfile, fname)
+     cpp_reader *pfile;
+     const char *fname;
+{
+  /* Open the main input file.  */
+  return _cpp_read_file (pfile, fname);
+}
+
 /* This is called after options have been parsed, and partially
    processed.  Setup for processing input from the file named FNAME,
    or stdin if it is the empty string.  Return the original filename
@@ -451,9 +462,8 @@ cpp_read_main_file (pfile, fname)
       deps_add_default_target (pfile->deps, fname);
     }
 
-  /* Open the main input file.  */
   pfile->line = 1;
-  if (!_cpp_read_file (pfile, fname))
+  if (!cpp_read_next_file (pfile, fname))
     return NULL;
 
   /* Set this here so the client can change the option if it wishes,
Index: gcc/gcc/cpplib.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cpplib.c,v
retrieving revision 1.336
diff -u -p -u -p -r1.336 cpplib.c
--- gcc/gcc/cpplib.c	24 Apr 2003 20:03:51 -0000	1.336
+++ gcc/gcc/cpplib.c	19 May 2003 19:01:40 -0000
@@ -115,6 +115,7 @@ static int  strtoul_for_line	PARAMS ((co
 					 unsigned long *));
 static void do_diagnostic	PARAMS ((cpp_reader *, int, int));
 static cpp_hashnode *lex_macro_node	PARAMS ((cpp_reader *));
+static int undefine_macros PARAMS ((cpp_reader *, cpp_hashnode *, void *));
 static void do_include_common	PARAMS ((cpp_reader *, enum include_type));
 static struct pragma_entry *lookup_pragma_entry
   PARAMS ((struct pragma_entry *, const cpp_hashnode *pragma));
@@ -567,6 +568,48 @@ do_undef (pfile)
     }
   check_eol (pfile);
 }
+
+/* Undefine a single macro/assertion/whatever.  */
+
+static int
+undefine_macros (pfile, h, data_p)
+     cpp_reader *pfile;
+     cpp_hashnode *h;
+     void *data_p ATTRIBUTE_UNUSED;
+{
+  switch (h->type)
+    {
+    case NT_VOID:
+      break;
+      
+    case NT_MACRO:
+      if (pfile->cb.undef)
+        (*pfile->cb.undef) (pfile, pfile->directive_line, h);
+
+      if (CPP_OPTION (pfile, warn_unused_macros))
+        _cpp_warn_if_unused_macro (pfile, h, NULL);
+
+      /* and fall through... */
+    case NT_ASSERTION:
+      _cpp_free_definition (h);
+      break;
+
+    default:
+      abort ();
+    }
+  h->flags &= ~NODE_POISONED;
+  return 1;
+}
+
+/* Undefine all macros and assertions.  */
+
+void
+cpp_undef_all (pfile)
+     cpp_reader *pfile;
+{
+  cpp_forall_identifiers (pfile, undefine_macros, NULL);
+}
+
 
 /* Helper routine used by parse_include.  Reinterpret the current line
    as an h-char-sequence (< ... >); we are looking at the first token
Index: gcc/gcc/cpplib.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cpplib.h,v
retrieving revision 1.253
diff -u -p -u -p -r1.253 cpplib.h
--- gcc/gcc/cpplib.h	23 Apr 2003 22:43:58 -0000	1.253
+++ gcc/gcc/cpplib.h	19 May 2003 19:01:40 -0000
@@ -525,6 +525,10 @@ extern void cpp_set_callbacks PARAMS ((c
    too.  If there was an error opening the file, it returns NULL.  */
 extern const char *cpp_read_main_file PARAMS ((cpp_reader *, const char *));
 
+/* This continues processing to a new file.  It will return false if
+   there was an error opening the file.  */
+extern bool cpp_read_next_file PARAMS ((cpp_reader *, const char *));
+
 /* Set up built-ins like __FILE__.  */
 extern void cpp_init_builtins PARAMS ((cpp_reader *));
 
@@ -570,6 +574,9 @@ extern void cpp_define PARAMS ((cpp_read
 extern void cpp_assert PARAMS ((cpp_reader *, const char *));
 extern void cpp_undef  PARAMS ((cpp_reader *, const char *));
 extern void cpp_unassert PARAMS ((cpp_reader *, const char *));
+
+/* Undefine all macros and assertions.  */
+extern void cpp_undef_all PARAMS ((cpp_reader *));
 
 extern cpp_buffer *cpp_push_buffer PARAMS ((cpp_reader *,
 					    const unsigned char *, size_t,
Index: gcc/gcc/gcc.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/gcc.c,v
retrieving revision 1.373
diff -u -p -u -p -r1.373 gcc.c
--- gcc/gcc/gcc.c	3 May 2003 13:28:32 -0000	1.373
+++ gcc/gcc/gcc.c	19 May 2003 19:01:41 -0000
@@ -2903,6 +2903,11 @@ static struct infile *infiles;
 
 int n_infiles;
 
+/* True if multiple input files are being compiled to a single
+   assembly file.  */
+
+static bool combine_inputs;
+
 /* This counts the number of libraries added by lang_specific_driver, so that
    we can tell if there were any user supplied any files or libraries.  */
 
@@ -3737,8 +3742,7 @@ warranty; not even for MERCHANTABILITY o
 	}
     }
 
-  if (have_c && have_o && lang_n_infiles > 1)
-    fatal ("cannot specify -o with -c or -S and multiple compilations");
+  combine_inputs = (have_c && have_o && lang_n_infiles > 1);
 
   if ((save_temps_flag || report_times) && use_pipes)
     {
@@ -4739,8 +4743,16 @@ do_spec_1 (spec, inswitch, soft_matched_
 	    break;
 
 	  case 'i':
-	    obstack_grow (&obstack, input_filename, input_filename_length);
-	    arg_going = 1;
+	    if (combine_inputs)
+	      {
+		for (i = 0; (int) i < n_infiles; i++)
+		  store_arg (infiles[i].name, 0, 0);
+	      }
+	    else
+	      {
+		obstack_grow (&obstack, input_filename, input_filename_length);
+		arg_going = 1;
+	      }
 	    break;
 
 	  case 'I':
@@ -6425,7 +6437,28 @@ main (argc, argv)
 
   explicit_link_files = xcalloc (1, n_infiles);
 
-  for (i = 0; (int) i < n_infiles; i++)
+  if (combine_inputs)
+    {
+       int lang_n_infiles = 0;
+       for (i = 0; (int) i < n_infiles; i++)
+	 {
+	   const char *name = infiles[i].name;
+	   struct compiler *compiler
+	     = lookup_compiler (name, strlen (name), infiles[i].language);
+	   if (compiler == NULL)
+	     error ("%s: linker input file unused because linking not done",
+		    name);
+	   else if (lang_n_infiles > 0 && compiler != input_file_compiler)
+	     fatal ("cannot specify -o with -c or -S and multiple languages");
+	   else
+	     {
+	       lang_n_infiles++;
+	       input_file_compiler = compiler;
+	     }
+	 }
+    }
+  
+  for (i = 0; (int) i < (combine_inputs ? 1 : n_infiles); i++)
     {
       int this_file_error = 0;
 
@@ -6440,9 +6473,10 @@ main (argc, argv)
 
       /* Figure out which compiler from the file's suffix.  */
 
-      input_file_compiler
-	= lookup_compiler (infiles[i].name, input_filename_length,
-			   infiles[i].language);
+      if (! combine_inputs)
+	input_file_compiler
+	  = lookup_compiler (infiles[i].name, input_filename_length,
+			     infiles[i].language);
 
       if (input_file_compiler)
 	{
Index: gcc/gcc/langhooks-def.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/langhooks-def.h,v
retrieving revision 1.47
diff -u -p -u -p -r1.47 langhooks-def.h
--- gcc/gcc/langhooks-def.h	7 Apr 2003 06:03:09 -0000	1.47
+++ gcc/gcc/langhooks-def.h	19 May 2003 19:01:41 -0000
@@ -84,8 +84,6 @@ int lhd_tree_inlining_start_inlining		PA
 void lhd_tree_inlining_end_inlining		PARAMS ((tree));
 tree lhd_tree_inlining_convert_parm_for_inlining PARAMS ((tree, tree, tree));
 
-void write_global_declarations PARAMS ((void));
-
 #define LANG_HOOKS_NAME			"GNU unknown"
 #define LANG_HOOKS_IDENTIFIER_SIZE	sizeof (struct lang_identifier)
 #define LANG_HOOKS_INIT			hook_bool_void_false
Index: gcc/gcc/toplev.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/toplev.h,v
retrieving revision 1.91
diff -u -p -u -p -r1.91 toplev.h
--- gcc/gcc/toplev.h	4 May 2003 15:18:21 -0000	1.91
+++ gcc/gcc/toplev.h	19 May 2003 19:01:42 -0000
@@ -103,6 +103,7 @@ extern void fnotice			PARAMS ((FILE *, c
 
 extern int wrapup_global_declarations   PARAMS ((union tree_node **, int));
 extern void check_global_declarations   PARAMS ((union tree_node **, int));
+extern void write_global_declarations PARAMS ((void));
 
 extern const char *progname;
 extern const char *dump_base_name;
Index: gcc/gcc/tree.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree.c,v
retrieving revision 1.301
diff -u -p -u -p -r1.301 tree.c
--- gcc/gcc/tree.c	1 May 2003 16:13:30 -0000	1.301
+++ gcc/gcc/tree.c	19 May 2003 19:01:42 -0000
@@ -4298,26 +4298,30 @@ decl_type_context (decl)
   tree context = DECL_CONTEXT (decl);
 
   while (context)
-    {
-      if (TREE_CODE (context) == NAMESPACE_DECL)
+    switch (TREE_CODE (context))
+      {
+      case NAMESPACE_DECL:
+      case TRANSLATION_UNIT_DECL:
 	return NULL_TREE;
 
-      if (TREE_CODE (context) == RECORD_TYPE
-	  || TREE_CODE (context) == UNION_TYPE
-	  || TREE_CODE (context) == QUAL_UNION_TYPE)
+      case RECORD_TYPE:
+      case UNION_TYPE:
+      case QUAL_UNION_TYPE:
 	return context;
-
-      if (TREE_CODE (context) == TYPE_DECL
-	  || TREE_CODE (context) == FUNCTION_DECL)
+	
+      case TYPE_DECL:
+      case FUNCTION_DECL:
 	context = DECL_CONTEXT (context);
-
-      else if (TREE_CODE (context) == BLOCK)
+	break;
+	
+      case BLOCK:
 	context = BLOCK_SUPERCONTEXT (context);
-
-      else
-	/* Unhandled CONTEXT!?  */
+	break;
+	
+      default:
 	abort ();
-    }
+      }
+
   return NULL_TREE;
 }
 
Index: gcc/gcc/tree.def
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree.def,v
retrieving revision 1.58
diff -u -p -u -p -r1.58 tree.def
--- gcc/gcc/tree.def	28 Apr 2003 20:02:23 -0000	1.58
+++ gcc/gcc/tree.def	19 May 2003 19:01:43 -0000
@@ -276,17 +276,18 @@ DEFTREECODE (VECTOR_CST, "vector_cst", '
 /* Contents are TREE_STRING_LENGTH and TREE_STRING_POINTER fields. */
 DEFTREECODE (STRING_CST, "string_cst", 'c', 0)
 
-/* Declarations.  All references to names are represented as ..._DECL nodes.
-   The decls in one binding context are chained through the TREE_CHAIN field.
-   Each DECL has a DECL_NAME field which contains an IDENTIFIER_NODE.
-    (Some decls, most often labels, may have zero as the DECL_NAME).
-   DECL_CONTEXT points to the node representing the context in which
-    this declaration has its scope.  For FIELD_DECLs, this is the
-    RECORD_TYPE, UNION_TYPE, or QUAL_UNION_TYPE node that the field
-    is a member of.  For VAR_DECL, PARM_DECL, FUNCTION_DECL, LABEL_DECL,
-    and CONST_DECL nodes, this points to either the FUNCTION_DECL for the
-    containing function, the RECORD_TYPE or UNION_TYPE for the containing
-    type, or NULL_TREE if the given decl has "file scope".
+/* Declarations.  All references to names are represented as ..._DECL
+   nodes.  The decls in one binding context are chained through the
+   TREE_CHAIN field.  Each DECL has a DECL_NAME field which contains
+   an IDENTIFIER_NODE.  (Some decls, most often labels, may have zero
+   as the DECL_NAME).  DECL_CONTEXT points to the node representing
+   the context in which this declaration has its scope.  For
+   FIELD_DECLs, this is the RECORD_TYPE, UNION_TYPE, or
+   QUAL_UNION_TYPE node that the field is a member of.  For VAR_DECL,
+   PARM_DECL, FUNCTION_DECL, LABEL_DECL, and CONST_DECL nodes, this
+   points to either the FUNCTION_DECL for the containing function, the
+   RECORD_TYPE or UNION_TYPE for the containing type, or NULL_TREE or
+   a TRANSLATION_UNIT_DECL if the given decl has "file scope".
    DECL_ABSTRACT_ORIGIN, if non-NULL, points to the original (abstract)
     ..._DECL node of which this decl is an (inlined or template expanded)
     instance.
@@ -297,9 +298,9 @@ DEFTREECODE (STRING_CST, "string_cst", '
     and DECL_MODE fields exist in decl nodes just as in type nodes.
     They are unused in LABEL_DECL, TYPE_DECL and CONST_DECL nodes.
 
-   DECL_OFFSET holds an integer number of bits offset for the location.
-   DECL_VOFFSET holds an expression for a variable offset; it is
-   to be multiplied by DECL_VOFFSET_UNIT (an integer).
+   DECL_FIELD_BIT_OFFSET holds an integer number of bits offset for
+   the location.  DECL_VOFFSET holds an expression for a variable
+   offset; it is to be multiplied by DECL_VOFFSET_UNIT (an integer).
    These fields are relevant only in FIELD_DECLs and PARM_DECLs.
 
    DECL_INITIAL holds the value to initialize a variable to,
@@ -345,6 +346,10 @@ DEFTREECODE (FIELD_DECL, "field_decl", '
 /* A namespace declaration.  Namespaces appear in DECL_CONTEXT of other
    _DECLs, providing a hierarchy of names.  */
 DEFTREECODE (NAMESPACE_DECL, "namespace_decl", 'd', 0)
+
+/* A translation unit.  This is not technically a declaration, since it
+   can't be looked up, but it's close enough.  */
+DEFTREECODE (TRANSLATION_UNIT_DECL, "translation_unit_decl", 'd', 0)
 
 /* References to storage.  */
 
Index: gcc/gcc/tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tree.h,v
retrieving revision 1.400
diff -u -p -u -p -r1.400 tree.h
--- gcc/gcc/tree.h	2 May 2003 11:33:04 -0000	1.400
+++ gcc/gcc/tree.h	19 May 2003 19:01:43 -0000
@@ -1426,12 +1426,13 @@ struct tree_type GTY(())
    the name from decl_attributes to make_function_rtl and make_decl_rtl.  */
 #define DECL_SECTION_NAME(NODE) (DECL_CHECK (NODE)->decl.section_name)
 
-/*  For FIELD_DECLs, this is the
-    RECORD_TYPE, UNION_TYPE, or QUAL_UNION_TYPE node that the field is
-    a member of.  For VAR_DECL, PARM_DECL, FUNCTION_DECL, LABEL_DECL,
-    and CONST_DECL nodes, this points to either the FUNCTION_DECL for the
-    containing function, the RECORD_TYPE or UNION_TYPE for the containing
-    type, or NULL_TREE if the given decl has "file scope".  */
+/*  For FIELD_DECLs, this is the RECORD_TYPE, UNION_TYPE, or
+    QUAL_UNION_TYPE node that the field is a member of.  For VAR_DECL,
+    PARM_DECL, FUNCTION_DECL, LABEL_DECL, and CONST_DECL nodes, this
+    points to either the FUNCTION_DECL for the containing function,
+    the RECORD_TYPE or UNION_TYPE for the containing type, or
+    NULL_TREE or a TRANSLATION_UNIT_DECL if the given decl has "file
+    scope".  */
 #define DECL_CONTEXT(NODE) (DECL_CHECK (NODE)->decl.context)
 #define DECL_FIELD_CONTEXT(NODE) (FIELD_DECL_CHECK (NODE)->decl.context)
 /* In a DECL this is the field where attributes are stored.  */
@@ -1460,6 +1461,7 @@ struct tree_type GTY(())
 /* In PARM_DECL, holds the type as written (perhaps a function or array).  */
 #define DECL_ARG_TYPE_AS_WRITTEN(NODE) (PARM_DECL_CHECK (NODE)->decl.result)
 /* For a FUNCTION_DECL, holds the tree of BINDINGs.
+   For a TRANSLATION_UNIT_DECL, holds the namespace's BLOCK.
    For a VAR_DECL, holds the initial value.
    For a PARM_DECL, not used--default
    values for parameters are encoded in the type of the function,
Index: gcc/gcc/cp/cp-lang.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/cp-lang.c,v
retrieving revision 1.49
diff -u -p -u -p -r1.49 cp-lang.c
--- gcc/gcc/cp/cp-lang.c	7 Apr 2003 06:03:14 -0000	1.49
+++ gcc/gcc/cp/cp-lang.c	19 May 2003 19:01:53 -0000
@@ -356,3 +356,9 @@ cp_var_mod_type_p (tree type)
   return false;
 }
 
+/* Stub routine to tell people that this doesn't work yet.  */
+void
+c_reset_state ()
+{
+  sorry ("inter-module optimisations not implemented yet");
+}
Index: gcc/gcc/cp/cp-tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/cp-tree.h,v
retrieving revision 1.842
diff -u -p -u -p -r1.842 cp-tree.h
--- gcc/gcc/cp/cp-tree.h	1 May 2003 14:39:37 -0000	1.842
+++ gcc/gcc/cp/cp-tree.h	19 May 2003 19:01:54 -0000
@@ -3760,7 +3760,6 @@ extern void import_export_vtable (tree, 
 extern void import_export_decl (tree);
 extern void import_export_tinfo	(tree, tree, bool);
 extern tree build_cleanup			(tree);
-extern void finish_file				(void);
 extern tree build_expr_from_tree		(tree);
 extern tree build_cleanup			(tree);
 extern tree build_expr_from_tree		(tree);
Index: gcc/gcc/cp/parser.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/parser.c,v
retrieving revision 1.59
diff -u -p -u -p -r1.59 parser.c
--- gcc/gcc/cp/parser.c	3 May 2003 11:37:22 -0000	1.59
+++ gcc/gcc/cp/parser.c	19 May 2003 19:01:55 -0000
@@ -14670,10 +14670,10 @@ static GTY (()) cp_parser *the_parser;
 
 /* External interface.  */
 
-/* Parse the entire translation unit.  */
+/* Parse one entire translation unit.  */
 
-int
-yyparse (void)
+void
+c_parse_file (void)
 {
   bool error_occurred;
 
@@ -14681,10 +14681,6 @@ yyparse (void)
   push_deferring_access_checks (false);
   error_occurred = cp_parser_translation_unit (the_parser);
   the_parser = NULL;
-  
-  finish_file ();
-
-  return error_occurred;
 }
 
 /* Clean up after parsing the entire translation unit.  */
Index: gcc/gcc/doc/invoke.texi
===================================================================
RCS file: /cvs/gcc/gcc/gcc/doc/invoke.texi,v
retrieving revision 1.271
diff -u -p -u -p -r1.271 invoke.texi
--- gcc/gcc/doc/invoke.texi	29 Apr 2003 20:45:55 -0000	1.271
+++ gcc/gcc/doc/invoke.texi	19 May 2003 19:01:57 -0000
@@ -705,10 +705,12 @@ in the following sections.
 @section Options Controlling the Kind of Output
 
 Compilation can involve up to four stages: preprocessing, compilation
-proper, assembly and linking, always in that order.  The first three
-stages apply to an individual source file, and end by producing an
-object file; linking combines all the object files (those newly
-compiled, and those specified as input) into an executable file.
+proper, assembly and linking, always in that order.  GCC is capable of
+preprocessing and compiling several files either into several
+assembler input files, or into one assembler input file; then each
+assembler input file produces an object file, and linking combines all
+the object files (those newly compiled, and those specified as input)
+into an executable file.
 
 @cindex file name suffix
 For any given input file, the file name suffix determines what kind of
@@ -880,9 +882,9 @@ Place output in file @var{file}.  This a
 sort of output is being produced, whether it be an executable file,
 an object file, an assembler file or preprocessed C code.
 
-Since only one output file can be specified, it does not make sense to
-use @option{-o} when compiling more than one input file, unless you are
-producing an executable file as output.
+If you specify @option{-o} when compiling more than one input file, or
+you are producing an executable file as output, all the source files
+on the command line will be compiled at once.
 
 If @option{-o} is not specified, the default is to put an executable file
 in @file{a.out}, the object file for @file{@var{source}.@var{suffix}} in
@@ -3431,6 +3433,14 @@ Turning on optimization flags makes the 
 the performance and/or code size at the expense of compilation time
 and possibly the ability to debug the program.
 
+The compiler performs optimisation based on the knowledge it has of
+the program.  Using the @option{-funit-at-a-time} flag will allow the
+compiler to consider information gained from later functions in the
+file when compiling a function.  Compiling multiple files at once to a
+single output file (and using @option{-funit-at-a-time}) will allow
+the compiler to use information gained from all of the files when
+compiling each of them.
+
 Not all optimizations are controlled directly by a flag.  Only
 optimizations that have a flag are listed.
 
@@ -4308,8 +4318,9 @@ better job.
 
 @item -funit-at-a-time
 @opindex funit-at-a-time
-Parse the whole compilation unit before starting to produce code.  This allows some
-extra optimizations to take place but consumes more memory.
+Parse the whole compilation unit before starting to produce code.
+This allows some extra optimizations to take place but consumes more
+memory.
 
 @item -funroll-loops
 @opindex funroll-loops
Index: gcc/gcc/objc/objc-act.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/objc/objc-act.c,v
retrieving revision 1.171
diff -u -p -u -p -r1.171 objc-act.c
--- gcc/gcc/objc/objc-act.c	1 May 2003 16:13:36 -0000	1.171
+++ gcc/gcc/objc/objc-act.c	19 May 2003 19:01:58 -0000
@@ -3574,7 +3574,7 @@ check_ivars (inter, imp)
 
       t1 = TREE_TYPE (intdecls); t2 = TREE_TYPE (impdecls);
 
-      if (!comptypes (t1, t2))
+      if (!comptypes (t1, t2, false))
 	{
 	  if (DECL_NAME (intdecls) == DECL_NAME (impdecls))
 	    {
@@ -4971,7 +4971,7 @@ finish_message_expr (receiver, sel_name,
 	;
       else if (! IS_ID (rtype)
 	       /* Allow any type that matches objc_class_type.  */
-	       && ! comptypes (rtype, objc_class_type))
+	       && ! comptypes (rtype, objc_class_type, false))
 	{
 	  warning ("invalid receiver type `%s'",
 		   gen_declaration (rtype, errbuf));
@@ -7139,7 +7139,8 @@ comp_method_with_proto (method, proto)
   /* install return type */
   TREE_TYPE (function1_template) = groktypename (TREE_TYPE (proto));
 
-  return comptypes (TREE_TYPE (METHOD_DEFINITION (method)), function1_template);
+  return comptypes (TREE_TYPE (METHOD_DEFINITION (method)), function1_template,
+		    false);
 }
 
 /* Return 1 if PROTO1 is consistent with PROTO2.  */
@@ -7162,7 +7163,7 @@ comp_proto_with_proto (proto0, proto1)
   TREE_TYPE (function1_template) = groktypename (TREE_TYPE (proto0));
   TREE_TYPE (function2_template) = groktypename (TREE_TYPE (proto1));
 
-  return comptypes (function1_template, function2_template);
+  return comptypes (function1_template, function2_template, false);
 }
 
 /* - Generate an identifier for the function. the format is "_n_cls",
============================================================



More information about the Gcc-patches mailing list