From 4684cd27fc05d4b4b14401c639fe4427a3bbbe3e Mon Sep 17 00:00:00 2001 From: Mark Mitchell Date: Thu, 29 Jul 2004 17:59:31 +0000 Subject: [PATCH] c-common.h (lang_post_pch_load): New variable. * 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. * 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. * 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. From-SVN: r85309 --- gcc/ChangeLog | 13 + gcc/c-common.h | 4 + gcc/c-pch.c | 9 + gcc/cgraphunit.c | 7 +- gcc/cp/ChangeLog | 100 ++++ gcc/cp/class.c | 55 +- gcc/cp/cp-tree.h | 76 ++- gcc/cp/decl.c | 48 +- gcc/cp/decl2.c | 621 +++++++++++++---------- gcc/cp/lex.c | 13 +- gcc/cp/method.c | 5 +- gcc/cp/optimize.c | 4 +- gcc/cp/pt.c | 217 ++++---- gcc/cp/repo.c | 319 ++++-------- gcc/cp/rtti.c | 192 +++---- gcc/cp/semantics.c | 44 +- gcc/cp/tree.c | 26 +- gcc/testsuite/ChangeLog | 17 + gcc/testsuite/g++.dg/abi/inline1.C | 6 + gcc/testsuite/g++.dg/abi/local1-a.cc | 14 + gcc/testsuite/g++.dg/abi/local1.C | 22 + gcc/testsuite/g++.dg/abi/mangle11.C | 4 +- gcc/testsuite/g++.dg/abi/mangle12.C | 4 +- gcc/testsuite/g++.dg/abi/mangle17.C | 8 +- gcc/testsuite/g++.dg/abi/mangle20-2.C | 4 +- gcc/testsuite/g++.dg/opt/interface1-a.cc | 9 + gcc/testsuite/g++.dg/opt/interface1.C | 13 + gcc/testsuite/g++.dg/opt/interface1.h | 8 + gcc/testsuite/g++.dg/parse/repo1.C | 7 + gcc/testsuite/g++.dg/template/repo1.C | 17 + gcc/testsuite/g++.dg/warn/Winline-1.C | 6 +- gcc/testsuite/lib/gcc-dg.exp | 6 +- gcc/tlink.c | 9 + 33 files changed, 1134 insertions(+), 773 deletions(-) create mode 100644 gcc/testsuite/g++.dg/abi/inline1.C create mode 100644 gcc/testsuite/g++.dg/abi/local1-a.cc create mode 100644 gcc/testsuite/g++.dg/abi/local1.C create mode 100644 gcc/testsuite/g++.dg/opt/interface1-a.cc create mode 100644 gcc/testsuite/g++.dg/opt/interface1.C create mode 100644 gcc/testsuite/g++.dg/opt/interface1.h create mode 100644 gcc/testsuite/g++.dg/parse/repo1.C create mode 100644 gcc/testsuite/g++.dg/template/repo1.C diff --git a/gcc/ChangeLog b/gcc/ChangeLog index dbda154ab8d..1a6e4e130d3 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,16 @@ +2004-07-29 Mark Mitchell + + * 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 Zdenek Dvorak * tree-ssa-loop-im.c (force_move_till_expr, force_move_till): diff --git a/gcc/c-common.h b/gcc/c-common.h index 6df90a4f215..63972dc96bb 100644 --- a/gcc/c-common.h +++ b/gcc/c-common.h @@ -286,6 +286,10 @@ extern void (*lang_expand_function_end) (void); 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); diff --git a/gcc/c-pch.c b/gcc/c-pch.c index eb043bd089e..21c3135b110 100644 --- a/gcc/c-pch.c +++ b/gcc/c-pch.c @@ -384,6 +384,10 @@ c_common_valid_pch (cpp_reader *pfile, const char *name, int fd) 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. */ @@ -443,6 +447,11 @@ c_common_read_pch (cpp_reader *pfile, const char *name, 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. */ diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c index 059ae86081e..9e903e09b9d 100644 --- a/gcc/cgraphunit.c +++ b/gcc/cgraphunit.c @@ -400,7 +400,12 @@ record_call_1 (tree *tp, int *walk_subtrees, void *data) 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)); + { + 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: diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index da4dad7448b..d87584ec711 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,103 @@ +2004-07-29 Mark Mitchell + + * 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-28 Eric Christopher * cp-lang.c (LANG_HOOKS_UNSAFE_FOR_REEVAL): Delete. diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 8da2e586548..365febbb704 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -581,6 +581,32 @@ 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. */ @@ -601,17 +627,42 @@ build_vtable (tree class_type, tree name, tree vtable_type) 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); - import_export_vtable (decl, class_type, 0); return decl; } diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index c69320fadbc..8d14911235d 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -48,7 +48,7 @@ struct diagnostic_context; 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. + 1: IDENTIFIER_VIRTUAL_P (in IDENTIFIER_NODE) TI_PENDING_TEMPLATE_FLAG. TEMPLATE_PARMS_FOR_INLINE. DELETE_EXPR_USE_VEC (in DELETE_EXPR). @@ -56,7 +56,7 @@ struct diagnostic_context; TYPE_BASE_CONVS_MAY_REQUIRE_CODE_P (in _TYPE). ICS_ELLIPSIS_FLAG (in _CONV) DECL_INITIALIZED_P (in VAR_DECL) - 2: IDENTIFIER_OPNAME_P. + 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) @@ -70,9 +70,10 @@ struct diagnostic_context; 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: For future expansion + 6: IDENTIFIER_REPO_CHOSEN (in IDENTIFIER_NODE) Usage of TYPE_LANG_FLAG_?: 0: TYPE_DEPENDENT_P @@ -375,6 +376,12 @@ typedef enum cp_id_kind #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) @@ -1515,7 +1522,11 @@ struct lang_type GTY(()) struct lang_decl_flags GTY(()) { - ENUM_BITFIELD(languages) language : 8; + 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; @@ -1534,14 +1545,12 @@ struct lang_decl_flags GTY(()) 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; + unsigned repo_available_p : 1; + unsigned dummy : 3; union lang_decl_u { /* In a FUNCTION_DECL for which DECL_THUNK_P holds, this is @@ -1631,19 +1640,6 @@ struct lang_decl GTY(()) #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 @@ -1730,6 +1726,21 @@ struct lang_decl GTY(()) #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 \ @@ -1921,6 +1932,11 @@ struct lang_decl GTY(()) 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) \ @@ -1965,6 +1981,10 @@ struct lang_decl GTY(()) (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)) @@ -3643,6 +3663,7 @@ 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); @@ -3787,9 +3808,7 @@ 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); @@ -3801,6 +3820,9 @@ 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) \ @@ -3973,9 +3995,9 @@ 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 init_repo (void); +extern int repo_emit_p (tree); +extern bool repo_export_class_p (tree); extern void finish_repo (void); /* in rtti.c */ @@ -4192,7 +4214,7 @@ 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 tree no_linkage_check (tree, bool); extern void debug_binfo (tree); extern tree build_dummy_object (tree); extern tree maybe_dummy_object (tree, tree *); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index f901d98f3db..c84c4be7687 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -1753,6 +1753,7 @@ duplicate_decls (tree newdecl, tree 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); @@ -4571,7 +4572,8 @@ make_rtl_for_nonlocal_decl (tree decl, tree init, const char* asmspec) defer_p = 1; } /* Likewise for template instantiations. */ - else if (DECL_COMDAT (decl)) + 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 @@ -5513,7 +5515,8 @@ grokfndecl (tree ctype, declare an entity with linkage. Only check this for public decls for now. See core 319, 389. */ - t = no_linkage_check (TREE_TYPE (decl)); + t = no_linkage_check (TREE_TYPE (decl), + /*relaxed_p=*/false); if (t) { if (TYPE_ANONYMOUS_P (t)) @@ -5723,6 +5726,25 @@ grokfndecl (tree ctype, 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 @@ -5782,12 +5804,10 @@ grokvardecl (tree type, 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; + 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 @@ -5822,7 +5842,8 @@ grokvardecl (tree type, declare an entity with linkage. Only check this for public decls for now. */ - tree t = no_linkage_check (TREE_TYPE (decl)); + tree t = no_linkage_check (TREE_TYPE (decl), + /*relaxed_p=*/false); if (t) { if (TYPE_ANONYMOUS_P (t)) @@ -7859,9 +7880,11 @@ grokdeclarator (const cp_declarator *declarator, /* 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; + 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 { @@ -9842,6 +9865,11 @@ start_preparsed_function (tree decl1, tree attrs, int flags) 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)) diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index ea9aa49c13c..40322ab31cc 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -729,6 +729,33 @@ check_classfn (tree ctype, tree function, tree template_parms) 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. @@ -750,11 +777,7 @@ finish_static_data_member_decl (tree decl, tree init, tree asmspec_tree, 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); - } + note_vague_linkage_var (decl); if (LOCAL_CLASS_P (current_class_type)) pedwarn ("local class `%#T' shall not have static data member `%#D'", @@ -1403,51 +1426,6 @@ maybe_make_one_only (tree 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. */ @@ -1479,21 +1457,18 @@ import_export_class (tree 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)) - { + 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 @@ -1525,10 +1500,52 @@ import_export_class (tree ctype) 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); + 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. @@ -1539,8 +1556,7 @@ maybe_emit_vtables (tree ctype) { tree vtbl; tree primary_vtbl; - bool needed = false; - bool weaken_vtables; + int needed = 0; /* If the vtables for this class have already been emitted there is nothing more to do. */ @@ -1551,16 +1567,14 @@ maybe_emit_vtables (tree ctype) 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; + import_export_decl (vtbl); + if (DECL_NOT_REALLY_EXTERN (vtbl) && decl_needed_p (vtbl)) + needed = 1; } - if (!vtbl) + if (!needed) { /* If the references to this class' vtables are optimized away, still emit the appropriate debugging information. See @@ -1570,45 +1584,14 @@ maybe_emit_vtables (tree 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 entities references from the virtual table as used. */ 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. */ @@ -1616,36 +1599,8 @@ maybe_emit_vtables (tree ctype) 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); - + /* 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 @@ -1661,38 +1616,194 @@ maybe_emit_vtables (tree ctype) return true; } -/* Determines the proper settings of TREE_PUBLIC and DECL_EXTERNAL for an - inline function or template instantiation at end-of-file. */ +/* 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; - 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)))) + /* 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)) { - if (!TREE_PUBLIC (decl)) - /* Templates are allowed to have internal linkage. See - [basic.link]. */ - ; - else - comdat_linkage (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)) { - DECL_EXTERNAL (decl) = 1; - DECL_NOT_REALLY_EXTERN (decl) = 0; + /* 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)) { @@ -1713,55 +1824,31 @@ import_export_decl (tree decl) /* Always make artificials weak. */ if (DECL_ARTIFICIAL (decl) && flag_weak) - comdat_linkage (decl); + comdat_p = true; else maybe_make_one_only (decl); } } else - comdat_linkage (decl); + comdat_p = true; } 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. */ + comdat_p = true; -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) + if (import_p) { - DECL_NOT_REALLY_EXTERN (decl) = !CLASSTYPE_INTERFACE_ONLY (type); - DECL_COMDAT (decl) = 0; + /* 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 + else if (comdat_p) { - DECL_NOT_REALLY_EXTERN (decl) = 1; - DECL_COMDAT (decl) = 1; + /* If we decided to put DECL in COMDAT, mark it accordingly at + this point. */ + comdat_linkage (decl); } - /* 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; } @@ -2403,8 +2490,14 @@ 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); + { + 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 @@ -2520,21 +2613,36 @@ cxx_callgraph_analyze_expr (tree *tp, int *walk_subtrees 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; - } + 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; } @@ -2732,16 +2840,15 @@ finish_file (void) #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); - 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 @@ -2772,7 +2879,7 @@ finish_file (void) function twice. */ if (DECL_NOT_REALLY_EXTERN (decl) && DECL_INITIAL (decl) - && DECL_NEEDED_P (decl)) + && decl_needed_p (decl)) DECL_EXTERNAL (decl) = 0; /* If we're going to need to write this function out, and @@ -2780,10 +2887,9 @@ finish_file (void) (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) + && decl_needed_p (decl) && !TREE_ASM_WRITTEN (decl) - && (!flag_unit_at_a_time - || !cgraph_node (decl)->local.finalized)) + && !cgraph_node (decl)->local.finalized) { /* We will output the function; no longer consider it in this loop. */ @@ -2807,10 +2913,12 @@ finish_file (void) for (i = 0; i < pending_statics_used; ++i) { tree decl = VARRAY_TREE (pending_statics, i); - if (var_finalized_p (decl)) + if (var_finalized_p (decl) || DECL_REALLY_EXTERN (decl)) continue; import_export_decl (decl); - if (DECL_NOT_REALLY_EXTERN (decl) && ! DECL_IN_AGGR_P (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 @@ -2818,8 +2926,13 @@ finish_file (void) 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); @@ -2828,7 +2941,17 @@ finish_file (void) { tree decl = VARRAY_TREE (deferred_fns, i); - if (!TREE_ASM_WRITTEN (decl) && !DECL_SAVED_TREE (decl) + 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. */ @@ -2840,7 +2963,6 @@ finish_file (void) warning. */ TREE_PUBLIC (decl) = 1; } - } /* We give C linkage to static constructors and destructors. */ @@ -2871,11 +2993,8 @@ finish_file (void) linkage now. */ pop_lang_context (); - if (flag_unit_at_a_time) - { - cgraph_finalize_compilation_unit (); - cgraph_optimize (); - } + cgraph_finalize_compilation_unit (); + cgraph_optimize (); /* Emit mudflap static registration function. This must be done after all the user functions have been expanded. */ @@ -3009,12 +3128,7 @@ mark_used (tree decl) { 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); + note_vague_linkage_fn (decl); } assemble_external (decl); @@ -3044,40 +3158,11 @@ mark_used (tree 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); - } + /* 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" diff --git a/gcc/cp/lex.c b/gcc/cp/lex.c index c5b14460b94..00adb7239c5 100644 --- a/gcc/cp/lex.c +++ b/gcc/cp/lex.c @@ -361,6 +361,17 @@ cxx_init (void) 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(); @@ -369,7 +380,7 @@ cxx_init (void) init_cp_pragma (); - init_repo (main_input_filename); + init_repo (); pop_srcloc(); return true; diff --git a/gcc/cp/method.c b/gcc/cp/method.c index 07fbacf266a..d741d3d3cd1 100644 --- a/gcc/cp/method.c +++ b/gcc/cp/method.c @@ -700,9 +700,6 @@ synthesize_method (tree 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. */ @@ -1014,7 +1011,7 @@ implicitly_declare_fn (special_function_kind kind, tree type, bool const_p) 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)); + 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; diff --git a/gcc/cp/optimize.c b/gcc/cp/optimize.c index 000d6cc4c27..b94270eabd6 100644 --- a/gcc/cp/optimize.c +++ b/gcc/cp/optimize.c @@ -89,9 +89,7 @@ maybe_clone_body (tree 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)) + FOR_EACH_CLONE (clone, fn) { tree parm; tree clone_parm; diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index def63108bd4..0ecbda0fa15 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -5693,10 +5693,7 @@ instantiate_class_template (tree type) 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 @@ -5715,7 +5712,11 @@ instantiate_class_template (tree type) pop_deferring_access_checks (); pop_tinst_level (); - if (TYPE_CONTAINS_VPTR_P (type)) + /* 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; @@ -6235,7 +6236,10 @@ tsubst_decl (tree t, tree args, tree type, tsubst_flags_t complain) TREE_STATIC (r) = 0; TREE_PUBLIC (r) = TREE_PUBLIC (t); DECL_EXTERNAL (r) = 1; - DECL_INTERFACE_KNOWN (r) = 0; + /* 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; @@ -8564,7 +8568,7 @@ check_instantiated_args (tree tmpl, tree args, tsubst_flags_t complain) 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); + tree nt = no_linkage_check (t, /*relaxed_p=*/false); if (nt) { @@ -8628,9 +8632,7 @@ instantiate_template (tree tmpl, tree targ_ptr, tsubst_flags_t complain) return error_mark_node; /* Look for the clone. */ - for (clone = TREE_CHAIN (spec); - clone && DECL_CLONED_FUNCTION_P (clone); - clone = TREE_CHAIN (clone)) + FOR_EACH_CLONE (clone, spec) if (DECL_NAME (clone) == DECL_NAME (tmpl)) return clone; /* We should always have found the clone by now. */ @@ -10076,9 +10078,20 @@ unify (tree tparms, tree targs, tree parm, tree arg, int strict) } } +/* 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, or if using -frepo and the - instantiation of RESULT has been assigned to this file. */ + explicitly instantiated class. */ void mark_decl_instantiated (tree result, int extern_p) @@ -10098,11 +10111,11 @@ mark_decl_instantiated (tree result, int extern_p) /* This might have been set by an earlier implicit instantiation. */ DECL_COMDAT (result) = 0; - if (! extern_p) + if (extern_p) + DECL_NOT_REALLY_EXTERN (result) = 0; + else { - DECL_INTERFACE_KNOWN (result) = 1; - DECL_NOT_REALLY_EXTERN (result) = 1; - + mark_definable (result); /* Always make artificials weak. */ if (DECL_ARTIFICIAL (result) && flag_weak) comdat_linkage (result); @@ -10111,6 +10124,13 @@ mark_decl_instantiated (tree result, int extern_p) 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: @@ -10548,15 +10568,14 @@ do_decl_instantiation (tree decl, tree storage) 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) + 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 we've already instantiated the template, just return now. */ - if (DECL_INTERFACE_KNOWN (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)) @@ -10583,7 +10602,6 @@ do_decl_instantiation (tree decl, tree storage) 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); } @@ -10621,7 +10639,6 @@ 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); } @@ -10701,14 +10718,10 @@ do_type_instantiation (tree t, tree storage, tsubst_flags_t complain) 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. */ - + 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); @@ -10718,7 +10731,6 @@ do_type_instantiation (tree t, tree storage, tsubst_flags_t complain) } mark_class_instantiated (t, extern_p); - repo_template_instantiated (t, extern_p); if (nomem_p) return; @@ -11001,38 +11013,22 @@ instantiate_decl (tree d, int defer_ok, int undefined_ok) 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) + if (! pattern_defined && DECL_EXPLICIT_INSTANTIATION (d) && undefined_ok) { - /* 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); + DECL_NOT_REALLY_EXTERN (d) = 0; + SET_DECL_IMPLICIT_INSTANTIATION (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 @@ -11061,15 +11057,19 @@ instantiate_decl (tree d, int defer_ok, int undefined_ok) 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))) + /* 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 @@ -11093,6 +11093,22 @@ instantiate_decl (tree d, int defer_ok, int undefined_ok) 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) @@ -11105,7 +11121,7 @@ instantiate_decl (tree d, int defer_ok, int undefined_ok) /* 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); @@ -11115,51 +11131,27 @@ instantiate_decl (tree d, int defer_ok, int undefined_ok) /* 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 (); - } + /* 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) { @@ -11168,10 +11160,6 @@ instantiate_decl (tree d, int defer_ok, int undefined_ok) 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; @@ -11183,7 +11171,6 @@ instantiate_decl (tree d, int defer_ok, int undefined_ok) NULL); /* Set up context. */ - import_export_decl (d); start_preparsed_function (d, NULL_TREE, SF_PRE_PARSED); /* Create substitution entries for the parameters. */ diff --git a/gcc/cp/repo.c b/gcc/cp/repo.c index a9a5b35c293..b3edf4875fc 100644 --- a/gcc/cp/repo.c +++ b/gcc/cp/repo.c @@ -37,7 +37,6 @@ Boston, MA 02111-1307, USA. */ #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 *); @@ -45,162 +44,13 @@ 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; - } -} +static bool temporary_obstack_initialized_p; /* Parse a reasonable subset of shell quoting syntax. */ @@ -298,16 +148,22 @@ afgets (FILE *stream) } void -init_repo (const char *filename) +init_repo (void) { char *buf; if (! flag_use_repository) return; - gcc_obstack_init (&temporary_obstack); + /* 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 (filename); + open_repo_file (main_input_filename); if (repo_file == 0) return; @@ -325,21 +181,16 @@ init_repo (const char *filename) case 'M': old_main = ggc_strdup (buf + 2); break; - case 'C': 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); - 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); + IDENTIFIER_REPO_CHOSEN (id) = 1; } break; default: @@ -347,13 +198,12 @@ init_repo (const char *filename) } obstack_free (&temporary_obstack, buf); } + fclose (repo_file); } static void reopen_repo_file_for_write (void) { - if (repo_file) - fclose (repo_file); repo_file = fopen (repo_name, "w"); if (repo_file == 0) @@ -369,69 +219,31 @@ 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) + 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); - char type = IDENTIFIER_REPO_CHOSEN (val) ? 'C' : 'O'; - - fprintf (repo_file, "%c %s\n", type, IDENTIFIER_POINTER (val)); + 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: @@ -439,4 +251,87 @@ finish_repo (void) 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" diff --git a/gcc/cp/rtti.c b/gcc/cp/rtti.c index c6c9fc6acc4..83e24c4e21c 100644 --- a/gcc/cp/rtti.c +++ b/gcc/cp/rtti.c @@ -89,18 +89,15 @@ 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_init (tree, tree); 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; @@ -348,14 +345,16 @@ get_tinfo_decl (tree type) 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_COMDAT (d) = 1; - TREE_PUBLIC (d) = 1; - SET_DECL_ASSEMBLER_NAME (d, name); + DECL_NOT_REALLY_EXTERN (d) = 1; + set_linkage_according_to_type (type, d); pushdecl_top_level_and_finish (d, NULL_TREE); @@ -732,6 +731,38 @@ target_incomplete_p (tree type) 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 @@ -754,20 +785,32 @@ tinfo_base_init (tree desc, tree target) 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; - TREE_PUBLIC (name_decl) = 1; + 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); + DECL_VISIBILITY_SPECIFIED (name_decl) + = CLASSTYPE_VISIBILITY_SPECIFIED (target); } - import_export_tinfo (name_decl, target, typeinfo_in_lib_p (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, @@ -843,7 +886,7 @@ generic_initializer (tree desc, tree target) 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) +ptr_initializer (tree desc, tree target) { tree init = tinfo_base_init (desc, target); tree to = TREE_TYPE (target); @@ -851,10 +894,7 @@ ptr_initializer (tree desc, tree target, bool *non_public_ptr) bool incomplete = target_incomplete_p (to); if (incomplete) - { - flags |= 8; - *non_public_ptr = true; - } + 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)), @@ -873,7 +913,7 @@ ptr_initializer (tree desc, tree target, bool *non_public_ptr) base. */ static tree -ptm_initializer (tree desc, tree target, bool *non_public_ptr) +ptm_initializer (tree desc, tree target) { tree init = tinfo_base_init (desc, target); tree to = TYPE_PTRMEM_POINTED_TO_TYPE (target); @@ -882,15 +922,9 @@ ptm_initializer (tree desc, tree target, bool *non_public_ptr) bool incomplete = target_incomplete_p (to); if (incomplete) - { - flags |= 0x8; - *non_public_ptr = true; - } + flags |= 0x8; if (!COMPLETE_TYPE_P (klass)) - { - flags |= 0x10; - *non_public_ptr = true; - } + 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)), @@ -1003,22 +1037,18 @@ typeinfo_in_lib_p (tree type) } } -/* 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. */ +/* Generate the initializer for the type info describing TYPE. */ static tree -get_pseudo_ti_init (tree type, tree var_desc, bool *non_public_p) +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, non_public_p); + return ptm_initializer (var_desc, type); case POINTER_TYPE: - return ptr_initializer (var_desc, type, non_public_p); + return ptr_initializer (var_desc, type); case ENUMERAL_TYPE: return generic_initializer (var_desc, type); break; @@ -1031,14 +1061,9 @@ get_pseudo_ti_init (tree type, tree var_desc, bool *non_public_p) case UNION_TYPE: case RECORD_TYPE: if (TYPE_PTRMEMFUNC_P (type)) - return ptm_initializer (var_desc, type, non_public_p); + return ptm_initializer (var_desc, type); 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); - } + 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); @@ -1414,30 +1439,6 @@ emit_support_tinfos (void) } } -/* 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. */ @@ -1446,35 +1447,48 @@ 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); + my_friendly_assert (DECL_TINFO_P (decl), 20030307); - import_export_tinfo (decl, type, in_library); - if (DECL_REALLY_EXTERN (decl) || !DECL_NEEDED_P (decl)) - return false; + 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; + } - if (!doing_runtime && in_library) + 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; - - 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; } diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index f6f71759478..152d75ca1f0 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -2892,18 +2892,6 @@ expand_body (tree fn) 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 @@ -2957,15 +2945,39 @@ expand_or_defer_fn (tree fn) 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; - /* 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. */ diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 79070f0629a..6a626e9470d 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -1062,10 +1062,11 @@ find_tree (tree t, tree x) } /* Check if the type T depends on a type with no linkage and if so, return - it. */ + 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) +no_linkage_check (tree t, bool relaxed_p) { tree r; @@ -1076,6 +1077,8 @@ no_linkage_check (tree t) switch (TREE_CODE (t)) { + tree fn; + case RECORD_TYPE: if (TYPE_PTRMEMFUNC_P (t)) goto ptrmem; @@ -1085,25 +1088,28 @@ no_linkage_check (tree t) return NULL_TREE; /* Fall through. */ case ENUMERAL_TYPE: - if (decl_function_context (TYPE_MAIN_DECL (t)) - || TYPE_ANONYMOUS_P (t)) + 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)); + return no_linkage_check (TREE_TYPE (t), relaxed_p); case OFFSET_TYPE: ptrmem: - r = no_linkage_check (TYPE_PTRMEM_POINTED_TO_TYPE (t)); + 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)); + return no_linkage_check (TYPE_PTRMEM_CLASS_TYPE (t), relaxed_p); case METHOD_TYPE: - r = no_linkage_check (TYPE_METHOD_BASETYPE (t)); + r = no_linkage_check (TYPE_METHOD_BASETYPE (t), relaxed_p); if (r) return r; /* Fall through. */ @@ -1114,11 +1120,11 @@ no_linkage_check (tree t) parm && parm != void_list_node; parm = TREE_CHAIN (parm)) { - r = no_linkage_check (TREE_VALUE (parm)); + r = no_linkage_check (TREE_VALUE (parm), relaxed_p); if (r) return r; } - return no_linkage_check (TREE_TYPE (t)); + return no_linkage_check (TREE_TYPE (t), relaxed_p); } default: diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index c82cbe55ddc..5dc06fc7beb 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,20 @@ +2004-07-29 Mark Mitchell + + * 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. + 2004-07-29 Diego Novillo * gcc.dg/tree-ssa/20040729-1.c: New test. diff --git a/gcc/testsuite/g++.dg/abi/inline1.C b/gcc/testsuite/g++.dg/abi/inline1.C new file mode 100644 index 00000000000..97082aa7377 --- /dev/null +++ b/gcc/testsuite/g++.dg/abi/inline1.C @@ -0,0 +1,6 @@ +struct S { + S() {} + virtual void g() {} +}; + +// { dg-final { scan-assembler-not "_ZTV1S" } } diff --git a/gcc/testsuite/g++.dg/abi/local1-a.cc b/gcc/testsuite/g++.dg/abi/local1-a.cc new file mode 100644 index 00000000000..638479e7459 --- /dev/null +++ b/gcc/testsuite/g++.dg/abi/local1-a.cc @@ -0,0 +1,14 @@ +struct B { + virtual void b() {} +}; + +static B* f() { + struct D : public B { + }; + + return new D; +} + +B* g() { + return f(); +} diff --git a/gcc/testsuite/g++.dg/abi/local1.C b/gcc/testsuite/g++.dg/abi/local1.C new file mode 100644 index 00000000000..518193c8980 --- /dev/null +++ b/gcc/testsuite/g++.dg/abi/local1.C @@ -0,0 +1,22 @@ +// { dg-do run } +// { dg-additional-sources "local1-a.cc" } + +#include + +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; +} diff --git a/gcc/testsuite/g++.dg/abi/mangle11.C b/gcc/testsuite/g++.dg/abi/mangle11.C index a049a956671..6d09b51a6a1 100644 --- a/gcc/testsuite/g++.dg/abi/mangle11.C +++ b/gcc/testsuite/g++.dg/abi/mangle11.C @@ -1,10 +1,10 @@ // { dg-options "-Wabi -fabi-version=1" } template -void f (typename Q::X) {} +void f (typename Q::X) {} // { dg-warning "mangle" } struct S { typedef int X; }; -template void f (int); // { dg-warning "mangle" } +template void f (int); diff --git a/gcc/testsuite/g++.dg/abi/mangle12.C b/gcc/testsuite/g++.dg/abi/mangle12.C index 406a13b3f79..a3bd9ff6fa7 100644 --- a/gcc/testsuite/g++.dg/abi/mangle12.C +++ b/gcc/testsuite/g++.dg/abi/mangle12.C @@ -1,11 +1,11 @@ // { dg-options "-Wabi -fabi-version=1" } template