about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2020-10-02 22:47:35 +0000
committerbors <bors@rust-lang.org>2020-10-02 22:47:35 +0000
commit6ebad43c255e63ac0734646fe817de5780d76b45 (patch)
tree807dbc3a528785d6119b683c2a511bbc2f9629f9
parent8876ffc9235dade728e1fbc4be4c85415fdd0bcd (diff)
parenteff63980142872227dcd66bf429f7337b1b68c31 (diff)
downloadrust-6ebad43c255e63ac0734646fe817de5780d76b45.tar.gz
rust-6ebad43c255e63ac0734646fe817de5780d76b45.zip
Auto merge of #77470 - jonas-schievink:rollup-9a2hulp, r=jonas-schievink
Rollup of 8 pull requests

Successful merges:

 - #75377 (Fix Debug implementations of some of the HashMap and BTreeMap iterator types)
 - #76107 (Write manifest for MAJOR.MINOR channel to enable rustup convenience)
 - #76745 (Move Wrapping<T> ui tests into library)
 - #77182 (Add missing examples for Fd traits)
 - #77251 (Bypass const_item_mutation if const's type has Drop impl)
 - #77264 (Only use LOCAL_{STDOUT,STDERR} when set_{print/panic} is used. )
 - #77421 (Revert "resolve: Avoid "self-confirming" import resolutions in one more case")
 - #77452 (Permit ty::Bool in const generics for v0 mangling)

Failed merges:

r? `@ghost`
-rw-r--r--compiler/rustc_mir/src/transform/check_const_item_mutation.rs31
-rw-r--r--compiler/rustc_resolve/src/imports.rs13
-rw-r--r--compiler/rustc_symbol_mangling/src/v0.rs1
-rw-r--r--library/alloc/src/collections/btree/map.rs58
-rw-r--r--library/core/tests/num/wrapping.rs76
-rw-r--r--library/std/src/collections/hash/map.rs12
-rw-r--r--library/std/src/io/stdio.rs83
-rw-r--r--library/std/src/lib.rs1
-rw-r--r--library/std/src/sys/unix/ext/io.rs40
-rw-r--r--src/test/ui/imports/issue-62767.rs23
-rw-r--r--src/test/ui/imports/issue-62767.stderr21
-rw-r--r--src/test/ui/lint/lint-const-item-mutation.rs21
-rw-r--r--src/test/ui/lint/lint-const-item-mutation.stderr64
-rw-r--r--src/test/ui/symbol-names/issue-76365.rs18
-rw-r--r--src/test/ui/wrapping-int-combinations.rs77
-rw-r--r--src/tools/build-manifest/src/main.rs4
16 files changed, 398 insertions, 145 deletions
diff --git a/compiler/rustc_mir/src/transform/check_const_item_mutation.rs b/compiler/rustc_mir/src/transform/check_const_item_mutation.rs
index 0281c478a6c..b6d57b899dd 100644
--- a/compiler/rustc_mir/src/transform/check_const_item_mutation.rs
+++ b/compiler/rustc_mir/src/transform/check_const_item_mutation.rs
@@ -31,6 +31,35 @@ impl<'a, 'tcx> ConstMutationChecker<'a, 'tcx> {
             None
         }
     }
