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 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; + 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 @@ +// { 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
