diff --git a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs index 1bc9f8cf3ccc8..881ebed602946 100644 --- a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs @@ -368,6 +368,7 @@ fn try_extract_error_from_fulfill_cx<'tcx>( error_region, cause.clone(), placeholder_region, + vec![], ), ), (Some(error_region), _) => NiceRegionError::new( diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 8c4508ed18882..98c619cdd291c 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -15,16 +15,18 @@ use rustc_span::symbol::sym; use rustc_span::{BytePos, MultiSpan, Span, DUMMY_SP}; use rustc_trait_selection::infer::InferCtxtExt; +use crate::borrow_set::TwoPhaseActivation; use crate::borrowck_errors; +use crate::diagnostics::find_all_local_uses; use crate::{ borrow_set::BorrowData, diagnostics::Instance, prefixes::IsPrefixOf, InitializationRequiringAction, MirBorrowckCtxt, PrefixSet, WriteKind, }; use super::{ - explain_borrow::BorrowExplanation, FnSelfUseKind, IncludingDowncast, RegionName, - RegionNameSource, UseSpans, + explain_borrow::{BorrowExplanation, LaterUseKind}, + FnSelfUseKind, IncludingDowncast, RegionName, RegionNameSource, UseSpans, }; #[derive(Debug)] @@ -768,9 +770,92 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { Some((issued_span, span)), ); + self.suggest_using_local_if_applicable( + &mut err, + location, + (place, span), + gen_borrow_kind, + issued_borrow, + explanation, + ); + err } + #[instrument(level = "debug", skip(self, err))] + fn suggest_using_local_if_applicable( + &self, + err: &mut DiagnosticBuilder<'_>, + location: Location, + (place, span): (Place<'tcx>, Span), + gen_borrow_kind: BorrowKind, + issued_borrow: &BorrowData<'tcx>, + explanation: BorrowExplanation, + ) { + let used_in_call = + matches!(explanation, BorrowExplanation::UsedLater(LaterUseKind::Call, _call_span, _)); + if !used_in_call { + debug!("not later used in call"); + return; + } + + let outer_call_loc = + if let TwoPhaseActivation::ActivatedAt(loc) = issued_borrow.activation_location { + loc + } else { + issued_borrow.reserve_location + }; + let outer_call_stmt = self.body.stmt_at(outer_call_loc); + + let inner_param_location = location; + let Some(inner_param_stmt) = self.body.stmt_at(inner_param_location).left() else { + debug!("`inner_param_location` {:?} is not for a statement", inner_param_location); + return; + }; + let Some(&inner_param) = inner_param_stmt.kind.as_assign().map(|(p, _)| p) else { + debug!( + "`inner_param_location` {:?} is not for an assignment: {:?}", + inner_param_location, inner_param_stmt + ); + return; + }; + let inner_param_uses = find_all_local_uses::find(self.body, inner_param.local); + let Some((inner_call_loc,inner_call_term)) = inner_param_uses.into_iter().find_map(|loc| { + let Either::Right(term) = self.body.stmt_at(loc) else { + debug!("{:?} is a statement, so it can't be a call", loc); + return None; + }; + let TerminatorKind::Call { args, .. } = &term.kind else { + debug!("not a call: {:?}", term); + return None; + }; + debug!("checking call args for uses of inner_param: {:?}", args); + if args.contains(&Operand::Move(inner_param)) { + Some((loc,term)) + } else { + None + } + }) else { + debug!("no uses of inner_param found as a by-move call arg"); + return; + }; + debug!("===> outer_call_loc = {:?}, inner_call_loc = {:?}", outer_call_loc, inner_call_loc); + + let inner_call_span = inner_call_term.source_info.span; + let outer_call_span = outer_call_stmt.either(|s| s.source_info, |t| t.source_info).span; + if outer_call_span == inner_call_span || !outer_call_span.contains(inner_call_span) { + // FIXME: This stops the suggestion in some cases where it should be emitted. + // Fix the spans for those cases so it's emitted correctly. + debug!( + "outer span {:?} does not strictly contain inner span {:?}", + outer_call_span, inner_call_span + ); + return; + } + err.span_help(inner_call_span, "try adding a local storing this argument..."); + err.span_help(outer_call_span, "...and then using that local as the argument to this call"); + } + fn suggest_split_at_mut_if_applicable( &self, err: &mut DiagnosticBuilder<'_>, diff --git a/compiler/rustc_borrowck/src/diagnostics/find_all_local_uses.rs b/compiler/rustc_borrowck/src/diagnostics/find_all_local_uses.rs new file mode 100644 index 0000000000000..49d9caae71144 --- /dev/null +++ b/compiler/rustc_borrowck/src/diagnostics/find_all_local_uses.rs @@ -0,0 +1,26 @@ +use std::collections::BTreeSet; + +use rustc_middle::mir::visit::{PlaceContext, Visitor}; +use rustc_middle::mir::{Body, Local, Location}; + +/// Find all uses of (including assignments to) a [`Local`]. +/// +/// Uses `BTreeSet` so output is deterministic. +pub(super) fn find<'tcx>(body: &Body<'tcx>, local: Local) -> BTreeSet { + let mut visitor = AllLocalUsesVisitor { for_local: local, uses: BTreeSet::default() }; + visitor.visit_body(body); + visitor.uses +} + +struct AllLocalUsesVisitor { + for_local: Local, + uses: BTreeSet, +} + +impl<'tcx> Visitor<'tcx> for AllLocalUsesVisitor { + fn visit_local(&mut self, local: &Local, _context: PlaceContext, location: Location) { + if *local == self.for_local { + self.uses.insert(location); + } + } +} diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index 42f5d55754208..dec1940ace881 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -19,6 +19,7 @@ use rustc_target::abi::VariantIdx; use super::borrow_set::BorrowData; use super::MirBorrowckCtxt; +mod find_all_local_uses; mod find_use; mod outlives_suggestion; mod region_name; diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index 025d2998b0052..18dde3bc34ef1 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -322,6 +322,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { sym::copy => { self.copy_intrinsic(&args[0], &args[1], &args[2], /*nonoverlapping*/ false)?; } + sym::write_bytes => { + self.write_bytes_intrinsic(&args[0], &args[1], &args[2])?; + } sym::offset => { let ptr = self.read_pointer(&args[0])?; let offset_count = self.read_scalar(&args[1])?.to_machine_isize(self)?; @@ -567,6 +570,27 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.memory.copy(src, align, dst, align, size, nonoverlapping) } + pub(crate) fn write_bytes_intrinsic( + &mut self, + dst: &OpTy<'tcx, >::PointerTag>, + byte: &OpTy<'tcx, >::PointerTag>, + count: &OpTy<'tcx, >::PointerTag>, + ) -> InterpResult<'tcx> { + let layout = self.layout_of(dst.layout.ty.builtin_deref(true).unwrap().ty)?; + + let dst = self.read_pointer(&dst)?; + let byte = self.read_scalar(&byte)?.to_u8()?; + let count = self.read_scalar(&count)?.to_machine_usize(self)?; + + let len = layout + .size + .checked_mul(count, self) + .ok_or_else(|| err_ub_format!("overflow computing total size of `write_bytes`"))?; + + let bytes = std::iter::repeat(byte).take(len.bytes_usize()); + self.memory.write_bytes(dst, bytes) + } + pub(crate) fn raw_eq_intrinsic( &mut self, lhs: &OpTy<'tcx, >::PointerTag>, diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 85226e60bdbdb..c3f2213229a01 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -384,6 +384,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { sub_r, sup_origin, sup_r, + _, ) => { if sub_r.is_placeholder() { self.report_placeholder_failure(sub_origin, sub_r, sup_r).emit(); @@ -464,7 +465,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { errors.sort_by_key(|u| match *u { RegionResolutionError::ConcreteFailure(ref sro, _, _) => sro.span(), RegionResolutionError::GenericBoundFailure(ref sro, _, _) => sro.span(), - RegionResolutionError::SubSupConflict(_, ref rvo, _, _, _, _) => rvo.span(), + RegionResolutionError::SubSupConflict(_, ref rvo, _, _, _, _, _) => rvo.span(), RegionResolutionError::UpperBoundUniverseConflict(_, ref rvo, _, _, _) => rvo.span(), }); errors diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs index 6a3309770028f..fd295b743420c 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs @@ -67,7 +67,7 @@ impl<'cx, 'tcx> NiceRegionError<'cx, 'tcx> { pub fn regions(&self) -> Option<(Span, ty::Region<'tcx>, ty::Region<'tcx>)> { match (&self.error, self.regions) { (Some(ConcreteFailure(origin, sub, sup)), None) => Some((origin.span(), sub, sup)), - (Some(SubSupConflict(_, _, origin, sub, _, sup)), None) => { + (Some(SubSupConflict(_, _, origin, sub, _, sup, _)), None) => { Some((origin.span(), sub, sup)) } (None, Some((span, sub, sup))) => Some((span, sub, sup)), diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs index 4aecc2f40b874..1a4a280382189 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs @@ -34,6 +34,7 @@ impl NiceRegionError<'me, 'tcx> { sub_placeholder @ ty::RePlaceholder(_), _, sup_placeholder @ ty::RePlaceholder(_), + _, )) => self.try_report_trait_placeholder_mismatch( Some(self.tcx().mk_region(ty::ReVar(*vid))), cause, @@ -49,6 +50,7 @@ impl NiceRegionError<'me, 'tcx> { sub_placeholder @ ty::RePlaceholder(_), _, _, + _, )) => self.try_report_trait_placeholder_mismatch( Some(self.tcx().mk_region(ty::ReVar(*vid))), cause, @@ -64,6 +66,7 @@ impl NiceRegionError<'me, 'tcx> { _, _, sup_placeholder @ ty::RePlaceholder(_), + _, )) => self.try_report_trait_placeholder_mismatch( Some(self.tcx().mk_region(ty::ReVar(*vid))), cause, @@ -79,6 +82,7 @@ impl NiceRegionError<'me, 'tcx> { _, SubregionOrigin::Subtype(box TypeTrace { cause, values }), sup_placeholder @ ty::RePlaceholder(_), + _, )) => self.try_report_trait_placeholder_mismatch( Some(self.tcx().mk_region(ty::ReVar(*vid))), cause, diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs index 2aaebed28ced7..80d4a2e57da4a 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -10,7 +10,8 @@ use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{walk_ty, ErasedMap, NestedVisitorMap, Visitor}; use rustc_hir::{self as hir, GenericBound, Item, ItemKind, Lifetime, LifetimeName, Node, TyKind}; use rustc_middle::ty::{ - self, AssocItemContainer, RegionKind, Ty, TyCtxt, TypeFoldable, TypeVisitor, + self, AssocItemContainer, RegionKind, StaticLifetimeVisitor, Ty, TyCtxt, TypeFoldable, + TypeVisitor, }; use rustc_span::symbol::Ident; use rustc_span::{MultiSpan, Span}; @@ -23,7 +24,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { pub(super) fn try_report_static_impl_trait(&self) -> Option { debug!("try_report_static_impl_trait(error={:?})", self.error); let tcx = self.tcx(); - let (var_origin, sub_origin, sub_r, sup_origin, sup_r) = match self.error.as_ref()? { + let (var_origin, sub_origin, sub_r, sup_origin, sup_r, spans) = match self.error.as_ref()? { RegionResolutionError::SubSupConflict( _, var_origin, @@ -31,8 +32,9 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { sub_r, sup_origin, sup_r, + spans, ) if **sub_r == RegionKind::ReStatic => { - (var_origin, sub_origin, sub_r, sup_origin, sup_r) + (var_origin, sub_origin, sub_r, sup_origin, sup_r, spans) } RegionResolutionError::ConcreteFailure( SubregionOrigin::Subtype(box TypeTrace { cause, .. }), @@ -74,7 +76,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { err.span_label( cause.span, &format!( - "...is captured and required to live as long as `'static` here \ + "...is used and required to live as long as `'static` here \ because of an implicit lifetime bound on the {}", match ctxt.assoc_item.container { AssocItemContainer::TraitContainer(id) => @@ -123,56 +125,101 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { param_name, lifetime, ); - err.span_label(param.param_ty_span, &format!("this data with {}...", lifetime)); - debug!("try_report_static_impl_trait: param_info={:?}", param); - // We try to make the output have fewer overlapping spans if possible. - if (sp == sup_origin.span() || !return_sp.overlaps(sup_origin.span())) - && sup_origin.span() != return_sp - { - // FIXME: account for `async fn` like in `async-await/issues/issue-62097.rs` - - // Customize the spans and labels depending on their relative order so - // that split sentences flow correctly. - if sup_origin.span().overlaps(return_sp) && sp == sup_origin.span() { - // Avoid the following: - // - // error: cannot infer an appropriate lifetime - // --> $DIR/must_outlive_least_region_or_bound.rs:18:50 - // | - // LL | fn foo(x: &i32) -> Box { Box::new(x) } - // | ---- ---------^- + let (mention_influencer, influencer_point) = + if sup_origin.span().overlaps(param.param_ty_span) { + // Account for `async fn` like in `async-await/issues/issue-62097.rs`. + // The desugaring of `async `fn`s causes `sup_origin` and `param` to point at the same + // place (but with different `ctxt`, hence `overlaps` instead of `==` above). // - // and instead show: + // This avoids the following: // - // error: cannot infer an appropriate lifetime - // --> $DIR/must_outlive_least_region_or_bound.rs:18:50 - // | - // LL | fn foo(x: &i32) -> Box { Box::new(x) } - // | ---- ^ - err.span_label( - sup_origin.span(), - "...is captured here, requiring it to live as long as `'static`", - ); + // LL | pub async fn run_dummy_fn(&self) { + // | ^^^^^ + // | | + // | this data with an anonymous lifetime `'_`... + // | ...is captured here... + (false, sup_origin.span()) } else { - err.span_label(sup_origin.span(), "...is captured here..."); - if return_sp < sup_origin.span() { - err.span_note( - return_sp, - "...and is required to live as long as `'static` here", + (!sup_origin.span().overlaps(return_sp), param.param_ty_span) + }; + err.span_label(influencer_point, &format!("this data with {}...", lifetime)); + + debug!("try_report_static_impl_trait: param_info={:?}", param); + + let mut spans = spans.clone(); + + if mention_influencer { + spans.push(sup_origin.span()); + } + // We dedup the spans *ignoring* expansion context. + spans.sort(); + spans.dedup_by_key(|span| (span.lo(), span.hi())); + + // We try to make the output have fewer overlapping spans if possible. + let require_msg = if spans.is_empty() { + "...is used and required to live as long as `'static` here" + } else { + "...and is required to live as long as `'static` here" + }; + let require_span = + if sup_origin.span().overlaps(return_sp) { sup_origin.span() } else { return_sp }; + + for span in &spans { + err.span_label(*span, "...is used here..."); + } + + if spans.iter().any(|sp| sp.overlaps(return_sp) || *sp > return_sp) { + // If any of the "captured here" labels appears on the same line or after + // `require_span`, we put it on a note to ensure the text flows by appearing + // always at the end. + err.span_note(require_span, require_msg); + } else { + // We don't need a note, it's already at the end, it can be shown as a `span_label`. + err.span_label(require_span, require_msg); + } + + if let SubregionOrigin::RelateParamBound(_, _, Some(bound)) = sub_origin { + err.span_note(*bound, "`'static` lifetime requirement introduced by this bound"); + } + if let SubregionOrigin::Subtype(box TypeTrace { cause, .. }) = sub_origin { + if let ObligationCauseCode::ReturnValue(hir_id) + | ObligationCauseCode::BlockTailExpression(hir_id) = &cause.code + { + let parent_id = tcx.hir().get_parent_item(*hir_id); + if let Some(fn_decl) = tcx.hir().fn_decl_by_hir_id(parent_id) { + let mut span: MultiSpan = fn_decl.output.span().into(); + let mut add_label = true; + if let hir::FnRetTy::Return(ty) = fn_decl.output { + let mut v = StaticLifetimeVisitor(vec![], tcx.hir()); + v.visit_ty(ty); + if !v.0.is_empty() { + span = v.0.clone().into(); + for sp in v.0 { + span.push_span_label( + sp, + "`'static` requirement introduced here".to_string(), + ); + } + add_label = false; + } + } + if add_label { + span.push_span_label( + fn_decl.output.span(), + "requirement introduced by this return type".to_string(), + ); + } + span.push_span_label( + cause.span, + "because of this returned expression".to_string(), ); - } else { - err.span_label( - return_sp, - "...and is required to live as long as `'static` here", + err.span_note( + span, + "`'static` lifetime requirement introduced by the return type", ); } } - } else { - err.span_label( - return_sp, - "...is captured and required to live as long as `'static` here", - ); } let fn_returns = tcx.return_type_impl_or_dyn_traits(anon_reg_sup.def_id); diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs index cfa79213c805c..452ca5eeabd49 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs @@ -28,6 +28,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { _sub, sup_origin, _sup, + _, ) = error.clone() { if let (&Subtype(ref sup_trace), &Subtype(ref sub_trace)) = (&sup_origin, &sub_origin) { diff --git a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs index 4c9dcab26b14f..85ee6d2cdc282 100644 --- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs +++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs @@ -19,6 +19,7 @@ use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{ReEarlyBound, ReEmpty, ReErased, ReFree, ReStatic}; use rustc_middle::ty::{ReLateBound, RePlaceholder, ReVar}; use rustc_middle::ty::{Region, RegionVid}; +use rustc_span::Span; use std::fmt; /// This function performs lexical region resolution given a complete @@ -96,6 +97,7 @@ pub enum RegionResolutionError<'tcx> { Region<'tcx>, SubregionOrigin<'tcx>, Region<'tcx>, + Vec, // All the influences on a given value that didn't meet its constraints. ), /// Indicates a `'b: 'a` constraint where `'a` is in a universe that @@ -567,7 +569,30 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { // if this rule starts to create problems we'll // have to revisit this portion of the code and // think hard about it. =) -- nikomatsakis - self.collect_error_for_expanding_node(graph, &mut dup_vec, node_vid, errors); + + // Obtain the spans for all the places that can + // influence the constraints on this value for + // richer diagnostics in `static_impl_trait`. + let influences: Vec = self + .data + .constraints + .iter() + .filter_map(|(constraint, origin)| match (constraint, origin) { + ( + Constraint::VarSubVar(_, sup), + SubregionOrigin::DataBorrowed(_, sp), + ) if sup == &node_vid => Some(*sp), + _ => None, + }) + .collect(); + + self.collect_error_for_expanding_node( + graph, + &mut dup_vec, + node_vid, + errors, + influences, + ); } } } @@ -621,6 +646,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { dup_vec: &mut IndexVec>, node_idx: RegionVid, errors: &mut Vec>, + influences: Vec, ) { // Errors in expanding nodes result from a lower-bound that is // not contained by an upper-bound. @@ -667,6 +693,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { sup: {:?}", origin, node_idx, lower_bound.region, upper_bound.region ); + errors.push(RegionResolutionError::SubSupConflict( node_idx, origin, @@ -674,6 +701,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> { lower_bound.region, upper_bound.origin.clone(), upper_bound.region, + influences, )); return; } diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index d4530883b6a10..afd8083dfe46a 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -12,6 +12,7 @@ use crate::ty::print::{FmtPrinter, Printer}; use crate::ty::subst::{Subst, SubstsRef}; use crate::ty::{self, List, Ty, TyCtxt}; use crate::ty::{AdtDef, InstanceDef, Region, ScalarInt, UserTypeAnnotationIndex}; + use rustc_hir::def::{CtorKind, Namespace}; use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc_hir::{self, GeneratorKind}; @@ -30,6 +31,9 @@ use rustc_serialize::{Decodable, Encodable}; use rustc_span::symbol::Symbol; use rustc_span::{Span, DUMMY_SP}; use rustc_target::asm::InlineAsmRegOrRegClass; + +use either::Either; + use std::borrow::Cow; use std::convert::TryInto; use std::fmt::{self, Debug, Display, Formatter, Write}; @@ -503,6 +507,16 @@ impl<'tcx> Body<'tcx> { Location { block: bb, statement_index: self[bb].statements.len() } } + pub fn stmt_at(&self, location: Location) -> Either<&Statement<'tcx>, &Terminator<'tcx>> { + let Location { block, statement_index } = location; + let block_data = &self.basic_blocks[block]; + block_data + .statements + .get(statement_index) + .map(Either::Left) + .unwrap_or_else(|| Either::Right(block_data.terminator())) + } + #[inline] pub fn predecessors(&self) -> &Predecessors { self.predecessor_cache.compute(&self.basic_blocks) diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 275a2128c4556..0bf457ca8a824 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1481,40 +1481,8 @@ impl<'tcx> TyCtxt<'tcx> { scope_def_id: LocalDefId, ) -> Vec<&'tcx hir::Ty<'tcx>> { let hir_id = self.hir().local_def_id_to_hir_id(scope_def_id); - let hir_output = match self.hir().get(hir_id) { - Node::Item(hir::Item { - kind: - ItemKind::Fn( - hir::FnSig { - decl: hir::FnDecl { output: hir::FnRetTy::Return(ty), .. }, - .. - }, - .., - ), - .. - }) - | Node::ImplItem(hir::ImplItem { - kind: - hir::ImplItemKind::Fn( - hir::FnSig { - decl: hir::FnDecl { output: hir::FnRetTy::Return(ty), .. }, - .. - }, - _, - ), - .. - }) - | Node::TraitItem(hir::TraitItem { - kind: - hir::TraitItemKind::Fn( - hir::FnSig { - decl: hir::FnDecl { output: hir::FnRetTy::Return(ty), .. }, - .. - }, - _, - ), - .. - }) => ty, + let hir_output = match self.hir().fn_decl_by_hir_id(hir_id) { + Some(hir::FnDecl { output: hir::FnRetTy::Return(ty), .. }) => ty, _ => return vec![], }; diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index 8803370251b38..1acb3ec57dea6 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -6,6 +6,7 @@ use rustc_errors::{Applicability, DiagnosticBuilder}; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::{QPath, TyKind, WhereBoundPredicate, WherePredicate}; +use rustc_span::Span; impl<'tcx> TyS<'tcx> { /// Similar to `TyS::is_primitive`, but also considers inferred numeric values to be primitive. @@ -432,3 +433,22 @@ impl<'v> hir::intravisit::Visitor<'v> for TraitObjectVisitor<'v> { hir::intravisit::walk_ty(self, ty); } } + +/// Collect al types that have an implicit `'static` obligation that we could suggest `'_` for. +pub struct StaticLifetimeVisitor<'tcx>(pub Vec, pub crate::hir::map::Map<'tcx>); + +impl<'v> hir::intravisit::Visitor<'v> for StaticLifetimeVisitor<'v> { + type Map = rustc_hir::intravisit::ErasedMap<'v>; + + fn nested_visit_map(&mut self) -> hir::intravisit::NestedVisitorMap { + hir::intravisit::NestedVisitorMap::None + } + + fn visit_lifetime(&mut self, lt: &'v hir::Lifetime) { + if let hir::LifetimeName::ImplicitObjectLifetimeDefault | hir::LifetimeName::Static = + lt.name + { + self.0.push(lt.span); + } + } +} diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs index 5e295ffbff740..0e33e95271e50 100644 --- a/library/core/src/array/mod.rs +++ b/library/core/src/array/mod.rs @@ -162,14 +162,16 @@ impl AsMut<[T]> for [T; N] { } #[stable(feature = "array_borrow", since = "1.4.0")] -impl Borrow<[T]> for [T; N] { +#[rustc_const_unstable(feature = "const_borrow", issue = "91522")] +impl const Borrow<[T]> for [T; N] { fn borrow(&self) -> &[T] { self } } #[stable(feature = "array_borrow", since = "1.4.0")] -impl BorrowMut<[T]> for [T; N] { +#[rustc_const_unstable(feature = "const_borrow", issue = "91522")] +impl const BorrowMut<[T]> for [T; N] { fn borrow_mut(&mut self) -> &mut [T] { self } diff --git a/library/core/src/borrow.rs b/library/core/src/borrow.rs index f28be20aaa1e6..58eabecf3f091 100644 --- a/library/core/src/borrow.rs +++ b/library/core/src/borrow.rs @@ -205,7 +205,8 @@ pub trait BorrowMut: Borrow { } #[stable(feature = "rust1", since = "1.0.0")] -impl Borrow for T { +#[rustc_const_unstable(feature = "const_borrow", issue = "91522")] +impl const Borrow for T { #[rustc_diagnostic_item = "noop_method_borrow"] fn borrow(&self) -> &T { self @@ -213,28 +214,32 @@ impl Borrow for T { } #[stable(feature = "rust1", since = "1.0.0")] -impl BorrowMut for T { +#[rustc_const_unstable(feature = "const_borrow", issue = "91522")] +impl const BorrowMut for T { fn borrow_mut(&mut self) -> &mut T { self } } #[stable(feature = "rust1", since = "1.0.0")] -impl Borrow for &T { +#[rustc_const_unstable(feature = "const_borrow", issue = "91522")] +impl const Borrow for &T { fn borrow(&self) -> &T { &**self } } #[stable(feature = "rust1", since = "1.0.0")] -impl Borrow for &mut T { +#[rustc_const_unstable(feature = "const_borrow", issue = "91522")] +impl const Borrow for &mut T { fn borrow(&self) -> &T { &**self } } #[stable(feature = "rust1", since = "1.0.0")] -impl BorrowMut for &mut T { +#[rustc_const_unstable(feature = "const_borrow", issue = "91522")] +impl const BorrowMut for &mut T { fn borrow_mut(&mut self) -> &mut T { &mut **self } diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs index 95798879155c5..f49aefea81bac 100644 --- a/library/core/src/hint.rs +++ b/library/core/src/hint.rs @@ -137,6 +137,11 @@ pub fn spin_loop() { unsafe { crate::arch::arm::__yield() }; } } + + #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] + { + crate::arch::riscv::pause(); + } } /// An identity function that *__hints__* to the compiler to be maximally pessimistic about what diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index f45ee7b6ee88b..ad2f6f213dec8 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -2244,13 +2244,29 @@ pub const unsafe fn copy(src: *const T, dst: *mut T, count: usize) { /// assert_eq!(*v, 42); /// ``` #[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")] #[inline] -pub unsafe fn write_bytes(dst: *mut T, val: u8, count: usize) { +pub const unsafe fn write_bytes(dst: *mut T, val: u8, count: usize) { extern "rust-intrinsic" { + #[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")] fn write_bytes(dst: *mut T, val: u8, count: usize); } - debug_assert!(is_aligned_and_not_null(dst), "attempt to write to unaligned or null pointer"); + #[cfg(debug_assertions)] + fn runtime_check(ptr: *mut T) { + debug_assert!( + is_aligned_and_not_null(ptr), + "attempt to write to unaligned or null pointer" + ); + } + #[cfg(debug_assertions)] + const fn compiletime_check(_ptr: *mut T) {} + #[cfg(debug_assertions)] + // SAFETY: runtime debug-assertions are a best-effort basis; it's fine to + // not do them during compile time + unsafe { + const_eval_select((dst,), compiletime_check, runtime_check); + } // SAFETY: the safety contract for `write_bytes` must be upheld by the caller. unsafe { write_bytes(dst, val, count) } diff --git a/library/core/tests/intrinsics.rs b/library/core/tests/intrinsics.rs index de163a60c98f4..84cef53b3584b 100644 --- a/library/core/tests/intrinsics.rs +++ b/library/core/tests/intrinsics.rs @@ -35,3 +35,33 @@ fn test_assume_can_be_in_const_contexts() { let rs = unsafe { foo(42, 97) }; assert_eq!(rs, 0); } + +#[test] +#[cfg(not(bootstrap))] +const fn test_write_bytes_in_const_contexts() { + use core::intrinsics::write_bytes; + + const TEST: [u32; 3] = { + let mut arr = [1u32, 2, 3]; + unsafe { + write_bytes(arr.as_mut_ptr(), 0, 2); + } + arr + }; + + assert!(TEST[0] == 0); + assert!(TEST[1] == 0); + assert!(TEST[2] == 3); + + const TEST2: [u32; 3] = { + let mut arr = [1u32, 2, 3]; + unsafe { + write_bytes(arr.as_mut_ptr(), 1, 2); + } + arr + }; + + assert!(TEST2[0] == 16843009); + assert!(TEST2[1] == 16843009); + assert!(TEST2[2] == 3); +} diff --git a/library/std/src/os/fd/owned.rs b/library/std/src/os/fd/owned.rs index 52d7d4690d39f..0b6588db92c83 100644 --- a/library/std/src/os/fd/owned.rs +++ b/library/std/src/os/fd/owned.rs @@ -8,6 +8,8 @@ use crate::fmt; use crate::fs; use crate::marker::PhantomData; use crate::mem::forget; +#[cfg(not(target_os = "wasi"))] +use crate::sys::cvt; use crate::sys_common::{AsInner, FromInner, IntoInner}; /// A borrowed file descriptor. @@ -67,6 +69,37 @@ impl BorrowedFd<'_> { } } +impl OwnedFd { + /// Creates a new `OwnedFd` instance that shares the same underlying file handle + /// as the existing `OwnedFd` instance. + #[cfg(not(target_os = "wasi"))] + pub fn try_clone(&self) -> crate::io::Result { + // We want to atomically duplicate this file descriptor and set the + // CLOEXEC flag, and currently that's done via F_DUPFD_CLOEXEC. This + // is a POSIX flag that was added to Linux in 2.6.24. + #[cfg(not(target_os = "espidf"))] + let cmd = libc::F_DUPFD_CLOEXEC; + + // For ESP-IDF, F_DUPFD is used instead, because the CLOEXEC semantics + // will never be supported, as this is a bare metal framework with + // no capabilities for multi-process execution. While F_DUPFD is also + // not supported yet, it might be (currently it returns ENOSYS). + #[cfg(target_os = "espidf")] + let cmd = libc::F_DUPFD; + + let fd = cvt(unsafe { libc::fcntl(self.as_raw_fd(), cmd, 0) })?; + Ok(unsafe { Self::from_raw_fd(fd) }) + } + + #[cfg(target_os = "wasi")] + pub fn try_clone(&self) -> crate::io::Result { + Err(crate::io::Error::new_const( + crate::io::ErrorKind::Unsupported, + &"operation not supported on WASI yet", + )) + } +} + #[unstable(feature = "io_safety", issue = "87074")] impl AsRawFd for BorrowedFd<'_> { #[inline] diff --git a/library/std/src/os/windows/io/handle.rs b/library/std/src/os/windows/io/handle.rs index 1527f5b6b07e0..e37ce633a129a 100644 --- a/library/std/src/os/windows/io/handle.rs +++ b/library/std/src/os/windows/io/handle.rs @@ -6,9 +6,11 @@ use super::raw::{AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle}; use crate::convert::TryFrom; use crate::fmt; use crate::fs; +use crate::io; use crate::marker::PhantomData; use crate::mem::forget; use crate::sys::c; +use crate::sys::cvt; use crate::sys_common::{AsInner, FromInner, IntoInner}; /// A borrowed handle. @@ -144,6 +146,36 @@ impl TryFrom for OwnedHandle { } } +impl OwnedHandle { + /// Creates a new `OwnedHandle` instance that shares the same underlying file handle + /// as the existing `OwnedHandle` instance. + pub fn try_clone(&self) -> crate::io::Result { + self.duplicate(0, false, c::DUPLICATE_SAME_ACCESS) + } + + pub(crate) fn duplicate( + &self, + access: c::DWORD, + inherit: bool, + options: c::DWORD, + ) -> io::Result { + let mut ret = 0 as c::HANDLE; + cvt(unsafe { + let cur_proc = c::GetCurrentProcess(); + c::DuplicateHandle( + cur_proc, + self.as_raw_handle(), + cur_proc, + &mut ret, + access, + inherit as c::BOOL, + options, + ) + })?; + unsafe { Ok(Self::from_raw_handle(ret)) } + } +} + impl TryFrom for OwnedHandle { type Error = (); diff --git a/library/std/src/os/windows/io/socket.rs b/library/std/src/os/windows/io/socket.rs index 23db66df09f7a..e0af4f1f6cb16 100644 --- a/library/std/src/os/windows/io/socket.rs +++ b/library/std/src/os/windows/io/socket.rs @@ -4,9 +4,12 @@ use super::raw::{AsRawSocket, FromRawSocket, IntoRawSocket, RawSocket}; use crate::fmt; +use crate::io; use crate::marker::PhantomData; +use crate::mem; use crate::mem::forget; use crate::sys::c; +use crate::sys::cvt; /// A borrowed socket. /// @@ -69,6 +72,77 @@ impl BorrowedSocket<'_> { } } +impl OwnedSocket { + /// Creates a new `OwnedSocket` instance that shares the same underlying socket + /// as the existing `OwnedSocket` instance. + pub fn try_clone(&self) -> io::Result { + let mut info = unsafe { mem::zeroed::() }; + let result = unsafe { + c::WSADuplicateSocketW(self.as_raw_socket(), c::GetCurrentProcessId(), &mut info) + }; + cvt(result)?; + let socket = unsafe { + c::WSASocketW( + info.iAddressFamily, + info.iSocketType, + info.iProtocol, + &mut info, + 0, + c::WSA_FLAG_OVERLAPPED | c::WSA_FLAG_NO_HANDLE_INHERIT, + ) + }; + + if socket != c::INVALID_SOCKET { + unsafe { Ok(OwnedSocket::from_raw_socket(socket)) } + } else { + let error = unsafe { c::WSAGetLastError() }; + + if error != c::WSAEPROTOTYPE && error != c::WSAEINVAL { + return Err(io::Error::from_raw_os_error(error)); + } + + let socket = unsafe { + c::WSASocketW( + info.iAddressFamily, + info.iSocketType, + info.iProtocol, + &mut info, + 0, + c::WSA_FLAG_OVERLAPPED, + ) + }; + + if socket == c::INVALID_SOCKET { + return Err(last_error()); + } + + unsafe { + let socket = OwnedSocket::from_raw_socket(socket); + socket.set_no_inherit()?; + Ok(socket) + } + } + } + + #[cfg(not(target_vendor = "uwp"))] + pub(crate) fn set_no_inherit(&self) -> io::Result<()> { + cvt(unsafe { + c::SetHandleInformation(self.as_raw_socket() as c::HANDLE, c::HANDLE_FLAG_INHERIT, 0) + }) + .map(drop) + } + + #[cfg(target_vendor = "uwp")] + pub(crate) fn set_no_inherit(&self) -> io::Result<()> { + Err(io::Error::new_const(io::ErrorKind::Unsupported, &"Unavailable on UWP")) + } +} + +/// Returns the last error from the Windows socket interface. +fn last_error() -> io::Error { + io::Error::from_raw_os_error(unsafe { c::WSAGetLastError() }) +} + impl AsRawSocket for BorrowedSocket<'_> { #[inline] fn as_raw_socket(&self) -> RawSocket { diff --git a/library/std/src/sys/unix/fd.rs b/library/std/src/sys/unix/fd.rs index 2362bff913f13..3de7c68a6866d 100644 --- a/library/std/src/sys/unix/fd.rs +++ b/library/std/src/sys/unix/fd.rs @@ -259,22 +259,9 @@ impl FileDesc { } } + #[inline] pub fn duplicate(&self) -> io::Result { - // We want to atomically duplicate this file descriptor and set the - // CLOEXEC flag, and currently that's done via F_DUPFD_CLOEXEC. This - // is a POSIX flag that was added to Linux in 2.6.24. - #[cfg(not(target_os = "espidf"))] - let cmd = libc::F_DUPFD_CLOEXEC; - - // For ESP-IDF, F_DUPFD is used instead, because the CLOEXEC semantics - // will never be supported, as this is a bare metal framework with - // no capabilities for multi-process execution. While F_DUPFD is also - // not supported yet, it might be (currently it returns ENOSYS). - #[cfg(target_os = "espidf")] - let cmd = libc::F_DUPFD; - - let fd = cvt(unsafe { libc::fcntl(self.as_raw_fd(), cmd, 0) })?; - Ok(unsafe { FileDesc::from_raw_fd(fd) }) + Ok(Self(self.0.try_clone()?)) } } diff --git a/library/std/src/sys/windows/fs.rs b/library/std/src/sys/windows/fs.rs index b258fc0478bdc..36e93696e72fe 100644 --- a/library/std/src/sys/windows/fs.rs +++ b/library/std/src/sys/windows/fs.rs @@ -460,7 +460,7 @@ impl File { } pub fn duplicate(&self) -> io::Result { - Ok(File { handle: self.handle.duplicate(0, false, c::DUPLICATE_SAME_ACCESS)? }) + Ok(Self { handle: self.handle.try_clone()? }) } fn reparse_point<'a>( diff --git a/library/std/src/sys/windows/handle.rs b/library/std/src/sys/windows/handle.rs index c3a3482f91051..daab39bb00cbc 100644 --- a/library/std/src/sys/windows/handle.rs +++ b/library/std/src/sys/windows/handle.rs @@ -262,26 +262,17 @@ impl Handle { Ok(written as usize) } + pub fn try_clone(&self) -> io::Result { + Ok(Self(self.0.try_clone()?)) + } + pub fn duplicate( &self, access: c::DWORD, inherit: bool, options: c::DWORD, - ) -> io::Result { - let mut ret = 0 as c::HANDLE; - cvt(unsafe { - let cur_proc = c::GetCurrentProcess(); - c::DuplicateHandle( - cur_proc, - self.as_raw_handle(), - cur_proc, - &mut ret, - access, - inherit as c::BOOL, - options, - ) - })?; - unsafe { Ok(Handle::from_raw_handle(ret)) } + ) -> io::Result { + Ok(Self(self.0.duplicate(access, inherit, options)?)) } } diff --git a/library/std/src/sys/windows/net.rs b/library/std/src/sys/windows/net.rs index 9c631e7e51c1d..14d5f15d20248 100644 --- a/library/std/src/sys/windows/net.rs +++ b/library/std/src/sys/windows/net.rs @@ -134,7 +134,7 @@ impl Socket { unsafe { let socket = Self::from_raw_socket(socket); - socket.set_no_inherit()?; + socket.0.set_no_inherit()?; Ok(socket) } } @@ -213,52 +213,7 @@ impl Socket { } pub fn duplicate(&self) -> io::Result { - let mut info = unsafe { mem::zeroed::() }; - let result = unsafe { - c::WSADuplicateSocketW(self.as_raw_socket(), c::GetCurrentProcessId(), &mut info) - }; - cvt(result)?; - let socket = unsafe { - c::WSASocketW( - info.iAddressFamily, - info.iSocketType, - info.iProtocol, - &mut info, - 0, - c::WSA_FLAG_OVERLAPPED | c::WSA_FLAG_NO_HANDLE_INHERIT, - ) - }; - - if socket != c::INVALID_SOCKET { - unsafe { Ok(Self::from_inner(OwnedSocket::from_raw_socket(socket))) } - } else { - let error = unsafe { c::WSAGetLastError() }; - - if error != c::WSAEPROTOTYPE && error != c::WSAEINVAL { - return Err(io::Error::from_raw_os_error(error)); - } - - let socket = unsafe { - c::WSASocketW( - info.iAddressFamily, - info.iSocketType, - info.iProtocol, - &mut info, - 0, - c::WSA_FLAG_OVERLAPPED, - ) - }; - - if socket == c::INVALID_SOCKET { - return Err(last_error()); - } - - unsafe { - let socket = Self::from_inner(OwnedSocket::from_raw_socket(socket)); - socket.set_no_inherit()?; - Ok(socket) - } - } + Ok(Self(self.0.try_clone()?)) } fn recv_with_flags(&self, buf: &mut [u8], flags: c_int) -> io::Result { @@ -421,19 +376,6 @@ impl Socket { } } - #[cfg(not(target_vendor = "uwp"))] - fn set_no_inherit(&self) -> io::Result<()> { - sys::cvt(unsafe { - c::SetHandleInformation(self.as_raw_socket() as c::HANDLE, c::HANDLE_FLAG_INHERIT, 0) - }) - .map(drop) - } - - #[cfg(target_vendor = "uwp")] - fn set_no_inherit(&self) -> io::Result<()> { - Err(io::Error::new_const(io::ErrorKind::Unsupported, &"Unavailable on UWP")) - } - pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { let how = match how { Shutdown::Write => c::SD_SEND, diff --git a/library/stdarch b/library/stdarch index cfba59fccd90b..b70ae88ef2a6c 160000 --- a/library/stdarch +++ b/library/stdarch @@ -1 +1 @@ -Subproject commit cfba59fccd90b3b52a614120834320f764ab08d1 +Subproject commit b70ae88ef2a6c83acad0a1e83d5bd78f9655fd05 diff --git a/src/test/ui/associated-types/cache/project-fn-ret-contravariant.transmute.stderr b/src/test/ui/associated-types/cache/project-fn-ret-contravariant.transmute.stderr index 0be9b37263a48..33f1e0f05b252 100644 --- a/src/test/ui/associated-types/cache/project-fn-ret-contravariant.transmute.stderr +++ b/src/test/ui/associated-types/cache/project-fn-ret-contravariant.transmute.stderr @@ -4,7 +4,7 @@ error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime LL | fn baz<'a,'b>(x: &'a u32) -> &'static u32 { | ------- this data with lifetime `'a`... LL | bar(foo, x) - | ----^^^---- ...is captured and required to live as long as `'static` here + | ^^^ - ...is used and required to live as long as `'static` here error: aborting due to previous error diff --git a/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr b/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr index 0a44864b24955..609627aaa9ef0 100644 --- a/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr +++ b/src/test/ui/associated-types/cache/project-fn-ret-invariant.transmute.stderr @@ -5,7 +5,16 @@ LL | fn baz<'a, 'b>(x: Type<'a>) -> Type<'static> { | -------- this data with lifetime `'a`... ... LL | bar(foo, x) - | ----^^^---- ...is captured and required to live as long as `'static` here + | ^^^ - ...is used and required to live as long as `'static` here + | +note: `'static` lifetime requirement introduced by the return type + --> $DIR/project-fn-ret-invariant.rs:45:37 + | +LL | fn baz<'a, 'b>(x: Type<'a>) -> Type<'static> { + | ^^^^^^^ `'static` requirement introduced here +... +LL | bar(foo, x) + | ----------- because of this returned expression error: aborting due to previous error diff --git a/src/test/ui/async-await/issues/issue-62097.stderr b/src/test/ui/async-await/issues/issue-62097.stderr index 56a28d904b91d..e23277543c66f 100644 --- a/src/test/ui/async-await/issues/issue-62097.stderr +++ b/src/test/ui/async-await/issues/issue-62097.stderr @@ -2,12 +2,15 @@ error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `' --> $DIR/issue-62097.rs:12:31 | LL | pub async fn run_dummy_fn(&self) { - | ^^^^^ - | | - | this data with an anonymous lifetime `'_`... - | ...is captured here... + | ^^^^^ this data with an anonymous lifetime `'_`... LL | foo(|| self.bar()).await; - | --- ...and is required to live as long as `'static` here + | --- ...is used and required to live as long as `'static` here + | +note: `'static` lifetime requirement introduced by this bound + --> $DIR/issue-62097.rs:4:19 + | +LL | F: FnOnce() + 'static + | ^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/async-await/issues/issue-72312.nll.stderr b/src/test/ui/async-await/issues/issue-72312.nll.stderr new file mode 100644 index 0000000000000..068d8c64d6898 --- /dev/null +++ b/src/test/ui/async-await/issues/issue-72312.nll.stderr @@ -0,0 +1,21 @@ +error[E0521]: borrowed data escapes outside of associated function + --> $DIR/issue-72312.rs:13:24 + | +LL | pub async fn start(&self) { + | ----- + | | + | `self` is a reference that is only valid in the associated function body + | let's call the lifetime of this reference `'1` +... +LL | require_static(async move { + | ________________________^ +LL | | &self; +LL | | }); + | | ^ + | | | + | |_________`self` escapes the associated function body here + | argument requires that `'1` must outlive `'static` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0521`. diff --git a/src/test/ui/async-await/issues/issue-72312.rs b/src/test/ui/async-await/issues/issue-72312.rs new file mode 100644 index 0000000000000..eb7d12e290cb6 --- /dev/null +++ b/src/test/ui/async-await/issues/issue-72312.rs @@ -0,0 +1,19 @@ +// edition:2018 +fn require_static(val: T) -> T { + //~^ NOTE 'static` lifetime requirement introduced by this bound + val +} + +struct Problem; + +impl Problem { + pub async fn start(&self) { //~ ERROR E0759 + //~^ NOTE this data with an anonymous lifetime `'_` + //~| NOTE in this expansion of desugaring of `async` block or function + require_static(async move { //~ NOTE ...and is required to live as long as `'static` here + &self; //~ NOTE ...is used here... + }); + } +} + +fn main() {} diff --git a/src/test/ui/async-await/issues/issue-72312.stderr b/src/test/ui/async-await/issues/issue-72312.stderr new file mode 100644 index 0000000000000..798f755765cc1 --- /dev/null +++ b/src/test/ui/async-await/issues/issue-72312.stderr @@ -0,0 +1,23 @@ +error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement + --> $DIR/issue-72312.rs:10:24 + | +LL | pub async fn start(&self) { + | ^^^^^ this data with an anonymous lifetime `'_`... +... +LL | &self; + | ----- ...is used here... + | +note: ...and is required to live as long as `'static` here + --> $DIR/issue-72312.rs:13:9 + | +LL | require_static(async move { + | ^^^^^^^^^^^^^^ +note: `'static` lifetime requirement introduced by this bound + --> $DIR/issue-72312.rs:2:22 + | +LL | fn require_static(val: T) -> T { + | ^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0759`. diff --git a/src/test/ui/borrowck/suggest-local-var-double-mut.rs b/src/test/ui/borrowck/suggest-local-var-double-mut.rs new file mode 100644 index 0000000000000..d5996ba68be53 --- /dev/null +++ b/src/test/ui/borrowck/suggest-local-var-double-mut.rs @@ -0,0 +1,27 @@ +// See issue #77834. + +#![crate_type = "lib"] + +mod method_syntax { + struct Foo; + + impl Foo { + fn foo(&mut self, _: f32) -> i32 { todo!() } + fn bar(&mut self) -> f32 { todo!() } + fn baz(&mut self) { + self.foo(self.bar()); //~ ERROR + } + } +} + +mod fully_qualified_syntax { + struct Foo; + + impl Foo { + fn foo(&mut self, _: f32) -> i32 { todo!() } + fn bar(&mut self) -> f32 { todo!() } + fn baz(&mut self) { + Self::foo(self, Self::bar(self)); //~ ERROR + } + } +} diff --git a/src/test/ui/borrowck/suggest-local-var-double-mut.stderr b/src/test/ui/borrowck/suggest-local-var-double-mut.stderr new file mode 100644 index 0000000000000..3a43c18a7ed52 --- /dev/null +++ b/src/test/ui/borrowck/suggest-local-var-double-mut.stderr @@ -0,0 +1,44 @@ +error[E0499]: cannot borrow `*self` as mutable more than once at a time + --> $DIR/suggest-local-var-double-mut.rs:12:22 + | +LL | self.foo(self.bar()); + | ---------^^^^^^^^^^- + | | | | + | | | second mutable borrow occurs here + | | first borrow later used by call + | first mutable borrow occurs here + | +help: try adding a local storing this argument... + --> $DIR/suggest-local-var-double-mut.rs:12:22 + | +LL | self.foo(self.bar()); + | ^^^^^^^^^^ +help: ...and then using that local as the argument to this call + --> $DIR/suggest-local-var-double-mut.rs:12:13 + | +LL | self.foo(self.bar()); + | ^^^^^^^^^^^^^^^^^^^^ + +error[E0499]: cannot borrow `*self` as mutable more than once at a time + --> $DIR/suggest-local-var-double-mut.rs:24:39 + | +LL | Self::foo(self, Self::bar(self)); + | --------- ---- ^^^^ second mutable borrow occurs here + | | | + | | first mutable borrow occurs here + | first borrow later used by call + | +help: try adding a local storing this argument... + --> $DIR/suggest-local-var-double-mut.rs:24:29 + | +LL | Self::foo(self, Self::bar(self)); + | ^^^^^^^^^^^^^^^ +help: ...and then using that local as the argument to this call + --> $DIR/suggest-local-var-double-mut.rs:24:13 + | +LL | Self::foo(self, Self::bar(self)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0499`. diff --git a/src/test/ui/borrowck/suggest-local-var-imm-and-mut.nll.stderr b/src/test/ui/borrowck/suggest-local-var-imm-and-mut.nll.stderr new file mode 100644 index 0000000000000..2ba0b6b28aaaa --- /dev/null +++ b/src/test/ui/borrowck/suggest-local-var-imm-and-mut.nll.stderr @@ -0,0 +1,33 @@ +error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable + --> $DIR/suggest-local-var-imm-and-mut.rs:12:22 + | +LL | self.foo(self.bar()); + | ---------^^^^^^^^^^- + | | | | + | | | mutable borrow occurs here + | | immutable borrow later used by call + | immutable borrow occurs here + | +help: try adding a local storing this argument... + --> $DIR/suggest-local-var-imm-and-mut.rs:12:22 + | +LL | self.foo(self.bar()); + | ^^^^^^^^^^ +help: ...and then using that local as the argument to this call + --> $DIR/suggest-local-var-imm-and-mut.rs:12:13 + | +LL | self.foo(self.bar()); + | ^^^^^^^^^^^^^^^^^^^^ + +error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable + --> $DIR/suggest-local-var-imm-and-mut.rs:24:39 + | +LL | Self::foo(self, Self::bar(self)); + | --------- ---- ^^^^ mutable borrow occurs here + | | | + | | immutable borrow occurs here + | immutable borrow later used by call + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0502`. diff --git a/src/test/ui/borrowck/suggest-local-var-imm-and-mut.rs b/src/test/ui/borrowck/suggest-local-var-imm-and-mut.rs new file mode 100644 index 0000000000000..bf167ba79f311 --- /dev/null +++ b/src/test/ui/borrowck/suggest-local-var-imm-and-mut.rs @@ -0,0 +1,27 @@ +// See issue #77834. + +#![crate_type = "lib"] + +mod method_syntax { + struct Foo; + + impl Foo { + fn foo(&self, _: f32) -> i32 { todo!() } + fn bar(&mut self) -> f32 { todo!() } + fn baz(&mut self) { + self.foo(self.bar()); //~ ERROR + } + } +} + +mod fully_qualified_syntax { + struct Foo; + + impl Foo { + fn foo(&self, _: f32) -> i32 { todo!() } + fn bar(&mut self) -> f32 { todo!() } + fn baz(&mut self) { + Self::foo(self, Self::bar(self)); //~ ERROR + } + } +} diff --git a/src/test/ui/borrowck/suggest-local-var-imm-and-mut.stderr b/src/test/ui/borrowck/suggest-local-var-imm-and-mut.stderr new file mode 100644 index 0000000000000..eb934e7b72b08 --- /dev/null +++ b/src/test/ui/borrowck/suggest-local-var-imm-and-mut.stderr @@ -0,0 +1,22 @@ +error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable + --> $DIR/suggest-local-var-imm-and-mut.rs:12:22 + | +LL | self.foo(self.bar()); + | ---------^^^^^^^^^^- + | | | | + | | | mutable borrow occurs here + | | immutable borrow later used by call + | immutable borrow occurs here + +error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable + --> $DIR/suggest-local-var-imm-and-mut.rs:24:29 + | +LL | Self::foo(self, Self::bar(self)); + | --------- ---- ^^^^^^^^^^^^^^^ mutable borrow occurs here + | | | + | | immutable borrow occurs here + | immutable borrow later used by call + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0502`. diff --git a/src/test/ui/borrowck/two-phase-cannot-nest-mut-self-calls.stderr b/src/test/ui/borrowck/two-phase-cannot-nest-mut-self-calls.stderr index a89bb941532b6..85c7159952ffa 100644 --- a/src/test/ui/borrowck/two-phase-cannot-nest-mut-self-calls.stderr +++ b/src/test/ui/borrowck/two-phase-cannot-nest-mut-self-calls.stderr @@ -13,6 +13,23 @@ LL | | LL | | 0 LL | | }); | |______- immutable borrow occurs here + | +help: try adding a local storing this argument... + --> $DIR/two-phase-cannot-nest-mut-self-calls.rs:16:9 + | +LL | vec.push(2); + | ^^^^^^^^^^^ +help: ...and then using that local as the argument to this call + --> $DIR/two-phase-cannot-nest-mut-self-calls.rs:14:5 + | +LL | / vec.get({ +LL | | +LL | | vec.push(2); +LL | | +LL | | +LL | | 0 +LL | | }); + | |______^ error: aborting due to previous error diff --git a/src/test/ui/closures/closure-bounds-static-cant-capture-borrowed.stderr b/src/test/ui/closures/closure-bounds-static-cant-capture-borrowed.stderr index d761abdfc6a34..af1f908a80852 100644 --- a/src/test/ui/closures/closure-bounds-static-cant-capture-borrowed.stderr +++ b/src/test/ui/closures/closure-bounds-static-cant-capture-borrowed.stderr @@ -8,13 +8,18 @@ LL | bar(|| { LL | | LL | | let _ = x; LL | | }) - | |_____^ ...is captured here... + | |_____^ ...is used here... | note: ...and is required to live as long as `'static` here --> $DIR/closure-bounds-static-cant-capture-borrowed.rs:5:5 | LL | bar(|| { | ^^^ +note: `'static` lifetime requirement introduced by this bound + --> $DIR/closure-bounds-static-cant-capture-borrowed.rs:1:39 + | +LL | fn bar(blk: F) where F: FnOnce() + 'static { + | ^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/codemap_tests/one_line.stderr b/src/test/ui/codemap_tests/one_line.stderr index 1ee612184def2..6fe6e26135b92 100644 --- a/src/test/ui/codemap_tests/one_line.stderr +++ b/src/test/ui/codemap_tests/one_line.stderr @@ -7,6 +7,17 @@ LL | v.push(v.pop().unwrap()); | | | second mutable borrow occurs here | | first borrow later used by call | first mutable borrow occurs here + | +help: try adding a local storing this argument... + --> $DIR/one_line.rs:3:12 + | +LL | v.push(v.pop().unwrap()); + | ^^^^^^^ +help: ...and then using that local as the argument to this call + --> $DIR/one_line.rs:3:5 + | +LL | v.push(v.pop().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/generator/generator-region-requirements.stderr b/src/test/ui/generator/generator-region-requirements.stderr index b6b9db22426eb..30d67050b904c 100644 --- a/src/test/ui/generator/generator-region-requirements.stderr +++ b/src/test/ui/generator/generator-region-requirements.stderr @@ -5,7 +5,7 @@ LL | fn dangle(x: &mut i32) -> &'static mut i32 { | -------- this data with an anonymous lifetime `'_`... ... LL | x - | ^ ...is captured here... + | ^ ...is used here... ... LL | GeneratorState::Complete(c) => return c, | - ...and is required to live as long as `'static` here diff --git a/src/test/ui/generic-associated-types/projection-type-lifetime-mismatch.stderr b/src/test/ui/generic-associated-types/projection-type-lifetime-mismatch.stderr index 1ffd205652f66..32c5ccf164874 100644 --- a/src/test/ui/generic-associated-types/projection-type-lifetime-mismatch.stderr +++ b/src/test/ui/generic-associated-types/projection-type-lifetime-mismatch.stderr @@ -4,7 +4,9 @@ error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'sta LL | fn f(x: &impl for<'a> X = &'a ()>) -> &'static () { | ------------------------------- this data with an anonymous lifetime `'_`... LL | x.m() - | --^-- ...is captured and required to live as long as `'static` here + | - ^ + | | + | ...is used and required to live as long as `'static` here error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement --> $DIR/projection-type-lifetime-mismatch.rs:22:7 @@ -12,7 +14,9 @@ error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'sta LL | fn g X = &'a ()>>(x: &T) -> &'static () { | -- this data with an anonymous lifetime `'_`... LL | x.m() - | --^-- ...is captured and required to live as long as `'static` here + | - ^ + | | + | ...is used and required to live as long as `'static` here error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement --> $DIR/projection-type-lifetime-mismatch.rs:27:7 @@ -20,7 +24,9 @@ error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'sta LL | fn h(x: &()) -> &'static () { | --- this data with an anonymous lifetime `'_`... LL | x.m() - | --^-- ...is captured and required to live as long as `'static` here + | - ^ + | | + | ...is used and required to live as long as `'static` here error: aborting due to 3 previous errors diff --git a/src/test/ui/impl-header-lifetime-elision/dyn-trait.stderr b/src/test/ui/impl-header-lifetime-elision/dyn-trait.stderr index b3bef677d19c1..2307572cc3f24 100644 --- a/src/test/ui/impl-header-lifetime-elision/dyn-trait.stderr +++ b/src/test/ui/impl-header-lifetime-elision/dyn-trait.stderr @@ -4,7 +4,7 @@ error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime LL | fn with_dyn_debug_static<'a>(x: Box) { | ------------------- this data with lifetime `'a`... LL | static_val(x); - | ^ ...is captured here... + | ^ ...is used here... | note: ...and is required to live as long as `'static` here --> $DIR/dyn-trait.rs:20:5 diff --git a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr index d65dea7adc90b..de5d3b612c9c2 100644 --- a/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr +++ b/src/test/ui/impl-trait/must_outlive_least_region_or_bound.stderr @@ -28,7 +28,7 @@ error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'sta --> $DIR/must_outlive_least_region_or_bound.rs:9:46 | LL | fn elided2(x: &i32) -> impl Copy + 'static { x } - | ---- ^ ...is captured here... + | ---- ^ ...is used here... | | | this data with an anonymous lifetime `'_`... | @@ -50,7 +50,7 @@ error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime --> $DIR/must_outlive_least_region_or_bound.rs:11:55 | LL | fn explicit2<'a>(x: &'a i32) -> impl Copy + 'static { x } - | ------- ^ ...is captured here... + | ------- ^ ...is used here... | | | this data with lifetime `'a`... | @@ -80,7 +80,7 @@ error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'sta --> $DIR/must_outlive_least_region_or_bound.rs:24:65 | LL | fn elided5(x: &i32) -> (Box, impl Debug) { (Box::new(x), x) } - | ---- this data with an anonymous lifetime `'_`... ^ ...is captured here, requiring it to live as long as `'static` + | ---- this data with an anonymous lifetime `'_`... ^ ...is used and required to live as long as `'static` here | help: to declare that the trait object captures data from argument `x`, you can add an explicit `'_` lifetime bound | @@ -95,7 +95,7 @@ error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime --> $DIR/must_outlive_least_region_or_bound.rs:29:69 | LL | fn with_bound<'a>(x: &'a i32) -> impl LifetimeTrait<'a> + 'static { x } - | ------- this data with lifetime `'a`... ^ ...is captured here... + | ------- this data with lifetime `'a`... ^ ...is used here... | note: ...and is required to live as long as `'static` here --> $DIR/must_outlive_least_region_or_bound.rs:29:34 @@ -136,10 +136,17 @@ error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'sta --> $DIR/must_outlive_least_region_or_bound.rs:16:50 | LL | fn elided3(x: &i32) -> Box { Box::new(x) } - | ---- ^ ...is captured here, requiring it to live as long as `'static` + | ---- ^ ...is used and required to live as long as `'static` here | | | this data with an anonymous lifetime `'_`... | +note: `'static` lifetime requirement introduced by the return type + --> $DIR/must_outlive_least_region_or_bound.rs:16:28 + | +LL | fn elided3(x: &i32) -> Box { Box::new(x) } + | ^^^^^^^^^ ----------- because of this returned expression + | | + | `'static` requirement introduced here help: to declare that the trait object captures data from argument `x`, you can add an explicit `'_` lifetime bound | LL | fn elided3(x: &i32) -> Box { Box::new(x) } @@ -149,10 +156,17 @@ error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime --> $DIR/must_outlive_least_region_or_bound.rs:18:59 | LL | fn explicit3<'a>(x: &'a i32) -> Box { Box::new(x) } - | ------- ^ ...is captured here, requiring it to live as long as `'static` + | ------- ^ ...is used and required to live as long as `'static` here | | | this data with lifetime `'a`... | +note: `'static` lifetime requirement introduced by the return type + --> $DIR/must_outlive_least_region_or_bound.rs:18:37 + | +LL | fn explicit3<'a>(x: &'a i32) -> Box { Box::new(x) } + | ^^^^^^^^^ ----------- because of this returned expression + | | + | `'static` requirement introduced here help: to declare that the trait object captures data from argument `x`, you can add an explicit `'a` lifetime bound | LL | fn explicit3<'a>(x: &'a i32) -> Box { Box::new(x) } @@ -162,10 +176,17 @@ error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'sta --> $DIR/must_outlive_least_region_or_bound.rs:20:60 | LL | fn elided4(x: &i32) -> Box { Box::new(x) } - | ---- ^ ...is captured here, requiring it to live as long as `'static` + | ---- ^ ...is used and required to live as long as `'static` here | | | this data with an anonymous lifetime `'_`... | +note: `'static` lifetime requirement introduced by the return type + --> $DIR/must_outlive_least_region_or_bound.rs:20:40 + | +LL | fn elided4(x: &i32) -> Box { Box::new(x) } + | ^^^^^^^ ----------- because of this returned expression + | | + | `'static` requirement introduced here help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `x` | LL | fn elided4(x: &i32) -> Box { Box::new(x) } @@ -179,8 +200,15 @@ error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime --> $DIR/must_outlive_least_region_or_bound.rs:22:69 | LL | fn explicit4<'a>(x: &'a i32) -> Box { Box::new(x) } - | ------- this data with lifetime `'a`... ^ ...is captured here, requiring it to live as long as `'static` + | ------- this data with lifetime `'a`... ^ ...is used and required to live as long as `'static` here | +note: `'static` lifetime requirement introduced by the return type + --> $DIR/must_outlive_least_region_or_bound.rs:22:49 + | +LL | fn explicit4<'a>(x: &'a i32) -> Box { Box::new(x) } + | ^^^^^^^ ----------- because of this returned expression + | | + | `'static` requirement introduced here help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `x` | LL | fn explicit4<'a>(x: &'a i32) -> Box { Box::new(x) } diff --git a/src/test/ui/issues/issue-16922.stderr b/src/test/ui/issues/issue-16922.stderr index 8b09b7d59079f..53405a660f861 100644 --- a/src/test/ui/issues/issue-16922.stderr +++ b/src/test/ui/issues/issue-16922.stderr @@ -4,7 +4,7 @@ error[E0759]: `value` has an anonymous lifetime `'_` but it needs to satisfy a ` LL | fn foo(value: &T) -> Box { | -- this data with an anonymous lifetime `'_`... LL | Box::new(value) as Box - | ^^^^^ ...is captured here, requiring it to live as long as `'static` + | ^^^^^ ...is used and required to live as long as `'static` here | help: to declare that the trait object captures data from argument `value`, you can add an explicit `'_` lifetime bound | diff --git a/src/test/ui/issues/issue-46983.stderr b/src/test/ui/issues/issue-46983.stderr index 77fb130f5192e..ed9f1884c42fb 100644 --- a/src/test/ui/issues/issue-46983.stderr +++ b/src/test/ui/issues/issue-46983.stderr @@ -4,7 +4,7 @@ error[E0759]: `x` has an anonymous lifetime `'_` but it needs to satisfy a `'sta LL | fn foo(x: &u32) -> &'static u32 { | ---- this data with an anonymous lifetime `'_`... LL | &*x - | ^^^ ...is captured and required to live as long as `'static` here + | ^^^ ...is used and required to live as long as `'static` here error: aborting due to previous error diff --git a/src/test/ui/lifetimes/issue-90600-expected-return-static-indirect.stderr b/src/test/ui/lifetimes/issue-90600-expected-return-static-indirect.stderr index 3f65d3af725cf..e06255e4ea3ff 100644 --- a/src/test/ui/lifetimes/issue-90600-expected-return-static-indirect.stderr +++ b/src/test/ui/lifetimes/issue-90600-expected-return-static-indirect.stderr @@ -4,7 +4,7 @@ error[E0759]: `foo` has an anonymous lifetime `'_` but it needs to satisfy a `'s LL | fn inner(mut foo: &[u8]) { | ----- this data with an anonymous lifetime `'_`... LL | let refcell = RefCell::new(&mut foo); - | ^^^^^^^^ ...is captured here... + | ^^^^^^^^ ...is used here... ... LL | read_thing(read); | ---- ...and is required to live as long as `'static` here diff --git a/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.stderr b/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.stderr index 1931934a2112a..4a6378b84f1e6 100644 --- a/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.stderr +++ b/src/test/ui/nll/user-annotations/constant-in-expr-inherent-1.stderr @@ -4,7 +4,7 @@ error[E0759]: `fn` parameter has lifetime `'a` but it needs to satisfy a `'stati LL | fn foo<'a>(_: &'a u32) -> &'static u32 { | ------- this data with lifetime `'a`... LL | >::C - | ^^^^^^^^^^^^ ...is captured and required to live as long as `'static` here + | ^^^^^^^^^^^^ ...is used and required to live as long as `'static` here error: aborting due to previous error diff --git a/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.stderr b/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.stderr index e0a8534cd28fa..1708700f77aaa 100644 --- a/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.stderr +++ b/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.stderr @@ -5,8 +5,16 @@ LL | fn load(ss: &mut SomeStruct) -> Box { | --------------- this data with an anonymous lifetime `'_`... ... LL | ss.r - | ^^^^ ...is captured and required to live as long as `'static` here + | ^^^^ ...is used and required to live as long as `'static` here | +note: `'static` lifetime requirement introduced by the return type + --> $DIR/object-lifetime-default-from-box-error.rs:14:37 + | +LL | fn load(ss: &mut SomeStruct) -> Box { + | ^^^^^^^^^^^^^ `'static` requirement introduced here +... +LL | ss.r + | ---- because of this returned expression help: to declare that the trait object captures data from argument `ss`, you can add an explicit `'_` lifetime bound | LL | fn load(ss: &mut SomeStruct) -> Box { diff --git a/src/test/ui/regions/region-object-lifetime-in-coercion.stderr b/src/test/ui/regions/region-object-lifetime-in-coercion.stderr index 04d22e58a1dc5..d8932c067acd8 100644 --- a/src/test/ui/regions/region-object-lifetime-in-coercion.stderr +++ b/src/test/ui/regions/region-object-lifetime-in-coercion.stderr @@ -4,7 +4,7 @@ error[E0759]: `v` has an anonymous lifetime `'_` but it needs to satisfy a `'sta LL | fn a(v: &[u8]) -> Box { | ----- this data with an anonymous lifetime `'_`... LL | let x: Box = Box::new(v); - | ^ ...is captured here, requiring it to live as long as `'static` + | ^ ...is used and required to live as long as `'static` here | help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `v` | @@ -21,8 +21,15 @@ error[E0759]: `v` has an anonymous lifetime `'_` but it needs to satisfy a `'sta LL | fn b(v: &[u8]) -> Box { | ----- this data with an anonymous lifetime `'_`... LL | Box::new(v) - | ^ ...is captured here, requiring it to live as long as `'static` + | ^ ...is used and required to live as long as `'static` here | +note: `'static` lifetime requirement introduced by the return type + --> $DIR/region-object-lifetime-in-coercion.rs:12:33 + | +LL | fn b(v: &[u8]) -> Box { + | ^^^^^^^ `'static` requirement introduced here +LL | Box::new(v) + | ----------- because of this returned expression help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `v` | LL | fn b(v: &[u8]) -> Box { @@ -39,8 +46,16 @@ LL | fn c(v: &[u8]) -> Box { | ----- this data with an anonymous lifetime `'_`... ... LL | Box::new(v) - | ^ ...is captured here, requiring it to live as long as `'static` + | ^ ...is used and required to live as long as `'static` here + | +note: `'static` lifetime requirement introduced by the return type + --> $DIR/region-object-lifetime-in-coercion.rs:16:23 | +LL | fn c(v: &[u8]) -> Box { + | ^^^^^^^ `'static` requirement introduced here +... +LL | Box::new(v) + | ----------- because of this returned expression help: to declare that the trait object captures data from argument `v`, you can add an explicit `'_` lifetime bound | LL | fn c(v: &[u8]) -> Box { diff --git a/src/test/ui/regions/regions-addr-of-self.stderr b/src/test/ui/regions/regions-addr-of-self.stderr index 738691fd695eb..3453c6458f1da 100644 --- a/src/test/ui/regions/regions-addr-of-self.stderr +++ b/src/test/ui/regions/regions-addr-of-self.stderr @@ -4,7 +4,7 @@ error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `' LL | pub fn chase_cat(&mut self) { | --------- this data with an anonymous lifetime `'_`... LL | let p: &'static mut usize = &mut self.cats_chased; - | ^^^^^^^^^^^^^^^^^^^^^ ...is captured and required to live as long as `'static` here + | ^^^^^^^^^^^^^^^^^^^^^ ...is used and required to live as long as `'static` here error: aborting due to previous error diff --git a/src/test/ui/regions/regions-close-object-into-object-2.stderr b/src/test/ui/regions/regions-close-object-into-object-2.stderr index 9a7df8c0188b1..4153f4f29bc28 100644 --- a/src/test/ui/regions/regions-close-object-into-object-2.stderr +++ b/src/test/ui/regions/regions-close-object-into-object-2.stderr @@ -4,8 +4,15 @@ error[E0759]: `v` has lifetime `'a` but it needs to satisfy a `'static` lifetime LL | fn g<'a, T: 'static>(v: Box + 'a>) -> Box { | ------------------ this data with lifetime `'a`... LL | Box::new(B(&*v)) as Box - | ^^^ ...is captured here, requiring it to live as long as `'static` + | ^^^ ...is used and required to live as long as `'static` here | +note: `'static` lifetime requirement introduced by the return type + --> $DIR/regions-close-object-into-object-2.rs:8:60 + | +LL | fn g<'a, T: 'static>(v: Box + 'a>) -> Box { + | ^^^^^^^ `'static` requirement introduced here +LL | Box::new(B(&*v)) as Box + | ------------------------------ because of this returned expression help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `v` | LL | fn g<'a, T: 'static>(v: Box + 'a>) -> Box { diff --git a/src/test/ui/regions/regions-close-object-into-object-4.stderr b/src/test/ui/regions/regions-close-object-into-object-4.stderr index a7a9b16b08013..2ea4b431b38da 100644 --- a/src/test/ui/regions/regions-close-object-into-object-4.stderr +++ b/src/test/ui/regions/regions-close-object-into-object-4.stderr @@ -4,8 +4,15 @@ error[E0759]: `v` has lifetime `'a` but it needs to satisfy a `'static` lifetime LL | fn i<'a, T, U>(v: Box+'a>) -> Box { | ---------------- this data with lifetime `'a`... LL | Box::new(B(&*v)) as Box - | ^^^ ...is captured here, requiring it to live as long as `'static` + | ^^^ ...is used and required to live as long as `'static` here | +note: `'static` lifetime requirement introduced by the return type + --> $DIR/regions-close-object-into-object-4.rs:8:52 + | +LL | fn i<'a, T, U>(v: Box+'a>) -> Box { + | ^^^^^^^ `'static` requirement introduced here +LL | Box::new(B(&*v)) as Box + | ------------------------------ because of this returned expression help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `v` | LL | fn i<'a, T, U>(v: Box+'a>) -> Box { diff --git a/src/test/ui/regions/regions-proc-bound-capture.stderr b/src/test/ui/regions/regions-proc-bound-capture.stderr index 50b3748bf40e9..2ebe874da9350 100644 --- a/src/test/ui/regions/regions-proc-bound-capture.stderr +++ b/src/test/ui/regions/regions-proc-bound-capture.stderr @@ -5,8 +5,16 @@ LL | fn static_proc(x: &isize) -> Box (isize) + 'static> { | ------ this data with an anonymous lifetime `'_`... LL | // This is illegal, because the region bound on `proc` is 'static. LL | Box::new(move || { *x }) - | ^^^^^^^^^^^^^^ ...is captured here, requiring it to live as long as `'static` + | ^^^^^^^^^^^^^^ ...is used and required to live as long as `'static` here | +note: `'static` lifetime requirement introduced by the return type + --> $DIR/regions-proc-bound-capture.rs:7:59 + | +LL | fn static_proc(x: &isize) -> Box (isize) + 'static> { + | ^^^^^^^ `'static` requirement introduced here +LL | // This is illegal, because the region bound on `proc` is 'static. +LL | Box::new(move || { *x }) + | ------------------------ because of this returned expression help: consider changing the trait object's explicit `'static` bound to the lifetime of argument `x` | LL | fn static_proc(x: &isize) -> Box (isize) + '_> { diff --git a/src/test/ui/regions/regions-static-bound.stderr b/src/test/ui/regions/regions-static-bound.stderr index 51fe16ca9da03..b8e69e02609d6 100644 --- a/src/test/ui/regions/regions-static-bound.stderr +++ b/src/test/ui/regions/regions-static-bound.stderr @@ -17,7 +17,7 @@ error[E0759]: `u` has an anonymous lifetime `'_` but it needs to satisfy a `'sta LL | fn error(u: &(), v: &()) { | --- this data with an anonymous lifetime `'_`... LL | static_id(&u); - | ^^^^^^^^^ -- ...is captured here... + | ^^^^^^^^^ -- ...is used here... | note: ...and is required to live as long as `'static` here --> $DIR/regions-static-bound.rs:10:5 @@ -32,7 +32,7 @@ LL | fn error(u: &(), v: &()) { | --- this data with an anonymous lifetime `'_`... LL | static_id(&u); LL | static_id_indirect(&v); - | ^^^^^^^^^^^^^^^^^^ -- ...is captured here... + | ^^^^^^^^^^^^^^^^^^ -- ...is used here... | note: ...and is required to live as long as `'static` here --> $DIR/regions-static-bound.rs:11:5 diff --git a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.stderr b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.stderr index 2961d8d7eacc9..63d291ed7cdb9 100644 --- a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.stderr +++ b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.stderr @@ -22,7 +22,7 @@ error[E0772]: `val` has lifetime `'a` but calling `use_self` introduces an impli LL | fn use_it<'a>(val: Box + 'a>) -> &'a () { | -------------------------------------- this data with lifetime `'a`... LL | val.use_self() - | ^^^^^^^^ ...is captured and required to live as long as `'static` here + | ^^^^^^^^ ...is used and required to live as long as `'static` here | note: the used `impl` has a `'static` requirement --> $DIR/impl-on-dyn-trait-with-implicit-static-bound-needing-more-suggestions.rs:60:30 diff --git a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.stderr b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.stderr index 6d9f0811b2735..55a1bbf18ab9f 100644 --- a/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.stderr +++ b/src/test/ui/suggestions/impl-on-dyn-trait-with-implicit-static-bound.stderr @@ -4,7 +4,7 @@ error[E0759]: `val` has lifetime `'a` but it needs to satisfy a `'static` lifeti LL | fn use_it<'a, T>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a { | ---------------------- this data with lifetime `'a`... LL | val.use_self::() - | ^^^^^^^^ ...is captured and required to live as long as `'static` here + | ^^^^^^^^ ...is used and required to live as long as `'static` here | note: the used `impl` has a `'static` requirement --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:14:32 @@ -24,7 +24,7 @@ error[E0772]: `val` has lifetime `'a` but calling `use_self` introduces an impli LL | fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a { | ------------------- this data with lifetime `'a`... LL | val.use_self() - | ^^^^^^^^ ...is captured and required to live as long as `'static` here because of an implicit lifetime bound on the inherent `impl` + | ^^^^^^^^ ...is used and required to live as long as `'static` here because of an implicit lifetime bound on the inherent `impl` | note: the used `impl` has a `'static` requirement --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:64:14 @@ -44,7 +44,7 @@ error[E0759]: `val` has lifetime `'a` but it needs to satisfy a `'static` lifeti LL | fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> { | ------------------- this data with lifetime `'a`... LL | val.use_self() - | ^^^^^^^^ ...is captured and required to live as long as `'static` here + | ^^^^^^^^ ...is used and required to live as long as `'static` here | note: the used `impl` has a `'static` requirement --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:85:26 @@ -69,7 +69,7 @@ error[E0759]: `val` has lifetime `'a` but it needs to satisfy a `'static` lifeti LL | fn use_it<'a>(val: &'a dyn ObjectTrait) -> impl OtherTrait<'a> + 'a { | ------------------- this data with lifetime `'a`... LL | MyTrait::use_self(val) - | ^^^ ...is captured here... + | ^^^ ...is used here... | note: ...and is required to live as long as `'static` here --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:108:9 @@ -95,7 +95,7 @@ error[E0772]: `val` has lifetime `'a` but calling `use_self` introduces an impli LL | fn use_it<'a>(val: &'a dyn ObjectTrait) -> &'a () { | ------------------- this data with lifetime `'a`... LL | val.use_self() - | ^^^^^^^^ ...is captured and required to live as long as `'static` here + | ^^^^^^^^ ...is used and required to live as long as `'static` here | note: the used `impl` has a `'static` requirement --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:31:26 @@ -115,7 +115,7 @@ error[E0772]: `val` has lifetime `'a` but calling `use_self` introduces an impli LL | fn use_it<'a>(val: &'a Box) -> &'a () { | ----------------------------- this data with lifetime `'a`... LL | val.use_self() - | ^^^^^^^^ ...is captured and required to live as long as `'static` here + | ^^^^^^^^ ...is used and required to live as long as `'static` here | note: the used `impl` has a `'static` requirement --> $DIR/impl-on-dyn-trait-with-implicit-static-bound.rs:48:30 diff --git a/src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.stderr b/src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.stderr index 1ca22ebeef479..a5b50634c71ea 100644 --- a/src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.stderr +++ b/src/test/ui/suggestions/lifetimes/trait-object-nested-in-impl-trait.stderr @@ -7,7 +7,7 @@ LL | fn iter(&self) -> impl Iterator> { LL | remaining: self.0.iter(), | ------ ^^^^ | | - | ...is captured here... + | ...is used here... | note: ...and is required to live as long as `'static` here --> $DIR/trait-object-nested-in-impl-trait.rs:27:23 @@ -32,7 +32,7 @@ LL | fn iter(&self) -> impl Iterator> + '_ { LL | remaining: self.0.iter(), | ------ ^^^^ | | - | ...is captured here... + | ...is used here... | note: ...and is required to live as long as `'static` here --> $DIR/trait-object-nested-in-impl-trait.rs:38:23 @@ -53,7 +53,7 @@ LL | fn iter<'a>(&'a self) -> impl Iterator> + 'a { LL | remaining: self.0.iter(), | ------ ^^^^ | | - | ...is captured here... + | ...is used here... | note: ...and is required to live as long as `'static` here --> $DIR/trait-object-nested-in-impl-trait.rs:49:30 @@ -74,7 +74,7 @@ LL | fn iter<'a>(&'a self) -> impl Iterator> { LL | remaining: self.0.iter(), | ------ ^^^^ | | - | ...is captured here... + | ...is used here... | note: ...and is required to live as long as `'static` here --> $DIR/trait-object-nested-in-impl-trait.rs:60:30 diff --git a/src/test/ui/traits/trait-upcasting/type-checking-test-4.rs b/src/test/ui/traits/trait-upcasting/type-checking-test-4.rs index 9b27fd46f7acd..95698fd1e1a80 100644 --- a/src/test/ui/traits/trait-upcasting/type-checking-test-4.rs +++ b/src/test/ui/traits/trait-upcasting/type-checking-test-4.rs @@ -29,4 +29,22 @@ fn test_wrong3<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> { y.get_b() // ERROR } +fn test_wrong4<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> { + <_ as Bar>::get_b(x) // ERROR + //~^ ERROR `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement +} + +fn test_wrong5<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> { + <_ as Bar<'_, '_>>::get_b(x) // ERROR + //~^ ERROR `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement +} + +fn test_wrong6<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> { + let y = x as &dyn Bar<'_, '_>; + //~^ ERROR `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement + y.get_b(); // ERROR + let z = y; + z.get_b() // ERROR +} + fn main() {} diff --git a/src/test/ui/traits/trait-upcasting/type-checking-test-4.stderr b/src/test/ui/traits/trait-upcasting/type-checking-test-4.stderr index 4967f3dc2c8cf..d4bb9350b0b4e 100644 --- a/src/test/ui/traits/trait-upcasting/type-checking-test-4.stderr +++ b/src/test/ui/traits/trait-upcasting/type-checking-test-4.stderr @@ -36,12 +36,88 @@ LL | fn test_wrong3<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> { LL | let y = x as &dyn Bar<'_, '_>; | - ^^ | | - | ...is captured here... + | ...is used here... LL | LL | y.get_b() // ERROR - | --------- ...and is required to live as long as `'static` here + | - ...is used here... + | +note: ...and is required to live as long as `'static` here + --> $DIR/type-checking-test-4.rs:29:5 + | +LL | y.get_b() // ERROR + | ^^^^^^^^^ +note: `'static` lifetime requirement introduced by the return type + --> $DIR/type-checking-test-4.rs:26:48 + | +LL | fn test_wrong3<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> { + | ^^^^^^^ `'static` requirement introduced here +... +LL | y.get_b() // ERROR + | --------- because of this returned expression + +error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement + --> $DIR/type-checking-test-4.rs:33:5 + | +LL | fn test_wrong4<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> { + | ------------ this data with lifetime `'a`... +LL | <_ as Bar>::get_b(x) // ERROR + | ^^^^^^^^^^^^^^^^^ ...is used and required to live as long as `'static` here + | +note: `'static` lifetime requirement introduced by the return type + --> $DIR/type-checking-test-4.rs:32:48 + | +LL | fn test_wrong4<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> { + | ^^^^^^^ `'static` requirement introduced here +LL | <_ as Bar>::get_b(x) // ERROR + | -------------------- because of this returned expression + +error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement + --> $DIR/type-checking-test-4.rs:38:15 + | +LL | fn test_wrong5<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> { + | ------------ this data with lifetime `'a`... +LL | <_ as Bar<'_, '_>>::get_b(x) // ERROR + | ----------^^------------- ...is used and required to live as long as `'static` here + | +note: `'static` lifetime requirement introduced by the return type + --> $DIR/type-checking-test-4.rs:37:48 + | +LL | fn test_wrong5<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> { + | ^^^^^^^ `'static` requirement introduced here +LL | <_ as Bar<'_, '_>>::get_b(x) // ERROR + | ---------------------------- because of this returned expression + +error[E0759]: `x` has lifetime `'a` but it needs to satisfy a `'static` lifetime requirement + --> $DIR/type-checking-test-4.rs:43:27 + | +LL | fn test_wrong6<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> { + | ------------ this data with lifetime `'a`... +LL | let y = x as &dyn Bar<'_, '_>; + | - ^^ + | | + | ...is used here... +LL | +LL | y.get_b(); // ERROR + | - ...is used here... +LL | let z = y; +LL | z.get_b() // ERROR + | - ...is used here... + | +note: ...and is required to live as long as `'static` here + --> $DIR/type-checking-test-4.rs:47:5 + | +LL | z.get_b() // ERROR + | ^^^^^^^^^ +note: `'static` lifetime requirement introduced by the return type + --> $DIR/type-checking-test-4.rs:42:48 + | +LL | fn test_wrong6<'a>(x: &dyn Foo<'a>) -> Option<&'static u32> { + | ^^^^^^^ `'static` requirement introduced here +... +LL | z.get_b() // ERROR + | --------- because of this returned expression -error: aborting due to 3 previous errors +error: aborting due to 6 previous errors Some errors have detailed explanations: E0308, E0759. For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr b/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr index de3a6bbae1795..f4285a0f98e7c 100644 --- a/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr +++ b/src/test/ui/underscore-lifetime/dyn-trait-underscore.stderr @@ -5,8 +5,18 @@ LL | fn a(items: &[T]) -> Box> { | ---- this data with an anonymous lifetime `'_`... LL | // ^^^^^^^^^^^^^^^^^^^^^ bound *here* defaults to `'static` LL | Box::new(items.iter()) - | ---------------^^^^--- ...is captured and required to live as long as `'static` here + | ----- ^^^^ + | | + | ...is used and required to live as long as `'static` here | +note: `'static` lifetime requirement introduced by the return type + --> $DIR/dyn-trait-underscore.rs:6:29 + | +LL | fn a(items: &[T]) -> Box> { + | ^^^^^^^^^^^^^^^^^^^^^ `'static` requirement introduced here +LL | // ^^^^^^^^^^^^^^^^^^^^^ bound *here* defaults to `'static` +LL | Box::new(items.iter()) + | ---------------------- because of this returned expression help: to declare that the trait object captures data from argument `items`, you can add an explicit `'_` lifetime bound | LL | fn a(items: &[T]) -> Box + '_> {