Improve error messages even more

This commit is contained in:
Deadbeef 2021-12-09 22:42:17 +08:00
parent 1b0dcdc341
commit f7f0f843b7
No known key found for this signature in database
GPG Key ID: 6D017A96D8E6C2F9
10 changed files with 433 additions and 238 deletions

View File

@ -1,4 +1,5 @@
use either::Either;
use rustc_const_eval::util::{CallDesugaringKind, CallKind};
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::{Applicability, DiagnosticBuilder};
use rustc_hir as hir;
@ -26,7 +27,7 @@
use super::{
explain_borrow::{BorrowExplanation, LaterUseKind},
FnSelfUseKind, IncludingDowncast, RegionName, RegionNameSource, UseSpans,
IncludingDowncast, RegionName, RegionNameSource, UseSpans,
};
#[derive(Debug)]
@ -195,7 +196,7 @@ pub(crate) fn report_use_of_moved_or_uninitialized(
.map(|n| format!("`{}`", n))
.unwrap_or_else(|| "value".to_owned());
match kind {
FnSelfUseKind::FnOnceCall => {
CallKind::FnCall(once_did) if Some(once_did) == self.infcx.tcx.lang_items().fn_once_trait() => {
err.span_label(
fn_call_span,
&format!(
@ -208,7 +209,8 @@ pub(crate) fn report_use_of_moved_or_uninitialized(
"this value implements `FnOnce`, which causes it to be moved when called",
);
}
FnSelfUseKind::Operator { self_arg } => {
CallKind::Operator { self_arg, .. } => {
let self_arg = self_arg.unwrap();
err.span_label(
fn_call_span,
&format!(
@ -235,12 +237,9 @@ pub(crate) fn report_use_of_moved_or_uninitialized(
);
}
}
FnSelfUseKind::Normal {
self_arg,
implicit_into_iter,
is_option_or_result,
} => {
if implicit_into_iter {
CallKind::Normal { self_arg, desugaring, is_option_or_result } => {
let self_arg = self_arg.unwrap();
if let Some((CallDesugaringKind::ForLoopIntoIter, _)) = desugaring {
err.span_label(
fn_call_span,
&format!(
@ -305,8 +304,8 @@ pub(crate) fn report_use_of_moved_or_uninitialized(
);
}
}
// Deref::deref takes &self, which cannot cause a move
FnSelfUseKind::DerefCoercion { .. } => unreachable!(),
// Other desugarings takes &self, which cannot cause a move
_ => unreachable!(),
}
} else {
err.span_label(
@ -433,7 +432,7 @@ pub(crate) fn report_use_of_moved_or_uninitialized(
}
if let UseSpans::FnSelfUse {
kind: FnSelfUseKind::DerefCoercion { deref_target, deref_target_ty },
kind: CallKind::DerefCoercion { deref_target, deref_target_ty, .. },
..
} = use_spans
{

View File

@ -1,10 +1,10 @@
//! Borrow checker diagnostics.
use rustc_const_eval::util::call_kind;
use rustc_errors::DiagnosticBuilder;
use rustc_hir as hir;
use rustc_hir::def::Namespace;
use rustc_hir::def_id::DefId;
use rustc_hir::lang_items::LangItemGroup;
use rustc_hir::GeneratorKind;
use rustc_middle::mir::{
AggregateKind, Constant, FakeReadCause, Field, Local, LocalInfo, LocalKind, Location, Operand,
@ -13,7 +13,7 @@
use rustc_middle::ty::print::Print;
use rustc_middle::ty::{self, DefIdTree, Instance, Ty, TyCtxt};
use rustc_mir_dataflow::move_paths::{InitLocation, LookupResult};
use rustc_span::{hygiene::DesugaringKind, symbol::sym, Span};
use rustc_span::{symbol::sym, Span};
use rustc_target::abi::VariantIdx;
use super::borrow_set::BorrowData;
@ -37,7 +37,7 @@
crate use outlives_suggestion::OutlivesSuggestionBuilder;
crate use region_errors::{ErrorConstraintInfo, RegionErrorKind, RegionErrors};
crate use region_name::{RegionName, RegionNameSource};
use rustc_span::symbol::Ident;
crate use rustc_const_eval::util::CallKind;
pub(super) struct IncludingDowncast(pub(super) bool);
@ -563,7 +563,7 @@ pub(super) enum UseSpans<'tcx> {
fn_call_span: Span,
/// The definition span of the method being called
fn_span: Span,
kind: FnSelfUseKind<'tcx>,
kind: CallKind<'tcx>,
},
/// This access is caused by a `match` or `if let` pattern.
PatUse(Span),
@ -571,38 +571,15 @@ pub(super) enum UseSpans<'tcx> {
OtherUse(Span),
}
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub(super) enum FnSelfUseKind<'tcx> {
/// A normal method call of the form `receiver.foo(a, b, c)`
Normal {
self_arg: Ident,
implicit_into_iter: bool,
/// Whether the self type of the method call has an `.as_ref()` method.
/// Used for better diagnostics.
is_option_or_result: bool,
},
/// A call to `FnOnce::call_once`, desugared from `my_closure(a, b, c)`
FnOnceCall,
/// A call to an operator trait, desuraged from operator syntax (e.g. `a << b`)
Operator { self_arg: Ident },
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>,
},
}
impl UseSpans<'_> {
pub(super) fn args_or_use(self) -> Span {
match self {
UseSpans::ClosureUse { args_span: span, .. }
| UseSpans::PatUse(span)
| UseSpans::OtherUse(span) => span,
UseSpans::FnSelfUse {
fn_call_span, kind: FnSelfUseKind::DerefCoercion { .. }, ..
} => fn_call_span,
UseSpans::FnSelfUse { fn_call_span, kind: CallKind::DerefCoercion { .. }, .. } => {
fn_call_span
}
UseSpans::FnSelfUse { var_span, .. } => var_span,
}
}
@ -613,9 +590,9 @@ pub(super) fn var_or_use_path_span(self) -> Span {
UseSpans::ClosureUse { path_span: span, .. }
| UseSpans::PatUse(span)
| UseSpans::OtherUse(span) => span,
UseSpans::FnSelfUse {
fn_call_span, kind: FnSelfUseKind::DerefCoercion { .. }, ..
} => fn_call_span,
UseSpans::FnSelfUse { fn_call_span, kind: CallKind::DerefCoercion { .. }, .. } => {
fn_call_span
}
UseSpans::FnSelfUse { var_span, .. } => var_span,
}
}
@ -626,9 +603,9 @@ pub(super) fn var_or_use(self) -> Span {
UseSpans::ClosureUse { capture_kind_span: span, .. }
| UseSpans::PatUse(span)
| UseSpans::OtherUse(span) => span,
UseSpans::FnSelfUse {
fn_call_span, kind: FnSelfUseKind::DerefCoercion { .. }, ..
} => fn_call_span,
UseSpans::FnSelfUse { fn_call_span, kind: CallKind::DerefCoercion { .. }, .. } => {
fn_call_span
}
UseSpans::FnSelfUse { var_span, .. } => var_span,
}
}
@ -904,67 +881,19 @@ pub(super) fn move_spans(
return normal_ret;
};
let tcx = self.infcx.tcx;
let parent = tcx.parent(method_did);
let is_fn_once = parent == tcx.lang_items().fn_once_trait();
let is_operator = !from_hir_call
&& parent.map_or(false, |p| tcx.lang_items().group(LangItemGroup::Op).contains(&p));
let is_deref = !from_hir_call && tcx.is_diagnostic_item(sym::deref_method, method_did);
let fn_call_span = *fn_span;
let self_arg = tcx.fn_arg_names(method_did)[0];
debug!(
"terminator = {:?} from_hir_call={:?}",
self.body[location.block].terminator, from_hir_call
let kind = call_kind(
self.infcx.tcx,
self.param_env,
method_did,
method_substs,
*fn_span,
*from_hir_call,
Some(self.infcx.tcx.fn_arg_names(method_did)[0]),
);
// Check for a 'special' use of 'self' -
// an FnOnce call, an operator (e.g. `<<`), or a
// deref coercion.
let kind = if is_fn_once {
Some(FnSelfUseKind::FnOnceCall)
} else if is_operator {
Some(FnSelfUseKind::Operator { self_arg })
} else if is_deref {
let deref_target =
tcx.get_diagnostic_item(sym::deref_target).and_then(|deref_target| {
Instance::resolve(tcx, self.param_env, deref_target, method_substs)
.transpose()
});
if let Some(Ok(instance)) = deref_target {
let deref_target_ty = instance.ty(tcx, self.param_env);
Some(FnSelfUseKind::DerefCoercion {
deref_target: tcx.def_span(instance.def_id()),
deref_target_ty,
})
} else {
None
}
} else {
None
};
let kind = kind.unwrap_or_else(|| {
// This isn't a 'special' use of `self`
debug!("move_spans: method_did={:?}, fn_call_span={:?}", method_did, fn_call_span);
let implicit_into_iter = Some(method_did) == tcx.lang_items().into_iter_fn()
&& fn_call_span.desugaring_kind() == Some(DesugaringKind::ForLoop);
let parent_self_ty = parent
.filter(|did| tcx.def_kind(*did) == rustc_hir::def::DefKind::Impl)
.and_then(|did| match tcx.type_of(did).kind() {
ty::Adt(def, ..) => Some(def.did),
_ => None,
});
let is_option_or_result = parent_self_ty.map_or(false, |def_id| {
matches!(tcx.get_diagnostic_name(def_id), Some(sym::Option | sym::Result))
});
FnSelfUseKind::Normal { self_arg, implicit_into_iter, is_option_or_result }
});
return FnSelfUse {
var_span: stmt.source_info.span,
fn_call_span,
fn_call_span: *fn_span,
fn_span: self
.infcx
.tcx

View File

@ -1,3 +1,4 @@
use rustc_const_eval::util::CallDesugaringKind;
use rustc_errors::{Applicability, DiagnosticBuilder};
use rustc_infer::infer::TyCtxtInferExt;
use rustc_middle::mir::*;
@ -8,7 +9,7 @@
use rustc_span::{sym, Span, DUMMY_SP};
use rustc_trait_selection::traits::type_known_to_meet_bound_modulo_regions;
use crate::diagnostics::{FnSelfUseKind, UseSpans};
use crate::diagnostics::{CallKind, UseSpans};
use crate::prefixes::PrefixSet;
use crate::MirBorrowckCtxt;
@ -410,7 +411,8 @@ fn report_cannot_move_from_borrowed_content(
Applicability::MaybeIncorrect,
);
} else if let Some(UseSpans::FnSelfUse {
kind: FnSelfUseKind::Normal { implicit_into_iter: true, .. },
kind:
CallKind::Normal { desugaring: Some((CallDesugaringKind::ForLoopIntoIter, _)), .. },
..
}) = use_spans
{

View File

@ -293,13 +293,13 @@ pub fn qualifs_in_return_place(&mut self) -> ConstQualifs {
}
/// Emits an error if an expression cannot be evaluated in the current context.
pub fn check_op(&mut self, op: impl NonConstOp) {
pub fn check_op(&mut self, op: impl NonConstOp<'tcx>) {
self.check_op_spanned(op, self.span);
}
/// Emits an error at the given `span` if an expression cannot be evaluated in the current
/// context.
pub fn check_op_spanned<O: NonConstOp>(&mut self, op: O, span: Span) {
pub fn check_op_spanned<O: NonConstOp<'tcx>>(&mut self, op: O, span: Span) {
let gate = match op.status_in_item(self.ccx) {
Status::Allowed => return,
@ -773,7 +773,7 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location
self.super_terminator(terminator, location);
match &terminator.kind {
TerminatorKind::Call { func, args, .. } => {
TerminatorKind::Call { func, args, fn_span, from_hir_call, .. } => {
let ConstCx { tcx, body, param_env, .. } = *self.ccx;
let caller = self.def_id().to_def_id();
@ -797,7 +797,13 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location
if let Some(trait_id) = tcx.trait_of_item(callee) {
trace!("attempting to call a trait method");
if !self.tcx.features().const_trait_impl {
self.check_op(ops::FnCallNonConst(callee, substs));
self.check_op(ops::FnCallNonConst {
caller,
callee,
substs,
span: *fn_span,
from_hir_call: *from_hir_call,
});
return;
}
@ -856,7 +862,13 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location
}
if !nonconst_call_permission {
self.check_op(ops::FnCallNonConst(callee, substs));
self.check_op(ops::FnCallNonConst {
caller,
callee,
substs,
span: *fn_span,
from_hir_call: *from_hir_call,
});
return;
}
}
@ -925,7 +937,13 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location
}
if !nonconst_call_permission {
self.check_op(ops::FnCallNonConst(callee, substs));
self.check_op(ops::FnCallNonConst {
caller,
callee,
substs,
span: *fn_span,
from_hir_call: *from_hir_call,
});
return;
}
}

View File

@ -3,14 +3,20 @@
use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder};
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_infer::infer::TyCtxtInferExt;
use rustc_infer::traits::{ImplSource, Obligation, ObligationCause};
use rustc_middle::mir;
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
use rustc_middle::{mir, ty::AssocKind};
use rustc_middle::ty::{suggest_constraining_type_param, Adt, Param, TraitPredicate, Ty};
use rustc_middle::ty::{Binder, BoundConstness, ImplPolarity, TraitRef};
use rustc_session::parse::feature_err;
use rustc_span::symbol::sym;
use rustc_span::{symbol::Ident, Span, Symbol};
use rustc_span::{BytePos, Pos};
use rustc_span::{BytePos, Pos, Span, Symbol};
use rustc_trait_selection::traits::SelectionContext;
use super::ConstCx;
use crate::util::{call_kind, CallDesugaringKind, CallKind};
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Status {
@ -29,9 +35,9 @@ pub enum DiagnosticImportance {
}
/// An operation that is not *always* allowed in a const context.
pub trait NonConstOp: std::fmt::Debug {
pub trait NonConstOp<'tcx>: std::fmt::Debug {
/// Returns an enum indicating whether this operation is allowed within the given item.
fn status_in_item(&self, _ccx: &ConstCx<'_, '_>) -> Status {
fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status {
Status::Forbidden
}
@ -39,13 +45,13 @@ fn importance(&self) -> DiagnosticImportance {
DiagnosticImportance::Primary
}
fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx>;
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx>;
}
#[derive(Debug)]
pub struct FloatingPointOp;
impl NonConstOp for FloatingPointOp {
fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
impl<'tcx> NonConstOp<'tcx> for FloatingPointOp {
fn status_in_item(&self, ccx: &ConstCx<'_, 'tcx>) -> Status {
if ccx.const_kind() == hir::ConstContext::ConstFn {
Status::Unstable(sym::const_fn_floating_point_arithmetic)
} else {
@ -53,7 +59,7 @@ fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
}
}
fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
feature_err(
&ccx.tcx.sess.parse_sess,
sym::const_fn_floating_point_arithmetic,
@ -66,40 +72,120 @@ fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBu
/// A function call where the callee is a pointer.
#[derive(Debug)]
pub struct FnCallIndirect;
impl NonConstOp for FnCallIndirect {
fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
impl<'tcx> NonConstOp<'tcx> for FnCallIndirect {
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
ccx.tcx.sess.struct_span_err(span, "function pointers are not allowed in const fn")
}
}
/// A function call where the callee is not marked as `const`.
#[derive(Debug)]
pub struct FnCallNonConst<'tcx>(pub DefId, pub SubstsRef<'tcx>);
impl<'a> NonConstOp for FnCallNonConst<'a> {
fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
let FnCallNonConst(def_id, substs) = *self;
let mut err = struct_span_err!(
ccx.tcx.sess,
span,
E0015,
"cannot call non-const fn `{}` in {}s",
ccx.tcx.def_path_str_with_substs(def_id, substs),
ccx.const_kind()
);
err.note(&format!(
"calls in {}s are limited to constant functions, \
tuple structs and tuple variants",
ccx.const_kind(),
));
#[derive(Debug, Clone, Copy)]
pub struct FnCallNonConst<'tcx> {
pub caller: DefId,
pub callee: DefId,
pub substs: SubstsRef<'tcx>,
pub span: Span,
pub from_hir_call: bool,
}
if let Some(trait_def_id) = ccx.tcx.lang_items().eq_trait() {
if let Some(eq_item) = ccx.tcx.associated_items(trait_def_id).find_by_name_and_kind(
ccx.tcx,
Ident::with_dummy_span(sym::eq),
AssocKind::Fn,
trait_def_id,
) {
if callee == eq_item.def_id && substs.len() == 2 {
impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, _: Span) -> DiagnosticBuilder<'tcx> {
let FnCallNonConst { caller, callee, substs, span, from_hir_call } = *self;
let ConstCx { tcx, param_env, .. } = *ccx;
let diag_trait = |mut err, self_ty: Ty<'_>, trait_id| {
let trait_ref = TraitRef::from_method(tcx, trait_id, substs);
match self_ty.kind() {
Param(param_ty) => {
debug!(?param_ty);
if let Some(generics) = caller
.as_local()
.map(|id| tcx.hir().local_def_id_to_hir_id(id))
.map(|id| tcx.hir().get(id))
.as_ref()
.and_then(|node| node.generics())
{
let constraint = with_no_trimmed_paths(|| {
format!("~const {}", trait_ref.print_only_trait_path())
});
suggest_constraining_type_param(
tcx,
generics,
&mut err,
&param_ty.name.as_str(),
&constraint,
None,
);
}
}
Adt(..) => {
let obligation = Obligation::new(
ObligationCause::dummy(),
param_env,
Binder::dummy(TraitPredicate {
trait_ref,
constness: BoundConstness::ConstIfConst,
polarity: ImplPolarity::Positive,
}),
);
let implsrc = tcx.infer_ctxt().enter(|infcx| {
let mut selcx = SelectionContext::new(&infcx);
selcx.select(&obligation)
});
if let Ok(Some(ImplSource::UserDefined(data))) = implsrc {
let span =
tcx.sess.source_map().guess_head_span(tcx.def_span(data.impl_def_id));
err.span_note(span, "impl defined here, but it is not `const`");
}
}
_ => {}
}
err
};
let call_kind = call_kind(tcx, ccx.param_env, callee, substs, span, from_hir_call, None);
debug!(?call_kind);
let mut err = match call_kind {
CallKind::Normal { desugaring: Some((kind, self_ty)), .. } => {
macro_rules! error {
($fmt:literal) => {
struct_span_err!(tcx.sess, span, E0015, $fmt, self_ty, ccx.const_kind(),)
};
}
let err = match kind {
CallDesugaringKind::ForLoopIntoIter => {
error!("cannot convert `{}` into an iterator in {}s")
}
CallDesugaringKind::QuestionBranch => {
error!("`?` cannot determine the branch of `{}` in {}s")
}
CallDesugaringKind::QuestionFromResidual => {
error!("`?` cannot convert from residual of `{}` in {}s")
}
CallDesugaringKind::TryBlockFromOutput => {
error!("`try` block cannot convert `{}` to the result in {}s")
}
};
diag_trait(err, self_ty, kind.trait_def_id(tcx))
}
CallKind::Operator { trait_id, self_ty, .. } => {
let mut err = struct_span_err!(
tcx.sess,
span,
E0015,
"cannot call non-const operator in {}s",
ccx.const_kind()
);
if Some(trait_id) == ccx.tcx.lang_items().eq_trait() {
match (substs[0].unpack(), substs[1].unpack()) {
(GenericArgKind::Type(self_ty), GenericArgKind::Type(rhs_ty))
if self_ty == rhs_ty
@ -137,8 +223,43 @@ fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBu
_ => {}
}
}
diag_trait(err, self_ty, trait_id)
}
}
CallKind::DerefCoercion { deref_target, deref_target_ty, self_ty } => {
let mut err = struct_span_err!(
tcx.sess,
span,
E0015,
"cannot perform deref coercion on `{}` in {}s",
self_ty,
ccx.const_kind()
);
err.note(&format!("attempting to deref into `{}`", deref_target_ty));
// Check first whether the source is accessible (issue #87060)
if tcx.sess.source_map().span_to_snippet(deref_target).is_ok() {
err.span_note(deref_target, "deref defined here");
}
diag_trait(err, self_ty, tcx.lang_items().deref_trait().unwrap())
}
_ => struct_span_err!(
ccx.tcx.sess,
span,
E0015,
"cannot call non-const fn `{}` in {}s",
ccx.tcx.def_path_str_with_substs(callee, substs),
ccx.const_kind(),
),
};
err.note(&format!(
"calls in {}s are limited to constant functions, \
tuple structs and tuple variants",
ccx.const_kind(),
));
err
}
@ -150,8 +271,8 @@ fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBu
#[derive(Debug)]
pub struct FnCallUnstable(pub DefId, pub Option<Symbol>);
impl NonConstOp for FnCallUnstable {
fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
impl<'tcx> NonConstOp<'tcx> for FnCallUnstable {
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
let FnCallUnstable(def_id, feature) = *self;
let mut err = ccx.tcx.sess.struct_span_err(
@ -176,8 +297,8 @@ fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBu
#[derive(Debug)]
pub struct FnPtrCast;
impl NonConstOp for FnPtrCast {
fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
impl<'tcx> NonConstOp<'tcx> for FnPtrCast {
fn status_in_item(&self, ccx: &ConstCx<'_, 'tcx>) -> Status {
if ccx.const_kind() != hir::ConstContext::ConstFn {
Status::Allowed
} else {
@ -185,7 +306,7 @@ fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
}
}
fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
feature_err(
&ccx.tcx.sess.parse_sess,
sym::const_fn_fn_ptr_basics,
@ -197,8 +318,8 @@ fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBu
#[derive(Debug)]
pub struct Generator(pub hir::GeneratorKind);
impl NonConstOp for Generator {
fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
impl<'tcx> NonConstOp<'tcx> for Generator {
fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status {
if let hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Block) = self.0 {
Status::Unstable(sym::const_async_blocks)
} else {
@ -206,7 +327,7 @@ fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
}
}
fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
let msg = format!("{}s are not allowed in {}s", self.0, ccx.const_kind());
if let hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Block) = self.0 {
feature_err(&ccx.tcx.sess.parse_sess, sym::const_async_blocks, span, &msg)
@ -218,8 +339,8 @@ fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBu
#[derive(Debug)]
pub struct HeapAllocation;
impl NonConstOp for HeapAllocation {
fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
impl<'tcx> NonConstOp<'tcx> for HeapAllocation {
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
let mut err = struct_span_err!(
ccx.tcx.sess,
span,
@ -242,8 +363,8 @@ fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBu
#[derive(Debug)]
pub struct InlineAsm;
impl NonConstOp for InlineAsm {
fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
impl<'tcx> NonConstOp<'tcx> for InlineAsm {
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
struct_span_err!(
ccx.tcx.sess,
span,
@ -258,8 +379,8 @@ fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBu
pub struct LiveDrop {
pub dropped_at: Option<Span>,
}
impl NonConstOp for LiveDrop {
fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
impl<'tcx> NonConstOp<'tcx> for LiveDrop {
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
let mut err = struct_span_err!(
ccx.tcx.sess,
span,
@ -278,8 +399,8 @@ fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBu
/// A borrow of a type that contains an `UnsafeCell` somewhere. The borrow never escapes to
/// the final value of the constant.
pub struct TransientCellBorrow;
impl NonConstOp for TransientCellBorrow {
fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
impl<'tcx> NonConstOp<'tcx> for TransientCellBorrow {
fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status {
Status::Unstable(sym::const_refs_to_cell)
}
fn importance(&self) -> DiagnosticImportance {
@ -287,7 +408,7 @@ fn importance(&self) -> DiagnosticImportance {
// not additionally emit a feature gate error if activating the feature gate won't work.
DiagnosticImportance::Secondary
}
fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
feature_err(
&ccx.tcx.sess.parse_sess,
sym::const_refs_to_cell,
@ -302,8 +423,8 @@ fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBu
/// the final value of the constant, and thus we cannot allow this (for now). We may allow
/// it in the future for static items.
pub struct CellBorrow;
impl NonConstOp for CellBorrow {
fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
impl<'tcx> NonConstOp<'tcx> for CellBorrow {
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
let mut err = struct_span_err!(
ccx.tcx.sess,
span,
@ -339,8 +460,8 @@ fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBu
/// static or const items.
pub struct MutBorrow(pub hir::BorrowKind);
impl NonConstOp for MutBorrow {
fn status_in_item(&self, _ccx: &ConstCx<'_, '_>) -> Status {
impl<'tcx> NonConstOp<'tcx> for MutBorrow {
fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status {
Status::Forbidden
}
@ -350,7 +471,7 @@ fn importance(&self) -> DiagnosticImportance {
DiagnosticImportance::Secondary
}
fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
let raw = match self.0 {
hir::BorrowKind::Raw => "raw ",
hir::BorrowKind::Ref => "",
@ -384,12 +505,12 @@ fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBu
#[derive(Debug)]
pub struct TransientMutBorrow(pub hir::BorrowKind);
impl NonConstOp for TransientMutBorrow {
fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
impl<'tcx> NonConstOp<'tcx> for TransientMutBorrow {
fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status {
Status::Unstable(sym::const_mut_refs)
}
fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
let raw = match self.0 {
hir::BorrowKind::Raw => "raw ",
hir::BorrowKind::Ref => "",
@ -406,8 +527,8 @@ fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBu
#[derive(Debug)]
pub struct MutDeref;
impl NonConstOp for MutDeref {
fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
impl<'tcx> NonConstOp<'tcx> for MutDeref {
fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status {
Status::Unstable(sym::const_mut_refs)
}
@ -416,7 +537,7 @@ fn importance(&self) -> DiagnosticImportance {
DiagnosticImportance::Secondary
}
fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
feature_err(
&ccx.tcx.sess.parse_sess,
sym::const_mut_refs,
@ -429,8 +550,8 @@ fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBu
/// A call to a `panic()` lang item where the first argument is _not_ a `&str`.
#[derive(Debug)]
pub struct PanicNonStr;
impl NonConstOp for PanicNonStr {
fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
impl<'tcx> NonConstOp<'tcx> for PanicNonStr {
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
ccx.tcx.sess.struct_span_err(
span,
"argument to `panic!()` in a const context must have type `&str`",
@ -443,8 +564,8 @@ fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBu
/// allocation base addresses that are not known at compile-time.
#[derive(Debug)]
pub struct RawPtrComparison;
impl NonConstOp for RawPtrComparison {
fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
impl<'tcx> NonConstOp<'tcx> for RawPtrComparison {
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
let mut err = ccx
.tcx
.sess
@ -459,12 +580,12 @@ fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBu
#[derive(Debug)]
pub struct RawMutPtrDeref;
impl NonConstOp for RawMutPtrDeref {
impl<'tcx> NonConstOp<'tcx> for RawMutPtrDeref {
fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
Status::Unstable(sym::const_mut_refs)
}
fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
feature_err(
&ccx.tcx.sess.parse_sess,
sym::const_mut_refs,
@ -479,8 +600,8 @@ fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBu
/// allocation base addresses that are not known at compile-time.
#[derive(Debug)]
pub struct RawPtrToIntCast;
impl NonConstOp for RawPtrToIntCast {
fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
impl<'tcx> NonConstOp<'tcx> for RawPtrToIntCast {
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
let mut err = ccx
.tcx
.sess
@ -496,8 +617,8 @@ fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBu
/// An access to a (non-thread-local) `static`.
#[derive(Debug)]
pub struct StaticAccess;
impl NonConstOp for StaticAccess {
fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
impl<'tcx> NonConstOp<'tcx> for StaticAccess {
fn status_in_item(&self, ccx: &ConstCx<'_, 'tcx>) -> Status {
if let hir::ConstContext::Static(_) = ccx.const_kind() {
Status::Allowed
} else {
@ -505,7 +626,7 @@ fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
}
}
fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
let mut err = struct_span_err!(
ccx.tcx.sess,
span,
@ -530,8 +651,8 @@ fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBu
/// An access to a thread-local `static`.
#[derive(Debug)]
pub struct ThreadLocalAccess;
impl NonConstOp for ThreadLocalAccess {
fn build_error<'tcx>(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
impl<'tcx> NonConstOp<'tcx> for ThreadLocalAccess {
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
struct_span_err!(
ccx.tcx.sess,
span,
@ -548,8 +669,8 @@ pub mod ty {
#[derive(Debug)]
pub struct MutRef(pub mir::LocalKind);
impl NonConstOp for MutRef {
fn status_in_item(&self, _ccx: &ConstCx<'_, '_>) -> Status {
impl<'tcx> NonConstOp<'tcx> for MutRef {
fn status_in_item(&self, _ccx: &ConstCx<'_, 'tcx>) -> Status {
Status::Unstable(sym::const_mut_refs)
}
@ -562,11 +683,7 @@ fn importance(&self) -> DiagnosticImportance {
}
}
fn build_error<'tcx>(
&self,
ccx: &ConstCx<'_, 'tcx>,
span: Span,
) -> DiagnosticBuilder<'tcx> {
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
feature_err(
&ccx.tcx.sess.parse_sess,
sym::const_mut_refs,
@ -578,7 +695,7 @@ fn build_error<'tcx>(
#[derive(Debug)]
pub struct FnPtr(pub mir::LocalKind);
impl NonConstOp for FnPtr {
impl<'tcx> NonConstOp<'tcx> for FnPtr {
fn importance(&self) -> DiagnosticImportance {
match self.0 {
mir::LocalKind::Var | mir::LocalKind::Temp => DiagnosticImportance::Secondary,
@ -588,7 +705,7 @@ fn importance(&self) -> DiagnosticImportance {
}
}
fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
fn status_in_item(&self, ccx: &ConstCx<'_, 'tcx>) -> Status {
if ccx.const_kind() != hir::ConstContext::ConstFn {
Status::Allowed
} else {
@ -596,11 +713,7 @@ fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
}
}
fn build_error<'tcx>(
&self,
ccx: &ConstCx<'_, 'tcx>,
span: Span,
) -> DiagnosticBuilder<'tcx> {
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
feature_err(
&ccx.tcx.sess.parse_sess,
sym::const_fn_fn_ptr_basics,
@ -612,16 +725,12 @@ fn build_error<'tcx>(
#[derive(Debug)]
pub struct ImplTrait;
impl NonConstOp for ImplTrait {
impl<'tcx> NonConstOp<'tcx> for ImplTrait {
fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
Status::Unstable(sym::const_impl_trait)
}
fn build_error<'tcx>(
&self,
ccx: &ConstCx<'_, 'tcx>,
span: Span,
) -> DiagnosticBuilder<'tcx> {
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
feature_err(
&ccx.tcx.sess.parse_sess,
sym::const_impl_trait,
@ -633,7 +742,7 @@ fn build_error<'tcx>(
#[derive(Debug)]
pub struct TraitBound(pub mir::LocalKind);
impl NonConstOp for TraitBound {
impl<'tcx> NonConstOp<'tcx> for TraitBound {
fn importance(&self) -> DiagnosticImportance {
match self.0 {
mir::LocalKind::Var | mir::LocalKind::Temp => DiagnosticImportance::Secondary,
@ -643,7 +752,7 @@ fn importance(&self) -> DiagnosticImportance {
}
}
fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
fn status_in_item(&self, ccx: &ConstCx<'_, 'tcx>) -> Status {
if ccx.const_kind() != hir::ConstContext::ConstFn {
Status::Allowed
} else {
@ -651,11 +760,7 @@ fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
}
}
fn build_error<'tcx>(
&self,
ccx: &ConstCx<'_, 'tcx>,
span: Span,
) -> DiagnosticBuilder<'tcx> {
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
let mut err = feature_err(
&ccx.tcx.sess.parse_sess,
sym::const_fn_trait_bound,
@ -676,7 +781,7 @@ fn build_error<'tcx>(
#[derive(Debug)]
pub struct DynTrait(pub mir::LocalKind);
impl NonConstOp for DynTrait {
impl<'tcx> NonConstOp<'tcx> for DynTrait {
fn importance(&self) -> DiagnosticImportance {
match self.0 {
mir::LocalKind::Var | mir::LocalKind::Temp => DiagnosticImportance::Secondary,
@ -686,7 +791,7 @@ fn importance(&self) -> DiagnosticImportance {
}
}
fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
fn status_in_item(&self, ccx: &ConstCx<'_, 'tcx>) -> Status {
if ccx.const_kind() != hir::ConstContext::ConstFn {
Status::Allowed
} else {
@ -694,11 +799,7 @@ fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status {
}
}
fn build_error<'tcx>(
&self,
ccx: &ConstCx<'_, 'tcx>,
span: Span,
) -> DiagnosticBuilder<'tcx> {
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
let mut err = feature_err(
&ccx.tcx.sess.parse_sess,
sym::const_fn_trait_bound,
@ -720,16 +821,12 @@ fn build_error<'tcx>(
/// A trait bound with the `?const Trait` opt-out
#[derive(Debug)]
pub struct TraitBoundNotConst;
impl NonConstOp for TraitBoundNotConst {
fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status {
impl<'tcx> NonConstOp<'tcx> for TraitBoundNotConst {
fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status {
Status::Unstable(sym::const_trait_bound_opt_out)
}
fn build_error<'tcx>(
&self,
ccx: &ConstCx<'_, 'tcx>,
span: Span,
) -> DiagnosticBuilder<'tcx> {
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
feature_err(
&ccx.tcx.sess.parse_sess,
sym::const_trait_bound_opt_out,

View File

@ -0,0 +1,145 @@
//! 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::LangItemGroup;
use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::{self, AssocItemContainer, DefIdTree, 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.lang_items().try_trait().unwrap()
}
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<Ident>,
desugaring: Option<(CallDesugaringKind, Ty<'tcx>)>,
/// Whether the self type of the method call has an `.as_ref()` method.
/// Used for better diagnostics.
is_option_or_result: bool,
},
/// A call to `Fn(..)::call(..)`, desugared from `my_closure(a, b, c)`
FnCall(DefId),
/// A call to an operator trait, desuraged 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| match assoc.container {
AssocItemContainer::ImplContainer(impl_did) => tcx.trait_id_of_impl(impl_did),
AssocItemContainer::TraitContainer(trait_did) => Some(trait_did),
});
let fn_call = (!from_hir_call)
.then(|| parent)
.flatten()
.and_then(|p| tcx.lang_items().group(LangItemGroup::Fn).iter().find(|did| **did == p));
let operator = (!from_hir_call)
.then(|| parent)
.flatten()
.and_then(|p| tcx.lang_items().group(LangItemGroup::Op).iter().find(|did| **did == p));
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(trait_id))
} 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
};
let parent_self_ty = tcx
.parent(method_did)
.filter(|did| tcx.def_kind(*did) == rustc_hir::def::DefKind::Impl)
.and_then(|did| match tcx.type_of(did).kind() {
ty::Adt(def, ..) => Some(def.did),
_ => None,
});
let is_option_or_result = parent_self_ty.map_or(false, |def_id| {
matches!(tcx.get_diagnostic_name(def_id), Some(sym::Option | sym::Result))
});
CallKind::Normal { self_arg, desugaring, is_option_or_result }
})
}

View File

@ -1,8 +1,10 @@
pub mod aggregate;
mod alignment;
mod call_kind;
pub mod collect_writes;
mod find_self_call;
pub use self::aggregate::expand_aggregate;
pub use self::alignment::is_disaligned;
pub use self::call_kind::{call_kind, CallDesugaringKind, CallKind};
pub use self::find_self_call::find_self_call;

View File

@ -21,6 +21,7 @@
pub enum LangItemGroup {
Op,
Fn,
}
const NUM_GROUPS: usize = 1;
@ -251,9 +252,9 @@ pub fn extract(attrs: &[ast::Attribute]) -> Option<(Symbol, Span)> {
DerefTarget, sym::deref_target, deref_target, Target::AssocTy, GenericRequirement::None;
Receiver, sym::receiver, receiver_trait, Target::Trait, GenericRequirement::None;
Fn, kw::Fn, fn_trait, Target::Trait, GenericRequirement::Exact(1);
FnMut, sym::fn_mut, fn_mut_trait, Target::Trait, GenericRequirement::Exact(1);
FnOnce, sym::fn_once, fn_once_trait, Target::Trait, GenericRequirement::Exact(1);
Fn(Fn), kw::Fn, fn_trait, Target::Trait, GenericRequirement::Exact(1);
FnMut(Fn), sym::fn_mut, fn_mut_trait, Target::Trait, GenericRequirement::Exact(1);
FnOnce(Fn), sym::fn_once, fn_once_trait, Target::Trait, GenericRequirement::Exact(1);
FnOnceOutput, sym::fn_once_output, fn_once_output, Target::AssocTy, GenericRequirement::None;
@ -264,8 +265,8 @@ pub fn extract(attrs: &[ast::Attribute]) -> Option<(Symbol, Span)> {
Unpin, sym::unpin, unpin_trait, Target::Trait, GenericRequirement::None;
Pin, sym::pin, pin_type, Target::Struct, GenericRequirement::None;
PartialEq, sym::eq, eq_trait, Target::Trait, GenericRequirement::Exact(1);
PartialOrd, sym::partial_ord, partial_ord_trait, Target::Trait, GenericRequirement::Exact(1);
PartialEq(Op), sym::eq, eq_trait, Target::Trait, GenericRequirement::Exact(1);
PartialOrd(Op), sym::partial_ord, partial_ord_trait, Target::Trait, GenericRequirement::Exact(1);
// A number of panic-related lang items. The `panic` item corresponds to divide-by-zero and
// various panic cases with `match`. The `panic_bounds_check` item is for indexing arrays.

View File

@ -184,6 +184,7 @@
Formatter,
From,
FromIterator,
FromResidual,
Future,
FxHashMap,
FxHashSet,

View File

@ -302,6 +302,7 @@ pub trait Try: FromResidual {
enclosing_scope = "this function should return `Result` or `Option` to accept `?`"
),
)]
#[rustc_diagnostic_item = "FromResidual"]
#[unstable(feature = "try_trait_v2", issue = "84277")]
pub trait FromResidual<R = <Self as Try>::Residual> {
/// Constructs the type from a compatible `Residual` type.