From 261765fe8ba7dbe28d33ed4f92609e5d468064d6 Mon Sep 17 00:00:00 2001 From: lightning1141 Date: Fri, 25 Feb 2022 19:35:03 +0800 Subject: [PATCH 01/15] Fix show error message when literal overflows in match patterns --- compiler/rustc_mir_build/src/thir/constant.rs | 8 +++++++- src/test/ui/issues/issue-94239.rs | 8 ++++++++ src/test/ui/issues/issue-94239.stderr | 11 +++++++++++ 3 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/issues/issue-94239.rs create mode 100644 src/test/ui/issues/issue-94239.stderr diff --git a/compiler/rustc_mir_build/src/thir/constant.rs b/compiler/rustc_mir_build/src/thir/constant.rs index 72c0985a63c33..a94c2b9f5f7d4 100644 --- a/compiler/rustc_mir_build/src/thir/constant.rs +++ b/compiler/rustc_mir_build/src/thir/constant.rs @@ -17,7 +17,13 @@ crate fn lit_to_const<'tcx>( let param_ty = ParamEnv::reveal_all().and(ty); let width = tcx.layout_of(param_ty).map_err(|_| LitToConstError::Reported)?.size; trace!("trunc {} with size {} and shift {}", n, width.bits(), 128 - width.bits()); - let result = width.truncate(n); + let result = match &ty.kind() { + ty::Uint(_) => { + let max_value = width.unsigned_int_max(); + if n >= max_value { max_value } else { width.truncate(n) } + } + _ => width.truncate(n), + }; trace!("trunc result: {}", result); Ok(ConstValue::Scalar(Scalar::from_uint(result, width))) }; diff --git a/src/test/ui/issues/issue-94239.rs b/src/test/ui/issues/issue-94239.rs new file mode 100644 index 0000000000000..58ebba6764cef --- /dev/null +++ b/src/test/ui/issues/issue-94239.rs @@ -0,0 +1,8 @@ +pub const fn test_match_range(len: usize) -> usize { + match len { + 10000000000000000000..=99999999999999999999 => 0, //~ ERROR literal out of range for `usize` + _ => unreachable!(), + } +} + +fn main() {} diff --git a/src/test/ui/issues/issue-94239.stderr b/src/test/ui/issues/issue-94239.stderr new file mode 100644 index 0000000000000..f847d45949baf --- /dev/null +++ b/src/test/ui/issues/issue-94239.stderr @@ -0,0 +1,11 @@ +error: literal out of range for `usize` + --> $DIR/issue-94239.rs:3:32 + | +LL | 10000000000000000000..=99999999999999999999 => 0, + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[deny(overflowing_literals)]` on by default + = note: the literal `99999999999999999999` does not fit into the type `usize` whose range is `0..=18446744073709551615` + +error: aborting due to previous error + From 5b58c6feb87face0118bd36b61f58d137dd625e7 Mon Sep 17 00:00:00 2001 From: lightning1141 Date: Fri, 25 Feb 2022 21:12:04 +0800 Subject: [PATCH 02/15] fix E0081 error message due to lit_to_const behavior change --- src/test/ui/error-codes/E0081.rs | 6 +++--- src/test/ui/error-codes/E0081.stderr | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/test/ui/error-codes/E0081.rs b/src/test/ui/error-codes/E0081.rs index 255e05ced19f7..6f15b9d2ef95c 100644 --- a/src/test/ui/error-codes/E0081.rs +++ b/src/test/ui/error-codes/E0081.rs @@ -10,10 +10,10 @@ enum Enum { #[repr(u8)] enum EnumOverflowRepr { P = 257, - //~^ NOTE first use of `1` (overflowed from `257`) + //~^ NOTE first use of `255` (overflowed from `257`) X = 513, - //~^ ERROR discriminant value `1` already exists - //~| NOTE enum already has `1` (overflowed from `513`) + //~^ ERROR discriminant value `255` already exists + //~| NOTE enum already has `255` (overflowed from `513`) } fn main() { diff --git a/src/test/ui/error-codes/E0081.stderr b/src/test/ui/error-codes/E0081.stderr index 9b279bb0214c6..68bb0f407b82f 100644 --- a/src/test/ui/error-codes/E0081.stderr +++ b/src/test/ui/error-codes/E0081.stderr @@ -7,14 +7,14 @@ LL | LL | X = 3, | ^ enum already has `3` -error[E0081]: discriminant value `1` already exists +error[E0081]: discriminant value `255` already exists --> $DIR/E0081.rs:14:9 | LL | P = 257, - | --- first use of `1` (overflowed from `257`) + | --- first use of `255` (overflowed from `257`) LL | LL | X = 513, - | ^^^ enum already has `1` (overflowed from `513`) + | ^^^ enum already has `255` (overflowed from `513`) error: aborting due to 2 previous errors From b0c4db35942cfaa860d2d60b468af8734a34674d Mon Sep 17 00:00:00 2001 From: lightning1141 Date: Fri, 25 Feb 2022 21:57:09 +0800 Subject: [PATCH 03/15] Fix ci test issue-94239.rs --- src/test/ui/issues/issue-94239.rs | 4 ++-- src/test/ui/issues/issue-94239.stderr | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/test/ui/issues/issue-94239.rs b/src/test/ui/issues/issue-94239.rs index 58ebba6764cef..a09ae32aa74d6 100644 --- a/src/test/ui/issues/issue-94239.rs +++ b/src/test/ui/issues/issue-94239.rs @@ -1,6 +1,6 @@ -pub const fn test_match_range(len: usize) -> usize { +pub const fn test_match_range(len: u64) -> u64 { match len { - 10000000000000000000..=99999999999999999999 => 0, //~ ERROR literal out of range for `usize` + 10000000000000000000..=99999999999999999999 => 0, //~ ERROR literal out of range for `u64` _ => unreachable!(), } } diff --git a/src/test/ui/issues/issue-94239.stderr b/src/test/ui/issues/issue-94239.stderr index f847d45949baf..057fbfec64f9b 100644 --- a/src/test/ui/issues/issue-94239.stderr +++ b/src/test/ui/issues/issue-94239.stderr @@ -1,11 +1,11 @@ -error: literal out of range for `usize` +error: literal out of range for `u64` --> $DIR/issue-94239.rs:3:32 | LL | 10000000000000000000..=99999999999999999999 => 0, | ^^^^^^^^^^^^^^^^^^^^ | = note: `#[deny(overflowing_literals)]` on by default - = note: the literal `99999999999999999999` does not fit into the type `usize` whose range is `0..=18446744073709551615` + = note: the literal `99999999999999999999` does not fit into the type `u64` whose range is `0..=18446744073709551615` error: aborting due to previous error From 2bf56b9aa7f92f665c40ddbe8259417de84bb142 Mon Sep 17 00:00:00 2001 From: xFrednet Date: Sat, 26 Feb 2022 11:32:07 +0100 Subject: [PATCH 04/15] Document that pre-expansion lint passes are deprecated --- compiler/rustc_lint/src/context.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 0582a4e01bfeb..ad9a16fb39ae2 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -166,7 +166,12 @@ impl LintStore { self.early_passes.push(Box::new(pass)); } - /// Used by clippy. + /// This lint pass is softly deprecated. It misses expanded code and has caused a few + /// errors in the past. Currently, it is only used in Clippy. New implementations + /// should avoid using this interface, as it might be removed in the future. + /// + /// * See [rust#69838](https://github.com/rust-lang/rust/pull/69838) + /// * See [rust-clippy#5518](https://github.com/rust-lang/rust-clippy/pull/5518) pub fn register_pre_expansion_pass( &mut self, pass: impl Fn() -> EarlyLintPassObject + 'static + sync::Send + sync::Sync, From ca2ad69143eff606f051aed98422d98a8d4e43d8 Mon Sep 17 00:00:00 2001 From: Caio Date: Sat, 26 Feb 2022 07:43:47 -0300 Subject: [PATCH 05/15] Make more use of `let_chains` --- compiler/rustc_typeck/src/astconv/mod.rs | 11 ++- compiler/rustc_typeck/src/check/check.rs | 39 ++++----- compiler/rustc_typeck/src/check/coercion.rs | 11 ++- compiler/rustc_typeck/src/check/demand.rs | 19 ++--- compiler/rustc_typeck/src/check/expr.rs | 6 +- .../rustc_typeck/src/check/fn_ctxt/checks.rs | 34 ++++---- .../rustc_typeck/src/check/method/suggest.rs | 82 +++++++++---------- compiler/rustc_typeck/src/check/pat.rs | 9 +- compiler/rustc_typeck/src/collect.rs | 69 ++++++++-------- compiler/rustc_typeck/src/lib.rs | 13 +-- .../src/outlives/implicit_infer.rs | 13 ++- 11 files changed, 142 insertions(+), 164 deletions(-) diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index 4a310e2be3e3c..14a6e686a6424 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -1054,12 +1054,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let mut result = Vec::new(); for ast_bound in ast_bounds { - if let Some(trait_ref) = ast_bound.trait_ref() { - if let Some(trait_did) = trait_ref.trait_def_id() { - if self.tcx().trait_may_define_assoc_type(trait_did, assoc_name) { - result.push(ast_bound.clone()); - } - } + if let Some(trait_ref) = ast_bound.trait_ref() + && let Some(trait_did) = trait_ref.trait_def_id() + && self.tcx().trait_may_define_assoc_type(trait_did, assoc_name) + { + result.push(ast_bound.clone()); } } diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs index 8ed87497f1b32..100d2d07a5c9f 100644 --- a/compiler/rustc_typeck/src/check/check.rs +++ b/compiler/rustc_typeck/src/check/check.rs @@ -282,13 +282,12 @@ pub(super) fn check_fn<'a, 'tcx>( sess.span_err(decl.inputs[0].span, "argument should be `&PanicInfo`"); } - if let Node::Item(item) = hir.get(fn_id) { - if let ItemKind::Fn(_, ref generics, _) = item.kind { - if !generics.params.is_empty() { + if let Node::Item(item) = hir.get(fn_id) + && let ItemKind::Fn(_, ref generics, _) = item.kind + && !generics.params.is_empty() + { sess.span_err(span, "should have no type parameters"); } - } - } } else { let span = sess.source_map().guess_head_span(span); sess.span_err(span, "function should have one argument"); @@ -319,17 +318,15 @@ pub(super) fn check_fn<'a, 'tcx>( sess.span_err(decl.inputs[0].span, "argument should be `Layout`"); } - if let Node::Item(item) = hir.get(fn_id) { - if let ItemKind::Fn(_, ref generics, _) = item.kind { - if !generics.params.is_empty() { + if let Node::Item(item) = hir.get(fn_id) + && let ItemKind::Fn(_, ref generics, _) = item.kind + && !generics.params.is_empty() + { sess.span_err( span, - "`#[alloc_error_handler]` function should have no type \ - parameters", + "`#[alloc_error_handler]` function should have no type parameters", ); } - } - } } else { let span = sess.source_map().guess_head_span(span); sess.span_err(span, "function should have one argument"); @@ -1146,9 +1143,10 @@ pub(super) fn check_packed(tcx: TyCtxt<'_>, sp: Span, def: &ty::AdtDef) { if repr.packed() { for attr in tcx.get_attrs(def.did).iter() { for r in attr::find_repr_attrs(&tcx.sess, attr) { - if let attr::ReprPacked(pack) = r { - if let Some(repr_pack) = repr.pack { - if pack as u64 != repr_pack.bytes() { + if let attr::ReprPacked(pack) = r + && let Some(repr_pack) = repr.pack + && pack as u64 != repr_pack.bytes() + { struct_span_err!( tcx.sess, sp, @@ -1156,8 +1154,6 @@ pub(super) fn check_packed(tcx: TyCtxt<'_>, sp: Span, def: &ty::AdtDef) { "type has conflicting packed representation hints" ) .emit(); - } - } } } } @@ -1399,12 +1395,11 @@ fn display_discriminant_value<'tcx>( ) -> String { if let Some(expr) = &variant.disr_expr { let body = &tcx.hir().body(expr.body).value; - if let hir::ExprKind::Lit(lit) = &body.kind { - if let rustc_ast::LitKind::Int(lit_value, _int_kind) = &lit.node { - if evaluated != *lit_value { + if let hir::ExprKind::Lit(lit) = &body.kind + && let rustc_ast::LitKind::Int(lit_value, _int_kind) = &lit.node + && evaluated != *lit_value + { return format!("`{}` (overflowed from `{}`)", evaluated, lit_value); - } - } } } format!("`{}`", evaluated) diff --git a/compiler/rustc_typeck/src/check/coercion.rs b/compiler/rustc_typeck/src/check/coercion.rs index 8ca27b010b6af..c6b14d3e10458 100644 --- a/compiler/rustc_typeck/src/check/coercion.rs +++ b/compiler/rustc_typeck/src/check/coercion.rs @@ -1696,13 +1696,12 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { } fn is_return_ty_unsized<'a>(&self, fcx: &FnCtxt<'a, 'tcx>, blk_id: hir::HirId) -> bool { - if let Some((fn_decl, _)) = fcx.get_fn_decl(blk_id) { - if let hir::FnRetTy::Return(ty) = fn_decl.output { - let ty = >::ast_ty_to_ty(fcx, ty); - if let ty::Dynamic(..) = ty.kind() { + if let Some((fn_decl, _)) = fcx.get_fn_decl(blk_id) + && let hir::FnRetTy::Return(ty) = fn_decl.output + && let ty = >::ast_ty_to_ty(fcx, ty) + && let ty::Dynamic(..) = ty.kind() + { return true; - } - } } false } diff --git a/compiler/rustc_typeck/src/check/demand.rs b/compiler/rustc_typeck/src/check/demand.rs index 80096b90f9530..faead1bf5cd6d 100644 --- a/compiler/rustc_typeck/src/check/demand.rs +++ b/compiler/rustc_typeck/src/check/demand.rs @@ -587,9 +587,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match (&expr.kind, expected.kind(), checked_ty.kind()) { (_, &ty::Ref(_, exp, _), &ty::Ref(_, check, _)) => match (exp.kind(), check.kind()) { (&ty::Str, &ty::Array(arr, _) | &ty::Slice(arr)) if arr == self.tcx.types.u8 => { - if let hir::ExprKind::Lit(_) = expr.kind { - if let Ok(src) = sm.span_to_snippet(sp) { - if replace_prefix(&src, "b\"", "\"").is_some() { + if let hir::ExprKind::Lit(_) = expr.kind + && let Ok(src) = sm.span_to_snippet(sp) + && replace_prefix(&src, "b\"", "\"").is_some() + { let pos = sp.lo() + BytePos(1); return Some(( sp.with_hi(pos), @@ -600,12 +601,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { )); } } - } - } (&ty::Array(arr, _) | &ty::Slice(arr), &ty::Str) if arr == self.tcx.types.u8 => { - if let hir::ExprKind::Lit(_) = expr.kind { - if let Ok(src) = sm.span_to_snippet(sp) { - if replace_prefix(&src, "\"", "b\"").is_some() { + if let hir::ExprKind::Lit(_) = expr.kind + && let Ok(src) = sm.span_to_snippet(sp) + && replace_prefix(&src, "\"", "b\"").is_some() + { return Some(( sp.shrink_to_lo(), "consider adding a leading `b`", @@ -613,8 +613,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Applicability::MachineApplicable, true, )); - } - } + } } _ => {} diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index 8d4ffefda73bb..14a1318517a19 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -810,10 +810,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Use the span of the trailing expression for our cause, // not the span of the entire function if !explicit_return { - if let ExprKind::Block(body, _) = return_expr.kind { - if let Some(last_expr) = body.expr { - span = last_expr.span; - } + if let ExprKind::Block(body, _) = return_expr.kind && let Some(last_expr) = body.expr { + span = last_expr.span; } } ret_coercion.borrow_mut().coerce( diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs index 4b6460b62b77a..76339998a2fbb 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs @@ -402,25 +402,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if arg_count == 0 || i + 1 == arg_count { &label } else { "" }, ); } - if let Some(def_id) = fn_def_id { - if let Some(def_span) = tcx.def_ident_span(def_id) { - let mut spans: MultiSpan = def_span.into(); - - let params = tcx - .hir() - .get_if_local(def_id) - .and_then(|node| node.body_id()) - .into_iter() - .map(|id| tcx.hir().body(id).params) - .flatten(); - - for param in params { - spans.push_span_label(param.span, String::new()); - } - - let def_kind = tcx.def_kind(def_id); - err.span_note(spans, &format!("{} defined here", def_kind.descr(def_id))); + if let Some(def_id) = fn_def_id && let Some(def_span) = tcx.def_ident_span(def_id) { + let mut spans: MultiSpan = def_span.into(); + + let params = tcx + .hir() + .get_if_local(def_id) + .and_then(|node| node.body_id()) + .into_iter() + .map(|id| tcx.hir().body(id).params) + .flatten(); + + for param in params { + spans.push_span_label(param.span, String::new()); } + + let def_kind = tcx.def_kind(def_id); + err.span_note(spans, &format!("{} defined here", def_kind.descr(def_id))); } if sugg_unit { let sugg_span = tcx.sess.source_map().end_point(call_expr.span); diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs index ccaea10233dc1..32de5d23c1ea7 100644 --- a/compiler/rustc_typeck/src/check/method/suggest.rs +++ b/compiler/rustc_typeck/src/check/method/suggest.rs @@ -430,12 +430,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { actual.prefix_string(self.tcx), ty_str_reported, ); - if let Mode::MethodCall = mode { - if let SelfSource::MethodCall(call) = source { - self.suggest_await_before_method( - &mut err, item_name, actual, call, span, - ); - } + if let Mode::MethodCall = mode && let SelfSource::MethodCall(cal) = source { + self.suggest_await_before_method( + &mut err, item_name, actual, cal, span, + ); } if let Some(span) = tcx.resolutions(()).confused_type_with_std_module.get(&span) @@ -1525,43 +1523,41 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (self.tcx.mk_diagnostic_item(*rcvr_ty, sym::Arc), "Arc::new"), (self.tcx.mk_diagnostic_item(*rcvr_ty, sym::Rc), "Rc::new"), ] { - if let Some(new_rcvr_t) = *rcvr_ty { - if let Ok(pick) = self.lookup_probe( - span, - item_name, - new_rcvr_t, - rcvr, - crate::check::method::probe::ProbeScope::AllTraits, - ) { - debug!("try_alt_rcvr: pick candidate {:?}", pick); - let did = Some(pick.item.container.id()); - // We don't want to suggest a container type when the missing - // method is `.clone()` or `.deref()` otherwise we'd suggest - // `Arc::new(foo).clone()`, which is far from what the user wants. - // Explicitly ignore the `Pin::as_ref()` method as `Pin` does not - // implement the `AsRef` trait. - let skip = skippable.contains(&did) - || (("Pin::new" == *pre) && (sym::as_ref == item_name.name)); - // Make sure the method is defined for the *actual* receiver: we don't - // want to treat `Box` as a receiver if it only works because of - // an autoderef to `&self` - if pick.autoderefs == 0 && !skip { - err.span_label( - pick.item.ident(self.tcx).span, - &format!("the method is available for `{}` here", new_rcvr_t), - ); - err.multipart_suggestion( - "consider wrapping the receiver expression with the \ - appropriate type", - vec![ - (rcvr.span.shrink_to_lo(), format!("{}({}", pre, post)), - (rcvr.span.shrink_to_hi(), ")".to_string()), - ], - Applicability::MaybeIncorrect, - ); - // We don't care about the other suggestions. - alt_rcvr_sugg = true; - } + if let Some(new_rcvr_t) = *rcvr_ty && let Ok(pick) = self.lookup_probe( + span, + item_name, + new_rcvr_t, + rcvr, + crate::check::method::probe::ProbeScope::AllTraits, + ) { + debug!("try_alt_rcvr: pick candidate {:?}", pick); + let did = Some(pick.item.container.id()); + // We don't want to suggest a container type when the missing + // method is `.clone()` or `.deref()` otherwise we'd suggest + // `Arc::new(foo).clone()`, which is far from what the user wants. + // Explicitly ignore the `Pin::as_ref()` method as `Pin` does not + // implement the `AsRef` trait. + let skip = skippable.contains(&did) + || (("Pin::new" == *pre) && (sym::as_ref == item_name.name)); + // Make sure the method is defined for the *actual* receiver: we don't + // want to treat `Box` as a receiver if it only works because of + // an autoderef to `&self` + if pick.autoderefs == 0 && !skip { + err.span_label( + pick.item.ident(self.tcx).span, + &format!("the method is available for `{}` here", new_rcvr_t), + ); + err.multipart_suggestion( + "consider wrapping the receiver expression with the \ + appropriate type", + vec![ + (rcvr.span.shrink_to_lo(), format!("{}({}", pre, post)), + (rcvr.span.shrink_to_hi(), ")".to_string()), + ], + Applicability::MaybeIncorrect, + ); + // We don't care about the other suggestions. + alt_rcvr_sugg = true; } } } diff --git a/compiler/rustc_typeck/src/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs index 7c6917734b2ae..9963a922268a4 100644 --- a/compiler/rustc_typeck/src/check/pat.rs +++ b/compiler/rustc_typeck/src/check/pat.rs @@ -685,9 +685,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } pub fn check_dereferenceable(&self, span: Span, expected: Ty<'tcx>, inner: &Pat<'_>) -> bool { - if let PatKind::Binding(..) = inner.kind { - if let Some(mt) = self.shallow_resolve(expected).builtin_deref(true) { - if let ty::Dynamic(..) = mt.ty.kind() { + if let PatKind::Binding(..) = inner.kind + && let Some(mt) = self.shallow_resolve(expected).builtin_deref(true) + && let ty::Dynamic(..) = mt.ty.kind() + { // This is "x = SomeTrait" being reduced from // "let &x = &SomeTrait" or "let box x = Box", an error. let type_str = self.ty_to_string(expected); @@ -705,8 +706,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.emit(); return false; } - } - } true } diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index 2317ae43f1143..88e3e67c99ee3 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -190,25 +190,23 @@ crate fn placeholder_type_error<'tcx>( let mut is_fn = false; let mut is_const_or_static = false; - if let Some(hir_ty) = hir_ty { - if let hir::TyKind::BareFn(_) = hir_ty.kind { - is_fn = true; - - // Check if parent is const or static - let parent_id = tcx.hir().get_parent_node(hir_ty.hir_id); - let parent_node = tcx.hir().get(parent_id); - - is_const_or_static = matches!( - parent_node, - Node::Item(&hir::Item { - kind: hir::ItemKind::Const(..) | hir::ItemKind::Static(..), - .. - }) | Node::TraitItem(&hir::TraitItem { - kind: hir::TraitItemKind::Const(..), - .. - }) | Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Const(..), .. }) - ); - } + if let Some(hir_ty) = hir_ty && let hir::TyKind::BareFn(_) = hir_ty.kind { + is_fn = true; + + // Check if parent is const or static + let parent_id = tcx.hir().get_parent_node(hir_ty.hir_id); + let parent_node = tcx.hir().get(parent_id); + + is_const_or_static = matches!( + parent_node, + Node::Item(&hir::Item { + kind: hir::ItemKind::Const(..) | hir::ItemKind::Static(..), + .. + }) | Node::TraitItem(&hir::TraitItem { + kind: hir::TraitItemKind::Const(..), + .. + }) | Node::ImplItem(&hir::ImplItem { kind: hir::ImplItemKind::Const(..), .. }) + ); } // if function is wrapped around a const or static, @@ -2417,16 +2415,14 @@ fn const_evaluatable_predicates_of<'tcx>( let node = tcx.hir().get(hir_id); let mut collector = ConstCollector { tcx, preds: FxIndexSet::default() }; - if let hir::Node::Item(item) = node { - if let hir::ItemKind::Impl(ref impl_) = item.kind { - if let Some(of_trait) = &impl_.of_trait { - debug!("const_evaluatable_predicates_of({:?}): visit impl trait_ref", def_id); - collector.visit_trait_ref(of_trait); - } - - debug!("const_evaluatable_predicates_of({:?}): visit_self_ty", def_id); - collector.visit_ty(impl_.self_ty); + if let hir::Node::Item(item) = node && let hir::ItemKind::Impl(ref impl_) = item.kind { + if let Some(of_trait) = &impl_.of_trait { + debug!("const_evaluatable_predicates_of({:?}): visit impl trait_ref", def_id); + collector.visit_trait_ref(of_trait); } + + debug!("const_evaluatable_predicates_of({:?}): visit_self_ty", def_id); + collector.visit_ty(impl_.self_ty); } if let Some(generics) = node.generics() { @@ -3280,15 +3276,14 @@ fn asm_target_features<'tcx>(tcx: TyCtxt<'tcx>, id: DefId) -> &'tcx FxHashSet, def_id: DefId) -> bool { - if let Some(impl_item) = tcx.opt_associated_item(def_id) { - if let ty::AssocItemContainer::ImplContainer(_) = impl_item.container { - if let Some(trait_item) = impl_item.trait_item_def_id { - return tcx - .codegen_fn_attrs(trait_item) - .flags - .intersects(CodegenFnAttrFlags::TRACK_CALLER); - } - } + if let Some(impl_item) = tcx.opt_associated_item(def_id) + && let ty::AssocItemContainer::ImplContainer(_) = impl_item.container + && let Some(trait_item) = impl_item.trait_item_def_id + { + return tcx + .codegen_fn_attrs(trait_item) + .flags + .intersects(CodegenFnAttrFlags::TRACK_CALLER); } false diff --git a/compiler/rustc_typeck/src/lib.rs b/compiler/rustc_typeck/src/lib.rs index f0289fd505a47..de030c5b60bcc 100644 --- a/compiler/rustc_typeck/src/lib.rs +++ b/compiler/rustc_typeck/src/lib.rs @@ -55,22 +55,23 @@ This API is completely unstable and subject to change. */ +#![allow(rustc::potential_query_instability)] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(bool_to_option)] +#![feature(control_flow_enum)] #![feature(crate_visibility_modifier)] +#![feature(hash_drain_filter)] #![feature(if_let_guard)] #![feature(is_sorted)] +#![feature(let_chains)] #![feature(let_else)] #![feature(min_specialization)] -#![feature(nll)] -#![feature(try_blocks)] #![feature(never_type)] -#![feature(slice_partition_dedup)] -#![feature(control_flow_enum)] -#![feature(hash_drain_filter)] +#![feature(nll)] #![feature(once_cell)] +#![feature(slice_partition_dedup)] +#![feature(try_blocks)] #![recursion_limit = "256"] -#![allow(rustc::potential_query_instability)] #[macro_use] extern crate tracing; diff --git a/compiler/rustc_typeck/src/outlives/implicit_infer.rs b/compiler/rustc_typeck/src/outlives/implicit_infer.rs index 89f0bd8d42154..61ca09f6b982c 100644 --- a/compiler/rustc_typeck/src/outlives/implicit_infer.rs +++ b/compiler/rustc_typeck/src/outlives/implicit_infer.rs @@ -304,13 +304,12 @@ pub fn check_explicit_predicates<'tcx>( // = X` binding from the object type (there must be such a // binding) and thus infer an outlives requirement that `X: // 'b`. - if let Some(self_ty) = ignored_self_ty { - if let GenericArgKind::Type(ty) = outlives_predicate.0.unpack() { - if ty.walk().any(|arg| arg == self_ty.into()) { - debug!("skipping self ty = {:?}", &ty); - continue; - } - } + if let Some(self_ty) = ignored_self_ty + && let GenericArgKind::Type(ty) = outlives_predicate.0.unpack() + && ty.walk().any(|arg| arg == self_ty.into()) + { + debug!("skipping self ty = {:?}", &ty); + continue; } let predicate = outlives_predicate.subst(tcx, substs); From 915740c392e0147a5afa6f6fd0e2c303c066ac34 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sat, 26 Feb 2022 16:58:21 +0100 Subject: [PATCH 06/15] Add test for #79465 to prevent regression --- src/test/rustdoc-ui/issue-79465.rs | 3 +++ src/test/rustdoc-ui/issue-79465.stderr | 15 +++++++++++++++ 2 files changed, 18 insertions(+) create mode 100644 src/test/rustdoc-ui/issue-79465.rs create mode 100644 src/test/rustdoc-ui/issue-79465.stderr diff --git a/src/test/rustdoc-ui/issue-79465.rs b/src/test/rustdoc-ui/issue-79465.rs new file mode 100644 index 0000000000000..f1a77982fb523 --- /dev/null +++ b/src/test/rustdoc-ui/issue-79465.rs @@ -0,0 +1,3 @@ +pub fn f1(x: T::A) {} +//~^ ERROR +//~^^ ERROR diff --git a/src/test/rustdoc-ui/issue-79465.stderr b/src/test/rustdoc-ui/issue-79465.stderr new file mode 100644 index 0000000000000..489cc14420a4c --- /dev/null +++ b/src/test/rustdoc-ui/issue-79465.stderr @@ -0,0 +1,15 @@ +error[E0220]: associated type `A` not found for `T` + --> $DIR/issue-79465.rs:1:20 + | +LL | pub fn f1(x: T::A) {} + | ^ associated type `A` not found + +error[E0220]: associated type `A` not found for `T` + --> $DIR/issue-79465.rs:1:20 + | +LL | pub fn f1(x: T::A) {} + | ^ associated type `A` not found + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0220`. From 530e2ddba6e029cb0e4ba9e7aba57ab2e3339f97 Mon Sep 17 00:00:00 2001 From: Bart Massey Date: Fri, 25 Feb 2022 12:59:08 -0800 Subject: [PATCH 07/15] added TcpListener::bind_with_backlog to both sys_common and std::net Also added TcpListener::DEFAULT_BACKLOG to document the default backlog (currently 128). --- library/std/src/net/tcp.rs | 46 +++++++++++++++++++++++++++++-- library/std/src/sys_common/net.rs | 12 ++++++-- 2 files changed, 54 insertions(+), 4 deletions(-) diff --git a/library/std/src/net/tcp.rs b/library/std/src/net/tcp.rs index cc4e4fd4fdc77..7f51196a6d0e3 100644 --- a/library/std/src/net/tcp.rs +++ b/library/std/src/net/tcp.rs @@ -707,10 +707,52 @@ impl fmt::Debug for TcpStream { } impl TcpListener { + /// Default "backlog" for [`TcpListener::bind`]. See + /// [`TcpListener::bind_with_backlog`] for an explanation of backlog + /// values. + #[unstable(feature = "bind_with_backlog", issue = "none")] + pub const DEFAULT_BACKLOG: usize = 128; + /// Creates a new `TcpListener` which will be bound to the specified /// address. /// - /// The returned listener is ready for accepting connections. + /// The given backlog specifies the maximum number of outstanding + /// connections that will be buffered in the OS waiting to be accepted by + /// [`TcpListener::accept`]. The backlog argument overrides the default + /// specified by [`TcpListener::DEFAULT_BACKLOG`]; that default is + /// reasonable for most use cases. + /// + /// This function is otherwise [`TcpListener::bind`]: see that + /// documentation for full details of operation. + /// + /// # Examples + /// + /// Creates a TCP listener bound to `127.0.0.1:80` with a backlog of 1000: + /// + /// ```no_run + /// use std::net::TcpListener; + /// + /// let listener = TcpListener::bind_with_backlog("127.0.0.1:80", 1000).unwrap(); + /// ``` + /// + /// # Errors + /// + /// The specified backlog may be larger than supported by the underlying + /// system. In this case an [`io::Error`] with + /// [`io::ErrorKind::InvalidData`] will be returned. + #[unstable(feature = "bind_with_backlog", issue = "none")] + pub fn bind_with_backlog(addr: A, backlog: usize) -> io::Result { + super::each_addr(addr, move |a| net_imp::TcpListener::bind_with_backlog(a, backlog)) + .map(TcpListener) + } + + /// Creates a new `TcpListener` which will be bound to the specified + /// address. The returned listener is ready for accepting + /// connections. + /// + /// The listener will have a backlog given by + /// [`TcpListener::DEFAULT_BACKLOG`]. See the documentation for + /// [`TcpListener::bind_with_backlog`] for further information. /// /// Binding with a port number of 0 will request that the OS assigns a port /// to this listener. The port allocated can be queried via the @@ -748,7 +790,7 @@ impl TcpListener { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn bind(addr: A) -> io::Result { - super::each_addr(addr, net_imp::TcpListener::bind).map(TcpListener) + Self::bind_with_backlog(addr, TcpListener::DEFAULT_BACKLOG) } /// Returns the local socket address of this listener. diff --git a/library/std/src/sys_common/net.rs b/library/std/src/sys_common/net.rs index 70b29d4a92ed5..8eaa15af5fb3e 100644 --- a/library/std/src/sys_common/net.rs +++ b/library/std/src/sys_common/net.rs @@ -363,9 +363,17 @@ pub struct TcpListener { } impl TcpListener { - pub fn bind(addr: io::Result<&SocketAddr>) -> io::Result { + pub fn bind_with_backlog( + addr: io::Result<&SocketAddr>, + backlog: usize, + ) -> io::Result { let addr = addr?; + // Type-convert the backlog + let backlog = backlog + .try_into() + .map_err(|e| crate::io::Error::new(crate::io::ErrorKind::InvalidData, e))?; + init(); let sock = Socket::new(addr, c::SOCK_STREAM)?; @@ -385,7 +393,7 @@ impl TcpListener { cvt(unsafe { c::bind(sock.as_raw(), addrp, len as _) })?; // Start listening - cvt(unsafe { c::listen(sock.as_raw(), 128) })?; + cvt(unsafe { c::listen(sock.as_raw(), backlog) })?; Ok(TcpListener { inner: sock }) } From 6f03b9508392868f00bc0d280e53117e1867cde0 Mon Sep 17 00:00:00 2001 From: Bart Massey Date: Sat, 26 Feb 2022 11:19:12 -0800 Subject: [PATCH 08/15] added UnixListener::bind_with_backlog and UnixListener::bind_addr_with_backlog Also added UnixListener::DEFAULT_BACKLOG --- library/std/src/os/unix/net/listener.rs | 99 ++++++++++++++++++++++++- 1 file changed, 97 insertions(+), 2 deletions(-) diff --git a/library/std/src/os/unix/net/listener.rs b/library/std/src/os/unix/net/listener.rs index b23dd6062f682..5b0ada5701b05 100644 --- a/library/std/src/os/unix/net/listener.rs +++ b/library/std/src/os/unix/net/listener.rs @@ -5,6 +5,7 @@ use crate::sys::cvt; use crate::sys::net::Socket; use crate::sys_common::{AsInner, FromInner, IntoInner}; use crate::{fmt, io, mem}; +use core::convert::TryInto; /// A structure representing a Unix domain socket server. /// @@ -53,8 +54,18 @@ impl fmt::Debug for UnixListener { } impl UnixListener { + /// Default "backlog" for [`UnixListener::bind`] and + /// [`UnixListener::bind_addr`]. See [`UnixListener::bind_with_backlog`] + /// for an explanation of backlog values. + #[unstable(feature = "bind_with_backlog", issue = "none")] + pub const DEFAULT_BACKLOG: usize = 128; + /// Creates a new `UnixListener` bound to the specified socket. /// + /// The listener will have a backlog given by + /// [`UnixListener::DEFAULT_BACKLOG`]. See the documentation for + /// [`UnixListener::bind_with_backlog`] for further information. + /// /// # Examples /// /// ```no_run @@ -70,12 +81,50 @@ impl UnixListener { /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] pub fn bind>(path: P) -> io::Result { + UnixListener::bind_with_backlog(path, UnixListener::DEFAULT_BACKLOG) + } + + /// Creates a new `UnixListener` bound to the specified socket. + /// + /// The given backlog specifies the maximum number of outstanding + /// connections that will be buffered in the OS waiting to be accepted by + /// [`UnixListener::accept`]. The backlog argument overrides the default + /// specified by [`UnixListener::DEFAULT_BACKLOG`]; that default is + /// reasonable for most use cases. + /// + /// This function is otherwise [`UnixListener::bind`]: see that + /// documentation for full details of operation. + /// + /// # Examples + /// + /// ```no_run + /// use std::os::unix::net::UnixListener; + /// + /// let listener = match UnixListener::bind_with_backlog("/path/to/the/socket", 1000) { + /// Ok(sock) => sock, + /// Err(e) => { + /// println!("Couldn't connect: {:?}", e); + /// return + /// } + /// }; + /// ``` + /// + /// # Errors + /// + /// The specified backlog may be larger than supported by the underlying + /// system. In this case an [`io::Error`] with + /// [`io::ErrorKind::InvalidData`] will be returned. + #[unstable(feature = "bind_with_backlog", issue = "none")] + pub fn bind_with_backlog>(path: P, backlog: usize) -> io::Result { unsafe { + let backlog = backlog + .try_into() + .map_err(|e| crate::io::Error::new(crate::io::ErrorKind::InvalidData, e))?; let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; let (addr, len) = sockaddr_un(path.as_ref())?; cvt(libc::bind(inner.as_inner().as_raw_fd(), &addr as *const _ as *const _, len as _))?; - cvt(libc::listen(inner.as_inner().as_raw_fd(), 128))?; + cvt(libc::listen(inner.as_inner().as_raw_fd(), backlog))?; Ok(UnixListener(inner)) } @@ -107,14 +156,60 @@ impl UnixListener { /// ``` #[unstable(feature = "unix_socket_abstract", issue = "85410")] pub fn bind_addr(socket_addr: &SocketAddr) -> io::Result { + UnixListener::bind_addr_with_backlog(socket_addr, UnixListener::DEFAULT_BACKLOG) + } + + /// Creates a new `UnixListener` bound to the specified [`socket address`]. + /// + /// The given backlog specifies the maximum number of outstanding + /// connections that will be buffered in the OS waiting to be accepted by + /// [`UnixListener::accept`]. The backlog argument overrides the default + /// specified by [`UnixListener::DEFAULT_BACKLOG`]; that default is + /// reasonable for most use cases. + /// + /// This function is otherwise [`UnixListener::bind_addr`]: see that + /// documentation for full details of operation. + /// + /// [`socket address`]: crate::os::unix::net::SocketAddr + /// + /// # Examples + /// + /// ```no_run + /// #![feature(unix_socket_abstract)] + /// #![feature(bind_with_backlog)] + /// use std::os::unix::net::{UnixListener}; + /// + /// fn main() -> std::io::Result<()> { + /// let listener1 = UnixListener::bind("path/to/socket")?; + /// let addr = listener1.local_addr()?; + /// + /// let listener2 = match UnixListener::bind_addr_with_backlog(&addr, 1000) { + /// Ok(sock) => sock, + /// Err(err) => { + /// println!("Couldn't bind: {:?}", err); + /// return Err(err); + /// } + /// }; + /// Ok(()) + /// } + /// ``` + //#[unstable(feature = "unix_socket_abstract", issue = "85410")] + #[unstable(feature = "bind_with_backlog", issue = "none")] + pub fn bind_addr_with_backlog( + socket_addr: &SocketAddr, + backlog: usize, + ) -> io::Result { unsafe { + let backlog = backlog + .try_into() + .map_err(|e| crate::io::Error::new(crate::io::ErrorKind::InvalidData, e))?; let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; cvt(libc::bind( inner.as_raw_fd(), &socket_addr.addr as *const _ as *const _, socket_addr.len as _, ))?; - cvt(libc::listen(inner.as_raw_fd(), 128))?; + cvt(libc::listen(inner.as_raw_fd(), backlog))?; Ok(UnixListener(inner)) } } From a6ca55bbd278cea6872d659fd9afe33acf707e09 Mon Sep 17 00:00:00 2001 From: Bart Massey Date: Sat, 26 Feb 2022 12:42:31 -0800 Subject: [PATCH 09/15] modified TcpListener and UnixListener tests to use with_backlog variants where appropriate --- library/std/src/net/tcp.rs | 1 + library/std/src/net/tcp/tests.rs | 32 +++++++++++++++++++++---- library/std/src/os/unix/net/listener.rs | 1 + library/std/src/os/unix/net/tests.rs | 10 ++++---- 4 files changed, 34 insertions(+), 10 deletions(-) diff --git a/library/std/src/net/tcp.rs b/library/std/src/net/tcp.rs index 7f51196a6d0e3..ca9a4a568bf76 100644 --- a/library/std/src/net/tcp.rs +++ b/library/std/src/net/tcp.rs @@ -730,6 +730,7 @@ impl TcpListener { /// Creates a TCP listener bound to `127.0.0.1:80` with a backlog of 1000: /// /// ```no_run + /// #![feature(bind_with_backlog)] /// use std::net::TcpListener; /// /// let listener = TcpListener::bind_with_backlog("127.0.0.1:80", 1000).unwrap(); diff --git a/library/std/src/net/tcp/tests.rs b/library/std/src/net/tcp/tests.rs index c2061c1351262..8ead0e31270fe 100644 --- a/library/std/src/net/tcp/tests.rs +++ b/library/std/src/net/tcp/tests.rs @@ -48,7 +48,7 @@ fn connect_error() { #[test] fn listen_localhost() { let socket_addr = next_test_ip4(); - let listener = t!(TcpListener::bind(&socket_addr)); + let listener = t!(TcpListener::bind_with_backlog(&socket_addr, 1)); let _t = thread::spawn(move || { let mut stream = t!(TcpStream::connect(&("localhost", socket_addr.port()))); @@ -64,7 +64,7 @@ fn listen_localhost() { #[test] fn connect_loopback() { each_ip(&mut |addr| { - let acceptor = t!(TcpListener::bind(&addr)); + let acceptor = t!(TcpListener::bind_with_backlog(&addr, 1)); let _t = thread::spawn(move || { let host = match addr { @@ -85,7 +85,7 @@ fn connect_loopback() { #[test] fn smoke_test() { each_ip(&mut |addr| { - let acceptor = t!(TcpListener::bind(&addr)); + let acceptor = t!(TcpListener::bind_with_backlog(&addr, 1)); let (tx, rx) = channel(); let _t = thread::spawn(move || { @@ -172,11 +172,33 @@ fn multiple_connect_serial() { }) } +#[test] +fn multiple_connect_serial_with_backlog() { + each_ip(&mut |addr| { + let max = 10; + let acceptor = t!(TcpListener::bind_with_backlog(&addr, max)); + + let _t = thread::spawn(move || { + for _ in 0..max { + let mut stream = t!(TcpStream::connect(&addr)); + t!(stream.write(&[99])); + } + }); + + for stream in acceptor.incoming().take(max) { + let mut stream = t!(stream); + let mut buf = [0]; + t!(stream.read(&mut buf)); + assert_eq!(buf[0], 99); + } + }) +} + #[test] fn multiple_connect_interleaved_greedy_schedule() { const MAX: usize = 10; each_ip(&mut |addr| { - let acceptor = t!(TcpListener::bind(&addr)); + let acceptor = t!(TcpListener::bind_with_backlog(&addr, MAX)); let _t = thread::spawn(move || { let acceptor = acceptor; @@ -213,7 +235,7 @@ fn multiple_connect_interleaved_greedy_schedule() { fn multiple_connect_interleaved_lazy_schedule() { const MAX: usize = 10; each_ip(&mut |addr| { - let acceptor = t!(TcpListener::bind(&addr)); + let acceptor = t!(TcpListener::bind_with_backlog(&addr, MAX)); let _t = thread::spawn(move || { for stream in acceptor.incoming().take(MAX) { diff --git a/library/std/src/os/unix/net/listener.rs b/library/std/src/os/unix/net/listener.rs index 5b0ada5701b05..52799335cdd94 100644 --- a/library/std/src/os/unix/net/listener.rs +++ b/library/std/src/os/unix/net/listener.rs @@ -98,6 +98,7 @@ impl UnixListener { /// # Examples /// /// ```no_run + /// #![feature(bind_with_backlog)] /// use std::os::unix::net::UnixListener; /// /// let listener = match UnixListener::bind_with_backlog("/path/to/the/socket", 1000) { diff --git a/library/std/src/os/unix/net/tests.rs b/library/std/src/os/unix/net/tests.rs index 7ad4a02611e07..b06cc4abc116c 100644 --- a/library/std/src/os/unix/net/tests.rs +++ b/library/std/src/os/unix/net/tests.rs @@ -41,7 +41,7 @@ fn basic() { let msg1 = b"hello"; let msg2 = b"world!"; - let listener = or_panic!(UnixListener::bind(&socket_path)); + let listener = or_panic!(UnixListener::bind_with_backlog(&socket_path, 1)); let thread = thread::spawn(move || { let mut stream = or_panic!(listener.accept()).0; let mut buf = [0; 5]; @@ -111,7 +111,7 @@ fn try_clone() { let msg1 = b"hello"; let msg2 = b"world"; - let listener = or_panic!(UnixListener::bind(&socket_path)); + let listener = or_panic!(UnixListener::bind_with_backlog(&socket_path, 1)); let thread = thread::spawn(move || { let mut stream = or_panic!(listener.accept()).0; or_panic!(stream.write_all(msg1)); @@ -135,7 +135,7 @@ fn iter() { let dir = tmpdir(); let socket_path = dir.path().join("sock"); - let listener = or_panic!(UnixListener::bind(&socket_path)); + let listener = or_panic!(UnixListener::bind_with_backlog(&socket_path, 2)); let thread = thread::spawn(move || { for stream in listener.incoming().take(2) { let mut stream = or_panic!(stream); @@ -423,7 +423,7 @@ fn test_abstract_stream_connect() { let msg2 = b"world"; let socket_addr = or_panic!(SocketAddr::from_abstract_namespace(b"namespace")); - let listener = or_panic!(UnixListener::bind_addr(&socket_addr)); + let listener = or_panic!(UnixListener::bind_addr_with_backlog(&socket_addr, 1)); let thread = thread::spawn(move || { let mut stream = or_panic!(listener.accept()).0; @@ -451,7 +451,7 @@ fn test_abstract_stream_connect() { #[test] fn test_abstract_stream_iter() { let addr = or_panic!(SocketAddr::from_abstract_namespace(b"hidden")); - let listener = or_panic!(UnixListener::bind_addr(&addr)); + let listener = or_panic!(UnixListener::bind_addr_with_backlog(&addr, 2)); let thread = thread::spawn(move || { for stream in listener.incoming().take(2) { From 86439473e24cc79efa11fcd588c1c5d0dcb65d7d Mon Sep 17 00:00:00 2001 From: Bart Massey Date: Sat, 26 Feb 2022 14:36:42 -0800 Subject: [PATCH 10/15] added issue numbers for with_backlog --- library/std/src/net/tcp.rs | 4 ++-- library/std/src/os/unix/net/listener.rs | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/library/std/src/net/tcp.rs b/library/std/src/net/tcp.rs index ca9a4a568bf76..74060c79e5b3d 100644 --- a/library/std/src/net/tcp.rs +++ b/library/std/src/net/tcp.rs @@ -710,7 +710,7 @@ impl TcpListener { /// Default "backlog" for [`TcpListener::bind`]. See /// [`TcpListener::bind_with_backlog`] for an explanation of backlog /// values. - #[unstable(feature = "bind_with_backlog", issue = "none")] + #[unstable(feature = "bind_with_backlog", issue = "94406")] pub const DEFAULT_BACKLOG: usize = 128; /// Creates a new `TcpListener` which will be bound to the specified @@ -741,7 +741,7 @@ impl TcpListener { /// The specified backlog may be larger than supported by the underlying /// system. In this case an [`io::Error`] with /// [`io::ErrorKind::InvalidData`] will be returned. - #[unstable(feature = "bind_with_backlog", issue = "none")] + #[unstable(feature = "bind_with_backlog", issue = "94406")] pub fn bind_with_backlog(addr: A, backlog: usize) -> io::Result { super::each_addr(addr, move |a| net_imp::TcpListener::bind_with_backlog(a, backlog)) .map(TcpListener) diff --git a/library/std/src/os/unix/net/listener.rs b/library/std/src/os/unix/net/listener.rs index 52799335cdd94..d1b09976cb490 100644 --- a/library/std/src/os/unix/net/listener.rs +++ b/library/std/src/os/unix/net/listener.rs @@ -57,7 +57,7 @@ impl UnixListener { /// Default "backlog" for [`UnixListener::bind`] and /// [`UnixListener::bind_addr`]. See [`UnixListener::bind_with_backlog`] /// for an explanation of backlog values. - #[unstable(feature = "bind_with_backlog", issue = "none")] + #[unstable(feature = "bind_with_backlog", issue = "94406")] pub const DEFAULT_BACKLOG: usize = 128; /// Creates a new `UnixListener` bound to the specified socket. @@ -115,7 +115,7 @@ impl UnixListener { /// The specified backlog may be larger than supported by the underlying /// system. In this case an [`io::Error`] with /// [`io::ErrorKind::InvalidData`] will be returned. - #[unstable(feature = "bind_with_backlog", issue = "none")] + #[unstable(feature = "bind_with_backlog", issue = "94406")] pub fn bind_with_backlog>(path: P, backlog: usize) -> io::Result { unsafe { let backlog = backlog @@ -195,7 +195,7 @@ impl UnixListener { /// } /// ``` //#[unstable(feature = "unix_socket_abstract", issue = "85410")] - #[unstable(feature = "bind_with_backlog", issue = "none")] + #[unstable(feature = "bind_with_backlog", issue = "94406")] pub fn bind_addr_with_backlog( socket_addr: &SocketAddr, backlog: usize, From b98c009ef5bd3b64bbb73d3249a32f39fd83a719 Mon Sep 17 00:00:00 2001 From: Bart Massey Date: Sat, 26 Feb 2022 15:17:16 -0800 Subject: [PATCH 11/15] unpublished listener DEFAULT_BACKLOGs --- library/std/src/net/tcp.rs | 13 ++++-------- library/std/src/os/unix/net/listener.rs | 28 ++++++++++++------------- 2 files changed, 17 insertions(+), 24 deletions(-) diff --git a/library/std/src/net/tcp.rs b/library/std/src/net/tcp.rs index 74060c79e5b3d..74f03ecaa2ff8 100644 --- a/library/std/src/net/tcp.rs +++ b/library/std/src/net/tcp.rs @@ -707,11 +707,8 @@ impl fmt::Debug for TcpStream { } impl TcpListener { - /// Default "backlog" for [`TcpListener::bind`]. See - /// [`TcpListener::bind_with_backlog`] for an explanation of backlog - /// values. - #[unstable(feature = "bind_with_backlog", issue = "94406")] - pub const DEFAULT_BACKLOG: usize = 128; + /// Default listen backlog. + const DEFAULT_BACKLOG: usize = 128; /// Creates a new `TcpListener` which will be bound to the specified /// address. @@ -719,8 +716,7 @@ impl TcpListener { /// The given backlog specifies the maximum number of outstanding /// connections that will be buffered in the OS waiting to be accepted by /// [`TcpListener::accept`]. The backlog argument overrides the default - /// specified by [`TcpListener::DEFAULT_BACKLOG`]; that default is - /// reasonable for most use cases. + /// value of 128; that default is reasonable for most use cases. /// /// This function is otherwise [`TcpListener::bind`]: see that /// documentation for full details of operation. @@ -751,8 +747,7 @@ impl TcpListener { /// address. The returned listener is ready for accepting /// connections. /// - /// The listener will have a backlog given by - /// [`TcpListener::DEFAULT_BACKLOG`]. See the documentation for + /// The listener will have a backlog of 128. See the documentation for /// [`TcpListener::bind_with_backlog`] for further information. /// /// Binding with a port number of 0 will request that the OS assigns a port diff --git a/library/std/src/os/unix/net/listener.rs b/library/std/src/os/unix/net/listener.rs index d1b09976cb490..71bea61fbe825 100644 --- a/library/std/src/os/unix/net/listener.rs +++ b/library/std/src/os/unix/net/listener.rs @@ -54,16 +54,12 @@ impl fmt::Debug for UnixListener { } impl UnixListener { - /// Default "backlog" for [`UnixListener::bind`] and - /// [`UnixListener::bind_addr`]. See [`UnixListener::bind_with_backlog`] - /// for an explanation of backlog values. - #[unstable(feature = "bind_with_backlog", issue = "94406")] - pub const DEFAULT_BACKLOG: usize = 128; + /// Default backlog for `bind` and `bind_addr`. + const DEFAULT_BACKLOG: usize = 128; /// Creates a new `UnixListener` bound to the specified socket. /// - /// The listener will have a backlog given by - /// [`UnixListener::DEFAULT_BACKLOG`]. See the documentation for + /// The listener will have a backlog of 128. See the documentation for /// [`UnixListener::bind_with_backlog`] for further information. /// /// # Examples @@ -87,10 +83,10 @@ impl UnixListener { /// Creates a new `UnixListener` bound to the specified socket. /// /// The given backlog specifies the maximum number of outstanding - /// connections that will be buffered in the OS waiting to be accepted by - /// [`UnixListener::accept`]. The backlog argument overrides the default - /// specified by [`UnixListener::DEFAULT_BACKLOG`]; that default is - /// reasonable for most use cases. + /// connections that will be buffered in the OS waiting to be accepted + /// by [`UnixListener::accept`]. The backlog argument overrides the + /// default backlog of 128; that default is reasonable for most use + /// cases. /// /// This function is otherwise [`UnixListener::bind`]: see that /// documentation for full details of operation. @@ -133,6 +129,9 @@ impl UnixListener { /// Creates a new `UnixListener` bound to the specified [`socket address`]. /// + /// The listener will have a backlog of 128. See the documentation for + /// [`UnixListener::bind_addr_with_backlog`] for further information. + /// /// [`socket address`]: crate::os::unix::net::SocketAddr /// /// # Examples @@ -163,10 +162,9 @@ impl UnixListener { /// Creates a new `UnixListener` bound to the specified [`socket address`]. /// /// The given backlog specifies the maximum number of outstanding - /// connections that will be buffered in the OS waiting to be accepted by - /// [`UnixListener::accept`]. The backlog argument overrides the default - /// specified by [`UnixListener::DEFAULT_BACKLOG`]; that default is - /// reasonable for most use cases. + /// connections that will be buffered in the OS waiting to be accepted + /// by [`UnixListener::accept`]. The backlog argument overrides the + /// default of 128; that default is reasonable for most use cases. /// /// This function is otherwise [`UnixListener::bind_addr`]: see that /// documentation for full details of operation. From 35e3aaf8d87180b7b11568d7bd49b832d7fb63d8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 26 Feb 2022 19:07:02 -0500 Subject: [PATCH 12/15] avoid rebuilding bootstrap when PATH changes --- src/bootstrap/build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/build.rs b/src/bootstrap/build.rs index 6e39ea00f808c..8a5bf933d56ec 100644 --- a/src/bootstrap/build.rs +++ b/src/bootstrap/build.rs @@ -4,13 +4,13 @@ use std::path::PathBuf; fn main() { println!("cargo:rerun-if-changed=build.rs"); println!("cargo:rerun-if-env-changed=RUSTC"); - println!("cargo:rerun-if-env-changed=PATH"); println!("cargo:rustc-env=BUILD_TRIPLE={}", env::var("HOST").unwrap()); // This may not be a canonicalized path. let mut rustc = PathBuf::from(env::var_os("RUSTC").unwrap()); if rustc.is_relative() { + println!("cargo:rerun-if-env-changed=PATH"); for dir in env::split_paths(&env::var_os("PATH").unwrap_or_default()) { let absolute = dir.join(&rustc); if absolute.exists() { From b582bd388f5693119bbefa85ed7ea055760f9eef Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sat, 26 Feb 2022 18:57:15 -0800 Subject: [PATCH 13/15] For MIRI, cfg out the swap logic from 94212 --- library/core/src/mem/mod.rs | 27 ++++++++++++++++++++++----- library/core/src/ptr/mod.rs | 23 +++++++++++++++-------- src/test/codegen/swap-large-types.rs | 27 +++++++++++++++++++++++++++ 3 files changed, 64 insertions(+), 13 deletions(-) diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index b5c1ae37e5e89..8a99bed6a96ab 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -708,7 +708,10 @@ pub const fn swap(x: &mut T, y: &mut T) { // understanding `mem::replace`, `Option::take`, etc. - a better overall // solution might be to make `ptr::swap_nonoverlapping` into an intrinsic, which // a backend can choose to implement using the block optimization, or not. - #[cfg(not(target_arch = "spirv"))] + // NOTE(scottmcm) MIRI is disabled here as reading in smaller units is a + // pessimization for it. Also, if the type contains any unaligned pointers, + // copying those over multiple reads is difficult to support. + #[cfg(not(any(target_arch = "spirv", miri)))] { // For types that are larger multiples of their alignment, the simple way // tends to copy the whole thing to stack rather than doing it one part @@ -737,12 +740,26 @@ pub const fn swap(x: &mut T, y: &mut T) { #[rustc_const_unstable(feature = "const_swap", issue = "83163")] #[inline] pub(crate) const fn swap_simple(x: &mut T, y: &mut T) { + // We arrange for this to typically be called with small types, + // so this reads-and-writes approach is actually better than using + // copy_nonoverlapping as it easily puts things in LLVM registers + // directly and doesn't end up inlining allocas. + // And LLVM actually optimizes it to 3×memcpy if called with + // a type larger than it's willing to keep in a register. + // Having typed reads and writes in MIR here is also good as + // it lets MIRI and CTFE understand them better, including things + // like enforcing type validity for them. + // Importantly, read+copy_nonoverlapping+write introduces confusing + // asymmetry to the behaviour where one value went through read+write + // whereas the other was copied over by the intrinsic (see #94371). + // SAFETY: exclusive references are always valid to read/write, - // are non-overlapping, and nothing here panics so it's drop-safe. + // including being aligned, and nothing here panics so it's drop-safe. unsafe { - let z = ptr::read(x); - ptr::copy_nonoverlapping(y, x, 1); - ptr::write(y, z); + let a = ptr::read(x); + let b = ptr::read(y); + ptr::write(x, b); + ptr::write(y, a); } } diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index ff71fadb61418..59b1b4c136752 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -419,6 +419,7 @@ pub const unsafe fn swap(x: *mut T, y: *mut T) { #[stable(feature = "swap_nonoverlapping", since = "1.27.0")] #[rustc_const_unstable(feature = "const_swap", issue = "83163")] pub const unsafe fn swap_nonoverlapping(x: *mut T, y: *mut T, count: usize) { + #[allow(unused)] macro_rules! attempt_swap_as_chunks { ($ChunkTy:ty) => { if mem::align_of::() >= mem::align_of::<$ChunkTy>() @@ -437,15 +438,21 @@ pub const unsafe fn swap_nonoverlapping(x: *mut T, y: *mut T, count: usize) { }; } - // Split up the slice into small power-of-two-sized chunks that LLVM is able - // to vectorize (unless it's a special type with more-than-pointer alignment, - // because we don't want to pessimize things like slices of SIMD vectors.) - if mem::align_of::() <= mem::size_of::() - && (!mem::size_of::().is_power_of_two() - || mem::size_of::() > mem::size_of::() * 2) + // NOTE(scottmcm) MIRI is disabled here as reading in smaller units is a + // pessimization for it. Also, if the type contains any unaligned pointers, + // copying those over multiple reads is difficult to support. + #[cfg(not(miri))] { - attempt_swap_as_chunks!(usize); - attempt_swap_as_chunks!(u8); + // Split up the slice into small power-of-two-sized chunks that LLVM is able + // to vectorize (unless it's a special type with more-than-pointer alignment, + // because we don't want to pessimize things like slices of SIMD vectors.) + if mem::align_of::() <= mem::size_of::() + && (!mem::size_of::().is_power_of_two() + || mem::size_of::() > mem::size_of::() * 2) + { + attempt_swap_as_chunks!(usize); + attempt_swap_as_chunks!(u8); + } } // SAFETY: Same preconditions as this function diff --git a/src/test/codegen/swap-large-types.rs b/src/test/codegen/swap-large-types.rs index 535d301a3d27b..91a1ab7144fd4 100644 --- a/src/test/codegen/swap-large-types.rs +++ b/src/test/codegen/swap-large-types.rs @@ -39,6 +39,9 @@ pub fn swap_std(x: &mut KeccakBuffer, y: &mut KeccakBuffer) { swap(x, y) } +// Verify that types with usize alignment are swapped via vectored usizes, +// not falling back to byte-level code. + // CHECK-LABEL: @swap_slice #[no_mangle] pub fn swap_slice(x: &mut [KeccakBuffer], y: &mut [KeccakBuffer]) { @@ -50,6 +53,8 @@ pub fn swap_slice(x: &mut [KeccakBuffer], y: &mut [KeccakBuffer]) { } } +// But for a large align-1 type, vectorized byte copying is what we want. + type OneKilobyteBuffer = [u8; 1024]; // CHECK-LABEL: @swap_1kb_slices @@ -62,3 +67,25 @@ pub fn swap_1kb_slices(x: &mut [OneKilobyteBuffer], y: &mut [OneKilobyteBuffer]) x.swap_with_slice(y); } } + +// This verifies that the 2×read + 2×write optimizes to just 3 memcpys +// for an unusual type like this. It's not clear whether we should do anything +// smarter in Rust for these, so for now it's fine to leave these up to the backend. +// That's not as bad as it might seem, as for example, LLVM will lower the +// memcpys below to VMOVAPS on YMMs if one enables the AVX target feature. +// Eventually we'll be able to pass `align_of::` to a const generic and +// thus pick a smarter chunk size ourselves without huge code duplication. + +#[repr(align(64))] +pub struct BigButHighlyAligned([u8; 64 * 3]); + +// CHECK-LABEL: @swap_big_aligned +#[no_mangle] +pub fn swap_big_aligned(x: &mut BigButHighlyAligned, y: &mut BigButHighlyAligned) { +// CHECK-NOT: call void @llvm.memcpy +// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* noundef nonnull align 64 dereferenceable(192) +// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* noundef nonnull align 64 dereferenceable(192) +// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* noundef nonnull align 64 dereferenceable(192) +// CHECK-NOT: call void @llvm.memcpy + swap(x, y) +} From 7ad4297a4960c657932885173bef77fde0f26ccd Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sun, 27 Feb 2022 10:59:10 +0100 Subject: [PATCH 14/15] Use the first codegen backend in the config.toml as default It is currently hard coded to llvm if enabled and cranelift otherwise. This made some sense when cranelift was the only alternative codegen backend. Since the introduction of the gcc backend this doesn't make much sense anymore. Before this PR bootstrapping rustc using a backend other than llvm or cranelift required changing the source of rustc_interface. With this PR it becomes a matter of putting the right backend as first enabled backend in config.toml. --- compiler/rustc_interface/src/util.rs | 8 ++------ config.toml.example | 4 +++- src/bootstrap/compile.rs | 4 ++++ 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index 83b54810db2f2..046f4f9451f58 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -236,13 +236,9 @@ pub fn get_codegen_backend( static LOAD: SyncOnceCell Box> = SyncOnceCell::new(); let load = LOAD.get_or_init(|| { - #[cfg(feature = "llvm")] - const DEFAULT_CODEGEN_BACKEND: &str = "llvm"; + let default_codegen_backend = option_env!("CFG_DEFAULT_CODEGEN_BACKEND").unwrap_or("llvm"); - #[cfg(not(feature = "llvm"))] - const DEFAULT_CODEGEN_BACKEND: &str = "cranelift"; - - match backend_name.unwrap_or(DEFAULT_CODEGEN_BACKEND) { + match backend_name.unwrap_or(default_codegen_backend) { filename if filename.contains('.') => load_backend_from_dylib(filename.as_ref()), #[cfg(feature = "llvm")] "llvm" => rustc_codegen_llvm::LlvmCodegenBackend::new, diff --git a/config.toml.example b/config.toml.example index ad48cc881f3e6..466a3a29c4c78 100644 --- a/config.toml.example +++ b/config.toml.example @@ -551,7 +551,9 @@ changelog-seen = 2 # This is an array of the codegen backends that will be compiled for the rustc # that's being compiled. The default is to only build the LLVM codegen backend, -# and currently the only standard options supported are `"llvm"` and `"cranelift"`. +# and currently the only standard options supported are `"llvm"`, `"cranelift"` +# and `"gcc"`. The first backend in this list will be used as default by rustc +# when no explicit backend is specified. #codegen-backends = ["llvm"] # Indicates whether LLD will be compiled and made available in the sysroot for diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 53226977fd881..2ceca28da0c6e 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -662,6 +662,10 @@ pub fn rustc_cargo_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetS .env("CFG_RELEASE_CHANNEL", &builder.config.channel) .env("CFG_VERSION", builder.rust_version()); + if let Some(backend) = builder.config.rust_codegen_backends.get(0) { + cargo.env("CFG_DEFAULT_CODEGEN_BACKEND", backend); + } + let libdir_relative = builder.config.libdir_relative().unwrap_or_else(|| Path::new("lib")); let target_config = builder.config.target_config.get(&target); From 0eb8b32de3b40ce45827af33f290b53ffa012919 Mon Sep 17 00:00:00 2001 From: Caio Date: Sun, 27 Feb 2022 11:10:20 -0300 Subject: [PATCH 15/15] 3 - Make more use of let_chains Continuation of #94376. cc #53667 --- .../src/diagnostics/conflict_errors.rs | 21 +++++++-------- .../src/diagnostics/explain_borrow.rs | 15 +++++------ .../src/diagnostics/mutability_errors.rs | 26 ++++++++----------- .../src/diagnostics/region_errors.rs | 13 ++++------ compiler/rustc_borrowck/src/lib.rs | 21 +++++++-------- .../rustc_borrowck/src/places_conflict.rs | 6 ++--- 6 files changed, 44 insertions(+), 58 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index cd1f73d529818..eb906d5fde7b4 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -1921,17 +1921,16 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { err.span_label(assigned_span, format!("first assignment to {}", place_description)); } } - if let Some(decl) = local_decl { - if let Some(name) = local_name { - if decl.can_be_made_mutable() { - err.span_suggestion( - decl.source_info.span, - "consider making this binding mutable", - format!("mut {}", name), - Applicability::MachineApplicable, - ); - } - } + if let Some(decl) = local_decl + && let Some(name) = local_name + && decl.can_be_made_mutable() + { + err.span_suggestion( + decl.source_info.span, + "consider making this binding mutable", + format!("mut {}", name), + Applicability::MachineApplicable, + ); } err.span_label(span, msg); self.buffer_error(err); diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs index da6610c002efc..2217c0e14b2aa 100644 --- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs +++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs @@ -375,15 +375,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { Some(Cause::DropVar(local, location)) => { let mut should_note_order = false; - if self.local_names[local].is_some() { - if let Some((WriteKind::StorageDeadOrDrop, place)) = kind_place { - if let Some(borrowed_local) = place.as_local() { - if self.local_names[borrowed_local].is_some() && local != borrowed_local - { - should_note_order = true; - } - } - } + if self.local_names[local].is_some() + && let Some((WriteKind::StorageDeadOrDrop, place)) = kind_place + && let Some(borrowed_local) = place.as_local() + && self.local_names[borrowed_local].is_some() && local != borrowed_local + { + should_note_order = true; } BorrowExplanation::UsedLaterWhenDropped { diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index 2c9bd8ea96e9a..610798c7c05c8 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -1086,21 +1086,17 @@ fn get_mut_span_in_struct_field<'tcx>( field: &mir::Field, ) -> Option { // Expect our local to be a reference to a struct of some kind. - if let ty::Ref(_, ty, _) = ty.kind() { - if let ty::Adt(def, _) = ty.kind() { - let field = def.all_fields().nth(field.index())?; - // Use the HIR types to construct the diagnostic message. - let node = tcx.hir().find_by_def_id(field.did.as_local()?)?; - // Now we're dealing with the actual struct that we're going to suggest a change to, - // we can expect a field that is an immutable reference to a type. - if let hir::Node::Field(field) = node { - if let hir::TyKind::Rptr(lifetime, hir::MutTy { mutbl: hir::Mutability::Not, ty }) = - field.ty.kind - { - return Some(lifetime.span.between(ty.span)); - } - } - } + if let ty::Ref(_, ty, _) = ty.kind() + && let ty::Adt(def, _) = ty.kind() + && let field = def.all_fields().nth(field.index())? + // Use the HIR types to construct the diagnostic message. + && let node = tcx.hir().find_by_def_id(field.did.as_local()?)? + // Now we're dealing with the actual struct that we're going to suggest a change to, + // we can expect a field that is an immutable reference to a type. + && let hir::Node::Field(field) = node + && let hir::TyKind::Rptr(lt, hir::MutTy { mutbl: hir::Mutability::Not, ty }) = field.ty.kind + { + return Some(lt.span.between(ty.span)); } None diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index 64f05f6004f53..369aef6798ba6 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -140,14 +140,11 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { /// Returns `true` if a closure is inferred to be an `FnMut` closure. fn is_closure_fn_mut(&self, fr: RegionVid) -> bool { - if let Some(ty::ReFree(free_region)) = self.to_error_region(fr).as_deref() { - if let ty::BoundRegionKind::BrEnv = free_region.bound_region { - if let DefiningTy::Closure(_, substs) = - self.regioncx.universal_regions().defining_ty - { - return substs.as_closure().kind() == ty::ClosureKind::FnMut; - } - } + if let Some(ty::ReFree(free_region)) = self.to_error_region(fr).as_deref() + && let ty::BoundRegionKind::BrEnv = free_region.bound_region + && let DefiningTy::Closure(_, substs) = self.regioncx.universal_regions().defining_ty + { + return substs.as_closure().kind() == ty::ClosureKind::FnMut; } false diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index c489f409fb53b..82d2d0dd4557f 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -1,15 +1,16 @@ //! This query borrow-checks the MIR to (further) ensure it is not broken. +#![allow(rustc::potential_query_instability)] #![feature(bool_to_option)] #![feature(box_patterns)] #![feature(crate_visibility_modifier)] +#![feature(let_chains)] #![feature(let_else)] #![feature(min_specialization)] #![feature(stmt_expr_attributes)] #![feature(trusted_step)] #![feature(try_blocks)] #![recursion_limit = "256"] -#![allow(rustc::potential_query_instability)] #[macro_use] extern crate rustc_middle; @@ -159,16 +160,14 @@ fn do_mir_borrowck<'a, 'tcx>( for var_debug_info in &input_body.var_debug_info { if let VarDebugInfoContents::Place(place) = var_debug_info.value { if let Some(local) = place.as_local() { - if let Some(prev_name) = local_names[local] { - if var_debug_info.name != prev_name { - span_bug!( - var_debug_info.source_info.span, - "local {:?} has many names (`{}` vs `{}`)", - local, - prev_name, - var_debug_info.name - ); - } + if let Some(prev_name) = local_names[local] && var_debug_info.name != prev_name { + span_bug!( + var_debug_info.source_info.span, + "local {:?} has many names (`{}` vs `{}`)", + local, + prev_name, + var_debug_info.name + ); } local_names[local] = Some(var_debug_info.name); } diff --git a/compiler/rustc_borrowck/src/places_conflict.rs b/compiler/rustc_borrowck/src/places_conflict.rs index 773e9e90b0c6b..5a935c3b8fbfd 100644 --- a/compiler/rustc_borrowck/src/places_conflict.rs +++ b/compiler/rustc_borrowck/src/places_conflict.rs @@ -60,10 +60,8 @@ pub(super) fn borrow_conflicts_with_place<'tcx>( // This Local/Local case is handled by the more general code below, but // it's so common that it's a speed win to check for it first. - if let Some(l1) = borrow_place.as_local() { - if let Some(l2) = access_place.as_local() { - return l1 == l2; - } + if let Some(l1) = borrow_place.as_local() && let Some(l2) = access_place.as_local() { + return l1 == l2; } place_components_conflict(tcx, body, borrow_place, borrow_kind, access_place, access, bias)