summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_middle/src/util
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-18 02:49:50 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-18 02:49:50 +0000
commit9835e2ae736235810b4ea1c162ca5e65c547e770 (patch)
tree3fcebf40ed70e581d776a8a4c65923e8ec20e026 /compiler/rustc_middle/src/util
parentReleasing progress-linux version 1.70.0+dfsg2-1~progress7.99u1. (diff)
downloadrustc-9835e2ae736235810b4ea1c162ca5e65c547e770.tar.xz
rustc-9835e2ae736235810b4ea1c162ca5e65c547e770.zip
Merging upstream version 1.71.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_middle/src/util')
-rw-r--r--compiler/rustc_middle/src/util/bug.rs8
-rw-r--r--compiler/rustc_middle/src/util/call_kind.rs142
-rw-r--r--compiler/rustc_middle/src/util/find_self_call.rs36
-rw-r--r--compiler/rustc_middle/src/util/mod.rs7
4 files changed, 189 insertions, 4 deletions
diff --git a/compiler/rustc_middle/src/util/bug.rs b/compiler/rustc_middle/src/util/bug.rs
index b73ae5939..43ee0343f 100644
--- a/compiler/rustc_middle/src/util/bug.rs
+++ b/compiler/rustc_middle/src/util/bug.rs
@@ -31,8 +31,8 @@ fn opt_span_bug_fmt<S: Into<MultiSpan>>(
tls::with_opt(move |tcx| {
let msg = format!("{}: {}", location, args);
match (tcx, span) {
- (Some(tcx), Some(span)) => tcx.sess.diagnostic().span_bug(span, &msg),
- (Some(tcx), None) => tcx.sess.diagnostic().bug(&msg),
+ (Some(tcx), Some(span)) => tcx.sess.diagnostic().span_bug(span, msg),
+ (Some(tcx), None) => tcx.sess.diagnostic().bug(msg),
(None, _) => panic_any(msg),
}
})
@@ -48,6 +48,6 @@ pub fn trigger_delay_span_bug(tcx: TyCtxt<'_>, key: rustc_hir::def_id::DefId) {
);
}
-pub fn provide(providers: &mut crate::ty::query::Providers) {
- *providers = crate::ty::query::Providers { trigger_delay_span_bug, ..*providers };
+pub fn provide(providers: &mut crate::query::Providers) {
+ *providers = crate::query::Providers { trigger_delay_span_bug, ..*providers };
}
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 000000000..98d55ea6d
--- /dev/null
+++ b/compiler/rustc_middle/src/util/call_kind.rs
@@ -0,0 +1,142 @@
+//! 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,
+ /// `.await` calls `IntoFuture::into_future`
+ Await,
+}
+
+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(),
+ Self::Await => tcx.get_diagnostic_item(sym::IntoFuture).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<Ident>,
+ 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<Ident>, 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<Ident>,
+) -> 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 if fn_call_span.is_desugaring(DesugaringKind::Await) {
+ Some((CallDesugaringKind::Await, 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 000000000..0eab0adf0
--- /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 000000000..53b425789
--- /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;