Skip to content

Commit 1860072

Browse files
committed
make the c_variadic region late bound
1 parent c0bd2ec commit 1860072

4 files changed

Lines changed: 80 additions & 50 deletions

File tree

compiler/rustc_borrowck/src/universal_regions.rs

Lines changed: 64 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ use rustc_macros::extension;
2626
use rustc_middle::mir::RETURN_PLACE;
2727
use rustc_middle::ty::print::with_no_trimmed_paths;
2828
use rustc_middle::ty::{
29-
self, GenericArgs, GenericArgsRef, InlineConstArgs, InlineConstArgsParts, RegionExt, RegionVid,
30-
Ty, TyCtxt, TypeFoldable, TypeVisitableExt, fold_regions,
29+
self, BoundVariableKind, GenericArgs, GenericArgsRef, InlineConstArgs, InlineConstArgsParts,
30+
List, RegionExt, RegionVid, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, fold_regions,
3131
};
3232
use rustc_middle::{bug, span_bug};
3333
use rustc_span::{ErrorGuaranteed, kw, sym};
@@ -183,21 +183,52 @@ impl<'tcx> DefiningTy<'tcx> {
183183
}
184184
}
185185

186-
#[instrument(level = "debug", skip(tcx, c_variadic_region), ret)]
187-
fn inputs_and_output(
188-
self,
189-
tcx: TyCtxt<'tcx>,
190-
c_variadic_region: impl FnOnce() -> ty::Region<'tcx>,
191-
) -> ty::Binder<'tcx, &'tcx ty::List<Ty<'tcx>>> {
186+
/// The bound variables for a given defining type. This differs from their usual bound vars
187+
/// in that closures and coroutine closures have an additional `'env`, while C-variadic
188+
/// functions have an additional region for their implicit `VaList` input.
189+
pub(crate) fn bound_vars(self, tcx: TyCtxt<'tcx>) -> &'tcx List<BoundVariableKind<'tcx>> {
190+
match self {
191+
DefiningTy::Closure(_, args) => {
192+
let closure_sig = args.as_closure().sig();
193+
let inputs_and_output = closure_sig.inputs_and_output();
194+
tcx.mk_bound_variable_kinds_from_iter(inputs_and_output.bound_vars().iter().chain(
195+
iter::once(ty::BoundVariableKind::Region(ty::BoundRegionKind::ClosureEnv)),
196+
))
197+
}
198+
199+
DefiningTy::CoroutineClosure(_, args) => {
200+
let closure_sig = args.as_coroutine_closure().coroutine_closure_sig();
201+
tcx.mk_bound_variable_kinds_from_iter(closure_sig.bound_vars().iter().chain(
202+
iter::once(ty::BoundVariableKind::Region(ty::BoundRegionKind::ClosureEnv)),
203+
))
204+
}
205+
206+
DefiningTy::FnDef(def_id, _) => {
207+
let sig = tcx.fn_sig(def_id).instantiate_identity().skip_norm_wip();
208+
if sig.skip_binder().c_variadic() {
209+
// FIXME(#160495): Don't use an anonymous region here
210+
tcx.mk_bound_variable_kinds_from_iter(sig.bound_vars().iter().chain(
211+
iter::once(ty::BoundVariableKind::Region(ty::BoundRegionKind::Anon)),
212+
))
213+
} else {
214+
sig.bound_vars()
215+
}
216+
}
217+
218+
DefiningTy::Coroutine(..)
219+
| DefiningTy::Const(..)
220+
| DefiningTy::InlineConst(..)
221+
| DefiningTy::GlobalAsm(..) => ty::List::empty(),
222+
}
223+
}
224+
225+
#[instrument(level = "debug", skip(tcx), ret)]
226+
fn inputs_and_output(self, tcx: TyCtxt<'tcx>) -> ty::Binder<'tcx, &'tcx ty::List<Ty<'tcx>>> {
192227
match self {
193228
DefiningTy::Closure(def_id, args) => {
194229
let closure_sig = args.as_closure().sig();
195230
let inputs_and_output = closure_sig.inputs_and_output();
196-
let bound_vars = tcx.mk_bound_variable_kinds_from_iter(
197-
inputs_and_output.bound_vars().iter().chain(iter::once(
198-
ty::BoundVariableKind::Region(ty::BoundRegionKind::ClosureEnv),
199-
)),
200-
);
231+
let bound_vars = self.bound_vars(tcx);
201232
let br = ty::BoundRegion {
202233
var: ty::BoundVar::from_usize(bound_vars.len() - 1),
203234
kind: ty::BoundRegionKind::ClosureEnv,
@@ -245,10 +276,7 @@ impl<'tcx> DefiningTy<'tcx> {
245276
// Then we wrap it all up into a list of inputs and output.
246277
DefiningTy::CoroutineClosure(def_id, args) => {
247278
let closure_sig = args.as_coroutine_closure().coroutine_closure_sig();
248-
let bound_vars =
249-
tcx.mk_bound_variable_kinds_from_iter(closure_sig.bound_vars().iter().chain(
250-
iter::once(ty::BoundVariableKind::Region(ty::BoundRegionKind::ClosureEnv)),
251-
));
279+
let bound_vars = self.bound_vars(tcx);
252280
let br = ty::BoundRegion {
253281
var: ty::BoundVar::from_usize(bound_vars.len() - 1),
254282
kind: ty::BoundRegionKind::ClosureEnv,
@@ -290,17 +318,24 @@ impl<'tcx> DefiningTy<'tcx> {
290318
if tcx.fn_sig(def_id).skip_binder().c_variadic() {
291319
let va_list_did = tcx.require_lang_item(LangItem::VaList, tcx.def_span(def_id));
292320

293-
let region = c_variadic_region();
321+
let bound_vars = self.bound_vars(tcx);
322+
let br = ty::BoundRegion {
323+
var: ty::BoundVar::from_usize(bound_vars.len() - 1),
324+
kind: ty::BoundRegionKind::Anon,
325+
};
326+
let region = ty::Region::new_bound(tcx, ty::INNERMOST, br);
294327
let va_list_ty =
295328
tcx.type_of(va_list_did).instantiate(tcx, &[region.into()]).skip_norm_wip();
296329

297330
// The signature needs to follow the order [input_tys, va_list_ty, output_ty]
298-
return inputs_and_output.map_bound(|tys| {
299-
let (output_ty, input_tys) = tys.split_last().unwrap();
331+
let (output_ty, input_tys) =
332+
inputs_and_output.skip_binder().split_last().unwrap();
333+
return ty::Binder::bind_with_vars(
300334
tcx.mk_type_list_from_iter(
301335
input_tys.iter().copied().chain([va_list_ty, *output_ty]),
302-
)
303-
});
336+
),
337+
bound_vars,
338+
);
304339
}
305340

306341
inputs_and_output
@@ -678,7 +713,9 @@ impl<'tcx> UniversalRegionsBuilder<'_, 'tcx> {
678713
} else {
679714
// If this is a closure, coroutine, or inline-const, then the late-bound regions from the enclosing
680715
// function/closures are actually external regions to us. For example, here, 'a is not local
681-
// to the closure c (although it is local to the fn foo):
716+
// to the closure c (although it is local to the fn foo). We need to add them as they could be
717+
// explicitly named in this body:
718+
//
682719
// fn foo<'a>() {
683720
// let c = || { let x: &'a u32 = ...; }
684721
// }
@@ -708,8 +745,9 @@ impl<'tcx> UniversalRegionsBuilder<'_, 'tcx> {
708745
// on its signature are local.
709746
//
710747
// We manually loop over `bound_inputs_and_output` instead of using
711-
// `for_each_late_bound_region_in_item` as we may need to add the otherwise
712-
// implicit `ClosureEnv` region.
748+
// `for_each_late_bound_region_in_item` as both closures and function
749+
// definitions have implicit late bound regions. Closures have a `'env`
750+
// regions while c-variadic function definitions have a `&VaList` argument.
713751
let bound_inputs_and_output = self.compute_inputs_and_output(&indices, defining_ty);
714752
for (idx, bound_var) in bound_inputs_and_output.bound_vars().iter().enumerate() {
715753
if let ty::BoundVariableKind::Region(kind) = bound_var {
@@ -825,12 +863,7 @@ impl<'tcx> UniversalRegionsBuilder<'_, 'tcx> {
825863
defining_ty: DefiningTy<'tcx>,
826864
) -> ty::Binder<'tcx, &'tcx ty::List<Ty<'tcx>>> {
827865
let tcx = self.infcx.tcx;
828-
let inputs_and_output = defining_ty.inputs_and_output(tcx, || {
829-
self.infcx.next_nll_region_var(NllRegionVariableOrigin::FreeRegion, || {
830-
RegionCtxt::Free(sym::c_dash_variadic)
831-
})
832-
});
833-
866+
let inputs_and_output = defining_ty.inputs_and_output(tcx);
834867
let inputs_and_output = indices.fold_to_region_vids(tcx, inputs_and_output);
835868

836869
// FIXME(#129952): We probably want a more principled approach here.

tests/ui/c-variadic/not-async.stderr

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,21 +14,19 @@ error[E0700]: hidden type for `impl Future<Output = ()>` captures lifetime that
1414
--> $DIR/not-async.rs:4:65
1515
|
1616
LL | async unsafe extern "C" fn fn_cannot_be_async(x: isize, _: ...) {}
17-
| -^^
18-
| |
19-
| opaque type defined here
20-
|
21-
= note: hidden type `{async fn body of fn_cannot_be_async()}` captures lifetime `'_`
17+
| ----------------------------------------------------------------^^
18+
| | |
19+
| | opaque type defined here
20+
| hidden type `{async fn body of fn_cannot_be_async()}` captures the anonymous lifetime as defined here
2221

2322
error[E0700]: hidden type for `impl Future<Output = ()>` captures lifetime that does not appear in bounds
2423
--> $DIR/not-async.rs:11:73
2524
|
2625
LL | async unsafe extern "C" fn method_cannot_be_async(x: isize, _: ...) {}
27-
| -^^
28-
| |
29-
| opaque type defined here
30-
|
31-
= note: hidden type `{async fn body of S::method_cannot_be_async()}` captures lifetime `'_`
26+
| --------------------------------------------------------------------^^
27+
| | |
28+
| | opaque type defined here
29+
| hidden type `{async fn body of S::method_cannot_be_async()}` captures the anonymous lifetime as defined here
3230

3331
error: aborting due to 4 previous errors
3432

tests/ui/c-variadic/variadic-ffi-4.stderr

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,9 @@ error: lifetime may not live long enough
3030
--> $DIR/variadic-ffi-4.rs:21:5
3131
|
3232
LL | pub unsafe extern "C" fn no_escape4(_: usize, mut ap0: &mut VaList, mut ap1: ...) {
33-
| ------- ------- has type `VaList<'1>`
33+
| ------- ------- has type `VaList<'2>`
3434
| |
35-
| has type `&mut VaList<'2>`
35+
| has type `&mut VaList<'1>`
3636
LL | ap0 = &mut ap1;
3737
| ^^^^^^^^^^^^^^ assignment requires that `'1` must outlive `'2`
3838
|
@@ -44,9 +44,9 @@ error: lifetime may not live long enough
4444
--> $DIR/variadic-ffi-4.rs:21:5
4545
|
4646
LL | pub unsafe extern "C" fn no_escape4(_: usize, mut ap0: &mut VaList, mut ap1: ...) {
47-
| ------- ------- has type `VaList<'1>`
47+
| ------- ------- has type `VaList<'2>`
4848
| |
49-
| has type `&mut VaList<'2>`
49+
| has type `&mut VaList<'1>`
5050
LL | ap0 = &mut ap1;
5151
| ^^^^^^^^^^^^^^ assignment requires that `'2` must outlive `'1`
5252
|

tests/ui/inference/note-and-explain-ReVar-124973.stderr

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,10 @@ error[E0700]: hidden type for `impl Future<Output = ()>` captures lifetime that
88
--> $DIR/note-and-explain-ReVar-124973.rs:3:76
99
|
1010
LL | async unsafe extern "C" fn multiple_named_lifetimes<'a, 'b>(_: u8, _: ...) {}
11-
| -^^
12-
| |
13-
| opaque type defined here
14-
|
15-
= note: hidden type `{async fn body of multiple_named_lifetimes<'a, 'b>()}` captures lifetime `'_`
11+
| ---------------------------------------------------------------------------^^
12+
| | |
13+
| | opaque type defined here
14+
| hidden type `{async fn body of multiple_named_lifetimes<'a, 'b>()}` captures the anonymous lifetime as defined here
1615

1716
error: aborting due to 2 previous errors
1817

0 commit comments

Comments
 (0)