On 2/6/26 4:44 AM, Marek Polacek wrote:
On Tue, Feb 03, 2026 at 12:13:41AM +0800, Jason Merrill wrote:
On 2/2/26 2:43 AM, Marek Polacek wrote:
On Fri, Jan 30, 2026 at 10:55:43AM +0800, Jason Merrill wrote:
On 1/30/26 8:36 AM, Marek Polacek wrote:
On Thu, Jan 29, 2026 at 07:32:03PM +0800, Jason Merrill wrote:
On 1/28/26 11:49 PM, Marek Polacek wrote:
On Wed, Jan 28, 2026 at 11:21:53AM +0800, Jason Merrill wrote:
On 1/28/26 10:50 AM, Marek Polacek wrote:
Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?

-- >8 --
This patch fixes the problem that when cp_parser_splice_specifier sees
:]<, it always thinks it's a template-id.  Consequently, this should compile
but does not:

       int i;
       constexpr auto r = ^^i;
       bool b = [:r:] < 42;

because we think that a template argument list follows the splice.
Fixed by using the new cp_parser_next_token_starts_template_argument_list_p
which checks that we see the whole <...>.

But this turned out to be more complicated when I considered
splice-specialization-specifiers in a template-argument-list.  With this
patch we reject

       S<[:r:] < 43> s;

but I think that's fine given the footnote in [temp.names]: "A > that
encloses [...] the template-arguments of a subsequent template-id or
splice-specialization-specifier, is considered nested for the purpose
of this description."  (We can't just check !in_template_argument_list_p
because [:x:]<> can be valid in a template argument list.)

I think that's wrong under https://eel.is/c++draft/temp.names#3.1 since the
splice is not in a type-only context and is not preceded by template or
typename.

We should accept the above and not assume that the < starts a
template-argument-list.  It would still be helpful to check whether it could
do so for -Wmissing-template-keyword.

Ah, fixed (by checking template_p and typename_p).  We don't emit
a -Wmissing-template-keyword warning but currently we say:
      note: add 'template' to denote a template
although this may change if we downgrade the error to a pedwarn.

I think that cp_parser_skip_entire_template_parameter_list has a bug
because it doesn't correctly handle >> in a template argument list;
see the xfail in parse3.C.

Sounds right.

We have to make sure that in a template argument list we don't eat
both > because the second > isn't spurious.  I gave it a few minutes
but my quick fix didn't work, so I'm leaving it for later.

I also realized that my code to detect unparenthesized splice
expressions as template arguments is wrong.  [expr.prim.splice] says that

       constexpr auto i = e<[:^^h:]>;

is ill-formed, but I think "S<[:r:] >= 1>" is fine.

Agreed, the normative citation is https://eel.is/c++draft/temp#names-6

Cool, I've added that reference to a comment in the patch.

So I moved the
checking to cp_parser_template_argument while making sure that we
only complain when the splice-expression is the whole template-argument.

Sounds good.

Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?

-- >8 --
This patch fixes the problem that when cp_parser_splice_specifier sees
:]<, it always thinks it's a template-id.  Consequently, this should compile
but does not:

      int i;
      constexpr auto r = ^^i;
      bool b = [:r:] < 42;

because we think that a template argument list follows the splice.
Fixed by using the new cp_parser_next_token_starts_template_argument_list_p
which checks that we see the whole <...>.

But this turned out to be more complicated when I considered
splice-specialization-specifiers in a template-argument-list.  We should
accept the following given [temp.names]/3:

      S<[:r:] < 43> s;

To that effect, I'm checking !in_template_argument_list_p along with

I don't think that's valid either, unfortunately; even outside of a template
argument list

     [:r:] < 42 > 0

seems to be well-formed (though pathological) code.

Oh well.  How about if I parse the template-id tentatively, and only
consider the [:r:] < 42 > as a splice-specialization-specifier when
the parsing worked out?

This patch still breaks

Sorry :(

using info = decltype(^^::);

template <info R>
bool f()
{
    return [: R :]<42>0;
}

int i;
int main()
{
    f<^^i>();
}

We must only consider it a splice-specialization-specifier as specified by
[temp.names]/3.1; otherwise we should only -Wmissing-template-keyword.  And
I think we should share that warning code with cp_parser_id_expression.

Well, I suppose we could also treat it as a (ill-formed)
splice-specialization-specifier if 'expr' is known to be a template at that
point, but not if it's dependent as above, and of course not if it's a
non-template.

I've tried to do the latter.

Ah, I wasn't thinking of them as alternatives; the latter was a refinement
of the former (an addition to [temp.names]/3.1).  That is, template_p ||
typename_p || TREE_CODE (expr) == TEMPLATE_DECL.

Done.

I don't think using _next_token_starts_ here is appropriate for this case;
[temp.names] says if we have template or typename and see < it's a
template-id regardless of what follows, and I expect we can give better
syntax errors if we go ahead with that.

I went back to cp_parser_nth_token_starts_template_argument_list_p.

Once again, I think that's wrong; see below.

The -Wmissing-template-keyword suggestion was to avoid regressing diagnostic
quality on e.g. crash6.C.  You could also give that warning at the point of
cp_parser_simulate_error in this patch.  Without that I don't see the point
of doing the tentative parse at all, as we're just going to throw away the
result.

I tried to give warnings for dependent_splice_p with missing_template_diag,
but then we suggest adding 'template' where doing so would make the code
ill-formed, so I removed that.  And so the crash6.C change remains.
I hope that's okay.

Yes, that's OK.

And _next_token_starts_ seems redundant with tentative parsing in the
missing "template" case; either one or the other seems sufficient to detect
a possible template-id, both is excessive.

I still think it would be good to share the warning code between here and
_id_expression, since they're doing the exact same thing.

I think I should be able to use missing_template_diag in
cp_parser_splice_expression instead of the error.  But that can
hopefully wait for a different patch.

Agreed.

So, how about this version?  Thanks,

@@ -6169,8 +6173,18 @@ cp_parser_splice_specifier (cp_parser *parser, bool 
template_p = false,
    /* Get the reflected operand.  */
    expr = splice (expr);
- /* If the next token is a '<', it's a splice-specialization-specifier. */
-  if (cp_lexer_next_token_is (parser->lexer, CPP_LESS))
+  /* If the next token is a <, it could be a splice-specialization-specifier.
+     But we need to handle "[:r:] < 42" where the < doesn't start a template
+     argument list.  [temp.names]/3: A < is interpreted as the delimiter of
+     a template-argument-list if either
+     -- it follows a splice-specifier that either
+       -- appears in a type-only context or
+       -- is preceded by template or typename.  */
+  if (cp_parser_nth_token_starts_template_argument_list_p (parser, 1)

This line should not change.

+      /* As a courtesy to the user, if there is a < after a template
+        name, parse the construct as an s-s-s and warn about the missing
+        'template'; it can't be anything else.  */
+      && (template_p || typename_p || TREE_CODE (expr) == TEMPLATE_DECL))

Adding this line is enough.

Jason

Reply via email to