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


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

C++ PATCH: PR 22252


This patch fixes PR c++/22252, a regression with #pragma interface,
another "fun" extension.

The basic problem is that #pragma interface shouldn't (and,
historically, didn't) apply to implicitly-declared class members,
because they are not supposed to be defined until needed.  We were
also issuing spurious messages about inline, but allegedly not-defined
methods.  (The methods were defined, but we decided that, to the
extent we needed an out-of-line copy, it was going somewhere else.)
Finally, g++.dg/pch/static-1.C popped out as a failure.  The problem
there was that we were setting DECL_INTERFACE_KNOWN in
note_decl_for_pch and then depending on people changing DECL_EXTERNAL
after that point, which doesn't make sense.  

Fundamentally, setting DECL_INTERFACE_KNOWN in note_decl_for_pch is
weird; either what we were doing there was safe, and always made
sense, or should not have been done at all; anything else just means
we're going to have weird skew between PCH and non-PCH builds.  I
think it's safe to do this all the time, so I've moved it into the
normal processing path.

Tested on x86_64-unknown-linux-gnu, applied on the mainline.  I do
intend to put this on the 4.0 branch, but I'll be a little surprised
if this doesn't break something somehow, in particular with respect to
the bits that used to be in note_decl_for_pch, so not yet applied on
the branch.

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

2005-09-09  Mark Mitchell  <mark@codesourcery.com>

	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-09  Mark Mitchell  <mark@codesourcery.com>

	PR c++/22252
	* g++.dg/ext/interface1.C: New test.
	* g++.dg/ext/interface1.h: Likewise.
	* g++.dg/ext/interface1a.cc: Likewise.

Index: cp/decl.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/decl.c,v
retrieving revision 1.1423
diff -c -5 -p -r1.1423 decl.c
*** cp/decl.c	6 Sep 2005 10:30:09 -0000	1.1423
--- cp/decl.c	9 Sep 2005 16:03:15 -0000
*************** start_preparsed_function (tree decl1, tr
*** 10005,10014 ****
--- 10005,10015 ----
    int doing_friend = 0;
    struct cp_binding_level *bl;
    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);
    gcc_assert (TREE_CHAIN (void_list_node) == NULL_TREE);
  
*************** start_preparsed_function (tree decl1, tr
*** 10219,10228 ****
--- 10220,10238 ----
  	  gcc_assert (DECL_NAME (t) == vtt_parm_identifier);
  	  current_vtt_parm = t;
  	}
      }
  
+   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);
  
        if (DECL_NOT_REALLY_EXTERN (decl1))
*************** start_preparsed_function (tree decl1, tr
*** 10235,10246 ****
  	comdat_linkage (decl1);
      }
    /* 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))
      {
        if (DECL_DECLARED_INLINE_P (decl1)
  	  || DECL_TEMPLATE_INSTANTIATION (decl1)
  	  || processing_template_decl)
  	{
--- 10245,10255 ----
  	comdat_linkage (decl1);
      }
    /* 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 && honor_interface)
      {
        if (DECL_DECLARED_INLINE_P (decl1)
  	  || DECL_TEMPLATE_INSTANTIATION (decl1)
  	  || processing_template_decl)
  	{
*************** start_preparsed_function (tree decl1, tr
*** 10253,10272 ****
  	  /* For WIN32 we also want to put these in linkonce sections.  */
  	  maybe_make_one_only (decl1);
  	}
        else
  	DECL_EXTERNAL (decl1) = 0;
