Skip to content

Commit 928783d

Browse files
committed
Auto merge of #91799 - matthiaskrgr:rollup-b38xx6i, r=matthiaskrgr
Rollup of 6 pull requests Successful merges: - #83174 (Suggest using a temporary variable to fix borrowck errors) - #89734 (Point at capture points for non-`'static` reference crossing a `yield` point) - #90270 (Make `Borrow` and `BorrowMut` impls `const`) - #90741 (Const `Option::cloned`) - #91548 (Add spin_loop hint for RISC-V architecture) - #91721 (Minor improvements to `future::join!`'s implementation) Failed merges: r? `@ghost` `@rustbot` modify labels: rollup
2 parents b8dc6aa + ed81098 commit 928783d

File tree

56 files changed

+949
-201
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

56 files changed

+949
-201
lines changed

compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs

+1
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,7 @@ fn try_extract_error_from_fulfill_cx<'tcx>(
368368
error_region,
369369
cause.clone(),
370370
placeholder_region,
371+
vec![],
371372
),
372373
),
373374
(Some(error_region), _) => NiceRegionError::new(

compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs

+87-2
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,18 @@ use rustc_span::symbol::sym;
1515
use rustc_span::{BytePos, MultiSpan, Span, DUMMY_SP};
1616
use rustc_trait_selection::infer::InferCtxtExt;
1717

18+
use crate::borrow_set::TwoPhaseActivation;
1819
use crate::borrowck_errors;
1920

21+
use crate::diagnostics::find_all_local_uses;
2022
use crate::{
2123
borrow_set::BorrowData, diagnostics::Instance, prefixes::IsPrefixOf,
2224
InitializationRequiringAction, MirBorrowckCtxt, PrefixSet, WriteKind,
2325
};
2426

2527
use super::{
26-
explain_borrow::BorrowExplanation, FnSelfUseKind, IncludingDowncast, RegionName,
27-
RegionNameSource, UseSpans,
28+
explain_borrow::{BorrowExplanation, LaterUseKind},
29+
FnSelfUseKind, IncludingDowncast, RegionName, RegionNameSource, UseSpans,
2830
};
2931

3032
#[derive(Debug)]
@@ -768,9 +770,92 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
768770
Some((issued_span, span)),
769771
);
770772

773+
self.suggest_using_local_if_applicable(
774+
&mut err,
775+
location,
776+
(place, span),
777+
gen_borrow_kind,
778+
issued_borrow,
779+
explanation,
780+
);
781+
771782
err
772783
}
773784

