and this patch aligns our behaviour with that of other compilers by
removing the check for a null instance (that was primarily targetting
offsetof according to its comment) from build_class_member_access_expr,
and having finish_offsetof check and report accesses to members from a
virtual base class.
Successfully tested on x86_64-pc-linux-gnu.
PR c++/118346
gcc/cp/ChangeLog:
* semantics.cc (finish_offsetof): Reject accesses to a virtual
base member.
* typeck.cc (build_class_member_access_expr): Don't reject
virtual base member access of null objects.
gcc/testsuite/ChangeLog:
* g++.dg/other/offsetof8.C: Add untested scenarios.
* g++.dg/other/offsetof9.C: Adjust test expectations.
---
gcc/cp/semantics.cc | 28 ++++++++++++++++++------
gcc/cp/typeck.cc | 20 -----------------
gcc/testsuite/g++.dg/other/offsetof8.C | 30 +++++++++++++++++++++-----
gcc/testsuite/g++.dg/other/offsetof9.C | 6 +++---
4 files changed, 50 insertions(+), 34 deletions(-)
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index 43a0eabfa12..9ba00196542 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -5324,13 +5324,29 @@ finish_offsetof (tree object_ptr, tree expr, location_t
loc)
expr = TREE_OPERAND (expr, 0);
if (!complete_type_or_else (TREE_TYPE (TREE_TYPE (object_ptr)), object_ptr))
return error_mark_node;
+
if (warn_invalid_offsetof
- && CLASS_TYPE_P (TREE_TYPE (TREE_TYPE (object_ptr)))
- && CLASSTYPE_NON_STD_LAYOUT (TREE_TYPE (TREE_TYPE (object_ptr)))
- && cp_unevaluated_operand == 0)
- warning_at (loc, OPT_Winvalid_offsetof, "%<offsetof%> within "
- "non-standard-layout type %qT is conditionally-supported",
- TREE_TYPE (TREE_TYPE (object_ptr)));
+ && CLASS_TYPE_P (TREE_TYPE (TREE_TYPE (object_ptr))))
+ {
+ bool member_in_base_p = false;
+ if (TREE_CODE (expr) == COMPONENT_REF)
+ {
+ tree member = expr;
+ do {
+ member = TREE_OPERAND (member, 1);
+ } while (TREE_CODE (member) == COMPONENT_REF);
+ member_in_base_p = !same_type_p (TREE_TYPE (TREE_TYPE (object_ptr)),
+ DECL_CONTEXT (member));
+ }
+ if (member_in_base_p
+ && CLASSTYPE_VBASECLASSES (TREE_TYPE (TREE_TYPE (object_ptr))))
+ error_at (loc, "invalid %<offsetof%> to data member in virtual base");
+ else if (CLASSTYPE_NON_STD_LAYOUT (TREE_TYPE (TREE_TYPE (object_ptr)))
+ && cp_unevaluated_operand == 0)
+ warning_at (loc, OPT_Winvalid_offsetof, "%<offsetof%> within "
+ "non-standard-layout type %qT is conditionally-supported",
+ TREE_TYPE (TREE_TYPE (object_ptr)));
+ }
return fold_offsetof (expr);
}
diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc
index 1b9fdf5b21d..4e5d0507493 100644
--- a/gcc/cp/typeck.cc
+++ b/gcc/cp/typeck.cc
@@ -2926,16 +2926,9 @@ build_class_member_access_expr (cp_expr object, tree
member,
else if (TREE_CODE (member) == FIELD_DECL)
{
/* A non-static data member. */
- bool null_object_p;
int type_quals;
tree member_type;
- if (INDIRECT_REF_P (object))
- null_object_p =
- integer_zerop (tree_strip_nop_conversions (TREE_OPERAND (object, 0)));
- else
- null_object_p = false;
-
/* Convert OBJECT to the type of MEMBER. */
if (!same_type_p (TYPE_MAIN_VARIANT (object_type),
TYPE_MAIN_VARIANT (member_scope)))
@@ -2957,19 +2950,6 @@ build_class_member_access_expr (cp_expr object, tree
member,
if (binfo == error_mark_node)
return error_mark_node;
- /* It is invalid to try to get to a virtual base of a
- NULL object. The most common cause is invalid use of
- offsetof macro. */
- if (null_object_p && kind == bk_via_virtual)
- {
- if (complain & tf_error)
- {
- error ("invalid access to non-static data member %qD in "
- "virtual base of NULL object", member);
- }
- return error_mark_node;
- }
-
/* Convert to the base. */
object = build_base_path (PLUS_EXPR, object, binfo,
/*nonnull=*/1, complain);
diff --git a/gcc/testsuite/g++.dg/other/offsetof8.C
b/gcc/testsuite/g++.dg/other/offsetof8.C
index daca70a6fe4..96f1507b845 100644
--- a/gcc/testsuite/g++.dg/other/offsetof8.C
+++ b/gcc/testsuite/g++.dg/other/offsetof8.C
@@ -1,12 +1,32 @@
// PR c++/68711 - [5 regression] SEGV on an invalid offsetof of a member
// of a virtual base
+// PR c++/118346
// { dg-do compile }
-struct A { int i; };
+struct A {
+ int i;
+ static int s;
+};
+
+struct B: virtual A { int j; };
+
+long unsigned a[] = {
+ // Non static data member in virtual base.
+ !&((B*)0)->i,
+ __builtin_offsetof (B, i), // { dg-error "data member in virtual base" }
+
+ // Non static data member in class with virtual base.
+ !&((B*)0)->j,
+ __builtin_offsetof (B, j), // { dg-warning "within non-standard-layout type"
}
-struct B: virtual A { };
+ // Static data member in virtual base.
+ !&((B*)0)->s,
+ __builtin_offsetof (B, s), // { dg-error "to static data" }
+ // { dg-warning "within non-standard-layout type" "" { target *-*-* } .-1 }
-int a[] = {
- !&((B*)0)->i, // { dg-error "invalid access to non-static data member" }
- __builtin_offsetof (B, i) // { dg-error "invalid access to non-static" }
+ // No virtual base involvement.
+ !&((A*)0)->i,
+ __builtin_offsetof (A, i),
+ !&((A*)0)->s,
+ __builtin_offsetof (A, s) // { dg-error "to static data" }
};
diff --git a/gcc/testsuite/g++.dg/other/offsetof9.C
b/gcc/testsuite/g++.dg/other/offsetof9.C
index 1936f2e5f76..ac07c21ef34 100644
--- a/gcc/testsuite/g++.dg/other/offsetof9.C
+++ b/gcc/testsuite/g++.dg/other/offsetof9.C
@@ -4,14 +4,14 @@
struct A { int i; };
struct B : virtual A { };
-__SIZE_TYPE__ s = __builtin_offsetof (B, A::i); // { dg-warning "'offsetof'
within non-standard-layout type" }
+__SIZE_TYPE__ s = __builtin_offsetof (B, A::i); // { dg-error "'offsetof' to
data member in virtual base" }
template <typename T>
__SIZE_TYPE__
foo ()
{
- return __builtin_offsetof (T, A::i) // { dg-warning "'offsetof' within
non-standard-layout type" }
- + __builtin_offsetof (B, A::i); // { dg-warning "'offsetof' within
non-standard-layout type" }
+ return __builtin_offsetof (T, A::i) // { dg-error "'offsetof' to data
member in virtual base" }
+ + __builtin_offsetof (B, A::i); // { dg-error "'offsetof' to data
member in virtual base" }
}
__SIZE_TYPE__ t = foo<B> ();