C++ PATCH: More memory savings

Mark Mitchell mark@codesourcery.com
Thu Apr 6 09:28:00 GMT 2000


This patch saves some additional space and time by avoiding generating
RTL for even more functions that we did previously.  (It's roughly an
invariant of the C++ front-end that RTL should only be generated for
functions that are actually going to be written out, and that RTL
should never be saved across functions.)  Good for an additional 4MB
on the test case I've been working with the last couple of days.

As a side-effect, we actually improve our warning situation.  In
particular, GCC warns about falling off the end of a function only
when RTL is generated, and it doesn't do a very good job if
`DECL_DEFER_OUTPUT' is set.  (That's probably a bug in the back-end.)
That meant that, in the past, we didn't warn about a lot of functions
that fell off the end in g++, even when they were actually put out in
the object file.  Now, in contrast, we warn about all such functions
-- but fail to warn about some that we do not put out.  That's not
perfect, but it's certainly better; at least if the function will
actually be used we're warning about it.  That change accounts for the
testsuite patches here.

--
Mark Mitchell                   mark@codesourcery.com
CodeSourcery, LLC               http://www.codesourcery.com

2000-04-06  Mark Mitchell  <mark@codesourcery.com>

	* cp-tree.h (lang_decl_flags): Rename saved_inline to deferred.
	(DECL_SAVED_INLINE): Rename to ...
	(DECL_DEFERRED_FN): ... this.
	(in_function_p): Remove declaration.
	(mark_inline_for_output): Rename to ... 
	(defer_fn): ... this.
	* decl.c (finish_function): Adjust call to mark_inline_for_output.
	(in_function_p): Remove definition.
	* decl2.c (saved_inlines): Rename to ...
	(deferred_fns): ... this.
	(saved_inlines_used): Rename to ...
	(deferred_fns_used): ... this.
	(mark_inline_for_output): Rename to ...
	(defer_fn): ... this.
	(finish_file): Adjust accordingly.
	(init_decl2): Likewise.
	* lex.c (cons_up_default_function): Likewise.
	* pt.c (mark_decl_instantiated): Likewise.
	(instantiate_decl): Don't set DECL_DEFER_OUTPUT under any
	circumstances.
	* rtti.c (get_tinfo_decl): Adjust call to mark_inline_for_output.
	* semantics.c (expand_body): Defer more functions.

Index: cp-tree.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/cp-tree.h,v
retrieving revision 1.431
diff -c -p -r1.431 cp-tree.h
*** cp-tree.h	2000/04/06 03:12:18	1.431
--- cp-tree.h	2000/04/06 16:07:52
*************** struct lang_decl_flags
*** 1830,1836 ****
    unsigned constructor_for_vbase_attr : 1;
  
    unsigned mutable_flag : 1;
!   unsigned saved_inline : 1;
    unsigned use_template : 2;
    unsigned nonconverting : 1;
    unsigned declared_inline : 1;
--- 1830,1836 ----
    unsigned constructor_for_vbase_attr : 1;
  
    unsigned mutable_flag : 1;
!   unsigned deferred : 1;
    unsigned use_template : 2;
    unsigned nonconverting : 1;
    unsigned declared_inline : 1;
*************** struct lang_decl
*** 2104,2112 ****
  #define DECL_SORTED_FIELDS(NODE) \
  	(DECL_LANG_SPECIFIC (TYPE_DECL_CHECK (NODE))->u.sorted_fields)
  
! /* True if on the saved_inlines (see decl2.c) list.  */
! #define DECL_SAVED_INLINE(DECL) \
!   (DECL_LANG_SPECIFIC(DECL)->decl_flags.saved_inline)
  
  /* For a VAR_DECL, FUNCTION_DECL, TYPE_DECL or TEMPLATE_DECL:
     template-specific information.  */
--- 2104,2112 ----
  #define DECL_SORTED_FIELDS(NODE) \
  	(DECL_LANG_SPECIFIC (TYPE_DECL_CHECK (NODE))->u.sorted_fields)
  
! /* True if on the deferred_fns (see decl2.c) list.  */
! #define DECL_DEFERRED_FN(DECL) \
!   (DECL_LANG_SPECIFIC(DECL)->decl_flags.deferred)
  
  /* For a VAR_DECL, FUNCTION_DECL, TYPE_DECL or TEMPLATE_DECL:
     template-specific information.  */
*************** extern tree maybe_build_cleanup_and_dele
*** 3837,3843 ****
  extern tree maybe_build_cleanup			PARAMS ((tree));
  extern void cplus_expand_expr_stmt		PARAMS ((tree));
  extern void finish_stmt				PARAMS ((void));
- extern int in_function_p			PARAMS ((void));
  extern void replace_defarg			PARAMS ((tree, tree));
  extern void print_other_binding_stack		PARAMS ((struct binding_level *));
  extern void revert_static_member_fn             PARAMS ((tree));
--- 3837,3842 ----
*************** extern void cplus_decl_attributes		PARAM
*** 3898,3904 ****
  extern tree constructor_name_full		PARAMS ((tree));
  extern tree constructor_name			PARAMS ((tree));
  extern void setup_vtbl_ptr			PARAMS ((void));
! extern void mark_inline_for_output		PARAMS ((tree));
  extern tree get_temp_name			PARAMS ((tree, int));
  extern void finish_anon_union			PARAMS ((tree));
  extern tree finish_table			PARAMS ((tree, tree, tree, int));
--- 3897,3903 ----
  extern tree constructor_name_full		PARAMS ((tree));
  extern tree constructor_name			PARAMS ((tree));
  extern void setup_vtbl_ptr			PARAMS ((void));
! extern void defer_fn             		PARAMS ((tree));
  extern tree get_temp_name			PARAMS ((tree, int));
  extern void finish_anon_union			PARAMS ((tree));
  extern tree finish_table			PARAMS ((tree, tree, tree, int));
Index: decl.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/decl.c,v
retrieving revision 1.580
diff -c -p -r1.580 decl.c
*** decl.c	2000/04/06 00:51:24	1.580
--- decl.c	2000/04/06 16:08:01
*************** finish_function (lineno, flags)
*** 14153,14159 ****
  	  if (! DECL_EXTERNAL (fndecl))
  	    DECL_NOT_REALLY_EXTERN (fndecl) = 1;
  	  DECL_EXTERNAL (fndecl) = 1;
! 	  mark_inline_for_output (fndecl);
  	}
  
  #if 0
--- 14153,14159 ----
  	  if (! DECL_EXTERNAL (fndecl))
  	    DECL_NOT_REALLY_EXTERN (fndecl) = 1;
  	  DECL_EXTERNAL (fndecl) = 1;
! 	  defer_fn (fndecl);
  	}
  
  #if 0
*************** mark_cp_function_context (f)
*** 14669,14681 ****
  {
    mark_lang_function (f->language);
  }
- 
- int
- in_function_p ()
- {
-   return function_depth != 0;
- }
- 
  
  void
  lang_mark_false_label_stack (l)
--- 14669,14674 ----
Index: decl2.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/decl2.c,v
retrieving revision 1.325
diff -c -p -r1.325 decl2.c
*** decl2.c	2000/04/06 03:12:19	1.325
--- decl2.c	2000/04/06 16:08:04
*************** static varray_type pending_statics;
*** 108,116 ****
  
  /* A list of functions which were declared inline, but which we
     may need to emit outline anyway.  */
! static varray_type saved_inlines;
! #define saved_inlines_used \
!   (saved_inlines ? saved_inlines->elements_used : 0)
  
  /* Same, but not reset.  Local temp variables and global temp variables
     can have the same name.  */
--- 108,116 ----
  
  /* A list of functions which were declared inline, but which we
     may need to emit outline anyway.  */
! static varray_type deferred_fns;
! #define deferred_fns_used \
!   (deferred_fns ? deferred_fns->elements_used : 0)
  
  /* Same, but not reset.  Local temp variables and global temp variables
     can have the same name.  */
*************** constructor_name (thing)
*** 1976,1995 ****
    return t;
  }
  
! /* Record the existence of an addressable inline function.  */
  
  void
! mark_inline_for_output (decl)
!      tree decl;
  {
!   decl = DECL_MAIN_VARIANT (decl);
!   if (DECL_SAVED_INLINE (decl))
      return;
!   DECL_SAVED_INLINE (decl) = 1;
!   if (!saved_inlines)
!     VARRAY_TREE_INIT (saved_inlines, 32, "saved_inlines");
  
!   VARRAY_PUSH_TREE (saved_inlines, decl);
  }
  
  /* Hand off a unique name which can be used for variable we don't really
--- 1976,1995 ----
    return t;
  }
  
! /* Defer the compilation of the FN until the end of compilation.  */
  
  void
! defer_fn (fn)
!      tree fn;
  {
!   fn = DECL_MAIN_VARIANT (fn);
!   if (DECL_DEFERRED_FN (fn))
      return;
!   DECL_DEFERRED_FN (fn) = 1;
!   if (!deferred_fns)
!     VARRAY_TREE_INIT (deferred_fns, 32, "deferred_fns");
  
!   VARRAY_PUSH_TREE (deferred_fns, fn);
  }
  
  /* Hand off a unique name which can be used for variable we don't really
*************** finish_file ()
*** 3537,3545 ****
        
        /* Go through the various inline functions, and see if any need
  	 synthesizing.  */
!       for (i = 0; i < saved_inlines_used; ++i)
  	{
! 	  tree decl = VARRAY_TREE (saved_inlines, i);
  	  import_export_decl (decl);
  	  if (DECL_ARTIFICIAL (decl) && ! DECL_INITIAL (decl)
  	      && TREE_USED (decl)
--- 3537,3545 ----
        
        /* Go through the various inline functions, and see if any need
  	 synthesizing.  */
!       for (i = 0; i < deferred_fns_used; ++i)
  	{
! 	  tree decl = VARRAY_TREE (deferred_fns, i);
  	  import_export_decl (decl);
  	  if (DECL_ARTIFICIAL (decl) && ! DECL_INITIAL (decl)
  	      && TREE_USED (decl)
*************** finish_file ()
*** 3569,3577 ****
  	 from being put out unncessarily.  But, we must stop lying
  	 when the functions are referenced, or if they are not comdat
  	 since they need to be put out now.  */
!       for (i = 0; i < saved_inlines_used; ++i)
  	{
! 	  tree decl = VARRAY_TREE (saved_inlines, i);
        
  	  if (DECL_NOT_REALLY_EXTERN (decl)
  	      && DECL_INITIAL (decl)
--- 3569,3577 ----
  	 from being put out unncessarily.  But, we must stop lying
  	 when the functions are referenced, or if they are not comdat
  	 since they need to be put out now.  */
!       for (i = 0; i < deferred_fns_used; ++i)
  	{
! 	  tree decl = VARRAY_TREE (deferred_fns, i);
        
  	  if (DECL_NOT_REALLY_EXTERN (decl)
  	      && DECL_INITIAL (decl)
*************** finish_file ()
*** 3609,3617 ****
  	    }
  	}
  
!       if (saved_inlines_used
! 	  && wrapup_global_declarations (&VARRAY_TREE (saved_inlines, 0),
! 					 saved_inlines_used))
  	reconsider = 1;
        if (walk_namespaces (wrapup_globals_for_namespace, /*data=*/0))
  	reconsider = 1;
--- 3609,3617 ----
  	    }
  	}
  
!       if (deferred_fns_used
! 	  && wrapup_global_declarations (&VARRAY_TREE (deferred_fns, 0),
! 					 deferred_fns_used))
  	reconsider = 1;
        if (walk_namespaces (wrapup_globals_for_namespace, /*data=*/0))
  	reconsider = 1;
*************** void
*** 5302,5308 ****
  init_decl2 ()
  {
    ggc_add_tree_root (&decl_namespace_list, 1);
!   ggc_add_tree_varray_root (&saved_inlines, 1);
    ggc_add_tree_varray_root (&pending_statics, 1);
    ggc_add_tree_varray_root (&ssdf_decls, 1);
    ggc_add_tree_root (&ssdf_decl, 1);
--- 5302,5308 ----
  init_decl2 ()
  {
    ggc_add_tree_root (&decl_namespace_list, 1);
!   ggc_add_tree_varray_root (&deferred_fns, 1);
    ggc_add_tree_varray_root (&pending_statics, 1);
    ggc_add_tree_varray_root (&ssdf_decls, 1);
    ggc_add_tree_root (&ssdf_decl, 1);
Index: lex.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/lex.c,v
retrieving revision 1.187
diff -c -p -r1.187 lex.c
*** lex.c	2000/03/27 01:26:18	1.187
--- lex.c	2000/04/06 16:08:07
*************** cons_up_default_function (type, full_nam
*** 2085,2091 ****
  #endif
      DECL_NOT_REALLY_EXTERN (fn) = 1;
  
!   mark_inline_for_output (fn);
  
  #ifdef DEBUG_DEFAULT_FUNCTIONS
    { char *fn_type = NULL;
--- 2085,2091 ----
  #endif
      DECL_NOT_REALLY_EXTERN (fn) = 1;
  
!   defer_fn (fn);
  
  #ifdef DEBUG_DEFAULT_FUNCTIONS
    { char *fn_type = NULL;
Index: pt.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/pt.c,v
retrieving revision 1.415
diff -c -p -r1.415 pt.c
*** pt.c	2000/04/06 03:12:19	1.415
--- pt.c	2000/04/06 16:08:14
*************** mark_decl_instantiated (result, extern_p
*** 8688,8694 ****
  	maybe_make_one_only (result);
      }
    else if (TREE_CODE (result) == FUNCTION_DECL)
!     mark_inline_for_output (result);
  }
  
  /* Given two function templates PAT1 and PAT2, and explicit template
--- 8688,8694 ----
  	maybe_make_one_only (result);
      }
    else if (TREE_CODE (result) == FUNCTION_DECL)
!     defer_fn (result);
  }
  
  /* Given two function templates PAT1 and PAT2, and explicit template
*************** instantiate_decl (d, defer_ok)
*** 9391,9401 ****
    tree code_pattern;
    tree spec;
    tree gen_tmpl;
-   int nested = in_function_p ();
    int pattern_defined;
    int line = lineno;
    char *file = input_filename;
-   tree old_fn = current_function_decl;
  
    /* This function should only be used to instantiate templates for
       functions and static member variables.  */
--- 9391,9399 ----
*************** instantiate_decl (d, defer_ok)
*** 9546,9570 ****
        add_pending_template (d);
        goto out;
      }
- 
-   /* If this instantiation is COMDAT, we don't know whether or not we
-      will really need to write it out.  If we can't be sure, mark it
-      DECL_DEFER_OUTPUT.  NOTE: This increases memory consumption,
-      since we keep some instantiations in memory rather than write
-      them out immediately and forget them.  A better approach would be
-      to wait until we know we need them to do the instantiation, but
-      that would break templates with static locals, because we
-      generate the functions to destroy statics before we determine
-      which functions are needed.  A better solution would be to
-      generate the ctor and dtor functions as we go.  */
- 
-   if (TREE_CODE (d) == FUNCTION_DECL
-       && DECL_COMDAT (d)
-       && ! DECL_NEEDED_P (d)
-       /* If the function that caused us to be instantiated is needed, we
- 	 will be needed, too.  */
-       && (! nested || (old_fn && ! DECL_NEEDED_P (old_fn))))
-     DECL_DEFER_OUTPUT (d) = 1;
  
    /* We're now committed to instantiating this template.  Mark it as
       instantiated so that recursive calls to instantiate_decl do not
--- 9544,9549 ----
Index: rtti.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/rtti.c,v
retrieving revision 1.81
diff -c -p -r1.81 rtti.c
*** rtti.c	2000/04/04 20:46:23	1.81
--- rtti.c	2000/04/06 16:08:15
*************** get_tinfo_decl (type)
*** 411,417 ****
        DECL_NOT_REALLY_EXTERN (d) = 1;
        SET_DECL_TINFO_FN_P (d);
        TREE_TYPE (name) = type;
!       mark_inline_for_output (d);
      }
    else
      {
--- 411,417 ----
        DECL_NOT_REALLY_EXTERN (d) = 1;
        SET_DECL_TINFO_FN_P (d);
        TREE_TYPE (name) = type;
!       defer_fn (d);
      }
    else
      {
Index: semantics.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/cp/semantics.c,v
retrieving revision 1.133
diff -c -p -r1.133 semantics.c
*** semantics.c	2000/04/04 20:46:23	1.133
--- semantics.c	2000/04/06 16:08:16
*************** expand_body (fn)
*** 2727,2743 ****
    /* If possible, avoid generating RTL for this function.  Instead,
       just record it as an inline function, and wait until end-of-file
       to decide whether to write it out or not.  */
!   if (/* We have to generate RTL if we can't inline trees.  */
!       flag_inline_trees
!       /* Or if it's not an inline function.  */
!       && DECL_INLINE (fn)
        /* Or if we have to keep all inline functions anyhow.  */
        && !flag_keep_inline_functions
        /* Or if we actually have a reference to the function.  */
        && !DECL_NEEDED_P (fn)
-       /* Or if we're at the end-of-file, and this function is not
- 	 DECL_COMDAT.  */
-       && (!at_eof || DECL_COMDAT (fn))
        /* Or if this is a nested function.  */
        && !decl_function_context (fn))
      {
--- 2727,2738 ----
    /* If possible, avoid generating RTL for this function.  Instead,
       just record it as an inline function, and wait until end-of-file
       to decide whether to write it out or not.  */
!   if (/* We have to generate RTL if it's not an inline function.  */
!       (DECL_INLINE (fn) || DECL_COMDAT (fn))
        /* Or if we have to keep all inline functions anyhow.  */
        && !flag_keep_inline_functions
        /* Or if we actually have a reference to the function.  */
        && !DECL_NEEDED_P (fn)
        /* Or if this is a nested function.  */
        && !decl_function_context (fn))
      {
*************** expand_body (fn)
*** 2753,2759 ****
  	}
        /* Remember this function.  In finish_file we'll decide if
  	 we actually need to write this function out.  */
!       mark_inline_for_output (fn);
        /* Let the back-end know that this funtion exists.  */
        note_deferral_of_defined_inline_function (fn);
        return;
--- 2748,2754 ----
  	}
        /* Remember this function.  In finish_file we'll decide if
  	 we actually need to write this function out.  */
!       defer_fn (fn);
        /* Let the back-end know that this funtion exists.  */
        note_deferral_of_defined_inline_function (fn);
        return;
? testsuite/g++.old-deja/g++.jason/vecdel.s
? testsuite/g++.old-deja/g++.other/rtti4.s
Index: testsuite/g++.old-deja/g++.bugs/900205_03.C
===================================================================
RCS file: /cvs/gcc/egcs/gcc/testsuite/g++.old-deja/g++.bugs/900205_03.C,v
retrieving revision 1.2
diff -c -p -r1.2 900205_03.C
*** 900205_03.C	1998/12/16 21:28:26	1.2
--- 900205_03.C	2000/04/06 16:22:26
*************** struct00 global_function_1 () {
*** 25,34 ****
  struct struct0 {
  
    int struct0_member_function_0 () {
!   }					// ERROR - 
  
    struct0 struct0_member_function_1 () {
!   }					// ERROR - 
  };
  
  struct struct1 {
--- 25,34 ----
  struct struct0 {
  
    int struct0_member_function_0 () {
!   }					// ERROR - XFAIL
  
    struct0 struct0_member_function_1 () {
!   }					// ERROR - XFAIL
  };
  
  struct struct1 {
Index: testsuite/g++.old-deja/g++.jason/offset2.C
===================================================================
RCS file: /cvs/gcc/egcs/gcc/testsuite/g++.old-deja/g++.jason/offset2.C,v
retrieving revision 1.3
diff -c -p -r1.3 offset2.C
*** offset2.C	1998/12/16 21:34:20	1.3
--- offset2.C	2000/04/06 16:22:26
***************
*** 3,9 ****
  int status = 1;
  
  struct foo {
!   foo& operator= (const foo&) { status = 0; }
  };
  
  struct xx {
--- 3,9 ----
  int status = 1;
  
  struct foo {
!   foo& operator= (const foo&) { status = 0; return *this; }
  };
  
  struct xx {
Index: testsuite/g++.old-deja/g++.jason/opeq.C
===================================================================
RCS file: /cvs/gcc/egcs/gcc/testsuite/g++.old-deja/g++.jason/opeq.C,v
retrieving revision 1.3
diff -c -p -r1.3 opeq.C
*** opeq.C	2000/01/04 15:52:22	1.3
--- opeq.C	2000/04/06 16:22:26
*************** class Y 
*** 8,14 ****
  {
  public:
      Y(char*) {}
!     Y& operator = (const Y&) {}
  };
      
  
--- 8,14 ----
  {
  public:
      Y(char*) {}
!     Y& operator = (const Y&) { return *this; }
  };
      
  
Index: testsuite/g++.old-deja/g++.law/operators16.C
===================================================================
RCS file: /cvs/gcc/egcs/gcc/testsuite/g++.old-deja/g++.law/operators16.C,v
retrieving revision 1.4
diff -c -p -r1.4 operators16.C
*** operators16.C	1999/06/17 00:48:26	1.4
--- operators16.C	2000/04/06 16:22:26
*************** int pass = 0;
*** 11,17 ****
  struct A {
          A(void) {}
          A(const A& a) { ; }
!         A& operator = (const A& a) { pass = 1; }
  };
  
  struct B {
--- 11,17 ----
  struct A {
          A(void) {}
          A(const A& a) { ; }
!         A& operator = (const A& a) { pass = 1; return *this; }
  };
  
  struct B {
Index: testsuite/g++.old-deja/g++.law/operators17.C
===================================================================
RCS file: /cvs/gcc/egcs/gcc/testsuite/g++.old-deja/g++.law/operators17.C,v
retrieving revision 1.2
diff -c -p -r1.2 operators17.C
*** operators17.C	1998/12/16 21:41:26	1.2
--- operators17.C	2000/04/06 16:22:26
***************
*** 8,12 ****
  // Message-ID: <9304291053.AA00090@mencon>
  
          struct A {
!                 A& operator = (const A& a) {}// ERROR - 
          };
--- 8,12 ----
  // Message-ID: <9304291053.AA00090@mencon>
  
          struct A {
!                 A& operator = (const A& a) {}// ERROR - XFAIL
          };
Index: testsuite/g++.old-deja/g++.mike/net26.C
===================================================================
RCS file: /cvs/gcc/egcs/gcc/testsuite/g++.old-deja/g++.mike/net26.C,v
retrieving revision 1.3
diff -c -p -r1.3 net26.C
*** net26.C	1998/12/16 21:45:36	1.3
--- net26.C	2000/04/06 16:22:26
*************** extern "C" int printf(const char *, ...)
*** 4,11 ****
  
  class A {
  public:
! 	int foo() { printf("ok nv\n"); }
! 	virtual int vfoo() { printf("ok v\n"); }
  };
  
  struct S {
--- 4,11 ----
  
  class A {
  public:
! 	int foo() { printf("ok nv\n"); return 0; }
! 	virtual int vfoo() { printf("ok v\n"); return 0; }
  };
  
  struct S {
Index: testsuite/g++.old-deja/g++.mike/virt3.C
===================================================================
RCS file: /cvs/gcc/egcs/gcc/testsuite/g++.old-deja/g++.mike/virt3.C,v
retrieving revision 1.2
diff -c -p -r1.2 virt3.C
*** virt3.C	1998/12/16 21:49:25	1.2
--- virt3.C	2000/04/06 16:22:26
***************
*** 3,9 ****
  class B {
  public:
    int Bi;
!   virtual int g() { };
  };
  
  class D : private B {
--- 3,9 ----
  class B {
  public:
    int Bi;
!   virtual int g() { return  0; };
  };
  
  class D : private B {
Index: testsuite/g++.old-deja/g++.mike/virt6.C
===================================================================
RCS file: /cvs/gcc/egcs/gcc/testsuite/g++.old-deja/g++.mike/virt6.C,v
retrieving revision 1.2
diff -c -p -r1.2 virt6.C
*** virt6.C	1998/12/16 21:49:29	1.2
--- virt6.C	2000/04/06 16:22:26
***************
*** 3,9 ****
  
  class C_A {
  public:
!   virtual int foo(void *) { }
  } a;
   
  class C_B : public C_A {
--- 3,9 ----
  
  class C_A {
  public:
!   virtual int foo(void *) { return  0; }
  } a;
   
  class C_B : public C_A {
*************** class C_D : public C_A {
*** 17,38 ****
   
  class C_E : public C_C, public C_B {
  public:
!   virtual int foo(void *) { }
  } e;
   
  class C_F : public C_D, public C_B {
  public:
!   virtual int foo(void *) { }
  } f;
   
  class C_G : public C_A {
  public:
!   virtual int foo(void *) { }
  } g;
   
  class C_H : public C_G, public C_E, public C_F {
  public:
!   virtual int foo(void *) { }
  } h;
   
  int main() {
--- 17,38 ----
   
  class C_E : public C_C, public C_B {
  public:
!   virtual int foo(void *) { return 0; }
  } e;
   
  class C_F : public C_D, public C_B {
  public:
!   virtual int foo(void *) { return 0; }
  } f;
   
  class C_G : public C_A {
  public:
!   virtual int foo(void *) { return 0; }
  } g;
   
  class C_H : public C_G, public C_E, public C_F {
  public:
!   virtual int foo(void *) { return 0; }
  } h;
   
  int main() {


More information about the Gcc-patches mailing list