From 1ef0df4745a48b0ba491b460c041cfb720f0de46 Mon Sep 17 00:00:00 2001 From: Mark Mitchell Date: Fri, 9 Sep 2005 18:56:16 +0000 Subject: [PATCH] re PR c++/22252 (pragma interface/implementation still break synthesized methods) PR c++/22252 * decl.c (start_preparsed_function): Do not pay attention to #pragma interface for implicitly-defined methods. * decl2.c (cp_finish_file): Do not complain about uses of inline functions that have bodies, even if we decided not to emit the body in this translation unit. * semantics.c (note_decl_for_pch): Do not mess with linkage. (expand_or_defer_fn): Make inline, non-template functions COMDAT at this point. PR c++/22252 * g++.dg/ext/interface1.C: New test. * g++.dg/ext/interface1.h: Likewise. * g++.dg/ext/interface1a.cc: Likewise. From-SVN: r104103 --- gcc/cp/ChangeLog | 12 +++++++++ gcc/cp/decl.c | 16 +++++++++--- gcc/cp/decl2.c | 33 ++++++++++++++----------- gcc/cp/pt.c | 2 +- gcc/cp/semantics.c | 33 ++++++++++++++----------- gcc/testsuite/ChangeLog | 7 ++++++ gcc/testsuite/g++.dg/ext/interface1.C | 7 ++++++ gcc/testsuite/g++.dg/ext/interface1.h | 10 ++++++++ gcc/testsuite/g++.dg/ext/interface1a.cc | 4 +++ 9 files changed, 89 insertions(+), 35 deletions(-) create mode 100644 gcc/testsuite/g++.dg/ext/interface1.C create mode 100644 gcc/testsuite/g++.dg/ext/interface1.h create mode 100644 gcc/testsuite/g++.dg/ext/interface1a.cc diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 2967e18d8c7..ae12c20e2ff 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,15 @@ +2005-09-09 Mark Mitchell + + PR c++/22252 + * decl.c (start_preparsed_function): Do not pay attention to + #pragma interface for implicitly-defined methods. + * decl2.c (cp_finish_file): Do not complain about uses of inline + functions that have bodies, even if we decided not to emit the + body in this translation unit. + * semantics.c (note_decl_for_pch): Do not mess with linkage. + (expand_or_defer_fn): Make inline, non-template functions COMDAT + at this point. + 2005-09-08 Richard Henderson PR debug/23190 diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 50c1fd6406a..f33276144bf 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -10008,6 +10008,7 @@ start_preparsed_function (tree decl1, tree attrs, int flags) tree current_function_parms; struct c_fileinfo *finfo = get_fileinfo (lbasename (LOCATION_FILE (DECL_SOURCE_LOCATION (decl1)))); + bool honor_interface; /* Sanity check. */ gcc_assert (TREE_CODE (TREE_VALUE (void_list_node)) == VOID_TYPE); @@ -10222,6 +10223,15 @@ start_preparsed_function (tree decl1, tree attrs, int flags) } } + honor_interface = (!DECL_TEMPLATE_INSTANTIATION (decl1) + /* Implicitly-defined methods (like the + destructor for a class in which no destructor + is explicitly declared) must not be defined + until their definition is needed. So, we + ignore interface specifications for + compiler-generated functions. */ + && !DECL_ARTIFICIAL (decl1)); + if (DECL_INTERFACE_KNOWN (decl1)) { tree ctx = decl_function_context (decl1); @@ -10238,8 +10248,7 @@ start_preparsed_function (tree decl1, tree attrs, int flags) /* If this function belongs to an interface, it is public. If it belongs to someone else's interface, it is also external. This only affects inlines and template instantiations. */ - else if (finfo->interface_unknown == 0 - && ! DECL_TEMPLATE_INSTANTIATION (decl1)) + else if (!finfo->interface_unknown && honor_interface) { if (DECL_DECLARED_INLINE_P (decl1) || DECL_TEMPLATE_INSTANTIATION (decl1) @@ -10256,7 +10265,6 @@ start_preparsed_function (tree decl1, tree attrs, int flags) } else DECL_EXTERNAL (decl1) = 0; - DECL_NOT_REALLY_EXTERN (decl1) = 0; DECL_INTERFACE_KNOWN (decl1) = 1; /* If this function is in an interface implemented in this file, make sure that the backend knows to emit this function @@ -10265,7 +10273,7 @@ start_preparsed_function (tree decl1, tree attrs, int flags) mark_needed (decl1); } else if (finfo->interface_unknown && finfo->interface_only - && ! DECL_TEMPLATE_INSTANTIATION (decl1)) + && honor_interface) { /* If MULTIPLE_SYMBOL_SPACES is defined and we saw a #pragma interface, we will have both finfo->interface_unknown and diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index afb747fde40..8a7d7d61452 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -2976,18 +2976,22 @@ cp_finish_file (void) if (!DECL_SAVED_TREE (decl)) continue; - import_export_decl (decl); - /* We lie to the back-end, pretending that some functions are not defined when they really are. This keeps these functions from being put out unnecessarily. But, we must stop lying when the functions are referenced, or if they - are not comdat since they need to be put out now. This - is done in a separate for cycle, because if some deferred - function is contained in another deferred function later - in deferred_fns varray, rest_of_compilation would skip - this function and we really cannot expand the same - function twice. */ + are not comdat since they need to be put out now. If + DECL_INTERFACE_KNOWN, then we have already set + DECL_EXTERNAL appropriately, so there's no need to check + again, and we do not want to clear DECL_EXTERNAL if a + previous call to import_export_decl set it. + + This is done in a separate for cycle, because if some + deferred function is contained in another deferred + function later in deferred_fns varray, + rest_of_compilation would skip this function and we + really cannot expand the same function twice. */ + import_export_decl (decl); if (DECL_NOT_REALLY_EXTERN (decl) && DECL_INITIAL (decl) && decl_needed_p (decl)) @@ -3047,13 +3051,12 @@ cp_finish_file (void) 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 + /* If the definition actually was available here, then the + fact that the function was not defined merely represents + that for some reason (use of a template repository, + #pragma interface, etc.) we decided not to emit the + definition here. */ + && !DECL_INITIAL (decl) /* An explicit instantiation can be used to specify that the body is in another unit. It will have already verified there was a definition. */ diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index d6ab9dfbafc..f78da9338cc 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -5939,8 +5939,8 @@ tsubst_template_arg (tree t, tree args, tsubst_flags_t complain, tree in_decl) tf_error, /*in_decl=*/NULL_TREE, /*function_p=*/false); processing_template_decl = saved_processing_template_decl; + r = fold (r); } - r = fold (r); } } return r; diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index c7fd1bbf929..36914573e6e 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -2259,20 +2259,6 @@ note_decl_for_pch (tree decl) { gcc_assert (pch_file); - /* A non-template inline function with external linkage will always - be COMDAT. As we must eventually determine the linkage of all - functions, and as that causes writes to the data mapped in from - the PCH file, it's advantageous to mark the functions at this - point. */ - if (TREE_CODE (decl) == FUNCTION_DECL - && TREE_PUBLIC (decl) - && DECL_DECLARED_INLINE_P (decl) - && !DECL_IMPLICIT_INSTANTIATION (decl)) - { - comdat_linkage (decl); - DECL_INTERFACE_KNOWN (decl) = 1; - } - /* There's a good chance that we'll have to mangle names at some point, even if only for emission in debugging information. */ if (TREE_CODE (decl) == VAR_DECL @@ -3041,11 +3027,28 @@ expand_or_defer_fn (tree fn) these functions so that it can inline them as appropriate. */ if (DECL_DECLARED_INLINE_P (fn) || DECL_IMPLICIT_INSTANTIATION (fn)) { - if (!at_eof) + if (DECL_INTERFACE_KNOWN (fn)) + /* We've already made a decision as to how this function will + be handled. */; + else if (!at_eof) { DECL_EXTERNAL (fn) = 1; DECL_NOT_REALLY_EXTERN (fn) = 1; note_vague_linkage_fn (fn); + /* A non-template inline function with external linkage will + always be COMDAT. As we must eventually determine the + linkage of all functions, and as that causes writes to + the data mapped in from the PCH file, it's advantageous + to mark the functions at this point. */ + if (!DECL_IMPLICIT_INSTANTIATION (fn)) + { + /* This function must have external linkage, as + otherwise DECL_INTERFACE_KNOWN would have been + set. */ + gcc_assert (TREE_PUBLIC (fn)); + comdat_linkage (fn); + DECL_INTERFACE_KNOWN (fn) = 1; + } } else import_export_decl (fn); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index da40a592199..3942c3348a8 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2005-09-09 Mark Mitchell + + PR c++/22252 + * g++.dg/ext/interface1.C: New test. + * g++.dg/ext/interface1.h: Likewise. + * g++.dg/ext/interface1a.cc: Likewise. + 2005-09-09 Thomas Koenig * gfortran.dg/iomsg_1.f90: New test case. diff --git a/gcc/testsuite/g++.dg/ext/interface1.C b/gcc/testsuite/g++.dg/ext/interface1.C new file mode 100644 index 00000000000..0f803abc492 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/interface1.C @@ -0,0 +1,7 @@ +// PR c++/22252 +// { dg-do link } +// { dg-additional-sources "interface1a.cc" } +// { dg-options "-fno-inline" } + +#pragma implementation +#include "interface1.h" diff --git a/gcc/testsuite/g++.dg/ext/interface1.h b/gcc/testsuite/g++.dg/ext/interface1.h new file mode 100644 index 00000000000..ce91527b8b9 --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/interface1.h @@ -0,0 +1,10 @@ +#pragma interface +struct B +{ + B(){}; + ~B(){} +}; +struct A { + B a; + +}; diff --git a/gcc/testsuite/g++.dg/ext/interface1a.cc b/gcc/testsuite/g++.dg/ext/interface1a.cc new file mode 100644 index 00000000000..1859d5ce3ab --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/interface1a.cc @@ -0,0 +1,4 @@ +#include "interface1.h" +A a; +int main() {} +