Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions compiler/rustc_feature/src/accepted.rs
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,8 @@ declare_features! (
(accepted, extended_key_value_attributes, "1.54.0", Some(78835), None),
/// Allows unsizing coercions in `const fn`.
(accepted, const_fn_unsize, "1.54.0", Some(64992), None),
/// Allows `impl Trait` with multiple unrelated lifetimes.
(accepted, member_constraints, "1.54.0", Some(61997), None),

// -------------------------------------------------------------------------
// feature-group-end: accepted features
Expand Down
3 changes: 0 additions & 3 deletions compiler/rustc_feature/src/active.rs
Original file line number Diff line number Diff line change
Expand Up @@ -472,9 +472,6 @@ declare_features! (
/// Allows explicit discriminants on non-unit enum variants.
(active, arbitrary_enum_discriminant, "1.37.0", Some(60553), None),

/// Allows `impl Trait` with multiple unrelated lifetimes.
(active, member_constraints, "1.37.0", Some(61997), None),

/// Allows `async || body` closures.
(active, async_closure, "1.37.0", Some(62290), None),

Expand Down
66 changes: 0 additions & 66 deletions compiler/rustc_trait_selection/src/opaque_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -140,15 +140,6 @@ pub trait InferCtxtExt<'tcx> {
first_own_region_index: usize,
);

/*private*/
fn member_constraint_feature_gate(
&self,
opaque_defn: &OpaqueTypeDecl<'tcx>,
opaque_type_def_id: DefId,
conflict1: ty::Region<'tcx>,
conflict2: ty::Region<'tcx>,
) -> bool;

fn infer_opaque_definition_from_instantiation(
&self,
def_id: DefId,
Expand Down Expand Up @@ -490,9 +481,6 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
// ['a, 'b, 'c]`, where `'a..'c` are the
// regions that appear in the impl trait.

// For now, enforce a feature gate outside of async functions.
self.member_constraint_feature_gate(opaque_defn, def_id, lr, subst_region);

return self.generate_member_constraint(
concrete_ty,
opaque_defn,
Expand Down Expand Up @@ -559,60 +547,6 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
});
}

/// Member constraints are presently feature-gated except for
/// async-await. We expect to lift this once we've had a bit more
/// time.
fn member_constraint_feature_gate(
&self,
opaque_defn: &OpaqueTypeDecl<'tcx>,
opaque_type_def_id: DefId,
conflict1: ty::Region<'tcx>,
conflict2: ty::Region<'tcx>,
) -> bool {
// If we have `#![feature(member_constraints)]`, no problems.
if self.tcx.features().member_constraints {
return false;
}

let span = self.tcx.def_span(opaque_type_def_id);

// Without a feature-gate, we only generate member-constraints for async-await.
let context_name = match opaque_defn.origin {
// No feature-gate required for `async fn`.
hir::OpaqueTyOrigin::AsyncFn => return false,

// Otherwise, generate the label we'll use in the error message.
hir::OpaqueTyOrigin::Binding
| hir::OpaqueTyOrigin::FnReturn
| hir::OpaqueTyOrigin::TyAlias
| hir::OpaqueTyOrigin::Misc => "impl Trait",
};
let msg = format!("ambiguous lifetime bound in `{}`", context_name);
let mut err = self.tcx.sess.struct_span_err(span, &msg);

let conflict1_name = conflict1.to_string();
let conflict2_name = conflict2.to_string();
let label_owned;
let label = match (&*conflict1_name, &*conflict2_name) {
("'_", "'_") => "the elided lifetimes here do not outlive one another",
_ => {
label_owned = format!(
"neither `{}` nor `{}` outlives the other",
conflict1_name, conflict2_name,
);
&label_owned
}
};
err.span_label(span, label);

if self.tcx.sess.is_nightly_build() {
err.help("add #![feature(member_constraints)] to the crate attributes to enable");
}

err.emit();
true
}

