On Fri, Mar 06, 2026 at 01:17:08PM +0000, Boris Staletic wrote:
> 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)

I wonder if, instead of this, we should check for such invalid
uses earlier in check_splice_expr:

  if (member_access_p && DECL_TYPE_TEMPLATE_P (t))
    {
      if (complain_p)
        error_at (loc, "...");
      return false;
    }

In the test below,

  s.tt;
  s.tt<int>;

also produces "invalid use" error rather than saying that tt is
not a member.  Even if it were, the code would still be ill-formed.

> 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

This would then check variable_template_p instead.

>                  || 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
> 

Marek

Reply via email to