https://gcc.gnu.org/g:5686e69266cff73830551db19766c39bc83e3dd3
commit r16-8536-g5686e69266cff73830551db19766c39bc83e3dd3 Author: Marek Polacek <[email protected]> Date: Wed Mar 18 13:48:40 2026 -0400 c++/reflection: ICE with invalid splice in member access expr [PR123726] This patch fixes a crash on invalid code. In a class member access with a splice, the splice cannot designate something that is not a member of the object we're accessing. check_splice_expr could also detect more invalid splices, such as accessing a class template or alias template member with . or ->. PR c++/123726 gcc/cp/ChangeLog: * reflect.cc (check_splice_expr): Detect accessing a class template or alias template with . or ->. * typeck.cc (finish_class_member_access_expr): Check if the scope of the spliced entity in a member access expression is of a class type. Allow variable_template_p for context_for_name_lookup. gcc/testsuite/ChangeLog: * g++.dg/reflect/member1.C: Adjust dg-error. * g++.dg/reflect/member22.C: New test. Co-authored-by: Boris Staletic <[email protected]> Reviewed-by: Jason Merrill <[email protected]> Diff: --- gcc/cp/reflect.cc | 9 ++++++++ gcc/cp/typeck.cc | 17 +++++++++++++-- gcc/testsuite/g++.dg/reflect/member1.C | 3 +-- gcc/testsuite/g++.dg/reflect/member22.C | 37 +++++++++++++++++++++++++++++++++ 4 files changed, 62 insertions(+), 4 deletions(-) diff --git a/gcc/cp/reflect.cc b/gcc/cp/reflect.cc index b066576eba58..78d48db29ba2 100644 --- a/gcc/cp/reflect.cc +++ b/gcc/cp/reflect.cc @@ -8884,6 +8884,15 @@ check_splice_expr (location_t loc, location_t start_loc, tree t, "through a splice", t); return false; } + + /* One can't access a class template or alias template with . or ->. */ + if (member_access_p && DECL_TYPE_TEMPLATE_P (t)) + { + if (complain_p) + error_at (loc, "invalid class member access of type template %qE", t); + return false; + } + /* [expr.unary.op]/3.1 "If the operand [of unary &] is a qualified-id or splice-expression designating a non-static member m, other than an explicit object member function, m shall be a direct member of some diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc index e019d6e22a96..b88b5e3217b2 100644 --- a/gcc/cp/typeck.cc +++ b/gcc/cp/typeck.cc @@ -3599,8 +3599,21 @@ finish_class_member_access_expr (cp_expr object, tree name, bool template_p, || VAR_P (name) || TREE_CODE (name) == CONST_DECL || TREE_CODE (name) == FUNCTION_DECL - || DECL_FUNCTION_TEMPLATE_P (OVL_FIRST (name)))) - scope = context_for_name_lookup (OVL_FIRST (name)); + || DECL_FUNCTION_TEMPLATE_P (OVL_FIRST (name)) + || variable_template_p (name))) + { + scope = context_for_name_lookup (OVL_FIRST (name)); + if (!CLASS_TYPE_P (scope)) + { + if (complain & tf_error) + { + auto_diagnostic_group d; + error ("%q#D is not a member of %qT", name, object_type); + inform (DECL_SOURCE_LOCATION (OVL_FIRST (name)), "declared here"); + } + return error_mark_node; + } + } if (TREE_CODE (name) == TEMPLATE_ID_EXPR) { diff --git a/gcc/testsuite/g++.dg/reflect/member1.C b/gcc/testsuite/g++.dg/reflect/member1.C index cecb4a4204d9..124b74f12504 100644 --- a/gcc/testsuite/g++.dg/reflect/member1.C +++ b/gcc/testsuite/g++.dg/reflect/member1.C @@ -92,8 +92,7 @@ f () sp.[: ^^S::x :] = 2; // { dg-error "which is of pointer type" } c.[: ^^C<char>::x :] = 1; // { dg-error "is not a base of" } cp->[: ^^C<char>::x :] = 1; // { dg-error "is not a base of" } - s.template [: ^^S::N :].t; // { dg-error "expected a reflection of a function template" } - // { dg-message "but .S::N. is a class template" "" { target *-*-* } 20 } + s.template [: ^^S::N :].t; // { dg-error "invalid class member access of type template .S::N." } S::template [: ^^S::N<int> :] e1; // { dg-error "expected unqualified-id" } C<int>::template [: ^^S::N<int> :] e2; // { dg-error "expected unqualified-id" } s.template [: ^^S::var<int> :] = 1; // { dg-error "expected a reflection of a function template" } diff --git a/gcc/testsuite/g++.dg/reflect/member22.C b/gcc/testsuite/g++.dg/reflect/member22.C new file mode 100644 index 000000000000..8267e1846700 --- /dev/null +++ b/gcc/testsuite/g++.dg/reflect/member22.C @@ -0,0 +1,37 @@ +// PR c++/123726 +// { dg-do compile { target c++26 } } +// { dg-additional-options "-freflection" } + +struct S { + template<typename> + struct tt {}; + template<typename T> + using tu = tt<T>; +}; +int x; +void f() {} + +template<typename> +struct tt {}; + +template<typename> +void tf() {} + +template<typename> +int tv = 5; + +template<typename T> +using tu = tt<T>; + +int main() { + S s; + s.[:^^x:]; // { dg-error "not a member of .S." } + s.[:^^s:]; // { dg-error "not a member of .S." } + s.[:^^f:]; // { dg-error "not a member of .S." } + s.[:^^tt:]; // { dg-error "invalid class member access of type template .tt." } + s.template [:^^tf:]; // { dg-error "not a member of .S." } + s.[:^^tv:]; // { dg-error "not a member of .S." } + s.[:^^tu:]; // { dg-error "invalid class member access of type template .tu." } + s.[:^^S::tt:]; // { dg-error "invalid class member access of type template .S::tt." } + s.[:^^S::tu:]; // { dg-error "invalid class member access of type template .S::tu." } +}
