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 0281c478a6ca0..b6d57b899ddab 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 { + 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 bf8a2f269dd57..adff4542b0ff8 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 { 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 091d488138e46..da9c93143bfb3 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 3fb03a5412e4f..2b244a04d2223 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -297,14 +297,23 @@ pub struct IntoIter { length: usize, } -#[stable(feature = "collection_debug", since = "1.17.0")] -impl fmt::Debug for IntoIter { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +impl IntoIter { + /// 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 fmt::Debug for IntoIter { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.iter()).finish() } } @@ -351,11 +360,17 @@ impl 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 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 { inner: IntoIter, } +#[unstable(feature = "map_into_keys_values", issue = "75294")] +impl fmt::Debug for IntoKeys { + 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 { /// /// [`into_values`]: BTreeMap::into_values #[unstable(feature = "map_into_keys_values", issue = "75294")] -#[derive(Debug)] pub struct IntoValues { inner: IntoIter, } +#[unstable(feature = "map_into_keys_values", issue = "75294")] +impl fmt::Debug for IntoValues { + 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 ExactSizeIterator for IterMut<'_, K, V> { #[stable(feature = "fused", since = "1.26.0")] impl 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 IntoIterator for BTreeMap { 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 0000000000000..5d4ecb2669a96 --- /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 4424a4c199226..f12cefffbf662 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -2042,13 +2042,9 @@ impl ExactSizeIterator for ValuesMut<'_, K, V> { impl FusedIterator for ValuesMut<'_, K, V> {} #[stable(feature = "std_debug", since = "1.16.0")] -impl fmt::Debug for ValuesMut<'_, K, V> -where - K: fmt::Debug, - V: fmt::Debug, -{ +impl 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 ExactSizeIterator for IntoKeys { impl FusedIterator for IntoKeys {} #[unstable(feature = "map_into_keys_values", issue = "75294")] -impl fmt::Debug for IntoKeys { +impl fmt::Debug for IntoKeys { 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 ExactSizeIterator for IntoValues { impl FusedIterator for IntoValues {} #[unstable(feature = "map_into_keys_values", issue = "75294")] -impl fmt::Debug for IntoValues { +impl fmt::Debug for IntoValues { 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 61ccc6f13c8da..36b49401591f5 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>> = { 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>> = { 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>) -> Option> { 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>) -> Option>) -> Option> { 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( ) 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 e343eef91126e..b2bd5f4da5012 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 fbea1aa9f2abf..ef3c689bd3921 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 984d3f0ca92f4..0e0f915ea53c2 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 0000000000000..a4334bda6dd87 --- /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 43371560e02c1..c49a13f1065b5 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 = 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 c5a221128ffab..11b5124b2d26a 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 = 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 0000000000000..61ba255dac04d --- /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; + +impl Bar { + pub fn foo() {} +} + +impl Bar { + 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 f0bc479ee0ff2..0000000000000 --- 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 be3e862e7aecd..e1dc9111bf326 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::>().join("."); + self.write_channel_files(&major_minor, &manifest); + } } /// If a tool does not pass its tests, don't ship it.