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] Fix PR6749 (infinite loop generating vtable)


Hi

This patch fixes an infinite loop: generating a vtable may trigger
template instantiation of function template which is virtual.  This
in turn can cause another vtable to be generated.  And this could
continue forever.  With the patch, the option -ftemplate-depth
to limit the number of such attempts.

Since the function 'instantiate_pending_templates', modified by this
patch, is only used by 'finish_file' and its return type is never used.
I simplify this as well.

Tested on i686-pc-linux-gnu with no regressions.  OK for mainline?

--Kriang


2004-08-15  Kriang Lerdsuwanakij  <lerdsuwa@users.sourceforge.net>

	PR c++/6749
	* pt.c (instantiate_pending_templates): Add int parameter.  Don't
	return anything.
	* cp-tree.h (instantiate_pending_templates): Adjust prototype.
	* decl2.c (finish_file): Adjust call to
	instantiate_pending_templates.

2004-08-15  Kriang Lerdsuwanakij  <lerdsuwa@users.sourceforge.net>

	PR c++/6749
	* g++.dg/template/vtable2.C: New test.


diff -cprN gcc-main-save/gcc/cp/cp-tree.h gcc-main-new/gcc/cp/cp-tree.h
*** gcc-main-save/gcc/cp/cp-tree.h	Thu Aug  5 21:33:50 2004
--- gcc-main-new/gcc/cp/cp-tree.h	Sat Aug 14 22:32:10 2004
*************** extern void maybe_process_partial_specia
*** 3990,3996 ****
  extern void maybe_check_template_type           (tree);
  extern tree most_specialized_instantiation      (tree);
  extern void print_candidates                    (tree);
! extern int instantiate_pending_templates        (void);
  extern tree tsubst_default_argument             (tree, tree, tree);
  extern tree tsubst_copy_and_build               (tree, tree, tsubst_flags_t, tree, bool);
  extern tree most_general_template		(tree);
--- 3990,3996 ----
  extern void maybe_check_template_type           (tree);
  extern tree most_specialized_instantiation      (tree);
  extern void print_candidates                    (tree);
! extern void instantiate_pending_templates       (int);
  extern tree tsubst_default_argument             (tree, tree, tree);
  extern tree tsubst_copy_and_build               (tree, tree, tsubst_flags_t, tree, bool);
  extern tree most_general_template		(tree);
diff -cprN gcc-main-save/gcc/cp/decl2.c gcc-main-new/gcc/cp/decl2.c
*** gcc-main-save/gcc/cp/decl2.c	Sat Aug 14 14:25:54 2004
--- gcc-main-new/gcc/cp/decl2.c	Sun Aug 15 22:23:20 2004
*************** finish_file (void)
*** 2719,2724 ****
--- 2719,2725 ----
    size_t i;
    location_t locus;
    unsigned ssdf_count = 0;
+   int retries = 0;
  
    locus = input_location;
    at_eof = 1;
*************** finish_file (void)
*** 2770,2776 ****
  
        /* If there are templates that we've put off instantiating, do
  	 them now.  */
!       instantiate_pending_templates ();
        ggc_collect ();
  
        /* Write out virtual tables as required.  Note that writing out
--- 2771,2777 ----
  
        /* If there are templates that we've put off instantiating, do
  	 them now.  */
!       instantiate_pending_templates (retries);
        ggc_collect ();
  
        /* Write out virtual tables as required.  Note that writing out
*************** finish_file (void)
*** 2778,2784 ****
   	 instantiation of members of that class.  If we write out
   	 vtables then we remove the class from our list so we don't
   	 have to look at it again.  */
!  
        while (keyed_classes != NULL_TREE
   	     && maybe_emit_vtables (TREE_VALUE (keyed_classes)))
   	{
--- 2779,2785 ----
   	 instantiation of members of that class.  If we write out
   	 vtables then we remove the class from our list so we don't
   	 have to look at it again.  */
! 
        while (keyed_classes != NULL_TREE
   	     && maybe_emit_vtables (TREE_VALUE (keyed_classes)))
   	{
*************** finish_file (void)
*** 2804,2817 ****
   	      next = TREE_CHAIN (t);
   	    }
   	}
!        
        /* Write out needed type info variables.  We have to be careful
   	 looping through unemitted decls, because emit_tinfo_decl may
   	 cause other variables to be needed.  We stick new elements
   	 (and old elements that we may need to reconsider) at the end
   	 of the array, then shift them back to the beginning once we're
   	 done.  */
!   
        n_old = VARRAY_ACTIVE_SIZE (unemitted_tinfo_decls);
        for (i = 0; i < n_old; ++i)
    	{
--- 2805,2818 ----
   	      next = TREE_CHAIN (t);
   	    }
   	}
! 
        /* Write out needed type info variables.  We have to be careful
   	 looping through unemitted decls, because emit_tinfo_decl may
   	 cause other variables to be needed.  We stick new elements
   	 (and old elements that we may need to reconsider) at the end
   	 of the array, then shift them back to the beginning once we're
   	 done.  */
