about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2024-11-09 19:16:43 +0100
committerGitHub <noreply@github.com>2024-11-09 19:16:43 +0100
commit9b50092fdc8ffd40751e5e7efaa689a4e7ac2b56 (patch)
treeec122eb26e5604d04c8df181c356c8f5dfb849c3
parentb73478b6ee1ed915ac3727da02d4675835588538 (diff)
parent1990f1560801ca3f9e6a3286e58204aa329ee037 (diff)
downloadrust-9b50092fdc8ffd40751e5e7efaa689a4e7ac2b56.tar.gz
rust-9b50092fdc8ffd40751e5e7efaa689a4e7ac2b56.zip
Rollup merge of #132341 - compiler-errors:raw-lt-prefix-id, r=chenyukang
Reject raw lifetime followed by `'`, like regular lifetimes do

See comment. We want to reject cases like `'r#long'id`, which currently gets interpreted as a raw lifetime (`'r#long`) followed by a lifetime (`'id`). This could have alternative lexes, such as an overlong char literal (`'r#long'`) followed by an identifier (`id`). To avoid committing to this in any case, let's reject the whole thing.

`@mattheww,` is this what you were looking for in https://github.com/rust-lang/reference/pull/1603#issuecomment-2339237325? I'd say ignore the details about the specific error message (the fact that this gets reinterpreted as a char literal is 🤷), just that because this causes a lexer error we're effectively saving syntactical space like you wanted.
-rw-r--r--compiler/rustc_lexer/src/lib.rs12
-rw-r--r--tests/ui/lifetimes/raw/immediately-followed-by-lt.rs14
-rw-r--r--tests/ui/lifetimes/raw/immediately-followed-by-lt.stderr13
3 files changed, 38 insertions, 1 deletions
diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs
index b0ab50dd773..f9f2a14dbd2 100644
--- a/compiler/rustc_lexer/src/lib.rs
+++ b/compiler/rustc_lexer/src/lib.rs
@@ -715,7 +715,17 @@ impl Cursor<'_> {
             self.bump();
             self.bump();
             self.eat_while(is_id_continue);
-            return RawLifetime;
+            match self.first() {
+                '\'' => {
+                    // Check if after skipping literal contents we've met a closing
+                    // single quote (which means that user attempted to create a
+                    // string with single quotes).
+                    self.bump();
+                    let kind = Char { terminated: true };
+                    return Literal { kind, suffix_start: self.pos_within_token() };
+                }
+                _ => return RawLifetime,
+            }
         }
 
         // Either a lifetime or a character literal with
diff --git a/tests/ui/lifetimes/raw/immediately-followed-by-lt.rs b/tests/ui/lifetimes/raw/immediately-followed-by-lt.rs
new file mode 100644
index 00000000000..fe2b6de7bb3
--- /dev/null
+++ b/tests/ui/lifetimes/raw/immediately-followed-by-lt.rs
@@ -0,0 +1,14 @@
+//@ edition: 2021
+
+// Make sure we reject the case where a raw lifetime is immediately followed by another
+// lifetime. This reserves a modest amount of space for changing lexing to, for example,
+// delay rejection of overlong char literals like `'r#long'id`.
+
+macro_rules! w {
+    ($($tt:tt)*) => {}
+}
+
+w!('r#long'id);
+//~^ ERROR character literal may only contain one codepoint
+
+fn main() {}
diff --git a/tests/ui/lifetimes/raw/immediately-followed-by-lt.stderr b/tests/ui/lifetimes/raw/immediately-followed-by-lt.stderr
new file mode 100644
index 00000000000..1caeec84b22
--- /dev/null
+++ b/tests/ui/lifetimes/raw/immediately-followed-by-lt.stderr
@@ -0,0 +1,13 @@
+error: character literal may only contain one codepoint
+  --> $DIR/immediately-followed-by-lt.rs:11:4
+   |
+LL | w!('r#long'id);
+   |    ^^^^^^^^
+   |
+help: if you meant to write a string literal, use double quotes
+   |
+LL | w!("r#long"id);
+   |    ~      ~
+
+error: aborting due to 1 previous error
+