]> git.lizzy.rs Git - rust.git/commitdiff
Warn when an escaped newline skips multiple lines
authorAnton Golov <jesyspa@gmail.com>
Sat, 31 Jul 2021 18:35:37 +0000 (20:35 +0200)
committerAnton Golov <jesyspa@gmail.com>
Wed, 11 Aug 2021 09:35:08 +0000 (11:35 +0200)
compiler/rustc_lexer/src/unescape.rs
compiler/rustc_lexer/src/unescape/tests.rs
compiler/rustc_parse/src/lexer/unescape_error_reporting.rs

index 9a96c03cd3c8086806ebcfd1ea3ee3f47395e6d1..6550eed39583c50d7787f2f1567ee004c5e44bb7 100644 (file)
@@ -60,6 +60,9 @@ pub enum EscapeError {
     /// After a line ending with '\', the next line contains whitespace
     /// characters that are not skipped.
     UnskippedWhitespaceWarning,
+
+    /// After a line ending with '\', multiple lines are skipped.
+    MultipleSkippedLinesWarning,
 }
 
 impl EscapeError {
@@ -67,6 +70,7 @@ impl EscapeError {
     pub fn is_fatal(&self) -> bool {
         match self {
             EscapeError::UnskippedWhitespaceWarning => false,
+            EscapeError::MultipleSkippedLinesWarning => false,
             _ => true,
         }
     }
@@ -320,6 +324,11 @@ fn skip_ascii_whitespace<F>(chars: &mut Chars<'_>, start: usize, callback: &mut
             .bytes()
             .position(|b| b != b' ' && b != b'\t' && b != b'\n' && b != b'\r')
             .unwrap_or(str.len());
+        if str[1..first_non_space].contains('\n') {
+            // The +1 accounts for the escaping slash.
+            let end = start + first_non_space + 1;
+            callback(start..end, Err(EscapeError::MultipleSkippedLinesWarning));
+        }
         let tail = &str[first_non_space..];
         if let Some(c) = tail.chars().nth(0) {
             // For error reporting, we would like the span to contain the character that was not
index 1f4dbb20f4e9896e292e44e3208146c8ab23830e..fa61554afde6c5d16c87b462e0ca802b15a7e0a7 100644 (file)
@@ -106,6 +106,10 @@ fn check(literal: &str, expected: &[(Range<usize>, Result<char, EscapeError>)])
         assert_eq!(unescaped, expected);
     }
 
+    // Check we can handle escaped newlines at the end of a file.
+    check("\\\n", &[]);
+    check("\\\n ", &[]);
+
     check(
         "\\\n \u{a0} x",
         &[
@@ -115,6 +119,7 @@ fn check(literal: &str, expected: &[(Range<usize>, Result<char, EscapeError>)])
             (6..7, Ok('x')),
         ],
     );
+    check("\\\n  \n  x", &[(0..7, Err(EscapeError::MultipleSkippedLinesWarning)), (7..8, Ok('x'))]);
 }
 
 #[test]
index 4e95cdc0efa5f30c83392dc47498ca379b5d6d4d..aa6b424ce2b57ec167c85c7086471cc3165d62ec 100644 (file)
@@ -280,6 +280,11 @@ pub(crate) fn emit_unescape_error(
                 format!("non-ASCII whitespace symbol '{}' is not skipped", c.escape_unicode());
             handler.struct_span_warn(span, &msg).span_label(char_span, &msg).emit();
         }
+        EscapeError::MultipleSkippedLinesWarning => {
+            let msg = "multiple lines skipped by escaped newline";
+            let bottom_msg = "skipping everything up to and including this point";
+            handler.struct_span_warn(span, msg).span_label(span, bottom_msg).emit();
+        }
     }
 }