This is the v4 patch, incorporating Jason's remark about templates. Without the change in cp/parser.cc, the assert triggers. Similarly, in order to actually diagnose the invalid template use I had to add the same condition to condition in finish_class_member_access_expr().
Link to v3 (sorry about the typo in title - it really is v3): https://gcc.gnu.org/pipermail/gcc-patches/2026-March/709870.html Tested on g++.dg/reflect/* on x86_64-pc-linux-gnu. -- >8 -- We have to allow splicing "regular" variables (i.e. VAR_P (name) == true), because of static data members. Similar rationale goes for FUNCTION_DECL and TEMPLATE_DECL. The rest of the finish_class_member_access_expr() assumes that, if there's a scope, it is of a class type (i.e. `CLASS_TYPE_P (scope)`). For that reason, checking that `CLASS_TYPE_P (scope)` holds (and erroring otherwise), is necessary. Signed-off-by: Boris Staletic <[email protected]> PR c++/123726 gcc/cp/ChangeLog: * 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. * parser.cc (cp_parser_splice_expression): Allow TEMPLATE_DECL in member access splice expressions. gcc/testsuite/ChangeLog: * g++.dg/reflect/member21.C: New test. --- gcc/cp/parser.cc | 1 + gcc/cp/typeck.cc | 15 +++++++++++- gcc/testsuite/g++.dg/reflect/member21.C | 31 +++++++++++++++++++++++++ 3 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/g++.dg/reflect/member21.C diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index 53fbb75b15..0367ba7403 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -6371,6 +6371,7 @@ cp_parser_splice_expression (cp_parser *parser, bool template_p, gcc_assert (TREE_CODE (t) == FIELD_DECL || VAR_P (t) || TREE_CODE (t) == CONST_DECL + || TREE_CODE (t) == TEMPLATE_DECL || TREE_CODE (t) == FUNCTION_DECL || DECL_FUNCTION_TEMPLATE_P (OVL_FIRST (t)) || variable_template_p (t) diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc index 79eb3b5ba2..c578de0939 100644 --- a/gcc/cp/typeck.cc +++ b/gcc/cp/typeck.cc @@ -3598,9 +3598,22 @@ finish_class_member_access_expr (cp_expr object, tree name, bool template_p, && (TREE_CODE (name) == FIELD_DECL || VAR_P (name) || TREE_CODE (name) == CONST_DECL + || TREE_CODE (name) == TEMPLATE_DECL || TREE_CODE (name) == FUNCTION_DECL || DECL_FUNCTION_TEMPLATE_P (OVL_FIRST (name)))) - scope = context_for_name_lookup (OVL_FIRST (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/member21.C b/gcc/testsuite/g++.dg/reflect/member21.C new file mode 100644 index 0000000000..d7a488c45d --- /dev/null +++ b/gcc/testsuite/g++.dg/reflect/member21.C @@ -0,0 +1,31 @@ +// PR c++/123726 +// { dg-do compile { target c++26 } } +// { dg-additional-options "-freflection" } + +struct S {}; +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 "not a member of .S." } + s.template [:^^tf:]; // { dg-error "not a member of .S." } + s.[:^^tv:]; // { dg-error "not a member of .S." } + s.[:^^tu:]; // { dg-error "not a member of .S." } +} + -- 2.51.1