/// Given the fully resolved, instantiated type for an opaque
/// type, i.e., the value of an inference variable like C1 or C2
/// (*), computes the "definition type" for an opaque type
Expand Down
14 changes: 13 additions & 1 deletion library/alloc/src/rc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1859,6 +1859,18 @@ where
B: ToOwned + ?Sized,
Rc<B>: From<&'a B> + From<B::Owned>,
{
/// Create a reference-counted pointer from
/// a clone-on-write pointer by copying its content.
///
/// # Example
///
/// ```rust
/// # use std::rc::Rc;
/// # use std::borrow::Cow;
/// let cow: Cow<str> = Cow::Borrowed("eggplant");
/// let shared: Rc<str> = Rc::from(cow);
/// assert_eq!("eggplant", &shared[..]);
/// ```
#[inline]
fn from(cow: Cow<'a, B>) -> Rc<B> {
match cow {
Expand Down Expand Up @@ -2303,7 +2315,7 @@ impl<T: ?Sized> Weak<T> {
}

#[stable(feature = "rc_weak", since = "1.4.0")]
impl<T: ?Sized> Drop for Weak<T> {
unsafe impl<#[may_dangle] T: ?Sized> Drop for Weak<T> {
/// Drops the `Weak` pointer.
///
/// # Examples
Expand Down
14 changes: 13 additions & 1 deletion library/alloc/src/sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2015,7 +2015,7 @@ impl<T> Default for Weak<T> {
}

#[stable(feature = "arc_weak", since = "1.4.0")]
impl<T: ?Sized> Drop for Weak<T> {
unsafe impl<#[may_dangle] T: ?Sized> Drop for Weak<T> {
/// Drops the `Weak` pointer.
///
/// # Examples
Expand Down Expand Up @@ -2413,6 +2413,18 @@ where
B: ToOwned + ?Sized,
Arc<B>: From<&'a B> + From<B::Owned>,
{
/// Create an atomically reference-counted pointer from
/// a clone-on-write pointer by copying its content.
///
/// # Example
///
/// ```rust
/// # use std::sync::Arc;
/// # use std::borrow::Cow;
/// let cow: Cow<str> = Cow::Borrowed("eggplant");
/// let shared: Arc<str> = Arc::from(cow);
/// assert_eq!("eggplant", &shared[..]);
/// ```
#[inline]
fn from(cow: Cow<'a, B>) -> Arc<B> {
match cow {
Expand Down
15 changes: 15 additions & 0 deletions library/alloc/tests/arc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -195,3 +195,18 @@ fn shared_from_iter_trustedlen_no_fuse() {
assert_trusted_len(&iter);
assert_eq!(&[Box::new(42), Box::new(24)], &*iter.collect::<Rc<[_]>>());
}

#[test]
fn weak_may_dangle() {
fn hmm<'a>(val: &'a mut Weak<&'a str>) -> Weak<&'a str> {
val.clone()
}

// Without #[may_dangle] we get:
let mut val = Weak::new();
hmm(&mut val);
// ~~~~~~~~ borrowed value does not live long enough
//
// `val` dropped here while still borrowed
// borrow might be used here, when `val` is dropped and runs the `Drop` code for type `std::sync::Weak`
}
15 changes: 15 additions & 0 deletions library/alloc/tests/rc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -191,3 +191,18 @@ fn shared_from_iter_trustedlen_no_fuse() {
assert_trusted_len(&iter);
assert_eq!(&[Box::new(42), Box::new(24)], &*iter.collect::<Rc<[_]>>());
}

#[test]
fn weak_may_dangle() {
fn hmm<'a>(val: &'a mut Weak<&'a str>) -> Weak<&'a str> {
val.clone()
}

// Without #[may_dangle] we get:
let mut val = Weak::new();
hmm(&mut val);
// ~~~~~~~~ borrowed value does not live long enough
//
// `val` dropped here while still borrowed
// borrow might be used here, when `val` is dropped and runs the `Drop` code for type `std::rc::Weak`
}
15 changes: 7 additions & 8 deletions library/core/src/ops/control_flow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -187,42 +187,41 @@ impl<B, C> ControlFlow<B, C> {
#[cfg(bootstrap)]
impl<R: ops::TryV1> ControlFlow<R, R::Output> {
/// Create a `ControlFlow` from any type implementing `Try`.
#[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
#[inline]
pub fn from_try(r: R) -> Self {
pub(crate) fn from_try(r: R) -> Self {
match R::into_result(r) {
Ok(v) => ControlFlow::Continue(v),
Err(v) => ControlFlow::Break(R::from_error(v)),
}
}

/// Convert a `ControlFlow` into any type implementing `Try`;
#[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
#[inline]
pub fn into_try(self) -> R {
pub(crate) fn into_try(self) -> R {
match self {
ControlFlow::Continue(v) => R::from_ok(v),
ControlFlow::Break(v) => v,
}
}
}

/// These are used only as part of implementing the iterator adapters.
/// They have mediocre names and non-obvious semantics, so aren't
/// currently on a path to potential stabilization.
#[cfg(not(bootstrap))]
impl<R: ops::TryV2> ControlFlow<R, R::Output> {
/// Create a `ControlFlow` from any type implementing `Try`.
#[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
#[inline]
pub fn from_try(r: R) -> Self {
pub(crate) fn from_try(r: R) -> Self {
match R::branch(r) {
ControlFlow::Continue(v) => ControlFlow::Continue(v),
ControlFlow::Break(v) => ControlFlow::Break(R::from_residual(v)),
}
}

/// Convert a `ControlFlow` into any type implementing `Try`;
#[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")]
#[inline]
pub fn into_try(self) -> R {
pub(crate) fn into_try(self) -> R {
match self {
ControlFlow::Continue(v) => R::from_output(v),
ControlFlow::Break(v) => v,
Expand Down
6 changes: 5 additions & 1 deletion library/core/src/slice/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3096,7 +3096,11 @@ impl<T> [T] {
// SAFETY: the conditions for `ptr::copy` have all been checked above,
// as have those for `ptr::add`.
unsafe {
ptr::copy(self.as_ptr().add(src_start), self.as_mut_ptr().add(dest), count);
// Derive both `src_ptr` and `dest_ptr` from the same loan
let ptr = self.as_mut_ptr();
let src_ptr = ptr.add(src_start);
let dest_ptr = ptr.add(dest);
ptr::copy(src_ptr, dest_ptr, count);
}
}

Expand Down
10 changes: 8 additions & 2 deletions library/std/src/sync/mutex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -294,8 +294,14 @@ impl<T: ?Sized> Mutex<T> {
/// # Errors
///
/// If another user of this mutex panicked while holding the mutex, then
/// this call will return an error if the mutex would otherwise be
/// acquired.
/// this call will return the [`Poisoned`] error if the mutex would
/// otherwise be acquired.
///
/// If the mutex could not be acquired because it is already locked, then
/// this call will return the [`WouldBlock`] error.
///
/// [`Poisoned`]: TryLockError::Poisoned
/// [`WouldBlock`]: TryLockError::WouldBlock
///
/// # Examples
///
Expand Down
27 changes: 20 additions & 7 deletions library/std/src/sync/rwlock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -199,11 +199,17 @@ impl<T: ?Sized> RwLock<T> {
///
/// # Errors
///
/// This function will return an error if the RwLock is poisoned. An RwLock
/// is poisoned whenever a writer panics while holding an exclusive lock. An
/// error will only be returned if the lock would have otherwise been
/// This function will return the [`Poisoned`] error if the RwLock is poisoned.
/// An RwLock is poisoned whenever a writer panics while holding an exclusive
/// lock. `Poisoned` will only be returned if the lock would have otherwise been
/// acquired.
///
/// This function will return the [`WouldBlock`] error if the RwLock could not
/// be acquired because it was already locked exclusively.
///
/// [`Poisoned`]: TryLockError::Poisoned
/// [`WouldBlock`]: TryLockError::WouldBlock
///
/// # Examples
///
/// ```
Expand Down Expand Up @@ -281,10 +287,17 @@ impl<T: ?Sized> RwLock<T> {
///
/// # Errors
///
/// This function will return an error if the RwLock is poisoned. An RwLock
/// is poisoned whenever a writer panics while holding an exclusive lock. An
/// error will only be returned if the lock would have otherwise been
/// acquired.
/// This function will return the [`Poisoned`] error if the RwLock is
/// poisoned. An RwLock is poisoned whenever a writer panics while holding
/// an exclusive lock. `Poisoned` will only be returned if the lock would have
/// otherwise been acquired.
///
/// This function will return the [`WouldBlock`] error if the RwLock could not
/// be acquired because it was already locked exclusively.
///
/// [`Poisoned`]: TryLockError::Poisoned
/// [`WouldBlock`]: TryLockError::WouldBlock
///
///
/// # Examples
///
Expand Down
16 changes: 12 additions & 4 deletions src/bootstrap/bootstrap.py
Original file line number Diff line number Diff line change
Expand Up @@ -991,20 +991,28 @@ def update_submodules(self):
).decode(default_encoding).splitlines()]
filtered_submodules = []
submodules_names = []
llvm_checked_out = os.path.exists(os.path.join(self.rust_root, "src/llvm-project/.git"))
external_llvm_provided = self.get_toml('llvm-config') or self.downloading_llvm()
llvm_needed = not self.get_toml('codegen-backends', 'rust') \
or "llvm" in self.get_toml('codegen-backends', 'rust')
for module in submodules:
# This is handled by native::Llvm in rustbuild, not here
if module.endswith("llvm-project"):
continue
# Don't sync the llvm-project submodule if an external LLVM was
# provided, if we are downloading LLVM or if the LLVM backend is
# not being built. Also, if the submodule has been initialized
# already, sync it anyways so that it doesn't mess up contributor
# pull requests.
if external_llvm_provided or not llvm_needed:
if self.get_toml('lld') != 'true' and not llvm_checked_out:
continue
check = self.check_submodule(module, slow_submodules)
filtered_submodules.append((module, check))
submodules_names.append(module)
recorded = subprocess.Popen(["git", "ls-tree", "HEAD"] + submodules_names,
cwd=self.rust_root, stdout=subprocess.PIPE)
recorded = recorded.communicate()[0].decode(default_encoding).strip().splitlines()
# { filename: hash }
recorded_submodules = {}
for data in recorded:
# [mode, kind, hash, filename]
data = data.split()
recorded_submodules[data[3]] = data[2]
for module in filtered_submodules:
Expand Down
10 changes: 0 additions & 10 deletions src/bootstrap/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -472,22 +472,12 @@ impl Build {
slice::from_ref(&self.build.triple)
}

/// If the LLVM submodule has been initialized already, sync it unconditionally. This avoids
/// contributors checking in a submodule change by accident.
pub fn maybe_update_llvm_submodule(&self) {
if self.in_tree_llvm_info.is_git() {
native::update_llvm_submodule(self);
}
}

/// Executes the entire build, as configured by the flags and configuration.
pub fn build(&mut self) {
unsafe {
job::setup(self);
}

self.maybe_update_llvm_submodule();

if let Subcommand::Format { check, paths } = &self.config.cmd {
return format::format(self, *check, &paths);
}
Expand Down
Loading