Skip to content

Rollup of 5 pull requests #106809

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 14 commits into from
Closed
Changes from all commits
Commits
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
148 changes: 144 additions & 4 deletions compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
Original file line number Diff line number Diff line change
@@ -6,6 +6,7 @@ use rustc_errors::{
struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan,
};
use rustc_hir as hir;
use rustc_hir::def::Res;
use rustc_hir::intravisit::{walk_block, walk_expr, Visitor};
use rustc_hir::{AsyncGeneratorKind, GeneratorKind, LangItem};
use rustc_infer::infer::TyCtxtInferExt;
@@ -20,7 +21,7 @@ use rustc_middle::ty::{self, suggest_constraining_type_params, PredicateKind, Ty
use rustc_mir_dataflow::move_paths::{InitKind, MoveOutIndex, MovePathIndex};
use rustc_span::def_id::LocalDefId;
use rustc_span::hygiene::DesugaringKind;
use rustc_span::symbol::sym;
use rustc_span::symbol::{kw, sym};
use rustc_span::{BytePos, Span, Symbol};
use rustc_trait_selection::infer::InferCtxtExt;

@@ -29,6 +30,7 @@ use crate::borrowck_errors;

use crate::diagnostics::conflict_errors::StorageDeadOrDrop::LocalStorageDead;
use crate::diagnostics::find_all_local_uses;
use crate::diagnostics::mutability_errors::mut_borrow_of_mutable_ref;
use crate::{
borrow_set::BorrowData, diagnostics::Instance, prefixes::IsPrefixOf,
InitializationRequiringAction, MirBorrowckCtxt, PrefixSet, WriteKind,
@@ -356,7 +358,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
if let Some(hir::Node::Item(hir::Item {
kind: hir::ItemKind::Fn(_, _, body_id),
..
})) = hir.find(hir.local_def_id_to_hir_id(self.mir_def_id()))
})) = hir.find(self.mir_hir_id())
&& let Some(hir::Node::Expr(expr)) = hir.find(body_id.hir_id)
{
let place = &self.move_data.move_paths[mpi].place;
@@ -948,7 +950,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
}
(BorrowKind::Mut { .. }, BorrowKind::Shared) => {
first_borrow_desc = "immutable ";
self.cannot_reborrow_already_borrowed(
let mut err = self.cannot_reborrow_already_borrowed(
span,
&desc_place,
&msg_place,
@@ -958,7 +960,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
"immutable",
&msg_borrow,
None,
)
);
self.suggest_binding_for_closure_capture_self(
&mut err,
issued_borrow.borrowed_place,
&issued_spans,
);
err
}

(BorrowKind::Mut { .. }, BorrowKind::Mut { .. }) => {
@@ -1240,6 +1248,138 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
}
}

fn suggest_binding_for_closure_capture_self(
&self,
err: &mut Diagnostic,
borrowed_place: Place<'tcx>,
issued_spans: &UseSpans<'tcx>,
) {
let UseSpans::ClosureUse { capture_kind_span, .. } = issued_spans else { return };
let hir = self.infcx.tcx.hir();

// check whether the borrowed place is capturing `self` by mut reference
let local = borrowed_place.local;
let Some(_) = self
.body
.local_decls
.get(local)
.map(|l| mut_borrow_of_mutable_ref(l, self.local_names[local])) else { return };

struct ExpressionFinder<'hir> {
capture_span: Span,
closure_change_spans: Vec<Span>,
closure_arg_span: Option<Span>,
in_closure: bool,
suggest_arg: String,
hir: rustc_middle::hir::map::Map<'hir>,
closure_local_id: Option<hir::HirId>,
closure_call_changes: Vec<(Span, String)>,
}
impl<'hir> Visitor<'hir> for ExpressionFinder<'hir> {
fn visit_expr(&mut self, e: &'hir hir::Expr<'hir>) {
if e.span.contains(self.capture_span) {
if let hir::ExprKind::Closure(&hir::Closure {
movability: None,
body,
fn_arg_span,
fn_decl: hir::FnDecl{ inputs, .. },
..
}) = e.kind &&
let Some(hir::Node::Expr(body )) = self.hir.find(body.hir_id) {
self.suggest_arg = "this: &Self".to_string();
if inputs.len() > 0 {
self.suggest_arg.push_str(", ");
}
self.in_closure = true;
self.closure_arg_span = fn_arg_span;
self.visit_expr(body);
self.in_closure = false;
}
}
if let hir::Expr { kind: hir::ExprKind::Path(path), .. } = e {
if let hir::QPath::Resolved(_, hir::Path { segments: [seg], ..}) = path &&
seg.ident.name == kw::SelfLower && self.in_closure {
self.closure_change_spans.push(e.span);
}
}
hir::intravisit::walk_expr(self, e);
}

