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]

PATCH: Abstract virtuals warning


Hi,
Some time ago I filed a bug report about an abstract virtuals warning
not being as helpful as it might be
(http://www.cygnus.com/ml/egcs-bugs/1998-Jun/0634.html). Here's a patch
against the 19981122 snapshot for that problem.

The first part of showing a functions declaration location was very
simple (abstract_virtuals_error). The next bit of removing duplicate
abstract virtuals from a class's CLASSTYPE_ABSTRACT_VIRTUALS list was a
bit more involved, and appeared to be a deeper bug.

When a structure is declared, finish_struct_bits is supposed to tidy up
the CLASSTYPE_ABSTRACT_VIRTUALS by calling get_abstract_virtuals, if
necessary. get_abstract_virtuals scans a class's vtable definitions to
build this list. However, it prepends the existing value of
CLASSTYPE_ABSTRACT_VIRTUALS to this list. Thus any abstract virtuals
that are declared within the class are duplicated on this list. I
changed get_abstract_virtuals to not prepend the original value. Also
finish_struct_bits was going through quite a bit of work to determine
whether it was worth calling get_abstract_virtuals. I removed that code
as it was essentially doing the work of get_abstract_virtuals but to no
advantage.

Lastly, build_new_method_call was calling get_abstract_virtuals, rather
than simply using CLASSTYPE_ABSTRACT_VIRTUALS, and each such call
extended a class's list of abstract virtuals (causing a memory leak). I
changed this to use CLASSTYPE_ABSTRACT_VIRTUALS.

I've also attached two test cases which you can use to compare the old
and new error message behaviour.

Hope this is satisfactory.

nathan
-- 
Dr Nathan Sidwell :: Computer Science Department :: Bristol University
      You can up the bandwidth, but you can't up the speed of light      
nathan@acm.org  http://www.cs.bris.ac.uk/~nathan/  nathan@cs.bris.ac.uk
egcs/gcc/cp/ChangeLog

Tue Nov 24 14:18:09 GMT 1998  Nathan Sidwell  <nathan@acm.org>

	* search.c (get_abstract_virtuals): Do not use initial
	CLASSTYPE_ABSTRACT_VIRTUALS.
	* typeck2.c (abstract_virtuals_error): Show location of abstract
	declaration.
	* call.c (build_new_method_call): Use
	CLASSTYPE_ABSTRACT_VIRTUAL, rather than recalculate.
	* class.c (finish_struct_bits): Don't bother working out whether
	get_abstract_virtuals will do anything, just do it.

Index: egcs/gcc/cp/search.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/search.c,v
retrieving revision 1.71
diff -c -3 -p -r1.71 search.c
*** search.c	1998/11/21 05:42:19	1.71
--- search.c	1998/11/24 14:10:10
*************** get_abstract_virtuals (type)
*** 1952,1958 ****
       tree type;
  {
    tree vbases;
!   tree abstract_virtuals = CLASSTYPE_ABSTRACT_VIRTUALS (type);
  
    /* First get all from non-virtual bases.  */
    abstract_virtuals
--- 1952,1958 ----
       tree type;
  {
    tree vbases;
!   tree abstract_virtuals = NULL;
  
    /* First get all from non-virtual bases.  */
    abstract_virtuals
Index: egcs/gcc/cp/typeck2.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/typeck2.c,v
retrieving revision 1.43
diff -c -3 -p -r1.43 typeck2.c
*** typeck2.c	1998/11/18 12:27:30	1.43
--- typeck2.c	1998/11/24 14:10:19
*************** abstract_virtuals_error (decl, type)
*** 165,171 ****
  
        error ("  since the following virtual functions are abstract:");
        for (tu = u; tu; tu = TREE_CHAIN (tu))
! 	cp_error ("\t%#D", TREE_VALUE (tu));
      }
    else
      cp_error ("  since type `%T' has abstract virtual functions", type);
--- 165,171 ----
  
        error ("  since the following virtual functions are abstract:");
        for (tu = u; tu; tu = TREE_CHAIN (tu))
! 	cp_error_at ("\t%#D", TREE_VALUE (tu));
      }
    else
      cp_error ("  since type `%T' has abstract virtual functions", type);
Index: egcs/gcc/cp/call.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/call.c,v
retrieving revision 1.120
diff -c -3 -p -r1.120 call.c
*** call.c	1998/11/18 12:27:21	1.120
--- call.c	1998/11/24 14:10:35
*************** build_new_method_call (instance, name, a
*** 3662,3668 ****
        && instance == current_class_ref
        && DECL_CONSTRUCTOR_P (current_function_decl)
        && ! (flags & LOOKUP_NONVIRTUAL)
!       && value_member (cand->fn, get_abstract_virtuals (basetype)))
      cp_error ("abstract virtual `%#D' called from constructor", cand->fn);
    if (TREE_CODE (TREE_TYPE (cand->fn)) == METHOD_TYPE
        && is_dummy_object (instance_ptr))
--- 3662,3668 ----
        && instance == current_class_ref
        && DECL_CONSTRUCTOR_P (current_function_decl)
        && ! (flags & LOOKUP_NONVIRTUAL)
!       && value_member (cand->fn, CLASSTYPE_ABSTRACT_VIRTUALS (basetype)))
      cp_error ("abstract virtual `%#D' called from constructor", cand->fn);
    if (TREE_CODE (TREE_TYPE (cand->fn)) == METHOD_TYPE
        && is_dummy_object (instance_ptr))
