diff options
43 files changed, 492 insertions, 421 deletions
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index b945d687043..9e5fb674772 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -785,13 +785,22 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { issued_borrow: &BorrowData<'tcx>, explanation: BorrowExplanation, ) { - let used_in_call = - matches!(explanation, BorrowExplanation::UsedLater(LaterUseKind::Call, _call_span, _)); + let used_in_call = matches!( + explanation, + BorrowExplanation::UsedLater(LaterUseKind::Call | LaterUseKind::Other, _call_span, _) + ); if !used_in_call { debug!("not later used in call"); return; } + let use_span = + if let BorrowExplanation::UsedLater(LaterUseKind::Other, use_span, _) = explanation { + Some(use_span) + } else { + None + }; + let outer_call_loc = if let TwoPhaseActivation::ActivatedAt(loc) = issued_borrow.activation_location { loc @@ -835,7 +844,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { debug!("===> outer_call_loc = {:?}, inner_call_loc = {:?}", outer_call_loc, inner_call_loc); let inner_call_span = inner_call_term.source_info.span; - let outer_call_span = outer_call_stmt.either(|s| s.source_info, |t| t.source_info).span; + let outer_call_span = match use_span { + Some(span) => span, + None => outer_call_stmt.either(|s| s.source_info, |t| t.source_info).span, + }; if outer_call_span == inner_call_span || !outer_call_span.contains(inner_call_span) { // FIXME: This stops the suggestion in some cases where it should be emitted. // Fix the spans for those cases so it's emitted correctly. @@ -845,8 +857,20 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ); return; } - err.span_help(inner_call_span, "try adding a local storing this argument..."); - err.span_help(outer_call_span, "...and then using that local as the argument to this call"); + err.span_help( + inner_call_span, + &format!( + "try adding a local storing this{}...", + if use_span.is_some() { "" } else { " argument" } + ), + ); + err.span_help( + outer_call_span, + &format!( + "...and then using that local {}", + if use_span.is_some() { "here" } else { "as the argument to this call" } + ), + ); } fn suggest_split_at_mut_if_applicable( @@ -1912,10 +1936,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } else { "cannot assign twice to immutable variable" }; - if span != assigned_span { - if !from_arg { - err.span_label(assigned_span, format!("first assignment to {}", place_description)); - } + if span != assigned_span && !from_arg { + err.span_label(assigned_span, format!("first assignment to {}", place_description)); } if let Some(decl) = local_decl && let Some(name) = local_name diff --git a/compiler/rustc_error_messages/locales/en-US/diagnostics.ftl b/compiler/rustc_error_messages/locales/en-US/diagnostics.ftl index 336e7a66857..2b1deb34304 100644 --- a/compiler/rustc_error_messages/locales/en-US/diagnostics.ftl +++ b/compiler/rustc_error_messages/locales/en-US/diagnostics.ftl @@ -62,6 +62,7 @@ typeck-functional-record-update-on-non-struct = typeck-typeof-reserved-keyword-used = `typeof` is a reserved keyword but unimplemented + .suggestion = consider replacing `typeof(...)` with an actual type .label = reserved keyword typeck-return-stmt-outside-of-fn-body = diff --git a/compiler/rustc_hir/src/definitions.rs b/compiler/rustc_hir/src/definitions.rs index c62d3b9be2f..4908992085a 100644 --- a/compiler/rustc_hir/src/definitions.rs +++ b/compiler/rustc_hir/src/definitions.rs @@ -147,6 +147,11 @@ impl DefKey { // DefPathHashes in this DefPathTable. DefPathHash::new(parent.stable_crate_id(), local_hash) } + + #[inline] + pub fn get_opt_name(&self) -> Option<Symbol> { + self.disambiguated_data.data.get_opt_name() + } } /// A pair of `DefPathData` and an integer disambiguator. The integer is diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 561653f3beb..65796fbc698 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -1,5 +1,5 @@ use crate::hir::{ModuleItems, Owner}; -use crate::ty::TyCtxt; +use crate::ty::{DefIdTree, TyCtxt}; use rustc_ast as ast; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; @@ -545,23 +545,21 @@ impl<'hir> Map<'hir> { }); } - pub fn ty_param_owner(self, id: HirId) -> LocalDefId { - match self.get(id) { - Node::Item(&Item { kind: ItemKind::Trait(..) | ItemKind::TraitAlias(..), .. }) => { - id.expect_owner() - } - Node::GenericParam(_) => self.get_parent_item(id), - _ => bug!("ty_param_owner: {} not a type parameter", self.node_to_string(id)), + pub fn ty_param_owner(self, def_id: LocalDefId) -> LocalDefId { + let def_kind = self.tcx.def_kind(def_id); + match def_kind { + DefKind::Trait | DefKind::TraitAlias => def_id, + DefKind::TyParam | DefKind::ConstParam => self.tcx.local_parent(def_id).unwrap(), + _ => bug!("ty_param_owner: {:?} is a {:?} not a type parameter", def_id, def_kind), } } - pub fn ty_param_name(self, id: HirId) -> Symbol { - match self.get(id) { - Node::Item(&Item { kind: ItemKind::Trait(..) | ItemKind::TraitAlias(..), .. }) => { - kw::SelfUpper - } - Node::GenericParam(param) => param.name.ident().name, - _ => bug!("ty_param_name: {} not a type parameter", self.node_to_string(id)), + pub fn ty_param_name(self, def_id: LocalDefId) -> Symbol { + let def_kind = self.tcx.def_kind(def_id); + match def_kind { + DefKind::Trait | DefKind::TraitAlias => kw::SelfUpper, + DefKind::TyParam | DefKind::ConstParam => self.tcx.item_name(def_id.to_def_id()), + _ => bug!("ty_param_name: {:?} is a {:?} not a type parameter", def_id, def_kind), } } diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 89761bf4e27..bbe1d367b77 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -517,10 +517,7 @@ rustc_queries! { /// To avoid cycles within the predicates of a single item we compute /// per-type-parameter predicates for resolving `T::AssocTy`. query type_param_predicates(key: (DefId, LocalDefId, rustc_span::symbol::Ident)) -> ty::GenericPredicates<'tcx> { - desc { |tcx| "computing the bounds for type parameter `{}`", { - let id = tcx.hir().local_def_id_to_hir_id(key.1); - tcx.hir().ty_param_name(id) - }} + desc { |tcx| "computing the bounds for type parameter `{}`", tcx.hir().ty_param_name(key.1) } } query trait_def(key: DefId) -> ty::TraitDef { diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 399817d59c4..c2accea11ba 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1991,27 +1991,25 @@ impl<'tcx> TyCtxt<'tcx> { .filter(|item| item.kind == AssocKind::Fn && item.defaultness.has_value()) } - fn item_name_from_hir(self, def_id: DefId) -> Option<Ident> { - self.hir().get_if_local(def_id).and_then(|node| node.ident()) - } - - fn item_name_from_def_id(self, def_id: DefId) -> Option<Symbol> { + fn opt_item_name(self, def_id: DefId) -> Option<Symbol> { if def_id.index == CRATE_DEF_INDEX { Some(self.crate_name(def_id.krate)) } else { let def_key = self.def_key(def_id); match def_key.disambiguated_data.data { // The name of a constructor is that of its parent. - rustc_hir::definitions::DefPathData::Ctor => self.item_name_from_def_id(DefId { - krate: def_id.krate, - index: def_key.parent.unwrap(), - }), - _ => def_key.disambiguated_data.data.get_opt_name(), + rustc_hir::definitions::DefPathData::Ctor => self + .opt_item_name(DefId { krate: def_id.krate, index: def_key.parent.unwrap() }), + // The name of opaque types only exists in HIR. + rustc_hir::definitions::DefPathData::ImplTrait + if let Some(def_id) = def_id.as_local() => + self.hir().opt_name(self.hir().local_def_id_to_hir_id(def_id)), + _ => def_key.get_opt_name(), } } } - /// Look up the name of an item across crates. This does not look at HIR. + /// Look up the name of a definition across crates. This does not look at HIR. /// /// When possible, this function should be used for cross-crate lookups over /// [`opt_item_name`] to avoid invalidating the incremental cache. If you @@ -2023,18 +2021,21 @@ impl<'tcx> TyCtxt<'tcx> { pub fn item_name(self, id: DefId) -> Symbol { // Look at cross-crate items first to avoid invalidating the incremental cache // unless we have to. - self.item_name_from_def_id(id).unwrap_or_else(|| { + self.opt_item_name(id).unwrap_or_else(|| { bug!("item_name: no name for {:?}", self.def_path(id)); }) } - /// Look up the name and span of an item or [`Node`]. + /// Look up the name and span of a definition. /// /// See [`item_name`][Self::item_name] for more information. - pub fn opt_item_name(self, def_id: DefId) -> Option<Ident> { - // Look at the HIR first so the span will be correct if this is a local item. - self.item_name_from_hir(def_id) - .or_else(|| self.item_name_from_def_id(def_id).map(Ident::with_dummy_span)) + pub fn opt_item_ident(self, def_id: DefId) -> Option<Ident> { + let def = self.opt_item_name(def_id)?; + let span = def_id + .as_local() + .and_then(|id| self.def_ident_span(id)) + .unwrap_or(rustc_span::DUMMY_SP); + Some(Ident::new(def, span)) } pub fn opt_associated_item(self, def_id: DefId) -> Option<&'tcx AssocItem> { diff --git a/compiler/rustc_mir_transform/src/deref_separator.rs b/compiler/rustc_mir_transform/src/deref_separator.rs index 79aac163550..24b626ad966 100644 --- a/compiler/rustc_mir_transform/src/deref_separator.rs +++ b/compiler/rustc_mir_transform/src/deref_separator.rs @@ -11,6 +11,8 @@ pub fn deref_finder<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { for (i, stmt) in data.statements.iter_mut().enumerate() { match stmt.kind { StatementKind::Assign(box (og_place, Rvalue::Ref(region, borrow_knd, place))) => { + let mut place_local = place.local; + let mut last_len = 0; for (idx, (p_ref, p_elem)) in place.iter_projections().enumerate() { if p_elem == ProjectionElem::Deref && !p_ref.projection.is_empty() { // The type that we are derefing. @@ -23,15 +25,18 @@ pub fn deref_finder<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { patch.add_statement(loc, StatementKind::StorageLive(temp)); // We are adding current p_ref's projections to our - // temp value. - let deref_place = - Place::from(p_ref.local).project_deeper(p_ref.projection, tcx); + // temp value, excluding projections we already covered. + let deref_place = Place::from(place_local) + .project_deeper(&p_ref.projection[last_len..], tcx); patch.add_assign( loc, Place::from(temp), Rvalue::Use(Operand::Move(deref_place)), ); + place_local = temp; + last_len = p_ref.projection.len(); + // We are creating a place by using our temp value's location // and copying derefed values which we need to create new statement. let temp_place = @@ -50,11 +55,6 @@ pub fn deref_finder<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { // Since our job with the temp is done it should be gone let loc = Location { block: block, statement_index: i + 1 }; patch.add_statement(loc, StatementKind::StorageDead(temp)); - - // As all projections are off the base projection, if there are - // multiple derefs in the middle of projection, it might cause - // unsoundness, to not let that happen we break the loop. - break; } } } diff --git a/compiler/rustc_monomorphize/src/polymorphize.rs b/compiler/rustc_monomorphize/src/polymorphize.rs index 489d513c104..cf13c856a71 100644 --- a/compiler/rustc_monomorphize/src/polymorphize.rs +++ b/compiler/rustc_monomorphize/src/polymorphize.rs @@ -201,7 +201,7 @@ fn emit_unused_generic_params_error<'tcx>( return; } - let fn_span = match tcx.opt_item_name(def_id) { + let fn_span = match tcx.opt_item_ident(def_id) { Some(ident) => ident.span, _ => tcx.def_span(def_id), }; diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 7c3f306717a..c920c80d1bb 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -2064,7 +2064,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { ObligationCauseCode::BindingObligation(item_def_id, span) => { let item_name = tcx.def_path_str(item_def_id); let mut multispan = MultiSpan::from(span); - if let Some(ident) = tcx.opt_item_name(item_def_id) { + if let Some(ident) = tcx.opt_item_ident(item_def_id) { let sm = tcx.sess.source_map(); let same_line = match (sm.lookup_line(ident.span.hi()), sm.lookup_line(span.lo())) { @@ -2267,7 +2267,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { if !is_upvar_tys_infer_tuple { let msg = format!("required because it appears within the type `{}`", ty); match ty.kind() { - ty::Adt(def, _) => match self.tcx.opt_item_name(def.did()) { + ty::Adt(def, _) => match self.tcx.opt_item_ident(def.did()) { Some(ident) => err.span_note(ident.span, &msg), None => err.note(&msg), }, @@ -2475,7 +2475,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { ); let sp = self .tcx - .opt_item_name(trait_item_def_id) + .opt_item_ident(trait_item_def_id) .map(|i| i.span) .unwrap_or_else(|| self.tcx.def_span(trait_item_def_id)); let mut assoc_span: MultiSpan = sp.into(); @@ -2486,7 +2486,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { if let Some(ident) = self .tcx .opt_associated_item(trait_item_def_id) - .and_then(|i| self.tcx.opt_item_name(i.container.id())) + .and_then(|i| self.tcx.opt_item_ident(i.container.id())) { assoc_span.push_span_label(ident.span, "in this trait"); } @@ -2511,7 +2511,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { if let Some(ident) = self .tcx .opt_associated_item(trait_item_def_id) - .and_then(|i| self.tcx.opt_item_name(i.container.id())) + .and_then(|i| self.tcx.opt_item_ident(i.container.id())) { assoc_span.push_span_label(ident.span, "in this trait"); } diff --git a/compiler/rustc_typeck/src/astconv/generics.rs b/compiler/rustc_typeck/src/astconv/generics.rs index a50301dbc87..5f5b81b8924 100644 --- a/compiler/rustc_typeck/src/astconv/generics.rs +++ b/compiler/rustc_typeck/src/astconv/generics.rs @@ -82,8 +82,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } Res::Def(DefKind::TyParam, src_def_id) => { if let Some(param_local_id) = param.def_id.as_local() { - let param_hir_id = tcx.hir().local_def_id_to_hir_id(param_local_id); - let param_name = tcx.hir().ty_param_name(param_hir_id); + let param_name = tcx.hir().ty_param_name(param_local_id); let param_type = tcx.infer_ctxt().enter(|infcx| { infcx.resolve_numeric_literals_with_default(tcx.type_of(param.def_id)) }); diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index b6287031665..6bae0f2eac9 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -1620,8 +1620,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { debug!("find_bound_for_assoc_item: predicates={:#?}", predicates); - let param_hir_id = tcx.hir().local_def_id_to_hir_id(ty_param_def_id); - let param_name = tcx.hir().ty_param_name(param_hir_id); + let param_name = tcx.hir().ty_param_name(ty_param_def_id); self.one_bound_for_assoc_type( || { traits::transitive_bounds_that_define_assoc_type( @@ -2265,12 +2264,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { assert_eq!(opt_self_ty, None); self.prohibit_generics(path.segments); - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); - let item_id = tcx.hir().get_parent_node(hir_id); - let item_def_id = tcx.hir().local_def_id(item_id); + let def_id = def_id.expect_local(); + let item_def_id = tcx.hir().ty_param_owner(def_id); let generics = tcx.generics_of(item_def_id); - let index = generics.param_def_id_to_index[&def_id]; - tcx.mk_ty_param(index, tcx.hir().name(hir_id)) + let index = generics.param_def_id_to_index[&def_id.to_def_id()]; + tcx.mk_ty_param(index, tcx.hir().ty_param_name(def_id)) } Res::SelfTy { trait_: Some(_), alias_to: None } => { // `Self` in trait or type alias. @@ -2462,8 +2460,16 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { self.normalize_ty(ast_ty.span, array_ty) } hir::TyKind::Typeof(ref e) => { - tcx.sess.emit_err(TypeofReservedKeywordUsed { span: ast_ty.span }); - tcx.type_of(tcx.hir().local_def_id(e.hir_id)) + let ty = tcx.type_of(tcx.hir().local_def_id(e.hir_id)); + let span = ast_ty.span; + tcx.sess.emit_err(TypeofReservedKeywordUsed { + span, + ty, + opt_sugg: Some((span, Applicability::MachineApplicable)) + .filter(|_| ty.is_suggestable()), + }); + + ty } hir::TyKind::Infer => { // Infer also appears as the type of arguments or return diff --git a/compiler/rustc_typeck/src/check/cast.rs b/compiler/rustc_typeck/src/check/cast.rs index 6091b8fee00..e73b9c979eb 100644 --- a/compiler/rustc_typeck/src/check/cast.rs +++ b/compiler/rustc_typeck/src/check/cast.rs @@ -1012,7 +1012,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { err.help(msg); } err.help( - "if you can't comply with strict provenance and need to expose the pointer\ + "if you can't comply with strict provenance and need to expose the pointer \ provenance you can use `.expose_addr()` instead" ); diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index 82641a489f6..669521bc472 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -2195,7 +2195,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { None => return, }; let param_span = self.tcx.hir().span(param_hir_id); - let param_name = self.tcx.hir().ty_param_name(param_hir_id); + let param_name = self.tcx.hir().ty_param_name(param_def_id.expect_local()); err.span_label(param_span, &format!("type parameter '{}' declared here", param_name)); } diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs b/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs index 55a5eb966c2..77cba1c22c4 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs @@ -184,8 +184,7 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { _: Ident, ) -> ty::GenericPredicates<'tcx> { let tcx = self.tcx; - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); - let item_def_id = tcx.hir().ty_param_owner(hir_id); + let item_def_id = tcx.hir().ty_param_owner(def_id.expect_local()); let generics = tcx.generics_of(item_def_id); let index = generics.param_def_id_to_index[&def_id]; ty::GenericPredicates { diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index ec783a16ef7..026151ce7df 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -558,10 +558,10 @@ fn type_param_predicates( // `where T: Foo`. let param_id = tcx.hir().local_def_id_to_hir_id(def_id); - let param_owner = tcx.hir().ty_param_owner(param_id); + let param_owner = tcx.hir().ty_param_owner(def_id); let generics = tcx.generics_of(param_owner); let index = generics.param_def_id_to_index[&def_id.to_def_id()]; - let ty = tcx.mk_ty_param(index, tcx.hir().ty_param_name(param_id)); + let ty = tcx.mk_ty_param(index, tcx.hir().ty_param_name(def_id)); // Don't look for bounds where the type parameter isn't in scope. let parent = if item_def_id == param_owner.to_def_id() { diff --git a/compiler/rustc_typeck/src/errors.rs b/compiler/rustc_typeck/src/errors.rs index 0b78aea9f05..1088be5f566 100644 --- a/compiler/rustc_typeck/src/errors.rs +++ b/compiler/rustc_typeck/src/errors.rs @@ -1,5 +1,7 @@ //! Errors emitted by typeck. +use rustc_errors::Applicability; use rustc_macros::SessionDiagnostic; +use rustc_middle::ty::Ty; use rustc_span::{symbol::Ident, Span, Symbol}; #[derive(SessionDiagnostic)] @@ -127,10 +129,13 @@ pub struct FunctionalRecordUpdateOnNonStruct { #[derive(SessionDiagnostic)] #[error(code = "E0516", slug = "typeck-typeof-reserved-keyword-used")] -pub struct TypeofReservedKeywordUsed { +pub struct TypeofReservedKeywordUsed<'tcx> { + pub ty: Ty<'tcx>, #[primary_span] #[label] pub span: Span, + #[suggestion_verbose(message = "suggestion", code = "{ty}")] + pub opt_sugg: Option<(Span, Applicability)>, } #[derive(SessionDiagnostic)] diff --git a/library/core/src/char/convert.rs b/library/core/src/char/convert.rs index 4ee0310b361..778f06aeb63 100644 --- a/library/core/src/char/convert.rs +++ b/library/core/src/char/convert.rs @@ -6,52 +6,10 @@ use crate::fmt; use crate::mem::transmute; use crate::str::FromStr; -/// Converts a `u32` to a `char`. -/// -/// Note that all [`char`]s are valid [`u32`]s, and can be cast to one with -/// `as`: -/// -/// ``` -/// let c = '💯'; -/// let i = c as u32; -/// -/// assert_eq!(128175, i); -/// ``` -/// -/// However, the reverse is not true: not all valid [`u32`]s are valid -/// [`char`]s. `from_u32()` will return `None` if the input is not a valid value -/// for a [`char`]. -/// -/// For an unsafe version of this function which ignores these checks, see -/// [`from_u32_unchecked`]. -/// -/// # Examples -/// -/// Basic usage: -/// -/// ``` -/// use std::char; -/// -/// let c = char::from_u32(0x2764); -/// -/// assert_eq!(Some('❤'), c); -/// ``` -/// -/// Returning `None` when the input is not a valid [`char`]: -/// -/// ``` -/// use std::char; -/// -/// let c = char::from_u32(0x110000); -/// -/// assert_eq!(None, c); -/// ``` -#[doc(alias = "chr")] +/// Converts a `u32` to a `char`. See [`char::from_u32`]. #[must_use] #[inline] -#[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_unstable(feature = "const_char_convert", issue = "89259")] -pub const fn from_u32(i: u32) -> Option<char> { +pub(super) const fn from_u32(i: u32) -> Option<char> { // FIXME: once Result::ok is const fn, use it here match char_try_from_u32(i) { Ok(c) => Some(c), @@ -59,44 +17,11 @@ pub const fn from_u32(i: u32) -> Option<char> { } } -/// Converts a `u32` to a `char`, ignoring validity. -/// -/// Note that all [`char`]s are valid [`u32`]s, and can be cast to one with -/// `as`: -/// -/// ``` -/// let c = '💯'; -/// let i = c as u32; -/// -/// assert_eq!(128175, i); -/// ``` -/// -/// However, the reverse is not true: not all valid [`u32`]s are valid -/// [`char`]s. `from_u32_unchecked()` will ignore this, and blindly cast to -/// [`char`], possibly creating an invalid one. -/// -/// # Safety -/// -/// This function is unsafe, as it may construct invalid `char` values. -/// -/// For a safe version of this function, see the [`from_u32`] function. -/// -/// # Examples -/// -/// Basic usage: -/// -/// ``` -/// use std::char; -/// -/// let c = unsafe { char::from_u32_unchecked(0x2764) }; -/// -/// assert_eq!('❤', c); -/// ``` +/// Converts a `u32` to a `char`, ignoring validity. See [`char::from_u32_unchecked`]. +#[rustc_const_unstable(feature = "const_char_convert", issue = "89259")] #[inline] #[must_use] -#[stable(feature = "char_from_unchecked", since = "1.5.0")] -#[rustc_const_unstable(feature = "const_char_convert", issue = "89259")] -pub const unsafe fn from_u32_unchecked(i: u32) -> char { +pub(super) const unsafe fn from_u32_unchecked(i: u32) -> char { // SAFETY: the caller must guarantee that `i` is a valid char value. if cfg!(debug_assertions) { char::from_u32(i).unwrap() } else { unsafe { transmute(i) } } } @@ -317,60 +242,10 @@ impl fmt::Display for CharTryFromError { } } -/// Converts a digit in the given radix to a `char`. -/// -/// A 'radix' here is sometimes also called a 'base'. A radix of two -/// indicates a binary number, a radix of ten, decimal, and a radix of -/// sixteen, hexadecimal, to give some common values. Arbitrary -/// radices are supported. -/// -/// `from_digit()` will return `None` if the input is not a digit in -/// the given radix. -/// -/// # Panics -/// -/// Panics if given a radix larger than 36. -/// -/// # Examples -/// -/// Basic usage: -/// -/// ``` -/// use std::char; -/// -/// let c = char::from_digit(4, 10); -/// -/// assert_eq!(Some('4'), c); -/// -/// // Decimal 11 is a single digit in base 16 -/// let c = char::from_digit(11, 16); -/// -/// assert_eq!(Some('b'), c); -/// ``` -/// -/// Returning `None` when the input is not a digit: -/// -/// ``` -/// use std::char; -/// -/// let c = char::from_digit(20, 10); -/// -/// assert_eq!(None, c); -/// ``` -/// -/// Passing a large radix, causing a panic: -/// -/// ```should_panic -/// use std::char; -/// -/// // this panics -/// let c = char::from_digit(1, 37); -/// ``` +/// Converts a digit in the given radix to a `char`. See [`char::from_digit`]. #[inline] #[must_use] -#[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_unstable(feature = "const_char_convert", issue = "89259")] -pub const fn from_digit(num: u32, radix: u32) -> Option<char> { +pub(super) const fn from_digit(num: u32, radix: u32) -> Option<char> { if radix > 36 { panic!("from_digit: radix is too high (maximum 36)"); } diff --git a/library/core/src/char/decode.rs b/library/core/src/char/decode.rs index 794c9c13cc3..71297acd171 100644 --- a/library/core/src/char/decode.rs +++ b/library/core/src/char/decode.rs @@ -30,54 +30,9 @@ pub struct DecodeUtf16Error { } /// Creates an iterator over the UTF-16 encoded code points in `iter`, -/// returning unpaired surrogates as `Err`s. -/// -/// # Examples -/// -/// Basic usage: -/// -/// ``` -/// use std::char::decode_utf16; -/// -/// // 𝄞mus<invalid>ic<invalid> -/// let v = [ -/// 0xD834, 0xDD1E, 0x006d, 0x0075, 0x0073, 0xDD1E, 0x0069, 0x0063, 0xD834, -/// ]; -/// -/// assert_eq!( -/// decode_utf16(v.iter().cloned()) -/// .map(|r| r.map_err(|e| e.unpaired_surrogate())) -/// .collect::<Vec<_>>(), -/// vec![ -/// Ok('𝄞'), -/// Ok('m'), Ok('u'), Ok('s'), -/// Err(0xDD1E), -/// Ok('i'), Ok('c'), -/// Err(0xD834) -/// ] -/// ); -/// ``` -/// -/// A lossy decoder can be obtained by replacing `Err` results with the replacement character: -/// -/// ``` -/// use std::char::{decode_utf16, REPLACEMENT_CHARACTER}; -/// -/// // 𝄞mus<invalid>ic<invalid> -/// let v = [ -/// 0xD834, 0xDD1E, 0x006d, 0x0075, 0x0073, 0xDD1E, 0x0069, 0x0063, 0xD834, -/// ]; -/// -/// assert_eq!( -/// decode_utf16(v.iter().cloned()) -/// .map(|r| r.unwrap_or(REPLACEMENT_CHARACTER)) -/// .collect::<String>(), -/// "𝄞mus�ic�" -/// ); -/// ``` -#[stable(feature = "decode_utf16", since = "1.9.0")] +/// returning unpaired surrogates as `Err`s. See [`char::decode_utf16`]. #[inline] -pub fn decode_utf16<I: IntoIterator<Item = u16>>(iter: I) -> DecodeUtf16<I::IntoIter> { +pub(super) fn decode_utf16<I: IntoIterator<Item = u16>>(iter: I) -> DecodeUtf16<I::IntoIter> { DecodeUtf16 { iter: iter.into_iter(), buf: None } } diff --git a/library/core/src/char/mod.rs b/library/core/src/char/mod.rs index 9364ac4f3ec..0df23e7bbe6 100644 --- a/library/core/src/char/mod.rs +++ b/library/core/src/char/mod.rs @@ -23,18 +23,12 @@ mod decode; mod methods; // stable re-exports -#[stable(feature = "char_from_unchecked", since = "1.5.0")] -pub use self::convert::from_u32_unchecked; #[stable(feature = "try_from", since = "1.34.0")] pub use self::convert::CharTryFromError; #[stable(feature = "char_from_str", since = "1.20.0")] pub use self::convert::ParseCharError; -#[stable(feature = "rust1", since = "1.0.0")] -pub use self::convert::{from_digit, from_u32}; #[stable(feature = "decode_utf16", since = "1.9.0")] -pub use self::decode::{decode_utf16, DecodeUtf16, DecodeUtf16Error}; -#[stable(feature = "unicode_version", since = "1.45.0")] -pub use crate::unicode::UNICODE_VERSION; +pub use self::decode::{DecodeUtf16, DecodeUtf16Error}; // perma-unstable re-exports #[unstable(feature = "char_internals", reason = "exposed only for libstd", issue = "none")] @@ -89,30 +83,57 @@ const MAX_THREE_B: u32 = 0x10000; Cn Unassigned a reserved unassigned code point or a noncharacter */ -/// The highest valid code point a `char` can have, `'\u{10FFFF}'`. -/// -/// # Examples -/// -/// ``` -/// # fn something_which_returns_char() -> char { 'a' } -/// let c: char = something_which_returns_char(); -/// assert!(c <= char::MAX); -/// -/// let value_at_max = char::MAX as u32; -/// assert_eq!(char::from_u32(value_at_max), Some('\u{10FFFF}')); -/// assert_eq!(char::from_u32(value_at_max + 1), None); -/// ``` +/// The highest valid code point a `char` can have, `'\u{10FFFF}'`. Use [`char::MAX`] instead. #[stable(feature = "rust1", since = "1.0.0")] pub const MAX: char = char::MAX; /// `U+FFFD REPLACEMENT CHARACTER` (�) is used in Unicode to represent a -/// decoding error. -/// -/// It can occur, for example, when giving ill-formed UTF-8 bytes to -/// [`String::from_utf8_lossy`](../../std/string/struct.String.html#method.from_utf8_lossy). +/// decoding error. Use [`char::REPLACEMENT_CHARACTER`] instead. #[stable(feature = "decode_utf16", since = "1.9.0")] pub const REPLACEMENT_CHARACTER: char = char::REPLACEMENT_CHARACTER; +/// The version of [Unicode](https://www.unicode.org/) that the Unicode parts of +/// `char` and `str` methods are based on. Use [`char::UNICODE_VERSION`] instead. +#[stable(feature = "unicode_version", since = "1.45.0")] +pub const UNICODE_VERSION: (u8, u8, u8) = char::UNICODE_VERSION; + +/// Creates an iterator over the UTF-16 encoded code points in `iter`, returning +/// unpaired surrogates as `Err`s. Use [`char::decode_utf16`] instead. +#[stable(feature = "decode_utf16", since = "1.9.0")] +#[inline] +pub fn decode_utf16<I: IntoIterator<Item = u16>>(iter: I) -> DecodeUtf16<I::IntoIter> { + self::decode::decode_utf16(iter) +} + +/// Converts a `u32` to a `char`. Use [`char::from_u32`] instead. +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_unstable(feature = "const_char_convert", issue = "89259")] +#[must_use] +#[inline] +pub const fn from_u32(i: u32) -> Option<char> { + self::convert::from_u32(i) +} + +/// Converts a `u32` to a `char`, ignoring validity. Use [`char::from_u32_unchecked`]. +/// instead. +#[stable(feature = "char_from_unchecked", since = "1.5.0")] +#[rustc_const_unstable(feature = "const_char_convert", issue = "89259")] +#[must_use] +#[inline] +pub const unsafe fn from_u32_unchecked(i: u32) -> char { + // SAFETY: the safety contract must be upheld by the caller. + unsafe { self::convert::from_u32_unchecked(i) } +} + +/// Converts a digit in the given radix to a `char`. Use [`char::from_digit`] instead. +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_unstable(feature = "const_char_convert", issue = "89259")] +#[must_use] +#[inline] +pub const fn from_digit(num: u32, radix: u32) -> Option<char> { + self::convert::from_digit(num, radix) +} + /// Returns an iterator that yields the hexadecimal Unicode escape of a /// character, as `char`s. /// diff --git a/library/std/src/sync/mpsc/blocking.rs b/library/std/src/sync/mpsc/blocking.rs index 4c852b8ee81..021df7b096c 100644 --- a/library/std/src/sync/mpsc/blocking.rs +++ b/library/std/src/sync/mpsc/blocking.rs @@ -1,6 +1,5 @@ //! Generic support for building blocking abstractions. -use crate::mem; use crate::sync::atomic::{AtomicBool, Ordering}; use crate::sync::Arc; use crate::thread::{self, Thread}; @@ -47,18 +46,18 @@ impl SignalToken { wake } - /// Converts to an unsafe usize value. Useful for storing in a pipe's state + /// Converts to an unsafe raw pointer. Useful for storing in a pipe's state /// flag. #[inline] - pub unsafe fn cast_to_usize(self) -> usize { - mem::transmute(self.inner) + pub unsafe fn to_raw(self) -> *mut u8 { + Arc::into_raw(self.inner) as *mut u8 } - /// Converts from an unsafe usize value. Useful for retrieving a pipe's state + /// Converts from an unsafe raw pointer. Useful for retrieving a pipe's state /// flag. #[inline] - pub unsafe fn cast_from_usize(signal_ptr: usize) -> SignalToken { - SignalToken { inner: mem::transmute(signal_ptr) } + pub unsafe fn from_raw(signal_ptr: *mut u8) -> SignalToken { + SignalToken { inner: Arc::from_raw(signal_ptr as *mut Inner) } } } diff --git a/library/std/src/sync/mpsc/oneshot.rs b/library/std/src/sync/mpsc/oneshot.rs index 3dcf03f579a..0e259b8aecb 100644 --- a/library/std/src/sync/mpsc/oneshot.rs +++ b/library/std/src/sync/mpsc/oneshot.rs @@ -27,15 +27,15 @@ pub use self::UpgradeResult::*; use crate::cell::UnsafeCell; use crate::ptr; -use crate::sync::atomic::{AtomicUsize, Ordering}; +use crate::sync::atomic::{AtomicPtr, Ordering}; use crate::sync::mpsc::blocking::{self, SignalToken}; use crate::sync::mpsc::Receiver; use crate::time::Instant; // Various states you can find a port in. -const EMPTY: usize = 0; // initial state: no data, no blocked receiver -const DATA: usize = 1; // data ready for receiver to take -const DISCONNECTED: usize = 2; // channel is disconnected OR upgraded +const EMPTY: *mut u8 = ptr::invalid_mut::<u8>(0); // initial state: no data, no blocked receiver +const DATA: *mut u8 = ptr::invalid_mut::<u8>(1); // data ready for receiver to take +const DISCONNECTED: *mut u8 = ptr::invalid_mut::<u8>(2); // channel is disconnected OR upgraded // Any other value represents a pointer to a SignalToken value. The // protocol ensures that when the state moves *to* a pointer, // ownership of the token is given to the packet, and when the state @@ -44,7 +44,7 @@ const DISCONNECTED: usize = 2; // channel is disconnected OR upgraded pub struct Packet<T> { // Internal state of the chan/port pair (stores the blocked thread as well) - state: AtomicUsize, + state: AtomicPtr<u8>, // One-shot data slot location data: UnsafeCell<Option<T>>, // when used for the second time, a oneshot channel must be upgraded, and @@ -75,7 +75,7 @@ impl<T> Packet<T> { Packet { data: UnsafeCell::new(None), upgrade: UnsafeCell::new(NothingSent), - state: AtomicUsize::new(EMPTY), + state: AtomicPtr::new(EMPTY), } } @@ -108,7 +108,7 @@ impl<T> Packet<T> { // There is a thread waiting on the other end. We leave the 'DATA' // state inside so it'll pick it up on the other end. ptr => { - SignalToken::cast_from_usize(ptr).signal(); + SignalToken::from_raw(ptr).signal(); Ok(()) } } @@ -126,7 +126,7 @@ impl<T> Packet<T> { // like we're not empty, then immediately go through to `try_recv`. if self.state.load(Ordering::SeqCst) == EMPTY { let (wait_token, signal_token) = blocking::tokens(); - let ptr = unsafe { signal_token.cast_to_usize() }; + let ptr = unsafe { signal_token.to_raw() }; // race with senders to enter the blocking state if self.state.compare_exchange(EMPTY, ptr, Ordering::SeqCst, Ordering::SeqCst).is_ok() { @@ -142,7 +142,7 @@ impl<T> Packet<T> { } } else { // drop the signal token, since we never blocked - drop(unsafe { SignalToken::cast_from_usize(ptr) }); + drop(unsafe { SignalToken::from_raw(ptr) }); } } @@ -218,7 +218,7 @@ impl<T> Packet<T> { } // If someone's waiting, we gotta wake them up - ptr => UpWoke(SignalToken::cast_from_usize(ptr)), + ptr => UpWoke(SignalToken::from_raw(ptr)), } } } @@ -229,7 +229,7 @@ impl<T> Packet<T> { // If someone's waiting, we gotta wake them up ptr => unsafe { - SignalToken::cast_from_usize(ptr).signal(); + SignalToken::from_raw(ptr).signal(); }, } } @@ -301,7 +301,7 @@ impl<T> Packet<T> { // We woke ourselves up from select. ptr => unsafe { - drop(SignalToken::cast_from_usize(ptr)); + drop(SignalToken::from_raw(ptr)); Ok(false) }, } diff --git a/library/std/src/sync/mpsc/shared.rs b/library/std/src/sync/mpsc/shared.rs index 56162655544..51917bd96bd 100644 --- a/library/std/src/sync/mpsc/shared.rs +++ b/library/std/src/sync/mpsc/shared.rs @@ -15,7 +15,7 @@ use core::intrinsics::abort; use crate::cell::UnsafeCell; use crate::ptr; -use crate::sync::atomic::{AtomicBool, AtomicIsize, AtomicUsize, Ordering}; +use crate::sync::atomic::{AtomicBool, AtomicIsize, AtomicPtr, AtomicUsize, Ordering}; use crate::sync::mpsc::blocking::{self, SignalToken}; use crate::sync::mpsc::mpsc_queue as mpsc; use crate::sync::{Mutex, MutexGuard}; @@ -29,12 +29,13 @@ const MAX_REFCOUNT: usize = (isize::MAX) as usize; const MAX_STEALS: isize = 5; #[cfg(not(test))] const MAX_STEALS: isize = 1 << 20; +const EMPTY: *mut u8 = ptr::null_mut(); // initial state: no data, no blocked receiver pub struct Packet<T> { queue: mpsc::Queue<T>, cnt: AtomicIsize, // How many items are on this channel steals: UnsafeCell<isize>, // How many times has a port received without blocking? - to_wake: AtomicUsize, // SignalToken for wake up + to_wake: AtomicPtr<u8>, // SignalToken for wake up // The number of channels which are currently using this packet. channels: AtomicUsize, @@ -68,7 +69,7 @@ impl<T> Packet<T> { queue: mpsc::Queue::new(), cnt: AtomicIsize::new(0), steals: UnsafeCell::new(0), - to_wake: AtomicUsize::new(0), + to_wake: AtomicPtr::new(EMPTY), channels: AtomicUsize::new(2), port_dropped: AtomicBool::new(false), sender_drain: AtomicIsize::new(0), @@ -93,8 +94,8 @@ impl<T> Packet<T> { pub fn inherit_blocker(&self, token: Option<SignalToken>, guard: MutexGuard<'_, ()>) { if let Some(token) = token { assert_eq!(self.cnt.load(Ordering::SeqCst), 0); - assert_eq!(self.to_wake.load(Ordering::SeqCst), 0); - self.to_wake.store(unsafe { token.cast_to_usize() }, Ordering::SeqCst); + assert_eq!(self.to_wake.load(Ordering::SeqCst), EMPTY); + self.to_wake.store(unsafe { token.to_raw() }, Ordering::SeqCst); self.cnt.store(-1, Ordering::SeqCst); // This store is a little sketchy. What's happening here is that @@ -250,10 +251,10 @@ impl<T> Packet<T> { unsafe { assert_eq!( self.to_wake.load(Ordering::SeqCst), - 0, + EMPTY, "This is a known bug in the Rust standard library. See https://github.com/rust-lang/rust/issues/39364" ); - let ptr = token.cast_to_usize(); + let ptr = token.to_raw(); self.to_wake.store(ptr, Ordering::SeqCst); let steals = ptr::replace(self.steals.get(), 0); @@ -272,8 +273,8 @@ impl<T> Packet<T> { } } - self.to_wake.store(0, Ordering::SeqCst); - drop(SignalToken::cast_from_usize(ptr)); + self.to_wake.store(EMPTY, Ordering::SeqCst); + drop(SignalToken::from_raw(ptr)); Abort } } @@ -415,9 +416,9 @@ impl<T> Packet<T> { // Consumes ownership of the 'to_wake' field. fn take_to_wake(&self) -> SignalToken { let ptr = self.to_wake.load(Ordering::SeqCst); - self.to_wake.store(0, Ordering::SeqCst); - assert!(ptr != 0); - unsafe { SignalToken::cast_from_usize(ptr) } + self.to_wake.store(EMPTY, Ordering::SeqCst); + assert!(ptr != EMPTY); + unsafe { SignalToken::from_raw(ptr) } } //////////////////////////////////////////////////////////////////////////// @@ -462,7 +463,7 @@ impl<T> Packet<T> { let prev = self.bump(steals + 1); if prev == DISCONNECTED { - assert_eq!(self.to_wake.load(Ordering::SeqCst), 0); + assert_eq!(self.to_wake.load(Ordering::SeqCst), EMPTY); true } else { let cur = prev + steals + 1; @@ -470,7 +471,7 @@ impl<T> Packet<T> { if prev < 0 { drop(self.take_to_wake()); } else { - while self.to_wake.load(Ordering::SeqCst) != 0 { + while self.to_wake.load(Ordering::SeqCst) != EMPTY { thread::yield_now(); } } @@ -494,7 +495,7 @@ impl<T> Drop for Packet<T> { // `to_wake`, so this assert cannot be removed with also removing // the `to_wake` assert. assert_eq!(self.cnt.load(Ordering::SeqCst), DISCONNECTED); - assert_eq!(self.to_wake.load(Ordering::SeqCst), 0); + assert_eq!(self.to_wake.load(Ordering::SeqCst), EMPTY); assert_eq!(self.channels.load(Ordering::SeqCst), 0); } } diff --git a/library/std/src/sync/mpsc/stream.rs b/library/std/src/sync/mpsc/stream.rs index 2a1d3f8967e..4c3812c79f6 100644 --- a/library/std/src/sync/mpsc/stream.rs +++ b/library/std/src/sync/mpsc/stream.rs @@ -17,7 +17,7 @@ use crate::ptr; use crate::thread; use crate::time::Instant; -use crate::sync::atomic::{AtomicBool, AtomicIsize, AtomicUsize, Ordering}; +use crate::sync::atomic::{AtomicBool, AtomicIsize, AtomicPtr, Ordering}; use crate::sync::mpsc::blocking::{self, SignalToken}; use crate::sync::mpsc::spsc_queue as spsc; use crate::sync::mpsc::Receiver; @@ -27,6 +27,7 @@ const DISCONNECTED: isize = isize::MIN; const MAX_STEALS: isize = 5; #[cfg(not(test))] const MAX_STEALS: isize = 1 << 20; +const EMPTY: *mut u8 = ptr::null_mut(); // initial state: no data, no blocked receiver pub struct Packet<T> { // internal queue for all messages @@ -34,8 +35,8 @@ pub struct Packet<T> { } struct ProducerAddition { - cnt: AtomicIsize, // How many items are on this channel - to_wake: AtomicUsize, // SignalToken for the blocked thread to wake up + cnt: AtomicIsize, // How many items are on this channel + to_wake: AtomicPtr<u8>, // SignalToken for the blocked thread to wake up port_dropped: AtomicBool, // flag if the channel has been destroyed. } @@ -71,7 +72,7 @@ impl<T> Packet<T> { 128, ProducerAddition { cnt: AtomicIsize::new(0), - to_wake: AtomicUsize::new(0), + to_wake: AtomicPtr::new(EMPTY), port_dropped: AtomicBool::new(false), }, @@ -147,17 +148,17 @@ impl<T> Packet<T> { // Consumes ownership of the 'to_wake' field. fn take_to_wake(&self) -> SignalToken { let ptr = self.queue.producer_addition().to_wake.load(Ordering::SeqCst); - self.queue.producer_addition().to_wake.store(0, Ordering::SeqCst); - assert!(ptr != 0); - unsafe { SignalToken::cast_from_usize(ptr) } + self.queue.producer_addition().to_wake.store(EMPTY, Ordering::SeqCst); + assert!(ptr != EMPTY); + unsafe { SignalToken::from_raw(ptr) } } // Decrements the count on the channel for a sleeper, returning the sleeper // back if it shouldn't sleep. Note that this is the location where we take // steals into account. fn decrement(&self, token: SignalToken) -> Result<(), SignalToken> { - assert_eq!(self.queue.producer_addition().to_wake.load(Ordering::SeqCst), 0); - let ptr = unsafe { token.cast_to_usize() }; + assert_eq!(self.queue.producer_addition().to_wake.load(Ordering::SeqCst), EMPTY); + let ptr = unsafe { token.to_raw() }; self.queue.producer_addition().to_wake.store(ptr, Ordering::SeqCst); let steals = unsafe { ptr::replace(self.queue.consumer_addition().steals.get(), 0) }; @@ -176,8 +177,8 @@ impl<T> Packet<T> { } } - self.queue.producer_addition().to_wake.store(0, Ordering::SeqCst); - Err(unsafe { SignalToken::cast_from_usize(ptr) }) + self.queue.producer_addition().to_wake.store(EMPTY, Ordering::SeqCst); + Err(unsafe { SignalToken::from_raw(ptr) }) } pub fn recv(&self, deadline: Option<Instant>) -> Result<T, Failure<T>> { @@ -376,7 +377,7 @@ impl<T> Packet<T> { // of time until the data is actually sent. if was_upgrade { assert_eq!(unsafe { *self.queue.consumer_addition().steals.get() }, 0); - assert_eq!(self.queue.producer_addition().to_wake.load(Ordering::SeqCst), 0); + assert_eq!(self.queue.producer_addition().to_wake.load(Ordering::SeqCst), EMPTY); return Ok(true); } @@ -389,7 +390,7 @@ impl<T> Packet<T> { // If we were previously disconnected, then we know for sure that there // is no thread in to_wake, so just keep going let has_data = if prev == DISCONNECTED { - assert_eq!(self.queue.producer_addition().to_wake.load(Ordering::SeqCst), 0); + assert_eq!(self.queue.producer_addition().to_wake.load(Ordering::SeqCst), EMPTY); true // there is data, that data is that we're disconnected } else { let cur = prev + steals + 1; @@ -412,7 +413,7 @@ impl<T> Packet<T> { if prev < 0 { drop(self.take_to_wake()); } else { - while self.queue.producer_addition().to_wake.load(Ordering::SeqCst) != 0 { + while self.queue.producer_addition().to_wake.load(Ordering::SeqCst) != EMPTY { thread::yield_now(); } } @@ -451,6 +452,6 @@ impl<T> Drop for Packet<T> { // `to_wake`, so this assert cannot be removed with also removing // the `to_wake` assert. assert_eq!(self.queue.producer_addition().cnt.load(Ordering::SeqCst), DISCONNECTED); - assert_eq!(self.queue.producer_addition().to_wake.load(Ordering::SeqCst), 0); + assert_eq!(self.queue.producer_addition().to_wake.load(Ordering::SeqCst), EMPTY); } } diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 0b6bdf47419..00dc7da275a 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -1097,8 +1097,19 @@ class RustBuild(object): def update_submodules(self): """Update submodules""" - if (not os.path.exists(os.path.join(self.rust_root, ".git"))) or \ - self.get_toml('submodules') == "false": + has_git = os.path.exists(os.path.join(self.rust_root, ".git")) + # This just arbitrarily checks for cargo, but any workspace member in + # a submodule would work. + has_submodules = os.path.exists(os.path.join(self.rust_root, "src/tools/cargo/Cargo.toml")) + if not has_git and not has_submodules: + print("This is not a git repository, and the requisite git submodules were not found.") + print("If you downloaded the source from https://github.com/rust-lang/rust/releases,") + print("those sources will not work. Instead, consider downloading from the source") + print("releases linked at") + print("https://forge.rust-lang.org/infra/other-installation-methods.html#source-code") + print("or clone the repository at https://github.com/rust-lang/rust/.") + raise SystemExit(1) + if not has_git or self.get_toml('submodules') == "false": return default_encoding = sys.getdefaultencoding() diff --git a/src/bootstrap/build.rs b/src/bootstrap/build.rs index 8a5bf933d56..ab34d5c1e55 100644 --- a/src/bootstrap/build.rs +++ b/src/bootstrap/build.rs @@ -1,10 +1,25 @@ +use env::consts::{EXE_EXTENSION, EXE_SUFFIX}; use std::env; +use std::ffi::OsString; use std::path::PathBuf; +/// Given an executable called `name`, return the filename for the +/// executable for a particular target. +pub fn exe(name: &PathBuf) -> PathBuf { + if EXE_EXTENSION != "" && name.extension() != Some(EXE_EXTENSION.as_ref()) { + let mut name: OsString = name.clone().into(); + name.push(EXE_SUFFIX); + name.into() + } else { + name.clone() + } +} + fn main() { + let host = env::var("HOST").unwrap(); println!("cargo:rerun-if-changed=build.rs"); println!("cargo:rerun-if-env-changed=RUSTC"); - println!("cargo:rustc-env=BUILD_TRIPLE={}", env::var("HOST").unwrap()); + println!("cargo:rustc-env=BUILD_TRIPLE={}", host); // This may not be a canonicalized path. let mut rustc = PathBuf::from(env::var_os("RUSTC").unwrap()); @@ -12,7 +27,7 @@ fn main() { 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); + let absolute = dir.join(&exe(&rustc)); if absolute.exists() { rustc = absolute; break; diff --git a/src/bootstrap/builder/tests.rs b/src/bootstrap/builder/tests.rs index b76bb569852..a59f72ed968 100644 --- a/src/bootstrap/builder/tests.rs +++ b/src/bootstrap/builder/tests.rs @@ -8,12 +8,9 @@ fn configure(cmd: &str, host: &[&str], target: &[&str]) -> Config { config.save_toolstates = None; config.dry_run = true; config.ninja_in_file = false; - config.out = PathBuf::from(env::var_os("BOOTSTRAP_OUTPUT_DIRECTORY").unwrap()); - config.initial_rustc = PathBuf::from(env::var_os("RUSTC").unwrap()); - config.initial_cargo = PathBuf::from(env::var_os("BOOTSTRAP_INITIAL_CARGO").unwrap()); // try to avoid spurious failures in dist where we create/delete each others file - let dir = config - .out + // HACK: rather than pull in `tempdir`, use the one that cargo has conveniently created for us + let dir = Path::new(env!("OUT_DIR")) .join("tmp-rustbuild-tests") .join(&thread::current().name().unwrap_or("unknown").replace(":", "-")); t!(fs::create_dir_all(&dir)); diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index 5f16716a0fd..077a86af50b 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -7,7 +7,6 @@ //! Everything here is basically just a shim around calling either `rustbook` or //! `rustdoc`. -use std::collections::HashSet; use std::fs; use std::io; use std::path::{Path, PathBuf}; @@ -554,13 +553,9 @@ impl Step for Rustc { let paths = builder .paths .iter() - .map(components_simplified) - .filter_map(|path| { - if path.get(0) == Some(&"compiler") { - path.get(1).map(|p| p.to_owned()) - } else { - None - } + .filter(|path| { + let components = components_simplified(path); + components.len() >= 2 && components[0] == "compiler" }) .collect::<Vec<_>>(); @@ -608,38 +603,22 @@ impl Step for Rustc { cargo.rustdocflag("--extern-html-root-url"); cargo.rustdocflag("ena=https://docs.rs/ena/latest/"); - let mut compiler_crates = HashSet::new(); - - if paths.is_empty() { - // Find dependencies for top level crates. - for root_crate in &["rustc_driver", "rustc_codegen_llvm", "rustc_codegen_ssa"] { - compiler_crates.extend( - builder - .in_tree_crates(root_crate, Some(target)) - .into_iter() - .map(|krate| krate.name), - ); - } + let root_crates = if paths.is_empty() { + vec![ + INTERNER.intern_str("rustc_driver"), + INTERNER.intern_str("rustc_codegen_llvm"), + INTERNER.intern_str("rustc_codegen_ssa"), + ] } else { - for root_crate in paths { - if !builder.src.join("compiler").join(&root_crate).exists() { - builder.info(&format!( - "\tskipping - compiler/{} (unknown compiler crate)", - root_crate - )); - } else { - compiler_crates.extend( - builder - .in_tree_crates(root_crate, Some(target)) - .into_iter() - .map(|krate| krate.name), - ); - } - } - } + paths.into_iter().map(|p| builder.crate_paths[p]).collect() + }; + // Find dependencies for top level crates. + let compiler_crates = root_crates.iter().flat_map(|krate| { + builder.in_tree_crates(krate, Some(target)).into_iter().map(|krate| krate.name) + }); let mut to_open = None; - for krate in &compiler_crates { + for krate in compiler_crates { // Create all crate output directories first to make sure rustdoc uses // relative links. // FIXME: Cargo should probably do this itself. diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 570a61742bc..e4937d7bbcc 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -302,7 +302,9 @@ pub struct Build { ar: HashMap<TargetSelection, PathBuf>, ranlib: HashMap<TargetSelection, PathBuf>, // Miscellaneous + // allow bidirectional lookups: both name -> path and path -> name crates: HashMap<Interned<String>, Crate>, + crate_paths: HashMap<PathBuf, Interned<String>>, is_sudo: bool, ci_env: CiEnv, delayed_failures: RefCell<Vec<String>>, @@ -452,7 +454,7 @@ impl Build { .map(PathBuf::from) .unwrap_or_else(|_| src.join("target")); let bootstrap_out = workspace_target_dir.join("debug"); - if !bootstrap_out.join("rustc").exists() { + if !bootstrap_out.join("rustc").exists() && !cfg!(test) { // this restriction can be lifted whenever https://github.com/rust-lang/rfcs/pull/3028 is implemented panic!("run `cargo build --bins` before `cargo run`") } @@ -492,6 +494,7 @@ impl Build { ar: HashMap::new(), ranlib: HashMap::new(), crates: HashMap::new(), + crate_paths: HashMap::new(), is_sudo, ci_env: CiEnv::current(), delayed_failures: RefCell::new(Vec::new()), diff --git a/src/bootstrap/metadata.rs b/src/bootstrap/metadata.rs index 59dc50be47f..e193e70a0c4 100644 --- a/src/bootstrap/metadata.rs +++ b/src/bootstrap/metadata.rs @@ -49,7 +49,11 @@ pub fn build(build: &mut Build) { .filter(|dep| dep.source.is_none()) .map(|dep| INTERNER.intern_string(dep.name)) .collect(); - build.crates.insert(name, Crate { name, deps, path }); + let krate = Crate { name, deps, path }; + let relative_path = krate.local_path(build); + build.crates.insert(name, krate); + let existing_path = build.crate_paths.insert(relative_path, name); + assert!(existing_path.is_none(), "multiple crates with the same path"); } } } diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 81200ba60b0..b88684791bc 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -21,7 +21,6 @@ use crate::native; use crate::tool::{self, SourceType, Tool}; use crate::toolstate::ToolState; use crate::util::{self, add_link_lib_path, dylib_path, dylib_path_var, output, t}; -use crate::Crate as CargoCrate; use crate::{envify, CLang, DocTests, GitRepo, Mode}; const ADB_TEST_DIR: &str = "/data/tmp/work"; @@ -1901,19 +1900,10 @@ impl Step for CrateLibrustc { fn make_run(run: RunConfig<'_>) { let builder = run.builder; let compiler = builder.compiler(builder.top_stage, run.build_triple()); + let krate = builder.crate_paths[&run.path]; + let test_kind = builder.kind.into(); - for krate in builder.in_tree_crates("rustc-main", Some(run.target)) { - if krate.path.ends_with(&run.path) { - let test_kind = builder.kind.into(); - - builder.ensure(CrateLibrustc { - compiler, - target: run.target, - test_kind, - krate: krate.name, - }); - } - } + builder.ensure(CrateLibrustc { compiler, target: run.target, test_kind, krate }); } fn run(self, builder: &Builder<'_>) { @@ -1947,24 +1937,10 @@ impl Step for Crate { fn make_run(run: RunConfig<'_>) { let builder = run.builder; let compiler = builder.compiler(builder.top_stage, run.build_triple()); + let test_kind = builder.kind.into(); + let krate = builder.crate_paths[&run.path]; - let make = |mode: Mode, krate: &CargoCrate| { - let test_kind = builder.kind.into(); - - builder.ensure(Crate { - compiler, - target: run.target, - mode, - test_kind, - krate: krate.name, - }); - }; - - for krate in builder.in_tree_crates("test", Some(run.target)) { - if krate.path.ends_with(&run.path) { - make(Mode::Std, krate); - } - } + builder.ensure(Crate { compiler, target: run.target, mode: Mode::Std, test_kind, krate }); } /// Runs all unit tests plus documentation tests for a given crate defined @@ -2392,10 +2368,6 @@ impl Step for Bootstrap { .current_dir(builder.src.join("src/bootstrap")) .env("RUSTFLAGS", "-Cdebuginfo=2") .env("CARGO_TARGET_DIR", builder.out.join("bootstrap")) - // HACK: bootstrap's tests want to know the output directory, but there's no way to set - // it except through config.toml. Set it through an env variable instead. - .env("BOOTSTRAP_OUTPUT_DIRECTORY", &builder.config.out) - .env("BOOTSTRAP_INITIAL_CARGO", &builder.config.initial_cargo) .env("RUSTC_BOOTSTRAP", "1") .env("RUSTC", &builder.initial_rustc); if let Some(flags) = option_env!("RUSTFLAGS") { diff --git a/src/test/mir-opt/derefer_test_multiple.main.Derefer.diff b/src/test/mir-opt/derefer_test_multiple.main.Derefer.diff new file mode 100644 index 00000000000..d465724326e --- /dev/null +++ b/src/test/mir-opt/derefer_test_multiple.main.Derefer.diff @@ -0,0 +1,100 @@ +- // MIR for `main` before Derefer ++ // MIR for `main` after Derefer + + fn main() -> () { + let mut _0: (); // return place in scope 0 at $DIR/derefer_test_multiple.rs:2:12: 2:12 + let mut _1: (i32, i32); // in scope 0 at $DIR/derefer_test_multiple.rs:3:9: 3:14 + let mut _3: &mut (i32, i32); // in scope 0 at $DIR/derefer_test_multiple.rs:4:22: 4:28 + let mut _5: &mut (i32, &mut (i32, i32)); // in scope 0 at $DIR/derefer_test_multiple.rs:5:22: 5:28 + let mut _7: &mut (i32, &mut (i32, &mut (i32, i32))); // in scope 0 at $DIR/derefer_test_multiple.rs:6:22: 6:28 ++ let mut _10: &mut (i32, &mut (i32, &mut (i32, i32))); // in scope 0 at $DIR/derefer_test_multiple.rs:7:13: 7:30 ++ let mut _11: &mut (i32, &mut (i32, i32)); // in scope 0 at $DIR/derefer_test_multiple.rs:7:13: 7:30 ++ let mut _12: &mut (i32, i32); // in scope 0 at $DIR/derefer_test_multiple.rs:7:13: 7:30 ++ let mut _13: &mut (i32, &mut (i32, &mut (i32, i32))); // in scope 0 at $DIR/derefer_test_multiple.rs:8:13: 8:30 ++ let mut _14: &mut (i32, &mut (i32, i32)); // in scope 0 at $DIR/derefer_test_multiple.rs:8:13: 8:30 ++ let mut _15: &mut (i32, i32); // in scope 0 at $DIR/derefer_test_multiple.rs:8:13: 8:30 + scope 1 { + debug a => _1; // in scope 1 at $DIR/derefer_test_multiple.rs:3:9: 3:14 + let mut _2: (i32, &mut (i32, i32)); // in scope 1 at $DIR/derefer_test_multiple.rs:4:9: 4:14 + scope 2 { + debug b => _2; // in scope 2 at $DIR/derefer_test_multiple.rs:4:9: 4:14 + let mut _4: (i32, &mut (i32, &mut (i32, i32))); // in scope 2 at $DIR/derefer_test_multiple.rs:5:9: 5:14 + scope 3 { + debug c => _4; // in scope 3 at $DIR/derefer_test_multiple.rs:5:9: 5:14 + let mut _6: (i32, &mut (i32, &mut (i32, &mut (i32, i32)))); // in scope 3 at $DIR/derefer_test_multiple.rs:6:9: 6:14 + scope 4 { + debug d => _6; // in scope 4 at $DIR/derefer_test_multiple.rs:6:9: 6:14 + let _8: &mut i32; // in scope 4 at $DIR/derefer_test_multiple.rs:7:9: 7:10 + scope 5 { + debug x => _8; // in scope 5 at $DIR/derefer_test_multiple.rs:7:9: 7:10 + let _9: &mut i32; // in scope 5 at $DIR/derefer_test_multiple.rs:8:9: 8:10 + scope 6 { + debug y => _9; // in scope 6 at $DIR/derefer_test_multiple.rs:8:9: 8:10 + } + } + } + } + } + } + + bb0: { + StorageLive(_1); // scope 0 at $DIR/derefer_test_multiple.rs:3:9: 3:14 + (_1.0: i32) = const 42_i32; // scope 0 at $DIR/derefer_test_multiple.rs:3:17: 3:25 + (_1.1: i32) = const 43_i32; // scope 0 at $DIR/derefer_test_multiple.rs:3:17: 3:25 + StorageLive(_2); // scope 1 at $DIR/derefer_test_multiple.rs:4:9: 4:14 + StorageLive(_3); // scope 1 at $DIR/derefer_test_multiple.rs:4:22: 4:28 + _3 = &mut _1; // scope 1 at $DIR/derefer_test_multiple.rs:4:22: 4:28 + (_2.0: i32) = const 99_i32; // scope 1 at $DIR/derefer_test_multiple.rs:4:17: 4:29 + (_2.1: &mut (i32, i32)) = move _3; // scope 1 at $DIR/derefer_test_multiple.rs:4:17: 4:29 + StorageDead(_3); // scope 1 at $DIR/derefer_test_multiple.rs:4:28: 4:29 + StorageLive(_4); // scope 2 at $DIR/derefer_test_multiple.rs:5:9: 5:14 + StorageLive(_5); // scope 2 at $DIR/derefer_test_multiple.rs:5:22: 5:28 + _5 = &mut _2; // scope 2 at $DIR/derefer_test_multiple.rs:5:22: 5:28 + (_4.0: i32) = const 11_i32; // scope 2 at $DIR/derefer_test_multiple.rs:5:17: 5:29 + (_4.1: &mut (i32, &mut (i32, i32))) = move _5; // scope 2 at $DIR/derefer_test_multiple.rs:5:17: 5:29 + StorageDead(_5); // scope 2 at $DIR/derefer_test_multiple.rs:5:28: 5:29 + StorageLive(_6); // scope 3 at $DIR/derefer_test_multiple.rs:6:9: 6:14 + StorageLive(_7); // scope 3 at $DIR/derefer_test_multiple.rs:6:22: 6:28 + _7 = &mut _4; // scope 3 at $DIR/derefer_test_multiple.rs:6:22: 6:28 + (_6.0: i32) = const 13_i32; // scope 3 at $DIR/derefer_test_multiple.rs:6:17: 6:29 + (_6.1: &mut (i32, &mut (i32, &mut (i32, i32)))) = move _7; // scope 3 at $DIR/derefer_test_multiple.rs:6:17: 6:29 + StorageDead(_7); // scope 3 at $DIR/derefer_test_multiple.rs:6:28: 6:29 + StorageLive(_8); // scope 4 at $DIR/derefer_test_multiple.rs:7:9: 7:10 +- _8 = &mut ((*((*((*(_6.1: &mut (i32, &mut (i32, &mut (i32, i32))))).1: &mut (i32, &mut (i32, i32)))).1: &mut (i32, i32))).1: i32); // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30 ++ StorageLive(_10); // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30 ++ _10 = move (_6.1: &mut (i32, &mut (i32, &mut (i32, i32)))); // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30 ++ StorageLive(_11); // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30 ++ _11 = move ((*_10).1: &mut (i32, &mut (i32, i32))); // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30 ++ StorageLive(_12); // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30 ++ _12 = move ((*_11).1: &mut (i32, i32)); // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30 ++ _8 = &mut ((*_12).1: i32); // scope 4 at $DIR/derefer_test_multiple.rs:7:13: 7:30 ++ StorageDead(_10); // scope 5 at $DIR/derefer_test_multiple.rs:8:9: 8:10 ++ StorageDead(_11); // scope 5 at $DIR/derefer_test_multiple.rs:8:9: 8:10 ++ StorageDead(_12); // scope 5 at $DIR/derefer_test_multiple.rs:8:9: 8:10 + StorageLive(_9); // scope 5 at $DIR/derefer_test_multiple.rs:8:9: 8:10 +- _9 = &mut ((*((*((*(_6.1: &mut (i32, &mut (i32, &mut (i32, i32))))).1: &mut (i32, &mut (i32, i32)))).1: &mut (i32, i32))).1: i32); // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30 ++ StorageLive(_13); // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30 ++ _13 = move (_6.1: &mut (i32, &mut (i32, &mut (i32, i32)))); // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30 ++ StorageLive(_14); // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30 ++ _14 = move ((*_13).1: &mut (i32, &mut (i32, i32))); // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30 ++ StorageLive(_15); // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30 ++ _15 = move ((*_14).1: &mut (i32, i32)); // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30 ++ _9 = &mut ((*_15).1: i32); // scope 5 at $DIR/derefer_test_multiple.rs:8:13: 8:30 ++ StorageDead(_13); // scope 0 at $DIR/derefer_test_multiple.rs:2:12: 9:2 ++ StorageDead(_14); // scope 0 at $DIR/derefer_test_multiple.rs:2:12: 9:2 ++ StorageDead(_15); // scope 0 at $DIR/derefer_test_multiple.rs:2:12: 9:2 + _0 = const (); // scope 0 at $DIR/derefer_test_multiple.rs:2:12: 9:2 + StorageDead(_9); // scope 5 at $DIR/derefer_test_multiple.rs:9:1: 9:2 + StorageDead(_8); // scope 4 at $DIR/derefer_test_multiple.rs:9:1: 9:2 + StorageDead(_6); // scope 3 at $DIR/derefer_test_multiple.rs:9:1: 9:2 + StorageDead(_4); // scope 2 at $DIR/derefer_test_multiple.rs:9:1: 9:2 + StorageDead(_2); // scope 1 at $DIR/derefer_test_multiple.rs:9:1: 9:2 + StorageDead(_1); // scope 0 at $DIR/derefer_test_multiple.rs:9:1: 9:2 + return; // scope 0 at $DIR/derefer_test_multiple.rs:9:2: 9:2 ++ } ++ ++ bb1 (cleanup): { ++ resume; // scope 0 at $DIR/derefer_test_multiple.rs:2:1: 9:2 + } + } + diff --git a/src/test/mir-opt/derefer_test_multiple.rs b/src/test/mir-opt/derefer_test_multiple.rs new file mode 100644 index 00000000000..a27363447fe --- /dev/null +++ b/src/test/mir-opt/derefer_test_multiple.rs @@ -0,0 +1,9 @@ +// EMIT_MIR derefer_test_multiple.main.Derefer.diff +fn main () { + let mut a = (42, 43); + let mut b = (99, &mut a); + let mut c = (11, &mut b); + let mut d = (13, &mut c); + let x = &mut (*d.1).1.1.1; + let y = &mut (*d.1).1.1.1; +} diff --git a/src/test/ui/borrowck/suggest-local-var-for-vector.rs b/src/test/ui/borrowck/suggest-local-var-for-vector.rs new file mode 100644 index 00000000000..40f013f6a78 --- /dev/null +++ b/src/test/ui/borrowck/suggest-local-var-for-vector.rs @@ -0,0 +1,4 @@ +fn main() { + let mut vec = vec![0u32; 420]; + vec[vec.len() - 1] = 123; //~ ERROR cannot borrow `vec` as immutable because it is also borrowed as mutable +} diff --git a/src/test/ui/borrowck/suggest-local-var-for-vector.stderr b/src/test/ui/borrowck/suggest-local-var-for-vector.stderr new file mode 100644 index 00000000000..615fffcd578 --- /dev/null +++ b/src/test/ui/borrowck/suggest-local-var-for-vector.stderr @@ -0,0 +1,24 @@ +error[E0502]: cannot borrow `vec` as immutable because it is also borrowed as mutable + --> $DIR/suggest-local-var-for-vector.rs:3:9 + | +LL | vec[vec.len() - 1] = 123; + | ----^^^^^^^^^----- + | | | + | | immutable borrow occurs here + | mutable borrow occurs here + | mutable borrow later used here + | +help: try adding a local storing this... + --> $DIR/suggest-local-var-for-vector.rs:3:9 + | +LL | vec[vec.len() - 1] = 123; + | ^^^^^^^^^ +help: ...and then using that local here + --> $DIR/suggest-local-var-for-vector.rs:3:5 + | +LL | vec[vec.len() - 1] = 123; + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0502`. diff --git a/src/test/ui/borrowck/suggest-storing-local-var-for-vector.rs b/src/test/ui/borrowck/suggest-storing-local-var-for-vector.rs new file mode 100644 index 00000000000..40f013f6a78 --- /dev/null +++ b/src/test/ui/borrowck/suggest-storing-local-var-for-vector.rs @@ -0,0 +1,4 @@ +fn main() { + let mut vec = vec![0u32; 420]; + vec[vec.len() - 1] = 123; //~ ERROR cannot borrow `vec` as immutable because it is also borrowed as mutable +} diff --git a/src/test/ui/borrowck/suggest-storing-local-var-for-vector.stderr b/src/test/ui/borrowck/suggest-storing-local-var-for-vector.stderr new file mode 100644 index 00000000000..e3a16eddfd5 --- /dev/null +++ b/src/test/ui/borrowck/suggest-storing-local-var-for-vector.stderr @@ -0,0 +1,24 @@ +error[E0502]: cannot borrow `vec` as immutable because it is also borrowed as mutable + --> $DIR/suggest-storing-local-var-for-vector.rs:3:9 + | +LL | vec[vec.len() - 1] = 123; + | ----^^^^^^^^^----- + | | | + | | immutable borrow occurs here + | mutable borrow occurs here + | mutable borrow later used here + | +help: try adding a local storing this... + --> $DIR/suggest-storing-local-var-for-vector.rs:3:9 + | +LL | vec[vec.len() - 1] = 123; + | ^^^^^^^^^ +help: ...and then using that local here + --> $DIR/suggest-storing-local-var-for-vector.rs:3:5 + | +LL | vec[vec.len() - 1] = 123; + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0502`. diff --git a/src/test/ui/borrowck/two-phase-nonrecv-autoref.nll.stderr b/src/test/ui/borrowck/two-phase-nonrecv-autoref.nll.stderr index 50d277a12f7..0f2daaf99d9 100644 --- a/src/test/ui/borrowck/two-phase-nonrecv-autoref.nll.stderr +++ b/src/test/ui/borrowck/two-phase-nonrecv-autoref.nll.stderr @@ -54,6 +54,17 @@ LL | i[i[3]] = 4; | | immutable borrow occurs here | mutable borrow occurs here | mutable borrow later used here + | +help: try adding a local storing this... + --> $DIR/two-phase-nonrecv-autoref.rs:138:7 + | +LL | i[i[3]] = 4; + | ^^^^ +help: ...and then using that local here + --> $DIR/two-phase-nonrecv-autoref.rs:138:5 + | +LL | i[i[3]] = 4; + | ^^^^^^^ error[E0502]: cannot borrow `i` as immutable because it is also borrowed as mutable --> $DIR/two-phase-nonrecv-autoref.rs:143:7 @@ -64,6 +75,17 @@ LL | i[i[3]] = i[4]; | | immutable borrow occurs here | mutable borrow occurs here | mutable borrow later used here + | +help: try adding a local storing this... + --> $DIR/two-phase-nonrecv-autoref.rs:143:7 + | +LL | i[i[3]] = i[4]; + | ^^^^ +help: ...and then using that local here + --> $DIR/two-phase-nonrecv-autoref.rs:143:5 + | +LL | i[i[3]] = i[4]; + | ^^^^^^^ error: aborting due to 7 previous errors diff --git a/src/test/ui/const-generics/occurs-check/unused-substs-1.stderr b/src/test/ui/const-generics/occurs-check/unused-substs-1.stderr index 8431d989278..48e12e903b8 100644 --- a/src/test/ui/const-generics/occurs-check/unused-substs-1.stderr +++ b/src/test/ui/const-generics/occurs-check/unused-substs-1.stderr @@ -8,6 +8,9 @@ LL | let _ = A; note: required by a bound in `A` --> $DIR/unused-substs-1.rs:9:11 | +LL | struct A<const N: usize> + | - required by a bound in this +LL | where LL | A<N>: Bar<N>; | ^^^^^^ required by this bound in `A` diff --git a/src/test/ui/error-codes/E0516.stderr b/src/test/ui/error-codes/E0516.stderr index 2e6de5053d5..5243b7caf22 100644 --- a/src/test/ui/error-codes/E0516.stderr +++ b/src/test/ui/error-codes/E0516.stderr @@ -3,6 +3,11 @@ error[E0516]: `typeof` is a reserved keyword but unimplemented | LL | let x: typeof(92) = 92; | ^^^^^^^^^^ reserved keyword + | +help: consider replacing `typeof(...)` with an actual type + | +LL | let x: i32 = 92; + | ~~~ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-29184.stderr b/src/test/ui/issues/issue-29184.stderr index 87d3632ee42..75b6c64f2ce 100644 --- a/src/test/ui/issues/issue-29184.stderr +++ b/src/test/ui/issues/issue-29184.stderr @@ -3,6 +3,11 @@ error[E0516]: `typeof` is a reserved keyword but unimplemented | LL | let x: typeof(92) = 92; | ^^^^^^^^^^ reserved keyword + | +help: consider replacing `typeof(...)` with an actual type + | +LL | let x: i32 = 92; + | ~~~ error: aborting due to previous error diff --git a/src/test/ui/lint/lint-strict-provenance-lossy-casts.stderr b/src/test/ui/lint/lint-strict-provenance-lossy-casts.stderr index 489cb03ddd3..e7a6c1837bd 100644 --- a/src/test/ui/lint/lint-strict-provenance-lossy-casts.stderr +++ b/src/test/ui/lint/lint-strict-provenance-lossy-casts.stderr @@ -9,7 +9,7 @@ note: the lint level is defined here | LL | #![deny(lossy_provenance_casts)] | ^^^^^^^^^^^^^^^^^^^^^^ - = help: if you can't comply with strict provenance and need to expose the pointerprovenance you can use `.expose_addr()` instead + = help: if you can't comply with strict provenance and need to expose the pointer provenance you can use `.expose_addr()` instead error: under strict provenance it is considered bad style to cast pointer `*const u8` to integer `u32` --> $DIR/lint-strict-provenance-lossy-casts.rs:9:22 @@ -17,7 +17,7 @@ error: under strict provenance it is considered bad style to cast pointer `*cons LL | let addr_32bit = &x as *const u8 as u32; | ^^^^^^^^^^^^^^^^^^^^^^ help: use `.addr()` to obtain the address of a pointer: `(&x as *const u8).addr() as u32` | - = help: if you can't comply with strict provenance and need to expose the pointerprovenance you can use `.expose_addr()` instead + = help: if you can't comply with strict provenance and need to expose the pointer provenance you can use `.expose_addr()` instead error: aborting due to 2 previous errors diff --git a/src/test/ui/typeof/type_mismatch.stderr b/src/test/ui/typeof/type_mismatch.stderr index e82b5e44973..e75214cd31a 100644 --- a/src/test/ui/typeof/type_mismatch.stderr +++ b/src/test/ui/typeof/type_mismatch.stderr @@ -3,6 +3,11 @@ error[E0516]: `typeof` is a reserved keyword but unimplemented | LL | let b: typeof(a) = 1i8; | ^^^^^^^^^ reserved keyword + | +help: consider replacing `typeof(...)` with an actual type + | +LL | let b: u8 = 1i8; + | ~~ error[E0308]: mismatched types --> $DIR/type_mismatch.rs:5:24 diff --git a/src/tools/miri b/src/tools/miri -Subproject be72564a643758afcc1de152ead2359d489149c +Subproject c568f32f165d86aba51ec544756c3c833acbabd |
