From 4f4f7f2c7d393e8667fadc7cfc5631d8c2383d3d Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Thu, 17 Dec 2020 22:55:01 -0500 Subject: [PATCH 01/43] Remove giant badge in README --- README.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/README.md b/README.md index 07c09604664..20ca1e8aae2 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,3 @@ - -The Rust Programming Language - - This is the main source code repository for [Rust]. It contains the compiler, standard library, and documentation. From d2cc79eaa2785358a4d0343485122e06235f00c2 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Wed, 23 Dec 2020 14:17:34 -0500 Subject: [PATCH 02/43] Bring back a top level heading --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 20ca1e8aae2..6ab11e7e2be 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ +# The Rust Programming Language + This is the main source code repository for [Rust]. It contains the compiler, standard library, and documentation. From af2983a9122138cb9055b79fda54e72f71599a6f Mon Sep 17 00:00:00 2001 From: The8472 Date: Mon, 4 Jan 2021 01:08:13 +0100 Subject: [PATCH 03/43] TrustedRandomAaccess spec composes incorrectly for nested iter::Zips After partially consuming a Zip adapter and then wrapping it into another Zip where the adapters use their TrustedRandomAccess specializations leads to the outer adapter returning elements which should have already been consumed. --- library/core/src/iter/adapters/zip.rs | 1 + library/core/tests/iter.rs | 21 +++++++++++++++++++++ library/core/tests/lib.rs | 1 + 3 files changed, 23 insertions(+) diff --git a/library/core/src/iter/adapters/zip.rs b/library/core/src/iter/adapters/zip.rs index 8cd4c775231..55670452200 100644 --- a/library/core/src/iter/adapters/zip.rs +++ b/library/core/src/iter/adapters/zip.rs @@ -286,6 +286,7 @@ where #[inline] unsafe fn get_unchecked(&mut self, idx: usize) -> ::Item { + let idx = self.index + idx; // SAFETY: the caller must uphold the contract for // `Iterator::__iterator_get_unchecked`. unsafe { (self.a.__iterator_get_unchecked(idx), self.b.__iterator_get_unchecked(idx)) } diff --git a/library/core/tests/iter.rs b/library/core/tests/iter.rs index 7376e7848ef..5caba1ad229 100644 --- a/library/core/tests/iter.rs +++ b/library/core/tests/iter.rs @@ -2,6 +2,7 @@ use core::cell::Cell; use core::convert::TryFrom; +use core::iter::TrustedRandomAccess; use core::iter::*; /// An iterator wrapper that panics whenever `next` or `next_back` is called @@ -601,6 +602,26 @@ fn test_zip_nth_back_side_effects_exhausted() { assert_eq!(b, vec![200, 300, 400]); } +#[test] +fn test_zip_trusted_random_access_composition() { + let a = [0, 1, 2, 3, 4]; + let b = a; + let c = a; + + let a = a.iter().copied(); + let b = b.iter().copied(); + let mut c = c.iter().copied(); + c.next(); + + let mut z1 = a.zip(b); + assert_eq!(z1.next().unwrap(), (0, 0)); + + let mut z2 = z1.zip(c); + fn assert_trusted_random_access(_a: &T) {} + assert_trusted_random_access(&z2); + assert_eq!(z2.next().unwrap(), ((1, 1), 1)); +} + #[test] fn test_iterator_step_by() { // Identity diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index e01aaa4cbf1..4c90844e07d 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -73,6 +73,7 @@ #![feature(const_option)] #![feature(integer_atomics)] #![feature(slice_group_by)] +#![feature(trusted_random_access)] #![deny(unsafe_op_in_unsafe_fn)] extern crate test; From 6bc772cdc0a9021a6286ebd550c2f6221179f21d Mon Sep 17 00:00:00 2001 From: CAD97 Date: Wed, 6 Jan 2021 16:34:13 -0500 Subject: [PATCH 04/43] Re-stabilize Weak::as_ptr &friends for unsized T As per T-lang consensus, this uses a branch to handle the dangling case. The discussed optimization of only doing the branch in the T: ?Sized case is left for a followup patch, as doing so is not trivial (as it requires specialization for correctness, not just optimization). --- library/alloc/src/lib.rs | 1 + library/alloc/src/rc.rs | 41 ++++++++++++++++++--------------- library/alloc/src/rc/tests.rs | 41 +++++++++++++++++++++++++++++++++ library/alloc/src/sync.rs | 41 +++++++++++++++++++-------------- library/alloc/src/sync/tests.rs | 41 +++++++++++++++++++++++++++++++++ 5 files changed, 130 insertions(+), 35 deletions(-) diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index cfad111aa54..d0bfa038aa1 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -120,6 +120,7 @@ #![feature(receiver_trait)] #![cfg_attr(bootstrap, feature(min_const_generics))] #![feature(min_specialization)] +#![feature(set_ptr_value)] #![feature(slice_ptr_get)] #![feature(slice_ptr_len)] #![feature(staged_api)] diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 8183a582d33..48b9b8a34f1 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -1862,7 +1862,7 @@ struct WeakInner<'a> { strong: &'a Cell, } -impl Weak { +impl Weak { /// Returns a raw pointer to the object `T` pointed to by this `Weak`. /// /// The pointer is valid only if there are some strong references. The pointer may be dangling, @@ -1892,15 +1892,17 @@ impl Weak { pub fn as_ptr(&self) -> *const T { let ptr: *mut RcBox = NonNull::as_ptr(self.ptr); - // SAFETY: we must offset the pointer manually, and said pointer may be - // a dangling weak (usize::MAX) if T is sized. data_offset is safe to call, - // because we know that a pointer to unsized T was derived from a real - // unsized T, as dangling weaks are only created for sized T. wrapping_offset - // is used so that we can use the same code path for the non-dangling - // unsized case and the potentially dangling sized case. - unsafe { - let offset = data_offset(ptr as *mut T); - set_data_ptr(ptr as *mut T, (ptr as *mut u8).wrapping_offset(offset)) + if is_dangling(self.ptr) { + // If the pointer is dangling, we return a null pointer as the dangling sentinel. + // We can't return the usize::MAX sentinel, as that could valid if T is ZST. + // SAFETY: we have to return a known sentinel here that cannot be produced for + // a valid pointer, so that `from_raw` can reverse this transformation. + (ptr as *mut T).set_ptr_value(ptr::null_mut()) + } else { + // SAFETY: If the pointer is not dangling, it describes to a valid allocation. + // The payload may be dropped at this point, and we have to maintain provenance, + // so use raw pointer manipulation. + unsafe { &raw mut (*ptr).value } } } @@ -1982,22 +1984,25 @@ impl Weak { /// [`new`]: Weak::new #[stable(feature = "weak_into_raw", since = "1.45.0")] pub unsafe fn from_raw(ptr: *const T) -> Self { - // SAFETY: data_offset is safe to call, because this pointer originates from a Weak. // See Weak::as_ptr for context on how the input pointer is derived. - let offset = unsafe { data_offset(ptr) }; - // Reverse the offset to find the original RcBox. - // SAFETY: we use wrapping_offset here because the pointer may be dangling (but only if T: Sized). - let ptr = unsafe { - set_data_ptr(ptr as *mut RcBox, (ptr as *mut u8).wrapping_offset(-offset)) + let ptr = if ptr.is_null() { + // If we get a null pointer, this is a dangling weak. + // SAFETY: this is the same sentinel as used in Weak::new and is_dangling + (ptr as *mut RcBox).set_ptr_value(usize::MAX as *mut _) + } else { + // Otherwise, this describes a real allocation. + // SAFETY: data_offset is safe to call, as ptr describes a real allocation. + let offset = unsafe { data_offset(ptr) }; + // Thus, we reverse the offset to get the whole RcBox. + // SAFETY: the pointer originated from a Weak, so this offset is safe. + unsafe { (ptr as *mut RcBox).set_ptr_value((ptr as *mut u8).offset(-offset)) } }; // SAFETY: we now have recovered the original Weak pointer, so can create the Weak. Weak { ptr: unsafe { NonNull::new_unchecked(ptr) } } } -} -impl Weak { /// Attempts to upgrade the `Weak` pointer to an [`Rc`], delaying /// dropping of the inner value if successful. /// diff --git a/library/alloc/src/rc/tests.rs b/library/alloc/src/rc/tests.rs index 2d183a8c88c..843a9b07fa9 100644 --- a/library/alloc/src/rc/tests.rs +++ b/library/alloc/src/rc/tests.rs @@ -208,6 +208,30 @@ fn into_from_weak_raw() { } } +#[test] +fn test_into_from_weak_raw_unsized() { + use std::fmt::Display; + use std::string::ToString; + + let arc: Rc = Rc::from("foo"); + let weak: Weak = Rc::downgrade(&arc); + + let ptr = Weak::into_raw(weak.clone()); + let weak2 = unsafe { Weak::from_raw(ptr) }; + + assert_eq!(unsafe { &*ptr }, "foo"); + assert!(weak.ptr_eq(&weak2)); + + let arc: Rc = Rc::new(123); + let weak: Weak = Rc::downgrade(&arc); + + let ptr = Weak::into_raw(weak.clone()); + let weak2 = unsafe { Weak::from_raw(ptr) }; + + assert_eq!(unsafe { &*ptr }.to_string(), "123"); + assert!(weak.ptr_eq(&weak2)); +} + #[test] fn get_mut() { let mut x = Rc::new(3); @@ -294,6 +318,23 @@ fn test_unsized() { assert_eq!(foo, foo.clone()); } +#[test] +fn test_maybe_thin_unsized() { + // If/when custom thin DSTs exist, this test should be updated to use one + use std::ffi::{CStr, CString}; + + let x: Rc = Rc::from(CString::new("swordfish").unwrap().into_boxed_c_str()); + assert_eq!(format!("{:?}", x), "\"swordfish\""); + let y: Weak = Rc::downgrade(&x); + drop(x); + + // At this point, the weak points to a dropped DST + assert!(y.upgrade().is_none()); + // But we still need to be able to get the alloc layout to drop. + // CStr has no drop glue, but custom DSTs might, and need to work. + drop(y); +} + #[test] fn test_from_owned() { let foo = 123; diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 06ad6217271..ae61f4a2384 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -1648,7 +1648,7 @@ struct WeakInner<'a> { strong: &'a atomic::AtomicUsize, } -impl Weak { +impl Weak { /// Returns a raw pointer to the object `T` pointed to by this `Weak`. /// /// The pointer is valid only if there are some strong references. The pointer may be dangling, @@ -1678,15 +1678,17 @@ impl Weak { pub fn as_ptr(&self) -> *const T { let ptr: *mut ArcInner = NonNull::as_ptr(self.ptr); - // SAFETY: we must offset the pointer manually, and said pointer may be - // a dangling weak (usize::MAX) if T is sized. data_offset is safe to call, - // because we know that a pointer to unsized T was derived from a real - // unsized T, as dangling weaks are only created for sized T. wrapping_offset - // is used so that we can use the same code path for the non-dangling - // unsized case and the potentially dangling sized case. - unsafe { - let offset = data_offset(ptr as *mut T); - set_data_ptr(ptr as *mut T, (ptr as *mut u8).wrapping_offset(offset)) + if is_dangling(self.ptr) { + // If the pointer is dangling, we return a null pointer as the dangling sentinel. + // We can't return the usize::MAX sentinel, as that could valid if T is ZST. + // SAFETY: we have to return a known sentinel here that cannot be produced for + // a valid pointer, so that `from_raw` can reverse this transformation. + (ptr as *mut T).set_ptr_value(ptr::null_mut()) + } else { + // SAFETY: If the pointer is not dangling, it describes to a valid allocation. + // The payload may be dropped at this point, and we have to maintain provenance, + // so use raw pointer manipulation. + unsafe { &raw mut (*ptr).data } } } @@ -1768,18 +1770,23 @@ impl Weak { /// [`forget`]: std::mem::forget #[stable(feature = "weak_into_raw", since = "1.45.0")] pub unsafe fn from_raw(ptr: *const T) -> Self { - // SAFETY: data_offset is safe to call, because this pointer originates from a Weak. // See Weak::as_ptr for context on how the input pointer is derived. - let offset = unsafe { data_offset(ptr) }; - // Reverse the offset to find the original ArcInner. - // SAFETY: we use wrapping_offset here because the pointer may be dangling (but only if T: Sized) - let ptr = unsafe { - set_data_ptr(ptr as *mut ArcInner, (ptr as *mut u8).wrapping_offset(-offset)) + let ptr = if ptr.is_null() { + // If we get a null pointer, this is a dangling weak. + // SAFETY: this is the same sentinel as used in Weak::new and is_dangling + (ptr as *mut ArcInner).set_ptr_value(usize::MAX as *mut _) + } else { + // Otherwise, this describes a real allocation. + // SAFETY: data_offset is safe to call, as ptr describes a real allocation. + let offset = unsafe { data_offset(ptr) }; + // Thus, we reverse the offset to get the whole RcBox. + // SAFETY: the pointer originated from a Weak, so this offset is safe. + unsafe { (ptr as *mut ArcInner).set_ptr_value((ptr as *mut u8).offset(-offset)) } }; // SAFETY: we now have recovered the original Weak pointer, so can create the Weak. - unsafe { Weak { ptr: NonNull::new_unchecked(ptr) } } + Weak { ptr: unsafe { NonNull::new_unchecked(ptr) } } } } diff --git a/library/alloc/src/sync/tests.rs b/library/alloc/src/sync/tests.rs index e8e1e66da5e..ce5c32ed8c5 100644 --- a/library/alloc/src/sync/tests.rs +++ b/library/alloc/src/sync/tests.rs @@ -158,6 +158,30 @@ fn into_from_weak_raw() { } } +#[test] +fn test_into_from_weak_raw_unsized() { + use std::fmt::Display; + use std::string::ToString; + + let arc: Arc = Arc::from("foo"); + let weak: Weak = Arc::downgrade(&arc); + + let ptr = Weak::into_raw(weak.clone()); + let weak2 = unsafe { Weak::from_raw(ptr) }; + + assert_eq!(unsafe { &*ptr }, "foo"); + assert!(weak.ptr_eq(&weak2)); + + let arc: Arc = Arc::new(123); + let weak: Weak = Arc::downgrade(&arc); + + let ptr = Weak::into_raw(weak.clone()); + let weak2 = unsafe { Weak::from_raw(ptr) }; + + assert_eq!(unsafe { &*ptr }.to_string(), "123"); + assert!(weak.ptr_eq(&weak2)); +} + #[test] fn test_cowarc_clone_make_mut() { let mut cow0 = Arc::new(75); @@ -329,6 +353,23 @@ fn test_unsized() { assert!(y.upgrade().is_none()); } +#[test] +fn test_maybe_thin_unsized() { + // If/when custom thin DSTs exist, this test should be updated to use one + use std::ffi::{CStr, CString}; + + let x: Arc = Arc::from(CString::new("swordfish").unwrap().into_boxed_c_str()); + assert_eq!(format!("{:?}", x), "\"swordfish\""); + let y: Weak = Arc::downgrade(&x); + drop(x); + + // At this point, the weak points to a dropped DST + assert!(y.upgrade().is_none()); + // But we still need to be able to get the alloc layout to drop. + // CStr has no drop glue, but custom DSTs might, and need to work. + drop(y); +} + #[test] fn test_from_owned() { let foo = 123; From f00b45890311da955bf2081a0fab2837f3a36a4d Mon Sep 17 00:00:00 2001 From: CAD97 Date: Thu, 7 Jan 2021 12:32:42 -0500 Subject: [PATCH 05/43] Tighten/clarify documentation of rc data_offset --- library/alloc/src/rc.rs | 7 ++----- library/alloc/src/sync.rs | 7 ++----- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 48b9b8a34f1..61d70a62dca 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -2325,11 +2325,8 @@ impl Unpin for Rc {} /// /// # Safety /// -/// This has the same safety requirements as `align_of_val_raw`. In effect: -/// -/// - This function is safe for any argument if `T` is sized, and -/// - if `T` is unsized, the pointer must have appropriate pointer metadata -/// acquired from the real instance that you are getting this offset for. +/// The pointer must point to (and have valid metadata for) a previously +/// valid instance of T, but the T is allowed to be dropped. unsafe fn data_offset(ptr: *const T) -> isize { // Align the unsized value to the end of the `RcBox`. // Because it is ?Sized, it will always be the last field in memory. diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index ae61f4a2384..1ca6b6d6335 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -2476,11 +2476,8 @@ impl Unpin for Arc {} /// /// # Safety /// -/// This has the same safety requirements as `align_of_val_raw`. In effect: -/// -/// - This function is safe for any argument if `T` is sized, and -/// - if `T` is unsized, the pointer must have appropriate pointer metadata -/// acquired from the real instance that you are getting this offset for. +/// The pointer must point to (and have valid metadata for) a previously +/// valid instance of T, but the T is allowed to be dropped. unsafe fn data_offset(ptr: *const T) -> isize { // Align the unsized value to the end of the `ArcInner`. // Because it is `?Sized`, it will always be the last field in memory. From b10b9e25ffcb06077375960f07a0c6443184f07a Mon Sep 17 00:00:00 2001 From: CAD97 Date: Thu, 7 Jan 2021 12:41:58 -0500 Subject: [PATCH 06/43] Remove "pointer describes" terminology --- library/alloc/src/rc.rs | 9 ++++----- library/alloc/src/sync.rs | 9 ++++----- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 61d70a62dca..7f500af59a8 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -1899,7 +1899,7 @@ impl Weak { // a valid pointer, so that `from_raw` can reverse this transformation. (ptr as *mut T).set_ptr_value(ptr::null_mut()) } else { - // SAFETY: If the pointer is not dangling, it describes to a valid allocation. + // SAFETY: If the pointer is not dangling, it references a valid allocation. // The payload may be dropped at this point, and we have to maintain provenance, // so use raw pointer manipulation. unsafe { &raw mut (*ptr).value } @@ -1991,8 +1991,8 @@ impl Weak { // SAFETY: this is the same sentinel as used in Weak::new and is_dangling (ptr as *mut RcBox).set_ptr_value(usize::MAX as *mut _) } else { - // Otherwise, this describes a real allocation. - // SAFETY: data_offset is safe to call, as ptr describes a real allocation. + // Otherwise, this references a real allocation. + // SAFETY: data_offset is safe to call, as ptr references a real (potentially dropped) T. let offset = unsafe { data_offset(ptr) }; // Thus, we reverse the offset to get the whole RcBox. // SAFETY: the pointer originated from a Weak, so this offset is safe. @@ -2320,8 +2320,7 @@ impl AsRef for Rc { #[stable(feature = "pin", since = "1.33.0")] impl Unpin for Rc {} -/// Get the offset within an `RcBox` for -/// a payload of type described by a pointer. +/// Get the offset within an `RcBox` for the payload behind a pointer. /// /// # Safety /// diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 1ca6b6d6335..e2811a5cd6c 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -1685,7 +1685,7 @@ impl Weak { // a valid pointer, so that `from_raw` can reverse this transformation. (ptr as *mut T).set_ptr_value(ptr::null_mut()) } else { - // SAFETY: If the pointer is not dangling, it describes to a valid allocation. + // SAFETY: If the pointer is not dangling, it references a valid allocation. // The payload may be dropped at this point, and we have to maintain provenance, // so use raw pointer manipulation. unsafe { &raw mut (*ptr).data } @@ -1777,8 +1777,8 @@ impl Weak { // SAFETY: this is the same sentinel as used in Weak::new and is_dangling (ptr as *mut ArcInner).set_ptr_value(usize::MAX as *mut _) } else { - // Otherwise, this describes a real allocation. - // SAFETY: data_offset is safe to call, as ptr describes a real allocation. + // Otherwise, this references a real allocation. + // SAFETY: data_offset is safe to call, as ptr references a real (potentially dropped) T. let offset = unsafe { data_offset(ptr) }; // Thus, we reverse the offset to get the whole RcBox. // SAFETY: the pointer originated from a Weak, so this offset is safe. @@ -2471,8 +2471,7 @@ impl AsRef for Arc { #[stable(feature = "pin", since = "1.33.0")] impl Unpin for Arc {} -/// Get the offset within an `ArcInner` for -/// a payload of type described by a pointer. +/// Get the offset within an `ArcInner` for the payload behind a pointer. /// /// # Safety /// From 1e578c9fb051ed3a4e608a43d840ad2877701333 Mon Sep 17 00:00:00 2001 From: CAD97 Date: Thu, 7 Jan 2021 12:50:31 -0500 Subject: [PATCH 07/43] Reclarify Weak<->raw pointer safety comments --- library/alloc/src/rc.rs | 4 ++-- library/alloc/src/sync.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 7f500af59a8..dd7710e5c05 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -1899,7 +1899,7 @@ impl Weak { // a valid pointer, so that `from_raw` can reverse this transformation. (ptr as *mut T).set_ptr_value(ptr::null_mut()) } else { - // SAFETY: If the pointer is not dangling, it references a valid allocation. + // SAFETY: if is_dangling returns false, then the pointer is dereferencable. // The payload may be dropped at this point, and we have to maintain provenance, // so use raw pointer manipulation. unsafe { &raw mut (*ptr).value } @@ -1991,7 +1991,7 @@ impl Weak { // SAFETY: this is the same sentinel as used in Weak::new and is_dangling (ptr as *mut RcBox).set_ptr_value(usize::MAX as *mut _) } else { - // Otherwise, this references a real allocation. + // Otherwise, we're guaranteed the pointer came from a nondangling Weak. // SAFETY: data_offset is safe to call, as ptr references a real (potentially dropped) T. let offset = unsafe { data_offset(ptr) }; // Thus, we reverse the offset to get the whole RcBox. diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index e2811a5cd6c..6241ee626f7 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -1685,7 +1685,7 @@ impl Weak { // a valid pointer, so that `from_raw` can reverse this transformation. (ptr as *mut T).set_ptr_value(ptr::null_mut()) } else { - // SAFETY: If the pointer is not dangling, it references a valid allocation. + // SAFETY: if is_dangling returns false, then the pointer is dereferencable. // The payload may be dropped at this point, and we have to maintain provenance, // so use raw pointer manipulation. unsafe { &raw mut (*ptr).data } @@ -1777,7 +1777,7 @@ impl Weak { // SAFETY: this is the same sentinel as used in Weak::new and is_dangling (ptr as *mut ArcInner).set_ptr_value(usize::MAX as *mut _) } else { - // Otherwise, this references a real allocation. + // Otherwise, we're guaranteed the pointer came from a nondangling Weak. // SAFETY: data_offset is safe to call, as ptr references a real (potentially dropped) T. let offset = unsafe { data_offset(ptr) }; // Thus, we reverse the offset to get the whole RcBox. From 4901c55af7ec98231653cd0c3a0b1a6937eac743 Mon Sep 17 00:00:00 2001 From: CAD97 Date: Thu, 7 Jan 2021 13:39:32 -0500 Subject: [PATCH 08/43] Replace set_data_ptr with pointer::set_ptr_value --- library/alloc/src/rc.rs | 19 +++---------------- library/alloc/src/sync.rs | 18 ++---------------- 2 files changed, 5 insertions(+), 32 deletions(-) diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index dd7710e5c05..ed22571409c 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -827,8 +827,8 @@ impl Rc { let offset = unsafe { data_offset(ptr) }; // Reverse the offset to find the original RcBox. - let fake_ptr = ptr as *mut RcBox; - let rc_ptr = unsafe { set_data_ptr(fake_ptr, (ptr as *mut u8).offset(-offset)) }; + let rc_ptr = + unsafe { (ptr as *mut RcBox).set_ptr_value((ptr as *mut u8).offset(-offset)) }; unsafe { Self::from_ptr(rc_ptr) } } @@ -1154,7 +1154,7 @@ impl Rc { Self::allocate_for_layout( Layout::for_value(&*ptr), |layout| Global.allocate(layout), - |mem| set_data_ptr(ptr as *mut T, mem) as *mut RcBox, + |mem| (ptr as *mut RcBox).set_ptr_value(mem), ) } } @@ -1193,20 +1193,7 @@ impl Rc<[T]> { ) } } -} -/// Sets the data pointer of a `?Sized` raw pointer. -/// -/// For a slice/trait object, this sets the `data` field and leaves the rest -/// unchanged. For a sized raw pointer, this simply sets the pointer. -unsafe fn set_data_ptr(mut ptr: *mut T, data: *mut U) -> *mut T { - unsafe { - ptr::write(&mut ptr as *mut _ as *mut *mut u8, data as *mut u8); - } - ptr -} - -impl Rc<[T]> { /// Copy elements from slice into newly allocated Rc<\[T\]> /// /// Unsafe because the caller must either take ownership or bind `T: Copy` diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 6241ee626f7..aa6acdbff34 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -844,8 +844,7 @@ impl Arc { let offset = data_offset(ptr); // Reverse the offset to find the original ArcInner. - let fake_ptr = ptr as *mut ArcInner; - let arc_ptr = set_data_ptr(fake_ptr, (ptr as *mut u8).offset(-offset)); + let arc_ptr = (ptr as *mut ArcInner).set_ptr_value((ptr as *mut u8).offset(-offset)); Self::from_ptr(arc_ptr) } @@ -1129,7 +1128,7 @@ impl Arc { Self::allocate_for_layout( Layout::for_value(&*ptr), |layout| Global.allocate(layout), - |mem| set_data_ptr(ptr as *mut T, mem) as *mut ArcInner, + |mem| (ptr as *mut ArcInner).set_ptr_value(mem) as *mut ArcInner, ) } } @@ -1168,20 +1167,7 @@ impl Arc<[T]> { ) } } -} -/// Sets the data pointer of a `?Sized` raw pointer. -/// -/// For a slice/trait object, this sets the `data` field and leaves the rest -/// unchanged. For a sized raw pointer, this simply sets the pointer. -unsafe fn set_data_ptr(mut ptr: *mut T, data: *mut U) -> *mut T { - unsafe { - ptr::write(&mut ptr as *mut _ as *mut *mut u8, data as *mut u8); - } - ptr -} - -impl Arc<[T]> { /// Copy elements from slice into newly allocated Arc<\[T\]> /// /// Unsafe because the caller must either take ownership or bind `T: Copy`. From 747dbcb3255399396ca16c8462c5a809423c7350 Mon Sep 17 00:00:00 2001 From: CAD97 Date: Sat, 9 Jan 2021 14:32:55 -0500 Subject: [PATCH 09/43] Provide reasoning for rc data_offset safety --- library/alloc/src/rc.rs | 10 ++++++---- library/alloc/src/sync.rs | 10 ++++++---- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index ed22571409c..b9f3f357c1a 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -2314,10 +2314,12 @@ impl Unpin for Rc {} /// The pointer must point to (and have valid metadata for) a previously /// valid instance of T, but the T is allowed to be dropped. unsafe fn data_offset(ptr: *const T) -> isize { - // Align the unsized value to the end of the `RcBox`. - // Because it is ?Sized, it will always be the last field in memory. - // Note: This is a detail of the current implementation of the compiler, - // and is not a guaranteed language detail. Do not rely on it outside of std. + // Align the unsized value to the end of the RcBox. + // Because RcBox is repr(C), it will always be the last field in memory. + // SAFETY: since the only unsized types possible are slices, trait objects, + // and extern types, the input safety requirement is currently enough to + // satisfy the requirements of align_of_val_raw; this is an implementation + // detail of the language that may not be relied upon outside of std. unsafe { data_offset_align(align_of_val_raw(ptr)) } } diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index aa6acdbff34..c50f5270a4d 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -2464,10 +2464,12 @@ impl Unpin for Arc {} /// The pointer must point to (and have valid metadata for) a previously /// valid instance of T, but the T is allowed to be dropped. unsafe fn data_offset(ptr: *const T) -> isize { - // Align the unsized value to the end of the `ArcInner`. - // Because it is `?Sized`, it will always be the last field in memory. - // Note: This is a detail of the current implementation of the compiler, - // and is not a guaranteed language detail. Do not rely on it outside of std. + // Align the unsized value to the end of the ArcInner. + // Because RcBox is repr(C), it will always be the last field in memory. + // SAFETY: since the only unsized types possible are slices, trait objects, + // and extern types, the input safety requirement is currently enough to + // satisfy the requirements of align_of_val_raw; this is an implementation + // detail of the language that may not be relied upon outside of std. unsafe { data_offset_align(align_of_val_raw(ptr)) } } From 5ccef564560df65db0cb761cb27751f15821f1af Mon Sep 17 00:00:00 2001 From: 1000teslas <47207223+1000teslas@users.noreply.github.com> Date: Sat, 2 Jan 2021 22:03:21 +1100 Subject: [PATCH 10/43] Explain why borrows can't be held across yield point in async blocks --- .../diagnostics/conflict_errors.rs | 10 ++++++ .../issues/issue-78938-async-block.rs | 33 +++++++++++++++++++ .../issues/issue-78938-async-block.stderr | 30 +++++++++++++++++ 3 files changed, 73 insertions(+) create mode 100644 src/test/ui/async-await/issues/issue-78938-async-block.rs create mode 100644 src/test/ui/async-await/issues/issue-78938-async-block.stderr diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs index 0bb09e26f03..1dd102f4f34 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs @@ -1323,6 +1323,16 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { suggestion, Applicability::MachineApplicable, ); + if let Some(generator_kind) = use_span.generator_kind() { + if let GeneratorKind::Async(_) = generator_kind { + err.note( + "borrows cannot be held across a yield point, because the stack space of the current \ + function is not preserved", + ); + err.help("see https://rust-lang.github.io/async-book/03_async_await/01_chapter.html#awaiting-on-a-multithreaded-executor \ + for more information"); + } + } let msg = match category { ConstraintCategory::Return(_) | ConstraintCategory::OpaqueType => { diff --git a/src/test/ui/async-await/issues/issue-78938-async-block.rs b/src/test/ui/async-await/issues/issue-78938-async-block.rs new file mode 100644 index 00000000000..e3d8eb73772 --- /dev/null +++ b/src/test/ui/async-await/issues/issue-78938-async-block.rs @@ -0,0 +1,33 @@ +// edition:2018 + +use std::{sync::Arc, future::Future, pin::Pin, task::{Context,Poll}}; + +async fn f() { + let room_ref = Arc::new(Vec::new()); + + let gameloop_handle = spawn(async { //~ ERROR E0373 + game_loop(Arc::clone(&room_ref)) + }); + gameloop_handle.await; +} + +fn game_loop(v: Arc>) {} + +fn spawn(future: F) -> JoinHandle +where + F: Future + Send + 'static, + F::Output: Send + 'static, +{ + loop {} +} + +struct JoinHandle; + +impl Future for JoinHandle { + type Output = (); + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + loop {} + } +} + +fn main() {} \ No newline at end of file diff --git a/src/test/ui/async-await/issues/issue-78938-async-block.stderr b/src/test/ui/async-await/issues/issue-78938-async-block.stderr new file mode 100644 index 00000000000..83cf1a5bc46 --- /dev/null +++ b/src/test/ui/async-await/issues/issue-78938-async-block.stderr @@ -0,0 +1,30 @@ +error[E0373]: async block may outlive the current function, but it borrows `room_ref`, which is owned by the current function + --> $DIR/issue-78938-async-block.rs:8:39 + | +LL | let gameloop_handle = spawn(async { + | _______________________________________^ +LL | | game_loop(Arc::clone(&room_ref)) + | | -------- `room_ref` is borrowed here +LL | | }); + | |_____^ may outlive borrowed value `room_ref` + | + = note: borrows cannot be held across a yield point, because the stack space of the current function is not preserved + = help: see https://rust-lang.github.io/async-book/03_async_await/01_chapter.html#awaiting-on-a-multithreaded-executor for more information +note: function requires argument type to outlive `'static` + --> $DIR/issue-78938-async-block.rs:8:33 + | +LL | let gameloop_handle = spawn(async { + | _________________________________^ +LL | | game_loop(Arc::clone(&room_ref)) +LL | | }); + | |_____^ +help: to force the async block to take ownership of `room_ref` (and any other referenced variables), use the `move` keyword + | +LL | let gameloop_handle = spawn(async move { +LL | game_loop(Arc::clone(&room_ref)) +LL | }); + | + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0373`. From 12f17957432fa03a8fe57c2b6063c662add45c2c Mon Sep 17 00:00:00 2001 From: 1000teslas <47207223+1000teslas@users.noreply.github.com> Date: Sun, 3 Jan 2021 03:53:50 +1100 Subject: [PATCH 11/43] Fix location of error message explanation --- .../diagnostics/conflict_errors.rs | 22 ++++++++++--------- .../issues/issue-78938-async-block.rs | 6 ++--- .../issues/issue-78938-async-block.stderr | 4 ++-- 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs index 1dd102f4f34..43e9701aa25 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs @@ -1323,16 +1323,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { suggestion, Applicability::MachineApplicable, ); - if let Some(generator_kind) = use_span.generator_kind() { - if let GeneratorKind::Async(_) = generator_kind { - err.note( - "borrows cannot be held across a yield point, because the stack space of the current \ - function is not preserved", - ); - err.help("see https://rust-lang.github.io/async-book/03_async_await/01_chapter.html#awaiting-on-a-multithreaded-executor \ - for more information"); - } - } let msg = match category { ConstraintCategory::Return(_) | ConstraintCategory::OpaqueType => { @@ -1349,6 +1339,18 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ), }; err.span_note(constraint_span, &msg); + if let ConstraintCategory::CallArgument = category { + if let Some(generator_kind) = use_span.generator_kind() { + if let GeneratorKind::Async(_) = generator_kind { + err.note( + "borrows cannot be held across a yield point, because the stack \ + space of the current function is not preserved", + ); + err.help("see https://rust-lang.github.io/async-book/03_async_await/01_chapter.html#awaiting-on-a-multithreaded-executor \ + for more information"); + } + } + } err } diff --git a/src/test/ui/async-await/issues/issue-78938-async-block.rs b/src/test/ui/async-await/issues/issue-78938-async-block.rs index e3d8eb73772..a16061fd979 100644 --- a/src/test/ui/async-await/issues/issue-78938-async-block.rs +++ b/src/test/ui/async-await/issues/issue-78938-async-block.rs @@ -16,7 +16,7 @@ fn game_loop(v: Arc>) {} fn spawn(future: F) -> JoinHandle where F: Future + Send + 'static, - F::Output: Send + 'static, + F::Output: Send + 'static, { loop {} } @@ -26,8 +26,8 @@ struct JoinHandle; impl Future for JoinHandle { type Output = (); fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - loop {} + loop {} } } -fn main() {} \ No newline at end of file +fn main() {} diff --git a/src/test/ui/async-await/issues/issue-78938-async-block.stderr b/src/test/ui/async-await/issues/issue-78938-async-block.stderr index 83cf1a5bc46..604c47b430f 100644 --- a/src/test/ui/async-await/issues/issue-78938-async-block.stderr +++ b/src/test/ui/async-await/issues/issue-78938-async-block.stderr @@ -8,8 +8,6 @@ LL | | game_loop(Arc::clone(&room_ref)) LL | | }); | |_____^ may outlive borrowed value `room_ref` | - = note: borrows cannot be held across a yield point, because the stack space of the current function is not preserved - = help: see https://rust-lang.github.io/async-book/03_async_await/01_chapter.html#awaiting-on-a-multithreaded-executor for more information note: function requires argument type to outlive `'static` --> $DIR/issue-78938-async-block.rs:8:33 | @@ -18,6 +16,8 @@ LL | let gameloop_handle = spawn(async { LL | | game_loop(Arc::clone(&room_ref)) LL | | }); | |_____^ + = note: borrows cannot be held across a yield point, because the stack space of the current function is not preserved + = help: see https://rust-lang.github.io/async-book/03_async_await/01_chapter.html#awaiting-on-a-multithreaded-executor for more information help: to force the async block to take ownership of `room_ref` (and any other referenced variables), use the `move` keyword | LL | let gameloop_handle = spawn(async move { From 2b9c8ff6b37e0fd9143ba0f5a1fd11057880cebc Mon Sep 17 00:00:00 2001 From: 1000teslas <47207223+1000teslas@users.noreply.github.com> Date: Sun, 3 Jan 2021 04:00:51 +1100 Subject: [PATCH 12/43] Update issue-78938-async-block.rs Fix whitespace --- src/test/ui/async-await/issues/issue-78938-async-block.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/ui/async-await/issues/issue-78938-async-block.rs b/src/test/ui/async-await/issues/issue-78938-async-block.rs index a16061fd979..86afef08fc7 100644 --- a/src/test/ui/async-await/issues/issue-78938-async-block.rs +++ b/src/test/ui/async-await/issues/issue-78938-async-block.rs @@ -26,7 +26,7 @@ struct JoinHandle; impl Future for JoinHandle { type Output = (); fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - loop {} + loop {} } } From 9e345a58936edc81acf09d89675f71711f3d2439 Mon Sep 17 00:00:00 2001 From: 1000teslas <47207223+1000teslas@users.noreply.github.com> Date: Sat, 9 Jan 2021 19:46:19 +1100 Subject: [PATCH 13/43] Revise async block error message --- .../diagnostics/conflict_errors.rs | 31 +++++++++---------- .../issues/issue-78938-async-block.stderr | 10 +----- 2 files changed, 16 insertions(+), 25 deletions(-) diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs index 43e9701aa25..85ea70cefba 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs @@ -1324,33 +1324,32 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { Applicability::MachineApplicable, ); - let msg = match category { + match category { ConstraintCategory::Return(_) | ConstraintCategory::OpaqueType => { - format!("{} is returned here", kind) + let msg = format!("{} is returned here", kind); + err.span_note(constraint_span, &msg); } ConstraintCategory::CallArgument => { fr_name.highlight_region_name(&mut err); - format!("function requires argument type to outlive `{}`", fr_name) + if matches!(use_span.generator_kind(), Some(generator_kind) + if matches!(generator_kind, GeneratorKind::Async(_))) + { + err.note("async blocks are not executed immediately and either must take a \ + reference or ownership of outside variables they use"); + err.help("see https://rust-lang.github.io/async-book/03_async_await/01_chapter.html#awaiting-on-a-multithreaded-executor \ + for more information"); + } else { + let msg = format!("function requires argument type to outlive `{}`", fr_name); + err.span_note(constraint_span, &msg); + } } _ => bug!( "report_escaping_closure_capture called with unexpected constraint \ category: `{:?}`", category ), - }; - err.span_note(constraint_span, &msg); - if let ConstraintCategory::CallArgument = category { - if let Some(generator_kind) = use_span.generator_kind() { - if let GeneratorKind::Async(_) = generator_kind { - err.note( - "borrows cannot be held across a yield point, because the stack \ - space of the current function is not preserved", - ); - err.help("see https://rust-lang.github.io/async-book/03_async_await/01_chapter.html#awaiting-on-a-multithreaded-executor \ - for more information"); - } - } } + err } diff --git a/src/test/ui/async-await/issues/issue-78938-async-block.stderr b/src/test/ui/async-await/issues/issue-78938-async-block.stderr index 604c47b430f..4468975b2f5 100644 --- a/src/test/ui/async-await/issues/issue-78938-async-block.stderr +++ b/src/test/ui/async-await/issues/issue-78938-async-block.stderr @@ -8,15 +8,7 @@ LL | | game_loop(Arc::clone(&room_ref)) LL | | }); | |_____^ may outlive borrowed value `room_ref` | -note: function requires argument type to outlive `'static` - --> $DIR/issue-78938-async-block.rs:8:33 - | -LL | let gameloop_handle = spawn(async { - | _________________________________^ -LL | | game_loop(Arc::clone(&room_ref)) -LL | | }); - | |_____^ - = note: borrows cannot be held across a yield point, because the stack space of the current function is not preserved + = note: async blocks are not executed immediately and either must take a reference or ownership of outside variables they use = help: see https://rust-lang.github.io/async-book/03_async_await/01_chapter.html#awaiting-on-a-multithreaded-executor for more information help: to force the async block to take ownership of `room_ref` (and any other referenced variables), use the `move` keyword | From 757bd23503e16311190c943efba093d70d6b3454 Mon Sep 17 00:00:00 2001 From: 1000teslas <47207223+1000teslas@users.noreply.github.com> Date: Sat, 9 Jan 2021 20:02:47 +1100 Subject: [PATCH 14/43] Remove trailing whitespace --- .../src/borrow_check/diagnostics/conflict_errors.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs index 85ea70cefba..49cdf8c3cbe 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs @@ -1331,11 +1331,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } ConstraintCategory::CallArgument => { fr_name.highlight_region_name(&mut err); - if matches!(use_span.generator_kind(), Some(generator_kind) + if matches!(use_span.generator_kind(), Some(generator_kind) if matches!(generator_kind, GeneratorKind::Async(_))) { - err.note("async blocks are not executed immediately and either must take a \ - reference or ownership of outside variables they use"); + err.note( + "async blocks are not executed immediately and either must take a \ + reference or ownership of outside variables they use", + ); err.help("see https://rust-lang.github.io/async-book/03_async_await/01_chapter.html#awaiting-on-a-multithreaded-executor \ for more information"); } else { From b5b6760c03867e2b16862324b4764cf35be8a1cd Mon Sep 17 00:00:00 2001 From: CAD97 Date: Sun, 10 Jan 2021 23:27:32 -0500 Subject: [PATCH 15/43] Weak::into_raw shouldn't translate sentinel value --- library/alloc/src/rc.rs | 27 ++++++++++++--------------- library/alloc/src/sync.rs | 21 +++++++++------------ 2 files changed, 21 insertions(+), 27 deletions(-) diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index b9f3f357c1a..43affa396c9 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -848,7 +848,7 @@ impl Rc { pub fn downgrade(this: &Self) -> Weak { this.inner().inc_weak(); // Make sure we do not create a dangling Weak - debug_assert!(!is_dangling(this.ptr)); + debug_assert!(!is_dangling(this.ptr.as_ptr())); Weak { ptr: this.ptr } } @@ -1837,8 +1837,8 @@ impl Weak { } } -pub(crate) fn is_dangling(ptr: NonNull) -> bool { - let address = ptr.as_ptr() as *mut () as usize; +pub(crate) fn is_dangling(ptr: *mut T) -> bool { + let address = ptr as *mut () as usize; address == usize::MAX } @@ -1879,17 +1879,15 @@ impl Weak { pub fn as_ptr(&self) -> *const T { let ptr: *mut RcBox = NonNull::as_ptr(self.ptr); - if is_dangling(self.ptr) { - // If the pointer is dangling, we return a null pointer as the dangling sentinel. - // We can't return the usize::MAX sentinel, as that could valid if T is ZST. - // SAFETY: we have to return a known sentinel here that cannot be produced for - // a valid pointer, so that `from_raw` can reverse this transformation. - (ptr as *mut T).set_ptr_value(ptr::null_mut()) + if is_dangling(ptr) { + // If the pointer is dangling, we return the sentinel directly. This cannot be + // a valid payload address, as it is at least as aligned as RcBox (usize). + ptr as *const T } else { // SAFETY: if is_dangling returns false, then the pointer is dereferencable. // The payload may be dropped at this point, and we have to maintain provenance, // so use raw pointer manipulation. - unsafe { &raw mut (*ptr).value } + unsafe { &raw const (*ptr).value } } } @@ -1973,10 +1971,9 @@ impl Weak { pub unsafe fn from_raw(ptr: *const T) -> Self { // See Weak::as_ptr for context on how the input pointer is derived. - let ptr = if ptr.is_null() { - // If we get a null pointer, this is a dangling weak. - // SAFETY: this is the same sentinel as used in Weak::new and is_dangling - (ptr as *mut RcBox).set_ptr_value(usize::MAX as *mut _) + let ptr = if is_dangling(ptr as *mut T) { + // This is a dangling Weak. + ptr as *mut RcBox } else { // Otherwise, we're guaranteed the pointer came from a nondangling Weak. // SAFETY: data_offset is safe to call, as ptr references a real (potentially dropped) T. @@ -2052,7 +2049,7 @@ impl Weak { /// (i.e., when this `Weak` was created by `Weak::new`). #[inline] fn inner(&self) -> Option> { - if is_dangling(self.ptr) { + if is_dangling(self.ptr.as_ptr()) { None } else { // We are careful to *not* create a reference covering the "data" field, as diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index c50f5270a4d..8917e2d4b40 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -885,7 +885,7 @@ impl Arc { match this.inner().weak.compare_exchange_weak(cur, cur + 1, Acquire, Relaxed) { Ok(_) => { // Make sure we do not create a dangling Weak - debug_assert!(!is_dangling(this.ptr)); + debug_assert!(!is_dangling(this.ptr.as_ptr())); return Weak { ptr: this.ptr }; } Err(old) => cur = old, @@ -1664,12 +1664,10 @@ impl Weak { pub fn as_ptr(&self) -> *const T { let ptr: *mut ArcInner = NonNull::as_ptr(self.ptr); - if is_dangling(self.ptr) { - // If the pointer is dangling, we return a null pointer as the dangling sentinel. - // We can't return the usize::MAX sentinel, as that could valid if T is ZST. - // SAFETY: we have to return a known sentinel here that cannot be produced for - // a valid pointer, so that `from_raw` can reverse this transformation. - (ptr as *mut T).set_ptr_value(ptr::null_mut()) + if is_dangling(ptr) { + // If the pointer is dangling, we return the sentinel directly. This cannot be + // a valid payload address, as it is at least as aligned as ArcInner (usize). + ptr as *const T } else { // SAFETY: if is_dangling returns false, then the pointer is dereferencable. // The payload may be dropped at this point, and we have to maintain provenance, @@ -1758,10 +1756,9 @@ impl Weak { pub unsafe fn from_raw(ptr: *const T) -> Self { // See Weak::as_ptr for context on how the input pointer is derived. - let ptr = if ptr.is_null() { - // If we get a null pointer, this is a dangling weak. - // SAFETY: this is the same sentinel as used in Weak::new and is_dangling - (ptr as *mut ArcInner).set_ptr_value(usize::MAX as *mut _) + let ptr = if is_dangling(ptr as *mut T) { + // This is a dangling Weak. + ptr as *mut ArcInner } else { // Otherwise, we're guaranteed the pointer came from a nondangling Weak. // SAFETY: data_offset is safe to call, as ptr references a real (potentially dropped) T. @@ -1877,7 +1874,7 @@ impl Weak { /// (i.e., when this `Weak` was created by `Weak::new`). #[inline] fn inner(&self) -> Option> { - if is_dangling(self.ptr) { + if is_dangling(self.ptr.as_ptr()) { None } else { // We are careful to *not* create a reference covering the "data" field, as From 04b60362f8eafdcd62acc2232e9ba0459d5acb5d Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Sun, 10 Jan 2021 23:01:49 -0500 Subject: [PATCH 16/43] Make `--color always` apply to logging too --- src/bootstrap/builder.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index ec9ce4c820c..62065e27dd9 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -814,12 +814,22 @@ impl<'a> Builder<'a> { cargo.env("REAL_LIBRARY_PATH", e); } + // Found with `rg "init_env_logger\("`. If anyone uses `init_env_logger` + // from out of tree it shouldn't matter, since x.py is only used for + // building in-tree. + let color_logs = ["RUSTDOC_LOG_COLOR", "RUSTC_LOG_COLOR", "RUST_LOG_COLOR"]; match self.build.config.color { Color::Always => { cargo.arg("--color=always"); + for log in &color_logs { + cargo.env(log, "always"); + } } Color::Never => { cargo.arg("--color=never"); + for log in &color_logs { + cargo.env(log, "never"); + } } Color::Auto => {} // nothing to do } From 3ee3071344334a0ac9defe876d6781d2d9658933 Mon Sep 17 00:00:00 2001 From: 1000teslas <47207223+1000teslas@users.noreply.github.com> Date: Tue, 12 Jan 2021 14:12:12 +1100 Subject: [PATCH 17/43] Update src/test/ui/async-await/issues/issue-78938-async-block.stderr Co-authored-by: Esteban Kuber --- src/test/ui/async-await/issues/issue-78938-async-block.stderr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/ui/async-await/issues/issue-78938-async-block.stderr b/src/test/ui/async-await/issues/issue-78938-async-block.stderr index 4468975b2f5..5450038c0d9 100644 --- a/src/test/ui/async-await/issues/issue-78938-async-block.stderr +++ b/src/test/ui/async-await/issues/issue-78938-async-block.stderr @@ -8,7 +8,7 @@ LL | | game_loop(Arc::clone(&room_ref)) LL | | }); | |_____^ may outlive borrowed value `room_ref` | - = note: async blocks are not executed immediately and either must take a reference or ownership of outside variables they use + = note: async blocks are not executed immediately and must either take a reference or ownership of outside variables they use = help: see https://rust-lang.github.io/async-book/03_async_await/01_chapter.html#awaiting-on-a-multithreaded-executor for more information help: to force the async block to take ownership of `room_ref` (and any other referenced variables), use the `move` keyword | From 4362da13b128e897712140b3c11397e871e5b2fc Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Tue, 12 Jan 2021 17:31:13 +0900 Subject: [PATCH 18/43] Do not suggest invalid code in pattern with loop --- .../borrow_check/diagnostics/conflict_errors.rs | 5 ++++- .../ui/borrowck/move-in-pattern-mut-in-loop.rs | 10 ++++++++++ .../borrowck/move-in-pattern-mut-in-loop.stderr | 15 +++++++++++++++ 3 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/borrowck/move-in-pattern-mut-in-loop.rs create mode 100644 src/test/ui/borrowck/move-in-pattern-mut-in-loop.stderr diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs index db02ee67910..c745601c336 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs @@ -141,6 +141,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { self.add_moved_or_invoked_closure_note(location, used_place, &mut err); let mut is_loop_move = false; + let mut in_pattern = false; for move_site in &move_site_vec { let move_out = self.move_data.moves[(*move_site).moi]; @@ -256,6 +257,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { "ref ".to_string(), Applicability::MachineApplicable, ); + in_pattern = true; } if let Some(DesugaringKind::ForLoop(_)) = move_span.desugaring_kind() { @@ -302,7 +304,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let place = &self.move_data.move_paths[mpi].place; let ty = place.ty(self.body, self.infcx.tcx).ty; - if is_loop_move { + // If we're in pattern, we do nothing in favor of the previous suggestion (#80913). + if is_loop_move & !in_pattern { if let ty::Ref(_, _, hir::Mutability::Mut) = ty.kind() { // We have a `&mut` ref, we need to reborrow on each iteration (#62112). err.span_suggestion_verbose( diff --git a/src/test/ui/borrowck/move-in-pattern-mut-in-loop.rs b/src/test/ui/borrowck/move-in-pattern-mut-in-loop.rs new file mode 100644 index 00000000000..4b42f9d4cd5 --- /dev/null +++ b/src/test/ui/borrowck/move-in-pattern-mut-in-loop.rs @@ -0,0 +1,10 @@ +// Regression test for #80913. + +fn main() { + let mut x = 42_i32; + let mut opt = Some(&mut x); + for _ in 0..5 { + if let Some(mut _x) = opt {} + //~^ ERROR: use of moved value + } +} diff --git a/src/test/ui/borrowck/move-in-pattern-mut-in-loop.stderr b/src/test/ui/borrowck/move-in-pattern-mut-in-loop.stderr new file mode 100644 index 00000000000..9373e4d95fc --- /dev/null +++ b/src/test/ui/borrowck/move-in-pattern-mut-in-loop.stderr @@ -0,0 +1,15 @@ +error[E0382]: use of moved value + --> $DIR/move-in-pattern-mut-in-loop.rs:7:21 + | +LL | if let Some(mut _x) = opt {} + | ^^^^^^ value moved here, in previous iteration of loop + | + = note: move occurs because value has type `&mut i32`, which does not implement the `Copy` trait +help: borrow this field in the pattern to avoid moving `opt.0` + | +LL | if let Some(ref mut _x) = opt {} + | ^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0382`. From b2f504801c5c7cadc1e5f0c950ec11cef7c1a3ef Mon Sep 17 00:00:00 2001 From: Ashley Mannix Date: Wed, 13 Jan 2021 14:51:27 +1000 Subject: [PATCH 19/43] stabilize the poll_map feature --- library/core/src/task/poll.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/core/src/task/poll.rs b/library/core/src/task/poll.rs index 6851f3fcd2f..42c9d9f0cc0 100644 --- a/library/core/src/task/poll.rs +++ b/library/core/src/task/poll.rs @@ -84,7 +84,7 @@ impl Poll> { impl Poll>> { /// Changes the success value of this `Poll` with the closure provided. - #[unstable(feature = "poll_map", issue = "63514")] + #[stable(feature = "poll_map", since = "1.51.0")] pub fn map_ok(self, f: F) -> Poll>> where F: FnOnce(T) -> U, @@ -98,7 +98,7 @@ impl Poll>> { } /// Changes the error value of this `Poll` with the closure provided. - #[unstable(feature = "poll_map", issue = "63514")] + #[stable(feature = "poll_map", since = "1.51.0")] pub fn map_err(self, f: F) -> Poll>> where F: FnOnce(E) -> U, From c20003627453df608b2c6929a1b2ab1c316389a9 Mon Sep 17 00:00:00 2001 From: Camelid Date: Tue, 12 Jan 2021 20:57:57 -0800 Subject: [PATCH 20/43] Put all feature gate tests under `feature-gates/` There was one directory that had only a single test and there was also a test in the top-level directory. This moves both of them to `feature-gates/`. --- .../feature-gate-const_refs_to_cell.rs | 0 .../ui/{ => feature-gates}/feature-gate-edition_macro_pats.rs | 0 .../ui/{ => feature-gates}/feature-gate-edition_macro_pats.stderr | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename src/test/ui/{feature-gate => feature-gates}/feature-gate-const_refs_to_cell.rs (100%) rename src/test/ui/{ => feature-gates}/feature-gate-edition_macro_pats.rs (100%) rename src/test/ui/{ => feature-gates}/feature-gate-edition_macro_pats.stderr (100%) diff --git a/src/test/ui/feature-gate/feature-gate-const_refs_to_cell.rs b/src/test/ui/feature-gates/feature-gate-const_refs_to_cell.rs similarity index 100% rename from src/test/ui/feature-gate/feature-gate-const_refs_to_cell.rs rename to src/test/ui/feature-gates/feature-gate-const_refs_to_cell.rs diff --git a/src/test/ui/feature-gate-edition_macro_pats.rs b/src/test/ui/feature-gates/feature-gate-edition_macro_pats.rs similarity index 100% rename from src/test/ui/feature-gate-edition_macro_pats.rs rename to src/test/ui/feature-gates/feature-gate-edition_macro_pats.rs diff --git a/src/test/ui/feature-gate-edition_macro_pats.stderr b/src/test/ui/feature-gates/feature-gate-edition_macro_pats.stderr similarity index 100% rename from src/test/ui/feature-gate-edition_macro_pats.stderr rename to src/test/ui/feature-gates/feature-gate-edition_macro_pats.stderr From 7f41465f6d025445374626c14958f8181a54c639 Mon Sep 17 00:00:00 2001 From: 1000teslas <47207223+1000teslas@users.noreply.github.com> Date: Wed, 13 Jan 2021 23:37:49 +1100 Subject: [PATCH 21/43] Move help link to error index --- .../src/error_codes/E0373.md | 22 +++++++++++++++++++ .../diagnostics/conflict_errors.rs | 4 +--- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_error_codes/src/error_codes/E0373.md b/compiler/rustc_error_codes/src/error_codes/E0373.md index fd969877931..1dec705260a 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0373.md +++ b/compiler/rustc_error_codes/src/error_codes/E0373.md @@ -50,3 +50,25 @@ fn foo() -> Box u32> { Now that the closure has its own copy of the data, there's no need to worry about safety. + +This error may also be encountered while using `async` blocks: + +```compile_fail,E0373 +use std::sync::Arc; +use tokio::runtime::Runtime; // 0.3.1 + +async fn f() { + let room_ref = Arc::new(Vec::new()); + + let gameloop_handle = Runtime::new().unwrap().spawn(async { + game_loop(Arc::clone(&room_ref)) + }); + gameloop_handle.await; +} + +fn game_loop(v: Arc>) {} +``` + +Similarly to closures, `async` blocks are not executed immediately and may +capture closed-over data by reference. For more information, see +https://rust-lang.github.io/async-book/03_async_await/01_chapter.html. \ No newline at end of file diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs index 49cdf8c3cbe..fb817d3ca1e 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs @@ -1335,11 +1335,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { if matches!(generator_kind, GeneratorKind::Async(_))) { err.note( - "async blocks are not executed immediately and either must take a \ + "async blocks are not executed immediately and must either take a \ reference or ownership of outside variables they use", ); - err.help("see https://rust-lang.github.io/async-book/03_async_await/01_chapter.html#awaiting-on-a-multithreaded-executor \ - for more information"); } else { let msg = format!("function requires argument type to outlive `{}`", fr_name); err.span_note(constraint_span, &msg); From f5c428799f42a34cc22621cc865fba787a32b405 Mon Sep 17 00:00:00 2001 From: 1000teslas <47207223+1000teslas@users.noreply.github.com> Date: Thu, 14 Jan 2021 01:02:49 +1100 Subject: [PATCH 22/43] Bless test output --- src/test/ui/async-await/issues/issue-78938-async-block.stderr | 1 - 1 file changed, 1 deletion(-) diff --git a/src/test/ui/async-await/issues/issue-78938-async-block.stderr b/src/test/ui/async-await/issues/issue-78938-async-block.stderr index 5450038c0d9..01ffc48d654 100644 --- a/src/test/ui/async-await/issues/issue-78938-async-block.stderr +++ b/src/test/ui/async-await/issues/issue-78938-async-block.stderr @@ -9,7 +9,6 @@ LL | | }); | |_____^ may outlive borrowed value `room_ref` | = note: async blocks are not executed immediately and must either take a reference or ownership of outside variables they use - = help: see https://rust-lang.github.io/async-book/03_async_await/01_chapter.html#awaiting-on-a-multithreaded-executor for more information help: to force the async block to take ownership of `room_ref` (and any other referenced variables), use the `move` keyword | LL | let gameloop_handle = spawn(async move { From a9ead34371e92767f0dfcf0d6d347a65988420af Mon Sep 17 00:00:00 2001 From: 1000teslas <47207223+1000teslas@users.noreply.github.com> Date: Thu, 14 Jan 2021 01:21:27 +1100 Subject: [PATCH 23/43] Fix whitespace --- compiler/rustc_error_codes/src/error_codes/E0373.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_error_codes/src/error_codes/E0373.md b/compiler/rustc_error_codes/src/error_codes/E0373.md index 1dec705260a..8da16eb6e52 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0373.md +++ b/compiler/rustc_error_codes/src/error_codes/E0373.md @@ -70,5 +70,5 @@ fn game_loop(v: Arc>) {} ``` Similarly to closures, `async` blocks are not executed immediately and may -capture closed-over data by reference. For more information, see -https://rust-lang.github.io/async-book/03_async_await/01_chapter.html. \ No newline at end of file +capture closed-over data by reference. For more information, see +https://rust-lang.github.io/async-book/03_async_await/01_chapter.html. From c14e919f1e221dd0629bd88db6db77c52e03604e Mon Sep 17 00:00:00 2001 From: Christopher Durham Date: Wed, 13 Jan 2021 17:21:23 -0500 Subject: [PATCH 24/43] Apply suggestions from code review Co-authored-by: Ralf Jung --- library/alloc/src/rc.rs | 2 +- library/alloc/src/sync.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 43affa396c9..3ca10480b34 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -1881,7 +1881,7 @@ impl Weak { if is_dangling(ptr) { // If the pointer is dangling, we return the sentinel directly. This cannot be - // a valid payload address, as it is at least as aligned as RcBox (usize). + // a valid payload address, as the payload is at least as aligned as RcBox (usize). ptr as *const T } else { // SAFETY: if is_dangling returns false, then the pointer is dereferencable. diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 8917e2d4b40..306c0c91e4b 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -1666,7 +1666,7 @@ impl Weak { if is_dangling(ptr) { // If the pointer is dangling, we return the sentinel directly. This cannot be - // a valid payload address, as it is at least as aligned as ArcInner (usize). + // a valid payload address, as the payload is at least as aligned as ArcInner (usize). ptr as *const T } else { // SAFETY: if is_dangling returns false, then the pointer is dereferencable. From 174135fb3b212f53c4b24ffb243398306b9146d0 Mon Sep 17 00:00:00 2001 From: 1000teslas <47207223+1000teslas@users.noreply.github.com> Date: Thu, 14 Jan 2021 17:15:04 +1100 Subject: [PATCH 25/43] Fix error E0373 documentation --- .../src/error_codes/E0373.md | 30 ++++++++++++++----- .../issues/issue-78938-async-block.rs | 2 +- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_error_codes/src/error_codes/E0373.md b/compiler/rustc_error_codes/src/error_codes/E0373.md index 8da16eb6e52..0723897614f 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0373.md +++ b/compiler/rustc_error_codes/src/error_codes/E0373.md @@ -54,19 +54,35 @@ about safety. This error may also be encountered while using `async` blocks: ```compile_fail,E0373 -use std::sync::Arc; -use tokio::runtime::Runtime; // 0.3.1 +use std::{sync::Arc, future::Future, pin::Pin, task::{Context, Poll}}; async fn f() { - let room_ref = Arc::new(Vec::new()); + let v = Arc::new(Vec::new()); - let gameloop_handle = Runtime::new().unwrap().spawn(async { - game_loop(Arc::clone(&room_ref)) + let handle = spawn(async { //~ ERROR E0373 + g(Arc::clone(&v)) }); - gameloop_handle.await; + handle.await; } -fn game_loop(v: Arc>) {} +fn g(v: Arc>) {} + +fn spawn(future: F) -> JoinHandle +where + F: Future + Send + 'static, + F::Output: Send + 'static, +{ + unimplemented!() +} + +struct JoinHandle; + +impl Future for JoinHandle { + type Output = (); + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + unimplemented!() + } +} ``` Similarly to closures, `async` blocks are not executed immediately and may diff --git a/src/test/ui/async-await/issues/issue-78938-async-block.rs b/src/test/ui/async-await/issues/issue-78938-async-block.rs index 86afef08fc7..36f71601985 100644 --- a/src/test/ui/async-await/issues/issue-78938-async-block.rs +++ b/src/test/ui/async-await/issues/issue-78938-async-block.rs @@ -1,6 +1,6 @@ // edition:2018 -use std::{sync::Arc, future::Future, pin::Pin, task::{Context,Poll}}; +use std::{sync::Arc, future::Future, pin::Pin, task::{Context, Poll}}; async fn f() { let room_ref = Arc::new(Vec::new()); From 63deae5e2525ab7428b205d13953423a6cd91bdd Mon Sep 17 00:00:00 2001 From: 1000teslas <47207223+1000teslas@users.noreply.github.com> Date: Thu, 14 Jan 2021 21:52:38 +1100 Subject: [PATCH 26/43] Fix E0373 code example --- compiler/rustc_error_codes/src/error_codes/E0373.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_error_codes/src/error_codes/E0373.md b/compiler/rustc_error_codes/src/error_codes/E0373.md index 0723897614f..540a88a0d95 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0373.md +++ b/compiler/rustc_error_codes/src/error_codes/E0373.md @@ -53,7 +53,7 @@ about safety. This error may also be encountered while using `async` blocks: -```compile_fail,E0373 +```compile_fail,E0373,edition2018 use std::{sync::Arc, future::Future, pin::Pin, task::{Context, Poll}}; async fn f() { From 5468d9805aba869e7712b5aadabb021e692ba1d0 Mon Sep 17 00:00:00 2001 From: 1000teslas <47207223+1000teslas@users.noreply.github.com> Date: Fri, 15 Jan 2021 16:50:48 +1100 Subject: [PATCH 27/43] Simplify E0373 async code example --- .../src/error_codes/E0373.md | 27 ++++--------------- 1 file changed, 5 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_error_codes/src/error_codes/E0373.md b/compiler/rustc_error_codes/src/error_codes/E0373.md index 540a88a0d95..effa597aad9 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0373.md +++ b/compiler/rustc_error_codes/src/error_codes/E0373.md @@ -54,35 +54,18 @@ about safety. This error may also be encountered while using `async` blocks: ```compile_fail,E0373,edition2018 -use std::{sync::Arc, future::Future, pin::Pin, task::{Context, Poll}}; +use std::future::Future; async fn f() { - let v = Arc::new(Vec::new()); - - let handle = spawn(async { //~ ERROR E0373 - g(Arc::clone(&v)) + let v = vec![1, 2, 3i32]; + spawn(async { //~ ERROR E0373 + println!("{:?}", v) }); - handle.await; } -fn g(v: Arc>) {} - -fn spawn(future: F) -> JoinHandle -where - F: Future + Send + 'static, - F::Output: Send + 'static, -{ +fn spawn(future: F) { unimplemented!() } - -struct JoinHandle; - -impl Future for JoinHandle { - type Output = (); - fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - unimplemented!() - } -} ``` Similarly to closures, `async` blocks are not executed immediately and may From 0660b8b5a592a004557147ebe128d5d8fd024cc5 Mon Sep 17 00:00:00 2001 From: John-John Tedro Date: Wed, 28 Oct 2020 00:15:36 +0100 Subject: [PATCH 28/43] Introduce {Ref, RefMut}::try_map for optional projections --- library/core/src/cell.rs | 70 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index c5ab7a39ff0..af421cb00f0 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -1261,6 +1261,36 @@ impl<'b, T: ?Sized> Ref<'b, T> { Ref { value: f(orig.value), borrow: orig.borrow } } + /// Makes a new `Ref` for an optional component of the borrowed data. + /// + /// The `RefCell` is already immutably borrowed, so this cannot fail. + /// + /// This is an associated function that needs to be used as + /// `Ref::try_map(...)`. A method would interfere with methods of the same + /// name on the contents of a `RefCell` used through `Deref`. + /// + /// # Examples + /// + /// ``` + /// #![feature(cell_try_map)] + /// + /// use std::cell::{RefCell, Ref}; + /// + /// let c = RefCell::new(vec![1, 2, 3]); + /// let b1: Ref> = c.borrow(); + /// let b2: Option> = Ref::try_map(b1, |v| v.get(1)); + /// assert_eq!(b2.as_deref(), Some(&2)) + /// ``` + #[unstable(feature = "cell_try_map", reason = "recently added", issue = "none")] + #[inline] + pub fn try_map(orig: Ref<'b, T>, f: F) -> Option> + where + F: FnOnce(&T) -> Option<&U>, + { + let value = f(orig.value)?; + Some(Ref { value, borrow: orig.borrow }) + } + /// Splits a `Ref` into multiple `Ref`s for different components of the /// borrowed data. /// @@ -1372,6 +1402,46 @@ impl<'b, T: ?Sized> RefMut<'b, T> { RefMut { value: f(value), borrow } } + /// Makes a new `RefMut` for an optional component of the borrowed data. + /// + /// The `RefCell` is already mutably borrowed, so this cannot fail. + /// + /// This is an associated function that needs to be used as + /// `RefMut::try_map(...)`. A method would interfere with methods of the + /// same name on the contents of a `RefCell` used through `Deref`. + /// + /// # Examples + /// + /// ``` + /// #![feature(cell_try_map)] + /// + /// use std::cell::{RefCell, RefMut}; + /// + /// let c = RefCell::new(vec![1, 2, 3]); + /// + /// { + /// let b1: RefMut> = c.borrow_mut(); + /// let mut b2: Option> = RefMut::try_map(b1, |v| v.get_mut(1)); + /// + /// if let Some(mut b2) = b2 { + /// *b2 += 2; + /// } + /// } + /// + /// assert_eq!(*c.borrow(), vec![1, 4, 3]); + /// ``` + #[unstable(feature = "cell_try_map", reason = "recently added", issue = "none")] + #[inline] + pub fn try_map(orig: RefMut<'b, T>, f: F) -> Option> + where + F: FnOnce(&mut T) -> Option<&mut U>, + { + // FIXME(nll-rfc#40): fix borrow-check + let RefMut { value, borrow } = orig; + let value = f(value)?; + Some(RefMut { value, borrow }) + } + /// Splits a `RefMut` into multiple `RefMut`s for different components of the /// borrowed data. /// From 3e9c95b9d44aba57ee70a596b73af514046b4b26 Mon Sep 17 00:00:00 2001 From: 1000teslas <47207223+1000teslas@users.noreply.github.com> Date: Sat, 16 Jan 2021 03:32:54 +1100 Subject: [PATCH 29/43] Update compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs Co-authored-by: Esteban Kuber --- .../rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs index fb817d3ca1e..9325f94393f 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs @@ -1331,9 +1331,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } ConstraintCategory::CallArgument => { fr_name.highlight_region_name(&mut err); - if matches!(use_span.generator_kind(), Some(generator_kind) - if matches!(generator_kind, GeneratorKind::Async(_))) - { + if matches!(use_span.generator_kind(), Some(GeneratorKind::Async(_))) { err.note( "async blocks are not executed immediately and must either take a \ reference or ownership of outside variables they use", From e8757af311601681f8002b699ab0d64838e75eab Mon Sep 17 00:00:00 2001 From: John-John Tedro Date: Thu, 17 Dec 2020 01:46:06 +0100 Subject: [PATCH 30/43] Use Result and rename to filter_map The use of Result allows for making use of a reconstructed original value on failed projections. --- library/core/src/cell.rs | 52 ++++++++++++++++++++++++++-------------- 1 file changed, 34 insertions(+), 18 deletions(-) diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index af421cb00f0..c0a0e2f618f 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -1261,34 +1261,38 @@ impl<'b, T: ?Sized> Ref<'b, T> { Ref { value: f(orig.value), borrow: orig.borrow } } - /// Makes a new `Ref` for an optional component of the borrowed data. + /// Makes a new `Ref` for an optional component of the borrowed data. The + /// original guard is returned as an `Err(..)` if the closure returns + /// `None`. /// /// The `RefCell` is already immutably borrowed, so this cannot fail. /// /// This is an associated function that needs to be used as - /// `Ref::try_map(...)`. A method would interfere with methods of the same + /// `Ref::filter_map(...)`. A method would interfere with methods of the same /// name on the contents of a `RefCell` used through `Deref`. /// /// # Examples /// /// ``` - /// #![feature(cell_try_map)] + /// #![feature(cell_filter_map)] /// /// use std::cell::{RefCell, Ref}; /// /// let c = RefCell::new(vec![1, 2, 3]); /// let b1: Ref> = c.borrow(); - /// let b2: Option> = Ref::try_map(b1, |v| v.get(1)); - /// assert_eq!(b2.as_deref(), Some(&2)) + /// let b2: Result, _> = Ref::filter_map(b1, |v| v.get(1)); + /// assert_eq!(*b2.unwrap(), 2); /// ``` - #[unstable(feature = "cell_try_map", reason = "recently added", issue = "none")] + #[unstable(feature = "cell_filter_map", reason = "recently added", issue = "none")] #[inline] - pub fn try_map(orig: Ref<'b, T>, f: F) -> Option> + pub fn filter_map(orig: Ref<'b, T>, f: F) -> Result, Self> where F: FnOnce(&T) -> Option<&U>, { - let value = f(orig.value)?; - Some(Ref { value, borrow: orig.borrow }) + match f(orig.value) { + Some(value) => Ok(Ref { value, borrow: orig.borrow }), + None => Err(orig), + } } /// Splits a `Ref` into multiple `Ref`s for different components of the @@ -1402,18 +1406,20 @@ impl<'b, T: ?Sized> RefMut<'b, T> { RefMut { value: f(value), borrow } } - /// Makes a new `RefMut` for an optional component of the borrowed data. + /// Makes a new `RefMut` for an optional component of the borrowed data. The + /// original guard is returned as an `Err(..)` if the closure returns + /// `None`. /// /// The `RefCell` is already mutably borrowed, so this cannot fail. /// /// This is an associated function that needs to be used as - /// `RefMut::try_map(...)`. A method would interfere with methods of the + /// `RefMut::filter_map(...)`. A method would interfere with methods of the /// same name on the contents of a `RefCell` used through `Deref`. /// /// # Examples /// /// ``` - /// #![feature(cell_try_map)] + /// #![feature(cell_filter_map)] /// /// use std::cell::{RefCell, RefMut}; /// @@ -1421,25 +1427,35 @@ impl<'b, T: ?Sized> RefMut<'b, T> { /// /// { /// let b1: RefMut> = c.borrow_mut(); - /// let mut b2: Option> = RefMut::try_map(b1, |v| v.get_mut(1)); + /// let mut b2: Result, _> = RefMut::filter_map(b1, |v| v.get_mut(1)); /// - /// if let Some(mut b2) = b2 { + /// if let Ok(mut b2) = b2 { /// *b2 += 2; /// } /// } /// /// assert_eq!(*c.borrow(), vec![1, 4, 3]); /// ``` - #[unstable(feature = "cell_try_map", reason = "recently added", issue = "none")] + #[unstable(feature = "cell_filter_map", reason = "recently added", issue = "none")] #[inline] - pub fn try_map(orig: RefMut<'b, T>, f: F) -> Option> + pub fn filter_map(orig: RefMut<'b, T>, f: F) -> Result, Self> where F: FnOnce(&mut T) -> Option<&mut U>, { // FIXME(nll-rfc#40): fix borrow-check let RefMut { value, borrow } = orig; - let value = f(value)?; - Some(RefMut { value, borrow }) + let value = value as *mut T; + // SAFETY: function holds onto an exclusive reference for the duration + // of its call through `orig`, and the pointer is only de-referenced + // inside of the function call never allowing the exclusive reference to + // escape. + match f(unsafe { &mut *value }) { + Some(value) => Ok(RefMut { value, borrow }), + None => { + // SAFETY: same as above. + Err(RefMut { value: unsafe { &mut *value }, borrow }) + } + } } /// Splits a `RefMut` into multiple `RefMut`s for different components of the From e3274fd148273796e93c142d8cef28acc3af0b60 Mon Sep 17 00:00:00 2001 From: Rune Tynan Date: Thu, 14 Jan 2021 14:49:58 -0500 Subject: [PATCH 31/43] Remove doctree::Import --- src/librustdoc/clean/mod.rs | 198 ++++++++++++++++++------------------ src/librustdoc/doctree.rs | 14 --- src/librustdoc/visit_ast.rs | 10 +- 3 files changed, 99 insertions(+), 123 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 5ec79c586dc..0aabd9477e3 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -219,7 +219,6 @@ impl Clean for CrateNum { impl Clean for doctree::Module<'_> { fn clean(&self, cx: &DocContext<'_>) -> Item { let mut items: Vec = vec![]; - items.extend(self.imports.iter().flat_map(|x| x.clean(cx))); items.extend(self.foreigns.iter().map(|x| x.clean(cx))); items.extend(self.mods.iter().map(|x| x.clean(cx))); items.extend(self.items.iter().map(|x| x.clean(cx)).flatten()); @@ -2019,7 +2018,7 @@ impl Clean> for (&hir::Item<'_>, Option) { ItemKind::Fn(ref sig, ref generics, body_id) => { clean_fn_or_proc_macro(item, sig, generics, body_id, &mut name, cx) } - hir::ItemKind::Trait(is_auto, unsafety, ref generics, ref bounds, ref item_ids) => { + ItemKind::Trait(is_auto, unsafety, ref generics, ref bounds, ref item_ids) => { let items = item_ids .iter() .map(|ti| cx.tcx.hir().trait_item(ti.id).clean(cx)) @@ -2038,6 +2037,9 @@ impl Clean> for (&hir::Item<'_>, Option) { ItemKind::ExternCrate(orig_name) => { return clean_extern_crate(item, name, orig_name, cx); } + ItemKind::Use(path, kind) => { + return clean_use_statement(item, name, path, kind, cx); + } _ => unreachable!("not yet converted"), }; @@ -2159,105 +2161,101 @@ fn clean_extern_crate( }] } -impl Clean> for doctree::Import<'_> { - fn clean(&self, cx: &DocContext<'_>) -> Vec { - // We need this comparison because some imports (for std types for example) - // are "inserted" as well but directly by the compiler and they should not be - // taken into account. - if self.span.ctxt().outer_expn_data().kind == ExpnKind::AstPass(AstPass::StdImports) { - return Vec::new(); - } - - let (doc_meta_item, please_inline) = self.attrs.lists(sym::doc).get_word_attr(sym::inline); - let pub_underscore = self.vis.node.is_pub() && self.name == kw::Underscore; - - if pub_underscore && please_inline { - rustc_errors::struct_span_err!( - cx.tcx.sess, - doc_meta_item.unwrap().span(), - E0780, - "anonymous imports cannot be inlined" - ) - .span_label(self.span, "anonymous import") - .emit(); - } - - // We consider inlining the documentation of `pub use` statements, but we - // forcefully don't inline if this is not public or if the - // #[doc(no_inline)] attribute is present. - // Don't inline doc(hidden) imports so they can be stripped at a later stage. - let mut denied = !self.vis.node.is_pub() - || pub_underscore - || self.attrs.iter().any(|a| { - a.has_name(sym::doc) - && match a.meta_item_list() { - Some(l) => { - attr::list_contains_name(&l, sym::no_inline) - || attr::list_contains_name(&l, sym::hidden) - } - None => false, - } - }); - // Also check whether imports were asked to be inlined, in case we're trying to re-export a - // crate in Rust 2018+ - let path = self.path.clean(cx); - let inner = if self.glob { - if !denied { - let mut visited = FxHashSet::default(); - if let Some(items) = inline::try_inline_glob(cx, path.res, &mut visited) { - return items; - } - } - Import::new_glob(resolve_use_source(cx, path), true) - } else { - let name = self.name; - if !please_inline { - if let Res::Def(DefKind::Mod, did) = path.res { - if !did.is_local() && did.index == CRATE_DEF_INDEX { - // if we're `pub use`ing an extern crate root, don't inline it unless we - // were specifically asked for it - denied = true; - } - } - } - if !denied { - let mut visited = FxHashSet::default(); - - if let Some(mut items) = inline::try_inline( - cx, - cx.tcx.parent_module(self.id).to_def_id(), - path.res, - name, - Some(self.attrs), - &mut visited, - ) { - items.push(Item { - name: None, - attrs: box self.attrs.clean(cx), - source: self.span.clean(cx), - def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(), - visibility: self.vis.clean(cx), - kind: box ImportItem(Import::new_simple( - self.name, - resolve_use_source(cx, path), - false, - )), - }); - return items; - } - } - Import::new_simple(name, resolve_use_source(cx, path), true) - }; - - vec![Item { - name: None, - attrs: box self.attrs.clean(cx), - source: self.span.clean(cx), - def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(), - visibility: self.vis.clean(cx), - kind: box ImportItem(inner), - }] +fn clean_use_statement( + import: &hir::Item<'_>, + name: Symbol, + path: &hir::Path<'_>, + kind: hir::UseKind, + cx: &DocContext<'_>, +) -> Vec { + // We need this comparison because some imports (for std types for example) + // are "inserted" as well but directly by the compiler and they should not be + // taken into account. + if import.span.ctxt().outer_expn_data().kind == ExpnKind::AstPass(AstPass::StdImports) { + return Vec::new(); } + + let (doc_meta_item, please_inline) = import.attrs.lists(sym::doc).get_word_attr(sym::inline); + let pub_underscore = import.vis.node.is_pub() && name == kw::Underscore; + + if pub_underscore && please_inline { + rustc_errors::struct_span_err!( + cx.tcx.sess, + doc_meta_item.unwrap().span(), + E0780, + "anonymous imports cannot be inlined" + ) + .span_label(import.span, "anonymous import") + .emit(); + } + + // We consider inlining the documentation of `pub use` statements, but we + // forcefully don't inline if this is not public or if the + // #[doc(no_inline)] attribute is present. + // Don't inline doc(hidden) imports so they can be stripped at a later stage. + let mut denied = !import.vis.node.is_pub() + || pub_underscore + || import.attrs.iter().any(|a| { + a.has_name(sym::doc) + && match a.meta_item_list() { + Some(l) => { + attr::list_contains_name(&l, sym::no_inline) + || attr::list_contains_name(&l, sym::hidden) + } + None => false, + } + }); + + // Also check whether imports were asked to be inlined, in case we're trying to re-export a + // crate in Rust 2018+ + let path = path.clean(cx); + let inner = if kind == hir::UseKind::Glob { + if !denied { + let mut visited = FxHashSet::default(); + if let Some(items) = inline::try_inline_glob(cx, path.res, &mut visited) { + return items; + } + } + Import::new_glob(resolve_use_source(cx, path), true) + } else { + if !please_inline { + if let Res::Def(DefKind::Mod, did) = path.res { + if !did.is_local() && did.index == CRATE_DEF_INDEX { + // if we're `pub use`ing an extern crate root, don't inline it unless we + // were specifically asked for it + denied = true; + } + } + } + if !denied { + let mut visited = FxHashSet::default(); + + if let Some(mut items) = inline::try_inline( + cx, + cx.tcx.parent_module(import.hir_id).to_def_id(), + path.res, + name, + Some(import.attrs), + &mut visited, + ) { + items.push(Item::from_def_id_and_parts( + cx.tcx.hir().local_def_id(import.hir_id).to_def_id(), + None, + ImportItem(Import::new_simple(name, resolve_use_source(cx, path), false)), + cx, + )); + return items; + } + } + Import::new_simple(name, resolve_use_source(cx, path), true) + }; + + vec![Item::from_def_id_and_parts( + cx.tcx.hir().local_def_id(import.hir_id).to_def_id(), + None, + ImportItem(inner), + cx, + )] } impl Clean for (&hir::ForeignItem<'_>, Option) { diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs index 4710c91f929..f90623c0311 100644 --- a/src/librustdoc/doctree.rs +++ b/src/librustdoc/doctree.rs @@ -2,7 +2,6 @@ //! manner (and with prettier names) before cleaning. crate use self::StructType::*; -use rustc_ast as ast; use rustc_span::{self, Span, Symbol}; use rustc_hir as hir; @@ -11,7 +10,6 @@ crate struct Module<'hir> { crate name: Option, crate where_outer: Span, crate where_inner: Span, - crate imports: Vec>, crate mods: Vec>, crate id: hir::HirId, // (item, renamed) @@ -28,7 +26,6 @@ impl Module<'hir> { id: hir::CRATE_HIR_ID, where_outer: rustc_span::DUMMY_SP, where_inner: rustc_span::DUMMY_SP, - imports: Vec::new(), mods: Vec::new(), items: Vec::new(), foreigns: Vec::new(), @@ -48,17 +45,6 @@ crate enum StructType { Unit, } -#[derive(Debug)] -crate struct Import<'hir> { - crate name: Symbol, - crate id: hir::HirId, - crate vis: &'hir hir::Visibility<'hir>, - crate attrs: &'hir [ast::Attribute], - crate path: &'hir hir::Path<'hir>, - crate glob: bool, - crate span: Span, -} - crate fn struct_type_from_def(vdata: &hir::VariantData<'_>) -> StructType { match *vdata { hir::VariantData::Struct(..) => Plain, diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index f701352c486..7d161ca3648 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -316,15 +316,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { } } - om.imports.push(Import { - name, - id: item.hir_id, - vis: &item.vis, - attrs: &item.attrs, - path, - glob: is_glob, - span: item.span, - }); + om.items.push((item, renamed)) } hir::ItemKind::Mod(ref m) => { om.mods.push(self.visit_mod_contents( From 2a0c9e28cb5136c72753c93752c18ee64abc8a88 Mon Sep 17 00:00:00 2001 From: Rune Tynan Date: Thu, 14 Jan 2021 15:03:17 -0500 Subject: [PATCH 32/43] Address nit --- src/librustdoc/clean/mod.rs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 0aabd9477e3..e2cc7547781 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2208,6 +2208,7 @@ fn clean_use_statement( // Also check whether imports were asked to be inlined, in case we're trying to re-export a // crate in Rust 2018+ + let def_id = cx.tcx.hir().local_def_id(import.hir_id).to_def_id(); let path = path.clean(cx); let inner = if kind == hir::UseKind::Glob { if !denied { @@ -2239,7 +2240,7 @@ fn clean_use_statement( &mut visited, ) { items.push(Item::from_def_id_and_parts( - cx.tcx.hir().local_def_id(import.hir_id).to_def_id(), + def_id, None, ImportItem(Import::new_simple(name, resolve_use_source(cx, path), false)), cx, @@ -2250,12 +2251,7 @@ fn clean_use_statement( Import::new_simple(name, resolve_use_source(cx, path), true) }; - vec![Item::from_def_id_and_parts( - cx.tcx.hir().local_def_id(import.hir_id).to_def_id(), - None, - ImportItem(inner), - cx, - )] + vec![Item::from_def_id_and_parts(def_id, None, ImportItem(inner), cx)] } impl Clean for (&hir::ForeignItem<'_>, Option) { From e42c1b9c2acb218217c02ee25514b39a1b4efb62 Mon Sep 17 00:00:00 2001 From: Rune Tynan Date: Thu, 14 Jan 2021 19:01:48 -0500 Subject: [PATCH 33/43] Fix JSON test --- src/test/rustdoc-json/nested.expected | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/rustdoc-json/nested.expected b/src/test/rustdoc-json/nested.expected index 65bb0c5fa03..80070e75f1e 100644 --- a/src/test/rustdoc-json/nested.expected +++ b/src/test/rustdoc-json/nested.expected @@ -41,8 +41,8 @@ "inner": { "is_crate": false, "items": [ - "0:7", - "0:4" + "0:4", + "0:7" ] }, "kind": "module", From 31b17f513b79e7213f16c8acdcc38a5b9018d8a4 Mon Sep 17 00:00:00 2001 From: Rune Tynan Date: Thu, 14 Jan 2021 19:39:59 -0500 Subject: [PATCH 34/43] Add warning to compare.py about error messages --- src/test/rustdoc-json/compare.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/test/rustdoc-json/compare.py b/src/test/rustdoc-json/compare.py index b0c5b16a197..6a921266336 100644 --- a/src/test/rustdoc-json/compare.py +++ b/src/test/rustdoc-json/compare.py @@ -7,6 +7,9 @@ # and then create `yourtest.expected` by stripping unnecessary details from `yourtest.json`. If # you're on windows, replace `\` with `/`. +# WARNING: The error messages produced by this may be misleading, in the case of list re-ordering +# it may point to apparently unrelated keys. + import copy import sys import json From af0d099004e1b1ffe19109fba5813aebfd435437 Mon Sep 17 00:00:00 2001 From: Simonas Kazlauskas Date: Thu, 14 Jan 2021 20:10:13 +0200 Subject: [PATCH 35/43] Add a regression test for #50041 AFAICT the test case never landed alongside the fix for the issue. --- .../ui/mir/ssa-analysis-regression-50041.rs | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 src/test/ui/mir/ssa-analysis-regression-50041.rs diff --git a/src/test/ui/mir/ssa-analysis-regression-50041.rs b/src/test/ui/mir/ssa-analysis-regression-50041.rs new file mode 100644 index 00000000000..c818f2976e1 --- /dev/null +++ b/src/test/ui/mir/ssa-analysis-regression-50041.rs @@ -0,0 +1,34 @@ +// build-pass +// compile-flags: -Z mir-opt-level=3 + +#![crate_type="lib"] +#![feature(lang_items)] +#![no_std] + +#[lang = "owned_box"] +pub struct Box(*mut T); + +impl Drop for Box { + fn drop(&mut self) { + } +} + +#[lang = "box_free"] +#[inline(always)] +unsafe fn box_free(ptr: *mut T) { + dealloc(ptr) +} + +#[inline(never)] +fn dealloc(_: *mut T) { +} + +pub struct Foo(T); + +pub fn foo(a: Option>>) -> usize { + let f = match a { + None => Foo(0), + Some(vec) => *vec, + }; + f.0 +} From c625b979aed9ad3c8380ea2239d9345d4cec695a Mon Sep 17 00:00:00 2001 From: Ashley Mannix Date: Sat, 16 Jan 2021 10:40:36 +1000 Subject: [PATCH 36/43] add tracking issue to cell_filter_map --- library/core/src/cell.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index c0a0e2f618f..fa0fbaa35c9 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -1283,7 +1283,7 @@ impl<'b, T: ?Sized> Ref<'b, T> { /// let b2: Result, _> = Ref::filter_map(b1, |v| v.get(1)); /// assert_eq!(*b2.unwrap(), 2); /// ``` - #[unstable(feature = "cell_filter_map", reason = "recently added", issue = "none")] + #[unstable(feature = "cell_filter_map", reason = "recently added", issue = "81061")] #[inline] pub fn filter_map(orig: Ref<'b, T>, f: F) -> Result, Self> where @@ -1436,7 +1436,7 @@ impl<'b, T: ?Sized> RefMut<'b, T> { /// /// assert_eq!(*c.borrow(), vec![1, 4, 3]); /// ``` - #[unstable(feature = "cell_filter_map", reason = "recently added", issue = "none")] + #[unstable(feature = "cell_filter_map", reason = "recently added", issue = "81061")] #[inline] pub fn filter_map(orig: RefMut<'b, T>, f: F) -> Result, Self> where From eef383fa00be7565123f62e2dddd325e10e3ec21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96mer=20Sinan=20A=C4=9Facan?= Date: Fri, 15 Jan 2021 15:51:32 +0300 Subject: [PATCH 37/43] doctest: Reset errors before dropping the parse session The first parse is to collect whether the code contains macros, has `main`, and uses other crates. In that pass we ignore errors as those will be reported when the test file is actually built. For that we need to reset errors in the `Diagnostic` otherwise when dropping it unhandled errors will be reported as compiler bugs. Fixes #80992 --- src/librustdoc/doctest.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index cf51162cfb5..3de97f2dd2e 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -500,6 +500,12 @@ crate fn make_test( } } + // Reset errors so that they won't be reported as compiler bugs when dropping the + // handler. Any errors in the tests will be reported when the test file is compiled, + // Note that we still need to cancel the errors above otherwise `DiagnosticBuilder` + // will panic on drop. + sess.span_diagnostic.reset_err_count(); + (found_main, found_extern_crate, found_macro) }) }); From 0ef55570fb35a79a32bc062c0a441c02952fd65e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96mer=20Sinan=20A=C4=9Facan?= Date: Sat, 16 Jan 2021 06:55:16 +0300 Subject: [PATCH 38/43] Add a test --- src/test/rustdoc-ui/issue-80992.rs | 11 +++++++++++ src/test/rustdoc-ui/issue-80992.stdout | 6 ++++++ 2 files changed, 17 insertions(+) create mode 100644 src/test/rustdoc-ui/issue-80992.rs create mode 100644 src/test/rustdoc-ui/issue-80992.stdout diff --git a/src/test/rustdoc-ui/issue-80992.rs b/src/test/rustdoc-ui/issue-80992.rs new file mode 100644 index 00000000000..8983439bb64 --- /dev/null +++ b/src/test/rustdoc-ui/issue-80992.rs @@ -0,0 +1,11 @@ +// check-pass +// compile-flags:--test +// normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR" +// normalize-stdout-test "finished in \d+\.\d+s" -> "finished in $$TIME" + +pub fn test() -> Result<(), ()> { + //! ```compile_fail + //! fn test() -> Result< {} + //! ``` + Ok(()) +} diff --git a/src/test/rustdoc-ui/issue-80992.stdout b/src/test/rustdoc-ui/issue-80992.stdout new file mode 100644 index 00000000000..1dd19f46827 --- /dev/null +++ b/src/test/rustdoc-ui/issue-80992.stdout @@ -0,0 +1,6 @@ + +running 1 test +test $DIR/issue-80992.rs - test (line 7) ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + From b681631eff8d842c9b5f1e9d7fcf5d8259a02a0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96mer=20Sinan=20A=C4=9Facan?= Date: Sat, 16 Jan 2021 07:17:13 +0300 Subject: [PATCH 39/43] codegen_cranelift: Fix redundant semicolon warn --- compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs index be5b247bb9f..8946ac43bc6 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs @@ -824,7 +824,7 @@ pub(crate) fn codegen_intrinsic_call<'tcx>( } ty => unreachable!("bswap {}", ty), } - }; + } let res = CValue::by_val(swap(&mut fx.bcx, arg), fx.layout_of(T)); ret.write_cvalue(fx, res); }; From 8797986391022adf98bde252002dcfc9eaaef975 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Mon, 11 Jan 2021 13:20:18 +0900 Subject: [PATCH 40/43] Add a regression test for #76281 This has been fixed between 1.47.0-nightly (663d2f5cd 2020-08-22) and 1.47.0-nightly (5180f3da5 2020-08-23). --- src/test/ui/wasm/wasm-hang-issue-76281.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 src/test/ui/wasm/wasm-hang-issue-76281.rs diff --git a/src/test/ui/wasm/wasm-hang-issue-76281.rs b/src/test/ui/wasm/wasm-hang-issue-76281.rs new file mode 100644 index 00000000000..a4adfa6d044 --- /dev/null +++ b/src/test/ui/wasm/wasm-hang-issue-76281.rs @@ -0,0 +1,12 @@ +// only-wasm32 +// compile-flags: -C opt-level=2 +// build-pass + +// Regression test for #76281. +// This seems like an issue related to LLVM rather than +// libs-impl so place here. + +fn main() { + let mut v: Vec<&()> = Vec::new(); + v.sort_by_key(|&r| r as *const ()); +} From 9952632a2f6fc0d5c41976070ba39f57be5ede0c Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Sat, 16 Jan 2021 10:29:21 +0100 Subject: [PATCH 41/43] Add sample code for Rc::new_cyclic --- library/alloc/src/rc.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 0973a6e362b..d6f48238900 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -353,6 +353,26 @@ impl Rc { /// to upgrade the weak reference before this function returns will result /// in a `None` value. However, the weak reference may be cloned freely and /// stored for use at a later time. + /// + /// # Examples + /// + /// ``` + /// #![feature(arc_new_cyclic)] + /// #![allow(dead_code)] + /// use std::rc::{Rc, Weak}; + /// + /// struct Gadget { + /// self_weak: Weak, + /// // ... more fields + /// } + /// impl Gadget { + /// pub fn new() -> Rc { + /// Rc::new_cyclic(|self_weak| { + /// Gadget { self_weak: self_weak.clone(), /* ... */ } + /// }) + /// } + /// } + /// ``` #[unstable(feature = "arc_new_cyclic", issue = "75861")] pub fn new_cyclic(data_fn: impl FnOnce(&Weak) -> T) -> Rc { // Construct the inner in the "uninitialized" state with a single From 78d919280d36652c1ca069cb3f6713d38e64e823 Mon Sep 17 00:00:00 2001 From: Chris Jefferson Date: Mon, 4 Jan 2021 09:22:56 +0000 Subject: [PATCH 42/43] Clarify what the effects of a 'logic error' are --- library/alloc/src/collections/binary_heap.rs | 5 ++++- library/alloc/src/collections/btree/map.rs | 3 +++ library/alloc/src/collections/btree/set.rs | 3 +++ library/std/src/collections/hash/map.rs | 3 +++ library/std/src/collections/hash/set.rs | 4 +++- 5 files changed, 16 insertions(+), 2 deletions(-) diff --git a/library/alloc/src/collections/binary_heap.rs b/library/alloc/src/collections/binary_heap.rs index 76051d9e1df..c63e79745f1 100644 --- a/library/alloc/src/collections/binary_heap.rs +++ b/library/alloc/src/collections/binary_heap.rs @@ -161,7 +161,10 @@ use super::SpecExtend; /// It is a logic error for an item to be modified in such a way that the /// item's ordering relative to any other item, as determined by the `Ord` /// trait, changes while it is in the heap. This is normally only possible -/// through `Cell`, `RefCell`, global state, I/O, or unsafe code. +/// through `Cell`, `RefCell`, global state, I/O, or unsafe code. The +/// behavior resulting from such a logic error is not specified, but will +/// not result in undefined behavior. This could include panics, incorrect +/// results, aborts, memory leaks, and non-termination. /// /// # Examples /// diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index 944e0e65cf7..5e63a303d22 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -51,6 +51,9 @@ pub(super) const MIN_LEN: usize = node::MIN_LEN_AFTER_SPLIT; /// It is a logic error for a key to be modified in such a way that the key's ordering relative to /// any other key, as determined by the [`Ord`] trait, changes while it is in the map. This is /// normally only possible through [`Cell`], [`RefCell`], global state, I/O, or unsafe code. +/// The behavior resulting from such a logic error is not specified, but will not result in +/// undefined behavior. This could include panics, incorrect results, aborts, memory leaks, and +/// non-termination. /// /// [`Cell`]: core::cell::Cell /// [`RefCell`]: core::cell::RefCell diff --git a/library/alloc/src/collections/btree/set.rs b/library/alloc/src/collections/btree/set.rs index c72e305a1f9..c2a96dd8ef4 100644 --- a/library/alloc/src/collections/btree/set.rs +++ b/library/alloc/src/collections/btree/set.rs @@ -22,6 +22,9 @@ use super::Recover; /// It is a logic error for an item to be modified in such a way that the item's ordering relative /// to any other item, as determined by the [`Ord`] trait, changes while it is in the set. This is /// normally only possible through [`Cell`], [`RefCell`], global state, I/O, or unsafe code. +/// The behavior resulting from such a logic error is not specified, but will not result in +/// undefined behavior. This could include panics, incorrect results, aborts, memory leaks, and +/// non-termination. /// /// [`Ord`]: core::cmp::Ord /// [`Cell`]: core::cell::Cell diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index 0680b1fc329..829fc3817af 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -52,6 +52,9 @@ use crate::sys; /// hash, as determined by the [`Hash`] trait, or its equality, as determined by /// the [`Eq`] trait, changes while it is in the map. This is normally only /// possible through [`Cell`], [`RefCell`], global state, I/O, or unsafe code. +/// The behavior resulting from such a logic error is not specified, but will +/// not result in undefined behavior. This could include panics, incorrect results, +/// aborts, memory leaks, and non-termination. /// /// The hash table implementation is a Rust port of Google's [SwissTable]. /// The original C++ version of SwissTable can be found [here], and this diff --git a/library/std/src/collections/hash/set.rs b/library/std/src/collections/hash/set.rs index f49e5801c35..baa3026ff75 100644 --- a/library/std/src/collections/hash/set.rs +++ b/library/std/src/collections/hash/set.rs @@ -37,7 +37,9 @@ use super::map::{map_try_reserve_error, RandomState}; /// item's hash, as determined by the [`Hash`] trait, or its equality, as /// determined by the [`Eq`] trait, changes while it is in the set. This is /// normally only possible through [`Cell`], [`RefCell`], global state, I/O, or -/// unsafe code. +/// unsafe code. The behavior resulting from such a logic error is not +/// specified, but will not result in undefined behavior. This could include +/// panics, incorrect results, aborts, memory leaks, and non-termination. /// /// # Examples /// From bdc7ff79969550e7d1bf6a2ccddce3a83903316e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1niel=20Buga?= Date: Sat, 16 Jan 2021 16:41:53 +0100 Subject: [PATCH 43/43] Add test for #34792 --- .../associated-item-two-bounds.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 src/test/ui/associated-item/associated-item-two-bounds.rs diff --git a/src/test/ui/associated-item/associated-item-two-bounds.rs b/src/test/ui/associated-item/associated-item-two-bounds.rs new file mode 100644 index 00000000000..25b0d5a56bf --- /dev/null +++ b/src/test/ui/associated-item/associated-item-two-bounds.rs @@ -0,0 +1,16 @@ +// This test is a regression test for #34792 + +// check-pass + +pub struct A; +pub struct B; + +pub trait Foo { + type T: PartialEq + PartialEq; +} + +pub fn generic(t: F::T, a: A, b: B) -> bool { + t == a && t == b +} + +pub fn main() {}