This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

C++ PATCH: Cleanup linkage handling


This patch makes the C++ front end always work in unit-at-a-time mode.
This has approximately no compile-time impact, in my testing, and
permits some cleanups of the various decisions about whether to emit
definitions, weak definitions, or external references -- all of those
decisions are now put off until the end of the translation unit.

This are still more complicated that they should be, but part of that
is what we get for having all of:

* #pragma interface, #pragma implementation

* -fno-implicit-templates, -fno-implicit-template-inlines

* -frepo

* -fno-rtti

* "extern template" directives

* "inline template" directives

As a side effect of this cleanup, -frepo can now deal with inline
functions, virtual tables, and other similar entities with "vague
linkage" in addition to templates.  There is nothing about templates
that makes them more appropriate for repository storage than other
entities with vague linkage; in all of these cases, using -frepo can
be used to eliminate duplicates.  However, I've not enabled this
functionality because it would be a behavior change in that
command-line option.

This patch also fixes several bugs:

* PCH and -frepo did not play nice together.  init_repo runs when the
  compiler starts, and sets various bits on identifiers -- which
  loading a PCH destroys.

* The testsuite was not correctly handling -frepo compilations, with
  the result that -frepo could be broken without the testsuite
  noticing.

* The IDENTIFIER_REPO_CHOSEN and IDENTIFIER_REPO_USED bits conflicted
  with other bits set on identifier nodes, resulting in spurious
  errors and other confusion when using -frepo.

* Linkage for virtual tables and associate information for local
  classes was being set to external linkage, even when the local class
  was located within a function with internal linkage.

* Using -O1 resulted in different sets of things being defined that
  -O0 for no particularly good reason.

I also added tests for some things that I broke, and then un-broke,
during my testing.  Some of these things were hard to find because we
had no basic tests; for example, I broke "#pragma interface" with
"-O2", which was revealed only by the fact that libgcj did not link;
now we have a straightforward test in the G++ testsuite.

Tested on i686-pc-linux-gnu, applied on the mainline.

--
Mark Mitchell
CodeSourcery, LLC
mark@codesourcery.com

2004-07-29  Mark Mitchell  <mark@codesourcery.com>

	* c-common.h (lang_post_pch_load): New variable.
	* c-pch.c (lang_post_pch_load): Define it.
	(c_common_read_pch): Use it.
	* cgraphunit.c (record_call_1): Give the front end a chance to
	record additional needed entities when a variable is marked as
	needed.
	* tlink.c (recompile_files): Robustify.
	(scan_linker_output): If a symbol is assigned to a file,
	but after recompilation is not present there, issue an error
	message.

2004-07-29  Mark Mitchell  <mark@codesourcery.com>

	* cp-tree.h (IDENTIFIER_REPO_CHOSEN): Define.
	(lang_decl_flags): Narrow the width of "languages".  Add
	repo_available_p.
	(DECL_NEEDED_P): Remove.
	(FOR_EACH_CLONE): New macro.
	(DECL_REPO_AVAILABLE_P): Likewise.
	(DECL_TINFO_P): Likewise.
	(set_linkage_according_to_type): Declare.
	(import_export_vtable): Remove.
	(import_export_tinfo): Likewise.
	(mark_needed): New function.
	(decl_needed_p): Likewise.
	(note_vauge_linkage_fn): Likewise.
	(init_repo): Change prototype.
	(repo_template_used): Remove.
	(repo_template_instantiated): Likewise.
	(repo_emit_p): New function.
	(repo_export_class_p): Likewise.
	(no_linkage_check): Change prototype.
	* class.c (set_linkage_according_to_type): New function.
	(build_vtable): Use it.  Do not call import_export_vtable.  Set
	DECL_IGNORED_P if appropriate.
	* decl.c (duplicate_decls): Preserve DECL_REPO_AVAILABLE_P.
	(make_rtL_for_nonlocal_decls): Check for template instantiations
	explicitly.
	(grokfndecl): Adjust call to no_linkage_check.
	(set_linkage_for_static_data_member): New function.
	(grokvardecl): Use it.  Adjust call to no_linkage_check.
	(grokdeclarator): Use set_linkage_for_static_data_member.
	* decl2.c (note_vague_linkage_fn): New function.
	(note_vague_linkage_var): Likewise.
	(finish_static_data_member_decl): Use it.
	(import_export_vtable): Remove.
	(import_export_class): Use repo_export_class_p.
	(var_finalized_p): Simplify.
	(maybe_emit_vtables): Simplify.
	(mark_needed): New function.
	(decl_needed_p): Likewise.
	(import_export_decl): Add documentation and consistency checks.
	Use repo_emit_p.  Handle virtual tables and RTTI information
	here.
	(import_export_tinfo): Remove.
	(write_out_vars): Call import_export_decl.
	(cxx_callgraph_analyze_expr): Ensure that all vtables are emitted
	whenever one is.
	(finish_file): Use decl_needed_p.  Do not call import_export_decl
	for undefined static data members.  Do not warn about undefined
	inlines when using a repository.
	(mark_used): Use note_vague_linkage_fn.  Always defer template
	instantiations.
	* lex.c (cxx_init): Adjust call to init_repo.  Always set
	flag_unit_at_a-time.
	* method.c (synthesize_method): Remove unncessary
	import_export_decl call.
	(implicitly_declare_fn): Use set_linkage_according_to_type.
	* optimize.c (maybe_clone_body): Use FOR_EACH_CLONE.
	* pt.c (instantiate_class_template): Don't redundantly add classes
	to keyed_classes.  Don't call repo_template_used.
	(tsubst_decl): Set DECL_INTERFACE_KNOWN for instantiations of
	templates with internal linkage.
	(check_instantiated_args): Adjust call to no_linkage_check.
	(instantiate_template): Use FOR_EACH_CLONE.
	(mark_definable): New function.
	(mark_decl_instantiated): Use it.
	(do_decl_instantiation): Adjust tests for explicit instantiation
	after "extern template".
	(instantiate_class_member): Do not use repo_template_instantiated.
	(do_type_instantiation): Simplify.
	(instantiate_decl): Use mark_definable.  Check repo_emit_p.
	Simplify.
	* repo.c (repo_get_id): Remove.
	(original_repo): Remove.
	(IDENTIFIER_REPO_USED): Remove.
	(IDENTIFIER_REPO_CHOSEN): Remove.
	Remove all #if 0'd code.
	(repo_template_used): Remove.
	(repo_template_instantiated): Remove.
	(temporary_obstack_initialized_p): New variable.
	(init_repo): Register with lang_post_pch_load.  Avoid creating
	identifiers unnecessarily.  Don't use original_repo.  Close the
	file here.
	(reopen_repo_file_for_write): Not here.
	(finish_repo): Always write out a new repository file.
	(repo_emit_p): New function.
	(repo_export_class_p): Likewise.
	* rtti.c (get_tinfo_decl): Use set_linkage_according_to_type.
	(involves_incomplete_p): New function.
	(tinfo_base_init): Use it.
	(ptr_initializer): Remove non_public_ptr parameter.
	(ptm_initializer): Likewise.
	(get_pseudo_ti_init): Likewise.
	(unemitted_tinfo_decl_p): Remove.
	(emit_tinfo_decl): Use import_export_decl.
	* semantics.c (expand_body): Move updates of static_ctors and
	static_dtors to ...
	(expand_or_defer_fn): ... here.
	* tree.c (no_linkage_check): Add relaxed_p parameter.
	
2004-07-29  Mark Mitchell  <mark@codesourcery.com>

	* g++.dg/abi/inline1.C: New test.
	* g++.dg/abi/local1-a.cc: Likewise.
	* g++.dg/abi/local1.C: Likewise.
	* g++.dg/abi/mangle11.C: Tweak location of warnings.
	* g++.dg/abi/mangle12.C: Likewise.
	* g++.dg/abi/mangle17.C: Likewise.
	* g++.dg/abi/mangle20-2.C: Likewise.
	* g++.dg/opt/interface1.C: Likewise.
	* g++.dg/opt/interface1.h: Likewise.
	* g++.dg/opt/interface1-a.cc: New test.
	* g++.dg/parse/repo1.C: New test.
	* g++.dg/template/repo1.C: Likewise.
	* g++.dg/warn/Winline-1.C: Likewise.
	* lib/gcc-dg.exp (gcc-dg-test-1): Fix -frepo handling.

Index: c-common.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-common.h,v
retrieving revision 1.252
diff -c -5 -p -r1.252 c-common.h
*** c-common.h	25 Jul 2004 02:50:56 -0000	1.252
--- c-common.h	29 Jul 2004 17:57:40 -0000
*************** extern void (*lang_expand_function_end) 
*** 284,293 ****
--- 284,297 ----
  
  /* Callback that determines if it's ok for a function to have no
     noreturn attribute.  */
  extern int (*lang_missing_noreturn_ok_p) (tree);
  
+ /* If non-NULL, this function is called after a precompile header file
+    is loaded.  */
+ extern void (*lang_post_pch_load) (void);
+ 
  extern void push_file_scope (void);
  extern void pop_file_scope (void);
  extern int yyparse (void);
  extern stmt_tree current_stmt_tree (void);
  extern tree push_stmt_list (void);
Index: c-pch.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/c-pch.c,v
retrieving revision 1.24
diff -c -5 -p -r1.24 c-pch.c
*** c-pch.c	22 Jun 2004 06:51:50 -0000	1.24
--- c-pch.c	29 Jul 2004 17:57:40 -0000
*************** c_common_valid_pch (cpp_reader *pfile, c
*** 382,391 ****
--- 382,395 ----
      return 2;
    else
      return result == 0;
  }
  
