From 853831a06e30e72ea14054e0bce14505be56e8d7 Mon Sep 17 00:00:00 2001 From: Travis Cross Date: Tue, 18 Aug 2026 23:07:25 +0000 Subject: [PATCH] Tolerate malformed comments in shebang lookahead Our `SHEBANG` rule did not accept `#!/*`, even though that's a valid shebang per `rustc`. The trouble is the interaction between the negative lookahead and the cut within `BLOCK_COMMENT`: the cut forces an immediate error even within the context of a negative lookahead. We rely on that semantic elsewhere. To fix this, let's add a `SHEBANG_BLOCK_COMMENT` rule that accepts what `rustc` does. --- src/shebang.md | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/shebang.md b/src/shebang.md index 96d7ce6b94..dbc5ee339d 100644 --- a/src/shebang.md +++ b/src/shebang.md @@ -17,18 +17,31 @@ A *[shebang]* is an optional line that is typically used in Unix-like systems to r[shebang.syntax] ```grammar,lexer @root SHEBANG -> - `#!` !((WHITESPACE | LINE_COMMENT | BLOCK_COMMENT)* `[`) + `#!` !((WHITESPACE | LINE_COMMENT | SHEBANG_BLOCK_COMMENT)* `[`) ~LF* (LF | EOF) + +SHEBANG_BLOCK_COMMENT -> + `/*` !(`!` | `*` ![`*` `/`]) + ( SHEBANG_NESTED_BLOCK_COMMENT | (!(`*/` | `/*`) CHAR) )* + `*/` + +SHEBANG_NESTED_BLOCK_COMMENT -> + `/*` + ( SHEBANG_NESTED_BLOCK_COMMENT | (!(`*/` | `/*`) CHAR) )* + `*/` ``` r[shebang.syntax-description] -The shebang starts with the characters `#!` and extends through the first `U+000A` (LF) or through EOF if no LF is present. If the `#!` characters are followed by `[` (ignoring any intervening [comments] or [whitespace]), the line is not considered a shebang (to avoid ambiguity with an [inner attribute]). +The shebang starts with the characters `#!` and extends through the first `U+000A` (LF) or through EOF if no LF is present. If the `#!` characters are followed by `[` (ignoring any intervening [whitespace] or [non-doc comments]), the line is not considered a shebang (to avoid ambiguity with an [inner attribute]). + +> [!NOTE] +> Doc comments are not ignored when determining whether `[` follows the `#!` characters. For example, `#! /*! */ [allow(unused)]` at the start of a file is a shebang, not an inner attribute, because `/*! */` is a doc comment. Likewise, text following `#!` that resembles an unterminated block comment, as in `#!/*`, does not cause an error; the line is a shebang. r[shebang.position] The shebang may appear immediately at the start of the file or after the optional [byte order mark]. [byte order mark]: https://en.wikipedia.org/wiki/Byte_order_mark#UTF-8 -[comments]: comments.md [inner attribute]: attributes.md +[non-doc comments]: comments.normal [shebang]: https://en.wikipedia.org/wiki/Shebang_(Unix) [whitespace]: whitespace.md