about summary refs log tree commit diff
path: root/src/liballoc
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2019-12-12 02:11:31 +0000
committerbors <bors@rust-lang.org>2019-12-12 02:11:31 +0000
commitf284f8b4be3a899bf2ecc03e2a1589f486b62a9f (patch)
treef384ae1a43bfcacfdce90d2723d50fe09bd4ca96 /src/liballoc
parentde0abf7599023b71dd72b44f0165e86c040ee7ea (diff)
parent685d4cc7463afe2674dac4ac4298c93157965c2a (diff)
downloadrust-f284f8b4be3a899bf2ecc03e2a1589f486b62a9f.tar.gz
rust-f284f8b4be3a899bf2ecc03e2a1589f486b62a9f.zip
Auto merge of #67246 - JohnTitor:rollup-nfa7skn, r=JohnTitor
Rollup of 8 pull requests

Successful merges:

 - #62514 (Clarify `Box<T>` representation and its use in FFI)
 - #66983 (Fix `unused_parens` triggers on macro by example code)
 - #67215 (Fix `-Z print-type-sizes`'s handling of zero-sized fields.)
 - #67230 (Remove irelevant comment on `register_dtor`)
 - #67236 (resolve: Always resolve visibilities on impl items)
 - #67237 (Some small readability improvements)
 - #67238 (Small std::borrow::Cow improvements)
 - #67239 (Make TinyList::remove iterate instead of recurse)

Failed merges:

r? @ghost
Diffstat (limited to 'src/liballoc')
-rw-r--r--src/liballoc/borrow.rs18
-rw-r--r--src/liballoc/boxed.rs53
-rw-r--r--src/liballoc/tests/cow_str.rs3
3 files changed, 61 insertions, 13 deletions
diff --git a/src/liballoc/borrow.rs b/src/liballoc/borrow.rs
index d2bdda83fa9..fc960451968 100644
--- a/src/liballoc/borrow.rs
+++ b/src/liballoc/borrow.rs
@@ -195,14 +195,10 @@ impl<B: ?Sized + ToOwned> Clone for Cow<'_, B> {
     }
 
     fn clone_from(&mut self, source: &Self) {
-        if let Owned(ref mut dest) = *self {
-            if let Owned(ref o) = *source {
-                o.borrow().clone_into(dest);
-                return;
-            }
+        match (self, source) {
+            (&mut Owned(ref mut dest), &Owned(ref o)) => o.borrow().clone_into(dest),
+            (t, s) => *t = s.clone(),
         }
-
-        *self = source.clone();
     }
 }
 
@@ -449,9 +445,7 @@ impl<'a> AddAssign<&'a str> for Cow<'a, str> {
     fn add_assign(&mut self, rhs: &'a str) {
         if self.is_empty() {
             *self = Cow::Borrowed(rhs)
-        } else if rhs.is_empty() {
-            return;
-        } else {
+        } else if !rhs.is_empty() {
             if let Cow::Borrowed(lhs) = *self {
                 let mut s = String::with_capacity(lhs.len() + rhs.len());
                 s.push_str(lhs);
@@ -467,9 +461,7 @@ impl<'a> AddAssign<Cow<'a, str>> for Cow<'a, str> {
     fn add_assign(&mut self, rhs: Cow<'a, str>) {
         if self.is_empty() {
             *self = rhs
-        } else if rhs.is_empty() {
-            return;
-        } else {
+        } else if !rhs.is_empty() {
             if let Cow::Borrowed(lhs) = *self {
                 let mut s = String::with_capacity(lhs.len() + rhs.len());
                 s.push_str(lhs);
diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs
index 51ad3a04e87..1c39a3721f4 100644
--- a/src/liballoc/boxed.rs
+++ b/src/liballoc/boxed.rs
@@ -61,7 +61,60 @@
 //! T` obtained from [`Box::<T>::into_raw`] may be deallocated using the
 //! [`Global`] allocator with [`Layout::for_value(&*value)`].
 //!
+//! So long as `T: Sized`, a `Box<T>` is guaranteed to be represented
+//! as a single pointer and is also ABI-compatible with C pointers
+//! (i.e. the C type `T*`). This means that if you have extern "C"
+//! Rust functions that will be called from C, you can define those
+//! Rust functions using `Box<T>` types, and use `T*` as corresponding
+//! type on the C side. As an example, consider this C header which
+//! declares functions that create and destroy some kind of `Foo`
+//! value:
 //!
+//! ```c
+//! /* C header */
+//!
+//! /* Returns ownership to the caller */
+//! struct Foo* foo_new(void);
+//!
+//! /* Takes ownership from the caller; no-op when invoked with NULL */
+//! void foo_delete(struct Foo*);
+//! ```
+//!
+//! These two functions might be implemented in Rust as follows. Here, the
+//! `struct Foo*` type from C is translated to `Box<Foo>`, which captures
+//! the ownership constraints. Note also that the nullable argument to
+//! `foo_delete` is represented in Rust as `Option<Box<Foo>>`, since `Box<Foo>`
+//! cannot be null.
+//!
+//! ```
+//! #[repr(C)]
+//! pub struct Foo;
+//!
+//! #[no_mangle]
+//! pub extern "C" fn foo_new() -> Box<Foo> {
+//!     Box::new(Foo)
+//! }
+//!
+//! #[no_mangle]
+//! pub extern "C" fn foo_delete(_: Option<Box<Foo>>) {}
+//! ```
+//!
+//! Even though `Box<T>` has the same representation and C ABI as a C pointer,
+//! this does not mean that you can convert an arbitrary `T*` into a `Box<T>`
+//! and expect things to work. `Box<T>` values will always be fully aligned,
+//! non-null pointers. Moreover, the destructor for `Box<T>` will attempt to
+//! free the value with the global allocator. In general, the best practice
+//! is to only use `Box<T>` for pointers that originated from the global
+//! allocator.
+//!
+//! **Important.** At least at present, you should avoid using
+//! `Box<T>` types for functions that are defined in C but invoked
+//! from Rust. In those cases, you should directly mirror the C types
+//! as closely as possible. Using types like `Box<T>` where the C
+//! definition is just using `T*` can lead to undefined behavior, as
+//! described in [rust-lang/unsafe-code-guidelines#198][ucg#198].
+//!
+//! [ucg#198]: https://github.com/rust-lang/unsafe-code-guidelines/issues/198
 //! [dereferencing]: ../../std/ops/trait.Deref.html
 //! [`Box`]: struct.Box.html
 //! [`Box<T>`]: struct.Box.html
diff --git a/src/liballoc/tests/cow_str.rs b/src/liballoc/tests/cow_str.rs
index 6f357eda9b8..62a5c245a54 100644
--- a/src/liballoc/tests/cow_str.rs
+++ b/src/liballoc/tests/cow_str.rs
@@ -138,4 +138,7 @@ fn check_cow_clone_from() {
     let c2: Cow<'_, str> = Cow::Owned(s);
     c1.clone_from(&c2);
     assert!(c1.into_owned().capacity() >= 25);
+    let mut c3: Cow<'_, str> = Cow::Borrowed("bye");
+    c3.clone_from(&c2);
+    assert_eq!(c2, c3);
 }