fn visit_local(&mut self, local: &'hir hir::Local<'hir>) {
if let hir::Pat { kind: hir::PatKind::Binding(_, hir_id, _ident, _), .. } = local.pat &&
let Some(init) = local.init
{
if let hir::Expr { kind: hir::ExprKind::Closure(&hir::Closure {
movability: None,
..
}), .. } = init &&
init.span.contains(self.capture_span) {
self.closure_local_id = Some(*hir_id);
}
}
hir::intravisit::walk_local(self, local);
}

fn visit_stmt(&mut self, s: &'hir hir::Stmt<'hir>) {
if let hir::StmtKind::Semi(e) = s.kind &&
let hir::ExprKind::Call(hir::Expr { kind: hir::ExprKind::Path(path), ..}, args) = e.kind &&
let hir::QPath::Resolved(_, hir::Path { segments: [seg], ..}) = path &&
let Res::Local(hir_id) = seg.res &&
Some(hir_id) == self.closure_local_id {
let (span, arg_str) = if args.len() > 0 {
(args[0].span.shrink_to_lo(), "self, ".to_string())
} else {
let span = e.span.trim_start(seg.ident.span).unwrap_or(e.span);
(span, "(self)".to_string())
};
self.closure_call_changes.push((span, arg_str));
}
hir::intravisit::walk_stmt(self, s);
}
}

if let Some(hir::Node::ImplItem(
hir::ImplItem { kind: hir::ImplItemKind::Fn(_fn_sig, body_id), .. }
)) = hir.find(self.mir_hir_id()) &&
let Some(hir::Node::Expr(expr)) = hir.find(body_id.hir_id) {
let mut finder = ExpressionFinder {
capture_span: *capture_kind_span,
closure_change_spans: vec![],
closure_arg_span: None,
in_closure: false,
suggest_arg: String::new(),
closure_local_id: None,
closure_call_changes: vec![],
hir,
};
finder.visit_expr(expr);

if finder.closure_change_spans.is_empty() || finder.closure_call_changes.is_empty() {
return;
}

let mut sugg = vec![];
let sm = self.infcx.tcx.sess.source_map();

if let Some(span) = finder.closure_arg_span {
sugg.push((sm.next_point(span.shrink_to_lo()).shrink_to_hi(), finder.suggest_arg));
}
for span in finder.closure_change_spans {
sugg.push((span, "this".to_string()));
}

for (span, suggest) in finder.closure_call_changes {
sugg.push((span, suggest));
}

err.multipart_suggestion_verbose(
"try explicitly pass `&Self` into the Closure as an argument",
sugg,
Applicability::MachineApplicable,
);
}
}

/// Returns the description of the root place for a conflicting borrow and the full
/// descriptions of the places that caused the conflict.
///
Original file line number Diff line number Diff line change
@@ -1094,7 +1094,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
}
}

