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 21687


We were missing ggc_push_context calls around functions in local
classes; we want to collect within those functions, but we have local
state that is not in GC roots.  Someone else had tried to fix this
before with a change that acknowledged itself as a hack; not only did
the hack not work, but it was probably actively dangerous, as we use
function_depth for other things....

Tested on x86_64-unknown-linux-gnu, applied on the mainline and on the
4.0 branch..

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

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

	PR c++/21687
	* parser.c (cp_parser_class_specifier): Push/pop GC contexts
	around functions in local classes.

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

	PR c++/21687
	* g++.dg/other/gc3.C: New test.

Index: gcc/cp/parser.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/parser.c,v
retrieving revision 1.351
diff -c -5 -p -r1.351 parser.c
*** gcc/cp/parser.c	24 Aug 2005 10:21:31 -0000	1.351
--- gcc/cp/parser.c	2 Sep 2005 15:49:41 -0000
*************** cp_parser_class_specifier (cp_parser* pa
*** 12669,12679 ****
      {
        tree queue_entry;
        tree fn;
        tree class_type = NULL_TREE;
        tree pushed_scope = NULL_TREE;
! 
        /* In a first pass, parse default arguments to the functions.
  	 Then, in a second pass, parse the bodies of the functions.
  	 This two-phased approach handles cases like:
  
  	    struct S {
--- 12669,12682 ----
      {
        tree queue_entry;
        tree fn;
        tree class_type = NULL_TREE;
        tree pushed_scope = NULL_TREE;
!       /* True if we have called ggc_push_context, and therefore need
! 	 to make a matching call to ggc_pop_context.  */
!       bool need_ggc_pop_context;
!  
        /* In a first pass, parse default arguments to the functions.
  	 Then, in a second pass, parse the bodies of the functions.
  	 This two-phased approach handles cases like:
  
  	    struct S {
*************** cp_parser_class_specifier (cp_parser* pa
*** 12705,12731 ****
  	  /* Remove any template parameters from the symbol table.  */
  	  maybe_end_member_template_processing ();
  	}
        if (pushed_scope)
  	pop_scope (pushed_scope);
        /* Now parse the body of the functions.  */
        for (TREE_VALUE (parser->unparsed_functions_queues)
  	     = nreverse (TREE_VALUE (parser->unparsed_functions_queues));
  	   (queue_entry = TREE_VALUE (parser->unparsed_functions_queues));
  	   TREE_VALUE (parser->unparsed_functions_queues)
  	     = TREE_CHAIN (TREE_VALUE (parser->unparsed_functions_queues)))
  	{
  	  /* Figure out which function we need to process.  */
  	  fn = TREE_VALUE (queue_entry);
! 
! 	  /* A hack to prevent garbage collection.  */
! 	  function_depth++;
! 
  	  /* Parse the function.  */
  	  cp_parser_late_parsing_for_member (parser, fn);
- 	  function_depth--;
  	}
      }
  
    /* Put back any saved access checks.  */
    pop_deferring_access_checks ();
  
--- 12708,12742 ----
  	  /* Remove any template parameters from the symbol table.  */
  	  maybe_end_member_template_processing ();
  	}
        if (pushed_scope)
  	pop_scope (pushed_scope);
+       need_ggc_pop_context = false;
        /* Now parse the body of the functions.  */
        for (TREE_VALUE (parser->unparsed_functions_queues)
  	     = nreverse (TREE_VALUE (parser->unparsed_functions_queues));
  	   (queue_entry = TREE_VALUE (parser->unparsed_functions_queues));
  	   TREE_VALUE (parser->unparsed_functions_queues)
  	     = TREE_CHAIN (TREE_VALUE (parser->unparsed_functions_queues)))
  	{
  	  /* Figure out which function we need to process.  */
  	  fn = TREE_VALUE (queue_entry);
! 	  /* We call ggc_collect after processing a function body in
! 	     order to clean up garbage generated.  If we're processing
! 	     a local class, however, then we must not clean up stuff
! 	     from the function containing the class, so we have to
! 	     push a new garbage-collection context.  */
! 	  if (function_depth && !need_ggc_pop_context)
! 	    {
! 	      need_ggc_pop_context = true;
! 	      ggc_push_context ();
! 	    }
  	  /* Parse the function.  */
  	  cp_parser_late_parsing_for_member (parser, fn);
  	}
+       if (need_ggc_pop_context)
+ 	ggc_pop_context ();
      }
  
    /* Put back any saved access checks.  */
    pop_deferring_access_checks ();
  
Index: gcc/testsuite/g++.dg/other/gc3.C
===================================================================
RCS file: gcc/testsuite/g++.dg/other/gc3.C
diff -N gcc/testsuite/g++.dg/other/gc3.C
*** /dev/null	1 Jan 1970 00:00:00 -0000
--- gcc/testsuite/g++.dg/other/gc3.C	2 Sep 2005 15:49:41 -0000
***************
*** 0 ****
--- 1,8 ----
+ // PR c++/21687
+ // { dg-options "--param ggc-min-expand=0 --param ggc-min-heapsize=0" }
+ 
+ template <class Union>
+ void perform_test_trivial() {
+   struct check_union {  void perform_test_trivial() {} };
+ }
+ 


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