2019-11-29 19:48:29 -06:00
|
|
|
//! Print diagnostics to explain why values are borrowed.
|
|
|
|
|
|
2024-02-06 09:51:39 +11:00
|
|
|
#![allow(rustc::diagnostic_outside_of_impl)]
|
|
|
|
|
#![allow(rustc::untranslatable_diagnostic)]
|
|
|
|
|
|
2024-08-11 12:10:36 -04:00
|
|
|
use std::assert_matches::assert_matches;
|
|
|
|
|
|
2024-02-23 10:20:45 +11:00
|
|
|
use rustc_errors::{Applicability, Diag};
|
2023-01-15 03:06:44 +00:00
|
|
|
use rustc_hir as hir;
|
|
|
|
|
use rustc_hir::intravisit::Visitor;
|
2023-04-19 10:57:17 +00:00
|
|
|
use rustc_index::IndexSlice;
|
2021-01-28 16:18:25 +09:00
|
|
|
use rustc_infer::infer::NllRegionVariableOrigin;
|
2023-11-12 13:48:47 +01:00
|
|
|
use rustc_middle::middle::resolve_bound_vars::ObjectLifetimeDefault;
|
2020-03-29 16:41:09 +02:00
|
|
|
use rustc_middle::mir::{
|
2023-06-18 05:24:38 +00:00
|
|
|
Body, CallSource, CastKind, ConstraintCategory, FakeReadCause, Local, LocalInfo, Location,
|
|
|
|
|
Operand, Place, Rvalue, Statement, StatementKind, TerminatorKind,
|
2018-10-05 17:05:33 +02:00
|
|
|
};
|
2023-07-05 20:07:03 +02:00
|
|
|
use rustc_middle::ty::adjustment::PointerCoercion;
|
2023-11-12 13:48:47 +01:00
|
|
|
use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt};
|
2022-07-17 04:09:20 +09:00
|
|
|
use rustc_span::symbol::{kw, Symbol};
|
2021-10-25 23:33:12 -05:00
|
|
|
use rustc_span::{sym, DesugaringKind, Span};
|
2024-07-08 15:36:57 -04:00
|
|
|
use rustc_trait_selection::error_reporting::traits::FindExprBySpan;
|
2018-06-27 16:13:33 -03:00
|
|
|
|
2019-11-27 12:22:17 -06:00
|
|
|
use super::{find_use, RegionName, UseSpans};
|
2019-12-28 20:36:42 -06:00
|
|
|
use crate::borrow_set::BorrowData;
|
|
|
|
|
use crate::nll::ConstraintDescription;
|
2022-09-16 17:33:12 -04:00
|
|
|
use crate::region_infer::{BlameConstraint, Cause, ExtraConstraintInfo};
|
2019-12-28 20:36:42 -06:00
|
|
|
use crate::{MirBorrowckCtxt, WriteKind};
|
2017-12-12 17:29:37 -03:00
|
|
|
|
2019-10-06 21:58:32 +08:00
|
|
|
#[derive(Debug)]
|
2022-10-27 16:15:11 +00:00
|
|
|
pub(crate) enum BorrowExplanation<'tcx> {
|
2021-03-17 02:51:27 -04:00
|
|
|
UsedLater(LaterUseKind, Span, Option<Span>),
|
|
|
|
|
UsedLaterInLoop(LaterUseKind, Span, Option<Span>),
|
2018-09-28 15:25:02 +02:00
|
|
|
UsedLaterWhenDropped {
|
|
|
|
|
drop_loc: Location,
|
|
|
|
|
dropped_local: Local,
|
|
|
|
|
should_note_order: bool,
|
|
|
|
|
},
|
2018-10-14 15:12:02 +01:00
|
|
|
MustBeValidFor {
|
2022-10-27 16:15:11 +00:00
|
|
|
category: ConstraintCategory<'tcx>,
|
2018-10-14 15:12:02 +01:00
|
|
|
from_closure: bool,
|
|
|
|
|
span: Span,
|
|
|
|
|
region_name: RegionName,
|
|
|
|
|
opt_place_desc: Option<String>,
|
2022-09-16 17:33:12 -04:00
|
|
|
extra_info: Vec<ExtraConstraintInfo>,
|
2018-10-14 15:12:02 +01:00
|
|
|
},
|
2018-09-09 19:34:39 +02:00
|
|
|
Unexplained,
|
|
|
|
|
}
|
|
|
|
|
|
2019-10-06 21:58:32 +08:00
|
|
|
#[derive(Clone, Copy, Debug)]
|
2020-12-30 18:48:40 +01:00
|
|
|
pub(crate) enum LaterUseKind {
|
2018-10-05 17:05:33 +02:00
|
|
|
TraitCapture,
|
2018-09-29 11:47:47 +01:00
|
|
|
ClosureCapture,
|
|
|
|
|
Call,
|
|
|
|
|
FakeLetRead,
|
|
|
|
|
Other,
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-27 16:15:11 +00:00
|
|
|
impl<'tcx> BorrowExplanation<'tcx> {
|
2020-12-30 18:48:40 +01:00
|
|
|
pub(crate) fn is_explained(&self) -> bool {
|
2021-11-06 01:31:32 +01:00
|
|
|
!matches!(self, BorrowExplanation::Unexplained)
|
2018-11-30 14:55:51 +01:00
|
|
|
}
|
2022-05-22 17:00:23 +02:00
|
|
|
pub(crate) fn add_explanation_to_diagnostic(
|
2018-09-09 19:34:39 +02:00
|
|
|
&self,
|
2019-06-14 00:48:52 +03:00
|
|
|
tcx: TyCtxt<'tcx>,
|
2019-06-03 18:26:48 -04:00
|
|
|
body: &Body<'tcx>,
|
2023-03-31 00:32:44 -07:00
|
|
|
local_names: &IndexSlice<Local, Option<Symbol>>,
|
2024-02-23 10:20:45 +11:00
|
|
|
err: &mut Diag<'_>,
|
2018-10-05 11:00:05 +02:00
|
|
|
borrow_desc: &str,
|
2019-03-25 19:11:41 -07:00
|
|
|
borrow_span: Option<Span>,
|
2021-06-16 09:44:47 +09:00
|
|
|
multiple_borrow_span: Option<(Span, Span)>,
|
2018-09-09 19:34:39 +02:00
|
|
|
) {
|
2023-01-15 03:06:44 +00:00
|
|
|
if let Some(span) = borrow_span {
|
|
|
|
|
let def_id = body.source.def_id();
|
|
|
|
|
if let Some(node) = tcx.hir().get_if_local(def_id)
|
|
|
|
|
&& let Some(body_id) = node.body_id()
|
|
|
|
|
{
|
|
|
|
|
let body = tcx.hir().body(body_id);
|
2024-04-18 20:41:43 +00:00
|
|
|
let mut expr_finder = FindExprBySpan::new(span, tcx);
|
2023-01-15 03:06:44 +00:00
|
|
|
expr_finder.visit_expr(body.value);
|
|
|
|
|
if let Some(mut expr) = expr_finder.result {
|
2023-01-17 02:45:11 +00:00
|
|
|
while let hir::ExprKind::AddrOf(_, _, inner)
|
2023-01-17 02:47:50 +00:00
|
|
|
| hir::ExprKind::Unary(hir::UnOp::Deref, inner)
|
2023-01-17 02:52:43 +00:00
|
|
|
| hir::ExprKind::Field(inner, _)
|
|
|
|
|
| hir::ExprKind::MethodCall(_, inner, _, _)
|
2023-08-03 21:43:17 +02:00
|
|
|
| hir::ExprKind::Index(inner, _, _) = &expr.kind
|
2023-01-17 02:45:11 +00:00
|
|
|
{
|
2023-01-15 03:06:44 +00:00
|
|
|
expr = inner;
|
|
|
|
|
}
|
|
|
|
|
if let hir::ExprKind::Path(hir::QPath::Resolved(None, p)) = expr.kind
|
|
|
|
|
&& let [hir::PathSegment { ident, args: None, .. }] = p.segments
|
|
|
|
|
&& let hir::def::Res::Local(hir_id) = p.res
|
2024-01-21 21:13:15 +03:00
|
|
|
&& let hir::Node::Pat(pat) = tcx.hir_node(hir_id)
|
2023-01-15 03:06:44 +00:00
|
|
|
{
|
Restrict `From<S>` for `{D,Subd}iagnosticMessage`.
Currently a `{D,Subd}iagnosticMessage` can be created from any type that
impls `Into<String>`. That includes `&str`, `String`, and `Cow<'static,
str>`, which are reasonable. It also includes `&String`, which is pretty
weird, and results in many places making unnecessary allocations for
patterns like this:
```
self.fatal(&format!(...))
```
This creates a string with `format!`, takes a reference, passes the
reference to `fatal`, which does an `into()`, which clones the
reference, doing a second allocation. Two allocations for a single
string, bleh.
This commit changes the `From` impls so that you can only create a
`{D,Subd}iagnosticMessage` from `&str`, `String`, or `Cow<'static,
str>`. This requires changing all the places that currently create one
from a `&String`. Most of these are of the `&format!(...)` form
described above; each one removes an unnecessary static `&`, plus an
allocation when executed. There are also a few places where the existing
use of `&String` was more reasonable; these now just use `clone()` at
the call site.
As well as making the code nicer and more efficient, this is a step
towards possibly using `Cow<'static, str>` in
`{D,Subd}iagnosticMessage::{Str,Eager}`. That would require changing
the `From<&'a str>` impls to `From<&'static str>`, which is doable, but
I'm not yet sure if it's worthwhile.
2023-04-20 13:26:58 +10:00
|
|
|
err.span_label(pat.span, format!("binding `{ident}` declared here"));
|
2023-01-15 03:06:44 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-09-09 19:34:39 +02:00
|
|
|
match *self {
|
2021-03-17 02:51:27 -04:00
|
|
|
BorrowExplanation::UsedLater(later_use_kind, var_or_use_span, path_span) => {
|
2018-10-05 11:00:05 +02:00
|
|
|
let message = match later_use_kind {
|
2019-03-25 19:11:41 -07:00
|
|
|
LaterUseKind::TraitCapture => "captured here by trait object",
|
|
|
|
|
LaterUseKind::ClosureCapture => "captured here by closure",
|
|
|
|
|
LaterUseKind::Call => "used by call",
|
|
|
|
|
LaterUseKind::FakeLetRead => "stored here",
|
|
|
|
|
LaterUseKind::Other => "used here",
|
2018-09-09 19:34:39 +02:00
|
|
|
};
|
2021-03-17 02:51:27 -04:00
|
|
|
// We can use `var_or_use_span` if either `path_span` is not present, or both spans are the same
|
2021-04-28 21:31:49 -04:00
|
|
|
if path_span.map(|path_span| path_span == var_or_use_span).unwrap_or(true) {
|
|
|
|
|
if borrow_span.map(|sp| !sp.overlaps(var_or_use_span)).unwrap_or(true) {
|
2021-03-17 02:51:27 -04:00
|
|
|
err.span_label(
|
|
|
|
|
var_or_use_span,
|
2023-01-06 19:34:45 -05:00
|
|
|
format!("{borrow_desc}borrow later {message}"),
|
2021-03-17 02:51:27 -04:00
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// path_span must be `Some` as otherwise the if condition is true
|
|
|
|
|
let path_span = path_span.unwrap();
|
|
|
|
|
// path_span is only present in the case of closure capture
|
2024-08-11 12:10:36 -04:00
|
|
|
assert_matches!(later_use_kind, LaterUseKind::ClosureCapture);
|
2023-05-24 14:19:22 +00:00
|
|
|
if !borrow_span.is_some_and(|sp| sp.overlaps(var_or_use_span)) {
|
2021-03-17 02:51:27 -04:00
|
|
|
let path_label = "used here by closure";
|
|
|
|
|
let capture_kind_label = message;
|
|
|
|
|
err.span_label(
|
|
|
|
|
var_or_use_span,
|
2023-01-06 19:34:45 -05:00
|
|
|
format!("{borrow_desc}borrow later {capture_kind_label}"),
|
2021-03-17 02:51:27 -04:00
|
|
|
);
|
|
|
|
|
err.span_label(path_span, path_label);
|
|
|
|
|
}
|
2019-03-25 19:11:41 -07:00
|
|
|
}
|
2019-02-20 12:15:27 -03:00
|
|
|
}
|
2021-03-17 02:51:27 -04:00
|
|
|
BorrowExplanation::UsedLaterInLoop(later_use_kind, var_or_use_span, path_span) => {
|
2018-10-05 11:00:05 +02:00
|
|
|
let message = match later_use_kind {
|
2019-02-20 12:15:27 -03:00
|
|
|
LaterUseKind::TraitCapture => {
|
|
|
|
|
"borrow captured here by trait object, in later iteration of loop"
|
|
|
|
|
}
|
|
|
|
|
LaterUseKind::ClosureCapture => {
|
|
|
|
|
"borrow captured here by closure, in later iteration of loop"
|
|
|
|
|
}
|
|
|
|
|
LaterUseKind::Call => "borrow used by call, in later iteration of loop",
|
2018-09-29 11:47:47 +01:00
|
|
|
LaterUseKind::FakeLetRead => "borrow later stored here",
|
|
|
|
|
LaterUseKind::Other => "borrow used here, in later iteration of loop",
|
2018-09-09 19:34:39 +02:00
|
|
|
};
|
2021-03-17 02:51:27 -04:00
|
|
|
// We can use `var_or_use_span` if either `path_span` is not present, or both spans are the same
|
2021-04-28 21:32:01 -04:00
|
|
|
if path_span.map(|path_span| path_span == var_or_use_span).unwrap_or(true) {
|
2023-01-06 19:34:45 -05:00
|
|
|
err.span_label(var_or_use_span, format!("{borrow_desc}{message}"));
|
2021-03-17 02:51:27 -04:00
|
|
|
} else {
|
|
|
|
|
// path_span must be `Some` as otherwise the if condition is true
|
|
|
|
|
let path_span = path_span.unwrap();
|
|
|
|
|
// path_span is only present in the case of closure capture
|
2024-08-11 12:10:36 -04:00
|
|
|
assert_matches!(later_use_kind, LaterUseKind::ClosureCapture);
|
2021-04-28 21:32:28 -04:00
|
|
|
if borrow_span.map(|sp| !sp.overlaps(var_or_use_span)).unwrap_or(true) {
|
2021-03-17 02:51:27 -04:00
|
|
|
let path_label = "used here by closure";
|
|
|
|
|
let capture_kind_label = message;
|
|
|
|
|
err.span_label(
|
|
|
|
|
var_or_use_span,
|
2023-01-06 19:34:45 -05:00
|
|
|
format!("{borrow_desc}borrow later {capture_kind_label}"),
|
2021-03-17 02:51:27 -04:00
|
|
|
);
|
|
|
|
|
err.span_label(path_span, path_label);
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-02-20 12:15:27 -03:00
|
|
|
}
|
|
|
|
|
BorrowExplanation::UsedLaterWhenDropped {
|
|
|
|
|
drop_loc,
|
|
|
|
|
dropped_local,
|
|
|
|
|
should_note_order,
|
|
|
|
|
} => {
|
2019-06-03 18:26:48 -04:00
|
|
|
let local_decl = &body.local_decls[dropped_local];
|
2021-10-25 23:33:12 -05:00
|
|
|
let mut ty = local_decl.ty;
|
|
|
|
|
if local_decl.source_info.span.desugaring_kind() == Some(DesugaringKind::ForLoop) {
|
2023-07-11 22:35:29 +01:00
|
|
|
if let ty::Adt(adt, args) = local_decl.ty.kind() {
|
2022-03-05 07:28:41 +11:00
|
|
|
if tcx.is_diagnostic_item(sym::Option, adt.did()) {
|
2021-10-25 23:33:12 -05:00
|
|
|
// in for loop desugaring, only look at the `Some(..)` inner type
|
2023-07-11 22:35:29 +01:00
|
|
|
ty = args.type_at(0);
|
2021-10-25 23:33:12 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
let (dtor_desc, type_desc) = match ty.kind() {
|
2018-09-28 15:25:02 +02:00
|
|
|
// If type is an ADT that implements Drop, then
|
|
|
|
|
// simplify output by reporting just the ADT name.
|
2023-07-11 22:35:29 +01:00
|
|
|
ty::Adt(adt, _args) if adt.has_dtor(tcx) && !adt.is_box() => {
|
2022-03-05 07:28:41 +11:00
|
|
|
("`Drop` code", format!("type `{}`", tcx.def_path_str(adt.did())))
|
2019-12-22 17:42:04 -05:00
|
|
|
}
|
2018-09-28 15:25:02 +02:00
|
|
|
|
|
|
|
|
// Otherwise, just report the whole type (and use
|
|
|
|
|
// the intentionally fuzzy phrase "destructor")
|
2019-02-20 12:15:27 -03:00
|
|
|
ty::Closure(..) => ("destructor", "closure".to_owned()),
|
2023-10-19 21:46:28 +00:00
|
|
|
ty::Coroutine(..) => ("destructor", "coroutine".to_owned()),
|
2018-09-28 15:25:02 +02:00
|
|
|
|
|
|
|
|
_ => ("destructor", format!("type `{}`", local_decl.ty)),
|
|
|
|
|
};
|
2018-09-09 19:34:39 +02:00
|
|
|
|
2018-05-16 18:58:54 +03:00
|
|
|
match local_names[dropped_local] {
|
2019-05-03 22:24:52 +01:00
|
|
|
Some(local_name) if !local_decl.from_compiler_desugaring() => {
|
2019-02-20 12:15:27 -03:00
|
|
|
let message = format!(
|
2023-01-06 19:34:45 -05:00
|
|
|
"{borrow_desc}borrow might be used here, when `{local_name}` is dropped \
|
|
|
|
|
and runs the {dtor_desc} for {type_desc}",
|
2019-02-20 12:15:27 -03:00
|
|
|
);
|
2019-06-03 18:26:48 -04:00
|
|
|
err.span_label(body.source_info(drop_loc).span, message);
|
2018-09-28 15:25:02 +02:00
|
|
|
|
|
|
|
|
if should_note_order {
|
|
|
|
|
err.note(
|
|
|
|
|
"values in a scope are dropped \
|
|
|
|
|
in the opposite order they are defined",
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-05-03 22:24:52 +01:00
|
|
|
_ => {
|
2019-02-20 12:15:27 -03:00
|
|
|
err.span_label(
|
|
|
|
|
local_decl.source_info.span,
|
|
|
|
|
format!(
|
2023-01-06 19:34:45 -05:00
|
|
|
"a temporary with access to the {borrow_desc}borrow \
|
2019-02-20 12:15:27 -03:00
|
|
|
is created here ...",
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
let message = format!(
|
2023-01-06 19:34:45 -05:00
|
|
|
"... and the {borrow_desc}borrow might be used here, \
|
2019-02-20 12:15:27 -03:00
|
|
|
when that temporary is dropped \
|
2023-01-06 19:34:45 -05:00
|
|
|
and runs the {dtor_desc} for {type_desc}",
|
2019-02-20 12:15:27 -03:00
|
|
|
);
|
2019-06-03 18:26:48 -04:00
|
|
|
err.span_label(body.source_info(drop_loc).span, message);
|
2018-09-28 15:25:02 +02:00
|
|
|
|
2023-03-10 09:08:10 +00:00
|
|
|
if let LocalInfo::BlockTailTemp(info) = local_decl.local_info() {
|
2020-04-16 12:43:40 -07:00
|
|
|
if info.tail_result_is_ignored {
|
2021-06-16 09:44:47 +09:00
|
|
|
// #85581: If the first mutable borrow's scope contains
|
|
|
|
|
// the second borrow, this suggestion isn't helpful.
|
2023-05-24 14:33:43 +00:00
|
|
|
if !multiple_borrow_span.is_some_and(|(old, new)| {
|
|
|
|
|
old.to(info.span.shrink_to_hi()).contains(new)
|
|
|
|
|
}) {
|
2021-06-16 09:44:47 +09:00
|
|
|
err.span_suggestion_verbose(
|
|
|
|
|
info.span.shrink_to_hi(),
|
|
|
|
|
"consider adding semicolon after the expression so its \
|
|
|
|
|
temporaries are dropped sooner, before the local variables \
|
|
|
|
|
declared by the block are dropped",
|
2022-06-13 15:48:40 +09:00
|
|
|
";",
|
2021-06-16 09:44:47 +09:00
|
|
|
Applicability::MaybeIncorrect,
|
|
|
|
|
);
|
|
|
|
|
}
|
2018-09-28 15:25:02 +02:00
|
|
|
} else {
|
2020-04-16 12:43:40 -07:00
|
|
|
err.note(
|
|
|
|
|
"the temporary is part of an expression at the end of a \
|
|
|
|
|
block;\nconsider forcing this temporary to be dropped sooner, \
|
|
|
|
|
before the block's local variables are dropped",
|
|
|
|
|
);
|
|
|
|
|
err.multipart_suggestion(
|
|
|
|
|
"for example, you could save the expression's value in a new \
|
|
|
|
|
local variable `x` and then make `x` be the expression at the \
|
|
|
|
|
end of the block",
|
|
|
|
|
vec![
|
|
|
|
|
(info.span.shrink_to_lo(), "let x = ".to_string()),
|
|
|
|
|
(info.span.shrink_to_hi(), "; x".to_string()),
|
|
|
|
|
],
|
|
|
|
|
Applicability::MaybeIncorrect,
|
|
|
|
|
);
|
2018-09-28 15:25:02 +02:00
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-09-09 19:34:39 +02:00
|
|
|
}
|
2019-02-20 12:15:27 -03:00
|
|
|
}
|
2018-10-14 15:12:02 +01:00
|
|
|
BorrowExplanation::MustBeValidFor {
|
|
|
|
|
category,
|
|
|
|
|
span,
|
|
|
|
|
ref region_name,
|
|
|
|
|
ref opt_place_desc,
|
|
|
|
|
from_closure: _,
|
2022-09-16 17:33:12 -04:00
|
|
|
ref extra_info,
|
2018-10-14 15:12:02 +01:00
|
|
|
} => {
|
|
|
|
|
region_name.highlight_region_name(err);
|
2018-09-28 15:25:02 +02:00
|
|
|
|
2018-10-14 15:12:02 +01:00
|
|
|
if let Some(desc) = opt_place_desc {
|
2019-02-20 12:15:27 -03:00
|
|
|
err.span_label(
|
|
|
|
|
span,
|
|
|
|
|
format!(
|
2023-01-06 19:34:45 -05:00
|
|
|
"{}requires that `{desc}` is borrowed for `{region_name}`",
|
2019-02-20 12:15:27 -03:00
|
|
|
category.description(),
|
|
|
|
|
),
|
|
|
|
|
);
|
2018-10-14 15:12:02 +01:00
|
|
|
} else {
|
2019-02-20 12:15:27 -03:00
|
|
|
err.span_label(
|
|
|
|
|
span,
|
|
|
|
|
format!(
|
2023-01-06 19:34:45 -05:00
|
|
|
"{}requires that {borrow_desc}borrow lasts for `{region_name}`",
|
2019-02-20 12:15:27 -03:00
|
|
|
category.description(),
|
|
|
|
|
),
|
|
|
|
|
);
|
2018-10-14 15:12:02 +01:00
|
|
|
};
|
2019-12-24 19:14:20 +01:00
|
|
|
|
2022-09-16 17:33:12 -04:00
|
|
|
for extra in extra_info {
|
|
|
|
|
match extra {
|
2022-09-16 17:43:45 -04:00
|
|
|
ExtraConstraintInfo::PlaceholderFromPredicate(span) => {
|
2022-12-18 16:17:46 +01:00
|
|
|
err.span_note(*span, "due to current limitations in the borrow checker, this implies a `'static` lifetime");
|
2022-09-16 17:43:45 -04:00
|
|
|
}
|
2022-09-16 17:33:12 -04:00
|
|
|
}
|
|
|
|
|
}
|
2022-09-16 17:43:45 -04:00
|
|
|
|
2023-11-12 13:48:47 +01:00
|
|
|
if let ConstraintCategory::Cast { unsize_to: Some(unsize_ty) } = category {
|
|
|
|
|
self.add_object_lifetime_default_note(tcx, err, unsize_ty);
|
|
|
|
|
}
|
2020-04-05 16:16:55 -07:00
|
|
|
self.add_lifetime_bound_suggestion_to_diagnostic(err, &category, span, region_name);
|
2019-12-24 19:14:20 +01:00
|
|
|
}
|
|
|
|
|
_ => {}
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-08-24 11:34:14 +09:00
|
|
|
|
2023-11-12 13:48:47 +01:00
|
|
|
fn add_object_lifetime_default_note(
|
|
|
|
|
&self,
|
|
|
|
|
tcx: TyCtxt<'tcx>,
|
2024-02-23 10:20:45 +11:00
|
|
|
err: &mut Diag<'_>,
|
2023-11-12 13:48:47 +01:00
|
|
|
unsize_ty: Ty<'tcx>,
|
|
|
|
|
) {
|
|
|
|
|
if let ty::Adt(def, args) = unsize_ty.kind() {
|
|
|
|
|
// We try to elaborate the object lifetime defaults and present those to the user. This should
|
|
|
|
|
// make it clear where the region constraint is coming from.
|
|
|
|
|
let generics = tcx.generics_of(def.did());
|
|
|
|
|
|
|
|
|
|
let mut has_dyn = false;
|
|
|
|
|
let mut failed = false;
|
|
|
|
|
|
2024-05-09 20:56:44 -04:00
|
|
|
let elaborated_args =
|
|
|
|
|
std::iter::zip(*args, &generics.own_params).map(|(arg, param)| {
|
|
|
|
|
if let Some(ty::Dynamic(obj, _, ty::Dyn)) = arg.as_type().map(Ty::kind) {
|
|
|
|
|
let default = tcx.object_lifetime_default(param.def_id);
|
2023-11-12 13:48:47 +01:00
|
|
|
|
2024-05-09 20:56:44 -04:00
|
|
|
let re_static = tcx.lifetimes.re_static;
|
2023-11-12 13:48:47 +01:00
|
|
|
|
2024-05-09 20:56:44 -04:00
|
|
|
let implied_region = match default {
|
|
|
|
|
// This is not entirely precise.
|
|
|
|
|
ObjectLifetimeDefault::Empty => re_static,
|
|
|
|
|
ObjectLifetimeDefault::Ambiguous => {
|
2023-11-12 13:48:47 +01:00
|
|
|
failed = true;
|
|
|
|
|
re_static
|
2024-05-09 20:56:44 -04:00
|
|
|
}
|
|
|
|
|
ObjectLifetimeDefault::Param(param_def_id) => {
|
|
|
|
|
let index = generics.param_def_id_to_index[¶m_def_id] as usize;
|
|
|
|
|
args.get(index).and_then(|arg| arg.as_region()).unwrap_or_else(
|
|
|
|
|
|| {
|
|
|
|
|
failed = true;
|
|
|
|
|
re_static
|
|
|
|
|
},
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
ObjectLifetimeDefault::Static => re_static,
|
|
|
|
|
};
|
2023-11-12 13:48:47 +01:00
|
|
|
|
2024-05-09 20:56:44 -04:00
|
|
|
has_dyn = true;
|
2023-11-12 13:48:47 +01:00
|
|
|
|
2024-05-09 20:56:44 -04:00
|
|
|
Ty::new_dynamic(tcx, obj, implied_region, ty::Dyn).into()
|
|
|
|
|
} else {
|
|
|
|
|
arg
|
|
|
|
|
}
|
|
|
|
|
});
|
2023-11-12 13:48:47 +01:00
|
|
|
let elaborated_ty = Ty::new_adt(tcx, *def, tcx.mk_args_from_iter(elaborated_args));
|
|
|
|
|
|
|
|
|
|
if has_dyn && !failed {
|
|
|
|
|
err.note(format!(
|
|
|
|
|
"due to object lifetime defaults, `{unsize_ty}` actually means `{elaborated_ty}`"
|
|
|
|
|
));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-24 11:34:14 +09:00
|
|
|
fn add_lifetime_bound_suggestion_to_diagnostic(
|
2019-12-24 19:14:20 +01:00
|
|
|
&self,
|
2024-02-23 10:20:45 +11:00
|
|
|
err: &mut Diag<'_>,
|
2022-10-27 16:15:11 +00:00
|
|
|
category: &ConstraintCategory<'tcx>,
|
2019-12-24 19:14:20 +01:00
|
|
|
span: Span,
|
|
|
|
|
region_name: &RegionName,
|
|
|
|
|
) {
|
2022-08-24 11:34:14 +09:00
|
|
|
if !span.is_desugaring(DesugaringKind::OpaqueTy) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2020-03-22 13:36:56 +01:00
|
|
|
if let ConstraintCategory::OpaqueType = category {
|
2020-04-05 16:16:55 -07:00
|
|
|
let suggestable_name =
|
2022-07-17 04:09:20 +09:00
|
|
|
if region_name.was_named() { region_name.name } else { kw::UnderscoreLifetime };
|
2019-12-24 19:14:20 +01:00
|
|
|
|
2020-04-05 16:16:55 -07:00
|
|
|
let msg = format!(
|
2023-01-06 19:34:45 -05:00
|
|
|
"you can add a bound to the {}to make it last less than `'static` and match `{region_name}`",
|
2020-04-05 16:16:55 -07:00
|
|
|
category.description(),
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
err.span_suggestion_verbose(
|
|
|
|
|
span.shrink_to_hi(),
|
Restrict `From<S>` for `{D,Subd}iagnosticMessage`.
Currently a `{D,Subd}iagnosticMessage` can be created from any type that
impls `Into<String>`. That includes `&str`, `String`, and `Cow<'static,
str>`, which are reasonable. It also includes `&String`, which is pretty
weird, and results in many places making unnecessary allocations for
patterns like this:
```
self.fatal(&format!(...))
```
This creates a string with `format!`, takes a reference, passes the
reference to `fatal`, which does an `into()`, which clones the
reference, doing a second allocation. Two allocations for a single
string, bleh.
This commit changes the `From` impls so that you can only create a
`{D,Subd}iagnosticMessage` from `&str`, `String`, or `Cow<'static,
str>`. This requires changing all the places that currently create one
from a `&String`. Most of these are of the `&format!(...)` form
described above; each one removes an unnecessary static `&`, plus an
allocation when executed. There are also a few places where the existing
use of `&String` was more reasonable; these now just use `clone()` at
the call site.
As well as making the code nicer and more efficient, this is a step
towards possibly using `Cow<'static, str>` in
`{D,Subd}iagnosticMessage::{Str,Eager}`. That would require changing
the `From<&'a str>` impls to `From<&'static str>`, which is doable, but
I'm not yet sure if it's worthwhile.
2023-04-20 13:26:58 +10:00
|
|
|
msg,
|
2023-01-06 19:34:45 -05:00
|
|
|
format!(" + {suggestable_name}"),
|
2020-04-05 16:16:55 -07:00
|
|
|
Applicability::Unspecified,
|
|
|
|
|
);
|
2018-09-09 19:34:39 +02:00
|
|
|
}
|
|
|
|
|
}
|
2018-09-09 19:43:10 +01:00
|
|
|
}
|
|
|
|
|
|
2024-06-24 14:28:08 +00:00
|
|
|
impl<'tcx> MirBorrowckCtxt<'_, '_, '_, 'tcx> {
|
2019-12-28 19:25:57 -06:00
|
|
|
fn free_region_constraint_info(
|
|
|
|
|
&self,
|
|
|
|
|
borrow_region: RegionVid,
|
|
|
|
|
outlived_region: RegionVid,
|
2022-10-27 16:15:11 +00:00
|
|
|
) -> (ConstraintCategory<'tcx>, bool, Span, Option<RegionName>, Vec<ExtraConstraintInfo>) {
|
2022-09-16 17:33:12 -04:00
|
|
|
let (blame_constraint, extra_info) = self.regioncx.best_blame_constraint(
|
2022-09-16 17:08:35 -04:00
|
|
|
borrow_region,
|
|
|
|
|
NllRegionVariableOrigin::FreeRegion,
|
|
|
|
|
|r| self.regioncx.provides_universal_region(r, borrow_region, outlived_region),
|
|
|
|
|
);
|
|
|
|
|
let BlameConstraint { category, from_closure, cause, .. } = blame_constraint;
|
2019-12-28 19:25:57 -06:00
|
|
|
|
2019-12-28 20:36:42 -06:00
|
|
|
let outlived_fr_name = self.give_region_a_name(outlived_region);
|
2019-12-28 19:25:57 -06:00
|
|
|
|
2022-09-16 17:33:12 -04:00
|
|
|
(category, from_closure, cause.span, outlived_fr_name, extra_info)
|
2019-12-28 19:25:57 -06:00
|
|
|
}
|
|
|
|
|
|
2018-09-28 11:50:05 +02:00
|
|
|
/// Returns structured explanation for *why* the borrow contains the
|
2019-05-02 06:03:17 +09:00
|
|
|
/// point from `location`. This is key for the "3-point errors"
|
2018-03-05 16:12:19 -03:00
|
|
|
/// [described in the NLL RFC][d].
|
|
|
|
|
///
|
2018-06-13 14:51:53 -03:00
|
|
|
/// # Parameters
|
|
|
|
|
///
|
|
|
|
|
/// - `borrow`: the borrow in question
|
2019-05-02 06:03:17 +09:00
|
|
|
/// - `location`: where the borrow occurs
|
2018-06-13 14:51:53 -03:00
|
|
|
/// - `kind_place`: if Some, this describes the statement that triggered the error.
|
|
|
|
|
/// - first half is the kind of write, if any, being performed
|
|
|
|
|
/// - second half is the place being accessed
|
|
|
|
|
///
|
2018-03-05 16:12:19 -03:00
|
|
|
/// [d]: https://rust-lang.github.io/rfcs/2094-nll.html#leveraging-intuition-framing-errors-in-terms-of-points
|
2022-08-29 02:00:08 -04:00
|
|
|
#[instrument(level = "debug", skip(self))]
|
2020-12-30 18:48:40 +01:00
|
|
|
pub(crate) fn explain_why_borrow_contains_point(
|
2018-09-09 19:43:10 +01:00
|
|
|
&self,
|
2019-05-02 06:03:17 +09:00
|
|
|
location: Location,
|
2018-03-01 11:56:43 -03:00
|
|
|
borrow: &BorrowData<'tcx>,
|
2020-03-30 17:49:33 -03:00
|
|
|
kind_place: Option<(WriteKind, Place<'tcx>)>,
|
2022-10-27 16:15:11 +00:00
|
|
|
) -> BorrowExplanation<'tcx> {
|
2019-12-28 20:02:20 -06:00
|
|
|
let regioncx = &self.regioncx;
|
2023-11-21 20:07:32 +01:00
|
|
|
let body: &Body<'_> = self.body;
|
2018-09-11 16:38:35 +02:00
|
|
|
let tcx = self.infcx.tcx;
|
2017-12-12 17:29:37 -03:00
|
|
|
|
2018-11-10 23:52:20 +00:00
|
|
|
let borrow_region_vid = borrow.region;
|
2022-08-29 02:00:08 -04:00
|
|
|
debug!(?borrow_region_vid);
|
2018-06-13 14:51:53 -03:00
|
|
|
|
2022-09-20 14:44:55 -07:00
|
|
|
let mut region_sub = self.regioncx.find_sub_region_live_at(borrow_region_vid, location);
|
2022-08-29 02:00:08 -04:00
|
|
|
debug!(?region_sub);
|
2018-06-19 21:22:52 -03:00
|
|
|
|
2022-09-20 14:44:55 -07:00
|
|
|
let mut use_location = location;
|
|
|
|
|
let mut use_in_later_iteration_of_loop = false;
|
|
|
|
|
|
|
|
|
|
if region_sub == borrow_region_vid {
|
|
|
|
|
// When `region_sub` is the same as `borrow_region_vid` (the location where the borrow is
|
|
|
|
|
// issued is the same location that invalidates the reference), this is likely a loop iteration
|
|
|
|
|
// - in this case, try using the loop terminator location in `find_sub_region_live_at`.
|
|
|
|
|
if let Some(loop_terminator_location) =
|
|
|
|
|
regioncx.find_loop_terminator_location(borrow.region, body)
|
|
|
|
|
{
|
|
|
|
|
region_sub = self
|
|
|
|
|
.regioncx
|
|
|
|
|
.find_sub_region_live_at(borrow_region_vid, loop_terminator_location);
|
|
|
|
|
debug!("explain_why_borrow_contains_point: region_sub in loop={:?}", region_sub);
|
|
|
|
|
use_location = loop_terminator_location;
|
|
|
|
|
use_in_later_iteration_of_loop = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
match find_use::find(body, regioncx, tcx, region_sub, use_location) {
|
2018-09-09 19:34:39 +02:00
|
|
|
Some(Cause::LiveVar(local, location)) => {
|
2019-06-03 18:26:48 -04:00
|
|
|
let span = body.source_info(location).span;
|
2019-02-20 12:15:27 -03:00
|
|
|
let spans = self
|
2019-07-21 22:38:30 +02:00
|
|
|
.move_spans(Place::from(local).as_ref(), location)
|
2018-08-01 20:38:02 +01:00
|
|
|
.or_else(|| self.borrow_spans(span, location));
|
2018-09-09 19:34:39 +02:00
|
|
|
|
2022-09-20 14:44:55 -07:00
|
|
|
if use_in_later_iteration_of_loop {
|
|
|
|
|
let later_use = self.later_use_kind(borrow, spans, use_location);
|
2021-03-17 02:51:27 -04:00
|
|
|
BorrowExplanation::UsedLaterInLoop(later_use.0, later_use.1, later_use.2)
|
2018-08-01 17:02:43 +02:00
|
|
|
} else {
|
2018-09-09 19:34:39 +02:00
|
|
|
// Check if the location represents a `FakeRead`, and adapt the error
|
|
|
|
|
// message to the `FakeReadCause` it is from: in particular,
|
|
|
|
|
// the ones inserted in optimized `let var = <expr>` patterns.
|
2018-10-05 17:05:33 +02:00
|
|
|
let later_use = self.later_use_kind(borrow, spans, location);
|
2021-03-17 02:51:27 -04:00
|
|
|
BorrowExplanation::UsedLater(later_use.0, later_use.1, later_use.2)
|
2018-09-09 19:34:39 +02:00
|
|
|
}
|
2018-07-01 19:43:01 -03:00
|
|
|
}
|
2018-06-19 21:22:52 -03:00
|
|
|
|
2019-02-20 12:15:27 -03:00
|
|
|
Some(Cause::DropVar(local, location)) => {
|
|
|
|
|
let mut should_note_order = false;
|
2022-02-27 11:10:20 -03:00
|
|
|
if self.local_names[local].is_some()
|
|
|
|
|
&& let Some((WriteKind::StorageDeadOrDrop, place)) = kind_place
|
|
|
|
|
&& let Some(borrowed_local) = place.as_local()
|
|
|
|
|
&& self.local_names[borrowed_local].is_some()
|
|
|
|
|
&& local != borrowed_local
|
|
|
|
|
{
|
|
|
|
|
should_note_order = true;
|
2019-02-20 12:15:27 -03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BorrowExplanation::UsedLaterWhenDropped {
|
|
|
|
|
drop_loc: location,
|
|
|
|
|
dropped_local: local,
|
|
|
|
|
should_note_order,
|
|
|
|
|
}
|
2018-09-28 15:25:02 +02:00
|
|
|
}
|
2018-09-09 19:34:39 +02:00
|
|
|
|
2019-02-20 12:15:27 -03:00
|
|
|
None => {
|
2019-12-20 23:59:31 -06:00
|
|
|
if let Some(region) = self.to_error_region_vid(borrow_region_vid) {
|
2022-09-16 17:33:12 -04:00
|
|
|
let (category, from_closure, span, region_name, extra_info) =
|
2019-12-28 19:25:57 -06:00
|
|
|
self.free_region_constraint_info(borrow_region_vid, region);
|
2019-02-20 12:15:27 -03:00
|
|
|
if let Some(region_name) = region_name {
|
2019-07-21 22:38:30 +02:00
|
|
|
let opt_place_desc = self.describe_place(borrow.borrowed_place.as_ref());
|
2019-02-20 12:15:27 -03:00
|
|
|
BorrowExplanation::MustBeValidFor {
|
|
|
|
|
category,
|
|
|
|
|
from_closure,
|
|
|
|
|
span,
|
|
|
|
|
region_name,
|
|
|
|
|
opt_place_desc,
|
2022-09-16 17:33:12 -04:00
|
|
|
extra_info,
|
2019-02-20 12:15:27 -03:00
|
|
|
}
|
|
|
|
|
} else {
|
2022-08-29 02:00:08 -04:00
|
|
|
debug!("Could not generate a region name");
|
2019-02-20 12:15:27 -03:00
|
|
|
BorrowExplanation::Unexplained
|
2018-12-03 14:13:28 +01:00
|
|
|
}
|
|
|
|
|
} else {
|
2022-08-29 02:00:08 -04:00
|
|
|
debug!("Could not generate an error region vid");
|
2018-12-03 14:13:28 +01:00
|
|
|
BorrowExplanation::Unexplained
|
2018-10-14 15:12:02 +01:00
|
|
|
}
|
|
|
|
|
}
|
2017-12-12 17:29:37 -03:00
|
|
|
}
|
|
|
|
|
}
|
2018-08-01 17:02:43 +02:00
|
|
|
|
2018-10-05 17:05:33 +02:00
|
|
|
/// Determine how the borrow was later used.
|
2021-03-17 02:51:27 -04:00
|
|
|
/// First span returned points to the location of the conflicting use
|
|
|
|
|
/// Second span if `Some` is returned in the case of closures and points
|
|
|
|
|
/// to the use of the path
|
2023-01-05 21:29:36 +00:00
|
|
|
#[instrument(level = "debug", skip(self))]
|
2018-10-05 17:05:33 +02:00
|
|
|
fn later_use_kind(
|
|
|
|
|
&self,
|
|
|
|
|
borrow: &BorrowData<'tcx>,
|
2020-07-25 07:04:13 -04:00
|
|
|
use_spans: UseSpans<'tcx>,
|
2019-02-20 12:15:27 -03:00
|
|
|
location: Location,
|
2021-03-17 02:51:27 -04:00
|
|
|
) -> (LaterUseKind, Span, Option<Span>) {
|
2018-09-29 11:47:47 +01:00
|
|
|
match use_spans {
|
2021-03-17 02:51:27 -04:00
|
|
|
UseSpans::ClosureUse { capture_kind_span, path_span, .. } => {
|
2018-10-05 17:05:33 +02:00
|
|
|
// Used in a closure.
|
2021-03-17 02:51:27 -04:00
|
|
|
(LaterUseKind::ClosureCapture, capture_kind_span, Some(path_span))
|
2019-02-20 12:15:27 -03:00
|
|
|
}
|
2020-06-11 13:48:46 -04:00
|
|
|
UseSpans::PatUse(span)
|
|
|
|
|
| UseSpans::OtherUse(span)
|
|
|
|
|
| UseSpans::FnSelfUse { var_span: span, .. } => {
|
2022-07-05 00:00:00 +00:00
|
|
|
let block = &self.body.basic_blocks[location.block];
|
2018-10-05 17:05:33 +02:00
|
|
|
|
|
|
|
|
let kind = if let Some(&Statement {
|
2023-01-05 21:29:36 +00:00
|
|
|
kind: StatementKind::FakeRead(box (FakeReadCause::ForLet(_), place)),
|
2018-10-05 17:05:33 +02:00
|
|
|
..
|
2019-02-20 12:15:27 -03:00
|
|
|
}) = block.statements.get(location.statement_index)
|
|
|
|
|
{
|
2023-01-05 21:29:36 +00:00
|
|
|
if let Some(l) = place.as_local()
|
|
|
|
|
&& let local_decl = &self.body.local_decls[l]
|
|
|
|
|
&& local_decl.ty.is_closure()
|
|
|
|
|
{
|
|
|
|
|
LaterUseKind::ClosureCapture
|
|
|
|
|
} else {
|
|
|
|
|
LaterUseKind::FakeLetRead
|
|
|
|
|
}
|
2018-10-05 17:05:33 +02:00
|
|
|
} else if self.was_captured_by_trait_object(borrow) {
|
|
|
|
|
LaterUseKind::TraitCapture
|
|
|
|
|
} else if location.statement_index == block.statements.len() {
|
2023-06-18 05:24:38 +00:00
|
|
|
if let TerminatorKind::Call { func, call_source: CallSource::Normal, .. } =
|
2022-12-02 19:07:57 +00:00
|
|
|
&block.terminator().kind
|
2019-02-20 12:15:27 -03:00
|
|
|
{
|
2018-10-05 17:05:33 +02:00
|
|
|
// Just point to the function, to reduce the chance of overlapping spans.
|
|
|
|
|
let function_span = match func {
|
|
|
|
|
Operand::Constant(c) => c.span,
|
2019-10-20 16:09:36 -04:00
|
|
|
Operand::Copy(place) | Operand::Move(place) => {
|
|
|
|
|
if let Some(l) = place.as_local() {
|
2019-11-06 12:00:46 -05:00
|
|
|
let local_decl = &self.body.local_decls[l];
|
2018-05-16 18:58:54 +03:00
|
|
|
if self.local_names[l].is_none() {
|
2019-10-20 16:09:36 -04:00
|
|
|
local_decl.source_info.span
|
|
|
|
|
} else {
|
|
|
|
|
span
|
|
|
|
|
}
|
2018-10-05 17:05:33 +02:00
|
|
|
} else {
|
|
|
|
|
span
|
|
|
|
|
}
|
2019-02-20 12:15:27 -03:00
|
|
|
}
|
2018-10-05 17:05:33 +02:00
|
|
|
};
|
2021-03-17 02:51:27 -04:00
|
|
|
return (LaterUseKind::Call, function_span, None);
|
2018-10-05 17:05:33 +02:00
|
|
|
} else {
|
|
|
|
|
LaterUseKind::Other
|
2018-09-29 11:47:47 +01:00
|
|
|
}
|
|
|
|
|
} else {
|
2018-10-05 17:05:33 +02:00
|
|
|
LaterUseKind::Other
|
|
|
|
|
};
|
|
|
|
|
|
2021-03-17 02:51:27 -04:00
|
|
|
(kind, span, None)
|
2018-10-05 17:05:33 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-02-08 14:53:55 +01:00
|
|
|
/// Checks if a borrowed value was captured by a trait object. We do this by
|
2018-10-05 23:31:33 +02:00
|
|
|
/// looking forward in the MIR from the reserve location and checking if we see
|
2021-08-22 17:27:18 +02:00
|
|
|
/// an unsized cast to a trait object on our data.
|
2018-10-05 17:05:33 +02:00
|
|
|
fn was_captured_by_trait_object(&self, borrow: &BorrowData<'tcx>) -> bool {
|
2018-10-05 23:31:33 +02:00
|
|
|
// Start at the reserve location, find the place that we want to see cast to a trait object.
|
2018-10-05 17:05:33 +02:00
|
|
|
let location = borrow.reserve_location;
|
2019-11-06 12:00:46 -05:00
|
|
|
let block = &self.body[location.block];
|
2018-10-05 17:05:33 +02:00
|
|
|
let stmt = block.statements.get(location.statement_index);
|
2019-02-20 12:15:27 -03:00
|
|
|
debug!("was_captured_by_trait_object: location={:?} stmt={:?}", location, stmt);
|
2018-10-05 23:31:33 +02:00
|
|
|
|
|
|
|
|
// We make a `queue` vector that has the locations we want to visit. As of writing, this
|
|
|
|
|
// will only ever have one item at any given time, but by using a vector, we can pop from
|
|
|
|
|
// it which simplifies the termination logic.
|
|
|
|
|
let mut queue = vec![location];
|
2022-12-02 19:07:57 +00:00
|
|
|
let mut target =
|
|
|
|
|
if let Some(Statement { kind: StatementKind::Assign(box (place, _)), .. }) = stmt {
|
|
|
|
|
if let Some(local) = place.as_local() {
|
|
|
|
|
local
|
|
|
|
|
} else {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2019-10-20 16:09:36 -04:00
|
|
|
} else {
|
|
|
|
|
return false;
|
2022-12-02 19:07:57 +00:00
|
|
|
};
|
2018-10-05 17:05:33 +02:00
|
|
|
|
2019-02-20 12:15:27 -03:00
|
|
|
debug!("was_captured_by_trait: target={:?} queue={:?}", target, queue);
|
2018-10-05 23:31:33 +02:00
|
|
|
while let Some(current_location) = queue.pop() {
|
|
|
|
|
debug!("was_captured_by_trait: target={:?}", target);
|
2019-11-06 12:00:46 -05:00
|
|
|
let block = &self.body[current_location.block];
|
2018-10-05 23:31:33 +02:00
|
|
|
// We need to check the current location to find out if it is a terminator.
|
|
|
|
|
let is_terminator = current_location.statement_index == block.statements.len();
|
|
|
|
|
if !is_terminator {
|
|
|
|
|
let stmt = &block.statements[current_location.statement_index];
|
|
|
|
|
debug!("was_captured_by_trait_object: stmt={:?}", stmt);
|
|
|
|
|
|
|
|
|
|
// The only kind of statement that we care about is assignments...
|
2019-09-11 16:05:45 -03:00
|
|
|
if let StatementKind::Assign(box (place, rvalue)) = &stmt.kind {
|
2022-02-19 00:48:49 +01:00
|
|
|
let Some(into) = place.local_or_deref_local() else {
|
|
|
|
|
// Continue at the next location.
|
|
|
|
|
queue.push(current_location.successor_within_block());
|
|
|
|
|
continue;
|
2018-10-05 23:31:33 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
match rvalue {
|
|
|
|
|
// If we see a use, we should check whether it is our data, and if so
|
|
|
|
|
// update the place that we're looking for to that new place.
|
|
|
|
|
Rvalue::Use(operand) => match operand {
|
2019-10-20 16:09:36 -04:00
|
|
|
Operand::Copy(place) | Operand::Move(place) => {
|
|
|
|
|
if let Some(from) = place.as_local() {
|
|
|
|
|
if from == target {
|
|
|
|
|
target = into;
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-02-20 12:15:27 -03:00
|
|
|
}
|
|
|
|
|
_ => {}
|
2018-10-05 23:31:33 +02:00
|
|
|
},
|
2021-08-22 17:27:18 +02:00
|
|
|
// If we see an unsized cast, then if it is our data we should check
|
2018-10-05 23:31:33 +02:00
|
|
|
// whether it is being cast to a trait object.
|
2023-07-05 20:07:03 +02:00
|
|
|
Rvalue::Cast(
|
|
|
|
|
CastKind::PointerCoercion(PointerCoercion::Unsize),
|
|
|
|
|
operand,
|
|
|
|
|
ty,
|
|
|
|
|
) => {
|
2019-04-15 19:20:44 +05:30
|
|
|
match operand {
|
2019-10-20 16:09:36 -04:00
|
|
|
Operand::Copy(place) | Operand::Move(place) => {
|
|
|
|
|
if let Some(from) = place.as_local() {
|
|
|
|
|
if from == target {
|
|
|
|
|
debug!("was_captured_by_trait_object: ty={:?}", ty);
|
|
|
|
|
// Check the type for a trait object.
|
2020-08-03 00:49:11 +02:00
|
|
|
return match ty.kind() {
|
2019-10-20 16:09:36 -04:00
|
|
|
// `&dyn Trait`
|
|
|
|
|
ty::Ref(_, ty, _) if ty.is_trait() => true,
|
|
|
|
|
// `Box<dyn Trait>`
|
|
|
|
|
_ if ty.is_box() && ty.boxed_ty().is_trait() => {
|
|
|
|
|
true
|
2019-12-22 17:42:04 -05:00
|
|
|
}
|
2019-10-20 16:09:36 -04:00
|
|
|
// `dyn Trait`
|
|
|
|
|
_ if ty.is_trait() => true,
|
|
|
|
|
// Anything else.
|
|
|
|
|
_ => false,
|
|
|
|
|
};
|
2019-12-22 17:42:04 -05:00
|
|
|
}
|
2019-10-20 16:09:36 -04:00
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
_ => return false,
|
2019-02-20 12:15:27 -03:00
|
|
|
}
|
2018-10-05 23:31:33 +02:00
|
|
|
}
|
2019-02-20 12:15:27 -03:00
|
|
|
_ => {}
|
2018-10-05 17:05:33 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-05 23:31:33 +02:00
|
|
|
// Continue at the next location.
|
|
|
|
|
queue.push(current_location.successor_within_block());
|
|
|
|
|
} else {
|
|
|
|
|
// The only thing we need to do for terminators is progress to the next block.
|
|
|
|
|
let terminator = block.terminator();
|
|
|
|
|
debug!("was_captured_by_trait_object: terminator={:?}", terminator);
|
|
|
|
|
|
2022-04-16 09:27:54 -04:00
|
|
|
if let TerminatorKind::Call { destination, target: Some(block), args, .. } =
|
2019-10-20 16:09:36 -04:00
|
|
|
&terminator.kind
|
|
|
|
|
{
|
2022-04-16 09:27:54 -04:00
|
|
|
if let Some(dest) = destination.as_local() {
|
2019-10-20 16:09:36 -04:00
|
|
|
debug!(
|
|
|
|
|
"was_captured_by_trait_object: target={:?} dest={:?} args={:?}",
|
|
|
|
|
target, dest, args
|
|
|
|
|
);
|
|
|
|
|
// Check if one of the arguments to this function is the target place.
|
|
|
|
|
let found_target = args.iter().any(|arg| {
|
2024-01-12 08:21:42 +01:00
|
|
|
if let Operand::Move(place) = arg.node {
|
2019-10-20 16:09:36 -04:00
|
|
|
if let Some(potential) = place.as_local() {
|
|
|
|
|
potential == target
|
|
|
|
|
} else {
|
|
|
|
|
false
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
false
|
|
|
|
|
}
|
|
|
|
|
});
|
2018-10-17 16:58:12 +02:00
|
|
|
|
2019-10-20 16:09:36 -04:00
|
|
|
// If it is, follow this to the next block and update the target.
|
|
|
|
|
if found_target {
|
|
|
|
|
target = dest;
|
|
|
|
|
queue.push(block.start_location());
|
|
|
|
|
}
|
2018-10-17 16:58:12 +02:00
|
|
|
}
|
2018-10-05 17:05:33 +02:00
|
|
|
}
|
2018-09-29 11:47:47 +01:00
|
|
|
}
|
2018-10-05 23:31:33 +02:00
|
|
|
|
|
|
|
|
debug!("was_captured_by_trait: queue={:?}", queue);
|
2018-09-29 11:47:47 +01:00
|
|
|
}
|
2018-10-05 17:05:33 +02:00
|
|
|
|
2018-10-05 23:31:33 +02:00
|
|
|
// We didn't find anything and ran out of locations to check.
|
2018-10-05 17:05:33 +02:00
|
|
|
false
|
2018-09-29 11:47:47 +01:00
|
|
|
}
|
2017-12-12 17:29:37 -03:00
|
|
|
}
|