785+
#[instrument(level = "debug", skip(self, err))]
786+
fn suggest_using_local_if_applicable(
787+
&self,
788+
err: &mut DiagnosticBuilder<'_>,
789+
location: Location,
790+
(place, span): (Place<'tcx>, Span),
791+
gen_borrow_kind: BorrowKind,
792+
issued_borrow: &BorrowData<'tcx>,
793+
explanation: BorrowExplanation,
794+
) {
795+
let used_in_call =
796+
matches!(explanation, BorrowExplanation::UsedLater(LaterUseKind::Call, _call_span, _));
797+
if !used_in_call {
798+
debug!("not later used in call");
799+
return;
800+
}
801+
802+
let outer_call_loc =
803+
if let TwoPhaseActivation::ActivatedAt(loc) = issued_borrow.activation_location {
804+
loc
805+
} else {
806+
issued_borrow.reserve_location
807+
};
808+
let outer_call_stmt = self.body.stmt_at(outer_call_loc);
809+
810+
let inner_param_location = location;
811+
let Some(inner_param_stmt) = self.body.stmt_at(inner_param_location).left() else {
812+
debug!("`inner_param_location` {:?} is not for a statement", inner_param_location);
813+
return;
814+
};
815+
let Some(&inner_param) = inner_param_stmt.kind.as_assign().map(|(p, _)| p) else {
816+
debug!(
817+
"`inner_param_location` {:?} is not for an assignment: {:?}",
818+
inner_param_location, inner_param_stmt
819+
);
820+
return;
821+
};
822+
let inner_param_uses = find_all_local_uses::find(self.body, inner_param.local);
823+
let Some((inner_call_loc,inner_call_term)) = inner_param_uses.into_iter().find_map(|loc| {
824+
let Either::Right(term) = self.body.stmt_at(loc) else {
825+
debug!("{:?} is a statement, so it can't be a call", loc);
826+
return None;
827+
};
828+
let TerminatorKind::Call { args, .. } = &term.kind else {
829+
debug!("not a call: {:?}", term);
830+
return None;
831+
};
832+
debug!("checking call args for uses of inner_param: {:?}", args);
833+
if args.contains(&Operand::Move(inner_param)) {
834+
Some((loc,term))
835+
} else {
836+
None
837+
}
838+
}) else {
839+
debug!("no uses of inner_param found as a by-move call arg");
840+
return;
841+
};
842+
debug!("===> outer_call_loc = {:?}, inner_call_loc = {:?}", outer_call_loc, inner_call_loc);
843+
844+
let inner_call_span = inner_call_term.source_info.span;
845+
let outer_call_span = outer_call_stmt.either(|s| s.source_info, |t| t.source_info).span;
846+
if outer_call_span == inner_call_span || !outer_call_span.contains(inner_call_span) {
847+
// FIXME: This stops the suggestion in some cases where it should be emitted.
848+
// Fix the spans for those cases so it's emitted correctly.
849+
debug!(
850+
"outer span {:?} does not strictly contain inner span {:?}",
851+
outer_call_span, inner_call_span
852+
);
853+
return;
854+
}
855+
err.span_help(inner_call_span, "try adding a local storing this argument...");
856+
err.span_help(outer_call_span, "...and then using that local as the argument to this call");
857+
}
858+
774859
fn suggest_split_at_mut_if_applicable(
775860
&self,
776861
err: &mut DiagnosticBuilder<'_>,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
use std::collections::BTreeSet;
2+
3+
use rustc_middle::mir::visit::{PlaceContext, Visitor};
4+
use rustc_middle::mir::{Body, Local, Location};
5+
6+
/// Find all uses of (including assignments to) a [`Local`].
7+
///
8+
/// Uses `BTreeSet` so output is deterministic.
9+
pub(super) fn find<'tcx>(body: &Body<'tcx>, local: Local) -> BTreeSet<Location> {
10+
let mut visitor = AllLocalUsesVisitor { for_local: local, uses: BTreeSet::default() };
11+
visitor.visit_body(body);
12+
visitor.uses
13+
}
14+
15+
struct AllLocalUsesVisitor {
16+
for_local: Local,
17+
uses: BTreeSet<Location>,
18+
}
19+
20+
impl<'tcx> Visitor<'tcx> for AllLocalUsesVisitor {
21+
fn visit_local(&mut self, local: &Local, _context: PlaceContext, location: Location) {
22+
if *local == self.for_local {
23+
self.uses.insert(location);
24+
}
25+
}
26+
}

compiler/rustc_borrowck/src/diagnostics/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ use rustc_target::abi::VariantIdx;
1919
use super::borrow_set::BorrowData;
2020
use super::MirBorrowckCtxt;
2121

22+
mod find_all_local_uses;
2223
mod find_use;
2324
mod outlives_suggestion;
2425
mod region_name;

compiler/rustc_infer/src/infer/error_reporting/mod.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
384384
sub_r,
385385
sup_origin,
386386
sup_r,
387+
_,
387388
) => {
388389
if sub_r.is_placeholder() {
389390
self.report_placeholder_failure(sub_origin, sub_r, sup_r).emit();
@@ -464,7 +465,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
464465
errors.sort_by_key(|u| match *u {
465466
RegionResolutionError::ConcreteFailure(ref sro, _, _) => sro.span(),
466467
RegionResolutionError::GenericBoundFailure(ref sro, _, _) => sro.span(),
467-
RegionResolutionError::SubSupConflict(_, ref rvo, _, _, _, _) => rvo.span(),
468+
RegionResolutionError::SubSupConflict(_, ref rvo, _, _, _, _, _) => rvo.span(),
468469
RegionResolutionError::UpperBoundUniverseConflict(_, ref rvo, _, _, _) => rvo.span(),
469470
});
470471
errors

compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ impl<'cx, 'tcx> NiceRegionError<'cx, 'tcx> {
6767
pub fn regions(&self) -> Option<(Span, ty::Region<'tcx>, ty::Region<'tcx>)> {
6868
match (&self.error, self.regions) {
6969
(Some(ConcreteFailure(origin, sub, sup)), None) => Some((origin.span(), sub, sup)),
70-
(Some(SubSupConflict(_, _, origin, sub, _, sup)), None) => {
70+
(Some(SubSupConflict(_, _, origin, sub, _, sup, _)), None) => {
7171
Some((origin.span(), sub, sup))
7272
}
7373
(None, Some((span, sub, sup))) => Some((span, sub, sup)),

compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs

+4
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ impl NiceRegionError<'me, 'tcx> {
3434
sub_placeholder @ ty::RePlaceholder(_),
3535
_,
3636
sup_placeholder @ ty::RePlaceholder(_),
37+
_,
3738
)) => self.try_report_trait_placeholder_mismatch(
3839
Some(self.tcx().mk_region(ty::ReVar(*vid))),
3940
cause,
@@ -49,6 +50,7 @@ impl NiceRegionError<'me, 'tcx> {
4950
sub_placeholder @ ty::RePlaceholder(_),
5051
_,
5152
_,
53+
_,
5254
)) => self.try_report_trait_placeholder_mismatch(
5355
Some(self.tcx().mk_region(ty::ReVar(*vid))),
5456
cause,
@@ -64,6 +66,7 @@ impl NiceRegionError<'me, 'tcx> {
6466
_,
6567
_,
6668
sup_placeholder @ ty::RePlaceholder(_),
69+
_,
6770
)) => self.try_report_trait_placeholder_mismatch(
6871
Some(self.tcx().mk_region(ty::ReVar(*vid))),
6972
cause,
@@ -79,6 +82,7 @@ impl NiceRegionError<'me, 'tcx> {
7982
_,
8083
SubregionOrigin::Subtype(box TypeTrace { cause, values }),
8184
sup_placeholder @ ty::RePlaceholder(_),
85+
_,
8286
)) => self.try_report_trait_placeholder_mismatch(
8387
Some(self.tcx().mk_region(ty::ReVar(*vid))),
8488
cause,

compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs

+93-46
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ use rustc_hir::def_id::DefId;
1010
use rustc_hir::intravisit::{walk_ty, ErasedMap, NestedVisitorMap, Visitor};
1111
use rustc_hir::{self as hir, GenericBound, Item, ItemKind, Lifetime, LifetimeName, Node, TyKind};
1212
use rustc_middle::ty::{
13-
self, AssocItemContainer, RegionKind, Ty, TyCtxt, TypeFoldable, TypeVisitor,
13+
self, AssocItemContainer, RegionKind, StaticLifetimeVisitor, Ty, TyCtxt, TypeFoldable,
14+
TypeVisitor,
1415
};
1516
use rustc_span::symbol::Ident;
1617
use rustc_span::{MultiSpan, Span};
@@ -23,16 +24,17 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
2324
pub(super) fn try_report_static_impl_trait(&self) -> Option<ErrorReported> {
2425
debug!("try_report_static_impl_trait(error={:?})", self.error);
2526
let tcx = self.tcx();
26-
let (var_origin, sub_origin, sub_r, sup_origin, sup_r) = match self.error.as_ref()? {
27+
let (var_origin, sub_origin, sub_r, sup_origin, sup_r, spans) = match self.error.as_ref()? {
2728
RegionResolutionError::SubSupConflict(
2829
_,
2930
var_origin,
3031
sub_origin,
3132
sub_r,
3233
sup_origin,
3334
sup_r,
35+
spans,
3436
) if **sub_r == RegionKind::ReStatic => {
35-
(var_origin, sub_origin, sub_r, sup_origin, sup_r)
37+
(var_origin, sub_origin, sub_r, sup_origin, sup_r, spans)
3638
}
3739
RegionResolutionError::ConcreteFailure(
3840
SubregionOrigin::Subtype(box TypeTrace { cause, .. }),
@@ -74,7 +76,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
7476
err.span_label(
7577
cause.span,
7678
&format!(
77-
"...is captured and required to live as long as `'static` here \
79+
"...is used and required to live as long as `'static` here \
7880
because of an implicit lifetime bound on the {}",
7981
match ctxt.assoc_item.container {
8082
AssocItemContainer::TraitContainer(id) =>
@@ -123,56 +125,101 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
123125
param_name,
124126
lifetime,
125127
);
126-
err.span_label(param.param_ty_span, &format!("this data with {}...", lifetime));
127-
debug!("try_report_static_impl_trait: param_info={:?}", param);
128128

129-
// We try to make the output have fewer overlapping spans if possible.
130-
if (sp == sup_origin.span() || !return_sp.overlaps(sup_origin.span()))
131-
&& sup_origin.span() != return_sp
132-
{
133-
// FIXME: account for `async fn` like in `async-await/issues/issue-62097.rs`
134-
135-
// Customize the spans and labels depending on their relative order so
136-
// that split sentences flow correctly.
137-
if sup_origin.span().overlaps(return_sp) && sp == sup_origin.span() {
138-
// Avoid the following:
139-
//
140-
// error: cannot infer an appropriate lifetime
141-
// --> $DIR/must_outlive_least_region_or_bound.rs:18:50
142-
// |
143-
// LL | fn foo(x: &i32) -> Box<dyn Debug> { Box::new(x) }
144-
// | ---- ---------^-
129+
let (mention_influencer, influencer_point) =
130+
if sup_origin.span().overlaps(param.param_ty_span) {
131+
// Account for `async fn` like in `async-await/issues/issue-62097.rs`.
132+
// The desugaring of `async `fn`s causes `sup_origin` and `param` to point at the same
133+
// place (but with different `ctxt`, hence `overlaps` instead of `==` above).
145134
//
146-
// and instead show:
135+
// This avoids the following:
147136
//
148-
// error: cannot infer an appropriate lifetime
149-
// --> $DIR/must_outlive_least_region_or_bound.rs:18:50
150-
// |
151-
// LL | fn foo(x: &i32) -> Box<dyn Debug> { Box::new(x) }
152-
// | ---- ^
153-
err.span_label(
154-
sup_origin.span(),
155-
"...is captured here, requiring it to live as long as `'static`",
156-
);
137+
// LL | pub async fn run_dummy_fn(&self) {
138+
// | ^^^^^
139+
// | |
140+
// | this data with an anonymous lifetime `'_`...
141+
// | ...is captured here...
142+
(false, sup_origin.span())
157143
} else {
158-
err.span_label(sup_origin.span(), "...is captured here...");
159-
if return_sp < sup_origin.span() {
160-
err.span_note(
161-
return_sp,
162-
"...and is required to live as long as `'static` here",
144+
(!sup_origin.span().overlaps(return_sp), param.param_ty_span)
145+
};
146+
err.span_label(influencer_point, &format!("this data with {}...", lifetime));
147+
148+
debug!("try_report_static_impl_trait: param_info={:?}", param);
149+
150+
let mut spans = spans.clone();
151+
152+
if mention_influencer {
153+
spans.push(sup_origin.span());
154+
}
155+
// We dedup the spans *ignoring* expansion context.
156+
spans.sort();
157+
spans.dedup_by_key(|span| (span.lo(), span.hi()));
158+
159+
// We try to make the output have fewer overlapping spans if possible.
160+
let require_msg = if spans.is_empty() {
161+
"...is used and required to live as long as `'static` here"
162+
} else {
163+
"...and is required to live as long as `'static` here"
164+
};
165+
let require_span =
166+
if sup_origin.span().overlaps(return_sp) { sup_origin.span() } else { return_sp };
167+
168+
for span in &spans {
169+
err.span_label(*span, "...is used here...");
170+
}
171+
172+
if spans.iter().any(|sp| sp.overlaps(return_sp) || *sp > return_sp) {
173+
// If any of the "captured here" labels appears on the same line or after
174+
// `require_span`, we put it on a note to ensure the text flows by appearing
175+
// always at the end.
176+
err.span_note(require_span, require_msg);
177+
} else {
178+
// We don't need a note, it's already at the end, it can be shown as a `span_label`.
179+
err.span_label(require_span, require_msg);
180+
}
181+
182+
if let SubregionOrigin::RelateParamBound(_, _, Some(bound)) = sub_origin {
183+
err.span_note(*bound, "`'static` lifetime requirement introduced by this bound");
184+
}
185+
if let SubregionOrigin::Subtype(box TypeTrace { cause, .. }) = sub_origin {
186+
if let ObligationCauseCode::ReturnValue(hir_id)
187+
| ObligationCauseCode::BlockTailExpression(hir_id) = &cause.code
188+
{
189+
let parent_id = tcx.hir().get_parent_item(*hir_id);
190+
if let Some(fn_decl) = tcx.hir().fn_decl_by_hir_id(parent_id) {
191+
let mut span: MultiSpan = fn_decl.output.span().into();
192+
let mut add_label = true;
193+
if let hir::FnRetTy::Return(ty) = fn_decl.output {
194+
let mut v = StaticLifetimeVisitor(vec![], tcx.hir());
195+
v.visit_ty(ty);
196+
if !v.0.is_empty() {
197+
span = v.0.clone().into();
198+
for sp in v.0 {
199+
span.push_span_label(
200+
sp,
201+
"`'static` requirement introduced here".to_string(),
202+
);
203+
}
204+
add_label = false;
205+
}
206+
}
207+
if add_label {
208+
span.push_span_label(
209+
fn_decl.output.span(),
210+
"requirement introduced by this return type".to_string(),
211+
);
212+
}
213+
span.push_span_label(
214+
cause.span,
215+
"because of this returned expression".to_string(),
163216
);
164-
} else {
165-
err.span_label(
166-
return_sp,
167-
"...and is required to live as long as `'static` here",
217+
err.span_note(
218+
span,
219+
"`'static` lifetime requirement introduced by the return type",
168220
);
169221
}
170222
}
171-
} else {
172-
err.span_label(
173-
return_sp,
174-
"...is captured and required to live as long as `'static` here",
175-
);
176223
}
177224

178225
let fn_returns = tcx.return_type_impl_or_dyn_traits(anon_reg_sup.def_id);

0 commit comments

Comments
 (0)