On 3/4/26 4:55 PM, Boris Staletic wrote:
On Wednesday, March 4th, 2026 at 9:48 PM, Marek Polacek <[email protected]> 
wrote:

On Wed, Mar 04, 2026 at 09:26:32PM +0000, Boris Staletic wrote:
On Wednesday, March 4th, 2026 at 8:29 PM, Jakub Jelinek <[email protected]> 
wrote:

On Wed, Mar 04, 2026 at 03:21:26PM -0500, Jason Merrill wrote:
On 3/4/26 2:35 PM, Boris Staletic wrote:
Bootstrapped and tested on tested on x86_64-pc-linux-gnu.
For the patch I did run the entire `make check`.

I don't think the error message is great,
but I'm not sure how to improve it.
I did try `%D` to format the scope as well,
but that fails when the reflected entity has TU scope.

No need, I think; for decls outside the global namespace printing the
spliced decl will print its scope without needing to repeat it.  But let's
use %q#D instead of %<%D%>, 'q' to add quotes and # to add decl-specifiers.
And you might add

         inform (DECL_SOURCE_LOCATION (decl), "declared here");

after the error.

Done.


But in that case also
     auto_diagnostic_group d;

Done.

to group error and inform together.

        Jakub



Here's the v2.
-- >8 --
We have to allow splicing "regular" variables
(i.e. VAR_P (name) == true), because of static data members.
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

Extra ':' after typeck.cc.

Fixed.


        the scope of the spliced entity in a member access expression
        is of a class type.

gcc/testsuite/ChangeLog:

        * g++.dg/reflect/member21.C: New test.
---
  gcc/cp/typeck.cc                        | 14 +++++++++++++-
  gcc/testsuite/g++.dg/reflect/member21.C | 13 +++++++++++++
  2 files changed, 26 insertions(+), 1 deletion(-)
  create mode 100644 gcc/testsuite/g++.dg/reflect/member21.C

diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc
index 79eb3b5ba2..afe8a1ddf6 100644
--- a/gcc/cp/typeck.cc
+++ b/gcc/cp/typeck.cc
@@ -3600,7 +3600,19 @@ finish_class_member_access_expr (cp_expr object, tree 
name, bool template_p,
                   || 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));
+       {
+         scope = context_for_name_lookup (OVL_FIRST (name));
+         if (!CLASS_TYPE_P (scope))
+           {
+             auto_diagnostic_group d;

I think I'd move this auto_diagnostic_group into the following block.


Yeah... noticed immediately after sending v2. Fixed now.

+             if (complain & tf_error)
+               {
+                 error ("%q#D is not a member of %qT", name, object_type);
+                 inform (DECL_SOURCE_LOCATION (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..2b6222ec1a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/reflect/member21.C
@@ -0,0 +1,13 @@

Add
// PR c++/123726

Added.


Otherwise I'm OK with the patch, thanks!

+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+struct S {};
+int x;
+void f() {}
+
+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." }
+}
--
2.51.1


Marek



Here's the v3.
-- >8 --
We have to allow splicing "regular" variables
(i.e. VAR_P (name) == true), because of static data members.
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.

gcc/testsuite/ChangeLog:

        * g++.dg/reflect/member21.C: New test.
---
  gcc/cp/typeck.cc                        | 14 +++++++++++++-
  gcc/testsuite/g++.dg/reflect/member21.C | 14 ++++++++++++++
  2 files changed, 27 insertions(+), 1 deletion(-)
  create mode 100644 gcc/testsuite/g++.dg/reflect/member21.C

diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc
index 79eb3b5ba2..fd6f92bc27 100644
--- a/gcc/cp/typeck.cc
+++ b/gcc/cp/typeck.cc
@@ -3600,7 +3600,19 @@ finish_class_member_access_expr (cp_expr object, tree 
name, bool template_p,
                   || 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));
+       {
+         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 (name), "declared here");

I expect this to break if 'name' represents a template (which would be an OVERLOAD at this point, so DECL_SOURCE_LOCATION fails, which is why the existing code uses OVL_FIRST); please add that to the testcase.

+               }
+             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..1173ebf298
--- /dev/null
+++ b/gcc/testsuite/g++.dg/reflect/member21.C
@@ -0,0 +1,14 @@
+// PR c++/123726
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+struct S {};
+int x;
+void f() {}
+
+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." }
+}

Reply via email to