-       DECL_NOT_REALLY_EXTERN (decl1) = 0;
        DECL_INTERFACE_KNOWN (decl1) = 1;
        /* If this function is in an interface implemented in this file,
  	 make sure that the backend knows to emit this function
  	 here.  */
        if (!DECL_EXTERNAL (decl1))
  	mark_needed (decl1);
      }
    else if (finfo->interface_unknown && finfo->interface_only
! 	   && ! DECL_TEMPLATE_INSTANTIATION (decl1))
      {
        /* If MULTIPLE_SYMBOL_SPACES is defined and we saw a #pragma
  	 interface, we will have both finfo->interface_unknown and
  	 finfo->interface_only set.  In that case, we don't want to
  	 use the normal heuristics because someone will supply a
--- 10262,10280 ----
  	  /* For WIN32 we also want to put these in linkonce sections.  */
  	  maybe_make_one_only (decl1);
  	}
        else
  	DECL_EXTERNAL (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 (finfo->interface_unknown && finfo->interface_only
! 	   && honor_interface)
      {
        /* If MULTIPLE_SYMBOL_SPACES is defined and we saw a #pragma
  	 interface, we will have both finfo->interface_unknown and
  	 finfo->interface_only set.  In that case, we don't want to
  	 use the normal heuristics because someone will supply a
Index: cp/decl2.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/decl2.c,v
retrieving revision 1.798
diff -c -5 -p -r1.798 decl2.c
*** cp/decl2.c	8 Sep 2005 18:56:40 -0000	1.798
--- cp/decl2.c	9 Sep 2005 16:03:15 -0000
*************** cp_finish_file (void)
*** 2974,2995 ****
  	    }
  
  	  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.  */
  	  if (DECL_NOT_REALLY_EXTERN (decl)
  	      && DECL_INITIAL (decl)
  	      && decl_needed_p (decl))
  	    DECL_EXTERNAL (decl) = 0;
  
--- 2974,2999 ----
  	    }
  
  	  if (!DECL_SAVED_TREE (decl))
  	    continue;
  
  	  /* 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.  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))
  	    DECL_EXTERNAL (decl) = 0;
  
*************** cp_finish_file (void)
*** 3045,3061 ****
      {
        if (/* Check online inline functions that were actually used.  */
  	  TREE_USED (decl) && DECL_DECLARED_INLINE_P (decl)
  	  /* But not defined.  */
  	  && DECL_REALLY_EXTERN (decl)
! 	  /* If we decided to emit this function in another
! 	     translation unit, the fact that the definition was
! 	     missing here likely indicates only that the repository
! 	     decided to place the function elsewhere.  With -Winline,
! 	     we will still warn if we could not inline the
! 	     function.  */
! 	  && !flag_use_repository
  	  /* An explicit instantiation can be used to specify
  	     that the body is in another unit. It will have
  	     already verified there was a definition.  */
  	  && !DECL_EXPLICIT_INSTANTIATION (decl))
  	{
--- 3049,3064 ----
      {
        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 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.  */
  	  && !DECL_EXPLICIT_INSTANTIATION (decl))
  	{
Index: cp/semantics.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/semantics.c,v
retrieving revision 1.487
diff -c -5 -p -r1.487 semantics.c
*** cp/semantics.c	6 Sep 2005 20:07:02 -0000	1.487
--- cp/semantics.c	9 Sep 2005 16:03:16 -0000
*************** finish_member_declaration (tree decl)
*** 2257,2280 ****
  void
  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
        || TREE_CODE (decl) == FUNCTION_DECL)
      mangle_decl (decl);
--- 2257,2266 ----
*************** expand_or_defer_fn (tree fn)
*** 3039,3053 ****
       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 functions 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);
  
        /* If the user wants us to keep all inline functions, then mark
--- 3025,3056 ----
       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 functions so that it can inline them as appropriate.  */
    if (DECL_DECLARED_INLINE_P (fn) || DECL_IMPLICIT_INSTANTIATION (fn))
      {
!       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);
  
        /* If the user wants us to keep all inline functions, then mark
Index: testsuite/g++.dg/ext/interface1.C
===================================================================
RCS file: testsuite/g++.dg/ext/interface1.C
diff -N testsuite/g++.dg/ext/interface1.C
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- testsuite/g++.dg/ext/interface1.C	9 Sep 2005 16:03:16 -0000
***************
*** 0 ****
--- 1,7 ----
+ // PR c++/22252
+ // { dg-do link }
+ // { dg-additional-sources "interface1a.cc" }
+ // { dg-options "-fno-inline" }
+ 
+ #pragma implementation 
+ #include "interface1.h"
Index: testsuite/g++.dg/ext/interface1.h
===================================================================
RCS file: testsuite/g++.dg/ext/interface1.h
diff -N testsuite/g++.dg/ext/interface1.h
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- testsuite/g++.dg/ext/interface1.h	9 Sep 2005 16:03:16 -0000
***************
*** 0 ****
--- 1,10 ----
+ #pragma interface
+ struct B
+ {
+   B(){};
+   ~B(){}
+ };
+ struct A {
+   B a;
+ 
+ };
Index: testsuite/g++.dg/ext/interface1a.cc
===================================================================
RCS file: testsuite/g++.dg/ext/interface1a.cc
diff -N testsuite/g++.dg/ext/interface1a.cc
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- testsuite/g++.dg/ext/interface1a.cc	9 Sep 2005 16:03:16 -0000
***************
*** 0 ****
--- 1,4 ----
+ #include "interface1.h"
+ A a;
+ int main() {}
+ 


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