On 10/6/26 5:55 PM, Marek Polacek wrote:
Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk/16?
OK.
-- >8 -- We ICE in perform_or_defer_access_check on a null binfo of the object type here: struct A { int m{}; }; template <int> struct E : A {}; template <class W> int get(W *o) { return o->[:^^A::m:]; } int main() { return get((E<2> *)0); } The problem is that in tsubst_expr we call finish_non_static_data_member on any FIELD_DECL, but when the FIELD_DECL is coming from o->[:^^A::m:], the object's type may not have been instantiated yet. I think we should just send COMPONENT_REFs with a splice expression down the finish_class_member_access_expr path which has: if (!currently_open_class (object_type) && !complete_type_or_maybe_complain (object_type, object, complain)) return error_mark_node; so it will instantiate the class and create a TREE_BINFO. With that, the dependent_splice_p check should be unreachable. PR c++/126794 gcc/cp/ChangeLog: * pt.cc (tsubst_expr) <case COMPONENT_REF>: Don't call finish_non_static_data_member on a FIELD_DECL of a COMPONENT_REF when COMPONENT_REF_SPLICE_P is set. Don't check dependent_splice_p in an assert. gcc/testsuite/ChangeLog: * g++.dg/reflect/member16.C: Adjust dg-error. * g++.dg/reflect/member25.C: New test. --- gcc/cp/pt.cc | 8 ++-- gcc/testsuite/g++.dg/reflect/member16.C | 4 +- gcc/testsuite/g++.dg/reflect/member25.C | 61 +++++++++++++++++++++++++ 3 files changed, 68 insertions(+), 5 deletions(-) create mode 100644 gcc/testsuite/g++.dg/reflect/member25.C diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index c7f5d55b14f..d68cf5aeb23 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -22905,13 +22905,15 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) r = build_ptrmemfunc_access_expr (object, DECL_NAME (member)); RETURN (r); } - else if (TREE_CODE (member) == FIELD_DECL) + /* For obj->[:^^A::m:], go down the finish_class_member_access_expr + path because object's type may not be instantiated yet. */ + else if (TREE_CODE (member) == FIELD_DECL + && !COMPONENT_REF_SPLICE_P (t)) { /* Assume access of this FIELD_DECL has already been checked; we don't recheck it to avoid bogus access errors when substituting a reduced constant initializer (97740). */ - gcc_checking_assert (TREE_CODE (TREE_OPERAND (t, 1)) == FIELD_DECL - || dependent_splice_p (TREE_OPERAND (t, 1))); + gcc_checking_assert (TREE_CODE (TREE_OPERAND (t, 1)) == FIELD_DECL); push_deferring_access_checks (dk_deferred); r = finish_non_static_data_member (member, object, NULL_TREE, complain); diff --git a/gcc/testsuite/g++.dg/reflect/member16.C b/gcc/testsuite/g++.dg/reflect/member16.C index 2679cdc6714..473363d72a4 100644 --- a/gcc/testsuite/g++.dg/reflect/member16.C +++ b/gcc/testsuite/g++.dg/reflect/member16.C @@ -46,7 +46,7 @@ bar (S &c, T &d, U &g, V &h) d.[: ^^B::b :] = 5; // { dg-error "'B' is an ambiguous base of 'D'" } d.[: ^^C::c :] = 6; d.[: ^^D::d :] = 7; - d.[: ^^I::i :] = 8; // { dg-error "invalid use of non-static data member 'I::i'" } + d.[: ^^I::i :] = 8; // { dg-error "'I' is not a base of 'D'" } g.[: ^^E::_ :] = 1; g.[: ^^F::_ :] = 2; g.[: ^^G::_ :] = 3; @@ -54,7 +54,7 @@ bar (S &c, T &d, U &g, V &h) h.[: ^^F::_ :] = 5; // { dg-error "'F' is an ambiguous base of 'H'" } h.[: ^^G::_ :] = 6; h.[: ^^H::_ :] = 7; - h.[: ^^J::_ :] = 8; // { dg-error "invalid use of non-static data member 'J::_'" } + h.[: ^^J::_ :] = 8; // { dg-error "'J' is not a base of 'H'" } }voiddiff --git a/gcc/testsuite/g++.dg/reflect/member25.C b/gcc/testsuite/g++.dg/reflect/member25.C new file mode 100644 index 00000000000..4db05cebdd3 --- /dev/null +++ b/gcc/testsuite/g++.dg/reflect/member25.C @@ -0,0 +1,61 @@ +// PR c++/126794 +// { dg-do compile { target c++26 } } +// { dg-additional-options "-freflection" } + +template<class, class> struct same_type; +template<class T> struct same_type<T, T> {}; + +struct A { int m{}; }; +template<int> struct E : A {}; + +int +f1 () +{ + E<2> *o = 0; + return o->[:^^A::m:]; +} + +template<class W> +int +get (W *o) +{ + return o->[:^^A::m:]; +} + +int +f2 () +{ + return get ((E<2> *) 0); +} + +template<class W> +void +f3 (W *o) +{ + same_type<decltype (o->[:^^A::m:]), int>(); + same_type<decltype ((o->[:^^A::m:])), int &>(); +} +template void f3 (E<3> *); + +template<int> struct F; + +template<class W> +int +f4 (W *o) +{ + return o->[:^^A::m:]; // { dg-error "invalid use of incomplete type" } +} + +int +f5 () +{ + return f4 ((F<0> *) 0); +} + +template<class W> +int +f6 (W &o) +{ + return o.[:^^A::m:]; +} +template int f6 (E<4> &); base-commit: 1b961bf9d7e76de9a36f93d8749dbe7fae302246
