Skip to content

Commit efd3583

Browse files
committed
Auto merge of #99300 - Mark-Simulacrum:beta-next, r=Mark-Simulacrum
[beta] rollup * Fix sized check ICE in asm check #99124 * Windows: Fallback for overlapped I/O #98950 * promote placeholder bounds to 'static obligations #98713 * Create fresh lifetime parameters for bare fn trait too #98637 r? `@Mark-Simulacrum`
2 parents 93ef0cd + f0227e8 commit efd3583

File tree

17 files changed

+377
-35
lines changed

17 files changed

+377
-35
lines changed

compiler/rustc_ast_lowering/src/lib.rs

+27
Original file line numberDiff line numberDiff line change
@@ -1174,6 +1174,33 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
11741174
param_mode: ParamMode,
11751175
itctx: ImplTraitContext,
11761176
) -> hir::Ty<'hir> {
1177+
// Check whether we should interpret this as a bare trait object.
1178+
// This check mirrors the one in late resolution. We only introduce this special case in
1179+
// the rare occurence we need to lower `Fresh` anonymous lifetimes.
1180+
// The other cases when a qpath should be opportunistically made a trait object are handled
1181+
// by `ty_path`.
1182+
if qself.is_none()
1183+
&& let Some(partial_res) = self.resolver.get_partial_res(t.id)
1184+
&& partial_res.unresolved_segments() == 0
1185+
&& let Res::Def(DefKind::Trait | DefKind::TraitAlias, _) = partial_res.base_res()
1186+
{
1187+
let (bounds, lifetime_bound) = self.with_dyn_type_scope(true, |this| {
1188+
let bound = this.lower_poly_trait_ref(
1189+
&PolyTraitRef {
1190+
bound_generic_params: vec![],
1191+
trait_ref: TraitRef { path: path.clone(), ref_id: t.id },
1192+
span: t.span
1193+
},
1194+
itctx,
1195+
);
1196+
let bounds = this.arena.alloc_from_iter([bound]);
1197+
let lifetime_bound = this.elided_dyn_bound(t.span);
1198+
(bounds, lifetime_bound)
1199+
});
1200+
let kind = hir::TyKind::TraitObject(bounds, lifetime_bound, TraitObjectSyntax::None);
1201+
return hir::Ty { kind, span: self.lower_span(t.span), hir_id: self.next_id() };
1202+
}
1203+
11771204
let id = self.lower_node_id(t.id);
11781205
let qpath = self.lower_qpath(t.id, qself, path, param_mode, itctx);
11791206
self.ty_path(id, t.span, qpath)

compiler/rustc_borrowck/src/region_infer/mod.rs

