diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 7c88205da3b9..f43b611f54ed 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -1985,18 +1985,16 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let (place_desc, note) = if let Some(place_desc) = opt_place_desc { let local_kind = if let Some(local) = borrow.borrowed_place.as_local() { match self.body.local_kind(local) { - LocalKind::Temp if self.body.local_decls[local].is_user_variable() => { - "local variable " + LocalKind::ReturnPointer | LocalKind::Temp => { + bug!("temporary or return pointer with a name") } + LocalKind::Var => "local variable ", LocalKind::Arg if !self.upvars.is_empty() && local == ty::CAPTURE_STRUCT_LOCAL => { "variable captured by `move` " } LocalKind::Arg => "function parameter ", - LocalKind::ReturnPointer | LocalKind::Temp => { - bug!("temporary or return pointer with a name") - } } } else { "local data " @@ -2010,16 +2008,16 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { self.prefixes(borrow.borrowed_place.as_ref(), PrefixSet::All).last().unwrap(); let local = root_place.local; match self.body.local_kind(local) { + LocalKind::ReturnPointer | LocalKind::Temp => { + ("temporary value".to_string(), "temporary value created here".to_string()) + } LocalKind::Arg => ( "function parameter".to_string(), "function parameter borrowed here".to_string(), ), - LocalKind::Temp if self.body.local_decls[local].is_user_variable() => { + LocalKind::Var => { ("local binding".to_string(), "local binding introduced here".to_string()) } - LocalKind::ReturnPointer | LocalKind::Temp => { - ("temporary value".to_string(), "temporary value created here".to_string()) - } } }; @@ -2484,14 +2482,15 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let (place_description, assigned_span) = match local_decl { Some(LocalDecl { local_info: - ClearCrossCrate::Set( - box LocalInfo::User(BindingForm::Var(VarBindingForm { + Some(box LocalInfo::User( + ClearCrossCrate::Clear + | ClearCrossCrate::Set(BindingForm::Var(VarBindingForm { opt_match_place: None, .. - })) - | box LocalInfo::StaticRef { .. } - | box LocalInfo::Boring, - ), + })), + )) + | Some(box LocalInfo::StaticRef { .. }) + | None, .. }) | None => (self.describe_any_place(place.as_ref()), assigned_span), diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs index 62b3f3ecfc32..19855075ced8 100644 --- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs +++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs @@ -6,8 +6,8 @@ use rustc_hir::intravisit::Visitor; use rustc_index::vec::IndexVec; use rustc_infer::infer::NllRegionVariableOrigin; use rustc_middle::mir::{ - Body, CastKind, ConstraintCategory, FakeReadCause, Local, LocalInfo, Location, Operand, Place, - Rvalue, Statement, StatementKind, TerminatorKind, + Body, CastKind, ConstraintCategory, FakeReadCause, Local, Location, Operand, Place, Rvalue, + Statement, StatementKind, TerminatorKind, }; use rustc_middle::ty::adjustment::PointerCast; use rustc_middle::ty::{self, RegionVid, TyCtxt}; @@ -220,7 +220,7 @@ impl<'tcx> BorrowExplanation<'tcx> { ); err.span_label(body.source_info(drop_loc).span, message); - if let LocalInfo::BlockTailTemp(info) = local_decl.local_info() { + if let Some(info) = &local_decl.is_block_tail { if info.tail_result_is_ignored { // #85581: If the first mutable borrow's scope contains // the second borrow, this suggestion isn't helpful. diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index 611abb01238b..af705e6a80fe 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -196,10 +196,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { if self.body.local_decls[local].is_ref_for_guard() { continue; } - if let LocalInfo::StaticRef { def_id, .. } = - *self.body.local_decls[local].local_info() + if let Some(box LocalInfo::StaticRef { def_id, .. }) = + &self.body.local_decls[local].local_info { - buf.push_str(self.infcx.tcx.item_name(def_id).as_str()); + buf.push_str(self.infcx.tcx.item_name(*def_id).as_str()); ok = Ok(()); continue; } diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs index 3662bec0c763..5e4c7292e590 100644 --- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs @@ -102,12 +102,14 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { // // opt_match_place is None for let [mut] x = ... statements, // whether or not the right-hand side is a place expression - if let LocalInfo::User(BindingForm::Var(VarBindingForm { - opt_match_place: Some((opt_match_place, match_span)), - binding_mode: _, - opt_ty_info: _, - pat_span: _, - })) = *local_decl.local_info() + if let Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var( + VarBindingForm { + opt_match_place: Some((opt_match_place, match_span)), + binding_mode: _, + opt_ty_info: _, + pat_span: _, + }, + )))) = local_decl.local_info { let stmt_source_info = self.body.source_info(location); self.append_binding_error( @@ -476,8 +478,9 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let mut suggestions: Vec<(Span, String, String)> = Vec::new(); for local in binds_to { let bind_to = &self.body.local_decls[*local]; - if let LocalInfo::User(BindingForm::Var(VarBindingForm { pat_span, .. })) = - *bind_to.local_info() + if let Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var( + VarBindingForm { pat_span, .. }, + )))) = bind_to.local_info { let Ok(pat_snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(pat_span) else { continue; }; diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index bad08451adf0..eded913ae968 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -7,7 +7,7 @@ use rustc_middle::mir::{Mutability, Place, PlaceRef, ProjectionElem}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::{ hir::place::PlaceBase, - mir::{self, BindingForm, Local, LocalDecl, LocalInfo, LocalKind, Location}, + mir::{self, BindingForm, ClearCrossCrate, Local, LocalDecl, LocalInfo, LocalKind, Location}, }; use rustc_span::source_map::DesugaringKind; use rustc_span::symbol::{kw, Symbol}; @@ -105,8 +105,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { reason = String::new(); } else { item_msg = access_place_desc; - let local_info = self.body.local_decls[local].local_info(); - if let LocalInfo::StaticRef { def_id, .. } = *local_info { + let local_info = &self.body.local_decls[local].local_info; + if let Some(box LocalInfo::StaticRef { def_id, .. }) = *local_info { let static_name = &self.infcx.tcx.item_name(def_id); reason = format!(", as `{static_name}` is an immutable static item"); } else { @@ -305,13 +305,15 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { .. }) = &self.body[location.block].statements.get(location.statement_index) { - match *decl.local_info() { - LocalInfo::User(BindingForm::Var(mir::VarBindingForm { - binding_mode: ty::BindingMode::BindByValue(Mutability::Not), - opt_ty_info: Some(sp), - opt_match_place: _, - pat_span: _, - })) => { + match decl.local_info { + Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var( + mir::VarBindingForm { + binding_mode: ty::BindingMode::BindByValue(Mutability::Not), + opt_ty_info: Some(sp), + opt_match_place: _, + pat_span: _, + }, + )))) => { if suggest { err.span_note(sp, "the binding is already a mutable borrow"); } @@ -344,8 +346,10 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } } else if decl.mutability.is_not() { if matches!( - decl.local_info(), - LocalInfo::User(BindingForm::ImplicitSelf(hir::ImplicitSelfKind::MutRef)) + decl.local_info, + Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::ImplicitSelf( + hir::ImplicitSelfKind::MutRef + ),))) ) { err.note( "as `Self` may be unsized, this call attempts to take `&mut &mut self`", @@ -478,18 +482,22 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { match self.local_names[local] { Some(name) if !local_decl.from_compiler_desugaring() => { - let label = match *local_decl.local_info() { - LocalInfo::User(mir::BindingForm::ImplicitSelf(_)) => { + let label = match local_decl.local_info.as_deref().unwrap() { + LocalInfo::User(ClearCrossCrate::Set( + mir::BindingForm::ImplicitSelf(_), + )) => { let (span, suggestion) = suggest_ampmut_self(self.infcx.tcx, local_decl); Some((true, span, suggestion)) } - LocalInfo::User(mir::BindingForm::Var(mir::VarBindingForm { - binding_mode: ty::BindingMode::BindByValue(_), - opt_ty_info, - .. - })) => { + LocalInfo::User(ClearCrossCrate::Set(mir::BindingForm::Var( + mir::VarBindingForm { + binding_mode: ty::BindingMode::BindByValue(_), + opt_ty_info, + .. + }, + ))) => { // check if the RHS is from desugaring let opt_assignment_rhs_span = self.body.find_assignments(local).first().map(|&location| { @@ -526,15 +534,16 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { self.infcx.tcx, local_decl, opt_assignment_rhs_span, - opt_ty_info, + *opt_ty_info, ) } else { - match local_decl.local_info() { - LocalInfo::User(mir::BindingForm::Var( - mir::VarBindingForm { - opt_ty_info: None, .. - }, - )) => { + match local_decl.local_info.as_deref() { + Some(LocalInfo::User(ClearCrossCrate::Set( + mir::BindingForm::Var(mir::VarBindingForm { + opt_ty_info: None, + .. + }), + ))) => { let (span, sugg) = suggest_ampmut_self( self.infcx.tcx, local_decl, @@ -546,7 +555,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { self.infcx.tcx, local_decl, opt_assignment_rhs_span, - opt_ty_info, + *opt_ty_info, ), } }; @@ -555,15 +564,21 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } } - LocalInfo::User(mir::BindingForm::Var(mir::VarBindingForm { - binding_mode: ty::BindingMode::BindByReference(_), - .. - })) => { + LocalInfo::User(ClearCrossCrate::Set(mir::BindingForm::Var( + mir::VarBindingForm { + binding_mode: ty::BindingMode::BindByReference(_), + .. + }, + ))) => { let pattern_span = local_decl.source_info.span; suggest_ref_mut(self.infcx.tcx, pattern_span) .map(|replacement| (true, pattern_span, replacement)) } + LocalInfo::User(ClearCrossCrate::Clear) => { + bug!("saw cleared local state") + } + _ => unreachable!(), }; @@ -1136,19 +1151,20 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { pub fn mut_borrow_of_mutable_ref(local_decl: &LocalDecl<'_>, local_name: Option) -> bool { debug!("local_info: {:?}, ty.kind(): {:?}", local_decl.local_info, local_decl.ty.kind()); - match *local_decl.local_info() { + match local_decl.local_info.as_deref() { // Check if mutably borrowing a mutable reference. - LocalInfo::User(mir::BindingForm::Var(mir::VarBindingForm { - binding_mode: ty::BindingMode::BindByValue(Mutability::Not), - .. - })) => matches!(local_decl.ty.kind(), ty::Ref(_, _, hir::Mutability::Mut)), - LocalInfo::User(mir::BindingForm::ImplicitSelf(kind)) => { + Some(LocalInfo::User(ClearCrossCrate::Set(mir::BindingForm::Var( + mir::VarBindingForm { + binding_mode: ty::BindingMode::BindByValue(Mutability::Not), .. + }, + )))) => matches!(local_decl.ty.kind(), ty::Ref(_, _, hir::Mutability::Mut)), + Some(LocalInfo::User(ClearCrossCrate::Set(mir::BindingForm::ImplicitSelf(kind)))) => { // Check if the user variable is a `&mut self` and we can therefore // suggest removing the `&mut`. // // Deliberately fall into this case for all implicit self types, // so that we don't fall in to the next case with them. - kind == hir::ImplicitSelfKind::MutRef + *kind == hir::ImplicitSelfKind::MutRef } _ if Some(kw::SelfLower) == local_name => { // Otherwise, check if the name is the `self` keyword - in which case diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 53fef4d75bf6..3919c4793a06 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -1180,7 +1180,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } } Some(l) - if matches!(body.local_decls[l].local_info(), LocalInfo::AggregateTemp) => + if matches!( + body.local_decls[l].local_info, + Some(box LocalInfo::AggregateTemp) + ) => { ConstraintCategory::Usage } @@ -1681,7 +1684,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // - maybe we should make that a warning. return; } - LocalKind::Temp => {} + LocalKind::Var | LocalKind::Temp => {} } // When `unsized_fn_params` or `unsized_locals` is enabled, only function calls diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs index 6e32c28a42c6..708f3bc0c78f 100644 --- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs +++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs @@ -241,6 +241,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { pub fn debug_introduce_local(&self, bx: &mut Bx, local: mir::Local) { let full_debug_info = bx.sess().opts.debuginfo == DebugInfo::Full; + // FIXME(eddyb) maybe name the return place as `_0` or `return`? + if local == mir::RETURN_PLACE && !self.mir.local_decls[mir::RETURN_PLACE].is_user_variable() + { + return; + } + let vars = match &self.per_local_var_debug_info { Some(per_local) => &per_local[local], None => return, @@ -297,8 +303,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let local_ref = &self.locals[local]; - // FIXME Should the return place be named? - let name = if bx.sess().fewer_names() || local == mir::RETURN_PLACE { + let name = if bx.sess().fewer_names() { None } else { Some(match whole_local_var.or(fallback_var.clone()) { diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs index f775b4796678..db55dbc2bfd7 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -643,7 +643,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { if base_ty.is_unsafe_ptr() { if proj_base.is_empty() { let decl = &self.body.local_decls[place_local]; - if let LocalInfo::StaticRef { def_id, .. } = *decl.local_info() { + if let Some(box LocalInfo::StaticRef { def_id, .. }) = decl.local_info { let span = decl.source_info.span; self.check_static(def_id, span); return; diff --git a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs index c0f5b3725b36..e586720a0d08 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs @@ -704,7 +704,7 @@ pub mod ty { fn importance(&self) -> DiagnosticImportance { match self.0 { - mir::LocalKind::Temp => DiagnosticImportance::Secondary, + mir::LocalKind::Var | mir::LocalKind::Temp => DiagnosticImportance::Secondary, mir::LocalKind::ReturnPointer | mir::LocalKind::Arg => { DiagnosticImportance::Primary } diff --git a/compiler/rustc_const_eval/src/transform/promote_consts.rs b/compiler/rustc_const_eval/src/transform/promote_consts.rs index 648a86d32fcf..3f3b66b0645a 100644 --- a/compiler/rustc_const_eval/src/transform/promote_consts.rs +++ b/compiler/rustc_const_eval/src/transform/promote_consts.rs @@ -106,9 +106,8 @@ impl<'tcx> Visitor<'tcx> for Collector<'_, 'tcx> { debug!("visit_local: index={:?} context={:?} location={:?}", index, context, location); // We're only interested in temporaries and the return place match self.ccx.body.local_kind(index) { - LocalKind::Arg => return, - LocalKind::Temp if self.ccx.body.local_decls[index].is_user_variable() => return, - LocalKind::ReturnPointer | LocalKind::Temp => {} + LocalKind::Temp | LocalKind::ReturnPointer => {} + LocalKind::Arg | LocalKind::Var => return, } // Ignore drops, if the temp gets promoted, diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 7d515bb0f5a4..b34651c3ea79 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -401,6 +401,8 @@ impl<'tcx> Body<'tcx> { LocalKind::ReturnPointer } else if index < self.arg_count + 1 { LocalKind::Arg + } else if self.local_decls[local].is_user_variable() { + LocalKind::Var } else { LocalKind::Temp } @@ -570,13 +572,6 @@ impl ClearCrossCrate { } } - pub fn as_mut(&mut self) -> ClearCrossCrate<&mut T> { - match self { - ClearCrossCrate::Clear => ClearCrossCrate::Clear, - ClearCrossCrate::Set(v) => ClearCrossCrate::Set(v), - } - } - pub fn assert_crate_local(self) -> T { match self { ClearCrossCrate::Clear => bug!("unwrapping cross-crate data"), @@ -666,7 +661,9 @@ impl Atom for Local { /// Classifies locals into categories. See `Body::local_kind`. #[derive(Clone, Copy, PartialEq, Eq, Debug, HashStable)] pub enum LocalKind { - /// User-declared variable binding or compiler-introduced temporary. + /// User-declared variable binding. + Var, + /// Compiler-introduced temporary. Temp, /// Function argument. Arg, @@ -763,7 +760,7 @@ pub struct LocalDecl<'tcx> { pub mutability: Mutability, // FIXME(matthewjasper) Don't store in this in `Body` - pub local_info: ClearCrossCrate>>, + pub local_info: Option>>, /// `true` if this is an internal local. /// @@ -781,6 +778,13 @@ pub struct LocalDecl<'tcx> { /// generator. pub internal: bool, + /// If this local is a temporary and `is_block_tail` is `Some`, + /// then it is a temporary created for evaluation of some + /// subexpression of some block's tail expression (with no + /// intervening statement context). + // FIXME(matthewjasper) Don't store in this in `Body` + pub is_block_tail: Option, + /// The type of this local. pub ty: Ty<'tcx>, @@ -886,7 +890,7 @@ pub enum LocalInfo<'tcx> { /// The `BindingForm` is solely used for local diagnostics when generating /// warnings/errors when compiling the current crate, and therefore it need /// not be visible across crates. - User(BindingForm<'tcx>), + User(ClearCrossCrate>), /// A temporary created that references the static with the given `DefId`. StaticRef { def_id: DefId, is_thread_local: bool }, /// A temporary created that references the const with the given `DefId` @@ -894,23 +898,13 @@ pub enum LocalInfo<'tcx> { /// A temporary created during the creation of an aggregate /// (e.g. a temporary for `foo` in `MyStruct { my_field: foo }`) AggregateTemp, - /// A temporary created for evaluation of some subexpression of some block's tail expression - /// (with no intervening statement context). - // FIXME(matthewjasper) Don't store in this in `Body` - BlockTailTemp(BlockTailInfo), /// A temporary created during the pass `Derefer` to avoid it's retagging DerefTemp, /// A temporary created for borrow checking. FakeBorrow, - /// A local without anything interesting about it. - Boring, } impl<'tcx> LocalDecl<'tcx> { - pub fn local_info(&self) -> &LocalInfo<'tcx> { - &**self.local_info.as_ref().assert_crate_local() - } - /// Returns `true` only if local is a binding that can itself be /// made mutable via the addition of the `mut` keyword, namely /// something like the occurrences of `x` in: @@ -919,15 +913,15 @@ impl<'tcx> LocalDecl<'tcx> { /// - or `match ... { C(x) => ... }` pub fn can_be_made_mutable(&self) -> bool { matches!( - self.local_info(), - LocalInfo::User( + self.local_info, + Some(box LocalInfo::User(ClearCrossCrate::Set( BindingForm::Var(VarBindingForm { binding_mode: ty::BindingMode::BindByValue(_), opt_ty_info: _, opt_match_place: _, pat_span: _, }) | BindingForm::ImplicitSelf(ImplicitSelfKind::Imm), - ) + ))) ) } @@ -936,15 +930,15 @@ impl<'tcx> LocalDecl<'tcx> { /// mutable bindings, but the inverse does not necessarily hold). pub fn is_nonref_binding(&self) -> bool { matches!( - self.local_info(), - LocalInfo::User( + self.local_info, + Some(box LocalInfo::User(ClearCrossCrate::Set( BindingForm::Var(VarBindingForm { binding_mode: ty::BindingMode::BindByValue(_), opt_ty_info: _, opt_match_place: _, pat_span: _, }) | BindingForm::ImplicitSelf(_), - ) + ))) ) } @@ -952,35 +946,38 @@ impl<'tcx> LocalDecl<'tcx> { /// parameter declared by the user. #[inline] pub fn is_user_variable(&self) -> bool { - matches!(self.local_info(), LocalInfo::User(_)) + matches!(self.local_info, Some(box LocalInfo::User(_))) } /// Returns `true` if this is a reference to a variable bound in a `match` /// expression that is used to access said variable for the guard of the /// match arm. pub fn is_ref_for_guard(&self) -> bool { - matches!(self.local_info(), LocalInfo::User(BindingForm::RefForGuard)) + matches!( + self.local_info, + Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::RefForGuard))) + ) } /// Returns `Some` if this is a reference to a static item that is used to /// access that static. pub fn is_ref_to_static(&self) -> bool { - matches!(self.local_info(), LocalInfo::StaticRef { .. }) + matches!(self.local_info, Some(box LocalInfo::StaticRef { .. })) } /// Returns `Some` if this is a reference to a thread-local static item that is used to /// access that static. pub fn is_ref_to_thread_local(&self) -> bool { - match self.local_info() { - LocalInfo::StaticRef { is_thread_local, .. } => *is_thread_local, + match self.local_info { + Some(box LocalInfo::StaticRef { is_thread_local, .. }) => is_thread_local, _ => false, } } /// Returns `true` if this is a DerefTemp pub fn is_deref_temp(&self) -> bool { - match self.local_info() { - LocalInfo::DerefTemp => return true, + match self.local_info { + Some(box LocalInfo::DerefTemp) => return true, _ => (), } return false; @@ -1004,8 +1001,9 @@ impl<'tcx> LocalDecl<'tcx> { pub fn with_source_info(ty: Ty<'tcx>, source_info: SourceInfo) -> Self { LocalDecl { mutability: Mutability::Mut, - local_info: ClearCrossCrate::Set(Box::new(LocalInfo::Boring)), + local_info: None, internal: false, + is_block_tail: None, ty, user_ty: None, source_info, @@ -1025,6 +1023,14 @@ impl<'tcx> LocalDecl<'tcx> { self.mutability = Mutability::Not; self } + + /// Converts `self` into same `LocalDecl` except tagged as internal temporary. + #[inline] + pub fn block_tail(mut self, info: BlockTailInfo) -> Self { + assert!(self.is_block_tail.is_none()); + self.is_block_tail = Some(info); + self + } } #[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)] @@ -3085,7 +3091,7 @@ mod size_asserts { use rustc_data_structures::static_assert_size; // tidy-alphabetical-start static_assert_size!(BasicBlockData<'_>, 144); - static_assert_size!(LocalDecl<'_>, 40); + static_assert_size!(LocalDecl<'_>, 56); static_assert_size!(Statement<'_>, 32); static_assert_size!(StatementKind<'_>, 16); static_assert_size!(Terminator<'_>, 112); diff --git a/compiler/rustc_middle/src/mir/patch.rs b/compiler/rustc_middle/src/mir/patch.rs index eb860c04de20..24fe3b47256e 100644 --- a/compiler/rustc_middle/src/mir/patch.rs +++ b/compiler/rustc_middle/src/mir/patch.rs @@ -72,12 +72,12 @@ impl<'tcx> MirPatch<'tcx> { &mut self, ty: Ty<'tcx>, span: Span, - local_info: LocalInfo<'tcx>, + local_info: Option>>, ) -> Local { let index = self.next_local; self.next_local += 1; let mut new_decl = LocalDecl::new(ty, span).internal(); - **new_decl.local_info.as_mut().assert_crate_local() = local_info; + new_decl.local_info = local_info; self.new_locals.push(new_decl); Local::new(index as usize) } diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index cffdd7ff37f2..cbeacf21c19f 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -804,6 +804,7 @@ macro_rules! make_mir_visitor { source_info, internal: _, local_info: _, + is_block_tail: _, } = local_decl; self.visit_ty($(& $mutability)? *ty, TyContext::LocalDecl { diff --git a/compiler/rustc_mir_build/src/build/expr/as_operand.rs b/compiler/rustc_mir_build/src/build/expr/as_operand.rs index 6941da331fc5..ff3198847df6 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_operand.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_operand.rs @@ -20,7 +20,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { expr: &Expr<'tcx>, ) -> BlockAnd> { let local_scope = self.local_scope(); - self.as_operand(block, Some(local_scope), expr, LocalInfo::Boring, NeedsTemporary::Maybe) + self.as_operand(block, Some(local_scope), expr, None, NeedsTemporary::Maybe) } /// Returns an operand suitable for use until the end of the current scope expression and @@ -102,7 +102,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { mut block: BasicBlock, scope: Option, expr: &Expr<'tcx>, - local_info: LocalInfo<'tcx>, + local_info: Option>>, needs_temporary: NeedsTemporary, ) -> BlockAnd> { let this = self; @@ -124,12 +124,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } Category::Constant | Category::Place | Category::Rvalue(..) => { let operand = unpack!(block = this.as_temp(block, scope, expr, Mutability::Mut)); - // Overwrite temp local info if we have something more interesting to record. - if !matches!(local_info, LocalInfo::Boring) { - let decl_info = this.local_decls[operand].local_info.as_mut().assert_crate_local(); - if let LocalInfo::Boring | LocalInfo::BlockTailTemp(_) = **decl_info { - **decl_info = local_info; - } + if this.local_decls[operand].local_info.is_none() { + this.local_decls[operand].local_info = local_info; } block.and(Operand::Move(Place::from(operand))) } @@ -182,6 +178,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - this.as_operand(block, scope, expr, LocalInfo::Boring, NeedsTemporary::Maybe) + this.as_operand(block, scope, expr, None, NeedsTemporary::Maybe) } } diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs index 9f48986b1ad8..259e0f8f75c1 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs @@ -64,7 +64,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block, scope, &this.thir[value], - LocalInfo::Boring, + None, NeedsTemporary::No ) ); @@ -74,18 +74,18 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ExprKind::Binary { op, lhs, rhs } => { let lhs = unpack!( block = - this.as_operand(block, scope, &this.thir[lhs], LocalInfo::Boring, NeedsTemporary::Maybe) + this.as_operand(block, scope, &this.thir[lhs], None, NeedsTemporary::Maybe) ); let rhs = unpack!( block = - this.as_operand(block, scope, &this.thir[rhs], LocalInfo::Boring, NeedsTemporary::No) + this.as_operand(block, scope, &this.thir[rhs], None, NeedsTemporary::No) ); this.build_binary_op(block, op, expr_span, expr.ty, lhs, rhs) } ExprKind::Unary { op, arg } => { let arg = unpack!( block = - this.as_operand(block, scope, &this.thir[arg], LocalInfo::Boring, NeedsTemporary::No) + this.as_operand(block, scope, &this.thir[arg], None, NeedsTemporary::No) ); // Check for -MIN on signed integers if this.check_overflow && op == UnOp::Neg && expr.ty.is_signed() { @@ -260,7 +260,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } else { let ty = source.ty; let source = unpack!( - block = this.as_operand(block, scope, source, LocalInfo::Boring, NeedsTemporary::No) + block = this.as_operand(block, scope, source, None, NeedsTemporary::No) ); (source, ty) }; @@ -273,7 +273,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ExprKind::Pointer { cast, source } => { let source = unpack!( block = - this.as_operand(block, scope, &this.thir[source], LocalInfo::Boring, NeedsTemporary::No) + this.as_operand(block, scope, &this.thir[source], None, NeedsTemporary::No) ); block.and(Rvalue::Cast(CastKind::Pointer(cast), source, expr.ty)) } @@ -315,7 +315,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block, scope, &this.thir[f], - LocalInfo::Boring, + None, NeedsTemporary::Maybe ) ) @@ -336,7 +336,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block, scope, &this.thir[f], - LocalInfo::Boring, + None, NeedsTemporary::Maybe ) ) @@ -424,7 +424,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block, scope, upvar, - LocalInfo::Boring, + None, NeedsTemporary::Maybe ) ) @@ -503,7 +503,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Some(Category::Rvalue(RvalueFunc::AsRvalue) | Category::Constant) )); let operand = - unpack!(block = this.as_operand(block, scope, expr, LocalInfo::Boring, NeedsTemporary::No)); + unpack!(block = this.as_operand(block, scope, expr, None, NeedsTemporary::No)); block.and(Rvalue::Use(operand)) } } @@ -663,7 +663,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } else { // For a non-const, we may need to generate an appropriate `Drop` let value_operand = - unpack!(block = this.as_operand(block, scope, value, LocalInfo::Boring, NeedsTemporary::No)); + unpack!(block = this.as_operand(block, scope, value, None, NeedsTemporary::No)); if let Operand::Move(to_drop) = value_operand { let success = this.cfg.start_new_block(); this.cfg.terminate( diff --git a/compiler/rustc_mir_build/src/build/expr/as_temp.rs b/compiler/rustc_mir_build/src/build/expr/as_temp.rs index c8910c272b1b..3d3cf75559e3 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_temp.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_temp.rs @@ -49,28 +49,29 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } debug!("creating temp {:?} with block_context: {:?}", local_decl, this.block_context); - let local_info = match expr.kind { + // Find out whether this temp is being created within the + // tail expression of a block whose result is ignored. + if let Some(tail_info) = this.block_context.currently_in_block_tail() { + local_decl = local_decl.block_tail(tail_info); + } + match expr.kind { ExprKind::StaticRef { def_id, .. } => { assert!(!this.tcx.is_thread_local_static(def_id)); local_decl.internal = true; - LocalInfo::StaticRef { def_id, is_thread_local: false } + local_decl.local_info = + Some(Box::new(LocalInfo::StaticRef { def_id, is_thread_local: false })); } ExprKind::ThreadLocalRef(def_id) => { assert!(this.tcx.is_thread_local_static(def_id)); local_decl.internal = true; - LocalInfo::StaticRef { def_id, is_thread_local: true } + local_decl.local_info = + Some(Box::new(LocalInfo::StaticRef { def_id, is_thread_local: true })); } ExprKind::NamedConst { def_id, .. } | ExprKind::ConstParam { def_id, .. } => { - LocalInfo::ConstRef { def_id } - } - // Find out whether this temp is being created within the - // tail expression of a block whose result is ignored. - _ if let Some(tail_info) = this.block_context.currently_in_block_tail() => { - LocalInfo::BlockTailTemp(tail_info) + local_decl.local_info = Some(Box::new(LocalInfo::ConstRef { def_id })); } - _ => LocalInfo::Boring, - }; - **local_decl.local_info.as_mut().assert_crate_local() = local_info; + _ => {} + } this.local_decls.push(local_decl) }; let temp_place = Place::from(temp); diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs index ebe8ea25ad3a..dac9bf0a8835 100644 --- a/compiler/rustc_mir_build/src/build/expr/into.rs +++ b/compiler/rustc_mir_build/src/build/expr/into.rs @@ -328,6 +328,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let fields_map: FxHashMap<_, _> = fields .into_iter() .map(|f| { + let local_info = Box::new(LocalInfo::AggregateTemp); ( f.name, unpack!( @@ -335,7 +336,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block, Some(scope), &this.thir[f.expr], - LocalInfo::AggregateTemp, + Some(local_info), NeedsTemporary::Maybe, ) ), @@ -525,7 +526,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block, Some(scope), &this.thir[value], - LocalInfo::Boring, + None, NeedsTemporary::No ) ); diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 22785dfd2ce0..3fb8a6db2d27 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -607,9 +607,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // }; // ``` if let Some(place) = initializer.try_to_place(self) { - let LocalInfo::User(BindingForm::Var( + let Some(box LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var( VarBindingForm { opt_match_place: Some((ref mut match_place, _)), .. }, - )) = **self.local_decls[local].local_info.as_mut().assert_crate_local() else { + )))) = self.local_decls[local].local_info else { bug!("Let binding to non-user variable.") }; *match_place = Some(place); @@ -1754,7 +1754,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let fake_borrow_ty = tcx.mk_imm_ref(tcx.lifetimes.re_erased, fake_borrow_deref_ty); let mut fake_borrow_temp = LocalDecl::new(fake_borrow_ty, temp_span); fake_borrow_temp.internal = self.local_decls[matched_place.local].internal; - fake_borrow_temp.local_info = ClearCrossCrate::Set(Box::new(LocalInfo::FakeBorrow)); + fake_borrow_temp.local_info = Some(Box::new(LocalInfo::FakeBorrow)); let fake_borrow_temp = self.local_decls.push(fake_borrow_temp); (matched_place, fake_borrow_temp) @@ -2224,7 +2224,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { user_ty: if user_ty.is_empty() { None } else { Some(Box::new(user_ty)) }, source_info, internal: false, - local_info: ClearCrossCrate::Set(Box::new(LocalInfo::User(BindingForm::Var( + is_block_tail: None, + local_info: Some(Box::new(LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var( VarBindingForm { binding_mode, // hypothetically, `visit_primary_bindings` could try to unzip @@ -2235,7 +2236,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { opt_match_place, pat_span, }, - )))), + ))))), }; let for_arm_body = self.local_decls.push(local); self.var_debug_info.push(VarDebugInfo { @@ -2252,7 +2253,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { user_ty: None, source_info, internal: false, - local_info: ClearCrossCrate::Set(Box::new(LocalInfo::User(BindingForm::RefForGuard))), + is_block_tail: None, + local_info: Some(Box::new(LocalInfo::User(ClearCrossCrate::Set( + BindingForm::RefForGuard, + )))), }); self.var_debug_info.push(VarDebugInfo { name, diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index 6814fd4cb35e..70d5fc2d9588 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -876,20 +876,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } => { self.local_decls[local].mutability = mutability; self.local_decls[local].source_info.scope = self.source_scope; - **self.local_decls[local].local_info.as_mut().assert_crate_local() = if let Some(kind) = param.self_kind { - LocalInfo::User( + self.local_decls[local].local_info = if let Some(kind) = param.self_kind { + Some(Box::new(LocalInfo::User(ClearCrossCrate::Set( BindingForm::ImplicitSelf(kind), - ) + )))) } else { let binding_mode = ty::BindingMode::BindByValue(mutability); - LocalInfo::User(BindingForm::Var( + Some(Box::new(LocalInfo::User(ClearCrossCrate::Set(BindingForm::Var( VarBindingForm { binding_mode, opt_ty_info: param.ty_span, opt_match_place: Some((None, span)), pat_span: span, }, - )) + ))))) }; self.var_indices.insert(var, LocalsForNode::One(local)); } diff --git a/compiler/rustc_mir_transform/src/check_const_item_mutation.rs b/compiler/rustc_mir_transform/src/check_const_item_mutation.rs index 3d32c586554d..536745d2cfea 100644 --- a/compiler/rustc_mir_transform/src/check_const_item_mutation.rs +++ b/compiler/rustc_mir_transform/src/check_const_item_mutation.rs @@ -24,7 +24,7 @@ struct ConstMutationChecker<'a, 'tcx> { impl<'tcx> ConstMutationChecker<'_, 'tcx> { fn is_const_item(&self, local: Local) -> Option { - if let LocalInfo::ConstRef { def_id } = *self.body.local_decls[local].local_info() { + if let Some(box LocalInfo::ConstRef { def_id }) = self.body.local_decls[local].local_info { Some(def_id) } else { None diff --git a/compiler/rustc_mir_transform/src/check_unsafety.rs b/compiler/rustc_mir_transform/src/check_unsafety.rs index c4d058e8ecbf..a8ec568eb0d7 100644 --- a/compiler/rustc_mir_transform/src/check_unsafety.rs +++ b/compiler/rustc_mir_transform/src/check_unsafety.rs @@ -182,7 +182,7 @@ impl<'tcx> Visitor<'tcx> for UnsafetyChecker<'_, 'tcx> { // If the projection root is an artificial local that we introduced when // desugaring `static`, give a more specific error message // (avoid the general "raw pointer" clause below, that would only be confusing). - if let LocalInfo::StaticRef { def_id, .. } = *decl.local_info() { + if let Some(box LocalInfo::StaticRef { def_id, .. }) = decl.local_info { if self.tcx.is_mutable_static(def_id) { self.require_unsafe( UnsafetyViolationKind::General, diff --git a/compiler/rustc_mir_transform/src/deref_separator.rs b/compiler/rustc_mir_transform/src/deref_separator.rs index b8a5b92be4a6..7508df92df1d 100644 --- a/compiler/rustc_mir_transform/src/deref_separator.rs +++ b/compiler/rustc_mir_transform/src/deref_separator.rs @@ -40,7 +40,7 @@ impl<'tcx> MutVisitor<'tcx> for DerefChecker<'tcx> { let temp = self.patcher.new_internal_with_info( ty, self.local_decls[p_ref.local].source_info.span, - LocalInfo::DerefTemp, + Some(Box::new(LocalInfo::DerefTemp)), ); // We are adding current p_ref's projections to our diff --git a/compiler/rustc_mir_transform/src/dest_prop.rs b/compiler/rustc_mir_transform/src/dest_prop.rs index 35e7efed87a9..7344ec793ea6 100644 --- a/compiler/rustc_mir_transform/src/dest_prop.rs +++ b/compiler/rustc_mir_transform/src/dest_prop.rs @@ -788,7 +788,7 @@ impl<'tcx> Visitor<'tcx> for FindAssignments<'_, '_, 'tcx> { fn is_local_required(local: Local, body: &Body<'_>) -> bool { match body.local_kind(local) { LocalKind::Arg | LocalKind::ReturnPointer => true, - LocalKind::Temp => false, + LocalKind::Var | LocalKind::Temp => false, } } diff --git a/compiler/rustc_mir_transform/src/generator.rs b/compiler/rustc_mir_transform/src/generator.rs index e6875fad3068..b7f1cdfc7f21 100644 --- a/compiler/rustc_mir_transform/src/generator.rs +++ b/compiler/rustc_mir_transform/src/generator.rs @@ -924,19 +924,13 @@ fn compute_layout<'tcx>( debug!(?decl); let ignore_for_traits = if tcx.sess.opts.unstable_opts.drop_tracking_mir { - // Do not `assert_crate_local` here, as post-borrowck cleanup may have already cleared - // the information. This is alright, since `ignore_for_traits` is only relevant when - // this code runs on pre-cleanup MIR, and `ignore_for_traits = false` is the safer - // default. match decl.local_info { // Do not include raw pointers created from accessing `static` items, as those could // well be re-created by another access to the same static. - ClearCrossCrate::Set(box LocalInfo::StaticRef { is_thread_local, .. }) => { - !is_thread_local - } + Some(box LocalInfo::StaticRef { is_thread_local, .. }) => !is_thread_local, // Fake borrows are only read by fake reads, so do not have any reality in // post-analysis MIR. - ClearCrossCrate::Set(box LocalInfo::FakeBorrow) => true, + Some(box LocalInfo::FakeBorrow) => true, _ => false, } } else { diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 50c3023b02bd..b2c477c84d2f 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -29,9 +29,9 @@ use rustc_hir::intravisit::{self, Visitor}; use rustc_index::vec::IndexVec; use rustc_middle::mir::visit::Visitor as _; use rustc_middle::mir::{ - traversal, AnalysisPhase, Body, ClearCrossCrate, ConstQualifs, Constant, LocalDecl, MirPass, - MirPhase, Operand, Place, ProjectionElem, Promoted, RuntimePhase, Rvalue, SourceInfo, - Statement, StatementKind, TerminatorKind, + traversal, AnalysisPhase, Body, ConstQualifs, Constant, LocalDecl, MirPass, MirPhase, Operand, + Place, ProjectionElem, Promoted, RuntimePhase, Rvalue, SourceInfo, Statement, StatementKind, + TerminatorKind, }; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt}; @@ -532,12 +532,6 @@ fn run_runtime_cleanup_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { &[&lower_intrinsics::LowerIntrinsics, &simplify::SimplifyCfg::new("elaborate-drops")]; pm::run_passes(tcx, body, passes, Some(MirPhase::Runtime(RuntimePhase::PostCleanup))); - - // Clear this by anticipation. Optimizations and runtime MIR have no reason to look - // into this information, which is meant for borrowck diagnostics. - for decl in &mut body.local_decls { - decl.local_info = ClearCrossCrate::Clear; - } } fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { diff --git a/compiler/rustc_mir_transform/src/nrvo.rs b/compiler/rustc_mir_transform/src/nrvo.rs index b6e73eaad509..4291e81c78c2 100644 --- a/compiler/rustc_mir_transform/src/nrvo.rs +++ b/compiler/rustc_mir_transform/src/nrvo.rs @@ -102,7 +102,7 @@ fn local_eligible_for_nrvo(body: &mut mir::Body<'_>) -> Option { mir::LocalKind::Arg => return None, mir::LocalKind::ReturnPointer => bug!("Return place was assigned to itself?"), - mir::LocalKind::Temp => {} + mir::LocalKind::Var | mir::LocalKind::Temp => {} } // If multiple different locals are copied to the return place. We can't pick a diff --git a/src/tools/clippy/tests/ui/redundant_clone.fixed b/src/tools/clippy/tests/ui/redundant_clone.fixed index 00b427450935..e51c502a5119 100644 --- a/src/tools/clippy/tests/ui/redundant_clone.fixed +++ b/src/tools/clippy/tests/ui/redundant_clone.fixed @@ -62,6 +62,8 @@ fn main() { clone_then_move_cloned(); hashmap_neg(); false_negative_5707(); + false_positive_10577(); + false_positive_10517(); } #[derive(Clone)] @@ -239,3 +241,26 @@ fn false_negative_5707() { let _z = x.clone(); // pr 7346 can't lint on `x` drop(y); } + +fn false_positive_10577() { + use std::sync::Arc; + #[derive(Clone)] + struct Account { + data: Arc, + } + + fn take(_a: &T) { + } + + let account = Account {data: Arc::new(30)}; + let data = account.data.clone(); + take(&account); + take(&data); +} + +#[allow(unused_variables)] +fn false_positive_10517() { + let i: Box<_> = Box::new(1); + let j = i.clone(); + assert_eq!(*i, 2); +} diff --git a/src/tools/clippy/tests/ui/redundant_clone.rs b/src/tools/clippy/tests/ui/redundant_clone.rs index f899127db8d0..846a6c71b550 100644 --- a/src/tools/clippy/tests/ui/redundant_clone.rs +++ b/src/tools/clippy/tests/ui/redundant_clone.rs @@ -62,6 +62,8 @@ fn main() { clone_then_move_cloned(); hashmap_neg(); false_negative_5707(); + false_positive_10577(); + false_positive_10517(); } #[derive(Clone)] @@ -239,3 +241,26 @@ fn false_negative_5707() { let _z = x.clone(); // pr 7346 can't lint on `x` drop(y); } + +fn false_positive_10577() { + use std::sync::Arc; + #[derive(Clone)] + struct Account { + data: Arc, + } + + fn take(_a: &T) { + } + + let account = Account {data: Arc::new(30)}; + let data = account.data.clone(); + take(&account); + take(&data); +} + +#[allow(unused_variables)] +fn false_positive_10517() { + let i: Box<_> = Box::new(1); + let j = i.clone(); + assert_eq!(*i, 2); +} diff --git a/src/tools/clippy/tests/ui/redundant_clone.stderr b/src/tools/clippy/tests/ui/redundant_clone.stderr index 782590034d05..d3fa46e0086b 100644 --- a/src/tools/clippy/tests/ui/redundant_clone.stderr +++ b/src/tools/clippy/tests/ui/redundant_clone.stderr @@ -108,73 +108,73 @@ LL | let _t = tup.0.clone(); | ^^^^^ error: redundant clone - --> $DIR/redundant_clone.rs:70:25 + --> $DIR/redundant_clone.rs:72:25 | LL | if b { (a.clone(), a.clone()) } else { (Alpha, a) } | ^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/redundant_clone.rs:70:24 + --> $DIR/redundant_clone.rs:72:24 | LL | if b { (a.clone(), a.clone()) } else { (Alpha, a) } | ^ error: redundant clone - --> $DIR/redundant_clone.rs:127:15 + --> $DIR/redundant_clone.rs:129:15 | LL | let _s = s.clone(); | ^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/redundant_clone.rs:127:14 + --> $DIR/redundant_clone.rs:129:14 | LL | let _s = s.clone(); | ^ error: redundant clone - --> $DIR/redundant_clone.rs:128:15 + --> $DIR/redundant_clone.rs:130:15 | LL | let _t = t.clone(); | ^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/redundant_clone.rs:128:14 + --> $DIR/redundant_clone.rs:130:14 | LL | let _t = t.clone(); | ^ error: redundant clone - --> $DIR/redundant_clone.rs:138:19 + --> $DIR/redundant_clone.rs:140:19 | LL | let _f = f.clone(); | ^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/redundant_clone.rs:138:18 + --> $DIR/redundant_clone.rs:140:18 | LL | let _f = f.clone(); | ^ error: redundant clone - --> $DIR/redundant_clone.rs:150:14 + --> $DIR/redundant_clone.rs:152:14 | LL | let y = x.clone().join("matthias"); | ^^^^^^^^ help: remove this | note: cloned value is neither consumed nor mutated - --> $DIR/redundant_clone.rs:150:13 + --> $DIR/redundant_clone.rs:152:13 | LL | let y = x.clone().join("matthias"); | ^^^^^^^^^ error: redundant clone - --> $DIR/redundant_clone.rs:204:11 + --> $DIR/redundant_clone.rs:206:11 | LL | foo(&x.clone(), move || { | ^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/redundant_clone.rs:204:10 + --> $DIR/redundant_clone.rs:206:10 | LL | foo(&x.clone(), move || { | ^ diff --git a/tests/codegen/fewer-names.rs b/tests/codegen/fewer-names.rs index 7f383a5c1497..ac8cba06b48f 100644 --- a/tests/codegen/fewer-names.rs +++ b/tests/codegen/fewer-names.rs @@ -13,8 +13,8 @@ pub fn sum(x: u32, y: u32) -> u32 { // NO-LABEL: define{{.*}}i32 @sum(i32 noundef %x, i32 noundef %y) // NO-NEXT: start: -// NO-NEXT: %0 = add i32 %y, %x -// NO-NEXT: ret i32 %0 +// NO-NEXT: %z = add i32 %y, %x +// NO-NEXT: ret i32 %z let z = x + y; z } diff --git a/tests/codegen/var-names.rs b/tests/codegen/var-names.rs index 53841df32e8d..d4715efad73c 100644 --- a/tests/codegen/var-names.rs +++ b/tests/codegen/var-names.rs @@ -9,7 +9,7 @@ pub fn test(a: u32, b: u32) -> u32 { // CHECK: %c = add i32 %a, %b let d = c; let e = d * a; - // CHECK-NEXT: %0 = mul i32 %c, %a + // CHECK-NEXT: %e = mul i32 %c, %a e - // CHECK-NEXT: ret i32 %0 + // CHECK-NEXT: ret i32 %e } diff --git a/tests/incremental/hashes/let_expressions.rs b/tests/incremental/hashes/let_expressions.rs index 7aca4324233b..180bf6fec877 100644 --- a/tests/incremental/hashes/let_expressions.rs +++ b/tests/incremental/hashes/let_expressions.rs @@ -193,9 +193,9 @@ pub fn add_initializer() { } #[cfg(not(any(cfail1,cfail4)))] -#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,typeck")] +#[rustc_clean(cfg="cfail2", except="hir_owner_nodes,typeck,optimized_mir")] #[rustc_clean(cfg="cfail3")] -#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,typeck")] +#[rustc_clean(cfg="cfail5", except="hir_owner_nodes,typeck,optimized_mir")] #[rustc_clean(cfg="cfail6")] pub fn add_initializer() { let _x: i16 = 3i16; diff --git a/tests/mir-opt/separate_const_switch.identity.SeparateConstSwitch.diff b/tests/mir-opt/separate_const_switch.identity.SeparateConstSwitch.diff index bdf1de468b39..cfcd43093c07 100644 --- a/tests/mir-opt/separate_const_switch.identity.SeparateConstSwitch.diff +++ b/tests/mir-opt/separate_const_switch.identity.SeparateConstSwitch.diff @@ -12,6 +12,7 @@ let mut _7: !; // in scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10 let mut _8: std::result::Result; // in scope 0 at $DIR/separate_const_switch.rs:+1:9: +1:10 let _9: i32; // in scope 0 at $DIR/separate_const_switch.rs:+1:8: +1:10 + let mut _16: i32; // in scope 0 at $SRC_DIR/core/src/result.rs:LL:COL scope 1 { debug residual => _6; // in scope 1 at $DIR/separate_const_switch.rs:+1:9: +1:10 scope 2 { @@ -22,7 +23,7 @@ scope 9 { debug e => _14; // in scope 9 at $SRC_DIR/core/src/result.rs:LL:COL scope 10 (inlined >::from) { // at $SRC_DIR/core/src/result.rs:LL:COL - debug t => _14; // in scope 10 at $SRC_DIR/core/src/convert/mod.rs:LL:COL + debug t => _16; // in scope 10 at $SRC_DIR/core/src/convert/mod.rs:LL:COL } } } @@ -89,7 +90,10 @@ StorageLive(_14); // scope 2 at $DIR/separate_const_switch.rs:+1:8: +1:10 _14 = move ((_8 as Err).0: i32); // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL StorageLive(_15); // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL - _15 = move _14; // scope 10 at $SRC_DIR/core/src/convert/mod.rs:LL:COL + StorageLive(_16); // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL + _16 = move _14; // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL + _15 = move _16; // scope 10 at $SRC_DIR/core/src/convert/mod.rs:LL:COL + StorageDead(_16); // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL _0 = Result::::Err(move _15); // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL StorageDead(_15); // scope 9 at $SRC_DIR/core/src/result.rs:LL:COL StorageDead(_14); // scope 2 at $DIR/separate_const_switch.rs:+1:8: +1:10