From 8dee9bc8fcaf74776d067f34745bc4d7411d80f7 Mon Sep 17 00:00:00 2001 From: lrh2000 Date: Sun, 16 May 2021 11:10:05 +0800 Subject: [PATCH 01/14] Reserve prefixed identifiers and string literals (RFC 3101) This commit denies any identifiers immediately followed by one of three tokens `"`, `'` or `#`, which is stricter than the requirements of RFC 3101 but may be necessary according to the discussion at [Zulip]. [Zulip]: https://rust-lang.zulipchat.com/#narrow/stream/268952-edition-2021/topic/reserved.20prefixes/near/238470099 --- compiler/rustc_lexer/src/lib.rs | 17 +++- compiler/rustc_parse/src/lexer/mod.rs | 32 ++++++- src/librustdoc/html/highlight.rs | 2 +- src/test/ui/rust-2021/reserved-prefixes.rs | 36 ++++++++ .../ui/rust-2021/reserved-prefixes.stderr | 92 +++++++++++++++++++ 5 files changed, 172 insertions(+), 7 deletions(-) create mode 100644 src/test/ui/rust-2021/reserved-prefixes.rs create mode 100644 src/test/ui/rust-2021/reserved-prefixes.stderr diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs index b9781581ff75d..5f3e245bf9973 100644 --- a/compiler/rustc_lexer/src/lib.rs +++ b/compiler/rustc_lexer/src/lib.rs @@ -66,6 +66,8 @@ pub enum TokenKind { Ident, /// "r#ident" RawIdent, + /// `foo#`, `foo'`, `foo"`. Note the tailer is not included. + BadPrefix, /// "12_u8", "1.0e-40", "b"123"". See `LiteralKind` for more details. Literal { kind: LiteralKind, suffix_start: usize }, /// "'a" @@ -323,7 +325,7 @@ impl Cursor<'_> { let kind = RawStr { n_hashes, err }; Literal { kind, suffix_start } } - _ => self.ident(), + _ => self.ident_or_bad_prefix(), }, // Byte literal, byte string literal, raw byte string literal or identifier. @@ -358,12 +360,12 @@ impl Cursor<'_> { let kind = RawByteStr { n_hashes, err }; Literal { kind, suffix_start } } - _ => self.ident(), + _ => self.ident_or_bad_prefix(), }, // Identifier (this should be checked after other variant that can // start as identifier). - c if is_id_start(c) => self.ident(), + c if is_id_start(c) => self.ident_or_bad_prefix(), // Numeric literal. c @ '0'..='9' => { @@ -487,11 +489,16 @@ impl Cursor<'_> { RawIdent } - fn ident(&mut self) -> TokenKind { + fn ident_or_bad_prefix(&mut self) -> TokenKind { debug_assert!(is_id_start(self.prev())); // Start is already eaten, eat the rest of identifier. self.eat_while(is_id_continue); - Ident + // Good prefixes must have been handled eariler. So if + // we see a prefix here, it is definitely a bad prefix. + match self.first() { + '#' | '"' | '\'' => BadPrefix, + _ => Ident, + } } fn number(&mut self, first_digit: char) -> LiteralKind { diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index 1c2f9a9645fe0..5710c386e3ba2 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -5,6 +5,7 @@ use rustc_errors::{error_code, Applicability, DiagnosticBuilder, FatalError, PRe use rustc_lexer::unescape::{self, Mode}; use rustc_lexer::{Base, DocStyle, RawStrError}; use rustc_session::parse::ParseSess; +use rustc_span::edition::Edition; use rustc_span::symbol::{sym, Symbol}; use rustc_span::{BytePos, Pos, Span}; @@ -166,12 +167,18 @@ impl<'a> StringReader<'a> { self.cook_doc_comment(content_start, content, CommentKind::Block, doc_style) } rustc_lexer::TokenKind::Whitespace => return None, - rustc_lexer::TokenKind::Ident | rustc_lexer::TokenKind::RawIdent => { + rustc_lexer::TokenKind::Ident + | rustc_lexer::TokenKind::RawIdent + | rustc_lexer::TokenKind::BadPrefix => { let is_raw_ident = token == rustc_lexer::TokenKind::RawIdent; + let is_bad_prefix = token == rustc_lexer::TokenKind::BadPrefix; let mut ident_start = start; if is_raw_ident { ident_start = ident_start + BytePos(2); } + if is_bad_prefix { + self.report_reserved_prefix(start); + } let sym = nfc_normalize(self.str_from(ident_start)); let span = self.mk_sp(start, self.pos); self.sess.symbol_gallery.insert(sym, span); @@ -491,6 +498,29 @@ impl<'a> StringReader<'a> { FatalError.raise() } + fn report_reserved_prefix(&self, start: BytePos) { + // See RFC 3101. + if self.sess.edition < Edition::Edition2021 { + return; + } + + let mut err = self.sess.span_diagnostic.struct_span_err( + self.mk_sp(start, self.pos), + &format!("prefix `{}` is unknown", self.str_from_to(start, self.pos)), + ); + err.span_label(self.mk_sp(start, self.pos), "unknown prefix"); + err.span_label( + self.mk_sp(self.pos, self.pos), + &format!( + "help: consider inserting a whitespace before this `{}`", + self.str_from_to(self.pos, self.pos + BytePos(1)), + ), + ); + err.note("prefixed identifiers and string literals are reserved since Rust 2021"); + + err.emit(); + } + /// Note: It was decided to not add a test case, because it would be too big. /// fn report_too_many_hashes(&self, start: BytePos, found: usize) -> ! { diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index 51392ca119189..36e4a240f14eb 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -413,7 +413,7 @@ impl<'a> Classifier<'a> { }, c => c, }, - TokenKind::RawIdent => Class::Ident, + TokenKind::RawIdent | TokenKind::BadPrefix => Class::Ident, TokenKind::Lifetime { .. } => Class::Lifetime, }; // Anything that didn't return above is the simple case where we the diff --git a/src/test/ui/rust-2021/reserved-prefixes.rs b/src/test/ui/rust-2021/reserved-prefixes.rs new file mode 100644 index 0000000000000..5882c7d83d8be --- /dev/null +++ b/src/test/ui/rust-2021/reserved-prefixes.rs @@ -0,0 +1,36 @@ +// compile-flags: -Z unstable-options --edition 2021 + +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") }; +} + +fn main() { + demo3!(foo#bar); //~ ERROR prefix `foo` is unknown + demo2!(foo"bar"); //~ ERROR prefix `foo` is unknown + demo2!(foo'b'); //~ ERROR prefix `foo` is unknown + + demo2!(foo'b); //~ ERROR prefix `foo` is unknown + demo3!(foo# bar); //~ ERROR prefix `foo` is unknown + demo4!(foo#! bar); //~ ERROR prefix `foo` is unknown + demo4!(foo## bar); //~ ERROR prefix `foo` is unknown + + demo4!(foo#bar#); + //~^ ERROR prefix `foo` is unknown + //~| ERROR prefix `bar` is unknown + + demo3!(foo # bar); + demo3!(foo #bar); + demo4!(foo!#bar); + demo4!(foo ##bar); + + demo3!(r"foo"#bar); + demo3!(r#foo#bar); +} diff --git a/src/test/ui/rust-2021/reserved-prefixes.stderr b/src/test/ui/rust-2021/reserved-prefixes.stderr new file mode 100644 index 0000000000000..ffaad31520224 --- /dev/null +++ b/src/test/ui/rust-2021/reserved-prefixes.stderr @@ -0,0 +1,92 @@ +error: prefix `foo` is unknown + --> $DIR/reserved-prefixes.rs:16:12 + | +LL | demo3!(foo#bar); + | ^^^- help: consider inserting a whitespace before this `#` + | | + | unknown prefix + | + = note: prefixed identifiers and string literals are reserved since Rust 2021 + +error: prefix `foo` is unknown + --> $DIR/reserved-prefixes.rs:17:12 + | +LL | demo2!(foo"bar"); + | ^^^- help: consider inserting a whitespace before this `"` + | | + | unknown prefix + | + = note: prefixed identifiers and string literals are reserved since Rust 2021 + +error: prefix `foo` is unknown + --> $DIR/reserved-prefixes.rs:18:12 + | +LL | demo2!(foo'b'); + | ^^^- help: consider inserting a whitespace before this `'` + | | + | unknown prefix + | + = note: prefixed identifiers and string literals are reserved since Rust 2021 + +error: prefix `foo` is unknown + --> $DIR/reserved-prefixes.rs:20:12 + | +LL | demo2!(foo'b); + | ^^^- help: consider inserting a whitespace before this `'` + | | + | unknown prefix + | + = note: prefixed identifiers and string literals are reserved since Rust 2021 + +error: prefix `foo` is unknown + --> $DIR/reserved-prefixes.rs:21:12 + | +LL | demo3!(foo# bar); + | ^^^- help: consider inserting a whitespace before this `#` + | | + | unknown prefix + | + = note: prefixed identifiers and string literals are reserved since Rust 2021 + +error: prefix `foo` is unknown + --> $DIR/reserved-prefixes.rs:22:12 + | +LL | demo4!(foo#! bar); + | ^^^- help: consider inserting a whitespace before this `#` + | | + | unknown prefix + | + = note: prefixed identifiers and string literals are reserved since Rust 2021 + +error: prefix `foo` is unknown + --> $DIR/reserved-prefixes.rs:23:12 + | +LL | demo4!(foo## bar); + | ^^^- help: consider inserting a whitespace before this `#` + | | + | unknown prefix + | + = note: prefixed identifiers and string literals are reserved since Rust 2021 + +error: prefix `foo` is unknown + --> $DIR/reserved-prefixes.rs:25:12 + | +LL | demo4!(foo#bar#); + | ^^^- help: consider inserting a whitespace before this `#` + | | + | unknown prefix + | + = note: prefixed identifiers and string literals are reserved since Rust 2021 + +error: prefix `bar` is unknown + --> $DIR/reserved-prefixes.rs:25:16 + | +LL | demo4!(foo#bar#); + | ^^^- help: consider inserting a whitespace before this `#` + | | + | unknown prefix + | + = note: prefixed identifiers and string literals are reserved since Rust 2021 + +error: aborting due to 9 previous errors + From c856e6fa531a0a84819578272ae01d3cabc2cd4d Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Mon, 14 Jun 2021 12:25:18 +0000 Subject: [PATCH 02/14] Add machine applicable suggestion to unknown prefix error. --- compiler/rustc_parse/src/lexer/mod.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index 5710c386e3ba2..5d794b1369938 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -509,12 +509,11 @@ impl<'a> StringReader<'a> { &format!("prefix `{}` is unknown", self.str_from_to(start, self.pos)), ); err.span_label(self.mk_sp(start, self.pos), "unknown prefix"); - err.span_label( + err.span_suggestion_verbose( self.mk_sp(self.pos, self.pos), - &format!( - "help: consider inserting a whitespace before this `{}`", - self.str_from_to(self.pos, self.pos + BytePos(1)), - ), + "consider inserting whitespace here", + " ".into(), + Applicability::MachineApplicable, ); err.note("prefixed identifiers and string literals are reserved since Rust 2021"); From ce43fc9404f7a205d882ea9146c3f568229b96b9 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Mon, 14 Jun 2021 12:25:59 +0000 Subject: [PATCH 03/14] Fix note in reserved prefix error. --- compiler/rustc_parse/src/lexer/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index 5d794b1369938..f5eba5056eab3 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -515,7 +515,7 @@ impl<'a> StringReader<'a> { " ".into(), Applicability::MachineApplicable, ); - err.note("prefixed identifiers and string literals are reserved since Rust 2021"); + err.note("prefixed identifiers and literals are reserved since Rust 2021"); err.emit(); } From 40fb2e97053e2655016688264ff19160741c1dbb Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Mon, 14 Jun 2021 13:03:55 +0000 Subject: [PATCH 04/14] Update reserved-prefixes test output. --- .../ui/rust-2021/reserved-prefixes.stderr | 90 +++++++++++-------- 1 file changed, 54 insertions(+), 36 deletions(-) diff --git a/src/test/ui/rust-2021/reserved-prefixes.stderr b/src/test/ui/rust-2021/reserved-prefixes.stderr index ffaad31520224..32e1856332925 100644 --- a/src/test/ui/rust-2021/reserved-prefixes.stderr +++ b/src/test/ui/rust-2021/reserved-prefixes.stderr @@ -2,91 +2,109 @@ error: prefix `foo` is unknown --> $DIR/reserved-prefixes.rs:16:12 | LL | demo3!(foo#bar); - | ^^^- help: consider inserting a whitespace before this `#` - | | - | unknown prefix + | ^^^ unknown prefix | - = note: prefixed identifiers and string literals are reserved since Rust 2021 + = note: prefixed identifiers and literals are reserved since Rust 2021 +help: consider inserting whitespace here + | +LL | demo3!(foo #bar); + | -- error: prefix `foo` is unknown --> $DIR/reserved-prefixes.rs:17:12 | LL | demo2!(foo"bar"); - | ^^^- help: consider inserting a whitespace before this `"` - | | - | unknown prefix + | ^^^ unknown prefix + | + = note: prefixed identifiers and literals are reserved since Rust 2021 +help: consider inserting whitespace here | - = note: prefixed identifiers and string literals are reserved since Rust 2021 +LL | demo2!(foo "bar"); + | -- error: prefix `foo` is unknown --> $DIR/reserved-prefixes.rs:18:12 | LL | demo2!(foo'b'); - | ^^^- help: consider inserting a whitespace before this `'` - | | - | unknown prefix + | ^^^ unknown prefix + | + = note: prefixed identifiers and literals are reserved since Rust 2021 +help: consider inserting whitespace here | - = note: prefixed identifiers and string literals are reserved since Rust 2021 +LL | demo2!(foo 'b'); + | -- error: prefix `foo` is unknown --> $DIR/reserved-prefixes.rs:20:12 | LL | demo2!(foo'b); - | ^^^- help: consider inserting a whitespace before this `'` - | | - | unknown prefix + | ^^^ unknown prefix | - = note: prefixed identifiers and string literals are reserved since Rust 2021 + = note: prefixed identifiers and literals are reserved since Rust 2021 +help: consider inserting whitespace here + | +LL | demo2!(foo 'b); + | -- error: prefix `foo` is unknown --> $DIR/reserved-prefixes.rs:21:12 | LL | demo3!(foo# bar); - | ^^^- help: consider inserting a whitespace before this `#` - | | - | unknown prefix + | ^^^ unknown prefix + | + = note: prefixed identifiers and literals are reserved since Rust 2021 +help: consider inserting whitespace here | - = note: prefixed identifiers and string literals are reserved since Rust 2021 +LL | demo3!(foo # bar); + | -- error: prefix `foo` is unknown --> $DIR/reserved-prefixes.rs:22:12 | LL | demo4!(foo#! bar); - | ^^^- help: consider inserting a whitespace before this `#` - | | - | unknown prefix + | ^^^ unknown prefix | - = note: prefixed identifiers and string literals are reserved since Rust 2021 + = note: prefixed identifiers and literals are reserved since Rust 2021 +help: consider inserting whitespace here + | +LL | demo4!(foo #! bar); + | -- error: prefix `foo` is unknown --> $DIR/reserved-prefixes.rs:23:12 | LL | demo4!(foo## bar); - | ^^^- help: consider inserting a whitespace before this `#` - | | - | unknown prefix + | ^^^ unknown prefix + | + = note: prefixed identifiers and literals are reserved since Rust 2021 +help: consider inserting whitespace here | - = note: prefixed identifiers and string literals are reserved since Rust 2021 +LL | demo4!(foo ## bar); + | -- error: prefix `foo` is unknown --> $DIR/reserved-prefixes.rs:25:12 | LL | demo4!(foo#bar#); - | ^^^- help: consider inserting a whitespace before this `#` - | | - | unknown prefix + | ^^^ unknown prefix | - = note: prefixed identifiers and string literals are reserved since Rust 2021 + = note: prefixed identifiers and literals are reserved since Rust 2021 +help: consider inserting whitespace here + | +LL | demo4!(foo #bar#); + | -- error: prefix `bar` is unknown --> $DIR/reserved-prefixes.rs:25:16 | LL | demo4!(foo#bar#); - | ^^^- help: consider inserting a whitespace before this `#` - | | - | unknown prefix + | ^^^ unknown prefix + | + = note: prefixed identifiers and literals are reserved since Rust 2021 +help: consider inserting whitespace here | - = note: prefixed identifiers and string literals are reserved since Rust 2021 +LL | demo4!(foo#bar #); + | -- error: aborting due to 9 previous errors From d837c00d1008c2ab13bf80117b81f5e482fc9edb Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Mon, 14 Jun 2021 12:56:49 +0000 Subject: [PATCH 05/14] Add migration lint for reserved prefixes. --- compiler/rustc_lint/src/context.rs | 9 ++++++ compiler/rustc_lint_defs/src/builtin.rs | 37 +++++++++++++++++++++++++ compiler/rustc_lint_defs/src/lib.rs | 1 + compiler/rustc_parse/src/lexer/mod.rs | 23 ++++++++++----- 4 files changed, 63 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 2dc04d57d1e66..933f7e47c3e9d 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -723,6 +723,15 @@ pub trait LintContext: Sized { BuiltinLintDiagnostics::OrPatternsBackCompat(span,suggestion) => { db.span_suggestion(span, "use pat_param to preserve semantics", suggestion, Applicability::MachineApplicable); } + BuiltinLintDiagnostics::ReservedPrefix(span) => { + db.span_label(span, "unknown prefix"); + db.span_suggestion_verbose( + span.shrink_to_hi(), + "insert whitespace here to avoid this being parsed as a prefix in Rust 2021", + " ".into(), + Applicability::MachineApplicable, + ); + } } // Rewrap `db`, and pass control to the user. decorate(LintDiagnosticBuilder::new(db)); diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 53970b485eecd..ba8a8c3d8c993 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -2973,6 +2973,7 @@ declare_lint_pass! { OR_PATTERNS_BACK_COMPAT, LARGE_ASSIGNMENTS, FUTURE_PRELUDE_COLLISION, + RESERVED_PREFIX, ] } @@ -3263,3 +3264,39 @@ declare_lint! { reason: FutureIncompatibilityReason::EditionError(Edition::Edition2021), }; } + +declare_lint! { + /// The `reserved_prefix` lint detects identifiers that will be parsed as a + /// prefix instead in Rust 2021. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(reserved_prefix)] + /// + /// macro_rules! m { + /// (z $x:expr) => (); + /// } + /// + /// m!(z"hey"); + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// In Rust 2015 and 2018, `z"hey"` is two tokens: the identifier `z` + /// followed by the string literal `"hey"`. In Rust 2021, the `z` is + /// considered a prefix for `"hey"`. + /// + /// This lint suggests to add whitespace between the `z` and `"hey"` tokens + /// to keep them separated in Rust 2021. + pub RESERVED_PREFIX, + Allow, + "identifiers that will be parsed as a prefix in Rust 2021", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #84978 ", + edition: Some(Edition::Edition2021), + }; + crate_level_only +} diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index b3d98747dcfa2..3372bc716d28c 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -300,6 +300,7 @@ pub enum BuiltinLintDiagnostics { ExternDepSpec(String, ExternDepSpec), ProcMacroBackCompat(String), OrPatternsBackCompat(Span, String), + ReservedPrefix(Span), } /// Lints that are buffered up early on in the `Session` before the diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index f5eba5056eab3..f50e8a8db0193 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -1,9 +1,11 @@ -use rustc_ast::ast::AttrStyle; +use rustc_ast::ast::{self, AttrStyle}; use rustc_ast::token::{self, CommentKind, Token, TokenKind}; use rustc_ast::tokenstream::{Spacing, TokenStream}; use rustc_errors::{error_code, Applicability, DiagnosticBuilder, FatalError, PResult}; use rustc_lexer::unescape::{self, Mode}; use rustc_lexer::{Base, DocStyle, RawStrError}; +use rustc_session::lint::builtin::RESERVED_PREFIX; +use rustc_session::lint::BuiltinLintDiagnostics; use rustc_session::parse::ParseSess; use rustc_span::edition::Edition; use rustc_span::symbol::{sym, Symbol}; @@ -498,17 +500,24 @@ impl<'a> StringReader<'a> { FatalError.raise() } + // See RFC 3101. fn report_reserved_prefix(&self, start: BytePos) { - // See RFC 3101. + let prefix_span = self.mk_sp(start, self.pos); + let msg = format!("prefix `{}` is unknown", self.str_from_to(start, self.pos)); + if self.sess.edition < Edition::Edition2021 { + self.sess.buffer_lint_with_diagnostic( + &RESERVED_PREFIX, + prefix_span, + ast::CRATE_NODE_ID, + &msg, + BuiltinLintDiagnostics::ReservedPrefix(prefix_span), + ); return; } - let mut err = self.sess.span_diagnostic.struct_span_err( - self.mk_sp(start, self.pos), - &format!("prefix `{}` is unknown", self.str_from_to(start, self.pos)), - ); - err.span_label(self.mk_sp(start, self.pos), "unknown prefix"); + let mut err = self.sess.span_diagnostic.struct_span_err(prefix_span, &msg); + err.span_label(prefix_span, "unknown prefix"); err.span_suggestion_verbose( self.mk_sp(self.pos, self.pos), "consider inserting whitespace here", From 3b18e215a3517bf32cc598b6e14743b14e4a928e Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Mon, 14 Jun 2021 12:57:26 +0000 Subject: [PATCH 06/14] Add test for the reserved_prefix migration lint. --- .../reserved-prefixes-migration.fixed | 28 +++++++++ .../rust-2021/reserved-prefixes-migration.rs | 28 +++++++++ .../reserved-prefixes-migration.stderr | 59 +++++++++++++++++++ 3 files changed, 115 insertions(+) create mode 100644 src/test/ui/rust-2021/reserved-prefixes-migration.fixed create mode 100644 src/test/ui/rust-2021/reserved-prefixes-migration.rs create mode 100644 src/test/ui/rust-2021/reserved-prefixes-migration.stderr diff --git a/src/test/ui/rust-2021/reserved-prefixes-migration.fixed b/src/test/ui/rust-2021/reserved-prefixes-migration.fixed new file mode 100644 index 0000000000000..88e7584c197f0 --- /dev/null +++ b/src/test/ui/rust-2021/reserved-prefixes-migration.fixed @@ -0,0 +1,28 @@ +// check-pass +// run-rustfix +// compile-flags: -Z unstable-options --edition 2018 + +#![warn(reserved_prefix)] + +macro_rules! m2 { + ($a:tt $b:tt) => {}; +} + +macro_rules! m3 { + ($a:tt $b:tt $c:tt) => {}; +} + +fn main() { + m2!(z "hey"); + //~^ WARNING prefix `z` is unknown [reserved_prefix] + //~| WARNING become a hard error + m2!(prefix "hey"); + //~^ WARNING prefix `prefix` is unknown [reserved_prefix] + //~| WARNING become a hard error + m3!(hey #123); + //~^ WARNING prefix `hey` is unknown [reserved_prefix] + //~| WARNING become a hard error + m3!(hey #hey); + //~^ WARNING prefix `hey` is unknown [reserved_prefix] + //~| WARNING become a hard error +} diff --git a/src/test/ui/rust-2021/reserved-prefixes-migration.rs b/src/test/ui/rust-2021/reserved-prefixes-migration.rs new file mode 100644 index 0000000000000..ee835eb97a295 --- /dev/null +++ b/src/test/ui/rust-2021/reserved-prefixes-migration.rs @@ -0,0 +1,28 @@ +// check-pass +// run-rustfix +// compile-flags: -Z unstable-options --edition 2018 + +#![warn(reserved_prefix)] + +macro_rules! m2 { + ($a:tt $b:tt) => {}; +} + +macro_rules! m3 { + ($a:tt $b:tt $c:tt) => {}; +} + +fn main() { + m2!(z"hey"); + //~^ WARNING prefix `z` is unknown [reserved_prefix] + //~| WARNING become a hard error + m2!(prefix"hey"); + //~^ WARNING prefix `prefix` is unknown [reserved_prefix] + //~| WARNING become a hard error + m3!(hey#123); + //~^ WARNING prefix `hey` is unknown [reserved_prefix] + //~| WARNING become a hard error + m3!(hey#hey); + //~^ WARNING prefix `hey` is unknown [reserved_prefix] + //~| WARNING become a hard error +} diff --git a/src/test/ui/rust-2021/reserved-prefixes-migration.stderr b/src/test/ui/rust-2021/reserved-prefixes-migration.stderr new file mode 100644 index 0000000000000..2c9d94803bec2 --- /dev/null +++ b/src/test/ui/rust-2021/reserved-prefixes-migration.stderr @@ -0,0 +1,59 @@ +warning: prefix `z` is unknown + --> $DIR/reserved-prefixes-migration.rs:16:9 + | +LL | m2!(z"hey"); + | ^ unknown prefix + | +note: the lint level is defined here + --> $DIR/reserved-prefixes-migration.rs:5:9 + | +LL | #![warn(reserved_prefix)] + | ^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition! + = note: for more information, see issue #84978 +help: insert whitespace here to avoid this being parsed as a prefix in Rust 2021 + | +LL | m2!(z "hey"); + | -- + +warning: prefix `prefix` is unknown + --> $DIR/reserved-prefixes-migration.rs:19:9 + | +LL | m2!(prefix"hey"); + | ^^^^^^ unknown prefix + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition! + = note: for more information, see issue #84978 +help: insert whitespace here to avoid this being parsed as a prefix in Rust 2021 + | +LL | m2!(prefix "hey"); + | -- + +warning: prefix `hey` is unknown + --> $DIR/reserved-prefixes-migration.rs:22:9 + | +LL | m3!(hey#123); + | ^^^ unknown prefix + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition! + = note: for more information, see issue #84978 +help: insert whitespace here to avoid this being parsed as a prefix in Rust 2021 + | +LL | m3!(hey #123); + | -- + +warning: prefix `hey` is unknown + --> $DIR/reserved-prefixes-migration.rs:25:9 + | +LL | m3!(hey#hey); + | ^^^ unknown prefix + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition! + = note: for more information, see issue #84978 +help: insert whitespace here to avoid this being parsed as a prefix in Rust 2021 + | +LL | m3!(hey #hey); + | -- + +warning: 4 warnings emitted + From 6adce70a58808426753fa8e74068dcb959c004a6 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Mon, 14 Jun 2021 16:46:46 +0000 Subject: [PATCH 07/14] Improve comments for reserved prefixes. Co-authored-by: Niko Matsakis --- compiler/rustc_lexer/src/lib.rs | 9 +++++++-- compiler/rustc_parse/src/lexer/mod.rs | 5 ++++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs index 5f3e245bf9973..4a8f34e2815c4 100644 --- a/compiler/rustc_lexer/src/lib.rs +++ b/compiler/rustc_lexer/src/lib.rs @@ -66,7 +66,12 @@ pub enum TokenKind { Ident, /// "r#ident" RawIdent, - /// `foo#`, `foo'`, `foo"`. Note the tailer is not included. + /// An unknown prefix like `foo#`, `foo'`, `foo"`. Note that only the + /// prefix (`foo`) is included in the token, not the separator (which is + /// lexed as its own distinct token). In Rust 2021 and later, reserved + /// prefixes are reported as errors; in earlier editions, they result in a + /// (allowed by default) lint, and are treated as regular identifier + /// tokens. BadPrefix, /// "12_u8", "1.0e-40", "b"123"". See `LiteralKind` for more details. Literal { kind: LiteralKind, suffix_start: usize }, @@ -493,7 +498,7 @@ impl Cursor<'_> { debug_assert!(is_id_start(self.prev())); // Start is already eaten, eat the rest of identifier. self.eat_while(is_id_continue); - // Good prefixes must have been handled eariler. So if + // Good prefixes must have been handled earlier. So if // we see a prefix here, it is definitely a bad prefix. match self.first() { '#' | '"' | '\'' => BadPrefix, diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index f50e8a8db0193..b694217b58a95 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -500,7 +500,10 @@ impl<'a> StringReader<'a> { FatalError.raise() } - // See RFC 3101. + // RFC 3101 introduced the idea of (reserved) prefixes. As of Rust 2021, + // using a (unknown) prefix is an error. In earlier editions, however, they + // only result in a (allowed by default) lint, and are treated as regular + // identifier tokens. fn report_reserved_prefix(&self, start: BytePos) { let prefix_span = self.mk_sp(start, self.pos); let msg = format!("prefix `{}` is unknown", self.str_from_to(start, self.pos)); From d40be0fc6418affeeb765a9b6a99315e90aa57c8 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Mon, 14 Jun 2021 16:48:07 +0000 Subject: [PATCH 08/14] Check the span's edition for the reserved prefixes. --- compiler/rustc_parse/src/lexer/mod.rs | 31 ++++++++++++++------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index b694217b58a95..21a6ace7cf48f 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -7,7 +7,6 @@ use rustc_lexer::{Base, DocStyle, RawStrError}; use rustc_session::lint::builtin::RESERVED_PREFIX; use rustc_session::lint::BuiltinLintDiagnostics; use rustc_session::parse::ParseSess; -use rustc_span::edition::Edition; use rustc_span::symbol::{sym, Symbol}; use rustc_span::{BytePos, Pos, Span}; @@ -508,7 +507,22 @@ impl<'a> StringReader<'a> { let prefix_span = self.mk_sp(start, self.pos); let msg = format!("prefix `{}` is unknown", self.str_from_to(start, self.pos)); - if self.sess.edition < Edition::Edition2021 { + if prefix_span.rust_2021() { + // In Rust 2021, this is a hard error. + self.sess + .span_diagnostic + .struct_span_err(prefix_span, &msg) + .span_label(prefix_span, "unknown prefix") + .span_suggestion_verbose( + self.mk_sp(self.pos, self.pos), + "consider inserting whitespace here", + " ".into(), + Applicability::MachineApplicable, + ) + .note("prefixed identifiers and literals are reserved since Rust 2021") + .emit(); + } else { + // Before Rust 2021, only emit a lint for migration. self.sess.buffer_lint_with_diagnostic( &RESERVED_PREFIX, prefix_span, @@ -516,20 +530,7 @@ impl<'a> StringReader<'a> { &msg, BuiltinLintDiagnostics::ReservedPrefix(prefix_span), ); - return; } - - let mut err = self.sess.span_diagnostic.struct_span_err(prefix_span, &msg); - err.span_label(prefix_span, "unknown prefix"); - err.span_suggestion_verbose( - self.mk_sp(self.pos, self.pos), - "consider inserting whitespace here", - " ".into(), - Applicability::MachineApplicable, - ); - err.note("prefixed identifiers and literals are reserved since Rust 2021"); - - err.emit(); } /// Note: It was decided to not add a test case, because it would be too big. From 0eeeebc990719b666a5cf4e3e488c79751596f87 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Mon, 14 Jun 2021 16:50:20 +0000 Subject: [PATCH 09/14] Rename 'bad prefix' to 'unknown prefix'. --- compiler/rustc_lexer/src/lib.rs | 16 ++++++++-------- compiler/rustc_parse/src/lexer/mod.rs | 10 +++++----- src/librustdoc/html/highlight.rs | 2 +- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs index 4a8f34e2815c4..4cb2a6ca50f8d 100644 --- a/compiler/rustc_lexer/src/lib.rs +++ b/compiler/rustc_lexer/src/lib.rs @@ -72,7 +72,7 @@ pub enum TokenKind { /// prefixes are reported as errors; in earlier editions, they result in a /// (allowed by default) lint, and are treated as regular identifier /// tokens. - BadPrefix, + UnknownPrefix, /// "12_u8", "1.0e-40", "b"123"". See `LiteralKind` for more details. Literal { kind: LiteralKind, suffix_start: usize }, /// "'a" @@ -330,7 +330,7 @@ impl Cursor<'_> { let kind = RawStr { n_hashes, err }; Literal { kind, suffix_start } } - _ => self.ident_or_bad_prefix(), + _ => self.ident_or_unknown_prefix(), }, // Byte literal, byte string literal, raw byte string literal or identifier. @@ -365,12 +365,12 @@ impl Cursor<'_> { let kind = RawByteStr { n_hashes, err }; Literal { kind, suffix_start } } - _ => self.ident_or_bad_prefix(), + _ => self.ident_or_unknown_prefix(), }, // Identifier (this should be checked after other variant that can // start as identifier). - c if is_id_start(c) => self.ident_or_bad_prefix(), + c if is_id_start(c) => self.ident_or_unknown_prefix(), // Numeric literal. c @ '0'..='9' => { @@ -494,14 +494,14 @@ impl Cursor<'_> { RawIdent } - fn ident_or_bad_prefix(&mut self) -> TokenKind { + fn ident_or_unknown_prefix(&mut self) -> TokenKind { debug_assert!(is_id_start(self.prev())); // Start is already eaten, eat the rest of identifier. self.eat_while(is_id_continue); - // Good prefixes must have been handled earlier. So if - // we see a prefix here, it is definitely a bad prefix. + // Known prefixes must have been handled earlier. So if + // we see a prefix here, it is definitely a unknown prefix. match self.first() { - '#' | '"' | '\'' => BadPrefix, + '#' | '"' | '\'' => UnknownPrefix, _ => Ident, } } diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index 21a6ace7cf48f..0f6b9a2f122d8 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -170,15 +170,15 @@ impl<'a> StringReader<'a> { rustc_lexer::TokenKind::Whitespace => return None, rustc_lexer::TokenKind::Ident | rustc_lexer::TokenKind::RawIdent - | rustc_lexer::TokenKind::BadPrefix => { + | rustc_lexer::TokenKind::UnknownPrefix => { let is_raw_ident = token == rustc_lexer::TokenKind::RawIdent; - let is_bad_prefix = token == rustc_lexer::TokenKind::BadPrefix; + let is_unknown_prefix = token == rustc_lexer::TokenKind::UnknownPrefix; let mut ident_start = start; if is_raw_ident { ident_start = ident_start + BytePos(2); } - if is_bad_prefix { - self.report_reserved_prefix(start); + if is_unknown_prefix { + self.report_unknown_prefix(start); } let sym = nfc_normalize(self.str_from(ident_start)); let span = self.mk_sp(start, self.pos); @@ -503,7 +503,7 @@ impl<'a> StringReader<'a> { // using a (unknown) prefix is an error. In earlier editions, however, they // only result in a (allowed by default) lint, and are treated as regular // identifier tokens. - fn report_reserved_prefix(&self, start: BytePos) { + fn report_unknown_prefix(&self, start: BytePos) { let prefix_span = self.mk_sp(start, self.pos); let msg = format!("prefix `{}` is unknown", self.str_from_to(start, self.pos)); diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index 36e4a240f14eb..33b1d98313ce3 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -413,7 +413,7 @@ impl<'a> Classifier<'a> { }, c => c, }, - TokenKind::RawIdent | TokenKind::BadPrefix => Class::Ident, + TokenKind::RawIdent | TokenKind::UnknownPrefix => Class::Ident, TokenKind::Lifetime { .. } => Class::Lifetime, }; // Anything that didn't return above is the simple case where we the From c7f7c2efe02170850428e435b5a616f0bbc4ac37 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Mon, 14 Jun 2021 17:07:40 +0000 Subject: [PATCH 10/14] Add quote!() example to reserved_prefix lint test. --- .../rust-2021/reserved-prefixes-migration.fixed | 10 ++++++++++ .../ui/rust-2021/reserved-prefixes-migration.rs | 10 ++++++++++ .../rust-2021/reserved-prefixes-migration.stderr | 15 ++++++++++++++- 3 files changed, 34 insertions(+), 1 deletion(-) diff --git a/src/test/ui/rust-2021/reserved-prefixes-migration.fixed b/src/test/ui/rust-2021/reserved-prefixes-migration.fixed index 88e7584c197f0..5537822e8fd75 100644 --- a/src/test/ui/rust-2021/reserved-prefixes-migration.fixed +++ b/src/test/ui/rust-2021/reserved-prefixes-migration.fixed @@ -26,3 +26,13 @@ fn main() { //~^ WARNING prefix `hey` is unknown [reserved_prefix] //~| WARNING become a hard error } + +macro_rules! quote { + (# name = # kind # value) => {}; +} + +quote! { + #name = #kind #value + //~^ WARNING prefix `kind` is unknown [reserved_prefix] + //~| WARNING become a hard error +} diff --git a/src/test/ui/rust-2021/reserved-prefixes-migration.rs b/src/test/ui/rust-2021/reserved-prefixes-migration.rs index ee835eb97a295..5fff0f234f864 100644 --- a/src/test/ui/rust-2021/reserved-prefixes-migration.rs +++ b/src/test/ui/rust-2021/reserved-prefixes-migration.rs @@ -26,3 +26,13 @@ fn main() { //~^ WARNING prefix `hey` is unknown [reserved_prefix] //~| WARNING become a hard error } + +macro_rules! quote { + (# name = # kind # value) => {}; +} + +quote! { + #name = #kind#value + //~^ WARNING prefix `kind` is unknown [reserved_prefix] + //~| WARNING become a hard error +} diff --git a/src/test/ui/rust-2021/reserved-prefixes-migration.stderr b/src/test/ui/rust-2021/reserved-prefixes-migration.stderr index 2c9d94803bec2..0c38dbd76c223 100644 --- a/src/test/ui/rust-2021/reserved-prefixes-migration.stderr +++ b/src/test/ui/rust-2021/reserved-prefixes-migration.stderr @@ -55,5 +55,18 @@ help: insert whitespace here to avoid this being parsed as a prefix in Rust 2021 LL | m3!(hey #hey); | -- -warning: 4 warnings emitted +warning: prefix `kind` is unknown + --> $DIR/reserved-prefixes-migration.rs:35:14 + | +LL | #name = #kind#value + | ^^^^ unknown prefix + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition! + = note: for more information, see issue #84978 +help: insert whitespace here to avoid this being parsed as a prefix in Rust 2021 + | +LL | #name = #kind #value + | -- + +warning: 5 warnings emitted From 7490305e13bd90b4c4697d465ceea8df2625a7ad Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Mon, 14 Jun 2021 20:38:57 +0000 Subject: [PATCH 11/14] No reserved_prefix suggestion in proc macro call_site. --- compiler/rustc_parse/src/lexer/mod.rs | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index 0f6b9a2f122d8..87e60a48e4457 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -8,7 +8,7 @@ use rustc_session::lint::builtin::RESERVED_PREFIX; use rustc_session::lint::BuiltinLintDiagnostics; use rustc_session::parse::ParseSess; use rustc_span::symbol::{sym, Symbol}; -use rustc_span::{BytePos, Pos, Span}; +use rustc_span::{edition::Edition, BytePos, Pos, Span}; use tracing::debug; @@ -507,20 +507,22 @@ impl<'a> StringReader<'a> { let prefix_span = self.mk_sp(start, self.pos); let msg = format!("prefix `{}` is unknown", self.str_from_to(start, self.pos)); - if prefix_span.rust_2021() { + let expn_data = prefix_span.ctxt().outer_expn_data(); + + if expn_data.edition >= Edition::Edition2021 { // In Rust 2021, this is a hard error. - self.sess - .span_diagnostic - .struct_span_err(prefix_span, &msg) - .span_label(prefix_span, "unknown prefix") - .span_suggestion_verbose( - self.mk_sp(self.pos, self.pos), + let mut err = self.sess.span_diagnostic.struct_span_err(prefix_span, &msg); + err.span_label(prefix_span, "unknown prefix"); + if expn_data.is_root() { + err.span_suggestion_verbose( + prefix_span.shrink_to_hi(), "consider inserting whitespace here", " ".into(), Applicability::MachineApplicable, - ) - .note("prefixed identifiers and literals are reserved since Rust 2021") - .emit(); + ); + } + err.note("prefixed identifiers and literals are reserved since Rust 2021"); + err.emit(); } else { // Before Rust 2021, only emit a lint for migration. self.sess.buffer_lint_with_diagnostic( From 2bcd66310062b54b07216008f9e10bc063f9ad5e Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Mon, 14 Jun 2021 20:39:04 +0000 Subject: [PATCH 12/14] Add reserved_prefixe tests for macros from different editions. --- .../auxiliary/reserved-prefixes-macro-2018.rs | 25 ++++++++++++++++ .../auxiliary/reserved-prefixes-macro-2021.rs | 25 ++++++++++++++++ .../reserved-prefixes-via-macro-2.rs | 21 ++++++++++++++ .../reserved-prefixes-via-macro-2.stderr | 29 +++++++++++++++++++ .../rust-2021/reserved-prefixes-via-macro.rs | 12 ++++++++ 5 files changed, 112 insertions(+) create mode 100644 src/test/ui/rust-2021/auxiliary/reserved-prefixes-macro-2018.rs create mode 100644 src/test/ui/rust-2021/auxiliary/reserved-prefixes-macro-2021.rs create mode 100644 src/test/ui/rust-2021/reserved-prefixes-via-macro-2.rs create mode 100644 src/test/ui/rust-2021/reserved-prefixes-via-macro-2.stderr create mode 100644 src/test/ui/rust-2021/reserved-prefixes-via-macro.rs diff --git a/src/test/ui/rust-2021/auxiliary/reserved-prefixes-macro-2018.rs b/src/test/ui/rust-2021/auxiliary/reserved-prefixes-macro-2018.rs new file mode 100644 index 0000000000000..eb301e5e1be32 --- /dev/null +++ b/src/test/ui/rust-2021/auxiliary/reserved-prefixes-macro-2018.rs @@ -0,0 +1,25 @@ +// force-host +// edition:2018 +// 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_prefixed_integer_literal(_: TokenStream) -> TokenStream { + TokenStream::from_str("hey#123").unwrap().into_iter().count().to_string().parse().unwrap() +} + +#[proc_macro] +pub fn number_of_tokens_in_a_prefixed_char_literal(_: TokenStream) -> TokenStream { + TokenStream::from_str("hey#'a'").unwrap().into_iter().count().to_string().parse().unwrap() +} + +#[proc_macro] +pub fn number_of_tokens_in_a_prefixed_string_literal(_: TokenStream) -> TokenStream { + TokenStream::from_str("hey#\"abc\"").unwrap().into_iter().count().to_string().parse().unwrap() +} diff --git a/src/test/ui/rust-2021/auxiliary/reserved-prefixes-macro-2021.rs b/src/test/ui/rust-2021/auxiliary/reserved-prefixes-macro-2021.rs new file mode 100644 index 0000000000000..691bfdc15c3ad --- /dev/null +++ b/src/test/ui/rust-2021/auxiliary/reserved-prefixes-macro-2021.rs @@ -0,0 +1,25 @@ +// 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_prefixed_integer_literal(_: TokenStream) -> TokenStream { + TokenStream::from_str("hey#123").unwrap().into_iter().count().to_string().parse().unwrap() +} + +#[proc_macro] +pub fn number_of_tokens_in_a_prefixed_char_literal(_: TokenStream) -> TokenStream { + TokenStream::from_str("hey#'a'").unwrap().into_iter().count().to_string().parse().unwrap() +} + +#[proc_macro] +pub fn number_of_tokens_in_a_prefixed_string_literal(_: TokenStream) -> TokenStream { + TokenStream::from_str("hey#\"abc\"").unwrap().into_iter().count().to_string().parse().unwrap() +} diff --git a/src/test/ui/rust-2021/reserved-prefixes-via-macro-2.rs b/src/test/ui/rust-2021/reserved-prefixes-via-macro-2.rs new file mode 100644 index 0000000000000..74f20660613ad --- /dev/null +++ b/src/test/ui/rust-2021/reserved-prefixes-via-macro-2.rs @@ -0,0 +1,21 @@ +// edition:2018 +// aux-build:reserved-prefixes-macro-2018.rs +// aux-build:reserved-prefixes-macro-2021.rs + +extern crate reserved_prefixes_macro_2018 as m2018; +extern crate reserved_prefixes_macro_2021 as m2021; + +fn main() { + // Ok: + m2018::number_of_tokens_in_a_prefixed_integer_literal!(); + m2018::number_of_tokens_in_a_prefixed_char_literal!(); + m2018::number_of_tokens_in_a_prefixed_string_literal!(); + + // Error, even though *this* crate is 2018: + m2021::number_of_tokens_in_a_prefixed_integer_literal!(); + //~^ ERROR prefix `hey` is unknown + m2021::number_of_tokens_in_a_prefixed_char_literal!(); + //~^ ERROR prefix `hey` is unknown + m2021::number_of_tokens_in_a_prefixed_string_literal!(); + //~^ ERROR prefix `hey` is unknown +} diff --git a/src/test/ui/rust-2021/reserved-prefixes-via-macro-2.stderr b/src/test/ui/rust-2021/reserved-prefixes-via-macro-2.stderr new file mode 100644 index 0000000000000..9d7ca570c4cc3 --- /dev/null +++ b/src/test/ui/rust-2021/reserved-prefixes-via-macro-2.stderr @@ -0,0 +1,29 @@ +error: prefix `hey` is unknown + --> $DIR/reserved-prefixes-via-macro-2.rs:15:5 + | +LL | m2021::number_of_tokens_in_a_prefixed_integer_literal!(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unknown prefix + | + = note: prefixed identifiers and literals are reserved since Rust 2021 + = note: this error originates in the macro `m2021::number_of_tokens_in_a_prefixed_integer_literal` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: prefix `hey` is unknown + --> $DIR/reserved-prefixes-via-macro-2.rs:17:5 + | +LL | m2021::number_of_tokens_in_a_prefixed_char_literal!(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unknown prefix + | + = note: prefixed identifiers and literals are reserved since Rust 2021 + = note: this error originates in the macro `m2021::number_of_tokens_in_a_prefixed_char_literal` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: prefix `hey` is unknown + --> $DIR/reserved-prefixes-via-macro-2.rs:19:5 + | +LL | m2021::number_of_tokens_in_a_prefixed_string_literal!(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unknown prefix + | + = note: prefixed identifiers and literals are reserved since Rust 2021 + = note: this error originates in the macro `m2021::number_of_tokens_in_a_prefixed_string_literal` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/rust-2021/reserved-prefixes-via-macro.rs b/src/test/ui/rust-2021/reserved-prefixes-via-macro.rs new file mode 100644 index 0000000000000..110b6d64ccc68 --- /dev/null +++ b/src/test/ui/rust-2021/reserved-prefixes-via-macro.rs @@ -0,0 +1,12 @@ +// run-pass +// edition:2021 +// aux-build:reserved-prefixes-macro-2018.rs + +extern crate reserved_prefixes_macro_2018 as m2018; + +fn main() { + // Ok, even though *this* crate is 2021: + assert_eq!(m2018::number_of_tokens_in_a_prefixed_integer_literal!(), 3); + assert_eq!(m2018::number_of_tokens_in_a_prefixed_char_literal!(), 3); + assert_eq!(m2018::number_of_tokens_in_a_prefixed_string_literal!(), 3); +} From e9fc942b4db1946993477ed3816d409a95d98d88 Mon Sep 17 00:00:00 2001 From: lrh2000 Date: Sat, 26 Jun 2021 23:40:07 +0800 Subject: [PATCH 13/14] Use FutureIncompatibilityReason to denote edition --- compiler/rustc_lint_defs/src/builtin.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index ba8a8c3d8c993..dbc9a11100f5b 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -3296,7 +3296,7 @@ declare_lint! { "identifiers that will be parsed as a prefix in Rust 2021", @future_incompatible = FutureIncompatibleInfo { reference: "issue #84978 ", - edition: Some(Edition::Edition2021), + reason: FutureIncompatibilityReason::EditionError(Edition::Edition2021), }; crate_level_only } From f6dd1378f0918554ace992df0b3d03529f6a2715 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Sat, 26 Jun 2021 20:49:29 +0000 Subject: [PATCH 14/14] Update reserved prefixes test for new edition lint wording. --- .../ui/rust-2021/reserved-prefixes-migration.fixed | 10 +++++----- src/test/ui/rust-2021/reserved-prefixes-migration.rs | 10 +++++----- .../ui/rust-2021/reserved-prefixes-migration.stderr | 10 +++++----- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/test/ui/rust-2021/reserved-prefixes-migration.fixed b/src/test/ui/rust-2021/reserved-prefixes-migration.fixed index 5537822e8fd75..dbc2ec6d42ee2 100644 --- a/src/test/ui/rust-2021/reserved-prefixes-migration.fixed +++ b/src/test/ui/rust-2021/reserved-prefixes-migration.fixed @@ -15,16 +15,16 @@ macro_rules! m3 { fn main() { m2!(z "hey"); //~^ WARNING prefix `z` is unknown [reserved_prefix] - //~| WARNING become a hard error + //~| WARNING hard error in Rust 2021 m2!(prefix "hey"); //~^ WARNING prefix `prefix` is unknown [reserved_prefix] - //~| WARNING become a hard error + //~| WARNING hard error in Rust 2021 m3!(hey #123); //~^ WARNING prefix `hey` is unknown [reserved_prefix] - //~| WARNING become a hard error + //~| WARNING hard error in Rust 2021 m3!(hey #hey); //~^ WARNING prefix `hey` is unknown [reserved_prefix] - //~| WARNING become a hard error + //~| WARNING hard error in Rust 2021 } macro_rules! quote { @@ -34,5 +34,5 @@ macro_rules! quote { quote! { #name = #kind #value //~^ WARNING prefix `kind` is unknown [reserved_prefix] - //~| WARNING become a hard error + //~| WARNING hard error in Rust 2021 } diff --git a/src/test/ui/rust-2021/reserved-prefixes-migration.rs b/src/test/ui/rust-2021/reserved-prefixes-migration.rs index 5fff0f234f864..6f7e3eb7a43a6 100644 --- a/src/test/ui/rust-2021/reserved-prefixes-migration.rs +++ b/src/test/ui/rust-2021/reserved-prefixes-migration.rs @@ -15,16 +15,16 @@ macro_rules! m3 { fn main() { m2!(z"hey"); //~^ WARNING prefix `z` is unknown [reserved_prefix] - //~| WARNING become a hard error + //~| WARNING hard error in Rust 2021 m2!(prefix"hey"); //~^ WARNING prefix `prefix` is unknown [reserved_prefix] - //~| WARNING become a hard error + //~| WARNING hard error in Rust 2021 m3!(hey#123); //~^ WARNING prefix `hey` is unknown [reserved_prefix] - //~| WARNING become a hard error + //~| WARNING hard error in Rust 2021 m3!(hey#hey); //~^ WARNING prefix `hey` is unknown [reserved_prefix] - //~| WARNING become a hard error + //~| WARNING hard error in Rust 2021 } macro_rules! quote { @@ -34,5 +34,5 @@ macro_rules! quote { quote! { #name = #kind#value //~^ WARNING prefix `kind` is unknown [reserved_prefix] - //~| WARNING become a hard error + //~| WARNING hard error in Rust 2021 } diff --git a/src/test/ui/rust-2021/reserved-prefixes-migration.stderr b/src/test/ui/rust-2021/reserved-prefixes-migration.stderr index 0c38dbd76c223..28ac1966a1bce 100644 --- a/src/test/ui/rust-2021/reserved-prefixes-migration.stderr +++ b/src/test/ui/rust-2021/reserved-prefixes-migration.stderr @@ -9,7 +9,7 @@ note: the lint level is defined here | LL | #![warn(reserved_prefix)] | ^^^^^^^^^^^^^^^ - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition! + = warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2021! = note: for more information, see issue #84978 help: insert whitespace here to avoid this being parsed as a prefix in Rust 2021 | @@ -22,7 +22,7 @@ warning: prefix `prefix` is unknown LL | m2!(prefix"hey"); | ^^^^^^ unknown prefix | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition! + = warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2021! = note: for more information, see issue #84978 help: insert whitespace here to avoid this being parsed as a prefix in Rust 2021 | @@ -35,7 +35,7 @@ warning: prefix `hey` is unknown LL | m3!(hey#123); | ^^^ unknown prefix | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition! + = warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2021! = note: for more information, see issue #84978 help: insert whitespace here to avoid this being parsed as a prefix in Rust 2021 | @@ -48,7 +48,7 @@ warning: prefix `hey` is unknown LL | m3!(hey#hey); | ^^^ unknown prefix | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition! + = warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2021! = note: for more information, see issue #84978 help: insert whitespace here to avoid this being parsed as a prefix in Rust 2021 | @@ -61,7 +61,7 @@ warning: prefix `kind` is unknown LL | #name = #kind#value | ^^^^ unknown prefix | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition! + = warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2021! = note: for more information, see issue #84978 help: insert whitespace here to avoid this being parsed as a prefix in Rust 2021 |