From 5451b722b0d564e8e376ef89920de5d97b01eac3 Mon Sep 17 00:00:00 2001 From: Federico Mena Quintero Date: Fri, 22 Sep 2017 17:31:18 -0500 Subject: Expand the introduction to the ffi module. We describe the representation of C strings, and the purpose of OsString/OsStr. Part of https://github.com/rust-lang/rust/issues/29354 --- src/libstd/ffi/mod.rs | 101 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 100 insertions(+), 1 deletion(-) (limited to 'src/libstd') diff --git a/src/libstd/ffi/mod.rs b/src/libstd/ffi/mod.rs index ca1ff18f1ca..6c8ddfc3944 100644 --- a/src/libstd/ffi/mod.rs +++ b/src/libstd/ffi/mod.rs @@ -8,7 +8,106 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Utilities related to FFI bindings. +//! This module provides utilities to handle C-like strings. It is +//! mainly of use for FFI (Foreign Function Interface) bindings and +//! code that needs to exchange C-like strings with other languages. +//! +//! # Overview +//! +//! Rust represents owned strings with the [`String`] type, and +//! borrowed slices of strings with the [`str`] primitive. Both are +//! always in UTF-8 encoding, and may contain nul bytes in the middle, +//! i.e. if you look at the bytes that make up the string, there may +//! be a `0` among them. Both `String` and `str` know their length; +//! there are no nul terminators at the end of strings like in C. +//! +//! C strings are different from Rust strings: +//! +//! * **Encodings** - C strings may have different encodings. If +//! you are bringing in strings from C APIs, you should check what +//! encoding you are getting. Rust strings are always UTF-8. +//! +//! * **Character width** - C strings may use "normal" or "wide" +//! characters, i.e. `char` or `wchar_t`, respectively. The C +//! standard leaves the actual sizes of those types open to +//! interpretation, but defines different APIs for strings made up of +//! each character type. Rust strings are always UTF-8, so different +//! Unicode characters will be encoded in a variable number of bytes +//! each. The Rust type [`char`] represents a '[Unicode +//! scalar value]', which is similar to, but not the same as, a +//! '[Unicode code point]'. +//! +//! * **Nul terminators and implicit string lengths** - Often, C +//! strings are nul-terminated, i.e. they have a `0` character at the +//! end. The length of a string buffer is not known *a priori*; +//! instead, to compute the length of a string, C code must manually +//! call a function like `strlen()` for `char`-based strings, or +//! `wcslen()` for `wchar_t`-based ones. Those functions return the +//! number of characters in the string excluding the nul terminator, +//! so the buffer length is really `len+1` characters. Rust strings +//! don't have a nul terminator, and they always know their length. +//! +//! * **No nul characters in the middle of the string** - When C +//! strings have a nul terminator character, this usually means that +//! they cannot have nul characters in the middle — a nul character +//! would essentially truncate the string. Rust strings *can* have +//! nul characters in the middle, since they don't use nul +//! terminators. +//! +//! # Representations of non-Rust strings +//! +//! [`CString`] and [`CStr`] are useful when you need to transfer +//! UTF-8 strings to and from C, respectively: +//! +//! * **From Rust to C:** [`CString`] represents an owned, C-friendly +//! UTF-8 string: it is valid UTF-8, it is nul-terminated, and has no +//! nul characters in the middle. Rust code can create a `CString` +//! out of a normal string (provided that the string doesn't have nul +//! characters in the middle), and then use a variety of methods to +//! obtain a raw `*mut u8` that can then be passed as an argument to C +//! functions. +//! +//! * **From C to Rust:** [`CStr`] represents a borrowed C string; it +//! is what you would use to wrap a raw `*const u8` that you got from +//! a C function. A `CStr` is just guaranteed to be a nul-terminated +//! array of bytes; the UTF-8 validation step only happens when you +//! request to convert it to a `&str`. +//! +//! [`OsString`] and [`OsStr`] are useful when you need to transfer +//! strings to and from operating system calls. If you need Rust +//! strings out of them, they can take care of conversion to and from +//! the operating system's preferred form for strings — of course, it +//! may not be possible to convert all valid operating system strings +//! into valid UTF-8; the `OsString` and `OsStr` functions let you know +//! when this is the case. +//! +//! * [`OsString`] represents an owned string in whatever +//! representation the operating system prefers. In the Rust standard +//! library, various APIs that transfer strings to/from the operating +//! system use `OsString` instead of plain strings. For example, +//! [`env::var_os()`] is used to query environment variables; it +//! returns an `Option`. If the environment variable exists +//! you will get a `Some(os_string)`, which you can *then* try to +//! convert to a Rust string. This yields a [`Result<>`], so that +//! your code can detect errors in case the environment variable did +//! not in fact contain valid Unicode data. +//! +//! * [`OsStr`] represents a borrowed reference to a string in a format that +//! can be passed to the operating system. It can be converted into +//! an UTF-8 Rust string slice in a similar way to `OsString`. +//! +//! [`String`]: ../string/struct.String.html +//! [`str`]: ../primitive.str.html +//! [`char`]: ../primitive.char.html +//! [Unicode scalar value]: http://www.unicode.org/glossary/#unicode_scalar_value +//! [Unicode code point]: http://www.unicode.org/glossary/#code_point +//! [`CString`]: struct.CString.html +//! [`CStr`]: struct.CStr.html +//! [`OsString`]: struct.OsString.html +//! [`OsStr`]: struct.OsStr.html +//! [`env::set_var()`]: ../env/fn.set_var.html +//! [`env::var_os()`]: ../env/fn.var_os.html +//! [`Result<>`]: ../result/enum.Result.html #![stable(feature = "rust1", since = "1.0.0")] -- cgit 1.4.1-3-g733a5 From 8da694a42138ac74047d989abd3c7daf0edcbe93 Mon Sep 17 00:00:00 2001 From: Federico Mena Quintero Date: Fri, 22 Sep 2017 20:36:44 -0500 Subject: Overhaul the ffi::CString docs Explain the struct's reason for being, and its most common usage patterns. Add a bunch of links. Clarify the method docs a bit. Part of https://github.com/rust-lang/rust/issues/29354 --- src/libstd/ffi/c_str.rs | 146 ++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 115 insertions(+), 31 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs index 7992aefcb42..f0a691fd668 100644 --- a/src/libstd/ffi/c_str.rs +++ b/src/libstd/ffi/c_str.rs @@ -23,19 +23,68 @@ use ptr; use slice; use str::{self, Utf8Error}; -/// A type representing an owned C-compatible string. +/// A type representing an owned, C-compatible, UTF-8 string. /// -/// This type serves the primary purpose of being able to safely generate a -/// C-compatible string from a Rust byte slice or vector. An instance of this +/// This type serves the purpose of being able to safely generate a +/// C-compatible UTF-8 string from a Rust byte slice or vector. An instance of this /// type is a static guarantee that the underlying bytes contain no interior 0 -/// bytes and the final byte is 0. +/// bytes ("nul characters") and that the final byte is 0 ("nul terminator"). /// -/// A `CString` is created from either a byte slice or a byte vector. A [`u8`] -/// slice can be obtained with the `as_bytes` method. Slices produced from a -/// `CString` do *not* contain the trailing nul terminator unless otherwise -/// specified. +/// `CString` is to [`CStr`] as [`String`] is to [`&str`]: the former +/// in each pair are owned strings; the latter are borrowed +/// references. /// +/// # Creating a `CString` +/// +/// A `CString` is created from either a byte slice or a byte vector, +/// or anything that implements [`Into`]`<`[`Vec`]`<`[`u8`]`>>` (for +/// example, you can build a `CString` straight out of a [`String`] or +/// a [`&str`], since both implement that trait). +/// +/// The [`new`] method will actually check that the provided `&[u8]` +/// does not have 0 bytes in the middle, and return an error if it +/// finds one. +/// +/// # Extracting a raw pointer to the whole C string +/// +/// `CString` implements a [`as_ptr`] method through the [`Deref`] +/// trait. This method will give you a `*const c_char` which you can +/// feed directly to extern functions that expect a nul-terminated +/// string, like C's `strdup()`. +/// +/// # Extracting a slice of the whole C string +/// +/// Alternatively, you can obtain a `&[`[`u8`]`]` slice from a +/// `CString` with the [`as_bytes`] method. Slices produced in this +/// way do *not* contain the trailing nul terminator. This is useful +/// when you will be calling an extern function that takes a `*const +/// u8` argument which is not necessarily nul-terminated, plus another +/// argument with the length of the string — like C's `strndup()`. +/// You can of course get the slice's length with its +/// [`len`][slice.len] method. +/// +/// If you need a `&[`[`u8`]`]` slice *with* the nul terminator, you +/// can use [`as_bytes_with_nul`] instead. +/// +/// Once you have the kind of slice you need (with or without a nul +/// terminator), you can call the slice's own +/// [`as_ptr`][slice.as_ptr] method to get a raw pointer to pass to +/// extern functions. See the documentation for that function for a +/// discussion on ensuring the lifetime of the raw pointer. +/// +/// [`Into`]: ../convert/trait.Into.html +/// [`Vec`]: ../vec/struct.Vec.html +/// [`String`]: ../string/struct.String.html +/// [`&str`]: ../primitive.str.html /// [`u8`]: ../primitive.u8.html +/// [`new`]: #method.new +/// [`as_bytes`]: #method.as_bytes +/// [`as_bytes_with_nul`]: #method.as_bytes_with_nul +/// [`as_ptr`]: #method.as_ptr +/// [slice.as_ptr]: ../primitive.slice.html#method.as_ptr +/// [slice.len]: ../primitive.slice.html#method.len +/// [`Deref`]: ../ops/trait.Deref.html +/// [`CStr`]: struct.CStr.html /// /// # Examples /// @@ -48,6 +97,8 @@ use str::{self, Utf8Error}; /// fn my_printer(s: *const c_char); /// } /// +/// // We are certain that our string doesn't have 0 bytes in the middle, +/// // so we can .unwrap() /// let c_to_print = CString::new("Hello, world!").unwrap(); /// unsafe { /// my_printer(c_to_print.as_ptr()); @@ -58,7 +109,7 @@ use str::{self, Utf8Error}; /// # Safety /// /// `CString` is intended for working with traditional C-style strings -/// (a sequence of non-null bytes terminated by a single null byte); the +/// (a sequence of non-nul bytes terminated by a single nul byte); the /// primary use case for these kinds of strings is interoperating with C-like /// code. Often you will need to transfer ownership to/from that external /// code. It is strongly recommended that you thoroughly read through the @@ -215,8 +266,11 @@ pub struct IntoStringError { impl CString { /// Creates a new C-compatible string from a container of bytes. /// - /// This method will consume the provided data and use the underlying bytes - /// to construct a new string, ensuring that there is a trailing 0 byte. + /// This method will consume the provided data and use the + /// underlying bytes to construct a new string, ensuring that + /// there is a trailing 0 byte. This trailing 0 byte will be + /// appended by this method; the provided data should *not* + /// contain any 0 bytes in it. /// /// # Examples /// @@ -234,9 +288,11 @@ impl CString { /// /// # Errors /// - /// This function will return an error if the bytes yielded contain an - /// internal 0 byte. The error returned will contain the bytes as well as + /// This function will return an error if the supplied bytes contain an + /// internal 0 byte. The [`NulError`] returned will contain the bytes as well as /// the position of the nul byte. + /// + /// [`NulError`]: struct.NulError.html #[stable(feature = "rust1", since = "1.0.0")] pub fn new>>(t: T) -> Result { Self::_new(t.into()) @@ -249,8 +305,8 @@ impl CString { } } - /// Creates a C-compatible string from a byte vector without checking for - /// interior 0 bytes. + /// Creates a C-compatible string by consuming a byte vector, + /// without checking for interior 0 bytes. /// /// This method is equivalent to [`new`] except that no runtime assertion /// is made that `v` contains no 0 bytes, and it requires an actual @@ -275,7 +331,7 @@ impl CString { CString { inner: v.into_boxed_slice() } } - /// Retakes ownership of a `CString` that was transferred to C. + /// Retakes ownership of a `CString` that was transferred to C via [`into_raw`]. /// /// Additionally, the length of the string will be recalculated from the pointer. /// @@ -286,7 +342,14 @@ impl CString { /// ownership of a string that was allocated by foreign code) is likely to lead /// to undefined behavior or allocator corruption. /// + /// > **Note:** If you need to borrow a string that was allocated by + /// > foreign code, use [`CStr`]. If you need to take ownership of + /// > a string that was allocated by foreign code, you will need to + /// > make your own provisions for freeing it appropriately, likely + /// > with the foreign code's API to do that. + /// /// [`into_raw`]: #method.into_raw + /// [`CStr`]: struct.CStr.html /// /// # Examples /// @@ -315,11 +378,11 @@ impl CString { CString { inner: mem::transmute(slice) } } - /// Transfers ownership of the string to a C caller. + /// Consumes the `CString` and transfers ownership of the string to a C caller. /// - /// The pointer must be returned to Rust and reconstituted using + /// The pointer which this function returns must be returned to Rust and reconstituted using /// [`from_raw`] to be properly deallocated. Specifically, one - /// should *not* use the standard C `free` function to deallocate + /// should *not* use the standard C `free()` function to deallocate /// this string. /// /// Failure to call [`from_raw`] will lead to a memory leak. @@ -356,6 +419,22 @@ impl CString { /// On failure, ownership of the original `CString` is returned. /// /// [`String`]: ../string/struct.String.html + /// + /// # Examples + /// + /// ``` + /// use std::ffi::CString; + /// + /// let valid_utf8 = vec![b'f', b'o', b'o']; + /// let cstring = CString::new(valid_utf8).unwrap(); + /// assert_eq!(cstring.into_string().unwrap(), "foo"); + /// + /// let invalid_utf8 = vec![b'f', 0xff, b'o', b'o']; + /// let cstring = CString::new(invalid_utf8).unwrap(); + /// let err = cstring.into_string().err().unwrap(); + /// assert_eq!(err.utf8_error().valid_up_to(), 1); + /// ``` + #[stable(feature = "cstring_into", since = "1.7.0")] pub fn into_string(self) -> Result { String::from_utf8(self.into_bytes()) @@ -365,10 +444,11 @@ impl CString { }) } - /// Returns the underlying byte buffer. + /// Consumes the `CString` and returns the underlying byte buffer. /// - /// The returned buffer does **not** contain the trailing nul separator and - /// it is guaranteed to not have any interior nul bytes. + /// The returned buffer does **not** contain the trailing nul + /// terminator, and it is guaranteed to not have any interior nul + /// bytes. /// /// # Examples /// @@ -388,7 +468,7 @@ impl CString { } /// Equivalent to the [`into_bytes`] function except that the returned vector - /// includes the trailing nul byte. + /// includes the trailing nul terminator. /// /// [`into_bytes`]: #method.into_bytes /// @@ -408,8 +488,12 @@ impl CString { /// Returns the contents of this `CString` as a slice of bytes. /// - /// The returned slice does **not** contain the trailing nul separator and - /// it is guaranteed to not have any interior nul bytes. + /// The returned slice does **not** contain the trailing nul + /// terminator, and it is guaranteed to not have any interior nul + /// bytes. If you need the nul terminator, use + /// [`as_bytes_with_nul`] instead. + /// + /// [`as_bytes_with_nul`]: #method.as_bytes_with_nul /// /// # Examples /// @@ -427,7 +511,7 @@ impl CString { } /// Equivalent to the [`as_bytes`] function except that the returned slice - /// includes the trailing nul byte. + /// includes the trailing nul terminator. /// /// [`as_bytes`]: #method.as_bytes /// @@ -598,8 +682,8 @@ impl Default for Box { } impl NulError { - /// Returns the position of the nul byte in the slice that was provided to - /// [`CString::new`]. + /// Returns the position of the nul byte in the slice that caused + /// [`CString::new`] to fail. /// /// [`CString::new`]: struct.CString.html#method.new /// @@ -766,7 +850,7 @@ impl CStr { /// assert!(cstr.is_ok()); /// ``` /// - /// Creating a `CStr` without a trailing nul byte is an error: + /// Creating a `CStr` without a trailing nul terminator is an error: /// /// ``` /// use std::ffi::CStr; @@ -869,7 +953,7 @@ impl CStr { /// requires a linear amount of work to be done) and then return the /// resulting slice of `u8` elements. /// - /// The returned slice will **not** contain the trailing nul that this C + /// The returned slice will **not** contain the trailing nul terminator that this C /// string has. /// /// > **Note**: This method is currently implemented as a 0-cost cast, but @@ -894,7 +978,7 @@ impl CStr { /// Converts this C string to a byte slice containing the trailing 0 byte. /// /// This function is the equivalent of [`to_bytes`] except that it will retain - /// the trailing nul instead of chopping it off. + /// the trailing nul terminator instead of chopping it off. /// /// > **Note**: This method is currently implemented as a 0-cost cast, but /// > it is planned to alter its definition in the future to perform the -- cgit 1.4.1-3-g733a5 From 2cb2a0606a47a3e2b7777ef099692c735d772b32 Mon Sep 17 00:00:00 2001 From: Federico Mena Quintero Date: Sun, 24 Sep 2017 20:12:51 -0500 Subject: Overhaul the ffi::CStr documentation. --- src/libstd/ffi/c_str.rs | 76 ++++++++++++++++++++++++++++++------------------- 1 file changed, 46 insertions(+), 30 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs index f0a691fd668..a10d0a4214b 100644 --- a/src/libstd/ffi/c_str.rs +++ b/src/libstd/ffi/c_str.rs @@ -128,17 +128,21 @@ pub struct CString { /// Representation of a borrowed C string. /// -/// This dynamically sized type is only safely constructed via a borrowed -/// version of an instance of `CString`. This type can be constructed from a raw -/// C string as well and represents a C string borrowed from another location. +/// This type represents a borrowed reference to a nul-terminated +/// array of bytes. It can be constructed safely from a `&[`[`u8`]`]` +/// slice, or unsafely from a raw `*const c_char`. It can then be +/// converted to a Rust [`&str`] by performing UTF-8 validation, or +/// into an owned [`CString`]. +/// +/// `CStr` is to [`CString`] as [`&str`] is to [`String`]: the former +/// in each pair are borrowed references; the latter are owned +/// strings. /// /// Note that this structure is **not** `repr(C)` and is not recommended to be -/// placed in the signatures of FFI functions. Instead safe wrappers of FFI +/// placed in the signatures of FFI functions. Instead, safe wrappers of FFI /// functions may leverage the unsafe [`from_ptr`] constructor to provide a safe /// interface to other consumers. /// -/// [`from_ptr`]: #method.from_ptr -/// /// # Examples /// /// Inspecting a foreign C string: @@ -151,7 +155,7 @@ pub struct CString { /// /// unsafe { /// let slice = CStr::from_ptr(my_string()); -/// println!("string length: {}", slice.to_bytes().len()); +/// println!("string buffer size without nul terminator: {}", slice.to_bytes().len()); /// } /// ``` /// @@ -173,8 +177,6 @@ pub struct CString { /// /// Converting a foreign C string into a Rust [`String`]: /// -/// [`String`]: ../string/struct.String.html -/// /// ```no_run /// use std::ffi::CStr; /// use std::os::raw::c_char; @@ -189,6 +191,12 @@ pub struct CString { /// /// println!("string: {}", my_string_safe()); /// ``` +/// +/// [`u8`]: ../primitive.u8.html +/// [`&str`]: ../primitive.str.html +/// [`String`]: ../string/struct.String.html +/// [`CString`]: struct.CString.html +/// [`from_ptr`]: #method.from_ptr #[derive(Hash)] #[stable(feature = "rust1", since = "1.0.0")] pub struct CStr { @@ -215,8 +223,10 @@ pub struct CStr { #[stable(feature = "rust1", since = "1.0.0")] pub struct NulError(usize, Vec); -/// An error returned from [`CStr::from_bytes_with_nul`] to indicate that a nul -/// byte was found too early in the slice provided or one wasn't found at all. +/// An error returned from [`CStr::from_bytes_with_nul`] to indicate +/// that a nul byte was found too early in the slice provided, or one +/// wasn't found at all. The slice used to create a `CStr` must have one +/// and only one nul byte at the end of the slice. /// /// [`CStr::from_bytes_with_nul`]: struct.CStr.html#method.from_bytes_with_nul /// @@ -795,9 +805,9 @@ impl fmt::Display for IntoStringError { } impl CStr { - /// Casts a raw C string to a safe C string wrapper. + /// Wraps a raw C string with a safe C string wrapper. /// - /// This function will cast the provided `ptr` to the `CStr` wrapper which + /// This function will wrap the provided `ptr` with a `CStr` wrapper, which /// allows inspection and interoperation of non-owned C strings. This method /// is unsafe for a number of reasons: /// @@ -837,9 +847,9 @@ impl CStr { /// Creates a C string wrapper from a byte slice. /// - /// This function will cast the provided `bytes` to a `CStr` wrapper after - /// ensuring that it is null terminated and does not contain any interior - /// nul bytes. + /// This function will cast the provided `bytes` to a `CStr` + /// wrapper after ensuring that the byte slice is nul-terminated + /// and does not contain any interior nul bytes. /// /// # Examples /// @@ -884,7 +894,7 @@ impl CStr { /// Unsafely creates a C string wrapper from a byte slice. /// /// This function will cast the provided `bytes` to a `CStr` wrapper without - /// performing any sanity checks. The provided slice must be null terminated + /// performing any sanity checks. The provided slice **must** be nul-terminated /// and not contain any interior nul bytes. /// /// # Examples @@ -906,7 +916,7 @@ impl CStr { /// Returns the inner pointer to this C string. /// - /// The returned pointer will be valid for as long as `self` is and points + /// The returned pointer will be valid for as long as `self` is, and points /// to a contiguous region of memory terminated with a 0 byte to represent /// the end of the string. /// @@ -927,9 +937,9 @@ impl CStr { /// ``` /// /// This happens because the pointer returned by `as_ptr` does not carry any - /// lifetime information and the string is deallocated immediately after + /// lifetime information and the [`CString`] is deallocated immediately after /// the `CString::new("Hello").unwrap().as_ptr()` expression is evaluated. - /// To fix the problem, bind the string to a local variable: + /// To fix the problem, bind the `CString` to a local variable: /// /// ```no_run /// use std::ffi::{CString}; @@ -941,6 +951,11 @@ impl CStr { /// *ptr; /// } /// ``` + /// + /// This way, the lifetime of the `CString` in `hello` encompasses + /// the lifetime of `ptr` and the `unsafe` block. + /// + /// [`CString`]: struct.CString.html #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn as_ptr(&self) -> *const c_char { @@ -949,10 +964,6 @@ impl CStr { /// Converts this C string to a byte slice. /// - /// This function will calculate the length of this string (which normally - /// requires a linear amount of work to be done) and then return the - /// resulting slice of `u8` elements. - /// /// The returned slice will **not** contain the trailing nul terminator that this C /// string has. /// @@ -1002,8 +1013,9 @@ impl CStr { /// Yields a [`&str`] slice if the `CStr` contains valid UTF-8. /// - /// This function will calculate the length of this string and check for - /// UTF-8 validity, and then return the [`&str`] if it's valid. + /// If the contents of the `CStr` are valid UTF-8 data, this + /// function will return the corresponding [`&str`] slice. Otherwise, + /// it will return an error with details of where UTF-8 validation failed. /// /// > **Note**: This method is currently implemented to check for validity /// > after a 0-cost cast, but it is planned to alter its definition in the @@ -1031,10 +1043,12 @@ impl CStr { /// Converts a `CStr` into a [`Cow`]`<`[`str`]`>`. /// - /// This function will calculate the length of this string (which normally - /// requires a linear amount of work to be done) and then return the - /// resulting slice as a [`Cow`]`<`[`str`]`>`, replacing any invalid UTF-8 sequences - /// with `U+FFFD REPLACEMENT CHARACTER`. + /// If the contents of the `CStr` are valid UTF-8 data, this + /// function will return a [`Cow`]`::`[`Borrowed`]`(`[`&str`]`)` + /// with the the corresponding [`&str`] slice. Otherwise, it will + /// replace any invalid UTF-8 sequences with `U+FFFD REPLACEMENT + /// CHARACTER` and return a [`Cow`]`::`[`Owned`]`(`[`String`]`)` + /// with the result. /// /// > **Note**: This method is currently implemented to check for validity /// > after a 0-cost cast, but it is planned to alter its definition in the @@ -1042,7 +1056,9 @@ impl CStr { /// > check whenever this method is called. /// /// [`Cow`]: ../borrow/enum.Cow.html + /// [`Borrowed`]: ../borrow/enum.Cow.html#variant.Borrowed /// [`str`]: ../primitive.str.html + /// [`String`]: ../string/struct.String.html /// /// # Examples /// -- cgit 1.4.1-3-g733a5 From 3c5e18f322818f54cd9764031979f29b89a3e80d Mon Sep 17 00:00:00 2001 From: Federico Mena Quintero Date: Mon, 25 Sep 2017 10:53:13 -0500 Subject: Point from the error structs back to the method that created them, like in iterators --- src/libstd/ffi/c_str.rs | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs index a10d0a4214b..01d2b70e423 100644 --- a/src/libstd/ffi/c_str.rs +++ b/src/libstd/ffi/c_str.rs @@ -208,8 +208,13 @@ pub struct CStr { } /// An error returned from [`CString::new`] to indicate that a nul byte was found -/// in the vector provided. +/// in the vector provided. While Rust strings may contain nul bytes in the middle, +/// C strings can't, as that byte would effectively truncate the string. /// +/// This `struct` is created by the [`new`][`CString::new`] method on +/// [`CString`]. See its documentation for more. +/// +/// [`CString`]: struct.CString.html /// [`CString::new`]: struct.CString.html#method.new /// /// # Examples @@ -225,9 +230,15 @@ pub struct NulError(usize, Vec); /// An error returned from [`CStr::from_bytes_with_nul`] to indicate /// that a nul byte was found too early in the slice provided, or one -/// wasn't found at all. The slice used to create a `CStr` must have one -/// and only one nul byte at the end of the slice. +/// wasn't found at all for the nul terminator. The slice used to +/// create a `CStr` must have one and only one nul byte at the end of +/// the slice. +/// +/// This `struct` is created by the +/// [`from_bytes_with_nul`][`CStr::from_bytes_with_nul`] method on +/// [`CStr`]. See its documentation for more. /// +/// [`CStr`]: struct.CStr.html /// [`CStr::from_bytes_with_nul`]: struct.CStr.html#method.from_bytes_with_nul /// /// # Examples @@ -262,9 +273,17 @@ impl FromBytesWithNulError { } } -/// An error returned from [`CString::into_string`] to indicate that a UTF-8 error -/// was encountered during the conversion. +/// An error returned from [`CString::into_string`] to indicate that a +/// UTF-8 error was encountered during the conversion. `CString` is +/// just a wrapper over a buffer of bytes with a nul terminator; +/// [`into_string`][`CString::into_string`] performs UTF-8 validation +/// and may return this error. +/// +/// This `struct` is created by the +/// [`into_string`][`CString::into_string`] method on [`CString`]. See +/// its documentation for more. /// +/// [`CString`]: struct.CString.html /// [`CString::into_string`]: struct.CString.html#method.into_string #[derive(Clone, PartialEq, Eq, Debug)] #[stable(feature = "cstring_into", since = "1.7.0")] -- cgit 1.4.1-3-g733a5 From 155b4b1c5fff6a2a5a87de25e2fbe8c96743efb2 Mon Sep 17 00:00:00 2001 From: Federico Mena Quintero Date: Mon, 25 Sep 2017 12:51:11 -0500 Subject: Module overview for std::os::windows:ffi --- src/libstd/ffi/mod.rs | 2 +- src/libstd/sys/windows/ext/ffi.rs | 56 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 1 deletion(-) (limited to 'src/libstd') diff --git a/src/libstd/ffi/mod.rs b/src/libstd/ffi/mod.rs index 6c8ddfc3944..376e13e3b03 100644 --- a/src/libstd/ffi/mod.rs +++ b/src/libstd/ffi/mod.rs @@ -92,7 +92,7 @@ //! your code can detect errors in case the environment variable did //! not in fact contain valid Unicode data. //! -//! * [`OsStr`] represents a borrowed reference to a string in a format that +//! * [`OsStr`] represents a borrowed string slice in a format that //! can be passed to the operating system. It can be converted into //! an UTF-8 Rust string slice in a similar way to `OsString`. //! diff --git a/src/libstd/sys/windows/ext/ffi.rs b/src/libstd/sys/windows/ext/ffi.rs index 3f6c2827a3f..d6b8896ac09 100644 --- a/src/libstd/sys/windows/ext/ffi.rs +++ b/src/libstd/sys/windows/ext/ffi.rs @@ -9,6 +9,62 @@ // except according to those terms. //! Windows-specific extensions to the primitives in the `std::ffi` module. +//! +//! # Overview +//! +//! For historical reasons, the Windows API uses a form of potentially +//! ill-formed UTF-16 encoding for strings. Specifically, the 16-bit +//! code units in Windows strings may contain [isolated surrogate code +//! points which are not paired together][ill-formed-utf-16]. The +//! Unicode standard requires that surrogate code points (those in the +//! range U+D800 to U+DFFF) always be *paired*, because in the UTF-16 +//! encoding a *surrogate code unit pair* is used to encode a single +//! character. For compatibility with code that does not enforce +//! these pairings, Windows does not enforce them, either. +//! +//! While it is not always possible to convert such a string losslessly into +//! a valid UTF-16 string (or even UTF-8), it is often desirable to be +//! able to round-trip such a string from and to Windows APIs +//! losslessly. For example, some Rust code may be "bridging" some +//! Windows APIs together, just passing `WCHAR` strings among those +//! APIs without ever really looking into the strings. +//! +//! If Rust code *does* need to look into those strings, it can +//! convert them to valid UTF-8, possibly lossily, by substituting +//! invalid sequences with U+FFFD REPLACEMENT CHARACTER, as is +//! conventionally done in other Rust APIs that deal with string +//! encodings. +//! +//! # `OsStringExt` and `OsStrExt` +//! +//! [`OsString`] is the Rust wrapper for owned strings in the +//! preferred representation of the operating system. On Windows, +//! this struct gets augmented with an implementation of the +//! [`OsStringExt`] trait, which has a [`from_wide`] method. This +//! lets you create an [`OsString`] from a `&[u16]` slice; presumably +//! you get such a slice out of a `WCHAR` Windows API. +//! +//! Similarly, [`OsStr`] is the Rust wrapper for borrowed strings from +//! preferred representation of the operating system. On Windows, the +//! [`OsStrExt`] trait provides the [`encode_wide`] method, which +//! outputs an [`EncodeWide`] iterator. You can [`collect`] this +//! iterator, for example, to obtain a `Vec`; you can later get a +//! pointer to this vector's contents and feed it to Windows APIs. +//! +//! These traits, along with [`OsString`] and [`OsStr`], work in +//! conjunction so that it is possible to **round-trip** strings from +//! Windows and back, with no loss of data, even if the strings are +//! ill-formed UTF-16. +//! +//! [ill-formed-utf-16]: https://simonsapin.github.io/wtf-8/#ill-formed-utf-16 +//! [`OsString`]: ../../../ffi/struct.OsString.html +//! [`OsStr`]: ../../../ffi/struct.OsStr.html +//! [`OsStringExt`]: trait.OsStringExt.html +//! [`OsStrExt`]: trait.OsStrExt.html +//! [`EncodeWide`]: struct.EncodeWide.html +//! [`from_wide`]: trait.OsStringExt.html#tymethod.from_wide +//! [`encode_wide`]: trait.OsStrExt.html#tymethod.encode_wide +//! [`collect`]: ../../../iter/trait.Iterator.html#method.collect #![stable(feature = "rust1", since = "1.0.0")] -- cgit 1.4.1-3-g733a5 From 91f6445b5956aff72755b84854a19d2921009e1e Mon Sep 17 00:00:00 2001 From: Federico Mena Quintero Date: Mon, 25 Sep 2017 13:51:28 -0500 Subject: Overhaul the documentation for OsString / OsStr --- src/libstd/ffi/mod.rs | 45 +++++++++++++++++++++++++++++++++++++++--- src/libstd/ffi/os_str.rs | 51 ++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 91 insertions(+), 5 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/ffi/mod.rs b/src/libstd/ffi/mod.rs index 376e13e3b03..1214a2406e2 100644 --- a/src/libstd/ffi/mod.rs +++ b/src/libstd/ffi/mod.rs @@ -92,13 +92,40 @@ //! your code can detect errors in case the environment variable did //! not in fact contain valid Unicode data. //! -//! * [`OsStr`] represents a borrowed string slice in a format that -//! can be passed to the operating system. It can be converted into -//! an UTF-8 Rust string slice in a similar way to `OsString`. +//! * [`OsStr`] represents a borrowed reference to a string in a +//! format that can be passed to the operating system. It can be +//! converted into an UTF-8 Rust string slice in a similar way to +//! `OsString`. +//! +//! # Conversions +//! +//! ## On Unix +//! +//! On Unix, [`OsStr`] implements the `std::os::unix:ffi::`[`OsStrExt`][unix.OsStrExt] trait, which +//! augments it with two methods, [`from_bytes`] and [`as_bytes`]. These do inexpensive conversions +//! from and to UTF-8 byte slices. +//! +//! Additionally, on Unix [`OsString`] implements the +//! `std::os::unix:ffi::`[`OsStringExt`][unix.OsStringExt] trait, +//! which provides [`from_vec`] and [`into_vec`] methods that consume +//! their arguments, and take or produce vectors of [`u8`]. +//! +//! ## On Windows +//! +//! On Windows, [`OsStr`] implements the `std::os::windows::ffi::`[`OsStrExt`][windows.OsStrExt] +//! trait, which provides an [`encode_wide`] method. This provides an iterator that can be +//! [`collect`]ed into a vector of [`u16`]. +//! +//! Additionally, on Windows [`OsString`] implements the +//! `std::os::windows:ffi::`[`OsStringExt`][windows.OsStringExt] trait, which provides a +//! [`from_wide`] method. The result of this method is an `OsString` which can be round-tripped to +//! a Windows string losslessly. //! //! [`String`]: ../string/struct.String.html //! [`str`]: ../primitive.str.html //! [`char`]: ../primitive.char.html +//! [`u8`]: ../primitive.u8.html +//! [`u16`]: ../primitive.u16.html //! [Unicode scalar value]: http://www.unicode.org/glossary/#unicode_scalar_value //! [Unicode code point]: http://www.unicode.org/glossary/#code_point //! [`CString`]: struct.CString.html @@ -108,6 +135,18 @@ //! [`env::set_var()`]: ../env/fn.set_var.html //! [`env::var_os()`]: ../env/fn.var_os.html //! [`Result<>`]: ../result/enum.Result.html +//! [unix.OsStringExt]: ../os/unix/ffi/trait.OsStringExt.html +//! [`from_vec`]: ../os/unix/ffi/trait.OsStringExt.html#tymethod.from_vec +//! [`into_vec`]: ../os/unix/ffi/trait.OsStringExt.html#tymethod.into_vec +//! [unix.OsStrExt]: ../os/unix/ffi/trait.OsStrExt.html +//! [`from_bytes`]: ../os/unix/ffi/trait.OsStrExt.html#tymethod.from_bytes +//! [`as_bytes`]: ../os/unix/ffi/trait.OsStrExt.html#tymethod.as_bytes +//! [`OsStrExt`]: ../os/unix/ffi/trait.OsStrExt.html +//! [windows.OsStrExt]: ../os/windows/ffi/trait.OsStrExt.html +//! [`encode_wide`]: ../os/windows/ffi/trait.OsStrExt.html#tymethod.encode_wide +//! [`collect`]: ../iter/trait.Iterator.html#method.collect +//! [windows.OsStringExt]: ../os/windows/ffi/trait.OsStringExt.html +//! [`from_wide`]: ../os/windows/ffi/trait.OsStringExt.html#tymethod.from_wide #![stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libstd/ffi/os_str.rs b/src/libstd/ffi/os_str.rs index a40a9329ed9..72b0e68a9b6 100644 --- a/src/libstd/ffi/os_str.rs +++ b/src/libstd/ffi/os_str.rs @@ -33,18 +33,65 @@ use sys_common::{AsInner, IntoInner, FromInner}; /// /// `OsString` and [`OsStr`] bridge this gap by simultaneously representing Rust /// and platform-native string values, and in particular allowing a Rust string -/// to be converted into an "OS" string with no cost. +/// to be converted into an "OS" string with no cost if possible. +/// +/// `OsString` is to [`OsStr`] as [`String`] is to [`&str`]: the former +/// in each pair are owned strings; the latter are borrowed +/// references. +/// +/// # Creating an `OsString` +/// +/// **From a Rust string**: `OsString` implements +/// [`From`]`<`[`String`]`>`, so you can use `my_string.`[`from`] to +/// create an `OsString` from a normal Rust string. +/// +/// **From slices:** Just like you can start with an empty Rust +/// [`String`] and then [`push_str`][String.push_str] `&str` +/// sub-string slices into it, you can create an empty `OsString` with +/// the [`new`] method and then push string slices into it with the +/// [`push`] method. +/// +/// # Extracting a borrowed reference to the whole OS string +/// +/// You can use the [`as_os_str`] method to get an `&`[`OsStr`] from +/// an `OsString`; this is effectively a borrowed reference to the +/// whole string. +/// +/// # Conversions +/// +/// See the [module's toplevel documentation about conversions][conversions] for a discussion on the traits which +/// `OsString` implements for conversions from/to native representations. /// /// [`OsStr`]: struct.OsStr.html +/// [`From`]: ../convert/trait.From.html +/// [`from`]: ../convert/trait.From.html#tymethod.from +/// [`String`]: ../string/struct.String.html +/// [`&str`]: ../primitive.str.html +/// [`u8`]: ../primitive.u8.html +/// [`u16`]: ../primitive.u16.html +/// [String.push_str]: ../string/struct.String.html#method.push_str +/// [`new`]: #struct.OsString.html#method.new +/// [`push`]: #struct.OsString.html#method.push +/// [`as_os_str`]: #struct.OsString.html#method.as_os_str #[derive(Clone)] #[stable(feature = "rust1", since = "1.0.0")] pub struct OsString { inner: Buf } -/// Slices into OS strings (see [`OsString`]). +/// Borrowed reference to an OS string (see [`OsString`]). +/// +/// This type represents a borrowed reference to a string in the operating system's preferred +/// representation. +/// +/// `OsStr` is to [`OsString`] as [`String`] is to [`&str`]: the former in each pair are borrowed +/// references; the latter are owned strings. +/// +/// See the [module's toplevel documentation about conversions][conversions] for a discussion on the traits which +/// `OsStr` implements for conversions from/to native representations. /// /// [`OsString`]: struct.OsString.html +/// [conversions]: index.html#conversions #[stable(feature = "rust1", since = "1.0.0")] pub struct OsStr { inner: Slice -- cgit 1.4.1-3-g733a5 From 4143422981e5be3593d3248e99cd503442aae698 Mon Sep 17 00:00:00 2001 From: Federico Mena Quintero Date: Tue, 26 Sep 2017 08:56:44 -0500 Subject: os_str: Fix too-long lines --- src/libstd/ffi/os_str.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/ffi/os_str.rs b/src/libstd/ffi/os_str.rs index 72b0e68a9b6..b6032f7c74c 100644 --- a/src/libstd/ffi/os_str.rs +++ b/src/libstd/ffi/os_str.rs @@ -59,8 +59,8 @@ use sys_common::{AsInner, IntoInner, FromInner}; /// /// # Conversions /// -/// See the [module's toplevel documentation about conversions][conversions] for a discussion on the traits which -/// `OsString` implements for conversions from/to native representations. +/// See the [module's toplevel documentation about conversions][conversions] for a discussion on +/// the traits which `OsString` implements for conversions from/to native representations. /// /// [`OsStr`]: struct.OsStr.html /// [`From`]: ../convert/trait.From.html @@ -87,8 +87,8 @@ pub struct OsString { /// `OsStr` is to [`OsString`] as [`String`] is to [`&str`]: the former in each pair are borrowed /// references; the latter are owned strings. /// -/// See the [module's toplevel documentation about conversions][conversions] for a discussion on the traits which -/// `OsStr` implements for conversions from/to native representations. +/// See the [module's toplevel documentation about conversions][conversions] for a discussion on +/// the traits which `OsStr` implements for conversions from/to native representations. /// /// [`OsString`]: struct.OsString.html /// [conversions]: index.html#conversions -- cgit 1.4.1-3-g733a5 From 8ef54478157adb980598104af0ce571cb6637931 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Mon, 25 Sep 2017 00:14:56 -0400 Subject: Migrate to eprint/eprintln macros where appropriate. --- src/bootstrap/bin/rustc.rs | 4 +--- src/librustc_driver/lib.rs | 2 +- src/librustdoc/externalfiles.rs | 9 ++------- src/librustdoc/markdown.rs | 14 +++----------- src/librustdoc/test.rs | 9 ++++----- src/libstd/process.rs | 4 +--- src/test/run-fail/mir_drop_panics.rs | 3 +-- src/test/run-fail/mir_dynamic_drops_1.rs | 5 ++--- src/test/run-fail/mir_dynamic_drops_2.rs | 5 ++--- src/test/run-fail/mir_dynamic_drops_3.rs | 5 ++--- src/test/run-fail/mir_trans_calls_converging_drops.rs | 6 ++---- src/test/run-fail/mir_trans_calls_converging_drops_2.rs | 6 ++---- src/test/run-fail/mir_trans_calls_diverging_drops.rs | 4 +--- src/test/run-fail/panic-set-handler.rs | 3 +-- src/test/run-fail/panic-set-unset-handler.rs | 3 +-- src/test/run-pass/backtrace-debuginfo.rs | 4 +--- src/tools/tidy/src/lib.rs | 5 ++--- src/tools/tidy/src/main.rs | 3 +-- 18 files changed, 30 insertions(+), 64 deletions(-) (limited to 'src/libstd') diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs index 848b10d312c..54a3dbafe27 100644 --- a/src/bootstrap/bin/rustc.rs +++ b/src/bootstrap/bin/rustc.rs @@ -31,8 +31,6 @@ extern crate bootstrap; use std::env; use std::ffi::OsString; -use std::io; -use std::io::prelude::*; use std::str::FromStr; use std::path::PathBuf; use std::process::{Command, ExitStatus}; @@ -270,7 +268,7 @@ fn main() { } if verbose > 1 { - writeln!(&mut io::stderr(), "rustc command: {:?}", cmd).unwrap(); + eprintln!("rustc command: {:?}", cmd); } // Actually run the compiler! diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 044f4a5eaf5..29d15188500 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -1307,7 +1307,7 @@ pub fn monitor(f: F) { errors::Level::Note); } - writeln!(io::stderr(), "{}", str::from_utf8(&data.lock().unwrap()).unwrap()).unwrap(); + eprintln!("{}", str::from_utf8(&data.lock().unwrap()).unwrap()); } exit_on_err(); diff --git a/src/librustdoc/externalfiles.rs b/src/librustdoc/externalfiles.rs index 111ae4ede27..2f7bd5e39a1 100644 --- a/src/librustdoc/externalfiles.rs +++ b/src/librustdoc/externalfiles.rs @@ -10,7 +10,6 @@ use std::fs::File; use std::io::prelude::*; -use std::io; use std::path::Path; use std::str; use html::markdown::{Markdown, RenderType}; @@ -70,17 +69,13 @@ pub fn load_string>(file_path: P) -> Result Ok(s.to_string()), Err(_) => { - let _ = writeln!(&mut io::stderr(), - "error reading `{}`: not UTF-8", - file_path.display()); + eprintln!("error reading `{}`: not UTF-8", file_path.display()); Err(LoadStringError::BadUtf8) } } diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs index 57e8e88cd13..484285e91f6 100644 --- a/src/librustdoc/markdown.rs +++ b/src/librustdoc/markdown.rs @@ -11,7 +11,6 @@ use std::default::Default; use std::fs::File; use std::io::prelude::*; -use std::io; use std::path::{PathBuf, Path}; use getopts; @@ -75,9 +74,7 @@ pub fn render(input: &str, mut output: PathBuf, matches: &getopts::Matches, let mut out = match File::create(&output) { Err(e) => { - let _ = writeln!(&mut io::stderr(), - "rustdoc: {}: {}", - output.display(), e); + eprintln!("rustdoc: {}: {}", output.display(), e); return 4; } Ok(f) => f @@ -85,10 +82,7 @@ pub fn render(input: &str, mut output: PathBuf, matches: &getopts::Matches, let (metadata, text) = extract_leading_metadata(&input_str); if metadata.is_empty() { - let _ = writeln!( - &mut io::stderr(), - "rustdoc: invalid markdown file: no initial lines starting with `# ` or `%`" - ); + eprintln!("rustdoc: invalid markdown file: no initial lines starting with `# ` or `%`"); return 5; } let title = metadata[0]; @@ -138,9 +132,7 @@ pub fn render(input: &str, mut output: PathBuf, matches: &getopts::Matches, match err { Err(e) => { - let _ = writeln!(&mut io::stderr(), - "rustdoc: cannot write to `{}`: {}", - output.display(), e); + eprintln!("rustdoc: cannot write to `{}`: {}", output.display(), e); 6 } Ok(_) => 0 diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index f9cb4b84545..5f6ccb8a75e 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -479,11 +479,10 @@ impl Collector { found = entry.remove_item(&test).is_some(); } if !found { - let _ = writeln!(&mut io::stderr(), - "WARNING: {} Code block is not currently run as a test, but will \ - in future versions of rustdoc. Please ensure this code block is \ - a runnable test, or use the `ignore` directive.", - name); + eprintln!("WARNING: {} Code block is not currently run as a test, but will \ + in future versions of rustdoc. Please ensure this code block is \ + a runnable test, or use the `ignore` directive.", + name); return } } diff --git a/src/libstd/process.rs b/src/libstd/process.rs index 1869ad3ed70..015f859b5cc 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -1083,8 +1083,6 @@ impl Child { /// function and compute the exit code from its return value: /// /// ``` -/// use std::io::{self, Write}; -/// /// fn run_app() -> Result<(), ()> { /// // Application logic here /// Ok(()) @@ -1094,7 +1092,7 @@ impl Child { /// ::std::process::exit(match run_app() { /// Ok(_) => 0, /// Err(err) => { -/// writeln!(io::stderr(), "error: {:?}", err).unwrap(); +/// eprintln!("error: {:?}", err); /// 1 /// } /// }); diff --git a/src/test/run-fail/mir_drop_panics.rs b/src/test/run-fail/mir_drop_panics.rs index 98311525ad0..51191dd7087 100644 --- a/src/test/run-fail/mir_drop_panics.rs +++ b/src/test/run-fail/mir_drop_panics.rs @@ -10,7 +10,6 @@ // error-pattern:panic 1 // error-pattern:drop 2 -use std::io::{self, Write}; struct Droppable(u32); impl Drop for Droppable { @@ -18,7 +17,7 @@ impl Drop for Droppable { if self.0 == 1 { panic!("panic 1"); } else { - write!(io::stderr(), "drop {}", self.0); + eprint!("drop {}", self.0); } } } diff --git a/src/test/run-fail/mir_dynamic_drops_1.rs b/src/test/run-fail/mir_dynamic_drops_1.rs index 6cf2851d93d..69f934272b7 100644 --- a/src/test/run-fail/mir_dynamic_drops_1.rs +++ b/src/test/run-fail/mir_dynamic_drops_1.rs @@ -9,7 +9,6 @@ // except according to those terms. // error-pattern:drop 1 // error-pattern:drop 2 -use std::io::{self, Write}; /// Structure which will not allow to be dropped twice. @@ -17,10 +16,10 @@ struct Droppable<'a>(&'a mut bool, u32); impl<'a> Drop for Droppable<'a> { fn drop(&mut self) { if *self.0 { - writeln!(io::stderr(), "{} dropped twice", self.1); + eprintln!("{} dropped twice", self.1); ::std::process::exit(1); } - writeln!(io::stderr(), "drop {}", self.1); + eprintln!("drop {}", self.1); *self.0 = true; } } diff --git a/src/test/run-fail/mir_dynamic_drops_2.rs b/src/test/run-fail/mir_dynamic_drops_2.rs index 7a90298e422..d2fe50401ab 100644 --- a/src/test/run-fail/mir_dynamic_drops_2.rs +++ b/src/test/run-fail/mir_dynamic_drops_2.rs @@ -9,7 +9,6 @@ // except according to those terms. // error-pattern:drop 1 -use std::io::{self, Write}; /// Structure which will not allow to be dropped twice. @@ -17,10 +16,10 @@ struct Droppable<'a>(&'a mut bool, u32); impl<'a> Drop for Droppable<'a> { fn drop(&mut self) { if *self.0 { - writeln!(io::stderr(), "{} dropped twice", self.1); + eprintln!("{} dropped twice", self.1); ::std::process::exit(1); } - writeln!(io::stderr(), "drop {}", self.1); + eprintln!("drop {}", self.1); *self.0 = true; } } diff --git a/src/test/run-fail/mir_dynamic_drops_3.rs b/src/test/run-fail/mir_dynamic_drops_3.rs index 79ecbbb35bc..ecc35ee9b24 100644 --- a/src/test/run-fail/mir_dynamic_drops_3.rs +++ b/src/test/run-fail/mir_dynamic_drops_3.rs @@ -12,7 +12,6 @@ // error-pattern:drop 3 // error-pattern:drop 2 // error-pattern:drop 1 -use std::io::{self, Write}; /// Structure which will not allow to be dropped twice. @@ -20,10 +19,10 @@ struct Droppable<'a>(&'a mut bool, u32); impl<'a> Drop for Droppable<'a> { fn drop(&mut self) { if *self.0 { - writeln!(io::stderr(), "{} dropped twice", self.1); + eprintln!("{} dropped twice", self.1); ::std::process::exit(1); } - writeln!(io::stderr(), "drop {}", self.1); + eprintln!("drop {}", self.1); *self.0 = true; } } diff --git a/src/test/run-fail/mir_trans_calls_converging_drops.rs b/src/test/run-fail/mir_trans_calls_converging_drops.rs index 7a7526c5fc1..9c851eb7346 100644 --- a/src/test/run-fail/mir_trans_calls_converging_drops.rs +++ b/src/test/run-fail/mir_trans_calls_converging_drops.rs @@ -12,17 +12,15 @@ // error-pattern:0 dropped // error-pattern:exit -use std::io::{self, Write}; - struct Droppable(u8); impl Drop for Droppable { fn drop(&mut self) { - write!(io::stderr(), "{} dropped\n", self.0); + eprintln!("{} dropped", self.0); } } fn converging_fn() { - write!(io::stderr(), "converging_fn called\n"); + eprintln!("converging_fn called"); } fn mir(d: Droppable) { diff --git a/src/test/run-fail/mir_trans_calls_converging_drops_2.rs b/src/test/run-fail/mir_trans_calls_converging_drops_2.rs index 1301630cc85..6f105211556 100644 --- a/src/test/run-fail/mir_trans_calls_converging_drops_2.rs +++ b/src/test/run-fail/mir_trans_calls_converging_drops_2.rs @@ -12,18 +12,16 @@ // error-pattern:dropped // error-pattern:exit -use std::io::{self, Write}; - struct Droppable; impl Drop for Droppable { fn drop(&mut self) { - write!(io::stderr(), "dropped\n"); + eprintln!("dropped"); } } // return value of this function is copied into the return slot fn complex() -> u64 { - write!(io::stderr(), "complex called\n"); + eprintln!("complex called"); 42 } diff --git a/src/test/run-fail/mir_trans_calls_diverging_drops.rs b/src/test/run-fail/mir_trans_calls_diverging_drops.rs index c1918704929..f8fbe8f79cc 100644 --- a/src/test/run-fail/mir_trans_calls_diverging_drops.rs +++ b/src/test/run-fail/mir_trans_calls_diverging_drops.rs @@ -11,12 +11,10 @@ // error-pattern:diverging_fn called // error-pattern:0 dropped -use std::io::{self, Write}; - struct Droppable(u8); impl Drop for Droppable { fn drop(&mut self) { - write!(io::stderr(), "{} dropped", self.0); + eprintln!("{} dropped", self.0); } } diff --git a/src/test/run-fail/panic-set-handler.rs b/src/test/run-fail/panic-set-handler.rs index b589544ae15..68f1c4ed0bc 100644 --- a/src/test/run-fail/panic-set-handler.rs +++ b/src/test/run-fail/panic-set-handler.rs @@ -13,11 +13,10 @@ #![feature(panic_handler)] use std::panic; -use std::io::{self, Write}; fn main() { panic::set_hook(Box::new(|i| { - write!(io::stderr(), "greetings from the panic handler"); + eprint!("greetings from the panic handler"); })); panic!("foobar"); } diff --git a/src/test/run-fail/panic-set-unset-handler.rs b/src/test/run-fail/panic-set-unset-handler.rs index 6741c2d9c2c..072139a8c9b 100644 --- a/src/test/run-fail/panic-set-unset-handler.rs +++ b/src/test/run-fail/panic-set-unset-handler.rs @@ -13,11 +13,10 @@ #![feature(panic_handler)] use std::panic; -use std::io::{self, Write}; fn main() { panic::set_hook(Box::new(|i| { - write!(io::stderr(), "greetings from the panic handler"); + eprint!("greetings from the panic handler"); })); panic::take_hook(); panic!("foobar"); diff --git a/src/test/run-pass/backtrace-debuginfo.rs b/src/test/run-pass/backtrace-debuginfo.rs index f81352e1773..f9233026a1e 100644 --- a/src/test/run-pass/backtrace-debuginfo.rs +++ b/src/test/run-pass/backtrace-debuginfo.rs @@ -19,8 +19,6 @@ // ignore-pretty issue #37195 // ignore-emscripten spawning processes is not supported -use std::io; -use std::io::prelude::*; use std::env; #[path = "backtrace-debuginfo-aux.rs"] mod aux; @@ -163,7 +161,7 @@ fn main() { let args: Vec = env::args().collect(); if args.len() >= 2 { let case = args[1].parse().unwrap(); - writeln!(&mut io::stderr(), "test case {}", case).unwrap(); + eprintln!("test case {}", case); outer(case, pos!()); println!("done."); } else { diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs index 90bf7a5e0a6..c316ec46762 100644 --- a/src/tools/tidy/src/lib.rs +++ b/src/tools/tidy/src/lib.rs @@ -33,10 +33,9 @@ macro_rules! t { macro_rules! tidy_error { ($bad:expr, $fmt:expr, $($arg:tt)*) => ({ - use std::io::Write; *$bad = true; - write!(::std::io::stderr(), "tidy error: ").expect("could not write to stderr"); - writeln!(::std::io::stderr(), $fmt, $($arg)*).expect("could not write to stderr"); + eprint!("tidy error: "); + eprintln!($fmt, $($arg)*); }); } diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs index 433192a21ec..f6640c902bc 100644 --- a/src/tools/tidy/src/main.rs +++ b/src/tools/tidy/src/main.rs @@ -22,7 +22,6 @@ use tidy::*; use std::process; use std::path::PathBuf; use std::env; -use std::io::{self, Write}; fn main() { let path = env::args_os().skip(1).next().expect("need an argument"); @@ -44,7 +43,7 @@ fn main() { } if bad { - writeln!(io::stderr(), "some tidy checks failed").expect("could not write to stderr"); + eprintln!("some tidy checks failed"); process::exit(1); } } -- cgit 1.4.1-3-g733a5 From 68341a91eecb830c57779cd2423733a7395258ab Mon Sep 17 00:00:00 2001 From: Joshua Lockerman Date: Fri, 29 Sep 2017 15:58:11 -0400 Subject: Improve performance of spsc_queue and stream. This commit makes two main changes. 1. It switches the spsc_queue node caching strategy from keeping a shared counter of the number of nodes in the cache to keeping a consumer only counter of the number of node eligible to be cached. 2. It separate the consumer and producers fields of spsc_queue and stream into a producer cache line and consumer cache line. --- src/libstd/lib.rs | 2 + src/libstd/sync/mpsc/cache_aligned.rs | 37 ++++++++ src/libstd/sync/mpsc/mod.rs | 2 + src/libstd/sync/mpsc/spsc_queue.rs | 161 ++++++++++++++++++++++------------ src/libstd/sync/mpsc/stream.rs | 105 ++++++++++++---------- 5 files changed, 208 insertions(+), 99 deletions(-) create mode 100644 src/libstd/sync/mpsc/cache_aligned.rs (limited to 'src/libstd') diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 9fc7e2c01aa..83cc9ce582e 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -244,6 +244,7 @@ #![feature(allow_internal_unstable)] #![feature(align_offset)] #![feature(asm)] +#![feature(attr_literals)] #![feature(box_syntax)] #![feature(cfg_target_has_atomic)] #![feature(cfg_target_thread_local)] @@ -290,6 +291,7 @@ #![feature(prelude_import)] #![feature(rand)] #![feature(raw)] +#![feature(repr_align)] #![feature(repr_simd)] #![feature(rustc_attrs)] #![cfg_attr(not(stage0), feature(rustc_const_unstable))] diff --git a/src/libstd/sync/mpsc/cache_aligned.rs b/src/libstd/sync/mpsc/cache_aligned.rs new file mode 100644 index 00000000000..5af01262573 --- /dev/null +++ b/src/libstd/sync/mpsc/cache_aligned.rs @@ -0,0 +1,37 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use ops::{Deref, DerefMut}; + +#[derive(Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[repr(align(64))] +pub(super) struct Aligner; + +#[derive(Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub(super) struct CacheAligned(pub T, pub Aligner); + +impl Deref for CacheAligned { + type Target = T; + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for CacheAligned { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +impl CacheAligned { + pub(super) fn new(t: T) -> Self { + CacheAligned(t, Aligner) + } +} diff --git a/src/libstd/sync/mpsc/mod.rs b/src/libstd/sync/mpsc/mod.rs index dcd4c8dfdf5..0bfbcd2d2cd 100644 --- a/src/libstd/sync/mpsc/mod.rs +++ b/src/libstd/sync/mpsc/mod.rs @@ -297,6 +297,8 @@ mod sync; mod mpsc_queue; mod spsc_queue; +mod cache_aligned; + /// The receiving half of Rust's [`channel`][] (or [`sync_channel`]) type. /// This half can only be owned by one thread. /// diff --git a/src/libstd/sync/mpsc/spsc_queue.rs b/src/libstd/sync/mpsc/spsc_queue.rs index 1148bc66fba..3ce59270335 100644 --- a/src/libstd/sync/mpsc/spsc_queue.rs +++ b/src/libstd/sync/mpsc/spsc_queue.rs @@ -22,12 +22,15 @@ use core::cell::UnsafeCell; use sync::atomic::{AtomicPtr, AtomicUsize, Ordering}; +use super::cache_aligned::CacheAligned; + // Node within the linked list queue of messages to send struct Node { // FIXME: this could be an uninitialized T if we're careful enough, and // that would reduce memory usage (and be a bit faster). // is it worth it? value: Option, // nullable for re-use of nodes + cached: bool, // This node goes into the node cache next: AtomicPtr>, // next node in the queue } @@ -35,37 +38,45 @@ struct Node { /// but it can be safely shared in an Arc if it is guaranteed that there /// is only one popper and one pusher touching the queue at any one point in /// time. -pub struct Queue { +pub struct Queue { // consumer fields + consumer: CacheAligned>, + + // producer fields + producer: CacheAligned>, +} + +struct Consumer { tail: UnsafeCell<*mut Node>, // where to pop from tail_prev: AtomicPtr>, // where to pop from + cache_bound: usize, // maximum cache size + cached_nodes: AtomicUsize, // number of nodes marked as cachable + addition: Addition, +} - // producer fields +struct Producer { head: UnsafeCell<*mut Node>, // where to push to first: UnsafeCell<*mut Node>, // where to get new nodes from tail_copy: UnsafeCell<*mut Node>, // between first/tail - - // Cache maintenance fields. Additions and subtractions are stored - // separately in order to allow them to use nonatomic addition/subtraction. - cache_bound: usize, - cache_additions: AtomicUsize, - cache_subtractions: AtomicUsize, + addition: Addition, } -unsafe impl Send for Queue { } +unsafe impl Send for Queue { } -unsafe impl Sync for Queue { } +unsafe impl Sync for Queue { } impl Node { fn new() -> *mut Node { Box::into_raw(box Node { value: None, + cached: false, next: AtomicPtr::new(ptr::null_mut::>()), }) } } impl Queue { + #[cfg(test)] /// Creates a new queue. /// /// This is unsafe as the type system doesn't enforce a single @@ -84,18 +95,60 @@ impl Queue { /// no bound. Otherwise, the cache will never grow larger than /// `bound` (although the queue itself could be much larger. pub unsafe fn new(bound: usize) -> Queue { + Self::with_additions(bound, (), ()) + } +} + +impl Queue { + + /// Creates a new queue. With given additional elements in the producer and + /// consumer portions of the queue. + /// + /// Due to the performance implications of cache-contention, + /// we wish to keep fields used mainly by the producer on a separate cache + /// line than those used by the consumer. + /// Since cache lines are usually 64 bytes, it is unreasonably expensive to + /// allocate one for small fields, so we allow users to insert additional + /// fields into the cache lines already allocated by this for the producer + /// and consumer. + /// + /// This is unsafe as the type system doesn't enforce a single + /// consumer-producer relationship. It also allows the consumer to `pop` + /// items while there is a `peek` active due to all methods having a + /// non-mutable receiver. + /// + /// # Arguments + /// + /// * `bound` - This queue implementation is implemented with a linked + /// list, and this means that a push is always a malloc. In + /// order to amortize this cost, an internal cache of nodes is + /// maintained to prevent a malloc from always being + /// necessary. This bound is the limit on the size of the + /// cache (if desired). If the value is 0, then the cache has + /// no bound. Otherwise, the cache will never grow larger than + /// `bound` (although the queue itself could be much larger. + pub unsafe fn with_additions( + bound: usize, + producer_addition: ProducerAddition, + consumer_addition: ConsumerAddition, + ) -> Self { let n1 = Node::new(); let n2 = Node::new(); (*n1).next.store(n2, Ordering::Relaxed); Queue { - tail: UnsafeCell::new(n2), - tail_prev: AtomicPtr::new(n1), - head: UnsafeCell::new(n2), - first: UnsafeCell::new(n1), - tail_copy: UnsafeCell::new(n1), - cache_bound: bound, - cache_additions: AtomicUsize::new(0), - cache_subtractions: AtomicUsize::new(0), + consumer: CacheAligned::new(Consumer { + tail: UnsafeCell::new(n2), + tail_prev: AtomicPtr::new(n1), + cache_bound: bound, + cached_nodes: AtomicUsize::new(0), + addition: consumer_addition + }), + producer: CacheAligned::new(Producer { + head: UnsafeCell::new(n2), + first: UnsafeCell::new(n1), + tail_copy: UnsafeCell::new(n1), + addition: producer_addition + }), } } @@ -109,35 +162,25 @@ impl Queue { assert!((*n).value.is_none()); (*n).value = Some(t); (*n).next.store(ptr::null_mut(), Ordering::Relaxed); - (**self.head.get()).next.store(n, Ordering::Release); - *self.head.get() = n; + (**self.producer.head.get()).next.store(n, Ordering::Release); + *(&self.producer.head).get() = n; } } unsafe fn alloc(&self) -> *mut Node { // First try to see if we can consume the 'first' node for our uses. - // We try to avoid as many atomic instructions as possible here, so - // the addition to cache_subtractions is not atomic (plus we're the - // only one subtracting from the cache). - if *self.first.get() != *self.tail_copy.get() { - if self.cache_bound > 0 { - let b = self.cache_subtractions.load(Ordering::Relaxed); - self.cache_subtractions.store(b + 1, Ordering::Relaxed); - } - let ret = *self.first.get(); - *self.first.get() = (*ret).next.load(Ordering::Relaxed); + if *self.producer.first.get() != *self.producer.tail_copy.get() { + let ret = *self.producer.first.get(); + *self.producer.0.first.get() = (*ret).next.load(Ordering::Relaxed); return ret; } // If the above fails, then update our copy of the tail and try // again. - *self.tail_copy.get() = self.tail_prev.load(Ordering::Acquire); - if *self.first.get() != *self.tail_copy.get() { - if self.cache_bound > 0 { - let b = self.cache_subtractions.load(Ordering::Relaxed); - self.cache_subtractions.store(b + 1, Ordering::Relaxed); - } - let ret = *self.first.get(); - *self.first.get() = (*ret).next.load(Ordering::Relaxed); + *self.producer.0.tail_copy.get() = + self.consumer.tail_prev.load(Ordering::Acquire); + if *self.producer.first.get() != *self.producer.tail_copy.get() { + let ret = *self.producer.first.get(); + *self.producer.0.first.get() = (*ret).next.load(Ordering::Relaxed); return ret; } // If all of that fails, then we have to allocate a new node @@ -153,27 +196,27 @@ impl Queue { // sentinel from where we should start popping from. Hence, look at // tail's next field and see if we can use it. If we do a pop, then // the current tail node is a candidate for going into the cache. - let tail = *self.tail.get(); + let tail = *self.consumer.tail.get(); let next = (*tail).next.load(Ordering::Acquire); if next.is_null() { return None } assert!((*next).value.is_some()); let ret = (*next).value.take(); - *self.tail.get() = next; - if self.cache_bound == 0 { - self.tail_prev.store(tail, Ordering::Release); + *self.consumer.0.tail.get() = next; + if self.consumer.cache_bound == 0 { + self.consumer.tail_prev.store(tail, Ordering::Release); } else { - // FIXME: this is dubious with overflow. - let additions = self.cache_additions.load(Ordering::Relaxed); - let subtractions = self.cache_subtractions.load(Ordering::Relaxed); - let size = additions - subtractions; - - if size < self.cache_bound { - self.tail_prev.store(tail, Ordering::Release); - self.cache_additions.store(additions + 1, Ordering::Relaxed); + let cached_nodes = self.consumer.cached_nodes.load(Ordering::Relaxed); + if cached_nodes < self.consumer.cache_bound && !(*tail).cached { + self.consumer.cached_nodes.store(cached_nodes, Ordering::Relaxed); + (*tail).cached = true; + } + + if (*tail).cached { + self.consumer.tail_prev.store(tail, Ordering::Release); } else { - (*self.tail_prev.load(Ordering::Relaxed)) - .next.store(next, Ordering::Relaxed); + (*self.consumer.tail_prev.load(Ordering::Relaxed)) + .next.store(next, Ordering::Relaxed); // We have successfully erased all references to 'tail', so // now we can safely drop it. let _: Box> = Box::from_raw(tail); @@ -194,17 +237,25 @@ impl Queue { // This is essentially the same as above with all the popping bits // stripped out. unsafe { - let tail = *self.tail.get(); + let tail = *self.consumer.tail.get(); let next = (*tail).next.load(Ordering::Acquire); if next.is_null() { None } else { (*next).value.as_mut() } } } + + pub fn producer_addition(&self) -> &ProducerAddition { + &self.producer.addition + } + + pub fn consumer_addition(&self) -> &ConsumerAddition { + &self.consumer.addition + } } -impl Drop for Queue { +impl Drop for Queue { fn drop(&mut self) { unsafe { - let mut cur = *self.first.get(); + let mut cur = *self.producer.first.get(); while !cur.is_null() { let next = (*cur).next.load(Ordering::Relaxed); let _n: Box> = Box::from_raw(cur); diff --git a/src/libstd/sync/mpsc/stream.rs b/src/libstd/sync/mpsc/stream.rs index 47cd8977fda..d1515eba68c 100644 --- a/src/libstd/sync/mpsc/stream.rs +++ b/src/libstd/sync/mpsc/stream.rs @@ -41,15 +41,22 @@ const MAX_STEALS: isize = 5; const MAX_STEALS: isize = 1 << 20; pub struct Packet { - queue: spsc::Queue>, // internal queue for all message + // internal queue for all messages + queue: spsc::Queue, ProducerAddition, ConsumerAddition>, +} +struct ProducerAddition { cnt: AtomicIsize, // How many items are on this channel - steals: UnsafeCell, // How many times has a port received without blocking? to_wake: AtomicUsize, // SignalToken for the blocked thread to wake up port_dropped: AtomicBool, // flag if the channel has been destroyed. } +struct ConsumerAddition { + steals: UnsafeCell, // How many times has a port received without blocking? +} + + pub enum Failure { Empty, Disconnected, @@ -78,13 +85,18 @@ enum Message { impl Packet { pub fn new() -> Packet { Packet { - queue: unsafe { spsc::Queue::new(128) }, - - cnt: AtomicIsize::new(0), - steals: UnsafeCell::new(0), - to_wake: AtomicUsize::new(0), - - port_dropped: AtomicBool::new(false), + queue: unsafe { spsc::Queue::with_additions( + 128, + ProducerAddition { + cnt: AtomicIsize::new(0), + to_wake: AtomicUsize::new(0), + + port_dropped: AtomicBool::new(false), + }, + ConsumerAddition { + steals: UnsafeCell::new(0), + } + )}, } } @@ -92,7 +104,7 @@ impl Packet { // If the other port has deterministically gone away, then definitely // must return the data back up the stack. Otherwise, the data is // considered as being sent. - if self.port_dropped.load(Ordering::SeqCst) { return Err(t) } + if self.queue.producer_addition().port_dropped.load(Ordering::SeqCst) { return Err(t) } match self.do_send(Data(t)) { UpSuccess | UpDisconnected => {}, @@ -104,14 +116,16 @@ impl Packet { pub fn upgrade(&self, up: Receiver) -> UpgradeResult { // If the port has gone away, then there's no need to proceed any // further. - if self.port_dropped.load(Ordering::SeqCst) { return UpDisconnected } + if self.queue.producer_addition().port_dropped.load(Ordering::SeqCst) { + return UpDisconnected + } self.do_send(GoUp(up)) } fn do_send(&self, t: Message) -> UpgradeResult { self.queue.push(t); - match self.cnt.fetch_add(1, Ordering::SeqCst) { + match self.queue.producer_addition().cnt.fetch_add(1, Ordering::SeqCst) { // As described in the mod's doc comment, -1 == wakeup -1 => UpWoke(self.take_to_wake()), // As as described before, SPSC queues must be >= -2 @@ -125,7 +139,7 @@ impl Packet { // will never remove this data. We can only have at most one item to // drain (the port drains the rest). DISCONNECTED => { - self.cnt.store(DISCONNECTED, Ordering::SeqCst); + self.queue.producer_addition().cnt.store(DISCONNECTED, Ordering::SeqCst); let first = self.queue.pop(); let second = self.queue.pop(); assert!(second.is_none()); @@ -144,8 +158,8 @@ impl Packet { // Consumes ownership of the 'to_wake' field. fn take_to_wake(&self) -> SignalToken { - let ptr = self.to_wake.load(Ordering::SeqCst); - self.to_wake.store(0, Ordering::SeqCst); + let ptr = self.queue.producer_addition().to_wake.load(Ordering::SeqCst); + self.queue.producer_addition().to_wake.store(0, Ordering::SeqCst); assert!(ptr != 0); unsafe { SignalToken::cast_from_usize(ptr) } } @@ -154,14 +168,16 @@ impl Packet { // back if it shouldn't sleep. Note that this is the location where we take // steals into account. fn decrement(&self, token: SignalToken) -> Result<(), SignalToken> { - assert_eq!(self.to_wake.load(Ordering::SeqCst), 0); + assert_eq!(self.queue.producer_addition().to_wake.load(Ordering::SeqCst), 0); let ptr = unsafe { token.cast_to_usize() }; - self.to_wake.store(ptr, Ordering::SeqCst); + self.queue.producer_addition().to_wake.store(ptr, Ordering::SeqCst); - let steals = unsafe { ptr::replace(self.steals.get(), 0) }; + let steals = unsafe { ptr::replace(self.queue.consumer_addition().steals.get(), 0) }; - match self.cnt.fetch_sub(1 + steals, Ordering::SeqCst) { - DISCONNECTED => { self.cnt.store(DISCONNECTED, Ordering::SeqCst); } + match self.queue.producer_addition().cnt.fetch_sub(1 + steals, Ordering::SeqCst) { + DISCONNECTED => { + self.queue.producer_addition().cnt.store(DISCONNECTED, Ordering::SeqCst); + } // If we factor in our steals and notice that the channel has no // data, we successfully sleep n => { @@ -170,7 +186,7 @@ impl Packet { } } - self.to_wake.store(0, Ordering::SeqCst); + self.queue.producer_addition().to_wake.store(0, Ordering::SeqCst); Err(unsafe { SignalToken::cast_from_usize(ptr) }) } @@ -201,7 +217,7 @@ impl Packet { // "steal" factored into the channel count above). data @ Ok(..) | data @ Err(Upgraded(..)) => unsafe { - *self.steals.get() -= 1; + *self.queue.consumer_addition().steals.get() -= 1; data }, @@ -223,20 +239,21 @@ impl Packet { // down as much as possible (without going negative), and then // adding back in whatever we couldn't factor into steals. Some(data) => unsafe { - if *self.steals.get() > MAX_STEALS { - match self.cnt.swap(0, Ordering::SeqCst) { + if *self.queue.consumer_addition().steals.get() > MAX_STEALS { + match self.queue.producer_addition().cnt.swap(0, Ordering::SeqCst) { DISCONNECTED => { - self.cnt.store(DISCONNECTED, Ordering::SeqCst); + self.queue.producer_addition().cnt.store( + DISCONNECTED, Ordering::SeqCst); } n => { - let m = cmp::min(n, *self.steals.get()); - *self.steals.get() -= m; + let m = cmp::min(n, *self.queue.consumer_addition().steals.get()); + *self.queue.consumer_addition().steals.get() -= m; self.bump(n - m); } } - assert!(*self.steals.get() >= 0); + assert!(*self.queue.consumer_addition().steals.get() >= 0); } - *self.steals.get() += 1; + *self.queue.consumer_addition().steals.get() += 1; match data { Data(t) => Ok(t), GoUp(up) => Err(Upgraded(up)), @@ -244,7 +261,7 @@ impl Packet { }, None => { - match self.cnt.load(Ordering::SeqCst) { + match self.queue.producer_addition().cnt.load(Ordering::SeqCst) { n if n != DISCONNECTED => Err(Empty), // This is a little bit of a tricky case. We failed to pop @@ -273,7 +290,7 @@ impl Packet { pub fn drop_chan(&self) { // Dropping a channel is pretty simple, we just flag it as disconnected // and then wakeup a blocker if there is one. - match self.cnt.swap(DISCONNECTED, Ordering::SeqCst) { + match self.queue.producer_addition().cnt.swap(DISCONNECTED, Ordering::SeqCst) { -1 => { self.take_to_wake().signal(); } DISCONNECTED => {} n => { assert!(n >= 0); } @@ -300,7 +317,7 @@ impl Packet { // sends are gated on this flag, so we're immediately guaranteed that // there are a bounded number of active sends that we'll have to deal // with. - self.port_dropped.store(true, Ordering::SeqCst); + self.queue.producer_addition().port_dropped.store(true, Ordering::SeqCst); // Now that we're guaranteed to deal with a bounded number of senders, // we need to drain the queue. This draining process happens atomically @@ -310,9 +327,9 @@ impl Packet { // continue to fail while active senders send data while we're dropping // data, but eventually we're guaranteed to break out of this loop // (because there is a bounded number of senders). - let mut steals = unsafe { *self.steals.get() }; + let mut steals = unsafe { *self.queue.consumer_addition().steals.get() }; while { - let cnt = self.cnt.compare_and_swap( + let cnt = self.queue.producer_addition().cnt.compare_and_swap( steals, DISCONNECTED, Ordering::SeqCst); cnt != DISCONNECTED && cnt != steals } { @@ -353,9 +370,9 @@ impl Packet { // increment the count on the channel (used for selection) fn bump(&self, amt: isize) -> isize { - match self.cnt.fetch_add(amt, Ordering::SeqCst) { + match self.queue.producer_addition().cnt.fetch_add(amt, Ordering::SeqCst) { DISCONNECTED => { - self.cnt.store(DISCONNECTED, Ordering::SeqCst); + self.queue.producer_addition().cnt.store(DISCONNECTED, Ordering::SeqCst); DISCONNECTED } n => n @@ -404,8 +421,8 @@ impl Packet { // this end. This is fine because we know it's a small bounded windows // of time until the data is actually sent. if was_upgrade { - assert_eq!(unsafe { *self.steals.get() }, 0); - assert_eq!(self.to_wake.load(Ordering::SeqCst), 0); + assert_eq!(unsafe { *self.queue.consumer_addition().steals.get() }, 0); + assert_eq!(self.queue.producer_addition().to_wake.load(Ordering::SeqCst), 0); return Ok(true) } @@ -418,7 +435,7 @@ impl Packet { // If we were previously disconnected, then we know for sure that there // is no thread in to_wake, so just keep going let has_data = if prev == DISCONNECTED { - assert_eq!(self.to_wake.load(Ordering::SeqCst), 0); + assert_eq!(self.queue.producer_addition().to_wake.load(Ordering::SeqCst), 0); true // there is data, that data is that we're disconnected } else { let cur = prev + steals + 1; @@ -441,13 +458,13 @@ impl Packet { if prev < 0 { drop(self.take_to_wake()); } else { - while self.to_wake.load(Ordering::SeqCst) != 0 { + while self.queue.producer_addition().to_wake.load(Ordering::SeqCst) != 0 { thread::yield_now(); } } unsafe { - assert_eq!(*self.steals.get(), 0); - *self.steals.get() = steals; + assert_eq!(*self.queue.consumer_addition().steals.get(), 0); + *self.queue.consumer_addition().steals.get() = steals; } // if we were previously positive, then there's surely data to @@ -481,7 +498,7 @@ impl Drop for Packet { // disconnection, but also a proper fence before the read of // `to_wake`, so this assert cannot be removed with also removing // the `to_wake` assert. - assert_eq!(self.cnt.load(Ordering::SeqCst), DISCONNECTED); - assert_eq!(self.to_wake.load(Ordering::SeqCst), 0); + assert_eq!(self.queue.producer_addition().cnt.load(Ordering::SeqCst), DISCONNECTED); + assert_eq!(self.queue.producer_addition().to_wake.load(Ordering::SeqCst), 0); } } -- cgit 1.4.1-3-g733a5 From 9854e836a35c3114c81b8102d3468ff9071b4141 Mon Sep 17 00:00:00 2001 From: Federico Mena Quintero Date: Mon, 2 Oct 2017 13:53:50 -0500 Subject: Remove the implication that CString contains UTF-8 data. --- src/libstd/ffi/c_str.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs index 01d2b70e423..0d0280e2586 100644 --- a/src/libstd/ffi/c_str.rs +++ b/src/libstd/ffi/c_str.rs @@ -23,10 +23,11 @@ use ptr; use slice; use str::{self, Utf8Error}; -/// A type representing an owned, C-compatible, UTF-8 string. +/// A type representing an owned, C-compatible, nul-terminated string with no nul bytes in the +/// middle. /// /// This type serves the purpose of being able to safely generate a -/// C-compatible UTF-8 string from a Rust byte slice or vector. An instance of this +/// C-compatible string from a Rust byte slice or vector. An instance of this /// type is a static guarantee that the underlying bytes contain no interior 0 /// bytes ("nul characters") and that the final byte is 0 ("nul terminator"). /// @@ -443,7 +444,7 @@ impl CString { Box::into_raw(self.into_inner()) as *mut c_char } - /// Converts the `CString` into a [`String`] if it contains valid Unicode data. + /// Converts the `CString` into a [`String`] if it contains valid UTF-8 data. /// /// On failure, ownership of the original `CString` is returned. /// -- cgit 1.4.1-3-g733a5 From 50505aadbd9314375a56bf397a4a97f0102180ce Mon Sep 17 00:00:00 2001 From: Federico Mena Quintero Date: Mon, 2 Oct 2017 14:16:37 -0500 Subject: Clarify the ffi module's toplevel docs, per @clarcharr's comments --- src/libstd/ffi/mod.rs | 119 +++++++++++++++++++++++++++----------------------- 1 file changed, 65 insertions(+), 54 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/ffi/mod.rs b/src/libstd/ffi/mod.rs index 1214a2406e2..f8a4a904fc5 100644 --- a/src/libstd/ffi/mod.rs +++ b/src/libstd/ffi/mod.rs @@ -8,9 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! This module provides utilities to handle C-like strings. It is -//! mainly of use for FFI (Foreign Function Interface) bindings and -//! code that needs to exchange C-like strings with other languages. +//! This module provides utilities to handle data across non-Rust +//! interfaces, like other programming languages and the underlying +//! operating system. It is mainly of use for FFI (Foreign Function +//! Interface) bindings and code that needs to exchange C-like strings +//! with other languages. //! //! # Overview //! @@ -18,68 +20,74 @@ //! borrowed slices of strings with the [`str`] primitive. Both are //! always in UTF-8 encoding, and may contain nul bytes in the middle, //! i.e. if you look at the bytes that make up the string, there may -//! be a `0` among them. Both `String` and `str` know their length; -//! there are no nul terminators at the end of strings like in C. +//! be a `\0` among them. Both `String` and `str` store their length +//! explicitly; there are no nul terminators at the end of strings +//! like in C. //! //! C strings are different from Rust strings: //! -//! * **Encodings** - C strings may have different encodings. If -//! you are bringing in strings from C APIs, you should check what -//! encoding you are getting. Rust strings are always UTF-8. +//! * **Encodings** - Rust strings are UTF-8, but C strings may use +//! other encodings. If you are using a string from C, you should +//! check its encoding explicitly, rather than just assuming that it +//! is UTF-8 like you can do in Rust. //! -//! * **Character width** - C strings may use "normal" or "wide" -//! characters, i.e. `char` or `wchar_t`, respectively. The C -//! standard leaves the actual sizes of those types open to +//! * **Character size** - C strings may use `char` or `wchar_t`-sized +//! characters; please **note** that C's `char` is different from Rust's. +//! The C standard leaves the actual sizes of those types open to //! interpretation, but defines different APIs for strings made up of //! each character type. Rust strings are always UTF-8, so different //! Unicode characters will be encoded in a variable number of bytes -//! each. The Rust type [`char`] represents a '[Unicode -//! scalar value]', which is similar to, but not the same as, a -//! '[Unicode code point]'. +//! each. The Rust type [`char`] represents a '[Unicode scalar +//! value]', which is similar to, but not the same as, a '[Unicode +//! code point]'. //! //! * **Nul terminators and implicit string lengths** - Often, C -//! strings are nul-terminated, i.e. they have a `0` character at the -//! end. The length of a string buffer is not known *a priori*; -//! instead, to compute the length of a string, C code must manually -//! call a function like `strlen()` for `char`-based strings, or -//! `wcslen()` for `wchar_t`-based ones. Those functions return the -//! number of characters in the string excluding the nul terminator, -//! so the buffer length is really `len+1` characters. Rust strings -//! don't have a nul terminator, and they always know their length. -//! -//! * **No nul characters in the middle of the string** - When C -//! strings have a nul terminator character, this usually means that -//! they cannot have nul characters in the middle — a nul character -//! would essentially truncate the string. Rust strings *can* have -//! nul characters in the middle, since they don't use nul -//! terminators. +//! strings are nul-terminated, i.e. they have a `\0` character at the +//! end. The length of a string buffer is not stored, but has to be +//! calculated; to compute the length of a string, C code must +//! manually call a function like `strlen()` for `char`-based strings, +//! or `wcslen()` for `wchar_t`-based ones. Those functions return +//! the number of characters in the string excluding the nul +//! terminator, so the buffer length is really `len+1` characters. +//! Rust strings don't have a nul terminator; their length is always +//! stored and does not need to be calculated. While in Rust +//! accessing a string's length is a O(1) operation (becasue the +//! length is stored); in C it is an O(length) operation because the +//! length needs to be computed by scanning the string for the nul +//! terminator. +//! +//! * **Internal nul characters** - When C strings have a nul +//! terminator character, this usually means that they cannot have nul +//! characters in the middle — a nul character would essentially +//! truncate the string. Rust strings *can* have nul characters in +//! the middle, because nul does not have to mark the end of the +//! string in Rust. //! //! # Representations of non-Rust strings //! //! [`CString`] and [`CStr`] are useful when you need to transfer -//! UTF-8 strings to and from C, respectively: +//! UTF-8 strings to and from languages with a C ABI, like Python. //! //! * **From Rust to C:** [`CString`] represents an owned, C-friendly -//! UTF-8 string: it is valid UTF-8, it is nul-terminated, and has no -//! nul characters in the middle. Rust code can create a `CString` -//! out of a normal string (provided that the string doesn't have nul -//! characters in the middle), and then use a variety of methods to -//! obtain a raw `*mut u8` that can then be passed as an argument to C -//! functions. +//! string: it is nul-terminated, and has no internal nul characters. +//! Rust code can create a `CString` out of a normal string (provided +//! that the string doesn't have nul characters in the middle), and +//! then use a variety of methods to obtain a raw `*mut u8` that can +//! then be passed as an argument to functions which use the C +//! conventions for strings. //! //! * **From C to Rust:** [`CStr`] represents a borrowed C string; it //! is what you would use to wrap a raw `*const u8` that you got from -//! a C function. A `CStr` is just guaranteed to be a nul-terminated -//! array of bytes; the UTF-8 validation step only happens when you -//! request to convert it to a `&str`. +//! a C function. A `CStr` is guaranteed to be a nul-terminated array +//! of bytes. Once you have a `CStr`, you can convert it to a Rust +//! `&str` if it's valid UTF-8, or lossily convert it by adding +//! replacement characters. //! //! [`OsString`] and [`OsStr`] are useful when you need to transfer -//! strings to and from operating system calls. If you need Rust -//! strings out of them, they can take care of conversion to and from -//! the operating system's preferred form for strings — of course, it -//! may not be possible to convert all valid operating system strings -//! into valid UTF-8; the `OsString` and `OsStr` functions let you know -//! when this is the case. +//! strings to and from the operating system itself, or when capturing +//! the output of external commands. Conversions between `OsString`, +//! `OsStr` and Rust strings work similarly to those for [`CString`] +//! and [`CStr`]. //! //! * [`OsString`] represents an owned string in whatever //! representation the operating system prefers. In the Rust standard @@ -101,9 +109,10 @@ //! //! ## On Unix //! -//! On Unix, [`OsStr`] implements the `std::os::unix:ffi::`[`OsStrExt`][unix.OsStrExt] trait, which -//! augments it with two methods, [`from_bytes`] and [`as_bytes`]. These do inexpensive conversions -//! from and to UTF-8 byte slices. +//! On Unix, [`OsStr`] implements the +//! `std::os::unix:ffi::`[`OsStrExt`][unix.OsStrExt] trait, which +//! augments it with two methods, [`from_bytes`] and [`as_bytes`]. +//! These do inexpensive conversions from and to UTF-8 byte slices. //! //! Additionally, on Unix [`OsString`] implements the //! `std::os::unix:ffi::`[`OsStringExt`][unix.OsStringExt] trait, @@ -112,14 +121,16 @@ //! //! ## On Windows //! -//! On Windows, [`OsStr`] implements the `std::os::windows::ffi::`[`OsStrExt`][windows.OsStrExt] -//! trait, which provides an [`encode_wide`] method. This provides an iterator that can be -//! [`collect`]ed into a vector of [`u16`]. +//! On Windows, [`OsStr`] implements the +//! `std::os::windows::ffi::`[`OsStrExt`][windows.OsStrExt] trait, +//! which provides an [`encode_wide`] method. This provides an +//! iterator that can be [`collect`]ed into a vector of [`u16`]. //! //! Additionally, on Windows [`OsString`] implements the -//! `std::os::windows:ffi::`[`OsStringExt`][windows.OsStringExt] trait, which provides a -//! [`from_wide`] method. The result of this method is an `OsString` which can be round-tripped to -//! a Windows string losslessly. +//! `std::os::windows:ffi::`[`OsStringExt`][windows.OsStringExt] +//! trait, which provides a [`from_wide`] method. The result of this +//! method is an `OsString` which can be round-tripped to a Windows +//! string losslessly. //! //! [`String`]: ../string/struct.String.html //! [`str`]: ../primitive.str.html -- cgit 1.4.1-3-g733a5 From d989cd02b56524470cc8721f296add7039821777 Mon Sep 17 00:00:00 2001 From: Federico Mena Quintero Date: Mon, 2 Oct 2017 15:46:10 -0500 Subject: Fix broken links in documentation --- src/libstd/ffi/os_str.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/ffi/os_str.rs b/src/libstd/ffi/os_str.rs index b6032f7c74c..94b6911283b 100644 --- a/src/libstd/ffi/os_str.rs +++ b/src/libstd/ffi/os_str.rs @@ -70,9 +70,9 @@ use sys_common::{AsInner, IntoInner, FromInner}; /// [`u8`]: ../primitive.u8.html /// [`u16`]: ../primitive.u16.html /// [String.push_str]: ../string/struct.String.html#method.push_str -/// [`new`]: #struct.OsString.html#method.new -/// [`push`]: #struct.OsString.html#method.push -/// [`as_os_str`]: #struct.OsString.html#method.as_os_str +/// [`new`]: #method.new +/// [`push`]: #method.push +/// [`as_os_str`]: #method.as_os_str #[derive(Clone)] #[stable(feature = "rust1", since = "1.0.0")] pub struct OsString { -- cgit 1.4.1-3-g733a5 From b5b7666120658e332c1ea26e8bb3944aefde31ca Mon Sep 17 00:00:00 2001 From: Jake Goulding Date: Sun, 1 Oct 2017 14:55:58 -0400 Subject: Don't encourage people to ignore threading errors in the docs --- src/libstd/thread/mod.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index 30887b16c60..07bbddc62b9 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -485,15 +485,17 @@ impl Builder { /// let (tx, rx) = channel(); /// /// let sender = thread::spawn(move || { -/// let _ = tx.send("Hello, thread".to_owned()); +/// tx.send("Hello, thread".to_owned()) +/// .expect("Unable to send on channel"); /// }); /// /// let receiver = thread::spawn(move || { -/// println!("{}", rx.recv().unwrap()); +/// let value = rx.recv().expect("Unable to receive from channel"); +/// println!("{}", value); /// }); /// -/// let _ = sender.join(); -/// let _ = receiver.join(); +/// sender.join().expect("The sender thread has panicked"); +/// receiver.join().expect("The receiver thread has panicked"); /// ``` /// /// A thread can also return a value through its [`JoinHandle`], you can use @@ -1192,7 +1194,7 @@ impl JoinInner { /// }); /// }); /// -/// let _ = original_thread.join(); +/// original_thread.join().expect("The thread being joined has panicked"); /// println!("Original thread is joined."); /// /// // We make sure that the new thread has time to run, before the main -- cgit 1.4.1-3-g733a5 From 19029d5627218aa01f52c68b27dec71d39974cd7 Mon Sep 17 00:00:00 2001 From: Pirh Date: Sun, 8 Oct 2017 17:12:14 +0100 Subject: Add links and examples for std::process::Stdio As per #29370 --- src/libstd/process.rs | 109 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 108 insertions(+), 1 deletion(-) (limited to 'src/libstd') diff --git a/src/libstd/process.rs b/src/libstd/process.rs index dbb58991215..2b3f49ee3f7 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -742,21 +742,128 @@ impl fmt::Debug for Output { } } -/// Describes what to do with a standard I/O stream for a child process. +/// Describes what to do with a standard I/O stream for a child process when +/// passed to the [`stdin`], [`stdout`], and [`stderr`] methods of [`Command`]. +/// +/// [`stdin`]: ./struct.Command.html#method.stdin +/// [`stdout`]: ./struct.Command.html#method.stdout +/// [`stderr`]: ./struct.Command.html#method.stderr +/// [`Command`]: ./struct.Command.html #[stable(feature = "process", since = "1.0.0")] pub struct Stdio(imp::Stdio); impl Stdio { /// A new pipe should be arranged to connect the parent and child processes. + /// + /// # Examples + /// + /// With stdout: + /// + /// ```no_run + /// use std::process::{Command, Stdio}; + /// + /// let output = Command::new("echo") + /// .arg("Hello, world!") + /// .stdout(Stdio::piped()) + /// .output() + /// .expect("Failed to execute command"); + /// + /// assert_eq!(String::from_utf8_lossy(&output.stdout), "Hello, world!\n"); + /// // Nothing echoed to console + /// ``` + /// + /// With stdin: + /// + /// ```no_run + /// use std::io::Write; + /// use std::process::{Command, Stdio}; + /// + /// let mut child = Command::new("rev") + /// .stdin(Stdio::piped()) + /// .stdout(Stdio::piped()) + /// .spawn() + /// .expect("Failed to spawn child process"); + /// + /// { + /// let mut stdin = child.stdin.as_mut().expect("Failed to open stdin"); + /// stdin.write_all("Hello, world!".as_bytes()).expect("Failed to write to stdin"); + /// } + /// + /// let output = child.wait_with_output().expect("Failed to read stdout"); + /// assert_eq!(String::from_utf8_lossy(&output.stdout), "!dlrow ,olleH\n"); + /// ``` #[stable(feature = "process", since = "1.0.0")] pub fn piped() -> Stdio { Stdio(imp::Stdio::MakePipe) } /// The child inherits from the corresponding parent descriptor. + /// + /// # Examples + /// + /// With stdout: + /// + /// ```no_run + /// use std::process::{Command, Stdio}; + /// + /// let output = Command::new("echo") + /// .arg("Hello, world!") + /// .stdout(Stdio::inherit()) + /// .output() + /// .expect("Failed to execute command"); + /// + /// assert_eq!(String::from_utf8_lossy(&output.stdout), ""); + /// // "Hello, world!" echoed to console + /// ``` + /// + /// With stdin: + /// + /// ```no_run + /// use std::process::{Command, Stdio}; + /// + /// let output = Command::new("rev") + /// .stdin(Stdio::inherit()) + /// .stdout(Stdio::piped()) + /// .output() + /// .expect("Failed to execute command"); + /// + /// println!("You piped in the reverse of: {}", String::from_utf8_lossy(&output.stdout)); + /// ``` #[stable(feature = "process", since = "1.0.0")] pub fn inherit() -> Stdio { Stdio(imp::Stdio::Inherit) } /// This stream will be ignored. This is the equivalent of attaching the /// stream to `/dev/null` + /// + /// # Examples + /// + /// With stdout: + /// + /// ```no_run + /// use std::process::{Command, Stdio}; + /// + /// let output = Command::new("echo") + /// .arg("Hello, world!") + /// .stdout(Stdio::null()) + /// .output() + /// .expect("Failed to execute command"); + /// + /// assert_eq!(String::from_utf8_lossy(&output.stdout), ""); + /// // Nothing echoed to console + /// ``` + /// + /// With stdin: + /// + /// ```no_run + /// use std::process::{Command, Stdio}; + /// + /// let output = Command::new("rev") + /// .stdin(Stdio::null()) + /// .stdout(Stdio::piped()) + /// .output() + /// .expect("Failed to execute command"); + /// + /// assert_eq!(String::from_utf8_lossy(&output.stdout), ""); + /// // Ignores any piped-in input + /// ``` #[stable(feature = "process", since = "1.0.0")] pub fn null() -> Stdio { Stdio(imp::Stdio::Null) } } -- cgit 1.4.1-3-g733a5 From 977200310abe3ca6c71d467e585654537b5309c2 Mon Sep 17 00:00:00 2001 From: Pirh Date: Sun, 8 Oct 2017 19:09:16 +0100 Subject: Remove ./ prefix from relative URLs Also remove trailing whitespace to pass tidy checks. --- src/libstd/process.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/process.rs b/src/libstd/process.rs index 2b3f49ee3f7..af64e681820 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -745,10 +745,10 @@ impl fmt::Debug for Output { /// Describes what to do with a standard I/O stream for a child process when /// passed to the [`stdin`], [`stdout`], and [`stderr`] methods of [`Command`]. /// -/// [`stdin`]: ./struct.Command.html#method.stdin -/// [`stdout`]: ./struct.Command.html#method.stdout -/// [`stderr`]: ./struct.Command.html#method.stderr -/// [`Command`]: ./struct.Command.html +/// [`stdin`]: struct.Command.html#method.stdin +/// [`stdout`]: struct.Command.html#method.stdout +/// [`stderr`]: struct.Command.html#method.stderr +/// [`Command`]: struct.Command.html #[stable(feature = "process", since = "1.0.0")] pub struct Stdio(imp::Stdio); @@ -783,12 +783,12 @@ impl Stdio { /// .stdout(Stdio::piped()) /// .spawn() /// .expect("Failed to spawn child process"); - /// + /// /// { /// let mut stdin = child.stdin.as_mut().expect("Failed to open stdin"); /// stdin.write_all("Hello, world!".as_bytes()).expect("Failed to write to stdin"); /// } - /// + /// /// let output = child.wait_with_output().expect("Failed to read stdout"); /// assert_eq!(String::from_utf8_lossy(&output.stdout), "!dlrow ,olleH\n"); /// ``` @@ -818,13 +818,13 @@ impl Stdio { /// /// ```no_run /// use std::process::{Command, Stdio}; - /// + /// /// let output = Command::new("rev") /// .stdin(Stdio::inherit()) /// .stdout(Stdio::piped()) /// .output() /// .expect("Failed to execute command"); - /// + /// /// println!("You piped in the reverse of: {}", String::from_utf8_lossy(&output.stdout)); /// ``` #[stable(feature = "process", since = "1.0.0")] @@ -854,13 +854,13 @@ impl Stdio { /// /// ```no_run /// use std::process::{Command, Stdio}; - /// + /// /// let output = Command::new("rev") /// .stdin(Stdio::null()) /// .stdout(Stdio::piped()) /// .output() /// .expect("Failed to execute command"); - /// + /// /// assert_eq!(String::from_utf8_lossy(&output.stdout), ""); /// // Ignores any piped-in input /// ``` -- cgit 1.4.1-3-g733a5 From 32c4b714715338e82711e3611681aada3f28cf39 Mon Sep 17 00:00:00 2001 From: Pirh Date: Sun, 8 Oct 2017 22:11:20 +0100 Subject: Link std::process::Output to Command and Child --- src/libstd/process.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'src/libstd') diff --git a/src/libstd/process.rs b/src/libstd/process.rs index dbb58991215..847dbd14dd6 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -701,7 +701,14 @@ impl AsInnerMut for Command { fn as_inner_mut(&mut self) -> &mut imp::Command { &mut self.inner } } -/// The output of a finished process. +/// The output of a finished process. This is returned in a Result by +/// either the [`output`] method of a [`Command`], or the +/// [`wait_with_output`] method of a [`Child`] process. +/// +/// [`Command`]: struct.Command.html +/// [`Child`]: struct.Child.html +/// [`output`]: struct.Command.html#method.output +/// [`wait_with_output`]: struct.Child.html#method.wait_with_output #[derive(PartialEq, Eq, Clone)] #[stable(feature = "process", since = "1.0.0")] pub struct Output { -- cgit 1.4.1-3-g733a5 From 41320fa52e1e4dd85a200a34195ae32d7efd13e0 Mon Sep 17 00:00:00 2001 From: JLockerman Date: Sun, 8 Oct 2017 18:40:45 -0400 Subject: cfg out Queue::new for emscripten Queue::new is only used is tests atm, which causes warnings on emscripten which does not run queue tests. --- src/libstd/sync/mpsc/spsc_queue.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/libstd') diff --git a/src/libstd/sync/mpsc/spsc_queue.rs b/src/libstd/sync/mpsc/spsc_queue.rs index 3ce59270335..45a00978b35 100644 --- a/src/libstd/sync/mpsc/spsc_queue.rs +++ b/src/libstd/sync/mpsc/spsc_queue.rs @@ -76,7 +76,7 @@ impl Node { } impl Queue { - #[cfg(test)] + #[cfg(all(test, not(target_os = "emscripten")))] /// Creates a new queue. /// /// This is unsafe as the type system doesn't enforce a single -- cgit 1.4.1-3-g733a5 From bb7945e2fe662c86cb8e9e3a93730f20b7480dca Mon Sep 17 00:00:00 2001 From: Joshua Lockerman Date: Fri, 29 Sep 2017 15:58:11 -0400 Subject: Remove Queue::new. --- src/libstd/sync/mpsc/spsc_queue.rs | 34 +++++----------------------------- 1 file changed, 5 insertions(+), 29 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/sync/mpsc/spsc_queue.rs b/src/libstd/sync/mpsc/spsc_queue.rs index 45a00978b35..cc4be92276a 100644 --- a/src/libstd/sync/mpsc/spsc_queue.rs +++ b/src/libstd/sync/mpsc/spsc_queue.rs @@ -75,30 +75,6 @@ impl Node { } } -impl Queue { - #[cfg(all(test, not(target_os = "emscripten")))] - /// Creates a new queue. - /// - /// This is unsafe as the type system doesn't enforce a single - /// consumer-producer relationship. It also allows the consumer to `pop` - /// items while there is a `peek` active due to all methods having a - /// non-mutable receiver. - /// - /// # Arguments - /// - /// * `bound` - This queue implementation is implemented with a linked - /// list, and this means that a push is always a malloc. In - /// order to amortize this cost, an internal cache of nodes is - /// maintained to prevent a malloc from always being - /// necessary. This bound is the limit on the size of the - /// cache (if desired). If the value is 0, then the cache has - /// no bound. Otherwise, the cache will never grow larger than - /// `bound` (although the queue itself could be much larger. - pub unsafe fn new(bound: usize) -> Queue { - Self::with_additions(bound, (), ()) - } -} - impl Queue { /// Creates a new queue. With given additional elements in the producer and @@ -275,7 +251,7 @@ mod tests { #[test] fn smoke() { unsafe { - let queue = Queue::new(0); + let queue = Queue::with_additions(0, (), ()); queue.push(1); queue.push(2); assert_eq!(queue.pop(), Some(1)); @@ -292,7 +268,7 @@ mod tests { #[test] fn peek() { unsafe { - let queue = Queue::new(0); + let queue = Queue::with_additions(0, (), ()); queue.push(vec![1]); // Ensure the borrowchecker works @@ -315,7 +291,7 @@ mod tests { #[test] fn drop_full() { unsafe { - let q: Queue> = Queue::new(0); + let q: Queue> = Queue::with_additions(0, (), ()); q.push(box 1); q.push(box 2); } @@ -324,7 +300,7 @@ mod tests { #[test] fn smoke_bound() { unsafe { - let q = Queue::new(0); + let q = Queue::with_additions(0, (), ()); q.push(1); q.push(2); assert_eq!(q.pop(), Some(1)); @@ -346,7 +322,7 @@ mod tests { } unsafe fn stress_bound(bound: usize) { - let q = Arc::new(Queue::new(bound)); + let q = Arc::new(Queue::with_additions(bound, (), ())); let (tx, rx) = channel(); let q2 = q.clone(); -- cgit 1.4.1-3-g733a5 From 679457ad2a0f33aed6b206107afedcccf5124374 Mon Sep 17 00:00:00 2001 From: Malo Jaffré Date: Mon, 9 Oct 2017 20:09:08 +0200 Subject: Refactor to use `debug_struct` in several Debug impls Fixes #44771. --- src/librustc_data_structures/graph/mod.rs | 15 ++------------- src/libstd/sync/mpsc/mod.rs | 24 +++--------------------- src/libstd/sync/mpsc/select.rs | 18 ++---------------- src/libstd/sync/mutex.rs | 13 ++++++++++--- src/libstd/sync/rwlock.rs | 13 ++++++++++--- src/libstd/sys_common/remutex.rs | 13 ++++++++++--- src/libsyntax_pos/lib.rs | 7 +++++-- 7 files changed, 42 insertions(+), 61 deletions(-) (limited to 'src/libstd') diff --git a/src/librustc_data_structures/graph/mod.rs b/src/librustc_data_structures/graph/mod.rs index 474622f3669..56d5f5ffa3f 100644 --- a/src/librustc_data_structures/graph/mod.rs +++ b/src/librustc_data_structures/graph/mod.rs @@ -31,7 +31,7 @@ //! be indexed by the direction (see the type `Direction`). use bitvec::BitVector; -use std::fmt::{Formatter, Error, Debug}; +use std::fmt::Debug; use std::usize; use snapshot_vec::{SnapshotVec, SnapshotVecDelegate}; @@ -48,6 +48,7 @@ pub struct Node { pub data: N, } +#[derive(Debug)] pub struct Edge { next_edge: [EdgeIndex; 2], // see module comment source: NodeIndex, @@ -69,18 +70,6 @@ impl SnapshotVecDelegate for Edge { fn reverse(_: &mut Vec>, _: ()) {} } -impl Debug for Edge { - fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { - write!(f, - "Edge {{ next_edge: [{:?}, {:?}], source: {:?}, target: {:?}, data: {:?} }}", - self.next_edge[0], - self.next_edge[1], - self.source, - self.target, - self.data) - } -} - #[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] pub struct NodeIndex(pub usize); diff --git a/src/libstd/sync/mpsc/mod.rs b/src/libstd/sync/mpsc/mod.rs index dcd4c8dfdf5..ce1a07b31b2 100644 --- a/src/libstd/sync/mpsc/mod.rs +++ b/src/libstd/sync/mpsc/mod.rs @@ -919,7 +919,7 @@ impl Drop for Sender { #[stable(feature = "mpsc_debug", since = "1.8.0")] impl fmt::Debug for Sender { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "Sender {{ .. }}") + f.debug_struct("Sender").finish() } } @@ -1049,7 +1049,7 @@ impl Drop for SyncSender { #[stable(feature = "mpsc_debug", since = "1.8.0")] impl fmt::Debug for SyncSender { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "SyncSender {{ .. }}") + f.debug_struct("SyncSender").finish() } } @@ -1551,7 +1551,7 @@ impl Drop for Receiver { #[stable(feature = "mpsc_debug", since = "1.8.0")] impl fmt::Debug for Receiver { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "Receiver {{ .. }}") + f.debug_struct("Receiver").finish() } } @@ -3009,22 +3009,4 @@ mod sync_tests { repro() } } - - #[test] - fn fmt_debug_sender() { - let (tx, _) = channel::(); - assert_eq!(format!("{:?}", tx), "Sender { .. }"); - } - - #[test] - fn fmt_debug_recv() { - let (_, rx) = channel::(); - assert_eq!(format!("{:?}", rx), "Receiver { .. }"); - } - - #[test] - fn fmt_debug_sync_sender() { - let (tx, _) = sync_channel::(1); - assert_eq!(format!("{:?}", tx), "SyncSender { .. }"); - } } diff --git a/src/libstd/sync/mpsc/select.rs b/src/libstd/sync/mpsc/select.rs index e49f4cff024..a9f3cea243f 100644 --- a/src/libstd/sync/mpsc/select.rs +++ b/src/libstd/sync/mpsc/select.rs @@ -354,13 +354,13 @@ impl Iterator for Packets { impl fmt::Debug for Select { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "Select {{ .. }}") + f.debug_struct("Select").finish() } } impl<'rx, T:Send+'rx> fmt::Debug for Handle<'rx, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "Handle {{ .. }}") + f.debug_struct("Handle").finish() } } @@ -774,18 +774,4 @@ mod tests { } } } - - #[test] - fn fmt_debug_select() { - let sel = Select::new(); - assert_eq!(format!("{:?}", sel), "Select { .. }"); - } - - #[test] - fn fmt_debug_handle() { - let (_, rx) = channel::(); - let sel = Select::new(); - let handle = sel.handle(&rx); - assert_eq!(format!("{:?}", handle), "Handle { .. }"); - } } diff --git a/src/libstd/sync/mutex.rs b/src/libstd/sync/mutex.rs index 62d8de18f4b..a0349fe9d8b 100644 --- a/src/libstd/sync/mutex.rs +++ b/src/libstd/sync/mutex.rs @@ -384,11 +384,18 @@ impl Default for Mutex { impl fmt::Debug for Mutex { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self.try_lock() { - Ok(guard) => write!(f, "Mutex {{ data: {:?} }}", &*guard), + Ok(guard) => f.debug_struct("Mutex").field("data", &&*guard).finish(), Err(TryLockError::Poisoned(err)) => { - write!(f, "Mutex {{ data: Poisoned({:?}) }}", &**err.get_ref()) + f.debug_struct("Mutex").field("data", &&**err.get_ref()).finish() }, - Err(TryLockError::WouldBlock) => write!(f, "Mutex {{ }}") + Err(TryLockError::WouldBlock) => { + struct LockedPlaceholder; + impl fmt::Debug for LockedPlaceholder { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str("") } + } + + f.debug_struct("Mutex").field("data", &LockedPlaceholder).finish() + } } } } diff --git a/src/libstd/sync/rwlock.rs b/src/libstd/sync/rwlock.rs index 4757faabfb8..5c49d6b5845 100644 --- a/src/libstd/sync/rwlock.rs +++ b/src/libstd/sync/rwlock.rs @@ -428,11 +428,18 @@ unsafe impl<#[may_dangle] T: ?Sized> Drop for RwLock { impl fmt::Debug for RwLock { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self.try_read() { - Ok(guard) => write!(f, "RwLock {{ data: {:?} }}", &*guard), + Ok(guard) => f.debug_struct("RwLock").field("data", &&*guard).finish(), Err(TryLockError::Poisoned(err)) => { - write!(f, "RwLock {{ data: Poisoned({:?}) }}", &**err.get_ref()) + f.debug_struct("RwLock").field("data", &&**err.get_ref()).finish() }, - Err(TryLockError::WouldBlock) => write!(f, "RwLock {{ }}") + Err(TryLockError::WouldBlock) => { + struct LockedPlaceholder; + impl fmt::Debug for LockedPlaceholder { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str("") } + } + + f.debug_struct("RwLock").field("data", &LockedPlaceholder).finish() + } } } } diff --git a/src/libstd/sys_common/remutex.rs b/src/libstd/sys_common/remutex.rs index 4d0407ccf6c..ce43ec6d9ab 100644 --- a/src/libstd/sys_common/remutex.rs +++ b/src/libstd/sys_common/remutex.rs @@ -116,11 +116,18 @@ impl Drop for ReentrantMutex { impl fmt::Debug for ReentrantMutex { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self.try_lock() { - Ok(guard) => write!(f, "ReentrantMutex {{ data: {:?} }}", &*guard), + Ok(guard) => f.debug_struct("ReentrantMutex").field("data", &*guard).finish(), Err(TryLockError::Poisoned(err)) => { - write!(f, "ReentrantMutex {{ data: Poisoned({:?}) }}", &**err.get_ref()) + f.debug_struct("ReentrantMutex").field("data", &**err.get_ref()).finish() }, - Err(TryLockError::WouldBlock) => write!(f, "ReentrantMutex {{ }}") + Err(TryLockError::WouldBlock) => { + struct LockedPlaceholder; + impl fmt::Debug for LockedPlaceholder { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str("") } + } + + f.debug_struct("ReentrantMutex").field("data", &LockedPlaceholder).finish() + } } } } diff --git a/src/libsyntax_pos/lib.rs b/src/libsyntax_pos/lib.rs index 582f2798181..a06873aac0e 100644 --- a/src/libsyntax_pos/lib.rs +++ b/src/libsyntax_pos/lib.rs @@ -338,8 +338,11 @@ impl serialize::UseSpecializedDecodable for Span { } fn default_span_debug(span: Span, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "Span {{ lo: {:?}, hi: {:?}, ctxt: {:?} }}", - span.lo(), span.hi(), span.ctxt()) + f.debug_struct("Span") + .field("lo", &span.lo()) + .field("hi", &span.hi()) + .field("ctxt", &span.ctxt()) + .finish() } impl fmt::Debug for Span { -- cgit 1.4.1-3-g733a5 From d5bdfbced63c3d31b0f55a999cd0beb9de286d01 Mon Sep 17 00:00:00 2001 From: Federico Mena Quintero Date: Wed, 11 Oct 2017 17:51:37 -0500 Subject: ffi/c_str.rs: Make all descriptions have a single-sentence summary at the beginning Per https://github.com/rust-lang/rust/pull/44855#discussion_r144048837 and subsequent ones. --- src/libstd/ffi/c_str.rs | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs index 0d0280e2586..6541ad3f872 100644 --- a/src/libstd/ffi/c_str.rs +++ b/src/libstd/ffi/c_str.rs @@ -208,11 +208,12 @@ pub struct CStr { inner: [c_char] } -/// An error returned from [`CString::new`] to indicate that a nul byte was found -/// in the vector provided. While Rust strings may contain nul bytes in the middle, -/// C strings can't, as that byte would effectively truncate the string. +/// An error indicating that an interior nul byte was found. /// -/// This `struct` is created by the [`new`][`CString::new`] method on +/// While Rust strings may contain nul bytes in the middle, C strings +/// can't, as that byte would effectively truncate the string. +/// +/// This error is created by the [`new`][`CString::new`] method on /// [`CString`]. See its documentation for more. /// /// [`CString`]: struct.CString.html @@ -229,13 +230,12 @@ pub struct CStr { #[stable(feature = "rust1", since = "1.0.0")] pub struct NulError(usize, Vec); -/// An error returned from [`CStr::from_bytes_with_nul`] to indicate -/// that a nul byte was found too early in the slice provided, or one -/// wasn't found at all for the nul terminator. The slice used to -/// create a `CStr` must have one and only one nul byte at the end of -/// the slice. +/// An error indicating that a nul byte was not in the expected position. /// -/// This `struct` is created by the +/// The slice used to create a [`CStr`] must have one and only one nul +/// byte at the end of the slice. +/// +/// This error is created by the /// [`from_bytes_with_nul`][`CStr::from_bytes_with_nul`] method on /// [`CStr`]. See its documentation for more. /// @@ -274,16 +274,17 @@ impl FromBytesWithNulError { } } -/// An error returned from [`CString::into_string`] to indicate that a -/// UTF-8 error was encountered during the conversion. `CString` is -/// just a wrapper over a buffer of bytes with a nul terminator; -/// [`into_string`][`CString::into_string`] performs UTF-8 validation -/// and may return this error. +/// An error indicating invalid UTF-8 when converting a [`CString`] into a [`String`]. +/// +/// `CString` is just a wrapper over a buffer of bytes with a nul +/// terminator; [`into_string`][`CString::into_string`] performs UTF-8 +/// validation on those bytes and may return this error. /// /// This `struct` is created by the /// [`into_string`][`CString::into_string`] method on [`CString`]. See /// its documentation for more. /// +/// [`String`]: ../string/struct.String.html /// [`CString`]: struct.CString.html /// [`CString::into_string`]: struct.CString.html#method.into_string #[derive(Clone, PartialEq, Eq, Debug)] -- cgit 1.4.1-3-g733a5 From a9a4ce6dcc694e2ea35344aa790a73a5dea573f0 Mon Sep 17 00:00:00 2001 From: Federico Mena Quintero Date: Wed, 11 Oct 2017 17:52:39 -0500 Subject: ffi/c_str.rs: Fix method/function confusion Per https://github.com/rust-lang/rust/pull/44855#discussion_r144049179 --- src/libstd/ffi/c_str.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs index 6541ad3f872..51a5865d29c 100644 --- a/src/libstd/ffi/c_str.rs +++ b/src/libstd/ffi/c_str.rs @@ -297,10 +297,10 @@ pub struct IntoStringError { impl CString { /// Creates a new C-compatible string from a container of bytes. /// - /// This method will consume the provided data and use the + /// This function will consume the provided data and use the /// underlying bytes to construct a new string, ensuring that - /// there is a trailing 0 byte. This trailing 0 byte will be - /// appended by this method; the provided data should *not* + /// there is a trailing 0 byte. This trailing 0 byte will be + /// appended by this function; the provided data should *not* /// contain any 0 bytes in it. /// /// # Examples -- cgit 1.4.1-3-g733a5 From 026451093dbce9d1d2077d4c2bae3a92d413c203 Mon Sep 17 00:00:00 2001 From: Federico Mena Quintero Date: Wed, 11 Oct 2017 17:53:13 -0500 Subject: ffi/c_str.rs: Use only one space after a period ending a sentence --- src/libstd/ffi/c_str.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs index 51a5865d29c..7d3313fb9d5 100644 --- a/src/libstd/ffi/c_str.rs +++ b/src/libstd/ffi/c_str.rs @@ -49,7 +49,7 @@ use str::{self, Utf8Error}; /// # Extracting a raw pointer to the whole C string /// /// `CString` implements a [`as_ptr`] method through the [`Deref`] -/// trait. This method will give you a `*const c_char` which you can +/// trait. This method will give you a `*const c_char` which you can /// feed directly to extern functions that expect a nul-terminated /// string, like C's `strdup()`. /// @@ -70,7 +70,7 @@ use str::{self, Utf8Error}; /// Once you have the kind of slice you need (with or without a nul /// terminator), you can call the slice's own /// [`as_ptr`][slice.as_ptr] method to get a raw pointer to pass to -/// extern functions. See the documentation for that function for a +/// extern functions. See the documentation for that function for a /// discussion on ensuring the lifetime of the raw pointer. /// /// [`Into`]: ../convert/trait.Into.html @@ -130,8 +130,8 @@ pub struct CString { /// Representation of a borrowed C string. /// /// This type represents a borrowed reference to a nul-terminated -/// array of bytes. It can be constructed safely from a `&[`[`u8`]`]` -/// slice, or unsafely from a raw `*const c_char`. It can then be +/// array of bytes. It can be constructed safely from a `&[`[`u8`]`]` +/// slice, or unsafely from a raw `*const c_char`. It can then be /// converted to a Rust [`&str`] by performing UTF-8 validation, or /// into an owned [`CString`]. /// @@ -374,7 +374,7 @@ impl CString { /// to undefined behavior or allocator corruption. /// /// > **Note:** If you need to borrow a string that was allocated by - /// > foreign code, use [`CStr`]. If you need to take ownership of + /// > foreign code, use [`CStr`]. If you need to take ownership of /// > a string that was allocated by foreign code, you will need to /// > make your own provisions for freeing it appropriately, likely /// > with the foreign code's API to do that. @@ -521,7 +521,7 @@ impl CString { /// /// The returned slice does **not** contain the trailing nul /// terminator, and it is guaranteed to not have any interior nul - /// bytes. If you need the nul terminator, use + /// bytes. If you need the nul terminator, use /// [`as_bytes_with_nul`] instead. /// /// [`as_bytes_with_nul`]: #method.as_bytes_with_nul @@ -1035,7 +1035,7 @@ impl CStr { /// Yields a [`&str`] slice if the `CStr` contains valid UTF-8. /// /// If the contents of the `CStr` are valid UTF-8 data, this - /// function will return the corresponding [`&str`] slice. Otherwise, + /// function will return the corresponding [`&str`] slice. Otherwise, /// it will return an error with details of where UTF-8 validation failed. /// /// > **Note**: This method is currently implemented to check for validity @@ -1066,7 +1066,7 @@ impl CStr { /// /// If the contents of the `CStr` are valid UTF-8 data, this /// function will return a [`Cow`]`::`[`Borrowed`]`(`[`&str`]`)` - /// with the the corresponding [`&str`] slice. Otherwise, it will + /// with the the corresponding [`&str`] slice. Otherwise, it will /// replace any invalid UTF-8 sequences with `U+FFFD REPLACEMENT /// CHARACTER` and return a [`Cow`]`::`[`Owned`]`(`[`String`]`)` /// with the result. -- cgit 1.4.1-3-g733a5 From c8e232dfe83a95cf866c967752634db3ff7a98bb Mon Sep 17 00:00:00 2001 From: Federico Mena Quintero Date: Wed, 11 Oct 2017 17:55:01 -0500 Subject: ffi/mod.rs: Keep the one-sentence summary at the beginning of the module --- src/libstd/ffi/mod.rs | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/libstd') diff --git a/src/libstd/ffi/mod.rs b/src/libstd/ffi/mod.rs index f8a4a904fc5..6b751904c9f 100644 --- a/src/libstd/ffi/mod.rs +++ b/src/libstd/ffi/mod.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +//! Utilities related to FFI bindings. +//! //! This module provides utilities to handle data across non-Rust //! interfaces, like other programming languages and the underlying //! operating system. It is mainly of use for FFI (Foreign Function -- cgit 1.4.1-3-g733a5 From 5fb8e3d829e77643e9c153172fb3a67f85eebe81 Mon Sep 17 00:00:00 2001 From: Federico Mena Quintero Date: Wed, 11 Oct 2017 17:57:56 -0500 Subject: ffi/mod.rs: Use only one space after a period ending a sentence --- src/libstd/ffi/mod.rs | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/ffi/mod.rs b/src/libstd/ffi/mod.rs index 6b751904c9f..a75596351e4 100644 --- a/src/libstd/ffi/mod.rs +++ b/src/libstd/ffi/mod.rs @@ -12,24 +12,24 @@ //! //! This module provides utilities to handle data across non-Rust //! interfaces, like other programming languages and the underlying -//! operating system. It is mainly of use for FFI (Foreign Function +//! operating system. It is mainly of use for FFI (Foreign Function //! Interface) bindings and code that needs to exchange C-like strings //! with other languages. //! //! # Overview //! //! Rust represents owned strings with the [`String`] type, and -//! borrowed slices of strings with the [`str`] primitive. Both are +//! borrowed slices of strings with the [`str`] primitive. Both are //! always in UTF-8 encoding, and may contain nul bytes in the middle, //! i.e. if you look at the bytes that make up the string, there may -//! be a `\0` among them. Both `String` and `str` store their length +//! be a `\0` among them. Both `String` and `str` store their length //! explicitly; there are no nul terminators at the end of strings //! like in C. //! //! C strings are different from Rust strings: //! //! * **Encodings** - Rust strings are UTF-8, but C strings may use -//! other encodings. If you are using a string from C, you should +//! other encodings. If you are using a string from C, you should //! check its encoding explicitly, rather than just assuming that it //! is UTF-8 like you can do in Rust. //! @@ -37,22 +37,22 @@ //! characters; please **note** that C's `char` is different from Rust's. //! The C standard leaves the actual sizes of those types open to //! interpretation, but defines different APIs for strings made up of -//! each character type. Rust strings are always UTF-8, so different +//! each character type. Rust strings are always UTF-8, so different //! Unicode characters will be encoded in a variable number of bytes -//! each. The Rust type [`char`] represents a '[Unicode scalar +//! each. The Rust type [`char`] represents a '[Unicode scalar //! value]', which is similar to, but not the same as, a '[Unicode //! code point]'. //! //! * **Nul terminators and implicit string lengths** - Often, C //! strings are nul-terminated, i.e. they have a `\0` character at the -//! end. The length of a string buffer is not stored, but has to be +//! end. The length of a string buffer is not stored, but has to be //! calculated; to compute the length of a string, C code must //! manually call a function like `strlen()` for `char`-based strings, -//! or `wcslen()` for `wchar_t`-based ones. Those functions return +//! or `wcslen()` for `wchar_t`-based ones. Those functions return //! the number of characters in the string excluding the nul //! terminator, so the buffer length is really `len+1` characters. //! Rust strings don't have a nul terminator; their length is always -//! stored and does not need to be calculated. While in Rust +//! stored and does not need to be calculated. While in Rust //! accessing a string's length is a O(1) operation (becasue the //! length is stored); in C it is an O(length) operation because the //! length needs to be computed by scanning the string for the nul @@ -61,7 +61,7 @@ //! * **Internal nul characters** - When C strings have a nul //! terminator character, this usually means that they cannot have nul //! characters in the middle — a nul character would essentially -//! truncate the string. Rust strings *can* have nul characters in +//! truncate the string. Rust strings *can* have nul characters in //! the middle, because nul does not have to mark the end of the //! string in Rust. //! @@ -80,30 +80,30 @@ //! //! * **From C to Rust:** [`CStr`] represents a borrowed C string; it //! is what you would use to wrap a raw `*const u8` that you got from -//! a C function. A `CStr` is guaranteed to be a nul-terminated array -//! of bytes. Once you have a `CStr`, you can convert it to a Rust +//! a C function. A `CStr` is guaranteed to be a nul-terminated array +//! of bytes. Once you have a `CStr`, you can convert it to a Rust //! `&str` if it's valid UTF-8, or lossily convert it by adding //! replacement characters. //! //! [`OsString`] and [`OsStr`] are useful when you need to transfer //! strings to and from the operating system itself, or when capturing -//! the output of external commands. Conversions between `OsString`, +//! the output of external commands. Conversions between `OsString`, //! `OsStr` and Rust strings work similarly to those for [`CString`] //! and [`CStr`]. //! //! * [`OsString`] represents an owned string in whatever -//! representation the operating system prefers. In the Rust standard +//! representation the operating system prefers. In the Rust standard //! library, various APIs that transfer strings to/from the operating -//! system use `OsString` instead of plain strings. For example, +//! system use `OsString` instead of plain strings. For example, //! [`env::var_os()`] is used to query environment variables; it -//! returns an `Option`. If the environment variable exists +//! returns an `Option`. If the environment variable exists //! you will get a `Some(os_string)`, which you can *then* try to -//! convert to a Rust string. This yields a [`Result<>`], so that +//! convert to a Rust string. This yields a [`Result<>`], so that //! your code can detect errors in case the environment variable did //! not in fact contain valid Unicode data. //! //! * [`OsStr`] represents a borrowed reference to a string in a -//! format that can be passed to the operating system. It can be +//! format that can be passed to the operating system. It can be //! converted into an UTF-8 Rust string slice in a similar way to //! `OsString`. //! @@ -125,12 +125,12 @@ //! //! On Windows, [`OsStr`] implements the //! `std::os::windows::ffi::`[`OsStrExt`][windows.OsStrExt] trait, -//! which provides an [`encode_wide`] method. This provides an +//! which provides an [`encode_wide`] method. This provides an //! iterator that can be [`collect`]ed into a vector of [`u16`]. //! //! Additionally, on Windows [`OsString`] implements the //! `std::os::windows:ffi::`[`OsStringExt`][windows.OsStringExt] -//! trait, which provides a [`from_wide`] method. The result of this +//! trait, which provides a [`from_wide`] method. The result of this //! method is an `OsString` which can be round-tripped to a Windows //! string losslessly. //! -- cgit 1.4.1-3-g733a5 From 03419c846af0dea71e38064223d5e51550350a61 Mon Sep 17 00:00:00 2001 From: Marco A L Barbosa Date: Wed, 11 Oct 2017 21:29:46 -0300 Subject: Bump cc to 1.01 to include x86_64-unknown-linux-gnux32 support --- src/Cargo.lock | 36 ++++++++++++++--------------- src/bootstrap/Cargo.toml | 2 +- src/liballoc_jemalloc/Cargo.toml | 2 +- src/libprofiler_builtins/Cargo.toml | 2 +- src/librustc_llvm/Cargo.toml | 2 +- src/librustc_trans/Cargo.toml | 2 +- src/librustdoc/Cargo.toml | 2 +- src/libstd/Cargo.toml | 2 +- src/rustc/compiler_builtins_shim/Cargo.toml | 2 +- 9 files changed, 26 insertions(+), 26 deletions(-) (limited to 'src/libstd') diff --git a/src/Cargo.lock b/src/Cargo.lock index 77e33855f23..30fc7ee8d8c 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -42,7 +42,7 @@ dependencies = [ "alloc 0.0.0", "alloc_system 0.0.0", "build_helper 0.1.0", - "cc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "core 0.0.0", "libc 0.0.0", ] @@ -99,7 +99,7 @@ name = "backtrace-sys" version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -136,7 +136,7 @@ name = "bootstrap" version = "0.0.0" dependencies = [ "build_helper 0.1.0", - "cc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "cmake 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)", "filetime 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "getopts 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", @@ -246,7 +246,7 @@ version = "0.1.0" [[package]] name = "cc" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -275,7 +275,7 @@ name = "cmake" version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -290,7 +290,7 @@ dependencies = [ name = "compiler_builtins" version = "0.0.0" dependencies = [ - "cc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "core 0.0.0", ] @@ -407,7 +407,7 @@ name = "curl-sys" version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)", "libz-sys 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", "openssl-sys 0.9.19 (registry+https://github.com/rust-lang/crates.io-index)", @@ -833,7 +833,7 @@ name = "libgit2-sys" version = "0.6.15" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "cmake 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)", "curl-sys 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)", @@ -860,7 +860,7 @@ name = "libz-sys" version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "vcpkg 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -880,7 +880,7 @@ name = "lzma-sys" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "filetime 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -968,7 +968,7 @@ name = "miniz-sys" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1104,7 +1104,7 @@ name = "openssl-sys" version = "0.9.19" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "vcpkg 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1208,7 +1208,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "profiler_builtins" version = "0.0.0" dependencies = [ - "cc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "core 0.0.0", ] @@ -1623,7 +1623,7 @@ version = "0.0.0" dependencies = [ "bitflags 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "build_helper 0.1.0", - "cc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_cratesio_shim 0.0.0", ] @@ -1755,7 +1755,7 @@ name = "rustc_trans" version = "0.0.0" dependencies = [ "bitflags 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "flate2 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", "jobserver 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1824,7 +1824,7 @@ name = "rustdoc" version = "0.0.0" dependencies = [ "build_helper 0.1.0", - "cc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "html-diff 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1994,7 +1994,7 @@ dependencies = [ "alloc_jemalloc 0.0.0", "alloc_system 0.0.0", "build_helper 0.1.0", - "cc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "collections 0.0.0", "compiler_builtins 0.0.0", "core 0.0.0", @@ -2485,7 +2485,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5" "checksum bitflags 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f5cde24d1b2e2216a726368b2363a273739c91f4e3eb4e0dd12d672d396ad989" "checksum bufstream 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f2f382711e76b9de6c744cc00d0497baba02fb00a787f088c879f01d09468e32" -"checksum cc 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7db2f146208d7e0fbee761b09cd65a7f51ccc38705d4e7262dad4d73b12a76b1" +"checksum cc 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2c674f0870e3dbd4105184ea035acb1c32c8ae69939c9e228d2b11bbfe29efad" "checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de" "checksum clap 2.26.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3451e409013178663435d6f15fdb212f14ee4424a3d74f979d081d0a66b6f1f2" "checksum cmake 0.1.26 (registry+https://github.com/rust-lang/crates.io-index)" = "357c07e7a1fc95732793c1edb5901e1a1f305cfcf63a90eb12dbd22bdb6b789d" diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index 3f1d03b1872..bbbbf0e1915 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -34,7 +34,7 @@ cmake = "0.1.23" filetime = "0.1" num_cpus = "1.0" getopts = "0.2" -cc = "1.0" +cc = "1.0.1" libc = "0.2" serde = "1.0.8" serde_derive = "1.0.8" diff --git a/src/liballoc_jemalloc/Cargo.toml b/src/liballoc_jemalloc/Cargo.toml index 4042c4d2d4e..6d7d83dd993 100644 --- a/src/liballoc_jemalloc/Cargo.toml +++ b/src/liballoc_jemalloc/Cargo.toml @@ -19,7 +19,7 @@ libc = { path = "../rustc/libc_shim" } [build-dependencies] build_helper = { path = "../build_helper" } -cc = "1.0" +cc = "1.0.1" [features] debug = [] diff --git a/src/libprofiler_builtins/Cargo.toml b/src/libprofiler_builtins/Cargo.toml index eb31f5730d1..04f456917b9 100644 --- a/src/libprofiler_builtins/Cargo.toml +++ b/src/libprofiler_builtins/Cargo.toml @@ -15,4 +15,4 @@ doc = false core = { path = "../libcore" } [build-dependencies] -cc = "1.0" +cc = "1.0.1" diff --git a/src/librustc_llvm/Cargo.toml b/src/librustc_llvm/Cargo.toml index de5add56b76..a9566c4bcac 100644 --- a/src/librustc_llvm/Cargo.toml +++ b/src/librustc_llvm/Cargo.toml @@ -18,4 +18,4 @@ rustc_cratesio_shim = { path = "../librustc_cratesio_shim" } [build-dependencies] build_helper = { path = "../build_helper" } -cc = "1.0" +cc = "1.0.1" diff --git a/src/librustc_trans/Cargo.toml b/src/librustc_trans/Cargo.toml index 482350d04b5..5b7879ea58e 100644 --- a/src/librustc_trans/Cargo.toml +++ b/src/librustc_trans/Cargo.toml @@ -32,4 +32,4 @@ syntax = { path = "../libsyntax" } syntax_pos = { path = "../libsyntax_pos" } [target."cfg(windows)".dependencies] -cc = "1.0" +cc = "1.0.1" diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index b295b414a03..e168222058f 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -18,4 +18,4 @@ html-diff = "0.0.4" [build-dependencies] build_helper = { path = "../build_helper" } -cc = "1.0" +cc = "1.0.1" diff --git a/src/libstd/Cargo.toml b/src/libstd/Cargo.toml index fb276448ffa..c95287390b4 100644 --- a/src/libstd/Cargo.toml +++ b/src/libstd/Cargo.toml @@ -36,7 +36,7 @@ rustc_tsan = { path = "../librustc_tsan" } [build-dependencies] build_helper = { path = "../build_helper" } -cc = "1.0" +cc = "1.0.1" [features] backtrace = [] diff --git a/src/rustc/compiler_builtins_shim/Cargo.toml b/src/rustc/compiler_builtins_shim/Cargo.toml index 886e239246d..608e5f5f36d 100644 --- a/src/rustc/compiler_builtins_shim/Cargo.toml +++ b/src/rustc/compiler_builtins_shim/Cargo.toml @@ -30,7 +30,7 @@ doctest = false core = { path = "../../libcore" } [build-dependencies] -cc = "1.0" +cc = "1.0.1" [features] c = [] -- cgit 1.4.1-3-g733a5 From 8c4a68dca1428fab4bfb9c9f176ad66e2e1d85fc Mon Sep 17 00:00:00 2001 From: Pirh Date: Fri, 13 Oct 2017 18:18:09 +0100 Subject: Add line break after summary of process::Output --- src/libstd/process.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/process.rs b/src/libstd/process.rs index 847dbd14dd6..8287c43ba96 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -701,9 +701,11 @@ impl AsInnerMut for Command { fn as_inner_mut(&mut self) -> &mut imp::Command { &mut self.inner } } -/// The output of a finished process. This is returned in a Result by -/// either the [`output`] method of a [`Command`], or the -/// [`wait_with_output`] method of a [`Child`] process. +/// The output of a finished process. +/// +/// This is returned in a Result by either the [`output`] method of a +/// [`Command`], or the [`wait_with_output`] method of a [`Child`] +/// process. /// /// [`Command`]: struct.Command.html /// [`Child`]: struct.Child.html -- cgit 1.4.1-3-g733a5 From bb9e850246092d3931080ddbac551a0857b28364 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Fri, 13 Oct 2017 13:09:35 -0400 Subject: std: Get rid of hash_offet in RawTable This offset is always zero, and we don't consistently take it into account. This is okay, because it's zero, but if it ever changes we're going to have bugs (e.g. in the `dealloc` call, where we don't take it into account). It's better to remove this for now; if we ever have a need for a nonzero offset we can add it back, and handle it properly when we do so. --- src/libstd/collections/hash/table.rs | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs index 93929637e2f..527c4ef4592 100644 --- a/src/libstd/collections/hash/table.rs +++ b/src/libstd/collections/hash/table.rs @@ -717,26 +717,25 @@ fn calculate_offsets(hashes_size: usize, (pairs_offset, end_of_pairs, oflo) } -// Returns a tuple of (minimum required malloc alignment, hash_offset, +// Returns a tuple of (minimum required malloc alignment, // array_size), from the start of a mallocated array. fn calculate_allocation(hash_size: usize, hash_align: usize, pairs_size: usize, pairs_align: usize) - -> (usize, usize, usize, bool) { - let hash_offset = 0; + -> (usize, usize, bool) { let (_, end_of_pairs, oflo) = calculate_offsets(hash_size, pairs_size, pairs_align); let align = cmp::max(hash_align, pairs_align); - (align, hash_offset, end_of_pairs, oflo) + (align, end_of_pairs, oflo) } #[test] fn test_offset_calculation() { - assert_eq!(calculate_allocation(128, 8, 16, 8), (8, 0, 144, false)); - assert_eq!(calculate_allocation(3, 1, 2, 1), (1, 0, 5, false)); - assert_eq!(calculate_allocation(6, 2, 12, 4), (4, 0, 20, false)); + assert_eq!(calculate_allocation(128, 8, 16, 8), (8, 144, false)); + assert_eq!(calculate_allocation(3, 1, 2, 1), (1, 5, false)); + assert_eq!(calculate_allocation(6, 2, 12, 4), (4, 20, false)); assert_eq!(calculate_offsets(128, 15, 4), (128, 143, false)); assert_eq!(calculate_offsets(3, 2, 4), (4, 6, false)); assert_eq!(calculate_offsets(6, 12, 4), (8, 20, false)); @@ -768,10 +767,10 @@ impl RawTable { // This is great in theory, but in practice getting the alignment // right is a little subtle. Therefore, calculating offsets has been // factored out into a different function. - let (alignment, hash_offset, size, oflo) = calculate_allocation(hashes_size, - align_of::(), - pairs_size, - align_of::<(K, V)>()); + let (alignment, size, oflo) = calculate_allocation(hashes_size, + align_of::(), + pairs_size, + align_of::<(K, V)>()); assert!(!oflo, "capacity overflow"); // One check for overflow that covers calculation and rounding of size. @@ -784,7 +783,7 @@ impl RawTable { let buffer = Heap.alloc(Layout::from_size_align(size, alignment).unwrap()) .unwrap_or_else(|e| Heap.oom(e)); - let hashes = buffer.offset(hash_offset as isize) as *mut HashUint; + let hashes = buffer as *mut HashUint; RawTable { capacity_mask: capacity.wrapping_sub(1), @@ -1183,10 +1182,10 @@ unsafe impl<#[may_dangle] K, #[may_dangle] V> Drop for RawTable { let hashes_size = self.capacity() * size_of::(); let pairs_size = self.capacity() * size_of::<(K, V)>(); - let (align, _, size, oflo) = calculate_allocation(hashes_size, - align_of::(), - pairs_size, - align_of::<(K, V)>()); + let (align, size, oflo) = calculate_allocation(hashes_size, + align_of::(), + pairs_size, + align_of::<(K, V)>()); debug_assert!(!oflo, "should be impossible"); -- cgit 1.4.1-3-g733a5 From e8e7715bebdd401ebacfabb66928d0f7e4733120 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Fri, 13 Oct 2017 13:19:15 -0400 Subject: std: Set probe length tag on cloned hashmaps This isn't strictly necessary for hashmap cloning to work. The tag is used to hint for an upcoming resize, so it's good to copy this information over. (We can do cleverer things like actually resizing the hashmap when we see the tag, or even cleaning up the entry order, but this requires more thought and might not be worth it) --- src/libstd/collections/hash/table.rs | 1 + 1 file changed, 1 insertion(+) (limited to 'src/libstd') diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs index 527c4ef4592..7e623a0af17 100644 --- a/src/libstd/collections/hash/table.rs +++ b/src/libstd/collections/hash/table.rs @@ -1156,6 +1156,7 @@ impl Clone for RawTable { } new_ht.size = self.size(); + new_ht.set_tag(self.tag()); new_ht } -- cgit 1.4.1-3-g733a5 From cab99a3f8c8dcdfd9052fd54787d22611ab36edc Mon Sep 17 00:00:00 2001 From: Steven Fackler Date: Fri, 13 Oct 2017 19:22:33 -0700 Subject: Fix TcpStream::connect_timeout on linux Linux appears to set POLLOUT when a conection's refused, which is pretty weird. Invert the check to look for an error explicitly. Also add an explict test for this case. Closes #45265. --- src/libstd/net/tcp.rs | 15 +++++++++++++++ src/libstd/sys/unix/net.rs | 13 +++++++++---- 2 files changed, 24 insertions(+), 4 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/net/tcp.rs b/src/libstd/net/tcp.rs index b904641a336..4656cc5a7a7 100644 --- a/src/libstd/net/tcp.rs +++ b/src/libstd/net/tcp.rs @@ -1579,6 +1579,21 @@ mod tests { "bad error: {} {:?}", e, e.kind()); } + #[test] + fn connect_timeout_unbound() { + // bind and drop a socket to track down a "probably unassigned" port + let socket = TcpListener::bind("127.0.0.1:0").unwrap(); + let addr = socket.local_addr().unwrap(); + drop(socket); + + let timeout = Duration::from_secs(1); + let e = TcpStream::connect_timeout(&addr, timeout).unwrap_err(); + assert!(e.kind() == io::ErrorKind::ConnectionRefused || + e.kind() == io::ErrorKind::TimedOut || + e.kind() == io::ErrorKind::Other, + "bad error: {} {:?}", e, e.kind()); + } + #[test] fn connect_timeout_valid() { let listener = TcpListener::bind("127.0.0.1:0").unwrap(); diff --git a/src/libstd/sys/unix/net.rs b/src/libstd/sys/unix/net.rs index c8019d1c768..e775f857f2b 100644 --- a/src/libstd/sys/unix/net.rs +++ b/src/libstd/sys/unix/net.rs @@ -176,11 +176,16 @@ impl Socket { } 0 => {} _ => { - if pollfd.revents & libc::POLLOUT == 0 { - if let Some(e) = self.take_error()? { - return Err(e); - } + // linux returns POLLOUT|POLLERR|POLLHUP for refused connections (!), so look + // for POLLHUP rather than read readiness + if pollfd.revents & libc::POLLHUP != 0 { + let e = self.take_error()? + .unwrap_or_else(|| { + io::Error::new(io::ErrorKind::Other, "no error set after POLLHUP") + }); + return Err(e); } + return Ok(()); } } -- cgit 1.4.1-3-g733a5 From 9e0fc5ccd050201e77483b1efb2e6c76f47496f6 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Tue, 10 Oct 2017 23:06:22 +0300 Subject: rustbuild: Support specifying archiver and linker explicitly --- config.toml.example | 11 ++++- src/Cargo.lock | 1 - src/bootstrap/bin/rustc.rs | 13 +++--- src/bootstrap/bin/rustdoc.rs | 3 ++ src/bootstrap/builder.rs | 50 +++++++++++++++------ src/bootstrap/cc_detect.rs | 52 +++++++++++++++++++--- src/bootstrap/check.rs | 8 +++- src/bootstrap/config.rs | 8 +++- src/bootstrap/lib.rs | 23 +++++++--- src/bootstrap/native.rs | 7 +++ src/bootstrap/tool.rs | 2 +- src/build_helper/lib.rs | 21 --------- src/liballoc_jemalloc/build.rs | 15 +------ src/librustdoc/lib.rs | 8 +++- src/librustdoc/markdown.rs | 4 +- src/librustdoc/test.rs | 18 +++++--- src/libstd/Cargo.toml | 1 - src/libstd/build.rs | 12 +---- src/test/run-make/archive-duplicate-names/Makefile | 2 +- .../run-make/compiler-rt-works-on-mingw/Makefile | 4 +- src/test/run-make/invalid-library/Makefile | 2 +- src/test/run-make/issue-19371/foo.rs | 7 +-- src/test/run-make/issue-22131/Makefile | 2 +- src/test/run-make/rustdoc-output-path/Makefile | 2 +- src/test/run-make/staticlib-blank-lib/Makefile | 4 +- src/test/run-make/tools.mk | 10 ++++- src/tools/compiletest/src/common.rs | 2 + src/tools/compiletest/src/main.rs | 6 +++ src/tools/compiletest/src/runtest.rs | 10 ++++- 29 files changed, 200 insertions(+), 108 deletions(-) (limited to 'src/libstd') diff --git a/config.toml.example b/config.toml.example index a2f64e6b705..f50543e18a7 100644 --- a/config.toml.example +++ b/config.toml.example @@ -300,7 +300,7 @@ # ============================================================================= [target.x86_64-unknown-linux-gnu] -# C compiler to be used to compiler C code and link Rust code. Note that the +# C compiler to be used to compiler C code. Note that the # default value is platform specific, and if not specified it may also depend on # what platform is crossing to what platform. #cc = "cc" @@ -309,6 +309,15 @@ # This is only used for host targets. #cxx = "c++" +# Archiver to be used to assemble static libraries compiled from C/C++ code. +# Note: an absolute path should be used, otherwise LLVM build will break. +#ar = "ar" + +# Linker to be used to link Rust code. Note that the +# default value is platform specific, and if not specified it may also depend on +# what platform is crossing to what platform. +#linker = "cc" + # Path to the `llvm-config` binary of the installation of a custom LLVM to link # against. Note that if this is specifed we don't compile LLVM at all for this # target. diff --git a/src/Cargo.lock b/src/Cargo.lock index aa5e262e85f..2b95be27ffe 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -1994,7 +1994,6 @@ dependencies = [ "alloc_jemalloc 0.0.0", "alloc_system 0.0.0", "build_helper 0.1.0", - "cc 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "collections 0.0.0", "compiler_builtins 0.0.0", "core 0.0.0", diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs index e91acb21dac..e496ce27f50 100644 --- a/src/bootstrap/bin/rustc.rs +++ b/src/bootstrap/bin/rustc.rs @@ -120,12 +120,6 @@ fn main() { cmd.arg("-L").arg(&root); } - // Pass down extra flags, commonly used to configure `-Clinker` when - // cross compiling. - if let Ok(s) = env::var("RUSTC_FLAGS") { - cmd.args(&s.split(" ").filter(|s| !s.is_empty()).collect::>()); - } - // Pass down incremental directory, if any. if let Ok(dir) = env::var("RUSTC_INCREMENTAL") { cmd.arg(format!("-Zincremental={}", dir)); @@ -254,6 +248,13 @@ fn main() { } } + // Pass down extra flags, commonly used to configure `-Clinker`. + // Linker options should be set for build scripts as well, + // can't link a build script executable without a linker! + if let Ok(s) = env::var("RUSTC_FLAGS") { + cmd.args(&s.split(" ").filter(|s| !s.is_empty()).collect::>()); + } + let color = match env::var("RUSTC_COLOR") { Ok(s) => usize::from_str(&s).expect("RUSTC_COLOR should be an integer"), Err(_) => 0, diff --git a/src/bootstrap/bin/rustdoc.rs b/src/bootstrap/bin/rustdoc.rs index d18512b257d..2105797a830 100644 --- a/src/bootstrap/bin/rustdoc.rs +++ b/src/bootstrap/bin/rustdoc.rs @@ -47,6 +47,9 @@ fn main() { if env::var_os("RUSTC_FORCE_UNSTABLE").is_some() { cmd.arg("-Z").arg("force-unstable-if-unmarked"); } + if let Some(linker) = env::var_os("RUSTDOC_LINKER") { + cmd.arg("--linker").arg(linker).arg("-Z").arg("unstable-options"); + } // Bootstrap's Cargo-command builder sets this variable to the current Rust version; let's pick // it up so we can make rustdoc print this into the docs diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 1d63e112ca6..ef4f8f78b0d 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -413,13 +413,15 @@ impl<'a> Builder<'a> { pub fn rustdoc_cmd(&self, host: Interned) -> Command { let mut cmd = Command::new(&self.out.join("bootstrap/debug/rustdoc")); let compiler = self.compiler(self.top_stage, host); - cmd - .env("RUSTC_STAGE", compiler.stage.to_string()) - .env("RUSTC_SYSROOT", self.sysroot(compiler)) - .env("RUSTC_LIBDIR", self.sysroot_libdir(compiler, self.build.build)) - .env("CFG_RELEASE_CHANNEL", &self.build.config.channel) - .env("RUSTDOC_REAL", self.rustdoc(host)) - .env("RUSTDOC_CRATE_VERSION", self.build.rust_version()); + cmd.env("RUSTC_STAGE", compiler.stage.to_string()) + .env("RUSTC_SYSROOT", self.sysroot(compiler)) + .env("RUSTC_LIBDIR", self.sysroot_libdir(compiler, self.build.build)) + .env("CFG_RELEASE_CHANNEL", &self.build.config.channel) + .env("RUSTDOC_REAL", self.rustdoc(host)) + .env("RUSTDOC_CRATE_VERSION", self.build.rust_version()); + if let Some(linker) = self.build.linker(host) { + cmd.env("RUSTDOC_LINKER", linker); + } cmd } @@ -485,6 +487,10 @@ impl<'a> Builder<'a> { .env("TEST_MIRI", self.config.test_miri.to_string()) .env("RUSTC_FLAGS", self.rustc_flags(target).join(" ")); + if let Some(linker) = self.build.linker(target) { + cargo.env("RUSTDOC_LINKER", linker); + } + if mode != Mode::Tool { // Tools don't get debuginfo right now, e.g. cargo and rls don't // get compiled with debuginfo. @@ -557,17 +563,35 @@ impl<'a> Builder<'a> { cargo.env("RUSTC_VERBOSE", format!("{}", self.verbosity)); - // Specify some various options for build scripts used throughout - // the build. + // Throughout the build Cargo can execute a number of build scripts + // compiling C/C++ code and we need to pass compilers, archivers, flags, etc + // obtained previously to those build scripts. + // Build scripts use either the `cc` crate or `configure/make` so we pass + // the options through environment variables that are fetched and understood by both. // // FIXME: the guard against msvc shouldn't need to be here if !target.contains("msvc") { - cargo.env(format!("CC_{}", target), self.cc(target)) - .env(format!("AR_{}", target), self.ar(target).unwrap()) // only msvc is None - .env(format!("CFLAGS_{}", target), self.cflags(target).join(" ")); + let cc = self.cc(target); + cargo.env(format!("CC_{}", target), cc) + .env("CC", cc); + + let cflags = self.cflags(target).join(" "); + cargo.env(format!("CFLAGS_{}", target), cflags.clone()) + .env("CFLAGS", cflags.clone()); + + if let Some(ar) = self.ar(target) { + let ranlib = format!("{} s", ar.display()); + cargo.env(format!("AR_{}", target), ar) + .env("AR", ar) + .env(format!("RANLIB_{}", target), ranlib.clone()) + .env("RANLIB", ranlib); + } if let Ok(cxx) = self.cxx(target) { - cargo.env(format!("CXX_{}", target), cxx); + cargo.env(format!("CXX_{}", target), cxx) + .env("CXX", cxx) + .env(format!("CXXFLAGS_{}", target), cflags.clone()) + .env("CXXFLAGS", cflags); } } diff --git a/src/bootstrap/cc_detect.rs b/src/bootstrap/cc_detect.rs index 08df65c7611..6e3e3c92029 100644 --- a/src/bootstrap/cc_detect.rs +++ b/src/bootstrap/cc_detect.rs @@ -31,20 +31,51 @@ //! ever be probed for. Instead the compilers found here will be used for //! everything. +use std::collections::HashSet; +use std::{env, iter}; +use std::path::{Path, PathBuf}; use std::process::Command; -use std::iter; -use build_helper::{cc2ar, output}; +use build_helper::output; use cc; use Build; use config::Target; use cache::Interned; +// The `cc` crate doesn't provide a way to obtain a path to the detected archiver, +// so use some simplified logic here. First we respect the environment variable `AR`, then +// try to infer the archiver path from the C compiler path. +// In the future this logic should be replaced by calling into the `cc` crate. +fn cc2ar(cc: &Path, target: &str) -> Option { + if let Some(ar) = env::var_os("AR") { + Some(PathBuf::from(ar)) + } else if target.contains("msvc") { + None + } else if target.contains("musl") { + Some(PathBuf::from("ar")) + } else if target.contains("openbsd") { + Some(PathBuf::from("ar")) + } else { + let parent = cc.parent().unwrap(); + let file = cc.file_name().unwrap().to_str().unwrap(); + for suffix in &["gcc", "cc", "clang"] { + if let Some(idx) = file.rfind(suffix) { + let mut file = file[..idx].to_owned(); + file.push_str("ar"); + return Some(parent.join(&file)); + } + } + Some(parent.join(file)) + } +} + pub fn find(build: &mut Build) { // For all targets we're going to need a C compiler for building some shims // and such as well as for being a linker for Rust code. - for target in build.targets.iter().chain(&build.hosts).cloned().chain(iter::once(build.build)) { + let targets = build.targets.iter().chain(&build.hosts).cloned().chain(iter::once(build.build)) + .collect::>(); + for target in targets.into_iter() { let mut cfg = cc::Build::new(); cfg.cargo_metadata(false).opt_level(0).warnings(false).debug(false) .target(&target).host(&build.build); @@ -57,16 +88,23 @@ pub fn find(build: &mut Build) { } let compiler = cfg.get_compiler(); - let ar = cc2ar(compiler.path(), &target); + let ar = if let ar @ Some(..) = config.and_then(|c| c.ar.clone()) { + ar + } else { + cc2ar(compiler.path(), &target) + }; + build.verbose(&format!("CC_{} = {:?}", &target, compiler.path())); - if let Some(ref ar) = ar { + build.cc.insert(target, compiler); + if let Some(ar) = ar { build.verbose(&format!("AR_{} = {:?}", &target, ar)); + build.ar.insert(target, ar); } - build.cc.insert(target, (compiler, ar)); } // For all host triples we need to find a C++ compiler as well - for host in build.hosts.iter().cloned().chain(iter::once(build.build)) { + let hosts = build.hosts.iter().cloned().chain(iter::once(build.build)).collect::>(); + for host in hosts.into_iter() { let mut cfg = cc::Build::new(); cfg.cargo_metadata(false).opt_level(0).warnings(false).debug(false).cpp(true) .target(&host).host(&build.build); diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index fb32ab0cb86..d9b0ff4c7a4 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -725,6 +725,9 @@ impl Step for Compiletest { // Avoid depending on rustdoc when we don't need it. if mode == "rustdoc" || mode == "run-make" { cmd.arg("--rustdoc-path").arg(builder.rustdoc(compiler.host)); + if let Some(linker) = build.linker(target) { + cmd.arg("--linker").arg(linker); + } } cmd.arg("--src-base").arg(build.src.join("src/test").join(suite)); @@ -806,6 +809,9 @@ impl Step for Compiletest { .arg("--cflags").arg(build.cflags(target).join(" ")) .arg("--llvm-components").arg(llvm_components.trim()) .arg("--llvm-cxxflags").arg(llvm_cxxflags.trim()); + if let Some(ar) = build.ar(target) { + cmd.arg("--ar").arg(ar); + } } } if suite == "run-make" && !build.config.llvm_enabled { @@ -831,7 +837,7 @@ impl Step for Compiletest { // Note that if we encounter `PATH` we make sure to append to our own `PATH` // rather than stomp over it. if target.contains("msvc") { - for &(ref k, ref v) in build.cc[&target].0.env() { + for &(ref k, ref v) in build.cc[&target].env() { if k != "PATH" { cmd.env(k, v); } diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 5fb5eb3b7f1..69e0f58f1cd 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -143,6 +143,8 @@ pub struct Target { pub jemalloc: Option, pub cc: Option, pub cxx: Option, + pub ar: Option, + pub linker: Option, pub ndk: Option, pub crt_static: Option, pub musl_root: Option, @@ -282,6 +284,8 @@ struct TomlTarget { jemalloc: Option, cc: Option, cxx: Option, + ar: Option, + linker: Option, android_ndk: Option, crt_static: Option, musl_root: Option, @@ -484,8 +488,10 @@ impl Config { if let Some(ref s) = cfg.android_ndk { target.ndk = Some(env::current_dir().unwrap().join(s)); } - target.cxx = cfg.cxx.clone().map(PathBuf::from); target.cc = cfg.cc.clone().map(PathBuf::from); + target.cxx = cfg.cxx.clone().map(PathBuf::from); + target.ar = cfg.ar.clone().map(PathBuf::from); + target.linker = cfg.linker.clone().map(PathBuf::from); target.crt_static = cfg.crt_static.clone(); target.musl_root = cfg.musl_root.clone().map(PathBuf::from); target.qemu_rootfs = cfg.qemu_rootfs.clone().map(PathBuf::from); diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 2d721f45578..7c599f91838 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -240,10 +240,11 @@ pub struct Build { lldb_python_dir: Option, // Runtime state filled in later on - // target -> (cc, ar) - cc: HashMap, (cc::Tool, Option)>, - // host -> (cc, ar) + // C/C++ compilers and archiver for all targets + cc: HashMap, cc::Tool>, cxx: HashMap, cc::Tool>, + ar: HashMap, PathBuf>, + // Misc crates: HashMap, Crate>, is_sudo: bool, ci_env: CiEnv, @@ -324,6 +325,7 @@ impl Build { rls_info, cc: HashMap::new(), cxx: HashMap::new(), + ar: HashMap::new(), crates: HashMap::new(), lldb_version: None, lldb_python_dir: None, @@ -612,7 +614,7 @@ impl Build { /// Returns the path to the C compiler for the target specified. fn cc(&self, target: Interned) -> &Path { - self.cc[&target].0.path() + self.cc[&target].path() } /// Returns a list of flags to pass to the C compiler for the target @@ -620,7 +622,7 @@ impl Build { fn cflags(&self, target: Interned) -> Vec { // Filter out -O and /O (the optimization flags) that we picked up from // cc-rs because the build scripts will determine that for themselves. - let mut base = self.cc[&target].0.args().iter() + let mut base = self.cc[&target].args().iter() .map(|s| s.to_string_lossy().into_owned()) .filter(|s| !s.starts_with("-O") && !s.starts_with("/O")) .collect::>(); @@ -644,7 +646,11 @@ impl Build { /// Returns the path to the `ar` archive utility for the target specified. fn ar(&self, target: Interned) -> Option<&Path> { - self.cc[&target].1.as_ref().map(|p| &**p) + self.ar.get(&target).map(|p| &**p) + } + + fn linker(&self, target: Interned) -> Option<&Path> { + self.config.target_config.get(&target).and_then(|c| c.linker.as_ref().map(|p| &**p)) } /// Returns the path to the C++ compiler for the target specified. @@ -667,7 +673,10 @@ impl Build { // than an entry here. let mut base = Vec::new(); - if target != self.config.build && !target.contains("msvc") && + if let Some(linker) = self.linker(target) { + // If linker was explictly provided, force it on all the compiled Rust code. + base.push(format!("-Clinker={}", linker.display())); + } else if target != self.config.build && !target.contains("msvc") && !target.contains("emscripten") { base.push(format!("-Clinker={}", self.cc(target).display())); } diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index 2c8e5004041..941ea96bbec 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -227,6 +227,13 @@ impl Step for Llvm { cfg.build_arg("-j").build_arg(build.jobs().to_string()); cfg.define("CMAKE_C_FLAGS", build.cflags(target).join(" ")); cfg.define("CMAKE_CXX_FLAGS", build.cflags(target).join(" ")); + if let Some(ar) = build.ar(target) { + if ar.is_absolute() { + // LLVM build breaks if `CMAKE_AR` is a relative path, for some reason it + // tries to resolve this path in the LLVM build directory. + cfg.define("CMAKE_AR", sanitize_cc(ar)); + } + } }; configure_compilers(&mut cfg); diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index e95a5e07436..662c56d728d 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -561,7 +561,7 @@ impl<'a> Builder<'a> { if compiler.host.contains("msvc") { let curpaths = env::var_os("PATH").unwrap_or_default(); let curpaths = env::split_paths(&curpaths).collect::>(); - for &(ref k, ref v) in self.cc[&compiler.host].0.env() { + for &(ref k, ref v) in self.cc[&compiler.host].env() { if k != "PATH" { continue } diff --git a/src/build_helper/lib.rs b/src/build_helper/lib.rs index e81dab70b43..97723e260f6 100644 --- a/src/build_helper/lib.rs +++ b/src/build_helper/lib.rs @@ -138,27 +138,6 @@ pub fn gnu_target(target: &str) -> String { } } -pub fn cc2ar(cc: &Path, target: &str) -> Option { - if target.contains("msvc") { - None - } else if target.contains("musl") { - Some(PathBuf::from("ar")) - } else if target.contains("openbsd") { - Some(PathBuf::from("ar")) - } else { - let parent = cc.parent().unwrap(); - let file = cc.file_name().unwrap().to_str().unwrap(); - for suffix in &["gcc", "cc", "clang"] { - if let Some(idx) = file.rfind(suffix) { - let mut file = file[..idx].to_owned(); - file.push_str("ar"); - return Some(parent.join(&file)); - } - } - Some(parent.join(file)) - } -} - pub fn make(host: &str) -> PathBuf { if host.contains("bitrig") || host.contains("dragonfly") || host.contains("freebsd") || host.contains("netbsd") || diff --git a/src/liballoc_jemalloc/build.rs b/src/liballoc_jemalloc/build.rs index 7dd85ddcc79..65e035d4ffd 100644 --- a/src/liballoc_jemalloc/build.rs +++ b/src/liballoc_jemalloc/build.rs @@ -63,15 +63,6 @@ fn main() { _ => return, }; - let compiler = cc::Build::new().get_compiler(); - // only msvc returns None for ar so unwrap is okay - let ar = build_helper::cc2ar(compiler.path(), &target).unwrap(); - let cflags = compiler.args() - .iter() - .map(|s| s.to_str().unwrap()) - .collect::>() - .join(" "); - let mut cmd = Command::new("sh"); cmd.arg(native.src_dir.join("configure") .to_str() @@ -79,8 +70,6 @@ fn main() { .replace("C:\\", "/c/") .replace("\\", "/")) .current_dir(&native.out_dir) - .env("CC", compiler.path()) - .env("EXTRA_CFLAGS", cflags.clone()) // jemalloc generates Makefile deps using GCC's "-MM" flag. This means // that GCC will run the preprocessor, and only the preprocessor, over // jemalloc's source files. If we don't specify CPPFLAGS, then at least @@ -89,9 +78,7 @@ fn main() { // passed to GCC, and then GCC won't define the // "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4" macro that jemalloc needs to // select an atomic operation implementation. - .env("CPPFLAGS", cflags.clone()) - .env("AR", &ar) - .env("RANLIB", format!("{} s", ar.display())); + .env("CPPFLAGS", env::var_os("CFLAGS").unwrap_or_default()); if target.contains("ios") { cmd.arg("--disable-tls"); diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index f8bf00ad73f..890e1169c05 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -246,6 +246,9 @@ pub fn opts() -> Vec { unstable("crate-version", |o| { o.optopt("", "crate-version", "crate version to print into documentation", "VERSION") }), + unstable("linker", |o| { + o.optopt("", "linker", "linker used for building executable test code", "PATH") + }), ] } @@ -357,15 +360,16 @@ pub fn main_args(args: &[String]) -> isize { let playground_url = matches.opt_str("playground-url"); let maybe_sysroot = matches.opt_str("sysroot").map(PathBuf::from); let display_warnings = matches.opt_present("display-warnings"); + let linker = matches.opt_str("linker"); match (should_test, markdown_input) { (true, true) => { return markdown::test(input, cfgs, libs, externs, test_args, maybe_sysroot, render_type, - display_warnings) + display_warnings, linker) } (true, false) => { return test::run(input, cfgs, libs, externs, test_args, crate_name, maybe_sysroot, - render_type, display_warnings) + render_type, display_warnings, linker) } (false, true) => return markdown::render(input, output.unwrap_or(PathBuf::from("doc")), diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs index 484285e91f6..fe6bd985bb6 100644 --- a/src/librustdoc/markdown.rs +++ b/src/librustdoc/markdown.rs @@ -142,7 +142,7 @@ pub fn render(input: &str, mut output: PathBuf, matches: &getopts::Matches, /// Run any tests/code examples in the markdown file `input`. pub fn test(input: &str, cfgs: Vec, libs: SearchPaths, externs: Externs, mut test_args: Vec, maybe_sysroot: Option, - render_type: RenderType, display_warnings: bool) -> isize { + render_type: RenderType, display_warnings: bool, linker: Option) -> isize { let input_str = match load_string(input) { Ok(s) => s, Err(LoadStringError::ReadFail) => return 1, @@ -154,7 +154,7 @@ pub fn test(input: &str, cfgs: Vec, libs: SearchPaths, externs: Externs, let mut collector = Collector::new(input.to_string(), cfgs, libs, externs, true, opts, maybe_sysroot, None, Some(input.to_owned()), - render_type); + render_type, linker); if render_type == RenderType::Pulldown { old_find_testable_code(&input_str, &mut collector, DUMMY_SP); find_testable_code(&input_str, &mut collector, DUMMY_SP); diff --git a/src/librustdoc/test.rs b/src/librustdoc/test.rs index 4b2980bc3a6..8b2c8d2da39 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/test.rs @@ -61,7 +61,8 @@ pub fn run(input: &str, crate_name: Option, maybe_sysroot: Option, render_type: RenderType, - display_warnings: bool) + display_warnings: bool, + linker: Option) -> isize { let input_path = PathBuf::from(input); let input = config::Input::File(input_path.clone()); @@ -121,7 +122,8 @@ pub fn run(input: &str, maybe_sysroot, Some(codemap), None, - render_type); + render_type, + linker); { let map = hir::map::map_crate(&sess, &*cstore, &mut hir_forest, &defs); @@ -180,7 +182,8 @@ fn run_test(test: &str, cratename: &str, filename: &str, cfgs: Vec, libs externs: Externs, should_panic: bool, no_run: bool, as_test_harness: bool, compile_fail: bool, mut error_codes: Vec, opts: &TestOptions, - maybe_sysroot: Option) { + maybe_sysroot: Option, + linker: Option) { // the test harness wants its own `main` & top level functions, so // never wrap the test in `fn main() { ... }` let test = make_test(test, Some(cratename), as_test_harness, opts); @@ -201,6 +204,7 @@ fn run_test(test: &str, cratename: &str, filename: &str, cfgs: Vec, libs externs, cg: config::CodegenOptions { prefer_dynamic: true, + linker, .. config::basic_codegen_options() }, test: as_test_harness, @@ -442,13 +446,14 @@ pub struct Collector { filename: Option, // to be removed when hoedown will be removed as well pub render_type: RenderType, + linker: Option, } impl Collector { pub fn new(cratename: String, cfgs: Vec, libs: SearchPaths, externs: Externs, use_headers: bool, opts: TestOptions, maybe_sysroot: Option, codemap: Option>, filename: Option, - render_type: RenderType) -> Collector { + render_type: RenderType, linker: Option) -> Collector { Collector { tests: Vec::new(), old_tests: HashMap::new(), @@ -464,6 +469,7 @@ impl Collector { codemap, filename, render_type, + linker, } } @@ -510,6 +516,7 @@ impl Collector { let cratename = self.cratename.to_string(); let opts = self.opts.clone(); let maybe_sysroot = self.maybe_sysroot.clone(); + let linker = self.linker.clone(); debug!("Creating test {}: {}", name, test); self.tests.push(testing::TestDescAndFn { desc: testing::TestDesc { @@ -538,7 +545,8 @@ impl Collector { compile_fail, error_codes, &opts, - maybe_sysroot) + maybe_sysroot, + linker) }) } { Ok(()) => (), diff --git a/src/libstd/Cargo.toml b/src/libstd/Cargo.toml index c95287390b4..866c0038a7f 100644 --- a/src/libstd/Cargo.toml +++ b/src/libstd/Cargo.toml @@ -36,7 +36,6 @@ rustc_tsan = { path = "../librustc_tsan" } [build-dependencies] build_helper = { path = "../build_helper" } -cc = "1.0.1" [features] backtrace = [] diff --git a/src/libstd/build.rs b/src/libstd/build.rs index 7ca762c801a..0e6214ea04f 100644 --- a/src/libstd/build.rs +++ b/src/libstd/build.rs @@ -11,7 +11,6 @@ #![deny(warnings)] extern crate build_helper; -extern crate cc; use std::env; use std::process::Command; @@ -77,12 +76,6 @@ fn main() { fn build_libbacktrace(host: &str, target: &str) -> Result<(), ()> { let native = native_lib_boilerplate("libbacktrace", "libbacktrace", "backtrace", ".libs")?; - let compiler = cc::Build::new().get_compiler(); - // only msvc returns None for ar so unwrap is okay - let ar = build_helper::cc2ar(compiler.path(), target).unwrap(); - let mut cflags = compiler.args().iter().map(|s| s.to_str().unwrap()) - .collect::>().join(" "); - cflags.push_str(" -fvisibility=hidden"); run(Command::new("sh") .current_dir(&native.out_dir) .arg(native.src_dir.join("configure").to_str().unwrap() @@ -94,10 +87,7 @@ fn build_libbacktrace(host: &str, target: &str) -> Result<(), ()> { .arg("--disable-host-shared") .arg(format!("--host={}", build_helper::gnu_target(target))) .arg(format!("--build={}", build_helper::gnu_target(host))) - .env("CC", compiler.path()) - .env("AR", &ar) - .env("RANLIB", format!("{} s", ar.display())) - .env("CFLAGS", cflags), + .env("CFLAGS", env::var("CFLAGS").unwrap_or_default() + " -fvisibility=hidden"), BuildExpectation::None); run(Command::new(build_helper::make(host)) diff --git a/src/test/run-make/archive-duplicate-names/Makefile b/src/test/run-make/archive-duplicate-names/Makefile index 5202e6dea54..93711c41d79 100644 --- a/src/test/run-make/archive-duplicate-names/Makefile +++ b/src/test/run-make/archive-duplicate-names/Makefile @@ -5,7 +5,7 @@ all: mkdir $(TMPDIR)/b $(call COMPILE_OBJ,$(TMPDIR)/a/foo.o,foo.c) $(call COMPILE_OBJ,$(TMPDIR)/b/foo.o,bar.c) - ar crus $(TMPDIR)/libfoo.a $(TMPDIR)/a/foo.o $(TMPDIR)/b/foo.o + $(AR) crus $(TMPDIR)/libfoo.a $(TMPDIR)/a/foo.o $(TMPDIR)/b/foo.o $(RUSTC) foo.rs $(RUSTC) bar.rs $(call RUN,bar) diff --git a/src/test/run-make/compiler-rt-works-on-mingw/Makefile b/src/test/run-make/compiler-rt-works-on-mingw/Makefile index 4ec54f73e67..06d1bb6698e 100644 --- a/src/test/run-make/compiler-rt-works-on-mingw/Makefile +++ b/src/test/run-make/compiler-rt-works-on-mingw/Makefile @@ -3,8 +3,8 @@ ifneq (,$(findstring MINGW,$(UNAME))) ifndef IS_MSVC all: - g++ foo.cpp -c -o $(TMPDIR)/foo.o - ar crus $(TMPDIR)/libfoo.a $(TMPDIR)/foo.o + $(CXX) foo.cpp -c -o $(TMPDIR)/foo.o + $(AR) crus $(TMPDIR)/libfoo.a $(TMPDIR)/foo.o $(RUSTC) foo.rs -lfoo -lstdc++ $(call RUN,foo) else diff --git a/src/test/run-make/invalid-library/Makefile b/src/test/run-make/invalid-library/Makefile index 0dbe655b77d..5c9cc993509 100644 --- a/src/test/run-make/invalid-library/Makefile +++ b/src/test/run-make/invalid-library/Makefile @@ -2,5 +2,5 @@ all: touch $(TMPDIR)/rust.metadata.bin - ar crus $(TMPDIR)/libfoo-ffffffff-1.0.rlib $(TMPDIR)/rust.metadata.bin + $(AR) crus $(TMPDIR)/libfoo-ffffffff-1.0.rlib $(TMPDIR)/rust.metadata.bin $(RUSTC) foo.rs 2>&1 | grep "can't find crate for" diff --git a/src/test/run-make/issue-19371/foo.rs b/src/test/run-make/issue-19371/foo.rs index 461df49b468..4db027aaeef 100644 --- a/src/test/run-make/issue-19371/foo.rs +++ b/src/test/run-make/issue-19371/foo.rs @@ -18,7 +18,6 @@ extern crate rustc_errors; extern crate rustc_trans; extern crate syntax; -use rustc::dep_graph::DepGraph; use rustc::session::{build_session, Session}; use rustc::session::config::{basic_options, build_configuration, Input, OutputType, OutputTypes}; @@ -56,6 +55,9 @@ fn basic_sess(sysroot: PathBuf) -> (Session, Rc) { let mut opts = basic_options(); opts.output_types = OutputTypes::new(&[(OutputType::Exe, None)]); opts.maybe_sysroot = Some(sysroot); + if let Ok(linker) = std::env::var("RUSTC_LINKER") { + opts.cg.linker = Some(linker); + } let descriptions = Registry::new(&rustc::DIAGNOSTICS); let cstore = Rc::new(CStore::new(Box::new(rustc_trans::LlvmMetadataLoader))); @@ -67,8 +69,7 @@ fn basic_sess(sysroot: PathBuf) -> (Session, Rc) { fn compile(code: String, output: PathBuf, sysroot: PathBuf) { let (sess, cstore) = basic_sess(sysroot); - let cfg = build_configuration(&sess, HashSet::new()); let control = CompileController::basic(); let input = Input::Str { name: anon_src(), input: code }; - compile_input(&sess, &cstore, &input, &None, &Some(output), None, &control); + let _ = compile_input(&sess, &cstore, &input, &None, &Some(output), None, &control); } diff --git a/src/test/run-make/issue-22131/Makefile b/src/test/run-make/issue-22131/Makefile index 64af91b487b..cb4f1462733 100644 --- a/src/test/run-make/issue-22131/Makefile +++ b/src/test/run-make/issue-22131/Makefile @@ -2,6 +2,6 @@ all: foo.rs $(RUSTC) --cfg 'feature="bar"' --crate-type lib foo.rs - $(HOST_RPATH_ENV) '$(RUSTDOC)' --test --cfg 'feature="bar"' \ + $(RUSTDOC) --test --cfg 'feature="bar"' \ -L $(TMPDIR) foo.rs |\ grep -q 'foo.rs - foo (line 11) ... ok' diff --git a/src/test/run-make/rustdoc-output-path/Makefile b/src/test/run-make/rustdoc-output-path/Makefile index 4e570718a62..8ce1c699526 100644 --- a/src/test/run-make/rustdoc-output-path/Makefile +++ b/src/test/run-make/rustdoc-output-path/Makefile @@ -1,4 +1,4 @@ -include ../tools.mk all: - $(HOST_RPATH_ENV) '$(RUSTDOC)' -o "$(TMPDIR)/foo/bar/doc" foo.rs + $(RUSTDOC) -o "$(TMPDIR)/foo/bar/doc" foo.rs diff --git a/src/test/run-make/staticlib-blank-lib/Makefile b/src/test/run-make/staticlib-blank-lib/Makefile index 5878eec66ba..92a278825c2 100644 --- a/src/test/run-make/staticlib-blank-lib/Makefile +++ b/src/test/run-make/staticlib-blank-lib/Makefile @@ -1,6 +1,6 @@ -include ../tools.mk all: - ar crus $(TMPDIR)/libfoo.a foo.rs - ar d $(TMPDIR)/libfoo.a foo.rs + $(AR) crus $(TMPDIR)/libfoo.a foo.rs + $(AR) d $(TMPDIR)/libfoo.a foo.rs $(RUSTC) foo.rs diff --git a/src/test/run-make/tools.mk b/src/test/run-make/tools.mk index 27f235d54d4..c5d5626bf72 100644 --- a/src/test/run-make/tools.mk +++ b/src/test/run-make/tools.mk @@ -7,7 +7,13 @@ TARGET_RPATH_ENV = \ RUSTC_ORIGINAL := $(RUSTC) BARE_RUSTC := $(HOST_RPATH_ENV) '$(RUSTC)' +BARE_RUSTDOC := $(HOST_RPATH_ENV) '$(RUSTDOC)' RUSTC := $(BARE_RUSTC) --out-dir $(TMPDIR) -L $(TMPDIR) $(RUSTFLAGS) +RUSTDOC := $(BARE_RUSTDOC) +ifdef RUSTC_LINKER +RUSTC := $(RUSTC) -Clinker=$(RUSTC_LINKER) +RUSTDOC := $(RUSTDOC) --linker $(RUSTC_LINKER) -Z unstable-options +endif #CC := $(CC) -L $(TMPDIR) HTMLDOCCK := $(PYTHON) $(S)/src/etc/htmldocck.py @@ -102,13 +108,13 @@ REMOVE_DYLIBS = rm $(TMPDIR)/$(call DYLIB_GLOB,$(1)) REMOVE_RLIBS = rm $(TMPDIR)/$(call RLIB_GLOB,$(1)) %.a: %.o - ar crus $@ $< + $(AR) crus $@ $< ifdef IS_MSVC %.lib: lib%.o $(MSVC_LIB) -out:`cygpath -w $@` $< else %.lib: lib%.o - ar crus $@ $< + $(AR) crus $@ $< endif %.dylib: %.o $(CC) -dynamiclib -Wl,-dylib -o $@ $< diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index cee7e52c7f3..aa98f818f40 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -201,6 +201,8 @@ pub struct Config { pub cc: String, pub cxx: String, pub cflags: String, + pub ar: String, + pub linker: Option, pub llvm_components: String, pub llvm_cxxflags: String, pub nodejs: Option, diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs index 306497da9e3..1701c8a3e43 100644 --- a/src/tools/compiletest/src/main.rs +++ b/src/tools/compiletest/src/main.rs @@ -102,6 +102,8 @@ pub fn parse_config(args: Vec ) -> Config { .reqopt("", "cc", "path to a C compiler", "PATH") .reqopt("", "cxx", "path to a C++ compiler", "PATH") .reqopt("", "cflags", "flags for the C compiler", "FLAGS") + .optopt("", "ar", "path to an archiver", "PATH") + .optopt("", "linker", "path to a linker", "PATH") .reqopt("", "llvm-components", "list of LLVM components built in", "LIST") .reqopt("", "llvm-cxxflags", "C++ flags for LLVM", "FLAGS") .optopt("", "nodejs", "the name of nodejs", "PATH") @@ -198,6 +200,8 @@ pub fn parse_config(args: Vec ) -> Config { cc: matches.opt_str("cc").unwrap(), cxx: matches.opt_str("cxx").unwrap(), cflags: matches.opt_str("cflags").unwrap(), + ar: matches.opt_str("ar").unwrap_or("ar".into()), + linker: matches.opt_str("linker"), llvm_components: matches.opt_str("llvm-components").unwrap(), llvm_cxxflags: matches.opt_str("llvm-cxxflags").unwrap(), nodejs: matches.opt_str("nodejs"), @@ -234,6 +238,8 @@ pub fn log_config(config: &Config) { logv(c, format!("adb_test_dir: {:?}", config.adb_test_dir)); logv(c, format!("adb_device_status: {}", config.adb_device_status)); + logv(c, format!("ar: {}", config.ar)); + logv(c, format!("linker: {:?}", config.linker)); logv(c, format!("verbose: {}", config.verbose)); logv(c, format!("quiet: {}", config.quiet)); logv(c, "\n".to_string()); diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 60acc20e692..6d53c70bff6 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -1155,6 +1155,9 @@ actual:\n\ .arg("-o").arg(out_dir) .arg(&self.testpaths.file) .args(&self.props.compile_flags); + if let Some(ref linker) = self.config.linker { + rustdoc.arg("--linker").arg(linker).arg("-Z").arg("unstable-options"); + } self.compose_and_run_compiler(rustdoc, None) } @@ -2101,6 +2104,10 @@ actual:\n\ .env("LLVM_COMPONENTS", &self.config.llvm_components) .env("LLVM_CXXFLAGS", &self.config.llvm_cxxflags); + if let Some(ref linker) = self.config.linker { + cmd.env("RUSTC_LINKER", linker); + } + // We don't want RUSTFLAGS set from the outside to interfere with // compiler flags set in the test cases: cmd.env_remove("RUSTFLAGS"); @@ -2123,7 +2130,8 @@ actual:\n\ .env("CXX", &self.config.cxx); } else { cmd.env("CC", format!("{} {}", self.config.cc, self.config.cflags)) - .env("CXX", format!("{} {}", self.config.cxx, self.config.cflags)); + .env("CXX", format!("{} {}", self.config.cxx, self.config.cflags)) + .env("AR", &self.config.ar); if self.config.target.contains("windows") { cmd.env("IS_WINDOWS", "1"); -- cgit 1.4.1-3-g733a5