fn mut_borrow_of_mutable_ref(local_decl: &LocalDecl<'_>, local_name: Option<Symbol>) -> bool {
pub fn mut_borrow_of_mutable_ref(local_decl: &LocalDecl<'_>, local_name: Option<Symbol>) -> bool {
debug!("local_info: {:?}, ty.kind(): {:?}", local_decl.local_info, local_decl.ty.kind());

match local_decl.local_info.as_deref() {
22 changes: 17 additions & 5 deletions compiler/rustc_codegen_ssa/src/back/metadata.rs
Original file line number Diff line number Diff line change
@@ -165,11 +165,23 @@ pub(crate) fn create_object_file(sess: &Session) -> Option<write::Object<'static
};
e_flags
}
Architecture::Riscv64 if sess.target.options.features.contains("+d") => {
// copied from `riscv64-linux-gnu-gcc foo.c -c`, note though
// that the `+d` target feature represents whether the double
// float abi is enabled.
let e_flags = elf::EF_RISCV_RVC | elf::EF_RISCV_FLOAT_ABI_DOUBLE;
Architecture::Riscv32 | Architecture::Riscv64 => {
// Source: https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/079772828bd10933d34121117a222b4cc0ee2200/riscv-elf.adoc
let mut e_flags: u32 = 0x0;
let features = &sess.target.options.features;
// Check if compressed is enabled
if features.contains("+c") {
e_flags |= elf::EF_RISCV_RVC;
}

// Select the appropriate floating-point ABI
if features.contains("+d") {
e_flags |= elf::EF_RISCV_FLOAT_ABI_DOUBLE;
} else if features.contains("+f") {
e_flags |= elf::EF_RISCV_FLOAT_ABI_SINGLE;
} else {
e_flags |= elf::EF_RISCV_FLOAT_ABI_SOFT;
}
e_flags
}
_ => 0,
3 changes: 3 additions & 0 deletions compiler/rustc_error_messages/locales/en-US/interface.ftl
Original file line number Diff line number Diff line change
@@ -41,3 +41,6 @@ interface_rustc_error_unexpected_annotation =

interface_failed_writing_file =
failed to write file {$path}: {$error}"

interface_proc_macro_crate_panic_abort =
building proc macro crate with `panic=abort` may crash the compiler should the proc-macro panic
160 changes: 148 additions & 12 deletions compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
Original file line number Diff line number Diff line change
@@ -2,7 +2,9 @@ use super::potentially_plural_count;
use crate::errors::LifetimesOrBoundsMismatchOnTrait;
use hir::def_id::{DefId, LocalDefId};
use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticId, ErrorGuaranteed};
use rustc_errors::{
pluralize, struct_span_err, Applicability, DiagnosticId, ErrorGuaranteed, MultiSpan,
};
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::intravisit;
@@ -320,15 +322,6 @@ fn compare_method_predicate_entailment<'tcx>(
ty::Binder::dummy(ty::PredicateKind::WellFormed(unnormalized_impl_fty.into())),
));
}
let emit_implied_wf_lint = || {
infcx.tcx.struct_span_lint_hir(
rustc_session::lint::builtin::IMPLIED_BOUNDS_ENTAILMENT,
impl_m_hir_id,
infcx.tcx.def_span(impl_m.def_id),
"impl method assumes more implied bounds than the corresponding trait method",
|lint| lint,
);
};

// Check that all obligations are satisfied by the implementation's
// version.
@@ -346,7 +339,7 @@ fn compare_method_predicate_entailment<'tcx>(
)
.map(|()| {
// If the skip-mode was successful, emit a lint.
emit_implied_wf_lint();
emit_implied_wf_lint(infcx.tcx, impl_m, impl_m_hir_id, vec![]);
});
}
CheckImpliedWfMode::Skip => {
@@ -382,8 +375,16 @@ fn compare_method_predicate_entailment<'tcx>(
CheckImpliedWfMode::Skip,
)
.map(|()| {
let bad_args = extract_bad_args_for_implies_lint(
tcx,
&errors,
(trait_m, trait_sig),
// Unnormalized impl sig corresponds to the HIR types written
(impl_m, unnormalized_impl_sig),
impl_m_hir_id,
);
// If the skip-mode was successful, emit a lint.
emit_implied_wf_lint();
emit_implied_wf_lint(tcx, impl_m, impl_m_hir_id, bad_args);
});
}
CheckImpliedWfMode::Skip => {
@@ -400,6 +401,141 @@ fn compare_method_predicate_entailment<'tcx>(
Ok(())
}

