From 321a5db7d4026cf703d6deebc413c855ba133142 Mon Sep 17 00:00:00 2001
From: Peter Jaszkowiak
Date: Sun, 14 Apr 2024 17:37:45 -0600
Subject: [PATCH] Reserve guarded string literals (RFC 3593)
---
compiler/rustc_lexer/src/lib.rs | 93 +++++-
compiler/rustc_lint/messages.ftl | 3 +
.../rustc_lint/src/context/diagnostics.rs | 3 +
compiler/rustc_lint/src/lints.rs | 7 +
compiler/rustc_lint_defs/src/builtin.rs | 41 +++
compiler/rustc_lint_defs/src/lib.rs | 2 +
compiler/rustc_parse/messages.ftl | 4 +
compiler/rustc_parse/src/errors.rs | 18 ++
compiler/rustc_parse/src/lexer/mod.rs | 84 ++++-
src/librustdoc/html/highlight.rs | 1 +
.../crates/parser/src/lexed_str.rs | 6 +
.../reserved-guarded-strings-macro-2021.rs | 20 ++
.../reserved-guarded-strings-macro-2024.rs | 21 ++
.../reserved-guarded-strings-lexing.rs | 80 +++++
.../reserved-guarded-strings-lexing.stderr | 271 ++++++++++++++++
.../reserved-guarded-strings-migration.fixed | 99 ++++++
.../reserved-guarded-strings-migration.rs | 99 ++++++
.../reserved-guarded-strings-migration.stderr | 293 ++++++++++++++++++
.../reserved-guarded-strings-via-macro-2.rs | 18 ++
...eserved-guarded-strings-via-macro-2.stderr | 20 ++
.../reserved-guarded-strings-via-macro.rs | 12 +
.../ui/rust-2024/reserved-guarded-strings.rs | 74 +++++
.../rust-2024/reserved-guarded-strings.stderr | 254 +++++++++++++++
23 files changed, 1514 insertions(+), 9 deletions(-)
create mode 100644 tests/ui/rust-2024/auxiliary/reserved-guarded-strings-macro-2021.rs
create mode 100644 tests/ui/rust-2024/auxiliary/reserved-guarded-strings-macro-2024.rs
create mode 100644 tests/ui/rust-2024/reserved-guarded-strings-lexing.rs
create mode 100644 tests/ui/rust-2024/reserved-guarded-strings-lexing.stderr
create mode 100644 tests/ui/rust-2024/reserved-guarded-strings-migration.fixed
create mode 100644 tests/ui/rust-2024/reserved-guarded-strings-migration.rs
create mode 100644 tests/ui/rust-2024/reserved-guarded-strings-migration.stderr
create mode 100644 tests/ui/rust-2024/reserved-guarded-strings-via-macro-2.rs
create mode 100644 tests/ui/rust-2024/reserved-guarded-strings-via-macro-2.stderr
create mode 100644 tests/ui/rust-2024/reserved-guarded-strings-via-macro.rs
create mode 100644 tests/ui/rust-2024/reserved-guarded-strings.rs
create mode 100644 tests/ui/rust-2024/reserved-guarded-strings.stderr
diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs
index 60aab668cbaa6..b0ab50dd77388 100644
--- a/compiler/rustc_lexer/src/lib.rs
+++ b/compiler/rustc_lexer/src/lib.rs
@@ -104,6 +104,12 @@ pub enum TokenKind {
/// for emoji identifier recovery, as those are not meant to be ever accepted.
InvalidPrefix,
+ /// Guarded string literal prefix: `#"` or `##`.
+ ///
+ /// Used for reserving "guarded strings" (RFC 3598) in edition 2024.
+ /// Split into the component tokens on older editions.
+ GuardedStrPrefix,
+
/// Examples: `12u8`, `1.0e-40`, `b"123"`. Note that `_` is an invalid
/// suffix, but may be present here on string and float literals. Users of
/// this type will need to check for and reject that case.
@@ -191,30 +197,41 @@ pub enum DocStyle {
/// `rustc_ast::ast::LitKind`).
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum LiteralKind {
- /// "12_u8", "0o100", "0b120i99", "1f32".
+ /// `12_u8`, `0o100`, `0b120i99`, `1f32`.
Int { base: Base, empty_int: bool },
- /// "12.34f32", "1e3", but not "1f32".
+ /// `12.34f32`, `1e3`, but not `1f32`.
Float { base: Base, empty_exponent: bool },
- /// "'a'", "'\\'", "'''", "';"
+ /// `'a'`, `'\\'`, `'''`, `';`
Char { terminated: bool },
- /// "b'a'", "b'\\'", "b'''", "b';"
+ /// `b'a'`, `b'\\'`, `b'''`, `b';`
Byte { terminated: bool },
- /// ""abc"", ""abc"
+ /// `"abc"`, `"abc`
Str { terminated: bool },
- /// "b"abc"", "b"abc"
+ /// `b"abc"`, `b"abc`
ByteStr { terminated: bool },
/// `c"abc"`, `c"abc`
CStr { terminated: bool },
- /// "r"abc"", "r#"abc"#", "r####"ab"###"c"####", "r#"a". `None` indicates
+ /// `r"abc"`, `r#"abc"#`, `r####"ab"###"c"####`, `r#"a`. `None` indicates
/// an invalid literal.
RawStr { n_hashes: Option },
- /// "br"abc"", "br#"abc"#", "br####"ab"###"c"####", "br#"a". `None`
+ /// `br"abc"`, `br#"abc"#`, `br####"ab"###"c"####`, `br#"a`. `None`
/// indicates an invalid literal.
RawByteStr { n_hashes: Option },
/// `cr"abc"`, "cr#"abc"#", `cr#"a`. `None` indicates an invalid literal.
RawCStr { n_hashes: Option },
}
+/// `#"abc"#`, `##"a"` (fewer closing), or even `#"a` (unterminated).
+///
+/// Can capture fewer closing hashes than starting hashes,
+/// for more efficient lexing and better backwards diagnostics.
+#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
+pub struct GuardedStr {
+ pub n_hashes: u32,
+ pub terminated: bool,
+ pub token_len: u32,
+}
+
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub enum RawStrError {
/// Non `#` characters exist between `r` and `"`, e.g. `r##~"abcde"##`
@@ -403,6 +420,12 @@ impl Cursor<'_> {
TokenKind::Literal { kind: literal_kind, suffix_start }
}
+ // Guarded string literal prefix: `#"` or `##`
+ '#' if matches!(self.first(), '"' | '#') => {
+ self.bump();
+ TokenKind::GuardedStrPrefix
+ }
+
// One-symbol tokens.
';' => Semi,
',' => Comma,
@@ -780,6 +803,60 @@ impl Cursor<'_> {
false
}
+ /// Attempt to lex for a guarded string literal.
+ ///
+ /// Used by `rustc_parse::lexer` to lex for guarded strings
+ /// conditionally based on edition.
+ ///
+ /// Note: this will not reset the `Cursor` when a
+ /// guarded string is not found. It is the caller's
+ /// responsibility to do so.
+ pub fn guarded_double_quoted_string(&mut self) -> Option {
+ debug_assert!(self.prev() != '#');
+
+ let mut n_start_hashes: u32 = 0;
+ while self.first() == '#' {
+ n_start_hashes += 1;
+ self.bump();
+ }
+
+ if self.first() != '"' {
+ return None;
+ }
+ self.bump();
+ debug_assert!(self.prev() == '"');
+
+ // Lex the string itself as a normal string literal
+ // so we can recover that for older editions later.
+ let terminated = self.double_quoted_string();
+ if !terminated {
+ let token_len = self.pos_within_token();
+ self.reset_pos_within_token();
+
+ return Some(GuardedStr { n_hashes: n_start_hashes, terminated: false, token_len });
+ }
+
+ // Consume closing '#' symbols.
+ // Note that this will not consume extra trailing `#` characters:
+ // `###"abcde"####` is lexed as a `GuardedStr { n_end_hashes: 3, .. }`
+ // followed by a `#` token.
+ let mut n_end_hashes = 0;
+ while self.first() == '#' && n_end_hashes < n_start_hashes {
+ n_end_hashes += 1;
+ self.bump();
+ }
+
+ // Reserved syntax, always an error, so it doesn't matter if
+ // `n_start_hashes != n_end_hashes`.
+
+ self.eat_literal_suffix();
+
+ let token_len = self.pos_within_token();
+ self.reset_pos_within_token();
+
+ Some(GuardedStr { n_hashes: n_start_hashes, terminated: true, token_len })
+ }
+
/// Eats the double-quoted string and returns `n_hashes` and an error if encountered.
fn raw_double_quoted_string(&mut self, prefix_len: u32) -> Result {
// Wrap the actual function to handle the error with too many hashes.
diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl
index d379959487191..e733e92c7cb33 100644
--- a/compiler/rustc_lint/messages.ftl
+++ b/compiler/rustc_lint/messages.ftl
@@ -740,6 +740,9 @@ lint_reserved_prefix = prefix `{$prefix}` is unknown
.label = unknown prefix
.suggestion = insert whitespace here to avoid this being parsed as a prefix in Rust 2021
+lint_reserved_string = will be parsed as a guarded string in Rust 2024
+ .suggestion = insert whitespace here to avoid this being parsed as a guarded string in Rust 2024
+
lint_shadowed_into_iter =
this method call resolves to `<&{$target} as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<{$target} as IntoIterator>::into_iter` in Rust {$edition}
.use_iter_suggestion = use `.iter()` instead of `.into_iter()` to avoid ambiguity
diff --git a/compiler/rustc_lint/src/context/diagnostics.rs b/compiler/rustc_lint/src/context/diagnostics.rs
index b5ab56912cb2d..565c3c0425256 100644
--- a/compiler/rustc_lint/src/context/diagnostics.rs
+++ b/compiler/rustc_lint/src/context/diagnostics.rs
@@ -176,6 +176,9 @@ pub(super) fn decorate_lint(sess: &Session, diagnostic: BuiltinLintDiag, diag: &
lints::RawPrefix { label: label_span, suggestion: label_span.shrink_to_hi() }
.decorate_lint(diag);
}
+ BuiltinLintDiag::ReservedString(suggestion) => {
+ lints::ReservedString { suggestion }.decorate_lint(diag);
+ }
BuiltinLintDiag::UnusedBuiltinAttribute { attr_name, macro_name, invoc_span } => {
lints::UnusedBuiltinAttribute { invoc_span, attr_name, macro_name }.decorate_lint(diag);
}
diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs
index a861894a44493..87afeca0b28f6 100644
--- a/compiler/rustc_lint/src/lints.rs
+++ b/compiler/rustc_lint/src/lints.rs
@@ -3053,3 +3053,10 @@ pub(crate) enum MutRefSugg {
#[derive(LintDiagnostic)]
#[diag(lint_unqualified_local_imports)]
pub(crate) struct UnqualifiedLocalImportsDiag {}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_reserved_string)]
+pub(crate) struct ReservedString {
+ #[suggestion(code = " ", applicability = "machine-applicable")]
+ pub suggestion: Span,
+}
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index a123059df8f12..827791c54be01 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -92,6 +92,7 @@ declare_lint_pass! {
RUST_2021_INCOMPATIBLE_OR_PATTERNS,
RUST_2021_PREFIXES_INCOMPATIBLE_SYNTAX,
RUST_2021_PRELUDE_COLLISIONS,
+ RUST_2024_GUARDED_STRING_INCOMPATIBLE_SYNTAX,
RUST_2024_INCOMPATIBLE_PAT,
RUST_2024_PRELUDE_COLLISIONS,
SELF_CONSTRUCTOR_FROM_OUTER_ITEM,
@@ -4996,3 +4997,43 @@ declare_lint! {
Warn,
"detects pointer to integer transmutes in const functions and associated constants",
}
+
+declare_lint! {
+ /// The `rust_2024_guarded_string_incompatible_syntax` lint detects `#` tokens
+ /// that will be parsed as part of a guarded string literal in Rust 2024.
+ ///
+ /// ### Example
+ ///
+ /// ```rust,edition2021,compile_fail
+ /// #![deny(rust_2024_guarded_string_incompatible_syntax)]
+ ///
+ /// macro_rules! m {
+ /// (# $x:expr #) => ();
+ /// (# $x:expr) => ();
+ /// }
+ ///
+ /// m!(#"hey"#);
+ /// m!(#"hello");
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// Prior to Rust 2024, `#"hey"#` is three tokens: the first `#`
+ /// followed by the string literal `"hey"` then the final `#`.
+ /// In Rust 2024, the whole sequence is considered a single token.
+ ///
+ /// This lint suggests to add whitespace between the leading `#`
+ /// and the string to keep them separated in Rust 2024.
+ // Allow this lint -- rustdoc doesn't yet support threading edition into this lint's parser.
+ #[allow(rustdoc::invalid_rust_codeblocks)]
+ pub RUST_2024_GUARDED_STRING_INCOMPATIBLE_SYNTAX,
+ Allow,
+ "will be parsed as a guarded string in Rust 2024",
+ @future_incompatible = FutureIncompatibleInfo {
+ reason: FutureIncompatibilityReason::EditionError(Edition::Edition2024),
+ reference: "issue #123735 ",
+ };
+ crate_level_only
+}
diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs
index 386918a5c4157..c01fa5c54d65e 100644
--- a/compiler/rustc_lint_defs/src/lib.rs
+++ b/compiler/rustc_lint_defs/src/lib.rs
@@ -614,6 +614,8 @@ pub enum BuiltinLintDiag {
ReservedPrefix(Span, String),
/// `'r#` in edition < 2021.
RawPrefix(Span),
+ /// `##` or `#"` is edition < 2024.
+ ReservedString(Span),
TrailingMacro(bool, Ident),
BreakWithLabelAndLoop(Span),
UnicodeTextFlow(Span, String),
diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl
index 948199fd55c65..ba5e2ddf4fcd1 100644
--- a/compiler/rustc_parse/messages.ftl
+++ b/compiler/rustc_parse/messages.ftl
@@ -706,6 +706,10 @@ parse_require_colon_after_labeled_expression = labeled expression must be follow
.label = the label
.suggestion = add `:` after the label
+parse_reserved_string = invalid string literal
+ .note = unprefixed guarded string literals are reserved for future use since Rust 2024
+ .suggestion_whitespace = consider inserting whitespace here
+
parse_return_types_use_thin_arrow = return types are denoted using `->`
.suggestion = use `->` instead
diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs
index dade39127515f..124975f67f1ac 100644
--- a/compiler/rustc_parse/src/errors.rs
+++ b/compiler/rustc_parse/src/errors.rs
@@ -2110,6 +2110,24 @@ pub(crate) enum UnknownPrefixSugg {
},
}
+#[derive(Diagnostic)]
+#[diag(parse_reserved_string)]
+#[note]
+pub(crate) struct ReservedString {
+ #[primary_span]
+ pub span: Span,
+ #[subdiagnostic]
+ pub sugg: Option,
+}
+#[derive(Subdiagnostic)]
+#[suggestion(
+ parse_suggestion_whitespace,
+ code = " ",
+ applicability = "maybe-incorrect",
+ style = "verbose"
+)]
+pub(crate) struct GuardedStringSugg(#[primary_span] pub Span);
+
#[derive(Diagnostic)]
#[diag(parse_too_many_hashes)]
pub(crate) struct TooManyHashes {
diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs
index 3e46fc93fa49d..d627ef3d2cbe3 100644
--- a/compiler/rustc_parse/src/lexer/mod.rs
+++ b/compiler/rustc_parse/src/lexer/mod.rs
@@ -10,7 +10,8 @@ use rustc_lexer::unescape::{self, EscapeError, Mode};
use rustc_lexer::{Base, Cursor, DocStyle, LiteralKind, RawStrError};
use rustc_session::lint::BuiltinLintDiag;
use rustc_session::lint::builtin::{
- RUST_2021_PREFIXES_INCOMPATIBLE_SYNTAX, TEXT_DIRECTION_CODEPOINT_IN_COMMENT,
+ RUST_2021_PREFIXES_INCOMPATIBLE_SYNTAX, RUST_2024_GUARDED_STRING_INCOMPATIBLE_SYNTAX,
+ TEXT_DIRECTION_CODEPOINT_IN_COMMENT,
};
use rustc_session::parse::ParseSess;
use rustc_span::symbol::Symbol;
@@ -251,6 +252,7 @@ impl<'psess, 'src> StringReader<'psess, 'src> {
let prefix_span = self.mk_sp(start, lit_start);
return (Token::new(self.ident(start), prefix_span), preceded_by_whitespace);
}
+ rustc_lexer::TokenKind::GuardedStrPrefix => self.maybe_report_guarded_str(start, str_before),
rustc_lexer::TokenKind::Literal { kind, suffix_start } => {
let suffix_start = start + BytePos(suffix_start);
let (kind, symbol) = self.cook_lexer_literal(start, suffix_start, kind);
@@ -781,6 +783,86 @@ impl<'psess, 'src> StringReader<'psess, 'src> {
}
}
+ /// Detect guarded string literal syntax
+ ///
+ /// RFC 3598 reserved this syntax for future use. As of Rust 2024,
+ /// using this syntax produces an error. In earlier editions, however, it
+ /// only results in an (allowed by default) lint, and is treated as
+ /// separate tokens.
+ fn maybe_report_guarded_str(&mut self, start: BytePos, str_before: &'src str) -> TokenKind {
+ let span = self.mk_sp(start, self.pos);
+ let edition2024 = span.edition().at_least_rust_2024();
+
+ let space_pos = start + BytePos(1);
+ let space_span = self.mk_sp(space_pos, space_pos);
+
+ let mut cursor = Cursor::new(str_before);
+
+ let (span, unterminated) = match cursor.guarded_double_quoted_string() {
+ Some(rustc_lexer::GuardedStr { n_hashes, terminated, token_len }) => {
+ let end = start + BytePos(token_len);
+ let span = self.mk_sp(start, end);
+ let str_start = start + BytePos(n_hashes);
+
+ if edition2024 {
+ self.cursor = cursor;
+ self.pos = end;
+ }
+
+ let unterminated = if terminated { None } else { Some(str_start) };
+
+ (span, unterminated)
+ }
+ _ => {
+ // We should only get here in the `##+` case.
+ debug_assert_eq!(self.str_from_to(start, start + BytePos(2)), "##");
+
+ (span, None)
+ }
+ };
+ if edition2024 {
+ if let Some(str_start) = unterminated {
+ // Only a fatal error if string is unterminated.
+ self.dcx()
+ .struct_span_fatal(
+ self.mk_sp(str_start, self.pos),
+ "unterminated double quote string",
+ )
+ .with_code(E0765)
+ .emit()
+ }
+
+ let sugg = if span.from_expansion() {
+ None
+ } else {
+ Some(errors::GuardedStringSugg(space_span))
+ };
+
+ // In Edition 2024 and later, emit a hard error.
+ let err = self.dcx().emit_err(errors::ReservedString { span, sugg });
+
+ token::Literal(token::Lit {
+ kind: token::Err(err),
+ symbol: self.symbol_from_to(start, self.pos),
+ suffix: None,
+ })
+ } else {
+ // Before Rust 2024, only emit a lint for migration.
+ self.psess.buffer_lint(
+ RUST_2024_GUARDED_STRING_INCOMPATIBLE_SYNTAX,
+ span,
+ ast::CRATE_NODE_ID,
+ BuiltinLintDiag::ReservedString(space_span),
+ );
+
+ // For backwards compatibility, roll back to after just the first `#`
+ // and return the `Pound` token.
+ self.pos = start + BytePos(1);
+ self.cursor = Cursor::new(&str_before[1..]);
+ token::Pound
+ }
+ }
+
fn report_too_many_hashes(&self, start: BytePos, num: u32) -> ! {
self.dcx().emit_fatal(errors::TooManyHashes { span: self.mk_sp(start, self.pos), num });
}
diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs
index e7ddd4b73b47b..b68b729509635 100644
--- a/src/librustdoc/html/highlight.rs
+++ b/src/librustdoc/html/highlight.rs
@@ -845,6 +845,7 @@ impl<'src> Classifier<'src> {
// Number literals.
LiteralKind::Float { .. } | LiteralKind::Int { .. } => Class::Number,
},
+ TokenKind::GuardedStrPrefix => return no_highlight(sink),
TokenKind::Ident | TokenKind::RawIdent if lookahead == Some(TokenKind::Bang) => {
self.in_macro = true;
sink(Highlight::EnterSpan { class: Class::Macro(self.new_span(before, text)) });
diff --git a/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs b/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs
index dceac815e0b5c..7ea23b4f752c1 100644
--- a/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs
@@ -187,6 +187,12 @@ impl<'a> Converter<'a> {
}
rustc_lexer::TokenKind::RawIdent => IDENT,
+
+ rustc_lexer::TokenKind::GuardedStrPrefix => {
+ err = "Invalid string literal (reserved syntax)";
+ ERROR
+ },
+
rustc_lexer::TokenKind::Literal { kind, .. } => {
self.extend_literal(token_text.len(), kind);
return;
diff --git a/tests/ui/rust-2024/auxiliary/reserved-guarded-strings-macro-2021.rs b/tests/ui/rust-2024/auxiliary/reserved-guarded-strings-macro-2021.rs
new file mode 100644
index 0000000000000..81080fcdce307
--- /dev/null
+++ b/tests/ui/rust-2024/auxiliary/reserved-guarded-strings-macro-2021.rs
@@ -0,0 +1,20 @@
+//@ force-host
+//@ edition:2021
+//@ no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::TokenStream;
+use std::str::FromStr;
+
+#[proc_macro]
+pub fn number_of_tokens_in_a_guarded_string_literal(_: TokenStream) -> TokenStream {
+ TokenStream::from_str("#\"abc\"#").unwrap().into_iter().count().to_string().parse().unwrap()
+}
+
+#[proc_macro]
+pub fn number_of_tokens_in_a_guarded_unterminated_string_literal(_: TokenStream) -> TokenStream {
+ TokenStream::from_str("#\"abc\"").unwrap().into_iter().count().to_string().parse().unwrap()
+}
diff --git a/tests/ui/rust-2024/auxiliary/reserved-guarded-strings-macro-2024.rs b/tests/ui/rust-2024/auxiliary/reserved-guarded-strings-macro-2024.rs
new file mode 100644
index 0000000000000..2c3dc30f0ae9b
--- /dev/null
+++ b/tests/ui/rust-2024/auxiliary/reserved-guarded-strings-macro-2024.rs
@@ -0,0 +1,21 @@
+//@ force-host
+//@ compile-flags: -Zunstable-options
+//@ edition:2024
+//@ no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+
+use proc_macro::TokenStream;
+use std::str::FromStr;
+
+#[proc_macro]
+pub fn number_of_tokens_in_a_guarded_string_literal(_: TokenStream) -> TokenStream {
+ TokenStream::from_str("#\"abc\"#").unwrap().into_iter().count().to_string().parse().unwrap()
+}
+
+#[proc_macro]
+pub fn number_of_tokens_in_a_guarded_unterminated_string_literal(_: TokenStream) -> TokenStream {
+ TokenStream::from_str("#\"abc\"").unwrap().into_iter().count().to_string().parse().unwrap()
+}
diff --git a/tests/ui/rust-2024/reserved-guarded-strings-lexing.rs b/tests/ui/rust-2024/reserved-guarded-strings-lexing.rs
new file mode 100644
index 0000000000000..83e0dcbb4bebc
--- /dev/null
+++ b/tests/ui/rust-2024/reserved-guarded-strings-lexing.rs
@@ -0,0 +1,80 @@
+//@ edition:2021
+// ignore-tidy-linelength
+
+#![warn(rust_2024_guarded_string_incompatible_syntax)]
+
+macro_rules! demo2 {
+ ( $a:tt $b:tt ) => { println!("two tokens") };
+}
+
+macro_rules! demo3 {
+ ( $a:tt $b:tt $c:tt ) => { println!("three tokens") };
+}
+
+macro_rules! demo4 {
+ ( $a:tt $b:tt $c:tt $d:tt ) => { println!("four tokens") };
+}
+
+macro_rules! demo5 {
+ ( $a:tt $b:tt $c:tt $d:tt $e:tt ) => { println!("five tokens") };
+}
+
+macro_rules! demo7 {
+ ( $a:tt $b:tt $c:tt $d:tt $e:tt $f:tt $g:tt ) => { println!("seven tokens") };
+}
+
+
+fn main() {
+ demo3!(## "foo");
+ //~^ WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax]
+ //~| WARNING hard error in Rust 2024
+ demo4!(### "foo");
+ //~^ WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax]
+ //~| WARNING hard error in Rust 2024
+ //~| WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax]
+ //~| WARNING hard error in Rust 2024
+ demo4!(## "foo"#);
+ //~^ WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax]
+ //~| WARNING hard error in Rust 2024
+ demo7!(### "foo"###);
+ //~^ WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax]
+ //~| WARNING hard error in Rust 2024
+ //~| WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax]
+ //~| WARNING hard error in Rust 2024
+ //~| WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax]
+ //~| WARNING hard error in Rust 2024
+ //~| WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax]
+ //~| WARNING hard error in Rust 2024
+
+ demo5!(###"foo"#);
+ //~^ WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax]
+ //~| WARNING hard error in Rust 2024
+ //~| WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax]
+ //~| WARNING hard error in Rust 2024
+ //~| WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax]
+ //~| WARNING hard error in Rust 2024
+ demo5!(#"foo"###);
+ //~^ WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax]
+ //~| WARNING hard error in Rust 2024
+ //~| WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax]
+ //~| WARNING hard error in Rust 2024
+ //~| WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax]
+ //~| WARNING hard error in Rust 2024
+ demo4!("foo"###);
+ //~^ WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax]
+ //~| WARNING hard error in Rust 2024
+ //~| WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax]
+ //~| WARNING hard error in Rust 2024
+
+ // Non-ascii identifiers
+ demo2!(Ñ"foo");
+ //~^ ERROR prefix `Ñ` is unknown
+ demo4!(Ñ#""#);
+ //~^ ERROR prefix `Ñ` is unknown
+ //~| WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax]
+ //~| WARNING hard error in Rust 2024
+ demo3!(🙃#"");
+ //~^ ERROR identifiers cannot contain emoji
+ //~| WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax]
+ //~| WARNING hard error in Rust 2024
+}
diff --git a/tests/ui/rust-2024/reserved-guarded-strings-lexing.stderr b/tests/ui/rust-2024/reserved-guarded-strings-lexing.stderr
new file mode 100644
index 0000000000000..e2e1ac42f05c2
--- /dev/null
+++ b/tests/ui/rust-2024/reserved-guarded-strings-lexing.stderr
@@ -0,0 +1,271 @@
+error: prefix `Ñ` is unknown
+ --> $DIR/reserved-guarded-strings-lexing.rs:70:12
+ |
+LL | demo2!(Ñ"foo");
+ | ^ unknown prefix
+ |
+ = note: prefixed identifiers and literals are reserved since Rust 2021
+help: consider inserting whitespace here
+ |
+LL | demo2!(Ñ "foo");
+ | +
+
+error: prefix `Ñ` is unknown
+ --> $DIR/reserved-guarded-strings-lexing.rs:72:12
+ |
+LL | demo4!(Ñ#""#);
+ | ^ unknown prefix
+ |
+ = note: prefixed identifiers and literals are reserved since Rust 2021
+help: consider inserting whitespace here
+ |
+LL | demo4!(Ñ #""#);
+ | +
+
+error: identifiers cannot contain emoji: `🙃`
+ --> $DIR/reserved-guarded-strings-lexing.rs:76:12
+ |
+LL | demo3!(🙃#"");
+ | ^^
+
+warning: will be parsed as a guarded string in Rust 2024
+ --> $DIR/reserved-guarded-strings-lexing.rs:28:12
+ |
+LL | demo3!(## "foo");
+ | ^^
+ |
+ = warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
+ = note: for more information, see issue #123735
+note: the lint level is defined here
+ --> $DIR/reserved-guarded-strings-lexing.rs:4:9
+ |
+LL | #![warn(rust_2024_guarded_string_incompatible_syntax)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024
+ |
+LL | demo3!(# # "foo");
+ | +
+
+warning: will be parsed as a guarded string in Rust 2024
+ --> $DIR/reserved-guarded-strings-lexing.rs:31:12
+ |
+LL | demo4!(### "foo");
+ | ^^
+ |
+ = warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
+ = note: for more information, see issue #123735
+help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024
+ |
+LL | demo4!(# ## "foo");
+ | +
+
+warning: will be parsed as a guarded string in Rust 2024
+ --> $DIR/reserved-guarded-strings-lexing.rs:31:13
+ |
+LL | demo4!(### "foo");
+ | ^^
+ |
+ = warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
+ = note: for more information, see issue #123735
+help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024
+ |
+LL | demo4!(## # "foo");
+ | +
+
+warning: will be parsed as a guarded string in Rust 2024
+ --> $DIR/reserved-guarded-strings-lexing.rs:36:12
+ |
+LL | demo4!(## "foo"#);
+ | ^^
+ |
+ = warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
+ = note: for more information, see issue #123735
+help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024
+ |
+LL | demo4!(# # "foo"#);
+ | +
+
+warning: will be parsed as a guarded string in Rust 2024
+ --> $DIR/reserved-guarded-strings-lexing.rs:39:12
+ |
+LL | demo7!(### "foo"###);
+ | ^^
+ |
+ = warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
+ = note: for more information, see issue #123735
+help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024
+ |
+LL | demo7!(# ## "foo"###);
+ | +
+
+warning: will be parsed as a guarded string in Rust 2024
+ --> $DIR/reserved-guarded-strings-lexing.rs:39:13
+ |
+LL | demo7!(### "foo"###);
+ | ^^
+ |
+ = warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
+ = note: for more information, see issue #123735
+help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024
+ |
+LL | demo7!(## # "foo"###);
+ | +
+
+warning: will be parsed as a guarded string in Rust 2024
+ --> $DIR/reserved-guarded-strings-lexing.rs:39:21
+ |
+LL | demo7!(### "foo"###);
+ | ^^
+ |
+ = warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
+ = note: for more information, see issue #123735
+help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024
+ |
+LL | demo7!(### "foo"# ##);
+ | +
+
+warning: will be parsed as a guarded string in Rust 2024
+ --> $DIR/reserved-guarded-strings-lexing.rs:39:22
+ |
+LL | demo7!(### "foo"###);
+ | ^^
+ |
+ = warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
+ = note: for more information, see issue #123735
+help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024
+ |
+LL | demo7!(### "foo"## #);
+ | +
+
+warning: will be parsed as a guarded string in Rust 2024
+ --> $DIR/reserved-guarded-strings-lexing.rs:49:12
+ |
+LL | demo5!(###"foo"#);
+ | ^^^^^^^^^
+ |
+ = warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
+ = note: for more information, see issue #123735
+help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024
+ |
+LL | demo5!(# ##"foo"#);
+ | +
+
+warning: will be parsed as a guarded string in Rust 2024
+ --> $DIR/reserved-guarded-strings-lexing.rs:49:13
+ |
+LL | demo5!(###"foo"#);
+ | ^^^^^^^^
+ |
+ = warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
+ = note: for more information, see issue #123735
+help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024
+ |
+LL | demo5!(## #"foo"#);
+ | +
+
+warning: will be parsed as a guarded string in Rust 2024
+ --> $DIR/reserved-guarded-strings-lexing.rs:49:14
+ |
+LL | demo5!(###"foo"#);
+ | ^^^^^^^
+ |
+ = warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
+ = note: for more information, see issue #123735
+help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024
+ |
+LL | demo5!(### "foo"#);
+ | +
+
+warning: will be parsed as a guarded string in Rust 2024
+ --> $DIR/reserved-guarded-strings-lexing.rs:56:12
+ |
+LL | demo5!(#"foo"###);
+ | ^^^^^^^
+ |
+ = warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
+ = note: for more information, see issue #123735
+help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024
+ |
+LL | demo5!(# "foo"###);
+ | +
+
+warning: will be parsed as a guarded string in Rust 2024
+ --> $DIR/reserved-guarded-strings-lexing.rs:56:18
+ |
+LL | demo5!(#"foo"###);
+ | ^^
+ |
+ = warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
+ = note: for more information, see issue #123735
+help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024
+ |
+LL | demo5!(#"foo"# ##);
+ | +
+
+warning: will be parsed as a guarded string in Rust 2024
+ --> $DIR/reserved-guarded-strings-lexing.rs:56:19
+ |
+LL | demo5!(#"foo"###);
+ | ^^
+ |
+ = warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
+ = note: for more information, see issue #123735
+help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024
+ |
+LL | demo5!(#"foo"## #);
+ | +
+
+warning: will be parsed as a guarded string in Rust 2024
+ --> $DIR/reserved-guarded-strings-lexing.rs:63:17
+ |
+LL | demo4!("foo"###);
+ | ^^
+ |
+ = warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
+ = note: for more information, see issue #123735
+help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024
+ |
+LL | demo4!("foo"# ##);
+ | +
+
+warning: will be parsed as a guarded string in Rust 2024
+ --> $DIR/reserved-guarded-strings-lexing.rs:63:18
+ |
+LL | demo4!("foo"###);
+ | ^^
+ |
+ = warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
+ = note: for more information, see issue #123735
+help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024
+ |
+LL | demo4!("foo"## #);
+ | +
+
+warning: will be parsed as a guarded string in Rust 2024
+ --> $DIR/reserved-guarded-strings-lexing.rs:72:13
+ |
+LL | demo4!(Ñ#""#);
+ | ^^^^
+ |
+ = warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
+ = note: for more information, see issue #123735
+help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024
+ |
+LL | demo4!(Ñ# ""#);
+ | +
+
+warning: will be parsed as a guarded string in Rust 2024
+ --> $DIR/reserved-guarded-strings-lexing.rs:76:13
+ |
+LL | demo3!(🙃#"");
+ | ^^^
+ |
+ = warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
+ = note: for more information, see issue #123735
+help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024
+ |
+LL | demo3!(🙃# "");
+ | +
+
+error: aborting due to 3 previous errors; 18 warnings emitted
+
diff --git a/tests/ui/rust-2024/reserved-guarded-strings-migration.fixed b/tests/ui/rust-2024/reserved-guarded-strings-migration.fixed
new file mode 100644
index 0000000000000..d92df7b5375a7
--- /dev/null
+++ b/tests/ui/rust-2024/reserved-guarded-strings-migration.fixed
@@ -0,0 +1,99 @@
+//@ check-pass
+//@ run-rustfix
+//@ edition:2021
+
+#![warn(rust_2024_guarded_string_incompatible_syntax)]
+
+macro_rules! demo1 {
+ ( $a:tt ) => { println!("one tokens") };
+}
+
+macro_rules! demo2 {
+ ( $a:tt $b:tt ) => { println!("two tokens") };
+}
+
+macro_rules! demo3 {
+ ( $a:tt $b:tt $c:tt ) => { println!("three tokens") };
+}
+
+macro_rules! demo4 {
+ ( $a:tt $b:tt $c:tt $d:tt ) => { println!("four tokens") };
+}
+
+macro_rules! demo5 {
+ ( $a:tt $b:tt $c:tt $d:tt $e:tt ) => { println!("five tokens") };
+}
+
+macro_rules! demo6 {
+ ( $a:tt $b:tt $c:tt $d:tt $e:tt $f:tt ) => { println!("six tokens") };
+}
+
+
+fn main() {
+ demo1!("");
+ demo2!(# "");
+ demo3!(# ""#);
+ demo2!(# "foo");
+ demo3!(# "foo"#);
+ demo2!("foo"#);
+
+ demo3!(# # "foo");
+ //~^ WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax]
+ //~| WARNING hard error in Rust 2024
+ demo4!(# # # "foo");
+ //~^ WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax]
+ //~| WARNING hard error in Rust 2024
+ //~| WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax]
+ //~| WARNING hard error in Rust 2024
+ demo4!(# # "foo"#);
+ //~^ WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax]
+ //~| WARNING hard error in Rust 2024
+ demo6!(# # # "foo"# #);
+ //~^ WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax]
+ //~| WARNING hard error in Rust 2024
+ //~| WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax]
+ //~| WARNING hard error in Rust 2024
+ //~| WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax]
+ //~| WARNING hard error in Rust 2024
+
+ demo4!("foo"# # #);
+ //~^ WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax]
+ //~| WARNING hard error in Rust 2024
+ //~| WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax]
+ //~| WARNING hard error in Rust 2024
+
+ demo2!(# "");
+ //~^ WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax]
+ //~| WARNING hard error in Rust 2024
+ demo3!(# ""#);
+ //~^ WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax]
+ //~| WARNING hard error in Rust 2024
+ demo3!(# # "");
+ //~^ WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax]
+ //~| WARNING hard error in Rust 2024
+ //~| WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax]
+ //~| WARNING hard error in Rust 2024
+ demo2!(# "foo");
+ //~^ WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax]
+ //~| WARNING hard error in Rust 2024
+ demo3!(# # "foo");
+ //~^ WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax]
+ //~| WARNING hard error in Rust 2024
+ //~| WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax]
+ //~| WARNING hard error in Rust 2024
+ demo3!(# "foo"#);
+ //~^ WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax]
+ //~| WARNING hard error in Rust 2024
+ demo4!(# # "foo"#);
+ //~^ WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax]
+ //~| WARNING hard error in Rust 2024
+ //~| WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax]
+ //~| WARNING hard error in Rust 2024
+ demo5!(# # "foo"# #);
+ //~^ WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax]
+ //~| WARNING hard error in Rust 2024
+ //~| WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax]
+ //~| WARNING hard error in Rust 2024
+ //~| WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax]
+ //~| WARNING hard error in Rust 2024
+}
diff --git a/tests/ui/rust-2024/reserved-guarded-strings-migration.rs b/tests/ui/rust-2024/reserved-guarded-strings-migration.rs
new file mode 100644
index 0000000000000..5905f2abe3232
--- /dev/null
+++ b/tests/ui/rust-2024/reserved-guarded-strings-migration.rs
@@ -0,0 +1,99 @@
+//@ check-pass
+//@ run-rustfix
+//@ edition:2021
+
+#![warn(rust_2024_guarded_string_incompatible_syntax)]
+
+macro_rules! demo1 {
+ ( $a:tt ) => { println!("one tokens") };
+}
+
+macro_rules! demo2 {
+ ( $a:tt $b:tt ) => { println!("two tokens") };
+}
+
+macro_rules! demo3 {
+ ( $a:tt $b:tt $c:tt ) => { println!("three tokens") };
+}
+
+macro_rules! demo4 {
+ ( $a:tt $b:tt $c:tt $d:tt ) => { println!("four tokens") };
+}
+
+macro_rules! demo5 {
+ ( $a:tt $b:tt $c:tt $d:tt $e:tt ) => { println!("five tokens") };
+}
+
+macro_rules! demo6 {
+ ( $a:tt $b:tt $c:tt $d:tt $e:tt $f:tt ) => { println!("six tokens") };
+}
+
+
+fn main() {
+ demo1!("");
+ demo2!(# "");
+ demo3!(# ""#);
+ demo2!(# "foo");
+ demo3!(# "foo"#);
+ demo2!("foo"#);
+
+ demo3!(## "foo");
+ //~^ WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax]
+ //~| WARNING hard error in Rust 2024
+ demo4!(### "foo");
+ //~^ WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax]
+ //~| WARNING hard error in Rust 2024
+ //~| WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax]
+ //~| WARNING hard error in Rust 2024
+ demo4!(## "foo"#);
+ //~^ WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax]
+ //~| WARNING hard error in Rust 2024
+ demo6!(### "foo"##);
+ //~^ WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax]
+ //~| WARNING hard error in Rust 2024
+ //~| WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax]
+ //~| WARNING hard error in Rust 2024
+ //~| WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax]
+ //~| WARNING hard error in Rust 2024
+
+ demo4!("foo"###);
+ //~^ WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax]
+ //~| WARNING hard error in Rust 2024
+ //~| WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax]
+ //~| WARNING hard error in Rust 2024
+
+ demo2!(#"");
+ //~^ WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax]
+ //~| WARNING hard error in Rust 2024
+ demo3!(#""#);
+ //~^ WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax]
+ //~| WARNING hard error in Rust 2024
+ demo3!(##"");
+ //~^ WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax]
+ //~| WARNING hard error in Rust 2024
+ //~| WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax]
+ //~| WARNING hard error in Rust 2024
+ demo2!(#"foo");
+ //~^ WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax]
+ //~| WARNING hard error in Rust 2024
+ demo3!(##"foo");
+ //~^ WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax]
+ //~| WARNING hard error in Rust 2024
+ //~| WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax]
+ //~| WARNING hard error in Rust 2024
+ demo3!(#"foo"#);
+ //~^ WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax]
+ //~| WARNING hard error in Rust 2024
+ demo4!(##"foo"#);
+ //~^ WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax]
+ //~| WARNING hard error in Rust 2024
+ //~| WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax]
+ //~| WARNING hard error in Rust 2024
+ demo5!(##"foo"##);
+ //~^ WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax]
+ //~| WARNING hard error in Rust 2024
+ //~| WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax]
+ //~| WARNING hard error in Rust 2024
+ //~| WARNING parsed as a guarded string in Rust 2024 [rust_2024_guarded_string_incompatible_syntax]
+ //~| WARNING hard error in Rust 2024
+}
diff --git a/tests/ui/rust-2024/reserved-guarded-strings-migration.stderr b/tests/ui/rust-2024/reserved-guarded-strings-migration.stderr
new file mode 100644
index 0000000000000..d7f8e5c9b4b24
--- /dev/null
+++ b/tests/ui/rust-2024/reserved-guarded-strings-migration.stderr
@@ -0,0 +1,293 @@
+warning: will be parsed as a guarded string in Rust 2024
+ --> $DIR/reserved-guarded-strings-migration.rs:40:12
+ |
+LL | demo3!(## "foo");
+ | ^^
+ |
+ = warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
+ = note: for more information, see issue #123735
+note: the lint level is defined here
+ --> $DIR/reserved-guarded-strings-migration.rs:5:9
+ |
+LL | #![warn(rust_2024_guarded_string_incompatible_syntax)]
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024
+ |
+LL | demo3!(# # "foo");
+ | +
+
+warning: will be parsed as a guarded string in Rust 2024
+ --> $DIR/reserved-guarded-strings-migration.rs:43:12
+ |
+LL | demo4!(### "foo");
+ | ^^
+ |
+ = warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
+ = note: for more information, see issue #123735
+help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024
+ |
+LL | demo4!(# ## "foo");
+ | +
+
+warning: will be parsed as a guarded string in Rust 2024
+ --> $DIR/reserved-guarded-strings-migration.rs:43:13
+ |
+LL | demo4!(### "foo");
+ | ^^
+ |
+ = warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
+ = note: for more information, see issue #123735
+help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024
+ |
+LL | demo4!(## # "foo");
+ | +
+
+warning: will be parsed as a guarded string in Rust 2024
+ --> $DIR/reserved-guarded-strings-migration.rs:48:12
+ |
+LL | demo4!(## "foo"#);
+ | ^^
+ |
+ = warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
+ = note: for more information, see issue #123735
+help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024
+ |
+LL | demo4!(# # "foo"#);
+ | +
+
+warning: will be parsed as a guarded string in Rust 2024
+ --> $DIR/reserved-guarded-strings-migration.rs:51:12
+ |
+LL | demo6!(### "foo"##);
+ | ^^
+ |
+ = warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
+ = note: for more information, see issue #123735
+help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024
+ |
+LL | demo6!(# ## "foo"##);
+ | +
+
+warning: will be parsed as a guarded string in Rust 2024
+ --> $DIR/reserved-guarded-strings-migration.rs:51:13
+ |
+LL | demo6!(### "foo"##);
+ | ^^
+ |
+ = warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
+ = note: for more information, see issue #123735
+help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024
+ |
+LL | demo6!(## # "foo"##);
+ | +
+
+warning: will be parsed as a guarded string in Rust 2024
+ --> $DIR/reserved-guarded-strings-migration.rs:51:21
+ |
+LL | demo6!(### "foo"##);
+ | ^^
+ |
+ = warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
+ = note: for more information, see issue #123735
+help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024
+ |
+LL | demo6!(### "foo"# #);
+ | +
+
+warning: will be parsed as a guarded string in Rust 2024
+ --> $DIR/reserved-guarded-strings-migration.rs:59:17
+ |
+LL | demo4!("foo"###);
+ | ^^
+ |
+ = warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
+ = note: for more information, see issue #123735
+help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024
+ |
+LL | demo4!("foo"# ##);
+ | +
+
+warning: will be parsed as a guarded string in Rust 2024
+ --> $DIR/reserved-guarded-strings-migration.rs:59:18
+ |
+LL | demo4!("foo"###);
+ | ^^
+ |
+ = warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
+ = note: for more information, see issue #123735
+help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024
+ |
+LL | demo4!("foo"## #);
+ | +
+
+warning: will be parsed as a guarded string in Rust 2024
+ --> $DIR/reserved-guarded-strings-migration.rs:65:12
+ |
+LL | demo2!(#"");
+ | ^^^
+ |
+ = warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
+ = note: for more information, see issue #123735
+help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024
+ |
+LL | demo2!(# "");
+ | +
+
+warning: will be parsed as a guarded string in Rust 2024
+ --> $DIR/reserved-guarded-strings-migration.rs:68:12
+ |
+LL | demo3!(#""#);
+ | ^^^^
+ |
+ = warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
+ = note: for more information, see issue #123735
+help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024
+ |
+LL | demo3!(# ""#);
+ | +
+
+warning: will be parsed as a guarded string in Rust 2024
+ --> $DIR/reserved-guarded-strings-migration.rs:71:12
+ |
+LL | demo3!(##"");
+ | ^^^^
+ |
+ = warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
+ = note: for more information, see issue #123735
+help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024
+ |
+LL | demo3!(# #"");
+ | +
+
+warning: will be parsed as a guarded string in Rust 2024
+ --> $DIR/reserved-guarded-strings-migration.rs:71:13
+ |
+LL | demo3!(##"");
+ | ^^^
+ |
+ = warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
+ = note: for more information, see issue #123735
+help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024
+ |
+LL | demo3!(## "");
+ | +
+
+warning: will be parsed as a guarded string in Rust 2024
+ --> $DIR/reserved-guarded-strings-migration.rs:76:12
+ |
+LL | demo2!(#"foo");
+ | ^^^^^^
+ |
+ = warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
+ = note: for more information, see issue #123735
+help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024
+ |
+LL | demo2!(# "foo");
+ | +
+
+warning: will be parsed as a guarded string in Rust 2024
+ --> $DIR/reserved-guarded-strings-migration.rs:79:12
+ |
+LL | demo3!(##"foo");
+ | ^^^^^^^
+ |
+ = warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
+ = note: for more information, see issue #123735
+help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024
+ |
+LL | demo3!(# #"foo");
+ | +
+
+warning: will be parsed as a guarded string in Rust 2024
+ --> $DIR/reserved-guarded-strings-migration.rs:79:13
+ |
+LL | demo3!(##"foo");
+ | ^^^^^^
+ |
+ = warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
+ = note: for more information, see issue #123735
+help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024
+ |
+LL | demo3!(## "foo");
+ | +
+
+warning: will be parsed as a guarded string in Rust 2024
+ --> $DIR/reserved-guarded-strings-migration.rs:84:12
+ |
+LL | demo3!(#"foo"#);
+ | ^^^^^^^
+ |
+ = warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
+ = note: for more information, see issue #123735
+help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024
+ |
+LL | demo3!(# "foo"#);
+ | +
+
+warning: will be parsed as a guarded string in Rust 2024
+ --> $DIR/reserved-guarded-strings-migration.rs:87:12
+ |
+LL | demo4!(##"foo"#);
+ | ^^^^^^^^
+ |
+ = warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
+ = note: for more information, see issue #123735
+help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024
+ |
+LL | demo4!(# #"foo"#);
+ | +
+
+warning: will be parsed as a guarded string in Rust 2024
+ --> $DIR/reserved-guarded-strings-migration.rs:87:13
+ |
+LL | demo4!(##"foo"#);
+ | ^^^^^^^
+ |
+ = warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
+ = note: for more information, see issue #123735
+help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024
+ |
+LL | demo4!(## "foo"#);
+ | +
+
+warning: will be parsed as a guarded string in Rust 2024
+ --> $DIR/reserved-guarded-strings-migration.rs:92:12
+ |
+LL | demo5!(##"foo"##);
+ | ^^^^^^^^^
+ |
+ = warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
+ = note: for more information, see issue #123735
+help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024
+ |
+LL | demo5!(# #"foo"##);
+ | +
+
+warning: will be parsed as a guarded string in Rust 2024
+ --> $DIR/reserved-guarded-strings-migration.rs:92:13
+ |
+LL | demo5!(##"foo"##);
+ | ^^^^^^^
+ |
+ = warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
+ = note: for more information, see issue #123735
+help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024
+ |
+LL | demo5!(## "foo"##);
+ | +
+
+warning: will be parsed as a guarded string in Rust 2024
+ --> $DIR/reserved-guarded-strings-migration.rs:92:19
+ |
+LL | demo5!(##"foo"##);
+ | ^^
+ |
+ = warning: this is accepted in the current edition (Rust 2021) but is a hard error in Rust 2024!
+ = note: for more information, see issue #123735
+help: insert whitespace here to avoid this being parsed as a guarded string in Rust 2024
+ |
+LL | demo5!(##"foo"# #);
+ | +
+
+warning: 22 warnings emitted
+
diff --git a/tests/ui/rust-2024/reserved-guarded-strings-via-macro-2.rs b/tests/ui/rust-2024/reserved-guarded-strings-via-macro-2.rs
new file mode 100644
index 0000000000000..3f9f373ba227b
--- /dev/null
+++ b/tests/ui/rust-2024/reserved-guarded-strings-via-macro-2.rs
@@ -0,0 +1,18 @@
+//@ edition:2021
+//@ aux-build:reserved-guarded-strings-macro-2021.rs
+//@ aux-build:reserved-guarded-strings-macro-2024.rs
+
+extern crate reserved_guarded_strings_macro_2021 as m2021;
+extern crate reserved_guarded_strings_macro_2024 as m2024;
+
+fn main() {
+ // Ok:
+ m2021::number_of_tokens_in_a_guarded_string_literal!();
+ m2021::number_of_tokens_in_a_guarded_unterminated_string_literal!();
+
+ // Error, even though *this* crate is 2021:
+ m2024::number_of_tokens_in_a_guarded_string_literal!();
+ //~^ ERROR invalid string literal
+ m2024::number_of_tokens_in_a_guarded_unterminated_string_literal!();
+ //~^ ERROR invalid string literal
+}
diff --git a/tests/ui/rust-2024/reserved-guarded-strings-via-macro-2.stderr b/tests/ui/rust-2024/reserved-guarded-strings-via-macro-2.stderr
new file mode 100644
index 0000000000000..1074c8a682bfb
--- /dev/null
+++ b/tests/ui/rust-2024/reserved-guarded-strings-via-macro-2.stderr
@@ -0,0 +1,20 @@
+error: invalid string literal
+ --> $DIR/reserved-guarded-strings-via-macro-2.rs:14:5
+ |
+LL | m2024::number_of_tokens_in_a_guarded_string_literal!();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: unprefixed guarded string literals are reserved for future use since Rust 2024
+ = note: this error originates in the macro `m2024::number_of_tokens_in_a_guarded_string_literal` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: invalid string literal
+ --> $DIR/reserved-guarded-strings-via-macro-2.rs:16:5
+ |
+LL | m2024::number_of_tokens_in_a_guarded_unterminated_string_literal!();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: unprefixed guarded string literals are reserved for future use since Rust 2024
+ = note: this error originates in the macro `m2024::number_of_tokens_in_a_guarded_unterminated_string_literal` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/rust-2024/reserved-guarded-strings-via-macro.rs b/tests/ui/rust-2024/reserved-guarded-strings-via-macro.rs
new file mode 100644
index 0000000000000..f9e3c1e3c51b4
--- /dev/null
+++ b/tests/ui/rust-2024/reserved-guarded-strings-via-macro.rs
@@ -0,0 +1,12 @@
+//@ run-pass
+//@ compile-flags: -Zunstable-options
+//@ edition:2024
+//@ aux-build:reserved-guarded-strings-macro-2021.rs
+
+extern crate reserved_guarded_strings_macro_2021 as m2021;
+
+fn main() {
+ // Ok, even though *this* crate is 2024:
+ assert_eq!(m2021::number_of_tokens_in_a_guarded_string_literal!(), 3);
+ assert_eq!(m2021::number_of_tokens_in_a_guarded_unterminated_string_literal!(), 2);
+}
diff --git a/tests/ui/rust-2024/reserved-guarded-strings.rs b/tests/ui/rust-2024/reserved-guarded-strings.rs
new file mode 100644
index 0000000000000..dab97039be03f
--- /dev/null
+++ b/tests/ui/rust-2024/reserved-guarded-strings.rs
@@ -0,0 +1,74 @@
+//@ compile-flags: -Zunstable-options
+//@ edition:2024
+// ignore-tidy-linelength
+
+macro_rules! demo1 {
+ ( $a:tt ) => { println!("one tokens") };
+}
+
+macro_rules! demo2 {
+ ( $a:tt $b:tt ) => { println!("two tokens") };
+}
+
+macro_rules! demo3 {
+ ( $a:tt $b:tt $c:tt ) => { println!("three tokens") };
+}
+
+macro_rules! demo4 {
+ ( $a:tt $b:tt $c:tt $d:tt ) => { println!("four tokens") };
+}
+
+macro_rules! demo5 {
+ ( $a:tt $b:tt $c:tt $d:tt $e:tt ) => { println!("five tokens") };
+}
+
+macro_rules! demo6 {
+ ( $a:tt $b:tt $c:tt $d:tt $e:tt $f:tt ) => { println!("six tokens") };
+}
+
+macro_rules! demo7 {
+ ( $a:tt $b:tt $c:tt $d:tt $e:tt $f:tt $g:tt ) => { println!("seven tokens") };
+}
+
+macro_rules! demon {
+ ( $($n:tt)* ) => { println!("unknown number of tokens") };
+}
+
+fn main() {
+ demo1!("");
+ demo2!(# "");
+ demo3!(# ""#);
+ demo2!(# "foo");
+ demo3!(# "foo"#);
+ demo2!("foo"#);
+
+ demo2!(blah"xx"); //~ ERROR prefix `blah` is unknown
+ demo2!(blah#"xx"#);
+ //~^ ERROR prefix `blah` is unknown
+ //~| ERROR invalid string literal
+
+ demo2!(## "foo"); //~ ERROR invalid string literal
+ demo3!("foo"###); //~ ERROR invalid string literal
+ demo3!(### "foo"); //~ ERROR invalid string literal
+ demo3!(## "foo"#); //~ ERROR invalid string literal
+ demo5!(### "foo"###);
+ //~^ ERROR invalid string literal
+ //~| ERROR invalid string literal
+
+ demo1!(#""); //~ ERROR invalid string literal
+ demo1!(#""#); //~ ERROR invalid string literal
+ demo1!(####""); //~ ERROR invalid string literal
+ demo1!(#"foo"); //~ ERROR invalid string literal
+ demo1!(###"foo"); //~ ERROR invalid string literal
+ demo1!(#"foo"#); //~ ERROR invalid string literal
+ demo1!(###"foo"#); //~ ERROR invalid string literal
+ demo1!(###"foo"##); //~ ERROR invalid string literal
+ demo1!(###"foo"###); //~ ERROR invalid string literal
+ demo2!(#"foo"###);
+ //~^ ERROR invalid string literal
+ //~| ERROR invalid string literal
+
+ // More than 255 hashes
+ demon!(####################################################################################################################################################################################################################################################################"foo");
+ //~^ ERROR invalid string literal
+}
diff --git a/tests/ui/rust-2024/reserved-guarded-strings.stderr b/tests/ui/rust-2024/reserved-guarded-strings.stderr
new file mode 100644
index 0000000000000..f465ba7944a08
--- /dev/null
+++ b/tests/ui/rust-2024/reserved-guarded-strings.stderr
@@ -0,0 +1,254 @@
+error: prefix `blah` is unknown
+ --> $DIR/reserved-guarded-strings.rs:45:12
+ |
+LL | demo2!(blah"xx");
+ | ^^^^ unknown prefix
+ |
+ = note: prefixed identifiers and literals are reserved since Rust 2021
+help: consider inserting whitespace here
+ |
+LL | demo2!(blah "xx");
+ | +
+
+error: prefix `blah` is unknown
+ --> $DIR/reserved-guarded-strings.rs:46:12
+ |
+LL | demo2!(blah#"xx"#);
+ | ^^^^ unknown prefix
+ |
+ = note: prefixed identifiers and literals are reserved since Rust 2021
+help: consider inserting whitespace here
+ |
+LL | demo2!(blah #"xx"#);
+ | +
+
+error: invalid string literal
+ --> $DIR/reserved-guarded-strings.rs:46:16
+ |
+LL | demo2!(blah#"xx"#);
+ | ^^^^^^
+ |
+ = note: unprefixed guarded string literals are reserved for future use since Rust 2024
+help: consider inserting whitespace here
+ |
+LL | demo2!(blah# "xx"#);
+ | +
+
+error: invalid string literal
+ --> $DIR/reserved-guarded-strings.rs:50:12
+ |
+LL | demo2!(## "foo");
+ | ^^
+ |
+ = note: unprefixed guarded string literals are reserved for future use since Rust 2024
+help: consider inserting whitespace here
+ |
+LL | demo2!(# # "foo");
+ | +
+
+error: invalid string literal
+ --> $DIR/reserved-guarded-strings.rs:51:17
+ |
+LL | demo3!("foo"###);
+ | ^^
+ |
+ = note: unprefixed guarded string literals are reserved for future use since Rust 2024
+help: consider inserting whitespace here
+ |
+LL | demo3!("foo"# ##);
+ | +
+
+error: invalid string literal
+ --> $DIR/reserved-guarded-strings.rs:52:12
+ |
+LL | demo3!(### "foo");
+ | ^^
+ |
+ = note: unprefixed guarded string literals are reserved for future use since Rust 2024
+help: consider inserting whitespace here
+ |
+LL | demo3!(# ## "foo");
+ | +
+
+error: invalid string literal
+ --> $DIR/reserved-guarded-strings.rs:53:12
+ |
+LL | demo3!(## "foo"#);
+ | ^^
+ |
+ = note: unprefixed guarded string literals are reserved for future use since Rust 2024
+help: consider inserting whitespace here
+ |
+LL | demo3!(# # "foo"#);
+ | +
+
+error: invalid string literal
+ --> $DIR/reserved-guarded-strings.rs:54:12
+ |
+LL | demo5!(### "foo"###);
+ | ^^
+ |
+ = note: unprefixed guarded string literals are reserved for future use since Rust 2024
+help: consider inserting whitespace here
+ |
+LL | demo5!(# ## "foo"###);
+ | +
+
+error: invalid string literal
+ --> $DIR/reserved-guarded-strings.rs:54:21
+ |
+LL | demo5!(### "foo"###);
+ | ^^
+ |
+ = note: unprefixed guarded string literals are reserved for future use since Rust 2024
+help: consider inserting whitespace here
+ |
+LL | demo5!(### "foo"# ##);
+ | +
+
+error: invalid string literal
+ --> $DIR/reserved-guarded-strings.rs:58:12
+ |
+LL | demo1!(#"");
+ | ^^^
+ |
+ = note: unprefixed guarded string literals are reserved for future use since Rust 2024
+help: consider inserting whitespace here
+ |
+LL | demo1!(# "");
+ | +
+
+error: invalid string literal
+ --> $DIR/reserved-guarded-strings.rs:59:12
+ |
+LL | demo1!(#""#);
+ | ^^^^
+ |
+ = note: unprefixed guarded string literals are reserved for future use since Rust 2024
+help: consider inserting whitespace here
+ |
+LL | demo1!(# ""#);
+ | +
+
+error: invalid string literal
+ --> $DIR/reserved-guarded-strings.rs:60:12
+ |
+LL | demo1!(####"");
+ | ^^^^^^
+ |
+ = note: unprefixed guarded string literals are reserved for future use since Rust 2024
+help: consider inserting whitespace here
+ |
+LL | demo1!(# ###"");
+ | +
+
+error: invalid string literal
+ --> $DIR/reserved-guarded-strings.rs:61:12
+ |
+LL | demo1!(#"foo");
+ | ^^^^^^
+ |
+ = note: unprefixed guarded string literals are reserved for future use since Rust 2024
+help: consider inserting whitespace here
+ |
+LL | demo1!(# "foo");
+ | +
+
+error: invalid string literal
+ --> $DIR/reserved-guarded-strings.rs:62:12
+ |
+LL | demo1!(###"foo");
+ | ^^^^^^^^
+ |
+ = note: unprefixed guarded string literals are reserved for future use since Rust 2024
+help: consider inserting whitespace here
+ |
+LL | demo1!(# ##"foo");
+ | +
+
+error: invalid string literal
+ --> $DIR/reserved-guarded-strings.rs:63:12
+ |
+LL | demo1!(#"foo"#);
+ | ^^^^^^^
+ |
+ = note: unprefixed guarded string literals are reserved for future use since Rust 2024
+help: consider inserting whitespace here
+ |
+LL | demo1!(# "foo"#);
+ | +
+
+error: invalid string literal
+ --> $DIR/reserved-guarded-strings.rs:64:12
+ |
+LL | demo1!(###"foo"#);
+ | ^^^^^^^^^
+ |
+ = note: unprefixed guarded string literals are reserved for future use since Rust 2024
+help: consider inserting whitespace here
+ |
+LL | demo1!(# ##"foo"#);
+ | +
+
+error: invalid string literal
+ --> $DIR/reserved-guarded-strings.rs:65:12
+ |
+LL | demo1!(###"foo"##);
+ | ^^^^^^^^^^
+ |
+ = note: unprefixed guarded string literals are reserved for future use since Rust 2024
+help: consider inserting whitespace here
+ |
+LL | demo1!(# ##"foo"##);
+ | +
+
+error: invalid string literal
+ --> $DIR/reserved-guarded-strings.rs:66:12
+ |
+LL | demo1!(###"foo"###);
+ | ^^^^^^^^^^^
+ |
+ = note: unprefixed guarded string literals are reserved for future use since Rust 2024
+help: consider inserting whitespace here
+ |
+LL | demo1!(# ##"foo"###);
+ | +
+
+error: invalid string literal
+ --> $DIR/reserved-guarded-strings.rs:67:12
+ |
+LL | demo2!(#"foo"###);
+ | ^^^^^^^
+ |
+ = note: unprefixed guarded string literals are reserved for future use since Rust 2024
+help: consider inserting whitespace here
+ |
+LL | demo2!(# "foo"###);
+ | +
+
+error: invalid string literal
+ --> $DIR/reserved-guarded-strings.rs:67:19
+ |
+LL | demo2!(#"foo"###);
+ | ^^
+ |
+ = note: unprefixed guarded string literals are reserved for future use since Rust 2024
+help: consider inserting whitespace here
+ |
+LL | demo2!(#"foo"## #);
+ | +
+
+error: invalid string literal
+ --> $DIR/reserved-guarded-strings.rs:72:12
+ |
+LL | ...n!(####################################################################################################################################################################################################################################################################"foo...
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: unprefixed guarded string literals are reserved for future use since Rust 2024
+help: consider inserting whitespace here
+ |
+LL | demon!(# ###################################################################################################################################################################################################################################################################"foo");
+ | +
+
+error: aborting due to 21 previous errors
+