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

Reply via email to