fn extract_bad_args_for_implies_lint<'tcx>(
tcx: TyCtxt<'tcx>,
errors: &[infer::RegionResolutionError<'tcx>],
(trait_m, trait_sig): (&ty::AssocItem, ty::FnSig<'tcx>),
(impl_m, impl_sig): (&ty::AssocItem, ty::FnSig<'tcx>),
hir_id: hir::HirId,
) -> Vec<(Span, Option<String>)> {
let mut blame_generics = vec![];
for error in errors {
// Look for the subregion origin that contains an input/output type
let origin = match error {
infer::RegionResolutionError::ConcreteFailure(o, ..) => o,
infer::RegionResolutionError::GenericBoundFailure(o, ..) => o,
infer::RegionResolutionError::SubSupConflict(_, _, o, ..) => o,
infer::RegionResolutionError::UpperBoundUniverseConflict(.., o, _) => o,
};
// Extract (possible) input/output types from origin
match origin {
infer::SubregionOrigin::Subtype(trace) => {
if let Some((a, b)) = trace.values.ty() {
blame_generics.extend([a, b]);
}
}
infer::SubregionOrigin::RelateParamBound(_, ty, _) => blame_generics.push(*ty),
infer::SubregionOrigin::ReferenceOutlivesReferent(ty, _) => blame_generics.push(*ty),
_ => {}
}
}

let fn_decl = tcx.hir().fn_decl_by_hir_id(hir_id).unwrap();
let opt_ret_ty = match fn_decl.output {
hir::FnRetTy::DefaultReturn(_) => None,
hir::FnRetTy::Return(ty) => Some(ty),
};

// Map late-bound regions from trait to impl, so the names are right.
let mapping = std::iter::zip(
tcx.fn_sig(trait_m.def_id).bound_vars(),
tcx.fn_sig(impl_m.def_id).bound_vars(),
)
.filter_map(|(impl_bv, trait_bv)| {
if let ty::BoundVariableKind::Region(impl_bv) = impl_bv
&& let ty::BoundVariableKind::Region(trait_bv) = trait_bv
{
Some((impl_bv, trait_bv))
} else {
None
}
})
.collect();

// For each arg, see if it was in the "blame" of any of the region errors.
// If so, then try to produce a suggestion to replace the argument type with
// one from the trait.
let mut bad_args = vec![];
for (idx, (ty, hir_ty)) in
std::iter::zip(impl_sig.inputs_and_output, fn_decl.inputs.iter().chain(opt_ret_ty))
.enumerate()
{
let expected_ty = trait_sig.inputs_and_output[idx]
.fold_with(&mut RemapLateBound { tcx, mapping: &mapping });
if blame_generics.iter().any(|blame| ty.contains(*blame)) {
let expected_ty_sugg = expected_ty.to_string();
bad_args.push((
hir_ty.span,
// Only suggest something if it actually changed.
(expected_ty_sugg != ty.to_string()).then_some(expected_ty_sugg),
));
}
}

bad_args
}

struct RemapLateBound<'a, 'tcx> {
tcx: TyCtxt<'tcx>,
mapping: &'a FxHashMap<ty::BoundRegionKind, ty::BoundRegionKind>,
}

impl<'tcx> TypeFolder<'tcx> for RemapLateBound<'_, 'tcx> {
fn tcx(&self) -> TyCtxt<'tcx> {
self.tcx
}

fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
if let ty::ReFree(fr) = *r {
self.tcx.mk_region(ty::ReFree(ty::FreeRegion {
bound_region: self
.mapping
.get(&fr.bound_region)
.copied()
.unwrap_or(fr.bound_region),
..fr
}))
} else {
r
}
}
}

fn emit_implied_wf_lint<'tcx>(
tcx: TyCtxt<'tcx>,
impl_m: &ty::AssocItem,
hir_id: hir::HirId,
bad_args: Vec<(Span, Option<String>)>,
) {
let span: MultiSpan = if bad_args.is_empty() {
tcx.def_span(impl_m.def_id).into()
} else {
bad_args.iter().map(|(span, _)| *span).collect::<Vec<_>>().into()
};
tcx.struct_span_lint_hir(
rustc_session::lint::builtin::IMPLIED_BOUNDS_ENTAILMENT,
hir_id,
span,
"impl method assumes more implied bounds than the corresponding trait method",
|lint| {
let bad_args: Vec<_> =
bad_args.into_iter().filter_map(|(span, sugg)| Some((span, sugg?))).collect();
if !bad_args.is_empty() {
lint.multipart_suggestion(
format!(
"replace {} type{} to make the impl signature compatible",
pluralize!("this", bad_args.len()),
pluralize!(bad_args.len())
),
bad_args,
Applicability::MaybeIncorrect,
);
}
lint
},
);
}