+
+    fn is_const_item_without_destructor(&self, local: Local) -> Option<DefId> {
+        let def_id = self.is_const_item(local)?;
+        let mut any_dtor = |_tcx, _def_id| Ok(());
+
+        // We avoid linting mutation of a const item if the const's type has a
+        // Drop impl. The Drop logic observes the mutation which was performed.
+        //
+        //     pub struct Log { msg: &'static str }
+        //     pub const LOG: Log = Log { msg: "" };
+        //     impl Drop for Log {
+        //         fn drop(&mut self) { println!("{}", self.msg); }
+        //     }
+        //
+        //     LOG.msg = "wow";  // prints "wow"
+        //
+        // FIXME(https://github.com/rust-lang/rust/issues/77425):
+        // Drop this exception once there is a stable attribute to suppress the
+        // const item mutation lint for a single specific const only. Something
+        // equivalent to:
+        //
+        //     #[const_mutation_allowed]
+        //     pub const LOG: Log = Log { msg: "" };
+        match self.tcx.calculate_dtor(def_id, &mut any_dtor) {
+            Some(_) => None,
+            None => Some(def_id),
+        }
+    }
+
     fn lint_const_item_usage(
         &self,
         const_item: DefId,
@@ -59,7 +88,7 @@ impl<'a, 'tcx> Visitor<'tcx> for ConstMutationChecker<'a, 'tcx> {
             // Assigning directly to a constant (e.g. `FOO = true;`) is a hard error,
             // so emitting a lint would be redundant.
             if !lhs.projection.is_empty() {
-                if let Some(def_id) = self.is_const_item(lhs.local) {
+                if let Some(def_id) = self.is_const_item_without_destructor(lhs.local) {
                     // Don't lint on writes through a pointer
                     // (e.g. `unsafe { *FOO = 0; *BAR.field = 1; }`)
                     if !matches!(lhs.projection.last(), Some(PlaceElem::Deref)) {
diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs
index bf8a2f269dd..adff4542b0f 100644
--- a/compiler/rustc_resolve/src/imports.rs
+++ b/compiler/rustc_resolve/src/imports.rs
@@ -875,12 +875,6 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
     /// consolidate multiple unresolved import errors into a single diagnostic.
     fn finalize_import(&mut self, import: &'b Import<'b>) -> Option<UnresolvedImportError> {
         let orig_vis = import.vis.replace(ty::Visibility::Invisible);
-        let orig_unusable_binding = match &import.kind {
-            ImportKind::Single { target_bindings, .. } => {
-                Some(mem::replace(&mut self.r.unusable_binding, target_bindings[TypeNS].get()))
-            }
-            _ => None,
-        };
         let prev_ambiguity_errors_len = self.r.ambiguity_errors.len();
         let path_res = self.r.resolve_path(
             &import.module_path,
@@ -891,9 +885,6 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
             import.crate_lint(),
         );
         let no_ambiguity = self.r.ambiguity_errors.len() == prev_ambiguity_errors_len;
-        if let Some(orig_unusable_binding) = orig_unusable_binding {
-            self.r.unusable_binding = orig_unusable_binding;
-        }
         import.vis.set(orig_vis);
         if let PathResult::Failed { .. } | PathResult::NonModule(..) = path_res {
             // Consider erroneous imports used to avoid duplicate diagnostics.
@@ -904,7 +895,8 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
                 // Consistency checks, analogous to `finalize_macro_resolutions`.
                 if let Some(initial_module) = import.imported_module.get() {
                     if !ModuleOrUniformRoot::same_def(module, initial_module) && no_ambiguity {
-                        span_bug!(import.span, "inconsistent resolution for an import");
+                        let msg = "inconsistent resolution for an import";
+                        self.r.session.span_err(import.span, msg);
                     }
                 } else {
                     if self.r.privacy_errors.is_empty() {
@@ -926,7 +918,6 @@ impl<'a, 'b> ImportResolver<'a, 'b> {
             }
             PathResult::Failed { is_error_from_last_segment: true, span, label, suggestion } => {
                 if no_ambiguity {
-                    assert!(import.imported_module.get().is_none());
                     let err = match self.make_path_suggestion(
                         span,
                         import.module_path.clone(),
diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs
index 091d488138e..da9c93143bf 100644
--- a/compiler/rustc_symbol_mangling/src/v0.rs
+++ b/compiler/rustc_symbol_mangling/src/v0.rs
@@ -504,6 +504,7 @@ impl Printer<'tcx> for SymbolMangler<'tcx> {
 
         match ct.ty.kind() {
             ty::Uint(_) => {}
+            ty::Bool => {}
             _ => {
                 bug!("symbol_names: unsupported constant of type `{}` ({:?})", ct.ty, ct);
             }
diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs
index 3fb03a5412e..2b244a04d22 100644
--- a/library/alloc/src/collections/btree/map.rs
+++ b/library/alloc/src/collections/btree/map.rs
@@ -297,14 +297,23 @@ pub struct IntoIter<K, V> {
     length: usize,
 }
 
-#[stable(feature = "collection_debug", since = "1.17.0")]
-impl<K: fmt::Debug, V: fmt::Debug> fmt::Debug for IntoIter<K, V> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+impl<K, V> IntoIter<K, V> {
+    /// Returns an iterator of references over the remaining items.
+    #[inline]
+    pub(super) fn iter(&self) -> Iter<'_, K, V> {
         let range = Range {
             front: self.front.as_ref().map(|f| f.reborrow()),
             back: self.back.as_ref().map(|b| b.reborrow()),
         };
-        f.debug_list().entries(range).finish()
+
+        Iter { range: range, length: self.length }
+    }
+}
+
+#[stable(feature = "collection_debug", since = "1.17.0")]
+impl<K: fmt::Debug, V: fmt::Debug> fmt::Debug for IntoIter<K, V> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_list().entries(self.iter()).finish()
     }
 }
 
@@ -351,11 +360,17 @@ impl<K, V: fmt::Debug> fmt::Debug for Values<'_, K, V> {
 ///
 /// [`values_mut`]: BTreeMap::values_mut
 #[stable(feature = "map_values_mut", since = "1.10.0")]
-#[derive(Debug)]
 pub struct ValuesMut<'a, K: 'a, V: 'a> {
     inner: IterMut<'a, K, V>,
 }
 
+#[stable(feature = "map_values_mut", since = "1.10.0")]
+impl<K, V: fmt::Debug> fmt::Debug for ValuesMut<'_, K, V> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_list().entries(self.inner.iter().map(|(_, val)| val)).finish()
+    }
+}
+
 /// An owning iterator over the keys of a `BTreeMap`.
 ///
 /// This `struct` is created by the [`into_keys`] method on [`BTreeMap`].
@@ -363,11 +378,17 @@ pub struct ValuesMut<'a, K: 'a, V: 'a> {
 ///
 /// [`into_keys`]: BTreeMap::into_keys
 #[unstable(feature = "map_into_keys_values", issue = "75294")]
-#[derive(Debug)]
 pub struct IntoKeys<K, V> {
     inner: IntoIter<K, V>,
 }
 
+#[unstable(feature = "map_into_keys_values", issue = "75294")]
+impl<K: fmt::Debug, V> fmt::Debug for IntoKeys<K, V> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_list().entries(self.inner.iter().map(|(key, _)| key)).finish()
+    }
+}
+
 /// An owning iterator over the values of a `BTreeMap`.
 ///
 /// This `struct` is created by the [`into_values`] method on [`BTreeMap`].
@@ -375,11 +396,17 @@ pub struct IntoKeys<K, V> {
 ///
 /// [`into_values`]: BTreeMap::into_values
 #[unstable(feature = "map_into_keys_values", issue = "75294")]
-#[derive(Debug)]
 pub struct IntoValues<K, V> {
     inner: IntoIter<K, V>,
 }
 
+#[unstable(feature = "map_into_keys_values", issue = "75294")]
+impl<K, V: fmt::Debug> fmt::Debug for IntoValues<K, V> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.debug_list().entries(self.inner.iter().map(|(_, val)| val)).finish()
+    }
+}
+
 /// An iterator over a sub-range of entries in a `BTreeMap`.
 ///
 /// This `struct` is created by the [`range`] method on [`BTreeMap`]. See its
@@ -1465,6 +1492,14 @@ impl<K, V> ExactSizeIterator for IterMut<'_, K, V> {
 #[stable(feature = "fused", since = "1.26.0")]
 impl<K, V> FusedIterator for IterMut<'_, K, V> {}
 
+impl<'a, K, V> IterMut<'a, K, V> {
+    /// Returns an iterator of references over the remaining items.
+    #[inline]
+    pub(super) fn iter(&self) -> Iter<'_, K, V> {
+        Iter { range: self.range.iter(), length: self.length }
+    }
+}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<K, V> IntoIterator for BTreeMap<K, V> {
     type Item = (K, V);
@@ -1949,6 +1984,15 @@ impl<'a, K, V> RangeMut<'a, K, V> {
     unsafe fn next_unchecked(&mut self) -> (&'a K, &'a mut V) {
         unsafe { unwrap_unchecked(self.front.as_mut()).next_unchecked() }
     }
+
+    /// Returns an iterator of references over the remaining items.
+    #[inline]
+    pub(super) fn iter(&self) -> Range<'_, K, V> {
+        Range {
+            front: self.front.as_ref().map(|f| f.reborrow()),
+            back: self.back.as_ref().map(|b| b.reborrow()),
+        }
+    }
 }
 
 #[stable(feature = "btree_range", since = "1.17.0")]
diff --git a/library/core/tests/num/wrapping.rs b/library/core/tests/num/wrapping.rs
new file mode 100644
index 00000000000..5d4ecb2669a
--- /dev/null
+++ b/library/core/tests/num/wrapping.rs
@@ -0,0 +1,76 @@
+use core::num::Wrapping;
+
+macro_rules! wrapping_operation {
+    ($result:expr, $lhs:ident $op:tt $rhs:expr) => {
+        assert_eq!($result, $lhs $op $rhs);
+        assert_eq!($result, &$lhs $op $rhs);
+        assert_eq!($result, $lhs $op &$rhs);
+        assert_eq!($result, &$lhs $op &$rhs);
+    };
+    ($result:expr, $op:tt $expr:expr) => {
+        assert_eq!($result, $op $expr);
+        assert_eq!($result, $op &$expr);
+    };
+}
+
+macro_rules! wrapping_assignment {
+    ($result:expr, $lhs:ident $op:tt $rhs:expr) => {
+        let mut lhs1 = $lhs;
+        lhs1 $op $rhs;
+        assert_eq!($result, lhs1);
+
+        let mut lhs2 = $lhs;
+        lhs2 $op &$rhs;
+        assert_eq!($result, lhs2);
+    };
+}
+
+macro_rules! wrapping_test {
+    ($type:ty, $min:expr, $max:expr) => {
+        #[test]
+        fn wrapping_$type() {
+            let zero: Wrapping<$type> = Wrapping(0);
+            let one: Wrapping<$type> = Wrapping(1);
+            let min: Wrapping<$type> = Wrapping($min);
+            let max: Wrapping<$type> = Wrapping($max);
+
+            wrapping_operation!(min, max + one);
+            wrapping_assignment!(min, max += one);
+            wrapping_operation!(max, min - one);
+            wrapping_assignment!(max, min -= one);
+            wrapping_operation!(max, max * one);
+            wrapping_assignment!(max, max *= one);
+            wrapping_operation!(max, max / one);
+            wrapping_assignment!(max, max /= one);
+            wrapping_operation!(zero, max % one);
+            wrapping_assignment!(zero, max %= one);
+            wrapping_operation!(zero, zero & max);
+            wrapping_assignment!(zero, zero &= max);
+            wrapping_operation!(max, zero | max);
+            wrapping_assignment!(max, zero |= max);
+            wrapping_operation!(zero, max ^ max);
+            wrapping_assignment!(zero, max ^= max);
+            wrapping_operation!(zero, zero << 1usize);
+            wrapping_assignment!(zero, zero <<= 1usize);
+            wrapping_operation!(zero, zero >> 1usize);
+            wrapping_assignment!(zero, zero >>= 1usize);
+            wrapping_operation!(zero, -zero);
+            wrapping_operation!(max, !min);
+        }
+    };
+}
+
+wrapping_test!(i8, i8::MIN, i8::MAX);
+wrapping_test!(i16, i16::MIN, i16::MAX);
+wrapping_test!(i32, i32::MIN, i32::MAX);
+wrapping_test!(i64, i64::MIN, i64::MAX);
+#[cfg(not(target_os = "emscripten"))]
+wrapping_test!(i128, i128::MIN, i128::MAX);
+wrapping_test!(isize, isize::MIN, isize::MAX);
+wrapping_test!(u8, u8::MIN, u8::MAX);
+wrapping_test!(u16, u16::MIN, u16::MAX);
+wrapping_test!(u32, u32::MIN, u32::MAX);
+wrapping_test!(u64, u64::MIN, u64::MAX);
+#[cfg(not(target_os = "emscripten"))]
+wrapping_test!(u128, u128::MIN, u128::MAX);
+wrapping_test!(usize, usize::MIN, usize::MAX);
diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs
index 4424a4c1992..f12cefffbf6 100644
--- a/library/std/src/collections/hash/map.rs
+++ b/library/std/src/collections/hash/map.rs
@@ -2042,13 +2042,9 @@ impl<K, V> ExactSizeIterator for ValuesMut<'_, K, V> {
 impl<K, V> FusedIterator for ValuesMut<'_, K, V> {}
 
 #[stable(feature = "std_debug", since = "1.16.0")]
-impl<K, V> fmt::Debug for ValuesMut<'_, K, V>
-where
-    K: fmt::Debug,
-    V: fmt::Debug,
-{
+impl<K, V: fmt::Debug> fmt::Debug for ValuesMut<'_, K, V> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.debug_list().entries(self.inner.iter()).finish()
+        f.debug_list().entries(self.inner.iter().map(|(_, val)| val)).finish()
     }
 }
 
@@ -2076,7 +2072,7 @@ impl<K, V> ExactSizeIterator for IntoKeys<K, V> {
 impl<K, V> FusedIterator for IntoKeys<K, V> {}
 
 #[unstable(feature = "map_into_keys_values", issue = "75294")]
-impl<K: Debug, V: Debug> fmt::Debug for IntoKeys<K, V> {
+impl<K: Debug, V> fmt::Debug for IntoKeys<K, V> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         f.debug_list().entries(self.inner.iter().map(|(k, _)| k)).finish()
     }
@@ -2106,7 +2102,7 @@ impl<K, V> ExactSizeIterator for IntoValues<K, V> {
 impl<K, V> FusedIterator for IntoValues<K, V> {}
 
 #[unstable(feature = "map_into_keys_values", issue = "75294")]
-impl<K: Debug, V: Debug> fmt::Debug for IntoValues<K, V> {
+impl<K, V: Debug> fmt::Debug for IntoValues<K, V> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         f.debug_list().entries(self.inner.iter().map(|(_, v)| v)).finish()
     }
diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs
index 61ccc6f13c8..36b49401591 100644
--- a/library/std/src/io/stdio.rs
+++ b/library/std/src/io/stdio.rs
@@ -9,6 +9,7 @@ use crate::cell::RefCell;
 use crate::fmt;
 use crate::io::{self, BufReader, Initializer, IoSlice, IoSliceMut, LineWriter};
 use crate::lazy::SyncOnceCell;
+use crate::sync::atomic::{AtomicBool, Ordering};
 use crate::sync::{Mutex, MutexGuard};
 use crate::sys::stdio;
 use crate::sys_common;
@@ -16,19 +17,33 @@ use crate::sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard};
 use crate::thread::LocalKey;
 
 thread_local! {
-    /// Stdout used by print! and println! macros
+    /// Used by the test crate to capture the output of the print! and println! macros.
     static LOCAL_STDOUT: RefCell<Option<Box<dyn Write + Send>>> = {
         RefCell::new(None)
     }
 }
 
 thread_local! {
-    /// Stderr used by eprint! and eprintln! macros, and panics
+    /// Used by the test crate to capture the output of the eprint! and eprintln! macros, and panics.
     static LOCAL_STDERR: RefCell<Option<Box<dyn Write + Send>>> = {
         RefCell::new(None)
     }
 }
 
+/// Flag to indicate LOCAL_STDOUT and/or LOCAL_STDERR is used.
+///
+/// If both are None and were never set on any thread, this flag is set to
+/// false, and both LOCAL_STDOUT and LOCAL_STDOUT can be safely ignored on all
+/// threads, saving some time and memory registering an unused thread local.
+///
+/// Note about memory ordering: This contains information about whether two
+/// thread local variables might be in use. Although this is a global flag, the
+/// memory ordering between threads does not matter: we only want this flag to
+/// have a consistent order between set_print/set_panic and print_to *within
+/// the same thread*. Within the same thread, things always have a perfectly
+/// consistent order. So Ordering::Relaxed is fine.
+static LOCAL_STREAMS: AtomicBool = AtomicBool::new(false);
+
 /// A handle to a raw instance of the standard input stream of this process.
 ///
 /// This handle is not synchronized or buffered in any fashion. Constructed via
@@ -890,10 +905,18 @@ impl fmt::Debug for StderrLock<'_> {
 #[doc(hidden)]
 pub fn set_panic(sink: Option<Box<dyn Write + Send>>) -> Option<Box<dyn Write + Send>> {
     use crate::mem;
-    LOCAL_STDERR.with(move |slot| mem::replace(&mut *slot.borrow_mut(), sink)).and_then(|mut s| {
-        let _ = s.flush();
-        Some(s)
-    })
+    if sink.is_none() && !LOCAL_STREAMS.load(Ordering::Relaxed) {
+        // LOCAL_STDERR is definitely None since LOCAL_STREAMS is false.
+        return None;
+    }
+    let s = LOCAL_STDERR.with(move |slot| mem::replace(&mut *slot.borrow_mut(), sink)).and_then(
+        |mut s| {
+            let _ = s.flush();
+            Some(s)
+        },
+    );
+    LOCAL_STREAMS.store(true, Ordering::Relaxed);
+    s
 }
 
 /// Resets the thread-local stdout handle to the specified writer
@@ -913,10 +936,18 @@ pub fn set_panic(sink: Option<Box<dyn Write + Send>>) -> Option<Box<dyn Write +
 #[doc(hidden)]
 pub fn set_print(sink: Option<Box<dyn Write + Send>>) -> Option<Box<dyn Write + Send>> {
     use crate::mem;
-    LOCAL_STDOUT.with(move |slot| mem::replace(&mut *slot.borrow_mut(), sink)).and_then(|mut s| {
-        let _ = s.flush();
-        Some(s)
-    })
+    if sink.is_none() && !LOCAL_STREAMS.load(Ordering::Relaxed) {
+        // LOCAL_STDOUT is definitely None since LOCAL_STREAMS is false.
+        return None;
+    }
+    let s = LOCAL_STDOUT.with(move |slot| mem::replace(&mut *slot.borrow_mut(), sink)).and_then(
+        |mut s| {
+            let _ = s.flush();
+            Some(s)
+        },
+    );
+    LOCAL_STREAMS.store(true, Ordering::Relaxed);
+    s
 }
 
 /// Write `args` to output stream `local_s` if possible, `global_s`
@@ -937,20 +968,26 @@ fn print_to<T>(
 ) where
     T: Write,
 {
-    let result = local_s
-        .try_with(|s| {
-            // Note that we completely remove a local sink to write to in case
-            // our printing recursively panics/prints, so the recursive
-            // panic/print goes to the global sink instead of our local sink.
-            let prev = s.borrow_mut().take();
-            if let Some(mut w) = prev {
-                let result = w.write_fmt(args);
-                *s.borrow_mut() = Some(w);
-                return result;
-            }
-            global_s().write_fmt(args)
+    let result = LOCAL_STREAMS
+        .load(Ordering::Relaxed)
+        .then(|| {
+            local_s
+                .try_with(|s| {
+                    // Note that we completely remove a local sink to write to in case
+                    // our printing recursively panics/prints, so the recursive
+                    // panic/print goes to the global sink instead of our local sink.
+                    let prev = s.borrow_mut().take();
+                    if let Some(mut w) = prev {
+                        let result = w.write_fmt(args);
+                        *s.borrow_mut() = Some(w);
+                        return result;
+                    }
+                    global_s().write_fmt(args)
+                })
+                .ok()
         })
-        .unwrap_or_else(|_| global_s().write_fmt(args));
+        .flatten()
+        .unwrap_or_else(|| global_s().write_fmt(args));
 
     if let Err(e) = result {
         panic!("failed printing to {}: {}", label, e);
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index e343eef9112..b2bd5f4da50 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -226,6 +226,7 @@
 #![feature(asm)]
 #![feature(associated_type_bounds)]
 #![feature(atomic_mut_ptr)]
+#![feature(bool_to_option)]
 #![feature(box_syntax)]
 #![feature(c_variadic)]
 #![feature(cfg_accessible)]
diff --git a/library/std/src/sys/unix/ext/io.rs b/library/std/src/sys/unix/ext/io.rs
index fbea1aa9f2a..ef3c689bd39 100644
--- a/library/std/src/sys/unix/ext/io.rs
+++ b/library/std/src/sys/unix/ext/io.rs
@@ -25,6 +25,19 @@ pub trait AsRawFd {
     /// This method does **not** pass ownership of the raw file descriptor
     /// to the caller. The descriptor is only guaranteed to be valid while
     /// the original object has not yet been destroyed.
+    ///
+    /// # Example
+    ///
+    /// ```no_run
+    /// use std::fs::File;
+    /// # use std::io;
+    /// use std::os::unix::io::{AsRawFd, RawFd};
+    ///
+    /// let mut f = File::open("foo.txt")?;
+    /// // Note that `raw_fd` is only valid as long as `f` exists.
+    /// let raw_fd: RawFd = f.as_raw_fd();
+    /// # Ok::<(), io::Error>(())
+    /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     fn as_raw_fd(&self) -> RawFd;
 }
@@ -45,6 +58,21 @@ pub trait FromRawFd {
     /// descriptor they are wrapping. Usage of this function could
     /// accidentally allow violating this contract which can cause memory
     /// unsafety in code that relies on it being true.
+    ///
+    /// # Example
+    ///
+    /// ```no_run
+    /// use std::fs::File;
+    /// # use std::io;
+    /// use std::os::unix::io::{FromRawFd, IntoRawFd, RawFd};
+    ///
+    /// let f = File::open("foo.txt")?;
+    /// let raw_fd: RawFd = f.into_raw_fd();
+    /// // SAFETY: no other functions should call `from_raw_fd`, so there
+    /// // is only one owner for the file descriptor.
+    /// let f = unsafe { File::from_raw_fd(raw_fd) };
+    /// # Ok::<(), io::Error>(())
+    /// ```
     #[stable(feature = "from_raw_os", since = "1.1.0")]
     unsafe fn from_raw_fd(fd: RawFd) -> Self;
 }
@@ -58,6 +86,18 @@ pub trait IntoRawFd {
     /// This function **transfers ownership** of the underlying file descriptor
     /// to the caller. Callers are then the unique owners of the file descriptor
     /// and must close the descriptor once it's no longer needed.
+    ///
+    /// # Example
+    ///
+    /// ```no_run
+    /// use std::fs::File;
+    /// # use std::io;
+    /// use std::os::unix::io::{IntoRawFd, RawFd};
+    ///
+    /// let f = File::open("foo.txt")?;
+    /// let raw_fd: RawFd = f.into_raw_fd();
+    /// # Ok::<(), io::Error>(())
+    /// ```
     #[stable(feature = "into_raw_os", since = "1.4.0")]
     fn into_raw_fd(self) -> RawFd;
 }
diff --git a/src/test/ui/imports/issue-62767.rs b/src/test/ui/imports/issue-62767.rs
index 984d3f0ca92..0e0f915ea53 100644
--- a/src/test/ui/imports/issue-62767.rs
+++ b/src/test/ui/imports/issue-62767.rs
@@ -1,5 +1,4 @@
-// check-pass
-
+// Minimized case from #62767.
 mod m {
     pub enum Same {
         Same,
@@ -8,8 +7,22 @@ mod m {
 
 use m::*;
 
-// The variant `Same` introduced by this import is not considered when resolving the prefix
-// `Same::` during import validation (issue #62767).
-use Same::Same;
+// The variant `Same` introduced by this import is also considered when resolving the prefix
+// `Same::` during import validation to avoid effects similar to time travel (#74556).
+use Same::Same; //~ ERROR unresolved import `Same`
+
+// Case from #74556.
+mod foo {
+    pub mod bar {
+        pub mod bar {
+            pub fn foobar() {}
+        }
+    }
+}
+
+use foo::*;
+use bar::bar; //~ ERROR unresolved import `bar::bar`
+              //~| ERROR inconsistent resolution for an import
+use bar::foobar;
 
 fn main() {}
diff --git a/src/test/ui/imports/issue-62767.stderr b/src/test/ui/imports/issue-62767.stderr
new file mode 100644
index 00000000000..a4334bda6dd
--- /dev/null
+++ b/src/test/ui/imports/issue-62767.stderr
@@ -0,0 +1,21 @@
+error: inconsistent resolution for an import
+  --> $DIR/issue-62767.rs:24:5
+   |
+LL | use bar::bar;
+   |     ^^^^^^^^
+
+error[E0432]: unresolved import `Same`
+  --> $DIR/issue-62767.rs:12:5
+   |
+LL | use Same::Same;
+   |     ^^^^ `Same` is a variant, not a module
+
+error[E0432]: unresolved import `bar::bar`
+  --> $DIR/issue-62767.rs:24:5
+   |
+LL | use bar::bar;
+   |     ^^^^^^^^ no `bar` in `foo::bar::bar`
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0432`.
diff --git a/src/test/ui/lint/lint-const-item-mutation.rs b/src/test/ui/lint/lint-const-item-mutation.rs
index 43371560e02..c49a13f1065 100644
--- a/src/test/ui/lint/lint-const-item-mutation.rs
+++ b/src/test/ui/lint/lint-const-item-mutation.rs
@@ -9,9 +9,26 @@ impl MyStruct {
     fn use_mut(&mut self) {}
 }
 
+struct Mutable {
+    msg: &'static str,
+}
+impl Drop for Mutable {
+    fn drop(&mut self) {
+        println!("{}", self.msg);
+    }
+}
+
+struct Mutable2 { // this one has drop glue but not a Drop impl
+    msg: &'static str,
+    other: String,
+}
+
 const ARRAY: [u8; 1] = [25];
 const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'], raw_ptr: 2 as *mut u8 };
 const RAW_PTR: *mut u8 = 1 as *mut u8;
+const MUTABLE: Mutable = Mutable { msg: "" };
+const MUTABLE2: Mutable2 = Mutable2 { msg: "", other: String::new() };
+const VEC: Vec<i32> = Vec::new();
 
 fn main() {
     ARRAY[0] = 5; //~ WARN attempting to modify
@@ -29,4 +46,8 @@ fn main() {
         *RAW_PTR = 0;
         *MY_STRUCT.raw_ptr = 0;
     }
+
+    MUTABLE.msg = "wow"; // no warning, because Drop observes the mutation
+    MUTABLE2.msg = "wow"; //~ WARN attempting to modify
+    VEC.push(0); //~ WARN taking a mutable reference to a `const` item
 }
diff --git a/src/test/ui/lint/lint-const-item-mutation.stderr b/src/test/ui/lint/lint-const-item-mutation.stderr
index c5a221128ff..11b5124b2d2 100644
--- a/src/test/ui/lint/lint-const-item-mutation.stderr
+++ b/src/test/ui/lint/lint-const-item-mutation.stderr
@@ -1,5 +1,5 @@
 warning: attempting to modify a `const` item
-  --> $DIR/lint-const-item-mutation.rs:17:5
+  --> $DIR/lint-const-item-mutation.rs:34:5
    |
 LL |     ARRAY[0] = 5;
    |     ^^^^^^^^^^^^
@@ -7,39 +7,39 @@ LL |     ARRAY[0] = 5;
    = note: `#[warn(const_item_mutation)]` on by default
    = note: each usage of a `const` item creates a new temporary - the original `const` item will not be modified
 note: `const` item defined here
-  --> $DIR/lint-const-item-mutation.rs:12:1
+  --> $DIR/lint-const-item-mutation.rs:26:1
    |
 LL | const ARRAY: [u8; 1] = [25];
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: attempting to modify a `const` item
-  --> $DIR/lint-const-item-mutation.rs:18:5
+  --> $DIR/lint-const-item-mutation.rs:35:5
    |
 LL |     MY_STRUCT.field = false;
    |     ^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: each usage of a `const` item creates a new temporary - the original `const` item will not be modified
 note: `const` item defined here
-  --> $DIR/lint-const-item-mutation.rs:13:1
+  --> $DIR/lint-const-item-mutation.rs:27:1
    |
 LL | const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'], raw_ptr: 2 as *mut u8 };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: attempting to modify a `const` item
-  --> $DIR/lint-const-item-mutation.rs:19:5
+  --> $DIR/lint-const-item-mutation.rs:36:5
    |
 LL |     MY_STRUCT.inner_array[0] = 'b';
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = note: each usage of a `const` item creates a new temporary - the original `const` item will not be modified
 note: `const` item defined here
-  --> $DIR/lint-const-item-mutation.rs:13:1
+  --> $DIR/lint-const-item-mutation.rs:27:1
    |
 LL | const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'], raw_ptr: 2 as *mut u8 };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: taking a mutable reference to a `const` item
-  --> $DIR/lint-const-item-mutation.rs:20:5
+  --> $DIR/lint-const-item-mutation.rs:37:5
    |
 LL |     MY_STRUCT.use_mut();
    |     ^^^^^^^^^^^^^^^^^^^
@@ -52,13 +52,13 @@ note: mutable reference created due to call to this method
 LL |     fn use_mut(&mut self) {}
    |     ^^^^^^^^^^^^^^^^^^^^^
 note: `const` item defined here
-  --> $DIR/lint-const-item-mutation.rs:13:1
+  --> $DIR/lint-const-item-mutation.rs:27:1
    |
 LL | const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'], raw_ptr: 2 as *mut u8 };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: taking a mutable reference to a `const` item
-  --> $DIR/lint-const-item-mutation.rs:21:5
+  --> $DIR/lint-const-item-mutation.rs:38:5
    |
 LL |     &mut MY_STRUCT;
    |     ^^^^^^^^^^^^^^
@@ -66,13 +66,13 @@ LL |     &mut MY_STRUCT;
    = note: each usage of a `const` item creates a new temporary
    = note: the mutable reference will refer to this temporary, not the original `const` item
 note: `const` item defined here
-  --> $DIR/lint-const-item-mutation.rs:13:1
+  --> $DIR/lint-const-item-mutation.rs:27:1
    |
 LL | const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'], raw_ptr: 2 as *mut u8 };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 warning: taking a mutable reference to a `const` item
-  --> $DIR/lint-const-item-mutation.rs:22:5
+  --> $DIR/lint-const-item-mutation.rs:39:5
    |
 LL |     (&mut MY_STRUCT).use_mut();
    |     ^^^^^^^^^^^^^^^^
@@ -80,10 +80,48 @@ LL |     (&mut MY_STRUCT).use_mut();
    = note: each usage of a `const` item creates a new temporary
    = note: the mutable reference will refer to this temporary, not the original `const` item
 note: `const` item defined here
-  --> $DIR/lint-const-item-mutation.rs:13:1
+  --> $DIR/lint-const-item-mutation.rs:27:1
    |
 LL | const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'], raw_ptr: 2 as *mut u8 };
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-warning: 6 warnings emitted
+warning: attempting to modify a `const` item
+  --> $DIR/lint-const-item-mutation.rs:51:5
+   |
+LL |     MUTABLE2.msg = "wow";
+   |     ^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: each usage of a `const` item creates a new temporary - the original `const` item will not be modified
+note: `const` item defined here
+  --> $DIR/lint-const-item-mutation.rs:30:1
+   |
+LL | const MUTABLE2: Mutable2 = Mutable2 { msg: "", other: String::new() };
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: taking a mutable reference to a `const` item
+  --> $DIR/lint-const-item-mutation.rs:52:5
+   |
+LL |     VEC.push(0);
+   |     ^^^^^^^^^^^
+   |
+   = note: each usage of a `const` item creates a new temporary
+   = note: the mutable reference will refer to this temporary, not the original `const` item
+note: mutable reference created due to call to this method
+  --> $SRC_DIR/alloc/src/vec.rs:LL:COL
+   |
+LL | /     pub fn push(&mut self, value: T) {
+LL | |         // This will panic or abort if we would allocate > isize::MAX bytes
+LL | |         // or if the length increment would overflow for zero-sized types.
+LL | |         if self.len == self.buf.capacity() {
+...  |
+LL | |         }
+LL | |     }
+   | |_____^
+note: `const` item defined here
+  --> $DIR/lint-const-item-mutation.rs:31:1
+   |
+LL | const VEC: Vec<i32> = Vec::new();
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: 8 warnings emitted
 
diff --git a/src/test/ui/symbol-names/issue-76365.rs b/src/test/ui/symbol-names/issue-76365.rs
new file mode 100644
index 00000000000..61ba255dac0
--- /dev/null
+++ b/src/test/ui/symbol-names/issue-76365.rs
@@ -0,0 +1,18 @@
+// check-pass
+// revisions: legacy v0
+//[legacy]compile-flags: -Z symbol-mangling-version=legacy --crate-type=lib
+    //[v0]compile-flags: -Z symbol-mangling-version=v0 --crate-type=lib
+
+#![feature(min_const_generics)]
+
+pub struct Bar<const F: bool>;
+
+impl Bar<true> {
+    pub fn foo() {}
+}
+
+impl<const F: bool> Bar<F> {
+    pub fn bar() {}
+}
+
+fn main() {}
diff --git a/src/test/ui/wrapping-int-combinations.rs b/src/test/ui/wrapping-int-combinations.rs
deleted file mode 100644
index f0bc479ee0f..00000000000
--- a/src/test/ui/wrapping-int-combinations.rs
+++ /dev/null
@@ -1,77 +0,0 @@
-// run-pass
-
-use std::num::Wrapping;
-
-macro_rules! wrapping_operation {
-    ($result:expr, $lhs:ident $op:tt $rhs:expr) => {
-        assert_eq!($result, $lhs $op $rhs);
-        assert_eq!($result, &$lhs $op $rhs);
-        assert_eq!($result, $lhs $op &$rhs);
-        assert_eq!($result, &$lhs $op &$rhs);
-    };
-    ($result:expr, $op:tt $expr:expr) => {
-        assert_eq!($result, $op $expr);
-        assert_eq!($result, $op &$expr);
-    };
-}
-
-macro_rules! wrapping_assignment {
-    ($result:expr, $lhs:ident $op:tt $rhs:expr) => {
-        let mut lhs1 = $lhs;
-        lhs1 $op $rhs;
-        assert_eq!($result, lhs1);
-
-        let mut lhs2 = $lhs;
-        lhs2 $op &$rhs;
-        assert_eq!($result, lhs2);
-    };
-}
-
-macro_rules! wrapping_test {
-    ($type:ty, $min:expr, $max:expr) => {
-        let zero: Wrapping<$type> = Wrapping(0);
-        let one: Wrapping<$type> = Wrapping(1);
-        let min: Wrapping<$type> = Wrapping($min);
-        let max: Wrapping<$type> = Wrapping($max);
-
-        wrapping_operation!(min, max + one);
-        wrapping_assignment!(min, max += one);
-        wrapping_operation!(max, min - one);
-        wrapping_assignment!(max, min -= one);
-        wrapping_operation!(max, max * one);
-        wrapping_assignment!(max, max *= one);
-        wrapping_operation!(max, max / one);
-        wrapping_assignment!(max, max /= one);
-        wrapping_operation!(zero, max % one);
-        wrapping_assignment!(zero, max %= one);
-        wrapping_operation!(zero, zero & max);
-        wrapping_assignment!(zero, zero &= max);
-        wrapping_operation!(max, zero | max);
-        wrapping_assignment!(max, zero |= max);
-        wrapping_operation!(zero, max ^ max);
-        wrapping_assignment!(zero, max ^= max);
-        wrapping_operation!(zero, zero << 1usize);
-        wrapping_assignment!(zero, zero <<= 1usize);
-        wrapping_operation!(zero, zero >> 1usize);
-        wrapping_assignment!(zero, zero >>= 1usize);
-        wrapping_operation!(zero, -zero);
-        wrapping_operation!(max, !min);
-    };
-}
-
-fn main() {
-    wrapping_test!(i8, std::i8::MIN, std::i8::MAX);
-    wrapping_test!(i16, std::i16::MIN, std::i16::MAX);
-    wrapping_test!(i32, std::i32::MIN, std::i32::MAX);
-    wrapping_test!(i64, std::i64::MIN, std::i64::MAX);
-    #[cfg(not(target_os = "emscripten"))]
-    wrapping_test!(i128, std::i128::MIN, std::i128::MAX);
-    wrapping_test!(isize, std::isize::MIN, std::isize::MAX);
-    wrapping_test!(u8, std::u8::MIN, std::u8::MAX);
-    wrapping_test!(u16, std::u16::MIN, std::u16::MAX);
-    wrapping_test!(u32, std::u32::MIN, std::u32::MAX);
-    wrapping_test!(u64, std::u64::MIN, std::u64::MAX);
-    #[cfg(not(target_os = "emscripten"))]
-    wrapping_test!(u128, std::u128::MIN, std::u128::MAX);
-    wrapping_test!(usize, std::usize::MIN, std::usize::MAX);
-}
diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs
index be3e862e7ae..e1dc9111bf3 100644
--- a/src/tools/build-manifest/src/main.rs
+++ b/src/tools/build-manifest/src/main.rs
@@ -294,6 +294,10 @@ impl Builder {
         if self.versions.channel() != rust_version {
             self.write_channel_files(&rust_version, &manifest);
         }
+        if self.versions.channel() == "stable" {
+            let major_minor = rust_version.split('.').take(2).collect::<Vec<_>>().join(".");
+            self.write_channel_files(&major_minor, &manifest);
+        }
     }
 
     /// If a tool does not pass its tests, don't ship it.