On Wed, Feb 11, 2026 at 05:02:40PM +0900, Jason Merrill wrote:
> On 2/11/26 1:05 AM, Marek Polacek wrote:
> > Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?
> > 
> > -- >8 --
> > In <https://gcc.gnu.org/pipermail/gcc-patches/2026-January/705175.html>
> > (bottom of the message) we discussed not passing ctx to finish_id_expression
> > so that we can get rid of the _deferring_access_checks calls.  So the
> > cp_parser_splice_expression changes are what we want.  In order to be
> > able to do that, I had to adjust finish_id_expression_1 so that things
> > like &[: ^^S::fn :] and &[: ^^S::mem :] keep working.
> 
> Would it make sense to call build_offset_ref in cp_parser_splice_expression?

I could do that, but then I'd also have to duplicate the calls to
push/pop_deferring_access_checks, and add checks around build_offset_ref
just like in the r16-7445 patch.  But then I think I wouldn't have
to add the new splice_p parameter.  Thought maybe we want to signal to
finish_class_member_access_expr that we're coming from a splice anyway.
So I think the patch wouldn't be much simpler if I called b_o_r in _parser_.

> > gcc/cp/ChangeLog:
> > 
> >     * cp-tree.h (finish_id_expression): Adjust declaration.
> >     * parser.cc (cp_parser_splice_expression): Don't defer access checking.
> >     Don't pass context to finish_id_expression.  Call finish_id_expression
> >     with splice_p = true.
> >     (cp_parser_primary_expression): Adjust the call to finish_id_expression.
> >     (cp_parser_lambda_introducer): Likewise.
> >     (cp_parser_decltype_expr): Likewise.
> >     (cp_finish_omp_declare_variant): Likewise.
> >     * pt.cc (tsubst_expr): Likewise.
> >     * semantics.cc (finish_id_expression_1): New splice_p parameter.
> >     For FIELD_DECLs and functions, call build_offset_ref when taking
> >     the address when the entity was designated by a splice-expression.
> >     Use nullptr.  Allow a VAR_DECL in an assert.
> >     (finish_id_expression): New splice_p parameter.  Use it.
> >     (omp_reduction_lookup): Adjust the call to finish_id_expression.
> > ---
> >   gcc/cp/cp-tree.h    |  2 +-
> >   gcc/cp/parser.cc    | 21 +++++++--------------
> >   gcc/cp/pt.cc        |  1 +
> >   gcc/cp/semantics.cc | 41 +++++++++++++++++++++++++++++------------
> >   4 files changed, 38 insertions(+), 27 deletions(-)
> > 
> > diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
> > index fcad67a662c..99f4c2fc2e4 100644
> > --- a/gcc/cp/cp-tree.h
> > +++ b/gcc/cp/cp-tree.h
> > @@ -8443,7 +8443,7 @@ extern tree process_outer_var_ref             (tree, 
> > tsubst_flags_t, bool force_use = false
> >   extern cp_expr finish_id_expression               (tree, tree, tree,
> >                                              cp_id_kind *,
> >                                              bool, bool, bool *,
> > -                                            bool, bool, bool, bool,
> > +                                            bool, bool, bool, bool, bool,
> >                                              const char **,
> >                                                    location_t);
> >   extern tree finish_typeof                 (tree);
> > diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
> > index 8c46b260fff..a7ad4876ac3 100644
> > --- a/gcc/cp/parser.cc
> > +++ b/gcc/cp/parser.cc
> > @@ -6395,18 +6395,8 @@ cp_parser_splice_expression (cp_parser *parser, bool 
> > template_p,
> >      a variable template.  For &[: ^^S::x :], we have to create an
> >      OFFSET_REF.  For a VAR_DECL, we need the convert_from_reference.  */
> >         cp_unevaluated u;
> > -      /* CWG 3109 adjusted [class.protected] to say that checking access to
> > -    protected non-static members is disabled for members designated by a
> > -    splice-expression.  */
> > -      push_deferring_access_checks (dk_no_check);
> >         const char *error_msg;
> > -      /* We don't have the parser scope here, so figure out the context.  
> > In
> > -      struct S { static constexpr int i = 42; };
> > -      constexpr auto r = ^^S::i;
> > -      int i = [: r :];
> > -    we need to pass down 'S'.  */
> > -      tree ctx = DECL_P (t) ? DECL_CONTEXT (t) : NULL_TREE;
> > -      t = finish_id_expression (t, t, ctx, idk,
> > +      t = finish_id_expression (t, t, NULL_TREE, idk,
> >                             /*integral_constant_expression_p=*/false,
> >                             /*allow_non_integral_constant_expr_p=*/true,
> >                             &parser->non_integral_constant_expression_p,
> > @@ -6414,11 +6404,11 @@ cp_parser_splice_expression (cp_parser *parser, 
> > bool template_p,
> >                             /*done=*/true,
> >                             address_p,
> >                             template_arg_p,
> > +                           /*splice_p=*/true,
> >                             &error_msg,
> >                             loc);
> >         if (error_msg)
> >     cp_parser_error (parser, error_msg);
> > -      pop_deferring_access_checks ();
> >       }
> >     return t;
> > @@ -7174,6 +7164,7 @@ cp_parser_primary_expression (cp_parser *parser,
> >              &parser->non_integral_constant_expression_p,
> >              template_p, done, address_p,
> >              template_arg_p,
> > +            /*splice_p=*/false,
> >              &error_msg,
> >              id_expression.get_location ()));
> >     if (error_msg)
> > @@ -13177,6 +13168,7 @@ cp_parser_lambda_introducer (cp_parser* parser, 
> > tree lambda_expr)
> >                    /*done=*/true,
> >                    /*address_p=*/false,
> >                    /*template_arg_p=*/false,
> > +            /*splice_p=*/false,
> >                    &error_msg,
> >                    capture_token->location);
> > @@ -19299,6 +19291,7 @@ cp_parser_decltype_expr (cp_parser *parser,
> >                      /*done=*/true,
> >                      /*address_p=*/false,
> >                      /*template_arg_p=*/false,
> > +              /*splice_p=*/false,
> >                      &error_msg,
> >                id_expr_start_token->location));
> > @@ -53549,8 +53542,8 @@ cp_finish_omp_declare_variant (cp_parser *parser, 
> > cp_token *pragma_tok,
> >     = finish_id_expression (varid, variant, parser->scope,
> >                             &idk, false, true,
> >                             &parser->non_integral_constant_expression_p,
> > -                           template_p, true, false, false, &error_msg,
> > -                           varid.get_location ());
> > +                           template_p, true, false, false, false,
> > +                           &error_msg, varid.get_location ());
> >         if (error_msg)
> >     cp_parser_error (parser, error_msg);
> >       }
> > diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
> > index 7c6577b48ef..c510733d41b 100644
> > --- a/gcc/cp/pt.cc
> > +++ b/gcc/cp/pt.cc
> > @@ -21185,6 +21185,7 @@ tsubst_expr (tree t, tree args, tsubst_flags_t 
> > complain, tree in_decl)
> >                                  /*done=*/true,
> >                                  /*address_p=*/false,
> >                                  /*template_arg_p=*/false,
> > +                                /*splice_p=*/false,
> >                                  &error_msg,
> >                                  input_location);
> >     if (error_msg)
> > diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
> > index 236bc625c25..76b0ddb1b12 100644
> > --- a/gcc/cp/semantics.cc
> > +++ b/gcc/cp/semantics.cc
> > @@ -4735,6 +4735,7 @@ process_outer_var_ref (tree decl, tsubst_flags_t 
> > complain, bool odr_use)
> >      TEMPLATE_P is true iff the qualified-id was of the form
> >      "A::template B".  TEMPLATE_ARG_P is true iff this qualified name
> >      appears as a template argument.
> > +   SPLICE_P is true if ID_EXPRESSION was designated by a splice-expression.
> >      If an error occurs, and it is the kind of error that might cause
> >      the parser to abort a tentative parse, *ERROR_MSG is filled in.  It
> > @@ -4760,6 +4761,7 @@ finish_id_expression_1 (tree id_expression,
> >                     bool done,
> >                     bool address_p,
> >                     bool template_arg_p,
> > +                   bool splice_p,
> >                     const char **error_msg,
> >                     location_t location)
> >   {
> > @@ -5022,16 +5024,23 @@ finish_id_expression_1 (tree id_expression,
> >           && contract_class_ptr == current_class_ptr)
> >         {
> >           error ("%qD 'this' required when accessing a member within a "
> > -             "constructor precondition or destructor postcondition "
> > -             "contract check", decl);
> > -                 return error_mark_node;
> > +                "constructor precondition or destructor postcondition "
> > +                "contract check", decl);
> > +         return error_mark_node;
> >         }
> >       /* Since SCOPE is NULL here, this is an unqualified name.
> >          Access checking has been performed during name lookup
> >          already.  Turn off checking to avoid duplicate errors.  */
> >       push_deferring_access_checks (dk_no_check);
> > -     decl = finish_non_static_data_member (decl, NULL_TREE,
> > -                                           /*qualifying_scope=*/NULL_TREE);
> > +
> > +     if (splice_p && address_p)
> > +       decl = build_offset_ref (DECL_CONTEXT (decl), decl,
> > +                                /*address_p=*/true,
> > +                                tf_warning_or_error);
> > +     else
> > +       decl
> > +         = finish_non_static_data_member (decl, NULL_TREE,
> > +                                          /*qualifying_scope=*/NULL_TREE);
> >       pop_deferring_access_checks ();
> >     }
> >         else if (is_overloaded_fn (decl))
> > @@ -5041,6 +5050,11 @@ finish_id_expression_1 (tree id_expression,
> >          concerned with (all member fns or all non-members).  */
> >       tree first_fn = get_first_fn (decl);
> >       first_fn = STRIP_TEMPLATE (first_fn);
> > +     tree ctx = DECL_CONTEXT (first_fn);
> > +
> > +     if (splice_p && address_p)
> > +       return build_offset_ref (ctx, first_fn, /*address_p=*/true,
> > +                                tf_warning_or_error);
> >       if (!template_arg_p
> >           && (TREE_CODE (first_fn) == USING_DECL
> > @@ -5053,14 +5067,15 @@ finish_id_expression_1 (tree id_expression,
> >               && contract_class_ptr == current_class_ptr)
> >             {
> >               error ("%qD 'this' required when accessing a member within a "
> > -                 "constructor precondition or destructor postcondition "
> > -                 "contract check", decl);
> > +                    "constructor precondition or destructor postcondition "
> > +                    "contract check", decl);
> >               return error_mark_node;
> >             }
> > -         decl = maybe_dummy_object (DECL_CONTEXT (first_fn), 0);
> > +         decl = maybe_dummy_object (ctx, nullptr);
> >           return finish_class_member_access_expr (decl, id_expression,
> >                                                   /*template_p=*/false,
> > -                                                 tf_warning_or_error);
> > +                                                 tf_warning_or_error,
> > +                                                 splice_p);
> >         }
> >       decl = baselink_for_fns (decl);
> > @@ -5080,7 +5095,8 @@ finish_id_expression_1 (tree id_expression,
> >                    ??? Should this case make a clone instead, like
> >                    handle_using_decl?  */
> > -               gcc_assert (TREE_CODE (decl) == CONST_DECL);
> > +               gcc_assert (TREE_CODE (decl) == CONST_DECL
> > +                           || (splice_p && VAR_P (decl)));
> >               else
> >                 perform_or_defer_access_check (TYPE_BINFO (path),
> >                                                decl, decl,
> > @@ -5114,6 +5130,7 @@ finish_id_expression (tree id_expression,
> >                   bool done,
> >                   bool address_p,
> >                   bool template_arg_p,
> > +                 bool splice_p,
> >                   const char **error_msg,
> >                   location_t location)
> >   {
> > @@ -5123,7 +5140,7 @@ finish_id_expression (tree id_expression,
> >                           allow_non_integral_constant_expression_p,
> >                           non_integral_constant_expression_p,
> >                           template_p, done, address_p, template_arg_p,
> > -                         error_msg, location);
> > +                         splice_p, error_msg, location);
> >     return result.maybe_add_location_wrapper ();
> >   }
> > @@ -6744,7 +6761,7 @@ omp_reduction_lookup (location_t loc, tree id, tree 
> > type, tree *baselinkp,
> >     decl = error_mark_node;
> >         id = finish_id_expression (id, decl, NULL_TREE, &idk, false, true,
> >                              &nonint_cst_expression_p, false, true, false,
> > -                            false, &error_msg, loc);
> > +                            false, false, &error_msg, loc);
> >         if (idk == CP_ID_KIND_UNQUALIFIED
> >       && identifier_p (id))
> >     {
> > 
> > base-commit: 065a6ab3747fe9116643ac6754582bc195847bfc
> 

Marek

Reply via email to