diff --git a/compiler/rustc_builtin_macros/src/edition_panic.rs b/compiler/rustc_builtin_macros/src/edition_panic.rs index b39c9861fd643..ccfcc3079ebf8 100644 --- a/compiler/rustc_builtin_macros/src/edition_panic.rs +++ b/compiler/rustc_builtin_macros/src/edition_panic.rs @@ -74,11 +74,11 @@ pub(crate) fn use_panic_2021(mut span: Span) -> bool { // (To avoid using the edition of e.g. the assert!() or debug_assert!() definition.) loop { let expn = span.ctxt().outer_expn_data(); - if let Some(features) = expn.allow_internal_unstable { - if features.iter().any(|&f| f == sym::edition_panic) { - span = expn.call_site; - continue; - } + if let Some(features) = expn.allow_internal_unstable + && features.contains(&sym::edition_panic) + { + span = expn.call_site; + continue; } break expn.edition >= Edition::Edition2021; } diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 216a18e72edff..ccc0273280fe3 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -2186,7 +2186,7 @@ fn msvc_imps_needed(tcx: TyCtxt<'_>) -> bool { // indirectly from ThinLTO. In theory these are not needed as ThinLTO could resolve // these, but it currently does not do so. let can_have_static_objects = - tcx.sess.lto() == Lto::Thin || tcx.crate_types().iter().any(|ct| *ct == CrateType::Rlib); + tcx.sess.lto() == Lto::Thin || tcx.crate_types().contains(&CrateType::Rlib); tcx.sess.target.is_like_windows && can_have_static_objects && diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index d16d4ed228389..a85d032f36eee 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -604,7 +604,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { if let Some((name, _)) = lang_items::extract(attrs) && let Some(lang_item) = LangItem::from_name(name) { - if WEAK_LANG_ITEMS.iter().any(|&l| l == lang_item) { + if WEAK_LANG_ITEMS.contains(&lang_item) { codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL; } if let Some(link_name) = lang_item.link_name() { diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs index c71a5ea8b9761..6fb289235de96 100644 --- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs @@ -1,6 +1,9 @@ //! A different sort of visitor for walking fn bodies. Unlike the //! normal visitor, which just walks the entire body in one shot, the //! `ExprUseVisitor` determines how expressions are being used. +//! +//! In the compiler, this is only used for upvar inference, but there +//! are many uses within clippy. use std::cell::{Ref, RefCell}; use std::ops::Deref; @@ -25,7 +28,7 @@ use rustc_middle::ty::{ use rustc_middle::{bug, span_bug}; use rustc_span::{ErrorGuaranteed, Span}; use rustc_trait_selection::infer::InferCtxtExt; -use tracing::{debug, trace}; +use tracing::{debug, instrument, trace}; use crate::fn_ctxt::FnCtxt; @@ -35,11 +38,8 @@ pub trait Delegate<'tcx> { /// The value found at `place` is moved, depending /// on `mode`. Where `diag_expr_id` is the id used for diagnostics for `place`. /// - /// Use of a `Copy` type in a ByValue context is considered a use - /// by `ImmBorrow` and `borrow` is called instead. This is because - /// a shared borrow is the "minimum access" that would be needed - /// to perform a copy. - /// + /// If the value is `Copy`, [`copy`][Self::copy] is called instead, which + /// by default falls back to [`borrow`][Self::borrow]. /// /// The parameter `diag_expr_id` indicates the HIR id that ought to be used for /// diagnostics. Around pattern matching such as `let pat = expr`, the diagnostic @@ -73,6 +73,10 @@ pub trait Delegate<'tcx> { /// The value found at `place` is being copied. /// `diag_expr_id` is the id used for diagnostics (see `consume` for more details). + /// + /// If an implementation is not provided, use of a `Copy` type in a ByValue context is instead + /// considered a use by `ImmBorrow` and `borrow` is called instead. This is because a shared + /// borrow is the "minimum access" that would be needed to perform a copy. fn copy(&mut self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: HirId) { // In most cases, copying data from `x` is equivalent to doing `*&x`, so by default // we treat a copy of `x` as a borrow of `x`. @@ -141,6 +145,8 @@ impl<'tcx, D: Delegate<'tcx>> Delegate<'tcx> for &mut D { } } +/// This trait makes `ExprUseVisitor` usable with both [`FnCtxt`] +/// and [`LateContext`], depending on where in the compiler it is used. pub trait TypeInformationCtxt<'tcx> { type TypeckResults<'a>: Deref> where @@ -154,7 +160,7 @@ pub trait TypeInformationCtxt<'tcx> { fn try_structurally_resolve_type(&self, span: Span, ty: Ty<'tcx>) -> Ty<'tcx>; - fn report_error(&self, span: Span, msg: impl ToString) -> Self::Error; + fn report_bug(&self, span: Span, msg: impl ToString) -> Self::Error; fn error_reported_in_ty(&self, ty: Ty<'tcx>) -> Result<(), Self::Error>; @@ -189,7 +195,7 @@ impl<'tcx> TypeInformationCtxt<'tcx> for &FnCtxt<'_, 'tcx> { (**self).try_structurally_resolve_type(sp, ty) } - fn report_error(&self, span: Span, msg: impl ToString) -> Self::Error { + fn report_bug(&self, span: Span, msg: impl ToString) -> Self::Error { self.dcx().span_delayed_bug(span, msg.to_string()) } @@ -239,7 +245,7 @@ impl<'tcx> TypeInformationCtxt<'tcx> for (&LateContext<'tcx>, LocalDefId) { t } - fn report_error(&self, span: Span, msg: impl ToString) -> ! { + fn report_bug(&self, span: Span, msg: impl ToString) -> ! { span_bug!(span, "{}", msg.to_string()) } @@ -268,9 +274,9 @@ impl<'tcx> TypeInformationCtxt<'tcx> for (&LateContext<'tcx>, LocalDefId) { } } -/// The ExprUseVisitor type +/// A visitor that reports how each expression is being used. /// -/// This is the code that actually walks the tree. +/// See [module-level docs][self] and [`Delegate`] for details. pub struct ExprUseVisitor<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> { cx: Cx, /// We use a `RefCell` here so that delegates can mutate themselves, but we can @@ -314,9 +320,8 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx Ok(()) } + #[instrument(skip(self), level = "debug")] fn consume_or_copy(&self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: HirId) { - debug!("delegate_consume(place_with_id={:?})", place_with_id); - if self.cx.type_is_copy_modulo_regions(place_with_id.place.ty()) { self.delegate.borrow_mut().copy(place_with_id, diag_expr_id); } else { @@ -324,9 +329,8 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx } } + #[instrument(skip(self), level = "debug")] pub fn consume_clone_or_copy(&self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: HirId) { - debug!("delegate_consume_or_clone(place_with_id={:?})", place_with_id); - // `x.use` will do one of the following // * if it implements `Copy`, it will be a copy // * if it implements `UseCloned`, it will be a call to `clone` @@ -351,18 +355,16 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx } // FIXME: It's suspicious that this is public; clippy should probably use `walk_expr`. + #[instrument(skip(self), level = "debug")] pub fn consume_expr(&self, expr: &hir::Expr<'_>) -> Result<(), Cx::Error> { - debug!("consume_expr(expr={:?})", expr); - let place_with_id = self.cat_expr(expr)?; self.consume_or_copy(&place_with_id, place_with_id.hir_id); self.walk_expr(expr)?; Ok(()) } + #[instrument(skip(self), level = "debug")] pub fn consume_or_clone_expr(&self, expr: &hir::Expr<'_>) -> Result<(), Cx::Error> { - debug!("consume_or_clone_expr(expr={:?})", expr); - let place_with_id = self.cat_expr(expr)?; self.consume_clone_or_copy(&place_with_id, place_with_id.hir_id); self.walk_expr(expr)?; @@ -376,17 +378,15 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx Ok(()) } + #[instrument(skip(self), level = "debug")] fn borrow_expr(&self, expr: &hir::Expr<'_>, bk: ty::BorrowKind) -> Result<(), Cx::Error> { - debug!("borrow_expr(expr={:?}, bk={:?})", expr, bk); - let place_with_id = self.cat_expr(expr)?; self.delegate.borrow_mut().borrow(&place_with_id, place_with_id.hir_id, bk); self.walk_expr(expr) } + #[instrument(skip(self), level = "debug")] pub fn walk_expr(&self, expr: &hir::Expr<'_>) -> Result<(), Cx::Error> { - debug!("walk_expr(expr={:?})", expr); - self.walk_adjustment(expr)?; match expr.kind { @@ -733,9 +733,8 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx /// Indicates that the value of `blk` will be consumed, meaning either copied or moved /// depending on its type. + #[instrument(skip(self), level = "debug")] fn walk_block(&self, blk: &hir::Block<'_>) -> Result<(), Cx::Error> { - debug!("walk_block(blk.hir_id={})", blk.hir_id); - for stmt in blk.stmts { self.walk_stmt(stmt)?; } @@ -861,7 +860,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx } /// Walks the autoref `autoref` applied to the autoderef'd - /// `expr`. `base_place` is the mem-categorized form of `expr` + /// `expr`. `base_place` is `expr` represented as a place, /// after all relevant autoderefs have occurred. fn walk_autoref( &self, @@ -942,14 +941,13 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx } /// The core driver for walking a pattern + #[instrument(skip(self), level = "debug")] fn walk_pat( &self, discr_place: &PlaceWithHirId<'tcx>, pat: &hir::Pat<'_>, has_guard: bool, ) -> Result<(), Cx::Error> { - debug!("walk_pat(discr_place={:?}, pat={:?}, has_guard={:?})", discr_place, pat, has_guard); - let tcx = self.cx.tcx(); self.cat_pattern(discr_place.clone(), pat, &mut |place, pat| { match pat.kind { @@ -1042,6 +1040,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx /// /// - When reporting the Place back to the Delegate, ensure that the UpvarId uses the enclosing /// closure as the DefId. + #[instrument(skip(self), level = "debug")] fn walk_captures(&self, closure_expr: &hir::Closure<'_>) -> Result<(), Cx::Error> { fn upvar_is_local_variable( upvars: Option<&FxIndexMap>, @@ -1051,8 +1050,6 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx upvars.map(|upvars| !upvars.contains_key(&upvar_id)).unwrap_or(body_owner_is_closure) } - debug!("walk_captures({:?})", closure_expr); - let tcx = self.cx.tcx(); let closure_def_id = closure_expr.def_id; // For purposes of this function, coroutine and closures are equivalent. @@ -1164,55 +1161,17 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx } } -/// The job of the categorization methods is to analyze an expression to -/// determine what kind of memory is used in evaluating it (for example, -/// where dereferences occur and what kind of pointer is dereferenced; -/// whether the memory is mutable, etc.). -/// -/// Categorization effectively transforms all of our expressions into -/// expressions of the following forms (the actual enum has many more -/// possibilities, naturally, but they are all variants of these base -/// forms): -/// ```ignore (not-rust) -/// E = rvalue // some computed rvalue -/// | x // address of a local variable or argument -/// | *E // deref of a ptr -/// | E.comp // access to an interior component -/// ``` -/// Imagine a routine ToAddr(Expr) that evaluates an expression and returns an -/// address where the result is to be found. If Expr is a place, then this -/// is the address of the place. If `Expr` is an rvalue, this is the address of -/// some temporary spot in memory where the result is stored. -/// -/// Now, `cat_expr()` classifies the expression `Expr` and the address `A = ToAddr(Expr)` -/// as follows: -/// -/// - `cat`: what kind of expression was this? This is a subset of the -/// full expression forms which only includes those that we care about -/// for the purpose of the analysis. -/// - `mutbl`: mutability of the address `A`. -/// - `ty`: the type of data found at the address `A`. +/// The job of the methods whose name starts with `cat_` is to analyze +/// expressions and construct the corresponding [`Place`]s. The `cat` +/// stands for "categorize", this is a leftover from long ago when +/// places were called "categorizations". /// -/// The resulting categorization tree differs somewhat from the expressions -/// themselves. For example, auto-derefs are explicit. Also, an index `a[b]` is -/// decomposed into two operations: a dereference to reach the array data and -/// then an index to jump forward to the relevant item. -/// -/// ## By-reference upvars -/// -/// One part of the codegen which may be non-obvious is that we translate -/// closure upvars into the dereference of a borrowed pointer; this more closely -/// resembles the runtime codegen. So, for example, if we had: -/// -/// let mut x = 3; -/// let y = 5; -/// let inc = || x += y; -/// -/// Then when we categorize `x` (*within* the closure) we would yield a -/// result of `*x'`, effectively, where `x'` is a `Categorization::Upvar` reference -/// tied to `x`. The type of `x'` will be a borrowed pointer. +/// Note that a [`Place`] differs somewhat from the expression itself. For +/// example, auto-derefs are explicit. Also, an index `a[b]` is decomposed into +/// two operations: a dereference to reach the array data and then an index to +/// jump forward to the relevant item. impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx, Cx, D> { - fn resolve_type_vars_or_error( + fn resolve_type_vars_or_bug( &self, id: HirId, ty: Option>, @@ -1222,10 +1181,10 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx let ty = self.cx.resolve_vars_if_possible(ty); self.cx.error_reported_in_ty(ty)?; if ty.is_ty_var() { - debug!("resolve_type_vars_or_error: infer var from {:?}", ty); + debug!("resolve_type_vars_or_bug: infer var from {:?}", ty); Err(self .cx - .report_error(self.cx.tcx().hir().span(id), "encountered type variable")) + .report_bug(self.cx.tcx().hir().span(id), "encountered type variable")) } else { Ok(ty) } @@ -1233,24 +1192,21 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx None => { // FIXME: We shouldn't be relying on the infcx being tainted. self.cx.tainted_by_errors()?; - bug!( - "no type for node {} in mem_categorization", - self.cx.tcx().hir_id_to_string(id) - ); + bug!("no type for node {} in ExprUseVisitor", self.cx.tcx().hir_id_to_string(id)); } } } fn node_ty(&self, hir_id: HirId) -> Result, Cx::Error> { - self.resolve_type_vars_or_error(hir_id, self.cx.typeck_results().node_type_opt(hir_id)) + self.resolve_type_vars_or_bug(hir_id, self.cx.typeck_results().node_type_opt(hir_id)) } fn expr_ty(&self, expr: &hir::Expr<'_>) -> Result, Cx::Error> { - self.resolve_type_vars_or_error(expr.hir_id, self.cx.typeck_results().expr_ty_opt(expr)) + self.resolve_type_vars_or_bug(expr.hir_id, self.cx.typeck_results().expr_ty_opt(expr)) } fn expr_ty_adjusted(&self, expr: &hir::Expr<'_>) -> Result, Cx::Error> { - self.resolve_type_vars_or_error( + self.resolve_type_vars_or_bug( expr.hir_id, self.cx.typeck_results().expr_ty_adjusted_opt(expr), ) @@ -1285,7 +1241,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx self.pat_ty_unadjusted(pat) } - /// Like `TypeckResults::pat_ty`, but ignores implicit `&` patterns. + /// Like [`Self::pat_ty_adjusted`], but ignores implicit `&` patterns. fn pat_ty_unadjusted(&self, pat: &hir::Pat<'_>) -> Result, Cx::Error> { let base_ty = self.node_ty(pat.hir_id)?; trace!(?base_ty); @@ -1315,7 +1271,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx debug!("By-ref binding of non-derefable type"); Err(self .cx - .report_error(pat.span, "by-ref binding of non-derefable type")) + .report_bug(pat.span, "by-ref binding of non-derefable type")) } } } else { @@ -1511,7 +1467,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx } } - def => span_bug!(span, "unexpected definition in memory categorization: {:?}", def), + def => span_bug!(span, "unexpected definition in ExprUseVisitor: {:?}", def), } } @@ -1604,7 +1560,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx Some(ty) => ty, None => { debug!("explicit deref of non-derefable type: {:?}", base_curr_ty); - return Err(self.cx.report_error( + return Err(self.cx.report_bug( self.cx.tcx().hir().span(node), "explicit deref of non-derefable type", )); @@ -1629,7 +1585,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx let ty::Adt(adt_def, _) = self.cx.try_structurally_resolve_type(span, ty).kind() else { return Err(self .cx - .report_error(span, "struct or tuple struct pattern not applied to an ADT")); + .report_bug(span, "struct or tuple struct pattern not applied to an ADT")); }; match res { @@ -1675,7 +1631,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx let ty = self.cx.typeck_results().node_type(pat_hir_id); match self.cx.try_structurally_resolve_type(span, ty).kind() { ty::Tuple(args) => Ok(args.len()), - _ => Err(self.cx.report_error(span, "tuple pattern not applied to a tuple")), + _ => Err(self.cx.report_bug(span, "tuple pattern not applied to a tuple")), } } @@ -1854,7 +1810,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx debug!("explicit index of non-indexable type {:?}", place_with_id); return Err(self .cx - .report_error(pat.span, "explicit index of non-indexable type")); + .report_bug(pat.span, "explicit index of non-indexable type")); }; let elt_place = self.cat_projection( pat.hir_id, diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs index fc98a603dd852..d07bfade15708 100644 --- a/compiler/rustc_hir_typeck/src/upvar.rs +++ b/compiler/rustc_hir_typeck/src/upvar.rs @@ -18,12 +18,12 @@ //! from there). //! //! The fact that we are inferring borrow kinds as we go results in a -//! semi-hacky interaction with mem-categorization. In particular, -//! mem-categorization will query the current borrow kind as it -//! categorizes, and we'll return the *current* value, but this may get +//! semi-hacky interaction with the way `ExprUseVisitor` is computing +//! `Place`s. In particular, it will query the current borrow kind as it +//! goes, and we'll return the *current* value, but this may get //! adjusted later. Therefore, in this module, we generally ignore the -//! borrow kind (and derived mutabilities) that are returned from -//! mem-categorization, since they may be inaccurate. (Another option +//! borrow kind (and derived mutabilities) that `ExprUseVisitor` returns +//! within `Place`s, since they may be inaccurate. (Another option //! would be to use a unification scheme, where instead of returning a //! concrete borrow kind like `ty::ImmBorrow`, we return a //! `ty::InferBorrow(upvar_id)` or something like that, but this would diff --git a/compiler/rustc_middle/src/hir/place.rs b/compiler/rustc_middle/src/hir/place.rs index 316ad80eb9857..60ce8544aa0ed 100644 --- a/compiler/rustc_middle/src/hir/place.rs +++ b/compiler/rustc_middle/src/hir/place.rs @@ -53,7 +53,10 @@ pub struct Projection<'tcx> { pub kind: ProjectionKind, } -/// A `Place` represents how a value is located in memory. +/// A `Place` represents how a value is located in memory. This does not +/// always correspond to a syntactic place expression. For example, when +/// processing a pattern, a `Place` can be used to refer to the sub-value +/// currently being inspected. /// /// This is an HIR version of [`rustc_middle::mir::Place`]. #[derive(Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)] @@ -67,7 +70,10 @@ pub struct Place<'tcx> { pub projections: Vec>, } -/// A `PlaceWithHirId` represents how a value is located in memory. +/// A `PlaceWithHirId` represents how a value is located in memory. This does not +/// always correspond to a syntactic place expression. For example, when +/// processing a pattern, a `Place` can be used to refer to the sub-value +/// currently being inspected. /// /// This is an HIR version of [`rustc_middle::mir::Place`]. #[derive(Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)] diff --git a/compiler/rustc_mir_build/src/builder/scope.rs b/compiler/rustc_mir_build/src/builder/scope.rs index e56c0ae92cac6..e42336a1dbbcc 100644 --- a/compiler/rustc_mir_build/src/builder/scope.rs +++ b/compiler/rustc_mir_build/src/builder/scope.rs @@ -1496,7 +1496,7 @@ fn build_scope_drops<'tcx>( // path, then don't generate the drop. (We only take this into // account for non-unwind paths so as not to disturb the // caching mechanism.) - if scope.moved_locals.iter().any(|&o| o == local) { + if scope.moved_locals.contains(&local) { continue; } diff --git a/compiler/rustc_passes/src/entry.rs b/compiler/rustc_passes/src/entry.rs index d2729876ebbb4..2a435c4b2e05c 100644 --- a/compiler/rustc_passes/src/entry.rs +++ b/compiler/rustc_passes/src/entry.rs @@ -24,7 +24,7 @@ struct EntryContext<'tcx> { } fn entry_fn(tcx: TyCtxt<'_>, (): ()) -> Option<(DefId, EntryFnType)> { - let any_exe = tcx.crate_types().iter().any(|ty| *ty == CrateType::Executable); + let any_exe = tcx.crate_types().contains(&CrateType::Executable); if !any_exe { // No need to find a main function. return None; diff --git a/compiler/rustc_session/src/utils.rs b/compiler/rustc_session/src/utils.rs index fcede379b893a..2243e831b66ec 100644 --- a/compiler/rustc_session/src/utils.rs +++ b/compiler/rustc_session/src/utils.rs @@ -149,14 +149,15 @@ pub fn extra_compiler_flags() -> Option<(Vec, bool)> { arg[a.len()..].to_string() }; let option = content.split_once('=').map(|s| s.0).unwrap_or(&content); - if ICE_REPORT_COMPILER_FLAGS_EXCLUDE.iter().any(|exc| option == *exc) { + if ICE_REPORT_COMPILER_FLAGS_EXCLUDE.contains(&option) { excluded_cargo_defaults = true; } else { result.push(a.to_string()); - match ICE_REPORT_COMPILER_FLAGS_STRIP_VALUE.iter().find(|s| option == **s) { - Some(s) => result.push(format!("{s}=[REDACTED]")), - None => result.push(content), - } + result.push(if ICE_REPORT_COMPILER_FLAGS_STRIP_VALUE.contains(&option) { + format!("{option}=[REDACTED]") + } else { + content + }); } } } diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index f19d4d9f3624e..9e6ba2e1b9ce2 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -876,7 +876,7 @@ impl Span { self.ctxt() .outer_expn_data() .allow_internal_unstable - .is_some_and(|features| features.iter().any(|&f| f == feature)) + .is_some_and(|features| features.contains(&feature)) } /// Checks if this span arises from a compiler desugaring of kind `kind`. diff --git a/compiler/stable_mir/src/mir/body.rs b/compiler/stable_mir/src/mir/body.rs index b1bf7bce828c3..2a1c163de3c45 100644 --- a/compiler/stable_mir/src/mir/body.rs +++ b/compiler/stable_mir/src/mir/body.rs @@ -1057,8 +1057,7 @@ impl Place { /// In order to retrieve the correct type, the `locals` argument must match the list of all /// locals from the function body where this place originates from. pub fn ty(&self, locals: &[LocalDecl]) -> Result { - let start_ty = locals[self.local].ty; - self.projection.iter().fold(Ok(start_ty), |place_ty, elem| elem.ty(place_ty?)) + self.projection.iter().try_fold(locals[self.local].ty, |place_ty, elem| elem.ty(place_ty)) } } diff --git a/compiler/stable_mir/src/mir/visit.rs b/compiler/stable_mir/src/mir/visit.rs index 09447e70dfb18..9d2368ba33202 100644 --- a/compiler/stable_mir/src/mir/visit.rs +++ b/compiler/stable_mir/src/mir/visit.rs @@ -563,7 +563,7 @@ pub struct PlaceRef<'a> { impl PlaceRef<'_> { /// Get the type of this place. pub fn ty(&self, locals: &[LocalDecl]) -> Result { - self.projection.iter().fold(Ok(locals[self.local].ty), |place_ty, elem| elem.ty(place_ty?)) + self.projection.iter().try_fold(locals[self.local].ty, |place_ty, elem| elem.ty(place_ty)) } } diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index fa98db693066a..801baf3d99072 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -2370,7 +2370,7 @@ impl AsInner for DirEntry { #[doc(alias = "rm", alias = "unlink", alias = "DeleteFile")] #[stable(feature = "rust1", since = "1.0.0")] pub fn remove_file>(path: P) -> io::Result<()> { - fs_imp::unlink(path.as_ref()) + fs_imp::remove_file(path.as_ref()) } /// Given a path, queries the file system to get information about a file, @@ -2409,7 +2409,7 @@ pub fn remove_file>(path: P) -> io::Result<()> { #[doc(alias = "stat")] #[stable(feature = "rust1", since = "1.0.0")] pub fn metadata>(path: P) -> io::Result { - fs_imp::stat(path.as_ref()).map(Metadata) + fs_imp::metadata(path.as_ref()).map(Metadata) } /// Queries the metadata about a file without following symlinks. @@ -2444,7 +2444,7 @@ pub fn metadata>(path: P) -> io::Result { #[doc(alias = "lstat")] #[stable(feature = "symlink_metadata", since = "1.1.0")] pub fn symlink_metadata>(path: P) -> io::Result { - fs_imp::lstat(path.as_ref()).map(Metadata) + fs_imp::symlink_metadata(path.as_ref()).map(Metadata) } /// Renames a file or directory to a new name, replacing the original file if @@ -2598,7 +2598,7 @@ pub fn copy, Q: AsRef>(from: P, to: Q) -> io::Result { #[doc(alias = "CreateHardLink", alias = "linkat")] #[stable(feature = "rust1", since = "1.0.0")] pub fn hard_link, Q: AsRef>(original: P, link: Q) -> io::Result<()> { - fs_imp::link(original.as_ref(), link.as_ref()) + fs_imp::hard_link(original.as_ref(), link.as_ref()) } /// Creates a new symbolic link on the filesystem. @@ -2664,7 +2664,7 @@ pub fn soft_link, Q: AsRef>(original: P, link: Q) -> io::Re /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn read_link>(path: P) -> io::Result { - fs_imp::readlink(path.as_ref()) + fs_imp::read_link(path.as_ref()) } /// Returns the canonical, absolute form of a path with all intermediate @@ -2840,7 +2840,7 @@ pub fn create_dir_all>(path: P) -> io::Result<()> { #[doc(alias = "rmdir", alias = "RemoveDirectory")] #[stable(feature = "rust1", since = "1.0.0")] pub fn remove_dir>(path: P) -> io::Result<()> { - fs_imp::rmdir(path.as_ref()) + fs_imp::remove_dir(path.as_ref()) } /// Removes a directory at this path, after removing all its contents. Use @@ -2967,7 +2967,7 @@ pub fn remove_dir_all>(path: P) -> io::Result<()> { #[doc(alias = "ls", alias = "opendir", alias = "FindFirstFile", alias = "FindNextFile")] #[stable(feature = "rust1", since = "1.0.0")] pub fn read_dir>(path: P) -> io::Result { - fs_imp::readdir(path.as_ref()).map(ReadDir) + fs_imp::read_dir(path.as_ref()).map(ReadDir) } /// Changes the permissions found on a file or a directory. @@ -3003,7 +3003,7 @@ pub fn read_dir>(path: P) -> io::Result { #[doc(alias = "chmod", alias = "SetFileAttributes")] #[stable(feature = "set_permissions", since = "1.1.0")] pub fn set_permissions>(path: P, perm: Permissions) -> io::Result<()> { - fs_imp::set_perm(path.as_ref(), perm.0) + fs_imp::set_permissions(path.as_ref(), perm.0) } impl DirBuilder { diff --git a/library/std/src/sys/fs/mod.rs b/library/std/src/sys/fs/mod.rs index c2e19eb393a16..e701bfc7b2389 100644 --- a/library/std/src/sys/fs/mod.rs +++ b/library/std/src/sys/fs/mod.rs @@ -1,28 +1,113 @@ #![deny(unsafe_op_in_unsafe_fn)] +use crate::io; +use crate::path::{Path, PathBuf}; + pub mod common; cfg_if::cfg_if! { if #[cfg(target_family = "unix")] { mod unix; - pub use unix::*; + use unix as imp; + pub use unix::{chown, fchown, lchown, chroot}; + pub(crate) use unix::debug_assert_fd_is_open; + #[cfg(any(target_os = "linux", target_os = "android"))] + pub(crate) use unix::CachedFileMetadata; + use crate::sys::common::small_c_string::run_path_with_cstr as with_native_path; } else if #[cfg(target_os = "windows")] { mod windows; - pub use windows::*; + use windows as imp; + pub use windows::{symlink_inner, junction_point}; } else if #[cfg(target_os = "hermit")] { mod hermit; - pub use hermit::*; + use hermit as imp; } else if #[cfg(target_os = "solid_asp3")] { mod solid; - pub use solid::*; + use solid as imp; } else if #[cfg(target_os = "uefi")] { mod uefi; - pub use uefi::*; + use uefi as imp; } else if #[cfg(target_os = "wasi")] { mod wasi; - pub use wasi::*; + use wasi as imp; } else { mod unsupported; - pub use unsupported::*; + use unsupported as imp; } } + +// FIXME: Replace this with platform-specific path conversion functions. +#[cfg(not(target_family = "unix"))] +#[inline] +pub fn with_native_path(path: &Path, f: &dyn Fn(&Path) -> io::Result) -> io::Result { + f(path) +} + +pub use imp::{ + DirBuilder, DirEntry, File, FileAttr, FilePermissions, FileTimes, FileType, OpenOptions, + ReadDir, +}; + +pub fn read_dir(path: &Path) -> io::Result { + // FIXME: use with_native_path + imp::readdir(path) +} + +pub fn remove_file(path: &Path) -> io::Result<()> { + with_native_path(path, &imp::unlink) +} + +pub fn rename(old: &Path, new: &Path) -> io::Result<()> { + with_native_path(old, &|old| with_native_path(new, &|new| imp::rename(old, new))) +} + +pub fn remove_dir(path: &Path) -> io::Result<()> { + with_native_path(path, &imp::rmdir) +} + +pub fn remove_dir_all(path: &Path) -> io::Result<()> { + // FIXME: use with_native_path + imp::remove_dir_all(path) +} + +pub fn read_link(path: &Path) -> io::Result { + with_native_path(path, &imp::readlink) +} + +pub fn symlink(original: &Path, link: &Path) -> io::Result<()> { + with_native_path(original, &|original| { + with_native_path(link, &|link| imp::symlink(original, link)) + }) +} + +pub fn hard_link(original: &Path, link: &Path) -> io::Result<()> { + with_native_path(original, &|original| { + with_native_path(link, &|link| imp::link(original, link)) + }) +} + +pub fn metadata(path: &Path) -> io::Result { + with_native_path(path, &imp::stat) +} + +pub fn symlink_metadata(path: &Path) -> io::Result { + with_native_path(path, &imp::lstat) +} + +pub fn set_permissions(path: &Path, perm: FilePermissions) -> io::Result<()> { + with_native_path(path, &|path| imp::set_perm(path, perm.clone())) +} + +pub fn canonicalize(path: &Path) -> io::Result { + with_native_path(path, &imp::canonicalize) +} + +pub fn copy(from: &Path, to: &Path) -> io::Result { + // FIXME: use with_native_path + imp::copy(from, to) +} + +pub fn exists(path: &Path) -> io::Result { + // FIXME: use with_native_path + imp::exists(path) +} diff --git a/library/std/src/sys/fs/unix.rs b/library/std/src/sys/fs/unix.rs index 7c3ed8029f7dd..6bffe87428323 100644 --- a/library/std/src/sys/fs/unix.rs +++ b/library/std/src/sys/fs/unix.rs @@ -155,15 +155,15 @@ cfg_has_statx! {{ enum STATX_STATE{ Unknown = 0, Present, Unavailable } static STATX_SAVED_STATE: AtomicU8 = AtomicU8::new(STATX_STATE::Unknown as u8); - syscall! { + syscall!( fn statx( fd: c_int, pathname: *const c_char, flags: c_int, mask: libc::c_uint, - statxbuf: *mut libc::statx - ) -> c_int - } + statxbuf: *mut libc::statx, + ) -> c_int; + ); let statx_availability = STATX_SAVED_STATE.load(Ordering::Relaxed); if statx_availability == STATX_STATE::Unavailable as u8 { @@ -926,7 +926,7 @@ impl DirEntry { miri ))] pub fn metadata(&self) -> io::Result { - lstat(&self.path()) + run_path_with_cstr(&self.path(), &lstat) } #[cfg(any( @@ -1540,7 +1540,9 @@ impl File { let times = [to_timespec(times.accessed)?, to_timespec(times.modified)?]; // futimens requires Android API level 19 cvt(unsafe { - weak!(fn futimens(c_int, *const libc::timespec) -> c_int); + weak!( + fn futimens(fd: c_int, times: *const libc::timespec) -> c_int; + ); match futimens.get() { Some(futimens) => futimens(self.as_raw_fd(), times.as_ptr()), None => return Err(io::const_error!( @@ -1556,7 +1558,9 @@ impl File { use crate::sys::{time::__timespec64, weak::weak}; // Added in glibc 2.34 - weak!(fn __futimens64(libc::c_int, *const __timespec64) -> libc::c_int); + weak!( + fn __futimens64(fd: c_int, times: *const __timespec64) -> c_int; + ); if let Some(futimens64) = __futimens64.get() { let to_timespec = |time: Option| time.map(|time| time.t.to_timespec64()) @@ -1653,7 +1657,7 @@ impl fmt::Debug for File { fn get_path(fd: c_int) -> Option { let mut p = PathBuf::from("/proc/self/fd"); p.push(&fd.to_string()); - readlink(&p).ok() + run_path_with_cstr(&p, &readlink).ok() } #[cfg(any(target_vendor = "apple", target_os = "netbsd"))] @@ -1826,127 +1830,106 @@ pub fn readdir(path: &Path) -> io::Result { } } -pub fn unlink(p: &Path) -> io::Result<()> { - run_path_with_cstr(p, &|p| cvt(unsafe { libc::unlink(p.as_ptr()) }).map(|_| ())) +pub fn unlink(p: &CStr) -> io::Result<()> { + cvt(unsafe { libc::unlink(p.as_ptr()) }).map(|_| ()) } -pub fn rename(old: &Path, new: &Path) -> io::Result<()> { - run_path_with_cstr(old, &|old| { - run_path_with_cstr(new, &|new| { - cvt(unsafe { libc::rename(old.as_ptr(), new.as_ptr()) }).map(|_| ()) - }) - }) +pub fn rename(old: &CStr, new: &CStr) -> io::Result<()> { + cvt(unsafe { libc::rename(old.as_ptr(), new.as_ptr()) }).map(|_| ()) } -pub fn set_perm(p: &Path, perm: FilePermissions) -> io::Result<()> { - run_path_with_cstr(p, &|p| cvt_r(|| unsafe { libc::chmod(p.as_ptr(), perm.mode) }).map(|_| ())) +pub fn set_perm(p: &CStr, perm: FilePermissions) -> io::Result<()> { + cvt_r(|| unsafe { libc::chmod(p.as_ptr(), perm.mode) }).map(|_| ()) } -pub fn rmdir(p: &Path) -> io::Result<()> { - run_path_with_cstr(p, &|p| cvt(unsafe { libc::rmdir(p.as_ptr()) }).map(|_| ())) +pub fn rmdir(p: &CStr) -> io::Result<()> { + cvt(unsafe { libc::rmdir(p.as_ptr()) }).map(|_| ()) } -pub fn readlink(p: &Path) -> io::Result { - run_path_with_cstr(p, &|c_path| { - let p = c_path.as_ptr(); +pub fn readlink(c_path: &CStr) -> io::Result { + let p = c_path.as_ptr(); - let mut buf = Vec::with_capacity(256); + let mut buf = Vec::with_capacity(256); - loop { - let buf_read = - cvt(unsafe { libc::readlink(p, buf.as_mut_ptr() as *mut _, buf.capacity()) })? - as usize; - - unsafe { - buf.set_len(buf_read); - } + loop { + let buf_read = + cvt(unsafe { libc::readlink(p, buf.as_mut_ptr() as *mut _, buf.capacity()) })? as usize; - if buf_read != buf.capacity() { - buf.shrink_to_fit(); + unsafe { + buf.set_len(buf_read); + } - return Ok(PathBuf::from(OsString::from_vec(buf))); - } + if buf_read != buf.capacity() { + buf.shrink_to_fit(); - // Trigger the internal buffer resizing logic of `Vec` by requiring - // more space than the current capacity. The length is guaranteed to be - // the same as the capacity due to the if statement above. - buf.reserve(1); + return Ok(PathBuf::from(OsString::from_vec(buf))); } - }) + + // Trigger the internal buffer resizing logic of `Vec` by requiring + // more space than the current capacity. The length is guaranteed to be + // the same as the capacity due to the if statement above. + buf.reserve(1); + } } -pub fn symlink(original: &Path, link: &Path) -> io::Result<()> { - run_path_with_cstr(original, &|original| { - run_path_with_cstr(link, &|link| { - cvt(unsafe { libc::symlink(original.as_ptr(), link.as_ptr()) }).map(|_| ()) - }) - }) +pub fn symlink(original: &CStr, link: &CStr) -> io::Result<()> { + cvt(unsafe { libc::symlink(original.as_ptr(), link.as_ptr()) }).map(|_| ()) } -pub fn link(original: &Path, link: &Path) -> io::Result<()> { - run_path_with_cstr(original, &|original| { - run_path_with_cstr(link, &|link| { - cfg_if::cfg_if! { - if #[cfg(any(target_os = "vxworks", target_os = "redox", target_os = "android", target_os = "espidf", target_os = "horizon", target_os = "vita", target_env = "nto70"))] { - // VxWorks, Redox and ESP-IDF lack `linkat`, so use `link` instead. POSIX leaves - // it implementation-defined whether `link` follows symlinks, so rely on the - // `symlink_hard_link` test in library/std/src/fs/tests.rs to check the behavior. - // Android has `linkat` on newer versions, but we happen to know `link` - // always has the correct behavior, so it's here as well. - cvt(unsafe { libc::link(original.as_ptr(), link.as_ptr()) })?; - } else { - // Where we can, use `linkat` instead of `link`; see the comment above - // this one for details on why. - cvt(unsafe { libc::linkat(libc::AT_FDCWD, original.as_ptr(), libc::AT_FDCWD, link.as_ptr(), 0) })?; - } - } - Ok(()) - }) - }) +pub fn link(original: &CStr, link: &CStr) -> io::Result<()> { + cfg_if::cfg_if! { + if #[cfg(any(target_os = "vxworks", target_os = "redox", target_os = "android", target_os = "espidf", target_os = "horizon", target_os = "vita", target_env = "nto70"))] { + // VxWorks, Redox and ESP-IDF lack `linkat`, so use `link` instead. POSIX leaves + // it implementation-defined whether `link` follows symlinks, so rely on the + // `symlink_hard_link` test in library/std/src/fs/tests.rs to check the behavior. + // Android has `linkat` on newer versions, but we happen to know `link` + // always has the correct behavior, so it's here as well. + cvt(unsafe { libc::link(original.as_ptr(), link.as_ptr()) })?; + } else { + // Where we can, use `linkat` instead of `link`; see the comment above + // this one for details on why. + cvt(unsafe { libc::linkat(libc::AT_FDCWD, original.as_ptr(), libc::AT_FDCWD, link.as_ptr(), 0) })?; + } + } + Ok(()) } -pub fn stat(p: &Path) -> io::Result { - run_path_with_cstr(p, &|p| { - cfg_has_statx! { - if let Some(ret) = unsafe { try_statx( - libc::AT_FDCWD, - p.as_ptr(), - libc::AT_STATX_SYNC_AS_STAT, - libc::STATX_BASIC_STATS | libc::STATX_BTIME, - ) } { - return ret; - } +pub fn stat(p: &CStr) -> io::Result { + cfg_has_statx! { + if let Some(ret) = unsafe { try_statx( + libc::AT_FDCWD, + p.as_ptr(), + libc::AT_STATX_SYNC_AS_STAT, + libc::STATX_BASIC_STATS | libc::STATX_BTIME, + ) } { + return ret; } + } - let mut stat: stat64 = unsafe { mem::zeroed() }; - cvt(unsafe { stat64(p.as_ptr(), &mut stat) })?; - Ok(FileAttr::from_stat64(stat)) - }) + let mut stat: stat64 = unsafe { mem::zeroed() }; + cvt(unsafe { stat64(p.as_ptr(), &mut stat) })?; + Ok(FileAttr::from_stat64(stat)) } -pub fn lstat(p: &Path) -> io::Result { - run_path_with_cstr(p, &|p| { - cfg_has_statx! { - if let Some(ret) = unsafe { try_statx( - libc::AT_FDCWD, - p.as_ptr(), - libc::AT_SYMLINK_NOFOLLOW | libc::AT_STATX_SYNC_AS_STAT, - libc::STATX_BASIC_STATS | libc::STATX_BTIME, - ) } { - return ret; - } +pub fn lstat(p: &CStr) -> io::Result { + cfg_has_statx! { + if let Some(ret) = unsafe { try_statx( + libc::AT_FDCWD, + p.as_ptr(), + libc::AT_SYMLINK_NOFOLLOW | libc::AT_STATX_SYNC_AS_STAT, + libc::STATX_BASIC_STATS | libc::STATX_BTIME, + ) } { + return ret; } + } - let mut stat: stat64 = unsafe { mem::zeroed() }; - cvt(unsafe { lstat64(p.as_ptr(), &mut stat) })?; - Ok(FileAttr::from_stat64(stat)) - }) + let mut stat: stat64 = unsafe { mem::zeroed() }; + cvt(unsafe { lstat64(p.as_ptr(), &mut stat) })?; + Ok(FileAttr::from_stat64(stat)) } -pub fn canonicalize(p: &Path) -> io::Result { - let r = run_path_with_cstr(p, &|path| unsafe { - Ok(libc::realpath(path.as_ptr(), ptr::null_mut())) - })?; +pub fn canonicalize(path: &CStr) -> io::Result { + let r = unsafe { libc::realpath(path.as_ptr(), ptr::null_mut()) }; if r.is_null() { return Err(io::Error::last_os_error()); } @@ -2324,19 +2307,19 @@ mod remove_dir_impl { Ok(()) } - fn remove_dir_all_modern(p: &Path) -> io::Result<()> { + fn remove_dir_all_modern(p: &CStr) -> io::Result<()> { // We cannot just call remove_dir_all_recursive() here because that would not delete a passed // symlink. No need to worry about races, because remove_dir_all_recursive() does not recurse // into symlinks. let attr = lstat(p)?; if attr.file_type().is_symlink() { - crate::fs::remove_file(p) + super::unlink(p) } else { - run_path_with_cstr(p, &|p| remove_dir_all_recursive(None, &p)) + remove_dir_all_recursive(None, &p) } } pub fn remove_dir_all(p: &Path) -> io::Result<()> { - remove_dir_all_modern(p) + run_path_with_cstr(p, &remove_dir_all_modern) } } diff --git a/library/std/src/sys/pal/unix/fd.rs b/library/std/src/sys/pal/unix/fd.rs index f03c440e30e12..2ec8d01c13f46 100644 --- a/library/std/src/sys/pal/unix/fd.rs +++ b/library/std/src/sys/pal/unix/fd.rs @@ -232,14 +232,14 @@ impl FileDesc { // implementation if `preadv` is not available. #[cfg(all(target_os = "android", target_pointer_width = "64"))] pub fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result { - super::weak::syscall! { + super::weak::syscall!( fn preadv( fd: libc::c_int, iovec: *const libc::iovec, n_iovec: libc::c_int, - offset: off64_t - ) -> isize - } + offset: off64_t, + ) -> isize; + ); let ret = cvt(unsafe { preadv( @@ -257,7 +257,14 @@ impl FileDesc { // and its metadata from LLVM IR. #[no_sanitize(cfi)] pub fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result { - super::weak::weak!(fn preadv64(libc::c_int, *const libc::iovec, libc::c_int, off64_t) -> isize); + super::weak::weak!( + fn preadv64( + fd: libc::c_int, + iovec: *const libc::iovec, + n_iovec: libc::c_int, + offset: off64_t, + ) -> isize; + ); match preadv64.get() { Some(preadv) => { @@ -286,7 +293,14 @@ impl FileDesc { // use "weak" linking. #[cfg(target_vendor = "apple")] pub fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result { - super::weak::weak!(fn preadv(libc::c_int, *const libc::iovec, libc::c_int, off64_t) -> isize); + super::weak::weak!( + fn preadv( + fd: libc::c_int, + iovec: *const libc::iovec, + n_iovec: libc::c_int, + offset: off64_t, + ) -> isize; + ); match preadv.get() { Some(preadv) => { @@ -428,14 +442,14 @@ impl FileDesc { // implementation if `pwritev` is not available. #[cfg(all(target_os = "android", target_pointer_width = "64"))] pub fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result { - super::weak::syscall! { + super::weak::syscall!( fn pwritev( fd: libc::c_int, iovec: *const libc::iovec, n_iovec: libc::c_int, - offset: off64_t - ) -> isize - } + offset: off64_t, + ) -> isize; + ); let ret = cvt(unsafe { pwritev( @@ -450,7 +464,14 @@ impl FileDesc { #[cfg(all(target_os = "android", target_pointer_width = "32"))] pub fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result { - super::weak::weak!(fn pwritev64(libc::c_int, *const libc::iovec, libc::c_int, off64_t) -> isize); + super::weak::weak!( + fn pwritev64( + fd: libc::c_int, + iovec: *const libc::iovec, + n_iovec: libc::c_int, + offset: off64_t, + ) -> isize; + ); match pwritev64.get() { Some(pwritev) => { @@ -479,7 +500,14 @@ impl FileDesc { // use "weak" linking. #[cfg(target_vendor = "apple")] pub fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result { - super::weak::weak!(fn pwritev(libc::c_int, *const libc::iovec, libc::c_int, off64_t) -> isize); + super::weak::weak!( + fn pwritev( + fd: libc::c_int, + iovec: *const libc::iovec, + n_iovec: libc::c_int, + offset: off64_t, + ) -> isize; + ); match pwritev.get() { Some(pwritev) => { diff --git a/library/std/src/sys/pal/unix/kernel_copy.rs b/library/std/src/sys/pal/unix/kernel_copy.rs index bbf29f3252341..d42a7e2a7fc51 100644 --- a/library/std/src/sys/pal/unix/kernel_copy.rs +++ b/library/std/src/sys/pal/unix/kernel_copy.rs @@ -604,16 +604,16 @@ pub(super) fn copy_regular_files(reader: RawFd, writer: RawFd, max_len: u64) -> _ => true, }; - syscall! { + syscall!( fn copy_file_range( fd_in: libc::c_int, off_in: *mut libc::loff_t, fd_out: libc::c_int, off_out: *mut libc::loff_t, len: libc::size_t, - flags: libc::c_uint - ) -> libc::ssize_t - } + flags: libc::c_uint, + ) -> libc::ssize_t; + ); fn probe_copy_file_range_support() -> u8 { // In some cases, we cannot determine availability from the first @@ -727,16 +727,16 @@ fn sendfile_splice(mode: SpliceMode, reader: RawFd, writer: RawFd, len: u64) -> // Android builds use feature level 14, but the libc wrapper for splice is // gated on feature level 21+, so we have to invoke the syscall directly. #[cfg(target_os = "android")] - syscall! { + syscall!( fn splice( srcfd: libc::c_int, src_offset: *const i64, dstfd: libc::c_int, dst_offset: *const i64, len: libc::size_t, - flags: libc::c_int - ) -> libc::ssize_t - } + flags: libc::c_int, + ) -> libc::ssize_t; + ); #[cfg(target_os = "linux")] use libc::splice; diff --git a/library/std/src/sys/pal/unix/stack_overflow.rs b/library/std/src/sys/pal/unix/stack_overflow.rs index 4bd0cedd44ccb..34b3948e3f671 100644 --- a/library/std/src/sys/pal/unix/stack_overflow.rs +++ b/library/std/src/sys/pal/unix/stack_overflow.rs @@ -424,18 +424,32 @@ mod imp { let pages = PAGES.get_or_init(|| { use crate::sys::weak::dlsym; - dlsym!(fn sysctlbyname(*const libc::c_char, *mut libc::c_void, *mut libc::size_t, *const libc::c_void, libc::size_t) -> libc::c_int); + dlsym!( + fn sysctlbyname( + name: *const libc::c_char, + oldp: *mut libc::c_void, + oldlenp: *mut libc::size_t, + newp: *const libc::c_void, + newlen: libc::size_t, + ) -> libc::c_int; + ); let mut guard: usize = 0; let mut size = size_of_val(&guard); let oid = c"security.bsd.stack_guard_page"; match sysctlbyname.get() { - Some(fcn) if unsafe { - fcn(oid.as_ptr(), - (&raw mut guard).cast(), - &raw mut size, - ptr::null_mut(), - 0) == 0 - } => guard, + Some(fcn) + if unsafe { + fcn( + oid.as_ptr(), + (&raw mut guard).cast(), + &raw mut size, + ptr::null_mut(), + 0, + ) == 0 + } => + { + guard + } _ => 1, } }); diff --git a/library/std/src/sys/pal/unix/thread.rs b/library/std/src/sys/pal/unix/thread.rs index bb34c2fabe559..9078dd1c23166 100644 --- a/library/std/src/sys/pal/unix/thread.rs +++ b/library/std/src/sys/pal/unix/thread.rs @@ -193,11 +193,12 @@ impl Thread { // and its metadata from LLVM IR. #[no_sanitize(cfi)] pub fn set_name(name: &CStr) { - weak! { + weak!( fn pthread_setname_np( - libc::pthread_t, *const libc::c_char - ) -> libc::c_int - } + thread: libc::pthread_t, + name: *const libc::c_char, + ) -> libc::c_int; + ); if let Some(f) = pthread_setname_np.get() { #[cfg(target_os = "nto")] @@ -762,7 +763,9 @@ unsafe fn min_stack_size(attr: *const libc::pthread_attr_t) -> usize { // We use dlsym to avoid an ELF version dependency on GLIBC_PRIVATE. (#23628) // We shouldn't really be using such an internal symbol, but there's currently // no other way to account for the TLS size. - dlsym!(fn __pthread_get_minstack(*const libc::pthread_attr_t) -> libc::size_t); + dlsym!( + fn __pthread_get_minstack(attr: *const libc::pthread_attr_t) -> libc::size_t; + ); match __pthread_get_minstack.get() { None => libc::PTHREAD_STACK_MIN, diff --git a/library/std/src/sys/pal/unix/time.rs b/library/std/src/sys/pal/unix/time.rs index c0a3044660b7e..b8469b1681f03 100644 --- a/library/std/src/sys/pal/unix/time.rs +++ b/library/std/src/sys/pal/unix/time.rs @@ -123,7 +123,12 @@ impl Timespec { // __clock_gettime64 was added to 32-bit arches in glibc 2.34, // and it handles both vDSO calls and ENOSYS fallbacks itself. - weak!(fn __clock_gettime64(libc::clockid_t, *mut __timespec64) -> libc::c_int); + weak!( + fn __clock_gettime64( + clockid: libc::clockid_t, + tp: *mut __timespec64, + ) -> libc::c_int; + ); if let Some(clock_gettime64) = __clock_gettime64.get() { let mut t = MaybeUninit::uninit(); diff --git a/library/std/src/sys/pal/unix/weak.rs b/library/std/src/sys/pal/unix/weak.rs index ce3f66a83748b..e7f4e005cc48c 100644 --- a/library/std/src/sys/pal/unix/weak.rs +++ b/library/std/src/sys/pal/unix/weak.rs @@ -29,7 +29,7 @@ use crate::{mem, ptr}; // We can use true weak linkage on ELF targets. #[cfg(all(unix, not(target_vendor = "apple")))] pub(crate) macro weak { - (fn $name:ident($($t:ty),*) -> $ret:ty) => ( + (fn $name:ident($($param:ident : $t:ty),* $(,)?) -> $ret:ty;) => ( let ref $name: ExternWeak $ret> = { unsafe extern "C" { #[linkage = "extern_weak"] @@ -62,10 +62,16 @@ impl ExternWeak { } pub(crate) macro dlsym { - (fn $name:ident($($t:ty),*) -> $ret:ty) => ( - dlsym!(fn $name($($t),*) -> $ret, stringify!($name)); + (fn $name:ident($($param:ident : $t:ty),* $(,)?) -> $ret:ty;) => ( + dlsym!( + #[link_name = stringify!($name)] + fn $name($($param : $t),*) -> $ret; + ); ), - (fn $name:ident($($t:ty),*) -> $ret:ty, $sym:expr) => ( + ( + #[link_name = $sym:expr] + fn $name:ident($($param:ident : $t:ty),* $(,)?) -> $ret:ty; + ) => ( static DLSYM: DlsymWeak $ret> = DlsymWeak::new(concat!($sym, '\0')); let $name = &DLSYM; @@ -143,15 +149,15 @@ unsafe fn fetch(name: &str) -> *mut libc::c_void { #[cfg(not(any(target_os = "linux", target_os = "android")))] pub(crate) macro syscall { - (fn $name:ident($($arg_name:ident: $t:ty),*) -> $ret:ty) => ( + (fn $name:ident($($param:ident : $t:ty),* $(,)?) -> $ret:ty;) => ( // FIXME(#115199): Rust currently omits weak function definitions // and its metadata from LLVM IR. #[no_sanitize(cfi)] - unsafe fn $name($($arg_name: $t),*) -> $ret { - weak! { fn $name($($t),*) -> $ret } + unsafe fn $name($($param: $t),*) -> $ret { + weak!(fn $name($($param: $t),*) -> $ret;); if let Some(fun) = $name.get() { - fun($($arg_name),*) + fun($($param),*) } else { super::os::set_errno(libc::ENOSYS); -1 @@ -162,16 +168,18 @@ pub(crate) macro syscall { #[cfg(any(target_os = "linux", target_os = "android"))] pub(crate) macro syscall { - (fn $name:ident($($arg_name:ident: $t:ty),*) -> $ret:ty) => ( - unsafe fn $name($($arg_name:$t),*) -> $ret { - weak! { fn $name($($t),*) -> $ret } + ( + fn $name:ident($($param:ident : $t:ty),* $(,)?) -> $ret:ty; + ) => ( + unsafe fn $name($($param: $t),*) -> $ret { + weak!(fn $name($($param: $t),*) -> $ret;); // Use a weak symbol from libc when possible, allowing `LD_PRELOAD` // interposition, but if it's not found just use a raw syscall. if let Some(fun) = $name.get() { - fun($($arg_name),*) + fun($($param),*) } else { - libc::syscall(libc::${concat(SYS_, $name)}, $($arg_name),*) as $ret + libc::syscall(libc::${concat(SYS_, $name)}, $($param),*) as $ret } } ) @@ -179,9 +187,9 @@ pub(crate) macro syscall { #[cfg(any(target_os = "linux", target_os = "android"))] pub(crate) macro raw_syscall { - (fn $name:ident($($arg_name:ident: $t:ty),*) -> $ret:ty) => ( - unsafe fn $name($($arg_name:$t),*) -> $ret { - libc::syscall(libc::${concat(SYS_, $name)}, $($arg_name),*) as $ret + (fn $name:ident($($param:ident : $t:ty),* $(,)?) -> $ret:ty;) => ( + unsafe fn $name($($param: $t),*) -> $ret { + libc::syscall(libc::${concat(SYS_, $name)}, $($param),*) as $ret } ) } diff --git a/library/std/src/sys/pal/wasi/thread.rs b/library/std/src/sys/pal/wasi/thread.rs index c85b03d4a8918..cc569bb3daf68 100644 --- a/library/std/src/sys/pal/wasi/thread.rs +++ b/library/std/src/sys/pal/wasi/thread.rs @@ -67,7 +67,7 @@ cfg_if::cfg_if! { } } -pub const DEFAULT_MIN_STACK_SIZE: usize = 64 * 1024; +pub const DEFAULT_MIN_STACK_SIZE: usize = 1024 * 1024; impl Thread { // unsafe: see thread::Builder::spawn_unchecked for safety requirements diff --git a/library/std/src/sys/pal/wasm/atomics/thread.rs b/library/std/src/sys/pal/wasm/atomics/thread.rs index afdb159fe6f8b..dd5aff391fd8b 100644 --- a/library/std/src/sys/pal/wasm/atomics/thread.rs +++ b/library/std/src/sys/pal/wasm/atomics/thread.rs @@ -6,7 +6,7 @@ use crate::time::Duration; pub struct Thread(!); -pub const DEFAULT_MIN_STACK_SIZE: usize = 64 * 1024; +pub const DEFAULT_MIN_STACK_SIZE: usize = 1024 * 1024; impl Thread { // unsafe: see thread::Builder::spawn_unchecked for safety requirements diff --git a/library/std/src/sys/process/unix/unix.rs b/library/std/src/sys/process/unix/unix.rs index 42542f81b6545..191a09c8da913 100644 --- a/library/std/src/sys/process/unix/unix.rs +++ b/library/std/src/sys/process/unix/unix.rs @@ -461,18 +461,20 @@ impl Command { if #[cfg(target_os = "linux")] { use crate::sys::weak::weak; - weak! { + weak!( fn pidfd_spawnp( - *mut libc::c_int, - *const libc::c_char, - *const libc::posix_spawn_file_actions_t, - *const libc::posix_spawnattr_t, - *const *mut libc::c_char, - *const *mut libc::c_char - ) -> libc::c_int - } + pidfd: *mut libc::c_int, + path: *const libc::c_char, + file_actions: *const libc::posix_spawn_file_actions_t, + attrp: *const libc::posix_spawnattr_t, + argv: *const *mut libc::c_char, + envp: *const *mut libc::c_char, + ) -> libc::c_int; + ); - weak! { fn pidfd_getpid(libc::c_int) -> libc::c_int } + weak!( + fn pidfd_getpid(pidfd: libc::c_int) -> libc::c_int; + ); static PIDFD_SUPPORTED: AtomicU8 = AtomicU8::new(0); const UNKNOWN: u8 = 0; @@ -593,19 +595,19 @@ impl Command { // https://pubs.opengroup.org/onlinepubs/9799919799/functions/posix_spawn_file_actions_addchdir.html. // The _np version is more widely available, though, so try that first. - weak! { + weak!( fn posix_spawn_file_actions_addchdir_np( - *mut libc::posix_spawn_file_actions_t, - *const libc::c_char - ) -> libc::c_int - } + file_actions: *mut libc::posix_spawn_file_actions_t, + path: *const libc::c_char, + ) -> libc::c_int; + ); - weak! { + weak!( fn posix_spawn_file_actions_addchdir( - *mut libc::posix_spawn_file_actions_t, - *const libc::c_char - ) -> libc::c_int - } + file_actions: *mut libc::posix_spawn_file_actions_t, + path: *const libc::c_char, + ) -> libc::c_int; + ); posix_spawn_file_actions_addchdir_np .get() diff --git a/library/std/src/sys/random/linux.rs b/library/std/src/sys/random/linux.rs index e3cb79285cd15..c0591ec0c1527 100644 --- a/library/std/src/sys/random/linux.rs +++ b/library/std/src/sys/random/linux.rs @@ -73,13 +73,13 @@ fn getrandom(mut bytes: &mut [u8], insecure: bool) { // A weak symbol allows interposition, e.g. for perf measurements that want to // disable randomness for consistency. Otherwise, we'll try a raw syscall. // (`getrandom` was added in glibc 2.25, musl 1.1.20, android API level 28) - syscall! { + syscall!( fn getrandom( buffer: *mut libc::c_void, length: libc::size_t, - flags: libc::c_uint - ) -> libc::ssize_t - } + flags: libc::c_uint, + ) -> libc::ssize_t; + ); static GETRANDOM_AVAILABLE: AtomicBool = AtomicBool::new(true); static GRND_INSECURE_AVAILABLE: AtomicBool = AtomicBool::new(true); diff --git a/src/bootstrap/src/bin/main.rs b/src/bootstrap/src/bin/main.rs index 7ec3140c03862..cbfe00a757ce4 100644 --- a/src/bootstrap/src/bin/main.rs +++ b/src/bootstrap/src/bin/main.rs @@ -191,7 +191,7 @@ fn check_version(config: &Config) -> Option { } msg.push_str("There have been changes to x.py since you last updated:\n"); - msg.push_str(&human_readable_changes(&changes)); + msg.push_str(&human_readable_changes(changes)); msg.push_str("NOTE: to silence this warning, "); msg.push_str(&format!( diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index bbb0fbfbb9351..1712be7f947fa 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -1381,7 +1381,7 @@ impl Config { if !changes.is_empty() { println!( "WARNING: There have been changes to x.py since you last updated:\n{}", - crate::human_readable_changes(&changes) + crate::human_readable_changes(changes) ); } } diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs index 5314141dd1b02..244391739f38a 100644 --- a/src/bootstrap/src/utils/change_tracker.rs +++ b/src/bootstrap/src/utils/change_tracker.rs @@ -35,29 +35,25 @@ impl Display for ChangeSeverity { } } -pub fn find_recent_config_change_ids(current_id: usize) -> Vec { - if !CONFIG_CHANGE_HISTORY.iter().any(|config| config.change_id == current_id) { +pub fn find_recent_config_change_ids(current_id: usize) -> &'static [ChangeInfo] { + if let Some(index) = + CONFIG_CHANGE_HISTORY.iter().position(|config| config.change_id == current_id) + { + // Skip the current_id and IDs before it + &CONFIG_CHANGE_HISTORY[index + 1..] + } else { // If the current change-id is greater than the most recent one, return // an empty list (it may be due to switching from a recent branch to an // older one); otherwise, return the full list (assuming the user provided // the incorrect change-id by accident). if let Some(config) = CONFIG_CHANGE_HISTORY.iter().max_by_key(|config| config.change_id) { if current_id > config.change_id { - return Vec::new(); + return &[]; } } - return CONFIG_CHANGE_HISTORY.to_vec(); + CONFIG_CHANGE_HISTORY } - - let index = - CONFIG_CHANGE_HISTORY.iter().position(|config| config.change_id == current_id).unwrap(); - - CONFIG_CHANGE_HISTORY - .iter() - .skip(index + 1) // Skip the current_id and IDs before it - .cloned() - .collect() } pub fn human_readable_changes(changes: &[ChangeInfo]) -> String { diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index d7a5f304d2382..f654bd9c90b51 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -924,7 +924,14 @@ fn iter_header( impl Config { fn parse_and_update_revisions(&self, testfile: &Path, line: &str, existing: &mut Vec) { - const FORBIDDEN_REVISION_NAMES: [&str; 9] = + const FORBIDDEN_REVISION_NAMES: [&str; 2] = [ + // `//@ revisions: true false` Implying `--cfg=true` and `--cfg=false` makes it very + // weird for the test, since if the test writer wants a cfg of the same revision name + // they'd have to use `cfg(r#true)` and `cfg(r#false)`. + "true", "false", + ]; + + const FILECHECK_FORBIDDEN_REVISION_NAMES: [&str; 9] = ["CHECK", "COM", "NEXT", "SAME", "EMPTY", "NOT", "COUNT", "DAG", "LABEL"]; if let Some(raw) = self.parse_name_value_directive(line, "revisions") { @@ -933,25 +940,38 @@ impl Config { } let mut duplicates: HashSet<_> = existing.iter().cloned().collect(); - for revision in raw.split_whitespace().map(|r| r.to_string()) { - if !duplicates.insert(revision.clone()) { + for revision in raw.split_whitespace() { + if !duplicates.insert(revision.to_string()) { panic!( "duplicate revision: `{}` in line `{}`: {}", revision, raw, testfile.display() ); - } else if matches!(self.mode, Mode::Assembly | Mode::Codegen | Mode::MirOpt) - && FORBIDDEN_REVISION_NAMES.contains(&revision.as_str()) + } + + if FORBIDDEN_REVISION_NAMES.contains(&revision) { + panic!( + "revision name `{revision}` is not permitted: `{}` in line `{}`: {}", + revision, + raw, + testfile.display() + ); + } + + if matches!(self.mode, Mode::Assembly | Mode::Codegen | Mode::MirOpt) + && FILECHECK_FORBIDDEN_REVISION_NAMES.contains(&revision) { panic!( - "revision name `{revision}` is not permitted in a test suite that uses `FileCheck` annotations\n\ - as it is confusing when used as custom `FileCheck` prefix: `{revision}` in line `{}`: {}", + "revision name `{revision}` is not permitted in a test suite that uses \ + `FileCheck` annotations as it is confusing when used as custom `FileCheck` \ + prefix: `{revision}` in line `{}`: {}", raw, testfile.display() ); } - existing.push(revision); + + existing.push(revision.to_string()); } } } diff --git a/src/tools/compiletest/src/header/tests.rs b/src/tools/compiletest/src/header/tests.rs index 007318be7cc39..4d90f152ee204 100644 --- a/src/tools/compiletest/src/header/tests.rs +++ b/src/tools/compiletest/src/header/tests.rs @@ -567,6 +567,13 @@ fn test_assembly_mode_forbidden_revisions() { parse_rs(&config, "//@ revisions: CHECK"); } +#[test] +#[should_panic(expected = "revision name `true` is not permitted")] +fn test_forbidden_revisions() { + let config = cfg().mode("ui").build(); + parse_rs(&config, "//@ revisions: true"); +} + #[test] #[should_panic( expected = "revision name `CHECK` is not permitted in a test suite that uses `FileCheck` annotations"