#[derive(Debug, PartialEq, Eq)]
enum CheckImpliedWfMode {
/// Checks implied well-formedness of the impl method. If it fails, we will
1 change: 1 addition & 0 deletions compiler/rustc_interface/Cargo.toml
Original file line number Diff line number Diff line change
@@ -45,6 +45,7 @@ rustc_plugin_impl = { path = "../rustc_plugin_impl" }
rustc_privacy = { path = "../rustc_privacy" }
rustc_query_impl = { path = "../rustc_query_impl" }
rustc_resolve = { path = "../rustc_resolve" }
rustc_target = { path = "../rustc_target" }
rustc_trait_selection = { path = "../rustc_trait_selection" }
rustc_ty_utils = { path = "../rustc_ty_utils" }

4 changes: 4 additions & 0 deletions compiler/rustc_interface/src/errors.rs
Original file line number Diff line number Diff line change
@@ -87,3 +87,7 @@ pub struct FailedWritingFile<'a> {
pub path: &'a Path,
pub error: io::Error,
}

#[derive(Diagnostic)]
#[diag(interface_proc_macro_crate_panic_abort)]
pub struct ProcMacroCratePanicAbort;
8 changes: 7 additions & 1 deletion compiler/rustc_interface/src/passes.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use crate::errors::{
CantEmitMIR, EmojiIdentifier, ErrorWritingDependencies, FerrisIdentifier,
GeneratedFileConflictsWithDirectory, InputFileWouldBeOverWritten, MixedBinCrate,
MixedProcMacroCrate, OutDirError, ProcMacroDocWithoutArg, TempsDirError,
MixedProcMacroCrate, OutDirError, ProcMacroCratePanicAbort, ProcMacroDocWithoutArg,
TempsDirError,
};
use crate::interface::{Compiler, Result};
use crate::proc_macro_decls;
@@ -36,6 +37,7 @@ use rustc_session::search_paths::PathKind;
use rustc_session::{Limit, Session};
use rustc_span::symbol::{sym, Symbol};
use rustc_span::FileName;
use rustc_target::spec::PanicStrategy;
use rustc_trait_selection::traits;

use std::any::Any;
@@ -380,6 +382,10 @@ pub fn configure_and_expand(
}
}

if is_proc_macro_crate && sess.panic_strategy() == PanicStrategy::Abort {
sess.emit_warning(ProcMacroCratePanicAbort);
}

// For backwards compatibility, we don't try to run proc macro injection
// if rustdoc is run on a proc macro crate without '--crate-type proc-macro' being
// specified. This should only affect users who manually invoke 'rustdoc', as
4 changes: 2 additions & 2 deletions compiler/rustc_lint_defs/src/builtin.rs
Original file line number Diff line number Diff line change
@@ -4033,10 +4033,10 @@ declare_lint! {
///
/// This can be used to implement an unsound API if used incorrectly.
pub IMPLIED_BOUNDS_ENTAILMENT,
Warn,
Deny,
"impl method assumes more implied bounds than its corresponding trait method",
@future_incompatible = FutureIncompatibleInfo {
reference: "issue #105572 <https://github.com/rust-lang/rust/issues/105572>",
reason: FutureIncompatibilityReason::FutureReleaseError,
reason: FutureIncompatibilityReason::FutureReleaseErrorReportNow,
};
}
14 changes: 7 additions & 7 deletions library/std/src/sync/mpmc/array.rs
Original file line number Diff line number Diff line change
@@ -168,7 +168,7 @@ impl<T> Channel<T> {
return true;
}
Err(_) => {
backoff.spin();
backoff.spin_light();
tail = self.tail.load(Ordering::Relaxed);
}
}
@@ -182,11 +182,11 @@ impl<T> Channel<T> {
return false;
}

backoff.spin();
backoff.spin_light();
tail = self.tail.load(Ordering::Relaxed);
} else {
// Snooze because we need to wait for the stamp to get updated.
backoff.snooze();
backoff.spin_heavy();
tail = self.tail.load(Ordering::Relaxed);
}
}
@@ -251,7 +251,7 @@ impl<T> Channel<T> {
return true;
}
Err(_) => {
backoff.spin();
backoff.spin_light();
head = self.head.load(Ordering::Relaxed);
}
}
@@ -273,11 +273,11 @@ impl<T> Channel<T> {
}
}

backoff.spin();
backoff.spin_light();
head = self.head.load(Ordering::Relaxed);
} else {
// Snooze because we need to wait for the stamp to get updated.
backoff.snooze();
backoff.spin_heavy();
head = self.head.load(Ordering::Relaxed);
}
}
@@ -330,7 +330,7 @@ impl<T> Channel<T> {
if backoff.is_completed() {
break;
} else {
backoff.spin();
backoff.spin_light();
}
}

