diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs index 2d4d98d812c65..3479224cc5546 100644 --- a/compiler/rustc_borrowck/src/universal_regions.rs +++ b/compiler/rustc_borrowck/src/universal_regions.rs @@ -26,8 +26,8 @@ use rustc_macros::extension; use rustc_middle::mir::RETURN_PLACE; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{ - self, GenericArgs, GenericArgsRef, InlineConstArgs, InlineConstArgsParts, RegionExt, RegionVid, - Ty, TyCtxt, TypeFoldable, TypeVisitableExt, fold_regions, + self, BoundVariableKind, GenericArgs, GenericArgsRef, InlineConstArgs, InlineConstArgsParts, + List, RegionExt, RegionVid, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, fold_regions, }; use rustc_middle::{bug, span_bug}; use rustc_span::{ErrorGuaranteed, kw, sym}; @@ -134,6 +134,231 @@ pub(crate) enum DefiningTy<'tcx> { } impl<'tcx> DefiningTy<'tcx> { + #[instrument(level = "debug", skip(tcx), ret)] + fn new(tcx: TyCtxt<'tcx>, body_def_id: LocalDefId) -> DefiningTy<'tcx> { + match tcx.hir_body_owner_kind(body_def_id) { + BodyOwnerKind::Closure | BodyOwnerKind::Fn => { + let defining_ty = tcx.type_of(body_def_id).instantiate_identity().skip_norm_wip(); + match *defining_ty.kind() { + ty::Closure(def_id, args) => DefiningTy::Closure(def_id, args), + ty::Coroutine(def_id, args) => DefiningTy::Coroutine(def_id, args), + ty::CoroutineClosure(def_id, args) => { + DefiningTy::CoroutineClosure(def_id, args) + } + ty::FnDef(def_id, args) => { + DefiningTy::FnDef(def_id, args.no_bound_vars().unwrap()) + } + _ => span_bug!( + tcx.def_span(body_def_id), + "expected defining type for `{body_def_id:?}`: `{defining_ty:?}`", + ), + } + } + + BodyOwnerKind::Const { inline: true } => { + // This is required for `AscribeUserType` canonical query, which will call + // `type_of(inline_const_def_id)`. That `type_of` would inject erased lifetimes + // into borrowck, which is ICE #78174. + // + // As a workaround, inline consts have an additional generic param (`ty` + // below), so that `type_of(inline_const_def_id).substs(substs)` uses the + // proper type with NLL infer vars. + // + // Fetch the actual type from MIR, as `type_of` returns something useless + // like ``. + let body = tcx.mir_promoted(body_def_id).0.borrow(); + let ty = body.local_decls[RETURN_PLACE].ty; + let typeck_root_def_id = tcx.typeck_root_def_id(body_def_id.to_def_id()); + let parent_args = GenericArgs::identity_for_item(tcx, typeck_root_def_id); + let args = InlineConstArgs::new(tcx, InlineConstArgsParts { parent_args, ty }).args; + DefiningTy::InlineConst(body_def_id.to_def_id(), args) + } + + BodyOwnerKind::Const { inline: false } | BodyOwnerKind::Static(..) => { + let args = GenericArgs::identity_for_item(tcx, body_def_id.to_def_id()); + DefiningTy::Const(body_def_id.to_def_id(), args) + } + + BodyOwnerKind::GlobalAsm => DefiningTy::GlobalAsm(body_def_id.to_def_id()), + } + } + + /// The bound variables for a given defining type. This differs from their usual bound vars + /// in that closures and coroutine closures have an additional `'env`, while C-variadic + /// functions have an additional region for their implicit `VaList` input. + pub(crate) fn bound_vars(self, tcx: TyCtxt<'tcx>) -> &'tcx List> { + match self { + DefiningTy::Closure(_, args) => { + let closure_sig = args.as_closure().sig(); + let inputs_and_output = closure_sig.inputs_and_output(); + tcx.mk_bound_variable_kinds_from_iter(inputs_and_output.bound_vars().iter().chain( + iter::once(ty::BoundVariableKind::Region(ty::BoundRegionKind::ClosureEnv)), + )) + } + + DefiningTy::CoroutineClosure(_, args) => { + let closure_sig = args.as_coroutine_closure().coroutine_closure_sig(); + tcx.mk_bound_variable_kinds_from_iter(closure_sig.bound_vars().iter().chain( + iter::once(ty::BoundVariableKind::Region(ty::BoundRegionKind::ClosureEnv)), + )) + } + + DefiningTy::FnDef(def_id, _) => { + let sig = tcx.fn_sig(def_id).instantiate_identity().skip_norm_wip(); + if sig.skip_binder().c_variadic() { + // FIXME(#160495): Don't use an anonymous region here + tcx.mk_bound_variable_kinds_from_iter(sig.bound_vars().iter().chain( + iter::once(ty::BoundVariableKind::Region(ty::BoundRegionKind::Anon)), + )) + } else { + sig.bound_vars() + } + } + + DefiningTy::Coroutine(..) + | DefiningTy::Const(..) + | DefiningTy::InlineConst(..) + | DefiningTy::GlobalAsm(..) => ty::List::empty(), + } + } + + #[instrument(level = "debug", skip(tcx), ret)] + fn inputs_and_output(self, tcx: TyCtxt<'tcx>) -> ty::Binder<'tcx, &'tcx ty::List>> { + match self { + DefiningTy::Closure(def_id, args) => { + let closure_sig = args.as_closure().sig(); + let inputs_and_output = closure_sig.inputs_and_output(); + let bound_vars = self.bound_vars(tcx); + let br = ty::BoundRegion { + var: ty::BoundVar::from_usize(bound_vars.len() - 1), + kind: ty::BoundRegionKind::ClosureEnv, + }; + let env_region = ty::Region::new_bound(tcx, ty::INNERMOST, br); + let closure_ty = tcx.closure_env_ty( + Ty::new_closure(tcx, def_id, args), + args.as_closure().kind(), + env_region, + ); + + // The "inputs" of the closure in the + // signature appear as a tuple. The MIR side + // flattens this tuple. + let (&output, tuplized_inputs) = + inputs_and_output.skip_binder().split_last().unwrap(); + assert_eq!(tuplized_inputs.len(), 1, "multiple closure inputs"); + let &ty::Tuple(inputs) = tuplized_inputs[0].kind() else { + bug!("closure inputs not a tuple: {:?}", tuplized_inputs[0]); + }; + + ty::Binder::bind_with_vars( + tcx.mk_type_list_from_iter( + iter::once(closure_ty).chain(inputs).chain(iter::once(output)), + ), + bound_vars, + ) + } + + DefiningTy::Coroutine(def_id, args) => { + let resume_ty = args.as_coroutine().resume_ty(); + let output = args.as_coroutine().return_ty(); + let coroutine_ty = Ty::new_coroutine(tcx, def_id, args); + let inputs_and_output = tcx.mk_type_list(&[coroutine_ty, resume_ty, output]); + ty::Binder::dummy(inputs_and_output) + } + + // Construct the signature of the CoroutineClosure for the purposes of borrowck. + // This is pretty straightforward -- we: + // 1. first grab the `coroutine_closure_sig`, + // 2. compute the self type (`&`/`&mut`/no borrow), + // 3. flatten the tupled_input_tys, + // 4. construct the correct generator type to return with + // `CoroutineClosureSignature::to_coroutine_given_kind_and_upvars`. + // Then we wrap it all up into a list of inputs and output. + DefiningTy::CoroutineClosure(def_id, args) => { + let closure_sig = args.as_coroutine_closure().coroutine_closure_sig(); + let bound_vars = self.bound_vars(tcx); + let br = ty::BoundRegion { + var: ty::BoundVar::from_usize(bound_vars.len() - 1), + kind: ty::BoundRegionKind::ClosureEnv, + }; + let env_region = ty::Region::new_bound(tcx, ty::INNERMOST, br); + let closure_kind = args.as_coroutine_closure().kind(); + + let closure_ty = tcx.closure_env_ty( + Ty::new_coroutine_closure(tcx, def_id, args), + closure_kind, + env_region, + ); + + let inputs = closure_sig.skip_binder().tupled_inputs_ty.tuple_fields(); + let output = closure_sig.skip_binder().to_coroutine_given_kind_and_upvars( + tcx, + args.as_coroutine_closure().parent_args(), + tcx.coroutine_for_closure(def_id), + closure_kind, + env_region, + args.as_coroutine_closure().tupled_upvars_ty(), + args.as_coroutine_closure().coroutine_captures_by_ref_ty(), + ); + + ty::Binder::bind_with_vars( + tcx.mk_type_list_from_iter( + iter::once(closure_ty).chain(inputs).chain(iter::once(output)), + ), + bound_vars, + ) + } + + DefiningTy::FnDef(def_id, _) => { + let sig = tcx.fn_sig(def_id).instantiate_identity().skip_norm_wip(); + let inputs_and_output = sig.inputs_and_output(); + + // C-variadic fns also have a `VaList` input that's not listed in the signature + // (as it's created inside the body itself, not passed in from outside). + if tcx.fn_sig(def_id).skip_binder().c_variadic() { + let va_list_did = tcx.require_lang_item(LangItem::VaList, tcx.def_span(def_id)); + + let bound_vars = self.bound_vars(tcx); + let br = ty::BoundRegion { + var: ty::BoundVar::from_usize(bound_vars.len() - 1), + kind: ty::BoundRegionKind::Anon, + }; + let region = ty::Region::new_bound(tcx, ty::INNERMOST, br); + let va_list_ty = + tcx.type_of(va_list_did).instantiate(tcx, &[region.into()]).skip_norm_wip(); + + // The signature needs to follow the order [input_tys, va_list_ty, output_ty] + let (output_ty, input_tys) = + inputs_and_output.skip_binder().split_last().unwrap(); + return ty::Binder::bind_with_vars( + tcx.mk_type_list_from_iter( + input_tys.iter().copied().chain([va_list_ty, *output_ty]), + ), + bound_vars, + ); + } + + inputs_and_output + } + + DefiningTy::Const(def_id, _) => { + // For a constant body, there are no inputs, and one + // "output" (the type of the constant). + let ty = tcx.type_of(def_id).instantiate_identity().skip_norm_wip(); + ty::Binder::dummy(tcx.mk_type_list(&[ty])) + } + + DefiningTy::InlineConst(_def_id, args) => { + let ty = args.as_inline_const().ty(); + ty::Binder::dummy(tcx.mk_type_list(&[ty])) + } + + DefiningTy::GlobalAsm(def_id) => ty::Binder::dummy( + tcx.mk_type_list(&[tcx.type_of(def_id).instantiate_identity().skip_norm_wip()]), + ), + } + } + /// Returns a list of all the upvar types for this MIR. If this is /// not a closure or coroutine, there are no upvars, and hence it /// will be an empty list. The order of types in this list will @@ -488,7 +713,9 @@ impl<'tcx> UniversalRegionsBuilder<'_, 'tcx> { } else { // If this is a closure, coroutine, or inline-const, then the late-bound regions from the enclosing // function/closures are actually external regions to us. For example, here, 'a is not local - // to the closure c (although it is local to the fn foo): + // to the closure c (although it is local to the fn foo). We need to add them as they could be + // explicitly named in this body: + // // fn foo<'a>() { // let c = || { let x: &'a u32 = ...; } // } @@ -518,8 +745,9 @@ impl<'tcx> UniversalRegionsBuilder<'_, 'tcx> { // on its signature are local. // // We manually loop over `bound_inputs_and_output` instead of using - // `for_each_late_bound_region_in_item` as we may need to add the otherwise - // implicit `ClosureEnv` region. + // `for_each_late_bound_region_in_item` as both closures and function + // definitions have implicit late bound regions. Closures have a `'env` + // regions while c-variadic function definitions have a `&VaList` argument. let bound_inputs_and_output = self.compute_inputs_and_output(&indices, defining_ty); for (idx, bound_var) in bound_inputs_and_output.bound_vars().iter().enumerate() { if let ty::BoundVariableKind::Region(kind) = bound_var { @@ -581,82 +809,23 @@ impl<'tcx> UniversalRegionsBuilder<'_, 'tcx> { } } - /// Returns the "defining type" of the current MIR; - /// see `DefiningTy` for details. + /// Returns the "defining type" of the current MIR; see `DefiningTy` for details. fn defining_ty(&self) -> DefiningTy<'tcx> { - let tcx = self.infcx.tcx; - - match tcx.hir_body_owner_kind(self.mir_def) { - BodyOwnerKind::Closure | BodyOwnerKind::Fn => { - let defining_ty = tcx.type_of(self.mir_def).instantiate_identity().skip_norm_wip(); - - debug!("defining_ty (pre-replacement): {:?}", defining_ty); - - let defining_ty = self.infcx.replace_free_regions_with_nll_infer_vars( - NllRegionVariableOrigin::FreeRegion, - defining_ty, - ); - - match *defining_ty.kind() { - ty::Closure(def_id, args) => DefiningTy::Closure(def_id, args), - ty::Coroutine(def_id, args) => DefiningTy::Coroutine(def_id, args), - ty::CoroutineClosure(def_id, args) => { - DefiningTy::CoroutineClosure(def_id, args) - } - ty::FnDef(def_id, args) => { - DefiningTy::FnDef(def_id, args.no_bound_vars().unwrap()) - } - _ => span_bug!( - tcx.def_span(self.mir_def), - "expected defining type for `{:?}`: `{:?}`", - self.mir_def, - defining_ty - ), - } - } - - BodyOwnerKind::Const { .. } | BodyOwnerKind::Static(..) => { - match tcx.def_kind(self.mir_def) { - DefKind::AnonConst - if tcx.anon_const_kind(self.mir_def) - == ty::AnonConstKind::NonTypeSystemInline => - { - // This is required for `AscribeUserType` canonical query, which will call - // `type_of(inline_const_def_id)`. That `type_of` would inject erased lifetimes - // into borrowck, which is ICE #78174. - // - // As a workaround, inline consts have an additional generic param (`ty` - // below), so that `type_of(inline_const_def_id).substs(substs)` uses the - // proper type with NLL infer vars. - // - // Fetch the actual type from MIR, as `type_of` returns something useless - // like ``. - let body = tcx.mir_promoted(self.mir_def).0.borrow(); - let ty = body.local_decls[RETURN_PLACE].ty; - let typeck_root_def_id = tcx.typeck_root_def_id(self.mir_def.to_def_id()); - let parent_args = GenericArgs::identity_for_item(tcx, typeck_root_def_id); - let args = - InlineConstArgs::new(tcx, InlineConstArgsParts { parent_args, ty }) - .args; - let args = self.infcx.replace_free_regions_with_nll_infer_vars( - NllRegionVariableOrigin::FreeRegion, - args, - ); - DefiningTy::InlineConst(self.mir_def.to_def_id(), args) - } - _ => { - let identity_args = - GenericArgs::identity_for_item(tcx, self.mir_def.to_def_id()); - let args = self.infcx.replace_free_regions_with_nll_infer_vars( - NllRegionVariableOrigin::FreeRegion, - identity_args, - ); - DefiningTy::Const(self.mir_def.to_def_id(), args) - } - } + let defining_ty = DefiningTy::new(self.infcx.tcx, self.mir_def); + let f = |args| { + let fr = NllRegionVariableOrigin::FreeRegion; + self.infcx.replace_free_regions_with_nll_infer_vars(fr, args) + }; + match defining_ty { + DefiningTy::Closure(def_id, args) => DefiningTy::Closure(def_id, f(args)), + DefiningTy::Coroutine(def_id, args) => DefiningTy::Coroutine(def_id, f(args)), + DefiningTy::CoroutineClosure(def_id, args) => { + DefiningTy::CoroutineClosure(def_id, f(args)) } - - BodyOwnerKind::GlobalAsm => DefiningTy::GlobalAsm(self.mir_def.to_def_id()), + DefiningTy::FnDef(def_id, args) => DefiningTy::FnDef(def_id, f(args)), + DefiningTy::Const(def_id, args) => DefiningTy::Const(def_id, f(args)), + DefiningTy::InlineConst(def_id, args) => DefiningTy::InlineConst(def_id, f(args)), + DefiningTy::GlobalAsm(def_id) => DefiningTy::GlobalAsm(def_id), } } @@ -694,163 +863,8 @@ impl<'tcx> UniversalRegionsBuilder<'_, 'tcx> { defining_ty: DefiningTy<'tcx>, ) -> ty::Binder<'tcx, &'tcx ty::List>> { let tcx = self.infcx.tcx; - - let inputs_and_output = match defining_ty { - DefiningTy::Closure(def_id, args) => { - assert_eq!(self.mir_def.to_def_id(), def_id); - let closure_sig = args.as_closure().sig(); - let inputs_and_output = closure_sig.inputs_and_output(); - let bound_vars = tcx.mk_bound_variable_kinds_from_iter( - inputs_and_output.bound_vars().iter().chain(iter::once( - ty::BoundVariableKind::Region(ty::BoundRegionKind::ClosureEnv), - )), - ); - let br = ty::BoundRegion { - var: ty::BoundVar::from_usize(bound_vars.len() - 1), - kind: ty::BoundRegionKind::ClosureEnv, - }; - let env_region = ty::Region::new_bound(tcx, ty::INNERMOST, br); - let closure_ty = tcx.closure_env_ty( - Ty::new_closure(tcx, def_id, args), - args.as_closure().kind(), - env_region, - ); - - // The "inputs" of the closure in the - // signature appear as a tuple. The MIR side - // flattens this tuple. - let (&output, tuplized_inputs) = - inputs_and_output.skip_binder().split_last().unwrap(); - assert_eq!(tuplized_inputs.len(), 1, "multiple closure inputs"); - let &ty::Tuple(inputs) = tuplized_inputs[0].kind() else { - bug!("closure inputs not a tuple: {:?}", tuplized_inputs[0]); - }; - - ty::Binder::bind_with_vars( - tcx.mk_type_list_from_iter( - iter::once(closure_ty).chain(inputs).chain(iter::once(output)), - ), - bound_vars, - ) - } - - DefiningTy::Coroutine(def_id, args) => { - assert_eq!(self.mir_def.to_def_id(), def_id); - let resume_ty = args.as_coroutine().resume_ty(); - let output = args.as_coroutine().return_ty(); - let coroutine_ty = Ty::new_coroutine(tcx, def_id, args); - let inputs_and_output = - self.infcx.tcx.mk_type_list(&[coroutine_ty, resume_ty, output]); - ty::Binder::dummy(inputs_and_output) - } - - // Construct the signature of the CoroutineClosure for the purposes of borrowck. - // This is pretty straightforward -- we: - // 1. first grab the `coroutine_closure_sig`, - // 2. compute the self type (`&`/`&mut`/no borrow), - // 3. flatten the tupled_input_tys, - // 4. construct the correct generator type to return with - // `CoroutineClosureSignature::to_coroutine_given_kind_and_upvars`. - // Then we wrap it all up into a list of inputs and output. - DefiningTy::CoroutineClosure(def_id, args) => { - assert_eq!(self.mir_def.to_def_id(), def_id); - let closure_sig = args.as_coroutine_closure().coroutine_closure_sig(); - let bound_vars = - tcx.mk_bound_variable_kinds_from_iter(closure_sig.bound_vars().iter().chain( - iter::once(ty::BoundVariableKind::Region(ty::BoundRegionKind::ClosureEnv)), - )); - let br = ty::BoundRegion { - var: ty::BoundVar::from_usize(bound_vars.len() - 1), - kind: ty::BoundRegionKind::ClosureEnv, - }; - let env_region = ty::Region::new_bound(tcx, ty::INNERMOST, br); - let closure_kind = args.as_coroutine_closure().kind(); - - let closure_ty = tcx.closure_env_ty( - Ty::new_coroutine_closure(tcx, def_id, args), - closure_kind, - env_region, - ); - - let inputs = closure_sig.skip_binder().tupled_inputs_ty.tuple_fields(); - let output = closure_sig.skip_binder().to_coroutine_given_kind_and_upvars( - tcx, - args.as_coroutine_closure().parent_args(), - tcx.coroutine_for_closure(def_id), - closure_kind, - env_region, - args.as_coroutine_closure().tupled_upvars_ty(), - args.as_coroutine_closure().coroutine_captures_by_ref_ty(), - ); - - ty::Binder::bind_with_vars( - tcx.mk_type_list_from_iter( - iter::once(closure_ty).chain(inputs).chain(iter::once(output)), - ), - bound_vars, - ) - } - - DefiningTy::FnDef(def_id, _) => { - let sig = tcx.fn_sig(def_id).instantiate_identity().skip_norm_wip(); - let sig = indices.fold_to_region_vids(tcx, sig); - let inputs_and_output = sig.inputs_and_output(); - - // C-variadic fns also have a `VaList` input that's not listed in the signature - // (as it's created inside the body itself, not passed in from outside). - if self.infcx.tcx.fn_sig(def_id).skip_binder().c_variadic() { - let va_list_did = self - .infcx - .tcx - .require_lang_item(LangItem::VaList, self.infcx.tcx.def_span(self.mir_def)); - - let reg_vid = self - .infcx - .next_nll_region_var(NllRegionVariableOrigin::FreeRegion, || { - RegionCtxt::Free(sym::c_dash_variadic) - }) - .as_var(); - - let region = ty::Region::new_var(self.infcx.tcx, reg_vid); - let va_list_ty = self - .infcx - .tcx - .type_of(va_list_did) - .instantiate(self.infcx.tcx, &[region.into()]) - .skip_norm_wip(); - - // The signature needs to follow the order [input_tys, va_list_ty, output_ty] - return inputs_and_output.map_bound(|tys| { - let (output_ty, input_tys) = tys.split_last().unwrap(); - tcx.mk_type_list_from_iter( - input_tys.iter().copied().chain([va_list_ty, *output_ty]), - ) - }); - } - - inputs_and_output - } - - DefiningTy::Const(def_id, _) => { - // For a constant body, there are no inputs, and one - // "output" (the type of the constant). - assert_eq!(self.mir_def.to_def_id(), def_id); - let ty = tcx.type_of(self.mir_def).instantiate_identity().skip_norm_wip(); - - let ty = indices.fold_to_region_vids(tcx, ty); - ty::Binder::dummy(tcx.mk_type_list(&[ty])) - } - - DefiningTy::InlineConst(def_id, args) => { - assert_eq!(self.mir_def.to_def_id(), def_id); - let ty = args.as_inline_const().ty(); - ty::Binder::dummy(tcx.mk_type_list(&[ty])) - } - - DefiningTy::GlobalAsm(def_id) => ty::Binder::dummy( - tcx.mk_type_list(&[tcx.type_of(def_id).instantiate_identity().skip_norm_wip()]), - ), - }; + let inputs_and_output = defining_ty.inputs_and_output(tcx); + let inputs_and_output = indices.fold_to_region_vids(tcx, inputs_and_output); // FIXME(#129952): We probably want a more principled approach here. if let Err(e) = inputs_and_output.error_reported() { diff --git a/tests/ui/c-variadic/not-async.stderr b/tests/ui/c-variadic/not-async.stderr index 921210382236c..9a81e0ce270d6 100644 --- a/tests/ui/c-variadic/not-async.stderr +++ b/tests/ui/c-variadic/not-async.stderr @@ -14,21 +14,19 @@ error[E0700]: hidden type for `impl Future` captures lifetime that --> $DIR/not-async.rs:4:65 | LL | async unsafe extern "C" fn fn_cannot_be_async(x: isize, _: ...) {} - | -^^ - | | - | opaque type defined here - | - = note: hidden type `{async fn body of fn_cannot_be_async()}` captures lifetime `'_` + | ----------------------------------------------------------------^^ + | | | + | | opaque type defined here + | hidden type `{async fn body of fn_cannot_be_async()}` captures the anonymous lifetime as defined here error[E0700]: hidden type for `impl Future` captures lifetime that does not appear in bounds --> $DIR/not-async.rs:11:73 | LL | async unsafe extern "C" fn method_cannot_be_async(x: isize, _: ...) {} - | -^^ - | | - | opaque type defined here - | - = note: hidden type `{async fn body of S::method_cannot_be_async()}` captures lifetime `'_` + | --------------------------------------------------------------------^^ + | | | + | | opaque type defined here + | hidden type `{async fn body of S::method_cannot_be_async()}` captures the anonymous lifetime as defined here error: aborting due to 4 previous errors diff --git a/tests/ui/c-variadic/variadic-ffi-4.stderr b/tests/ui/c-variadic/variadic-ffi-4.stderr index d53f1f527748c..a92a5fd4bf61d 100644 --- a/tests/ui/c-variadic/variadic-ffi-4.stderr +++ b/tests/ui/c-variadic/variadic-ffi-4.stderr @@ -30,9 +30,9 @@ error: lifetime may not live long enough --> $DIR/variadic-ffi-4.rs:21:5 | LL | pub unsafe extern "C" fn no_escape4(_: usize, mut ap0: &mut VaList, mut ap1: ...) { - | ------- ------- has type `VaList<'1>` + | ------- ------- has type `VaList<'2>` | | - | has type `&mut VaList<'2>` + | has type `&mut VaList<'1>` LL | ap0 = &mut ap1; | ^^^^^^^^^^^^^^ assignment requires that `'1` must outlive `'2` | @@ -44,9 +44,9 @@ error: lifetime may not live long enough --> $DIR/variadic-ffi-4.rs:21:5 | LL | pub unsafe extern "C" fn no_escape4(_: usize, mut ap0: &mut VaList, mut ap1: ...) { - | ------- ------- has type `VaList<'1>` + | ------- ------- has type `VaList<'2>` | | - | has type `&mut VaList<'2>` + | has type `&mut VaList<'1>` LL | ap0 = &mut ap1; | ^^^^^^^^^^^^^^ assignment requires that `'2` must outlive `'1` | diff --git a/tests/ui/inference/note-and-explain-ReVar-124973.stderr b/tests/ui/inference/note-and-explain-ReVar-124973.stderr index 3610fa82754b9..3ba76eb2ece18 100644 --- a/tests/ui/inference/note-and-explain-ReVar-124973.stderr +++ b/tests/ui/inference/note-and-explain-ReVar-124973.stderr @@ -8,11 +8,10 @@ error[E0700]: hidden type for `impl Future` captures lifetime that --> $DIR/note-and-explain-ReVar-124973.rs:3:76 | LL | async unsafe extern "C" fn multiple_named_lifetimes<'a, 'b>(_: u8, _: ...) {} - | -^^ - | | - | opaque type defined here - | - = note: hidden type `{async fn body of multiple_named_lifetimes<'a, 'b>()}` captures lifetime `'_` + | ---------------------------------------------------------------------------^^ + | | | + | | opaque type defined here + | hidden type `{async fn body of multiple_named_lifetimes<'a, 'b>()}` captures the anonymous lifetime as defined here error: aborting due to 2 previous errors