+33-5
Original file line numberDiff line numberDiff line change
@@ -916,6 +916,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
916916
/// The idea then is to lower the `T: 'X` constraint into multiple
917917
/// bounds -- e.g., if `'X` is the union of two free lifetimes,
918918
/// `'1` and `'2`, then we would create `T: '1` and `T: '2`.
919+
#[instrument(level = "debug", skip(self, infcx, propagated_outlives_requirements))]
919920
fn try_promote_type_test(
920921
&self,
921922
infcx: &InferCtxt<'_, 'tcx>,
@@ -933,11 +934,41 @@ impl<'tcx> RegionInferenceContext<'tcx> {
933934
return false;
934935
};
935936

937+
debug!("subject = {:?}", subject);
938+
939+
let r_scc = self.constraint_sccs.scc(*lower_bound);
940+
941+
debug!(
942+
"lower_bound = {:?} r_scc={:?} universe={:?}",
943+
lower_bound, r_scc, self.scc_universes[r_scc]
944+
);
945+
946+
// If the type test requires that `T: 'a` where `'a` is a
947+
// placeholder from another universe, that effectively requires
948+
// `T: 'static`, so we have to propagate that requirement.
949+
//
950+
// It doesn't matter *what* universe because the promoted `T` will
951+
// always be in the root universe.
952+
if let Some(p) = self.scc_values.placeholders_contained_in(r_scc).next() {
953+
debug!("encountered placeholder in higher universe: {:?}, requiring 'static", p);
954+
let static_r = self.universal_regions.fr_static;
955+
propagated_outlives_requirements.push(ClosureOutlivesRequirement {
956+
subject,
957+
outlived_free_region: static_r,
958+
blame_span: locations.span(body),
959+
category: ConstraintCategory::Boring,
960+
});
961+
962+
// we can return here -- the code below might push add'l constraints
963+
// but they would all be weaker than this one.
964+
return true;
965+
}
966+
936967
// For each region outlived by lower_bound find a non-local,
937968
// universal region (it may be the same region) and add it to
938969
// `ClosureOutlivesRequirement`.
939-
let r_scc = self.constraint_sccs.scc(*lower_bound);
940970
for ur in self.scc_values.universal_regions_outlived_by(r_scc) {
971+
debug!("universal_region_outlived_by ur={:?}", ur);
941972
// Check whether we can already prove that the "subject" outlives `ur`.
942973
// If so, we don't have to propagate this requirement to our caller.
943974
//
@@ -962,8 +993,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
962993
continue;
963994
}
964995

965-
debug!("try_promote_type_test: ur={:?}", ur);
966-
967996
let non_local_ub = self.universal_region_relations.non_local_upper_bounds(ur);
968997
debug!("try_promote_type_test: non_local_ub={:?}", non_local_ub);
969998

@@ -1000,15 +1029,14 @@ impl<'tcx> RegionInferenceContext<'tcx> {
10001029
/// will use it's *external name*, which will be a `RegionKind`
10011030
/// variant that can be used in query responses such as
10021031
/// `ReEarlyBound`.
1032+
#[instrument(level = "debug", skip(self, infcx))]
10031033
fn try_promote_type_test_subject(
10041034
&self,
10051035
infcx: &InferCtxt<'_, 'tcx>,
10061036
ty: Ty<'tcx>,
10071037
) -> Option<ClosureOutlivesSubject<'tcx>> {
10081038
let tcx = infcx.tcx;
10091039

1010-
debug!("try_promote_type_test_subject(ty = {:?})", ty);
1011-
10121040
let ty = tcx.fold_regions(ty, &mut false, |r, _depth| {
10131041
let region_vid = self.to_region_vid(r);
10141042

compiler/rustc_resolve/src/late.rs

+24
Original file line numberDiff line numberDiff line change
@@ -611,6 +611,30 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
611611
TyKind::Path(ref qself, ref path) => {
612612
self.diagnostic_metadata.current_type_path = Some(ty);
613613
self.smart_resolve_path(ty.id, qself.as_ref(), path, PathSource::Type);
614+
615+
// Check whether we should interpret this as a bare trait object.
616+
if qself.is_none()
617+
&& let Some(partial_res) = self.r.partial_res_map.get(&ty.id)
618+
&& partial_res.unresolved_segments() == 0
619+
&& let Res::Def(DefKind::Trait | DefKind::TraitAlias, _) = partial_res.base_res()
620+
{
621+
// This path is actually a bare trait object. In case of a bare `Fn`-trait
622+
// object with anonymous lifetimes, we need this rib to correctly place the
623+
// synthetic lifetimes.
624+
let span = ty.span.shrink_to_lo().to(path.span.shrink_to_lo());
625+
self.with_generic_param_rib(
626+
&[],
627+
NormalRibKind,
628+
LifetimeRibKind::Generics {
629+
binder: ty.id,
630+
kind: LifetimeBinderKind::PolyTrait,
631+
span,
632+
},
633+
|this| this.visit_path(&path, ty.id),
634+
);
635+
self.diagnostic_metadata.current_type_path = prev_ty;
636+
return;
637+
}
614638
}
615639
TyKind::ImplicitSelf => {
616640
let self_ty = Ident::with_dummy_span(kw::SelfUpper);

compiler/rustc_typeck/src/check/intrinsicck.rs

+13-21
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use rustc_errors::struct_span_err;
44
use rustc_hir as hir;
55
use rustc_index::vec::Idx;
66
use rustc_middle::ty::layout::{LayoutError, SizeSkeleton};
7-
use rustc_middle::ty::{self, Article, FloatTy, InferTy, IntTy, Ty, TyCtxt, TypeFoldable, UintTy};
7+
use rustc_middle::ty::{self, Article, FloatTy, IntTy, Ty, TyCtxt, TypeFoldable, UintTy};
88
use rustc_session::lint;
99
use rustc_span::{Span, Symbol, DUMMY_SP};
1010
use rustc_target::abi::{Pointer, VariantIdx};
@@ -99,8 +99,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
9999
err.emit();
100100
}
101101

102+
// FIXME(compiler-errors): This could use `<$ty as Pointee>::Metadata == ()`
102103
fn is_thin_ptr_ty(&self, ty: Ty<'tcx>) -> bool {
103-
if ty.is_sized(self.tcx.at(DUMMY_SP), self.param_env) {
104+
// Type still may have region variables, but `Sized` does not depend
105+
// on those, so just erase them before querying.
106+
if self.tcx.erase_regions(ty).is_sized(self.tcx.at(DUMMY_SP), self.param_env) {
104107
return true;
105108
}
106109
if let ty::Foreign(..) = ty.kind() {
@@ -128,30 +131,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
128131
64 => InlineAsmType::I64,
129132
_ => unreachable!(),
130133
};
134+
135+
// Expect types to be fully resolved, no const or type variables.
136+
if ty.has_infer_types_or_consts() {
137+
assert!(self.is_tainted_by_errors());
138+
return None;
139+
}
140+
131141
let asm_ty = match *ty.kind() {
132142
// `!` is allowed for input but not for output (issue #87802)
133143
ty::Never if is_input => return None,
134144
ty::Error(_) => return None,
135145
ty::Int(IntTy::I8) | ty::Uint(UintTy::U8) => Some(InlineAsmType::I8),
136146
ty::Int(IntTy::I16) | ty::Uint(UintTy::U16) => Some(InlineAsmType::I16),
137-
// Somewhat of a hack: fallback in the presence of errors does not actually
138-
// fall back to i32, but to ty::Error. For integer inference variables this
139-
// means that they don't get any fallback and stay as `{integer}`.
140-
// Since compilation can't succeed anyway, it's fine to use this to avoid printing
141-
// "cannot use value of type `{integer}`", even though that would absolutely
142-
// work due due i32 fallback if the current function had no other errors.
143-
ty::Infer(InferTy::IntVar(_)) => {
144-
assert!(self.is_tainted_by_errors());
145-
Some(InlineAsmType::I32)
146-
}
147147
ty::Int(IntTy::I32) | ty::Uint(UintTy::U32) => Some(InlineAsmType::I32),
148148
ty::Int(IntTy::I64) | ty::Uint(UintTy::U64) => Some(InlineAsmType::I64),
149149
ty::Int(IntTy::I128) | ty::Uint(UintTy::U128) => Some(InlineAsmType::I128),
150150
ty::Int(IntTy::Isize) | ty::Uint(UintTy::Usize) => Some(asm_ty_isize),
151-
ty::Infer(InferTy::FloatVar(_)) => {
152-
assert!(self.is_tainted_by_errors());
153-
Some(InlineAsmType::F32)
154-
}
155151
ty::Float(FloatTy::F32) => Some(InlineAsmType::F32),
156152
ty::Float(FloatTy::F64) => Some(InlineAsmType::F64),
157153
ty::FnPtr(_) => Some(asm_ty_isize),
@@ -191,6 +187,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
191187
_ => None,
192188
}
193189
}
190+
ty::Infer(_) => unreachable!(),
194191
_ => None,
195192
};
196193
let Some(asm_ty) = asm_ty else {
@@ -204,11 +201,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
204201
return None;
205202
};
206203

207-
if ty.has_infer_types_or_consts() {
208-
assert!(self.is_tainted_by_errors());
209-
return None;
210-
}
211-
212204
// Check that the type implements Copy. The only case where this can
213205
// possibly fail is for SIMD types which don't #[derive(Copy)].
214206
if !self.infcx.type_is_copy_modulo_regions(self.param_env, ty, DUMMY_SP) {

library/std/src/sys/windows/c.rs

+13-1
Original file line numberDiff line numberDiff line change
@@ -326,7 +326,9 @@ union IO_STATUS_BLOCK_union {
326326
}
327327
impl Default for IO_STATUS_BLOCK_union {
328328
fn default() -> Self {
329-
Self { Pointer: ptr::null_mut() }
329+
let mut this = Self { Pointer: ptr::null_mut() };
330+
this.Status = STATUS_PENDING;
331+
this
330332
}
331333
}
332334
#[repr(C)]
@@ -335,6 +337,16 @@ pub struct IO_STATUS_BLOCK {
335337
u: IO_STATUS_BLOCK_union,
336338
pub Information: usize,
337339
}
340+
impl IO_STATUS_BLOCK {
341+
pub fn status(&self) -> NTSTATUS {
342+
// SAFETY: If `self.u.Status` was set then this is obviously safe.
343+
// If `self.u.Pointer` was set then this is the equivalent to converting
344+
// the pointer to an integer, which is also safe.
345+
// Currently the only safe way to construct `IO_STATUS_BLOCK` outside of
346+
// this module is to call the `default` method, which sets the `Status`.
347+
unsafe { self.u.Status }
348+
}
349+
}
338350

339351
pub type LPOVERLAPPED_COMPLETION_ROUTINE = unsafe extern "system" fn(
340352
dwErrorCode: DWORD,

library/std/src/sys/windows/handle.rs

+18-7
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
#![unstable(issue = "none", feature = "windows_handle")]
22

3+
#[cfg(test)]
4+
mod tests;
5+
36
use crate::cmp;
47
use crate::io::{self, ErrorKind, IoSlice, IoSliceMut, Read, ReadBuf};
58
use crate::mem;
@@ -248,14 +251,18 @@ impl Handle {
248251
offset.map(|n| n as _).as_ref(),
249252
None,
250253
);
254+
255+
let status = if status == c::STATUS_PENDING {
256+
c::WaitForSingleObject(self.as_raw_handle(), c::INFINITE);
257+
io_status.status()
258+
} else {
259+
status
260+
};
251261
match status {
252262
// If the operation has not completed then abort the process.
253263
// Doing otherwise means that the buffer and stack may be written to
254264
// after this function returns.
255-
c::STATUS_PENDING => {
256-
eprintln!("I/O error: operation failed to complete synchronously");
257-
crate::process::abort();
258-
}
265+
c::STATUS_PENDING => rtabort!("I/O error: operation failed to complete synchronously"),
259266

260267
// Return `Ok(0)` when there's nothing more to read.
261268
c::STATUS_END_OF_FILE => Ok(0),
@@ -294,13 +301,17 @@ impl Handle {
294301
None,
295302
)
296303
};
304+
let status = if status == c::STATUS_PENDING {
305+
unsafe { c::WaitForSingleObject(self.as_raw_handle(), c::INFINITE) };
306+
io_status.status()
307+
} else {
308+
status
309+
};
297310
match status {
298311
// If the operation has not completed then abort the process.
299312
// Doing otherwise means that the buffer may be read and the stack
300313
// written to after this function returns.
301-
c::STATUS_PENDING => {
302-
rtabort!("I/O error: operation failed to complete synchronously");
303-
}
314+
c::STATUS_PENDING => rtabort!("I/O error: operation failed to complete synchronously"),
304315

305316
// Success!
306317
status if c::nt_success(status) => Ok(io_status.Information),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
use crate::sys::pipe::{anon_pipe, Pipes};
2+
use crate::{thread, time};
3+
4+
/// Test the synchronous fallback for overlapped I/O.
5+
#[test]
6+
fn overlapped_handle_fallback() {
7+
// Create some pipes. `ours` will be asynchronous.
8+
let Pipes { ours, theirs } = anon_pipe(true, false).unwrap();
9+
10+
let async_readable = ours.into_handle();
11+
let sync_writeable = theirs.into_handle();
12+
13+
thread::scope(|_| {
14+
thread::sleep(time::Duration::from_millis(100));
15+
sync_writeable.write(b"hello world!").unwrap();
16+
});
17+
18+
// The pipe buffer starts empty so reading won't complete synchronously unless
19+
// our fallback path works.
20+
let mut buffer = [0u8; 1024];
21+
async_readable.read(&mut buffer).unwrap();
22+
}

0 commit comments

Comments
 (0)