aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/cp/ChangeLog26
-rw-r--r--gcc/cp/Make-lang.in4
-rw-r--r--gcc/cp/call.c2
-rw-r--r--gcc/cp/cp-lang.c5
-rw-r--r--gcc/cp/cp-tree.h4
-rw-r--r--gcc/cp/decl.c2
-rw-r--r--gcc/cp/decl2.c60
-rw-r--r--gcc/cp/method.c4
-rw-r--r--gcc/cp/optimize.c2
-rw-r--r--gcc/cp/parser.c2
-rw-r--r--gcc/cp/pt.c2
-rw-r--r--gcc/cp/semantics.c169
12 files changed, 192 insertions, 90 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index c2d4545..1c05850 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,29 @@
+Wed Jul 2 00:36:48 CEST 2003 Jan Hubicka <jh@suse.cz>
+
+ * decl2.c (defer_fn): Set DECL_DEFER_OUTPUT.
+ (finish-file): Do not process function with DECL_DEFER_OUTPUT clear;
+ clear DECL_DEFER_OUTPUT once function is processed; avoid flags
+ massaging.
+
+ * cp-tree.h (DECL_NEEDED_P): Support unit-at-a-time
+ (expand_or_defer_fn): Declare.
+ (lower_function): Declare.
+ * decl.c (start_cleanup_fn): Use expand_or_defer_fn.
+ * decl2.c: Include cgraph.h and varpool.h
+ (maybe_emit_vtables): Make explicit instantations as needed.
+ (mark_member_pointers, lower_function): New functions.
+ (finish_file): Do unit-at-a-time.
+ * method.c (synthesize_method): Use expand_or_defer_fn.
+ * optimize.c (maybe_clone_body): Use expand_or_defer_fn.
+ * parser.c (cp_parser_function_definition_after_decl): Use
+ expand_or_defer_fn.
+ * pt.c (instantiate_decl): Likewise.
+ * semantics.c: Include cgraph.h
+ (expand_or_defer_fn): Break out from ...
+ (expand_body): ... here; deal with unit-at-a-time.
+ * cp-lang.c (LANG_HOOKS_CALLGRAPH_EXPAND_FUNCTION,
+ LANG_HOOKS_CALLGRAPH_LOWER_FUNCTION): Define.
+
2003-07-01 Mark Mitchell <mark@codesourcery.com>
* call.c (resolve_scoped_fn_name): Return error_mark_node for
diff --git a/gcc/cp/Make-lang.in b/gcc/cp/Make-lang.in
index 2ca56346..d6b871a 100644
--- a/gcc/cp/Make-lang.in
+++ b/gcc/cp/Make-lang.in
@@ -240,7 +240,7 @@ cp/decl.o: cp/decl.c $(CXX_TREE_H) $(TM_H) flags.h cp/lex.h cp/decl.h stack.h \
cp/operators.def $(TM_P_H) tree-inline.h diagnostic.h c-pragma.h \
debug.h gt-cp-decl.h gtype-cp.h timevar.h
cp/decl2.o: cp/decl2.c $(CXX_TREE_H) $(TM_H) flags.h cp/lex.h cp/decl.h $(EXPR_H) \
- output.h except.h toplev.h $(RTL_H) c-common.h gt-cp-decl2.h
+ output.h except.h toplev.h $(RTL_H) c-common.h gt-cp-decl2.h cgraph.h
cp/typeck2.o: cp/typeck2.c $(CXX_TREE_H) $(TM_H) flags.h toplev.h output.h $(TM_P_H) \
diagnostic.h
cp/typeck.o: cp/typeck.c $(CXX_TREE_H) $(TM_H) flags.h $(RTL_H) $(EXPR_H) toplev.h \
@@ -271,7 +271,7 @@ cp/repo.o: cp/repo.c $(CXX_TREE_H) $(TM_H) toplev.h diagnostic.h \
gt-cp-repo.h
cp/semantics.o: cp/semantics.c $(CXX_TREE_H) $(TM_H) cp/lex.h except.h toplev.h \
flags.h debug.h output.h $(RTL_H) $(TIMEVAR_H) $(EXPR_H) \
- tree-inline.h
+ tree-inline.h cgraph.h
cp/dump.o: cp/dump.c $(CXX_TREE_H) $(TM_H) tree-dump.h
cp/optimize.o: cp/optimize.c $(CXX_TREE_H) $(TM_H) rtl.h integrate.h insn-config.h \
input.h $(PARAMS_H) debug.h tree-inline.h
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 6aab2ad..6e5bc8f 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -2749,7 +2749,7 @@ build_user_type_conversion (tree totype, tree expr, int flags)
tree
resolve_scoped_fn_name (tree scope, tree name)
{
- tree fn;
+ tree fn = NULL_TREE;
tree template_args = NULL_TREE;
bool is_template_id = TREE_CODE (name) == TEMPLATE_ID_EXPR;
diff --git a/gcc/cp/cp-lang.c b/gcc/cp/cp-lang.c
index f26317b..78a4e6b 100644
--- a/gcc/cp/cp-lang.c
+++ b/gcc/cp/cp-lang.c
@@ -150,6 +150,11 @@ static bool cp_var_mod_type_p (tree);
#undef LANG_HOOKS_PREPARE_ASSEMBLE_VARIABLE
#define LANG_HOOKS_PREPARE_ASSEMBLE_VARIABLE prepare_assemble_variable
+#undef LANG_HOOKS_CALLGRAPH_EXPAND_FUNCTION
+#define LANG_HOOKS_CALLGRAPH_EXPAND_FUNCTION expand_body
+#undef LANG_HOOKS_CALLGRAPH_LOWER_FUNCTION
+#define LANG_HOOKS_CALLGRAPH_LOWER_FUNCTION lower_function
+
#undef LANG_HOOKS_MAKE_TYPE
#define LANG_HOOKS_MAKE_TYPE cxx_make_type
#undef LANG_HOOKS_TYPE_FOR_MODE
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index aec80b3..8612b8c 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -1746,7 +1746,7 @@ struct lang_decl GTY(())
((at_eof && TREE_PUBLIC (DECL) && !DECL_COMDAT (DECL)) \
|| (DECL_ASSEMBLER_NAME_SET_P (DECL) \
&& TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (DECL))) \
- || (flag_syntax_only && TREE_USED (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
@@ -3800,6 +3800,7 @@ extern tree get_guard (tree);
extern tree get_guard_cond (tree);
extern tree set_guard (tree);
extern void prepare_assemble_variable (tree);
+extern void lower_function (tree);
extern void cp_error_at (const char *msgid, ...);
extern void cp_warning_at (const char *msgid, ...);
@@ -4151,6 +4152,7 @@ extern void clear_out_block (void);
extern tree begin_global_stmt_expr (void);
extern tree finish_global_stmt_expr (tree);
extern tree check_template_template_default_arg (tree);
+extern void expand_or_defer_fn (tree);
/* in tree.c */
extern void lang_check_failed (const char *, int,
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 24e8f78..863a21d 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -8446,7 +8446,7 @@ start_cleanup_fn (void)
static void
end_cleanup_fn (void)
{
- expand_body (finish_function (0));
+ expand_or_defer_fn (finish_function (0));
pop_from_top_level ();
}
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index d27bacd..a440c06 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -46,6 +46,8 @@ Boston, MA 02111-1307, USA. */
#include "cpplib.h"
#include "target.h"
#include "c-common.h"
+#include "cgraph.h"
+#include "tree-inline.h"
extern cpp_reader *parse_in;
/* This structure contains information about the initializations
@@ -1187,6 +1189,7 @@ defer_fn (tree fn)
if (DECL_DEFERRED_FN (fn))
return;
DECL_DEFERRED_FN (fn) = 1;
+ DECL_DEFER_OUTPUT (fn) = 1;
if (!deferred_fns)
VARRAY_TREE_INIT (deferred_fns, 32, "deferred_fns");
@@ -1671,6 +1674,11 @@ maybe_emit_vtables (tree ctype)
/* Write it out. */
import_export_vtable (vtbl, ctype, 1);
mark_vtable_entries (vtbl);
+
+ /* If we know that DECL is needed, mark it as such for the varpool. */
+ if (CLASSTYPE_EXPLICIT_INSTANTIATION (ctype))
+ cgraph_varpool_mark_needed_node (cgraph_varpool_node (vtbl));
+
if (TREE_TYPE (DECL_INITIAL (vtbl)) == 0)
store_init_value (vtbl, DECL_INITIAL (vtbl));
@@ -2010,7 +2018,7 @@ finish_objects (int method_type, int initp, tree body)
/* Finish up. */
finish_compound_stmt (/*has_no_scope=*/0, body);
fn = finish_function (0);
- expand_body (fn);
+ expand_or_defer_fn (fn);
/* When only doing semantic analysis, and no RTL generation, we
can't call functions that directly emit assembly code; there is
@@ -2163,7 +2171,7 @@ finish_static_storage_duration_function (tree body)
{
/* Close out the function. */
finish_compound_stmt (/*has_no_scope=*/0, body);
- expand_body (finish_function (0));
+ expand_or_defer_fn (finish_function (0));
}
/* Return the information about the indicated PRIORITY level. If no
@@ -2550,6 +2558,26 @@ generate_ctor_and_dtor_functions_for_priority (splay_tree_node n, void * data)
return 0;
}
+/* Callgraph code does not understand the member pointers. Mark the methods
+ referenced as used. */
+static tree
+mark_member_pointers (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED,
+ void *data ATTRIBUTE_UNUSED)
+{
+ if (TREE_CODE (*tp) == PTRMEM_CST)
+ cgraph_mark_needed_node (cgraph_node (PTRMEM_CST_MEMBER (*tp)), 1);
+ return 0;
+}
+
+/* Called via LANGHOOK_CALLGRAPH_LOWER_FUNCTION. It is supposed to lower
+ frontend specific constructs that would otherwise confuse the middle end. */
+void
+lower_function (tree fn)
+{
+ walk_tree_without_duplicates (&DECL_SAVED_TREE (fn), mark_member_pointers,
+ NULL);
+}
+
/* This routine is called from the last rule in yyparse ().
Its job is to create all the code needed to initialize and
destroy the global aggregates. We do the destruction
@@ -2787,20 +2815,16 @@ finish_file ()
if (!DECL_EXTERNAL (decl)
&& DECL_NEEDED_P (decl)
&& DECL_SAVED_TREE (decl)
- && !TREE_ASM_WRITTEN (decl))
+ && !TREE_ASM_WRITTEN (decl)
+ && (!flag_unit_at_a_time
+ || !cgraph_node (decl)->local.finalized))
{
- int saved_not_really_extern;
-
- /* When we call finish_function in expand_body, it will
- try to reset DECL_NOT_REALLY_EXTERN so we save and
- restore it here. */
- saved_not_really_extern = DECL_NOT_REALLY_EXTERN (decl);
+ /* We will output the function; no longer consider it in this
+ loop. */
+ DECL_DEFER_OUTPUT (decl) = 0;
/* Generate RTL for this function now that we know we
need it. */
- expand_body (decl);
- /* Undo the damage done by finish_function. */
- DECL_EXTERNAL (decl) = 0;
- DECL_NOT_REALLY_EXTERN (decl) = saved_not_really_extern;
+ expand_or_defer_fn (decl);
/* If we're compiling -fsyntax-only pretend that this
function has been written out so that we don't try to
expand it again. */
@@ -2810,10 +2834,6 @@ finish_file ()
}
}
- if (deferred_fns_used
- && wrapup_global_declarations (&VARRAY_TREE (deferred_fns, 0),
- deferred_fns_used))
- reconsider = true;
if (walk_namespaces (wrapup_globals_for_namespace, /*data=*/0))
reconsider = true;
@@ -2883,6 +2903,12 @@ finish_file ()
linkage now. */
pop_lang_context ();
+ if (flag_unit_at_a_time)
+ {
+ cgraph_finalize_compilation_unit ();
+ cgraph_optimize ();
+ }
+
/* Now, issue warnings about static, but not defined, functions,
etc., and emit debugging information. */
walk_namespaces (wrapup_globals_for_namespace, /*data=*/&reconsider);
diff --git a/gcc/cp/method.c b/gcc/cp/method.c
index cb2c864..e179d15 100644
--- a/gcc/cp/method.c
+++ b/gcc/cp/method.c
@@ -581,7 +581,7 @@ use_thunk (tree thunk_fndecl, bool emit_p)
/* Re-enable access control. */
pop_deferring_access_checks ();
- expand_body (finish_function (0));
+ expand_or_defer_fn (finish_function (0));
}
pop_from_top_level ();
@@ -862,7 +862,7 @@ synthesize_method (tree fndecl)
}
finish_function_body (stmt);
- expand_body (finish_function (0));
+ expand_or_defer_fn (finish_function (0));
extract_interface_info ();
if (! context)
diff --git a/gcc/cp/optimize.c b/gcc/cp/optimize.c
index b5d0f8f..4be829e 100644
--- a/gcc/cp/optimize.c
+++ b/gcc/cp/optimize.c
@@ -265,7 +265,7 @@ maybe_clone_body (tree fn)
/* Now, expand this function into RTL, if appropriate. */
finish_function (0);
BLOCK_ABSTRACT_ORIGIN (DECL_INITIAL (clone)) = DECL_INITIAL (fn);
- expand_body (clone);
+ expand_or_defer_fn (clone);
pop_from_top_level ();
}
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 173a62f..3654adb 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -13855,7 +13855,7 @@ cp_parser_function_definition_after_declarator (cp_parser* parser,
fn = finish_function ((ctor_initializer_p ? 1 : 0) |
(inline_p ? 2 : 0));
/* Generate code for it, if necessary. */
- expand_body (fn);
+ expand_or_defer_fn (fn);
/* Restore the saved values. */
parser->in_unbraced_linkage_specification_p
= saved_in_unbraced_linkage_specification_p;
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 2d80847..43fc5ab 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -10942,7 +10942,7 @@ instantiate_decl (tree d, int defer_ok)
/* Finish the function. */
d = finish_function (0);
- expand_body (d);
+ expand_or_defer_fn (d);
}
/* We're not deferring instantiation any more. */
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index a42443b..382bee5 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -41,6 +41,7 @@
#include "output.h"
#include "timevar.h"
#include "debug.h"
+#include "cgraph.h"
/* There routines provide a modular interface to perform many parsing
operations. They may therefore be used during actual parsing, or
@@ -2279,69 +2280,9 @@ expand_body (tree fn)
{
location_t saved_loc;
tree saved_function;
-
- /* When the parser calls us after finishing the body of a template
- function, we don't really want to expand the body. When we're
- processing an in-class definition of an inline function,
- PROCESSING_TEMPLATE_DECL will no longer be set here, so we have
- to look at the function itself. */
- if (processing_template_decl
- || (DECL_LANG_SPECIFIC (fn)
- && DECL_TEMPLATE_INFO (fn)
- && uses_template_parms (DECL_TI_ARGS (fn))))
- {
- /* Normally, collection only occurs in rest_of_compilation. So,
- if we don't collect here, we never collect junk generated
- during the processing of templates until we hit a
- non-template function. */
- ggc_collect ();
- return;
- }
-
- /* Replace AGGR_INIT_EXPRs with appropriate CALL_EXPRs. */
- walk_tree_without_duplicates (&DECL_SAVED_TREE (fn),
- simplify_aggr_init_exprs_r,
- NULL);
-
- /* If this is a constructor or destructor body, we have to clone
- it. */
- if (maybe_clone_body (fn))
- {
- /* We don't want to process FN again, so pretend we've written
- it out, even though we haven't. */
- TREE_ASM_WRITTEN (fn) = 1;
- return;
- }
-
- /* There's no reason to do any of the work here if we're only doing
- semantic analysis; this code just generates RTL. */
- if (flag_syntax_only)
- return;
-
- /* If possible, avoid generating RTL for this function. Instead,
- just record it as an inline function, and wait until end-of-file
- to decide whether to write it out or not. */
- if (/* We have to generate RTL if it's not an inline function. */
- (DECL_INLINE (fn) || DECL_COMDAT (fn))
- /* Or if we have to emit code for inline functions anyhow. */
- && !flag_keep_inline_functions
- /* Or if we actually have a reference to the function. */
- && !DECL_NEEDED_P (fn))
- {
- /* Set DECL_EXTERNAL so that assemble_external will be called as
- necessary. We'll clear it again in finish_file. */
- if (!DECL_EXTERNAL (fn))
- {
- DECL_NOT_REALLY_EXTERN (fn) = 1;
- DECL_EXTERNAL (fn) = 1;
- }
- /* Remember this function. In finish_file we'll decide if
- we actually need to write this function out. */
- defer_fn (fn);
- /* Let the back-end know that this function exists. */
- (*debug_hooks->deferred_inline_function) (fn);
- return;
- }
+
+ if (flag_unit_at_a_time && !cgraph_global_info_ready)
+ abort ();
/* Compute the appropriate object-file linkage for inline
functions. */
@@ -2413,6 +2354,108 @@ expand_body (tree fn)
emit_associated_thunks (fn);
}
+/* Generate RTL for FN. */
+
+void
+expand_or_defer_fn (fn)
+ tree fn;
+{
+ /* When the parser calls us after finishing the body of a template
+ function, we don't really want to expand the body. When we're
+ processing an in-class definition of an inline function,
+ PROCESSING_TEMPLATE_DECL will no longer be set here, so we have
+ to look at the function itself. */
+ if (processing_template_decl
+ || (DECL_LANG_SPECIFIC (fn)
+ && DECL_TEMPLATE_INFO (fn)
+ && uses_template_parms (DECL_TI_ARGS (fn))))
+ {
+ /* Normally, collection only occurs in rest_of_compilation. So,
+ if we don't collect here, we never collect junk generated
+ during the processing of templates until we hit a
+ non-template function. */
+ ggc_collect ();
+ return;
+ }
+
+ /* Replace AGGR_INIT_EXPRs with appropriate CALL_EXPRs. */
+ walk_tree_without_duplicates (&DECL_SAVED_TREE (fn),
+ simplify_aggr_init_exprs_r,
+ NULL);
+
+ /* If this is a constructor or destructor body, we have to clone
+ it. */
+ if (maybe_clone_body (fn))
+ {
+ /* We don't want to process FN again, so pretend we've written
+ it out, even though we haven't. */
+ TREE_ASM_WRITTEN (fn) = 1;
+ return;
+ }
+
+ /* There's no reason to do any of the work here if we're only doing
+ semantic analysis; this code just generates RTL. */
+ if (flag_syntax_only)
+ return;
+
+ if (flag_unit_at_a_time && cgraph_global_info_ready)
+ abort ();
+
+ if (flag_unit_at_a_time && !cgraph_global_info_ready)
+ {
+ if (at_eof)
+ {
+ /* Compute the appropriate object-file linkage for inline
+ functions. */
+ if (DECL_DECLARED_INLINE_P (fn))
+ import_export_decl (fn);
+ cgraph_finalize_function (fn, DECL_SAVED_TREE (fn));
+ }
+ else
+ {
+ if (!DECL_EXTERNAL (fn))
+ {
+ DECL_NOT_REALLY_EXTERN (fn) = 1;
+ DECL_EXTERNAL (fn) = 1;
+ }
+ /* Remember this function. In finish_file we'll decide if
+ we actually need to write this function out. */
+ defer_fn (fn);
+ /* Let the back-end know that this function exists. */
+ (*debug_hooks->deferred_inline_function) (fn);
+ }
+ return;
+ }
+
+
+ /* If possible, avoid generating RTL for this function. Instead,
+ just record it as an inline function, and wait until end-of-file
+ to decide whether to write it out or not. */
+ if (/* We have to generate RTL if it's not an inline function. */
+ (DECL_INLINE (fn) || DECL_COMDAT (fn))
+ /* Or if we have to emit code for inline functions anyhow. */
+ && !flag_keep_inline_functions
+ /* Or if we actually have a reference to the function. */
+ && !DECL_NEEDED_P (fn))
+ {
+ /* Set DECL_EXTERNAL so that assemble_external will be called as
+ necessary. We'll clear it again in finish_file. */
+ if (!DECL_EXTERNAL (fn))
+ {
+ DECL_NOT_REALLY_EXTERN (fn) = 1;
+ DECL_EXTERNAL (fn) = 1;
+ }
+ /* Remember this function. In finish_file we'll decide if
+ we actually need to write this function out. */
+ defer_fn (fn);
+ /* Let the back-end know that this function exists. */
+ (*debug_hooks->deferred_inline_function) (fn);
+ return;
+ }
+
+ expand_body (fn);
+}
+
/* Helper function for walk_tree, used by finish_function to override all
the RETURN_STMTs and pertinent CLEANUP_STMTs for the named return
value optimization. */