On 1/22/26 6:17 AM, Marek Polacek wrote:
Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?

-- >8 --
In cp_parser_splice_spec_is_nns_p I didn't use saved_token_sentinel:
its rollback uses cp_lexer_previous_token so if we are the first token
in the file, there are no previous tokens so we crash.

It would be simple to just use the _safe variant of cp_lexer_previous_token
and be done with this.  But that's not how this worked out: I saw a new
-fcompare-debug FAIL with pr104025.C.  The problem is that at the end of
cp_parser_id_expression we have a saved_token_sentinel guarded by
warn_missing_template_keyword and in that spot lexer->buffer is NULL (so
cp_lexer_set_source_position_from_token would be skipped).  pr104025.C
is compiled twice, the second time with "-w -fcompare-debug-second".  So
the first time we don't _set_source_position back to where we were after the
_skip_entire_template_parameter_list (lexer->buffer is NULL) and the second
time we don't get to the saved_token_sentinel at all.  That left us with
different columns in the location:

   "pr104025.C":16:16 vs "pr104025.C":16:12

thus the -fcompare-debug FAIL.  I assume we don't want -fcompare-debug
to ignore the column location.

Agreed.

So this patch adds STS_ROLLBACK_SAFE to
use the _safe variant of cp_lexer_previous_token.

How about if safe_previous_token returns null then we use the current token instead? I'd rather not add separate modes.

And then
cp_parser_splice_spec_is_nns_p can be simplified.

gcc/cp/ChangeLog:

        * parser.cc (enum saved_token_sentinel_mode): Add STS_ROLLBACK_SAFE.
        (saved_token_sentinel::rollback): Add a new "safe" parameter.  Use
        cp_lexer_safe_previous_token rather than cp_lexer_previous_token if
        "safe" is true.
        (saved_token_sentinel::~saved_token_sentinel): Also check
        STS_ROLLBACK_SAFE.
        (cp_parser_splice_spec_is_nns_p): Use saved_token_sentinel.  Refactor.
---
  gcc/cp/parser.cc | 39 ++++++++++++++++++++-------------------
  1 file changed, 20 insertions(+), 19 deletions(-)

diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 393c8b2ec44..5319e9d7fb6 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -1604,6 +1604,7 @@ cp_lexer_rollback_tokens (cp_lexer* lexer)
  enum saved_token_sentinel_mode {
    STS_COMMIT,
    STS_ROLLBACK,
+  STS_ROLLBACK_SAFE,
    STS_DONOTHING
  };
@@ -1613,9 +1614,11 @@ enum saved_token_sentinel_mode { Creating a variable saves tokens. MODE determines what happens when the
     object is destroyed.  STS_COMMIT commits tokens (default),
-   STS_ROLLBACK rolls-back and STS_DONOTHING does nothing.  Calling
+   STS_ROLLBACK{,_SAFE} rolls-back and STS_DONOTHING does nothing.  Calling
     rollback() will immediately roll-back tokens and set MODE to
-   STS_DONOTHING.  */
+   STS_DONOTHING.  STS_ROLLBACK_SAFE is like STS_ROLLBACK, but uses the
+   _safe version of _previous_token.  Use the _SAFE version when we may be at
+   the first token in the file in which case there are no previous tokens.  */
struct saved_token_sentinel
  {
@@ -1629,19 +1632,25 @@ struct saved_token_sentinel
      len = lexer->saved_tokens.length ();
      cp_lexer_save_tokens (lexer);
    }
-  void rollback ()
+  void rollback (bool safe = false)
    {
      cp_lexer_rollback_tokens (lexer);
-    cp_lexer_set_source_position_from_token
-      (cp_lexer_previous_token (lexer));
+    if (safe)
+      {
+       if (cp_token *prev_token = cp_lexer_safe_previous_token (lexer))
+         cp_lexer_set_source_position_from_token (prev_token);
+      }
+    else
+      cp_lexer_set_source_position_from_token
+       (cp_lexer_previous_token (lexer));
      mode = STS_DONOTHING;
    }
    ~saved_token_sentinel ()
    {
      if (mode == STS_COMMIT)
        cp_lexer_commit_tokens (lexer);
-    else if (mode == STS_ROLLBACK)
-      rollback ();
+    else if (mode == STS_ROLLBACK || mode == STS_ROLLBACK_SAFE)
+      rollback (mode == STS_ROLLBACK_SAFE);
gcc_assert (lexer->saved_tokens.length () == len);
    }
@@ -6458,20 +6467,15 @@ cp_parser_splice_scope_specifier (cp_parser *parser, 
bool typename_p,
  static bool
  cp_parser_splice_spec_is_nns_p (cp_parser *parser)
  {
-  /* ??? It'd be nice to use saved_token_sentinel, but its rollback
-     uses cp_lexer_previous_token, but we may be the first token in the
-     file so there are no previous tokens.  Sigh.  */
-  cp_lexer_save_tokens (parser->lexer);
+  saved_token_sentinel toks (parser->lexer, STS_ROLLBACK_SAFE);
if (cp_lexer_next_token_is_keyword (parser->lexer, RID_TYPENAME)
        || cp_lexer_next_token_is_keyword (parser->lexer, RID_TEMPLATE))
      cp_lexer_consume_token (parser->lexer);
- bool ok = false;
    size_t n = cp_parser_skip_balanced_tokens (parser, 1);
    if (n != 1)
      {
-      ok = true;
        /* Consume tokens up to the ':]' (including).  */
        for (n = n - 1; n; --n)
        cp_lexer_consume_token (parser->lexer);
@@ -6479,15 +6483,12 @@ cp_parser_splice_spec_is_nns_p (cp_parser *parser)
        /* Consume the whole '<....>', if present.  */
        if (cp_lexer_next_token_is (parser->lexer, CPP_LESS)
          && !cp_parser_skip_entire_template_parameter_list (parser))
-       ok = false;
+       return false;
- ok = ok && cp_lexer_next_token_is (parser->lexer, CPP_SCOPE);
+      return cp_lexer_next_token_is (parser->lexer, CPP_SCOPE);
      }
- /* Roll back the tokens we skipped. */
-  cp_lexer_rollback_tokens (parser->lexer);
-
-  return ok;
+  return false;
  }
/* Return true if the N-th token is '[:' and its closing ':]' is NOT

base-commit: 2a20b792133c8f3b3c5fcf2d9f647b1634362637

Reply via email to