From 71d98a8620b89f1efa3f597622a34396fd4966f8 Mon Sep 17 00:00:00 2001 From: Colin Finck Date: Fri, 9 Aug 2024 15:02:18 +0200 Subject: [PATCH 1/9] Ship MinGW-w64 runtime DLLs along with `rust-lld.exe` for `-pc-windows-gnu` targets `rust-lld.exe` built for `x86_64-pc-windows-gnu` depends on `libgcc_s_seh-1.dll` and `libwinpthread-1.dll` from MinGW-w64. Until now, they were not shipped alongside `rust-lld.exe`, and you could not run `rust-lld.exe` on most systems. This problem didn't surface until now because: * Most targets don't use `rust-lld` by default. * Some people had these DLLs in their `PATH` from some other MinGW binary. * `rustup` used to add `bin` to the `PATH`, which contains these DLLs for `rustc.exe`. But it no longer does that: https://github.com/rust-lang/rustup/commit/ce3c09a0cb126e2c65a3bb2a3bbf3f098b4c23a2 Fixes #125809 --- src/bootstrap/src/core/build_steps/dist.rs | 37 ++++++++++++++-------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index 530eb9b446a43..0e4b0b4ac8391 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -268,34 +268,45 @@ fn make_win_dist( let target_libs = find_files(&target_libs, &lib_path); // Copy runtime dlls next to rustc.exe - let dist_bin_dir = rust_root.join("bin/"); - fs::create_dir_all(&dist_bin_dir).expect("creating dist_bin_dir failed"); - for src in rustc_dlls { - builder.copy_link_to_folder(&src, &dist_bin_dir); + let rust_bin_dir = rust_root.join("bin/"); + fs::create_dir_all(&rust_bin_dir).expect("creating rust_bin_dir failed"); + for src in &rustc_dlls { + builder.copy_link_to_folder(src, &rust_bin_dir); + } + + if builder.config.lld_enabled { + // rust-lld.exe also needs runtime dlls + let rust_target_bin_dir = rust_root.join("lib/rustlib").join(target).join("bin"); + fs::create_dir_all(&rust_target_bin_dir).expect("creating rust_target_bin_dir failed"); + for src in &rustc_dlls { + builder.copy_link_to_folder(src, &rust_target_bin_dir); + } } //Copy platform tools to platform-specific bin directory - let target_bin_dir = - plat_root.join("lib").join("rustlib").join(target).join("bin").join("self-contained"); - fs::create_dir_all(&target_bin_dir).expect("creating target_bin_dir failed"); + let plat_target_bin_self_contained_dir = + plat_root.join("lib/rustlib").join(target).join("bin/self-contained"); + fs::create_dir_all(&plat_target_bin_self_contained_dir) + .expect("creating plat_target_bin_self_contained_dir failed"); for src in target_tools { - builder.copy_link_to_folder(&src, &target_bin_dir); + builder.copy_link_to_folder(&src, &plat_target_bin_self_contained_dir); } // Warn windows-gnu users that the bundled GCC cannot compile C files builder.create( - &target_bin_dir.join("GCC-WARNING.txt"), + &plat_target_bin_self_contained_dir.join("GCC-WARNING.txt"), "gcc.exe contained in this folder cannot be used for compiling C files - it is only \ used as a linker. In order to be able to compile projects containing C code use \ the GCC provided by MinGW or Cygwin.", ); //Copy platform libs to platform-specific lib directory - let target_lib_dir = - plat_root.join("lib").join("rustlib").join(target).join("lib").join("self-contained"); - fs::create_dir_all(&target_lib_dir).expect("creating target_lib_dir failed"); + let plat_target_lib_self_contained_dir = + plat_root.join("lib/rustlib").join(target).join("lib/self-contained"); + fs::create_dir_all(&plat_target_lib_self_contained_dir) + .expect("creating plat_target_lib_self_contained_dir failed"); for src in target_libs { - builder.copy_link_to_folder(&src, &target_lib_dir); + builder.copy_link_to_folder(&src, &plat_target_lib_self_contained_dir); } } From c51f2d24d1df7a797113b46def0d904d6c877055 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Thu, 22 Aug 2024 01:17:01 +0000 Subject: [PATCH 2/9] Use a LocalDefId in ResolvedArg. --- .../rustc_hir_analysis/src/check/check.rs | 4 +-- .../src/collect/resolve_bound_vars.rs | 27 +++++++++-------- .../src/hir_ty_lowering/mod.rs | 29 ++++++++++--------- compiler/rustc_lint/src/builtin.rs | 10 +++---- .../rustc_lint/src/impl_trait_overcaptures.rs | 7 +++-- .../src/middle/resolve_bound_vars.rs | 8 ++--- compiler/rustc_middle/src/ty/context.rs | 18 ++++++------ .../infer/nice_region_error/find_anon_type.rs | 8 ++--- src/librustdoc/clean/mod.rs | 2 +- 9 files changed, 58 insertions(+), 55 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 16eeb57b2b967..14c5f8d9f16da 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -529,7 +529,7 @@ fn check_opaque_precise_captures<'tcx>(tcx: TyCtxt<'tcx>, opaque_def_id: LocalDe match tcx.named_bound_var(hir_id) { Some(ResolvedArg::EarlyBound(def_id)) => { - expected_captures.insert(def_id); + expected_captures.insert(def_id.to_def_id()); // Make sure we allow capturing these lifetimes through `Self` and // `T::Assoc` projection syntax, too. These will occur when we only @@ -538,7 +538,7 @@ fn check_opaque_precise_captures<'tcx>(tcx: TyCtxt<'tcx>, opaque_def_id: LocalDe // feature -- see . if let DefKind::LifetimeParam = tcx.def_kind(def_id) && let Some(def_id) = tcx - .map_opaque_lifetime_to_parent_lifetime(def_id.expect_local()) + .map_opaque_lifetime_to_parent_lifetime(def_id) .opt_param_def_id(tcx, tcx.parent(opaque_def_id.to_def_id())) { shadowed_captures.insert(def_id); diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index ae0c70d232685..0cf9e128bceef 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -13,7 +13,6 @@ use rustc_ast::visit::walk_list; use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; -use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{GenericArg, GenericParam, GenericParamKind, HirId, HirIdMap, LifetimeName, Node}; use rustc_macros::extension; @@ -22,7 +21,7 @@ use rustc_middle::middle::resolve_bound_vars::*; use rustc_middle::query::Providers; use rustc_middle::ty::{self, TyCtxt, TypeSuperVisitable, TypeVisitor}; use rustc_middle::{bug, span_bug}; -use rustc_span::def_id::DefId; +use rustc_span::def_id::{DefId, LocalDefId}; use rustc_span::symbol::{sym, Ident}; use rustc_span::Span; @@ -32,7 +31,7 @@ use crate::errors; impl ResolvedArg { fn early(param: &GenericParam<'_>) -> (LocalDefId, ResolvedArg) { debug!("ResolvedArg::early: def_id={:?}", param.def_id); - (param.def_id, ResolvedArg::EarlyBound(param.def_id.to_def_id())) + (param.def_id, ResolvedArg::EarlyBound(param.def_id)) } fn late(idx: u32, param: &GenericParam<'_>) -> (LocalDefId, ResolvedArg) { @@ -41,10 +40,10 @@ impl ResolvedArg { "ResolvedArg::late: idx={:?}, param={:?} depth={:?} def_id={:?}", idx, param, depth, param.def_id, ); - (param.def_id, ResolvedArg::LateBound(depth, idx, param.def_id.to_def_id())) + (param.def_id, ResolvedArg::LateBound(depth, idx, param.def_id)) } - fn id(&self) -> Option { + fn id(&self) -> Option { match *self { ResolvedArg::StaticLifetime | ResolvedArg::Error(_) => None, @@ -288,13 +287,14 @@ fn late_arg_as_bound_arg<'tcx>( ) -> ty::BoundVariableKind { match arg { ResolvedArg::LateBound(_, _, def_id) => { - let name = tcx.hir().name(tcx.local_def_id_to_hir_id(def_id.expect_local())); + let def_id = def_id.to_def_id(); + let name = tcx.item_name(def_id); match param.kind { GenericParamKind::Lifetime { .. } => { - ty::BoundVariableKind::Region(ty::BrNamed(*def_id, name)) + ty::BoundVariableKind::Region(ty::BrNamed(def_id, name)) } GenericParamKind::Type { .. } => { - ty::BoundVariableKind::Ty(ty::BoundTyKind::Param(*def_id, name)) + ty::BoundVariableKind::Ty(ty::BoundTyKind::Param(def_id, name)) } GenericParamKind::Const { .. } => ty::BoundVariableKind::Const, } @@ -717,7 +717,6 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { // In the future, this should be fixed and this error should be removed. let def = self.map.defs.get(&lifetime.hir_id).copied(); let Some(ResolvedArg::LateBound(_, _, lifetime_def_id)) = def else { continue }; - let Some(lifetime_def_id) = lifetime_def_id.as_local() else { continue }; let lifetime_hir_id = self.tcx.local_def_id_to_hir_id(lifetime_def_id); let bad_place = match self.tcx.hir_node(self.tcx.parent_hir_id(lifetime_hir_id)) @@ -1150,7 +1149,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { .param_def_id_to_index(self.tcx, region_def_id.to_def_id()) .is_some() { - break Some(ResolvedArg::EarlyBound(region_def_id.to_def_id())); + break Some(ResolvedArg::EarlyBound(region_def_id)); } break None; } @@ -1259,7 +1258,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { kind => span_bug!( use_span, "did not expect to resolve lifetime to {}", - kind.descr(param_def_id) + kind.descr(param_def_id.to_def_id()) ), }; def = ResolvedArg::Error(guar); @@ -1277,10 +1276,10 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { kind: hir::ImplItemKind::Fn(..), .. }) => { - def = ResolvedArg::Free(owner_id.to_def_id(), def.id().unwrap()); + def = ResolvedArg::Free(owner_id.def_id, def.id().unwrap()); } Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(closure), .. }) => { - def = ResolvedArg::Free(closure.def_id.to_def_id(), def.id().unwrap()); + def = ResolvedArg::Free(closure.def_id, def.id().unwrap()); } _ => {} } @@ -1351,7 +1350,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> { .param_def_id_to_index(self.tcx, param_def_id.to_def_id()) .is_some() { - break Some(ResolvedArg::EarlyBound(param_def_id.to_def_id())); + break Some(ResolvedArg::EarlyBound(param_def_id)); } break None; } diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 2fb1bcf2dbfff..5c8ecf254a54e 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -296,25 +296,29 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { Some(rbv::ResolvedArg::StaticLifetime) => tcx.lifetimes.re_static, Some(rbv::ResolvedArg::LateBound(debruijn, index, def_id)) => { - let name = lifetime_name(def_id.expect_local()); + let name = lifetime_name(def_id); let br = ty::BoundRegion { var: ty::BoundVar::from_u32(index), - kind: ty::BrNamed(def_id, name), + kind: ty::BrNamed(def_id.to_def_id(), name), }; ty::Region::new_bound(tcx, debruijn, br) } Some(rbv::ResolvedArg::EarlyBound(def_id)) => { - let name = tcx.hir().ty_param_name(def_id.expect_local()); - let item_def_id = tcx.hir().ty_param_owner(def_id.expect_local()); + let name = tcx.hir().ty_param_name(def_id); + let item_def_id = tcx.hir().ty_param_owner(def_id); let generics = tcx.generics_of(item_def_id); - let index = generics.param_def_id_to_index[&def_id]; + let index = generics.param_def_id_to_index[&def_id.to_def_id()]; ty::Region::new_early_param(tcx, ty::EarlyParamRegion { index, name }) } Some(rbv::ResolvedArg::Free(scope, id)) => { - let name = lifetime_name(id.expect_local()); - ty::Region::new_late_param(tcx, scope, ty::BrNamed(id, name)) + let name = lifetime_name(id); + ty::Region::new_late_param( + tcx, + scope.to_def_id(), + ty::BrNamed(id.to_def_id(), name), + ) // (*) -- not late-bound, won't change } @@ -1953,15 +1957,14 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { let tcx = self.tcx(); match tcx.named_bound_var(hir_id) { Some(rbv::ResolvedArg::LateBound(debruijn, index, def_id)) => { - let name = tcx.item_name(def_id); + let name = tcx.item_name(def_id.to_def_id()); let br = ty::BoundTy { var: ty::BoundVar::from_u32(index), - kind: ty::BoundTyKind::Param(def_id, name), + kind: ty::BoundTyKind::Param(def_id.to_def_id(), name), }; Ty::new_bound(tcx, debruijn, br) } Some(rbv::ResolvedArg::EarlyBound(def_id)) => { - let def_id = def_id.expect_local(); let item_def_id = tcx.hir().ty_param_owner(def_id); let generics = tcx.generics_of(item_def_id); let index = generics.param_def_id_to_index[&def_id.to_def_id()]; @@ -1982,10 +1985,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { Some(rbv::ResolvedArg::EarlyBound(def_id)) => { // Find the name and index of the const parameter by indexing the generics of // the parent item and construct a `ParamConst`. - let item_def_id = tcx.parent(def_id); + let item_def_id = tcx.local_parent(def_id); let generics = tcx.generics_of(item_def_id); - let index = generics.param_def_id_to_index[&def_id]; - let name = tcx.item_name(def_id); + let index = generics.param_def_id_to_index[&def_id.to_def_id()]; + let name = tcx.item_name(def_id.to_def_id()); ty::Const::new_param(tcx, ty::ParamConst::new(index, name)) } Some(rbv::ResolvedArg::LateBound(debruijn, index, _)) => { diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 85132dd4f98f0..d8482567bbe5b 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -1925,8 +1925,8 @@ impl ExplicitOutlivesRequirements { fn lifetimes_outliving_lifetime<'tcx>( tcx: TyCtxt<'tcx>, inferred_outlives: impl Iterator, Span)>, - item: DefId, - lifetime: DefId, + item: LocalDefId, + lifetime: LocalDefId, ) -> Vec> { let item_generics = tcx.generics_of(item); @@ -1934,7 +1934,7 @@ impl ExplicitOutlivesRequirements { .filter_map(|(clause, _)| match clause.kind().skip_binder() { ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(a, b)) => match *a { ty::ReEarlyParam(ebr) - if item_generics.region_param(ebr, tcx).def_id == lifetime => + if item_generics.region_param(ebr, tcx).def_id == lifetime.to_def_id() => { Some(b) } @@ -1982,7 +1982,7 @@ impl ExplicitOutlivesRequirements { let is_inferred = match tcx.named_bound_var(lifetime.hir_id) { Some(ResolvedArg::EarlyBound(def_id)) => inferred_outlives .iter() - .any(|r| matches!(**r, ty::ReEarlyParam(ebr) if { item_generics.region_param(ebr, tcx).def_id == def_id })), + .any(|r| matches!(**r, ty::ReEarlyParam(ebr) if { item_generics.region_param(ebr, tcx).def_id == def_id.to_def_id() })), _ => false, }; @@ -2097,7 +2097,7 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements { inferred_outlives .iter() .filter(|(_, span)| !predicate.span.contains(*span)), - item.owner_id.to_def_id(), + item.owner_id.def_id, region_def_id, ), &predicate.bounds, diff --git a/compiler/rustc_lint/src/impl_trait_overcaptures.rs b/compiler/rustc_lint/src/impl_trait_overcaptures.rs index 990fb2d16f9dd..2e0da69e92070 100644 --- a/compiler/rustc_lint/src/impl_trait_overcaptures.rs +++ b/compiler/rustc_lint/src/impl_trait_overcaptures.rs @@ -300,16 +300,17 @@ impl<'tcx> TypeVisitor> for VisitOpaqueTypes<'tcx> { Some( ResolvedArg::EarlyBound(def_id) | ResolvedArg::LateBound(_, _, def_id), ) => { - if self.tcx.def_kind(self.tcx.parent(def_id)) == DefKind::OpaqueTy { + if self.tcx.def_kind(self.tcx.local_parent(def_id)) == DefKind::OpaqueTy + { let def_id = self .tcx - .map_opaque_lifetime_to_parent_lifetime(def_id.expect_local()) + .map_opaque_lifetime_to_parent_lifetime(def_id) .opt_param_def_id(self.tcx, self.parent_def_id.to_def_id()) .expect("variable should have been duplicated from parent"); explicitly_captured.insert(def_id); } else { - explicitly_captured.insert(def_id); + explicitly_captured.insert(def_id.to_def_id()); } } _ => { diff --git a/compiler/rustc_middle/src/middle/resolve_bound_vars.rs b/compiler/rustc_middle/src/middle/resolve_bound_vars.rs index a4f6d7afe4d11..32e2f3b4b1685 100644 --- a/compiler/rustc_middle/src/middle/resolve_bound_vars.rs +++ b/compiler/rustc_middle/src/middle/resolve_bound_vars.rs @@ -2,7 +2,7 @@ use rustc_data_structures::fx::FxIndexMap; use rustc_errors::ErrorGuaranteed; -use rustc_hir::def_id::DefId; +use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::{ItemLocalId, OwnerId}; use rustc_macros::{Decodable, Encodable, HashStable, TyDecodable, TyEncodable}; @@ -11,9 +11,9 @@ use crate::ty; #[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Debug, HashStable)] pub enum ResolvedArg { StaticLifetime, - EarlyBound(/* decl */ DefId), - LateBound(ty::DebruijnIndex, /* late-bound index */ u32, /* decl */ DefId), - Free(DefId, /* lifetime decl */ DefId), + EarlyBound(/* decl */ LocalDefId), + LateBound(ty::DebruijnIndex, /* late-bound index */ u32, /* decl */ LocalDefId), + Free(LocalDefId, /* lifetime decl */ LocalDefId), Error(ErrorGuaranteed), } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 9b39b84970420..cad3515f06809 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -3035,13 +3035,13 @@ impl<'tcx> TyCtxt<'tcx> { match self.named_bound_var(lifetime.hir_id) { Some(resolve_bound_vars::ResolvedArg::EarlyBound(ebv)) => { - let new_parent = self.parent(ebv); + let new_parent = self.local_parent(ebv); // If we map to another opaque, then it should be a parent // of the opaque we mapped from. Continue mapping. if matches!(self.def_kind(new_parent), DefKind::OpaqueTy) { - debug_assert_eq!(self.parent(parent.to_def_id()), new_parent); - opaque_lifetime_param_def_id = ebv.expect_local(); + debug_assert_eq!(self.local_parent(parent), new_parent); + opaque_lifetime_param_def_id = ebv; continue; } @@ -3050,20 +3050,20 @@ impl<'tcx> TyCtxt<'tcx> { self, ty::EarlyParamRegion { index: generics - .param_def_id_to_index(self, ebv) + .param_def_id_to_index(self, ebv.to_def_id()) .expect("early-bound var should be present in fn generics"), - name: self.hir().name(self.local_def_id_to_hir_id(ebv.expect_local())), + name: self.item_name(ebv.to_def_id()), }, ); } Some(resolve_bound_vars::ResolvedArg::LateBound(_, _, lbv)) => { - let new_parent = self.parent(lbv); + let new_parent = self.local_parent(lbv); return ty::Region::new_late_param( self, - new_parent, + new_parent.to_def_id(), ty::BoundRegionKind::BrNamed( - lbv, - self.hir().name(self.local_def_id_to_hir_id(lbv.expect_local())), + lbv.to_def_id(), + self.item_name(lbv.to_def_id()), ), ); } diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/find_anon_type.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/find_anon_type.rs index 3f35391be1355..cd61747917a88 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/find_anon_type.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/find_anon_type.rs @@ -101,7 +101,7 @@ impl<'tcx> Visitor<'tcx> for FindNestedTypeVisitor<'tcx> { // region at the right depth with the same index (Some(rbv::ResolvedArg::EarlyBound(id)), ty::BrNamed(def_id, _)) => { debug!("EarlyBound id={:?} def_id={:?}", id, def_id); - if id == def_id { + if id.to_def_id() == def_id { return ControlFlow::Break(arg); } } @@ -118,7 +118,7 @@ impl<'tcx> Visitor<'tcx> for FindNestedTypeVisitor<'tcx> { debruijn_index ); debug!("LateBound id={:?} def_id={:?}", id, def_id); - if debruijn_index == self.current_index && id == def_id { + if debruijn_index == self.current_index && id.to_def_id() == def_id { return ControlFlow::Break(arg); } } @@ -192,7 +192,7 @@ impl<'tcx> Visitor<'tcx> for TyPathVisitor<'tcx> { // the lifetime of the TyPath! (Some(rbv::ResolvedArg::EarlyBound(id)), ty::BrNamed(def_id, _)) => { debug!("EarlyBound id={:?} def_id={:?}", id, def_id); - if id == def_id { + if id.to_def_id() == def_id { return ControlFlow::Break(()); } } @@ -201,7 +201,7 @@ impl<'tcx> Visitor<'tcx> for TyPathVisitor<'tcx> { debug!("FindNestedTypeVisitor::visit_ty: LateBound depth = {:?}", debruijn_index,); debug!("id={:?}", id); debug!("def_id={:?}", def_id); - if debruijn_index == self.current_index && id == def_id { + if debruijn_index == self.current_index && id.to_def_id() == def_id { return ControlFlow::Break(()); } } diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index db81b4c4282a1..5260e363dd68c 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -272,7 +272,7 @@ fn clean_lifetime<'tcx>(lifetime: &hir::Lifetime, cx: &mut DocContext<'tcx>) -> | rbv::ResolvedArg::LateBound(_, _, did) | rbv::ResolvedArg::Free(_, did), ) = cx.tcx.named_bound_var(lifetime.hir_id) - && let Some(lt) = cx.args.get(&did).and_then(|arg| arg.as_lt()) + && let Some(lt) = cx.args.get(&did.to_def_id()).and_then(|arg| arg.as_lt()) { return lt.clone(); } From 57b164a9d2ee90ddf46bfe7b3a40d28bcd04b9c1 Mon Sep 17 00:00:00 2001 From: Amjad Alsharafi <26300843+Amjad50@users.noreply.github.com> Date: Thu, 22 Aug 2024 14:26:00 +0800 Subject: [PATCH 3/9] Update `compiler_builtins` to `0.1.120` Signed-off-by: Amjad Alsharafi <26300843+Amjad50@users.noreply.github.com> --- library/Cargo.lock | 4 ++-- library/alloc/Cargo.toml | 2 +- library/std/Cargo.toml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/library/Cargo.lock b/library/Cargo.lock index 30f5076e1e223..f2f446b61085d 100644 --- a/library/Cargo.lock +++ b/library/Cargo.lock @@ -58,9 +58,9 @@ dependencies = [ [[package]] name = "compiler_builtins" -version = "0.1.118" +version = "0.1.120" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92afe7344b64cccf3662ca26d5d1c0828ab826f04206b97d856e3625e390e4b5" +checksum = "38c44e9c76d996d8049dee591a997eab801069ad86ed892ed3039f68b73d301c" dependencies = [ "cc", "rustc-std-workspace-core", diff --git a/library/alloc/Cargo.toml b/library/alloc/Cargo.toml index bdf16257c7cd0..43799acc02736 100644 --- a/library/alloc/Cargo.toml +++ b/library/alloc/Cargo.toml @@ -10,7 +10,7 @@ edition = "2021" [dependencies] core = { path = "../core" } -compiler_builtins = { version = "0.1.118", features = ['rustc-dep-of-std'] } +compiler_builtins = { version = "0.1.120", features = ['rustc-dep-of-std'] } [dev-dependencies] rand = { version = "0.8.5", default-features = false, features = ["alloc"] } diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 7f23681ee45fc..dca42a3e98ec1 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -17,7 +17,7 @@ cfg-if = { version = "1.0", features = ['rustc-dep-of-std'] } panic_unwind = { path = "../panic_unwind", optional = true } panic_abort = { path = "../panic_abort" } core = { path = "../core", public = true } -compiler_builtins = { version = "0.1.118" } +compiler_builtins = { version = "0.1.120" } profiler_builtins = { path = "../profiler_builtins", optional = true } unwind = { path = "../unwind" } hashbrown = { version = "0.14", default-features = false, features = [ From e276d22efc1443772434981a69f974ad4984fd2d Mon Sep 17 00:00:00 2001 From: Oneirical Date: Tue, 13 Aug 2024 11:33:01 -0400 Subject: [PATCH 4/9] rewrite x86_64-fortanix-unknown-sgx-lvi to rmake --- src/tools/run-make-support/src/env.rs | 8 ++ src/tools/run-make-support/src/lib.rs | 2 +- .../tidy/src/allowed_run_make_makefiles.txt | 1 - .../x86_64-fortanix-unknown-sgx-lvi/Makefile | 23 ----- .../x86_64-fortanix-unknown-sgx-lvi/rmake.rs | 96 +++++++++++++++++++ .../x86_64-fortanix-unknown-sgx-lvi/script.sh | 69 ------------- 6 files changed, 105 insertions(+), 94 deletions(-) delete mode 100644 tests/run-make/x86_64-fortanix-unknown-sgx-lvi/Makefile create mode 100644 tests/run-make/x86_64-fortanix-unknown-sgx-lvi/rmake.rs delete mode 100644 tests/run-make/x86_64-fortanix-unknown-sgx-lvi/script.sh diff --git a/src/tools/run-make-support/src/env.rs b/src/tools/run-make-support/src/env.rs index e6460fb93d3e9..9acbb16d73e76 100644 --- a/src/tools/run-make-support/src/env.rs +++ b/src/tools/run-make-support/src/env.rs @@ -24,3 +24,11 @@ pub fn env_var_os(name: &str) -> OsString { pub fn no_debug_assertions() -> bool { std::env::var_os("NO_DEBUG_ASSERTIONS").is_some() } + +/// A wrapper around [`std::env::set_current_dir`] which includes the directory +/// path in the panic message. +#[track_caller] +pub fn set_current_dir>(dir: P) { + std::env::set_current_dir(dir.as_ref()) + .expect(&format!("could not set current directory to \"{}\"", dir.as_ref().display())); +} diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index fc20fd3b2e86a..956fa1404c7e2 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -64,7 +64,7 @@ pub use rustdoc::{bare_rustdoc, rustdoc, Rustdoc}; pub use diff::{diff, Diff}; /// Panic-on-fail [`std::env::var`] and [`std::env::var_os`] wrappers. -pub use env::{env_var, env_var_os}; +pub use env::{env_var, env_var_os, set_current_dir}; /// Convenience helpers for running binaries and other commands. pub use run::{cmd, run, run_fail, run_with_args}; diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index f55abb513b80d..05e8af5e1c5ce 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -11,4 +11,3 @@ run-make/macos-deployment-target/Makefile run-make/split-debuginfo/Makefile run-make/symbol-mangling-hashed/Makefile run-make/translation/Makefile -run-make/x86_64-fortanix-unknown-sgx-lvi/Makefile diff --git a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/Makefile b/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/Makefile deleted file mode 100644 index 3c88ec34f431e..0000000000000 --- a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/Makefile +++ /dev/null @@ -1,23 +0,0 @@ -include ../tools.mk - -#only-x86_64-fortanix-unknown-sgx - -# For cargo setting -export RUSTC := $(RUSTC_ORIGINAL) -export LD_LIBRARY_PATH := $(HOST_RPATH_DIR) -# We need to be outside of 'src' dir in order to run cargo -export WORK_DIR := $(TMPDIR) -export TEST_DIR := $(shell pwd) - -## clean up unused env variables which might cause harm. -unexport RUSTC_LINKER -unexport RUSTC_BOOTSTRAP -unexport RUST_BUILD_STAGE -unexport RUST_TEST_THREADS -unexport RUST_TEST_TMPDIR -unexport AR -unexport CC -unexport CXX - -all: - bash script.sh diff --git a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/rmake.rs b/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/rmake.rs new file mode 100644 index 0000000000000..130781a429371 --- /dev/null +++ b/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/rmake.rs @@ -0,0 +1,96 @@ +// ignore-tidy-linelength +// Reason: intel.com link + +// This security test checks that the disassembled form of certain symbols +// is "hardened" - that means, the assembly instructions match a pattern that +// mitigate potential Load Value Injection vulnerabilities. +// To do so, a test crate is compiled, and certain symbols are found, disassembled +// and checked one by one. +// See https://github.com/rust-lang/rust/pull/77008 + +// On load value injection: +// https://www.intel.com/content/www/us/en/developer/articles/technical/software-security-guidance/technical-documentation/load-value-injection.html + +//@ only-x86_64-fortanix-unknown-sgx + +use run_make_support::{cmd, cwd, llvm_filecheck, llvm_objdump, regex, set_current_dir, target}; + +fn main() { + let main_dir = cwd(); + set_current_dir("enclave"); + // HACK(eddyb) sets `RUSTC_BOOTSTRAP=1` so Cargo can accept nightly features. + // These come from the top-level Rust workspace, that this crate is not a + // member of, but Cargo tries to load the workspace `Cargo.toml` anyway. + cmd("cargo") + .env("RUSTC_BOOTSTRAP", "1") + .arg("-v") + .arg("run") + .arg("--target") + .arg(target()) + .run(); + set_current_dir(&main_dir); + // Rust has various ways of adding code to a binary: + // - Rust code + // - Inline assembly + // - Global assembly + // - C/C++ code compiled as part of Rust crates + // For those different kinds, we do have very small code examples that should be + // mitigated in some way. Mostly we check that ret instructions should no longer be present. + check("unw_getcontext", "unw_getcontext.checks"); + check("__libunwind_Registers_x86_64_jumpto", "jumpto.checks"); + + check("std::io::stdio::_print::[[:alnum:]]+", "print.with_frame_pointers.checks"); + + check("rust_plus_one_global_asm", "rust_plus_one_global_asm.checks"); + + check("cc_plus_one_c", "cc_plus_one_c.checks"); + check("cc_plus_one_c_asm", "cc_plus_one_c_asm.checks"); + check("cc_plus_one_cxx", "cc_plus_one_cxx.checks"); + check("cc_plus_one_cxx_asm", "cc_plus_one_cxx_asm.checks"); + check("cc_plus_one_asm", "cc_plus_one_asm.checks"); + + check("cmake_plus_one_c", "cmake_plus_one_c.checks"); + check("cmake_plus_one_c_asm", "cmake_plus_one_c_asm.checks"); + check("cmake_plus_one_c_global_asm", "cmake_plus_one_c_global_asm.checks"); + check("cmake_plus_one_cxx", "cmake_plus_one_cxx.checks"); + check("cmake_plus_one_cxx_asm", "cmake_plus_one_cxx_asm.checks"); + check("cmake_plus_one_cxx_global_asm", "cmake_plus_one_cxx_global_asm.checks"); + check("cmake_plus_one_asm", "cmake_plus_one_asm.checks"); +} + +fn check(func_re: &str, mut checks: &str) { + let dump = llvm_objdump() + .input("enclave/target/x86_64-fortanix-unknown-sgx/debug/enclave") + .args(&["--syms", "--demangle"]) + .run() + .stdout_utf8(); + let re = regex::Regex::new(&format!("[[:blank:]]+{func_re}")).unwrap(); + let func = re.find_iter(&dump).map(|m| m.as_str().trim()).collect::>().join(","); + assert!(!func.is_empty()); + let dump = llvm_objdump() + .input("enclave/target/x86_64-fortanix-unknown-sgx/debug/enclave") + .args(&["--demangle", &format!("--disassemble-symbols={func}")]) + .run() + .stdout_utf8(); + let dump = dump.as_bytes(); + + // Unique case, must succeed at one of two possible tests. + // This is because frame pointers are optional, and them being enabled requires + // an additional `popq` in the pattern checking file. + if func_re == "std::io::stdio::_print::[[:alnum:]]+" { + let output = llvm_filecheck().stdin(&dump).patterns(checks).run_unchecked(); + if !output.status().success() { + checks = "print.without_frame_pointers.checks"; + llvm_filecheck().stdin(&dump).patterns(checks).run(); + } + } else { + llvm_filecheck().stdin(&dump).patterns(checks).run(); + } + if !["rust_plus_one_global_asm", "cmake_plus_one_c_global_asm", "cmake_plus_one_cxx_global_asm"] + .contains(&func_re) + { + // The assembler cannot avoid explicit `ret` instructions. Sequences + // of `shlq $0x0, (%rsp); lfence; retq` are used instead. + llvm_filecheck().args(&["--implicit-check-not", "ret"]).stdin(dump).patterns(checks).run(); + } +} diff --git a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/script.sh b/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/script.sh deleted file mode 100644 index a7c4ae13ecb38..0000000000000 --- a/tests/run-make/x86_64-fortanix-unknown-sgx-lvi/script.sh +++ /dev/null @@ -1,69 +0,0 @@ -#!/bin/bash -set -exuo pipefail - -function build { - CRATE=enclave - - mkdir -p "${WORK_DIR}" - pushd "${WORK_DIR}" - rm -rf "${CRATE}" - cp -a "${TEST_DIR}"/enclave . - pushd $CRATE - echo "${WORK_DIR}" - # HACK(eddyb) sets `RUSTC_BOOTSTRAP=1` so Cargo can accept nightly features. - # These come from the top-level Rust workspace, that this crate is not a - # member of, but Cargo tries to load the workspace `Cargo.toml` anyway. - env RUSTC_BOOTSTRAP=1 - cargo -v run --target "${TARGET}" - popd - popd -} - -function check { - local func_re="$1" - local checks="${TEST_DIR}/$2" - local asm="" - local objdump="${LLVM_BIN_DIR}/llvm-objdump" - local filecheck="${LLVM_BIN_DIR}/FileCheck" - local enclave=${WORK_DIR}/enclave/target/x86_64-fortanix-unknown-sgx/debug/enclave - - asm=$(mktemp) - func="$(${objdump} --syms --demangle "${enclave}" | \ - grep --only-matching -E "[[:blank:]]+${func_re}\$" | \ - sed -e 's/^[[:space:]]*//' )" - ${objdump} --disassemble-symbols="${func}" --demangle \ - "${enclave}" > "${asm}" - ${filecheck} --input-file "${asm}" "${checks}" - - if [ "${func_re}" != "rust_plus_one_global_asm" ] && - [ "${func_re}" != "cmake_plus_one_c_global_asm" ] && - [ "${func_re}" != "cmake_plus_one_cxx_global_asm" ]; then - # The assembler cannot avoid explicit `ret` instructions. Sequences - # of `shlq $0x0, (%rsp); lfence; retq` are used instead. - # https://www.intel.com/content/www/us/en/developer/articles/technical/ - # software-security-guidance/technical-documentation/load-value-injection.html - ${filecheck} --implicit-check-not ret --input-file "${asm}" "${checks}" - fi -} - -build - -check "unw_getcontext" unw_getcontext.checks -check "__libunwind_Registers_x86_64_jumpto" jumpto.checks -check 'std::io::stdio::_print::[[:alnum:]]+' print.with_frame_pointers.checks || - check 'std::io::stdio::_print::[[:alnum:]]+' print.without_frame_pointers.checks -check rust_plus_one_global_asm rust_plus_one_global_asm.checks - -check cc_plus_one_c cc_plus_one_c.checks -check cc_plus_one_c_asm cc_plus_one_c_asm.checks -check cc_plus_one_cxx cc_plus_one_cxx.checks -check cc_plus_one_cxx_asm cc_plus_one_cxx_asm.checks -check cc_plus_one_asm cc_plus_one_asm.checks - -check cmake_plus_one_c cmake_plus_one_c.checks -check cmake_plus_one_c_asm cmake_plus_one_c_asm.checks -check cmake_plus_one_c_global_asm cmake_plus_one_c_global_asm.checks -check cmake_plus_one_cxx cmake_plus_one_cxx.checks -check cmake_plus_one_cxx_asm cmake_plus_one_cxx_asm.checks -check cmake_plus_one_cxx_global_asm cmake_plus_one_cxx_global_asm.checks -check cmake_plus_one_asm cmake_plus_one_asm.checks From 8eb15586c6472077916730ca994e7bd5def09220 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 22 Aug 2024 12:34:06 -0400 Subject: [PATCH 5/9] Don't trigger refinement lint if predicates reference errors --- .../src/check/compare_impl_item/refine.rs | 7 ++++++- tests/ui/impl-trait/in-trait/refine-err.rs | 14 ++++++++++++++ .../ui/impl-trait/in-trait/refine-err.stderr | 9 +++++++++ .../in-trait/span-bug-issue-121457.rs | 1 - .../in-trait/span-bug-issue-121457.stderr | 19 +------------------ 5 files changed, 30 insertions(+), 20 deletions(-) create mode 100644 tests/ui/impl-trait/in-trait/refine-err.rs create mode 100644 tests/ui/impl-trait/in-trait/refine-err.stderr diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs index 80daaa60324a3..d2b7ede65234f 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs @@ -7,7 +7,8 @@ use rustc_lint_defs::builtin::{REFINING_IMPL_TRAIT_INTERNAL, REFINING_IMPL_TRAIT use rustc_middle::span_bug; use rustc_middle::traits::{ObligationCause, Reveal}; use rustc_middle::ty::{ - self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperVisitable, TypeVisitable, TypeVisitor, + self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperVisitable, TypeVisitable, + TypeVisitableExt, TypeVisitor, }; use rustc_span::Span; use rustc_trait_selection::regions::InferCtxtRegionExt; @@ -177,6 +178,10 @@ pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>( return; }; + if trait_bounds.references_error() || impl_bounds.references_error() { + return; + } + // For quicker lookup, use an `IndexSet` (we don't use one earlier because // it's not foldable..). // Also, We have to anonymize binders in these types because they may contain diff --git a/tests/ui/impl-trait/in-trait/refine-err.rs b/tests/ui/impl-trait/in-trait/refine-err.rs new file mode 100644 index 0000000000000..7518cee97c444 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/refine-err.rs @@ -0,0 +1,14 @@ +#![deny(refining_impl_trait)] + +trait FromRow { + fn prepare(self) -> impl Fn() -> T; + //~^ ERROR cannot find type `T` in this scope +} + +impl FromRow for T { + fn prepare(self) -> impl Fn() -> T { + || todo!() + } +} + +fn main() {} diff --git a/tests/ui/impl-trait/in-trait/refine-err.stderr b/tests/ui/impl-trait/in-trait/refine-err.stderr new file mode 100644 index 0000000000000..6b4ef74d50afc --- /dev/null +++ b/tests/ui/impl-trait/in-trait/refine-err.stderr @@ -0,0 +1,9 @@ +error[E0412]: cannot find type `T` in this scope + --> $DIR/refine-err.rs:4:38 + | +LL | fn prepare(self) -> impl Fn() -> T; + | ^ not found in this scope + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0412`. diff --git a/tests/ui/impl-trait/in-trait/span-bug-issue-121457.rs b/tests/ui/impl-trait/in-trait/span-bug-issue-121457.rs index 7a51037324f28..ab21dae7dc50d 100644 --- a/tests/ui/impl-trait/in-trait/span-bug-issue-121457.rs +++ b/tests/ui/impl-trait/in-trait/span-bug-issue-121457.rs @@ -14,7 +14,6 @@ impl<'a, I: 'a + Iterable> Iterable for &'a I { //~^ ERROR binding for associated type `Item` references lifetime `'missing` //~| ERROR binding for associated type `Item` references lifetime `'missing` //~| ERROR `()` is not an iterator - //~| WARNING impl trait in impl method signature does not match trait method signature } fn main() {} diff --git a/tests/ui/impl-trait/in-trait/span-bug-issue-121457.stderr b/tests/ui/impl-trait/in-trait/span-bug-issue-121457.stderr index 67c4df0f3a9eb..d8a2eef94a180 100644 --- a/tests/ui/impl-trait/in-trait/span-bug-issue-121457.stderr +++ b/tests/ui/impl-trait/in-trait/span-bug-issue-121457.stderr @@ -32,24 +32,7 @@ LL | fn iter(&self) -> impl for<'missing> Iterator $DIR/span-bug-issue-121457.rs:13:51 - | -LL | fn iter(&self) -> impl Iterator; - | ------------- return type from trait method defined here -... -LL | fn iter(&self) -> impl for<'missing> Iterator> {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ this bound is stronger than that defined on the trait - | - = note: add `#[allow(refining_impl_trait)]` if it is intended for this to be part of the public API of this crate - = note: we are soliciting feedback, see issue #121718 for more information - = note: `#[warn(refining_impl_trait_reachable)]` on by default -help: replace the return type so that it matches the trait - | -LL | fn iter(&self) -> impl Iterator {} - | ~~~~~~~~~~~~~ - -error: aborting due to 4 previous errors; 1 warning emitted +error: aborting due to 4 previous errors Some errors have detailed explanations: E0195, E0277, E0582. For more information about an error, try `rustc --explain E0195`. From 736f773844e7ebf05ccb827c17b7ad9eb28aa295 Mon Sep 17 00:00:00 2001 From: binarycat Date: Thu, 11 Jul 2024 15:44:58 -0400 Subject: [PATCH 6/9] fix: fs::remove_dir_all: treat ENOENT as success fixes #127576 windows implementation still needs some work --- library/std/src/fs.rs | 2 + library/std/src/sys/pal/solid/fs.rs | 23 +++++--- library/std/src/sys/pal/unix/fs.rs | 49 +++++++++++----- library/std/src/sys/pal/wasi/fs.rs | 20 +++++-- library/std/src/sys/pal/windows/fs.rs | 4 +- library/std/src/sys_common/fs.rs | 21 +++++-- library/std/src/sys_common/mod.rs | 8 +++ tests/run-make/remove-dir-all-race/rmake.rs | 62 +++++++++++++++++++++ 8 files changed, 153 insertions(+), 36 deletions(-) create mode 100644 tests/run-make/remove-dir-all-race/rmake.rs diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index c5edb03bb08be..6a0d9f47960ec 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -2491,6 +2491,8 @@ pub fn remove_dir>(path: P) -> io::Result<()> { /// /// Consider ignoring the error if validating the removal is not required for your use case. /// +/// [`io::ErrorKind::NotFound`] is only returned if no removal occurs. +/// /// [`fs::remove_file`]: remove_file /// [`fs::remove_dir`]: remove_dir /// diff --git a/library/std/src/sys/pal/solid/fs.rs b/library/std/src/sys/pal/solid/fs.rs index 8179ec8821a38..591be66fcb463 100644 --- a/library/std/src/sys/pal/solid/fs.rs +++ b/library/std/src/sys/pal/solid/fs.rs @@ -10,6 +10,7 @@ use crate::sync::Arc; use crate::sys::time::SystemTime; use crate::sys::unsupported; pub use crate::sys_common::fs::exists; +use crate::sys_common::ignore_notfound; /// A file descriptor. #[derive(Clone, Copy)] @@ -527,15 +528,23 @@ pub fn rmdir(p: &Path) -> io::Result<()> { pub fn remove_dir_all(path: &Path) -> io::Result<()> { for child in readdir(path)? { - let child = child?; - let child_type = child.file_type()?; - if child_type.is_dir() { - remove_dir_all(&child.path())?; - } else { - unlink(&child.path())?; + let result: io::Result<()> = try { + let child = child?; + let child_type = child.file_type()?; + if child_type.is_dir() { + remove_dir_all(&child.path())?; + } else { + unlink(&child.path())?; + } + }; + // ignore internal NotFound errors + if let Err(err) = result + && err.kind() != io::ErrorKind::NotFound + { + return result; } } - rmdir(path) + ignore_notfound(rmdir(path)) } pub fn readlink(p: &Path) -> io::Result { diff --git a/library/std/src/sys/pal/unix/fs.rs b/library/std/src/sys/pal/unix/fs.rs index bdb83f0785784..acd9c338f05a6 100644 --- a/library/std/src/sys/pal/unix/fs.rs +++ b/library/std/src/sys/pal/unix/fs.rs @@ -2029,6 +2029,7 @@ mod remove_dir_impl { use crate::path::{Path, PathBuf}; use crate::sys::common::small_c_string::run_path_with_cstr; use crate::sys::{cvt, cvt_r}; + use crate::sys_common::ignore_notfound; pub fn openat_nofollow_dironly(parent_fd: Option, p: &CStr) -> io::Result { let fd = cvt_r(|| unsafe { @@ -2082,6 +2083,16 @@ mod remove_dir_impl { } } + fn is_enoent(result: &io::Result<()>) -> bool { + if let Err(err) = result + && matches!(err.raw_os_error(), Some(libc::ENOENT)) + { + true + } else { + false + } + } + fn remove_dir_all_recursive(parent_fd: Option, path: &CStr) -> io::Result<()> { // try opening as directory let fd = match openat_nofollow_dironly(parent_fd, &path) { @@ -2105,27 +2116,35 @@ mod remove_dir_impl { for child in dir { let child = child?; let child_name = child.name_cstr(); - match is_dir(&child) { - Some(true) => { - remove_dir_all_recursive(Some(fd), child_name)?; - } - Some(false) => { - cvt(unsafe { unlinkat(fd, child_name.as_ptr(), 0) })?; - } - None => { - // POSIX specifies that calling unlink()/unlinkat(..., 0) on a directory can succeed - // if the process has the appropriate privileges. This however can causing orphaned - // directories requiring an fsck e.g. on Solaris and Illumos. So we try recursing - // into it first instead of trying to unlink() it. - remove_dir_all_recursive(Some(fd), child_name)?; + // we need an inner try block, because if one of these + // directories has already been deleted, then we need to + // continue the loop, not return ok. + let result: io::Result<()> = try { + match is_dir(&child) { + Some(true) => { + remove_dir_all_recursive(Some(fd), child_name)?; + } + Some(false) => { + cvt(unsafe { unlinkat(fd, child_name.as_ptr(), 0) })?; + } + None => { + // POSIX specifies that calling unlink()/unlinkat(..., 0) on a directory can succeed + // if the process has the appropriate privileges. This however can causing orphaned + // directories requiring an fsck e.g. on Solaris and Illumos. So we try recursing + // into it first instead of trying to unlink() it. + remove_dir_all_recursive(Some(fd), child_name)?; + } } + }; + if result.is_err() && !is_enoent(&result) { + return result; } } // unlink the directory after removing its contents - cvt(unsafe { + ignore_notfound(cvt(unsafe { unlinkat(parent_fd.unwrap_or(libc::AT_FDCWD), path.as_ptr(), libc::AT_REMOVEDIR) - })?; + }))?; Ok(()) } diff --git a/library/std/src/sys/pal/wasi/fs.rs b/library/std/src/sys/pal/wasi/fs.rs index 11900886f0b5c..7064473f274e6 100644 --- a/library/std/src/sys/pal/wasi/fs.rs +++ b/library/std/src/sys/pal/wasi/fs.rs @@ -13,7 +13,7 @@ use crate::sys::common::small_c_string::run_path_with_cstr; use crate::sys::time::SystemTime; use crate::sys::unsupported; pub use crate::sys_common::fs::exists; -use crate::sys_common::{AsInner, FromInner, IntoInner}; +use crate::sys_common::{ignore_notfound, AsInner, FromInner, IntoInner}; use crate::{fmt, iter, ptr}; pub struct File { @@ -794,14 +794,22 @@ fn remove_dir_all_recursive(parent: &WasiFd, path: &Path) -> io::Result<()> { io::const_io_error!(io::ErrorKind::Uncategorized, "invalid utf-8 file name found") })?; - if entry.file_type()?.is_dir() { - remove_dir_all_recursive(&entry.inner.dir.fd, path.as_ref())?; - } else { - entry.inner.dir.fd.unlink_file(path)?; + let result: io::Result<()> = try { + if entry.file_type()?.is_dir() { + remove_dir_all_recursive(&entry.inner.dir.fd, path.as_ref())?; + } else { + entry.inner.dir.fd.unlink_file(path)?; + } + }; + // ignore internal NotFound errors + if let Err(err) = &result + && err.kind() != io::ErrorKind::NotFound + { + return result; } } // Once all this directory's contents are deleted it should be safe to // delete the directory tiself. - parent.remove_directory(osstr2str(path.as_ref())?) + ignore_notfound(parent.remove_directory(osstr2str(path.as_ref())?)) } diff --git a/library/std/src/sys/pal/windows/fs.rs b/library/std/src/sys/pal/windows/fs.rs index d99d4931de40f..2134152ea93f1 100644 --- a/library/std/src/sys/pal/windows/fs.rs +++ b/library/std/src/sys/pal/windows/fs.rs @@ -14,7 +14,7 @@ use crate::sys::handle::Handle; use crate::sys::path::maybe_verbatim; use crate::sys::time::SystemTime; use crate::sys::{c, cvt, Align8}; -use crate::sys_common::{AsInner, FromInner, IntoInner}; +use crate::sys_common::{ignore_notfound, AsInner, FromInner, IntoInner}; use crate::{fmt, ptr, slice, thread}; pub struct File { @@ -1160,7 +1160,7 @@ pub fn remove_dir_all(path: &Path) -> io::Result<()> { return Err(io::Error::from_raw_os_error(c::ERROR_DIRECTORY as _)); } - match remove_dir_all_iterative(&file, File::posix_delete) { + match ignore_notfound(remove_dir_all_iterative(&file, File::posix_delete)) { Err(e) => { if let Some(code) = e.raw_os_error() { match code as u32 { diff --git a/library/std/src/sys_common/fs.rs b/library/std/src/sys_common/fs.rs index acb6713cf1b14..a25a7244660bb 100644 --- a/library/std/src/sys_common/fs.rs +++ b/library/std/src/sys_common/fs.rs @@ -3,6 +3,7 @@ use crate::fs; use crate::io::{self, Error, ErrorKind}; use crate::path::Path; +use crate::sys_common::ignore_notfound; pub(crate) const NOT_FILE_ERROR: Error = io::const_io_error!( ErrorKind::InvalidInput, @@ -32,14 +33,22 @@ pub fn remove_dir_all(path: &Path) -> io::Result<()> { fn remove_dir_all_recursive(path: &Path) -> io::Result<()> { for child in fs::read_dir(path)? { - let child = child?; - if child.file_type()?.is_dir() { - remove_dir_all_recursive(&child.path())?; - } else { - fs::remove_file(&child.path())?; + let result: io::Result<()> = try { + let child = child?; + if child.file_type()?.is_dir() { + remove_dir_all_recursive(&child.path())?; + } else { + fs::remove_file(&child.path())?; + } + }; + // ignore internal NotFound errors to prevent race conditions + if let Err(err) = &result + && err.kind() != io::ErrorKind::NotFound + { + return result; } } - fs::remove_dir(path) + ignore_notfound(fs::remove_dir(path)) } pub fn exists(path: &Path) -> io::Result { diff --git a/library/std/src/sys_common/mod.rs b/library/std/src/sys_common/mod.rs index 60ee405ecaaa2..1c884f107beeb 100644 --- a/library/std/src/sys_common/mod.rs +++ b/library/std/src/sys_common/mod.rs @@ -80,3 +80,11 @@ pub fn mul_div_u64(value: u64, numer: u64, denom: u64) -> u64 { // r < denom, so (denom*numer) is the upper bound of (r*numer) q * numer + r * numer / denom } + +pub fn ignore_notfound(result: crate::io::Result) -> crate::io::Result<()> { + match result { + Err(err) if err.kind() == crate::io::ErrorKind::NotFound => Ok(()), + Ok(_) => Ok(()), + Err(err) => Err(err), + } +} diff --git a/tests/run-make/remove-dir-all-race/rmake.rs b/tests/run-make/remove-dir-all-race/rmake.rs new file mode 100644 index 0000000000000..03c94b76127d5 --- /dev/null +++ b/tests/run-make/remove-dir-all-race/rmake.rs @@ -0,0 +1,62 @@ +//@ ignore-windows + +// This test attempts to make sure that running `remove_dir_all` +// doesn't result in a NotFound error one of the files it +// is deleting is deleted concurrently. +// +// The windows implementation for `remove_dir_all` is significantly +// more complicated, and has not yet been brought up to par with +// the implementation on other platforms, so this test is marked as +// `ignore-windows` until someone more expirenced with windows can +// sort that out. + +use std::fs::remove_dir_all; +use std::path::Path; +use std::thread; +use std::time::Duration; + +use run_make_support::rfs::{create_dir, write}; +use run_make_support::run_in_tmpdir; + +fn main() { + let mut race_happened = false; + run_in_tmpdir(|| { + for i in 0..150 { + create_dir("outer"); + create_dir("outer/inner"); + write("outer/inner.txt", b"sometext"); + + thread::scope(|scope| { + let t1 = scope.spawn(|| { + thread::sleep(Duration::from_nanos(i)); + remove_dir_all("outer").unwrap(); + }); + + let race_happened_ref = &race_happened; + let t2 = scope.spawn(|| { + let r1 = remove_dir_all("outer/inner"); + let r2 = remove_dir_all("outer/inner.txt"); + if r1.is_ok() && r2.is_err() { + race_happened = true; + } + }); + }); + + assert!(!Path::new("outer").exists()); + + // trying to remove a nonexistant top-level directory should + // still result in an error. + let Err(err) = remove_dir_all("outer") else { + panic!("removing nonexistant dir did not result in an error"); + }; + assert_eq!(err.kind(), std::io::ErrorKind::NotFound); + } + }); + if !race_happened { + eprintln!( + "WARNING: multithreaded deletion never raced, \ + try increasing the number of attempts or \ + adjusting the sleep timing" + ); + } +} From e37e15dc0bd9e4a21ced7a5c534c4c64dc3dfeda Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 22 Aug 2024 18:05:11 +0200 Subject: [PATCH 7/9] Fix extern crates not being hidden with `doc(hidden)` --- src/librustdoc/passes/strip_hidden.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/librustdoc/passes/strip_hidden.rs b/src/librustdoc/passes/strip_hidden.rs index faf42b3aab13e..23e298571d5ce 100644 --- a/src/librustdoc/passes/strip_hidden.rs +++ b/src/librustdoc/passes/strip_hidden.rs @@ -2,7 +2,7 @@ use std::mem; -use rustc_hir::def_id::LocalDefId; +use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID}; use rustc_middle::ty::TyCtxt; use rustc_span::symbol::sym; @@ -145,8 +145,9 @@ impl<'a, 'tcx> DocFolder for Stripper<'a, 'tcx> { let old = mem::replace(&mut self.update_retained, false); let ret = self.set_is_in_hidden_item_and_fold(true, i); self.update_retained = old; - if ret.is_crate() { - // We don't strip the crate, even if it has `#[doc(hidden)]`. + if ret.item_id == clean::ItemId::DefId(CRATE_DEF_ID.into()) { + // We don't strip the current crate, even if it has `#[doc(hidden)]`. + debug!("strip_hidden: Not strippping local crate"); Some(ret) } else { Some(strip_item(ret)) From 4de29c90478003ce28880e92986ee7f2fc9c2d33 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 22 Aug 2024 18:05:52 +0200 Subject: [PATCH 8/9] Add regression test for #126796 --- tests/rustdoc/doc-hidden-crate.rs | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 tests/rustdoc/doc-hidden-crate.rs diff --git a/tests/rustdoc/doc-hidden-crate.rs b/tests/rustdoc/doc-hidden-crate.rs new file mode 100644 index 0000000000000..dac557107a903 --- /dev/null +++ b/tests/rustdoc/doc-hidden-crate.rs @@ -0,0 +1,27 @@ +// Regression test for . +// `doc(hidden)` should still be able to hide extern crates, only the local crates +// cannot be hidden because we still need to generate its `index.html` file. + +#![crate_name = "foo"] +#![doc(hidden)] + +//@ has 'foo/index.html' +// First we check that the page contains the crate name (`foo`). +//@ has - '//*' 'foo' +// But doesn't contain any of the other items. +//@ !has - '//*' 'other' +//@ !has - '//*' 'marker' +//@ !has - '//*' 'PhantomData' + +#[doc(inline)] +pub use std as other; + +#[doc(inline)] +pub use std::marker; + +#[doc(inline)] +pub use std::marker::PhantomData; + +//@ !has - '//*' 'myself' +#[doc(inline)] +pub use crate as myself; From 9ad0b15a8e3e199a73bcf32ab9e56f7caa1f14a7 Mon Sep 17 00:00:00 2001 From: Pavel Grigorenko Date: Fri, 23 Aug 2024 02:44:15 +0300 Subject: [PATCH 9/9] Fix a missing import in a doc in run-make-support --- src/tools/run-make-support/src/path_helpers.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tools/run-make-support/src/path_helpers.rs b/src/tools/run-make-support/src/path_helpers.rs index 1e6e44c458423..87901793a921e 100644 --- a/src/tools/run-make-support/src/path_helpers.rs +++ b/src/tools/run-make-support/src/path_helpers.rs @@ -21,6 +21,7 @@ pub fn cwd() -> PathBuf { /// # Example /// /// ```rust +/// # use run_make_support::path; /// let p = path("support_file.txt"); /// ``` pub fn path>(p: P) -> PathBuf {