about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2021-03-19 23:53:02 +0000
committerbors <bors@rust-lang.org>2021-03-19 23:53:02 +0000
commit6bfbf0c33a86707cedd02ca985285191282a80b3 (patch)
tree3379b7c53a90fdbb23ef8c041ae4a8eb0b1955fe
parentf5f33ec0e0455eefa72fc5567eb1280a4d5ee206 (diff)
parent51a29cbb23d2146322350fbfde53fe9523e554fb (diff)
downloadrust-6bfbf0c33a86707cedd02ca985285191282a80b3.tar.gz
rust-6bfbf0c33a86707cedd02ca985285191282a80b3.zip
Auto merge of #83308 - Dylan-DPC:rollup-p2j6sy8, r=Dylan-DPC
Rollup of 8 pull requests

Successful merges:

 - #79986 (Only build help popup when it's really needed)
 - #82570 (Add `as_str` method for split whitespace str iterators)
 - #83244 (Fix overflowing length in Vec<ZST> to VecDeque)
 - #83254 (Include output stream in `panic!()` documentation)
 - #83269 (Revert the second deprecation of collections::Bound)
 - #83277 (Mark early otherwise optimization unsound)
 - #83285 (Update LLVM to bring in SIMD updates for WebAssembly)
 - #83297 (Do not ICE on ty::Error as an error must already have been reported)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--compiler/rustc_middle/src/ty/relate.rs14
-rw-r--r--compiler/rustc_mir/src/transform/early_otherwise_branch.rs5
-rw-r--r--library/alloc/src/collections/vec_deque/mod.rs37
-rw-r--r--library/alloc/src/collections/vec_deque/tests.rs15
-rw-r--r--library/core/src/iter/adapters/filter.rs3
-rw-r--r--library/core/src/iter/adapters/map.rs3
-rw-r--r--library/core/src/macros/panic.md15
-rw-r--r--library/core/src/slice/iter.rs6
-rw-r--r--library/core/src/str/iter.rs53
-rw-r--r--library/std/src/collections/mod.rs5
-rw-r--r--src/librustdoc/html/static/main.js32
m---------src/llvm-project0
-rw-r--r--src/test/mir-opt/early_otherwise_branch.rs2
-rw-r--r--src/test/mir-opt/early_otherwise_branch_3_element_tuple.rs2
-rw-r--r--src/test/ui/const-generics/type_mismatch.rs9
-rw-r--r--src/test/ui/const-generics/type_mismatch.stderr23
-rw-r--r--src/test/ui/const-generics/type_not_in_scope.rs11
-rw-r--r--src/test/ui/const-generics/type_not_in_scope.stderr24
18 files changed, 210 insertions, 49 deletions
diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs
index 436ca4c0578..b41bf70e88e 100644
--- a/compiler/rustc_middle/src/ty/relate.rs
+++ b/compiler/rustc_middle/src/ty/relate.rs
@@ -10,6 +10,7 @@ use crate::ty::subst::{GenericArg, GenericArgKind, SubstsRef};
 use crate::ty::{self, Ty, TyCtxt, TypeFoldable};
 use rustc_hir as ast;
 use rustc_hir::def_id::DefId;
+use rustc_span::DUMMY_SP;
 use rustc_target::spec::abi;
 use std::iter;
 
@@ -499,11 +500,14 @@ pub fn super_relate_consts<R: TypeRelation<'tcx>>(
 
     // FIXME(oli-obk): once const generics can have generic types, this assertion
     // will likely get triggered. Move to `normalize_erasing_regions` at that point.
-    assert_eq!(
-        tcx.erase_regions(a.ty),
-        tcx.erase_regions(b.ty),
-        "cannot relate constants of different types"
-    );
+    let a_ty = tcx.erase_regions(a.ty);
+    let b_ty = tcx.erase_regions(b.ty);
+    if a_ty != b_ty {
+        relation.tcx().sess.delay_span_bug(
+            DUMMY_SP,
+            &format!("cannot relate constants of different types: {} != {}", a_ty, b_ty),
+        );
+    }
 
     let eagerly_eval = |x: &'tcx ty::Const<'tcx>| x.eval(tcx, relation.param_env());
     let a = eagerly_eval(a);
