This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
PATCH: Abstract virtuals warning
- To: egcs-patches at cygnus dot com
- Subject: PATCH: Abstract virtuals warning
- From: Nathan Sidwell <nathan at acm dot org>
- Date: Tue, 24 Nov 1998 14:44:10 +0000
- Organization: Computer Science Dept, Bristol University
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;
}