Index: egcs/gcc/cp/class.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/class.c,v
retrieving revision 1.108
diff -c -3 -p -r1.108 class.c
*** class.c	1998/11/21 05:42:00	1.108
--- class.c	1998/11/24 14:10:40
*************** finish_struct_bits (t, max_has_virtual)
*** 1942,1965 ****
  
    if (n_baseclasses && max_has_virtual)
      {
!       /* Done by `finish_struct' for classes without baseclasses.  */
!       int might_have_abstract_virtuals = CLASSTYPE_ABSTRACT_VIRTUALS (t) != 0;
!       tree binfos = TYPE_BINFO_BASETYPES (t);
!       for (i = n_baseclasses-1; i >= 0; i--)
! 	{
! 	  might_have_abstract_virtuals
! 	    |= (CLASSTYPE_ABSTRACT_VIRTUALS (BINFO_TYPE (TREE_VEC_ELT (binfos, i))) != 0);
! 	  if (might_have_abstract_virtuals)
! 	    break;
! 	}
!       if (might_have_abstract_virtuals)
! 	{
! 	  /* We use error_mark_node from override_one_vtable to signal
! 	     an artificial abstract.  */
! 	  if (CLASSTYPE_ABSTRACT_VIRTUALS (t) == error_mark_node)
! 	    CLASSTYPE_ABSTRACT_VIRTUALS (t) = NULL_TREE;
! 	  CLASSTYPE_ABSTRACT_VIRTUALS (t) = get_abstract_virtuals (t);
! 	}
      }
  
    if (n_baseclasses)
--- 1942,1956 ----
  
    if (n_baseclasses && max_has_virtual)
      {
!       /* for a class w/o baseclasses, `finish_struct' has set
!        * CLASS_TYPE_ABSTRACT_VIRTUALS correctly (by definition). Similarly
!        * for a class who's base classes do not have vtables. When neither of
!        * these is true, we might have removed abstract virtuals (by
!        * providing a definition), added some (by declaring new ones), or
!        * redeclared ones from a base class. We need to recalculate what's
!        * really an abstract virtual at this point (by looking in the vtables).
!        */
!       CLASSTYPE_ABSTRACT_VIRTUALS (t) = get_abstract_virtuals (t);
      }
  
    if (n_baseclasses)
struct B1
{
  virtual void fnB1() = 0;
};
struct B2
{
  virtual void fnB2() = 0;
};

struct C0 : B1
{
};
struct C1 : B1
{
  virtual void fnC1() = 0;
};
struct CB1 : B1
{
  virtual void fnB1() = 0;
};
struct C2 : B1
{
  virtual void fnB1() = 0;
  virtual void fnC2() = 0;
};

struct D0 : B1, B2
{
};
struct D1 : B1, B2
{
  virtual void fnD1() = 0;
};
struct DB1 : B1, B2
{
  virtual void fnB1() = 0;
};
struct DB2 : B1, B2
{
  virtual void fnB2() = 0;
};
struct DB1B2 : B1, B2
{
  virtual void fnB1() = 0;
  virtual void fnB2() = 0;
};
struct D2 : B1, B2
{
  virtual void fnB1() = 0;
  virtual void fnB2() = 0;
  virtual void fnD2() = 0;
};

struct E0 : virtual B1
{
};
struct E1 : virtual B1
{
  virtual void fnE1() = 0;
};
struct EB1 : virtual B1
{
  virtual void fnB1() = 0;
};
struct E2 : virtual B1
{
  virtual void fnB1() = 0;
  virtual void fnE2() = 0;
};

struct F0 : virtual B1
{
};
struct F1 : virtual B1
{
  virtual void fnF1() = 0;
};
struct FB1 : virtual B1
{
  virtual void fnB1() = 0;
};
struct F2 : virtual B1
{
  virtual void fnB1() = 0;
  virtual void fnF2() = 0;
};

struct G0: E1, F1
{
};

struct GB1: E1, F1
{
  virtual void fnB1() = 0;
};

struct H0: C1, E1
{
};

void f()
{
  B1 b1;
  B2 b2;
  
  C0 c0;
  C1 c1;
  CB1 cb1;
  C2 c2;
  
  D0 d0;
  D1 d1;
  DB1 db1;
  DB2 db2;
  DB1B2 db1b2;
  D2 d2;
  
  E0 e0;
  E1 e1;
  EB1 eb1;
  E2 e2;
  
  G0 g0;
  GB1 gb1;
  
  H0 h0;
}

struct J
{
  J(){fnJ();}
  virtual void fnJ() = 0;
};
struct B1
{
  virtual void fnB1() = 0;
};
struct B2
{
  virtual void fnB2() = 0;
};

struct CB1 : B1
{
  virtual void fnB1();
};

struct DB1B2 : B1, B2
{
  virtual void fnB1();
  virtual void fnB2();
};

struct EB1 : virtual B1
{
  virtual void fnB1();
};

struct FB1 : virtual B1
{
  virtual void fnB1();
};

struct G0: EB1, FB1
{
};

struct GB1: EB1, FB1
{
  virtual void fnB1();
};

void f()
{
  CB1 cb1;
  DB1B2 db1b2;
  EB1 eb1;
  G0 g0;
  GB1 gb1;
}

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