diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 8262ae4cdbb86..c044020d9301b 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -1014,86 +1014,7 @@ fn print_native_static_libs(sess: &Session, all_native_libs: &[NativeLib]) { } } -// Because windows-gnu target is meant to be self-contained for pure Rust code it bundles -// own mingw-w64 libraries. These libraries are usually not compatible with mingw-w64 -// installed in the system. This breaks many cases where Rust is mixed with other languages -// (e.g. *-sys crates). -// We prefer system mingw-w64 libraries if they are available to avoid this issue. -fn get_crt_libs_path(sess: &Session) -> Option { - fn find_exe_in_path

(exe_name: P) -> Option - where - P: AsRef, - { - for dir in env::split_paths(&env::var_os("PATH")?) { - let full_path = dir.join(&exe_name); - if full_path.is_file() { - return Some(fix_windows_verbatim_for_gcc(&full_path)); - } - } - None - } - - fn probe(sess: &Session) -> Option { - if let (linker, LinkerFlavor::Gcc) = linker_and_flavor(&sess) { - let linker_path = if cfg!(windows) && linker.extension().is_none() { - linker.with_extension("exe") - } else { - linker - }; - if let Some(linker_path) = find_exe_in_path(linker_path) { - let mingw_arch = match &sess.target.target.arch { - x if x == "x86" => "i686", - x => x, - }; - let mingw_bits = &sess.target.target.target_pointer_width; - let mingw_dir = format!("{}-w64-mingw32", mingw_arch); - // Here we have path/bin/gcc but we need path/ - let mut path = linker_path; - path.pop(); - path.pop(); - // Loosely based on Clang MinGW driver - let probe_paths = vec![ - path.join(&mingw_dir).join("lib"), // Typical path - path.join(&mingw_dir).join("sys-root/mingw/lib"), // Rare path - path.join(format!( - "lib/mingw/tools/install/mingw{}/{}/lib", - &mingw_bits, &mingw_dir - )), // Chocolatey is creative - ]; - for probe_path in probe_paths { - if probe_path.join("crt2.o").exists() { - return Some(probe_path); - }; - } - }; - }; - None - } - - let mut system_library_path = sess.system_library_path.borrow_mut(); - match &*system_library_path { - Some(Some(compiler_libs_path)) => Some(compiler_libs_path.clone()), - Some(None) => None, - None => { - let path = probe(sess); - *system_library_path = Some(path.clone()); - path - } - } -} - fn get_object_file_path(sess: &Session, name: &str, self_contained: bool) -> PathBuf { - // prefer system {,dll}crt2.o libs, see get_crt_libs_path comment for more details - if sess.opts.cg.link_self_contained.is_none() - && sess.target.target.llvm_target.contains("windows-gnu") - { - if let Some(compiler_libs_path) = get_crt_libs_path(sess) { - let file_path = compiler_libs_path.join(name); - if file_path.exists() { - return file_path; - } - } - } let fs = sess.target_filesearch(PathKind::Native); let file_path = fs.get_lib_path().join(name); if file_path.exists() { @@ -1286,6 +1207,28 @@ fn link_output_kind(sess: &Session, crate_type: CrateType) -> LinkOutputKind { } } +// Returns true if linker is located within sysroot +fn detect_self_contained_mingw(sess: &Session) -> bool { + let (linker, _) = linker_and_flavor(&sess); + // Assume `-C linker=rust-lld` as self-contained mode + if linker == Path::new("rust-lld") { + return true; + } + let linker_with_extension = if cfg!(windows) && linker.extension().is_none() { + linker.with_extension("exe") + } else { + linker + }; + for dir in env::split_paths(&env::var_os("PATH").unwrap_or_default()) { + let full_path = dir.join(&linker_with_extension); + // If linker comes from sysroot assume self-contained mode + if full_path.is_file() && !full_path.starts_with(&sess.sysroot) { + return false; + } + } + true +} + /// Whether we link to our own CRT objects instead of relying on gcc to pull them. /// We only provide such support for a very limited number of targets. fn crt_objects_fallback(sess: &Session, crate_type: CrateType) -> bool { @@ -1298,10 +1241,10 @@ fn crt_objects_fallback(sess: &Session, crate_type: CrateType) -> bool { // based on host and linker path, for example. // (https://github.com/rust-lang/rust/pull/71769#issuecomment-626330237). Some(CrtObjectsFallback::Musl) => sess.crt_static(Some(crate_type)), - // FIXME: Find some heuristic for "native mingw toolchain is available", - // likely based on `get_crt_libs_path` (https://github.com/rust-lang/rust/pull/67429). Some(CrtObjectsFallback::Mingw) => { - sess.host == sess.target.target && sess.target.target.target_vendor != "uwp" + sess.host == sess.target.target + && sess.target.target.target_vendor != "uwp" + && detect_self_contained_mingw(&sess) } // FIXME: Figure out cases in which WASM needs to link with a native toolchain. Some(CrtObjectsFallback::Wasm) => true, @@ -1498,16 +1441,6 @@ fn link_local_crate_native_libs_and_dependent_crate_libs<'a, B: ArchiveBuilder<' /// Add sysroot and other globally set directories to the directory search list. fn add_library_search_dirs(cmd: &mut dyn Linker, sess: &Session, self_contained: bool) { - // Prefer system mingw-w64 libs, see get_crt_libs_path comment for more details. - if sess.opts.cg.link_self_contained.is_none() - && cfg!(windows) - && sess.target.target.llvm_target.contains("windows-gnu") - { - if let Some(compiler_libs_path) = get_crt_libs_path(sess) { - cmd.include_path(&compiler_libs_path); - } - } - // The default library location, we need this to find the runtime. // The location of crates will be determined as needed. let lib_path = sess.target_filesearch(PathKind::All).get_lib_path(); diff --git a/compiler/rustc_mir/src/transform/inline.rs b/compiler/rustc_mir/src/transform/inline.rs index 315d4fa9d477d..428f4e138c7f9 100644 --- a/compiler/rustc_mir/src/transform/inline.rs +++ b/compiler/rustc_mir/src/transform/inline.rs @@ -107,8 +107,14 @@ impl Inliner<'tcx> { // Avoid a cycle here by only using `optimized_mir` only if we have // a lower `HirId` than the callee. This ensures that the callee will // not inline us. This trick only works without incremental compilation. - // So don't do it if that is enabled. - if !self.tcx.dep_graph.is_fully_enabled() && self_hir_id < callee_hir_id { + // So don't do it if that is enabled. Also avoid inlining into generators, + // since their `optimized_mir` is used for layout computation, which can + // create a cycle, even when no attempt is made to inline the function + // in the other direction. + if !self.tcx.dep_graph.is_fully_enabled() + && self_hir_id < callee_hir_id + && caller_body.generator_kind.is_none() + { self.tcx.optimized_mir(callsite.callee) } else { continue; diff --git a/library/alloc/src/collections/vec_deque.rs b/library/alloc/src/collections/vec_deque.rs index a4c6ccd6cb0d4..52b9f73ba8825 100644 --- a/library/alloc/src/collections/vec_deque.rs +++ b/library/alloc/src/collections/vec_deque.rs @@ -685,7 +685,7 @@ impl VecDeque { } /// Tries to reserve the minimum capacity for exactly `additional` more elements to - /// be inserted in the given `VecDeque`. After calling `reserve_exact`, + /// be inserted in the given `VecDeque`. After calling `try_reserve_exact`, /// capacity will be greater than or equal to `self.len() + additional`. /// Does nothing if the capacity is already sufficient. /// @@ -727,7 +727,7 @@ impl VecDeque { /// Tries to reserve capacity for at least `additional` more elements to be inserted /// in the given `VecDeque`. The collection may reserve more space to avoid - /// frequent reallocations. After calling `reserve`, capacity will be + /// frequent reallocations. After calling `try_reserve`, capacity will be /// greater than or equal to `self.len() + additional`. Does nothing if /// capacity is already sufficient. /// diff --git a/library/alloc/src/vec.rs b/library/alloc/src/vec.rs index c86798a1bd3a5..27eefb0584216 100644 --- a/library/alloc/src/vec.rs +++ b/library/alloc/src/vec.rs @@ -523,7 +523,7 @@ impl Vec { /// Tries to reserve capacity for at least `additional` more elements to be inserted /// in the given `Vec`. The collection may reserve more space to avoid - /// frequent reallocations. After calling `reserve`, capacity will be + /// frequent reallocations. After calling `try_reserve`, capacity will be /// greater than or equal to `self.len() + additional`. Does nothing if /// capacity is already sufficient. /// @@ -559,7 +559,7 @@ impl Vec { } /// Tries to reserves the minimum capacity for exactly `additional` more elements to - /// be inserted in the given `Vec`. After calling `reserve_exact`, + /// be inserted in the given `Vec`. After calling `try_reserve_exact`, /// capacity will be greater than or equal to `self.len() + additional`. /// Does nothing if the capacity is already sufficient. /// @@ -582,7 +582,7 @@ impl Vec { /// let mut output = Vec::new(); /// /// // Pre-reserve the memory, exiting if we can't - /// output.try_reserve(data.len())?; + /// output.try_reserve_exact(data.len())?; /// /// // Now we know this can't OOM in the middle of our complex work /// output.extend(data.iter().map(|&val| { diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs index f85be5584e3f1..f45c99c285c84 100644 --- a/library/core/src/array/mod.rs +++ b/library/core/src/array/mod.rs @@ -422,4 +422,17 @@ impl [T; N] { // and we just need to cast it to the correct type. unsafe { crate::mem::transmute_copy::<_, [U; N]>(&dst) } } + + /// Returns a slice containing the entire array. Equivalent to `&s[..]`. + #[unstable(feature = "array_methods", issue = "76118")] + pub fn as_slice(&self) -> &[T] { + self + } + + /// Returns a mutable slice containing the entire array. Equivalent to + /// `&mut s[..]`. + #[unstable(feature = "array_methods", issue = "76118")] + pub fn as_mut_slice(&mut self) -> &mut [T] { + self + } } diff --git a/library/core/src/iter/adapters/mod.rs b/library/core/src/iter/adapters/mod.rs index 9fcd137e1a634..f32c3963abea2 100644 --- a/library/core/src/iter/adapters/mod.rs +++ b/library/core/src/iter/adapters/mod.rs @@ -1,9 +1,9 @@ use crate::cmp; use crate::fmt; use crate::intrinsics; -use crate::ops::{Add, AddAssign, Try}; +use crate::ops::{Add, AddAssign, ControlFlow, Try}; -use super::{from_fn, LoopState}; +use super::from_fn; use super::{DoubleEndedIterator, ExactSizeIterator, FusedIterator, Iterator, TrustedLen}; mod chain; @@ -1164,10 +1164,10 @@ where #[inline] fn find( f: &mut impl FnMut(T) -> Option, - ) -> impl FnMut((), T) -> LoopState<(), B> + '_ { + ) -> impl FnMut((), T) -> ControlFlow<(), B> + '_ { move |(), x| match f(x) { - Some(x) => LoopState::Break(x), - None => LoopState::Continue(()), + Some(x) => ControlFlow::Break(x), + None => ControlFlow::Continue(()), } } @@ -1864,13 +1864,13 @@ where flag: &'a mut bool, p: &'a mut impl FnMut(&T) -> bool, mut fold: impl FnMut(Acc, T) -> R + 'a, - ) -> impl FnMut(Acc, T) -> LoopState + 'a { + ) -> impl FnMut(Acc, T) -> ControlFlow + 'a { move |acc, x| { if p(&x) { - LoopState::from_try(fold(acc, x)) + ControlFlow::from_try(fold(acc, x)) } else { *flag = true; - LoopState::Break(Try::from_ok(acc)) + ControlFlow::Break(Try::from_ok(acc)) } } } @@ -1963,8 +1963,8 @@ where { let Self { iter, predicate } = self; iter.try_fold(init, |acc, x| match predicate(x) { - Some(item) => LoopState::from_try(fold(acc, item)), - None => LoopState::Break(Try::from_ok(acc)), + Some(item) => ControlFlow::from_try(fold(acc, item)), + None => ControlFlow::Break(Try::from_ok(acc)), }) .into_try() } @@ -2135,11 +2135,11 @@ where fn check>( mut n: usize, mut fold: impl FnMut(Acc, T) -> R, - ) -> impl FnMut(Acc, T) -> LoopState { + ) -> impl FnMut(Acc, T) -> ControlFlow { move |acc, x| { n -= 1; let r = fold(acc, x); - if n == 0 { LoopState::Break(r) } else { LoopState::from_try(r) } + if n == 0 { ControlFlow::Break(r) } else { ControlFlow::from_try(r) } } } @@ -2246,11 +2246,11 @@ where fn check<'a, T, Acc, R: Try>( n: &'a mut usize, mut fold: impl FnMut(Acc, T) -> R + 'a, - ) -> impl FnMut(Acc, T) -> LoopState + 'a { + ) -> impl FnMut(Acc, T) -> ControlFlow + 'a { move |acc, x| { *n -= 1; let r = fold(acc, x); - if *n == 0 { LoopState::Break(r) } else { LoopState::from_try(r) } + if *n == 0 { ControlFlow::Break(r) } else { ControlFlow::from_try(r) } } } @@ -2414,10 +2414,10 @@ where state: &'a mut St, f: &'a mut impl FnMut(&mut St, T) -> Option, mut fold: impl FnMut(Acc, B) -> R + 'a, - ) -> impl FnMut(Acc, T) -> LoopState + 'a { + ) -> impl FnMut(Acc, T) -> ControlFlow + 'a { move |acc, x| match f(state, x) { - None => LoopState::Break(Try::from_ok(acc)), - Some(x) => LoopState::from_try(fold(acc, x)), + None => ControlFlow::Break(Try::from_ok(acc)), + Some(x) => ControlFlow::from_try(fold(acc, x)), } } @@ -2638,10 +2638,10 @@ where let error = &mut *self.error; self.iter .try_fold(init, |acc, x| match x { - Ok(x) => LoopState::from_try(f(acc, x)), + Ok(x) => ControlFlow::from_try(f(acc, x)), Err(e) => { *error = Err(e); - LoopState::Break(Try::from_ok(acc)) + ControlFlow::Break(Try::from_ok(acc)) } }) .into_try() diff --git a/library/core/src/iter/mod.rs b/library/core/src/iter/mod.rs index 1be9c4de91687..bab8dda2915d9 100644 --- a/library/core/src/iter/mod.rs +++ b/library/core/src/iter/mod.rs @@ -308,8 +308,6 @@ #![stable(feature = "rust1", since = "1.0.0")] -use crate::ops::Try; - #[stable(feature = "rust1", since = "1.0.0")] pub use self::traits::Iterator; @@ -367,57 +365,3 @@ mod adapters; mod range; mod sources; mod traits; - -/// Used to make try_fold closures more like normal loops -#[derive(PartialEq)] -enum LoopState { - Continue(C), - Break(B), -} - -impl Try for LoopState { - type Ok = C; - type Error = B; - #[inline] - fn into_result(self) -> Result { - match self { - LoopState::Continue(y) => Ok(y), - LoopState::Break(x) => Err(x), - } - } - #[inline] - fn from_error(v: Self::Error) -> Self { - LoopState::Break(v) - } - #[inline] - fn from_ok(v: Self::Ok) -> Self { - LoopState::Continue(v) - } -} - -impl LoopState { - #[inline] - fn break_value(self) -> Option { - match self { - LoopState::Continue(..) => None, - LoopState::Break(x) => Some(x), - } - } -} - -impl LoopState { - #[inline] - fn from_try(r: R) -> Self { - match Try::into_result(r) { - Ok(v) => LoopState::Continue(v), - Err(v) => LoopState::Break(Try::from_error(v)), - } - } - #[inline] - fn into_try(self) -> R { - match self { - LoopState::Continue(v) => Try::from_ok(v), - LoopState::Break(v) => v, - } - } -} diff --git a/library/core/src/iter/traits/double_ended.rs b/library/core/src/iter/traits/double_ended.rs index 851a1e49a493b..25230519f3744 100644 --- a/library/core/src/iter/traits/double_ended.rs +++ b/library/core/src/iter/traits/double_ended.rs @@ -1,5 +1,4 @@ -use crate::iter::LoopState; -use crate::ops::Try; +use crate::ops::{ControlFlow, Try}; /// An iterator able to yield elements from both ends. /// @@ -309,9 +308,9 @@ pub trait DoubleEndedIterator: Iterator { #[inline] fn check( mut predicate: impl FnMut(&T) -> bool, - ) -> impl FnMut((), T) -> LoopState<(), T> { + ) -> impl FnMut((), T) -> ControlFlow<(), T> { move |(), x| { - if predicate(&x) { LoopState::Break(x) } else { LoopState::Continue(()) } + if predicate(&x) { ControlFlow::Break(x) } else { ControlFlow::Continue(()) } } } diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 0bac21406bf4e..46ef12cd938b3 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -3,9 +3,8 @@ // can't split that into multiple files. use crate::cmp::{self, Ordering}; -use crate::ops::{Add, Try}; +use crate::ops::{Add, ControlFlow, Try}; -use super::super::LoopState; use super::super::TrustedRandomAccess; use super::super::{Chain, Cloned, Copied, Cycle, Enumerate, Filter, FilterMap, Fuse}; use super::super::{FlatMap, Flatten}; @@ -22,8 +21,8 @@ fn _assert_is_object_safe(_: &dyn Iterator) {} /// generally, please see the [module-level documentation]. In particular, you /// may want to know how to [implement `Iterator`][impl]. /// -/// [module-level documentation]: index.html -/// [impl]: index.html#implementing-iterator +/// [module-level documentation]: crate::iter +/// [impl]: crate::iter#implementing-iterator #[stable(feature = "rust1", since = "1.0.0")] #[rustc_on_unimplemented( on( @@ -212,7 +211,7 @@ pub trait Iterator { /// returning the number of times it saw [`Some`]. Note that [`next`] has to be /// called at least once even if the iterator does not have any elements. /// - /// [`next`]: #tymethod.next + /// [`next`]: Iterator::next /// /// # Overflow Behavior /// @@ -449,9 +448,7 @@ pub trait Iterator { /// } /// ``` /// - /// [`once`]: fn.once.html - /// [`Iterator`]: trait.Iterator.html - /// [`IntoIterator`]: trait.IntoIterator.html + /// [`once`]: crate::iter::once /// [`OsStr`]: ../../std/ffi/struct.OsStr.html #[inline] #[stable(feature = "rust1", since = "1.0.0")] @@ -496,9 +493,6 @@ pub trait Iterator { /// [`Iterator`] itself. For example, slices (`&[T]`) implement /// [`IntoIterator`], and so can be passed to `zip()` directly: /// - /// [`IntoIterator`]: trait.IntoIterator.html - /// [`Iterator`]: trait.Iterator.html - /// /// ``` /// let s1 = &[1, 2, 3]; /// let s2 = &[4, 5, 6]; @@ -530,8 +524,8 @@ pub trait Iterator { /// assert_eq!((2, 'o'), zipper[2]); /// ``` /// - /// [`enumerate`]: #method.enumerate - /// [`next`]: #tymethod.next + /// [`enumerate`]: Iterator::enumerate + /// [`next`]: Iterator::next #[inline] #[stable(feature = "rust1", since = "1.0.0")] fn zip(self, other: U) -> Zip @@ -734,8 +728,8 @@ pub trait Iterator { /// Why `filter_map` and not just [`filter`] and [`map`]? The key is in this /// part: /// - /// [`filter`]: #method.filter - /// [`map`]: #method.map + /// [`filter`]: Iterator::filter + /// [`map`]: Iterator::map /// /// > If the closure returns [`Some(element)`][`Some`], then that element is returned. /// @@ -802,7 +796,7 @@ pub trait Iterator { /// /// [`usize`]: type@usize /// [`usize::MAX`]: crate::usize::MAX - /// [`zip`]: #method.zip + /// [`zip`]: Iterator::zip /// /// # Examples /// @@ -837,8 +831,8 @@ pub trait Iterator { /// anything other than fetching the next value) of the [`next`] method /// will occur. /// - /// [`peek`]: crate::iter::Peekable::peek - /// [`next`]: #tymethod.next + /// [`peek`]: Peekable::peek + /// [`next`]: Iterator::next /// /// # Examples /// @@ -876,7 +870,7 @@ pub trait Iterator { /// Creates an iterator that [`skip`]s elements based on a predicate. /// - /// [`skip`]: #method.skip + /// [`skip`]: Iterator::skip /// /// `skip_while()` takes a closure as an argument. It will call this /// closure on each element of the iterator, and ignore elements @@ -1043,8 +1037,8 @@ pub trait Iterator { /// /// Here's the same example, but with [`take_while`] and [`map`]: /// - /// [`take_while`]: #method.take_while - /// [`map`]: #method.map + /// [`take_while`]: Iterator::take_while + /// [`map`]: Iterator::map /// /// ``` /// let a = [-1i32, 4, 0, 1]; @@ -1104,7 +1098,7 @@ pub trait Iterator { /// It is also not specified what this iterator returns after the first` None` is returned. /// If you need fused iterator, use [`fuse`]. /// - /// [`fuse`]: #method.fuse + /// [`fuse`]: Iterator::fuse #[inline] #[unstable(feature = "iter_map_while", reason = "recently added", issue = "68537")] fn map_while(self, predicate: P) -> MapWhile @@ -1190,7 +1184,7 @@ pub trait Iterator { /// An iterator adaptor similar to [`fold`] that holds internal state and /// produces a new iterator. /// - /// [`fold`]: #method.fold + /// [`fold`]: Iterator::fold /// /// `scan()` takes two arguments: an initial value which seeds the internal /// state, and a closure with two arguments, the first being a mutable @@ -1246,8 +1240,8 @@ pub trait Iterator { /// one item for each element, and `flat_map()`'s closure returns an /// iterator for each element. /// - /// [`map`]: #method.map - /// [`flatten`]: #method.flatten + /// [`map`]: Iterator::map + /// [`flatten`]: Iterator::flatten /// /// # Examples /// @@ -1333,7 +1327,7 @@ pub trait Iterator { /// two-dimensional and not one-dimensional. To get a one-dimensional /// structure, you have to `flatten()` again. /// - /// [`flat_map()`]: #method.flat_map + /// [`flat_map()`]: Iterator::flat_map #[inline] #[stable(feature = "iterator_flatten", since = "1.29.0")] fn flatten(self) -> Flatten @@ -1640,7 +1634,7 @@ pub trait Iterator { /// assert_eq!(Ok(vec![1, 3]), result); /// ``` /// - /// [`iter`]: #tymethod.next + /// [`iter`]: Iterator::next /// [`String`]: ../../std/string/struct.String.html /// [`char`]: type@char #[inline] @@ -1661,8 +1655,8 @@ pub trait Iterator { /// /// See also [`is_partitioned()`] and [`partition_in_place()`]. /// - /// [`is_partitioned()`]: #method.is_partitioned - /// [`partition_in_place()`]: #method.partition_in_place + /// [`is_partitioned()`]: Iterator::is_partitioned + /// [`partition_in_place()`]: Iterator::partition_in_place /// /// # Examples /// @@ -1716,8 +1710,8 @@ pub trait Iterator { /// /// See also [`is_partitioned()`] and [`partition()`]. /// - /// [`is_partitioned()`]: #method.is_partitioned - /// [`partition()`]: #method.partition + /// [`is_partitioned()`]: Iterator::is_partitioned + /// [`partition()`]: Iterator::partition /// /// # Examples /// @@ -1779,8 +1773,8 @@ pub trait Iterator { /// /// See also [`partition()`] and [`partition_in_place()`]. /// - /// [`partition()`]: #method.partition - /// [`partition_in_place()`]: #method.partition_in_place + /// [`partition()`]: Iterator::partition + /// [`partition_in_place()`]: Iterator::partition_in_place /// /// # Examples /// @@ -1879,8 +1873,8 @@ pub trait Iterator { /// This can also be thought of as the fallible form of [`for_each()`] /// or as the stateless version of [`try_fold()`]. /// - /// [`for_each()`]: #method.for_each - /// [`try_fold()`]: #method.try_fold + /// [`for_each()`]: Iterator::for_each + /// [`try_fold()`]: Iterator::try_fold /// /// # Examples /// @@ -2006,11 +2000,13 @@ pub trait Iterator { accum } - /// The same as [`fold()`](#method.fold), but uses the first element in the + /// The same as [`fold()`], but uses the first element in the /// iterator as the initial value, folding every subsequent element into it. /// If the iterator is empty, return `None`; otherwise, return the result /// of the fold. /// + /// [`fold()`]: Iterator::fold + /// /// # Example /// /// Find the maximum value: @@ -2088,12 +2084,12 @@ pub trait Iterator { F: FnMut(Self::Item) -> bool, { #[inline] - fn check(mut f: impl FnMut(T) -> bool) -> impl FnMut((), T) -> LoopState<(), ()> { + fn check(mut f: impl FnMut(T) -> bool) -> impl FnMut((), T) -> ControlFlow<(), ()> { move |(), x| { - if f(x) { LoopState::Continue(()) } else { LoopState::Break(()) } + if f(x) { ControlFlow::Continue(()) } else { ControlFlow::Break(()) } } } - self.try_fold((), check(f)) == LoopState::Continue(()) + self.try_fold((), check(f)) == ControlFlow::Continue(()) } /// Tests if any element of the iterator matches a predicate. @@ -2141,13 +2137,13 @@ pub trait Iterator { F: FnMut(Self::Item) -> bool, { #[inline] - fn check(mut f: impl FnMut(T) -> bool) -> impl FnMut((), T) -> LoopState<(), ()> { + fn check(mut f: impl FnMut(T) -> bool) -> impl FnMut((), T) -> ControlFlow<(), ()> { move |(), x| { - if f(x) { LoopState::Break(()) } else { LoopState::Continue(()) } + if f(x) { ControlFlow::Break(()) } else { ControlFlow::Continue(()) } } } - self.try_fold((), check(f)) == LoopState::Break(()) + self.try_fold((), check(f)) == ControlFlow::Break(()) } /// Searches for an element of an iterator that satisfies a predicate. @@ -2203,9 +2199,9 @@ pub trait Iterator { #[inline] fn check( mut predicate: impl FnMut(&T) -> bool, - ) -> impl FnMut((), T) -> LoopState<(), T> { + ) -> impl FnMut((), T) -> ControlFlow<(), T> { move |(), x| { - if predicate(&x) { LoopState::Break(x) } else { LoopState::Continue(()) } + if predicate(&x) { ControlFlow::Break(x) } else { ControlFlow::Continue(()) } } } @@ -2235,10 +2231,12 @@ pub trait Iterator { F: FnMut(Self::Item) -> Option, { #[inline] - fn check(mut f: impl FnMut(T) -> Option) -> impl FnMut((), T) -> LoopState<(), B> { + fn check( + mut f: impl FnMut(T) -> Option, + ) -> impl FnMut((), T) -> ControlFlow<(), B> { move |(), x| match f(x) { - Some(x) => LoopState::Break(x), - None => LoopState::Continue(()), + Some(x) => ControlFlow::Break(x), + None => ControlFlow::Continue(()), } } @@ -2274,15 +2272,15 @@ pub trait Iterator { R: Try, { #[inline] - fn check(mut f: F) -> impl FnMut((), T) -> LoopState<(), Result> + fn check(mut f: F) -> impl FnMut((), T) -> ControlFlow<(), Result> where F: FnMut(&T) -> R, R: Try, { move |(), x| match f(&x).into_result() { - Ok(false) => LoopState::Continue(()), - Ok(true) => LoopState::Break(Ok(x)), - Err(x) => LoopState::Break(Err(x)), + Ok(false) => ControlFlow::Continue(()), + Ok(true) => ControlFlow::Break(Ok(x)), + Err(x) => ControlFlow::Break(Err(x)), } } @@ -2352,10 +2350,14 @@ pub trait Iterator { #[inline] fn check( mut predicate: impl FnMut(T) -> bool, - ) -> impl FnMut(usize, T) -> LoopState { + ) -> impl FnMut(usize, T) -> ControlFlow { // The addition might panic on overflow move |i, x| { - if predicate(x) { LoopState::Break(i) } else { LoopState::Continue(Add::add(i, 1)) } + if predicate(x) { + ControlFlow::Break(i) + } else { + ControlFlow::Continue(Add::add(i, 1)) + } } } @@ -2411,10 +2413,10 @@ pub trait Iterator { #[inline] fn check( mut predicate: impl FnMut(T) -> bool, - ) -> impl FnMut(usize, T) -> LoopState { + ) -> impl FnMut(usize, T) -> ControlFlow { move |i, x| { let i = i - 1; - if predicate(x) { LoopState::Break(i) } else { LoopState::Continue(i) } + if predicate(x) { ControlFlow::Break(i) } else { ControlFlow::Continue(i) } } } @@ -2602,8 +2604,6 @@ pub trait Iterator { /// This is only possible if the iterator has an end, so `rev()` only /// works on [`DoubleEndedIterator`]s. /// - /// [`DoubleEndedIterator`]: trait.DoubleEndedIterator.html - /// /// # Examples /// /// ``` @@ -2634,7 +2634,7 @@ pub trait Iterator { /// /// This function is, in some sense, the opposite of [`zip`]. /// - /// [`zip`]: #method.zip + /// [`zip`]: Iterator::zip /// /// # Examples /// @@ -2713,7 +2713,7 @@ pub trait Iterator { /// This is useful when you have an iterator over `&T`, but you need an /// iterator over `T`. /// - /// [`clone`]: crate::clone::Clone::clone + /// [`clone`]: Clone::clone /// /// # Examples /// @@ -3201,7 +3201,7 @@ pub trait Iterator { /// assert!(![0.0, 1.0, f32::NAN].iter().is_sorted_by(|a, b| a.partial_cmp(b))); /// ``` /// - /// [`is_sorted`]: #method.is_sorted + /// [`is_sorted`]: Iterator::is_sorted #[unstable(feature = "is_sorted", reason = "new API", issue = "53485")] fn is_sorted_by(mut self, mut compare: F) -> bool where @@ -3230,7 +3230,7 @@ pub trait Iterator { /// the elements, as determined by `f`. Apart from that, it's equivalent to [`is_sorted`]; see /// its documentation for more information. /// - /// [`is_sorted`]: #method.is_sorted + /// [`is_sorted`]: Iterator::is_sorted /// /// # Examples /// diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index a02ee9c5ba965..9340b591ebd70 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -111,13 +111,13 @@ pub trait Sized { /// - `T` is not part of the type of any other fields /// - `Bar: Unsize>`, if the last field of `Foo` has type `Bar` /// -/// `Unsize` is used along with [`ops::CoerceUnsized`][coerceunsized] to allow -/// "user-defined" containers such as [`rc::Rc`][rc] to contain dynamically-sized +/// `Unsize` is used along with [`ops::CoerceUnsized`] to allow +/// "user-defined" containers such as [`Rc`] to contain dynamically-sized /// types. See the [DST coercion RFC][RFC982] and [the nomicon entry on coercion][nomicon-coerce] /// for more details. /// -/// [coerceunsized]: ../ops/trait.CoerceUnsized.html -/// [rc]: ../../std/rc/struct.Rc.html +/// [`ops::CoerceUnsized`]: crate::ops::CoerceUnsized +/// [`Rc`]: ../../std/rc/struct.Rc.html /// [RFC982]: https://github.com/rust-lang/rfcs/blob/master/text/0982-dst-coercion.md /// [nomicon-coerce]: ../../nomicon/coercions.html #[unstable(feature = "unsize", issue = "27732")] @@ -368,11 +368,7 @@ pub trait StructuralEq { /// /// [`Vec`]: ../../std/vec/struct.Vec.html /// [`String`]: ../../std/string/struct.String.html -/// [`Drop`]: ../../std/ops/trait.Drop.html -/// [`size_of::`]: ../../std/mem/fn.size_of.html -/// [`Clone`]: ../clone/trait.Clone.html -/// [`String`]: ../../std/string/struct.String.html -/// [`i32`]: ../../std/primitive.i32.html +/// [`size_of::`]: crate::mem::size_of /// [impls]: #implementors #[stable(feature = "rust1", since = "1.0.0")] #[lang = "copy"] @@ -400,18 +396,18 @@ pub macro Copy($item:item) { /// This trait is automatically implemented when the compiler determines /// it's appropriate. /// -/// The precise definition is: a type `T` is `Sync` if and only if `&T` is -/// [`Send`][send]. In other words, if there is no possibility of +/// The precise definition is: a type `T` is [`Sync`] if and only if `&T` is +/// [`Send`]. In other words, if there is no possibility of /// [undefined behavior][ub] (including data races) when passing /// `&T` references between threads. /// -/// As one would expect, primitive types like [`u8`][u8] and [`f64`][f64] -/// are all `Sync`, and so are simple aggregate types containing them, -/// like tuples, structs and enums. More examples of basic `Sync` +/// As one would expect, primitive types like [`u8`] and [`f64`] +/// are all [`Sync`], and so are simple aggregate types containing them, +/// like tuples, structs and enums. More examples of basic [`Sync`] /// types include "immutable" types like `&T`, and those with simple /// inherited mutability, such as [`Box`][box], [`Vec`][vec] and -/// most other collection types. (Generic parameters need to be `Sync` -/// for their container to be `Sync`.) +/// most other collection types. (Generic parameters need to be [`Sync`] +/// for their container to be [`Sync`].) /// /// A somewhat surprising consequence of the definition is that `&mut T` /// is `Sync` (if `T` is `Sync`) even though it seems like that might @@ -421,15 +417,15 @@ pub macro Copy($item:item) { /// of a data race. /// /// Types that are not `Sync` are those that have "interior -/// mutability" in a non-thread-safe form, such as [`cell::Cell`][cell] -/// and [`cell::RefCell`][refcell]. These types allow for mutation of +/// mutability" in a non-thread-safe form, such as [`Cell`][cell] +/// and [`RefCell`][refcell]. These types allow for mutation of /// their contents even through an immutable, shared reference. For /// example the `set` method on [`Cell`][cell] takes `&self`, so it requires /// only a shared reference [`&Cell`][cell]. The method performs no /// synchronization, thus [`Cell`][cell] cannot be `Sync`. /// /// Another example of a non-`Sync` type is the reference-counting -/// pointer [`rc::Rc`][rc]. Given any reference [`&Rc`][rc], you can clone +/// pointer [`Rc`][rc]. Given any reference [`&Rc`][rc], you can clone /// a new [`Rc`][rc], modifying the reference counts in a non-atomic way. /// /// For cases when one does need thread-safe interior mutability, @@ -445,24 +441,21 @@ pub macro Copy($item:item) { /// [undefined behavior][ub]. For example, [`transmute`][transmute]-ing /// from `&T` to `&mut T` is invalid. /// -/// See [the Nomicon](../../nomicon/send-and-sync.html) for more -/// details about `Sync`. +/// See [the Nomicon][nomicon-send-and-sync] for more details about `Sync`. /// -/// [send]: trait.Send.html -/// [u8]: ../../std/primitive.u8.html -/// [f64]: ../../std/primitive.f64.html /// [box]: ../../std/boxed/struct.Box.html /// [vec]: ../../std/vec/struct.Vec.html -/// [cell]: ../cell/struct.Cell.html -/// [refcell]: ../cell/struct.RefCell.html +/// [cell]: crate::cell::Cell +/// [refcell]: crate::cell::RefCell /// [rc]: ../../std/rc/struct.Rc.html /// [arc]: ../../std/sync/struct.Arc.html -/// [atomic data types]: ../sync/atomic/index.html +/// [atomic data types]: crate::sync::atomic /// [mutex]: ../../std/sync/struct.Mutex.html /// [rwlock]: ../../std/sync/struct.RwLock.html -/// [unsafecell]: ../cell/struct.UnsafeCell.html +/// [unsafecell]: crate::cell::UnsafeCell /// [ub]: ../../reference/behavior-considered-undefined.html -/// [transmute]: ../../std/mem/fn.transmute.html +/// [transmute]: crate::mem::transmute +/// [nomicon-send-and-sync]: ../../nomicon/send-and-sync.html #[stable(feature = "rust1", since = "1.0.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "sync_trait")] #[lang = "sync"] @@ -698,7 +691,7 @@ mod impls { /// guarantees to [`mem::Discriminant`]. It is **undefined behavior** to transmute /// between `DiscriminantKind::Discriminant` and `mem::Discriminant`. /// -/// [`mem::Discriminant`]: https://doc.rust-lang.org/stable/core/mem/struct.Discriminant.html +/// [`mem::Discriminant`]: crate::mem::Discriminant #[unstable( feature = "discriminant_kind", issue = "none", @@ -733,7 +726,7 @@ unsafe impl Freeze for &mut T {} /// /// The [`Pin`][Pin] type is used instead to prevent moves through the type /// system. Pointers `P` wrapped in the [`Pin>`][Pin] wrapper can't be -/// moved out of. See the [`pin module`] documentation for more information on +/// moved out of. See the [`pin` module] documentation for more information on /// pinning. /// /// Implementing the `Unpin` trait for `T` lifts the restrictions of pinning off @@ -764,9 +757,9 @@ unsafe impl Freeze for &mut T {} /// /// This trait is automatically implemented for almost every type. /// -/// [`mem::replace`]: ../../std/mem/fn.replace.html +/// [`mem::replace`]: crate::mem::replace /// [Pin]: crate::pin::Pin -/// [`pin module`]: crate::pin +/// [`pin` module]: crate::pin #[stable(feature = "pin", since = "1.33.0")] #[rustc_on_unimplemented( on(_Self = "std::future::Future", note = "consider using `Box::pin`",), diff --git a/library/core/src/ops/control_flow.rs b/library/core/src/ops/control_flow.rs new file mode 100644 index 0000000000000..687d423dcb635 --- /dev/null +++ b/library/core/src/ops/control_flow.rs @@ -0,0 +1,67 @@ +use crate::ops::Try; + +/// Used to make try_fold closures more like normal loops +#[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")] +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum ControlFlow { + /// Continue in the loop, using the given value for the next iteration + Continue(C), + /// Exit the loop, yielding the given value + Break(B), +} + +#[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")] +impl Try for ControlFlow { + type Ok = C; + type Error = B; + #[inline] + fn into_result(self) -> Result { + match self { + ControlFlow::Continue(y) => Ok(y), + ControlFlow::Break(x) => Err(x), + } + } + #[inline] + fn from_error(v: Self::Error) -> Self { + ControlFlow::Break(v) + } + #[inline] + fn from_ok(v: Self::Ok) -> Self { + ControlFlow::Continue(v) + } +} + +impl ControlFlow { + /// Converts the `ControlFlow` into an `Option` which is `Some` if the + /// `ControlFlow` was `Break` and `None` otherwise. + #[inline] + #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")] + pub fn break_value(self) -> Option { + match self { + ControlFlow::Continue(..) => None, + ControlFlow::Break(x) => Some(x), + } + } +} + +impl ControlFlow { + /// Create a `ControlFlow` from any type implementing `Try`. + #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")] + #[inline] + pub fn from_try(r: R) -> Self { + match Try::into_result(r) { + Ok(v) => ControlFlow::Continue(v), + Err(v) => ControlFlow::Break(Try::from_error(v)), + } + } + + /// Convert a `ControlFlow` into any type implementing `Try`; + #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")] + #[inline] + pub fn into_try(self) -> R { + match self { + ControlFlow::Continue(v) => Try::from_ok(v), + ControlFlow::Break(v) => v, + } + } +} diff --git a/library/core/src/ops/mod.rs b/library/core/src/ops/mod.rs index c19bd6e441e69..2a4186f9d5db9 100644 --- a/library/core/src/ops/mod.rs +++ b/library/core/src/ops/mod.rs @@ -140,6 +140,7 @@ mod arith; mod bit; +mod control_flow; mod deref; mod drop; mod function; @@ -191,3 +192,6 @@ pub use self::unsize::CoerceUnsized; #[unstable(feature = "dispatch_from_dyn", issue = "none")] pub use self::unsize::DispatchFromDyn; + +#[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")] +pub use self::control_flow::ControlFlow; diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 81e621318e141..4a651e5aa0ee3 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -1,5 +1,6 @@ #![feature(alloc_layout_extra)] #![feature(array_chunks)] +#![feature(array_methods)] #![feature(array_map)] #![feature(bool_to_option)] #![feature(bound_cloned)] diff --git a/library/core/tests/option.rs b/library/core/tests/option.rs index fa308160fc228..b46bcfd16d283 100644 --- a/library/core/tests/option.rs +++ b/library/core/tests/option.rs @@ -1,4 +1,3 @@ -use core::array::FixedSizeArray; use core::clone::Clone; use core::mem; use core::ops::DerefMut; diff --git a/library/core/tests/result.rs b/library/core/tests/result.rs index caa2d916cd7a8..35598295a9515 100644 --- a/library/core/tests/result.rs +++ b/library/core/tests/result.rs @@ -1,4 +1,3 @@ -use core::array::FixedSizeArray; use core::ops::DerefMut; use core::option::*; diff --git a/library/std/src/io/util.rs b/library/std/src/io/util.rs index b3df6f49dc490..44d2937ee1bf2 100644 --- a/library/std/src/io/util.rs +++ b/library/std/src/io/util.rs @@ -52,11 +52,14 @@ where W: Write, { let mut buf = MaybeUninit::<[u8; super::DEFAULT_BUF_SIZE]>::uninit(); - // FIXME(#76092): This is calling `get_mut` and `get_ref` on an uninitialized - // `MaybeUninit`. Revisit this once we decided whether that is valid or not. - // This is still technically undefined behavior due to creating a reference - // to uninitialized data, but within libstd we can rely on more guarantees - // than if this code were in an external lib. + // FIXME: #42788 + // + // - This creates a (mut) reference to a slice of + // _uninitialized_ integers, which is **undefined behavior** + // + // - Only the standard library gets to soundly "ignore" this, + // based on its privileged knowledge of unstable rustc + // internals; unsafe { reader.initializer().initialize(buf.assume_init_mut()); } diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 3141b3b9526d0..dc57c1c1f44db 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -240,6 +240,7 @@ #![feature(const_fn_transmute)] #![feature(const_ipv6)] #![feature(const_raw_ptr_deref)] +#![feature(const_ipv4)] #![feature(container_error_extra)] #![feature(core_intrinsics)] #![feature(custom_test_frameworks)] diff --git a/library/std/src/net/ip.rs b/library/std/src/net/ip.rs index 341a112df71b3..3f9afae880f93 100644 --- a/library/std/src/net/ip.rs +++ b/library/std/src/net/ip.rs @@ -365,8 +365,9 @@ impl Ipv4Addr { /// let addr = Ipv4Addr::new(127, 0, 0, 1); /// assert_eq!(addr.octets(), [127, 0, 0, 1]); /// ``` + #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] #[stable(feature = "rust1", since = "1.0.0")] - pub fn octets(&self) -> [u8; 4] { + pub const fn octets(&self) -> [u8; 4] { // This returns the order we want because s_addr is stored in big-endian. self.inner.s_addr.to_ne_bytes() } @@ -408,8 +409,9 @@ impl Ipv4Addr { /// assert_eq!(Ipv4Addr::new(127, 0, 0, 1).is_loopback(), true); /// assert_eq!(Ipv4Addr::new(45, 22, 13, 197).is_loopback(), false); /// ``` + #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] #[stable(since = "1.7.0", feature = "ip_17")] - pub fn is_loopback(&self) -> bool { + pub const fn is_loopback(&self) -> bool { self.octets()[0] == 127 } @@ -437,8 +439,9 @@ impl Ipv4Addr { /// assert_eq!(Ipv4Addr::new(192, 168, 0, 2).is_private(), true); /// assert_eq!(Ipv4Addr::new(192, 169, 0, 2).is_private(), false); /// ``` + #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] #[stable(since = "1.7.0", feature = "ip_17")] - pub fn is_private(&self) -> bool { + pub const fn is_private(&self) -> bool { match self.octets() { [10, ..] => true, [172, b, ..] if b >= 16 && b <= 31 => true, @@ -463,8 +466,9 @@ impl Ipv4Addr { /// assert_eq!(Ipv4Addr::new(169, 254, 10, 65).is_link_local(), true); /// assert_eq!(Ipv4Addr::new(16, 89, 10, 65).is_link_local(), false); /// ``` + #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] #[stable(since = "1.7.0", feature = "ip_17")] - pub fn is_link_local(&self) -> bool { + pub const fn is_link_local(&self) -> bool { match self.octets() { [169, 254, ..] => true, _ => false, @@ -542,10 +546,13 @@ impl Ipv4Addr { /// assert_eq!(Ipv4Addr::new(1, 1, 1, 1).is_global(), true); /// assert_eq!(Ipv4Addr::new(80, 9, 12, 3).is_global(), true); /// ``` - pub fn is_global(&self) -> bool { + #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] + pub const fn is_global(&self) -> bool { // check if this address is 192.0.0.9 or 192.0.0.10. These addresses are the only two // globally routable addresses in the 192.0.0.0/24 range. - if u32::from(*self) == 0xc0000009 || u32::from(*self) == 0xc000000a { + if u32::from_be_bytes(self.octets()) == 0xc0000009 + || u32::from_be_bytes(self.octets()) == 0xc000000a + { return true; } !self.is_private() @@ -577,7 +584,8 @@ impl Ipv4Addr { /// assert_eq!(Ipv4Addr::new(100, 127, 255, 255).is_shared(), true); /// assert_eq!(Ipv4Addr::new(100, 128, 0, 0).is_shared(), false); /// ``` - pub fn is_shared(&self) -> bool { + #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] + pub const fn is_shared(&self) -> bool { self.octets()[0] == 100 && (self.octets()[1] & 0b1100_0000 == 0b0100_0000) } @@ -609,7 +617,8 @@ impl Ipv4Addr { /// assert_eq!(Ipv4Addr::new(192, 0, 1, 0).is_ietf_protocol_assignment(), false); /// assert_eq!(Ipv4Addr::new(191, 255, 255, 255).is_ietf_protocol_assignment(), false); /// ``` - pub fn is_ietf_protocol_assignment(&self) -> bool { + #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] + pub const fn is_ietf_protocol_assignment(&self) -> bool { self.octets()[0] == 192 && self.octets()[1] == 0 && self.octets()[2] == 0 } @@ -632,7 +641,8 @@ impl Ipv4Addr { /// assert_eq!(Ipv4Addr::new(198, 19, 255, 255).is_benchmarking(), true); /// assert_eq!(Ipv4Addr::new(198, 20, 0, 0).is_benchmarking(), false); /// ``` - pub fn is_benchmarking(&self) -> bool { + #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] + pub const fn is_benchmarking(&self) -> bool { self.octets()[0] == 198 && (self.octets()[1] & 0xfe) == 18 } @@ -664,7 +674,8 @@ impl Ipv4Addr { /// // The broadcast address is not considered as reserved for future use by this implementation /// assert_eq!(Ipv4Addr::new(255, 255, 255, 255).is_reserved(), false); /// ``` - pub fn is_reserved(&self) -> bool { + #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] + pub const fn is_reserved(&self) -> bool { self.octets()[0] & 240 == 240 && !self.is_broadcast() } @@ -685,8 +696,9 @@ impl Ipv4Addr { /// assert_eq!(Ipv4Addr::new(236, 168, 10, 65).is_multicast(), true); /// assert_eq!(Ipv4Addr::new(172, 16, 10, 65).is_multicast(), false); /// ``` + #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] #[stable(since = "1.7.0", feature = "ip_17")] - pub fn is_multicast(&self) -> bool { + pub const fn is_multicast(&self) -> bool { self.octets()[0] >= 224 && self.octets()[0] <= 239 } @@ -705,9 +717,10 @@ impl Ipv4Addr { /// assert_eq!(Ipv4Addr::new(255, 255, 255, 255).is_broadcast(), true); /// assert_eq!(Ipv4Addr::new(236, 168, 10, 65).is_broadcast(), false); /// ``` + #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] #[stable(since = "1.7.0", feature = "ip_17")] - pub fn is_broadcast(&self) -> bool { - self == &Self::BROADCAST + pub const fn is_broadcast(&self) -> bool { + u32::from_be_bytes(self.octets()) == u32::from_be_bytes(Self::BROADCAST.octets()) } /// Returns [`true`] if this address is in a range designated for documentation. @@ -731,8 +744,9 @@ impl Ipv4Addr { /// assert_eq!(Ipv4Addr::new(203, 0, 113, 6).is_documentation(), true); /// assert_eq!(Ipv4Addr::new(193, 34, 17, 19).is_documentation(), false); /// ``` + #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] #[stable(since = "1.7.0", feature = "ip_17")] - pub fn is_documentation(&self) -> bool { + pub const fn is_documentation(&self) -> bool { match self.octets() { [192, 0, 2, _] => true, [198, 51, 100, _] => true, @@ -745,6 +759,9 @@ impl Ipv4Addr { /// /// a.b.c.d becomes ::a.b.c.d /// + /// This isn't typically the method you want; these addresses don't typically + /// function on modern systems. Use `to_ipv6_mapped` instead. + /// /// [`IPv6` address]: Ipv6Addr /// /// # Examples @@ -757,10 +774,13 @@ impl Ipv4Addr { /// Ipv6Addr::new(0, 0, 0, 0, 0, 0, 49152, 767) /// ); /// ``` + #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] #[stable(feature = "rust1", since = "1.0.0")] - pub fn to_ipv6_compatible(&self) -> Ipv6Addr { + pub const fn to_ipv6_compatible(&self) -> Ipv6Addr { let [a, b, c, d] = self.octets(); - Ipv6Addr::from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, a, b, c, d]) + Ipv6Addr { + inner: c::in6_addr { s6_addr: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, a, b, c, d] }, + } } /// Converts this address to an IPv4-mapped [`IPv6` address]. @@ -777,10 +797,13 @@ impl Ipv4Addr { /// assert_eq!(Ipv4Addr::new(192, 0, 2, 255).to_ipv6_mapped(), /// Ipv6Addr::new(0, 0, 0, 0, 0, 65535, 49152, 767)); /// ``` + #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] #[stable(feature = "rust1", since = "1.0.0")] - pub fn to_ipv6_mapped(&self) -> Ipv6Addr { + pub const fn to_ipv6_mapped(&self) -> Ipv6Addr { let [a, b, c, d] = self.octets(); - Ipv6Addr::from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, a, b, c, d]) + Ipv6Addr { + inner: c::in6_addr { s6_addr: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, a, b, c, d] }, + } } } diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs index d00824cfb3e98..2a4cb22cc52a2 100644 --- a/library/std/src/primitive_docs.rs +++ b/library/std/src/primitive_docs.rs @@ -510,7 +510,7 @@ mod prim_pointer {} /// an array. Indeed, this provides most of the API for working with arrays. /// Slices have a dynamic size and do not coerce to arrays. /// -/// You can move elements out of an array with a slice pattern. If you want +/// You can move elements out of an array with a [slice pattern]. If you want /// one element, see [`mem::replace`]. /// /// # Examples @@ -552,7 +552,7 @@ mod prim_pointer {} /// for x in &array { } /// ``` /// -/// You can use a slice pattern to move elements out of an array: +/// You can use a [slice pattern] to move elements out of an array: /// /// ``` /// fn move_away(_: String) { /* Do interesting things. */ } @@ -567,7 +567,7 @@ mod prim_pointer {} /// [`Hash`]: hash::Hash /// [`Borrow`]: borrow::Borrow /// [`BorrowMut`]: borrow::BorrowMut -/// +/// [slice pattern]: ../reference/patterns.html#slice-patterns #[stable(feature = "rust1", since = "1.0.0")] mod prim_array {} diff --git a/src/doc/book b/src/doc/book index c0a6a61b8205d..e5ed97128302d 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit c0a6a61b8205da14ac955425f74258ffd8ee065d +Subproject commit e5ed97128302d5fa45dbac0e64426bc7649a558c diff --git a/src/doc/edition-guide b/src/doc/edition-guide index bd6e4a9f59c5c..81f16863014de 160000 --- a/src/doc/edition-guide +++ b/src/doc/edition-guide @@ -1 +1 @@ -Subproject commit bd6e4a9f59c5c1545f572266af77f5c7a5bad6d1 +Subproject commit 81f16863014de60b53de401d71ff904d163ee030 diff --git a/src/doc/reference b/src/doc/reference index 1b6c4b0afab97..25391dba46262 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit 1b6c4b0afab97c0230433466c97167bbbe8445f6 +Subproject commit 25391dba46262f882fa846beefaff54a966a8fa5 diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example index 80a10e22140e2..19f0a0372af49 160000 --- a/src/doc/rust-by-example +++ b/src/doc/rust-by-example @@ -1 +1 @@ -Subproject commit 80a10e22140e28392b99d24ed02f4c6d8cb770a0 +Subproject commit 19f0a0372af497b34369cf182d9d16156cab2969 diff --git a/src/test/mir-opt/inline/inline-async.rs b/src/test/mir-opt/inline/inline-async.rs new file mode 100644 index 0000000000000..5c838159b986c --- /dev/null +++ b/src/test/mir-opt/inline/inline-async.rs @@ -0,0 +1,18 @@ +// Checks that inliner doesn't introduce cycles when optimizing generators. +// The outcome of optimization is not verfied, just the absence of the cycle. +// Regression test for #76181. +// +// edition:2018 + +#![crate_type = "lib"] + +pub struct S; + +impl S { + pub async fn g(&mut self) { + self.h(); + } + pub fn h(&mut self) { + let _ = self.g(); + } +} diff --git a/src/test/ui/consts/std/net/ipv4.rs b/src/test/ui/consts/std/net/ipv4.rs new file mode 100644 index 0000000000000..8c676999ae734 --- /dev/null +++ b/src/test/ui/consts/std/net/ipv4.rs @@ -0,0 +1,58 @@ +// run-pass + +#![feature(ip)] +#![feature(const_ipv4)] + +use std::net::{Ipv4Addr, Ipv6Addr}; + +fn main() { + const IP_ADDRESS: Ipv4Addr = Ipv4Addr::new(127, 0, 0, 1); + assert_eq!(IP_ADDRESS, Ipv4Addr::LOCALHOST); + + const OCTETS: [u8; 4] = IP_ADDRESS.octets(); + assert_eq!(OCTETS, [127, 0, 0, 1]); + + const IS_UNSPECIFIED : bool = IP_ADDRESS.is_unspecified(); + assert!(!IS_UNSPECIFIED); + + const IS_LOOPBACK : bool = IP_ADDRESS.is_loopback(); + assert!(IS_LOOPBACK); + + const IS_PRIVATE : bool = IP_ADDRESS.is_private(); + assert!(!IS_PRIVATE); + + const IS_LINK_LOCAL : bool = IP_ADDRESS.is_link_local(); + assert!(!IS_LINK_LOCAL); + + const IS_GLOBAL : bool = IP_ADDRESS.is_global(); + assert!(!IS_GLOBAL); + + const IS_SHARED : bool = IP_ADDRESS.is_shared(); + assert!(!IS_SHARED); + + const IS_IETF_PROTOCOL_ASSIGNMENT : bool = IP_ADDRESS.is_ietf_protocol_assignment(); + assert!(!IS_IETF_PROTOCOL_ASSIGNMENT); + + const IS_BENCHMARKING : bool = IP_ADDRESS.is_benchmarking(); + assert!(!IS_BENCHMARKING); + + const IS_RESERVED : bool = IP_ADDRESS.is_reserved(); + assert!(!IS_RESERVED); + + const IS_MULTICAST : bool = IP_ADDRESS.is_multicast(); + assert!(!IS_MULTICAST); + + const IS_BROADCAST : bool = IP_ADDRESS.is_broadcast(); + assert!(!IS_BROADCAST); + + const IS_DOCUMENTATION : bool = IP_ADDRESS.is_documentation(); + assert!(!IS_DOCUMENTATION); + + const IP_V6_COMPATIBLE : Ipv6Addr = IP_ADDRESS.to_ipv6_compatible(); + assert_eq!(IP_V6_COMPATIBLE, + Ipv6Addr::from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 0, 0, 1])); + + const IP_V6_MAPPED : Ipv6Addr = IP_ADDRESS.to_ipv6_mapped(); + assert_eq!(IP_V6_MAPPED, + Ipv6Addr::from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 127, 0, 0, 1])); +}