From 2109fe4e4e3cd8b81a4f91fab8be9a30f2eee8bc Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Sun, 16 Apr 2023 12:03:39 +0200 Subject: Move some utils out of `rustc_const_eval` This allows us to get rid of the `rustc_const_eval->rustc_borrowck` dependency edge which was delaying the compilation of borrowck. The added utils in `rustc_middle` are small and should not affect compile times there. --- Cargo.lock | 1 - compiler/rustc_borrowck/Cargo.toml | 1 - .../src/diagnostics/conflict_errors.rs | 4 +- compiler/rustc_borrowck/src/diagnostics/mod.rs | 6 +- .../src/diagnostics/mutability_errors.rs | 2 +- compiler/rustc_borrowck/src/lib.rs | 1 + compiler/rustc_borrowck/src/util/collect_writes.rs | 36 ++++++ compiler/rustc_borrowck/src/util/mod.rs | 3 + .../src/transform/check_consts/ops.rs | 2 +- compiler/rustc_const_eval/src/util/call_kind.rs | 137 --------------------- .../rustc_const_eval/src/util/collect_writes.rs | 36 ------ .../rustc_const_eval/src/util/find_self_call.rs | 36 ------ compiler/rustc_const_eval/src/util/mod.rs | 5 - compiler/rustc_middle/src/lib.rs | 6 +- compiler/rustc_middle/src/util/call_kind.rs | 137 +++++++++++++++++++++ compiler/rustc_middle/src/util/find_self_call.rs | 36 ++++++ compiler/rustc_middle/src/util/mod.rs | 7 ++ .../src/check_const_item_mutation.rs | 7 +- 18 files changed, 234 insertions(+), 229 deletions(-) create mode 100644 compiler/rustc_borrowck/src/util/collect_writes.rs create mode 100644 compiler/rustc_borrowck/src/util/mod.rs delete mode 100644 compiler/rustc_const_eval/src/util/call_kind.rs delete mode 100644 compiler/rustc_const_eval/src/util/collect_writes.rs delete mode 100644 compiler/rustc_const_eval/src/util/find_self_call.rs create mode 100644 compiler/rustc_middle/src/util/call_kind.rs create mode 100644 compiler/rustc_middle/src/util/find_self_call.rs create mode 100644 compiler/rustc_middle/src/util/mod.rs diff --git a/Cargo.lock b/Cargo.lock index 12be36ef861..670f4cc9562 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4421,7 +4421,6 @@ dependencies = [ "either", "itertools", "polonius-engine", - "rustc_const_eval", "rustc_data_structures", "rustc_errors", "rustc_graphviz", diff --git a/compiler/rustc_borrowck/Cargo.toml b/compiler/rustc_borrowck/Cargo.toml index 87c113f3e30..e0bb87336e5 100644 --- a/compiler/rustc_borrowck/Cargo.toml +++ b/compiler/rustc_borrowck/Cargo.toml @@ -20,7 +20,6 @@ rustc_infer = { path = "../rustc_infer" } rustc_lexer = { path = "../rustc_lexer" } rustc_macros = { path = "../rustc_macros" } rustc_middle = { path = "../rustc_middle" } -rustc_const_eval = { path = "../rustc_const_eval" } rustc_mir_dataflow = { path = "../rustc_mir_dataflow" } rustc_serialize = { path = "../rustc_serialize" } rustc_session = { path = "../rustc_session" } diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 75a3dd0c0f3..6259ae47e89 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -1,5 +1,4 @@ use either::Either; -use rustc_const_eval::util::CallKind; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxIndexSet; use rustc_errors::{ @@ -18,6 +17,7 @@ use rustc_middle::mir::{ ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, VarBindingForm, }; use rustc_middle::ty::{self, suggest_constraining_type_params, PredicateKind, Ty}; +use rustc_middle::util::CallKind; use rustc_mir_dataflow::move_paths::{InitKind, MoveOutIndex, MovePathIndex}; use rustc_span::def_id::LocalDefId; use rustc_span::hygiene::DesugaringKind; @@ -2424,7 +2424,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { Some((method_did, method_substs)), ) = ( &self.body[loan.reserve_location.block].terminator, - rustc_const_eval::util::find_self_call( + rustc_middle::util::find_self_call( tcx, self.body, loan.assigned_place.local, diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index 110354a20d8..dd003b5b040 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -1,7 +1,6 @@ //! Borrow checker diagnostics. use itertools::Itertools; -use rustc_const_eval::util::{call_kind, CallDesugaringKind}; use rustc_errors::{Applicability, Diagnostic}; use rustc_hir as hir; use rustc_hir::def::{CtorKind, Namespace}; @@ -15,6 +14,7 @@ use rustc_middle::mir::{ }; use rustc_middle::ty::print::Print; use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; +use rustc_middle::util::{call_kind, CallDesugaringKind}; use rustc_mir_dataflow::move_paths::{InitLocation, LookupResult}; use rustc_span::def_id::LocalDefId; use rustc_span::{symbol::sym, Span, Symbol, DUMMY_SP}; @@ -45,7 +45,7 @@ pub(crate) use mutability_errors::AccessKind; pub(crate) use outlives_suggestion::OutlivesSuggestionBuilder; pub(crate) use region_errors::{ErrorConstraintInfo, RegionErrorKind, RegionErrors}; pub(crate) use region_name::{RegionName, RegionNameSource}; -pub(crate) use rustc_const_eval::util::CallKind; +pub(crate) use rustc_middle::util::CallKind; pub(super) struct DescribePlaceOpt { pub including_downcast: bool, @@ -874,7 +874,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { }) = &self.body[location.block].terminator { let Some((method_did, method_substs)) = - rustc_const_eval::util::find_self_call( + rustc_middle::util::find_self_call( self.infcx.tcx, &self.body, target_temp, diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index 9d904009650..9c907147e5a 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -15,8 +15,8 @@ use rustc_span::{sym, BytePos, Span}; use rustc_target::abi::FieldIdx; use crate::diagnostics::BorrowedContentSource; +use crate::util::FindAssignments; use crate::MirBorrowckCtxt; -use rustc_const_eval::util::collect_writes::FindAssignments; #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub(crate) enum AccessKind { diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 70d0a101b4e..fdd82c7e3b2 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -88,6 +88,7 @@ mod session_diagnostics; mod type_check; mod universal_regions; mod used_muts; +mod util; /// A public API provided for the Rust compiler consumers. pub mod consumers; diff --git a/compiler/rustc_borrowck/src/util/collect_writes.rs b/compiler/rustc_borrowck/src/util/collect_writes.rs new file mode 100644 index 00000000000..8d92bb35938 --- /dev/null +++ b/compiler/rustc_borrowck/src/util/collect_writes.rs @@ -0,0 +1,36 @@ +use rustc_middle::mir::visit::PlaceContext; +use rustc_middle::mir::visit::Visitor; +use rustc_middle::mir::{Body, Local, Location}; + +pub trait FindAssignments { + // Finds all statements that assign directly to local (i.e., X = ...) + // and returns their locations. + fn find_assignments(&self, local: Local) -> Vec; +} + +impl<'tcx> FindAssignments for Body<'tcx> { + fn find_assignments(&self, local: Local) -> Vec { + let mut visitor = FindLocalAssignmentVisitor { needle: local, locations: vec![] }; + visitor.visit_body(self); + visitor.locations + } +} + +// The Visitor walks the MIR to return the assignment statements corresponding +// to a Local. +struct FindLocalAssignmentVisitor { + needle: Local, + locations: Vec, +} + +impl<'tcx> Visitor<'tcx> for FindLocalAssignmentVisitor { + fn visit_local(&mut self, local: Local, place_context: PlaceContext, location: Location) { + if self.needle != local { + return; + } + + if place_context.is_place_assignment() { + self.locations.push(location); + } + } +} diff --git a/compiler/rustc_borrowck/src/util/mod.rs b/compiler/rustc_borrowck/src/util/mod.rs new file mode 100644 index 00000000000..7377d4de727 --- /dev/null +++ b/compiler/rustc_borrowck/src/util/mod.rs @@ -0,0 +1,3 @@ +mod collect_writes; + +pub use collect_writes::FindAssignments; 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 c0f5b3725b3..4fe842856aa 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs @@ -14,6 +14,7 @@ use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::subst::{GenericArgKind, SubstsRef}; use rustc_middle::ty::{suggest_constraining_type_param, Adt, Closure, FnDef, FnPtr, Param, Ty}; use rustc_middle::ty::{Binder, TraitRef}; +use rustc_middle::util::{call_kind, CallDesugaringKind, CallKind}; use rustc_session::parse::feature_err; use rustc_span::symbol::sym; use rustc_span::{BytePos, Pos, Span, Symbol}; @@ -21,7 +22,6 @@ use rustc_trait_selection::traits::SelectionContext; use super::ConstCx; use crate::errors; -use crate::util::{call_kind, CallDesugaringKind, CallKind}; #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum Status { diff --git a/compiler/rustc_const_eval/src/util/call_kind.rs b/compiler/rustc_const_eval/src/util/call_kind.rs deleted file mode 100644 index 995363c0edd..00000000000 --- a/compiler/rustc_const_eval/src/util/call_kind.rs +++ /dev/null @@ -1,137 +0,0 @@ -//! Common logic for borrowck use-after-move errors when moved into a `fn(self)`, -//! as well as errors when attempting to call a non-const function in a const -//! context. - -use rustc_hir::def_id::DefId; -use rustc_hir::{lang_items, LangItem}; -use rustc_middle::ty::subst::SubstsRef; -use rustc_middle::ty::{AssocItemContainer, Instance, ParamEnv, Ty, TyCtxt}; -use rustc_span::symbol::Ident; -use rustc_span::{sym, DesugaringKind, Span}; - -#[derive(Clone, Copy, PartialEq, Eq, Debug)] -pub enum CallDesugaringKind { - /// for _ in x {} calls x.into_iter() - ForLoopIntoIter, - /// x? calls x.branch() - QuestionBranch, - /// x? calls type_of(x)::from_residual() - QuestionFromResidual, - /// try { ..; x } calls type_of(x)::from_output(x) - TryBlockFromOutput, -} - -impl CallDesugaringKind { - pub fn trait_def_id(self, tcx: TyCtxt<'_>) -> DefId { - match self { - Self::ForLoopIntoIter => tcx.get_diagnostic_item(sym::IntoIterator).unwrap(), - Self::QuestionBranch | Self::TryBlockFromOutput => { - tcx.require_lang_item(LangItem::Try, None) - } - Self::QuestionFromResidual => tcx.get_diagnostic_item(sym::FromResidual).unwrap(), - } - } -} - -#[derive(Clone, Copy, PartialEq, Eq, Debug)] -pub enum CallKind<'tcx> { - /// A normal method call of the form `receiver.foo(a, b, c)` - Normal { - self_arg: Option, - desugaring: Option<(CallDesugaringKind, Ty<'tcx>)>, - method_did: DefId, - method_substs: SubstsRef<'tcx>, - }, - /// A call to `Fn(..)::call(..)`, desugared from `my_closure(a, b, c)` - FnCall { fn_trait_id: DefId, self_ty: Ty<'tcx> }, - /// A call to an operator trait, desugared from operator syntax (e.g. `a << b`) - Operator { self_arg: Option, trait_id: DefId, self_ty: Ty<'tcx> }, - DerefCoercion { - /// The `Span` of the `Target` associated type - /// in the `Deref` impl we are using. - deref_target: Span, - /// The type `T::Deref` we are dereferencing to - deref_target_ty: Ty<'tcx>, - self_ty: Ty<'tcx>, - }, -} - -pub fn call_kind<'tcx>( - tcx: TyCtxt<'tcx>, - param_env: ParamEnv<'tcx>, - method_did: DefId, - method_substs: SubstsRef<'tcx>, - fn_call_span: Span, - from_hir_call: bool, - self_arg: Option, -) -> CallKind<'tcx> { - let parent = tcx.opt_associated_item(method_did).and_then(|assoc| { - let container_id = assoc.container_id(tcx); - match assoc.container { - AssocItemContainer::ImplContainer => tcx.trait_id_of_impl(container_id), - AssocItemContainer::TraitContainer => Some(container_id), - } - }); - - let fn_call = parent.and_then(|p| { - lang_items::FN_TRAITS.iter().filter_map(|&l| tcx.lang_items().get(l)).find(|&id| id == p) - }); - - let operator = if !from_hir_call && let Some(p) = parent { - lang_items::OPERATORS.iter().filter_map(|&l| tcx.lang_items().get(l)).find(|&id| id == p) - } else { - None - }; - - let is_deref = !from_hir_call && tcx.is_diagnostic_item(sym::deref_method, method_did); - - // Check for a 'special' use of 'self' - - // an FnOnce call, an operator (e.g. `<<`), or a - // deref coercion. - let kind = if let Some(trait_id) = fn_call { - Some(CallKind::FnCall { fn_trait_id: trait_id, self_ty: method_substs.type_at(0) }) - } else if let Some(trait_id) = operator { - Some(CallKind::Operator { self_arg, trait_id, self_ty: method_substs.type_at(0) }) - } else if is_deref { - let deref_target = tcx.get_diagnostic_item(sym::deref_target).and_then(|deref_target| { - Instance::resolve(tcx, param_env, deref_target, method_substs).transpose() - }); - if let Some(Ok(instance)) = deref_target { - let deref_target_ty = instance.ty(tcx, param_env); - Some(CallKind::DerefCoercion { - deref_target: tcx.def_span(instance.def_id()), - deref_target_ty, - self_ty: method_substs.type_at(0), - }) - } else { - None - } - } else { - None - }; - - kind.unwrap_or_else(|| { - // This isn't a 'special' use of `self` - debug!(?method_did, ?fn_call_span); - let desugaring = if Some(method_did) == tcx.lang_items().into_iter_fn() - && fn_call_span.desugaring_kind() == Some(DesugaringKind::ForLoop) - { - Some((CallDesugaringKind::ForLoopIntoIter, method_substs.type_at(0))) - } else if fn_call_span.desugaring_kind() == Some(DesugaringKind::QuestionMark) { - if Some(method_did) == tcx.lang_items().branch_fn() { - Some((CallDesugaringKind::QuestionBranch, method_substs.type_at(0))) - } else if Some(method_did) == tcx.lang_items().from_residual_fn() { - Some((CallDesugaringKind::QuestionFromResidual, method_substs.type_at(0))) - } else { - None - } - } else if Some(method_did) == tcx.lang_items().from_output_fn() - && fn_call_span.desugaring_kind() == Some(DesugaringKind::TryBlock) - { - Some((CallDesugaringKind::TryBlockFromOutput, method_substs.type_at(0))) - } else { - None - }; - CallKind::Normal { self_arg, desugaring, method_did, method_substs } - }) -} diff --git a/compiler/rustc_const_eval/src/util/collect_writes.rs b/compiler/rustc_const_eval/src/util/collect_writes.rs deleted file mode 100644 index 8d92bb35938..00000000000 --- a/compiler/rustc_const_eval/src/util/collect_writes.rs +++ /dev/null @@ -1,36 +0,0 @@ -use rustc_middle::mir::visit::PlaceContext; -use rustc_middle::mir::visit::Visitor; -use rustc_middle::mir::{Body, Local, Location}; - -pub trait FindAssignments { - // Finds all statements that assign directly to local (i.e., X = ...) - // and returns their locations. - fn find_assignments(&self, local: Local) -> Vec; -} - -impl<'tcx> FindAssignments for Body<'tcx> { - fn find_assignments(&self, local: Local) -> Vec { - let mut visitor = FindLocalAssignmentVisitor { needle: local, locations: vec![] }; - visitor.visit_body(self); - visitor.locations - } -} - -// The Visitor walks the MIR to return the assignment statements corresponding -// to a Local. -struct FindLocalAssignmentVisitor { - needle: Local, - locations: Vec, -} - -impl<'tcx> Visitor<'tcx> for FindLocalAssignmentVisitor { - fn visit_local(&mut self, local: Local, place_context: PlaceContext, location: Location) { - if self.needle != local { - return; - } - - if place_context.is_place_assignment() { - self.locations.push(location); - } - } -} diff --git a/compiler/rustc_const_eval/src/util/find_self_call.rs b/compiler/rustc_const_eval/src/util/find_self_call.rs deleted file mode 100644 index 33ad128eeeb..00000000000 --- a/compiler/rustc_const_eval/src/util/find_self_call.rs +++ /dev/null @@ -1,36 +0,0 @@ -use rustc_middle::mir::*; -use rustc_middle::ty::subst::SubstsRef; -use rustc_middle::ty::{self, TyCtxt}; -use rustc_span::def_id::DefId; - -/// Checks if the specified `local` is used as the `self` parameter of a method call -/// in the provided `BasicBlock`. If it is, then the `DefId` of the called method is -/// returned. -pub fn find_self_call<'tcx>( - tcx: TyCtxt<'tcx>, - body: &Body<'tcx>, - local: Local, - block: BasicBlock, -) -> Option<(DefId, SubstsRef<'tcx>)> { - debug!("find_self_call(local={:?}): terminator={:?}", local, &body[block].terminator); - if let Some(Terminator { kind: TerminatorKind::Call { func, args, .. }, .. }) = - &body[block].terminator - { - debug!("find_self_call: func={:?}", func); - if let Operand::Constant(box Constant { literal, .. }) = func { - if let ty::FnDef(def_id, substs) = *literal.ty().kind() { - if let Some(ty::AssocItem { fn_has_self_parameter: true, .. }) = - tcx.opt_associated_item(def_id) - { - debug!("find_self_call: args={:?}", args); - if let [Operand::Move(self_place) | Operand::Copy(self_place), ..] = **args { - if self_place.as_local() == Some(local) { - return Some((def_id, substs)); - } - } - } - } - } - } - None -} diff --git a/compiler/rustc_const_eval/src/util/mod.rs b/compiler/rustc_const_eval/src/util/mod.rs index c0aabd77cee..7641f560714 100644 --- a/compiler/rustc_const_eval/src/util/mod.rs +++ b/compiler/rustc_const_eval/src/util/mod.rs @@ -1,14 +1,9 @@ mod alignment; -mod call_kind; mod check_validity_requirement; -pub mod collect_writes; mod compare_types; -mod find_self_call; mod type_name; pub use self::alignment::is_disaligned; -pub use self::call_kind::{call_kind, CallDesugaringKind, CallKind}; pub use self::check_validity_requirement::check_validity_requirement; pub use self::compare_types::{is_equal_up_to_subtyping, is_subtype}; -pub use self::find_self_call::find_self_call; pub use self::type_name::type_name; diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index b4edb02f6c4..1ddc08eac7d 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -99,13 +99,9 @@ pub mod mir; pub mod thir; pub mod traits; pub mod ty; +pub mod util; mod values; -pub mod util { - pub mod bug; - pub mod common; -} - // Allows macros to refer to this crate as `::rustc_middle` extern crate self as rustc_middle; diff --git a/compiler/rustc_middle/src/util/call_kind.rs b/compiler/rustc_middle/src/util/call_kind.rs new file mode 100644 index 00000000000..627c84c388c --- /dev/null +++ b/compiler/rustc_middle/src/util/call_kind.rs @@ -0,0 +1,137 @@ +//! Common logic for borrowck use-after-move errors when moved into a `fn(self)`, +//! as well as errors when attempting to call a non-const function in a const +//! context. + +use crate::ty::subst::SubstsRef; +use crate::ty::{AssocItemContainer, Instance, ParamEnv, Ty, TyCtxt}; +use rustc_hir::def_id::DefId; +use rustc_hir::{lang_items, LangItem}; +use rustc_span::symbol::Ident; +use rustc_span::{sym, DesugaringKind, Span}; + +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +pub enum CallDesugaringKind { + /// for _ in x {} calls x.into_iter() + ForLoopIntoIter, + /// x? calls x.branch() + QuestionBranch, + /// x? calls type_of(x)::from_residual() + QuestionFromResidual, + /// try { ..; x } calls type_of(x)::from_output(x) + TryBlockFromOutput, +} + +impl CallDesugaringKind { + pub fn trait_def_id(self, tcx: TyCtxt<'_>) -> DefId { + match self { + Self::ForLoopIntoIter => tcx.get_diagnostic_item(sym::IntoIterator).unwrap(), + Self::QuestionBranch | Self::TryBlockFromOutput => { + tcx.require_lang_item(LangItem::Try, None) + } + Self::QuestionFromResidual => tcx.get_diagnostic_item(sym::FromResidual).unwrap(), + } + } +} + +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +pub enum CallKind<'tcx> { + /// A normal method call of the form `receiver.foo(a, b, c)` + Normal { + self_arg: Option, + desugaring: Option<(CallDesugaringKind, Ty<'tcx>)>, + method_did: DefId, + method_substs: SubstsRef<'tcx>, + }, + /// A call to `Fn(..)::call(..)`, desugared from `my_closure(a, b, c)` + FnCall { fn_trait_id: DefId, self_ty: Ty<'tcx> }, + /// A call to an operator trait, desugared from operator syntax (e.g. `a << b`) + Operator { self_arg: Option, trait_id: DefId, self_ty: Ty<'tcx> }, + DerefCoercion { + /// The `Span` of the `Target` associated type + /// in the `Deref` impl we are using. + deref_target: Span, + /// The type `T::Deref` we are dereferencing to + deref_target_ty: Ty<'tcx>, + self_ty: Ty<'tcx>, + }, +} + +pub fn call_kind<'tcx>( + tcx: TyCtxt<'tcx>, + param_env: ParamEnv<'tcx>, + method_did: DefId, + method_substs: SubstsRef<'tcx>, + fn_call_span: Span, + from_hir_call: bool, + self_arg: Option, +) -> CallKind<'tcx> { + let parent = tcx.opt_associated_item(method_did).and_then(|assoc| { + let container_id = assoc.container_id(tcx); + match assoc.container { + AssocItemContainer::ImplContainer => tcx.trait_id_of_impl(container_id), + AssocItemContainer::TraitContainer => Some(container_id), + } + }); + + let fn_call = parent.and_then(|p| { + lang_items::FN_TRAITS.iter().filter_map(|&l| tcx.lang_items().get(l)).find(|&id| id == p) + }); + + let operator = if !from_hir_call && let Some(p) = parent { + lang_items::OPERATORS.iter().filter_map(|&l| tcx.lang_items().get(l)).find(|&id| id == p) + } else { + None + }; + + let is_deref = !from_hir_call && tcx.is_diagnostic_item(sym::deref_method, method_did); + + // Check for a 'special' use of 'self' - + // an FnOnce call, an operator (e.g. `<<`), or a + // deref coercion. + let kind = if let Some(trait_id) = fn_call { + Some(CallKind::FnCall { fn_trait_id: trait_id, self_ty: method_substs.type_at(0) }) + } else if let Some(trait_id) = operator { + Some(CallKind::Operator { self_arg, trait_id, self_ty: method_substs.type_at(0) }) + } else if is_deref { + let deref_target = tcx.get_diagnostic_item(sym::deref_target).and_then(|deref_target| { + Instance::resolve(tcx, param_env, deref_target, method_substs).transpose() + }); + if let Some(Ok(instance)) = deref_target { + let deref_target_ty = instance.ty(tcx, param_env); + Some(CallKind::DerefCoercion { + deref_target: tcx.def_span(instance.def_id()), + deref_target_ty, + self_ty: method_substs.type_at(0), + }) + } else { + None + } + } else { + None + }; + + kind.unwrap_or_else(|| { + // This isn't a 'special' use of `self` + debug!(?method_did, ?fn_call_span); + let desugaring = if Some(method_did) == tcx.lang_items().into_iter_fn() + && fn_call_span.desugaring_kind() == Some(DesugaringKind::ForLoop) + { + Some((CallDesugaringKind::ForLoopIntoIter, method_substs.type_at(0))) + } else if fn_call_span.desugaring_kind() == Some(DesugaringKind::QuestionMark) { + if Some(method_did) == tcx.lang_items().branch_fn() { + Some((CallDesugaringKind::QuestionBranch, method_substs.type_at(0))) + } else if Some(method_did) == tcx.lang_items().from_residual_fn() { + Some((CallDesugaringKind::QuestionFromResidual, method_substs.type_at(0))) + } else { + None + } + } else if Some(method_did) == tcx.lang_items().from_output_fn() + && fn_call_span.desugaring_kind() == Some(DesugaringKind::TryBlock) + { + Some((CallDesugaringKind::TryBlockFromOutput, method_substs.type_at(0))) + } else { + None + }; + CallKind::Normal { self_arg, desugaring, method_did, method_substs } + }) +} diff --git a/compiler/rustc_middle/src/util/find_self_call.rs b/compiler/rustc_middle/src/util/find_self_call.rs new file mode 100644 index 00000000000..0eab0adf07e --- /dev/null +++ b/compiler/rustc_middle/src/util/find_self_call.rs @@ -0,0 +1,36 @@ +use crate::mir::*; +use crate::ty::subst::SubstsRef; +use crate::ty::{self, TyCtxt}; +use rustc_span::def_id::DefId; + +/// Checks if the specified `local` is used as the `self` parameter of a method call +/// in the provided `BasicBlock`. If it is, then the `DefId` of the called method is +/// returned. +pub fn find_self_call<'tcx>( + tcx: TyCtxt<'tcx>, + body: &Body<'tcx>, + local: Local, + block: BasicBlock, +) -> Option<(DefId, SubstsRef<'tcx>)> { + debug!("find_self_call(local={:?}): terminator={:?}", local, &body[block].terminator); + if let Some(Terminator { kind: TerminatorKind::Call { func, args, .. }, .. }) = + &body[block].terminator + { + debug!("find_self_call: func={:?}", func); + if let Operand::Constant(box Constant { literal, .. }) = func { + if let ty::FnDef(def_id, substs) = *literal.ty().kind() { + if let Some(ty::AssocItem { fn_has_self_parameter: true, .. }) = + tcx.opt_associated_item(def_id) + { + debug!("find_self_call: args={:?}", args); + if let [Operand::Move(self_place) | Operand::Copy(self_place), ..] = **args { + if self_place.as_local() == Some(local) { + return Some((def_id, substs)); + } + } + } + } + } + } + None +} diff --git a/compiler/rustc_middle/src/util/mod.rs b/compiler/rustc_middle/src/util/mod.rs new file mode 100644 index 00000000000..53b4257899b --- /dev/null +++ b/compiler/rustc_middle/src/util/mod.rs @@ -0,0 +1,7 @@ +pub mod bug; +pub mod call_kind; +pub mod common; +pub mod find_self_call; + +pub use call_kind::{call_kind, CallDesugaringKind, CallKind}; +pub use find_self_call::find_self_call; 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 3d32c586554..57b24c9c552 100644 --- a/compiler/rustc_mir_transform/src/check_const_item_mutation.rs +++ b/compiler/rustc_mir_transform/src/check_const_item_mutation.rs @@ -134,7 +134,12 @@ impl<'tcx> Visitor<'tcx> for ConstMutationChecker<'_, 'tcx> { // the `self` parameter of a method call (as the terminator of our current // BasicBlock). If so, we emit a more specific lint. let method_did = self.target_local.and_then(|target_local| { - crate::util::find_self_call(self.tcx, &self.body, target_local, loc.block) + rustc_middle::util::find_self_call( + self.tcx, + &self.body, + target_local, + loc.block, + ) }); let lint_loc = if method_did.is_some() { self.body.terminator_loc(loc.block) } else { loc }; -- cgit 1.4.1-3-g733a5