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