about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock1
-rw-r--r--compiler/rustc_driver/Cargo.toml1
-rw-r--r--compiler/rustc_driver/src/lib.rs35
-rw-r--r--compiler/rustc_errors/src/emitter.rs25
-rw-r--r--compiler/rustc_errors/src/styled_buffer.rs27
-rw-r--r--compiler/rustc_resolve/src/late.rs3
-rw-r--r--compiler/rustc_typeck/src/check/compare_method.rs2
-rw-r--r--library/alloc/src/collections/vec_deque/tests.rs15
-rw-r--r--library/core/src/mem/maybe_uninit.rs40
-rw-r--r--library/core/src/slice/mod.rs13
-rw-r--r--library/core/tests/lib.rs2
-rw-r--r--library/core/tests/mem.rs14
-rw-r--r--src/test/ui/drop/auxiliary/issue-10028.rs (renamed from src/test/ui/issues/auxiliary/issue-10028.rs)0
-rw-r--r--src/test/ui/drop/issue-10028.rs (renamed from src/test/ui/issues/issue-10028.rs)0
-rw-r--r--src/test/ui/extern/issue-10025.rs (renamed from src/test/ui/issues/issue-10025.rs)0
-rw-r--r--src/test/ui/issues/auxiliary/issue-10031-aux.rs1
-rw-r--r--src/test/ui/issues/issue-10031.rs9
-rw-r--r--src/test/ui/issues/issue-13033.stderr9
-rw-r--r--src/test/ui/mismatched_types/E0053.stderr9
-rw-r--r--src/test/ui/mismatched_types/trait-impl-fn-incompatibility.stderr9
-rw-r--r--src/test/ui/never_type/issue-10176.rs (renamed from src/test/ui/issues/issue-10176.rs)0
-rw-r--r--src/test/ui/never_type/issue-10176.stderr (renamed from src/test/ui/issues/issue-10176.stderr)0
-rw-r--r--src/test/ui/resolve/issue-10200.rs (renamed from src/test/ui/issues/issue-10200.rs)0
-rw-r--r--src/test/ui/resolve/issue-10200.stderr (renamed from src/test/ui/issues/issue-10200.stderr)0
-rw-r--r--src/test/ui/terminal-width/tabs-trimming.rs13
-rw-r--r--src/test/ui/terminal-width/tabs-trimming.stderr12
26 files changed, 142 insertions, 98 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 322b1632031..ab452c97e7b 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3652,6 +3652,7 @@ dependencies = [
 name = "rustc_driver"
 version = "0.0.0"
 dependencies = [
+ "atty",
  "libc",
  "rustc_ast",
  "rustc_ast_pretty",
diff --git a/compiler/rustc_driver/Cargo.toml b/compiler/rustc_driver/Cargo.toml
index 0adc006b624..b88b556d143 100644
--- a/compiler/rustc_driver/Cargo.toml
+++ b/compiler/rustc_driver/Cargo.toml
@@ -9,6 +9,7 @@ crate-type = ["dylib"]
 
 [dependencies]
 libc = "0.2"
+atty = "0.2"
 tracing = { version = "0.1.18" }
 tracing-subscriber = { version = "0.2.13", default-features = false, features = ["fmt", "env-filter", "smallvec", "parking_lot", "ansi"] }
 tracing-tree = "0.1.6"
diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs
index c2a0d8ef7ea..509f81e1653 100644
--- a/compiler/rustc_driver/src/lib.rs
+++ b/compiler/rustc_driver/src/lib.rs
@@ -546,43 +546,12 @@ impl Compilation {
 #[derive(Copy, Clone)]
 pub struct RustcDefaultCalls;
 
-// FIXME remove these and use winapi 0.3 instead
-// Duplicates: bootstrap/compile.rs, librustc_errors/emitter.rs
-#[cfg(unix)]
-fn stdout_isatty() -> bool {
-    unsafe { libc::isatty(libc::STDOUT_FILENO) != 0 }
-}
-
-#[cfg(windows)]
 fn stdout_isatty() -> bool {
-    use winapi::um::consoleapi::GetConsoleMode;
-    use winapi::um::processenv::GetStdHandle;
-    use winapi::um::winbase::STD_OUTPUT_HANDLE;
-
-    unsafe {
-        let handle = GetStdHandle(STD_OUTPUT_HANDLE);
-        let mut out = 0;
-        GetConsoleMode(handle, &mut out) != 0
-    }
+    atty::is(atty::Stream::Stdout)
 }
 
-// FIXME remove these and use winapi 0.3 instead
-#[cfg(unix)]
-fn stderr_isatty() -> bool {
-    unsafe { libc::isatty(libc::STDERR_FILENO) != 0 }
-}
-
-#[cfg(windows)]
 fn stderr_isatty() -> bool {
-    use winapi::um::consoleapi::GetConsoleMode;
-    use winapi::um::processenv::GetStdHandle;
-    use winapi::um::winbase::STD_ERROR_HANDLE;
-
-    unsafe {
-        let handle = GetStdHandle(STD_ERROR_HANDLE);
-        let mut out = 0;
-        GetConsoleMode(handle, &mut out) != 0
-    }
+    atty::is(atty::Stream::Stderr)
 }
 
 fn handle_explain(registry: Registry, code: &str, output: ErrorOutputType) {
diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs
index 32104e6f00d..00882bb287a 100644
--- a/compiler/rustc_errors/src/emitter.rs
+++ b/compiler/rustc_errors/src/emitter.rs
@@ -644,6 +644,8 @@ impl EmitterWriter {
         code_offset: usize,
         margin: Margin,
     ) {
+        // Tabs are assumed to have been replaced by spaces in calling code.
+        assert!(!source_string.contains('\t'));
         let line_len = source_string.len();
         // Create the source line we will highlight.
         let left = margin.left(line_len);
@@ -707,7 +709,7 @@ impl EmitterWriter {
         }
 
         let source_string = match file.get_line(line.line_index - 1) {
-            Some(s) => s,
+            Some(s) => replace_tabs(&*s),
             None => return Vec::new(),
         };
 
@@ -1376,8 +1378,17 @@ impl EmitterWriter {
                     let file = annotated_file.file.clone();
                     let line = &annotated_file.lines[line_idx];
                     if let Some(source_string) = file.get_line(line.line_index - 1) {
-                        let leading_whitespace =
-                            source_string.chars().take_while(|c| c.is_whitespace()).count();
+                        let leading_whitespace = source_string
+                            .chars()
+                            .take_while(|c| c.is_whitespace())
+                            .map(|c| {
+                                match c {
+                                    // Tabs are displayed as 4 spaces
+                                    '\t' => 4,
+                                    _ => 1,
+                                }
+                            })
+                            .sum();
                         if source_string.chars().any(|c| !c.is_whitespace()) {
                             whitespace_margin = min(whitespace_margin, leading_whitespace);
                         }
@@ -1502,7 +1513,7 @@ impl EmitterWriter {
 
                             self.draw_line(
                                 &mut buffer,
-                                &unannotated_line,
+                                &replace_tabs(&unannotated_line),
                                 annotated_file.lines[line_idx + 1].line_index - 1,
                                 last_buffer_line_num,
                                 width_offset,
@@ -1598,7 +1609,7 @@ impl EmitterWriter {
                 );
                 // print the suggestion
                 draw_col_separator(&mut buffer, row_num, max_line_num_len + 1);
-                buffer.append(row_num, line, Style::NoStyle);
+                buffer.append(row_num, &replace_tabs(line), Style::NoStyle);
                 row_num += 1;
             }
 
@@ -1930,6 +1941,10 @@ impl FileWithAnnotatedLines {
     }
 }
 
+fn replace_tabs(str: &str) -> String {
+    str.replace('\t', "    ")
+}
+
 fn draw_col_separator(buffer: &mut StyledBuffer, line: usize, col: usize) {
     buffer.puts(line, col, "| ", Style::LineNumber);
 }
diff --git a/compiler/rustc_errors/src/styled_buffer.rs b/compiler/rustc_errors/src/styled_buffer.rs
index f2d255d7d95..a4dd0f391bd 100644
--- a/compiler/rustc_errors/src/styled_buffer.rs
+++ b/compiler/rustc_errors/src/styled_buffer.rs
@@ -13,34 +13,13 @@ impl StyledBuffer {
         StyledBuffer { text: vec![], styles: vec![] }
     }
 
-    fn replace_tabs(&mut self) {
-        for (line_pos, line) in self.text.iter_mut().enumerate() {
-            let mut tab_pos = vec![];
-            for (pos, c) in line.iter().enumerate() {
-                if *c == '\t' {
-                    tab_pos.push(pos);
-                }
-            }
-            // start with the tabs at the end of the line to replace them with 4 space chars
-            for pos in tab_pos.iter().rev() {
-                assert_eq!(line.remove(*pos), '\t');
-                // fix the position of the style to match up after replacing the tabs
-                let s = self.styles[line_pos].remove(*pos);
-                for _ in 0..4 {
-                    line.insert(*pos, ' ');
-                    self.styles[line_pos].insert(*pos, s);
-                }
-            }
-        }
-    }
+    pub fn render(&self) -> Vec<Vec<StyledString>> {
+        // Tabs are assumed to have been replaced by spaces in calling code.
+        assert!(self.text.iter().all(|r| !r.contains(&'\t')));
 
-    pub fn render(&mut self) -> Vec<Vec<StyledString>> {
         let mut output: Vec<Vec<StyledString>> = vec![];
         let mut styled_vec: Vec<StyledString> = vec![];
 
-        // before we render, replace tabs with spaces
-        self.replace_tabs();
-
         for (row, row_style) in self.text.iter().zip(&self.styles) {
             let mut current_style = Style::NoStyle;
             let mut current_text = String::new();
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 8544e1d8ee5..6219d1b08eb 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -1947,8 +1947,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
             _ => report_errors(self, None),
         };
 
-        if let PathSource::TraitItem(..) = source {
-        } else {
+        if !matches!(source, PathSource::TraitItem(..)) {
             // Avoid recording definition of `A::B` in `<T as A>::B::C`.
             self.r.record_partial_res(id, partial_res);
         }
diff --git a/compiler/rustc_typeck/src/check/compare_method.rs b/compiler/rustc_typeck/src/check/compare_method.rs
index bb324d0d8bc..320ded5334e 100644
--- a/compiler/rustc_typeck/src/check/compare_method.rs
+++ b/compiler/rustc_typeck/src/check/compare_method.rs
@@ -296,7 +296,7 @@ fn compare_predicate_entailment<'tcx>(
                     {
                         diag.span_suggestion(
                             impl_err_span,
-                            "consider change the type to match the mutability in trait",
+                            "consider changing the mutability to match the trait",
                             trait_err_str,
                             Applicability::MachineApplicable,
                         );
diff --git a/library/alloc/src/collections/vec_deque/tests.rs b/library/alloc/src/collections/vec_deque/tests.rs
index 21f52af056b..27dc59ae644 100644
--- a/library/alloc/src/collections/vec_deque/tests.rs
+++ b/library/alloc/src/collections/vec_deque/tests.rs
@@ -225,6 +225,21 @@ fn make_contiguous_head_to_end() {
 }
 
 #[test]
+fn make_contiguous_head_to_end_2() {
+    // Another test case for #79808, taken from #80293.
+
+    let mut dq = VecDeque::from_iter(0..6);
+    dq.pop_front();
+    dq.pop_front();
+    dq.push_back(6);
+    dq.push_back(7);
+    dq.push_back(8);
+    dq.make_contiguous();
+    let collected: Vec<_> = dq.iter().copied().collect();
+    assert_eq!(dq.as_slices(), (&collected[..], &[] as &[_]));
+}
+
+#[test]
 fn test_remove() {
     // This test checks that every single combination of tail position, length, and
     // removal position is tested. Capacity 15 should be large enough to cover every case.
diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs
index b2a4d897eed..fda0553f94c 100644
--- a/library/core/src/mem/maybe_uninit.rs
+++ b/library/core/src/mem/maybe_uninit.rs
@@ -804,6 +804,46 @@ impl<T> MaybeUninit<T> {
         }
     }
 
+    /// Extracts the values from an array of `MaybeUninit` containers.
+    ///
+    /// # Safety
+    ///
+    /// It is up to the caller to guarantee that all elements of the array are
+    /// in an initialized state.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(maybe_uninit_uninit_array)]
+    /// #![feature(maybe_uninit_array_assume_init)]
+    /// use std::mem::MaybeUninit;
+    ///
+    /// let mut array: [MaybeUninit<i32>; 3] = MaybeUninit::uninit_array();
+    /// array[0] = MaybeUninit::new(0);
+    /// array[1] = MaybeUninit::new(1);
+    /// array[2] = MaybeUninit::new(2);
+    ///
+    /// // SAFETY: Now safe as we initialised all elements
+    /// let array = unsafe {
+    ///     MaybeUninit::array_assume_init(array)
+    /// };
+    ///
+    /// assert_eq!(array, [0, 1, 2]);
+    /// ```
+    #[unstable(feature = "maybe_uninit_array_assume_init", issue = "80908")]
+    #[inline(always)]
+    pub unsafe fn array_assume_init<const N: usize>(array: [Self; N]) -> [T; N] {
+        // SAFETY:
+        // * The caller guarantees that all elements of the array are initialized
+        // * `MaybeUninit<T>` and T are guaranteed to have the same layout
+        // * MaybeUnint does not drop, so there are no double-frees
+        // And thus the conversion is safe
+        unsafe {
+            intrinsics::assert_inhabited::<T>();
+            (&array as *const _ as *const [T; N]).read()
+        }
+    }
+
     /// Assuming all the elements are initialized, get a slice to them.
     ///
     /// # Safety
diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs
index bd01271ec15..439a39b8276 100644
--- a/library/core/src/slice/mod.rs
+++ b/library/core/src/slice/mod.rs
@@ -1357,14 +1357,11 @@ impl<T> [T] {
     ///
     /// ```
     /// let mut v = [1, 0, 3, 0, 5, 6];
-    /// // scoped to restrict the lifetime of the borrows
-    /// {
-    ///     let (left, right) = v.split_at_mut(2);
-    ///     assert_eq!(left, [1, 0]);
-    ///     assert_eq!(right, [3, 0, 5, 6]);
-    ///     left[1] = 2;
-    ///     right[1] = 4;
-    /// }
+    /// let (left, right) = v.split_at_mut(2);
+    /// assert_eq!(left, [1, 0]);
+    /// assert_eq!(right, [3, 0, 5, 6]);
+    /// left[1] = 2;
+    /// right[1] = 4;
     /// assert_eq!(v, [1, 2, 3, 4, 5, 6]);
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index e01aaa4cbf1..bc737cd1927 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -36,6 +36,8 @@
 #![feature(raw)]
 #![feature(sort_internals)]
 #![feature(slice_partition_at_index)]
+#![feature(maybe_uninit_uninit_array)]
+#![feature(maybe_uninit_array_assume_init)]
 #![feature(maybe_uninit_extra)]
 #![feature(maybe_uninit_write_slice)]
 #![feature(min_specialization)]
diff --git a/library/core/tests/mem.rs b/library/core/tests/mem.rs
index 79ca2bba403..2279a16429f 100644
--- a/library/core/tests/mem.rs
+++ b/library/core/tests/mem.rs
@@ -141,6 +141,20 @@ fn assume_init_good() {
 }
 
 #[test]
+fn uninit_array_assume_init() {
+    let mut array: [MaybeUninit<i16>; 5] = MaybeUninit::uninit_array();
+    array[0].write(3);
+    array[1].write(1);
+    array[2].write(4);
+    array[3].write(1);
+    array[4].write(5);
+
+    let array = unsafe { MaybeUninit::array_assume_init(array) };
+
+    assert_eq!(array, [3, 1, 4, 1, 5]);
+}
+
+#[test]
 fn uninit_write_slice() {
     let mut dst = [MaybeUninit::new(255); 64];
     let src = [0; 64];
diff --git a/src/test/ui/issues/auxiliary/issue-10028.rs b/src/test/ui/drop/auxiliary/issue-10028.rs
index 135f26f4047..135f26f4047 100644
--- a/src/test/ui/issues/auxiliary/issue-10028.rs
+++ b/src/test/ui/drop/auxiliary/issue-10028.rs
diff --git a/src/test/ui/issues/issue-10028.rs b/src/test/ui/drop/issue-10028.rs
index 1692470e8d1..1692470e8d1 100644
--- a/src/test/ui/issues/issue-10028.rs
+++ b/src/test/ui/drop/issue-10028.rs
diff --git a/src/test/ui/issues/issue-10025.rs b/src/test/ui/extern/issue-10025.rs
index 193d7ee891f..193d7ee891f 100644
--- a/src/test/ui/issues/issue-10025.rs
+++ b/src/test/ui/extern/issue-10025.rs
diff --git a/src/test/ui/issues/auxiliary/issue-10031-aux.rs b/src/test/ui/issues/auxiliary/issue-10031-aux.rs
deleted file mode 100644
index e2abeb99ea8..00000000000
--- a/src/test/ui/issues/auxiliary/issue-10031-aux.rs
+++ /dev/null
@@ -1 +0,0 @@
-pub struct Wrap<A>(pub A);
diff --git a/src/test/ui/issues/issue-10031.rs b/src/test/ui/issues/issue-10031.rs
deleted file mode 100644
index 136df05c239..00000000000
--- a/src/test/ui/issues/issue-10031.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-// run-pass
-// aux-build:issue-10031-aux.rs
-// pretty-expanded FIXME #23616
-
-extern crate issue_10031_aux;
-
-pub fn main() {
-    let _ = issue_10031_aux::Wrap(());
-}
diff --git a/src/test/ui/issues/issue-13033.stderr b/src/test/ui/issues/issue-13033.stderr
index a8473c8a524..57447fa48aa 100644
--- a/src/test/ui/issues/issue-13033.stderr
+++ b/src/test/ui/issues/issue-13033.stderr
@@ -5,14 +5,13 @@ LL |     fn bar(&mut self, other: &mut dyn Foo);
    |                              ------------ type in trait
 ...
 LL |     fn bar(&mut self, other: &dyn Foo) {}
-   |                              ^^^^^^^^ types differ in mutability
+   |                              ^^^^^^^^
+   |                              |
+   |                              types differ in mutability
+   |                              help: consider changing the mutability to match the trait: `&mut dyn Foo`
    |
    = note: expected fn pointer `fn(&mut Baz, &mut dyn Foo)`
               found fn pointer `fn(&mut Baz, &dyn Foo)`
-help: consider change the type to match the mutability in trait
-   |
-LL |     fn bar(&mut self, other: &mut dyn Foo) {}
-   |                              ^^^^^^^^^^^^
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/mismatched_types/E0053.stderr b/src/test/ui/mismatched_types/E0053.stderr
index fef83e6bbe2..e0a3ce922b9 100644
--- a/src/test/ui/mismatched_types/E0053.stderr
+++ b/src/test/ui/mismatched_types/E0053.stderr
@@ -17,14 +17,13 @@ LL |     fn bar(&self);
    |            ----- type in trait
 ...
 LL |     fn bar(&mut self) { }
-   |            ^^^^^^^^^ types differ in mutability
+   |            ^^^^^^^^^
+   |            |
+   |            types differ in mutability
+   |            help: consider changing the mutability to match the trait: `&self`
    |
    = note: expected fn pointer `fn(&Bar)`
               found fn pointer `fn(&mut Bar)`
-help: consider change the type to match the mutability in trait
-   |
-LL |     fn bar(&self) { }
-   |            ^^^^^
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/mismatched_types/trait-impl-fn-incompatibility.stderr b/src/test/ui/mismatched_types/trait-impl-fn-incompatibility.stderr
index 5735120f710..161843473b6 100644
--- a/src/test/ui/mismatched_types/trait-impl-fn-incompatibility.stderr
+++ b/src/test/ui/mismatched_types/trait-impl-fn-incompatibility.stderr
@@ -17,14 +17,13 @@ LL |     fn bar(&mut self, bar: &mut Bar);
    |                            -------- type in trait
 ...
 LL |     fn bar(&mut self, bar: &Bar) { }
-   |                            ^^^^ types differ in mutability
+   |                            ^^^^
+   |                            |
+   |                            types differ in mutability
+   |                            help: consider changing the mutability to match the trait: `&mut Bar`
    |
    = note: expected fn pointer `fn(&mut Bar, &mut Bar)`
               found fn pointer `fn(&mut Bar, &Bar)`
-help: consider change the type to match the mutability in trait
-   |
-LL |     fn bar(&mut self, bar: &mut Bar) { }
-   |                            ^^^^^^^^
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/issues/issue-10176.rs b/src/test/ui/never_type/issue-10176.rs
index 6277aa05eb3..6277aa05eb3 100644
--- a/src/test/ui/issues/issue-10176.rs
+++ b/src/test/ui/never_type/issue-10176.rs
diff --git a/src/test/ui/issues/issue-10176.stderr b/src/test/ui/never_type/issue-10176.stderr
index cd5361ffad3..cd5361ffad3 100644
--- a/src/test/ui/issues/issue-10176.stderr
+++ b/src/test/ui/never_type/issue-10176.stderr
diff --git a/src/test/ui/issues/issue-10200.rs b/src/test/ui/resolve/issue-10200.rs
index fe36a7e00bf..fe36a7e00bf 100644
--- a/src/test/ui/issues/issue-10200.rs
+++ b/src/test/ui/resolve/issue-10200.rs
diff --git a/src/test/ui/issues/issue-10200.stderr b/src/test/ui/resolve/issue-10200.stderr
index e60489f5b82..e60489f5b82 100644
--- a/src/test/ui/issues/issue-10200.stderr
+++ b/src/test/ui/resolve/issue-10200.stderr
diff --git a/src/test/ui/terminal-width/tabs-trimming.rs b/src/test/ui/terminal-width/tabs-trimming.rs
new file mode 100644
index 00000000000..ade21753b45
--- /dev/null
+++ b/src/test/ui/terminal-width/tabs-trimming.rs
@@ -0,0 +1,13 @@
+// Test for #78438: ensure underline alignment with many tabs on the left, long line on the right
+
+// ignore-tidy-linelength
+// ignore-tidy-tab
+
+					fn main() {
+						let money = 42i32;
+						match money {
+							v @ 1 | 2 | 3 => panic!("You gave me too little money {}", v), // Long text here: TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT
+							//~^ ERROR variable `v` is not bound in all patterns
+							v => println!("Enough money {}", v),
+						}
+					}
diff --git a/src/test/ui/terminal-width/tabs-trimming.stderr b/src/test/ui/terminal-width/tabs-trimming.stderr
new file mode 100644
index 00000000000..6c8d9afc73b
--- /dev/null
+++ b/src/test/ui/terminal-width/tabs-trimming.stderr
@@ -0,0 +1,12 @@
+error[E0408]: variable `v` is not bound in all patterns
+  --> $DIR/tabs-trimming.rs:9:16
+   |
+LL | ...   v @ 1 | 2 | 3 => panic!("You gave me too little money {}", v), // Long text here: TTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT...
+   |       -       ^   ^ pattern doesn't bind `v`
+   |       |       |
+   |       |       pattern doesn't bind `v`
+   |       variable not in all patterns
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0408`.