From 26bd43355f839f6005910056e89b2364b7fec06a Mon Sep 17 00:00:00 2001 From: Valentin Tolmer Date: Fri, 8 Feb 2019 14:14:15 +0100 Subject: [PATCH 01/10] Move the intrinsics into a submodule --- src/libcore/intrinsics.rs | 464 ++++++++++++++++++++------------------ 1 file changed, 249 insertions(+), 215 deletions(-) diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index f6de7566be914..e6098b1b24cc0 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -962,221 +962,6 @@ extern "rust-intrinsic" { /// value is not necessarily valid to be used to actually access memory. pub fn arith_offset(dst: *const T, offset: isize) -> *const T; - /// Copies `count * size_of::()` bytes from `src` to `dst`. The source - /// and destination must *not* overlap. - /// - /// For regions of memory which might overlap, use [`copy`] instead. - /// - /// `copy_nonoverlapping` is semantically equivalent to C's [`memcpy`], but - /// with the argument order swapped. - /// - /// [`copy`]: ./fn.copy.html - /// [`memcpy`]: https://en.cppreference.com/w/c/string/byte/memcpy - /// - /// # Safety - /// - /// Behavior is undefined if any of the following conditions are violated: - /// - /// * `src` must be [valid] for reads of `count * size_of::()` bytes. - /// - /// * `dst` must be [valid] for writes of `count * size_of::()` bytes. - /// - /// * Both `src` and `dst` must be properly aligned. - /// - /// * The region of memory beginning at `src` with a size of `count * - /// size_of::()` bytes must *not* overlap with the region of memory - /// beginning at `dst` with the same size. - /// - /// Like [`read`], `copy_nonoverlapping` creates a bitwise copy of `T`, regardless of - /// whether `T` is [`Copy`]. If `T` is not [`Copy`], using *both* the values - /// in the region beginning at `*src` and the region beginning at `*dst` can - /// [violate memory safety][read-ownership]. - /// - /// Note that even if the effectively copied size (`count * size_of::()`) is - /// `0`, the pointers must be non-NULL and properly aligned. - /// - /// [`Copy`]: ../marker/trait.Copy.html - /// [`read`]: ../ptr/fn.read.html - /// [read-ownership]: ../ptr/fn.read.html#ownership-of-the-returned-value - /// [valid]: ../ptr/index.html#safety - /// - /// # Examples - /// - /// Manually implement [`Vec::append`]: - /// - /// ``` - /// use std::ptr; - /// - /// /// Moves all the elements of `src` into `dst`, leaving `src` empty. - /// fn append(dst: &mut Vec, src: &mut Vec) { - /// let src_len = src.len(); - /// let dst_len = dst.len(); - /// - /// // Ensure that `dst` has enough capacity to hold all of `src`. - /// dst.reserve(src_len); - /// - /// unsafe { - /// // The call to offset is always safe because `Vec` will never - /// // allocate more than `isize::MAX` bytes. - /// let dst_ptr = dst.as_mut_ptr().offset(dst_len as isize); - /// let src_ptr = src.as_ptr(); - /// - /// // Truncate `src` without dropping its contents. We do this first, - /// // to avoid problems in case something further down panics. - /// src.set_len(0); - /// - /// // The two regions cannot overlap because mutable references do - /// // not alias, and two different vectors cannot own the same - /// // memory. - /// ptr::copy_nonoverlapping(src_ptr, dst_ptr, src_len); - /// - /// // Notify `dst` that it now holds the contents of `src`. - /// dst.set_len(dst_len + src_len); - /// } - /// } - /// - /// let mut a = vec!['r']; - /// let mut b = vec!['u', 's', 't']; - /// - /// append(&mut a, &mut b); - /// - /// assert_eq!(a, &['r', 'u', 's', 't']); - /// assert!(b.is_empty()); - /// ``` - /// - /// [`Vec::append`]: ../../std/vec/struct.Vec.html#method.append - #[stable(feature = "rust1", since = "1.0.0")] - pub fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize); - - /// Copies `count * size_of::()` bytes from `src` to `dst`. The source - /// and destination may overlap. - /// - /// If the source and destination will *never* overlap, - /// [`copy_nonoverlapping`] can be used instead. - /// - /// `copy` is semantically equivalent to C's [`memmove`], but with the argument - /// order swapped. Copying takes place as if the bytes were copied from `src` - /// to a temporary array and then copied from the array to `dst`. - /// - /// [`copy_nonoverlapping`]: ./fn.copy_nonoverlapping.html - /// [`memmove`]: https://en.cppreference.com/w/c/string/byte/memmove - /// - /// # Safety - /// - /// Behavior is undefined if any of the following conditions are violated: - /// - /// * `src` must be [valid] for reads of `count * size_of::()` bytes. - /// - /// * `dst` must be [valid] for writes of `count * size_of::()` bytes. - /// - /// * Both `src` and `dst` must be properly aligned. - /// - /// Like [`read`], `copy` creates a bitwise copy of `T`, regardless of - /// whether `T` is [`Copy`]. If `T` is not [`Copy`], using both the values - /// in the region beginning at `*src` and the region beginning at `*dst` can - /// [violate memory safety][read-ownership]. - /// - /// Note that even if the effectively copied size (`count * size_of::()`) is - /// `0`, the pointers must be non-NULL and properly aligned. - /// - /// [`Copy`]: ../marker/trait.Copy.html - /// [`read`]: ../ptr/fn.read.html - /// [read-ownership]: ../ptr/fn.read.html#ownership-of-the-returned-value - /// [valid]: ../ptr/index.html#safety - /// - /// # Examples - /// - /// Efficiently create a Rust vector from an unsafe buffer: - /// - /// ``` - /// use std::ptr; - /// - /// # #[allow(dead_code)] - /// unsafe fn from_buf_raw(ptr: *const T, elts: usize) -> Vec { - /// let mut dst = Vec::with_capacity(elts); - /// dst.set_len(elts); - /// ptr::copy(ptr, dst.as_mut_ptr(), elts); - /// dst - /// } - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn copy(src: *const T, dst: *mut T, count: usize); - - /// Sets `count * size_of::()` bytes of memory starting at `dst` to - /// `val`. - /// - /// `write_bytes` is similar to C's [`memset`], but sets `count * - /// size_of::()` bytes to `val`. - /// - /// [`memset`]: https://en.cppreference.com/w/c/string/byte/memset - /// - /// # Safety - /// - /// Behavior is undefined if any of the following conditions are violated: - /// - /// * `dst` must be [valid] for writes of `count * size_of::()` bytes. - /// - /// * `dst` must be properly aligned. - /// - /// Additionally, the caller must ensure that writing `count * - /// size_of::()` bytes to the given region of memory results in a valid - /// value of `T`. Using a region of memory typed as a `T` that contains an - /// invalid value of `T` is undefined behavior. - /// - /// Note that even if the effectively copied size (`count * size_of::()`) is - /// `0`, the pointer must be non-NULL and properly aligned. - /// - /// [valid]: ../ptr/index.html#safety - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// use std::ptr; - /// - /// let mut vec = vec![0u32; 4]; - /// unsafe { - /// let vec_ptr = vec.as_mut_ptr(); - /// ptr::write_bytes(vec_ptr, 0xfe, 2); - /// } - /// assert_eq!(vec, [0xfefefefe, 0xfefefefe, 0, 0]); - /// ``` - /// - /// Creating an invalid value: - /// - /// ``` - /// use std::ptr; - /// - /// let mut v = Box::new(0i32); - /// - /// unsafe { - /// // Leaks the previously held value by overwriting the `Box` with - /// // a null pointer. - /// ptr::write_bytes(&mut v as *mut Box, 0, 1); - /// } - /// - /// // At this point, using or dropping `v` results in undefined behavior. - /// // drop(v); // ERROR - /// - /// // Even leaking `v` "uses" it, and hence is undefined behavior. - /// // mem::forget(v); // ERROR - /// - /// // In fact, `v` is invalid according to basic type layout invariants, so *any* - /// // operation touching it is undefined behavior. - /// // let v2 = v; // ERROR - /// - /// unsafe { - /// // Let us instead put in a valid value - /// ptr::write(&mut v as *mut Box, Box::new(42i32)); - /// } - /// - /// // Now the box is fine - /// assert_eq!(*v, 42); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - pub fn write_bytes(dst: *mut T, val: u8, count: usize); - /// Equivalent to the appropriate `llvm.memcpy.p0i8.0i8.*` intrinsic, with /// a size of `count` * `size_of::()` and an alignment of /// `min_align_of::()` @@ -1524,3 +1309,252 @@ extern "rust-intrinsic" { /// Probably will never become stable. pub fn nontemporal_store(ptr: *mut T, val: T); } + +mod real_intrinsics { + extern "rust-intrinsic" { + /// Copies `count * size_of::()` bytes from `src` to `dst`. The source + /// and destination must *not* overlap. + /// For the full docs, see the stabilized wrapper [`copy_nonoverlapping`]. + /// + /// [`copy_nonoverlapping`]: ../../std/ptr/fn.copy_nonoverlapping.html + pub fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize); + + /// Copies `count * size_of::()` bytes from `src` to `dst`. The source + /// and destination may overlap. + /// For the full docs, see the stabilized wrapper [`copy`]. + /// + /// [`copy`]: ../../std/ptr/fn.copy.html + pub fn copy(src: *const T, dst: *mut T, count: usize); + + /// Sets `count * size_of::()` bytes of memory starting at `dst` to + /// `val`. + /// For the full docs, see the stabilized wrapper [`write_bytes`]. + /// + /// [`write_bytes`]: ../../std/ptr/fn.write_bytes.html + pub fn write_bytes(dst: *mut T, val: u8, count: usize); + } +} + +/// Copies `count * size_of::()` bytes from `src` to `dst`. The source +/// and destination must *not* overlap. +/// +/// For regions of memory which might overlap, use [`copy`] instead. +/// +/// `copy_nonoverlapping` is semantically equivalent to C's [`memcpy`], but +/// with the argument order swapped. +/// +/// [`copy`]: ./fn.copy.html +/// [`memcpy`]: https://en.cppreference.com/w/c/string/byte/memcpy +/// +/// # Safety +/// +/// Behavior is undefined if any of the following conditions are violated: +/// +/// * `src` must be [valid] for reads of `count * size_of::()` bytes. +/// +/// * `dst` must be [valid] for writes of `count * size_of::()` bytes. +/// +/// * Both `src` and `dst` must be properly aligned. +/// +/// * The region of memory beginning at `src` with a size of `count * +/// size_of::()` bytes must *not* overlap with the region of memory +/// beginning at `dst` with the same size. +/// +/// Like [`read`], `copy_nonoverlapping` creates a bitwise copy of `T`, regardless of +/// whether `T` is [`Copy`]. If `T` is not [`Copy`], using *both* the values +/// in the region beginning at `*src` and the region beginning at `*dst` can +/// [violate memory safety][read-ownership]. +/// +/// Note that even if the effectively copied size (`count * size_of::()`) is +/// `0`, the pointers must be non-NULL and properly aligned. +/// +/// [`Copy`]: ../marker/trait.Copy.html +/// [`read`]: ../ptr/fn.read.html +/// [read-ownership]: ../ptr/fn.read.html#ownership-of-the-returned-value +/// [valid]: ../ptr/index.html#safety +/// +/// # Examples +/// +/// Manually implement [`Vec::append`]: +/// +/// ``` +/// use std::ptr; +/// +/// /// Moves all the elements of `src` into `dst`, leaving `src` empty. +/// fn append(dst: &mut Vec, src: &mut Vec) { +/// let src_len = src.len(); +/// let dst_len = dst.len(); +/// +/// // Ensure that `dst` has enough capacity to hold all of `src`. +/// dst.reserve(src_len); +/// +/// unsafe { +/// // The call to offset is always safe because `Vec` will never +/// // allocate more than `isize::MAX` bytes. +/// let dst_ptr = dst.as_mut_ptr().offset(dst_len as isize); +/// let src_ptr = src.as_ptr(); +/// +/// // Truncate `src` without dropping its contents. We do this first, +/// // to avoid problems in case something further down panics. +/// src.set_len(0); +/// +/// // The two regions cannot overlap because mutable references do +/// // not alias, and two different vectors cannot own the same +/// // memory. +/// ptr::copy_nonoverlapping(src_ptr, dst_ptr, src_len); +/// +/// // Notify `dst` that it now holds the contents of `src`. +/// dst.set_len(dst_len + src_len); +/// } +/// } +/// +/// let mut a = vec!['r']; +/// let mut b = vec!['u', 's', 't']; +/// +/// append(&mut a, &mut b); +/// +/// assert_eq!(a, &['r', 'u', 's', 't']); +/// assert!(b.is_empty()); +/// ``` +/// +/// [`Vec::append`]: ../../std/vec/struct.Vec.html#method.append +#[stable(feature = "rust1", since = "1.0.0")] +#[inline] +pub unsafe fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize) { + real_intrinsics::copy_nonoverlapping(src, dst, count); +} + +/// Copies `count * size_of::()` bytes from `src` to `dst`. The source +/// and destination may overlap. +/// +/// If the source and destination will *never* overlap, +/// [`copy_nonoverlapping`] can be used instead. +/// +/// `copy` is semantically equivalent to C's [`memmove`], but with the argument +/// order swapped. Copying takes place as if the bytes were copied from `src` +/// to a temporary array and then copied from the array to `dst`. +/// +/// [`copy_nonoverlapping`]: ./fn.copy_nonoverlapping.html +/// [`memmove`]: https://en.cppreference.com/w/c/string/byte/memmove +/// +/// # Safety +/// +/// Behavior is undefined if any of the following conditions are violated: +/// +/// * `src` must be [valid] for reads of `count * size_of::()` bytes. +/// +/// * `dst` must be [valid] for writes of `count * size_of::()` bytes. +/// +/// * Both `src` and `dst` must be properly aligned. +/// +/// Like [`read`], `copy` creates a bitwise copy of `T`, regardless of +/// whether `T` is [`Copy`]. If `T` is not [`Copy`], using both the values +/// in the region beginning at `*src` and the region beginning at `*dst` can +/// [violate memory safety][read-ownership]. +/// +/// Note that even if the effectively copied size (`count * size_of::()`) is +/// `0`, the pointers must be non-NULL and properly aligned. +/// +/// [`Copy`]: ../marker/trait.Copy.html +/// [`read`]: ../ptr/fn.read.html +/// [read-ownership]: ../ptr/fn.read.html#ownership-of-the-returned-value +/// [valid]: ../ptr/index.html#safety +/// +/// # Examples +/// +/// Efficiently create a Rust vector from an unsafe buffer: +/// +/// ``` +/// use std::ptr; +/// +/// # #[allow(dead_code)] +/// unsafe fn from_buf_raw(ptr: *const T, elts: usize) -> Vec { +/// let mut dst = Vec::with_capacity(elts); +/// dst.set_len(elts); +/// ptr::copy(ptr, dst.as_mut_ptr(), elts); +/// dst +/// } +/// ``` +#[stable(feature = "rust1", since = "1.0.0")] +#[inline] +pub unsafe fn copy(src: *const T, dst: *mut T, count: usize) { + real_intrinsics::copy(src, dst, count) +} + +/// Sets `count * size_of::()` bytes of memory starting at `dst` to +/// `val`. +/// +/// `write_bytes` is similar to C's [`memset`], but sets `count * +/// size_of::()` bytes to `val`. +/// +/// [`memset`]: https://en.cppreference.com/w/c/string/byte/memset +/// +/// # Safety +/// +/// Behavior is undefined if any of the following conditions are violated: +/// +/// * `dst` must be [valid] for writes of `count * size_of::()` bytes. +/// +/// * `dst` must be properly aligned. +/// +/// Additionally, the caller must ensure that writing `count * +/// size_of::()` bytes to the given region of memory results in a valid +/// value of `T`. Using a region of memory typed as a `T` that contains an +/// invalid value of `T` is undefined behavior. +/// +/// Note that even if the effectively copied size (`count * size_of::()`) is +/// `0`, the pointer must be non-NULL and properly aligned. +/// +/// [valid]: ../ptr/index.html#safety +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// use std::ptr; +/// +/// let mut vec = vec![0u32; 4]; +/// unsafe { +/// let vec_ptr = vec.as_mut_ptr(); +/// ptr::write_bytes(vec_ptr, 0xfe, 2); +/// } +/// assert_eq!(vec, [0xfefefefe, 0xfefefefe, 0, 0]); +/// ``` +/// +/// Creating an invalid value: +/// +/// ``` +/// use std::ptr; +/// +/// let mut v = Box::new(0i32); +/// +/// unsafe { +/// // Leaks the previously held value by overwriting the `Box` with +/// // a null pointer. +/// ptr::write_bytes(&mut v as *mut Box, 0, 1); +/// } +/// +/// // At this point, using or dropping `v` results in undefined behavior. +/// // drop(v); // ERROR +/// +/// // Even leaking `v` "uses" it, and hence is undefined behavior. +/// // mem::forget(v); // ERROR +/// +/// // In fact, `v` is invalid according to basic type layout invariants, so *any* +/// // operation touching it is undefined behavior. +/// // let v2 = v; // ERROR +/// +/// unsafe { +/// // Let us instead put in a valid value +/// ptr::write(&mut v as *mut Box, Box::new(42i32)); +/// } +/// +/// // Now the box is fine +/// assert_eq!(*v, 42); +/// ``` +#[stable(feature = "rust1", since = "1.0.0")] +#[inline] +pub unsafe fn write_bytes(dst: *mut T, val: u8, count: usize) { + real_intrinsics::write_bytes(dst, val, count) +} From 564c569bcb1b85ec3b1f93de60b7f7b385c5bd17 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sat, 16 Feb 2019 23:18:43 -0800 Subject: [PATCH 02/10] Monomorphize less code in fs::{read|write} Since the generic-ness is only for the as_refs, might as well have std just compile the important part once instead of on every use. --- src/libstd/fs.rs | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index 3538816c1124c..7074e08b9b97a 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -254,10 +254,13 @@ fn initial_buffer_size(file: &File) -> usize { /// ``` #[stable(feature = "fs_read_write_bytes", since = "1.26.0")] pub fn read>(path: P) -> io::Result> { - let mut file = File::open(path)?; - let mut bytes = Vec::with_capacity(initial_buffer_size(&file)); - file.read_to_end(&mut bytes)?; - Ok(bytes) + fn inner(path: &Path) -> io::Result> { + let mut file = File::open(path)?; + let mut bytes = Vec::with_capacity(initial_buffer_size(&file)); + file.read_to_end(&mut bytes)?; + Ok(bytes) + } + inner(path.as_ref()) } /// Read the entire contents of a file into a string. @@ -296,10 +299,13 @@ pub fn read>(path: P) -> io::Result> { /// ``` #[stable(feature = "fs_read_write", since = "1.26.0")] pub fn read_to_string>(path: P) -> io::Result { - let mut file = File::open(path)?; - let mut string = String::with_capacity(initial_buffer_size(&file)); - file.read_to_string(&mut string)?; - Ok(string) + fn inner(path: &Path) -> io::Result { + let mut file = File::open(path)?; + let mut string = String::with_capacity(initial_buffer_size(&file)); + file.read_to_string(&mut string)?; + Ok(string) + } + inner(path.as_ref()) } /// Write a slice as the entire contents of a file. @@ -326,7 +332,10 @@ pub fn read_to_string>(path: P) -> io::Result { /// ``` #[stable(feature = "fs_read_write_bytes", since = "1.26.0")] pub fn write, C: AsRef<[u8]>>(path: P, contents: C) -> io::Result<()> { - File::create(path)?.write_all(contents.as_ref()) + fn inner(path: &Path, contents: &[u8]) -> io::Result<()> { + File::create(path)?.write_all(contents) + } + inner(path.as_ref(), contents.as_ref()) } impl File { From 8fbb013c1c0605a4738a6f5f5ec5b47550a2a5ec Mon Sep 17 00:00:00 2001 From: Dale Wijnand Date: Sun, 17 Feb 2019 10:24:06 +0000 Subject: [PATCH 03/10] Mention capping forbid lints I felt the description of forbid was misleading/incomplete without mentioning how --cap-lints interacts with it. --- src/doc/rustc/src/lints/levels.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/doc/rustc/src/lints/levels.md b/src/doc/rustc/src/lints/levels.md index 072c7585934e8..d315e0f8ca9e5 100644 --- a/src/doc/rustc/src/lints/levels.md +++ b/src/doc/rustc/src/lints/levels.md @@ -90,7 +90,9 @@ This lint level gives you that. 'forbid' is a special lint level that's stronger than 'deny'. It's the same as 'deny' in that a lint at this level will produce an error, but unlike the 'deny' level, the 'forbid' level can not be overridden to be anything lower -than an error. +than an error. However, lint levels may still be capped with `--cap-lints` +(see below) so `rustc --cap-lints warn` will make lints set to 'forbid' just +warn. ## Configuring warning levels From a23c40ec9435dd7b784e833e876a133c627aff92 Mon Sep 17 00:00:00 2001 From: Aaron Stillwell Date: Sun, 17 Feb 2019 15:17:46 +0000 Subject: [PATCH 04/10] Add alias methods to PathBuf for underlying OsString Implemented the following methods on PathBuf which forward to the underlying OsString. - capacity - with_capacity - clear - reserve - reserve_exact - shrink_to_fit - shrink_to --- src/libstd/path.rs | 82 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 81 insertions(+), 1 deletion(-) diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 0a9796d1a9c20..3e7949565507e 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -1137,7 +1137,7 @@ impl PathBuf { /// /// ``` /// use std::path::PathBuf; - /// + /// /// let path = PathBuf::new(); /// ``` #[stable(feature = "rust1", since = "1.0.0")] @@ -1145,6 +1145,32 @@ impl PathBuf { PathBuf { inner: OsString::new() } } + /// Creates a new `PathBuf` with a given capacity used to create the + /// internal [`OsString`]. See [`with_capacity`] defined on [`OsString`]. + /// + /// # Examples + /// + /// ``` + /// use std::path::PathBuf; + /// + /// let path = PathBuf::with_capacity(10); + /// let capacity = path.capacity(); + /// + /// // This push is done without reallocating + /// path.push(r"C:\"); + /// + /// assert_eq!(capacity, path.capacity()); + /// ``` + /// + /// [`with_capacity`]: ../ffi/struct.OsString.html#method.with_capacity + /// [`OsString`]: ../ffi/struct.OsString.html + #[stable(feature = "path_buf_os_string_methods", since = "1.33.0")] + pub fn with_capacity(capacity: usize) -> PathBuf { + PathBuf { + inner: OsString::with_capacity(capacity) + } + } + /// Coerces to a [`Path`] slice. /// /// [`Path`]: struct.Path.html @@ -1373,6 +1399,60 @@ impl PathBuf { let rw = Box::into_raw(self.inner.into_boxed_os_str()) as *mut Path; unsafe { Box::from_raw(rw) } } + + /// Invokes [`capacity`] on the underlying instance of [`OsString`]. + /// + /// [`capacity`]: ../ffi/struct.OsString.html#method.capacity + /// [`OsString`]: ../ffi/struct.OsString.html + #[stable(feature = "path_buf_os_string_methods", since = "1.33.0")] + pub fn capacity(self) -> usize { + self.inner.capacity() + } + + /// Invokes [`clear`] on the underlying instance of [`OsString`]. + /// + /// [`clear`]: ../ffi/struct.OsString.html#method.clear + /// [`OsString`]: ../ffi/struct.OsString.html + #[stable(feature = "path_buf_os_string_methods", since = "1.33.0")] + pub fn clear(mut self) { + self.inner.clear() + } + + /// Invokes [`reserve`] on the underlying instance of [`OsString`]. + /// + /// [`reserve`]: ../ffi/struct.OsString.html#method.reserve + /// [`OsString`]: ../ffi/struct.OsString.html + #[stable(feature = "path_buf_os_string_methods", since = "1.33.0")] + pub fn reserve(mut self, additional: usize) { + self.inner.reserve(additional) + } + + /// Invokes [`reserve_exact`] on the underlying instance of [`OsString`]. + /// + /// [`reserve_exact`]: ../ffi/struct.OsString.html#method.reserve_exact + /// [`OsString`]: ../ffi/struct.OsString.html + #[stable(feature = "path_buf_os_string_methods", since = "1.33.0")] + pub fn reserve_exact(mut self, additional: usize) { + self.inner.reserve_exact(additional) + } + + /// Invokes [`shrink_to_fit`] on the underlying instance of [`OsString`]. + /// + /// [`shrink_to_fit`]: ../ffi/struct.OsString.html#method.shrink_to_fit + /// [`OsString`]: ../ffi/struct.OsString.html + #[stable(feature = "path_buf_os_string_methods", since = "1.33.0")] + pub fn shrink_to_fit(mut self) { + self.inner.shrink_to_fit() + } + + /// Invokes [`shrink_to`] on the underlying instance of [`OsString`]. + /// + /// [`shrink_to`]: ../ffi/struct.OsString.html#method.shrink_to + /// [`OsString`]: ../ffi/struct.OsString.html + #[stable(feature = "path_buf_os_string_methods", since = "1.33.0")] + pub fn shrink_to(mut self, min_capacity: usize) { + self.inner.shrink_to(min_capacity) + } } #[stable(feature = "box_from_path", since = "1.17.0")] From dad211ef9fdcef5328813a1907d323303f09fc6c Mon Sep 17 00:00:00 2001 From: Andre Bogus Date: Mon, 3 Dec 2018 18:16:20 +0100 Subject: [PATCH 05/10] Modify doctest's auto-`fn main()` to allow `Result`s This lets the default `fn main()` unwrap any `Result`s, which allows the use of `?` in most tests without adding it manually. --- src/doc/rustdoc/src/documentation-tests.md | 17 +++++++++++++++ src/librustdoc/test.rs | 14 +++++++++---- src/test/rustdoc/process-termination.rs | 24 ++++++++++++++++++++++ 3 files changed, 51 insertions(+), 4 deletions(-) create mode 100644 src/test/rustdoc/process-termination.rs diff --git a/src/doc/rustdoc/src/documentation-tests.md b/src/doc/rustdoc/src/documentation-tests.md index dd8dcb7ff9bd2..020ffe4e1df87 100644 --- a/src/doc/rustdoc/src/documentation-tests.md +++ b/src/doc/rustdoc/src/documentation-tests.md @@ -236,6 +236,23 @@ appears to the reader as the initial idea but works with doc tests: /// ``` ``` +As of version 1.34.0, one can also omit the `fn main()`, but you will have to +disambiguate the error type: + +```ignore +/// ``` +/// use std::io; +/// let mut input = String::new(); +/// io::stdin().read_line(&mut input)?; +/// # Ok::<(), io:Error>(()) +/// ``` +``` + +This is an unfortunate consequence of the `?` operator adding an implicit +conversion, so type inference fails because the type is not unique. Please note +that you must write the `(())` in one sequence without intermediate whitespace +so that rustdoc understands you want an implicit `Result`-returning function. + ## Documenting macros Here’s an example of documenting a macro: diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 4d870daac4d03..133edb77051a6 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -470,13 +470,19 @@ pub fn make_test(s: &str, } } - if dont_insert_main || already_has_main { + // FIXME: This code cannot yet handle no_std test cases yet + if dont_insert_main || already_has_main || prog.contains("![no_std]") { prog.push_str(everything_else); } else { - prog.push_str("fn main() {\n"); + let returns_result = everything_else.trim_end().ends_with("(())"); + let (main_pre, main_post) = if returns_result { + ("fn main() { fn _inner() -> Result<(), impl core::fmt::Debug> {", + "}\n_inner().unwrap() }") + } else { + ("fn main() {\n", "\n}") + }; + prog.extend([main_pre, everything_else, main_post].iter().cloned()); line_offset += 1; - prog.push_str(everything_else); - prog.push_str("\n}"); } debug!("final doctest:\n{}", prog); diff --git a/src/test/rustdoc/process-termination.rs b/src/test/rustdoc/process-termination.rs new file mode 100644 index 0000000000000..32258792b6e8b --- /dev/null +++ b/src/test/rustdoc/process-termination.rs @@ -0,0 +1,24 @@ +// compile-flags:--test + +/// A check of using various process termination strategies +/// +/// # Examples +/// +/// ```rust +/// assert!(true); // this returns `()`, all is well +/// ``` +/// +/// You can also simply return `Ok(())`, but you'll need to disambiguate the +/// type using turbofish, because we cannot infer the type: +/// +/// ```rust +/// Ok::<(), &'static str>(()) +/// ``` +/// +/// You can err with anything that implements `Debug`: +/// +/// ```rust,should_panic +/// Err("This is returned from `main`, leading to panic")?; +/// Ok::<(), &'static str>(()) +/// ``` +pub fn check_process_termination() {} From dbf60d9ca1db6fb1ae296f25af02b27b8264577d Mon Sep 17 00:00:00 2001 From: Aaron Stillwell Date: Sun, 17 Feb 2019 16:41:05 +0000 Subject: [PATCH 06/10] Fixes for implementation of PathBuf methods (aliases for OsString) - Fixed incorrect `mut` usage - Fixed style in accordance with tidy - Marked all methods as unstable - Changed feature identifier to path_buf_alias_os_string_methods --- src/libstd/path.rs | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 3e7949565507e..0761b1d0a8fe6 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -1137,7 +1137,7 @@ impl PathBuf { /// /// ``` /// use std::path::PathBuf; - /// + /// /// let path = PathBuf::new(); /// ``` #[stable(feature = "rust1", since = "1.0.0")] @@ -1145,26 +1145,26 @@ impl PathBuf { PathBuf { inner: OsString::new() } } - /// Creates a new `PathBuf` with a given capacity used to create the + /// Creates a new `PathBuf` with a given capacity used to create the /// internal [`OsString`]. See [`with_capacity`] defined on [`OsString`]. /// /// # Examples - /// + /// /// ``` /// use std::path::PathBuf; - /// + /// /// let path = PathBuf::with_capacity(10); /// let capacity = path.capacity(); - /// + /// /// // This push is done without reallocating /// path.push(r"C:\"); /// /// assert_eq!(capacity, path.capacity()); /// ``` - /// + /// /// [`with_capacity`]: ../ffi/struct.OsString.html#method.with_capacity /// [`OsString`]: ../ffi/struct.OsString.html - #[stable(feature = "path_buf_os_string_methods", since = "1.33.0")] + #[unstable(feature = "path_buf_alias_os_string_methods", issue = "58234")] pub fn with_capacity(capacity: usize) -> PathBuf { PathBuf { inner: OsString::with_capacity(capacity) @@ -1404,8 +1404,8 @@ impl PathBuf { /// /// [`capacity`]: ../ffi/struct.OsString.html#method.capacity /// [`OsString`]: ../ffi/struct.OsString.html - #[stable(feature = "path_buf_os_string_methods", since = "1.33.0")] - pub fn capacity(self) -> usize { + #[unstable(feature = "path_buf_alias_os_string_methods", issue = "58234")] + pub fn capacity(&self) -> usize { self.inner.capacity() } @@ -1413,8 +1413,8 @@ impl PathBuf { /// /// [`clear`]: ../ffi/struct.OsString.html#method.clear /// [`OsString`]: ../ffi/struct.OsString.html - #[stable(feature = "path_buf_os_string_methods", since = "1.33.0")] - pub fn clear(mut self) { + #[unstable(feature = "path_buf_alias_os_string_methods", issue = "58234")] + pub fn clear(&mut self) { self.inner.clear() } @@ -1422,8 +1422,8 @@ impl PathBuf { /// /// [`reserve`]: ../ffi/struct.OsString.html#method.reserve /// [`OsString`]: ../ffi/struct.OsString.html - #[stable(feature = "path_buf_os_string_methods", since = "1.33.0")] - pub fn reserve(mut self, additional: usize) { + #[unstable(feature = "path_buf_alias_os_string_methods", issue = "58234")] + pub fn reserve(&mut self, additional: usize) { self.inner.reserve(additional) } @@ -1431,8 +1431,8 @@ impl PathBuf { /// /// [`reserve_exact`]: ../ffi/struct.OsString.html#method.reserve_exact /// [`OsString`]: ../ffi/struct.OsString.html - #[stable(feature = "path_buf_os_string_methods", since = "1.33.0")] - pub fn reserve_exact(mut self, additional: usize) { + #[unstable(feature = "path_buf_alias_os_string_methods", issue = "58234")] + pub fn reserve_exact(&mut self, additional: usize) { self.inner.reserve_exact(additional) } @@ -1440,8 +1440,8 @@ impl PathBuf { /// /// [`shrink_to_fit`]: ../ffi/struct.OsString.html#method.shrink_to_fit /// [`OsString`]: ../ffi/struct.OsString.html - #[stable(feature = "path_buf_os_string_methods", since = "1.33.0")] - pub fn shrink_to_fit(mut self) { + #[unstable(feature = "path_buf_alias_os_string_methods", issue = "58234")] + pub fn shrink_to_fit(&mut self) { self.inner.shrink_to_fit() } @@ -1449,8 +1449,8 @@ impl PathBuf { /// /// [`shrink_to`]: ../ffi/struct.OsString.html#method.shrink_to /// [`OsString`]: ../ffi/struct.OsString.html - #[stable(feature = "path_buf_os_string_methods", since = "1.33.0")] - pub fn shrink_to(mut self, min_capacity: usize) { + #[unstable(feature = "path_buf_alias_os_string_methods", issue = "58234")] + pub fn shrink_to(&mut self, min_capacity: usize) { self.inner.shrink_to(min_capacity) } } From 35d8c4400dcf346bbddfe53ddc48125b148b29bb Mon Sep 17 00:00:00 2001 From: Aaron Stillwell Date: Sun, 17 Feb 2019 17:14:10 +0000 Subject: [PATCH 07/10] Changed feature gate for new PathBuf methods Feature gate changed to `path_buf_capacity` as per advice from @Mark-Simulacrum --- src/libstd/path.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 0761b1d0a8fe6..735714aca104c 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -1164,7 +1164,7 @@ impl PathBuf { /// /// [`with_capacity`]: ../ffi/struct.OsString.html#method.with_capacity /// [`OsString`]: ../ffi/struct.OsString.html - #[unstable(feature = "path_buf_alias_os_string_methods", issue = "58234")] + #[unstable(feature = "path_buf_capacity", issue = "58234")] pub fn with_capacity(capacity: usize) -> PathBuf { PathBuf { inner: OsString::with_capacity(capacity) @@ -1404,7 +1404,7 @@ impl PathBuf { /// /// [`capacity`]: ../ffi/struct.OsString.html#method.capacity /// [`OsString`]: ../ffi/struct.OsString.html - #[unstable(feature = "path_buf_alias_os_string_methods", issue = "58234")] + #[unstable(feature = "path_buf_capacity", issue = "58234")] pub fn capacity(&self) -> usize { self.inner.capacity() } @@ -1413,7 +1413,7 @@ impl PathBuf { /// /// [`clear`]: ../ffi/struct.OsString.html#method.clear /// [`OsString`]: ../ffi/struct.OsString.html - #[unstable(feature = "path_buf_alias_os_string_methods", issue = "58234")] + #[unstable(feature = "path_buf_capacity", issue = "58234")] pub fn clear(&mut self) { self.inner.clear() } @@ -1422,7 +1422,7 @@ impl PathBuf { /// /// [`reserve`]: ../ffi/struct.OsString.html#method.reserve /// [`OsString`]: ../ffi/struct.OsString.html - #[unstable(feature = "path_buf_alias_os_string_methods", issue = "58234")] + #[unstable(feature = "path_buf_capacity", issue = "58234")] pub fn reserve(&mut self, additional: usize) { self.inner.reserve(additional) } @@ -1431,7 +1431,7 @@ impl PathBuf { /// /// [`reserve_exact`]: ../ffi/struct.OsString.html#method.reserve_exact /// [`OsString`]: ../ffi/struct.OsString.html - #[unstable(feature = "path_buf_alias_os_string_methods", issue = "58234")] + #[unstable(feature = "path_buf_capacity", issue = "58234")] pub fn reserve_exact(&mut self, additional: usize) { self.inner.reserve_exact(additional) } @@ -1440,7 +1440,7 @@ impl PathBuf { /// /// [`shrink_to_fit`]: ../ffi/struct.OsString.html#method.shrink_to_fit /// [`OsString`]: ../ffi/struct.OsString.html - #[unstable(feature = "path_buf_alias_os_string_methods", issue = "58234")] + #[unstable(feature = "path_buf_capacity", issue = "58234")] pub fn shrink_to_fit(&mut self) { self.inner.shrink_to_fit() } @@ -1449,7 +1449,7 @@ impl PathBuf { /// /// [`shrink_to`]: ../ffi/struct.OsString.html#method.shrink_to /// [`OsString`]: ../ffi/struct.OsString.html - #[unstable(feature = "path_buf_alias_os_string_methods", issue = "58234")] + #[unstable(feature = "path_buf_capacity", issue = "58234")] pub fn shrink_to(&mut self, min_capacity: usize) { self.inner.shrink_to(min_capacity) } From ee948d99815b73359214f28a8f1eb69f3091a026 Mon Sep 17 00:00:00 2001 From: emlai Date: Sun, 17 Feb 2019 20:41:18 +0200 Subject: [PATCH 08/10] Add regression test for a specialization-related ICE (#39448) --- src/test/ui/specialization/issue-39448.rs | 50 +++++++++++++++++++ src/test/ui/specialization/issue-39448.stderr | 12 +++++ 2 files changed, 62 insertions(+) create mode 100644 src/test/ui/specialization/issue-39448.rs create mode 100644 src/test/ui/specialization/issue-39448.stderr diff --git a/src/test/ui/specialization/issue-39448.rs b/src/test/ui/specialization/issue-39448.rs new file mode 100644 index 0000000000000..8ac6d8e9311fc --- /dev/null +++ b/src/test/ui/specialization/issue-39448.rs @@ -0,0 +1,50 @@ +#![feature(specialization)] + +// Regression test for a specialization-related ICE (#39448). + +trait A: Sized { + fn foo(self, _: Self) -> Self { + self + } +} + +impl A for u8 {} +impl A for u16 {} + +impl FromA for u16 { + fn from(x: u8) -> u16 { + x as u16 + } +} + +trait FromA { + fn from(T) -> Self; +} + +impl> FromA for U { + default fn from(x: T) -> Self { + ToA::to(x) + } +} + +trait ToA { + fn to(self) -> T; +} + +impl ToA for T +where + U: FromA, +{ + fn to(self) -> U { + U::from(self) + } +} + +#[allow(dead_code)] +fn foo(x: T, y: U) -> U { + x.foo(y.to()).to() //~ ERROR overflow evaluating the requirement +} + +fn main() { + let z = foo(8u8, 1u16); +} diff --git a/src/test/ui/specialization/issue-39448.stderr b/src/test/ui/specialization/issue-39448.stderr new file mode 100644 index 0000000000000..0b0fd2c4af591 --- /dev/null +++ b/src/test/ui/specialization/issue-39448.stderr @@ -0,0 +1,12 @@ +error[E0275]: overflow evaluating the requirement `T: FromA` + --> $DIR/issue-39448.rs:45:13 + | +LL | x.foo(y.to()).to() //~ ERROR overflow evaluating the requirement + | ^^ + | + = note: required because of the requirements on the impl of `FromA` for `T` + = note: required because of the requirements on the impl of `ToA` for `U` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0275`. From 55c25f8c8d0550f6e866e022a65bf6a331bd3ea8 Mon Sep 17 00:00:00 2001 From: Guy Taylor Date: Sun, 17 Feb 2019 14:18:03 +0000 Subject: [PATCH 09/10] Fix doc for rustc "-g" flag The rustc "-g" CLI flag was miss documented to be a synonym of "-C debug-level=2" and not the correct "-C debuginfo=2". --- src/doc/rustc/src/command-line-arguments.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc/src/command-line-arguments.md b/src/doc/rustc/src/command-line-arguments.md index b60c55240140e..380e9b3d388bf 100644 --- a/src/doc/rustc/src/command-line-arguments.md +++ b/src/doc/rustc/src/command-line-arguments.md @@ -42,7 +42,7 @@ This flag prints out various information about the compiler. ## `-g`: include debug information -A synonym for `-C debug-level=2`. +A synonym for `-C debuginfo=2`. ## `-O`: optimize your code From 88e462bf7fe9bcaccf2b0a43669067493ad919a4 Mon Sep 17 00:00:00 2001 From: Guy Taylor Date: Sun, 17 Feb 2019 18:00:33 +0000 Subject: [PATCH 10/10] Add links to codegen docs for rustc synonym flags The rustc "-g" and "-o" fags are synonyms of the "-c" codegen flags. This adds a link to the codegen docs for each synonym. --- src/doc/rustc/src/command-line-arguments.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/rustc/src/command-line-arguments.md b/src/doc/rustc/src/command-line-arguments.md index 380e9b3d388bf..d7e789b5a11f7 100644 --- a/src/doc/rustc/src/command-line-arguments.md +++ b/src/doc/rustc/src/command-line-arguments.md @@ -42,11 +42,11 @@ This flag prints out various information about the compiler. ## `-g`: include debug information -A synonym for `-C debuginfo=2`. +A synonym for `-C debuginfo=2`, for more see [here](codegen-options/index.html#debuginfo). ## `-O`: optimize your code -A synonym for `-C opt-level=2`. +A synonym for `-C opt-level=2`, for more see [here](codegen-options/index.html#opt-level). ## `-o`: filename of the output