diff --git a/compiler/rustc_mir/src/transform/early_otherwise_branch.rs b/compiler/rustc_mir/src/transform/early_otherwise_branch.rs
index e64a539c7f8..f7ea9faec47 100644
--- a/compiler/rustc_mir/src/transform/early_otherwise_branch.rs
+++ b/compiler/rustc_mir/src/transform/early_otherwise_branch.rs
@@ -26,6 +26,11 @@ pub struct EarlyOtherwiseBranch;
 
 impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch {
     fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+        //  FIXME(#78496)
+        if !tcx.sess.opts.debugging_opts.unsound_mir_opts {
+            return;
+        }
+
         if tcx.sess.mir_opt_level() < 3 {
             return;
         }
diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs
index f7cefdce278..7a0de74eb23 100644
--- a/library/alloc/src/collections/vec_deque/mod.rs
+++ b/library/alloc/src/collections/vec_deque/mod.rs
@@ -2783,27 +2783,26 @@ impl<T> From<Vec<T>> for VecDeque<T> {
     /// This avoids reallocating where possible, but the conditions for that are
     /// strict, and subject to change, and so shouldn't be relied upon unless the
     /// `Vec<T>` came from `From<VecDeque<T>>` and hasn't been reallocated.
-    fn from(other: Vec<T>) -> Self {
-        unsafe {
-            let mut other = ManuallyDrop::new(other);
-            let other_buf = other.as_mut_ptr();
-            let mut buf = RawVec::from_raw_parts(other_buf, other.capacity());
-            let len = other.len();
-
-            // We need to extend the buf if it's not a power of two, too small
-            // or doesn't have at least one free space.
-            // We check if `T` is a ZST in the first condition,
-            // because `usize::MAX` (the capacity returned by `capacity()` for ZST)
-            // is not a power of two and thus it'll always try
-            // to reserve more memory which will panic for ZST (rust-lang/rust#78532)
-            if (!buf.capacity().is_power_of_two() && mem::size_of::<T>() != 0)
-                || (buf.capacity() < (MINIMUM_CAPACITY + 1))
-                || (buf.capacity() == len)
-            {
-                let cap = cmp::max(buf.capacity() + 1, MINIMUM_CAPACITY + 1).next_power_of_two();
-                buf.reserve_exact(len, cap - len);
+    fn from(mut other: Vec<T>) -> Self {
+        let len = other.len();
+        if mem::size_of::<T>() == 0 {
+            // There's no actual allocation for ZSTs to worry about capacity,
+            // but `VecDeque` can't handle as much length as `Vec`.
+            assert!(len < MAXIMUM_ZST_CAPACITY, "capacity overflow");
+        } else {
+            // We need to resize if the capacity is not a power of two, too small or
+            // doesn't have at least one free space. We do this while it's still in
+            // the `Vec` so the items will drop on panic.
+            let min_cap = cmp::max(MINIMUM_CAPACITY, len) + 1;
+            let cap = cmp::max(min_cap, other.capacity()).next_power_of_two();
+            if other.capacity() != cap {
+                other.reserve_exact(cap - len);
             }
+        }
 
+        unsafe {
+            let (other_buf, len, capacity) = other.into_raw_parts();
+            let buf = RawVec::from_raw_parts(other_buf, capacity);
             VecDeque { tail: 0, head: len, buf }
         }
     }
diff --git a/library/alloc/src/collections/vec_deque/tests.rs b/library/alloc/src/collections/vec_deque/tests.rs
index 87e06fa394d..6116cfe1d01 100644
--- a/library/alloc/src/collections/vec_deque/tests.rs
+++ b/library/alloc/src/collections/vec_deque/tests.rs
@@ -457,6 +457,21 @@ fn test_from_vec() {
             assert!(vd.into_iter().eq(vec));
         }
     }
+
+    let vec = Vec::from([(); MAXIMUM_ZST_CAPACITY - 1]);
+    let vd = VecDeque::from(vec.clone());
+    assert!(vd.cap().is_power_of_two());
+    assert_eq!(vd.len(), vec.len());
+}
+
+#[test]
+#[should_panic = "capacity overflow"]
+fn test_from_vec_zst_overflow() {
+    use crate::vec::Vec;
+    let vec = Vec::from([(); MAXIMUM_ZST_CAPACITY]);
+    let vd = VecDeque::from(vec.clone()); // no room for +1
+    assert!(vd.cap().is_power_of_two());
+    assert_eq!(vd.len(), vec.len());
 }
 
 #[test]
diff --git a/library/core/src/iter/adapters/filter.rs b/library/core/src/iter/adapters/filter.rs
index f8d684fcdda..0337892b9e8 100644
--- a/library/core/src/iter/adapters/filter.rs
+++ b/library/core/src/iter/adapters/filter.rs
@@ -13,7 +13,8 @@ use crate::ops::Try;
 #[stable(feature = "rust1", since = "1.0.0")]
 #[derive(Clone)]
 pub struct Filter<I, P> {
-    iter: I,
+    // Used for `SplitWhitespace` and `SplitAsciiWhitespace` `as_str` methods
+    pub(crate) iter: I,
     predicate: P,
 }
 impl<I, P> Filter<I, P> {
diff --git a/library/core/src/iter/adapters/map.rs b/library/core/src/iter/adapters/map.rs
index 2d997cfe509..2a4b7efd5e6 100644
--- a/library/core/src/iter/adapters/map.rs
+++ b/library/core/src/iter/adapters/map.rs
@@ -57,7 +57,8 @@ use crate::ops::Try;
 #[stable(feature = "rust1", since = "1.0.0")]
 #[derive(Clone)]
 pub struct Map<I, F> {
-    iter: I,
+    // Used for `SplitWhitespace` and `SplitAsciiWhitespace` `as_str` methods
+    pub(crate) iter: I,
     f: F,
 }
 
diff --git a/library/core/src/macros/panic.md b/library/core/src/macros/panic.md
index 6e502426df9..5127a16bbfd 100644
--- a/library/core/src/macros/panic.md
+++ b/library/core/src/macros/panic.md
@@ -9,11 +9,15 @@ tests. `panic!` is closely tied with the `unwrap` method of both
 [`Option`][ounwrap] and [`Result`][runwrap] enums. Both implementations call
 `panic!` when they are set to [`None`] or [`Err`] variants.
 
-This macro is used to inject panic into a Rust thread, causing the thread to
-panic entirely. This macro panics with a string and uses the [`format!`] syntax
-for building the message.
-
-Each thread's panic can be reaped as the [`Box`]`<`[`Any`]`>` type,
+When using `panic!()` you can specify a string payload, that is built using
+the [`format!`] syntax. That payload is used when injecting the panic into
+the calling Rust thread, causing the thread to panic entirely.
+
+The behavior of the default `std` hook, i.e. the code that runs directly
+after the panic is invoked, is to print the message payload to
+`stderr` along with the file/line/column information of the `panic!()`
+call. You can override the panic hook using [`std::panic::set_hook()`].
+Inside the hook a panic can be accessed as a `&dyn Any + Send`,
 which contains either a `&str` or `String` for regular `panic!()` invocations.
 To panic with a value of another other type, [`panic_any`] can be used.
 
@@ -26,6 +30,7 @@ See also the macro [`compile_error!`], for raising errors during compilation.
 
 [ounwrap]: Option::unwrap
 [runwrap]: Result::unwrap
+[`std::panic::set_hook()`]: ../std/panic/fn.set_hook.html
 [`panic_any`]: ../std/panic/fn.panic_any.html
 [`Box`]: ../std/boxed/struct.Box.html
 [`Any`]: crate::any::Any
diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs
index 796301c76b6..c82b76df6ff 100644
--- a/library/core/src/slice/iter.rs
+++ b/library/core/src/slice/iter.rs
@@ -335,9 +335,11 @@ pub struct Split<'a, T: 'a, P>
 where
     P: FnMut(&T) -> bool,
 {
-    v: &'a [T],
+    // Used for `SplitWhitespace` and `SplitAsciiWhitespace` `as_str` methods
+    pub(crate) v: &'a [T],
     pred: P,
-    finished: bool,
+    // Used for `SplitAsciiWhitespace` `as_str` method
+    pub(crate) finished: bool,
 }
 
 impl<'a, T: 'a, P: FnMut(&T) -> bool> Split<'a, T, P> {
diff --git a/library/core/src/str/iter.rs b/library/core/src/str/iter.rs
index 0c9307a6d2f..4eac017f915 100644
--- a/library/core/src/str/iter.rs
+++ b/library/core/src/str/iter.rs
@@ -1200,6 +1200,30 @@ impl<'a> DoubleEndedIterator for SplitWhitespace<'a> {
 #[stable(feature = "fused", since = "1.26.0")]
 impl FusedIterator for SplitWhitespace<'_> {}
 
+impl<'a> SplitWhitespace<'a> {
+    /// Returns remainder of the splitted string
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(str_split_whitespace_as_str)]
+    ///
+    /// let mut split = "Mary had a little lamb".split_whitespace();
+    /// assert_eq!(split.as_str(), "Mary had a little lamb");
+    ///
+    /// split.next();
+    /// assert_eq!(split.as_str(), "had a little lamb");
+    ///
+    /// split.by_ref().for_each(drop);
+    /// assert_eq!(split.as_str(), "");
+    /// ```
+    #[inline]
+    #[unstable(feature = "str_split_whitespace_as_str", issue = "77998")]
+    pub fn as_str(&self) -> &'a str {
+        self.inner.iter.as_str()
+    }
+}
+
 #[stable(feature = "split_ascii_whitespace", since = "1.34.0")]
 impl<'a> Iterator for SplitAsciiWhitespace<'a> {
     type Item = &'a str;
@@ -1231,6 +1255,35 @@ impl<'a> DoubleEndedIterator for SplitAsciiWhitespace<'a> {
 #[stable(feature = "split_ascii_whitespace", since = "1.34.0")]
 impl FusedIterator for SplitAsciiWhitespace<'_> {}
 
+impl<'a> SplitAsciiWhitespace<'a> {
+    /// Returns remainder of the splitted string
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(str_split_whitespace_as_str)]
+    ///
+    /// let mut split = "Mary had a little lamb".split_ascii_whitespace();
+    /// assert_eq!(split.as_str(), "Mary had a little lamb");
+    ///
+    /// split.next();
+    /// assert_eq!(split.as_str(), "had a little lamb");
+    ///
+    /// split.by_ref().for_each(drop);
+    /// assert_eq!(split.as_str(), "");
+    /// ```
+    #[inline]
+    #[unstable(feature = "str_split_whitespace_as_str", issue = "77998")]
+    pub fn as_str(&self) -> &'a str {
+        if self.inner.iter.iter.finished {
+            return "";
+        }
+
+        // SAFETY: Slice is created from str.
+        unsafe { crate::str::from_utf8_unchecked(&self.inner.iter.iter.v) }
+    }
+}
+
 #[stable(feature = "split_inclusive", since = "1.51.0")]
 impl<'a, P: Pattern<'a>> Iterator for SplitInclusive<'a, P> {
     type Item = &'a str;
diff --git a/library/std/src/collections/mod.rs b/library/std/src/collections/mod.rs
index 7f8f9c991fe..8cda601edd1 100644
--- a/library/std/src/collections/mod.rs
+++ b/library/std/src/collections/mod.rs
@@ -401,9 +401,10 @@
 #![stable(feature = "rust1", since = "1.0.0")]
 
 #[stable(feature = "rust1", since = "1.0.0")]
-#[rustc_deprecated(reason = "moved to `std::ops::Bound`", since = "1.52.0")]
+// FIXME(#82080) The deprecation here is only theoretical, and does not actually produce a warning.
+#[rustc_deprecated(reason = "moved to `std::ops::Bound`", since = "1.26.0")]
 #[doc(hidden)]
-pub type Bound<T> = crate::ops::Bound<T>;
+pub use crate::ops::Bound;
 
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use alloc_crate::collections::{binary_heap, btree_map, btree_set};
diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js
index e7b522093c7..f1ecaaa619c 100644
--- a/src/librustdoc/html/static/main.js
+++ b/src/librustdoc/html/static/main.js
@@ -1,3 +1,4 @@
+// ignore-tidy-filelength
 // Local js definitions:
 /* global addClass, getSettingValue, hasClass */
 /* global onEach, onEachLazy, hasOwnProperty, removeClass, updateLocalStorage */
@@ -374,28 +375,35 @@ function defocusSearchBar() {
         }
     }
 
-    function getHelpElement() {
-        buildHelperPopup();
+    function getHelpElement(build) {
+        if (build !== false) {
+            buildHelperPopup();
+        }
         return document.getElementById("help");
     }
 
     function displayHelp(display, ev, help) {
-        help = help ? help : getHelpElement();
         if (display === true) {
+            help = help ? help : getHelpElement(true);
             if (hasClass(help, "hidden")) {
                 ev.preventDefault();
                 removeClass(help, "hidden");
                 addClass(document.body, "blur");
             }
-        } else if (hasClass(help, "hidden") === false) {
-            ev.preventDefault();
-            addClass(help, "hidden");
-            removeClass(document.body, "blur");
+        } else {
+            // No need to build the help popup if we want to hide it in case it hasn't been
+            // built yet...
+            help = help ? help : getHelpElement(false);
+            if (help && hasClass(help, "hidden") === false) {
+                ev.preventDefault();
+                addClass(help, "hidden");
+                removeClass(document.body, "blur");
+            }
         }
     }
 
     function handleEscape(ev) {
-        var help = getHelpElement();
+        var help = getHelpElement(false);
         var search = getSearchElement();
         if (hasClass(help, "hidden") === false) {
             displayHelp(false, ev, help);
@@ -558,6 +566,7 @@ function defocusSearchBar() {
     }());
 
     document.addEventListener("click", function(ev) {
+        var helpElem = getHelpElement(false);
         if (hasClass(ev.target, "help-button")) {
             displayHelp(true, ev);
         } else if (hasClass(ev.target, "collapse-toggle")) {
@@ -566,11 +575,10 @@ function defocusSearchBar() {
             collapseDocs(ev.target.parentNode, "toggle");
         } else if (ev.target.tagName === "SPAN" && hasClass(ev.target.parentNode, "line-numbers")) {
             handleSourceHighlight(ev);
-        } else if (hasClass(getHelpElement(), "hidden") === false) {
-            var help = getHelpElement();
-            var is_inside_help_popup = ev.target !== help && help.contains(ev.target);
+        } else if (helpElem && hasClass(helpElem, "hidden") === false) {
+            var is_inside_help_popup = ev.target !== helpElem && helpElem.contains(ev.target);
             if (is_inside_help_popup === false) {
-                addClass(help, "hidden");
+                addClass(helpElem, "hidden");
                 removeClass(document.body, "blur");
             }
         } else {
diff --git a/src/llvm-project b/src/llvm-project
-Subproject 62a1ddde22c267249eda72184520a21ad2052f0
+Subproject c3a26cbf6e73f2c5f8d03cee1f151d90a266ef3
diff --git a/src/test/mir-opt/early_otherwise_branch.rs b/src/test/mir-opt/early_otherwise_branch.rs
index 548213ab83c..b2caf7d7b8f 100644
--- a/src/test/mir-opt/early_otherwise_branch.rs
+++ b/src/test/mir-opt/early_otherwise_branch.rs
@@ -1,4 +1,4 @@
-// compile-flags: -Z mir-opt-level=4
+// compile-flags: -Z mir-opt-level=4 -Z unsound-mir-opts
 // EMIT_MIR early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff
 fn opt1(x: Option<u32>, y: Option<u32>) -> u32 {
     match (x, y) {
diff --git a/src/test/mir-opt/early_otherwise_branch_3_element_tuple.rs b/src/test/mir-opt/early_otherwise_branch_3_element_tuple.rs
index aa304f747f7..8527c01d756 100644
--- a/src/test/mir-opt/early_otherwise_branch_3_element_tuple.rs
+++ b/src/test/mir-opt/early_otherwise_branch_3_element_tuple.rs
@@ -1,4 +1,4 @@
-// compile-flags: -Z mir-opt-level=4
+// compile-flags: -Z mir-opt-level=4 -Z unsound-mir-opts
 
 // EMIT_MIR early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff
 fn opt1(x: Option<u32>, y: Option<u32>, z: Option<u32>) -> u32 {
diff --git a/src/test/ui/const-generics/type_mismatch.rs b/src/test/ui/const-generics/type_mismatch.rs
new file mode 100644
index 00000000000..4a7534e3713
--- /dev/null
+++ b/src/test/ui/const-generics/type_mismatch.rs
@@ -0,0 +1,9 @@
+fn foo<const N: usize>() -> [u8; N] {
+    bar::<N>() //~ ERROR mismatched types
+}
+
+fn bar<const N: u8>() -> [u8; N] {}
+//~^ ERROR mismatched types
+//~| ERROR mismatched types
+
+fn main() {}
diff --git a/src/test/ui/const-generics/type_mismatch.stderr b/src/test/ui/const-generics/type_mismatch.stderr
new file mode 100644
index 00000000000..f5053e4c8c8
--- /dev/null
+++ b/src/test/ui/const-generics/type_mismatch.stderr
@@ -0,0 +1,23 @@
+error[E0308]: mismatched types
+  --> $DIR/type_mismatch.rs:2:11
+   |
+LL |     bar::<N>()
+   |           ^ expected `u8`, found `usize`
+
+error[E0308]: mismatched types
+  --> $DIR/type_mismatch.rs:5:31
+   |
+LL | fn bar<const N: u8>() -> [u8; N] {}
+   |                               ^ expected `usize`, found `u8`
+
+error[E0308]: mismatched types
+  --> $DIR/type_mismatch.rs:5:26
+   |
+LL | fn bar<const N: u8>() -> [u8; N] {}
+   |    ---                   ^^^^^^^ expected array `[u8; N]`, found `()`
+   |    |
+   |    implicitly returns `()` as its body has no tail or `return` expression
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/const-generics/type_not_in_scope.rs b/src/test/ui/const-generics/type_not_in_scope.rs
new file mode 100644
index 00000000000..5933701808b
--- /dev/null
+++ b/src/test/ui/const-generics/type_not_in_scope.rs
@@ -0,0 +1,11 @@
+impl X {
+    //~^ ERROR cannot find type
+    fn getn<const N: usize>() -> [u8; N] {
+        getn::<N>()
+    }
+}
+fn getn<const N: cfg_attr>() -> [u8; N] {}
+//~^ ERROR expected type, found built-in attribute `cfg_attr`
+//~| ERROR mismatched types
+
+fn main() {}
diff --git a/src/test/ui/const-generics/type_not_in_scope.stderr b/src/test/ui/const-generics/type_not_in_scope.stderr
new file mode 100644
index 00000000000..16796acb3d2
--- /dev/null
+++ b/src/test/ui/const-generics/type_not_in_scope.stderr
@@ -0,0 +1,24 @@
+error[E0412]: cannot find type `X` in this scope
+  --> $DIR/type_not_in_scope.rs:1:6
+   |
+LL | impl X {
+   |      ^ not found in this scope
+
+error[E0573]: expected type, found built-in attribute `cfg_attr`
+  --> $DIR/type_not_in_scope.rs:7:18
+   |
+LL | fn getn<const N: cfg_attr>() -> [u8; N] {}
+   |                  ^^^^^^^^ not a type
+
+error[E0308]: mismatched types
+  --> $DIR/type_not_in_scope.rs:7:33
+   |
+LL | fn getn<const N: cfg_attr>() -> [u8; N] {}
+   |    ----                         ^^^^^^^ expected array `[u8; N]`, found `()`
+   |    |
+   |    implicitly returns `()` as its body has no tail or `return` expression
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0308, E0412, E0573.
+For more information about an error, try `rustc --explain E0308`.