From 15305a736f7cb40174ae276912806eaf077de783 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Sun, 16 Aug 2009 13:42:56 -0400 Subject: [PATCH] Make TREE_USED match the [basic.def.odr] concept for FUNCTION_DECL and VAR_DECL... Make TREE_USED match the [basic.def.odr] concept for FUNCTION_DECL and VAR_DECL, so mark_used only has effect the first time. * decl2.c (mark_used): Just return if TREE_USED is already set. Don't set TREE_USED if cp_unevaluated_operand is set. (tree_used_ok): New fn. * init.c (build_offset_ref): Check it instead of TREE_USED. * call.c (build_call_a): Likewise. * cp-tree.h: Declare it. (DECL_NO_LINKAGE_CHECKED): No longer needed. (struct lang_decl_base): Remove no_linkage_checked bitfield. From-SVN: r150807 --- gcc/cp/ChangeLog | 13 +++++- gcc/cp/call.c | 2 +- gcc/cp/cp-tree.h | 13 ++---- gcc/cp/decl2.c | 39 +++++++++------- gcc/cp/init.c | 2 +- gcc/cp/pt.c | 50 ++++++++++++--------- gcc/testsuite/ChangeLog | 4 ++ gcc/testsuite/g++.dg/debug/dwarf2/inline1.C | 18 ++++++++ 8 files changed, 93 insertions(+), 48 deletions(-) create mode 100644 gcc/testsuite/g++.dg/debug/dwarf2/inline1.C diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 9a694d922fa..b98842ee34d 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,4 +1,15 @@ -2009-08-15 Jason Merrill +2009-08-16 Jason Merrill + + Make TREE_USED match the [basic.def.odr] concept for FUNCTION_DECL + and VAR_DECL, so mark_used only has effect the first time. + * decl2.c (mark_used): Just return if TREE_USED is already set. + Don't set TREE_USED if cp_unevaluated_operand is set. + (tree_used_ok): New fn. + * init.c (build_offset_ref): Check it instead of TREE_USED. + * call.c (build_call_a): Likewise. + * cp-tree.h: Declare it. + (DECL_NO_LINKAGE_CHECKED): No longer needed. + (struct lang_decl_base): Remove no_linkage_checked bitfield. * decl2.c (finish_static_data_member_decl): Don't set TREE_USED. diff --git a/gcc/cp/call.c b/gcc/cp/call.c index f6a083bd677..30a1b45a1ed 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -318,7 +318,7 @@ build_call_a (tree function, int n, tree *argarray) && TREE_CODE (TREE_OPERAND (function, 0)) == FUNCTION_DECL) { decl = TREE_OPERAND (function, 0); - if (!TREE_USED (decl)) + if (!tree_used_ok (decl)) { /* We invoke build_call directly for several library functions. These may have been declared normally if diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index ae39110588b..bbd1a42f559 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -1579,9 +1579,8 @@ struct GTY(()) lang_decl_base { unsigned anticipated_p : 1; /* fn or type */ unsigned friend_attr : 1; /* fn or type */ unsigned template_conv_p : 1; /* template only? */ - unsigned no_linkage_checked : 1; /* var or fn */ unsigned u2sel : 1; - /* 1 spare bit */ + /* 2 spare bits */ }; /* True for DECL codes which have template info and access. */ @@ -1983,14 +1982,6 @@ struct GTY(()) lang_decl { (DECL_LANG_SPECIFIC (VAR_OR_FUNCTION_DECL_CHECK (DECL)) \ ->u.base.initialized_in_class) -/* Nonzero if we've checked whether DECL uses types without linkage in a - potentially invalid way. - ??? Instead, should fix mark_used to only set TREE_USED when we're - really using something, and just return if it's already set. */ -#define DECL_NO_LINKAGE_CHECKED(DECL) \ - (DECL_LANG_SPECIFIC (VAR_OR_FUNCTION_DECL_CHECK (DECL)) \ - ->u.base.no_linkage_checked) - /* Nonzero for DECL means that this decl is just a friend declaration, and should not be added to the list of members for this class. */ #define DECL_FRIEND_P(NODE) (DECL_LANG_SPECIFIC (NODE)->u.base.friend_attr) @@ -4486,6 +4477,7 @@ extern tree build_cleanup (tree); extern tree build_offset_ref_call_from_tree (tree, VEC(tree,gc) **); extern void check_default_args (tree); extern void mark_used (tree); +extern bool tree_used_ok (tree); extern void finish_static_data_member_decl (tree, tree, bool, tree, int); extern tree cp_build_parm_decl (tree, tree); extern tree get_guard (tree); @@ -4638,6 +4630,7 @@ extern void mark_decl_instantiated (tree, int); extern int more_specialized_fn (tree, tree, int); extern void do_decl_instantiation (tree, tree); extern void do_type_instantiation (tree, tree, tsubst_flags_t); +extern bool always_instantiate_p (tree); extern tree instantiate_decl (tree, int, bool); extern int comp_template_parms (const_tree, const_tree); extern bool uses_parameter_packs (tree); diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index f78508b99c3..e4ed9632b2d 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -3845,20 +3845,24 @@ mark_used (tree decl) decl = OVL_CURRENT (decl); } - TREE_USED (decl) = 1; - if (DECL_CLONED_FUNCTION_P (decl)) - TREE_USED (DECL_CLONED_FUNCTION (decl)) = 1; if (TREE_CODE (decl) == FUNCTION_DECL && DECL_DELETED_FN (decl)) { error ("deleted function %q+D", decl); error ("used here"); + TREE_USED (decl) = 1; return; } /* If we don't need a value, then we don't need to synthesize DECL. */ if (cp_unevaluated_operand != 0) return; + /* We only want to do this processing once. We don't need to keep trying + to instantiate inline templates, because unit-at-a-time will make sure + we get them compiled before functions that want to inline them. */ + if (TREE_USED (decl)) + return; + /* If within finish_function, defer the rest until that function finishes, otherwise it might recurse. */ if (defer_mark_used_calls) @@ -3892,6 +3896,10 @@ mark_used (tree decl) if (processing_template_decl) return; + TREE_USED (decl) = 1; + if (DECL_CLONED_FUNCTION_P (decl)) + TREE_USED (DECL_CLONED_FUNCTION (decl)) = 1; + /* DR 757: A type without linkage shall not be used as the type of a variable or function with linkage, unless o the variable or function has extern "C" linkage (7.5 [dcl.link]), or @@ -3900,10 +3908,8 @@ mark_used (tree decl) if (TREE_PUBLIC (decl) && (TREE_CODE (decl) == FUNCTION_DECL || TREE_CODE (decl) == VAR_DECL) - && DECL_LANG_SPECIFIC (decl) - && !DECL_NO_LINKAGE_CHECKED (decl)) + && DECL_LANG_SPECIFIC (decl)) { - DECL_NO_LINKAGE_CHECKED (decl) = true; if (!DECL_EXTERN_C_P (decl) && !DECL_ARTIFICIAL (decl) && !decl_defined_p (decl) @@ -3949,15 +3955,7 @@ mark_used (tree decl) else if ((DECL_NON_THUNK_FUNCTION_P (decl) || TREE_CODE (decl) == VAR_DECL) && DECL_LANG_SPECIFIC (decl) && DECL_TEMPLATE_INFO (decl) && (!DECL_EXPLICIT_INSTANTIATION (decl) - || (TREE_CODE (decl) == FUNCTION_DECL - && possibly_inlined_p - (DECL_TEMPLATE_RESULT ( - template_for_substitution (decl)))) - /* We need to instantiate static data members so that there - initializers are available in integral constant - expressions. */ - || (TREE_CODE (decl) == VAR_DECL - && DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl)))) + || always_instantiate_p (decl))) /* If this is a function or variable that is an instance of some template, we now know that we will need to actually do the instantiation. We check that DECL is not an explicit @@ -3973,4 +3971,15 @@ mark_used (tree decl) processing_template_decl = saved_processing_template_decl; } +/* Use this function to verify that mark_used has been called + previously. That is, either TREE_USED is set, or we're in a + context that doesn't set it. */ + +bool +tree_used_ok (tree decl) +{ + return (TREE_USED (decl) || cp_unevaluated_operand + || defer_mark_used_calls || processing_template_decl); +} + #include "gt-cp-decl2.h" diff --git a/gcc/cp/init.c b/gcc/cp/init.c index ef18a6c1041..9dac7de400e 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -1502,7 +1502,7 @@ build_offset_ref (tree type, tree member, bool address_p) gcc_assert (DECL_P (member) || BASELINK_P (member)); /* Callers should call mark_used before this point. */ - gcc_assert (!DECL_P (member) || TREE_USED (member)); + gcc_assert (!DECL_P (member) || tree_used_ok (member)); if (!COMPLETE_TYPE_P (complete_type (type)) && !TYPE_BEING_DEFINED (type)) diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 36f1b00fa6b..eb43271e850 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -15635,6 +15635,27 @@ template_for_substitution (tree decl) return tmpl; } +/* Returns true if we need to instantiate this template instance even if we + know we aren't going to emit it.. */ + +bool +always_instantiate_p (tree decl) +{ + /* We always instantiate inline functions so that we can inline them. An + explicit instantiation declaration prohibits implicit instantiation of + non-inline functions. With high levels of optimization, we would + normally inline non-inline functions -- but we're not allowed to do + that for "extern template" functions. Therefore, we check + DECL_DECLARED_INLINE_P, rather than possibly_inlined_p. */ + return ((TREE_CODE (decl) == FUNCTION_DECL + && DECL_DECLARED_INLINE_P (decl)) + /* And we need to instantiate static data members so that + their initializers are available in integral constant + expressions. */ + || (TREE_CODE (decl) == VAR_DECL + && DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl))); +} + /* Produce the definition of D, a _DECL generated from a template. If DEFER_OK is nonzero, then we don't have to actually do the instantiation now; we just have to do it sometime. Normally it is @@ -15688,6 +15709,15 @@ instantiate_decl (tree d, int defer_ok, the instantiation. */ return d; + /* Check to see whether we know that this template will be + instantiated in some other file, as with "extern template" + extension. */ + external_p = (DECL_INTERFACE_KNOWN (d) && DECL_REALLY_EXTERN (d)); + + /* In general, we do not instantiate such templates. */ + if (external_p && !always_instantiate_p (d)) + return d; + gen_tmpl = most_general_template (tmpl); gen_args = DECL_TI_ARGS (d); @@ -15781,26 +15811,6 @@ instantiate_decl (tree d, int defer_ok, pop_access_scope (d); } - /* Check to see whether we know that this template will be - instantiated in some other file, as with "extern template" - extension. */ - external_p = (DECL_INTERFACE_KNOWN (d) && DECL_REALLY_EXTERN (d)); - /* In general, we do not instantiate such templates... */ - if (external_p - /* ... but we instantiate inline functions so that we can inline - them. An explicit instantiation declaration prohibits implicit - instantiation of non-inline functions. With high levels of - optimization, we would normally inline non-inline functions - -- but we're not allowed to do that for "extern template" functions. - Therefore, we check DECL_DECLARED_INLINE_P, rather than - possibly_inlined_p. And ... */ - && ! (TREE_CODE (d) == FUNCTION_DECL - && DECL_DECLARED_INLINE_P (d)) - /* ... we instantiate static data members whose values are - needed in integral constant expressions. */ - && ! (TREE_CODE (d) == VAR_DECL - && DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (d))) - goto out; /* Defer all other templates, unless we have been explicitly forbidden from doing so. */ if (/* If there is no definition, we cannot instantiate the diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index acbc928700c..83eda2ffac2 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2009-08-16 Jason Merrill + + * g++.dg/debug/dwarf2/inline1.C: New. + 2009-08-16 Richard Sandiford PR target/38599 diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/inline1.C b/gcc/testsuite/g++.dg/debug/dwarf2/inline1.C new file mode 100644 index 00000000000..ea405f85339 --- /dev/null +++ b/gcc/testsuite/g++.dg/debug/dwarf2/inline1.C @@ -0,0 +1,18 @@ +// This isn't really testing dwarf output, but rather that we can inline f +// even though the call precedes the definition. + +// { dg-options "-gdwarf-2 -dA -O" } +// { dg-final { scan-assembler "DW_TAG_inlined_subroutine" } } + +template +inline T f(T); + +int main() +{ + f(1); +} + +int i; + +template +inline T f(T t) { ++i; return t; }