C++ PATCH: offsetof with multiple bases
Nathan Sidwell
nathan@acm.org
Tue May 11 07:40:00 GMT 1999
Hi,
here's a patch which deals with offsetof(T,m) handling. It permits that to be
used for all but virtual base classes. For those paying attention, this is
making offsetof handling nice and permissive, rather than the warnings I
previously attempted to do! (I reserve the right to be fickle :-)
The comment was made (by someone who I've forgotten) that although undefined,
it'd be nice if offsetof worked for all but virtual base members. However, as
bug report http://egcs.cygnus.com/ml/egcs-bugs/1999-04/msg00598.html says, this
goes wrong. The bug report invokes undefined effects (morething is not a POD
class).
The patch modifies build_component_ref not to check for NULL pointer, and not
to assume that convert_pointer_to succeeds. convert_pointer_to_real is not so
picky about being given a zero valued pointer (which it should NOT treat as a
null pointer constant), and build_vbase_path checks whether a virtual base is
being accessed off a constant pointer.
Also I attach two test cases, one which should succeed and the other which
should issue diagnostics. No regressions against the current snapshot.
ok to install?
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
1999-05-11 Nathan Sidwell <nathan@acm.org>
* typeck.c (build_component_ref): Don't check for a null pointer
constant with a complex inheritance, let build_vbase_path do
that. Check build_vbase_path didn't object. This lets offsetof
work for all but a virtual base class member.
* cvt.c (convert_pointer_to_real): Allow zero valued constants,
but do _not_ treat as NULL pointer constants.
(convert_pointer_to): Adjust comment likewise.
* class.c (build_vbase_path): Detect accessing a virtual base
from a constant pointer.
Index: egcs/gcc/cp/typeck.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/typeck.c,v
retrieving revision 1.160
diff -c -3 -p -r1.160 typeck.c
*** typeck.c 1999/05/07 09:47:57 1.160
--- typeck.c 1999/05/11 08:03:28
*************** build_component_ref (datum, component, b
*** 2219,2230 ****
/* Handle base classes here... */
if (base != basetype && TYPE_USES_COMPLEX_INHERITANCE (basetype))
{
tree addr = build_unary_op (ADDR_EXPR, datum, 0);
- if (integer_zerop (addr))
- {
- error ("invalid reference to NULL ptr, use ptr-to-member instead");
- return error_mark_node;
- }
if (VBASE_NAME_P (DECL_NAME (field)))
{
/* It doesn't matter which vbase pointer we grab, just
--- 2219,2226 ----
/* Handle base classes here... */
if (base != basetype && TYPE_USES_COMPLEX_INHERITANCE (basetype))
{
+ /* build_vbase_path will detect bad uses of NULL ptrs. */
tree addr = build_unary_op (ADDR_EXPR, datum, 0);
if (VBASE_NAME_P (DECL_NAME (field)))
{
/* It doesn't matter which vbase pointer we grab, just
*************** build_component_ref (datum, component, b
*** 2236,2242 ****
else
addr = convert_pointer_to (base, addr);
datum = build_indirect_ref (addr, NULL_PTR);
! my_friendly_assert (datum != error_mark_node, 311);
}
basetype = base;
--- 2232,2239 ----
else
addr = convert_pointer_to (base, addr);
datum = build_indirect_ref (addr, NULL_PTR);
! if (datum == error_mark_node)
! return datum;
}
basetype = base;
Index: egcs/gcc/cp/cvt.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/cvt.c,v
retrieving revision 1.57
diff -c -3 -p -r1.57 cvt.c
*** cvt.c 1999/05/07 09:47:53 1.57
--- cvt.c 1999/05/11 08:03:28
*************** convert_from_reference (val)
*** 546,553 ****
return val;
}
! /* Call this when we know (for any reason) that expr is not, in fact,
! zero. This routine is like convert_pointer_to, but it pays
attention to which specific instance of what type we want to
convert to. This routine should eventually become
convert_to_pointer after all references to convert_to_pointer
--- 546,556 ----
return val;
}
! /* Call this when we know (for any reason) that expr is not a null
! pointer constant. It might have value zero, because of dealing with
! offsetof in multiple base classes. When it is zero, we don't want to
! treat it as a null pointer constant.
! This routine is like convert_pointer_to, but it pays
attention to which specific instance of what type we want to
convert to. This routine should eventually become
convert_to_pointer after all references to convert_to_pointer
*************** convert_pointer_to_real (binfo, expr)
*** 582,589 ****
if (same_type_p (ptr_type, TYPE_MAIN_VARIANT (intype)))
return expr;
- my_friendly_assert (!integer_zerop (expr), 191);
-
intype = TYPE_MAIN_VARIANT (TREE_TYPE (intype));
if (TREE_CODE (type) == RECORD_TYPE
&& TREE_CODE (intype) == RECORD_TYPE
--- 585,590 ----
*************** convert_pointer_to_real (binfo, expr)
*** 614,620 ****
}
/* Call this when we know (for any reason) that expr is
! not, in fact, zero. This routine gets a type out of the first
argument and uses it to search for the type to convert to. If there
is more than one instance of that type in the expr, the conversion is
ambiguous. This routine should eventually go away, and all
--- 615,621 ----
}
/* Call this when we know (for any reason) that expr is
! not a null pointer constant. This routine gets a type out of the first
argument and uses it to search for the type to convert to. If there
is more than one instance of that type in the expr, the conversion is
ambiguous. This routine should eventually go away, and all
Index: egcs/gcc/cp/class.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/cp/class.c,v
retrieving revision 1.152
diff -c -3 -p -r1.152 class.c
*** class.c 1999/04/30 16:14:54 1.152
--- class.c 1999/05/11 08:03:32
*************** build_vbase_path (code, type, expr, path
*** 286,292 ****
--- 286,317 ----
{
if (TREE_VIA_VIRTUAL (path))
{
+ tree probe;
+
last_virtual = BINFO_TYPE (path);
+
+ /* If expr is constant, this is invalid. This is most likely to have
+ arisen by applying offsetof to a member of a virtual base.
+ We have to look inside expr, rather than strip nops, because
+ that would lose type information. integer_zerop is insufficient
+ too, as we might have already adjusted a null pointer. Any
+ constant value is wrong. */
+ for (probe = expr; TREE_CODE (probe) == NOP_EXPR;
+ probe = TREE_OPERAND (probe, 0))
+ ;
+ if (TREE_CODE (probe) == INTEGER_CST)
+ {
+ static int once = 0;
+
+ cp_error ("invalid reference from NULL ptr to virtual base `%T'",
+ last_virtual);
+ if (! once)
+ {
+ once = 1;
+ cp_error (" (use ptr-to-member instead)");
+ }
+ return error_mark_node;
+ }
if (code == PLUS_EXPR)
{
changed = ! fixed_type_p;
*************** build_vbase_path (code, type, expr, path
*** 393,399 ****
null_expr,
build (code, type, expr, offset));
}
! else return build (code, type, expr, offset);
}
/* Cannot change the TREE_TYPE of a NOP_EXPR here, since it may
--- 418,424 ----
null_expr,
build (code, type, expr, offset));
}
! else return fold (build (code, type, expr, offset));
}
/* Cannot change the TREE_TYPE of a NOP_EXPR here, since it may
More information about the Gcc-patches
mailing list