! 
        n_old = VARRAY_ACTIVE_SIZE (unemitted_tinfo_decls);
        for (i = 0; i < n_old; ++i)
    	{
*************** finish_file (void)
*** 2992,2997 ****
--- 2993,3000 ----
  	reconsider = true;
        if (cgraph_varpool_assemble_pending_decls ())
  	reconsider = true;
+ 
+       retries++;
      } 
    while (reconsider);
  
diff -cprN gcc-main-save/gcc/cp/pt.c gcc-main-new/gcc/cp/pt.c
*** gcc-main-save/gcc/cp/pt.c	Sat Aug 14 14:25:54 2004
--- gcc-main-new/gcc/cp/pt.c	Sun Aug 15 22:22:43 2004
*************** out:
*** 11272,11288 ****
  }
  
  /* Run through the list of templates that we wish we could
!    instantiate, and instantiate any we can.  */
  
! int
! instantiate_pending_templates (void)
  {
    tree *t;
    tree last = NULL_TREE;
-   int instantiated_something = 0;
    int reconsider;
    location_t saved_loc = input_location;
!   
    do 
      {
        reconsider = 0;
--- 11272,11301 ----
  }
  
  /* Run through the list of templates that we wish we could
!    instantiate, and instantiate any we can.  RETRIES is the
!    number of times we retry pending template instantiation.  */
  
! void
! instantiate_pending_templates (int retries)
  {
    tree *t;
    tree last = NULL_TREE;
    int reconsider;
    location_t saved_loc = input_location;
! 
!   /* Instantiating templates may trigger vtable generation.  This in turn
!      may require further template instantiations.  We place a limit here
!      to avoid infinite loop.  */
!   if (pending_templates && retries >= max_tinst_depth)
!     {
!       cp_error_at ("template instantiation depth exceeds maximum of %d"
! 		   " (use -ftemplate-depth-NN to increase the maximum)"
! 		   " instantiating `%+D', possibly from virtual table"
! 		   " generation",
! 		   max_tinst_depth, TREE_VALUE (pending_templates));
!       return;
!     }
! 
    do 
      {
        reconsider = 0;
*************** instantiate_pending_templates (void)
*** 11309,11318 ****
  			instantiate_decl (fn, /*defer_ok=*/0,
  					  /*undefined_ok=*/0);
  		  if (COMPLETE_TYPE_P (instantiation))
! 		    {
! 		      instantiated_something = 1;
! 		      reconsider = 1;
! 		    }
  		}
  
  	      if (COMPLETE_TYPE_P (instantiation))
--- 11322,11328 ----
  			instantiate_decl (fn, /*defer_ok=*/0,
  					  /*undefined_ok=*/0);
  		  if (COMPLETE_TYPE_P (instantiation))
! 		    reconsider = 1;
  		}
  
  	      if (COMPLETE_TYPE_P (instantiation))
*************** instantiate_pending_templates (void)
*** 11334,11343 ****
  						    /*defer_ok=*/0,
  						    /*undefined_ok=*/0);
  		  if (DECL_TEMPLATE_INSTANTIATED (instantiation))
! 		    {
! 		      instantiated_something = 1;
! 		      reconsider = 1;
! 		    }
  		}
  
  	      if (DECL_TEMPLATE_SPECIALIZATION (instantiation)
--- 11344,11350 ----
  						    /*defer_ok=*/0,
  						    /*undefined_ok=*/0);
  		  if (DECL_TEMPLATE_INSTANTIATED (instantiation))
! 		    reconsider = 1;
  		}
  
  	      if (DECL_TEMPLATE_SPECIALIZATION (instantiation)
*************** instantiate_pending_templates (void)
*** 11359,11365 ****
    while (reconsider);
  
    input_location = saved_loc;
-   return instantiated_something;
  }
  
  /* Substitute ARGVEC into T, which is a list of initializers for
--- 11366,11371 ----
diff -cprN gcc-main-save/gcc/testsuite/g++.dg/template/vtable2.C gcc-main-new/gcc/testsuite/g++.dg/template/vtable2.C
*** gcc-main-save/gcc/testsuite/g++.dg/template/vtable2.C	Thu Jan  1 07:00:00 1970
--- gcc-main-new/gcc/testsuite/g++.dg/template/vtable2.C	Sat Aug 14 23:03:08 2004
***************
*** 0 ****
--- 1,18 ----
+ // Use a small template instantiation depth to speed up testing 
+ // { dg-options "-ftemplate-depth-5" }
+ // { dg-do compile }
+ 
+ // Origin: rullo.pat@tiscalinet.it
+ //	   Nathanael Nerode <neroden@gcc.gnu.org>
+ //	   Wolfgang Bangerth <bangerth@dealii.org>
+ 
+ // PR c++/6749: Infinite loop generating vtable.
+ 
+ template <class T> struct inner {};
+ 
+ template <class T> struct parent {
+   virtual void f()
+     { parent<inner<T> > p; };		// { dg-error "instantiation depth" }
+ };
+ 
+ template struct parent<int>;


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