summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/cp/ChangeLog4
-rw-r--r--gcc/cp/typeck.c30
-rw-r--r--gcc/testsuite/g++.dg/abi/offsetof.C22
-rw-r--r--gcc/testsuite/g++.old-deja/g++.other/friend1.C19
4 files changed, 63 insertions, 12 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 63c87471241..af18329d129 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,5 +1,9 @@
2002-02-01 Jason Merrill <jason@redhat.com>
+ * typeck.c (build_component_ref): Always complain about offsetof
+ constructs on non-PODs. Only make it an error for members of
+ virtual bases.
+
* error.c (dump_scope): Don't add TFF_DECL_SPECIFIERS.
(dump_function_decl): Always dump parms.
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 5e69b98fc9d..ba37b10fff6 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -1999,6 +1999,8 @@ build_component_ref (datum, component, basetype_path, protect)
register tree ref;
tree field_type;
int type_quals;
+ tree old_datum;
+ tree old_basetype;
if (processing_template_decl)
return build_min_nt (COMPONENT_REF, datum, component);
@@ -2202,6 +2204,9 @@ build_component_ref (datum, component, basetype_path, protect)
if (TREE_DEPRECATED (field))
warn_deprecated_use (field);
+ old_datum = datum;
+ old_basetype = basetype;
+
/* See if we have to do any conversions so that we pick up the field from the
right context. */
if (DECL_FIELD_CONTEXT (field) != basetype)
@@ -2215,12 +2220,17 @@ build_component_ref (datum, component, basetype_path, protect)
/* Handle base classes here... */
if (base != basetype && TYPE_BASE_CONVS_MAY_REQUIRE_CODE_P (basetype))
{
- tree binfo = lookup_base (TREE_TYPE (datum), base, ba_check, NULL);
-
+ base_kind kind;
+ tree binfo = lookup_base (TREE_TYPE (datum), base, ba_check, &kind);
+
+ /* Complain about use of offsetof which will break. */
if (TREE_CODE (datum) == INDIRECT_REF
- && integer_zerop (TREE_OPERAND (datum, 0)))
+ && integer_zerop (TREE_OPERAND (datum, 0))
+ && kind == bk_via_virtual)
{
- error ("invalid reference to NULL ptr, use ptr-to-member instead");
+ error ("\
+invalid offsetof from non-POD type `%#T'; use pointer to member instead",
+ basetype);
return error_mark_node;
}
datum = build_base_path (PLUS_EXPR, datum, binfo, 1);
@@ -2239,6 +2249,18 @@ build_component_ref (datum, component, basetype_path, protect)
}
}
+ /* Complain about other invalid uses of offsetof, even though they will
+ give the right answer. Note that we complain whether or not they
+ actually used the offsetof macro, since there's no way to know at this
+ point. So we just give a warning, instead of a pedwarn. */
+ if (protect
+ && CLASSTYPE_NON_POD_P (old_basetype)
+ && TREE_CODE (old_datum) == INDIRECT_REF
+ && integer_zerop (TREE_OPERAND (old_datum, 0)))
+ warning ("\
+invalid offsetof from non-POD type `%#T'; use pointer to member instead",
+ basetype);
+
/* Compute the type of the field, as described in [expr.ref]. */
type_quals = TYPE_UNQUALIFIED;
field_type = TREE_TYPE (field);
diff --git a/gcc/testsuite/g++.dg/abi/offsetof.C b/gcc/testsuite/g++.dg/abi/offsetof.C
new file mode 100644
index 00000000000..8a2e732c9ff
--- /dev/null
+++ b/gcc/testsuite/g++.dg/abi/offsetof.C
@@ -0,0 +1,22 @@
+// Test that we can refer to the address of a base member of a null pointer
+// to get its offset. The standard says that offsetof shall not be used on
+// non-POD classes, but there seems to be no such restriction on the common
+// implementation thereof.
+
+// Yes, this is bad, naughty, evil code. But it seems to be well-formed.
+// So we'll just warn.
+
+// { dg-do run }
+
+struct A { int i; };
+
+struct B: public A {
+ virtual void f ();
+};
+
+struct C: public B { };
+
+int main ()
+{
+ return ((unsigned long) &((C*)0)->i) != 4; // { dg-warning "offsetof" "" }
+}
diff --git a/gcc/testsuite/g++.old-deja/g++.other/friend1.C b/gcc/testsuite/g++.old-deja/g++.other/friend1.C
index 76fcebe1fae..f8e22c2eb91 100644
--- a/gcc/testsuite/g++.old-deja/g++.other/friend1.C
+++ b/gcc/testsuite/g++.old-deja/g++.other/friend1.C
@@ -46,10 +46,13 @@ struct R {
X<&B::j> x;
};
+B b;
+D d;
+
void f()
{
- ((B*)0)->i = 3; // ERROR - protected
- ((D*)0)->i = 4;
+ b.i = 3; // ERROR - protected
+ d.i = 4;
B::j = 5;
D::j = 6;
}
@@ -57,8 +60,8 @@ void f()
template <typename T>
void g()
{
- ((B*)0)->i = 3; // ERROR - protected
- ((D*)0)->i = 4;
+ b.i = 3; // ERROR - protected
+ d.i = 4;
B::j = 5;
D::j = 6;
}
@@ -67,8 +70,8 @@ template void g<int>();
void S::h()
{
- ((B*)0)->i = 3; // ERROR - protected
- ((D*)0)->i = 4;
+ b.i = 3; // ERROR - protected
+ d.i = 4;
B::j = 5;
D::j = 6;
}
@@ -76,8 +79,8 @@ void S::h()
template <typename T>
void R<T>::h()
{
- ((B*)0)->i = 3; // ERROR - protected
- ((D*)0)->i = 4;
+ b.i = 3; // ERROR - protected
+ d.i = 4;
B::j = 5;
D::j = 6;
}