diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index d2e8227479271..0961203d76d7d 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -1,7 +1,7 @@ //! The entry point of the NLL borrow checker. use rustc_data_structures::vec_map::VecMap; -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::LocalDefId; use rustc_index::vec::IndexVec; use rustc_infer::infer::InferCtxt; use rustc_middle::mir::{create_dump_file, dump_enabled, dump_mir, PassWhere}; @@ -44,7 +44,7 @@ pub type PoloniusOutput = Output; /// closure requirements to propagate, and any generated errors. pub(crate) struct NllOutput<'tcx> { pub regioncx: RegionInferenceContext<'tcx>, - pub opaque_type_values: VecMap>, + pub opaque_type_values: VecMap>, pub polonius_input: Option>, pub polonius_output: Option>, pub opt_closure_req: Option>, @@ -373,7 +373,7 @@ pub(super) fn dump_annotation<'a, 'tcx>( body: &Body<'tcx>, regioncx: &RegionInferenceContext<'tcx>, closure_region_requirements: &Option>, - opaque_type_values: &VecMap>, + opaque_type_values: &VecMap>, errors: &mut crate::error::BorrowckErrors<'tcx>, ) { let tcx = infcx.tcx; diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index 7c1fa28b8dfcc..de9da84572983 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -1,6 +1,6 @@ use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::vec_map::VecMap; -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::LocalDefId; use rustc_hir::OpaqueTyOrigin; use rustc_infer::infer::error_reporting::unexpected_hidden_region_diagnostic; use rustc_infer::infer::InferCtxt; @@ -63,8 +63,8 @@ impl<'tcx> RegionInferenceContext<'tcx> { &self, infcx: &InferCtxt<'_, 'tcx>, opaque_ty_decls: VecMap, (OpaqueHiddenType<'tcx>, OpaqueTyOrigin)>, - ) -> VecMap> { - let mut result: VecMap> = VecMap::new(); + ) -> VecMap> { + let mut result: VecMap> = VecMap::new(); for (opaque_type_key, (concrete_type, origin)) in opaque_ty_decls { let substs = opaque_type_key.substs; debug!(?concrete_type, ?substs); @@ -235,7 +235,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { // lifetimes with 'static and remapping only those used in the // `impl Trait` return type, resulting in the parameters // shifting. - let id_substs = InternalSubsts::identity_for_item(self.tcx, def_id); + let id_substs = InternalSubsts::identity_for_item(self.tcx, def_id.to_def_id()); debug!(?id_substs); let map: FxHashMap, GenericArg<'tcx>> = substs.iter().enumerate().map(|(index, subst)| (subst, id_substs[index])).collect(); @@ -268,7 +268,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { // This logic duplicates most of `check_opaque_meets_bounds`. // FIXME(oli-obk): Also do region checks here and then consider removing `check_opaque_meets_bounds` entirely. let param_env = self.tcx.param_env(def_id); - let body_id = self.tcx.local_def_id_to_hir_id(def_id.as_local().unwrap()); + let body_id = self.tcx.local_def_id_to_hir_id(def_id); self.tcx.infer_ctxt().enter(move |infcx| { // Require the hidden type to be well-formed with only the generics of the opaque type. // Defining use functions may have more bounds than the opaque type, which is ok, as long as the @@ -296,7 +296,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { infcx .report_mismatched_types( &ObligationCause::misc(instantiated_ty.span, body_id), - self.tcx.mk_opaque(def_id, id_substs), + self.tcx.mk_opaque(def_id.to_def_id(), id_substs), definition_ty, err, ) @@ -423,7 +423,7 @@ fn check_opaque_type_parameter_valid( struct ReverseMapper<'tcx> { tcx: TyCtxt<'tcx>, - opaque_type_def_id: DefId, + opaque_type_def_id: LocalDefId, map: FxHashMap, GenericArg<'tcx>>, map_missing_regions_to_empty: bool, @@ -437,7 +437,7 @@ struct ReverseMapper<'tcx> { impl<'tcx> ReverseMapper<'tcx> { fn new( tcx: TyCtxt<'tcx>, - opaque_type_def_id: DefId, + opaque_type_def_id: LocalDefId, map: FxHashMap, GenericArg<'tcx>>, hidden_ty: Ty<'tcx>, span: Span, diff --git a/compiler/rustc_const_eval/src/interpret/visitor.rs b/compiler/rustc_const_eval/src/interpret/visitor.rs index f6a0c19d25953..3f6e8a8f755a1 100644 --- a/compiler/rustc_const_eval/src/interpret/visitor.rs +++ b/compiler/rustc_const_eval/src/interpret/visitor.rs @@ -473,6 +473,9 @@ macro_rules! make_value_visitor { // The second `Box` field is the allocator, which we recursively check for validity // like in regular structs. self.visit_field(v, 1, &alloc)?; + + // We visited all parts of this one. + return Ok(()); } _ => {}, }; diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index 1e8b212276f2f..8dc20544f1b1a 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -153,7 +153,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { .opaque_type_storage .take_opaque_types() .into_iter() - .map(|(k, v)| (self.tcx.mk_opaque(k.def_id, k.substs), v.hidden_type.ty)) + .map(|(k, v)| (self.tcx.mk_opaque(k.def_id.to_def_id(), k.substs), v.hidden_type.ty)) .collect() } diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index c5a342c1ba2ca..b3dc2e586d251 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -938,7 +938,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { #[instrument(skip(self), level = "debug")] pub fn member_constraint( &self, - opaque_type_def_id: DefId, + opaque_type_def_id: LocalDefId, definition_span: Span, hidden_ty: Ty<'tcx>, region: ty::Region<'tcx>, diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs index f11701bba6f43..4ee9c4eeda40a 100644 --- a/compiler/rustc_infer/src/infer/opaque_types.rs +++ b/compiler/rustc_infer/src/infer/opaque_types.rs @@ -51,7 +51,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { return InferOk { value: ty, obligations: vec![] }; } let mut obligations = vec![]; - let replace_opaque_type = |def_id| self.opaque_type_origin(def_id, span).is_some(); + let replace_opaque_type = |def_id: DefId| { + def_id + .as_local() + .map_or(false, |def_id| self.opaque_type_origin(def_id, span).is_some()) + }; let value = ty.fold_with(&mut ty::fold::BottomUpFolder { tcx: self.tcx, lt_op: |lt| lt, @@ -96,6 +100,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let (a, b) = if a_is_expected { (a, b) } else { (b, a) }; let process = |a: Ty<'tcx>, b: Ty<'tcx>| match *a.kind() { ty::Opaque(def_id, substs) if def_id.is_local() => { + let def_id = def_id.expect_local(); let origin = if self.defining_use_anchor.is_some() { // Check that this is `impl Trait` type is // declared by `parent_def_id` -- i.e., one whose @@ -141,7 +146,8 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // no one encounters it in practice. // It does occur however in `fn fut() -> impl Future { async { 42 } }`, // where it is of no concern, so we only check for TAITs. - if let Some(OpaqueTyOrigin::TyAlias) = self.opaque_type_origin(did2, cause.span) + if let Some(OpaqueTyOrigin::TyAlias) = + did2.as_local().and_then(|did2| self.opaque_type_origin(did2, cause.span)) { self.tcx .sess @@ -399,8 +405,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } #[instrument(skip(self), level = "trace")] - pub fn opaque_type_origin(&self, opaque_def_id: DefId, span: Span) -> Option { - let def_id = opaque_def_id.as_local()?; + pub fn opaque_type_origin(&self, def_id: LocalDefId, span: Span) -> Option { let opaque_hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id); let parent_def_id = self.defining_use_anchor?; let item_kind = &self.tcx.hir().expect_item(def_id).kind; @@ -409,7 +414,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { span_bug!( span, "weird opaque type: {:#?}, {:#?}", - opaque_def_id, + def_id, item_kind ) }; @@ -428,12 +433,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } #[instrument(skip(self), level = "trace")] - fn opaque_ty_origin_unchecked(&self, opaque_def_id: DefId, span: Span) -> OpaqueTyOrigin { - let def_id = opaque_def_id.as_local().unwrap(); + fn opaque_ty_origin_unchecked(&self, def_id: LocalDefId, span: Span) -> OpaqueTyOrigin { let origin = match self.tcx.hir().expect_item(def_id).kind { hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => origin, ref itemkind => { - span_bug!(span, "weird opaque type: {:?}, {:#?}", opaque_def_id, itemkind) + span_bug!(span, "weird opaque type: {:?}, {:#?}", def_id, itemkind) } }; trace!(?origin); @@ -557,7 +561,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { obligations = self.at(&cause, param_env).eq(prev, hidden_ty)?.obligations; } - let item_bounds = tcx.bound_explicit_item_bounds(def_id); + let item_bounds = tcx.bound_explicit_item_bounds(def_id.to_def_id()); for predicate in item_bounds.transpose_iter().map(|e| e.map_bound(|(p, _)| *p)) { debug!(?predicate); @@ -579,7 +583,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } // Replace all other mentions of the same opaque type with the hidden type, // as the bounds must hold on the hidden type after all. - ty::Opaque(def_id2, substs2) if def_id == def_id2 && substs == substs2 => { + ty::Opaque(def_id2, substs2) + if def_id.to_def_id() == def_id2 && substs == substs2 => + { hidden_ty } _ => ty, diff --git a/compiler/rustc_infer/src/infer/region_constraints/mod.rs b/compiler/rustc_infer/src/infer/region_constraints/mod.rs index c5747ecf702a7..551f398e0c2c4 100644 --- a/compiler/rustc_infer/src/infer/region_constraints/mod.rs +++ b/compiler/rustc_infer/src/infer/region_constraints/mod.rs @@ -12,7 +12,7 @@ use rustc_data_structures::intern::Interned; use rustc_data_structures::sync::Lrc; use rustc_data_structures::undo_log::UndoLogs; use rustc_data_structures::unify as ut; -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::LocalDefId; use rustc_index::vec::IndexVec; use rustc_middle::infer::unify_key::{RegionVidKey, UnifiedRegion}; use rustc_middle::ty::ReStatic; @@ -533,7 +533,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { pub fn member_constraint( &mut self, - opaque_type_def_id: DefId, + opaque_type_def_id: LocalDefId, definition_span: Span, hidden_ty: Ty<'tcx>, member_region: ty::Region<'tcx>, diff --git a/compiler/rustc_middle/src/infer/mod.rs b/compiler/rustc_middle/src/infer/mod.rs index 55e00c4c0d8ef..8b2f9bdfd486b 100644 --- a/compiler/rustc_middle/src/infer/mod.rs +++ b/compiler/rustc_middle/src/infer/mod.rs @@ -4,7 +4,7 @@ pub mod unify_key; use crate::ty::Region; use crate::ty::Ty; use rustc_data_structures::sync::Lrc; -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::LocalDefId; use rustc_span::Span; /// Requires that `region` must be equal to one of the regions in `choice_regions`. @@ -16,7 +16,7 @@ use rustc_span::Span; #[derive(Debug, Clone, HashStable, TypeFoldable, TypeVisitable, Lift)] pub struct MemberConstraint<'tcx> { /// The `DefId` of the opaque type causing this constraint: used for error reporting. - pub opaque_type_def_id: DefId, + pub opaque_type_def_id: LocalDefId, /// The span where the hidden type was instantiated. pub definition_span: Span, diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index 6a6ed3dc728d9..423e84d88cf73 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -235,7 +235,7 @@ pub struct BorrowCheckResult<'tcx> { /// All the opaque types that are restricted to concrete types /// by this function. Unlike the value in `TypeckResults`, this has /// unerased regions. - pub concrete_opaque_types: VecMap>, + pub concrete_opaque_types: VecMap>, pub closure_requirements: Option>, pub used_mut_upvars: SmallVec<[Field; 8]>, pub tainted_by_errors: Option, diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index a594dab2e20a3..0f98d19820e25 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -542,7 +542,7 @@ pub struct TypeckResults<'tcx> { /// even if they are only set in dead code (which doesn't show up in MIR). /// For type-alias-impl-trait, this map is only used to prevent query cycles, /// so the hidden types are all `None`. - pub concrete_opaque_types: VecMap>>, + pub concrete_opaque_types: VecMap>>, /// Tracks the minimum captures required for a closure; /// see `MinCaptureInformationMap` for more details. diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 3536d946db279..53919826bf617 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1108,8 +1108,7 @@ impl<'tcx> InstantiatedPredicates<'tcx> { #[derive(Copy, Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable, Lift)] #[derive(TypeFoldable, TypeVisitable)] pub struct OpaqueTypeKey<'tcx> { - // FIXME(oli-obk): make this a LocalDefId - pub def_id: DefId, + pub def_id: LocalDefId, pub substs: SubstsRef<'tcx>, } diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index d663f1a3ec6e7..9f622ad6cd2a1 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1707,13 +1707,6 @@ impl<'tcx> Ty<'tcx> { } } - pub fn expect_opaque_type(self) -> ty::OpaqueTypeKey<'tcx> { - match *self.kind() { - Opaque(def_id, substs) => ty::OpaqueTypeKey { def_id, substs }, - _ => bug!("`expect_opaque_type` called on non-opaque type: {}", self), - } - } - pub fn simd_size_and_type(self, tcx: TyCtxt<'tcx>) -> (u64, Ty<'tcx>) { match self.kind() { Adt(def, substs) => { diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs index d33b5b2140362..d079aeb4801ca 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs @@ -763,12 +763,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // src/test/ui/impl-trait/hidden-type-is-opaque-2.rs for examples that hit this path. if formal_ret.has_infer_types() { for ty in ret_ty.walk() { - if let ty::subst::GenericArgKind::Type(ty) = ty.unpack() { - if let ty::Opaque(def_id, _) = *ty.kind() { - if self.infcx.opaque_type_origin(def_id, DUMMY_SP).is_some() { - return None; - } - } + if let ty::subst::GenericArgKind::Type(ty) = ty.unpack() + && let ty::Opaque(def_id, _) = *ty.kind() + && let Some(def_id) = def_id.as_local() + && self.infcx.opaque_type_origin(def_id, DUMMY_SP).is_some() { + return None; } } } diff --git a/compiler/rustc_typeck/src/check/writeback.rs b/compiler/rustc_typeck/src/check/writeback.rs index 0cbb0e25d0d42..23ac638b2f430 100644 --- a/compiler/rustc_typeck/src/check/writeback.rs +++ b/compiler/rustc_typeck/src/check/writeback.rs @@ -4,6 +4,7 @@ use crate::check::FnCtxt; +use hir::def_id::LocalDefId; use rustc_data_structures::stable_map::FxHashMap; use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; @@ -509,13 +510,13 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { hir::OpaqueTyOrigin::FnReturn(_) | hir::OpaqueTyOrigin::AsyncFn(_) => { let ty = self.resolve(decl.hidden_type.ty, &decl.hidden_type.span); struct RecursionChecker { - def_id: DefId, + def_id: LocalDefId, } impl<'tcx> ty::TypeVisitor<'tcx> for RecursionChecker { type BreakTy = (); fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow { if let ty::Opaque(def_id, _) = *t.kind() { - if def_id == self.def_id { + if def_id == self.def_id.to_def_id() { return ControlFlow::Break(()); } } diff --git a/compiler/rustc_typeck/src/collect/type_of.rs b/compiler/rustc_typeck/src/collect/type_of.rs index f942a4fb53a26..faa4f3700bba8 100644 --- a/compiler/rustc_typeck/src/collect/type_of.rs +++ b/compiler/rustc_typeck/src/collect/type_of.rs @@ -342,7 +342,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { let concrete_ty = tcx .mir_borrowck(owner) .concrete_opaque_types - .get(&def_id.to_def_id()) + .get(&def_id) .copied() .map(|concrete| concrete.ty) .unwrap_or_else(|| { @@ -353,7 +353,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: DefId) -> Ty<'_> { // the `concrete_opaque_types` table. tcx.ty_error() } else { - table.concrete_opaque_types.get(&def_id.to_def_id()).copied().unwrap_or_else(|| { + table.concrete_opaque_types.get(&def_id).copied().unwrap_or_else(|| { // We failed to resolve the opaque type or it // resolves to itself. We interpret this as the // no values of the hidden type ever being constructed, @@ -526,7 +526,7 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> { tcx: TyCtxt<'tcx>, /// def_id of the opaque type whose defining uses are being checked - def_id: DefId, + def_id: LocalDefId, /// as we walk the defining uses, we are checking that all of them /// define the same hidden type. This variable is set to `Some` @@ -602,7 +602,7 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> { fn visit_item(&mut self, it: &'tcx Item<'tcx>) { trace!(?it.def_id); // The opaque type itself or its children are not within its reveal scope. - if it.def_id.to_def_id() != self.def_id { + if it.def_id != self.def_id { self.check(it.def_id); intravisit::walk_item(self, it); } @@ -610,7 +610,7 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> { fn visit_impl_item(&mut self, it: &'tcx ImplItem<'tcx>) { trace!(?it.def_id); // The opaque type itself or its children are not within its reveal scope. - if it.def_id.to_def_id() != self.def_id { + if it.def_id != self.def_id { self.check(it.def_id); intravisit::walk_impl_item(self, it); } @@ -624,7 +624,7 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> { let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); let scope = tcx.hir().get_defining_scope(hir_id); - let mut locator = ConstraintLocator { def_id: def_id.to_def_id(), tcx, found: None }; + let mut locator = ConstraintLocator { def_id: def_id, tcx, found: None }; debug!(?scope); diff --git a/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs index 649aeb0890dc0..efdc86bf57a8a 100644 --- a/library/alloc/src/alloc.rs +++ b/library/alloc/src/alloc.rs @@ -70,11 +70,14 @@ pub use std::alloc::Global; /// # Examples /// /// ``` -/// use std::alloc::{alloc, dealloc, Layout}; +/// use std::alloc::{alloc, dealloc, handle_alloc_error, Layout}; /// /// unsafe { /// let layout = Layout::new::(); /// let ptr = alloc(layout); +/// if ptr.is_null() { +/// handle_alloc_error(layout); +/// } /// /// *(ptr as *mut u16) = 42; /// assert_eq!(*(ptr as *mut u16), 42); diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index ecd2b75ae4427..66af491607435 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -1040,6 +1040,8 @@ pub fn copy(x: &T) -> T { #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature = "const_transmute_copy", issue = "83165")] pub const unsafe fn transmute_copy(src: &T) -> U { + assert!(size_of::() >= size_of::(), "cannot transmute_copy if U is larger than T"); + // If U has a higher alignment requirement, src might not be suitably aligned. if align_of::() > align_of::() { // SAFETY: `src` is a reference which is guaranteed to be valid for reads. diff --git a/library/core/tests/mem.rs b/library/core/tests/mem.rs index 3b13dc0832fa4..6856d1a1f51ae 100644 --- a/library/core/tests/mem.rs +++ b/library/core/tests/mem.rs @@ -97,6 +97,46 @@ fn test_transmute_copy() { assert_eq!(1, unsafe { transmute_copy(&1) }); } +#[test] +fn test_transmute_copy_shrink() { + assert_eq!(0_u8, unsafe { transmute_copy(&0_u64) }); +} + +#[test] +fn test_transmute_copy_unaligned() { + #[repr(C)] + #[derive(Default)] + struct Unaligned { + a: u8, + b: [u8; 8], + } + + let u = Unaligned::default(); + assert_eq!(0_u64, unsafe { transmute_copy(&u.b) }); +} + +#[test] +#[cfg(panic = "unwind")] +fn test_transmute_copy_grow_panics() { + use std::panic; + + let err = panic::catch_unwind(panic::AssertUnwindSafe(|| unsafe { + let _unused: u64 = transmute_copy(&1_u8); + })); + + match err { + Ok(_) => unreachable!(), + Err(payload) => { + payload + .downcast::<&'static str>() + .and_then(|s| { + if *s == "cannot transmute_copy if U is larger than T" { Ok(s) } else { Err(s) } + }) + .unwrap_or_else(|p| panic::resume_unwind(p)); + } + } +} + #[test] #[allow(dead_code)] fn test_discriminant_send_sync() { diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs index e8d0132f4b98c..d8806b6ec60bf 100644 --- a/library/std/src/fs/tests.rs +++ b/library/std/src/fs/tests.rs @@ -1534,3 +1534,17 @@ fn read_large_dir() { entry.unwrap(); } } + +/// Test the fallback for getting the metadata of files like hiberfil.sys that +/// Windows holds a special lock on, preventing normal means of querying +/// metadata. See #96980. +#[test] +#[cfg(windows)] +fn hiberfil_sys() { + let hiberfil = Path::new(r"C:\hiberfil.sys"); + + assert_eq!(true, hiberfil.try_exists().unwrap()); + fs::symlink_metadata(hiberfil).unwrap(); + fs::metadata(hiberfil).unwrap(); + assert_eq!(true, hiberfil.exists()); +} diff --git a/library/std/src/sys/windows/fs.rs b/library/std/src/sys/windows/fs.rs index e9b1006907741..4d3162f125462 100644 --- a/library/std/src/sys/windows/fs.rs +++ b/library/std/src/sys/windows/fs.rs @@ -155,22 +155,7 @@ impl DirEntry { } pub fn metadata(&self) -> io::Result { - Ok(FileAttr { - attributes: self.data.dwFileAttributes, - creation_time: self.data.ftCreationTime, - last_access_time: self.data.ftLastAccessTime, - last_write_time: self.data.ftLastWriteTime, - file_size: ((self.data.nFileSizeHigh as u64) << 32) | (self.data.nFileSizeLow as u64), - reparse_tag: if self.data.dwFileAttributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 { - // reserved unless this is a reparse point - self.data.dwReserved0 - } else { - 0 - }, - volume_serial_number: None, - number_of_links: None, - file_index: None, - }) + Ok(self.data.into()) } } @@ -879,6 +864,26 @@ impl FileAttr { self.file_index } } +impl From for FileAttr { + fn from(wfd: c::WIN32_FIND_DATAW) -> Self { + FileAttr { + attributes: wfd.dwFileAttributes, + creation_time: wfd.ftCreationTime, + last_access_time: wfd.ftLastAccessTime, + last_write_time: wfd.ftLastWriteTime, + file_size: ((wfd.nFileSizeHigh as u64) << 32) | (wfd.nFileSizeLow as u64), + reparse_tag: if wfd.dwFileAttributes & c::FILE_ATTRIBUTE_REPARSE_POINT != 0 { + // reserved unless this is a reparse point + wfd.dwReserved0 + } else { + 0 + }, + volume_serial_number: None, + number_of_links: None, + file_index: None, + } + } +} fn to_u64(ft: &c::FILETIME) -> u64 { (ft.dwLowDateTime as u64) | ((ft.dwHighDateTime as u64) << 32) @@ -1145,22 +1150,73 @@ pub fn link(_original: &Path, _link: &Path) -> io::Result<()> { } pub fn stat(path: &Path) -> io::Result { - let mut opts = OpenOptions::new(); - // No read or write permissions are necessary - opts.access_mode(0); - // This flag is so we can open directories too - opts.custom_flags(c::FILE_FLAG_BACKUP_SEMANTICS); - let file = File::open(path, &opts)?; - file.file_attr() + metadata(path, ReparsePoint::Follow) } pub fn lstat(path: &Path) -> io::Result { + metadata(path, ReparsePoint::Open) +} + +#[repr(u32)] +#[derive(Clone, Copy, PartialEq, Eq)] +enum ReparsePoint { + Follow = 0, + Open = c::FILE_FLAG_OPEN_REPARSE_POINT, +} +impl ReparsePoint { + fn as_flag(self) -> u32 { + self as u32 + } +} + +fn metadata(path: &Path, reparse: ReparsePoint) -> io::Result { let mut opts = OpenOptions::new(); // No read or write permissions are necessary opts.access_mode(0); - opts.custom_flags(c::FILE_FLAG_BACKUP_SEMANTICS | c::FILE_FLAG_OPEN_REPARSE_POINT); - let file = File::open(path, &opts)?; - file.file_attr() + opts.custom_flags(c::FILE_FLAG_BACKUP_SEMANTICS | reparse.as_flag()); + + // Attempt to open the file normally. + // If that fails with `ERROR_SHARING_VIOLATION` then retry using `FindFirstFileW`. + // If the fallback fails for any reason we return the original error. + match File::open(path, &opts) { + Ok(file) => file.file_attr(), + Err(e) if e.raw_os_error() == Some(c::ERROR_SHARING_VIOLATION as _) => { + // `ERROR_SHARING_VIOLATION` will almost never be returned. + // Usually if a file is locked you can still read some metadata. + // However, there are special system files, such as + // `C:\hiberfil.sys`, that are locked in a way that denies even that. + unsafe { + let path = maybe_verbatim(path)?; + + // `FindFirstFileW` accepts wildcard file names. + // Fortunately wildcards are not valid file names and + // `ERROR_SHARING_VIOLATION` means the file exists (but is locked) + // therefore it's safe to assume the file name given does not + // include wildcards. + let mut wfd = mem::zeroed(); + let handle = c::FindFirstFileW(path.as_ptr(), &mut wfd); + + if handle == c::INVALID_HANDLE_VALUE { + // This can fail if the user does not have read access to the + // directory. + Err(e) + } else { + // We no longer need the find handle. + c::FindClose(handle); + + // `FindFirstFileW` reads the cached file information from the + // directory. The downside is that this metadata may be outdated. + let attrs = FileAttr::from(wfd); + if reparse == ReparsePoint::Follow && attrs.file_type().is_symlink() { + Err(e) + } else { + Ok(attrs) + } + } + } + } + Err(e) => Err(e), + } } pub fn set_perm(p: &Path, perm: FilePermissions) -> io::Result<()> {