]> git.lizzy.rs Git - rust.git/commitdiff
Add migration lint for reserved prefixes.
authorMara Bos <m-ou.se@m-ou.se>
Mon, 14 Jun 2021 12:56:49 +0000 (12:56 +0000)
committerlrh2000 <lrh2000@pku.edu.cn>
Sat, 26 Jun 2021 15:11:04 +0000 (23:11 +0800)
compiler/rustc_lint/src/context.rs
compiler/rustc_lint_defs/src/builtin.rs
compiler/rustc_lint_defs/src/lib.rs
compiler/rustc_parse/src/lexer/mod.rs

index 2dc04d57d1e66de4edd05e224ec152df106196a8..933f7e47c3e9d1b36c75235ad791843f7051fee3 100644 (file)
@@ -723,6 +723,15 @@ fn lookup_with_diagnostics(
                 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));
index 53970b485eecd6a8d7616d149c931e8e066afe0d..ba8a8c3d8c993cc036270771d061417c0045d0de 100644 (file)
         OR_PATTERNS_BACK_COMPAT,
         LARGE_ASSIGNMENTS,
         FUTURE_PRELUDE_COLLISION,
+        RESERVED_PREFIX,
     ]
 }
 
         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 <https://github.com/rust-lang/rust/issues/84978>",
+        edition: Some(Edition::Edition2021),
+    };
+    crate_level_only
+}
index b3d98747dcfa2cd60362ed3bae7ae6e0bd608ab3..3372bc716d28ce150b9c7fb1a948c51c27231cb7 100644 (file)
@@ -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
index f5eba5056eab3430aba0add8ad7972e52ea880f9..f50e8a8db0193161fd078a692901da10689005d9 100644 (file)
@@ -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 @@ fn report_unterminated_raw_string(
         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",