+ /* If non-NULL, this function is called after a precompile header file
+    is loaded.  */
+ void (*lang_post_pch_load) (void);
+ 
  /* Load in the PCH file NAME, open on FD.  It was originally searched for
     by ORIG_NAME.  */
  
  void
  c_common_read_pch (cpp_reader *pfile, const char *name,
*************** c_common_read_pch (cpp_reader *pfile, co
*** 441,450 ****
--- 445,459 ----
  
    if (cpp_read_state (pfile, name, f, smd) != 0)
      return;
  
    fclose (f);
+   
+   /* Give the front end a chance to take action after a PCH file has
+      been loadeded.  */
+   if (lang_post_pch_load)
+     (*lang_post_pch_load) ();
  }
  
  /* Indicate that no more PCH files should be read.  */
  
  void
Index: cgraphunit.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cgraphunit.c,v
retrieving revision 1.71
diff -c -5 -p -r1.71 cgraphunit.c
*** cgraphunit.c	25 Jul 2004 14:39:42 -0000	1.71
--- cgraphunit.c	29 Jul 2004 17:57:40 -0000
*************** record_call_1 (tree *tp, int *walk_subtr
*** 398,408 ****
      case VAR_DECL:
        /* ??? Really, we should mark this decl as *potentially* referenced
  	 by this function and re-examine whether the decl is actually used
  	 after rtl has been generated.  */
        if (TREE_STATIC (t))
!         cgraph_varpool_mark_needed_node (cgraph_varpool_node (t));
        break;
  
      case ADDR_EXPR:
        if (flag_unit_at_a_time)
  	{
--- 398,413 ----
      case VAR_DECL:
        /* ??? Really, we should mark this decl as *potentially* referenced
  	 by this function and re-examine whether the decl is actually used
  	 after rtl has been generated.  */
        if (TREE_STATIC (t))
! 	{
! 	  cgraph_varpool_mark_needed_node (cgraph_varpool_node (t));
! 	  if (lang_hooks.callgraph.analyze_expr)
! 	    return lang_hooks.callgraph.analyze_expr (tp, walk_subtrees, 
! 						      data);
! 	}
        break;
  
      case ADDR_EXPR:
        if (flag_unit_at_a_time)
  	{
Index: tlink.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/tlink.c,v
retrieving revision 1.55
diff -c -5 -p -r1.55 tlink.c
*** tlink.c	19 Jul 2003 14:47:14 -0000	1.55
--- tlink.c	29 Jul 2004 17:57:40 -0000
*************** recompile_files (void)
*** 468,477 ****
--- 468,483 ----
        obstack_grow (&temporary_obstack, "cd ", 3);
        obstack_grow (&temporary_obstack, f->dir, strlen (f->dir));
        obstack_grow (&temporary_obstack, "; ", 2);
        obstack_grow (&temporary_obstack, c_file_name, strlen (c_file_name));
        obstack_1grow (&temporary_obstack, ' ');
+       if (!f->args)
+ 	{
+ 	  error ("repository file `%s' does not contain command-line "
+ 		 "arguments", f->key);
+ 	  return 0;
+ 	}
        obstack_grow (&temporary_obstack, f->args, strlen (f->args));
        obstack_1grow (&temporary_obstack, ' ');
        command = obstack_copy0 (&temporary_obstack, f->main, strlen (f->main));
  
        if (tlink_verbose)
*************** scan_linker_output (const char *fname)
*** 643,652 ****
--- 649,661 ----
  	    }
  	}
  
        if (sym && sym->tweaked)
  	{
+ 	  error ("`%s' was assigned to `%s', but was not defined "
+ 		 "during recompilation, or vice versa", 
+ 		 sym->key, sym->file->key);
  	  fclose (stream);
  	  return 0;
  	}
        if (sym && !sym->tweaking)
  	{
Index: cp/class.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/class.c,v
retrieving revision 1.646
diff -c -5 -p -r1.646 class.c
*** cp/class.c	28 Jul 2004 08:50:26 -0000	1.646
--- cp/class.c	29 Jul 2004 17:57:40 -0000
*************** tree
*** 579,588 ****
--- 579,614 ----
  get_vtt_name (tree type)
  {
    return mangle_vtt_for_type (type);
  }
  
+ /* DECL is an entity associated with TYPE, like a virtual table or an
+    implicitly generated constructor.  Determine whether or not DECL
+    should have external or internal linkage at the object file
+    level.  This routine does not deal with COMDAT linkage and other
+    similar complexities; it simply sets TREE_PUBLIC if it possible for
+    entities in other translation units to contain copies of DECL, in
+    the abstract.  */
+ 
+ void
+ set_linkage_according_to_type (tree type, tree decl)
+ {
+   /* If TYPE involves a local class in a function with internal
+      linkage, then DECL should have internal linkage too.  Other local
+      classes have no linkage -- but if their containing functions
+      have external linkage, it makes sense for DECL to have external
+      linkage too.  That will allow template definitions to be merged,
+      for example.  */
+   if (no_linkage_check (type, /*relaxed_p=*/true))
+     {
+       TREE_PUBLIC (decl) = 0;
+       DECL_INTERFACE_KNOWN (decl) = 1;
+     }
+   else
+     TREE_PUBLIC (decl) = 1;
+ }
+ 
  /* Create a VAR_DECL for a primary or secondary vtable for CLASS_TYPE.
     (For a secondary vtable for B-in-D, CLASS_TYPE should be D, not B.)
     Use NAME for the name of the vtable, and VTABLE_TYPE for its type.  */
  
  static tree
*************** build_vtable (tree class_type, tree name
*** 599,619 ****
    TREE_STATIC (decl) = 1;
    TREE_READONLY (decl) = 1;
    DECL_VIRTUAL_P (decl) = 1;
    DECL_ALIGN (decl) = TARGET_VTABLE_ENTRY_ALIGN;
    DECL_VTABLE_OR_VTT_P (decl) = 1;
- 
    /* At one time the vtable info was grabbed 2 words at a time.  This
       fails on sparc unless you have 8-byte alignment.  (tiemann) */
    DECL_ALIGN (decl) = MAX (TYPE_ALIGN (double_type_node),
  			   DECL_ALIGN (decl));
  
    /* The vtable's visibility is the class visibility.  There is no way
       to override the visibility for just the vtable. */
    DECL_VISIBILITY (decl) = CLASSTYPE_VISIBILITY (class_type);
    DECL_VISIBILITY_SPECIFIED (decl) = CLASSTYPE_VISIBILITY_SPECIFIED (class_type);
-   import_export_vtable (decl, class_type, 0);
  
    return decl;
  }
  
  /* Get the VAR_DECL of the vtable for TYPE. TYPE need not be polymorphic,
--- 625,670 ----
    TREE_STATIC (decl) = 1;
    TREE_READONLY (decl) = 1;
    DECL_VIRTUAL_P (decl) = 1;
    DECL_ALIGN (decl) = TARGET_VTABLE_ENTRY_ALIGN;
    DECL_VTABLE_OR_VTT_P (decl) = 1;
    /* At one time the vtable info was grabbed 2 words at a time.  This
       fails on sparc unless you have 8-byte alignment.  (tiemann) */
    DECL_ALIGN (decl) = MAX (TYPE_ALIGN (double_type_node),
  			   DECL_ALIGN (decl));
+   set_linkage_according_to_type (class_type, decl);
+   /* The vtable has not been defined -- yet.  */
+   DECL_EXTERNAL (decl) = 1;
+   DECL_NOT_REALLY_EXTERN (decl) = 1;
+ 
+   if (write_symbols == DWARF_DEBUG || write_symbols == DWARF2_DEBUG)
+     /* Mark the VAR_DECL node representing the vtable itself as a
+        "gratuitous" one, thereby forcing dwarfout.c to ignore it.  It
+        is rather important that such things be ignored because any
+        effort to actually generate DWARF for them will run into
+        trouble when/if we encounter code like:
+        
+          #pragma interface
+ 	 struct S { virtual void member (); };
+ 	   
+        because the artificial declaration of the vtable itself (as
+        manufactured by the g++ front end) will say that the vtable is
+        a static member of `S' but only *after* the debug output for
+        the definition of `S' has already been output.  This causes
+        grief because the DWARF entry for the definition of the vtable
+        will try to refer back to an earlier *declaration* of the
+        vtable as a static member of `S' and there won't be one.  We
+        might be able to arrange to have the "vtable static member"
+        attached to the member list for `S' before the debug info for
+        `S' get written (which would solve the problem) but that would
+        require more intrusive changes to the g++ front end.  */
+     DECL_IGNORED_P (decl) = 1;
  
    /* The vtable's visibility is the class visibility.  There is no way
       to override the visibility for just the vtable. */
    DECL_VISIBILITY (decl) = CLASSTYPE_VISIBILITY (class_type);
    DECL_VISIBILITY_SPECIFIED (decl) = CLASSTYPE_VISIBILITY_SPECIFIED (class_type);
  
    return decl;
  }
  
  /* Get the VAR_DECL of the vtable for TYPE. TYPE need not be polymorphic,
Index: cp/cp-tree.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/cp-tree.h,v
retrieving revision 1.1025
diff -c -5 -p -r1.1025 cp-tree.h
*** cp/cp-tree.h	28 Jul 2004 08:50:27 -0000	1.1025
--- cp/cp-tree.h	29 Jul 2004 17:57:40 -0000
*************** struct diagnostic_context;
*** 46,64 ****
        DECL_PRETTY_FUNCTION_P (in VAR_DECL)
        KOENIG_LOOKUP_P (in CALL_EXPR)
        STATEMENT_LIST_NO_SCOPE (in STATEMENT_LIST).
        EXPR_STMT_STMT_EXPR_RESULT (in EXPR_STMT)
        BIND_EXPR_TRY_BLOCK (in BIND_EXPR)
!    1: IDENTIFIER_VIRTUAL_P.
        TI_PENDING_TEMPLATE_FLAG.
        TEMPLATE_PARMS_FOR_INLINE.
        DELETE_EXPR_USE_VEC (in DELETE_EXPR).
        (TREE_CALLS_NEW) (in _EXPR or _REF) (commented-out).
        TYPE_BASE_CONVS_MAY_REQUIRE_CODE_P (in _TYPE).
        ICS_ELLIPSIS_FLAG (in _CONV)
        DECL_INITIALIZED_P (in VAR_DECL)
!    2: IDENTIFIER_OPNAME_P.
        TYPE_POLYMORPHIC_P (in _TYPE)
        ICS_THIS_FLAG (in _CONV)
        DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (in VAR_DECL)
        STATEMENT_LIST_TRY_BLOCK (in STATEMENT_LIST)
     3: TYPE_USES_VIRTUAL_BASECLASSES (in a class TYPE).
--- 46,64 ----
        DECL_PRETTY_FUNCTION_P (in VAR_DECL)
        KOENIG_LOOKUP_P (in CALL_EXPR)
        STATEMENT_LIST_NO_SCOPE (in STATEMENT_LIST).
        EXPR_STMT_STMT_EXPR_RESULT (in EXPR_STMT)
        BIND_EXPR_TRY_BLOCK (in BIND_EXPR)
!    1: IDENTIFIER_VIRTUAL_P (in IDENTIFIER_NODE)
        TI_PENDING_TEMPLATE_FLAG.
        TEMPLATE_PARMS_FOR_INLINE.
        DELETE_EXPR_USE_VEC (in DELETE_EXPR).
        (TREE_CALLS_NEW) (in _EXPR or _REF) (commented-out).
        TYPE_BASE_CONVS_MAY_REQUIRE_CODE_P (in _TYPE).
        ICS_ELLIPSIS_FLAG (in _CONV)
        DECL_INITIALIZED_P (in VAR_DECL)
!    2: IDENTIFIER_OPNAME_P (in IDENTIFIER_NODE)
        TYPE_POLYMORPHIC_P (in _TYPE)
        ICS_THIS_FLAG (in _CONV)
        DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (in VAR_DECL)
        STATEMENT_LIST_TRY_BLOCK (in STATEMENT_LIST)
     3: TYPE_USES_VIRTUAL_BASECLASSES (in a class TYPE).
*************** struct diagnostic_context;
*** 68,80 ****
        IDENTIFIER_CTOR_OR_DTOR_P (in IDENTIFIER_NODE)
        BIND_EXPR_BODY_BLOCK (in BIND_EXPR)
     4: TREE_HAS_CONSTRUCTOR (in INDIRECT_REF, SAVE_EXPR, CONSTRUCTOR,
            or FIELD_DECL).
        IDENTIFIER_TYPENAME_P (in IDENTIFIER_NODE)
     5: C_IS_RESERVED_WORD (in IDENTIFIER_NODE)
        DECL_VTABLE_OR_VTT_P (in VAR_DECL)
!    6: For future expansion
  
     Usage of TYPE_LANG_FLAG_?:
     0: TYPE_DEPENDENT_P
     1: TYPE_HAS_CONSTRUCTOR.
     2: TYPE_HAS_DESTRUCTOR.
--- 68,81 ----
        IDENTIFIER_CTOR_OR_DTOR_P (in IDENTIFIER_NODE)
        BIND_EXPR_BODY_BLOCK (in BIND_EXPR)
     4: TREE_HAS_CONSTRUCTOR (in INDIRECT_REF, SAVE_EXPR, CONSTRUCTOR,
            or FIELD_DECL).
        IDENTIFIER_TYPENAME_P (in IDENTIFIER_NODE)
+       DECL_TINFO_P (in VAR_DECL)
     5: C_IS_RESERVED_WORD (in IDENTIFIER_NODE)
        DECL_VTABLE_OR_VTT_P (in VAR_DECL)
!    6: IDENTIFIER_REPO_CHOSEN (in IDENTIFIER_NODE)
  
     Usage of TYPE_LANG_FLAG_?:
     0: TYPE_DEPENDENT_P
     1: TYPE_HAS_CONSTRUCTOR.
     2: TYPE_HAS_DESTRUCTOR.
*************** typedef enum cp_id_kind
*** 373,382 ****
--- 374,389 ----
  /* Nonzero if this identifier is the name of a constructor or
     destructor.  */
  #define IDENTIFIER_CTOR_OR_DTOR_P(NODE) \
    TREE_LANG_FLAG_3 (NODE)
  
+ /* True iff NAME is the DECL_ASSEMBLER_NAME for an entity with vague
+    linkage which the prelinker has assigned to this translation
+    unit.  */
+ #define IDENTIFIER_REPO_CHOSEN(NAME) \
+   (TREE_LANG_FLAG_6 (NAME))
+ 
  /* In a RECORD_TYPE or UNION_TYPE, nonzero if any component is read-only.  */
  #define C_TYPE_FIELDS_READONLY(TYPE) \
    (LANG_TYPE_CLASS_CHECK (TYPE)->fields_readonly)
  
  /* The tokens stored in the default argument.  */
*************** struct lang_type GTY(())
*** 1513,1523 ****
       || TREE_CODE (NODE) == FIELD_DECL		\
       || TREE_CODE (NODE) == USING_DECL))
  
  struct lang_decl_flags GTY(())
  {
!   ENUM_BITFIELD(languages) language : 8;
  
    unsigned operator_attr : 1;
    unsigned constructor_attr : 1;
    unsigned destructor_attr : 1;
    unsigned friend_attr : 1;
--- 1520,1534 ----
       || TREE_CODE (NODE) == FIELD_DECL		\
       || TREE_CODE (NODE) == USING_DECL))
  
  struct lang_decl_flags GTY(())
  {
!   ENUM_BITFIELD(languages) language : 4;
!   unsigned global_ctor_p : 1;
!   unsigned global_dtor_p : 1;
!   unsigned anticipated_p : 1;
!   unsigned template_conv_p : 1;
  
    unsigned operator_attr : 1;
    unsigned constructor_attr : 1;
    unsigned destructor_attr : 1;
    unsigned friend_attr : 1;
*************** struct lang_decl_flags GTY(())
*** 1532,1549 ****
    unsigned not_really_extern : 1;
    unsigned needs_final_overrider : 1;
    unsigned initialized_in_class : 1;
    unsigned assignment_operator_p : 1;
  
-   unsigned global_ctor_p : 1;
-   unsigned global_dtor_p : 1;
-   unsigned anticipated_p : 1;
-   unsigned template_conv_p : 1;
    unsigned u1sel : 1;
    unsigned u2sel : 1;
    unsigned can_be_full : 1;
    unsigned this_thunk_p : 1;
  
    union lang_decl_u {
      /* In a FUNCTION_DECL for which DECL_THUNK_P holds, this is
         THUNK_ALIAS.
         In a FUNCTION_DECL for which DECL_THUNK_P does not hold,
--- 1543,1558 ----
    unsigned not_really_extern : 1;
    unsigned needs_final_overrider : 1;
    unsigned initialized_in_class : 1;
    unsigned assignment_operator_p : 1;
  
    unsigned u1sel : 1;
    unsigned u2sel : 1;
    unsigned can_be_full : 1;
    unsigned this_thunk_p : 1;
+   unsigned repo_available_p : 1;
+   unsigned dummy : 3;
  
    union lang_decl_u {
      /* In a FUNCTION_DECL for which DECL_THUNK_P holds, this is
         THUNK_ALIAS.
         In a FUNCTION_DECL for which DECL_THUNK_P does not hold,
*************** struct lang_decl GTY(())
*** 1629,1651 ****
  #define LANG_DECL_U2_CHECK(NODE, TF) \
    (&DECL_LANG_SPECIFIC (NODE)->decl_flags.u2)
  
  #endif /* ENABLE_TREE_CHECKING */
  
- /* DECL_NEEDED_P holds of a declaration when we need to emit its
-    definition.  This is true when the back-end tells us that
-    the symbol has been referenced in the generated code.  If, however,
-    we are not generating code, then it is also true when a symbol has
-    just been used somewhere, even if it's not really needed.  We need
-    anything that isn't comdat, but we don't know for sure whether or
-    not something is comdat until end-of-file.  */
- #define DECL_NEEDED_P(DECL)					\
-   ((at_eof && TREE_PUBLIC (DECL) && !DECL_COMDAT (DECL))	\
-    || (DECL_ASSEMBLER_NAME_SET_P (DECL)				\
-        && TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (DECL)))	\
-    || (((flag_syntax_only || flag_unit_at_a_time) && TREE_USED (DECL))))
- 
  /* For a FUNCTION_DECL or a VAR_DECL, the language linkage for the
     declaration.  Some entities (like a member function in a local
     class, or a local variable) do not have linkage at all, and this
     macro should not be used in those cases.
     
--- 1638,1647 ----
*************** struct lang_decl GTY(())
*** 1728,1737 ****
--- 1724,1748 ----
  /* If DECL_CLONED_FUNCTION_P holds, this is the function that was
     cloned.  */
  #define DECL_CLONED_FUNCTION(NODE) \
    (DECL_LANG_SPECIFIC (NODE)->u.f.cloned_function)
  
+ /* Perform an action for each clone of FN, if FN is a function with
+    clones.  This macro should be used like:
+    
+       FOR_EACH_CLONE (clone, fn)
+         { ... }
+ 
+   */
+ #define FOR_EACH_CLONE(CLONE, FN)			\
+   if (TREE_CODE (FN) == FUNCTION_DECL			\
+       && (DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (FN)	\
+ 	  || DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (FN)))	\
+      for (CLONE = TREE_CHAIN (FN);			\
+ 	  CLONE && DECL_CLONED_FUNCTION_P (CLONE);	\
+ 	  CLONE = TREE_CHAIN (CLONE))
+ 
  /* Nonzero if NODE has DECL_DISCRIMINATOR and not DECL_ACCESS.  */
  #define DECL_DISCRIMINATOR_P(NODE)	\
    (TREE_CODE (NODE) == VAR_DECL		\
     && DECL_FUNCTION_SCOPE_P (NODE))
  
*************** struct lang_decl GTY(())
*** 1919,1928 ****
--- 1930,1944 ----
  #define SET_DECL_THUNK_P(NODE, THIS_ADJUSTING)			\
    (DECL_LANG_FLAG_7 (NODE) = 1, 				\
     DECL_LANG_SPECIFIC (NODE)->u.f.u3sel = 1,			\
     DECL_LANG_SPECIFIC (NODE)->decl_flags.this_thunk_p = (THIS_ADJUSTING))
  
+ /* True iff DECL is an entity with vague linkage whose definition is
+    available in this translation unit.  */
+ #define DECL_REPO_AVAILABLE_P(NODE) \
+   (DECL_LANG_SPECIFIC (NODE)->decl_flags.repo_available_p)
+ 
  /* Nonzero if this DECL is the __PRETTY_FUNCTION__ variable in a
     template function.  */
  #define DECL_PRETTY_FUNCTION_P(NODE) \
    (TREE_LANG_FLAG_0 (VAR_DECL_CHECK (NODE)))
  
*************** struct lang_decl GTY(())
*** 1963,1972 ****
--- 1979,1992 ----
  /* 1 iff NODE is function-local.  */
  #define DECL_FUNCTION_SCOPE_P(NODE) \
    (DECL_CONTEXT (NODE) \
     && TREE_CODE (DECL_CONTEXT (NODE)) == FUNCTION_DECL)
  
+ /* 1 iff VAR_DECL node NODE is a type-info decl.  This flag is set for
+    both the primary typeinfo object and the associated NTBS name.  */
+ #define DECL_TINFO_P(NODE) TREE_LANG_FLAG_4 (VAR_DECL_CHECK (NODE))
+ 
  /* 1 iff VAR_DECL node NODE is virtual table or VTT.  */
  #define DECL_VTABLE_OR_VTT_P(NODE) TREE_LANG_FLAG_5 (VAR_DECL_CHECK (NODE))
  
  /* 1 iff NODE is function-local, but for types.  */
  #define LOCAL_CLASS_P(NODE)				\
*************** extern tree get_vtbl_decl_for_binfo     
*** 3641,3650 ****
--- 3661,3671 ----
  extern tree get_vtt_name                        (tree);
  extern tree get_primary_binfo                   (tree);
  extern void debug_class				(tree);
  extern void debug_thunks 			(tree);
  extern tree cp_fold_obj_type_ref		(tree, tree);
+ extern void set_linkage_according_to_type       (tree, tree);
  
  /* in cvt.c */
  extern tree convert_to_reference (tree, tree, int, int, tree);
  extern tree convert_from_reference (tree);
  extern tree convert_lvalue (tree, tree);
*************** extern void cplus_decl_attributes (tree 
*** 3785,3797 ****
  extern void finish_anon_union (tree);
  extern tree finish_table (tree, tree, tree, int);
  extern tree coerce_new_type (tree);
  extern tree coerce_delete_type (tree);
  extern void comdat_linkage (tree);
- extern void import_export_vtable (tree, tree, int);
  extern void import_export_decl (tree);
- extern void import_export_tinfo	(tree, tree, bool);
  extern tree build_cleanup			(tree);
  extern tree build_offset_ref_call_from_tree     (tree, tree);
  extern void check_default_args (tree);
  extern void mark_used (tree);
  extern void finish_static_data_member_decl (tree, tree, tree, int);
--- 3806,3816 ----
*************** extern tree cp_build_parm_decl (tree, tr
*** 3799,3808 ****
--- 3818,3830 ----
  extern tree build_artificial_parm (tree, tree);
  extern tree get_guard (tree);
  extern tree get_guard_cond (tree);
  extern tree set_guard (tree);
  extern tree cxx_callgraph_analyze_expr (tree *, int *, tree);
+ extern void mark_needed (tree);
+ extern bool decl_needed_p (tree);
+ extern void note_vague_linkage_fn (tree);
  
  /* XXX Not i18n clean.  */
  #define cp_deprecated(STR)						\
    do {									\
      if (warn_deprecated)						\
*************** extern tree build_non_dependent_expr    
*** 3971,3983 ****
  extern tree build_non_dependent_args            (tree);
  extern bool reregister_specialization           (tree, tree, tree);
  extern tree fold_non_dependent_expr             (tree);
  
  /* in repo.c */
! extern void repo_template_used (tree);
! extern void repo_template_instantiated (tree, bool);
! extern void init_repo (const char *);
  extern void finish_repo (void);
  
  /* in rtti.c */
  /* A varray of all tinfo decls that haven't been emitted yet.  */
  extern GTY(()) varray_type unemitted_tinfo_decls;
--- 3993,4005 ----
  extern tree build_non_dependent_args            (tree);
  extern bool reregister_specialization           (tree, tree, tree);
  extern tree fold_non_dependent_expr             (tree);
  
  /* in repo.c */
! extern void init_repo (void);
! extern int repo_emit_p (tree);
! extern bool repo_export_class_p (tree);
  extern void finish_repo (void);
  
  /* in rtti.c */
  /* A varray of all tinfo decls that haven't been emitted yet.  */
  extern GTY(()) varray_type unemitted_tinfo_decls;
*************** extern tree decl_namespace_context		(tre
*** 4190,4200 ****
  extern tree lvalue_type				(tree);
  extern tree error_type				(tree);
  extern int varargs_function_p			(tree);
  extern int really_overloaded_fn			(tree);
  extern bool cp_tree_equal			(tree, tree);
! extern tree no_linkage_check			(tree);
  extern void debug_binfo				(tree);
  extern tree build_dummy_object			(tree);
  extern tree maybe_dummy_object			(tree, tree *);
  extern int is_dummy_object			(tree);
  extern const struct attribute_spec cxx_attribute_table[];
--- 4212,4222 ----
  extern tree lvalue_type				(tree);
  extern tree error_type				(tree);
  extern int varargs_function_p			(tree);
  extern int really_overloaded_fn			(tree);
  extern bool cp_tree_equal			(tree, tree);
! extern tree no_linkage_check			(tree, bool);
  extern void debug_binfo				(tree);
  extern tree build_dummy_object			(tree);
  extern tree maybe_dummy_object			(tree, tree *);
  extern int is_dummy_object			(tree);
  extern const struct attribute_spec cxx_attribute_table[];
Index: cp/decl.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/decl.c,v
retrieving revision 1.1264
diff -c -5 -p -r1.1264 decl.c
*** cp/decl.c	26 Jul 2004 08:23:54 -0000	1.1264
--- cp/decl.c	29 Jul 2004 17:57:40 -0000
*************** duplicate_decls (tree newdecl, tree oldd
*** 1751,1760 ****
--- 1751,1761 ----
  	 values we should copy from old to new.  */
        DECL_IN_AGGR_P (newdecl) = DECL_IN_AGGR_P (olddecl);
        DECL_LANG_SPECIFIC (newdecl)->decl_flags.u2 =
  	DECL_LANG_SPECIFIC (olddecl)->decl_flags.u2;
        DECL_NONCONVERTING_P (newdecl) = DECL_NONCONVERTING_P (olddecl);
+       DECL_REPO_AVAILABLE_P (newdecl) = DECL_REPO_AVAILABLE_P (olddecl);
        DECL_TEMPLATE_INFO (newdecl) = DECL_TEMPLATE_INFO (olddecl);
        DECL_INITIALIZED_IN_CLASS_P (newdecl)
          |= DECL_INITIALIZED_IN_CLASS_P (olddecl);
        olddecl_friend = DECL_FRIEND_P (olddecl);
  
*************** make_rtl_for_nonlocal_decl (tree decl, t
*** 4569,4579 ****
  	}
  
        defer_p = 1;
      }
    /* Likewise for template instantiations.  */
!   else if (DECL_COMDAT (decl))
      defer_p = 1;
  
    /* If we're deferring the variable, we only need to make RTL if
       there's an ASMSPEC.  Otherwise, we'll lazily create it later when
       we need it.  (There's no way to lazily create RTL for things that
--- 4570,4581 ----
  	}
  
        defer_p = 1;
      }
    /* Likewise for template instantiations.  */
!   else if (DECL_LANG_SPECIFIC (decl)
! 	   && DECL_IMPLICIT_INSTANTIATION (decl))
      defer_p = 1;
  
    /* If we're deferring the variable, we only need to make RTL if
       there's an ASMSPEC.  Otherwise, we'll lazily create it later when
       we need it.  (There's no way to lazily create RTL for things that
*************** grokfndecl (tree ctype,
*** 5511,5521 ****
        /* [basic.link]: A name with no linkage (notably, the name of a class
  	 or enumeration declared in a local scope) shall not be used to
  	 declare an entity with linkage.
  
  	 Only check this for public decls for now.  See core 319, 389.  */
!       t = no_linkage_check (TREE_TYPE (decl));
        if (t)
  	{
  	  if (TYPE_ANONYMOUS_P (t))
  	    {
  	      if (DECL_EXTERN_C_P (decl))
--- 5513,5524 ----
        /* [basic.link]: A name with no linkage (notably, the name of a class
  	 or enumeration declared in a local scope) shall not be used to
  	 declare an entity with linkage.
  
  	 Only check this for public decls for now.  See core 319, 389.  */
!       t = no_linkage_check (TREE_TYPE (decl),
! 			    /*relaxed_p=*/false);
        if (t)
  	{
  	  if (TYPE_ANONYMOUS_P (t))
  	    {
  	      if (DECL_EXTERN_C_P (decl))
*************** grokfndecl (tree ctype,
*** 5721,5730 ****
--- 5724,5752 ----
      DECL_VIRTUAL_P (decl) = 1;
  
    return decl;
  }
  
+ /* DECL is a VAR_DECL for a static data member.  Set flags to reflect
+    the linkage that DECL will receive in the object file.  */
+ 
+ static void
+ set_linkage_for_static_data_member (tree decl)
+ {
+   /* A static data member always has static storage duration and
+      external linkage.  Note that static data members are forbidden in
+      local classes -- the only situation in which a class has
+      non-external linkage.  */
+   TREE_PUBLIC (decl) = 1;
+   TREE_STATIC (decl) = 1;
+   /* For non-template classes, static data members are always put
+      out in exactly those files where they are defined, just as
+      with ordinarly namespace-scope variables.  */
+   if (!processing_template_decl)
+     DECL_INTERFACE_KNOWN (decl) = 1;
+ }
+ 
  /* Create a VAR_DECL named NAME with the indicated TYPE.
  
     If SCOPE is non-NULL, it is the class type or namespace containing
     the variable.  If SCOPE is NULL, the variable should is created in
     the innermost enclosings scope.  */
*************** grokvardecl (tree type,
*** 5780,5795 ****
      {
        DECL_THIS_EXTERN (decl) = 1;
        DECL_EXTERNAL (decl) = !initialized;
      }
  
-   /* In class context, static means one per class,
-      public access, and static storage.  */
    if (DECL_CLASS_SCOPE_P (decl))
      {
!       TREE_PUBLIC (decl) = 1;
!       TREE_STATIC (decl) = 1;
        DECL_EXTERNAL (decl) = 0;
      }
    /* At top level, either `static' or no s.c. makes a definition
       (perhaps tentative), and absence of `static' makes it public.  */
    else if (toplevel_bindings_p ())
--- 5802,5815 ----
      {
        DECL_THIS_EXTERN (decl) = 1;
        DECL_EXTERNAL (decl) = !initialized;
      }
  
    if (DECL_CLASS_SCOPE_P (decl))
      {
!       set_linkage_for_static_data_member (decl);
!       /* This function is only called with out-of-class definitions.  */
        DECL_EXTERNAL (decl) = 0;
      }
    /* At top level, either `static' or no s.c. makes a definition
       (perhaps tentative), and absence of `static' makes it public.  */
    else if (toplevel_bindings_p ())
*************** grokvardecl (tree type,
*** 5820,5830 ****
        /* [basic.link]: A name with no linkage (notably, the name of a class
  	 or enumeration declared in a local scope) shall not be used to
  	 declare an entity with linkage.
  
  	 Only check this for public decls for now.  */
!       tree t = no_linkage_check (TREE_TYPE (decl));
        if (t)
  	{
  	  if (TYPE_ANONYMOUS_P (t))
  	    {
  	      if (DECL_EXTERN_C_P (decl))
--- 5840,5851 ----
        /* [basic.link]: A name with no linkage (notably, the name of a class
  	 or enumeration declared in a local scope) shall not be used to
  	 declare an entity with linkage.
  
  	 Only check this for public decls for now.  */
!       tree t = no_linkage_check (TREE_TYPE (decl),
! 				 /*relaxed_p=*/false);
        if (t)
  	{
  	  if (TYPE_ANONYMOUS_P (t))
  	    {
  	      if (DECL_EXTERN_C_P (decl))
*************** grokdeclarator (const cp_declarator *dec
*** 7857,7869 ****
  	    if (staticp)
  	      {
  		/* C++ allows static class members.  All other work
  		   for this is done by grokfield.  */
  		decl = build_lang_decl (VAR_DECL, unqualified_id, type);
! 		TREE_STATIC (decl) = 1;
! 		/* In class context, 'static' means public access.  */
! 		TREE_PUBLIC (decl) = DECL_EXTERNAL (decl) = 1;
  	      }
  	    else
  	      {
  		decl = build_decl (FIELD_DECL, unqualified_id, type);
  		DECL_NONADDRESSABLE_P (decl) = bitfield;
--- 7878,7892 ----
  	    if (staticp)
  	      {
  		/* C++ allows static class members.  All other work
  		   for this is done by grokfield.  */
  		decl = build_lang_decl (VAR_DECL, unqualified_id, type);
! 		set_linkage_for_static_data_member (decl);
! 		/* Even if there is an in-class initialization, DECL
! 		   is considered undefined until an out-of-class
! 		   definition is provided.  */
! 		DECL_EXTERNAL (decl) = 1;
  	      }
  	    else
  	      {
  		decl = build_decl (FIELD_DECL, unqualified_id, type);
  		DECL_NONADDRESSABLE_P (decl) = bitfield;
*************** start_preparsed_function (tree decl1, tr
*** 9840,9849 ****
--- 9863,9877 ----
  	}
        else
  	DECL_EXTERNAL (decl1) = 0;
        DECL_NOT_REALLY_EXTERN (decl1) = 0;
        DECL_INTERFACE_KNOWN (decl1) = 1;
+       /* If this function is in an interface implemented in this file,
+ 	 make sure that the backend knows to emit this function 
+ 	 here.  */
+       if (!DECL_EXTERNAL (decl1))
+ 	mark_needed (decl1);
      }
    else if (interface_unknown && interface_only
  	   && ! DECL_TEMPLATE_INSTANTIATION (decl1))
      {
        /* If MULTIPLE_SYMBOL_SPACES is defined and we saw a #pragma
Index: cp/decl2.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/decl2.c,v
retrieving revision 1.729
diff -c -5 -p -r1.729 decl2.c
*** cp/decl2.c	18 Jul 2004 23:57:31 -0000	1.729
--- cp/decl2.c	29 Jul 2004 17:57:40 -0000
*************** check_classfn (tree ctype, tree function
*** 727,736 ****
--- 727,763 ----
    if (COMPLETE_TYPE_P (ctype))
      add_method (ctype, function);
    return NULL_TREE;
  }
  
+ /* DECL is a function with vague linkage.  Remember it so that at the
+    end of the translation unit we can decide whether or not to emit
+    it.  */
+ 
+ void
+ note_vague_linkage_fn (tree decl)
+ {
+   if (!DECL_DEFERRED_FN (decl))
+     {
+       DECL_DEFERRED_FN (decl) = 1;
+       DECL_DEFER_OUTPUT (decl) = 1;
+       if (!deferred_fns)
+ 	VARRAY_TREE_INIT (deferred_fns, 32, "deferred_fns");
+       VARRAY_PUSH_TREE (deferred_fns, decl);
+     }
+ }
+ 
+ /* Like note_vague_linkage_fn but for variables.  */
+ 
+ static void
+ note_vague_linkage_var (tree var)
+ {
+   if (!pending_statics)
+     VARRAY_TREE_INIT (pending_statics, 32, "pending_statics");
+   VARRAY_PUSH_TREE (pending_statics, var);
+ }
+ 
  /* We have just processed the DECL, which is a static data member.
     Its initializer, if present, is INIT.  The ASMSPEC_TREE, if
     present, is the assembly-language name for the data member.
     FLAGS is as for cp_finish_decl.  */
  
*************** finish_static_data_member_decl (tree dec
*** 748,762 ****
    /* current_class_type can be NULL_TREE in case of error.  */
    if (!asmspec_tree && current_class_type)
      DECL_INITIAL (decl) = error_mark_node;
  
    if (! processing_template_decl)
!     {
!       if (!pending_statics)
! 	VARRAY_TREE_INIT (pending_statics, 32, "pending_statics");
!       VARRAY_PUSH_TREE (pending_statics, decl);
!     }
  
    if (LOCAL_CLASS_P (current_class_type))
      pedwarn ("local class `%#T' shall not have static data member `%#D'",
  	     current_class_type, decl);
  
--- 775,785 ----
    /* current_class_type can be NULL_TREE in case of error.  */
    if (!asmspec_tree && current_class_type)
      DECL_INITIAL (decl) = error_mark_node;
  
    if (! processing_template_decl)
!     note_vague_linkage_var (decl);
  
    if (LOCAL_CLASS_P (current_class_type))
      pedwarn ("local class `%#T' shall not have static data member `%#D'",
  	     current_class_type, decl);
  
*************** maybe_make_one_only (tree decl)
*** 1401,1455 ****
  	  mark_decl_referenced (decl);
  	}
      }
  }
  
- /* Set TREE_PUBLIC and/or DECL_EXTERN on the vtable DECL,
-    based on TYPE and other static flags.
- 
-    Note that anything public is tagged TREE_PUBLIC, whether
-    it's public in this file or in another one.  */
- 
- void
- import_export_vtable (tree decl, tree type, int final)
- {
-   if (DECL_INTERFACE_KNOWN (decl))
-     return;
- 
-   if (TYPE_FOR_JAVA (type))
-     {
-       TREE_PUBLIC (decl) = 1;
-       DECL_EXTERNAL (decl) = 1;
-       DECL_INTERFACE_KNOWN (decl) = 1;
-     }
-   else if (CLASSTYPE_INTERFACE_KNOWN (type))
-     {
-       TREE_PUBLIC (decl) = 1;
-       DECL_EXTERNAL (decl) = CLASSTYPE_INTERFACE_ONLY (type);
-       DECL_INTERFACE_KNOWN (decl) = 1;
-     }
-   else
-     {
-       /* We can only wait to decide if we have real non-inline virtual
- 	 functions in our class, or if we come from a template.  */
- 
-       int found = (CLASSTYPE_TEMPLATE_INSTANTIATION (type)
- 		   || CLASSTYPE_KEY_METHOD (type) != NULL_TREE);
- 
-       if (final || ! found)
- 	{
- 	  comdat_linkage (decl);
- 	  DECL_EXTERNAL (decl) = 0;
- 	}
-       else
- 	{
- 	  TREE_PUBLIC (decl) = 1;
- 	  DECL_EXTERNAL (decl) = 1;
- 	}
-     }
- }
- 
  /* Determine whether or not we want to specifically import or export CTYPE,
     using various heuristics.  */
  
  static void
  import_export_class (tree ctype)
--- 1424,1433 ----
*************** import_export_class (tree ctype)
*** 1477,1501 ****
  
    if (lookup_attribute ("dllimport", TYPE_ATTRIBUTES (ctype)))
      import_export = -1;
    else if (lookup_attribute ("dllexport", TYPE_ATTRIBUTES (ctype)))
      import_export = 1;
! 
!   /* If we got -fno-implicit-templates, we import template classes that
!      weren't explicitly instantiated.  */
!   if (import_export == 0
!       && CLASSTYPE_IMPLICIT_INSTANTIATION (ctype)
!       && ! flag_implicit_templates)
!     import_export = -1;
! 
!   /* Base our import/export status on that of the first non-inline,
!      non-pure virtual function, if any.  */
!   if (import_export == 0
!       && TYPE_POLYMORPHIC_P (ctype))
      {
        tree method = CLASSTYPE_KEY_METHOD (ctype);
- 
        /* If weak symbol support is not available, then we must be
  	 careful not to emit the vtable when the key function is
  	 inline.  An inline function can be defined in multiple
  	 translation units.  If we were to emit the vtable in each
  	 translation unit containing a definition, we would get
--- 1455,1476 ----
  
    if (lookup_attribute ("dllimport", TYPE_ATTRIBUTES (ctype)))
      import_export = -1;
    else if (lookup_attribute ("dllexport", TYPE_ATTRIBUTES (ctype)))
      import_export = 1;
!   else if (CLASSTYPE_IMPLICIT_INSTANTIATION (ctype)
! 	   && !flag_implicit_templates)
!     /* For a template class, without -fimplicit-templates, check the
!        repository.  If the virtual table is assigned to this
!        translation unit, then export the class; otherwise, import
!        it.  */
!       import_export = repo_export_class_p (ctype) ? 1 : -1;
!   else if (TYPE_POLYMORPHIC_P (ctype))
      {
+       /* The ABI specifies that the virtual table and associated
+ 	 information are emitted with the key method, if any.  */
        tree method = CLASSTYPE_KEY_METHOD (ctype);
        /* If weak symbol support is not available, then we must be
  	 careful not to emit the vtable when the key function is
  	 inline.  An inline function can be defined in multiple
  	 translation units.  If we were to emit the vtable in each
  	 translation unit containing a definition, we would get
*************** import_export_class (tree ctype)
*** 1523,1653 ****
  /* Return true if VAR has already been provided to the back end; in that
     case VAR should not be modified further by the front end.  */
  static bool
  var_finalized_p (tree var)
  {
!   if (flag_unit_at_a_time)
!     return cgraph_varpool_node (var)->finalized;
!   else
!     return TREE_ASM_WRITTEN (var);
  }
  
  /* If necessary, write out the vtables for the dynamic class CTYPE.
     Returns true if any vtables were emitted.  */
  
  static bool
  maybe_emit_vtables (tree ctype)
  {
    tree vtbl;
    tree primary_vtbl;
!   bool needed = false;
!   bool weaken_vtables;
  
    /* If the vtables for this class have already been emitted there is
       nothing more to do.  */
    primary_vtbl = CLASSTYPE_VTABLES (ctype);
    if (var_finalized_p (primary_vtbl))
      return false;
    /* Ignore dummy vtables made by get_vtable_decl.  */
    if (TREE_TYPE (primary_vtbl) == void_type_node)
      return false;
  
-   import_export_class (ctype);
- 
    /* See if any of the vtables are needed.  */
    for (vtbl = CLASSTYPE_VTABLES (ctype); vtbl; vtbl = TREE_CHAIN (vtbl))
      {
!       import_export_vtable (vtbl, ctype, 1);
!       if (!DECL_EXTERNAL (vtbl) && DECL_NEEDED_P (vtbl))
! 	break;
      }
!   if (!vtbl)
      {
        /* If the references to this class' vtables are optimized away,
  	 still emit the appropriate debugging information.  See
  	 dfs_debug_mark.  */
        if (DECL_COMDAT (primary_vtbl) 
  	  && CLASSTYPE_DEBUG_REQUESTED (ctype))
  	note_debug_info_needed (ctype);
        return false;
      }
-   else if (TREE_PUBLIC (vtbl) && !DECL_COMDAT (vtbl))
-     needed = true;
-   
-   /* Determine whether to make vtables weak.  The ABI requires that we
-       do so.  There are two cases in which we have to violate the ABI
-       specification: targets where we don't have weak symbols
-       (obviously), and targets where weak symbols don't appear in
-       static archives' tables of contents.  On such targets, avoiding
-       undefined symbol link errors requires that we only make a symbol
-       weak if we know that it will be emitted everywhere it's needed.
-       So on such targets we don't make vtables weak in the common case
-       where we're emitting a vtable of a nontemplate class in the 
-       translation unit containing the definition of a noninline key
-       method. */
-   if (flag_weak && !TARGET_WEAK_NOT_IN_ARCHIVE_TOC)
-     weaken_vtables = true;
-   else if (flag_weak)
-     {
-       if (CLASSTYPE_USE_TEMPLATE (ctype))
-  	weaken_vtables = CLASSTYPE_IMPLICIT_INSTANTIATION (ctype);
-       else
-  	weaken_vtables = !CLASSTYPE_KEY_METHOD (ctype)
-  	  || DECL_DECLARED_INLINE_P (CLASSTYPE_KEY_METHOD (ctype));
-     }
-   else
-     weaken_vtables = false;
  
    /* The ABI requires that we emit all of the vtables if we emit any
       of them.  */
    for (vtbl = CLASSTYPE_VTABLES (ctype); vtbl; vtbl = TREE_CHAIN (vtbl))
      {
!       /* Write it out.  */
!       import_export_vtable (vtbl, ctype, 1);
        mark_vtable_entries (vtbl);
  
-       /* If we know that DECL is needed, mark it as such for the varpool.  */
-       if (needed)
- 	cgraph_varpool_mark_needed_node (cgraph_varpool_node (vtbl));
- 
        if (TREE_TYPE (DECL_INITIAL (vtbl)) == 0)
  	{
  	  /* It had better be all done at compile-time.  */
  	  if (store_init_value (vtbl, DECL_INITIAL (vtbl)))
  	    abort ();
  	}
  
!       if (write_symbols == DWARF_DEBUG || write_symbols == DWARF2_DEBUG)
! 	{
! 	  /* Mark the VAR_DECL node representing the vtable itself as a
! 	     "gratuitous" one, thereby forcing dwarfout.c to ignore it.
! 	     It is rather important that such things be ignored because
! 	     any effort to actually generate DWARF for them will run
! 	     into trouble when/if we encounter code like:
! 
! 		#pragma interface
! 		struct S { virtual void member (); };
! 
! 	      because the artificial declaration of the vtable itself (as
! 	      manufactured by the g++ front end) will say that the vtable
! 	      is a static member of `S' but only *after* the debug output
! 	      for the definition of `S' has already been output.  This causes
! 	      grief because the DWARF entry for the definition of the vtable
! 	      will try to refer back to an earlier *declaration* of the
! 	      vtable as a static member of `S' and there won't be one.
! 	      We might be able to arrange to have the "vtable static member"
! 	      attached to the member list for `S' before the debug info for
! 	      `S' get written (which would solve the problem) but that would
! 	      require more intrusive changes to the g++ front end.  */
! 
! 	  DECL_IGNORED_P (vtbl) = 1;
! 	}
! 
!       /* Always make vtables weak.  Or at least almost always; see above. */
!       if (weaken_vtables)
! 	comdat_linkage (vtbl);
! 
        rest_of_decl_compilation (vtbl, NULL, 1, 1);
  
        /* Because we're only doing syntax-checking, we'll never end up
  	 actually marking the variable as written.  */
        if (flag_syntax_only)
--- 1498,1608 ----
  /* Return true if VAR has already been provided to the back end; in that
     case VAR should not be modified further by the front end.  */
  static bool
  var_finalized_p (tree var)
  {
!   return cgraph_varpool_node (var)->finalized;
! }
! 
! /* DECL is a VAR_DECL or FUNCTION_DECL which, for whatever reason,
!    must be emitted in this translation unit.  Mark it as such.  */
! 
! void
! mark_needed (tree decl)
! {
!   /* It's possible that we no longer need to set
!      TREE_SYMBOL_REFERENCED here directly, but doing so is
!      harmless.  */
!   TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)) = 1;
!   mark_decl_referenced (decl);
! }
! 
! /* DECL is either a FUNCTION_DECL or a VAR_DECL.  This function
!    returns true if a definition of this entity should be provided in
!    this object file.  Callers use this function to determine whether
!    or not to let the back end know that a definition of DECL is
!    available in this translation unit.  */
! 
! bool
! decl_needed_p (tree decl)
! {
!   my_friendly_assert (TREE_CODE (decl) == VAR_DECL
! 		      || TREE_CODE (decl) == FUNCTION_DECL,
! 		      20040726);
!   /* This function should only be called at the end of the translation
!      unit.  We cannot be sure of whether or not something will be
!      COMDAT until that point.  */
!   my_friendly_assert (at_eof, 20040726);
! 
!   /* All entities with external linkage that are not COMDAT should be
!      emitted; they may be referred to from other object files.  */
!   if (TREE_PUBLIC (decl) && !DECL_COMDAT (decl))
!     return true;
!   /* If this entity was used, let the back-end see it; it will decide
!      whether or not to emit it into the object file.  */
!   if (TREE_USED (decl) 
!       || (DECL_ASSEMBLER_NAME_SET_P (decl)
! 	  && TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl))))
!       return true;
!   /* Otherwise, DECL does not need to be emitted -- yet.  A subsequent
!      reference to DECL might cause it to be emitted later.  */
!   return false;
  }
  
  /* If necessary, write out the vtables for the dynamic class CTYPE.
     Returns true if any vtables were emitted.  */
  
  static bool
  maybe_emit_vtables (tree ctype)
  {
    tree vtbl;
    tree primary_vtbl;
!   int needed = 0;
  
    /* If the vtables for this class have already been emitted there is
       nothing more to do.  */
    primary_vtbl = CLASSTYPE_VTABLES (ctype);
    if (var_finalized_p (primary_vtbl))
      return false;
    /* Ignore dummy vtables made by get_vtable_decl.  */
    if (TREE_TYPE (primary_vtbl) == void_type_node)
      return false;
  
    /* See if any of the vtables are needed.  */
    for (vtbl = CLASSTYPE_VTABLES (ctype); vtbl; vtbl = TREE_CHAIN (vtbl))
      {
!       import_export_decl (vtbl);
!       if (DECL_NOT_REALLY_EXTERN (vtbl) && decl_needed_p (vtbl))
! 	needed = 1;
      }
!   if (!needed)
      {
        /* If the references to this class' vtables are optimized away,
  	 still emit the appropriate debugging information.  See
  	 dfs_debug_mark.  */
        if (DECL_COMDAT (primary_vtbl) 
  	  && CLASSTYPE_DEBUG_REQUESTED (ctype))
  	note_debug_info_needed (ctype);
        return false;
      }
  
    /* The ABI requires that we emit all of the vtables if we emit any
       of them.  */
    for (vtbl = CLASSTYPE_VTABLES (ctype); vtbl; vtbl = TREE_CHAIN (vtbl))
      {
!       /* Mark entities references from the virtual table as used.  */
        mark_vtable_entries (vtbl);
  
        if (TREE_TYPE (DECL_INITIAL (vtbl)) == 0)
  	{
  	  /* It had better be all done at compile-time.  */
  	  if (store_init_value (vtbl, DECL_INITIAL (vtbl)))
  	    abort ();
  	}
  
!       /* Write it out.  */
!       DECL_EXTERNAL (vtbl) = 0;
        rest_of_decl_compilation (vtbl, NULL, 1, 1);
  
        /* Because we're only doing syntax-checking, we'll never end up
  	 actually marking the variable as written.  */
        if (flag_syntax_only)
*************** maybe_emit_vtables (tree ctype)
*** 1659,1700 ****
    note_debug_info_needed (ctype);
  
    return true;
  }
  
! /* Determines the proper settings of TREE_PUBLIC and DECL_EXTERNAL for an
!    inline function or template instantiation at end-of-file.  */
  
  void
  import_export_decl (tree decl)
  {
    if (DECL_INTERFACE_KNOWN (decl))
      return;
  
!   if (DECL_TEMPLATE_INSTANTIATION (decl)
!       || DECL_FRIEND_PSEUDO_TEMPLATE_INSTANTIATION (decl))
      {
!       DECL_NOT_REALLY_EXTERN (decl) = 1;
!       if ((DECL_IMPLICIT_INSTANTIATION (decl)
! 	   || DECL_FRIEND_PSEUDO_TEMPLATE_INSTANTIATION (decl))
! 	  && (flag_implicit_templates
! 	      || (flag_implicit_inline_templates
! 		  && TREE_CODE (decl) == FUNCTION_DECL 
! 		  && DECL_DECLARED_INLINE_P (decl))))
! 	{
! 	  if (!TREE_PUBLIC (decl))
! 	    /* Templates are allowed to have internal linkage.  See 
! 	       [basic.link].  */
! 	    ;
! 	  else
! 	    comdat_linkage (decl);
  	}
        else
  	{
! 	  DECL_EXTERNAL (decl) = 1;
! 	  DECL_NOT_REALLY_EXTERN (decl) = 0;
  	}
      }
    else if (DECL_FUNCTION_MEMBER_P (decl))
      {
        if (!DECL_DECLARED_INLINE_P (decl))
  	{
--- 1614,1811 ----
    note_debug_info_needed (ctype);
  
    return true;
  }
  
! /* DECL is a FUNCTION_DECL or VAR_DECL.  If the object file linkage
!    for DECL has not already been determined, do so now by setting
!    DECL_EXTERNAL, DECL_COMDAT and other related flags.  Until this
!    function is called entities with vague linkage whose definitions
!    are available must have TREE_PUBLIC set.
! 
!    If this function decides to place DECL in COMDAT, it will set
!    appropriate flags -- but will not clear DECL_EXTERNAL.  It is up to
!    the caller to decide whether or not to clear DECL_EXTERNAL.  Some
!    callers defer that decision until it is clear that DECL is actually
!    required.  */
  
  void
  import_export_decl (tree decl)
  {
+   int emit_p;
+   bool comdat_p;
+   bool import_p;
+ 
    if (DECL_INTERFACE_KNOWN (decl))
      return;
  
!   /* We cannot determine what linkage to give to an entity with vague
!      linkage until the end of the file.  For example, a virtual table
!      for a class will be defined if and only if the key method is
!      defined in this translation unit.  As a further example, consider
!      that when compiling a translation unit that uses PCH file with
!      "-frepo" it would be incorrect to make decisions about what
!      entities to emit when building the PCH; those decisions must be
!      delayed until the repository information has been processed.  */
!   my_friendly_assert (at_eof, 20040727);
!   /* Object file linkage for explicit instantiations is handled in
!      mark_decl_instantiated.  For static variables in functions with
!      vague linkage, maybe_commonize_var is used.
! 
!      Therefore, the only declarations that should be provided to this
!      function are those with external linkage that:
! 
!      * implicit instantiations of function templates
! 
!      * inline function
! 
!      * implicit instantiations of static data members of class
!        templates
! 
!      * virtual tables
! 
!      * typeinfo objects
! 
!      Furthermore, all entities that reach this point must have a
!      definition available in this translation unit.
! 
!      The following assertions check these conditions.  */
!   my_friendly_assert (TREE_CODE (decl) == FUNCTION_DECL
! 		      || TREE_CODE (decl) == VAR_DECL,
! 		      2004725);
!   /* Any code that creates entities with TREE_PUBLIC cleared should
!      also set DECL_INTERFACE_KNOWN.  */
!   my_friendly_assert (TREE_PUBLIC (decl), 20040725);
!   if (TREE_CODE (decl) == FUNCTION_DECL)
!     my_friendly_assert (DECL_IMPLICIT_INSTANTIATION (decl)
! 			|| DECL_FRIEND_PSEUDO_TEMPLATE_INSTANTIATION (decl)
! 			|| DECL_DECLARED_INLINE_P (decl),
! 			20040725);
!   else
!     my_friendly_assert (DECL_IMPLICIT_INSTANTIATION (decl)
! 			|| DECL_VTABLE_OR_VTT_P (decl)
! 			|| DECL_TINFO_P (decl),
! 			20040725);
!   /* Check that a definition of DECL is available in this translation
!      unit.  */
!   my_friendly_assert (!DECL_REALLY_EXTERN (decl), 20040725);
! 
!   /* Assume that DECL will not have COMDAT linkage.  */
!   comdat_p = false;
!   /* Assume that DECL will not be imported into this translation
!      unit.  */
!   import_p = false;
! 
!   /* See if the repository tells us whether or not to emit DECL in
!      this translation unit.  */
!   emit_p = repo_emit_p (decl);
!   if (emit_p == 0)
!     import_p = true;
!   else if (emit_p == 1)
      {
!       /* The repository indicates that this entity should be defined
! 	 here.  Make sure the back end honors that request.  */
!       if (TREE_CODE (decl) == VAR_DECL)
! 	mark_needed (decl);
!       else if (DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (decl)
! 	       || DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (decl))
! 	{
! 	  tree clone;
! 	  FOR_EACH_CLONE (clone, decl)
! 	    mark_needed (clone);
  	}
        else
+ 	mark_needed (decl);
+       /* Output the definition as an ordinary strong definition.  */
+       DECL_EXTERNAL (decl) = 0;
+       DECL_INTERFACE_KNOWN (decl) = 1;
+       return;
+     }
+ 
+   if (import_p)
+     /* We have already decided what to do with this DECL; there is no
+        need to check anything further.  */
+     ;
+   else if (TREE_CODE (decl) == VAR_DECL && DECL_VTABLE_OR_VTT_P (decl))
+     {
+       tree type = DECL_CONTEXT (decl);
+       import_export_class (type);
+       if (TYPE_FOR_JAVA (type))
+ 	import_p = true;
+       else if (CLASSTYPE_INTERFACE_KNOWN (type)
+ 	       && CLASSTYPE_INTERFACE_ONLY (type))
+ 	import_p = true;
+       else if (TARGET_WEAK_NOT_IN_ARCHIVE_TOC
+ 	       && !CLASSTYPE_USE_TEMPLATE (type)
+ 	       && CLASSTYPE_KEY_METHOD (type)
+ 	       && !DECL_DECLARED_INLINE_P (CLASSTYPE_KEY_METHOD (type)))
+ 	/* The ABI requires that all virtual tables be emitted with
+ 	   COMDAT linkage.  However, on systems where COMDAT symbols
+ 	   don't show up in the table of contents for a static
+ 	   archive, the linker will report errors about undefined
+ 	   symbols because it will not see the virtual table
+ 	   definition.  Therefore, in the case that we know that the
+ 	   virtual table will be emitted in only one translation
+ 	   unit, we make the virtual table an ordinary definition
+ 	   with external linkage.  */
+ 	DECL_EXTERNAL (decl) = 0;
+       else if (CLASSTYPE_INTERFACE_KNOWN (type))
+ 	{
+ 	  /* TYPE is being exported from this translation unit, so DECL
+ 	     should be defined here.  The ABI requires COMDAT
+ 	     linkage.  Normally, we only emit COMDAT things when they
+ 	     are needed; make sure that we realize that this entity is
+ 	     indeed needed.  */
+ 	  comdat_p = true;
+ 	  mark_needed (decl);
+ 	}
+       else if (!flag_implicit_templates
+ 	       && CLASSTYPE_IMPLICIT_INSTANTIATION (type))
+ 	import_p = true;
+       else
+ 	comdat_p = true;
+     }
+   else if (TREE_CODE (decl) == VAR_DECL && DECL_TINFO_P (decl))
+     {
+       tree type = TREE_TYPE (DECL_NAME (decl));
+       if (CLASS_TYPE_P (type))
  	{
! 	  import_export_class (type);
! 	  if (CLASSTYPE_INTERFACE_KNOWN (type)
! 	      && TYPE_POLYMORPHIC_P (type)
! 	      && CLASSTYPE_INTERFACE_ONLY (type)
! 	      /* If -fno-rtti was specified, then we cannot be sure
! 		 that RTTI information will be emitted with the
! 		 virtual table of the class, so we must emit it
! 		 wherever it is used.  */
! 	      && flag_rtti)
! 	    import_p = true;
! 	  else 
! 	    {
! 	      comdat_p = true;
! 	      if (CLASSTYPE_INTERFACE_KNOWN (type)
! 		  && !CLASSTYPE_INTERFACE_ONLY (type))
! 		mark_needed (decl);
! 	    }
  	}
+       else
+ 	comdat_p = true;
+     }
+   else if (DECL_TEMPLATE_INSTANTIATION (decl)
+ 	   || DECL_FRIEND_PSEUDO_TEMPLATE_INSTANTIATION (decl))
+     {
+       /* DECL is an implicit instantiation of a function or static
+ 	 data member.  */
+       if (flag_implicit_templates
+ 	  || (flag_implicit_inline_templates
+ 	      && TREE_CODE (decl) == FUNCTION_DECL 
+ 	      && DECL_DECLARED_INLINE_P (decl)))
+ 	comdat_p = true;
+       else
+ 	/* If we are not implicitly generating templates, then mark
+ 	   this entity as undefined in this translation unit.  */
+ 	import_p = true;
      }
    else if (DECL_FUNCTION_MEMBER_P (decl))
      {
        if (!DECL_DECLARED_INLINE_P (decl))
  	{
*************** import_export_decl (tree decl)
*** 1711,1769 ****
  	      if (!DECL_NOT_REALLY_EXTERN (decl))
  		DECL_EXTERNAL (decl) = 1;
  
  	      /* Always make artificials weak.  */
  	      if (DECL_ARTIFICIAL (decl) && flag_weak)
! 		comdat_linkage (decl);
  	      else
  		maybe_make_one_only (decl);
  	    }
  	}
        else
! 	comdat_linkage (decl);
      }
    else
!     comdat_linkage (decl);
  
!   DECL_INTERFACE_KNOWN (decl) = 1;
! }
! 
! /* Here, we only decide whether or not the tinfo node should be
!    emitted with the vtable.  IS_IN_LIBRARY is nonzero iff the
!    typeinfo for TYPE should be in the runtime library.  */
! 
! void
! import_export_tinfo (tree decl, tree type, bool is_in_library)
! {
!   if (DECL_INTERFACE_KNOWN (decl))
!     return;
!   
!   if (IS_AGGR_TYPE (type))
!     import_export_class (type);
!       
!   if (IS_AGGR_TYPE (type) && CLASSTYPE_INTERFACE_KNOWN (type)
!       && TYPE_POLYMORPHIC_P (type)
!       /* If -fno-rtti, we're not necessarily emitting this stuff with
! 	 the class, so go ahead and emit it now.  This can happen when
! 	 a class is used in exception handling.  */
!       && flag_rtti)
      {
!       DECL_NOT_REALLY_EXTERN (decl) = !CLASSTYPE_INTERFACE_ONLY (type);
!       DECL_COMDAT (decl) = 0;
      }
!   else
      {
!       DECL_NOT_REALLY_EXTERN (decl) = 1;
!       DECL_COMDAT (decl) = 1;
      }
  
-   /* Now override some cases.  */
-   if (flag_weak)
-     DECL_COMDAT (decl) = 1;
-   else if (is_in_library)
-     DECL_COMDAT (decl) = 0;
-   
    DECL_INTERFACE_KNOWN (decl) = 1;
  }
  
  /* Return an expression that performs the destruction of DECL, which
     must be a VAR_DECL whose type has a non-trivial destructor, or is
--- 1822,1856 ----
  	      if (!DECL_NOT_REALLY_EXTERN (decl))
  		DECL_EXTERNAL (decl) = 1;
  
  	      /* Always make artificials weak.  */
  	      if (DECL_ARTIFICIAL (decl) && flag_weak)
! 		comdat_p = true;
  	      else
  		maybe_make_one_only (decl);
  	    }
  	}
        else
! 	comdat_p = true;
      }
    else
!     comdat_p = true;
  
!   if (import_p)
      {
!       /* If we are importing DECL into this translation unit, mark is
! 	 an undefined here.  */
!       DECL_EXTERNAL (decl) = 1;
!       DECL_NOT_REALLY_EXTERN (decl) = 0;
      }
!   else if (comdat_p)
      {
!       /* If we decided to put DECL in COMDAT, mark it accordingly at
! 	 this point.  */
!       comdat_linkage (decl);
      }
  
    DECL_INTERFACE_KNOWN (decl) = 1;
  }
  
  /* Return an expression that performs the destruction of DECL, which
     must be a VAR_DECL whose type has a non-trivial destructor, or is
*************** static void
*** 2401,2412 ****
  write_out_vars (tree vars)
  {
    tree v;
  
    for (v = vars; v; v = TREE_CHAIN (v))
!     if (!var_finalized_p (TREE_VALUE (v)))
!       rest_of_decl_compilation (TREE_VALUE (v), 0, 1, 1);
  }
  
  /* Generate a static constructor (if CONSTRUCTOR_P) or destructor
     (otherwise) that will initialize all gobal objects with static
     storage duration having the indicated PRIORITY.  */
--- 2488,2505 ----
  write_out_vars (tree vars)
  {
    tree v;
  
    for (v = vars; v; v = TREE_CHAIN (v))
!     {
!       tree var = TREE_VALUE (v);
!       if (!var_finalized_p (var))
! 	{
! 	  import_export_decl (var);
! 	  rest_of_decl_compilation (var, 0, 1, 1);
! 	}
!     }
  }
  
  /* Generate a static constructor (if CONSTRUCTOR_P) or destructor
     (otherwise) that will initialize all gobal objects with static
     storage duration having the indicated PRIORITY.  */
*************** tree
*** 2518,2542 ****
  cxx_callgraph_analyze_expr (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED,
  			    tree from ATTRIBUTE_UNUSED)
  {
    tree t = *tp;
  
!   if (flag_unit_at_a_time)
!     switch (TREE_CODE (t))
!       {
!       case PTRMEM_CST:
! 	if (TYPE_PTRMEMFUNC_P (TREE_TYPE (t)))
! 	  cgraph_mark_needed_node (cgraph_node (PTRMEM_CST_MEMBER (t)));
! 	break;
!       case BASELINK:
! 	if (TREE_CODE (BASELINK_FUNCTIONS (t)) == FUNCTION_DECL)
! 	  cgraph_mark_needed_node (cgraph_node (BASELINK_FUNCTIONS (t)));
! 	break;
! 
!       default:
! 	break;
!       }
  
    return NULL;
  }
  
  /* This routine is called from the last rule in yyparse ().
--- 2611,2650 ----
  cxx_callgraph_analyze_expr (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED,
  			    tree from ATTRIBUTE_UNUSED)
  {
    tree t = *tp;
  
!   switch (TREE_CODE (t))
!     {
!     case PTRMEM_CST:
!       if (TYPE_PTRMEMFUNC_P (TREE_TYPE (t)))
! 	cgraph_mark_needed_node (cgraph_node (PTRMEM_CST_MEMBER (t)));
!       break;
!     case BASELINK:
!       if (TREE_CODE (BASELINK_FUNCTIONS (t)) == FUNCTION_DECL)
! 	cgraph_mark_needed_node (cgraph_node (BASELINK_FUNCTIONS (t)));
!       break;
!     case VAR_DECL:
!       if (DECL_VTABLE_OR_VTT_P (t))
! 	{
! 	  /* The ABI requires that all virtual tables be emitted
! 	     whenever one of them is.  */
! 	  tree vtbl;
! 	  for (vtbl = CLASSTYPE_VTABLES (DECL_CONTEXT (t));
! 	       vtbl;
! 	       vtbl = TREE_CHAIN (vtbl))
! 	    mark_decl_referenced (vtbl);
! 	}
!       else if (DECL_CONTEXT (t) 
! 	       && TREE_CODE (DECL_CONTEXT (t)) == FUNCTION_DECL)
! 	/* If we need a static variable in a function, then we
! 	   need the containing function.  */
! 	mark_decl_referenced (DECL_CONTEXT (t));
!       break;
!     default:
!       break;
!     }
  
    return NULL;
  }
  
  /* This routine is called from the last rule in yyparse ().
*************** finish_file (void)
*** 2730,2749 ****
  #else
  	  locus.line++;
  #endif
  	}
        
        for (i = 0; i < deferred_fns_used; ++i)
  	{
  	  tree decl = VARRAY_TREE (deferred_fns, i);
  
- 	  if (! DECL_DECLARED_INLINE_P (decl) || ! TREE_USED (decl))
- 	    abort ();
- 
  	  /* Does it need synthesizing?  */
  	  if (DECL_ARTIFICIAL (decl) && ! DECL_INITIAL (decl)
- 	      && TREE_USED (decl)
  	      && (! DECL_REALLY_EXTERN (decl) || DECL_INLINE (decl)))
  	    {
  	      /* Even though we're already at the top-level, we push
  		 there again.  That way, when we pop back a few lines
  		 hence, all of our state is restored.  Otherwise,
--- 2838,2856 ----
  #else
  	  locus.line++;
  #endif
  	}
        
+       /* Go through the set of inline functions whose bodies have not
+ 	 been emitted yet.  If out-of-line copies of these functions
+ 	 are required, emit them.  */
        for (i = 0; i < deferred_fns_used; ++i)
  	{
  	  tree decl = VARRAY_TREE (deferred_fns, i);
  
  	  /* Does it need synthesizing?  */
  	  if (DECL_ARTIFICIAL (decl) && ! DECL_INITIAL (decl)
  	      && (! DECL_REALLY_EXTERN (decl) || DECL_INLINE (decl)))
  	    {
  	      /* Even though we're already at the top-level, we push
  		 there again.  That way, when we pop back a few lines
  		 hence, all of our state is restored.  Otherwise,
*************** finish_file (void)
*** 2770,2791 ****
  	     in deferred_fns varray, rest_of_compilation would skip
  	     this function and we really cannot expand the same
  	     function twice.  */
  	  if (DECL_NOT_REALLY_EXTERN (decl)
  	      && DECL_INITIAL (decl)
! 	      && DECL_NEEDED_P (decl))
  	    DECL_EXTERNAL (decl) = 0;
  
  	  /* If we're going to need to write this function out, and
  	     there's already a body for it, create RTL for it now.
  	     (There might be no body if this is a method we haven't
  	     gotten around to synthesizing yet.)  */
  	  if (!DECL_EXTERNAL (decl)
! 	      && DECL_NEEDED_P (decl)
  	      && !TREE_ASM_WRITTEN (decl)
! 	      && (!flag_unit_at_a_time 
! 		  || !cgraph_node (decl)->local.finalized))
  	    {
  	      /* We will output the function; no longer consider it in this
  		 loop.  */
  	      DECL_DEFER_OUTPUT (decl) = 0;
  	      /* Generate RTL for this function now that we know we
--- 2877,2897 ----
  	     in deferred_fns varray, rest_of_compilation would skip
  	     this function and we really cannot expand the same
  	     function twice.  */
  	  if (DECL_NOT_REALLY_EXTERN (decl)
  	      && DECL_INITIAL (decl)
! 	      && decl_needed_p (decl))
  	    DECL_EXTERNAL (decl) = 0;
  
  	  /* If we're going to need to write this function out, and
  	     there's already a body for it, create RTL for it now.
  	     (There might be no body if this is a method we haven't
  	     gotten around to synthesizing yet.)  */
  	  if (!DECL_EXTERNAL (decl)
! 	      && decl_needed_p (decl)
  	      && !TREE_ASM_WRITTEN (decl)
! 	      && !cgraph_node (decl)->local.finalized)
  	    {
  	      /* We will output the function; no longer consider it in this
  		 loop.  */
  	      DECL_DEFER_OUTPUT (decl) = 0;
  	      /* Generate RTL for this function now that we know we
*************** finish_file (void)
*** 2805,2836 ****
  
        /* Static data members are just like namespace-scope globals.  */
        for (i = 0; i < pending_statics_used; ++i) 
  	{
  	  tree decl = VARRAY_TREE (pending_statics, i);
! 	  if (var_finalized_p (decl))
  	    continue;
  	  import_export_decl (decl);
! 	  if (DECL_NOT_REALLY_EXTERN (decl) && ! DECL_IN_AGGR_P (decl))
  	    DECL_EXTERNAL (decl) = 0;
  	}
        if (pending_statics
  	  && wrapup_global_declarations (&VARRAY_TREE (pending_statics, 0),
  					 pending_statics_used))
  	reconsider = true;
  
        if (cgraph_assemble_pending_functions ())
  	reconsider = true;
      } 
    while (reconsider);
  
    /* All used inline functions must have a definition at this point.  */
    for (i = 0; i < deferred_fns_used; ++i)
      {
        tree decl = VARRAY_TREE (deferred_fns, i);
  
!       if (!TREE_ASM_WRITTEN (decl) && !DECL_SAVED_TREE (decl)
  	  /* An explicit instantiation can be used to specify
  	     that the body is in another unit. It will have
  	     already verified there was a definition.  */
  	  && !DECL_EXPLICIT_INSTANTIATION (decl))
  	{
--- 2911,2959 ----
  
        /* Static data members are just like namespace-scope globals.  */
        for (i = 0; i < pending_statics_used; ++i) 
  	{
  	  tree decl = VARRAY_TREE (pending_statics, i);
! 	  if (var_finalized_p (decl) || DECL_REALLY_EXTERN (decl))
  	    continue;
  	  import_export_decl (decl);
! 	  /* If this static data member is needed, provide it to the
! 	     back end.  */
! 	  if (DECL_NOT_REALLY_EXTERN (decl) && decl_needed_p (decl))
  	    DECL_EXTERNAL (decl) = 0;
  	}
        if (pending_statics
  	  && wrapup_global_declarations (&VARRAY_TREE (pending_statics, 0),
  					 pending_statics_used))
  	reconsider = true;
  
+       /* Ask the back end to emit functions and variables that are
+ 	 enqued.  These emissions may result in marking more entities
+ 	 as needed.  */
        if (cgraph_assemble_pending_functions ())
  	reconsider = true;
+       if (cgraph_varpool_assemble_pending_decls ())
+ 	reconsider = true;
      } 
    while (reconsider);
  
    /* All used inline functions must have a definition at this point.  */
    for (i = 0; i < deferred_fns_used; ++i)
      {
        tree decl = VARRAY_TREE (deferred_fns, i);
  
!       if (/* Check online inline functions that were actually used.  */
! 	  TREE_USED (decl) && DECL_DECLARED_INLINE_P (decl)
! 	  /* But not defined.  */
! 	  && DECL_REALLY_EXTERN (decl)
! 	  /* If we decided to emit this function in another
! 	     translation unit, the fact that the definition was
! 	     missing here likely indicates only that the repository
! 	     decided to place the function elsewhere.  With -Winline,
! 	     we will still warn if we could not inline the
! 	     function.  */
! 	  && !flag_use_repository
  	  /* An explicit instantiation can be used to specify
  	     that the body is in another unit. It will have
  	     already verified there was a definition.  */
  	  && !DECL_EXPLICIT_INSTANTIATION (decl))
  	{
*************** finish_file (void)
*** 2838,2848 ****
  	  /* This symbol is effectively an "extern" declaration now.
  	     This is not strictly necessary, but removes a duplicate
  	     warning.  */
  	  TREE_PUBLIC (decl) = 1;
  	}
-       
      }
    
    /* We give C linkage to static constructors and destructors.  */
    push_lang_context (lang_name_c);
  
--- 2961,2970 ----
*************** finish_file (void)
*** 2869,2883 ****
  
    /* We're done with static constructors, so we can go back to "C++"
       linkage now.  */
    pop_lang_context ();
  
!   if (flag_unit_at_a_time)
!     {
!       cgraph_finalize_compilation_unit ();
!       cgraph_optimize ();
!     }
  
    /* Emit mudflap static registration function.  This must be done
       after all the user functions have been expanded.  */
    if (flag_mudflap)
      mudflap_finish_file ();
--- 2991,3002 ----
  
    /* We're done with static constructors, so we can go back to "C++"
       linkage now.  */
    pop_lang_context ();
  
!   cgraph_finalize_compilation_unit ();
!   cgraph_optimize ();
  
    /* Emit mudflap static registration function.  This must be done
       after all the user functions have been expanded.  */
    if (flag_mudflap)
      mudflap_finish_file ();
*************** mark_used (tree decl)
*** 3007,3022 ****
        && !TREE_ASM_WRITTEN (decl))
      /* Remember it, so we can check it was defined.  */
      {
        if (DECL_DEFERRED_FN (decl))
  	return;
!       DECL_DEFERRED_FN (decl) = 1;
!       DECL_DEFER_OUTPUT (decl) = 1;
!       if (!deferred_fns)
! 	VARRAY_TREE_INIT (deferred_fns, 32, "deferred_fns");
!       
!       VARRAY_PUSH_TREE (deferred_fns, decl);
      }
    
    assemble_external (decl);
  
    /* Is it a synthesized method that needs to be synthesized?  */
--- 3126,3136 ----
        && !TREE_ASM_WRITTEN (decl))
      /* Remember it, so we can check it was defined.  */
      {
        if (DECL_DEFERRED_FN (decl))
  	return;
!       note_vague_linkage_fn (decl);
      }
    
    assemble_external (decl);
  
    /* Is it a synthesized method that needs to be synthesized?  */
*************** mark_used (tree decl)
*** 3042,3083 ****
        && DECL_LANG_SPECIFIC (decl) && DECL_TEMPLATE_INFO (decl)
        && (!DECL_EXPLICIT_INSTANTIATION (decl)
  	  || (TREE_CODE (decl) == FUNCTION_DECL 
  	      && DECL_INLINE (DECL_TEMPLATE_RESULT 
  			      (template_for_substitution (decl))))))
!     {
!       bool defer;
! 
!       /* Normally, we put off instantiating functions in order to
! 	 improve compile times.  Maintaining a stack of active
! 	 functions is expensive, and the inliner knows to
! 	 instantiate any functions it might need.
! 
! 	 However, if instantiating this function might help us mark
! 	 the current function TREE_NOTHROW, we go ahead and
! 	 instantiate it now.  
! 	 
! 	 This is not needed for unit-at-a-time since we reorder the functions
! 	 in topological order anyway.
! 	 */
!       defer = (!flag_exceptions
! 	       || flag_unit_at_a_time
! 	       || !optimize
! 	       || TREE_CODE (decl) != FUNCTION_DECL
! 	       /* If the called function can't throw, we don't need to
! 		  generate its body to find that out.  */
! 	       || TREE_NOTHROW (decl)
! 	       || !cfun
! 	       || !current_function_decl
! 	       /* If we already know the current function can't throw,
! 		  then we don't need to work hard to prove it.  */
! 	       || TREE_NOTHROW (current_function_decl)
! 	       /* If we already know that the current function *can*
! 		  throw, there's no point in gathering more
! 		  information.  */
! 	       || cp_function_chain->can_throw);
! 
!       instantiate_decl (decl, defer, /*undefined_ok=*/0);
!     }
  }
  
  #include "gt-cp-decl2.h"
--- 3156,3168 ----
        && DECL_LANG_SPECIFIC (decl) && DECL_TEMPLATE_INFO (decl)
        && (!DECL_EXPLICIT_INSTANTIATION (decl)
  	  || (TREE_CODE (decl) == FUNCTION_DECL 
  	      && DECL_INLINE (DECL_TEMPLATE_RESULT 
  			      (template_for_substitution (decl))))))
!     /* We put off instantiating functions in order to improve compile
!        times.  Maintaining a stack of active functions is expensive,
!        and the inliner knows to instantiate any functions it might
!        need.  */
!     instantiate_decl (decl, /*defer_ok=*/true, /*undefined_ok=*/0);
  }
  
  #include "gt-cp-decl2.h"
Index: cp/lex.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/lex.c,v
retrieving revision 1.337
diff -c -5 -p -r1.337 lex.c
*** cp/lex.c	25 Jul 2004 17:19:38 -0000	1.337
--- cp/lex.c	29 Jul 2004 17:57:40 -0000
*************** cxx_init (void)
*** 359,377 ****
    TREE_TYPE (null_node) = c_common_type_for_size (POINTER_SIZE, 0);
    ridpointers[RID_NULL] = null_node;
  
    interface_unknown = 1;
  
    if (c_common_init () == false)
      {
        pop_srcloc();
        return false;
      }
  
    init_cp_pragma ();
  
!   init_repo (main_input_filename);
  
    pop_srcloc();
    return true;
  }
  
--- 359,388 ----
    TREE_TYPE (null_node) = c_common_type_for_size (POINTER_SIZE, 0);
    ridpointers[RID_NULL] = null_node;
  
    interface_unknown = 1;
  
+   /* The fact that G++ uses COMDAT for many entities (inline
+      functions, template instantiations, virtual tables, etc.) mean
+      that it is fundamentally unreliable to try to make decisions
+      about whether or not to output a particular entity until the end
+      of the compilation.  However, the inliner requires that functions
+      be provided to the back end if they are to be inlined.
+      Therefore, we always use unit-at-a-time mode; in that mode, we
+      can provide entities to the back end and it will decide what to
+      emit based on what is actually needed.  */
+   flag_unit_at_a_time = 1;
+ 
    if (c_common_init () == false)
      {
        pop_srcloc();
        return false;
      }
  
    init_cp_pragma ();
  
!   init_repo ();
  
    pop_srcloc();
    return true;
  }
  
Index: cp/method.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/method.c,v
retrieving revision 1.304
diff -c -5 -p -r1.304 method.c
*** cp/method.c	25 Jul 2004 22:52:18 -0000	1.304
--- cp/method.c	29 Jul 2004 17:57:40 -0000
*************** synthesize_method (tree fndecl)
*** 698,710 ****
    bool nested = (current_function_decl != NULL_TREE);
    tree context = decl_function_context (fndecl);
    bool need_body = true;
    tree stmt;
  
-   if (at_eof)
-     import_export_decl (fndecl);
- 
    /* If we've been asked to synthesize a clone, just synthesize the
       cloned function instead.  Doing so will automatically fill in the
       body for the clone.  */
    if (DECL_CLONED_FUNCTION_P (fndecl))
      {
--- 698,707 ----
*************** implicitly_declare_fn (special_function_
*** 1012,1022 ****
      }
  
    grokclassfn (type, fn, kind == sfk_destructor ? DTOR_FLAG : NO_SPECIAL,
  	       TYPE_UNQUALIFIED);
    grok_special_member_properties (fn);
!   TREE_PUBLIC (fn) = !decl_function_context (TYPE_MAIN_DECL (type));
    rest_of_decl_compilation (fn, /*asmspec=*/NULL,
  			    toplevel_bindings_p (), at_eof);
    DECL_IN_AGGR_P (fn) = 1;
    DECL_ARTIFICIAL (fn) = 1;
    DECL_NOT_REALLY_EXTERN (fn) = 1;
--- 1009,1019 ----
      }
  
    grokclassfn (type, fn, kind == sfk_destructor ? DTOR_FLAG : NO_SPECIAL,
  	       TYPE_UNQUALIFIED);
    grok_special_member_properties (fn);
!   set_linkage_according_to_type (type, fn);
    rest_of_decl_compilation (fn, /*asmspec=*/NULL,
  			    toplevel_bindings_p (), at_eof);
    DECL_IN_AGGR_P (fn) = 1;
    DECL_ARTIFICIAL (fn) = 1;
    DECL_NOT_REALLY_EXTERN (fn) = 1;
Index: cp/optimize.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/optimize.c,v
retrieving revision 1.112
diff -c -5 -p -r1.112 optimize.c
*** cp/optimize.c	25 Jul 2004 22:52:18 -0000	1.112
--- cp/optimize.c	29 Jul 2004 17:57:40 -0000
*************** maybe_clone_body (tree fn)
*** 87,99 ****
    (*debug_hooks->deferred_inline_function) (fn);
  
    /* We know that any clones immediately follow FN in the TYPE_METHODS
       list.  */
    push_to_top_level ();
!   for (clone = TREE_CHAIN (fn);
!        clone && DECL_CLONED_FUNCTION_P (clone);
!        clone = TREE_CHAIN (clone))
      {
        tree parm;
        tree clone_parm;
        int parmno;
        splay_tree decl_map;
--- 87,97 ----
    (*debug_hooks->deferred_inline_function) (fn);
  
    /* We know that any clones immediately follow FN in the TYPE_METHODS
       list.  */
    push_to_top_level ();
!   FOR_EACH_CLONE (clone, fn)
      {
        tree parm;
        tree clone_parm;
        int parmno;
        splay_tree decl_map;
Index: cp/pt.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/pt.c,v
retrieving revision 1.897
diff -c -5 -p -r1.897 pt.c
*** cp/pt.c	27 Jul 2004 23:24:07 -0000	1.897
--- cp/pt.c	29 Jul 2004 17:57:40 -0000
*************** instantiate_class_template (tree type)
*** 5691,5704 ****
    typedecl = TYPE_MAIN_DECL (type);
    input_location = DECL_SOURCE_LOCATION (typedecl);
  
    unreverse_member_declarations (type);
    finish_struct_1 (type);
- 
-   /* Clear this now so repo_template_used is happy.  */
    TYPE_BEING_DEFINED (type) = 0;
-   repo_template_used (type);
  
    /* Now that the class is complete, instantiate default arguments for
       any member functions.  We don't do this earlier because the
       default arguments may reference members of the class.  */
    if (!PRIMARY_TEMPLATE_P (template))
--- 5691,5701 ----
*************** instantiate_class_template (tree type)
*** 5713,5723 ****
    popclass ();
    pop_from_top_level ();
    pop_deferring_access_checks ();
    pop_tinst_level ();
  
!   if (TYPE_CONTAINS_VPTR_P (type))
      keyed_classes = tree_cons (NULL_TREE, type, keyed_classes);
  
    return type;
  }
  
--- 5710,5724 ----
    popclass ();
    pop_from_top_level ();
    pop_deferring_access_checks ();
    pop_tinst_level ();
  
!   /* The vtable for a template class can be emitted in any translation
!      unit in which the class is instantiated.  When there is no key
!      method, however, finish_struct_1 will already have added TYPE to
!      the keyed_classes list.  */
!   if (TYPE_CONTAINS_VPTR_P (type) && CLASSTYPE_KEY_METHOD (type))
      keyed_classes = tree_cons (NULL_TREE, type, keyed_classes);
  
    return type;
  }
  
*************** tsubst_decl (tree t, tree args, tree typ
*** 6233,6243 ****
  	DECL_RESULT (r) = NULL_TREE;
  
  	TREE_STATIC (r) = 0;
  	TREE_PUBLIC (r) = TREE_PUBLIC (t);
  	DECL_EXTERNAL (r) = 1;
! 	DECL_INTERFACE_KNOWN (r) = 0;
  	DECL_DEFER_OUTPUT (r) = 0;
  	TREE_CHAIN (r) = NULL_TREE;
  	DECL_PENDING_INLINE_INFO (r) = 0;
  	DECL_PENDING_INLINE_P (r) = 0;
  	DECL_SAVED_TREE (r) = NULL_TREE;
--- 6234,6247 ----
  	DECL_RESULT (r) = NULL_TREE;
  
  	TREE_STATIC (r) = 0;
  	TREE_PUBLIC (r) = TREE_PUBLIC (t);
  	DECL_EXTERNAL (r) = 1;
! 	/* If this is an instantiation of a function with internal
! 	   linkage, we already know what object file linkage will be
! 	   assigned to the instantiation.  */
! 	DECL_INTERFACE_KNOWN (r) = !TREE_PUBLIC (r);
  	DECL_DEFER_OUTPUT (r) = 0;
  	TREE_CHAIN (r) = NULL_TREE;
  	DECL_PENDING_INLINE_INFO (r) = 0;
  	DECL_PENDING_INLINE_P (r) = 0;
  	DECL_SAVED_TREE (r) = NULL_TREE;
*************** check_instantiated_args (tree tmpl, tree
*** 8562,8572 ****
  	  /* [basic.link]: A name with no linkage (notably, the name
  	     of a class or enumeration declared in a local scope)
  	     shall not be used to declare an entity with linkage.
  	     This implies that names with no linkage cannot be used as
  	     template arguments.  */
! 	  tree nt = no_linkage_check (t);
  
  	  if (nt)
  	    {
  	      if (!(complain & tf_error))
  		/*OK*/;
--- 8566,8576 ----
  	  /* [basic.link]: A name with no linkage (notably, the name
  	     of a class or enumeration declared in a local scope)
  	     shall not be used to declare an entity with linkage.
  	     This implies that names with no linkage cannot be used as
  	     template arguments.  */
! 	  tree nt = no_linkage_check (t, /*relaxed_p=*/false);
  
  	  if (nt)
  	    {
  	      if (!(complain & tf_error))
  		/*OK*/;
*************** instantiate_template (tree tmpl, tree ta
*** 8626,8638 ****
  				   complain);
        if (spec == error_mark_node)
  	return error_mark_node;
  
        /* Look for the clone.  */
!       for (clone = TREE_CHAIN (spec);
! 	   clone && DECL_CLONED_FUNCTION_P (clone);
! 	   clone = TREE_CHAIN (clone))
  	if (DECL_NAME (clone) == DECL_NAME (tmpl))
  	  return clone;
        /* We should always have found the clone by now.  */
        abort ();
        return NULL_TREE;
--- 8630,8640 ----
  				   complain);
        if (spec == error_mark_node)
  	return error_mark_node;
  
        /* Look for the clone.  */
!       FOR_EACH_CLONE (clone, spec)
  	if (DECL_NAME (clone) == DECL_NAME (tmpl))
  	  return clone;
        /* We should always have found the clone by now.  */
        abort ();
        return NULL_TREE;
*************** unify (tree tparms, tree targs, tree par
*** 10074,10086 ****
  
        return 1;
      }
  }
  
  /* Called if RESULT is explicitly instantiated, or is a member of an
!    explicitly instantiated class, or if using -frepo and the
!    instantiation of RESULT has been assigned to this file.  */
  
  void
  mark_decl_instantiated (tree result, int extern_p)
  {
    SET_DECL_EXPLICIT_INSTANTIATION (result);
--- 10076,10099 ----
  
        return 1;
      }
  }
  
+ /* Note that DECL can be defined in this translation unit, if
+    required.  */
+ 
+ static void
+ mark_definable (tree decl)
+ {
+   tree clone;
+   DECL_NOT_REALLY_EXTERN (decl) = 1;
+   FOR_EACH_CLONE (clone, decl)
+     DECL_NOT_REALLY_EXTERN (clone) = 1;
+ }
+ 
  /* Called if RESULT is explicitly instantiated, or is a member of an
!    explicitly instantiated class.  */
  
  void
  mark_decl_instantiated (tree result, int extern_p)
  {
    SET_DECL_EXPLICIT_INSTANTIATION (result);
*************** mark_decl_instantiated (tree result, int
*** 10096,10118 ****
      TREE_PUBLIC (result) = 1;
  
    /* This might have been set by an earlier implicit instantiation.  */
    DECL_COMDAT (result) = 0;
  
!   if (! extern_p)
      {
!       DECL_INTERFACE_KNOWN (result) = 1;
!       DECL_NOT_REALLY_EXTERN (result) = 1;
! 
        /* Always make artificials weak.  */
        if (DECL_ARTIFICIAL (result) && flag_weak)
  	comdat_linkage (result);
        /* For WIN32 we also want to put explicit instantiations in
  	 linkonce sections.  */
        else if (TREE_PUBLIC (result))
  	maybe_make_one_only (result);
      }
  }
  
  /* Given two function templates PAT1 and PAT2, return:
  
     DEDUCE should be DEDUCE_EXACT or DEDUCE_ORDER.
--- 10109,10138 ----
      TREE_PUBLIC (result) = 1;
  
    /* This might have been set by an earlier implicit instantiation.  */
    DECL_COMDAT (result) = 0;
  
!   if (extern_p)
!     DECL_NOT_REALLY_EXTERN (result) = 0;
!   else
      {
!       mark_definable (result);
        /* Always make artificials weak.  */
        if (DECL_ARTIFICIAL (result) && flag_weak)
  	comdat_linkage (result);
        /* For WIN32 we also want to put explicit instantiations in
  	 linkonce sections.  */
        else if (TREE_PUBLIC (result))
  	maybe_make_one_only (result);
      }
+   
+   /* If EXTERN_P, then this function will not be emitted -- unless
+      followed by an explicit instantiation, at which point its linkage
+      will be adjusted.  If !EXTERN_P, then this function will be
+      emitted here.  In neither circumstance do we want
+      import_export_decl to adjust the linkage.  */
+   DECL_INTERFACE_KNOWN (result) = 1; 
  }
  
  /* Given two function templates PAT1 and PAT2, return:
  
     DEDUCE should be DEDUCE_EXACT or DEDUCE_ORDER.
*************** do_decl_instantiation (tree decl, tree s
*** 10546,10564 ****
        /* [temp.spec]
  
  	 No program shall explicitly instantiate any template more
  	 than once.  
  
! 	 We check DECL_INTERFACE_KNOWN so as not to complain when the first
! 	 instantiation was `extern' and the second is not, and EXTERN_P for
! 	 the opposite case.  If -frepo, chances are we already got marked
! 	 as an explicit instantiation because of the repo file.  */
!       if (DECL_INTERFACE_KNOWN (result) && !extern_p && !flag_use_repository)
  	pedwarn ("duplicate explicit instantiation of `%#D'", result);
! 
!       /* If we've already instantiated the template, just return now.  */
!       if (DECL_INTERFACE_KNOWN (result))
  	return;
      }
    else if (!DECL_IMPLICIT_INSTANTIATION (result))
      {
        error ("no matching template for `%D' found", result);
--- 10566,10583 ----
        /* [temp.spec]
  
  	 No program shall explicitly instantiate any template more
  	 than once.  
  
! 	 We check DECL_NOT_REALLY_EXTERN so as not to complain when
! 	 the first instantiation was `extern' and the second is not,
! 	 and EXTERN_P for the opposite case.  */
!       if (DECL_NOT_REALLY_EXTERN (result) && !extern_p)
  	pedwarn ("duplicate explicit instantiation of `%#D'", result);
!       /* If an "extern" explicit instantiation follows an ordinary
! 	 explicit instantiation, the template is instantiated.  */
!       if (extern_p)
  	return;
      }
    else if (!DECL_IMPLICIT_INSTANTIATION (result))
      {
        error ("no matching template for `%D' found", result);
*************** do_decl_instantiation (tree decl, tree s
*** 10581,10591 ****
    else
      error ("storage class `%D' applied to template instantiation",
  	      storage);
  
    mark_decl_instantiated (result, extern_p);
-   repo_template_instantiated (result, extern_p);
    if (! extern_p)
      instantiate_decl (result, /*defer_ok=*/1, /*undefined_ok=*/0);
  }
  
  void
--- 10600,10609 ----
*************** bt_instantiate_type_proc (binding_entry 
*** 10619,10629 ****
     explicitly instantiated class template. */
  static void
  instantiate_class_member (tree decl, int extern_p)
  {
    mark_decl_instantiated (decl, extern_p);
-   repo_template_instantiated (decl, extern_p);
    if (! extern_p)
      instantiate_decl (decl, /*defer_ok=*/1, /* undefined_ok=*/1);
  }
  
  /* Perform an explicit instantiation of template class T.  STORAGE, if
--- 10637,10646 ----
*************** do_type_instantiation (tree t, tree stor
*** 10699,10726 ****
  	 No program shall explicitly instantiate any template more
  	 than once.  
  
           If PREVIOUS_INSTANTIATION_EXTERN_P, then the first explicit
  	 instantiation was `extern'.  If EXTERN_P then the second is.
! 	 If -frepo, chances are we already got marked as an explicit
! 	 instantiation because of the repo file.  All these cases are
! 	 OK.  */
! 
        previous_instantiation_extern_p = CLASSTYPE_INTERFACE_ONLY (t);
  
        if (!previous_instantiation_extern_p && !extern_p
- 	  && !flag_use_repository
  	  && (complain & tf_error))
  	pedwarn ("duplicate explicit instantiation of `%#T'", t);
        
        /* If we've already instantiated the template, just return now.  */
        if (!CLASSTYPE_INTERFACE_ONLY (t))
  	return;
      }
  
    mark_class_instantiated (t, extern_p);
-   repo_template_instantiated (t, extern_p);
  
    if (nomem_p)
      return;
  
    {
--- 10716,10738 ----
  	 No program shall explicitly instantiate any template more
  	 than once.  
  
           If PREVIOUS_INSTANTIATION_EXTERN_P, then the first explicit
  	 instantiation was `extern'.  If EXTERN_P then the second is.
! 	 These cases are OK.  */
        previous_instantiation_extern_p = CLASSTYPE_INTERFACE_ONLY (t);
  
        if (!previous_instantiation_extern_p && !extern_p
  	  && (complain & tf_error))
  	pedwarn ("duplicate explicit instantiation of `%#T'", t);
        
        /* If we've already instantiated the template, just return now.  */
        if (!CLASSTYPE_INTERFACE_ONLY (t))
  	return;
      }
  
    mark_class_instantiated (t, extern_p);
  
    if (nomem_p)
      return;
  
    {
*************** instantiate_decl (tree d, int defer_ok, 
*** 10999,11040 ****
  
    if (TREE_CODE (d) == FUNCTION_DECL)
      pattern_defined = (DECL_SAVED_TREE (code_pattern) != NULL_TREE);
    else
      pattern_defined = ! DECL_IN_AGGR_P (code_pattern);
  
    input_location = DECL_SOURCE_LOCATION (d);
  
!   if (pattern_defined)
      {
!       /* Let the repository code that this template definition is
! 	 available.
! 
! 	 The repository doesn't need to know about cloned functions
! 	 because they never actually show up in the object file.  It
! 	 does need to know about the clones; those are the symbols
! 	 that the linker will be emitting error messages about.  */
!       if (DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (d)
! 	  || DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (d))
! 	{
! 	  tree t;
! 
! 	  for (t = TREE_CHAIN (d);
! 	       t && DECL_CLONED_FUNCTION_P (t); 
! 	       t = TREE_CHAIN (t))
! 	    repo_template_used (t);
! 	}
!       else
! 	repo_template_used (d);
! 
!       if (at_eof)
! 	import_export_decl (d);
      }
  
-   if (! pattern_defined && DECL_EXPLICIT_INSTANTIATION (d) && undefined_ok)
-     SET_DECL_IMPLICIT_INSTANTIATION (d);
- 
    if (!defer_ok)
      {
        /* Recheck the substitutions to obtain any warning messages
  	 about ignoring cv qualifiers.  */
        tree gen = DECL_TEMPLATE_RESULT (gen_tmpl);
--- 11011,11036 ----
  
    if (TREE_CODE (d) == FUNCTION_DECL)
      pattern_defined = (DECL_SAVED_TREE (code_pattern) != NULL_TREE);
    else
      pattern_defined = ! DECL_IN_AGGR_P (code_pattern);
+   /* Unless an explicit instantiation directive has already determined
+      the linkage of D, remember that a definition is available for
+      this entity.  */
+   if (pattern_defined 
+       && !DECL_INTERFACE_KNOWN (d)
+       && !DECL_NOT_REALLY_EXTERN (d))
+     mark_definable (d);
  
    input_location = DECL_SOURCE_LOCATION (d);
  
!   if (! pattern_defined && DECL_EXPLICIT_INSTANTIATION (d) && undefined_ok)
      {
!       DECL_NOT_REALLY_EXTERN (d) = 0;
!       SET_DECL_IMPLICIT_INSTANTIATION (d);
      }
  
    if (!defer_ok)
      {
        /* Recheck the substitutions to obtain any warning messages
  	 about ignoring cv qualifiers.  */
        tree gen = DECL_TEMPLATE_RESULT (gen_tmpl);
*************** instantiate_decl (tree d, int defer_ok, 
*** 11059,11077 ****
        tsubst (type, gen_args, tf_error | tf_warning, d);
  
        pop_access_scope (d);
      }
    
!   if (TREE_CODE (d) == VAR_DECL && DECL_INITIALIZED_IN_CLASS_P (d)
!       && DECL_INITIAL (d) == NULL_TREE)
!     /* We should have set up DECL_INITIAL in instantiate_class_template.  */
!     abort ();
!   /* Reject all external templates except inline functions.  */
!   else if (DECL_INTERFACE_KNOWN (d)
! 	   && ! DECL_NOT_REALLY_EXTERN (d)
! 	   && ! (TREE_CODE (d) == FUNCTION_DECL 
! 		 && DECL_INLINE (d)))
      goto out;
    /* Defer all other templates, unless we have been explicitly
       forbidden from doing so.  We restore the source position here
       because it's used by add_pending_template.  */
    else if (! pattern_defined || defer_ok)
--- 11055,11077 ----
        tsubst (type, gen_args, tf_error | tf_warning, d);
  
        pop_access_scope (d);
      }
    
!   /* We should have set up DECL_INITIAL in instantiate_class_template
!      for in-class definitions of static data members.  */
!   my_friendly_assert (!(TREE_CODE (d) == VAR_DECL 
! 			&& DECL_INITIALIZED_IN_CLASS_P (d)
! 			&& DECL_INITIAL (d) == NULL_TREE),
! 		      20040726);
! 
!   /* Do not instantiate templates that we know will be defined
!      elsewhere.  */
!   if (DECL_INTERFACE_KNOWN (d)
!       && DECL_REALLY_EXTERN (d)
!       && ! (TREE_CODE (d) == FUNCTION_DECL 
! 	    && DECL_INLINE (d)))
      goto out;
    /* Defer all other templates, unless we have been explicitly
       forbidden from doing so.  We restore the source position here
       because it's used by add_pending_template.  */
    else if (! pattern_defined || defer_ok)
*************** instantiate_decl (tree d, int defer_ok, 
*** 11091,11100 ****
--- 11091,11116 ----
  	  ("explicit instantiation of `%D' but no definition available", d);
  
        add_pending_template (d);
        goto out;
      }
+   /* Tell the repository that D is available in this translation unit
+      -- and see if it is supposed to be instantiated here.  */
+   if (TREE_PUBLIC (d) && !DECL_REALLY_EXTERN (d) && !repo_emit_p (d))
+     {
+       /* In a PCH file, despite the fact that the repository hasn't
+ 	 requested instantiation in the PCH it is still possible that
+ 	 an instantiation will be required in a file that includes the
+ 	 PCH.  */
+       if (pch_file)
+ 	add_pending_template (d);
+       /* Instantiate inline functions so that the inliner can do its
+ 	 job, even though we'll not be emitting a copy of this
+ 	 function.  */
+       if (!flag_inline_trees || !DECL_DECLARED_INLINE_P (d))
+ 	goto out;
+     }
  
    need_push = !cfun || !global_bindings_p ();
    if (need_push)
      push_to_top_level ();
  
*************** instantiate_decl (tree d, int defer_ok, 
*** 11103,11179 ****
    DECL_TEMPLATE_INSTANTIATED (d) = 1;
  
    /* Regenerate the declaration in case the template has been modified
       by a subsequent redeclaration.  */
    regenerate_decl_from_template (d, td);
!   
    /* We already set the file and line above.  Reset them now in case
       they changed as a result of calling regenerate_decl_from_template.  */
    input_location = DECL_SOURCE_LOCATION (d);
  
    if (TREE_CODE (d) == VAR_DECL)
      {
        /* Clear out DECL_RTL; whatever was there before may not be right
  	 since we've reset the type of the declaration.  */
        SET_DECL_RTL (d, NULL_RTX);
- 
        DECL_IN_AGGR_P (d) = 0;
-       import_export_decl (d);
-       DECL_EXTERNAL (d) = ! DECL_NOT_REALLY_EXTERN (d);
- 
-       if (DECL_EXTERNAL (d))
- 	{
- 	  /* The fact that this code is executing indicates that:
- 	     
- 	     (1) D is a template static data member, for which a
- 	         definition is available.
- 
- 	     (2) An implicit or explicit instantiation has occurred.
  
! 	     (3) We are not going to emit a definition of the static
! 	         data member at this time.
! 
! 	     This situation is peculiar, but it occurs on platforms
! 	     without weak symbols when performing an implicit
! 	     instantiation.  There, we cannot implicitly instantiate a
! 	     defined static data member in more than one translation
! 	     unit, so import_export_decl marks the declaration as
! 	     external; we must rely on explicit instantiation.
! 
!              Reset instantiated marker to make sure that later
!              explicit instantiation will be processed.  */
!           DECL_TEMPLATE_INSTANTIATED (d) = 0;
! 	}
!       else
! 	{
! 	  /* This is done in analogous to `start_decl'.  It is
! 	     required for correct access checking.  */
! 	  push_nested_class (DECL_CONTEXT (d));
! 	  cp_finish_decl (d, 
! 			  (!DECL_INITIALIZED_IN_CLASS_P (d) 
! 			   ? DECL_INITIAL (d) : NULL_TREE),
! 			  NULL_TREE, 0);
! 	  /* Normally, pop_nested_class is called by cp_finish_decl
! 	     above.  But when instantiate_decl is triggered during
! 	     instantiate_class_template processing, its DECL_CONTEXT
! 	     is still not completed yet, and pop_nested_class isn't
! 	     called.  */
! 	  if (!COMPLETE_TYPE_P (DECL_CONTEXT (d)))
! 	    pop_nested_class ();
! 	}
      }
    else if (TREE_CODE (d) == FUNCTION_DECL)
      {
        htab_t saved_local_specializations;
        tree subst_decl;
        tree tmpl_parm;
        tree spec_parm;
  
-       /* Mark D as instantiated so that recursive calls to
- 	 instantiate_decl do not try to instantiate it again.  */
-       DECL_TEMPLATE_INSTANTIATED (d) = 1;
- 
        /* Save away the current list, in case we are instantiating one
  	 template from within the body of another.  */
        saved_local_specializations = local_specializations;
  
        /* Set up the list of local specializations.  */
--- 11119,11167 ----
    DECL_TEMPLATE_INSTANTIATED (d) = 1;
  
    /* Regenerate the declaration in case the template has been modified
       by a subsequent redeclaration.  */
    regenerate_decl_from_template (d, td);
! 
    /* We already set the file and line above.  Reset them now in case
       they changed as a result of calling regenerate_decl_from_template.  */
    input_location = DECL_SOURCE_LOCATION (d);
  
    if (TREE_CODE (d) == VAR_DECL)
      {
        /* Clear out DECL_RTL; whatever was there before may not be right
  	 since we've reset the type of the declaration.  */
        SET_DECL_RTL (d, NULL_RTX);
        DECL_IN_AGGR_P (d) = 0;
  
!       /* Clear DECL_EXTERNAL so that cp_finish_decl will process the
! 	 initializer.  That function will defer actual emission until
! 	 we have a chance to determine linkage.  */
!       DECL_EXTERNAL (d) = 0;
! 
!       /* This is done in analogous to `start_decl'.  It is required
! 	 for correct access checking.  */
!       push_nested_class (DECL_CONTEXT (d));
!       cp_finish_decl (d, 
! 		      (!DECL_INITIALIZED_IN_CLASS_P (d) 
! 		       ? DECL_INITIAL (d) : NULL_TREE),
! 		      NULL_TREE, 0);
!       /* Normally, pop_nested_class is called by cp_finish_decl above.
! 	 But when instantiate_decl is triggered during
! 	 instantiate_class_template processing, its DECL_CONTEXT is
! 	 still not completed yet, and pop_nested_class isn't
! 	 called.  */
!       if (!COMPLETE_TYPE_P (DECL_CONTEXT (d)))
! 	pop_nested_class ();
      }
    else if (TREE_CODE (d) == FUNCTION_DECL)
      {
        htab_t saved_local_specializations;
        tree subst_decl;
        tree tmpl_parm;
        tree spec_parm;
  
        /* Save away the current list, in case we are instantiating one
  	 template from within the body of another.  */
        saved_local_specializations = local_specializations;
  
        /* Set up the list of local specializations.  */
*************** instantiate_decl (tree d, int defer_ok, 
*** 11181,11191 ****
  					   hash_local_specialization,
  					   eq_local_specializations,
  					   NULL);
  
        /* Set up context.  */
-       import_export_decl (d);
        start_preparsed_function (d, NULL_TREE, SF_PRE_PARSED);
  
        /* Create substitution entries for the parameters.  */
        subst_decl = DECL_TEMPLATE_RESULT (template_for_substitution (d));
        tmpl_parm = DECL_ARGUMENTS (subst_decl);
--- 11169,11178 ----
Index: cp/repo.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/repo.c,v
retrieving revision 1.49
diff -c -5 -p -r1.49 repo.c
*** cp/repo.c	19 Dec 2003 23:28:09 -0000	1.49
--- cp/repo.c	29 Jul 2004 17:57:40 -0000
*************** Boston, MA 02111-1307, USA.  */
*** 35,208 ****
  #include "input.h"
  #include "obstack.h"
  #include "toplev.h"
  #include "diagnostic.h"
  
- static tree repo_get_id (tree);
  static char *extract_string (char **);
  static const char *get_base_filename (const char *);
  static void open_repo_file (const char *);
  static char *afgets (FILE *);
  static void reopen_repo_file_for_write (void);
  
  static GTY(()) tree pending_repo;
- static GTY(()) tree original_repo;
  static char *repo_name;
  static FILE *repo_file;
  
  static const char *old_args, *old_dir, *old_main;
  
  static struct obstack temporary_obstack;
! 
! #define IDENTIFIER_REPO_USED(NODE)   (TREE_LANG_FLAG_3 (NODE))
! #define IDENTIFIER_REPO_CHOSEN(NODE) (TREE_LANG_FLAG_4 (NODE))
! 
! #if 0
! /* Record the flags used to compile this translation unit.  */
! 
! void
! repo_compile_flags (int argc, char **argv)
! {
! }
! 
! /* If this template has not been seen before, add a note to the repository
!    saying where the declaration was.  This may be used to find the
!    definition at link time.  */
! 
! void
! repo_template_declared (tree t)
! {}
! 
! /* Note where the definition of a template lives so that instantiations can
!    be generated later.  */
! 
! void
! repo_template_defined (tree t)
! {}
! 
! /* Note where the definition of a class lives to that template
!    instantiations can use it.  */
! 
! void
! repo_class_defined (tree t)
! {}
! #endif
! 
! static tree
! repo_get_id (tree t)
! {
!   if (TYPE_P (t))
!     {
!       tree vtable;
! 
!       /* If we're not done setting up the class, we may not have set up
! 	 the vtable, so going ahead would give the wrong answer.
!          See g++.pt/instantiate4.C.  */
!       if (!COMPLETE_TYPE_P (t) || TYPE_BEING_DEFINED (t))
! 	abort ();
! 
!       vtable = get_vtbl_decl_for_binfo (TYPE_BINFO (t));
! 
!       t = vtable;
!       if (t == NULL_TREE)
! 	return t;
!     }
!   return DECL_ASSEMBLER_NAME (t);
! }
! 
! /* Note that a template has been used.  If we can see the definition, offer
!    to emit it.  */
! 
! void
! repo_template_used (tree t)
! {
!   tree id;
! 
!   if (! flag_use_repository)
!     return;
! 
!   id = repo_get_id (t);
!   if (id == NULL_TREE)
!     return;
!   
!   if (TYPE_P (t))
!     {
!       if (IDENTIFIER_REPO_CHOSEN (id))
! 	mark_class_instantiated (t, 0);
!     }
!   else if (DECL_P (t))
!     {
!       if (IDENTIFIER_REPO_CHOSEN (id))
! 	/* It doesn't make sense to instantiate a clone, so we
! 	   instantiate the cloned function instead.  Note that this
! 	   approach will not work correctly if collect2 assigns
! 	   different clones to different files -- but it shouldn't.  */
! 	mark_decl_instantiated (DECL_CLONED_FUNCTION_P (t)
! 				? DECL_CLONED_FUNCTION (t) : t, 
! 				0);
!     }
!   else
!     abort ();
! 
!   if (! IDENTIFIER_REPO_USED (id))
!     {
!       IDENTIFIER_REPO_USED (id) = 1;
!       pending_repo = tree_cons (NULL_TREE, id, pending_repo);
!     }
! }
! 
! #if 0
! /* Note that the vtable for a class has been used, and offer to emit it.  */
! 
! static void
! repo_vtable_used (tree t)
! {
!   if (! flag_use_repository)
!     return;
! 
!   pending_repo = tree_cons (NULL_TREE, t, pending_repo);
! }
! 
! /* Note that an inline with external linkage has been used, and offer to
!    emit it.  */
! 
! void
! repo_inline_used (tree fn)
! {
!   if (! flag_use_repository)
!     return;
! 
!   /* Member functions of polymorphic classes go with their vtables.  */
!   if (DECL_FUNCTION_MEMBER_P (fn) 
!       && TYPE_POLYMORPHIC_P (DECL_CONTEXT (fn)))
!     {
!       repo_vtable_used (DECL_CONTEXT (fn));
!       return;
!     }
! 
!   pending_repo = tree_cons (NULL_TREE, fn, pending_repo);
! }
! 
! /* Note that a particular typeinfo node has been used, and offer to
!    emit it.  */
! 
! void
! repo_tinfo_used (tree ti)
! {
! }
! #endif
! 
! void
! repo_template_instantiated (tree t, bool extern_p)
! {
!   if (! extern_p)
!     {
!       tree id = repo_get_id (t);
!       if (id)
! 	IDENTIFIER_REPO_CHOSEN (id) = 1;
!     }
! }
  
  /* Parse a reasonable subset of shell quoting syntax.  */
  
  static char *
  extract_string (char **pp)
--- 35,58 ----
  #include "input.h"
  #include "obstack.h"
  #include "toplev.h"
  #include "diagnostic.h"
  
  static char *extract_string (char **);
  static const char *get_base_filename (const char *);
  static void open_repo_file (const char *);
  static char *afgets (FILE *);
  static void reopen_repo_file_for_write (void);
  
  static GTY(()) tree pending_repo;
  static char *repo_name;
  static FILE *repo_file;
  
  static const char *old_args, *old_dir, *old_main;
  
  static struct obstack temporary_obstack;
! static bool temporary_obstack_initialized_p;
  
  /* Parse a reasonable subset of shell quoting syntax.  */
  
  static char *
  extract_string (char **pp)
*************** afgets (FILE *stream)
*** 296,315 ****
    obstack_1grow (&temporary_obstack, '\0');
    return obstack_finish (&temporary_obstack);
  }
  
  void
! init_repo (const char *filename)
  {
    char *buf;
  
    if (! flag_use_repository)
      return;
  
!   gcc_obstack_init (&temporary_obstack);
  
!   open_repo_file (filename);
  
    if (repo_file == 0)
      return;
  
    while ((buf = afgets (repo_file)))
--- 146,171 ----
    obstack_1grow (&temporary_obstack, '\0');
    return obstack_finish (&temporary_obstack);
  }
  
  void
! init_repo (void)
  {
    char *buf;
  
    if (! flag_use_repository)
      return;
  
!   /* When a PCH file is loaded, the entire identifier table is
!      replaced, with the result that IDENTIFIER_REPO_CHOSEN is cleared.
!      So, we have to reread the repository file.  */
!   lang_post_pch_load = init_repo;
  
!   if (!temporary_obstack_initialized_p)
!     gcc_obstack_init (&temporary_obstack);
! 
!   open_repo_file (main_input_filename);
  
    if (repo_file == 0)
      return;
  
    while ((buf = afgets (repo_file)))
*************** init_repo (const char *filename)
*** 323,361 ****
  	  old_dir = ggc_strdup (buf + 2);
  	  break;
  	case 'M':
  	  old_main = ggc_strdup (buf + 2);
  	  break;
- 	case 'C':
  	case 'O':
  	  {
  	    tree id = get_identifier (buf + 2);
! 	    tree orig;
! 
! 	    if (buf[0] == 'C')
! 	      {
! 		IDENTIFIER_REPO_CHOSEN (id) = 1;
! 		orig = integer_one_node;
! 	      }
! 	    else
! 	      orig = NULL_TREE;
! 
! 	    original_repo = tree_cons (orig, id, original_repo);
  	  }
  	  break;
  	default:
  	  error ("mysterious repository information in %s", repo_name);
  	}
        obstack_free (&temporary_obstack, buf);
      }
  }
  
  static void
  reopen_repo_file_for_write (void)
  {
-   if (repo_file)
-     fclose (repo_file);
    repo_file = fopen (repo_name, "w");
  
    if (repo_file == 0)
      {
        error ("can't create repository information file `%s'", repo_name);
--- 179,211 ----
  	  old_dir = ggc_strdup (buf + 2);
  	  break;
  	case 'M':
  	  old_main = ggc_strdup (buf + 2);
  	  break;
  	case 'O':
+ 	  /* A symbol that we were able to define the last time this
+ 	     file was compiled.  */
+ 	  break;
+ 	case 'C':
+ 	  /* A symbol that the prelinker has requested that we
+ 	     define.  */
  	  {
  	    tree id = get_identifier (buf + 2);
! 	    IDENTIFIER_REPO_CHOSEN (id) = 1;
  	  }
  	  break;
  	default:
  	  error ("mysterious repository information in %s", repo_name);
  	}
        obstack_free (&temporary_obstack, buf);
      }
+   fclose (repo_file);
  }
  
  static void
  reopen_repo_file_for_write (void)
  {
    repo_file = fopen (repo_name, "w");
  
    if (repo_file == 0)
      {
        error ("can't create repository information file `%s'", repo_name);
*************** reopen_repo_file_for_write (void)
*** 367,442 ****
  
  void
  finish_repo (void)
  {
    tree t;
-   bool repo_changed = false;
    char *dir, *args;
  
    if (!flag_use_repository)
      return;
  
!   /* Do we have to write out a new info file?  */
! 
!   /* Are there any old templates that aren't used any longer or that are
!      newly chosen?  */
!   
!   for (t = original_repo; t; t = TREE_CHAIN (t))
!     {
!       if (!IDENTIFIER_REPO_USED (TREE_VALUE (t))
! 	  || (!TREE_PURPOSE (t) && IDENTIFIER_REPO_CHOSEN (TREE_VALUE (t))))
! 	{
! 	  repo_changed = true;
! 	  break;
! 	}
!       IDENTIFIER_REPO_USED (TREE_VALUE (t)) = 0;
!     }
! 
!   /* Are there any templates that are newly used?  */
!   
!   if (!repo_changed)
!     for (t = pending_repo; t; t = TREE_CHAIN (t))
!       {
! 	if (IDENTIFIER_REPO_USED (TREE_VALUE (t)))
! 	  {
! 	    repo_changed = true;
! 	    break;
! 	  }
!       }
! 
!   dir = getpwd ();
!   args = getenv ("COLLECT_GCC_OPTIONS");
! 
!   if (!repo_changed && pending_repo)
!     if (strcmp (old_main, main_input_filename) != 0
! 	|| strcmp (old_dir, dir) != 0
! 	|| (args == NULL) != (old_args == NULL)
! 	|| (args && strcmp (old_args, args) != 0))
!       repo_changed = true;
! 
!   if (!repo_changed || errorcount || sorrycount)
      goto out;
  
    reopen_repo_file_for_write ();
- 
    if (repo_file == 0)
      goto out;
  
    fprintf (repo_file, "M %s\n", main_input_filename);
    fprintf (repo_file, "D %s\n", dir);
    if (args)
      fprintf (repo_file, "A %s\n", args);
  
    for (t = pending_repo; t; t = TREE_CHAIN (t))
      {
        tree val = TREE_VALUE (t);
!       char type = IDENTIFIER_REPO_CHOSEN (val) ? 'C' : 'O';
! 
!       fprintf (repo_file, "%c %s\n", type, IDENTIFIER_POINTER (val));
      }
  
   out:
    if (repo_file)
      fclose (repo_file);
  }
  
  #include "gt-cp-repo.h"
--- 217,337 ----
  
  void
  finish_repo (void)
  {
    tree t;
    char *dir, *args;
  
    if (!flag_use_repository)
      return;
  
!   if (errorcount || sorrycount)
      goto out;
  
    reopen_repo_file_for_write ();
    if (repo_file == 0)
      goto out;
  
    fprintf (repo_file, "M %s\n", main_input_filename);
+   dir = getpwd ();
    fprintf (repo_file, "D %s\n", dir);
+   args = getenv ("COLLECT_GCC_OPTIONS");
    if (args)
      fprintf (repo_file, "A %s\n", args);
  
    for (t = pending_repo; t; t = TREE_CHAIN (t))
      {
        tree val = TREE_VALUE (t);
!       tree name = DECL_ASSEMBLER_NAME (val);
!       char type = IDENTIFIER_REPO_CHOSEN (name) ? 'C' : 'O';
!       fprintf (repo_file, "%c %s\n", type, IDENTIFIER_POINTER (name));
      }
  
   out:
    if (repo_file)
      fclose (repo_file);
  }
  
+ /* DECL is a FUNCTION_DECL or VAR_DECL with vague linkage whose
+    definition is available in this translation unit.  Returns 0 if
+    this definition should not be emitted in this translation unit
+    because it will be emitted elsewhere.  Returns 1 if the repository
+    file indicates that that DECL should be emitted in this translation
+    unit, or 2 if the repository file is not in use.  */
+ 
+ int
+ repo_emit_p (tree decl)
+ {
+   my_friendly_assert (TREE_PUBLIC (decl), 20040725);
+   my_friendly_assert (TREE_CODE (decl) == FUNCTION_DECL
+ 		      || TREE_CODE (decl) == VAR_DECL,
+ 		      20040725);
+   my_friendly_assert (!DECL_REALLY_EXTERN (decl), 20040725);
+ 
+   /* When not using the repository, emit everything.  */
+   if (!flag_use_repository)
+     return 2;
+ 
+   /* Only template instantiations are managed by the repository.  This
+      is an artificial restriction; the code in the prelinker and here
+      will work fine if all entities with vague linkage are managed by
+      the repository.  */
+   if (TREE_CODE (decl) == VAR_DECL)
+     {
+       tree type = NULL_TREE;
+       if (DECL_VTABLE_OR_VTT_P (decl))
+ 	type = DECL_CONTEXT (decl);
+       else if (DECL_TINFO_P (decl))
+ 	type = TREE_TYPE (DECL_NAME (decl));
+       if (!DECL_TEMPLATE_INSTANTIATION (decl)
+ 	  && !CLASSTYPE_TEMPLATE_INSTANTIATION (type))
+ 	return 2;
+     }
+   else if (!DECL_TEMPLATE_INSTANTIATION (decl))
+     return 2;
+ 
+   /* For constructors and destructors, the repository contains
+      information about the clones -- not the original function --
+      because only the clones are emitted in the object file.  */
+   if (DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (decl)
+       || DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (decl))
+     {
+       int emit_p = 0;
+       tree clone;
+       /* There is no early exit from this loop because we want to
+ 	 ensure that all of the clones are marked as available in this
+ 	 object file.  */
+       FOR_EACH_CLONE (clone, decl)
+ 	/* The only possible results from the recursive call to
+ 	   repo_emit_p are 0 or 1.  */
+ 	if (repo_emit_p (clone))
+ 	  emit_p = 1;
+       return emit_p;
+     }
+ 
+   /* Keep track of all available entities.  */
+   if (!DECL_REPO_AVAILABLE_P (decl))
+     {
+       DECL_REPO_AVAILABLE_P (decl) = 1;
+       pending_repo = tree_cons (NULL_TREE, decl, pending_repo);
+     }
+ 
+   return IDENTIFIER_REPO_CHOSEN (DECL_ASSEMBLER_NAME (decl));
+ }
+ 
+ /* Returns true iff the prelinker has explicitly marked CLASS_TYPE for
+    export from this translation unit.  */
+ 
+ bool
+ repo_export_class_p (tree class_type)
+ {
+   if (!flag_use_repository)
+     return false;
+   if (!CLASSTYPE_VTABLES (class_type))
+     return false;
+   /* If the virtual table has been assigned to this translation unit,
+      export the class.  */
+   return (IDENTIFIER_REPO_CHOSEN 
+ 	  (DECL_ASSEMBLER_NAME (CLASSTYPE_VTABLES (class_type))));
+ }
+ 
  #include "gt-cp-repo.h"
Index: cp/rtti.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/rtti.c,v
retrieving revision 1.192
diff -c -5 -p -r1.192 rtti.c
*** cp/rtti.c	26 Jul 2004 08:23:58 -0000	1.192
--- cp/rtti.c	29 Jul 2004 17:57:40 -0000
*************** static tree get_tinfo_ptr (tree);
*** 87,108 ****
  static bool typeid_ok_p (void);
  static int qualifier_flags (tree);
  static bool target_incomplete_p (tree);
  static tree tinfo_base_init (tree, tree);
  static tree generic_initializer (tree, tree);
- static tree ptr_initializer (tree, tree, bool *);
- static tree ptm_initializer (tree, tree, bool *);
  static tree dfs_class_hint_mark (tree, void *);
  static tree dfs_class_hint_unmark (tree, void *);
  static int class_hint_flags (tree);
  static tree class_initializer (tree, tree, tree);
  static tree create_pseudo_type_info (const char *, int, ...);
! static tree get_pseudo_ti_init (tree, tree, bool *);
  static tree get_pseudo_ti_desc (tree);
  static void create_tinfo_types (void);
  static bool typeinfo_in_lib_p (tree);
- static bool unemitted_tinfo_decl_p (tree);
  
  static int doing_runtime = 0;
  
  
  /* Declare language defined type_info type and a pointer to const
--- 87,105 ----
  static bool typeid_ok_p (void);
  static int qualifier_flags (tree);
  static bool target_incomplete_p (tree);
  static tree tinfo_base_init (tree, tree);
  static tree generic_initializer (tree, tree);
  static tree dfs_class_hint_mark (tree, void *);
  static tree dfs_class_hint_unmark (tree, void *);
  static int class_hint_flags (tree);
  static tree class_initializer (tree, tree, tree);
  static tree create_pseudo_type_info (const char *, int, ...);
! static tree get_pseudo_ti_init (tree, tree);
  static tree get_pseudo_ti_desc (tree);
  static void create_tinfo_types (void);
  static bool typeinfo_in_lib_p (tree);
  
  static int doing_runtime = 0;
  
  
  /* Declare language defined type_info type and a pointer to const
*************** get_tinfo_decl (tree type)
*** 346,363 ****
    if (!d)
      {
        tree var_desc = get_pseudo_ti_desc (type);
  
        d = build_lang_decl (VAR_DECL, name, TINFO_PSEUDO_TYPE (var_desc));
!       
        DECL_ARTIFICIAL (d) = 1;
        TREE_READONLY (d) = 1;
        TREE_STATIC (d) = 1;
        DECL_EXTERNAL (d) = 1;
!       DECL_COMDAT (d) = 1;
!       TREE_PUBLIC (d) = 1;
!       SET_DECL_ASSEMBLER_NAME (d, name);
  
        pushdecl_top_level_and_finish (d, NULL_TREE);
  
        if (CLASS_TYPE_P (type))
  	{
--- 343,362 ----
    if (!d)
      {
        tree var_desc = get_pseudo_ti_desc (type);
  
        d = build_lang_decl (VAR_DECL, name, TINFO_PSEUDO_TYPE (var_desc));
!       SET_DECL_ASSEMBLER_NAME (d, name);
!       DECL_TINFO_P (d) = 1;
        DECL_ARTIFICIAL (d) = 1;
        TREE_READONLY (d) = 1;
        TREE_STATIC (d) = 1;
+       /* Mark the variable as undefined -- but remember that we can
+ 	 define it later if we need to do so.  */
        DECL_EXTERNAL (d) = 1;
!       DECL_NOT_REALLY_EXTERN (d) = 1;
!       set_linkage_according_to_type (type, d);
  
        pushdecl_top_level_and_finish (d, NULL_TREE);
  
        if (CLASS_TYPE_P (type))
  	{
*************** target_incomplete_p (tree type)
*** 730,739 ****
--- 729,770 ----
        type = TREE_TYPE (type);
      else
        return !COMPLETE_OR_VOID_TYPE_P (type);
  }
  
+ /* Returns true if TYPE involves an incomplete class type; in that
+    case, typeinfo variables for TYPE should be emitted with internal
+    linkage.  */
+ 
+ static bool
+ involves_incomplete_p (tree type)
+ {
+   switch (TREE_CODE (type))
+     {
+     case POINTER_TYPE:
+       return target_incomplete_p (TREE_TYPE (type));
+ 
+     case OFFSET_TYPE:
+     ptrmem:
+       return 
+ 	(target_incomplete_p (TYPE_PTRMEM_POINTED_TO_TYPE (type))
+ 	 || !COMPLETE_TYPE_P (TYPE_PTRMEM_CLASS_TYPE (type)));
+ 
+     case RECORD_TYPE:
+       if (TYPE_PTRMEMFUNC_P (type))
+ 	goto ptrmem;
+       /* Fall through.  */
+     case UNION_TYPE:
+       if (!COMPLETE_TYPE_P (type))
+ 	return true;
+ 
+     default:
+       /* All other types do not involve incomplete class types.  */
+       return false;
+     }
+ }
+ 
  /* Return a CONSTRUCTOR for the common part of the type_info objects. This
     is the vtable pointer and NTBS name.  The NTBS name is emitted as a
     comdat const char array, so it becomes a unique key for the type. Generate
     and emit that VAR_DECL here.  (We can't always emit the type_info itself
     as comdat, because of pointers to incomplete.) */
*************** tinfo_base_init (tree desc, tree target)
*** 752,775 ****
      tree name_type = build_cplus_array_type
                       (build_qualified_type (char_type_node, TYPE_QUAL_CONST),
                       NULL_TREE);
      tree name_string = tinfo_name (target);
  
      name_name = mangle_typeinfo_string_for_type (target);
      name_decl = build_lang_decl (VAR_DECL, name_name, name_type);
      
      DECL_ARTIFICIAL (name_decl) = 1;
      TREE_READONLY (name_decl) = 1;
      TREE_STATIC (name_decl) = 1;
      DECL_EXTERNAL (name_decl) = 0;
!     TREE_PUBLIC (name_decl) = 1;
      if (CLASS_TYPE_P (target))
        {
          DECL_VISIBILITY (name_decl) = CLASSTYPE_VISIBILITY (target);
!         DECL_VISIBILITY_SPECIFIED (name_decl) = CLASSTYPE_VISIBILITY_SPECIFIED (target);
        }
!     import_export_tinfo (name_decl, target, typeinfo_in_lib_p (target));
      /* External name of the string containing the type's name has a
         special name.  */
      SET_DECL_ASSEMBLER_NAME (name_decl,
  			     mangle_typeinfo_string_for_type (target));
      DECL_INITIAL (name_decl) = name_string;
--- 783,818 ----
      tree name_type = build_cplus_array_type
                       (build_qualified_type (char_type_node, TYPE_QUAL_CONST),
                       NULL_TREE);
      tree name_string = tinfo_name (target);
  
+     /* Determine the name of the variable -- and remember with which
+        type it is associated.  */
      name_name = mangle_typeinfo_string_for_type (target);
+     TREE_TYPE (name_name) = target;
+ 
      name_decl = build_lang_decl (VAR_DECL, name_name, name_type);
      
      DECL_ARTIFICIAL (name_decl) = 1;
      TREE_READONLY (name_decl) = 1;
      TREE_STATIC (name_decl) = 1;
      DECL_EXTERNAL (name_decl) = 0;
!     DECL_TINFO_P (name_decl) = 1;
      if (CLASS_TYPE_P (target))
        {
          DECL_VISIBILITY (name_decl) = CLASSTYPE_VISIBILITY (target);
!         DECL_VISIBILITY_SPECIFIED (name_decl) 
! 	  = CLASSTYPE_VISIBILITY_SPECIFIED (target);
!       }
!     if (involves_incomplete_p (target))
!       {
! 	TREE_PUBLIC (name_decl) = 0;
! 	DECL_INTERFACE_KNOWN (name_decl) = 1;
        }
!     else
!       set_linkage_according_to_type (target, name_decl);
!     import_export_decl (name_decl);
      /* External name of the string containing the type's name has a
         special name.  */
      SET_DECL_ASSEMBLER_NAME (name_decl,
  			     mangle_typeinfo_string_for_type (target));
      DECL_INITIAL (name_decl) = name_string;
*************** generic_initializer (tree desc, tree tar
*** 841,862 ****
  /* Return the CONSTRUCTOR expr for a type_info of pointer TYPE.
     DESC provides information about the particular type_info derivation,
     which adds target type and qualifier flags members to the type_info base.  */
  
  static tree
! ptr_initializer (tree desc, tree target, bool *non_public_ptr)
  {
    tree init = tinfo_base_init (desc, target);
    tree to = TREE_TYPE (target);
    int flags = qualifier_flags (to);
    bool incomplete = target_incomplete_p (to);
    
    if (incomplete)
!     {
!       flags |= 8;
!       *non_public_ptr = true;
!     }
    init = tree_cons (NULL_TREE, build_int_2 (flags, 0), init);
    init = tree_cons (NULL_TREE,
                      get_tinfo_ptr (TYPE_MAIN_VARIANT (to)),
                      init);
    
--- 884,902 ----
  /* Return the CONSTRUCTOR expr for a type_info of pointer TYPE.
     DESC provides information about the particular type_info derivation,
     which adds target type and qualifier flags members to the type_info base.  */
  
  static tree
! ptr_initializer (tree desc, tree target)
  {
    tree init = tinfo_base_init (desc, target);
    tree to = TREE_TYPE (target);
    int flags = qualifier_flags (to);
    bool incomplete = target_incomplete_p (to);
    
    if (incomplete)
!     flags |= 8;
    init = tree_cons (NULL_TREE, build_int_2 (flags, 0), init);
    init = tree_cons (NULL_TREE,
                      get_tinfo_ptr (TYPE_MAIN_VARIANT (to)),
                      init);
    
*************** ptr_initializer (tree desc, tree target,
*** 871,898 ****
     DESC provides information about the particular type_info derivation,
     which adds class, target type and qualifier flags members to the type_info
     base.  */
  
  static tree
! ptm_initializer (tree desc, tree target, bool *non_public_ptr)
  {
    tree init = tinfo_base_init (desc, target);
    tree to = TYPE_PTRMEM_POINTED_TO_TYPE (target);
    tree klass = TYPE_PTRMEM_CLASS_TYPE (target);
    int flags = qualifier_flags (to);
    bool incomplete = target_incomplete_p (to);
    
    if (incomplete)
!     {
!       flags |= 0x8;
!       *non_public_ptr = true;
!     }
    if (!COMPLETE_TYPE_P (klass))
!     {
!       flags |= 0x10;
!       *non_public_ptr = true;
!     }
    init = tree_cons (NULL_TREE, build_int_2 (flags, 0), init);
    init = tree_cons (NULL_TREE,
  		    get_tinfo_ptr (TYPE_MAIN_VARIANT (to)),
                      init);
    init = tree_cons (NULL_TREE,
--- 911,932 ----
     DESC provides information about the particular type_info derivation,
     which adds class, target type and qualifier flags members to the type_info
     base.  */
  
  static tree
! ptm_initializer (tree desc, tree target)
  {
    tree init = tinfo_base_init (desc, target);
    tree to = TYPE_PTRMEM_POINTED_TO_TYPE (target);
    tree klass = TYPE_PTRMEM_CLASS_TYPE (target);
    int flags = qualifier_flags (to);
    bool incomplete = target_incomplete_p (to);
    
    if (incomplete)
!     flags |= 0x8;
    if (!COMPLETE_TYPE_P (klass))
!     flags |= 0x10;
    init = tree_cons (NULL_TREE, build_int_2 (flags, 0), init);
    init = tree_cons (NULL_TREE,
  		    get_tinfo_ptr (TYPE_MAIN_VARIANT (to)),
                      init);
    init = tree_cons (NULL_TREE,
*************** typeinfo_in_lib_p (tree type)
*** 1001,1026 ****
      default:
        return false;
      }
  }
  
! /* Generate the initializer for the type info describing
!    TYPE. VAR_DESC is a . NON_PUBLIC_P is set nonzero, if the VAR_DECL
!    should not be exported from this object file.  This should only be
!    called at the end of translation, when we know that no further
!    types will be completed.  */
  
  static tree
! get_pseudo_ti_init (tree type, tree var_desc, bool *non_public_p)
  {
    my_friendly_assert (at_eof, 20021120);
    switch (TREE_CODE (type))
      {
      case OFFSET_TYPE:
!       return ptm_initializer (var_desc, type, non_public_p);
      case POINTER_TYPE:
!       return ptr_initializer (var_desc, type, non_public_p);
      case ENUMERAL_TYPE:
        return generic_initializer (var_desc, type);
        break;
      case FUNCTION_TYPE:
        return generic_initializer (var_desc, type);
--- 1035,1056 ----
      default:
        return false;
      }
  }
  
! /* Generate the initializer for the type info describing TYPE.  */
  
  static tree
! get_pseudo_ti_init (tree type, tree var_desc)
  {
    my_friendly_assert (at_eof, 20021120);
    switch (TREE_CODE (type))
      {
      case OFFSET_TYPE:
!       return ptm_initializer (var_desc, type);
      case POINTER_TYPE:
!       return ptr_initializer (var_desc, type);
      case ENUMERAL_TYPE:
        return generic_initializer (var_desc, type);
        break;
      case FUNCTION_TYPE:
        return generic_initializer (var_desc, type);
*************** get_pseudo_ti_init (tree type, tree var_
*** 1029,1046 ****
        return generic_initializer (var_desc, type);
        break;
      case UNION_TYPE:
      case RECORD_TYPE:
        if (TYPE_PTRMEMFUNC_P (type))
! 	return ptm_initializer (var_desc, type, non_public_p);
        else if (var_desc == class_desc_type_node)
!         {
! 	  if (!COMPLETE_TYPE_P (type))
! 	    /* Emit a non-public class_type_info.  */
! 	    *non_public_p = true;
! 	  return class_initializer (var_desc, type, NULL_TREE);
!         }
        else if (var_desc == si_class_desc_type_node)
  	{
            tree base_binfo = BINFO_BASE_BINFO (TYPE_BINFO (type), 0);
  	  tree tinfo = get_tinfo_ptr (BINFO_TYPE (base_binfo));
  	  tree base_inits = tree_cons (NULL_TREE, tinfo, NULL_TREE);
--- 1059,1071 ----
        return generic_initializer (var_desc, type);
        break;
      case UNION_TYPE:
      case RECORD_TYPE:
        if (TYPE_PTRMEMFUNC_P (type))
! 	return ptm_initializer (var_desc, type);
        else if (var_desc == class_desc_type_node)
! 	return class_initializer (var_desc, type, NULL_TREE);
        else if (var_desc == si_class_desc_type_node)
  	{
            tree base_binfo = BINFO_BASE_BINFO (TYPE_BINFO (type), 0);
  	  tree tinfo = get_tinfo_ptr (BINFO_TYPE (base_binfo));
  	  tree base_inits = tree_cons (NULL_TREE, tinfo, NULL_TREE);
*************** emit_support_tinfos (void)
*** 1412,1480 ****
        TREE_USED (tinfo) = 1;
        TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (tinfo)) = 1;
      }
  }
  
- /* Return true, iff T is a type_info variable which has not had a
-    definition emitted for it.  */
- 
- static bool
- unemitted_tinfo_decl_p (tree t)
- {
-   if (/* It's a var decl */
-       TREE_CODE (t) == VAR_DECL
-       /* which has a name */
-       && DECL_NAME (t)
-       /* whose name points back to itself */
-       && IDENTIFIER_GLOBAL_VALUE (DECL_NAME (t)) == t
-       /* whose name's type is non-null */
-       && TREE_TYPE (DECL_NAME (t))
-       /* and whose type is a struct */
-       && TREE_CODE (TREE_TYPE (t)) == RECORD_TYPE
-       /* with a field */
-       && TYPE_FIELDS (TREE_TYPE (t))
-       /* which is our pseudo type info */
-       && TREE_TYPE (TYPE_FIELDS (TREE_TYPE (t))) == ti_desc_type_node)
-     return true;
-   return false;
- }
- 
  /* Finish a type info decl. DECL_PTR is a pointer to an unemitted
     tinfo decl.  Determine whether it needs emitting, and if so
     generate the initializer.  */
  
  bool
  emit_tinfo_decl (tree decl)
  {
    tree type = TREE_TYPE (DECL_NAME (decl));
-   bool non_public;
    int in_library = typeinfo_in_lib_p (type);
    tree var_desc, var_init;
  
!   my_friendly_assert (unemitted_tinfo_decl_p (decl), 20030307); 
    
!   import_export_tinfo (decl, type, in_library);
!   if (DECL_REALLY_EXTERN (decl) || !DECL_NEEDED_P (decl))
!     return false;
! 
!   if (!doing_runtime && in_library)
      return false;
- 
-   non_public = false;
-   var_desc = get_pseudo_ti_desc (type);
-   var_init = get_pseudo_ti_init (type, var_desc, &non_public);
-   
-   DECL_EXTERNAL (decl) = 0;
-   TREE_PUBLIC (decl) = !non_public;
-   if (non_public)
-     DECL_COMDAT (decl) = 0;
- 
-   DECL_INITIAL (decl) = var_init;
-   mark_used (decl);
-   cp_finish_decl (decl, var_init, NULL_TREE, 0);
-   /* cp_finish_decl will have dealt with linkage.  */
-   
-   /* Say we've dealt with it.  */
-   TREE_TYPE (DECL_NAME (decl)) = NULL_TREE;
- 
-   return true;
  }
--- 1437,1494 ----
        TREE_USED (tinfo) = 1;
        TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (tinfo)) = 1;
      }
  }
  
  /* Finish a type info decl. DECL_PTR is a pointer to an unemitted
     tinfo decl.  Determine whether it needs emitting, and if so
     generate the initializer.  */
  
  bool
  emit_tinfo_decl (tree decl)
  {
    tree type = TREE_TYPE (DECL_NAME (decl));
    int in_library = typeinfo_in_lib_p (type);
    tree var_desc, var_init;
  
!   my_friendly_assert (DECL_TINFO_P (decl), 20030307); 
    
!   if (in_library)
!     {
!       if (doing_runtime)
! 	DECL_EXTERNAL (decl) = 0;
!       else
! 	{
! 	  /* If we're not in the runtime, then DECL (which is already
! 	     DECL_EXTERNAL) will not be defined here.  */
! 	  DECL_INTERFACE_KNOWN (decl) = 1;
! 	  return false;
! 	}
!     }
!   else if (involves_incomplete_p (type))
!     {
!       if (!decl_needed_p (decl))
! 	return false;
!       /* If TYPE involves an incomplete class type, then the typeinfo
! 	 object will be emitted with internal linkage.  There is no
! 	 way to know whether or not types are incomplete until the end
! 	 of the compilation, so this determination must be deferred
! 	 until this point.  */
!       TREE_PUBLIC (decl) = 0;
!       DECL_EXTERNAL (decl) = 0;
!       DECL_INTERFACE_KNOWN (decl) = 1;
!     }
! 
!   import_export_decl (decl);
!   if (DECL_NOT_REALLY_EXTERN (decl) && decl_needed_p (decl))
!     {
!       DECL_EXTERNAL (decl) = 0;
!       var_desc = get_pseudo_ti_desc (type);
!       var_init = get_pseudo_ti_init (type, var_desc);
!       DECL_INITIAL (decl) = var_init;
!       mark_used (decl);
!       cp_finish_decl (decl, var_init, NULL_TREE, 0);
!       return true;
!     }
!   else
      return false;
  }
Index: cp/semantics.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/semantics.c,v
retrieving revision 1.419
diff -c -5 -p -r1.419 semantics.c
*** cp/semantics.c	25 Jul 2004 08:10:27 -0000	1.419
--- cp/semantics.c	29 Jul 2004 17:57:40 -0000
*************** expand_body (tree fn)
*** 2890,2911 ****
  
    current_function_decl = saved_function;
  
    extract_interface_info ();
  
-   /* If this function is marked with the constructor attribute, add it
-      to the list of functions to be called along with constructors
-      from static duration objects.  */
-   if (DECL_STATIC_CONSTRUCTOR (fn))
-     static_ctors = tree_cons (NULL_TREE, fn, static_ctors);
- 
-   /* If this function is marked with the destructor attribute, add it
-      to the list of functions to be called along with destructors from
-      static duration objects.  */
-   if (DECL_STATIC_DESTRUCTOR (fn))
-     static_dtors = tree_cons (NULL_TREE, fn, static_dtors);
- 
    if (DECL_CLONED_FUNCTION_P (fn))
      {
        /* If this is a clone, go through the other clones now and mark
           their parameters used.  We have to do that here, as we don't
           know whether any particular clone will be expanded, and
--- 2890,2899 ----
*************** expand_or_defer_fn (tree fn)
*** 2955,2973 ****
  	 it out, even though we haven't.  */
        TREE_ASM_WRITTEN (fn) = 1;
        return;
      }
  
    /* There's no reason to do any of the work here if we're only doing
       semantic analysis; this code just generates RTL.  */
    if (flag_syntax_only)
      return;
  
-   /* Compute the appropriate object-file linkage for inline functions.  */
-   if (DECL_DECLARED_INLINE_P (fn))
-     import_export_decl (fn);
- 
    function_depth++;
  
    /* Expand or defer, at the whim of the compilation unit manager.  */
    cgraph_finalize_function (fn, function_depth > 1);
  
--- 2943,2985 ----
  	 it out, even though we haven't.  */
        TREE_ASM_WRITTEN (fn) = 1;
        return;
      }
  
+   /* If this function is marked with the constructor attribute, add it
+      to the list of functions to be called along with constructors
+      from static duration objects.  */
+   if (DECL_STATIC_CONSTRUCTOR (fn))
+     static_ctors = tree_cons (NULL_TREE, fn, static_ctors);
+ 
+   /* If this function is marked with the destructor attribute, add it
+      to the list of functions to be called along with destructors from
+      static duration objects.  */
+   if (DECL_STATIC_DESTRUCTOR (fn))
+     static_dtors = tree_cons (NULL_TREE, fn, static_dtors);
+ 
+   /* We make a decision about linkage for these functions at the end
+      of the compilation.  Until that point, we do not want the back
+      end to output them -- but we do want it to see the bodies of
+      these fucntions so that it can inline them as appropriate.  */
+   if (DECL_DECLARED_INLINE_P (fn) || DECL_IMPLICIT_INSTANTIATION (fn))
+     {
+       if (!at_eof)
+ 	{
+ 	  DECL_EXTERNAL (fn) = 1;
+ 	  DECL_NOT_REALLY_EXTERN (fn) = 1;
+ 	  note_vague_linkage_fn (fn);
+ 	}
+       else
+ 	import_export_decl (fn);
+     }
+ 
    /* There's no reason to do any of the work here if we're only doing
       semantic analysis; this code just generates RTL.  */
    if (flag_syntax_only)
      return;
  
    function_depth++;
  
    /* Expand or defer, at the whim of the compilation unit manager.  */
    cgraph_finalize_function (fn, function_depth > 1);
  
Index: cp/tree.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/tree.c,v
retrieving revision 1.398
diff -c -5 -p -r1.398 tree.c
*** cp/tree.c	28 Jul 2004 23:44:52 -0000	1.398
--- cp/tree.c	29 Jul 2004 17:57:40 -0000
*************** find_tree (tree t, tree x)
*** 1060,1126 ****
  {
    return walk_tree_without_duplicates (&t, find_tree_r, x);
  }
  
  /* Check if the type T depends on a type with no linkage and if so, return
!    it.  */
  
  tree
! no_linkage_check (tree t)
  {
    tree r;
  
    /* There's no point in checking linkage on template functions; we
       can't know their complete types.  */
    if (processing_template_decl)
      return NULL_TREE;
  
    switch (TREE_CODE (t))
      {
      case RECORD_TYPE:
        if (TYPE_PTRMEMFUNC_P (t))
  	goto ptrmem;
        /* Fall through.  */
      case UNION_TYPE:
        if (!CLASS_TYPE_P (t))
  	return NULL_TREE;
        /* Fall through.  */
      case ENUMERAL_TYPE:
!       if (decl_function_context (TYPE_MAIN_DECL (t))
! 	  || TYPE_ANONYMOUS_P (t))
  	return t;
        return NULL_TREE;
  
      case ARRAY_TYPE:
      case POINTER_TYPE:
      case REFERENCE_TYPE:
!       return no_linkage_check (TREE_TYPE (t));
  
      case OFFSET_TYPE:
      ptrmem:
!       r = no_linkage_check (TYPE_PTRMEM_POINTED_TO_TYPE (t));
        if (r)
  	return r;
!       return no_linkage_check (TYPE_PTRMEM_CLASS_TYPE (t));
  
      case METHOD_TYPE:
!       r = no_linkage_check (TYPE_METHOD_BASETYPE (t));
        if (r)
  	return r;
        /* Fall through.  */
      case FUNCTION_TYPE:
        {
  	tree parm;
  	for (parm = TYPE_ARG_TYPES (t);
  	     parm && parm != void_list_node;
  	     parm = TREE_CHAIN (parm))
  	  {
! 	    r = no_linkage_check (TREE_VALUE (parm));
  	    if (r)
  	      return r;
  	  }
! 	return no_linkage_check (TREE_TYPE (t));
        }
  
      default:
        return NULL_TREE;
      }
--- 1060,1132 ----
  {
    return walk_tree_without_duplicates (&t, find_tree_r, x);
  }
  
  /* Check if the type T depends on a type with no linkage and if so, return
!    it.  If RELAXED_P then do not consider a class type declared within
!    a TREE_PUBLIC function to have no linkage.  */
  
  tree
! no_linkage_check (tree t, bool relaxed_p)
  {
    tree r;
  
    /* There's no point in checking linkage on template functions; we
       can't know their complete types.  */
    if (processing_template_decl)
      return NULL_TREE;
  
    switch (TREE_CODE (t))
      {
+       tree fn;
+ 
      case RECORD_TYPE:
        if (TYPE_PTRMEMFUNC_P (t))
  	goto ptrmem;
        /* Fall through.  */
      case UNION_TYPE:
        if (!CLASS_TYPE_P (t))
  	return NULL_TREE;
        /* Fall through.  */
      case ENUMERAL_TYPE:
!       if (TYPE_ANONYMOUS_P (t))
! 	return t;
!       fn = decl_function_context (TYPE_MAIN_DECL (t));
!       if (fn && (!relaxed_p || !TREE_PUBLIC (fn)))
  	return t;
        return NULL_TREE;
  
      case ARRAY_TYPE:
      case POINTER_TYPE:
      case REFERENCE_TYPE:
!       return no_linkage_check (TREE_TYPE (t), relaxed_p);
  
      case OFFSET_TYPE:
      ptrmem:
!       r = no_linkage_check (TYPE_PTRMEM_POINTED_TO_TYPE (t),
! 			    relaxed_p);
        if (r)
  	return r;
!       return no_linkage_check (TYPE_PTRMEM_CLASS_TYPE (t), relaxed_p);
  
      case METHOD_TYPE:
!       r = no_linkage_check (TYPE_METHOD_BASETYPE (t), relaxed_p);
        if (r)
  	return r;
        /* Fall through.  */
      case FUNCTION_TYPE:
        {
  	tree parm;
  	for (parm = TYPE_ARG_TYPES (t);
  	     parm && parm != void_list_node;
  	     parm = TREE_CHAIN (parm))
  	  {
! 	    r = no_linkage_check (TREE_VALUE (parm), relaxed_p);
  	    if (r)
  	      return r;
  	  }
! 	return no_linkage_check (TREE_TYPE (t), relaxed_p);
        }
  
      default:
        return NULL_TREE;
      }
Index: testsuite/g++.dg/abi/inline1.C
===================================================================
RCS file: testsuite/g++.dg/abi/inline1.C
diff -N testsuite/g++.dg/abi/inline1.C
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- testsuite/g++.dg/abi/inline1.C	29 Jul 2004 17:57:40 -0000
***************
*** 0 ****
--- 1,6 ----
+ struct S {
+   S() {}
+   virtual void g() {}
+ };
+ 
+ // { dg-final { scan-assembler-not "_ZTV1S" } }
Index: testsuite/g++.dg/abi/local1-a.cc
===================================================================
RCS file: testsuite/g++.dg/abi/local1-a.cc
diff -N testsuite/g++.dg/abi/local1-a.cc
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- testsuite/g++.dg/abi/local1-a.cc	29 Jul 2004 17:57:40 -0000
***************
*** 0 ****
--- 1,14 ----
+ struct B {
+   virtual void b() {}
+ };
+ 
+ static B* f() {
+   struct D : public B {
+   };
+ 
+   return new D;
+ }
+ 
+ B* g() {
+   return f();
+ }
Index: testsuite/g++.dg/abi/local1.C
===================================================================
RCS file: testsuite/g++.dg/abi/local1.C
diff -N testsuite/g++.dg/abi/local1.C
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- testsuite/g++.dg/abi/local1.C	29 Jul 2004 17:57:40 -0000
***************
*** 0 ****
--- 1,22 ----
+ // { dg-do run }
+ // { dg-additional-sources "local1-a.cc" }
+ 
+ #include <typeinfo>
+ 
+ struct B {
+   virtual void b() {}
+ };
+ 
+ static B* f() {
+   struct D : public B {
+   };
+ 
+   return new D;
+ }
+ 
+ extern B* g();
+ 
+ int main () {
+   if (typeid (*f()) == typeid (*g()))
+     return 1;
+ }
Index: testsuite/g++.dg/abi/mangle11.C
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/g++.dg/abi/mangle11.C,v
retrieving revision 1.2
diff -c -5 -p -r1.2 mangle11.C
*** testsuite/g++.dg/abi/mangle11.C	23 Dec 2003 16:53:52 -0000	1.2
--- testsuite/g++.dg/abi/mangle11.C	29 Jul 2004 17:57:40 -0000
***************
*** 1,10 ****
  // { dg-options "-Wabi -fabi-version=1" }
  
  template <typename Q>
! void f (typename Q::X) {}
  
  struct S {
    typedef int X;
  };
  
! template void f<S> (int); // { dg-warning "mangle" }
--- 1,10 ----
  // { dg-options "-Wabi -fabi-version=1" }
  
  template <typename Q>
! void f (typename Q::X) {} // { dg-warning "mangle" }
  
  struct S {
    typedef int X;
  };
  
! template void f<S> (int);
Index: testsuite/g++.dg/abi/mangle12.C
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/g++.dg/abi/mangle12.C,v
retrieving revision 1.2
diff -c -5 -p -r1.2 mangle12.C
*** testsuite/g++.dg/abi/mangle12.C	23 Dec 2003 16:53:52 -0000	1.2
--- testsuite/g++.dg/abi/mangle12.C	29 Jul 2004 17:57:40 -0000
***************
*** 1,11 ****
  // { dg-options "-Wabi -fabi-version=1" }
  
  template <template <typename> class Q>
! void f (typename Q<int>::X) {}
  
  template <typename Q>
  struct S {
    typedef int X;
  };
  
! template void f<S> (int); // { dg-warning "mangle" }
--- 1,11 ----
  // { dg-options "-Wabi -fabi-version=1" }
  
  template <template <typename> class Q>
! void f (typename Q<int>::X) {} // { dg-warning "mangle" }
  
  template <typename Q>
  struct S {
    typedef int X;
  };
  
! template void f<S> (int); 
Index: testsuite/g++.dg/abi/mangle17.C
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/g++.dg/abi/mangle17.C,v
retrieving revision 1.3
diff -c -5 -p -r1.3 mangle17.C
*** testsuite/g++.dg/abi/mangle17.C	23 Dec 2003 16:53:52 -0000	1.3
--- testsuite/g++.dg/abi/mangle17.C	29 Jul 2004 17:57:40 -0000
***************
*** 2,11 ****
  
  enum E { e = 3 };
  
  template <int I> struct S {};
  
! template <int I> void f (S<I + e + int (3.7)>) {}
! template void f<7>(S<7 + e + int (3.7)>);  // { dg-warning "mangle" }
  
! template <int I> void g (S<I + e + int (3.7)>) {}
! template void g<7>(S<7 + e + int (3.7)>); // { dg-warning "mangle" }
--- 2,11 ----
  
  enum E { e = 3 };
  
  template <int I> struct S {};
  
! template <int I> void f (S<I + e + int (3.7)>) {} // { dg-warning "mangle" }
! template void f<7>(S<7 + e + int (3.7)>);  
  
! template <int I> void g (S<I + e + int (3.7)>) {} // { dg-warning "mangle" }
! template void g<7>(S<7 + e + int (3.7)>); 
Index: testsuite/g++.dg/abi/mangle20-2.C
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/g++.dg/abi/mangle20-2.C,v
retrieving revision 1.2
diff -c -5 -p -r1.2 mangle20-2.C
*** testsuite/g++.dg/abi/mangle20-2.C	18 Dec 2003 22:03:44 -0000	1.2
--- testsuite/g++.dg/abi/mangle20-2.C	29 Jul 2004 17:57:40 -0000
***************
*** 5,16 ****
  // Contributed by Nathan Sidwell 15 Dec 2003 <nathan@codesourcery.com>
  
  // PR 9043
  // mangled array types in templates
  
! template <int I> void f(int (*)[2]) {}
  template <int I> void g(int (*)[I+2]) {}
  
! template void f<1>(int (*)[2]);  // { dg-warning "mangled name" }
  //  { dg-final { scan-assembler "\n_?_Z1fILi1EEvPALi2E_i\[: \t\n\]" } }
  template void g<1>(int (*)[3]);
  //  { dg-final { scan-assembler "\n_?_Z1gILi1EEvPAplT_Li2E_i\[: \t\n\]" } }
--- 5,16 ----
  // Contributed by Nathan Sidwell 15 Dec 2003 <nathan@codesourcery.com>
  
  // PR 9043
  // mangled array types in templates
  
! template <int I> void f(int (*)[2]) {} // { dg-warning "mangled name" }
  template <int I> void g(int (*)[I+2]) {}
  
! template void f<1>(int (*)[2]);  
  //  { dg-final { scan-assembler "\n_?_Z1fILi1EEvPALi2E_i\[: \t\n\]" } }
  template void g<1>(int (*)[3]);
  //  { dg-final { scan-assembler "\n_?_Z1gILi1EEvPAplT_Li2E_i\[: \t\n\]" } }
Index: testsuite/g++.dg/opt/interface1-a.cc
===================================================================
RCS file: testsuite/g++.dg/opt/interface1-a.cc
diff -N testsuite/g++.dg/opt/interface1-a.cc
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- testsuite/g++.dg/opt/interface1-a.cc	29 Jul 2004 17:57:40 -0000
***************
*** 0 ****
--- 1,9 ----
+ struct Test {
+   void f();
+ };
+ 
+ Test t;
+ 
+ void g() {
+   t.f();
+ }
Index: testsuite/g++.dg/opt/interface1.C
===================================================================
RCS file: testsuite/g++.dg/opt/interface1.C
diff -N testsuite/g++.dg/opt/interface1.C
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- testsuite/g++.dg/opt/interface1.C	29 Jul 2004 17:57:40 -0000
***************
*** 0 ****
--- 1,13 ----
+ // { dg-do run }
+ // { dg-options "-O2" }
+ // { dg-additional-sources "interface1-a.cc" }
+ 
+ #pragma implementation "interface1.h"
+ 
+ #include "interface1.h"
+ 
+ extern void g();
+ 
+ int main () {
+   g();
+ }
Index: testsuite/g++.dg/opt/interface1.h
===================================================================
RCS file: testsuite/g++.dg/opt/interface1.h
diff -N testsuite/g++.dg/opt/interface1.h
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- testsuite/g++.dg/opt/interface1.h	29 Jul 2004 17:57:40 -0000
***************
*** 0 ****
--- 1,8 ----
+ #pragma interface "interface1.h"
+ 
+ struct Test {
+   void f();
+ };
+ 
+ inline void Test::f() {
+ }
Index: testsuite/g++.dg/parse/repo1.C
===================================================================
RCS file: testsuite/g++.dg/parse/repo1.C
diff -N testsuite/g++.dg/parse/repo1.C
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- testsuite/g++.dg/parse/repo1.C	29 Jul 2004 17:57:40 -0000
***************
*** 0 ****
--- 1,7 ----
+ // { dg-options "-frepo" }
+ 
+ extern "C" inline void f() {}
+ 
+ int main () {
+   f();
+ }
Index: testsuite/g++.dg/template/repo1.C
===================================================================
RCS file: testsuite/g++.dg/template/repo1.C
diff -N testsuite/g++.dg/template/repo1.C
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- testsuite/g++.dg/template/repo1.C	29 Jul 2004 17:57:40 -0000
***************
*** 0 ****
--- 1,17 ----
+ // { dg-options "-frepo" }
+ 
+ struct A {
+   A();
+ };
+ 
+ A::A() {}
+ 
+ template <typename T>
+ struct B : public A {
+   B() {} // { dg-bogus "" }
+ };
+ 
+ B<int> b;
+ 
+ int main () {}
+ 
Index: testsuite/g++.dg/warn/Winline-1.C
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/g++.dg/warn/Winline-1.C,v
retrieving revision 1.3
diff -c -5 -p -r1.3 Winline-1.C
*** testsuite/g++.dg/warn/Winline-1.C	12 Jul 2003 01:07:40 -0000	1.3
--- testsuite/g++.dg/warn/Winline-1.C	29 Jul 2004 17:57:40 -0000
***************
*** 1,10 ****
! // { dg-options "-Winline -O2 -fno-unit-at-a-time" }
  
! static inline int foo(int x); // { dg-warning "" }
  
  int main()
  {
!   return(foo(17)); // { dg-warning "" }
  }
  
  inline int foo(int x) {  return(x);  }
--- 1,10 ----
! // { dg-options "-Winline -O2" }
  
! static inline int foo(int x);
  
  int main()
  {
!   return(foo(17));
  }
  
  inline int foo(int x) {  return(x);  }
Index: testsuite/lib/gcc-dg.exp
===================================================================
RCS file: /cvs/gcc/gcc/gcc/testsuite/lib/gcc-dg.exp,v
retrieving revision 1.32
diff -c -5 -p -r1.32 gcc-dg.exp
*** testsuite/lib/gcc-dg.exp	13 May 2004 06:40:54 -0000	1.32
--- testsuite/lib/gcc-dg.exp	29 Jul 2004 17:57:41 -0000
*************** proc gcc-dg-test-1 { target_compile prog
*** 117,128 ****
      set comp_output [$target_compile "$prog" "$output_file" "$compile_type" $options];
  
      if { $do_what == "repo" } {
  	set object_file "$output_file"
  	set output_file "[file rootname [file tail $prog]].exe"
! 	concat comp_output \
! 	       [$target_compile "$object_file" "$output_file" "executable" $options]
      }
  
      return [list $comp_output $output_file]
  }
  
--- 117,130 ----
      set comp_output [$target_compile "$prog" "$output_file" "$compile_type" $options];
  
      if { $do_what == "repo" } {
  	set object_file "$output_file"
  	set output_file "[file rootname [file tail $prog]].exe"
! 	set comp_output \
! 	    [ concat $comp_output \
! 		  [$target_compile "$object_file" "$output_file" \
! 		       "executable" $options] ]
      }
  
      return [list $comp_output $output_file]
  }
  


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]