16 changes: 8 additions & 8 deletions library/std/src/sync/mpmc/list.rs
Original file line number Diff line number Diff line change
@@ -46,7 +46,7 @@ impl<T> Slot<T> {
fn wait_write(&self) {
let backoff = Backoff::new();
while self.state.load(Ordering::Acquire) & WRITE == 0 {
backoff.snooze();
backoff.spin_heavy();
}
}
}
@@ -82,7 +82,7 @@ impl<T> Block<T> {
if !next.is_null() {
return next;
}
backoff.snooze();
backoff.spin_heavy();
}
}

@@ -191,7 +191,7 @@ impl<T> Channel<T> {

// If we reached the end of the block, wait until the next one is installed.
if offset == BLOCK_CAP {
backoff.snooze();
backoff.spin_heavy();
tail = self.tail.index.load(Ordering::Acquire);
block = self.tail.block.load(Ordering::Acquire);
continue;
@@ -247,7 +247,7 @@ impl<T> Channel<T> {
return true;
},
Err(_) => {
backoff.spin();
backoff.spin_light();
tail = self.tail.index.load(Ordering::Acquire);
block = self.tail.block.load(Ordering::Acquire);
}
@@ -286,7 +286,7 @@ impl<T> Channel<T> {

// If we reached the end of the block, wait until the next one is installed.
if offset == BLOCK_CAP {
backoff.snooze();
backoff.spin_heavy();
head = self.head.index.load(Ordering::Acquire);
block = self.head.block.load(Ordering::Acquire);
continue;
@@ -320,7 +320,7 @@ impl<T> Channel<T> {
// The block can be null here only if the first message is being sent into the channel.
// In that case, just wait until it gets initialized.
if block.is_null() {
backoff.snooze();
backoff.spin_heavy();
head = self.head.index.load(Ordering::Acquire);
block = self.head.block.load(Ordering::Acquire);
continue;
@@ -351,7 +351,7 @@ impl<T> Channel<T> {
return true;
},
Err(_) => {
backoff.spin();
backoff.spin_light();
head = self.head.index.load(Ordering::Acquire);
block = self.head.block.load(Ordering::Acquire);
}
@@ -542,7 +542,7 @@ impl<T> Channel<T> {
// New updates to tail will be rejected by MARK_BIT and aborted unless it's
// at boundary. We need to wait for the updates take affect otherwise there
// can be memory leaks.
backoff.snooze();
backoff.spin_heavy();
tail = self.tail.index.load(Ordering::Acquire);
}

2 changes: 1 addition & 1 deletion library/std/src/sync/mpmc/mod.rs
Original file line number Diff line number Diff line change
@@ -43,7 +43,7 @@ mod zero;
use crate::fmt;
use crate::panic::{RefUnwindSafe, UnwindSafe};
use crate::time::{Duration, Instant};
use error::*;
pub use error::*;

/// Creates a channel of unbounded capacity.
///
31 changes: 15 additions & 16 deletions library/std/src/sync/mpmc/utils.rs
Original file line number Diff line number Diff line change
@@ -91,9 +91,8 @@ impl<T> DerefMut for CachePadded<T> {
}

const SPIN_LIMIT: u32 = 6;
const YIELD_LIMIT: u32 = 10;

/// Performs exponential backoff in spin loops.
/// Performs quadratic backoff in spin loops.
pub struct Backoff {
step: Cell<u32>,
}
@@ -104,25 +103,27 @@ impl Backoff {
Backoff { step: Cell::new(0) }
}

/// Backs off in a lock-free loop.
/// Backs off using lightweight spinning.
///
/// This method should be used when we need to retry an operation because another thread made
/// progress.
/// This method should be used for:
/// - Retrying an operation because another thread made progress. i.e. on CAS failure.
/// - Waiting for an operation to complete by spinning optimistically for a few iterations
/// before falling back to parking the thread (see `Backoff::is_completed`).
#[inline]
pub fn spin(&self) {
pub fn spin_light(&self) {
let step = self.step.get().min(SPIN_LIMIT);
for _ in 0..step.pow(2) {
crate::hint::spin_loop();
}

if self.step.get() <= SPIN_LIMIT {
self.step.set(self.step.get() + 1);
}
self.step.set(self.step.get() + 1);
}

/// Backs off in a blocking loop.
/// Backs off using heavyweight spinning.
///
/// This method should be used in blocking loops where parking the thread is not an option.
#[inline]
pub fn snooze(&self) {
pub fn spin_heavy(&self) {
if self.step.get() <= SPIN_LIMIT {
for _ in 0..self.step.get().pow(2) {
crate::hint::spin_loop()
@@ -131,14 +132,12 @@ impl Backoff {
crate::thread::yield_now();
}

if self.step.get() <= YIELD_LIMIT {
self.step.set(self.step.get() + 1);
}
self.step.set(self.step.get() + 1);
}

/// Returns `true` if quadratic backoff has completed and blocking the thread is advised.
/// Returns `true` if quadratic backoff has completed and parking the thread is advised.
#[inline]
pub fn is_completed(&self) -> bool {
self.step.get() > YIELD_LIMIT
self.step.get() > SPIN_LIMIT
}
}
2 changes: 1 addition & 1 deletion library/std/src/sync/mpmc/zero.rs
Original file line number Diff line number Diff line change
@@ -57,7 +57,7 @@ impl<T> Packet<T> {
fn wait_ready(&self) {
let backoff = Backoff::new();
while !self.ready.load(Ordering::Acquire) {
backoff.snooze();
backoff.spin_heavy();
}
}
}
9 changes: 9 additions & 0 deletions library/std/src/sync/mpsc/mod.rs
Original file line number Diff line number Diff line change
@@ -738,6 +738,15 @@ impl<T> SyncSender<T> {
pub fn try_send(&self, t: T) -> Result<(), TrySendError<T>> {
self.inner.try_send(t)
}

// Attempts to send for a value on this receiver, returning an error if the
// corresponding channel has hung up, or if it waits more than `timeout`.
//
// This method is currently private and only used for tests.
#[allow(unused)]
fn send_timeout(&self, t: T, timeout: Duration) -> Result<(), mpmc::SendTimeoutError<T>> {
self.inner.send_timeout(t, timeout)
}
}

#[stable(feature = "rust1", since = "1.0.0")]
8 changes: 8 additions & 0 deletions library/std/src/sync/mpsc/sync_tests.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use super::*;
use crate::env;
use crate::sync::mpmc::SendTimeoutError;
use crate::thread;
use crate::time::Duration;

@@ -41,6 +42,13 @@ fn recv_timeout() {
assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Ok(1));
}

#[test]
fn send_timeout() {
let (tx, _rx) = sync_channel::<i32>(1);
assert_eq!(tx.send_timeout(1, Duration::from_millis(1)), Ok(()));
assert_eq!(tx.send_timeout(1, Duration::from_millis(1)), Err(SendTimeoutError::Timeout(1)));
}

#[test]
fn smoke_threads() {
let (tx, rx) = sync_channel::<i32>(0);
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
error: impl method assumes more implied bounds than the corresponding trait method
--> $DIR/impl-implied-bounds-compatibility-unnormalized.rs:13:5
--> $DIR/impl-implied-bounds-compatibility-unnormalized.rs:13:31
|
LL | fn get<'s>(s: &'s str, _: <&'static &'s () as Project>::Ty) -> &'static str {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace this type to make the impl signature compatible: `()`
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #105572 <https://github.com/rust-lang/rust/issues/105572>
@@ -14,3 +14,18 @@ LL | #![deny(implied_bounds_entailment)]

error: aborting due to previous error

Future incompatibility report: Future breakage diagnostic:
error: impl method assumes more implied bounds than the corresponding trait method
--> $DIR/impl-implied-bounds-compatibility-unnormalized.rs:13:31
|
LL | fn get<'s>(s: &'s str, _: <&'static &'s () as Project>::Ty) -> &'static str {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace this type to make the impl signature compatible: `()`
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #105572 <https://github.com/rust-lang/rust/issues/105572>
note: the lint level is defined here
--> $DIR/impl-implied-bounds-compatibility-unnormalized.rs:1:9
|
LL | #![deny(implied_bounds_entailment)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^

19 changes: 17 additions & 2 deletions tests/ui/implied-bounds/impl-implied-bounds-compatibility.stderr
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
error: impl method assumes more implied bounds than the corresponding trait method
--> $DIR/impl-implied-bounds-compatibility.rs:14:5
--> $DIR/impl-implied-bounds-compatibility.rs:14:35
|
LL | fn listeners<'b>(&'b self) -> &'a MessageListeners<'b> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace this type to make the impl signature compatible: `&'b MessageListeners<'b>`
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #105572 <https://github.com/rust-lang/rust/issues/105572>
@@ -14,3 +14,18 @@ LL | #![deny(implied_bounds_entailment)]

error: aborting due to previous error

Future incompatibility report: Future breakage diagnostic:
error: impl method assumes more implied bounds than the corresponding trait method
--> $DIR/impl-implied-bounds-compatibility.rs:14:35
|
LL | fn listeners<'b>(&'b self) -> &'a MessageListeners<'b> {
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: replace this type to make the impl signature compatible: `&'b MessageListeners<'b>`
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #105572 <https://github.com/rust-lang/rust/issues/105572>
note: the lint level is defined here
--> $DIR/impl-implied-bounds-compatibility.rs:1:9
|
LL | #![deny(implied_bounds_entailment)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^

4 changes: 4 additions & 0 deletions tests/ui/proc-macro/panic-abort.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// error-pattern: building proc macro crate with `panic=abort` may crash the compiler should the proc-macro panic
// compile-flags: --crate-type proc-macro -Cpanic=abort
// force-host
// check-pass
4 changes: 4 additions & 0 deletions tests/ui/proc-macro/panic-abort.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
warning: building proc macro crate with `panic=abort` may crash the compiler should the proc-macro panic

warning: 1 warning emitted

28 changes: 28 additions & 0 deletions tests/ui/suggestions/issue-105761-suggest-self-for-closure.fixed
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//run-rustfix
#![allow(unused)]

struct S;
impl S {
fn foo(&mut self) {
let x = |this: &Self, v: i32| {
this.bar();
this.hel();
};
self.qux(); //~ ERROR cannot borrow `*self` as mutable because it is also borrowed as immutable
x(self, 1);
x(self, 3);
}
fn bar(&self) {}
fn hel(&self) {}
fn qux(&mut self) {}

fn hello(&mut self) {
let y = |this: &Self| {
this.bar();
};
self.qux(); //~ ERROR cannot borrow `*self` as mutable because it is also borrowed as immutable
y(self);
}
}

fn main() {}
28 changes: 28 additions & 0 deletions tests/ui/suggestions/issue-105761-suggest-self-for-closure.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//run-rustfix
#![allow(unused)]

struct S;
impl S {
fn foo(&mut self) {
let x = |v: i32| {
self.bar();
self.hel();
};
self.qux(); //~ ERROR cannot borrow `*self` as mutable because it is also borrowed as immutable
x(1);
x(3);
}
fn bar(&self) {}
fn hel(&self) {}
fn qux(&mut self) {}

fn hello(&mut self) {
let y = || {
self.bar();
};
self.qux(); //~ ERROR cannot borrow `*self` as mutable because it is also borrowed as immutable
y();
}
}

fn main() {}
49 changes: 49 additions & 0 deletions tests/ui/suggestions/issue-105761-suggest-self-for-closure.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable
--> $DIR/issue-105761-suggest-self-for-closure.rs:11:9
|
LL | let x = |v: i32| {
| -------- immutable borrow occurs here
LL | self.bar();
| ---- first borrow occurs due to use of `self` in closure
...
LL | self.qux();
| ^^^^^^^^^^ mutable borrow occurs here
LL | x(1);
| - immutable borrow later used here
|
help: try explicitly pass `&Self` into the Closure as an argument
|
LL ~ let x = |this: &Self, v: i32| {
LL ~ this.bar();
LL ~ this.hel();
LL | };
LL | self.qux();
LL ~ x(self, 1);
LL ~ x(self, 3);
|

error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable
--> $DIR/issue-105761-suggest-self-for-closure.rs:23:9
|
LL | let y = || {
| -- immutable borrow occurs here
LL | self.bar();
| ---- first borrow occurs due to use of `self` in closure
LL | };
LL | self.qux();
| ^^^^^^^^^^ mutable borrow occurs here
LL | y();
| - immutable borrow later used here
|
help: try explicitly pass `&Self` into the Closure as an argument
|
LL ~ let y = |this: &Self| {
LL ~ this.bar();
LL | };
LL | self.qux();
LL ~ y(self);
|

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0502`.